aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg')
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c1074
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h54
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni24
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/AppSupport.c232
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c1015
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h240
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf69
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c1444
-rw-r--r--roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c842
-rw-r--r--roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c610
-rw-r--r--roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni28
-rw-r--r--roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.c60
-rw-r--r--roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni22
-rw-r--r--roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c1361
-rw-r--r--roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c686
-rw-r--r--roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf58
-rw-r--r--roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.c1113
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.h213
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c139
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h82
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c672
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h130
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageStrings.uni68
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr80
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/String.c316
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/String.h71
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/Ui.h97
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/UiApp.inf82
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/UiApp.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Application/UiApp/UiAppExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.c273
-rw-r--r--roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c2139
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c338
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h731
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf72
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c516
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h257
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c514
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h177
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c132
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c384
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h240
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c277
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c263
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c2818
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h384
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c2649
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h1299
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf74
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c245
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c2661
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h198
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c1712
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h1075
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf71
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c1067
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c232
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c1492
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf53
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.c69
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.h1091
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c1222
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c174
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h145
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.c455
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.h40
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni23
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c346
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c1863
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c733
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c661
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h563
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf78
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c852
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h389
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c217
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c799
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h393
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf70
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c218
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.h141
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c2086
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h233
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c226
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h58
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf84
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.uni24
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c669
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h366
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c1126
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h207
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c652
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h330
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c560
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h151
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/DmaMem.c243
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c1314
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h316
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf67
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h303
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c463
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h93
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c627
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h324
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c517
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h86
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c2494
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.h782
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c379
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf48
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/ComponentName.c116
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c283
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c1700
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.h120
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c227
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c1422
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h745
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c1854
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h411
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c156
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h123
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf77
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c1126
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h70
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c1185
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c277
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c263
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c462
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h349
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf73
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.c523
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.h259
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c717
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h145
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.c828
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.h161
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c107
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c418
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h240
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c170
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h146
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c460
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h394
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf111
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c267
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h232
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c1056
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h266
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c188
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h83
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c2210
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h515
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c2848
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h470
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c484
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h205
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c2087
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h660
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c1653
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h159
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c764
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h136
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c82
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h28
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c2292
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h456
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c135
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h48
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c1596
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h269
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h44
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h571
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c1855
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c279
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf75
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c1250
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h783
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c1289
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/ComponentName.c171
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.c1108
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.h543
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c205
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c1363
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c1376
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c1423
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h864
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf70
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c2838
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h610
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c206
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h80
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c219
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c810
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h503
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c146
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h56
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c225
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.h139
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c1883
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h215
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c71
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h41
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf80
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c701
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h266
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c275
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h242
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c1040
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h265
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c558
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h155
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c222
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c3297
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h1390
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c217
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h140
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c752
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.h207
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c2236
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h722
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf70
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c718
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h551
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c4065
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h1487
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c370
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c631
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h140
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c1554
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h373
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h450
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c3029
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h1301
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ComponentName.c171
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c1520
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.h486
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf64
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c218
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c6327
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h1600
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf71
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c242
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c843
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h514
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c429
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h56
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c2894
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h339
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c236
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c2161
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h497
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c134
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h109
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c1205
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h501
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c242
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c653
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h510
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c429
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h56
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c2957
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h350
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c234
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c1381
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h252
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c132
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h109
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c908
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h475
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf64
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/DmaMem.c242
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c1150
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h693
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c429
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h56
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c1668
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h1339
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c216
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsDevConfigProtocol.c190
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c1187
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h998
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c2454
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h1339
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c394
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h217
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c647
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c134
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h143
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c915
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h339
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h26
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c303
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c1537
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h764
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf73
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c1017
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h227
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c1083
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h197
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c1285
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h181
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c1227
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h278
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c586
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h258
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c185
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h189
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c365
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c1243
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h257
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/ComponentName.c217
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c1239
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.h613
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.c1982
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.h326
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf93
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.uni29
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c156
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h187
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c998
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h338
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c607
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h187
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c606
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h134
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c156
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h123
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c1108
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h327
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf81
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni31
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/ComponentName.c218
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/MouseHid.c275
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c1018
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.h465
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf66
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.uni25
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c218
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c275
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c999
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h465
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf66
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni25
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c436
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c1488
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h2940
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf201
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c938
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c279
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c784
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h91
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c295
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c148
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c227
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c729
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c129
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h402
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c536
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c46
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c719
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h238
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c2675
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h40
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c958
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c1576
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h264
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c702
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c285
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c1909
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h24
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c100
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c1746
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h467
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h182
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c20
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c1759
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c2105
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c857
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c282
-rwxr-xr-xroms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c181
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c1514
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c1284
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c66
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c107
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c1601
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/Arm/DxeLoadFunc.c71
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h237
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf145
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIplExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c835
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ebc/DxeLoadFunc.c67
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c465
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/IdtVectorAsm.nasm71
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/RiscV64/DxeLoadFunc.c74
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c132
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c933
-rw-r--r--roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h330
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/BootMode/BootMode.c80
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c535
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.c247
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.h26
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c1828
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.c2434
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.h372
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Hob/Hob.c234
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Image/Image.c970
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Memory/MemoryServices.c895
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c122
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PeiCore.uni22
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PeiCoreExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PeiMain.h2037
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PeiMain.inf131
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c524
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Ppi/Ppi.c1118
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Reset/Reset.c111
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/Security/Security.c145
-rw-r--r--roms/edk2/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c68
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Dependency.c382
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Dispatcher.c1499
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Handle.c528
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.c1404
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.h392
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c171
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Locate.c489
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c1368
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Notify.c196
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Page.c1071
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c920
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h1353
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf123
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h119
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c1865
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf91
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Pool.c449
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/Smi.c333
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c1367
-rw-r--r--roms/edk2/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c2817
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/Crc32.c45
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.c424
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.h119
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/AcpiS3Context.h66
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h42
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/CapsuleVendor.h59
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/ConnectConInEvent.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/ConsoleInDevice.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/ConsoleOutDevice.h17
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/Crc32GuidedSectionExtraction.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/DebugMask.h68
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/DriverSampleHii.h31
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/EndOfS3Resume.h20
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/EventExitBootServiceFailed.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h254
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/FaultTolerantWrite.h48
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/FirmwarePerformance.h139
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/HiiBootMaintenanceFormset.h22
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/HiiResourceSampleHii.h17
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/IdleLoopEvent.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h28
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/LzmaDecompress.h29
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MdeModuleHii.h232
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MdeModulePkgTokenSpace.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MemoryProfile.h468
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MemoryStatusCodeRecord.h97
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MemoryTypeInformation.h30
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MigratedFvInfo.h22
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/MtcVendor.h25
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/NonDiscoverableDevice.h52
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseHobGuid.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseSignatureGuid.h228
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/Performance.h337
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PerformanceMeasurement.h72
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PiSmmCommunicationRegionTable.h57
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PiSmmMemoryAttributesTable.h45
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PlatDriOverrideHii.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/PlatformHasAcpi.h29
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/RamDiskHii.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/RecoveryDevice.h62
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/S3SmmInitDone.h21
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h57
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/SerialPortLibVendor.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/SmiHandlerProfile.h211
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/SmmLockBox.h66
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/SmmVariableCommon.h150
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/StandardErrorDevice.h18
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/StatusCodeCallbackGuid.h20
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeDebug.h43
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeVariable.h34
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/SystemNvDataGuid.h111
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/TtyTerm.h36
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/UsbKeyBoardLayout.h31
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/VarErrorFlag.h35
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/VariableFormat.h221
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/VariableIndexTable.h41
-rw-r--r--roms/edk2/MdeModulePkg/Include/Guid/ZeroGuid.h19
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/AuthVariableLib.h254
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/BmpSupportLib.h89
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/BootLogoLib.h64
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/CapsuleLib.h160
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/CpuExceptionHandlerLib.h200
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/CustomizedDisplayLib.h350
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/DebugAgentLib.h97
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/DisplayUpdateProgressLib.h48
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/FileExplorerLib.h41
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/FmpAuthenticationLib.h60
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/FrameBufferBltLib.h87
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/HiiLib.h1113
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/IpmiLib.h45
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/LockBoxLib.h137
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/MemoryProfileLib.h47
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/NonDiscoverableDeviceRegistrationLib.h58
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/OemHookStatusCodeLib.h73
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/PciHostBridgeLib.h115
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/PlatformBootManagerLib.h69
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/PlatformHookLib.h32
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/PlatformVarCleanupLib.h56
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/ResetSystemLib.h93
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/ResetUtilityLib.h130
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/SecurityManagementLib.h270
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/SmmCorePlatformHookLib.h44
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/SortLib.h107
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/TpmMeasurementLib.h38
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h817
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/UefiHiiServicesLib.h46
-rw-r--r--roms/edk2/MdeModulePkg/Include/Library/VarCheckLib.h174
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/AtaAhciController.h83
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/AtaController.h155
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/AtaPassThru.h213
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/CapsuleOnDisk.h55
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/Debug.h75
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/IoMmu.h201
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/IpmiPpi.h59
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressHostController.h86
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressPassThru.h156
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetFilter.h25
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetHandler.h23
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetNotification.h26
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/PostBootScriptTable.h20
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SdMmcHostController.h57
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SecPerformance.h60
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SerialPortPei.h20
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SmmAccess.h139
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SmmCommunication.h57
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/SmmControl.h89
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h277
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/UfsHostController.h53
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/Usb2HostController.h262
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/UsbController.h87
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/UsbHostController.h250
-rw-r--r--roms/edk2/MdeModulePkg/Include/Ppi/UsbIo.h189
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/AtaAtapiPolicy.h53
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/BootLogo.h59
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/BootLogo2.h101
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/DebuggerConfiguration.h25
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/DeviceSecurity.h162
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/DisplayProtocol.h352
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/EbcSimpleDebugger.h117
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/EbcVmTest.h184
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/EsrtManagement.h138
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/FaultTolerantWrite.h201
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/FileExplorer.h69
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/FirmwareManagementProgress.h49
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx.h149
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx2.h119
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/GenericMemoryTest.h120
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/IoMmu.h253
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/IpmiProtocol.h66
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/LoadPe32Image.h97
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/LockBox.h24
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/NonDiscoverableDevice.h71
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/PeCoffImageEmulator.h100
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/PlatformBootManager.h82
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/PlatformLogo.h67
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetFilter.h25
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetHandler.h23
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/Print2.h657
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/Ps2Policy.h35
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SdMmcOverride.h160
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmExitBootServices.h23
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h32
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h30
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmLegacyBoot.h22
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmMemoryAttribute.h127
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmReadyToBoot.h23
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h34
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmVarCheck.h30
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SmmVariable.h33
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/SwapAddressRange.h168
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/UfsHostController.h237
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/UfsHostControllerPlatform.h124
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/VarCheck.h120
-rw-r--r--roms/edk2/MdeModulePkg/Include/Protocol/VariableLock.h57
-rw-r--r--roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c71
-rw-r--r--roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c575
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.c536
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c47
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.c569
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c31
-rw-r--r--roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf30
-rw-r--r--roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c105
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c1104
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf43
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c228
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf35
-rw-r--r--roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c551
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BmLib.c83
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenance.c1770
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.h1328
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.vfr354
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.c93
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.h54
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.c469
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.h141
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerStrings.uni284
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf99
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c1005
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/ConsoleOption.c1166
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Data.c265
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/FormGuid.h206
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/UpdatePage.c1150
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Variable.c731
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.c929
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.h166
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerStrings.uni36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerVfr.Vfr51
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf73
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.c31
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.h43
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompress.c316
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLibInternal.h48
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/GuidedSectionExtraction.c191
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.editorconfig40
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitattributes1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitignore18
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitmodules6
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.travis.yml229
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/BUILD144
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CMakeLists.txt407
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CONTRIBUTING.md27
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/LICENSE19
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/MANIFEST.in17
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile55
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile.am38
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README15
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README.md98
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/WORKSPACE21
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/bootstrap31
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/constants.h184
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/context.h261
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.bin432
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.c5914
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.h64
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/platform.h567
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.c291
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.h85
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/version.h26
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.c65
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.h356
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/decode.c2605
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.c339
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.h128
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/prefix.h750
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.c157
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.h365
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.c145
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.h39
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.c843
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.h95
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_inc.h163
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.c35
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.h63
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost_inc.h127
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_encoder_inc.h34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.c194
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.h51
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter_inc.h440
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.c1329
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.h84
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.c56
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.h48
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster_inc.h320
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/command.h190
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.c790
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.h61
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.c645
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.h54
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.c1846
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.h25
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encode.c1925
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.c33
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.h43
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.c501
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.h122
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode_static.h539
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/fast_log.h147
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/find_match_length.h80
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash.h488
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_composite_inc.h125
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_forgetful_chain_inc.h293
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match64_inc.h267
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_inc.h262
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_quickly_inc.h266
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_rolling_inc.h212
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_to_binary_tree_inc.h329
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.c100
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.h63
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram_inc.h51
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.c175
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.h30
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.c170
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.h114
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.c663
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.h105
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock_inc.h183
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/params.h46
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/prefix.h53
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/quality.h165
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/ringbuffer.h167
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.c486
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.h40
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict_lut.h5864
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.c85
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.h32
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/write_bits.h87
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/decode_fuzzer.c58
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/run_decode_fuzzer.c44
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/test_fuzzer.sh33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/decode.h344
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/encode.h448
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/port.h288
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/types.h83
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.c1107
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.md107
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/compiler_config_setting.bzl28
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure8
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure-cmake318
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure.ac14
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/injected_code.txt32
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReader.cs271
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReaderTest.cs33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliInputStream.cs223
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliRuntimeException.cs22
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Context.cs57
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Decode.cs992
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DecodeTest.cs171
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Dictionary.cs97
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DictionaryTest.cs36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Huffman.cs149
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/HuffmanTreeGroup.cs50
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/IntReader.cs36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Prefix.cs33
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/RunningState.cs37
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/State.cs171
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/SynthTest.cs2174
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Transform.cs154
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/TransformTest.cs74
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Utils.cs59
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/WordTransformType.cs68
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/sharpen.cfg18
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/transpile.sh94
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli-comparison-study-2015-09-22.pdfbin0 -> 215208 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli.1132
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/decode.h.3415
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/encode.h.3586
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/types.h.3117
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/fetch-spec/shared-brotli-fetch-spec.txt116
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/BUILD2
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/WORKSPACE21
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/BUILD26
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cbrotli_test.go367
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cgo.go13
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/reader.go161
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/writer.go159
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/BUILD98
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/WORKSPACE41
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BUILD59
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReader.java289
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReaderTest.java54
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliInputStream.java160
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliRuntimeException.java21
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Context.java58
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Decode.java1251
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DecodeTest.java160
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Dictionary.java54
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryData.java51
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryTest.java38
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/EagerStreamTest.java386
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Huffman.java137
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SetDictionaryTest.java76
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/State.java89
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SynthTest.java2940
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Transform.java236
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/TransformTest.java71
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Utils.java102
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/build_defs.bzl34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/pom.xml172
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/proguard.pgcfg6
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BUILD73
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BrotliJniTestBase.java13
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleChecker.java112
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleHelper.java113
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/fuzz_data.zipbin0 -> 23854 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/pom.xml65
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_corpus.zipbin0 -> 3587214 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_data.zipbin0 -> 2859607 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/pom.xml101
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BUILD61
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BrotliCommon.java130
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/CommonJNI.java16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java74
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetZeroDictionaryTest.java48
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/common_jni.cc47
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BUILD84
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannel.java69
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannelTest.java84
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStream.java115
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStreamTest.java82
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/Decoder.java177
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderJNI.java121
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderTest.java77
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/EagerStreamTest.java75
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/decoder_jni.cc202
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BUILD88
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannel.java77
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannelTest.java118
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStream.java87
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStreamTest.java118
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EmptyInputTest.java29
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/Encoder.java205
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderJNI.java118
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderTest.java80
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/encoder_jni.cc195
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/BUILD43
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/WORKSPACE12
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.js2029
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.min.js2
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode_test.js79
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/polyfill.js65
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/premake5.lua78
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/Makefile57
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/README.md54
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/_brotli.cc753
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/bro.py160
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/brotli.py56
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/__init__.py0
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/_test_utils.py112
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/bro_test.py102
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compress_test.py41
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compressor_test.py94
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompress_test.py42
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompressor_test.py59
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD44
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD.libdivsufsort55
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/Makefile17
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/README.md67
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/WORKSPACE12
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotli_decoder.c93
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotlidump.py2362
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.cc302
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.h26
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/dictionary_generator.cc326
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_diff.cc117
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_histogram.cc197
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.cc726
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.h99
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/COPYING24
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/README34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/cmdline.h704
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/enumSubstring.cpp140
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/esa.hxx125
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/sais.hxx364
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/wafbin0 -> 88387 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/wscript23
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/find_opt_references.cc267
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_brotli.pngbin0 -> 1981984 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_diff.pngbin0 -> 5096698 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_opt.pngbin0 -> 2025431 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/.gitignore32
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CHANGELOG.md21
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeLists.txt99
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake38
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake15
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckLFS.cmake109
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/ProjectCPack.cmake38
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/LICENSE21
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/README.md140
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/VERSION.cmake23
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/CMakeLists.txt11
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/bwt.c220
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/mksary.c193
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/sasearch.c165
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/suftest.c164
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/unbwt.c207
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/CMakeLists.txt162
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/config.h.cmake81
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort.h.cmake180
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort_private.h207
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/lfs.h.cmake56
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/CMakeLists.txt31
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/divsufsort.c398
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/sssort.c815
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/trsort.c586
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/utils.c381
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/CMakeLists.txt9
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake11
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/read_dist.h50
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.cc259
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.h21
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.bintray.json19
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.configure-custom.sh1
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.travis.sh81
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/appveyor.yml111
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/README.md3
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-01-download-rfc.py16
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-02-rfc-to-bin.py34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-03-validate-bin.py38
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-04-generate-java-literals.py79
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/fix-win-bazel-build.py36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlicommon.pc.in11
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlidec.pc.in12
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlienc.pc.in12
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/sources.lst99
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.cfg5
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.py288
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/Makefile17
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/compatibility_test.sh25
-rwxr-xr-xroms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/roundtrip_test.sh34
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-compatibility-test.cmake31
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-roundtrip-test.cmake36
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y.compressedbin0 -> 12 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x.compressedbin0 -> 10 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt3609
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt.compressedbin0 -> 50096 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt4122
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt.compressedbin0 -> 45687 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536bin0 -> 65792 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536.compressedbin0 -> 19 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/bb.binastbin0 -> 12356697 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_filebin0 -> 50096 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file.compressedbin0 -> 50100 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeatedbin0 -> 144224 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated.compressedbin0 -> 50299 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty0
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.001
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.011
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.021
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.031
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.041
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.051
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.061
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.071
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.081
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.091
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.101
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.111
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.121
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.131
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.141
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.151
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.16bin0 -> 4 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.171
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.18bin0 -> 196610 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt7519
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt.compressedbin0 -> 124719 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrhbin0 -> 285886 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh.compressedbin0 -> 161743 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey.compressedbin0 -> 425 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt10699
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt.compressedbin0 -> 174771 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox.compressed1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated.compressed2
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_chunksbin0 -> 2704 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.binbin0 -> 10000 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin.compressedbin0 -> 10004 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa.compressedbin0 -> 69 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressedbin0 -> 5 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.00bin0 -> 5 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.01bin0 -> 8 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.02bin0 -> 5 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.03bin0 -> 10 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy.compressed1
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zerosbin0 -> 262144 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros.compressedbin0 -> 13 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stddef.h9
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdint.h9
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdlib.h9
-rw-r--r--roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/string.h9
-rw-r--r--roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c141
-rw-r--r--roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h38
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c952
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni57
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c978
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h291
-rw-r--r--roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c66
-rw-r--r--roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.c941
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.h189
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerStrings.uni58
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerVfr.Vfr60
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.c458
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf43
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.c157
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c1975
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h75
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c1650
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf98
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c691
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c70
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c473
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c69
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c174
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf74
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c170
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf40
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.inf43
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h100
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLib.c51
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLibNull.c49
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileServices.h48
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c1054
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c1822
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf77
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni22
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h78
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c230
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c382
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.c87
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c75
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c442
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf41
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c2220
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c622
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c103
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c312
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf34
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c13
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf25
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c529
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf43
-rw-r--r--roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c1653
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h236
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni55
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr79
-rw-r--r--roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h32
-rw-r--r--roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.c60
-rw-r--r--roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf35
-rw-r--r--roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.c718
-rw-r--r--roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf28
-rw-r--r--roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c135
-rw-r--r--roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf32
-rw-r--r--roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c213
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c196
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt4
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf63
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf59
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c214
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h90
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zTypes.h378
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h27
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h64
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c82
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Compiler.h33
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h335
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c1071
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h121
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h57
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c1187
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h234
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Precomp.h10
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-history.txt424
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-sdk.txt357
-rw-r--r--roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h37
-rw-r--r--roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.c208
-rw-r--r--roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf42
-rw-r--r--roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c56
-rw-r--r--roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf30
-rw-r--r--roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c109
-rw-r--r--roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf32
-rw-r--r--roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c210
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf44
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/DebugLib.c454
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf59
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c72
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf45
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c601
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c75
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf37
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c859
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c554
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c103
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c1776
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h181
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c2413
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf68
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h105
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c1105
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf42
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h185
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLib.c117
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLibNull.c48
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileServices.h48
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c54
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c78
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c30
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf33
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h102
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr35
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h53
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c1278
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni29
-rw-r--r--roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtility.c252
-rw-r--r--roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtilityLib.inf34
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c752
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c195
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.inf45
-rw-r--r--roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c1326
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf72
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni21
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h76
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c46
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c76
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf36
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c538
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf45
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h47
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c742
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c871
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/MemoryAllocationLib.c1134
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryProfileLib.c137
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c461
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c539
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.c106
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.inf41
-rw-r--r--roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c39
-rw-r--r--roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf29
-rw-r--r--roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c2587
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c875
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c315
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c761
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c585
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c1151
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c1457
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c535
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h468
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf120
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c90
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLib.c4481
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiString.c349
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h30
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c107
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/DxeMemoryProfileLib.c96
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/MemoryAllocationLib.c1051
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.inf48
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c316
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf42
-rw-r--r--roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h81
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h57
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c1583
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h130
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c437
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c67
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c601
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c664
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf44
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf58
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c472
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h70
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf81
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c933
-rw-r--r--roms/edk2/MdeModulePkg/Logo/Logo.bmpbin0 -> 12446 bytes
-rw-r--r--roms/edk2/MdeModulePkg/Logo/Logo.c153
-rw-r--r--roms/edk2/MdeModulePkg/Logo/Logo.idf10
-rw-r--r--roms/edk2/MdeModulePkg/Logo/Logo.inf31
-rw-r--r--roms/edk2/MdeModulePkg/Logo/Logo.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Logo/LogoDxe.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Logo/LogoDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Logo/LogoDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Logo/LogoExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/MdeModulePkg.ci.yaml111
-rw-r--r--roms/edk2/MdeModulePkg/MdeModulePkg.dec2095
-rw-r--r--roms/edk2/MdeModulePkg/MdeModulePkg.dsc495
-rw-r--r--roms/edk2/MdeModulePkg/MdeModulePkg.uni1313
-rw-r--r--roms/edk2/MdeModulePkg/MdeModulePkgExtra.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Test/MdeModulePkgHostTest.dsc32
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c257
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c1053
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h580
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c84
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h234
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf78
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c1850
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c296
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c274
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c608
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c446
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c539
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c602
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf86
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c56
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c497
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h91
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm130
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c261
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c677
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf83
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c225
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf67
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c318
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf67
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c325
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h171
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c928
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf69
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h154
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c913
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/Bds.h108
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf105
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c1170
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c42
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.c196
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.h24
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c281
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.inf56
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.c437
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.inf64
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.uni15
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/Capsule.h123
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf94
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf52
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.uni23
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64Extra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c1291
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h115
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c1332
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/PageFaultHandler.nasm81
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c305
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c36
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c32
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c29
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf108
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c397
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h70
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c21
-rw-r--r--roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c209
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ComponentName.c161
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c1271
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h419
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf95
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c770
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c5113
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h2000
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf114
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.uni23
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c622
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/ComponentName.c176
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c2136
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h594
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf72
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/LaffStd.c271
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/ComponentName.c184
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.c729
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.h53
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutputDxe.inf53
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c73
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c231
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c1383
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h1458
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c2093
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c959
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf98
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c322
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/ComponentName.c176
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c739
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.h390
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.inf66
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugService.h50
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.c94
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.inf46
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupport.c127
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf72
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/AsmFuncs.nasm493
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/DebugSupport.h292
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c367
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.h16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupportIa32.c139
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.nasm581
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupport.h16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupportX64.c140
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePath.c99
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c715
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h292
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c183
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c1262
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h467
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni21
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c182
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c275
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c883
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c353
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c1369
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h485
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf85
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni24
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c788
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl38
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c487
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c244
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf84
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c107
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr94
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni41
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c758
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h604
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h44
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c857
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c179
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/File.c904
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c214
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c2924
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c331
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h1215
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni20
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c467
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h181
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c4259
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h741
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni134
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c1664
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c724
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c1593
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthConfigureVfr.Vfr33
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c987
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.h127
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf74
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxeExtra.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerStrings.uni34
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.Vfr32
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.h26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c2239
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h122
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf96
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Inventory.vfr111
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/InventoryStrings.uni60
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h129
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr932
-rw-r--r--roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni428
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c475
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf108
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c247
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c585
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h60
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c306
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c288
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c542
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c176
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c145
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c76
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c578
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c38
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c118
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c99
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c862
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c656
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h115
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h239
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c1770
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h30
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c1211
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h567
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c833
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h477
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c384
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c1020
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c754
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c2230
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h244
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c267
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h241
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf81
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c5383
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h135
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c1542
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h260
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm191
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c526
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm236
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c570
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.c661
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf66
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c475
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.h238
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmp.c558
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDebugPrint.c144
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxeExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c887
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h784
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c277
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf86
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c636
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf95
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmCommon.h113
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.c559
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.h196
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf59
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.c90
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf85
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteTraditionalMm.c108
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c1378
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxe.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c607
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c315
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.c52
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.inf47
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/ComponentName.c181
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.c1030
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c673
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemInternal.h616
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c3329
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c6231
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c4632
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c2904
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h2352
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf94
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c251
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c1563
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ImageEx.c421
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c2085
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.c146
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleDxe.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/Sample.vfr39
-rw-r--r--roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/SampleStrings.uni38
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.c251
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.h169
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.uni24
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2DxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c421
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c434
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf59
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.uni19
-rw-r--r--roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBoxExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf53
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.c926
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.h335
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c284
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h131
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf46
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.c119
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.h51
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.uni24
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Metronome/MetronomeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounter.c269
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf55
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.c1378
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.inf349
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxe.uni291
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.c1901
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.h1195
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.c1672
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.inf351
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni290
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.c1081
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.h1082
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.inf50
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.uni17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2PeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c311
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/InternalPlatDriOverrideDxe.h211
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c1744
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.uni37
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c1941
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatOverMngr.h61
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatformDriOverrideDxe.inf109
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/Vfr.vfr100
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/VfrStrings.uni59
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PrintDxe/Print.c163
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.inf47
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.c98
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.h104
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c381
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.h125
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf129
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/config.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.gitignore79
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.travis.yml17
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/AUTHORS1
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/CMakeLists.txt180
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/COPYING26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/ChangeLog0
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/HISTORY2359
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/INSTALL368
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/Makefile.am81
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/NEWS0
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README195
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README.md346
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README_japanese183
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/autogen.sh9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/cmake/Config.cmake.in4
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/compile348
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.guess1476
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.sub1801
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/configure.ac68
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/depcomp791
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API982
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API.ja989
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API385
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API.ja382
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN95
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN.ja93
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ.ja22
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE578
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE.ja585
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/SYNTAX.md1091
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/UNICODE_PROPERTIES788
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/ascii_compatible.dict113
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/base.c389
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/deluxe.c206
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/dict_conv.py72
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/fuzzer.options2
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/libfuzzer-onig.cpp45
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/makefile68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/regset.c392
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index.html192
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index_ja.html195
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/install-sh518
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/m4/.whatever0
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win.bat5
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win32.bat5
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win64.bat5
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/missing215
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/onig-config.in78
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.cmake.in13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.in13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/CMakeLists.txt35
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/Makefile.am49
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/bug_fix.c93
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/callout.c268
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/count.c125
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/crnl.c129
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/echo.c136
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/encode.c212
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/listcap.c118
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/names.c79
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/posix.c107
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/regset.c95
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/scan.c90
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/simple.c63
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/sql.c81
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/syntax.c77
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/user_property.c92
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.am69
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.windows189
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/ascii.c118
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/big5.c193
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.cmake.in50
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win3256
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win6456
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.windows.in62
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/cp1251.c205
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp.c293
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.c151
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.gperf26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_kr.c193
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_tw.c187
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gb18030.c556
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_fold_key_conv.py71
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_unfold_key_conv.py57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_1.c268
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_10.c222
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_11.c101
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_13.c207
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_14.c223
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_15.c213
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_16.c220
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_2.c218
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_3.c214
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_4.c217
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_5.c218
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_6.c101
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_7.c206
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_8.c101
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_9.c207
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8.c236
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8_r.c204
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_property.sh20
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb.sh7
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb_data.py267
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold.sh36
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold_data.py486
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property.sh26
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property_data.py605
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb.sh7
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb_data.py267
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/mktable.c1184
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onig_init.c45
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniggnu.h87
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onigposix.h178
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniguruma.h1053
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regcomp.c7928
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.c985
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.h282
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regerror.c406
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regexec.c6518
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regext.c202
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/reggnu.c143
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regint.h1084
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.c8678
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.h475
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposerr.c123
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposix.c321
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regsyntax.c338
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regtrav.c76
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regversion.c59
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis.c310
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.c151
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.gperf26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.c584
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.h67
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode.c1215
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_egcb_data.c1374
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold1_key.c2998
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold2_key.c226
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold3_key.c136
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold_data.c1549
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data.c30389
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data_posix.c5347
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_unfold_key.c3303
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_wb_data.c1023
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_be.c276
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_le.c276
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_be.c163
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_le.c164
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf8.c290
-rwxr-xr-xroms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test-driver148
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/Makefile.am65
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_regset.c456
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_syntax.c246
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_utf8.c1438
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testc.c979
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testu.c955
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/windows/testc.c865
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdarg.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stddef.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdio.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdlib.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/string.h9
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.c315
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.h103
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf55
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.c409
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.h136
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf58
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c233
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.h103
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmmExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c362
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.h121
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c313
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.h98
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf60
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.c354
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf43
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.c263
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.inf44
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPeiExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c408
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.h89
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStub.c210
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf54
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf49
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialIo.c562
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c3734
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h259
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c2694
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c2645
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c6675
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h1875
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf79
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c1455
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h124
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf61
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c671
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c92
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf55
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferExtraDxe.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/MemoryStausCodeWorker.c121
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c161
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c63
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.h119
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPeiExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/MemoryStatusCodeWorker.c110
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCodeWorker.c156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.c201
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.h121
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf71
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/MemoryStatusCodeWorker.c107
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.c156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.c84
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.h117
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf65
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmmExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.c160
-rw-r--r--roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf46
-rw-r--r--roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.c1231
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.h144
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf74
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c339
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h157
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c155
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierDxe.c27
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierSmm.c26
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c124
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c512
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c149
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c3753
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h829
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c581
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c258
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c334
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h67
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c788
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h347
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c153
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h51
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf146
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni22
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c1188
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf149
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni27
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c1801
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf106
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni23
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c89
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf139
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c130
-rw-r--r--roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.c245
-rw-r--r--roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.h102
-rw-r--r--roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf51
-rw-r--r--roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimerExtra.uni14
2135 files changed, 791887 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
new file mode 100644
index 000000000..9e729074e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
@@ -0,0 +1,1074 @@
+/** @file
+ The application to show the Boot Manager Menu.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootManagerMenu.h"
+
+EFI_HII_HANDLE gStringPackHandle;
+
+BOOLEAN mModeInitialized = FALSE;
+
+//
+// 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;
+
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at
+ @param String String pointer.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+PrintStringAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String
+ )
+{
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
+ return Print (L"%s", String);
+}
+
+/**
+ Prints a character to the default console, at
+ the supplied cursor position, using L"%c" format.
+
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at.
+ @param Character Character to print.
+
+ @return Length of string printed to the console.
+
+**/
+UINTN
+PrintCharAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ CHAR16 Character
+ )
+{
+ gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
+ return Print (L"%c", Character);
+}
+
+/**
+ Count the storage space of a Unicode string which uses current language to get
+ from input string ID.
+
+ @param StringId The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+GetLineWidth (
+ IN EFI_STRING_ID StringId
+ )
+{
+ UINTN Index;
+ UINTN IncrementValue;
+ EFI_STRING String;
+ UINTN LineWidth;
+
+ LineWidth = 0;
+ String = HiiGetString (gStringPackHandle, StringId, NULL);
+
+ if (String != NULL) {
+ Index = 0;
+ IncrementValue = 1;
+
+ do {
+ //
+ // Advance to the null-terminator or to the first width directive
+ //
+ for (;
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
+ Index++, LineWidth = LineWidth + IncrementValue
+ )
+ ;
+
+ //
+ // We hit the null-terminator, we now have a count
+ //
+ if (String[Index] == 0) {
+ break;
+ }
+ //
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
+ //
+ if (String[Index] == NARROW_CHAR) {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 1;
+ } else {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 2;
+ }
+ } while (String[Index] != 0);
+ FreePool (String);
+ }
+
+ return LineWidth;
+}
+
+/**
+ This function uses calculate the boot menu location, size and scroll bar information.
+
+ @param BootMenuData The boot menu data to be processed.
+
+ @return EFI_SUCCESS calculate boot menu information successful.
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid
+
+**/
+EFI_STATUS
+InitializeBootMenuScreen (
+ IN OUT BOOT_MENU_POPUP_DATA *BootMenuData
+ )
+{
+ UINTN MaxStrWidth;
+ UINTN StrWidth;
+ UINTN Index;
+ UINTN Column;
+ UINTN Row;
+ UINTN MaxPrintRows;
+ UINTN UnSelectableItmes;
+
+ if (BootMenuData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get maximum string width
+ //
+ MaxStrWidth = 0;
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
+ StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
+ }
+
+ for (Index = 0; Index < BootMenuData->ItemCount; Index++) {
+ StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]);
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
+ }
+
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
+ StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
+ MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;
+ }
+ //
+ // query current row and column to calculate boot menu location
+ //
+ gST->ConOut->QueryMode (
+ gST->ConOut,
+ gST->ConOut->Mode->Mode,
+ &Column,
+ &Row
+ );
+
+ MaxPrintRows = Row - 6;
+ UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2;
+ BootMenuData->MenuScreen.Width = MaxStrWidth + 8;
+ if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) {
+ BootMenuData->MenuScreen.Height = MaxPrintRows;
+ BootMenuData->ScrollBarControl.HasScrollBar = TRUE;
+ BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes;
+ BootMenuData->ScrollBarControl.FirstItem = 0;
+ BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1;
+ } else {
+ BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes;
+ BootMenuData->ScrollBarControl.HasScrollBar = FALSE;
+ BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount;
+ BootMenuData->ScrollBarControl.FirstItem = 0;
+ BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1;
+ }
+ BootMenuData->MenuScreen.StartCol = (Column - BootMenuData->MenuScreen.Width) / 2;
+ BootMenuData->MenuScreen.StartRow = (Row - BootMenuData->MenuScreen.Height) / 2;
+
+ return EFI_SUCCESS;
+}
+/**
+ This function uses check boot option is wheher setup application or no
+
+ @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
+
+ @retval TRUE This boot option is setup application.
+ @retval FALSE This boot options isn't setup application
+
+**/
+BOOLEAN
+IsBootManagerMenu (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ if (!EFI_ERROR (Status)) {
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);
+ }
+
+ return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber));
+}
+
+/**
+ Return whether to ignore the boot option.
+
+ @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION to check.
+
+ @retval TRUE Ignore the boot option.
+ @retval FALSE Do not ignore the boot option.
+**/
+BOOLEAN
+IgnoreBootOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+
+ //
+ // Ignore myself.
+ //
+ Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath);
+ ASSERT_EFI_ERROR (Status);
+ if (CompareMem (BootOption->FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) {
+ return TRUE;
+ }
+
+ //
+ // Do not ignore Boot Manager Menu.
+ //
+ if (IsBootManagerMenu (BootOption)) {
+ return FALSE;
+ }
+
+ //
+ // Ignore the hidden/inactive boot option.
+ //
+ if (((BootOption->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption->Attributes & LOAD_OPTION_ACTIVE) == 0)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function uses to initialize boot menu data
+
+ @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
+ @param BootOptionCount Number of boot option.
+ @param BootMenuData The Input BootMenuData to be initialized.
+
+ @retval EFI_SUCCESS Initialize boot menu data successful.
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid.
+
+**/
+EFI_STATUS
+InitializeBootMenuData (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ IN UINTN BootOptionCount,
+ OUT BOOT_MENU_POPUP_DATA *BootMenuData
+ )
+{
+ UINTN Index;
+ UINTN StrIndex;
+
+ if (BootOption == NULL || BootMenuData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING);
+ BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID));
+ ASSERT (BootMenuData->PtrTokens != NULL);
+
+ //
+ // Skip boot option which created by BootNext Variable
+ //
+ for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) {
+ if (IgnoreBootOption (&BootOption[Index])) {
+ continue;
+ }
+
+ ASSERT (BootOption[Index].Description != NULL);
+ BootMenuData->PtrTokens[StrIndex++] = HiiSetString (
+ gStringPackHandle,
+ 0,
+ BootOption[Index].Description,
+ NULL
+ );
+ }
+
+ BootMenuData->ItemCount = StrIndex;
+ BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING);
+ BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING);
+ BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING);
+ InitializeBootMenuScreen (BootMenuData);
+ BootMenuData->SelectItem = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function uses input select item to highlight selected item
+ and set current selected item in BootMenuData
+
+ @param WantSelectItem The user wants to select item.
+ @param BootMenuData The boot menu data to be processed
+
+ @return EFI_SUCCESS Highlight selected item and update current selected
+ item successful
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid
+**/
+EFI_STATUS
+BootMenuSelectItem (
+ IN UINTN WantSelectItem,
+ IN OUT BOOT_MENU_POPUP_DATA *BootMenuData
+ )
+{
+ INT32 SavedAttribute;
+ EFI_STRING String;
+ UINTN StartCol;
+ UINTN StartRow;
+ UINTN PrintCol;
+ UINTN PrintRow;
+ UINTN TopShadeNum;
+ UINTN LowShadeNum;
+ UINTN FirstItem;
+ UINTN LastItem;
+ UINTN ItemCountPerScreen;
+ UINTN Index;
+ BOOLEAN RePaintItems;
+
+ if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+ ASSERT (BootMenuData->ItemCount != 0);
+ SavedAttribute = gST->ConOut->Mode->Attribute;
+ RePaintItems = FALSE;
+ StartCol = BootMenuData->MenuScreen.StartCol;
+ StartRow = BootMenuData->MenuScreen.StartRow;
+ //
+ // print selectable items again and adjust scroll bar if need
+ //
+ if (BootMenuData->ScrollBarControl.HasScrollBar &&
+ (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||
+ WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||
+ WantSelectItem == BootMenuData->SelectItem)) {
+ ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
+ //
+ // Set first item and last item
+ //
+ if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {
+ BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;
+ BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1;
+ } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {
+ BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1;
+ BootMenuData->ScrollBarControl.LastItem = WantSelectItem;
+ }
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
+ FirstItem = BootMenuData->ScrollBarControl.FirstItem;
+ LastItem = BootMenuData->ScrollBarControl.LastItem;
+ TopShadeNum = 0;
+ if (FirstItem != 0) {
+ TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;
+ if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
+ TopShadeNum++;
+ }
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
+ for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
+ }
+ }
+ LowShadeNum = 0;
+ if (LastItem != BootMenuData->ItemCount - 1) {
+ LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;
+ if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {
+ LowShadeNum++;
+ }
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum;
+ for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);
+ }
+ }
+ PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum;
+ for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {
+ PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);
+ }
+
+
+ //
+ // Clear selectable items first
+ //
+ PrintCol = StartCol + 1;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
+ String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));
+ ASSERT (String != NULL);
+ for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {
+ String[Index] = 0x20;
+ }
+ for (Index = 0; Index < ItemCountPerScreen; Index++) {
+ PrintStringAt (PrintCol, PrintRow + Index, String);
+ }
+ FreePool (String);
+ //
+ // print selectable items
+ //
+ for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+ }
+ RePaintItems = TRUE;
+ }
+
+ //
+ // if Want Select and selected item isn't the same and doesn't re-draw selectable
+ // items, clear select item
+ //
+ FirstItem = BootMenuData->ScrollBarControl.FirstItem;
+ if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);
+ PrintCol = StartCol + 1;
+ PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem;
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+ }
+
+ //
+ // Print want to select item
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);
+ PrintCol = StartCol + 1;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem;
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
+ BootMenuData->SelectItem = WantSelectItem;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function uses to draw boot popup menu
+
+ @param BootMenuData The Input BootMenuData to be processed.
+
+ @retval EFI_SUCCESS Draw boot popup menu successful.
+
+**/
+EFI_STATUS
+DrawBootPopupMenu (
+ IN BOOT_MENU_POPUP_DATA *BootMenuData
+ )
+{
+ EFI_STRING String;
+ UINTN Index;
+ UINTN Width;
+ UINTN StartCol;
+ UINTN StartRow;
+ UINTN PrintRow;
+ UINTN PrintCol;
+ UINTN LineWidth;
+ INT32 SavedAttribute;
+ UINTN ItemCountPerScreen;
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ SavedAttribute = gST->ConOut->Mode->Attribute;
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);
+ Width = BootMenuData->MenuScreen.Width;
+ StartCol = BootMenuData->MenuScreen.StartCol;
+ StartRow = BootMenuData->MenuScreen.StartRow;
+ ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;
+ PrintRow = StartRow;
+
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+ //
+ // Draw Boot popup menu screen
+ //
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);
+ for (Index = 1; Index < Width - 1; Index++) {
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
+ }
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);
+
+ //
+ // Draw the screen for title
+ //
+ String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));
+ ASSERT (String != NULL);
+ for (Index = 0; Index < Width - 2; Index++) {
+ String[Index] = 0x20;
+ }
+
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
+ PrintStringAt (StartCol + 1, PrintRow, String);
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
+ }
+
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
+ for (Index = 1; Index < Width - 1; Index++) {
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
+ }
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
+
+ //
+ // Draw screen for selectable items
+ //
+ for (Index = 0; Index < ItemCountPerScreen; Index++) {
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
+ PrintStringAt (StartCol + 1, PrintRow, String);
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
+ }
+
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);
+ for (Index = 1; Index < Width - 1; Index++) {
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
+ }
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);
+
+ //
+ // Draw screen for Help
+ //
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);
+ PrintStringAt (StartCol + 1, PrintRow, String);
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);
+ }
+ FreePool (String);
+
+ PrintRow++;
+ PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);
+ for (Index = 1; Index < Width - 1; Index++) {
+ PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL);
+ }
+ PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT);
+
+
+ //
+ // print title strings
+ //
+ PrintRow = StartRow + 1;
+ for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {
+ String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);
+ LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]);
+ PrintCol = StartCol + (Width - LineWidth) / 2;
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+ }
+
+ //
+ // print selectable items
+ //
+ PrintCol = StartCol + 1;
+ PrintRow = StartRow + TITLE_TOKEN_COUNT + 2;
+ for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {
+ String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+ }
+
+ //
+ // Print Help strings
+ //
+ PrintRow++;
+ for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {
+ String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);
+ LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);
+ PrintCol = StartCol + (Width - LineWidth) / 2;
+ PrintStringAt (PrintCol, PrintRow, String);
+ FreePool (String);
+ }
+
+ //
+ // Print scroll bar if has scroll bar
+ //
+ if (BootMenuData->ScrollBarControl.HasScrollBar) {
+ PrintCol = StartCol + Width - 2;
+ PrintRow = StartRow + 2;
+ PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE);
+ PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
+ PrintRow += (ItemCountPerScreen + 1);
+ PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);
+ PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
+ //
+ // Print Selected item
+ //
+ BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);
+ return EFI_SUCCESS;
+}
+
+/**
+ This function uses to boot from selected item
+
+ @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.
+ @param BootOptionCount Number of boot option.
+ @param SelectItem Current selected item.
+**/
+VOID
+BootFromSelectOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ IN UINTN BootOptionCount,
+ IN UINTN SelectItem
+ )
+{
+ UINTN ItemNum;
+ UINTN Index;
+
+ ASSERT (BootOptions != NULL);
+
+ for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {
+ if (IgnoreBootOption (&BootOptions[Index])) {
+ continue;
+ }
+
+ if (ItemNum++ == SelectItem) {
+ EfiBootManagerBoot (&BootOptions[Index]);
+ break;
+ }
+ }
+}
+
+/**
+ 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 required 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 required 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 required 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;
+}
+
+/**
+ Display the boot popup menu and allow user select boot item.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option
+ @retval EFI_NOT_FOUND User select to enter setup or can not find boot option
+
+**/
+EFI_STATUS
+EFIAPI
+BootManagerMenuEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ EFI_STATUS Status;
+ BOOT_MENU_POPUP_DATA BootMenuData;
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+ BOOLEAN ExitApplication;
+ UINTN SelectItem;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN BootTextColumn;
+ UINTN BootTextRow;
+
+ //
+ // Set Logo status invalid when boot manager menu is launched
+ //
+ BootLogo = NULL;
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
+ Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+ gStringPackHandle = HiiAddPackages (
+ &gEfiCallerIdGuid,
+ gImageHandle,
+ BootManagerMenuAppStrings,
+ NULL
+ );
+ ASSERT (gStringPackHandle != NULL);
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ EfiBootManagerConnectAll ();
+ EfiBootManagerRefreshAllBootOption ();
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ 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;
+ }
+
+ //
+ // Set back to conventional setup resolution
+ //
+ BdsSetConsoleMode (TRUE);
+
+ //
+ // Initialize Boot menu data
+ //
+ Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);
+ //
+ // According to boot menu data to draw boot popup menu
+ //
+ DrawBootPopupMenu (&BootMenuData);
+
+ //
+ // check user input to determine want to re-draw or boot from user selected item
+ //
+ ExitApplication = FALSE;
+ while (!ExitApplication) {
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status)) {
+ switch (Key.UnicodeChar) {
+
+ case CHAR_NULL:
+ switch (Key.ScanCode) {
+
+ case SCAN_UP:
+ SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;
+ BootMenuSelectItem (SelectItem, &BootMenuData);
+ break;
+
+ case SCAN_DOWN:
+ SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;
+ BootMenuSelectItem (SelectItem, &BootMenuData);
+ break;
+
+ case SCAN_ESC:
+ gST->ConOut->ClearScreen (gST->ConOut);
+ ExitApplication = TRUE;
+ //
+ // Set boot resolution for normal boot
+ //
+ BdsSetConsoleMode (FALSE);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ gST->ConOut->ClearScreen (gST->ConOut);
+ //
+ // Set boot resolution for normal boot
+ //
+ BdsSetConsoleMode (FALSE);
+ BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);
+ //
+ // Back to boot manager menu again, set back to setup resolution
+ //
+ BdsSetConsoleMode (TRUE);
+ DrawBootPopupMenu (&BootMenuData);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+ FreePool (BootMenuData.PtrTokens);
+
+ HiiRemovePackages (gStringPackHandle);
+
+ return Status;
+
+}
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h
new file mode 100644
index 000000000..e38e87824
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.h
@@ -0,0 +1,54 @@
+/** @file
+ FrontPage routines to handle the callbacks and browser calls
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _BOOT_MANAGER_MENU_H_
+#define _BOOT_MANAGER_MENU_H_
+
+#include <Uefi.h>
+#include <Guid/MdeModuleHii.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/BootLogo.h>
+
+#define TITLE_TOKEN_COUNT 1
+#define HELP_TOKEN_COUNT 3
+
+typedef struct _BOOT_MENU_SCREEN {
+ UINTN StartCol;
+ UINTN StartRow;
+ UINTN Width;
+ UINTN Height;
+} BOOT_MENU_SCREEN;
+
+typedef struct _BOOT_MENU_SCROLL_BAR_CONTROL {
+ BOOLEAN HasScrollBar;
+ UINTN ItemCountPerScreen;
+ UINTN FirstItem;
+ UINTN LastItem;
+} BOOT_MENU_SCROLL_BAR_CONTROL;
+
+typedef struct _BOOT_MENU_POPUP_DATA {
+ EFI_STRING_ID TitleToken[TITLE_TOKEN_COUNT]; // Title string ID
+ UINTN ItemCount; // Selectable item count
+ EFI_STRING_ID *PtrTokens; // All of selectable items string ID
+ EFI_STRING_ID HelpToken[HELP_TOKEN_COUNT]; // All of help string ID
+ UINTN SelectItem; // Current select item
+ BOOT_MENU_SCREEN MenuScreen; // Boot menu screen information
+ BOOT_MENU_SCROLL_BAR_CONTROL ScrollBarControl; // Boot menu scroll bar information
+} BOOT_MENU_POPUP_DATA;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
new file mode 100644
index 000000000..3dee2480d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
@@ -0,0 +1,62 @@
+## @file
+# The application to show the Boot Manager Menu.
+#
+# The application pops up a menu showing all the boot options referenced by
+# BootOrder NV variable and user can choose to boot from one of them.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootManagerMenuApp
+ MODULE_UNI_FILE = BootManagerMenuApp.uni
+ FILE_GUID = EEC25BDC-67F2-4D95-B1D5-F81B2039D11D
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BootManagerMenuEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootManagerMenu.c
+ BootManagerMenu.h
+ BootManagerMenuStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HiiLib
+ DebugLib
+ UefiLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiApplicationEntryPoint
+ UefiBootManagerLib
+
+[Guids]
+
+[Protocols]
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootManagerMenuAppExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni
new file mode 100644
index 000000000..8cda38fb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The application to show the Boot Manager Menu.
+//
+// The application pops up a menu showing all the boot options referenced by
+// BootOrder NV variable and user can choose to boot from one of them.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The application to show the Boot Manager Menu"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The application pops up a menu showing all the boot options referenced by BootOrder NV variable and user can choose to boot from one of them."
+
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni
new file mode 100644
index 000000000..c43d78ecb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuAppExtra.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The application to show the Boot Manager Menu.
+//
+// The application pops up a menu showing all the boot options referenced by
+// BootOrder NV variable and user can choose to boot from one of them.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Manager Menu Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni
new file mode 100644
index 000000000..355bd52c3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuStrings.uni
@@ -0,0 +1,24 @@
+// /** @file
+// String definitions for BootManagerMenuApp.
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_BOOT_POPUP_MENU_TITLE_STRING #language en-US "Please select boot device:"
+ #language fr-FR "Please select boot device:"
+
+#string STR_BOOT_POPUP_MENU_HELP1_STRING #language en-US "↑ and ↓ to move selection"
+ #language fr-FR "↑ and ↓ to move selection"
+
+#string STR_BOOT_POPUP_MENU_HELP2_STRING #language en-US "ENTER to select boot device"
+ #language fr-FR "ENTER to select boot device"
+
+#string STR_BOOT_POPUP_MENU_HELP3_STRING #language en-US "ESC to exit"
+ #language fr-FR "ESC to exit"
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/AppSupport.c b/roms/edk2/MdeModulePkg/Application/CapsuleApp/AppSupport.c
new file mode 100644
index 000000000..8fe70dc3b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/AppSupport.c
@@ -0,0 +1,232 @@
+/** @file
+ A shell application that triggers capsule update process.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleApp.h"
+
+UINTN Argc;
+CHAR16 **Argv;
+EFI_SHELL_PROTOCOL *mShellProtocol = NULL;
+
+/**
+
+ This function parse application ARG.
+
+ @return Status
+**/
+EFI_STATUS
+GetArg (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID**)&ShellParameters
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Argc = ShellParameters->Argc;
+ Argv = ShellParameters->Argv;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get shell protocol.
+
+ @return Pointer to shell protocol.
+**/
+EFI_SHELL_PROTOCOL *
+GetShellProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mShellProtocol == NULL) {
+ Status = gBS->LocateProtocol (
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **) &mShellProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mShellProtocol = NULL;
+ }
+ }
+
+ return mShellProtocol;
+}
+
+/**
+ Read a file.
+
+ @param[in] FileName The file to be read.
+ @param[out] BufferSize The file buffer size
+ @param[out] Buffer The file buffer
+
+ @retval EFI_SUCCESS Read file successfully
+ @retval EFI_NOT_FOUND Shell protocol or file not found
+ @retval others Read file failed
+**/
+EFI_STATUS
+ReadFileToBuffer (
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ SHELL_FILE_HANDLE Handle;
+ UINT64 FileSize;
+ UINTN TempBufferSize;
+ VOID *TempBuffer;
+
+ ShellProtocol = GetShellProtocol();
+ if (ShellProtocol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Open file by FileName.
+ //
+ Status = ShellProtocol->OpenFileByName (
+ FileName,
+ &Handle,
+ EFI_FILE_MODE_READ
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the file size.
+ //
+ Status = ShellProtocol->GetFileSize (Handle, &FileSize);
+ if (EFI_ERROR (Status)) {
+ ShellProtocol->CloseFile (Handle);
+ return Status;
+ }
+
+ TempBufferSize = (UINTN) FileSize;
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer == NULL) {
+ ShellProtocol->CloseFile (Handle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read the file data to the buffer
+ //
+ Status = ShellProtocol->ReadFile (
+ Handle,
+ &TempBufferSize,
+ TempBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ ShellProtocol->CloseFile (Handle);
+ return Status;
+ }
+
+ ShellProtocol->CloseFile (Handle);
+
+ *BufferSize = TempBufferSize;
+ *Buffer = TempBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Write a file.
+
+ @param[in] FileName The file to be written.
+ @param[in] BufferSize The file buffer size
+ @param[in] Buffer The file buffer
+
+ @retval EFI_SUCCESS Write file successfully
+ @retval EFI_NOT_FOUND Shell protocol not found
+ @retval others Write file failed
+**/
+EFI_STATUS
+WriteFileFromBuffer (
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ SHELL_FILE_HANDLE Handle;
+ EFI_FILE_INFO *FileInfo;
+ UINTN TempBufferSize;
+
+ ShellProtocol = GetShellProtocol();
+ if (ShellProtocol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Open file by FileName.
+ //
+ Status = ShellProtocol->OpenFileByName (
+ FileName,
+ &Handle,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Empty the file contents.
+ //
+ FileInfo = ShellProtocol->GetFileInfo (Handle);
+ if (FileInfo == NULL) {
+ ShellProtocol->CloseFile (Handle);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If the file size is already 0, then it has been empty.
+ //
+ if (FileInfo->FileSize != 0) {
+ //
+ // Set the file size to 0.
+ //
+ FileInfo->FileSize = 0;
+ Status = ShellProtocol->SetFileInfo (Handle, FileInfo);
+ if (EFI_ERROR (Status)) {
+ FreePool (FileInfo);
+ ShellProtocol->CloseFile (Handle);
+ return Status;
+ }
+ }
+ FreePool (FileInfo);
+
+ //
+ // Write the file data from the buffer
+ //
+ TempBufferSize = BufferSize;
+ Status = ShellProtocol->WriteFile (
+ Handle,
+ &TempBufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ ShellProtocol->CloseFile (Handle);
+ return Status;
+ }
+
+ ShellProtocol->CloseFile (Handle);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
new file mode 100644
index 000000000..403471477
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
@@ -0,0 +1,1015 @@
+/** @file
+ A shell application that triggers capsule update process.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleApp.h"
+
+//
+// Define how many block descriptors we want to test with.
+//
+UINTN NumberOfDescriptors = 1;
+UINTN CapsuleFirstIndex;
+UINTN CapsuleLastIndex;
+
+/**
+ Create UX capsule.
+
+ @retval EFI_SUCCESS The capsule header is appended.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
+**/
+EFI_STATUS
+CreateBmpFmp (
+ VOID
+ )
+{
+ CHAR16 *OutputCapsuleName;
+ VOID *BmpBuffer;
+ UINTN FileSize;
+ CHAR16 *BmpName;
+ UINT8 *FullCapsuleBuffer;
+ UINTN FullCapsuleBufferSize;
+ EFI_DISPLAY_CAPSULE *DisplayCapsule;
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;
+ UINTN GopBltSize;
+ UINTN Height;
+ UINTN Width;
+
+ Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: NO GOP is found.\n");
+ return EFI_UNSUPPORTED;
+ }
+ Info = Gop->Mode->Info;
+ Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
+ Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);
+ Print(L"VerticalResolution - %d\n", Info->VerticalResolution);
+ // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
+ // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
+
+ if (Argc != 5) {
+ Print(L"CapsuleApp: Incorrect parameter count.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ if (StrCmp(Argv[3], L"-O") != 0) {
+ Print(L"CapsuleApp: NO output capsule name.\n");
+ return EFI_UNSUPPORTED;
+ }
+ OutputCapsuleName = Argv[4];
+
+ BmpBuffer = NULL;
+ FileSize = 0;
+ FullCapsuleBuffer = NULL;
+
+ BmpName = Argv[2];
+ Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
+ goto Done;
+ }
+
+ GopBlt = NULL;
+ Status = TranslateBmpToGopBlt (
+ BmpBuffer,
+ FileSize,
+ &GopBlt,
+ &GopBltSize,
+ &Height,
+ &Width
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);
+ goto Done;
+ }
+ if (GopBlt != NULL) {
+ FreePool (GopBlt);
+ }
+ Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);
+
+ if (Height > Info->VerticalResolution) {
+ Status = EFI_INVALID_PARAMETER;
+ Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);
+ goto Done;
+ }
+ if (Width > Info->HorizontalResolution) {
+ Status = EFI_INVALID_PARAMETER;
+ Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);
+ goto Done;
+ }
+
+ FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;
+ FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
+ if (FullCapsuleBuffer == NULL) {
+ Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
+ CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
+ DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);
+ DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+ DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
+
+ DisplayCapsule->ImagePayload.Version = 1;
+ DisplayCapsule->ImagePayload.Checksum = 0;
+ DisplayCapsule->ImagePayload.ImageType = 0; // BMP
+ DisplayCapsule->ImagePayload.Reserved = 0;
+ DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;
+
+ //
+ // Center the bitmap horizontally
+ //
+ DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);
+
+ //
+ // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
+ // of bitmap at bottom of display.
+ //
+ DisplayCapsule->ImagePayload.OffsetY =
+ MIN (
+ (UINT32)(Info->VerticalResolution - Height),
+ (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)
+ );
+
+ Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
+ BmpName,
+ DisplayCapsule->ImagePayload.OffsetX,
+ DisplayCapsule->ImagePayload.OffsetY
+ );
+
+ CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
+
+ DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
+
+ Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
+ Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
+
+Done:
+ if (BmpBuffer != NULL) {
+ FreePool(BmpBuffer);
+ }
+
+ if (FullCapsuleBuffer != NULL) {
+ FreePool(FullCapsuleBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Get ImageTypeId in the FMP capsule header.
+
+ @param[in] CapsuleHeader The FMP capsule image header.
+
+ @return ImageTypeId
+**/
+EFI_GUID *
+GetCapsuleImageTypeId (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT64 *ItemOffsetList;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+ if (FmpCapsuleHeader->PayloadItemCount == 0) {
+ return NULL;
+ }
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
+ return &ImageHeader->UpdateImageTypeId;
+}
+
+/**
+ Get ESRT FwType according to ImageTypeId
+
+ @param[in] ImageTypeId ImageTypeId of an FMP capsule.
+
+ @return ESRT FwType
+**/
+UINT32
+GetEsrtFwType (
+ IN EFI_GUID *ImageTypeId
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
+ UINTN Index;
+
+ //
+ // Check ESRT
+ //
+ Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
+ if (!EFI_ERROR(Status)) {
+ ASSERT(Esrt != NULL);
+ EsrtEntry = (VOID *)(Esrt + 1);
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
+ if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {
+ return EsrtEntry->FwType;
+ }
+ }
+ }
+
+ return ESRT_FW_TYPE_UNKNOWN;
+}
+
+/**
+ Validate if it is valid capsule header
+
+ This function assumes the caller provided correct CapsuleHeader pointer
+ and CapsuleSize.
+
+ This function validates the fields in EFI_CAPSULE_HEADER.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapsuleSize Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN UINT64 CapsuleSize
+ )
+{
+ if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
+ return FALSE;
+ }
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+ return FALSE;
+ }
+ if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {
+ return FALSE;
+ }
+ if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+ @param[in] CapsuleGuid A pointer to EFI_GUID
+
+ @retval TRUE It is a FMP capsule GUID.
+ @retval FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+ IN EFI_GUID *CapsuleGuid
+ )
+{
+ if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Append a capsule header on top of current image.
+ This function follows Windows UEFI Firmware Update Platform document.
+
+ @retval EFI_SUCCESS The capsule header is appended.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
+**/
+EFI_STATUS
+CreateNestedFmp (
+ VOID
+ )
+{
+ CHAR16 *OutputCapsuleName;
+ VOID *CapsuleBuffer;
+ UINTN FileSize;
+ CHAR16 *CapsuleName;
+ UINT8 *FullCapsuleBuffer;
+ UINTN FullCapsuleBufferSize;
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;
+ EFI_GUID *ImageTypeId;
+ UINT32 FwType;
+ EFI_STATUS Status;
+
+ if (Argc != 5) {
+ Print(L"CapsuleApp: Incorrect parameter count.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ if (StrCmp(Argv[3], L"-O") != 0) {
+ Print(L"CapsuleApp: NO output capsule name.\n");
+ return EFI_UNSUPPORTED;
+ }
+ OutputCapsuleName = Argv[4];
+
+ CapsuleBuffer = NULL;
+ FileSize = 0;
+ FullCapsuleBuffer = NULL;
+
+ CapsuleName = Argv[2];
+ Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
+ goto Done;
+ }
+ if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) {
+ Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
+ if (ImageTypeId == NULL) {
+ Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ FwType = GetEsrtFwType(ImageTypeId);
+ if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {
+ Print(L"CapsuleApp: Capsule FwType is invalid.\n");
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
+ FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
+ if (FullCapsuleBuffer == NULL) {
+ Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
+ ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
+ CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
+ NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;
+ NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
+ NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
+
+ CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
+
+ Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
+ Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
+
+Done:
+ if (CapsuleBuffer != NULL) {
+ FreePool(CapsuleBuffer);
+ }
+
+ if (FullCapsuleBuffer != NULL) {
+ FreePool(FullCapsuleBuffer);
+ }
+
+ return Status;
+}
+
+
+/**
+ Clear capsule status variable.
+
+ @retval EFI_SUCCESS The capsule status variable is cleared.
+**/
+EFI_STATUS
+ClearCapsuleStatusVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CHAR16 CapsuleVarName[20];
+ CHAR16 *TempVarName;
+ BOOLEAN Found;
+
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ Index = 0;
+
+ Found = FALSE;
+ while (TRUE) {
+ UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
+
+ Status = gRT->SetVariable (
+ CapsuleVarName,
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ (VOID *)NULL
+ );
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // There is no more capsule variables, quit
+ //
+ break;
+ }
+ Found = TRUE;
+
+ Print (L"Clear %s %r\n", CapsuleVarName, Status);
+
+ Index++;
+ if (Index > 0xFFFF) {
+ break;
+ }
+ }
+
+ if (!Found) {
+ Print (L"No any Capsule#### variable found\n");
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build Gather list for a list of capsule images.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] FileSize An array of UINTN to capsule images size
+ @param[in] CapsuleNum The count of capsule images
+ @param[out] BlockDescriptors The block descriptors for the capsule images
+
+ @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
+**/
+EFI_STATUS
+BuildGatherList (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *FileSize,
+ IN UINTN CapsuleNum,
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
+ )
+{
+ EFI_STATUS Status;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
+ UINT8 *TempDataPtr;
+ UINTN SizeLeft;
+ UINTN Size;
+ INT32 Count;
+ INT32 Number;
+ UINTN Index;
+
+ TempBlockPtr = NULL;
+ BlockDescriptors1 = NULL;
+ BlockDescriptors2 = NULL;
+ BlockDescriptorPre = NULL;
+ BlockDescriptorsHeader = NULL;
+
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ //
+ // Allocate memory for the descriptors.
+ //
+ if (NumberOfDescriptors == 1) {
+ Count = 2;
+ } else {
+ Count = (INT32)(NumberOfDescriptors + 2) / 2;
+ }
+
+ Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ BlockDescriptors1 = AllocateRuntimeZeroPool (Size);
+ if (BlockDescriptors1 == NULL) {
+ Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ERREXIT;
+ } else {
+ Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);
+ Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);
+ }
+
+ //
+ // Record descriptor header
+ //
+ if (Index == 0) {
+ BlockDescriptorsHeader = BlockDescriptors1;
+ }
+
+ if (BlockDescriptorPre != NULL) {
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
+ BlockDescriptorPre->Length = 0;
+ }
+
+ //
+ // Fill them in
+ //
+ TempBlockPtr = BlockDescriptors1;
+ TempDataPtr = CapsuleBuffer[Index];
+ SizeLeft = FileSize[Index];
+ for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
+ //
+ // Divide remaining data in half
+ //
+ if (NumberOfDescriptors != 1) {
+ if (SizeLeft == 1) {
+ Size = 1;
+ } else {
+ Size = SizeLeft / 2;
+ }
+ } else {
+ Size = SizeLeft;
+ }
+ TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
+ TempBlockPtr->Length = Size;
+ Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
+ SizeLeft -= Size;
+ TempDataPtr += Size;
+ TempBlockPtr++;
+ }
+
+ //
+ // Allocate the second list, point the first block's last entry to point
+ // to this one, and fill this one in. Worst case is that the previous
+ // list only had one element that pointed here, so we need at least two
+ // elements -- one to point to all the data, another to terminate the list.
+ //
+ if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
+ Count = (INT32)(NumberOfDescriptors + 2) - Count;
+ if (Count == 1) {
+ Count++;
+ }
+
+ Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
+ if (BlockDescriptors2 == NULL) {
+ Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ERREXIT;
+ }
+
+ //
+ // Point the first list's last element to point to this second list.
+ //
+ TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;
+
+ TempBlockPtr->Length = 0;
+ TempBlockPtr = BlockDescriptors2;
+ for (Number = 0; Number < Count - 1; Number++) {
+ //
+ // If second-to-last one, then dump rest to this element
+ //
+ if (Number == (Count - 2)) {
+ Size = SizeLeft;
+ } else {
+ //
+ // Divide remaining data in half
+ //
+ if (SizeLeft == 1) {
+ Size = 1;
+ } else {
+ Size = SizeLeft / 2;
+ }
+ }
+
+ TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
+ TempBlockPtr->Length = Size;
+ Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
+ SizeLeft -= Size;
+ TempDataPtr += Size;
+ TempBlockPtr++;
+ if (SizeLeft == 0) {
+ break;
+ }
+ }
+ }
+
+ BlockDescriptorPre = TempBlockPtr;
+ BlockDescriptors1 = NULL;
+ }
+
+ //
+ // Null-terminate.
+ //
+ if (TempBlockPtr != NULL) {
+ TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;
+ TempBlockPtr->Length = 0;
+ *BlockDescriptors = BlockDescriptorsHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ERREXIT:
+ if (BlockDescriptors1 != NULL) {
+ FreePool(BlockDescriptors1);
+ }
+
+ if (BlockDescriptors2 != NULL) {
+ FreePool(BlockDescriptors2);
+ }
+
+ return Status;
+}
+
+/**
+ Clear the Gather list for a list of capsule images.
+
+ @param[in] BlockDescriptors The block descriptors for the capsule images
+ @param[in] CapsuleNum The count of capsule images
+**/
+VOID
+CleanGatherList (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
+ IN UINTN CapsuleNum
+ )
+{
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;
+ UINTN Index;
+
+ if (BlockDescriptors != NULL) {
+ TempBlockPtr1 = BlockDescriptors;
+ while (1){
+ TempBlockPtr = TempBlockPtr1;
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ if (TempBlockPtr[Index].Length == 0) {
+ break;
+ }
+ }
+
+ if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
+ break;
+ }
+
+ TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);
+ FreePool(TempBlockPtr1);
+ TempBlockPtr1 = TempBlockPtr2;
+ }
+ }
+}
+
+/**
+ Print APP usage.
+**/
+VOID
+PrintUsage (
+ VOID
+ )
+{
+ Print(L"CapsuleApp: usage\n");
+ Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
+ Print(L" CapsuleApp -S\n");
+ Print(L" CapsuleApp -C\n");
+ Print(L" CapsuleApp -P\n");
+ Print(L" CapsuleApp -E\n");
+ Print(L" CapsuleApp -L\n");
+ Print(L" CapsuleApp -L INFO\n");
+ Print(L" CapsuleApp -F\n");
+ Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");
+ Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
+ Print(L" CapsuleApp -D <Capsule>\n");
+ Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
+ Print(L"Parameter:\n");
+ Print(L" -NR: No reset will be triggered for the capsule\n");
+ Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
+ Print(L" -OD: Delivery of Capsules via file on Mass Storage device.\n");
+ Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
+ Print(L" which is defined in UEFI specification.\n");
+ Print(L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
+ Print(L" which is defined in UEFI specification.\n");
+ Print(L" -P: Dump UEFI FMP protocol info, or get image with specified\n");
+ Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
+ Print(L" option is used.\n");
+ Print(L" -E: Dump UEFI ESRT table info.\n");
+ Print(L" -L: Dump provisioned capsule image information.\n");
+ Print(L" -F: Dump all EFI System Partition.\n");
+ Print(L" -G: Convert a BMP file to be an UX capsule,\n");
+ Print(L" according to Windows Firmware Update document\n");
+ Print(L" -N: Append a Capsule Header to an existing FMP capsule image\n");
+ Print(L" with its ImageTypeId supported by the system,\n");
+ Print(L" according to Windows Firmware Update document\n");
+ Print(L" -O: Output new Capsule file name\n");
+ Print(L" -D: Dump Capsule image header information, image payload\n");
+ Print(L" information if it is an UX capsule and FMP header\n");
+ Print(L" information if it is a FMP capsule.\n");
+}
+
+/**
+ Update Capsule image.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS Command completed successfully.
+ @retval EFI_UNSUPPORTED Command usage unsupported.
+ @retval EFI_INVALID_PARAMETER Command usage invalid.
+ @retval EFI_NOT_FOUND The input file can't be found.
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ RETURN_STATUS RStatus;
+ UINTN CapsuleBufferSize[MAX_CAPSULE_NUM];
+ VOID *CapsuleBuffer[MAX_CAPSULE_NUM];
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
+ EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
+ UINT64 MaxCapsuleSize;
+ EFI_RESET_TYPE ResetType;
+ BOOLEAN NeedReset;
+ BOOLEAN NoReset;
+ BOOLEAN CapsuleOnDisk;
+ CHAR16 *CapsuleName;
+ CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];
+ CHAR16 *MapFsStr;
+ UINTN CapsuleNum;
+ UINTN Index;
+ UINTN ParaOdIndex;
+ UINTN ParaNrIndex;
+ EFI_GUID ImageTypeId;
+ UINTN ImageIndex;
+
+ BlockDescriptors = NULL;
+ MapFsStr = NULL;
+ CapsuleNum = 0;
+
+ Status = GetArg();
+ if (EFI_ERROR(Status)) {
+ Print(L"Please use UEFI SHELL to run this application!\n", Status);
+ return Status;
+ }
+ if (Argc < 2) {
+ PrintUsage();
+ return EFI_UNSUPPORTED;
+ }
+ if (StrCmp(Argv[1], L"-D") == 0) {
+ if (Argc != 3) {
+ Print(L"CapsuleApp: Incorrect parameter count.\n");
+ return EFI_UNSUPPORTED;
+ }
+ Status = DumpCapsule(Argv[2]);
+ return Status;
+ }
+ if (StrCmp(Argv[1], L"-G") == 0) {
+ Status = CreateBmpFmp();
+ return Status;
+ }
+ if (StrCmp(Argv[1], L"-N") == 0) {
+ Status = CreateNestedFmp();
+ return Status;
+ }
+ if (StrCmp(Argv[1], L"-S") == 0) {
+ Status = DumpCapsuleStatusVariable();
+ return EFI_SUCCESS;
+ }
+ if (StrCmp(Argv[1], L"-C") == 0) {
+ Status = ClearCapsuleStatusVariable();
+ return Status;
+ }
+ if (StrCmp(Argv[1], L"-P") == 0) {
+ if (Argc == 2) {
+ DumpFmpData();
+ }
+ if (Argc >= 3) {
+ if (StrCmp(Argv[2], L"GET") != 0) {
+ Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);
+ return EFI_UNSUPPORTED;
+ } else {
+ if (Argc != 7) {
+ Print(L"CapsuleApp: Incorrect parameter count.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // FMP->GetImage()
+ //
+ RStatus = StrToGuid (Argv[3], &ImageTypeId);
+ if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {
+ Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
+ return EFI_INVALID_PARAMETER;
+ }
+ ImageIndex = StrDecimalToUintn(Argv[4]);
+ if (StrCmp(Argv[5], L"-O") != 0) {
+ Print(L"CapsuleApp: NO output file name.\n");
+ return EFI_UNSUPPORTED;
+ }
+ DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);
+ }
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (StrCmp(Argv[1], L"-E") == 0) {
+ DumpEsrtData();
+ return EFI_SUCCESS;
+ }
+
+ if (StrCmp(Argv[1], L"-L") == 0) {
+ if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {
+ DumpProvisionedCapsule(TRUE);
+ } else {
+ DumpProvisionedCapsule(FALSE);
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (StrCmp(Argv[1], L"-F") == 0) {
+ DumpAllEfiSysPartition();
+ return EFI_SUCCESS;
+ }
+
+ if (Argv[1][0] == L'-') {
+ Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
+ return EFI_UNSUPPORTED;
+ }
+
+ CapsuleFirstIndex = 1;
+ NoReset = FALSE;
+ CapsuleOnDisk = FALSE;
+ ParaOdIndex = 0;
+ ParaNrIndex = 0;
+
+ for (Index = 1; Index < Argc; Index++) {
+ if (StrCmp(Argv[Index], L"-OD") == 0) {
+ ParaOdIndex = Index;
+ CapsuleOnDisk = TRUE;
+ } else if (StrCmp(Argv[Index], L"-NR") == 0) {
+ ParaNrIndex = Index;
+ NoReset = TRUE;
+ }
+ }
+
+ if (ParaOdIndex > ParaNrIndex) {
+ if (ParaNrIndex != 0) {
+ CapsuleLastIndex = ParaNrIndex - 1;
+ } else {
+ CapsuleLastIndex = ParaOdIndex - 1;
+ }
+
+ if (ParaOdIndex == Argc -1) {
+ MapFsStr = NULL;
+ } else if (ParaOdIndex == Argc - 2) {
+ MapFsStr = Argv[Argc-1];
+ } else {
+ Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ } else if (ParaOdIndex < ParaNrIndex) {
+ if (ParaOdIndex != 0) {
+ CapsuleLastIndex = ParaOdIndex - 1;
+ if (ParaOdIndex == ParaNrIndex - 1) {
+ MapFsStr = NULL;
+ } else if (ParaOdIndex == ParaNrIndex - 2) {
+ MapFsStr = Argv[ParaOdIndex + 1];
+ } else {
+ Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ } else {
+ CapsuleLastIndex = ParaNrIndex - 1;
+ }
+ } else {
+ CapsuleLastIndex = Argc - 1;
+ }
+
+ CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
+
+ if (CapsuleFirstIndex > CapsuleLastIndex) {
+ Print(L"CapsuleApp: NO capsule image.\n");
+ return EFI_UNSUPPORTED;
+ }
+ if (CapsuleNum > MAX_CAPSULE_NUM) {
+ Print(L"CapsuleApp: Too many capsule images.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
+ ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));
+ BlockDescriptors = NULL;
+
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ CapsuleName = Argv[CapsuleFirstIndex + Index];
+ Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
+ goto Done;
+ }
+ if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
+ return EFI_INVALID_PARAMETER;
+ }
+ CapsuleNames[Index] = CapsuleName;
+ }
+
+ //
+ // Every capsule use 2 descriptor 1 for data 1 for end
+ //
+ Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ //
+ // Call the runtime service capsule.
+ //
+ NeedReset = FALSE;
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
+ if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ NeedReset = TRUE;
+ }
+ }
+ CapsuleHeaderArray[CapsuleNum] = NULL;
+
+ //
+ // Inquire platform capability of UpdateCapsule.
+ //
+ Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
+ if (EFI_ERROR(Status)) {
+ Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
+ goto Done;
+ }
+
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
+ Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ //
+ // Check whether is capsule on disk.
+ //
+ if (CapsuleOnDisk) {
+ Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);
+ if (Status != EFI_SUCCESS) {
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
+ goto Done;
+ } else {
+ if (!NoReset) {
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
+ } else {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Check whether the input capsule image has the flag of persist across system reset.
+ //
+ if (NeedReset) {
+ Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
+ if (Status != EFI_SUCCESS) {
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
+ goto Done;
+ }
+ //
+ // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
+ // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
+ //
+ // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
+ // check if -NR (no-reset) has been specified or not.
+ //
+ if (!NoReset) {
+ //
+ // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
+ // trigger a system reset to process capsule persist across a system reset.
+ //
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
+ }
+ } else {
+ //
+ // For capsule who has no reset flag, only call UpdateCapsule Service without a
+ // system reset. The service will process the capsule immediately.
+ //
+ Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
+ if (Status != EFI_SUCCESS) {
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ if (CapsuleBuffer[Index] != NULL) {
+ FreePool (CapsuleBuffer[Index]);
+ }
+ }
+
+ CleanGatherList(BlockDescriptors, CapsuleNum);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h
new file mode 100644
index 000000000..270d2359a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.h
@@ -0,0 +1,240 @@
+/** @file
+ A shell application that triggers capsule update process.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _CAPSULE_APP_H_
+#define _CAPSULE_APP_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BmpSupportLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/SortLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/ShellParameters.h>
+#include <Protocol/Shell.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/FileInfo.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/CapsuleVendor.h>
+#include <Guid/Gpt.h>
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#define CAPSULE_HEADER_SIZE 0x20
+
+#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
+#define SYSTEM_FIRMWARE_FLAG 0x50000
+#define DEVICE_FIRMWARE_FLAG 0x78010
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+
+#define MAX_CAPSULE_NUM 10
+
+//
+// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
+//
+#define MAX_FILE_NAME_SIZE 522
+#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
+
+extern UINTN Argc;
+extern CHAR16 **Argv;
+
+/**
+
+ This function parse application ARG.
+
+ @return Status
+**/
+EFI_STATUS
+GetArg (
+ VOID
+ );
+
+/**
+ Get shell protocol.
+
+ @return Pointer to shell protocol.
+
+**/
+EFI_SHELL_PROTOCOL *
+GetShellProtocol (
+ VOID
+ );
+
+
+/**
+ Read a file.
+
+ @param[in] FileName The file to be read.
+ @param[out] BufferSize The file buffer size
+ @param[out] Buffer The file buffer
+
+ @retval EFI_SUCCESS Read file successfully
+ @retval EFI_NOT_FOUND Shell protocol or file not found
+ @retval others Read file failed
+**/
+EFI_STATUS
+ReadFileToBuffer (
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ );
+
+/**
+ Write a file.
+
+ @param[in] FileName The file to be written.
+ @param[in] BufferSize The file buffer size
+ @param[in] Buffer The file buffer
+
+ @retval EFI_SUCCESS Write file successfully
+ @retval EFI_NOT_FOUND Shell protocol not found
+ @retval others Write file failed
+**/
+EFI_STATUS
+WriteFileFromBuffer (
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Dump capsule information
+
+ @param[in] CapsuleName The name of the capsule image.
+
+ @retval EFI_SUCCESS The capsule information is dumped.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsule (
+ IN CHAR16 *CapsuleName
+ );
+
+/**
+ Dump capsule status variable.
+
+ @retval EFI_SUCCESS The capsule status variable is dumped.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsuleStatusVariable (
+ VOID
+ );
+
+/**
+ Dump FMP protocol info.
+**/
+VOID
+DumpFmpData (
+ VOID
+ );
+
+/**
+ Dump FMP image data.
+
+ @param[in] ImageTypeId The ImageTypeId of the FMP image.
+ It is used to identify the FMP protocol.
+ @param[in] ImageIndex The ImageIndex of the FMP image.
+ It is the input parameter for FMP->GetImage().
+ @param[in] ImageName The file name to hold the output FMP image.
+**/
+VOID
+DumpFmpImage (
+ IN EFI_GUID *ImageTypeId,
+ IN UINTN ImageIndex,
+ IN CHAR16 *ImageName
+ );
+
+/**
+ Dump ESRT info.
+**/
+VOID
+DumpEsrtData (
+ VOID
+ );
+
+/**
+ Dump Provisioned Capsule.
+
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
+**/
+VOID
+DumpProvisionedCapsule (
+ IN BOOLEAN DumpCapsuleInfo
+ );
+
+/**
+ Dump all EFI System Partition.
+**/
+VOID
+DumpAllEfiSysPartition (
+ VOID
+ );
+
+
+/**
+ Get SimpleFileSystem from boot option file path.
+
+ @param[in] DevicePath The file path of boot option
+ @param[out] FullPath The full device path of boot device
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+ @retval others Get file system failed
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromBootOptionFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ );
+
+
+/**
+ Process Capsule On Disk.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] CapsuleBufferSize An array of UINTN to capsule images size
+ @param[in] FilePath An array of capsule images file path
+ @param[in] Map File system mapping string
+ @param[in] CapsuleNum The count of capsule images
+
+ @retval EFI_SUCCESS Capsule on disk success.
+ @retval others Capsule on disk fail.
+
+**/
+EFI_STATUS
+ProcessCapsuleOnDisk (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *CapsuleBufferSize,
+ IN CHAR16 **FilePath,
+ IN CHAR16 *Map,
+ IN UINTN CapsuleNum
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
new file mode 100644
index 000000000..6ed065983
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
@@ -0,0 +1,69 @@
+## @file
+# A shell application that triggers capsule update process.
+#
+# This application can trigger capsule update process. It can also
+# generate capsule image, or dump capsule variable information.
+#
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = CapsuleApp
+ MODULE_UNI_FILE = CapsuleApp.uni
+ FILE_GUID = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CapsuleApp.c
+ CapsuleApp.h
+ CapsuleDump.c
+ CapsuleOnDisk.c
+ AppSupport.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids]
+ gEfiGlobalVariableGuid ## CONSUMES ## GUID
+ gEfiCapsuleReportGuid ## CONSUMES ## GUID
+ gEfiFmpCapsuleGuid ## CONSUMES ## GUID
+ gWindowsUxCapsuleGuid ## CONSUMES ## GUID
+ gEfiSystemResourceTableGuid ## CONSUMES ## GUID
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+ gEfiShellParametersProtocolGuid ## CONSUMES
+ gEfiShellProtocolGuid ## CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+
+[LibraryClasses]
+ BaseLib
+ UefiApplicationEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ PrintLib
+ BmpSupportLib
+ FileHandleLib
+ UefiBootManagerLib
+ SortLib
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsuleAppExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
new file mode 100644
index 000000000..955979dcc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
@@ -0,0 +1,17 @@
+// /** @file
+// A shell application that triggers capsule update process.
+//
+// This application can trigger capsule update process. It can also
+// generate capsule image, or dump capsule variable information.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that triggers capsule update process."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application can trigger capsule update process. It can also generate capsule image, or dump capsule variable information."
+
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
new file mode 100644
index 000000000..42bd212a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CapsuleApp Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Capsule Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
new file mode 100644
index 000000000..5725e2f6d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
@@ -0,0 +1,1444 @@
+/** @file
+ Dump Capsule image information.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleApp.h"
+
+/**
+ Validate if it is valid capsule header
+
+ This function assumes the caller provided correct CapsuleHeader pointer
+ and CapsuleSize.
+
+ This function validates the fields in EFI_CAPSULE_HEADER.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapsuleSize Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN UINT64 CapsuleSize
+ );
+
+/**
+ Dump UX capsule information.
+
+ @param[in] CapsuleHeader The UX capsule header
+**/
+VOID
+DumpUxCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_DISPLAY_CAPSULE *DisplayCapsule;
+ DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;
+ Print(L"[UxCapsule]\n");
+ Print(L"CapsuleHeader:\n");
+ Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid);
+ Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize);
+ Print(L" Flags - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags);
+ Print(L" CapsuleImageSize - 0x%x\n", DisplayCapsule->CapsuleHeader.CapsuleImageSize);
+ Print(L"ImagePayload:\n");
+ Print(L" Version - 0x%x\n", DisplayCapsule->ImagePayload.Version);
+ Print(L" Checksum - 0x%x\n", DisplayCapsule->ImagePayload.Checksum);
+ Print(L" ImageType - 0x%x\n", DisplayCapsule->ImagePayload.ImageType);
+ Print(L" Mode - 0x%x\n", DisplayCapsule->ImagePayload.Mode);
+ Print(L" OffsetX - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX);
+ Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY);
+}
+
+
+/**
+ Dump a non-nested FMP capsule.
+
+ @param[in] CapsuleHeader A pointer to CapsuleHeader
+**/
+VOID
+DumpFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT64 *ItemOffsetList;
+ UINTN Index;
+ UINTN Count;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader;
+
+ Print(L"[FmpCapsule]\n");
+ Print(L"CapsuleHeader:\n");
+ Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
+ Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
+ Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);
+ Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+ Print(L"FmpHeader:\n");
+ Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version);
+ Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount);
+ Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount);
+ Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+ for (Index = 0; Index < Count; Index++) {
+ Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Index]);
+ }
+
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) {
+ Print(L"FmpPayload[%d] ImageHeader:\n", Index);
+ FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ Print(L" Version - 0x%x\n", FmpImageHeader->Version);
+ Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateImageTypeId);
+ Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex);
+ Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize);
+ Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize);
+ if (FmpImageHeader->Version >= 2) {
+ Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);
+ if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ Print(L" ImageCapsuleSupport - 0x%lx\n", FmpImageHeader->ImageCapsuleSupport);
+ }
+ }
+ }
+}
+
+/**
+ Return if there is a FMP header below capsule header.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE There is a FMP header below capsule header.
+ @retval FALSE There is not a FMP header below capsule header
+**/
+BOOLEAN
+IsNestedFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
+ UINTN Index;
+ BOOLEAN EsrtGuidFound;
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;
+ UINTN NestedCapsuleSize;
+
+ //
+ // Check ESRT
+ //
+ EsrtGuidFound = FALSE;
+ Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
+ if (!EFI_ERROR(Status)) {
+ ASSERT (Esrt != NULL);
+ EsrtEntry = (VOID *)(Esrt + 1);
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
+ if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
+ EsrtGuidFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!EsrtGuidFound) {
+ return FALSE;
+ }
+
+ //
+ // Check nested capsule header
+ // FMP GUID after ESRT one
+ //
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize- (UINTN)NestedCapsuleHeader;
+ if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {
+ return FALSE;
+ }
+ if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Dump capsule information
+
+ @param[in] CapsuleName The name of the capsule image.
+
+ @retval EFI_SUCCESS The capsule information is dumped.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsule (
+ IN CHAR16 *CapsuleName
+ )
+{
+ VOID *Buffer;
+ UINTN FileSize;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ EFI_STATUS Status;
+
+ Buffer = NULL;
+ Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);
+ if (EFI_ERROR(Status)) {
+ Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);
+ goto Done;
+ }
+ if (!IsValidCapsuleHeader (Buffer, FileSize)) {
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ CapsuleHeader = Buffer;
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
+ DumpUxCapsule(CapsuleHeader);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+ DumpFmpCapsule(CapsuleHeader);
+ }
+ if (IsNestedFmpCapsule(CapsuleHeader)) {
+ Print(L"[NestedCapsule]\n");
+ Print(L"CapsuleHeader:\n");
+ Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
+ Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
+ Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);
+ Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
+ DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));
+ }
+
+Done:
+ if (Buffer != NULL) {
+ FreePool(Buffer);
+ }
+ return Status;
+}
+
+/**
+ Dump capsule status variable.
+
+ @retval EFI_SUCCESS The capsule status variable is dumped.
+ @retval EFI_UNSUPPORTED Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsuleStatusVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CHAR16 CapsuleVarName[20];
+ CHAR16 *TempVarName;
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;
+ UINTN CapsuleFileNameSize;
+ CHAR16 CapsuleIndexData[12];
+ CHAR16 *CapsuleIndex;
+ CHAR16 *CapsuleFileName;
+ CHAR16 *CapsuleTarget;
+
+ Status = GetVariable2(
+ L"CapsuleMax",
+ &gEfiCapsuleReportGuid,
+ (VOID **)&CapsuleIndex,
+ NULL
+ );
+ if (!EFI_ERROR(Status)) {
+ ASSERT (CapsuleIndex != NULL);
+ CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
+ CapsuleIndexData[11] = 0;
+ Print(L"CapsuleMax - %s\n", CapsuleIndexData);
+ FreePool(CapsuleIndex);
+ }
+ Status = GetVariable2(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ (VOID **)&CapsuleIndex,
+ NULL
+ );
+ if (!EFI_ERROR(Status)) {
+ ASSERT (CapsuleIndex != NULL);
+ CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
+ CapsuleIndexData[11] = 0;
+ Print(L"CapsuleLast - %s\n", CapsuleIndexData);
+ FreePool(CapsuleIndex);
+ }
+
+
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ Index = 0;
+
+ while (TRUE) {
+ UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
+
+ Status = GetVariable2 (
+ CapsuleVarName,
+ &gEfiCapsuleReportGuid,
+ (VOID **) &CapsuleResult,
+ NULL
+ );
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ } else if (EFI_ERROR(Status)) {
+ continue;
+ }
+ ASSERT (CapsuleResult != NULL);
+
+ //
+ // display capsule process status
+ //
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {
+ Print (L"CapsuleName: %s\n", CapsuleVarName);
+ Print (L" Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid);
+ Print (L" Capsule ProcessedTime: %t\n", &CapsuleResult->CapsuleProcessed);
+ Print (L" Capsule Status: %r\n", CapsuleResult->CapsuleStatus);
+ }
+
+ if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) {
+ CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);
+ Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version);
+ Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex);
+ Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex);
+ Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId);
+ CapsuleFileName = (CHAR16 *)(CapsuleResultFmp + 1);
+ Print(L" Capsule FMP CapsuleFileName: \"%s\"\n", CapsuleFileName);
+ CapsuleFileNameSize = StrSize(CapsuleFileName);
+ CapsuleTarget = (CHAR16 *)((UINTN)CapsuleFileName + CapsuleFileNameSize);
+ Print(L" Capsule FMP CapsuleTarget: \"%s\"\n", CapsuleTarget);
+ }
+ }
+
+ FreePool(CapsuleResult);
+
+ Index++;
+ if (Index > 0xFFFF) {
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+CHAR8 *mFwTypeString[] = {
+ "Unknown",
+ "SystemFirmware",
+ "DeviceFirmware",
+ "UefiDriver",
+};
+
+CHAR8 *mLastAttemptStatusString[] = {
+ "Success",
+ "Error: Unsuccessful",
+ "Error: Insufficient Resources",
+ "Error: Incorrect Version",
+ "Error: Invalid Format",
+ "Error: Auth Error",
+ "Error: Power Event AC",
+ "Error: Power Event Battery",
+ "Error: Unsatisfied Dependencies",
+};
+
+/**
+ Convert FwType to a string.
+
+ @param[in] FwType FwType in ESRT
+
+ @return a string for FwType.
+**/
+CHAR8 *
+FwTypeToString (
+ IN UINT32 FwType
+ )
+{
+ if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) {
+ return mFwTypeString[FwType];
+ } else {
+ return "Invalid";
+ }
+}
+
+/**
+ Convert LastAttemptStatus to a string.
+
+ @param[in] LastAttemptStatus LastAttemptStatus in FMP or ESRT
+
+ @return a string for LastAttemptStatus.
+**/
+CHAR8 *
+LastAttemptStatusToString (
+ IN UINT32 LastAttemptStatus
+ )
+{
+ if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / sizeof(mLastAttemptStatusString[0])) {
+ return mLastAttemptStatusString[LastAttemptStatus];
+ } else {
+ return "Error: Unknown";
+ }
+}
+
+/**
+ Dump ESRT entry.
+
+ @param[in] EsrtEntry ESRT entry
+**/
+VOID
+DumpEsrtEntry (
+ IN EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry
+ )
+{
+ Print(L" FwClass - %g\n", &EsrtEntry->FwClass);
+ Print(L" FwType - 0x%x (%a)\n", EsrtEntry->FwType, FwTypeToString(EsrtEntry->FwType));
+ Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion);
+ Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion);
+ Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags);
+ Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVersion);
+ Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus));
+}
+
+/**
+ Dump ESRT table.
+
+ @param[in] Esrt ESRT table
+**/
+VOID
+DumpEsrt (
+ IN EFI_SYSTEM_RESOURCE_TABLE *Esrt
+ )
+{
+ UINTN Index;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
+
+ if (Esrt == NULL) {
+ return ;
+ }
+
+ Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n");
+ Print(L"FwResourceCount - 0x%x\n", Esrt->FwResourceCount);
+ Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax);
+ Print(L"FwResourceVersion - 0x%lx\n", Esrt->FwResourceVersion);
+
+ EsrtEntry = (VOID *)(Esrt + 1);
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++) {
+ Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index);
+ DumpEsrtEntry(EsrtEntry);
+ EsrtEntry++;
+ }
+}
+
+/**
+ Dump ESRT info.
+**/
+VOID
+DumpEsrtData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;
+
+ Print(L"##############\n");
+ Print(L"# ESRT TABLE #\n");
+ Print(L"##############\n");
+
+ Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
+ if (EFI_ERROR(Status)) {
+ Print(L"ESRT - %r\n", Status);
+ return;
+ }
+ DumpEsrt(Esrt);
+ Print(L"\n");
+}
+
+
+/**
+ Dump capsule information from CapsuleHeader
+
+ @param[in] CapsuleHeader The CapsuleHeader of the capsule image.
+
+ @retval EFI_SUCCESS The capsule information is dumped.
+
+**/
+EFI_STATUS
+DumpCapsuleFromBuffer (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
+ DumpUxCapsule (CapsuleHeader);
+ return EFI_SUCCESS;
+ }
+
+ if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+ DumpFmpCapsule (CapsuleHeader);
+ }
+ if (IsNestedFmpCapsule (CapsuleHeader)) {
+ Print (L"[NestedCapusule]\n");
+ Print (L"CapsuleHeader:\n");
+ Print (L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
+ Print (L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
+ Print (L" Flags - 0x%x\n", CapsuleHeader->Flags);
+ Print (L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
+ DumpFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is called to upper case given unicode string.
+
+ @param[in] Str String to upper case
+
+ @retval upper cased string after process
+
+**/
+STATIC
+CHAR16 *
+UpperCaseString (
+ IN CHAR16 *Str
+ )
+{
+ CHAR16 *Cptr;
+
+ for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
+ if (L'a' <= *Cptr && *Cptr <= L'z') {
+ *Cptr = *Cptr - L'a' + L'A';
+ }
+ }
+
+ return Str;
+}
+
+/**
+ This routine is used to return substring before period '.' or '\0'
+ Caller should respsonsible of substr space allocation & free
+
+ @param[in] Str String to check
+ @param[out] SubStr First part of string before period or '\0'
+ @param[out] SubStrLen Length of first part of string
+
+**/
+STATIC
+VOID
+GetSubStringBeforePeriod (
+ IN CHAR16 *Str,
+ OUT CHAR16 *SubStr,
+ OUT UINTN *SubStrLen
+ )
+{
+ UINTN Index;
+ for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
+ SubStr[Index] = Str[Index];
+ }
+
+ SubStr[Index] = L'\0';
+ *SubStrLen = Index;
+}
+
+/**
+ This routine pad the string in tail with input character.
+
+ @param[in] StrBuf Str buffer to be padded, should be enough room for
+ @param[in] PadLen Expected padding length
+ @param[in] Character Character used to pad
+
+**/
+STATIC
+VOID
+PadStrInTail (
+ IN CHAR16 *StrBuf,
+ IN UINTN PadLen,
+ IN CHAR16 Character
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; StrBuf[Index] != L'\0'; Index++);
+
+ while(PadLen != 0) {
+ StrBuf[Index] = Character;
+ Index++;
+ PadLen--;
+ }
+
+ StrBuf[Index] = L'\0';
+}
+
+/**
+ This routine find the offset of the last period '.' of string. if No period exists
+ function FileNameExtension is set to L'\0'
+
+ @param[in] FileName File name to split between last period
+ @param[out] FileNameFirst First FileName before last period
+ @param[out] FileNameExtension FileName after last period
+
+**/
+STATIC
+VOID
+SplitFileNameExtension (
+ IN CHAR16 *FileName,
+ OUT CHAR16 *FileNameFirst,
+ OUT CHAR16 *FileNameExtension
+ )
+{
+ UINTN Index;
+ UINTN StringLen;
+
+ StringLen = StrLen(FileName);
+ for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);
+
+ //
+ // No period exists. No FileName Extension
+ //
+ if (Index == 0 && FileName[Index] != L'.') {
+ FileNameExtension[0] = L'\0';
+ Index = StringLen;
+ } else {
+ StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]);
+ }
+
+ //
+ // Copy First file name
+ //
+ StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index);
+ FileNameFirst[Index] = L'\0';
+}
+
+/**
+ The function is called by PerformQuickSort to sort file name in alphabet.
+
+ @param[in] Left The pointer to first buffer.
+ @param[in] Right The pointer to second buffer.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return <0 Buffer1 is less than Buffer2.
+ @return >0 Buffer1 is greater than Buffer2.
+
+**/
+INTN
+CompareFileNameInAlphabet (
+ IN VOID *Left,
+ IN VOID *Right
+ )
+{
+ EFI_FILE_INFO *FileInfo1;
+ EFI_FILE_INFO *FileInfo2;
+ CHAR16 FileName1[MAX_FILE_NAME_SIZE];
+ CHAR16 FileExtension1[MAX_FILE_NAME_SIZE];
+ CHAR16 FileName2[MAX_FILE_NAME_SIZE];
+ CHAR16 FileExtension2[MAX_FILE_NAME_SIZE];
+ CHAR16 TempSubStr1[MAX_FILE_NAME_SIZE];
+ CHAR16 TempSubStr2[MAX_FILE_NAME_SIZE];
+ UINTN SubStrLen1;
+ UINTN SubStrLen2;
+ INTN SubStrCmpResult;
+
+ FileInfo1 = (EFI_FILE_INFO *) (*(UINTN *)Left);
+ FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)Right);
+
+ SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1);
+ SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2);
+
+ UpperCaseString (FileName1);
+ UpperCaseString (FileName2);
+
+ GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1);
+ GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2);
+
+ if (SubStrLen1 > SubStrLen2) {
+ //
+ // Substr in NewFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' ');
+ } else if (SubStrLen1 < SubStrLen2){
+ //
+ // Substr in ListedFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' ');
+ }
+
+ SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2, MAX_FILE_NAME_LEN);
+ if (SubStrCmpResult != 0) {
+ return SubStrCmpResult;
+ }
+
+ UpperCaseString (FileExtension1);
+ UpperCaseString (FileExtension2);
+
+ return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN);
+}
+
+/**
+ Dump capsule information from disk.
+
+ @param[in] Fs The device path of disk.
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
+
+ @retval EFI_SUCCESS The capsule information is dumped.
+
+**/
+EFI_STATUS
+DumpCapsuleFromDisk (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs,
+ IN BOOLEAN DumpCapsuleInfo
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE *Root;
+ EFI_FILE *DirHandle;
+ EFI_FILE *FileHandle;
+ UINTN Index;
+ UINTN FileSize;
+ VOID *FileBuffer;
+ EFI_FILE_INFO **FileInfoBuffer;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileCount;
+ BOOLEAN NoFile;
+
+ DirHandle = NULL;
+ FileHandle = NULL;
+ Index = 0;
+ FileInfoBuffer = NULL;
+ FileInfo = NULL;
+ FileCount = 0;
+ NoFile = FALSE;
+
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot open volume. Status = %r\n", Status);
+ goto Done;
+ }
+
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status);
+ goto Done;
+ }
+
+ //
+ // Get file count first
+ //
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
+ do {
+ if (EFI_ERROR (Status) || FileInfo == NULL) {
+ Print (L"Get File Info Fail. Status = %r\n", Status);
+ goto Done;
+ }
+
+ if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {
+ FileCount++;
+ }
+
+ Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);
+ if (EFI_ERROR (Status)) {
+ Print (L"Get Next File Fail. Status = %r\n", Status);
+ goto Done;
+ }
+ } while (!NoFile);
+
+ if (FileCount == 0) {
+ Print (L"Error: No capsule file found!\n");
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount);
+ if (FileInfoBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ NoFile = FALSE;
+
+ //
+ // Get all file info
+ //
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
+ do {
+ if (EFI_ERROR (Status) || FileInfo == NULL) {
+ Print (L"Get File Info Fail. Status = %r\n", Status);
+ goto Done;
+ }
+
+ if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {
+ FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
+ }
+
+ Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);
+ if (EFI_ERROR (Status)) {
+ Print (L"Get Next File Fail. Status = %r\n", Status);
+ goto Done;
+ }
+ } while (!NoFile);
+
+ //
+ // Sort FileInfoBuffer by alphabet order
+ //
+ PerformQuickSort (
+ FileInfoBuffer,
+ FileCount,
+ sizeof (FileInfo),
+ (SORT_COMPARE) CompareFileNameInAlphabet
+ );
+
+ Print (L"The capsules will be performed by following order:\n");
+
+ for (Index = 0; Index < FileCount; Index++) {
+ Print (L" %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);
+ }
+
+ if (!DumpCapsuleInfo) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ Print(L"The infomation of the capsules:\n");
+
+ for (Index = 0; Index < FileCount; Index++) {
+ FileHandle = NULL;
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
+ FileHandleClose (FileHandle);
+ goto Done;
+ }
+
+ FileBuffer = AllocatePool (FileSize);
+ if (FileBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
+ FileHandleClose (FileHandle);
+ FreePool (FileBuffer);
+ goto Done;
+ }
+
+ Print (L"**************************\n");
+ Print (L" %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);
+ Print (L"**************************\n");
+ DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);
+ FileHandleClose (FileHandle);
+ FreePool (FileBuffer);
+ }
+
+Done:
+ if (FileInfoBuffer != NULL) {
+ for (Index = 0; Index < FileCount; Index++) {
+ if (FileInfoBuffer[Index] != NULL) {
+ FreePool (FileInfoBuffer[Index]);
+ }
+ }
+ FreePool (FileInfoBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Dump capsule inforomation form Gather list.
+
+ @param[in] BlockDescriptors The block descriptors for the capsule images
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
+
+**/
+VOID
+DumpBlockDescriptors (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
+ IN BOOLEAN DumpCapsuleInfo
+ )
+{
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
+
+ TempBlockPtr = BlockDescriptors;
+
+ while (TRUE) {
+ if (TempBlockPtr->Length != 0) {
+ if (DumpCapsuleInfo) {
+ Print(L"******************************************************\n");
+ }
+ Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr->Union.DataBlock, TempBlockPtr->Length);
+ if (DumpCapsuleInfo) {
+ Print(L"******************************************************\n");
+ DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) TempBlockPtr->Union.DataBlock);
+ }
+ TempBlockPtr += 1;
+ } else {
+ if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) {
+ break;
+ } else {
+ TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockPtr->Union.ContinuationPointer;
+ }
+ }
+ }
+}
+
+/**
+ Dump Provisioned Capsule.
+
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
+
+**/
+VOID
+DumpProvisionedCapsule (
+ IN BOOLEAN DumpCapsuleInfo
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS *CapsuleDataPtr64;
+ UINT16 *BootNext;
+ CHAR16 BootOptionName[20];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+
+ Index = 0;
+ CapsuleDataPtr64 = NULL;
+ BootNext = NULL;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ Print (L"Get Shell Protocol Fail\n");
+ return ;
+ }
+
+ //
+ // Dump capsule provisioned on Memory
+ //
+ Print (L"#########################\n");
+ Print (L"### Capsule on Memory ###\n");
+ Print (L"#########################\n");
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ while (TRUE) {
+ if (Index > 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
+ 0,
+ Index,
+ 0
+ );
+ }
+
+ Status = GetVariable2 (
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ (VOID **) &CapsuleDataPtr64,
+ NULL
+ );
+ if (EFI_ERROR (Status) || CapsuleDataPtr64 == NULL) {
+ if (Index == 0) {
+ Print (L"No data.\n");
+ }
+ break;
+ }
+
+ Index++;
+ Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64);
+ DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo);
+ }
+
+ //
+ // Dump capsule provisioned on Disk
+ //
+ Print (L"#########################\n");
+ Print (L"### Capsule on Disk #####\n");
+ Print (L"#########################\n");
+ Status = GetVariable2 (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ (VOID **) &BootNext,
+ NULL
+ );
+ if (EFI_ERROR (Status) || BootNext == NULL) {
+ Print (L"Get BootNext Variable Fail. Status = %r\n", Status);
+ } else {
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext);
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Display description and device path
+ //
+ GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs);
+ if(!EFI_ERROR (Status)) {
+ Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description);
+ Print (L" %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE));
+ DumpCapsuleFromDisk (Fs, DumpCapsuleInfo);
+ }
+ }
+ }
+}
+
+/**
+ Dump FMP information.
+
+ @param[in] ImageInfoSize The size of ImageInfo, in bytes.
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+ @param[in] PackageVersion The version of package.
+ @param[in] PackageVersionName The version name of package.
+**/
+VOID
+DumpFmpImageInfo (
+ IN UINTN ImageInfoSize,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ IN UINT32 DescriptorVersion,
+ IN UINT8 DescriptorCount,
+ IN UINTN DescriptorSize,
+ IN UINT32 PackageVersion,
+ IN CHAR16 *PackageVersionName
+ )
+{
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
+ UINTN Index;
+ UINTN Index2;
+
+ Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion);
+ Print(L" DescriptorCount - 0x%x\n", DescriptorCount);
+ Print(L" DescriptorSize - 0x%x\n", DescriptorSize);
+ Print(L" PackageVersion - 0x%x\n", PackageVersion);
+ Print(L" PackageVersionName - \"%s\"\n", PackageVersionName);
+ CurrentImageInfo = ImageInfo;
+ for (Index = 0; Index < DescriptorCount; Index++) {
+ Print(L" ImageDescriptor (%d)\n", Index);
+ Print(L" ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex);
+ Print(L" ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId);
+ Print(L" ImageId - 0x%lx\n", CurrentImageInfo->ImageId);
+ Print(L" ImageIdName - \"%s\"\n", CurrentImageInfo->ImageIdName);
+ Print(L" Version - 0x%x\n", CurrentImageInfo->Version);
+ Print(L" VersionName - \"%s\"\n", CurrentImageInfo->VersionName);
+ Print(L" Size - 0x%x\n", CurrentImageInfo->Size);
+ Print(L" AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported);
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+ Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+ Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE);
+ Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE);
+ Print(L" AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting);
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+ Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+ Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE);
+ Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE);
+ Print(L" Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities);
+ Print(L" COMPATIB_CHECK_SUPPORTED - 0x%lx\n", CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED);
+ if (DescriptorVersion > 1) {
+ Print(L" LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion);
+ if (DescriptorVersion > 2) {
+ Print(L" LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion);
+ Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus));
+ Print(L" HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance);
+ if (DescriptorVersion > 3) {
+ Print(L" Dependencies - ");
+ if (CurrentImageInfo->Dependencies == NULL) {
+ Print(L"NULL\n");
+ } else {
+ Index2 = 0;
+ do {
+ Print(L"%02x ", CurrentImageInfo->Dependencies->Dependencies[Index2]);
+ } while (CurrentImageInfo->Dependencies->Dependencies[Index2 ++] != EFI_FMP_DEP_END);
+ Print(L"\n");
+ }
+ }
+ }
+ }
+ //
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+ //
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
+ }
+}
+
+/**
+ Dump FMP package information.
+
+ @param[in] PackageVersion The version of package.
+ @param[in] PackageVersionName The version name of package.
+ @param[in] PackageVersionNameMaxLen The maximum length of PackageVersionName.
+ @param[in] AttributesSupported Package attributes that are supported by this device.
+ @param[in] AttributesSetting Package attributes.
+**/
+VOID
+DumpFmpPackageInfo (
+ IN UINT32 PackageVersion,
+ IN CHAR16 *PackageVersionName,
+ IN UINT32 PackageVersionNameMaxLen,
+ IN UINT64 AttributesSupported,
+ IN UINT64 AttributesSetting
+ )
+{
+ Print(L" PackageVersion - 0x%x\n", PackageVersion);
+ Print(L" PackageVersionName - \"%s\"\n", PackageVersionName);
+ Print(L" PackageVersionNameMaxLen - 0x%x\n", PackageVersionNameMaxLen);
+ Print(L" AttributesSupported - 0x%lx\n", AttributesSupported);
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+ Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+ Print(L" AttributesSetting - 0x%lx\n", AttributesSetting);
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+ Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+}
+
+/**
+ Dump FMP protocol info.
+**/
+VOID
+DumpFmpData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINTN ImageInfoSize;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ UINT32 PackageVersionNameMaxLen;
+ UINT64 AttributesSupported;
+ UINT64 AttributesSetting;
+
+ Print(L"############\n");
+ Print(L"# FMP DATA #\n");
+ Print(L"############\n");
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);
+ return;
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &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)) {
+ Print(L"FMP (%d) ImageInfo - %r\n", Index, Status);
+ FreePool(FmpImageInfoBuf);
+ continue;
+ }
+
+ Print(L"FMP (%d) ImageInfo:\n", Index);
+ DumpFmpImageInfo(
+ ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ FmpImageInfoDescriptorVer, // DescriptorVersion
+ FmpImageInfoCount, // DescriptorCount
+ DescriptorSize, // DescriptorSize
+ PackageVersion, // PackageVersion
+ PackageVersionName // PackageVersionName
+ );
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+ FreePool(FmpImageInfoBuf);
+
+ //
+ // Get package info
+ //
+ PackageVersionName = NULL;
+ Status = Fmp->GetPackageInfo (
+ Fmp,
+ &PackageVersion, // PackageVersion
+ &PackageVersionName, // PackageVersionName
+ &PackageVersionNameMaxLen, // PackageVersionNameMaxLen
+ &AttributesSupported, // AttributesSupported
+ &AttributesSetting // AttributesSetting
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"FMP (%d) PackageInfo - %r\n", Index, Status);
+ } else {
+ Print(L"FMP (%d) ImageInfo:\n", Index);
+ DumpFmpPackageInfo(
+ PackageVersion, // PackageVersion
+ PackageVersionName, // PackageVersionName
+ PackageVersionNameMaxLen, // PackageVersionNameMaxLen
+ AttributesSupported, // AttributesSupported
+ AttributesSetting // AttributesSetting
+ );
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+ }
+ }
+ Print(L"\n");
+
+EXIT:
+ FreePool(HandleBuffer);
+}
+
+/**
+ Check if the ImageInfo includes the ImageTypeId.
+
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+ @param[in] ImageTypeId A unique GUID identifying the firmware image type.
+
+ @return TRUE This ImageInfo includes the ImageTypeId
+ @return FALSE This ImageInfo does not include the ImageTypeId
+**/
+BOOLEAN
+IsThisFmpImageInfo (
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ IN UINT8 DescriptorCount,
+ IN UINTN DescriptorSize,
+ IN EFI_GUID *ImageTypeId
+ )
+{
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
+ UINTN Index;
+
+ CurrentImageInfo = ImageInfo;
+ for (Index = 0; Index < DescriptorCount; Index++) {
+ if (CompareGuid (&CurrentImageInfo->ImageTypeId, ImageTypeId)) {
+ return TRUE;
+ }
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
+ }
+ return FALSE;
+}
+
+/**
+ return the FMP whoes ImageInfo includes the ImageTypeId.
+
+ @param[in] ImageTypeId A unique GUID identifying the firmware image type.
+
+ @return The FMP whoes ImageInfo includes the ImageTypeId
+**/
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL *
+FindFmpFromImageTypeId (
+ IN EFI_GUID *ImageTypeId
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *TargetFmp;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINTN ImageInfoSize;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);
+ return NULL;
+ }
+
+ TargetFmp = NULL;
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &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) {
+ FreePool(HandleBuffer);
+ Print(L"Out of resource\n");
+ return NULL;
+ }
+
+ 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);
+ }
+
+ if (IsThisFmpImageInfo (FmpImageInfoBuf, FmpImageInfoCount, DescriptorSize, ImageTypeId)) {
+ TargetFmp = Fmp;
+ }
+ FreePool(FmpImageInfoBuf);
+ if (TargetFmp != NULL) {
+ break;
+ }
+ }
+ FreePool(HandleBuffer);
+ return TargetFmp;
+}
+
+/**
+ Dump FMP image data.
+
+ @param[in] ImageTypeId The ImageTypeId of the FMP image.
+ It is used to identify the FMP protocol.
+ @param[in] ImageIndex The ImageIndex of the FMP image.
+ It is the input parameter for FMP->GetImage().
+ @param[in] ImageName The file name to hold the output FMP image.
+**/
+VOID
+DumpFmpImage (
+ IN EFI_GUID *ImageTypeId,
+ IN UINTN ImageIndex,
+ IN CHAR16 *ImageName
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ VOID *Image;
+ UINTN ImageSize;
+
+ Fmp = FindFmpFromImageTypeId (ImageTypeId);
+ if (Fmp == NULL) {
+ Print(L"No FMP include ImageTypeId %g\n", ImageTypeId);
+ return ;
+ }
+
+ if (ImageIndex > 0xFF) {
+ Print(L"ImageIndex 0x%x too big\n", ImageIndex);
+ return ;
+ }
+
+ Image = Fmp;
+ ImageSize = 0;
+ Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Fmp->GetImage - %r\n", Status);
+ return ;
+ }
+
+ Image = AllocatePool (ImageSize);
+ if (Image == NULL) {
+ Print(L"Allocate FmpImage 0x%x - %r\n", ImageSize, EFI_OUT_OF_RESOURCES);
+ return ;
+ }
+
+ Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);
+ if (EFI_ERROR(Status)) {
+ Print(L"Fmp->GetImage - %r\n", Status);
+ return ;
+ }
+
+ Status = WriteFileFromBuffer(ImageName, ImageSize, Image);
+ Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status);
+
+ FreePool (Image);
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
new file mode 100644
index 000000000..dba50b320
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
@@ -0,0 +1,842 @@
+/** @file
+ Process Capsule On Disk.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleApp.h"
+
+EFI_GUID mCapsuleOnDiskBootOptionGuid = { 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 } };
+
+/**
+ Get file name from file path.
+
+ @param FilePath File path.
+
+ @return Pointer to file name.
+
+**/
+CHAR16 *
+GetFileNameFromPath (
+ CHAR16 *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ SHELL_FILE_HANDLE Handle;
+ EFI_FILE_INFO *FileInfo;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ return NULL;
+ }
+
+ //
+ // Open file by FileName.
+ //
+ Status = ShellProtocol->OpenFileByName (
+ FilePath,
+ &Handle,
+ EFI_FILE_MODE_READ
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get file name from EFI_FILE_INFO.
+ //
+ FileInfo = ShellProtocol->GetFileInfo (Handle);
+ ShellProtocol->CloseFile (Handle);
+ if (FileInfo == NULL) {
+ return NULL;
+ }
+
+ return FileInfo->FileName;
+}
+
+/**
+ Check if the device path is EFI system Partition.
+
+ @param DevicePath The ESP device path.
+
+ @retval TRUE DevicePath is a device path for ESP.
+ @retval FALSE DevicePath is not a device path for ESP.
+
+**/
+BOOLEAN
+IsEfiSysPartitionDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+
+ //
+ // Check if the device path contains GPT node
+ //
+ TempDevicePath = DevicePath;
+
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
+ Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+ if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
+ break;
+ }
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
+ return EFI_ERROR (Status) ? FALSE : TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Dump all EFI System Partition.
+
+**/
+VOID
+DumpAllEfiSysPartition (
+ VOID
+ )
+{
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN NumberEfiSystemPartitions;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+
+ NumberEfiSystemPartitions = 0;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ Print (L"Get Shell Protocol Fail\n");;
+ return ;
+ }
+
+ Print (L"EFI System Partition list:\n");
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ if (IsEfiSysPartitionDevicePath (DevicePath)) {
+ NumberEfiSystemPartitions++;
+ Print(L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
+ }
+ }
+
+ if (NumberEfiSystemPartitions == 0) {
+ Print(L" No ESP found.\n");
+ }
+}
+
+/**
+ Check if capsule is provisioned.
+
+ @retval TRUE Capsule is provisioned previously.
+ @retval FALSE No capsule is provisioned.
+
+**/
+BOOLEAN
+IsCapsuleProvisioned (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ OsIndication = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (!EFI_ERROR (Status) &&
+ (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get one active Efi System Partition.
+
+ @param[out] FsDevicePath The device path of Fs
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+
+**/
+EFI_STATUS
+GetEfiSysPartition (
+ OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ if (IsEfiSysPartitionDevicePath (DevicePath)) {
+ Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
+ if (!EFI_ERROR (Status)) {
+ *FsDevicePath = DevicePath;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Check if Active Efi System Partition within GPT is in the device path.
+
+ @param[in] DevicePath The device path
+ @param[out] FsDevicePath The device path of Fs
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+ @retval others Get file system failed
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromDevPath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+
+ //
+ // Check if the device path contains GPT node
+ //
+ TempDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
+ Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+ if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
+ break;
+ }
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
+
+ //
+ // Search for simple file system on this handler
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
+ if (!EFI_ERROR (Status)) {
+ *FsDevicePath = DevicePathFromHandle (Handle);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get SimpleFileSystem from boot option file path.
+
+ @param[in] DevicePath The file path of boot option
+ @param[out] FullPath The full device path of boot device
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+ @retval others Get file system failed
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromBootOptionFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *FsFullPath;
+
+ CurFullPath = NULL;
+ FsFullPath = NULL;
+ //
+ // Try every full device Path generated from bootoption
+ //
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
+
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+
+ if (CurFullPath == NULL) {
+ //
+ // No Active EFI system partition is found in BootOption device path
+ //
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr;
+
+ DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
+ if (DevicePathStr != NULL){
+ DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
+ FreePool (DevicePathStr);
+ }
+ );
+
+ Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
+ } while (EFI_ERROR (Status));
+
+ if (*Fs != NULL) {
+ *FullPath = FsFullPath;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Get a valid SimpleFileSystem within EFI system partition.
+
+ @param[in] Map The FS mapping capsule write to
+ @param[out] BootNext The value of BootNext Variable
+ @param[out] Fs The file system within EfiSysPartition
+ @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable
+
+ @retval EFI_SUCCESS Get FS successfully
+ @retval EFI_NOT_FOUND No valid FS found
+ @retval others Get FS failed
+
+**/
+EFI_STATUS
+GetUpdateFileSystem (
+ IN CHAR16 *Map,
+ OUT UINT16 *BootNext,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs,
+ OUT BOOLEAN *UpdateBootNext
+)
+{
+ EFI_STATUS Status;
+ CHAR16 BootOptionName[20];
+ UINTN Index;
+ CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+ UINT16 *BootNextData;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer;
+ UINTN BootOptionCount;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+
+ MappedDevicePath = NULL;
+ BootOptionBuffer = NULL;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ Print (L"Get Shell Protocol Fail\n");;
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 1. If Fs is not assigned and there are capsule provisioned before,
+ // Get EFI system partition from BootNext.
+ //
+ if (IsCapsuleProvisioned () && Map == NULL) {
+ Status = GetVariable2 (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ (VOID **)&BootNextData,
+ NULL
+ );
+ if (EFI_ERROR (Status) || BootNextData == NULL) {
+ Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
+ return EFI_NOT_FOUND;
+ } else {
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
+ if (!EFI_ERROR (Status)) {
+ DevicePath = BootNextOption.FilePath;
+ Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
+ if (!EFI_ERROR (Status)) {
+ *UpdateBootNext = FALSE;
+ Print(L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
+ Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ //
+ // Check if Map is valid.
+ //
+ if (Map != NULL) {
+ MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
+ if (MappedDevicePath == NULL) {
+ Print(L"'%s' is not a valid mapping.\n", Map);
+ return EFI_INVALID_PARAMETER;
+ } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
+ Print(L"'%s' is not a EFI System Partition.\n", Map);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 2. Get EFI system partition form boot options.
+ //
+ BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ if ( (BootOptionBuffer == NULL) ||
+ (BootOptionCount == 0 && Map == NULL)
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // Get the boot option from the link list
+ //
+ DevicePath = BootOptionBuffer[Index].FilePath;
+
+ //
+ // Skip inactive or legacy boot options
+ //
+ if ((BootOptionBuffer[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
+ DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
+ continue;
+ }
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr;
+
+ DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
+ if (DevicePathStr != NULL){
+ DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
+ FreePool (DevicePathStr);
+ } else {
+ DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
+ }
+ );
+
+ Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
+ if (!EFI_ERROR (Status)) {
+ if (Map == NULL) {
+ *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
+ *UpdateBootNext = TRUE;
+ Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
+ Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+
+ if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
+ *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
+ *UpdateBootNext = TRUE;
+ Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
+ //
+ if (Map != NULL) {
+ //
+ // If map is assigned, try to get ESP from mapped Fs.
+ //
+ DevicePath = DuplicateDevicePath (MappedDevicePath);
+ Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map, Status);
+ return EFI_NOT_FOUND;
+ }
+ Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
+ } else {
+ Status = GetEfiSysPartition (&DevicePath, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error: Cannot find a EFI system partition!\n");
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Print (L"Create Boot option for capsule on disk:\n");
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ L"UEFI Capsule On Disk",
+ DevicePath,
+ (UINT8 *) &mCapsuleOnDiskBootOptionGuid,
+ sizeof(EFI_GUID)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1); {
+ if (!EFI_ERROR (Status)) {
+ *UpdateBootNext = TRUE;
+ *BootNext = (UINT16) NewOption.OptionNumber;
+ Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText(DevicePath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Print (L"ERROR: Cannot create boot option! - %r\n", Status);
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Write files to a given SimpleFileSystem.
+
+ @param[in] Buffer The buffer array
+ @param[in] BufferSize The buffer size array
+ @param[in] FileName The file name array
+ @param[in] BufferNum The buffer number
+ @param[in] Fs The SimpleFileSystem handle to be written
+
+ @retval EFI_SUCCESS Write file successfully
+ @retval EFI_NOT_FOUND SFS protocol not found
+ @retval others Write file failed
+
+**/
+EFI_STATUS
+WriteUpdateFile (
+ IN VOID **Buffer,
+ IN UINTN *BufferSize,
+ IN CHAR16 **FileName,
+ IN UINTN BufferNum,
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
+)
+{
+ EFI_STATUS Status;
+ EFI_FILE *Root;
+ EFI_FILE *FileHandle;
+ EFI_FILE_PROTOCOL *DirHandle;
+ UINT64 FileInfo;
+ VOID *Filebuffer;
+ UINTN FileSize;
+ UINTN Index;
+
+ DirHandle = NULL;
+ FileHandle = NULL;
+ Index = 0;
+
+ //
+ // Open Root from SFS
+ //
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot open volume. Status = %r\n", Status);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Ensure that efi and updatecapsule directories exist
+ //
+ Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
+ if (EFI_ERROR (Status)) {
+ Print(L"Unable to create %s directory\n", L"\\EFI");
+ return EFI_NOT_FOUND;
+ }
+ }
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
+ if (EFI_ERROR (Status)) {
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
+ if (EFI_ERROR (Status)) {
+ Print(L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ for (Index = 0; Index < BufferNum; Index++) {
+ FileHandle = NULL;
+
+ //
+ // Open UpdateCapsule file
+ //
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to create %s file\n", FileName[Index]);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Empty the file contents
+ //
+ Status = FileHandleGetSize (FileHandle, &FileInfo);
+ if (EFI_ERROR (Status)) {
+ FileHandleClose (FileHandle);
+ Print (L"Error Reading %s\n", FileName[Index]);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If the file size is already 0, then it has been empty.
+ //
+ if (FileInfo != 0) {
+ //
+ // Set the file size to 0.
+ //
+ FileInfo = 0;
+ Status = FileHandleSetSize (FileHandle, FileInfo);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error Deleting %s\n", FileName[Index]);
+ FileHandleClose (FileHandle);
+ return Status;
+ }
+ }
+
+ //
+ // Write Filebuffer to file
+ //
+ Filebuffer = Buffer[Index];
+ FileSize = BufferSize[Index];
+ Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
+ return EFI_NOT_FOUND;
+ }
+
+ Print (L"Succeed to write %s\n", FileName[Index]);
+ FileHandleClose (FileHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set capsule status variable.
+
+ @param[in] SetCap Set or clear the capsule flag.
+
+ @retval EFI_SUCCESS Succeed to set SetCap variable.
+ @retval others Fail to set the variable.
+
+**/
+EFI_STATUS
+SetCapsuleStatusVariable (
+ BOOLEAN SetCap
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ OsIndication = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR (Status)) {
+ OsIndication = 0;
+ }
+ if (SetCap) {
+ OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ }
+ else {
+ OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ }
+ Status = gRT->SetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof(UINT64),
+ &OsIndication
+ );
+
+ return Status;
+}
+
+/**
+ Check if Capsule On Disk is supported.
+
+ @retval TRUE Capsule On Disk is supported.
+ @retval FALSE Capsule On Disk is not supported.
+
+**/
+BOOLEAN
+IsCapsuleOnDiskSupported (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndicationsSupported;
+ UINTN DataSize;
+
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndicationsSupported",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndicationsSupported
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Process Capsule On Disk.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] CapsuleBufferSize An array of UINTN to capsule images size
+ @param[in] FilePath An array of capsule images file path
+ @param[in] Map File system mapping string
+ @param[in] CapsuleNum The count of capsule images
+
+ @retval EFI_SUCCESS Capsule on disk success.
+ @retval others Capsule on disk fail.
+
+**/
+EFI_STATUS
+ProcessCapsuleOnDisk (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *CapsuleBufferSize,
+ IN CHAR16 **FilePath,
+ IN CHAR16 *Map,
+ IN UINTN CapsuleNum
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BootNext;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ BOOLEAN UpdateBootNext;
+ CHAR16 *FileName[MAX_CAPSULE_NUM];
+ UINTN Index;
+
+ //
+ // Check if Capsule On Disk is supported
+ //
+ if (!IsCapsuleOnDiskSupported ()) {
+ Print (L"CapsuleApp: Capsule On Disk is not supported.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get a valid file system from boot path
+ //
+ Fs = NULL;
+
+ Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: cannot find a valid file system on boot devices. Status = %r\n", Status);
+ return Status;
+ }
+
+ //
+ // Get file name from file path
+ //
+ for (Index = 0; Index < CapsuleNum; Index ++) {
+ FileName[Index] = GetFileNameFromPath (FilePath[Index]);
+ }
+
+ //
+ // Copy capsule image to '\efi\UpdateCapsule\'
+ //
+ Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: capsule image could not be copied for update.\n");
+ return Status;
+ }
+
+ //
+ // Set variable then reset
+ //
+ Status = SetCapsuleStatusVariable (TRUE);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: unable to set OSIndication variable.\n");
+ return Status;
+ }
+
+ if (UpdateBootNext) {
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof(UINT16),
+ &BootNext
+ );
+ if (EFI_ERROR (Status)){
+ Print (L"CapsuleApp: unable to set BootNext variable.\n");
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c
new file mode 100644
index 000000000..96b35d3da
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c
@@ -0,0 +1,610 @@
+/** @file
+ A shell application to dump dynamic PCD settings.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/PiPcd.h>
+#include <Protocol/Pcd.h>
+#include <Protocol/PiPcdInfo.h>
+#include <Protocol/PcdInfo.h>
+#include <Protocol/ShellParameters.h>
+#include <Protocol/Shell.h>
+
+
+//
+// String token ID of help message text.
+// Shell supports to find help message in the resource section of an application image if
+// .MAN file is not found. This global variable is added to make build tool recognizes
+// that the help string is consumed by user and then build tool will add the string into
+// the resource section. Thus the application can use '-?' option to show help message in
+// Shell.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStrDumpDynPcdHelpTokenId = STRING_TOKEN (STR_DUMP_DYN_PCD_HELP_INFORMATION);
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+
+static EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+static EFI_PCD_PROTOCOL *mPiPcd = NULL;
+static PCD_PROTOCOL *mPcd = NULL;
+static EFI_GET_PCD_INFO_PROTOCOL *mPiPcdInfo = NULL;
+static GET_PCD_INFO_PROTOCOL *mPcdInfo = NULL;
+static CHAR16 *mTempPcdNameBuffer = NULL;
+static UINTN mTempPcdNameBufferSize = 0;
+
+static CONST CHAR8 mHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+static UINTN Argc;
+static CHAR16 **Argv;
+
+
+/**
+
+ This function parse application ARG.
+
+ @return Status
+**/
+static
+EFI_STATUS
+GetArg (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID**)&ShellParameters
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Argc = ShellParameters->Argc;
+ Argv = ShellParameters->Argv;
+ return EFI_SUCCESS;
+}
+
+/**
+ Display current version.
+**/
+static
+VOID
+ShowVersion (
+ )
+{
+ Print (L"DumpDynPcd Version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION);
+}
+
+/**
+ Display Usage and Help information.
+**/
+static
+VOID
+ShowHelp (
+ )
+{
+ Print (L"Dump dynamic[ex] PCD info.\n");
+ Print (L"\n");
+ Print (L"DumpDynPcd [PcdName]\n");
+ Print (L"\n");
+ Print (L" PcdName Specifies the name of PCD.\n");
+ Print (L" A literal[or partial] name or a pattern as specified in\n");
+ Print (L" the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\n");
+ Print (L" If it is absent, dump all PCDs' info.\n");
+ Print (L"The PCD data is printed as hexadecimal dump.\n");
+}
+
+/**
+ Dump some hexadecimal data to the screen.
+
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the printing.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to print out.
+**/
+static
+VOID
+DumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ Print (L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+
+/**
+ Safely append with automatic string resizing given length of Destination and
+ desired length of copy from Source.
+
+ append the first D characters of Source to the end of Destination, where D is
+ the lesser of Count and the StrLen() of Source. If appending those D characters
+ will fit within Destination (whose Size is given as CurrentSize) and
+ still leave room for a NULL terminator, then those characters are appended,
+ starting at the original terminating NULL of Destination, and a new terminating
+ NULL is appended.
+
+ If appending D characters onto Destination will result in a overflow of the size
+ given in CurrentSize the string will be grown such that the copy can be performed
+ and CurrentSize will be updated to the new size.
+
+ If Source is NULL, there is nothing to append, just return the current buffer in
+ Destination.
+
+ if Destination is NULL, then ASSERT()
+ if Destination's current length (including NULL terminator) is already more then
+ CurrentSize, then ASSERT()
+
+ @param[in, out] Destination The String to append onto
+ @param[in, out] CurrentSize on call the number of bytes in Destination. On
+ return possibly the new size (still in bytes). if NULL
+ then allocate whatever is needed.
+ @param[in] Source The String to append from
+
+ @return Destination return the resultant string.
+**/
+static
+CHAR16*
+InternalStrnCatGrow (
+ IN OUT CHAR16 **Destination,
+ IN OUT UINTN *CurrentSize,
+ IN CONST CHAR16 *Source
+ )
+{
+ UINTN DestinationStartSize;
+ UINTN NewSize;
+ UINTN SourceLen;
+
+ SourceLen = StrLen(Source);
+
+ //
+ // ASSERTs
+ //
+ ASSERT(Destination != NULL);
+
+ //
+ // If there's nothing to do then just return Destination
+ //
+ if (Source == NULL) {
+ return (*Destination);
+ }
+
+ //
+ // allow for un-initialized pointers, based on size being 0
+ //
+ if (CurrentSize != NULL && *CurrentSize == 0) {
+ *Destination = NULL;
+ }
+
+ //
+ // allow for NULL pointers address as Destination
+ //
+ if (*Destination != NULL) {
+ ASSERT(CurrentSize != 0);
+ DestinationStartSize = StrSize(*Destination);
+ ASSERT(DestinationStartSize <= *CurrentSize);
+ } else {
+ DestinationStartSize = 0;
+ }
+
+ //
+ // Test and grow if required
+ //
+ if (CurrentSize != NULL) {
+ NewSize = *CurrentSize;
+ if (NewSize < DestinationStartSize + (SourceLen * sizeof(CHAR16))) {
+ while (NewSize < (DestinationStartSize + (SourceLen*sizeof(CHAR16)))) {
+ NewSize += 2 * SourceLen * sizeof(CHAR16);
+ }
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
+ *CurrentSize = NewSize;
+ }
+ } else {
+ NewSize = (SourceLen + 1)*sizeof(CHAR16);
+ *Destination = AllocateZeroPool(NewSize);
+ }
+
+ //
+ // Now use standard StrnCat on a big enough buffer
+ //
+ if (*Destination == NULL) {
+ return (NULL);
+ }
+
+ StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, SourceLen);
+ return *Destination;
+}
+
+/**
+ Get PCD type string based on input PCD type.
+
+ @param[in] TokenSpace PCD Token Space.
+ @param[in] PcdType The input PCD type.
+
+ @return Pointer to PCD type string.
+**/
+static
+CHAR16 *
+GetPcdTypeString (
+ IN CONST EFI_GUID *TokenSpace,
+ IN EFI_PCD_TYPE PcdType
+ )
+{
+ UINTN BufLen;
+ CHAR16 *RetString;
+
+ BufLen = 0;
+ RetString = NULL;
+
+ switch (PcdType) {
+ case EFI_PCD_TYPE_8:
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT8");
+ break;
+ case EFI_PCD_TYPE_16:
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT16");
+ break;
+ case EFI_PCD_TYPE_32:
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT32");
+ break;
+ case EFI_PCD_TYPE_64:
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT64");
+ break;
+ case EFI_PCD_TYPE_BOOL:
+ InternalStrnCatGrow (&RetString, &BufLen, L"BOOLEAN");
+ break;
+ case EFI_PCD_TYPE_PTR:
+ InternalStrnCatGrow (&RetString, &BufLen, L"POINTER");
+ break;
+ default:
+ InternalStrnCatGrow (&RetString, &BufLen, L"UNKNOWN");
+ break;
+ }
+
+ if (TokenSpace == NULL) {
+ InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMIC");
+ } else {
+ InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMICEX");
+ }
+
+ return RetString;
+}
+
+/**
+ Dump PCD info.
+
+ @param[in] TokenSpace PCD Token Space.
+ @param[in] TokenNumber PCD Token Number.
+ @param[in] PcdInfo Pointer to PCD info.
+**/
+static
+VOID
+DumpPcdInfo (
+ IN CONST EFI_GUID *TokenSpace,
+ IN UINTN TokenNumber,
+ IN EFI_PCD_INFO *PcdInfo
+ )
+{
+ CHAR16 *RetString;
+ UINT8 Uint8;
+ UINT16 Uint16;
+ UINT32 Uint32;
+ UINT64 Uint64;
+ BOOLEAN Boolean;
+ VOID *PcdData;
+
+ RetString = NULL;
+
+ if (PcdInfo->PcdName != NULL) {
+ Print (L"%a\n", PcdInfo->PcdName);
+ } else {
+ if (TokenSpace == NULL) {
+ Print (L"Default Token Space\n");
+ } else {
+ Print (L"%g\n", TokenSpace);
+ }
+ }
+
+ RetString = GetPcdTypeString (TokenSpace, PcdInfo->PcdType);
+
+ switch (PcdInfo->PcdType) {
+ case EFI_PCD_TYPE_8:
+ if (TokenSpace == NULL) {
+ Uint8 = mPcd->Get8 (TokenNumber);
+ } else {
+ Uint8 = mPiPcd->Get8 (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint8);
+ break;
+ case EFI_PCD_TYPE_16:
+ if (TokenSpace == NULL) {
+ Uint16 = mPcd->Get16 (TokenNumber);
+ } else {
+ Uint16 = mPiPcd->Get16 (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint16);
+ break;
+ case EFI_PCD_TYPE_32:
+ if (TokenSpace == NULL) {
+ Uint32 = mPcd->Get32 (TokenNumber);
+ } else {
+ Uint32 = mPiPcd->Get32 (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint32);
+ break;
+ case EFI_PCD_TYPE_64:
+ if (TokenSpace == NULL) {
+ Uint64 = mPcd->Get64 (TokenNumber);
+ } else {
+ Uint64 = mPiPcd->Get64 (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%lx\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint64);
+ break;
+ case EFI_PCD_TYPE_BOOL:
+ if (TokenSpace == NULL) {
+ Boolean = mPcd->GetBool (TokenNumber);
+ } else {
+ Boolean = mPiPcd->GetBool (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = %a\n", TokenNumber, RetString, PcdInfo->PcdSize, Boolean ? "TRUE" : "FALSE");
+ break;
+ case EFI_PCD_TYPE_PTR:
+ if (TokenSpace == NULL) {
+ PcdData = mPcd->GetPtr (TokenNumber);
+ } else {
+ PcdData = mPiPcd->GetPtr (TokenSpace, TokenNumber);
+ }
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize);
+ DumpHex (2, 0, PcdInfo->PcdSize, PcdData);
+ break;
+ default:
+ return;
+ }
+
+ if (RetString != NULL) {
+ FreePool (RetString);
+ }
+ Print (L"\n");
+}
+
+/**
+ Show one or all PCDs' info.
+
+ @param[in] InputPcdName Pointer to PCD name to show. If NULL, show all PCDs' info.
+
+ @retval EFI_SUCCESS Command completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.
+ @retval EFI_ABORTED Aborted by user.
+ @retval EFI_NOT_FOUND The specified PCD is not found.
+**/
+static
+EFI_STATUS
+ProcessPcd (
+ IN CHAR16 *InputPcdName
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *TokenSpace;
+ UINTN TokenNumber;
+ EFI_PCD_INFO PcdInfo;
+ BOOLEAN Found;
+ UINTN PcdNameSize;
+
+ PcdInfo.PcdName = NULL;
+ PcdInfo.PcdSize = 0;
+ PcdInfo.PcdType = 0xFF;
+ Found = FALSE;
+
+ Print (L"Current system SKU ID: 0x%x\n\n", mPiPcdInfo->GetSku ());
+
+ TokenSpace = NULL;
+ do {
+ TokenNumber = 0;
+ do {
+ Status = mPiPcd->GetNextToken (TokenSpace, &TokenNumber);
+ if (!EFI_ERROR (Status) && TokenNumber != 0) {
+ if (TokenSpace == NULL) {
+ //
+ // PCD in default Token Space.
+ //
+ mPcdInfo->GetInfo (TokenNumber, &PcdInfo);
+ } else {
+ mPiPcdInfo->GetInfo (TokenSpace, TokenNumber, &PcdInfo);
+ }
+ if (InputPcdName != NULL) {
+ if (PcdInfo.PcdName == NULL) {
+ continue;
+ }
+ PcdNameSize = AsciiStrSize (PcdInfo.PcdName) * sizeof (CHAR16);
+ if (mTempPcdNameBuffer == NULL) {
+ mTempPcdNameBufferSize = PcdNameSize;
+ mTempPcdNameBuffer = AllocatePool (mTempPcdNameBufferSize);
+ } else if (mTempPcdNameBufferSize < PcdNameSize) {
+ mTempPcdNameBuffer = ReallocatePool (mTempPcdNameBufferSize, PcdNameSize, mTempPcdNameBuffer);
+ mTempPcdNameBufferSize = PcdNameSize;
+ }
+ if (mTempPcdNameBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AsciiStrToUnicodeStrS (PcdInfo.PcdName, mTempPcdNameBuffer, mTempPcdNameBufferSize / sizeof (CHAR16));
+ //
+ // Compare the input PCD name with the PCD name in PCD database.
+ //
+ if ((StrStr (mTempPcdNameBuffer, InputPcdName) != NULL) ||
+ (mUnicodeCollation != NULL && mUnicodeCollation->MetaiMatch (mUnicodeCollation, mTempPcdNameBuffer, InputPcdName))) {
+ //
+ // Found matched PCD.
+ //
+ DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);
+ Found = TRUE;
+ }
+ } else {
+ DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);
+ }
+ }
+ } while (!EFI_ERROR (Status) && TokenNumber != 0);
+
+ Status = mPiPcd->GetNextTokenSpace ((CONST EFI_GUID **) &TokenSpace);
+ } while (!EFI_ERROR (Status) && TokenSpace != NULL);
+
+ if ((InputPcdName != NULL) && !Found) {
+ //
+ // The specified PCD is not found, print error.
+ //
+ Print (L"%EError. %NNo matching PCD found: %s.\n", InputPcdName);
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entrypoint for DumpDynPcd shell application.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS Command completed successfully.
+ @retval EFI_INVALID_PARAMETER Command usage error.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.
+ @retval EFI_ABORTED Aborted by user.
+ @retval EFI_NOT_FOUND The specified PCD is not found.
+ @retval Others Error status returned from gBS->LocateProtocol.
+**/
+EFI_STATUS
+EFIAPI
+DumpDynPcdMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *InputPcdName;
+
+ InputPcdName = NULL;
+
+ Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **) &mUnicodeCollation);
+ if (EFI_ERROR (Status)) {
+ mUnicodeCollation = NULL;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, (VOID **) &mPiPcd);
+ if (EFI_ERROR (Status)) {
+ Print (L"DumpDynPcd: %EError. %NPI PCD protocol is not present.\n");
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiGetPcdInfoProtocolGuid, NULL, (VOID **) &mPiPcdInfo);
+ if (EFI_ERROR (Status)) {
+ Print (L"DumpDynPcd: %EError. %NPI PCD info protocol is not present.\n");
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gPcdProtocolGuid, NULL, (VOID **) &mPcd);
+ if (EFI_ERROR (Status)) {
+ Print (L"DumpDynPcd: %EError. %NPCD protocol is not present.\n");
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gGetPcdInfoProtocolGuid, NULL, (VOID **) &mPcdInfo);
+ if (EFI_ERROR (Status)) {
+ Print (L"DumpDynPcd: %EError. %NPCD info protocol is not present.\n");
+ return Status;
+ }
+
+ //
+ // get the command line arguments
+ //
+ Status = GetArg();
+ if (EFI_ERROR(Status)){
+ Print (L"DumpDynPcd: %EError. %NThe input parameters are not recognized.\n");
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ if (Argc > 2){
+ Print (L"DumpDynPcd: %EError. %NToo many arguments specified.\n");
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ if (Argc == 1){
+ Status = ProcessPcd (InputPcdName);
+ goto Done;
+ }
+
+ if ((StrCmp(Argv[1], L"-?") == 0)||(StrCmp(Argv[1], L"-h") == 0)||(StrCmp(Argv[1], L"-H") == 0)){
+ ShowHelp ();
+ goto Done;
+ } else {
+ if ((StrCmp(Argv[1], L"-v") == 0)||(StrCmp(Argv[1], L"-V") == 0)){
+ ShowVersion ();
+ goto Done;
+ } else {
+ if (StrStr(Argv[1], L"-") != NULL){
+ Print (L"DumpDynPcd: %EError. %NThe argument '%B%s%N' is invalid.\n", Argv[1]);
+ goto Done;
+ }
+ }
+ }
+
+ InputPcdName = Argv[1];
+ Status = ProcessPcd (InputPcdName);
+
+ Done:
+
+ if (mTempPcdNameBuffer != NULL) {
+ FreePool (mTempPcdNameBuffer);
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
new file mode 100644
index 000000000..a3542dd36
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
@@ -0,0 +1,50 @@
+## @file
+# DumpDynPcd is a shell application to dump dynamic pcd information.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = DumpDynPcd
+ FILE_GUID = 31ADA2B2-62EA-4866-9B87-03FEA8425974
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DumpDynPcdMain
+
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DumpDynPcd.c
+ DumpDynPcdStr.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiApplicationEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPcdProtocolGuid ## CONSUMES
+ gPcdProtocolGuid ## CONSUMES
+ gEfiGetPcdInfoProtocolGuid ## CONSUMES
+ gGetPcdInfoProtocolGuid ## CONSUMES
+ gEfiShellParametersProtocolGuid ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni
new file mode 100644
index 000000000..f0ee98219
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/DumpDynPcd/DumpDynPcdStr.uni
@@ -0,0 +1,28 @@
+//
+// DumpDynPcd is a shell application to dump dynamic pcd information.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_DUMP_DYN_PCD_HELP_INFORMATION #language en-US ""
+ ".TH DumpDynPcd 0 "Dump dynamic[ex] PCD info."\r\n"
+ ".SH NAME\r\n"
+ "Dump dynamic[ex] PCD info.\r\n"
+ ".SH SYNOPSIS\r\n"
+ " \r\n"
+ "DumpDynPcd [PcdName].\r\n"
+ ".SH OPTIONS\r\n"
+ " \r\n"
+ " PcdName Specifies the name of PCD.\r\n"
+ " A literal[or partial] name or a pattern as specified in\r\n"
+ " the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\r\n"
+ " If it is absent, dump all PCDs' info.\r\n"
+ "The PCD data is printed as hexadecimal dump.\n"
+ "\r\n"
+
diff --git a/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.c b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.c
new file mode 100644
index 000000000..e45a3746e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.c
@@ -0,0 +1,60 @@
+/** @file
+ This sample application bases on HelloWorld PCD setting
+ to print "UEFI Hello World!" to the UEFI Console.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+
+//
+// String token ID of help message text.
+// Shell supports to find help message in the resource section of an application image if
+// .MAN file is not found. This global variable is added to make build tool recognizes
+// that the help string is consumed by user and then build tool will add the string into
+// the resource section. Thus the application can use '-?' option to show help message in
+// Shell.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringHelpTokenId = STRING_TOKEN (STR_HELLO_WORLD_HELP_INFORMATION);
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the application.
+
+ @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
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINT32 Index;
+
+ Index = 0;
+
+ //
+ // Three PCD type (FeatureFlag, UINT32 and String) are used as the sample.
+ //
+ if (FeaturePcdGet (PcdHelloWorldPrintEnable)) {
+ for (Index = 0; Index < PcdGet32 (PcdHelloWorldPrintTimes); Index ++) {
+ //
+ // Use UefiLib Print API to print string to UEFI console
+ //
+ Print ((CHAR16*)PcdGetPtr (PcdHelloWorldPrintString));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.inf b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.inf
new file mode 100644
index 000000000..4520a370e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.inf
@@ -0,0 +1,57 @@
+## @file
+# Sample UEFI Application Reference EDKII Module.
+#
+# This is a sample shell application that will print "UEFI Hello World!" to the
+# UEFI Console based on PCD setting.
+#
+# It demos how to use EDKII PCD mechanism to make code more flexible.
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HelloWorld
+ MODULE_UNI_FILE = HelloWorld.uni
+ FILE_GUID = 6987936E-ED34-44db-AE97-1FA5E4ED2116
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ HelloWorld.c
+ HelloWorldStr.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ PcdLib
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ HelloWorldExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.uni b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.uni
new file mode 100644
index 000000000..aade016c6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorld.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Sample UEFI Application Reference EDKII Module.
+//
+// This is a sample shell application that will print "UEFI Hello World!" to the
+// UEFI Console based on PCD setting.
+//
+// It demos how to use EDKII PCD mechanism to make code more flexible.
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Sample UEFI Application Reference EDKII Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is a sample shell application that will print UEFI Hello World! to the UEFI Console based on PCD setting. It demonstrates how to use the EDKII PCD mechanism to make code more flexible"
+
diff --git a/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni
new file mode 100644
index 000000000..70dd81e87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// HelloWorld Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Hello World Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni
new file mode 100644
index 000000000..eb03b78dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/HelloWorld/HelloWorldStr.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Sample UEFI Application Reference EDKII Module.
+//
+// This is a sample shell application that will print "UEFI Hello World!" to the
+// UEFI Console based on PCD setting.
+//
+// It demos how to use EDKII PCD mechanism to make code more flexible.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_HELLO_WORLD_HELP_INFORMATION #language en-US ""
+".TH HelloWorld 0 "Displays a \"UEFI Hello World!\" string."\r\n"
+".SH NAME\r\n"
+"HelloWorld application.\r\n"
diff --git a/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c
new file mode 100644
index 000000000..191c31068
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c
@@ -0,0 +1,1361 @@
+/** @file
+
+ Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/PrintLib.h>
+
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/SmmAccess2.h>
+
+#include <Guid/MemoryProfile.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+CHAR8 *mActionString[] = {
+ "Unknown",
+ "gBS->AllocatePages",
+ "gBS->FreePages",
+ "gBS->AllocatePool",
+ "gBS->FreePool",
+};
+
+CHAR8 *mSmmActionString[] = {
+ "SmmUnknown",
+ "gSmst->SmmAllocatePages",
+ "gSmst->SmmFreePages",
+ "gSmst->SmmAllocatePool",
+ "gSmst->SmmFreePool",
+};
+
+typedef struct {
+ MEMORY_PROFILE_ACTION Action;
+ CHAR8 *String;
+} ACTION_STRING;
+
+ACTION_STRING mExtActionString[] = {
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool"},
+};
+
+CHAR8 mUserDefinedActionString[] = {"UserDefined-0x80000000"};
+
+CHAR8 *mMemoryTypeString[] = {
+ "EfiReservedMemoryType",
+ "EfiLoaderCode",
+ "EfiLoaderData",
+ "EfiBootServicesCode",
+ "EfiBootServicesData",
+ "EfiRuntimeServicesCode",
+ "EfiRuntimeServicesData",
+ "EfiConventionalMemory",
+ "EfiUnusableMemory",
+ "EfiACPIReclaimMemory",
+ "EfiACPIMemoryNVS",
+ "EfiMemoryMappedIO",
+ "EfiMemoryMappedIOPortSpace",
+ "EfiPalCode",
+ "EfiPersistentMemory",
+ "EfiOSReserved",
+ "EfiOemReserved",
+};
+
+CHAR8 *mSubsystemString[] = {
+ "Unknown",
+ "NATIVE",
+ "WINDOWS_GUI",
+ "WINDOWS_CUI",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "POSIX_CUI",
+ "Unknown",
+ "WINDOWS_CE_GUI",
+ "EFI_APPLICATION",
+ "EFI_BOOT_SERVICE_DRIVER",
+ "EFI_RUNTIME_DRIVER",
+ "EFI_ROM",
+ "XBOX",
+ "Unknown",
+};
+
+CHAR8 *mFileTypeString[] = {
+ "Unknown",
+ "RAW",
+ "FREEFORM",
+ "SECURITY_CORE",
+ "PEI_CORE",
+ "DXE_CORE",
+ "PEIM",
+ "DRIVER",
+ "COMBINED_PEIM_DRIVER",
+ "APPLICATION",
+ "SMM",
+ "FIRMWARE_VOLUME_IMAGE",
+ "COMBINED_SMM_DXE",
+ "SMM_CORE",
+};
+
+#define PROFILE_NAME_STRING_LENGTH 64
+CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1];
+
+//
+// Profile summary information
+//
+#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','S')
+#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION 0x0001
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ PHYSICAL_ADDRESS CallerAddress;
+ MEMORY_PROFILE_ACTION Action;
+ CHAR8 *ActionString;
+ UINT32 AllocateCount;
+ UINT64 TotalSize;
+} MEMORY_PROFILE_ALLOC_SUMMARY_INFO;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO AllocSummaryInfo;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ LIST_ENTRY *AllocSummaryInfoList;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_CONTEXT *Context;
+ LIST_ENTRY *DriverSummaryInfoList;
+} MEMORY_PROFILE_CONTEXT_SUMMARY_DATA;
+
+LIST_ENTRY mImageSummaryQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageSummaryQueue);
+MEMORY_PROFILE_CONTEXT_SUMMARY_DATA mMemoryProfileContextSummary;
+
+/**
+ Get the file name portion of the Pdb File Name.
+
+ The portion of the Pdb File Name between the last backslash and
+ either a following period or the end of the string is copied into
+ AsciiBuffer. The name is truncated, if necessary, to ensure that
+ AsciiBuffer is not overrun.
+
+ @param[in] PdbFileName Pdb file name.
+ @param[out] AsciiBuffer The resultant Ascii File Name.
+
+**/
+VOID
+GetShortPdbFileName (
+ IN CHAR8 *PdbFileName,
+ OUT CHAR8 *AsciiBuffer
+ )
+{
+ UINTN IndexPdb; // Current work location within a Pdb string.
+ UINTN IndexBuffer; // Current work location within a Buffer string.
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1);
+
+ if (PdbFileName == NULL) {
+ AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1);
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++);
+ for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) {
+ if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) {
+ StartIndex = IndexPdb + 1;
+ }
+
+ if (PdbFileName[IndexPdb] == '.') {
+ EndIndex = IndexPdb;
+ }
+ }
+
+ IndexBuffer = 0;
+ for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) {
+ AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb];
+ IndexBuffer++;
+ if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) {
+ AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Get a human readable name for an image.
+ The following methods will be tried orderly:
+ 1. Image PDB
+ 2. FFS UI section
+ 3. Image GUID
+
+ @param[in] DriverInfo Pointer to memory profile driver info.
+
+ @return The resulting Ascii name string is stored in the mNameString global array.
+
+**/
+CHAR8 *
+GetDriverNameString (
+ IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *NameString;
+ UINTN StringSize;
+
+ //
+ // Method 1: Get the name string from image PDB
+ //
+ if (DriverInfo->PdbStringOffset != 0) {
+ GetShortPdbFileName ((CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), mNameString);
+ return mNameString;
+ }
+
+ if (!IsZeroGuid (&DriverInfo->FileName)) {
+ //
+ // Try to get the image's FFS UI section by image GUID
+ //
+ NameString = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ &DriverInfo->FileName,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &NameString,
+ &StringSize
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Method 2: Get the name string from FFS UI section
+ //
+ if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) {
+ NameString[PROFILE_NAME_STRING_LENGTH] = 0;
+ }
+ UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString));
+ FreePool (NameString);
+ return mNameString;
+ }
+ }
+
+ //
+ // Method 3: Get the name string from image GUID
+ //
+ AsciiSPrint (mNameString, sizeof (mNameString), "%g", &DriverInfo->FileName);
+ return mNameString;
+}
+
+/**
+ Memory type to string.
+
+ @param[in] MemoryType Memory type.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+ProfileMemoryTypeToStr (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINTN Index;
+
+ if ((UINT32) MemoryType >= 0x80000000) {
+ //
+ // OS reserved memory type.
+ //
+ Index = EfiMaxMemoryType;
+ } else if ((UINT32) MemoryType >= 0x70000000) {
+ //
+ // OEM reserved memory type.
+ //
+ Index = EfiMaxMemoryType + 1;
+ } else {
+ Index = MemoryType;
+ }
+
+ return mMemoryTypeString[Index];
+}
+
+/**
+ Action to string.
+
+ @param[in] Action Profile action.
+ @param[in] UserDefinedActionString Pointer to user defined action string.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+ProfileActionToStr (
+ IN MEMORY_PROFILE_ACTION Action,
+ IN CHAR8 *UserDefinedActionString,
+ IN BOOLEAN IsForSmm
+ )
+{
+ UINTN Index;
+ UINTN ActionStringCount;
+ CHAR8 **ActionString;
+
+ if (IsForSmm) {
+ ActionString = mSmmActionString;
+ ActionStringCount = ARRAY_SIZE (mSmmActionString);
+ } else {
+ ActionString = mActionString;
+ ActionStringCount = ARRAY_SIZE (mActionString);
+ }
+
+ if ((UINTN) (UINT32) Action < ActionStringCount) {
+ return ActionString[Action];
+ }
+ for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
+ if (mExtActionString[Index].Action == Action) {
+ return mExtActionString[Index].String;
+ }
+ }
+ if ((Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
+ if (UserDefinedActionString != NULL) {
+ return UserDefinedActionString;
+ }
+ AsciiSPrint (mUserDefinedActionString, sizeof (mUserDefinedActionString), "UserDefined-0x%08x", Action);
+ return mUserDefinedActionString;
+ }
+
+ return ActionString[0];
+}
+
+/**
+ Dump memory profile allocate information.
+
+ @param[in] DriverInfo Pointer to memory profile driver info.
+ @param[in] AllocIndex Memory profile alloc info index.
+ @param[in] AllocInfo Pointer to memory profile alloc info.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+ @return Pointer to next memory profile alloc info.
+
+**/
+MEMORY_PROFILE_ALLOC_INFO *
+DumpMemoryProfileAllocInfo (
+ IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo,
+ IN UINTN AllocIndex,
+ IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo,
+ IN BOOLEAN IsForSmm
+ )
+{
+ CHAR8 *ActionString;
+
+ if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) {
+ return NULL;
+ }
+
+ if (AllocInfo->ActionStringOffset != 0) {
+ ActionString = (CHAR8 *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset);
+ } else {
+ ActionString = NULL;
+ }
+
+ Print (L" MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex);
+ Print (L" Signature - 0x%08x\n", AllocInfo->Header.Signature);
+ Print (L" Length - 0x%04x\n", AllocInfo->Header.Length);
+ Print (L" Revision - 0x%04x\n", AllocInfo->Header.Revision);
+ Print (L" CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, (UINTN) (AllocInfo->CallerAddress - DriverInfo->ImageBase));
+ Print (L" SequenceId - 0x%08x\n", AllocInfo->SequenceId);
+ Print (L" Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action, ActionString, IsForSmm));
+ Print (L" MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType));
+ Print (L" Buffer - 0x%016lx\n", AllocInfo->Buffer);
+ Print (L" Size - 0x%016lx\n", AllocInfo->Size);
+
+ return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
+}
+
+/**
+ Dump memory profile driver information.
+
+ @param[in] DriverIndex Memory profile driver info index.
+ @param[in] DriverInfo Pointer to memory profile driver info.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+ @return Pointer to next memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO *
+DumpMemoryProfileDriverInfo (
+ IN UINTN DriverIndex,
+ IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo,
+ IN BOOLEAN IsForSmm
+ )
+{
+ UINTN TypeIndex;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ UINTN AllocIndex;
+ CHAR8 *NameString;
+
+ if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) {
+ return NULL;
+ }
+ Print (L" MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex);
+ Print (L" Signature - 0x%08x\n", DriverInfo->Header.Signature);
+ Print (L" Length - 0x%04x\n", DriverInfo->Header.Length);
+ Print (L" Revision - 0x%04x\n", DriverInfo->Header.Revision);
+ NameString = GetDriverNameString (DriverInfo);
+ Print (L" FileName - %a\n", NameString);
+ if (DriverInfo->PdbStringOffset != 0) {
+ Print (L" Pdb - %a\n", (CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset));
+ }
+ Print (L" ImageBase - 0x%016lx\n", DriverInfo->ImageBase);
+ Print (L" ImageSize - 0x%016lx\n", DriverInfo->ImageSize);
+ Print (L" EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint);
+ Print (L" ImageSubsystem - 0x%04x (%a)\n", DriverInfo->ImageSubsystem, mSubsystemString[(DriverInfo->ImageSubsystem < sizeof(mSubsystemString)/sizeof(mSubsystemString[0])) ? DriverInfo->ImageSubsystem : 0]);
+ Print (L" FileType - 0x%02x (%a)\n", DriverInfo->FileType, mFileTypeString[(DriverInfo->FileType < sizeof(mFileTypeString)/sizeof(mFileTypeString[0])) ? DriverInfo->FileType : 0]);
+ Print (L" CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage);
+ Print (L" PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage);
+ for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
+ if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
+ (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {
+ Print (L" CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
+ Print (L" PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
+ }
+ }
+ Print (L" AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount);
+
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
+ for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) {
+ AllocInfo = DumpMemoryProfileAllocInfo (DriverInfo, AllocIndex, AllocInfo, IsForSmm);
+ if (AllocInfo == NULL) {
+ return NULL;
+ }
+ }
+ return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;
+}
+
+/**
+ Dump memory profile context information.
+
+ @param[in] Context Pointer to memory profile context.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+ @return Pointer to the end of memory profile context buffer.
+
+**/
+VOID *
+DumpMemoryProfileContext (
+ IN MEMORY_PROFILE_CONTEXT *Context,
+ IN BOOLEAN IsForSmm
+ )
+{
+ UINTN TypeIndex;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ UINTN DriverIndex;
+
+ if (Context->Header.Signature != MEMORY_PROFILE_CONTEXT_SIGNATURE) {
+ return NULL;
+ }
+ Print (L"MEMORY_PROFILE_CONTEXT\n");
+ Print (L" Signature - 0x%08x\n", Context->Header.Signature);
+ Print (L" Length - 0x%04x\n", Context->Header.Length);
+ Print (L" Revision - 0x%04x\n", Context->Header.Revision);
+ Print (L" CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage);
+ Print (L" PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage);
+ for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
+ if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
+ (Context->PeakTotalUsageByType[TypeIndex] != 0)) {
+ Print (L" CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
+ Print (L" PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
+ }
+ }
+ Print (L" TotalImageSize - 0x%016lx\n", Context->TotalImageSize);
+ Print (L" ImageCount - 0x%08x\n", Context->ImageCount);
+ Print (L" SequenceCount - 0x%08x\n", Context->SequenceCount);
+
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length);
+ for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) {
+ DriverInfo = DumpMemoryProfileDriverInfo (DriverIndex, DriverInfo, IsForSmm);
+ if (DriverInfo == NULL) {
+ return NULL;
+ }
+ }
+ return (VOID *) DriverInfo;
+}
+
+/**
+ Dump memory profile descriptor information.
+
+ @param[in] DescriptorIndex Memory profile descriptor index.
+ @param[in] Descriptor Pointer to memory profile descriptor.
+
+ @return Pointer to next memory profile descriptor.
+
+**/
+MEMORY_PROFILE_DESCRIPTOR *
+DumpMemoryProfileDescriptor (
+ IN UINTN DescriptorIndex,
+ IN MEMORY_PROFILE_DESCRIPTOR *Descriptor
+ )
+{
+ if (Descriptor->Header.Signature != MEMORY_PROFILE_DESCRIPTOR_SIGNATURE) {
+ return NULL;
+ }
+ Print (L" MEMORY_PROFILE_DESCRIPTOR (0x%x)\n", DescriptorIndex);
+ Print (L" Signature - 0x%08x\n", Descriptor->Header.Signature);
+ Print (L" Length - 0x%04x\n", Descriptor->Header.Length);
+ Print (L" Revision - 0x%04x\n", Descriptor->Header.Revision);
+ Print (L" Address - 0x%016lx\n", Descriptor->Address);
+ Print (L" Size - 0x%016lx\n", Descriptor->Size);
+
+ return (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) Descriptor + Descriptor->Header.Length);
+}
+
+/**
+ Dump memory profile free memory information.
+
+ @param[in] FreeMemory Pointer to memory profile free memory.
+
+ @return Pointer to the end of memory profile free memory buffer.
+
+**/
+VOID *
+DumpMemoryProfileFreeMemory (
+ IN MEMORY_PROFILE_FREE_MEMORY *FreeMemory
+ )
+{
+ MEMORY_PROFILE_DESCRIPTOR *Descriptor;
+ UINTN DescriptorIndex;
+
+ if (FreeMemory->Header.Signature != MEMORY_PROFILE_FREE_MEMORY_SIGNATURE) {
+ return NULL;
+ }
+ Print (L"MEMORY_PROFILE_FREE_MEMORY\n");
+ Print (L" Signature - 0x%08x\n", FreeMemory->Header.Signature);
+ Print (L" Length - 0x%04x\n", FreeMemory->Header.Length);
+ Print (L" Revision - 0x%04x\n", FreeMemory->Header.Revision);
+ Print (L" TotalFreeMemoryPages - 0x%016lx\n", FreeMemory->TotalFreeMemoryPages);
+ Print (L" FreeMemoryEntryCount - 0x%08x\n", FreeMemory->FreeMemoryEntryCount);
+
+ Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) FreeMemory + FreeMemory->Header.Length);
+ for (DescriptorIndex = 0; DescriptorIndex < FreeMemory->FreeMemoryEntryCount; DescriptorIndex++) {
+ Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);
+ if (Descriptor == NULL) {
+ return NULL;
+ }
+ }
+
+ return (VOID *) Descriptor;
+}
+
+/**
+ Dump memory profile memory range information.
+
+ @param[in] MemoryRange Pointer to memory profile memory range.
+
+ @return Pointer to the end of memory profile memory range buffer.
+
+**/
+VOID *
+DumpMemoryProfileMemoryRange (
+ IN MEMORY_PROFILE_MEMORY_RANGE *MemoryRange
+ )
+{
+ MEMORY_PROFILE_DESCRIPTOR *Descriptor;
+ UINTN DescriptorIndex;
+
+ if (MemoryRange->Header.Signature != MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE) {
+ return NULL;
+ }
+ Print (L"MEMORY_PROFILE_MEMORY_RANGE\n");
+ Print (L" Signature - 0x%08x\n", MemoryRange->Header.Signature);
+ Print (L" Length - 0x%04x\n", MemoryRange->Header.Length);
+ Print (L" Revision - 0x%04x\n", MemoryRange->Header.Revision);
+ Print (L" MemoryRangeCount - 0x%08x\n", MemoryRange->MemoryRangeCount);
+
+ Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) MemoryRange + MemoryRange->Header.Length);
+ for (DescriptorIndex = 0; DescriptorIndex < MemoryRange->MemoryRangeCount; DescriptorIndex++) {
+ Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);
+ if (Descriptor == NULL) {
+ return NULL;
+ }
+ }
+
+ return (VOID *) Descriptor;
+}
+
+/**
+ Scan memory profile by Signature.
+
+ @param[in] ProfileBuffer Memory profile base address.
+ @param[in] ProfileSize Memory profile size.
+ @param[in] Signature Signature.
+
+ @return Pointer to the structure with the signature.
+
+**/
+VOID *
+ScanMemoryProfileBySignature (
+ IN PHYSICAL_ADDRESS ProfileBuffer,
+ IN UINT64 ProfileSize,
+ IN UINT32 Signature
+ )
+{
+ MEMORY_PROFILE_COMMON_HEADER *CommonHeader;
+ UINTN ProfileEnd;
+
+ ProfileEnd = (UINTN) (ProfileBuffer + ProfileSize);
+ CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) (UINTN) ProfileBuffer;
+ while ((UINTN) CommonHeader < ProfileEnd) {
+ if (CommonHeader->Signature == Signature) {
+ //
+ // Found it.
+ //
+ return (VOID *) CommonHeader;
+ }
+ if (CommonHeader->Length == 0) {
+ ASSERT (FALSE);
+ return NULL;
+ }
+ CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) ((UINTN) CommonHeader + CommonHeader->Length);
+ }
+
+ return NULL;
+}
+
+/**
+ Dump memory profile information.
+
+ @param[in] ProfileBuffer Memory profile base address.
+ @param[in] ProfileSize Memory profile size.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+**/
+VOID
+DumpMemoryProfile (
+ IN PHYSICAL_ADDRESS ProfileBuffer,
+ IN UINT64 ProfileSize,
+ IN BOOLEAN IsForSmm
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_FREE_MEMORY *FreeMemory;
+ MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;
+
+ Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE);
+ if (Context != NULL) {
+ DumpMemoryProfileContext (Context, IsForSmm);
+ }
+
+ FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_FREE_MEMORY_SIGNATURE);
+ if (FreeMemory != NULL) {
+ DumpMemoryProfileFreeMemory (FreeMemory);
+ }
+
+ MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE);
+ if (MemoryRange != NULL) {
+ DumpMemoryProfileMemoryRange (MemoryRange);
+ }
+}
+
+/**
+ Get Allocate summary information structure by caller address.
+
+ @param[in] CallerAddress Caller address.
+ @param[in] DriverSummaryInfoData Driver summary information data structure.
+
+ @return Allocate summary information structure by caller address.
+
+**/
+MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *
+GetAllocSummaryInfoByCallerAddress (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData
+ )
+{
+ LIST_ENTRY *AllocSummaryInfoList;
+ LIST_ENTRY *AllocSummaryLink;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
+
+ AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
+
+ for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
+ AllocSummaryLink != AllocSummaryInfoList;
+ AllocSummaryLink = AllocSummaryLink->ForwardLink) {
+ AllocSummaryInfoData = CR (
+ AllocSummaryLink,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
+ );
+ AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
+ if (AllocSummaryInfo->CallerAddress == CallerAddress) {
+ return AllocSummaryInfoData;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Create Allocate summary information structure and
+ link to Driver summary information data structure.
+
+ @param[in, out] DriverSummaryInfoData Driver summary information data structure.
+ @param[in] AllocInfo Pointer to memory profile alloc info.
+
+ @return Pointer to next memory profile alloc info.
+
+**/
+MEMORY_PROFILE_ALLOC_INFO *
+CreateAllocSummaryInfo (
+ IN OUT MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData,
+ IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo
+ )
+{
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
+
+ if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) {
+ return NULL;
+ }
+
+ AllocSummaryInfoData = GetAllocSummaryInfoByCallerAddress (AllocInfo->CallerAddress, DriverSummaryInfoData);
+ if (AllocSummaryInfoData == NULL) {
+ AllocSummaryInfoData = AllocatePool (sizeof (*AllocSummaryInfoData));
+ if (AllocSummaryInfoData == NULL) {
+ return NULL;
+ }
+
+ AllocSummaryInfoData->Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE;
+ AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
+ AllocSummaryInfo->Header.Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE;
+ AllocSummaryInfo->Header.Length = sizeof (*AllocSummaryInfo);
+ AllocSummaryInfo->Header.Revision = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION;
+ AllocSummaryInfo->CallerAddress = AllocInfo->CallerAddress;
+ AllocSummaryInfo->Action = AllocInfo->Action;
+ if (AllocInfo->ActionStringOffset != 0) {
+ AllocSummaryInfo->ActionString = (CHAR8 *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset);
+ } else {
+ AllocSummaryInfo->ActionString = NULL;
+ }
+ AllocSummaryInfo->AllocateCount = 0;
+ AllocSummaryInfo->TotalSize = 0;
+ InsertTailList (DriverSummaryInfoData->AllocSummaryInfoList, &AllocSummaryInfoData->Link);
+ }
+ AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
+ AllocSummaryInfo->AllocateCount ++;
+ AllocSummaryInfo->TotalSize += AllocInfo->Size;
+
+ return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
+}
+
+/**
+ Create Driver summary information structure and
+ link to Context summary information data structure.
+
+ @param[in, out] ContextSummaryData Context summary information data structure.
+ @param[in] DriverInfo Pointer to memory profile driver info.
+
+ @return Pointer to next memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO *
+CreateDriverSummaryInfo (
+ IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData,
+ IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo
+ )
+{
+ MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ UINTN AllocIndex;
+
+ if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) {
+ return NULL;
+ }
+
+ DriverSummaryInfoData = AllocatePool (sizeof (*DriverSummaryInfoData) + sizeof (LIST_ENTRY));
+ if (DriverSummaryInfoData == NULL) {
+ return NULL;
+ }
+ DriverSummaryInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverSummaryInfoData->DriverInfo = DriverInfo;
+ DriverSummaryInfoData->AllocSummaryInfoList = (LIST_ENTRY *) (DriverSummaryInfoData + 1);
+ InitializeListHead (DriverSummaryInfoData->AllocSummaryInfoList);
+ InsertTailList (ContextSummaryData->DriverSummaryInfoList, &DriverSummaryInfoData->Link);
+
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
+ for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) {
+ AllocInfo = CreateAllocSummaryInfo (DriverSummaryInfoData, AllocInfo);
+ if (AllocInfo == NULL) {
+ return NULL;
+ }
+ }
+ return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;
+}
+
+/**
+ Create Context summary information structure.
+
+ @param[in] ProfileBuffer Memory profile base address.
+ @param[in] ProfileSize Memory profile size.
+
+ @return Context summary information structure.
+
+**/
+MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *
+CreateContextSummaryData (
+ IN PHYSICAL_ADDRESS ProfileBuffer,
+ IN UINT64 ProfileSize
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ UINTN DriverIndex;
+
+ Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE);
+ if (Context == NULL) {
+ return NULL;
+ }
+
+ mMemoryProfileContextSummary.Signature = MEMORY_PROFILE_CONTEXT_SIGNATURE;
+ mMemoryProfileContextSummary.Context = Context;
+ mMemoryProfileContextSummary.DriverSummaryInfoList = &mImageSummaryQueue;
+
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length);
+ for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) {
+ DriverInfo = CreateDriverSummaryInfo (&mMemoryProfileContextSummary, DriverInfo);
+ if (DriverInfo == NULL) {
+ return NULL;
+ }
+ }
+
+ return &mMemoryProfileContextSummary;
+}
+
+/**
+ Dump Context summary information.
+
+ @param[in] ContextSummaryData Context summary information data.
+ @param[in] IsForSmm TRUE - SMRAM profile.
+ FALSE - UEFI memory profile.
+
+**/
+VOID
+DumpContextSummaryData (
+ IN MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData,
+ IN BOOLEAN IsForSmm
+ )
+{
+ MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
+ LIST_ENTRY *DriverSummaryInfoList;
+ LIST_ENTRY *DriverSummaryLink;
+ LIST_ENTRY *AllocSummaryInfoList;
+ LIST_ENTRY *AllocSummaryLink;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
+ CHAR8 *NameString;
+
+ if (ContextSummaryData == NULL) {
+ return ;
+ }
+
+ Print (L"\nSummary Data:\n");
+
+ DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList;
+ for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink;
+ DriverSummaryLink != DriverSummaryInfoList;
+ DriverSummaryLink = DriverSummaryLink->ForwardLink) {
+ DriverSummaryInfoData = CR (
+ DriverSummaryLink,
+ MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = DriverSummaryInfoData->DriverInfo;
+
+ NameString = GetDriverNameString (DriverInfo);
+ Print (L"\nDriver - %a (Usage - 0x%08x)", NameString, DriverInfo->CurrentUsage);
+ if (DriverInfo->CurrentUsage == 0) {
+ Print (L"\n");
+ continue;
+ }
+
+ if (DriverInfo->PdbStringOffset != 0) {
+ Print (L" (Pdb - %a)\n", (CHAR8 *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset));
+ } else {
+ Print (L"\n");
+ }
+ Print (L"Caller List:\n");
+ Print(L" Count Size RVA Action\n");
+ Print(L"========== ================== ================== (================================)\n");
+ AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
+ for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
+ AllocSummaryLink != AllocSummaryInfoList;
+ AllocSummaryLink = AllocSummaryLink->ForwardLink) {
+ AllocSummaryInfoData = CR (
+ AllocSummaryLink,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
+ );
+ AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
+
+ Print(L"0x%08x 0x%016lx <== 0x%016lx",
+ AllocSummaryInfo->AllocateCount,
+ AllocSummaryInfo->TotalSize,
+ AllocSummaryInfo->CallerAddress - DriverInfo->ImageBase
+ );
+ Print (L" (%a)\n", ProfileActionToStr (AllocSummaryInfo->Action, AllocSummaryInfo->ActionString, IsForSmm));
+ }
+ }
+ return ;
+}
+
+/**
+ Destroy Context summary information.
+
+ @param[in, out] ContextSummaryData Context summary information data.
+
+**/
+VOID
+DestroyContextSummaryData (
+ IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData
+ )
+{
+ MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
+ LIST_ENTRY *DriverSummaryInfoList;
+ LIST_ENTRY *DriverSummaryLink;
+ LIST_ENTRY *AllocSummaryInfoList;
+ LIST_ENTRY *AllocSummaryLink;
+
+ if (ContextSummaryData == NULL) {
+ return ;
+ }
+
+ DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList;
+ for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink;
+ DriverSummaryLink != DriverSummaryInfoList;
+ ) {
+ DriverSummaryInfoData = CR (
+ DriverSummaryLink,
+ MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverSummaryLink = DriverSummaryLink->ForwardLink;
+
+ AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
+ for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
+ AllocSummaryLink != AllocSummaryInfoList;
+ ) {
+ AllocSummaryInfoData = CR (
+ AllocSummaryLink,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
+ );
+ AllocSummaryLink = AllocSummaryLink->ForwardLink;
+
+ RemoveEntryList (&AllocSummaryInfoData->Link);
+ FreePool (AllocSummaryInfoData);
+ }
+
+ RemoveEntryList (&DriverSummaryInfoData->Link);
+ FreePool (DriverSummaryInfoData);
+ }
+ return ;
+}
+
+/**
+ Get and dump UEFI memory profile data.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return other Fail to get the memory profile data.
+
+**/
+EFI_STATUS
+GetUefiMemoryProfileData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
+ VOID *Data;
+ UINT64 Size;
+ MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData;
+ BOOLEAN RecordingState;
+
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UefiMemoryProfile: Locate MemoryProfile protocol - %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Set recording state if needed.
+ //
+ RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
+ Status = ProfileProtocol->GetRecordingState (ProfileProtocol, &RecordingState);
+ if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
+ ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_DISABLE);
+ }
+
+ Size = 0;
+ Data = NULL;
+ Status = ProfileProtocol->GetData (
+ ProfileProtocol,
+ &Size,
+ Data
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print (L"UefiMemoryProfile: GetData - %r\n", Status);
+ goto Done;
+ }
+
+ Data = AllocateZeroPool ((UINTN) Size);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", Size, Status);
+ return Status;
+ }
+
+ Status = ProfileProtocol->GetData (
+ ProfileProtocol,
+ &Size,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ Print (L"UefiMemoryProfile: GetData - %r\n", Status);
+ goto Done;
+ }
+
+
+ Print (L"UefiMemoryProfileSize - 0x%x\n", Size);
+ Print (L"======= UefiMemoryProfile begin =======\n");
+ DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) Data, Size, FALSE);
+
+ //
+ // Dump summary information
+ //
+ MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS) (UINTN) Data, Size);
+ if (MemoryProfileContextSummaryData != NULL) {
+ DumpContextSummaryData (MemoryProfileContextSummaryData, FALSE);
+ DestroyContextSummaryData (MemoryProfileContextSummaryData);
+ }
+
+ Print (L"======= UefiMemoryProfile end =======\n\n\n");
+
+Done:
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ //
+ // Restore recording state if needed.
+ //
+ if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
+ ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_ENABLE);
+ }
+
+ return Status;
+}
+
+/**
+ Get and dump SMRAM profile data.
+
+ @return EFI_SUCCESS Get the SMRAM profile data successfully.
+ @return other Fail to get the SMRAM profile data.
+
+**/
+EFI_STATUS
+GetSmramProfileData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *CommGetProfileInfo;
+ SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *CommGetProfileData;
+ SMRAM_PROFILE_PARAMETER_RECORDING_STATE *CommRecordingState;
+ UINTN ProfileSize;
+ VOID *ProfileBuffer;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ UINTN MinimalSizeNeeded;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ VOID *Buffer;
+ UINTN Size;
+ UINTN Offset;
+ MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData;
+ BOOLEAN RecordingState;
+
+ ProfileBuffer = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfile: Locate SmmCommunication protocol - %r\n", Status));
+ return Status;
+ }
+
+ MinimalSizeNeeded = sizeof (EFI_GUID) +
+ sizeof (UINTN) +
+ MAX (sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO),
+ MAX (sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET),
+ sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)));
+ MinimalSizeNeeded += MAX (sizeof (MEMORY_PROFILE_CONTEXT),
+ MAX (sizeof (MEMORY_PROFILE_DRIVER_INFO),
+ MAX (sizeof (MEMORY_PROFILE_ALLOC_INFO),
+ MAX (sizeof (MEMORY_PROFILE_DESCRIPTOR),
+ MAX (sizeof (MEMORY_PROFILE_FREE_MEMORY),
+ sizeof (MEMORY_PROFILE_MEMORY_RANGE))))));
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfile: Get PiSmmCommunicationRegionTable - %r\n", Status));
+ return Status;
+ }
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
+ if (Size >= MinimalSizeNeeded) {
+ break;
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
+ CommBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
+
+ //
+ // Set recording state if needed.
+ //
+ RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
+
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
+ CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
+
+ CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE;
+ CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
+ CommRecordingState->Header.ReturnStatus = (UINT64)-1;
+ CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
+
+ CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
+ Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfile: SmmCommunication - %r\n", Status));
+ return Status;
+ }
+
+ if (CommRecordingState->Header.ReturnStatus != 0) {
+ Print (L"SmramProfile: GetRecordingState - 0x%0x\n", CommRecordingState->Header.ReturnStatus);
+ return EFI_SUCCESS;
+ }
+ RecordingState = CommRecordingState->RecordingState;
+ if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
+ CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
+
+ CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE;
+ CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
+ CommRecordingState->Header.ReturnStatus = (UINT64)-1;
+ CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
+
+ CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
+ SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
+ }
+
+ //
+ // Get Size
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
+ CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO);
+
+ CommGetProfileInfo = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommGetProfileInfo->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO;
+ CommGetProfileInfo->Header.DataLength = sizeof (*CommGetProfileInfo);
+ CommGetProfileInfo->Header.ReturnStatus = (UINT64)-1;
+ CommGetProfileInfo->ProfileSize = 0;
+
+ CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
+ Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ if (CommGetProfileInfo->Header.ReturnStatus != 0) {
+ Status = EFI_SUCCESS;
+ Print (L"SmramProfile: GetProfileInfo - 0x%0x\n", CommGetProfileInfo->Header.ReturnStatus);
+ goto Done;
+ }
+
+ ProfileSize = (UINTN) CommGetProfileInfo->ProfileSize;
+
+ //
+ // Get Data
+ //
+ ProfileBuffer = AllocateZeroPool (ProfileSize);
+ if (ProfileBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ Print (L"SmramProfile: AllocateZeroPool (0x%x) for profile buffer - %r\n", ProfileSize, Status);
+ goto Done;
+ }
+
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof(gEdkiiMemoryProfileGuid));
+ CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET);
+
+ CommGetProfileData = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommGetProfileData->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET;
+ CommGetProfileData->Header.DataLength = sizeof (*CommGetProfileData);
+ CommGetProfileData->Header.ReturnStatus = (UINT64)-1;
+
+ CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
+ Buffer = (UINT8 *) CommHeader + CommSize;
+ Size -= CommSize;
+
+ CommGetProfileData->ProfileBuffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
+ CommGetProfileData->ProfileOffset = 0;
+ while (CommGetProfileData->ProfileOffset < ProfileSize) {
+ Offset = (UINTN) CommGetProfileData->ProfileOffset;
+ if (Size <= (ProfileSize - CommGetProfileData->ProfileOffset)) {
+ CommGetProfileData->ProfileSize = (UINT64) Size;
+ } else {
+ CommGetProfileData->ProfileSize = (UINT64) (ProfileSize - CommGetProfileData->ProfileOffset);
+ }
+ Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ if (CommGetProfileData->Header.ReturnStatus != 0) {
+ Status = EFI_SUCCESS;
+ Print (L"GetProfileData - 0x%x\n", CommGetProfileData->Header.ReturnStatus);
+ goto Done;
+ }
+ CopyMem ((UINT8 *) ProfileBuffer + Offset, (VOID *) (UINTN) CommGetProfileData->ProfileBuffer, (UINTN) CommGetProfileData->ProfileSize);
+ }
+
+
+ Print (L"SmramProfileSize - 0x%x\n", ProfileSize);
+ Print (L"======= SmramProfile begin =======\n");
+ DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) ProfileBuffer, ProfileSize, TRUE);
+
+ //
+ // Dump summary information
+ //
+ MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS) (UINTN) ProfileBuffer, ProfileSize);
+ if (MemoryProfileContextSummaryData != NULL) {
+ DumpContextSummaryData (MemoryProfileContextSummaryData, TRUE);
+ DestroyContextSummaryData (MemoryProfileContextSummaryData);
+ }
+
+ Print (L"======= SmramProfile end =======\n\n\n");
+
+Done:
+ if (ProfileBuffer != NULL) {
+ FreePool (ProfileBuffer);
+ }
+
+ //
+ // Restore recording state if needed.
+ //
+ if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
+ CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
+
+ CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE;
+ CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
+ CommRecordingState->Header.ReturnStatus = (UINT64)-1;
+ CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_ENABLE;
+
+ CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
+ SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
+ }
+
+ return Status;
+}
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the image goes into a library that calls 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
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetUefiMemoryProfileData ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "GetUefiMemoryProfileData - %r\n", Status));
+ }
+
+ Status = GetSmramProfileData ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "GetSmramProfileData - %r\n", Status));
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
new file mode 100644
index 000000000..73eb877aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
@@ -0,0 +1,56 @@
+## @file
+# Shell application to dump UEFI memory and SMRAM profile information.
+#
+# Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask,
+# the application will not display memory profile information.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MemoryProfileInfo
+ MODULE_UNI_FILE = MemoryProfileInfo.uni
+ FILE_GUID = 21429B90-5F67-4e93-AF55-1D314D646E12
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MemoryProfileInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ BaseLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DebugLib
+ UefiLib
+ MemoryAllocationLib
+ DxeServicesLib
+ PrintLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+ ## SOMETIMES_CONSUMES ## GUID # SmiHandlerRegister
+ gEdkiiMemoryProfileGuid
+ gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MemoryProfileInfoExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni
new file mode 100644
index 000000000..675316f5d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Shell application to dump UEFI memory and SMRAM profile information.
+//
+// Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask,
+// the application will not display memory profile information.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Shell application to dump UEFI memory and SMRAM profile information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask, the application will not display memory profile information."
+
diff --git a/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni
new file mode 100644
index 000000000..354edd980
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// MemoryProfileInfo Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Memory Profile Information Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c
new file mode 100644
index 000000000..4153074b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c
@@ -0,0 +1,686 @@
+/** @file
+ Shell application to dump SMI handler profile information.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#include <Guid/SmiHandlerProfile.h>
+
+#define PROFILE_NAME_STRING_LENGTH 64
+CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1];
+
+VOID *mSmiHandlerProfileDatabase;
+UINTN mSmiHandlerProfileDatabaseSize;
+
+/**
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ Print (L"%02x", (UINTN)Data[Index]);
+ if ((Index + 1) != Size) {
+ Print (L" ");
+ }
+ }
+}
+
+/**
+ Get SMI handler profile database.
+**/
+VOID
+GetSmiHandlerProfileDatabase(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *CommGetInfo;
+ SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *CommGetData;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ UINTN MinimalSizeNeeded;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ VOID *Buffer;
+ UINTN Size;
+ UINTN Offset;
+
+ Status = gBS->LocateProtocol(&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **)&SmmCommunication);
+ if (EFI_ERROR(Status)) {
+ Print(L"SmiHandlerProfile: Locate SmmCommunication protocol - %r\n", Status);
+ return ;
+ }
+
+ MinimalSizeNeeded = EFI_PAGE_SIZE;
+
+ Status = EfiGetSystemConfigurationTable(
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **)&PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"SmiHandlerProfile: Get PiSmmCommunicationRegionTable - %r\n", Status);
+ return ;
+ }
+ ASSERT(PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE((UINTN)Entry->NumberOfPages);
+ if (Size >= MinimalSizeNeeded) {
+ break;
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ ASSERT(Index < PiSmmCommunicationRegionTable->NumberOfEntries);
+ CommBuffer = (UINT8 *)(UINTN)Entry->PhysicalStart;
+
+ //
+ // Get Size
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid));
+ CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO);
+
+ CommGetInfo = (SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommGetInfo->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_INFO;
+ CommGetInfo->Header.DataLength = sizeof(*CommGetInfo);
+ CommGetInfo->Header.ReturnStatus = (UINT64)-1;
+ CommGetInfo->DataSize = 0;
+
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength;
+ Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize);
+ if (EFI_ERROR(Status)) {
+ Print(L"SmiHandlerProfile: SmmCommunication - %r\n", Status);
+ return ;
+ }
+
+ if (CommGetInfo->Header.ReturnStatus != 0) {
+ Print(L"SmiHandlerProfile: GetInfo - 0x%0x\n", CommGetInfo->Header.ReturnStatus);
+ return ;
+ }
+
+ mSmiHandlerProfileDatabaseSize = (UINTN)CommGetInfo->DataSize;
+
+ //
+ // Get Data
+ //
+ mSmiHandlerProfileDatabase = AllocateZeroPool(mSmiHandlerProfileDatabaseSize);
+ if (mSmiHandlerProfileDatabase == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ Print(L"SmiHandlerProfile: AllocateZeroPool (0x%x) for dump buffer - %r\n", mSmiHandlerProfileDatabaseSize, Status);
+ return ;
+ }
+
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid));
+ CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET);
+
+ CommGetData = (SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)];
+ CommGetData->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET;
+ CommGetData->Header.DataLength = sizeof(*CommGetData);
+ CommGetData->Header.ReturnStatus = (UINT64)-1;
+
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength;
+ Buffer = (UINT8 *)CommHeader + CommSize;
+ Size -= CommSize;
+
+ CommGetData->DataBuffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
+ CommGetData->DataOffset = 0;
+ while (CommGetData->DataOffset < mSmiHandlerProfileDatabaseSize) {
+ Offset = (UINTN)CommGetData->DataOffset;
+ if (Size <= (mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset)) {
+ CommGetData->DataSize = (UINT64)Size;
+ } else {
+ CommGetData->DataSize = (UINT64)(mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset);
+ }
+ Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR(Status);
+
+ if (CommGetData->Header.ReturnStatus != 0) {
+ FreePool(mSmiHandlerProfileDatabase);
+ mSmiHandlerProfileDatabase = NULL;
+ Print(L"SmiHandlerProfile: GetData - 0x%x\n", CommGetData->Header.ReturnStatus);
+ return ;
+ }
+ CopyMem((UINT8 *)mSmiHandlerProfileDatabase + Offset, (VOID *)(UINTN)CommGetData->DataBuffer, (UINTN)CommGetData->DataSize);
+ }
+
+ DEBUG ((DEBUG_INFO, "SmiHandlerProfileSize - 0x%x\n", mSmiHandlerProfileDatabaseSize));
+
+ return ;
+}
+
+/**
+ Get the file name portion of the Pdb File Name.
+
+ The portion of the Pdb File Name between the last backslash and
+ either a following period or the end of the string is copied into
+ AsciiBuffer. The name is truncated, if necessary, to ensure that
+ AsciiBuffer is not overrun.
+
+ @param[in] PdbFileName Pdb file name.
+ @param[out] AsciiBuffer The resultant Ascii File Name.
+
+**/
+VOID
+GetShortPdbFileName (
+ IN CHAR8 *PdbFileName,
+ OUT CHAR8 *AsciiBuffer
+ )
+{
+ UINTN IndexPdb; // Current work location within a Pdb string.
+ UINTN IndexBuffer; // Current work location within a Buffer string.
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1);
+
+ if (PdbFileName == NULL) {
+ AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1);
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++);
+ for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) {
+ if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) {
+ StartIndex = IndexPdb + 1;
+ }
+
+ if (PdbFileName[IndexPdb] == '.') {
+ EndIndex = IndexPdb;
+ }
+ }
+
+ IndexBuffer = 0;
+ for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) {
+ AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb];
+ IndexBuffer++;
+ if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) {
+ AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Get a human readable name for an image.
+ The following methods will be tried orderly:
+ 1. Image PDB
+ 2. FFS UI section
+ 3. Image GUID
+
+ @param[in] ImageStruct Point to the image structure.
+
+ @return The resulting Ascii name string is stored in the mNameString global array.
+
+**/
+CHAR8 *
+GetDriverNameString (
+ IN SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *NameString;
+ UINTN StringSize;
+
+ if (ImageStruct == NULL) {
+ return "???";
+ }
+
+ //
+ // Method 1: Get the name string from image PDB
+ //
+ if (ImageStruct->PdbStringOffset != 0) {
+ GetShortPdbFileName ((CHAR8 *) ((UINTN) ImageStruct + ImageStruct->PdbStringOffset), mNameString);
+ return mNameString;
+ }
+
+ if (!IsZeroGuid (&ImageStruct->FileGuid)) {
+ //
+ // Try to get the image's FFS UI section by image GUID
+ //
+ NameString = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ &ImageStruct->FileGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &NameString,
+ &StringSize
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Method 2: Get the name string from FFS UI section
+ //
+ if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) {
+ NameString[PROFILE_NAME_STRING_LENGTH] = 0;
+ }
+ UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString));
+ FreePool (NameString);
+ return mNameString;
+ }
+ }
+
+ //
+ // Method 3: Get the name string from image GUID
+ //
+ AsciiSPrint (mNameString, sizeof (mNameString), "%g", &ImageStruct->FileGuid);
+ return mNameString;
+}
+
+/**
+ Get image structure from reference index.
+
+ @param ImageRef the image reference index
+
+ @return image structure
+**/
+SMM_CORE_IMAGE_DATABASE_STRUCTURE *
+GetImageFromRef (
+ IN UINTN ImageRef
+ )
+{
+ SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
+
+ ImageStruct = (VOID *)mSmiHandlerProfileDatabase;
+ while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) {
+ if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) {
+ if (ImageStruct->ImageRef == ImageRef) {
+ return ImageStruct;
+ }
+ }
+ ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length);
+ }
+
+ return NULL;
+}
+
+/**
+ Dump SMM loaded image information.
+**/
+VOID
+DumpSmmLoadedImage(
+ VOID
+ )
+{
+ SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
+ CHAR8 *PdbString;
+ CHAR8 *NameString;
+
+ ImageStruct = (VOID *)mSmiHandlerProfileDatabase;
+ while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) {
+ if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) {
+ NameString = GetDriverNameString (ImageStruct);
+ Print(L" <Image Name=\"%a\"", NameString);
+ Print(L" Base=\"0x%lx\" Size=\"0x%lx\"", ImageStruct->ImageBase, ImageStruct->ImageSize);
+ if (ImageStruct->EntryPoint != 0) {
+ Print(L" EntryPoint=\"0x%lx\"", ImageStruct->EntryPoint);
+ }
+ Print(L" FvFile=\"%g\"", &ImageStruct->FileGuid);
+ Print(L" RefId=\"0x%x\"", ImageStruct->ImageRef);
+ Print(L">\n");
+ if (ImageStruct->PdbStringOffset != 0) {
+ PdbString = (CHAR8 *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset);
+ Print(L" <Pdb>%a</Pdb>\n", PdbString);
+ }
+ Print(L" </Image>\n");
+ }
+
+ ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length);
+ }
+
+ return;
+}
+
+CHAR8 *mSxTypeString[] = {
+ "SxS0",
+ "SxS1",
+ "SxS2",
+ "SxS3",
+ "SxS4",
+ "SxS5",
+};
+
+/**
+ Convert SxType to a string.
+
+ @param Type SxType
+
+ @return SxType string
+**/
+CHAR8 *
+SxTypeToString (
+ IN EFI_SLEEP_TYPE Type
+ )
+{
+ if (Type >= 0 && Type < ARRAY_SIZE(mSxTypeString)) {
+ return mSxTypeString[Type];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type);
+ return mNameString;
+ }
+}
+
+CHAR8 *mSxPhaseString[] = {
+ "SxEntry",
+ "SxExit",
+};
+
+/**
+ Convert SxPhase to a string.
+
+ @param Phase SxPhase
+
+ @return SxPhase string
+**/
+CHAR8 *
+SxPhaseToString (
+ IN EFI_SLEEP_PHASE Phase
+ )
+{
+ if (Phase >= 0 && Phase < ARRAY_SIZE(mSxPhaseString)) {
+ return mSxPhaseString[Phase];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase);
+ return mNameString;
+ }
+}
+
+CHAR8 *mPowerButtonPhaseString[] = {
+ "PowerButtonEntry",
+ "PowerButtonExit",
+};
+
+/**
+ Convert PowerButtonPhase to a string.
+
+ @param Phase PowerButtonPhase
+
+ @return PowerButtonPhase string
+**/
+CHAR8 *
+PowerButtonPhaseToString (
+ IN EFI_POWER_BUTTON_PHASE Phase
+ )
+{
+ if (Phase >= 0 && Phase < ARRAY_SIZE(mPowerButtonPhaseString)) {
+ return mPowerButtonPhaseString[Phase];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase);
+ return mNameString;
+ }
+}
+
+CHAR8 *mStandbyButtonPhaseString[] = {
+ "StandbyButtonEntry",
+ "StandbyButtonExit",
+};
+
+/**
+ Convert StandbyButtonPhase to a string.
+
+ @param Phase StandbyButtonPhase
+
+ @return StandbyButtonPhase string
+**/
+CHAR8 *
+StandbyButtonPhaseToString (
+ IN EFI_STANDBY_BUTTON_PHASE Phase
+ )
+{
+ if (Phase >= 0 && Phase < ARRAY_SIZE(mStandbyButtonPhaseString)) {
+ return mStandbyButtonPhaseString[Phase];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase);
+ return mNameString;
+ }
+}
+
+CHAR8 *mIoTrapTypeString[] = {
+ "WriteTrap",
+ "ReadTrap",
+ "ReadWriteTrap",
+};
+
+/**
+ Convert IoTrapType to a string.
+
+ @param Type IoTrapType
+
+ @return IoTrapType string
+**/
+CHAR8 *
+IoTrapTypeToString (
+ IN EFI_SMM_IO_TRAP_DISPATCH_TYPE Type
+ )
+{
+ if (Type >= 0 && Type < ARRAY_SIZE(mIoTrapTypeString)) {
+ return mIoTrapTypeString[Type];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type);
+ return mNameString;
+ }
+}
+
+CHAR8 *mUsbTypeString[] = {
+ "UsbLegacy",
+ "UsbWake",
+};
+
+/**
+ Convert UsbType to a string.
+
+ @param Type UsbType
+
+ @return UsbType string
+**/
+CHAR8 *
+UsbTypeToString (
+ IN EFI_USB_SMI_TYPE Type
+ )
+{
+ if (Type >= 0 && Type < ARRAY_SIZE(mUsbTypeString)) {
+ return mUsbTypeString[Type];
+ } else {
+ AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type);
+ return mNameString;
+ }
+}
+
+/**
+ Dump SMI child context.
+
+ @param HandlerType the handler type
+ @param Context the handler context
+ @param ContextSize the handler context size
+**/
+VOID
+DumpSmiChildContext (
+ IN EFI_GUID *HandlerType,
+ IN VOID *Context,
+ IN UINTN ContextSize
+ )
+{
+ CHAR16 *Str;
+
+ if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ Print(L" SwSmi=\"0x%lx\"", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue);
+ } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) {
+ Print(L" SxType=\"%a\"", SxTypeToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type));
+ Print(L" SxPhase=\"%a\"", SxPhaseToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) {
+ Print(L" PowerButtonPhase=\"%a\"", PowerButtonPhaseToString(((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) {
+ Print(L" StandbyButtonPhase=\"%a\"", StandbyButtonPhaseToString(((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) {
+ Print(L" PeriodicTimerPeriod=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period);
+ Print(L" PeriodicTimerSmiTickInterval=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval);
+ } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) {
+ Print(L" GpiNum=\"0x%lx\"", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum);
+ } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) {
+ Print(L" IoTrapAddress=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address);
+ Print(L" IoTrapLength=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length);
+ Print(L" IoTrapType=\"%a\"", IoTrapTypeToString(((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type));
+ } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ Print(L" UsbType=\"0x%x\"", UsbTypeToString(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type));
+ Str = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE);
+ Print(L" UsbDevicePath=\"%s\"", Str);
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+ } else {
+ Print(L" Context=\"");
+ InternalDumpData (Context, ContextSize);
+ Print(L"\"");
+ }
+}
+
+/**
+ Dump SMI handler in HandlerCategory.
+
+ @param HandlerCategory SMI handler category
+**/
+VOID
+DumpSmiHandler(
+ IN UINT32 HandlerCategory
+ )
+{
+ SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct;
+ SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct;
+ UINTN Index;
+ SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
+ CHAR8 *NameString;
+
+ SmiStruct = (VOID *)mSmiHandlerProfileDatabase;
+ while ((UINTN)SmiStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) {
+ if ((SmiStruct->Header.Signature == SMM_CORE_SMI_DATABASE_SIGNATURE) && (SmiStruct->HandlerCategory == HandlerCategory)) {
+ SmiHandlerStruct = (VOID *)(SmiStruct + 1);
+ Print(L" <SmiEntry");
+ if (!IsZeroGuid (&SmiStruct->HandlerType)) {
+ Print(L" HandlerType=\"%g\"", &SmiStruct->HandlerType);
+ }
+ Print(L">\n");
+ for (Index = 0; Index < SmiStruct->HandlerCount; Index++) {
+ Print(L" <SmiHandler");
+ if (SmiHandlerStruct->ContextBufferSize != 0) {
+ DumpSmiChildContext (&SmiStruct->HandlerType, (UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandlerStruct->ContextBufferSize);
+ }
+ Print(L">\n");
+ ImageStruct = GetImageFromRef((UINTN)SmiHandlerStruct->ImageRef);
+ NameString = GetDriverNameString (ImageStruct);
+ Print(L" <Module RefId=\"0x%x\" Name=\"%a\">\n", SmiHandlerStruct->ImageRef, NameString);
+ if ((ImageStruct != NULL) && (ImageStruct->PdbStringOffset != 0)) {
+ Print(L" <Pdb>%a</Pdb>\n", (UINT8 *)ImageStruct + ImageStruct->PdbStringOffset);
+ }
+ Print(L" </Module>\n");
+ Print(L" <Handler Address=\"0x%lx\">\n", SmiHandlerStruct->Handler);
+ if (ImageStruct != NULL) {
+ Print(L" <RVA>0x%x</RVA>\n", (UINTN) (SmiHandlerStruct->Handler - ImageStruct->ImageBase));
+ }
+ Print(L" </Handler>\n", SmiHandlerStruct->Handler);
+ Print(L" <Caller Address=\"0x%lx\">\n", SmiHandlerStruct->CallerAddr);
+ if (ImageStruct != NULL) {
+ Print(L" <RVA>0x%x</RVA>\n", (UINTN) (SmiHandlerStruct->CallerAddr - ImageStruct->ImageBase));
+ }
+ Print(L" </Caller>\n", SmiHandlerStruct->Handler);
+ SmiHandlerStruct = (VOID *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length);
+ Print(L" </SmiHandler>\n");
+ }
+ Print(L" </SmiEntry>\n");
+ }
+ SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length);
+ }
+
+ return;
+}
+
+/**
+ The Entry Point for SMI handler profile info application.
+
+ @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.
+ @retval Other Some error occurred when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileInfoEntrypoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ GetSmiHandlerProfileDatabase();
+
+ if (mSmiHandlerProfileDatabase == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Dump all image
+ //
+ Print(L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ Print(L"<SmiHandlerProfile>\n");
+ Print(L"<ImageDatabase>\n");
+ Print(L" <!-- SMM image loaded -->\n");
+ DumpSmmLoadedImage();
+ Print(L"</ImageDatabase>\n\n");
+
+ //
+ // Dump SMI Handler
+ //
+ Print(L"<SmiHandlerDatabase>\n");
+ Print(L" <!-- SMI Handler registered -->\n\n");
+ Print(L" <SmiHandlerCategory Name=\"RootSmi\">\n");
+ Print(L" <!-- The root SMI Handler registered by SmmCore -->\n");
+ DumpSmiHandler(SmmCoreSmiHandlerCategoryRootHandler);
+ Print(L" </SmiHandlerCategory>\n\n");
+
+ Print(L" <SmiHandlerCategory Name=\"GuidSmi\">\n");
+ Print(L" <!-- The GUID SMI Handler registered by SmmCore -->\n");
+ DumpSmiHandler(SmmCoreSmiHandlerCategoryGuidHandler);
+ Print(L" </SmiHandlerCategory>\n\n");
+
+ Print(L" <SmiHandlerCategory Name=\"HardwareSmi\">\n");
+ Print(L" <!-- The hardware SMI Handler registered by SmmChildDispatcher -->\n");
+ DumpSmiHandler(SmmCoreSmiHandlerCategoryHardwareHandler);
+ Print(L" </SmiHandlerCategory>\n\n");
+
+ Print(L"</SmiHandlerDatabase>\n");
+ Print(L"</SmiHandlerProfile>\n");
+
+ if (mSmiHandlerProfileDatabase != NULL) {
+ FreePool(mSmiHandlerProfileDatabase);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf
new file mode 100644
index 000000000..eae4e6a87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf
@@ -0,0 +1,58 @@
+## @file
+# Shell application to dump SMI handler profile information.
+#
+# Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask,
+# the application will not display SMI handler profile information.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmiHandlerProfileInfo
+ MODULE_UNI_FILE = SmiHandlerProfileInfo.uni
+ FILE_GUID = 611EA796-8DF8-4BB6-91FE-6540ED70DC66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmiHandlerProfileInfoEntrypoint
+
+[Sources]
+ SmiHandlerProfileInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ PrintLib
+ DevicePathLib
+ DxeServicesLib
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## CONSUMES
+ gEfiSmmSwDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmPowerButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmStandbyButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEdkiiPiSmmCommunicationRegionTableGuid ## CONSUMES ## SystemTable
+ gSmiHandlerProfileGuid ## SOMETIMES_CONSUMES ## GUID # SmiHandlerRegister
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmiHandlerProfileInfoExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni
new file mode 100644
index 000000000..71ec9c223
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Shell application to dump SMI handler profile information.
+//
+// Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask,
+// the application will not display SMI handler profile information.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Shell application to dump SMI handler profile information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note that if the feature is not enabled by setting PcdSmiHandlerProfilePropertyMask, the application will not display SMI handler profile information."
+
diff --git a/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni
new file mode 100644
index 000000000..449e6a100
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfoExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmiHandlerProfileInfo Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMI Handler Profile Information Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.c b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.c
new file mode 100644
index 000000000..4b95cccb5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.c
@@ -0,0 +1,1113 @@
+/** @file
+ FrontPage routines to handle the callbacks and browser calls
+
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FrontPage.h"
+#include "FrontPageCustomizedUi.h"
+
+#define MAX_STRING_LEN 200
+
+EFI_GUID mFrontPageGuid = FRONT_PAGE_FORMSET_GUID;
+
+BOOLEAN mResetRequired = FALSE;
+
+EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+CHAR8 *mLanguageString;
+BOOLEAN mModeInitialized = FALSE;
+//
+// 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;
+
+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)
+ }
+ },
+ //
+ // {8E6D99EE-7531-48f8-8745-7F6144468FF2}
+ //
+ { 0x8e6d99ee, 0x7531, 0x48f8, { 0x87, 0x45, 0x7f, 0x61, 0x44, 0x46, 0x8f, 0xf2 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Update the banner information for the Front Page based on Smbios information.
+
+**/
+VOID
+UpdateFrontPageBannerStrings (
+ VOID
+ );
+
+/**
+ 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;
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ 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
+ )
+{
+ return UiFrontPageCallbackHandler (gFrontPagePrivate.HiiHandle, Action, QuestionId, Type, Value, ActionRequest);
+}
+
+/**
+
+ Update the menus in the front page.
+
+**/
+VOID
+UpdateFrontPageForm (
+ VOID
+ )
+{
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartGuidLabel;
+ EFI_IFR_GUID_LABEL *EndGuidLabel;
+
+ //
+ // 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
+ //
+ StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartGuidLabel->Number = LABEL_FRANTPAGE_INFORMATION;
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndGuidLabel->Number = LABEL_END;
+
+ //
+ //Updata Front Page form
+ //
+ UiCustomizeFrontPage (
+ gFrontPagePrivate.HiiHandle,
+ StartOpCodeHandle
+ );
+
+ HiiUpdateForm (
+ gFrontPagePrivate.HiiHandle,
+ &mFrontPageGuid,
+ FRONT_PAGE_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+/**
+ Initialize HII information for the FrontPage
+
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed.
+
+**/
+EFI_STATUS
+InitializeFrontPage (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ //
+ // 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
+ //
+ gFrontPagePrivate.DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gFrontPagePrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mFrontPageHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gFrontPagePrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ gFrontPagePrivate.HiiHandle = HiiAddPackages (
+ &mFrontPageGuid,
+ gFrontPagePrivate.DriverHandle,
+ FrontPageVfrBin,
+ UiAppStrings,
+ NULL
+ );
+ ASSERT (gFrontPagePrivate.HiiHandle != NULL);
+
+ //
+ //Updata Front Page banner strings
+ //
+ UpdateFrontPageBannerStrings ();
+
+ //
+ // Update front page menus.
+ //
+ UpdateFrontPageForm();
+
+ 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,
+ &mFrontPageGuid,
+ 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;
+}
+
+/**
+ Remove the installed packages from the HiiDatabase.
+
+**/
+VOID
+FreeFrontPage(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gFrontPagePrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mFrontPageHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gFrontPagePrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ HiiRemovePackages (gFrontPagePrivate.HiiHandle);
+ if (gFrontPagePrivate.LanguageToken != NULL) {
+ FreePool (gFrontPagePrivate.LanguageToken);
+ gFrontPagePrivate.LanguageToken = NULL;
+ }
+}
+
+/**
+ 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;
+ UINTN DestMax;
+ UINT32 FreqMhz;
+
+ if (Base10Exponent >= 6) {
+ FreqMhz = ProcessorFrequency;
+ for (Index = 0; Index < (UINT32) Base10Exponent - 6; Index++) {
+ FreqMhz *= 10;
+ }
+ } else {
+ FreqMhz = 0;
+ }
+ DestMax = 0x20 / sizeof (CHAR16);
+ StringBuffer = AllocateZeroPool (0x20);
+ ASSERT (StringBuffer != NULL);
+ UnicodeValueToStringS (StringBuffer, sizeof (CHAR16) * DestMax, LEFT_JUSTIFY, FreqMhz / 1000, 3);
+ Index = StrnLenS (StringBuffer, DestMax);
+ StrCatS (StringBuffer, DestMax, L".");
+ UnicodeValueToStringS (
+ StringBuffer + Index + 1,
+ sizeof (CHAR16) * (DestMax - (Index + 1)),
+ PREFIX_ZERO,
+ (FreqMhz % 1000) / 10,
+ 2
+ );
+ StrCatS (StringBuffer, DestMax, 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 (0x24);
+ ASSERT (StringBuffer != NULL);
+ UnicodeValueToStringS (StringBuffer, 0x24, LEFT_JUSTIFY, MemorySize, 10);
+ StrCatS (StringBuffer, 0x24 / 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 Smbios information.
+
+**/
+VOID
+UpdateFrontPageBannerStrings (
+ VOID
+ )
+{
+ UINT8 StrIndex;
+ CHAR16 *NewString;
+ CHAR16 *FirmwareVersionString;
+ EFI_STATUS Status;
+ 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;
+ UINT64 InstalledMemory;
+ BOOLEAN FoundCpu;
+
+ InstalledMemory = 0;
+ FoundCpu = 0;
+
+ //
+ // Update default banner string.
+ //
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_LEFT), NULL);
+ UiCustomizeFrontPageBanner (4, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_LEFT), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_RIGHT), NULL);
+ UiCustomizeFrontPageBanner (4, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE4_RIGHT), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_LEFT), NULL);
+ UiCustomizeFrontPageBanner (5, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_LEFT), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_RIGHT), NULL);
+ UiCustomizeFrontPageBanner (5, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_CUSTOMIZE_BANNER_LINE5_RIGHT), NewString, NULL);
+ FreePool (NewString);
+
+ //
+ // Update Front Page banner strings base on SmBios Table.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &Smbios);
+ if (EFI_ERROR (Status)) {
+ //
+ // Smbios protocol not found, get the default value.
+ //
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NULL);
+ UiCustomizeFrontPageBanner (1, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NULL);
+ UiCustomizeFrontPageBanner (2, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NULL);
+ UiCustomizeFrontPageBanner (2, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NULL);
+ UiCustomizeFrontPageBanner (3, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL);
+ FreePool (NewString);
+
+ NewString = HiiGetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NULL);
+ UiCustomizeFrontPageBanner (3, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NewString, NULL);
+ FreePool (NewString);
+
+ return;
+ }
+
+ SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+ Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+ while (!EFI_ERROR(Status)) {
+ if (Record->Type == SMBIOS_TYPE_BIOS_INFORMATION) {
+ Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
+ StrIndex = Type0Record->BiosVersion;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
+
+ FirmwareVersionString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);
+ if (*FirmwareVersionString != 0x0000 ) {
+ FreePool (NewString);
+ NewString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);
+ UiCustomizeFrontPageBanner (3, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL);
+ } else {
+ UiCustomizeFrontPageBanner (3, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL);
+ FreePool (NewString);
+ }
+ }
+
+ if (Record->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) {
+ Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
+ StrIndex = Type1Record->ProductName;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
+ UiCustomizeFrontPageBanner (1, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NewString, NULL);
+ FreePool (NewString);
+ }
+
+ if ((Record->Type == SMBIOS_TYPE_PROCESSOR_INFORMATION) && !FoundCpu) {
+ Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
+ //
+ // The information in the record should be only valid when the CPU Socket is populated.
+ //
+ if ((Type4Record->Status & SMBIOS_TYPE4_CPU_SOCKET_POPULATED) == SMBIOS_TYPE4_CPU_SOCKET_POPULATED) {
+ StrIndex = Type4Record->ProcessorVersion;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
+ UiCustomizeFrontPageBanner (2, TRUE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL), NewString, NULL);
+ FreePool (NewString);
+
+ ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
+ UiCustomizeFrontPageBanner (2, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED), NewString, NULL);
+ FreePool (NewString);
+
+ FoundCpu = TRUE;
+ }
+ }
+
+ if ( Record->Type == SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
+ Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
+ if (Type19Record->StartingAddress != 0xFFFFFFFF ) {
+ InstalledMemory += RShiftU64(Type19Record->EndingAddress -
+ Type19Record->StartingAddress + 1, 10);
+ } else {
+ InstalledMemory += RShiftU64(Type19Record->ExtendedEndingAddress -
+ Type19Record->ExtendedStartingAddress + 1, 20);
+ }
+ }
+
+ Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+ }
+
+ //
+ // Now update the total installed RAM size
+ //
+ ConvertMemorySizeToString ((UINT32)InstalledMemory, &NewString );
+ UiCustomizeFrontPageBanner (3, FALSE, &NewString);
+ HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE), NewString, NULL);
+ FreePool (NewString);
+}
+
+/**
+ 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
+UiSetConsoleMode (
+ 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 required 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 required 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 required 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;
+}
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the image goes into a library that calls 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
+InitializeUserInterface (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HII_HANDLE HiiHandle;
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN BootTextColumn;
+ UINTN BootTextRow;
+
+ 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;
+ }
+
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ //
+ // Install customized fonts needed by Front Page
+ //
+ HiiHandle = ExportFonts ();
+ ASSERT (HiiHandle != NULL);
+
+ InitializeStringSupport ();
+
+ UiSetConsoleMode (TRUE);
+ UiEntry (FALSE);
+ UiSetConsoleMode (FALSE);
+
+ UninitializeStringSupport ();
+ HiiRemovePackages (HiiHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry of the UI entry.
+ The function will present the main menu of the system UI.
+
+ @param ConnectAllHappened Caller passes the value to UI to avoid unnecessary connect-all.
+
+**/
+VOID
+EFIAPI
+UiEntry (
+ IN BOOLEAN ConnectAllHappened
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+
+ //
+ // Enter Setup page.
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
+ );
+
+ //
+ // Indicate if the connect all has been performed before.
+ // If has not been performed before, do here.
+ //
+ if (!ConnectAllHappened) {
+ EfiBootManagerConnectAll ();
+ }
+
+ //
+ // The boot option enumeration time is acceptable in Ui driver
+ //
+ EfiBootManagerRefreshAllBootOption ();
+
+ //
+ // 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);
+ }
+
+ InitializeFrontPage ();
+
+ CallFrontPage ();
+
+ FreeFrontPage ();
+
+ if (mLanguageString != NULL) {
+ FreePool (mLanguageString);
+ mLanguageString = NULL;
+ }
+
+ //
+ //Will leave browser, check any reset required change is applied? if yes, reset system
+ //
+ SetupResetReminder ();
+}
+
+//
+// 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.
+//
+
+
+
+
+
+/**
+ 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;
+}
+
+
+
+
+
+/**
+ 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 (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);
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.h b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.h
new file mode 100644
index 000000000..36207287b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPage.h
@@ -0,0 +1,213 @@
+/** @file
+Head file for front page.
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FRONT_PAGE_H_
+#define _FRONT_PAGE_H_
+
+#include "String.h"
+#include "Ui.h"
+
+#include <Protocol/BootLogo.h>
+//
+// These is the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 FrontPageVfrBin[];
+
+extern EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+
+
+#define SMBIOS_TYPE4_CPU_SOCKET_POPULATED BIT6
+
+//
+// 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 LABEL_FRANTPAGE_INFORMATION 0x1000
+#define LABEL_END 0xffff
+
+#define FRONT_PAGE_FORMSET_GUID \
+ { \
+ 0x9e0c30bc, 0x3f06, 0x4ba6, {0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe} \
+ }
+
+#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
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed.
+
+**/
+EFI_STATUS
+InitializeFrontPage (
+ VOID
+ );
+
+/**
+ 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 UI entry.
+ The function will present the main menu of the system UI.
+
+ @param ConnectAllHappened Caller passes the value to UI to avoid unnecessary connect-all.
+
+**/
+VOID
+EFIAPI
+UiEntry (
+ IN BOOLEAN ConnectAllHappened
+ );
+
+/**
+ Extract device path for given HII handle and class guid.
+
+ @param Handle The HII handle.
+
+ @retval NULL Fail to get the device path string.
+ @return PathString Get the device path string.
+
+**/
+CHAR16 *
+ExtractDevicePathFromHiiHandle (
+ IN EFI_HII_HANDLE Handle
+ );
+
+#endif // _FRONT_PAGE_H_
+
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c
new file mode 100644
index 000000000..e6d0be548
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.c
@@ -0,0 +1,139 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include "FrontPage.h"
+#include "FrontPageCustomizedUiSupport.h"
+
+extern FRONT_PAGE_CALLBACK_DATA gFrontPagePrivate;
+
+/**
+ Customize menus in the page.
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] StartOpCodeHandle The context used to insert opcode.
+ @param[in] CustomizePageType The page type need to be customized.
+
+**/
+VOID
+UiCustomizeFrontPage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ //
+ // Create "Select Language" menu with Oneof opcode.
+ //
+ UiCreateLanguageMenu (HiiHandle, StartOpCodeHandle);
+
+ //
+ // Create empty line.
+ //
+ UiCreateEmptyLine(HiiHandle, StartOpCodeHandle);
+
+ //
+ // Find third party drivers which need to be shown in the front page.
+ //
+ UiListThirdPartyDrivers (HiiHandle, &gEfiIfrFrontPageGuid, NULL, StartOpCodeHandle);
+
+ //
+ // Create empty line.
+ //
+ UiCreateEmptyLine(HiiHandle, StartOpCodeHandle);
+
+ //
+ // Create "Continue" menu.
+ //
+ UiCreateContinueMenu(HiiHandle, StartOpCodeHandle);
+
+ //
+ // Create reset menu.
+ //
+ UiCreateResetMenu(HiiHandle, StartOpCodeHandle);
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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
+UiFrontPageCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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
+ )
+{
+ EFI_STATUS Status;
+
+ if (UiSupportLibCallbackHandler (HiiHandle, Action, QuestionId, Type, Value, ActionRequest, &Status)) {
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Update the banner string in the front page.
+
+ Current layout for the banner string like below:
+ PS: Totally only 5 lines of banner supported.
+
+ Line 1: Left BannerStr RightBannerStr
+ Line 2: Left BannerStr RightBannerStr
+ Line 3: Left BannerStr RightBannerStr
+ Line 4: Left BannerStr RightBannerStr
+ Line 5: Left BannerStr RightBannerStr
+ <EmptyLine>
+ First menu in front page.
+ ...
+
+ @param LineIndex The line index of the banner need to check.
+ @param LeftOrRight The left or right banner need to check.
+ @param BannerStr Banner string need to update.
+ Input the current string and user can update
+ it and return the new string.
+
+**/
+VOID
+UiCustomizeFrontPageBanner (
+ IN UINTN LineIndex,
+ IN BOOLEAN LeftOrRight,
+ IN OUT EFI_STRING *BannerStr
+ )
+{
+ if ((LineIndex == 5) && LeftOrRight) {
+ // Update STR_CUSTOMIZE_BANNER_LINE5_LEFT
+ if (PcdGetBool(PcdTestKeyUsed)) {
+ if (BannerStr != NULL) {
+ FreePool(*BannerStr);
+ }
+ *BannerStr = HiiGetString(gFrontPagePrivate.HiiHandle, STRING_TOKEN(STR_TEST_KEY_USED), NULL);
+ }
+ }
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h
new file mode 100644
index 000000000..648f30338
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUi.h
@@ -0,0 +1,82 @@
+/** @file
+ This library class defines a set of interfaces to customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FRONTPAGE_CUSTOMIZED_UI_H__
+#define __FRONTPAGE_CUSTOMIZED_UI_H__
+
+/**
+ Update the banner string in the front page.
+
+ Current layout for the banner string like below:
+ PS: Totally only 5 lines of banner supported.
+
+ Line 1: Left BannerStr RightBannerStr
+ Line 2: Left BannerStr RightBannerStr
+ Line 3: Left BannerStr RightBannerStr
+ Line 4: Left BannerStr RightBannerStr
+ Line 5: Left BannerStr RightBannerStr
+ <EmptyLine>
+ First menu in front page.
+ ...
+
+ @param LineIndex The line index of the banner need to check.
+ @param LeftOrRight The left or right banner need to check.
+ @param BannerStr Banner string need to update.
+ Input the current string and user can update
+ it and return the new string.
+
+**/
+VOID
+UiCustomizeFrontPageBanner (
+ IN UINTN LineIndex,
+ IN BOOLEAN LeftOrRight,
+ IN OUT EFI_STRING *BannerStr
+ );
+
+/**
+ Customize menus in the page.
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] StartOpCodeHandle The context used to insert opcode.
+
+**/
+VOID
+UiCustomizeFrontPage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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
+UiFrontPageCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c
new file mode 100644
index 000000000..858fdfc53
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c
@@ -0,0 +1,672 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiString.h>
+
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "FrontPageCustomizedUiSupport.h"
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+#define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001
+
+#define UI_HII_DRIVER_LIST_SIZE 0x8
+
+#define FRONT_PAGE_KEY_CONTINUE 0x1000
+#define FRONT_PAGE_KEY_RESET 0x1001
+#define FRONT_PAGE_KEY_LANGUAGE 0x1002
+#define FRONT_PAGE_KEY_DRIVER 0x2000
+
+typedef struct {
+ EFI_STRING_ID PromptId;
+ EFI_STRING_ID HelpId;
+ EFI_STRING_ID DevicePathId;
+ EFI_GUID FormSetGuid;
+ BOOLEAN EmptyLineAfter;
+} UI_HII_DRIVER_INSTANCE;
+
+CHAR8 *gLanguageString;
+EFI_STRING_ID *gLanguageToken;
+UI_HII_DRIVER_INSTANCE *gHiiDriverList;
+extern EFI_HII_HANDLE gStringPackHandle;
+UINT8 gCurrentLanguageIndex;
+
+
+/**
+ 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
+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;
+}
+
+/**
+ This function processes the language changes in configuration.
+
+ @param Value A pointer to the data being sent to the original exporting driver.
+
+
+ @retval TRUE The callback successfully handled the action.
+ @retval FALSE The callback not supported in this handler.
+
+**/
+EFI_STATUS
+LanguageChangeHandler (
+ IN EFI_IFR_TYPE_VALUE *Value
+ )
+{
+ CHAR8 *LangCode;
+ CHAR8 *Lang;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Allocate working buffer for RFC 4646 language in supported LanguageString.
+ //
+ Lang = AllocatePool (AsciiStrSize (gLanguageString));
+ ASSERT (Lang != NULL);
+
+ Index = 0;
+ LangCode = gLanguageString;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (Index == Value->u8) {
+ gCurrentLanguageIndex = Value->u8;
+ break;
+ }
+
+ Index++;
+ }
+
+ if (Index == Value->u8) {
+ Status = gRT->SetVariable (
+ L"PlatformLang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (Lang),
+ Lang
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Lang);
+ return EFI_DEVICE_ERROR;
+ }
+ } else {
+ ASSERT (FALSE);
+ }
+ FreePool (Lang);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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.
+ @param Status Return the handle status.
+
+ @retval TRUE The callback successfully handled the action.
+ @retval FALSE The callback not supported in this handler.
+
+**/
+BOOLEAN
+UiSupportLibCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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,
+ OUT EFI_STATUS *Status
+ )
+{
+ if (QuestionId != FRONT_PAGE_KEY_CONTINUE &&
+ QuestionId != FRONT_PAGE_KEY_RESET &&
+ QuestionId != FRONT_PAGE_KEY_LANGUAGE) {
+ return FALSE;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) {
+ Value->u8 = gCurrentLanguageIndex;
+ *Status = EFI_SUCCESS;
+ } else {
+ *Status = EFI_UNSUPPORTED;
+ }
+ return TRUE;
+ }
+
+ if (Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ *Status = EFI_UNSUPPORTED;
+ return TRUE;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ *Status = EFI_INVALID_PARAMETER;
+ return TRUE;
+ }
+
+ *Status = EFI_SUCCESS;
+ 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:
+ *Status = LanguageChangeHandler(Value);
+ break;
+
+ case FRONT_PAGE_KEY_RESET:
+ //
+ // Reset
+ //
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ *Status = EFI_UNSUPPORTED;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Create Select language menu in the front page with oneof opcode.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateLanguageMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ CHAR8 *LangCode;
+ CHAR8 *Lang;
+ UINTN LangSize;
+ CHAR8 *CurrentLang;
+ UINTN OptionCount;
+ CHAR16 *StringBuffer;
+ VOID *OptionsOpCodeHandle;
+ UINTN StringSize;
+ EFI_STATUS Status;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+
+ Lang = NULL;
+ StringBuffer = NULL;
+
+ //
+ // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
+
+ //
+ // Get Support language list from variable.
+ //
+ GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL);
+ if (gLanguageString == NULL) {
+ gLanguageString = AllocateCopyPool (
+ AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
+ (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
+ );
+ ASSERT (gLanguageString != NULL);
+ }
+
+ if (gLanguageToken == NULL) {
+ //
+ // Count the language list number.
+ //
+ LangCode = gLanguageString;
+ Lang = AllocatePool (AsciiStrSize (gLanguageString));
+ ASSERT (Lang != NULL);
+
+ OptionCount = 0;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+ OptionCount ++;
+ }
+
+ //
+ // Allocate extra 1 as the end tag.
+ //
+ gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
+ ASSERT (gLanguageToken != NULL);
+
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
+ ASSERT_EFI_ERROR (Status);
+
+ LangCode = gLanguageString;
+ 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);
+ gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
+ FreePool (StringBuffer);
+
+ OptionCount++;
+ }
+ }
+
+ ASSERT (gLanguageToken != NULL);
+ LangCode = gLanguageString;
+ OptionCount = 0;
+ if (Lang == NULL) {
+ Lang = AllocatePool (AsciiStrSize (gLanguageString));
+ ASSERT (Lang != NULL);
+ }
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ gLanguageToken[OptionCount],
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_NUMERIC_SIZE_1,
+ (UINT8) OptionCount
+ );
+ gCurrentLanguageIndex = (UINT8) OptionCount;
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ gLanguageToken[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
+ );
+}
+
+/**
+ Create continue menu in the front page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateContinueMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ FRONT_PAGE_KEY_CONTINUE,
+ STRING_TOKEN (STR_CONTINUE_PROMPT),
+ STRING_TOKEN (STR_CONTINUE_PROMPT),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+}
+
+/**
+ Create empty line menu in the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateEmptyLine (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0);
+}
+
+/**
+ Create Reset menu in the front page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateResetMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ FRONT_PAGE_KEY_RESET,
+ STRING_TOKEN (STR_RESET_STRING),
+ STRING_TOKEN (STR_RESET_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+}
+
+/**
+ Extract device path for given HII handle and class guid.
+
+ @param Handle The HII handle.
+
+ @retval NULL Fail to get the device path string.
+ @return PathString Get the device path string.
+
+**/
+CHAR16 *
+ExtractDevicePathFromHiiHandle (
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ ASSERT (Handle != NULL);
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
+}
+
+/**
+ Check whether this driver need to be shown in the front page.
+
+ @param HiiHandle The hii handle for the driver.
+ @param Guid The special guid for the driver which is the target.
+ @param PromptId Return the prompt string id.
+ @param HelpId Return the help string id.
+ @param FormsetGuid Return the formset guid info.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+BOOLEAN
+RequiredDriver (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *Guid,
+ OUT EFI_STRING_ID *PromptId,
+ OUT EFI_STRING_ID *HelpId,
+ OUT VOID *FormsetGuid
+ )
+{
+ EFI_STATUS Status;
+ UINT8 ClassGuidNum;
+ EFI_GUID *ClassGuid;
+ EFI_IFR_FORM_SET *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ UINTN TempSize;
+ BOOLEAN RetVal;
+
+ Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+ TempSize = 0;
+ Ptr = (UINT8 *) Buffer;
+ while(TempSize < BufferSize) {
+ TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+
+ if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
+ Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+ continue;
+ }
+
+ ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0) {
+ if (!CompareGuid (Guid, ClassGuid)){
+ ClassGuid ++;
+ continue;
+ }
+
+ *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle;
+ *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help;
+ CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
+ RetVal = TRUE;
+ }
+ }
+
+ FreePool (Buffer);
+
+ return RetVal;
+}
+
+/**
+ Search the drivers in the system which need to show in the front page
+ and insert the menu to the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param ClassGuid The class guid for the driver which is the target.
+ @param SpecialHandlerFn The pointer to the special handler function, if any.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+EFI_STATUS
+UiListThirdPartyDrivers (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *ClassGuid,
+ IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ UINTN Index;
+ EFI_STRING String;
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ EFI_HII_HANDLE *HiiHandles;
+ CHAR16 *DevicePathStr;
+ UINTN Count;
+ UINTN CurrentSize;
+ UI_HII_DRIVER_INSTANCE *DriverListPtr;
+ EFI_STRING NewName;
+ BOOLEAN EmptyLineAfter;
+
+ if (gHiiDriverList != NULL) {
+ FreePool (gHiiDriverList);
+ }
+
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE));
+ ASSERT (gHiiDriverList != NULL);
+ DriverListPtr = gHiiDriverList;
+ CurrentSize = UI_HII_DRIVER_LIST_SIZE;
+
+ for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) {
+ if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) {
+ continue;
+ }
+
+ String = HiiGetString (HiiHandles[Index], Token, NULL);
+ if (String == NULL) {
+ String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ } else if (SpecialHandlerFn != NULL) {
+ //
+ // Check whether need to rename the driver name.
+ //
+ EmptyLineAfter = FALSE;
+ if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) {
+ FreePool (String);
+ String = NewName;
+ DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter;
+ }
+ }
+ DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ String = HiiGetString (HiiHandles[Index], TokenHelp, NULL);
+ if (String == NULL) {
+ String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ }
+ DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]);
+ if (DevicePathStr != NULL){
+ DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
+ FreePool (DevicePathStr);
+ } else {
+ DriverListPtr[Count].DevicePathId = 0;
+ }
+
+ Count++;
+ if (Count >= CurrentSize) {
+ DriverListPtr = ReallocatePool (
+ CurrentSize * sizeof (UI_HII_DRIVER_INSTANCE),
+ (Count + UI_HII_DRIVER_LIST_SIZE)
+ * sizeof (UI_HII_DRIVER_INSTANCE),
+ gHiiDriverList
+ );
+ ASSERT (DriverListPtr != NULL);
+ gHiiDriverList = DriverListPtr;
+ CurrentSize += UI_HII_DRIVER_LIST_SIZE;
+ }
+ }
+
+ FreePool (HiiHandles);
+
+ Index = 0;
+ while (gHiiDriverList[Index].PromptId != 0) {
+ HiiCreateGotoExOpCode (
+ StartOpCodeHandle,
+ 0,
+ gHiiDriverList[Index].PromptId,
+ gHiiDriverList[Index].HelpId,
+ 0,
+ (EFI_QUESTION_ID) (Index + FRONT_PAGE_KEY_DRIVER),
+ 0,
+ &gHiiDriverList[Index].FormSetGuid,
+ gHiiDriverList[Index].DevicePathId
+ );
+
+ if (gHiiDriverList[Index].EmptyLineAfter) {
+ UiCreateEmptyLine (HiiHandle, StartOpCodeHandle);
+ }
+
+ Index ++;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h
new file mode 100644
index 000000000..7be45849f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.h
@@ -0,0 +1,130 @@
+/** @file
+ This library class defines a set of interfaces to be used by customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FRONTPAGE_CUSTOMIZE_UI_SUPPORT_UI_H__
+#define __FRONTPAGE_CUSTOMIZE_UI_SUPPORT_UI_H__
+
+/**
+ Create continue menu in the front page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateContinueMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create empty line menu.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateEmptyLine (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Select language menu in the front page with oneof opcode.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateLanguageMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Reset menu.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+UiCreateResetMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Rename the driver name if necessary.
+
+ @param DriverName Input the driver name.
+ @param NewDriverName Return the new driver name.
+ @param EmptyLineAfter Whether need to insert empty line.
+
+ @retval New driver name if compared, else NULL.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *DRIVER_SPECIAL_HANDLER)(
+ IN CHAR16 *DriverName,
+ OUT CHAR16 **NewName,
+ OUT BOOLEAN *EmptyLineAfter
+);
+
+/**
+ Search the drivers in the system which need to show in the front page
+ and insert the menu to the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param ClassGuid The class guid for the driver which is the target.
+ @param SpecialHandlerFn The pointer to the special handler function, if any.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+EFI_STATUS
+UiListThirdPartyDrivers (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *ClassGuid,
+ IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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.
+ @param Status Return the handle status.
+
+ @retval TRUE The callback successfully handled the action.
+ @retval FALSE The callback not supported in this handler.
+
+**/
+BOOLEAN
+UiSupportLibCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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,
+ OUT EFI_STATUS *Status
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageStrings.uni b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageStrings.uni
new file mode 100644
index 000000000..a0ab9abce
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageStrings.uni
@@ -0,0 +1,68 @@
+///** @file
+//
+// String definitions for BdsPlatform formset.
+//
+// Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+#langdef en "Standard English"
+#langdef fr "Standard Français"
+
+#string STR_FRONT_PAGE_TITLE #language en-US "Front Page"
+ #language fr-FR "Front Page"
+#string STR_FRONT_PAGE_COMPUTER_MODEL #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_CPU_MODEL #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_CPU_SPEED #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_MEMORY_SIZE #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_BIOS_VERSION #language en-US ""
+ #language fr-FR ""
+#string STR_FRONT_PAGE_BANNER_0_LEFT #language en-US "Wonder Computer Model 1000Z Manufactured by Intel®"
+ #language fr-FR "Demander le Modèle d'Ordinateur 1000Z A Fabriqué par Intel®"
+#string STR_FRONT_PAGE_BANNER_0_RIGHT #language en-US "OK"
+ #language fr-FR "Bon"
+#string STR_FRONT_PAGE_BANNER_1_LEFT #language en-US "2 Pentium® X Xeon processors running at 800Thz"
+ #language fr-FR "2 processeurs Pentium® X Xeon tournants à 800Thz"
+#string STR_FRONT_PAGE_BANNER_1_RIGHT #language en-US "24 TB System RAM"
+ #language fr-FR "24 TB RAM de Système"
+#string STR_FRONT_PAGE_BANNER_2_LEFT #language en-US "ACME® EFI BIOS Version 13.5 Release 1039.92"
+ #language fr-FR "ACME® EFI BIOS Version 13.5 Release 1039.92"
+#string STR_FRONT_PAGE_BANNER_3_LEFT #language en-US "Serial Number: 1Z123456789MARMAR (Need SMBIOS entries)"
+ #language fr-FR "Numéro de série: 1Z123456789MARMAR (Les entrées de SMBIOS de besoin)"
+#string STR_CONTINUE_PROMPT #language en-US "Continue"
+ #language fr-FR "Continuer"
+#string STR_CONTINUE_HELP #language en-US "This selection will direct the system to continue to booting process"
+ #language fr-FR "Cette sélection dirigera le système pour continuer au processus d'amorçage"
+#string STR_LANGUAGE_SELECT #language en-US "Select Language"
+ #language fr-FR "Choisir la Langue"
+#string STR_LANGUAGE_SELECT_HELP #language en-US "This is the option one adjusts to change the language for the current system"
+ #language fr-FR "Ceci est l'option qu'on ajuste pour changer la langue pour le système actuel"
+#string STR_MISSING_STRING #language en-US "Missing String"
+ #language fr-FR "Missing String"
+#string STR_EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_RESET_STRING #language en-US "Reset"
+ #language fr-FR "Reset"
+#string STR_RESET_STRING_HELP #language en-US "Reset the current setting."
+ #language fr-FR "Reset the current setting."
+#string STR_CUSTOMIZE_BANNER_LINE4_LEFT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE4_RIGHT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE5_LEFT #language en-US ""
+ #language fr-FR ""
+#string STR_CUSTOMIZE_BANNER_LINE5_RIGHT #language en-US ""
+ #language fr-FR ""
+#string STR_TEST_KEY_USED #language en-US "WARNING: Test key detected."
+ #language fr-FR "WARNING: Test key detected."
+#string STR_NULL_STRING #language en-US " "
+ #language fr-FR " "
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr
new file mode 100644
index 000000000..aabf47fdf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/FrontPageVfr.Vfr
@@ -0,0 +1,80 @@
+///** @file
+//
+// Front page formset.
+//
+// Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#define FORMSET_GUID { 0x9e0c30bc, 0x3f06, 0x4ba6, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe }
+
+#define FRONT_PAGE_FORM_ID 0x1000
+
+#define LABEL_FRANTPAGE_INFORMATION 0x1000
+#define LABEL_END 0xffff
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_FRONT_PAGE_TITLE),
+ help = STRING_TOKEN(STR_EMPTY_STRING ),
+ classguid = 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_CUSTOMIZE_BANNER_LINE4_LEFT),
+ line 4,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE4_RIGHT),
+ line 4,
+ align right;
+
+ banner
+ title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE5_LEFT),
+ line 5,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_CUSTOMIZE_BANNER_LINE5_RIGHT),
+ line 5,
+ align right;
+
+ label LABEL_FRANTPAGE_INFORMATION;
+ //
+ // This is where we will dynamically add a Action type op-code to show
+ // the platform information.
+ //
+ label LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/String.c b/roms/edk2/MdeModulePkg/Application/UiApp/String.c
new file mode 100644
index 000000000..a4d0c3210
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/String.c
@@ -0,0 +1,316 @@
+/** @file
+ String support
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ui.h"
+#include "FrontPage.h"
+
+EFI_HII_HANDLE gStringPackHandle;
+
+EFI_GUID mUiStringPackGuid = {
+ 0x136a3048, 0x752a, 0x4bf6, { 0xa7, 0x57, 0x9, 0x36, 0x11, 0x95, 0x38, 0xed }
+};
+
+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
+ }
+ }
+ }
+};
+
+/**
+ Initialize HII global accessor for string support.
+
+**/
+VOID
+InitializeStringSupport (
+ VOID
+ )
+{
+ gStringPackHandle = HiiAddPackages (
+ &mUiStringPackGuid,
+ gImageHandle,
+ UiAppStrings,
+ NULL
+ );
+ ASSERT (gStringPackHandle != NULL);
+}
+
+/**
+ Remove the string package.
+
+**/
+VOID
+UninitializeStringSupport (
+ VOID
+ )
+{
+ HiiRemovePackages (gStringPackHandle);
+}
+
+/**
+ 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);
+}
+
+/**
+ Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver.
+
+**/
+EFI_HII_HANDLE
+ExportFonts (
+ VOID
+ )
+{
+ return HiiAddPackages (
+ &mFontPackageGuid,
+ gImageHandle,
+ &mFontBin,
+ NULL
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/String.h b/roms/edk2/MdeModulePkg/Application/UiApp/String.h
new file mode 100644
index 000000000..3dc4c3316
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/String.h
@@ -0,0 +1,71 @@
+/** @file
+ String support
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+extern EFI_HII_HANDLE gStringPackHandle;
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+
+extern UINT8 BdsDxeStrings[];
+
+//
+// String Definition Guid for BDS Platform
+//
+#define EFI_BDS_PLATFORM_GUID \
+ { \
+ 0x7777E939, 0xD57E, 0x4DCB, 0xA0, 0x8E, 0x64, 0xD7, 0x98, 0x57, 0x1E, 0x0F \
+ }
+
+/**
+ 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
+ );
+
+/**
+ Remove the string package.
+
+**/
+VOID
+UninitializeStringSupport (
+ VOID
+ );
+
+/**
+ Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver.
+
+**/
+EFI_HII_HANDLE
+ExportFonts (
+ VOID
+ );
+
+#endif // _STRING_H_
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/Ui.h b/roms/edk2/MdeModulePkg/Application/UiApp/Ui.h
new file mode 100644
index 000000000..56e54033b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/Ui.h
@@ -0,0 +1,97 @@
+/** @file
+ FrontPage routines to handle the callbacks and browser calls
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _BDS_MODULE_H_
+#define _BDS_MODULE_H_
+
+#include <IndustryStandard/SmBios.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Protocol/Smbios.h>
+#include <Protocol/HiiConfigAccess.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/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiBootManagerLib.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()
+
+
+//
+//The interface functions related to the Setup Browser Reset Reminder feature
+//
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.inf b/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.inf
new file mode 100644
index 000000000..3b9e04885
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.inf
@@ -0,0 +1,82 @@
+## @file
+# UiApp module is driver for BDS phase.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UiApp
+ MODULE_UNI_FILE = UiApp.uni
+ FILE_GUID = 462CAA21-7614-4503-836E-8AB6F4662331
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUserInterface
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FrontPage.h
+ String.h
+ Ui.h
+ FrontPageVfr.Vfr
+ FrontPageStrings.uni
+ FrontPage.c
+ String.c
+ FrontPageCustomizedUi.c
+ FrontPageCustomizedUiSupport.c
+ FrontPageCustomizedUi.h
+ FrontPageCustomizedUiSupport.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiApplicationEntryPoint
+ PcdLib
+ UefiHiiServicesLib
+ UefiBootManagerLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode)
+ gEfiIfrFrontPageGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiSmbiosProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## CONSUMES ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## CONSUMES ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UiAppExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.uni b/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.uni
new file mode 100644
index 000000000..89448ef2b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/UiApp.uni
@@ -0,0 +1,17 @@
+// /** @file
+// UiApp module is driver for BDS phase.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"UiApp module is driver for BDS phase."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"UiApp module is driver for BDS phase."
+
diff --git a/roms/edk2/MdeModulePkg/Application/UiApp/UiAppExtra.uni b/roms/edk2/MdeModulePkg/Application/UiApp/UiAppExtra.uni
new file mode 100644
index 000000000..2e0972ce4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/UiApp/UiAppExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// UiApp Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME #language en-US "UiApp module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.c b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.c
new file mode 100644
index 000000000..a7df365b5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.c
@@ -0,0 +1,273 @@
+/** @file
+ If the Variable services have PcdVariableCollectStatistics set to TRUE then
+ this utility will print out the statistics information. You can use console
+ redirection to capture the data.
+
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/SmmVariableCommon.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/SmmVariable.h>
+
+EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 = NULL;
+
+/**
+ This function get the variable statistics data from SMM variable driver.
+
+ @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will
+ be passed into an SMM environment. In output, a pointer
+ to a collection of data that comes from an SMM environment.
+ @param[in, out] SmmCommunicateSize The size of the SmmCommunicateHeader.
+
+ @retval EFI_SUCCESS Get the statistics data information.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableStatisticsData (
+ IN OUT EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader,
+ IN OUT UINTN *SmmCommunicateSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0];
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS;
+
+ Status = mMmCommunication2->Communicate (mMmCommunication2,
+ SmmCommunicateHeader,
+ SmmCommunicateHeader,
+ SmmCommunicateSize);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ return Status;
+}
+
+/**
+
+ This function get and print the variable statistics data from SMM variable driver.
+
+ @retval EFI_SUCCESS Print the statistics information successfully.
+ @retval EFI_NOT_FOUND Not found the statistics information.
+
+**/
+EFI_STATUS
+PrintInfoFromSmm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ EFI_MM_COMMUNICATE_HEADER *CommBuffer;
+ UINTN RealCommSize;
+ UINTN CommSize;
+ SMM_VARIABLE_COMMUNICATE_HEADER *FunctionHeader;
+ EFI_SMM_VARIABLE_PROTOCOL *Smmvariable;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ UINTN Size;
+ UINTN MaxSize;
+
+ Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **) &mMmCommunication2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CommBuffer = NULL;
+ RealCommSize = 0;
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ MaxSize = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
+ if (Size > (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (VARIABLE_INFO_ENTRY))) {
+ if (Size > MaxSize) {
+ MaxSize = Size;
+ RealCommSize = MaxSize;
+ CommBuffer = (EFI_MM_COMMUNICATE_HEADER *) (UINTN) Entry->PhysicalStart;
+ }
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ ASSERT (CommBuffer != NULL);
+ ZeroMem (CommBuffer, RealCommSize);
+
+ Print (L"SMM Driver Non-Volatile Variables:\n");
+ do {
+ CommSize = RealCommSize;
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n");
+ return Status;
+ }
+
+ if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {
+ break;
+ }
+
+ FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;
+ VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;
+
+ if (!VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ (CHAR16 *)(VariableInfo + 1)
+ );
+ }
+ } while (TRUE);
+
+ Print (L"SMM Driver Volatile Variables:\n");
+ ZeroMem (CommBuffer, RealCommSize);
+ do {
+ CommSize = RealCommSize;
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n");
+ return Status;
+ }
+
+ if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {
+ break;
+ }
+
+ FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;
+ VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;
+
+ if (VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ (CHAR16 *)(VariableInfo + 1)
+ );
+ }
+ } while (TRUE);
+
+ return Status;
+}
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the image goes into a library that calls 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
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS RuntimeDxeStatus;
+ EFI_STATUS SmmStatus;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ VARIABLE_INFO_ENTRY *Entry;
+
+ RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiVariableGuid, (VOID **) &Entry);
+ if (EFI_ERROR (RuntimeDxeStatus) || (Entry == NULL)) {
+ RuntimeDxeStatus = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **) &Entry);
+ }
+
+ if (!EFI_ERROR (RuntimeDxeStatus) && (Entry != NULL)) {
+ Print (L"Runtime DXE Driver Non-Volatile EFI Variables:\n");
+ VariableInfo = Entry;
+ do {
+ if (!VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ VariableInfo->Name
+ );
+ }
+
+ VariableInfo = VariableInfo->Next;
+ } while (VariableInfo != NULL);
+
+ Print (L"Runtime DXE Driver Volatile EFI Variables:\n");
+ VariableInfo = Entry;
+ do {
+ if (VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ VariableInfo->Name
+ );
+ }
+ VariableInfo = VariableInfo->Next;
+ } while (VariableInfo != NULL);
+ }
+
+ SmmStatus = PrintInfoFromSmm ();
+
+ if (EFI_ERROR (RuntimeDxeStatus) && EFI_ERROR (SmmStatus)) {
+ Print (L"Warning: Variable Dxe/Smm driver doesn't enable the feature of statistical information!\n");
+ Print (L"If you want to see this info, please:\n");
+ Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n");
+ Print (L" 2. Rebuild Variable Dxe/Smm driver\n");
+ Print (L" 3. Run \"VariableInfo\" cmd again\n");
+
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.inf b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.inf
new file mode 100644
index 000000000..f7c533b54
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.inf
@@ -0,0 +1,56 @@
+## @file
+# A shell application that displays statistical information about variable usage.
+#
+# This application can display statistical information about variable usage for SMM variable
+# driver and non-SMM variable driver.
+# Note that if Variable Dxe/Smm driver doesn't enable the feature by setting PcdVariableCollectStatistics
+# as TRUE, the application will not display variable statistical information.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableInfo
+ MODULE_UNI_FILE = VariableInfo.uni
+ FILE_GUID = 202A2922-8C27-4943-9855-26180BF9F113
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ VariableInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiMmCommunication2ProtocolGuid ## SOMETIMES_CONSUMES
+
+ ## UNDEFINED # Used to do smm communication
+ ## SOMETIMES_CONSUMES
+ gEfiSmmVariableProtocolGuid
+
+[Guids]
+ gEfiAuthenticatedVariableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiVariableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableInfoExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.uni b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.uni
new file mode 100644
index 000000000..efd614d91
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfo.uni
@@ -0,0 +1,19 @@
+// /** @file
+// A shell application that displays statistical information about variable usage.
+//
+// This application can display statistical information about variable usage for SMM variable
+// driver and non-SMM variable driver.
+// Note that if Variable Dxe/Smm driver doesn't enable the feature by setting PcdVariableCollectStatistics
+// as TRUE, the application will not display variable statistical information.
+//
+// Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that displays statistical information about variable usage"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application can display statistical information about variable usage for SMM variable driver and non-SMM variable driver. Note that if Variable DXE/SMM driver doesn't enable the feature by setting PcdVariableCollectStatistics as TRUE, the application will not display variable statistical information."
+
diff --git a/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni
new file mode 100644
index 000000000..529e781a5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Application/VariableInfo/VariableInfoExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableInfo Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Variable Information Application"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
new file mode 100644
index 000000000..7636ad27c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
@@ -0,0 +1,2139 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+#define ATA_CMD_TRUST_NON_DATA 0x5B
+#define ATA_CMD_TRUST_RECEIVE 0x5C
+#define ATA_CMD_TRUST_SEND 0x5E
+
+//
+// Look up table (IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL
+//
+EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[2] = {
+ EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,
+ EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
+};
+
+//
+// Look up table (Lba48Bit, IsIsWrite) for ATA_CMD
+//
+UINT8 mAtaCommands[2][2] = {
+ {
+ ATA_CMD_READ_SECTORS, // 28-bit LBA; PIO read
+ ATA_CMD_WRITE_SECTORS // 28-bit LBA; PIO write
+ },
+ {
+ ATA_CMD_READ_SECTORS_EXT, // 48-bit LBA; PIO read
+ ATA_CMD_WRITE_SECTORS_EXT // 48-bit LBA; PIO write
+ }
+};
+
+//
+// Look up table (IsTrustSend) for ATA_CMD
+//
+UINT8 mAtaTrustCommands[2] = {
+ ATA_CMD_TRUST_RECEIVE, // PIO read
+ ATA_CMD_TRUST_SEND // PIO write
+};
+
+//
+// Look up table (Lba48Bit) for maximum transfer block number
+//
+#define MAX_28BIT_TRANSFER_BLOCK_NUM 0x100
+//
+// Due to limited resource for VTd PEI DMA buffer on platforms, the driver
+// limits the maximum transfer block number for 48-bit addressing.
+// Here, setting to 0x800 means that for device with 512-byte block size, the
+// maximum buffer for DMA mapping will be 1M bytes in size.
+//
+#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x800
+
+UINT32 mMaxTransferBlockNumber[2] = {
+ MAX_28BIT_TRANSFER_BLOCK_NUM,
+ MAX_48BIT_TRANSFER_BLOCK_NUM
+};
+
+//
+// The maximum total sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+
+/**
+ Read AHCI Operation register.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Offset The operation register offset.
+
+ @return The register content read.
+
+**/
+UINT32
+AhciReadReg (
+ IN UINTN AhciBar,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ Data = 0;
+ Data = MmioRead32 (AhciBar + Offset);
+
+ return Data;
+}
+
+/**
+ Write AHCI Operation register.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Offset The operation register offset.
+ @param[in] Data The Data used to write down.
+
+**/
+VOID
+AhciWriteReg (
+ IN UINTN AhciBar,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ MmioWrite32 (AhciBar + Offset, Data);
+}
+
+/**
+ Do AND operation with the value of AHCI Operation register.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Offset The operation register offset.
+ @param[in] AndData The data used to do AND operation.
+
+**/
+VOID
+AhciAndReg (
+ IN UINTN AhciBar,
+ IN UINT32 Offset,
+ IN UINT32 AndData
+ )
+{
+ UINT32 Data;
+
+ Data = AhciReadReg (AhciBar, Offset);
+ Data &= AndData;
+
+ AhciWriteReg (AhciBar, Offset, Data);
+}
+
+/**
+ Do OR operation with the Value of AHCI Operation register.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Offset The operation register offset.
+ @param[in] OrData The Data used to do OR operation.
+
+**/
+VOID
+AhciOrReg (
+ IN UINTN AhciBar,
+ IN UINT32 Offset,
+ IN UINT32 OrData
+ )
+{
+ UINT32 Data;
+
+ Data = AhciReadReg (AhciBar, Offset);
+ Data |= OrData;
+
+ AhciWriteReg (AhciBar, Offset, Data);
+}
+
+/**
+ Wait for memory set to the test Value.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Offset The memory offset to test.
+ @param[in] MaskValue The mask Value of memory.
+ @param[in] TestValue The test Value of memory.
+ @param[in] Timeout The timeout, in 100ns units, for wait memory set.
+
+ @retval EFI_DEVICE_ERROR The memory is not set.
+ @retval EFI_TIMEOUT The memory setting is time out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMmioSet (
+ IN UINTN AhciBar,
+ IN UINT32 Offset,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT32 Delay;
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+ do {
+ Value = AhciReadReg (AhciBar, Offset) & MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check the memory status to the test value.
+
+ @param[in] Address The memory address to test.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+
+ @retval EFI_NOT_READY The memory is not set.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+AhciCheckMemSet (
+ IN UINTN Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue
+ )
+{
+ UINT32 Value;
+
+ Value = *(volatile UINT32 *) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Wait for the value of the specified system memory set to the test value.
+
+ @param[in] Address The system memory address to test.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The timeout, in 100ns units, for wait memory set.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+
+**/
+EFI_STATUS
+AhciWaitMemSet (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+
+ do {
+ //
+ // Access system memory to see if the value is the tested one.
+ //
+ // The system memory pointed by Address will be updated by the
+ // SATA Host Controller, "volatile" is introduced to prevent
+ // compiler from optimizing the access to the memory address
+ // to only read once.
+ //
+ Value = *(volatile UINT32 *) (UINTN) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+
+ Clear the port interrupt and error status. It will also clear HBA interrupt
+ status.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Port The number of port.
+
+**/
+VOID
+AhciClearPortStatus (
+ IN UINTN AhciBar,
+ IN UINT8 Port
+ )
+{
+ UINT32 Offset;
+
+ //
+ // Clear any error status
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SERR;
+ AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+
+ //
+ // Clear any port interrupt status
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_IS;
+ AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+
+ //
+ // Clear any HBA interrupt status
+ //
+ AhciWriteReg (AhciBar, AHCI_IS_OFFSET, AhciReadReg (AhciBar, AHCI_IS_OFFSET));
+}
+
+/**
+ Enable the FIS running for giving port.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Port The number of port.
+ @param[in] Timeout The timeout, in 100ns units, to enabling FIS.
+
+ @retval EFI_DEVICE_ERROR The FIS enable setting fails.
+ @retval EFI_TIMEOUT The FIS enable setting is time out.
+ @retval EFI_SUCCESS The FIS enable successfully.
+
+**/
+EFI_STATUS
+AhciEnableFisReceive (
+ IN UINTN AhciBar,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_FRE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable the FIS running for giving port.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Port The number of port.
+ @param[in] Timeout The timeout value of disabling FIS, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The FIS disable setting fails.
+ @retval EFI_TIMEOUT The FIS disable setting is time out.
+ @retval EFI_UNSUPPORTED The port is in running state.
+ @retval EFI_SUCCESS The FIS disable successfully.
+
+**/
+EFI_STATUS
+AhciDisableFisReceive (
+ IN UINTN AhciBar,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ Data = AhciReadReg (AhciBar, Offset);
+
+ //
+ // Before disabling Fis receive, the DMA engine of the port should NOT be in
+ // running status.
+ //
+ if ((Data & (AHCI_PORT_CMD_ST | AHCI_PORT_CMD_CR)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check if the Fis receive DMA engine for the port is running.
+ //
+ if ((Data & AHCI_PORT_CMD_FR) != AHCI_PORT_CMD_FR) {
+ return EFI_SUCCESS;
+ }
+
+ AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_FRE));
+
+ return AhciWaitMmioSet (
+ AhciBar,
+ Offset,
+ AHCI_PORT_CMD_FR,
+ 0,
+ Timeout
+ );
+}
+
+/**
+ Build the command list, command table and prepare the fis receiver.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The number of port multiplier.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] CommandFis The control fis will be used for the transfer.
+ @param[in] CommandList The command list will be used for the transfer.
+ @param[in] CommandSlotNumber The command slot will be used for the transfer.
+ @param[in,out] DataPhysicalAddr The pointer to the data buffer pci bus master
+ address.
+ @param[in] DataLength The data count to be transferred.
+
+**/
+VOID
+AhciBuildCommand (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN EFI_AHCI_COMMAND_FIS *CommandFis,
+ IN EFI_AHCI_COMMAND_LIST *CommandList,
+ IN UINT8 CommandSlotNumber,
+ IN OUT VOID *DataPhysicalAddr,
+ IN UINT32 DataLength
+ )
+{
+ EFI_AHCI_REGISTERS *AhciRegisters;
+ UINTN AhciBar;
+ UINT64 BaseAddr;
+ UINT32 PrdtNumber;
+ UINT32 PrdtIndex;
+ UINTN RemainedData;
+ UINTN MemAddr;
+ DATA_64 Data64;
+ UINT32 Offset;
+
+ AhciRegisters = &Private->AhciRegisters;
+ AhciBar = Private->MmioBase;
+
+ //
+ // Filling the PRDT
+ //
+ PrdtNumber = (UINT32)DivU64x32 (
+ (UINT64)DataLength + AHCI_MAX_DATA_PER_PRDT - 1,
+ AHCI_MAX_DATA_PER_PRDT
+ );
+
+ //
+ // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
+ // It also limits that the maximum amount of the PRDT entry in the command table
+ // is 65535.
+ // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
+ // PRDT entries.
+ //
+ ASSERT (PrdtNumber <= AHCI_MAX_PRDT_NUMBER);
+ if (PrdtNumber > AHCI_MAX_PRDT_NUMBER) {
+ return;
+ }
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+
+ BaseAddr = Data64.Uint64;
+
+ ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
+
+ ZeroMem (AhciRegisters->AhciCmdTable, sizeof (EFI_AHCI_COMMAND_TABLE));
+
+ CommandFis->AhciCFisPmNum = PortMultiplier;
+
+ CopyMem (&AhciRegisters->AhciCmdTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_DLAE | AHCI_PORT_CMD_ATAPI));
+
+ RemainedData = (UINTN) DataLength;
+ MemAddr = (UINTN) DataPhysicalAddr;
+ CommandList->AhciCmdPrdtl = PrdtNumber;
+
+ for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
+ if (RemainedData < AHCI_MAX_DATA_PER_PRDT) {
+ AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
+ } else {
+ AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbc = AHCI_MAX_DATA_PER_PRDT - 1;
+ }
+
+ Data64.Uint64 = (UINT64)MemAddr;
+ AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;
+ RemainedData -= AHCI_MAX_DATA_PER_PRDT;
+ MemAddr += AHCI_MAX_DATA_PER_PRDT;
+ }
+
+ //
+ // Set the last PRDT to Interrupt On Complete
+ //
+ if (PrdtNumber > 0) {
+ AhciRegisters->AhciCmdTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;
+ }
+
+ CopyMem (
+ (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
+ CommandList,
+ sizeof (EFI_AHCI_COMMAND_LIST)
+ );
+
+ Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCmdTable;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;
+}
+
+/**
+ Build a command FIS.
+
+ @param[in,out] CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data
+ structure.
+ @param[in] AtaCommandBlock A pointer to the EFI_ATA_COMMAND_BLOCK data
+ structure.
+
+**/
+VOID
+AhciBuildCommandFis (
+ IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
+ )
+{
+ ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ CmdFis->AhciCFisType = AHCI_FIS_REGISTER_H2D;
+ //
+ // Indicator it's a command
+ //
+ CmdFis->AhciCFisCmdInd = 0x1;
+ CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
+
+ CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
+ CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
+
+ CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
+ CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;
+
+ CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
+ CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
+
+ CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
+ CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
+
+ CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
+ CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
+
+ CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
+}
+
+/**
+ Stop command running for giving port
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Port The number of port.
+ @param[in] Timeout The timeout value, in 100ns units, to stop.
+
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command stop successfully.
+
+**/
+EFI_STATUS
+AhciStopCommand (
+ IN UINTN AhciBar,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ Data = AhciReadReg (AhciBar, Offset);
+
+ if ((Data & (AHCI_PORT_CMD_ST | AHCI_PORT_CMD_CR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Data & AHCI_PORT_CMD_ST) != 0) {
+ AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_ST));
+ }
+
+ return AhciWaitMmioSet (
+ AhciBar,
+ Offset,
+ AHCI_PORT_CMD_CR,
+ 0,
+ Timeout
+ );
+}
+
+/**
+ Start command for give slot on specific port.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Port The number of port.
+ @param[in] CommandSlot The number of Command Slot.
+ @param[in] Timeout The timeout value, in 100ns units, to start.
+
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command start successfully.
+
+**/
+EFI_STATUS
+AhciStartCommand (
+ IN UINTN AhciBar,
+ IN UINT8 Port,
+ IN UINT8 CommandSlot,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 CmdSlotBit;
+ EFI_STATUS Status;
+ UINT32 PortStatus;
+ UINT32 StartCmd;
+ UINT32 PortTfd;
+ UINT32 Offset;
+ UINT32 Capability;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+ CmdSlotBit = (UINT32) (1 << CommandSlot);
+
+ AhciClearPortStatus (
+ AhciBar,
+ Port
+ );
+
+ Status = AhciEnableFisReceive (
+ AhciBar,
+ Port,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ PortStatus = AhciReadReg (AhciBar, Offset);
+
+ StartCmd = 0;
+ if ((PortStatus & AHCI_PORT_CMD_ALPE) != 0) {
+ StartCmd = AhciReadReg (AhciBar, Offset);
+ StartCmd &= ~AHCI_PORT_CMD_ICC_MASK;
+ StartCmd |= AHCI_PORT_CMD_ACTIVE;
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (AhciBar, Offset);
+
+ if ((PortTfd & (AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ)) != 0) {
+ if ((Capability & BIT24) != 0) {
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_CLO);
+
+ AhciWaitMmioSet (
+ AhciBar,
+ Offset,
+ AHCI_PORT_CMD_CLO,
+ 0,
+ Timeout
+ );
+ }
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_ST | StartCmd);
+
+ //
+ // Setting the command
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CI;
+ AhciAndReg (AhciBar, Offset, 0);
+ AhciOrReg (AhciBar, Offset, CmdSlotBit);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start a PIO Data transfer on specific port.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The number of port multiplier.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in,out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of PIO data transfer, uses
+ 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+ @retval EFI_SUCCESS The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciPioTransfer (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_OPERATION MapOp;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *MapData;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+ UINTN AhciBar;
+ BOOLEAN InfiniteWait;
+ UINT32 Offset;
+ UINT32 OldRfisLo;
+ UINT32 OldRfisHi;
+ UINT32 OldCmdListLo;
+ UINT32 OldCmdListHi;
+ DATA_64 Data64;
+ UINT32 FisBaseAddr;
+ UINT32 Delay;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+ UINT32 PortTfd;
+ UINT32 PrdCount;
+ BOOLEAN PioFisReceived;
+ BOOLEAN D2hFisReceived;
+
+ //
+ // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
+ // PRDT entries.
+ //
+ if (DataCount / (UINT32)AHCI_MAX_PRDT_NUMBER > AHCI_MAX_DATA_PER_PRDT) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Driver only support a maximum of 0x%x PRDT entries, "
+ "current number of data byte 0x%x is too large, maximum allowed is 0x%x.\n",
+ __FUNCTION__, AHCI_MAX_PRDT_NUMBER, DataCount,
+ AHCI_MAX_PRDT_NUMBER * AHCI_MAX_DATA_PER_PRDT
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ MapOp = Read ? EdkiiIoMmuOperationBusMasterWrite :
+ EdkiiIoMmuOperationBusMasterRead;
+ MapLength = DataCount;
+ Status = IoMmuMap (
+ MapOp,
+ MemoryAddr,
+ &MapLength,
+ &PhyAddr,
+ &MapData
+ );
+ if (EFI_ERROR (Status) || (MapLength != DataCount)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map data buffer.\n", __FUNCTION__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AhciRegisters = &Private->AhciRegisters;
+ AhciBar = Private->MmioBase;
+ InfiniteWait = (Timeout == 0) ? TRUE : FALSE;
+
+ //
+ // Fill FIS base address register
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+ OldRfisLo = AhciReadReg (AhciBar, Offset);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+ OldRfisHi = AhciReadReg (AhciBar, Offset);
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+ //
+ // Single task environment, we only use one command table for all port
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+ OldCmdListLo = AhciReadReg (AhciBar, Offset);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+ OldCmdListHi = AhciReadReg (AhciBar, Offset);
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdList);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+ CmdList.AhciCmdW = Read ? 0 : 1;
+
+ AhciBuildCommand (
+ Private,
+ Port,
+ PortMultiplier,
+ FisIndex,
+ &CFis,
+ &CmdList,
+ 0,
+ (VOID *)(UINTN)PhyAddr,
+ DataCount
+ );
+
+ Status = AhciStartCommand (
+ AhciBar,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Checking the status and wait the driver sending Data
+ //
+ FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+ if (Read) {
+ //
+ // Wait device sends the PIO setup fis before data transfer
+ //
+ Status = EFI_TIMEOUT;
+ Delay = (UINT32) DivU64x32 (Timeout, 1000) + 1;
+ do {
+ PioFisReceived = FALSE;
+ D2hFisReceived = FALSE;
+ Offset = FisBaseAddr + AHCI_PIO_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, AHCI_FIS_TYPE_MASK, AHCI_FIS_PIO_SETUP);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a: PioFisReceived.\n", __FUNCTION__));
+ PioFisReceived = TRUE;
+ }
+ //
+ // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
+ // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from
+ // device after the transaction is finished successfully.
+ // To get better device compatibilities, we further check if the PxTFD's
+ // ERR bit is set. By this way, we can know if there is a real error happened.
+ //
+ Offset = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, AHCI_FIS_TYPE_MASK, AHCI_FIS_REGISTER_D2H);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a: D2hFisReceived.\n", __FUNCTION__));
+ D2hFisReceived = TRUE;
+ }
+
+ if (PioFisReceived || D2hFisReceived) {
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+ //
+ // PxTFD will be updated if there is a D2H or SetupFIS received.
+ //
+ if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
+ if (PrdCount == DataCount) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ if (Delay == 0) {
+ Status = EFI_TIMEOUT;
+ }
+ } while (InfiniteWait || (Delay > 0));
+ } else {
+ //
+ // Wait for D2H Fis is received
+ //
+ Offset = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ AHCI_FIS_TYPE_MASK,
+ AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: AhciWaitMemSet (%r)\n", __FUNCTION__, Status));
+ goto Exit;
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+ if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+Exit:
+ AhciStopCommand (
+ AhciBar,
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ AhciBar,
+ Port,
+ Timeout
+ );
+
+ if (MapData != NULL) {
+ IoMmuUnmap (MapData);
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+ AhciWriteReg (AhciBar, Offset, OldRfisLo);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+ AhciWriteReg (AhciBar, Offset, OldRfisHi);
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+ AhciWriteReg (AhciBar, Offset, OldCmdListLo);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+ AhciWriteReg (AhciBar, Offset, OldCmdListHi);
+
+ return Status;
+}
+
+/**
+ Start a non data transfer on specific port.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The number of port multiplier.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in] Timeout The timeout value of non data transfer, uses
+ 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciNonDataTransfer (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINTN AhciBar;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+ UINTN FisBaseAddr;
+ UINTN Offset;
+ UINT32 PortTfd;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+
+ AhciBar = Private->MmioBase;
+ AhciRegisters = &Private->AhciRegisters;
+
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+
+ AhciBuildCommand (
+ Private,
+ Port,
+ PortMultiplier,
+ FisIndex,
+ &CFis,
+ &CmdList,
+ 0,
+ NULL,
+ 0
+ );
+
+ Status = AhciStartCommand (
+ AhciBar,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Wait device sends the Response Fis
+ //
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+ Offset = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ AHCI_FIS_TYPE_MASK,
+ AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+ if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ AhciStopCommand (
+ AhciBar,
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ AhciBar,
+ Port,
+ Timeout
+ );
+
+ return Status;
+}
+
+/**
+ Do AHCI HBA reset.
+
+ @param[in] AhciBar AHCI bar address.
+ @param[in] Timeout The timeout, in 100ns units, to reset.
+
+ @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
+ @retval EFI_TIMEOUT The reset operation is time out.
+ @retval EFI_SUCCESS AHCI controller is reset successfully.
+
+**/
+EFI_STATUS
+AhciReset (
+ IN UINTN AhciBar,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT32 Value;
+ UINT32 Capability;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
+ //
+ if ((Capability & AHCI_CAP_SAM) == 0) {
+ AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_ENABLE);
+ }
+
+ AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_RESET);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+ do {
+ Value = AhciReadReg(AhciBar, AHCI_GHC_OFFSET);
+ if ((Value & AHCI_GHC_RESET) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Send Identify Drive command to a specific device.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The port multiplier port number.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] Buffer The data buffer to store IDENTIFY PACKET data.
+
+ @retval EFI_SUCCESS The cmd executes successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+
+**/
+EFI_STATUS
+AhciIdentify (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN ATA_IDENTIFY_DATA *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK Acb;
+ EFI_ATA_STATUS_BLOCK Asb;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&Asb, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ Acb.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ Acb.AtaSectorCount = 1;
+
+ Status = AhciPioTransfer (
+ Private,
+ Port,
+ PortMultiplier,
+ FisIndex,
+ TRUE,
+ &Acb,
+ &Asb,
+ Buffer,
+ sizeof (ATA_IDENTIFY_DATA),
+ ATA_TIMEOUT
+ );
+
+ return Status;
+}
+
+
+/**
+ Collect the number of bits set within a port bitmap.
+
+ @param[in] PortBitMap A 32-bit wide bit map of ATA AHCI ports.
+
+ @retval The number of bits set in the bitmap.
+
+**/
+UINT8
+AhciGetNumberOfPortsFromMap (
+ IN UINT32 PortBitMap
+ )
+{
+ UINT8 NumberOfPorts;
+
+ NumberOfPorts = 0;
+
+ while (PortBitMap != 0) {
+ if ((PortBitMap & ((UINT32)BIT0)) != 0) {
+ NumberOfPorts++;
+ }
+ PortBitMap = PortBitMap >> 1;
+ }
+
+ return NumberOfPorts;
+}
+
+/**
+ Get the specified port number from a port bitmap.
+
+ @param[in] PortBitMap A 32-bit wide bit map of ATA AHCI ports.
+ @param[in] PortIndex The specified port index.
+ @param[out] Port The port number of the port specified by PortIndex.
+
+ @retval EFI_SUCCESS The specified port is found and its port number is
+ in Port.
+ @retval EFI_NOT_FOUND Cannot find the specified port within the port bitmap.
+
+**/
+EFI_STATUS
+AhciGetPortFromMap (
+ IN UINT32 PortBitMap,
+ IN UINT8 PortIndex,
+ OUT UINT8 *Port
+ )
+{
+ if (PortIndex == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Port = 0;
+
+ while (PortBitMap != 0) {
+ if ((PortBitMap & ((UINT32)BIT0)) != 0) {
+ PortIndex--;
+
+ //
+ // Found the port specified by PortIndex.
+ //
+ if (PortIndex == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ PortBitMap = PortBitMap >> 1;
+ *Port = *Port + 1;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Allocate transfer-related data struct which is used at AHCI mode.
+
+ @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS Data structures are allocated successfully.
+ @retval Others Data structures are not allocated successfully.
+
+**/
+EFI_STATUS
+AhciCreateTransferDescriptor (
+ IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN AhciBar;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *Base;
+ VOID *Mapping;
+ UINT32 Capability;
+ UINT32 PortImplementBitMap;
+ UINT8 MaxPortNumber;
+ UINT8 MaxCommandSlotNumber;
+ UINTN MaxRFisSize;
+ UINTN MaxCmdListSize;
+ UINTN MaxCmdTableSize;
+
+ AhciBar = Private->MmioBase;
+ AhciRegisters = &Private->AhciRegisters;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Get the number of command slots per port supported by this HBA.
+ //
+ MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
+ ASSERT (MaxCommandSlotNumber > 0);
+ if (MaxCommandSlotNumber == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get the highest bit of implemented ports which decides how many bytes are
+ // allocated for recived FIS.
+ //
+ PortImplementBitMap = AhciReadReg (AhciBar, AHCI_PI_OFFSET);
+ MaxPortNumber = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);
+ if (MaxPortNumber == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get the number of ports that actually needed to be initialized.
+ //
+ MaxPortNumber = MIN (MaxPortNumber, AhciGetNumberOfPortsFromMap (Private->PortBitMap));
+
+ //
+ // Allocate memory for received FIS.
+ //
+ MaxRFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Status = IoMmuAllocateBuffer (
+ EFI_SIZE_TO_PAGES (MaxRFisSize),
+ &Base,
+ &DeviceAddress,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+ AhciRegisters->AhciRFis = Base;
+ AhciRegisters->AhciRFisMap = Mapping;
+ AhciRegisters->MaxRFisSize = MaxRFisSize;
+ ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxRFisSize));
+
+ //
+ // Allocate memory for command list.
+ // Note that the implemenation is a single task model which only use a command
+ // list for each port.
+ //
+ MaxCmdListSize = 1 * sizeof (EFI_AHCI_COMMAND_LIST);
+ Status = IoMmuAllocateBuffer (
+ EFI_SIZE_TO_PAGES (MaxCmdListSize),
+ &Base,
+ &DeviceAddress,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+ AhciRegisters->AhciCmdList = Base;
+ AhciRegisters->AhciCmdListMap = Mapping;
+ AhciRegisters->MaxCmdListSize = MaxCmdListSize;
+ ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxCmdListSize));
+
+ //
+ // Allocate memory for command table
+ // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
+ //
+ MaxCmdTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);
+ Status = IoMmuAllocateBuffer (
+ EFI_SIZE_TO_PAGES (MaxCmdTableSize),
+ &Base,
+ &DeviceAddress,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+ AhciRegisters->AhciCmdTable = Base;
+ AhciRegisters->AhciCmdTableMap = Mapping;
+ AhciRegisters->MaxCmdTableSize = MaxCmdTableSize;
+ ZeroMem (AhciRegisters->AhciCmdTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxCmdTableSize));
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (AhciRegisters->AhciRFisMap != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
+ AhciRegisters->AhciRFis,
+ AhciRegisters->AhciRFisMap
+ );
+ AhciRegisters->AhciRFis = NULL;
+ }
+
+ if (AhciRegisters->AhciCmdListMap != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
+ AhciRegisters->AhciCmdList,
+ AhciRegisters->AhciCmdListMap
+ );
+ AhciRegisters->AhciCmdList = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Gets ATA device Capacity according to ATA 6.
+
+ This function returns the capacity of the ATA device if it follows
+ ATA 6 to support 48 bit addressing.
+
+ @param[in] IdentifyData A pointer to ATA_IDENTIFY_DATA structure.
+
+ @return The capacity of the ATA device or 0 if the device does not support
+ 48-bit addressing defined in ATA 6.
+
+**/
+EFI_LBA
+GetAtapi6Capacity (
+ IN ATA_IDENTIFY_DATA *IdentifyData
+ )
+{
+ EFI_LBA Capacity;
+ EFI_LBA TmpLba;
+ UINTN Index;
+
+ if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {
+ //
+ // The device doesn't support 48 bit addressing
+ //
+ return 0;
+ }
+
+ //
+ // 48 bit address feature set is supported, get maximum capacity
+ //
+ Capacity = 0;
+ for (Index = 0; Index < 4; Index++) {
+ //
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+ //
+ TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);
+ }
+
+ return Capacity;
+}
+
+/**
+ Identifies ATA device via the Identify data.
+
+ This function identifies the ATA device and initializes the media information.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from peripheral hardware device.
+
+ The Identify Drive command response data from an ATA device is the peripheral
+ hardware input, so this routine will do basic validation for the Identify Drive
+ command response data.
+
+ @param[in,out] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+
+ @retval EFI_SUCCESS The device is successfully identified and media
+ information is correctly initialized.
+ @retval EFI_UNSUPPORTED The device is not a valid ATA device (hard disk).
+
+**/
+EFI_STATUS
+IdentifyAtaDevice (
+ IN OUT PEI_AHCI_ATA_DEVICE_DATA *DeviceData
+ )
+{
+ ATA_IDENTIFY_DATA *IdentifyData;
+ EFI_PEI_BLOCK_IO2_MEDIA *Media;
+ EFI_LBA Capacity;
+ UINT32 MaxSectorCount;
+ UINT16 PhyLogicSectorSupport;
+
+ IdentifyData = DeviceData->IdentifyData;
+ Media = &DeviceData->Media;
+
+ if ((IdentifyData->config & BIT15) != 0) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Not a hard disk device on Port 0x%x PortMultiplierPort 0x%x\n",
+ __FUNCTION__, DeviceData->Port, DeviceData->PortMultiplier
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((
+ DEBUG_INFO, "%a: Identify Device: Port 0x%x PortMultiplierPort 0x%x\n",
+ __FUNCTION__, DeviceData->Port, DeviceData->PortMultiplier
+ ));
+
+ //
+ // Skip checking whether the WORD 88 (supported UltraDMA by drive), since the
+ // driver only support PIO data transfer for now.
+ //
+
+ //
+ // Get the capacity information of the device.
+ //
+ Capacity = GetAtapi6Capacity (IdentifyData);
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+ //
+ // Capacity exceeds 120GB. 48-bit addressing is really needed
+ //
+ DeviceData->Lba48Bit = TRUE;
+ } else {
+ //
+ // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+ //
+ Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) |
+ IdentifyData->user_addressable_sectors_lo;
+ DeviceData->Lba48Bit = FALSE;
+ }
+
+ if (Capacity == 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid Capacity (0) for ATA device.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+ Media->LastBlock = (EFI_PEI_LBA) (Capacity - 1);
+
+ Media->BlockSize = 0x200;
+ //
+ // Check whether Long Physical Sector Feature is supported
+ //
+ PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;
+ DEBUG ((
+ DEBUG_INFO, "%a: PhyLogicSectorSupport = 0x%x\n",
+ __FUNCTION__, PhyLogicSectorSupport
+ ));
+ if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {
+ //
+ // Check logical block size
+ //
+ if ((PhyLogicSectorSupport & BIT12) != 0) {
+ Media->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) |
+ IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
+ }
+ }
+
+ //
+ // Check BlockSize validity
+ //
+ MaxSectorCount = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+ if ((Media->BlockSize == 0) || (Media->BlockSize > MAX_UINT32 / MaxSectorCount)) {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid BlockSize (0x%x).\n", __FUNCTION__, Media->BlockSize));
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((
+ DEBUG_INFO, "%a: BlockSize = 0x%x, LastBlock = 0x%lx\n",
+ __FUNCTION__, Media->BlockSize, Media->LastBlock
+ ));
+
+ if ((IdentifyData->trusted_computing_support & BIT0) != 0) {
+ DEBUG ((DEBUG_INFO, "%a: Found Trust Computing feature support.\n", __FUNCTION__));
+ DeviceData->TrustComputing = TRUE;
+ }
+
+ Media->InterfaceType = MSG_SATA_DP;
+ Media->RemovableMedia = FALSE;
+ Media->MediaPresent = TRUE;
+ Media->ReadOnly = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate device information data structure to contain device information.
+ And insert the data structure to the tail of device list for tracing.
+
+ @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ instance.
+ @param[in] DeviceIndex The device index.
+ @param[in] Port The port number of the ATA device to send
+ the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA
+ device to send the command.
+ If there is no port multiplier, then specify
+ 0xFFFF.
+ @param[in] FisIndex The index of the FIS of the ATA device to
+ send the command.
+ @param[in] IdentifyData The data buffer to store the output of the
+ IDENTIFY command.
+
+ @retval EFI_SUCCESS Successfully insert the ATA device to the
+ tail of device list.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource.
+
+**/
+EFI_STATUS
+CreateNewDevice (
+ IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINTN DeviceIndex,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN ATA_IDENTIFY_DATA *IdentifyData
+ )
+{
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ EFI_STATUS Status;
+
+ DeviceData = AllocateZeroPool (sizeof (PEI_AHCI_ATA_DEVICE_DATA));
+ if (DeviceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (IdentifyData != NULL) {
+ DeviceData->IdentifyData = AllocateCopyPool (sizeof (ATA_IDENTIFY_DATA), IdentifyData);
+ if (DeviceData->IdentifyData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ DeviceData->Signature = AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE;
+ DeviceData->Port = Port;
+ DeviceData->PortMultiplier = PortMultiplier;
+ DeviceData->FisIndex = FisIndex;
+ DeviceData->DeviceIndex = DeviceIndex;
+ DeviceData->Private = Private;
+
+ Status = IdentifyAtaDevice (DeviceData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DeviceData->TrustComputing) {
+ Private->TrustComputingDevices++;
+ DeviceData->TrustComputingDeviceIndex = Private->TrustComputingDevices;
+ }
+ Private->ActiveDevices++;
+ InsertTailList (&Private->DeviceList, &DeviceData->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS The ATA AHCI controller is initialized successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete while initializing
+ the controller.
+ @retval Others A device error occurred while initializing the
+ controller.
+
+**/
+EFI_STATUS
+AhciModeInitialization (
+ IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN AhciBar;
+ UINT32 Capability;
+ UINT32 Value;
+ UINT8 MaxPortNumber;
+ UINT32 PortImplementBitMap;
+ UINT32 PortInitializeBitMap;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+ UINT8 PortIndex;
+ UINT8 Port;
+ DATA_64 Data64;
+ UINT32 Data;
+ UINT32 Offset;
+ UINT32 PhyDetectDelay;
+ UINTN DeviceIndex;
+ ATA_IDENTIFY_DATA IdentifyData;
+
+ AhciBar = Private->MmioBase;
+
+ Status = AhciReset (AhciBar, AHCI_PEI_RESET_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: AHCI HBA reset failed with %r.\n", __FUNCTION__, Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.
+ //
+ Value = AhciReadReg (AhciBar, AHCI_GHC_OFFSET);
+ if ((Value & AHCI_GHC_ENABLE) == 0) {
+ AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_ENABLE);
+ }
+
+ Status = AhciCreateTransferDescriptor (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Transfer-related data allocation failed with %r.\n",
+ __FUNCTION__, Status
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get the number of command slots per port supported by this HBA.
+ //
+ MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
+
+ //
+ // Get the bit map of those ports exposed by this HBA.
+ // It indicates which ports that the HBA supports are available for software
+ // to use.
+ //
+ PortImplementBitMap = AhciReadReg (AhciBar, AHCI_PI_OFFSET);
+
+ //
+ // Get the number of ports that actually needed to be initialized.
+ //
+ MaxPortNumber = MIN (MaxPortNumber, (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1));
+ MaxPortNumber = MIN (MaxPortNumber, AhciGetNumberOfPortsFromMap (Private->PortBitMap));
+
+ PortInitializeBitMap = Private->PortBitMap & PortImplementBitMap;
+ AhciRegisters = &Private->AhciRegisters;
+ DeviceIndex = 0;
+ //
+ // Enumerate ATA ports
+ //
+ for (PortIndex = 1; PortIndex <= MaxPortNumber; PortIndex ++) {
+ Status = AhciGetPortFromMap (PortInitializeBitMap, PortIndex, &Port);
+ if (EFI_ERROR (Status)) {
+ //
+ // No more available port, just break out of the loop.
+ //
+ break;
+ }
+
+ if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
+ //
+ // Initialize FIS Base Address Register and Command List Base Address
+ // Register for use.
+ //
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) +
+ sizeof (EFI_AHCI_RECEIVED_FIS) * (PortIndex - 1);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdList);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+ AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ Data = AhciReadReg (AhciBar, Offset);
+ if ((Data & AHCI_PORT_CMD_CPD) != 0) {
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_POD);
+ }
+
+ if ((Capability & AHCI_CAP_SSS) != 0) {
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_SUD);
+ }
+
+ //
+ // Disable aggressive power management.
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SCTL;
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_SCTL_IPM_INIT);
+ //
+ // Disable the reporting of the corresponding interrupt to system software.
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_IE;
+ AhciAndReg (AhciBar, Offset, 0);
+
+ //
+ // Enable FIS Receive DMA engine for the first D2H FIS.
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_FRE);
+
+ //
+ // Wait no longer than 15 ms to wait the Phy to detect the presence of a device.
+ //
+ PhyDetectDelay = AHCI_BUS_PHY_DETECT_TIMEOUT;
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SSTS;
+ do {
+ Data = AhciReadReg (AhciBar, Offset) & AHCI_PORT_SSTS_DET_MASK;
+ if ((Data == AHCI_PORT_SSTS_DET_PCE) || (Data == AHCI_PORT_SSTS_DET)) {
+ break;
+ }
+
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ //
+ // No device detected at this port.
+ // Clear PxCMD.SUD for those ports at which there are no device present.
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+ AhciAndReg (AhciBar, Offset, (UINT32) ~(AHCI_PORT_CMD_SUD));
+ DEBUG ((DEBUG_ERROR, "%a: No device detected at Port %d.\n", __FUNCTION__, Port));
+ continue;
+ }
+
+ //
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+ //
+ PhyDetectDelay = 16 * 1000;
+ do {
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SERR;
+ if (AhciReadReg(AhciBar, Offset) != 0) {
+ AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+ }
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+
+ Data = AhciReadReg (AhciBar, Offset) & AHCI_PORT_TFD_MASK;
+ if (Data == 0) {
+ break;
+ }
+
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Port %d device presence detected but phy not ready (TFD=0x%x).\n",
+ __FUNCTION__, Port, Data
+ ));
+ continue;
+ }
+
+ //
+ // When the first D2H register FIS is received, the content of PxSIG register is updated.
+ //
+ Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SIG;
+ Status = AhciWaitMmioSet (
+ AhciBar,
+ Offset,
+ 0x0000FFFF,
+ 0x00000101,
+ 160000000
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Error occurred when waiting for the first D2H register FIS - %r\n",
+ __FUNCTION__, Status
+ ));
+ continue;
+ }
+
+ Data = AhciReadReg (AhciBar, Offset);
+ if ((Data & AHCI_ATAPI_SIG_MASK) == AHCI_ATA_DEVICE_SIG) {
+ Status = AhciIdentify (Private, Port, 0, PortIndex - 1, &IdentifyData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: AhciIdentify() failed with %r\n", __FUNCTION__, Status));
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "%a: ATA hard disk found on Port %d.\n", __FUNCTION__, Port));
+ } else {
+ continue;
+ }
+
+ //
+ // Found an ATA hard disk device, add it into the device list.
+ //
+ DeviceIndex++;
+ CreateNewDevice (
+ Private,
+ DeviceIndex,
+ Port,
+ 0xFFFF,
+ PortIndex - 1,
+ &IdentifyData
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer data from ATA device.
+
+ This function performs one ATA pass through transaction to transfer data from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINT32 TransferLength,
+ IN BOOLEAN IsWrite
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;
+ EFI_ATA_COMMAND_BLOCK Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
+
+ Private = DeviceData->Private;
+ AtaPassThru = &Private->AtaPassThruPpi;
+
+ //
+ // Ensure Lba48Bit and IsWrite are valid boolean values
+ //
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
+ ASSERT ((UINTN) IsWrite < 2);
+ if (((UINTN) DeviceData->Lba48Bit >= 2) ||
+ ((UINTN) IsWrite >= 2)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Prepare for ATA command block.
+ //
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ Acb.AtaCommand = mAtaCommands[DeviceData->Lba48Bit][IsWrite];
+ Acb.AtaSectorNumber = (UINT8) StartLba;
+ Acb.AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
+ Acb.AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |
+ (DeviceData->PortMultiplier == 0xFFFF ?
+ 0 : (DeviceData->PortMultiplier << 4)));
+ Acb.AtaSectorCount = (UINT8) TransferLength;
+ if (DeviceData->Lba48Bit) {
+ Acb.AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
+ Acb.AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);
+ Acb.AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);
+ Acb.AtaSectorCountExp = (UINT8) (TransferLength >> 8);
+ } else {
+ Acb.AtaDeviceHead = (UINT8) (Acb.AtaDeviceHead | RShiftU64 (StartLba, 24));
+ }
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ if (IsWrite) {
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = TransferLength;
+ } else {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = TransferLength;
+ }
+ Packet.Asb = NULL;
+ Packet.Acb = &Acb;
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsWrite];
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
+ //
+ // |------------------------|-----------------|
+ // | ATA PIO Transfer Mode | Transfer Rate |
+ // |------------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec |
+ // |------------------------|-----------------|
+ //
+ // As AtaBus is used to manage ATA devices, we have to use the lowest transfer
+ // rate to calculate the possible maximum timeout value for each read/write
+ // operation. The timout value is rounded up to nearest integar and here an
+ // additional 30s is added to follow ATA spec in which it mentioned that the
+ // device may take up to 30s to respond commands in the Standby/Idle mode.
+ //
+ // Calculate the maximum timeout value for PIO read/write operation.
+ //
+ Packet.Timeout = TIMER_PERIOD_SECONDS (
+ DivU64x32 (
+ MultU64x32 (TransferLength, DeviceData->Media.BlockSize),
+ 3300000
+ ) + 31
+ );
+
+ return AtaPassThru->PassThru (
+ AtaPassThru,
+ DeviceData->Port,
+ DeviceData->PortMultiplier,
+ &Packet
+ );
+}
+
+/**
+ Trust transfer data from/to ATA device.
+
+ This function performs one ATA pass through transaction to do a trust transfer
+ from/to ATA device. It chooses the appropriate ATA command and protocol to invoke
+ PassThru interface of ATA pass through.
+
+ @param[in] DeviceData Pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter
+ of the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to
+ be sent.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsTrustSend Indicates whether it is a trust send operation
+ or not.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[out] TransferLengthOut
+ A pointer to a buffer to store the size in bytes
+ of the data written to the buffer. Ignore it when
+ IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;
+ EFI_ATA_COMMAND_BLOCK Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ VOID *NewBuffer;
+
+ Private = DeviceData->Private;
+ AtaPassThru = &Private->AtaPassThruPpi;
+
+ //
+ // Ensure IsTrustSend are valid boolean values
+ //
+ ASSERT ((UINTN) IsTrustSend < 2);
+ if ((UINTN) IsTrustSend >= 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Prepare for ATA command block.
+ //
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ if (TransferLength == 0) {
+ Acb.AtaCommand = ATA_CMD_TRUST_NON_DATA;
+ } else {
+ Acb.AtaCommand = mAtaTrustCommands[IsTrustSend];
+ }
+ Acb.AtaFeatures = SecurityProtocolId;
+ Acb.AtaSectorCount = (UINT8) (TransferLength / 512);
+ Acb.AtaSectorNumber = (UINT8) ((TransferLength / 512) >> 8);
+ //
+ // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.
+ // Here use big endian for Cylinder register.
+ //
+ Acb.AtaCylinderHigh = (UINT8) SecurityProtocolSpecificData;
+ Acb.AtaCylinderLow = (UINT8) (SecurityProtocolSpecificData >> 8);
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |
+ (DeviceData->PortMultiplier == 0xFFFF ?
+ 0 : (DeviceData->PortMultiplier << 4)));
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ if (TransferLength == 0) {
+ Packet.InTransferLength = 0;
+ Packet.OutTransferLength = 0;
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
+ } else if (IsTrustSend) {
+ //
+ // Check the alignment of the incoming buffer prior to invoking underlying
+ // ATA PassThru PPI.
+ //
+ if ((AtaPassThru->Mode->IoAlign > 1) &&
+ !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
+ NewBuffer = AllocateAlignedPages (
+ EFI_SIZE_TO_PAGES (TransferLength),
+ AtaPassThru->Mode->IoAlign
+ );
+ if (NewBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (NewBuffer, Buffer, TransferLength);
+ Buffer = NewBuffer;
+ }
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = (UINT32) TransferLength;
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsTrustSend];
+ } else {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = (UINT32) TransferLength;
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsTrustSend];
+ }
+ Packet.Asb = NULL;
+ Packet.Acb = &Acb;
+ Packet.Timeout = Timeout;
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
+
+ Status = AtaPassThru->PassThru (
+ AtaPassThru,
+ DeviceData->Port,
+ DeviceData->PortMultiplier,
+ &Packet
+ );
+ if (TransferLengthOut != NULL) {
+ if (!IsTrustSend) {
+ *TransferLengthOut = Packet.InTransferLength;
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
new file mode 100644
index 000000000..31b072c11
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
@@ -0,0 +1,338 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+EFI_PEI_PPI_DESCRIPTOR mAhciAtaPassThruPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiAtaPassThruPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIoPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIo2PpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiStorageSecurityCommandPpiGuid,
+ NULL
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR mAhciEndOfPeiNotifyListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ AhciPeimEndOfPei
+};
+
+
+/**
+ Free the DMA resources allocated by an ATA AHCI controller.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA data
+ structure.
+
+**/
+VOID
+AhciFreeDmaResource (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_AHCI_REGISTERS *AhciRegisters;
+
+ ASSERT (Private != NULL);
+
+ AhciRegisters = &Private->AhciRegisters;
+
+ if (AhciRegisters->AhciRFisMap != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
+ AhciRegisters->AhciRFis,
+ AhciRegisters->AhciRFisMap
+ );
+ }
+
+ if (AhciRegisters->AhciCmdListMap != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
+ AhciRegisters->AhciCmdList,
+ AhciRegisters->AhciCmdListMap
+ );
+ }
+
+ if (AhciRegisters->AhciCmdTableMap != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdTableSize),
+ AhciRegisters->AhciCmdTable,
+ AhciRegisters->AhciCmdTableMap
+ );
+ }
+
+}
+
+/**
+ One notified function to cleanup the allocated DMA buffers at EndOfPei.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+ AhciFreeDmaResource (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of the PEIM.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaAhciPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *AhciHcPpi;
+ UINT8 Controller;
+ UINTN MmioBase;
+ UINTN DevicePathLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT32 PortBitMap;
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ UINT8 NumberOfPorts;
+
+ DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
+
+ //
+ // Get the current boot mode.
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
+ return Status;
+ }
+
+ //
+ // Locate the ATA AHCI host controller PPI.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiAtaAhciHostControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &AhciHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to locate AtaAhciHostControllerPpi.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+
+ Controller = 0;
+ MmioBase = 0;
+ while (TRUE) {
+ Status = AhciHcPpi->GetAhciHcMmioBar (
+ AhciHcPpi,
+ Controller,
+ &MmioBase
+ );
+ //
+ // When status is error, meant no controller is found.
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = AhciHcPpi->GetAhciHcDevicePath (
+ AhciHcPpi,
+ Controller,
+ &DevicePathLength,
+ &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ return Status;
+ }
+
+ //
+ // Check validity of the device path of the ATA AHCI controller.
+ //
+ Status = AhciIsHcDevicePathValid (DevicePath, DevicePathLength);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ Controller++;
+ continue;
+ }
+
+ //
+ // For S3 resume performance consideration, not all ports on an ATA AHCI
+ // controller will be enumerated/initialized. The driver consumes the
+ // content within S3StorageDeviceInitList LockBox to get the ports that
+ // will be enumerated/initialized during S3 resume.
+ //
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ NumberOfPorts = AhciS3GetEumeratePorts (DevicePath, DevicePathLength, &PortBitMap);
+ if (NumberOfPorts == 0) {
+ //
+ // No ports need to be enumerated for this controller.
+ //
+ Controller++;
+ continue;
+ }
+ } else {
+ PortBitMap = MAX_UINT32;
+ }
+
+ //
+ // Memory allocation for controller private data.
+ //
+ Private = AllocateZeroPool (sizeof (PEI_AHCI_CONTROLLER_PRIVATE_DATA));
+ if (Private == NULL) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize controller private data.
+ //
+ Private->Signature = AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+ Private->MmioBase = MmioBase;
+ Private->DevicePathLength = DevicePathLength;
+ Private->DevicePath = DevicePath;
+ Private->PortBitMap = PortBitMap;
+ InitializeListHead (&Private->DeviceList);
+
+ Status = AhciModeInitialization (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Controller initialization fail for Controller %d with Status - %r.\n",
+ __FUNCTION__,
+ Controller,
+ Status
+ ));
+ Controller++;
+ continue;
+ }
+
+ Private->AtaPassThruMode.Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL |
+ EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
+ Private->AtaPassThruMode.IoAlign = sizeof (UINTN);
+ Private->AtaPassThruPpi.Revision = EDKII_PEI_ATA_PASS_THRU_PPI_REVISION;
+ Private->AtaPassThruPpi.Mode = &Private->AtaPassThruMode;
+ Private->AtaPassThruPpi.PassThru = AhciAtaPassThruPassThru;
+ Private->AtaPassThruPpi.GetNextPort = AhciAtaPassThruGetNextPort;
+ Private->AtaPassThruPpi.GetNextDevice = AhciAtaPassThruGetNextDevice;
+ Private->AtaPassThruPpi.GetDevicePath = AhciAtaPassThruGetDevicePath;
+ CopyMem (
+ &Private->AtaPassThruPpiList,
+ &mAhciAtaPassThruPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;
+ PeiServicesInstallPpi (&Private->AtaPassThruPpiList);
+
+ Private->BlkIoPpi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo;
+ Private->BlkIoPpi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo;
+ Private->BlkIoPpi.ReadBlocks = AhciBlockIoReadBlocks;
+ CopyMem (
+ &Private->BlkIoPpiList,
+ &mAhciBlkIoPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+
+ Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
+ Private->BlkIo2Ppi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo2;
+ Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo2;
+ Private->BlkIo2Ppi.ReadBlocks = AhciBlockIoReadBlocks2;
+ CopyMem (
+ &Private->BlkIo2PpiList,
+ &mAhciBlkIo2PpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
+ PeiServicesInstallPpi (&Private->BlkIo2PpiList);
+
+ if (Private->TrustComputingDevices != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Security Security Command PPI will be produced for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;
+ Private->StorageSecurityPpi.GetNumberofDevices = AhciStorageSecurityGetDeviceNo;
+ Private->StorageSecurityPpi.GetDevicePath = AhciStorageSecurityGetDevicePath;
+ Private->StorageSecurityPpi.ReceiveData = AhciStorageSecurityReceiveData;
+ Private->StorageSecurityPpi.SendData = AhciStorageSecuritySendData;
+ CopyMem (
+ &Private->StorageSecurityPpiList,
+ &mAhciStorageSecurityPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
+ PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
+ }
+
+ CopyMem (
+ &Private->EndOfPeiNotifyList,
+ &mAhciEndOfPeiNotifyListTemplate,
+ sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
+ );
+ PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+
+ DEBUG ((
+ DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
+ __FUNCTION__, Controller
+ ));
+ Controller++;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
new file mode 100644
index 000000000..2be78076b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
@@ -0,0 +1,731 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AHCI_PEI_H_
+#define _AHCI_PEI_H_
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Atapi.h>
+
+#include <Ppi/AtaAhciController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/AtaPassThru.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/StorageSecurityCommand.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+
+//
+// Structure forward declarations
+//
+typedef struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA PEI_AHCI_CONTROLLER_PRIVATE_DATA;
+
+#include "AhciPeiPassThru.h"
+#include "AhciPeiBlockIo.h"
+#include "AhciPeiStorageSecurity.h"
+
+//
+// ATA AHCI driver implementation related definitions
+//
+//
+// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
+// The value is in millisecond units. Add a bit of margin for robustness.
+//
+#define AHCI_BUS_PHY_DETECT_TIMEOUT 15
+//
+// Refer SATA1.0a spec, the bus reset time should be less than 1s.
+// The value is in 100ns units.
+//
+#define AHCI_PEI_RESET_TIMEOUT 10000000
+//
+// Time out Value for ATA pass through protocol, in 100ns units.
+//
+#define ATA_TIMEOUT 30000000
+//
+// Maximal number of Physical Region Descriptor Table entries supported.
+//
+#define AHCI_MAX_PRDT_NUMBER 8
+
+#define AHCI_CAPABILITY_OFFSET 0x0000
+#define AHCI_CAP_SAM BIT18
+#define AHCI_CAP_SSS BIT27
+
+#define AHCI_GHC_OFFSET 0x0004
+#define AHCI_GHC_RESET BIT0
+#define AHCI_GHC_ENABLE BIT31
+
+#define AHCI_IS_OFFSET 0x0008
+#define AHCI_PI_OFFSET 0x000C
+
+#define AHCI_MAX_PORTS 32
+
+typedef struct {
+ UINT32 Lower32;
+ UINT32 Upper32;
+} DATA_32;
+
+typedef union {
+ DATA_32 Uint32;
+ UINT64 Uint64;
+} DATA_64;
+
+#define AHCI_ATAPI_SIG_MASK 0xFFFF0000
+#define AHCI_ATA_DEVICE_SIG 0x00000000
+
+//
+// Each PRDT entry can point to a memory block up to 4M byte
+//
+#define AHCI_MAX_DATA_PER_PRDT 0x400000
+
+#define AHCI_FIS_REGISTER_H2D 0x27 //Register FIS - Host to Device
+#define AHCI_FIS_REGISTER_H2D_LENGTH 20
+#define AHCI_FIS_REGISTER_D2H 0x34 //Register FIS - Device to Host
+#define AHCI_FIS_PIO_SETUP 0x5F //PIO Setup FIS - Device to Host
+
+#define AHCI_D2H_FIS_OFFSET 0x40
+#define AHCI_PIO_FIS_OFFSET 0x20
+#define AHCI_FIS_TYPE_MASK 0xFF
+
+//
+// Port register
+//
+#define AHCI_PORT_START 0x0100
+#define AHCI_PORT_REG_WIDTH 0x0080
+#define AHCI_PORT_CLB 0x0000
+#define AHCI_PORT_CLBU 0x0004
+#define AHCI_PORT_FB 0x0008
+#define AHCI_PORT_FBU 0x000C
+#define AHCI_PORT_IS 0x0010
+#define AHCI_PORT_IE 0x0014
+#define AHCI_PORT_CMD 0x0018
+#define AHCI_PORT_CMD_ST BIT0
+#define AHCI_PORT_CMD_SUD BIT1
+#define AHCI_PORT_CMD_POD BIT2
+#define AHCI_PORT_CMD_CLO BIT3
+#define AHCI_PORT_CMD_FRE BIT4
+#define AHCI_PORT_CMD_FR BIT14
+#define AHCI_PORT_CMD_CR BIT15
+#define AHCI_PORT_CMD_CPD BIT20
+#define AHCI_PORT_CMD_ATAPI BIT24
+#define AHCI_PORT_CMD_DLAE BIT25
+#define AHCI_PORT_CMD_ALPE BIT26
+#define AHCI_PORT_CMD_ACTIVE (1 << 28)
+#define AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31)
+
+#define AHCI_PORT_TFD 0x0020
+#define AHCI_PORT_TFD_ERR BIT0
+#define AHCI_PORT_TFD_DRQ BIT3
+#define AHCI_PORT_TFD_BSY BIT7
+#define AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0)
+
+#define AHCI_PORT_SIG 0x0024
+#define AHCI_PORT_SSTS 0x0028
+#define AHCI_PORT_SSTS_DET_MASK 0x000F
+#define AHCI_PORT_SSTS_DET 0x0001
+#define AHCI_PORT_SSTS_DET_PCE 0x0003
+
+#define AHCI_PORT_SCTL 0x002C
+#define AHCI_PORT_SCTL_IPM_INIT 0x0300
+
+#define AHCI_PORT_SERR 0x0030
+#define AHCI_PORT_CI 0x0038
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define TIMER_PERIOD_SECONDS(Seconds) MultU64x32((UINT64)(Seconds), 10000000)
+
+#pragma pack(1)
+
+//
+// Received FIS structure
+//
+typedef struct {
+ UINT8 AhciDmaSetupFis[0x1C]; // Dma Setup Fis: offset 0x00
+ UINT8 AhciDmaSetupFisRsvd[0x04];
+ UINT8 AhciPioSetupFis[0x14]; // Pio Setup Fis: offset 0x20
+ UINT8 AhciPioSetupFisRsvd[0x0C];
+ UINT8 AhciD2HRegisterFis[0x14]; // D2H Register Fis: offset 0x40
+ UINT8 AhciD2HRegisterFisRsvd[0x04];
+ UINT64 AhciSetDeviceBitsFis; // Set Device Bits Fix: offset 0x58
+ UINT8 AhciUnknownFis[0x40]; // Unknown Fis: offset 0x60
+ UINT8 AhciUnknownFisRsvd[0x60];
+} EFI_AHCI_RECEIVED_FIS;
+
+//
+// Command List structure includes total 32 entries.
+// The entry Data structure is listed at the following.
+//
+typedef struct {
+ UINT32 AhciCmdCfl:5; //Command FIS Length
+ UINT32 AhciCmdA:1; //ATAPI
+ UINT32 AhciCmdW:1; //Write
+ UINT32 AhciCmdP:1; //Prefetchable
+ UINT32 AhciCmdR:1; //Reset
+ UINT32 AhciCmdB:1; //BIST
+ UINT32 AhciCmdC:1; //Clear Busy upon R_OK
+ UINT32 AhciCmdRsvd:1;
+ UINT32 AhciCmdPmp:4; //Port Multiplier Port
+ UINT32 AhciCmdPrdtl:16; //Physical Region Descriptor Table Length
+ UINT32 AhciCmdPrdbc; //Physical Region Descriptor Byte Count
+ UINT32 AhciCmdCtba; //Command Table Descriptor Base Address
+ UINT32 AhciCmdCtbau; //Command Table Descriptor Base Address Upper 32-BITs
+ UINT32 AhciCmdRsvd1[4];
+} EFI_AHCI_COMMAND_LIST;
+
+//
+// This is a software constructed FIS.
+// For Data transfer operations, this is the H2D Register FIS format as
+// specified in the Serial ATA Revision 2.6 specification.
+//
+typedef struct {
+ UINT8 AhciCFisType;
+ UINT8 AhciCFisPmNum:4;
+ UINT8 AhciCFisRsvd:1;
+ UINT8 AhciCFisRsvd1:1;
+ UINT8 AhciCFisRsvd2:1;
+ UINT8 AhciCFisCmdInd:1;
+ UINT8 AhciCFisCmd;
+ UINT8 AhciCFisFeature;
+ UINT8 AhciCFisSecNum;
+ UINT8 AhciCFisClyLow;
+ UINT8 AhciCFisClyHigh;
+ UINT8 AhciCFisDevHead;
+ UINT8 AhciCFisSecNumExp;
+ UINT8 AhciCFisClyLowExp;
+ UINT8 AhciCFisClyHighExp;
+ UINT8 AhciCFisFeatureExp;
+ UINT8 AhciCFisSecCount;
+ UINT8 AhciCFisSecCountExp;
+ UINT8 AhciCFisRsvd3;
+ UINT8 AhciCFisControl;
+ UINT8 AhciCFisRsvd4[4];
+ UINT8 AhciCFisRsvd5[44];
+} EFI_AHCI_COMMAND_FIS;
+
+//
+// ACMD: ATAPI command (12 or 16 bytes)
+//
+typedef struct {
+ UINT8 AtapiCmd[0x10];
+} EFI_AHCI_ATAPI_COMMAND;
+
+//
+// Physical Region Descriptor Table includes up to 65535 entries
+// The entry data structure is listed at the following.
+// the actual entry number comes from the PRDTL field in the command
+// list entry for this command slot.
+//
+typedef struct {
+ UINT32 AhciPrdtDba; //Data Base Address
+ UINT32 AhciPrdtDbau; //Data Base Address Upper 32-BITs
+ UINT32 AhciPrdtRsvd;
+ UINT32 AhciPrdtDbc:22; //Data Byte Count
+ UINT32 AhciPrdtRsvd1:9;
+ UINT32 AhciPrdtIoc:1; //Interrupt on Completion
+} EFI_AHCI_COMMAND_PRDT;
+
+//
+// Command table Data structure which is pointed to by the entry in the command list
+//
+typedef struct {
+ EFI_AHCI_COMMAND_FIS CommandFis; // A software constructed FIS.
+ EFI_AHCI_ATAPI_COMMAND AtapiCmd; // 12 or 16 bytes ATAPI cmd.
+ UINT8 Reserved[0x30];
+ //
+ // The scatter/gather list for Data transfer.
+ //
+ EFI_AHCI_COMMAND_PRDT PrdtTable[AHCI_MAX_PRDT_NUMBER];
+} EFI_AHCI_COMMAND_TABLE;
+
+#pragma pack()
+
+typedef struct {
+ EFI_AHCI_RECEIVED_FIS *AhciRFis;
+ EFI_AHCI_COMMAND_LIST *AhciCmdList;
+ EFI_AHCI_COMMAND_TABLE *AhciCmdTable;
+ UINTN MaxRFisSize;
+ UINTN MaxCmdListSize;
+ UINTN MaxCmdTableSize;
+ VOID *AhciRFisMap;
+ VOID *AhciCmdListMap;
+ VOID *AhciCmdTableMap;
+} EFI_AHCI_REGISTERS;
+
+//
+// Unique signature for AHCI ATA device information structure.
+//
+#define AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE SIGNATURE_32 ('A', 'P', 'A', 'D')
+
+//
+// AHCI mode device information structure.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT16 Port;
+ UINT16 PortMultiplier;
+ UINT8 FisIndex;
+ UINTN DeviceIndex;
+ ATA_IDENTIFY_DATA *IdentifyData;
+
+ BOOLEAN Lba48Bit;
+ BOOLEAN TrustComputing;
+ UINTN TrustComputingDeviceIndex;
+ EFI_PEI_BLOCK_IO2_MEDIA Media;
+
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+} PEI_AHCI_ATA_DEVICE_DATA;
+
+#define AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS(a) \
+ CR (a, \
+ PEI_AHCI_ATA_DEVICE_DATA, \
+ Link, \
+ AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE \
+ );
+
+//
+// Unique signature for private data structure.
+//
+#define AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('A','P','C','P')
+
+//
+// ATA AHCI controller private data structure.
+//
+struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA {
+ UINT32 Signature;
+ UINTN MmioBase;
+ UINTN DevicePathLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ EFI_ATA_PASS_THRU_MODE AtaPassThruMode;
+ EDKII_PEI_ATA_PASS_THRU_PPI AtaPassThruPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi;
+ EFI_PEI_PPI_DESCRIPTOR AtaPassThruPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+ EFI_PEI_PPI_DESCRIPTOR StorageSecurityPpiList;
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ EFI_AHCI_REGISTERS AhciRegisters;
+
+ UINT32 PortBitMap;
+ UINT32 ActiveDevices;
+ UINT32 TrustComputingDevices;
+ LIST_ENTRY DeviceList;
+
+ UINT16 PreviousPort;
+ UINT16 PreviousPortMultiplier;
+};
+
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU(a) \
+ CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, AtaPassThruPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a) \
+ CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, BlkIoPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a) \
+ CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, BlkIo2Ppi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY(a) \
+ CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, StorageSecurityPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) \
+ CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global variables
+//
+extern UINT32 mMaxTransferBlockNumber[2];
+
+//
+// Internal functions
+//
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ One notified function to cleanup the allocated DMA buffers at EndOfPei.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Collect the number of bits set within a port bitmap.
+
+ @param[in] PortBitMap A 32-bit wide bit map of ATA AHCI ports.
+
+ @retval The number of bits set in the bitmap.
+
+**/
+UINT8
+AhciGetNumberOfPortsFromMap (
+ IN UINT32 PortBitMap
+ );
+
+/**
+ Start a PIO Data transfer on specific port.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The number of port multiplier.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in,out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of PIO data transfer, uses
+ 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+ @retval EFI_SUCCESS The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciPioTransfer (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout
+ );
+
+/**
+ Start a non data transfer on specific port.
+
+ @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The number of port multiplier.
+ @param[in] FisIndex The offset index of the FIS base address.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in] Timeout The timeout value of non data transfer, uses
+ 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciNonDataTransfer (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT8 FisIndex,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout
+ );
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS The ATA AHCI controller is initialized successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete while initializing
+ the controller.
+ @retval Others A device error occurred while initializing the
+ controller.
+
+**/
+EFI_STATUS
+AhciModeInitialization (
+ IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
+ );
+
+/**
+ Transfer data from ATA device.
+
+ This function performs one ATA pass through transaction to transfer data from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINT32 TransferLength,
+ IN BOOLEAN IsWrite
+ );
+
+/**
+ Trust transfer data from/to ATA device.
+
+ This function performs one ATA pass through transaction to do a trust transfer
+ from/to ATA device. It chooses the appropriate ATA command and protocol to invoke
+ PassThru interface of ATA pass through.
+
+ @param[in] DeviceData Pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter
+ of the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to
+ be sent.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsTrustSend Indicates whether it is a trust send operation
+ or not.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[out] TransferLengthOut
+ A pointer to a buffer to store the size in bytes
+ of the data written to the buffer. Ignore it when
+ IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ );
+
+/**
+ Returns a pointer to the next node in a device path.
+
+ If Node is NULL, then ASSERT().
+
+ @param Node A pointer to a device path node data structure.
+
+ @return a pointer to the device path node that follows the device path node
+ specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+ IN CONST VOID *Node
+ );
+
+/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ );
+
+/**
+ Check the validity of the device path of a ATA AHCI host controller.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[in] DevicePathLength The length of the device path.
+
+ @retval EFI_SUCCESS The device path is valid.
+ @retval EFI_INVALID_PARAMETER The device path is invalid.
+
+**/
+EFI_STATUS
+AhciIsHcDevicePathValid (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN DevicePathLength
+ );
+
+/**
+ Build the device path for an ATA device with given port and port multiplier number.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ data structure.
+ @param[in] Port The given port number.
+ @param[in] PortMultiplierPort The given port multiplier number.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of ATA device.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+AhciBuildDevicePath (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Collect the ports that need to be enumerated on a controller for S3 phase.
+
+ @param[in] HcDevicePath Device path of the controller.
+ @param[in] HcDevicePathLength Length of the device path specified by
+ HcDevicePath.
+ @param[out] PortBitMap Bitmap that indicates the ports that need
+ to be enumerated on the controller.
+
+ @retval The number of ports that need to be enumerated.
+
+**/
+UINT8
+AhciS3GetEumeratePorts (
+ IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath,
+ IN UINTN HcDevicePathLength,
+ OUT UINT32 *PortBitMap
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
new file mode 100644
index 000000000..912ff7a8b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
@@ -0,0 +1,72 @@
+## @file
+# The AhciPei driver is used to manage ATA hard disk device working under AHCI
+# mode at PEI phase.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AhciPei
+ MODULE_UNI_FILE = AhciPei.uni
+ FILE_GUID = 79E5CA15-7A2D-4F37-A63B-D1C7BBCA47AD
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = AtaAhciPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ AhciPei.c
+ AhciPei.h
+ AhciPeiBlockIo.c
+ AhciPeiBlockIo.h
+ AhciPeiPassThru.c
+ AhciPeiPassThru.h
+ AhciPeiS3.c
+ AhciPeiStorageSecurity.c
+ AhciPeiStorageSecurity.h
+ AhciMode.c
+ DevicePath.c
+ DmaMem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PeiServicesLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ LockBoxLib
+ PeimEntryPoint
+
+[Ppis]
+ gEdkiiPeiAtaAhciHostControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+ gEdkiiPeiAtaPassThruPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES
+ gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES
+
+[Guids]
+ gS3StorageDeviceInitListGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND
+ gEfiPeiMasterBootModePpiGuid AND
+ gEdkiiPeiAtaAhciHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AhciPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni
new file mode 100644
index 000000000..c45ffd1dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// The AhciPei driver is used to manage ATA hard disk device working under AHCI
+// mode at PEI phase.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manage AHCI mode ATA hard disk device at PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The AhciPei driver is used to manage ATA hard disk device working under AHCI mode at PEI phase."
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
new file mode 100644
index 000000000..e7c7a3953
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
@@ -0,0 +1,516 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+/**
+ Traverse the attached ATA devices list to find out the device with given index.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ instance.
+ @param[in] DeviceIndex The device index.
+
+ @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+ info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchDeviceByIndex (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINTN DeviceIndex
+ )
+{
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveDevices)) {
+ return NULL;
+ }
+
+ Node = GetFirstNode (&Private->DeviceList);
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceData->DeviceIndex == DeviceIndex) {
+ return DeviceData;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return NULL;
+}
+
+/**
+ Read a number of blocks from ATA device.
+
+ This function performs ATA pass through transactions to read data from ATA device.
+ It may separate the read request into several ATA pass through transactions.
+
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA
+ data structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] NumberOfBlocks The block number or sector count of the transfer.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return Others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+AccessAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT UINT8 *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxTransferBlockNumber;
+ UINTN TransferBlockNumber;
+ UINTN BlockSize;
+
+ //
+ // Ensure Lba48Bit is a valid boolean value
+ //
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
+ if ((UINTN) DeviceData->Lba48Bit >= 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ MaxTransferBlockNumber = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+ BlockSize = DeviceData->Media.BlockSize;
+
+ do {
+ if (NumberOfBlocks > MaxTransferBlockNumber) {
+ TransferBlockNumber = MaxTransferBlockNumber;
+ NumberOfBlocks -= MaxTransferBlockNumber;
+ } else {
+ TransferBlockNumber = NumberOfBlocks;
+ NumberOfBlocks = 0;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "%a: Blocking AccessAtaDevice, TransferBlockNumber = %x; StartLba = %x\n",
+ __FUNCTION__, TransferBlockNumber, StartLba
+ ));
+
+ Status = TransferAtaDevice (
+ DeviceData,
+ Buffer,
+ StartLba,
+ (UINT32) TransferBlockNumber,
+ FALSE // Read
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StartLba += TransferBlockNumber;
+ Buffer += TransferBlockNumber * BlockSize;
+ } while (NumberOfBlocks > 0);
+
+ return Status;
+}
+
+/**
+ Read specified bytes from Lba from the device.
+
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA data structure.
+ @param[out] Buffer The Buffer used to store the Data read from the device.
+ @param[in] StartLba The start block number.
+ @param[in] BufferSize Total bytes to be read.
+
+ @retval EFI_SUCCESS Data are read from the device.
+ @retval Others Fail to read all the data.
+
+**/
+EFI_STATUS
+AhciRead (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = DeviceData->Media.BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLba > DeviceData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+ NumberOfBlocks = BufferSize / BlockSize;
+ if (NumberOfBlocks - 1 > DeviceData->Media.LastBlock - StartLba) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Invoke low level AtaDevice Access Routine.
+ //
+ Status = AccessAtaDevice (DeviceData, Buffer, StartLba, NumberOfBlocks);
+
+ return Status;
+}
+
+
+/**
+ 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. 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ *NumberBlockDevices = Private->ActiveDevices;
+
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE) EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK;
+ MediaInfo->MediaPresent = TRUE;
+ MediaInfo->LastBlock = (UINTN) DeviceData->Media.LastBlock;
+ MediaInfo->BlockSize = DeviceData->Media.BlockSize;
+
+ 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, 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
+AhciBlockIoReadBlocks (
+ 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
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return AhciRead (DeviceData, Buffer, StartLBA, BufferSize);
+}
+
+/**
+ 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. 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ *NumberBlockDevices = Private->ActiveDevices;
+
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (
+ MediaInfo,
+ &DeviceData->Media,
+ sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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, 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
+AhciBlockIoReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ return AhciBlockIoReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
new file mode 100644
index 000000000..5896ae5ac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
@@ -0,0 +1,257 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AHCI_PEI_BLOCKIO_H_
+#define _AHCI_PEI_BLOCKIO_H_
+
+//
+// ATA hard disk device for EFI_PEI_BLOCK_DEVICE_TYPE
+//
+#define EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK 8
+
+/**
+ 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. 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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, 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
+AhciBlockIoReadBlocks (
+ 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
+ );
+
+/**
+ 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. 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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, 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
+AhciBlockIoReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni
new file mode 100644
index 000000000..743443a25
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// AhciPei Localized Strings and Content
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"AHCI Bus Peim"
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
new file mode 100644
index 000000000..191b78c88
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
@@ -0,0 +1,514 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+/**
+ Traverse the attached ATA devices list to find out the device with given Port
+ and PortMultiplierPort.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ instance.
+ @param[in] Port The port number of the ATA device.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
+
+ @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+ info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchDeviceByPort (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort
+ )
+{
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ Node = GetFirstNode (&Private->DeviceList);
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceData->Port == Port) &&
+ (DeviceData->PortMultiplier == PortMultiplierPort)) {
+ return DeviceData;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return NULL;
+}
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+ @param[in] Private Pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+ @param[in] Port The port number of the ATA device.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA
+ device.
+ @param[in] FisIndex The index of the FIS.
+ @param[in,out] Packet A pointer to the ATA command to send to
+ the ATA device specified by Port and
+ PortMultiplierPort.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For
+ bi-directional commands, InTransferLength bytes
+ were transferred from InDataBuffer. For write
+ and bi-directional commands, OutTransferLength
+ bytes were transferred by OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
+ of bytes that could be transferred is returned
+ in InTransferLength. For write and bi-directional
+ commands, OutTransferLength bytes were transferred
+ by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there
+ are too many ATA commands already queued. The
+ caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ send the ATA command.
+ @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of
+ Acb are invalid. The ATA command was not sent,
+ so no additional status information is available.
+
+**/
+EFI_STATUS
+AhciPassThruExecute (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN UINT8 FisIndex,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+
+ switch (Packet->Protocol) {
+ case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
+ Status = AhciNonDataTransfer (
+ Private,
+ (UINT8) Port,
+ (UINT8) PortMultiplierPort,
+ FisIndex,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
+ Status = AhciPioTransfer (
+ Private,
+ (UINT8) Port,
+ (UINT8) PortMultiplierPort,
+ FisIndex,
+ TRUE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->InDataBuffer,
+ Packet->InTransferLength,
+ Packet->Timeout
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
+ Status = AhciPioTransfer (
+ Private,
+ (UINT8) Port,
+ (UINT8) PortMultiplierPort,
+ FisIndex,
+ FALSE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->OutDataBuffer,
+ Packet->OutTransferLength,
+ Packet->Timeout
+ );
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number of the ATA device to send
+ the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA
+ device to send the command.
+ If there is no port multiplier, then specify
+ 0xFFFF.
+ @param[in,out] Packet A pointer to the ATA command to send to
+ the ATA device specified by Port and
+ PortMultiplierPort.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For
+ bi-directional commands, InTransferLength bytes
+ were transferred from InDataBuffer. For write
+ and bi-directional commands, OutTransferLength
+ bytes were transferred by OutDataBuffer.
+ @retval EFI_NOT_FOUND The specified ATA device is not found.
+ @retval EFI_INVALID_PARAMETER The contents of Acb are invalid. The ATA command
+ was not sent, so no additional status information
+ is available.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
+ of bytes that could be transferred is returned
+ in InTransferLength. For write and bi-directional
+ commands, OutTransferLength bytes were transferred
+ by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there
+ are too many ATA commands already queued. The
+ caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ send the ATA command.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruPassThru (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ UINT32 IoAlign;
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ UINT32 MaxSectorCount;
+ UINT32 BlockSize;
+
+ if (This == NULL || Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = This->Mode->IoAlign;
+ if ((IoAlign > 1) && !IS_ALIGNED (Packet->InDataBuffer, IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((IoAlign > 1) && !IS_ALIGNED (Packet->OutDataBuffer, IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((IoAlign > 1) && !IS_ALIGNED (Packet->Asb, IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+ DeviceData = SearchDeviceByPort (Private, Port, PortMultiplierPort);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ MaxSectorCount = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+ BlockSize = DeviceData->Media.BlockSize;
+
+ //
+ // Convert the transfer length from sector count to byte.
+ //
+ if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+ (Packet->InTransferLength != 0)) {
+ Packet->InTransferLength = Packet->InTransferLength * BlockSize;
+ }
+
+ //
+ // Convert the transfer length from sector count to byte.
+ //
+ if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+ (Packet->OutTransferLength != 0)) {
+ Packet->OutTransferLength = Packet->OutTransferLength * BlockSize;
+ }
+
+ //
+ // If the data buffer described by InDataBuffer/OutDataBuffer and
+ // InTransferLength/OutTransferLength is too big to be transferred in a single
+ // command, then no data is transferred and EFI_BAD_BUFFER_SIZE is returned.
+ //
+ if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) ||
+ ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return AhciPassThruExecute (
+ Private,
+ DeviceData->Port,
+ DeviceData->PortMultiplier,
+ DeviceData->FisIndex,
+ Packet
+ );
+}
+
+/**
+ Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+ These can either be the list of ports where ATA devices are actually present or the
+ list of legal port numbers for the ATA controller. Regardless, the caller of this
+ function must probe the port number returned to see if an ATA device is actually
+ present at that location on the ATA controller.
+
+ The GetNextPort() function retrieves the port number on an ATA controller. If on
+ input Port is 0xFFFF, then the port number of the first port on the ATA controller
+ is returned in Port and EFI_SUCCESS is returned.
+
+ If Port is a port number that was returned on a previous call to GetNextPort(),
+ then the port number of the next port on the ATA controller is returned in Port,
+ and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+ a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+ If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] Port On input, a pointer to the port number on the ATA controller.
+ On output, a pointer to the next port number on the ATA
+ controller. An input value of 0xFFFF retrieves the first
+ port number on the ATA controller.
+
+ @retval EFI_SUCCESS The next port number on the ATA controller was
+ returned in Port.
+ @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
+ @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned
+ on a previous call to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextPort (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN OUT UINT16 *Port
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ if (This == NULL || Port == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+ if (*Port == 0xFFFF) {
+ //
+ // If the Port is all 0xFF's, start to traverse the device list from the
+ // beginning.
+ //
+ Node = GetFirstNode (&Private->DeviceList);
+ if (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ *Port = DeviceData->Port;
+ goto Exit;
+ }
+
+ return EFI_NOT_FOUND;
+ } else if (*Port == Private->PreviousPort) {
+ Node = GetFirstNode (&Private->DeviceList);
+
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceData->Port > *Port){
+ *Port = DeviceData->Port;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // Port is not equal to all 0xFF's and not equal to previous return value.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+Exit:
+ //
+ // Update the PreviousPort.
+ //
+ Private->PreviousPort = *Port;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to retrieve the list of legal port multiplier port numbers for ATA devices
+ on a port of an ATA controller. These can either be the list of port multiplier
+ ports where ATA devices are actually present on port or the list of legal port
+ multiplier ports on that port. Regardless, the caller of this function must probe
+ the port number and port multiplier port number returned to see if an ATA device
+ is actually present.
+
+ The GetNextDevice() function retrieves the port multiplier port number of an ATA
+ device present on a port of an ATA controller.
+
+ If PortMultiplierPort points to a port multiplier port number value that was
+ returned on a previous call to GetNextDevice(), then the port multiplier port
+ number of the next ATA device on the port of the ATA controller is returned in
+ PortMultiplierPort, and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+ of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+ and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+ was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+ is returned.
+
+ If PortMultiplierPort is the port multiplier port number of the last ATA device
+ on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number present on the ATA controller.
+ @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier
+ port number of an ATA device present on the
+ ATA controller. If on input a PortMultiplierPort
+ of 0xFFFF is specified, then the port multiplier
+ port number of the first ATA device is returned.
+ On output, a pointer to the port multiplier port
+ number of the next ATA device present on an ATA
+ controller.
+
+ @retval EFI_SUCCESS The port multiplier port number of the next ATA
+ device on the port of the ATA controller was
+ returned in PortMultiplierPort.
+ @retval EFI_NOT_FOUND There are no more ATA devices on this port of
+ the ATA controller.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+ was not returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextDevice (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN OUT UINT16 *PortMultiplierPort
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ if (This == NULL || PortMultiplierPort == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+ if (Private->PreviousPortMultiplier == 0xFFFF) {
+ //
+ // If a device is directly attached on a port, previous call to this
+ // function will return the value 0xFFFF for PortMultiplierPort. In
+ // this case, there should be no more device on the port multiplier.
+ //
+ Private->PreviousPortMultiplier = 0;
+ return EFI_NOT_FOUND;
+ }
+
+ if (*PortMultiplierPort == Private->PreviousPortMultiplier) {
+ Node = GetFirstNode (&Private->DeviceList);
+
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceData->Port == Port) &&
+ (DeviceData->PortMultiplier > *PortMultiplierPort)){
+ *PortMultiplierPort = DeviceData->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else if (*PortMultiplierPort == 0xFFFF) {
+ //
+ // If the PortMultiplierPort is all 0xFF's, start to traverse the device list
+ // from the beginning.
+ //
+ Node = GetFirstNode (&Private->DeviceList);
+
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceData->Port == Port){
+ *PortMultiplierPort = DeviceData->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // PortMultiplierPort is not equal to all 0xFF's and not equal to previous
+ // return value.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+Exit:
+ //
+ // Update the PreviousPortMultiplier.
+ //
+ Private->PreviousPortMultiplier = *PortMultiplierPort;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the device path information of the underlying ATA host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying ATA host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The device path of the ATA host controller has
+ been successfully returned.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to return the device path.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetDevicePath (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+ *DevicePathLength = Private->DevicePathLength;
+ *DevicePath = AllocateCopyPool (Private->DevicePathLength, Private->DevicePath);
+ if (*DevicePath == NULL) {
+ *DevicePathLength = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h
new file mode 100644
index 000000000..94395aade
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h
@@ -0,0 +1,177 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AHCI_PEI_PASSTHRU_H_
+#define _AHCI_PEI_PASSTHRU_H_
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number of the ATA device to send
+ the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA
+ device to send the command.
+ If there is no port multiplier, then specify
+ 0xFFFF.
+ @param[in,out] Packet A pointer to the ATA command to send to
+ the ATA device specified by Port and
+ PortMultiplierPort.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For
+ bi-directional commands, InTransferLength bytes
+ were transferred from InDataBuffer. For write
+ and bi-directional commands, OutTransferLength
+ bytes were transferred by OutDataBuffer.
+ @retval EFI_NOT_FOUND The specified ATA device is not found.
+ @retval EFI_INVALID_PARAMETER The contents of Acb are invalid. The ATA command
+ was not sent, so no additional status information
+ is available.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
+ of bytes that could be transferred is returned
+ in InTransferLength. For write and bi-directional
+ commands, OutTransferLength bytes were transferred
+ by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there
+ are too many ATA commands already queued. The
+ caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ send the ATA command.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruPassThru (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+/**
+ Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+ These can either be the list of ports where ATA devices are actually present or the
+ list of legal port numbers for the ATA controller. Regardless, the caller of this
+ function must probe the port number returned to see if an ATA device is actually
+ present at that location on the ATA controller.
+
+ The GetNextPort() function retrieves the port number on an ATA controller. If on
+ input Port is 0xFFFF, then the port number of the first port on the ATA controller
+ is returned in Port and EFI_SUCCESS is returned.
+
+ If Port is a port number that was returned on a previous call to GetNextPort(),
+ then the port number of the next port on the ATA controller is returned in Port,
+ and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+ a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+ If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] Port On input, a pointer to the port number on the ATA controller.
+ On output, a pointer to the next port number on the ATA
+ controller. An input value of 0xFFFF retrieves the first
+ port number on the ATA controller.
+
+ @retval EFI_SUCCESS The next port number on the ATA controller was
+ returned in Port.
+ @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
+ @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned
+ on a previous call to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextPort (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN OUT UINT16 *Port
+ );
+
+/**
+ Used to retrieve the list of legal port multiplier port numbers for ATA devices
+ on a port of an ATA controller. These can either be the list of port multiplier
+ ports where ATA devices are actually present on port or the list of legal port
+ multiplier ports on that port. Regardless, the caller of this function must probe
+ the port number and port multiplier port number returned to see if an ATA device
+ is actually present.
+
+ The GetNextDevice() function retrieves the port multiplier port number of an ATA
+ device present on a port of an ATA controller.
+
+ If PortMultiplierPort points to a port multiplier port number value that was
+ returned on a previous call to GetNextDevice(), then the port multiplier port
+ number of the next ATA device on the port of the ATA controller is returned in
+ PortMultiplierPort, and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+ of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+ and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+ was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+ is returned.
+
+ If PortMultiplierPort is the port multiplier port number of the last ATA device
+ on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number present on the ATA controller.
+ @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier
+ port number of an ATA device present on the
+ ATA controller. If on input a PortMultiplierPort
+ of 0xFFFF is specified, then the port multiplier
+ port number of the first ATA device is returned.
+ On output, a pointer to the port multiplier port
+ number of the next ATA device present on an ATA
+ controller.
+
+ @retval EFI_SUCCESS The port multiplier port number of the next ATA
+ device on the port of the ATA controller was
+ returned in PortMultiplierPort.
+ @retval EFI_NOT_FOUND There are no more ATA devices on this port of
+ the ATA controller.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+ was not returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextDevice (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN OUT UINT16 *PortMultiplierPort
+ );
+
+/**
+ Gets the device path information of the underlying ATA host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying ATA host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The device path of the ATA host controller has
+ been successfully returned.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to return the device path.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetDevicePath (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
new file mode 100644
index 000000000..bf0489fa6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
@@ -0,0 +1,132 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+#include <Guid/S3StorageDeviceInitList.h>
+
+#include <Library/LockBoxLib.h>
+
+/**
+ Collect the ports that need to be enumerated on a controller for S3 phase.
+
+ @param[in] HcDevicePath Device path of the controller.
+ @param[in] HcDevicePathLength Length of the device path specified by
+ HcDevicePath.
+ @param[out] PortBitMap Bitmap that indicates the ports that need
+ to be enumerated on the controller.
+
+ @retval The number of ports that need to be enumerated.
+
+**/
+UINT8
+AhciS3GetEumeratePorts (
+ IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath,
+ IN UINTN HcDevicePathLength,
+ OUT UINT32 *PortBitMap
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DummyData;
+ UINTN S3InitDevicesLength;
+ EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN DevicePathInstLength;
+ BOOLEAN EntireEnd;
+ SATA_DEVICE_PATH *SataDeviceNode;
+
+ *PortBitMap = 0;
+
+ //
+ // From the LockBox, get the list of device paths for devices need to be
+ // initialized in S3.
+ //
+ S3InitDevices = NULL;
+ S3InitDevicesLength = sizeof (DummyData);
+ EntireEnd = FALSE;
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return 0;
+ } else {
+ S3InitDevices = AllocatePool (S3InitDevicesLength);
+ if (S3InitDevices == NULL) {
+ return 0;
+ }
+
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+ }
+
+ if (S3InitDevices == NULL) {
+ return 0;
+ }
+
+ //
+ // Only enumerate the ports that exist in the device list.
+ //
+ do {
+ //
+ // Fetch the size of current device path instance.
+ //
+ Status = GetDevicePathInstanceSize (
+ S3InitDevices,
+ &DevicePathInstLength,
+ &EntireEnd
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ DevicePathInst = S3InitDevices;
+ S3InitDevices = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);
+
+ if (HcDevicePathLength >= DevicePathInstLength) {
+ continue;
+ }
+
+ //
+ // Compare the device paths to determine if the device is managed by this
+ // controller.
+ //
+ if (CompareMem (
+ DevicePathInst,
+ HcDevicePath,
+ HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+ ) == 0) {
+ //
+ // Get the port number.
+ //
+ while (DevicePathInst->Type != END_DEVICE_PATH_TYPE) {
+ if ((DevicePathInst->Type == MESSAGING_DEVICE_PATH) &&
+ (DevicePathInst->SubType == MSG_SATA_DP)) {
+ SataDeviceNode = (SATA_DEVICE_PATH *) DevicePathInst;
+ //
+ // For now, the driver only support upto AHCI_MAX_PORTS ports and
+ // devices directly connected to a HBA.
+ //
+ if ((SataDeviceNode->HBAPortNumber >= AHCI_MAX_PORTS) ||
+ (SataDeviceNode->PortMultiplierPortNumber != 0xFFFF)) {
+ break;
+ }
+ *PortBitMap |= (UINT32)BIT0 << SataDeviceNode->HBAPortNumber;
+ break;
+ }
+ DevicePathInst = NextDevicePathNode (DevicePathInst);
+ }
+ }
+ } while (!EntireEnd);
+
+ //
+ // Return the number of ports need to be enumerated on this controller.
+ //
+ return AhciGetNumberOfPortsFromMap (*PortBitMap);
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c
new file mode 100644
index 000000000..1bc25a788
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c
@@ -0,0 +1,384 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+/**
+ Traverse the attached ATA devices list to find out the device with given trust
+ computing device index.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ instance.
+ @param[in] TrustComputingDeviceIndex The trust computing device index.
+
+ @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+ info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchTrustComputingDeviceByIndex (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINTN TrustComputingDeviceIndex
+ )
+{
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ Node = GetFirstNode (&Private->DeviceList);
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceData->TrustComputingDeviceIndex == TrustComputingDeviceIndex) {
+ return DeviceData;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return NULL;
+}
+
+/**
+ Gets the count of storage security devices that one specific driver detects.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] NumberofDevices The number of storage security devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDeviceNo (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ OUT UINTN *NumberofDevices
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberofDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ *NumberofDevices = Private->TrustComputingDevices;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the device path of a specific storage security device.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which
+ the function wants to talk. Because the driver
+ that implements Storage Security Command PPIs
+ will manage multiple storage 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 NumberofDevices.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of storage security device.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_NOT_FOUND The specified storage security device not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDevicePath (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ EFI_STATUS Status;
+
+ if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = AhciBuildDevicePath (
+ Private,
+ DeviceData->Port,
+ DeviceData->PortMultiplier,
+ DevicePathLength,
+ DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given DeviceIndex.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which the
+ function wants to talk. Because the driver that
+ implements Storage Security Command PPIs will manage
+ multiple storage 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 NumberofDevices.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize
+ Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command. The caller is
+ responsible for having either implicit or explicit
+ ownership of the buffer.
+ @param[out] PayloadTransferSize
+ A pointer to a buffer to store the size in bytes
+ of the data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed
+ successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to
+ store the available data from the device.
+ The PayloadBuffer contains the truncated
+ data.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support
+ security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed
+ with an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize
+ is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the
+ security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityReceiveData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
+ if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return TrustTransferAtaDevice (
+ DeviceData,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ FALSE,
+ Timeout,
+ PayloadTransferSize
+ );
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is
+ sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is
+ sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command
+ is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error,
+ the functio shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex The ID of the device.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[in] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support security
+ protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with
+ an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize
+ is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecuritySendData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
+ if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return TrustTransferAtaDevice (
+ DeviceData,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ TRUE,
+ Timeout,
+ NULL
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h
new file mode 100644
index 000000000..905cdb88a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h
@@ -0,0 +1,240 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AHCI_PEI_STORAGE_SECURITY_H_
+#define _AHCI_PEI_STORAGE_SECURITY_H_
+
+/**
+ Gets the count of storage security devices that one specific driver detects.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] NumberofDevices The number of storage security devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDeviceNo (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ OUT UINTN *NumberofDevices
+ );
+
+/**
+ Gets the device path of a specific storage security device.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which
+ the function wants to talk. Because the driver
+ that implements Storage Security Command PPIs
+ will manage multiple storage 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 NumberofDevices.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of storage security device.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_NOT_FOUND The specified storage security device not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDevicePath (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given DeviceIndex.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which the
+ function wants to talk. Because the driver that
+ implements Storage Security Command PPIs will manage
+ multiple storage 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 NumberofDevices.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize
+ Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command. The caller is
+ responsible for having either implicit or explicit
+ ownership of the buffer.
+ @param[out] PayloadTransferSize
+ A pointer to a buffer to store the size in bytes
+ of the data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed
+ successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to
+ store the available data from the device.
+ The PayloadBuffer contains the truncated
+ data.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support
+ security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed
+ with an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize
+ is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the
+ security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityReceiveData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is
+ sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is
+ sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command
+ is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error,
+ the functio shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex The ID of the device.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[in] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support security
+ protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with
+ an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize
+ is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecuritySendData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c
new file mode 100644
index 000000000..65d6fcb32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c
@@ -0,0 +1,277 @@
+/** @file
+ The device path help function.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+//
+// Template for a SATA Device Path node
+//
+SATA_DEVICE_PATH mAhciSataDevicePathNodeTemplate = {
+ { // Header
+ MESSAGING_DEVICE_PATH,
+ MSG_SATA_DP,
+ {
+ (UINT8) (sizeof (SATA_DEVICE_PATH)),
+ (UINT8) ((sizeof (SATA_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0x0, // HBAPortNumber
+ 0xFFFF, // PortMultiplierPortNumber
+ 0x0 // Lun
+};
+
+//
+// Template for an End of entire Device Path node
+//
+EFI_DEVICE_PATH_PROTOCOL mAhciEndDevicePathNodeTemplate = {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+ (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+ }
+};
+
+/**
+ Returns the 16-bit Length field of a device path node.
+
+ Returns the 16-bit Length field of the device path node specified by Node.
+ Node is not required to be aligned on a 16-bit boundary, so it is recommended
+ that a function such as ReadUnaligned16() be used to extract the contents of
+ the Length field.
+
+ If Node is NULL, then ASSERT().
+
+ @param Node A pointer to a device path node data structure.
+
+ @return The 16-bit Length field of the device path node specified by Node.
+
+**/
+UINTN
+DevicePathNodeLength (
+ IN CONST VOID *Node
+ )
+{
+ ASSERT (Node != NULL);
+ return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
+}
+
+/**
+ Returns a pointer to the next node in a device path.
+
+ If Node is NULL, then ASSERT().
+
+ @param Node A pointer to a device path node data structure.
+
+ @return a pointer to the device path node that follows the device path node
+ specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+ IN CONST VOID *Node
+ )
+{
+ ASSERT (Node != NULL);
+ return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
+}
+
+/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Walker;
+
+ if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the end of the device path instance
+ //
+ Walker = DevicePath;
+ while (Walker->Type != END_DEVICE_PATH_TYPE) {
+ Walker = NextDevicePathNode (Walker);
+ }
+
+ //
+ // Check if 'Walker' points to the end of an entire device path
+ //
+ if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = TRUE;
+ } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = FALSE;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Compute the size of the device path instance
+ //
+ *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the validity of the device path of a ATA AHCI host controller.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[in] DevicePathLength The length of the device path.
+
+ @retval EFI_SUCCESS The device path is valid.
+ @retval EFI_INVALID_PARAMETER The device path is invalid.
+
+**/
+EFI_STATUS
+AhciIsHcDevicePathValid (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN DevicePathLength
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Start;
+ UINTN Size;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Validate the DevicePathLength is big enough to touch the first node.
+ //
+ if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Start = DevicePath;
+ while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&
+ DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+
+ //
+ // Prevent overflow and invalid zero in the 'Length' field of a device path
+ // node.
+ //
+ if ((UINTN) DevicePath <= (UINTN) Start) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Prevent touching memory beyond given DevicePathLength.
+ //
+ if ((UINTN) DevicePath - (UINTN) Start >
+ DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Check if the device path and its size match each other.
+ //
+ Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ if (Size != DevicePathLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build the device path for an ATA device with given port and port multiplier number.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ data structure.
+ @param[in] Port The given port number.
+ @param[in] PortMultiplierPort The given port multiplier number.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of ATA device.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+AhciBuildDevicePath (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
+ SATA_DEVICE_PATH *SataDeviceNode;
+
+ if (DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *DevicePathLength = Private->DevicePathLength + sizeof (SATA_DEVICE_PATH);
+ *DevicePath = AllocatePool (*DevicePathLength);
+ if (*DevicePath == NULL) {
+ *DevicePathLength = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Construct the host controller part device nodes
+ //
+ DevicePathWalker = *DevicePath;
+ CopyMem (
+ DevicePathWalker,
+ Private->DevicePath,
+ Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+ );
+
+ //
+ // Construct the SATA device node
+ //
+ DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+ (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
+ CopyMem (
+ DevicePathWalker,
+ &mAhciSataDevicePathNodeTemplate,
+ sizeof (mAhciSataDevicePathNodeTemplate)
+ );
+ SataDeviceNode = (SATA_DEVICE_PATH *)DevicePathWalker;
+ SataDeviceNode->HBAPortNumber = Port;
+ SataDeviceNode->PortMultiplierPortNumber = PortMultiplierPort;
+
+ //
+ // Construct the end device node
+ //
+ DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+ sizeof (SATA_DEVICE_PATH));
+ CopyMem (
+ DevicePathWalker,
+ &mAhciEndDevicePathNodeTemplate,
+ sizeof (mAhciEndDevicePathNodeTemplate)
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
new file mode 100644
index 000000000..3a506d8c2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
@@ -0,0 +1,263 @@
+/** @file
+ The DMA memory help function.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+/**
+ Get IOMMU PPI.
+
+ @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = NULL;
+ Status = PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->Map (
+ IoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ Status = IoMmu->Unmap (IoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ Status = IoMmu->Unmap (IoMmu, Mapping);
+ Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
new file mode 100644
index 000000000..7e2fade40
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
@@ -0,0 +1,2818 @@
+/** @file
+ The file for AHCI mode of ATA host controller.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtaAtapiPassThru.h"
+
+/**
+ Read AHCI Operation register.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The operation register offset.
+
+ @return The register content read.
+
+**/
+UINT32
+EFIAPI
+AhciReadReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ ASSERT (PciIo != NULL);
+
+ Data = 0;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ EFI_AHCI_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Write AHCI Operation register.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The operation register offset.
+ @param Data The data used to write down.
+
+**/
+VOID
+EFIAPI
+AhciWriteReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (PciIo != NULL);
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ EFI_AHCI_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ return ;
+}
+
+/**
+ Do AND operation with the value of AHCI Operation register.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The operation register offset.
+ @param AndData The data used to do AND operation.
+
+**/
+VOID
+EFIAPI
+AhciAndReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT32 AndData
+ )
+{
+ UINT32 Data;
+
+ ASSERT (PciIo != NULL);
+
+ Data = AhciReadReg (PciIo, Offset);
+
+ Data &= AndData;
+
+ AhciWriteReg (PciIo, Offset, Data);
+}
+
+/**
+ Do OR operation with the value of AHCI Operation register.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The operation register offset.
+ @param OrData The data used to do OR operation.
+
+**/
+VOID
+EFIAPI
+AhciOrReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT32 OrData
+ )
+{
+ UINT32 Data;
+
+ ASSERT (PciIo != NULL);
+
+ Data = AhciReadReg (PciIo, Offset);
+
+ Data |= OrData;
+
+ AhciWriteReg (PciIo, Offset, Data);
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The MMIO address to test.
+ @param MaskValue The mask value of memory.
+ @param TestValue The test value of memory.
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The MMIO setting is time out.
+ @retval EFI_SUCCESS The MMIO is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Offset,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+
+ do {
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Wait for the value of the specified system memory set to the test value.
+
+ @param Address The system memory address to test.
+ @param MaskValue The mask value of memory.
+ @param TestValue The test value of memory.
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMemSet (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+
+ do {
+ //
+ // Access system memory to see if the value is the tested one.
+ //
+ // The system memory pointed by Address will be updated by the
+ // SATA Host Controller, "volatile" is introduced to prevent
+ // compiler from optimizing the access to the memory address
+ // to only read once.
+ //
+ Value = *(volatile UINT32 *) (UINTN) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check the memory status to the test value.
+
+ @param[in] Address The memory address to test.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in, out] Task Optional. Pointer to the ATA_NONBLOCK_TASK used by
+ non-blocking mode. If NULL, then just try once.
+
+ @retval EFI_NOTREADY The memory is not set.
+ @retval EFI_TIMEOUT The memory setting retry times out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciCheckMemSet (
+ IN UINTN Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN OUT ATA_NONBLOCK_TASK *Task
+ )
+{
+ UINT32 Value;
+
+ if (Task != NULL) {
+ Task->RetryTimes--;
+ }
+
+ Value = *(volatile UINT32 *) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Task != NULL) && !Task->InfiniteWait && (Task->RetryTimes == 0)) {
+ return EFI_TIMEOUT;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+
+/**
+
+ Clear the port interrupt and error status. It will also clear
+ HBA interrupt status.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+
+**/
+VOID
+EFIAPI
+AhciClearPortStatus (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port
+ )
+{
+ UINT32 Offset;
+
+ //
+ // Clear any error status
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
+
+ //
+ // Clear any port interrupt status
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
+ AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
+
+ //
+ // Clear any HBA interrupt status
+ //
+ AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));
+}
+
+/**
+ This function is used to dump the Status Registers and if there is ERR bit set
+ in the Status Register, the Error Register's value is also be dumped.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+AhciDumpPortStatus (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ UINTN Offset;
+ UINT32 Data;
+ UINTN FisBaseAddr;
+ EFI_STATUS Status;
+
+ ASSERT (PciIo != NULL);
+
+ if (AtaStatusBlock != NULL) {
+ ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If D2H FIS is received, update StatusBlock with its content.
+ //
+ CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));
+ } else {
+ //
+ // If D2H FIS is not received, only update Status & Error field through PxTFD
+ // as there is no other way to get the content of the Shadow Register Block.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ Data = AhciReadReg (PciIo, (UINT32)Offset);
+
+ AtaStatusBlock->AtaStatus = (UINT8)Data;
+ if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {
+ AtaStatusBlock->AtaError = (UINT8)(Data >> 8);
+ }
+ }
+ }
+}
+
+
+/**
+ Enable the FIS running for giving port.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The FIS enable setting fails.
+ @retval EFI_TIMEOUT The FIS enable setting is time out.
+ @retval EFI_SUCCESS The FIS enable successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciEnableFisReceive (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable the FIS running for giving port.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The FIS disable setting fails.
+ @retval EFI_TIMEOUT The FIS disable setting is time out.
+ @retval EFI_UNSUPPORTED The port is in running state.
+ @retval EFI_SUCCESS The FIS disable successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciDisableFisReceive (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (PciIo, Offset);
+
+ //
+ // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
+ //
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check if the Fis receive DMA engine for the port is running.
+ //
+ if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
+ return EFI_SUCCESS;
+ }
+
+ AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
+
+ return AhciWaitMmioSet (
+ PciIo,
+ Offset,
+ EFI_AHCI_PORT_CMD_FR,
+ 0,
+ Timeout
+ );
+}
+
+
+
+/**
+ Build the command list, command table and prepare the fis receiver.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The timeout value of stop.
+ @param CommandFis The control fis will be used for the transfer.
+ @param CommandList The command list will be used for the transfer.
+ @param AtapiCommand The atapi command will be used for the transfer.
+ @param AtapiCommandLength The length of the atapi command.
+ @param CommandSlotNumber The command slot will be used for the transfer.
+ @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
+ @param DataLength The data count to be transferred.
+
+**/
+VOID
+EFIAPI
+AhciBuildCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_COMMAND_FIS *CommandFis,
+ IN EFI_AHCI_COMMAND_LIST *CommandList,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN UINT8 CommandSlotNumber,
+ IN OUT VOID *DataPhysicalAddr,
+ IN UINT32 DataLength
+ )
+{
+ UINT64 BaseAddr;
+ UINT32 PrdtNumber;
+ UINT32 PrdtIndex;
+ UINTN RemainedData;
+ UINTN MemAddr;
+ DATA_64 Data64;
+ UINT32 Offset;
+
+ //
+ // Filling the PRDT
+ //
+ PrdtNumber = (UINT32)DivU64x32 (((UINT64)DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1), EFI_AHCI_MAX_DATA_PER_PRDT);
+
+ //
+ // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
+ // It also limits that the maximum amount of the PRDT entry in the command table
+ // is 65535.
+ //
+ ASSERT (PrdtNumber <= 65535);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
+
+ BaseAddr = Data64.Uint64;
+
+ ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
+
+ ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
+
+ CommandFis->AhciCFisPmNum = PortMultiplier;
+
+ CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ if (AtapiCommand != NULL) {
+ CopyMem (
+ &AhciRegisters->AhciCommandTable->AtapiCmd,
+ AtapiCommand,
+ AtapiCommandLength
+ );
+
+ CommandList->AhciCmdA = 1;
+ CommandList->AhciCmdP = 1;
+
+ AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
+ } else {
+ AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
+ }
+
+ RemainedData = (UINTN) DataLength;
+ MemAddr = (UINTN) DataPhysicalAddr;
+ CommandList->AhciCmdPrdtl = PrdtNumber;
+
+ for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
+ if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {
+ AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
+ } else {
+ AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;
+ }
+
+ Data64.Uint64 = (UINT64)MemAddr;
+ AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;
+ RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;
+ MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;
+ }
+
+ //
+ // Set the last PRDT to Interrupt On Complete
+ //
+ if (PrdtNumber > 0) {
+ AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;
+ }
+
+ CopyMem (
+ (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
+ CommandList,
+ sizeof (EFI_AHCI_COMMAND_LIST)
+ );
+
+ Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;
+
+}
+
+/**
+ Build a command FIS.
+
+ @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
+ @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
+
+**/
+VOID
+EFIAPI
+AhciBuildCommandFis (
+ IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
+ )
+{
+ ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
+ //
+ // Indicator it's a command
+ //
+ CmdFis->AhciCFisCmdInd = 0x1;
+ CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
+
+ CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
+ CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
+
+ CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
+ CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;
+
+ CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
+ CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
+
+ CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
+ CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
+
+ CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
+ CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
+
+ CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
+}
+
+/**
+ Start a PIO data transfer on specific port.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPioTransfer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ UINTN FisBaseAddr;
+ UINTN Offset;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ UINTN MapLength;
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ UINT64 Delay;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+ UINT32 PortTfd;
+ UINT32 PrdCount;
+ BOOLEAN InfiniteWait;
+ BOOLEAN PioFisReceived;
+ BOOLEAN D2hFisReceived;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ if (Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
+
+ //
+ // construct command list and command table with pci bus address
+ //
+ MapLength = DataCount;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ MemoryAddr,
+ &MapLength,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (DataCount != MapLength)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+ CmdList.AhciCmdW = Read ? 0 : 1;
+
+ AhciBuildCommand (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ &CFis,
+ &CmdList,
+ AtapiCommand,
+ AtapiCommandLength,
+ 0,
+ (VOID *)(UINTN)PhyAddr,
+ DataCount
+ );
+
+ Status = AhciStartCommand (
+ PciIo,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Check the status and wait the driver sending data
+ //
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+
+ if (Read && (AtapiCommand == 0)) {
+ //
+ // Wait device sends the PIO setup fis before data transfer
+ //
+ Status = EFI_TIMEOUT;
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+ do {
+ PioFisReceived = FALSE;
+ D2hFisReceived = FALSE;
+ Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL);
+ if (!EFI_ERROR (Status)) {
+ PioFisReceived = TRUE;
+ }
+ //
+ // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
+ // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
+ // after the transaction is finished successfully.
+ // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
+ // By this way, we can know if there is a real error happened.
+ //
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);
+ if (!EFI_ERROR (Status)) {
+ D2hFisReceived = TRUE;
+ }
+
+ if (PioFisReceived || D2hFisReceived) {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ //
+ // PxTFD will be updated if there is a D2H or SetupFIS received.
+ //
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
+ if (PrdCount == DataCount) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ if (Delay == 0) {
+ Status = EFI_TIMEOUT;
+ }
+ } while (InfiniteWait || (Delay > 0));
+ } else {
+ //
+ // Wait for D2H Fis is received
+ //
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+Exit:
+ AhciStopCommand (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ PciIo->Unmap (
+ PciIo,
+ Map
+ );
+
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
+
+ return Status;
+}
+
+/**
+ Start a DMA data transfer on specific port
+
+ @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The DMA data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciDmaTransfer (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ UINTN MapLength;
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+ UINTN FisBaseAddr;
+ UINT32 PortTfd;
+
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_TPL OldTpl;
+
+ Map = NULL;
+ PciIo = Instance->PciIo;
+
+ if (PciIo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Before starting the Blocking BlockIO operation, push to finish all non-blocking
+ // BlockIO tasks.
+ // Delay 100us to simulate the blocking time out checking.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {
+ AsyncNonBlockingTransferRoutine (NULL, Instance);
+ //
+ // Stall for 100us.
+ //
+ MicroSecondDelay (100);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {
+ //
+ // Mark the Task to indicate that it has been started.
+ //
+ if (Task != NULL) {
+ Task->IsStart = TRUE;
+ }
+ if (Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
+
+ //
+ // Construct command list and command table with pci bus address.
+ //
+ MapLength = DataCount;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ MemoryAddr,
+ &MapLength,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (DataCount != MapLength)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Task != NULL) {
+ Task->Map = Map;
+ }
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+ CmdList.AhciCmdW = Read ? 0 : 1;
+
+ AhciBuildCommand (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ &CFis,
+ &CmdList,
+ AtapiCommand,
+ AtapiCommandLength,
+ 0,
+ (VOID *)(UINTN)PhyAddr,
+ DataCount
+ );
+
+ Status = AhciStartCommand (
+ PciIo,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+
+ //
+ // Wait for command complete
+ //
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ if (Task != NULL) {
+ //
+ // For Non-blocking
+ //
+ Status = AhciCheckMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Task
+ );
+ } else {
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ //
+ // For Blocking mode, the command should be stopped, the Fis should be disabled
+ // and the PciIo should be unmapped.
+ // For non-blocking mode, only when a error is happened (if the return status is
+ // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
+ // context cleanup, then set the packet's Asb status.
+ //
+ if (Task == NULL ||
+ ((Task != NULL) && (Status != EFI_NOT_READY))
+ ) {
+ AhciStopCommand (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ PciIo->Unmap (
+ PciIo,
+ (Task != NULL) ? Task->Map : Map
+ );
+
+ if (Task != NULL) {
+ Task->Packet->Asb->AtaStatus = 0x01;
+ }
+ }
+
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
+ return Status;
+}
+
+/**
+ Start a non data transfer on specific port.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciNonDataTransfer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ UINTN FisBaseAddr;
+ UINTN Offset;
+ UINT32 PortTfd;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+
+ AhciBuildCommand (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ &CFis,
+ &CmdList,
+ AtapiCommand,
+ AtapiCommandLength,
+ 0,
+ NULL,
+ 0
+ );
+
+ Status = AhciStartCommand (
+ PciIo,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Wait device sends the Response Fis
+ //
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ AhciStopCommand (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
+
+ return Status;
+}
+
+/**
+ Stop command running for giving port
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param Timeout The timeout value of stop, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command stop successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStopCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (PciIo, Offset);
+
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
+ AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
+ }
+
+ return AhciWaitMmioSet (
+ PciIo,
+ Offset,
+ EFI_AHCI_PORT_CMD_CR,
+ 0,
+ Timeout
+ );
+}
+
+/**
+ Start command for give slot on specific port.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param CommandSlot The number of Command Slot.
+ @param Timeout The timeout value of start, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command start successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStartCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT8 CommandSlot,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 CmdSlotBit;
+ EFI_STATUS Status;
+ UINT32 PortStatus;
+ UINT32 StartCmd;
+ UINT32 PortTfd;
+ UINT32 Offset;
+ UINT32 Capability;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
+
+ CmdSlotBit = (UINT32) (1 << CommandSlot);
+
+ AhciClearPortStatus (
+ PciIo,
+ Port
+ );
+
+ Status = AhciEnableFisReceive (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ PortStatus = AhciReadReg (PciIo, Offset);
+
+ StartCmd = 0;
+ if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
+ StartCmd = AhciReadReg (PciIo, Offset);
+ StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
+ StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, Offset);
+
+ if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
+ if ((Capability & BIT24) != 0) {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);
+
+ AhciWaitMmioSet (
+ PciIo,
+ Offset,
+ EFI_AHCI_PORT_CMD_CLO,
+ 0,
+ Timeout
+ );
+ }
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
+
+ //
+ // Setting the command
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
+ AhciAndReg (PciIo, Offset, 0);
+ AhciOrReg (PciIo, Offset, CmdSlotBit);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Do AHCI HBA reset.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Timeout The timeout value of reset, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
+ @retval EFI_TIMEOUT The reset operation is time out.
+ @retval EFI_SUCCESS AHCI controller is reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciReset (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT32 Value;
+
+ //
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.
+ //
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
+
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
+
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+
+ do {
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
+
+ if ((Value & EFI_AHCI_GHC_RESET) == 0) {
+ break;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
+ @retval Others Fail to get return status data.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaSmartReturnStatusCheck (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+ UINTN FisBaseAddr;
+ UINT32 Value;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ //
+ // Send S.M.A.R.T Read Return Status command to device
+ //
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+ );
+
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+
+ Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);
+
+ if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {
+ LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];
+ LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];
+
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+ //
+ // The threshold exceeded condition is not detected by the device
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
+ 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
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable SMART command of the disk if supported.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+AhciAtaSmartSupport (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_IDENTIFY_DATA *IdentifyData,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ //
+ // Detect if the device supports S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+ //
+ // S.M.A.R.T is not supported by the device
+ //
+ DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
+ Port, PortMultiplier));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+ );
+ } else {
+ //
+ // Check if the feature is enabled. If not, then enable S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)
+ );
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ //
+ // Send S.M.A.R.T Enable command to device
+ //
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Send S.M.A.R.T AutoSave command to device
+ //
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = 0xD2;
+ AtaCommandBlock.AtaSectorCount = 0xF1;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = AhciAtaSmartReturnStatusCheck (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ AtaStatusBlock
+ );
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
+ Port, PortMultiplier));
+ }
+
+ return ;
+}
+
+/**
+ Send Buffer cmd to specific device.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param Buffer The data buffer to store IDENTIFY PACKET data.
+
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+ @retval EFI_SUCCESS The cmd executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciIdentify (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT EFI_IDENTIFY_DATA *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+
+ if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ AtaCommandBlock.AtaSectorCount = 1;
+
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ NULL,
+ 0,
+ TRUE,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Send Buffer cmd to specific device.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param Buffer The data buffer to store IDENTIFY PACKET data.
+
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+ @retval EFI_SUCCESS The cmd executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciIdentifyPacket (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT EFI_IDENTIFY_DATA *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+
+ if (PciIo == NULL || AhciRegisters == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;
+ AtaCommandBlock.AtaSectorCount = 1;
+
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ NULL,
+ 0,
+ TRUE,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Send SET FEATURE cmd on specific device.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param Feature The data to send Feature register.
+ @param FeatureSpecificData The specific data for SET FEATURE cmd.
+ @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+ @retval EFI_SUCCESS The cmd executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciDeviceSetFeature (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN UINT16 Feature,
+ IN UINT32 FeatureSpecificData,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;
+ AtaCommandBlock.AtaFeatures = (UINT8) Feature;
+ AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);
+ AtaCommandBlock.AtaSectorCount = (UINT8) FeatureSpecificData;
+ AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);
+ AtaCommandBlock.AtaCylinderLow = (UINT8) (FeatureSpecificData >> 16);
+ AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);
+
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Timeout,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Protocol.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The number of port multiplier.
+ @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
+
+ @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
+EFIAPI
+AhciPacketCommandExecute (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ VOID *Buffer;
+ UINT32 Length;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+ BOOLEAN Read;
+
+ if (Packet == NULL || Packet->Cdb == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+ AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;
+ //
+ // No OVL; No DMA
+ //
+ AtaCommandBlock.AtaFeatures = 0x00;
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
+ // determine how many data should be transferred.
+ //
+ AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);
+ AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);
+
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ Buffer = Packet->InDataBuffer;
+ Length = Packet->InTransferLength;
+ Read = TRUE;
+ } else {
+ Buffer = Packet->OutDataBuffer;
+ Length = Packet->OutTransferLength;
+ Read = FALSE;
+ }
+
+ if (Length == 0) {
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ Packet->Cdb,
+ Packet->CdbLength,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Packet->Timeout,
+ NULL
+ );
+ } else {
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ Packet->Cdb,
+ Packet->CdbLength,
+ Read,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ Length,
+ Packet->Timeout,
+ NULL
+ );
+ }
+ return Status;
+}
+
+/**
+ Allocate transfer-related data struct which is used at AHCI mode.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciCreateTransferDescriptor (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN OUT EFI_AHCI_REGISTERS *AhciRegisters
+ )
+{
+ EFI_STATUS Status;
+ UINTN Bytes;
+ VOID *Buffer;
+
+ UINT32 Capability;
+ UINT32 PortImplementBitMap;
+ UINT8 MaxPortNumber;
+ UINT8 MaxCommandSlotNumber;
+ BOOLEAN Support64Bit;
+ UINT64 MaxReceiveFisSize;
+ UINT64 MaxCommandListSize;
+ UINT64 MaxCommandTableSize;
+ EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;
+ EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;
+ EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;
+
+ Buffer = NULL;
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
+ //
+ // Get the number of command slots per port supported by this HBA.
+ //
+ MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
+ Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);
+
+ PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
+ //
+ // Get the highest bit of implemented ports which decides how many bytes are allocated for received FIS.
+ //
+ MaxPortNumber = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);
+ if (MaxPortNumber == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
+ &Buffer,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);
+
+ AhciRegisters->AhciRFis = Buffer;
+ AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;
+ Bytes = (UINTN)MaxReceiveFisSize;
+
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buffer,
+ &Bytes,
+ &AhciRFisPciAddr,
+ &AhciRegisters->MapRFis
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {
+ //
+ // Map error or unable to map the whole RFis buffer into a contiguous region.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error6;
+ }
+
+ if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {
+ //
+ // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Error5;
+ }
+ AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;
+
+ //
+ // Allocate memory for command list
+ // Note that the implementation is a single task model which only use a command list for all ports.
+ //
+ Buffer = NULL;
+ MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
+ &Buffer,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free mapped resource.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error5;
+ }
+
+ ZeroMem (Buffer, (UINTN)MaxCommandListSize);
+
+ AhciRegisters->AhciCmdList = Buffer;
+ AhciRegisters->MaxCommandListSize = MaxCommandListSize;
+ Bytes = (UINTN)MaxCommandListSize;
+
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buffer,
+ &Bytes,
+ &AhciCmdListPciAddr,
+ &AhciRegisters->MapCmdList
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {
+ //
+ // Map error or unable to map the whole cmd list buffer into a contiguous region.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error4;
+ }
+
+ if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {
+ //
+ // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Error3;
+ }
+ AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;
+
+ //
+ // Allocate memory for command table
+ // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
+ //
+ Buffer = NULL;
+ MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
+ &Buffer,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free mapped resource.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error3;
+ }
+
+ ZeroMem (Buffer, (UINTN)MaxCommandTableSize);
+
+ AhciRegisters->AhciCommandTable = Buffer;
+ AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;
+ Bytes = (UINTN)MaxCommandTableSize;
+
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buffer,
+ &Bytes,
+ &AhciCommandTablePciAddr,
+ &AhciRegisters->MapCommandTable
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {
+ //
+ // Map error or unable to map the whole cmd list buffer into a contiguous region.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {
+ //
+ // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Error1;
+ }
+ AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;
+
+ return EFI_SUCCESS;
+ //
+ // Map error or unable to map the whole CmdList buffer into a contiguous region.
+ //
+Error1:
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapCommandTable
+ );
+Error2:
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
+ AhciRegisters->AhciCommandTable
+ );
+Error3:
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapCmdList
+ );
+Error4:
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
+ AhciRegisters->AhciCmdList
+ );
+Error5:
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapRFis
+ );
+Error6:
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
+ AhciRegisters->AhciRFis
+ );
+
+ return Status;
+}
+
+/**
+ Read logs from SATA device.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The multiplier of port.
+ @param Buffer The data buffer to store SATA logs.
+ @param LogNumber The address of the log.
+ @param PageNumber The page number of the log.
+
+ @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.
+ @retval others Return status of AhciPioTransfer().
+**/
+EFI_STATUS
+AhciReadLogExt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT UINT8 *Buffer,
+ IN UINT8 LogNumber,
+ IN UINT8 PageNumber
+ )
+{
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+
+ if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ///
+ /// Read log from device
+ ///
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+ ZeroMem (Buffer, 512);
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_READ_LOG_EXT;
+ AtaCommandBlock.AtaSectorCount = 1;
+ AtaCommandBlock.AtaSectorNumber = LogNumber;
+ AtaCommandBlock.AtaCylinderLow = PageNumber;
+
+ return AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ NULL,
+ 0,
+ TRUE,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ 512,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+}
+
+/**
+ Enable DEVSLP of the disk if supported.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The multiplier of port.
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
+
+ @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.
+ @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.
+**/
+EFI_STATUS
+AhciEnableDevSlp (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_IDENTIFY_DATA *IdentifyData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Offset;
+ UINT32 Capability2;
+ UINT8 LogData[512];
+ DEVSLP_TIMING_VARIABLES DevSlpTiming;
+ UINT32 PortCmd;
+ UINT32 PortDevSlp;
+
+ if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do not enable DevSlp if DevSlp is not supported.
+ //
+ Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);
+ DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));
+ if ((Capability2 & AHCI_CAP2_SDS) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Do not enable DevSlp if DevSlp is not present
+ // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;
+ PortCmd = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);
+ PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);
+ DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));
+ if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||
+ ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Do not enable DevSlp if the device doesn't support DevSlp
+ //
+ DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",
+ IdentifyData->AtaData.reserved_77,
+ IdentifyData->AtaData.serial_ata_features_supported, IdentifyData->AtaData.serial_ata_features_enabled));
+ if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {
+ DEBUG ((DEBUG_INFO, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",
+ Port, PortMultiplier));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Enable DevSlp when it is not enabled.
+ //
+ if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {
+ Status = AhciDeviceSetFeature (
+ PciIo, AhciRegisters, Port, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE, 0x09, ATA_ATAPI_TIMEOUT
+ );
+ DEBUG ((DEBUG_INFO, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",
+ Port, PortMultiplier, Status));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = AhciReadLogExt(PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);
+
+ //
+ // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.
+ //
+ AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);
+
+ //
+ // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.
+ //
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);
+ DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));
+ if (EFI_ERROR (Status)) {
+ //
+ // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails
+ //
+ ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));
+ } else {
+ CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));
+ DEBUG ((DEBUG_INFO, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",
+ DevSlpTiming.Supported, DevSlpTiming.Deto, DevSlpTiming.Madt));
+ }
+
+ //
+ // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.
+ //
+ if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {
+ DevSlpTiming.Deto = 20;
+ }
+
+ //
+ // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.
+ //
+ if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {
+ DevSlpTiming.Madt = 10;
+ }
+
+ PortDevSlp |= DevSlpTiming.Deto << 2;
+ PortDevSlp |= DevSlpTiming.Madt << 10;
+ AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);
+
+ if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {
+ if ((Capability2 & AHCI_CAP2_SADM) != 0) {
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;
+ PortDevSlp |= (625 << 15);
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);
+
+ PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);
+ }
+ }
+
+
+ AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);
+
+ DEBUG ((DEBUG_INFO, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",
+ Port, PortMultiplier, PortCmd, PortDevSlp));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Spin-up disk if IDD was incomplete or PUIS feature is enabled
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The multiplier of port.
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
+
+**/
+EFI_STATUS
+AhciSpinUpDisk (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT EFI_IDENTIFY_DATA *IdentifyData
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;
+ UINT8 Buffer[512];
+
+ if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {
+ //
+ // Use SET_FEATURE subcommand to spin up the device.
+ //
+ Status = AhciDeviceSetFeature (
+ PciIo, AhciRegisters, Port, PortMultiplier,
+ ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP, 0x00, ATA_SPINUP_TIMEOUT
+ );
+ DEBUG ((DEBUG_INFO, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",
+ Port, PortMultiplier, Status));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);
+
+ //
+ // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported
+ //
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+ //
+ // Perform READ SECTORS PIO Data-In command to Read LBA 0
+ //
+ AtaCommandBlock.AtaCommand = ATA_CMD_READ_SECTORS;
+ AtaCommandBlock.AtaSectorCount = 0x1;
+
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ NULL,
+ 0,
+ TRUE,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ &Buffer,
+ sizeof (Buffer),
+ ATA_SPINUP_TIMEOUT,
+ NULL
+ );
+ DEBUG ((DEBUG_INFO, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",
+ Port, PortMultiplier, Status));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Read the complete IDENTIFY DEVICE data.
+ //
+ ZeroMem (IdentifyData, sizeof (*IdentifyData));
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",
+ Port, PortMultiplier, Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
+ IdentifyData->AtaData.config, IdentifyData->AtaData.specific_config,
+ IdentifyData->AtaData.command_set_supported_83, IdentifyData->AtaData.command_set_feature_enb_86));
+ //
+ // Check if IDD is incomplete
+ //
+ if ((IdentifyData->AtaData.config & BIT2) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable/disable/skip PUIS of the disk according to policy.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The multiplier of port.
+
+**/
+EFI_STATUS
+AhciPuisEnable (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ if (mAtaAtapiPolicy->PuisEnable == 0) {
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_DISABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);
+ } else if (mAtaAtapiPolicy->PuisEnable == 1) {
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_ENABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);
+ }
+ DEBUG ((DEBUG_INFO, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",
+ (mAtaAtapiPolicy->PuisEnable == 0) ? "Disable" : (
+ (mAtaAtapiPolicy->PuisEnable == 1) ? "Enable" : "Skip"
+ ), Port, PortMultiplier, Status));
+ return Status;
+}
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciModeInitialization (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ UINT32 Capability;
+ UINT8 MaxPortNumber;
+ UINT32 PortImplementBitMap;
+
+ EFI_AHCI_REGISTERS *AhciRegisters;
+
+ UINT8 Port;
+ DATA_64 Data64;
+ UINT32 Offset;
+ UINT32 Data;
+ EFI_IDENTIFY_DATA Buffer;
+ EFI_ATA_DEVICE_TYPE DeviceType;
+ EFI_ATA_COLLECTIVE_MODE *SupportedModes;
+ EFI_ATA_TRANSFER_MODE TransferMode;
+ UINT32 PhyDetectDelay;
+ UINT32 Value;
+
+ if (Instance == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PciIo = Instance->PciIo;
+ IdeInit = Instance->IdeControllerInit;
+
+ Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.
+ //
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
+
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if ((Capability & EFI_AHCI_CAP_S64A) != 0) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN,
+ "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
+ Status));
+ }
+ }
+
+ //
+ // Get the number of command slots per port supported by this HBA.
+ //
+ MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
+
+ //
+ // Get the bit map of those ports exposed by this HBA.
+ // It indicates which ports that the HBA supports are available for software to use.
+ //
+ PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
+
+ AhciRegisters = &Instance->AhciRegisters;
+ Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {
+ if ((PortImplementBitMap & (((UINT32)BIT0) << Port)) != 0) {
+ //
+ // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
+ //
+ if ((MaxPortNumber--) == 0) {
+ //
+ // Should never be here.
+ //
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+ }
+
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
+
+ //
+ // Initialize FIS Base Address Register and Command List Base Address Register for use.
+ //
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (PciIo, Offset);
+ if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);
+ }
+
+ if ((Capability & EFI_AHCI_CAP_SSS) != 0) {
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
+ }
+
+ //
+ // Disable aggressive power management.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
+ //
+ // Disable the reporting of the corresponding interrupt to system software.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
+ AhciAndReg (PciIo, Offset, 0);
+
+ //
+ // Now inform the IDE Controller Init Module.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
+
+ //
+ // Enable FIS Receive DMA engine for the first D2H FIS.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
+
+ //
+ // Wait for the Phy to detect the presence of a device.
+ //
+ PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
+ do {
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
+ if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {
+ break;
+ }
+
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ //
+ // No device detected at this port.
+ // Clear PxCMD.SUD for those ports at which there are no device present.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));
+ continue;
+ }
+
+ //
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+ //
+ PhyDetectDelay = 16 * 1000;
+ do {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ if (AhciReadReg(PciIo, Offset) != 0) {
+ AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));
+ }
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;
+ if (Data == 0) {
+ break;
+ }
+
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ DEBUG ((EFI_D_ERROR, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port, Data));
+ continue;
+ }
+
+ //
+ // When the first D2H register FIS is received, the content of PxSIG register is updated.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
+ Status = AhciWaitMmioSet (
+ PciIo,
+ Offset,
+ 0x0000FFFF,
+ 0x00000101,
+ EFI_TIMER_PERIOD_SECONDS(16)
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Data = AhciReadReg (PciIo, Offset);
+ if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
+ Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ DeviceType = EfiIdeCdrom;
+ } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
+ continue;
+ }
+
+ DEBUG ((
+ DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
+ Buffer.AtaData.config, Buffer.AtaData.specific_config,
+ Buffer.AtaData.command_set_supported_83, Buffer.AtaData.command_set_feature_enb_86
+ ));
+ if ((Buffer.AtaData.config & BIT2) != 0) {
+ //
+ // SpinUp disk if device reported incomplete IDENTIFY DEVICE.
+ //
+ Status = AhciSpinUpDisk (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0,
+ &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));
+ continue;
+ }
+ }
+
+ DeviceType = EfiIdeHarddisk;
+ } else {
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "port [%d] port multitplier [%d] has a [%a]\n",
+ Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
+
+ //
+ // If the device is a hard disk, then try to enable S.M.A.R.T feature
+ //
+ if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {
+ AhciAtaSmartSupport (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0,
+ &Buffer,
+ NULL
+ );
+ }
+
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
+
+ //
+ // Now start to config ide device parameter and transfer mode.
+ //
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ Port,
+ 0,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can'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 = EFI_ATA_MODE_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ }
+
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Found a ATA or ATAPI device, add it into the device list.
+ //
+ CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);
+ if (DeviceType == EfiIdeHarddisk) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
+ AhciEnableDevSlp (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0,
+ &Buffer
+ );
+ }
+
+ //
+ // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).
+ //
+ if ((Buffer.AtaData.command_set_supported_83 & BIT5) != 0) {
+ Status = AhciPuisEnable (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "PUIS enable/disable failed, Status = %r\n", Status));
+ continue;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
new file mode 100644
index 000000000..786413930
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
@@ -0,0 +1,384 @@
+/** @file
+ Header file for AHCI mode of ATA host controller.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __ATA_HC_AHCI_MODE_H__
+#define __ATA_HC_AHCI_MODE_H__
+
+#define EFI_AHCI_BAR_INDEX 0x05
+
+#define EFI_AHCI_CAPABILITY_OFFSET 0x0000
+#define EFI_AHCI_CAP_SAM BIT18
+#define EFI_AHCI_CAP_SSS BIT27
+#define EFI_AHCI_CAP_S64A BIT31
+#define EFI_AHCI_GHC_OFFSET 0x0004
+#define EFI_AHCI_GHC_RESET BIT0
+#define EFI_AHCI_GHC_IE BIT1
+#define EFI_AHCI_GHC_ENABLE BIT31
+#define EFI_AHCI_IS_OFFSET 0x0008
+#define EFI_AHCI_PI_OFFSET 0x000C
+
+#define EFI_AHCI_MAX_PORTS 32
+
+#define AHCI_CAPABILITY2_OFFSET 0x0024
+#define AHCI_CAP2_SDS BIT3
+#define AHCI_CAP2_SADM BIT4
+
+typedef struct {
+ UINT32 Lower32;
+ UINT32 Upper32;
+} DATA_32;
+
+typedef union {
+ DATA_32 Uint32;
+ UINT64 Uint64;
+} DATA_64;
+
+//
+// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
+// Add a bit of margin for robustness.
+//
+#define EFI_AHCI_BUS_PHY_DETECT_TIMEOUT 15
+//
+// Refer SATA1.0a spec, the FIS enable time should be less than 500ms.
+//
+#define EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT EFI_TIMER_PERIOD_MILLISECONDS(500)
+//
+// Refer SATA1.0a spec, the bus reset time should be less than 1s.
+//
+#define EFI_AHCI_BUS_RESET_TIMEOUT EFI_TIMER_PERIOD_SECONDS(1)
+
+#define EFI_AHCI_ATAPI_DEVICE_SIG 0xEB140000
+#define EFI_AHCI_ATA_DEVICE_SIG 0x00000000
+#define EFI_AHCI_PORT_MULTIPLIER_SIG 0x96690000
+#define EFI_AHCI_ATAPI_SIG_MASK 0xFFFF0000
+
+//
+// Each PRDT entry can point to a memory block up to 4M byte
+//
+#define EFI_AHCI_MAX_DATA_PER_PRDT 0x400000
+
+#define EFI_AHCI_FIS_REGISTER_H2D 0x27 //Register FIS - Host to Device
+#define EFI_AHCI_FIS_REGISTER_H2D_LENGTH 20
+#define EFI_AHCI_FIS_REGISTER_D2H 0x34 //Register FIS - Device to Host
+#define EFI_AHCI_FIS_REGISTER_D2H_LENGTH 20
+#define EFI_AHCI_FIS_DMA_ACTIVATE 0x39 //DMA Activate FIS - Device to Host
+#define EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH 4
+#define EFI_AHCI_FIS_DMA_SETUP 0x41 //DMA Setup FIS - Bi-directional
+#define EFI_AHCI_FIS_DMA_SETUP_LENGTH 28
+#define EFI_AHCI_FIS_DATA 0x46 //Data FIS - Bi-directional
+#define EFI_AHCI_FIS_BIST 0x58 //BIST Activate FIS - Bi-directional
+#define EFI_AHCI_FIS_BIST_LENGTH 12
+#define EFI_AHCI_FIS_PIO_SETUP 0x5F //PIO Setup FIS - Device to Host
+#define EFI_AHCI_FIS_PIO_SETUP_LENGTH 20
+#define EFI_AHCI_FIS_SET_DEVICE 0xA1 //Set Device Bits FIS - Device to Host
+#define EFI_AHCI_FIS_SET_DEVICE_LENGTH 8
+
+#define EFI_AHCI_D2H_FIS_OFFSET 0x40
+#define EFI_AHCI_DMA_FIS_OFFSET 0x00
+#define EFI_AHCI_PIO_FIS_OFFSET 0x20
+#define EFI_AHCI_SDB_FIS_OFFSET 0x58
+#define EFI_AHCI_FIS_TYPE_MASK 0xFF
+#define EFI_AHCI_U_FIS_OFFSET 0x60
+
+//
+// Port register
+//
+#define EFI_AHCI_PORT_START 0x0100
+#define EFI_AHCI_PORT_REG_WIDTH 0x0080
+#define EFI_AHCI_PORT_CLB 0x0000
+#define EFI_AHCI_PORT_CLBU 0x0004
+#define EFI_AHCI_PORT_FB 0x0008
+#define EFI_AHCI_PORT_FBU 0x000C
+#define EFI_AHCI_PORT_IS 0x0010
+#define EFI_AHCI_PORT_IS_DHRS BIT0
+#define EFI_AHCI_PORT_IS_PSS BIT1
+#define EFI_AHCI_PORT_IS_SSS BIT2
+#define EFI_AHCI_PORT_IS_SDBS BIT3
+#define EFI_AHCI_PORT_IS_UFS BIT4
+#define EFI_AHCI_PORT_IS_DPS BIT5
+#define EFI_AHCI_PORT_IS_PCS BIT6
+#define EFI_AHCI_PORT_IS_DIS BIT7
+#define EFI_AHCI_PORT_IS_PRCS BIT22
+#define EFI_AHCI_PORT_IS_IPMS BIT23
+#define EFI_AHCI_PORT_IS_OFS BIT24
+#define EFI_AHCI_PORT_IS_INFS BIT26
+#define EFI_AHCI_PORT_IS_IFS BIT27
+#define EFI_AHCI_PORT_IS_HBDS BIT28
+#define EFI_AHCI_PORT_IS_HBFS BIT29
+#define EFI_AHCI_PORT_IS_TFES BIT30
+#define EFI_AHCI_PORT_IS_CPDS BIT31
+#define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF
+#define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F
+
+#define EFI_AHCI_PORT_IE 0x0014
+#define EFI_AHCI_PORT_CMD 0x0018
+#define EFI_AHCI_PORT_CMD_ST_MASK 0xFFFFFFFE
+#define EFI_AHCI_PORT_CMD_ST BIT0
+#define EFI_AHCI_PORT_CMD_SUD BIT1
+#define EFI_AHCI_PORT_CMD_POD BIT2
+#define EFI_AHCI_PORT_CMD_CLO BIT3
+#define EFI_AHCI_PORT_CMD_CR BIT15
+#define EFI_AHCI_PORT_CMD_FRE BIT4
+#define EFI_AHCI_PORT_CMD_FR BIT14
+#define EFI_AHCI_PORT_CMD_MASK ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)
+#define EFI_AHCI_PORT_CMD_PMA BIT17
+#define EFI_AHCI_PORT_CMD_HPCP BIT18
+#define EFI_AHCI_PORT_CMD_MPSP BIT19
+#define EFI_AHCI_PORT_CMD_CPD BIT20
+#define EFI_AHCI_PORT_CMD_ESP BIT21
+#define EFI_AHCI_PORT_CMD_ATAPI BIT24
+#define EFI_AHCI_PORT_CMD_DLAE BIT25
+#define EFI_AHCI_PORT_CMD_ALPE BIT26
+#define EFI_AHCI_PORT_CMD_ASP BIT27
+#define EFI_AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31)
+#define EFI_AHCI_PORT_CMD_ACTIVE (1 << 28 )
+#define EFI_AHCI_PORT_TFD 0x0020
+#define EFI_AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0)
+#define EFI_AHCI_PORT_TFD_BSY BIT7
+#define EFI_AHCI_PORT_TFD_DRQ BIT3
+#define EFI_AHCI_PORT_TFD_ERR BIT0
+#define EFI_AHCI_PORT_TFD_ERR_MASK 0x00FF00
+#define EFI_AHCI_PORT_SIG 0x0024
+#define EFI_AHCI_PORT_SSTS 0x0028
+#define EFI_AHCI_PORT_SSTS_DET_MASK 0x000F
+#define EFI_AHCI_PORT_SSTS_DET 0x0001
+#define EFI_AHCI_PORT_SSTS_DET_PCE 0x0003
+#define EFI_AHCI_PORT_SSTS_SPD_MASK 0x00F0
+#define EFI_AHCI_PORT_SCTL 0x002C
+#define EFI_AHCI_PORT_SCTL_DET_MASK 0x000F
+#define EFI_AHCI_PORT_SCTL_MASK (~EFI_AHCI_PORT_SCTL_DET_MASK)
+#define EFI_AHCI_PORT_SCTL_DET_INIT 0x0001
+#define EFI_AHCI_PORT_SCTL_DET_PHYCOMM 0x0003
+#define EFI_AHCI_PORT_SCTL_SPD_MASK 0x00F0
+#define EFI_AHCI_PORT_SCTL_IPM_MASK 0x0F00
+#define EFI_AHCI_PORT_SCTL_IPM_INIT 0x0300
+#define EFI_AHCI_PORT_SCTL_IPM_PSD 0x0100
+#define EFI_AHCI_PORT_SCTL_IPM_SSD 0x0200
+#define EFI_AHCI_PORT_SERR 0x0030
+#define EFI_AHCI_PORT_SERR_RDIE BIT0
+#define EFI_AHCI_PORT_SERR_RCE BIT1
+#define EFI_AHCI_PORT_SERR_TDIE BIT8
+#define EFI_AHCI_PORT_SERR_PCDIE BIT9
+#define EFI_AHCI_PORT_SERR_PE BIT10
+#define EFI_AHCI_PORT_SERR_IE BIT11
+#define EFI_AHCI_PORT_SERR_PRC BIT16
+#define EFI_AHCI_PORT_SERR_PIE BIT17
+#define EFI_AHCI_PORT_SERR_CW BIT18
+#define EFI_AHCI_PORT_SERR_BDE BIT19
+#define EFI_AHCI_PORT_SERR_DE BIT20
+#define EFI_AHCI_PORT_SERR_CRCE BIT21
+#define EFI_AHCI_PORT_SERR_HE BIT22
+#define EFI_AHCI_PORT_SERR_LSE BIT23
+#define EFI_AHCI_PORT_SERR_TSTE BIT24
+#define EFI_AHCI_PORT_SERR_UFT BIT25
+#define EFI_AHCI_PORT_SERR_EX BIT26
+#define EFI_AHCI_PORT_ERR_CLEAR 0xFFFFFFFF
+#define EFI_AHCI_PORT_SACT 0x0034
+#define EFI_AHCI_PORT_CI 0x0038
+#define EFI_AHCI_PORT_SNTF 0x003C
+#define AHCI_PORT_DEVSLP 0x0044
+#define AHCI_PORT_DEVSLP_ADSE BIT0
+#define AHCI_PORT_DEVSLP_DSP BIT1
+#define AHCI_PORT_DEVSLP_DETO_MASK 0x000003FC
+#define AHCI_PORT_DEVSLP_MDAT_MASK 0x00007C00
+#define AHCI_PORT_DEVSLP_DITO_MASK 0x01FF8000
+#define AHCI_PORT_DEVSLP_DM_MASK 0x1E000000
+
+#pragma pack(1)
+//
+// Command List structure includes total 32 entries.
+// The entry data structure is listed at the following.
+//
+typedef struct {
+ UINT32 AhciCmdCfl:5; //Command FIS Length
+ UINT32 AhciCmdA:1; //ATAPI
+ UINT32 AhciCmdW:1; //Write
+ UINT32 AhciCmdP:1; //Prefetchable
+ UINT32 AhciCmdR:1; //Reset
+ UINT32 AhciCmdB:1; //BIST
+ UINT32 AhciCmdC:1; //Clear Busy upon R_OK
+ UINT32 AhciCmdRsvd:1;
+ UINT32 AhciCmdPmp:4; //Port Multiplier Port
+ UINT32 AhciCmdPrdtl:16; //Physical Region Descriptor Table Length
+ UINT32 AhciCmdPrdbc; //Physical Region Descriptor Byte Count
+ UINT32 AhciCmdCtba; //Command Table Descriptor Base Address
+ UINT32 AhciCmdCtbau; //Command Table Descriptor Base Address Upper 32-BITs
+ UINT32 AhciCmdRsvd1[4];
+} EFI_AHCI_COMMAND_LIST;
+
+//
+// This is a software constructed FIS.
+// For data transfer operations, this is the H2D Register FIS format as
+// specified in the Serial ATA Revision 2.6 specification.
+//
+typedef struct {
+ UINT8 AhciCFisType;
+ UINT8 AhciCFisPmNum:4;
+ UINT8 AhciCFisRsvd:1;
+ UINT8 AhciCFisRsvd1:1;
+ UINT8 AhciCFisRsvd2:1;
+ UINT8 AhciCFisCmdInd:1;
+ UINT8 AhciCFisCmd;
+ UINT8 AhciCFisFeature;
+ UINT8 AhciCFisSecNum;
+ UINT8 AhciCFisClyLow;
+ UINT8 AhciCFisClyHigh;
+ UINT8 AhciCFisDevHead;
+ UINT8 AhciCFisSecNumExp;
+ UINT8 AhciCFisClyLowExp;
+ UINT8 AhciCFisClyHighExp;
+ UINT8 AhciCFisFeatureExp;
+ UINT8 AhciCFisSecCount;
+ UINT8 AhciCFisSecCountExp;
+ UINT8 AhciCFisRsvd3;
+ UINT8 AhciCFisControl;
+ UINT8 AhciCFisRsvd4[4];
+ UINT8 AhciCFisRsvd5[44];
+} EFI_AHCI_COMMAND_FIS;
+
+//
+// ACMD: ATAPI command (12 or 16 bytes)
+//
+typedef struct {
+ UINT8 AtapiCmd[0x10];
+} EFI_AHCI_ATAPI_COMMAND;
+
+//
+// Physical Region Descriptor Table includes up to 65535 entries
+// The entry data structure is listed at the following.
+// the actual entry number comes from the PRDTL field in the command
+// list entry for this command slot.
+//
+typedef struct {
+ UINT32 AhciPrdtDba; //Data Base Address
+ UINT32 AhciPrdtDbau; //Data Base Address Upper 32-BITs
+ UINT32 AhciPrdtRsvd;
+ UINT32 AhciPrdtDbc:22; //Data Byte Count
+ UINT32 AhciPrdtRsvd1:9;
+ UINT32 AhciPrdtIoc:1; //Interrupt on Completion
+} EFI_AHCI_COMMAND_PRDT;
+
+//
+// Command table data structure which is pointed to by the entry in the command list
+//
+typedef struct {
+ EFI_AHCI_COMMAND_FIS CommandFis; // A software constructed FIS.
+ EFI_AHCI_ATAPI_COMMAND AtapiCmd; // 12 or 16 bytes ATAPI cmd.
+ UINT8 Reserved[0x30];
+ EFI_AHCI_COMMAND_PRDT PrdtTable[65535]; // The scatter/gather list for data transfer
+} EFI_AHCI_COMMAND_TABLE;
+
+//
+// Received FIS structure
+//
+typedef struct {
+ UINT8 AhciDmaSetupFis[0x1C]; // Dma Setup Fis: offset 0x00
+ UINT8 AhciDmaSetupFisRsvd[0x04];
+ UINT8 AhciPioSetupFis[0x14]; // Pio Setup Fis: offset 0x20
+ UINT8 AhciPioSetupFisRsvd[0x0C];
+ UINT8 AhciD2HRegisterFis[0x14]; // D2H Register Fis: offset 0x40
+ UINT8 AhciD2HRegisterFisRsvd[0x04];
+ UINT64 AhciSetDeviceBitsFis; // Set Device Bits Fix: offset 0x58
+ UINT8 AhciUnknownFis[0x40]; // Unknown Fis: offset 0x60
+ UINT8 AhciUnknownFisRsvd[0x60];
+} EFI_AHCI_RECEIVED_FIS;
+
+typedef struct {
+ UINT8 Madt : 5;
+ UINT8 Reserved_5 : 3;
+ UINT8 Deto;
+ UINT16 Reserved_16;
+ UINT32 Reserved_32 : 31;
+ UINT32 Supported : 1;
+} DEVSLP_TIMING_VARIABLES;
+
+#pragma pack()
+
+typedef struct {
+ EFI_AHCI_RECEIVED_FIS *AhciRFis;
+ EFI_AHCI_COMMAND_LIST *AhciCmdList;
+ EFI_AHCI_COMMAND_TABLE *AhciCommandTable;
+ EFI_AHCI_RECEIVED_FIS *AhciRFisPciAddr;
+ EFI_AHCI_COMMAND_LIST *AhciCmdListPciAddr;
+ EFI_AHCI_COMMAND_TABLE *AhciCommandTablePciAddr;
+ UINT64 MaxCommandListSize;
+ UINT64 MaxCommandTableSize;
+ UINT64 MaxReceiveFisSize;
+ VOID *MapRFis;
+ VOID *MapCmdList;
+ VOID *MapCommandTable;
+} EFI_AHCI_REGISTERS;
+
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Protocol.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The number of port multiplier.
+ @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
+
+ @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
+EFIAPI
+AhciPacketCommandExecute (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ );
+
+/**
+ Start command for give slot on specific port.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param CommandSlot The number of CommandSlot.
+ @param Timeout The timeout value of start, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command start successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStartCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT8 CommandSlot,
+ IN UINT64 Timeout
+ );
+
+/**
+ Stop command running for giving port
+
+ @param PciIo The PCI IO protocol instance.
+ @param Port The number of port.
+ @param Timeout The timeout value of stop, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command stop successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStopCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
new file mode 100644
index 000000000..86fe9d954
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
@@ -0,0 +1,2649 @@
+/** @file
+ This file implements ATA_PASSTHRU_PROTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces
+ for managed ATA controllers.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtaAtapiPassThru.h"
+
+//
+// EFI_DRIVER_BINDING_PROTOCOL instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gAtaAtapiPassThruDriverBinding = {
+ AtaAtapiPassThruSupported,
+ AtaAtapiPassThruStart,
+ AtaAtapiPassThruStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
+ ATA_ATAPI_PASS_THRU_SIGNATURE,
+ 0, // Controller Handle
+ NULL, // PciIo Protocol
+ NULL, // IdeControllerInit Protocol
+ { // AtaPassThruMode
+ //
+ // According to UEFI2.3 spec Section 12.10, Drivers for non-RAID ATA controllers should set
+ // both EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL and EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL
+ // bits.
+ // Note that the driver doesn't support AtaPassThru non blocking I/O.
+ //
+ EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_NONBLOCKIO,
+ //
+ // IoAlign
+ //
+ sizeof (UINTN)
+ },
+ { // AtaPassThru
+ NULL,
+ AtaPassThruPassThru,
+ AtaPassThruGetNextPort,
+ AtaPassThruGetNextDevice,
+ AtaPassThruBuildDevicePath,
+ AtaPassThruGetDevice,
+ AtaPassThruResetPort,
+ AtaPassThruResetDevice
+ },
+ { // ExtScsiPassThruMode
+ //
+ // AdapterId
+ //
+ 0,
+ //
+ // According to UEFI2.3 spec Section 14.7, Drivers for non-RAID SCSI controllers should set
+ // both EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL and EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
+ // bits.
+ // Note that the driver doesn't support ExtScsiPassThru non blocking I/O.
+ //
+ EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
+ //
+ // IoAlign
+ //
+ sizeof (UINTN)
+ },
+ { // ExtScsiPassThru
+ NULL,
+ ExtScsiPassThruPassThru,
+ ExtScsiPassThruGetNextTargetLun,
+ ExtScsiPassThruBuildDevicePath,
+ ExtScsiPassThruGetTargetLun,
+ ExtScsiPassThruResetChannel,
+ ExtScsiPassThruResetTargetLun,
+ ExtScsiPassThruGetNextTarget
+ },
+ EfiAtaUnknownMode, // Work Mode
+ { // IdeRegisters
+ {0},
+ {0}
+ },
+ { // AhciRegisters
+ 0
+ },
+ { // DeviceList
+ NULL,
+ NULL
+ },
+ 0, // EnabledPciAttributes
+ 0, // OriginalAttributes
+ 0, // PreviousPort
+ 0, // PreviousPortMultiplier
+ 0, // PreviousTargetId
+ 0, // PreviousLun
+ NULL, // Timer event
+ { // NonBlocking TaskList
+ NULL,
+ NULL
+ }
+};
+
+ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_ATAPI_DP,
+ {
+ (UINT8) (sizeof (ATAPI_DEVICE_PATH)),
+ (UINT8) ((sizeof (ATAPI_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0,
+ 0
+};
+
+SATA_DEVICE_PATH mSataDevicePathTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_SATA_DP,
+ {
+ (UINT8) (sizeof (SATA_DEVICE_PATH)),
+ (UINT8) ((sizeof (SATA_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0,
+ 0
+};
+
+UINT8 mScsiId[TARGET_MAX_BYTES] = {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+EDKII_ATA_ATAPI_POLICY_PROTOCOL *mAtaAtapiPolicy;
+EDKII_ATA_ATAPI_POLICY_PROTOCOL mDefaultAtaAtapiPolicy = {
+ EDKII_ATA_ATAPI_POLICY_VERSION,
+ 2, // PuisEnable
+ 0, // DeviceSleepEnable
+ 0, // AggressiveDeviceSleepEnable
+ 0 // Reserved
+};
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller. This function
+ supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
+ and the non-blocking I/O functionality is optional.
+
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port
+ and PortMultiplierPort.
+ @param[in] Instance Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For
+ bi-directional commands, InTransferLength bytes
+ were transferred from InDataBuffer. For
+ write and bi-directional commands, OutTransferLength
+ bytes were transferred by OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
+ of bytes that could be transferred is returned
+ in InTransferLength. For write and bi-directional
+ commands, OutTransferLength bytes were transferred
+ by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because
+ there are too many ATA commands already
+ queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting
+ to send the ATA command.
+ @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents
+ of Acb are invalid. The ATA command was
+ not sent, so no additional status information
+ is available.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruPassThruExecute (
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN ATA_NONBLOCK_TASK *Task OPTIONAL
+ )
+{
+ EFI_ATA_PASS_THRU_CMD_PROTOCOL Protocol;
+ EFI_ATA_HC_WORK_MODE Mode;
+ EFI_STATUS Status;
+
+ Protocol = Packet->Protocol;
+
+ Mode = Instance->Mode;
+ switch (Mode) {
+ case EfiAtaIdeMode:
+ //
+ // Reassign IDE mode io port registers' base addresses
+ //
+ Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Protocol) {
+ case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Port],
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
+ Status = AtaPioDataInOut (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Port],
+ Packet->InDataBuffer,
+ Packet->InTransferLength,
+ TRUE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
+ Status = AtaPioDataInOut (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Port],
+ Packet->OutDataBuffer,
+ Packet->OutTransferLength,
+ FALSE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:
+ Status = AtaUdmaInOut (
+ Instance,
+ &Instance->IdeRegisters[Port],
+ TRUE,
+ Packet->InDataBuffer,
+ Packet->InTransferLength,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:
+ Status = AtaUdmaInOut (
+ Instance,
+ &Instance->IdeRegisters[Port],
+ FALSE,
+ Packet->OutDataBuffer,
+ Packet->OutTransferLength,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ default :
+ return EFI_UNSUPPORTED;
+ }
+ break;
+ case EfiAtaAhciMode :
+ if (PortMultiplierPort == 0xFFFF) {
+ //
+ // If there is no port multiplier, PortMultiplierPort will be 0xFFFF
+ // according to UEFI spec. Here, we convert its value to 0 to follow
+ // AHCI spec.
+ //
+ PortMultiplierPort = 0;
+ }
+ switch (Protocol) {
+ case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
+ Status = AhciNonDataTransfer (
+ Instance->PciIo,
+ &Instance->AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplierPort,
+ NULL,
+ 0,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
+ Status = AhciPioTransfer (
+ Instance->PciIo,
+ &Instance->AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplierPort,
+ NULL,
+ 0,
+ TRUE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->InDataBuffer,
+ Packet->InTransferLength,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
+ Status = AhciPioTransfer (
+ Instance->PciIo,
+ &Instance->AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplierPort,
+ NULL,
+ 0,
+ FALSE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->OutDataBuffer,
+ Packet->OutTransferLength,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:
+ Status = AhciDmaTransfer (
+ Instance,
+ &Instance->AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplierPort,
+ NULL,
+ 0,
+ TRUE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->InDataBuffer,
+ Packet->InTransferLength,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:
+ Status = AhciDmaTransfer (
+ Instance,
+ &Instance->AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplierPort,
+ NULL,
+ 0,
+ FALSE,
+ Packet->Acb,
+ Packet->Asb,
+ Packet->OutDataBuffer,
+ Packet->OutTransferLength,
+ Packet->Timeout,
+ Task
+ );
+ break;
+ default :
+ return EFI_UNSUPPORTED;
+ }
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncNonBlockingTransferRoutine (
+ EFI_EVENT Event,
+ VOID* Context
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *EntryHeader;
+ ATA_NONBLOCK_TASK *Task;
+ EFI_STATUS Status;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+
+ Instance = (ATA_ATAPI_PASS_THRU_INSTANCE *) Context;
+ EntryHeader = &Instance->NonBlockingTaskList;
+ //
+ // Get the Tasks from the Tasks List and execute it, until there is
+ // no task in the list or the device is busy with task (EFI_NOT_READY).
+ //
+ while (TRUE) {
+ if (!IsListEmpty (EntryHeader)) {
+ Entry = GetFirstNode (EntryHeader);
+ Task = ATA_NON_BLOCK_TASK_FROM_ENTRY (Entry);
+ } else {
+ return;
+ }
+
+ Status = AtaPassThruPassThruExecute (
+ Task->Port,
+ Task->PortMultiplier,
+ Task->Packet,
+ Instance,
+ Task
+ );
+
+ //
+ // If the data transfer meet a error, remove all tasks in the list since these tasks are
+ // associated with one task from Ata Bus and signal the event with error status.
+ //
+ if ((Status != EFI_NOT_READY) && (Status != EFI_SUCCESS)) {
+ DestroyAsynTaskList (Instance, TRUE);
+ break;
+ }
+
+ //
+ // For Non blocking mode, the Status of EFI_NOT_READY means the operation
+ // is not finished yet. Otherwise the operation is successful.
+ //
+ if (Status == EFI_NOT_READY) {
+ break;
+ } else {
+ RemoveEntryList (&Task->Link);
+ gBS->SignalEvent (Task->Event);
+ FreePool (Task);
+ }
+ }
+}
+
+/**
+ The Entry Point of module.
+
+ @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
+InitializeAtaAtapiPassThru (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gAtaAtapiPassThruDriverBinding,
+ ImageHandle,
+ &gAtaAtapiPassThruComponentName,
+ &gAtaAtapiPassThruComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+AtaAtapiPassThruSupported (
+ 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;
+ PCI_TYPE00 PciData;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInit;
+
+ //
+ // SATA Controller is a device driver, and should ignore the
+ // "RemainingDevicePath" according to UEFI spec
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeControllerInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Now test 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 ATA controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (PciData.Hdr.ClassCode),
+ PciData.Hdr.ClassCode
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (IS_PCI_IDE (&PciData) || IS_PCI_SATADPA (&PciData)) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaAtapiPassThruStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInit;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 EnabledPciAttributes;
+ UINT64 OriginalPciAttributes;
+
+ Status = EFI_SUCCESS;
+ IdeControllerInit = NULL;
+ Instance = NULL;
+ OriginalPciAttributes = 0;
+
+ DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Start== Controller = %x\n", Controller));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeControllerInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open Ide_Controller_Init Error, Status=%r", Status));
+ goto ErrorExit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Get Pci_Io Protocol Error, Status=%r", Status));
+ goto ErrorExit;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &EnabledPciAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EnabledPciAttributes,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->LocateProtocol (&gEdkiiAtaAtapiPolicyProtocolGuid, NULL, (VOID **)&mAtaAtapiPolicy);
+ if (EFI_ERROR (Status)) {
+ //
+ // If there is no AtaAtapiPolicy exposed, use the default policy.
+ //
+ mAtaAtapiPolicy = &mDefaultAtaAtapiPolicy;
+ }
+
+ //
+ // Allocate a buffer to store the ATA_ATAPI_PASS_THRU_INSTANCE data structure
+ //
+ Instance = AllocateCopyPool (sizeof (ATA_ATAPI_PASS_THRU_INSTANCE), &gAtaAtapiPassThruInstanceTemplate);
+ if (Instance == NULL) {
+ goto ErrorExit;
+ }
+
+ Instance->ControllerHandle = Controller;
+ Instance->IdeControllerInit = IdeControllerInit;
+ Instance->PciIo = PciIo;
+ Instance->EnabledPciAttributes = EnabledPciAttributes;
+ Instance->OriginalPciAttributes = OriginalPciAttributes;
+ Instance->AtaPassThru.Mode = &Instance->AtaPassThruMode;
+ Instance->ExtScsiPassThru.Mode = &Instance->ExtScsiPassThruMode;
+ InitializeListHead(&Instance->DeviceList);
+ InitializeListHead(&Instance->NonBlockingTaskList);
+
+ Instance->TimerEvent = NULL;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncNonBlockingTransferRoutine,
+ Instance,
+ &Instance->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Set 1ms timer.
+ //
+ Status = gBS->SetTimer (Instance->TimerEvent, TimerPeriodic, 10000);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Enumerate all inserted ATA devices.
+ //
+ Status = EnumerateAttachedDevice (Instance);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru),
+ &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru),
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+
+ErrorExit:
+ if (IdeControllerInit != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if ((Instance != NULL) && (Instance->TimerEvent != NULL)) {
+ gBS->CloseEvent (Instance->TimerEvent);
+ }
+
+ if (Instance != NULL) {
+ //
+ // Remove all inserted ATA devices.
+ //
+ DestroyDeviceInfoList (Instance);
+ FreePool (Instance);
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+AtaAtapiPassThruStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+
+ DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Stop== Controller = %x\n", Controller));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassThru);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru),
+ &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru),
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close protocols opened by AtaAtapiPassThru controller driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Close Non-Blocking timer and free Task list.
+ //
+ if (Instance->TimerEvent != NULL) {
+ gBS->CloseEvent (Instance->TimerEvent);
+ Instance->TimerEvent = NULL;
+ }
+ DestroyAsynTaskList (Instance, FALSE);
+ //
+ // Free allocated resource
+ //
+ DestroyDeviceInfoList (Instance);
+
+ PciIo = Instance->PciIo;
+
+ //
+ // Disable this ATA host controller.
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Instance->EnabledPciAttributes,
+ NULL
+ );
+
+ //
+ // If the current working mode is AHCI mode, then pre-allocated resource
+ // for AHCI initialization should be released.
+ //
+ if (Instance->Mode == EfiAtaAhciMode) {
+ AhciRegisters = &Instance->AhciRegisters;
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapCommandTable
+ );
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxCommandTableSize),
+ AhciRegisters->AhciCommandTable
+ );
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapCmdList
+ );
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxCommandListSize),
+ AhciRegisters->AhciCmdList
+ );
+ PciIo->Unmap (
+ PciIo,
+ AhciRegisters->MapRFis
+ );
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxReceiveFisSize),
+ AhciRegisters->AhciRFis
+ );
+ }
+
+ //
+ // Restore original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Instance->OriginalPciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Instance);
+
+ return Status;
+}
+
+/**
+ Traverse the attached ATA devices list to find out the device to access.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in] DeviceType The device type of the ATA device.
+
+ @retval The pointer to the data structure of the device info to access.
+
+**/
+LIST_ENTRY *
+EFIAPI
+SearchDeviceInfoList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplier,
+ IN EFI_ATA_DEVICE_TYPE DeviceType
+ )
+{
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ LIST_ENTRY *Node;
+
+ Node = GetFirstNode (&Instance->DeviceList);
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ //
+ // For CD-ROM working in the AHCI mode, only 8 bits are used to record
+ // the PortMultiplier information. If the CD-ROM is directly attached
+ // on a SATA port, the PortMultiplier should be translated from 0xFF
+ // to 0xFFFF according to the UEFI spec.
+ //
+ if ((Instance->Mode == EfiAtaAhciMode) &&
+ (DeviceInfo->Type == EfiIdeCdrom) &&
+ (PortMultiplier == 0xFF)) {
+ PortMultiplier = 0xFFFF;
+ }
+
+ if ((DeviceInfo->Type == DeviceType) &&
+ (Port == DeviceInfo->Port) &&
+ (PortMultiplier == DeviceInfo->PortMultiplier)) {
+ return Node;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return NULL;
+}
+
+/**
+ Allocate device info data structure to contain device info.
+ And insert the data structure to the tail of device list for tracing.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in] DeviceType The device type of the ATA device.
+ @param[in] IdentifyData The data buffer to store the output of the IDENTIFY cmd.
+
+ @retval EFI_SUCCESS Successfully insert the ata device to the tail of device list.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate enough resource for use.
+
+**/
+EFI_STATUS
+EFIAPI
+CreateNewDeviceInfo (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplier,
+ IN EFI_ATA_DEVICE_TYPE DeviceType,
+ IN EFI_IDENTIFY_DATA *IdentifyData
+ )
+{
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+
+ DeviceInfo = AllocateZeroPool (sizeof (EFI_ATA_DEVICE_INFO));
+
+ if (DeviceInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DeviceInfo->Signature = ATA_ATAPI_DEVICE_SIGNATURE;
+ DeviceInfo->Port = Port;
+ DeviceInfo->PortMultiplier = PortMultiplier;
+ DeviceInfo->Type = DeviceType;
+
+ if (IdentifyData != NULL) {
+ DeviceInfo->IdentifyData = AllocateCopyPool (sizeof (EFI_IDENTIFY_DATA), IdentifyData);
+ if (DeviceInfo->IdentifyData == NULL) {
+ FreePool (DeviceInfo);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ InsertTailList (&Instance->DeviceList, &DeviceInfo->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Destroy all attached ATA devices info.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+VOID
+EFIAPI
+DestroyDeviceInfoList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ )
+{
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ LIST_ENTRY *Node;
+
+ Node = GetFirstNode (&Instance->DeviceList);
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+
+ RemoveEntryList (&DeviceInfo->Link);
+ if (DeviceInfo->IdentifyData != NULL) {
+ FreePool (DeviceInfo->IdentifyData);
+ }
+ FreePool (DeviceInfo);
+ }
+}
+
+/**
+ Destroy all pending non blocking tasks.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] IsSigEvent Indicate whether signal the task event when remove the
+ task.
+
+**/
+VOID
+EFIAPI
+DestroyAsynTaskList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN BOOLEAN IsSigEvent
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *DelEntry;
+ ATA_NONBLOCK_TASK *Task;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (!IsListEmpty (&Instance->NonBlockingTaskList)) {
+ //
+ // Free the Subtask list.
+ //
+ for (Entry = (&Instance->NonBlockingTaskList)->ForwardLink;
+ Entry != (&Instance->NonBlockingTaskList);
+ ) {
+ DelEntry = Entry;
+ Entry = Entry->ForwardLink;
+ Task = ATA_NON_BLOCK_TASK_FROM_ENTRY (DelEntry);
+
+ RemoveEntryList (DelEntry);
+ if (IsSigEvent) {
+ Task->Packet->Asb->AtaStatus = 0x01;
+ gBS->SignalEvent (Task->Event);
+ }
+ FreePool (Task);
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Enumerate all attached ATA devices at IDE mode or AHCI mode separately.
+
+ The function is designed to enumerate all attached ATA devices.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+ @retval EFI_SUCCESS Successfully enumerate attached ATA devices.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EnumerateAttachedDevice (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+ UINT8 ClassCode;
+
+ Status = EFI_SUCCESS;
+
+ Status = Instance->PciIo->Pci.Read (
+ Instance->PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (PciData.Hdr.ClassCode),
+ PciData.Hdr.ClassCode
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ClassCode = PciData.Hdr.ClassCode[1];
+
+ switch (ClassCode) {
+ case PCI_CLASS_MASS_STORAGE_IDE :
+ //
+ // The ATA controller is working at IDE mode
+ //
+ Instance->Mode = EfiAtaIdeMode;
+
+ Status = IdeModeInitialization (Instance);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ break;
+ case PCI_CLASS_MASS_STORAGE_SATADPA :
+ //
+ // The ATA controller is working at AHCI mode
+ //
+ Instance->Mode = EfiAtaAhciMode;
+
+ Status = AhciModeInitialization (Instance);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ break;
+ default :
+ Status = EFI_UNSUPPORTED;
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller. This function
+ supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
+ and the non-blocking I/O functionality is optional.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port
+ and PortMultiplierPort.
+ @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then non-blocking
+ I/O is performed, and Event will be signaled when the ATA command completes.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For bi-directional commands,
+ InTransferLength bytes were transferred from InDataBuffer. For write and
+ bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number of bytes that could be transferred
+ is returned in InTransferLength. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there are too many ATA commands
+ already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the ATA command.
+ @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA
+ command was not sent, so no additional status information is available.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruPassThru (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ EFI_IDENTIFY_DATA *IdentifyData;
+ UINT64 Capacity;
+ UINT32 MaxSectorCount;
+ ATA_NONBLOCK_TASK *Task;
+ EFI_TPL OldTpl;
+ UINT32 BlockSize;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->Asb, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Node = SearchDeviceInfoList (Instance, Port, PortMultiplierPort, EfiIdeHarddisk);
+
+ if (Node == NULL) {
+ Node = SearchDeviceInfoList(Instance, Port, PortMultiplierPort, EfiIdeCdrom);
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Check whether this device needs 48-bit addressing (ATAPI-6 ata device).
+ // Per ATA-6 spec, word83: bit15 is zero and bit14 is one.
+ // If bit10 is one, it means the ata device support 48-bit addressing.
+ //
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+ IdentifyData = DeviceInfo->IdentifyData;
+ MaxSectorCount = 0x100;
+ if ((IdentifyData->AtaData.command_set_supported_83 & (BIT10 | BIT15 | BIT14)) == 0x4400) {
+ Capacity = *((UINT64 *)IdentifyData->AtaData.maximum_lba_for_48bit_addressing);
+ if (Capacity > 0xFFFFFFF) {
+ //
+ // Capacity exceeds 120GB. 48-bit addressing is really needed
+ // In this case, the max sector count is 0x10000
+ //
+ MaxSectorCount = 0x10000;
+ }
+ }
+
+ BlockSize = 0x200;
+ if ((IdentifyData->AtaData.phy_logic_sector_support & (BIT14 | BIT15)) == BIT14) {
+ //
+ // Check logical block size
+ //
+ if ((IdentifyData->AtaData.phy_logic_sector_support & BIT12) != 0) {
+ BlockSize = (UINT32) (((IdentifyData->AtaData.logic_sector_size_hi << 16) | IdentifyData->AtaData.logic_sector_size_lo) * sizeof (UINT16));
+ }
+ }
+
+ //
+ // convert the transfer length from sector count to byte.
+ //
+ if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+ (Packet->InTransferLength != 0)) {
+ Packet->InTransferLength = Packet->InTransferLength * BlockSize;
+ }
+
+ //
+ // convert the transfer length from sector count to byte.
+ //
+ if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+ (Packet->OutTransferLength != 0)) {
+ Packet->OutTransferLength = Packet->OutTransferLength * BlockSize;
+ }
+
+ //
+ // If the data buffer described by InDataBuffer/OutDataBuffer and InTransferLength/OutTransferLength
+ // is too big to be transferred in a single command, then no data is transferred and EFI_BAD_BUFFER_SIZE
+ // is returned.
+ //
+ if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) ||
+ ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // For non-blocking mode, queue the Task into the list.
+ //
+ if (Event != NULL) {
+ Task = AllocateZeroPool (sizeof (ATA_NONBLOCK_TASK));
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Task->Signature = ATA_NONBLOCKING_TASK_SIGNATURE;
+ Task->Port = Port;
+ Task->PortMultiplier = PortMultiplierPort;
+ Task->Packet = Packet;
+ Task->Event = Event;
+ Task->IsStart = FALSE;
+ Task->RetryTimes = DivU64x32(Packet->Timeout, 1000) + 1;
+ if (Packet->Timeout == 0) {
+ Task->InfiniteWait = TRUE;
+ } else {
+ Task->InfiniteWait = FALSE;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Instance->NonBlockingTaskList, &Task->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+ } else {
+ return AtaPassThruPassThruExecute (
+ Port,
+ PortMultiplierPort,
+ Packet,
+ Instance,
+ NULL
+ );
+ }
+}
+
+/**
+ Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+ These can either be the list of ports where ATA devices are actually present or the
+ list of legal port numbers for the ATA controller. Regardless, the caller of this
+ function must probe the port number returned to see if an ATA device is actually
+ present at that location on the ATA controller.
+
+ The GetNextPort() function retrieves the port number on an ATA controller. If on input
+ Port is 0xFFFF, then the port number of the first port on the ATA controller is returned
+ in Port and EFI_SUCCESS is returned.
+
+ If Port is a port number that was returned on a previous call to GetNextPort(), then the
+ port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS
+ is returned. If Port is not 0xFFFF and Port was not returned on a previous call to
+ GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+ If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is
+ returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in, out] Port On input, a pointer to the port number on the ATA controller.
+ On output, a pointer to the next port number on the ATA
+ controller. An input value of 0xFFFF retrieves the first port
+ number on the ATA controller.
+
+ @retval EFI_SUCCESS The next port number on the ATA controller was returned in Port.
+ @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
+ @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call
+ to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetNextPort (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT16 *Port
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Port == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Port == 0xFFFF) {
+ //
+ // If the Port is all 0xFF's, start to traverse the device list from the beginning
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceInfo->Type == EfiIdeHarddisk) {
+ *Port = DeviceInfo->Port;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else if (*Port == Instance->PreviousPort) {
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceInfo->Type == EfiIdeHarddisk) &&
+ (DeviceInfo->Port > *Port)){
+ *Port = DeviceInfo->Port;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // Port is not equal to 0xFFFF and also not equal to previous return value
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+Exit:
+ //
+ // Update the PreviousPort and PreviousPortMultiplier.
+ //
+ Instance->PreviousPort = *Port;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA
+ controller. These can either be the list of port multiplier ports where ATA devices are actually
+ present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this
+ function must probe the port number and port multiplier port number returned to see if an ATA
+ device is actually present.
+
+ The GetNextDevice() function retrieves the port multiplier port number of an ATA device
+ present on a port of an ATA controller.
+
+ If PortMultiplierPort points to a port multiplier port number value that was returned on a
+ previous call to GetNextDevice(), then the port multiplier port number of the next ATA device
+ on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
+ returned.
+
+ If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first
+ ATA device on port of the ATA controller is returned in PortMultiplierPort and
+ EFI_SUCCESS is returned.
+
+ If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+ was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+ is returned.
+
+ If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of
+ the ATA controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number present on the ATA controller.
+ @param[in, out] PortMultiplierPort On input, a pointer to the port multiplier port number of an
+ ATA device present on the ATA controller.
+ If on input a PortMultiplierPort of 0xFFFF is specified,
+ then the port multiplier port number of the first ATA device
+ is returned. On output, a pointer to the port multiplier port
+ number of the next ATA device present on an ATA controller.
+
+ @retval EFI_SUCCESS The port multiplier port number of the next ATA device on the port
+ of the ATA controller was returned in PortMultiplierPort.
+ @retval EFI_NOT_FOUND There are no more ATA devices on this port of the ATA controller.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not
+ returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetNextDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN OUT UINT16 *PortMultiplierPort
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PortMultiplierPort == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Instance->PreviousPortMultiplier == 0xFFFF) {
+ //
+ // If a device is directly attached on a port, previous call to this
+ // function will return the value 0xFFFF for PortMultiplierPort. In
+ // this case, there should be no more device on the port multiplier.
+ //
+ Instance->PreviousPortMultiplier = 0;
+ return EFI_NOT_FOUND;
+ }
+
+ if (*PortMultiplierPort == Instance->PreviousPortMultiplier) {
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceInfo->Type == EfiIdeHarddisk) &&
+ (DeviceInfo->Port == Port) &&
+ (DeviceInfo->PortMultiplier > *PortMultiplierPort)){
+ *PortMultiplierPort = DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else if (*PortMultiplierPort == 0xFFFF) {
+ //
+ // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceInfo->Type == EfiIdeHarddisk) &&
+ (DeviceInfo->Port == Port)){
+ *PortMultiplierPort = DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // PortMultiplierPort is not equal to 0xFFFF and also not equal to previous return value
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+Exit:
+ //
+ // Update the PreviousPort and PreviousPortMultiplier.
+ //
+ Instance->PreviousPortMultiplier = *PortMultiplierPort;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to allocate and build a device path node for an ATA device on an ATA controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the ATA
+ device specified by Port and PortMultiplierPort. If the ATA device specified by Port and
+ PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough
+ resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,
+ and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port Port specifies the port number of the ATA device for which a
+ device path node is to be allocated and built.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device for which a
+ device path node is to be allocated and built. If there is no
+ port multiplier, then specify 0xFFFF.
+ @param[in, out] DevicePath A pointer to a single device path node that describes the ATA
+ device specified by Port and PortMultiplierPort. This function
+ is responsible for allocating the buffer DevicePath with the
+ boot service AllocatePool(). It is the caller's responsibility
+ to free DevicePath when the caller is finished with DevicePath.
+ @retval EFI_SUCCESS The device path node that describes the ATA device specified by
+ Port and PortMultiplierPort was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The ATA device specified by Port and PortMultiplierPort does not
+ exist on the ATA controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruBuildDevicePath (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEV_PATH *DevicePathNode;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Validate parameters passed in.
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Node = SearchDeviceInfoList(Instance, Port, PortMultiplierPort, EfiIdeHarddisk);
+ if (Node == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Instance->Mode == EfiAtaIdeMode) {
+ DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);
+ if (DevicePathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevicePathNode->Atapi.PrimarySecondary = (UINT8) Port;
+ DevicePathNode->Atapi.SlaveMaster = (UINT8) PortMultiplierPort;
+ DevicePathNode->Atapi.Lun = 0;
+ } else {
+ DevicePathNode = AllocateCopyPool (sizeof (SATA_DEVICE_PATH), &mSataDevicePathTemplate);
+ if (DevicePathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevicePathNode->Sata.HBAPortNumber = Port;
+ DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplierPort;
+ DevicePathNode->Sata.Lun = 0;
+ }
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to translate a device path node to a port number and port multiplier port number.
+
+ The GetDevice() function determines the port and port multiplier port number associated with
+ the ATA device described by DevicePath. If DevicePath is a device path node type that the
+ ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents
+ DevicePath into a port number and port multiplier port number.
+
+ If this translation is successful, then that port number and port multiplier port number are returned
+ in Port and PortMultiplierPort, and EFI_SUCCESS is returned.
+
+ If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then
+ EFI_UNSUPPORTED is returned.
+
+ If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not
+ a valid translation from DevicePath to a port number and port multiplier port number, then
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes an ATA device on the
+ ATA controller.
+ @param[out] Port On return, points to the port number of an ATA device on the ATA controller.
+ @param[out] PortMultiplierPort On return, points to the port multiplier port number of an ATA device
+ on the ATA controller.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a port number and port multiplier
+ port number, and they were returned in Port and PortMultiplierPort.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER Port is NULL.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is NULL.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier
+ port number does not exist.
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT16 *Port,
+ OUT UINT16 *PortMultiplierPort
+ )
+{
+ EFI_DEV_PATH *DevicePathNode;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Validate parameters passed in.
+ //
+ if (DevicePath == NULL || Port == NULL || PortMultiplierPort == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the DevicePath belongs to SCSI_DEVICE_PATH or ATAPI_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ ((DevicePath->SubType != MSG_SATA_DP) &&
+ (DevicePath->SubType != MSG_ATAPI_DP)) ||
+ ((DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH)) &&
+ (DevicePathNodeLength(DevicePath) != sizeof(SATA_DEVICE_PATH)))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DevicePathNode = (EFI_DEV_PATH *) DevicePath;
+
+ if (Instance->Mode == EfiAtaIdeMode) {
+ *Port = DevicePathNode->Atapi.PrimarySecondary;
+ *PortMultiplierPort = DevicePathNode->Atapi.SlaveMaster;
+ } else {
+ *Port = DevicePathNode->Sata.HBAPortNumber;
+ *PortMultiplierPort = DevicePathNode->Sata.PortMultiplierPortNumber;
+ }
+
+ Node = SearchDeviceInfoList(Instance, *Port, *PortMultiplierPort, EfiIdeHarddisk);
+
+ if (Node == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a specific port on the ATA controller. This operation also resets all the ATA devices
+ connected to the port.
+
+ The ResetChannel() function resets an a specific port on an ATA controller. This operation
+ resets all the ATA devices connected to that port. If this ATA controller does not support
+ a reset port operation, then EFI_UNSUPPORTED is returned.
+
+ If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is
+ returned.
+
+ If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.
+
+ If the port reset operation is completed, then EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number on the ATA controller.
+
+ @retval EFI_SUCCESS The ATA controller port was reset.
+ @retval EFI_UNSUPPORTED The ATA controller does not support a port reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA port.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA port.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruResetPort (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port
+ )
+{
+ //
+ // Return success directly then upper layer driver could think reset port operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets an ATA device that is connected to an ATA controller.
+
+ The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.
+ If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is
+ returned.
+
+ If Port or PortMultiplierPort are not in a valid range for this ATA controller, then
+ EFI_INVALID_PARAMETER is returned.
+
+ If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR
+ is returned.
+
+ If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is
+ returned.
+
+ If the device reset operation is completed, then EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port Port represents the port number of the ATA device to be reset.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to reset.
+ If there is no port multiplier, then specify 0xFFFF.
+ @retval EFI_SUCCESS The ATA device specified by Port and PortMultiplierPort was reset.
+ @retval EFI_UNSUPPORTED The ATA controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA device
+ specified by Port and PortMultiplierPort.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA device
+ specified by Port and PortMultiplierPort.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruResetDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ Node = SearchDeviceInfoList (Instance, Port, PortMultiplierPort, EfiIdeHarddisk);
+
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Return success directly then upper layer driver could think reset device operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Submit ATAPI request sense command.
+
+ @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it represents
+ the id of the SCSI device to send the SCSI Request Packet. Each
+ transport driver may choose to utilize a subset of this size to suit the needs
+ of transport target representation. For example, a Fibre Channel driver
+ may use only 8 bytes (WWN) to represent an FC target.
+ @param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet.
+ @param[in] SenseData A pointer to store sense data.
+ @param[in] SenseDataLength The sense data length.
+ @param[in] Timeout The timeout value to execute this cmd, uses 100ns as a unit.
+
+ @retval EFI_SUCCESS Send out the ATAPI packet command successfully.
+ @retval EFI_DEVICE_ERROR The device failed to send data.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPacketRequestSense (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN VOID *SenseData,
+ IN UINT8 SenseDataLength,
+ IN UINT64 Timeout
+ )
+{
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[12];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, 12);
+
+ Cdb[0] = ATA_CMD_REQUEST_SENSE;
+ Cdb[4] = SenseDataLength;
+
+ Packet.Timeout = Timeout;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = 12;
+ Packet.DataDirection = EFI_EXT_SCSI_DATA_DIRECTION_READ;
+ Packet.InDataBuffer = SenseData;
+ Packet.InTransferLength = SenseDataLength;
+
+ Status = ExtScsiPassThruPassThru (This, Target, Lun, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
+ supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
+ nonblocking I/O functionality is optional.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it represents
+ the id of the SCSI device to send the SCSI Request Packet. Each
+ transport driver may choose to utilize a subset of this size to suit the needs
+ of transport target representation. For example, a Fibre Channel driver
+ may use only 8 bytes (WWN) to represent an FC target.
+ @param Lun The LUN of the SCSI device to send the SCSI Request Packet.
+ @param Packet A pointer to the SCSI Request Packet to send to the SCSI device
+ specified by Target and Lun.
+ @param Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed. The number of bytes that
+ could be transferred is returned in InTransferLength. For write
+ and bi-directional commands, OutTransferLength bytes were
+ transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
+ SCSI Request Packets already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported
+ by the host adapter. This includes the case of Bi-directional SCSI
+ commands not supported by the implementation. The SCSI Request
+ Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruPassThru (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ UINT8 Port;
+ UINT8 PortMultiplier;
+ EFI_ATA_HC_WORK_MODE Mode;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ BOOLEAN SenseReq;
+ EFI_SCSI_SENSE_DATA *PtrSenseData;
+ UINTN SenseDataLen;
+ EFI_STATUS SenseStatus;
+
+ SenseDataLen = 0;
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((Packet == NULL) || (Packet->Cdb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Don't support variable length CDB
+ //
+ if ((Packet->CdbLength != 6) && (Packet->CdbLength != 10) &&
+ (Packet->CdbLength != 12) && (Packet->CdbLength != 16)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For ATAPI device, doesn't support multiple LUN device.
+ //
+ if (Lun != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The layout of Target array:
+ // ________________________________________________________________________
+ // | Byte 0 | Byte 1 | ... | TARGET_MAX_BYTES - 1 |
+ // |_____________________|_____________________|_____|______________________|
+ // | | The port multiplier | | |
+ // | The port number | port number | N/A | N/A |
+ // |_____________________|_____________________|_____|______________________|
+ //
+ // For ATAPI device, 2 bytes is enough to represent the location of SCSI device.
+ //
+ Port = Target[0];
+ PortMultiplier = Target[1];
+
+ Node = SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom);
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ //
+ // ATA_CMD_IDENTIFY_DEVICE cmd is a ATA cmd but not a SCSI cmd.
+ // Normally it should NOT be passed down through ExtScsiPassThru protocol interface.
+ // But to response EFI_DISK_INFO.Identify() request from ScsiDisk, we should handle this command.
+ //
+ if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {
+ CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA));
+ //
+ // For IDENTIFY DEVICE cmd, we don't need to get sense data.
+ //
+ Packet->SenseDataLength = 0;
+ return EFI_SUCCESS;
+ }
+
+ Mode = Instance->Mode;
+ switch (Mode) {
+ case EfiAtaIdeMode:
+ //
+ // Reassign IDE mode io port registers' base addresses
+ //
+ Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AtaPacketCommandExecute (Instance->PciIo, &Instance->IdeRegisters[Port], Port, PortMultiplier, Packet);
+ break;
+ case EfiAtaAhciMode:
+ if (PortMultiplier == 0xFF) {
+ //
+ // If there is no port multiplier, the PortMultiplier will be 0xFF
+ // Here, we convert its value to 0 to follow the AHCI spec.
+ //
+ PortMultiplier = 0;
+ }
+ Status = AhciPacketCommandExecute (Instance->PciIo, &Instance->AhciRegisters, Port, PortMultiplier, Packet);
+ break;
+ default :
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ //
+ // If the cmd doesn't get executed correctly, then check sense data.
+ //
+ if (EFI_ERROR (Status) && (Packet->SenseDataLength != 0) && (*((UINT8*)Packet->Cdb) != ATA_CMD_REQUEST_SENSE)) {
+ PtrSenseData = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)), This->Mode->IoAlign);
+ if (PtrSenseData == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (SenseReq = TRUE; SenseReq;) {
+ SenseStatus = AtaPacketRequestSense (
+ This,
+ Target,
+ Lun,
+ PtrSenseData,
+ sizeof (EFI_SCSI_SENSE_DATA),
+ Packet->Timeout
+ );
+ if (EFI_ERROR (SenseStatus)) {
+ break;
+ }
+
+ CopyMem ((UINT8*)Packet->SenseData + SenseDataLen, PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
+ SenseDataLen += sizeof (EFI_SCSI_SENSE_DATA);
+
+ //
+ // no more sense key or number of sense keys exceeds predefined,
+ // skip the loop.
+ //
+ if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
+ (SenseDataLen + sizeof (EFI_SCSI_SENSE_DATA) > Packet->SenseDataLength)) {
+ SenseReq = FALSE;
+ }
+ }
+ FreeAlignedPages (PtrSenseData, EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)));
+ }
+ //
+ // Update the SenseDataLength field to the data length received.
+ //
+ Packet->SenseDataLength = (UINT8)SenseDataLen;
+ return Status;
+}
+
+/**
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These
+ can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal
+ Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the
+ Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI
+ channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target On input, a pointer to the Target ID (an array of size
+ TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+ @param Lun On input, a pointer to the LUN of a SCSI device present on the SCSI
+ channel. On output, a pointer to the LUN of the next SCSI device present
+ on a SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID and LUN of the next SCSI device on the SCSI
+ channel was returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were
+ not returned on a previous call to GetNextTargetLun().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ UINT8 *Target8;
+ UINT16 *Target16;
+
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Target8 = *Target;
+ Target16 = (UINT16 *)*Target;
+
+ if (CompareMem(Target8, mScsiId, TARGET_MAX_BYTES) != 0) {
+ //
+ // For ATAPI device, we use 2 least significant bytes to represent the location of SCSI device.
+ // So the higher bytes in Target array should be 0xFF.
+ //
+ if (CompareMem (&Target8[2], &mScsiId[2], TARGET_MAX_BYTES - 2) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // When Target is not all 0xFF's, compare 2 least significant bytes with
+ // previous target id to see if it is returned by previous call.
+ //
+ if ((*Target16 != Instance->PreviousTargetId) ||
+ (*Lun != Instance->PreviousLun)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Traverse the whole device list to find the next cdrom closed to
+ // the device signified by Target[0] and Target[1].
+ //
+ // Note that we here use a tricky way to find the next cdrom :
+ // All ata devices are detected and inserted into the device list
+ // sequentially.
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceInfo->Type == EfiIdeCdrom) &&
+ ((Target8[0] < DeviceInfo->Port) ||
+ ((Target8[0] == DeviceInfo->Port) &&
+ (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) {
+ Target8[0] = (UINT8)DeviceInfo->Port;
+ Target8[1] = (UINT8)DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // If the array is all 0xFF's, start to traverse the device list from the beginning
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceInfo->Type == EfiIdeCdrom) {
+ Target8[0] = (UINT8)DeviceInfo->Port;
+ Target8[1] = (UINT8)DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ }
+
+Exit:
+ *Lun = 0;
+
+ //
+ // Update the PreviousTargetId.
+ //
+ Instance->PreviousTargetId = *Target16;
+ Instance->PreviousLun = *Lun;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to allocate and build a device path node for a SCSI device on a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it specifies the
+ Target ID of the SCSI device for which a device path node is to be
+ allocated and built. Transport drivers may chose to utilize a subset of
+ this size to suit the representation of targets. For example, a Fibre
+ Channel driver may use only 8 bytes (WWN) in the array to represent a
+ FC target.
+ @param Lun The LUN of the SCSI device for which a device path node is to be
+ allocated and built.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ specified by Target and Lun. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SCSI device specified by
+ Target and Lun was allocated and returned in
+ DevicePath.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist
+ on the SCSI channel.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEV_PATH *DevicePathNode;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ UINT8 Port;
+ UINT8 PortMultiplier;
+
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ Port = Target[0];
+ PortMultiplier = Target[1];
+
+ //
+ // Validate parameters passed in.
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // can not build device path for the SCSI Host Controller.
+ //
+ if (Lun != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom) == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Instance->Mode == EfiAtaIdeMode) {
+ DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);
+ if (DevicePathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevicePathNode->Atapi.PrimarySecondary = Port;
+ DevicePathNode->Atapi.SlaveMaster = PortMultiplier;
+ DevicePathNode->Atapi.Lun = (UINT16) Lun;
+ } else {
+ DevicePathNode = AllocateCopyPool (sizeof (SATA_DEVICE_PATH), &mSataDevicePathTemplate);
+ if (DevicePathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevicePathNode->Sata.HBAPortNumber = Port;
+ //
+ // For CD-ROM working in the AHCI mode, only 8 bits are used to record
+ // the PortMultiplier information. If the CD-ROM is directly attached
+ // on a SATA port, the PortMultiplier should be translated from 0xFF
+ // to 0xFFFF according to the UEFI spec.
+ //
+ DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier == 0xFF ? 0xFFFF : PortMultiplier;
+ DevicePathNode->Sata.Lun = (UINT16) Lun;
+ }
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to translate a device path node to a Target ID and LUN.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ on the SCSI channel.
+ @param Target A pointer to the Target Array which represents the ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of a SCSI device on the SCSI channel.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a Target ID and
+ LUN, and they were returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target ID and LUN
+ does not exist.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ )
+{
+ EFI_DEV_PATH *DevicePathNode;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Validate parameters passed in.
+ //
+ if (DevicePath == NULL || Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ ((DevicePath->SubType != MSG_ATAPI_DP) &&
+ (DevicePath->SubType != MSG_SATA_DP)) ||
+ ((DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH)) &&
+ (DevicePathNodeLength(DevicePath) != sizeof(SATA_DEVICE_PATH)))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SetMem (*Target, TARGET_MAX_BYTES, 0xFF);
+
+ DevicePathNode = (EFI_DEV_PATH *) DevicePath;
+
+ if (Instance->Mode == EfiAtaIdeMode) {
+ (*Target)[0] = (UINT8) DevicePathNode->Atapi.PrimarySecondary;
+ (*Target)[1] = (UINT8) DevicePathNode->Atapi.SlaveMaster;
+ *Lun = (UINT8) DevicePathNode->Atapi.Lun;
+ } else {
+ (*Target)[0] = (UINT8) DevicePathNode->Sata.HBAPortNumber;
+ (*Target)[1] = (UINT8) DevicePathNode->Sata.PortMultiplierPortNumber;
+ *Lun = (UINT8) DevicePathNode->Sata.Lun;
+ }
+
+ Node = SearchDeviceInfoList(Instance, (*Target)[0], (*Target)[1], EfiIdeCdrom);
+
+ if (Node == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*Lun != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SCSI channel was reset.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI channel.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a channel reset operation.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ )
+{
+ //
+ // Return success directly then upper layer driver could think reset channel operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a SCSI logical unit that is connected to a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTE and it represents the
+ target port ID of the SCSI device containing the SCSI logical unit to
+ reset. Transport drivers may chose to utilize a subset of this array to suit
+ the representation of their targets.
+ @param Lun The LUN of the SCSI device to reset.
+
+ @retval EFI_SUCCESS The SCSI device specified by Target and Lun was reset.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a target reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruResetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ UINT8 Port;
+ UINT8 PortMultiplier;
+
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+ //
+ // For ATAPI device, doesn't support multiple LUN device.
+ //
+ if (Lun != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // The layout of Target array:
+ // ________________________________________________________________________
+ // | Byte 0 | Byte 1 | ... | TARGET_MAX_BYTES - 1 |
+ // |_____________________|_____________________|_____|______________________|
+ // | | The port multiplier | | |
+ // | The port number | port number | N/A | N/A |
+ // |_____________________|_____________________|_____|______________________|
+ //
+ // For ATAPI device, 2 bytes is enough to represent the location of SCSI device.
+ //
+ Port = Target[0];
+ PortMultiplier = Target[1];
+
+ Node = SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom);
+ if (Node == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Return success directly then upper layer driver could think reset target LUN operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either
+ be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs
+ for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to
+ see if a SCSI device is actually present at that location on the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
+ channel was returned in Target.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
+ returned on a previous call to GetNextTarget().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ LIST_ENTRY *Node;
+ EFI_ATA_DEVICE_INFO *DeviceInfo;
+ UINT8 *Target8;
+ UINT16 *Target16;
+
+ Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Target == NULL || *Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Target8 = *Target;
+ Target16 = (UINT16 *)*Target;
+
+ if (CompareMem(Target8, mScsiId, TARGET_MAX_BYTES) != 0) {
+ //
+ // For ATAPI device, we use 2 least significant bytes to represent the location of SCSI device.
+ // So the higher bytes in Target array should be 0xFF.
+ //
+ if (CompareMem (&Target8[2], &mScsiId[2], TARGET_MAX_BYTES - 2) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // When Target is not all 0xFF's, compare 2 least significant bytes with
+ // previous target id to see if it is returned by previous call.
+ //
+ if (*Target16 != Instance->PreviousTargetId) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Traverse the whole device list to find the next cdrom closed to
+ // the device signified by Target[0] and Target[1].
+ //
+ // Note that we here use a tricky way to find the next cdrom :
+ // All ata devices are detected and inserted into the device list
+ // sequentially.
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if ((DeviceInfo->Type == EfiIdeCdrom) &&
+ ((Target8[0] < DeviceInfo->Port) ||
+ ((Target8[0] == DeviceInfo->Port) &&
+ (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) {
+ Target8[0] = (UINT8)DeviceInfo->Port;
+ Target8[1] = (UINT8)DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // If the array is all 0xFF's, start to traverse the device list from the beginning
+ //
+ Node = GetFirstNode (&Instance->DeviceList);
+
+ while (!IsNull (&Instance->DeviceList, Node)) {
+ DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceInfo->Type == EfiIdeCdrom) {
+ Target8[0] = (UINT8)DeviceInfo->Port;
+ Target8[1] = (UINT8)DeviceInfo->PortMultiplier;
+ goto Exit;
+ }
+
+ Node = GetNextNode (&Instance->DeviceList, Node);
+ }
+
+ return EFI_NOT_FOUND;
+ }
+
+Exit:
+ //
+ // Update the PreviousTargetId.
+ //
+ Instance->PreviousTargetId = *Target16;
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
new file mode 100644
index 000000000..5f582b9b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
@@ -0,0 +1,1299 @@
+/** @file
+ Header file for ATA/ATAPI PASS THRU driver.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __ATA_ATAPI_PASS_THRU_H__
+#define __ATA_ATAPI_PASS_THRU_H__
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Atapi.h>
+#include <IndustryStandard/Scsi.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/AtaPassThru.h>
+#include <Protocol/ScsiPassThruExt.h>
+#include <Protocol/AtaAtapiPolicy.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "IdeMode.h"
+#include "AhciMode.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL gAtaAtapiPassThruDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gAtaAtapiPassThruComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gAtaAtapiPassThruComponentName2;
+
+extern EDKII_ATA_ATAPI_POLICY_PROTOCOL *mAtaAtapiPolicy;
+
+#define ATA_ATAPI_PASS_THRU_SIGNATURE SIGNATURE_32 ('a', 'a', 'p', 't')
+#define ATA_ATAPI_DEVICE_SIGNATURE SIGNATURE_32 ('a', 'd', 'e', 'v')
+#define ATA_NONBLOCKING_TASK_SIGNATURE SIGNATURE_32 ('a', 't', 's', 'k')
+
+typedef struct _ATA_NONBLOCK_TASK ATA_NONBLOCK_TASK;
+
+typedef enum {
+ EfiAtaIdeMode,
+ EfiAtaAhciMode,
+ EfiAtaRaidMode,
+ EfiAtaUnknownMode
+} EFI_ATA_HC_WORK_MODE;
+
+typedef enum {
+ EfiIdeCdrom, /* ATAPI CDROM */
+ EfiIdeHarddisk, /* Hard Disk */
+ EfiPortMultiplier, /* Port Multiplier */
+ EfiIdeUnknown
+} EFI_ATA_DEVICE_TYPE;
+
+//
+// Ahci mode device info
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT16 Port;
+ UINT16 PortMultiplier;
+ EFI_ATA_DEVICE_TYPE Type;
+
+ EFI_IDENTIFY_DATA *IdentifyData;
+} EFI_ATA_DEVICE_INFO;
+
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE ControllerHandle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInit;
+
+ EFI_ATA_PASS_THRU_MODE AtaPassThruMode;
+ EFI_ATA_PASS_THRU_PROTOCOL AtaPassThru;
+ EFI_EXT_SCSI_PASS_THRU_MODE ExtScsiPassThruMode;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL ExtScsiPassThru;
+
+ EFI_ATA_HC_WORK_MODE Mode;
+
+ EFI_IDE_REGISTERS IdeRegisters[EfiIdeMaxChannel];
+ EFI_AHCI_REGISTERS AhciRegisters;
+
+ //
+ // The attached device list
+ //
+ LIST_ENTRY DeviceList;
+ UINT64 EnabledPciAttributes;
+ UINT64 OriginalPciAttributes;
+
+ //
+ // For AtaPassThru protocol, using the following bytes to record the previous call in
+ // GetNextPort()/GetNextDevice().
+ //
+ UINT16 PreviousPort;
+ UINT16 PreviousPortMultiplier;
+ //
+ // For ExtScsiPassThru protocol, using the following bytes to record the previous call in
+ // GetNextTarget()/GetNextTargetLun().
+ //
+ UINT16 PreviousTargetId;
+ UINT64 PreviousLun;
+
+ //
+ // For Non-blocking.
+ //
+ EFI_EVENT TimerEvent;
+ LIST_ENTRY NonBlockingTaskList;
+} ATA_ATAPI_PASS_THRU_INSTANCE;
+
+//
+// Task for Non-blocking mode.
+//
+struct _ATA_NONBLOCK_TASK {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT16 Port;
+ UINT16 PortMultiplier;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN IsStart;
+ EFI_EVENT Event;
+ UINT64 RetryTimes;
+ BOOLEAN InfiniteWait;
+ VOID *Map; // Pointer to map.
+ VOID *TableMap; // Pointer to PRD table map.
+ EFI_ATA_DMA_PRD *MapBaseAddress; // Pointer to range Base address for Map.
+ UINTN PageCount; // The page numbers used by PCIO freebuffer.
+};
+
+//
+// Timeout value which uses 100ns as a unit.
+// It means 3 second span.
+//
+#define ATA_ATAPI_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3)
+#define ATA_SPINUP_TIMEOUT EFI_TIMER_PERIOD_SECONDS(10)
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+#define ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ ATA_ATAPI_PASS_THRU_INSTANCE, \
+ AtaPassThru, \
+ ATA_ATAPI_PASS_THRU_SIGNATURE \
+ )
+
+#define EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ ATA_ATAPI_PASS_THRU_INSTANCE, \
+ ExtScsiPassThru, \
+ ATA_ATAPI_PASS_THRU_SIGNATURE \
+ )
+
+#define ATA_ATAPI_DEVICE_INFO_FROM_THIS(a) \
+ CR (a, \
+ EFI_ATA_DEVICE_INFO, \
+ Link, \
+ ATA_ATAPI_DEVICE_SIGNATURE \
+ );
+
+#define ATA_NON_BLOCK_TASK_FROM_ENTRY(a) \
+ CR (a, \
+ ATA_NONBLOCK_TASK, \
+ Link, \
+ ATA_NONBLOCKING_TASK_SIGNATURE \
+ );
+
+/**
+ 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
+AtaAtapiPassThruComponentNameGetDriverName (
+ 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
+AtaAtapiPassThruComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+AtaAtapiPassThruSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaAtapiPassThruStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+AtaAtapiPassThruStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Traverse the attached ATA devices list to find out the device to access.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in] DeviceType The device type of the ATA device.
+
+ @retval The pointer to the data structure of the device info to access.
+
+**/
+LIST_ENTRY *
+EFIAPI
+SearchDeviceInfoList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplier,
+ IN EFI_ATA_DEVICE_TYPE DeviceType
+ );
+
+/**
+ Allocate device info data structure to contain device info.
+ And insert the data structure to the tail of device list for tracing.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in] DeviceType The device type of the ATA device.
+ @param[in] IdentifyData The data buffer to store the output of the IDENTIFY cmd.
+
+ @retval EFI_SUCCESS Successfully insert the ata device to the tail of device list.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate enough resource for use.
+
+**/
+EFI_STATUS
+EFIAPI
+CreateNewDeviceInfo (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplier,
+ IN EFI_ATA_DEVICE_TYPE DeviceType,
+ IN EFI_IDENTIFY_DATA *IdentifyData
+ );
+
+/**
+ Destroy all attached ATA devices info.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+VOID
+EFIAPI
+DestroyDeviceInfoList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ );
+
+/**
+ Destroy all pending non blocking tasks.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+ @param[in] IsSigEvent Indicate whether signal the task event when remove the
+ task.
+
+**/
+VOID
+EFIAPI
+DestroyAsynTaskList (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN BOOLEAN IsSigEvent
+ );
+
+/**
+ Enumerate all attached ATA devices at IDE mode or AHCI mode separately.
+
+ The function is designed to enumerate all attached ATA devices.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+ @retval EFI_SUCCESS Successfully enumerate attached ATA devices.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EnumerateAttachedDevice (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ );
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncNonBlockingTransferRoutine (
+ EFI_EVENT Event,
+ VOID* Context
+ );
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller. This function
+ supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
+ and the non-blocking I/O functionality is optional.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number of the ATA device to send the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
+ If there is no port multiplier, then specify 0xFFFF.
+ @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port
+ and PortMultiplierPort.
+ @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then non-blocking
+ I/O is performed, and Event will be signaled when the ATA command completes.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For bi-directional commands,
+ InTransferLength bytes were transferred from InDataBuffer. For write and
+ bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number of bytes that could be transferred
+ is returned in InTransferLength. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there are too many ATA commands
+ already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the ATA command.
+ @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA
+ command was not sent, so no additional status information is available.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruPassThru (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+ These can either be the list of ports where ATA devices are actually present or the
+ list of legal port numbers for the ATA controller. Regardless, the caller of this
+ function must probe the port number returned to see if an ATA device is actually
+ present at that location on the ATA controller.
+
+ The GetNextPort() function retrieves the port number on an ATA controller. If on input
+ Port is 0xFFFF, then the port number of the first port on the ATA controller is returned
+ in Port and EFI_SUCCESS is returned.
+
+ If Port is a port number that was returned on a previous call to GetNextPort(), then the
+ port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS
+ is returned. If Port is not 0xFFFF and Port was not returned on a previous call to
+ GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+ If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is
+ returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in, out] Port On input, a pointer to the port number on the ATA controller.
+ On output, a pointer to the next port number on the ATA
+ controller. An input value of 0xFFFF retrieves the first port
+ number on the ATA controller.
+
+ @retval EFI_SUCCESS The next port number on the ATA controller was returned in Port.
+ @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
+ @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call
+ to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetNextPort (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT16 *Port
+ );
+
+/**
+ Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA
+ controller. These can either be the list of port multiplier ports where ATA devices are actually
+ present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this
+ function must probe the port number and port multiplier port number returned to see if an ATA
+ device is actually present.
+
+ The GetNextDevice() function retrieves the port multiplier port number of an ATA device
+ present on a port of an ATA controller.
+
+ If PortMultiplierPort points to a port multiplier port number value that was returned on a
+ previous call to GetNextDevice(), then the port multiplier port number of the next ATA device
+ on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
+ returned.
+
+ If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first
+ ATA device on port of the ATA controller is returned in PortMultiplierPort and
+ EFI_SUCCESS is returned.
+
+ If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+ was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+ is returned.
+
+ If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of
+ the ATA controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number present on the ATA controller.
+ @param[in, out] PortMultiplierPort On input, a pointer to the port multiplier port number of an
+ ATA device present on the ATA controller.
+ If on input a PortMultiplierPort of 0xFFFF is specified,
+ then the port multiplier port number of the first ATA device
+ is returned. On output, a pointer to the port multiplier port
+ number of the next ATA device present on an ATA controller.
+
+ @retval EFI_SUCCESS The port multiplier port number of the next ATA device on the port
+ of the ATA controller was returned in PortMultiplierPort.
+ @retval EFI_NOT_FOUND There are no more ATA devices on this port of the ATA controller.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not
+ returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetNextDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN OUT UINT16 *PortMultiplierPort
+ );
+
+/**
+ Used to allocate and build a device path node for an ATA device on an ATA controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the ATA
+ device specified by Port and PortMultiplierPort. If the ATA device specified by Port and
+ PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough
+ resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,
+ and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port Port specifies the port number of the ATA device for which a
+ device path node is to be allocated and built.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device for which a
+ device path node is to be allocated and built. If there is no
+ port multiplier, then specify 0xFFFF.
+ @param[in, out] DevicePath A pointer to a single device path node that describes the ATA
+ device specified by Port and PortMultiplierPort. This function
+ is responsible for allocating the buffer DevicePath with the
+ boot service AllocatePool(). It is the caller's responsibility
+ to free DevicePath when the caller is finished with DevicePath.
+ @retval EFI_SUCCESS The device path node that describes the ATA device specified by
+ Port and PortMultiplierPort was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The ATA device specified by Port and PortMultiplierPort does not
+ exist on the ATA controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruBuildDevicePath (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Used to translate a device path node to a port number and port multiplier port number.
+
+ The GetDevice() function determines the port and port multiplier port number associated with
+ the ATA device described by DevicePath. If DevicePath is a device path node type that the
+ ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents
+ DevicePath into a port number and port multiplier port number.
+
+ If this translation is successful, then that port number and port multiplier port number are returned
+ in Port and PortMultiplierPort, and EFI_SUCCESS is returned.
+
+ If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then
+ EFI_UNSUPPORTED is returned.
+
+ If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not
+ a valid translation from DevicePath to a port number and port multiplier port number, then
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes an ATA device on the
+ ATA controller.
+ @param[out] Port On return, points to the port number of an ATA device on the ATA controller.
+ @param[out] PortMultiplierPort On return, points to the port multiplier port number of an ATA device
+ on the ATA controller.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a port number and port multiplier
+ port number, and they were returned in Port and PortMultiplierPort.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER Port is NULL.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is NULL.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier
+ port number does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruGetDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT16 *Port,
+ OUT UINT16 *PortMultiplierPort
+ );
+
+/**
+ Resets a specific port on the ATA controller. This operation also resets all the ATA devices
+ connected to the port.
+
+ The ResetChannel() function resets an a specific port on an ATA controller. This operation
+ resets all the ATA devices connected to that port. If this ATA controller does not support
+ a reset port operation, then EFI_UNSUPPORTED is returned.
+
+ If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is
+ returned.
+
+ If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.
+
+ If the port reset operation is completed, then EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port The port number on the ATA controller.
+
+ @retval EFI_SUCCESS The ATA controller port was reset.
+ @retval EFI_UNSUPPORTED The ATA controller does not support a port reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA port.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA port.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruResetPort (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port
+ );
+
+/**
+ Resets an ATA device that is connected to an ATA controller.
+
+ The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.
+ If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is
+ returned.
+
+ If Port or PortMultiplierPort are not in a valid range for this ATA controller, then
+ EFI_INVALID_PARAMETER is returned.
+
+ If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR
+ is returned.
+
+ If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is
+ returned.
+
+ If the device reset operation is completed, then EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
+ @param[in] Port Port represents the port number of the ATA device to be reset.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to reset.
+ If there is no port multiplier, then specify 0xFFFF.
+ @retval EFI_SUCCESS The ATA device specified by Port and PortMultiplierPort was reset.
+ @retval EFI_UNSUPPORTED The ATA controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA device
+ specified by Port and PortMultiplierPort.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA device
+ specified by Port and PortMultiplierPort.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPassThruResetDevice (
+ IN EFI_ATA_PASS_THRU_PROTOCOL *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort
+ );
+
+/**
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
+ supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
+ nonblocking I/O functionality is optional.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it represents
+ the id of the SCSI device to send the SCSI Request Packet. Each
+ transport driver may choose to utilize a subset of this size to suit the needs
+ of transport target representation. For example, a Fibre Channel driver
+ may use only 8 bytes (WWN) to represent an FC target.
+ @param Lun The LUN of the SCSI device to send the SCSI Request Packet.
+ @param Packet A pointer to the SCSI Request Packet to send to the SCSI device
+ specified by Target and Lun.
+ @param Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed. The number of bytes that
+ could be transferred is returned in InTransferLength. For write
+ and bi-directional commands, OutTransferLength bytes were
+ transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
+ SCSI Request Packets already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported
+ by the host adapter. This includes the case of Bi-directional SCSI
+ commands not supported by the implementation. The SCSI Request
+ Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruPassThru (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These
+ can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal
+ Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the
+ Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI
+ channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target On input, a pointer to the Target ID (an array of size
+ TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+ @param Lun On input, a pointer to the LUN of a SCSI device present on the SCSI
+ channel. On output, a pointer to the LUN of the next SCSI device present
+ on a SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID and LUN of the next SCSI device on the SCSI
+ channel was returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were
+ not returned on a previous call to GetNextTargetLun().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ );
+
+/**
+ Used to allocate and build a device path node for a SCSI device on a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it specifies the
+ Target ID of the SCSI device for which a device path node is to be
+ allocated and built. Transport drivers may chose to utilize a subset of
+ this size to suit the representation of targets. For example, a Fibre
+ Channel driver may use only 8 bytes (WWN) in the array to represent a
+ FC target.
+ @param Lun The LUN of the SCSI device for which a device path node is to be
+ allocated and built.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ specified by Target and Lun. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SCSI device specified by
+ Target and Lun was allocated and returned in
+ DevicePath.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist
+ on the SCSI channel.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Used to translate a device path node to a Target ID and LUN.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ on the SCSI channel.
+ @param Target A pointer to the Target Array which represents the ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of a SCSI device on the SCSI channel.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a Target ID and
+ LUN, and they were returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target ID and LUN
+ does not exist.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ );
+
+/**
+ Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SCSI channel was reset.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI channel.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a channel reset operation.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ );
+
+/**
+ Resets a SCSI logical unit that is connected to a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTE and it represents the
+ target port ID of the SCSI device containing the SCSI logical unit to
+ reset. Transport drivers may chose to utilize a subset of this array to suit
+ the representation of their targets.
+ @param Lun The LUN of the SCSI device to reset.
+
+ @retval EFI_SUCCESS The SCSI device specified by Target and Lun was reset.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a target reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruResetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ );
+
+/**
+ Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either
+ be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs
+ for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to
+ see if a SCSI device is actually present at that location on the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
+ channel was returned in Target.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
+ returned on a previous call to GetNextTarget().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtScsiPassThruGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ );
+
+/**
+ Initialize ATA host controller at IDE mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeModeInitialization (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ );
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciModeInitialization (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ );
+
+/**
+ Start a non data transfer on specific port.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciNonDataTransfer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+/**
+ Start a DMA data transfer on specific port
+
+ @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The DMA data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciDmaTransfer (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+/**
+ Start a PIO data transfer on specific port.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPioTransfer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+/**
+ Send ATA command into device with NON_DATA protocol
+
+ @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE
+ data structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data
+ structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaNonDataCommandIn (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+/**
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+ @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
+ structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in] 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[in] DataBuffer A pointer to the source buffer for the data.
+ @param[in] DataLength The length of the data.
+ @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @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
+EFIAPI
+AtaUdmaInOut (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN BOOLEAN Read,
+ IN VOID *DataBuffer,
+ IN UINT64 DataLength,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
+ structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in, out] Buffer A pointer to the source buffer for the data.
+ @param[in] ByteCount The length of the data.
+ @param[in] 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[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPioDataInOut (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT VOID *Buffer,
+ IN UINT64 ByteCount,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
new file mode 100644
index 000000000..a3e42a9ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
@@ -0,0 +1,74 @@
+## @file
+# AtaAtapiPassThru driver to provide native IDE/AHCI mode support.
+#
+# This driver installs AtaPassThru and ExtScsiPassThru protocol in each ide/sata controller
+# to access to all attached Ata/Atapi devices.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AtaAtapiPassThruDxe
+ MODULE_UNI_FILE = AtaAtapiPassThruDxe.uni
+ FILE_GUID = 5E523CB4-D397-4986-87BD-A6DD8B22F455
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeAtaAtapiPassThru
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gAtaAtapiPassThruDriverBinding
+# COMPONENT_NAME = gAtaAtapiPassThruComponentName
+# COMPONENT_NAME2 = gAtaAtapiPassThruComponentName2
+#
+#
+
+[Sources]
+ AtaAtapiPassThru.c
+ AtaAtapiPassThru.h
+ AhciMode.c
+ AhciMode.h
+ IdeMode.c
+ IdeMode.h
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+ TimerLib
+ ReportStatusCodeLib
+ PcdLib
+
+[Protocols]
+ gEfiAtaPassThruProtocolGuid ## BY_START
+ gEfiExtScsiPassThruProtocolGuid ## BY_START
+ gEfiIdeControllerInitProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEdkiiAtaAtapiPolicyProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAtaSmartEnable ## SOMETIMES_CONSUMES
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AtaAtapiPassThruDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxe.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxe.uni
new file mode 100644
index 000000000..2223779b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// AtaAtapiPassThru driver to provide native IDE/AHCI mode support.
+//
+// This driver installs AtaPassThru and ExtScsiPassThru protocol in each ide/sata controller
+// to access to all attached Ata/Atapi devices.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "AtaAtapiPassThru driver to provide native IDE/AHCI mode support."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver installs AtaPassThru and ExtScsiPassThru protocols in each IDE/SATA controller to access to all attached ATA/ATAPI devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxeExtra.uni
new file mode 100644
index 000000000..f64154c9f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThruDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// AtaAtapiPassThruDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ATA ATAPI Pass Thru DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c
new file mode 100644
index 000000000..663f777e1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c
@@ -0,0 +1,245 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for AtaAtapiPassThru driver.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtaAtapiPassThru.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruDriverNameTable[] = {
+ { "eng;en", L"AtaAtapiPassThru Driver" },
+ { NULL , NULL }
+};
+
+//
+// Controller name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruIdeControllerNameTable[] = {
+ { "eng;en", L"IDE Controller" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruAhciControllerNameTable[] = {
+ { "eng;en", L"AHCI Controller" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gAtaAtapiPassThruComponentName = {
+ AtaAtapiPassThruComponentNameGetDriverName,
+ AtaAtapiPassThruComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtaAtapiPassThruComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtaAtapiPassThruComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtaAtapiPassThruComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+AtaAtapiPassThruComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mAtaAtapiPassThruDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gAtaAtapiPassThruComponentName)
+ );
+}
+
+
+/**
+ 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
+AtaAtapiPassThruComponentNameGetControllerName (
+ 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_UNICODE_STRING_TABLE *ControllerNameTable;
+ VOID *Interface;
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+
+ 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;
+ }
+
+ //
+ // Make sure this driver is currently managing Controller Handle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gAtaAtapiPassThruDriverBinding.DriverBindingHandle,
+ &gEfiIdeControllerInitProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // AtaPassThru and ExtScsiPassThru should also be installed at the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiAtaPassThruProtocolGuid,
+ &Interface,
+ gAtaAtapiPassThruDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (Interface);
+
+ if (Instance->Mode == EfiAtaIdeMode) {
+ ControllerNameTable = mAtaAtapiPassThruIdeControllerNameTable;
+ } else if (Instance->Mode == EfiAtaAhciMode) {
+ ControllerNameTable = mAtaAtapiPassThruAhciControllerNameTable;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gAtaAtapiPassThruComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
new file mode 100644
index 000000000..d284cc600
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
@@ -0,0 +1,2661 @@
+/** @file
+ Header file for AHCI mode of ATA host controller.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtaAtapiPassThru.h"
+
+/**
+ read a one-byte data from a IDE port.
+
+ @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port The IDE Port number
+
+ @return the one-byte data read from IDE port
+**/
+UINT8
+EFIAPI
+IdeReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+{
+ UINT8 Data;
+
+ ASSERT (PciIo != NULL);
+
+ 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;
+}
+
+/**
+ write a 1-byte data to a specific IDE port.
+
+ @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port The IDE port to be written
+ @param Data The data to write to the port
+**/
+VOID
+EFIAPI
+IdeWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+{
+ ASSERT (PciIo != NULL);
+
+ //
+ // 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 A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port The IDE port to be written
+ @param Data The data to write to the port
+**/
+VOID
+EFIAPI
+IdeWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+{
+ ASSERT (PciIo != NULL);
+
+ //
+ // perform 1-word data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+}
+
+/**
+ write a 2-word data to a specific IDE port.
+
+ @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port The IDE port to be written
+ @param Data The data to write to the port
+**/
+VOID
+EFIAPI
+IdeWritePortDW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT32 Data
+ )
+{
+ ASSERT (PciIo != NULL);
+
+ //
+ // perform 2-word data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 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 A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+EFIAPI
+IdeWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (PciIo != NULL);
+ ASSERT (Buffer != NULL);
+
+ //
+ // perform UINT16 data write to the FIFO
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16 *) Buffer
+ );
+
+}
+
+/**
+ 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 A pointer to EFI_PCI_IO_PROTOCOL data structure
+ @param Port IO port to read
+ @param Count Number of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+EFIAPI
+IdeReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (PciIo != NULL);
+ ASSERT (Buffer != NULL);
+
+ //
+ // Perform UINT16 data read from FIFO
+ //
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16 *) Buffer
+ );
+
+}
+
+/**
+ 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 PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+DumpAllIdeRegisters (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_ATA_STATUS_BLOCK StatusBlock;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ ZeroMem (&StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ StatusBlock.AtaStatus = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);
+ StatusBlock.AtaError = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);
+ StatusBlock.AtaSectorCount = IdeReadPortB (PciIo, IdeRegisters->SectorCount);
+ StatusBlock.AtaSectorCountExp = IdeReadPortB (PciIo, IdeRegisters->SectorCount);
+ StatusBlock.AtaSectorNumber = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);
+ StatusBlock.AtaSectorNumberExp = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);
+ StatusBlock.AtaCylinderLow = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);
+ StatusBlock.AtaCylinderLowExp = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);
+ StatusBlock.AtaCylinderHigh = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);
+ StatusBlock.AtaCylinderHighExp = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);
+ StatusBlock.AtaDeviceHead = IdeReadPortB (PciIo, IdeRegisters->Head);
+
+ if (AtaStatusBlock != NULL) {
+ //
+ // Dump the content of all ATA registers.
+ //
+ CopyMem (AtaStatusBlock, &StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+ }
+
+ DEBUG_CODE_BEGIN ();
+ if ((StatusBlock.AtaStatus & ATA_STSREG_DWF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", StatusBlock.AtaStatus));
+ }
+
+ if ((StatusBlock.AtaStatus & ATA_STSREG_CORR) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", StatusBlock.AtaStatus));
+ }
+
+ if ((StatusBlock.AtaStatus & ATA_STSREG_ERR) != 0) {
+ if ((StatusBlock.AtaError & ATA_ERRREG_BBK) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", StatusBlock.AtaError));
+ }
+
+ if ((StatusBlock.AtaError & ATA_ERRREG_UNC) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", StatusBlock.AtaError));
+ }
+
+ if ((StatusBlock.AtaError & ATA_ERRREG_MC) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", StatusBlock.AtaError));
+ }
+
+ if ((StatusBlock.AtaError & ATA_ERRREG_ABRT) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", StatusBlock.AtaError));
+ }
+
+ if ((StatusBlock.AtaError & ATA_ERRREG_TK0NF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", StatusBlock.AtaError));
+ }
+
+ if ((StatusBlock.AtaError & ATA_ERRREG_AMNF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", StatusBlock.AtaError));
+ }
+ }
+ DEBUG_CODE_END ();
+}
+
+/**
+ This function is used to analyze the Status Register at the condition that BSY is zero.
+ if there is ERR bit set in the Status Register, then return error.
+
+ @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+
+ @retval EFI_SUCCESS No err information in the Status Register.
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckStatusRegister (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ UINT8 StatusRegister;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);
+
+ if ((StatusRegister & ATA_STSREG_BSY) == 0) {
+ if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @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
+EFIAPI
+DRQClear (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT8 StatusRegister;
+ BOOLEAN InfiniteWait;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+ do {
+ StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);
+
+ //
+ // Wait for BSY == 0, then judge if DRQ is clear
+ //
+ if ((StatusRegister & ATA_STSREG_BSY) == 0) {
+ if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+/**
+ 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 PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @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
+EFIAPI
+DRQClear2 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT8 AltRegister;
+ BOOLEAN InfiniteWait;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+ do {
+ AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
+
+ //
+ // Wait for BSY == 0, then judge if DRQ is clear
+ //
+ if ((AltRegister & ATA_STSREG_BSY) == 0) {
+ if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ 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 PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the
+ timeout.
+
+ @retval EFI_TIMEOUT BSY bit not cleared within the timeout.
+
+ @retval EFI_ABORTED Polling abandoned due to command abort.
+
+ @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.
+
+ @retval EFI_NOT_READY BSY bit cleared within timeout, and device
+ reported "command complete" by clearing DRQ
+ bit.
+
+ @note Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+EFIAPI
+DRQReady (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+ BOOLEAN InfiniteWait;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+ do {
+ //
+ // Read Status Register will clear interrupt
+ //
+ StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);
+
+ //
+ // Wait for BSY == 0, then judge if DRQ is clear or ERR is set
+ //
+ if ((StatusRegister & ATA_STSREG_BSY) == 0) {
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);
+
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+/**
+ 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 PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the
+ timeout.
+
+ @retval EFI_TIMEOUT BSY bit not cleared within the timeout.
+
+ @retval EFI_ABORTED Polling abandoned due to command abort.
+
+ @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.
+
+ @retval EFI_NOT_READY BSY bit cleared within timeout, and device
+ reported "command complete" by clearing DRQ
+ bit.
+
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+EFIAPI
+DRQReady2 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+ BOOLEAN InfiniteWait;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+
+ do {
+ //
+ // Read Alternate Status Register will not clear interrupt status
+ //
+ AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
+ //
+ // Wait for BSY == 0, then judge if DRQ is clear or ERR is set
+ //
+ if ((AltRegister & ATA_STSREG_BSY) == 0) {
+ if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);
+
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+
+
+
+/**
+ 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 PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @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
+EFIAPI
+WaitForBSYClear (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Delay;
+ UINT8 StatusRegister;
+ BOOLEAN InfiniteWait;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32(Timeout, 1000) + 1;
+ do {
+ StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);
+
+ if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Get IDE i/o 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 i/o 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.
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+
+ 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.
+ ___________________________________________________
+ | | 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
+
+ @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o 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 configuration data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetIdeRegisterIoAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN OUT EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINT16 BusMasterBaseAddr;
+
+ if ((PciIo == NULL) || (IdeRegisters == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusMasterBaseAddr = (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
+ CommandBlockBaseAddr = 0x1f0;
+ ControlBlockBaseAddr = 0x3f6;
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[0] & BIT0) == 0 ||
+ (PciData.Device.Bar[1] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
+ ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
+ }
+
+ //
+ // Calculate IDE primary channel I/O register base address.
+ //
+ IdeRegisters[EfiIdePrimary].Data = CommandBlockBaseAddr;
+ IdeRegisters[EfiIdePrimary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeRegisters[EfiIdePrimary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeRegisters[EfiIdePrimary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeRegisters[EfiIdePrimary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeRegisters[EfiIdePrimary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeRegisters[EfiIdePrimary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ IdeRegisters[EfiIdePrimary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);
+ IdeRegisters[EfiIdePrimary].AltOrDev = ControlBlockBaseAddr;
+ IdeRegisters[EfiIdePrimary].BusMasterBaseAddr = BusMasterBaseAddr;
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
+ CommandBlockBaseAddr = 0x170;
+ ControlBlockBaseAddr = 0x376;
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[2] & BIT0) == 0 ||
+ (PciData.Device.Bar[3] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
+ ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
+ }
+
+ //
+ // Calculate IDE secondary channel I/O register base address.
+ //
+ IdeRegisters[EfiIdeSecondary].Data = CommandBlockBaseAddr;
+ IdeRegisters[EfiIdeSecondary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeRegisters[EfiIdeSecondary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeRegisters[EfiIdeSecondary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeRegisters[EfiIdeSecondary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeRegisters[EfiIdeSecondary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeRegisters[EfiIdeSecondary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ IdeRegisters[EfiIdeSecondary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);
+ IdeRegisters[EfiIdeSecondary].AltOrDev = ControlBlockBaseAddr;
+ IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = (UINT16) (BusMasterBaseAddr + 0x8);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol.
+
+ @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.
+ @param Timeout The time to complete the command, uses 100ns as a unit.
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaIssueCommand (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceHead;
+ UINT8 AtaCommand;
+
+ ASSERT (PciIo != NULL);
+ ASSERT (IdeRegisters != NULL);
+ ASSERT (AtaCommandBlock != NULL);
+
+ DeviceHead = AtaCommandBlock->AtaDeviceHead;
+ AtaCommand = AtaCommandBlock->AtaCommand;
+
+ Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);
+ IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);
+ IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);
+ IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);
+
+ IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);
+ IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);
+
+ IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);
+ IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, AtaCommand);
+
+ //
+ // Stall at least 400 microseconds.
+ //
+ MicroSecondDelay (400);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
+ structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in, out] Buffer A pointer to the source buffer for the data.
+ @param[in] ByteCount The length of the data.
+ @param[in] 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[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPioDataInOut (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT VOID *Buffer,
+ IN UINT64 ByteCount,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ if ((PciIo == NULL) || (IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Issue ATA command
+ //
+ Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ 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 transferred data
+ //
+ WordCount = 0;
+
+ while (WordCount < RShiftU64(ByteCount, 1)) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready
+ //
+ Status = DRQReady2 (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {
+ Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);
+ }
+
+ if (Read) {
+ IdeReadPortWMultiple (
+ PciIo,
+ IdeRegisters->Data,
+ Increment,
+ Buffer16
+ );
+ } else {
+ IdeWritePortWMultiple (
+ PciIo,
+ IdeRegisters->Data,
+ Increment,
+ Buffer16
+ );
+ }
+
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+ }
+
+ Status = DRQClear (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+Exit:
+ //
+ // Dump All Ide registers to ATA_STATUS_BLOCK
+ //
+ DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);
+
+ //
+ // Not support the Non-blocking now,just do the blocking process.
+ //
+ return Status;
+}
+
+/**
+ Send ATA command into device with NON_DATA protocol
+
+ @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE
+ data structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data
+ structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaNonDataCommandIn (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+
+ if ((PciIo == NULL) || (IdeRegisters == NULL) || (AtaCommandBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Issue ATA command
+ //
+ Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Wait for command completion
+ //
+ Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+Exit:
+ //
+ // Dump All Ide registers to ATA_STATUS_BLOCK
+ //
+ DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);
+
+ //
+ // Not support the Non-blocking now,just do the blocking process.
+ //
+ return Status;
+}
+
+/**
+ Wait for memory to be set.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR The memory is not set.
+ @retval EFI_TIMEOUT The memory setting is time out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+AtaUdmStatusWait (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT8 RegisterValue;
+ EFI_STATUS Status;
+ UINT16 IoPortForBmis;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+
+ do {
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);
+ RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);
+ if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {
+ DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ if ((RegisterValue & BMIS_INTERRUPT) != 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+ Delay--;
+ } while (InfiniteWait || (Delay > 0));
+
+ return Status;
+}
+
+/**
+ Check if the memory to be set.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+
+ @retval EFI_DEVICE_ERROR The memory setting met a issue.
+ @retval EFI_NOT_READY The memory is not set.
+ @retval EFI_TIMEOUT The memory setting is time out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+AtaUdmStatusCheck (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN ATA_NONBLOCK_TASK *Task,
+ IN EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ UINT8 RegisterValue;
+ UINT16 IoPortForBmis;
+ EFI_STATUS Status;
+
+ Task->RetryTimes--;
+
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);
+ RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);
+
+ if ((RegisterValue & BMIS_ERROR) != 0) {
+ DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((RegisterValue & BMIS_INTERRUPT) != 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {
+ return EFI_TIMEOUT;
+ } else {
+ //
+ // The memory is not set.
+ //
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+ @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
+ structure.
+ @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @param[in] 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[in] DataBuffer A pointer to the source buffer for the data.
+ @param[in] DataLength The length of the data.
+ @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.
+ @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
+
+ @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
+EFIAPI
+AtaUdmaInOut (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN BOOLEAN Read,
+ IN VOID *DataBuffer,
+ IN UINT64 DataLength,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IoPortForBmic;
+ UINT16 IoPortForBmis;
+ UINT16 IoPortForBmid;
+
+ UINTN PrdTableSize;
+ EFI_PHYSICAL_ADDRESS PrdTableMapAddr;
+ VOID *PrdTableMap;
+ EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;
+ EFI_ATA_DMA_PRD *TempPrdBaseAddr;
+ UINTN PrdTableNum;
+
+ UINT8 RegisterValue;
+ UINTN PageCount;
+ UINTN ByteCount;
+ UINTN ByteRemaining;
+ UINT8 DeviceControl;
+
+ VOID *BufferMap;
+ EFI_PHYSICAL_ADDRESS BufferMapAddress;
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;
+
+ UINT8 DeviceHead;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_TPL OldTpl;
+
+ UINTN AlignmentMask;
+ UINTN RealPageCount;
+ EFI_PHYSICAL_ADDRESS BaseAddr;
+ EFI_PHYSICAL_ADDRESS BaseMapAddr;
+
+ Status = EFI_SUCCESS;
+ PrdTableMap = NULL;
+ BufferMap = NULL;
+ PageCount = 0;
+ RealPageCount = 0;
+ BaseAddr = 0;
+ PciIo = Instance->PciIo;
+
+ if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Before starting the Blocking BlockIO operation, push to finish all non-blocking
+ // BlockIO tasks.
+ // Delay 1ms to simulate the blocking time out checking.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {
+ AsyncNonBlockingTransferRoutine (NULL, Instance);
+ //
+ // Stall for 1 milliseconds.
+ //
+ MicroSecondDelay (1000);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // The data buffer should be even alignment
+ //
+ if (((UINTN)DataBuffer & 0x1) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Set relevant IO Port address.
+ //
+ IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);
+ IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);
+ IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);
+
+ //
+ // For Blocking mode, start the command.
+ // For non-blocking mode, when the command is not started, start it, otherwise
+ // go to check the status.
+ //
+ if (((Task != NULL) && (!Task->IsStart)) || (Task == NULL)) {
+ //
+ // Calculate the number of PRD entry.
+ // Every entry in PRD table can specify a 64K memory region.
+ //
+ PrdTableNum = (UINTN)(RShiftU64(DataLength, 16) + 1);
+
+ //
+ // Make sure that the memory region of PRD table is not cross 64K boundary
+ //
+ PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);
+ if (PrdTableSize > 0x10000) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate buffer for PRD table initialization.
+ // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte
+ // boundary and the table cannot cross a 64K boundary in memory.
+ //
+ PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);
+ RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);
+
+ //
+ // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.
+ //
+ ASSERT (RealPageCount > PageCount);
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ RealPageCount,
+ (VOID **)&BaseAddr,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ (VOID*)(UINTN)BaseAddr,
+ &ByteCount,
+ &BaseMapAddr,
+ &PrdTableMap
+ );
+ if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {
+ //
+ // If the data length actually mapped is not equal to the requested amount,
+ // it means the DMA operation may be broken into several discontinuous smaller chunks.
+ // Can't handle this case.
+ //
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);
+
+ //
+ // Calculate the 64K align address as PRD Table base address.
+ //
+ AlignmentMask = SIZE_64KB - 1;
+ PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;
+ PrdTableMapAddr = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;
+
+ //
+ // Map the host address of DataBuffer to DMA master address.
+ //
+ if (Read) {
+ PciIoOperation = EfiPciIoOperationBusMasterWrite;
+ } else {
+ PciIoOperation = EfiPciIoOperationBusMasterRead;
+ }
+
+ ByteCount = (UINTN)DataLength;
+ Status = PciIo->Map (
+ PciIo,
+ PciIoOperation,
+ DataBuffer,
+ &ByteCount,
+ &BufferMapAddress,
+ &BufferMap
+ );
+ if (EFI_ERROR (Status) || (ByteCount != DataLength)) {
+ PciIo->Unmap (PciIo, PrdTableMap);
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // According to Ata spec, it requires the buffer address and size to be even.
+ //
+ ASSERT ((BufferMapAddress & 0x1) == 0);
+ ASSERT ((ByteCount & 0x1) == 0);
+
+ //
+ // Fill the PRD table with appropriate bus master address of data buffer and data length.
+ //
+ ByteRemaining = ByteCount;
+ TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;
+ while (ByteRemaining != 0) {
+ if (ByteRemaining <= 0x10000) {
+ TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
+ TempPrdBaseAddr->ByteCount = (UINT16) ByteRemaining;
+ TempPrdBaseAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
+ TempPrdBaseAddr->ByteCount = (UINT16) 0x0;
+
+ ByteRemaining -= 0x10000;
+ BufferMapAddress += 0x10000;
+ TempPrdBaseAddr++;
+ }
+
+ //
+ // Start to enable the DMA operation
+ //
+ DeviceHead = AtaCommandBlock->AtaDeviceHead;
+
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));
+
+ //
+ // Enable interrupt to support UDMA
+ //
+ DeviceControl = 0;
+ IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ RegisterValue = IdeReadPortB(PciIo, IoPortForBmis);
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+ IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);
+ if (Read) {
+ RegisterValue |= BMIC_NREAD;
+ } else {
+ RegisterValue &= ~((UINT8) BMIC_NREAD);
+ }
+ IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);
+
+ if (Task != NULL) {
+ Task->Map = BufferMap;
+ Task->TableMap = PrdTableMap;
+ Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;
+ Task->PageCount = RealPageCount;
+ Task->IsStart = TRUE;
+ }
+
+ //
+ // Issue ATA command
+ //
+ Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Set START bit of BMIC register
+ //
+ RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);
+ RegisterValue |= BMIC_START;
+ IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);
+
+ }
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ //
+ if (Task != NULL) {
+ Status = AtaUdmStatusCheck (PciIo, Task, IdeRegisters);
+ } else {
+ Status = AtaUdmStatusWait (PciIo, IdeRegisters, Timeout);
+ }
+
+ //
+ // For blocking mode, clear registers and free buffers.
+ // For non blocking mode, when the related registers have been set or time
+ // out, or a error has been happened, it needs to clear the register and free
+ // buffer.
+ //
+ if ((Task == NULL) || Status != EFI_NOT_READY) {
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+ IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);
+
+ //
+ // Read Status Register of IDE device to clear interrupt
+ //
+ RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);
+
+ //
+ // Clear START bit of BMIC register
+ //
+ RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);
+ RegisterValue &= ~((UINT8) BMIC_START);
+ IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);
+
+ //
+ // Disable interrupt of Select device
+ //
+ DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
+ DeviceControl |= ATA_CTLREG_IEN_L;
+ IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);
+ //
+ // Stall for 10 milliseconds.
+ //
+ MicroSecondDelay (10000);
+
+ }
+
+Exit:
+ //
+ // Free all allocated resource
+ //
+ if ((Task == NULL) || Status != EFI_NOT_READY) {
+ if (Task != NULL) {
+ PciIo->Unmap (PciIo, Task->TableMap);
+ PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress);
+ PciIo->Unmap (PciIo, Task->Map);
+ } else {
+ PciIo->Unmap (PciIo, PrdTableMap);
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
+ PciIo->Unmap (PciIo, BufferMap);
+ }
+
+ //
+ // Dump All Ide registers to ATA_STATUS_BLOCK
+ //
+ DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);
+ }
+
+ return Status;
+}
+
+/**
+ This function reads the pending data in the device.
+
+ @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+
+ @retval EFI_SUCCESS Successfully read.
+ @retval EFI_NOT_READY The BSY is set avoiding reading.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPacketReadPendingData (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ UINT8 AltRegister;
+ UINT16 TempWordBuffer;
+
+ AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
+ 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 (PciIo, IdeRegisters->AltOrDev);
+ while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ IdeReadPortWMultiple (
+ PciIo,
+ IdeRegisters->Data,
+ 1,
+ &TempWordBuffer
+ );
+ TempWordBuffer = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called by AtaPacketCommandExecute().
+ It is used to transfer data between host and device. The data direction is specified
+ by the fourth parameter.
+
+ @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
+ @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
+ , uses 100ns as a unit.
+
+ @retval EFI_SUCCESS data is transferred successfully.
+ @retval EFI_DEVICE_ERROR the device failed to transfer data.
+**/
+EFI_STATUS
+EFIAPI
+AtaPacketReadWrite (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *ByteCount,
+ IN BOOLEAN Read,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 RequiredWordCount;
+ UINT32 ActualWordCount;
+ UINT32 WordCount;
+ EFI_STATUS Status;
+ UINT16 *PtrBuffer;
+
+ PtrBuffer = Buffer;
+ RequiredWordCount = *ByteCount >> 1;
+
+ //
+ // No data transfer is permitted.
+ //
+ if (RequiredWordCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ActualWordCount 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 (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_READY) {
+ //
+ // Device provided less data than we intended to read, or wanted less
+ // data than we intended to write, but it may still be successful.
+ //
+ break;
+ } else {
+ return Status;
+ }
+ }
+
+ //
+ // get current data transfer size from Cylinder Registers.
+ //
+ WordCount = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb) << 8;
+ WordCount = WordCount | IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);
+ WordCount = WordCount & 0xffff;
+ WordCount /= 2;
+
+ WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));
+
+ if (Read) {
+ IdeReadPortWMultiple (
+ PciIo,
+ IdeRegisters->Data,
+ WordCount,
+ PtrBuffer
+ );
+ } else {
+ IdeWritePortWMultiple (
+ PciIo,
+ IdeRegisters->Data,
+ WordCount,
+ PtrBuffer
+ );
+ }
+
+ //
+ // read status register to check whether error happens.
+ //
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ 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.
+ //
+ AtaPacketReadPendingData (PciIo, IdeRegisters);
+ }
+
+ //
+ // read status register to check whether error happens.
+ //
+ Status = CheckStatusRegister (PciIo, IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // After data transfer is completed, normally, DRQ bit should clear.
+ //
+ Status = DRQClear (PciIo, IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *ByteCount = ActualWordCount << 1;
+ return Status;
+}
+
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Data In Protocol.
+
+ @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o port registers' base addresses
+ @param[in] Channel The channel number of device.
+ @param[in] Device The device number of device.
+ @param[in] Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
+
+ @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
+EFIAPI
+AtaPacketCommandExecute (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ EFI_STATUS Status;
+ UINT8 Count;
+ UINT8 PacketCommand[12];
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ //
+ // Fill ATAPI Command Packet according to CDB.
+ // For Atapi cmd, its length should be less than or equal to 12 bytes.
+ //
+ if (Packet->CdbLength > 12) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (PacketCommand, 12);
+ CopyMem (PacketCommand, Packet->Cdb, Packet->CdbLength);
+
+ //
+ // No OVL; No DMA
+ //
+ AtaCommandBlock.AtaFeatures = 0x00;
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
+ // determine how many data should be transferred.
+ //
+ AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);
+ AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);
+ AtaCommandBlock.AtaDeviceHead = (UINT8) (Device << 0x4);
+ AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;
+
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | (Device << 0x4)));
+ //
+ // Disable interrupt
+ //
+ IdeWritePortB (PciIo, IdeRegisters->AltOrDev, ATA_DEFAULT_CTL);
+
+ //
+ // Issue ATA PACKET command firstly
+ //
+ Status = AtaIssueCommand (PciIo, IdeRegisters, &AtaCommandBlock, Packet->Timeout);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DRQReady (PciIo, IdeRegisters, Packet->Timeout);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Send out ATAPI command packet
+ //
+ for (Count = 0; Count < 6; Count++) {
+ IdeWritePortW (PciIo, IdeRegisters->Data, *((UINT16*)PacketCommand + Count));
+ //
+ // Stall for 10 microseconds.
+ //
+ MicroSecondDelay (10);
+ }
+
+ //
+ // Read/Write the data of ATAPI Command
+ //
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ Status = AtaPacketReadWrite (
+ PciIo,
+ IdeRegisters,
+ Packet->InDataBuffer,
+ &Packet->InTransferLength,
+ TRUE,
+ Packet->Timeout
+ );
+ } else {
+ Status = AtaPacketReadWrite (
+ PciIo,
+ IdeRegisters,
+ Packet->OutDataBuffer,
+ &Packet->OutTransferLength,
+ FALSE,
+ Packet->Timeout
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Set the calculated Best transfer mode to a detected device.
+
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param TransferMode A pointer to EFI_ATA_TRANSFER_MODE data structure.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Set transfer mode successfully.
+ @retval EFI_DEVICE_ERROR Set transfer mode failed.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDeviceTransferMode (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_TRANSFER_MODE *TransferMode,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;
+ AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
+ AtaCommandBlock.AtaFeatures = 0x03;
+ AtaCommandBlock.AtaSectorCount = *((UINT8 *)TransferMode);
+
+ //
+ // Send SET FEATURE command (sub command 0x03) to set pio mode.
+ //
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Set drive parameters for devices not support PACKETS command.
+
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param DriveParameters A pointer to EFI_ATA_DRIVE_PARMS data structure.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Set drive parameter successfully.
+ @retval EFI_DEVICE_ERROR Set drive parameter failed.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDriveParameters (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_DRIVE_PARMS *DriveParameters,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_INIT_DRIVE_PARAM;
+ AtaCommandBlock.AtaSectorCount = DriveParameters->Sector;
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) + DriveParameters->Heads);
+
+ //
+ // Send Init drive parameters
+ //
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ //
+ // Send Set Multiple parameters
+ //
+ AtaCommandBlock.AtaCommand = ATA_CMD_SET_MULTIPLE_MODE;
+ AtaCommandBlock.AtaSectorCount = DriveParameters->MultipleSector;
+ AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
+
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
+
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
+ @retval Others Fail to get return status data.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeAtaSmartReturnStatusCheck (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
+
+ //
+ // Send S.M.A.R.T Read Return Status command to device
+ //
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+ );
+
+ LBAMid = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);
+ LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);
+
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+ //
+ // The threshold exceeded condition is not detected by the device
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
+ 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
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable SMART command of the disk if supported.
+
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+IdeAtaSmartSupport (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_IDENTIFY_DATA *IdentifyData,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ //
+ // Detect if the device supports S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+ //
+ // S.M.A.R.T is not supported by the device
+ //
+ DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at [%a] channel [%a] device!\n",
+ (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+ );
+ } else {
+ //
+ // Check if the feature is enabled. If not, then enable S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)
+ );
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
+
+ //
+ // Send S.M.A.R.T Enable command to device
+ //
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Send S.M.A.R.T AutoSave command to device
+ //
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = 0xD2;
+ AtaCommandBlock.AtaSectorCount = 0xF1;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
+
+ Status = AtaNonDataCommandIn (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = IdeAtaSmartReturnStatusCheck (
+ Instance,
+ Channel,
+ Device,
+ AtaStatusBlock
+ );
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n",
+ (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));
+
+ }
+
+ 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 Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaIdentify (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN OUT EFI_IDENTIFY_DATA *Buffer,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
+
+ Status = AtaPioDataInOut (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ Buffer,
+ sizeof (EFI_IDENTIFY_DATA),
+ TRUE,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ 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 Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Identify ATAPI device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Packet Device Command failed or device type
+ is not supported by this IDE driver.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaIdentifyPacket (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN OUT EFI_IDENTIFY_DATA *Buffer,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;
+ AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
+
+ //
+ // Send ATAPI Identify Command to get IDENTIFY data.
+ //
+ Status = AtaPioDataInOut (
+ Instance->PciIo,
+ &Instance->IdeRegisters[Channel],
+ (VOID *) Buffer,
+ sizeof (EFI_IDENTIFY_DATA),
+ TRUE,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ return Status;
+}
+
+
+/**
+ This function 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 Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
+ @param IdeChannel The channel number of device.
+
+ @retval EFI_SUCCESS successfully detects device.
+ @retval other any failure during detection process will return this value.
+
+**/
+EFI_STATUS
+EFIAPI
+DetectAndConfigIdeDevice (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
+ IN UINT8 IdeChannel
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SectorCountReg;
+ UINT8 LBALowReg;
+ UINT8 LBAMidReg;
+ UINT8 LBAHighReg;
+ EFI_ATA_DEVICE_TYPE DeviceType;
+ UINT8 IdeDevice;
+ EFI_IDE_REGISTERS *IdeRegisters;
+ EFI_IDENTIFY_DATA Buffer;
+
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ EFI_ATA_COLLECTIVE_MODE *SupportedModes;
+ EFI_ATA_TRANSFER_MODE TransferMode;
+ EFI_ATA_DRIVE_PARMS DriveParameters;
+
+ IdeRegisters = &Instance->IdeRegisters[IdeChannel];
+ IdeInit = Instance->IdeControllerInit;
+ PciIo = Instance->PciIo;
+
+ for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {
+ //
+ // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.
+ //
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));
+
+ //
+ // Send ATA Device Execut Diagnostic command.
+ // This command should work no matter DRDY is ready or not
+ //
+ IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, ATA_CMD_EXEC_DRIVE_DIAG);
+
+ Status = WaitForBSYClear (PciIo, IdeRegisters, 350000000);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
+ continue;
+ }
+
+ //
+ // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.
+ //
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));
+ //
+ // Stall for 1 milliseconds.
+ //
+ MicroSecondDelay (1000);
+
+ SectorCountReg = IdeReadPortB (PciIo, IdeRegisters->SectorCount);
+ LBALowReg = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);
+ LBAMidReg = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);
+ LBAHighReg = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);
+
+ //
+ // Refer to ATA/ATAPI 4 Spec, section 9.1
+ //
+ if ((SectorCountReg == 0x1) && (LBALowReg == 0x1) && (LBAMidReg == 0x0) && (LBAHighReg == 0x0)) {
+ DeviceType = EfiIdeHarddisk;
+ } else if ((LBAMidReg == 0x14) && (LBAHighReg == 0xeb)) {
+ DeviceType = EfiIdeCdrom;
+ } else {
+ continue;
+ }
+
+ //
+ // Send IDENTIFY cmd to the device to test if it is really attached.
+ //
+ if (DeviceType == EfiIdeHarddisk) {
+ Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);
+ //
+ // if identifying ata device is failure, then try to send identify packet cmd.
+ //
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
+
+ DeviceType = EfiIdeCdrom;
+ Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);
+ }
+ } else {
+ Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);
+ //
+ // if identifying atapi device is failure, then try to send identify cmd.
+ //
+ if (EFI_ERROR (Status)) {
+ DeviceType = EfiIdeHarddisk;
+ Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No device is found at this port
+ //
+ continue;
+ }
+
+ DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n",
+ (IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",
+ DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));
+ //
+ // If the device is a hard disk, then try to enable S.M.A.R.T feature
+ //
+ if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {
+ IdeAtaSmartSupport (
+ Instance,
+ IdeChannel,
+ IdeDevice,
+ &Buffer,
+ NULL
+ );
+ }
+
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &Buffer);
+
+ //
+ // Now start to config ide device parameter and transfer mode.
+ //
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ IdeChannel,
+ IdeDevice,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ if (SupportedModes->ExtModeCount == 0){
+ Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+ }
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can'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 = EFI_ATA_MODE_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+ }
+
+ //
+ // Set Parameters for the device:
+ // 1) Init
+ // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command
+ //
+ if (DeviceType == EfiIdeHarddisk) {
+ //
+ // Init driver parameters
+ //
+ DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;
+ DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);
+ DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;
+
+ Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);
+ }
+
+ //
+ // Set IDE controller Timing Blocks in the PCI Configuration Space
+ //
+ IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);
+
+ //
+ // IDE controller and IDE device timing is configured successfully.
+ // Now insert the device into device list.
+ //
+ Status = CreateNewDeviceInfo (Instance, IdeChannel, IdeDevice, DeviceType, &Buffer);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DeviceType == EfiIdeHarddisk) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize ATA host controller at IDE mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeModeInitialization (
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Channel;
+ UINT8 IdeChannel;
+ BOOLEAN ChannelEnabled;
+ UINT8 MaxDevices;
+
+ IdeInit = Instance->IdeControllerInit;
+ PciIo = Instance->PciIo;
+ Channel = IdeInit->ChannelCount;
+
+ //
+ // Obtain IDE IO port registers' base addresses
+ //
+ Status = GetIdeRegisterIoAddr (PciIo, Instance->IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ for (IdeChannel = 0; IdeChannel < Channel; IdeChannel++) {
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);
+
+ //
+ // now obtain channel information fron IdeControllerInit protocol.
+ //
+ Status = IdeInit->GetChannelInfo (
+ IdeInit,
+ IdeChannel,
+ &ChannelEnabled,
+ &MaxDevices
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));
+ continue;
+ }
+
+ if (!ChannelEnabled) {
+ continue;
+ }
+
+ ASSERT (MaxDevices <= 2);
+ //
+ // Now inform the IDE Controller Init Module.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);
+
+ //
+ // No reset channel function implemented.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);
+
+ //
+ // Now inform the IDE Controller Init Module.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, IdeChannel);
+
+ //
+ // Detect all attached ATA devices and set the transfer mode for each device.
+ //
+ DetectAndConfigIdeDevice (Instance, IdeChannel);
+ }
+
+ //
+ // 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);
+
+ErrorExit:
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h
new file mode 100644
index 000000000..c39ebd066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h
@@ -0,0 +1,198 @@
+/** @file
+ Header file for IDE mode of ATA host controller.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __ATA_HC_IDE_MODE_H__
+#define __ATA_HC_IDE_MODE_H__
+
+typedef enum {
+ EfiIdePrimary = 0,
+ EfiIdeSecondary = 1,
+ EfiIdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+ EfiIdeMaster = 0,
+ EfiIdeSlave = 1,
+ EfiIdeMaxDevice = 2
+} EFI_IDE_DEVICE;
+
+///
+/// PIO mode definition
+///
+typedef enum {
+ EfiAtaPioModeBelow2,
+ EfiAtaPioMode2,
+ EfiAtaPioMode3,
+ EfiAtaPioMode4
+} EFI_ATA_PIO_MODE;
+
+//
+// Multi word DMA definition
+//
+typedef enum {
+ EfiAtaMdmaMode0,
+ EfiAtaMdmaMode1,
+ EfiAtaMdmaMode2
+} EFI_ATA_MDMA_MODE;
+
+//
+// UDMA mode definition
+//
+typedef enum {
+ EfiAtaUdmaMode0,
+ EfiAtaUdmaMode1,
+ EfiAtaUdmaMode2,
+ EfiAtaUdmaMode3,
+ EfiAtaUdmaMode4,
+ EfiAtaUdmaMode5
+} EFI_ATA_UDMA_MODE;
+
+//
+// Bus Master Reg
+//
+#define BMIC_NREAD BIT3
+#define BMIC_START BIT0
+#define BMIS_INTERRUPT BIT2
+#define BMIS_ERROR BIT1
+
+#define BMIC_OFFSET 0x00
+#define BMIS_OFFSET 0x02
+#define BMID_OFFSET 0x04
+
+//
+// IDE transfer mode
+//
+#define EFI_ATA_MODE_DEFAULT_PIO 0x00
+#define EFI_ATA_MODE_FLOW_PIO 0x01
+#define EFI_ATA_MODE_MDMA 0x04
+#define EFI_ATA_MODE_UDMA 0x08
+
+typedef struct {
+ UINT32 RegionBaseAddr;
+ UINT16 ByteCount;
+ UINT16 EndOfTable;
+} EFI_ATA_DMA_PRD;
+
+typedef struct {
+ UINT8 ModeNumber : 3;
+ UINT8 ModeCategory : 5;
+} EFI_ATA_TRANSFER_MODE;
+
+typedef struct {
+ UINT8 Sector;
+ UINT8 Heads;
+ UINT8 MultipleSector;
+} EFI_ATA_DRIVE_PARMS;
+
+//
+// IDE registers set
+//
+typedef struct {
+ UINT16 Data;
+ UINT16 ErrOrFeature;
+ UINT16 SectorCount;
+ UINT16 SectorNumber;
+ UINT16 CylinderLsb;
+ UINT16 CylinderMsb;
+ UINT16 Head;
+ UINT16 CmdOrStatus;
+ UINT16 AltOrDev;
+
+ UINT16 BusMasterBaseAddr;
+} EFI_IDE_REGISTERS;
+
+//
+// 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
+
+/**
+ Get IDE i/o 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 i/o 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.
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+
+ 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.
+ ___________________________________________________
+ | | 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
+
+ @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o 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 configuration data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetIdeRegisterIoAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN OUT EFI_IDE_REGISTERS *IdeRegisters
+ );
+
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Data In Protocol.
+
+ @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o port registers' base addresses
+ @param[in] Channel The channel number of device.
+ @param[in] Device The device number of device.
+ @param[in] Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
+
+ @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
+EFIAPI
+AtaPacketCommandExecute (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
new file mode 100644
index 000000000..28f8638c5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
@@ -0,0 +1,1712 @@
+/** @file
+ This file implements protocol interfaces for ATA bus driver.
+
+ This file implements protocol interfaces: Driver Binding protocol,
+ Block IO protocol and DiskInfo protocol.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "AtaBus.h"
+
+//
+// ATA Bus Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding = {
+ AtaBusDriverBindingSupported,
+ AtaBusDriverBindingStart,
+ AtaBusDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for ATA Child Device.
+//
+ATA_DEVICE gAtaDeviceTemplate = {
+ ATA_DEVICE_SIGNATURE, // Signature
+ NULL, // Handle
+ { // BlockIo
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ NULL,
+ AtaBlockIoReset,
+ AtaBlockIoReadBlocks,
+ AtaBlockIoWriteBlocks,
+ AtaBlockIoFlushBlocks
+ },
+ { // BlockIo2
+ NULL,
+ AtaBlockIoResetEx,
+ AtaBlockIoReadBlocksEx,
+ AtaBlockIoWriteBlocksEx,
+ AtaBlockIoFlushBlocksEx
+ },
+ { // BlockMedia
+ 0, // MediaId
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicPartition
+ FALSE, // ReadOnly
+ FALSE, // WritingCache
+ 0x200, // BlockSize
+ 0, // IoAlign
+ 0, // LastBlock
+ 0, // LowestAlignedLba
+ 1 // LogicalBlocksPerPhysicalBlock
+ },
+ { // DiskInfo
+ EFI_DISK_INFO_IDE_INTERFACE_GUID,
+ AtaDiskInfoInquiry,
+ AtaDiskInfoIdentify,
+ AtaDiskInfoSenseData,
+ AtaDiskInfoWhichIde
+ },
+ NULL, // DevicePath
+ {
+ AtaStorageSecurityReceiveData,
+ AtaStorageSecuritySendData
+ },
+ NULL, // AtaBusDriverData
+ 0, // Port
+ 0, // PortMultiplierPort
+ { 0, }, // Packet
+ {{ 0}, }, // Acb
+ NULL, // Asb
+ FALSE, // UdmaValid
+ FALSE, // Lba48Bit
+ NULL, // IdentifyData
+ NULL, // ControllerNameTable
+ {L'\0', }, // ModelName
+ {NULL, NULL}, // AtaTaskList
+ {NULL, NULL}, // AtaSubTaskList
+ FALSE // Abort
+};
+
+/**
+ Allocates an aligned buffer for ATA device.
+
+ This function allocates an aligned buffer for the ATA device to perform
+ ATA pass through operations. The alignment requirement is from ATA pass
+ through interface.
+
+ @param AtaDevice The ATA child device involved for the operation.
+ @param BufferSize The request buffer size.
+
+ @return A pointer to the aligned buffer or NULL if the allocation fails.
+
+**/
+VOID *
+AllocateAlignedBuffer (
+ IN ATA_DEVICE *AtaDevice,
+ IN UINTN BufferSize
+ )
+{
+ return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign);
+}
+
+/**
+ Frees an aligned buffer for ATA device.
+
+ This function frees an aligned buffer for the ATA device to perform
+ ATA pass through operations.
+
+ @param Buffer The aligned buffer to be freed.
+ @param BufferSize The request buffer size.
+
+**/
+VOID
+FreeAlignedBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ if (Buffer != NULL) {
+ FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+}
+
+
+/**
+ Release all the resources allocated for the ATA device.
+
+ This function releases all the resources allocated for the ATA device.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+**/
+VOID
+ReleaseAtaResources (
+ IN ATA_DEVICE *AtaDevice
+ )
+{
+ ATA_BUS_ASYN_SUB_TASK *SubTask;
+ ATA_BUS_ASYN_TASK *AtaTask;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *DelEntry;
+ EFI_TPL OldTpl;
+
+ FreeUnicodeStringTable (AtaDevice->ControllerNameTable);
+ FreeAlignedBuffer (AtaDevice->Asb, sizeof (EFI_ATA_STATUS_BLOCK));
+ FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (ATA_IDENTIFY_DATA));
+ if (AtaDevice->DevicePath != NULL) {
+ FreePool (AtaDevice->DevicePath);
+ }
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {
+ //
+ // Free the Subtask list.
+ //
+ for(Entry = AtaDevice->AtaSubTaskList.ForwardLink;
+ Entry != (&AtaDevice->AtaSubTaskList);
+ ) {
+ DelEntry = Entry;
+ Entry = Entry->ForwardLink;
+ SubTask = ATA_ASYN_SUB_TASK_FROM_ENTRY (DelEntry);
+
+ RemoveEntryList (DelEntry);
+ FreeAtaSubTask (SubTask);
+ }
+ }
+ if (!IsListEmpty (&AtaDevice->AtaTaskList)) {
+ //
+ // Free the Subtask list.
+ //
+ for(Entry = AtaDevice->AtaTaskList.ForwardLink;
+ Entry != (&AtaDevice->AtaTaskList);
+ ) {
+ DelEntry = Entry;
+ Entry = Entry->ForwardLink;
+ AtaTask = ATA_ASYN_TASK_FROM_ENTRY (DelEntry);
+
+ RemoveEntryList (DelEntry);
+ FreePool (AtaTask);
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+ FreePool (AtaDevice);
+}
+
+
+/**
+ Registers an ATA device.
+
+ This function allocates an ATA device structure for the ATA device specified by
+ Port and PortMultiplierPort if the ATA device is identified as a valid one.
+ Then it will create child handle and install Block IO and Disk Info protocol on
+ it.
+
+ @param AtaBusDriverData The parent ATA bus driver data structure.
+ @param Port The port number of the ATA device.
+ @param PortMultiplierPort The port multiplier port number of the ATA device.
+
+ @retval EFI_SUCCESS The ATA device is successfully registered.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to allocate the ATA device
+ and related data structures.
+ @return Others Some error occurs when registering the ATA device.
+**/
+EFI_STATUS
+RegisterAtaDevice (
+ IN OUT ATA_BUS_DRIVER_DATA *AtaBusDriverData,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *AtaDevice;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+
+ AtaDevice = NULL;
+ NewDevicePathNode = NULL;
+ DevicePath = NULL;
+ RemainingDevicePath = NULL;
+
+ //
+ // Build device path
+ //
+ AtaPassThru = AtaBusDriverData->AtaPassThru;
+ Status = AtaPassThru->BuildDevicePath (AtaPassThru, Port, PortMultiplierPort, &NewDevicePathNode);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DevicePath = AppendDevicePathNode (AtaBusDriverData->ParentDevicePath, NewDevicePathNode);
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ FreePool (DevicePath);
+ goto Done;
+ }
+
+ //
+ // Allocate ATA device from the template.
+ //
+ AtaDevice = AllocateCopyPool (sizeof (ATA_DEVICE), &gAtaDeviceTemplate);
+ if (AtaDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initializes ATA device structures and allocates the required buffer.
+ //
+ AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia;
+ AtaDevice->BlockIo2.Media = &AtaDevice->BlockMedia;
+ AtaDevice->AtaBusDriverData = AtaBusDriverData;
+ AtaDevice->DevicePath = DevicePath;
+ AtaDevice->Port = Port;
+ AtaDevice->PortMultiplierPort = PortMultiplierPort;
+ AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (EFI_ATA_STATUS_BLOCK));
+ if (AtaDevice->Asb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AtaDevice->IdentifyData = AllocateAlignedBuffer (AtaDevice, sizeof (ATA_IDENTIFY_DATA));
+ if (AtaDevice->IdentifyData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initial Ata Task List
+ //
+ InitializeListHead (&AtaDevice->AtaTaskList);
+ InitializeListHead (&AtaDevice->AtaSubTaskList);
+
+ //
+ // Report Status Code to indicate the ATA device will be enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_ENABLE),
+ AtaBusDriverData->ParentDevicePath
+ );
+
+ //
+ // Try to identify the ATA device via the ATA pass through command.
+ //
+ Status = DiscoverAtaDevice (AtaDevice);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Build controller name for Component Name (2) protocol.
+ //
+ Status = AddUnicodeString2 (
+ "eng",
+ gAtaBusComponentName.SupportedLanguages,
+ &AtaDevice->ControllerNameTable,
+ AtaDevice->ModelName,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = AddUnicodeString2 (
+ "en",
+ gAtaBusComponentName2.SupportedLanguages,
+ &AtaDevice->ControllerNameTable,
+ AtaDevice->ModelName,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Update to AHCI interface GUID based on device path node. The default one
+ // is IDE interface GUID copied from template.
+ //
+ if (NewDevicePathNode->SubType == MSG_SATA_DP) {
+ CopyGuid (&AtaDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &AtaDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ AtaDevice->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &AtaDevice->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &AtaDevice->BlockIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &AtaDevice->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // See if the ata device support trust computing feature or not.
+ // If yes, then install Storage Security Protocol at the ata device handle.
+ //
+ if ((AtaDevice->IdentifyData->trusted_computing_support & BIT0) != 0) {
+ DEBUG ((EFI_D_INFO, "Found TCG support in Port %x PortMultiplierPort %x\n", Port, PortMultiplierPort));
+ Status = gBS->InstallProtocolInterface (
+ &AtaDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &AtaDevice->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ DEBUG ((EFI_D_INFO, "Successfully Install Storage Security Protocol on the ATA device\n"));
+ }
+
+ gBS->OpenProtocol (
+ AtaBusDriverData->Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ AtaBusDriverData->DriverBindingHandle,
+ AtaDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+Done:
+ if (NewDevicePathNode != NULL) {
+ FreePool (NewDevicePathNode);
+ }
+
+ if (EFI_ERROR (Status) && (AtaDevice != NULL)) {
+ ReleaseAtaResources (AtaDevice);
+ DEBUG ((EFI_D_ERROR | EFI_D_INIT, "Failed to initialize Port %x PortMultiplierPort %x, status = %r\n", Port, PortMultiplierPort, Status));
+ }
+ return Status;
+}
+
+
+/**
+ Unregisters an ATA device.
+
+ This function removes the protocols installed on the controller handle and
+ frees the resources allocated for the ATA device.
+
+ @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The controller handle of the ATA device.
+ @param Handle The child handle.
+
+ @retval EFI_SUCCESS The ATA device is successfully unregistered.
+ @return Others Some error occurs when unregistering the ATA device.
+
+**/
+EFI_STATUS
+UnregisterAtaDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ ATA_DEVICE *AtaDevice;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
+
+ BlockIo2 = NULL;
+ BlockIo = NULL;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Locate BlockIo2 protocol
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Get AtaDevice data.
+ //
+ if (BlockIo != NULL) {
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo);
+ } else {
+ ASSERT (BlockIo2 != NULL);
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (BlockIo2);
+ }
+
+ //
+ // Close the child handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // The Ata Bus driver installs the BlockIo and BlockIo2 in the DriverBindingStart().
+ // Here should uninstall both of them.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ AtaDevice->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &AtaDevice->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &AtaDevice->BlockIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &AtaDevice->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // If Storage Security Command Protocol is installed, then uninstall this protocol.
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **) &StorageSecurity,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallProtocolInterface (
+ Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &AtaDevice->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+ }
+
+ ReleaseAtaResources (AtaDevice);
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+AtaBusDriverBindingSupported (
+ 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_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ UINT16 Port;
+ UINT16 PortMultiplierPort;
+
+ //
+ // Test EFI_ATA_PASS_THRU_PROTOCOL on controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Test to see if this ATA Pass Thru Protocol is for a LOGICAL channel
+ //
+ if ((AtaPassThru->Mode->Attributes & EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL) == 0) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Test RemainingDevicePath is valid or not.
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort);
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ 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_GET_PROTOCOL
+ );
+ return Status;
+}
+
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ ATA_BUS_DRIVER_DATA *AtaBusDriverData;
+ UINT16 Port;
+ UINT16 PortMultiplierPort;
+
+ AtaBusDriverData = NULL;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Report Status Code to indicate ATA bus starts
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ (VOID **) &AtaPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Check EFI_ALREADY_STARTED to reuse the original ATA_BUS_DRIVER_DATA.
+ //
+ if (Status != EFI_ALREADY_STARTED) {
+ AtaBusDriverData = AllocateZeroPool (sizeof (ATA_BUS_DRIVER_DATA));
+ if (AtaBusDriverData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ AtaBusDriverData->AtaPassThru = AtaPassThru;
+ AtaBusDriverData->Controller = Controller;
+ AtaBusDriverData->ParentDevicePath = ParentDevicePath;
+ AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiCallerIdGuid,
+ AtaBusDriverData,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &AtaBusDriverData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AtaBusDriverData = NULL;
+ goto ErrorExit;
+ }
+ }
+
+ //
+ // Report Status Code to indicate detecting devices on bus
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_DETECT),
+ ParentDevicePath
+ );
+
+ if (RemainingDevicePath == NULL) {
+ Port = 0xFFFF;
+ while (TRUE) {
+ Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);
+ if (EFI_ERROR (Status)) {
+ //
+ // We cannot find more legal port then we are done.
+ //
+ break;
+ }
+
+ PortMultiplierPort = 0xFFFF;
+ while (TRUE) {
+ Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);
+ if (EFI_ERROR (Status)) {
+ //
+ // We cannot find more legal port multiplier port number for ATA device
+ // on the port, then we are done.
+ //
+ break;
+ }
+ RegisterAtaDevice (AtaBusDriverData, Port, PortMultiplierPort);
+ }
+ }
+ Status = EFI_SUCCESS;
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort);
+ if (!EFI_ERROR (Status)) {
+ Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort);
+ }
+ }
+
+ return Status;
+
+ErrorExit:
+
+ if (AtaBusDriverData != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ AtaBusDriverData,
+ NULL
+ );
+ FreePool (AtaBusDriverData);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+
+}
+
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+AtaBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ ATA_BUS_DRIVER_DATA *AtaBusDriverData;
+
+ if (NumberOfChildren == 0) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &AtaBusDriverData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ AtaBusDriverData,
+ NULL
+ );
+ FreePool (AtaBusDriverData);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiAtaPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = UnregisterAtaDevice (This, Controller, ChildHandleBuffer[Index]);
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ 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
+AtaBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *AtaDevice;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);
+
+ Status = ResetAtaDevice (AtaDevice);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Read/Write BufferSize bytes from Lba from/into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context. Either be
+ block I/O or block I/O2.
+ @param[in] MediaId The media ID that the read/write request is for.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] IsBlockIo2 Indicate the calling is from BlockIO or BlockIO2. TRUE is
+ from BlockIO2, FALSE is for BlockIO.
+ @param[in] IsWrite Indicates whether it is a write operation.
+
+ @retval EFI_SUCCESS The data was read/written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match 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/write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+BlockIoReadWrite (
+ IN VOID *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer,
+ IN BOOLEAN IsBlockIo2,
+ IN BOOLEAN IsWrite
+ )
+{
+ ATA_DEVICE *AtaDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+
+ if (IsBlockIo2) {
+ Media = ((EFI_BLOCK_IO2_PROTOCOL *) This)->Media;
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (This);
+ } else {
+ Media = ((EFI_BLOCK_IO_PROTOCOL *) This)->Media;
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);
+ }
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Invoke low level AtaDevice Access Routine.
+ //
+ Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite, Token);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ 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 match 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
+AtaBlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return BlockIoReadWrite ((VOID *) This, MediaId, Lba, NULL, BufferSize, Buffer, FALSE, FALSE);
+}
+
+
+/**
+ 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_CHANGED The MediaId does not match 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
+AtaBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return BlockIoReadWrite ((VOID *) This, MediaId, Lba, NULL, BufferSize, Buffer, FALSE, TRUE);
+}
+
+
+/**
+ 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+AtaBlockIoResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *AtaDevice;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (This);
+
+ AtaTerminateNonBlockingTask (AtaDevice);
+
+ Status = ResetAtaDevice (AtaDevice);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return BlockIoReadWrite ((VOID *) This, MediaId, Lba, Token, BufferSize, Buffer, TRUE, FALSE);
+}
+
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+AtaBlockIoWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return BlockIoReadWrite ((VOID *) This, MediaId, Lba, Token, BufferSize, Buffer, TRUE, TRUE);
+}
+
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ //
+ // Signal event and return directly.
+ //
+ if (Token != NULL && Token->Event != NULL) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Provides inquiry information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+AtaDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+AtaDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *AtaDevice;
+
+ AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*IdentifyDataSize >= sizeof (ATA_IDENTIFY_DATA)) {
+ Status = EFI_SUCCESS;
+ CopyMem (IdentifyData, AtaDevice->IdentifyData, sizeof (ATA_IDENTIFY_DATA));
+ }
+ *IdentifyDataSize = sizeof (ATA_IDENTIFY_DATA);
+
+ return Status;
+}
+
+
+/**
+ Provides sense data information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaDiskInfoSenseData (
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+AtaDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ ATA_DEVICE *AtaDevice;
+
+ AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This);
+ *IdeChannel = AtaDevice->Port;
+ *IdeDevice = AtaDevice->PortMultiplierPort;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaStorageSecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *Private;
+ EFI_TPL OldTpl;
+
+ DEBUG ((EFI_D_INFO, "EFI Storage Security Protocol - Read\n"));
+ if ((PayloadBuffer == NULL || PayloadTransferSize == NULL) && PayloadBufferSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = ATA_DEVICE_FROM_STORAGE_SECURITY (This);
+
+ if (MediaId != Private->BlockIo.Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!Private->BlockIo.Media->MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Status = TrustTransferAtaDevice (
+ Private,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ FALSE,
+ Timeout,
+ PayloadTransferSize
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaStorageSecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ EFI_STATUS Status;
+ ATA_DEVICE *Private;
+ EFI_TPL OldTpl;
+
+ DEBUG ((EFI_D_INFO, "EFI Storage Security Protocol - Send\n"));
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = ATA_DEVICE_FROM_STORAGE_SECURITY (This);
+
+ if (MediaId != Private->BlockIo.Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Status = TrustTransferAtaDevice (
+ Private,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ TRUE,
+ Timeout,
+ NULL
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The user Entry Point for module AtaBus. 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
+InitializeAtaBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gAtaBusDriverBinding,
+ ImageHandle,
+ &gAtaBusComponentName,
+ &gAtaBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
new file mode 100644
index 000000000..a5a865209
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
@@ -0,0 +1,1075 @@
+/** @file
+ Master header file for ATA Bus Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ATA_BUS_H_
+#define _ATA_BUS_H_
+
+#include <Uefi.h>
+
+#include <Protocol/AtaPassThru.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/StorageSecurityCommand.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/DevicePathLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/TimerLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Atapi.h>
+
+//
+// Time out value for ATA pass through protocol
+//
+#define ATA_TIMEOUT EFI_TIMER_PERIOD_SECONDS (3)
+
+//
+// Maximum number of times to retry ATA command
+//
+#define MAX_RETRY_TIMES 3
+
+//
+// The maximum total sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+//
+// The maximum ATA transaction sector count in 28 bit addressing mode.
+//
+#define MAX_28BIT_TRANSFER_BLOCK_NUM 0x100
+
+//
+// The maximum ATA transaction sector count in 48 bit addressing mode.
+//
+//#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x10000
+
+//
+// BugBug: if the TransferLength is equal with 0x10000 (the 48bit max length),
+// there is a bug that even the register interrupt bit has been sit, the buffer
+// seems not ready. Change the Maximum Sector Numbers to 0xFFFF to work round
+// this issue.
+//
+#define MAX_48BIT_TRANSFER_BLOCK_NUM 0xFFFF
+
+//
+// The maximum model name in ATA identify data
+//
+#define MAX_MODEL_NAME_LEN 40
+
+#define ATA_TASK_SIGNATURE SIGNATURE_32 ('A', 'T', 'S', 'K')
+#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D')
+#define ATA_SUB_TASK_SIGNATURE SIGNATURE_32 ('A', 'S', 'T', 'S')
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+//
+// ATA bus data structure for ATA controller
+//
+typedef struct {
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_HANDLE Controller;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_HANDLE DriverBindingHandle;
+} ATA_BUS_DRIVER_DATA;
+
+//
+// ATA device data structure for each child device
+//
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+
+ ATA_BUS_DRIVER_DATA *AtaBusDriverData;
+ UINT16 Port;
+ UINT16 PortMultiplierPort;
+
+ //
+ // Buffer for the execution of ATA pass through protocol
+ //
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_ATA_COMMAND_BLOCK Acb;
+ EFI_ATA_STATUS_BLOCK *Asb;
+
+ BOOLEAN UdmaValid;
+ BOOLEAN Lba48Bit;
+
+ //
+ // Cached data for ATA identify data
+ //
+ ATA_IDENTIFY_DATA *IdentifyData;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1];
+
+ LIST_ENTRY AtaTaskList;
+ LIST_ENTRY AtaSubTaskList;
+ BOOLEAN Abort;
+} ATA_DEVICE;
+
+//
+// Sub-Task for the non blocking I/O
+//
+typedef struct {
+ UINT32 Signature;
+ ATA_DEVICE *AtaDevice;
+ EFI_BLOCK_IO2_TOKEN *Token;
+ UINTN *UnsignalledEventCount;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
+ BOOLEAN *IsError;// Indicate whether meeting error during source allocation for new task.
+ LIST_ENTRY TaskEntry;
+} ATA_BUS_ASYN_SUB_TASK;
+
+//
+// Task for the non blocking I/O
+//
+typedef struct {
+ UINT32 Signature;
+ EFI_BLOCK_IO2_TOKEN *Token;
+ ATA_DEVICE *AtaDevice;
+ UINT8 *Buffer;
+ EFI_LBA StartLba;
+ UINTN NumberOfBlocks;
+ BOOLEAN IsWrite;
+ LIST_ENTRY TaskEntry;
+} ATA_BUS_ASYN_TASK;
+
+#define ATA_DEVICE_FROM_BLOCK_IO(a) CR (a, ATA_DEVICE, BlockIo, ATA_DEVICE_SIGNATURE)
+#define ATA_DEVICE_FROM_BLOCK_IO2(a) CR (a, ATA_DEVICE, BlockIo2, ATA_DEVICE_SIGNATURE)
+#define ATA_DEVICE_FROM_DISK_INFO(a) CR (a, ATA_DEVICE, DiskInfo, ATA_DEVICE_SIGNATURE)
+#define ATA_DEVICE_FROM_STORAGE_SECURITY(a) CR (a, ATA_DEVICE, StorageSecurity, ATA_DEVICE_SIGNATURE)
+#define ATA_ASYN_SUB_TASK_FROM_ENTRY(a) CR (a, ATA_BUS_ASYN_SUB_TASK, TaskEntry, ATA_SUB_TASK_SIGNATURE)
+#define ATA_ASYN_TASK_FROM_ENTRY(a) CR (a, ATA_BUS_ASYN_TASK, TaskEntry, ATA_TASK_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2;
+
+/**
+ Allocates an aligned buffer for ATA device.
+
+ This function allocates an aligned buffer for the ATA device to perform
+ ATA pass through operations. The alignment requirement is from ATA pass
+ through interface.
+
+ @param AtaDevice The ATA child device involved for the operation.
+ @param BufferSize The request buffer size.
+
+ @return A pointer to the aligned buffer or NULL if the allocation fails.
+
+**/
+VOID *
+AllocateAlignedBuffer (
+ IN ATA_DEVICE *AtaDevice,
+ IN UINTN BufferSize
+ );
+
+/**
+ Frees an aligned buffer for ATA device.
+
+ This function frees an aligned buffer for the ATA device to perform
+ ATA pass through operations.
+
+ @param Buffer The aligned buffer to be freed.
+ @param BufferSize The request buffer size.
+
+**/
+VOID
+FreeAlignedBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Free SubTask.
+
+ @param[in, out] Task Pointer to task to be freed.
+
+**/
+VOID
+EFIAPI
+FreeAtaSubTask (
+ IN OUT ATA_BUS_ASYN_SUB_TASK *Task
+ );
+
+/**
+ Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().
+
+ This function wraps the ResetDevice() invocation for ATA pass through function
+ for an ATA device.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
+
+**/
+EFI_STATUS
+ResetAtaDevice (
+ IN ATA_DEVICE *AtaDevice
+ );
+
+
+/**
+ Discovers whether it is a valid ATA device.
+
+ This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it.
+ If the command is executed successfully, it then identifies it and initializes
+ the Media information in Block IO protocol interface.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @retval EFI_SUCCESS The device is successfully identified and Media information
+ is correctly initialized.
+ @return others Some error occurs when discovering the ATA device.
+
+**/
+EFI_STATUS
+DiscoverAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice
+ );
+
+/**
+ Read or write a number of blocks from ATA device.
+
+ This function performs ATA pass through transactions to read/write data from/to
+ ATA device. It may separate the read/write request into several ATA pass through
+ transactions.
+
+ @param[in, out] AtaDevice The ATA child device involved for the operation.
+ @param[in, out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] NumberOfBlocks The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+AccessAtaDevice(
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT UINT8 *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN BOOLEAN IsWrite,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Trust transfer data from/to ATA device.
+
+ This function performs one ATA pass through transaction to do a trust transfer from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param AtaDevice The ATA child device involved for the operation.
+ @param Buffer The pointer to the current transaction buffer.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param TransferLength The block number or sector count of the transfer.
+ @param IsTrustSend Indicates whether it is a trust send operation or not.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data
+ written to the buffer. Ignore it when IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+EFIAPI
+TrustTransferAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ );
+
+//
+// Protocol interface prototypes
+//
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+AtaBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+AtaBusDriverBindingStop (
+ 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
+AtaBusComponentNameGetDriverName (
+ 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
+AtaBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ 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
+AtaBlockIoReset (
+ 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 match 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
+AtaBlockIoReadBlocks (
+ 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_CHANGED The MediaId does not match 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
+AtaBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device through Block I/O2 protocol.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+AtaBlockIoResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+AtaBlockIoWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaBlockIoFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Terminate any in-flight non-blocking I/O requests by signaling an EFI_ABORTED
+ in the TransactionStatus member of the EFI_BLOCK_IO2_TOKEN for the non-blocking
+ I/O. After that it is safe to free any Token or Buffer data structures that
+ were allocated to initiate the non-blockingI/O requests that were in-flight for
+ this device.
+
+ @param[in] AtaDevice The ATA child device involved for the operation.
+
+**/
+VOID
+EFIAPI
+AtaTerminateNonBlockingTask (
+ IN ATA_DEVICE *AtaDevice
+ );
+
+/**
+ Provides inquiry information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+AtaDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+
+/**
+ Provides identify information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+AtaDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+
+/**
+ Provides sense data information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaDiskInfoSenseData (
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+AtaDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaStorageSecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaStorageSecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+/**
+ Send TPer Reset command to reset eDrive to lock all protected bands.
+ Typically, there are 2 mechanism for resetting eDrive. They are:
+ 1. TPer Reset through IEEE 1667 protocol.
+ 2. TPer Reset through native TCG protocol.
+ This routine will detect what protocol the attached eDrive conform to, TCG or
+ IEEE 1667 protocol. Then send out TPer Reset command separately.
+
+ @param[in] AtaDevice ATA_DEVICE pointer.
+
+**/
+VOID
+InitiateTPerReset (
+ IN ATA_DEVICE *AtaDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
new file mode 100644
index 000000000..086ec5f7c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# ATA Bus driver to enumerate and identify ATA devices.
+#
+# This driver follows UEFI driver model and layers on ATA Pass Thru protocol defined
+# in UEFI spec 2.2. It installs Block IO and Disk Info protocol for each ATA device
+# it enumerates and identifies successfully.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AtaBusDxe
+ MODULE_UNI_FILE = AtaBusDxe.uni
+ FILE_GUID = 19DF145A-B1D4-453f-8507-38816676D7F6
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeAtaBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gAtaBusDriverBinding
+# COMPONENT_NAME = gAtaBusComponentName
+# COMPONENT_NAME2 = gAtaBusComponentName2
+#
+#
+
+[Sources]
+ AtaBus.h
+ AtaBus.c
+ AtaPassThruExecute.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+ TimerLib
+ ReportStatusCodeLib
+
+[Guids]
+ gEfiDiskInfoAhciInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+
+[Protocols]
+ gEfiDiskInfoProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+ gEfiAtaPassThruProtocolGuid ## TO_START
+ gEfiStorageSecurityCommandProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AtaBusDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.uni
new file mode 100644
index 000000000..ec4aab24d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// ATA Bus driver to enumerate and identify ATA devices.
+//
+// This driver follows UEFI driver model and layers on ATA Pass Thru protocol defined
+// in UEFI spec 2.2. It installs Block IO and Disk Info protocol for each ATA device
+// it enumerates and identifies successfully.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ATA Bus driver to enumerate and identify ATA devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the ATA Pass Thru protocol defined in UEFI Specification 2.2. It installs Block IO and Disk Info protocols for each ATA device it enumerates and identifies successfully."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxeExtra.uni
new file mode 100644
index 000000000..71372a9dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// AtaBusDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ATA Bus DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
new file mode 100644
index 000000000..79026a4a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
@@ -0,0 +1,1067 @@
+/** @file
+ This file implements ATA pass through transaction for ATA bus driver.
+
+ This file implements the low level execution of ATA pass through transaction.
+ It transforms the high level identity, read/write, reset command to ATA pass
+ through command and protocol.
+
+ NOTE: This file also implements the StorageSecurityCommandProtocol(SSP). For input
+ parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition
+ for Security Protocol Specific layout. This implementation uses big endian for
+ Cylinder register.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "AtaBus.h"
+
+#define ATA_CMD_TRUST_NON_DATA 0x5B
+#define ATA_CMD_TRUST_RECEIVE 0x5C
+#define ATA_CMD_TRUST_RECEIVE_DMA 0x5D
+#define ATA_CMD_TRUST_SEND 0x5E
+#define ATA_CMD_TRUST_SEND_DMA 0x5F
+
+//
+// Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL
+//
+EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[][2] = {
+ {
+ EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,
+ EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
+ },
+ {
+ EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN,
+ EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT,
+ }
+};
+
+//
+// Look up table (UdmaValid, Lba48Bit, IsIsWrite) for ATA_CMD
+//
+UINT8 mAtaCommands[][2][2] = {
+ {
+ {
+ ATA_CMD_READ_SECTORS, // 28-bit LBA; PIO read
+ ATA_CMD_WRITE_SECTORS // 28-bit LBA; PIO write
+ },
+ {
+ ATA_CMD_READ_SECTORS_EXT, // 48-bit LBA; PIO read
+ ATA_CMD_WRITE_SECTORS_EXT // 48-bit LBA; PIO write
+ }
+ },
+ {
+ {
+ ATA_CMD_READ_DMA, // 28-bit LBA; DMA read
+ ATA_CMD_WRITE_DMA // 28-bit LBA; DMA write
+ },
+ {
+ ATA_CMD_READ_DMA_EXT, // 48-bit LBA; DMA read
+ ATA_CMD_WRITE_DMA_EXT // 48-bit LBA; DMA write
+ }
+ }
+};
+
+//
+// Look up table (UdmaValid, IsTrustSend) for ATA_CMD
+//
+UINT8 mAtaTrustCommands[2][2] = {
+ {
+ ATA_CMD_TRUST_RECEIVE, // PIO read
+ ATA_CMD_TRUST_SEND // PIO write
+ },
+ {
+ ATA_CMD_TRUST_RECEIVE_DMA, // DMA read
+ ATA_CMD_TRUST_SEND_DMA // DMA write
+ }
+};
+
+
+//
+// Look up table (Lba48Bit) for maximum transfer block number
+//
+UINTN mMaxTransferBlockNumber[] = {
+ MAX_28BIT_TRANSFER_BLOCK_NUM,
+ MAX_48BIT_TRANSFER_BLOCK_NUM
+};
+
+
+/**
+ Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
+
+ This function wraps the PassThru() invocation for ATA pass through function
+ for an ATA device. It assembles the ATA pass through command packet for ATA
+ transaction.
+
+ @param[in, out] AtaDevice The ATA child device involved for the operation.
+ @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional,
+ if it is NULL, blocking mode, and use the packet
+ in AtaDevice. If it is not NULL, non blocking mode,
+ and pass down this Packet.
+ @param[in, out] Event If Event is NULL, then blocking I/O is performed.
+ If Event is not NULL and non-blocking I/O is
+ supported,then non-blocking I/O is performed,
+ and Event will be signaled when the write
+ request is completed.
+
+ @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
+
+**/
+EFI_STATUS
+AtaDevicePassThru (
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL
+ IN OUT EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;
+
+ //
+ // Assemble packet. If it is non blocking mode, the Ata driver should keep each
+ // subtask and clean them when the event is signaled.
+ //
+ if (TaskPacket != NULL) {
+ Packet = TaskPacket;
+ Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (EFI_ATA_STATUS_BLOCK));
+ if (Packet->Asb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (EFI_ATA_STATUS_BLOCK));
+ Packet->Acb = AllocateCopyPool (sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);
+ } else {
+ Packet = &AtaDevice->Packet;
+ Packet->Asb = AtaDevice->Asb;
+ Packet->Acb = &AtaDevice->Acb;
+ }
+
+ AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
+
+ Status = AtaPassThru->PassThru (
+ AtaPassThru,
+ AtaDevice->Port,
+ AtaDevice->PortMultiplierPort,
+ Packet,
+ Event
+ );
+ //
+ // Ensure ATA pass through caller and callee have the same
+ // interpretation of ATA pass through protocol.
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+ ASSERT (Status != EFI_BAD_BUFFER_SIZE);
+
+ return Status;
+}
+
+
+/**
+ Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().
+
+ This function wraps the ResetDevice() invocation for ATA pass through function
+ for an ATA device.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
+
+**/
+EFI_STATUS
+ResetAtaDevice (
+ IN ATA_DEVICE *AtaDevice
+ )
+{
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+
+ AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
+
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+ AtaDevice->AtaBusDriverData->ParentDevicePath
+ );
+
+ return AtaPassThru->ResetDevice (
+ AtaPassThru,
+ AtaDevice->Port,
+ AtaDevice->PortMultiplierPort
+ );
+}
+
+
+/**
+ Prints ATA model name to ATA device structure.
+
+ This function converts ATA device model name from ATA identify data
+ to a string in ATA device structure. It needs to change the character
+ order in the original model name string.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+**/
+VOID
+PrintAtaModelName (
+ IN OUT ATA_DEVICE *AtaDevice
+ )
+{
+ UINTN Index;
+ CHAR8 *Source;
+ CHAR16 *Destination;
+
+ Source = AtaDevice->IdentifyData->ModelName;
+ Destination = AtaDevice->ModelName;
+
+ //
+ // Swap the byte order in the original module name.
+ //
+ for (Index = 0; Index < MAX_MODEL_NAME_LEN; Index += 2) {
+ Destination[Index] = Source[Index + 1];
+ Destination[Index + 1] = Source[Index];
+ }
+ AtaDevice->ModelName[MAX_MODEL_NAME_LEN] = L'\0';
+}
+
+
+/**
+ Gets ATA device Capacity according to ATA 6.
+
+ This function returns the capacity of the ATA device if it follows
+ ATA 6 to support 48 bit addressing.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @return The capacity of the ATA device or 0 if the device does not support
+ 48-bit addressing defined in ATA 6.
+
+**/
+EFI_LBA
+GetAtapi6Capacity (
+ IN ATA_DEVICE *AtaDevice
+ )
+{
+ EFI_LBA Capacity;
+ EFI_LBA TmpLba;
+ UINTN Index;
+ ATA_IDENTIFY_DATA *IdentifyData;
+
+ IdentifyData = AtaDevice->IdentifyData;
+ if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {
+ //
+ // The device doesn't support 48 bit addressing
+ //
+ return 0;
+ }
+
+ //
+ // 48 bit address feature set is supported, get maximum capacity
+ //
+ Capacity = 0;
+ for (Index = 0; Index < 4; Index++) {
+ //
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+ //
+ TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);
+ }
+
+ return Capacity;
+}
+
+
+/**
+ Identifies ATA device via the Identify data.
+
+ This function identifies the ATA device and initializes the Media information in
+ Block IO protocol interface.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @retval EFI_UNSUPPORTED The device is not a valid ATA device (hard disk).
+ @retval EFI_SUCCESS The device is successfully identified and Media information
+ is correctly initialized.
+
+**/
+EFI_STATUS
+IdentifyAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice
+ )
+{
+ ATA_IDENTIFY_DATA *IdentifyData;
+ EFI_BLOCK_IO_MEDIA *BlockMedia;
+ EFI_LBA Capacity;
+ UINT16 PhyLogicSectorSupport;
+ UINT16 UdmaMode;
+
+ IdentifyData = AtaDevice->IdentifyData;
+
+ if ((IdentifyData->config & BIT15) != 0) {
+ //
+ // This is not an hard disk
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "AtaBus - Identify Device: Port %x PortMultiplierPort %x\n", AtaDevice->Port, AtaDevice->PortMultiplierPort));
+
+ //
+ // Check whether the WORD 88 (supported UltraDMA by drive) is valid
+ //
+ if ((IdentifyData->field_validity & BIT2) != 0) {
+ UdmaMode = IdentifyData->ultra_dma_mode;
+ if ((UdmaMode & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0) {
+ //
+ // If BIT0~BIT6 is selected, then UDMA is supported
+ //
+ AtaDevice->UdmaValid = TRUE;
+ }
+ }
+
+ Capacity = GetAtapi6Capacity (AtaDevice);
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+ //
+ // Capacity exceeds 120GB. 48-bit addressing is really needed
+ //
+ AtaDevice->Lba48Bit = TRUE;
+ } else {
+ //
+ // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+ //
+ Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) | IdentifyData->user_addressable_sectors_lo;
+ AtaDevice->Lba48Bit = FALSE;
+ }
+
+ //
+ // Block Media Information:
+ //
+ BlockMedia = &AtaDevice->BlockMedia;
+ BlockMedia->LastBlock = Capacity - 1;
+ BlockMedia->IoAlign = AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign;
+ //
+ // Check whether Long Physical Sector Feature is supported
+ //
+ PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;
+ if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {
+ //
+ // Check whether one physical block contains multiple physical blocks
+ //
+ if ((PhyLogicSectorSupport & BIT13) != 0) {
+ BlockMedia->LogicalBlocksPerPhysicalBlock = (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));
+ //
+ // Check lowest alignment of logical blocks within physical block
+ //
+ if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) {
+ BlockMedia->LowestAlignedLba = (EFI_LBA) ((BlockMedia->LogicalBlocksPerPhysicalBlock - ((UINT32)IdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %
+ BlockMedia->LogicalBlocksPerPhysicalBlock);
+ }
+ }
+ //
+ // Check logical block size
+ //
+ if ((PhyLogicSectorSupport & BIT12) != 0) {
+ BlockMedia->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) | IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
+ }
+ AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
+ }
+ //
+ // Get ATA model name from identify data structure.
+ //
+ PrintAtaModelName (AtaDevice);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Discovers whether it is a valid ATA device.
+
+ This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it.
+ If the command is executed successfully, it then identifies it and initializes
+ the Media information in Block IO protocol interface.
+
+ @param AtaDevice The ATA child device involved for the operation.
+
+ @retval EFI_SUCCESS The device is successfully identified and Media information
+ is correctly initialized.
+ @return others Some error occurs when discovering the ATA device.
+
+**/
+EFI_STATUS
+DiscoverAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK *Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;
+ UINTN Retry;
+
+ //
+ // Prepare for ATA command block.
+ //
+ Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ Packet->InDataBuffer = AtaDevice->IdentifyData;
+ Packet->InTransferLength = sizeof (ATA_IDENTIFY_DATA);
+ Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
+ Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
+ Packet->Timeout = ATA_TIMEOUT;
+
+ Retry = MAX_RETRY_TIMES;
+ do {
+ Status = AtaDevicePassThru (AtaDevice, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // The command is issued successfully
+ //
+ Status = IdentifyAtaDevice (AtaDevice);
+ return Status;
+ }
+ } while (Retry-- > 0);
+
+ return Status;
+}
+
+/**
+ Transfer data from ATA device.
+
+ This function performs one ATA pass through transaction to transfer data from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param[in, out] AtaDevice The ATA child device involved for the operation.
+ @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional,
+ if it is NULL, blocking mode, and use the packet
+ in AtaDevice. If it is not NULL, non blocking mode,
+ and pass down this Packet.
+ @param[in, out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+ @param[in] Event If Event is NULL, then blocking I/O is performed.
+ If Event is not NULL and non-blocking I/O is
+ supported,then non-blocking I/O is performed,
+ and Event will be signaled when the write
+ request is completed.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TransferAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL
+ IN OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINT32 TransferLength,
+ IN BOOLEAN IsWrite,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_ATA_COMMAND_BLOCK *Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;
+
+ //
+ // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values
+ //
+ ASSERT ((UINTN) AtaDevice->UdmaValid < 2);
+ ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
+ ASSERT ((UINTN) IsWrite < 2);
+ //
+ // Prepare for ATA command block.
+ //
+ Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite];
+ Acb->AtaSectorNumber = (UINT8) StartLba;
+ Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
+ Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);
+ Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));
+ Acb->AtaSectorCount = (UINT8) TransferLength;
+ if (AtaDevice->Lba48Bit) {
+ Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
+ Acb->AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);
+ Acb->AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);
+ Acb->AtaSectorCountExp = (UINT8) (TransferLength >> 8);
+ } else {
+ Acb->AtaDeviceHead = (UINT8) (Acb->AtaDeviceHead | RShiftU64 (StartLba, 24));
+ }
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ if (TaskPacket != NULL) {
+ Packet = ZeroMem (TaskPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ } else {
+ Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ }
+
+ if (IsWrite) {
+ Packet->OutDataBuffer = Buffer;
+ Packet->OutTransferLength = TransferLength;
+ } else {
+ Packet->InDataBuffer = Buffer;
+ Packet->InTransferLength = TransferLength;
+ }
+
+ Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];
+ Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
+ //
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | ATA PIO Transfer Mode | Transfer Rate | ATA DMA Transfer Mode | Transfer Rate |
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec | Single-word DMA Mode 0 | 2.1Mbytes/sec |
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec | Single-word DMA Mode 1 | 4.2Mbytes/sec |
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec | Single-word DMA Mode 2 | 8.4Mbytes/sec |
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec | Multi-word DMA Mode 0 | 4.2Mbytes/sec |
+ // |------------------------|-----------------|------------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec | Multi-word DMA Mode 1 | 13.3Mbytes/sec |
+ // |------------------------|-----------------|------------------------|-----------------|
+ //
+ // As AtaBus is used to manage ATA devices, we have to use the lowest transfer rate to
+ // calculate the possible maximum timeout value for each read/write operation.
+ // The timeout value is rounded up to nearest integer and here an additional 30s is added
+ // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
+ // commands in the Standby/Idle mode.
+ //
+ if (AtaDevice->UdmaValid) {
+ //
+ // Calculate the maximum timeout value for DMA read/write operation.
+ //
+ Packet->Timeout = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 2100000) + 31);
+ } else {
+ //
+ // Calculate the maximum timeout value for PIO read/write operation
+ //
+ Packet->Timeout = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 3300000) + 31);
+ }
+
+ return AtaDevicePassThru (AtaDevice, TaskPacket, Event);
+}
+
+/**
+ Free SubTask.
+
+ @param[in, out] Task Pointer to task to be freed.
+
+**/
+VOID
+EFIAPI
+FreeAtaSubTask (
+ IN OUT ATA_BUS_ASYN_SUB_TASK *Task
+ )
+{
+ if (Task->Packet.Asb != NULL) {
+ FreeAlignedBuffer (Task->Packet.Asb, sizeof (EFI_ATA_STATUS_BLOCK));
+ }
+ if (Task->Packet.Acb != NULL) {
+ FreePool (Task->Packet.Acb);
+ }
+
+ FreePool (Task);
+}
+
+/**
+ Terminate any in-flight non-blocking I/O requests by signaling an EFI_ABORTED
+ in the TransactionStatus member of the EFI_BLOCK_IO2_TOKEN for the non-blocking
+ I/O. After that it is safe to free any Token or Buffer data structures that
+ were allocated to initiate the non-blockingI/O requests that were in-flight for
+ this device.
+
+ @param[in] AtaDevice The ATA child device involved for the operation.
+
+**/
+VOID
+EFIAPI
+AtaTerminateNonBlockingTask (
+ IN ATA_DEVICE *AtaDevice
+ )
+{
+ BOOLEAN SubTaskEmpty;
+ EFI_TPL OldTpl;
+ ATA_BUS_ASYN_TASK *AtaTask;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *List;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ //
+ // Abort all executing tasks from now.
+ //
+ AtaDevice->Abort = TRUE;
+
+ List = &AtaDevice->AtaTaskList;
+ for (Entry = GetFirstNode (List); !IsNull (List, Entry);) {
+ AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);
+ AtaTask->Token->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (AtaTask->Token->Event);
+
+ Entry = RemoveEntryList (Entry);
+ FreePool (AtaTask);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ do {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ //
+ // Wait for executing subtasks done.
+ //
+ SubTaskEmpty = IsListEmpty (&AtaDevice->AtaSubTaskList);
+ gBS->RestoreTPL (OldTpl);
+ } while (!SubTaskEmpty);
+
+ //
+ // Aborting operation has been done. From now on, don't need to abort normal operation.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ AtaDevice->Abort = FALSE;
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Call back function when the event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AtaNonBlockingCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ATA_BUS_ASYN_SUB_TASK *Task;
+ ATA_BUS_ASYN_TASK *AtaTask;
+ ATA_DEVICE *AtaDevice;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ Task = (ATA_BUS_ASYN_SUB_TASK *) Context;
+ gBS->CloseEvent (Event);
+
+ AtaDevice = Task->AtaDevice;
+
+ //
+ // Check the command status.
+ // If there is error during the sub task source allocation, the error status
+ // should be returned to the caller directly, so here the Task->Token may already
+ // be deleted by the caller and no need to update the status.
+ //
+ if ((!(*Task->IsError)) && ((Task->Packet.Asb->AtaStatus & 0x01) == 0x01)) {
+ Task->Token->TransactionStatus = EFI_DEVICE_ERROR;
+ }
+
+ if (AtaDevice->Abort) {
+ Task->Token->TransactionStatus = EFI_ABORTED;
+ }
+
+ DEBUG ((
+ EFI_D_BLKIO,
+ "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",
+ Task->Token->TransactionStatus
+ ));
+
+ //
+ // Reduce the SubEventCount, till it comes to zero.
+ //
+ (*Task->UnsignalledEventCount) --;
+ DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));
+
+ //
+ // Remove the SubTask from the Task list.
+ //
+ RemoveEntryList (&Task->TaskEntry);
+ if ((*Task->UnsignalledEventCount) == 0) {
+ //
+ // All Sub tasks are done, then signal the upper layer event.
+ // Except there is error during the sub task source allocation.
+ //
+ if (!(*Task->IsError)) {
+ gBS->SignalEvent (Task->Token->Event);
+ DEBUG ((EFI_D_BLKIO, "Signal the upper layer event!\n"));
+ }
+
+ FreePool (Task->UnsignalledEventCount);
+ FreePool (Task->IsError);
+
+
+ //
+ // Finish all subtasks and move to the next task in AtaTaskList.
+ //
+ if (!IsListEmpty (&AtaDevice->AtaTaskList)) {
+ Entry = GetFirstNode (&AtaDevice->AtaTaskList);
+ AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);
+ DEBUG ((EFI_D_BLKIO, "Start to embark a new Ata Task\n"));
+ DEBUG ((EFI_D_BLKIO, "AtaTask->NumberOfBlocks = %x; AtaTask->Token=%x\n", AtaTask->NumberOfBlocks, AtaTask->Token));
+ Status = AccessAtaDevice (
+ AtaTask->AtaDevice,
+ AtaTask->Buffer,
+ AtaTask->StartLba,
+ AtaTask->NumberOfBlocks,
+ AtaTask->IsWrite,
+ AtaTask->Token
+ );
+ if (EFI_ERROR (Status)) {
+ AtaTask->Token->TransactionStatus = Status;
+ gBS->SignalEvent (AtaTask->Token->Event);
+ }
+ RemoveEntryList (Entry);
+ FreePool (AtaTask);
+ }
+ }
+
+ DEBUG ((
+ EFI_D_BLKIO,
+ "PACKET INFO: Write=%s, Length=%x, LowCylinder=%x, HighCylinder=%x, SectionNumber=%x\n",
+ Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO",
+ Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength,
+ Task->Packet.Acb->AtaCylinderLow,
+ Task->Packet.Acb->AtaCylinderHigh,
+ Task->Packet.Acb->AtaSectorCount
+ ));
+
+ //
+ // Free the buffer of SubTask.
+ //
+ FreeAtaSubTask (Task);
+}
+
+/**
+ Read or write a number of blocks from ATA device.
+
+ This function performs ATA pass through transactions to read/write data from/to
+ ATA device. It may separate the read/write request into several ATA pass through
+ transactions.
+
+ @param[in, out] AtaDevice The ATA child device involved for the operation.
+ @param[in, out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] NumberOfBlocks The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+AccessAtaDevice(
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT UINT8 *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN BOOLEAN IsWrite,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxTransferBlockNumber;
+ UINTN TransferBlockNumber;
+ UINTN BlockSize;
+ ATA_BUS_ASYN_SUB_TASK *SubTask;
+ UINTN *EventCount;
+ UINTN TempCount;
+ ATA_BUS_ASYN_TASK *AtaTask;
+ EFI_EVENT SubEvent;
+ UINTN Index;
+ BOOLEAN *IsError;
+ EFI_TPL OldTpl;
+
+ TempCount = 0;
+ Status = EFI_SUCCESS;
+ EventCount = NULL;
+ IsError = NULL;
+ Index = 0;
+ SubTask = NULL;
+ SubEvent = NULL;
+ AtaTask = NULL;
+
+ //
+ // Ensure AtaDevice->Lba48Bit is a valid boolean value
+ //
+ ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
+ MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];
+ BlockSize = AtaDevice->BlockMedia.BlockSize;
+
+ //
+ // Initial the return status and shared account for Non Blocking.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {
+ AtaTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));
+ if (AtaTask == NULL) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AtaTask->AtaDevice = AtaDevice;
+ AtaTask->Buffer = Buffer;
+ AtaTask->IsWrite = IsWrite;
+ AtaTask->NumberOfBlocks = NumberOfBlocks;
+ AtaTask->Signature = ATA_TASK_SIGNATURE;
+ AtaTask->StartLba = StartLba;
+ AtaTask->Token = Token;
+
+ InsertTailList (&AtaDevice->AtaTaskList, &AtaTask->TaskEntry);
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ Token->TransactionStatus = EFI_SUCCESS;
+ EventCount = AllocateZeroPool (sizeof (UINTN));
+ if (EventCount == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IsError = AllocateZeroPool (sizeof (BOOLEAN));
+ if (IsError == NULL) {
+ FreePool (EventCount);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DEBUG ((EFI_D_BLKIO, "Allocation IsError Addr=%x\n", IsError));
+ *IsError = FALSE;
+ TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;
+ *EventCount = TempCount;
+ DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, NumberOfBlocks=%x\n", NumberOfBlocks));
+ DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, MaxTransferBlockNumber=%x\n", MaxTransferBlockNumber));
+ DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, EventCount=%x\n", TempCount));
+ } else {
+ while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {
+ //
+ // Stall for 100us.
+ //
+ MicroSecondDelay (100);
+ }
+ }
+
+ do {
+ if (NumberOfBlocks > MaxTransferBlockNumber) {
+ TransferBlockNumber = MaxTransferBlockNumber;
+ NumberOfBlocks -= MaxTransferBlockNumber;
+ } else {
+ TransferBlockNumber = NumberOfBlocks;
+ NumberOfBlocks = 0;
+ }
+
+ //
+ // Create sub event for the sub ata task. Non-blocking mode.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ SubTask = NULL;
+ SubEvent = NULL;
+
+ SubTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_SUB_TASK));
+ if (SubTask == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ SubTask->UnsignalledEventCount = EventCount;
+ SubTask->Signature = ATA_SUB_TASK_SIGNATURE;
+ SubTask->AtaDevice = AtaDevice;
+ SubTask->Token = Token;
+ SubTask->IsError = IsError;
+ InsertTailList (&AtaDevice->AtaSubTaskList, &SubTask->TaskEntry);
+ gBS->RestoreTPL (OldTpl);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AtaNonBlockingCallBack,
+ SubTask,
+ &SubEvent
+ );
+ //
+ // If resource allocation fail, the un-signalled event count should equal to
+ // the original one minus the unassigned subtasks number.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);
+ } else {
+ //
+ // Blocking Mode.
+ //
+ DEBUG ((EFI_D_BLKIO, "Blocking AccessAtaDevice, TransferBlockNumber=%x; StartLba = %x\n", TransferBlockNumber, StartLba));
+ Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ Index++;
+ StartLba += TransferBlockNumber;
+ Buffer += TransferBlockNumber * BlockSize;
+ } while (NumberOfBlocks > 0);
+
+EXIT:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // Release resource at non-blocking mode.
+ //
+ if (EFI_ERROR (Status)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Token->TransactionStatus = Status;
+ *EventCount = (*EventCount) - (TempCount - Index);
+ *IsError = TRUE;
+
+ if (*EventCount == 0) {
+ FreePool (EventCount);
+ FreePool (IsError);
+ }
+
+ if (SubTask != NULL) {
+ RemoveEntryList (&SubTask->TaskEntry);
+ FreeAtaSubTask (SubTask);
+ }
+
+ if (SubEvent != NULL) {
+ gBS->CloseEvent (SubEvent);
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Trust transfer data from/to ATA device.
+
+ This function performs one ATA pass through transaction to do a trust transfer from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param AtaDevice The ATA child device involved for the operation.
+ @param Buffer The pointer to the current transaction buffer.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param TransferLength The block number or sector count of the transfer.
+ @param IsTrustSend Indicates whether it is a trust send operation or not.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data
+ written to the buffer. Ignore it when IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+EFIAPI
+TrustTransferAtaDevice (
+ IN OUT ATA_DEVICE *AtaDevice,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ )
+{
+ EFI_ATA_COMMAND_BLOCK *Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_STATUS Status;
+ VOID *NewBuffer;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+
+ //
+ // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values
+ //
+ ASSERT ((UINTN) AtaDevice->UdmaValid < 2);
+ ASSERT ((UINTN) IsTrustSend < 2);
+ //
+ // Prepare for ATA command block.
+ //
+ Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ if (TransferLength == 0) {
+ Acb->AtaCommand = ATA_CMD_TRUST_NON_DATA;
+ } else {
+ Acb->AtaCommand = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];
+ }
+ Acb->AtaFeatures = SecurityProtocolId;
+ Acb->AtaSectorCount = (UINT8) (TransferLength / 512);
+ Acb->AtaSectorNumber = (UINT8) ((TransferLength / 512) >> 8);
+ //
+ // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.
+ // Here use big endian for Cylinder register.
+ //
+ Acb->AtaCylinderHigh = (UINT8) SecurityProtocolSpecificData;
+ Acb->AtaCylinderLow = (UINT8) (SecurityProtocolSpecificData >> 8);
+ Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ if (TransferLength == 0) {
+ Packet->InTransferLength = 0;
+ Packet->OutTransferLength = 0;
+ Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
+ } else if (IsTrustSend) {
+ //
+ // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru
+ //
+ AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
+ if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
+ NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);
+ if (NewBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (NewBuffer, Buffer, TransferLength);
+ FreePool (Buffer);
+ Buffer = NewBuffer;
+ }
+ Packet->OutDataBuffer = Buffer;
+ Packet->OutTransferLength = (UINT32) TransferLength;
+ Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];
+ } else {
+ Packet->InDataBuffer = Buffer;
+ Packet->InTransferLength = (UINT32) TransferLength;
+ Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];
+ }
+ Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
+ Packet->Timeout = Timeout;
+
+ Status = AtaDevicePassThru (AtaDevice, NULL, NULL);
+ if (TransferLengthOut != NULL) {
+ if (! IsTrustSend) {
+ *TransferLengthOut = Packet->InTransferLength;
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c
new file mode 100644
index 000000000..bb219072f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c
@@ -0,0 +1,232 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for ConPlatform driver.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtaBus.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaBusDriverNameTable[] = {
+ { "eng;en", L"ATA Bus Driver" },
+ { NULL , NULL }
+};
+
+//
+// Controller name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaBusControllerNameTable[] = {
+ { "eng;en", L"ATA Controller" },
+ { NULL , NULL }
+};
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName = {
+ AtaBusComponentNameGetDriverName,
+ AtaBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtaBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtaBusComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+AtaBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mAtaBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gAtaBusComponentName)
+ );
+}
+
+
+/**
+ 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
+AtaBusComponentNameGetControllerName (
+ 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;
+ ATA_DEVICE *AtaDevice;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gAtaBusDriverBinding.DriverBindingHandle,
+ &gEfiAtaPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = mAtaBusControllerNameTable;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiAtaPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gAtaBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo);
+ ControllerNameTable =AtaDevice->ControllerNameTable;
+ }
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gAtaBusComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c
new file mode 100644
index 000000000..1833c0afb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c
@@ -0,0 +1,1492 @@
+/** @file
+ This file implements I2C IO Protocol which enables the user to manipulate a single
+ I2C device independent of the host controller and I2C design.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "I2cDxe.h"
+
+//
+// EFI_DRIVER_BINDING_PROTOCOL instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gI2cBusDriverBinding = {
+ I2cBusDriverSupported,
+ I2cBusDriverStart,
+ I2cBusDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for I2C Bus Child Device.
+//
+I2C_DEVICE_CONTEXT gI2cDeviceContextTemplate = {
+ I2C_DEVICE_SIGNATURE,
+ NULL,
+ { // I2cIo Protocol
+ I2cBusQueueRequest, // QueueRequest
+ NULL, // DeviceGuid
+ 0, // DeviceIndex
+ 0, // HardwareRevision
+ NULL // I2cControllerCapabilities
+ },
+ NULL, // DevicePath
+ NULL, // I2cDevice
+ NULL, // I2cBusContext
+};
+
+//
+// Template for controller device path node.
+//
+CONTROLLER_DEVICE_PATH gControllerDevicePathTemplate = {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_CONTROLLER_DP,
+ {
+ (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),
+ (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+//
+// Template for vendor device path node.
+//
+VENDOR_DEVICE_PATH gVendorDevicePathTemplate = {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
+};
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cBusDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"I2C Bus Driver" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cBusComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) I2cBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) I2cBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cBusComponentName2 = {
+ I2cBusComponentNameGetDriverName,
+ I2cBusComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+I2cBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mI2cBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gI2cBusComponentName2)
+ );
+}
+
+/**
+ 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
+I2cBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Check if the child of I2C controller has been created.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller I2C controller handle.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ @param[in] RemainingHasControllerNode Indicate if RemainingDevicePath contains CONTROLLER_DEVICE_PATH.
+ @param[in] RemainingControllerNumber Controller number in CONTROLLER_DEVICE_PATH.
+
+ @retval EFI_SUCCESS The child of I2C controller is not created.
+ @retval Others The child of I2C controller has been created or other errors happen.
+
+**/
+EFI_STATUS
+CheckRemainingDevicePath (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN BOOLEAN RemainingHasControllerNode,
+ IN UINT32 RemainingControllerNumber
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *SystemDevicePath;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ BOOLEAN SystemHasControllerNode;
+ UINT32 SystemControllerNumber;
+
+ SystemHasControllerNode = FALSE;
+ SystemControllerNumber = 0;
+
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ &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 **) &SystemDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find vendor device path node and compare
+ //
+ while (!IsDevicePathEnd (SystemDevicePath)) {
+ if ((DevicePathType (SystemDevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (SystemDevicePath) == HW_VENDOR_DP)) {
+ //
+ // Check if vendor device path is same between system device path and remaining device path
+ //
+ if (CompareMem (SystemDevicePath, RemainingDevicePath, sizeof (VENDOR_DEVICE_PATH)) == 0) {
+ //
+ // Get controller node appended after vendor node
+ //
+ SystemDevicePath = NextDevicePathNode (SystemDevicePath);
+ if ((DevicePathType (SystemDevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (SystemDevicePath) == HW_CONTROLLER_DP)) {
+ SystemHasControllerNode = TRUE;
+ SystemControllerNumber = ((CONTROLLER_DEVICE_PATH *) SystemDevicePath)->ControllerNumber;
+ } else {
+ SystemHasControllerNode = FALSE;
+ SystemControllerNumber = 0;
+ }
+ if (((SystemHasControllerNode) && (!RemainingHasControllerNode) && (SystemControllerNumber == 0)) ||
+ ((!SystemHasControllerNode) && (RemainingHasControllerNode) && (RemainingControllerNumber == 0)) ||
+ ((SystemHasControllerNode) && (RemainingHasControllerNode) && (SystemControllerNumber == RemainingControllerNumber)) ||
+ ((!SystemHasControllerNode) && (!RemainingHasControllerNode))) {
+ DEBUG ((EFI_D_ERROR, "This I2C device has been already started.\n"));
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+ }
+ SystemDevicePath = NextDevicePathNode (SystemDevicePath);
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ }
+ FreePool (OpenInfoBuffer);
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+I2cBusDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_I2C_ENUMERATE_PROTOCOL *I2cEnumerate;
+ EFI_I2C_HOST_PROTOCOL *I2cHost;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
+ BOOLEAN RemainingHasControllerNode;
+ UINT32 RemainingControllerNumber;
+
+ RemainingHasControllerNode = FALSE;
+ RemainingControllerNumber = 0;
+
+ //
+ // Determine if the I2c Enumerate Protocol is available
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cEnumerateProtocolGuid,
+ (VOID **) &I2cEnumerate,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cEnumerateProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ 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;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // Check if the first node of RemainingDevicePath is a hardware vendor device path
+ //
+ if ((DevicePathType (RemainingDevicePath) != HARDWARE_DEVICE_PATH) ||
+ (DevicePathSubType (RemainingDevicePath) != HW_VENDOR_DP)) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check if the second node of RemainingDevicePath is a controller node
+ //
+ DevPathNode = NextDevicePathNode (RemainingDevicePath);
+ if (!IsDevicePathEnd (DevPathNode)) {
+ if ((DevicePathType (DevPathNode) != HARDWARE_DEVICE_PATH) ||
+ (DevicePathSubType (DevPathNode) != HW_CONTROLLER_DP)) {
+ return EFI_UNSUPPORTED;
+ } else {
+ RemainingHasControllerNode = TRUE;
+ RemainingControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevPathNode)->ControllerNumber;
+ }
+ }
+ }
+
+ //
+ // Determine if the I2C Host Protocol is available
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ (VOID **) &I2cHost,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+
+ if (Status == EFI_ALREADY_STARTED) {
+ if ((RemainingDevicePath == NULL) ||
+ ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath))) {
+ //
+ // If RemainingDevicePath is NULL or is the End of Device Path Node, return EFI_SUCCESS.
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Test if the child with the RemainingDevicePath has already been created.
+ //
+ Status = CheckRemainingDevicePath (
+ This,
+ Controller,
+ RemainingDevicePath,
+ RemainingHasControllerNode,
+ RemainingControllerNumber
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_I2C_ENUMERATE_PROTOCOL *I2cEnumerate;
+ EFI_I2C_HOST_PROTOCOL *I2cHost;
+ I2C_BUS_CONTEXT *I2cBusContext;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ I2cBusContext = NULL;
+ ParentDevicePath = NULL;
+ I2cEnumerate = NULL;
+ I2cHost = NULL;
+
+ //
+ // Determine if the I2C controller is available
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ (VOID**)&I2cHost,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: open I2C host error, Status = %r\n", Status));
+ return Status;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &I2cBusContext,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: open private protocol error, Status = %r.\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Get the I2C bus enumeration API
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cEnumerateProtocolGuid,
+ (VOID**)&I2cEnumerate,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: open I2C enumerate error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: open device path error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create any child device and return EFI_SUCCESS
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Allocate the buffer for I2C_BUS_CONTEXT if it is not allocated before.
+ //
+ if (I2cBusContext == NULL) {
+ //
+ // Allocate the I2C context structure for the current I2C controller
+ //
+ I2cBusContext = AllocateZeroPool (sizeof (I2C_BUS_CONTEXT));
+ if (I2cBusContext == NULL) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: there is no enough memory to allocate.\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ /*
+ +----------------+
+ .->| I2C_BUS_CONTEXT|<----- This file Protocol (gEfiCallerIdGuid) installed on I2C Controller handle
+ | +----------------+
+ |
+ | +----------------------------+
+ | | I2C_DEVICE_CONTEXT |
+ `--| |
+ | |
+ | I2C IO Protocol Structure | <----- I2C IO Protocol
+ | |
+ +----------------------------+
+
+ */
+ I2cBusContext->I2cHost = I2cHost;
+ I2cBusContext->I2cEnumerate = I2cEnumerate;
+ //
+ // Parent controller used to create children
+ //
+ I2cBusContext->Controller = Controller;
+ //
+ // Parent controller device path used to create children device path
+ //
+ I2cBusContext->ParentDevicePath = ParentDevicePath;
+
+ I2cBusContext->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiCallerIdGuid,
+ I2cBusContext,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: install private protocol error, Status = %r.\n", Status));
+ goto Error;
+ }
+ }
+
+ //
+ // Start the driver
+ //
+ Status = RegisterI2cDevice (I2cBusContext, Controller, RemainingDevicePath);
+
+ return Status;
+
+Error:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cBus: Start() function failed, Status = %r\n", Status));
+ if (ParentDevicePath != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (I2cHost != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (I2cEnumerate != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cEnumerateProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (I2cBusContext != NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ gEfiCallerIdGuid,
+ I2cBusContext,
+ NULL
+ );
+ FreePool (I2cBusContext);
+ }
+ }
+
+ //
+ // Return the operation status.
+ //
+ return Status;
+}
+
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+I2cBusDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ I2C_BUS_CONTEXT *I2cBusContext;
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+
+ if (NumberOfChildren == 0) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cEnumerateProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &I2cBusContext,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ I2cBusContext,
+ NULL
+ );
+ //
+ // No more child now, free bus context data.
+ //
+ FreePool (I2cBusContext);
+ }
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = UnRegisterI2cDevice (This, Controller, ChildHandleBuffer[Index]);
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Enumerate the I2C bus
+
+ This routine walks the platform specific data describing the
+ I2C bus to create the I2C devices where driver GUIDs were
+ specified.
+
+ @param[in] I2cBusContext Address of an I2C_BUS_CONTEXT structure
+ @param[in] Controller Handle to the controller
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The bus is successfully configured
+
+**/
+EFI_STATUS
+RegisterI2cDevice (
+ IN I2C_BUS_CONTEXT *I2cBusContext,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ I2C_DEVICE_CONTEXT *I2cDeviceContext;
+ EFI_STATUS Status;
+ CONST EFI_I2C_DEVICE *Device;
+ CONST EFI_I2C_DEVICE *TempDevice;
+ UINT32 RemainingPathDeviceIndex;
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
+ BOOLEAN BuildControllerNode;
+ UINTN Count;
+
+ Status = EFI_SUCCESS;
+ BuildControllerNode = TRUE;
+
+ //
+ // Default DeviceIndex
+ //
+ RemainingPathDeviceIndex = 0;
+
+ //
+ // Determine the controller number in Controller Node Device Path when RemainingDevicePath is not NULL.
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if there is a controller node appended after vendor node
+ //
+ DevPathNode = NextDevicePathNode (RemainingDevicePath);
+ if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType(DevPathNode) == HW_CONTROLLER_DP)) {
+ //
+ // RemainingDevicePath != NULL and RemainingDevicePath contains Controller Node,
+ // add Controller Node to Device Path on child handle.
+ //
+ RemainingPathDeviceIndex = ((CONTROLLER_DEVICE_PATH *) DevPathNode)->ControllerNumber;
+ } else {
+ //
+ // RemainingDevicePath != NULL and RemainingDevicePath does not contain Controller Node,
+ // do not add controller node to Device Path on child handle.
+ //
+ BuildControllerNode = FALSE;
+ }
+ }
+
+ //
+ // Walk the list of I2C devices on this bus
+ //
+ Device = NULL;
+ while (TRUE) {
+ //
+ // Get the next I2C device
+ //
+ Status = I2cBusContext->I2cEnumerate->Enumerate (I2cBusContext->I2cEnumerate, &Device);
+ if (EFI_ERROR (Status) || Device == NULL) {
+ if (RemainingDevicePath != NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ break;
+ }
+
+ //
+ // Determine if the device info is valid
+ //
+ if ((Device->DeviceGuid == NULL) || (Device->SlaveAddressCount == 0) || (Device->SlaveAddressArray == NULL)) {
+ DEBUG ((EFI_D_ERROR, "Invalid EFI_I2C_DEVICE reported by I2c Enumerate protocol.\n"));
+ continue;
+ }
+
+ if (RemainingDevicePath == NULL) {
+ if (Device->DeviceIndex == 0) {
+ //
+ // Determine if the controller node is necessary when controller number is zero in I2C device
+ //
+ TempDevice = NULL;
+ Count = 0;
+ while (TRUE) {
+ //
+ // Get the next I2C device
+ //
+ Status = I2cBusContext->I2cEnumerate->Enumerate (I2cBusContext->I2cEnumerate, &TempDevice);
+ if (EFI_ERROR (Status) || TempDevice == NULL) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ if (CompareGuid (Device->DeviceGuid, TempDevice->DeviceGuid)) {
+ Count++;
+ }
+ }
+ if (Count == 1) {
+ //
+ // RemainingDevicePath == NULL and only DeviceIndex 0 is present on the I2C bus,
+ // do not add Controller Node to Device Path on child handle.
+ //
+ BuildControllerNode = FALSE;
+ }
+ }
+ } else {
+ //
+ // Find I2C device reported in Remaining Device Path
+ //
+ if ((!CompareGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid, Device->DeviceGuid)) ||
+ (RemainingPathDeviceIndex != Device->DeviceIndex)) {
+ continue;
+ }
+ }
+
+ //
+ // Build the device context for current I2C device.
+ //
+ I2cDeviceContext = NULL;
+ I2cDeviceContext = AllocateCopyPool (sizeof (I2C_DEVICE_CONTEXT), &gI2cDeviceContextTemplate);
+ ASSERT (I2cDeviceContext != NULL);
+ if (I2cDeviceContext == NULL) {
+ continue;
+ }
+
+ //
+ // Initialize the specific device context
+ //
+ I2cDeviceContext->I2cBusContext = I2cBusContext;
+ I2cDeviceContext->I2cDevice = Device;
+ I2cDeviceContext->I2cIo.DeviceGuid = Device->DeviceGuid;
+ I2cDeviceContext->I2cIo.DeviceIndex = Device->DeviceIndex;
+ I2cDeviceContext->I2cIo.HardwareRevision = Device->HardwareRevision;
+ I2cDeviceContext->I2cIo.I2cControllerCapabilities = I2cBusContext->I2cHost->I2cControllerCapabilities;
+
+ //
+ // Build the device path
+ //
+ Status = I2cBusDevicePathAppend (I2cDeviceContext, BuildControllerNode);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Install the protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &I2cDeviceContext->Handle,
+ &gEfiI2cIoProtocolGuid,
+ &I2cDeviceContext->I2cIo,
+ &gEfiDevicePathProtocolGuid,
+ I2cDeviceContext->DevicePath,
+ NULL );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free resources for this I2C device
+ //
+ ReleaseI2cDeviceContext (I2cDeviceContext);
+ continue;
+ }
+
+ //
+ // Create the child handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ (VOID **) &I2cBusContext->I2cHost,
+ I2cBusContext->DriverBindingHandle,
+ I2cDeviceContext->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ I2cDeviceContext->Handle,
+ &gEfiDevicePathProtocolGuid,
+ I2cDeviceContext->DevicePath,
+ &gEfiI2cIoProtocolGuid,
+ &I2cDeviceContext->I2cIo,
+ NULL
+ );
+ //
+ // Free resources for this I2C device
+ //
+ ReleaseI2cDeviceContext (I2cDeviceContext);
+ continue;
+ }
+
+ if (RemainingDevicePath != NULL) {
+ //
+ // Child has been created successfully
+ //
+ break;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Queue an I2C transaction for execution on the I2C device.
+
+ This routine must be called at or below TPL_NOTIFY. For synchronous
+ requests this routine must be called at or below TPL_CALLBACK.
+
+ This routine queues an I2C transaction to the I2C controller for
+ execution on the I2C bus.
+
+ When Event is NULL, QueueRequest() operates synchronously and returns
+ the I2C completion status as its return value.
+
+ When Event is not NULL, QueueRequest() synchronously returns EFI_SUCCESS
+ indicating that the asynchronous I2C transaction was queued. The values
+ above are returned in the buffer pointed to by I2cStatus upon the
+ completion of the I2C transaction when I2cStatus is not NULL.
+
+ The upper layer driver writer provides the following to the platform
+ vendor:
+
+ 1. Vendor specific GUID for the I2C part
+ 2. Guidance on proper construction of the slave address array when the
+ I2C device uses more than one slave address. The I2C bus protocol
+ uses the SlaveAddressIndex to perform relative to physical address
+ translation to access the blocks of hardware within the I2C device.
+
+ @param[in] This Pointer to an EFI_I2C_IO_PROTOCOL structure.
+ @param[in] SlaveAddressIndex Index value into an array of slave addresses
+ for the I2C device. The values in the array
+ are specified by the board designer, with the
+ third party I2C device driver writer providing
+ the slave address order.
+
+ For devices that have a single slave address,
+ this value must be zero. If the I2C device
+ uses more than one slave address then the
+ third party (upper level) I2C driver writer
+ needs to specify the order of entries in the
+ slave address array.
+
+ \ref ThirdPartyI2cDrivers "Third Party I2C
+ Drivers" section in I2cMaster.h.
+ @param[in] Event Event to signal for asynchronous transactions,
+ NULL for synchronous transactions
+ @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET structure
+ describing the I2C transaction
+ @param[out] I2cStatus Optional buffer to receive the I2C transaction
+ completion status
+
+ @retval EFI_SUCCESS The asynchronous transaction was successfully
+ queued when Event is not NULL.
+ @retval EFI_SUCCESS The transaction completed successfully when
+ Event is NULL.
+ @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too
+ large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the
+ transaction.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_NO_MAPPING The EFI_I2C_HOST_PROTOCOL could not set the
+ bus configuration required to access this I2C
+ device.
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the slave
+ address selected by SlaveAddressIndex.
+ EFI_DEVICE_ERROR will be returned if the
+ controller cannot distinguish when the NACK
+ occurred.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction
+ @retval EFI_UNSUPPORTED The controller does not support the requested
+ transaction.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusQueueRequest (
+ IN CONST EFI_I2C_IO_PROTOCOL *This,
+ IN UINTN SlaveAddressIndex,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ )
+{
+ CONST EFI_I2C_DEVICE *I2cDevice;
+ I2C_BUS_CONTEXT *I2cBusContext;
+ CONST EFI_I2C_HOST_PROTOCOL *I2cHost;
+ I2C_DEVICE_CONTEXT *I2cDeviceContext;
+ EFI_STATUS Status;
+
+ if (RequestPacket == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Validate the I2C slave index
+ //
+ I2cDeviceContext = I2C_DEVICE_CONTEXT_FROM_PROTOCOL (This);
+ I2cDevice = I2cDeviceContext->I2cDevice;
+ if ( SlaveAddressIndex >= I2cDevice->SlaveAddressCount ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Locate the I2c Host Protocol to queue request
+ //
+ I2cBusContext = I2cDeviceContext->I2cBusContext;
+ I2cHost = I2cBusContext->I2cHost;
+
+ //
+ // Start the I2C operation
+ //
+ Status = I2cHost->QueueRequest (
+ I2cHost,
+ I2cDevice->I2cBusConfiguration,
+ I2cDevice->SlaveAddressArray [SlaveAddressIndex],
+ Event,
+ RequestPacket,
+ I2cStatus
+ );
+
+ return Status;
+}
+
+/**
+ Release all the resources allocated for the I2C device.
+
+ This function releases all the resources allocated for the I2C device.
+
+ @param I2cDeviceContext The I2C child device involved for the operation.
+
+**/
+VOID
+ReleaseI2cDeviceContext (
+ IN I2C_DEVICE_CONTEXT *I2cDeviceContext
+ )
+{
+ if (I2cDeviceContext == NULL) {
+ return;
+ }
+
+ if (I2cDeviceContext->DevicePath != NULL) {
+ FreePool (I2cDeviceContext->DevicePath);
+ }
+
+ FreePool (I2cDeviceContext);
+}
+
+/**
+ Unregister an I2C device.
+
+ This function removes the protocols installed on the controller handle and
+ frees the resources allocated for the I2C device.
+
+ @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The controller handle of the I2C device.
+ @param Handle The child handle.
+
+ @retval EFI_SUCCESS The I2C device is successfully unregistered.
+ @return Others Some error occurs when unregistering the I2C device.
+
+**/
+EFI_STATUS
+UnRegisterI2cDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ I2C_DEVICE_CONTEXT *I2cDeviceContext;
+ EFI_I2C_IO_PROTOCOL *I2cIo;
+ EFI_I2C_HOST_PROTOCOL *I2cHost;
+
+ I2cIo = NULL;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &I2cIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get I2c device context data.
+ //
+ I2cDeviceContext = I2C_DEVICE_CONTEXT_FROM_PROTOCOL (I2cIo);
+
+ //
+ // Close the child handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // The I2C Bus driver installs the I2C Io and Device Path Protocol in the DriverBindingStart().
+ // Here should uninstall them.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ I2cDeviceContext->DevicePath,
+ &gEfiI2cIoProtocolGuid,
+ &I2cDeviceContext->I2cIo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Keep parent and child relationship
+ //
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ (VOID **) &I2cHost,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // Free resources for this I2C device
+ //
+ ReleaseI2cDeviceContext (I2cDeviceContext);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a path for the I2C device
+
+ Append the I2C slave path to the I2C master controller path.
+
+ @param[in] I2cDeviceContext Address of an I2C_DEVICE_CONTEXT structure.
+ @param[in] BuildControllerNode Flag to build controller node in device path.
+
+ @retval EFI_SUCCESS The I2C device path is built successfully.
+ @return Others It is failed to built device path.
+
+**/
+EFI_STATUS
+I2cBusDevicePathAppend (
+ IN I2C_DEVICE_CONTEXT *I2cDeviceContext,
+ IN BOOLEAN BuildControllerNode
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *PreviousDevicePath;
+
+ PreviousDevicePath = NULL;
+
+ //
+ // Build vendor device path
+ //
+ CopyMem (&gVendorDevicePathTemplate.Guid, I2cDeviceContext->I2cDevice->DeviceGuid, sizeof (EFI_GUID));
+ I2cDeviceContext->DevicePath = AppendDevicePathNode (
+ I2cDeviceContext->I2cBusContext->ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &gVendorDevicePathTemplate
+ );
+ ASSERT (I2cDeviceContext->DevicePath != NULL);
+ if (I2cDeviceContext->DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((BuildControllerNode) && (I2cDeviceContext->DevicePath != NULL)) {
+ //
+ // Build the final I2C device path with controller node
+ //
+ PreviousDevicePath = I2cDeviceContext->DevicePath;
+ gControllerDevicePathTemplate.ControllerNumber = I2cDeviceContext->I2cDevice->DeviceIndex;
+ I2cDeviceContext->DevicePath = AppendDevicePathNode (
+ I2cDeviceContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &gControllerDevicePathTemplate
+ );
+ gBS->FreePool (PreviousDevicePath);
+ ASSERT (I2cDeviceContext->DevicePath != NULL);
+ if (I2cDeviceContext->DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user entry point for the I2C bus module. 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
+InitializeI2cBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gI2cBusDriverBinding,
+ NULL,
+ &gI2cBusComponentName,
+ &gI2cBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+/**
+ This is the unload handle for I2C bus module.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+
+ //
+ // Get the list of all I2C Controller handles in the handle database.
+ // If there is an error getting the list, then the unload
+ // operation fails.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiI2cHostProtocolGuid,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Disconnect the driver specified by Driver BindingHandle from all
+ // the devices in the handle database.
+ //
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ gI2cBusDriverBinding.DriverBindingHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Uninstall all the protocols installed in the driver entry point
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gI2cBusDriverBinding.DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gI2cBusDriverBinding,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Note we have to one by one uninstall the following protocols.
+ // It's because some of them are optionally installed based on
+ // the following PCD settings.
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable
+ //
+ Status = gBS->HandleProtocol (
+ gI2cBusDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ gI2cBusDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ ComponentName
+ );
+ }
+
+ Status = gBS->HandleProtocol (
+ gI2cBusDriverBinding.DriverBindingHandle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ gI2cBusDriverBinding.DriverBindingHandle,
+ &gEfiComponentName2ProtocolGuid,
+ ComponentName2
+ );
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf
new file mode 100644
index 000000000..6dc14022d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# This driver enumerates I2C devices on I2C bus and produce I2C IO Protocol on I2C devices.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = I2cBusDxe
+ MODULE_UNI_FILE = I2cBusDxe.uni
+ FILE_GUID = 0C34B372-2622-4A13-A46E-BFD0DEB48BFF
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeI2cBus
+ UNLOAD_IMAGE = I2cBusUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ I2cDxe.h
+ I2cBus.c
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Protocols]
+ gEfiI2cIoProtocolGuid ## BY_START
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiI2cEnumerateProtocolGuid ## TO_START
+ gEfiI2cHostProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ I2cBusDxeExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.uni
new file mode 100644
index 000000000..fe17e1d18
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver enumerates I2C devices on I2C bus and produce I2C IO Protocol on I2C devices.
+//
+// This driver enumerates I2C devices on I2C bus and produce I2C IO Protocol on I2C devices.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This driver enumerates I2C devices on I2C bus and produce I2C IO Protocol on I2C devices."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver enumerates I2C devices on I2C bus and produce I2C IO Protocol on I2C devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxeExtra.uni
new file mode 100644
index 000000000..0e87aec58
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// I2cBusDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"I2C Bus DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.c b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.c
new file mode 100644
index 000000000..bb5d83927
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.c
@@ -0,0 +1,69 @@
+/** @file
+ This file implements the entrypoint and unload function for I2C DXE module.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "I2cDxe.h"
+
+/**
+ The user Entry Point for I2C module. 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
+InitializeI2c(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = InitializeI2cHost ( ImageHandle, SystemTable );
+ if ( !EFI_ERROR ( Status ))
+ {
+ Status = InitializeI2cBus ( ImageHandle, SystemTable );
+ }
+ return Status;
+}
+
+/**
+ This is the unload handle for I2C module.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disconnect the drivers
+ //
+ Status = I2cBusUnload ( ImageHandle );
+ if ( !EFI_ERROR ( Status )) {
+ Status = I2cHostUnload ( ImageHandle );
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.h b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.h
new file mode 100644
index 000000000..49f1e9b17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.h
@@ -0,0 +1,1091 @@
+/** @file
+ Private data structures for the I2C DXE driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __I2C_DXE_H__
+#define __I2C_DXE_H__
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/I2cEnumerate.h>
+#include <Protocol/I2cHost.h>
+#include <Protocol/I2cIo.h>
+#include <Protocol/I2cMaster.h>
+#include <Protocol/I2cBusConfigurationManagement.h>
+#include <Protocol/LoadedImage.h>
+
+#define I2C_DEVICE_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'D')
+#define I2C_HOST_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'H')
+#define I2C_REQUEST_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'R')
+
+//
+// Synchronize access to the list of requests
+//
+#define TPL_I2C_SYNC TPL_NOTIFY
+
+//
+// I2C bus context
+//
+typedef struct {
+ EFI_I2C_ENUMERATE_PROTOCOL *I2cEnumerate;
+ EFI_I2C_HOST_PROTOCOL *I2cHost;
+ EFI_HANDLE Controller;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_HANDLE DriverBindingHandle;
+} I2C_BUS_CONTEXT;
+
+//
+// I2C device context
+//
+typedef struct {
+ //
+ // Structure identification
+ //
+ UINT32 Signature;
+
+ //
+ // I2c device handle
+ //
+ EFI_HANDLE Handle;
+
+ //
+ // Upper level API to support the I2C device I/O
+ //
+ EFI_I2C_IO_PROTOCOL I2cIo;
+
+ //
+ // Device path for this device
+ //
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Platform specific data for this device
+ //
+ CONST EFI_I2C_DEVICE *I2cDevice;
+
+ //
+ // Context for the common I/O support including the
+ // lower level API to the host controller.
+ //
+ I2C_BUS_CONTEXT *I2cBusContext;
+} I2C_DEVICE_CONTEXT;
+
+#define I2C_DEVICE_CONTEXT_FROM_PROTOCOL(a) CR (a, I2C_DEVICE_CONTEXT, I2cIo, I2C_DEVICE_SIGNATURE)
+
+//
+// I2C Request
+//
+typedef struct {
+ //
+ // Signature
+ //
+ UINT32 Signature;
+
+ //
+ // Next request in the pending request list
+ //
+ LIST_ENTRY Link;
+
+ //
+ // I2C bus configuration for the operation
+ //
+ UINTN I2cBusConfiguration;
+
+ //
+ // I2C slave address for the operation
+ //
+ UINTN SlaveAddress;
+
+ //
+ // Event to set for asynchronous operations, NULL for
+ // synchronous operations
+ //
+ EFI_EVENT Event;
+
+ //
+ // I2C operation description
+ //
+ EFI_I2C_REQUEST_PACKET *RequestPacket;
+
+ //
+ // Optional buffer to receive the I2C operation completion status
+ //
+ EFI_STATUS *Status;
+} I2C_REQUEST;
+
+#define I2C_REQUEST_FROM_ENTRY(a) CR (a, I2C_REQUEST, Link, I2C_REQUEST_SIGNATURE);
+
+//
+// I2C host context
+//
+typedef struct {
+ //
+ // Structure identification
+ //
+ UINTN Signature;
+
+ //
+ // Current I2C bus configuration
+ //
+ UINTN I2cBusConfiguration;
+
+ //
+ // I2C bus configuration management event
+ //
+ EFI_EVENT I2cBusConfigurationEvent;
+
+ //
+ // I2C operation completion event
+ //
+ EFI_EVENT I2cEvent;
+
+ //
+ // I2C operation and I2C bus configuration management status
+ //
+ EFI_STATUS Status;
+
+ //
+ // I2C bus configuration management operation pending
+ //
+ BOOLEAN I2cBusConfigurationManagementPending;
+
+ //
+ // I2C request list maintained by I2C Host
+ //
+ LIST_ENTRY RequestList;
+
+ //
+ // Upper level API
+ //
+ EFI_I2C_HOST_PROTOCOL I2cHost;
+
+ //
+ // I2C bus configuration management protocol
+ //
+ EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
+
+ //
+ // Lower level API for I2C master (controller)
+ //
+ EFI_I2C_MASTER_PROTOCOL *I2cMaster;
+} I2C_HOST_CONTEXT;
+
+#define I2C_HOST_CONTEXT_FROM_PROTOCOL(a) CR (a, I2C_HOST_CONTEXT, I2cHost, I2C_HOST_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gI2cBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gI2cBusComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gI2cBusDriverBinding;
+
+extern EFI_COMPONENT_NAME_PROTOCOL gI2cHostComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gI2cHostComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gI2cHostDriverBinding;
+
+/**
+ Start the I2C driver
+
+ This routine allocates the necessary resources for the driver.
+
+ This routine is called by I2cBusDriverStart to complete the driver
+ initialization.
+
+ @param[in] I2cBus Address of an I2C_BUS_CONTEXT structure
+ @param[in] Controller Handle to the controller
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Driver API properly initialized
+
+**/
+EFI_STATUS
+RegisterI2cDevice (
+ IN I2C_BUS_CONTEXT *I2cBus,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Unregister an I2C device.
+
+ This function removes the protocols installed on the controller handle and
+ frees the resources allocated for the I2C device.
+
+ @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The controller handle of the I2C device.
+ @param Handle The child handle.
+
+ @retval EFI_SUCCESS The I2C device is successfully unregistered.
+ @return Others Some error occurs when unregistering the I2C device.
+
+**/
+EFI_STATUS
+UnRegisterI2cDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Create a path for the I2C device
+
+ Append the I2C slave path to the I2C master controller path.
+
+ @param[in] I2cDeviceContext Address of an I2C_DEVICE_CONTEXT structure.
+ @param[in] BuildControllerNode Flag to build controller node in device path.
+
+ @retval EFI_SUCCESS The I2C device path is built successfully.
+ @return Others It is failed to built device path.
+
+**/
+EFI_STATUS
+I2cBusDevicePathAppend (
+ IN I2C_DEVICE_CONTEXT *I2cDeviceContext,
+ IN BOOLEAN BuildControllerNode
+ );
+
+/**
+ Queue an I2C transaction for execution on the I2C device.
+
+ This routine must be called at or below TPL_NOTIFY. For synchronous
+ requests this routine must be called at or below TPL_CALLBACK.
+
+ This routine queues an I2C transaction to the I2C controller for
+ execution on the I2C bus.
+
+ When Event is NULL, QueueRequest() operates synchronously and returns
+ the I2C completion status as its return value.
+
+ When Event is not NULL, QueueRequest() synchronously returns EFI_SUCCESS
+ indicating that the asynchronous I2C transaction was queued. The values
+ above are returned in the buffer pointed to by I2cStatus upon the
+ completion of the I2C transaction when I2cStatus is not NULL.
+
+ The upper layer driver writer provides the following to the platform
+ vendor:
+
+ 1. Vendor specific GUID for the I2C part
+ 2. Guidance on proper construction of the slave address array when the
+ I2C device uses more than one slave address. The I2C bus protocol
+ uses the SlaveAddressIndex to perform relative to physical address
+ translation to access the blocks of hardware within the I2C device.
+
+ @param[in] This Pointer to an EFI_I2C_IO_PROTOCOL structure.
+ @param[in] SlaveAddressIndex Index value into an array of slave addresses
+ for the I2C device. The values in the array
+ are specified by the board designer, with the
+ third party I2C device driver writer providing
+ the slave address order.
+
+ For devices that have a single slave address,
+ this value must be zero. If the I2C device
+ uses more than one slave address then the
+ third party (upper level) I2C driver writer
+ needs to specify the order of entries in the
+ slave address array.
+
+ \ref ThirdPartyI2cDrivers "Third Party I2C
+ Drivers" section in I2cMaster.h.
+ @param[in] Event Event to signal for asynchronous transactions,
+ NULL for synchronous transactions
+ @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET structure
+ describing the I2C transaction
+ @param[out] I2cStatus Optional buffer to receive the I2C transaction
+ completion status
+
+ @retval EFI_SUCCESS The asynchronous transaction was successfully
+ queued when Event is not NULL.
+ @retval EFI_SUCCESS The transaction completed successfully when
+ Event is NULL.
+ @retval EFI_ABORTED The request did not complete because the driver
+ binding Stop() routine was called.
+ @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too
+ large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the
+ transaction.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_NOT_FOUND Reserved bit set in the SlaveAddress parameter
+ @retval EFI_NO_MAPPING The EFI_I2C_HOST_PROTOCOL could not set the
+ bus configuration required to access this I2C
+ device.
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the slave
+ address selected by SlaveAddressIndex.
+ EFI_DEVICE_ERROR will be returned if the
+ controller cannot distinguish when the NACK
+ occurred.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction
+ @retval EFI_UNSUPPORTED The controller does not support the requested
+ transaction.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusQueueRequest (
+ IN CONST EFI_I2C_IO_PROTOCOL *This,
+ IN UINTN SlaveAddressIndex,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+I2cBusDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+I2cBusDriverStop (
+ 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
+I2cBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_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
+I2cBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ The user entry point for the I2C bus module. 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
+InitializeI2cBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ This is the unload handle for I2C bus module.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cBusUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Release all the resources allocated for the I2C device.
+
+ This function releases all the resources allocated for the I2C device.
+
+ @param I2cDeviceContext The I2C child device involved for the operation.
+
+**/
+VOID
+ReleaseI2cDeviceContext (
+ IN I2C_DEVICE_CONTEXT *I2cDeviceContext
+ );
+
+/**
+ Complete the current request
+
+ @param[in] I2cHost Address of an I2C_HOST_CONTEXT structure.
+ @param[in] Status Status of the I<sub>2</sub>C operation.
+
+ @return This routine returns the input status value.
+
+**/
+EFI_STATUS
+I2cHostRequestComplete (
+ I2C_HOST_CONTEXT *I2cHost,
+ EFI_STATUS Status
+ );
+
+/**
+ Enable access to the I2C bus configuration
+
+ @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_ABORTED The request did not complete because the driver
+ was shutdown.
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
+ This could indicate the slave device is not present.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the
+ slave address. EFI_DEVICE_ERROR may also be
+ returned if the controller can not distinguish
+ when the NACK occurred.
+ @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
+ @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
+ the event and then read status.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
+ @retval EFI_TIMEOUT The transaction did not complete within an internally
+ specified timeout period.
+
+**/
+EFI_STATUS
+I2cHostRequestEnable (
+ I2C_HOST_CONTEXT *I2cHost
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+I2cHostDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+I2cHostDriverStop (
+ 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
+I2cHostComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_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
+I2cHostComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Handle the bus available event
+
+ This routine is called at TPL_I2C_SYNC.
+
+ @param[in] Event Address of an EFI_EVENT handle
+ @param[in] Context Address of an I2C_HOST_CONTEXT structure
+
+**/
+VOID
+EFIAPI
+I2cHostRequestCompleteEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Handle the I2C bus configuration available event
+
+ This routine is called at TPL_I2C_SYNC.
+
+ @param[in] Event Address of an EFI_EVENT handle
+ @param[in] Context Address of an I2C_HOST_CONTEXT structure
+
+**/
+VOID
+EFIAPI
+I2cHostI2cBusConfigurationAvailable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Queue an I2C operation for execution on the I2C controller.
+
+ This routine must be called at or below TPL_NOTIFY. For synchronous
+ requests this routine must be called at or below TPL_CALLBACK.
+
+ N.B. The typical consumers of this API are the I2C bus driver and
+ on rare occasions the I2C test application. Extreme care must be
+ taken by other consumers of this API to prevent confusing the
+ third party I2C drivers due to a state change at the I2C device
+ which the third party I2C drivers did not initiate. I2C platform
+ drivers may use this API within these guidelines.
+
+ This layer uses the concept of I2C bus configurations to describe
+ the I2C bus. An I2C bus configuration is defined as a unique
+ setting of the multiplexers and switches in the I2C bus which
+ enable access to one or more I2C devices. When using a switch
+ to divide a bus, due to speed differences, the I2C platform layer
+ would define an I2C bus configuration for the I2C devices on each
+ side of the switch. When using a multiplexer, the I2C platform
+ layer defines an I2C bus configuration for each of the selector
+ values required to control the multiplexer. See Figure 1 in the
+ <a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">I<sup>2</sup>C
+ Specification</a> for a complex I2C bus configuration.
+
+ The I2C host driver processes all operations in FIFO order. Prior to
+ performing the operation, the I2C host driver calls the I2C platform
+ driver to reconfigure the switches and multiplexers in the I2C bus
+ enabling access to the specified I2C device. The I2C platform driver
+ also selects the maximum bus speed for the device. After the I2C bus
+ is configured, the I2C host driver calls the I2C port driver to
+ initialize the I2C controller and start the I2C operation.
+
+ @param[in] This Address of an EFI_I2C_HOST_PROTOCOL instance.
+ @param[in] I2cBusConfiguration I2C bus configuration to access the I2C
+ device.
+ @param[in] SlaveAddress Address of the device on the I2C bus.
+ @param[in] Event Event to set for asynchronous operations,
+ NULL for synchronous operations
+ @param[in] RequestPacket Address of an EFI_I2C_REQUEST_PACKET
+ structure describing the I2C operation
+ @param[out] I2cStatus Optional buffer to receive the I2C operation
+ completion status
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_ABORTED The request did not complete because the driver
+ was shutdown.
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
+ This could indicate the slave device is not present.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_INVALID_PARAMETER TPL is too high
+ @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the
+ slave address. EFI_DEVICE_ERROR may also be
+ returned if the controller can not distinguish
+ when the NACK occurred.
+ @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
+ @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
+ the event and then read status pointed to by
+ the request packet.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
+ @retval EFI_TIMEOUT The transaction did not complete within an internally
+ specified timeout period.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostQueueRequest (
+ IN CONST EFI_I2C_HOST_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN UINTN SlaveAddress,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ );
+
+/**
+ The user Entry Point for I2C host module. 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
+InitializeI2cHost(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ This is the unload handle for I2C host module.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+#endif // __I2C_DXE_H__
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
new file mode 100644
index 000000000..1ee8324b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# I2c Dxe driver includes both I2c Bus and Host functionality.
+#
+# This driver produce I2C Host Protocol on I2C controller handle, enumerate I2C
+# devices on I2C bus and produce I2C IO Protocol on I2C devices.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = I2cDxe
+ MODULE_UNI_FILE = I2cDxe.uni
+ FILE_GUID = ECA2AE9E-7594-4901-871C-449DA1A11660
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeI2c
+ UNLOAD_IMAGE = I2cUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ I2cDxe.c
+ I2cDxe.h
+ I2cHost.c
+ I2cBus.c
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Protocols]
+ gEfiI2cIoProtocolGuid ## BY_START
+ ## BY_START
+ ## TO_START
+ gEfiI2cHostProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiI2cMasterProtocolGuid ## TO_START
+ gEfiI2cEnumerateProtocolGuid ## TO_START
+ gEfiI2cBusConfigurationManagementProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ I2cDxeExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.uni
new file mode 100644
index 000000000..47e3e6d30
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// I2c Dxe driver includes both I2c Bus and Host functionality.
+//
+// This driver produce I2C Host Protocol on I2C controller handle, enumerate I2C
+// devices on I2C bus and produce I2C IO Protocol on I2C devices.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This driver produce I2C Host Protocol on I2C controller handle, enumerate I2C devices on I2C bus and produce I2C IO Protocol on I2C devices."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produce I2C Host Protocol on I2C controller handle, enumerate I2C devices on I2C bus and produce I2C IO Protocol on I2C devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxeExtra.uni
new file mode 100644
index 000000000..9e22f6050
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// I2cDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"I2C DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c
new file mode 100644
index 000000000..95294c9c9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c
@@ -0,0 +1,1222 @@
+/** @file
+ This file implements I2C Host Protocol which provides callers with the ability to
+ do I/O transactions to all of the devices on the I2C bus.
+
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "I2cDxe.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gI2cHostDriverBinding = {
+ I2cHostDriverSupported,
+ I2cHostDriverStart,
+ I2cHostDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cHostDriverNameTable[] = {
+ { "eng;en", L"I2c Host Driver" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cHostComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) I2cHostComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) I2cHostComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cHostComponentName2 = {
+ I2cHostComponentNameGetDriverName,
+ I2cHostComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+I2cHostComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mI2cHostDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gI2cHostComponentName2)
+ );
+}
+
+/**
+ 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
+I2cHostComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+I2cHostDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_I2C_MASTER_PROTOCOL *I2cMaster;
+ EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
+ EFI_STATUS Status;
+
+ //
+ // Locate I2C Bus Configuration Management Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ (VOID **)&I2cBusConfigurationManagement,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the protocol because we don't use it here
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Locate I2C Master Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cMasterProtocolGuid,
+ (VOID **)&I2cMaster,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_I2C_MASTER_PROTOCOL *I2cMaster;
+ EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
+ I2C_HOST_CONTEXT *I2cHostContext;
+
+ I2cMaster = NULL;
+ I2cHostContext = NULL;
+ I2cBusConfigurationManagement = NULL;
+
+ //
+ // Locate I2C Bus Configuration Management Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ (VOID **)&I2cBusConfigurationManagement,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C bus configuration error, Status = %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Locate I2C Master Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cMasterProtocolGuid,
+ (VOID **)&I2cMaster,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C master error, Status = %r\n", Status));
+ goto Exit;
+ }
+
+ //
+ // Allocate the I2C Host Context structure
+ //
+ I2cHostContext = AllocateZeroPool (sizeof (I2C_HOST_CONTEXT));
+ if (I2cHostContext == NULL) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: there is no enough memory to allocate.\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Initialize the context structure for the current I2C Controller
+ //
+ I2cHostContext->Signature = I2C_HOST_SIGNATURE;
+ I2cHostContext->I2cMaster = I2cMaster;
+ I2cHostContext->I2cBusConfigurationManagement = I2cBusConfigurationManagement;
+ I2cHostContext->I2cBusConfiguration = (UINTN) -1;
+ InitializeListHead(&I2cHostContext->RequestList);
+
+ //
+ // Reset the controller
+ //
+ Status = I2cMaster->Reset (I2cMaster);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: I2C controller reset failed!\n"));
+ goto Exit;
+ }
+
+ //
+ // Create the I2C transaction complete event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_I2C_SYNC,
+ I2cHostRequestCompleteEvent,
+ I2cHostContext,
+ &I2cHostContext->I2cEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: create complete event error, Status = %r\n", Status));
+ goto Exit;
+ }
+
+ //
+ // Get the bus management event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_I2C_SYNC,
+ I2cHostI2cBusConfigurationAvailable,
+ I2cHostContext,
+ &I2cHostContext->I2cBusConfigurationEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: create bus available event error, Status = %r\n", Status));
+ goto Exit;
+ }
+
+ //
+ // Build the I2C host protocol for the current I2C controller
+ //
+ I2cHostContext->I2cHost.QueueRequest = I2cHostQueueRequest;
+ I2cHostContext->I2cHost.I2cControllerCapabilities = I2cMaster->I2cControllerCapabilities;
+
+ //
+ // Install the driver protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiI2cHostProtocolGuid,
+ &I2cHostContext->I2cHost,
+ NULL
+ );
+Exit:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: Start() function failed, Status = %r\n", Status));
+ if (I2cBusConfigurationManagement != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if ((I2cHostContext != NULL) && (I2cHostContext->I2cEvent != NULL)) {
+ gBS->CloseEvent (I2cHostContext->I2cEvent);
+ I2cHostContext->I2cEvent = NULL;
+ }
+
+ if ((I2cHostContext != NULL) && (I2cHostContext->I2cBusConfigurationEvent != NULL)) {
+ gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent);
+ I2cHostContext->I2cBusConfigurationEvent = NULL;
+ }
+
+ //
+ // Release the context structure upon failure
+ //
+ if (I2cHostContext != NULL) {
+ FreePool (I2cHostContext);
+ }
+ }
+
+ //
+ // Return the operation status.
+ //
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+I2cHostDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ I2C_HOST_CONTEXT *I2cHostContext;
+ EFI_I2C_HOST_PROTOCOL *I2cHost;
+ EFI_TPL TplPrevious;
+
+ TplPrevious = EfiGetCurrentTpl ();
+ if (TplPrevious > TPL_I2C_SYNC) {
+ DEBUG ((EFI_D_ERROR, "I2cHost: TPL %d is too high in Stop.\n", TplPrevious));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ (VOID **) &I2cHost,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (I2cHost);
+
+ //
+ // Raise TPL for critical section
+ //
+ TplPrevious = gBS->RaiseTPL (TPL_I2C_SYNC);
+
+ //
+ // If there is pending request or pending bus configuration, do not stop
+ //
+ Status = EFI_DEVICE_ERROR;
+ if (( !I2cHostContext->I2cBusConfigurationManagementPending )
+ && IsListEmpty (&I2cHostContext->RequestList)) {
+
+ //
+ // Remove the I2C host protocol
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiI2cHostProtocolGuid,
+ I2cHost,
+ NULL
+ );
+ }
+
+ //
+ // Leave critical section
+ //
+ gBS->RestoreTPL (TplPrevious);
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Release I2c Host resources
+ //
+ if (I2cHostContext->I2cBusConfigurationEvent != NULL) {
+ gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent);
+ I2cHostContext->I2cBusConfigurationEvent = NULL;
+ }
+
+ if (I2cHostContext->I2cEvent != NULL) {
+ gBS->CloseEvent (I2cHostContext->I2cEvent);
+ I2cHostContext->I2cEvent = NULL;
+ }
+
+ FreePool (I2cHostContext);
+ }
+
+ //
+ // Return the stop status
+ //
+ return Status;
+}
+
+/**
+ Handle the I2C bus configuration available event
+
+ This routine is called at TPL_I2C_SYNC.
+
+ @param[in] Event Address of an EFI_EVENT handle
+ @param[in] Context Address of an I2C_HOST_CONTEXT structure
+
+**/
+VOID
+EFIAPI
+I2cHostI2cBusConfigurationAvailable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ I2C_HOST_CONTEXT *I2cHostContext;
+ EFI_I2C_MASTER_PROTOCOL *I2cMaster;
+ I2C_REQUEST *I2cRequest;
+ LIST_ENTRY *EntryHeader;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ //
+ // Mark this I2C bus configuration management operation as complete
+ //
+ I2cHostContext = (I2C_HOST_CONTEXT *)Context;
+ I2cMaster = I2cHostContext->I2cMaster;
+ ASSERT (I2cMaster != NULL);
+ //
+ // Clear flag to indicate I2C bus configuration is finished
+ //
+ I2cHostContext->I2cBusConfigurationManagementPending = FALSE;
+
+ //
+ // Validate the completion status
+ //
+ if (EFI_ERROR (I2cHostContext->Status)) {
+ //
+ // Setting I2C bus configuration failed before
+ //
+ I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);
+
+ //
+ // Unknown I2C bus configuration
+ // Force next operation to enable the I2C bus configuration
+ //
+ I2cHostContext->I2cBusConfiguration = (UINTN) -1;
+
+ //
+ // Do not continue current I2C request
+ //
+ return;
+ }
+
+ //
+ // Get the first request in the link with FIFO order
+ //
+ EntryHeader = &I2cHostContext->RequestList;
+ Entry = GetFirstNode (EntryHeader);
+ I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
+
+ //
+ // Update the I2C bus configuration of the current I2C request
+ //
+ I2cHostContext->I2cBusConfiguration = I2cRequest->I2cBusConfiguration;
+
+ //
+ // Start an I2C operation on the host, the status is returned by I2cHostContext->Status
+ //
+ Status = I2cMaster->StartRequest (
+ I2cMaster,
+ I2cRequest->SlaveAddress,
+ I2cRequest->RequestPacket,
+ I2cHostContext->I2cEvent,
+ &I2cHostContext->Status
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "I2cHostI2cBusConfigurationAvailable: Error starting I2C operation, %r\n", Status));
+ }
+}
+
+/**
+ Complete the current request
+
+ This routine is called at TPL_I2C_SYNC.
+
+ @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure.
+ @param[in] Status Status of the I2C operation.
+
+ @return This routine returns the input status value.
+
+**/
+EFI_STATUS
+I2cHostRequestComplete (
+ I2C_HOST_CONTEXT *I2cHostContext,
+ EFI_STATUS Status
+ )
+{
+ I2C_REQUEST *I2cRequest;
+ LIST_ENTRY *EntryHeader;
+ LIST_ENTRY *Entry;
+
+ //
+ // Remove the current I2C request from the list
+ //
+ EntryHeader = &I2cHostContext->RequestList;
+ Entry = GetFirstNode (EntryHeader);
+ I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
+
+ //
+ // Save the status for QueueRequest
+ //
+ if ( NULL != I2cRequest->Status ) {
+ *I2cRequest->Status = Status;
+ }
+
+ //
+ // Notify the user of the I2C request completion
+ //
+ if ( NULL != I2cRequest->Event ) {
+ gBS->SignalEvent (I2cRequest->Event);
+ }
+
+ //
+ // Done with this request, remove the current request from list
+ //
+ RemoveEntryList (&I2cRequest->Link);
+ FreePool (I2cRequest->RequestPacket);
+ FreePool (I2cRequest);
+
+ //
+ // If there is more I2C request, start next one
+ //
+ if(!IsListEmpty (EntryHeader)) {
+ I2cHostRequestEnable (I2cHostContext);
+ }
+
+ return Status;
+}
+
+/**
+ Handle the bus available event
+
+ This routine is called at TPL_I2C_SYNC.
+
+ @param[in] Event Address of an EFI_EVENT handle
+ @param[in] Context Address of an I2C_HOST_CONTEXT structure
+
+**/
+VOID
+EFIAPI
+I2cHostRequestCompleteEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ I2C_HOST_CONTEXT *I2cHostContext;
+
+ //
+ // Handle the completion event
+ //
+ I2cHostContext = (I2C_HOST_CONTEXT *)Context;
+ I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);
+}
+
+/**
+ Enable access to the I2C bus configuration
+
+ @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_ABORTED The request did not complete because the driver
+ was shutdown.
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
+ This could indicate the slave device is not present.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the
+ slave address. EFI_DEVICE_ERROR may also be
+ returned if the controller can not distinguish
+ when the NACK occurred.
+ @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
+ @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
+ the event and then read status.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
+ @retval EFI_TIMEOUT The transaction did not complete within an internally
+ specified timeout period.
+
+**/
+EFI_STATUS
+I2cHostRequestEnable (
+ I2C_HOST_CONTEXT *I2cHostContext
+ )
+{
+ UINTN I2cBusConfiguration;
+ CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;
+ I2C_REQUEST *I2cRequest;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+ LIST_ENTRY *EntryHeader;
+ LIST_ENTRY *Entry;
+
+ //
+ // Assume pending request
+ //
+ Status = EFI_NOT_READY;
+
+ I2cBusConfigurationManagement = I2cHostContext->I2cBusConfigurationManagement;
+
+ //
+ // Validate the I2c bus configuration
+ //
+ EntryHeader = &I2cHostContext->RequestList;
+ Entry = GetFirstNode (EntryHeader);
+ I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);
+
+ I2cBusConfiguration = I2cRequest->I2cBusConfiguration;
+
+ if (I2cHostContext->I2cBusConfiguration != I2cBusConfiguration ) {
+ //
+ // Set flag to indicate I2C bus configuration is in progress
+ //
+ I2cHostContext->I2cBusConfigurationManagementPending = TRUE;
+ //
+ // Update bus configuration for this device's requesting bus configuration
+ //
+ Status = I2cBusConfigurationManagement->EnableI2cBusConfiguration (
+ I2cBusConfigurationManagement,
+ I2cBusConfiguration,
+ I2cHostContext->I2cBusConfigurationEvent,
+ &I2cHostContext->Status
+ );
+ } else {
+ //
+ // I2C bus configuration is same, no need change configuration and start I2c transaction directly
+ //
+ TplPrevious = gBS->RaiseTPL ( TPL_I2C_SYNC );
+
+ //
+ // Same I2C bus configuration
+ //
+ I2cHostContext->Status = EFI_SUCCESS;
+ I2cHostI2cBusConfigurationAvailable (I2cHostContext->I2cBusConfigurationEvent, I2cHostContext);
+
+ //
+ // Release the thread synchronization
+ //
+ gBS->RestoreTPL ( TplPrevious );
+ }
+ return Status;
+}
+
+/**
+ Queue an I2C operation for execution on the I2C controller.
+
+ This routine must be called at or below TPL_NOTIFY. For synchronous
+ requests this routine must be called at or below TPL_CALLBACK.
+
+ N.B. The typical consumers of this API are the I2C bus driver and
+ on rare occasions the I2C test application. Extreme care must be
+ taken by other consumers of this API to prevent confusing the
+ third party I2C drivers due to a state change at the I2C device
+ which the third party I2C drivers did not initiate. I2C platform
+ drivers may use this API within these guidelines.
+
+ This layer uses the concept of I2C bus configurations to describe
+ the I2C bus. An I2C bus configuration is defined as a unique
+ setting of the multiplexers and switches in the I2C bus which
+ enable access to one or more I2C devices. When using a switch
+ to divide a bus, due to speed differences, the I2C platform layer
+ would define an I2C bus configuration for the I2C devices on each
+ side of the switch. When using a multiplexer, the I2C platform
+ layer defines an I2C bus configuration for each of the selector
+ values required to control the multiplexer. See Figure 1 in the
+ <a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">I<sup>2</sup>C
+ Specification</a> for a complex I2C bus configuration.
+
+ The I2C host driver processes all operations in FIFO order. Prior to
+ performing the operation, the I2C host driver calls the I2C platform
+ driver to reconfigure the switches and multiplexers in the I2C bus
+ enabling access to the specified I2C device. The I2C platform driver
+ also selects the maximum bus speed for the device. After the I2C bus
+ is configured, the I2C host driver calls the I2C port driver to
+ initialize the I2C controller and start the I2C operation.
+
+ @param[in] This Address of an EFI_I2C_HOST_PROTOCOL instance.
+ @param[in] I2cBusConfiguration I2C bus configuration to access the I2C
+ device.
+ @param[in] SlaveAddress Address of the device on the I2C bus.
+ @param[in] Event Event to set for asynchronous operations,
+ NULL for synchronous operations
+ @param[in] RequestPacket Address of an EFI_I2C_REQUEST_PACKET
+ structure describing the I2C operation
+ @param[out] I2cStatus Optional buffer to receive the I2C operation
+ completion status
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.
+ @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.
+ This could indicate the slave device is not present.
+ @retval EFI_INVALID_PARAMETER RequestPacket is NULL
+ @retval EFI_INVALID_PARAMETER TPL is too high
+ @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value
+ @retval EFI_NO_RESPONSE The I2C device is not responding to the
+ slave address. EFI_DEVICE_ERROR may also be
+ returned if the controller can not distinguish
+ when the NACK occurred.
+ @retval EFI_NOT_FOUND I2C slave address exceeds maximum address
+ @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for
+ the event and then read status pointed to by
+ the request packet.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation
+ @retval EFI_TIMEOUT The transaction did not complete within an internally
+ specified timeout period.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostQueueRequest (
+ IN CONST EFI_I2C_HOST_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN UINTN SlaveAddress,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT SyncEvent;
+ EFI_TPL TplPrevious;
+ I2C_REQUEST *I2cRequest;
+ I2C_HOST_CONTEXT *I2cHostContext;
+ BOOLEAN FirstRequest;
+ UINTN RequestPacketSize;
+ UINTN StartBit;
+
+ SyncEvent = NULL;
+ FirstRequest = FALSE;
+ Status = EFI_SUCCESS;
+
+ if (RequestPacket == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SlaveAddress & I2C_ADDRESSING_10_BIT) != 0) {
+ //
+ // 10-bit address, bits 0-9 are used for 10-bit I2C slave addresses,
+ // bits 10-30 are reserved bits and must be zero
+ //
+ StartBit = 10;
+ } else {
+ //
+ // 7-bit address, Bits 0-6 are used for 7-bit I2C slave addresses,
+ // bits 7-30 are reserved bits and must be zero
+ //
+ StartBit = 7;
+ }
+
+ if (BitFieldRead32 ((UINT32)SlaveAddress, StartBit, 30) != 0) {
+ //
+ // Reserved bit set in the SlaveAddress parameter
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (This);
+
+ if (Event == NULL) {
+ //
+ // For synchronous transaction, register an event used to wait for finishing synchronous transaction
+ //
+ Status = gBS->CreateEvent (
+ 0,
+ TPL_I2C_SYNC,
+ NULL,
+ NULL,
+ &SyncEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // TPL should be at or below TPL_NOTIFY.
+ // For synchronous requests this routine must be called at or below TPL_CALLBACK.
+ //
+ TplPrevious = EfiGetCurrentTpl ();
+ if ((TplPrevious > TPL_I2C_SYNC) || ((Event == NULL) && (TplPrevious > TPL_CALLBACK))) {
+ DEBUG ((EFI_D_ERROR, "ERROR - TPL %d is too high!\n", TplPrevious));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate the request structure
+ //
+ I2cRequest = AllocateZeroPool (sizeof (I2C_REQUEST));
+ if (I2cRequest == NULL) {
+ DEBUG ((EFI_D_ERROR, "WARNING - Failed to allocate I2C_REQUEST!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the request
+ //
+ I2cRequest->Signature = I2C_REQUEST_SIGNATURE;
+ I2cRequest->I2cBusConfiguration = I2cBusConfiguration;
+ I2cRequest->SlaveAddress = SlaveAddress;
+ I2cRequest->Event = (Event == NULL) ? SyncEvent : Event;
+ I2cRequest->Status = I2cStatus;
+
+ //
+ // Copy request packet into private buffer, as RequestPacket may be freed during asynchronous transaction
+ //
+ RequestPacketSize = sizeof (UINTN) + RequestPacket->OperationCount * sizeof (EFI_I2C_OPERATION);
+ I2cRequest->RequestPacket = AllocateZeroPool (RequestPacketSize);
+ ASSERT (I2cRequest->RequestPacket != NULL);
+ CopyMem (I2cRequest->RequestPacket, RequestPacket, RequestPacketSize);
+
+ //
+ // Synchronize with the other threads
+ //
+ gBS->RaiseTPL ( TPL_I2C_SYNC );
+
+ FirstRequest = IsListEmpty (&I2cHostContext->RequestList);
+
+ //
+ // Insert new I2C request in the list
+ //
+ InsertTailList (&I2cHostContext->RequestList, &I2cRequest->Link);
+
+ //
+ // Release the thread synchronization
+ //
+ gBS->RestoreTPL (TplPrevious);
+
+ if (FirstRequest) {
+ //
+ // Start the first I2C request, then the subsequent of I2C request will continue
+ //
+ Status = I2cHostRequestEnable (I2cHostContext);
+ }
+
+ if (Event != NULL) {
+ //
+ // For asynchronous, return EFI_SUCCESS indicating that the asynchronously I2C transaction was queued.
+ // No real I2C operation status in I2cStatus
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For synchronous transaction, wait for the operation completion
+ //
+ do {
+ Status = gBS->CheckEvent (SyncEvent);
+ } while (Status == EFI_NOT_READY);
+
+ //
+ // Get the I2C operation status
+ //
+ Status = I2cHostContext->Status;
+
+ //
+ // Return the I2C operation status
+ //
+ if (I2cStatus != NULL) {
+ *I2cStatus = Status;
+ }
+
+ //
+ // Close the event if necessary
+ //
+ if (SyncEvent != NULL) {
+ gBS->CloseEvent (SyncEvent);
+ }
+
+ return Status;
+}
+
+/**
+ The user Entry Point for I2C host module. 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
+InitializeI2cHost(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gI2cHostDriverBinding,
+ ImageHandle,
+ &gI2cHostComponentName,
+ &gI2cHostComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This is the unload handle for I2C host module.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHostUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+
+ //
+ // Get the list of all I2C Controller handles in the handle database.
+ // If there is an error getting the list, then the unload
+ // operation fails.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiI2cHostProtocolGuid,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Disconnect the driver specified by ImageHandle from all
+ // the devices in the handle database.
+ //
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ ImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Uninstall all the protocols installed in the driver entry point
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gI2cHostDriverBinding.DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gI2cHostDriverBinding,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Note we have to one by one uninstall the following protocols.
+ // It's because some of them are optionally installed based on
+ // the following PCD settings.
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable
+ //
+ Status = gBS->HandleProtocol (
+ gI2cHostDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ gI2cHostDriverBinding.DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ ComponentName
+ );
+ }
+
+ Status = gBS->HandleProtocol (
+ gI2cHostDriverBinding.DriverBindingHandle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ gI2cHostDriverBinding.DriverBindingHandle,
+ &gEfiComponentName2ProtocolGuid,
+ ComponentName2
+ );
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.inf b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.inf
new file mode 100644
index 000000000..b30d79156
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.inf
@@ -0,0 +1,49 @@
+## @file
+# This driver produce I2C Host Protocol on I2C controller handle.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = I2cHostDxe
+ MODULE_UNI_FILE = I2cHostDxe.uni
+ FILE_GUID = CDEC3671-816E-43DC-A002-DCD645229338
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeI2cHost
+ UNLOAD_IMAGE = I2cHostUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ I2cDxe.h
+ I2cHost.c
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Protocols]
+ gEfiI2cHostProtocolGuid ## BY_START
+ gEfiI2cMasterProtocolGuid ## TO_START
+ gEfiI2cBusConfigurationManagementProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ I2cHostDxeExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.uni
new file mode 100644
index 000000000..0bb212566
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver produce I2C Host Protocol on I2C controller handle.
+//
+// This driver produce I2C Host Protocol on I2C controller handle.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This driver produce I2C Host Protocol on I2C controller handle."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produce I2C Host Protocol on I2C controller handle."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxeExtra.uni
new file mode 100644
index 000000000..5671bc022
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// I2cHostDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"I2C Host DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c
new file mode 100644
index 000000000..84f4c5d16
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c
@@ -0,0 +1,174 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for IsaBusDxe driver.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ComponentName.h"
+#include <Library/UefiLib.h>
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIsaBusDriverNameTable[] = {
+ { "eng;en", L"PI ISA BUS Driver" },
+ { NULL , NULL }
+};
+
+//
+// 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"
+};
+
+/**
+ 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/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h
new file mode 100644
index 000000000..c8d4601e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for IsaBusDxe driver.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ISA_BUS_COMPONENT_NAME_H_
+#define _ISA_BUS_COMPONENT_NAME_H_
+
+#include <Uefi.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.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/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.c b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.c
new file mode 100644
index 000000000..ccda7c3f7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.c
@@ -0,0 +1,455 @@
+/** @file
+ This file consumes the ISA Host Controller protocol produced by the ISA Host
+ Controller and installs the ISA Host Controller Service Binding protocol
+ on the ISA Host Controller's handle.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "IsaBusDxe.h"
+#include "ComponentName.h"
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+IsaBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VOID *Instance;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaHcProtocolGuid,
+ &Instance,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ &Instance,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+ISA_BUS_CHILD_PRIVATE_DATA mIsaBusChildPrivateTemplate = {
+ ISA_BUS_CHILD_PRIVATE_DATA_SIGNATURE,
+ FALSE
+};
+
+/**
+ Creates a child handle and installs a protocol.
+
+ The CreateChild() function installs a protocol on ChildHandle.
+ If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+ If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child
+ @retval other The child handle was not created
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ ISA_BUS_PRIVATE_DATA *Private;
+ EFI_ISA_HC_PROTOCOL *IsaHc;
+ ISA_BUS_CHILD_PRIVATE_DATA *Child;
+
+ Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (This);
+
+ Child = AllocateCopyPool (sizeof (mIsaBusChildPrivateTemplate), &mIsaBusChildPrivateTemplate);
+ if (Child == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiIsaHcProtocolGuid, Private->IsaHc,
+ &gEfiCallerIdGuid, Child,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Child);
+ return Status;
+ }
+
+ return gBS->OpenProtocol (
+ Private->IsaHcHandle,
+ &gEfiIsaHcProtocolGuid,
+ (VOID **) &IsaHc,
+ gIsaBusDriverBinding.DriverBindingHandle,
+ *ChildHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+}
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCESS The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is NULL.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
+ because its services are being used.
+ @retval other The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ ISA_BUS_PRIVATE_DATA *Private;
+ EFI_ISA_HC_PROTOCOL *IsaHc;
+ ISA_BUS_CHILD_PRIVATE_DATA *Child;
+
+ Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (This);
+
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &Child,
+ gIsaBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (Child->Signature == ISA_BUS_CHILD_PRIVATE_DATA_SIGNATURE);
+
+ if (Child->InDestroying) {
+ return EFI_SUCCESS;
+ }
+
+ Child->InDestroying = TRUE;
+ Status = gBS->CloseProtocol (
+ Private->IsaHcHandle,
+ &gEfiIsaHcProtocolGuid,
+ gIsaBusDriverBinding.DriverBindingHandle,
+ ChildHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiIsaHcProtocolGuid, Private->IsaHc,
+ &gEfiCallerIdGuid, Child,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Private->IsaHcHandle,
+ &gEfiIsaHcProtocolGuid,
+ (VOID **) &IsaHc,
+ gIsaBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Child->InDestroying = FALSE;
+ } else {
+ FreePool (Child);
+ }
+
+ return Status;
+}
+
+ISA_BUS_PRIVATE_DATA mIsaBusPrivateTemplate = {
+ ISA_BUS_PRIVATE_DATA_SIGNATURE,
+ {
+ IsaBusCreateChild,
+ IsaBusDestroyChild
+ }
+};
+
+/**
+ Starts a device controller or a bus 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ISA_BUS_PRIVATE_DATA *Private;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaHcProtocolGuid,
+ (VOID **) &mIsaBusPrivateTemplate.IsaHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ 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)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ Private = AllocateCopyPool (sizeof (mIsaBusPrivateTemplate), &mIsaBusPrivateTemplate);
+ ASSERT (Private != NULL);
+
+ Private->IsaHcHandle = Controller;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiIsaHcServiceBindingProtocolGuid, &Private->ServiceBinding,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus 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
+IsaBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
+ ISA_BUS_PRIVATE_DATA *Private;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaHcServiceBindingProtocolGuid,
+ (VOID **) &ServiceBinding,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (ServiceBinding);
+
+ if (NumberOfChildren == 0) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiIsaHcServiceBindingProtocolGuid, &Private->ServiceBinding,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (Private);
+ }
+
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = ServiceBinding->DestroyChild (ServiceBinding, ChildHandleBuffer[Index]);
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ return AllChildrenStopped ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+}
+
+//
+// ISA Bus Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gIsaBusDriverBinding = {
+ IsaBusDriverBindingSupported,
+ IsaBusDriverBindingStart,
+ IsaBusDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ Entry point of the IsaBusDxe 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
+InitializeIsaBus (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gIsaBusDriverBinding,
+ ImageHandle,
+ &gIsaBusComponentName,
+ &gIsaBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.h b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.h
new file mode 100644
index 000000000..939a08b50
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.h
@@ -0,0 +1,40 @@
+/** @file
+ Header file for the ISA BUS driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _ISA_BUS_H_
+#define _ISA_BUS_H_
+
+#include <Uefi.h>
+#include <Protocol/IsaHc.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/ServiceBinding.h>
+
+typedef struct {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_ISA_HC_PROTOCOL *IsaHc; ///< ISA HC protocol produced by the ISA Host Controller driver
+ EFI_HANDLE IsaHcHandle; ///< ISA HC handle created by the ISA Host Controller driver
+} ISA_BUS_PRIVATE_DATA;
+#define ISA_BUS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('_', 'i', 's', 'b')
+#define ISA_BUS_PRIVATE_DATA_FROM_THIS(a) CR (a, ISA_BUS_PRIVATE_DATA, ServiceBinding, ISA_BUS_PRIVATE_DATA_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ BOOLEAN InDestroying; ///< Flag to avoid DestroyChild() re-entry.
+} ISA_BUS_CHILD_PRIVATE_DATA;
+#define ISA_BUS_CHILD_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('_', 'i', 's', 'c')
+
+extern EFI_DRIVER_BINDING_PROTOCOL gIsaBusDriverBinding;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
new file mode 100644
index 000000000..9eb6504ce
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# ISA Bus driver to manage the child devices attached to the ISA Host Controller.
+#
+# This driver follows UEFI driver model and layers on ISA HC protocol defined
+# in PI spec 1.2.1. It consumes the ISA Host Controller protocol produced by
+# the ISA Host Controller and installs the ISA Host Controller Service Binding
+# protocol on the ISA Host Controller's handle.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaBusDxe
+ MODULE_UNI_FILE = IsaBusDxe.uni
+ FILE_GUID = DCBE6D66-D928-4138-8041-358F35CBCF80
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIsaBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gIsaBusDriverBinding
+# COMPONENT_NAME = gIsaBusComponentName
+# COMPONENT_NAME2 = gIsaBusComponentName2
+#
+
+[Sources]
+ IsaBusDxe.h
+ IsaBusDxe.c
+ ComponentName.h
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ DebugLib
+
+[Protocols]
+ ## CONSUMES
+ ## PRODUCES
+ gEfiIsaHcProtocolGuid
+ gEfiIsaHcServiceBindingProtocolGuid ## PRODUCES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaBusDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni
new file mode 100644
index 000000000..2202a53e5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// ISA Bus driver to manage the child devices attached to the ISA Host Controller.
+//
+// This driver follows UEFI driver model and layers on ISA HC protocol defined
+// in PI spec 1.2.1. It consumes the ISA Host Controller protocol produced by
+// the ISA Host Controller and installs the ISA Host Controller Service Binding
+// protocol on the ISA Host Controller's handle.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"ISA Bus driver to manage the child devices attached to the ISA Host Controller."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"This driver follows UEFI driver model and layers on ISA HC protocol defined in PI spec 1.2.1. It consumes the ISA Host Controller protocol produced by the ISA Host Controller and installs the ISA Host Controller Service Binding protocol on the ISA Host Controller's handle."
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni
new file mode 100644
index 000000000..1243391b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// IsaBusDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME #language en-US "IsaBusDxe module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c
new file mode 100644
index 000000000..3d2e9de67
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c
@@ -0,0 +1,346 @@
+/** @file
+ Routines related Component Name protocol.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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;
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check Controller's handle
+ //
+ Status = EfiTestManagedDevice (ControllerHandle, gKeyboardControllerDriver.DriverBindingHandle, &gEfiSioProtocolGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
new file mode 100644
index 000000000..d8d050b0a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
@@ -0,0 +1,1863 @@
+/** @file
+ Routines that access 8042 keyboard controller
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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
+ )
+
+{
+ return IoRead8 (ConsoleIn->DataRegisterAddress);
+}
+
+/**
+ 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
+ )
+{
+ IoWrite8 (ConsoleIn->DataRegisterAddress, 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
+ )
+{
+ return IoRead8 (ConsoleIn->StatusRegisterAddress);
+}
+
+/**
+ 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
+ )
+{
+ IoWrite8 (ConsoleIn->CommandRegisterAddress, 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 should 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 register 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 success 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;
+}
+
+/**
+ Initialize the key state.
+
+ @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ OUT EFI_KEY_STATE *KeyState
+ )
+{
+ KeyState->KeyShiftState = 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)
+ ;
+ KeyState->KeyToggleState = 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)
+ ;
+}
+
+/**
+ 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
+ //
+ InitializeKeyState (ConsoleIn, &KeyData.KeyState);
+ 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 ;
+ }
+ }
+
+ //
+ // Signal KeyNotify process event if this key pressed matches any key registered.
+ //
+ 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)) {
+ //
+ // The key notification function needs to run at TPL_CALLBACK
+ // while current TPL is TPL_NOTIFY. It will be invoked in
+ // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+ //
+ PushEfikeyBufTail (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);
+ gBS->SignalEvent (ConsoleIn->KeyNotifyProcessEvent);
+ break;
+ }
+ }
+
+ 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;
+ ConsoleIn->EfiKeyQueueForNotify.Head = 0;
+ ConsoleIn->EfiKeyQueueForNotify.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 resetting 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 resetting 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 acquired 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 acquired 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 acquired 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 acquired 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 acquired 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;
+ }
+
+}
+
+
+/**
+ 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
new file mode 100644
index 000000000..835f33cfa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
@@ -0,0 +1,733 @@
+/** @file
+ Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
+ provided by Ps2KbdCtrller.c.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#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 registered 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 FALSE 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 existence 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 available.
+ @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);
+ if (Status == EFI_NOT_READY) {
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ InitializeKeyState (ConsoleInDev, &KeyData->KeyState);
+ }
+ }
+
+ 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 waiting 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 support 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 optionally 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 existence 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 available.
+ @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. If KeyData.Key,
+ KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState are 0,
+ then any incomplete keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 necessary 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;
+}
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_TPL OldTpl;
+
+ ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
+
+ //
+ // Invoke notification functions.
+ //
+ NotifyList = &ConsoleIn->NotifyList;
+ while (TRUE) {
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);
+ //
+ // Leave critical section
+ //
+ gBS->RestoreTPL (OldTpl);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (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);
+ }
+ }
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c
new file mode 100644
index 000000000..855fda742
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c
@@ -0,0 +1,661 @@
+/** @file
+
+ PS/2 Keyboard driver. Routines that interacts with callers,
+ conforming to EFI driver model
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 stopping 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 Success 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_SIO_PROTOCOL *Sio;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ACPI_HID_DEVICE_PATH *Acpi;
+
+ //
+ // Check whether the controller is keyboard.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ do {
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } while (!IsDevicePathEnd (DevicePath));
+
+ if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
+ (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Acpi->HID != EISA_PNP_ID (0x303) || Acpi->UID != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ 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_SIO_PROTOCOL *Sio;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ UINT8 Data;
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ StatusCode = 0;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ 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,
+ DevicePath
+ );
+
+ //
+ // Get the ISA I/O Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // 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->DevicePath = DevicePath;
+
+ 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;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ KeyNotifyProcessHandler,
+ ConsoleIn,
+ &ConsoleIn->KeyNotifyProcessEvent
+ );
+ 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,
+ DevicePath
+ );
+
+ //
+ // 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,
+ DevicePath
+ );
+
+ 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,
+ DevicePath
+ );
+ }
+
+ 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);
+ }
+ if ((ConsoleIn != NULL) && (ConsoleIn->KeyNotifyProcessEvent != NULL)) {
+ gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
+ }
+ 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,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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,
+ &gEfiSioProtocolGuid,
+ 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;
+ }
+ if (ConsoleIn->KeyNotifyProcessEvent != NULL) {
+ gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
+ ConsoleIn->KeyNotifyProcessEvent = 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 Success 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h
new file mode 100644
index 000000000..c2762db03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h
@@ -0,0 +1,563 @@
+/** @file
+ PS/2 keyboard driver header file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PS2KEYBOARD_H_
+#define _PS2KEYBOARD_H_
+
+#include <Uefi.h>
+
+#include <Protocol/SuperIo.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Ps2Policy.h>
+
+#include <Library/IoLib.h>
+#include <Library/DevicePathLib.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_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;
+ EFI_KEY_QUEUE EfiKeyQueueForNotify;
+
+ //
+ // Error state
+ //
+ BOOLEAN KeyboardErr;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ //
+ // Notification Function List
+ //
+ LIST_ENTRY NotifyList;
+ EFI_EVENT KeyNotifyProcessEvent;
+} 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
+ );
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ 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
+ );
+
+
+/**
+ 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 waiting 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 optionally 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 existence 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 available.
+ @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. If KeyData.Key,
+ KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState are 0,
+ then any incomplete keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction - Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 necessary 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 registered 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 FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Initialize the key state.
+
+ @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ OUT EFI_KEY_STATE *KeyState
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
new file mode 100644
index 000000000..d551c53fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
@@ -0,0 +1,78 @@
+## @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 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ps2KeyboardDxe
+ MODULE_UNI_FILE = Ps2KeyboardDxe.uni
+ FILE_GUID = C4D1F932-821F-4744-BF06-6D30F7730F8D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePs2Keyboard
+
+#
+# VALID_ARCHITECTURES = IA32 X64 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
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiRuntimeServicesTableLib
+ DebugLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ TimerLib
+ PcdLib
+ IoLib
+
+[Protocols]
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ gEfiPs2PolicyProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSioProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPs2KbdExtendedVerification ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni
new file mode 100644
index 000000000..f1d383efe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni
@@ -0,0 +1,17 @@
+// /** @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 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Ps2 Keyboard Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Ps2 Keyboard Driver for UEFI. The keyboard type implemented follows IBM compatible PS2 protocol using Scan Code Set 1."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni
new file mode 100644
index 000000000..6c1ccb44a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Ps2KeyboardDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"PS2 Keyboard DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c
new file mode 100644
index 000000000..d8fed87c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c
@@ -0,0 +1,852 @@
+/** @file
+ PS2 Mouse Communication Interface.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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.
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Keyboard controller self test
+ //
+ Status = Out8042Command (SELF_TEST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Read return code
+ //
+ Status = In8042Data (&Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Data != 0x55) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set system flag
+ //
+ Status = Out8042Command (READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (&Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042Command (WRITE_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data |= CMD_SYS_FLAG;
+ Status = Out8042Data (Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ VOID
+ )
+{
+ //
+ // Send 8042 enable mouse command
+ //
+ return Out8042Command (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 (
+ VOID
+ )
+{
+ //
+ // Send 8042 disable mouse command
+ //
+ return Out8042Command (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 (
+ VOID
+ )
+{
+ //
+ // Send 8042 enable keyboard command
+ //
+ return Out8042Command (ENABLE_KB);
+}
+
+/**
+ Issue command to disable keyboard.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ VOID
+ )
+{
+ //
+ // Send 8042 disable keyboard command
+ //
+ return Out8042Command (DISABLE_KB);
+}
+
+/**
+ Issue command to check keyboard status.
+
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ OUT BOOLEAN *KeyboardEnable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Send command to read KBC command byte
+ //
+ Status = Out8042Command (READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (&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.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Status = Out8042AuxCommand (RESET_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042AuxData (&Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check BAT Complete Code
+ //
+ if (Data != PS2MOUSE_BAT1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = In8042AuxData (&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 SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN MOUSE_SR SampleRate
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse sample rate
+ //
+ Status = Out8042AuxCommand (SETSR_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (SampleRateTbl[SampleRate]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN MOUSE_RE Resolution
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse resolution
+ //
+ Status = Out8042AuxCommand (SETRE_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (ResolutionTbl[Resolution]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN MOUSE_SF Scaling
+ )
+{
+ //
+ // Send auxiliary command to set mouse scaling data
+ //
+ return Out8042AuxCommand (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD, FALSE);
+}
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ VOID
+ )
+{
+ //
+ // Send auxiliary command to enable mouse
+ //
+ return Out8042AuxCommand (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;
+ 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 ();
+ Count = 1;
+ Status = PS2MouseRead (&Data, &Count, State);
+ if (EFI_ERROR (Status)) {
+ KbcEnableAux ();
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 1) {
+ KbcEnableAux ();
+ return EFI_NOT_READY;
+ }
+
+ if (IS_PS2_SYNC_BYTE (Data)) {
+ Packet[0] = Data;
+ State = PS2_READ_DATA_BYTE;
+
+ CheckKbStatus (&KeyboardEnable);
+ KbcDisableKb ();
+ KbcEnableAux ();
+ }
+ break;
+
+ case PS2_READ_DATA_BYTE:
+ Count = 2;
+ Status = PS2MouseRead ((Packet + 1), &Count, State);
+ if (EFI_ERROR (Status)) {
+ if (KeyboardEnable) {
+ KbcEnableKb ();
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 2) {
+ if (KeyboardEnable) {
+ KbcEnableKb ();
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ State = PS2_PROCESS_PACKET;
+ break;
+
+ case PS2_PROCESS_PACKET:
+ if (KeyboardEnable) {
+ KbcEnableKb ();
+ }
+ //
+ // 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 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 (
+ OUT UINT8 *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ )
+{
+ EFI_STATUS Status;
+ UINTN BytesRead;
+
+ Status = EFI_SUCCESS;
+
+ if (State == PS2_READ_BYTE_ONE) {
+ //
+ // Check input for mouse
+ //
+ Status = CheckForInput ();
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ for (BytesRead = 0; BytesRead < *BufSize; BytesRead++) {
+
+ Status = WaitOutputFull (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ Buffer[BytesRead] = IoRead8 (KBC_DATA_PORT);
+ }
+ //
+ // 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 Command I/O command.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN UINT8 Command
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send command
+ //
+ IoWrite8 (KBC_CMD_STS_PORT, Command);
+
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IoWrite8 (KBC_DATA_PORT, Data);
+ return WaitInputEmpty (TIMEOUT);
+}
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN OUT UINT8 *Data
+ )
+{
+ UINTN Delay;
+
+ Delay = TIMEOUT / 50;
+
+ do {
+ //
+ // Check keyboard controller status bit 0(output buffer status)
+ //
+ if ((IoRead8 (KBC_CMD_STS_PORT) & KBC_OUTB) == KBC_OUTB) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ *Data = IoRead8 (KBC_DATA_PORT);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ IoWrite8 (KBC_CMD_STS_PORT, WRITE_AUX_DEV);
+
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send auxiliary device command
+ //
+ IoWrite8 (KBC_DATA_PORT, Command);
+
+ //
+ // Read return code
+ //
+ Status = In8042AuxData (&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 (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 Data Buffer holding return value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow.
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ IoWrite8 (KBC_CMD_STS_PORT, WRITE_AUX_DEV);
+
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IoWrite8 (KBC_DATA_PORT, Data);
+
+ Status = WaitInputEmpty (TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN OUT UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // wait for output data
+ //
+ Status = WaitOutputFull (BAT_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Data = IoRead8 (KBC_DATA_PORT);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ VOID
+ )
+{
+ UINT8 Data;
+
+ Data = IoRead8 (KBC_CMD_STS_PORT);
+
+ //
+ // 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 Timeout Waiting time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ Data = IoRead8 (KBC_CMD_STS_PORT);
+
+ //
+ // 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 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 UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ Data = IoRead8 (KBC_CMD_STS_PORT);
+
+ //
+ // 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h
new file mode 100644
index 000000000..60da42121
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h
@@ -0,0 +1,389 @@
+/** @file
+ PS2 Mouse Communication Interface
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _COMMPS2_H_
+#define _COMMPS2_H_
+
+#include "Ps2Mouse.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.
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ VOID
+ );
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ VOID
+ );
+
+/**
+ Issue command to disable keyboard AUX functionality.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableAux (
+ VOID
+ );
+
+/**
+ Issue command to enable keyboard.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableKb (
+ VOID
+ );
+
+/**
+ Issue command to disable keyboard.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ VOID
+ );
+
+/**
+ Issue command to check keyboard status.
+
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ OUT BOOLEAN *KeyboardEnable
+ );
+
+/**
+ Issue command to reset keyboard.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ VOID
+ );
+
+/**
+ Issue command to set mouse's sample rate
+
+ @param SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN MOUSE_SR SampleRate
+ );
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN MOUSE_RE Resolution
+ );
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN MOUSE_SF Scaling
+ );
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ VOID
+ );
+
+/**
+ 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 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 (
+ OUT UINT8 *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ );
+
+//
+// 8042 I/O function
+//
+/**
+ I/O work flow of outing 8042 command.
+
+ @param Command I/O command.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN UINT8 Command
+ );
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN UINT8 Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ );
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux data.
+
+ @param Data Buffer holding return value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN UINT8 Data
+ );
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ VOID
+ );
+
+/**
+ I/O work flow to wait input buffer empty in given time.
+
+ @param Timeout Waiting time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN UINTN Timeout
+ );
+
+/**
+ I/O work flow to wait output buffer full in given time.
+
+ @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 UINTN Timeout
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c
new file mode 100644
index 000000000..3dd8efb1d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c
@@ -0,0 +1,217 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Ps2MouseDxe driver.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check Controller's handle
+ //
+ Status = EfiTestManagedDevice (ControllerHandle, gPS2MouseDriver.DriverBindingHandle, &gEfiSioProtocolGuid);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c
new file mode 100644
index 000000000..ebcb2a43d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c
@@ -0,0 +1,799 @@
+/** @file
+ PS/2 Mouse driver. Routines that interacts with callers,
+ conforming to EFI driver model.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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_SIO_PROTOCOL *Sio;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ACPI_HID_DEVICE_PATH *Acpi;
+
+ //
+ // Check whether the controller is keyboard.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ do {
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } while (!IsDevicePathEnd (DevicePath));
+
+ if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
+ (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (Acpi->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 (Acpi->UID == 1) {
+ break;
+ }
+
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Sio protocol, creating
+ PS2_MOUSE_DEV device and install gEfiSimplePointerProtocolGuid 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_SIO_PROTOCOL *Sio;
+ PS2_MOUSE_DEV *MouseDev;
+ UINT8 Data;
+ EFI_TPL OldTpl;
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ StatusCode = 0;
+
+ //
+ // Open the device path protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ 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,
+ DevicePath
+ );
+
+ //
+ // Get the ISA I/O Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // 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->DevicePath = DevicePath;
+
+ //
+ // 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
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_MOUSE_PC_SELF_TEST,
+ DevicePath
+ );
+
+ Data = IoRead8 (KBC_CMD_STS_PORT);
+ //
+ // 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;
+ }
+
+ if ((Data & KBC_SYSF) != KBC_SYSF) {
+ Status = KbcSelfTest ();
+ if (EFI_ERROR (Status)) {
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ }
+
+ KbcEnableAux ();
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT,
+ DevicePath
+ );
+
+ //
+ // 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,
+ DevicePath
+ );
+
+ //
+ // 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 ();
+ }
+
+ if (StatusCode != 0) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode,
+ DevicePath
+ );
+ }
+
+ 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 (&Data);
+ }
+ }
+
+ if (MouseDev != NULL) {
+ FreePool (MouseDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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 (&Data);
+ }
+
+ gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
+ FreeUnicodeStringTable (MouseDev->ControllerNameTable);
+ FreePool (MouseDev);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and
+ there is a mouse device connected 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 resetting 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 (&Data);
+ }
+
+ CheckKbStatus (&KeyboardEnable);
+
+ KbcDisableKb ();
+
+ //
+ // if there's data block on KBC data port, read it out
+ //
+ if ((IoRead8 (KBC_CMD_STS_PORT) & KBC_OUTB) == KBC_OUTB) {
+ IoRead8 (KBC_DATA_PORT);
+ }
+
+ Status = EFI_SUCCESS;
+ //
+ // The PS2 mouse driver reset behavior is always successfully return no matter whether or not there is mouse connected to system.
+ // This behavior is needed by performance speed. The following mouse command only successfully 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 ();
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetSampleRate (MouseDev->SampleRate);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetResolution (MouseDev->Resolution);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetScaling (MouseDev->Scaling);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseEnable ();
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ if (KeyboardEnable) {
+ KbcEnableKb ();
+ }
+
+ 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 ();
+ 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h
new file mode 100644
index 000000000..1f7c310ad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h
@@ -0,0 +1,393 @@
+/** @file
+ PS/2 Mouse driver header file.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PS2MOUSE_H_
+#define _PS2MOUSE_H_
+
+#include <Uefi.h>
+
+#include <Protocol/SimplePointer.h>
+#include <Protocol/SuperIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DevicePathLib.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>
+#include <Library/IoLib.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_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
+ 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
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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 is TRUE and
+ there is a mouse device connected 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 resetting 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 Data Data value
+
+ @retval EFI_SUCCESS Success to execute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ 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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
new file mode 100644
index 000000000..7e801ecd1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# PS2 Mouse Driver.
+#
+# This driver provides support for PS2 based mice.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ps2MouseDxe
+ MODULE_UNI_FILE = Ps2MouseDxe.uni
+ FILE_GUID = 08464531-4C99-4C4C-A887-8D8BA4BBB063
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePs2Mouse
+
+#
+# VALID_ARCHITECTURES = IA32 X64 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
+
+[LibraryClasses]
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ IoLib
+ DevicePathLib
+
+[Protocols]
+ gEfiSioProtocolGuid ## TO_START
+ gEfiSimplePointerProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.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/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni
new file mode 100644
index 000000000..e41869a01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// PS2 Mouse Driver.
+//
+// This driver provides support for PS2 based mice.
+//
+// Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PS2 Mouse Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides support for PS2-based mice."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni
new file mode 100644
index 000000000..1f109457b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Ps2MouseDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"PS2 Mouse DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c
new file mode 100644
index 000000000..a2132d072
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for EHCI driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ehci.h"
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gEhciComponentName = {
+ EhciComponentNameGetDriverName,
+ EhciComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEhciComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EhciComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EhciComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEhciDriverNameTable[] = {
+ { "eng;en", L"Usb Ehci 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
+EhciComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mEhciDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gEhciComponentName)
+ );
+}
+
+/**
+ 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
+EhciComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB2_HC_DEV *EhciDev;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gEhciDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ gEhciDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EhciDev = EHC_FROM_THIS (Usb2Hc);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ EhciDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gEhciComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.h
new file mode 100644
index 000000000..739592a6f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.h
@@ -0,0 +1,141 @@
+/** @file
+
+ This file contains the delarations for componet name routines.
+
+Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_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
+EhciComponentNameGetDriverName (
+ 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
+EhciComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
new file mode 100644
index 000000000..bdd9c27db
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
@@ -0,0 +1,2086 @@
+/** @file
+ The Ehci controller driver.
+
+ EhciDxe driver is responsible for managing the behavior of EHCI controller.
+ It implements the interfaces of monitoring the status of all ports and transferring
+ Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.
+
+ Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
+ to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or
+ OHCI controller. This way avoids the control transfer on a shared port between EHCI
+ and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a
+ USB 2.0 device inserts.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ehci.h"
+
+//
+// Two arrays used to translate the EHCI port state (change)
+// to the UEFI protocol's port state (change).
+//
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {
+ {PORTSC_CONN, USB_PORT_STAT_CONNECTION},
+ {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},
+ {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},
+ {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},
+ {PORTSC_RESET, USB_PORT_STAT_RESET},
+ {PORTSC_POWER, USB_PORT_STAT_POWER},
+ {PORTSC_OWNER, USB_PORT_STAT_OWNER}
+};
+
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
+ {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},
+ {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},
+ {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
+};
+
+EFI_DRIVER_BINDING_PROTOCOL
+gEhciDriverBinding = {
+ EhcDriverBindingSupported,
+ EhcDriverBindingStart,
+ EhcDriverBindingStop,
+ 0x30,
+ NULL,
+ NULL
+};
+
+/**
+ Retrieves the capability of root hub ports.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param MaxSpeed Max speed supported by the controller.
+ @param PortNumber Number of the root hub ports.
+ @param Is64BitCapable Whether the controller supports 64-bit memory
+ addressing.
+
+ @retval EFI_SUCCESS Host controller capability were retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcGetCapability (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *PortNumber,
+ OUT UINT8 *Is64BitCapable
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+
+ if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ *MaxSpeed = EFI_USB_SPEED_HIGH;
+ *PortNumber = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);
+ *Is64BitCapable = (UINT8) Ehc->Support64BitDma;
+
+ DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcReset (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ Ehc = EHC_FROM_THIS (This);
+
+ if (Ehc->DevicePath != NULL) {
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
+ Ehc->DevicePath
+ );
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+
+ switch (Attributes) {
+ case EFI_USB_HC_RESET_GLOBAL:
+ //
+ // Flow through, same behavior as Host Controller Reset
+ //
+ case EFI_USB_HC_RESET_HOST_CONTROLLER:
+ //
+ // Host Controller must be Halt when Reset it
+ //
+ if (EhcIsDebugPortInUse (Ehc, NULL)) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (!EhcIsHalt (Ehc)) {
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Clean up the asynchronous transfers, currently only
+ // interrupt supports asynchronous operation.
+ //
+ EhciDelAllAsyncIntTransfers (Ehc);
+ EhcAckAllInterrupt (Ehc);
+ EhcFreeSched (Ehc);
+
+ Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EhcInitHC (Ehc);
+ break;
+
+ case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
+ case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "EhcReset: exit status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Retrieve the current state of the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State Variable to return the current host controller
+ state.
+
+ @retval EFI_SUCCESS Host controller state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to
+ retrieve the host controller's current state.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcGetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ )
+{
+ EFI_TPL OldTpl;
+ USB2_HC_DEV *Ehc;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
+ *State = EfiUsbHcStateHalt;
+ } else {
+ *State = EfiUsbHcStateOperational;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ DEBUG ((EFI_D_INFO, "EhcGetState: current state %d\n", *State));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets the USB host controller to a specific state.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State The state of the host controller that will be set.
+
+ @retval EFI_SUCCESS The USB host controller was successfully placed
+ in the state specified by State.
+ @retval EFI_INVALID_PARAMETER State is invalid.
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcSetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_USB_HC_STATE CurState;
+
+ Status = EhcGetState (This, &CurState);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (CurState == State) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ switch (State) {
+ case EfiUsbHcStateHalt:
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbHcStateOperational:
+ if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ //
+ // Software must not write a one to this field unless the host controller
+ // is in the Halted state. Doing so will yield undefined results.
+ // refers to Spec[EHCI1.0-2.3.1]
+ //
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbHcStateSuspend:
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "EhcSetState: exit status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber The root hub port to retrieve the state from.
+ This value is zero-based.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcGetRootHubPortStatus (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ UINTN Index;
+ UINTN MapSize;
+ EFI_STATUS Status;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+
+ Ehc = EHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ if (EhcIsDebugPortInUse (Ehc, &PortNumber)) {
+ goto ON_EXIT;
+ }
+
+ State = EhcReadOpReg (Ehc, Offset);
+
+ //
+ // Identify device speed. If in K state, it is low speed.
+ // If the port is enabled after reset, the device is of
+ // high speed. The USB bus driver should retrieve the actual
+ // port speed after reset.
+ //
+ if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+
+ } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ }
+
+ //
+ // Convert the EHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcSetRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
+ State = EhcReadOpReg (Ehc, Offset);
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bit
+ //
+ State &= ~PORTSC_CHANGE_MASK;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Sofeware can't set this bit, Port can only be enable by
+ // EHCI as a part of the reset and enable
+ //
+ State |= PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= PORTSC_SUSPEND;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // Make sure Host Controller not halt before reset it
+ //
+ if (EhcIsHalt (Ehc)) {
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
+ break;
+ }
+ }
+
+ //
+ // Set one to PortReset bit must also set zero to PortEnable bit
+ //
+ State |= PORTSC_RESET;
+ State &= ~PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // Set port power bit when PPC is 1
+ //
+ if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
+ State |= PORTSC_POWER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ }
+ break;
+
+ case EfiUsbPortOwner:
+ State |= PORTSC_OWNER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcClearRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
+ State = EhcReadOpReg (Ehc, Offset);
+ State &= ~PORTSC_CHANGE_MASK;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Clear PORT_ENABLE feature means disable port.
+ //
+ State &= ~PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ //
+ // A write of zero to this bit is ignored by the host
+ // controller. The host controller will unconditionally
+ // set this bit to a zero when:
+ // 1. software sets the Forct Port Resume bit to a zero from a one.
+ // 2. software sets the Port Reset bit to a one frome a zero.
+ //
+ State &= ~PORSTSC_RESUME;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // Clear PORT_RESET means clear the reset signal.
+ //
+ State &= ~PORTSC_RESET;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // Clear port owner means this port owned by EHC
+ //
+ State &= ~PORTSC_OWNER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortConnectChange:
+ //
+ // Clear connect status change
+ //
+ State |= PORTSC_CONN_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortEnableChange:
+ //
+ // Clear enable status change
+ //
+ State |= PORTSC_ENABLE_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ //
+ // Clear PortOverCurrent change
+ //
+ State |= PORTSC_OVERCUR_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // Clear port power bit when PPC is 1
+ //
+ if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
+ State &= ~PORTSC_POWER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ }
+ break;
+ case EfiUsbPortSuspendChange:
+ case EfiUsbPortResetChange:
+ //
+ // Not supported or not related operation
+ //
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage
+ @param Data Data buffer to be transmitted or received from USB
+ device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcControlTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB2_HC_DEV *Ehc;
+ URB *Urb;
+ EFI_TPL OldTpl;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+
+ //
+ // Validate parameters
+ //
+ if ((Request == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbDataIn) &&
+ (TransferDirection != EfiUsbDataOut) &&
+ (TransferDirection != EfiUsbNoData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection == EfiUsbNoData) &&
+ ((Data != NULL) || (*DataLength != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) &&
+ ((Data == NULL) || (*DataLength == 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ Status = EFI_DEVICE_ERROR;
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n"));
+
+ EhcAckAllInterrupt (Ehc);
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ //
+ // Encode the direction in address, although default control
+ // endpoint is bidirectional. EhcCreateUrb expects this
+ // combination of Ep addr and its direction.
+ //
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
+ Urb = EhcCreateUrb (
+ Ehc,
+ DeviceAddress,
+ Endpoint,
+ DeviceSpeed,
+ 0,
+ MaximumPacketLength,
+ Translator,
+ EHC_CTRL_TRANSFER,
+ Request,
+ Data,
+ *DataLength,
+ NULL,
+ NULL,
+ 1
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EhcLinkQhToAsync (Ehc, Urb->Qh);
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
+
+ //
+ // Get the status from URB. The result is updated in EhcCheckUrbResult
+ // which is called by EhcExecTransfer
+ //
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+ EhcFreeUrb (Ehc, Urb);
+
+ON_EXIT:
+ Ehc->PciIo->Flush (Ehc->PciIo);
+ gBS->RestoreTPL (OldTpl);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ return Status;
+}
+
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param DeviceSpeed Device speed, Low speed device doesn't support bulk
+ transfer.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to
+ use of the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcBulkTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB2_HC_DEV *Ehc;
+ URB *Urb;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n"));
+
+ EhcAckAllInterrupt (Ehc);
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = EhcCreateUrb (
+ Ehc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ *DataToggle,
+ MaximumPacketLength,
+ Translator,
+ EHC_BULK_TRANSFER,
+ NULL,
+ Data[0],
+ *DataLength,
+ NULL,
+ NULL,
+ 1
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EhcLinkQhToAsync (Ehc, Urb->Qh);
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+ *DataToggle = Urb->DataToggle;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+ EhcFreeUrb (Ehc, Urb);
+
+ON_EXIT:
+ Ehc->PciIo->Flush (Ehc->PciIo);
+ gBS->RestoreTPL (OldTpl);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ return Status;
+}
+
+
+/**
+ Submits an asynchronous interrupt transfer to an
+ interrupt endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
+ transfer If FALSE, to remove the specified
+ asynchronous interrupt.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param PollingInterval The he interval, in milliseconds, that the transfer
+ is polled.
+ @param DataLength The length of data to receive at the rate specified
+ by PollingInterval.
+ @param Translator Transaction translator to use.
+ @param CallBackFunction Function to call at the rate specified by
+ PollingInterval.
+ @param Context Context to CallBackFunction.
+
+ @retval EFI_SUCCESS The request has been successfully submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcAsyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context OPTIONAL
+ )
+{
+ USB2_HC_DEV *Ehc;
+ URB *Urb;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Validate parameters
+ //
+ if (!EHCI_IS_DATAIN (EndPointAddress)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsNewTransfer) {
+ if (DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((PollingInterval > 255) || (PollingInterval < 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ //
+ // Delete Async interrupt transfer request. DataToggle will return
+ // the next data toggle to use.
+ //
+ if (!IsNewTransfer) {
+ Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);
+
+ DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));
+ goto ON_EXIT;
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));
+ EhcAckAllInterrupt (Ehc);
+
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ Urb = EhciInsertAsyncIntTransfer (
+ Ehc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ *DataToggle,
+ MaximumPacketLength,
+ Translator,
+ DataLength,
+ CallBackFunction,
+ Context,
+ PollingInterval
+ );
+
+ if (Urb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+ Ehc->PciIo->Flush (Ehc->PciIo);
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ of sending or receiving.
+ @param Data Buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param DataLength On input, the size, in bytes, of the data buffer; On
+ output, the number of bytes transferred.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param TimeOut Maximum time, in second, to complete.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_SUCCESS The transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT The transfer failed due to timeout.
+ @return EFI_DEVICE_ERROR The failed due to host controller or device error
+
+**/
+EFI_STATUS
+EFIAPI
+EhcSyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ URB *Urb;
+ EFI_STATUS Status;
+
+ //
+ // Validates parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = EHC_FROM_THIS (This);
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
+
+ EhcAckAllInterrupt (Ehc);
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ Urb = EhcCreateUrb (
+ Ehc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ *DataToggle,
+ MaximumPacketLength,
+ Translator,
+ EHC_INT_TRANSFER_SYNC,
+ NULL,
+ Data,
+ *DataLength,
+ NULL,
+ NULL,
+ 1
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EhcLinkQhToPeriod (Ehc, Urb->Qh);
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+ *DataToggle = Urb->DataToggle;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ EhcFreeUrb (Ehc, Urb);
+ON_EXIT:
+ Ehc->PciIo->Flush (Ehc->PciIo);
+ gBS->RestoreTPL (OldTpl);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ return Status;
+}
+
+
+/**
+ Submits isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Submits Async isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param IsochronousCallBack Function to be called when the transfer complete.
+ @param Context Context passed to the call back function as
+ parameter.
+
+ @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcAsyncIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @return EFI_SUCCESS Success.
+ EFI_DEVICE_ERROR Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gEhciDriverBinding,
+ ImageHandle,
+ &gEhciComponentName,
+ &gEhciComponentName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has Usb2HcProtocol installed will
+ be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_CLASSC UsbClassCReg;
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Test whether the controller belongs to Ehci type
+ //
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)
+ || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI))) {
+
+ Status = EFI_UNSUPPORTED;
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Get the usb debug port related information.
+
+ @param Ehc The EHCI device.
+
+ @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
+ @retval Others The usb host controller does not supported usb debug port capability.
+
+**/
+EFI_STATUS
+EhcGetUsbDebugPortInfo (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 PciStatus;
+ UINT8 CapabilityPtr;
+ UINT8 CapabilityId;
+ UINT16 DebugPort;
+ EFI_STATUS Status;
+
+ ASSERT (Ehc->PciIo != NULL);
+ PciIo = Ehc->PciIo;
+
+ //
+ // Detect if the EHCI host controller support Capaility Pointer.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_PRIMARY_STATUS_OFFSET,
+ sizeof (UINT16),
+ &PciStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {
+ //
+ // The Pci Device Doesn't Support Capability Pointer.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Pointer To Capability List
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CAPBILITY_POINTER_OFFSET,
+ 1,
+ &CapabilityPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Capability ID 0xA, Which Is For Debug Port
+ //
+ while (CapabilityPtr != 0) {
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ CapabilityPtr,
+ 1,
+ &CapabilityId
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CapabilityId == EHC_DEBUG_PORT_CAP_ID) {
+ break;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ CapabilityPtr + 1,
+ 1,
+ &CapabilityPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // No Debug Port Capability Found
+ //
+ if (CapabilityPtr == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get The Base Address Of Debug Port Register In Debug Port Capability Register
+ //
+ Status = PciIo->Pci.Read (
+ Ehc->PciIo,
+ EfiPciIoWidthUint8,
+ CapabilityPtr + 2,
+ sizeof (UINT16),
+ &DebugPort
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ehc->DebugPortOffset = DebugPort & 0x1FFF;
+ Ehc->DebugPortBarNum = (UINT8)((DebugPort >> 13) - 1);
+ Ehc->DebugPortNum = (UINT8)((Ehc->HcStructParams & 0x00F00000) >> 20);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Create and initialize a USB2_HC_DEV.
+
+ @param PciIo The PciIo on this device.
+ @param DevicePath The device path of host controller.
+ @param OriginalPciAttributes Original PCI attributes.
+
+ @return The allocated and initialized USB2_HC_DEV structure if created,
+ otherwise NULL.
+
+**/
+USB2_HC_DEV *
+EhcCreateUsb2Hc (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT64 OriginalPciAttributes
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_STATUS Status;
+
+ Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
+
+ if (Ehc == NULL) {
+ return NULL;
+ }
+
+ //
+ // Init EFI_USB2_HC_PROTOCOL interface and private data structure
+ //
+ Ehc->Signature = USB2_HC_DEV_SIGNATURE;
+
+ Ehc->Usb2Hc.GetCapability = EhcGetCapability;
+ Ehc->Usb2Hc.Reset = EhcReset;
+ Ehc->Usb2Hc.GetState = EhcGetState;
+ Ehc->Usb2Hc.SetState = EhcSetState;
+ Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;
+ Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;
+ Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;
+ Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;
+ Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;
+ Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;
+ Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;
+ Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;
+ Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
+ Ehc->Usb2Hc.MajorRevision = 0x2;
+ Ehc->Usb2Hc.MinorRevision = 0x0;
+
+ Ehc->PciIo = PciIo;
+ Ehc->DevicePath = DevicePath;
+ Ehc->OriginalPciAttributes = OriginalPciAttributes;
+
+ InitializeListHead (&Ehc->AsyncIntTransfers);
+
+ Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
+ Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
+ Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
+
+ DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));
+
+ //
+ // EHCI Controllers with a CapLen of 0 are ignored.
+ //
+ if (Ehc->CapLen == 0) {
+ gBS->FreePool (Ehc);
+ return NULL;
+ }
+
+ EhcGetUsbDebugPortInfo (Ehc);
+
+ //
+ // Create AsyncRequest Polling Timer
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EhcMonitorAsyncRequests,
+ Ehc,
+ &Ehc->PollTimer
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Ehc);
+ return NULL;
+ }
+
+ return Ehc;
+}
+
+/**
+ One notified function to stop the Host Controller when gBS->ExitBootServices() called.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+EhcExitBootService (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+
+{
+ USB2_HC_DEV *Ehc;
+
+ Ehc = (USB2_HC_DEV *) Context;
+
+ //
+ // Reset the Host Controller
+ //
+ EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
+}
+
+
+/**
+ Starting the Usb EHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS supports this device.
+ @return EFI_UNSUPPORTED do not support this device.
+ @return EFI_DEVICE_ERROR cannot be started due to device Error.
+ @return EFI_OUT_OF_RESOURCES cannot allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ USB2_HC_DEV *Ehc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_PCI_IO_PROTOCOL *Instance;
+ UINT64 Supports;
+ UINT64 OriginalPciAttributes;
+ BOOLEAN PciAttributesSaved;
+ USB_CLASSC UsbClassCReg;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ UINTN CompanionSegmentNumber;
+ UINTN CompanionBusNumber;
+ UINTN CompanionDeviceNumber;
+ UINTN CompanionFunctionNumber;
+ UINTN EhciSegmentNumber;
+ UINTN EhciBusNumber;
+ UINTN EhciDeviceNumber;
+ UINTN EhciFunctionNumber;
+ EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
+
+ //
+ // Open the PciIo Protocol, then enable the USB host controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open Device Path Protocol for on USB host controller
+ //
+ HcDevicePath = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &HcDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ PciAttributesSaved = FALSE;
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ PciAttributesSaved = TRUE;
+
+ 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)) {
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));
+ goto CLOSE_PCIIO;
+ }
+
+ //
+ // Get the Pci device class code.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto CLOSE_PCIIO;
+ }
+ //
+ // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
+ // companion usb ehci host controller and force EHCI driver get attached to it before
+ // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
+ //
+ if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI || UsbClassCReg.ProgInterface == PCI_IF_OHCI) &&
+ (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
+ (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {
+ Status = PciIo->GetLocation (
+ PciIo,
+ &CompanionSegmentNumber,
+ &CompanionBusNumber,
+ &CompanionDeviceNumber,
+ &CompanionFunctionNumber
+ );
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ //
+ // Get the device path on this handle
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&Instance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = Instance->Pci.Read (
+ Instance,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto CLOSE_PCIIO;
+ }
+
+ if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) &&
+ (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
+ (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {
+ Status = Instance->GetLocation (
+ Instance,
+ &EhciSegmentNumber,
+ &EhciBusNumber,
+ &EhciDeviceNumber,
+ &EhciFunctionNumber
+ );
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ //
+ // Currently, the judgment on the companion usb host controller is through the
+ // same bus number, which may vary on different platform.
+ //
+ if (EhciBusNumber == CompanionBusNumber) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ EhcDriverBindingStart(This, HandleBuffer[Index], NULL);
+ }
+ }
+ }
+ Status = EFI_NOT_FOUND;
+ goto CLOSE_PCIIO;
+ }
+
+ //
+ // Create then install USB2_HC_PROTOCOL
+ //
+ Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);
+
+ if (Ehc == NULL) {
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CLOSE_PCIIO;
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if (EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT)) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Ehc->Support64BitDma = TRUE;
+ } else {
+ DEBUG ((EFI_D_WARN,
+ "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
+ __FUNCTION__, Controller, Status));
+ }
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiUsb2HcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Ehc->Usb2Hc
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
+ goto FREE_POOL;
+ }
+
+ //
+ // Robustnesss improvement such as for Duet platform
+ // Default is not required.
+ //
+ if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
+ EhcClearLegacySupport (Ehc);
+ }
+
+ if (!EhcIsDebugPortInUse (Ehc, NULL)) {
+ EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
+ }
+
+ Status = EhcInitHC (Ehc);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));
+ goto UNINSTALL_USBHC;
+ }
+
+ //
+ // Start the asynchronous interrupt monitor
+ //
+ Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
+
+ EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
+ goto UNINSTALL_USBHC;
+ }
+
+ //
+ // Create event to stop the HC when exit boot service.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EhcExitBootService,
+ Ehc,
+ &gEfiEventExitBootServicesGuid,
+ &Ehc->ExitBootServiceEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto UNINSTALL_USBHC;
+ }
+
+ //
+ // Install the component name protocol, don't fail the start
+ // because of something for display.
+ //
+ AddUnicodeString2 (
+ "eng",
+ gEhciComponentName.SupportedLanguages,
+ &Ehc->ControllerNameTable,
+ L"Enhanced Host Controller (USB 2.0)",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gEhciComponentName2.SupportedLanguages,
+ &Ehc->ControllerNameTable,
+ L"Enhanced Host Controller (USB 2.0)",
+ FALSE
+ );
+
+
+ DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));
+ return EFI_SUCCESS;
+
+UNINSTALL_USBHC:
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ &Ehc->Usb2Hc
+ );
+
+FREE_POOL:
+ EhcFreeSched (Ehc);
+ gBS->CloseEvent (Ehc->PollTimer);
+ gBS->FreePool (Ehc);
+
+CLOSE_PCIIO:
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalPciAttributes,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB2_HC_DEV *Ehc;
+
+ //
+ // Test whether the Controller handler passed in is a valid
+ // Usb controller handle that should be supported, if not,
+ // return the error status directly
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ehc = EHC_FROM_THIS (Usb2Hc);
+ PciIo = Ehc->PciIo;
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ Usb2Hc
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Stop AsyncRequest Polling timer then stop the EHCI driver
+ // and uninstall the EHCI protocl.
+ //
+ gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);
+ EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (Ehc->PollTimer != NULL) {
+ gBS->CloseEvent (Ehc->PollTimer);
+ }
+
+ if (Ehc->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (Ehc->ExitBootServiceEvent);
+ }
+
+ EhcFreeSched (Ehc);
+
+ if (Ehc->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (Ehc->ControllerNameTable);
+ }
+
+ //
+ // Disable routing of all ports to EHCI controller, so all ports are
+ // routed back to the UHCI or OHCI controller.
+ //
+ EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
+
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Ehc->OriginalPciAttributes,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (Ehc);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h
new file mode 100644
index 000000000..65933d943
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h
@@ -0,0 +1,233 @@
+/** @file
+
+ Provides some data struct used by EHCI controller driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_H_
+#define _EFI_EHCI_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/Usb2HostController.h>
+#include <Protocol/PciIo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+typedef struct _USB2_HC_DEV USB2_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "EhciReg.h"
+#include "EhciUrb.h"
+#include "EhciSched.h"
+#include "EhciDebug.h"
+#include "ComponentName.h"
+
+//
+// EHC timeout experience values
+//
+
+#define EHC_1_MICROSECOND 1
+#define EHC_1_MILLISECOND (1000 * EHC_1_MICROSECOND)
+#define EHC_1_SECOND (1000 * EHC_1_MILLISECOND)
+
+//
+// EHCI register operation timeout, set by experience
+//
+#define EHC_RESET_TIMEOUT (1 * EHC_1_SECOND)
+#define EHC_GENERIC_TIMEOUT (10 * EHC_1_MILLISECOND)
+
+//
+// Wait for roothub port power stable, refers to Spec[EHCI1.0-2.3.9]
+//
+#define EHC_ROOT_PORT_RECOVERY_STALL (20 * EHC_1_MILLISECOND)
+
+//
+// Sync and Async transfer polling interval, set by experience,
+// and the unit of Async is 100us, means 1ms as interval.
+//
+#define EHC_SYNC_POLL_INTERVAL (1 * EHC_1_MILLISECOND)
+#define EHC_ASYNC_POLL_INTERVAL EFI_TIMER_PERIOD_MILLISECONDS(1)
+
+//
+// EHCI debug port control status register bit definition
+//
+#define USB_DEBUG_PORT_IN_USE BIT10
+#define USB_DEBUG_PORT_ENABLE BIT28
+#define USB_DEBUG_PORT_OWNER BIT30
+#define USB_DEBUG_PORT_IN_USE_MASK (USB_DEBUG_PORT_IN_USE | \
+ USB_DEBUG_PORT_OWNER)
+
+//
+// EHC raises TPL to TPL_NOTIFY to serialize all its operations
+// to protect shared data structures.
+//
+#define EHC_TPL TPL_NOTIFY
+
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)
+
+
+#define EHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))
+#define EHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \
+ (EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))
+
+#define USB2_HC_DEV_SIGNATURE SIGNATURE_32 ('e', 'h', 'c', 'i')
+#define EHC_FROM_THIS(a) CR(a, USB2_HC_DEV, Usb2Hc, USB2_HC_DEV_SIGNATURE)
+
+struct _USB2_HC_DEV {
+ UINTN Signature;
+ EFI_USB2_HC_PROTOCOL Usb2Hc;
+
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT64 OriginalPciAttributes;
+ USBHC_MEM_POOL *MemPool;
+
+ //
+ // Schedule data shared between asynchronous and periodic
+ // transfers:
+ // ShortReadStop, as its name indicates, is used to terminate
+ // the short read except the control transfer. EHCI follows
+ // the alternative next QTD point when a short read happens.
+ // For control transfer, even the short read happens, try the
+ // status stage.
+ //
+ EHC_QTD *ShortReadStop;
+ EFI_EVENT PollTimer;
+
+ //
+ // ExitBootServicesEvent is used to stop the EHC DMA operation
+ // after exit boot service.
+ //
+ EFI_EVENT ExitBootServiceEvent;
+
+ //
+ // Asynchronous(bulk and control) transfer schedule data:
+ // ReclaimHead is used as the head of the asynchronous transfer
+ // list. It acts as the reclamation header.
+ //
+ EHC_QH *ReclaimHead;
+
+ //
+ // Periodic (interrupt) transfer schedule data:
+ //
+ VOID *PeriodFrame; // the buffer pointed by this pointer is used to store pci bus address of the QH descriptor.
+ VOID *PeriodFrameHost; // the buffer pointed by this pointer is used to store host memory address of the QH descriptor.
+ VOID *PeriodFrameMap;
+
+ EHC_QH *PeriodOne;
+ LIST_ENTRY AsyncIntTransfers;
+
+ //
+ // EHCI configuration data
+ //
+ UINT32 HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET
+ UINT32 HcCapParams; // Cache of HC capability parameter, HCCPARAMS
+ UINT32 CapLen; // Capability length
+
+ //
+ // Misc
+ //
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // EHCI debug port info
+ //
+ UINT16 DebugPortOffset; // The offset of debug port mmio register
+ UINT8 DebugPortBarNum; // The bar number of debug port mmio register
+ UINT8 DebugPortNum; // The port number of usb debug port
+
+ BOOLEAN Support64BitDma; // Whether 64 bit DMA may be used with this device
+};
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL gEhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gEhciComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gEhciComponentName2;
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has Usb2HcProtocol installed will
+ be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the Usb EHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS supports this device.
+ @return EFI_UNSUPPORTED do not support this device.
+ @return EFI_DEVICE_ERROR cannot be started due to device Error.
+ @return EFI_OUT_OF_RESOURCES cannot allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c
new file mode 100644
index 000000000..db0e2c6d3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c
@@ -0,0 +1,226 @@
+/** @file
+
+ This file provides the information dump support for EHCI when in debug mode.
+
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ehci.h"
+
+/**
+ Dump the status byte in QTD/QH to a more friendly format.
+
+ @param State The state in the QTD/QH.
+
+**/
+VOID
+EhcDumpStatus (
+ IN UINT32 State
+ )
+{
+ if (EHC_BIT_IS_SET (State, QTD_STAT_DO_PING)) {
+ DEBUG ((EFI_D_VERBOSE, " Do_Ping"));
+ } else {
+ DEBUG ((EFI_D_VERBOSE, " Do_Out"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_DO_CS)) {
+ DEBUG ((EFI_D_VERBOSE, " Do_CS"));
+ } else {
+ DEBUG ((EFI_D_VERBOSE, " Do_SS"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR)) {
+ DEBUG ((EFI_D_VERBOSE, " Transfer_Error"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
+ DEBUG ((EFI_D_VERBOSE, " Babble_Error"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
+ DEBUG ((EFI_D_VERBOSE, " Buffer_Error"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
+ DEBUG ((EFI_D_VERBOSE, " Halted"));
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
+ DEBUG ((EFI_D_VERBOSE, " Active"));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+}
+
+
+/**
+ Dump the fields of a QTD.
+
+ @param Qtd The QTD to dump.
+ @param Msg The message to print before the dump.
+
+**/
+VOID
+EhcDumpQtd (
+ IN EHC_QTD *Qtd,
+ IN CHAR8 *Msg
+ )
+{
+ QTD_HW *QtdHw;
+ UINTN Index;
+
+ if (Msg != NULL) {
+ DEBUG ((EFI_D_VERBOSE, Msg));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "Queue TD @ 0x%p, data length %d\n", Qtd, (UINT32)Qtd->DataLen));
+
+ QtdHw = &Qtd->QtdHw;
+
+ DEBUG ((EFI_D_VERBOSE, "Next QTD : %x\n", QtdHw->NextQtd));
+ DEBUG ((EFI_D_VERBOSE, "AltNext QTD : %x\n", QtdHw->AltNext));
+ DEBUG ((EFI_D_VERBOSE, "Status : %x\n", QtdHw->Status));
+ EhcDumpStatus (QtdHw->Status);
+
+ if (QtdHw->Pid == QTD_PID_SETUP) {
+ DEBUG ((EFI_D_VERBOSE, "PID : Setup\n"));
+
+ } else if (QtdHw->Pid == QTD_PID_INPUT) {
+ DEBUG ((EFI_D_VERBOSE, "PID : IN\n"));
+
+ } else if (QtdHw->Pid == QTD_PID_OUTPUT) {
+ DEBUG ((EFI_D_VERBOSE, "PID : OUT\n"));
+
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "Error Count : %d\n", QtdHw->ErrCnt));
+ DEBUG ((EFI_D_VERBOSE, "Current Page : %d\n", QtdHw->CurPage));
+ DEBUG ((EFI_D_VERBOSE, "IOC : %d\n", QtdHw->Ioc));
+ DEBUG ((EFI_D_VERBOSE, "Total Bytes : %d\n", QtdHw->TotalBytes));
+ DEBUG ((EFI_D_VERBOSE, "Data Toggle : %d\n", QtdHw->DataToggle));
+
+ for (Index = 0; Index < 5; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "Page[%d] : 0x%x\n", (UINT32)Index, QtdHw->Page[Index]));
+ }
+}
+
+
+/**
+ Dump the queue head.
+
+ @param Qh The queue head to dump.
+ @param Msg The message to print before the dump.
+ @param DumpBuf Whether to dump the memory buffer of the associated QTD.
+
+**/
+VOID
+EhcDumpQh (
+ IN EHC_QH *Qh,
+ IN CHAR8 *Msg,
+ IN BOOLEAN DumpBuf
+ )
+{
+ EHC_QTD *Qtd;
+ QH_HW *QhHw;
+ LIST_ENTRY *Entry;
+ UINTN Index;
+
+ if (Msg != NULL) {
+ DEBUG ((EFI_D_VERBOSE, Msg));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "Queue head @ 0x%p, interval %ld, next qh %p\n",
+ Qh, (UINT64)Qh->Interval, Qh->NextQh));
+
+ QhHw = &Qh->QhHw;
+
+ DEBUG ((EFI_D_VERBOSE, "Hoziontal link: %x\n", QhHw->HorizonLink));
+ DEBUG ((EFI_D_VERBOSE, "Device address: %d\n", QhHw->DeviceAddr));
+ DEBUG ((EFI_D_VERBOSE, "Inactive : %d\n", QhHw->Inactive));
+ DEBUG ((EFI_D_VERBOSE, "EP number : %d\n", QhHw->EpNum));
+ DEBUG ((EFI_D_VERBOSE, "EP speed : %d\n", QhHw->EpSpeed));
+ DEBUG ((EFI_D_VERBOSE, "DT control : %d\n", QhHw->DtCtrl));
+ DEBUG ((EFI_D_VERBOSE, "Reclaim head : %d\n", QhHw->ReclaimHead));
+ DEBUG ((EFI_D_VERBOSE, "Max packet len: %d\n", QhHw->MaxPacketLen));
+ DEBUG ((EFI_D_VERBOSE, "Ctrl EP : %d\n", QhHw->CtrlEp));
+ DEBUG ((EFI_D_VERBOSE, "Nak reload : %d\n", QhHw->NakReload));
+
+ DEBUG ((EFI_D_VERBOSE, "SMask : %x\n", QhHw->SMask));
+ DEBUG ((EFI_D_VERBOSE, "CMask : %x\n", QhHw->CMask));
+ DEBUG ((EFI_D_VERBOSE, "Hub address : %d\n", QhHw->HubAddr));
+ DEBUG ((EFI_D_VERBOSE, "Hub port : %d\n", QhHw->PortNum));
+ DEBUG ((EFI_D_VERBOSE, "Multiplier : %d\n", QhHw->Multiplier));
+
+ DEBUG ((EFI_D_VERBOSE, "Cur QTD : %x\n", QhHw->CurQtd));
+
+ DEBUG ((EFI_D_VERBOSE, "Next QTD : %x\n", QhHw->NextQtd));
+ DEBUG ((EFI_D_VERBOSE, "AltNext QTD : %x\n", QhHw->AltQtd));
+ DEBUG ((EFI_D_VERBOSE, "Status : %x\n", QhHw->Status));
+
+ EhcDumpStatus (QhHw->Status);
+
+ if (QhHw->Pid == QTD_PID_SETUP) {
+ DEBUG ((EFI_D_VERBOSE, "PID : Setup\n"));
+
+ } else if (QhHw->Pid == QTD_PID_INPUT) {
+ DEBUG ((EFI_D_VERBOSE, "PID : IN\n"));
+
+ } else if (QhHw->Pid == QTD_PID_OUTPUT) {
+ DEBUG ((EFI_D_VERBOSE, "PID : OUT\n"));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "Error Count : %d\n", QhHw->ErrCnt));
+ DEBUG ((EFI_D_VERBOSE, "Current Page : %d\n", QhHw->CurPage));
+ DEBUG ((EFI_D_VERBOSE, "IOC : %d\n", QhHw->Ioc));
+ DEBUG ((EFI_D_VERBOSE, "Total Bytes : %d\n", QhHw->TotalBytes));
+ DEBUG ((EFI_D_VERBOSE, "Data Toggle : %d\n", QhHw->DataToggle));
+
+ for (Index = 0; Index < 5; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "Page[%d] : 0x%x\n", Index, QhHw->Page[Index]));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+
+ BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
+ EhcDumpQtd (Qtd, NULL);
+
+ if (DumpBuf && (Qtd->DataLen != 0)) {
+ EhcDumpBuf (Qtd->Data, Qtd->DataLen);
+ }
+ }
+}
+
+
+/**
+ Dump the buffer in the form of hex.
+
+ @param Buf The buffer to dump.
+ @param Len The length of buffer.
+
+**/
+VOID
+EhcDumpBuf (
+ IN UINT8 *Buf,
+ IN UINTN Len
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Len; Index++) {
+ if (Index % 16 == 0) {
+ DEBUG ((EFI_D_VERBOSE,"\n"));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "%02x ", Buf[Index]));
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h
new file mode 100644
index 000000000..eff85dcec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h
@@ -0,0 +1,58 @@
+/** @file
+
+ This file contains the definination for host controller debug support routines.
+
+Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_DEBUG_H_
+#define _EFI_EHCI_DEBUG_H_
+
+
+/**
+ Dump the fields of a QTD.
+
+ @param Qtd The QTD to dump.
+ @param Msg The message to print before the dump.
+
+**/
+VOID
+EhcDumpQtd (
+ IN EHC_QTD *Qtd,
+ IN CHAR8 *Msg
+ );
+
+
+/**
+ Dump the queue head.
+
+ @param Qh The queue head to dump.
+ @param Msg The message to print before the dump.
+ @param DumpBuf Whether to dump the memory buffer of the associated QTD.
+
+**/
+VOID
+EhcDumpQh (
+ IN EHC_QH *Qh,
+ IN CHAR8 *Msg,
+ IN BOOLEAN DumpBuf
+ );
+
+
+/**
+ Dump the buffer in the form of hex.
+
+ @param Buf The buffer to dump.
+ @param Len The length of buffer.
+
+**/
+VOID
+EhcDumpBuf (
+ IN UINT8 *Buf,
+ IN UINTN Len
+ );
+
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
new file mode 100644
index 000000000..ffce075c2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
@@ -0,0 +1,84 @@
+## @file
+# The EhciDxe driver is responsible for managing the behavior of EHCI controller.
+# It implements the interfaces of monitoring the status of all ports and transferring
+# Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.
+#
+# Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
+# to the EHCI controller before the UHCI driver attaches to the companion UHCI controller.
+# This way avoids the control transfer on a shared port between EHCI and companion host
+# controller when UHCI gets attached earlier than EHCI and a USB 2.0 device inserts.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EhciDxe
+ MODULE_UNI_FILE = EhciDxe.uni
+ FILE_GUID = BDFE430E-8F2A-4db0-9991-6F856594777E
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = EhcDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gEhciDriverBinding
+# COMPONENT_NAME = gEhciComponentName
+# COMPONENT_NAME2 = gEhciComponentName2
+#
+
+[Sources]
+ UsbHcMem.h
+ EhciUrb.c
+ EhciReg.h
+ UsbHcMem.c
+ EhciSched.c
+ EhciDebug.c
+ EhciReg.c
+ EhciDebug.h
+ ComponentName.c
+ ComponentName.h
+ EhciUrb.h
+ Ehci.h
+ EhciSched.h
+ Ehci.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport ## CONSUMES
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ ReportStatusCodeLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiUsb2HcProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EhciDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.uni
new file mode 100644
index 000000000..cc5a35fa7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.uni
@@ -0,0 +1,24 @@
+// /** @file
+// The EhciDxe driver is responsible for managing the behavior of EHCI controller.
+//
+// It implements the interfaces of monitoring the status of all ports and transferring
+// Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.
+//
+// Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
+// to the EHCI controller before the UHCI driver attaches to the companion UHCI controller.
+// This way avoids the control transfer on a shared port between EHCI and companion host
+// controller when UHCI gets attached earlier than EHCI and a USB 2.0 device inserts.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the behavior of EHCI controller"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Implements the interfaces for monitoring the status of all ports and transferring\n"
+ "Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.<BR><BR>\n"
+ "Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached to the EHCI controller before the UHCI driver attaches to the companion UHCI controller. This method avoids the control transfer on a shared port between EHCI and a companion host controller when UHCI attaches earlier than EHCI and a USB 2.0 device inserts.<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxeExtra.uni
new file mode 100644
index 000000000..e714c7283
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EhciDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EHCI Controller DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
new file mode 100644
index 000000000..ca63736f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
@@ -0,0 +1,669 @@
+/** @file
+
+ The EHCI register operation routines.
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ehci.h"
+
+
+/**
+ Read EHCI capability register.
+
+ @param Ehc The EHCI device.
+ @param Offset Capability register address.
+
+ @return The register content read.
+ @retval If err, return 0xffff.
+
+**/
+UINT32
+EhcReadCapRegister (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = Ehc->PciIo->Mem.Read (
+ Ehc->PciIo,
+ EfiPciIoWidthUint32,
+ EHC_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcReadCapRegister: Pci Io read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFF;
+ }
+
+ return Data;
+}
+
+/**
+ Read EHCI debug port register.
+
+ @param Ehc The EHCI device.
+ @param Offset Debug port register offset.
+
+ @return The register content read.
+ @retval If err, return 0xffff.
+
+**/
+UINT32
+EhcReadDbgRegister (
+ IN CONST USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = Ehc->PciIo->Mem.Read (
+ Ehc->PciIo,
+ EfiPciIoWidthUint32,
+ Ehc->DebugPortBarNum,
+ Ehc->DebugPortOffset + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcReadDbgRegister: Pci Io read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFF;
+ }
+
+ return Data;
+}
+
+
+/**
+ Check whether the host controller has an in-use debug port.
+
+ @param[in] Ehc The Enhanced Host Controller to query.
+
+ @param[in] PortNumber If PortNumber is not NULL, then query whether
+ PortNumber is an in-use debug port on Ehc. (PortNumber
+ is taken in UEFI notation, i.e., zero-based.)
+ Otherwise, query whether Ehc has any in-use debug
+ port.
+
+ @retval TRUE PortNumber is an in-use debug port on Ehc (if PortNumber is
+ not NULL), or some port on Ehc is an in-use debug port
+ (otherwise).
+
+ @retval FALSE PortNumber is not an in-use debug port on Ehc (if PortNumber
+ is not NULL), or no port on Ehc is an in-use debug port
+ (otherwise).
+**/
+BOOLEAN
+EhcIsDebugPortInUse (
+ IN CONST USB2_HC_DEV *Ehc,
+ IN CONST UINT8 *PortNumber OPTIONAL
+ )
+{
+ UINT32 State;
+
+ if (Ehc->DebugPortNum == 0) {
+ //
+ // The host controller has no debug port.
+ //
+ return FALSE;
+ }
+
+ //
+ // The Debug Port Number field in HCSPARAMS is one-based.
+ //
+ if (PortNumber != NULL && *PortNumber != Ehc->DebugPortNum - 1) {
+ //
+ // The caller specified a port, but it's not the debug port of the host
+ // controller.
+ //
+ return FALSE;
+ }
+
+ //
+ // Deduce usage from the Control Register.
+ //
+ State = EhcReadDbgRegister(Ehc, 0);
+ return (State & USB_DEBUG_PORT_IN_USE_MASK) == USB_DEBUG_PORT_IN_USE_MASK;
+}
+
+
+/**
+ Read EHCI Operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset The operation register offset.
+
+ @return The register content read.
+ @retval If err, return 0xffff.
+
+**/
+UINT32
+EhcReadOpReg (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ ASSERT (Ehc->CapLen != 0);
+
+ Status = Ehc->PciIo->Mem.Read (
+ Ehc->PciIo,
+ EfiPciIoWidthUint32,
+ EHC_BAR_INDEX,
+ Ehc->CapLen + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFF;
+ }
+
+ return Data;
+}
+
+
+/**
+ Write the data to the EHCI operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset EHCI operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+EhcWriteOpReg (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Ehc->CapLen != 0);
+
+ Status = Ehc->PciIo->Mem.Write (
+ Ehc->PciIo,
+ EfiPciIoWidthUint32,
+ EHC_BAR_INDEX,
+ Ehc->CapLen + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
+ }
+}
+
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+EhcSetOpRegBit (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = EhcReadOpReg (Ehc, Offset);
+ Data |= Bit;
+ EhcWriteOpReg (Ehc, Offset, Data);
+}
+
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+EhcClearOpRegBit (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = EhcReadOpReg (Ehc, Offset);
+ Data &= ~Bit;
+ EhcWriteOpReg (Ehc, Offset, Data);
+}
+
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to become set (or clear).
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operation register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EhcWaitOpRegBit (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
+ if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (EHC_SYNC_POLL_INTERVAL);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Add support for UEFI Over Legacy (UoL) feature, stop
+ the legacy USB SMI support.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcClearLegacySupport (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ UINT32 ExtendCap;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 Value;
+ UINT32 TimeOut;
+
+ DEBUG ((EFI_D_INFO, "EhcClearLegacySupport: called to clear legacy support\n"));
+
+ PciIo = Ehc->PciIo;
+ ExtendCap = (Ehc->HcCapParams >> 8) & 0xFF;
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
+ Value |= (0x1 << 24);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
+
+ TimeOut = 40;
+ while (TimeOut-- != 0) {
+ gBS->Stall (500);
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
+
+ if ((Value & 0x01010000) == 0x01000000) {
+ break;
+ }
+ }
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
+}
+
+
+
+/**
+ Set door bell and wait it to be ACKed by host controller.
+ This function is used to synchronize with the hardware.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS Synchronized with the hardware.
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
+
+**/
+EFI_STATUS
+EhcSetAndWaitDoorBell (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
+
+ //
+ // ACK the IAA bit in USBSTS register. Make sure other
+ // interrupt bits are not ACKed. These bits are WC (Write Clean).
+ //
+ Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
+ Data &= ~USBSTS_INTACK_MASK;
+ Data |= USBSTS_IAA;
+
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
+
+ return Status;
+}
+
+
+/**
+ Clear all the interrutp status bits, these bits
+ are Write-Clean.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcAckAllInterrupt (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
+}
+
+
+/**
+ Enable the periodic schedule then wait EHC to
+ actually enable it.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The periodical schedule is enabled.
+ @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
+
+**/
+EFI_STATUS
+EhcEnablePeriodSchd (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
+ return Status;
+}
+
+
+
+
+
+
+/**
+ Enable asynchrounous schedule.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
+ @return Others Failed to enable the asynchronous scheudle.
+
+**/
+EFI_STATUS
+EhcEnableAsyncSchd (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
+ return Status;
+}
+
+
+
+
+
+
+
+/**
+ Whether Ehc is halted.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE It isn't halted.
+
+**/
+BOOLEAN
+EhcIsHalt (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
+}
+
+
+/**
+ Whether system error occurred.
+
+ @param Ehc The EHCI device.
+
+ @return TRUE System error happened.
+ @return FALSE No system error.
+
+**/
+BOOLEAN
+EhcIsSysError (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
+}
+
+
+/**
+ Reset the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The host controller is reset.
+ @return Others Failed to reset the host.
+
+**/
+EFI_STATUS
+EhcResetHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Host can only be reset when it is halt. If not so, halt it
+ //
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
+ Status = EhcHaltHC (Ehc, Timeout);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
+ return Status;
+}
+
+
+/**
+ Halt the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI is halt.
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
+
+**/
+EFI_STATUS
+EhcHaltHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
+ return Status;
+}
+
+
+/**
+ Set the EHCI to run.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI is running.
+ @return Others Failed to set the EHCI to run.
+
+**/
+EFI_STATUS
+EhcRunHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
+ return Status;
+}
+
+
+/**
+ Initialize the HC hardware.
+ EHCI spec lists the five things to do to initialize the hardware:
+ 1. Program CTRLDSSEGMENT
+ 2. Set USBINTR to enable interrupts
+ 3. Set periodic list base
+ 4. Set USBCMD, interrupt threshold, frame list size etc
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI
+
+ @param Ehc The EHCI device.
+
+ @return EFI_SUCCESS The EHCI has come out of halt state.
+ @return EFI_TIMEOUT Time out happened.
+
+**/
+EFI_STATUS
+EhcInitHC (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 RegVal;
+
+ // This ASSERT crashes the BeagleBoard. There is some issue in the USB stack.
+ // This ASSERT needs to be removed so the BeagleBoard will boot. When we fix
+ // the USB stack we can put this ASSERT back in
+ // ASSERT (EhcIsHalt (Ehc));
+
+ //
+ // Allocate the periodic frame and associated memeory
+ // management facilities if not already done.
+ //
+ if (Ehc->PeriodFrame != NULL) {
+ EhcFreeSched (Ehc);
+ }
+
+ Status = EhcInitSched (Ehc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 1. Clear USBINTR to disable all the interrupt. UEFI works by polling
+ //
+ EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
+
+ //
+ // 2. Start the Host Controller
+ //
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+
+ //
+ // 3. Power up all ports if EHCI has Port Power Control (PPC) support
+ //
+ if (Ehc->HcStructParams & HCSP_PPC) {
+ for (Index = 0; Index < (UINT8) (Ehc->HcStructParams & HCSP_NPORTS); Index++) {
+ //
+ // Do not clear port status bits on initialization. Otherwise devices will
+ // not enumerate properly at startup.
+ //
+ RegVal = EhcReadOpReg(Ehc, (UINT32)(EHC_PORT_STAT_OFFSET + (4 * Index)));
+ RegVal &= ~PORTSC_CHANGE_MASK;
+ RegVal |= PORTSC_POWER;
+ EhcWriteOpReg (Ehc, (UINT32) (EHC_PORT_STAT_OFFSET + (4 * Index)), RegVal);
+ }
+ }
+
+ //
+ // Wait roothub port power stable
+ //
+ gBS->Stall (EHC_ROOT_PORT_RECOVERY_STALL);
+
+ //
+ // 4. Set all ports routing to EHC
+ //
+ EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
+
+ Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable period schedule\n"));
+ return Status;
+ }
+
+ Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcInitHC: failed to enable async schedule\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h
new file mode 100644
index 000000000..911cd2135
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h
@@ -0,0 +1,366 @@
+/** @file
+
+ This file contains the definination for host controller register operation routines.
+
+Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_REG_H_
+#define _EFI_EHCI_REG_H_
+
+//
+// EHCI register offset
+//
+
+
+//
+// Capability register offset
+//
+#define EHC_CAPLENGTH_OFFSET 0 // Capability register length offset
+#define EHC_HCSPARAMS_OFFSET 0x04 // Structural Parameters 04-07h
+#define EHC_HCCPARAMS_OFFSET 0x08 // Capability parameters offset
+
+//
+// Capability register bit definition
+//
+#define HCSP_NPORTS 0x0F // Number of root hub port
+#define HCSP_PPC 0x10 // Port Power Control
+#define HCCP_64BIT 0x01 // 64-bit addressing capability
+
+//
+// Operational register offset
+//
+#define EHC_USBCMD_OFFSET 0x0 // USB command register offset
+#define EHC_USBSTS_OFFSET 0x04 // Statue register offset
+#define EHC_USBINTR_OFFSET 0x08 // USB interrutp offset
+#define EHC_FRINDEX_OFFSET 0x0C // Frame index offset
+#define EHC_CTRLDSSEG_OFFSET 0x10 // Control data structure segment offset
+#define EHC_FRAME_BASE_OFFSET 0x14 // Frame list base address offset
+#define EHC_ASYNC_HEAD_OFFSET 0x18 // Next asynchronous list address offset
+#define EHC_CONFIG_FLAG_OFFSET 0x40 // Configure flag register offset
+#define EHC_PORT_STAT_OFFSET 0x44 // Port status/control offset
+
+#define EHC_FRAME_LEN 1024
+
+//
+// Register bit definition
+//
+#define CONFIGFLAG_ROUTE_EHC 0x01 // Route port to EHC
+
+#define USBCMD_RUN 0x01 // Run/stop
+#define USBCMD_RESET 0x02 // Start the host controller reset
+#define USBCMD_ENABLE_PERIOD 0x10 // Enable periodic schedule
+#define USBCMD_ENABLE_ASYNC 0x20 // Enable asynchronous schedule
+#define USBCMD_IAAD 0x40 // Interrupt on async advance doorbell
+
+#define USBSTS_IAA 0x20 // Interrupt on async advance
+#define USBSTS_PERIOD_ENABLED 0x4000 // Periodic schedule status
+#define USBSTS_ASYNC_ENABLED 0x8000 // Asynchronous schedule status
+#define USBSTS_HALT 0x1000 // Host controller halted
+#define USBSTS_SYS_ERROR 0x10 // Host system error
+#define USBSTS_INTACK_MASK 0x003F // Mask for the interrupt ACK, the WC
+ // (write clean) bits in USBSTS register
+
+#define PORTSC_CONN 0x01 // Current Connect Status
+#define PORTSC_CONN_CHANGE 0x02 // Connect Status Change
+#define PORTSC_ENABLED 0x04 // Port Enable / Disable
+#define PORTSC_ENABLE_CHANGE 0x08 // Port Enable / Disable Change
+#define PORTSC_OVERCUR 0x10 // Over current Active
+#define PORTSC_OVERCUR_CHANGE 0x20 // Over current Change
+#define PORSTSC_RESUME 0x40 // Force Port Resume
+#define PORTSC_SUSPEND 0x80 // Port Suspend State
+#define PORTSC_RESET 0x100 // Port Reset
+#define PORTSC_LINESTATE_K 0x400 // Line Status K-state
+#define PORTSC_LINESTATE_J 0x800 // Line Status J-state
+#define PORTSC_POWER 0x1000 // Port Power
+#define PORTSC_OWNER 0x2000 // Port Owner
+#define PORTSC_CHANGE_MASK 0x2A // Mask of the port change bits,
+ // they are WC (write clean)
+//
+// PCI Configuration Registers
+//
+#define EHC_BAR_INDEX 0 // how many bytes away from USB_BASE to 0x10
+
+//
+// Debug port capability id
+//
+#define EHC_DEBUG_PORT_CAP_ID 0x0A
+
+#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)
+
+#define EHC_ADDR(High, QhHw32) \
+ ((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))
+
+#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)
+
+//
+// Structure to map the hardware port states to the
+// UEFI's port states.
+//
+typedef struct {
+ UINT16 HwState;
+ UINT16 UefiState;
+} USB_PORT_STATE_MAP;
+
+//
+// Ehci Data and Ctrl Structures
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+#pragma pack()
+
+/**
+ Read EHCI capability register.
+
+ @param Ehc The EHCI device.
+ @param Offset Capability register address.
+
+ @return The register content.
+
+**/
+UINT32
+EhcReadCapRegister (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ );
+
+/**
+ Check whether the host controller has an in-use debug port.
+
+ @param[in] Ehc The Enhanced Host Controller to query.
+
+ @param[in] PortNumber If PortNumber is not NULL, then query whether
+ PortNumber is an in-use debug port on Ehc. (PortNumber
+ is taken in UEFI notation, i.e., zero-based.)
+ Otherwise, query whether Ehc has any in-use debug
+ port.
+
+ @retval TRUE PortNumber is an in-use debug port on Ehc (if PortNumber is
+ not NULL), or some port on Ehc is an in-use debug port
+ (otherwise).
+
+ @retval FALSE PortNumber is not an in-use debug port on Ehc (if PortNumber
+ is not NULL), or no port on Ehc is an in-use debug port
+ (otherwise).
+**/
+BOOLEAN
+EhcIsDebugPortInUse (
+ IN CONST USB2_HC_DEV *Ehc,
+ IN CONST UINT8 *PortNumber OPTIONAL
+ );
+
+/**
+ Read EHCI Operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset The operation register offset.
+
+ @return The register content.
+
+**/
+UINT32
+EhcReadOpReg (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ );
+
+
+/**
+ Write the data to the EHCI operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset EHCI operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+EhcWriteOpReg (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+EhcSetOpRegBit (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+EhcClearOpRegBit (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Add support for UEFI Over Legacy (UoL) feature, stop
+ the legacy USB SMI support.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcClearLegacySupport (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+
+/**
+ Set door bell and wait it to be ACKed by host controller.
+ This function is used to synchronize with the hardware.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS Synchronized with the hardware.
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
+
+**/
+EFI_STATUS
+EhcSetAndWaitDoorBell (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ );
+
+
+/**
+ Clear all the interrutp status bits, these bits are Write-Clean.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcAckAllInterrupt (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+
+/**
+ Whether Ehc is halted.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE It isn't halted.
+
+**/
+BOOLEAN
+EhcIsHalt (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+/**
+ Whether system error occurred.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+EhcIsSysError (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+/**
+ Reset the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The host controller is reset.
+ @return Others Failed to reset the host.
+
+**/
+EFI_STATUS
+EhcResetHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ );
+
+
+/**
+ Halt the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @return EFI_SUCCESS The EHCI is halt.
+ @return EFI_TIMEOUT Failed to halt the controller before Timeout.
+
+**/
+EFI_STATUS
+EhcHaltHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ );
+
+
+/**
+ Set the EHCI to run.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @return EFI_SUCCESS The EHCI is running.
+ @return Others Failed to set the EHCI to run.
+
+**/
+EFI_STATUS
+EhcRunHC (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ );
+
+
+
+/**
+ Initialize the HC hardware.
+ EHCI spec lists the five things to do to initialize the hardware:
+ 1. Program CTRLDSSEGMENT
+ 2. Set USBINTR to enable interrupts
+ 3. Set periodic list base
+ 4. Set USBCMD, interrupt threshold, frame list size etc
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI
+
+ @param Ehc The EHCI device.
+
+ @return EFI_SUCCESS The EHCI has come out of halt state.
+ @return EFI_TIMEOUT Time out happened.
+
+**/
+EFI_STATUS
+EhcInitHC (
+ IN USB2_HC_DEV *Ehc
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
new file mode 100644
index 000000000..5fe7cf466
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
@@ -0,0 +1,1126 @@
+/** @file
+
+ EHCI transfer scheduling routines.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ehci.h"
+
+
+/**
+ Create helper QTD/QH for the EHCI device.
+
+ @param Ehc The EHCI device.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH.
+ @retval EFI_SUCCESS Helper QH/QTD are created.
+
+**/
+EFI_STATUS
+EhcCreateHelpQ (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ USB_ENDPOINT Ep;
+ EHC_QH *Qh;
+ QH_HW *QhHw;
+ EHC_QTD *Qtd;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ //
+ // Create an inactive Qtd to terminate the short packet read.
+ //
+ Qtd = EhcCreateQtd (Ehc, NULL, NULL, 0, QTD_PID_INPUT, 0, 64);
+
+ if (Qtd == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Qtd->QtdHw.Status = QTD_STAT_HALTED;
+ Ehc->ShortReadStop = Qtd;
+
+ //
+ // Create a QH to act as the EHC reclamation header.
+ // Set the header to loopback to itself.
+ //
+ Ep.DevAddr = 0;
+ Ep.EpAddr = 1;
+ Ep.Direction = EfiUsbDataIn;
+ Ep.DevSpeed = EFI_USB_SPEED_HIGH;
+ Ep.MaxPacket = 64;
+ Ep.HubAddr = 0;
+ Ep.HubPort = 0;
+ Ep.Toggle = 0;
+ Ep.Type = EHC_BULK_TRANSFER;
+ Ep.PollRate = 1;
+
+ Qh = EhcCreateQh (Ehc, &Ep);
+
+ if (Qh == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
+ QhHw = &Qh->QhHw;
+ QhHw->HorizonLink = QH_LINK (PciAddr + OFFSET_OF(EHC_QH, QhHw), EHC_TYPE_QH, FALSE);
+ QhHw->Status = QTD_STAT_HALTED;
+ QhHw->ReclaimHead = 1;
+ Qh->NextQh = Qh;
+ Ehc->ReclaimHead = Qh;
+
+ //
+ // Create a dummy QH to act as the terminator for periodical schedule
+ //
+ Ep.EpAddr = 2;
+ Ep.Type = EHC_INT_TRANSFER_SYNC;
+
+ Qh = EhcCreateQh (Ehc, &Ep);
+
+ if (Qh == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Qh->QhHw.Status = QTD_STAT_HALTED;
+ Ehc->PeriodOne = Qh;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize the schedule data structure such as frame list.
+
+ @param Ehc The EHCI device to init schedule data.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.
+ @retval EFI_SUCCESS The schedule data is initialized.
+
+**/
+EFI_STATUS
+EhcInitSched (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ UINTN Pages;
+ UINTN Bytes;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ //
+ // First initialize the periodical schedule data:
+ // 1. Allocate and map the memory for the frame list
+ // 2. Create the help QTD/QH
+ // 3. Initialize the frame entries
+ // 4. Set the frame list register
+ //
+ PciIo = Ehc->PciIo;
+
+ Bytes = 4096;
+ Pages = EFI_SIZE_TO_PAGES (Bytes);
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &Buf,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buf,
+ &Bytes,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != 4096)) {
+ PciIo->FreeBuffer (PciIo, Pages, Buf);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ehc->PeriodFrame = Buf;
+ Ehc->PeriodFrameMap = Map;
+
+ //
+ // Program the FRAMELISTBASE register with the low 32 bit addr
+ //
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr));
+ //
+ // Program the CTRLDSSEGMENT register with the high 32 bit addr
+ //
+ EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, EHC_HIGH_32BIT (PhyAddr));
+
+ //
+ // Init memory pool management then create the helper
+ // QTD/QH. If failed, previously allocated resources
+ // will be freed by EhcFreeSched
+ //
+ Ehc->MemPool = UsbHcInitMemPool (
+ PciIo,
+ Ehc->Support64BitDma,
+ EHC_HIGH_32BIT (PhyAddr)
+ );
+
+ if (Ehc->MemPool == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit1;
+ }
+
+ Status = EhcCreateHelpQ (Ehc);
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize the frame list entries then set the registers
+ //
+ Ehc->PeriodFrameHost = AllocateZeroPool (EHC_FRAME_LEN * sizeof (UINTN));
+ if (Ehc->PeriodFrameHost == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
+
+ for (Index = 0; Index < EHC_FRAME_LEN; Index++) {
+ //
+ // Store the pci bus address of the QH in period frame list which will be accessed by pci bus master.
+ //
+ ((UINT32 *)(Ehc->PeriodFrame))[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ //
+ // Store the host address of the QH in period frame list which will be accessed by host.
+ //
+ ((UINTN *)(Ehc->PeriodFrameHost))[Index] = (UINTN)Ehc->PeriodOne;
+ }
+
+ //
+ // Second initialize the asynchronous schedule:
+ // Only need to set the AsynListAddr register to
+ // the reclamation header
+ //
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr));
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (Ehc->PeriodOne != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
+ Ehc->PeriodOne = NULL;
+ }
+
+ if (Ehc->ReclaimHead != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
+ Ehc->ReclaimHead = NULL;
+ }
+
+ if (Ehc->ShortReadStop != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
+ Ehc->ShortReadStop = NULL;
+ }
+
+ErrorExit1:
+ PciIo->FreeBuffer (PciIo, Pages, Buf);
+ PciIo->Unmap (PciIo, Map);
+
+ return Status;
+}
+
+
+/**
+ Free the schedule data. It may be partially initialized.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcFreeSched (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);
+
+ if (Ehc->PeriodOne != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
+ Ehc->PeriodOne = NULL;
+ }
+
+ if (Ehc->ReclaimHead != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
+ Ehc->ReclaimHead = NULL;
+ }
+
+ if (Ehc->ShortReadStop != NULL) {
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
+ Ehc->ShortReadStop = NULL;
+ }
+
+ if (Ehc->MemPool != NULL) {
+ UsbHcFreeMemPool (Ehc->MemPool);
+ Ehc->MemPool = NULL;
+ }
+
+ if (Ehc->PeriodFrame != NULL) {
+ PciIo = Ehc->PciIo;
+ ASSERT (PciIo != NULL);
+
+ PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);
+
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),
+ Ehc->PeriodFrame
+ );
+
+ Ehc->PeriodFrame = NULL;
+ }
+
+ if (Ehc->PeriodFrameHost != NULL) {
+ FreePool (Ehc->PeriodFrameHost);
+ Ehc->PeriodFrameHost = NULL;
+ }
+}
+
+
+/**
+ Link the queue head to the asynchronous schedule list.
+ UEFI only supports one CTRL/BULK transfer at a time
+ due to its interfaces. This simplifies the AsynList
+ management: A reclamation header is always linked to
+ the AsyncListAddr, the only active QH is appended to it.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToAsync (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ )
+{
+ EHC_QH *Head;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ //
+ // Append the queue head after the reclaim header, then
+ // fix the hardware visiable parts (EHCI R1.0 page 72).
+ // ReclaimHead is always linked to the EHCI's AsynListAddr.
+ //
+ Head = Ehc->ReclaimHead;
+
+ Qh->NextQh = Head->NextQh;
+ Head->NextQh = Qh;
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh->NextQh, sizeof (EHC_QH));
+ Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
+ Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+}
+
+
+/**
+ Unlink a queue head from the asynchronous schedule list.
+ Need to synchronize with hardware.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromAsync (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ )
+{
+ EHC_QH *Head;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ ASSERT (Ehc->ReclaimHead->NextQh == Qh);
+
+ //
+ // Remove the QH from reclamation head, then update the hardware
+ // visiable part: Only need to loopback the ReclaimHead. The Qh
+ // is pointing to ReclaimHead (which is staill in the list).
+ //
+ Head = Ehc->ReclaimHead;
+
+ Head->NextQh = Qh->NextQh;
+ Qh->NextQh = NULL;
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
+ Head->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+
+ //
+ // Set and wait the door bell to synchronize with the hardware
+ //
+ Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));
+ }
+}
+
+
+/**
+ Link a queue head for interrupt transfer to the periodic
+ schedule frame list. This code is very much the same as
+ that in UHCI.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToPeriod (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ )
+{
+ UINTN Index;
+ EHC_QH *Prev;
+ EHC_QH *Next;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
+ //
+ // First QH can't be NULL because we always keep PeriodOne
+ // heads on the frame list
+ //
+ ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));
+ Next = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];
+ Prev = NULL;
+
+ //
+ // Now, insert the queue head (Qh) into this frame:
+ // 1. Find a queue head with the same poll interval, just insert
+ // Qh after this queue head, then we are done.
+ //
+ // 2. Find the position to insert the queue head into:
+ // Previous head's interval is bigger than Qh's
+ // Next head's interval is less than Qh's
+ // Then, insert the Qh between then
+ //
+ while (Next->Interval > Qh->Interval) {
+ Prev = Next;
+ Next = Next->NextQh;
+ }
+
+ ASSERT (Next != NULL);
+
+ //
+ // The entry may have been linked into the frame by early insertation.
+ // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
+ // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
+ // It isn't necessary to compare all the QH with the same interval to
+ // Qh. This is because if there is other QH with the same interval, Qh
+ // should has been inserted after that at Frames[0] and at Frames[0] it is
+ // impossible for (Next == Qh)
+ //
+ if (Next == Qh) {
+ continue;
+ }
+
+ if (Next->Interval == Qh->Interval) {
+ //
+ // If there is a QH with the same interval, it locates at
+ // Frames[0], and we can simply insert it after this QH. We
+ // are all done.
+ //
+ ASSERT ((Index == 0) && (Qh->NextQh == NULL));
+
+ Prev = Next;
+ Next = Next->NextQh;
+
+ Qh->NextQh = Next;
+ Prev->NextQh = Qh;
+
+ Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
+ Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ break;
+ }
+
+ //
+ // OK, find the right position, insert it in. If Qh's next
+ // link has already been set, it is in position. This is
+ // guarranted by 2^n polling interval.
+ //
+ if (Qh->NextQh == NULL) {
+ Qh->NextQh = Next;
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Next, sizeof (EHC_QH));
+ Qh->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ }
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
+
+ if (Prev == NULL) {
+ ((UINT32*)Ehc->PeriodFrame)[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh;
+ } else {
+ Prev->NextQh = Qh;
+ Prev->QhHw.HorizonLink = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ }
+ }
+}
+
+
+/**
+ Unlink an interrupt queue head from the periodic
+ schedule frame list.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromPeriod (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ )
+{
+ UINTN Index;
+ EHC_QH *Prev;
+ EHC_QH *This;
+
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
+ //
+ // Frame link can't be NULL because we always keep PeroidOne
+ // on the frame list
+ //
+ ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));
+ This = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];
+ Prev = NULL;
+
+ //
+ // Walk through the frame's QH list to find the
+ // queue head to remove
+ //
+ while ((This != NULL) && (This != Qh)) {
+ Prev = This;
+ This = This->NextQh;
+ }
+
+ //
+ // Qh may have already been unlinked from this frame
+ // by early action. See the comments in EhcLinkQhToPeriod.
+ //
+ if (This == NULL) {
+ continue;
+ }
+
+ if (Prev == NULL) {
+ //
+ // Qh is the first entry in the frame
+ //
+ ((UINT32*)Ehc->PeriodFrame)[Index] = Qh->QhHw.HorizonLink;
+ ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh->NextQh;
+ } else {
+ Prev->NextQh = Qh->NextQh;
+ Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;
+ }
+ }
+}
+
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to check result.
+
+ @return Whether the result of URB transfer is finialized.
+
+**/
+BOOLEAN
+EhcCheckUrbResult (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ )
+{
+ LIST_ENTRY *Entry;
+ EHC_QTD *Qtd;
+ QTD_HW *QtdHw;
+ UINT8 State;
+ BOOLEAN Finished;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));
+
+ Finished = TRUE;
+ Urb->Completed = 0;
+
+ Urb->Result = EFI_USB_NOERROR;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ Urb->Result |= EFI_USB_ERR_SYSTEM;
+ goto ON_EXIT;
+ }
+
+ BASE_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
+ QtdHw = &Qtd->QtdHw;
+ State = (UINT8) QtdHw->Status;
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
+ //
+ // EHCI will halt the queue head when met some error.
+ // If it is halted, the result of URB is finialized.
+ //
+ if ((State & QTD_STAT_ERR_MASK) == 0) {
+ Urb->Result |= EFI_USB_ERR_STALL;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
+ Urb->Result |= EFI_USB_ERR_BABBLE;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
+ Urb->Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ Finished = TRUE;
+ goto ON_EXIT;
+
+ } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
+ //
+ // The QTD is still active, no need to check furthur.
+ //
+ Urb->Result |= EFI_USB_ERR_NOTEXECUTE;
+
+ Finished = FALSE;
+ goto ON_EXIT;
+
+ } else {
+ //
+ // This QTD is finished OK or met short packet read. Update the
+ // transfer length if it isn't a setup.
+ //
+ if (QtdHw->Pid != QTD_PID_SETUP) {
+ Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;
+ }
+
+ if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {
+ EhcDumpQh (Urb->Qh, "Short packet read", FALSE);
+
+ //
+ // Short packet read condition. If it isn't a setup transfer,
+ // no need to check furthur: the queue head will halt at the
+ // ShortReadStop. If it is a setup transfer, need to check the
+ // Status Stage of the setup transfer to get the finial result
+ //
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
+ if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) {
+ DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n"));
+
+ Finished = TRUE;
+ goto ON_EXIT;
+ }
+
+ DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n"));
+ }
+ }
+ }
+
+ON_EXIT:
+ //
+ // Return the data toggle set by EHCI hardware, bulk and interrupt
+ // transfer will use this to initialize the next transaction. For
+ // Control transfer, it always start a new data toggle sequence for
+ // new transfer.
+ //
+ // NOTICE: don't move DT update before the loop, otherwise there is
+ // a race condition that DT is wrong.
+ //
+ Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;
+
+ return Finished;
+}
+
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to execute.
+ @param TimeOut The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+EhcExecTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb,
+ IN UINTN TimeOut
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Loop;
+ BOOLEAN Finished;
+ BOOLEAN InfiniteLoop;
+
+ Status = EFI_SUCCESS;
+ Loop = TimeOut * EHC_1_MILLISECOND;
+ Finished = FALSE;
+ InfiniteLoop = FALSE;
+
+ //
+ // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
+ // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
+ // is returned.
+ //
+ if (TimeOut == 0) {
+ InfiniteLoop = TRUE;
+ }
+
+ for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {
+ Finished = EhcCheckUrbResult (Ehc, Urb);
+
+ if (Finished) {
+ break;
+ }
+
+ gBS->Stall (EHC_1_MICROSECOND);
+ }
+
+ if (!Finished) {
+ DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut));
+ EhcDumpQh (Urb->Qh, NULL, FALSE);
+
+ Status = EFI_TIMEOUT;
+
+ } else if (Urb->Result != EFI_USB_NOERROR) {
+ DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result));
+ EhcDumpQh (Urb->Qh, NULL, FALSE);
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The address of the target device.
+ @param EpNum The endpoint of the target.
+ @param DataToggle Return the next data toggle to use.
+
+ @retval EFI_SUCCESS An asynchronous transfer is removed.
+ @retval EFI_NOT_FOUND No transfer for the device is found.
+
+**/
+EFI_STATUS
+EhciDelAsyncIntTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpNum,
+ OUT UINT8 *DataToggle
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ URB *Urb;
+ EFI_USB_DATA_DIRECTION Direction;
+
+ Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
+ EpNum &= 0x0F;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+
+ if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) &&
+ (Urb->Ep.Direction == Direction)) {
+ //
+ // Check the URB status to retrieve the next data toggle
+ // from the associated queue head.
+ //
+ EhcCheckUrbResult (Ehc, Urb);
+ *DataToggle = Urb->DataToggle;
+
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
+ RemoveEntryList (&Urb->UrbList);
+
+ gBS->FreePool (Urb->Data);
+ EhcFreeUrb (Ehc, Urb);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Remove all the asynchronous interrutp transfers.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhciDelAllAsyncIntTransfers (
+ IN USB2_HC_DEV *Ehc
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ URB *Urb;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
+ RemoveEntryList (&Urb->UrbList);
+
+ gBS->FreePool (Urb->Data);
+ EhcFreeUrb (Ehc, Urb);
+ }
+}
+
+/**
+ Insert a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @return Created URB or NULL.
+
+**/
+URB *
+EhciInsertAsyncIntTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ )
+{
+ VOID *Data;
+ URB *Urb;
+
+ Data = AllocatePool (DataLen);
+
+ if (Data == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));
+ return NULL;
+ }
+
+ Urb = EhcCreateUrb (
+ Ehc,
+ DevAddr,
+ EpAddr,
+ DevSpeed,
+ Toggle,
+ MaxPacket,
+ Hub,
+ EHC_INT_TRANSFER_ASYNC,
+ NULL,
+ Data,
+ DataLen,
+ Callback,
+ Context,
+ Interval
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));
+ gBS->FreePool (Data);
+ return NULL;
+ }
+
+ //
+ // New asynchronous transfer must inserted to the head.
+ // Check the comments in EhcMoniteAsyncRequests
+ //
+ EhcLinkQhToPeriod (Ehc, Urb->Qh);
+ InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);
+
+ return Urb;
+}
+
+/**
+ Flush data from PCI controller specific address to mapped system
+ memory address.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to unmap.
+
+ @retval EFI_SUCCESS Success to flush data to mapped system memory.
+ @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
+
+**/
+EFI_STATUS
+EhcFlushAsyncIntMap (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Len;
+ VOID *Map;
+
+ PciIo = Ehc->PciIo;
+ Len = Urb->DataLen;
+
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+
+ Status = PciIo->Unmap (PciIo, Urb->DataMap);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Urb->DataMap = NULL;
+
+ Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
+ goto ON_ERROR;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Update the queue head for next round of asynchronous transfer.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to update.
+
+**/
+VOID
+EhcUpdateAsyncRequest (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ )
+{
+ LIST_ENTRY *Entry;
+ EHC_QTD *FirstQtd;
+ QH_HW *QhHw;
+ EHC_QTD *Qtd;
+ QTD_HW *QtdHw;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ Qtd = NULL;
+
+ if (Urb->Result == EFI_USB_NOERROR) {
+ FirstQtd = NULL;
+
+ BASE_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
+
+ if (FirstQtd == NULL) {
+ FirstQtd = Qtd;
+ }
+
+ //
+ // Update the QTD for next round of transfer. Host control
+ // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/
+ // Current Offset. These fields need to be updated. DT isn't
+ // used by interrupt transfer. It uses DT in queue head.
+ // Current Offset is in Page[0], only need to reset Page[0]
+ // to initial data buffer.
+ //
+ QtdHw = &Qtd->QtdHw;
+ QtdHw->Status = QTD_STAT_ACTIVE;
+ QtdHw->ErrCnt = QTD_MAX_ERR;
+ QtdHw->CurPage = 0;
+ QtdHw->TotalBytes = (UINT32) Qtd->DataLen;
+ //
+ // calculate physical address by offset.
+ //
+ PciAddr = (UINTN)Urb->DataPhy + ((UINTN)Qtd->Data - (UINTN)Urb->Data);
+ QtdHw->Page[0] = EHC_LOW_32BIT (PciAddr);
+ QtdHw->PageHigh[0]= EHC_HIGH_32BIT (PciAddr);
+ }
+
+ //
+ // Update QH for next round of transfer. Host control only
+ // touch the fields in transfer overlay area. Only need to
+ // zero out the overlay area and set NextQtd to the first
+ // QTD. DateToggle bit is left untouched.
+ //
+ QhHw = &Urb->Qh->QhHw;
+ QhHw->CurQtd = QTD_LINK (0, TRUE);
+ QhHw->AltQtd = 0;
+
+ QhHw->Status = 0;
+ QhHw->Pid = 0;
+ QhHw->ErrCnt = 0;
+ QhHw->CurPage = 0;
+ QhHw->Ioc = 0;
+ QhHw->TotalBytes = 0;
+
+ for (Index = 0; Index < 5; Index++) {
+ QhHw->Page[Index] = 0;
+ QhHw->PageHigh[Index] = 0;
+ }
+
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, FirstQtd, sizeof (EHC_QTD));
+ QhHw->NextQtd = QTD_LINK (PciAddr, FALSE);
+ }
+
+ return ;
+}
+
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event Interrupt event.
+ @param Context Pointer to USB2_HC_DEV.
+
+**/
+VOID
+EFIAPI
+EhcMonitorAsyncRequests (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB2_HC_DEV *Ehc;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ BOOLEAN Finished;
+ UINT8 *ProcBuf;
+ URB *Urb;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ Ehc = (USB2_HC_DEV *) Context;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+
+ //
+ // Check the result of URB execution. If it is still
+ // active, check the next one.
+ //
+ Finished = EhcCheckUrbResult (Ehc, Urb);
+
+ if (!Finished) {
+ continue;
+ }
+
+ //
+ // Flush any PCI posted write transactions from a PCI host
+ // bridge to system memory.
+ //
+ Status = EhcFlushAsyncIntMap (Ehc, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
+ }
+
+ //
+ // Allocate a buffer then copy the transferred data for user.
+ // If failed to allocate the buffer, update the URB for next
+ // round of transfer. Ignore the data of this round.
+ //
+ ProcBuf = NULL;
+
+ if (Urb->Result == EFI_USB_NOERROR) {
+ //
+ // Make sure the data received from HW is no more than expected.
+ //
+ if (Urb->Completed <= Urb->DataLen) {
+ ProcBuf = AllocatePool (Urb->Completed);
+ }
+
+ if (ProcBuf == NULL) {
+ EhcUpdateAsyncRequest (Ehc, Urb);
+ continue;
+ }
+
+ CopyMem (ProcBuf, Urb->Data, Urb->Completed);
+ }
+
+ EhcUpdateAsyncRequest (Ehc, Urb);
+
+ //
+ // Leave error recovery to its related device driver. A
+ // common case of the error recovery is to re-submit the
+ // interrupt transfer which is linked to the head of the
+ // list. This function scans from head to tail. So the
+ // re-submitted interrupt transfer's callback function
+ // will not be called again in this round. Don't touch this
+ // URB after the callback, it may have been removed by the
+ // callback.
+ //
+ if (Urb->Callback != NULL) {
+ //
+ // Restore the old TPL, USB bus maybe connect device in
+ // his callback. Some drivers may has a lower TPL restriction.
+ //
+ gBS->RestoreTPL (OldTpl);
+ (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
+ OldTpl = gBS->RaiseTPL (EHC_TPL);
+ }
+
+ if (ProcBuf != NULL) {
+ FreePool (ProcBuf);
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h
new file mode 100644
index 000000000..34fb9a3be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h
@@ -0,0 +1,207 @@
+/** @file
+
+ This file contains the definination for host controller schedule routines.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_SCHED_H_
+#define _EFI_EHCI_SCHED_H_
+
+
+/**
+ Initialize the schedule data structure such as frame list.
+
+ @param Ehc The EHCI device to init schedule data for.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.
+ @retval EFI_SUCCESS The schedule data is initialized.
+
+**/
+EFI_STATUS
+EhcInitSched (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+/**
+ Free the schedule data. It may be partially initialized.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcFreeSched (
+ IN USB2_HC_DEV *Ehc
+ );
+
+
+/**
+ Link the queue head to the asynchronous schedule list.
+ UEFI only supports one CTRL/BULK transfer at a time
+ due to its interfaces. This simplifies the AsynList
+ management: A reclamation header is always linked to
+ the AsyncListAddr, the only active QH is appended to it.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToAsync (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ );
+
+
+/**
+ Unlink a queue head from the asynchronous schedule list.
+ Need to synchronize with hardware.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromAsync (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ );
+
+
+/**
+ Link a queue head for interrupt transfer to the periodic
+ schedule frame list. This code is very much the same as
+ that in UHCI.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToPeriod (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ );
+
+
+/**
+ Unlink an interrupt queue head from the periodic
+ schedule frame list.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromPeriod (
+ IN USB2_HC_DEV *Ehc,
+ IN EHC_QH *Qh
+ );
+
+
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to execute.
+ @param TimeOut The time to wait before abort, in millisecond.
+
+ @retval EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+EhcExecTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb,
+ IN UINTN TimeOut
+ );
+
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The address of the target device.
+ @param EpNum The endpoint of the target.
+ @param DataToggle Return the next data toggle to use.
+
+ @retval EFI_SUCCESS An asynchronous transfer is removed.
+ @retval EFI_NOT_FOUND No transfer for the device is found.
+
+**/
+EFI_STATUS
+EhciDelAsyncIntTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpNum,
+ OUT UINT8 *DataToggle
+ );
+
+
+/**
+ Remove all the asynchronous interrutp transfers.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhciDelAllAsyncIntTransfers (
+ IN USB2_HC_DEV *Ehc
+ );
+
+/**
+ Insert a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @return Created URB or NULL.
+
+**/
+URB *
+EhciInsertAsyncIntTransfer (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ );
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event Interrupt event.
+ @param Context Pointer to USB2_HC_DEV.
+
+**/
+VOID
+EFIAPI
+EhcMonitorAsyncRequests (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
new file mode 100644
index 000000000..37cef6d13
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
@@ -0,0 +1,652 @@
+/** @file
+
+ This file contains URB request, each request is warpped in a
+ URB (Usb Request Block).
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Ehci.h"
+
+
+/**
+ Create a single QTD to hold the data.
+
+ @param Ehc The EHCI device.
+ @param Data The cpu memory address of current data not associated with a QTD.
+ @param DataPhy The pci bus address of current data not associated with a QTD.
+ @param DataLen The length of the data.
+ @param PktId Packet ID to use in the QTD.
+ @param Toggle Data toggle to use in the QTD.
+ @param MaxPacket Maximu packet length of the endpoint.
+
+ @return Created QTD or NULL if failed to create one.
+
+**/
+EHC_QTD *
+EhcCreateQtd (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket
+ )
+{
+ EHC_QTD *Qtd;
+ QTD_HW *QtdHw;
+ UINTN Index;
+ UINTN Len;
+ UINTN ThisBufLen;
+
+ ASSERT (Ehc != NULL);
+
+ Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));
+
+ if (Qtd == NULL) {
+ return NULL;
+ }
+
+ Qtd->Signature = EHC_QTD_SIG;
+ Qtd->Data = Data;
+ Qtd->DataLen = 0;
+
+ InitializeListHead (&Qtd->QtdList);
+
+ QtdHw = &Qtd->QtdHw;
+ QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
+ QtdHw->AltNext = QTD_LINK (NULL, TRUE);
+ QtdHw->Status = QTD_STAT_ACTIVE;
+ QtdHw->Pid = PktId;
+ QtdHw->ErrCnt = QTD_MAX_ERR;
+ QtdHw->Ioc = 0;
+ QtdHw->TotalBytes = 0;
+ QtdHw->DataToggle = Toggle;
+
+ //
+ // Fill in the buffer points
+ //
+ if (Data != NULL) {
+ Len = 0;
+
+ for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
+ //
+ // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
+ // compute the offset and clear Reserved fields. This is already
+ // done in the data point.
+ //
+ QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);
+ QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);
+
+ ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);
+
+ if (Len + ThisBufLen >= DataLen) {
+ Len = DataLen;
+ break;
+ }
+
+ Len += ThisBufLen;
+ Data += ThisBufLen;
+ DataPhy += ThisBufLen;
+ }
+
+ //
+ // Need to fix the last pointer if the Qtd can't hold all the
+ // user's data to make sure that the length is in the unit of
+ // max packets. If it can hold all the data, there is no such
+ // need.
+ //
+ if (Len < DataLen) {
+ Len = Len - Len % MaxPacket;
+ }
+
+ QtdHw->TotalBytes = (UINT32) Len;
+ Qtd->DataLen = Len;
+ }
+
+ return Qtd;
+}
+
+
+
+/**
+ Initialize the queue head for interrupt transfer,
+ that is, initialize the following three fields:
+ 1. SplitXState in the Status field
+ 2. Microframe S-mask
+ 3. Microframe C-mask
+
+ @param Ep The queue head's related endpoint.
+ @param QhHw The queue head to initialize.
+
+**/
+VOID
+EhcInitIntQh (
+ IN USB_ENDPOINT *Ep,
+ IN QH_HW *QhHw
+ )
+{
+ //
+ // Because UEFI interface can't utilitize an endpoint with
+ // poll rate faster than 1ms, only need to set one bit in
+ // the queue head. simple. But it may be changed later. If
+ // sub-1ms interrupt is supported, need to update the S-Mask
+ // here
+ //
+ if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
+ QhHw->SMask = QH_MICROFRAME_0;
+ return ;
+ }
+
+ //
+ // For low/full speed device, the transfer must go through
+ // the split transaction. Need to update three fields
+ // 1. SplitXState in the status
+ // 2. Microframe S-Mask
+ // 3. Microframe C-Mask
+ // UEFI USB doesn't exercise admission control. It simplely
+ // schedule the high speed transactions in microframe 0, and
+ // full/low speed transactions at microframe 1. This also
+ // avoid the use of FSTN.
+ //
+ QhHw->SMask = QH_MICROFRAME_1;
+ QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
+}
+
+
+
+/**
+ Allocate and initialize a EHCI queue head.
+
+ @param Ehci The EHCI device.
+ @param Ep The endpoint to create queue head for.
+
+ @return Created queue head or NULL if failed to create one.
+
+**/
+EHC_QH *
+EhcCreateQh (
+ IN USB2_HC_DEV *Ehci,
+ IN USB_ENDPOINT *Ep
+ )
+{
+ EHC_QH *Qh;
+ QH_HW *QhHw;
+
+ Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
+
+ if (Qh == NULL) {
+ return NULL;
+ }
+
+ Qh->Signature = EHC_QH_SIG;
+ Qh->NextQh = NULL;
+ Qh->Interval = Ep->PollRate;
+
+ InitializeListHead (&Qh->Qtds);
+
+ QhHw = &Qh->QhHw;
+ QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
+ QhHw->DeviceAddr = Ep->DevAddr;
+ QhHw->Inactive = 0;
+ QhHw->EpNum = Ep->EpAddr;
+ QhHw->EpSpeed = Ep->DevSpeed;
+ QhHw->DtCtrl = 0;
+ QhHw->ReclaimHead = 0;
+ QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
+ QhHw->CtrlEp = 0;
+ QhHw->NakReload = QH_NAK_RELOAD;
+ QhHw->HubAddr = Ep->HubAddr;
+ QhHw->PortNum = Ep->HubPort;
+ QhHw->Multiplier = 1;
+ QhHw->DataToggle = Ep->Toggle;
+
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
+ QhHw->Status |= QTD_STAT_DO_SS;
+ }
+
+ switch (Ep->Type) {
+ case EHC_CTRL_TRANSFER:
+ //
+ // Special initialization for the control transfer:
+ // 1. Control transfer initialize data toggle from each QTD
+ // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
+ //
+ QhHw->DtCtrl = 1;
+
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
+ QhHw->CtrlEp = 1;
+ }
+ break;
+
+ case EHC_INT_TRANSFER_ASYNC:
+ case EHC_INT_TRANSFER_SYNC:
+ //
+ // Special initialization for the interrupt transfer
+ // to set the S-Mask and C-Mask
+ //
+ QhHw->NakReload = 0;
+ EhcInitIntQh (Ep, QhHw);
+ break;
+
+ case EHC_BULK_TRANSFER:
+ if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
+ QhHw->Status |= QTD_STAT_DO_PING;
+ }
+
+ break;
+ }
+
+ return Qh;
+}
+
+
+/**
+ Convert the poll interval from application to that
+ be used by EHCI interface data structure. Only need
+ to get the max 2^n that is less than interval. UEFI
+ can't support high speed endpoint with a interval less
+ than 8 microframe because interval is specified in
+ the unit of ms (millisecond).
+
+ @param Interval The interval to convert.
+
+ @return The converted interval.
+
+**/
+UINTN
+EhcConvertPollRate (
+ IN UINTN Interval
+ )
+{
+ UINTN BitCount;
+
+ if (Interval == 0) {
+ return 1;
+ }
+
+ //
+ // Find the index (1 based) of the highest non-zero bit
+ //
+ BitCount = 0;
+
+ while (Interval != 0) {
+ Interval >>= 1;
+ BitCount++;
+ }
+
+ return (UINTN)1 << (BitCount - 1);
+}
+
+
+/**
+ Free a list of QTDs.
+
+ @param Ehc The EHCI device.
+ @param Qtds The list head of the QTD.
+
+**/
+VOID
+EhcFreeQtds (
+ IN USB2_HC_DEV *Ehc,
+ IN LIST_ENTRY *Qtds
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ EHC_QTD *Qtd;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
+
+ RemoveEntryList (&Qtd->QtdList);
+ UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
+ }
+}
+
+
+/**
+ Free an allocated URB. It is possible for it to be partially inited.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+EhcFreeUrb (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Ehc->PciIo;
+
+ if (Urb->RequestPhy != NULL) {
+ PciIo->Unmap (PciIo, Urb->RequestMap);
+ }
+
+ if (Urb->DataMap != NULL) {
+ PciIo->Unmap (PciIo, Urb->DataMap);
+ }
+
+ if (Urb->Qh != NULL) {
+ //
+ // Ensure that this queue head has been unlinked from the
+ // schedule data structures. Free all the associated QTDs
+ //
+ EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
+ UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
+ }
+
+ gBS->FreePool (Urb);
+}
+
+
+/**
+ Create a list of QTDs for the URB.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to create QTDs for.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
+ @retval EFI_SUCCESS The QTDs are allocated for the URB.
+
+**/
+EFI_STATUS
+EhcCreateQtds (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ )
+{
+ USB_ENDPOINT *Ep;
+ EHC_QH *Qh;
+ EHC_QTD *Qtd;
+ EHC_QTD *StatusQtd;
+ EHC_QTD *NextQtd;
+ LIST_ENTRY *Entry;
+ UINT32 AlterNext;
+ UINT8 Toggle;
+ UINTN Len;
+ UINT8 Pid;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
+
+ //
+ // EHCI follows the alternet next QTD pointer if it meets
+ // a short read and the AlterNext pointer is valid. UEFI
+ // EHCI driver should terminate the transfer except the
+ // control transfer.
+ //
+ Toggle = 0;
+ Qh = Urb->Qh;
+ Ep = &Urb->Ep;
+ StatusQtd = NULL;
+ AlterNext = QTD_LINK (NULL, TRUE);
+
+ PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
+ if (Ep->Direction == EfiUsbDataIn) {
+ AlterNext = QTD_LINK (PhyAddr, FALSE);
+ }
+
+ //
+ // Build the Setup and status packets for control transfer
+ //
+ if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
+
+ if (Qtd == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);
+
+ //
+ // Create the status packet now. Set the AlterNext to it. So, when
+ // EHCI meets a short control read, it can resume at the status stage.
+ // Use the opposite direction of the data stage, or IN if there is
+ // no data stage.
+ //
+ if (Ep->Direction == EfiUsbDataIn) {
+ Pid = QTD_PID_OUTPUT;
+ } else {
+ Pid = QTD_PID_INPUT;
+ }
+
+ StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);
+
+ if (StatusQtd == NULL) {
+ goto ON_ERROR;
+ }
+
+ if (Ep->Direction == EfiUsbDataIn) {
+ PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));
+ AlterNext = QTD_LINK (PhyAddr, FALSE);
+ }
+
+ Toggle = 1;
+ }
+
+ //
+ // Build the data packets for all the transfers
+ //
+ if (Ep->Direction == EfiUsbDataIn) {
+ Pid = QTD_PID_INPUT;
+ } else {
+ Pid = QTD_PID_OUTPUT;
+ }
+
+ Qtd = NULL;
+ Len = 0;
+
+ while (Len < Urb->DataLen) {
+ Qtd = EhcCreateQtd (
+ Ehc,
+ (UINT8 *) Urb->Data + Len,
+ (UINT8 *) Urb->DataPhy + Len,
+ Urb->DataLen - Len,
+ Pid,
+ Toggle,
+ Ep->MaxPacket
+ );
+
+ if (Qtd == NULL) {
+ goto ON_ERROR;
+ }
+
+ Qtd->QtdHw.AltNext = AlterNext;
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);
+
+ //
+ // Switch the Toggle bit if odd number of packets are included in the QTD.
+ //
+ if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
+ Toggle = (UINT8) (1 - Toggle);
+ }
+
+ Len += Qtd->DataLen;
+ }
+
+ //
+ // Insert the status packet for control transfer
+ //
+ if (Ep->Type == EHC_CTRL_TRANSFER) {
+ InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
+ }
+
+ //
+ // OK, all the QTDs needed are created. Now, fix the NextQtd point
+ //
+ BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
+
+ //
+ // break if it is the last entry on the list
+ //
+ if (Entry->ForwardLink == &Qh->Qtds) {
+ break;
+ }
+
+ NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
+ PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
+ Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
+ }
+
+ //
+ // Link the QTDs to the queue head
+ //
+ NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
+ PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
+ Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ EhcFreeQtds (Ehc, &Qh->Qtds);
+ return EFI_OUT_OF_RESOURCES;
+}
+
+
+/**
+ Create a new URB and its associated QTD.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param Type The transaction type.
+ @param Request The standard USB request for control transfer.
+ @param Data The user data to transfer.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @return Created URB or NULL.
+
+**/
+URB *
+EhcCreateUrb (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ )
+{
+ USB_ENDPOINT *Ep;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINTN Len;
+ URB *Urb;
+ VOID *Map;
+
+ Urb = AllocateZeroPool (sizeof (URB));
+
+ if (Urb == NULL) {
+ return NULL;
+ }
+
+ Urb->Signature = EHC_URB_SIG;
+ InitializeListHead (&Urb->UrbList);
+
+ Ep = &Urb->Ep;
+ Ep->DevAddr = DevAddr;
+ Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
+ Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
+ Ep->DevSpeed = DevSpeed;
+ Ep->MaxPacket = MaxPacket;
+
+ Ep->HubAddr = 0;
+ Ep->HubPort = 0;
+
+ if (DevSpeed != EFI_USB_SPEED_HIGH) {
+ ASSERT (Hub != NULL);
+
+ Ep->HubAddr = Hub->TranslatorHubAddress;
+ Ep->HubPort = Hub->TranslatorPortNumber;
+ }
+
+ Ep->Toggle = Toggle;
+ Ep->Type = Type;
+ Ep->PollRate = EhcConvertPollRate (Interval);
+
+ Urb->Request = Request;
+ Urb->Data = Data;
+ Urb->DataLen = DataLen;
+ Urb->Callback = Callback;
+ Urb->Context = Context;
+
+ PciIo = Ehc->PciIo;
+ Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
+
+ if (Urb->Qh == NULL) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Map the request and user data
+ //
+ if (Request != NULL) {
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ MapOp = EfiPciIoOperationBusMasterRead;
+ Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
+ goto ON_ERROR;
+ }
+
+ Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->RequestMap = Map;
+ }
+
+ if (Data != NULL) {
+ Len = DataLen;
+
+ if (Ep->Direction == EfiUsbDataIn) {
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+
+ Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != DataLen)) {
+ goto ON_ERROR;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ }
+
+ Status = EhcCreateQtds (Ehc, Urb);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return Urb;
+
+ON_ERROR:
+ EhcFreeUrb (Ehc, Urb);
+ return NULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h
new file mode 100644
index 000000000..6342bf6b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h
@@ -0,0 +1,330 @@
+/** @file
+
+ This file contains URB request, each request is warpped in a
+ URB (Usb Request Block).
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_URB_H_
+#define _EFI_EHCI_URB_H_
+
+
+typedef struct _EHC_QTD EHC_QTD;
+typedef struct _EHC_QH EHC_QH;
+typedef struct _URB URB;
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define EHC_CTRL_TRANSFER 0x01
+#define EHC_BULK_TRANSFER 0x02
+#define EHC_INT_TRANSFER_SYNC 0x04
+#define EHC_INT_TRANSFER_ASYNC 0x08
+
+#define EHC_QTD_SIG SIGNATURE_32 ('U', 'S', 'B', 'T')
+#define EHC_QH_SIG SIGNATURE_32 ('U', 'S', 'B', 'H')
+#define EHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')
+
+//
+// Hardware related bit definitions
+//
+#define EHC_TYPE_ITD 0x00
+#define EHC_TYPE_QH 0x02
+#define EHC_TYPE_SITD 0x04
+#define EHC_TYPE_FSTN 0x06
+
+#define QH_NAK_RELOAD 3
+#define QH_HSHBW_MULTI 1
+
+#define QTD_MAX_ERR 3
+#define QTD_PID_OUTPUT 0x00
+#define QTD_PID_INPUT 0x01
+#define QTD_PID_SETUP 0x02
+
+#define QTD_STAT_DO_OUT 0
+#define QTD_STAT_DO_SS 0
+#define QTD_STAT_DO_PING 0x01
+#define QTD_STAT_DO_CS 0x02
+#define QTD_STAT_TRANS_ERR 0x08
+#define QTD_STAT_BABBLE_ERR 0x10
+#define QTD_STAT_BUFF_ERR 0x20
+#define QTD_STAT_HALTED 0x40
+#define QTD_STAT_ACTIVE 0x80
+#define QTD_STAT_ERR_MASK (QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR)
+
+#define QTD_MAX_BUFFER 4
+#define QTD_BUF_LEN 4096
+#define QTD_BUF_MASK 0x0FFF
+
+#define QH_MICROFRAME_0 0x01
+#define QH_MICROFRAME_1 0x02
+#define QH_MICROFRAME_2 0x04
+#define QH_MICROFRAME_3 0x08
+#define QH_MICROFRAME_4 0x10
+#define QH_MICROFRAME_5 0x20
+#define QH_MICROFRAME_6 0x40
+#define QH_MICROFRAME_7 0x80
+
+#define USB_ERR_SHORT_PACKET 0x200
+
+//
+// Fill in the hardware link point: pass in a EHC_QH/QH_HW
+// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK
+//
+#define QH_LINK(Addr, Type, Term) \
+ ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))
+
+#define QTD_LINK(Addr, Term) QH_LINK((Addr), 0, (Term))
+
+//
+// The defination of EHCI hardware used data structure for
+// little endian architecture. The QTD and QH structures
+// are required to be 32 bytes aligned. Don't add members
+// to the head of the associated software strucuture.
+//
+#pragma pack(1)
+typedef struct {
+ UINT32 NextQtd;
+ UINT32 AltNext;
+
+ UINT32 Status : 8;
+ UINT32 Pid : 2;
+ UINT32 ErrCnt : 2;
+ UINT32 CurPage : 3;
+ UINT32 Ioc : 1;
+ UINT32 TotalBytes : 15;
+ UINT32 DataToggle : 1;
+
+ UINT32 Page[5];
+ UINT32 PageHigh[5];
+} QTD_HW;
+
+typedef struct {
+ UINT32 HorizonLink;
+ //
+ // Endpoint capabilities/Characteristics DWord 1 and DWord 2
+ //
+ UINT32 DeviceAddr : 7;
+ UINT32 Inactive : 1;
+ UINT32 EpNum : 4;
+ UINT32 EpSpeed : 2;
+ UINT32 DtCtrl : 1;
+ UINT32 ReclaimHead : 1;
+ UINT32 MaxPacketLen : 11;
+ UINT32 CtrlEp : 1;
+ UINT32 NakReload : 4;
+
+ UINT32 SMask : 8;
+ UINT32 CMask : 8;
+ UINT32 HubAddr : 7;
+ UINT32 PortNum : 7;
+ UINT32 Multiplier : 2;
+
+ //
+ // Transaction execution overlay area
+ //
+ UINT32 CurQtd;
+ UINT32 NextQtd;
+ UINT32 AltQtd;
+
+ UINT32 Status : 8;
+ UINT32 Pid : 2;
+ UINT32 ErrCnt : 2;
+ UINT32 CurPage : 3;
+ UINT32 Ioc : 1;
+ UINT32 TotalBytes : 15;
+ UINT32 DataToggle : 1;
+
+ UINT32 Page[5];
+ UINT32 PageHigh[5];
+} QH_HW;
+#pragma pack()
+
+
+//
+// Endpoint address and its capabilities
+//
+typedef struct _USB_ENDPOINT {
+ UINT8 DevAddr;
+ UINT8 EpAddr; // Endpoint address, no direction encoded in
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 DevSpeed;
+ UINTN MaxPacket;
+ UINT8 HubAddr;
+ UINT8 HubPort;
+ UINT8 Toggle; // Data toggle, not used for control transfer
+ UINTN Type;
+ UINTN PollRate; // Polling interval used by EHCI
+} USB_ENDPOINT;
+
+//
+// Software QTD strcture, this is used to manage all the
+// QTD generated from a URB. Don't add fields before QtdHw.
+//
+struct _EHC_QTD {
+ QTD_HW QtdHw;
+ UINT32 Signature;
+ LIST_ENTRY QtdList; // The list of QTDs to one end point
+ UINT8 *Data; // Buffer of the original data
+ UINTN DataLen; // Original amount of data in this QTD
+};
+
+//
+// Software QH structure. All three different transaction types
+// supported by UEFI USB, that is the control/bulk/interrupt
+// transfers use the queue head and queue token strcuture.
+//
+// Interrupt QHs are linked to periodic frame list in the reversed
+// 2^N tree. Each interrupt QH is linked to the list starting at
+// frame 0. There is a dummy interrupt QH linked to each frame as
+// a sentinental whose polling interval is 1. Synchronous interrupt
+// transfer is linked after this dummy QH.
+//
+// For control/bulk transfer, only synchronous (in the sense of UEFI)
+// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr
+// as the reclamation header. New transfer is inserted after this QH.
+//
+struct _EHC_QH {
+ QH_HW QhHw;
+ UINT32 Signature;
+ EHC_QH *NextQh; // The queue head pointed to by horizontal link
+ LIST_ENTRY Qtds; // The list of QTDs to this queue head
+ UINTN Interval;
+};
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+struct _URB {
+ UINT32 Signature;
+ LIST_ENTRY UrbList;
+
+ //
+ // Transaction information
+ //
+ USB_ENDPOINT Ep;
+ EFI_USB_DEVICE_REQUEST *Request; // Control transfer only
+ VOID *RequestPhy; // Address of the mapped request
+ VOID *RequestMap;
+ VOID *Data;
+ UINTN DataLen;
+ VOID *DataPhy; // Address of the mapped user data
+ VOID *DataMap;
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
+ VOID *Context;
+
+ //
+ // Schedule data
+ //
+ EHC_QH *Qh;
+
+ //
+ // Transaction result
+ //
+ UINT32 Result;
+ UINTN Completed; // completed data length
+ UINT8 DataToggle;
+};
+
+
+
+/**
+ Create a single QTD to hold the data.
+
+ @param Ehc The EHCI device.
+ @param Data The cpu memory address of current data not associated with a QTD.
+ @param DataPhy The pci bus address of current data not associated with a QTD.
+ @param DataLen The length of the data.
+ @param PktId Packet ID to use in the QTD.
+ @param Toggle Data toggle to use in the QTD.
+ @param MaxPacket Maximu packet length of the endpoint.
+
+ @return Created QTD or NULL if failed to create one.
+
+**/
+EHC_QTD *
+EhcCreateQtd (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket
+ );
+
+
+
+/**
+ Allocate and initialize a EHCI queue head.
+
+ @param Ehci The EHCI device.
+ @param Ep The endpoint to create queue head for.
+
+ @return Created queue head or NULL if failed to create one.
+
+**/
+EHC_QH *
+EhcCreateQh (
+ IN USB2_HC_DEV *Ehci,
+ IN USB_ENDPOINT *Ep
+ );
+
+
+/**
+ Free an allocated URB. It is possible for it to be partially inited.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+EhcFreeUrb (
+ IN USB2_HC_DEV *Ehc,
+ IN URB *Urb
+ );
+
+
+/**
+ Create a new URB and its associated QTD.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param Type The transaction type.
+ @param Request The standard USB request for control transfer.
+ @param Data The user data to transfer.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @return Created URB or NULL.
+
+**/
+URB *
+EhcCreateUrb (
+ IN USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c
new file mode 100644
index 000000000..43d0968dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c
@@ -0,0 +1,560 @@
+/** @file
+
+ Routine procedures for memory allocate/free.
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ehci.h"
+
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ UINTN Bytes;
+ EFI_STATUS Status;
+
+ PciIo = Pool->PciIo;
+
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
+ if (Block == NULL) {
+ return NULL;
+ }
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+ Block->Bits = AllocateZeroPool (Block->BitsLen);
+
+ if (Block->Bits == NULL) {
+ gBS->FreePool (Block);
+ return NULL;
+ }
+
+ //
+ // Allocate the number of Pages of memory, then map it for
+ // bus master read and write.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &BufHost,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_BITARRAY;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ BufHost,
+ &Bytes,
+ &MappedAddr,
+ &Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+ goto FREE_BUFFER;
+ }
+
+ //
+ // Check whether the data structure used by the host controller
+ // should be restricted into the same 4G
+ //
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+ PciIo->Unmap (PciIo, Mapping);
+ goto FREE_BUFFER;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+
+ return Block;
+
+FREE_BUFFER:
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);
+
+FREE_BITARRAY:
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+ return NULL;
+}
+
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ PciIo = Pool->PciIo;
+
+ //
+ // Unmap the common buffer then free the structures
+ //
+ PciIo->Unmap (PciIo, Block->Mapping);
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
+
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+}
+
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Unlink the memory block from the pool's list.
+
+ @param Head The block list head of the memory's pool.
+ @param BlockToUnlink The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *BlockToUnlink
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ if (Block->Next == BlockToUnlink) {
+ Block->Next = BlockToUnlink->Next;
+ BlockToUnlink->Next = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+{
+ USBHC_MEM_POOL *Pool;
+
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
+
+ if (Pool == NULL) {
+ return Pool;
+ }
+
+ Pool->PciIo = PciIo;
+ Pool->Check4G = Check4G;
+ Pool->Which4G = Which4G;
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ gBS->FreePool (Pool);
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UsbHcUnlinkMemBlock (Pool->Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+ gBS->FreePool (Pool);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+ if (NewBlock == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbHcAllocateMem: failed to allocate block\n"));
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcUnlinkMemBlock (Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h
new file mode 100644
index 000000000..ace20832c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h
@@ -0,0 +1,151 @@
+/** @file
+
+ This file contains the definination for host controller memory management routines.
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_MEM_H_
+#define _EFI_EHCI_MEM_H_
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64) \
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ );
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ );
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/DmaMem.c
new file mode 100644
index 000000000..63870a129
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/DmaMem.c
@@ -0,0 +1,243 @@
+/** @file
+The DMA memory help functions.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EhcPeim.h"
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->Map (
+ IoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, Mapping);
+ *Mapping = NULL;
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuUnmap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN VOID *Mapping
+ )
+{
+ if (IoMmu != NULL) {
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ IoMmu->Unmap (IoMmu, Mapping);
+ }
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ *Mapping = NULL;
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *HostAddress = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, *Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *Mapping = NULL;
+ *HostAddress = NULL;
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *) (UINTN) HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuFreeBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ if (IoMmu != NULL) {
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ IoMmu->Unmap (IoMmu, Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
+ }
+}
+
+/**
+ Initialize IOMMU.
+
+ @param IoMmu Pointer to pointer to IOMMU PPI.
+
+**/
+VOID
+IoMmuInit (
+ OUT EDKII_IOMMU_PPI **IoMmu
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) IoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
new file mode 100644
index 000000000..cd1f87911
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
@@ -0,0 +1,1314 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EhcPeim.h"
+
+//
+// Two arrays used to translate the EHCI port state (change)
+// to the UEFI protocol's port state (change).
+//
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {
+ {PORTSC_CONN, USB_PORT_STAT_CONNECTION},
+ {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},
+ {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},
+ {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},
+ {PORTSC_RESET, USB_PORT_STAT_RESET},
+ {PORTSC_POWER, USB_PORT_STAT_POWER},
+ {PORTSC_OWNER, USB_PORT_STAT_OWNER}
+};
+
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
+ {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},
+ {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},
+ {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
+};
+
+/**
+ Read Ehc Operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset The operation register offset.
+
+ @retval the register content read.
+
+**/
+UINT32
+EhcReadOpReg (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ ASSERT (Ehc->CapLen != 0);
+
+ Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);
+
+ return Data;
+}
+
+/**
+ Write the data to the EHCI operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset EHCI operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+EhcWriteOpReg (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+
+ ASSERT (Ehc->CapLen != 0);
+
+ MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);
+
+}
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+EhcSetOpRegBit (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = EhcReadOpReg (Ehc, Offset);
+ Data |= Bit;
+ EhcWriteOpReg (Ehc, Offset, Data);
+}
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+EhcClearOpRegBit (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = EhcReadOpReg (Ehc, Offset);
+ Data &= ~Bit;
+ EhcWriteOpReg (Ehc, Offset, Data);
+}
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to become set (or clear).
+
+ @param Ehc The EHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EhcWaitOpRegBit (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
+ if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
+ return EFI_SUCCESS;
+ }
+
+ MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Read EHCI capability register.
+
+ @param Ehc The EHCI device.
+ @param Offset Capability register address.
+
+ @retval the register content read.
+
+**/
+UINT32
+EhcReadCapRegister (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset);
+
+ return Data;
+}
+
+/**
+ Set door bell and wait it to be ACKed by host controller.
+ This function is used to synchronize with the hardware.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
+ @retval EFI_SUCCESS Synchronized with the hardware.
+
+**/
+EFI_STATUS
+EhcSetAndWaitDoorBell (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
+
+ //
+ // ACK the IAA bit in USBSTS register. Make sure other
+ // interrupt bits are not ACKed. These bits are WC (Write Clean).
+ //
+ Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
+ Data &= ~USBSTS_INTACK_MASK;
+ Data |= USBSTS_IAA;
+
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
+
+ return Status;
+}
+
+/**
+ Clear all the interrutp status bits, these bits
+ are Write-Clean.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcAckAllInterrupt (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
+}
+
+/**
+ Enable the periodic schedule then wait EHC to
+ actually enable it.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.
+ @retval EFI_SUCCESS The periodical schedule is enabled.
+
+**/
+EFI_STATUS
+EhcEnablePeriodSchd (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
+ return Status;
+}
+
+/**
+ Enable asynchrounous schedule.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.
+ @retval Others Failed to enable the asynchronous scheudle.
+
+**/
+EFI_STATUS
+EhcEnableAsyncSchd (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
+
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
+ return Status;
+}
+
+/**
+ Check whether Ehc is halted.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE The controller isn't halted.
+
+**/
+BOOLEAN
+EhcIsHalt (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
+}
+
+/**
+ Check whether system error occurred.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+EhcIsSysError (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
+}
+
+/**
+ Reset the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval Others Failed to reset the host.
+
+**/
+EFI_STATUS
+EhcResetHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Host can only be reset when it is halt. If not so, halt it
+ //
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
+ Status = EhcHaltHC (Ehc, Timeout);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
+ return Status;
+}
+
+/**
+ Halt the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
+ @retval EFI_SUCCESS The EHCI is halt.
+
+**/
+EFI_STATUS
+EhcHaltHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
+ return Status;
+}
+
+/**
+ Set the EHCI to run.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI is running.
+ @retval Others Failed to set the EHCI to run.
+
+**/
+EFI_STATUS
+EhcRunHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
+ return Status;
+}
+
+/**
+ Power On All EHCI Ports.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcPowerOnAllPorts (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ UINT8 PortNumber;
+ UINT8 Index;
+ UINT32 RegVal;
+
+ PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
+ for (Index = 0; Index < PortNumber; Index++) {
+ //
+ // Do not clear port status bits on initialization. Otherwise devices will
+ // not enumerate properly at startup.
+ //
+ RegVal = EhcReadOpReg(Ehc, EHC_PORT_STAT_OFFSET + 4 * Index);
+ RegVal &= ~PORTSC_CHANGE_MASK;
+ RegVal |= PORTSC_POWER;
+ EhcWriteOpReg (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, RegVal);
+ }
+}
+
+/**
+ Initialize the HC hardware.
+ EHCI spec lists the five things to do to initialize the hardware.
+ 1. Program CTRLDSSEGMENT.
+ 2. Set USBINTR to enable interrupts.
+ 3. Set periodic list base.
+ 4. Set USBCMD, interrupt threshold, frame list size etc.
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI.
+
+ @param Ehc The EHCI device.
+
+ @retval EFI_SUCCESS The EHCI has come out of halt state.
+ @retval EFI_TIMEOUT Time out happened.
+
+**/
+EFI_STATUS
+EhcInitHC (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ UINTN PageNumber;
+
+ ASSERT (EhcIsHalt (Ehc));
+
+ //
+ // Allocate the periodic frame and associated memeory
+ // management facilities if not already done.
+ //
+ if (Ehc->PeriodFrame != NULL) {
+ EhcFreeSched (Ehc);
+ }
+ PageNumber = sizeof(PEI_URB)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+ Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);
+ if (Ehc->Urb == NULL) {
+ return Status;
+ }
+
+ EhcPowerOnAllPorts (Ehc);
+ MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
+
+ Status = EhcInitSched (Ehc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
+ //
+ EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
+
+ //
+ // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
+ //
+ EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
+
+ //
+ // 3. Program periodic frame list, already done in EhcInitSched
+ // 4. Start the Host Controller
+ //
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
+
+ //
+ // 5. Set all ports routing to EHC
+ //
+ EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
+
+ //
+ // Wait roothub port power stable
+ //
+ MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
+
+ Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param DeviceSpeed Device speed, Low speed device doesn't support
+ bulk transfer.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+ PEI_URB *Urb;
+ EFI_STATUS Status;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ EhcAckAllInterrupt (Ehc);
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = EhcCreateUrb (
+ Ehc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ *DataToggle,
+ MaximumPacketLength,
+ Translator,
+ EHC_BULK_TRANSFER,
+ NULL,
+ Data[0],
+ *DataLength,
+ NULL,
+ NULL,
+ 1
+ );
+
+ if (Urb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EhcLinkQhToAsync (Ehc, Urb->Qh);
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+ *DataToggle = Urb->DataToggle;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+ EhcFreeUrb (Ehc, Urb);
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ )
+{
+
+ PEI_USB2_HC_DEV *EhcDev;
+ EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
+
+ if (PortNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
+ State = EhcReadOpReg (Ehc, Offset);
+ State &= ~PORTSC_CHANGE_MASK;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Clear PORT_ENABLE feature means disable port.
+ //
+ State &= ~PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ //
+ // A write of zero to this bit is ignored by the host
+ // controller. The host controller will unconditionally
+ // set this bit to a zero when:
+ // 1. software sets the Forct Port Resume bit to a zero from a one.
+ // 2. software sets the Port Reset bit to a one frome a zero.
+ //
+ State &= ~PORSTSC_RESUME;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // Clear PORT_RESET means clear the reset signal.
+ //
+ State &= ~PORTSC_RESET;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // Clear port owner means this port owned by EHC
+ //
+ State &= ~PORTSC_OWNER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortConnectChange:
+ //
+ // Clear connect status change
+ //
+ State |= PORTSC_CONN_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortEnableChange:
+ //
+ // Clear enable status change
+ //
+ State |= PORTSC_ENABLE_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ //
+ // Clear PortOverCurrent change
+ //
+ State |= PORTSC_OVERCUR_CHANGE;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortPower:
+ case EfiUsbPortSuspendChange:
+ case EfiUsbPortResetChange:
+ //
+ // Not supported or not related operation
+ //
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
+ State = EhcReadOpReg (Ehc, Offset);
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bit
+ //
+ State &= ~PORTSC_CHANGE_MASK;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Sofeware can't set this bit, Port can only be enable by
+ // EHCI as a part of the reset and enable
+ //
+ State |= PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= PORTSC_SUSPEND;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // Make sure Host Controller not halt before reset it
+ //
+ if (EhcIsHalt (Ehc)) {
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Set one to PortReset bit must also set zero to PortEnable bit
+ //
+ State |= PORTSC_RESET;
+ State &= ~PORTSC_ENABLED;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // Not supported, ignore the operation
+ //
+ Status = EFI_SUCCESS;
+ break;
+
+ case EfiUsbPortOwner:
+ State |= PORTSC_OWNER;
+ EhcWriteOpReg (Ehc, Offset, State);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ UINTN Index;
+ UINTN MapSize;
+ EFI_STATUS Status;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ State = EhcReadOpReg (Ehc, Offset);
+
+ //
+ // Identify device speed. If in K state, it is low speed.
+ // If the port is enabled after reset, the device is of
+ // high speed. The USB bus driver should retrieve the actual
+ // port speed after reset.
+ //
+ if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+
+ } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ }
+
+ //
+ // Convert the EHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
+ }
+ }
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+ PEI_URB *Urb;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+
+ //
+ // Validate parameters
+ //
+ if ((Request == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbDataIn) &&
+ (TransferDirection != EfiUsbDataOut) &&
+ (TransferDirection != EfiUsbNoData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection == EfiUsbNoData) &&
+ ((Data != NULL) || (*DataLength != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) &&
+ ((Data == NULL) || (*DataLength == 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
+
+ Status = EFI_DEVICE_ERROR;
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ EhcAckAllInterrupt (Ehc);
+ goto ON_EXIT;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ //
+ // Encode the direction in address, although default control
+ // endpoint is bidirectional. EhcCreateUrb expects this
+ // combination of Ep addr and its direction.
+ //
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
+ Urb = EhcCreateUrb (
+ Ehc,
+ DeviceAddress,
+ Endpoint,
+ DeviceSpeed,
+ 0,
+ MaximumPacketLength,
+ Translator,
+ EHC_CTRL_TRANSFER,
+ Request,
+ Data,
+ *DataLength,
+ NULL,
+ NULL,
+ 1
+ );
+
+ if (Urb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EhcLinkQhToAsync (Ehc, Urb->Qh);
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
+
+ //
+ // Get the status from URB. The result is updated in EhcCheckUrbResult
+ // which is called by EhcExecTransfer
+ //
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ EhcAckAllInterrupt (Ehc);
+ EhcFreeUrb (Ehc, Urb);
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ One notified function to stop the Host Controller at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+ @retval others
+**/
+EFI_STATUS
+EFIAPI
+EhcEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_USB2_HC_DEV *Ehc;
+
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
+
+ EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
+
+ EhcFreeSched (Ehc);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+EhcPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINTN ControllerType;
+ UINTN BaseAddress;
+ UINTN MemPages;
+ PEI_USB2_HC_DEV *EhcDev;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &ChipSetUsbControllerPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Index = 0;
+ while (TRUE) {
+ Status = ChipSetUsbControllerPpi->GetUsbController (
+ (EFI_PEI_SERVICES **) PeiServices,
+ ChipSetUsbControllerPpi,
+ Index,
+ &ControllerType,
+ &BaseAddress
+ );
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // This PEIM is for UHC type controller.
+ //
+ if (ControllerType != PEI_EHCI_CONTROLLER) {
+ Index++;
+ continue;
+ }
+
+ MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
+ EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);
+
+ EhcDev->Signature = USB2_HC_DEV_SIGNATURE;
+
+ IoMmuInit (&EhcDev->IoMmu);
+
+ EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
+
+
+ EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);
+ EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);
+ EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;
+ //
+ // Initialize Uhc's hardware
+ //
+ Status = InitializeUsbHC (EhcDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer;
+ EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer;
+ EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber;
+ EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus;
+ EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature;
+ EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
+
+ EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
+ EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;
+
+ Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ Index++;
+ continue;
+ }
+
+ EhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ EhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
+ EhcDev->EndOfPeiNotifyList.Notify = EhcEndOfPei;
+
+ PeiServicesNotifyPpi (&EhcDev->EndOfPeiNotifyList);
+
+ Index++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @param EhcDev EHCI Device.
+
+ @retval EFI_SUCCESS EHCI successfully initialized.
+ @retval EFI_ABORTED EHCI was failed to be initialized.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN PEI_USB2_HC_DEV *EhcDev
+ )
+{
+ EFI_STATUS Status;
+
+
+ EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);
+
+ Status = EhcInitHC (EhcDev);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h
new file mode 100644
index 000000000..8e5b6418e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h
@@ -0,0 +1,316 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RECOVERY_EHC_H_
+#define _RECOVERY_EHC_H_
+
+#include <PiPei.h>
+
+#include <Ppi/UsbController.h>
+#include <Ppi/Usb2HostController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+
+typedef struct _PEI_USB2_HC_DEV PEI_USB2_HC_DEV;
+
+#define EFI_LIST_ENTRY LIST_ENTRY
+
+#include "UsbHcMem.h"
+#include "EhciReg.h"
+#include "EhciUrb.h"
+#include "EhciSched.h"
+
+#define EFI_USB_SPEED_FULL 0x0000
+#define EFI_USB_SPEED_LOW 0x0001
+#define EFI_USB_SPEED_HIGH 0x0002
+
+#define PAGESIZE 4096
+
+#define EHC_1_MICROSECOND 1
+#define EHC_1_MILLISECOND (1000 * EHC_1_MICROSECOND)
+#define EHC_1_SECOND (1000 * EHC_1_MILLISECOND)
+
+//
+// EHCI register operation timeout, set by experience
+//
+#define EHC_RESET_TIMEOUT (1 * EHC_1_SECOND)
+#define EHC_GENERIC_TIMEOUT (10 * EHC_1_MILLISECOND)
+
+
+//
+// Wait for roothub port power stable, refers to Spec[EHCI1.0-2.3.9]
+//
+#define EHC_ROOT_PORT_RECOVERY_STALL (20 * EHC_1_MILLISECOND)
+
+//
+// Sync transfer polling interval, set by experience.
+//
+#define EHC_SYNC_POLL_INTERVAL (6 * EHC_1_MILLISECOND)
+
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)
+
+
+#define EHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))
+#define EHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \
+ (EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))
+
+#define USB2_HC_DEV_SIGNATURE SIGNATURE_32 ('e', 'h', 'c', 'i')
+
+struct _PEI_USB2_HC_DEV {
+ UINTN Signature;
+ PEI_USB2_HOST_CONTROLLER_PPI Usb2HostControllerPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ //
+ // EndOfPei callback is used to stop the EHC DMA operation
+ // after exit PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+ UINT32 UsbHostControllerBaseAddress;
+ PEI_URB *Urb;
+ USBHC_MEM_POOL *MemPool;
+
+ //
+ // Schedule data shared between asynchronous and periodic
+ // transfers:
+ // ShortReadStop, as its name indicates, is used to terminate
+ // the short read except the control transfer. EHCI follows
+ // the alternative next QTD point when a short read happens.
+ // For control transfer, even the short read happens, try the
+ // status stage.
+ //
+ PEI_EHC_QTD *ShortReadStop;
+ EFI_EVENT PollTimer;
+
+ //
+ // Asynchronous(bulk and control) transfer schedule data:
+ // ReclaimHead is used as the head of the asynchronous transfer
+ // list. It acts as the reclamation header.
+ //
+ PEI_EHC_QH *ReclaimHead;
+
+ //
+ // Periodic (interrupt) transfer schedule data:
+ //
+ VOID *PeriodFrame; // Mapped as common buffer
+ VOID *PeriodFrameMap;
+
+ PEI_EHC_QH *PeriodOne;
+ EFI_LIST_ENTRY AsyncIntTransfers;
+
+ //
+ // EHCI configuration data
+ //
+ UINT32 HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET
+ UINT32 HcCapParams; // Cache of HC capability parameter, HCCPARAMS
+ UINT32 CapLen; // Capability length
+ UINT32 High32bitAddr;
+};
+
+#define PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(a) CR (a, PEI_USB2_HC_DEV, Usb2HostControllerPpi, USB2_HC_DEV_SIGNATURE)
+#define PEI_RECOVERY_USB_EHC_DEV_FROM_THIS_NOTIFY(a) CR (a, PEI_USB2_HC_DEV, EndOfPeiNotifyList, USB2_HC_DEV_SIGNATURE)
+
+/**
+ @param EhcDev EHCI Device.
+
+ @retval EFI_SUCCESS EHCI successfully initialized.
+ @retval EFI_ABORTED EHCI was failed to be initialized.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN PEI_USB2_HC_DEV *EhcDev
+ );
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Ehc The EHCI device.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+;
+
+/**
+ Release the memory management pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool
+ )
+;
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Ehc The EHCI device.
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+;
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuUnmap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuFreeBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ Initialize IOMMU.
+
+ @param IoMmu Pointer to pointer to IOMMU PPI.
+
+**/
+VOID
+IoMmuInit (
+ OUT EDKII_IOMMU_PPI **IoMmu
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf
new file mode 100644
index 000000000..01ebb371a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf
@@ -0,0 +1,67 @@
+## @file
+# The EhcPeim driver is responsible for managing EHCI host controller at PEI phase.
+#
+# It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+# which is used to enable recovery function from USB Drivers.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EhciPei
+ MODULE_UNI_FILE = EhciPei.uni
+ FILE_GUID = BAB4F20F-0981-4b5f-A047-6EF83BEEAB3C
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = EhcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ EhcPeim.c
+ EhcPeim.h
+ EhciUrb.c
+ EhciSched.c
+ UsbHcMem.c
+ EhciReg.h
+ EhciSched.h
+ EhciUrb.h
+ UsbHcMem.h
+ DmaMem.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+
+
+[Ppis]
+ gPeiUsb2HostControllerPpiGuid ## PRODUCES
+ gPeiUsbControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EhciPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.uni
new file mode 100644
index 000000000..798a8cc01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The EhcPeim driver is responsible for managing EHCI host controller at PEI phase.
+//
+// It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+// which is used to enable recovery function from USB Drivers.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing EHCI host controllers at the PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid, which is used to enable recovery function from USB Drivers."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPeiExtra.uni
new file mode 100644
index 000000000..cf53e8057
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EhciPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EHCI PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h
new file mode 100644
index 000000000..98113519a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h
@@ -0,0 +1,303 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_REG_H_
+#define _EFI_EHCI_REG_H_
+
+
+
+//
+// Capability register offset
+//
+#define EHC_CAPLENGTH_OFFSET 0 // Capability register length offset
+#define EHC_HCSPARAMS_OFFSET 0x04 // Structural Parameters 04-07h
+#define EHC_HCCPARAMS_OFFSET 0x08 // Capability parameters offset
+
+//
+// Capability register bit definition
+//
+#define HCSP_NPORTS 0x0F // Number of root hub port
+#define HCCP_64BIT 0x01 // 64-bit addressing capability
+
+//
+// Operational register offset
+//
+#define EHC_USBCMD_OFFSET 0x0 // USB command register offset
+#define EHC_USBSTS_OFFSET 0x04 // Statue register offset
+#define EHC_USBINTR_OFFSET 0x08 // USB interrutp offset
+#define EHC_FRINDEX_OFFSET 0x0C // Frame index offset
+#define EHC_CTRLDSSEG_OFFSET 0x10 // Control data structure segment offset
+#define EHC_FRAME_BASE_OFFSET 0x14 // Frame list base address offset
+#define EHC_ASYNC_HEAD_OFFSET 0x18 // Next asynchronous list address offset
+#define EHC_CONFIG_FLAG_OFFSET 0x40 // Configure flag register offset
+#define EHC_PORT_STAT_OFFSET 0x44 // Port status/control offset
+
+#define EHC_FRAME_LEN 1024
+
+//
+// Register bit definition
+//
+#define CONFIGFLAG_ROUTE_EHC 0x01 // Route port to EHC
+
+#define USBCMD_RUN 0x01 // Run/stop
+#define USBCMD_RESET 0x02 // Start the host controller reset
+#define USBCMD_ENABLE_PERIOD 0x10 // Enable periodic schedule
+#define USBCMD_ENABLE_ASYNC 0x20 // Enable asynchronous schedule
+#define USBCMD_IAAD 0x40 // Interrupt on async advance doorbell
+
+#define USBSTS_IAA 0x20 // Interrupt on async advance
+#define USBSTS_PERIOD_ENABLED 0x4000 // Periodic schedule status
+#define USBSTS_ASYNC_ENABLED 0x8000 // Asynchronous schedule status
+#define USBSTS_HALT 0x1000 // Host controller halted
+#define USBSTS_SYS_ERROR 0x10 // Host system error
+#define USBSTS_INTACK_MASK 0x003F // Mask for the interrupt ACK, the WC
+ // (write clean) bits in USBSTS register
+
+#define PORTSC_CONN 0x01 // Current Connect Status
+#define PORTSC_CONN_CHANGE 0x02 // Connect Status Change
+#define PORTSC_ENABLED 0x04 // Port Enable / Disable
+#define PORTSC_ENABLE_CHANGE 0x08 // Port Enable / Disable Change
+#define PORTSC_OVERCUR 0x10 // Over current Active
+#define PORTSC_OVERCUR_CHANGE 0x20 // Over current Change
+#define PORSTSC_RESUME 0x40 // Force Port Resume
+#define PORTSC_SUSPEND 0x80 // Port Suspend State
+#define PORTSC_RESET 0x100 // Port Reset
+#define PORTSC_LINESTATE_K 0x400 // Line Status K-state
+#define PORTSC_LINESTATE_J 0x800 // Line Status J-state
+#define PORTSC_POWER 0x1000 // Port Power
+#define PORTSC_OWNER 0x2000 // Port Owner
+#define PORTSC_CHANGE_MASK 0x2A // Mask of the port change bits,
+ // they are WC (write clean)
+//
+// PCI Configuration Registers
+//
+#define EHC_BAR_INDEX 0 // how many bytes away from USB_BASE to 0x10
+
+#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)
+
+#define EHC_ADDR(High, QhHw32) \
+ ((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))
+
+#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)
+
+//
+// Structure to map the hardware port states to the
+// UEFI's port states.
+//
+typedef struct {
+ UINT16 HwState;
+ UINT16 UefiState;
+} USB_PORT_STATE_MAP;
+
+//
+// Ehci Data and Ctrl Structures
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Pi;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+#pragma pack()
+
+
+/**
+ Read EHCI capability register.
+
+ @param Ehc The EHCI device.
+ @param Offset Capability register address.
+
+ @retval the register content read.
+
+**/
+UINT32
+EhcReadCapRegister (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+;
+
+/**
+ Read Ehc Operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset The operation register offset.
+
+ @retval the register content read.
+
+**/
+UINT32
+EhcReadOpReg (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset
+ )
+;
+
+/**
+ Write the data to the EHCI operation register.
+
+ @param Ehc The EHCI device.
+ @param Offset EHCI operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+EhcWriteOpReg (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+;
+
+/**
+ Stop the legacy USB SMI support.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcClearLegacySupport (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Set door bell and wait it to be ACKed by host controller.
+ This function is used to synchronize with the hardware.
+
+ @param Ehc The EHCI device.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.
+ @retval EFI_SUCCESS Synchronized with the hardware.
+
+**/
+EFI_STATUS
+EhcSetAndWaitDoorBell (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+;
+
+/**
+ Clear all the interrutp status bits, these bits
+ are Write-Clean.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcAckAllInterrupt (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Check whether Ehc is halted.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE The controller isn't halted.
+
+**/
+BOOLEAN
+EhcIsHalt (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Check whether system error occurred.
+
+ @param Ehc The EHCI device.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+EhcIsSysError (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Reset the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval Others Failed to reset the host.
+
+**/
+EFI_STATUS
+EhcResetHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+;
+
+/**
+ Halt the host controller.
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
+ @retval EFI_SUCCESS The EHCI is halt.
+
+**/
+EFI_STATUS
+EhcHaltHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+;
+
+/**
+ Set the EHCI to run
+
+ @param Ehc The EHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The EHCI is running.
+ @retval Others Failed to set the EHCI to run.
+
+**/
+EFI_STATUS
+EhcRunHC (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT32 Timeout
+ )
+;
+
+/**
+ Initialize the HC hardware.
+ EHCI spec lists the five things to do to initialize the hardware.
+ 1. Program CTRLDSSEGMENT.
+ 2. Set USBINTR to enable interrupts.
+ 3. Set periodic list base.
+ 4. Set USBCMD, interrupt threshold, frame list size etc.
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI.
+
+ @param Ehc The EHCI device.
+
+ @retval EFI_SUCCESS The EHCI has come out of halt state.
+ @retval EFI_TIMEOUT Time out happened.
+
+**/
+EFI_STATUS
+EhcInitHC (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c
new file mode 100644
index 000000000..311f50198
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c
@@ -0,0 +1,463 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EhcPeim.h"
+
+/**
+ Create helper QTD/QH for the EHCI device.
+
+ @param Ehc The EHCI device.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH.
+ @retval EFI_SUCCESS Helper QH/QTD are created.
+
+**/
+EFI_STATUS
+EhcCreateHelpQ (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ USB_ENDPOINT Ep;
+ PEI_EHC_QH *Qh;
+ QH_HW *QhHw;
+ PEI_EHC_QTD *Qtd;
+
+ //
+ // Create an inactive Qtd to terminate the short packet read.
+ //
+ Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);
+
+ if (Qtd == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Qtd->QtdHw.Status = QTD_STAT_HALTED;
+ Ehc->ShortReadStop = Qtd;
+
+ //
+ // Create a QH to act as the EHC reclamation header.
+ // Set the header to loopback to itself.
+ //
+ Ep.DevAddr = 0;
+ Ep.EpAddr = 1;
+ Ep.Direction = EfiUsbDataIn;
+ Ep.DevSpeed = EFI_USB_SPEED_HIGH;
+ Ep.MaxPacket = 64;
+ Ep.HubAddr = 0;
+ Ep.HubPort = 0;
+ Ep.Toggle = 0;
+ Ep.Type = EHC_BULK_TRANSFER;
+ Ep.PollRate = 1;
+
+ Qh = EhcCreateQh (Ehc, &Ep);
+
+ if (Qh == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ QhHw = &Qh->QhHw;
+ QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);
+ QhHw->Status = QTD_STAT_HALTED;
+ QhHw->ReclaimHead = 1;
+ Ehc->ReclaimHead = Qh;
+
+ //
+ // Create a dummy QH to act as the terminator for periodical schedule
+ //
+ Ep.EpAddr = 2;
+ Ep.Type = EHC_INT_TRANSFER_SYNC;
+
+ Qh = EhcCreateQh (Ehc, &Ep);
+
+ if (Qh == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Qh->QhHw.Status = QTD_STAT_HALTED;
+ Ehc->PeriodOne = Qh;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the schedule data structure such as frame list.
+
+ @param Ehc The EHCI device to init schedule data for.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.
+ @retval EFI_SUCCESS The schedule data is initialized.
+
+**/
+EFI_STATUS
+EhcInitSched (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ UINTN Index;
+ UINT32 *Desc;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PciAddr;
+
+ //
+ // First initialize the periodical schedule data:
+ // 1. Allocate and map the memory for the frame list
+ // 2. Create the help QTD/QH
+ // 3. Initialize the frame entries
+ // 4. Set the frame list register
+ //
+ //
+ // The Frame List ocupies 4K bytes,
+ // and must be aligned on 4-Kbyte boundaries.
+ //
+ Status = IoMmuAllocateBuffer (
+ Ehc->IoMmu,
+ 1,
+ &Buf,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (Buf == NULL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ehc->PeriodFrame = Buf;
+ Ehc->PeriodFrameMap = Map;
+ Ehc->High32bitAddr = EHC_HIGH_32BIT (PhyAddr);
+
+ //
+ // Init memory pool management then create the helper
+ // QTD/QH. If failed, previously allocated resources
+ // will be freed by EhcFreeSched
+ //
+ Ehc->MemPool = UsbHcInitMemPool (
+ Ehc,
+ EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),
+ Ehc->High32bitAddr
+ );
+
+ if (Ehc->MemPool == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EhcCreateHelpQ (Ehc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize the frame list entries then set the registers
+ //
+ Desc = (UINT32 *) Ehc->PeriodFrame;
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (PEI_EHC_QH));
+ for (Index = 0; Index < EHC_FRAME_LEN; Index++) {
+ Desc[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
+ }
+
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr));
+
+ //
+ // Second initialize the asynchronous schedule:
+ // Only need to set the AsynListAddr register to
+ // the reclamation header
+ //
+ PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (PEI_EHC_QH));
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr));
+ return EFI_SUCCESS;
+}
+
+/**
+ Free the schedule data. It may be partially initialized.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcFreeSched (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+{
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);
+
+ if (Ehc->PeriodOne != NULL) {
+ UsbHcFreeMem (Ehc, Ehc->MemPool, Ehc->PeriodOne, sizeof (PEI_EHC_QH));
+ Ehc->PeriodOne = NULL;
+ }
+
+ if (Ehc->ReclaimHead != NULL) {
+ UsbHcFreeMem (Ehc, Ehc->MemPool, Ehc->ReclaimHead, sizeof (PEI_EHC_QH));
+ Ehc->ReclaimHead = NULL;
+ }
+
+ if (Ehc->ShortReadStop != NULL) {
+ UsbHcFreeMem (Ehc, Ehc->MemPool, Ehc->ShortReadStop, sizeof (PEI_EHC_QTD));
+ Ehc->ShortReadStop = NULL;
+ }
+
+ if (Ehc->MemPool != NULL) {
+ UsbHcFreeMemPool (Ehc, Ehc->MemPool);
+ Ehc->MemPool = NULL;
+ }
+
+ if (Ehc->PeriodFrame != NULL) {
+ IoMmuFreeBuffer (Ehc->IoMmu, 1, Ehc->PeriodFrame, Ehc->PeriodFrameMap);
+ Ehc->PeriodFrame = NULL;
+ }
+}
+
+/**
+ Link the queue head to the asynchronous schedule list.
+ UEFI only supports one CTRL/BULK transfer at a time
+ due to its interfaces. This simplifies the AsynList
+ management: A reclamation header is always linked to
+ the AsyncListAddr, the only active QH is appended to it.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToAsync (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_EHC_QH *Qh
+ )
+{
+ PEI_EHC_QH *Head;
+
+ //
+ // Append the queue head after the reclaim header, then
+ // fix the hardware visiable parts (EHCI R1.0 page 72).
+ // ReclaimHead is always linked to the EHCI's AsynListAddr.
+ //
+ Head = Ehc->ReclaimHead;
+
+ Qh->NextQh = Head->NextQh;
+ Head->NextQh = Qh;
+
+ Qh->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);;
+ Head->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);
+}
+
+/**
+ Unlink a queue head from the asynchronous schedule list.
+ Need to synchronize with hardware.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromAsync (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_EHC_QH *Qh
+ )
+{
+ PEI_EHC_QH *Head;
+
+ ASSERT (Ehc->ReclaimHead->NextQh == Qh);
+
+ //
+ // Remove the QH from reclamation head, then update the hardware
+ // visiable part: Only need to loopback the ReclaimHead. The Qh
+ // is pointing to ReclaimHead (which is staill in the list).
+ //
+ Head = Ehc->ReclaimHead;
+
+ Head->NextQh = Qh->NextQh;
+ Qh->NextQh = NULL;
+
+ Head->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);
+
+ //
+ // Set and wait the door bell to synchronize with the hardware
+ //
+ EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);
+
+ return;
+}
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to check result.
+
+ @retval TRUE URB transfer is finialized.
+ @retval FALSE URB transfer is not finialized.
+
+**/
+BOOLEAN
+EhcCheckUrbResult (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb
+ )
+{
+ EFI_LIST_ENTRY *Entry;
+ PEI_EHC_QTD *Qtd;
+ QTD_HW *QtdHw;
+ UINT8 State;
+ BOOLEAN Finished;
+
+ ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));
+
+ Finished = TRUE;
+ Urb->Completed = 0;
+
+ Urb->Result = EFI_USB_NOERROR;
+
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
+ Urb->Result |= EFI_USB_ERR_SYSTEM;
+ goto ON_EXIT;
+ }
+
+ BASE_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
+ QtdHw = &Qtd->QtdHw;
+ State = (UINT8) QtdHw->Status;
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
+ //
+ // EHCI will halt the queue head when met some error.
+ // If it is halted, the result of URB is finialized.
+ //
+ if ((State & QTD_STAT_ERR_MASK) == 0) {
+ Urb->Result |= EFI_USB_ERR_STALL;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
+ Urb->Result |= EFI_USB_ERR_BABBLE;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
+ Urb->Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ Finished = TRUE;
+ goto ON_EXIT;
+
+ } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
+ //
+ // The QTD is still active, no need to check furthur.
+ //
+ Urb->Result |= EFI_USB_ERR_NOTEXECUTE;
+
+ Finished = FALSE;
+ goto ON_EXIT;
+
+ } else {
+ //
+ // This QTD is finished OK or met short packet read. Update the
+ // transfer length if it isn't a setup.
+ //
+ if (QtdHw->Pid != QTD_PID_SETUP) {
+ Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;
+ }
+
+ if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {
+ //EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));
+
+ //
+ // Short packet read condition. If it isn't a setup transfer,
+ // no need to check furthur: the queue head will halt at the
+ // ShortReadStop. If it is a setup transfer, need to check the
+ // Status Stage of the setup transfer to get the finial result
+ //
+ if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {
+
+ Finished = TRUE;
+ goto ON_EXIT;
+ }
+ }
+ }
+ }
+
+ON_EXIT:
+ //
+ // Return the data toggle set by EHCI hardware, bulk and interrupt
+ // transfer will use this to initialize the next transaction. For
+ // Control transfer, it always start a new data toggle sequence for
+ // new transfer.
+ //
+ // NOTICE: don't move DT update before the loop, otherwise there is
+ // a race condition that DT is wrong.
+ //
+ Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;
+
+ return Finished;
+}
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to execute.
+ @param TimeOut The time to wait before abort, in millisecond.
+
+ @retval EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+EhcExecTransfer (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb,
+ IN UINTN TimeOut
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Loop;
+ BOOLEAN Finished;
+ BOOLEAN InfiniteLoop;
+
+ Status = EFI_SUCCESS;
+ Loop = TimeOut * EHC_1_MILLISECOND;
+ Finished = FALSE;
+ InfiniteLoop = FALSE;
+
+ //
+ // If Timeout is 0, then the caller must wait for the function to be completed
+ // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ //
+ if (TimeOut == 0) {
+ InfiniteLoop = TRUE;
+ }
+
+ for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {
+ Finished = EhcCheckUrbResult (Ehc, Urb);
+
+ if (Finished) {
+ break;
+ }
+
+ MicroSecondDelay (EHC_1_MICROSECOND);
+ }
+
+ if (!Finished) {
+ Status = EFI_TIMEOUT;
+ } else if (Urb->Result != EFI_USB_NOERROR) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h
new file mode 100644
index 000000000..60f8cb815
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h
@@ -0,0 +1,93 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_SCHED_H_
+#define _EFI_EHCI_SCHED_H_
+
+/**
+ Initialize the schedule data structure such as frame list.
+
+ @param Ehc The EHCI device to init schedule data for.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.
+ @retval EFI_SUCCESS The schedule data is initialized.
+
+**/
+EFI_STATUS
+EhcInitSched (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Free the schedule data. It may be partially initialized.
+
+ @param Ehc The EHCI device.
+
+**/
+VOID
+EhcFreeSched (
+ IN PEI_USB2_HC_DEV *Ehc
+ )
+;
+
+/**
+ Link the queue head to the asynchronous schedule list.
+ UEFI only supports one CTRL/BULK transfer at a time
+ due to its interfaces. This simplifies the AsynList
+ management: A reclamation header is always linked to
+ the AsyncListAddr, the only active QH is appended to it.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to link.
+
+**/
+VOID
+EhcLinkQhToAsync (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_EHC_QH *Qh
+ )
+;
+
+/**
+ Unlink a queue head from the asynchronous schedule list.
+ Need to synchronize with hardware.
+
+ @param Ehc The EHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+EhcUnlinkQhFromAsync (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_EHC_QH *Qh
+ )
+;
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to execute.
+ @param TimeOut The time to wait before abort, in millisecond.
+
+ @retval EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+EhcExecTransfer (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb,
+ IN UINTN TimeOut
+ )
+;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c
new file mode 100644
index 000000000..df512ed6f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c
@@ -0,0 +1,627 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EhcPeim.h"
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param Data Current data not associated with a QTD.
+ @param DataLen The length of the data.
+ @param PktId Packet ID to use in the QTD.
+ @param Toggle Data toggle to use in the QTD.
+ @param MaxPacket Maximu packet length of the endpoint.
+
+ @retval the pointer to the created QTD or NULL if failed to create one.
+
+**/
+PEI_EHC_QTD *
+EhcCreateQtd (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT8 *Data,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket
+ )
+{
+ PEI_EHC_QTD *Qtd;
+ QTD_HW *QtdHw;
+ UINTN Index;
+ UINTN Len;
+ UINTN ThisBufLen;
+
+ ASSERT (Ehc != NULL);
+
+ Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD));
+
+ if (Qtd == NULL) {
+ return NULL;
+ }
+
+ Qtd->Signature = EHC_QTD_SIG;
+ Qtd->Data = Data;
+ Qtd->DataLen = 0;
+
+ InitializeListHead (&Qtd->QtdList);
+
+ QtdHw = &Qtd->QtdHw;
+ QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
+ QtdHw->AltNext = QTD_LINK (NULL, TRUE);
+ QtdHw->Status = QTD_STAT_ACTIVE;
+ QtdHw->Pid = PktId;
+ QtdHw->ErrCnt = QTD_MAX_ERR;
+ QtdHw->Ioc = 0;
+ QtdHw->TotalBytes = 0;
+ QtdHw->DataToggle = Toggle;
+
+ //
+ // Fill in the buffer points
+ //
+ if (Data != NULL) {
+ Len = 0;
+
+ for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
+ //
+ // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
+ // compute the offset and clear Reserved fields. This is already
+ // done in the data point.
+ //
+ QtdHw->Page[Index] = EHC_LOW_32BIT (Data);
+ QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);
+
+ ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);
+
+ if (Len + ThisBufLen >= DataLen) {
+ Len = DataLen;
+ break;
+ }
+
+ Len += ThisBufLen;
+ Data += ThisBufLen;
+ }
+
+ //
+ // Need to fix the last pointer if the Qtd can't hold all the
+ // user's data to make sure that the length is in the unit of
+ // max packets. If it can hold all the data, there is no such
+ // need.
+ //
+ if (Len < DataLen) {
+ Len = Len - Len % MaxPacket;
+ }
+
+ QtdHw->TotalBytes = (UINT32) Len;
+ Qtd->DataLen = Len;
+ }
+
+ return Qtd;
+}
+
+/**
+ Initialize the queue head for interrupt transfer,
+ that is, initialize the following three fields:
+ 1. SplitXState in the Status field.
+ 2. Microframe S-mask.
+ 3. Microframe C-mask.
+
+ @param Ep The queue head's related endpoint.
+ @param QhHw The queue head to initialize.
+
+**/
+VOID
+EhcInitIntQh (
+ IN USB_ENDPOINT *Ep,
+ IN QH_HW *QhHw
+ )
+{
+ //
+ // Because UEFI interface can't utilitize an endpoint with
+ // poll rate faster than 1ms, only need to set one bit in
+ // the queue head. simple. But it may be changed later. If
+ // sub-1ms interrupt is supported, need to update the S-Mask
+ // here
+ //
+ if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
+ QhHw->SMask = QH_MICROFRAME_0;
+ return ;
+ }
+
+ //
+ // For low/full speed device, the transfer must go through
+ // the split transaction. Need to update three fields
+ // 1. SplitXState in the status
+ // 2. Microframe S-Mask
+ // 3. Microframe C-Mask
+ // UEFI USB doesn't exercise admission control. It simplely
+ // schedule the high speed transactions in microframe 0, and
+ // full/low speed transactions at microframe 1. This also
+ // avoid the use of FSTN.
+ //
+ QhHw->SMask = QH_MICROFRAME_1;
+ QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
+}
+
+/**
+ Allocate and initialize a EHCI queue head.
+
+ @param Ehci The EHCI device.
+ @param Ep The endpoint to create queue head for.
+
+ @retval the pointer to the created queue head or NULL if failed to create one.
+
+**/
+PEI_EHC_QH *
+EhcCreateQh (
+ IN PEI_USB2_HC_DEV *Ehci,
+ IN USB_ENDPOINT *Ep
+ )
+{
+ PEI_EHC_QH *Qh;
+ QH_HW *QhHw;
+
+ Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH));
+
+ if (Qh == NULL) {
+ return NULL;
+ }
+
+ Qh->Signature = EHC_QH_SIG;
+ Qh->NextQh = NULL;
+ Qh->Interval = Ep->PollRate;
+
+ InitializeListHead (&Qh->Qtds);
+
+ QhHw = &Qh->QhHw;
+ QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
+ QhHw->DeviceAddr = Ep->DevAddr;
+ QhHw->Inactive = 0;
+ QhHw->EpNum = Ep->EpAddr;
+ QhHw->EpSpeed = Ep->DevSpeed;
+ QhHw->DtCtrl = 0;
+ QhHw->ReclaimHead = 0;
+ QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
+ QhHw->CtrlEp = 0;
+ QhHw->NakReload = QH_NAK_RELOAD;
+ QhHw->HubAddr = Ep->HubAddr;
+ QhHw->PortNum = Ep->HubPort;
+ QhHw->Multiplier = 1;
+ QhHw->DataToggle = Ep->Toggle;
+
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
+ QhHw->Status |= QTD_STAT_DO_SS;
+ }
+
+ switch (Ep->Type) {
+ case EHC_CTRL_TRANSFER:
+ //
+ // Special initialization for the control transfer:
+ // 1. Control transfer initialize data toggle from each QTD
+ // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
+ //
+ QhHw->DtCtrl = 1;
+
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
+ QhHw->CtrlEp = 1;
+ }
+ break;
+
+ case EHC_INT_TRANSFER_ASYNC:
+ case EHC_INT_TRANSFER_SYNC:
+ //
+ // Special initialization for the interrupt transfer
+ // to set the S-Mask and C-Mask
+ //
+ QhHw->NakReload = 0;
+ EhcInitIntQh (Ep, QhHw);
+ break;
+
+ case EHC_BULK_TRANSFER:
+ if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
+ QhHw->Status |= QTD_STAT_DO_PING;
+ }
+
+ break;
+ }
+
+ return Qh;
+}
+
+/**
+ Convert the poll interval from application to that
+ be used by EHCI interface data structure. Only need
+ to get the max 2^n that is less than interval. UEFI
+ can't support high speed endpoint with a interval less
+ than 8 microframe because interval is specified in
+ the unit of ms (millisecond).
+
+ @param Interval The interval to convert.
+
+ @retval The converted interval.
+
+**/
+UINTN
+EhcConvertPollRate (
+ IN UINTN Interval
+ )
+{
+ UINTN BitCount;
+
+ if (Interval == 0) {
+ return 1;
+ }
+
+ //
+ // Find the index (1 based) of the highest non-zero bit
+ //
+ BitCount = 0;
+
+ while (Interval != 0) {
+ Interval >>= 1;
+ BitCount++;
+ }
+
+ return (UINTN)1 << (BitCount - 1);
+}
+
+/**
+ Free a list of QTDs.
+
+ @param Ehc The EHCI device.
+ @param Qtds The list head of the QTD.
+
+**/
+VOID
+EhcFreeQtds (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN EFI_LIST_ENTRY *Qtds
+ )
+{
+ EFI_LIST_ENTRY *Entry;
+ EFI_LIST_ENTRY *Next;
+ PEI_EHC_QTD *Qtd;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
+
+ RemoveEntryList (&Qtd->QtdList);
+ UsbHcFreeMem (Ehc, Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD));
+ }
+}
+
+/**
+ Free an allocated URB. It is possible for it to be partially inited.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+EhcFreeUrb (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb
+ )
+{
+ if (Urb->RequestPhy != NULL) {
+ IoMmuUnmap (Ehc->IoMmu, Urb->RequestMap);
+ }
+
+ if (Urb->DataMap != NULL) {
+ IoMmuUnmap (Ehc->IoMmu, Urb->DataMap);
+ }
+
+ if (Urb->Qh != NULL) {
+ //
+ // Ensure that this queue head has been unlinked from the
+ // schedule data structures. Free all the associated QTDs
+ //
+ EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
+ UsbHcFreeMem (Ehc, Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH));
+ }
+}
+
+/**
+ Create a list of QTDs for the URB.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to create QTDs for.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
+ @retval EFI_SUCCESS The QTDs are allocated for the URB.
+
+**/
+EFI_STATUS
+EhcCreateQtds (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb
+ )
+{
+ USB_ENDPOINT *Ep;
+ PEI_EHC_QH *Qh;
+ PEI_EHC_QTD *Qtd;
+ PEI_EHC_QTD *StatusQtd;
+ PEI_EHC_QTD *NextQtd;
+ EFI_LIST_ENTRY *Entry;
+ UINT32 AlterNext;
+ UINT8 Toggle;
+ UINTN Len;
+ UINT8 Pid;
+
+ ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
+
+ //
+ // EHCI follows the alternet next QTD pointer if it meets
+ // a short read and the AlterNext pointer is valid. UEFI
+ // EHCI driver should terminate the transfer except the
+ // control transfer.
+ //
+ Toggle = 0;
+ Qh = Urb->Qh;
+ Ep = &Urb->Ep;
+ StatusQtd = NULL;
+ AlterNext = QTD_LINK (NULL, TRUE);
+
+ if (Ep->Direction == EfiUsbDataIn) {
+ AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);
+ }
+
+ //
+ // Build the Setup and status packets for control transfer
+ //
+ if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
+
+ if (Qtd == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);
+
+ //
+ // Create the status packet now. Set the AlterNext to it. So, when
+ // EHCI meets a short control read, it can resume at the status stage.
+ // Use the opposite direction of the data stage, or IN if there is
+ // no data stage.
+ //
+ if (Ep->Direction == EfiUsbDataIn) {
+ Pid = QTD_PID_OUTPUT;
+ } else {
+ Pid = QTD_PID_INPUT;
+ }
+
+ StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);
+
+ if (StatusQtd == NULL) {
+ goto ON_ERROR;
+ }
+
+ if (Ep->Direction == EfiUsbDataIn) {
+ AlterNext = QTD_LINK (StatusQtd, FALSE);
+ }
+
+ Toggle = 1;
+ }
+
+ //
+ // Build the data packets for all the transfers
+ //
+ if (Ep->Direction == EfiUsbDataIn) {
+ Pid = QTD_PID_INPUT;
+ } else {
+ Pid = QTD_PID_OUTPUT;
+ }
+
+ Qtd = NULL;
+ Len = 0;
+
+ while (Len < Urb->DataLen) {
+ Qtd = EhcCreateQtd (
+ Ehc,
+ (UINT8 *) Urb->DataPhy + Len,
+ Urb->DataLen - Len,
+ Pid,
+ Toggle,
+ Ep->MaxPacket
+ );
+
+ if (Qtd == NULL) {
+ goto ON_ERROR;
+ }
+
+ Qtd->QtdHw.AltNext = AlterNext;
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);
+
+ //
+ // Switch the Toggle bit if odd number of packets are included in the QTD.
+ //
+ if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
+ Toggle = (UINT8) (1 - Toggle);
+ }
+
+ Len += Qtd->DataLen;
+ }
+
+ //
+ // Insert the status packet for control transfer
+ //
+ if (Ep->Type == EHC_CTRL_TRANSFER) {
+ InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
+ }
+
+ //
+ // OK, all the QTDs needed are created. Now, fix the NextQtd point
+ //
+ BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
+
+ //
+ // break if it is the last entry on the list
+ //
+ if (Entry->ForwardLink == &Qh->Qtds) {
+ break;
+ }
+
+ NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList);
+ Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);
+ }
+
+ //
+ // Link the QTDs to the queue head
+ //
+ NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList);
+ Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ EhcFreeQtds (Ehc, &Qh->Qtds);
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Create a new URB and its associated QTD.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param Type The transaction type.
+ @param Request The standard USB request for control transfer.
+ @param Data The user data to transfer.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @retval the pointer to the created URB or NULL.
+
+**/
+PEI_URB *
+EhcCreateUrb (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ )
+{
+ USB_ENDPOINT *Ep;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ EDKII_IOMMU_OPERATION MapOp;
+ EFI_STATUS Status;
+ UINTN Len;
+ PEI_URB *Urb;
+ VOID *Map;
+
+ Map = NULL;
+
+ Urb = Ehc->Urb;
+ Urb->Signature = EHC_URB_SIG;
+ InitializeListHead (&Urb->UrbList);
+
+ Ep = &Urb->Ep;
+ Ep->DevAddr = DevAddr;
+ Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
+ Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
+ Ep->DevSpeed = DevSpeed;
+ Ep->MaxPacket = MaxPacket;
+
+ Ep->HubAddr = 0;
+ Ep->HubPort = 0;
+
+ if (DevSpeed != EFI_USB_SPEED_HIGH) {
+ ASSERT (Hub != NULL);
+
+ Ep->HubAddr = Hub->TranslatorHubAddress;
+ Ep->HubPort = Hub->TranslatorPortNumber;
+ }
+
+ Ep->Toggle = Toggle;
+ Ep->Type = Type;
+ Ep->PollRate = EhcConvertPollRate (Interval);
+
+ Urb->Request = Request;
+ Urb->Data = Data;
+ Urb->DataLen = DataLen;
+ Urb->Callback = Callback;
+ Urb->Context = Context;
+ Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
+
+ if (Urb->Qh == NULL) {
+ goto ON_ERROR;
+ }
+
+ Urb->RequestPhy = NULL;
+ Urb->RequestMap = NULL;
+ Urb->DataPhy = NULL;
+ Urb->DataMap = NULL;
+
+ //
+ // Map the request and user data
+ //
+ if (Request != NULL) {
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ Status = IoMmuMap (Ehc->IoMmu, MapOp, Request, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
+ goto ON_ERROR;
+ }
+
+ Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->RequestMap = Map;
+ }
+
+ if (Data != NULL) {
+ Len = DataLen;
+
+ if (Ep->Direction == EfiUsbDataIn) {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ Status = IoMmuMap (Ehc->IoMmu, MapOp, Data, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != DataLen)) {
+ goto ON_ERROR;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ }
+
+ Status = EhcCreateQtds (Ehc, Urb);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return Urb;
+
+ON_ERROR:
+ EhcFreeUrb (Ehc, Urb);
+ return NULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h
new file mode 100644
index 000000000..756b663fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h
@@ -0,0 +1,324 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_URB_H_
+#define _EFI_EHCI_URB_H_
+
+typedef struct _PEI_EHC_QTD PEI_EHC_QTD;
+typedef struct _PEI_EHC_QH PEI_EHC_QH;
+typedef struct _PEI_URB PEI_URB;
+
+#define EHC_CTRL_TRANSFER 0x01
+#define EHC_BULK_TRANSFER 0x02
+#define EHC_INT_TRANSFER_SYNC 0x04
+#define EHC_INT_TRANSFER_ASYNC 0x08
+
+#define EHC_QTD_SIG SIGNATURE_32 ('U', 'S', 'B', 'T')
+#define EHC_QH_SIG SIGNATURE_32 ('U', 'S', 'B', 'H')
+#define EHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')
+
+//
+// Hardware related bit definitions
+//
+#define EHC_TYPE_ITD 0x00
+#define EHC_TYPE_QH 0x02
+#define EHC_TYPE_SITD 0x04
+#define EHC_TYPE_FSTN 0x06
+
+#define QH_NAK_RELOAD 3
+#define QH_HSHBW_MULTI 1
+
+#define QTD_MAX_ERR 3
+#define QTD_PID_OUTPUT 0x00
+#define QTD_PID_INPUT 0x01
+#define QTD_PID_SETUP 0x02
+
+#define QTD_STAT_DO_OUT 0
+#define QTD_STAT_DO_SS 0
+#define QTD_STAT_DO_PING 0x01
+#define QTD_STAT_DO_CS 0x02
+#define QTD_STAT_TRANS_ERR 0x08
+#define QTD_STAT_BABBLE_ERR 0x10
+#define QTD_STAT_BUFF_ERR 0x20
+#define QTD_STAT_HALTED 0x40
+#define QTD_STAT_ACTIVE 0x80
+#define QTD_STAT_ERR_MASK (QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR)
+
+#define QTD_MAX_BUFFER 4
+#define QTD_BUF_LEN 4096
+#define QTD_BUF_MASK 0x0FFF
+
+#define QH_MICROFRAME_0 0x01
+#define QH_MICROFRAME_1 0x02
+#define QH_MICROFRAME_2 0x04
+#define QH_MICROFRAME_3 0x08
+#define QH_MICROFRAME_4 0x10
+#define QH_MICROFRAME_5 0x20
+#define QH_MICROFRAME_6 0x40
+#define QH_MICROFRAME_7 0x80
+
+#define USB_ERR_SHORT_PACKET 0x200
+
+//
+// Fill in the hardware link point: pass in a EHC_QH/QH_HW
+// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK
+//
+#define QH_LINK(Addr, Type, Term) \
+ ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))
+
+#define QTD_LINK(Addr, Term) QH_LINK((Addr), 0, (Term))
+
+//
+// The defination of EHCI hardware used data structure for
+// little endian architecture. The QTD and QH structures
+// are required to be 32 bytes aligned. Don't add members
+// to the head of the associated software strucuture.
+//
+#pragma pack(1)
+typedef struct {
+ UINT32 NextQtd;
+ UINT32 AltNext;
+
+ UINT32 Status : 8;
+ UINT32 Pid : 2;
+ UINT32 ErrCnt : 2;
+ UINT32 CurPage : 3;
+ UINT32 Ioc : 1;
+ UINT32 TotalBytes : 15;
+ UINT32 DataToggle : 1;
+
+ UINT32 Page[5];
+ UINT32 PageHigh[5];
+} QTD_HW;
+
+typedef struct {
+ UINT32 HorizonLink;
+ //
+ // Endpoint capabilities/Characteristics DWord 1 and DWord 2
+ //
+ UINT32 DeviceAddr : 7;
+ UINT32 Inactive : 1;
+ UINT32 EpNum : 4;
+ UINT32 EpSpeed : 2;
+ UINT32 DtCtrl : 1;
+ UINT32 ReclaimHead : 1;
+ UINT32 MaxPacketLen : 11;
+ UINT32 CtrlEp : 1;
+ UINT32 NakReload : 4;
+
+ UINT32 SMask : 8;
+ UINT32 CMask : 8;
+ UINT32 HubAddr : 7;
+ UINT32 PortNum : 7;
+ UINT32 Multiplier : 2;
+
+ //
+ // Transaction execution overlay area
+ //
+ UINT32 CurQtd;
+ UINT32 NextQtd;
+ UINT32 AltQtd;
+
+ UINT32 Status : 8;
+ UINT32 Pid : 2;
+ UINT32 ErrCnt : 2;
+ UINT32 CurPage : 3;
+ UINT32 Ioc : 1;
+ UINT32 TotalBytes : 15;
+ UINT32 DataToggle : 1;
+
+ UINT32 Page[5];
+ UINT32 PageHigh[5];
+} QH_HW;
+#pragma pack()
+
+
+//
+// Endpoint address and its capabilities
+//
+typedef struct _USB_ENDPOINT {
+ UINT8 DevAddr;
+ UINT8 EpAddr; // Endpoint address, no direction encoded in
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 DevSpeed;
+ UINTN MaxPacket;
+ UINT8 HubAddr;
+ UINT8 HubPort;
+ UINT8 Toggle; // Data toggle, not used for control transfer
+ UINTN Type;
+ UINTN PollRate; // Polling interval used by EHCI
+} USB_ENDPOINT;
+
+//
+// Software QTD strcture, this is used to manage all the
+// QTD generated from a URB. Don't add fields before QtdHw.
+//
+struct _PEI_EHC_QTD {
+ QTD_HW QtdHw;
+ UINT32 Signature;
+ EFI_LIST_ENTRY QtdList; // The list of QTDs to one end point
+ UINT8 *Data; // Buffer of the original data
+ UINTN DataLen; // Original amount of data in this QTD
+};
+
+
+
+//
+// Software QH structure. All three different transaction types
+// supported by UEFI USB, that is the control/bulk/interrupt
+// transfers use the queue head and queue token strcuture.
+//
+// Interrupt QHs are linked to periodic frame list in the reversed
+// 2^N tree. Each interrupt QH is linked to the list starting at
+// frame 0. There is a dummy interrupt QH linked to each frame as
+// a sentinental whose polling interval is 1. Synchronous interrupt
+// transfer is linked after this dummy QH.
+//
+// For control/bulk transfer, only synchronous (in the sense of UEFI)
+// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr
+// as the reclamation header. New transfer is inserted after this QH.
+//
+struct _PEI_EHC_QH {
+ QH_HW QhHw;
+ UINT32 Signature;
+ PEI_EHC_QH *NextQh; // The queue head pointed to by horizontal link
+ EFI_LIST_ENTRY Qtds; // The list of QTDs to this queue head
+ UINTN Interval;
+};
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+struct _PEI_URB {
+ UINT32 Signature;
+ EFI_LIST_ENTRY UrbList;
+
+ //
+ // Transaction information
+ //
+ USB_ENDPOINT Ep;
+ EFI_USB_DEVICE_REQUEST *Request; // Control transfer only
+ VOID *RequestPhy; // Address of the mapped request
+ VOID *RequestMap;
+ VOID *Data;
+ UINTN DataLen;
+ VOID *DataPhy; // Address of the mapped user data
+ VOID *DataMap;
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
+ VOID *Context;
+
+ //
+ // Schedule data
+ //
+ PEI_EHC_QH *Qh;
+
+ //
+ // Transaction result
+ //
+ UINT32 Result;
+ UINTN Completed; // completed data length
+ UINT8 DataToggle;
+};
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Ehc The EHCI device.
+ @param Data Current data not associated with a QTD.
+ @param DataLen The length of the data.
+ @param PktId Packet ID to use in the QTD.
+ @param Toggle Data toggle to use in the QTD.
+ @param MaxPacket Maximu packet length of the endpoint.
+
+ @retval the pointer to the created QTD or NULL if failed to create one.
+
+**/
+PEI_EHC_QTD *
+EhcCreateQtd (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT8 *Data,
+ IN UINTN DataLen,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket
+ )
+;
+
+/**
+ Allocate and initialize a EHCI queue head.
+
+ @param Ehci The EHCI device.
+ @param Ep The endpoint to create queue head for.
+
+ @retval the pointer to the created queue head or NULL if failed to create one.
+
+**/
+PEI_EHC_QH *
+EhcCreateQh (
+ IN PEI_USB2_HC_DEV *Ehci,
+ IN USB_ENDPOINT *Ep
+ )
+;
+
+/**
+ Free an allocated URB. It is possible for it to be partially inited.
+
+ @param Ehc The EHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+EhcFreeUrb (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN PEI_URB *Urb
+ )
+;
+
+/**
+ Create a new URB and its associated QTD.
+
+ @param Ehc The EHCI device.
+ @param DevAddr The device address.
+ @param EpAddr Endpoint addrress & its direction.
+ @param DevSpeed The device speed.
+ @param Toggle Initial data toggle to use.
+ @param MaxPacket The max packet length of the endpoint.
+ @param Hub The transaction translator to use.
+ @param Type The transaction type.
+ @param Request The standard USB request for control transfer.
+ @param Data The user data to transfer.
+ @param DataLen The length of data buffer.
+ @param Callback The function to call when data is transferred.
+ @param Context The context to the callback.
+ @param Interval The interval for interrupt transfer.
+
+ @retval the pointer to the created URB or NULL.
+
+**/
+PEI_URB *
+EhcCreateUrb (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINT8 Toggle,
+ IN UINTN MaxPacket,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN UINTN Interval
+ )
+;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c
new file mode 100644
index 000000000..269b3edb8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c
@@ -0,0 +1,517 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EhcPeim.h"
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ UINTN PageNumber;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ Mapping = NULL;
+ PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+
+ PageNumber = (Block->BitsLen)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ Block->Bits = (UINT8 *)(UINTN)TempPtr;
+
+ Status = IoMmuAllocateBuffer (
+ Ehc->IoMmu,
+ Pages,
+ (VOID **) &BufHost,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem (BufHost, Pages*EFI_PAGE_SIZE);
+
+ //
+ // Check whether the data structure used by the host controller
+ // should be restricted into the same 4G
+ //
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+ return NULL;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+
+}
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (Ehc->IoMmu, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+}
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Ehc The EHCI device.
+ @param Check4G Whether the host controller requires allocated memory.
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+{
+ USBHC_MEM_POOL *Pool;
+ UINTN PageNumber;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
+
+ Pool->Check4G = Check4G;
+ Pool->Which4G = Which4G;
+ Pool->Head = UsbHcAllocMemBlock (Ehc, Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+/**
+ Release the memory management pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Block->Next) {
+ UsbHcFreeMemBlock (Ehc, Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Ehc, Pool, Pool->Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Ehc The EHCI device.
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+ NewBlock = UsbHcAllocMemBlock (Ehc,Pool, Pages);
+
+ if (NewBlock == NULL) {
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Ehc The EHCI device.
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN PEI_USB2_HC_DEV *Ehc,
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcFreeMemBlock (Ehc, Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h
new file mode 100644
index 000000000..21b2d7fa9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h
@@ -0,0 +1,86 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_MEM_H_
+#define _EFI_EHCI_MEM_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Pci22.h>
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64) \
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c
new file mode 100644
index 000000000..2f888424d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c
@@ -0,0 +1,2494 @@
+/** @file
+PEIM to produce gEfiPeiVirtualBlockIoPpiGuid & gEfiPeiVirtualBlockIo2PpiGuid PPI for
+ATA controllers in the platform.
+
+This PPI can be consumed by PEIM which produce gEfiPeiDeviceRecoveryModulePpiGuid
+for Atapi CD ROM device.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AtapiPeim.h"
+
+/**
+ Initializes the Atapi Block Io PPI.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PEI_ATA_CONTROLLER_PPI *AtaControllerPpi;
+ EFI_STATUS Status;
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+
+ Status = PeiServicesRegisterForShadow (FileHandle);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiAtaControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &AtaControllerPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ AtapiBlkIoDev = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*AtapiBlkIoDev)));
+ if (AtapiBlkIoDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AtapiBlkIoDev->Signature = ATAPI_BLK_IO_DEV_SIGNATURE;
+ AtapiBlkIoDev->AtaControllerPpi = AtaControllerPpi;
+
+ //
+ // atapi device enumeration and build private data
+ //
+ AtapiEnumerateDevices (AtapiBlkIoDev);
+
+ AtapiBlkIoDev->AtapiBlkIo.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices;
+ AtapiBlkIoDev->AtapiBlkIo.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo;
+ AtapiBlkIoDev->AtapiBlkIo.ReadBlocks = AtapiReadBlocks;
+ AtapiBlkIoDev->AtapiBlkIo2.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
+ AtapiBlkIoDev->AtapiBlkIo2.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices2;
+ AtapiBlkIoDev->AtapiBlkIo2.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo2;
+ AtapiBlkIoDev->AtapiBlkIo2.ReadBlocks = AtapiReadBlocks2;
+
+ AtapiBlkIoDev->PpiDescriptor.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI;
+ AtapiBlkIoDev->PpiDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
+ AtapiBlkIoDev->PpiDescriptor.Ppi = &AtapiBlkIoDev->AtapiBlkIo;
+
+ AtapiBlkIoDev->PpiDescriptor2.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ AtapiBlkIoDev->PpiDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid;
+ AtapiBlkIoDev->PpiDescriptor2.Ppi = &AtapiBlkIoDev->AtapiBlkIo2;
+
+ DEBUG ((EFI_D_INFO, "Atatpi Device Count is %d\n", AtapiBlkIoDev->DeviceCount));
+ if (AtapiBlkIoDev->DeviceCount != 0) {
+ Status = PeiServicesInstallPpi (&AtapiBlkIoDev->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+AtapiGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+
+ AtapiBlkIoDev = NULL;
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
+
+ *NumberBlockDevices = AtapiBlkIoDev->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
+AtapiGetBlockDeviceMediaInfo (
+ 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;
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ AtapiBlkIoDev = NULL;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
+
+ DeviceCount = AtapiBlkIoDev->DeviceCount;
+
+ //
+ // DeviceIndex is a value from 1 to NumberBlockDevices.
+ //
+ if ((DeviceIndex < 1) || (DeviceIndex > DeviceCount) || (DeviceIndex > MAX_IDE_DEVICES)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = DeviceIndex - 1;
+
+ //
+ // probe media and retrieve latest media information
+ //
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo LastBlock is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));
+
+ Status = DetectMedia (
+ AtapiBlkIoDev,
+ AtapiBlkIoDev->DeviceInfo[Index].DevicePosition,
+ &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo,
+ &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo2
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));
+ DEBUG ((EFI_D_INFO, "Atatpi GetInfo LastBlock is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));
+
+ //
+ // Get media info from AtapiBlkIoDev
+ //
+ CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[Index].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
+AtapiReadBlocks (
+ 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 NumberOfBlocks;
+ UINTN BlockSize;
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+
+ AtapiBlkIoDev = NULL;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = AtapiGetBlockDeviceMediaInfo (
+ PeiServices,
+ This,
+ DeviceIndex,
+ &MediaInfo
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!MediaInfo.MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ BlockSize = MediaInfo.BlockSize;
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if ((StartLBA + NumberOfBlocks - 1) > AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ReadSectors (
+ AtapiBlkIoDev,
+ AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].DevicePosition,
+ Buffer,
+ StartLBA,
+ NumberOfBlocks,
+ BlockSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiGetNumberOfBlockDevices2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
+
+ Status = AtapiGetNumberOfBlockDevices (
+ PeiServices,
+ &AtapiBlkIoDev->AtapiBlkIo,
+ NumberBlockDevices
+ );
+
+ return Status;
+}
+
+/**
+ 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_IO2_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
+AtapiGetBlockDeviceMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+ EFI_STATUS Status;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+
+ AtapiBlkIoDev = NULL;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
+
+ Status = AtapiGetBlockDeviceMediaInfo (
+ PeiServices,
+ &AtapiBlkIoDev->AtapiBlkIo,
+ DeviceIndex,
+ &Media
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get media info from AtapiBlkIoDev
+ //
+ CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2, sizeof(EFI_PEI_BLOCK_IO2_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_IO2_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
+AtapiReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_BLK_IO_DEV *AtapiBlkIoDev;
+
+ AtapiBlkIoDev = NULL;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
+
+ Status = AtapiReadBlocks (
+ PeiServices,
+ &AtapiBlkIoDev->AtapiBlkIo,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+
+ return Status;
+}
+
+
+/**
+ Enumerate Atapi devices.
+
+ This function is used to enumerate Atatpi device in Ide channel.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device
+
+**/
+VOID
+AtapiEnumerateDevices (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev
+ )
+{
+ UINT8 Index1;
+ UINT8 Index2;
+ UINTN DevicePosition;
+ EFI_PEI_BLOCK_IO_MEDIA MediaInfo;
+ EFI_PEI_BLOCK_IO2_MEDIA MediaInfo2;
+ EFI_STATUS Status;
+ UINTN DeviceCount;
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINT32 IdeEnabledNumber;
+ IDE_REGS_BASE_ADDR IdeRegsBaseAddr[MAX_IDE_CHANNELS];
+
+ DeviceCount = 0;
+ DevicePosition = 0;
+
+ //
+ // Scan IDE bus for ATAPI devices
+ //
+
+ //
+ // Enable Sata and IDE controller.
+ //
+ AtapiBlkIoDev->AtaControllerPpi->EnableAtaChannel (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
+ AtapiBlkIoDev->AtaControllerPpi,
+ PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY
+ );
+
+ //
+ // Allow SATA Devices to spin-up. This is needed if
+ // SEC and PEI phase is too short, for example Release Build.
+ //
+ DEBUG ((EFI_D_INFO, "Delay for %d seconds for SATA devices to spin-up\n", PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath)));
+ MicroSecondDelay (PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath) * 1000 * 1000); //
+
+ //
+ // Get four channels (primary or secondary Pata, Sata Channel) Command and Control Regs Base address.
+ //
+ IdeEnabledNumber = AtapiBlkIoDev->AtaControllerPpi->GetIdeRegsBaseAddr (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
+ AtapiBlkIoDev->AtaControllerPpi,
+ IdeRegsBaseAddr
+ );
+
+ //
+ // Using Command and Control Regs Base Address to fill other registers.
+ //
+ for (Index1 = 0; Index1 < IdeEnabledNumber; Index1 ++) {
+ CommandBlockBaseAddr = IdeRegsBaseAddr[Index1].CommandBlockBaseAddr;
+ AtapiBlkIoDev->IdeIoPortReg[Index1].Data = CommandBlockBaseAddr;
+ AtapiBlkIoDev->IdeIoPortReg[Index1].Reg1.Feature = (UINT16) (CommandBlockBaseAddr + 0x1);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x2);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x3);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x4);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x5);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].Head = (UINT16) (CommandBlockBaseAddr + 0x6);
+ AtapiBlkIoDev->IdeIoPortReg[Index1].Reg.Command = (UINT16) (CommandBlockBaseAddr + 0x7);
+
+ ControlBlockBaseAddr = IdeRegsBaseAddr[Index1].ControlBlockBaseAddr;
+ AtapiBlkIoDev->IdeIoPortReg[Index1].Alt.DeviceControl = ControlBlockBaseAddr;
+ AtapiBlkIoDev->IdeIoPortReg[Index1].DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x1);
+
+ //
+ // Scan IDE bus for ATAPI devices IDE or Sata device
+ //
+ for (Index2 = IdeMaster; Index2 < IdeMaxDevice; Index2++) {
+ //
+ // Pata & Sata, Primary & Secondary channel, Master & Slave device
+ //
+ DevicePosition = Index1 * 2 + Index2;
+
+ if (DiscoverAtapiDevice (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2)) {
+ //
+ // ATAPI Device at DevicePosition is found.
+ //
+ AtapiBlkIoDev->DeviceInfo[DeviceCount].DevicePosition = DevicePosition;
+ //
+ // Retrieve Media Info
+ //
+ Status = DetectMedia (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2);
+ CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo), &MediaInfo, sizeof (MediaInfo));
+ CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2), &MediaInfo2, sizeof (MediaInfo2));
+
+ DEBUG ((EFI_D_INFO, "Atatpi Device Position is %d\n", DevicePosition));
+ DEBUG ((EFI_D_INFO, "Atatpi DeviceType is %d\n", MediaInfo.DeviceType));
+ DEBUG ((EFI_D_INFO, "Atatpi MediaPresent is %d\n", MediaInfo.MediaPresent));
+ DEBUG ((EFI_D_INFO, "Atatpi BlockSize is 0x%x\n", MediaInfo.BlockSize));
+
+ if (EFI_ERROR (Status)) {
+ AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.MediaPresent = FALSE;
+ AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.LastBlock = 0;
+ AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.MediaPresent = FALSE;
+ AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.LastBlock = 0;
+ }
+ DeviceCount += 1;
+ }
+ }
+ }
+
+ AtapiBlkIoDev->DeviceCount = DeviceCount;
+}
+
+/**
+ Detect Atapi devices.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[out] MediaInfo The media information of the specified block media.
+ @param[out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval TRUE Atapi device exists in specified position.
+ @retval FALSE Atapi device does not exist in specified position.
+
+**/
+BOOLEAN
+DiscoverAtapiDevice (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ )
+{
+ EFI_STATUS Status;
+
+ if (!DetectIDEController (AtapiBlkIoDev, DevicePosition)) {
+ return FALSE;
+ }
+ //
+ // test if it is an ATAPI device (only supported device)
+ //
+ if (ATAPIIdentify (AtapiBlkIoDev, DevicePosition) == EFI_SUCCESS) {
+
+ Status = Inquiry (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check power mode of Atapi devices.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] AtaCommand The Ata Command passed in.
+
+ @retval EFI_SUCCESS The Atapi device support power mode.
+ @retval EFI_NOT_FOUND The Atapi device not found.
+ @retval EFI_TIMEOUT Atapi command transaction is time out.
+ @retval EFI_ABORTED Atapi command abort.
+
+**/
+EFI_STATUS
+CheckPowerMode (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN UINT8 AtaCommand
+ )
+{
+ UINT8 Channel;
+ UINT8 Device;
+ UINT16 StatusRegister;
+ UINT16 HeadRegister;
+ UINT16 CommandRegister;
+ UINT16 ErrorRegister;
+ UINT16 SectorCountRegister;
+ EFI_STATUS Status;
+ UINT8 StatusValue;
+ UINT8 ErrorValue;
+ UINT8 SectorCountValue;
+
+ Channel = (UINT8) (DevicePosition / 2);
+ Device = (UINT8) (DevicePosition % 2);
+
+ ASSERT (Channel < MAX_IDE_CHANNELS);
+
+ StatusRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
+ HeadRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
+ CommandRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
+ ErrorRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Error;
+ SectorCountRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;
+
+ //
+ // select device
+ //
+ IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
+
+ //
+ // refresh the SectorCount register
+ //
+ SectorCountValue = 0x55;
+ IoWrite8 (SectorCountRegister, SectorCountValue);
+
+ //
+ // select device
+ //
+ IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
+
+ Status = DRDYReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 100);
+
+ //
+ // select device
+ //
+ IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
+ //
+ // send 'check power' commandd via Command Register
+ //
+ IoWrite8 (CommandRegister, AtaCommand);
+
+ Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 3000);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+
+ StatusValue = IoRead8 (StatusRegister);
+
+ //
+ // command returned status is DRDY, indicating device supports the command,
+ // so device is present.
+ //
+ if ((StatusValue & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {
+ return EFI_SUCCESS;
+ }
+
+ SectorCountValue = IoRead8 (SectorCountRegister);
+
+ //
+ // command returned status is ERR & ABRT_ERR, indicating device does not support
+ // the command, so device is present.
+ //
+ if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ ErrorValue = IoRead8 (ErrorRegister);
+ if ((ErrorValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ } else {
+ //
+ // According to spec, no other error code is valid
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if ((SectorCountValue == 0x00) || (SectorCountValue == 0x80) || (SectorCountValue == 0xff)) {
+ //
+ // Write SectorCount 0x55 but return valid state value. Maybe no device
+ // exists or some slow kind of ATAPI device exists.
+ //
+ IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
+
+ //
+ // write 0x55 and 0xaa to SectorCounter register,
+ // if the data could be written into the register,
+ // indicating the device is present, otherwise the device is not present.
+ //
+ SectorCountValue = 0x55;
+ IoWrite8 (SectorCountRegister, SectorCountValue);
+ MicroSecondDelay (10000);
+
+ SectorCountValue = IoRead8 (SectorCountRegister);
+ if (SectorCountValue != 0x55) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Send a "ATAPI TEST UNIT READY" command ... slow but accurate
+ //
+ Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);
+ return Status;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Detect if an IDE controller exists in specified position.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval TRUE The Atapi device exists.
+ @retval FALSE The Atapi device does not present.
+
+**/
+BOOLEAN
+DetectIDEController (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ )
+{
+ UINT8 Channel;
+ EFI_STATUS Status;
+ UINT8 AtaCommand;
+
+ Channel = (UINT8) (DevicePosition / 2);
+
+ ASSERT (Channel < MAX_IDE_CHANNELS);
+ //
+ // Wait 31 seconds for BSY clear
+ //
+ Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // Send 'check power' command for IDE device
+ //
+ AtaCommand = 0xE5;
+ Status = CheckPowerMode (AtapiBlkIoDev, DevicePosition, AtaCommand);
+ if ((Status == EFI_ABORTED) || (Status == EFI_SUCCESS)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Wait specified time interval to poll for BSY bit clear in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS BSY bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT BSY bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 StatusRegister;
+ UINT8 StatusValue;
+
+ StatusValue = 0;
+
+ StatusRegister = IdeIoRegisters->Reg.Status;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+ StatusValue = IoRead8 (StatusRegister);
+ if ((StatusValue & ATA_STSREG_BSY) == 0x00) {
+ break;
+ }
+ MicroSecondDelay (250);
+
+ Delay--;
+
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait specified time interval to poll for DRDY bit set in the Status register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRDY bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRDY bit is not set in the specified time interval.
+
+**/
+EFI_STATUS
+DRDYReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 StatusRegister;
+ UINT8 StatusValue;
+ UINT8 ErrValue;
+
+ StatusValue = 0;
+
+ StatusRegister = IdeIoRegisters->Reg.Status;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+ StatusValue = IoRead8 (StatusRegister);
+ //
+ // BSY == 0 , DRDY == 1
+ //
+ if ((StatusValue & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+ break;
+ }
+
+ if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_BSY)) == ATA_STSREG_ERR) {
+ ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
+ if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ MicroSecondDelay (250);
+
+ Delay--;
+
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait specified time interval to poll for DRQ bit clear in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+DRQClear (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 StatusRegister;
+ UINT8 StatusValue;
+ UINT8 ErrValue;
+
+ StatusValue = 0;
+
+ StatusRegister = IdeIoRegisters->Reg.Status;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+
+ StatusValue = IoRead8 (StatusRegister);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((StatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+ ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
+ if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ MicroSecondDelay (250);
+
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait specified time interval to poll for DRQ bit clear in the Alternate Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 AltStatusRegister;
+ UINT8 AltStatusValue;
+ UINT8 ErrValue;
+
+ AltStatusValue = 0;
+
+ AltStatusRegister = IdeIoRegisters->Alt.AltStatus;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+
+ AltStatusValue = IoRead8 (AltStatusRegister);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((AltStatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+ ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
+ if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ MicroSecondDelay (250);
+
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait specified time interval to poll for DRQ bit set in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.
+ @retval EFI_ABORTED Operation Aborted.
+
+**/
+EFI_STATUS
+DRQReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 StatusRegister;
+ UINT8 StatusValue;
+ UINT8 ErrValue;
+
+ StatusValue = 0;
+ ErrValue = 0;
+
+ StatusRegister = IdeIoRegisters->Reg.Status;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+ //
+ // read Status Register will clear interrupt
+ //
+ StatusValue = IoRead8 (StatusRegister);
+
+ //
+ // BSY==0,DRQ==1
+ //
+ if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
+ if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+ MicroSecondDelay (250);
+
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait specified time interval to poll for DRQ bit set in the Alternate Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.
+ @retval EFI_ABORTED Operation Aborted.
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINTN Delay;
+ UINT16 AltStatusRegister;
+ UINT8 AltStatusValue;
+ UINT8 ErrValue;
+
+ AltStatusValue = 0;
+
+ AltStatusRegister = IdeIoRegisters->Alt.AltStatus;
+
+ Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
+ do {
+
+ AltStatusValue = IoRead8 (AltStatusRegister);
+
+ //
+ // BSY==0,DRQ==1
+ //
+ if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
+ if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+ MicroSecondDelay (250);
+
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if there is an error in Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] StatusReg The address to IDE IO registers.
+
+ @retval EFI_SUCCESS Operation success.
+ @retval EFI_DEVICE_ERROR Device error.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINT16 StatusReg
+ )
+{
+ UINT8 StatusValue;
+
+ StatusValue = IoRead8 (StatusReg);
+
+ if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+}
+
+/**
+ Idendify Atapi devices.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval EFI_SUCCESS Identify successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be identified successfully.
+
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ )
+{
+ ATAPI_IDENTIFY_DATA AtapiIdentifyData;
+ UINT8 Channel;
+ UINT8 Device;
+ UINT16 StatusReg;
+ UINT16 HeadReg;
+ UINT16 CommandReg;
+ UINT16 DataReg;
+ UINT16 SectorCountReg;
+ UINT16 SectorNumberReg;
+ UINT16 CylinderLsbReg;
+ UINT16 CylinderMsbReg;
+
+ UINT32 WordCount;
+ UINT32 Increment;
+ UINT32 Index;
+ UINT32 ByteCount;
+ UINT16 *Buffer16;
+
+ EFI_STATUS Status;
+
+ ByteCount = sizeof (AtapiIdentifyData);
+ Buffer16 = (UINT16 *) &AtapiIdentifyData;
+
+ Channel = (UINT8) (DevicePosition / 2);
+ Device = (UINT8) (DevicePosition % 2);
+
+ ASSERT (Channel < MAX_IDE_CHANNELS);
+
+ StatusReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
+ HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
+ CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
+ DataReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;
+ SectorCountReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;
+ SectorNumberReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorNumber;
+ CylinderLsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;
+ CylinderMsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;
+
+ //
+ // Send ATAPI Identify Command to get IDENTIFY data.
+ //
+ if (WaitForBSYClear (
+ AtapiBlkIoDev,
+ &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
+ ATATIMEOUT
+ ) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // select device via Head/Device register.
+ // Before write Head/Device register, BSY and DRQ must be 0.
+ //
+ if (DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.
+ // bit6 set means LBA mode
+ //
+ IoWrite8 (HeadReg, (UINT8) ((Device << 4) | 0xe0));
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ if (DRQClear2 (
+ AtapiBlkIoDev,
+ &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
+ ATATIMEOUT
+ ) != EFI_SUCCESS) {
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ IoWrite8 (SectorCountReg, 0);
+ IoWrite8 (SectorNumberReg, 0);
+ IoWrite8 (CylinderLsbReg, 0);
+ IoWrite8 (CylinderMsbReg, 0);
+
+ //
+ // send command via Command Register
+ //
+ IoWrite8 (CommandReg, ATA_CMD_IDENTIFY_DEVICE);
+
+ //
+ // 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,
+ // hense 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, whole 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 whole data size of one ATA commmand request is larger than 256 words.
+ //
+ Increment = 256;
+ //
+ // 256 words
+ //
+ WordCount = 0;
+ //
+ // WordCount is used to record bytes of currently transfered data
+ //
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT);
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (CheckErrorStatus (AtapiBlkIoDev, StatusReg) != EFI_SUCCESS) {
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+ //
+ // perform a series of read without check DRQ ready
+ //
+ for (Index = 0; Index < Increment; Index++) {
+ *Buffer16++ = IoRead16 (DataReg);
+ }
+
+ WordCount += Increment;
+
+ }
+ //
+ // while
+ //
+ if (DRQClear (
+ AtapiBlkIoDev,
+ &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
+ ATATIMEOUT
+ ) != EFI_SUCCESS) {
+ return CheckErrorStatus (AtapiBlkIoDev, StatusReg);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval EFI_SUCCESS TestUnit command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
+
+**/
+EFI_STATUS
+TestUnitReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = AtapiPacketCommandIn (AtapiBlkIoDev, DevicePosition, &Packet, NULL, 0, ATAPITIMEOUT);
+ return Status;
+}
+
+/**
+ Send out ATAPI commands conforms to the Packet Command with PIO Data In Protocol.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Packet A pointer to ATAPI command packet.
+ @param[in] Buffer Buffer to contain requested transfer data from device.
+ @param[in] ByteCount Requested transfer data length.
+ @param[in] TimeoutInMilliSeconds Time out value, in unit of milliseconds.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.
+
+**/
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT8 Channel;
+ UINT8 Device;
+ UINT16 StatusReg;
+ UINT16 HeadReg;
+ UINT16 CommandReg;
+ UINT16 FeatureReg;
+ UINT16 CylinderLsbReg;
+ UINT16 CylinderMsbReg;
+ UINT16 DeviceControlReg;
+ UINT16 DataReg;
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINT16 *CommandIndex;
+ UINT16 *PtrBuffer;
+ UINT32 Index;
+ UINT8 StatusValue;
+ UINT32 WordCount;
+
+ //
+ // required transfer data in word unit.
+ //
+ UINT32 RequiredWordCount;
+
+ //
+ // actual transfer data in word unit.
+ //
+ UINT32 ActualWordCount;
+
+ Channel = (UINT8) (DevicePosition / 2);
+ Device = (UINT8) (DevicePosition % 2);
+
+ ASSERT (Channel < MAX_IDE_CHANNELS);
+
+ StatusReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
+ HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
+ CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
+ FeatureReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Feature;
+ CylinderLsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;
+ CylinderMsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;
+ DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;
+ DataReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;
+
+ //
+ // Set all the command parameters by fill related registers.
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ if (DRQClear2 (
+ AtapiBlkIoDev,
+ &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
+ ATATIMEOUT
+ ) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Select device via Device/Head Register.
+ // DEFAULT_CMD: 0xa0 (1010,0000)
+ //
+ IoWrite8 (HeadReg, (UINT8) ((Device << 4) | ATA_DEFAULT_CMD));
+
+ //
+ // No OVL; No DMA
+ //
+ IoWrite8 (FeatureReg, 0x00);
+
+ //
+ // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
+ // determine how many data should be transfered.
+ //
+ IoWrite8 (CylinderLsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff));
+ IoWrite8 (CylinderMsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8));
+
+ //
+ // DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IoWrite8 (DeviceControlReg, ATA_DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IoWrite8 (CommandReg, ATA_CMD_PACKET);
+
+ Status = DRQReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // Send out command packet
+ //
+ CommandIndex = Packet->Data16;
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {
+ IoWrite16 (DataReg, *CommandIndex);
+ MicroSecondDelay (10);
+ }
+
+ StatusValue = IoRead8 (StatusReg);
+ if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ //
+ // Trouble! Something's wrong here... Wait some time and return. 3 second is
+ // supposed to be long enough for a device reset latency or error recovery
+ //
+ MicroSecondDelay (3000000);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Buffer == NULL || ByteCount == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // call PioReadWriteData() function to get
+ // requested transfer data form device.
+ //
+ PtrBuffer = Buffer;
+ RequiredWordCount = ByteCount / 2;
+ //
+ // ActuralWordCount means the word count of data really transfered.
+ //
+ ActualWordCount = 0;
+
+ Status = EFI_SUCCESS;
+ while ((Status == EFI_SUCCESS) && (ActualWordCount < RequiredWordCount)) {
+ //
+ // before each data transfer stream, the host should poll DRQ bit ready,
+ // which informs device is ready to transfer data.
+ //
+ if (DRQReady2 (
+ AtapiBlkIoDev,
+ &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
+ TimeoutInMilliSeconds
+ ) != EFI_SUCCESS) {
+ return CheckErrorStatus (AtapiBlkIoDev, StatusReg);
+ }
+ //
+ // read Status Register will clear interrupt
+ //
+ StatusValue = IoRead8 (StatusReg);
+
+ //
+ // get current data transfer size from Cylinder Registers.
+ //
+ WordCount = IoRead8 (CylinderMsbReg) << 8;
+ WordCount = WordCount | IoRead8 (CylinderLsbReg);
+ WordCount = WordCount & 0xffff;
+ WordCount /= 2;
+
+ //
+ // perform a series data In/Out.
+ //
+ for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
+
+ *PtrBuffer = IoRead16 (DataReg);
+
+ PtrBuffer++;
+
+ }
+
+ if (((ATAPI_REQUEST_SENSE_CMD *) Packet)->opcode == ATA_CMD_REQUEST_SENSE && ActualWordCount >= 4) {
+ RequiredWordCount = MIN (
+ RequiredWordCount,
+ (UINT32) (4 + (((ATAPI_REQUEST_SENSE_DATA *) Buffer)->addnl_sense_length / 2))
+ );
+ }
+
+ }
+ //
+ // After data transfer is completed, normally, DRQ bit should clear.
+ //
+ Status = DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // read status register to check whether error happens.
+ //
+ Status = CheckErrorStatus (AtapiBlkIoDev, StatusReg);
+ return Status;
+}
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return INQUIRY data of the device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[out] MediaInfo The media information of the specified block media.
+ @param[out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.
+ @retval EFI_UNSUPPORTED Unsupported device type.
+
+**/
+EFI_STATUS
+Inquiry (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ ATAPI_INQUIRY_DATA Idata;
+
+ //
+ // prepare command packet for the ATAPI Inquiry Packet Command.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
+
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = (UINT8) sizeof (ATAPI_INQUIRY_DATA);
+
+ //
+ // Send command packet and get requested Inquiry data.
+ //
+ Status = AtapiPacketCommandIn (
+ AtapiBlkIoDev,
+ DevicePosition,
+ &Packet,
+ (UINT16 *) (&Idata),
+ sizeof (ATAPI_INQUIRY_DATA),
+ ATAPITIMEOUT
+ //50
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Identify device type via INQUIRY data.
+ //
+ switch (Idata.peripheral_type & 0x1f) {
+ case 0x00:
+ //
+ // Magnetic Disk
+ //
+ MediaInfo->DeviceType = IdeLS120;
+ MediaInfo->MediaPresent = FALSE;
+ MediaInfo->LastBlock = 0;
+ MediaInfo->BlockSize = 0x200;
+ MediaInfo2->InterfaceType = MSG_ATAPI_DP;
+ MediaInfo2->RemovableMedia = TRUE;
+ MediaInfo2->MediaPresent = FALSE;
+ MediaInfo2->ReadOnly = FALSE;
+ MediaInfo2->BlockSize = 0x200;
+ MediaInfo2->LastBlock = 0;
+ break;
+
+ case 0x05:
+ //
+ // CD-ROM
+ //
+ MediaInfo->DeviceType = IdeCDROM;
+ MediaInfo->MediaPresent = FALSE;
+ MediaInfo->LastBlock = 0;
+ MediaInfo->BlockSize = 0x800;
+ MediaInfo2->InterfaceType = MSG_ATAPI_DP;
+ MediaInfo2->RemovableMedia = TRUE;
+ MediaInfo2->MediaPresent = FALSE;
+ MediaInfo2->ReadOnly = TRUE;
+ MediaInfo2->BlockSize = 0x200;
+ MediaInfo2->LastBlock = 0;
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ 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.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in, out] MediaInfo The media information of the specified block media.
+ @param[in, out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate required resources.
+
+**/
+EFI_STATUS
+DetectMedia (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ )
+{
+
+ UINTN Index;
+ UINTN RetryNum;
+ UINTN MaxRetryNum;
+ ATAPI_REQUEST_SENSE_DATA *SenseBuffers;
+ BOOLEAN NeedReadCapacity;
+ BOOLEAN NeedRetry;
+ EFI_STATUS Status;
+ UINT8 SenseCounts;
+
+ SenseBuffers = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*SenseBuffers)));
+ if (SenseBuffers == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Test Unit Ready command is used to detect whether device is accessible,
+ // the device will produce corresponding Sense data.
+ //
+ for (Index = 0; Index < 2; Index++) {
+
+ Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);
+ if (Status != EFI_SUCCESS) {
+ Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);
+
+ if (Status != EFI_SUCCESS) {
+ ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);
+ }
+
+ } else {
+ break;
+ }
+ }
+
+ SenseCounts = MAX_SENSE_KEY_COUNT;
+ Status = EFI_SUCCESS;
+ NeedReadCapacity = TRUE;
+
+ for (Index = 0; Index < 5; Index++) {
+ SenseCounts = MAX_SENSE_KEY_COUNT;
+ Status = RequestSense (
+ AtapiBlkIoDev,
+ DevicePosition,
+ SenseBuffers,
+ &SenseCounts
+ );
+ DEBUG ((EFI_D_INFO, "Atapi Request Sense Count is %d\n", SenseCounts));
+ if (IsDeviceStateUnclear (SenseBuffers, SenseCounts) || IsNoMedia (SenseBuffers, SenseCounts)) {
+ //
+ // We are not sure whether the media is present or not, try again
+ //
+ TestUnitReady (AtapiBlkIoDev, DevicePosition);
+ } else {
+ break;
+ }
+ }
+
+ if (Status == EFI_SUCCESS) {
+
+ if (IsNoMedia (SenseBuffers, SenseCounts)) {
+
+ NeedReadCapacity = FALSE;
+ MediaInfo->MediaPresent = FALSE;
+ MediaInfo->LastBlock = 0;
+ MediaInfo2->MediaPresent = FALSE;
+ MediaInfo2->LastBlock = 0;
+ }
+
+ if (IsMediaError (SenseBuffers, SenseCounts)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (NeedReadCapacity) {
+ //
+ // at most retry 5 times
+ //
+ MaxRetryNum = 5;
+ RetryNum = 1;
+ //
+ // initial retry once
+ //
+ for (Index = 0; (Index < RetryNum) && (Index < MaxRetryNum); Index++) {
+
+ Status = ReadCapacity (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);
+ MicroSecondDelay (200000);
+ SenseCounts = MAX_SENSE_KEY_COUNT;
+
+ if (Status != EFI_SUCCESS) {
+
+ Status = RequestSense (AtapiBlkIoDev, DevicePosition, SenseBuffers, &SenseCounts);
+ //
+ // If Request Sense data failed, reset the device and retry.
+ //
+ if (Status != EFI_SUCCESS) {
+
+ Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);
+ //
+ // if ATAPI soft reset fail,
+ // use stronger reset mechanism -- ATA soft reset.
+ //
+ if (Status != EFI_SUCCESS) {
+ ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);
+ }
+
+ RetryNum++;
+ //
+ // retry once more
+ //
+ continue;
+ }
+ //
+ // No Media
+ //
+ if (IsNoMedia (SenseBuffers, SenseCounts)) {
+
+ MediaInfo->MediaPresent = FALSE;
+ MediaInfo->LastBlock = 0;
+ MediaInfo2->MediaPresent = FALSE;
+ MediaInfo2->LastBlock = 0;
+ break;
+ }
+
+ if (IsMediaError (SenseBuffers, SenseCounts)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!IsDriveReady (SenseBuffers, SenseCounts, &NeedRetry)) {
+ //
+ // Drive not ready: if NeedRetry, then retry once more;
+ // else return error
+ //
+ if (NeedRetry) {
+ RetryNum++;
+ continue;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // if read capacity fail not for above reasons, retry once more
+ //
+ RetryNum++;
+
+ }
+
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset specified Atapi device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Extensive If TRUE, use ATA soft reset, otherwise use Atapi soft reset.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ResetDevice (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN BOOLEAN Extensive
+ )
+{
+ UINT8 DevControl;
+ UINT8 Command;
+ UINT8 DeviceSelect;
+ UINT16 DeviceControlReg;
+ UINT16 CommandReg;
+ UINT16 HeadReg;
+ UINT8 Channel;
+ UINT8 Device;
+
+ Channel = (UINT8) (DevicePosition / 2);
+ Device = (UINT8) (DevicePosition % 2);
+
+ ASSERT (Channel < MAX_IDE_CHANNELS);
+
+ DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;
+ CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
+ HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
+
+ if (Extensive) {
+
+ DevControl = 0;
+ DevControl |= ATA_CTLREG_SRST;
+ //
+ // set SRST bit to initiate soft reset
+ //
+ DevControl |= BIT1;
+ //
+ // disable Interrupt
+ //
+ IoWrite8 (DeviceControlReg, DevControl);
+
+ //
+ // Wait 10us
+ //
+ MicroSecondDelay (10);
+
+ //
+ // Clear SRST bit
+ //
+ DevControl &= 0xfb;
+ //
+ // 0xfb:1111,1011
+ //
+ IoWrite8 (DeviceControlReg, DevControl);
+
+ //
+ // slave device needs at most 31s to clear BSY
+ //
+ if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ } else {
+ //
+ // 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) | (Device << 4)));
+ IoWrite8 (HeadReg, DeviceSelect);
+
+ Command = ATA_CMD_SOFT_RESET;
+ IoWrite8 (CommandReg, 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
+ //
+ if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // stall 5 seconds to make the device status stable
+ //
+ MicroSecondDelay (STALL_1_SECONDS * 5);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] SenseBuffers Pointer to sense buffer.
+ @param[in, out] SenseCounts Length of sense buffer.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+RequestSense (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN ATAPI_REQUEST_SENSE_DATA *SenseBuffers,
+ IN OUT UINT8 *SenseCounts
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_REQUEST_SENSE_DATA *Sense;
+ UINT16 *Ptr;
+ BOOLEAN SenseReq;
+ ATAPI_PACKET_COMMAND Packet;
+
+ ZeroMem (SenseBuffers, sizeof (ATAPI_REQUEST_SENSE_DATA) * (*SenseCounts));
+ //
+ // 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);
+
+ Ptr = (UINT16 *) SenseBuffers;
+ //
+ // initialize pointer
+ //
+ *SenseCounts = 0;
+ //
+ // request sense data from device continiously until no sense data exists in the device.
+ //
+ for (SenseReq = TRUE; SenseReq;) {
+
+ Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense data form device
+ //
+ Status = AtapiPacketCommandIn (
+ AtapiBlkIoDev,
+ DevicePosition,
+ &Packet,
+ Ptr,
+ sizeof (ATAPI_REQUEST_SENSE_DATA),
+ ATAPITIMEOUT
+ );
+ //
+ // failed to get Sense data
+ //
+ if (Status != EFI_SUCCESS) {
+ if (*SenseCounts == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ (*SenseCounts)++;
+
+ if (*SenseCounts > MAX_SENSE_KEY_COUNT) {
+ return EFI_SUCCESS;
+ }
+ //
+ // 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 += sizeof (ATAPI_REQUEST_SENSE_DATA) / 2;
+ //
+ // Ptr is word based pointer
+ //
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ SenseReq = FALSE;
+ }
+ }
+
+ 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.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in, out] MediaInfo The media information of the specified block media.
+ @param[in, out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ReadCapacity (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+
+ //
+ // 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 (MediaInfo->DeviceType == IdeCDROM) {
+
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+ Status = AtapiPacketCommandIn (
+ AtapiBlkIoDev,
+ DevicePosition,
+ &Packet,
+ (UINT16 *) (&Data),
+ sizeof (ATAPI_READ_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+
+ } else {
+ //
+ // DeviceType == IdeLS120
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+ Status = AtapiPacketCommandIn (
+ AtapiBlkIoDev,
+ DevicePosition,
+ &Packet,
+ (UINT16 *) (&FormatData),
+ sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
+ ATAPITIMEOUT*10
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+
+ if (MediaInfo->DeviceType == IdeCDROM) {
+
+ MediaInfo->LastBlock = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
+ MediaInfo->MediaPresent = TRUE;
+ //
+ // Because the user data portion in the sector of the Data CD supported
+ // is always 800h
+ //
+ MediaInfo->BlockSize = 0x800;
+
+ MediaInfo2->LastBlock = MediaInfo->LastBlock;
+ MediaInfo2->MediaPresent = MediaInfo->MediaPresent;
+ MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;
+ }
+
+ if (MediaInfo->DeviceType == IdeLS120) {
+
+ if (FormatData.DesCode == 3) {
+ MediaInfo->MediaPresent = FALSE;
+ MediaInfo->LastBlock = 0;
+ MediaInfo2->MediaPresent = FALSE;
+ MediaInfo2->LastBlock = 0;
+ } else {
+ MediaInfo->LastBlock = ((UINT32) FormatData.LastLba3 << 24) |
+ (FormatData.LastLba2 << 16) |
+ (FormatData.LastLba1 << 8) |
+ FormatData.LastLba0;
+ MediaInfo->LastBlock--;
+
+ MediaInfo->MediaPresent = TRUE;
+
+ MediaInfo->BlockSize = 0x200;
+
+ MediaInfo2->LastBlock = MediaInfo->LastBlock;
+ MediaInfo2->MediaPresent = MediaInfo->MediaPresent;
+ MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;
+
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Perform read from disk in block unit.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Buffer Buffer to contain read data.
+ @param[in] StartLba Starting LBA address.
+ @param[in] NumberOfBlocks Number of blocks to read.
+ @param[in] BlockSize Size of each block.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ReadSectors (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN UINTN BlockSize
+ )
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ10_CMD *Read10Packet;
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT32 ByteCount;
+ UINT16 SectorCount;
+ VOID *PtrBuffer;
+ UINT16 MaxBlock;
+
+ //
+ // fill command packet for Read(10) command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+ Lba32 = (UINT32) StartLba;
+ PtrBuffer = Buffer;
+
+ //
+ // limit the data bytes that can be transfered by one Read(10) Command
+ //
+ MaxBlock = (UINT16) (0x10000 / BlockSize);
+ //
+ // (64k bytes)
+ //
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+ SectorCount = MaxBlock;
+ }
+ //
+ // fill the Packet data sturcture
+ //
+ 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 = (UINT32) (SectorCount * BlockSize);
+
+ Status = AtapiPacketCommandIn (
+ AtapiBlkIoDev,
+ DevicePosition,
+ &Packet,
+ (UINT16 *) PtrBuffer,
+ ByteCount,
+ ATAPILONGTIMEOUT
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+/**
+ Check if there is media according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE No media
+ @retval FALSE Media exists
+
+**/
+BOOLEAN
+IsNoMedia (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsNoMedia;
+
+ IsNoMedia = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ if ((SensePtr->sense_key == ATA_SK_NOT_READY) && (SensePtr->addnl_sense_code == ATA_ASC_NO_MEDIA)) {
+ IsNoMedia = TRUE;
+ }
+
+ SensePtr++;
+ }
+
+ return IsNoMedia;
+}
+
+/**
+ Check if device state is unclear according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE Device state is unclear
+ @retval FALSE Device state is clear
+
+**/
+BOOLEAN
+IsDeviceStateUnclear (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN Unclear;
+
+ Unclear = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ if (SensePtr->sense_key == 0x06) {
+ //
+ // Sense key is 0x06 means the device is just be reset or media just
+ // changed. The current state of the device is unclear.
+ //
+ Unclear = TRUE;
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return Unclear;
+}
+
+/**
+ Check if there is media error according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE Media error
+ @retval FALSE No media error
+
+**/
+BOOLEAN
+IsMediaError (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsError;
+
+ IsError = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+
+ case ATA_SK_MEDIUM_ERROR:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_ERR1:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR2:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR3:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR4:
+ IsError = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:
+ IsError = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return IsError;
+}
+
+/**
+ Check if drive is ready according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+ @param[out] NeedRetry Indicate if retry is needed.
+
+ @retval TRUE Drive ready
+ @retval FALSE Drive not ready
+
+**/
+BOOLEAN
+IsDriveReady (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *NeedRetry
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsReady;
+
+ IsReady = TRUE;
+ *NeedRetry = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_NOT_READY:
+ switch (SensePtr->addnl_sense_code_qualifier) {
+ case ATA_ASCQ_IN_PROGRESS:
+ IsReady = FALSE;
+ *NeedRetry = TRUE;
+ break;
+
+ default:
+ IsReady = FALSE;
+ *NeedRetry = FALSE;
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return IsReady;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.h b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.h
new file mode 100644
index 000000000..8851b1118
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.h
@@ -0,0 +1,782 @@
+/** @file
+Private Include file for IdeBus PEIM.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RECOVERY_ATAPI_H_
+#define _RECOVERY_ATAPI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/AtaController.h>
+
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+
+#include <IndustryStandard/Atapi.h>
+
+#define MAX_SENSE_KEY_COUNT 6
+#define MAX_IDE_CHANNELS 4 // Ide and Sata Primary, Secondary Channel.
+#define MAX_IDE_DEVICES 8 // Ide, Sata Primary, Secondary and Master, Slave device.
+
+typedef enum {
+ IdePrimary = 0,
+ IdeSecondary = 1,
+ IdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+ IdeMaster = 0,
+ IdeSlave = 1,
+ IdeMaxDevice = 2
+} EFI_IDE_DEVICE;
+
+//
+// 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;
+} IDE_BASE_REGISTERS;
+
+typedef struct {
+
+ UINTN DevicePosition;
+ EFI_PEI_BLOCK_IO_MEDIA MediaInfo;
+ EFI_PEI_BLOCK_IO2_MEDIA MediaInfo2;
+
+} PEI_ATAPI_DEVICE_INFO;
+
+#define ATAPI_BLK_IO_DEV_SIGNATURE SIGNATURE_32 ('a', 'b', 'i', 'o')
+typedef struct {
+ UINTN Signature;
+
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI AtapiBlkIo;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI AtapiBlkIo2;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor2;
+ PEI_ATA_CONTROLLER_PPI *AtaControllerPpi;
+
+ UINTN DeviceCount;
+ PEI_ATAPI_DEVICE_INFO DeviceInfo[MAX_IDE_DEVICES]; //for max 8 device
+ IDE_BASE_REGISTERS IdeIoPortReg[MAX_IDE_CHANNELS]; //for max 4 channel.
+} ATAPI_BLK_IO_DEV;
+
+#define PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS(a) CR (a, ATAPI_BLK_IO_DEV, AtapiBlkIo, ATAPI_BLK_IO_DEV_SIGNATURE)
+#define PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS(a) CR (a, ATAPI_BLK_IO_DEV, AtapiBlkIo2, ATAPI_BLK_IO_DEV_SIGNATURE)
+
+
+#define STALL_1_MILLI_SECOND 1000 // stall 1 ms
+#define STALL_1_SECONDS 1000 * STALL_1_MILLI_SECOND
+
+//
+// Time Out Value For IDE Device Polling
+//
+// ATATIMEOUT is used for waiting time out for ATA device
+//
+#define ATATIMEOUT 1000 // 1 second
+// ATAPITIMEOUT is used for waiting operation
+// except read and write time out for ATAPI device
+//
+#define ATAPITIMEOUT 1000 // 1 second
+// ATAPILONGTIMEOUT is used for waiting read and
+// write operation timeout for ATAPI device
+//
+#define CDROMLONGTIMEOUT 2000 // 2 seconds
+#define ATAPILONGTIMEOUT 5000 // 5 seconds
+
+//
+// PEI Recovery Block I/O PPI
+//
+
+/**
+ 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
+AtapiGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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
+AtapiGetBlockDeviceMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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
+AtapiReadBlocks (
+ 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
+ );
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiGetNumberOfBlockDevices2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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
+AtapiGetBlockDeviceMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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
+AtapiReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+//
+// Internal functions
+//
+
+/**
+ Enumerate Atapi devices.
+
+ This function is used to enumerate Atatpi device in Ide channel.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device
+
+**/
+VOID
+AtapiEnumerateDevices (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev
+ );
+
+/**
+ Detect Atapi devices.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[out] MediaInfo The media information of the specified block media.
+ @param[out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval TRUE Atapi device exists in specified position.
+ @retval FALSE Atapi device does not exist in specified position.
+
+**/
+BOOLEAN
+DiscoverAtapiDevice (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ );
+
+/**
+ Detect if an IDE controller exists in specified position.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval TRUE The Atapi device exists.
+ @retval FALSE The Atapi device does not present.
+
+**/
+BOOLEAN
+DetectIDEController (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ );
+
+/**
+ Wait specified time interval to poll for BSY bit clear in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS BSY bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT BSY bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Wait specified time interval to poll for DRDY bit set in the Status register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRDY bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRDY bit is not set in the specified time interval.
+
+**/
+EFI_STATUS
+DRDYReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Wait specified time interval to poll for DRQ bit clear in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+DRQClear (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Wait specified time interval to poll for DRQ bit clear in the Alternate Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Wait specified time interval to poll for DRQ bit set in the Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.
+ @retval EFI_ABORTED Operation Aborted.
+
+**/
+EFI_STATUS
+DRQReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Wait specified time interval to poll for DRQ bit set in the Alternate Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] IdeIoRegisters A pointer to IDE IO registers.
+ @param[in] TimeoutInMilliSeconds Time specified in milliseconds.
+
+ @retval EFI_SUCCESS DRQ bit is set in the specified time interval.
+ @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.
+ @retval EFI_ABORTED Operation Aborted.
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN IDE_BASE_REGISTERS *IdeIoRegisters,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Check if there is an error in Status Register.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] StatusReg The address to IDE IO registers.
+
+ @retval EFI_SUCCESS Operation success.
+ @retval EFI_DEVICE_ERROR Device error.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINT16 StatusReg
+ );
+
+/**
+ Idendify Atapi devices.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval EFI_SUCCESS Identify successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be identified successfully.
+
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ );
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+
+ @retval EFI_SUCCESS TestUnit command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
+
+**/
+EFI_STATUS
+TestUnitReady (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition
+ ) ;
+
+/**
+ Send out ATAPI commands conforms to the Packet Command with PIO Data In Protocol.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Packet A pointer to ATAPI command packet.
+ @param[in] Buffer Buffer to contain requested transfer data from device.
+ @param[in] ByteCount Requested transfer data length.
+ @param[in] TimeoutInMilliSeconds Time out value, in unit of milliseconds.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.
+
+**/
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return INQUIRY data of the device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[out] MediaInfo The media information of the specified block media.
+ @param[out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.
+ @retval EFI_UNSUPPORTED Unsupported device type.
+
+**/
+EFI_STATUS
+Inquiry (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ );
+
+/**
+ 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.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in, out] MediaInfo The media information of the specified block media.
+ @param[in, out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate required resources.
+
+**/
+EFI_STATUS
+DetectMedia (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ );
+
+/**
+ Reset specified Atapi device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Extensive If TRUE, use ATA soft reset, otherwise use Atapi soft reset.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ResetDevice (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN BOOLEAN Extensive
+ );
+
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] SenseBuffers Pointer to sense buffer.
+ @param[in, out] SenseCounts Length of sense buffer.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+RequestSense (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN ATAPI_REQUEST_SENSE_DATA *SenseBuffers,
+ IN OUT UINT8 *SenseCounts
+ );
+
+/**
+ 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.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in, out] MediaInfo The media information of the specified block media.
+ @param[in, out] MediaInfo2 The media information 2 of the specified block media.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ReadCapacity (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,
+ IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2
+ );
+
+/**
+ Perform read from disk in block unit.
+
+ @param[in] AtapiBlkIoDev A pointer to atapi block IO device.
+ @param[in] DevicePosition An integer to signify device position.
+ @param[in] Buffer Buffer to contain read data.
+ @param[in] StartLba Starting LBA address.
+ @param[in] NumberOfBlocks Number of blocks to read.
+ @param[in] BlockSize Size of each block.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+ReadSectors (
+ IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,
+ IN UINTN DevicePosition,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN UINTN BlockSize
+ );
+
+/**
+ Check if there is media according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE No media
+ @retval FALSE Media exists
+
+**/
+BOOLEAN
+IsNoMedia (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check if device state is unclear according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE Device state is unclear
+ @retval FALSE Device state is clear
+
+**/
+BOOLEAN
+IsDeviceStateUnclear (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check if there is media error according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+
+ @retval TRUE Media error
+ @retval FALSE No media error
+
+**/
+BOOLEAN
+IsMediaError (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check if drive is ready according to sense data.
+
+ @param[in] SenseData Pointer to sense data.
+ @param[in] SenseCounts Count of sense data.
+ @param[out] NeedRetry Indicate if retry is needed.
+
+ @retval TRUE Drive ready
+ @retval FALSE Drive not ready
+
+**/
+BOOLEAN
+IsDriveReady (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *NeedRetry
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf
new file mode 100644
index 000000000..ad50d4c0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf
@@ -0,0 +1,62 @@
+## @file
+# PEIM to produce gEfiPeiVirtualBlockIoPpiGuid PPI for ATA controllers in the platform.
+# This PPI can be consumed by PEIM which produce gEfiPeiDeviceRecoveryModulePpiGuid
+# for Atapi CD ROM device.
+#
+# This module discovers CDROM devices in Legacy and native mode and installs block IO ppis for them.
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IdeBusPei
+ MODULE_UNI_FILE = IdeBusPei.uni
+ FILE_GUID = B7A5041A-78BA-49e3-B73B-54C757811FB6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = AtapiPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ AtapiPeim.h
+ AtapiPeim.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ IoLib
+ BaseMemoryLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ TimerLib
+ PeiServicesTablePointerLib
+ MemoryAllocationLib
+ PcdLib
+
+[Ppis]
+ gPeiAtaControllerPpiGuid ## CONSUMES
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSataSpinUpDelayInSecForRecoveryPath ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiAtaControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IdeBusPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.uni
new file mode 100644
index 000000000..ee10591ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.uni
@@ -0,0 +1,19 @@
+// /** @file
+// PEIM to produce gEfiPeiVirtualBlockIoPpiGuid PPI for ATA controllers in the platform.
+//
+// This PPI can be consumed by PEIM which produce gEfiPeiDeviceRecoveryModulePpiGuid
+// for Atapi CD ROM device.
+//
+// This module discovers CDROM devices in Legacy and native mode and installs block IO ppis for them.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PEIM to produce gEfiPeiVirtualBlockIoPpiGuid PPI for ATA controllers in the platform"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This PPI can be consumed by PEIM, which produces gEfiPeiDeviceRecoveryModulePpiGuid for an Atapi CD ROM device. This module discovers CDROM devices in Legacy and native mode and installs block IO ppis for them."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPeiExtra.uni
new file mode 100644
index 000000000..acbe645a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IdeBusPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"IDE Bus PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
new file mode 100644
index 000000000..be9f873c3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c
@@ -0,0 +1,379 @@
+/** @file
+ This module is one template module for Incompatible PCI Device Support protocol.
+ It includes one incompatible pci devices list template.
+
+ Incompatible PCI Device Support protocol allows the PCI bus driver to support
+ resource allocation for some PCI devices that do not comply with the PCI Specification.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/IncompatiblePciDeviceSupport.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+
+typedef struct {
+ UINT64 VendorId;
+ UINT64 DeviceId;
+ UINT64 RevisionId;
+ UINT64 SubsystemVendorId;
+ UINT64 SubsystemDeviceId;
+} EFI_PCI_DEVICE_HEADER_INFO;
+
+typedef struct {
+ UINT64 ResType;
+ UINT64 GenFlag;
+ UINT64 SpecificFlag;
+ UINT64 AddrSpaceGranularity;
+ UINT64 AddrRangeMin;
+ UINT64 AddrRangeMax;
+ UINT64 AddrTranslationOffset;
+ UINT64 AddrLen;
+} EFI_PCI_RESOUCE_DESCRIPTOR;
+
+#define PCI_DEVICE_ID(VendorId, DeviceId, Revision, SubVendorId, SubDeviceId) \
+ VendorId, DeviceId, Revision, SubVendorId, SubDeviceId
+
+#define DEVICE_INF_TAG 0xFFF2
+#define DEVICE_RES_TAG 0xFFF1
+#define LIST_END_TAG 0x0000
+
+#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
+
+/**
+ Returns a list of ACPI resource descriptors that detail the special
+ resource configuration requirements for an incompatible PCI device.
+
+ @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
+ @param VendorId A unique ID to identify the manufacturer of the PCI device.
+ @param DeviceId A unique ID to identify the particular PCI device.
+ @param RevisionId A PCI device-specific revision identifier.
+ @param SubsystemVendorId Specifies the subsystem vendor ID.
+ @param SubsystemDeviceId Specifies the subsystem device ID.
+ @param Configuration A list of ACPI resource descriptors returned that detail
+ the configuration requirement.
+
+ @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+ @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PCheckDevice (
+ IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
+ IN UINTN VendorId,
+ IN UINTN DeviceId,
+ IN UINTN RevisionId,
+ IN UINTN SubsystemVendorId,
+ IN UINTN SubsystemDeviceId,
+ OUT VOID **Configuration
+ );
+
+//
+// Handle onto which the Incompatible PCI Device List is installed
+//
+EFI_HANDLE mIncompatiblePciDeviceSupportHandle = NULL;
+
+//
+// The Incompatible PCI Device Support Protocol instance produced by this driver
+//
+EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL mIncompatiblePciDeviceSupport = {
+ PCheckDevice
+};
+
+//
+// The incompatible PCI devices list template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mIncompatiblePciDeviceList[] = {
+ //
+ // DEVICE_INF_TAG,
+ // PCI_DEVICE_ID (VendorID, DeviceID, Revision, SubVendorId, SubDeviceId),
+ // DEVICE_RES_TAG,
+ // ResType, GFlag , SFlag, Granularity, RangeMin,
+ // RangeMax, Offset, AddrLen
+ //
+ //
+ // Device Adaptec 9004
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x9004, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
+ DEVICE_RES_TAG,
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ 0,
+ 0,
+ 0,
+ 0,
+ EVEN_ALIGN,
+ MAX_UINT64,
+ 0,
+ //
+ // Device Adaptec 9005
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x9005, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
+ DEVICE_RES_TAG,
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ 0,
+ 0,
+ 0,
+ 0,
+ EVEN_ALIGN,
+ MAX_UINT64,
+ 0,
+ //
+ // Device QLogic 1007
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x1077, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
+ DEVICE_RES_TAG,
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ 0,
+ 0,
+ 0,
+ 0,
+ EVEN_ALIGN,
+ MAX_UINT64,
+ 0,
+ //
+ // Device Agilent 103C
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x103C, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
+ DEVICE_RES_TAG,
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ 0,
+ 0,
+ 0,
+ 0,
+ EVEN_ALIGN,
+ MAX_UINT64,
+ 0,
+ //
+ // Device Agilent 15BC
+ //
+ DEVICE_INF_TAG,
+ PCI_DEVICE_ID(0x15BC, MAX_UINT64, MAX_UINT64, MAX_UINT64, MAX_UINT64),
+ DEVICE_RES_TAG,
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ 0,
+ 0,
+ 0,
+ 0,
+ EVEN_ALIGN,
+ MAX_UINT64,
+ 0,
+ //
+ // The end of the list
+ //
+ LIST_END_TAG
+};
+
+
+/**
+ Entry point of the incompatible pci device support code. Setup an incompatible device list template
+ and install EFI Incompatible PCI Device Support protocol.
+
+ @param ImageHandle A handle for the image that is initializing this driver.
+ @param SystemTable A pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Installed EFI Incompatible PCI Device Support Protocol successfully.
+ @retval others Failed to install protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+IncompatiblePciDeviceSupportEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install EFI Incompatible PCI Device Support Protocol on a new handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mIncompatiblePciDeviceSupportHandle,
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mIncompatiblePciDeviceSupport
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Returns a list of ACPI resource descriptors that detail the special
+ resource configuration requirements for an incompatible PCI device.
+
+ @param This Pointer to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL instance.
+ @param VendorId A unique ID to identify the manufacturer of the PCI device.
+ @param DeviceId A unique ID to identify the particular PCI device.
+ @param RevisionId A PCI device-specific revision identifier.
+ @param SubsystemVendorId Specifies the subsystem vendor ID.
+ @param SubsystemDeviceId Specifies the subsystem device ID.
+ @param Configuration A list of ACPI resource descriptors returned that detail
+ the configuration requirement.
+
+ @retval EFI_SUCCESS Successfully got ACPI resource for specified PCI device.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+ @retval EFI_UNSUPPORTED The specified PCI device wasn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PCheckDevice (
+ IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This,
+ IN UINTN VendorId,
+ IN UINTN DeviceId,
+ IN UINTN RevisionId,
+ IN UINTN SubsystemVendorId,
+ IN UINTN SubsystemDeviceId,
+ OUT VOID **Configuration
+ )
+{
+ UINT64 Tag;
+ UINT64 *ListPtr;
+ UINT64 *TempListPtr;
+ EFI_PCI_DEVICE_HEADER_INFO *Header;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr;
+ EFI_PCI_RESOUCE_DESCRIPTOR *Dsc;
+ EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
+ UINTN Index;
+
+ //
+ // Validate the parameters
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the return value to NULL
+ //
+ * (VOID **) Configuration = NULL;
+
+ ListPtr = mIncompatiblePciDeviceList;
+ while (*ListPtr != LIST_END_TAG) {
+
+ Tag = *ListPtr;
+
+ switch (Tag) {
+ case DEVICE_INF_TAG:
+ Header = (EFI_PCI_DEVICE_HEADER_INFO *) (ListPtr + 1);
+ ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_HEADER_INFO) / sizeof (UINT64);
+ //
+ // See if the Header matches the parameters passed in
+ //
+ if ((Header->VendorId != MAX_UINT64) && (VendorId != MAX_UINTN)) {
+ if (Header->VendorId != VendorId) {
+ continue;
+ }
+ }
+
+ if ((Header->DeviceId != MAX_UINT64) && (DeviceId != MAX_UINTN)) {
+ if (DeviceId != Header->DeviceId) {
+ continue;
+ }
+ }
+
+ if ((Header->RevisionId != MAX_UINT64) && (RevisionId != MAX_UINTN)) {
+ if (RevisionId != Header->RevisionId) {
+ continue;
+ }
+ }
+
+ if ((Header->SubsystemVendorId != MAX_UINT64) && (SubsystemVendorId != MAX_UINTN)) {
+ if (SubsystemVendorId != Header->SubsystemVendorId) {
+ continue;
+ }
+ }
+
+ if ((Header->SubsystemDeviceId != MAX_UINT64) && (SubsystemDeviceId != MAX_UINTN)) {
+ if (SubsystemDeviceId != Header->SubsystemDeviceId) {
+ continue;
+ }
+ }
+ //
+ // Matched an item, so construct the ACPI descriptor for the resource.
+ //
+ //
+ // Count the resource items so that to allocate space
+ //
+ for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) {
+ TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ }
+ //
+ // If there is at least one type of resource request,
+ // allocate an acpi resource node
+ //
+ if (Index == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ AcpiPtr = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (AcpiPtr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldAcpiPtr = AcpiPtr;
+ //
+ // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure
+ // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure
+ //
+ for (; *ListPtr == DEVICE_RES_TAG;) {
+
+ Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1);
+
+ AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ AcpiPtr->Len = (UINT16) sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ AcpiPtr->ResType = (UINT8) Dsc->ResType;
+ AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag;
+ AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag;
+ AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;;
+ AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin;
+ AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax;
+ AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset;
+ AcpiPtr->AddrLen = Dsc->AddrLen;
+
+ ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ AcpiPtr++;
+ }
+ //
+ // Put the checksum
+ //
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr);
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+
+ *(VOID **) Configuration = OldAcpiPtr;
+
+ return EFI_SUCCESS;
+
+ case DEVICE_RES_TAG:
+ //
+ // Adjust the pointer to the next PCI resource descriptor item
+ //
+ ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64));
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.uni b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.uni
new file mode 100644
index 000000000..f34c68c18
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PCI Incompatible device support module template.
+//
+// Installs EFI PCI Incompatible Device Support protocol and includes one incompatile
+// pci devices list template.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PCI Incompatible device support module template"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Installs EFI PCI Incompatible Device Support protocol and includes one incompatible PCI device list template."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
new file mode 100644
index 000000000..c4caac907
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
@@ -0,0 +1,48 @@
+## @file
+# PCI Incompatible device support module template.
+#
+# Installs EFI PCI Incompatible Device Support protocol and includes one incompatile
+# pci devices list template.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IncompatiblePciDeviceSupport
+ MODULE_UNI_FILE = IncompatiblePciDeviceSupport.uni
+ FILE_GUID = AD70855E-0CC5-4abf-8979-BE762A949EA3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = IncompatiblePciDeviceSupportEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ IncompatiblePciDeviceSupport.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ DebugLib
+
+[Protocols]
+ gEfiIncompatiblePciDeviceSupportProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IncompatiblePciDeviceSupportExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportExtra.uni
new file mode 100644
index 000000000..6114aed8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IncompatiblePciDeviceSupport Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Incompatible PCI Device Support DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/ComponentName.c
new file mode 100644
index 000000000..74b6e281b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/ComponentName.c
@@ -0,0 +1,116 @@
+/** @file
+
+ Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NonDiscoverablePciDeviceIo.h"
+
+//
+// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
+// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
+// in English, for display on standard console devices. This is recommended for
+// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
+// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
+//
+
+STATIC
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
+ { "eng;en", L"PCI I/O protocol emulation driver for non-discoverable devices" },
+ { NULL, NULL }
+};
+
+EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+
+/**
+ Retrieves a Unicode string that is the user readable name of the UEFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ @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.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gComponentName) // Iso639Language
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an UEFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param DeviceHandle 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 three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ @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.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciGetDeviceName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
+ &NonDiscoverablePciGetDriverName,
+ &NonDiscoverablePciGetDeviceName,
+ "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &NonDiscoverablePciGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &NonDiscoverablePciGetDeviceName,
+ "en" // SupportedLanguages, RFC 4646 language codes
+};
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
new file mode 100644
index 000000000..5c93e2a76
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
@@ -0,0 +1,283 @@
+/** @file
+
+ Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NonDiscoverablePciDeviceIo.h"
+
+#include <Protocol/DriverBinding.h>
+
+#define MAX_NON_DISCOVERABLE_PCI_DEVICE_ID (32 * 256)
+
+STATIC UINTN mUniqueIdCounter = 0;
+EFI_CPU_ARCH_PROTOCOL *mCpu;
+
+//
+// We only support the following device types
+//
+STATIC
+CONST EFI_GUID * CONST
+SupportedNonDiscoverableDevices[] = {
+ &gEdkiiNonDiscoverableAhciDeviceGuid,
+ &gEdkiiNonDiscoverableEhciDeviceGuid,
+ &gEdkiiNonDiscoverableNvmeDeviceGuid,
+ &gEdkiiNonDiscoverableOhciDeviceGuid,
+ &gEdkiiNonDiscoverableSdhciDeviceGuid,
+ &gEdkiiNonDiscoverableUfsDeviceGuid,
+ &gEdkiiNonDiscoverableUhciDeviceGuid,
+ &gEdkiiNonDiscoverableXhciDeviceGuid,
+};
+
+//
+// Probe, start and stop functions of this driver, called by the DXE core for
+// specific devices.
+//
+// The following specifications document these interfaces:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
+// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
+//
+// The implementation follows:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01
+// - 5.1.3.4 OpenProtocol() and CloseProtocol()
+// - UEFI Spec 2.3.1 + Errata C
+// - 6.3 Protocol Handler Services
+//
+
+/**
+ Supported function of Driver Binding protocol for this driver.
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param DeviceHandle Handle of device to test.
+ @param RemainingDevicePath A pointer to the device path.
+ it should be ignored by device driver.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciDeviceSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ NON_DISCOVERABLE_DEVICE *Device;
+ EFI_STATUS Status;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ INTN Idx;
+
+ Status = gBS->OpenProtocol (DeviceHandle,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,
+ This->DriverBindingHandle, DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {
+ if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocol;
+ }
+
+ //
+ // We only support MMIO devices, so iterate over the resources to ensure
+ // that they only describe things that we can handle
+ //
+ for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
+ if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR ||
+ Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+
+CloseProtocol:
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ This->DriverBindingHandle, DeviceHandle);
+
+ return Status;
+}
+
+/**
+ This routine is called right after the .Supported() called and
+ Start this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param DeviceHandle Handle of device to bind driver to.
+ @param RemainingDevicePath A pointer to the device path.
+ it should be ignored by device driver.
+
+ @retval EFI_SUCCESS This driver is added to this device.
+ @retval other Some error occurs when binding this driver to this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciDeviceStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+
+ ASSERT (mUniqueIdCounter < MAX_NON_DISCOVERABLE_PCI_DEVICE_ID);
+ if (mUniqueIdCounter >= MAX_NON_DISCOVERABLE_PCI_DEVICE_ID) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Dev = AllocateZeroPool (sizeof *Dev);
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->OpenProtocol (DeviceHandle,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ (VOID **)&Dev->Device, This->DriverBindingHandle,
+ DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR (Status)) {
+ goto FreeDev;
+ }
+
+ InitializePciIoProtocol (Dev);
+
+ //
+ // Setup complete, attempt to export the driver instance's
+ // EFI_PCI_IO_PROTOCOL interface.
+ //
+ Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG;
+ Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid,
+ EFI_NATIVE_INTERFACE, &Dev->PciIo);
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocol;
+ }
+
+ Dev->UniqueId = mUniqueIdCounter++;
+
+ return EFI_SUCCESS;
+
+CloseProtocol:
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ This->DriverBindingHandle, DeviceHandle);
+
+FreeDev:
+ FreePool (Dev);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param DeviceHandle Handle of device to stop driver on.
+ @param NumberOfChildren Not used.
+ @param ChildHandleBuffer Not used.
+
+ @retval EFI_SUCCESS This driver is removed from this device.
+ @retval other Some error occurs when removing this driver from this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciDeviceStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+
+ Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo);
+
+ //
+ // Handle Stop() requests for in-use driver instances gracefully.
+ //
+ Status = gBS->UninstallProtocolInterface (DeviceHandle,
+ &gEfiPciIoProtocolGuid, &Dev->PciIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ This->DriverBindingHandle, DeviceHandle);
+
+ FreePool (Dev);
+
+ return EFI_SUCCESS;
+}
+
+
+//
+// The static object that groups the Supported() (ie. probe), Start() and
+// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
+// C, 10.1 EFI Driver Binding Protocol.
+//
+STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
+ &NonDiscoverablePciDeviceSupported,
+ &NonDiscoverablePciDeviceStart,
+ &NonDiscoverablePciDeviceStop,
+ 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
+ NULL,
+ NULL
+};
+
+/**
+ Entry point of this driver.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+NonDiscoverablePciDeviceDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
+ ASSERT_EFI_ERROR(Status);
+
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDriverBinding,
+ ImageHandle,
+ &gComponentName,
+ &gComponentName2
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
new file mode 100644
index 000000000..a2850706e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
@@ -0,0 +1,50 @@
+## @file
+# PCI I/O driver for non-discoverable devices.
+#
+# Copyright (C) 2016, Linaro Ltd.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = NonDiscoverablePciDeviceDxe
+ FILE_GUID = 71fd84cd-353b-464d-b7a4-6ea7b96995cb
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = NonDiscoverablePciDeviceDxeEntryPoint
+
+[Sources]
+ ComponentName.c
+ NonDiscoverablePciDeviceDxe.c
+ NonDiscoverablePciDeviceIo.c
+ NonDiscoverablePciDeviceIo.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## BY_START
+ gEdkiiNonDiscoverableDeviceProtocolGuid ## TO_START
+ gEfiCpuArchProtocolGuid ## CONSUMES
+
+[Guids]
+ gEdkiiNonDiscoverableAhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableEhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableNvmeDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableOhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableSdhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableUfsDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableUhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableXhciDeviceGuid ## CONSUMES ## GUID
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
new file mode 100644
index 000000000..a40c1a959
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
@@ -0,0 +1,1700 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NonDiscoverablePciDeviceIo.h"
+
+#include <Library/DxeServicesTableLib.h>
+
+#include <IndustryStandard/Acpi.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS AllocAddress;
+ VOID *HostAddress;
+ EFI_PCI_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;
+
+/**
+ Get the resource associated with BAR number 'BarIndex'.
+
+ @param Dev Point to the NON_DISCOVERABLE_PCI_DEVICE instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Descriptor Points to the address space descriptor
+**/
+STATIC
+EFI_STATUS
+GetBarResource (
+ IN NON_DISCOVERABLE_PCI_DEVICE *Dev,
+ IN UINT8 BarIndex,
+ OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+
+ if (BarIndex < Dev->BarOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ BarIndex -= (UINT8)Dev->BarOffset;
+
+ if (BarIndex >= Dev->BarCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ for (Desc = Dev->Device->Resources;
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
+
+ if (BarIndex == 0) {
+ *Descriptor = Desc;
+ return EFI_SUCCESS;
+ }
+
+ BarIndex -= 1;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ UINTN Count;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Count = 1;
+
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ UINTN Count;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Count = 1;
+
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param DstStride The stride of the destination buffer.
+ @param Dst For read operations, the destination buffer to store the results. For write
+ operations, the destination buffer to write data to.
+ @param SrcStride The stride of the source buffer.
+ @param Src For read operations, the source buffer to read data from. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoMemRW (
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINTN DstStride,
+ IN VOID *Dst,
+ IN UINTN SrcStride,
+ OUT CONST VOID *Src
+ )
+{
+ volatile UINT8 *Dst8;
+ volatile UINT16 *Dst16;
+ volatile UINT32 *Dst32;
+ volatile CONST UINT8 *Src8;
+ volatile CONST UINT16 *Src16;
+ volatile CONST UINT32 *Src32;
+
+ //
+ // Loop for each iteration and move the data
+ //
+ switch (Width & 0x3) {
+ case EfiPciWidthUint8:
+ Dst8 = (UINT8 *)Dst;
+ Src8 = (UINT8 *)Src;
+ for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
+ *Dst8 = *Src8;
+ }
+ break;
+ case EfiPciWidthUint16:
+ Dst16 = (UINT16 *)Dst;
+ Src16 = (UINT16 *)Src;
+ for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
+ *Dst16 = *Src16;
+ }
+ break;
+ case EfiPciWidthUint32:
+ Dst32 = (UINT32 *)Dst;
+ Src32 = (UINT32 *)Src;
+ for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
+ *Dst32 = *Src32;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ UINTN AlignMask;
+ VOID *Address;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ //
+ // Only allow accesses to the BARs we emulate
+ //
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
+ AlignMask = (1 << (Width & 0x03)) - 1;
+ if ((UINTN)Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Width) {
+ case EfiPciIoWidthUint8:
+ case EfiPciIoWidthUint16:
+ case EfiPciIoWidthUint32:
+ case EfiPciIoWidthUint64:
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
+
+ case EfiPciIoWidthFifoUint8:
+ case EfiPciIoWidthFifoUint16:
+ case EfiPciIoWidthFifoUint32:
+ case EfiPciIoWidthFifoUint64:
+ return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);
+
+ case EfiPciIoWidthFillUint8:
+ case EfiPciIoWidthFillUint16:
+ case EfiPciIoWidthFillUint32:
+ case EfiPciIoWidthFillUint64:
+ return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);
+
+ default:
+ break;
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ UINTN AlignMask;
+ VOID *Address;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ //
+ // Only allow accesses to the BARs we emulate
+ //
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
+ AlignMask = (1 << (Width & 0x03)) - 1;
+ if ((UINTN)Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Width) {
+ case EfiPciIoWidthUint8:
+ case EfiPciIoWidthUint16:
+ case EfiPciIoWidthUint32:
+ case EfiPciIoWidthUint64:
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
+
+ case EfiPciIoWidthFifoUint8:
+ case EfiPciIoWidthFifoUint16:
+ case EfiPciIoWidthFifoUint32:
+ case EfiPciIoWidthFifoUint64:
+ return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);
+
+ case EfiPciIoWidthFillUint8:
+ case EfiPciIoWidthFillUint16:
+ case EfiPciIoWidthFillUint32:
+ case EfiPciIoWidthFillUint64:
+ return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);
+
+ default:
+ break;
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Enable a PCI driver to access PCI config space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoPciRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ VOID *Address;
+ UINTN Length;
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;
+ Length = Count << ((UINTN)Width & 0x3);
+
+ if (Offset >= sizeof (Dev->ConfigSpace)) {
+ ZeroMem (Buffer, Length);
+ return EFI_SUCCESS;
+ }
+
+ if (Offset + Length > sizeof (Dev->ConfigSpace)) {
+ //
+ // Read all zeroes for config space accesses beyond the first
+ // 64 bytes
+ //
+ Length -= sizeof (Dev->ConfigSpace) - Offset;
+ ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);
+
+ Count -= Length >> ((UINTN)Width & 0x3);
+ }
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
+}
+
+/**
+ Enable a PCI driver to access PCI config space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoPciWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ VOID *Address;
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;
+
+ if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
+}
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *DestDesc;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *SrcDesc;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = GetBarResource (Dev, DestBarIndex, &DestDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DestOffset + (Count << (Width & 0x3)) > DestDesc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = GetBarResource (Dev, SrcBarIndex, &SrcDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SrcOffset + (Count << (Width & 0x3)) > SrcDesc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentPciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+
+ if (Operation != EfiPciIoOperationBusMasterRead &&
+ Operation != EfiPciIoOperationBusMasterWrite &&
+ Operation != EfiPciIoOperationBusMasterCommonBuffer) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HostAddress == NULL ||
+ NumberOfBytes == NULL ||
+ DeviceAddress == NULL ||
+ Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
+ // addressing, we need to allocate a bounce buffer and copy over the data.
+ //
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
+
+ //
+ // Bounce buffering is not possible for consistent mappings
+ //
+ if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MapInfo = AllocatePool (sizeof *MapInfo);
+ if (MapInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MapInfo->AllocAddress = MAX_UINT32;
+ MapInfo->HostAddress = HostAddress;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+ &MapInfo->AllocAddress);
+ if (EFI_ERROR (Status)) {
+ //
+ // If we fail here, it is likely because the system has no memory below
+ // 4 GB to begin with. There is not much we can do about that other than
+ // fail the map request.
+ //
+ FreePool (MapInfo);
+ return EFI_DEVICE_ERROR;
+ }
+ if (Operation == EfiPciIoOperationBusMasterRead) {
+ gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,
+ *NumberOfBytes);
+ }
+ *DeviceAddress = MapInfo->AllocAddress;
+ *Mapping = MapInfo;
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentPciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+
+ MapInfo = Mapping;
+ if (MapInfo != NULL) {
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+ gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
+ MapInfo->NumberOfBytes);
+ }
+ gBS->FreePages (MapInfo->AllocAddress,
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));
+ FreePool (MapInfo);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentPciIoAllocateBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_PHYSICAL_ADDRESS AllocAddress;
+ EFI_ALLOCATE_TYPE AllocType;
+ EFI_STATUS Status;
+
+ if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((MemoryType != EfiBootServicesData) &&
+ (MemoryType != EfiRuntimeServicesData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate below 4 GB if the dual address cycle attribute has not
+ // been set. If the system has no memory available below 4 GB, there
+ // is little we can do except propagate the error.
+ //
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+ AllocAddress = MAX_UINT32;
+ AllocType = AllocateMaxAddress;
+ } else {
+ AllocType = AllocateAnyPages;
+ }
+
+ Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);
+ if (!EFI_ERROR (Status)) {
+ *HostAddress = (VOID *)(UINTN)AllocAddress;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentPciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ FreePages (HostAddress, Pages);
+ return EFI_SUCCESS;
+}
+
+/**
+ Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval others The operation contain some errors.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentPciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+ NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
+ BOOLEAN Found;
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Found = FALSE;
+ Alloc = NULL;
+
+ //
+ // Find the uncached allocation list entry associated
+ // with this allocation
+ //
+ for (Entry = Dev->UncachedAllocationList.ForwardLink;
+ Entry != &Dev->UncachedAllocationList;
+ Entry = Entry->ForwardLink) {
+
+ Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);
+ if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {
+ //
+ // We are freeing the exact allocation we were given
+ // before by AllocateBuffer()
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ return EFI_NOT_FOUND;
+ }
+
+ RemoveEntryList (&Alloc->List);
+
+ Status = gDS->SetMemorySpaceAttributes (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ Alloc->Attributes);
+ if (EFI_ERROR (Status)) {
+ goto FreeAlloc;
+ }
+
+ //
+ // If we fail to restore the original attributes, it is better to leak the
+ // memory than to return it to the heap
+ //
+ FreePages (HostAddress, Pages);
+
+FreeAlloc:
+ FreePool (Alloc);
+ return Status;
+}
+
+/**
+ Allocates pages.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentPciIoAllocateBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+ EFI_STATUS Status;
+ UINT64 MemType;
+ NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
+ VOID *AllocAddress;
+
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
+ &AllocAddress, Attributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gDS->GetMemorySpaceDescriptor (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+ &GcdDescriptor);
+ if (EFI_ERROR (Status)) {
+ goto FreeBuffer;
+ }
+
+ if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {
+ Status = EFI_UNSUPPORTED;
+ goto FreeBuffer;
+ }
+
+ //
+ // Set the preferred memory attributes
+ //
+ if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||
+ (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {
+ //
+ // Use write combining if it was requested, or if it is the only
+ // type supported by the region.
+ //
+ MemType = EFI_MEMORY_WC;
+ } else {
+ MemType = EFI_MEMORY_UC;
+ }
+
+ Alloc = AllocatePool (sizeof *Alloc);
+ if (Alloc == NULL) {
+ goto FreeBuffer;
+ }
+
+ Alloc->HostAddress = AllocAddress;
+ Alloc->NumPages = Pages;
+ Alloc->Attributes = GcdDescriptor.Attributes;
+
+ //
+ // Record this allocation in the linked list, so we
+ // can restore the memory space attributes later
+ //
+ InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
+
+ Status = gDS->SetMemorySpaceAttributes (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ MemType);
+ if (EFI_ERROR (Status)) {
+ goto RemoveList;
+ }
+
+ Status = mCpu->FlushDataCache (
+ mCpu,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ EfiCpuFlushTypeInvalidate);
+ if (EFI_ERROR (Status)) {
+ goto RemoveList;
+ }
+
+ *HostAddress = AllocAddress;
+
+ return EFI_SUCCESS;
+
+RemoveList:
+ RemoveEntryList (&Alloc->List);
+ FreePool (Alloc);
+
+FreeBuffer:
+ CoherentPciIoFreeBuffer (This, Pages, AllocAddress);
+ return Status;
+}
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentPciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+ UINTN AlignMask;
+ VOID *AllocAddress;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+ BOOLEAN Bounce;
+
+ if (HostAddress == NULL ||
+ NumberOfBytes == NULL ||
+ DeviceAddress == NULL ||
+ Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Operation != EfiPciIoOperationBusMasterRead &&
+ Operation != EfiPciIoOperationBusMasterWrite &&
+ Operation != EfiPciIoOperationBusMasterCommonBuffer) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MapInfo = AllocatePool (sizeof *MapInfo);
+ if (MapInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MapInfo->HostAddress = HostAddress;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ //
+ // If this device does not support 64-bit DMA addressing, we need to allocate
+ // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
+ //
+ Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);
+
+ if (!Bounce) {
+ switch (Operation) {
+ case EfiPciIoOperationBusMasterRead:
+ case EfiPciIoOperationBusMasterWrite:
+ //
+ // For streaming DMA, it is sufficient if the buffer is aligned to
+ // the CPUs DMA buffer alignment.
+ //
+ AlignMask = mCpu->DmaBufferAlignment - 1;
+ if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {
+ break;
+ }
+ // fall through
+
+ case EfiPciIoOperationBusMasterCommonBuffer:
+ //
+ // Check whether the host address refers to an uncached mapping.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+ &GcdDescriptor);
+ if (EFI_ERROR (Status) ||
+ (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {
+ Bounce = TRUE;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+ }
+
+ if (Bounce) {
+ if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
+ Status = EFI_DEVICE_ERROR;
+ goto FreeMapInfo;
+ }
+
+ Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
+ EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+ &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);
+ if (EFI_ERROR (Status)) {
+ goto FreeMapInfo;
+ }
+ MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
+ if (Operation == EfiPciIoOperationBusMasterRead) {
+ gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
+ }
+ *DeviceAddress = MapInfo->AllocAddress;
+ } else {
+ MapInfo->AllocAddress = 0;
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+
+ //
+ // We are not using a bounce buffer: the mapping is sufficiently
+ // aligned to allow us to simply flush the caches. Note that cleaning
+ // the caches is necessary for both data directions:
+ // - for bus master read, we want the latest data to be present
+ // in main memory
+ // - for bus master write, we don't want any stale dirty cachelines that
+ // may be written back unexpectedly, and clobber the data written to
+ // main memory by the device.
+ //
+ mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+ *NumberOfBytes, EfiCpuFlushTypeWriteBack);
+ }
+
+ *Mapping = MapInfo;
+ return EFI_SUCCESS;
+
+FreeMapInfo:
+ FreePool (MapInfo);
+
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentPciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+
+ if (Mapping == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ MapInfo = Mapping;
+ if (MapInfo->AllocAddress != 0) {
+ //
+ // We are using a bounce buffer: copy back the data if necessary,
+ // and free the buffer.
+ //
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+ gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
+ MapInfo->NumberOfBytes);
+ }
+ NonCoherentPciIoFreeBuffer (This,
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+ (VOID *)(UINTN)MapInfo->AllocAddress);
+ } else {
+ //
+ // We are *not* using a bounce buffer: if this is a bus master write,
+ // we have to invalidate the caches so the CPU will see the uncached
+ // data written by the device.
+ //
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+ mCpu->FlushDataCache (mCpu,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
+ MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
+ }
+ }
+ FreePool (MapInfo);
+ return EFI_SUCCESS;
+}
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *SegmentNumber,
+ OUT UINTN *BusNumber,
+ OUT UINTN *DeviceNumber,
+ OUT UINTN *FunctionNumber
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+
+ if (SegmentNumber == NULL ||
+ BusNumber == NULL ||
+ DeviceNumber == NULL ||
+ FunctionNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ *SegmentNumber = 0xff;
+ *BusNumber = Dev->UniqueId >> 5;
+ *DeviceNumber = Dev->UniqueId & 0x1f;
+ *FunctionNumber = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ BOOLEAN Enable;
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ if ((Attributes & (~(DEV_SUPPORTED_ATTRIBUTES))) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Enable = FALSE;
+ switch (Operation) {
+ case EfiPciIoAttributeOperationGet:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Result = Dev->Attributes;
+ break;
+
+ case EfiPciIoAttributeOperationSupported:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Result = DEV_SUPPORTED_ATTRIBUTES;
+ break;
+
+ case EfiPciIoAttributeOperationEnable:
+ Attributes |= Dev->Attributes;
+ case EfiPciIoAttributeOperationSet:
+ Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;
+ Dev->Attributes = Attributes;
+ break;
+
+ case EfiPciIoAttributeOperationDisable:
+ Dev->Attributes &= ~Attributes;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ };
+
+ //
+ // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
+ // the device specific initialization now.
+ //
+ if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
+ Dev->Device->Initialize (Dev->Device);
+ Dev->Enabled = TRUE;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports OPTIONAL,
+ OUT VOID **Resources OPTIONAL
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ EFI_STATUS Status;
+
+ if (Supports == NULL && Resources == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = GetBarResource (Dev, BarIndex, &BarDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Don't expose any configurable attributes for our emulated BAR
+ //
+ if (Supports != NULL) {
+ *Supports = 0;
+ }
+
+ if (Resources != NULL) {
+ Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Descriptor == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
+
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ *Resources = Descriptor;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+ UINTN Count;
+ EFI_STATUS Status;
+
+ if ((Attributes & (~DEV_SUPPORTED_ATTRIBUTES)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Offset == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Width = EfiPciIoWidthUint8;
+ Count = (UINT32) *Length;
+
+ Status = GetBarResource(Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =
+{
+ PciIoPollMem,
+ PciIoPollIo,
+ { PciIoMemRead, PciIoMemWrite },
+ { PciIoIoRead, PciIoIoWrite },
+ { PciIoPciRead, PciIoPciWrite },
+ PciIoCopyMem,
+ CoherentPciIoMap,
+ CoherentPciIoUnmap,
+ CoherentPciIoAllocateBuffer,
+ CoherentPciIoFreeBuffer,
+ PciIoFlush,
+ PciIoGetLocation,
+ PciIoAttributes,
+ PciIoGetBarAttributes,
+ PciIoSetBarAttributes,
+ 0,
+ 0
+};
+
+/**
+ Initialize PciIo Protocol.
+
+ @param Dev Point to NON_DISCOVERABLE_PCI_DEVICE instance.
+
+**/
+VOID
+InitializePciIoProtocol (
+ NON_DISCOVERABLE_PCI_DEVICE *Dev
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ INTN Idx;
+
+ InitializeListHead (&Dev->UncachedAllocationList);
+
+ Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
+ Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
+
+ // Copy protocol structure
+ CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
+
+ if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {
+ Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
+ Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
+ Dev->PciIo.Map = NonCoherentPciIoMap;
+ Dev->PciIo.Unmap = NonCoherentPciIoUnmap;
+ }
+
+ if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 5;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableEhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableNvmeDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableOhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableSdhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableXhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableUhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableUfsDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 0;
+ } else {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Iterate over the resources to populate the virtual BARs
+ //
+ Idx = Dev->BarOffset;
+ for (Desc = Dev->Device->Resources, Dev->BarCount = 0;
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
+
+ ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
+
+ if (Idx >= PCI_MAX_BAR ||
+ (Idx == PCI_MAX_BAR - 1 && Desc->AddrSpaceGranularity == 64)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: resource count exceeds number of emulated BARs\n",
+ __FUNCTION__));
+ ASSERT (FALSE);
+ break;
+ }
+
+ Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
+ Dev->BarCount++;
+
+ if (Desc->AddrSpaceGranularity == 64) {
+ Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
+ Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (
+ Desc->AddrRangeMin, 32);
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.h b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.h
new file mode 100644
index 000000000..3e6df3beb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.h
@@ -0,0 +1,120 @@
+/** @file
+
+ Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __NON_DISCOVERABLE_PCI_DEVICE_IO_H__
+#define __NON_DISCOVERABLE_PCI_DEVICE_IO_H__
+
+#include <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/NonDiscoverableDevice.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/PciIo.h>
+
+#define NON_DISCOVERABLE_PCI_DEVICE_SIG SIGNATURE_32 ('P', 'P', 'I', 'D')
+
+#define NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(PciIoPointer) \
+ CR (PciIoPointer, NON_DISCOVERABLE_PCI_DEVICE, PciIo, \
+ NON_DISCOVERABLE_PCI_DEVICE_SIG)
+
+#define DEV_SUPPORTED_ATTRIBUTES \
+ (EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define PCI_ID_VENDOR_UNKNOWN 0xffff
+#define PCI_ID_DEVICE_DONTCARE 0x0000
+
+extern EFI_CPU_ARCH_PROTOCOL *mCpu;
+
+typedef struct {
+ //
+ // The linked-list next pointer
+ //
+ LIST_ENTRY List;
+ //
+ // The address of the uncached allocation
+ //
+ VOID *HostAddress;
+ //
+ // The number of pages in the allocation
+ //
+ UINTN NumPages;
+ //
+ // The attributes of the allocation
+ //
+ UINT64 Attributes;
+} NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION;
+
+typedef struct {
+ UINT32 Signature;
+ //
+ // The bound non-discoverable device protocol instance
+ //
+ NON_DISCOVERABLE_DEVICE *Device;
+ //
+ // The exposed PCI I/O protocol instance.
+ //
+ EFI_PCI_IO_PROTOCOL PciIo;
+ //
+ // The emulated PCI config space of the device. Only the minimally required
+ // items are assigned.
+ //
+ PCI_TYPE00 ConfigSpace;
+ //
+ // The first virtual BAR to assign based on the resources described
+ // by the non-discoverable device.
+ //
+ UINT32 BarOffset;
+ //
+ // The number of virtual BARs we expose based on the number of
+ // resources
+ //
+ UINT32 BarCount;
+ //
+ // The PCI I/O attributes for this device
+ //
+ UINT64 Attributes;
+ //
+ // Whether this device has been enabled
+ //
+ BOOLEAN Enabled;
+ //
+ // Linked list to keep track of uncached allocations performed
+ // on behalf of this device
+ //
+ LIST_ENTRY UncachedAllocationList;
+ //
+ // Unique ID for this device instance: needed so that we can report unique
+ // segment/bus/device number for each device instance. Note that this number
+ // may change when disconnecting/reconnecting the driver.
+ //
+ UINTN UniqueId;
+} NON_DISCOVERABLE_PCI_DEVICE;
+
+/**
+ Initialize PciIo Protocol.
+
+ @param Device Point to NON_DISCOVERABLE_PCI_DEVICE instance.
+
+**/
+VOID
+InitializePciIoProtocol (
+ NON_DISCOVERABLE_PCI_DEVICE *Device
+ );
+
+extern EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c
new file mode 100644
index 000000000..7ef345eec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c
@@ -0,0 +1,227 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNvmExpressComponentName = {
+ NvmExpressComponentNameGetDriverName,
+ NvmExpressComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNvmExpressComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) NvmExpressComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) NvmExpressComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mNvmExpressDriverNameTable[] = {
+ { "eng;en", L"NVM Express Driver" },
+ { NULL, NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mNvmExpressControllerNameTable[] = {
+ { "eng;en", L"NVM Express 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
+NvmExpressComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mNvmExpressDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gNvmExpressComponentName)
+ );
+}
+
+/**
+ 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
+NvmExpressComponentNameGetControllerName (
+ 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;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gNvmExpressDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = mNvmExpressControllerNameTable;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiNvmExpressPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gNvmExpressDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);
+ ControllerNameTable = Device->ControllerNameTable;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gNvmExpressComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
new file mode 100644
index 000000000..62886d5c9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
@@ -0,0 +1,1422 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+//
+// NVM Express Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding = {
+ NvmExpressDriverBindingSupported,
+ NvmExpressDriverBindingStart,
+ NvmExpressDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// NVM Express EFI Driver Supported EFI Version Protocol Instance
+//
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion = {
+ sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.
+ 0 // Version number to be filled at start up.
+};
+
+//
+// Template for NVM Express Pass Thru Mode data structure.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_NVM_EXPRESS_PASS_THRU_MODE gEfiNvmExpressPassThruMode = {
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_NONBLOCKIO |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM,
+ sizeof (UINTN),
+ 0x10100
+};
+
+/**
+ Check if the specified Nvm Express device namespace is active, and create child handles
+ for them with BlockIo and DiskInfo protocol instances.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+
+ @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
+ @return Others Some error occurs when enumerating the namespaces.
+
+**/
+EFI_STATUS
+EnumerateNvmeDevNamespace (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ UINT32 NamespaceId
+ )
+{
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ UINT32 Lbads;
+ UINT32 Flbas;
+ UINT32 LbaFmtIdx;
+ UINT8 Sn[21];
+ UINT8 Mn[41];
+ VOID *DummyInterface;
+
+ NewDevicePathNode = NULL;
+ DevicePath = NULL;
+ Device = NULL;
+
+ //
+ // Allocate a buffer for Identify Namespace data
+ //
+ NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ if(NamespaceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ParentDevicePath = Private->ParentDevicePath;
+ //
+ // Identify Namespace
+ //
+ Status = NvmeIdentifyNamespace (
+ Private,
+ NamespaceId,
+ (VOID *)NamespaceData
+ );
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+ //
+ // Validate Namespace
+ //
+ if (NamespaceData->Ncap == 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ //
+ // allocate device private data for each discovered namespace
+ //
+ Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));
+ if (Device == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Initialize SSD namespace instance data
+ //
+ Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;
+ Device->NamespaceId = NamespaceId;
+ Device->NamespaceUuid = NamespaceData->Eui64;
+
+ Device->ControllerHandle = Private->ControllerHandle;
+ Device->DriverBindingHandle = Private->DriverBindingHandle;
+ Device->Controller = Private;
+
+ //
+ // Build BlockIo media structure
+ //
+ Device->Media.MediaId = 0;
+ Device->Media.RemovableMedia = FALSE;
+ Device->Media.MediaPresent = TRUE;
+ Device->Media.LogicalPartition = FALSE;
+ Device->Media.ReadOnly = FALSE;
+ Device->Media.WriteCaching = FALSE;
+ Device->Media.IoAlign = Private->PassThruMode.IoAlign;
+
+ Flbas = NamespaceData->Flbas;
+ LbaFmtIdx = Flbas & 0xF;
+ Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
+ Device->Media.BlockSize = (UINT32)1 << Lbads;
+
+ Device->Media.LastBlock = NamespaceData->Nsze - 1;
+ Device->Media.LogicalBlocksPerPhysicalBlock = 1;
+ Device->Media.LowestAlignedLba = 1;
+
+ //
+ // Create BlockIo Protocol instance
+ //
+ Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
+ Device->BlockIo.Media = &Device->Media;
+ Device->BlockIo.Reset = NvmeBlockIoReset;
+ Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;
+ Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;
+ Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;
+
+ //
+ // Create BlockIo2 Protocol instance
+ //
+ Device->BlockIo2.Media = &Device->Media;
+ Device->BlockIo2.Reset = NvmeBlockIoResetEx;
+ Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;
+ Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;
+ Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;
+ InitializeListHead (&Device->AsyncQueue);
+
+ //
+ // Create StorageSecurityProtocol Instance
+ //
+ Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;
+ Device->StorageSecurity.SendData = NvmeStorageSecuritySendData;
+
+ //
+ // Create DiskInfo Protocol instance
+ //
+ CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ InitializeDiskInfo (Device);
+
+ //
+ // Create a Nvm Express Namespace Device Path Node
+ //
+ Status = Private->Passthru.BuildDevicePath (
+ &Private->Passthru,
+ Device->NamespaceId,
+ &NewDevicePathNode
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+
+ //
+ // Append the SSD node to the controller's device path
+ //
+ DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ FreePool (DevicePath);
+ goto Exit;
+ }
+
+ Device->DevicePath = DevicePath;
+
+ //
+ // Make sure the handle is NULL so we create a new handle
+ //
+ Device->DeviceHandle = NULL;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Device->DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ Device->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Device->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Device->BlockIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &Device->DiskInfo,
+ NULL
+ );
+
+ if(EFI_ERROR(Status)) {
+ goto Exit;
+ }
+
+ //
+ // Check if the NVMe controller supports the Security Send and Security Receive commands
+ //
+ if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
+ Status = gBS->InstallProtocolInterface (
+ &Device->DeviceHandle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Device->StorageSecurity
+ );
+ if(EFI_ERROR(Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Device->DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ Device->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Device->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Device->BlockIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &Device->DiskInfo,
+ NULL
+ );
+ goto Exit;
+ }
+ }
+
+ gBS->OpenProtocol (
+ Private->ControllerHandle,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &DummyInterface,
+ Private->DriverBindingHandle,
+ Device->DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ //
+ // Dump NvmExpress Identify Namespace Data
+ //
+ DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));
+ DEBUG ((EFI_D_INFO, " NSZE : 0x%x\n", NamespaceData->Nsze));
+ DEBUG ((EFI_D_INFO, " NCAP : 0x%x\n", NamespaceData->Ncap));
+ DEBUG ((EFI_D_INFO, " NUSE : 0x%x\n", NamespaceData->Nuse));
+ DEBUG ((EFI_D_INFO, " LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));
+
+ //
+ // Build controller name for Component Name (2) protocol.
+ //
+ CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));
+ Sn[20] = 0;
+ CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));
+ Mn[40] = 0;
+ UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Sn, Mn, NamespaceData->Eui64);
+
+ AddUnicodeString2 (
+ "eng",
+ gNvmExpressComponentName.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ TRUE
+ );
+
+ AddUnicodeString2 (
+ "en",
+ gNvmExpressComponentName2.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ FALSE
+ );
+ }
+
+Exit:
+ if(NamespaceData != NULL) {
+ FreePool (NamespaceData);
+ }
+
+ if (NewDevicePathNode != NULL) {
+ FreePool (NewDevicePathNode);
+ }
+
+ if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {
+ FreePool (Device->DevicePath);
+ }
+ if(EFI_ERROR(Status) && (Device != NULL)) {
+ FreePool (Device);
+ }
+ return Status;
+}
+
+/**
+ Discover all Nvm Express device namespaces, and create child handles for them with BlockIo
+ and DiskInfo protocol instances.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
+ @return Others Some error occurs when enumerating the namespaces.
+
+**/
+EFI_STATUS
+DiscoverAllNamespaces (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NamespaceId;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;
+
+ NamespaceId = 0xFFFFFFFF;
+ Passthru = &Private->Passthru;
+
+ while (TRUE) {
+ Status = Passthru->GetNextNamespace (
+ Passthru,
+ (UINT32 *)&NamespaceId
+ );
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = EnumerateNvmeDevNamespace (
+ Private,
+ NamespaceId
+ );
+
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregisters a Nvm Express device namespace.
+
+ This function removes the protocols installed on the controller handle and
+ frees the resources allocated for the namespace.
+
+ @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The controller handle of the namespace.
+ @param Handle The child handle.
+
+ @retval EFI_SUCCESS The namespace is successfully unregistered.
+ @return Others Some error occurs when unregistering the namespace.
+
+**/
+EFI_STATUS
+UnregisterNvmeNamespace (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+ VOID *DummyInterface;
+
+ BlockIo = NULL;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);
+
+ //
+ // Wait for the device's asynchronous I/O queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ //
+ // Close the child handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().
+ // Here should uninstall both of them.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ Device->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Device->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Device->BlockIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &Device->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &DummyInterface,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // If Storage Security Command Protocol is installed, then uninstall this protocol.
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **) &StorageSecurity,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallProtocolInterface (
+ Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &Device->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &DummyInterface,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+ }
+
+ if(Device->DevicePath != NULL) {
+ FreePool (Device->DevicePath);
+ }
+
+ if (Device->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (Device->ControllerNameTable);
+ }
+
+ FreePool (Device);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ NVME_CQ *Cq;
+ UINT16 QueueId;
+ UINT32 Data;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
+ NVME_BLKIO2_SUBTASK *Subtask;
+ NVME_BLKIO2_REQUEST *BlkIo2Request;
+ EFI_BLOCK_IO2_TOKEN *Token;
+ BOOLEAN HasNewItem;
+ EFI_STATUS Status;
+
+ Private = (NVME_CONTROLLER_PRIVATE_DATA*)Context;
+ QueueId = 2;
+ Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
+ HasNewItem = FALSE;
+ PciIo = Private->PciIo;
+
+ //
+ // Submit asynchronous subtasks to the NVMe Submission Queue
+ //
+ for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
+ !IsNull (&Private->UnsubmittedSubtasks, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);
+ Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
+ BlkIo2Request = Subtask->BlockIo2Request;
+ Token = BlkIo2Request->Token;
+ RemoveEntryList (Link);
+ BlkIo2Request->UnsubmittedSubtaskNum--;
+
+ //
+ // If any previous subtask fails, do not process subsequent ones.
+ //
+ if (Token->TransactionStatus != EFI_SUCCESS) {
+ if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
+ BlkIo2Request->LastSubtaskSubmitted &&
+ (BlkIo2Request->UnsubmittedSubtaskNum == 0)) {
+ //
+ // Remove the BlockIo2 request from the device asynchronous queue.
+ //
+ RemoveEntryList (&BlkIo2Request->Link);
+ FreePool (BlkIo2Request);
+ gBS->SignalEvent (Token->Event);
+ }
+
+ FreePool (Subtask->CommandPacket->NvmeCmd);
+ FreePool (Subtask->CommandPacket->NvmeCompletion);
+ FreePool (Subtask->CommandPacket);
+ FreePool (Subtask);
+
+ continue;
+ }
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ Subtask->NamespaceId,
+ Subtask->CommandPacket,
+ Subtask->Event
+ );
+ if (Status == EFI_NOT_READY) {
+ InsertHeadList (&Private->UnsubmittedSubtasks, Link);
+ BlkIo2Request->UnsubmittedSubtaskNum++;
+ break;
+ } else if (EFI_ERROR (Status)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+
+ if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
+ Subtask->IsLast) {
+ //
+ // Remove the BlockIo2 request from the device asynchronous queue.
+ //
+ RemoveEntryList (&BlkIo2Request->Link);
+ FreePool (BlkIo2Request);
+ gBS->SignalEvent (Token->Event);
+ }
+
+ FreePool (Subtask->CommandPacket->NvmeCmd);
+ FreePool (Subtask->CommandPacket->NvmeCompletion);
+ FreePool (Subtask->CommandPacket);
+ FreePool (Subtask);
+ } else {
+ InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
+ if (Subtask->IsLast) {
+ BlkIo2Request->LastSubtaskSubmitted = TRUE;
+ }
+ }
+ }
+
+ while (Cq->Pt != Private->Pt[QueueId]) {
+ ASSERT (Cq->Sqid == QueueId);
+
+ HasNewItem = TRUE;
+
+ //
+ // Find the command with given Command Id.
+ //
+ for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
+ !IsNull (&Private->AsyncPassThruQueue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
+ AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);
+ if (AsyncRequest->CommandId == Cq->Cid) {
+ //
+ // Copy the Respose Queue entry for this command to the callers
+ // response buffer.
+ //
+ CopyMem (
+ AsyncRequest->Packet->NvmeCompletion,
+ Cq,
+ sizeof(EFI_NVM_EXPRESS_COMPLETION)
+ );
+
+ //
+ // Free the resources allocated before cmd submission
+ //
+ if (AsyncRequest->MapData != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapData);
+ }
+ if (AsyncRequest->MapMeta != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapMeta);
+ }
+ if (AsyncRequest->MapPrpList != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);
+ }
+ if (AsyncRequest->PrpListHost != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ AsyncRequest->PrpListNo,
+ AsyncRequest->PrpListHost
+ );
+ }
+
+ RemoveEntryList (Link);
+ gBS->SignalEvent (AsyncRequest->CallerEvent);
+ FreePool (AsyncRequest);
+
+ //
+ // Update submission queue head.
+ //
+ Private->AsyncSqHead = Cq->Sqhd;
+ break;
+ }
+ }
+
+ Private->CqHdbl[QueueId].Cqh++;
+ if (Private->CqHdbl[QueueId].Cqh > MIN (NVME_ASYNC_CCQ_SIZE, Private->Cap.Mqes)) {
+ Private->CqHdbl[QueueId].Cqh = 0;
+ Private->Pt[QueueId] ^= 1;
+ }
+
+ Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
+ }
+
+ if (HasNewItem) {
+ Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),
+ 1,
+ &Data
+ );
+ }
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEV_PATH_PTR DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 ClassCode[3];
+
+ //
+ // Check whether device path is valid
+ //
+ 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
+ //
+ DevicePathNode.DevPath = RemainingDevicePath;
+
+ if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||
+ (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||
+ (DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // 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;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Attempt to Open PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ 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 a Nvm Express controller.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (ClassCode),
+ ClassCode
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Examine Nvm Express controller PCI Configuration table fields
+ //
+ if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+NvmExpressDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ UINT32 NamespaceId;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ UINTN Bytes;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;
+
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));
+
+ Private = NULL;
+ Passthru = NULL;
+ ParentDevicePath = NULL;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ //
+ // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.
+ //
+ if (Status != EFI_ALREADY_STARTED) {
+ Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));
+
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // 6 x 4kB aligned buffers will be carved out of this buffer.
+ // 1st 4kB boundary is the start of the admin submission queue.
+ // 2nd 4kB boundary is the start of the admin completion queue.
+ // 3rd 4kB boundary is the start of I/O submission queue #1.
+ // 4th 4kB boundary is the start of I/O completion queue #1.
+ // 5th 4kB boundary is the start of I/O submission queue #2.
+ // 6th 4kB boundary is the start of I/O completion queue #2.
+ //
+ // Allocate 6 pages of memory, then map it for bus master read and write.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ 6,
+ (VOID**)&Private->Buffer,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (6);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Private->Buffer,
+ &Bytes,
+ &MappedAddr,
+ &Private->Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (6))) {
+ goto Exit;
+ }
+
+ Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;
+
+ Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+ Private->ControllerHandle = Controller;
+ Private->ImageHandle = This->DriverBindingHandle;
+ Private->DriverBindingHandle = This->DriverBindingHandle;
+ Private->PciIo = PciIo;
+ Private->ParentDevicePath = ParentDevicePath;
+ Private->Passthru.Mode = &Private->PassThruMode;
+ Private->Passthru.PassThru = NvmExpressPassThru;
+ Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;
+ Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;
+ Private->Passthru.GetNamespace = NvmExpressGetNamespace;
+ CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));
+ InitializeListHead (&Private->AsyncPassThruQueue);
+ InitializeListHead (&Private->UnsubmittedSubtasks);
+
+ Status = NvmeControllerInit (Private);
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+
+ //
+ // Start the asynchronous I/O completion monitor
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ProcessAsyncTaskList,
+ Private,
+ &Private->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->SetTimer (
+ Private->TimerEvent,
+ TimerPeriodic,
+ NVME_HC_ASYNC_TIMER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ &Private->Passthru,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ NvmeRegisterShutdownNotification ();
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &Passthru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (Passthru);
+ }
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // Enumerate all NVME namespaces in the controller
+ //
+ Status = DiscoverAllNamespaces (
+ Private
+ );
+
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // Enumerate the specified NVME namespace
+ //
+ Status = Private->Passthru.GetNamespace (
+ &Private->Passthru,
+ RemainingDevicePath,
+ &NamespaceId
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EnumerateNvmeDevNamespace (
+ Private,
+ NamespaceId
+ );
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));
+ return EFI_SUCCESS;
+
+Exit:
+ if ((Private != NULL) && (Private->Mapping != NULL)) {
+ PciIo->Unmap (PciIo, Private->Mapping);
+ }
+
+ if ((Private != NULL) && (Private->Buffer != NULL)) {
+ PciIo->FreeBuffer (PciIo, 6, Private->Buffer);
+ }
+
+ if ((Private != NULL) && (Private->ControllerData != NULL)) {
+ FreePool (Private->ControllerData);
+ }
+
+ if (Private != NULL) {
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ FreePool (Private);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end with %r\n", Status));
+
+ return Status;
+}
+
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+NvmExpressDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ if (NumberOfChildren == 0) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);
+
+ //
+ // Wait for the asynchronous PassThru queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&
+ IsListEmpty (&Private->UnsubmittedSubtasks);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ PassThru,
+ NULL
+ );
+
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ if (Private->Mapping != NULL) {
+ Private->PciIo->Unmap (Private->PciIo, Private->Mapping);
+ }
+
+ if (Private->Buffer != NULL) {
+ Private->PciIo->FreeBuffer (Private->PciIo, 6, Private->Buffer);
+ }
+
+ FreePool (Private->ControllerData);
+ FreePool (Private);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ NvmeUnregisterShutdownNotification ();
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = UnregisterNvmeNamespace (This, Controller, ChildHandleBuffer[Index]);
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the unload handle for the NVM Express driver.
+
+ Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.
+ Uninstall all the protocols installed in the driver.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+
+ //
+ // Get the list of the device handles managed by this driver.
+ // If there is an error getting the list, then means the driver
+ // doesn't manage any device. At this way, we would only close
+ // those protocols installed at image handle.
+ //
+ DeviceHandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Disconnect the driver specified by ImageHandle from all
+ // the devices in the handle database.
+ //
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ ImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+ }
+ }
+
+ //
+ // Uninstall all the protocols installed in the driver entry point
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gNvmExpressDriverBinding,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gNvmExpressDriverSupportedEfiVersion,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Note we have to one by one uninstall the following protocols.
+ // It's because some of them are optionally installed based on
+ // the following PCD settings.
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable
+ // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable
+ // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable
+ //
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ ImageHandle,
+ &gEfiComponentNameProtocolGuid,
+ ComponentName
+ );
+ }
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ ImageHandle,
+ &gEfiComponentName2ProtocolGuid,
+ ComponentName2
+ );
+ }
+
+ Status = EFI_SUCCESS;
+
+EXIT:
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+ return Status;
+}
+
+/**
+ The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.
+
+ @param ImageHandle The firmware allocated handle for this driver image.
+ @param SystemTable Pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gNvmExpressDriverBinding,
+ ImageHandle,
+ &gNvmExpressComponentName,
+ &gNvmExpressComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install EFI Driver Supported EFI Version Protocol required for
+ // EFI drivers that are on PCI and other plug in cards.
+ //
+ gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gNvmExpressDriverSupportedEfiVersion,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
new file mode 100644
index 000000000..45a144750
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
@@ -0,0 +1,745 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_NVM_EXPRESS_H_
+#define _EFI_NVM_EXPRESS_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Nvme.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/NvmExpressPassthru.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/ResetNotification.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/ReportStatusCodeLib.h>
+
+typedef struct _NVME_CONTROLLER_PRIVATE_DATA NVME_CONTROLLER_PRIVATE_DATA;
+typedef struct _NVME_DEVICE_PRIVATE_DATA NVME_DEVICE_PRIVATE_DATA;
+
+#include "NvmExpressBlockIo.h"
+#include "NvmExpressDiskInfo.h"
+#include "NvmExpressHci.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gNvmExpressComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gNvmExpressComponentName2;
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion;
+
+#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass storage sub-class non-volatile memory.
+#define PCI_IF_NVMHCI 0x02 // mass storage programming interface NVMHCI.
+
+#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based
+#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based
+
+#define NVME_CSQ_SIZE 1 // Number of I/O submission queue entries, which is 0-based
+#define NVME_CCQ_SIZE 1 // Number of I/O completion queue entries, which is 0-based
+
+//
+// Number of asynchronous I/O submission queue entries, which is 0-based.
+// The asynchronous I/O submission queue size is 4kB in total.
+//
+#define NVME_ASYNC_CSQ_SIZE 63
+//
+// Number of asynchronous I/O completion queue entries, which is 0-based.
+// The asynchronous I/O completion queue size is 4kB in total.
+//
+#define NVME_ASYNC_CCQ_SIZE 255
+
+#define NVME_MAX_QUEUES 3 // Number of queues supported by the driver
+
+#define NVME_CONTROLLER_ID 0
+
+//
+// Time out value for Nvme transaction execution
+//
+#define NVME_GENERIC_TIMEOUT EFI_TIMER_PERIOD_SECONDS (5)
+
+//
+// Nvme async transfer timer interval, set by experience.
+//
+#define NVME_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS (1)
+
+//
+// Unique signature for private data structure.
+//
+#define NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('N','V','M','E')
+
+//
+// Nvme private data structure.
+//
+struct _NVME_CONTROLLER_PRIVATE_DATA {
+ UINT32 Signature;
+
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE DriverBindingHandle;
+
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 PciAttributes;
+
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ EFI_NVM_EXPRESS_PASS_THRU_MODE PassThruMode;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL Passthru;
+
+ //
+ // pointer to identify controller data
+ //
+ NVME_ADMIN_CONTROLLER_DATA *ControllerData;
+
+ //
+ // 6 x 4kB aligned buffers will be carved out of this buffer.
+ // 1st 4kB boundary is the start of the admin submission queue.
+ // 2nd 4kB boundary is the start of the admin completion queue.
+ // 3rd 4kB boundary is the start of I/O submission queue #1.
+ // 4th 4kB boundary is the start of I/O completion queue #1.
+ // 5th 4kB boundary is the start of I/O submission queue #2.
+ // 6th 4kB boundary is the start of I/O completion queue #2.
+ //
+ UINT8 *Buffer;
+ UINT8 *BufferPciAddr;
+
+ //
+ // Pointers to 4kB aligned submission & completion queues.
+ //
+ NVME_SQ *SqBuffer[NVME_MAX_QUEUES];
+ NVME_CQ *CqBuffer[NVME_MAX_QUEUES];
+ NVME_SQ *SqBufferPciAddr[NVME_MAX_QUEUES];
+ NVME_CQ *CqBufferPciAddr[NVME_MAX_QUEUES];
+
+ //
+ // Submission and completion queue indices.
+ //
+ NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES];
+ NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES];
+ UINT16 AsyncSqHead;
+
+ //
+ // Flag to indicate internal IO queue creation.
+ //
+ BOOLEAN CreateIoQueue;
+
+ UINT8 Pt[NVME_MAX_QUEUES];
+ UINT16 Cid[NVME_MAX_QUEUES];
+
+ //
+ // Nvme controller capabilities
+ //
+ NVME_CAP Cap;
+
+ VOID *Mapping;
+
+ //
+ // For Non-blocking operations.
+ //
+ EFI_EVENT TimerEvent;
+ LIST_ENTRY AsyncPassThruQueue;
+ LIST_ENTRY UnsubmittedSubtasks;
+};
+
+#define NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU(a) \
+ CR (a, \
+ NVME_CONTROLLER_PRIVATE_DATA, \
+ Passthru, \
+ NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE \
+ )
+
+//
+// Unique signature for private data structure.
+//
+#define NVME_DEVICE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('X','S','S','D')
+
+//
+// Nvme device private data structure
+//
+struct _NVME_DEVICE_PRIVATE_DATA {
+ UINT32 Signature;
+
+ EFI_HANDLE DeviceHandle;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE DriverBindingHandle;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ UINT32 NamespaceId;
+ UINT64 NamespaceUuid;
+
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+
+ LIST_ENTRY AsyncQueue;
+
+ EFI_LBA NumBlocks;
+
+ CHAR16 ModelName[80];
+ NVME_ADMIN_NAMESPACE_DATA NamespaceData;
+
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;
+
+};
+
+//
+// Statments to retrieve the private data from produced protocols.
+//
+#define NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO(a) \
+ CR (a, \
+ NVME_DEVICE_PRIVATE_DATA, \
+ BlockIo, \
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2(a) \
+ CR (a, \
+ NVME_DEVICE_PRIVATE_DATA, \
+ BlockIo2, \
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO(a) \
+ CR (a, \
+ NVME_DEVICE_PRIVATE_DATA, \
+ DiskInfo, \
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY(a)\
+ CR (a, \
+ NVME_DEVICE_PRIVATE_DATA, \
+ StorageSecurity, \
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
+ )
+
+//
+// Nvme block I/O 2 request.
+//
+#define NVME_BLKIO2_REQUEST_SIGNATURE SIGNATURE_32 ('N', 'B', '2', 'R')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_BLOCK_IO2_TOKEN *Token;
+ UINTN UnsubmittedSubtaskNum;
+ BOOLEAN LastSubtaskSubmitted;
+ //
+ // The queue for Nvme read/write sub-tasks of a BlockIo2 request.
+ //
+ LIST_ENTRY SubtasksQueue;
+} NVME_BLKIO2_REQUEST;
+
+#define NVME_BLKIO2_REQUEST_FROM_LINK(a) \
+ CR (a, NVME_BLKIO2_REQUEST, Link, NVME_BLKIO2_REQUEST_SIGNATURE)
+
+#define NVME_BLKIO2_SUBTASK_SIGNATURE SIGNATURE_32 ('N', 'B', '2', 'S')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ BOOLEAN IsLast;
+ UINT32 NamespaceId;
+ EFI_EVENT Event;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
+ //
+ // The BlockIo2 request this subtask belongs to
+ //
+ NVME_BLKIO2_REQUEST *BlockIo2Request;
+} NVME_BLKIO2_SUBTASK;
+
+#define NVME_BLKIO2_SUBTASK_FROM_LINK(a) \
+ CR (a, NVME_BLKIO2_SUBTASK, Link, NVME_BLKIO2_SUBTASK_SIGNATURE)
+
+//
+// Nvme asynchronous passthru request.
+//
+#define NVME_PASS_THRU_ASYNC_REQ_SIG SIGNATURE_32 ('N', 'P', 'A', 'R')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT16 CommandId;
+ VOID *MapPrpList;
+ UINTN PrpListNo;
+ VOID *PrpListHost;
+ VOID *MapData;
+ VOID *MapMeta;
+ EFI_EVENT CallerEvent;
+} NVME_PASS_THRU_ASYNC_REQ;
+
+#define NVME_PASS_THRU_ASYNC_REQ_FROM_THIS(a) \
+ CR (a, \
+ NVME_PASS_THRU_ASYNC_REQ, \
+ Link, \
+ NVME_PASS_THRU_ASYNC_REQ_SIG \
+ )
+
+/**
+ 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
+NvmExpressComponentNameGetDriverName (
+ 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
+NvmExpressComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+NvmExpressDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+NvmExpressDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
+ I/O functionality is optional.
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace
+ ID specifies that the command packet should be sent to all valid namespaces.
+ @param[in,out] Packet A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
+ by NamespaceId.
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking I/O is performed.
+ If Event is NULL, then blocking I/O is performed. If Event is not NULL and non blocking I/O
+ is supported, then nonblocking I/O is performed, and Event will be signaled when the NVM
+ Express Command Packet completes.
+
+ @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
+ to, or from DataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred
+ is returned in TransferLength.
+ @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller
+ may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
+ Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the host adapter.
+ The NVM Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressPassThru (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve the next namespace ID for this NVM Express controller.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves the next valid
+ namespace ID on this NVM Express controller.
+
+ If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first valid namespace
+ ID defined on the NVM Express controller is returned in the location pointed to by NamespaceId
+ and a status of EFI_SUCCESS is returned.
+
+ If on input the value pointed to by NamespaceId is an invalid namespace ID other than 0xFFFFFFFF,
+ then EFI_INVALID_PARAMETER is returned.
+
+ If on input the value pointed to by NamespaceId is a valid namespace ID, then the next valid
+ namespace ID on the NVM Express controller is returned in the location pointed to by NamespaceId,
+ and EFI_SUCCESS is returned.
+
+ If the value pointed to by NamespaceId is the namespace ID of the last namespace on the NVM
+ Express controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express
+ namespace present on the NVM Express controller. On output, a
+ pointer to the next NamespaceId of an NVM Express namespace on
+ an NVM Express controller. An input value of 0xFFFFFFFF retrieves
+ the first NamespaceId for an NVM Express namespace present on an
+ NVM Express controller.
+
+ @retval EFI_SUCCESS The Namespace ID of the next Namespace was returned.
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.
+ @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than 0xFFFFFFFF.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressGetNextNamespace (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT32 *NamespaceId
+ );
+
+/**
+ Used to translate a device path node to a namespace ID.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamespace() function determines the namespace ID associated with the
+ namespace described by DevicePath.
+
+ If DevicePath is a device path node type that the NVM Express Pass Thru driver supports, then the NVM Express
+ Pass Thru driver will attempt to translate the contents DevicePath into a namespace ID.
+
+ If this translation is successful, then that namespace ID is returned in NamespaceId, and EFI_SUCCESS is returned
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on
+ the NVM Express controller.
+ @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId.
+ @retval EFI_INVALID_PARAMETER If DevicePath or NamespaceId are NULL, then EFI_INVALID_PARAMETER is returned.
+ @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver
+ supports, then EFI_UNSUPPORTED is returned.
+ @retval EFI_NOT_FOUND If DevicePath is a device path node type that the NVM Express Pass Thru driver
+ supports, but there is not a valid translation from DevicePath to a namespace ID,
+ then EFI_NOT_FOUND is returned.
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressGetNamespace (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT32 *NamespaceId
+ );
+
+/**
+ Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device
+ path node for the NVM Express namespace specified by NamespaceId.
+
+ If the NamespaceId is not valid, then EFI_NOT_FOUND is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are
+ initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express
+ namespace specified by NamespaceId. This function is responsible for
+ allocating the buffer DevicePath with the boot service AllocatePool().
+ It is the caller's responsibility to free DevicePath when the caller
+ is finished with DevicePath.
+ @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified
+ by NamespaceId was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The NamespaceId is not valid.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressBuildDevicePath (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Dump the execution status from a given completion queue entry.
+
+ @param[in] Cq A pointer to the NVME_CQ item.
+
+**/
+VOID
+NvmeDumpStatus (
+ IN NVME_CQ *Cq
+ );
+
+/**
+ Register the shutdown notification through the ResetNotification protocol.
+
+ Register the shutdown notification when mNvmeControllerNumber increased from 0 to 1.
+**/
+VOID
+NvmeRegisterShutdownNotification (
+ VOID
+ );
+
+/**
+ Unregister the shutdown notification through the ResetNotification protocol.
+
+ Unregister the shutdown notification when mNvmeControllerNumber decreased from 1 to 0.
+**/
+VOID
+NvmeUnregisterShutdownNotification (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c
new file mode 100644
index 000000000..c63a6537a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c
@@ -0,0 +1,1854 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+/**
+ Read some sectors from the device.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
+ @param Buffer The buffer used to store the data read from the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be read.
+
+ @retval EFI_SUCCESS Datum are read from the device.
+ @retval Others Fail to read all the datum.
+
+**/
+EFI_STATUS
+ReadSectors (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 Bytes;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ Bytes = Blocks * BlockSize;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
+ CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;
+
+ CommandPacket.TransferLength = Bytes;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_IO_QUEUE;
+
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ Device->NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Write some sectors to the device.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
+ @param Buffer The buffer to be written into the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be written.
+
+ @retval EFI_SUCCESS Datum are written into the buffer.
+ @retval Others Fail to write all the datum.
+
+**/
+EFI_STATUS
+WriteSectors (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ UINT32 Bytes;
+ UINT32 BlockSize;
+
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ Bytes = Blocks * BlockSize;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
+ CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;
+
+ CommandPacket.TransferLength = Bytes;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_IO_QUEUE;
+
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
+ //
+ // Set Force Unit Access bit (bit 30) to use write-through behaviour
+ //
+ CommandPacket.NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
+
+ CommandPacket.MetadataBuffer = NULL;
+ CommandPacket.MetadataLength = 0;
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ Device->NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Read some blocks from the device.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
+ @param Buffer The buffer used to store the data read from the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be read.
+
+ @retval EFI_SUCCESS Datum are read from the device.
+ @retval Others Fail to read all the datum.
+
+**/
+EFI_STATUS
+NvmeRead (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ OUT VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 MaxTransferBlocks;
+ UINTN OrginalBlocks;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ //
+ // Wait for the device's asynchronous I/O queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ Status = EFI_SUCCESS;
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ OrginalBlocks = Blocks;
+
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
+
+ Blocks -= MaxTransferBlocks;
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
+
+ return Status;
+}
+
+/**
+ Write some blocks to the device.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
+ @param Buffer The buffer to be written into the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be written.
+
+ @retval EFI_SUCCESS Datum are written into the buffer.
+ @retval Others Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeWrite (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 MaxTransferBlocks;
+ UINTN OrginalBlocks;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ //
+ // Wait for the device's asynchronous I/O queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ Status = EFI_SUCCESS;
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ OrginalBlocks = Blocks;
+
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
+
+ Blocks -= MaxTransferBlocks;
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
+
+ return Status;
+}
+
+/**
+ Flushes all modified data to the device.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS Datum are written into the buffer.
+ @retval Others Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeFlush (
+ IN NVME_DEVICE_PRIVATE_DATA *Device
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ Private = Device->Controller;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_IO_QUEUE;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ Device->NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Nonblocking I/O callback funtion when the event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncIoCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ NVME_BLKIO2_SUBTASK *Subtask;
+ NVME_BLKIO2_REQUEST *Request;
+ NVME_CQ *Completion;
+ EFI_BLOCK_IO2_TOKEN *Token;
+
+ gBS->CloseEvent (Event);
+
+ Subtask = (NVME_BLKIO2_SUBTASK *) Context;
+ Completion = (NVME_CQ *) Subtask->CommandPacket->NvmeCompletion;
+ Request = Subtask->BlockIo2Request;
+ Token = Request->Token;
+
+ if (Token->TransactionStatus == EFI_SUCCESS) {
+ //
+ // If previous subtask already fails, do not check the result of
+ // subsequent subtasks.
+ //
+ if ((Completion->Sct != 0) || (Completion->Sc != 0)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+
+ //
+ // Dump completion entry status for debugging.
+ //
+ DEBUG_CODE_BEGIN();
+ NvmeDumpStatus (Completion);
+ DEBUG_CODE_END();
+ }
+ }
+
+ //
+ // Remove the subtask from the BlockIo2 subtasks list.
+ //
+ RemoveEntryList (&Subtask->Link);
+
+ if (IsListEmpty (&Request->SubtasksQueue) && Request->LastSubtaskSubmitted) {
+ //
+ // Remove the BlockIo2 request from the device asynchronous queue.
+ //
+ RemoveEntryList (&Request->Link);
+ FreePool (Request);
+ gBS->SignalEvent (Token->Event);
+ }
+
+ FreePool (Subtask->CommandPacket->NvmeCmd);
+ FreePool (Subtask->CommandPacket->NvmeCompletion);
+ FreePool (Subtask->CommandPacket);
+ FreePool (Subtask);
+}
+
+/**
+ Read some sectors from the device in an asynchronous manner.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
+ structure.
+ @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.
+ @param Buffer The buffer used to store the data read from the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be read.
+ @param IsLast The last subtask of an asynchronous read request.
+
+ @retval EFI_SUCCESS Asynchronous read request has been queued.
+ @retval Others Fail to send the asynchronous request.
+
+**/
+EFI_STATUS
+AsyncReadSectors (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN NVME_BLKIO2_REQUEST *Request,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks,
+ IN BOOLEAN IsLast
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 Bytes;
+ NVME_BLKIO2_SUBTASK *Subtask;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND *Command;
+ EFI_NVM_EXPRESS_COMPLETION *Completion;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_TPL OldTpl;
+
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ Bytes = Blocks * BlockSize;
+ CommandPacket = NULL;
+ Command = NULL;
+ Completion = NULL;
+
+ Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
+ if (Subtask == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;
+ Subtask->IsLast = IsLast;
+ Subtask->NamespaceId = Device->NamespaceId;
+ Subtask->BlockIo2Request = Request;
+
+ CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ if (CommandPacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ } else {
+ Subtask->CommandPacket = CommandPacket;
+ }
+
+ Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
+ if (Command == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
+ if (Completion == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ Subtask,
+ &Subtask->Event
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ CommandPacket->NvmeCmd = Command;
+ CommandPacket->NvmeCompletion = Completion;
+
+ CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
+ CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;
+ CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;
+
+ CommandPacket->TransferLength = Bytes;
+ CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket->QueueType = NVME_IO_QUEUE;
+
+ CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
+ CommandPacket->NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
+
+ CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
+ Request->UnsubmittedSubtaskNum++;
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ //
+ // Resource cleanup if asynchronous read request has not been queued.
+ //
+ if (Completion != NULL) {
+ FreePool (Completion);
+ }
+
+ if (Command != NULL) {
+ FreePool (Command);
+ }
+
+ if (CommandPacket != NULL) {
+ FreePool (CommandPacket);
+ }
+
+ if (Subtask != NULL) {
+ if (Subtask->Event != NULL) {
+ gBS->CloseEvent (Subtask->Event);
+ }
+
+ FreePool (Subtask);
+ }
+
+ return Status;
+}
+
+/**
+ Write some sectors from the device in an asynchronous manner.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
+ structure.
+ @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.
+ @param Buffer The buffer used to store the data written to the
+ device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be written.
+ @param IsLast The last subtask of an asynchronous write request.
+
+ @retval EFI_SUCCESS Asynchronous write request has been queued.
+ @retval Others Fail to send the asynchronous request.
+
+**/
+EFI_STATUS
+AsyncWriteSectors (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN NVME_BLKIO2_REQUEST *Request,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks,
+ IN BOOLEAN IsLast
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 Bytes;
+ NVME_BLKIO2_SUBTASK *Subtask;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND *Command;
+ EFI_NVM_EXPRESS_COMPLETION *Completion;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_TPL OldTpl;
+
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ Bytes = Blocks * BlockSize;
+ CommandPacket = NULL;
+ Command = NULL;
+ Completion = NULL;
+
+ Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
+ if (Subtask == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;
+ Subtask->IsLast = IsLast;
+ Subtask->NamespaceId = Device->NamespaceId;
+ Subtask->BlockIo2Request = Request;
+
+ CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ if (CommandPacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ } else {
+ Subtask->CommandPacket = CommandPacket;
+ }
+
+ Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
+ if (Command == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
+ if (Completion == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ Subtask,
+ &Subtask->Event
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ CommandPacket->NvmeCmd = Command;
+ CommandPacket->NvmeCompletion = Completion;
+
+ CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
+ CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;
+ CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;
+
+ CommandPacket->TransferLength = Bytes;
+ CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket->QueueType = NVME_IO_QUEUE;
+
+ CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
+ //
+ // Set Force Unit Access bit (bit 30) to use write-through behaviour
+ //
+ CommandPacket->NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
+
+ CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
+ Request->UnsubmittedSubtaskNum++;
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ //
+ // Resource cleanup if asynchronous read request has not been queued.
+ //
+ if (Completion != NULL) {
+ FreePool (Completion);
+ }
+
+ if (Command != NULL) {
+ FreePool (Command);
+ }
+
+ if (CommandPacket != NULL) {
+ FreePool (CommandPacket);
+ }
+
+ if (Subtask != NULL) {
+ if (Subtask->Event != NULL) {
+ gBS->CloseEvent (Subtask->Event);
+ }
+
+ FreePool (Subtask);
+ }
+
+ return Status;
+}
+
+/**
+ Read some blocks from the device in an asynchronous manner.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
+ structure.
+ @param Buffer The buffer used to store the data read from the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be read.
+ @param Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS Data are read from the device.
+ @retval Others Fail to read all the data.
+
+**/
+EFI_STATUS
+NvmeAsyncRead (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ OUT VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ NVME_BLKIO2_REQUEST *BlkIo2Req;
+ UINT32 MaxTransferBlocks;
+ UINTN OrginalBlocks;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ Status = EFI_SUCCESS;
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ OrginalBlocks = Blocks;
+ BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
+ if (BlkIo2Req == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
+ BlkIo2Req->Token = Token;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ InitializeListHead (&BlkIo2Req->SubtasksQueue);
+
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = AsyncReadSectors (
+ Device,
+ BlkIo2Req, (UINT64)(UINTN)Buffer,
+ Lba,
+ MaxTransferBlocks,
+ FALSE
+ );
+
+ Blocks -= MaxTransferBlocks;
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = AsyncReadSectors (
+ Device,
+ BlkIo2Req,
+ (UINT64)(UINTN)Buffer,
+ Lba,
+ (UINT32)Blocks,
+ TRUE
+ );
+
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
+ (BlkIo2Req->UnsubmittedSubtaskNum == 0);
+
+ if (IsEmpty) {
+ //
+ // Remove the BlockIo2 request from the device asynchronous queue.
+ //
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ //
+ // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
+ // should be returned to make sure that the caller does not free
+ // resources still using by these requests.
+ //
+ Status = EFI_SUCCESS;
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ BlkIo2Req->LastSubtaskSubmitted = TRUE;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
+
+ return Status;
+}
+
+/**
+ Write some blocks from the device in an asynchronous manner.
+
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
+ structure.
+ @param Buffer The buffer used to store the data written to the
+ device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be written.
+ @param Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS Data are written to the device.
+ @retval Others Fail to write all the data.
+
+**/
+EFI_STATUS
+NvmeAsyncWrite (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ NVME_BLKIO2_REQUEST *BlkIo2Req;
+ UINT32 MaxTransferBlocks;
+ UINTN OrginalBlocks;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ Status = EFI_SUCCESS;
+ Private = Device->Controller;
+ BlockSize = Device->Media.BlockSize;
+ OrginalBlocks = Blocks;
+ BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
+ if (BlkIo2Req == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
+ BlkIo2Req->Token = Token;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ InitializeListHead (&BlkIo2Req->SubtasksQueue);
+
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = AsyncWriteSectors (
+ Device,
+ BlkIo2Req,
+ (UINT64)(UINTN)Buffer,
+ Lba,
+ MaxTransferBlocks,
+ FALSE
+ );
+
+ Blocks -= MaxTransferBlocks;
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = AsyncWriteSectors (
+ Device,
+ BlkIo2Req,
+ (UINT64)(UINTN)Buffer,
+ Lba,
+ (UINT32)Blocks,
+ TRUE
+ );
+
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
+ (BlkIo2Req->UnsubmittedSubtaskNum == 0);
+
+ if (IsEmpty) {
+ //
+ // Remove the BlockIo2 request from the device asynchronous queue.
+ //
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ //
+ // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
+ // should be returned to make sure that the caller does not free
+ // resources still using by these requests.
+ //
+ Status = EFI_SUCCESS;
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ BlkIo2Req->LastSubtaskSubmitted = TRUE;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
+
+ return Status;
+}
+
+/**
+ 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
+NvmeBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_TPL OldTpl;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For Nvm Express subsystem, reset block device means reset controller.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ Private = Device->Controller;
+
+ Status = NvmeControllerInit (Private);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ 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
+NvmeBlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
+
+ gBS->RestoreTPL (OldTpl);
+ 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
+NvmeBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ 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 writing back the data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ Status = NvmeFlush (Device);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reset the block device hardware.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Indicates that the driver may perform a more
+ exhausive verfication operation of the
+ device during 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
+NvmeBlockIoResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+ Private = Device->Controller;
+
+ //
+ // Wait for the asynchronous PassThru queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&
+ IsListEmpty (&Private->UnsubmittedSubtasks);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Status = NvmeControllerInit (Private);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device
+ block size.
+ @param[out] 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 read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ Status = NvmeAsyncRead (Device, Buffer, Lba, NumberOfBlocks, Token);
+ } else {
+ Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device
+ block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @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_CHNAGED The MediaId does not matched the current
+ device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the write.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ Status = NvmeAsyncWrite (Device, Buffer, Lba, NumberOfBlocks, Token);
+ } else {
+ Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in,out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL.
+ All outstanding data was written correctly to
+ the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ BOOLEAN IsEmpty;
+ EFI_TPL OldTpl;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+
+ //
+ // Wait for the asynchronous I/O queue to become empty.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);
+ gBS->RestoreTPL (OldTpl);
+
+ if (IsEmpty) {
+ break;
+ }
+
+ gBS->Stall (100);
+ }
+
+ //
+ // Signal caller event
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Trust transfer data from/to NVMe device.
+
+ This function performs one NVMe transaction to do a trust transfer from/to NVMe device.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Buffer The pointer to the current transaction buffer.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param TransferLength The block number or sector count of the transfer.
+ @param IsTrustSend Indicates whether it is a trust send operation or not.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data
+ written to the buffer. Ignore it when IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferNvmeDevice (
+ IN OUT NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ UINT16 SpecificData;
+
+ ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ //
+ // Change Endianness of SecurityProtocolSpecificData
+ //
+ SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
+
+ if (IsTrustSend) {
+ Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_SEND_CMD;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = (UINT32)TransferLength;
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+ } else {
+ Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_RECEIVE_CMD;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = (UINT32)TransferLength;
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+ }
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+ CommandPacket.NvmeCmd->Nsid = NVME_CONTROLLER_ID;
+ CommandPacket.CommandTimeout = Timeout;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ NVME_CONTROLLER_ID,
+ &CommandPacket,
+ NULL
+ );
+
+ if (!IsTrustSend) {
+ if (EFI_ERROR (Status)) {
+ *TransferLengthOut = 0;
+ } else {
+ *TransferLengthOut = (UINTN) TransferLength;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ EFI_STATUS Status;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+
+ Status = EFI_SUCCESS;
+
+ if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
+
+ if (MediaId != Device->BlockIo.Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!Device->BlockIo.Media->MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ Status = TrustTransferNvmeDevice (
+ Device->Controller,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ FALSE,
+ Timeout,
+ PayloadTransferSize
+ );
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the send data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ EFI_STATUS Status;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+
+ Status = EFI_SUCCESS;
+
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
+
+ if (MediaId != Device->BlockIo.Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!Device->BlockIo.Media->MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ Status = TrustTransferNvmeDevice (
+ Device->Controller,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ TRUE,
+ Timeout,
+ NULL
+ );
+
+ return Status;
+}
+
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h
new file mode 100644
index 000000000..ba00dde44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h
@@ -0,0 +1,411 @@
+/** @file
+ Header file for EFI_BLOCK_IO_PROTOCOL interface.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_NVME_BLOCKIO_H_
+#define _EFI_NVME_BLOCKIO_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
+NvmeBlockIoReset (
+ 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
+NvmeBlockIoReadBlocks (
+ 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
+NvmeBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the block device hardware.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Indicates that the driver may perform a more
+ exhausive verfication operation of the
+ device during 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
+NvmeBlockIoResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device
+ block size.
+ @param[out] 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 read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device
+ block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @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_CHNAGED The MediaId does not matched the current
+ device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the write.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in,out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL.
+ All outstanding data was written correctly to
+ the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c
new file mode 100644
index 000000000..10b79d4ad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c
@@ -0,0 +1,156 @@
+/** @file
+ This file is used to implement the EFI_DISK_INFO_PROTOCOL interface..
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+EFI_DISK_INFO_PROTOCOL gNvmExpressDiskInfoProtocolTemplate = {
+ EFI_DISK_INFO_NVME_INTERFACE_GUID,
+ NvmExpressDiskInfoInquiry,
+ NvmExpressDiskInfoIdentify,
+ NvmExpressDiskInfoSenseData,
+ NvmExpressDiskInfoWhichIde
+};
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with NVME interface GUID.
+
+ @param[in] Device The pointer of NVME_DEVICE_PRIVATE_DATA.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN NVME_DEVICE_PRIVATE_DATA *Device
+ )
+{
+ CopyMem (&Device->DiskInfo, &gNvmExpressDiskInfoProtocolTemplate, sizeof (EFI_DISK_INFO_PROTOCOL));
+}
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+NvmExpressDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ EFI_STATUS Status;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*IdentifyDataSize >= sizeof (Device->NamespaceData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (IdentifyData, &Device->NamespaceData, sizeof (Device->NamespaceData));
+ }
+ *IdentifyDataSize = sizeof (Device->NamespaceData);
+ return Status;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoSenseData (
+ 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 to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+NvmExpressDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h
new file mode 100644
index 000000000..b19e6f0a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h
@@ -0,0 +1,123 @@
+/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVME_DISKINFO_H_
+#define _NVME_DISKINFO_H_
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with NVME interface GUID.
+
+ @param[in] Device The pointer of NVME_DEVICE_PRIVATE_DATA.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN NVME_DEVICE_PRIVATE_DATA *Device
+ );
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+NvmExpressDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+NvmExpressDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
new file mode 100644
index 000000000..dc1990c32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# NVM Express Host Controller Module.
+#
+# NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+# NVM Express specification.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NvmExpressDxe
+ MODULE_UNI_FILE = NvmExpressDxe.uni
+ FILE_GUID = 5BE3BDF4-53CF-46a3-A6A9-73C34A6E5EE3
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = NvmExpressDriverEntry
+ UNLOAD_IMAGE = NvmExpressUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gNvmExpressDriverBinding
+# COMPONENT_NAME = gNvmExpressComponentName
+# COMPONENT_NAME2 = gNvmExpressComponentName2
+
+[Sources]
+ NvmExpressBlockIo.c
+ NvmExpressBlockIo.h
+ ComponentName.c
+ NvmExpress.c
+ NvmExpress.h
+ NvmExpressDiskInfo.c
+ NvmExpressDiskInfo.h
+ NvmExpressHci.c
+ NvmExpressHci.h
+ NvmExpressPassthru.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+ PrintLib
+ ReportStatusCodeLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiNvmExpressPassThruProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+ gEfiStorageSecurityCommandProtocolGuid ## BY_START
+ gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES
+ gEfiResetNotificationProtocolGuid ## CONSUMES
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## SOMETIMES_CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ NvmExpressDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.uni
new file mode 100644
index 000000000..829be6bbe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// NVM Express Host Controller Module.
+//
+// NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+// NVM Express specification.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NVM Express Host Controller Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows NVM Express specification."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxeExtra.uni
new file mode 100644
index 000000000..c74e13d87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// NvmExpressDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"NVM Express DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
new file mode 100644
index 000000000..95f8b18bc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
@@ -0,0 +1,1126 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+#define NVME_SHUTDOWN_PROCESS_TIMEOUT 45
+
+//
+// The number of NVME controllers managed by this driver, used by
+// NvmeRegisterShutdownNotification() and NvmeUnregisterShutdownNotification().
+//
+UINTN mNvmeControllerNumber = 0;
+
+/**
+ Read Nvm Express controller capability register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Cap The buffer used to store capability register content.
+
+ @return EFI_SUCCESS Successfully read the controller capability register content.
+ @return EFI_DEVICE_ERROR Fail to read the controller capability register.
+
+**/
+EFI_STATUS
+ReadNvmeControllerCapabilities (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_CAP *Cap
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT64 Data;
+
+ PciIo = Private->PciIo;
+ Status = PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CAP_OFFSET,
+ 2,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ WriteUnaligned64 ((UINT64*)Cap, Data);
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Nvm Express controller configuration register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Cc The buffer used to store configuration register content.
+
+ @return EFI_SUCCESS Successfully read the controller configuration register content.
+ @return EFI_DEVICE_ERROR Fail to read the controller configuration register.
+
+**/
+EFI_STATUS
+ReadNvmeControllerConfiguration (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_CC *Cc
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ PciIo = Private->PciIo;
+ Status = PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CC_OFFSET,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ WriteUnaligned32 ((UINT32*)Cc, Data);
+ return EFI_SUCCESS;
+}
+
+/**
+ Write Nvm Express controller configuration register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Cc The buffer used to store the content to be written into configuration register.
+
+ @return EFI_SUCCESS Successfully write data into the controller configuration register.
+ @return EFI_DEVICE_ERROR Fail to write data into the controller configuration register.
+
+**/
+EFI_STATUS
+WriteNvmeControllerConfiguration (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_CC *Cc
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ PciIo = Private->PciIo;
+ Data = ReadUnaligned32 ((UINT32*)Cc);
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CC_OFFSET,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Cc.En: %d\n", Cc->En));
+ DEBUG ((EFI_D_INFO, "Cc.Css: %d\n", Cc->Css));
+ DEBUG ((EFI_D_INFO, "Cc.Mps: %d\n", Cc->Mps));
+ DEBUG ((EFI_D_INFO, "Cc.Ams: %d\n", Cc->Ams));
+ DEBUG ((EFI_D_INFO, "Cc.Shn: %d\n", Cc->Shn));
+ DEBUG ((EFI_D_INFO, "Cc.Iosqes: %d\n", Cc->Iosqes));
+ DEBUG ((EFI_D_INFO, "Cc.Iocqes: %d\n", Cc->Iocqes));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Nvm Express controller status register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Csts The buffer used to store status register content.
+
+ @return EFI_SUCCESS Successfully read the controller status register content.
+ @return EFI_DEVICE_ERROR Fail to read the controller status register.
+
+**/
+EFI_STATUS
+ReadNvmeControllerStatus (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_CSTS *Csts
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ PciIo = Private->PciIo;
+ Status = PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CSTS_OFFSET,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ WriteUnaligned32 ((UINT32*)Csts, Data);
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Write Nvm Express admin queue attributes register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Aqa The buffer used to store the content to be written into admin queue attributes register.
+
+ @return EFI_SUCCESS Successfully write data into the admin queue attributes register.
+ @return EFI_DEVICE_ERROR Fail to write data into the admin queue attributes register.
+
+**/
+EFI_STATUS
+WriteNvmeAdminQueueAttributes (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_AQA *Aqa
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ PciIo = Private->PciIo;
+ Data = ReadUnaligned32 ((UINT32*)Aqa);
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_AQA_OFFSET,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Aqa.Asqs: %d\n", Aqa->Asqs));
+ DEBUG ((EFI_D_INFO, "Aqa.Acqs: %d\n", Aqa->Acqs));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Write Nvm Express admin submission queue base address register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Asq The buffer used to store the content to be written into admin submission queue base address register.
+
+ @return EFI_SUCCESS Successfully write data into the admin submission queue base address register.
+ @return EFI_DEVICE_ERROR Fail to write data into the admin submission queue base address register.
+
+**/
+EFI_STATUS
+WriteNvmeAdminSubmissionQueueBaseAddress (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_ASQ *Asq
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT64 Data;
+
+ PciIo = Private->PciIo;
+ Data = ReadUnaligned64 ((UINT64*)Asq);
+
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_ASQ_OFFSET,
+ 2,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Asq: %lx\n", *Asq));
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Write Nvm Express admin completion queue base address register.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Acq The buffer used to store the content to be written into admin completion queue base address register.
+
+ @return EFI_SUCCESS Successfully write data into the admin completion queue base address register.
+ @return EFI_DEVICE_ERROR Fail to write data into the admin completion queue base address register.
+
+**/
+EFI_STATUS
+WriteNvmeAdminCompletionQueueBaseAddress (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN NVME_ACQ *Acq
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT64 Data;
+
+ PciIo = Private->PciIo;
+ Data = ReadUnaligned64 ((UINT64*)Acq);
+
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_ACQ_OFFSET,
+ 2,
+ &Data
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Acq: %lxh\n", *Acq));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable the Nvm Express controller.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully disable the controller.
+ @return EFI_DEVICE_ERROR Fail to disable the controller.
+
+**/
+EFI_STATUS
+NvmeDisableController (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 Timeout;
+
+ //
+ // Read Controller Configuration Register.
+ //
+ Status = ReadNvmeControllerConfiguration (Private, &Cc);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Cc.En = 0;
+
+ //
+ // Disable the controller.
+ //
+ Status = WriteNvmeControllerConfiguration (Private, &Cc);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to transition from 1 to 0 after
+ // Cc.Enable transition from 1 to 0. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
+ //
+ if (Private->Cap.To == 0) {
+ Timeout = 1;
+ } else {
+ Timeout = Private->Cap.To;
+ }
+
+ for(Index = (Timeout * 500); Index != 0; --Index) {
+ gBS->Stall(1000);
+
+ //
+ // Check if the controller is initialized
+ //
+ Status = ReadNvmeControllerStatus (Private, &Csts);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (Csts.Rdy == 0) {
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_DEVICE_ERROR;
+ REPORT_STATUS_CODE (
+ (EFI_ERROR_CODE | EFI_ERROR_MAJOR),
+ (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR)
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "NVMe controller is disabled with status [%r].\n", Status));
+ return Status;
+}
+
+/**
+ Enable the Nvm Express controller.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully enable the controller.
+ @return EFI_DEVICE_ERROR Fail to enable the controller.
+ @return EFI_TIMEOUT Fail to enable the controller in given time slot.
+
+**/
+EFI_STATUS
+NvmeEnableController (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 Timeout;
+
+ //
+ // Enable the controller.
+ // CC.AMS, CC.MPS and CC.CSS are all set to 0.
+ //
+ ZeroMem (&Cc, sizeof (NVME_CC));
+ Cc.En = 1;
+ Cc.Iosqes = 6;
+ Cc.Iocqes = 4;
+
+ Status = WriteNvmeControllerConfiguration (Private, &Cc);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
+ //
+ if (Private->Cap.To == 0) {
+ Timeout = 1;
+ } else {
+ Timeout = Private->Cap.To;
+ }
+
+ for(Index = (Timeout * 500); Index != 0; --Index) {
+ gBS->Stall(1000);
+
+ //
+ // Check if the controller is initialized
+ //
+ Status = ReadNvmeControllerStatus (Private, &Csts);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (Csts.Rdy) {
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_TIMEOUT;
+ REPORT_STATUS_CODE (
+ (EFI_ERROR_CODE | EFI_ERROR_MAJOR),
+ (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR)
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "NVMe controller is enabled with status [%r].\n", Status));
+ return Status;
+}
+
+/**
+ Get identify controller data.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Buffer The buffer used to store the identify controller data.
+
+ @return EFI_SUCCESS Successfully get the identify controller data.
+ @return EFI_DEVICE_ERROR Fail to get the identify controller data.
+
+**/
+EFI_STATUS
+NvmeIdentifyController (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
+ //
+ Command.Nsid = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a controller
+ //
+ Command.Cdw10 = 1;
+ Command.Flags = CDW10_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ NVME_CONTROLLER_ID,
+ &CommandPacket,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Get specified identify namespace data.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param NamespaceId The specified namespace identifier.
+ @param Buffer The buffer used to store the identify namespace data.
+
+ @return EFI_SUCCESS Successfully get the identify namespace data.
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
+
+**/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ Command.Nsid = NamespaceId;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a namespace
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 0;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Create io completion queue.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io completion queue.
+ @return EFI_DEVICE_ERROR Fail to create io completion queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoCompletionQueue (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOCQ CrIoCq;
+ UINT32 Index;
+ UINT16 QueueSize;
+
+ Status = EFI_SUCCESS;
+ Private->CreateIoQueue = TRUE;
+
+ for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
+ CommandPacket.TransferBuffer = Private->CqBufferPciAddr[Index];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ if (Index == 1) {
+ QueueSize = NVME_CCQ_SIZE;
+ } else {
+ if (Private->Cap.Mqes > NVME_ASYNC_CCQ_SIZE) {
+ QueueSize = NVME_ASYNC_CCQ_SIZE;
+ } else {
+ QueueSize = Private->Cap.Mqes;
+ }
+ }
+
+ CrIoCq.Qid = Index;
+ CrIoCq.Qsize = QueueSize;
+ CrIoCq.Pc = 1;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ 0,
+ &CommandPacket,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ Private->CreateIoQueue = FALSE;
+
+ return Status;
+}
+
+/**
+ Create io submission queue.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io submission queue.
+ @return EFI_DEVICE_ERROR Fail to create io submission queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoSubmissionQueue (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOSQ CrIoSq;
+ UINT32 Index;
+ UINT16 QueueSize;
+
+ Status = EFI_SUCCESS;
+ Private->CreateIoQueue = TRUE;
+
+ for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
+ CommandPacket.TransferBuffer = Private->SqBufferPciAddr[Index];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ if (Index == 1) {
+ QueueSize = NVME_CSQ_SIZE;
+ } else {
+ if (Private->Cap.Mqes > NVME_ASYNC_CSQ_SIZE) {
+ QueueSize = NVME_ASYNC_CSQ_SIZE;
+ } else {
+ QueueSize = Private->Cap.Mqes;
+ }
+ }
+
+ CrIoSq.Qid = Index;
+ CrIoSq.Qsize = QueueSize;
+ CrIoSq.Pc = 1;
+ CrIoSq.Cqid = Index;
+ CrIoSq.Qprio = 0;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = Private->Passthru.PassThru (
+ &Private->Passthru,
+ 0,
+ &CommandPacket,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ Private->CreateIoQueue = FALSE;
+
+ return Status;
+}
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ NVME_AQA Aqa;
+ NVME_ASQ Asq;
+ NVME_ACQ Acq;
+ UINT8 Sn[21];
+ UINT8 Mn[41];
+ //
+ // Save original PCI attributes and enable this controller.
+ //
+ PciIo = Private->PciIo;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->PciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ 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)) {
+ DEBUG ((EFI_D_INFO, "NvmeControllerInit: failed to enable controller\n"));
+ return Status;
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer.
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN, "NvmeControllerInit: failed to enable 64-bit DMA (%r)\n", Status));
+ }
+
+ //
+ // Read the Controller Capabilities register and verify that the NVM command set is supported
+ //
+ Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->Cap.Css != 0x01) {
+ DEBUG ((EFI_D_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Currently the driver only supports 4k page size.
+ //
+ ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);
+
+ Private->Cid[0] = 0;
+ Private->Cid[1] = 0;
+ Private->Cid[2] = 0;
+ Private->Pt[0] = 0;
+ Private->Pt[1] = 0;
+ Private->Pt[2] = 0;
+ Private->SqTdbl[0].Sqt = 0;
+ Private->SqTdbl[1].Sqt = 0;
+ Private->SqTdbl[2].Sqt = 0;
+ Private->CqHdbl[0].Cqh = 0;
+ Private->CqHdbl[1].Cqh = 0;
+ Private->CqHdbl[2].Cqh = 0;
+ Private->AsyncSqHead = 0;
+
+ Status = NvmeDisableController (Private);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // set number of entries admin submission & completion queues.
+ //
+ Aqa.Asqs = NVME_ASQ_SIZE;
+ Aqa.Rsvd1 = 0;
+ Aqa.Acqs = NVME_ACQ_SIZE;
+ Aqa.Rsvd2 = 0;
+
+ //
+ // Address of admin submission queue.
+ //
+ Asq = (UINT64)(UINTN)(Private->BufferPciAddr) & ~0xFFF;
+
+ //
+ // Address of admin completion queue.
+ //
+ Acq = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) & ~0xFFF;
+
+ //
+ // Address of I/O submission & completion queue.
+ //
+ ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (6));
+ Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);
+ Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);
+ Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);
+ Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);
+ Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);
+ Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);
+ Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);
+ Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);
+ Private->SqBuffer[2] = (NVME_SQ *)(UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);
+ Private->SqBufferPciAddr[2] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);
+ Private->CqBuffer[2] = (NVME_CQ *)(UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);
+ Private->CqBufferPciAddr[2] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);
+
+ DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));
+ DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
+ DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
+ DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));
+ DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));
+ DEBUG ((EFI_D_INFO, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));
+ DEBUG ((EFI_D_INFO, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));
+ DEBUG ((EFI_D_INFO, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));
+ DEBUG ((EFI_D_INFO, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));
+
+ //
+ // Program admin queue attributes.
+ //
+ Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Program admin submission queue address.
+ //
+ Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Program admin completion queue address.
+ //
+ Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = NvmeEnableController (Private);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer for Identify Controller data
+ //
+ if (Private->ControllerData == NULL) {
+ Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));
+
+ if (Private->ControllerData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Get current Identify Controller Data
+ //
+ Status = NvmeIdentifyController (Private, Private->ControllerData);
+
+ if (EFI_ERROR(Status)) {
+ FreePool(Private->ControllerData);
+ Private->ControllerData = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Dump NvmExpress Identify Controller Data
+ //
+ CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));
+ Sn[20] = 0;
+ CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));
+ Mn[40] = 0;
+ DEBUG ((EFI_D_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));
+ DEBUG ((EFI_D_INFO, " PCI VID : 0x%x\n", Private->ControllerData->Vid));
+ DEBUG ((EFI_D_INFO, " PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));
+ DEBUG ((EFI_D_INFO, " SN : %a\n", Sn));
+ DEBUG ((EFI_D_INFO, " MN : %a\n", Mn));
+ DEBUG ((EFI_D_INFO, " FR : 0x%x\n", *((UINT64*)Private->ControllerData->Fr)));
+ DEBUG ((EFI_D_INFO, " RAB : 0x%x\n", Private->ControllerData->Rab));
+ DEBUG ((EFI_D_INFO, " IEEE : 0x%x\n", *(UINT32*)Private->ControllerData->Ieee_oui));
+ DEBUG ((EFI_D_INFO, " AERL : 0x%x\n", Private->ControllerData->Aerl));
+ DEBUG ((EFI_D_INFO, " SQES : 0x%x\n", Private->ControllerData->Sqes));
+ DEBUG ((EFI_D_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes));
+ DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));
+
+ //
+ // Create two I/O completion queues.
+ // One for blocking I/O, one for non-blocking I/O.
+ //
+ Status = NvmeCreateIoCompletionQueue (Private);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Create two I/O Submission queues.
+ // One for blocking I/O, one for non-blocking I/O.
+ //
+ Status = NvmeCreateIoSubmissionQueue (Private);
+
+ return Status;
+}
+
+/**
+ This routine is called to properly shutdown the Nvm Express controller per NVMe spec.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+**/
+VOID
+EFIAPI
+NvmeShutdownAllControllers (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN HandleIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfos;
+ UINTN OpenInfoCount;
+ UINTN OpenInfoIndex;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassThru;
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ UINTN Index;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ HandleCount = 0;
+ }
+
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = gBS->OpenProtocolInformation (
+ Handles[HandleIndex],
+ &gEfiPciIoProtocolGuid,
+ &OpenInfos,
+ &OpenInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+ //
+ // Find all the NVME controller managed by this driver.
+ // gImageHandle equals to DriverBinding handle for this driver.
+ //
+ if (((OpenInfos[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) &&
+ (OpenInfos[OpenInfoIndex].AgentHandle == gImageHandle)) {
+ Status = gBS->OpenProtocol (
+ OpenInfos[OpenInfoIndex].ControllerHandle,
+ &gEfiNvmExpressPassThruProtocolGuid,
+ (VOID **) &NvmePassThru,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (NvmePassThru);
+
+ //
+ // Read Controller Configuration Register.
+ //
+ Status = ReadNvmeControllerConfiguration (Private, &Cc);
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ //
+ // The host should set the Shutdown Notification (CC.SHN) field to 01b
+ // to indicate a normal shutdown operation.
+ //
+ Cc.Shn = NVME_CC_SHN_NORMAL_SHUTDOWN;
+ Status = WriteNvmeControllerConfiguration (Private, &Cc);
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ //
+ // The controller indicates when shutdown processing is completed by updating the
+ // Shutdown Status (CSTS.SHST) field to 10b.
+ // Wait up to 45 seconds (break down to 4500 x 10ms) for the shutdown to complete.
+ //
+ for (Index = 0; Index < NVME_SHUTDOWN_PROCESS_TIMEOUT * 100; Index++) {
+ Status = ReadNvmeControllerStatus (Private, &Csts);
+ if (!EFI_ERROR(Status) && (Csts.Shst == NVME_CSTS_SHST_SHUTDOWN_COMPLETED)) {
+ DEBUG((DEBUG_INFO, "NvmeShutdownController: shutdown processing is completed after %dms.\n", Index * 10));
+ break;
+ }
+ //
+ // Stall for 10ms
+ //
+ gBS->Stall (10 * 1000);
+ }
+
+ if (Index == NVME_SHUTDOWN_PROCESS_TIMEOUT * 100) {
+ DEBUG((DEBUG_ERROR, "NvmeShutdownController: shutdown processing is timed out\n"));
+ }
+ }
+ }
+ }
+}
+
+/**
+ Register the shutdown notification through the ResetNotification protocol.
+
+ Register the shutdown notification when mNvmeControllerNumber increased from 0 to 1.
+**/
+VOID
+NvmeRegisterShutdownNotification (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;
+
+ mNvmeControllerNumber++;
+ if (mNvmeControllerNumber == 1) {
+ Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **) &ResetNotify);
+ if (!EFI_ERROR (Status)) {
+ Status = ResetNotify->RegisterResetNotify (ResetNotify, NvmeShutdownAllControllers);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((DEBUG_WARN, "NVME: ResetNotification absent! Shutdown notification cannot be performed!\n"));
+ }
+ }
+}
+
+/**
+ Unregister the shutdown notification through the ResetNotification protocol.
+
+ Unregister the shutdown notification when mNvmeControllerNumber decreased from 1 to 0.
+**/
+VOID
+NvmeUnregisterShutdownNotification (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;
+
+ mNvmeControllerNumber--;
+ if (mNvmeControllerNumber == 0) {
+ Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **) &ResetNotify);
+ if (!EFI_ERROR (Status)) {
+ Status = ResetNotify->UnregisterResetNotify (ResetNotify, NvmeShutdownAllControllers);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h
new file mode 100644
index 000000000..60b377058
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h
@@ -0,0 +1,70 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVME_HCI_H_
+#define _NVME_HCI_H_
+
+#define NVME_BAR 0
+
+//
+// Offset from the beginning of private data queue buffer
+//
+#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ );
+
+/**
+ Get identify controller data.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param Buffer The buffer used to store the identify controller data.
+
+ @return EFI_SUCCESS Successfully get the identify controller data.
+ @return EFI_DEVICE_ERROR Fail to get the identify controller data.
+
+**/
+EFI_STATUS
+NvmeIdentifyController (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN VOID *Buffer
+ );
+
+/**
+ Get specified identify namespace data.
+
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param NamespaceId The specified namespace identifier.
+ @param Buffer The buffer used to store the identify namespace data.
+
+ @return EFI_SUCCESS Successfully get the identify namespace data.
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
+
+**/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
new file mode 100644
index 000000000..e9357b123
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
@@ -0,0 +1,1185 @@
+/** @file
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
+ NVM Express specification.
+
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+/**
+ Dump the execution status from a given completion queue entry.
+
+ @param[in] Cq A pointer to the NVME_CQ item.
+
+**/
+VOID
+NvmeDumpStatus (
+ IN NVME_CQ *Cq
+ )
+{
+ DEBUG ((EFI_D_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));
+
+ DEBUG ((EFI_D_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));
+
+ DEBUG ((EFI_D_VERBOSE, " NVMe Cmd Execution Result - "));
+
+ switch (Cq->Sct) {
+ case 0x0:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((EFI_D_VERBOSE, "Successful Completion\n"));
+ break;
+ case 0x1:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Command Opcode\n"));
+ break;
+ case 0x2:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Field in Command\n"));
+ break;
+ case 0x3:
+ DEBUG ((EFI_D_VERBOSE, "Command ID Conflict\n"));
+ break;
+ case 0x4:
+ DEBUG ((EFI_D_VERBOSE, "Data Transfer Error\n"));
+ break;
+ case 0x5:
+ DEBUG ((EFI_D_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));
+ break;
+ case 0x6:
+ DEBUG ((EFI_D_VERBOSE, "Internal Device Error\n"));
+ break;
+ case 0x7:
+ DEBUG ((EFI_D_VERBOSE, "Command Abort Requested\n"));
+ break;
+ case 0x8:
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to SQ Deletion\n"));
+ break;
+ case 0x9:
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Failed Fused Command\n"));
+ break;
+ case 0xA:
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Missing Fused Command\n"));
+ break;
+ case 0xB:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Namespace or Format\n"));
+ break;
+ case 0xC:
+ DEBUG ((EFI_D_VERBOSE, "Command Sequence Error\n"));
+ break;
+ case 0xD:
+ DEBUG ((EFI_D_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));
+ break;
+ case 0xE:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Number of SGL Descriptors\n"));
+ break;
+ case 0xF:
+ DEBUG ((EFI_D_VERBOSE, "Data SGL Length Invalid\n"));
+ break;
+ case 0x10:
+ DEBUG ((EFI_D_VERBOSE, "Metadata SGL Length Invalid\n"));
+ break;
+ case 0x11:
+ DEBUG ((EFI_D_VERBOSE, "SGL Descriptor Type Invalid\n"));
+ break;
+ case 0x80:
+ DEBUG ((EFI_D_VERBOSE, "LBA Out of Range\n"));
+ break;
+ case 0x81:
+ DEBUG ((EFI_D_VERBOSE, "Capacity Exceeded\n"));
+ break;
+ case 0x82:
+ DEBUG ((EFI_D_VERBOSE, "Namespace Not Ready\n"));
+ break;
+ case 0x83:
+ DEBUG ((EFI_D_VERBOSE, "Reservation Conflict\n"));
+ break;
+ }
+ break;
+
+ case 0x1:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((EFI_D_VERBOSE, "Completion Queue Invalid\n"));
+ break;
+ case 0x1:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Queue Identifier\n"));
+ break;
+ case 0x2:
+ DEBUG ((EFI_D_VERBOSE, "Maximum Queue Size Exceeded\n"));
+ break;
+ case 0x3:
+ DEBUG ((EFI_D_VERBOSE, "Abort Command Limit Exceeded\n"));
+ break;
+ case 0x5:
+ DEBUG ((EFI_D_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));
+ break;
+ case 0x6:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Slot\n"));
+ break;
+ case 0x7:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Image\n"));
+ break;
+ case 0x8:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Interrupt Vector\n"));
+ break;
+ case 0x9:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Log Page\n"));
+ break;
+ case 0xA:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Format\n"));
+ break;
+ case 0xB:
+ DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires Conventional Reset\n"));
+ break;
+ case 0xC:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Queue Deletion\n"));
+ break;
+ case 0xD:
+ DEBUG ((EFI_D_VERBOSE, "Feature Identifier Not Saveable\n"));
+ break;
+ case 0xE:
+ DEBUG ((EFI_D_VERBOSE, "Feature Not Changeable\n"));
+ break;
+ case 0xF:
+ DEBUG ((EFI_D_VERBOSE, "Feature Not Namespace Specific\n"));
+ break;
+ case 0x10:
+ DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));
+ break;
+ case 0x80:
+ DEBUG ((EFI_D_VERBOSE, "Conflicting Attributes\n"));
+ break;
+ case 0x81:
+ DEBUG ((EFI_D_VERBOSE, "Invalid Protection Information\n"));
+ break;
+ case 0x82:
+ DEBUG ((EFI_D_VERBOSE, "Attempted Write to Read Only Range\n"));
+ break;
+ }
+ break;
+
+ case 0x2:
+ switch (Cq->Sc) {
+ case 0x80:
+ DEBUG ((EFI_D_VERBOSE, "Write Fault\n"));
+ break;
+ case 0x81:
+ DEBUG ((EFI_D_VERBOSE, "Unrecovered Read Error\n"));
+ break;
+ case 0x82:
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Guard Check Error\n"));
+ break;
+ case 0x83:
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Application Tag Check Error\n"));
+ break;
+ case 0x84:
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Reference Tag Check Error\n"));
+ break;
+ case 0x85:
+ DEBUG ((EFI_D_VERBOSE, "Compare Failure\n"));
+ break;
+ case 0x86:
+ DEBUG ((EFI_D_VERBOSE, "Access Denied\n"));
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create PRP lists for data transfer which is larger than 2 memory pages.
+ Note here we calcuate the number of required PRP lists and allocate them at one time.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PhysicalAddr The physical base address of data buffer.
+ @param[in] Pages The number of pages to be transfered.
+ @param[out] PrpListHost The host base address of PRP lists.
+ @param[in,out] PrpListNo The number of PRP List.
+ @param[out] Mapping The mapping value returned from PciIo.Map().
+
+ @retval The pointer to the first PRP List of the PRP lists.
+
+**/
+VOID*
+NvmeCreatePrpList (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,
+ IN UINTN Pages,
+ OUT VOID **PrpListHost,
+ IN OUT UINTN *PrpListNo,
+ OUT VOID **Mapping
+ )
+{
+ UINTN PrpEntryNo;
+ UINT64 PrpListBase;
+ UINTN PrpListIndex;
+ UINTN PrpEntryIndex;
+ UINT64 Remainder;
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;
+ UINTN Bytes;
+ EFI_STATUS Status;
+
+ //
+ // The number of Prp Entry in a memory page.
+ //
+ PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
+
+ //
+ // Calculate total PrpList number.
+ //
+ *PrpListNo = (UINTN)DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo - 1, &Remainder);
+ if (*PrpListNo == 0) {
+ *PrpListNo = 1;
+ } else if ((Remainder != 0) && (Remainder != 1)) {
+ *PrpListNo += 1;
+ } else if (Remainder == 1) {
+ Remainder = PrpEntryNo;
+ } else if (Remainder == 0) {
+ Remainder = PrpEntryNo - 1;
+ }
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ *PrpListNo,
+ PrpListHost,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ *PrpListHost,
+ &Bytes,
+ &PrpListPhyAddr,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (*PrpListNo))) {
+ DEBUG ((EFI_D_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));
+ goto EXIT;
+ }
+ //
+ // Fill all PRP lists except of last one.
+ //
+ ZeroMem (*PrpListHost, Bytes);
+ for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+
+ for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
+ if (PrpEntryIndex != PrpEntryNo - 1) {
+ //
+ // Fill all PRP entries except of last one.
+ //
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;
+ PhysicalAddr += EFI_PAGE_SIZE;
+ } else {
+ //
+ // Fill last PRP entries with next PRP List pointer.
+ //
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;
+ }
+ }
+ }
+ //
+ // Fill last PRP list.
+ //
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+ for (PrpEntryIndex = 0; PrpEntryIndex < Remainder; ++PrpEntryIndex) {
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;
+ PhysicalAddr += EFI_PAGE_SIZE;
+ }
+
+ return (VOID*)(UINTN)PrpListPhyAddr;
+
+EXIT:
+ PciIo->FreeBuffer (PciIo, *PrpListNo, *PrpListHost);
+ return NULL;
+}
+
+
+/**
+ Aborts the asynchronous PassThru requests.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA
+ data structure.
+
+ @retval EFI_SUCCESS The asynchronous PassThru requests have been aborted.
+ @return EFI_DEVICE_ERROR Fail to abort all the asynchronous PassThru requests.
+
+**/
+EFI_STATUS
+AbortAsyncPassThruTasks (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ NVME_BLKIO2_SUBTASK *Subtask;
+ NVME_BLKIO2_REQUEST *BlkIo2Request;
+ NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
+ EFI_BLOCK_IO2_TOKEN *Token;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ PciIo = Private->PciIo;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Cancel the unsubmitted subtasks.
+ //
+ for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
+ !IsNull (&Private->UnsubmittedSubtasks, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);
+ Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
+ BlkIo2Request = Subtask->BlockIo2Request;
+ Token = BlkIo2Request->Token;
+
+ BlkIo2Request->UnsubmittedSubtaskNum--;
+ if (Subtask->IsLast) {
+ BlkIo2Request->LastSubtaskSubmitted = TRUE;
+ }
+ Token->TransactionStatus = EFI_ABORTED;
+
+ RemoveEntryList (Link);
+ InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
+ gBS->SignalEvent (Subtask->Event);
+ }
+
+ //
+ // Cleanup the resources for the asynchronous PassThru requests.
+ //
+ for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
+ !IsNull (&Private->AsyncPassThruQueue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
+ AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);
+
+ if (AsyncRequest->MapData != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapData);
+ }
+ if (AsyncRequest->MapMeta != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapMeta);
+ }
+ if (AsyncRequest->MapPrpList != NULL) {
+ PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);
+ }
+ if (AsyncRequest->PrpListHost != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ AsyncRequest->PrpListNo,
+ AsyncRequest->PrpListHost
+ );
+ }
+
+ RemoveEntryList (Link);
+ gBS->SignalEvent (AsyncRequest->CallerEvent);
+ FreePool (AsyncRequest);
+ }
+
+ if (IsListEmpty (&Private->AsyncPassThruQueue) &&
+ IsListEmpty (&Private->UnsubmittedSubtasks)) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
+ both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, and the non-blocking
+ I/O functionality is optional.
+
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] NamespaceId A 32 bit namespace ID as defined in the NVMe specification to which the NVM Express Command
+ Packet will be sent. A value of 0 denotes the NVM Express controller, a value of all 0xFF's
+ (all bytes are 0xFF) in the namespace ID specifies that the command packet should be sent to
+ all valid namespaces.
+ @param[in,out] Packet A pointer to the NVM Express Command Packet.
+ @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking I/O is performed.
+ If Event is NULL, then blocking I/O is performed. If Event is not NULL and non-blocking I/O
+ is supported, then non-blocking I/O is performed, and Event will be signaled when the NVM
+ Express Command Packet completes.
+
+ @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
+ to, or from DataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred
+ is returned in TransferLength.
+ @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller
+ may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.
+ @retval EFI_INVALID_PARAMETER NamespaceId or the contents of EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
+ Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the NVM Express
+ controller. The NVM Express Command Packet was not sent so no additional status information
+ is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressPassThru (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ EFI_STATUS PreviousStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ NVME_SQ *Sq;
+ NVME_CQ *Cq;
+ UINT16 QueueId;
+ UINT16 QueueSize;
+ UINT32 Bytes;
+ UINT16 Offset;
+ EFI_EVENT TimerEvent;
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *MapData;
+ VOID *MapMeta;
+ VOID *MapPrpList;
+ UINTN MapLength;
+ UINT64 *Prp;
+ VOID *PrpListHost;
+ UINTN PrpListNo;
+ UINT32 Attributes;
+ UINT32 IoAlign;
+ UINT32 MaxTransLen;
+ UINT32 Data;
+ NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
+ EFI_TPL OldTpl;
+
+ //
+ // check the data fields in Packet parameter.
+ //
+ if ((This == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->NvmeCmd == NULL) || (Packet->NvmeCompletion == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet->QueueType != NVME_ADMIN_QUEUE && Packet->QueueType != NVME_IO_QUEUE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 'Attributes' with neither EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL nor
+ // EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL set is an illegal
+ // configuration.
+ //
+ Attributes = This->Mode->Attributes;
+ if ((Attributes & (EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Buffer alignment check for TransferBuffer & MetadataBuffer.
+ //
+ IoAlign = This->Mode->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Packet->TransferBuffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IoAlign > 0 && (((UINTN) Packet->MetadataBuffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
+
+ //
+ // Check NamespaceId is valid or not.
+ //
+ if ((NamespaceId > Private->ControllerData->Nn) &&
+ (NamespaceId != (UINT32) -1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether TransferLength exceeds the maximum data transfer size.
+ //
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransLen = (1 << (Private->ControllerData->Mdts)) *
+ (1 << (Private->Cap.Mpsmin + 12));
+ if (Packet->TransferLength > MaxTransLen) {
+ Packet->TransferLength = MaxTransLen;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ MapData = NULL;
+ MapMeta = NULL;
+ MapPrpList = NULL;
+ PrpListHost = NULL;
+ PrpListNo = 0;
+ Prp = NULL;
+ TimerEvent = NULL;
+ Status = EFI_SUCCESS;
+ QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;
+
+ if (Packet->QueueType == NVME_ADMIN_QUEUE) {
+ QueueId = 0;
+ } else {
+ if (Event == NULL) {
+ QueueId = 1;
+ } else {
+ QueueId = 2;
+
+ //
+ // Submission queue full check.
+ //
+ if ((Private->SqTdbl[QueueId].Sqt + 1) % QueueSize ==
+ Private->AsyncSqHead) {
+ return EFI_NOT_READY;
+ }
+ }
+ }
+ Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;
+ Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
+
+ if (Packet->NvmeCmd->Nsid != NamespaceId) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Sq, sizeof (NVME_SQ));
+ Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
+ Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
+ Sq->Cid = Private->Cid[QueueId]++;
+ Sq->Nsid = Packet->NvmeCmd->Nsid;
+
+ //
+ // Currently we only support PRP for data transfer, SGL is NOT supported.
+ //
+ ASSERT (Sq->Psdt == 0);
+ if (Sq->Psdt != 0) {
+ DEBUG ((EFI_D_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;
+ if ((Packet->QueueType == NVME_ADMIN_QUEUE) &&
+ ((Sq->Opc == NVME_ADMIN_CRIOCQ_CMD) || (Sq->Opc == NVME_ADMIN_CRIOSQ_CMD))) {
+ //
+ // Currently, we only use the IO Completion/Submission queues created internally
+ // by this driver during controller initialization. Any other IO queues created
+ // will not be consumed here. The value is little to accept external IO queue
+ // creation requests, so here we will return EFI_UNSUPPORTED for external IO
+ // queue creation request.
+ //
+ if (!Private->CreateIoQueue) {
+ DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Does not support external IO queues creation request.\n"));
+ return EFI_UNSUPPORTED;
+ }
+ } else if ((Sq->Opc & (BIT0 | BIT1)) != 0) {
+ //
+ // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.
+ //
+ if (((Packet->TransferLength != 0) && (Packet->TransferBuffer == NULL)) ||
+ ((Packet->TransferLength == 0) && (Packet->TransferBuffer != NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Sq->Opc & BIT0) != 0) {
+ Flag = EfiPciIoOperationBusMasterRead;
+ } else {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ }
+
+ if ((Packet->TransferLength != 0) && (Packet->TransferBuffer != NULL)) {
+ MapLength = Packet->TransferLength;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Packet->TransferBuffer,
+ &MapLength,
+ &PhyAddr,
+ &MapData
+ );
+ if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Sq->Prp[0] = PhyAddr;
+ Sq->Prp[1] = 0;
+ }
+
+ if((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {
+ MapLength = Packet->MetadataLength;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Packet->MetadataBuffer,
+ &MapLength,
+ &PhyAddr,
+ &MapMeta
+ );
+ if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) {
+ PciIo->Unmap (
+ PciIo,
+ MapData
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Sq->Mptr = PhyAddr;
+ }
+ }
+ //
+ // If the buffer size spans more than two memory pages (page size as defined in CC.Mps),
+ // then build a PRP list in the second PRP submission queue entry.
+ //
+ Offset = ((UINT16)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
+ Bytes = Packet->TransferLength;
+
+ if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
+ //
+ // Create PrpList for remaining data buffer.
+ //
+ PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);
+ if (Prp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ Sq->Prp[1] = (UINT64)(UINTN)Prp;
+ } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
+ Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ }
+
+ if(Packet->NvmeCmd->Flags & CDW2_VALID) {
+ Sq->Rsvd2 = (UINT64)Packet->NvmeCmd->Cdw2;
+ }
+ if(Packet->NvmeCmd->Flags & CDW3_VALID) {
+ Sq->Rsvd2 |= LShiftU64 ((UINT64)Packet->NvmeCmd->Cdw3, 32);
+ }
+ if(Packet->NvmeCmd->Flags & CDW10_VALID) {
+ Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
+ }
+ if(Packet->NvmeCmd->Flags & CDW11_VALID) {
+ Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
+ }
+ if(Packet->NvmeCmd->Flags & CDW12_VALID) {
+ Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
+ }
+ if(Packet->NvmeCmd->Flags & CDW13_VALID) {
+ Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
+ }
+ if(Packet->NvmeCmd->Flags & CDW14_VALID) {
+ Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
+ }
+ if(Packet->NvmeCmd->Flags & CDW15_VALID) {
+ Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
+ }
+
+ //
+ // Ring the submission queue doorbell.
+ //
+ if ((Event != NULL) && (QueueId != 0)) {
+ Private->SqTdbl[QueueId].Sqt =
+ (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;
+ } else {
+ Private->SqTdbl[QueueId].Sqt ^= 1;
+ }
+ Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueId]);
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_SQTDBL_OFFSET(QueueId, Private->Cap.Dstrd),
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // For non-blocking requests, return directly if the command is placed
+ // in the submission queue.
+ //
+ if ((Event != NULL) && (QueueId != 0)) {
+ AsyncRequest = AllocateZeroPool (sizeof (NVME_PASS_THRU_ASYNC_REQ));
+ if (AsyncRequest == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto EXIT;
+ }
+
+ AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;
+ AsyncRequest->Packet = Packet;
+ AsyncRequest->CommandId = Sq->Cid;
+ AsyncRequest->CallerEvent = Event;
+ AsyncRequest->MapData = MapData;
+ AsyncRequest->MapMeta = MapMeta;
+ AsyncRequest->MapPrpList = MapPrpList;
+ AsyncRequest->PrpListNo = PrpListNo;
+ AsyncRequest->PrpListHost = PrpListHost;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ Status = gBS->SetTimer(TimerEvent, TimerRelative, Packet->CommandTimeout);
+
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Wait for completion queue to get filled in.
+ //
+ Status = EFI_TIMEOUT;
+ while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {
+ if (Cq->Pt != Private->Pt[QueueId]) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ //
+ // Check the NVMe cmd execution result
+ //
+ if (Status != EFI_TIMEOUT) {
+ if ((Cq->Sct == 0) && (Cq->Sc == 0)) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ //
+ // Dump every completion entry status for debugging.
+ //
+ DEBUG_CODE_BEGIN();
+ NvmeDumpStatus(Cq);
+ DEBUG_CODE_END();
+ }
+ //
+ // Copy the Respose Queue entry for this command to the callers response buffer
+ //
+ CopyMem(Packet->NvmeCompletion, Cq, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ } else {
+ //
+ // Timeout occurs for an NVMe command. Reset the controller to abort the
+ // outstanding commands.
+ //
+ DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe command.\n"));
+
+ //
+ // Disable the timer to trigger the process of async transfers temporarily.
+ //
+ Status = gBS->SetTimer (Private->TimerEvent, TimerCancel, 0);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Reset the NVMe controller.
+ //
+ Status = NvmeControllerInit (Private);
+ if (!EFI_ERROR (Status)) {
+ Status = AbortAsyncPassThruTasks (Private);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Re-enable the timer to trigger the process of async transfers.
+ //
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME_HC_ASYNC_TIMER);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe PassThru command.
+ //
+ Status = EFI_TIMEOUT;
+ }
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ goto EXIT;
+ }
+
+ if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {
+ Private->Pt[QueueId] ^= 1;
+ }
+
+ Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);
+ PreviousStatus = Status;
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ NVME_BAR,
+ NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),
+ 1,
+ &Data
+ );
+ // The return status of PciIo->Mem.Write should not override
+ // previous status if previous status contains error.
+ Status = EFI_ERROR (PreviousStatus) ? PreviousStatus : Status;
+
+ //
+ // For now, the code does not support the non-blocking feature for admin queue.
+ // If Event is not NULL for admin queue, signal the caller's event here.
+ //
+ if (Event != NULL) {
+ ASSERT (QueueId == 0);
+ gBS->SignalEvent (Event);
+ }
+
+EXIT:
+ if (MapData != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ MapData
+ );
+ }
+
+ if (MapMeta != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ MapMeta
+ );
+ }
+
+ if (MapPrpList != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ MapPrpList
+ );
+ }
+
+ if (Prp != NULL) {
+ PciIo->FreeBuffer (PciIo, PrpListNo, PrpListHost);
+ }
+
+ if (TimerEvent != NULL) {
+ gBS->CloseEvent (TimerEvent);
+ }
+ return Status;
+}
+
+/**
+ Used to retrieve the next namespace ID for this NVM Express controller.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves the next valid
+ namespace ID on this NVM Express controller.
+
+ If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first valid namespace
+ ID defined on the NVM Express controller is returned in the location pointed to by NamespaceId
+ and a status of EFI_SUCCESS is returned.
+
+ If on input the value pointed to by NamespaceId is an invalid namespace ID other than 0xFFFFFFFF,
+ then EFI_INVALID_PARAMETER is returned.
+
+ If on input the value pointed to by NamespaceId is a valid namespace ID, then the next valid
+ namespace ID on the NVM Express controller is returned in the location pointed to by NamespaceId,
+ and EFI_SUCCESS is returned.
+
+ If the value pointed to by NamespaceId is the namespace ID of the last namespace on the NVM
+ Express controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express
+ namespace present on the NVM Express controller. On output, a
+ pointer to the next NamespaceId of an NVM Express namespace on
+ an NVM Express controller. An input value of 0xFFFFFFFF retrieves
+ the first NamespaceId for an NVM Express namespace present on an
+ NVM Express controller.
+
+ @retval EFI_SUCCESS The Namespace ID of the next Namespace was returned.
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.
+ @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than 0xFFFFFFFF.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressGetNextNamespace (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT32 *NamespaceId
+ )
+{
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+ UINT32 NextNamespaceId;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (NamespaceId == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NamespaceData = NULL;
+ Status = EFI_NOT_FOUND;
+
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
+ //
+ // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID
+ //
+ if (*NamespaceId == 0xFFFFFFFF) {
+ //
+ // Start with the first namespace ID
+ //
+ NextNamespaceId = 1;
+ //
+ // Allocate buffer for Identify Namespace data.
+ //
+ NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
+
+ if (NamespaceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ *NamespaceId = NextNamespaceId;
+ } else {
+ if (*NamespaceId > Private->ControllerData->Nn) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NextNamespaceId = *NamespaceId + 1;
+ if (NextNamespaceId > Private->ControllerData->Nn) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate buffer for Identify Namespace data.
+ //
+ NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ if (NamespaceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ *NamespaceId = NextNamespaceId;
+ }
+
+Done:
+ if (NamespaceData != NULL) {
+ FreePool(NamespaceData);
+ }
+
+ return Status;
+}
+
+/**
+ Used to translate a device path node to a namespace ID.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamespace() function determines the namespace ID associated with the
+ namespace described by DevicePath.
+
+ If DevicePath is a device path node type that the NVM Express Pass Thru driver supports, then the NVM Express
+ Pass Thru driver will attempt to translate the contents DevicePath into a namespace ID.
+
+ If this translation is successful, then that namespace ID is returned in NamespaceId, and EFI_SUCCESS is returned
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on
+ the NVM Express controller.
+ @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId.
+ @retval EFI_INVALID_PARAMETER If DevicePath or NamespaceId are NULL, then EFI_INVALID_PARAMETER is returned.
+ @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver
+ supports, then EFI_UNSUPPORTED is returned.
+ @retval EFI_NOT_FOUND If DevicePath is a device path node type that the NVM Express Pass Thru driver
+ supports, but there is not a valid translation from DevicePath to a namespace ID,
+ then EFI_NOT_FOUND is returned.
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressGetNamespace (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT32 *NamespaceId
+ )
+{
+ NVME_NAMESPACE_DEVICE_PATH *Node;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || (DevicePath == NULL) || (NamespaceId == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DevicePath->Type != MESSAGING_DEVICE_PATH) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Node = (NVME_NAMESPACE_DEVICE_PATH *)DevicePath;
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
+
+ if (DevicePath->SubType == MSG_NVME_NAMESPACE_DP) {
+ if (DevicePathNodeLength(DevicePath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check NamespaceId in the device path node is valid or not.
+ //
+ if ((Node->NamespaceId == 0) ||
+ (Node->NamespaceId > Private->ControllerData->Nn)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *NamespaceId = Node->NamespaceId;
+
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.
+
+ The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device
+ path node for the NVM Express namespace specified by NamespaceId.
+
+ If the NamespaceId is not valid, then EFI_NOT_FOUND is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are
+ initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express
+ namespace specified by NamespaceId. This function is responsible for
+ allocating the buffer DevicePath with the boot service AllocatePool().
+ It is the caller's responsibility to free DevicePath when the caller
+ is finished with DevicePath.
+ @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified
+ by NamespaceId was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The NamespaceId is not valid.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressBuildDevicePath (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ NVME_NAMESPACE_DEVICE_PATH *Node;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+
+ //
+ // Validate parameters
+ //
+ if ((This == NULL) || (DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
+
+ //
+ // Check NamespaceId is valid or not.
+ //
+ if ((NamespaceId == 0) ||
+ (NamespaceId > Private->ControllerData->Nn)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Node = (NVME_NAMESPACE_DEVICE_PATH *)AllocateZeroPool (sizeof (NVME_NAMESPACE_DEVICE_PATH));
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Node->Header.Type = MESSAGING_DEVICE_PATH;
+ Node->Header.SubType = MSG_NVME_NAMESPACE_DP;
+ SetDevicePathNodeLength (&Node->Header, sizeof (NVME_NAMESPACE_DEVICE_PATH));
+ Node->NamespaceId = NamespaceId;
+
+ //
+ // Allocate a buffer for Identify Namespace data.
+ //
+ NamespaceData = NULL;
+ NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ if(NamespaceData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Get UUID from specified Identify Namespace data.
+ //
+ Status = NvmeIdentifyNamespace (
+ Private,
+ NamespaceId,
+ (VOID *)NamespaceData
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+
+ Node->NamespaceUuid = NamespaceData->Eui64;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;
+
+Exit:
+ if(NamespaceData != NULL) {
+ FreePool (NamespaceData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Node);
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
new file mode 100644
index 000000000..6f9ff4b7d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
@@ -0,0 +1,277 @@
+/** @file
+ The device path help function.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+//
+// Template for an Nvm Express Device Path node
+//
+NVME_NAMESPACE_DEVICE_PATH mNvmeDevicePathNodeTemplate = {
+ { // Header
+ MESSAGING_DEVICE_PATH,
+ MSG_NVME_NAMESPACE_DP,
+ {
+ (UINT8) (sizeof (NVME_NAMESPACE_DEVICE_PATH)),
+ (UINT8) ((sizeof (NVME_NAMESPACE_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0x0, // NamespaceId
+ 0x0 // NamespaceUuid
+};
+
+//
+// Template for an End of entire Device Path node
+//
+EFI_DEVICE_PATH_PROTOCOL mNvmeEndDevicePathNodeTemplate = {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+ (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+ }
+};
+
+/**
+ Returns the 16-bit Length field of a device path node.
+
+ Returns the 16-bit Length field of the device path node specified by Node.
+ Node is not required to be aligned on a 16-bit boundary, so it is recommended
+ that a function such as ReadUnaligned16() be used to extract the contents of
+ the Length field.
+
+ If Node is NULL, then ASSERT().
+
+ @param Node A pointer to a device path node data structure.
+
+ @return The 16-bit Length field of the device path node specified by Node.
+
+**/
+UINTN
+DevicePathNodeLength (
+ IN CONST VOID *Node
+ )
+{
+ ASSERT (Node != NULL);
+ return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
+}
+
+/**
+ Returns a pointer to the next node in a device path.
+
+ If Node is NULL, then ASSERT().
+
+ @param Node A pointer to a device path node data structure.
+
+ @return a pointer to the device path node that follows the device path node
+ specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+ IN CONST VOID *Node
+ )
+{
+ ASSERT (Node != NULL);
+ return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
+}
+
+/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Walker;
+
+ if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the end of the device path instance
+ //
+ Walker = DevicePath;
+ while (Walker->Type != END_DEVICE_PATH_TYPE) {
+ Walker = NextDevicePathNode (Walker);
+ }
+
+ //
+ // Check if 'Walker' points to the end of an entire device path
+ //
+ if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = TRUE;
+ } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = FALSE;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Compute the size of the device path instance
+ //
+ *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the validity of the device path of a NVM Express host controller.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[in] DevicePathLength The length of the device path.
+
+ @retval EFI_SUCCESS The device path is valid.
+ @retval EFI_INVALID_PARAMETER The device path is invalid.
+
+**/
+EFI_STATUS
+NvmeIsHcDevicePathValid (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN DevicePathLength
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Start;
+ UINTN Size;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Validate the DevicePathLength is big enough to touch the first node.
+ //
+ if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Start = DevicePath;
+ while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&
+ DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+
+ //
+ // Prevent overflow and invalid zero in the 'Length' field of a device path
+ // node.
+ //
+ if ((UINTN) DevicePath <= (UINTN) Start) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Prevent touching memory beyond given DevicePathLength.
+ //
+ if ((UINTN) DevicePath - (UINTN) Start >
+ DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Check if the device path and its size match exactly with each other.
+ //
+ Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ if (Size != DevicePathLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build the device path for an Nvm Express device with given namespace identifier
+ and namespace extended unique identifier.
+
+ @param[in] Private A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+ data structure.
+ @param[in] NamespaceId The given namespace identifier.
+ @param[in] NamespaceUuid The given namespace extended unique identifier.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of Nvm Express device.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+NvmeBuildDevicePath (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN UINT64 NamespaceUuid,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
+ NVME_NAMESPACE_DEVICE_PATH *NvmeDeviceNode;
+
+ if (DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *DevicePathLength = Private->DevicePathLength + sizeof (NVME_NAMESPACE_DEVICE_PATH);
+ *DevicePath = AllocatePool (*DevicePathLength);
+ if (*DevicePath == NULL) {
+ *DevicePathLength = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Construct the host controller part device nodes
+ //
+ DevicePathWalker = *DevicePath;
+ CopyMem (
+ DevicePathWalker,
+ Private->DevicePath,
+ Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+ );
+
+ //
+ // Construct the Nvm Express device node
+ //
+ DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+ (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
+ CopyMem (
+ DevicePathWalker,
+ &mNvmeDevicePathNodeTemplate,
+ sizeof (mNvmeDevicePathNodeTemplate)
+ );
+ NvmeDeviceNode = (NVME_NAMESPACE_DEVICE_PATH *)DevicePathWalker;
+ NvmeDeviceNode->NamespaceId = NamespaceId;
+ NvmeDeviceNode->NamespaceUuid = NamespaceUuid;
+
+ //
+ // Construct the end device node
+ //
+ DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+ sizeof (NVME_NAMESPACE_DEVICE_PATH));
+ CopyMem (
+ DevicePathWalker,
+ &mNvmeEndDevicePathNodeTemplate,
+ sizeof (mNvmeEndDevicePathNodeTemplate)
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c
new file mode 100644
index 000000000..7b049b9e4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c
@@ -0,0 +1,263 @@
+/** @file
+ The DMA memory help function.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Get IOMMU PPI.
+
+ @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = NULL;
+ Status = PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->Map (
+ IoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ Status = IoMmu->Unmap (IoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = GetIoMmu ();
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ Status = IoMmu->Unmap (IoMmu, Mapping);
+ Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
new file mode 100644
index 000000000..a8cb7f3a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
@@ -0,0 +1,462 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiStorageSecurityCommandPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mNvmePassThruPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiNvmExpressPassThruPpiGuid,
+ NULL
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ NvmePeimEndOfPei
+};
+
+/**
+ Check if the specified Nvm Express device namespace is active, and then get the Identify
+ Namespace data.
+
+ @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] NamespaceId The specified namespace identifier.
+
+ @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
+ @return Others Error occurs when enumerating the namespace.
+
+**/
+EFI_STATUS
+EnumerateNvmeDevNamespace (
+ IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId
+ )
+{
+ EFI_STATUS Status;
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+ PEI_NVME_NAMESPACE_INFO *NamespaceInfo;
+ UINT32 DeviceIndex;
+ UINT32 Lbads;
+ UINT32 Flbas;
+ UINT32 LbaFmtIdx;
+
+ NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ if (NamespaceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Identify Namespace
+ //
+ Status = NvmeIdentifyNamespace (
+ Private,
+ NamespaceId,
+ NamespaceData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));
+ goto Exit;
+ }
+
+ //
+ // Validate Namespace
+ //
+ if (NamespaceData->Ncap == 0) {
+ DEBUG ((DEBUG_INFO, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__, NamespaceId));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ DeviceIndex = Private->ActiveNamespaceNum;
+ NamespaceInfo = &Private->NamespaceInfo[DeviceIndex];
+ NamespaceInfo->NamespaceId = NamespaceId;
+ NamespaceInfo->NamespaceUuid = NamespaceData->Eui64;
+ NamespaceInfo->Controller = Private;
+ Private->ActiveNamespaceNum++;
+
+ //
+ // Build BlockIo media structure
+ //
+ Flbas = NamespaceData->Flbas;
+ LbaFmtIdx = Flbas & 0xF;
+ Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
+
+ NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP;
+ NamespaceInfo->Media.RemovableMedia = FALSE;
+ NamespaceInfo->Media.MediaPresent = TRUE;
+ NamespaceInfo->Media.ReadOnly = FALSE;
+ NamespaceInfo->Media.BlockSize = (UINT32) 1 << Lbads;
+ NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA) NamespaceData->Nsze - 1;
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
+ __FUNCTION__,
+ NamespaceId,
+ NamespaceInfo->Media.BlockSize,
+ NamespaceInfo->Media.LastBlock
+ ));
+
+Exit:
+ if (NamespaceData != NULL) {
+ FreePool (NamespaceData);
+ }
+
+ return Status;
+}
+
+/**
+ Discover all Nvm Express device active namespaces.
+
+ @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
+ @return EFI_NOT_FOUND No active namespaces can be found.
+
+**/
+EFI_STATUS
+NvmeDiscoverNamespaces (
+ IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ UINT32 NamespaceId;
+
+ Private->ActiveNamespaceNum = 0;
+ Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));
+
+ //
+ // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
+ // controller data defines the number of valid namespaces present for the
+ // controller. Namespaces shall be allocated in order (starting with 1) and
+ // packed sequentially.
+ //
+ for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {
+ //
+ // For now, we do not care the return status. Since if a valid namespace is inactive,
+ // error status will be returned. But we continue to enumerate other valid namespaces.
+ //
+ EnumerateNvmeDevNamespace (Private, NamespaceId);
+ }
+ if (Private->ActiveNamespaceNum == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ One notified function to cleanup the allocated resources at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+ NvmeFreeDmaResource (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of the PEIM.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;
+ UINT8 Controller;
+ UINTN MmioBase;
+ UINTN DevicePathLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+
+ DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
+
+ //
+ // Get the current boot mode.
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
+ return Status;
+ }
+
+ //
+ // Locate the NVME host controller PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiNvmExpressHostControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &NvmeHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+
+ Controller = 0;
+ MmioBase = 0;
+ while (TRUE) {
+ Status = NvmeHcPpi->GetNvmeHcMmioBar (
+ NvmeHcPpi,
+ Controller,
+ &MmioBase
+ );
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = NvmeHcPpi->GetNvmeHcDevicePath (
+ NvmeHcPpi,
+ Controller,
+ &DevicePathLength,
+ &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ return Status;
+ }
+
+ //
+ // Check validity of the device path of the NVM Express controller.
+ //
+ Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ Controller++;
+ continue;
+ }
+
+ //
+ // For S3 resume performance consideration, not all NVM Express controllers
+ // will be initialized. The driver consumes the content within
+ // S3StorageDeviceInitList LockBox to see if a controller will be skipped
+ // during S3 resume.
+ //
+ if ((BootMode == BOOT_ON_S3_RESUME) &&
+ (NvmeS3SkipThisController (DevicePath, DevicePathLength))) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n",
+ __FUNCTION__, Controller
+ ));
+ Controller++;
+ continue;
+ }
+
+ //
+ // Memory allocation for controller private data
+ //
+ Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));
+ if (Private == NULL) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Memory allocation for transfer-related data
+ //
+ Status = IoMmuAllocateBuffer (
+ NVME_MEM_MAX_PAGES,
+ &Private->Buffer,
+ &DeviceAddress,
+ &Private->BufferMapping
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "%a: Fail to allocate DMA buffers for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ return Status;
+ }
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Private->Buffer));
+ DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));
+
+ //
+ // Initialize controller private data
+ //
+ Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+ Private->MmioBase = MmioBase;
+ Private->DevicePathLength = DevicePathLength;
+ Private->DevicePath = DevicePath;
+
+ //
+ // Initialize the NVME controller
+ //
+ Status = NvmeControllerInit (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Controller initialization fail for Controller %d with Status - %r.\n",
+ __FUNCTION__, Controller, Status
+ ));
+ NvmeFreeDmaResource (Private);
+ Controller++;
+ continue;
+ }
+
+ //
+ // Enumerate the NVME namespaces on the controller
+ //
+ Status = NvmeDiscoverNamespaces (Private);
+ if (EFI_ERROR (Status)) {
+ //
+ // No active namespace was found on the controller
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
+ __FUNCTION__, Controller, Status
+ ));
+ NvmeFreeDmaResource (Private);
+ Controller++;
+ continue;
+ }
+
+ //
+ // Nvm Express Pass Thru PPI
+ //
+ Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM;
+ Private->PassThruMode.IoAlign = sizeof (UINTN);
+ Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION;
+ Private->NvmePassThruPpi.Mode = &Private->PassThruMode;
+ Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath;
+ Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace;
+ Private->NvmePassThruPpi.PassThru = NvmePassThru;
+ CopyMem (
+ &Private->NvmePassThruPpiList,
+ &mNvmePassThruPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi;
+ PeiServicesInstallPpi (&Private->NvmePassThruPpiList);
+
+ //
+ // Block Io PPI
+ //
+ Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;
+ Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;
+ Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;
+ CopyMem (
+ &Private->BlkIoPpiList,
+ &mNvmeBlkIoPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
+
+ Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
+ Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;
+ Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;
+ Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2;
+ CopyMem (
+ &Private->BlkIo2PpiList,
+ &mNvmeBlkIo2PpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+
+ //
+ // Check if the NVME controller supports the Security Receive/Send commands
+ //
+ if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Security Security Command PPI will be produced for Controller %d.\n",
+ __FUNCTION__, Controller
+ ));
+ Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;
+ Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;
+ Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath;
+ Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData;
+ Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData;
+ CopyMem (
+ &Private->StorageSecurityPpiList,
+ &mNvmeStorageSecurityPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
+ PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
+ }
+
+ CopyMem (
+ &Private->EndOfPeiNotifyList,
+ &mNvmeEndOfPeiNotifyListTemplate,
+ sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
+ );
+ PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+
+ DEBUG ((
+ DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
+ __FUNCTION__, Controller
+ ));
+ Controller++;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
new file mode 100644
index 000000000..8cd905191
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
@@ -0,0 +1,349 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_H_
+#define _NVM_EXPRESS_PEI_H_
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Nvme.h>
+
+#include <Ppi/NvmExpressHostController.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/StorageSecurityCommand.h>
+#include <Ppi/NvmExpressPassThru.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+
+//
+// Structure forward declarations
+//
+typedef struct _PEI_NVME_NAMESPACE_INFO PEI_NVME_NAMESPACE_INFO;
+typedef struct _PEI_NVME_CONTROLLER_PRIVATE_DATA PEI_NVME_CONTROLLER_PRIVATE_DATA;
+
+#include "NvmExpressPeiHci.h"
+#include "NvmExpressPeiPassThru.h"
+#include "NvmExpressPeiBlockIo.h"
+#include "NvmExpressPeiStorageSecurity.h"
+
+//
+// NVME PEI driver implementation related definitions
+//
+#define NVME_MAX_QUEUES 2 // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ
+#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based
+#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based
+#define NVME_CSQ_SIZE 63 // Number of I/O submission queue entries, which is 0-based
+#define NVME_CCQ_SIZE 63 // Number of I/O completion queue entries, which is 0-based
+#define NVME_PRP_SIZE (8) // Pages of PRP list
+
+#define NVME_MEM_MAX_PAGES \
+ ( \
+ 1 /* ASQ */ + \
+ 1 /* ACQ */ + \
+ 1 /* SQs */ + \
+ 1 /* CQs */ + \
+ NVME_PRP_SIZE) /* PRPs */
+
+#define NVME_ADMIN_QUEUE 0x00
+#define NVME_IO_QUEUE 0x01
+#define NVME_GENERIC_TIMEOUT 5000000 // Generic PassThru command timeout value, in us unit
+#define NVME_POLL_INTERVAL 100 // Poll interval for PassThru command, in us unit
+
+//
+// Nvme namespace data structure.
+//
+struct _PEI_NVME_NAMESPACE_INFO {
+ UINT32 NamespaceId;
+ UINT64 NamespaceUuid;
+ EFI_PEI_BLOCK_IO2_MEDIA Media;
+
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Controller;
+};
+
+#define NVME_CONTROLLER_NSID 0
+
+//
+// Unique signature for private data structure.
+//
+#define NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('N','V','P','C')
+
+//
+// Nvme controller private data structure.
+//
+struct _PEI_NVME_CONTROLLER_PRIVATE_DATA {
+ UINT32 Signature;
+ UINTN MmioBase;
+ EFI_NVM_EXPRESS_PASS_THRU_MODE PassThruMode;
+ UINTN DevicePathLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi;
+ EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI NvmePassThruPpi;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+ EFI_PEI_PPI_DESCRIPTOR StorageSecurityPpiList;
+ EFI_PEI_PPI_DESCRIPTOR NvmePassThruPpiList;
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ //
+ // Pointer to identify controller data
+ //
+ NVME_ADMIN_CONTROLLER_DATA *ControllerData;
+
+ //
+ // (4 + NVME_PRP_SIZE) x 4kB aligned buffers will be carved out of this buffer
+ // 1st 4kB boundary is the start of the admin submission queue
+ // 2nd 4kB boundary is the start of the admin completion queue
+ // 3rd 4kB boundary is the start of I/O submission queue
+ // 4th 4kB boundary is the start of I/O completion queue
+ // 5th 4kB boundary is the start of PRP list buffers
+ //
+ VOID *Buffer;
+ VOID *BufferMapping;
+
+ //
+ // Pointers to 4kB aligned submission & completion queues
+ //
+ NVME_SQ *SqBuffer[NVME_MAX_QUEUES];
+ NVME_CQ *CqBuffer[NVME_MAX_QUEUES];
+
+ //
+ // Submission and completion queue indices
+ //
+ NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES];
+ NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES];
+
+ UINT8 Pt[NVME_MAX_QUEUES];
+ UINT16 Cid[NVME_MAX_QUEUES];
+
+ //
+ // Nvme controller capabilities
+ //
+ NVME_CAP Cap;
+
+ //
+ // Namespaces information on the controller
+ //
+ UINT32 ActiveNamespaceNum;
+ PEI_NVME_NAMESPACE_INFO *NamespaceInfo;
+};
+
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a) \
+ CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIoPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a) \
+ CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIo2Ppi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY(a) \
+ CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, StorageSecurityPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU(a) \
+ CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, NvmePassThruPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) \
+ CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+
+
+//
+// Internal functions
+//
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ One notified function to cleanup the allocated resources at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ );
+
+/**
+ Check the validity of the device path of a NVM Express host controller.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[in] DevicePathLength The length of the device path.
+
+ @retval EFI_SUCCESS The device path is valid.
+ @retval EFI_INVALID_PARAMETER The device path is invalid.
+
+**/
+EFI_STATUS
+NvmeIsHcDevicePathValid (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN DevicePathLength
+ );
+
+/**
+ Build the device path for an Nvm Express device with given namespace identifier
+ and namespace extended unique identifier.
+
+ @param[in] Private A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+ data structure.
+ @param[in] NamespaceId The given namespace identifier.
+ @param[in] NamespaceUuid The given namespace extended unique identifier.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of Nvm Express device.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+NvmeBuildDevicePath (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN UINT64 NamespaceUuid,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Determine if a specific NVM Express controller can be skipped for S3 phase.
+
+ @param[in] HcDevicePath Device path of the controller.
+ @param[in] HcDevicePathLength Length of the device path specified by
+ HcDevicePath.
+
+ @retval The number of ports that need to be enumerated.
+
+**/
+BOOLEAN
+NvmeS3SkipThisController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath,
+ IN UINTN HcDevicePathLength
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
new file mode 100644
index 000000000..4dd6c5704
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
@@ -0,0 +1,73 @@
+## @file
+# The NvmExpressPei driver is used to manage non-volatile memory subsystem
+# which follows NVM Express specification at PEI phase.
+#
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NvmExpressPei
+ MODULE_UNI_FILE = NvmExpressPei.uni
+ FILE_GUID = 94813714-E10A-4798-9909-8C904F66B4D9
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = NvmExpressPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DevicePath.c
+ DmaMem.c
+ NvmExpressPei.c
+ NvmExpressPei.h
+ NvmExpressPeiBlockIo.c
+ NvmExpressPeiBlockIo.h
+ NvmExpressPeiHci.c
+ NvmExpressPeiHci.h
+ NvmExpressPeiPassThru.c
+ NvmExpressPeiPassThru.h
+ NvmExpressPeiS3.c
+ NvmExpressPeiStorageSecurity.c
+ NvmExpressPeiStorageSecurity.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PeiServicesLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ LockBoxLib
+ PeimEntryPoint
+
+[Ppis]
+ gEdkiiPeiNvmExpressHostControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+ gEdkiiPeiNvmExpressPassThruPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES
+ gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES
+
+[Guids]
+ gS3StorageDeviceInitListGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND
+ gEdkiiPeiNvmExpressHostControllerPpiGuid AND
+ gEfiPeiMasterBootModePpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ NvmExpressPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.uni
new file mode 100644
index 000000000..e1e98ba83
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// The NvmExpressPei driver is used to manage non-volatile memory subsystem
+// which follows NVM Express specification at PEI phase.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manage non-volatile memory subsystem at PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The NvmExpressPei driver is used to manage non-volatile memory subsystem which follows NVM Express specification at PEI phase."
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.c
new file mode 100644
index 000000000..a9bf4f819
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.c
@@ -0,0 +1,523 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Read some sectors from the device.
+
+ @param NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
+ @param Buffer The buffer used to store the data read from the device.
+ @param Lba The start block number.
+ @param Blocks Total block number to be read.
+
+ @retval EFI_SUCCESS Data are read from the device.
+ @retval Others Fail to read all the data.
+
+**/
+EFI_STATUS
+ReadSectors (
+ IN PEI_NVME_NAMESPACE_INFO *NamespaceInfo,
+ OUT UINTN Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 Bytes;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *NvmePassThru;
+
+ Private = NamespaceInfo->Controller;
+ NvmePassThru = &Private->NvmePassThruPpi;
+ BlockSize = NamespaceInfo->Media.BlockSize;
+ Bytes = Blocks * BlockSize;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
+ CommandPacket.NvmeCmd->Nsid = NamespaceInfo->NamespaceId;
+ CommandPacket.TransferBuffer = (VOID *)Buffer;
+
+ CommandPacket.TransferLength = Bytes;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_IO_QUEUE;
+
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ Status = NvmePassThru->PassThru (
+ NvmePassThru,
+ NamespaceInfo->NamespaceId,
+ &CommandPacket
+ );
+
+ return Status;
+}
+
+/**
+ Read some blocks from the device.
+
+ @param[in] NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
+ @param[out] Buffer The Buffer used to store the Data read from the device.
+ @param[in] Lba The start block number.
+ @param[in] Blocks Total block number to be read.
+
+ @retval EFI_SUCCESS Data are read from the device.
+ @retval Others Fail to read all the data.
+
+**/
+EFI_STATUS
+NvmeRead (
+ IN PEI_NVME_NAMESPACE_INFO *NamespaceInfo,
+ OUT UINTN Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Retries;
+ UINT32 BlockSize;
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 MaxTransferBlocks;
+ UINTN OrginalBlocks;
+
+ Status = EFI_SUCCESS;
+ Retries = 0;
+ Private = NamespaceInfo->Controller;
+ BlockSize = NamespaceInfo->Media.BlockSize;
+ OrginalBlocks = Blocks;
+
+ if (Private->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ Status = ReadSectors (
+ NamespaceInfo,
+ Buffer,
+ Lba,
+ Blocks > MaxTransferBlocks ? MaxTransferBlocks : (UINT32)Blocks
+ );
+ if (EFI_ERROR(Status)) {
+ Retries++;
+ MaxTransferBlocks = MaxTransferBlocks >> 1;
+
+ if (Retries > NVME_READ_MAX_RETRY || MaxTransferBlocks < 1) {
+ DEBUG ((DEBUG_ERROR, "%a: ReadSectors fail, Status - %r\n", __FUNCTION__, Status));
+ break;
+ }
+ DEBUG ((
+ DEBUG_BLKIO,
+ "%a: ReadSectors fail, retry with smaller transfer block number - 0x%x\n",
+ __FUNCTION__,
+ MaxTransferBlocks
+ ));
+ continue;
+ }
+
+ if (Blocks > MaxTransferBlocks) {
+ Blocks -= MaxTransferBlocks;
+ Buffer += (MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Blocks = 0;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
+ return Status;
+}
+
+/**
+ 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. 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ *NumberBlockDevices = Private->ActiveNamespaceNum;
+
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveNamespaceNum)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE) EDKII_PEI_BLOCK_DEVICE_TYPE_NVME;
+ MediaInfo->MediaPresent = TRUE;
+ MediaInfo->LastBlock = (UINTN)Private->NamespaceInfo[DeviceIndex-1].Media.LastBlock;
+ MediaInfo->BlockSize = Private->NamespaceInfo[DeviceIndex-1].Media.BlockSize;
+
+ 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, 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
+NvmeBlockIoPeimReadBlocks (
+ 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
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_NVME_NAMESPACE_INFO *NamespaceInfo;
+ UINT32 BlockSize;
+ UINTN NumberOfBlocks;
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+
+ //
+ // Check parameters
+ //
+ if (This == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveNamespaceNum)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check BufferSize and StartLBA
+ //
+ NamespaceInfo = &(Private->NamespaceInfo[DeviceIndex - 1]);
+ BlockSize = NamespaceInfo->Media.BlockSize;
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > NamespaceInfo->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+ NumberOfBlocks = BufferSize / BlockSize;
+ if (NumberOfBlocks - 1 > NamespaceInfo->Media.LastBlock - StartLBA) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return NvmeRead (NamespaceInfo, (UINTN)Buffer, StartLBA, NumberOfBlocks);
+}
+
+/**
+ 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. 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ *NumberBlockDevices = Private->ActiveNamespaceNum;
+
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+
+ Status = NvmeBlockIoPeimGetMediaInfo (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ &Media
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (
+ MediaInfo,
+ &(Private->NamespaceInfo[DeviceIndex - 1].Media),
+ sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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, 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
+NvmeBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ return NvmeBlockIoPeimReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.h
new file mode 100644
index 000000000..2c7065cb7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiBlockIo.h
@@ -0,0 +1,259 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_BLOCKIO_H_
+#define _NVM_EXPRESS_PEI_BLOCKIO_H_
+
+//
+// Nvme device for EFI_PEI_BLOCK_DEVICE_TYPE
+//
+#define EDKII_PEI_BLOCK_DEVICE_TYPE_NVME 7
+
+#define NVME_READ_MAX_RETRY 3
+
+/**
+ 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. 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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, 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
+NvmeBlockIoPeimReadBlocks (
+ 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
+ );
+
+/**
+ 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. 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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, 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
+NvmeBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiExtra.uni
new file mode 100644
index 000000000..e486fef8b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// NvmExpressPei Localized Strings and Content
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"NVM Express Peim"
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
new file mode 100644
index 000000000..1d7e3d26e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
@@ -0,0 +1,717 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Transfer MMIO Data to memory.
+
+ @param[in,out] MemBuffer Destination: Memory address.
+ @param[in] MmioAddr Source: MMIO address.
+ @param[in] Size Size for read.
+
+ @retval EFI_SUCCESS MMIO read sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);
+ break;
+
+ case 8:
+ *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);
+ break;
+
+ case 2:
+ *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);
+ break;
+
+ case 1:
+ *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = MmioRead8 (MmioAddr + Offset);
+ Ptr[Offset] = Data;
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr Destination: MMIO address.
+ @param[in] MemBuffer Source: Memory address.
+ @param[in] Size Size for write.
+
+ @retval EFI_SUCCESS MMIO write sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
+ break;
+
+ case 8:
+ MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));
+ break;
+
+ case 2:
+ MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
+ break;
+
+ case 1:
+ MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = Ptr[Offset];
+ MmioWrite8 (MmioAddr + Offset, Data);
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the page offset for specific NVME based memory.
+
+ @param[in] BaseMemIndex The Index of BaseMem (0-based).
+
+ @retval - The page count for specific BaseMem Index
+
+**/
+UINT32
+NvmeBaseMemPageOffset (
+ IN UINTN BaseMemIndex
+ )
+{
+ UINT32 Pages;
+ UINTN Index;
+ UINT32 PageSizeList[5];
+
+ PageSizeList[0] = 1; /* ASQ */
+ PageSizeList[1] = 1; /* ACQ */
+ PageSizeList[2] = 1; /* SQs */
+ PageSizeList[3] = 1; /* CQs */
+ PageSizeList[4] = NVME_PRP_SIZE; /* PRPs */
+
+ if (BaseMemIndex > MAX_BASEMEM_COUNT) {
+ DEBUG ((DEBUG_ERROR, "%a: The input BaseMem index is invalid.\n", __FUNCTION__));
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ Pages = 0;
+ for (Index = 0; Index < BaseMemIndex; Index++) {
+ Pages += PageSizeList[Index];
+ }
+
+ return Pages;
+}
+
+/**
+ Wait for NVME controller status to be ready or not.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] WaitReady Flag for waitting status ready or not.
+
+ @return EFI_SUCCESS Successfully to wait specific status.
+ @return others Fail to wait for specific controller status.
+
+**/
+EFI_STATUS
+NvmeWaitController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN BOOLEAN WaitReady
+ )
+{
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 Timeout;
+
+ //
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
+ //
+ if (Private->Cap.To == 0) {
+ Timeout = 1;
+ } else {
+ Timeout = Private->Cap.To;
+ }
+
+ Status = EFI_SUCCESS;
+ for(Index = (Timeout * 500); Index != 0; --Index) {
+ MicroSecondDelay (1000);
+
+ //
+ // Check if the controller is initialized
+ //
+ Status = NVME_GET_CSTS (Private, &Csts);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CSTS fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ if ((BOOLEAN) Csts.Rdy == WaitReady) {
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
+/**
+ Disable the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully disable the controller.
+ @return others Fail to disable the controller.
+
+**/
+EFI_STATUS
+NvmeDisableController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+
+ Status = NVME_GET_CSTS (Private, &Csts);
+
+ //
+ // Read Controller Configuration Register.
+ //
+ Status = NVME_GET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ if (Cc.En == 1) {
+ Cc.En = 0;
+ //
+ // Disable the controller.
+ //
+ Status = NVME_SET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+ }
+
+ Status = NvmeWaitController (Private, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ DEBUG ((DEBUG_ERROR, "%a fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+}
+
+/**
+ Enable the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully enable the controller.
+ @return EFI_DEVICE_ERROR Fail to enable the controller.
+ @return EFI_TIMEOUT Fail to enable the controller in given time slot.
+
+**/
+EFI_STATUS
+NvmeEnableController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ EFI_STATUS Status;
+
+ //
+ // Enable the controller
+ // CC.AMS, CC.MPS and CC.CSS are all set to 0
+ //
+ ZeroMem (&Cc, sizeof (NVME_CC));
+ Cc.En = 1;
+ Cc.Iosqes = 6;
+ Cc.Iocqes = 4;
+ Status = NVME_SET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ Status = NvmeWaitController (Private, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ DEBUG ((DEBUG_ERROR, "%a fail, Status: %r\n", __FUNCTION__, Status));
+ return Status;
+}
+
+/**
+ Get the Identify Controller data.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] Buffer The Buffer used to store the Identify Controller data.
+
+ @return EFI_SUCCESS Successfully get the Identify Controller data.
+ @return others Fail to get the Identify Controller data.
+
+**/
+EFI_STATUS
+NvmeIdentifyController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
+ //
+ Command.Nsid = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify the controller
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 1;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Get specified identify namespace data.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] NamespaceId The specified namespace identifier.
+ @param[in] Buffer The buffer used to store the identify namespace data.
+
+ @return EFI_SUCCESS Successfully get the identify namespace data.
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
+
+**/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ Command.Nsid = NamespaceId;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a namespace
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 0;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NamespaceId,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Dump the Identify Controller data.
+
+ @param[in] ControllerData The pointer to the NVME_ADMIN_CONTROLLER_DATA data structure.
+
+**/
+VOID
+NvmeDumpControllerData (
+ IN NVME_ADMIN_CONTROLLER_DATA *ControllerData
+ )
+{
+ UINT8 Sn[21];
+ UINT8 Mn[41];
+
+ CopyMem (Sn, ControllerData->Sn, sizeof (ControllerData->Sn));
+ Sn[20] = 0;
+ CopyMem (Mn, ControllerData->Mn, sizeof (ControllerData->Mn));
+ Mn[40] = 0;
+
+ DEBUG ((DEBUG_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));
+ DEBUG ((DEBUG_INFO, " PCI VID : 0x%x\n", ControllerData->Vid));
+ DEBUG ((DEBUG_INFO, " PCI SSVID : 0x%x\n", ControllerData->Ssvid));
+ DEBUG ((DEBUG_INFO, " SN : %a\n", Sn));
+ DEBUG ((DEBUG_INFO, " MN : %a\n", Mn));
+ DEBUG ((DEBUG_INFO, " FR : 0x%lx\n", *((UINT64*)ControllerData->Fr)));
+ DEBUG ((DEBUG_INFO, " RAB : 0x%x\n", ControllerData->Rab));
+ DEBUG ((DEBUG_INFO, " IEEE : 0x%x\n", *(UINT32*)ControllerData->Ieee_oui));
+ DEBUG ((DEBUG_INFO, " AERL : 0x%x\n", ControllerData->Aerl));
+ DEBUG ((DEBUG_INFO, " SQES : 0x%x\n", ControllerData->Sqes));
+ DEBUG ((DEBUG_INFO, " CQES : 0x%x\n", ControllerData->Cqes));
+ DEBUG ((DEBUG_INFO, " NN : 0x%x\n", ControllerData->Nn));
+ return;
+}
+
+/**
+ Create IO completion queue.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io completion queue.
+ @return others Fail to create io completion queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoCompletionQueue (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOCQ CrIoCq;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
+ CommandPacket.TransferBuffer = Private->CqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ CrIoCq.Qid = NVME_IO_QUEUE;
+ CrIoCq.Qsize = NVME_CCQ_SIZE;
+ CrIoCq.Pc = 1;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Create IO submission queue.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io submission queue.
+ @return others Fail to create io submission queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoSubmissionQueue (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOSQ CrIoSq;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
+ CommandPacket.TransferBuffer = Private->SqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ CrIoSq.Qid = NVME_IO_QUEUE;
+ CrIoSq.Qsize = NVME_CSQ_SIZE;
+ CrIoSq.Pc = 1;
+ CrIoSq.Cqid = NVME_IO_QUEUE;
+ CrIoSq.Qprio = 0;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ NVME_AQA Aqa;
+ NVME_ASQ Asq;
+ NVME_ACQ Acq;
+ NVME_VER Ver;
+
+ //
+ // Dump the NVME controller implementation version
+ //
+ NVME_GET_VER (Private, &Ver);
+ DEBUG ((DEBUG_INFO, "NVME controller implementation version: %d.%d\n", Ver.Mjr, Ver.Mnr));
+
+ //
+ // Read the controller Capabilities register and verify that the NVM command set is supported
+ //
+ NVME_GET_CAP (Private, &Private->Cap);
+ if (Private->Cap.Css != 0x01) {
+ DEBUG ((DEBUG_ERROR, "%a: The NVME controller doesn't support NVMe command set.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Currently, the driver only supports 4k page size
+ //
+ if ((Private->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
+ DEBUG ((DEBUG_ERROR, "%a: The driver doesn't support page size other than 4K.\n", __FUNCTION__));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ for (Index = 0; Index < NVME_MAX_QUEUES; Index++) {
+ Private->Pt[Index] = 0;
+ Private->Cid[Index] = 0;
+ ZeroMem ((VOID *)(UINTN)(&Private->SqTdbl[Index]), sizeof (NVME_SQTDBL));
+ ZeroMem ((VOID *)(UINTN)(&Private->CqHdbl[Index]), sizeof (NVME_CQHDBL));
+ }
+ ZeroMem (Private->Buffer, EFI_PAGE_SIZE * NVME_MEM_MAX_PAGES);
+
+ //
+ // Disable the NVME controller first
+ //
+ Status = NvmeDisableController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeDisableController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Set the number of entries in admin submission & completion queues
+ //
+ Aqa.Asqs = NVME_ASQ_SIZE;
+ Aqa.Rsvd1 = 0;
+ Aqa.Acqs = NVME_ACQ_SIZE;
+ Aqa.Rsvd2 = 0;
+
+ //
+ // Address of admin submission & completion queues
+ //
+ Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Private) & ~0xFFF);
+ Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Private) & ~0xFFF);
+
+ //
+ // Address of I/O submission & completion queues
+ //
+ Private->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Private); // NVME_ADMIN_QUEUE
+ Private->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Private); // NVME_ADMIN_QUEUE
+ Private->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Private, 0); // NVME_IO_QUEUE
+ Private->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Private, 0); // NVME_IO_QUEUE
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Private->SqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Private->CqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Private->SqBuffer[1]));
+ DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Private->CqBuffer[1]));
+
+ //
+ // Program admin queue attributes
+ //
+ NVME_SET_AQA (Private, &Aqa);
+
+ //
+ // Program admin submission & completion queues address
+ //
+ NVME_SET_ASQ (Private, &Asq);
+ NVME_SET_ACQ (Private, &Acq);
+
+ //
+ // Enable the NVME controller
+ //
+ Status = NvmeEnableController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeEnableController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Get the Identify Controller data
+ //
+ if (Private->ControllerData == NULL) {
+ Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA));
+ if (Private->ControllerData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ Status = NvmeIdentifyController (Private, Private->ControllerData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ NvmeDumpControllerData (Private->ControllerData);
+
+ //
+ // Check the namespace number for storing the namespaces information
+ //
+ if (Private->ControllerData->Nn > MAX_UINT32 / sizeof (PEI_NVME_NAMESPACE_INFO)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Number of Namespaces field in Identify Controller data not supported by the driver.\n",
+ __FUNCTION__
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Create one I/O completion queue and one I/O submission queue
+ //
+ Status = NvmeCreateIoCompletionQueue (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Create IO completion queue fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ Status = NvmeCreateIoSubmissionQueue (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Create IO submission queue fail, Status - %r\n", __FUNCTION__, Status));
+ }
+
+ return Status;
+}
+
+/**
+ Free the DMA resources allocated by an NVME controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+**/
+VOID
+NvmeFreeDmaResource (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ ASSERT (Private != NULL);
+
+ if (Private->BufferMapping != NULL) {
+ IoMmuFreeBuffer (
+ NVME_MEM_MAX_PAGES,
+ Private->Buffer,
+ Private->BufferMapping
+ );
+ }
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h
new file mode 100644
index 000000000..89fee735f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h
@@ -0,0 +1,145 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_HCI_H_
+#define _NVM_EXPRESS_PEI_HCI_H_
+
+//
+// NVME host controller registers operation definitions
+//
+#define NVME_GET_CAP(Private, Cap) NvmeMmioRead (Cap, Private->MmioBase + NVME_CAP_OFFSET, sizeof (NVME_CAP))
+#define NVME_GET_CC(Private, Cc) NvmeMmioRead (Cc, Private->MmioBase + NVME_CC_OFFSET, sizeof (NVME_CC))
+#define NVME_SET_CC(Private, Cc) NvmeMmioWrite (Private->MmioBase + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))
+#define NVME_GET_CSTS(Private, Csts) NvmeMmioRead (Csts, Private->MmioBase + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))
+#define NVME_GET_AQA(Private, Aqa) NvmeMmioRead (Aqa, Private->MmioBase + NVME_AQA_OFFSET, sizeof (NVME_AQA))
+#define NVME_SET_AQA(Private, Aqa) NvmeMmioWrite (Private->MmioBase + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))
+#define NVME_GET_ASQ(Private, Asq) NvmeMmioRead (Asq, Private->MmioBase + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))
+#define NVME_SET_ASQ(Private, Asq) NvmeMmioWrite (Private->MmioBase + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))
+#define NVME_GET_ACQ(Private, Acq) NvmeMmioRead (Acq, Private->MmioBase + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))
+#define NVME_SET_ACQ(Private, Acq) NvmeMmioWrite (Private->MmioBase + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))
+#define NVME_GET_VER(Private, Ver) NvmeMmioRead (Ver, Private->MmioBase + NVME_VER_OFFSET, sizeof (NVME_VER))
+#define NVME_SET_SQTDBL(Private, Qid, Sqtdbl) NvmeMmioWrite (Private->MmioBase + NVME_SQTDBL_OFFSET(Qid, Private->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL))
+#define NVME_SET_CQHDBL(Private, Qid, Cqhdbl) NvmeMmioWrite (Private->MmioBase + NVME_CQHDBL_OFFSET(Qid, Private->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL))
+
+//
+// Base memory address enum types
+//
+enum {
+ BASEMEM_ASQ,
+ BASEMEM_ACQ,
+ BASEMEM_SQ,
+ BASEMEM_CQ,
+ BASEMEM_PRP,
+ MAX_BASEMEM_COUNT
+};
+
+//
+// All of base memories are 4K(0x1000) alignment
+//
+#define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) + 1)
+#define NVME_MEM_BASE(Private) ((UINTN)(Private->Buffer))
+#define NVME_ASQ_BASE(Private) (ALIGN (NVME_MEM_BASE(Private) + ((NvmeBaseMemPageOffset (BASEMEM_ASQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_ACQ_BASE(Private) (ALIGN (NVME_MEM_BASE(Private) + ((NvmeBaseMemPageOffset (BASEMEM_ACQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_SQ_BASE(Private, Index) (ALIGN (NVME_MEM_BASE(Private) + ((NvmeBaseMemPageOffset (BASEMEM_SQ) + ((Index)*(NVME_MAX_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_CQ_BASE(Private, Index) (ALIGN (NVME_MEM_BASE(Private) + ((NvmeBaseMemPageOffset (BASEMEM_CQ) + ((Index)*(NVME_MAX_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_PRP_BASE(Private) (ALIGN (NVME_MEM_BASE(Private) + ((NvmeBaseMemPageOffset (BASEMEM_PRP)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+
+
+/**
+ Transfer MMIO Data to memory.
+
+ @param[in,out] MemBuffer Destination: Memory address.
+ @param[in] MmioAddr Source: MMIO address.
+ @param[in] Size Size for read.
+
+ @retval EFI_SUCCESS MMIO read sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ );
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr Destination: MMIO address.
+ @param[in] MemBuffer Source: Memory address.
+ @param[in] Size Size for write.
+
+ @retval EFI_SUCCESS MMIO write sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ );
+
+/**
+ Get the page offset for specific NVME based memory.
+
+ @param[in] BaseMemIndex The Index of BaseMem (0-based).
+
+ @retval - The page count for specific BaseMem Index
+
+**/
+UINT32
+NvmeBaseMemPageOffset (
+ IN UINTN BaseMemIndex
+ );
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ );
+
+/**
+ Get specified identify namespace data.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] NamespaceId The specified namespace identifier.
+ @param[in] Buffer The buffer used to store the identify namespace data.
+
+ @return EFI_SUCCESS Successfully get the identify namespace data.
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
+
+**/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ );
+
+/**
+ Free the DMA resources allocated by an NVME controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+**/
+VOID
+NvmeFreeDmaResource (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.c
new file mode 100644
index 000000000..370a54e5a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.c
@@ -0,0 +1,828 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Create PRP lists for Data transfer which is larger than 2 memory pages.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] PhysicalAddr The physical base address of Data Buffer.
+ @param[in] Pages The number of pages to be transfered.
+
+ @retval The pointer Value to the first PRP List of the PRP lists.
+
+**/
+UINT64
+NvmeCreatePrpList (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,
+ IN UINTN Pages
+ )
+{
+ UINTN PrpEntryNo;
+ UINTN PrpListNo;
+ UINT64 PrpListBase;
+ VOID *PrpListHost;
+ UINTN PrpListIndex;
+ UINTN PrpEntryIndex;
+ UINT64 Remainder;
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;
+ UINTN Bytes;
+ UINT8 *PrpEntry;
+ EFI_PHYSICAL_ADDRESS NewPhyAddr;
+
+ //
+ // The number of Prp Entry in a memory page.
+ //
+ PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
+
+ //
+ // Calculate total PrpList number.
+ //
+ PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder);
+ if (Remainder != 0) {
+ PrpListNo += 1;
+ }
+
+ if (PrpListNo > NVME_PRP_SIZE) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: The implementation only supports PrpList number up to 4."
+ " But %d are needed here.\n",
+ __FUNCTION__,
+ PrpListNo
+ ));
+ return 0;
+ }
+ PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Private);
+
+ Bytes = EFI_PAGES_TO_SIZE (PrpListNo);
+ PrpListPhyAddr = (UINT64)(UINTN)(PrpListHost);
+
+ //
+ // Fill all PRP lists except of last one.
+ //
+ ZeroMem (PrpListHost, Bytes);
+ for (PrpListIndex = 0; PrpListIndex < PrpListNo - 1; ++PrpListIndex) {
+ PrpListBase = (UINTN)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+
+ for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
+ if (PrpEntryIndex != PrpEntryNo - 1) {
+ //
+ // Fill all PRP entries except of last one.
+ //
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
+ PhysicalAddr += EFI_PAGE_SIZE;
+ } else {
+ //
+ // Fill last PRP entries with next PRP List pointer.
+ //
+ NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE);
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof (UINT64));
+ }
+ }
+ }
+
+ //
+ // Fill last PRP list.
+ //
+ PrpListBase = (UINTN)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+ for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) {
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
+
+ PhysicalAddr += EFI_PAGE_SIZE;
+ }
+
+ return PrpListPhyAddr;
+}
+
+/**
+ Check the execution status from a given completion queue entry.
+
+ @param[in] Cq A pointer to the NVME_CQ item.
+
+**/
+EFI_STATUS
+NvmeCheckCqStatus (
+ IN NVME_CQ *Cq
+ )
+{
+ if (Cq->Sct == 0x0 && Cq->Sc == 0x0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN)Cq));
+ DEBUG ((
+ DEBUG_INFO,
+ " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n",
+ Cq->Sqid,
+ Cq->Pt,
+ Cq->Cid
+ ));
+ DEBUG ((DEBUG_INFO, " Status Code Type : [0x%x], Status Code : [0x%x]\n", Cq->Sct, Cq->Sc));
+ DEBUG ((DEBUG_INFO, " NVMe Cmd Execution Result - "));
+
+ switch (Cq->Sct) {
+ case 0x0:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((DEBUG_INFO, "Successful Completion\n"));
+ return EFI_SUCCESS;
+ case 0x1:
+ DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n"));
+ break;
+ case 0x2:
+ DEBUG ((DEBUG_INFO, "Invalid Field in Command\n"));
+ break;
+ case 0x3:
+ DEBUG ((DEBUG_INFO, "Command ID Conflict\n"));
+ break;
+ case 0x4:
+ DEBUG ((DEBUG_INFO, "Data Transfer Error\n"));
+ break;
+ case 0x5:
+ DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss Notification\n"));
+ break;
+ case 0x6:
+ DEBUG ((DEBUG_INFO, "Internal Device Error\n"));
+ break;
+ case 0x7:
+ DEBUG ((DEBUG_INFO, "Command Abort Requested\n"));
+ break;
+ case 0x8:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to SQ Deletion\n"));
+ break;
+ case 0x9:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused Command\n"));
+ break;
+ case 0xA:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused Command\n"));
+ break;
+ case 0xB:
+ DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n"));
+ break;
+ case 0xC:
+ DEBUG ((DEBUG_INFO, "Command Sequence Error\n"));
+ break;
+ case 0xD:
+ DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n"));
+ break;
+ case 0xE:
+ DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n"));
+ break;
+ case 0xF:
+ DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n"));
+ break;
+ case 0x10:
+ DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n"));
+ break;
+ case 0x11:
+ DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n"));
+ break;
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "LBA Out of Range\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Capacity Exceeded\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "Namespace Not Ready\n"));
+ break;
+ case 0x83:
+ DEBUG ((DEBUG_INFO, "Reservation Conflict\n"));
+ break;
+ }
+ break;
+
+ case 0x1:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n"));
+ break;
+ case 0x1:
+ DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n"));
+ break;
+ case 0x2:
+ DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n"));
+ break;
+ case 0x3:
+ DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n"));
+ break;
+ case 0x5:
+ DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit Exceeded\n"));
+ break;
+ case 0x6:
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n"));
+ break;
+ case 0x7:
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n"));
+ break;
+ case 0x8:
+ DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n"));
+ break;
+ case 0x9:
+ DEBUG ((DEBUG_INFO, "Invalid Log Page\n"));
+ break;
+ case 0xA:
+ DEBUG ((DEBUG_INFO, "Invalid Format\n"));
+ break;
+ case 0xB:
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires Conventional Reset\n"));
+ break;
+ case 0xC:
+ DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n"));
+ break;
+ case 0xD:
+ DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n"));
+ break;
+ case 0xE:
+ DEBUG ((DEBUG_INFO, "Feature Not Changeable\n"));
+ break;
+ case 0xF:
+ DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n"));
+ break;
+ case 0x10:
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM Subsystem Reset\n"));
+ break;
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "Conflicting Attributes\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Invalid Protection Information\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n"));
+ break;
+ }
+ break;
+
+ case 0x2:
+ switch (Cq->Sc) {
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "Write Fault\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n"));
+ break;
+ case 0x83:
+ DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check Error\n"));
+ break;
+ case 0x84:
+ DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check Error\n"));
+ break;
+ case 0x85:
+ DEBUG ((DEBUG_INFO, "Compare Failure\n"));
+ break;
+ case 0x86:
+ DEBUG ((DEBUG_INFO, "Access Denied\n"));
+ break;
+ }
+ break;
+
+ default:
+ DEBUG ((DEBUG_INFO, "Unknown error\n"));
+ break;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
+ supports blocking execution of the command.
+
+ @param[in] Private The pointer to the NVME_CONTEXT Data structure.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will
+ be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
+ the namespace ID specifies that the command packet should be sent to all
+ valid namespaces.
+ @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
+ to the NVMe namespace specified by NamespaceId.
+
+ @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
+ TransferLength bytes were transferred to, or from DataBuffer.
+ @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
+ the controller is not ready. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
+ Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
+ are invalid.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
+ is not supported by the host adapter.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
+ Packet to execute.
+
+**/
+EFI_STATUS
+NvmePassThruExecute (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ NVME_SQ *Sq;
+ NVME_CQ *Cq;
+ UINT8 QueueId;
+ UINTN SqSize;
+ UINTN CqSize;
+ EDKII_IOMMU_OPERATION MapOp;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *MapData;
+ VOID *MapMeta;
+ UINT32 Bytes;
+ UINT32 Offset;
+ UINT32 Data32;
+ UINT64 Timer;
+
+ //
+ // Check the data fields in Packet parameter
+ //
+ if (Packet == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a, Invalid parameter: Packet(%lx)\n",
+ __FUNCTION__,
+ (UINTN)Packet
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->NvmeCmd == NULL) || (Packet->NvmeCompletion == NULL)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a, Invalid parameter: NvmeCmd (%lx)/NvmeCompletion(%lx)\n",
+ __FUNCTION__,
+ (UINTN)Packet->NvmeCmd,
+ (UINTN)Packet->NvmeCompletion
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet->QueueType != NVME_ADMIN_QUEUE && Packet->QueueType != NVME_IO_QUEUE) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a, Invalid parameter: QueueId(%lx)\n",
+ __FUNCTION__,
+ (UINTN)Packet->QueueType
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ QueueId = Packet->QueueType;
+ Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;
+ Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
+ if (QueueId == NVME_ADMIN_QUEUE) {
+ SqSize = NVME_ASQ_SIZE + 1;
+ CqSize = NVME_ACQ_SIZE + 1;
+ } else {
+ SqSize = NVME_CSQ_SIZE + 1;
+ CqSize = NVME_CCQ_SIZE + 1;
+ }
+
+ if (Packet->NvmeCmd->Nsid != NamespaceId) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Nsid mismatch (%x, %x)\n",
+ __FUNCTION__,
+ Packet->NvmeCmd->Nsid,
+ NamespaceId
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Sq, sizeof (NVME_SQ));
+ Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
+ Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
+ Sq->Cid = Private->Cid[QueueId]++;;
+ Sq->Nsid = Packet->NvmeCmd->Nsid;
+
+ //
+ // Currently we only support PRP for data transfer, SGL is NOT supported
+ //
+ ASSERT (Sq->Psdt == 0);
+ if (Sq->Psdt != 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Does not support SGL mechanism.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+
+ Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;
+ Sq->Prp[1] = 0;
+ MapData = NULL;
+ MapMeta = NULL;
+ Status = EFI_SUCCESS;
+ //
+ // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller
+ // specific addresses.
+ //
+ if ((Sq->Opc & (BIT0 | BIT1)) != 0) {
+ if (((Packet->TransferLength != 0) && (Packet->TransferBuffer == NULL)) ||
+ ((Packet->TransferLength == 0) && (Packet->TransferBuffer != NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Currently, we only support creating IO submission/completion queues that are
+ // allocated internally by the driver.
+ //
+ if ((Packet->QueueType == NVME_ADMIN_QUEUE) &&
+ ((Sq->Opc == NVME_ADMIN_CRIOCQ_CMD) || (Sq->Opc == NVME_ADMIN_CRIOSQ_CMD))) {
+ if ((Packet->TransferBuffer != Private->SqBuffer[NVME_IO_QUEUE]) &&
+ (Packet->TransferBuffer != Private->CqBuffer[NVME_IO_QUEUE])) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Does not support external IO queues creation request.\n",
+ __FUNCTION__
+ ));
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if ((Sq->Opc & BIT0) != 0) {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ }
+
+ if ((Packet->TransferLength != 0) && (Packet->TransferBuffer != NULL)) {
+ MapLength = Packet->TransferLength;
+ Status = IoMmuMap (
+ MapOp,
+ Packet->TransferBuffer,
+ &MapLength,
+ &PhyAddr,
+ &MapData
+ );
+ if (EFI_ERROR (Status) || (MapLength != Packet->TransferLength)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map data buffer.\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ Sq->Prp[0] = PhyAddr;
+ }
+
+ if((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {
+ MapLength = Packet->MetadataLength;
+ Status = IoMmuMap (
+ MapOp,
+ Packet->MetadataBuffer,
+ &MapLength,
+ &PhyAddr,
+ &MapMeta
+ );
+ if (EFI_ERROR (Status) || (MapLength != Packet->MetadataLength)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map meta data buffer.\n", __FUNCTION__));
+ goto Exit;
+ }
+ Sq->Mptr = PhyAddr;
+ }
+ }
+ }
+
+ //
+ // If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
+ // then build a PRP list in the second PRP submission queue entry.
+ //
+ Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
+ Bytes = Packet->TransferLength;
+
+ if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
+ //
+ // Create PrpList for remaining Data Buffer.
+ //
+ PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ Sq->Prp[1] = NvmeCreatePrpList (
+ Private,
+ PhyAddr,
+ EFI_SIZE_TO_PAGES(Offset + Bytes) - 1
+ );
+ if (Sq->Prp[1] == 0) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "%a: Create PRP list fail, Status - %r\n", __FUNCTION__, Status));
+ goto Exit;
+ }
+
+ } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
+ Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ }
+
+ if (Packet->NvmeCmd->Flags & CDW10_VALID) {
+ Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
+ }
+ if (Packet->NvmeCmd->Flags & CDW11_VALID) {
+ Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
+ }
+ if (Packet->NvmeCmd->Flags & CDW12_VALID) {
+ Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
+ }
+ if (Packet->NvmeCmd->Flags & CDW13_VALID) {
+ Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
+ }
+ if (Packet->NvmeCmd->Flags & CDW14_VALID) {
+ Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
+ }
+ if (Packet->NvmeCmd->Flags & CDW15_VALID) {
+ Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
+ }
+
+ //
+ // Ring the submission queue doorbell.
+ //
+ Private->SqTdbl[QueueId].Sqt++;
+ if (Private->SqTdbl[QueueId].Sqt == SqSize) {
+ Private->SqTdbl[QueueId].Sqt = 0;
+ }
+ Data32 = ReadUnaligned32 ((UINT32 *)&Private->SqTdbl[QueueId]);
+ Status = NVME_SET_SQTDBL (Private, QueueId, &Data32);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_SET_SQTDBL fail, Status - %r\n", __FUNCTION__, Status));
+ goto Exit;
+ }
+
+ //
+ // Wait for completion queue to get filled in.
+ //
+ Status = EFI_TIMEOUT;
+ Timer = 0;
+ while (Timer < Packet->CommandTimeout) {
+ if (Cq->Pt != Private->Pt[QueueId]) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ MicroSecondDelay (NVME_POLL_INTERVAL);
+ Timer += NVME_POLL_INTERVAL;
+ }
+
+ if (Status == EFI_TIMEOUT) {
+ //
+ // Timeout occurs for an NVMe command, reset the controller to abort the outstanding command
+ //
+ DEBUG ((DEBUG_ERROR, "%a: Timeout occurs for the PassThru command.\n", __FUNCTION__));
+ Status = NvmeControllerInit (Private);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ //
+ // Return EFI_TIMEOUT to indicate a timeout occurs for PassThru command
+ //
+ Status = EFI_TIMEOUT;
+ }
+ goto Exit;
+ }
+
+ //
+ // Move forward the Completion Queue head
+ //
+ Private->CqHdbl[QueueId].Cqh++;
+ if (Private->CqHdbl[QueueId].Cqh == CqSize) {
+ Private->CqHdbl[QueueId].Cqh = 0;
+ Private->Pt[QueueId] ^= 1;
+ }
+
+ //
+ // Copy the Respose Queue entry for this command to the callers response buffer
+ //
+ CopyMem (Packet->NvmeCompletion, Cq, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+
+ //
+ // Check the NVMe cmd execution result
+ //
+ Status = NvmeCheckCqStatus (Cq);
+ NVME_SET_CQHDBL (Private, QueueId, &Private->CqHdbl[QueueId]);
+
+Exit:
+ if (MapMeta != NULL) {
+ IoMmuUnmap (MapMeta);
+ }
+
+ if (MapData != NULL) {
+ IoMmuUnmap (MapData);
+ }
+
+ return Status;
+}
+
+/**
+ Gets the device path information of the underlying NVM Express host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying NVM Express
+ host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThruGetDevicePath (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This);
+
+ *DevicePathLength = Private->DevicePathLength;
+ *DevicePath = AllocateCopyPool (Private->DevicePathLength, Private->DevicePath);
+ if (*DevicePath == NULL) {
+ *DevicePathLength = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to retrieve the next namespace ID for this NVM Express controller.
+
+ If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first
+ valid namespace ID defined on the NVM Express controller is returned in the
+ location pointed to by NamespaceId and a status of EFI_SUCCESS is returned.
+
+ If on input the value pointed to by NamespaceId is an invalid namespace ID
+ other than 0xFFFFFFFF, then EFI_INVALID_PARAMETER is returned.
+
+ If on input the value pointed to by NamespaceId is a valid namespace ID, then
+ the next valid namespace ID on the NVM Express controller is returned in the
+ location pointed to by NamespaceId, and EFI_SUCCESS is returned.
+
+ If the value pointed to by NamespaceId is the namespace ID of the last
+ namespace on the NVM Express controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId
+ for an NVM Express namespace present on the
+ NVM Express controller. On output, a pointer
+ to the next NamespaceId of an NVM Express
+ namespace on an NVM Express controller. An
+ input value of 0xFFFFFFFF retrieves the
+ first NamespaceId for an NVM Express
+ namespace present on an NVM Express
+ controller.
+
+ @retval EFI_SUCCESS The Namespace ID of the next Namespace was
+ returned.
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this
+ controller.
+ @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than
+ 0xFFFFFFFF.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThruGetNextNameSpace (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN OUT UINT32 *NamespaceId
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 DeviceIndex;
+ EFI_STATUS Status;
+
+ if (This == NULL || NamespaceId == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This);
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // If active namespace number is 0, then valid namespace ID is unavailable
+ //
+ if (Private->ActiveNamespaceNum == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID
+ //
+ if (*NamespaceId == 0xFFFFFFFF) {
+ //
+ // Start with the first namespace ID
+ //
+ *NamespaceId = Private->NamespaceInfo[0].NamespaceId;
+ Status = EFI_SUCCESS;
+ } else {
+ if (*NamespaceId > Private->ControllerData->Nn) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*NamespaceId + 1) > Private->ControllerData->Nn) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (DeviceIndex = 0; DeviceIndex < Private->ActiveNamespaceNum; DeviceIndex++) {
+ if (*NamespaceId == Private->NamespaceInfo[DeviceIndex].NamespaceId) {
+ if ((DeviceIndex + 1) < Private->ActiveNamespaceNum) {
+ *NamespaceId = Private->NamespaceInfo[DeviceIndex + 1].NamespaceId;
+ Status = EFI_SUCCESS;
+ }
+ break;
+ }
+ }
+ }
+
+ return Status;
+
+}
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
+ supports blocking execution of the command.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Nvm Express command packet will
+ be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
+ the namespace ID specifies that the command packet should be sent to all
+ valid namespaces.
+ @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
+ to the NVMe namespace specified by NamespaceId.
+
+ @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
+ TransferLength bytes were transferred to, or from DataBuffer.
+ @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
+ the controller is not ready. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
+ Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
+ are invalid.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
+ is not supported by the host adapter.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
+ Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThru (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ if (This == NULL || Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This);
+ //
+ // Check NamespaceId is valid or not.
+ //
+ if ((NamespaceId > Private->ControllerData->Nn) &&
+ (NamespaceId != (UINT32) -1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = NvmePassThruExecute (
+ Private,
+ NamespaceId,
+ Packet
+ );
+
+ return Status;
+
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.h
new file mode 100644
index 000000000..00e8f0abd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiPassThru.h
@@ -0,0 +1,161 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_PASSTHRU_H_
+#define _NVM_EXPRESS_PEI_PASSTHRU_H_
+
+
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
+ supports blocking execution of the command.
+
+ @param[in] Private The pointer to the NVME_CONTEXT Data structure.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will
+ be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
+ the namespace ID specifies that the command packet should be sent to all
+ valid namespaces.
+ @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
+ to the NVMe namespace specified by NamespaceId.
+
+ @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
+ TransferLength bytes were transferred to, or from DataBuffer.
+ @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
+ the controller is not ready. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
+ Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
+ are invalid.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
+ is not supported by the host adapter.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
+ Packet to execute.
+
+**/
+EFI_STATUS
+NvmePassThruExecute (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+/**
+ Gets the device path information of the underlying NVM Express host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying NVM Express
+ host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThruGetDevicePath (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Used to retrieve the next namespace ID for this NVM Express controller.
+
+ If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first
+ valid namespace ID defined on the NVM Express controller is returned in the
+ location pointed to by NamespaceId and a status of EFI_SUCCESS is returned.
+
+ If on input the value pointed to by NamespaceId is an invalid namespace ID
+ other than 0xFFFFFFFF, then EFI_INVALID_PARAMETER is returned.
+
+ If on input the value pointed to by NamespaceId is a valid namespace ID, then
+ the next valid namespace ID on the NVM Express controller is returned in the
+ location pointed to by NamespaceId, and EFI_SUCCESS is returned.
+
+ If the value pointed to by NamespaceId is the namespace ID of the last
+ namespace on the NVM Express controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId
+ for an NVM Express namespace present on the
+ NVM Express controller. On output, a pointer
+ to the next NamespaceId of an NVM Express
+ namespace on an NVM Express controller. An
+ input value of 0xFFFFFFFF retrieves the
+ first NamespaceId for an NVM Express
+ namespace present on an NVM Express
+ controller.
+
+ @retval EFI_SUCCESS The Namespace ID of the next Namespace was
+ returned.
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this
+ controller.
+ @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than
+ 0xFFFFFFFF.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThruGetNextNameSpace (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN OUT UINT32 *NamespaceId
+ );
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
+ supports blocking execution of the command.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Nvm Express command packet will
+ be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
+ the namespace ID specifies that the command packet should be sent to all
+ valid namespaces.
+ @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
+ to the NVMe namespace specified by NamespaceId.
+
+ @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
+ TransferLength bytes were transferred to, or from DataBuffer.
+ @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
+ the controller is not ready. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
+ Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
+ are invalid.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
+ is not supported by the host adapter.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
+ Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmePassThru (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
new file mode 100644
index 000000000..f409285d5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
@@ -0,0 +1,107 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+#include <Guid/S3StorageDeviceInitList.h>
+
+#include <Library/LockBoxLib.h>
+
+/**
+ Determine if a specific NVM Express controller can be skipped for S3 phase.
+
+ @param[in] HcDevicePath Device path of the controller.
+ @param[in] HcDevicePathLength Length of the device path specified by
+ HcDevicePath.
+
+ @retval The number of ports that need to be enumerated.
+
+**/
+BOOLEAN
+NvmeS3SkipThisController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath,
+ IN UINTN HcDevicePathLength
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DummyData;
+ UINTN S3InitDevicesLength;
+ EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN DevicePathInstLength;
+ BOOLEAN EntireEnd;
+ BOOLEAN Skip;
+
+ //
+ // From the LockBox, get the list of device paths for devices need to be
+ // initialized in S3.
+ //
+ S3InitDevices = NULL;
+ S3InitDevicesLength = sizeof (DummyData);
+ EntireEnd = FALSE;
+ Skip = TRUE;
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Skip;
+ } else {
+ S3InitDevices = AllocatePool (S3InitDevicesLength);
+ if (S3InitDevices == NULL) {
+ return Skip;
+ }
+
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);
+ if (EFI_ERROR (Status)) {
+ return Skip;
+ }
+ }
+
+ if (S3InitDevices == NULL) {
+ return Skip;
+ }
+
+ //
+ // Only need to initialize the controllers that exist in the device list.
+ //
+ do {
+ //
+ // Fetch the size of current device path instance.
+ //
+ Status = GetDevicePathInstanceSize (
+ S3InitDevices,
+ &DevicePathInstLength,
+ &EntireEnd
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ DevicePathInst = S3InitDevices;
+ S3InitDevices = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);
+
+ if (HcDevicePathLength >= DevicePathInstLength) {
+ continue;
+ }
+
+ //
+ // Compare the device paths to determine if the device is managed by this
+ // controller.
+ //
+ if (CompareMem (
+ DevicePathInst,
+ HcDevicePath,
+ HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+ ) == 0) {
+ Skip = FALSE;
+ break;
+ }
+ } while (!EntireEnd);
+
+ return Skip;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c
new file mode 100644
index 000000000..094d61bb8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c
@@ -0,0 +1,418 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Trust transfer data from/to NVM Express device.
+
+ This function performs one NVMe transaction to do a trust transfer from/to NVM
+ Express device.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+ data structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter
+ of the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to
+ be sent.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsTrustSend Indicates whether it is a trust send operation
+ or not.
+ @param[in] Timeout The timeout, in 100ns units, to use for the
+ execution of the security protocol command.
+ A Timeout value of 0 means that this function
+ will wait indefinitely for the security protocol
+ command to execute. If Timeout is greater than
+ zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive
+ data command is greater than Timeout.
+ @param[out] TransferLengthOut A pointer to a buffer to store the size in bytes
+ of the data written to the buffer. Ignore it
+ when IsTrustSend is TRUE.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferNvmeDevice (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN OUT VOID *Buffer,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN TransferLength,
+ IN BOOLEAN IsTrustSend,
+ IN UINT64 Timeout,
+ OUT UINTN *TransferLengthOut
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ UINT16 SpecificData;
+ EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *NvmePassThru;
+
+ NvmePassThru = &Private->NvmePassThruPpi;
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ //
+ // Change Endianness of SecurityProtocolSpecificData
+ //
+ SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
+
+ if (IsTrustSend) {
+ Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_SEND_CMD;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = (UINT32)TransferLength;
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+ } else {
+ Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_RECEIVE_CMD;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = (UINT32)TransferLength;
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+ }
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+ CommandPacket.NvmeCmd->Nsid = NVME_CONTROLLER_NSID;
+ CommandPacket.CommandTimeout = Timeout;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ Status = NvmePassThru->PassThru (
+ NvmePassThru,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+
+ if (!IsTrustSend) {
+ if (EFI_ERROR (Status)) {
+ *TransferLengthOut = 0;
+ } else {
+ *TransferLengthOut = (UINTN) TransferLength;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Gets the count of storage security devices that one specific driver detects.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] NumberofDevices The number of storage security devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDeviceNo (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ OUT UINTN *NumberofDevices
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberofDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ *NumberofDevices = Private->ActiveNamespaceNum;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the device path of a specific storage security device.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which
+ the function wants to talk. Because the driver
+ that implements Storage Security Command PPIs
+ will manage multiple storage 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 NumberofDevices.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of storage security device.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_NOT_FOUND The specified storage security device not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDevicePath (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveNamespaceNum)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return NvmeBuildDevicePath (
+ Private,
+ Private->NamespaceInfo[DeviceIndex-1].NamespaceId,
+ Private->NamespaceInfo[DeviceIndex-1].NamespaceUuid,
+ DevicePathLength,
+ DevicePath
+ );
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given DeviceIndex.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which the
+ function wants to talk. Because the driver that
+ implements Storage Security Command PPIs will manage
+ multiple storage 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 NumberofDevices.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize
+ Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command. The caller is
+ responsible for having either implicit or explicit
+ ownership of the buffer.
+ @param[out] PayloadTransferSize
+ A pointer to a buffer to store the size in bytes
+ of the data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed
+ successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to
+ store the available data from the device.
+ The PayloadBuffer contains the truncated
+ data.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support
+ security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed
+ with an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize
+ is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the
+ security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+
+ Status = TrustTransferNvmeDevice (
+ Private,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ FALSE,
+ Timeout,
+ PayloadTransferSize
+ );
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is
+ sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is
+ sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command
+ is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error,
+ the functio shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex The ID of the device.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[in] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support security
+ protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with
+ an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize
+ is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+
+ Status = TrustTransferNvmeDevice (
+ Private,
+ PayloadBuffer,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ TRUE,
+ Timeout,
+ NULL
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h
new file mode 100644
index 000000000..18f3e1ce2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h
@@ -0,0 +1,240 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_STORAGE_SECURITY_H_
+#define _NVM_EXPRESS_PEI_STORAGE_SECURITY_H_
+
+/**
+ Gets the count of storage security devices that one specific driver detects.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] NumberofDevices The number of storage security devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDeviceNo (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ OUT UINTN *NumberofDevices
+ );
+
+/**
+ Gets the device path of a specific storage security device.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which
+ the function wants to talk. Because the driver
+ that implements Storage Security Command PPIs
+ will manage multiple storage 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 NumberofDevices.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of storage security device.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_NOT_FOUND The specified storage security device not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDevicePath (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given DeviceIndex.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which the
+ function wants to talk. Because the driver that
+ implements Storage Security Command PPIs will manage
+ multiple storage 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 NumberofDevices.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize
+ Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command. The caller is
+ responsible for having either implicit or explicit
+ ownership of the buffer.
+ @param[out] PayloadTransferSize
+ A pointer to a buffer to store the size in bytes
+ of the data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed
+ successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to
+ store the available data from the device.
+ The PayloadBuffer contains the truncated
+ data.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support
+ security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed
+ with an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize
+ is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the
+ security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is
+ sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is
+ sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command
+ is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error,
+ the functio shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex The ID of the device.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[in] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support security
+ protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with
+ an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize
+ is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c
new file mode 100644
index 000000000..ff2a2314f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.c
@@ -0,0 +1,170 @@
+/** @file
+ EFI Component Name functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName = {
+ PciBusComponentNameGetDriverName,
+ PciBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PciBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PciBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPciBusDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"PCI 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
+PciBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPciBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPciBusComponentName)
+ );
+}
+
+/**
+ 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
+PciBusComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h
new file mode 100644
index 000000000..b211391b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/ComponentName.h
@@ -0,0 +1,146 @@
+/** @file
+ EFI Component Name functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_PCI_BUS_COMPONENT_NAME_H_
+#define _EFI_PCI_BUS_COMPONENT_NAME_H_
+
+extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2;
+
+//
+// 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
+PciBusComponentNameGetDriverName (
+ 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
+PciBusComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
new file mode 100644
index 000000000..64284ac82
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c
@@ -0,0 +1,460 @@
+/** @file
+ Driver Binding functions for PCI Bus module.
+
+ Single PCI bus driver instance will manager all PCI Root Bridges in one EFI based firmware,
+ since all PCI Root Bridges' resources need to be managed together.
+ Supported() function will try to get PCI Root Bridge IO Protocol.
+ Start() function will get PCI Host Bridge Resource Allocation Protocol to manage all
+ PCI Root Bridges. So it means platform needs install PCI Root Bridge IO protocol for each
+ PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+//
+// PCI Bus Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding = {
+ PciBusDriverBindingSupported,
+ PciBusDriverBindingStart,
+ PciBusDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_HANDLE gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
+EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gIncompatiblePciDeviceSupport = NULL;
+UINTN gPciHostBridgeNumber = 0;
+BOOLEAN gFullEnumeration = TRUE;
+UINT64 gAllOne = 0xFFFFFFFFFFFFFFFFULL;
+UINT64 gAllZero = 0;
+
+EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol;
+EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol;
+EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
+EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL mPciHotPlugRequest = {
+ PciHotPlugRequestNotify
+};
+
+/**
+ The Entry Point for PCI Bus module. The user code starts with this function.
+
+ Installs driver module protocols and. Creates virtual device handles for ConIn,
+ ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
+ Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
+ Installs Graphics Output protocol and/or UGA Draw protocol if needed.
+
+ @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 occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PciBusEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Initializes PCI devices pool
+ //
+ InitializePciDevicePool ();
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPciBusDriverBinding,
+ ImageHandle,
+ &gPciBusComponentName,
+ &gPciBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is supported, install EFI PCI Hot Plug Request protocol.
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiPciHotPlugRequestProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPciHotPlugRequest
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller 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
+PciBusDriverBindingSupported (
+ 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_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_DEV_PATH_PTR Node;
+
+ //
+ // 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
+ //
+ Node.DevPath = RemainingDevicePath;
+ if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
+ Node.DevPath->SubType != HW_PCI_DP ||
+ DevicePathNodeLength(Node.DevPath) != sizeof(PCI_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Check if Pci Root Bridge IO protocol is installed by platform
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ 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,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ 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;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on ControllerHandle and enumerate Pci bus and start
+ all device under PCI bus.
+
+ @param This Protocol instance pointer.
+ @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 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
+PciBusDriverBindingStart (
+ 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_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ //
+ // Initialize PciRootBridgeIo to suppress incorrect compiler warning.
+ //
+ PciRootBridgeIo = NULL;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ gBS->LocateProtocol (
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ NULL,
+ (VOID **) &gIncompatiblePciDeviceSupport
+ );
+
+ //
+ // If PCI Platform protocol is available, get it now.
+ // If the platform implements this, it must be installed before BDS phase
+ //
+ gPciPlatformProtocol = NULL;
+ gBS->LocateProtocol (
+ &gEfiPciPlatformProtocolGuid,
+ NULL,
+ (VOID **) &gPciPlatformProtocol
+ );
+
+ //
+ // If PCI Platform protocol doesn't exist, try to Pci Override Protocol.
+ //
+ if (gPciPlatformProtocol == NULL) {
+ gPciOverrideProtocol = NULL;
+ gBS->LocateProtocol (
+ &gEfiPciOverrideProtocolGuid,
+ NULL,
+ (VOID **) &gPciOverrideProtocol
+ );
+ }
+
+ if (mIoMmuProtocol == NULL) {
+ gBS->LocateProtocol (
+ &gEdkiiIoMmuProtocolGuid,
+ NULL,
+ (VOID **) &mIoMmuProtocol
+ );
+ }
+
+ if (mDeviceSecurityProtocol == NULL) {
+ gBS->LocateProtocol (
+ &gEdkiiDeviceSecurityProtocolGuid,
+ NULL,
+ (VOID **) &mDeviceSecurityProtocol
+ );
+ }
+
+ if (PcdGetBool (PcdPciDisableBusEnumeration)) {
+ gFullEnumeration = FALSE;
+ } else {
+ gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ? FALSE : TRUE));
+ }
+
+ //
+ // Open Device Path Protocol for PCI root bridge
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Report Status Code to indicate PCI bus starts
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_PCI | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ Status = EFI_SUCCESS;
+ //
+ // Enumerate the entire host bridge
+ // After enumeration, a database that records all the device information will be created
+ //
+ //
+ if (gFullEnumeration) {
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = PciEnumerator (Controller, PciRootBridgeIo->ParentHandle);
+ }
+ } else {
+ //
+ // If PCI bus has already done the full enumeration, never do it again
+ //
+ Status = PciEnumeratorLight (Controller);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Start all the devices under the entire host bridge.
+ //
+ StartPciDevices (Controller);
+
+ if (gFullEnumeration) {
+ gFullEnumeration = FALSE;
+
+ Status = gBS->InstallProtocolInterface (
+ &PciRootBridgeIo->ParentHandle,
+ &gEfiPciEnumerationCompleteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller 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
+PciBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DestroyRootBridgeByHandle (
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stop all the children
+ //
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ //
+ // De register all the pci device
+ //
+ Status = DeRegisterPciDevice (Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
new file mode 100644
index 000000000..d4113993c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
@@ -0,0 +1,394 @@
+/** @file
+ Header files and data structures needed by PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_PCI_BUS_H_
+#define _EFI_PCI_BUS_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHotPlugRequest.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciPlatform.h>
+#include <Protocol/PciHotPlugInit.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/IncompatiblePciDeviceSupport.h>
+#include <Protocol/PciOverride.h>
+#include <Protocol/PciEnumerationComplete.h>
+#include <Protocol/IoMmu.h>
+#include <Protocol/DeviceSecurity.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/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/Acpi.h>
+
+typedef struct _PCI_IO_DEVICE PCI_IO_DEVICE;
+typedef struct _PCI_BAR PCI_BAR;
+
+#define EFI_PCI_RID(Bus, Device, Function) (((UINT32)Bus << 8) + ((UINT32)Device << 3) + (UINT32)Function)
+#define EFI_PCI_BUS_OF_RID(RID) ((UINT32)RID >> 8)
+
+#define EFI_PCI_IOV_POLICY_ARI 0x0001
+#define EFI_PCI_IOV_POLICY_SRIOV 0x0002
+#define EFI_PCI_IOV_POLICY_MRIOV 0x0004
+
+typedef enum {
+ PciBarTypeUnknown = 0,
+ PciBarTypeIo16,
+ PciBarTypeIo32,
+ PciBarTypeMem32,
+ PciBarTypePMem32,
+ PciBarTypeMem64,
+ PciBarTypePMem64,
+ PciBarTypeOpRom,
+ PciBarTypeIo,
+ PciBarTypeMem,
+ PciBarTypeMaxType
+} PCI_BAR_TYPE;
+
+#include "ComponentName.h"
+#include "PciIo.h"
+#include "PciCommand.h"
+#include "PciDeviceSupport.h"
+#include "PciEnumerator.h"
+#include "PciEnumeratorSupport.h"
+#include "PciDriverOverride.h"
+#include "PciRomTable.h"
+#include "PciOptionRomSupport.h"
+#include "PciPowerManagement.h"
+#include "PciHotPlugSupport.h"
+#include "PciLib.h"
+
+#define VGABASE1 0x3B0
+#define VGALIMIT1 0x3BB
+
+#define VGABASE2 0x3C0
+#define VGALIMIT2 0x3DF
+
+#define ISABASE 0x100
+#define ISALIMIT 0x3FF
+
+//
+// PCI BAR parameters
+//
+struct _PCI_BAR {
+ UINT64 BaseAddress;
+ UINT64 Length;
+ UINT64 Alignment;
+ PCI_BAR_TYPE BarType;
+ BOOLEAN BarTypeFixed;
+ UINT16 Offset;
+};
+
+//
+// defined in PCI Card Specification, 8.0
+//
+#define PCI_CARD_MEMORY_BASE_0 0x1C
+#define PCI_CARD_MEMORY_LIMIT_0 0x20
+#define PCI_CARD_MEMORY_BASE_1 0x24
+#define PCI_CARD_MEMORY_LIMIT_1 0x28
+#define PCI_CARD_IO_BASE_0_LOWER 0x2C
+#define PCI_CARD_IO_BASE_0_UPPER 0x2E
+#define PCI_CARD_IO_LIMIT_0_LOWER 0x30
+#define PCI_CARD_IO_LIMIT_0_UPPER 0x32
+#define PCI_CARD_IO_BASE_1_LOWER 0x34
+#define PCI_CARD_IO_BASE_1_UPPER 0x36
+#define PCI_CARD_IO_LIMIT_1_LOWER 0x38
+#define PCI_CARD_IO_LIMIT_1_UPPER 0x3A
+#define PCI_CARD_BRIDGE_CONTROL 0x3E
+
+#define PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE BIT8
+#define PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE BIT9
+
+#define RB_IO_RANGE 1
+#define RB_MEM32_RANGE 2
+#define RB_PMEM32_RANGE 3
+#define RB_MEM64_RANGE 4
+#define RB_PMEM64_RANGE 5
+
+#define PPB_BAR_0 0
+#define PPB_BAR_1 1
+#define PPB_IO_RANGE 2
+#define PPB_MEM32_RANGE 3
+#define PPB_PMEM32_RANGE 4
+#define PPB_PMEM64_RANGE 5
+#define PPB_MEM64_RANGE 0xFF
+
+#define P2C_BAR_0 0
+#define P2C_MEM_1 1
+#define P2C_MEM_2 2
+#define P2C_IO_1 3
+#define P2C_IO_2 4
+
+#define EFI_BRIDGE_IO32_DECODE_SUPPORTED 0x0001
+#define EFI_BRIDGE_PMEM32_DECODE_SUPPORTED 0x0002
+#define EFI_BRIDGE_PMEM64_DECODE_SUPPORTED 0x0004
+#define EFI_BRIDGE_IO16_DECODE_SUPPORTED 0x0008
+#define EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED 0x0010
+#define EFI_BRIDGE_MEM64_DECODE_SUPPORTED 0x0020
+#define EFI_BRIDGE_MEM32_DECODE_SUPPORTED 0x0040
+
+#define PCI_MAX_HOST_BRIDGE_NUM 0x0010
+
+//
+// Define option for attribute
+//
+#define EFI_SET_SUPPORTS 0
+#define EFI_SET_ATTRIBUTES 1
+
+#define PCI_IO_DEVICE_SIGNATURE SIGNATURE_32 ('p', 'c', 'i', 'o')
+
+struct _PCI_IO_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_PCI_IO_PROTOCOL PciIo;
+ LIST_ENTRY Link;
+
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL PciDriverOverride;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_LOAD_FILE2_PROTOCOL LoadFile2;
+
+ //
+ // PCI configuration space header type
+ //
+ PCI_TYPE00 Pci;
+
+ //
+ // Bus number, Device number, Function number
+ //
+ UINT8 BusNumber;
+ UINT8 DeviceNumber;
+ UINT8 FunctionNumber;
+
+ //
+ // BAR for this PCI Device
+ //
+ PCI_BAR PciBar[PCI_MAX_BAR];
+
+ //
+ // The bridge device this pci device is subject to
+ //
+ PCI_IO_DEVICE *Parent;
+
+ //
+ // A linked list for children Pci Device if it is bridge device
+ //
+ LIST_ENTRY ChildList;
+
+ //
+ // TRUE if the PCI bus driver creates the handle for this PCI device
+ //
+ BOOLEAN Registered;
+
+ //
+ // TRUE if the PCI bus driver successfully allocates the resource required by
+ // this PCI device
+ //
+ BOOLEAN Allocated;
+
+ //
+ // The attribute this PCI device currently set
+ //
+ UINT64 Attributes;
+
+ //
+ // The attributes this PCI device actually supports
+ //
+ UINT64 Supports;
+
+ //
+ // The resource decode the bridge supports
+ //
+ UINT32 Decodes;
+
+ //
+ // TRUE if the ROM image is from the PCI Option ROM BAR
+ //
+ BOOLEAN EmbeddedRom;
+
+ //
+ // The OptionRom Size
+ //
+ UINT32 RomSize;
+
+ //
+ // TRUE if all OpROM (in device or in platform specific position) have been processed
+ //
+ BOOLEAN AllOpRomProcessed;
+
+ //
+ // TRUE if there is any EFI driver in the OptionRom
+ //
+ BOOLEAN BusOverride;
+
+ //
+ // A list tracking reserved resource on a bridge device
+ //
+ LIST_ENTRY ReservedResourceList;
+
+ //
+ // A list tracking image handle of platform specific overriding driver
+ //
+ LIST_ENTRY OptionRomDriverList;
+
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ResourcePaddingDescriptors;
+ EFI_HPC_PADDING_ATTRIBUTES PaddingAttributes;
+
+ //
+ // Bus number ranges for a PCI Root Bridge device
+ //
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
+
+ BOOLEAN IsPciExp;
+ //
+ // For SR-IOV
+ //
+ UINT8 PciExpressCapabilityOffset;
+ UINT32 AriCapabilityOffset;
+ UINT32 SrIovCapabilityOffset;
+ UINT32 MrIovCapabilityOffset;
+ PCI_BAR VfPciBar[PCI_MAX_BAR];
+ UINT32 SystemPageSize;
+ UINT16 InitialVFs;
+ UINT16 ReservedBusNum;
+ //
+ // Per PCI to PCI Bridge spec, I/O window is 4K aligned,
+ // but some chipsets support non-standard I/O window alignments less than 4K.
+ // This field is used to support this case.
+ //
+ UINT16 BridgeIoAlignment;
+};
+
+#define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \
+ CR (a, PCI_IO_DEVICE, PciIo, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS(a) \
+ CR (a, PCI_IO_DEVICE, PciDriverOverride, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_LINK(a) \
+ CR (a, PCI_IO_DEVICE, Link, PCI_IO_DEVICE_SIGNATURE)
+
+#define PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS(a) \
+ CR (a, PCI_IO_DEVICE, LoadFile2, PCI_IO_DEVICE_SIGNATURE)
+
+
+
+//
+// Global Variables
+//
+extern EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *gIncompatiblePciDeviceSupport;
+extern EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2;
+extern BOOLEAN gFullEnumeration;
+extern UINTN gPciHostBridgeNumber;
+extern EFI_HANDLE gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
+extern UINT64 gAllOne;
+extern UINT64 gAllZero;
+extern EFI_PCI_PLATFORM_PROTOCOL *gPciPlatformProtocol;
+extern EFI_PCI_OVERRIDE_PROTOCOL *gPciOverrideProtocol;
+extern BOOLEAN mReserveIsaAliases;
+extern BOOLEAN mReserveVgaAliases;
+
+/**
+ Macro that checks whether device is a GFX device.
+
+ @param _p Specified device.
+
+ @retval TRUE Device is a GFX device.
+ @retval FALSE Device is not a GFX device.
+
+**/
+#define IS_PCI_GFX(_p) IS_CLASS2 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_OTHER)
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller 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
+PciBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle and enumerate Pci bus and start
+ all device under PCI bus.
+
+ @param This Protocol instance pointer.
+ @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 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
+PciBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller 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
+PciBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
new file mode 100644
index 000000000..9284998f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -0,0 +1,111 @@
+## @file
+# The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices.
+# Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciBusDxe
+ MODULE_UNI_FILE = PciBusDxe.uni
+ FILE_GUID = 93B80004-9FB3-11d4-9A3A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciBusEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gPciBusDriverBinding
+# COMPONENT_NAME = gPciBusComponentName
+# COMPONENT_NAME2 = gPciBusComponentName2
+#
+
+[Sources]
+ PciLib.c
+ PciIo.c
+ PciBus.c
+ PciDeviceSupport.c
+ ComponentName.c
+ ComponentName.h
+ PciCommand.c
+ PciResourceSupport.c
+ PciEnumeratorSupport.c
+ PciEnumerator.c
+ PciOptionRomSupport.c
+ PciDriverOverride.c
+ PciPowerManagement.c
+ PciPowerManagement.h
+ PciDriverOverride.h
+ PciRomTable.c
+ PciHotPlugSupport.c
+ PciLib.h
+ PciHotPlugSupport.h
+ PciRomTable.h
+ PciOptionRomSupport.h
+ PciEnumeratorSupport.h
+ PciEnumerator.h
+ PciResourceSupport.h
+ PciDeviceSupport.h
+ PciCommand.h
+ PciIo.h
+ PciBus.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiPciHotPlugRequestProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiPciIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiBusSpecificDriverOverrideProtocolGuid ## BY_START
+ gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDecompressProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciHotPlugInitProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciHostBridgeResourceAllocationProtocolGuid ## TO_START
+ gEfiPciPlatformProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciEnumerationCompleteProtocolGuid ## PRODUCES
+ gEfiPciRootBridgeIoProtocolGuid ## TO_START
+ gEfiIncompatiblePciDeviceSupportProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiDeviceSecurityProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiDeviceIdentifierTypePciGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBridgeIoAlignmentProbe ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnalignedPciIoEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PciBusDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.uni
new file mode 100644
index 000000000..8e2c0ef68
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The PCI bus driver will probe all PCI devices and allocate MMIO and IO space for these devices.
+//
+// Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Probes all PCI devices and allocate MMIO and IO space for these devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxeExtra.uni
new file mode 100644
index 000000000..f6028d238
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PciBusDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"PCI Bus DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c
new file mode 100644
index 000000000..6283d6022
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c
@@ -0,0 +1,267 @@
+/** @file
+ PCI command register operations supporting functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Operate the PCI register via PciIo function interface.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+ @param Command Operator command.
+ @param Offset The address within the PCI configuration space for the PCI controller.
+ @param Operation Type of Operation.
+ @param PtrCommand Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
+
+ @return Status of PciIo operation.
+
+**/
+EFI_STATUS
+PciOperateRegister (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT8 Offset,
+ IN UINT8 Operation,
+ OUT UINT16 *PtrCommand
+ )
+{
+ UINT16 OldCommand;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ OldCommand = 0;
+ PciIo = &PciIoDevice->PciIo;
+
+ if (Operation != EFI_SET_REGISTER) {
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ Offset,
+ 1,
+ &OldCommand
+ );
+
+ if (Operation == EFI_GET_REGISTER) {
+ *PtrCommand = OldCommand;
+ return Status;
+ }
+ }
+
+ if (Operation == EFI_ENABLE_REGISTER) {
+ OldCommand = (UINT16) (OldCommand | Command);
+ } else if (Operation == EFI_DISABLE_REGISTER) {
+ OldCommand = (UINT16) (OldCommand & ~(Command));
+ } else {
+ OldCommand = Command;
+ }
+
+ return PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ Offset,
+ 1,
+ &OldCommand
+ );
+}
+
+/**
+ Check the capability supporting by given device.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+
+ @retval TRUE Capability supported.
+ @retval FALSE Capability not supported.
+
+**/
+BOOLEAN
+PciCapabilitySupport (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if ((PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Locate capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfully located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocateCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 CapId,
+ IN OUT UINT8 *Offset,
+ OUT UINT8 *NextRegBlock OPTIONAL
+ )
+{
+ UINT8 CapabilityPtr;
+ UINT16 CapabilityEntry;
+ UINT8 CapabilityID;
+
+ //
+ // To check the capability of this device supports
+ //
+ if (!PciCapabilitySupport (PciIoDevice)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*Offset != 0) {
+ CapabilityPtr = *Offset;
+ } else {
+
+ CapabilityPtr = 0;
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR,
+ 1,
+ &CapabilityPtr
+ );
+ } else {
+
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CAPBILITY_POINTER_OFFSET,
+ 1,
+ &CapabilityPtr
+ );
+ }
+ }
+
+ while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) {
+ PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ CapabilityPtr,
+ 1,
+ &CapabilityEntry
+ );
+
+ CapabilityID = (UINT8) CapabilityEntry;
+
+ if (CapabilityID == CapId) {
+ *Offset = CapabilityPtr;
+ if (NextRegBlock != NULL) {
+ *NextRegBlock = (UINT8) (CapabilityEntry >> 8);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Certain PCI device may incorrectly have capability pointing to itself,
+ // break to avoid dead loop.
+ //
+ if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) {
+ break;
+ }
+
+ CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate PciExpress capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfully located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocatePciExpressCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 CapId,
+ IN OUT UINT32 *Offset,
+ OUT UINT32 *NextRegBlock OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT32 CapabilityPtr;
+ UINT32 CapabilityEntry;
+ UINT16 CapabilityID;
+
+ //
+ // To check the capability of this device supports
+ //
+ if (!PciIoDevice->IsPciExp) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*Offset != 0) {
+ CapabilityPtr = *Offset;
+ } else {
+ CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
+ }
+
+ while (CapabilityPtr != 0) {
+ //
+ // Mask it to DWORD alignment per PCI spec
+ //
+ CapabilityPtr &= 0xFFC;
+ Status = PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint32,
+ CapabilityPtr,
+ 1,
+ &CapabilityEntry
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (CapabilityEntry == MAX_UINT32) {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: [%02x|%02x|%02x] failed to access config space at offset 0x%x\n",
+ __FUNCTION__,
+ PciIoDevice->BusNumber,
+ PciIoDevice->DeviceNumber,
+ PciIoDevice->FunctionNumber,
+ CapabilityPtr
+ ));
+ break;
+ }
+
+ CapabilityID = (UINT16) CapabilityEntry;
+
+ if (CapabilityID == CapId) {
+ *Offset = CapabilityPtr;
+ if (NextRegBlock != NULL) {
+ *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h
new file mode 100644
index 000000000..cf9903270
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.h
@@ -0,0 +1,232 @@
+/** @file
+ PCI command register operations supporting functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_PCI_COMMAND_H_
+#define _EFI_PCI_COMMAND_H_
+
+//
+// The PCI Command register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCI_COMMAND_BITS_OWNED ( \
+ EFI_PCI_COMMAND_IO_SPACE | \
+ EFI_PCI_COMMAND_MEMORY_SPACE | \
+ EFI_PCI_COMMAND_BUS_MASTER | \
+ EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE | \
+ EFI_PCI_COMMAND_VGA_PALETTE_SNOOP | \
+ EFI_PCI_COMMAND_FAST_BACK_TO_BACK \
+ )
+
+//
+// The PCI Bridge Control register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCI_BRIDGE_CONTROL_BITS_OWNED ( \
+ EFI_PCI_BRIDGE_CONTROL_ISA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA_16 | \
+ EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \
+ )
+
+//
+// The PCCard Bridge Control register bits owned by PCI Bus driver.
+//
+// They should be cleared at the beginning. The other registers
+// are owned by chipset, we should not touch them.
+//
+#define EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED ( \
+ EFI_PCI_BRIDGE_CONTROL_ISA | \
+ EFI_PCI_BRIDGE_CONTROL_VGA | \
+ EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \
+ )
+
+
+#define EFI_GET_REGISTER 1
+#define EFI_SET_REGISTER 2
+#define EFI_ENABLE_REGISTER 3
+#define EFI_DISABLE_REGISTER 4
+
+/**
+ Operate the PCI register via PciIo function interface.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+ @param Command Operator command.
+ @param Offset The address within the PCI configuration space for the PCI controller.
+ @param Operation Type of Operation.
+ @param PtrCommand Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
+
+ @return Status of PciIo operation.
+
+**/
+EFI_STATUS
+PciOperateRegister (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT8 Offset,
+ IN UINT8 Operation,
+ OUT UINT16 *PtrCommand
+ );
+
+/**
+ Check the capability supporting by given device.
+
+ @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
+
+ @retval TRUE Capability supported.
+ @retval FALSE Capability not supported.
+
+**/
+BOOLEAN
+PciCapabilitySupport (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Locate capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfully located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocateCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 CapId,
+ IN OUT UINT8 *Offset,
+ OUT UINT8 *NextRegBlock OPTIONAL
+ );
+
+/**
+ Locate PciExpress capability register block per capability ID.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param CapId The capability ID.
+ @param Offset A pointer to the offset returned.
+ @param NextRegBlock A pointer to the next block returned.
+
+ @retval EFI_SUCCESS Successfully located capability register block.
+ @retval EFI_UNSUPPORTED Pci device does not support capability.
+ @retval EFI_NOT_FOUND Pci device support but can not find register block.
+
+**/
+EFI_STATUS
+LocatePciExpressCapabilityRegBlock (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 CapId,
+ IN OUT UINT32 *Offset,
+ OUT UINT32 *NextRegBlock OPTIONAL
+ );
+
+/**
+ Macro that reads command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[out] Pointer to the 16-bit value read from command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_READ_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, 0, PCI_COMMAND_OFFSET, EFI_GET_REGISTER, b)
+
+/**
+ Macro that writes command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The 16-bit value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_SET_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_SET_REGISTER, NULL)
+
+/**
+ Macro that enables command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The enabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_ENABLE_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_ENABLE_REGISTER, NULL)
+
+/**
+ Macro that disables command register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The disabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_DISABLE_COMMAND_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_DISABLE_REGISTER, NULL)
+
+/**
+ Macro that reads PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[out] The 16-bit value read from control register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_READ_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, 0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_GET_REGISTER, b)
+
+/**
+ Macro that writes PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The 16-bit value written into control register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_SET_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_SET_REGISTER, NULL)
+
+/**
+ Macro that enables PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The enabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_ENABLE_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_ENABLE_REGISTER, NULL)
+
+/**
+ Macro that disables PCI bridge control register.
+
+ @param a[in] Pointer to instance of PCI_IO_DEVICE.
+ @param b[in] The disabled value written into command register.
+
+ @return status of PciIo operation
+
+**/
+#define PCI_DISABLE_BRIDGE_CONTROL_REGISTER(a,b) \
+ PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET, EFI_DISABLE_REGISTER, NULL)
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
new file mode 100644
index 000000000..292dd25da
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
@@ -0,0 +1,1056 @@
+/** @file
+ Supporting functions implementation for PCI devices management.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+//
+// This device structure is serviced as a header.
+// Its next field points to the first root bridge device node.
+//
+LIST_ENTRY mPciDevicePool;
+
+/**
+ Initialize the PCI devices pool.
+
+**/
+VOID
+InitializePciDevicePool (
+ VOID
+ )
+{
+ InitializeListHead (&mPciDevicePool);
+}
+
+/**
+ Insert a root bridge into PCI device pool.
+
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+InsertRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ )
+{
+ InsertTailList (&mPciDevicePool, &(RootBridge->Link));
+}
+
+/**
+ This function is used to insert a PCI device node under
+ a bridge.
+
+ @param Bridge The PCI bridge.
+ @param PciDeviceNode The PCI device needs inserting.
+
+**/
+VOID
+InsertPciDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciDeviceNode
+ )
+{
+ InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
+ PciDeviceNode->Parent = Bridge;
+}
+
+/**
+ Destroy root bridge and remove it from device tree.
+
+ @param RootBridge The bridge want to be removed.
+
+**/
+VOID
+DestroyRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ )
+{
+ DestroyPciDeviceTree (RootBridge);
+
+ FreePciDevice (RootBridge);
+}
+
+/**
+ Destroy a pci device node.
+
+ All direct or indirect allocated resource for this node will be freed.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destroyed.
+
+**/
+VOID
+FreePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ ASSERT (PciIoDevice != NULL);
+ //
+ // Assume all children have been removed underneath this device
+ //
+ if (PciIoDevice->ResourcePaddingDescriptors != NULL) {
+ FreePool (PciIoDevice->ResourcePaddingDescriptors);
+ }
+
+ if (PciIoDevice->DevicePath != NULL) {
+ FreePool (PciIoDevice->DevicePath);
+ }
+
+ if (PciIoDevice->BusNumberRanges != NULL) {
+ FreePool (PciIoDevice->BusNumberRanges);
+ }
+
+ FreePool (PciIoDevice);
+}
+
+/**
+ Destroy all the pci device node under the bridge.
+ Bridge itself is not included.
+
+ @param Bridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+DestroyPciDeviceTree (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ //
+ // Remove this node from the linked list
+ //
+ RemoveEntryList (CurrentLink);
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ DestroyPciDeviceTree (Temp);
+ }
+
+ FreePciDevice (Temp);
+ }
+}
+
+/**
+ Destroy all device nodes under the root bridge
+ specified by Controller.
+
+ The root bridge itself is also included.
+
+ @param Controller Root bridge handle.
+
+ @retval EFI_SUCCESS Destroy all device nodes successfully.
+ @retval EFI_NOT_FOUND Cannot find any PCI device under specified
+ root bridge.
+
+**/
+EFI_STATUS
+DestroyRootBridgeByHandle (
+ IN EFI_HANDLE Controller
+ )
+{
+
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Temp->Handle == Controller) {
+
+ RemoveEntryList (CurrentLink);
+
+ DestroyPciDeviceTree (Temp);
+
+ FreePciDevice (Temp);
+
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function registers the PCI IO device.
+
+ It creates a handle for this PCI IO device (if the handle does not exist), attaches
+ appropriate protocols onto the handle, does necessary initialization, and sets up
+ parent/child relationship with its bus controller.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
+ @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
+
+ @retval EFI_SUCCESS The PCI device is successfully registered.
+ @retval other An error occurred when registering the PCI device.
+
+**/
+EFI_STATUS
+RegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *PciIoDevice,
+ OUT EFI_HANDLE *Handle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ VOID *PlatformOpRomBuffer;
+ UINTN PlatformOpRomSize;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data8;
+ BOOLEAN HasEfiImage;
+
+ //
+ // Install the pciio protocol, device path protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Force Interrupt line to "Unknown" or "No Connection"
+ //
+ PciIo = &(PciIoDevice->PciIo);
+ Data8 = PCI_INT_LINE_UNKNOWN;
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
+
+ //
+ // Process OpRom
+ //
+ if (!PciIoDevice->AllOpRomProcessed) {
+
+ //
+ // Get the OpRom provided by platform
+ //
+ if (gPciPlatformProtocol != NULL) {
+ Status = gPciPlatformProtocol->GetPciRom (
+ gPciPlatformProtocol,
+ PciIoDevice->Handle,
+ &PlatformOpRomBuffer,
+ &PlatformOpRomSize
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->EmbeddedRom = FALSE;
+ PciIoDevice->RomSize = (UINT32) PlatformOpRomSize;
+ PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
+ //
+ // For OpROM read from gPciPlatformProtocol:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciIoDevice->PciRootBridgeIo->SegmentNumber,
+ PciIoDevice->BusNumber,
+ PciIoDevice->DeviceNumber,
+ PciIoDevice->FunctionNumber,
+ PciIoDevice->PciIo.RomImage,
+ PciIoDevice->PciIo.RomSize
+ );
+ }
+ } else if (gPciOverrideProtocol != NULL) {
+ Status = gPciOverrideProtocol->GetPciRom (
+ gPciOverrideProtocol,
+ PciIoDevice->Handle,
+ &PlatformOpRomBuffer,
+ &PlatformOpRomSize
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->EmbeddedRom = FALSE;
+ PciIoDevice->RomSize = (UINT32) PlatformOpRomSize;
+ PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
+ PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
+ //
+ // For OpROM read from gPciOverrideProtocol:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciIoDevice->PciRootBridgeIo->SegmentNumber,
+ PciIoDevice->BusNumber,
+ PciIoDevice->DeviceNumber,
+ PciIoDevice->FunctionNumber,
+ PciIoDevice->PciIo.RomImage,
+ PciIoDevice->PciIo.RomSize
+ );
+ }
+ }
+ }
+
+ //
+ // Determine if there are EFI images in the option rom
+ //
+ HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);
+
+ if (HasEfiImage) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ return Status;
+ }
+ }
+
+
+ if (!PciIoDevice->AllOpRomProcessed) {
+
+ PciIoDevice->AllOpRomProcessed = TRUE;
+
+ //
+ // Dispatch the EFI OpRom for the PCI device.
+ // The OpRom is got from platform in the above code
+ // or loaded from device in the previous round of bus enumeration
+ //
+ if (HasEfiImage) {
+ ProcessOpRomImage (PciIoDevice);
+ }
+ }
+
+ if (PciIoDevice->BusOverride) {
+ //
+ // Install Bus Specific Driver Override Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PciIoDevice->Handle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ &PciIoDevice->PciDriverOverride,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ PciIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ if (HasEfiImage) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ PciIoDevice->Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ }
+
+ return Status;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &(PciIoDevice->PciRootBridgeIo),
+ gPciBusDriverBinding.DriverBindingHandle,
+ PciIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Handle != NULL) {
+ *Handle = PciIoDevice->Handle;
+ }
+
+ //
+ // Indicate the pci device is registered
+ //
+ PciIoDevice->Registered = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to remove the whole PCI devices on the specified bridge from
+ the root bridge.
+
+ @param RootBridgeHandle The root bridge device handle.
+ @param Bridge The bridge device to be removed.
+
+**/
+VOID
+RemoveAllPciDeviceOnBridge (
+ EFI_HANDLE RootBridgeHandle,
+ PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ //
+ // Check if the current node has been deregistered before
+ // If it is not, then deregister it
+ //
+ if (Temp->Registered) {
+ DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
+ }
+
+ //
+ // Remove this node from the linked list
+ //
+ RemoveEntryList (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
+ }
+
+ FreePciDevice (Temp);
+ }
+}
+
+/**
+ This function is used to de-register the PCI IO device.
+
+ That includes un-installing PciIo protocol from the specified PCI
+ device handle.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param Handle PCI device handle.
+
+ @retval EFI_SUCCESS The PCI device is successfully de-registered.
+ @retval other An error occurred when de-registering the PCI device.
+
+**/
+EFI_STATUS
+DeRegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ PCI_IO_DEVICE *Node;
+ LIST_ENTRY *CurrentLink;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
+
+ //
+ // If it is already de-registered
+ //
+ if (!PciIoDevice->Registered) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If it is PPB, first de-register its children
+ //
+
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+ Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ Status = DeRegisterPciDevice (Controller, Node->Handle);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // Un-install the Device Path protocol and PCI I/O protocol
+ // and Bus Specific Driver Override protocol if needed.
+ //
+ if (PciIoDevice->BusOverride) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ &PciIoDevice->PciDriverOverride,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEfiPciIoProtocolGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to uninstall LoadFile2 protocol if exists
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ NULL,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiLoadFile2ProtocolGuid,
+ &PciIoDevice->LoadFile2,
+ NULL
+ );
+ }
+ //
+ // Restore Status
+ //
+ Status = EFI_SUCCESS;
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // The Device Driver should disable this device after disconnect
+ // so the Pci Bus driver will not touch this device any more.
+ // Restore the register field to the original value
+ //
+ PciIoDevice->Registered = FALSE;
+ PciIoDevice->Handle = NULL;
+ } else {
+
+ //
+ // Handle may be closed before
+ //
+ return EFI_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
+
+ @param Controller The root bridge handle.
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+ @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
+ @param NumberOfChildren Children number.
+ @param ChildHandleBuffer A pointer to the child handle buffer.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
+ @retval EFI_NOT_FOUND Can not find the specific device.
+ @retval EFI_SUCCESS Success to start Pci devices on bridge.
+
+**/
+EFI_STATUS
+StartPciDevicesOnBridge (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE *ChildHandleBuffer
+ )
+
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_DEV_PATH_PTR Node;
+ EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
+ EFI_STATUS Status;
+ LIST_ENTRY *CurrentLink;
+ UINT64 Supports;
+
+ PciIoDevice = NULL;
+ CurrentLink = RootBridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (RemainingDevicePath != NULL) {
+
+ Node.DevPath = RemainingDevicePath;
+
+ if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
+ Node.Pci->Function != PciIoDevice->FunctionNumber) {
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+ }
+
+ //
+ // Check if the device has been assigned with required resource
+ //
+ if (!PciIoDevice->Allocated) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Check if the current node has been registered before
+ // If it is not, register it
+ //
+ if (!PciIoDevice->Registered) {
+ Status = RegisterPciDevice (
+ Controller,
+ PciIoDevice,
+ NULL
+ );
+
+ }
+
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
+ ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
+ (*NumberOfChildren)++;
+ }
+
+ //
+ // Get the next device path
+ //
+ CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
+ if (IsDevicePathEnd (CurrentDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If it is a PPB
+ //
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ Status = StartPciDevicesOnBridge (
+ Controller,
+ PciIoDevice,
+ CurrentDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+
+ return Status;
+ } else {
+
+ //
+ // Currently, the PCI bus driver only support PCI-PCI bridge
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+
+ //
+ // If remaining device path is NULL,
+ // try to enable all the pci devices under this bridge
+ //
+ if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
+ Status = RegisterPciDevice (
+ Controller,
+ PciIoDevice,
+ NULL
+ );
+
+ }
+
+ if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
+ ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
+ (*NumberOfChildren)++;
+ }
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ Status = StartPciDevicesOnBridge (
+ Controller,
+ PciIoDevice,
+ RemainingDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+
+ if (PciIoDevice == NULL) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Start to manage all the PCI devices it found previously under
+ the entire host bridge.
+
+ @param Controller The root bridge handle.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_SUCCESS Success to start Pci device on host bridge.
+
+**/
+EFI_STATUS
+StartPciDevices (
+ IN EFI_HANDLE Controller
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_HANDLE ThisHostBridge;
+ LIST_ENTRY *CurrentLink;
+
+ RootBridge = GetRootBridgeByHandle (Controller);
+ ASSERT (RootBridge != NULL);
+ ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ //
+ // Locate the right root bridge to start
+ //
+ if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
+ StartPciDevicesOnBridge (
+ RootBridge->Handle,
+ RootBridge,
+ NULL,
+ NULL,
+ NULL
+ );
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create root bridge device.
+
+ @param RootBridgeHandle Specified root bridge handle.
+
+ @return The crated root bridge device instance, NULL means no
+ root bridge device instance created.
+
+**/
+PCI_IO_DEVICE *
+CreateRootBridge (
+ IN EFI_HANDLE RootBridgeHandle
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *Dev;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
+ if (Dev == NULL) {
+ return NULL;
+ }
+
+ Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
+ Dev->Handle = RootBridgeHandle;
+ InitializeListHead (&Dev->ChildList);
+
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Dev);
+ return NULL;
+ }
+
+ //
+ // Record the root bridge parent device path
+ //
+ Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
+
+ //
+ // Get the pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePciDevice (Dev);
+ return NULL;
+ }
+
+ Dev->PciRootBridgeIo = PciRootBridgeIo;
+
+ //
+ // Initialize the PCI I/O instance structure
+ //
+ InitializePciIoInstance (Dev);
+ InitializePciDriverOverrideInstance (Dev);
+ InitializePciLoadFile2 (Dev);
+
+ //
+ // Initialize reserved resource list and
+ // option rom driver list
+ //
+ InitializeListHead (&Dev->ReservedResourceList);
+ InitializeListHead (&Dev->OptionRomDriverList);
+
+ return Dev;
+}
+
+/**
+ Get root bridge device instance by specific root bridge handle.
+
+ @param RootBridgeHandle Given root bridge handle.
+
+ @return The root bridge device instance, NULL means no root bridge
+ device instance found.
+
+**/
+PCI_IO_DEVICE *
+GetRootBridgeByHandle (
+ EFI_HANDLE RootBridgeHandle
+ )
+{
+ PCI_IO_DEVICE *RootBridgeDev;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (RootBridgeDev->Handle == RootBridgeHandle) {
+ return RootBridgeDev;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Judge whether Pci device existed.
+
+ @param Bridge Parent bridge instance.
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Pci device existed.
+ @retval FALSE Pci device did not exist.
+
+**/
+BOOLEAN
+PciDeviceExisted (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (Temp == PciIoDevice) {
+ return TRUE;
+ }
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ if (PciDeviceExisted (Temp, PciIoDevice)) {
+ return TRUE;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the active VGA device on the specified Host Bridge.
+
+ @param HostBridgeHandle Host Bridge handle.
+
+ @return The active VGA device on the specified Host Bridge.
+
+**/
+PCI_IO_DEVICE *
+LocateVgaDeviceOnHostBridge (
+ IN EFI_HANDLE HostBridgeHandle
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ CurrentLink = mPciDevicePool.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (PciIoDevice->PciRootBridgeIo->ParentHandle== HostBridgeHandle) {
+
+ PciIoDevice = LocateVgaDevice (PciIoDevice);
+
+ if (PciIoDevice != NULL) {
+ return PciIoDevice;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ Locate the active VGA device under the bridge.
+
+ @param Bridge PCI IO instance for the bridge.
+
+ @return The active VGA device.
+
+**/
+PCI_IO_DEVICE *
+LocateVgaDevice (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_VGA(&PciIoDevice->Pci) &&
+ (PciIoDevice->Attributes &
+ (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ return PciIoDevice;
+ }
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+
+ PciIoDevice = LocateVgaDevice (PciIoDevice);
+
+ if (PciIoDevice != NULL) {
+ return PciIoDevice;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h
new file mode 100644
index 000000000..3dae540da
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.h
@@ -0,0 +1,266 @@
+/** @file
+ Supporting functions declaration for PCI devices management.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_DEVICE_SUPPORT_H_
+#define _EFI_PCI_DEVICE_SUPPORT_H_
+
+/**
+ Initialize the PCI devices pool.
+
+**/
+VOID
+InitializePciDevicePool (
+ VOID
+ );
+
+/**
+ Insert a root bridge into PCI device pool.
+
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+InsertRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ );
+
+/**
+ This function is used to insert a PCI device node under
+ a bridge.
+
+ @param Bridge The PCI bridge.
+ @param PciDeviceNode The PCI device needs inserting.
+
+**/
+VOID
+InsertPciDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciDeviceNode
+ );
+
+/**
+ Destroy root bridge and remove it from device tree.
+
+ @param RootBridge The bridge want to be removed.
+
+**/
+VOID
+DestroyRootBridge (
+ IN PCI_IO_DEVICE *RootBridge
+ );
+
+/**
+ Destroy all the pci device node under the bridge.
+ Bridge itself is not included.
+
+ @param Bridge A pointer to the PCI_IO_DEVICE.
+
+**/
+VOID
+DestroyPciDeviceTree (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Destroy all device nodes under the root bridge
+ specified by Controller.
+
+ The root bridge itself is also included.
+
+ @param Controller Root bridge handle.
+
+ @retval EFI_SUCCESS Destroy all device nodes successfully.
+ @retval EFI_NOT_FOUND Cannot find any PCI device under specified
+ root bridge.
+
+**/
+EFI_STATUS
+DestroyRootBridgeByHandle (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ This function registers the PCI IO device.
+
+ It creates a handle for this PCI IO device (if the handle does not exist), attaches
+ appropriate protocols onto the handle, does necessary initialization, and sets up
+ parent/child relationship with its bus controller.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
+ @param Handle A pointer to hold the returned EFI handle for the PCI IO device.
+
+ @retval EFI_SUCCESS The PCI device is successfully registered.
+ @retval other An error occurred when registering the PCI device.
+
+**/
+EFI_STATUS
+RegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *PciIoDevice,
+ OUT EFI_HANDLE *Handle OPTIONAL
+ );
+
+/**
+ This function is used to remove the whole PCI devices on the specified bridge from
+ the root bridge.
+
+ @param RootBridgeHandle The root bridge device handle.
+ @param Bridge The bridge device to be removed.
+
+**/
+VOID
+RemoveAllPciDeviceOnBridge (
+ EFI_HANDLE RootBridgeHandle,
+ PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ This function is used to de-register the PCI IO device.
+
+ That includes un-installing PciIo protocol from the specified PCI
+ device handle.
+
+ @param Controller An EFI handle for the PCI bus controller.
+ @param Handle PCI device handle.
+
+ @retval EFI_SUCCESS The PCI device is successfully de-registered.
+ @retval other An error occurred when de-registering the PCI device.
+
+**/
+EFI_STATUS
+DeRegisterPciDevice (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
+
+ @param Controller The root bridge handle.
+ @param RootBridge A pointer to the PCI_IO_DEVICE.
+ @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
+ @param NumberOfChildren Children number.
+ @param ChildHandleBuffer A pointer to the child handle buffer.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
+ @retval EFI_NOT_FOUND Can not find the specific device.
+ @retval EFI_SUCCESS Success to start Pci devices on bridge.
+
+**/
+EFI_STATUS
+StartPciDevicesOnBridge (
+ IN EFI_HANDLE Controller,
+ IN PCI_IO_DEVICE *RootBridge,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Start to manage all the PCI devices it found previously under
+ the entire host bridge.
+
+ @param Controller The root bridge handle.
+
+ @retval EFI_NOT_READY Device is not allocated.
+ @retval EFI_SUCCESS Success to start Pci device on host bridge.
+
+**/
+EFI_STATUS
+StartPciDevices (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ Create root bridge device.
+
+ @param RootBridgeHandle Specified root bridge handle.
+
+ @return The crated root bridge device instance, NULL means no
+ root bridge device instance created.
+
+**/
+PCI_IO_DEVICE *
+CreateRootBridge (
+ IN EFI_HANDLE RootBridgeHandle
+ );
+
+/**
+ Get root bridge device instance by specific root bridge handle.
+
+ @param RootBridgeHandle Given root bridge handle.
+
+ @return The root bridge device instance, NULL means no root bridge
+ device instance found.
+
+**/
+PCI_IO_DEVICE *
+GetRootBridgeByHandle (
+ EFI_HANDLE RootBridgeHandle
+ );
+
+
+/**
+ Judge whether Pci device existed.
+
+ @param Bridge Parent bridge instance.
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Pci device existed.
+ @retval FALSE Pci device did not exist.
+
+**/
+BOOLEAN
+PciDeviceExisted (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Get the active VGA device on the specified Host Bridge.
+
+ @param HostBridgeHandle Host Bridge handle.
+
+ @return The active VGA device on the specified Host Bridge.
+
+**/
+PCI_IO_DEVICE *
+LocateVgaDeviceOnHostBridge (
+ IN EFI_HANDLE HostBridgeHandle
+ );
+
+/**
+ Locate the active VGA device under the bridge.
+
+ @param Bridge PCI IO instance for the bridge.
+
+ @return The active VGA device.
+
+**/
+PCI_IO_DEVICE *
+LocateVgaDevice (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+
+/**
+ Destroy a pci device node.
+
+ All direct or indirect allocated resource for this node will be freed.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destroyed.
+
+**/
+VOID
+FreePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c
new file mode 100644
index 000000000..3531e6b6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.c
@@ -0,0 +1,188 @@
+/** @file
+ Functions implementation for Bus Specific Driver Override protocol.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Initializes a PCI Driver Override Instance.
+
+ @param PciIoDevice PCI Device instance.
+
+**/
+VOID
+InitializePciDriverOverrideInstance (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PciIoDevice->PciDriverOverride.GetDriver = GetDriver;
+}
+
+/**
+ Find the image handle whose path equals to ImagePath.
+
+ @param ImagePath Image path.
+
+ @return Image handle.
+**/
+EFI_HANDLE
+LocateImageHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *ImagePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+ UINTN HandleNum;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ImagePathSize;
+ EFI_HANDLE ImageHandle;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ NULL,
+ &HandleNum,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ImageHandle = NULL;
+ ImagePathSize = GetDevicePathSize (ImagePath);
+
+ for (Index = 0; Index < HandleNum; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if ((ImagePathSize == GetDevicePathSize (DevicePath)) &&
+ (CompareMem (ImagePath, DevicePath, ImagePathSize) == 0)
+ ) {
+ ImageHandle = Handles[Index];
+ break;
+ }
+ }
+
+ FreePool (Handles);
+ return ImageHandle;
+}
+
+/**
+ Uses a bus specific algorithm to retrieve a driver image handle for a controller.
+
+ @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param DriverImageHandle On input, a pointer to the previous driver image handle returned
+ by GetDriver(). On output, a pointer to the next driver
+ image handle. Passing in a NULL, will return the first driver
+ image handle.
+
+ @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle.
+ @retval EFI_NOT_FOUND The end of the list of override drivers was reached.
+ A bus specific override driver is not returned in DriverImageHandle.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a
+ previous call to GetDriver().
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriver (
+ IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN OUT EFI_HANDLE *DriverImageHandle
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ LIST_ENTRY *Link;
+ PCI_DRIVER_OVERRIDE_LIST *Override;
+ BOOLEAN ReturnNext;
+
+ Override = NULL;
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This);
+ ReturnNext = (BOOLEAN) (*DriverImageHandle == NULL);
+ for ( Link = GetFirstNode (&PciIoDevice->OptionRomDriverList)
+ ; !IsNull (&PciIoDevice->OptionRomDriverList, Link)
+ ; Link = GetNextNode (&PciIoDevice->OptionRomDriverList, Link)
+ ) {
+
+ Override = DRIVER_OVERRIDE_FROM_LINK (Link);
+
+ if (ReturnNext) {
+ if (Override->DriverImageHandle == NULL) {
+ Override->DriverImageHandle = LocateImageHandle (Override->DriverImagePath);
+ }
+
+ if (Override->DriverImageHandle == NULL) {
+ //
+ // The Option ROM identified by Override->DriverImagePath is not loaded.
+ //
+ continue;
+ } else {
+ *DriverImageHandle = Override->DriverImageHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (*DriverImageHandle == Override->DriverImageHandle) {
+ ReturnNext = TRUE;
+ }
+ }
+
+ ASSERT (IsNull (&PciIoDevice->OptionRomDriverList, Link));
+ //
+ // ReturnNext indicates a handle match happens.
+ // If all nodes are checked without handle match happening,
+ // the DriverImageHandle should be a invalid handle.
+ //
+ if (ReturnNext) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Add an overriding driver image.
+
+ @param PciIoDevice Instance of PciIo device.
+ @param DriverImageHandle Image handle of newly added driver image.
+ @param DriverImagePath Device path of newly added driver image.
+
+ @retval EFI_SUCCESS Successfully added driver.
+ @retval EFI_OUT_OF_RESOURCES No memory resource for new driver instance.
+ @retval other Some error occurred when locating gEfiLoadedImageProtocolGuid.
+
+**/
+EFI_STATUS
+AddDriver (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_HANDLE DriverImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
+ )
+{
+ PCI_DRIVER_OVERRIDE_LIST *Node;
+
+ //
+ // Caller should pass in either Image Handle or Image Path, but not both.
+ //
+ ASSERT ((DriverImageHandle == NULL) || (DriverImagePath == NULL));
+
+ Node = AllocateZeroPool (sizeof (PCI_DRIVER_OVERRIDE_LIST));
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Node->Signature = DRIVER_OVERRIDE_SIGNATURE;
+ Node->DriverImageHandle = DriverImageHandle;
+ Node->DriverImagePath = DuplicateDevicePath (DriverImagePath);
+
+ InsertTailList (&PciIoDevice->OptionRomDriverList, &Node->Link);
+
+ PciIoDevice->BusOverride = TRUE;
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h
new file mode 100644
index 000000000..03447a59c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciDriverOverride.h
@@ -0,0 +1,83 @@
+/** @file
+ Functions declaration for Bus Specific Driver Override protocol.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_PCI_DRIVER_OVERRRIDE_H_
+#define _EFI_PCI_DRIVER_OVERRRIDE_H_
+
+#define DRIVER_OVERRIDE_SIGNATURE SIGNATURE_32 ('d', 'r', 'o', 'v')
+
+//
+// PCI driver override driver image list
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE DriverImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
+} PCI_DRIVER_OVERRIDE_LIST;
+
+
+#define DRIVER_OVERRIDE_FROM_LINK(a) \
+ CR (a, PCI_DRIVER_OVERRIDE_LIST, Link, DRIVER_OVERRIDE_SIGNATURE)
+
+/**
+ Initializes a PCI Driver Override Instance.
+
+ @param PciIoDevice PCI Device instance.
+
+**/
+VOID
+InitializePciDriverOverrideInstance (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Add an overriding driver image.
+
+ @param PciIoDevice Instance of PciIo device.
+ @param DriverImageHandle Image handle of newly added driver image.
+ @param DriverImagePath Device path of newly added driver image.
+
+ @retval EFI_SUCCESS Successfully added driver.
+ @retval EFI_OUT_OF_RESOURCES No memory resource for new driver instance.
+ @retval other Some error occurred when locating gEfiLoadedImageProtocolGuid.
+
+**/
+EFI_STATUS
+AddDriver (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_HANDLE DriverImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
+ );
+
+
+/**
+ Uses a bus specific algorithm to retrieve a driver image handle for a controller.
+
+ @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param DriverImageHandle On input, a pointer to the previous driver image handle returned
+ by GetDriver(). On output, a pointer to the next driver
+ image handle. Passing in a NULL, will return the first driver
+ image handle.
+
+ @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle.
+ @retval EFI_NOT_FOUND The end of the list of override drivers was reached.
+ A bus specific override driver is not returned in DriverImageHandle.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a
+ previous call to GetDriver().
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriver (
+ IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN OUT EFI_HANDLE *DriverImageHandle
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
new file mode 100644
index 000000000..8db1ebf8e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
@@ -0,0 +1,2210 @@
+/** @file
+ PCI eunmeration implementation on entire PCI bus system for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ @param Controller Parent controller handle.
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumerator (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE HostBridgeHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;
+
+ //
+ // Get the pci host bridge resource allocation protocol
+ //
+ Status = gBS->OpenProtocol (
+ HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ (VOID **) &PciResAlloc,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the pci bus enumeration is about to begin
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Start the bus allocation phase
+ //
+ Status = PciHostBridgeEnumerator (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Submit the resource request
+ //
+ Status = PciHostBridgeResourceAllocator (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the pci bus enumeration is about to complete
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Process P2C
+ //
+ Status = PciHostBridgeP2CProcess (PciResAlloc);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Process attributes for devices on this host bridge
+ //
+ Status = PciHostBridgeDeviceAttribute (PciResAlloc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enumerate PCI root bridge.
+
+ @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+ @param RootBridgeDev Instance of root bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated root bridge.
+ @retval other Failed to enumerate root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration1;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration2;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration3;
+ UINT8 SubBusNumber;
+ UINT8 StartBusNumber;
+ UINT8 PaddedBusRange;
+ EFI_HANDLE RootBridgeHandle;
+ UINT8 Desc;
+ UINT64 AddrLen;
+ UINT64 AddrRangeMin;
+
+ SubBusNumber = 0;
+ StartBusNumber = 0;
+ PaddedBusRange = 0;
+
+ //
+ // Get the root bridge handle
+ //
+ RootBridgeHandle = RootBridgeDev->Handle;
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_BUS_ENUM,
+ RootBridgeDev->DevicePath
+ );
+
+ //
+ // Get the Bus information
+ //
+ Status = PciResAlloc->StartBusEnumeration (
+ PciResAlloc,
+ RootBridgeHandle,
+ (VOID **) &Configuration
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Configuration == NULL || Configuration->Desc == ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+ RootBridgeDev->BusNumberRanges = Configuration;
+
+ //
+ // Sort the descriptors in ascending order
+ //
+ for (Configuration1 = Configuration; Configuration1->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration1++) {
+ Configuration2 = Configuration1;
+ for (Configuration3 = Configuration1 + 1; Configuration3->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration3++) {
+ if (Configuration2->AddrRangeMin > Configuration3->AddrRangeMin) {
+ Configuration2 = Configuration3;
+ }
+ }
+ //
+ // All other fields other than AddrRangeMin and AddrLen are ignored in a descriptor,
+ // so only need to swap these two fields.
+ //
+ if (Configuration2 != Configuration1) {
+ AddrRangeMin = Configuration1->AddrRangeMin;
+ Configuration1->AddrRangeMin = Configuration2->AddrRangeMin;
+ Configuration2->AddrRangeMin = AddrRangeMin;
+
+ AddrLen = Configuration1->AddrLen;
+ Configuration1->AddrLen = Configuration2->AddrLen;
+ Configuration2->AddrLen = AddrLen;
+ }
+ }
+
+ //
+ // Get the bus number to start with
+ //
+ StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
+
+ //
+ // Initialize the subordinate bus number
+ //
+ SubBusNumber = StartBusNumber;
+
+ //
+ // Reset all assigned PCI bus number
+ //
+ ResetAllPpbBusNumber (
+ RootBridgeDev,
+ StartBusNumber
+ );
+
+ //
+ // Assign bus number
+ //
+ Status = PciScanBus (
+ RootBridgeDev,
+ StartBusNumber,
+ &SubBusNumber,
+ &PaddedBusRange
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+
+ //
+ // Assign max bus number scanned
+ //
+
+ Status = PciAllocateBusNumber (RootBridgeDev, SubBusNumber, PaddedBusRange, &SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find the bus range which contains the higest bus number, then returns the number of buses
+ // that should be decoded.
+ //
+ while (Configuration->AddrRangeMin + Configuration->AddrLen - 1 < SubBusNumber) {
+ Configuration++;
+ }
+ AddrLen = Configuration->AddrLen;
+ Configuration->AddrLen = SubBusNumber - Configuration->AddrRangeMin + 1;
+
+ //
+ // Save the Desc field of the next descriptor. Mark the next descriptor as an END descriptor.
+ //
+ Configuration++;
+ Desc = Configuration->Desc;
+ Configuration->Desc = ACPI_END_TAG_DESCRIPTOR;
+
+ //
+ // Set bus number
+ //
+ Status = PciResAlloc->SetBusNumbers (
+ PciResAlloc,
+ RootBridgeHandle,
+ RootBridgeDev->BusNumberRanges
+ );
+
+ //
+ // Restore changed fields
+ //
+ Configuration->Desc = Desc;
+ (Configuration - 1)->AddrLen = AddrLen;
+
+ return Status;
+}
+
+/**
+ This routine is used to process all PCI devices' Option Rom
+ on a certain root bridge.
+
+ @param Bridge Given parent's root bridge.
+ @param RomBase Base address of ROM driver loaded from.
+ @param MaxLength Maximum rom size.
+
+**/
+VOID
+ProcessOptionRom (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT64 RomBase,
+ IN UINT64 MaxLength
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+
+ //
+ // Go through bridges to reach all devices
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (!IsListEmpty (&Temp->ChildList)) {
+
+ //
+ // Go further to process the option rom under this bridge
+ //
+ ProcessOptionRom (Temp, RomBase, MaxLength);
+ }
+
+ if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) {
+
+ //
+ // Load and process the option rom
+ //
+ LoadOpRomImage (Temp, RomBase);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ This routine is used to assign bus number to the given PCI bus system
+
+ @param Bridge Parent root bridge instance.
+ @param StartBusNumber Number of beginning.
+ @param SubBusNumber The number of sub bus.
+
+ @retval EFI_SUCCESS Successfully assigned bus number.
+ @retval EFI_DEVICE_ERROR Failed to assign bus number.
+
+**/
+EFI_STATUS
+PciAssignBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 Address;
+ UINTN SecondBus;
+ UINT16 Register;
+ UINT8 Register8;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+
+ SecondBus = 0;
+ Register = 0;
+
+ *SubBusNumber = StartBusNumber;
+
+ //
+ // First check to see whether the parent is ppb
+ //
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (EFI_ERROR (Status) && Func == 0) {
+ //
+ // go to next device if there is no Function 0
+ //
+ break;
+ }
+
+ if (!EFI_ERROR (Status) &&
+ (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
+
+ //
+ // Reserved one bus for cardbus bridge
+ //
+ Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ SecondBus = *SubBusNumber;
+
+ Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
+
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &Register
+ );
+
+ //
+ // Initialize SubBusNumber to SecondBus
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+ //
+ // If it is PPB, resursively search down this bridge
+ //
+ if (IS_PCI_BRIDGE (&Pci)) {
+
+ Register8 = 0xFF;
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &Register8
+ );
+
+ Status = PciAssignBusNumber (
+ Bridge,
+ (UINT8) (SecondBus),
+ SubBusNumber
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Set the current maximum bus number under the PPB
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is used to determine the root bridge attribute by interfacing
+ the host bridge resource allocation protocol.
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param RootBridgeDev Root bridge instance
+
+ @retval EFI_SUCCESS Successfully got root bridge's attribute.
+ @retval other Failed to get attribute.
+
+**/
+EFI_STATUS
+DetermineRootBridgeAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+ EFI_HANDLE RootBridgeHandle;
+
+ Attributes = 0;
+ RootBridgeHandle = RootBridgeDev->Handle;
+
+ //
+ // Get root bridge attribute by calling into pci host bridge resource allocation protocol
+ //
+ Status = PciResAlloc->GetAllocAttributes (
+ PciResAlloc,
+ RootBridgeHandle,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Here is the point where PCI bus driver calls HOST bridge allocation protocol
+ // Currently we hardcoded for ea815
+ //
+ if ((Attributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED;
+ }
+
+ if ((Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0) {
+ RootBridgeDev->Decodes |= EFI_BRIDGE_MEM64_DECODE_SUPPORTED;
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
+ }
+
+ RootBridgeDev->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
+ RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ RootBridgeDev->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Max Option Rom size on specified bridge.
+
+ @param Bridge Given bridge device instance.
+
+ @return Max size of option rom needed.
+
+**/
+UINT32
+GetMaxOptionRomSize (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+ UINT32 MaxOptionRomSize;
+ UINT32 TempOptionRomSize;
+
+ MaxOptionRomSize = 0;
+
+ //
+ // Go through bridges to reach all devices
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (!IsListEmpty (&Temp->ChildList)) {
+
+ //
+ // Get max option rom size under this bridge
+ //
+ TempOptionRomSize = GetMaxOptionRomSize (Temp);
+
+ //
+ // Compare with the option rom size of the bridge
+ // Get the larger one
+ //
+ if (Temp->RomSize > TempOptionRomSize) {
+ TempOptionRomSize = Temp->RomSize;
+ }
+
+ } else {
+
+ //
+ // For devices get the rom size directly
+ //
+ TempOptionRomSize = Temp->RomSize;
+ }
+
+ //
+ // Get the largest rom size on this bridge
+ //
+ if (TempOptionRomSize > MaxOptionRomSize) {
+ MaxOptionRomSize = TempOptionRomSize;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return MaxOptionRomSize;
+}
+
+/**
+ Process attributes of devices on this host bridge
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully process attribute.
+ @retval EFI_NOT_FOUND Can not find the specific root bridge device.
+ @retval other Failed to determine the root bridge device's attribute.
+
+**/
+EFI_STATUS
+PciHostBridgeDeviceAttribute (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+
+ RootBridgeHandle = NULL;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set the attributes for devcies behind the Root Bridge
+ //
+ Status = DetermineDeviceAttribute (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource allocation status from the ACPI resource descriptor.
+
+ @param AcpiConfig Point to Acpi configuration table.
+ @param IoResStatus Return the status of I/O resource.
+ @param Mem32ResStatus Return the status of 32-bit Memory resource.
+ @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource.
+ @param Mem64ResStatus Return the status of 64-bit Memory resource.
+ @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource.
+
+**/
+VOID
+GetResourceAllocationStatus (
+ VOID *AcpiConfig,
+ OUT UINT64 *IoResStatus,
+ OUT UINT64 *Mem32ResStatus,
+ OUT UINT64 *PMem32ResStatus,
+ OUT UINT64 *Mem64ResStatus,
+ OUT UINT64 *PMem64ResStatus
+ )
+{
+ UINT8 *Temp;
+ UINT64 ResStatus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ACPIAddressDesc;
+
+ Temp = (UINT8 *) AcpiConfig;
+
+ while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+
+ ACPIAddressDesc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = ACPIAddressDesc->AddrTranslationOffset;
+
+ switch (ACPIAddressDesc->ResType) {
+ case 0:
+ if (ACPIAddressDesc->AddrSpaceGranularity == 32) {
+ if (ACPIAddressDesc->SpecificFlag == 0x06) {
+ //
+ // Pmem32
+ //
+ *PMem32ResStatus = ResStatus;
+ } else {
+ //
+ // Mem32
+ //
+ *Mem32ResStatus = ResStatus;
+ }
+ }
+
+ if (ACPIAddressDesc->AddrSpaceGranularity == 64) {
+ if (ACPIAddressDesc->SpecificFlag == 0x06) {
+ //
+ // PMem64
+ //
+ *PMem64ResStatus = ResStatus;
+ } else {
+ //
+ // Mem64
+ //
+ *Mem64ResStatus = ResStatus;
+ }
+ }
+
+ break;
+
+ case 1:
+ //
+ // Io
+ //
+ *IoResStatus = ResStatus;
+ break;
+
+ default:
+ break;
+ }
+
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+}
+
+/**
+ Remove a PCI device from device pool and mark its bar.
+
+ @param PciDevice Instance of Pci device.
+
+ @retval EFI_SUCCESS Successfully remove the PCI device.
+ @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
+
+**/
+EFI_STATUS
+RejectPciDevice (
+ IN PCI_IO_DEVICE *PciDevice
+ )
+{
+ PCI_IO_DEVICE *Bridge;
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // Remove the padding resource from a bridge
+ //
+ if ( IS_PCI_BRIDGE(&PciDevice->Pci) &&
+ PciDevice->ResourcePaddingDescriptors != NULL ) {
+ FreePool (PciDevice->ResourcePaddingDescriptors);
+ PciDevice->ResourcePaddingDescriptors = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip RB and PPB
+ //
+ if (IS_PCI_BRIDGE (&PciDevice->Pci) || (PciDevice->Parent == NULL)) {
+ return EFI_ABORTED;
+ }
+
+ if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) {
+ //
+ // Get the root bridge device
+ //
+ Bridge = PciDevice;
+ while (Bridge->Parent != NULL) {
+ Bridge = Bridge->Parent;
+ }
+
+ RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice);
+
+ //
+ // Mark its bar
+ //
+ InitializeP2C (PciDevice);
+ }
+
+ //
+ // Remove the device
+ //
+ Bridge = PciDevice->Parent;
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (Temp == PciDevice) {
+ InitializePciDevice (Temp);
+ RemoveEntryList (CurrentLink);
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ Determine whethter a PCI device can be rejected.
+
+ @param PciResNode Pointer to Pci resource node instance.
+
+ @retval TRUE The PCI device can be rejected.
+ @retval TRUE The PCI device cannot be rejected.
+
+**/
+BOOLEAN
+IsRejectiveDevice (
+ IN PCI_RESOURCE_NODE *PciResNode
+ )
+{
+ PCI_IO_DEVICE *Temp;
+
+ Temp = PciResNode->PciDev;
+
+ //
+ // Ensure the device is present
+ //
+ if (Temp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // PPB and RB should go ahead
+ //
+ if (IS_PCI_BRIDGE (&Temp->Pci) || (Temp->Parent == NULL)) {
+ return TRUE;
+ }
+
+ //
+ // Skip device on Bus0
+ //
+ if ((Temp->Parent != NULL) && (Temp->BusNumber == 0)) {
+ return FALSE;
+ }
+
+ //
+ // Skip VGA
+ //
+ if (IS_PCI_VGA (&Temp->Pci)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Compare two resource nodes and get the larger resource consumer.
+
+ @param PciResNode1 resource node 1 want to be compared
+ @param PciResNode2 resource node 2 want to be compared
+
+ @return Larger resource node.
+
+**/
+PCI_RESOURCE_NODE *
+GetLargerConsumerDevice (
+ IN PCI_RESOURCE_NODE *PciResNode1,
+ IN PCI_RESOURCE_NODE *PciResNode2
+ )
+{
+ if (PciResNode2 == NULL) {
+ return PciResNode1;
+ }
+
+ if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || (PciResNode2->PciDev->Parent == NULL)) \
+ && (PciResNode2->ResourceUsage != PciResUsagePadding) )
+ {
+ return PciResNode1;
+ }
+
+ if (PciResNode1 == NULL) {
+ return PciResNode2;
+ }
+
+ if ((PciResNode1->Length) > (PciResNode2->Length)) {
+ return PciResNode1;
+ }
+
+ return PciResNode2;
+}
+
+
+/**
+ Get the max resource consumer in the host resource pool.
+
+ @param ResPool Pointer to resource pool node.
+
+ @return The max resource consumer in the host resource pool.
+
+**/
+PCI_RESOURCE_NODE *
+GetMaxResourceConsumerDevice (
+ IN PCI_RESOURCE_NODE *ResPool
+ )
+{
+ PCI_RESOURCE_NODE *Temp;
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *PciResNode;
+ PCI_RESOURCE_NODE *PPBResNode;
+
+ PciResNode = NULL;
+
+ CurrentLink = ResPool->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &ResPool->ChildList) {
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (!IsRejectiveDevice (Temp)) {
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+ }
+
+ if ((IS_PCI_BRIDGE (&(Temp->PciDev->Pci)) || (Temp->PciDev->Parent == NULL)) \
+ && (Temp->ResourceUsage != PciResUsagePadding))
+ {
+ PPBResNode = GetMaxResourceConsumerDevice (Temp);
+ PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode);
+ } else {
+ PciResNode = GetLargerConsumerDevice (PciResNode, Temp);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return PciResNode;
+}
+
+/**
+ Adjust host bridge allocation so as to reduce resource requirement
+
+ @param IoPool Pointer to instance of I/O resource Node.
+ @param Mem32Pool Pointer to instance of 32-bit memory resource Node.
+ @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node.
+ @param Mem64Pool Pointer to instance of 64-bit memory resource node.
+ @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node.
+ @param IoResStatus Status of I/O resource Node.
+ @param Mem32ResStatus Status of 32-bit memory resource Node.
+ @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node.
+ @param Mem64ResStatus Status of 64-bit memory resource node.
+ @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node.
+
+ @retval EFI_SUCCESS Successfully adjusted resource on host bridge.
+ @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted.
+
+**/
+EFI_STATUS
+PciHostBridgeAdjustAllocation (
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool,
+ IN UINT64 IoResStatus,
+ IN UINT64 Mem32ResStatus,
+ IN UINT64 PMem32ResStatus,
+ IN UINT64 Mem64ResStatus,
+ IN UINT64 PMem64ResStatus
+ )
+{
+ BOOLEAN AllocationAjusted;
+ PCI_RESOURCE_NODE *PciResNode;
+ PCI_RESOURCE_NODE *ResPool[5];
+ PCI_IO_DEVICE *RemovedPciDev[5];
+ UINT64 ResStatus[5];
+ UINTN RemovedPciDevNum;
+ UINTN DevIndex;
+ UINTN ResType;
+ EFI_STATUS Status;
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
+
+ PciResNode = NULL;
+ ZeroMem (RemovedPciDev, 5 * sizeof (PCI_IO_DEVICE *));
+ RemovedPciDevNum = 0;
+
+ ResPool[0] = IoPool;
+ ResPool[1] = Mem32Pool;
+ ResPool[2] = PMem32Pool;
+ ResPool[3] = Mem64Pool;
+ ResPool[4] = PMem64Pool;
+
+ ResStatus[0] = IoResStatus;
+ ResStatus[1] = Mem32ResStatus;
+ ResStatus[2] = PMem32ResStatus;
+ ResStatus[3] = Mem64ResStatus;
+ ResStatus[4] = PMem64ResStatus;
+
+ AllocationAjusted = FALSE;
+
+ for (ResType = 0; ResType < 5; ResType++) {
+
+ if (ResStatus[ResType] == EFI_RESOURCE_SATISFIED) {
+ continue;
+ }
+
+ if (ResStatus[ResType] == EFI_RESOURCE_NOT_SATISFIED) {
+ //
+ // Host bridge hasn't this resource type
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Hostbridge hasn't enough resource
+ //
+ PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]);
+ if (PciResNode == NULL) {
+ continue;
+ }
+
+ //
+ // Check if the device has been removed before
+ //
+ for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) {
+ if (PciResNode->PciDev == RemovedPciDev[DevIndex]) {
+ break;
+ }
+ }
+
+ if (DevIndex != RemovedPciDevNum) {
+ continue;
+ }
+
+ //
+ // Remove the device if it isn't in the array
+ //
+ Status = RejectPciDevice (PciResNode->PciDev);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "PciBus: [%02x|%02x|%02x] was rejected due to resource confliction.\n",
+ PciResNode->PciDev->BusNumber, PciResNode->PciDev->DeviceNumber, PciResNode->PciDev->FunctionNumber
+ ));
+
+ //
+ // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
+ //
+ //
+ // Have no way to get ReqRes, AllocRes & Bar here
+ //
+ ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
+ AllocFailExtendedData.DevicePathSize = (UINT16) sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ AllocFailExtendedData.DevicePath = (UINT8 *) PciResNode->PciDev->DevicePath;
+ AllocFailExtendedData.Bar = PciResNode->Bar;
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
+ (VOID *) &AllocFailExtendedData,
+ sizeof (AllocFailExtendedData)
+ );
+
+ //
+ // Add it to the array and indicate at least a device has been rejected
+ //
+ RemovedPciDev[RemovedPciDevNum++] = PciResNode->PciDev;
+ AllocationAjusted = TRUE;
+ }
+ }
+ //
+ // End for
+ //
+
+ if (AllocationAjusted) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_ABORTED;
+ }
+}
+
+/**
+ Summary requests for all resource type, and construct ACPI resource
+ requestor instance.
+
+ @param Bridge detecting bridge
+ @param IoNode Pointer to instance of I/O resource Node
+ @param Mem32Node Pointer to instance of 32-bit memory resource Node
+ @param PMem32Node Pointer to instance of 32-bit Pmemory resource node
+ @param Mem64Node Pointer to instance of 64-bit memory resource node
+ @param PMem64Node Pointer to instance of 64-bit Pmemory resource node
+ @param Config Output buffer holding new constructed APCI resource requestor
+
+ @retval EFI_SUCCESS Successfully constructed ACPI resource.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+
+**/
+EFI_STATUS
+ConstructAcpiResourceRequestor (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node,
+ OUT VOID **Config
+ )
+{
+ UINT8 NumConfig;
+ UINT8 Aperture;
+ UINT8 *Configuration;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;
+
+ NumConfig = 0;
+ Aperture = 0;
+
+ *Config = NULL;
+
+ //
+ // if there is io request, add to the io aperture
+ //
+ if (ResourceRequestExisted (IoNode)) {
+ NumConfig++;
+ Aperture |= 0x01;
+ }
+
+ //
+ // if there is mem32 request, add to the mem32 aperture
+ //
+ if (ResourceRequestExisted (Mem32Node)) {
+ NumConfig++;
+ Aperture |= 0x02;
+ }
+
+ //
+ // if there is pmem32 request, add to the pmem32 aperture
+ //
+ if (ResourceRequestExisted (PMem32Node)) {
+ NumConfig++;
+ Aperture |= 0x04;
+ }
+
+ //
+ // if there is mem64 request, add to the mem64 aperture
+ //
+ if (ResourceRequestExisted (Mem64Node)) {
+ NumConfig++;
+ Aperture |= 0x08;
+ }
+
+ //
+ // if there is pmem64 request, add to the pmem64 aperture
+ //
+ if (ResourceRequestExisted (PMem64Node)) {
+ NumConfig++;
+ Aperture |= 0x10;
+ }
+
+ if (NumConfig != 0) {
+
+ //
+ // If there is at least one type of resource request,
+ // allocate a acpi resource node
+ //
+ Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+
+ //
+ // Deal with io aperture
+ //
+ if ((Aperture & 0x01) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ //
+ // Io
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ //
+ // non ISA range
+ //
+ Ptr->SpecificFlag = 1;
+ Ptr->AddrLen = IoNode->Length;
+ Ptr->AddrRangeMax = IoNode->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with mem32 aperture
+ //
+ if ((Aperture & 0x02) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // Nonprefechable
+ //
+ Ptr->SpecificFlag = 0;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ Ptr->AddrLen = Mem32Node->Length;
+ Ptr->AddrRangeMax = Mem32Node->Alignment;
+
+ Ptr++;
+ }
+
+ //
+ // Deal with Pmem32 aperture
+ //
+ if ((Aperture & 0x04) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x6;
+ //
+ // 32 bit
+ //
+ Ptr->AddrSpaceGranularity = 32;
+ Ptr->AddrLen = PMem32Node->Length;
+ Ptr->AddrRangeMax = PMem32Node->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with mem64 aperture
+ //
+ if ((Aperture & 0x08) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // nonprefechable
+ //
+ Ptr->SpecificFlag = 0;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ Ptr->AddrLen = Mem64Node->Length;
+ Ptr->AddrRangeMax = Mem64Node->Alignment;
+
+ Ptr++;
+ }
+ //
+ // Deal with Pmem64 aperture
+ //
+ if ((Aperture & 0x10) != 0) {
+ Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Ptr->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ //
+ // Mem
+ //
+ Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // prefechable
+ //
+ Ptr->SpecificFlag = 0x06;
+ //
+ // 64 bit
+ //
+ Ptr->AddrSpaceGranularity = 64;
+ Ptr->AddrLen = PMem64Node->Length;
+ Ptr->AddrRangeMax = PMem64Node->Alignment;
+
+ Ptr++;
+ }
+
+ //
+ // put the checksum
+ //
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr;
+
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+
+ } else {
+
+ //
+ // If there is no resource request
+ //
+ Configuration = AllocateZeroPool (sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration);
+ PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;
+ PtrEnd->Checksum = 0;
+ }
+
+ *Config = Configuration;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource base from an acpi configuration descriptor.
+
+ @param Config An acpi configuration descriptor.
+ @param IoBase Output of I/O resource base address.
+ @param Mem32Base Output of 32-bit memory base address.
+ @param PMem32Base Output of 32-bit prefetchable memory base address.
+ @param Mem64Base Output of 64-bit memory base address.
+ @param PMem64Base Output of 64-bit prefetchable memory base address.
+
+**/
+VOID
+GetResourceBase (
+ IN VOID *Config,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ )
+{
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ UINT64 ResStatus;
+
+ ASSERT (Config != NULL);
+
+ *IoBase = 0xFFFFFFFFFFFFFFFFULL;
+ *Mem32Base = 0xFFFFFFFFFFFFFFFFULL;
+ *PMem32Base = 0xFFFFFFFFFFFFFFFFULL;
+ *Mem64Base = 0xFFFFFFFFFFFFFFFFULL;
+ *PMem64Base = 0xFFFFFFFFFFFFFFFFULL;
+
+ Temp = (UINT8 *) Config;
+
+ while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = Ptr->AddrTranslationOffset;
+
+ if (ResStatus == EFI_RESOURCE_SATISFIED) {
+
+ switch (Ptr->ResType) {
+
+ //
+ // Memory type aperture
+ //
+ case 0:
+
+ //
+ // Check to see the granularity
+ //
+ if (Ptr->AddrSpaceGranularity == 32) {
+ if ((Ptr->SpecificFlag & 0x06) != 0) {
+ *PMem32Base = Ptr->AddrRangeMin;
+ } else {
+ *Mem32Base = Ptr->AddrRangeMin;
+ }
+ }
+
+ if (Ptr->AddrSpaceGranularity == 64) {
+ if ((Ptr->SpecificFlag & 0x06) != 0) {
+ *PMem64Base = Ptr->AddrRangeMin;
+ } else {
+ *Mem64Base = Ptr->AddrRangeMin;
+ }
+ }
+ break;
+
+ case 1:
+
+ //
+ // Io type aperture
+ //
+ *IoBase = Ptr->AddrRangeMin;
+ break;
+
+ default:
+ break;
+
+ }
+ //
+ // End switch
+ //
+ }
+ //
+ // End for
+ //
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+}
+
+/**
+ Enumerate pci bridge, allocate resource and determine attribute
+ for devices on this bridge.
+
+ @param BridgeDev Pointer to instance of bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated PCI bridge.
+ @retval other Failed to enumerate.
+
+**/
+EFI_STATUS
+PciBridgeEnumerator (
+ IN PCI_IO_DEVICE *BridgeDev
+ )
+{
+ UINT8 SubBusNumber;
+ UINT8 StartBusNumber;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ SubBusNumber = 0;
+ StartBusNumber = 0;
+ PciIo = &(BridgeDev->PciIo);
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &StartBusNumber);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciAssignBusNumber (
+ BridgeDev,
+ StartBusNumber,
+ &SubBusNumber
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciPciDeviceInfoCollector (BridgeDev, StartBusNumber);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciBridgeResourceAllocator (BridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DetermineDeviceAttribute (BridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Allocate all kinds of resource for PCI bridge.
+
+ @param Bridge Pointer to bridge instance.
+
+ @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
+ @retval other Failed to allocate resource for bridge.
+
+**/
+EFI_STATUS
+PciBridgeResourceAllocator (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ UINT64 IoBase;
+ UINT64 Mem32Base;
+ UINT64 PMem32Base;
+ UINT64 Mem64Base;
+ UINT64 PMem64Base;
+ EFI_STATUS Status;
+
+ IoBridge = CreateResourceNode (
+ Bridge,
+ 0,
+ Bridge->BridgeIoAlignment,
+ 0,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ Bridge,
+ 0,
+ 0xFFFFF,
+ 0,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Create resourcemap by going through all the devices subject to this root bridge
+ //
+ CreateResourceMap (
+ Bridge,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ Status = GetResourceBaseFromBridge (
+ Bridge,
+ &IoBase,
+ &Mem32Base,
+ &PMem32Base,
+ &Mem64Base,
+ &PMem64Base
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Program IO resources
+ //
+ ProgramResource (
+ IoBase,
+ IoBridge
+ );
+
+ //
+ // Program Mem32 resources
+ //
+ ProgramResource (
+ Mem32Base,
+ Mem32Bridge
+ );
+
+ //
+ // Program PMem32 resources
+ //
+ ProgramResource (
+ PMem32Base,
+ PMem32Bridge
+ );
+
+ //
+ // Program Mem64 resources
+ //
+ ProgramResource (
+ Mem64Base,
+ Mem64Bridge
+ );
+
+ //
+ // Program PMem64 resources
+ //
+ ProgramResource (
+ PMem64Base,
+ PMem64Bridge
+ );
+
+ DestroyResourceTree (IoBridge);
+ DestroyResourceTree (Mem32Bridge);
+ DestroyResourceTree (PMem32Bridge);
+ DestroyResourceTree (PMem64Bridge);
+ DestroyResourceTree (Mem64Bridge);
+
+ gBS->FreePool (IoBridge);
+ gBS->FreePool (Mem32Bridge);
+ gBS->FreePool (PMem32Bridge);
+ gBS->FreePool (PMem64Bridge);
+ gBS->FreePool (Mem64Bridge);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get resource base address for a pci bridge device.
+
+ @param Bridge Given Pci driver instance.
+ @param IoBase Output for base address of I/O type resource.
+ @param Mem32Base Output for base address of 32-bit memory type resource.
+ @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource.
+ @param Mem64Base Output for base address of 64-bit memory type resource.
+ @param PMem64Base Output for base address of 64-bit Pmemory type resource.
+
+ @retval EFI_SUCCESS Successfully got resource base address.
+ @retval EFI_OUT_OF_RESOURCES PCI bridge is not available.
+
+**/
+EFI_STATUS
+GetResourceBaseFromBridge (
+ IN PCI_IO_DEVICE *Bridge,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ )
+{
+ if (!Bridge->Allocated) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *IoBase = gAllOne;
+ *Mem32Base = gAllOne;
+ *PMem32Base = gAllOne;
+ *Mem64Base = gAllOne;
+ *PMem64Base = gAllOne;
+
+ if (IS_PCI_BRIDGE (&Bridge->Pci)) {
+
+ if (Bridge->PciBar[PPB_IO_RANGE].Length > 0) {
+ *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_MEM32_RANGE].Length > 0) {
+ *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_PMEM32_RANGE].Length > 0) {
+ *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress;
+ }
+
+ if (Bridge->PciBar[PPB_PMEM64_RANGE].Length > 0) {
+ *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress;
+ } else {
+ *PMem64Base = gAllOne;
+ }
+
+ }
+
+ if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) {
+ if (Bridge->PciBar[P2C_IO_1].Length > 0) {
+ *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress;
+ } else {
+ if (Bridge->PciBar[P2C_IO_2].Length > 0) {
+ *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress;
+ }
+ }
+
+ if (Bridge->PciBar[P2C_MEM_1].Length > 0) {
+ if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypePMem32) {
+ *PMem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
+ }
+
+ if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypeMem32) {
+ *Mem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
+ }
+ }
+
+ if (Bridge->PciBar[P2C_MEM_2].Length > 0) {
+ if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypePMem32) {
+ *PMem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
+ }
+
+ if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypeMem32) {
+ *Mem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ These are the notifications from the PCI bus driver that it is about to enter a certain
+ phase of the PCI enumeration process.
+
+ This member function can be used to notify the host bridge driver to perform specific actions,
+ including any chipset-specific initialization, so that the chipset is ready to enter the next phase.
+ Eight notification points are defined at this time. See belows:
+ EfiPciHostBridgeBeginEnumeration Resets the host bridge PCI apertures and internal data
+ structures. The PCI enumerator should issue this notification
+ before starting a fresh enumeration process. Enumeration cannot
+ be restarted after sending any other notification such as
+ EfiPciHostBridgeBeginBusAllocation.
+ EfiPciHostBridgeBeginBusAllocation The bus allocation phase is about to begin. No specific action is
+ required here. This notification can be used to perform any
+ chipset-specific programming.
+ EfiPciHostBridgeEndBusAllocation The bus allocation and bus programming phase is complete. No
+ specific action is required here. This notification can be used to
+ perform any chipset-specific programming.
+ EfiPciHostBridgeBeginResourceAllocation
+ The resource allocation phase is about to begin. No specific
+ action is required here. This notification can be used to perform
+ any chipset-specific programming.
+ EfiPciHostBridgeAllocateResources Allocates resources per previously submitted requests for all the PCI
+ root bridges. These resource settings are returned on the next call to
+ GetProposedResources(). Before calling NotifyPhase() with a Phase of
+ EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible
+ for gathering I/O and memory requests for
+ all the PCI root bridges and submitting these requests using
+ SubmitResources(). This function pads the resource amount
+ to suit the root bridge hardware, takes care of dependencies between
+ the PCI root bridges, and calls the Global Coherency Domain (GCD)
+ with the allocation request. In the case of padding, the allocated range
+ could be bigger than what was requested.
+ EfiPciHostBridgeSetResources Programs the host bridge hardware to decode previously allocated
+ resources (proposed resources) for all the PCI root bridges. After the
+ hardware is programmed, reassigning resources will not be supported.
+ The bus settings are not affected.
+ EfiPciHostBridgeFreeResources Deallocates resources that were previously allocated for all the PCI
+ root bridges and resets the I/O and memory apertures to their initial
+ state. The bus settings are not affected. If the request to allocate
+ resources fails, the PCI enumerator can use this notification to
+ deallocate previous resources, adjust the requests, and retry
+ allocation.
+ EfiPciHostBridgeEndResourceAllocation The resource allocation phase is completed. No specific action is
+ required here. This notification can be used to perform any chipsetspecific
+ programming.
+
+ @param[in] PciResAlloc The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param[in] Phase The phase during enumeration
+
+ @retval EFI_NOT_READY This phase cannot be entered at this time. For example, this error
+ is valid for a Phase of EfiPciHostBridgeAllocateResources if
+ SubmitResources() has not been called for one or more
+ PCI root bridges before this call
+ @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. This error is valid
+ for a Phase of EfiPciHostBridgeSetResources.
+ @retval EFI_INVALID_PARAMETER Invalid phase parameter
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the
+ previously submitted resource requests cannot be fulfilled or
+ were only partially fulfilled.
+ @retval EFI_SUCCESS The notification was accepted without any errors.
+
+**/
+EFI_STATUS
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ EFI_HANDLE HostBridgeHandle;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_STATUS Status;
+
+ HostBridgeHandle = NULL;
+ RootBridgeHandle = NULL;
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Get Host Bridge Handle.
+ //
+ PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->HandleProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+
+ //
+ // Call PlatformPci::PlatformNotify() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformNotify (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetEntry
+ );
+ } else if (gPciOverrideProtocol != NULL){
+ //
+ // Get Host Bridge Handle.
+ //
+ PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->HandleProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+
+ //
+ // Call PlatformPci::PhaseNotify() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformNotify (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetEntry
+ );
+ }
+
+ Status = PciResAlloc->NotifyPhase (
+ PciResAlloc,
+ Phase
+ );
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PlatformNotify() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformNotify (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetExit
+ );
+
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PhaseNotify() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformNotify (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ Phase,
+ ChipsetExit
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various
+ stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual
+ PCI controllers before enumeration.
+
+ This function is called during the PCI enumeration process. No specific action is expected from this
+ member function. It allows the host bridge driver to preinitialize individual PCI controllers before
+ enumeration.
+
+ @param Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Bus The bus number of the pci device.
+ @param Device The device number of the pci device.
+ @param Func The function number of the pci device.
+ @param Phase The phase of the PCI device enumeration.
+
+ @retval EFI_SUCCESS The requested parameters were returned.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle.
+ @retval EFI_INVALID_PARAMETER Phase is not a valid phase that is defined in
+ EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
+ @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. The PCI enumerator should
+ not enumerate this device, including its child devices if it is a PCI-to-PCI
+ bridge.
+
+**/
+EFI_STATUS
+PreprocessController (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_HANDLE HostBridgeHandle;
+ EFI_STATUS Status;
+
+ //
+ // Get the host bridge handle
+ //
+ HostBridgeHandle = Bridge->PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get the pci host bridge resource allocation protocol
+ //
+ Status = gBS->OpenProtocol (
+ HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ (VOID **) &PciResAlloc,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Root Brige Handle
+ //
+ while (Bridge->Parent != NULL) {
+ Bridge = Bridge->Parent;
+ }
+
+ RootBridgeHandle = Bridge->Handle;
+
+ RootBridgePciAddress.Register = 0;
+ RootBridgePciAddress.Function = Func;
+ RootBridgePciAddress.Device = Device;
+ RootBridgePciAddress.Bus = Bus;
+ RootBridgePciAddress.ExtendedRegister = 0;
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformPrepController (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetEntry
+ );
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformPrepController (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetEntry
+ );
+ }
+
+ Status = PciResAlloc->PreprocessController (
+ PciResAlloc,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase
+ );
+
+ if (gPciPlatformProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciPlatformProtocol->PlatformPrepController (
+ gPciPlatformProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetExit
+ );
+ } else if (gPciOverrideProtocol != NULL) {
+ //
+ // Call PlatformPci::PrepController() if the protocol is present.
+ //
+ gPciOverrideProtocol->PlatformPrepController (
+ gPciOverrideProtocol,
+ HostBridgeHandle,
+ RootBridgeHandle,
+ RootBridgePciAddress,
+ Phase,
+ ChipsetExit
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has
+ happened on the hot-plug controller. Currently, the operations include add operation and remove operation..
+
+ @param This A pointer to the hot plug request protocol.
+ @param Operation The operation the PCI bus driver is requested to make.
+ @param Controller The handle of the hot-plug controller.
+ @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device.
+ @param NumberOfChildren The number of child handles.
+ For a add operation, it is an output parameter.
+ For a remove operation, it's an input parameter.
+ @param ChildHandleBuffer The buffer which contains the child handles.
+
+ @retval EFI_INVALID_PARAMETER Operation is not a legal value.
+ Controller is NULL or not a valid handle.
+ NumberOfChildren is NULL.
+ ChildHandleBuffer is NULL while Operation is add.
+ @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices.
+ @retval EFI_NOT_FOUND Can not find bridge according to controller handle.
+ @retval EFI_SUCCESS The handles for the specified device have been created or destroyed
+ as requested, and for an add operation, the new handles are
+ returned in ChildHandleBuffer.
+**/
+EFI_STATUS
+EFIAPI
+PciHotPlugRequestNotify (
+ IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
+ IN EFI_PCI_HOTPLUG_OPERATION Operation,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE * ChildHandleBuffer
+ )
+{
+ PCI_IO_DEVICE *Bridge;
+ PCI_IO_DEVICE *Temp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_STATUS Status;
+
+ //
+ // Check input parameter validity
+ //
+ if ((Controller == NULL) || (NumberOfChildren == NULL)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Operation != EfiPciHotPlugRequestAdd) && (Operation != EfiPciHotplugRequestRemove)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Operation == EfiPciHotPlugRequestAdd){
+ if (ChildHandleBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Operation == EfiPciHotplugRequestRemove) && (*NumberOfChildren != 0)) {
+ if (ChildHandleBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Bridge = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
+
+ //
+ // Get root bridge handle
+ //
+ Temp = Bridge;
+ while (Temp->Parent != NULL) {
+ Temp = Temp->Parent;
+ }
+
+ RootBridgeHandle = Temp->Handle;
+
+ if (Operation == EfiPciHotPlugRequestAdd) {
+ //
+ // Report Status Code to indicate hot plug happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_PCI | EFI_IOB_PC_HOTPLUG),
+ Temp->DevicePath
+ );
+
+ if (NumberOfChildren != NULL) {
+ *NumberOfChildren = 0;
+ }
+
+ if (IsListEmpty (&Bridge->ChildList)) {
+
+ Status = PciBridgeEnumerator (Bridge);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = StartPciDevicesOnBridge (
+ RootBridgeHandle,
+ Bridge,
+ RemainingDevicePath,
+ NumberOfChildren,
+ ChildHandleBuffer
+ );
+
+ return Status;
+ }
+
+ if (Operation == EfiPciHotplugRequestRemove) {
+
+ if (*NumberOfChildren == 0) {
+ //
+ // Remove all devices on the bridge
+ //
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge);
+ return EFI_SUCCESS;
+
+ }
+
+ for (Index = 0; Index < *NumberOfChildren; Index++) {
+ //
+ // De register all the pci device
+ //
+ Status = DeRegisterPciDevice (RootBridgeHandle, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+ //
+ // End for
+ //
+ return EFI_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search hostbridge according to given handle
+
+ @param RootBridgeHandle Host bridge handle.
+
+ @retval TRUE Found host bridge handle.
+ @retval FALSE Not found hot bridge handle.
+
+**/
+BOOLEAN
+SearchHostBridgeHandle (
+ IN EFI_HANDLE RootBridgeHandle
+ )
+{
+ EFI_HANDLE HostBridgeHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Get the rootbridge Io protocol to find the host bridge handle
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ HostBridgeHandle = PciRootBridgeIo->ParentHandle;
+ for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
+ if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Add host bridge handle to global variable for enumerating.
+
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS Successfully added host bridge.
+ @retval EFI_ABORTED Host bridge is NULL, or given host bridge
+ has been in host bridge list.
+
+**/
+EFI_STATUS
+AddHostBridgeEnumerator (
+ IN EFI_HANDLE HostBridgeHandle
+ )
+{
+ UINTN Index;
+
+ if (HostBridgeHandle == NULL) {
+ return EFI_ABORTED;
+ }
+
+ for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
+ if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if (Index < PCI_MAX_HOST_BRIDGE_NUM) {
+ gPciHostBrigeHandles[Index] = HostBridgeHandle;
+ gPciHostBridgeNumber++;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h
new file mode 100644
index 000000000..133454126
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.h
@@ -0,0 +1,515 @@
+/** @file
+ PCI bus enumeration logic function declaration for PCI bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_ENUMERATOR_H_
+#define _EFI_PCI_ENUMERATOR_H_
+
+#include "PciResourceSupport.h"
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ @param Controller Parent controller handle.
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumerator (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE HostBridgeHandle
+ );
+
+/**
+ Enumerate PCI root bridge.
+
+ @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+ @param RootBridgeDev Instance of root bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated root bridge.
+ @retval other Failed to enumerate root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ This routine is used to process all PCI devices' Option Rom
+ on a certain root bridge.
+
+ @param Bridge Given parent's root bridge.
+ @param RomBase Base address of ROM driver loaded from.
+ @param MaxLength Maximum rom size.
+
+**/
+VOID
+ProcessOptionRom (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT64 RomBase,
+ IN UINT64 MaxLength
+ );
+
+/**
+ This routine is used to assign bus number to the given PCI bus system
+
+ @param Bridge Parent root bridge instance.
+ @param StartBusNumber Number of beginning.
+ @param SubBusNumber The number of sub bus.
+
+ @retval EFI_SUCCESS Successfully assigned bus number.
+ @retval EFI_DEVICE_ERROR Failed to assign bus number.
+
+**/
+EFI_STATUS
+PciAssignBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber
+ );
+
+/**
+ This routine is used to determine the root bridge attribute by interfacing
+ the host bridge resource allocation protocol.
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param RootBridgeDev Root bridge instance
+
+ @retval EFI_SUCCESS Successfully got root bridge's attribute.
+ @retval other Failed to get attribute.
+
+**/
+EFI_STATUS
+DetermineRootBridgeAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ Get Max Option Rom size on specified bridge.
+
+ @param Bridge Given bridge device instance.
+
+ @return Max size of option rom needed.
+
+**/
+UINT32
+GetMaxOptionRomSize (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Process attributes of devices on this host bridge
+
+ @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully process attribute.
+ @retval EFI_NOT_FOUND Can not find the specific root bridge device.
+ @retval other Failed to determine the root bridge device's attribute.
+
+**/
+EFI_STATUS
+PciHostBridgeDeviceAttribute (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ Get resource allocation status from the ACPI resource descriptor.
+
+ @param AcpiConfig Point to Acpi configuration table.
+ @param IoResStatus Return the status of I/O resource.
+ @param Mem32ResStatus Return the status of 32-bit Memory resource.
+ @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource.
+ @param Mem64ResStatus Return the status of 64-bit Memory resource.
+ @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource.
+
+**/
+VOID
+GetResourceAllocationStatus (
+ VOID *AcpiConfig,
+ OUT UINT64 *IoResStatus,
+ OUT UINT64 *Mem32ResStatus,
+ OUT UINT64 *PMem32ResStatus,
+ OUT UINT64 *Mem64ResStatus,
+ OUT UINT64 *PMem64ResStatus
+ );
+
+/**
+ Remove a PCI device from device pool and mark its bar.
+
+ @param PciDevice Instance of Pci device.
+
+ @retval EFI_SUCCESS Successfully remove the PCI device.
+ @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
+
+**/
+EFI_STATUS
+RejectPciDevice (
+ IN PCI_IO_DEVICE *PciDevice
+ );
+
+/**
+ Determine whethter a PCI device can be rejected.
+
+ @param PciResNode Pointer to Pci resource node instance.
+
+ @retval TRUE The PCI device can be rejected.
+ @retval TRUE The PCI device cannot be rejected.
+
+**/
+BOOLEAN
+IsRejectiveDevice (
+ IN PCI_RESOURCE_NODE *PciResNode
+ );
+
+/**
+ Compare two resource nodes and get the larger resource consumer.
+
+ @param PciResNode1 resource node 1 want to be compared
+ @param PciResNode2 resource node 2 want to be compared
+
+ @return Larger resource node.
+
+**/
+PCI_RESOURCE_NODE *
+GetLargerConsumerDevice (
+ IN PCI_RESOURCE_NODE *PciResNode1,
+ IN PCI_RESOURCE_NODE *PciResNode2
+ );
+
+/**
+ Get the max resource consumer in the host resource pool.
+
+ @param ResPool Pointer to resource pool node.
+
+ @return The max resource consumer in the host resource pool.
+
+**/
+PCI_RESOURCE_NODE *
+GetMaxResourceConsumerDevice (
+ IN PCI_RESOURCE_NODE *ResPool
+ );
+
+/**
+ Adjust host bridge allocation so as to reduce resource requirement
+
+ @param IoPool Pointer to instance of I/O resource Node.
+ @param Mem32Pool Pointer to instance of 32-bit memory resource Node.
+ @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node.
+ @param Mem64Pool Pointer to instance of 64-bit memory resource node.
+ @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node.
+ @param IoResStatus Status of I/O resource Node.
+ @param Mem32ResStatus Status of 32-bit memory resource Node.
+ @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node.
+ @param Mem64ResStatus Status of 64-bit memory resource node.
+ @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node.
+
+ @retval EFI_SUCCESS Successfully adjusted resource on host bridge.
+ @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted.
+
+**/
+EFI_STATUS
+PciHostBridgeAdjustAllocation (
+ IN PCI_RESOURCE_NODE *IoPool,
+ IN PCI_RESOURCE_NODE *Mem32Pool,
+ IN PCI_RESOURCE_NODE *PMem32Pool,
+ IN PCI_RESOURCE_NODE *Mem64Pool,
+ IN PCI_RESOURCE_NODE *PMem64Pool,
+ IN UINT64 IoResStatus,
+ IN UINT64 Mem32ResStatus,
+ IN UINT64 PMem32ResStatus,
+ IN UINT64 Mem64ResStatus,
+ IN UINT64 PMem64ResStatus
+ );
+
+/**
+ Summary requests for all resource type, and construct ACPI resource
+ requestor instance.
+
+ @param Bridge detecting bridge
+ @param IoNode Pointer to instance of I/O resource Node
+ @param Mem32Node Pointer to instance of 32-bit memory resource Node
+ @param PMem32Node Pointer to instance of 32-bit Pmemory resource node
+ @param Mem64Node Pointer to instance of 64-bit memory resource node
+ @param PMem64Node Pointer to instance of 64-bit Pmemory resource node
+ @param Config Output buffer holding new constructed APCI resource requestor
+
+ @retval EFI_SUCCESS Successfully constructed ACPI resource.
+ @retval EFI_OUT_OF_RESOURCES No memory available.
+
+**/
+EFI_STATUS
+ConstructAcpiResourceRequestor (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node,
+ OUT VOID **Config
+ );
+
+/**
+ Get resource base from an acpi configuration descriptor.
+
+ @param Config An acpi configuration descriptor.
+ @param IoBase Output of I/O resource base address.
+ @param Mem32Base Output of 32-bit memory base address.
+ @param PMem32Base Output of 32-bit prefetchable memory base address.
+ @param Mem64Base Output of 64-bit memory base address.
+ @param PMem64Base Output of 64-bit prefetchable memory base address.
+
+**/
+VOID
+GetResourceBase (
+ IN VOID *Config,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ );
+
+/**
+ Enumerate pci bridge, allocate resource and determine attribute
+ for devices on this bridge.
+
+ @param BridgeDev Pointer to instance of bridge device.
+
+ @retval EFI_SUCCESS Successfully enumerated PCI bridge.
+ @retval other Failed to enumerate.
+
+**/
+EFI_STATUS
+PciBridgeEnumerator (
+ IN PCI_IO_DEVICE *BridgeDev
+ );
+
+/**
+ Allocate all kinds of resource for PCI bridge.
+
+ @param Bridge Pointer to bridge instance.
+
+ @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
+ @retval other Failed to allocate resource for bridge.
+
+**/
+EFI_STATUS
+PciBridgeResourceAllocator (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Get resource base address for a pci bridge device.
+
+ @param Bridge Given Pci driver instance.
+ @param IoBase Output for base address of I/O type resource.
+ @param Mem32Base Output for base address of 32-bit memory type resource.
+ @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource.
+ @param Mem64Base Output for base address of 64-bit memory type resource.
+ @param PMem64Base Output for base address of 64-bit Pmemory type resource.
+
+ @retval EFI_SUCCESS Successfully got resource base address.
+ @retval EFI_OUT_OF_RESOURCES PCI bridge is not available.
+
+**/
+EFI_STATUS
+GetResourceBaseFromBridge (
+ IN PCI_IO_DEVICE *Bridge,
+ OUT UINT64 *IoBase,
+ OUT UINT64 *Mem32Base,
+ OUT UINT64 *PMem32Base,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *PMem64Base
+ );
+
+/**
+ Process Option Rom on this host bridge
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval EFI_SUCCESS Success process.
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ These are the notifications from the PCI bus driver that it is about to enter a certain
+ phase of the PCI enumeration process.
+
+ This member function can be used to notify the host bridge driver to perform specific actions,
+ including any chipset-specific initialization, so that the chipset is ready to enter the next phase.
+ Eight notification points are defined at this time. See belows:
+ EfiPciHostBridgeBeginEnumeration Resets the host bridge PCI apertures and internal data
+ structures. The PCI enumerator should issue this notification
+ before starting a fresh enumeration process. Enumeration cannot
+ be restarted after sending any other notification such as
+ EfiPciHostBridgeBeginBusAllocation.
+ EfiPciHostBridgeBeginBusAllocation The bus allocation phase is about to begin. No specific action is
+ required here. This notification can be used to perform any
+ chipset-specific programming.
+ EfiPciHostBridgeEndBusAllocation The bus allocation and bus programming phase is complete. No
+ specific action is required here. This notification can be used to
+ perform any chipset-specific programming.
+ EfiPciHostBridgeBeginResourceAllocation
+ The resource allocation phase is about to begin. No specific
+ action is required here. This notification can be used to perform
+ any chipset-specific programming.
+ EfiPciHostBridgeAllocateResources Allocates resources per previously submitted requests for all the PCI
+ root bridges. These resource settings are returned on the next call to
+ GetProposedResources(). Before calling NotifyPhase() with a Phase of
+ EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible
+ for gathering I/O and memory requests for
+ all the PCI root bridges and submitting these requests using
+ SubmitResources(). This function pads the resource amount
+ to suit the root bridge hardware, takes care of dependencies between
+ the PCI root bridges, and calls the Global Coherency Domain (GCD)
+ with the allocation request. In the case of padding, the allocated range
+ could be bigger than what was requested.
+ EfiPciHostBridgeSetResources Programs the host bridge hardware to decode previously allocated
+ resources (proposed resources) for all the PCI root bridges. After the
+ hardware is programmed, reassigning resources will not be supported.
+ The bus settings are not affected.
+ EfiPciHostBridgeFreeResources Deallocates resources that were previously allocated for all the PCI
+ root bridges and resets the I/O and memory apertures to their initial
+ state. The bus settings are not affected. If the request to allocate
+ resources fails, the PCI enumerator can use this notification to
+ deallocate previous resources, adjust the requests, and retry
+ allocation.
+ EfiPciHostBridgeEndResourceAllocation The resource allocation phase is completed. No specific action is
+ required here. This notification can be used to perform any chipsetspecific
+ programming.
+
+ @param[in] PciResAlloc The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ @param[in] Phase The phase during enumeration
+
+ @retval EFI_NOT_READY This phase cannot be entered at this time. For example, this error
+ is valid for a Phase of EfiPciHostBridgeAllocateResources if
+ SubmitResources() has not been called for one or more
+ PCI root bridges before this call
+ @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. This error is valid
+ for a Phase of EfiPciHostBridgeSetResources.
+ @retval EFI_INVALID_PARAMETER Invalid phase parameter
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the
+ previously submitted resource requests cannot be fulfilled or
+ were only partially fulfilled.
+ @retval EFI_SUCCESS The notification was accepted without any errors.
+
+**/
+EFI_STATUS
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various
+ stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual
+ PCI controllers before enumeration.
+
+ This function is called during the PCI enumeration process. No specific action is expected from this
+ member function. It allows the host bridge driver to preinitialize individual PCI controllers before
+ enumeration.
+
+ @param Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Bus The bus number of the pci device.
+ @param Device The device number of the pci device.
+ @param Func The function number of the pci device.
+ @param Phase The phase of the PCI device enumeration.
+
+ @retval EFI_SUCCESS The requested parameters were returned.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle.
+ @retval EFI_INVALID_PARAMETER Phase is not a valid phase that is defined in
+ EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
+ @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. The PCI enumerator should
+ not enumerate this device, including its child devices if it is a PCI-to-PCI
+ bridge.
+
+**/
+EFI_STATUS
+PreprocessController (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has
+ happened on the hot-plug controller. Currently, the operations include add operation and remove operation..
+
+ @param This A pointer to the hot plug request protocol.
+ @param Operation The operation the PCI bus driver is requested to make.
+ @param Controller The handle of the hot-plug controller.
+ @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device.
+ @param NumberOfChildren The number of child handles.
+ For a add operation, it is an output parameter.
+ For a remove operation, it's an input parameter.
+ @param ChildHandleBuffer The buffer which contains the child handles.
+
+ @retval EFI_INVALID_PARAMETER Operation is not a legal value.
+ Controller is NULL or not a valid handle.
+ NumberOfChildren is NULL.
+ ChildHandleBuffer is NULL while Operation is add.
+ @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices.
+ @retval EFI_NOT_FOUND Can not find bridge according to controller handle.
+ @retval EFI_SUCCESS The handles for the specified device have been created or destroyed
+ as requested, and for an add operation, the new handles are
+ returned in ChildHandleBuffer.
+**/
+EFI_STATUS
+EFIAPI
+PciHotPlugRequestNotify (
+ IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
+ IN EFI_PCI_HOTPLUG_OPERATION Operation,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL,
+ IN OUT UINT8 *NumberOfChildren,
+ IN OUT EFI_HANDLE * ChildHandleBuffer
+ );
+
+/**
+ Search hostbridge according to given handle
+
+ @param RootBridgeHandle Host bridge handle.
+
+ @retval TRUE Found host bridge handle.
+ @retval FALSE Not found hot bridge handle.
+
+**/
+BOOLEAN
+SearchHostBridgeHandle (
+ IN EFI_HANDLE RootBridgeHandle
+ );
+
+/**
+ Add host bridge handle to global variable for enumerating.
+
+ @param HostBridgeHandle Host bridge handle.
+
+ @retval EFI_SUCCESS Successfully added host bridge.
+ @retval EFI_ABORTED Host bridge is NULL, or given host bridge
+ has been in host bridge list.
+
+**/
+EFI_STATUS
+AddHostBridgeEnumerator (
+ IN EFI_HANDLE HostBridgeHandle
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
new file mode 100644
index 000000000..6c68a97d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
@@ -0,0 +1,2848 @@
+/** @file
+ PCI emumeration support functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+extern CHAR16 *mBarTypeStr[];
+extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
+
+#define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
+#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
+#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
+#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
+
+/**
+ This routine is used to check whether the pci device is present.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Output buffer for PCI device configuration space.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI Func NO.
+
+ @retval EFI_NOT_FOUND PCI device not present.
+ @retval EFI_SUCCESS PCI device is found.
+
+**/
+EFI_STATUS
+PciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ UINT64 Address;
+ EFI_STATUS Status;
+
+ //
+ // Create PCI address map in terms of Bus, Device and Func
+ //
+ Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
+
+ //
+ // Read the Vendor ID register
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ Pci
+ );
+
+ if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {
+ //
+ // Read the entire config header for the device
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ sizeof (PCI_TYPE00) / sizeof (UINT32),
+ Pci
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Collect all the resource information under this root bridge.
+
+ A database that records all the information about pci device subject to this
+ root bridge will then be created.
+
+ @param Bridge Parent bridge instance.
+ @param StartBusNumber Bus number of beginning.
+
+ @retval EFI_SUCCESS PCI device is found.
+ @retval other Some error occurred when reading PCI bridge information.
+
+**/
+EFI_STATUS
+PciPciDeviceInfoCollector (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT8 SecBus;
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ Status = EFI_SUCCESS;
+ SecBus = 0;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether PCI device is present
+ //
+ Status = PciDevicePresent (
+ Bridge->PciRootBridgeIo,
+ &Pci,
+ (UINT8) StartBusNumber,
+ (UINT8) Device,
+ (UINT8) Func
+ );
+
+ if (EFI_ERROR (Status) && Func == 0) {
+ //
+ // go to next device if there is no Function 0
+ //
+ break;
+ }
+
+ if (!EFI_ERROR (Status)) {
+
+ //
+ // Call back to host bridge function
+ //
+ PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);
+
+ //
+ // Collect all the information about the PCI device discovered
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ (UINT8) StartBusNumber,
+ Device,
+ Func,
+ &PciIoDevice
+ );
+
+ //
+ // Recursively scan PCI busses on the other side of PCI-PCI bridges
+ //
+ //
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
+
+ //
+ // If it is PPB, we need to get the secondary bus to continue the enumeration
+ //
+ PciIo = &(PciIoDevice->PciIo);
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Ensure secondary bus number is greater than the primary bus number to avoid
+ // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
+ //
+ if (SecBus <= StartBusNumber) {
+ break;
+ }
+
+ //
+ // Get resource padding for PPB
+ //
+ GetResourcePaddingPpb (PciIoDevice);
+
+ //
+ // Deep enumerate the next level bus
+ //
+ Status = PciPciDeviceInfoCollector (
+ PciIoDevice,
+ (UINT8) (SecBus)
+ );
+
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search required device and create PCI device instance.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI func NO.
+ @param PciDevice Output of searched PCI device instance.
+
+ @retval EFI_SUCCESS Successfully created PCI device instance.
+ @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
+
+**/
+EFI_STATUS
+PciSearchDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ OUT PCI_IO_DEVICE **PciDevice
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = NULL;
+
+ DEBUG ((
+ EFI_D_INFO,
+ "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
+ IS_PCI_BRIDGE (Pci) ? L"PPB" :
+ IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :
+ L"PCI",
+ Bus, Device, Func
+ ));
+
+ if (!IS_PCI_BRIDGE (Pci)) {
+
+ if (IS_CARDBUS_BRIDGE (Pci)) {
+ PciIoDevice = GatherP2CInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+ if ((PciIoDevice != NULL) && gFullEnumeration) {
+ InitializeP2C (PciIoDevice);
+ }
+ } else {
+
+ //
+ // Create private data for Pci Device
+ //
+ PciIoDevice = GatherDeviceInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ }
+
+ } else {
+
+ //
+ // Create private data for PPB
+ //
+ PciIoDevice = GatherPpbInfo (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ //
+ // Special initialization for PPB including making the PPB quiet
+ //
+ if ((PciIoDevice != NULL) && gFullEnumeration) {
+ InitializePpb (PciIoDevice);
+ }
+ }
+
+ if (PciIoDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update the bar information for this PCI device so as to support some specific device
+ //
+ UpdatePciInfo (PciIoDevice);
+
+ if (PciIoDevice->DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Detect this function has option rom
+ //
+ if (gFullEnumeration) {
+
+ if (!IS_CARDBUS_BRIDGE (Pci)) {
+
+ GetOpRomInfo (PciIoDevice);
+
+ }
+
+ ResetPowerManagementFeature (PciIoDevice);
+
+ }
+
+ //
+ // Insert it into a global tree for future reference
+ //
+ InsertPciDevice (Bridge, PciIoDevice);
+
+ //
+ // Determine PCI device attributes
+ //
+
+ if (PciDevice != NULL) {
+ *PciDevice = PciIoDevice;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dump the PPB padding resource information.
+
+ @param PciIoDevice PCI IO instance.
+ @param ResourceType The desired resource type to dump.
+ PciBarTypeUnknown means to dump all types of resources.
+**/
+VOID
+DumpPpbPaddingResource (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN PCI_BAR_TYPE ResourceType
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ PCI_BAR_TYPE Type;
+
+ if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
+ return;
+ }
+
+ if (ResourceType == PciBarTypeIo16 || ResourceType == PciBarTypeIo32) {
+ ResourceType = PciBarTypeIo;
+ }
+
+ for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {
+
+ Type = PciBarTypeUnknown;
+ if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
+ Type = PciBarTypeIo;
+ } else if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+
+ if (Descriptor->AddrSpaceGranularity == 32) {
+ //
+ // prefetchable
+ //
+ if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
+ Type = PciBarTypePMem32;
+ }
+
+ //
+ // Non-prefetchable
+ //
+ if (Descriptor->SpecificFlag == 0) {
+ Type = PciBarTypeMem32;
+ }
+ }
+
+ if (Descriptor->AddrSpaceGranularity == 64) {
+ //
+ // prefetchable
+ //
+ if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
+ Type = PciBarTypePMem64;
+ }
+
+ //
+ // Non-prefetchable
+ //
+ if (Descriptor->SpecificFlag == 0) {
+ Type = PciBarTypeMem64;
+ }
+ }
+ }
+
+ if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) {
+ DEBUG ((
+ EFI_D_INFO,
+ " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
+ mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen
+ ));
+ }
+ }
+
+}
+
+/**
+ Dump the PCI BAR information.
+
+ @param PciIoDevice PCI IO instance.
+**/
+VOID
+DumpPciBars (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+ if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {
+ continue;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
+ Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],
+ PciIoDevice->PciBar[Index].Alignment, PciIoDevice->PciBar[Index].Length, PciIoDevice->PciBar[Index].Offset
+ ));
+ }
+
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+ if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {
+ continue;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
+ Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],
+ PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice->VfPciBar[Index].Length, PciIoDevice->VfPciBar[Index].Offset
+ ));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ Create PCI device instance for PCI device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherDeviceInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ UINTN Offset;
+ UINTN BarIndex;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = CreatePciIoDevice (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ //
+ // If it is a full enumeration, disconnect the device in advance
+ //
+ if (gFullEnumeration) {
+
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ }
+
+ //
+ // Start to parse the bars
+ //
+ for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
+ Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
+ }
+
+ //
+ // Parse the SR-IOV VF bars
+ //
+ if (PcdGetBool (PcdSrIovSupport) && PciIoDevice->SrIovCapabilityOffset != 0) {
+ for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
+ Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
+ BarIndex++) {
+
+ ASSERT (BarIndex < PCI_MAX_BAR);
+ Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
+ }
+ }
+
+ DEBUG_CODE (DumpPciBars (PciIoDevice););
+ return PciIoDevice;
+}
+
+/**
+ Create PCI device instance for PCI-PCI bridge.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherPpbInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_STATUS Status;
+ UINT8 Value;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Temp;
+ UINT32 PMemBaseLimit;
+ UINT16 PrefetchableMemoryBase;
+ UINT16 PrefetchableMemoryLimit;
+
+ PciIoDevice = CreatePciIoDevice (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ if (gFullEnumeration) {
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ //
+ // Initialize the bridge control register
+ //
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
+
+ }
+
+ //
+ // PPB can have two BARs
+ //
+ if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
+ //
+ // Not 64-bit bar
+ //
+ PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
+ }
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Test whether it support 32 decode or not
+ //
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
+
+ if (Value != 0) {
+ if ((Value & 0x01) != 0) {
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
+ } else {
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
+ }
+ }
+
+ //
+ // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
+ // PCI bridge supporting non-standard I/O window alignment less than 4K.
+ //
+
+ PciIoDevice->BridgeIoAlignment = 0xFFF;
+ if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {
+ //
+ // Check any bits of bit 3-1 of I/O Base Register are writable.
+ // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
+ // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
+ //
+ Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
+ Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));
+ switch (Value) {
+ case BIT3:
+ PciIoDevice->BridgeIoAlignment = 0x7FF;
+ break;
+ case BIT3 | BIT2:
+ PciIoDevice->BridgeIoAlignment = 0x3FF;
+ break;
+ case BIT3 | BIT2 | BIT1:
+ PciIoDevice->BridgeIoAlignment = 0x1FF;
+ break;
+ }
+ }
+
+ Status = BarExisted (
+ PciIoDevice,
+ 0x24,
+ NULL,
+ &PMemBaseLimit
+ );
+
+ //
+ // Test if it supports 64 memory or not
+ //
+ // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
+ // registers:
+ // 0 - the bridge supports only 32 bit addresses.
+ // 1 - the bridge supports 64-bit addresses.
+ //
+ PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);
+ PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
+ if (!EFI_ERROR (Status) &&
+ (PrefetchableMemoryBase & 0x000f) == 0x0001 &&
+ (PrefetchableMemoryLimit & 0x000f) == 0x0001) {
+ Status = BarExisted (
+ PciIoDevice,
+ 0x28,
+ NULL,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
+ } else {
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
+ }
+ }
+
+ //
+ // Memory 32 code is required for ppb
+ //
+ PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
+
+ GetResourcePaddingPpb (PciIoDevice);
+
+ DEBUG_CODE (
+ DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);
+ DumpPciBars (PciIoDevice);
+ );
+
+ return PciIoDevice;
+}
+
+
+/**
+ Create PCI device instance for PCI Card bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherP2CInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = CreatePciIoDevice (
+ Bridge,
+ Pci,
+ Bus,
+ Device,
+ Func
+ );
+
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ if (gFullEnumeration) {
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
+
+ //
+ // Initialize the bridge control register
+ //
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
+ }
+
+ //
+ // P2C only has one bar that is in 0x10
+ //
+ PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
+
+ //
+ // Read PciBar information from the bar register
+ //
+ GetBackPcCardBar (PciIoDevice);
+ PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
+ EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
+ EFI_BRIDGE_IO32_DECODE_SUPPORTED;
+
+ DEBUG_CODE (DumpPciBars (PciIoDevice););
+
+ return PciIoDevice;
+}
+
+/**
+ Create device path for pci device.
+
+ @param ParentDevicePath Parent bridge's path.
+ @param PciIoDevice Pci device instance.
+
+ @return Device path protocol instance for specific pci device.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CreatePciDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ PCI_DEVICE_PATH PciNode;
+
+ //
+ // Create PCI device path
+ //
+ PciNode.Header.Type = HARDWARE_DEVICE_PATH;
+ PciNode.Header.SubType = HW_PCI_DP;
+ SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
+
+ PciNode.Device = PciIoDevice->DeviceNumber;
+ PciNode.Function = PciIoDevice->FunctionNumber;
+ PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
+
+ return PciIoDevice->DevicePath;
+}
+
+/**
+ Check whether the PCI IOV VF bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+VfBarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 OriginalValue;
+ UINT32 Value;
+ EFI_TPL OldTpl;
+
+ //
+ // Ensure it is called properly
+ //
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Preserve the original value
+ //
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
+
+ //
+ // Write back the original value
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (BarLengthValue != NULL) {
+ *BarLengthValue = Value;
+ }
+
+ if (OriginalBarValue != NULL) {
+ *OriginalBarValue = OriginalValue;
+ }
+
+ if (Value == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Check whether the bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+BarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 OriginalValue;
+ UINT32 Value;
+ EFI_TPL OldTpl;
+
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Preserve the original value
+ //
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
+
+ //
+ // Write back the original value
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (BarLengthValue != NULL) {
+ *BarLengthValue = Value;
+ }
+
+ if (OriginalBarValue != NULL) {
+ *OriginalBarValue = OriginalValue;
+ }
+
+ if (Value == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Test whether the device can support given attributes.
+
+ @param PciIoDevice Pci device instance.
+ @param Command Input command register value, and
+ returned supported register value.
+ @param BridgeControl Input bridge control value for PPB or P2C, and
+ returned supported bridge control value.
+ @param OldCommand Returned and stored old command register offset.
+ @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
+
+**/
+VOID
+PciTestSupportedAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN OUT UINT16 *Command,
+ IN OUT UINT16 *BridgeControl,
+ OUT UINT16 *OldCommand,
+ OUT UINT16 *OldBridgeControl
+ )
+{
+ EFI_TPL OldTpl;
+
+ //
+ // Preserve the original value
+ //
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
+
+ //
+ // Write back the original value
+ //
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ //
+ // Preserve the original value
+ //
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
+
+ //
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+
+ //
+ // Write back the original value
+ //
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
+
+ //
+ // Restore TPL to its original level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ } else {
+ *OldBridgeControl = 0;
+ *BridgeControl = 0;
+ }
+}
+
+/**
+ Set the supported or current attributes of a PCI device.
+
+ @param PciIoDevice Structure pointer for PCI device.
+ @param Command Command register value.
+ @param BridgeControl Bridge control value for PPB or P2C.
+ @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
+
+**/
+VOID
+PciSetDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT16 BridgeControl,
+ IN UINTN Option
+ )
+{
+ UINT64 Attributes;
+
+ Attributes = 0;
+
+ if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
+ }
+
+ if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
+ }
+
+ if (Option == EFI_SET_SUPPORTS) {
+
+ Attributes |= (UINT64) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
+
+ if (IS_PCI_LPC (&PciIoDevice->Pci)) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
+ Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
+ (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
+ }
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // For bridge, it should support IDE attributes
+ //
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
+
+ if (mReserveVgaAliases) {
+ Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
+ EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
+ } else {
+ Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
+ EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
+ }
+ } else {
+
+ if (IS_PCI_IDE (&PciIoDevice->Pci)) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
+ }
+
+ if (IS_PCI_VGA (&PciIoDevice->Pci)) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
+ Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
+ (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
+ }
+ }
+
+ PciIoDevice->Supports = Attributes;
+ PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
+ EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
+
+ } else {
+ //
+ // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
+ // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
+ // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
+ // fields is not from the the ROM BAR of the PCI controller.
+ //
+ if (!PciIoDevice->EmbeddedRom) {
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
+ }
+ PciIoDevice->Attributes = Attributes;
+ }
+}
+
+/**
+ Determine if the device can support Fast Back to Back attribute.
+
+ @param PciIoDevice Pci device instance.
+ @param StatusIndex Status register value.
+
+ @retval EFI_SUCCESS This device support Fast Back to Back attribute.
+ @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
+
+**/
+EFI_STATUS
+GetFastBackToBackSupport (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 StatusIndex
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT32 StatusRegister;
+
+ //
+ // Read the status register
+ //
+ PciIo = &PciIoDevice->PciIo;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check the Fast B2B bit
+ //
+ if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Process the option ROM for all the children of the specified parent PCI device.
+ It can only be used after the first full Option ROM process.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+ProcessOptionRomLight (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children
+ //
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ ProcessOptionRomLight (Temp);
+ }
+
+ PciRomGetImageMapping (Temp);
+
+ //
+ // The OpRom has already been processed in the first round
+ //
+ Temp->AllOpRomProcessed = TRUE;
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Determine the related attributes of all devices under a Root Bridge.
+
+ @param PciIoDevice PCI device instance.
+
+**/
+EFI_STATUS
+DetermineDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT16 Command;
+ UINT16 BridgeControl;
+ UINT16 OldCommand;
+ UINT16 OldBridgeControl;
+ BOOLEAN FastB2BSupport;
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+ EFI_STATUS Status;
+
+ //
+ // For Root Bridge, just copy it by RootBridgeIo protocol
+ // so as to keep consistent with the actual attribute
+ //
+ if (PciIoDevice->Parent == NULL) {
+ Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ &PciIoDevice->Supports,
+ &PciIoDevice->Attributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Assume the PCI Root Bridge supports DAC
+ //
+ PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
+
+ } else {
+
+ //
+ // Set the attributes to be checked for common PCI devices and PPB or P2C
+ // Since some devices only support part of them, it is better to set the
+ // attribute according to its command or bridge control register
+ //
+ Command = EFI_PCI_COMMAND_IO_SPACE |
+ EFI_PCI_COMMAND_MEMORY_SPACE |
+ EFI_PCI_COMMAND_BUS_MASTER |
+ EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+
+ BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
+
+ //
+ // Test whether the device can support attributes above
+ //
+ PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
+
+ //
+ // Set the supported attributes for specified PCI device
+ //
+ PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
+
+ //
+ // Set the current attributes for specified PCI device
+ //
+ PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
+
+ //
+ // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
+ // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
+ if (!PciIoDevice->IsPciExp) {
+ PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
+ }
+ }
+
+ FastB2BSupport = TRUE;
+
+ //
+ // P2C can not support FB2B on the secondary side
+ //
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ FastB2BSupport = FALSE;
+ }
+
+ //
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children
+ //
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ Status = DetermineDeviceAttribute (Temp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Detect Fast Back to Back support for the device under the bridge
+ //
+ Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
+ if (FastB2BSupport && EFI_ERROR (Status)) {
+ FastB2BSupport = FALSE;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ //
+ // Set or clear Fast Back to Back bit for the whole bridge
+ //
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+
+ Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
+
+ if (EFI_ERROR (Status) || (!FastB2BSupport)) {
+ FastB2BSupport = FALSE;
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
+ } else {
+ PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
+ }
+ }
+
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+ if (FastB2BSupport) {
+ PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
+ } else {
+ PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ }
+ //
+ // End for IsListEmpty
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is used to update the bar information for those incompatible PCI device.
+
+ @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
+ Bar information.
+
+ @retval EFI_SUCCESS Successfully updated bar information.
+ @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
+
+**/
+EFI_STATUS
+UpdatePciInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN BarIndex;
+ BOOLEAN SetFlag;
+ VOID *Configuration;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+
+ Configuration = NULL;
+ Status = EFI_SUCCESS;
+
+ if (gIncompatiblePciDeviceSupport == NULL) {
+ //
+ // It can only be supported after the Incompatible PCI Device
+ // Support Protocol has been installed
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,
+ NULL,
+ (VOID **) &gIncompatiblePciDeviceSupport
+ );
+ }
+ if (Status == EFI_SUCCESS) {
+ //
+ // Check whether the device belongs to incompatible devices from protocol or not
+ // If it is , then get its special requirement in the ACPI table
+ //
+ Status = gIncompatiblePciDeviceSupport->CheckDevice (
+ gIncompatiblePciDeviceSupport,
+ PciIoDevice->Pci.Hdr.VendorId,
+ PciIoDevice->Pci.Hdr.DeviceId,
+ PciIoDevice->Pci.Hdr.RevisionID,
+ PciIoDevice->Pci.Device.SubsystemVendorID,
+ PciIoDevice->Pci.Device.SubsystemID,
+ &Configuration
+ );
+
+ }
+
+ if (EFI_ERROR (Status) || Configuration == NULL ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update PCI device information from the ACPI table
+ //
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+
+ while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
+
+ if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ //
+ // The format is not support
+ //
+ break;
+ }
+
+ for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
+ if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
+ (Ptr->AddrTranslationOffset != MAX_UINT8) &&
+ (Ptr->AddrTranslationOffset != BarIndex)
+ ) {
+ //
+ // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
+ // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
+ // Comparing against MAX_UINT8 is to keep backward compatibility.
+ //
+ continue;
+ }
+
+ SetFlag = FALSE;
+ switch (Ptr->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+
+ //
+ // Make sure the bar is memory type
+ //
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
+ SetFlag = TRUE;
+
+ //
+ // Ignored if granularity is 0.
+ // Ignored if PCI BAR is I/O or 32-bit memory.
+ // If PCI BAR is 64-bit memory and granularity is 32, then
+ // the PCI BAR resource is allocated below 4GB.
+ // If PCI BAR is 64-bit memory and granularity is 64, then
+ // the PCI BAR resource is allocated above 4GB.
+ //
+ if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
+ switch (Ptr->AddrSpaceGranularity) {
+ case 32:
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
+ case 64:
+ PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
+ switch (Ptr->AddrSpaceGranularity) {
+ case 32:
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
+ case 64:
+ PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+
+ //
+ // Make sure the bar is IO type
+ //
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
+ SetFlag = TRUE;
+ }
+ break;
+ }
+
+ if (SetFlag) {
+
+ //
+ // Update the new alignment for the device
+ //
+ SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
+
+ //
+ // Update the new length for the device
+ //
+ if (Ptr->AddrLen != 0) {
+ PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
+ }
+ }
+ }
+
+ Ptr++;
+ }
+
+ FreePool (Configuration);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine will update the alignment with the new alignment.
+ Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
+ backward compatibility.
+
+ @param Alignment Input Old alignment. Output updated alignment.
+ @param NewAlignment New alignment.
+
+**/
+VOID
+SetNewAlign (
+ IN OUT UINT64 *Alignment,
+ IN UINT64 NewAlignment
+ )
+{
+ UINT64 OldAlignment;
+ UINTN ShiftBit;
+
+ //
+ // The new alignment is the same as the original,
+ // so skip it
+ //
+ if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {
+ return ;
+ }
+ //
+ // Check the validity of the parameter
+ //
+ if (NewAlignment != EVEN_ALIGN &&
+ NewAlignment != SQUAD_ALIGN &&
+ NewAlignment != DQUAD_ALIGN ) {
+ *Alignment = NewAlignment;
+ return ;
+ }
+
+ OldAlignment = (*Alignment) + 1;
+ ShiftBit = 0;
+
+ //
+ // Get the first non-zero hex value of the length
+ //
+ while ((OldAlignment & 0x0F) == 0x00) {
+ OldAlignment = RShiftU64 (OldAlignment, 4);
+ ShiftBit += 4;
+ }
+
+ //
+ // Adjust the alignment to even, quad or double quad boundary
+ //
+ if (NewAlignment == EVEN_ALIGN) {
+ if ((OldAlignment & 0x01) != 0) {
+ OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
+ }
+ } else if (NewAlignment == SQUAD_ALIGN) {
+ if ((OldAlignment & 0x03) != 0) {
+ OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
+ }
+ } else if (NewAlignment == DQUAD_ALIGN) {
+ if ((OldAlignment & 0x07) != 0) {
+ OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
+ }
+ }
+
+ //
+ // Update the old value
+ //
+ NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
+ *Alignment = NewAlignment;
+
+ return ;
+}
+
+/**
+ Parse PCI IOV VF bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciIovParseVfBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ )
+{
+ UINT32 Value;
+ UINT32 OriginalValue;
+ UINT32 Mask;
+ EFI_STATUS Status;
+
+ //
+ // Ensure it is called properly
+ //
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {
+ return 0;
+ }
+
+ OriginalValue = 0;
+ Value = 0;
+
+ Status = VfBarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->VfPciBar[BarIndex].Length = 0;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
+
+ //
+ // Scan all the BARs anyway
+ //
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
+ return Offset + 4;
+ }
+
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
+ if ((Value & 0x01) != 0) {
+ //
+ // Device I/Os. Impossible
+ //
+ ASSERT (FALSE);
+ return Offset + 4;
+
+ } else {
+
+ Mask = 0xfffffff0;
+
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ switch (Value & 0x07) {
+
+ //
+ //memory space; anywhere in 32 bit address space
+ //
+ case 0x00:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
+ } else {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
+ }
+
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ //
+ // Adjust Length
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
+ //
+ // Adjust Alignment
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+
+ //
+ // memory space; anywhere in 64 bit address space
+ //
+ case 0x04:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
+ } else {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
+ }
+
+ //
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
+ // is regarded as an extension for the first bar. As a result
+ // the sizing will be conducted on combined 64 bit value
+ // Here just store the masked first 32bit value for future size
+ // calculation
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ //
+ // Increment the offset to point to next DWORD
+ //
+ Offset += 4;
+
+ Status = VfBarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Offset + 4;
+ }
+
+ //
+ // Fix the length to support some special 64 bit BAR
+ //
+ Value |= ((UINT32) -1 << HighBitSet32 (Value));
+
+ //
+ // Calculate the size of 64bit bar
+ //
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
+
+ PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ //
+ // Adjust Length
+ //
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
+ //
+ // Adjust Alignment
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+
+ //
+ // reserved
+ //
+ default:
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
+
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
+ }
+
+ break;
+ }
+ }
+
+ //
+ // Check the length again so as to keep compatible with some special bars
+ //
+ if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
+ }
+
+ //
+ // Increment number of bar
+ //
+ return Offset + 4;
+}
+
+/**
+ Parse PCI bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciParseBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ )
+{
+ UINT32 Value;
+ UINT32 OriginalValue;
+ UINT32 Mask;
+ EFI_STATUS Status;
+
+ OriginalValue = 0;
+ Value = 0;
+
+ Status = BarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->PciBar[BarIndex].Length = 0;
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;
+
+ //
+ // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
+ //
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
+ return Offset + 4;
+ }
+
+ PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
+ if ((Value & 0x01) != 0) {
+ //
+ // Device I/Os
+ //
+ Mask = 0xfffffffc;
+
+ if ((Value & 0xFFFF0000) != 0) {
+ //
+ // It is a IO32 bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
+ PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ } else {
+ //
+ // It is a IO16 bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
+ PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ }
+ //
+ // Workaround. Some platforms implement IO bar with 0 length
+ // Need to treat it as no-bar
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
+ }
+
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ } else {
+
+ Mask = 0xfffffff0;
+
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
+
+ switch (Value & 0x07) {
+
+ //
+ //memory space; anywhere in 32 bit address space
+ //
+ case 0x00:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
+ } else {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
+ }
+
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+ break;
+
+ //
+ // memory space; anywhere in 64 bit address space
+ //
+ case 0x04:
+ if ((Value & 0x08) != 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
+ } else {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
+ }
+
+ //
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
+ // is regarded as an extension for the first bar. As a result
+ // the sizing will be conducted on combined 64 bit value
+ // Here just store the masked first 32bit value for future size
+ // calculation
+ //
+ PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+
+ //
+ // Increment the offset to point to next DWORD
+ //
+ Offset += 4;
+
+ Status = BarExisted (
+ PciIoDevice,
+ Offset,
+ &Value,
+ &OriginalValue
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ //
+ // some device implement MMIO bar with 0 length, need to treat it as no-bar
+ //
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ return Offset + 4;
+ }
+ }
+
+ //
+ // Fix the length to support some special 64 bit BAR
+ //
+ if (Value == 0) {
+ DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
+ Value = (UINT32) -1;
+ } else {
+ Value |= ((UINT32)(-1) << HighBitSet32 (Value));
+ }
+
+ //
+ // Calculate the size of 64bit bar
+ //
+ PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
+
+ PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
+ PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+
+ break;
+
+ //
+ // reserved
+ //
+ default:
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
+ //
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
+ //
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
+ } else {
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
+ }
+ break;
+ }
+ }
+
+ //
+ // Check the length again so as to keep compatible with some special bars
+ //
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;
+ }
+
+ //
+ // Increment number of bar
+ //
+ return Offset + 4;
+}
+
+/**
+ This routine is used to initialize the bar of a PCI device.
+
+ @param PciIoDevice Pci device instance.
+
+ @note It can be called typically when a device is going to be rejected.
+
+**/
+VOID
+InitializePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Offset;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures
+ // Resource base is set to all ones so as to indicate its resource
+ // has not been allocated
+ //
+ for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
+ }
+}
+
+/**
+ This routine is used to initialize the bar of a PCI-PCI Bridge device.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+**/
+VOID
+InitializePpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures including IO16
+ // Io32, pMem32, pMem64 to quiescent state
+ // Resource base all ones, Resource limit all zeros
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
+
+ //
+ // Don't support use io32 as for now
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
+
+ //
+ // Force Interrupt line to zero for cards that come up randomly
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
+}
+
+/**
+ This routine is used to initialize the bar of a PCI Card Bridge device.
+
+ @param PciIoDevice PCI Card bridge device.
+
+**/
+VOID
+InitializeP2C (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &(PciIoDevice->PciIo);
+
+ //
+ // Put all the resource apertures including IO16
+ // Io32, pMem32, pMem64 to quiescent state(
+ // Resource base all ones, Resource limit all zeros
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
+
+ //
+ // Force Interrupt line to zero for cards that come up randomly
+ //
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
+}
+
+/**
+ Authenticate the PCI device by using DeviceSecurityProtocol.
+
+ @param PciIoDevice PCI device.
+
+ @retval EFI_SUCCESS The device passes the authentication.
+ @return not EFI_SUCCESS The device failes the authentication or
+ unexpected error happen during authentication.
+**/
+EFI_STATUS
+AuthenticatePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EDKII_DEVICE_IDENTIFIER DeviceIdentifier;
+ EFI_STATUS Status;
+
+ if (mDeviceSecurityProtocol != NULL) {
+ //
+ // Prepare the parameter
+ //
+ DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
+ CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);
+ DeviceIdentifier.DeviceHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DeviceIdentifier.DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEdkiiDeviceIdentifierTypePciGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Do DeviceAuthentication
+ //
+ Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);
+ //
+ // Always uninstall, because they are only for Authentication.
+ // No need to check return Status.
+ //
+ gBS->UninstallMultipleProtocolInterfaces (
+ DeviceIdentifier.DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ PciIoDevice->DevicePath,
+ &gEdkiiDeviceIdentifierTypePciGuid,
+ &PciIoDevice->PciIo,
+ NULL
+ );
+ return Status;
+ }
+
+ //
+ // Device Security Protocol is not found, just return success
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Create and initialize general PCI I/O device instance for
+ PCI device/bridge device/hotplug bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input Pci information block.
+ @param Bus Device Bus NO.
+ @param Device Device device NO.
+ @param Func Device func NO.
+
+ @return Instance of PCI device. NULL means no instance created.
+
+**/
+PCI_IO_DEVICE *
+CreatePciIoDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
+ if (PciIoDevice == NULL) {
+ return NULL;
+ }
+
+ PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
+ PciIoDevice->Handle = NULL;
+ PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ PciIoDevice->DevicePath = NULL;
+ PciIoDevice->BusNumber = Bus;
+ PciIoDevice->DeviceNumber = Device;
+ PciIoDevice->FunctionNumber = Func;
+ PciIoDevice->Decodes = 0;
+
+ if (gFullEnumeration) {
+ PciIoDevice->Allocated = FALSE;
+ } else {
+ PciIoDevice->Allocated = TRUE;
+ }
+
+ PciIoDevice->Registered = FALSE;
+ PciIoDevice->Attributes = 0;
+ PciIoDevice->Supports = 0;
+ PciIoDevice->BusOverride = FALSE;
+ PciIoDevice->AllOpRomProcessed = FALSE;
+
+ PciIoDevice->IsPciExp = FALSE;
+
+ CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
+
+ //
+ // Initialize the PCI I/O instance structure
+ //
+ InitializePciIoInstance (PciIoDevice);
+ InitializePciDriverOverrideInstance (PciIoDevice);
+ InitializePciLoadFile2 (PciIoDevice);
+ PciIo = &PciIoDevice->PciIo;
+
+ //
+ // Create a device path for this PCI device and store it into its private data
+ //
+ CreatePciDevicePath (
+ Bridge->DevicePath,
+ PciIoDevice
+ );
+
+ //
+ // Detect if PCI Express Device
+ //
+ PciIoDevice->PciExpressCapabilityOffset = 0;
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_PCIEXP,
+ &PciIoDevice->PciExpressCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIoDevice->IsPciExp = TRUE;
+ }
+
+ //
+ // Now we can do the authentication check for the device.
+ //
+ Status = AuthenticatePciDevice (PciIoDevice);
+ //
+ // If authentication fails, skip this device.
+ //
+ if (EFI_ERROR(Status)) {
+ if (PciIoDevice->DevicePath != NULL) {
+ FreePool (PciIoDevice->DevicePath);
+ }
+ FreePool (PciIoDevice);
+ return NULL;
+ }
+
+ if (PcdGetBool (PcdAriSupport)) {
+ //
+ // Check if the device is an ARI device.
+ //
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_ARI,
+ &PciIoDevice->AriCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // We need to enable ARI feature before calculate BusReservation,
+ // because FirstVFOffset and VFStride may change after that.
+ //
+ EFI_PCI_IO_PROTOCOL *ParentPciIo;
+ UINT32 Data32;
+
+ //
+ // Check if its parent supports ARI forwarding.
+ //
+ ParentPciIo = &Bridge->PciIo;
+ ParentPciIo->Pci.Read (
+ ParentPciIo,
+ EfiPciIoWidthUint32,
+ Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
+ 1,
+ &Data32
+ );
+ if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
+ //
+ // ARI forward support in bridge, so enable it.
+ //
+ ParentPciIo->Pci.Read (
+ ParentPciIo,
+ EfiPciIoWidthUint32,
+ Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
+ 1,
+ &Data32
+ );
+ if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
+ Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
+ ParentPciIo->Pci.Write (
+ ParentPciIo,
+ EfiPciIoWidthUint32,
+ Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
+ 1,
+ &Data32
+ );
+ DEBUG ((
+ EFI_D_INFO,
+ " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
+ Bridge->BusNumber,
+ Bridge->DeviceNumber,
+ Bridge->FunctionNumber
+ ));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));
+ }
+ }
+
+ //
+ // Initialization for SR-IOV
+ //
+
+ if (PcdGetBool (PcdSrIovSupport)) {
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_SRIOV,
+ &PciIoDevice->SrIovCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ UINT32 SupportedPageSize;
+ UINT16 VFStride;
+ UINT16 FirstVFOffset;
+ UINT16 Data16;
+ UINT32 PFRid;
+ UINT32 LastVF;
+
+ //
+ // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
+ //
+ if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
+ 1,
+ &Data16
+ );
+ Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
+ 1,
+ &Data16
+ );
+ }
+
+ //
+ // Calculate SystemPageSize
+ //
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
+ 1,
+ &SupportedPageSize
+ );
+ PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);
+ ASSERT (PciIoDevice->SystemPageSize != 0);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
+ 1,
+ &PciIoDevice->SystemPageSize
+ );
+ //
+ // Adjust SystemPageSize for Alignment usage later
+ //
+ PciIoDevice->SystemPageSize <<= 12;
+
+ //
+ // Calculate BusReservation for PCI IOV
+ //
+
+ //
+ // Read First FirstVFOffset, InitialVFs, and VFStride
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
+ 1,
+ &FirstVFOffset
+ );
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
+ 1,
+ &PciIoDevice->InitialVFs
+ );
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
+ 1,
+ &VFStride
+ );
+ //
+ // Calculate LastVF
+ //
+ PFRid = EFI_PCI_RID(Bus, Device, Func);
+ LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
+
+ //
+ // Calculate ReservedBusNum for this PF
+ //
+ PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
+
+ DEBUG ((
+ EFI_D_INFO,
+ " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
+ SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset
+ ));
+ DEBUG ((
+ EFI_D_INFO,
+ " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
+ PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset
+ ));
+ }
+ }
+
+ if (PcdGetBool (PcdMrIovSupport)) {
+ Status = LocatePciExpressCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCIE_CAPABILITY_ID_MRIOV,
+ &PciIoDevice->MrIovCapabilityOffset,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));
+ }
+ }
+
+ //
+ // Initialize the reserved resource list
+ //
+ InitializeListHead (&PciIoDevice->ReservedResourceList);
+
+ //
+ // Initialize the driver list
+ //
+ InitializeListHead (&PciIoDevice->OptionRomDriverList);
+
+ //
+ // Initialize the child list
+ //
+ InitializeListHead (&PciIoDevice->ChildList);
+
+ return PciIoDevice;
+}
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ It is only called on the second start on the same Root Bridge.
+
+ @param Controller Parent bridge handler.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumeratorLight (
+ IN EFI_HANDLE Controller
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ PCI_IO_DEVICE *RootBridgeDev;
+ UINT16 MinBus;
+ UINT16 MaxBus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+
+ MinBus = 0;
+ MaxBus = PCI_MAX_BUS;
+ Descriptors = NULL;
+
+ //
+ // If this root bridge has been already enumerated, then return successfully
+ //
+ if (GetRootBridgeByHandle (Controller) != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Open pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
+
+ //
+ // Create a device node for root bridge device with a NULL host bridge controller handle
+ //
+ RootBridgeDev = CreateRootBridge (Controller);
+
+ if (RootBridgeDev == NULL) {
+ Descriptors++;
+ continue;
+ }
+
+ //
+ // Record the root bridge-io protocol
+ //
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
+
+ Status = PciPciDeviceInfoCollector (
+ RootBridgeDev,
+ (UINT8) MinBus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ //
+ // Remove those PCI devices which are rejected when full enumeration
+ //
+ RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
+
+ //
+ // Process option rom light
+ //
+ ProcessOptionRomLight (RootBridgeDev);
+
+ //
+ // Determine attributes for all devices under this root bridge
+ //
+ DetermineDeviceAttribute (RootBridgeDev);
+
+ //
+ // If successfully, insert the node into device pool
+ //
+ InsertRootBridge (RootBridgeDev);
+ } else {
+
+ //
+ // If unsuccessfully, destroy the entire node
+ //
+ DestroyRootBridge (RootBridgeDev);
+ }
+
+ Descriptors++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get bus range from PCI resource descriptor list.
+
+ @param Descriptors A pointer to the address space descriptor.
+ @param MinBus The min bus returned.
+ @param MaxBus The max bus returned.
+ @param BusRange The bus range returned.
+
+ @retval EFI_SUCCESS Successfully got bus range.
+ @retval EFI_NOT_FOUND Can not find the specific bus.
+
+**/
+EFI_STATUS
+PciGetBusRange (
+ IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
+ OUT UINT16 *MinBus,
+ OUT UINT16 *MaxBus,
+ OUT UINT16 *BusRange
+ )
+{
+ while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ if (MinBus != NULL) {
+ *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
+ }
+
+ if (MaxBus != NULL) {
+ *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
+ }
+
+ if (BusRange != NULL) {
+ *BusRange = (UINT16) (*Descriptors)->AddrLen;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ (*Descriptors)++;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This routine can be used to start the root bridge.
+
+ @param RootBridgeDev Pci device instance.
+
+ @retval EFI_SUCCESS This device started.
+ @retval other Failed to get PCI Root Bridge I/O protocol.
+
+**/
+EFI_STATUS
+StartManagingRootBridge (
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ //
+ // Get the root bridge handle
+ //
+ RootBridgeHandle = RootBridgeDev->Handle;
+ PciRootBridgeIo = NULL;
+
+ //
+ // Get the pci root bridge io protocol
+ //
+ Status = gBS->OpenProtocol (
+ RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &PciRootBridgeIo,
+ gPciBusDriverBinding.DriverBindingHandle,
+ RootBridgeHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ //
+ // Store the PciRootBridgeIo protocol into root bridge private data
+ //
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This routine can be used to check whether a PCI device should be rejected when light enumeration.
+
+ @param PciIoDevice Pci device instance.
+
+ @retval TRUE This device should be rejected.
+ @retval FALSE This device shouldn't be rejected.
+
+**/
+BOOLEAN
+IsPciDeviceRejected (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TestValue;
+ UINT32 OldValue;
+ UINT32 Mask;
+ UINT8 BarOffset;
+
+ //
+ // PPB should be skip!
+ //
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ return FALSE;
+ }
+
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // Only test base registers for P2C
+ //
+ for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
+
+ Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ TestValue = TestValue & Mask;
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ //
+ // The bar isn't programed, so it should be rejected
+ //
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
+ //
+ // Test PCI devices
+ //
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((TestValue & 0x01) != 0) {
+
+ //
+ // IO Bar
+ //
+ Mask = 0xFFFFFFFC;
+ TestValue = TestValue & Mask;
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ return TRUE;
+ }
+
+ } else {
+
+ //
+ // Mem Bar
+ //
+ Mask = 0xFFFFFFF0;
+ TestValue = TestValue & Mask;
+
+ if ((TestValue & 0x07) == 0x04) {
+
+ //
+ // Mem64 or PMem64
+ //
+ BarOffset += sizeof (UINT32);
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+
+ //
+ // Test its high 32-Bit BAR
+ //
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
+ if (TestValue == OldValue) {
+ return TRUE;
+ }
+ }
+
+ } else {
+
+ //
+ // Mem32 or PMem32
+ //
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Reset all bus number from specific bridge.
+
+ @param Bridge Parent specific bridge.
+ @param StartBusNumber Start bus number.
+
+**/
+VOID
+ResetAllPpbBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT32 Register;
+ UINT8 Func;
+ UINT64 Address;
+ UINT8 SecondaryBus;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (EFI_ERROR (Status) && Func == 0) {
+ //
+ // go to next device if there is no Function 0
+ //
+ break;
+ }
+
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
+
+ Register = 0;
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Register
+ );
+ SecondaryBus = (UINT8)(Register >> 8);
+
+ if (SecondaryBus != 0) {
+ ResetAllPpbBusNumber (Bridge, SecondaryBus);
+ }
+
+ //
+ // Reset register 18h, 19h, 1Ah on PCI Bridge
+ //
+ Register &= 0xFF000000;
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Register
+ );
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h
new file mode 100644
index 000000000..d76606c7d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.h
@@ -0,0 +1,470 @@
+/** @file
+ PCI enumeration support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_ENUMERATOR_SUPPORT_H_
+#define _EFI_PCI_ENUMERATOR_SUPPORT_H_
+
+/**
+ This routine is used to check whether the pci device is present.
+
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pci Output buffer for PCI device configuration space.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI Func NO.
+
+ @retval EFI_NOT_FOUND PCI device not present.
+ @retval EFI_SUCCESS PCI device is found.
+
+**/
+EFI_STATUS
+PciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Collect all the resource information under this root bridge.
+
+ A database that records all the information about pci device subject to this
+ root bridge will then be created.
+
+ @param Bridge Parent bridge instance.
+ @param StartBusNumber Bus number of beginning.
+
+ @retval EFI_SUCCESS PCI device is found.
+ @retval other Some error occurred when reading PCI bridge information.
+
+**/
+EFI_STATUS
+PciPciDeviceInfoCollector (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ );
+
+/**
+ Search required device and create PCI device instance.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI bus NO.
+ @param Device PCI device NO.
+ @param Func PCI func NO.
+ @param PciDevice Output of searched PCI device instance.
+
+ @retval EFI_SUCCESS Successfully created PCI device instance.
+ @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
+
+**/
+EFI_STATUS
+PciSearchDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func,
+ OUT PCI_IO_DEVICE **PciDevice
+ );
+
+/**
+ Create PCI device instance for PCI device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherDeviceInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create PCI device instance for PCI-PCI bridge.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherPpbInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create PCI device instance for PCI Card bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input PCI device information block.
+ @param Bus PCI device Bus NO.
+ @param Device PCI device Device NO.
+ @param Func PCI device's func NO.
+
+ @return Created PCI device instance.
+
+**/
+PCI_IO_DEVICE *
+GatherP2CInfo (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ Create device path for pci device.
+
+ @param ParentDevicePath Parent bridge's path.
+ @param PciIoDevice Pci device instance.
+
+ @return Device path protocol instance for specific pci device.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CreatePciDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Check whether the PCI IOV VF bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+VfBarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ );
+
+/**
+ Check whether the bar is existed or not.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param Offset The offset.
+ @param BarLengthValue The bar length value returned.
+ @param OriginalBarValue The original bar value returned.
+
+ @retval EFI_NOT_FOUND The bar doesn't exist.
+ @retval EFI_SUCCESS The bar exist.
+
+**/
+EFI_STATUS
+BarExisted (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ OUT UINT32 *BarLengthValue,
+ OUT UINT32 *OriginalBarValue
+ );
+
+/**
+ Test whether the device can support given attributes.
+
+ @param PciIoDevice Pci device instance.
+ @param Command Input command register value, and
+ returned supported register value.
+ @param BridgeControl Input bridge control value for PPB or P2C, and
+ returned supported bridge control value.
+ @param OldCommand Returned and stored old command register offset.
+ @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
+
+**/
+VOID
+PciTestSupportedAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN OUT UINT16 *Command,
+ IN OUT UINT16 *BridgeControl,
+ OUT UINT16 *OldCommand,
+ OUT UINT16 *OldBridgeControl
+ );
+
+/**
+ Set the supported or current attributes of a PCI device.
+
+ @param PciIoDevice Structure pointer for PCI device.
+ @param Command Command register value.
+ @param BridgeControl Bridge control value for PPB or P2C.
+ @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
+
+**/
+VOID
+PciSetDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT16 Command,
+ IN UINT16 BridgeControl,
+ IN UINTN Option
+ );
+
+/**
+ Determine if the device can support Fast Back to Back attribute.
+
+ @param PciIoDevice Pci device instance.
+ @param StatusIndex Status register value.
+
+ @retval EFI_SUCCESS This device support Fast Back to Back attribute.
+ @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
+
+**/
+EFI_STATUS
+GetFastBackToBackSupport (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 StatusIndex
+ );
+
+/**
+ Determine the related attributes of all devices under a Root Bridge.
+
+ @param PciIoDevice PCI device instance.
+
+**/
+EFI_STATUS
+DetermineDeviceAttribute (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to update the bar information for those incompatible PCI device.
+
+ @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
+ Bar information.
+
+ @retval EFI_SUCCESS Successfully updated bar information.
+ @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
+
+**/
+EFI_STATUS
+UpdatePciInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine will update the alignment with the new alignment.
+
+ @param Alignment Input Old alignment. Output updated alignment.
+ @param NewAlignment New alignment.
+
+**/
+VOID
+SetNewAlign (
+ IN OUT UINT64 *Alignment,
+ IN UINT64 NewAlignment
+ );
+
+/**
+ Parse PCI bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciParseBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ );
+
+/**
+ Parse PCI IOV VF bar information and fill them into PCI device instance.
+
+ @param PciIoDevice Pci device instance.
+ @param Offset Bar offset.
+ @param BarIndex Bar index.
+
+ @return Next bar offset.
+
+**/
+UINTN
+PciIovParseVfBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINTN Offset,
+ IN UINTN BarIndex
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI device.
+
+ @param PciIoDevice Pci device instance.
+
+ @note It can be called typically when a device is going to be rejected.
+
+**/
+VOID
+InitializePciDevice (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI-PCI Bridge device.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+**/
+VOID
+InitializePpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ This routine is used to initialize the bar of a PCI Card Bridge device.
+
+ @param PciIoDevice PCI Card bridge device.
+
+**/
+VOID
+InitializeP2C (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Create and initialize general PCI I/O device instance for
+ PCI device/bridge device/hotplug bridge device.
+
+ @param Bridge Parent bridge instance.
+ @param Pci Input Pci information block.
+ @param Bus Device Bus NO.
+ @param Device Device device NO.
+ @param Func Device func NO.
+
+ @return Instance of PCI device. NULL means no instance created.
+
+**/
+PCI_IO_DEVICE *
+CreatePciIoDevice (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_TYPE00 *Pci,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+/**
+ This routine is used to enumerate entire pci bus system
+ in a given platform.
+
+ It is only called on the second start on the same Root Bridge.
+
+ @param Controller Parent bridge handler.
+
+ @retval EFI_SUCCESS PCI enumeration finished successfully.
+ @retval other Some error occurred when enumerating the pci bus system.
+
+**/
+EFI_STATUS
+PciEnumeratorLight (
+ IN EFI_HANDLE Controller
+ );
+
+/**
+ Get bus range from PCI resource descriptor list.
+
+ @param Descriptors A pointer to the address space descriptor.
+ @param MinBus The min bus returned.
+ @param MaxBus The max bus returned.
+ @param BusRange The bus range returned.
+
+ @retval EFI_SUCCESS Successfully got bus range.
+ @retval EFI_NOT_FOUND Can not find the specific bus.
+
+**/
+EFI_STATUS
+PciGetBusRange (
+ IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
+ OUT UINT16 *MinBus,
+ OUT UINT16 *MaxBus,
+ OUT UINT16 *BusRange
+ );
+
+/**
+ This routine can be used to start the root bridge.
+
+ @param RootBridgeDev Pci device instance.
+
+ @retval EFI_SUCCESS This device started.
+ @retval other Failed to get PCI Root Bridge I/O protocol.
+
+**/
+EFI_STATUS
+StartManagingRootBridge (
+ IN PCI_IO_DEVICE *RootBridgeDev
+ );
+
+/**
+ This routine can be used to check whether a PCI device should be rejected when light enumeration.
+
+ @param PciIoDevice Pci device instance.
+
+ @retval TRUE This device should be rejected.
+ @retval FALSE This device shouldn't be rejected.
+
+**/
+BOOLEAN
+IsPciDeviceRejected (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Reset all bus number from specific bridge.
+
+ @param Bridge Parent specific bridge.
+ @param StartBusNumber Start bus number.
+
+**/
+VOID
+ResetAllPpbBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber
+ );
+
+/**
+ Dump the PPB padding resource information.
+
+ @param PciIoDevice PCI IO instance.
+ @param ResourceType The desired resource type to dump.
+ PciBarTypeUnknown means to dump all types of resources.
+**/
+VOID
+DumpPpbPaddingResource (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN PCI_BAR_TYPE ResourceType
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c
new file mode 100644
index 000000000..0dc8ec23b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c
@@ -0,0 +1,484 @@
+/** @file
+ PCI Hot Plug support functions implementation for PCI Bus module..
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit = NULL;
+EFI_HPC_LOCATION *gPciRootHpcPool = NULL;
+UINTN gPciRootHpcCount = 0;
+ROOT_HPC_DATA *gPciRootHpcData = NULL;
+
+
+/**
+ Event notification function to set Hot Plug controller status.
+
+ @param Event The event that invoke this function.
+ @param Context The calling context, pointer to ROOT_HPC_DATA.
+
+**/
+VOID
+EFIAPI
+PciHPCInitialized (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ROOT_HPC_DATA *HpcData;
+
+ HpcData = (ROOT_HPC_DATA *) Context;
+ HpcData->Initialized = TRUE;
+}
+
+/**
+ Compare two device paths to check if they are exactly same.
+
+ @param DevicePath1 A pointer to the first device path data structure.
+ @param DevicePath2 A pointer to the second device path data structure.
+
+ @retval TRUE They are same.
+ @retval FALSE They are not same.
+
+**/
+BOOLEAN
+EfiCompareDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+
+ Size1 = GetDevicePathSize (DevicePath1);
+ Size2 = GetDevicePathSize (DevicePath2);
+
+ if (Size1 != Size2) {
+ return FALSE;
+ }
+
+ if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check hot plug support and initialize root hot plug private data.
+
+ If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
+ to get PCI Hot Plug controller's information and constructor the root hot plug
+ private data structure.
+
+ @retval EFI_SUCCESS They are same.
+ @retval EFI_UNSUPPORTED No PCI Hot Plug controller on the platform.
+ @retval EFI_OUT_OF_RESOURCES No memory to constructor root hot plug private
+ data structure.
+
+**/
+EFI_STATUS
+InitializeHotPlugSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HPC_LOCATION *HpcList;
+ UINTN HpcCount;
+
+ //
+ // Locate the PciHotPlugInit Protocol
+ // If it doesn't exist, that means there is no
+ // hot plug controller supported on the platform
+ // the PCI Bus driver is running on. HotPlug Support
+ // is an optional feature, so absence of the protocol
+ // won't incur the penalty.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciHotPlugInitProtocolGuid,
+ NULL,
+ (VOID **) &gPciHotPlugInit
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gPciHotPlugInit->GetRootHpcList (
+ gPciHotPlugInit,
+ &HpcCount,
+ &HpcList
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ gPciRootHpcPool = HpcList;
+ gPciRootHpcCount = HpcCount;
+ gPciRootHpcData = AllocateZeroPool (sizeof (ROOT_HPC_DATA) * gPciRootHpcCount);
+ if (gPciRootHpcData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test whether device path is for root pci hot plug bus.
+
+ @param HpbDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is returned.
+
+ @retval TRUE The device path is for root pci hot plug bus.
+ @retval FALSE The device path is not for root pci hot plug bus.
+
+**/
+BOOLEAN
+IsRootPciHotPlugBus (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath,
+ OUT UINTN *HpIndex OPTIONAL
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpbDevicePath, HpbDevicePath)) {
+
+ if (HpIndex != NULL) {
+ *HpIndex = Index;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Test whether device path is for root pci hot plug controller.
+
+ @param HpcDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is returned.
+
+ @retval TRUE The device path is for root pci hot plug controller.
+ @retval FALSE The device path is not for root pci hot plug controller.
+
+**/
+BOOLEAN
+IsRootPciHotPlugController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ OUT UINTN *HpIndex
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpcDevicePath, HpcDevicePath)) {
+
+ if (HpIndex != NULL) {
+ *HpIndex = Index;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Creating event object for PCI Hot Plug controller.
+
+ @param HpIndex Index of hot plug device in global array.
+ @param Event The returned event that invoke this function.
+
+ @return Status of create event.
+
+**/
+EFI_STATUS
+CreateEventForHpc (
+ IN UINTN HpIndex,
+ OUT EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PciHPCInitialized,
+ gPciRootHpcData + HpIndex,
+ &((gPciRootHpcData + HpIndex)->Event)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ *Event = (gPciRootHpcData + HpIndex)->Event;
+ }
+
+ return Status;
+}
+
+/**
+ Wait for all root PCI Hot Plug controller finished initializing.
+
+ @param TimeoutInMicroSeconds Microseconds to wait for all root HPCs' initialization.
+
+ @retval EFI_SUCCESS All HPCs initialization finished.
+ @retval EFI_TIMEOUT Not ALL HPCs initialization finished in Microseconds.
+
+**/
+EFI_STATUS
+AllRootHPCInitialized (
+ IN UINTN TimeoutInMicroSeconds
+ )
+{
+ UINT32 Delay;
+ UINTN Index;
+
+ Delay = (UINT32) ((TimeoutInMicroSeconds / 30) + 1);
+
+ do {
+ for (Index = 0; Index < gPciRootHpcCount; Index++) {
+
+ if (gPciRootHpcData[Index].Found && !gPciRootHpcData[Index].Initialized) {
+ break;
+ }
+ }
+
+ if (Index == gPciRootHpcCount) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 30 microseconds..
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
+
+ @param PciIoDevice A Pointer to the PCI-PCI bridge.
+
+ @retval TRUE PCI device is HPC.
+ @retval FALSE PCI device is not HPC.
+
+**/
+BOOLEAN
+IsSHPC (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+
+ EFI_STATUS Status;
+ UINT8 Offset;
+
+ if (PciIoDevice == NULL) {
+ return FALSE;
+ }
+
+ Offset = 0;
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_SHPC,
+ &Offset,
+ NULL
+ );
+
+ //
+ // If the PCI-PCI bridge has the hot plug controller build-in,
+ // then return TRUE;
+ //
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether PciIoDevice supports PCIe hotplug.
+
+ This is equivalent to the following condition:
+ - the device is either a PCIe switch downstream port or a root port,
+ - and the device has the SlotImplemented bit set in its PCIe capability
+ register,
+ - and the device has the HotPlugCapable bit set in its slot capabilities
+ register.
+
+ @param[in] PciIoDevice The device being checked.
+
+ @retval TRUE PciIoDevice is a PCIe port that accepts a hot-plugged device.
+ @retval FALSE Otherwise.
+
+**/
+BOOLEAN
+SupportsPcieHotplug (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT32 Offset;
+ EFI_STATUS Status;
+ PCI_REG_PCIE_CAPABILITY Capability;
+ PCI_REG_PCIE_SLOT_CAPABILITY SlotCapability;
+
+ if (PciIoDevice == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Read the PCI Express Capabilities Register
+ //
+ if (!PciIoDevice->IsPciExp) {
+ return FALSE;
+ }
+ Offset = PciIoDevice->PciExpressCapabilityOffset +
+ OFFSET_OF (PCI_CAPABILITY_PCIEXP, Capability);
+ Status = PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ Offset,
+ 1,
+ &Capability
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check the contents of the register
+ //
+ switch (Capability.Bits.DevicePortType) {
+ case PCIE_DEVICE_PORT_TYPE_ROOT_PORT:
+ case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT:
+ break;
+ default:
+ return FALSE;
+ }
+ if (!Capability.Bits.SlotImplemented) {
+ return FALSE;
+ }
+
+ //
+ // Read the Slot Capabilities Register
+ //
+ Offset = PciIoDevice->PciExpressCapabilityOffset +
+ OFFSET_OF (PCI_CAPABILITY_PCIEXP, SlotCapability);
+ Status = PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint32,
+ Offset,
+ 1,
+ &SlotCapability
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check the contents of the register
+ //
+ if (SlotCapability.Bits.HotPlugCapable) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Get resource padding if the specified PCI bridge is a hot plug bus.
+
+ @param PciIoDevice PCI bridge instance.
+
+**/
+VOID
+GetResourcePaddingForHpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_HPC_PADDING_ATTRIBUTES Attributes;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+
+ if (IsPciHotPlugBus (PciIoDevice)) {
+ //
+ // If PCI-PCI bridge device is PCI Hot Plug bus.
+ //
+ PciAddress = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
+ Status = gPciHotPlugInit->GetResourcePadding (
+ gPciHotPlugInit,
+ PciIoDevice->DevicePath,
+ PciAddress,
+ &State,
+ (VOID **) &Descriptors,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if ((State & EFI_HPC_STATE_ENABLED) != 0 && (State & EFI_HPC_STATE_INITIALIZED) != 0) {
+ PciIoDevice->ResourcePaddingDescriptors = Descriptors;
+ PciIoDevice->PaddingAttributes = Attributes;
+ }
+
+ return;
+ }
+}
+
+/**
+ Test whether PCI device is hot plug bus.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval TRUE PCI device is a hot plug bus.
+ @retval FALSE PCI device is not a hot plug bus.
+
+**/
+BOOLEAN
+IsPciHotPlugBus (
+ PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if (IsSHPC (PciIoDevice)) {
+ //
+ // If the PPB has the hot plug controller build-in,
+ // then return TRUE;
+ //
+ return TRUE;
+ }
+
+ if (SupportsPcieHotplug (PciIoDevice)) {
+ //
+ // If the PPB is a PCIe root complex port or a switch downstream port, and
+ // implements a hot-plug capable slot, then also return TRUE.
+ //
+ return TRUE;
+ }
+
+ //
+ // Otherwise, see if it is a Root HPC
+ //
+ if(IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h
new file mode 100644
index 000000000..e97d75362
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.h
@@ -0,0 +1,205 @@
+/** @file
+ PCI Hot Plug support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_HOT_PLUG_SUPPORT_H_
+#define _EFI_PCI_HOT_PLUG_SUPPORT_H_
+
+//
+// stall 1 second, its unit is 100ns
+//
+#define STALL_1_SECOND 1000000
+
+//
+// PCI Hot Plug controller private data
+//
+typedef struct {
+ EFI_EVENT Event;
+ BOOLEAN Found;
+ BOOLEAN Initialized;
+ VOID *Padding;
+} ROOT_HPC_DATA;
+
+//
+// Reference of some global variables
+//
+extern EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit;
+extern EFI_HPC_LOCATION *gPciRootHpcPool;
+extern ROOT_HPC_DATA *gPciRootHpcData;
+
+/**
+ Event notification function to set Hot Plug controller status.
+
+ @param Event The event that invoke this function.
+ @param Context The calling context, pointer to ROOT_HPC_DATA.
+
+**/
+VOID
+EFIAPI
+PciHPCInitialized (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Compare two device paths to check if they are exactly same.
+
+ @param DevicePath1 A pointer to the first device path data structure.
+ @param DevicePath2 A pointer to the second device path data structure.
+
+ @retval TRUE They are same.
+ @retval FALSE They are not same.
+
+**/
+BOOLEAN
+EfiCompareDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ );
+
+/**
+ Check hot plug support and initialize root hot plug private data.
+
+ If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
+ to get PCI Hot Plug controller's information and constructor the root hot plug
+ private data structure.
+
+ @retval EFI_SUCCESS They are same.
+ @retval EFI_UNSUPPORTED No PCI Hot Plug controller on the platform.
+ @retval EFI_OUT_OF_RESOURCES No memory to constructor root hot plug private
+ data structure.
+
+**/
+EFI_STATUS
+InitializeHotPlugSupport (
+ VOID
+ );
+
+/**
+ Test whether PCI device is hot plug bus.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval TRUE PCI device is a hot plug bus.
+ @retval FALSE PCI device is not a hot plug bus.
+
+**/
+BOOLEAN
+IsPciHotPlugBus (
+ PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Test whether device path is for root pci hot plug bus.
+
+ @param HpbDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is returned.
+
+ @retval TRUE The device path is for root pci hot plug bus.
+ @retval FALSE The device path is not for root pci hot plug bus.
+
+**/
+BOOLEAN
+IsRootPciHotPlugBus (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath,
+ OUT UINTN *HpIndex OPTIONAL
+ );
+
+/**
+ Test whether device path is for root pci hot plug controller.
+
+ @param HpcDevicePath A pointer to device path data structure to be tested.
+ @param HpIndex If HpIndex is not NULL, return the index of root hot
+ plug in global array when TRUE is returned.
+
+ @retval TRUE The device path is for root pci hot plug controller.
+ @retval FALSE The device path is not for root pci hot plug controller.
+
+**/
+BOOLEAN
+IsRootPciHotPlugController (
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
+ OUT UINTN *HpIndex
+ );
+
+/**
+ Creating event object for PCI Hot Plug controller.
+
+ @param HpIndex Index of hot plug device in global array.
+ @param Event The returned event that invoke this function.
+
+ @return Status of create event.
+
+**/
+EFI_STATUS
+CreateEventForHpc (
+ IN UINTN HpIndex,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Wait for all root PCI Hot Plug controller finished initializing.
+
+ @param TimeoutInMicroSeconds Microseconds to wait for all root HPCs' initialization.
+
+ @retval EFI_SUCCESS All HPCs initialization finished.
+ @retval EFI_TIMEOUT Not ALL HPCs initialization finished in Microseconds.
+
+**/
+EFI_STATUS
+AllRootHPCInitialized (
+ IN UINTN TimeoutInMicroSeconds
+ );
+
+/**
+ Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
+
+ @param PciIoDevice A Pointer to the PCI-PCI bridge.
+
+ @retval TRUE PCI device is HPC.
+ @retval FALSE PCI device is not HPC.
+
+**/
+BOOLEAN
+IsSHPC (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Check whether PciIoDevice supports PCIe hotplug.
+
+ This is equivalent to the following condition:
+ - the device is either a PCIe switch downstream port or a root port,
+ - and the device has the SlotImplemented bit set in its PCIe capability
+ register,
+ - and the device has the HotPlugCapable bit set in its slot capabilities
+ register.
+
+ @param[in] PciIoDevice The device being checked.
+
+ @retval TRUE PciIoDevice is a PCIe port that accepts a hot-plugged device.
+ @retval FALSE Otherwise.
+
+**/
+BOOLEAN
+SupportsPcieHotplug (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Get resource padding if the specified PCI bridge is a hot plug bus.
+
+ @param PciIoDevice PCI bridge instance.
+
+**/
+VOID
+GetResourcePaddingForHpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
new file mode 100644
index 000000000..40171f9ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
@@ -0,0 +1,2087 @@
+/** @file
+ EFI PCI IO protocol functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
+
+//
+// Pci Io Protocol Interface
+//
+EFI_PCI_IO_PROTOCOL mPciIoInterface = {
+ PciIoPollMem,
+ PciIoPollIo,
+ {
+ PciIoMemRead,
+ PciIoMemWrite
+ },
+ {
+ PciIoIoRead,
+ PciIoIoWrite
+ },
+ {
+ PciIoConfigRead,
+ PciIoConfigWrite
+ },
+ PciIoCopyMem,
+ PciIoMap,
+ PciIoUnmap,
+ PciIoAllocateBuffer,
+ PciIoFreeBuffer,
+ PciIoFlush,
+ PciIoGetLocation,
+ PciIoAttributes,
+ PciIoGetBarAttributes,
+ PciIoSetBarAttributes,
+ 0,
+ NULL
+};
+
+/**
+ Initializes a PCI I/O Instance.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+InitializePciIoInstance (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ CopyMem (&PciIoDevice->PciIo, &mPciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
+}
+
+/**
+ Verifies access to a PCI Base Address Register (BAR).
+
+ @param PciIoDevice Pci device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Type Operation type could be memory or I/O.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyBarAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE Type,
+ IN IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN IN UINTN Count,
+ IN UINT64 *Offset
+ )
+{
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // BarIndex 0-5 is legal
+ //
+ if (BarIndex >= PCI_MAX_BAR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
+ // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
+ //
+ if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verifies access to a PCI Configuration Header.
+
+ @param PciIoDevice Pci device instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width
+ @retval EFI_UNSUPPORTED Offset overflowed.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyConfigAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT64 *Offset
+ )
+{
+ UINT64 ExtendOffset;
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
+ //
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ if (PciIoDevice->IsPciExp) {
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ExtendOffset = LShiftU64 (*Offset, 32);
+ *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
+ *Offset = (*Offset) | ExtendOffset;
+
+ } else {
+ if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value || Delay == 0) {
+ return EFI_SUCCESS;
+ }
+ do {
+ //
+ // Stall 10 us = 100 * 100ns
+ //
+ gBS->Stall (10);
+
+ Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ if (Delay <= 100) {
+ return EFI_TIMEOUT;
+ }
+ Delay -= 100;
+ } while (TRUE);
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->PollMem (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Mask,
+ Value,
+ Delay,
+ Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width > EfiPciIoWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value || Delay == 0) {
+ return EFI_SUCCESS;
+ }
+ do {
+ //
+ // Stall 10 us = 100 * 100ns
+ //
+ gBS->Stall (10);
+
+ Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ if (Delay <= 100) {
+ return EFI_TIMEOUT;
+ }
+ Delay -= 100;
+ } while (TRUE);
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->PollIo (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Mask,
+ Value,
+ Delay,
+ Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+
+ Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Io.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Io.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 Address;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Address = Offset;
+ Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Address,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 Address;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Address = Offset;
+ Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ Address,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Width >= EfiPciIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == EfiPciIoWidthFifoUint8 ||
+ Width == EfiPciIoWidthFifoUint16 ||
+ Width == EfiPciIoWidthFifoUint32 ||
+ Width == EfiPciIoWidthFifoUint64 ||
+ Width == EfiPciIoWidthFillUint8 ||
+ Width == EfiPciIoWidthFillUint16 ||
+ Width == EfiPciIoWidthFillUint32 ||
+ Width == EfiPciIoWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
+ //
+ if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
+ if ((SrcOffset & ((1 << (Width & 0x03)) - 1)) != 0 || (DestOffset & ((1 << (Width & 0x03)) - 1)) != 0) {
+ Count *= (UINTN)(1 << (Width & 0x03));
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
+ }
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->CopyMem (
+ PciIoDevice->PciRootBridgeIo,
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+ DestOffset,
+ SrcOffset,
+ Count
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 IoMmuAttribute;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION RootBridgeIoOperation;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridgeIoOperation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)Operation;
+ if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
+ RootBridgeIoOperation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)(Operation + EfiPciOperationBusMasterRead64);
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Map (
+ PciIoDevice->PciRootBridgeIo,
+ RootBridgeIoOperation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ if (mIoMmuProtocol != NULL) {
+ if (!EFI_ERROR (Status)) {
+ switch (Operation) {
+ case EfiPciIoOperationBusMasterRead:
+ IoMmuAttribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EfiPciIoOperationBusMasterWrite:
+ IoMmuAttribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EfiPciIoOperationBusMasterCommonBuffer:
+ IoMmuAttribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ mIoMmuProtocol->SetAttribute (
+ mIoMmuProtocol,
+ PciIoDevice->Handle,
+ *Mapping,
+ IoMmuAttribute
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from 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
+PciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (mIoMmuProtocol != NULL) {
+ mIoMmuProtocol->SetAttribute (
+ mIoMmuProtocol,
+ PciIoDevice->Handle,
+ Mapping,
+ 0
+ );
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->Unmap (
+ PciIoDevice->PciRootBridgeIo,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ or EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAllocateBuffer (
+ IN EFI_PCI_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;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ if ((Attributes &
+ (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
+ return EFI_UNSUPPORTED;
+ }
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
+ Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
+ }
+
+ Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
+ PciIoDevice->PciRootBridgeIo,
+ Type,
+ MemoryType,
+ Pages,
+ HostAddress,
+ Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
+ PciIoDevice->PciRootBridgeIo,
+ Pages,
+ HostAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ Status = PciIoDevice->PciRootBridgeIo->Flush (
+ PciIoDevice->PciRootBridgeIo
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *Segment,
+ OUT UINTN *Bus,
+ OUT UINTN *Device,
+ OUT UINTN *Function
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Segment = PciIoDevice->PciRootBridgeIo->SegmentNumber;
+ *Bus = PciIoDevice->BusNumber;
+ *Device = PciIoDevice->DeviceNumber;
+ *Function = PciIoDevice->FunctionNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check BAR type for PCI resource.
+
+ @param PciIoDevice PCI device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param BarType Memory or I/O.
+
+ @retval TRUE Pci device's bar type is same with input BarType.
+ @retval TRUE Pci device's bar type is not same with input BarType.
+
+**/
+BOOLEAN
+CheckBarType (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE BarType
+ )
+{
+ switch (BarType) {
+
+ case PciBarTypeMem:
+
+ if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64 ) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+ case PciBarTypeIo:
+ if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
+ PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
+ return FALSE;
+ }
+
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ Set/Disable new attributes to a Root Bridge.
+
+ @param PciIoDevice Pci device instance.
+ @param Attributes New attribute want to be set.
+ @param Operation Set or Disable.
+
+ @retval EFI_UNSUPPORTED If root bridge does not support change attribute.
+ @retval EFI_SUCCESS Successfully set new attributes.
+
+**/
+EFI_STATUS
+ModifyRootBridgeAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT64 Attributes,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ )
+{
+ UINT64 PciRootBridgeSupports;
+ UINT64 PciRootBridgeAttributes;
+ UINT64 NewPciRootBridgeAttributes;
+ EFI_STATUS Status;
+
+ //
+ // Get the current attributes of this PCI device's PCI Root Bridge
+ //
+ Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ &PciRootBridgeSupports,
+ &PciRootBridgeAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Mask off attributes not supported by PCI root bridge.
+ //
+ Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
+
+ //
+ // Record the new attribute of the Root Bridge
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
+ } else {
+ NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
+ }
+
+ //
+ // Call the PCI Root Bridge to attempt to modify the attributes
+ //
+ if ((NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) != 0) {
+
+ Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
+ PciIoDevice->PciRootBridgeIo,
+ NewPciRootBridgeAttributes,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The PCI Root Bridge could not modify the attributes, so return the error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Also update the attributes for this Root Bridge structure
+ //
+ PciIoDevice->Attributes = NewPciRootBridgeAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether this device can be enable/disable to snoop.
+
+ @param PciIoDevice Pci device instance.
+ @param Operation Enable/Disable.
+
+ @retval EFI_UNSUPPORTED Pci device is not GFX device or not support snoop.
+ @retval EFI_SUCCESS Snoop can be supported.
+
+**/
+EFI_STATUS
+SupportPaletteSnoopAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ UINT16 VGACommand;
+
+ //
+ // Snoop attribute can be only modified by GFX
+ //
+ if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the boot VGA on the same Host Bridge
+ //
+ Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo->ParentHandle);
+
+ if (Temp == NULL) {
+ //
+ // If there is no VGA device on the segment, set
+ // this graphics card to decode the palette range
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check these two agents are on the same path
+ //
+ if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
+ //
+ // they are not on the same path, so snoop can be enabled or disabled
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // Check if they are on the same bus
+ //
+ if (Temp->Parent == PciIoDevice->Parent) {
+
+ PCI_READ_COMMAND_REGISTER (Temp, &VGACommand);
+
+ //
+ // If they are on the same bus, either one can
+ // be set to snoop, the other set to decode
+ //
+ if ((VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
+ //
+ // VGA has set to snoop, so GFX can be only set to disable snoop
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // VGA has disabled to snoop, so GFX can be only enabled
+ //
+ if (Operation == EfiPciIoAttributeOperationDisable) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If they are on the same path but on the different bus
+ // The first agent is set to snoop, the second one set to
+ // decode
+ //
+
+ if (Temp->BusNumber < PciIoDevice->BusNumber) {
+ //
+ // GFX should be set to decode
+ //
+ if (Operation == EfiPciIoAttributeOperationDisable) {
+ PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+ //
+ // GFX should be set to snoop
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ Temp->Attributes &= (~(UINT64)EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ PCI_IO_DEVICE *PciIoDevice;
+ PCI_IO_DEVICE *UpStreamBridge;
+ PCI_IO_DEVICE *Temp;
+
+ UINT64 Supports;
+ UINT64 UpStreamAttributes;
+ UINT16 BridgeControl;
+ UINT16 Command;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ switch (Operation) {
+ case EfiPciIoAttributeOperationGet:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Result = PciIoDevice->Attributes;
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationSupported:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Result = PciIoDevice->Supports;
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationSet:
+ Status = PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ Attributes,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIoDevice->PciIo.Attributes (
+ &(PciIoDevice->PciIo),
+ EfiPciIoAttributeOperationDisable,
+ (~Attributes) & (PciIoDevice->Supports),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+
+ case EfiPciIoAttributeOperationEnable:
+ case EfiPciIoAttributeOperationDisable:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Just a trick for ENABLE attribute
+ // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the internal usage.
+ // So, this logic doesn't conform to UEFI spec, which should be removed.
+ // But this trick logic is still kept for some binary drivers that depend on it.
+ //
+ if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
+ Attributes &= (PciIoDevice->Supports);
+
+ //
+ // Raise the EFI_P_PC_ENABLE Status code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ //
+ // Check VGA and VGA16, they can not be set at the same time
+ //
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) != 0) {
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // If no attributes can be supported, then return.
+ // Otherwise, set the attributes that it can support.
+ //
+ Supports = (PciIoDevice->Supports) & Attributes;
+ if (Supports != Attributes) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // For Root Bridge, just call RootBridgeIo to set attributes;
+ //
+ if (PciIoDevice->Parent == NULL) {
+ Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);
+ return Status;
+ }
+
+ Command = 0;
+ BridgeControl = 0;
+
+ //
+ // For PPB & P2C, set relevant attribute bits
+ //
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
+ }
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
+ Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
+ }
+
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
+ BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;
+ }
+
+ } else {
+ //
+ // Do with the attributes on VGA
+ // Only for VGA's legacy resource, we just can enable once.
+ //
+ if ((Attributes &
+ (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
+ EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) != 0) {
+ //
+ // Check if a VGA has been enabled before enabling a new one
+ //
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Check if there have been an active VGA device on the same Host Bridge
+ //
+ Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo->ParentHandle);
+ if (Temp != NULL && Temp != PciIoDevice) {
+ //
+ // An active VGA has been detected, so can not enable another
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Do with the attributes on GFX
+ //
+ if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
+
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Check if snoop can be enabled in current configuration
+ //
+ Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);
+
+ if (EFI_ERROR (Status)) {
+
+ //
+ // Enable operation is forbidden, so mask the bit in attributes
+ // so as to keep consistent with the actual Status
+ //
+ // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
+ //
+ //
+ //
+ return EFI_UNSUPPORTED;
+
+ }
+ }
+
+ //
+ // It can be supported, so get ready to set the bit
+ //
+ Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
+ }
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
+ Command |= EFI_PCI_COMMAND_IO_SPACE;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) != 0) {
+ Command |= EFI_PCI_COMMAND_MEMORY_SPACE;
+ }
+
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {
+ Command |= EFI_PCI_COMMAND_BUS_MASTER;
+ }
+ //
+ // The upstream bridge should be also set to relevant attribute
+ // expect for IO, Mem and BusMaster
+ //
+ UpStreamAttributes = Attributes &
+ (~(EFI_PCI_IO_ATTRIBUTE_IO |
+ EFI_PCI_IO_ATTRIBUTE_MEMORY |
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
+ )
+ );
+ UpStreamBridge = PciIoDevice->Parent;
+
+ if (Operation == EfiPciIoAttributeOperationEnable) {
+ //
+ // Enable relevant attributes to command register and bridge control register
+ //
+ Status = PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, Command);
+ if (BridgeControl != 0) {
+ Status = PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+ }
+
+ PciIoDevice->Attributes |= Attributes;
+
+ //
+ // Enable attributes of the upstream bridge
+ //
+ Status = UpStreamBridge->PciIo.Attributes (
+ &(UpStreamBridge->PciIo),
+ EfiPciIoAttributeOperationEnable,
+ UpStreamAttributes,
+ NULL
+ );
+ } else {
+
+ //
+ // Disable relevant attributes to command register and bridge control register
+ //
+ Status = PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, Command);
+ if (BridgeControl != 0) {
+ Status = PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
+ }
+
+ PciIoDevice->Attributes &= (~Attributes);
+ Status = EFI_SUCCESS;
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
+ PciIoDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Retrieve the AddrTranslationOffset from RootBridgeIo for the
+ specified range.
+
+ @param RootBridgeIo Root Bridge IO instance.
+ @param AddrRangeMin The base address of the MMIO.
+ @param AddrLen The length of the MMIO.
+
+ @retval The AddrTranslationOffset from RootBridgeIo for the
+ specified range, or (UINT64) -1 if the range is not
+ found in RootBridgeIo.
+**/
+UINT64
+GetMmioAddressTranslationOffset (
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo,
+ UINT64 AddrRangeMin,
+ UINT64 AddrLen
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+
+ Status = RootBridgeIo->Configuration (
+ RootBridgeIo,
+ (VOID **) &Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return (UINT64) -1;
+ }
+
+ // According to UEFI 2.7, EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration()
+ // returns host address instead of device address, while AddrTranslationOffset
+ // is not zero, and device address = host address + AddrTranslationOffset, so
+ // we convert host address to device address for range compare.
+ while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ if ((Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
+ (Configuration->AddrRangeMin + Configuration->AddrTranslationOffset <= AddrRangeMin) &&
+ (Configuration->AddrRangeMin + Configuration->AddrLen + Configuration->AddrTranslationOffset >= AddrRangeMin + AddrLen)
+ ) {
+ return Configuration->AddrTranslationOffset;
+ }
+ Configuration++;
+ }
+
+ //
+ // The resource occupied by BAR should be in the range reported by RootBridge.
+ //
+ ASSERT (FALSE);
+ return (UINT64) -1;
+}
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ if (Supports == NULL && Resources == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // This driver does not support modifications to the WRITE_COMBINE or
+ // CACHED attributes for BAR ranges.
+ //
+ if (Supports != NULL) {
+ *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
+ }
+
+ if (Resources != NULL) {
+ Descriptor = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Descriptor == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Resources = Descriptor;
+
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
+ Descriptor->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
+ Descriptor->AddrLen = PciIoDevice->PciBar[BarIndex].Length;
+ Descriptor->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
+
+ switch (PciIoDevice->PciBar[BarIndex].BarType) {
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ //
+ // Io
+ //
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case PciBarTypePMem32:
+ //
+ // prefetchable
+ //
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ //
+ // Fall through
+ //
+ case PciBarTypeMem32:
+ //
+ // Mem
+ //
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // 32 bit
+ //
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case PciBarTypePMem64:
+ //
+ // prefetchable
+ //
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ //
+ // Fall through
+ //
+ case PciBarTypeMem64:
+ //
+ // Mem
+ //
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ //
+ // 64 bit
+ //
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // put the checksum
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ //
+ // Get the Address Translation Offset
+ //
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ Descriptor->AddrTranslationOffset = GetMmioAddressTranslationOffset (
+ PciIoDevice->PciRootBridgeIo,
+ Descriptor->AddrRangeMin,
+ Descriptor->AddrLen
+ );
+ if (Descriptor->AddrTranslationOffset == (UINT64) -1) {
+ FreePool (Descriptor);
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ // According to UEFI spec 2.7, we need return host address for
+ // PciIo->GetBarAttributes, and host address = device address - translation.
+ Descriptor->AddrRangeMin -= Descriptor->AddrTranslationOffset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ PCI_IO_DEVICE *PciIoDevice;
+ UINT64 NonRelativeOffset;
+ UINT64 Supports;
+
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
+
+ //
+ // Make sure Offset and Length are not NULL
+ //
+ if (Offset == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
+ // If Attributes is not 0, then return EFI_UNSUPPORTED.
+ //
+ Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
+
+ if (Attributes != (Attributes & Supports)) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Attributes must be supported. Make sure the BAR range described by BarIndex, Offset, and
+ // Length are valid for this PCI device.
+ //
+ NonRelativeOffset = *Offset;
+ Status = PciIoVerifyBarAccess (
+ PciIoDevice,
+ BarIndex,
+ PciBarTypeMem,
+ EfiPciIoWidthUint8,
+ (UINT32) *Length,
+ &NonRelativeOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test whether two Pci devices has same parent bridge.
+
+ @param PciDevice1 The first pci device for testing.
+ @param PciDevice2 The second pci device for testing.
+
+ @retval TRUE Two Pci device has the same parent bridge.
+ @retval FALSE Two Pci device has not the same parent bridge.
+
+**/
+BOOLEAN
+PciDevicesOnTheSamePath (
+ IN PCI_IO_DEVICE *PciDevice1,
+ IN PCI_IO_DEVICE *PciDevice2
+ )
+{
+ BOOLEAN Existed1;
+ BOOLEAN Existed2;
+
+ if (PciDevice1->Parent == PciDevice2->Parent) {
+ return TRUE;
+ }
+
+ Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
+ Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
+
+ return (BOOLEAN) (Existed1 || Existed2);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h
new file mode 100644
index 000000000..8c50c48ac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h
@@ -0,0 +1,660 @@
+/** @file
+ EFI PCI IO protocol functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_IO_PROTOCOL_H_
+#define _EFI_PCI_IO_PROTOCOL_H_
+
+/**
+ Initializes a PCI I/O Instance.
+
+ @param PciIoDevice Pci device instance.
+
+**/
+VOID
+InitializePciIoInstance (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Verifies access to a PCI Base Address Register (BAR).
+
+ @param PciIoDevice Pci device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Type Operation type could be memory or I/O.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyBarAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE Type,
+ IN IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN IN UINTN Count,
+ IN UINT64 *Offset
+ );
+
+/**
+ Verifies access to a PCI Configuration Header.
+
+ @param PciIoDevice Pci device instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Count The number of memory or I/O operations to perform.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+
+ @retval EFI_INVALID_PARAMETER Invalid Width
+ @retval EFI_UNSUPPORTED Offset overflowed.
+ @retval EFI_SUCCESS Successfully verified.
+
+**/
+EFI_STATUS
+PciIoVerifyConfigAccess (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT64 *Offset
+ );
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param 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 read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoConfigWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from 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
+PciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ or EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAllocateBuffer (
+ IN EFI_PCI_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 AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ );
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *Segment,
+ OUT UINTN *Bus,
+ OUT UINTN *Device,
+ OUT UINTN *Function
+ );
+
+/**
+ Check BAR type for PCI resource.
+
+ @param PciIoDevice PCI device instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param BarType Memory or I/O.
+
+ @retval TRUE Pci device's bar type is same with input BarType.
+ @retval TRUE Pci device's bar type is not same with input BarType.
+
+**/
+BOOLEAN
+CheckBarType (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT8 BarIndex,
+ IN PCI_BAR_TYPE BarType
+ );
+
+/**
+ Set/Disable new attributes to a Root Bridge.
+
+ @param PciIoDevice Pci device instance.
+ @param Attributes New attribute want to be set.
+ @param Operation Set or Disable.
+
+ @retval EFI_UNSUPPORTED If root bridge does not support change attribute.
+ @retval EFI_SUCCESS Successfully set new attributes.
+
+**/
+EFI_STATUS
+ModifyRootBridgeAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN UINT64 Attributes,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ );
+
+/**
+ Check whether this device can be enable/disable to snoop.
+
+ @param PciIoDevice Pci device instance.
+ @param Operation Enable/Disable.
+
+ @retval EFI_UNSUPPORTED Pci device is not GFX device or not support snoop.
+ @retval EFI_SUCCESS Snoop can be supported.
+
+**/
+EFI_STATUS
+SupportPaletteSnoopAttributes (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
+ );
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ );
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL * This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ );
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+EFI_STATUS
+EFIAPI
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ );
+
+
+/**
+ Test whether two Pci devices has same parent bridge.
+
+ @param PciDevice1 The first pci device for testing.
+ @param PciDevice2 The second pci device for testing.
+
+ @retval TRUE Two Pci device has the same parent bridge.
+ @retval FALSE Two Pci device has not the same parent bridge.
+
+**/
+BOOLEAN
+PciDevicesOnTheSamePath (
+ IN PCI_IO_DEVICE *PciDevice1,
+ IN PCI_IO_DEVICE *PciDevice2
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
new file mode 100644
index 000000000..72690ab64
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
@@ -0,0 +1,1653 @@
+/** @file
+ Internal library implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mBarTypeStr[] = {
+ L"Unknow",
+ L" Io16",
+ L" Io32",
+ L" Mem32",
+ L"PMem32",
+ L" Mem64",
+ L"PMem64",
+ L" OpRom",
+ L" Io",
+ L" Mem",
+ L"Unknow"
+ };
+
+/**
+ Retrieve the max bus number that is assigned to the Root Bridge hierarchy.
+ It can support the case that there are multiple bus ranges.
+
+ @param Bridge Bridge device instance.
+
+ @retval The max bus number that is assigned to this Root Bridge hierarchy.
+
+**/
+UINT16
+PciGetMaxBusNumber (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
+ UINT64 MaxNumberInRange;
+
+ //
+ // Get PCI Root Bridge device
+ //
+ RootBridge = Bridge;
+ while (RootBridge->Parent != NULL) {
+ RootBridge = RootBridge->Parent;
+ }
+ MaxNumberInRange = 0;
+ //
+ // Iterate the bus number ranges to get max PCI bus number
+ //
+ BusNumberRanges = RootBridge->BusNumberRanges;
+ while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ BusNumberRanges++;
+ }
+ return (UINT16) MaxNumberInRange;
+}
+
+/**
+ Retrieve the PCI Card device BAR information via PciIo interface.
+
+ @param PciIoDevice PCI Card device instance.
+
+**/
+VOID
+GetBackPcCardBar (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT32 Address;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ //
+ // Read PciBar information from the bar register
+ //
+ if (!gFullEnumeration) {
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_0,
+ 1,
+ &Address
+ );
+
+ (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_1,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_0_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_1_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
+
+ }
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ GetResourcePaddingForHpb (PciIoDevice);
+ }
+}
+
+/**
+ Remove rejected pci device from specific root bridge
+ handle.
+
+ @param RootBridgeHandle Specific parent root bridge handle.
+ @param Bridge Bridge device instance.
+
+**/
+VOID
+RemoveRejectedPciDevices (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *LastLink;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+ //
+ // Remove rejected devices recusively
+ //
+ RemoveRejectedPciDevices (RootBridgeHandle, Temp);
+ } else {
+ //
+ // Skip rejection for all PPBs, while detect rejection for others
+ //
+ if (IsPciDeviceRejected (Temp)) {
+
+ //
+ // For P2C, remove all devices on it
+ //
+ if (!IsListEmpty (&Temp->ChildList)) {
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
+ }
+
+ //
+ // Finally remove itself
+ //
+ LastLink = CurrentLink->BackLink;
+ RemoveEntryList (CurrentLink);
+ FreePciDevice (Temp);
+
+ CurrentLink = LastLink;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Dump the resourc map of the bridge device.
+
+ @param[in] BridgeResource Resource descriptor of the bridge device.
+**/
+VOID
+DumpBridgeResource (
+ IN PCI_RESOURCE_NODE *BridgeResource
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_RESOURCE_NODE *Resource;
+ PCI_BAR *Bar;
+
+ if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {
+ DEBUG ((
+ EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx\n",
+ mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],
+ BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,
+ BridgeResource->Length, BridgeResource->Alignment
+ ));
+ for ( Link = GetFirstNode (&BridgeResource->ChildList)
+ ; !IsNull (&BridgeResource->ChildList, Link)
+ ; Link = GetNextNode (&BridgeResource->ChildList, Link)
+ ) {
+ Resource = RESOURCE_NODE_FROM_LINK (Link);
+ if (Resource->ResourceUsage == PciResUsageTypical) {
+ Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource->PciDev->PciBar;
+ DEBUG ((
+ EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s [%02x|%02x|%02x:",
+ Bar[Resource->Bar].BaseAddress, Resource->Length, Resource->Alignment,
+ IS_PCI_BRIDGE (&Resource->PciDev->Pci) ? L"PPB" :
+ IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :
+ L"PCI",
+ Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
+ Resource->PciDev->FunctionNumber
+ ));
+
+ if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) && !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||
+ (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < PPB_IO_RANGE)) ||
+ (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < P2C_MEM_1))
+ ) {
+ //
+ // The resource requirement comes from the device itself.
+ //
+ DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset));
+ } else {
+ //
+ // The resource requirement comes from the subordinate devices.
+ //
+ DEBUG ((EFI_D_INFO, "**]"));
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, " Base = Padding;\tLength = 0x%lx;\tAlignment = 0x%lx", Resource->Length, Resource->Alignment));
+ }
+ if (BridgeResource->ResType != Resource->ResType) {
+ DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource->ResType, PciBarTypeMaxType)]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ }
+}
+
+/**
+ Find the corresponding resource node for the Device in child list of BridgeResource.
+
+ @param[in] Device Pointer to PCI_IO_DEVICE.
+ @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE.
+ @param[out] DeviceResources Pointer to a buffer to receive resources for the Device.
+
+ @return Count of the resource descriptors returned.
+**/
+UINTN
+FindResourceNode (
+ IN PCI_IO_DEVICE *Device,
+ IN PCI_RESOURCE_NODE *BridgeResource,
+ OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_RESOURCE_NODE *Resource;
+ UINTN Count;
+
+ Count = 0;
+ for ( Link = BridgeResource->ChildList.ForwardLink
+ ; Link != &BridgeResource->ChildList
+ ; Link = Link->ForwardLink
+ ) {
+ Resource = RESOURCE_NODE_FROM_LINK (Link);
+ if (Resource->PciDev == Device) {
+ if (DeviceResources != NULL) {
+ DeviceResources[Count] = Resource;
+ }
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+/**
+ Dump the resource map of all the devices under Bridge.
+
+ @param[in] Bridge Bridge device instance.
+ @param[in] Resources Resource descriptors for the bridge device.
+ @param[in] ResourceCount Count of resource descriptors.
+**/
+VOID
+DumpResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE **Resources,
+ IN UINTN ResourceCount
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ PCI_IO_DEVICE *Device;
+ UINTN Index;
+ CHAR16 *Str;
+ PCI_RESOURCE_NODE **ChildResources;
+ UINTN ChildResourceCount;
+
+ DEBUG ((EFI_D_INFO, "PciBus: Resource Map for "));
+
+ Status = gBS->OpenProtocol (
+ Bridge->Handle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO, "Bridge [%02x|%02x|%02x]\n",
+ Bridge->BusNumber, Bridge->DeviceNumber, Bridge->FunctionNumber
+ ));
+ } else {
+ Str = ConvertDevicePathToText (
+ DevicePathFromHandle (Bridge->Handle),
+ FALSE,
+ FALSE
+ );
+ DEBUG ((EFI_D_INFO, "Root Bridge %s\n", Str != NULL ? Str : L""));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+ }
+
+ for (Index = 0; Index < ResourceCount; Index++) {
+ DumpBridgeResource (Resources[Index]);
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ for ( Link = Bridge->ChildList.ForwardLink
+ ; Link != &Bridge->ChildList
+ ; Link = Link->ForwardLink
+ ) {
+ Device = PCI_IO_DEVICE_FROM_LINK (Link);
+ if (IS_PCI_BRIDGE (&Device->Pci)) {
+
+ ChildResourceCount = 0;
+ for (Index = 0; Index < ResourceCount; Index++) {
+ ChildResourceCount += FindResourceNode (Device, Resources[Index], NULL);
+ }
+ ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) * ChildResourceCount);
+ ASSERT (ChildResources != NULL);
+ ChildResourceCount = 0;
+ for (Index = 0; Index < ResourceCount; Index++) {
+ ChildResourceCount += FindResourceNode (Device, Resources[Index], &ChildResources[ChildResourceCount]);
+ }
+
+ DumpResourceMap (Device, ChildResources, ChildResourceCount);
+ FreePool (ChildResources);
+ }
+ }
+}
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
+
+ @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully finished resource allocation.
+ @retval EFI_NOT_FOUND Cannot get root bridge instance.
+ @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
+ @retval other Some error occurred when allocating resources for the PCI Host Bridge.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciHostBridgeResourceAllocator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_HANDLE RootBridgeHandle;
+ VOID *AcpiConfig;
+ EFI_STATUS Status;
+ UINT64 IoBase;
+ UINT64 Mem32Base;
+ UINT64 PMem32Base;
+ UINT64 Mem64Base;
+ UINT64 PMem64Base;
+ UINT64 IoResStatus;
+ UINT64 Mem32ResStatus;
+ UINT64 PMem32ResStatus;
+ UINT64 Mem64ResStatus;
+ UINT64 PMem64ResStatus;
+ UINT32 MaxOptionRomSize;
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ PCI_RESOURCE_NODE IoPool;
+ PCI_RESOURCE_NODE Mem32Pool;
+ PCI_RESOURCE_NODE PMem32Pool;
+ PCI_RESOURCE_NODE Mem64Pool;
+ PCI_RESOURCE_NODE PMem64Pool;
+ EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
+
+ //
+ // It may try several times if the resource allocation fails
+ //
+ while (TRUE) {
+ //
+ // Initialize resource pool
+ //
+ InitializeResourcePool (&IoPool, PciBarTypeIo16);
+ InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
+ InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
+ InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
+ InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get Root Bridge Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+
+ //
+ // If non-standard PCI Bridge I/O window alignment is supported,
+ // set I/O aligment to minimum possible alignment for root bridge.
+ //
+ IoBridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,
+ RB_IO_RANGE,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_MEM32_RANGE,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_PMEM32_RANGE,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_MEM64_RANGE,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_PMEM64_RANGE,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Get the max ROM size that the root bridge can process
+ // Insert to resource map so that there will be dedicate MEM32 resource range for Option ROM.
+ // All devices' Option ROM share the same MEM32 resource.
+ //
+ MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
+ if (MaxOptionRomSize != 0) {
+ RootBridgeDev->PciBar[0].BarType = PciBarTypeOpRom;
+ RootBridgeDev->PciBar[0].Length = MaxOptionRomSize;
+ RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;
+ GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge, PMem32Bridge, Mem64Bridge, PMem64Bridge);
+ }
+
+ //
+ // Create resourcemap by going through all the devices subject to this root bridge
+ //
+ CreateResourceMap (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ //
+ // Based on the all the resource tree, construct ACPI resource node to
+ // submit the resource aperture to pci host bridge protocol
+ //
+ Status = ConstructAcpiResourceRequestor (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge,
+ &AcpiConfig
+ );
+
+ //
+ // Insert these resource nodes into the database
+ //
+ InsertResourceNode (&IoPool, IoBridge);
+ InsertResourceNode (&Mem32Pool, Mem32Bridge);
+ InsertResourceNode (&PMem32Pool, PMem32Bridge);
+ InsertResourceNode (&Mem64Pool, Mem64Bridge);
+ InsertResourceNode (&PMem64Pool, PMem64Bridge);
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Submit the resource requirement
+ //
+ Status = PciResAlloc->SubmitResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ AcpiConfig
+ );
+ //
+ // If SubmitResources returns error, PciBus isn't able to start.
+ // It's a fatal error so assertion is added.
+ //
+ DEBUG ((EFI_D_INFO, "PciBus: HostBridge->SubmitResources() - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Free acpi resource node
+ //
+ if (AcpiConfig != NULL) {
+ FreePool (AcpiConfig);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+ return Status;
+ }
+ }
+ //
+ // End while, at least one Root Bridge should be found.
+ //
+ ASSERT (RootBridgeDev != NULL);
+
+ //
+ // Notify platform to start to program the resource
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
+ DEBUG ((EFI_D_INFO, "PciBus: HostBridge->NotifyPhase(AllocateResources) - %r\n", Status));
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is not supported
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Allocation failed, then return
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocation succeed.
+ // Get host bridge handle for status report, and then skip the main while
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ break;
+
+ } else {
+ //
+ // If Hot Plug is supported
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocation succeed, then continue the following
+ //
+ break;
+ }
+
+ //
+ // If the resource allocation is unsuccessful, free resources on bridge
+ //
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ IoResStatus = EFI_RESOURCE_SATISFIED;
+ Mem32ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem32ResStatus = EFI_RESOURCE_SATISFIED;
+ Mem64ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem64ResStatus = EFI_RESOURCE_SATISFIED;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get host bridge handle for status report
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (AcpiConfig != NULL) {
+ //
+ // Adjust resource allocation policy for each RB
+ //
+ GetResourceAllocationStatus (
+ AcpiConfig,
+ &IoResStatus,
+ &Mem32ResStatus,
+ &PMem32ResStatus,
+ &Mem64ResStatus,
+ &PMem64ResStatus
+ );
+ FreePool (AcpiConfig);
+ }
+ }
+ //
+ // End while
+ //
+
+ //
+ // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
+ //
+ //
+ // It is very difficult to follow the spec here
+ // Device path , Bar index can not be get here
+ //
+ ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
+ (VOID *) &AllocFailExtendedData,
+ sizeof (AllocFailExtendedData)
+ );
+
+ Status = PciHostBridgeAdjustAllocation (
+ &IoPool,
+ &Mem32Pool,
+ &PMem32Pool,
+ &Mem64Pool,
+ &PMem64Pool,
+ IoResStatus,
+ Mem32ResStatus,
+ PMem32ResStatus,
+ Mem64ResStatus,
+ PMem64ResStatus
+ );
+
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ //
+ // End main while
+ //
+
+ //
+ // Raise the EFI_IOB_PCI_RES_ALLOC status code
+ //
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_RES_ALLOC,
+ (VOID *) &HandleExtendedData,
+ sizeof (HandleExtendedData)
+ );
+
+ //
+ // Notify pci bus driver starts to program the resource
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridgeDev = NULL;
+
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the resource base by interpreting acpi resource node
+ //
+ //
+ GetResourceBase (
+ AcpiConfig,
+ &IoBase,
+ &Mem32Base,
+ &PMem32Base,
+ &Mem64Base,
+ &PMem64Base
+ );
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+ FindResourceNode (RootBridgeDev, &IoPool, &IoBridge);
+ FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge);
+ FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge);
+ FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge);
+ FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge);
+
+ ASSERT (IoBridge != NULL);
+ ASSERT (Mem32Bridge != NULL);
+ ASSERT (PMem32Bridge != NULL);
+ ASSERT (Mem64Bridge != NULL);
+ ASSERT (PMem64Bridge != NULL);
+
+ //
+ // Program IO resources
+ //
+ ProgramResource (
+ IoBase,
+ IoBridge
+ );
+
+ //
+ // Program Mem32 resources
+ //
+ ProgramResource (
+ Mem32Base,
+ Mem32Bridge
+ );
+
+ //
+ // Program PMem32 resources
+ //
+ ProgramResource (
+ PMem32Base,
+ PMem32Bridge
+ );
+
+ //
+ // Program Mem64 resources
+ //
+ ProgramResource (
+ Mem64Base,
+ Mem64Bridge
+ );
+
+ //
+ // Program PMem64 resources
+ //
+ ProgramResource (
+ PMem64Base,
+ PMem64Bridge
+ );
+
+ //
+ // Process Option ROM for this root bridge after all BARs are programmed.
+ // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM BAR Base in order to
+ // shadow the Option ROM of the devices under the PPB.
+ // After the shadow, Option ROM BAR decoding is turned off and the PPB's MEM32 RANGE
+ // BAR is restored back to the original value.
+ // The original value is programmed by ProgramResource() above.
+ //
+ DEBUG ((
+ DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",
+ RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length
+ ));
+ ProcessOptionRom (RootBridgeDev, RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);
+
+ IoBridge ->PciDev->PciBar[IoBridge ->Bar].BaseAddress = IoBase;
+ Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress = Mem32Base;
+ PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress = PMem32Base;
+ Mem64Bridge ->PciDev->PciBar[Mem64Bridge ->Bar].BaseAddress = Mem64Base;
+ PMem64Bridge->PciDev->PciBar[PMem64Bridge->Bar].BaseAddress = PMem64Base;
+
+ //
+ // Dump the resource map for current root bridge
+ //
+ DEBUG_CODE (
+ PCI_RESOURCE_NODE *Resources[5];
+ Resources[0] = IoBridge;
+ Resources[1] = Mem32Bridge;
+ Resources[2] = PMem32Bridge;
+ Resources[3] = Mem64Bridge;
+ Resources[4] = PMem64Bridge;
+ DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE (Resources));
+ );
+
+ FreePool (AcpiConfig);
+ }
+
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ //
+ // Notify the resource allocation phase is to end
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
+
+ return Status;
+}
+
+/**
+ Allocate NumberOfBuses buses and return the next available PCI bus number.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber Current available PCI bus number.
+ @param NumberOfBuses Number of buses enumerated below the StartBusNumber.
+ @param NextBusNumber Next available PCI bus number.
+
+ @retval EFI_SUCCESS Available bus number resource is enough. Next available PCI bus number
+ is returned in NextBusNumber.
+ @retval EFI_OUT_OF_RESOURCES Available bus number resource is not enough for allocation.
+
+**/
+EFI_STATUS
+PciAllocateBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ IN UINT8 NumberOfBuses,
+ OUT UINT8 *NextBusNumber
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
+ UINT8 NextNumber;
+ UINT64 MaxNumberInRange;
+
+ //
+ // Get PCI Root Bridge device
+ //
+ RootBridge = Bridge;
+ while (RootBridge->Parent != NULL) {
+ RootBridge = RootBridge->Parent;
+ }
+
+ //
+ // Get next available PCI bus number
+ //
+ BusNumberRanges = RootBridge->BusNumberRanges;
+ while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ if (StartBusNumber >= BusNumberRanges->AddrRangeMin && StartBusNumber <= MaxNumberInRange) {
+ NextNumber = (UINT8)(StartBusNumber + NumberOfBuses);
+ while (NextNumber > MaxNumberInRange) {
+ ++BusNumberRanges;
+ if (BusNumberRanges->Desc == ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NextNumber = (UINT8)(NextNumber + (BusNumberRanges->AddrRangeMin - (MaxNumberInRange + 1)));
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ }
+ *NextBusNumber = NextNumber;
+ return EFI_SUCCESS;
+ }
+ BusNumberRanges++;
+ }
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Scan pci bus and assign bus number to the given PCI bus system.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber start point.
+ @param SubBusNumber Point to sub bus number.
+ @param PaddedBusRange Customized bus number.
+
+ @retval EFI_SUCCESS Successfully scanned and assigned bus number.
+ @retval other Some error occurred when scanning pci bus.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciScanBus (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber,
+ OUT UINT8 *PaddedBusRange
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 Address;
+ UINT8 SecondBus;
+ UINT8 PaddedSubBus;
+ UINT16 Register;
+ UINTN HpIndex;
+ PCI_IO_DEVICE *PciDevice;
+ EFI_EVENT Event;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_HPC_PADDING_ATTRIBUTES Attributes;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;
+ UINT16 BusRange;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ BOOLEAN BusPadding;
+ UINT32 TempReservedBusNum;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ SecondBus = 0;
+ Register = 0;
+ State = 0;
+ Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
+ BusRange = 0;
+ BusPadding = FALSE;
+ PciDevice = NULL;
+ PciAddress = 0;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ TempReservedBusNum = 0;
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (EFI_ERROR (Status) && Func == 0) {
+ //
+ // go to next device if there is no Function 0
+ //
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the PCI device information
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func,
+ &PciDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
+
+ if (!IS_PCI_BRIDGE (&Pci)) {
+ //
+ // PCI bridges will be called later
+ // Here just need for PCI device or PCI to cardbus controller
+ // EfiPciBeforeChildBusEnumeration for PCI Device Node
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // For Pci Hotplug controller devcie only
+ //
+ if (gPciHotPlugInit != NULL) {
+ //
+ // Check if it is a Hotplug PCI controller
+ //
+ if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
+ gPciRootHpcData[HpIndex].Found = TRUE;
+
+ if (!gPciRootHpcData[HpIndex].Initialized) {
+
+ Status = CreateEventForHpc (HpIndex, &Event);
+
+ ASSERT (!EFI_ERROR (Status));
+
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ gPciRootHpcPool[HpIndex].HpcDevicePath,
+ PciAddress,
+ Event,
+ &State
+ );
+
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+ }
+ }
+ }
+
+ if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
+ //
+ // For PPB
+ //
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is supported,
+ // Get the bridge information
+ //
+ BusPadding = FALSE;
+ if (gPciHotPlugInit != NULL) {
+
+ if (IsPciHotPlugBus (PciDevice)) {
+
+ //
+ // If it is initialized, get the padded bus range
+ //
+ Status = gPciHotPlugInit->GetResourcePadding (
+ gPciHotPlugInit,
+ PciDevice->DevicePath,
+ PciAddress,
+ &State,
+ (VOID **) &Descriptors,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusRange = 0;
+ NextDescriptors = Descriptors;
+ Status = PciGetBusRange (
+ &NextDescriptors,
+ NULL,
+ NULL,
+ &BusRange
+ );
+
+ FreePool (Descriptors);
+
+ if (!EFI_ERROR (Status)) {
+ BusPadding = TRUE;
+ } else if (Status != EFI_NOT_FOUND) {
+ //
+ // EFI_NOT_FOUND is not a real error. It indicates no bus number padding requested.
+ //
+ return Status;
+ }
+ }
+ }
+ }
+
+ Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ SecondBus = *SubBusNumber;
+
+ Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &Register
+ );
+
+
+ //
+ // If it is PPB, resursively search down this bridge
+ //
+ if (IS_PCI_BRIDGE (&Pci)) {
+
+ //
+ // Temporarily initialize SubBusNumber to maximum bus number to ensure the
+ // PCI configuration transaction to go through any PPB
+ //
+ Register = PciGetMaxBusNumber (Bridge);
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &Register
+ );
+
+ //
+ // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+
+ Status = PciScanBus (
+ PciDevice,
+ SecondBus,
+ SubBusNumber,
+ PaddedBusRange
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
+ //
+ // Ensure the device is enabled and initialized
+ //
+ if ((Attributes == EfiPaddingPciRootBridge) &&
+ (State & EFI_HPC_STATE_ENABLED) != 0 &&
+ (State & EFI_HPC_STATE_INITIALIZED) != 0) {
+ *PaddedBusRange = (UINT8) ((UINT8) (BusRange) + *PaddedBusRange);
+ } else {
+ //
+ // Reserve the larger one between the actual occupied bus number and padded bus number
+ //
+ Status = PciAllocateBusNumber (PciDevice, SecondBus, (UINT8) (BusRange), &PaddedSubBus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *SubBusNumber = MAX (PaddedSubBus, *SubBusNumber);
+ }
+ }
+
+ //
+ // Set the current maximum bus number under the PPB
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+ } else {
+ //
+ // It is device. Check PCI IOV for Bus reservation
+ // Go through each function, just reserve the MAX ReservedBusNum for one device
+ //
+ if (PcdGetBool (PcdSrIovSupport) && PciDevice->SrIovCapabilityOffset != 0) {
+ if (TempReservedBusNum < PciDevice->ReservedBusNum) {
+
+ Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8) (PciDevice->ReservedBusNum - TempReservedBusNum), SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ TempReservedBusNum = PciDevice->ReservedBusNum;
+
+ if (Func == 0) {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber));
+ } else {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber));
+ }
+ }
+ }
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified root bridge.
+
+ @param Bridge Pci root bridge device instance.
+
+ @retval EFI_SUCCESS Success process.
+ @retval other Some error occurred when processing Option Rom on the root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeP2CProcess (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_STATUS Status;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
+
+ if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+
+ //
+ // Raise the EFI_IOB_PCI_HPC_INIT status code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_HPC_INIT,
+ Temp->DevicePath
+ );
+
+ PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ Temp->DevicePath,
+ PciAddress,
+ NULL,
+ &State
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = PciBridgeEnumerator (Temp);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+
+ }
+ }
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ Status = PciRootBridgeP2CProcess (Temp);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified host bridge.
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Success process.
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval other Some error occurred when processing Option Rom on the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return EFI_SUCCESS;
+ }
+
+ RootBridgeHandle = NULL;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = PciRootBridgeP2CProcess (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to enumerate the entire host bridge
+ in a given platform.
+
+ @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval EFI_OUT_OF_RESOURCES No enough memory available.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINT16 MinBus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+ UINT8 StartBusNumber;
+ LIST_ENTRY RootBridgeList;
+ LIST_ENTRY *Link;
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InitializeHotPlugSupport ();
+ }
+
+ InitializeListHead (&RootBridgeList);
+
+ //
+ // Notify the bus allocation phase is about to start
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
+ } else {
+ DestroyRootBridge (RootBridgeDev);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is finished for the first time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // Reset all assigned PCI bus number in all PPB
+ //
+ RootBridgeHandle = NULL;
+ Link = GetFirstNode (&RootBridgeList);
+ while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
+ (!IsNull (&RootBridgeList, Link))) {
+ RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
+ //
+ // Get the Bus information
+ //
+ Status = PciResAlloc->StartBusEnumeration (
+ PciResAlloc,
+ RootBridgeHandle,
+ (VOID **) &Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the bus number to start with
+ //
+ StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
+
+ ResetAllPpbBusNumber (
+ RootBridgeDev,
+ StartBusNumber
+ );
+
+ FreePool (Configuration);
+ Link = RemoveEntryList (Link);
+ DestroyRootBridge (RootBridgeDev);
+ }
+
+ //
+ // Wait for all HPC initialized
+ //
+ Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Some root HPC failed to initialize\n"));
+ return Status;
+ }
+
+ //
+ // Notify the bus allocation phase is about to start for the 2nd time
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ DestroyRootBridge (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is to end for the 2nd time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+ }
+
+ //
+ // Notify the resource allocation phase is to start
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = StartManagingRootBridge (RootBridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Determine root bridge attribute by calling interface of Pcihostbridge
+ // protocol
+ //
+ DetermineRootBridgeAttributes (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ //
+ // Collect all the resource information under this root bridge
+ // A database that records all the information about pci device subject to this
+ // root bridge will then be created
+ //
+ Status = PciPciDeviceInfoCollector (
+ RootBridgeDev,
+ (UINT8) MinBus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ InsertRootBridge (RootBridgeDev);
+
+ //
+ // Record the hostbridge handle
+ //
+ AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h
new file mode 100644
index 000000000..10b435d14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h
@@ -0,0 +1,159 @@
+/** @file
+ Internal library declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_LIB_H_
+#define _EFI_PCI_LIB_H_
+
+
+typedef struct {
+ EFI_HANDLE Handle;
+} EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD;
+
+typedef struct {
+ UINT32 Bar;
+ UINT16 DevicePathSize;
+ UINT16 ReqResSize;
+ UINT16 AllocResSize;
+ UINT8 *DevicePath;
+ UINT8 *ReqRes;
+ UINT8 *AllocRes;
+} EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD;
+
+
+/**
+ Retrieve the PCI Card device BAR information via PciIo interface.
+
+ @param PciIoDevice PCI Card device instance.
+
+**/
+VOID
+GetBackPcCardBar (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Remove rejected pci device from specific root bridge
+ handle.
+
+ @param RootBridgeHandle Specific parent root bridge handle.
+ @param Bridge Bridge device instance.
+
+**/
+VOID
+RemoveRejectedPciDevices (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
+
+ @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully finished resource allocation.
+ @retval EFI_NOT_FOUND Cannot get root bridge instance.
+ @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
+ @retval other Some error occurred when allocating resources for the PCI Host Bridge.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciHostBridgeResourceAllocator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ Allocate NumberOfBuses buses and return the next available PCI bus number.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber Current available PCI bus number.
+ @param NumberOfBuses Number of buses enumerated below the StartBusNumber.
+ @param NextBusNumber Next available PCI bus number.
+
+ @retval EFI_SUCCESS Available bus number resource is enough. Next available PCI bus number
+ is returned in NextBusNumber.
+ @retval EFI_OUT_OF_RESOURCES Available bus number resource is not enough for allocation.
+
+**/
+EFI_STATUS
+PciAllocateBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ IN UINT8 NumberOfBuses,
+ OUT UINT8 *NextBusNumber
+ );
+
+/**
+ Scan pci bus and assign bus number to the given PCI bus system.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber start point.
+ @param SubBusNumber Point to sub bus number.
+ @param PaddedBusRange Customized bus number.
+
+ @retval EFI_SUCCESS Successfully scanned and assigned bus number.
+ @retval other Some error occurred when scanning pci bus.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciScanBus (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber,
+ OUT UINT8 *PaddedBusRange
+ );
+
+/**
+ Process Option Rom on the specified root bridge.
+
+ @param Bridge Pci root bridge device instance.
+
+ @retval EFI_SUCCESS Success process.
+ @retval other Some error occurred when processing Option Rom on the root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeP2CProcess (
+ IN PCI_IO_DEVICE *Bridge
+ );
+
+/**
+ Process Option Rom on the specified host bridge.
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Success process.
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval other Some error occurred when processing Option Rom on the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+/**
+ This function is used to enumerate the entire host bridge
+ in a given platform.
+
+ @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval EFI_OUT_OF_RESOURCES No enough memory available.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
new file mode 100644
index 000000000..c994ed5fe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
@@ -0,0 +1,764 @@
+/** @file
+ PCI Rom supporting funtions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+/**
+ Load the EFI Image from Option ROM
+
+ @param PciIoDevice PCI IO device instance.
+ @param FilePath The file path of the EFI Image
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+**/
+EFI_STATUS
+LocalLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode;
+ EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ UINT32 ImageSize;
+ UINT8 *ImageBuffer;
+ UINT32 ImageLength;
+ UINT32 DestinationSize;
+ UINT32 ScratchSize;
+ VOID *Scratch;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+ UINT32 InitializationSize;
+
+ EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;
+ if ((EfiOpRomImageNode == NULL) ||
+ (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||
+ (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) ||
+ (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||
+ (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||
+ (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) ||
+ (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||
+ (BufferSize == NULL)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (
+ (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset
+ );
+ if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ return EFI_NOT_FOUND;
+ }
+
+
+ Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset);
+ ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
+
+ if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
+ (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
+ ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&
+ (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)
+ ) {
+
+ ImageSize = Pcir->ImageLength * 512;
+ InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;
+ if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset >= InitializationSize) {
+ return EFI_NOT_FOUND;
+ }
+
+ ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset;
+ ImageLength = InitializationSize - EfiRomHeader->EfiImageHeaderOffset;
+
+ if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
+ //
+ // Uncompressed: Copy the EFI Image directly to user's buffer
+ //
+ if (Buffer == NULL || *BufferSize < ImageLength) {
+ *BufferSize = ImageLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ImageLength;
+ CopyMem (Buffer, ImageBuffer, ImageLength);
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Compressed: Uncompress before copying
+ //
+ Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ Status = Decompress->GetInfo (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ &DestinationSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Buffer == NULL || *BufferSize < DestinationSize) {
+ *BufferSize = DestinationSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = DestinationSize;
+ Scratch = AllocatePool (ScratchSize);
+ if (Scratch == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ ImageBuffer,
+ ImageLength,
+ Buffer,
+ DestinationSize,
+ Scratch,
+ ScratchSize
+ );
+ FreePool (Scratch);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize a PCI LoadFile2 instance.
+
+ @param PciIoDevice PCI IO Device.
+
+**/
+VOID
+InitializePciLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ PciIoDevice->LoadFile2.LoadFile = LoadFile2;
+}
+
+/**
+ Causes the driver to load a specified file.
+
+ @param This Indicates a pointer to the calling context.
+ @param FilePath The device specific path of the file to load.
+ @param BootPolicy Should always be FALSE.
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED BootPolicy is TRUE.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadFile2 (
+ IN EFI_LOAD_FILE2_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+
+ if (BootPolicy) {
+ return EFI_UNSUPPORTED;
+ }
+ PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
+
+ return LocalLoadFile2 (
+ PciIoDevice,
+ FilePath,
+ BufferSize,
+ Buffer
+ );
+}
+
+/**
+ Get Pci device's oprom information.
+
+ @param PciIoDevice Input Pci device instance.
+ Output Pci device instance with updated OptionRom size.
+
+ @retval EFI_NOT_FOUND Pci device has not Option Rom.
+ @retval EFI_SUCCESS Pci device has Option Rom.
+
+**/
+EFI_STATUS
+GetOpRomInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT8 RomBarIndex;
+ UINT32 AllOnes;
+ UINT64 Address;
+ EFI_STATUS Status;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ Bus = PciIoDevice->BusNumber;
+ Device = PciIoDevice->DeviceNumber;
+ Function = PciIoDevice->FunctionNumber;
+
+ PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
+
+ //
+ // Offset is 0x30 if is not ppb
+ //
+
+ //
+ // 0x30
+ //
+ RomBarIndex = PCI_EXPANSION_ROM_BASE;
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ //
+ // If is ppb, 0x38
+ //
+ RomBarIndex = PCI_BRIDGE_ROMBAR;
+ }
+ //
+ // The bit0 is 0 to prevent the enabling of the Rom address decoder
+ //
+ AllOnes = 0xfffffffe;
+ Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &AllOnes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read back
+ //
+ Status = PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &AllOnes
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Bits [1, 10] are reserved
+ //
+ AllOnes &= 0xFFFFF800;
+ if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PciIoDevice->RomSize = (~AllOnes) + 1;
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the RomImage contains EFI Images.
+
+ @param RomImage The ROM address of Image for check.
+ @param RomSize Size of ROM for check.
+
+ @retval TRUE ROM contain EFI Image.
+ @retval FALSE ROM not contain EFI Image.
+
+**/
+BOOLEAN
+ContainEfiImage (
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ )
+{
+ PCI_EXPANSION_ROM_HEADER *RomHeader;
+ PCI_DATA_STRUCTURE *RomPcir;
+ UINT8 Indicator;
+
+ Indicator = 0;
+ RomHeader = RomImage;
+ if (RomHeader == NULL) {
+ return FALSE;
+ }
+
+ do {
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);
+ continue;
+ }
+
+ //
+ // The PCI Data Structure must be DWORD aligned.
+ //
+ if (RomHeader->PcirOffset == 0 ||
+ (RomHeader->PcirOffset & 3) != 0 ||
+ (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) {
+ break;
+ }
+
+ RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset);
+ if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
+ break;
+ }
+
+ if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
+ return TRUE;
+ }
+
+ Indicator = RomPcir->Indicator;
+ RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->ImageLength * 512);
+ } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) && ((Indicator & 0x80) == 0x00));
+
+ return FALSE;
+}
+
+/**
+ Load Option Rom image for specified PCI device.
+
+ @param PciDevice Pci device instance.
+ @param RomBase Base address of Option Rom.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
+ @retval EFI_SUCESS Successfully loaded Option Rom.
+
+**/
+EFI_STATUS
+LoadOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT64 RomBase
+ )
+{
+ UINT8 RomBarIndex;
+ UINT8 Indicator;
+ UINT16 OffsetPcir;
+ UINT32 RomBarOffset;
+ UINT32 RomBar;
+ EFI_STATUS RetStatus;
+ BOOLEAN FirstCheck;
+ UINT8 *Image;
+ PCI_EXPANSION_ROM_HEADER *RomHeader;
+ PCI_DATA_STRUCTURE *RomPcir;
+ UINT64 RomSize;
+ UINT64 RomImageSize;
+ UINT32 LegacyImageLength;
+ UINT8 *RomInMemory;
+ UINT8 CodeType;
+
+ RomSize = PciDevice->RomSize;
+
+ Indicator = 0;
+ RomImageSize = 0;
+ RomInMemory = NULL;
+ CodeType = 0xFF;
+
+ //
+ // Get the RomBarIndex
+ //
+
+ //
+ // 0x30
+ //
+ RomBarIndex = PCI_EXPANSION_ROM_BASE;
+ if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
+ //
+ // if is ppb
+ //
+
+ //
+ // 0x38
+ //
+ RomBarIndex = PCI_BRIDGE_ROMBAR;
+ }
+ //
+ // Allocate memory for Rom header and PCIR
+ //
+ RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
+ if (RomHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
+ if (RomPcir == NULL) {
+ FreePool (RomHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RomBar = (UINT32) RomBase;
+
+ //
+ // Enable RomBar
+ //
+ RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
+
+ RomBarOffset = RomBar;
+ RetStatus = EFI_NOT_FOUND;
+ FirstCheck = TRUE;
+ LegacyImageLength = 0;
+
+ do {
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBarOffset,
+ sizeof (PCI_EXPANSION_ROM_HEADER),
+ (UINT8 *) RomHeader
+ );
+
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ RomBarOffset = RomBarOffset + 512;
+ if (FirstCheck) {
+ break;
+ } else {
+ RomImageSize = RomImageSize + 512;
+ continue;
+ }
+ }
+
+ FirstCheck = FALSE;
+ OffsetPcir = RomHeader->PcirOffset;
+ //
+ // 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 (OffsetPcir == 0 ||
+ (OffsetPcir & 3) != 0 ||
+ RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
+ break;
+ }
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBarOffset + OffsetPcir,
+ sizeof (PCI_DATA_STRUCTURE),
+ (UINT8 *) RomPcir
+ );
+ //
+ // If a valid signature is not present in the PCI Data Structure, no further images can be located.
+ //
+ if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
+ break;
+ }
+ if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
+ break;
+ }
+ if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
+ LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
+ }
+ Indicator = RomPcir->Indicator;
+ RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
+ RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
+ } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
+
+ //
+ // Some Legacy Cards do not report the correct ImageLength so used the maximum
+ // of the legacy length and the PCIR Image Length
+ //
+ if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ RomImageSize = MAX (RomImageSize, LegacyImageLength);
+ }
+
+ if (RomImageSize > 0) {
+ RetStatus = EFI_SUCCESS;
+ Image = AllocatePool ((UINT32) RomImageSize);
+ if (Image == NULL) {
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+ FreePool (RomHeader);
+ FreePool (RomPcir);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy Rom image into memory
+ //
+ PciDevice->PciRootBridgeIo->Mem.Read (
+ PciDevice->PciRootBridgeIo,
+ EfiPciWidthUint8,
+ RomBar,
+ (UINT32) RomImageSize,
+ Image
+ );
+ RomInMemory = Image;
+ }
+
+ RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
+
+ PciDevice->EmbeddedRom = TRUE;
+ PciDevice->PciIo.RomSize = RomImageSize;
+ PciDevice->PciIo.RomImage = RomInMemory;
+
+ //
+ // For OpROM read from PCI device:
+ // Add the Rom Image to internal database for later PCI light enumeration
+ //
+ PciRomAddImageMapping (
+ NULL,
+ PciDevice->PciRootBridgeIo->SegmentNumber,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ PciDevice->PciIo.RomImage,
+ PciDevice->PciIo.RomSize
+ );
+
+ //
+ // Free allocated memory
+ //
+ FreePool (RomHeader);
+ FreePool (RomPcir);
+
+ return RetStatus;
+}
+
+/**
+ Enable/Disable Option Rom decode.
+
+ @param PciDevice Pci device instance.
+ @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param RomBar Base address of Option Rom.
+ @param Enable Flag for enable/disable decode.
+
+**/
+VOID
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Value32;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = &PciDevice->PciIo;
+ if (Enable) {
+
+ //
+ // set the Rom base address: now is hardcode
+ // enable its decoder
+ //
+ Value32 = RomBar | 0x1;
+ PciIo->Pci.Write (
+ PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
+ RomBarIndex,
+ 1,
+ &Value32
+ );
+
+ //
+ // Programe all upstream bridge
+ //
+ ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE);
+
+ //
+ // Setting the memory space bit in the function's command register
+ //
+ PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ } else {
+
+ //
+ // disable command register decode to memory
+ //
+ PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ //
+ // Destroy the programmed bar in all the upstream bridge.
+ //
+ ProgramUpstreamBridgeForRom (PciDevice, RomBar, FALSE);
+
+ //
+ // disable rom decode
+ //
+ Value32 = 0xFFFFFFFE;
+ PciIo->Pci.Write (
+ PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
+ RomBarIndex,
+ 1,
+ &Value32
+ );
+
+ }
+}
+
+/**
+ Load and start the Option Rom image.
+
+ @param PciDevice Pci device instance.
+
+ @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
+ @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
+
+**/
+EFI_STATUS
+ProcessOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice
+ )
+{
+ UINT8 Indicator;
+ UINT32 ImageSize;
+ VOID *RomBar;
+ UINT8 *RomBarOffset;
+ EFI_HANDLE ImageHandle;
+ EFI_STATUS Status;
+ EFI_STATUS RetStatus;
+ EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
+ MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode;
+ VOID *Buffer;
+ UINTN BufferSize;
+
+ Indicator = 0;
+
+ //
+ // Get the Address of the Option Rom image
+ //
+ RomBar = PciDevice->PciIo.RomImage;
+ RomBarOffset = (UINT8 *) RomBar;
+ RetStatus = EFI_NOT_FOUND;
+
+ if (RomBar == NULL) {
+ return RetStatus;
+ }
+ ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
+
+ do {
+ EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
+ if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ RomBarOffset += 512;
+ continue;
+ }
+
+ Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
+ ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
+ ImageSize = (UINT32) (Pcir->ImageLength * 512);
+ Indicator = Pcir->Indicator;
+
+ //
+ // Skip the image if it is not an EFI PCI Option ROM image
+ //
+ if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
+ goto NextImage;
+ }
+
+ //
+ // Ignore the EFI PCI Option ROM image if it is an EFI application
+ //
+ if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ goto NextImage;
+ }
+
+ //
+ // Create Pci Option Rom Image device path header
+ //
+ EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH;
+ EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP;
+ SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode));
+ EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar;
+ EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar;
+
+ PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header);
+ ASSERT (PciOptionRomImageDevicePath != NULL);
+
+ //
+ // load image and start image
+ //
+ BufferSize = 0;
+ Buffer = NULL;
+ ImageHandle = NULL;
+
+ Status = gBS->LoadImage (
+ FALSE,
+ gPciBusDriverBinding.DriverBindingHandle,
+ PciOptionRomImageDevicePath,
+ Buffer,
+ BufferSize,
+ &ImageHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Record the Option ROM Image device path when LoadImage fails.
+ // PciOverride.GetDriver() will try to look for the Image Handle using the device path later.
+ //
+ AddDriver (PciDevice, NULL, PciOptionRomImageDevicePath);
+ } else {
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Record the Option ROM Image Handle
+ //
+ AddDriver (PciDevice, ImageHandle, NULL);
+ PciRomAddImageMapping (
+ ImageHandle,
+ PciDevice->PciRootBridgeIo->SegmentNumber,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ PciDevice->PciIo.RomImage,
+ PciDevice->PciIo.RomSize
+ );
+ RetStatus = EFI_SUCCESS;
+ }
+ }
+ FreePool (PciOptionRomImageDevicePath);
+
+NextImage:
+ RomBarOffset += ImageSize;
+
+ } while (((Indicator & 0x80) == 0x00) && (((UINTN) RomBarOffset - (UINTN) RomBar) < PciDevice->RomSize));
+
+ return RetStatus;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h
new file mode 100644
index 000000000..5c4e9fa3b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.h
@@ -0,0 +1,136 @@
+/** @file
+ PCI Rom supporting functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_OPTION_ROM_SUPPORT_H_
+#define _EFI_PCI_OPTION_ROM_SUPPORT_H_
+
+
+/**
+ Initialize a PCI LoadFile2 instance.
+
+ @param PciIoDevice PCI IO Device.
+
+**/
+VOID
+InitializePciLoadFile2 (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Causes the driver to load a specified file.
+
+ @param This Indicates a pointer to the calling context.
+ @param FilePath The device specific path of the file to load.
+ @param BootPolicy Should always be FALSE.
+ @param BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to Buffer.
+ On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param Buffer The memory buffer to transfer the file to. If Buffer is NULL,
+ then no the size of the requested file is returned in BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED BootPolicy is TRUE.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device.
+ @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadFile2 (
+ IN EFI_LOAD_FILE2_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ );
+
+/**
+ Check if the RomImage contains EFI Images.
+
+ @param RomImage The ROM address of Image for check.
+ @param RomSize Size of ROM for check.
+
+ @retval TRUE ROM contain EFI Image.
+ @retval FALSE ROM not contain EFI Image.
+
+**/
+BOOLEAN
+ContainEfiImage (
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ );
+
+/**
+ Get Pci device's oprom information.
+
+ @param PciIoDevice Input Pci device instance.
+ Output Pci device instance with updated OptionRom size.
+
+ @retval EFI_NOT_FOUND Pci device has not Option Rom.
+ @retval EFI_SUCCESS Pci device has Option Rom.
+
+**/
+EFI_STATUS
+GetOpRomInfo (
+ IN OUT PCI_IO_DEVICE *PciIoDevice
+ );
+
+/**
+ Load Option Rom image for specified PCI device.
+
+ @param PciDevice Pci device instance.
+ @param RomBase Base address of Option Rom.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
+ @retval EFI_SUCESS Successfully loaded Option Rom.
+
+**/
+EFI_STATUS
+LoadOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT64 RomBase
+ );
+
+/**
+ Enable/Disable Option Rom decode.
+
+ @param PciDevice Pci device instance.
+ @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param RomBar Base address of Option Rom.
+ @param Enable Flag for enable/disable decode.
+
+**/
+VOID
+RomDecode (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT8 RomBarIndex,
+ IN UINT32 RomBar,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Load and start the Option Rom image.
+
+ @param PciDevice Pci device instance.
+
+ @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image.
+ @retval EFI_NOT_FOUND Failed to process PCI Option Rom image.
+
+**/
+EFI_STATUS
+ProcessOpRomImage (
+ IN PCI_IO_DEVICE *PciDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c
new file mode 100644
index 000000000..c7f3ea509
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.c
@@ -0,0 +1,82 @@
+/** @file
+ Power management support functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+/**
+ This function is intended to turn off PWE assertion and
+ put the device to D0 state if the device supports
+ PCI Power Management.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval EFI_UNSUPPORTED PCI Device does not support power management.
+ @retval EFI_SUCCESS Turned off PWE successfully.
+
+**/
+EFI_STATUS
+ResetPowerManagementFeature (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINT8 PowerManagementRegBlock;
+ UINT16 PowerManagementCSR;
+
+ PowerManagementRegBlock = 0;
+
+ Status = LocateCapabilityRegBlock (
+ PciIoDevice,
+ EFI_PCI_CAPABILITY_ID_PMI,
+ &PowerManagementRegBlock,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Turn off the PWE assertion and put the device into D0 State
+ //
+
+ //
+ // Read PMCSR
+ //
+ Status = PciIoDevice->PciIo.Pci.Read (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ PowerManagementRegBlock + 4,
+ 1,
+ &PowerManagementCSR
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Clear PME_Status bit
+ //
+ PowerManagementCSR |= BIT15;
+ //
+ // Clear PME_En bit. PowerState = D0.
+ //
+ PowerManagementCSR &= ~(BIT8 | BIT1 | BIT0);
+
+ //
+ // Write PMCSR
+ //
+ Status = PciIoDevice->PciIo.Pci.Write (
+ &PciIoDevice->PciIo,
+ EfiPciIoWidthUint16,
+ PowerManagementRegBlock + 4,
+ 1,
+ &PowerManagementCSR
+ );
+ }
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h
new file mode 100644
index 000000000..b5018dcf1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciPowerManagement.h
@@ -0,0 +1,28 @@
+/** @file
+ Power management support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_POWER_MANAGEMENT_H_
+#define _EFI_PCI_POWER_MANAGEMENT_H_
+
+/**
+ This function is intended to turn off PWE assertion and
+ put the device to D0 state if the device supports
+ PCI Power Management.
+
+ @param PciIoDevice PCI device instance.
+
+ @retval EFI_UNSUPPORTED PCI Device does not support power management.
+ @retval EFI_SUCCESS Turned off PWE successfully.
+
+**/
+EFI_STATUS
+ResetPowerManagementFeature (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
new file mode 100644
index 000000000..4969ee0f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c
@@ -0,0 +1,2292 @@
+/** @file
+ PCI resources support functions implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+//
+// The default policy for the PCI bus driver is NOT to reserve I/O ranges for both ISA aliases and VGA aliases.
+//
+BOOLEAN mReserveIsaAliases = FALSE;
+BOOLEAN mReserveVgaAliases = FALSE;
+BOOLEAN mPolicyDetermined = FALSE;
+
+/**
+ The function is used to skip VGA range.
+
+ @param Start Returned start address including VGA range.
+ @param Length The length of VGA range.
+
+**/
+VOID
+SkipVGAAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ )
+{
+ UINT64 Original;
+ UINT64 Mask;
+ UINT64 StartOffset;
+ UINT64 LimitOffset;
+
+ ASSERT (Start != NULL);
+ //
+ // For legacy VGA, bit 10 to bit 15 is not decoded
+ //
+ Mask = 0x3FF;
+
+ Original = *Start;
+ StartOffset = Original & Mask;
+ LimitOffset = ((*Start) + Length - 1) & Mask;
+ if (LimitOffset >= VGABASE1) {
+ *Start = *Start - StartOffset + VGALIMIT2 + 1;
+ }
+}
+
+/**
+ This function is used to skip ISA aliasing aperture.
+
+ @param Start Returned start address including ISA aliasing aperture.
+ @param Length The length of ISA aliasing aperture.
+
+**/
+VOID
+SkipIsaAliasAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ )
+{
+
+ UINT64 Original;
+ UINT64 Mask;
+ UINT64 StartOffset;
+ UINT64 LimitOffset;
+
+ ASSERT (Start != NULL);
+
+ //
+ // For legacy ISA, bit 10 to bit 15 is not decoded
+ //
+ Mask = 0x3FF;
+
+ Original = *Start;
+ StartOffset = Original & Mask;
+ LimitOffset = ((*Start) + Length - 1) & Mask;
+
+ if (LimitOffset >= ISABASE) {
+ *Start = *Start - StartOffset + ISALIMIT + 1;
+ }
+}
+
+/**
+ This function inserts a resource node into the resource list.
+ The resource list is sorted in descend order.
+
+ @param Bridge PCI resource node for bridge.
+ @param ResNode Resource node want to be inserted.
+
+**/
+VOID
+InsertResourceNode (
+ IN OUT PCI_RESOURCE_NODE *Bridge,
+ IN PCI_RESOURCE_NODE *ResNode
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Temp;
+ UINT64 ResNodeAlignRest;
+ UINT64 TempAlignRest;
+
+ ASSERT (Bridge != NULL);
+ ASSERT (ResNode != NULL);
+
+ InsertHeadList (&Bridge->ChildList, &ResNode->Link);
+
+ CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
+ while (CurrentLink != &Bridge->ChildList) {
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (ResNode->Alignment > Temp->Alignment) {
+ break;
+ } else if (ResNode->Alignment == Temp->Alignment) {
+ ResNodeAlignRest = ResNode->Length & ResNode->Alignment;
+ TempAlignRest = Temp->Length & Temp->Alignment;
+ if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
+ break;
+ }
+ }
+
+ SwapListEntries (&ResNode->Link, CurrentLink);
+
+ CurrentLink = ResNode->Link.ForwardLink;
+ }
+}
+
+/**
+ This routine is used to merge two different resource trees in need of
+ resource degradation.
+
+ For example, if an upstream PPB doesn't support,
+ prefetchable memory decoding, the PCI bus driver will choose to call this function
+ to merge prefetchable memory resource list into normal memory list.
+
+ If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
+ type.
+ If Dst is NULL or Res is NULL, ASSERT ().
+
+ @param Dst Point to destination resource tree.
+ @param Res Point to source resource tree.
+ @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
+ destination resource type.
+
+**/
+VOID
+MergeResourceTree (
+ IN PCI_RESOURCE_NODE *Dst,
+ IN PCI_RESOURCE_NODE *Res,
+ IN BOOLEAN TypeMerge
+ )
+{
+
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Temp;
+
+ ASSERT (Dst != NULL);
+ ASSERT (Res != NULL);
+
+ while (!IsListEmpty (&Res->ChildList)) {
+ CurrentLink = Res->ChildList.ForwardLink;
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (TypeMerge) {
+ Temp->ResType = Dst->ResType;
+ }
+
+ RemoveEntryList (CurrentLink);
+ InsertResourceNode (Dst, Temp);
+ }
+}
+
+/**
+ This function is used to calculate the IO16 aperture
+ for a bridge.
+
+ @param Bridge PCI resource node for bridge.
+
+**/
+VOID
+CalculateApertureIo16 (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Aperture;
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+ UINT64 Offset;
+ EFI_PCI_PLATFORM_POLICY PciPolicy;
+ UINT64 PaddingAperture;
+
+ if (!mPolicyDetermined) {
+ //
+ // Check PciPlatform policy
+ //
+ Status = EFI_NOT_FOUND;
+ PciPolicy = 0;
+ if (gPciPlatformProtocol != NULL) {
+ Status = gPciPlatformProtocol->GetPlatformPolicy (
+ gPciPlatformProtocol,
+ &PciPolicy
+ );
+ }
+
+ if (EFI_ERROR (Status) && gPciOverrideProtocol != NULL) {
+ Status = gPciOverrideProtocol->GetPlatformPolicy (
+ gPciOverrideProtocol,
+ &PciPolicy
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
+ mReserveIsaAliases = TRUE;
+ }
+ if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
+ mReserveVgaAliases = TRUE;
+ }
+ }
+ mPolicyDetermined = TRUE;
+ }
+
+ Aperture = 0;
+ PaddingAperture = 0;
+
+ if (Bridge == NULL) {
+ return ;
+ }
+
+ //
+ // Assume the bridge is aligned
+ //
+ for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
+ ; !IsNull (&Bridge->ChildList, CurrentLink)
+ ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
+ ) {
+
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ if (Node->ResourceUsage == PciResUsagePadding) {
+ ASSERT (PaddingAperture == 0);
+ PaddingAperture = Node->Length;
+ continue;
+ }
+ //
+ // Consider the aperture alignment
+ //
+ Offset = Aperture & (Node->Alignment);
+
+ if (Offset != 0) {
+
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+
+ }
+
+ //
+ // IsaEnable and VGAEnable can not be implemented now.
+ // If both of them are enabled, then the IO resource would
+ // become too limited to meet the requirement of most of devices.
+ //
+ if (mReserveIsaAliases || mReserveVgaAliases) {
+ if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
+ //
+ // Check if there is need to support ISA/VGA decoding
+ // If so, we need to avoid isa/vga aliasing range
+ //
+ if (mReserveIsaAliases) {
+ SkipIsaAliasAperture (
+ &Aperture,
+ Node->Length
+ );
+ Offset = Aperture & (Node->Alignment);
+ if (Offset != 0) {
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+ }
+ } else if (mReserveVgaAliases) {
+ SkipVGAAperture (
+ &Aperture,
+ Node->Length
+ );
+ Offset = Aperture & (Node->Alignment);
+ if (Offset != 0) {
+ Aperture = Aperture + (Node->Alignment + 1) - Offset;
+ }
+ }
+ }
+ }
+
+ Node->Offset = Aperture;
+
+ //
+ // Increment aperture by the length of node
+ //
+ Aperture += Node->Length;
+ }
+
+ //
+ // Adjust the aperture with the bridge's alignment
+ //
+ Offset = Aperture & (Bridge->Alignment);
+
+ if (Offset != 0) {
+ Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
+ }
+
+ Bridge->Length = Aperture;
+ //
+ // At last, adjust the bridge's alignment to the first child's alignment
+ // if the bridge has at least one child
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ if (CurrentLink != &Bridge->ChildList) {
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ if (Node->Alignment > Bridge->Alignment) {
+ Bridge->Alignment = Node->Alignment;
+ }
+ }
+
+ //
+ // Hotplug controller needs padding resources.
+ // Use the larger one between the padding resource and actual occupied resource.
+ //
+ Bridge->Length = MAX (Bridge->Length, PaddingAperture);
+}
+
+/**
+ This function is used to calculate the resource aperture
+ for a given bridge device.
+
+ @param Bridge PCI resource node for given bridge device.
+
+**/
+VOID
+CalculateResourceAperture (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ UINT64 Aperture[2];
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+
+ if (Bridge == NULL) {
+ return ;
+ }
+
+ if (Bridge->ResType == PciBarTypeIo16) {
+
+ CalculateApertureIo16 (Bridge);
+ return ;
+ }
+
+ Aperture[PciResUsageTypical] = 0;
+ Aperture[PciResUsagePadding] = 0;
+ //
+ // Assume the bridge is aligned
+ //
+ for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
+ ; !IsNull (&Bridge->ChildList, CurrentLink)
+ ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
+ ) {
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ //
+ // It's possible for a bridge to contain multiple padding resource
+ // nodes due to DegradeResource().
+ //
+ ASSERT ((Node->ResourceUsage == PciResUsageTypical) ||
+ (Node->ResourceUsage == PciResUsagePadding));
+ ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture));
+ //
+ // Recode current aperture as a offset
+ // Apply padding resource to meet alignment requirement
+ // Node offset will be used in future real allocation
+ //
+ Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node->Alignment + 1);
+
+ //
+ // Record the total aperture.
+ //
+ Aperture[Node->ResourceUsage] = Node->Offset + Node->Length;
+ }
+
+ //
+ // Adjust the aperture with the bridge's alignment
+ //
+ Aperture[PciResUsageTypical] = ALIGN_VALUE (Aperture[PciResUsageTypical], Bridge->Alignment + 1);
+ Aperture[PciResUsagePadding] = ALIGN_VALUE (Aperture[PciResUsagePadding], Bridge->Alignment + 1);
+
+ //
+ // Hotplug controller needs padding resources.
+ // Use the larger one between the padding resource and actual occupied resource.
+ //
+ Bridge->Length = MAX (Aperture[PciResUsageTypical], Aperture[PciResUsagePadding]);
+
+ //
+ // Adjust the bridge's alignment to the MAX (first) alignment of all children.
+ //
+ CurrentLink = Bridge->ChildList.ForwardLink;
+ if (CurrentLink != &Bridge->ChildList) {
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ if (Node->Alignment > Bridge->Alignment) {
+ Bridge->Alignment = Node->Alignment;
+ }
+ }
+}
+
+/**
+ Get IO/Memory resource info for given PCI device.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO .
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+GetResourceFromDevice (
+ IN PCI_IO_DEVICE *PciDev,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+
+ UINT8 Index;
+ PCI_RESOURCE_NODE *Node;
+ BOOLEAN ResourceRequested;
+
+ Node = NULL;
+ ResourceRequested = FALSE;
+
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+
+ switch ((PciDev->PciBar)[Index].BarType) {
+
+ case PciBarTypeMem32:
+ case PciBarTypeOpRom:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ (PciDev->PciBar)[Index].BarType,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeMem64:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypePMem64:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypePMem32:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+
+ Node = CreateResourceNode (
+ PciDev,
+ (PciDev->PciBar)[Index].Length,
+ (PciDev->PciBar)[Index].Alignment,
+ Index,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+ ResourceRequested = TRUE;
+ break;
+
+ case PciBarTypeUnknown:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // Add VF resource
+ //
+ for (Index = 0; Index < PCI_MAX_BAR; Index++) {
+
+ switch ((PciDev->VfPciBar)[Index].BarType) {
+
+ case PciBarTypeMem32:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypeMem64:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypePMem64:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+
+ break;
+
+ case PciBarTypePMem32:
+
+ Node = CreateVfResourceNode (
+ PciDev,
+ (PciDev->VfPciBar)[Index].Length,
+ (PciDev->VfPciBar)[Index].Alignment,
+ Index,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ break;
+
+ case PciBarTypeUnknown:
+ break;
+
+ default:
+ break;
+ }
+ }
+ // If there is no resource requested from this device,
+ // then we indicate this device has been allocated naturally.
+ //
+ if (!ResourceRequested) {
+ PciDev->Allocated = TRUE;
+ }
+}
+
+/**
+ This function is used to create a resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ Node = NULL;
+
+ Node = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE));
+ ASSERT (Node != NULL);
+ if (Node == NULL) {
+ return NULL;
+ }
+
+ Node->Signature = PCI_RESOURCE_SIGNATURE;
+ Node->PciDev = PciDev;
+ Node->Length = Length;
+ Node->Alignment = Alignment;
+ Node->Bar = Bar;
+ Node->ResType = ResType;
+ Node->Reserved = FALSE;
+ Node->ResourceUsage = ResUsage;
+ InitializeListHead (&Node->ChildList);
+
+ return Node;
+}
+
+/**
+ This function is used to create a IOV VF resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given VF PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateVfResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage);
+ if (Node == NULL) {
+ return Node;
+ }
+
+ Node->Virtual = TRUE;
+
+ return Node;
+}
+
+/**
+ This function is used to extract resource request from
+ device node list.
+
+ @param Bridge Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+CreateResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ LIST_ENTRY *CurrentLink;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ //
+ // Create resource nodes for this device by scanning the
+ // Bar array in the device private data
+ // If the upstream bridge doesn't support this device,
+ // no any resource node will be created for this device
+ //
+ GetResourceFromDevice (
+ Temp,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+
+ //
+ // If the device has children, create a bridge resource node for this PPB
+ // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
+ // is aligned with 4KB (smaller alignments may be supported).
+ //
+ IoBridge = CreateResourceNode (
+ Temp,
+ 0,
+ Temp->BridgeIoAlignment,
+ PPB_IO_RANGE,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_MEM32_RANGE,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_PMEM32_RANGE,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_MEM64_RANGE,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ Temp,
+ 0,
+ 0xFFFFF,
+ PPB_PMEM64_RANGE,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Recursively create resource map on this bridge
+ //
+ CreateResourceMap (
+ Temp,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ if (ResourceRequestExisted (IoBridge)) {
+ InsertResourceNode (
+ IoNode,
+ IoBridge
+ );
+ } else {
+ FreePool (IoBridge);
+ IoBridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (Mem32Bridge)) {
+ InsertResourceNode (
+ Mem32Node,
+ Mem32Bridge
+ );
+ } else {
+ FreePool (Mem32Bridge);
+ Mem32Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (PMem32Bridge)) {
+ InsertResourceNode (
+ PMem32Node,
+ PMem32Bridge
+ );
+ } else {
+ FreePool (PMem32Bridge);
+ PMem32Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (Mem64Bridge)) {
+ InsertResourceNode (
+ Mem64Node,
+ Mem64Bridge
+ );
+ } else {
+ FreePool (Mem64Bridge);
+ Mem64Bridge = NULL;
+ }
+
+ //
+ // If there is node under this resource bridge,
+ // then calculate bridge's aperture of this type
+ // and insert it into the respective resource tree.
+ // If no, delete this resource bridge
+ //
+ if (ResourceRequestExisted (PMem64Bridge)) {
+ InsertResourceNode (
+ PMem64Node,
+ PMem64Bridge
+ );
+ } else {
+ FreePool (PMem64Bridge);
+ PMem64Bridge = NULL;
+ }
+
+ }
+
+ //
+ // If it is P2C, apply hard coded resource padding
+ //
+ if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
+ ResourcePaddingForCardBusBridge (
+ Temp,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // To do some platform specific resource padding ...
+ //
+ ResourcePaddingPolicy (
+ Bridge,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ //
+ // Degrade resource if necessary
+ //
+ DegradeResource (
+ Bridge,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+
+ //
+ // Calculate resource aperture for this bridge device
+ //
+ CalculateResourceAperture (Mem32Node);
+ CalculateResourceAperture (PMem32Node);
+ CalculateResourceAperture (Mem64Node);
+ CalculateResourceAperture (PMem64Node);
+ CalculateResourceAperture (IoNode);
+}
+
+/**
+ This function is used to do the resource padding for a specific platform.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingPolicy (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ //
+ // Create padding resource node
+ //
+ if (PciDev->ResourcePaddingDescriptors != NULL) {
+ ApplyResourcePadding (
+ PciDev,
+ IoNode,
+ Mem32Node,
+ PMem32Node,
+ Mem64Node,
+ PMem64Node
+ );
+ }
+}
+
+/**
+ This function is used to degrade resource if the upstream bridge
+ doesn't support certain resource. Degradation path is
+ PMEM64 -> MEM64 -> MEM32
+ PMEM64 -> PMEM32 -> MEM32
+ IO32 -> IO16.
+
+ @param Bridge Pci device instance.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+DegradeResource (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ LIST_ENTRY *ChildDeviceLink;
+ LIST_ENTRY *ChildNodeLink;
+ LIST_ENTRY *NextChildNodeLink;
+ PCI_RESOURCE_NODE *ResourceNode;
+
+ if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) {
+ //
+ // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64
+ // requests in case that if a legacy option ROM image can not access 64-bit resources.
+ //
+ ChildDeviceLink = Bridge->ChildList.ForwardLink;
+ while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) {
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);
+ if (PciIoDevice->RomSize != 0) {
+ if (!IsListEmpty (&Mem64Node->ChildList)) {
+ ChildNodeLink = Mem64Node->ChildList.ForwardLink;
+ while (ChildNodeLink != &Mem64Node->ChildList) {
+ ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
+ NextChildNodeLink = ChildNodeLink->ForwardLink;
+
+ if ((ResourceNode->PciDev == PciIoDevice) &&
+ (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)
+ ) {
+ RemoveEntryList (ChildNodeLink);
+ InsertResourceNode (Mem32Node, ResourceNode);
+ }
+ ChildNodeLink = NextChildNodeLink;
+ }
+ }
+
+ if (!IsListEmpty (&PMem64Node->ChildList)) {
+ ChildNodeLink = PMem64Node->ChildList.ForwardLink;
+ while (ChildNodeLink != &PMem64Node->ChildList) {
+ ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
+ NextChildNodeLink = ChildNodeLink->ForwardLink;
+
+ if ((ResourceNode->PciDev == PciIoDevice) &&
+ (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)
+ ) {
+ RemoveEntryList (ChildNodeLink);
+ InsertResourceNode (PMem32Node, ResourceNode);
+ }
+ ChildNodeLink = NextChildNodeLink;
+ }
+ }
+
+ }
+ ChildDeviceLink = ChildDeviceLink->ForwardLink;
+ }
+ }
+
+ //
+ // If firmware is in 32-bit mode,
+ // then degrade PMEM64/MEM64 requests
+ //
+ if (sizeof (UINTN) <= 4) {
+ MergeResourceTree (
+ Mem32Node,
+ Mem64Node,
+ TRUE
+ );
+
+ MergeResourceTree (
+ PMem32Node,
+ PMem64Node,
+ TRUE
+ );
+ } else {
+ //
+ // if the bridge does not support MEM64, degrade MEM64 to MEM32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ Mem64Node,
+ TRUE
+ );
+ }
+
+ //
+ // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ PMem32Node,
+ PMem64Node,
+ TRUE
+ );
+ }
+
+ //
+ // if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied
+ // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32 to MEM32.
+ //
+ if (!IsListEmpty (&PMem64Node->ChildList) && Bridge->Parent != NULL) {
+ MergeResourceTree (
+ Mem32Node,
+ PMem32Node,
+ TRUE
+ );
+ }
+ }
+
+ //
+ // If bridge doesn't support Pmem32
+ // degrade it to mem32
+ //
+ if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ PMem32Node,
+ TRUE
+ );
+ }
+
+ //
+ // if root bridge supports combined Pmem Mem decoding
+ // merge these two type of resource
+ //
+ if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
+ MergeResourceTree (
+ Mem32Node,
+ PMem32Node,
+ FALSE
+ );
+
+ //
+ // No need to check if to degrade MEM64 after merge, because
+ // if there are PMEM64 still here, 64-bit decode should be supported
+ // by the root bride.
+ //
+ MergeResourceTree (
+ Mem64Node,
+ PMem64Node,
+ FALSE
+ );
+ }
+}
+
+/**
+ Test whether bridge device support decode resource.
+
+ @param Bridge Bridge device instance.
+ @param Decode Decode type according to resource type.
+
+ @return TRUE The bridge device support decode resource.
+ @return FALSE The bridge device don't support decode resource.
+
+**/
+BOOLEAN
+BridgeSupportResourceDecode (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT32 Decode
+ )
+{
+ if (((Bridge->Decodes) & Decode) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function is used to program the resource allocated
+ for each resource node under specified bridge.
+
+ @param Base Base address of resource to be programmed.
+ @param Bridge PCI resource node for the bridge device.
+
+ @retval EFI_SUCCESS Successfully to program all resources
+ on given PCI bridge device.
+ @retval EFI_OUT_OF_RESOURCES Base is all one.
+
+**/
+EFI_STATUS
+ProgramResource (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_RESOURCE_NODE *Node;
+ EFI_STATUS Status;
+
+ if (Base == gAllOne) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != &Bridge->ChildList) {
+
+ Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
+
+ if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
+
+ if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
+ //
+ // Program the PCI Card Bus device
+ //
+ ProgramP2C (Base, Node);
+ } else {
+ //
+ // Program the PCI device BAR
+ //
+ ProgramBar (Base, Node);
+ }
+ } else {
+ //
+ // Program the PCI devices under this bridge
+ //
+ Status = ProgramResource (Base + Node->Offset, Node);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ProgramPpbApperture (Base, Node);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Program Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be programmed.
+ @param Node Point to resource node structure.
+
+**/
+VOID
+ProgramBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ ASSERT (Node->Bar < PCI_MAX_BAR);
+
+ //
+ // Check VF BAR
+ //
+ if (Node->Virtual) {
+ ProgramVfBar (Base, Node);
+ return;
+ }
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ case PciBarTypeMem32:
+ case PciBarTypePMem32:
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+ //
+ // Continue to the case PciBarTypeOpRom to set the BaseAddress.
+ // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture
+ // the MEM32 resource requirement for Option ROM shadow.
+ //
+
+ case PciBarTypeOpRom:
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+
+ break;
+
+ case PciBarTypeMem64:
+ case PciBarTypePMem64:
+
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Program IOV VF Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be programmed.
+ @param Node Point to resource node structure.
+
+**/
+EFI_STATUS
+ProgramVfBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ ASSERT (Node->Bar < PCI_MAX_BAR);
+ ASSERT (Node->Virtual);
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
+
+ case PciBarTypeMem32:
+ case PciBarTypePMem32:
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
+ break;
+
+ case PciBarTypeMem64:
+ case PciBarTypePMem64:
+
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->VfPciBar[Node->Bar]).Offset,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
+ break;
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Program PCI-PCI bridge aperture.
+
+ @param Base Base address for resource.
+ @param Node Point to resource node structure.
+
+**/
+VOID
+ProgramPpbApperture (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT32 Address32;
+
+ Address = 0;
+ //
+ // If no device resource of this PPB, return anyway
+ // Aperture is set default in the initialization code
+ //
+ if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
+ //
+ // For padding resource node, just ignore when programming
+ //
+ return ;
+ }
+
+ PciIo = &(Node->PciDev->PciIo);
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate the PPB resource has been allocated
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch (Node->Bar) {
+
+ case PPB_BAR_0:
+ case PPB_BAR_1:
+ switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
+
+ case PciBarTypeIo16:
+ case PciBarTypeIo32:
+ case PciBarTypeMem32:
+ case PciBarTypePMem32:
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case PciBarTypeMem64:
+ case PciBarTypePMem64:
+
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case PPB_IO_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x1C,
+ 1,
+ &Address32
+ );
+
+ Address32 >>= 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x30,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x1D,
+ 1,
+ &Address32
+ );
+
+ Address32 >>= 8;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x32,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case PPB_MEM32_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x20,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x22,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case PPB_PMEM32_RANGE:
+ case PPB_PMEM64_RANGE:
+
+ Address32 = ((UINT32) (Address)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x24,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) (Address + Node->Length - 1);
+ Address32 = ((UINT32) (Address32)) >> 16;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x26,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 (Address, 32);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0x28,
+ 1,
+ &Address32
+ );
+
+ Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0x2C,
+ 1,
+ &Address32
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Program parent bridge for Option Rom.
+
+ @param PciDevice Pci device instance.
+ @param OptionRomBase Base address for Option Rom.
+ @param Enable Enable or disable PCI memory.
+
+**/
+VOID
+ProgramUpstreamBridgeForRom (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT32 OptionRomBase,
+ IN BOOLEAN Enable
+ )
+{
+ PCI_IO_DEVICE *Parent;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 Base;
+ UINT16 Limit;
+ //
+ // For root bridge, just return.
+ //
+ Parent = PciDevice->Parent;
+ while (Parent != NULL) {
+ if (!IS_PCI_BRIDGE (&Parent->Pci)) {
+ break;
+ }
+
+ PciIo = &Parent->PciIo;
+
+ //
+ // Program PPB to only open a single <= 16MB aperture
+ //
+ if (Enable) {
+ //
+ // Only cover MMIO for Option ROM.
+ //
+ Base = (UINT16) (OptionRomBase >> 16);
+ Limit = (UINT16) ((OptionRomBase + PciDevice->RomSize - 1) >> 16);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);
+
+ PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
+ } else {
+ //
+ // Cover 32bit MMIO for devices below the bridge.
+ //
+ if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) {
+ //
+ // When devices under the bridge contains Option ROM and doesn't require 32bit MMIO.
+ //
+ Base = (UINT16) gAllOne;
+ Limit = (UINT16) gAllZero;
+ } else {
+ Base = (UINT16) ((UINT32) Parent->PciBar[PPB_MEM32_RANGE].BaseAddress >> 16);
+ Limit = (UINT16) ((UINT32) (Parent->PciBar[PPB_MEM32_RANGE].BaseAddress
+ + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >> 16);
+ }
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);
+
+ PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
+ }
+
+ Parent = Parent->Parent;
+ }
+}
+
+/**
+ Test whether resource exists for a bridge.
+
+ @param Bridge Point to resource node for a bridge.
+
+ @retval TRUE There is resource on the given bridge.
+ @retval FALSE There isn't resource on the given bridge.
+
+**/
+BOOLEAN
+ResourceRequestExisted (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ if (Bridge != NULL) {
+ if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Initialize resource pool structure.
+
+ @param ResourcePool Point to resource pool structure. This pool
+ is reset to all zero when returned.
+ @param ResourceType Type of resource.
+
+**/
+VOID
+InitializeResourcePool (
+ IN OUT PCI_RESOURCE_NODE *ResourcePool,
+ IN PCI_BAR_TYPE ResourceType
+ )
+{
+ ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
+ ResourcePool->ResType = ResourceType;
+ ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
+ InitializeListHead (&ResourcePool->ChildList);
+}
+
+/**
+ Destroy given resource tree.
+
+ @param Bridge PCI resource root node of resource tree.
+
+**/
+VOID
+DestroyResourceTree (
+ IN PCI_RESOURCE_NODE *Bridge
+ )
+{
+ PCI_RESOURCE_NODE *Temp;
+ LIST_ENTRY *CurrentLink;
+
+ while (!IsListEmpty (&Bridge->ChildList)) {
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
+ ASSERT (Temp);
+
+ RemoveEntryList (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
+ DestroyResourceTree (Temp);
+ }
+
+ FreePool (Temp);
+ }
+}
+
+/**
+ Insert resource padding for P2C.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingForCardBusBridge (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ PCI_RESOURCE_NODE *Node;
+
+ Node = NULL;
+
+ //
+ // Memory Base/Limit Register 0
+ // Bar 1 decodes memory range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x2000000,
+ 0x1ffffff,
+ 1,
+ PciBarTypeMem32,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+
+ //
+ // Memory Base/Limit Register 1
+ // Bar 2 decodes memory range1
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x2000000,
+ 0x1ffffff,
+ 2,
+ PciBarTypePMem32,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+
+ //
+ // Io Base/Limit
+ // Bar 3 decodes io range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x100,
+ 0xff,
+ 3,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+
+ //
+ // Io Base/Limit
+ // Bar 4 decodes io range 0
+ //
+ Node = CreateResourceNode (
+ PciDev,
+ 0x100,
+ 0xff,
+ 4,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+}
+
+/**
+ Program PCI Card device register for given resource node.
+
+ @param Base Base address of PCI Card device to be programmed.
+ @param Node Given resource node.
+
+**/
+VOID
+ProgramP2C (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Address;
+ UINT64 TempAddress;
+ UINT16 BridgeControl;
+
+ Address = 0;
+ PciIo = &(Node->PciDev->PciIo);
+
+ Address = Base + Node->Offset;
+
+ //
+ // Indicate pci bus driver has allocated
+ // resource for this device
+ // It might be a temporary solution here since
+ // pci device could have multiple bar
+ //
+ Node->PciDev->Allocated = TRUE;
+
+ switch (Node->Bar) {
+
+ case P2C_BAR_0:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ (Node->PciDev->PciBar[Node->Bar]).Offset,
+ 1,
+ &Address
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ break;
+
+ case P2C_MEM_1:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_0,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_LIMIT_0,
+ 1,
+ &TempAddress
+ );
+
+ if (Node->ResType == PciBarTypeMem32) {
+ //
+ // Set non-prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ } else {
+ //
+ // Set prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+ }
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+
+ break;
+
+ case P2C_MEM_2:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_1,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_LIMIT_1,
+ 1,
+ &TempAddress
+ );
+
+ if (Node->ResType == PciBarTypeMem32) {
+
+ //
+ // Set non-prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ } else {
+
+ //
+ // Set prefetchable bit
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+
+ BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_CARD_BRIDGE_CONTROL,
+ 1,
+ &BridgeControl
+ );
+ }
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+ break;
+
+ case P2C_IO_1:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_0_LOWER,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_LIMIT_0_LOWER,
+ 1,
+ &TempAddress
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+
+ break;
+
+ case P2C_IO_2:
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_1_LOWER,
+ 1,
+ &Address
+ );
+
+ TempAddress = Address + Node->Length - 1;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_LIMIT_1_LOWER,
+ 1,
+ &TempAddress
+ );
+
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
+ Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create padding resource node.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ApplyResourcePadding (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
+ PCI_RESOURCE_NODE *Node;
+ UINT8 DummyBarIndex;
+
+ DummyBarIndex = 0;
+ Ptr = PciDev->ResourcePaddingDescriptors;
+
+ while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
+
+ if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
+ if (Ptr->AddrLen != 0) {
+
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeIo16,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ IoNode,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+
+ if (Ptr->AddrSpaceGranularity == 32) {
+
+ //
+ // prefetchable
+ //
+ if (Ptr->SpecificFlag == 0x6) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypePMem32,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ PMem32Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ //
+ // Non-prefetchable
+ //
+ if (Ptr->SpecificFlag == 0) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeMem32,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ Mem32Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+ }
+
+ if (Ptr->AddrSpaceGranularity == 64) {
+
+ //
+ // prefetchable
+ //
+ if (Ptr->SpecificFlag == 0x6) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypePMem64,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ PMem64Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+
+ //
+ // Non-prefetchable
+ //
+ if (Ptr->SpecificFlag == 0) {
+ if (Ptr->AddrLen != 0) {
+ Node = CreateResourceNode (
+ PciDev,
+ Ptr->AddrLen,
+ Ptr->AddrRangeMax,
+ DummyBarIndex,
+ PciBarTypeMem64,
+ PciResUsagePadding
+ );
+ InsertResourceNode (
+ Mem64Node,
+ Node
+ );
+ }
+
+ Ptr++;
+ continue;
+ }
+ }
+ }
+
+ Ptr++;
+ }
+}
+
+/**
+ Get padding resource for PCI-PCI bridge.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determines
+ whether need to pad resource for them.
+**/
+VOID
+GetResourcePaddingPpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
+ GetResourcePaddingForHpb (PciIoDevice);
+ }
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h
new file mode 100644
index 000000000..9f2de291b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h
@@ -0,0 +1,456 @@
+/** @file
+ PCI resources support functions declaration for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_RESOURCE_SUPPORT_H_
+#define _EFI_PCI_RESOURCE_SUPPORT_H_
+
+typedef enum {
+ PciResUsageTypical,
+ PciResUsagePadding
+} PCI_RESOURCE_USAGE;
+
+#define PCI_RESOURCE_SIGNATURE SIGNATURE_32 ('p', 'c', 'r', 'c')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ LIST_ENTRY ChildList;
+ PCI_IO_DEVICE *PciDev;
+ UINT64 Alignment;
+ UINT64 Offset;
+ UINT8 Bar;
+ PCI_BAR_TYPE ResType;
+ UINT64 Length;
+ BOOLEAN Reserved;
+ PCI_RESOURCE_USAGE ResourceUsage;
+ BOOLEAN Virtual;
+} PCI_RESOURCE_NODE;
+
+#define RESOURCE_NODE_FROM_LINK(a) \
+ CR (a, PCI_RESOURCE_NODE, Link, PCI_RESOURCE_SIGNATURE)
+
+/**
+ The function is used to skip VGA range.
+
+ @param Start Returned start address including VGA range.
+ @param Length The length of VGA range.
+
+**/
+VOID
+SkipVGAAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ );
+
+/**
+ This function is used to skip ISA aliasing aperture.
+
+ @param Start Returned start address including ISA aliasing aperture.
+ @param Length The length of ISA aliasing aperture.
+
+**/
+VOID
+SkipIsaAliasAperture (
+ OUT UINT64 *Start,
+ IN UINT64 Length
+ );
+
+/**
+ This function inserts a resource node into the resource list.
+ The resource list is sorted in descend order.
+
+ @param Bridge PCI resource node for bridge.
+ @param ResNode Resource node want to be inserted.
+
+**/
+VOID
+InsertResourceNode (
+ IN OUT PCI_RESOURCE_NODE *Bridge,
+ IN PCI_RESOURCE_NODE *ResNode
+ );
+
+/**
+ This routine is used to merge two different resource trees in need of
+ resource degradation.
+
+ For example, if an upstream PPB doesn't support,
+ prefetchable memory decoding, the PCI bus driver will choose to call this function
+ to merge prefetchable memory resource list into normal memory list.
+
+ If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
+ type.
+ If Dst is NULL or Res is NULL, ASSERT ().
+
+ @param Dst Point to destination resource tree.
+ @param Res Point to source resource tree.
+ @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of
+ destination resource type.
+
+**/
+VOID
+MergeResourceTree (
+ IN PCI_RESOURCE_NODE *Dst,
+ IN PCI_RESOURCE_NODE *Res,
+ IN BOOLEAN TypeMerge
+ );
+
+/**
+ This function is used to calculate the IO16 aperture
+ for a bridge.
+
+ @param Bridge PCI resource node for bridge.
+
+**/
+VOID
+CalculateApertureIo16 (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ This function is used to calculate the resource aperture
+ for a given bridge device.
+
+ @param Bridge PCI resource node for given bridge device.
+
+**/
+VOID
+CalculateResourceAperture (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Get IO/Memory resource info for given PCI device.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO .
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+GetResourceFromDevice (
+ IN PCI_IO_DEVICE *PciDev,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to create a resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ );
+
+/**
+ This function is used to create a IOV VF resource node.
+
+ @param PciDev Pci device instance.
+ @param Length Length of Io/Memory resource.
+ @param Alignment Alignment of resource.
+ @param Bar Bar index.
+ @param ResType Type of resource: IO/Memory.
+ @param ResUsage Resource usage.
+
+ @return PCI resource node created for given VF PCI device.
+ NULL means PCI resource node is not created.
+
+**/
+PCI_RESOURCE_NODE *
+CreateVfResourceNode (
+ IN PCI_IO_DEVICE *PciDev,
+ IN UINT64 Length,
+ IN UINT64 Alignment,
+ IN UINT8 Bar,
+ IN PCI_BAR_TYPE ResType,
+ IN PCI_RESOURCE_USAGE ResUsage
+ );
+
+/**
+ This function is used to extract resource request from
+ device node list.
+
+ @param Bridge Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+CreateResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN OUT PCI_RESOURCE_NODE *IoNode,
+ IN OUT PCI_RESOURCE_NODE *Mem32Node,
+ IN OUT PCI_RESOURCE_NODE *PMem32Node,
+ IN OUT PCI_RESOURCE_NODE *Mem64Node,
+ IN OUT PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to do the resource padding for a specific platform.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingPolicy (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ This function is used to degrade resource if the upstream bridge
+ doesn't support certain resource. Degradation path is
+ PMEM64 -> MEM64 -> MEM32
+ PMEM64 -> PMEM32 -> MEM32
+ IO32 -> IO16.
+
+ @param Bridge Pci device instance.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+DegradeResource (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Test whether bridge device support decode resource.
+
+ @param Bridge Bridge device instance.
+ @param Decode Decode type according to resource type.
+
+ @return TRUE The bridge device support decode resource.
+ @return FALSE The bridge device don't support decode resource.
+
+**/
+BOOLEAN
+BridgeSupportResourceDecode (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT32 Decode
+ );
+
+/**
+ This function is used to program the resource allocated
+ for each resource node under specified bridge.
+
+ @param Base Base address of resource to be programmed.
+ @param Bridge PCI resource node for the bridge device.
+
+ @retval EFI_SUCCESS Successfully to program all resources
+ on given PCI bridge device.
+ @retval EFI_OUT_OF_RESOURCES Base is all one.
+
+**/
+EFI_STATUS
+ProgramResource (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Program Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be programmed.
+ @param Node Point to resource node structure.
+
+**/
+VOID
+ProgramBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program IOV VF Bar register for PCI device.
+
+ @param Base Base address for PCI device resource to be programmed.
+ @param Node Point to resource node structure.
+
+**/
+EFI_STATUS
+ProgramVfBar (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program PCI-PCI bridge aperture.
+
+ @param Base Base address for resource.
+ @param Node Point to resource node structure.
+
+**/
+VOID
+ProgramPpbApperture (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Program parent bridge for Option Rom.
+
+ @param PciDevice Pci device instance.
+ @param OptionRomBase Base address for Option Rom.
+ @param Enable Enable or disable PCI memory.
+
+**/
+VOID
+ProgramUpstreamBridgeForRom (
+ IN PCI_IO_DEVICE *PciDevice,
+ IN UINT32 OptionRomBase,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Test whether resource exists for a bridge.
+
+ @param Bridge Point to resource node for a bridge.
+
+ @retval TRUE There is resource on the given bridge.
+ @retval FALSE There isn't resource on the given bridge.
+
+**/
+BOOLEAN
+ResourceRequestExisted (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Initialize resource pool structure.
+
+ @param ResourcePool Point to resource pool structure. This pool
+ is reset to all zero when returned.
+ @param ResourceType Type of resource.
+
+**/
+VOID
+InitializeResourcePool (
+ IN OUT PCI_RESOURCE_NODE *ResourcePool,
+ IN PCI_BAR_TYPE ResourceType
+ );
+
+/**
+ Destroy given resource tree.
+
+ @param Bridge PCI resource root node of resource tree.
+
+**/
+VOID
+DestroyResourceTree (
+ IN PCI_RESOURCE_NODE *Bridge
+ );
+
+/**
+ Insert resource padding for P2C.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ResourcePaddingForCardBusBridge (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Program PCI Card device register for given resource node.
+
+ @param Base Base address of PCI Card device to be programmed.
+ @param Node Given resource node.
+
+**/
+VOID
+ProgramP2C (
+ IN UINT64 Base,
+ IN PCI_RESOURCE_NODE *Node
+ );
+
+/**
+ Create padding resource node.
+
+ @param PciDev Pci device instance.
+ @param IoNode Resource info node for IO.
+ @param Mem32Node Resource info node for 32-bit memory.
+ @param PMem32Node Resource info node for 32-bit Prefetchable Memory.
+ @param Mem64Node Resource info node for 64-bit memory.
+ @param PMem64Node Resource info node for 64-bit Prefetchable Memory.
+
+**/
+VOID
+ApplyResourcePadding (
+ IN PCI_IO_DEVICE *PciDev,
+ IN PCI_RESOURCE_NODE *IoNode,
+ IN PCI_RESOURCE_NODE *Mem32Node,
+ IN PCI_RESOURCE_NODE *PMem32Node,
+ IN PCI_RESOURCE_NODE *Mem64Node,
+ IN PCI_RESOURCE_NODE *PMem64Node
+ );
+
+/**
+ Get padding resource for PCI-PCI bridge.
+
+ @param PciIoDevice PCI-PCI bridge device instance.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determines
+ whether need to pad resource for them.
+**/
+VOID
+GetResourcePaddingPpb (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c
new file mode 100644
index 000000000..5575a364a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.c
@@ -0,0 +1,135 @@
+/** @file
+ Set up ROM Table for PCI Bus module.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+//
+// PCI ROM image information
+//
+typedef struct {
+ EFI_HANDLE ImageHandle;
+ UINTN Seg;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Func;
+ VOID *RomImage;
+ UINT64 RomSize;
+} PCI_ROM_IMAGE;
+
+UINTN mNumberOfPciRomImages = 0;
+UINTN mMaxNumberOfPciRomImages = 0;
+PCI_ROM_IMAGE *mRomImageTable = NULL;
+
+/**
+ Add the Rom Image to internal database for later PCI light enumeration.
+
+ @param ImageHandle Option Rom image handle.
+ @param Seg Segment of PCI space.
+ @param Bus Bus NO of PCI space.
+ @param Dev Dev NO of PCI space.
+ @param Func Func NO of PCI space.
+ @param RomImage Option Rom buffer.
+ @param RomSize Size of Option Rom buffer.
+**/
+VOID
+PciRomAddImageMapping (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN Seg,
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Func,
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ )
+{
+ UINTN Index;
+ PCI_ROM_IMAGE *NewTable;
+
+ for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
+ if (mRomImageTable[Index].Seg == Seg &&
+ mRomImageTable[Index].Bus == Bus &&
+ mRomImageTable[Index].Dev == Dev &&
+ mRomImageTable[Index].Func == Func) {
+ //
+ // Expect once RomImage and RomSize are recorded, they will be passed in
+ // later when updating ImageHandle
+ //
+ ASSERT ((mRomImageTable[Index].RomImage == NULL) || (RomImage == mRomImageTable[Index].RomImage));
+ ASSERT ((mRomImageTable[Index].RomSize == 0 ) || (RomSize == mRomImageTable[Index].RomSize ));
+ break;
+ }
+ }
+
+ if (Index == mNumberOfPciRomImages) {
+ //
+ // Rom Image Table buffer needs to grow.
+ //
+ if (mNumberOfPciRomImages == mMaxNumberOfPciRomImages) {
+ NewTable = ReallocatePool (
+ mMaxNumberOfPciRomImages * sizeof (PCI_ROM_IMAGE),
+ (mMaxNumberOfPciRomImages + 0x20) * sizeof (PCI_ROM_IMAGE),
+ mRomImageTable
+ );
+ if (NewTable == NULL) {
+ return ;
+ }
+
+ mRomImageTable = NewTable;
+ mMaxNumberOfPciRomImages += 0x20;
+ }
+ //
+ // Record the new PCI device
+ //
+ mRomImageTable[Index].Seg = Seg;
+ mRomImageTable[Index].Bus = Bus;
+ mRomImageTable[Index].Dev = Dev;
+ mRomImageTable[Index].Func = Func;
+ mNumberOfPciRomImages++;
+ }
+
+ mRomImageTable[Index].ImageHandle = ImageHandle;
+ mRomImageTable[Index].RomImage = RomImage;
+ mRomImageTable[Index].RomSize = RomSize;
+}
+
+/**
+ Get Option rom driver's mapping for PCI device.
+
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Found Image mapping.
+ @retval FALSE Cannot found image mapping.
+
+**/
+BOOLEAN
+PciRomGetImageMapping (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN Index;
+
+ PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
+
+ for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
+ if (mRomImageTable[Index].Seg == PciRootBridgeIo->SegmentNumber &&
+ mRomImageTable[Index].Bus == PciIoDevice->BusNumber &&
+ mRomImageTable[Index].Dev == PciIoDevice->DeviceNumber &&
+ mRomImageTable[Index].Func == PciIoDevice->FunctionNumber ) {
+
+ if (mRomImageTable[Index].ImageHandle != NULL) {
+ AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle, NULL);
+ }
+ PciIoDevice->PciIo.RomImage = mRomImageTable[Index].RomImage;
+ PciIoDevice->PciIo.RomSize = mRomImageTable[Index].RomSize;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h
new file mode 100644
index 000000000..4c2a4e198
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciBusDxe/PciRomTable.h
@@ -0,0 +1,48 @@
+/** @file
+ Set up ROM Table for PCI Bus module.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PCI_ROM_TABLE_H_
+#define _EFI_PCI_ROM_TABLE_H_
+
+/**
+ Add the Rom Image to internal database for later PCI light enumeration.
+
+ @param ImageHandle Option Rom image handle.
+ @param Seg Segment of PCI space.
+ @param Bus Bus NO of PCI space.
+ @param Dev Dev NO of PCI space.
+ @param Func Func NO of PCI space.
+ @param RomImage Option Rom buffer.
+ @param RomSize Size of Option Rom buffer.
+**/
+VOID
+PciRomAddImageMapping (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN Seg,
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Func,
+ IN VOID *RomImage,
+ IN UINT64 RomSize
+ );
+
+/**
+ Get Option rom driver's mapping for PCI device.
+
+ @param PciIoDevice Device instance.
+
+ @retval TRUE Found Image mapping.
+ @retval FALSE Cannot found image mapping.
+
+**/
+BOOLEAN
+PciRomGetImageMapping (
+ IN PCI_IO_DEVICE *PciIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
new file mode 100644
index 000000000..4ab9415c9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
@@ -0,0 +1,1596 @@
+/** @file
+
+ Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciHostResource.h"
+
+EFI_CPU_IO2_PROTOCOL *mCpuIo;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
+ L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"
+};
+
+EDKII_IOMMU_PROTOCOL *mIoMmu;
+EFI_EVENT mIoMmuEvent;
+VOID *mIoMmuRegistration;
+
+/**
+ This routine gets translation offset from a root bridge instance by resource type.
+
+ @param RootBridge The Root Bridge Instance for the resources.
+ @param ResourceType The Resource Type of the translation offset.
+
+ @retval The Translation Offset of the specified resource.
+**/
+UINT64
+GetTranslationByResourceType (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,
+ IN PCI_RESOURCE_TYPE ResourceType
+ )
+{
+ switch (ResourceType) {
+ case TypeIo:
+ return RootBridge->Io.Translation;
+ case TypeMem32:
+ return RootBridge->Mem.Translation;
+ case TypePMem32:
+ return RootBridge->PMem.Translation;
+ case TypeMem64:
+ return RootBridge->MemAbove4G.Translation;
+ case TypePMem64:
+ return RootBridge->PMemAbove4G.Translation;
+ case TypeBus:
+ return RootBridge->Bus.Translation;
+ default:
+ ASSERT (FALSE);
+ return 0;
+ }
+}
+
+/**
+ Ensure the compatibility of an IO space descriptor with the IO aperture.
+
+ The IO space descriptor can come from the GCD IO space map, or it can
+ represent a gap between two neighboring IO space descriptors. In the latter
+ case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent.
+
+ If the IO space descriptor already has type EfiGcdIoTypeIo, then no action is
+ taken -- it is by definition compatible with the aperture.
+
+ Otherwise, the intersection of the IO space descriptor is calculated with the
+ aperture. If the intersection is the empty set (no overlap), no action is
+ taken; the IO space descriptor is compatible with the aperture.
+
+ Otherwise, the type of the descriptor is investigated again. If the type is
+ EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor with
+ such a type), then an attempt is made to add the intersection as IO space to
+ the GCD IO space map. This ensures continuity for the aperture, and the
+ descriptor is deemed compatible with the aperture.
+
+ Otherwise, the IO space descriptor is incompatible with the IO aperture.
+
+ @param[in] Base Base address of the aperture.
+ @param[in] Length Length of the aperture.
+ @param[in] Descriptor The descriptor to ensure compatibility with the
+ aperture for.
+
+ @retval EFI_SUCCESS The descriptor is compatible. The GCD IO space
+ map may have been updated, for continuity
+ within the aperture.
+ @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
+ @return Error codes from gDS->AddIoSpace().
+**/
+EFI_STATUS
+IntersectIoDescriptor (
+ IN UINT64 Base,
+ IN UINT64 Length,
+ IN CONST EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ UINT64 IntersectionBase;
+ UINT64 IntersectionEnd;
+ EFI_STATUS Status;
+
+ if (Descriptor->GcdIoType == EfiGcdIoTypeIo) {
+ return EFI_SUCCESS;
+ }
+
+ IntersectionBase = MAX (Base, Descriptor->BaseAddress);
+ IntersectionEnd = MIN (Base + Length,
+ Descriptor->BaseAddress + Descriptor->Length);
+ if (IntersectionBase >= IntersectionEnd) {
+ //
+ // The descriptor and the aperture don't overlap.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (Descriptor->GcdIoType == EfiGcdIoTypeNonExistent) {
+ Status = gDS->AddIoSpace (EfiGcdIoTypeIo, IntersectionBase,
+ IntersectionEnd - IntersectionBase);
+
+ DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
+ "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
+ IntersectionBase, IntersectionEnd, Status));
+ return Status;
+ }
+
+ DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u conflicts with "
+ "aperture [%Lx, %Lx)\n", gEfiCallerBaseName, __FUNCTION__,
+ Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
+ (UINT32)Descriptor->GcdIoType, Base, Base + Length));
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Add IO space to GCD.
+ The routine checks the GCD database and only adds those which are
+ not added in the specified range to GCD.
+
+ @param Base Base address of the IO space.
+ @param Length Length of the IO space.
+
+ @retval EFI_SUCCES The IO space was added successfully.
+**/
+EFI_STATUS
+AddIoSpace (
+ IN UINT64 Base,
+ IN UINT64 Length
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;
+
+ Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a: %a: GetIoSpaceMap(): %r\n",
+ gEfiCallerBaseName, __FUNCTION__, Status));
+ return Status;
+ }
+
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]);
+ if (EFI_ERROR (Status)) {
+ goto FreeIoSpaceMap;
+ }
+ }
+
+ DEBUG_CODE (
+ //
+ // Make sure there are adjacent descriptors covering [Base, Base + Length).
+ // It is possible that they have not been merged; merging can be prevented
+ // by allocation.
+ //
+ UINT64 CheckBase;
+ EFI_STATUS CheckStatus;
+ EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor;
+
+ for (CheckBase = Base;
+ CheckBase < Base + Length;
+ CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
+ CheckStatus = gDS->GetIoSpaceDescriptor (CheckBase, &Descriptor);
+ ASSERT_EFI_ERROR (CheckStatus);
+ ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo);
+ }
+ );
+
+FreeIoSpaceMap:
+ FreePool (IoSpaceMap);
+
+ return Status;
+}
+
+/**
+ Ensure the compatibility of a memory space descriptor with the MMIO aperture.
+
+ The memory space descriptor can come from the GCD memory space map, or it can
+ represent a gap between two neighboring memory space descriptors. In the
+ latter case, the GcdMemoryType field is expected to be
+ EfiGcdMemoryTypeNonExistent.
+
+ If the memory space descriptor already has type
+ EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
+ required capabilities, then no action is taken -- it is by definition
+ compatible with the aperture.
+
+ Otherwise, the intersection of the memory space descriptor is calculated with
+ the aperture. If the intersection is the empty set (no overlap), no action is
+ taken; the memory space descriptor is compatible with the aperture.
+
+ Otherwise, the type of the descriptor is investigated again. If the type is
+ EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
+ such a type), then an attempt is made to add the intersection as MMIO space
+ to the GCD memory space map, with the specified capabilities. This ensures
+ continuity for the aperture, and the descriptor is deemed compatible with the
+ aperture.
+
+ Otherwise, the memory space descriptor is incompatible with the MMIO
+ aperture.
+
+ @param[in] Base Base address of the aperture.
+ @param[in] Length Length of the aperture.
+ @param[in] Capabilities Capabilities required by the aperture.
+ @param[in] Descriptor The descriptor to ensure compatibility with the
+ aperture for.
+
+ @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
+ space map may have been updated, for
+ continuity within the aperture.
+ @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
+ @return Error codes from gDS->AddMemorySpace().
+**/
+EFI_STATUS
+IntersectMemoryDescriptor (
+ IN UINT64 Base,
+ IN UINT64 Length,
+ IN UINT64 Capabilities,
+ IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ UINT64 IntersectionBase;
+ UINT64 IntersectionEnd;
+ EFI_STATUS Status;
+
+ if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo &&
+ (Descriptor->Capabilities & Capabilities) == Capabilities) {
+ return EFI_SUCCESS;
+ }
+
+ IntersectionBase = MAX (Base, Descriptor->BaseAddress);
+ IntersectionEnd = MIN (Base + Length,
+ Descriptor->BaseAddress + Descriptor->Length);
+ if (IntersectionBase >= IntersectionEnd) {
+ //
+ // The descriptor and the aperture don't overlap.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
+ IntersectionBase, IntersectionEnd - IntersectionBase,
+ Capabilities);
+
+ DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
+ "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
+ IntersectionBase, IntersectionEnd, Status));
+ return Status;
+ }
+
+ DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
+ "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName, __FUNCTION__,
+ Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
+ (UINT32)Descriptor->GcdMemoryType, Descriptor->Capabilities,
+ Base, Base + Length, Capabilities));
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Add MMIO space to GCD.
+ The routine checks the GCD database and only adds those which are
+ not added in the specified range to GCD.
+
+ @param Base Base address of the MMIO space.
+ @param Length Length of the MMIO space.
+ @param Capabilities Capabilities of the MMIO space.
+
+ @retval EFI_SUCCES The MMIO space was added successfully.
+**/
+EFI_STATUS
+AddMemoryMappedIoSpace (
+ IN UINT64 Base,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a: %a: GetMemorySpaceMap(): %r\n",
+ gEfiCallerBaseName, __FUNCTION__, Status));
+ return Status;
+ }
+
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ Status = IntersectMemoryDescriptor (Base, Length, Capabilities,
+ &MemorySpaceMap[Index]);
+ if (EFI_ERROR (Status)) {
+ goto FreeMemorySpaceMap;
+ }
+ }
+
+ DEBUG_CODE (
+ //
+ // Make sure there are adjacent descriptors covering [Base, Base + Length).
+ // It is possible that they have not been merged; merging can be prevented
+ // by allocation and different capabilities.
+ //
+ UINT64 CheckBase;
+ EFI_STATUS CheckStatus;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ for (CheckBase = Base;
+ CheckBase < Base + Length;
+ CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
+ CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
+ ASSERT_EFI_ERROR (CheckStatus);
+ ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
+ ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
+ }
+ );
+
+FreeMemorySpaceMap:
+ FreePool (MemorySpaceMap);
+
+ return Status;
+}
+
+/**
+ Event notification that is fired when IOMMU protocol is installed.
+
+ @param Event The Event that is being processed.
+ @param Context Event Context.
+
+**/
+VOID
+EFIAPI
+IoMmuProtocolCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);
+ if (!EFI_ERROR(Status)) {
+ gBS->CloseEvent (mIoMmuEvent);
+ }
+}
+
+/**
+
+ Entry point of this driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_DEVICE_ERROR Fail to install PCI_ROOT_BRIDGE_IO protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePciHostBridge (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_ROOT_BRIDGE *RootBridges;
+ UINTN RootBridgeCount;
+ UINTN Index;
+ PCI_ROOT_BRIDGE_APERTURE *MemApertures[4];
+ UINTN MemApertureIndex;
+ BOOLEAN ResourceAssigned;
+ LIST_ENTRY *Link;
+ UINT64 HostAddress;
+
+ RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
+ if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Most systems in the world including complex servers have only one Host Bridge.
+ //
+ HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
+ ASSERT (HostBridge != NULL);
+
+ HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;
+ HostBridge->CanRestarted = TRUE;
+ InitializeListHead (&HostBridge->RootBridges);
+ ResourceAssigned = FALSE;
+
+ //
+ // Create Root Bridge Device Handle in this Host Bridge
+ //
+ for (Index = 0; Index < RootBridgeCount; Index++) {
+ //
+ // Create Root Bridge Handle Instance
+ //
+ RootBridge = CreateRootBridge (&RootBridges[Index]);
+ ASSERT (RootBridge != NULL);
+ if (RootBridge == NULL) {
+ continue;
+ }
+
+ //
+ // Make sure all root bridges share the same ResourceAssigned value.
+ //
+ if (Index == 0) {
+ ResourceAssigned = RootBridges[Index].ResourceAssigned;
+ } else {
+ ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
+ }
+
+ if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {
+ //
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+ // For GCD resource manipulation, we need to use host address.
+ //
+ HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,
+ RootBridges[Index].Io.Translation);
+
+ Status = AddIoSpace (
+ HostAddress,
+ RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (ResourceAssigned) {
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAddress,
+ EfiGcdIoTypeIo,
+ 0,
+ RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,
+ &HostAddress,
+ gImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Add all the Mem/PMem aperture to GCD
+ // Mem/PMem shouldn't overlap with each other
+ // Root bridge which needs to combine MEM and PMEM should only report
+ // the MEM aperture in Mem
+ //
+ MemApertures[0] = &RootBridges[Index].Mem;
+ MemApertures[1] = &RootBridges[Index].MemAbove4G;
+ MemApertures[2] = &RootBridges[Index].PMem;
+ MemApertures[3] = &RootBridges[Index].PMemAbove4G;
+
+ for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
+ if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
+ //
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+ // For GCD resource manipulation, we need to use host address.
+ //
+ HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,
+ MemApertures[MemApertureIndex]->Translation);
+ Status = AddMemoryMappedIoSpace (
+ HostAddress,
+ MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+ EFI_MEMORY_UC
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gDS->SetMemorySpaceAttributes (
+ HostAddress,
+ MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+ EFI_MEMORY_UC
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
+ }
+ if (ResourceAssigned) {
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+ &HostAddress,
+ gImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+ //
+ // Insert Root Bridge Handle Instance
+ //
+ InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
+ }
+
+ //
+ // When resources were assigned, it's not needed to expose
+ // PciHostBridgeResourceAllocation protocol.
+ //
+ if (!ResourceAssigned) {
+ HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
+ HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
+ HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
+ HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
+ HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
+ HostBridge->ResAlloc.SubmitResources = SubmitResources;
+ HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
+ HostBridge->ResAlloc.PreprocessController = PreprocessController;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &HostBridge->Handle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &RootBridge->Handle,
+ &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,
+ &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
+
+ if (!EFI_ERROR (Status)) {
+ mIoMmuEvent = EfiCreateProtocolNotifyEvent (
+ &gEdkiiIoMmuProtocolGuid,
+ TPL_CALLBACK,
+ IoMmuProtocolCallback,
+ NULL,
+ &mIoMmuRegistration
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
+
+ @param HostBridge The Host Bridge Instance where the resource adjustment happens.
+**/
+VOID
+ResourceConflict (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridge
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ LIST_ENTRY *Link;
+ UINTN RootBridgeCount;
+ PCI_RESOURCE_TYPE Index;
+ PCI_RES_NODE *ResAllocNode;
+
+ RootBridgeCount = 0;
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridgeCount++;
+ }
+
+ Resources = AllocatePool (
+ RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ ASSERT (Resources != NULL);
+
+ for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ ResAllocNode = &RootBridge->ResAllocNode[Index];
+
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Descriptor->AddrRangeMin = ResAllocNode->Base;
+ Descriptor->AddrRangeMax = ResAllocNode->Alignment;
+ Descriptor->AddrLen = ResAllocNode->Length;
+ Descriptor->SpecificFlag = 0;
+ switch (ResAllocNode->Type) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+
+ case TypeBus:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ break;
+
+ default:
+ break;
+ }
+
+ Descriptor++;
+ }
+ //
+ // Terminate the root bridge resources.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);
+ }
+ //
+ // Terminate the host bridge resources.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));
+ PciHostBridgeResourceConflict (HostBridge->Handle, Resources);
+ FreePool (Resources);
+}
+
+/**
+ Allocate Length of MMIO or IO resource with alignment BitsOfAlignment
+ from GCD range [BaseAddress, Limit).
+
+ @param Mmio TRUE for MMIO and FALSE for IO.
+ @param Length Length of the resource to allocate.
+ @param BitsOfAlignment Alignment of the resource to allocate.
+ @param BaseAddress The starting address the allocation is from.
+ @param Limit The ending address the allocation is to.
+
+ @retval The base address of the allocated resource or MAX_UINT64 if allocation
+ fails.
+**/
+UINT64
+AllocateResource (
+ BOOLEAN Mmio,
+ UINT64 Length,
+ UINTN BitsOfAlignment,
+ UINT64 BaseAddress,
+ UINT64 Limit
+ )
+{
+ EFI_STATUS Status;
+
+ if (BaseAddress < Limit) {
+ //
+ // Have to make sure Aligment is handled since we are doing direct address allocation
+ // Strictly speaking, alignment requirement should be applied to device
+ // address instead of host address which is used in GCD manipulation below,
+ // but as we restrict the alignment of Translation to be larger than any BAR
+ // alignment in the root bridge, we can simplify the situation and consider
+ // the same alignment requirement is also applied to host address.
+ //
+ BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));
+
+ while (BaseAddress + Length <= Limit + 1) {
+ if (Mmio) {
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment,
+ Length,
+ &BaseAddress,
+ gImageHandle,
+ NULL
+ );
+ } else {
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAddress,
+ EfiGcdIoTypeIo,
+ BitsOfAlignment,
+ Length,
+ &BaseAddress,
+ gImageHandle,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return BaseAddress;
+ }
+ BaseAddress += LShiftU64 (1, BitsOfAlignment);
+ }
+ }
+ return MAX_UINT64;
+}
+
+/**
+
+ Enter a certain phase of the PCI enumeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Phase The phase during enumeration.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.
+ @retval EFI_NOT_READY Resources have not been submitted yet.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ LIST_ENTRY *Link;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN BitsOfAlignment;
+ UINT64 Alignment;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ PCI_RESOURCE_TYPE Index;
+ PCI_RESOURCE_TYPE Index1;
+ PCI_RESOURCE_TYPE Index2;
+ BOOLEAN ResNodeHandled[TypeMax];
+ UINT64 MaxAlignment;
+ UINT64 Translation;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+
+ switch (Phase) {
+ case EfiPciHostBridgeBeginEnumeration:
+ if (!HostBridge->CanRestarted) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Reset Root Bridge
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+
+ RootBridge->ResourceSubmitted = FALSE;
+ }
+ }
+
+ HostBridge->CanRestarted = TRUE;
+ break;
+
+ case EfiPciHostBridgeBeginBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ HostBridge->CanRestarted = FALSE;
+ break;
+
+ case EfiPciHostBridgeEndBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ break;
+
+ case EfiPciHostBridgeBeginResourceAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ break;
+
+ case EfiPciHostBridgeAllocateResources:
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Make sure the resource for all root bridges has been submitted.
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (!RootBridge->ResourceSubmitted) {
+ return EFI_NOT_READY;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ ResNodeHandled[Index] = FALSE;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));
+
+ for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
+ if (RootBridge->ResAllocNode[Index1].Status == ResNone) {
+ ResNodeHandled[Index1] = TRUE;
+ } else {
+ //
+ // Allocate the resource node with max alignment at first
+ //
+ MaxAlignment = 0;
+ Index = TypeMax;
+ for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {
+ if (ResNodeHandled[Index2]) {
+ continue;
+ }
+ if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {
+ MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;
+ Index = Index2;
+ }
+ }
+
+ ASSERT (Index < TypeMax);
+ ResNodeHandled[Index] = TRUE;
+ Alignment = RootBridge->ResAllocNode[Index].Alignment;
+ BitsOfAlignment = LowBitSet64 (Alignment + 1);
+ BaseAddress = MAX_UINT64;
+
+ //
+ // RESTRICTION: To simplify the situation, we require the alignment of
+ // Translation must be larger than any BAR alignment in the same root
+ // bridge, so that resource allocation alignment can be applied to
+ // both device address and host address.
+ //
+ Translation = GetTranslationByResourceType (RootBridge, Index);
+ if ((Translation & Alignment) != 0) {
+ DEBUG ((DEBUG_ERROR, "[%a:%d] Translation %lx is not aligned to %lx!\n",
+ __FUNCTION__, __LINE__, Translation, Alignment
+ ));
+ ASSERT ((Translation & Alignment) == 0);
+ //
+ // This may be caused by too large alignment or too small
+ // Translation; pick the 1st possibility and return out of resource,
+ // which can also go thru the same process for out of resource
+ // outside the loop.
+ //
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ continue;
+ }
+
+ switch (Index) {
+ case TypeIo:
+ //
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+ // For AllocateResource is manipulating GCD resource, we need to use
+ // host address here.
+ //
+ BaseAddress = AllocateResource (
+ FALSE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (15, BitsOfAlignment),
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),
+ RootBridge->Io.Translation),
+ TO_HOST_ADDRESS (RootBridge->Io.Limit,
+ RootBridge->Io.Translation)
+ );
+ break;
+
+ case TypeMem64:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (63, BitsOfAlignment),
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),
+ RootBridge->MemAbove4G.Translation),
+ TO_HOST_ADDRESS (RootBridge->MemAbove4G.Limit,
+ RootBridge->MemAbove4G.Translation)
+ );
+ if (BaseAddress != MAX_UINT64) {
+ break;
+ }
+ //
+ // If memory above 4GB is not available, try memory below 4GB
+ //
+
+ case TypeMem32:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (31, BitsOfAlignment),
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),
+ RootBridge->Mem.Translation),
+ TO_HOST_ADDRESS (RootBridge->Mem.Limit,
+ RootBridge->Mem.Translation)
+ );
+ break;
+
+ case TypePMem64:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (63, BitsOfAlignment),
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),
+ RootBridge->PMemAbove4G.Translation),
+ TO_HOST_ADDRESS (RootBridge->PMemAbove4G.Limit,
+ RootBridge->PMemAbove4G.Translation)
+ );
+ if (BaseAddress != MAX_UINT64) {
+ break;
+ }
+ //
+ // If memory above 4GB is not available, try memory below 4GB
+ //
+ case TypePMem32:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (31, BitsOfAlignment),
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),
+ RootBridge->PMem.Translation),
+ TO_HOST_ADDRESS (RootBridge->PMem.Limit,
+ RootBridge->PMem.Translation)
+ );
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ DEBUG ((DEBUG_INFO, " %s: Base/Length/Alignment = %lx/%lx/%lx - ",
+ mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));
+ if (BaseAddress != MAX_UINT64) {
+ RootBridge->ResAllocNode[Index].Base = BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ DEBUG ((DEBUG_INFO, "Success\n"));
+ } else {
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));
+ }
+ }
+ }
+ }
+
+ if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
+ ResourceConflict (HostBridge);
+ }
+
+ //
+ // Set resource to zero for nodes where allocation fails
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ RootBridge->ResAllocNode[Index].Length = 0;
+ }
+ }
+ }
+ return ReturnStatus;
+
+ case EfiPciHostBridgeSetResources:
+ //
+ // HostBridgeInstance->CanRestarted = FALSE;
+ //
+ break;
+
+ case EfiPciHostBridgeFreeResources:
+ //
+ // HostBridgeInstance->CanRestarted = FALSE;
+ //
+ ReturnStatus = EFI_SUCCESS;
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
+ switch (Index) {
+ case TypeIo:
+ Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypeMem32:
+ case TypePMem32:
+ case TypeMem64:
+ case TypePMem64:
+ Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ }
+ }
+
+ RootBridge->ResourceSubmitted = FALSE;
+ }
+
+ HostBridge->CanRestarted = TRUE;
+ return ReturnStatus;
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ //
+ // The resource allocation phase is completed. No specific action is required
+ // here. This notification can be used to perform any chipset specific programming.
+ //
+ break;
+
+ case EfiPciHostBridgeEndEnumeration:
+ //
+ // The Host Bridge Enumeration is completed. No specific action is required here.
+ // This notification can be used to perform any chipset specific programming.
+ //
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Return the device handle of the next PCI root bridge that is associated with
+ this Host Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.
+ On input, it holds the RootBridgeHandle returned by the most
+ recent call to GetNextRootBridge().The handle for the first
+ PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_NOT_FOUND Next PCI root bridge not found.
+ @retval EFI_INVALID_PARAMETER Wrong parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ )
+{
+ BOOLEAN ReturnNext;
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (RootBridgeHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);
+
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (ReturnNext) {
+ *RootBridgeHandle = RootBridge->Handle;
+ return EFI_SUCCESS;
+ }
+
+ ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);
+ }
+
+ if (ReturnNext) {
+ ASSERT (IsNull (&HostBridge->RootBridges, Link));
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+
+ Returns the attributes of a PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The device handle of the PCI Root Bridge
+ that the caller is interested in.
+ @param Attributes The pointer to attributes of the PCI Root Bridge.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or
+ RootBridgeHandle is not an EFI_HANDLE
+ that was returned on a previous call to
+ GetNextRootBridge().
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Attributes == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ *Attributes = RootBridge->AllocationAttributes;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This is the request from the PCI enumerator to set up
+ the specified PCI Root Bridge for bus enumeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge to be set up.
+ @param Configuration Pointer to the pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (*Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ Descriptor->GenFlag = 0;
+ Descriptor->SpecificFlag = 0;
+ Descriptor->AddrSpaceGranularity = 0;
+ Descriptor->AddrRangeMin = RootBridge->Bus.Base;
+ Descriptor->AddrRangeMax = 0;
+ Descriptor->AddrTranslationOffset = 0;
+ Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;
+
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function programs the PCI Root Bridge hardware so that
+ it decodes the specified PCI bus range.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.
+ @param Configuration The pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+
+ //
+ // Check the Configuration is valid
+ //
+ if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||
+ (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||
+ (End->Desc != ACPI_END_TAG_DESCRIPTOR)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+
+ if (Descriptor->AddrLen == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||
+ (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Update the Bus Range
+ //
+ RootBridge->ResAllocNode[TypeBus].Base = Descriptor->AddrRangeMin;
+ RootBridge->ResAllocNode[TypeBus].Length = Descriptor->AddrLen;
+ RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.
+ are being submitted.
+ @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ PCI_RESOURCE_TYPE Type;
+
+ //
+ // Check the input parameter: Configuration
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));
+ //
+ // Check the resource descriptors.
+ // If the Configuration includes one or more invalid resource descriptors, all the resource
+ // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
+ //
+ for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",
+ mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""
+ ));
+ DEBUG ((EFI_D_INFO, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));
+ switch (Descriptor->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+ if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If the PCI root bridge does not support separate windows for nonprefetchable and
+ // prefetchable memory, then the PCI bus driver needs to include requests for
+ // prefetchable memory in the nonprefetchable memory pool.
+ //
+ if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&
+ ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+ //
+ // Check aligment, it should be of the form 2^n-1
+ //
+ if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ if (Descriptor->AddrSpaceGranularity == 32) {
+ if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
+ Type = TypePMem32;
+ } else {
+ Type = TypeMem32;
+ }
+ } else {
+ ASSERT (Descriptor->AddrSpaceGranularity == 64);
+ if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
+ Type = TypePMem64;
+ } else {
+ Type = TypeMem64;
+ }
+ }
+ } else {
+ ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);
+ Type = TypeIo;
+ }
+ RootBridge->ResAllocNode[Type].Length = Descriptor->AddrLen;
+ RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;
+ RootBridge->ResAllocNode[Type].Status = ResSubmitted;
+ }
+ RootBridge->ResourceSubmitted = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function returns the proposed resource settings for the specified
+ PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge handle.
+ @param Configuration The pointer to the pointer to the PCI I/O
+ and memory resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINTN Index;
+ UINTN Number;
+ VOID *Buffer;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ UINT64 ResStatus;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ for (Index = 0, Number = 0; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResNone) {
+ Number++;
+ }
+ }
+
+ Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;
+ for (Index = 0; Index < TypeBus; Index++) {
+ ResStatus = RootBridge->ResAllocNode[Index].Status;
+ if (ResStatus != ResNone) {
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;
+ Descriptor->GenFlag = 0;
+ //
+ // AddrRangeMin in Resource Descriptor here should be device address
+ // instead of host address, or else PCI bus driver cannot set correct
+ // address into PCI BAR registers.
+ // Base in ResAllocNode is a host address, so conversion is needed.
+ //
+ Descriptor->AddrRangeMin = TO_DEVICE_ADDRESS (RootBridge->ResAllocNode[Index].Base,
+ GetTranslationByResourceType (RootBridge, Index));
+ Descriptor->AddrRangeMax = 0;
+ Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;
+ Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;
+
+ switch (Index) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+ }
+
+ Descriptor++;
+ }
+ }
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ *Configuration = Buffer;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function is called for all the PCI controllers that the PCI
+ bus driver finds. Can be used to Preprogram the controller.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge handle.
+ @param PciAddress Address of the controller on the PCI bus.
+ @param Phase The Phase during resource allocation.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if ((UINT32) Phase > EfiPciBeforeResourceCollection) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
new file mode 100644
index 000000000..755ab75b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
@@ -0,0 +1,269 @@
+/** @file
+
+ The Header file of the Pci Host Bridge Driver.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCI_HOST_BRIDGE_H_
+#define _PCI_HOST_BRIDGE_H_
+
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/IoMmu.h>
+
+#include "PciRootBridge.h"
+
+#define PCI_HOST_BRIDGE_SIGNATURE SIGNATURE_32 ('p', 'h', 'b', 'g')
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ LIST_ENTRY RootBridges;
+ BOOLEAN CanRestarted;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc;
+} PCI_HOST_BRIDGE_INSTANCE;
+
+#define PCI_HOST_BRIDGE_FROM_THIS(a) CR (a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE)
+
+//
+// Macros to translate device address to host address and vice versa. According
+// to UEFI 2.7, device address = host address + translation offset.
+//
+#define TO_HOST_ADDRESS(DeviceAddress,TranslationOffset) ((DeviceAddress) - (TranslationOffset))
+#define TO_DEVICE_ADDRESS(HostAddress,TranslationOffset) ((HostAddress) + (TranslationOffset))
+
+//
+// Driver Entry Point
+//
+/**
+
+ Entry point of this driver.
+
+ @param ImageHandle - Image handle of this driver.
+ @param SystemTable - Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_DEVICE_ERROR - Fail to install PCI_ROOT_BRIDGE_IO protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePciHostBridge (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+//
+// HostBridge Resource Allocation interface
+//
+/**
+
+ Enter a certain phase of the PCI enumeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Phase The phase during enumeration.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.
+ @retval EFI_NOT_READY Resources have not been submitted yet.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+
+ Return the device handle of the next PCI root bridge that is associated with
+ this Host Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.
+ On input, it holds the RootBridgeHandle returned by the most
+ recent call to GetNextRootBridge().The handle for the first
+ PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_NOT_FOUND Next PCI root bridge not found.
+ @retval EFI_INVALID_PARAMETER Wrong parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ );
+
+/**
+
+ Returns the attributes of a PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param RootBridgeHandle - The device handle of the PCI Root Bridge
+ that the caller is interested in
+ @param Attributes - The pointer to attributes of the PCI Root Bridge
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Attributes parameter passed in is NULL or
+ @retval RootBridgeHandle is not an EFI_HANDLE
+ @retval that was returned on a previous call to
+ @retval GetNextRootBridge().
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ );
+
+/**
+
+ This is the request from the PCI enumerator to set up
+ the specified PCI Root Bridge for bus enumeration process.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge to be set up.
+ @param Configuration - Pointer to the pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+
+ This function programs the PCI Root Bridge hardware so that
+ it decodes the specified PCI bus range.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge whose bus range is to be programmed.
+ @param Configuration - The pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+
+ Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param RootBridgeHandle - The PCI Root Bridge whose I/O and memory resource requirements
+ are being submitted
+ @param Configuration - The pointer to the PCI I/O and PCI memory resource descriptor
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+
+ This function returns the proposed resource settings for the specified
+ PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge handle.
+ @param Configuration - The pointer to the pointer to the PCI I/O
+ and memory resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+
+ This function is called for all the PCI controllers that the PCI
+ bus driver finds. Can be used to Preprogram the controller.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge handle.
+ @param PciAddress - Address of the controller on the PCI bus.
+ @param Phase - The Phase during resource allocation.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
+
+ @param HostBridge The Host Bridge Instance where the resource adjustment happens.
+**/
+VOID
+ResourceConflict (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridge
+ );
+
+/**
+ This routine gets translation offset from a root bridge instance by resource type.
+
+ @param RootBridge The Root Bridge Instance for the resources.
+ @param ResourceType The Resource Type of the translation offset.
+
+ @retval The Translation Offset of the specified resource.
+**/
+UINT64
+GetTranslationByResourceType (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,
+ IN PCI_RESOURCE_TYPE ResourceType
+ );
+
+extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
+extern EDKII_IOMMU_PROTOCOL *mIoMmu;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
new file mode 100644
index 000000000..9c24cacc3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
@@ -0,0 +1,52 @@
+## @file
+# Generic PCI Host Bridge driver.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHostBridgeDxe
+ FILE_GUID = 128FB770-5E79-4176-9E51-9BB268A17DD1
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePciHostBridge
+
+[Sources]
+ PciHostBridge.h
+ PciRootBridge.h
+ PciHostBridge.c
+ PciRootBridgeIo.c
+ PciHostResource.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesTableLib
+ DevicePathLib
+ BaseMemoryLib
+ BaseLib
+ PciSegmentLib
+ UefiLib
+ PciHostBridgeLib
+ TimerLib
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiPciRootBridgeIoProtocolGuid ## BY_START
+ gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid AND
+ gEfiCpuArchProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h
new file mode 100644
index 000000000..0f5a17d55
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h
@@ -0,0 +1,44 @@
+/** @file
+
+ The Header file of the Pci Host Bridge Driver.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _PCI_HOST_RESOURCE_H_
+#define _PCI_HOST_RESOURCE_H_
+
+#include <PiDxe.h>
+
+#define PCI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL
+
+typedef enum {
+ TypeIo = 0,
+ TypeMem32,
+ TypePMem32,
+ TypeMem64,
+ TypePMem64,
+ TypeBus,
+ TypeMax
+} PCI_RESOURCE_TYPE;
+
+typedef enum {
+ ResNone,
+ ResSubmitted,
+ ResAllocated,
+ ResStatusMax
+} RES_STATUS;
+
+typedef struct {
+ PCI_RESOURCE_TYPE Type;
+ //
+ // Base is a host address
+ //
+ UINT64 Base;
+ UINT64 Length;
+ UINT64 Alignment;
+ RES_STATUS Status;
+} PCI_RES_NODE;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
new file mode 100644
index 000000000..caa3faf00
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
@@ -0,0 +1,571 @@
+/** @file
+
+ The PCI Root Bridge header file.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCI_ROOT_BRIDGE_H_
+#define _PCI_ROOT_BRIDGE_H_
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Pci.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/CpuIo2.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include "PciHostResource.h"
+
+
+typedef enum {
+ IoOperation,
+ MemOperation,
+ PciOperation
+} OPERATION_TYPE;
+
+#define MAP_INFO_SIGNATURE SIGNATURE_32 ('_', 'm', 'a', 'p')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} MAP_INFO;
+#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
+
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('_', 'p', 'r', 'b')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE Handle;
+ UINT64 AllocationAttributes;
+ UINT64 Attributes;
+ UINT64 Supports;
+ PCI_RES_NODE ResAllocNode[TypeMax];
+ PCI_ROOT_BRIDGE_APERTURE Bus;
+ PCI_ROOT_BRIDGE_APERTURE Io;
+ PCI_ROOT_BRIDGE_APERTURE Mem;
+ PCI_ROOT_BRIDGE_APERTURE PMem;
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;
+ BOOLEAN DmaAbove4G;
+ BOOLEAN NoExtendedConfigSpace;
+ VOID *ConfigBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 *DevicePathStr;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL RootBridgeIo;
+
+ BOOLEAN ResourceSubmitted;
+ LIST_ENTRY Maps;
+} PCI_ROOT_BRIDGE_INSTANCE;
+
+#define ROOT_BRIDGE_FROM_THIS(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, RootBridgeIo, PCI_ROOT_BRIDGE_SIGNATURE)
+
+#define ROOT_BRIDGE_FROM_LINK(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE)
+
+/**
+ Construct the Pci Root Bridge instance.
+
+ @param Bridge The root bridge instance.
+
+ @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created
+ or NULL if creation fails.
+**/
+PCI_ROOT_BRIDGE_INSTANCE *
+CreateRootBridge (
+ IN PCI_ROOT_BRIDGE *Bridge
+ );
+
+//
+// Protocol Member Function Prototypes
+//
+/**
+
+ Poll an address in memory mapped space until an exit condition is met
+ or a timeout occurs.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Width of the memory operation.
+ @param Address - The base address of the memory operation.
+ @param Mask - Mask used for polling criteria.
+ @param Value - Comparison value used for polling exit criteria.
+ @param Delay - Number of 100ns units to poll.
+ @param Result - Pointer to the last value read from memory location.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_TIMEOUT - Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+;
+
+/**
+
+ Poll an address in I/O space until an exit condition is met
+ or a timeout occurs.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Width of I/O operation.
+ @param Address - The base address of the I/O operation.
+ @param Mask - Mask used for polling criteria.
+ @param Value - Comparison value used for polling exit criteria.
+ @param Delay - Number of 100ns units to poll.
+ @param Result - Pointer to the last value read from memory location.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_TIMEOUT - Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+;
+
+/**
+
+ Allow read from memory mapped I/O space.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - The width of memory operation.
+ @param Address - Base address of the memory operation.
+ @param Count - Number of memory opeartion to perform.
+ @param Buffer - The destination buffer to store data.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Allow write to memory mapped I/O space.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - The width of memory operation.
+ @param Address - Base address of the memory operation.
+ @param Count - Number of memory opeartion to perform.
+ @param Buffer - The source buffer to write data from.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Enable a PCI driver to read PCI controller registers in the
+ PCI root bridge I/O space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param UserAddress - The base address of the I/O operation.
+ @param Count - The number of I/O operations to perform.
+ @param UserBuffer - The destination buffer to store the results.
+
+ @retval EFI_SUCCESS - The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+;
+
+/**
+
+ Enable a PCI driver to write to PCI controller registers in the
+ PCI root bridge I/O space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param UserAddress - The base address of the I/O operation.
+ @param Count - The number of I/O operations to perform.
+ @param UserBuffer - The source buffer to write data from.
+
+ @retval EFI_SUCCESS - The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+;
+
+/**
+
+ Copy one region of PCI root bridge memory space to be copied to
+ another region of PCI root bridge memory space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Signifies the width of the memory operation.
+ @param DestAddress - Destination address of the memory operation.
+ @param SrcAddress - Source address of the memory operation.
+ @param Count - Number of memory operations to perform.
+
+ @retval EFI_SUCCESS - The data was copied successfully.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ )
+;
+
+/**
+
+ Allows read from PCI configuration space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param Address - The address within the PCI configuration space
+ for the PCI controller.
+ @param Count - The number of PCI configuration operations
+ to perform.
+ @param Buffer - The destination buffer to store the results.
+
+ @retval EFI_SUCCESS - The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Allows write to PCI configuration space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param Address - The address within the PCI configuration space
+ for the PCI controller.
+ @param Count - The number of PCI configuration operations
+ to perform.
+ @param Buffer - The source buffer to get the results.
+
+ @retval EFI_SUCCESS - The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+ Provides the PCI controller-specific address needed to access
+ system memory for DMA.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicate if the bus master is going to read or write
+ to system memory.
+ @param HostAddress The system memory address to map on the PCI controller.
+ @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 PCI
+ controller to use to access the system memory's HostAddress.
+ @param Mapping The value to pass to Unmap() when the bus master DMA
+ operation is complete.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+ @retval EFI_UNSUPPORTED The HostAddress cannot 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 request could not be completed due to lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+;
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ The Unmap() function completes the Map() operation and releases any
+ corresponding resources.
+ If the operation was an EfiPciOperationBusMasterWrite or
+ EfiPciOperationBusMasterWrite64, the data is committed to the target system
+ memory.
+ Any resources used for the mapping are freed.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+;
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer
+ or EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated
+ range. Only the attributes
+ EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED, and
+ EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this
+ function.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER MemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER HostAddress is NULL.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
+ attribute bits are MEMORY_WRITE_COMBINE,
+ MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+;
+
+/**
+
+ Free memory allocated in AllocateBuffer.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ instance.
+ @param Pages - Number of pages to free.
+ @param HostAddress - The base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS - Requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ )
+;
+
+/**
+
+ Flushes all PCI posted write transactions from a PCI host
+ bridge to system memory.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS - PCI posted write transactions were flushed
+ @retval from PCI host bridge to system memory.
+ @retval EFI_DEVICE_ERROR - Fail due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ )
+;
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with
+ SetAttributes(), and the attributes that a PCI root bridge is currently
+ using.
+
+ The GetAttributes() function returns the mask of attributes that this PCI
+ root bridge supports and the mask of attributes that the PCI root bridge is
+ currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supported A pointer to the mask of attributes that this PCI root
+ bridge supports setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root
+ bridge is currently using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes
+ that the PCI root bridge supports is returned
+ in Supports. If Attributes is not NULL, then
+ the attributes that the PCI root bridge is
+ currently using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ )
+;
+
+/**
+
+ Sets the attributes for a resource range on a PCI root bridge.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Attributes - The mask of attributes to set.
+ @param ResourceBase - Pointer to the base address of the resource range
+ to be modified by the attributes specified by Attributes.
+ @param ResourceLength - Pointer to the length of the resource range to be modified.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to set the attributes upon.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ )
+;
+
+/**
+
+ Retrieves the current resource settings of this PCI root bridge
+ in the form of a set of ACPI resource descriptor.
+
+ @param This - Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Resources - Pointer to the resource descriptor that
+ describe the current configuration of this PCI root
+ bridge.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_UNSUPPORTED - Current configuration of the PCI root bridge
+ @retval could not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ )
+;
+
+extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
new file mode 100644
index 000000000..d304fae42
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
@@ -0,0 +1,1855 @@
+/** @file
+
+ PCI Root Bridge Io Protocol code.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciHostResource.h"
+
+#define NO_MAPPING (VOID *) (UINTN) -1
+
+#define RESOURCE_VALID(Resource) ((Resource)->Base <= (Resource)->Limit)
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mInStride[] = {
+ 1, // EfiPciWidthUint8
+ 2, // EfiPciWidthUint16
+ 4, // EfiPciWidthUint32
+ 8, // EfiPciWidthUint64
+ 0, // EfiPciWidthFifoUint8
+ 0, // EfiPciWidthFifoUint16
+ 0, // EfiPciWidthFifoUint32
+ 0, // EfiPciWidthFifoUint64
+ 1, // EfiPciWidthFillUint8
+ 2, // EfiPciWidthFillUint16
+ 4, // EfiPciWidthFillUint32
+ 8 // EfiPciWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mOutStride[] = {
+ 1, // EfiPciWidthUint8
+ 2, // EfiPciWidthUint16
+ 4, // EfiPciWidthUint32
+ 8, // EfiPciWidthUint64
+ 1, // EfiPciWidthFifoUint8
+ 2, // EfiPciWidthFifoUint16
+ 4, // EfiPciWidthFifoUint32
+ 8, // EfiPciWidthFifoUint64
+ 0, // EfiPciWidthFillUint8
+ 0, // EfiPciWidthFillUint16
+ 0, // EfiPciWidthFillUint32
+ 0 // EfiPciWidthFillUint64
+};
+
+/**
+ Construct the Pci Root Bridge instance.
+
+ @param Bridge The root bridge instance.
+
+ @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created
+ or NULL if creation fails.
+**/
+PCI_ROOT_BRIDGE_INSTANCE *
+CreateRootBridge (
+ IN PCI_ROOT_BRIDGE *Bridge
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+ CHAR16 *DevicePathStr;
+ PCI_ROOT_BRIDGE_APERTURE *Aperture;
+
+ DevicePathStr = NULL;
+
+ DEBUG ((EFI_D_INFO, "RootBridge: "));
+ DEBUG ((EFI_D_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE)));
+ DEBUG ((EFI_D_INFO, " Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes));
+ DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No"));
+ DEBUG ((EFI_D_INFO, "NoExtConfSpace: %s\n", Bridge->NoExtendedConfigSpace ? L"Yes" : L"No"));
+ DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes,
+ (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",
+ (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""
+ ));
+ DEBUG ((
+ EFI_D_INFO, " Bus: %lx - %lx Translation=%lx\n",
+ Bridge->Bus.Base, Bridge->Bus.Limit, Bridge->Bus.Translation
+ ));
+ //
+ // Translation for bus is not supported.
+ //
+ ASSERT (Bridge->Bus.Translation == 0);
+ if (Bridge->Bus.Translation != 0) {
+ return NULL;
+ }
+
+ DEBUG ((
+ DEBUG_INFO, " Io: %lx - %lx Translation=%lx\n",
+ Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation
+ ));
+ DEBUG ((
+ DEBUG_INFO, " Mem: %lx - %lx Translation=%lx\n",
+ Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation
+ ));
+ DEBUG ((
+ DEBUG_INFO, " MemAbove4G: %lx - %lx Translation=%lx\n",
+ Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation
+ ));
+ DEBUG ((
+ DEBUG_INFO, " PMem: %lx - %lx Translation=%lx\n",
+ Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation
+ ));
+ DEBUG ((
+ DEBUG_INFO, " PMemAbove4G: %lx - %lx Translation=%lx\n",
+ Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation
+ ));
+
+ //
+ // Make sure Mem and MemAbove4G apertures are valid
+ //
+ if (RESOURCE_VALID (&Bridge->Mem)) {
+ ASSERT (Bridge->Mem.Limit < SIZE_4GB);
+ if (Bridge->Mem.Limit >= SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (RESOURCE_VALID (&Bridge->MemAbove4G)) {
+ ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB);
+ if (Bridge->MemAbove4G.Base < SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (RESOURCE_VALID (&Bridge->PMem)) {
+ ASSERT (Bridge->PMem.Limit < SIZE_4GB);
+ if (Bridge->PMem.Limit >= SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (RESOURCE_VALID (&Bridge->PMemAbove4G)) {
+ ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB);
+ if (Bridge->PMemAbove4G.Base < SIZE_4GB) {
+ return NULL;
+ }
+ }
+
+ //
+ // Ignore AllocationAttributes when resources were already assigned.
+ //
+ if (!Bridge->ResourceAssigned) {
+ if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {
+ //
+ // If this bit is set, then the PCI Root Bridge does not
+ // support separate windows for Non-prefetchable and Prefetchable
+ // memory.
+ //
+ ASSERT (!RESOURCE_VALID (&Bridge->PMem));
+ ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));
+ if (RESOURCE_VALID (&Bridge->PMem) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {
+ return NULL;
+ }
+ }
+
+ if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) {
+ //
+ // If this bit is not set, then the PCI Root Bridge does not support
+ // 64 bit memory windows.
+ //
+ ASSERT (!RESOURCE_VALID (&Bridge->MemAbove4G));
+ ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));
+ if (RESOURCE_VALID (&Bridge->MemAbove4G) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {
+ return NULL;
+ }
+ }
+ }
+
+ RootBridge = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));
+ ASSERT (RootBridge != NULL);
+
+ RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
+ RootBridge->Supports = Bridge->Supports;
+ RootBridge->Attributes = Bridge->Attributes;
+ RootBridge->DmaAbove4G = Bridge->DmaAbove4G;
+ RootBridge->NoExtendedConfigSpace = Bridge->NoExtendedConfigSpace;
+ RootBridge->AllocationAttributes = Bridge->AllocationAttributes;
+ RootBridge->DevicePath = DuplicateDevicePath (Bridge->DevicePath);
+ RootBridge->DevicePathStr = DevicePathStr;
+ RootBridge->ConfigBuffer = AllocatePool (
+ TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ ASSERT (RootBridge->ConfigBuffer != NULL);
+ InitializeListHead (&RootBridge->Maps);
+
+ CopyMem (&RootBridge->Bus, &Bridge->Bus, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->Io, &Bridge->Io, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->Mem, &Bridge->Mem, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->PMem, &Bridge->PMem, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ switch (Index) {
+ case TypeBus:
+ Aperture = &RootBridge->Bus;
+ break;
+ case TypeIo:
+ Aperture = &RootBridge->Io;
+ break;
+ case TypeMem32:
+ Aperture = &RootBridge->Mem;
+ break;
+ case TypeMem64:
+ Aperture = &RootBridge->MemAbove4G;
+ break;
+ case TypePMem32:
+ Aperture = &RootBridge->PMem;
+ break;
+ case TypePMem64:
+ Aperture = &RootBridge->PMemAbove4G;
+ break;
+ default:
+ ASSERT (FALSE);
+ Aperture = NULL;
+ break;
+ }
+ RootBridge->ResAllocNode[Index].Type = Index;
+ if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) {
+ //
+ // Base in ResAllocNode is a host address, while Base in Aperture is a
+ // device address.
+ //
+ RootBridge->ResAllocNode[Index].Base = TO_HOST_ADDRESS (Aperture->Base,
+ Aperture->Translation);
+ RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ } else {
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ }
+ }
+
+ RootBridge->RootBridgeIo.SegmentNumber = Bridge->Segment;
+ RootBridge->RootBridgeIo.PollMem = RootBridgeIoPollMem;
+ RootBridge->RootBridgeIo.PollIo = RootBridgeIoPollIo;
+ RootBridge->RootBridgeIo.Mem.Read = RootBridgeIoMemRead;
+ RootBridge->RootBridgeIo.Mem.Write = RootBridgeIoMemWrite;
+ RootBridge->RootBridgeIo.Io.Read = RootBridgeIoIoRead;
+ RootBridge->RootBridgeIo.Io.Write = RootBridgeIoIoWrite;
+ RootBridge->RootBridgeIo.CopyMem = RootBridgeIoCopyMem;
+ RootBridge->RootBridgeIo.Pci.Read = RootBridgeIoPciRead;
+ RootBridge->RootBridgeIo.Pci.Write = RootBridgeIoPciWrite;
+ RootBridge->RootBridgeIo.Map = RootBridgeIoMap;
+ RootBridge->RootBridgeIo.Unmap = RootBridgeIoUnmap;
+ RootBridge->RootBridgeIo.AllocateBuffer = RootBridgeIoAllocateBuffer;
+ RootBridge->RootBridgeIo.FreeBuffer = RootBridgeIoFreeBuffer;
+ RootBridge->RootBridgeIo.Flush = RootBridgeIoFlush;
+ RootBridge->RootBridgeIo.GetAttributes = RootBridgeIoGetAttributes;
+ RootBridge->RootBridgeIo.SetAttributes = RootBridgeIoSetAttributes;
+ RootBridge->RootBridgeIo.Configuration = RootBridgeIoConfiguration;
+
+ return RootBridge;
+}
+
+/**
+ Check parameters for IO,MMIO,PCI read/write services of PCI Root Bridge IO.
+
+ 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] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @param[in] OperationType I/O operation type: IO/MMIO/PCI.
+
+ @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_INVALID_PARAMETER Address or Count is invalid.
+
+ @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
+RootBridgeIoCheckParameter (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN OPERATION_TYPE OperationType,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;
+ UINT64 Base;
+ UINT64 Limit;
+ UINT32 Size;
+ UINT64 Length;
+
+ //
+ // 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 >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For FIFO type, the device address won't increase during the access,
+ // so treat Count as 1
+ //
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ Size = 1 << Width;
+
+ //
+ // Make sure (Count * Size) doesn't exceed MAX_UINT64
+ //
+ if (Count > DivU64x32 (MAX_UINT64, Size)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Address is aligned
+ //
+ if ((Address & (Size - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure (Address + Count * Size) doesn't exceed MAX_UINT64
+ //
+ Length = MultU64x32 (Count, Size);
+ if (Address > MAX_UINT64 - Length) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // 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 > Limit + 1
+ //
+ // Since Limit 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 oveflow conditions.
+ //
+ if (OperationType == IoOperation) {
+ //
+ // Allow Legacy IO access
+ //
+ if (Address + Length <= 0x1000) {
+ if ((RootBridge->Attributes & (
+ EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO |
+ EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |
+ EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_ATTRIBUTE_VGA_IO_16)) != 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ Base = RootBridge->Io.Base;
+ Limit = RootBridge->Io.Limit;
+ } else if (OperationType == MemOperation) {
+ //
+ // Allow Legacy MMIO access
+ //
+ if ((Address >= 0xA0000) && (Address + Length) <= 0xC0000) {
+ if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // By comparing the Address against Limit we know which range to be used
+ // for checking
+ //
+ if ((Address >= RootBridge->Mem.Base) && (Address + Length <= RootBridge->Mem.Limit + 1)) {
+ Base = RootBridge->Mem.Base;
+ Limit = RootBridge->Mem.Limit;
+ } else if ((Address >= RootBridge->PMem.Base) && (Address + Length <= RootBridge->PMem.Limit + 1)) {
+ Base = RootBridge->PMem.Base;
+ Limit = RootBridge->PMem.Limit;
+ } else if ((Address >= RootBridge->MemAbove4G.Base) && (Address + Length <= RootBridge->MemAbove4G.Limit + 1)) {
+ Base = RootBridge->MemAbove4G.Base;
+ Limit = RootBridge->MemAbove4G.Limit;
+ } else {
+ Base = RootBridge->PMemAbove4G.Base;
+ Limit = RootBridge->PMemAbove4G.Limit;
+ }
+ } else {
+ PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address;
+ if (PciRbAddr->Bus < RootBridge->Bus.Base ||
+ PciRbAddr->Bus > RootBridge->Bus.Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciRbAddr->Device > PCI_MAX_DEVICE ||
+ PciRbAddr->Function > PCI_MAX_FUNC) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciRbAddr->ExtendedRegister != 0) {
+ Address = PciRbAddr->ExtendedRegister;
+ } else {
+ Address = PciRbAddr->Register;
+ }
+ Base = 0;
+ Limit = RootBridge->NoExtendedConfigSpace ? 0xFF : 0xFFF;
+ }
+
+ if (Address < Base) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address + Length > Limit + 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Use address to match apertures of memory type and then get the corresponding
+ translation.
+
+ @param RootBridge The root bridge instance.
+ @param Address The address used to match aperture.
+ @param Translation Pointer containing the output translation.
+
+ @return EFI_SUCCESS Get translation successfully.
+ @return EFI_INVALID_PARAMETER No matched memory aperture; the input Address
+ must be invalid.
+**/
+EFI_STATUS
+RootBridgeIoGetMemTranslationByAddress (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,
+ IN UINT64 Address,
+ IN OUT UINT64 *Translation
+ )
+{
+ if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) {
+ *Translation = RootBridge->Mem.Translation;
+ } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) {
+ *Translation = RootBridge->PMem.Translation;
+ } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) {
+ *Translation = RootBridge->MemAbove4G.Translation;
+ } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) {
+ *Translation = RootBridge->PMemAbove4G.Translation;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the result of (Multiplicand * Multiplier / Divisor).
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Multiplicand * Multiplier / Divisor.
+**/
+UINT64
+MultThenDivU64x64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT64 Multiplier,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder OPTIONAL
+ )
+{
+ UINT64 Uint64;
+ UINT32 LocalRemainder;
+ UINT32 Uint32;
+ if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {
+ //
+ // Make sure Multiplicand is the bigger one.
+ //
+ if (Multiplicand < Multiplier) {
+ Uint64 = Multiplicand;
+ Multiplicand = Multiplier;
+ Multiplier = Uint64;
+ }
+ //
+ // Because Multiplicand * Multiplier overflows,
+ // Multiplicand * Multiplier / Divisor
+ // = (2 * Multiplicand' + 1) * Multiplier / Divisor
+ // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor
+ //
+ Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);
+ Uint64 = LShiftU64 (Uint64, 1);
+ Uint32 = 0;
+ if ((Multiplicand & 0x1) == 1) {
+ Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);
+ }
+ return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);
+ } else {
+ return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);
+ }
+}
+
+/**
+ Return the elapsed tick count from CurrentTick.
+
+ @param CurrentTick On input, the previous tick count.
+ On output, the current tick count.
+ @param StartTick The value the performance counter starts with when it
+ rolls over.
+ @param EndTick The value that the performance counter ends with before
+ it rolls over.
+
+ @return The elapsed tick count from CurrentTick.
+**/
+UINT64
+GetElapsedTick (
+ UINT64 *CurrentTick,
+ UINT64 StartTick,
+ UINT64 EndTick
+ )
+{
+ UINT64 PreviousTick;
+
+ PreviousTick = *CurrentTick;
+ *CurrentTick = GetPerformanceCounter();
+ if (StartTick < EndTick) {
+ return *CurrentTick - PreviousTick;
+ } else {
+ return PreviousTick - *CurrentTick;
+ }
+}
+
+/**
+ Polls an address in memory mapped I/O space until an exit condition is met,
+ or a timeout occurs.
+
+ This function provides a standard way to poll a PCI memory location. A PCI
+ memory read operation is performed at the PCI memory address specified by
+ Address for the width specified by Width. The result of this PCI memory read
+ operation is stored in Result. This PCI memory read operation is repeated
+ until either a timeout of Delay 100 ns units has expired, or (Result & Mask)
+ is equal to Value.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the memory operations. The caller
+ is responsible for aligning Address if required.
+ @param[in] Mask Mask used for the polling criteria. Bytes above Width
+ in Mask are ignored. The bits in the bytes below Width
+ which are zero in Mask are ignored when polling the
+ memory address.
+ @param[in] Value The comparison value used for the polling exit
+ criteria.
+ @param[in] Delay The number of 100 ns units to poll. Note that timer
+ available may be of poorer granularity.
+ @param[out] Result Pointer to the last value read from the memory
+ location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched
+ the poll exit criteria.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_INVALID_PARAMETER Result is NULL.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINT32 Remainder;
+ UINT64 StartTick;
+ UINT64 EndTick;
+ UINT64 CurrentTick;
+ UINT64 ElapsedTick;
+ UINT64 Frequency;
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // No matter what, always do a single poll.
+ //
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
+ //
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
+ NumberOfTicks++;
+ }
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
+ ; ElapsedTick <= NumberOfTicks
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
+ ) {
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Reads from the I/O space of a PCI Root Bridge. Returns when either the
+ polling exit criteria is satisfied or after a defined duration.
+
+ This function provides a standard way to poll a PCI I/O location. A PCI I/O
+ read operation is performed at the PCI I/O address specified by Address for
+ the width specified by Width.
+ The result of this PCI I/O read operation is stored in Result. This PCI I/O
+ read operation is repeated until either a timeout of Delay 100 ns units has
+ expired, or (Result & Mask) is equal to Value.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the I/O operations.
+ @param[in] Address The base address of the I/O operations. The caller is
+ responsible for aligning Address if required.
+ @param[in] Mask Mask used for the polling criteria. Bytes above Width in
+ Mask are ignored. The bits in the bytes below Width
+ which are zero in Mask are ignored when polling the I/O
+ address.
+ @param[in] Value The comparison value used for the polling exit criteria.
+ @param[in] Delay The number of 100 ns units to poll. Note that timer
+ available may be of poorer granularity.
+ @param[out] Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched
+ the poll exit criteria.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_INVALID_PARAMETER Result is NULL.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINT32 Remainder;
+ UINT64 StartTick;
+ UINT64 EndTick;
+ UINT64 CurrentTick;
+ UINT64 ElapsedTick;
+ UINT64 Frequency;
+
+ //
+ // No matter what, always do a single poll.
+ //
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
+ //
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
+ NumberOfTicks++;
+ }
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
+ ; ElapsedTick <= NumberOfTicks
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
+ ) {
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge memory space.
+
+ The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
+ controller registers in the PCI root bridge memory space.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI Root Bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operation.
+ @param[in] Address The base address of the memory operation. The caller
+ is responsible for aligning the Address if required.
+ @param[in] Count The number of memory operations to perform. 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
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT64 Translation;
+
+ Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,
+ Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Address passed to CpuIo->Mem.Read needs to be a host address instead of
+ // device address.
+ return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
+ TO_HOST_ADDRESS (Address, Translation), Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge memory space.
+
+ The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
+ controller registers in the PCI root bridge memory space.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI Root Bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operation.
+ @param[in] Address The base address of the memory operation. The caller
+ is responsible for aligning the Address if required.
+ @param[in] Count The number of memory operations to perform. 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
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT64 Translation;
+
+ Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,
+ Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Address passed to CpuIo->Mem.Write needs to be a host address instead of
+ // device address.
+ return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
+ TO_HOST_ADDRESS (Address, Translation), Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge I/O space.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the I/O operation. The caller is
+ responsible for aligning the Address if required.
+ @param[in] Count The number of I/O operations to perform. 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
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ Status = RootBridgeIoCheckParameter (
+ This, IoOperation, Width,
+ Address, Count, Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ // Address passed to CpuIo->Io.Read needs to be a host address instead of
+ // device address.
+ return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
+ TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge I/O space.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the I/O operation. The caller is
+ responsible for aligning the Address if required.
+ @param[in] Count The number of I/O operations to perform. 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
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ Status = RootBridgeIoCheckParameter (
+ This, IoOperation, Width,
+ Address, Count, Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ // Address passed to CpuIo->Io.Write needs to be a host address instead of
+ // device address.
+ return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
+ TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to copy one region of PCI root bridge memory space to
+ another region of PCI root bridge memory space.
+
+ The CopyMem() function enables a PCI driver to copy one region of PCI root
+ bridge memory space to another region of PCI root bridge memory space. This
+ is especially useful for video scroll operation on a memory mapped video
+ buffer.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI root bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ instance.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] DestAddress The destination address of the memory operation. The
+ caller is responsible for aligning the DestAddress if
+ required.
+ @param[in] SrcAddress The source address of the memory operation. The caller
+ is responsible for aligning the SrcAddress if
+ required.
+ @param[in] Count The number of memory operations to perform. Bytes
+ moved is Width size * Count, starting at DestAddress
+ and SrcAddress.
+
+ @retval EFI_SUCCESS The data was copied from one memory region
+ to another memory region.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Forward;
+ UINTN Stride;
+ UINTN Index;
+ UINT64 Result;
+
+ if ((UINT32) Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddress == SrcAddress) {
+ return EFI_SUCCESS;
+ }
+
+ Stride = (UINTN) (1 << Width);
+
+ Forward = TRUE;
+ if ((DestAddress > SrcAddress) &&
+ (DestAddress < (SrcAddress + Count * Stride))) {
+ Forward = FALSE;
+ SrcAddress = SrcAddress + (Count - 1) * Stride;
+ DestAddress = DestAddress + (Count - 1) * Stride;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ Status = RootBridgeIoMemRead (
+ This,
+ Width,
+ SrcAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RootBridgeIoMemWrite (
+ This,
+ Width,
+ DestAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Forward) {
+ SrcAddress += Stride;
+ DestAddress += Stride;
+ } else {
+ SrcAddress -= Stride;
+ DestAddress -= Stride;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ PCI configuration space access.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Read TRUE indicating it's a read operation.
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The destination buffer to store the results.
+
+ @retval EFI_SUCCESS The data was read/written from/to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciAccess (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
+ UINT8 *Uint8Buffer;
+ UINT8 InStride;
+ UINT8 OutStride;
+ UINTN Size;
+
+ Status = RootBridgeIoCheckParameter (This, PciOperation, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read Pci configuration space
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ CopyMem (&PciAddress, &Address, sizeof (PciAddress));
+
+ if (PciAddress.ExtendedRegister == 0) {
+ PciAddress.ExtendedRegister = PciAddress.Register;
+ }
+
+ Address = PCI_SEGMENT_LIB_ADDRESS (
+ RootBridge->RootBridgeIo.SegmentNumber,
+ PciAddress.Bus,
+ PciAddress.Device,
+ PciAddress.Function,
+ PciAddress.ExtendedRegister
+ );
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ Size = (UINTN) (1 << (Width & 0x03));
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (Read) {
+ PciSegmentReadBuffer (Address, Size, Uint8Buffer);
+ } else {
+ PciSegmentWriteBuffer (Address, Size, Uint8Buffer);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Allows read from PCI configuration space.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The destination buffer to store the results.
+
+ @retval EFI_SUCCESS The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return RootBridgeIoPciAccess (This, TRUE, Width, Address, Count, Buffer);
+}
+
+/**
+ Allows write to PCI configuration space.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The source buffer to get the results.
+
+ @retval EFI_SUCCESS The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return RootBridgeIoPciAccess (This, FALSE, Width, Address, Count, Buffer);
+}
+
+/**
+ Provides the PCI controller-specific address needed to access
+ system memory for DMA.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicate if the bus master is going to read or write
+ to system memory.
+ @param HostAddress The system memory address to map on the PCI controller.
+ @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 PCI
+ controller to use to access the system memory's HostAddress.
+ @param Mapping The value to pass to Unmap() when the bus master DMA
+ operation is complete.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+ @retval EFI_UNSUPPORTED The HostAddress cannot 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 request could not be completed due to lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ MAP_INFO *MapInfo;
+
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
+ Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that Operation is valid
+ //
+ if ((UINT32) Operation >= EfiPciOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if (mIoMmu != NULL) {
+ if (!RootBridge->DmaAbove4G) {
+ //
+ // Clear 64bit support
+ //
+ if (Operation > EfiPciOperationBusMasterCommonBuffer) {
+ Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);
+ }
+ }
+ Status = mIoMmu->Map (
+ mIoMmu,
+ (EDKII_IOMMU_OPERATION) Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ return Status;
+ }
+
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((!RootBridge->DmaAbove4G ||
+ (Operation != EfiPciOperationBusMasterRead64 &&
+ Operation != EfiPciOperationBusMasterWrite64 &&
+ Operation != EfiPciOperationBusMasterCommonBuffer64)) &&
+ ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {
+
+ //
+ // If the root bridge or the device cannot handle performing DMA above
+ // 4GB but any part of the DMA transfer being mapped is above 4GB, then
+ // map the DMA transfer to a buffer below 4GB.
+ //
+
+ if (Operation == EfiPciOperationBusMasterCommonBuffer ||
+ Operation == EfiPciOperationBusMasterCommonBuffer64) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // if above 4GB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
+ // called later.
+ //
+ MapInfo = AllocatePool (sizeof (MAP_INFO));
+ if (MapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ MapInfo->Signature = MAP_INFO_SIGNATURE;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+ MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
+ MapInfo->HostAddress = PhysicalAddress;
+ MapInfo->MappedHostAddress = SIZE_4GB - 1;
+
+ //
+ // Allocate a buffer below 4GB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ MapInfo->NumberOfPages,
+ &MapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MapInfo);
+ *NumberOfBytes = 0;
+ return Status;
+ }
+
+ //
+ // If this is a read operation from the Bus Master's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the Bus Master can read the contents of the real buffer.
+ //
+ if (Operation == EfiPciOperationBusMasterRead ||
+ Operation == EfiPciOperationBusMasterRead64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->MappedHostAddress,
+ (VOID *) (UINTN) MapInfo->HostAddress,
+ MapInfo->NumberOfBytes
+ );
+ }
+
+ InsertTailList (&RootBridge->Maps, &MapInfo->Link);
+
+ //
+ // The DeviceAddress is the address of the maped buffer below 4GB
+ //
+ *DeviceAddress = MapInfo->MappedHostAddress;
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = MapInfo;
+ } else {
+ //
+ // If the root bridge CAN handle performing DMA above 4GB or
+ // the transfer is below 4GB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ *Mapping = NO_MAPPING;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ The Unmap() function completes the Map() operation and releases any
+ corresponding resources.
+ If the operation was an EfiPciOperationBusMasterWrite or
+ EfiPciOperationBusMasterWrite64, the data is committed to the target system
+ memory.
+ Any resources used for the mapping are freed.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ MAP_INFO *MapInfo;
+ LIST_ENTRY *Link;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Unmap (
+ mIoMmu,
+ Mapping
+ );
+ return Status;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // 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 == NO_MAPPING) {
+ return EFI_SUCCESS;
+ }
+
+ MapInfo = NO_MAPPING;
+ for (Link = GetFirstNode (&RootBridge->Maps)
+ ; !IsNull (&RootBridge->Maps, Link)
+ ; Link = GetNextNode (&RootBridge->Maps, Link)
+ ) {
+ MapInfo = MAP_INFO_FROM_LINK (Link);
+ if (MapInfo == Mapping) {
+ break;
+ }
+ }
+ //
+ // Mapping is not a valid value returned by Map()
+ //
+ if (MapInfo != Mapping) {
+ return EFI_INVALID_PARAMETER;
+ }
+ RemoveEntryList (&MapInfo->Link);
+
+ //
+ // If this is a write operation from the Bus Master'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 (MapInfo->Operation == EfiPciOperationBusMasterWrite ||
+ MapInfo->Operation == EfiPciOperationBusMasterWrite64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->HostAddress,
+ (VOID *) (UINTN) MapInfo->MappedHostAddress,
+ MapInfo->NumberOfBytes
+ );
+ }
+
+ //
+ // Free the mapped buffer and the MAP_INFO structure.
+ //
+ gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
+ FreePool (Mapping);
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer
+ or EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated
+ range. Only the attributes
+ EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED, and
+ EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this
+ function.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER MemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER HostAddress is NULL.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
+ attribute bits are MEMORY_WRITE_COMBINE,
+ MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_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;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ALLOCATE_TYPE AllocateType;
+
+ //
+ // Validate Attributes
+ //
+ if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check for invalid inputs
+ //
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The only valid memory types are EfiBootServicesData and
+ // EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if (mIoMmu != NULL) {
+ if (!RootBridge->DmaAbove4G) {
+ //
+ // Clear DUAL_ADDRESS_CYCLE
+ //
+ Attributes &= ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
+ }
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ Type,
+ MemoryType,
+ Pages,
+ HostAddress,
+ Attributes
+ );
+ return Status;
+ }
+
+ AllocateType = AllocateAnyPages;
+ if (!RootBridge->DmaAbove4G ||
+ (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+ //
+ // Limit allocations to memory below 4GB
+ //
+ AllocateType = AllocateMaxAddress;
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);
+ }
+ Status = gBS->AllocatePages (
+ AllocateType,
+ MemoryType,
+ Pages,
+ &PhysicalAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+ }
+
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ The FreeBuffer() function frees memory that was allocated with
+ AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
+ Pages was not allocated with AllocateBuffer().
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->FreeBuffer (
+ mIoMmu,
+ Pages,
+ HostAddress
+ );
+ return Status;
+ }
+
+ return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
+}
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system
+ memory.
+
+ The Flush() function flushes any PCI posted write transactions from a PCI
+ host bridge to system memory. Posted write transactions are generated by PCI
+ bus masters when they perform write transactions to target addresses in
+ system memory.
+ This function does not flush posted write transactions from any PCI bridges.
+ A PCI controller specific action must be taken to guarantee that the posted
+ write transactions have been flushed from the PCI controller and from all the
+ PCI bridges into the PCI host bridge. This is typically done with a PCI read
+ transaction from the PCI controller prior to calling Flush().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed
+ from the PCI host bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed
+ from the PCI host bridge due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with
+ SetAttributes(), and the attributes that a PCI root bridge is currently
+ using.
+
+ The GetAttributes() function returns the mask of attributes that this PCI
+ root bridge supports and the mask of attributes that the PCI root bridge is
+ currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supported A pointer to the mask of attributes that this PCI root
+ bridge supports setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root
+ bridge is currently using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes
+ that the PCI root bridge supports is returned
+ in Supports. If Attributes is not NULL, then
+ the attributes that the PCI root bridge is
+ currently using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Attributes == NULL && Supported == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ //
+ // Set the return value for Supported and Attributes
+ //
+ if (Supported != NULL) {
+ *Supported = RootBridge->Supports;
+ }
+
+ if (Attributes != NULL) {
+ *Attributes = RootBridge->Attributes;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets attributes for a resource range on a PCI root bridge.
+
+ The SetAttributes() function sets the attributes specified in Attributes for
+ the PCI root bridge on the resource range specified by ResourceBase and
+ ResourceLength. Since the granularity of setting these attributes may vary
+ from resource type to resource type, and from platform to platform, the
+ actual resource range and the one passed in by the caller may differ. As a
+ result, this function may set the attributes specified by Attributes on a
+ larger resource range than the caller requested. The actual range is returned
+ in ResourceBase and ResourceLength. The caller is responsible for verifying
+ that the actual range for which the attributes were set is acceptable.
+
+ @param This A pointer to the
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Attributes The mask of attributes to set. If the
+ attribute bit MEMORY_WRITE_COMBINE,
+ MEMORY_CACHED, or MEMORY_DISABLE is set,
+ then the resource range is specified by
+ ResourceBase and ResourceLength. If
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED, and
+ MEMORY_DISABLE are not set, then
+ ResourceBase and ResourceLength are ignored,
+ and may be NULL.
+ @param ResourceBase A pointer to the base address of the
+ resource range to be modified by the
+ attributes specified by Attributes.
+ @param ResourceLength A pointer to the length of the resource
+ range to be modified by the attributes
+ specified by Attributes.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge
+ was returned in Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge
+ could not be retrieved.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if ((Attributes & (~RootBridge->Supports)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ RootBridge->Attributes = Attributes;
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current resource settings of this PCI root bridge in the form
+ of a set of ACPI resource descriptors.
+
+ There are only two resource descriptor types from the ACPI Specification that
+ may be used to describe the current resources allocated to a PCI root bridge.
+ These are the QWORD Address Space Descriptor, and the End Tag. The QWORD
+ Address Space Descriptor can describe memory, I/O, and bus number ranges for
+ dynamic or fixed resources. The configuration of a PCI root bridge is described
+ with one or more QWORD Address Space Descriptors followed by an End Tag.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[out] Resources A pointer to the resource descriptors that
+ describe the current configuration of this PCI root
+ bridge. The storage for the resource
+ descriptors is allocated by this function. The
+ caller must treat the return buffer as read-only
+ data, and the buffer must not be freed by the
+ caller.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge
+ was returned in Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge
+ could not be retrieved.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ )
+{
+ PCI_RESOURCE_TYPE Index;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RES_NODE *ResAllocNode;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ //
+ // Get this instance of the Root Bridge.
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ ZeroMem (
+ RootBridge->ConfigBuffer,
+ TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ Descriptor = RootBridge->ConfigBuffer;
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+
+ ResAllocNode = &RootBridge->ResAllocNode[Index];
+
+ if (ResAllocNode->Status != ResAllocated) {
+ continue;
+ }
+
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ // According to UEFI 2.7, RootBridgeIo->Configuration should return address
+ // range in CPU view (host address), and ResAllocNode->Base is already a CPU
+ // view address (host address).
+ Descriptor->AddrRangeMin = ResAllocNode->Base;
+ Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Descriptor->AddrLen = ResAllocNode->Length;
+ Descriptor->AddrTranslationOffset = GetTranslationByResourceType (
+ RootBridge,
+ ResAllocNode->Type
+ );
+
+ switch (ResAllocNode->Type) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+
+ case TypeBus:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ break;
+
+ default:
+ break;
+ }
+
+ Descriptor++;
+ }
+ //
+ // Terminate the entries.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ *Resources = RootBridge->ConfigBuffer;
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
new file mode 100644
index 000000000..68b0de8ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c
@@ -0,0 +1,279 @@
+/** @file
+ UEFI Component Name and Name2 protocol for Isa serial driver.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Serial.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName = {
+ SerialComponentNameGetDriverName,
+ SerialComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SerialComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SerialComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSerialDriverNameTable[] = {
+ {
+ "eng;en",
+ L"PCI SIO Serial 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
+SerialComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSerialDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPciSioSerialComponentName)
+ );
+}
+
+/**
+ 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
+SerialComponentNameGetControllerName (
+ 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;
+ EFI_GUID *IoProtocolGuid;
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ IoProtocolGuid = &gEfiSioProtocolGuid;
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSerialControllerDriver.DriverBindingHandle,
+ IoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ IoProtocolGuid = &gEfiPciIoProtocolGuid;
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSerialControllerDriver.DriverBindingHandle,
+ IoProtocolGuid
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = NULL;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ IoProtocolGuid
+ );
+ 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 == &gPciSioSerialComponentName)
+ );
+}
+
+/**
+ Add the ISO639-2 and RFC4646 component name both for the Serial IO device
+
+ @param SerialDevice A pointer to the SERIAL_DEV instance.
+ @param Instance Instance ID for the serial device.
+**/
+VOID
+AddName (
+ IN SERIAL_DEV *SerialDevice,
+ IN UINT32 Instance
+ )
+{
+ CHAR16 SerialPortName[SERIAL_PORT_NAME_LEN];
+ UnicodeSPrint (
+ SerialPortName,
+ sizeof (SerialPortName),
+ (SerialDevice->PciDeviceInfo != NULL) ? PCI_SERIAL_PORT_NAME : SIO_SERIAL_PORT_NAME,
+ Instance
+ );
+ AddUnicodeString2 (
+ "eng",
+ gPciSioSerialComponentName.SupportedLanguages,
+ &SerialDevice->ControllerNameTable,
+ SerialPortName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gPciSioSerialComponentName2.SupportedLanguages,
+ &SerialDevice->ControllerNameTable,
+ SerialPortName,
+ FALSE
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
new file mode 100644
index 000000000..826ed9d4e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
@@ -0,0 +1,75 @@
+## @file
+# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card.
+#
+# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciSioSerialDxe
+ MODULE_UNI_FILE = PciSioSerialDxe.uni
+ FILE_GUID = E2775B47-D453-4EE3-ADA7-391A1B05AC17
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePciSioSerial
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gSerialControllerDriver
+# COMPONENT_NAME = gPciSioSerialComponentName
+# COMPONENT_NAME2 = gPciSioSerialComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ SerialIo.c
+ Serial.h
+ Serial.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ IoLib
+
+[Guids]
+ gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiSioProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSerialIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PciSioSerialDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni
new file mode 100644
index 000000000..eafb8564d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Serial driver for standard UARTS on a SIO chip or PCI/PCIE card.
+//
+// Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Serial driver for standard UARTS on a SIO chip or PCI/PCIE card."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O."
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni
new file mode 100644
index 000000000..7d39ac23a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// PciSioSerialDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"PCI SIO UART Serial Bus DXE Driver"
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
new file mode 100644
index 000000000..9fe8a482e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c
@@ -0,0 +1,1250 @@
+/** @file
+ Serial driver for PCI or SIO UARTS.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Serial.h"
+
+//
+// ISA Serial Driver Global Variables
+//
+
+EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
+ SerialControllerDriverSupported,
+ SerialControllerDriverStart,
+ SerialControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_CONTROLLER_DP,
+ {
+ (UINT8) (sizeof (CONTROLLER_DEVICE_PATH)),
+ (UINT8) ((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+SERIAL_DEV gSerialDevTemplate = {
+ SERIAL_DEV_SIGNATURE,
+ NULL,
+ {
+ SERIAL_IO_INTERFACE_REVISION,
+ SerialReset,
+ SerialSetAttributes,
+ SerialSetControl,
+ SerialGetControl,
+ SerialWrite,
+ SerialRead,
+ NULL
+ }, // SerialIo
+ {
+ SERIAL_PORT_SUPPORT_CONTROL_MASK,
+ SERIAL_PORT_DEFAULT_TIMEOUT,
+ 0,
+ 16,
+ 0,
+ 0,
+ 0
+ }, // SerialMode
+ NULL, // DevicePath
+ NULL, // ParentDevicePath
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8) (sizeof (UART_DEVICE_PATH)),
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0, 0, 0, 0, 0
+ }, // UartDevicePath
+ 0, // BaseAddress
+ FALSE, // MmioAccess
+ 1, // RegisterStride
+ 0, // ClockRate
+ 16, // ReceiveFifoDepth
+ { 0, 0 }, // Receive;
+ 16, // TransmitFifoDepth
+ { 0, 0 }, // Transmit;
+ FALSE, // SoftwareLoopbackEnable;
+ FALSE, // HardwareFlowControl;
+ NULL, // *ControllerNameTable;
+ FALSE, // ContainsControllerNode;
+ 0, // Instance;
+ NULL // *PciDeviceInfo;
+};
+
+/**
+ 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
+IsUartFlowControlDevicePathNode (
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
+ )
+{
+ return (BOOLEAN) (
+ (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
+ (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
+ );
+}
+
+/**
+ The user Entry Point for module PciSioSerial. 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
+InitializePciSioSerial (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSerialControllerDriver,
+ ImageHandle,
+ &gPciSioSerialComponentName,
+ &gPciSioSerialComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize UART default setting in gSerialDevTempate
+ //
+ gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);
+ gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
+ gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);
+ gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
+ gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate);
+
+ return Status;
+}
+
+/**
+ Return whether the controller is a SIO serial controller.
+
+ @param Controller The controller handle.
+
+ @retval EFI_SUCCESS The controller is a SIO serial controller.
+ @retval others The controller is not a SIO serial controller.
+**/
+EFI_STATUS
+IsSioSerialController (
+ EFI_HANDLE Controller
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIO_PROTOCOL *Sio;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ACPI_HID_DEVICE_PATH *Acpi;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT (Status != EFI_ALREADY_STARTED);
+
+ if (!EFI_ERROR (Status)) {
+ do {
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } while (!IsDevicePathEnd (DevicePath));
+
+ if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
+ (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP) ||
+ Acpi->HID != EISA_PNP_ID (0x501)
+ ) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+/**
+ Return whether the controller is a PCI serial controller.
+
+ @param Controller The controller handle.
+
+ @retval EFI_SUCCESS The controller is a PCI serial controller.
+ @retval others The controller is not a PCI serial controller.
+**/
+EFI_STATUS
+IsPciSerialController (
+ EFI_HANDLE Controller
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PCI_TYPE00 Pci;
+ PCI_SERIAL_PARAMETER *PciSerialParameter;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
+ if (!EFI_ERROR (Status)) {
+ if (!IS_PCI_16550_SERIAL (&Pci)) {
+ for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr (PcdPciSerialParameters)
+ ; PciSerialParameter->VendorId != 0xFFFF
+ ; PciSerialParameter++
+ ) {
+ if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) &&
+ (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId)
+ ) {
+ break;
+ }
+ }
+ if (PciSerialParameter->VendorId == 0xFFFF) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT (Status != EFI_ALREADY_STARTED);
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller
+ );
+
+ 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;
+ UART_DEVICE_PATH *Uart;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
+
+ //
+ // Test RemainingDevicePath
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = EFI_UNSUPPORTED;
+
+ Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL);
+ if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH ||
+ DevicePathSubType (Uart) != MSG_UART_DP ||
+ DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH)
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Do a rough check because Clock Rate is unknown until DriverBindingStart()
+ //
+ if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, Uart->Parity, Uart->StopBits, NULL, NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {
+ //
+ // If the second node is Flow Control Node,
+ // return error when it request other than hardware flow control.
+ //
+ if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ Status = IsSioSerialController (Controller);
+ if (EFI_ERROR (Status)) {
+ Status = IsPciSerialController (Controller);
+ }
+ return Status;
+}
+
+/**
+ Create the child serial device instance.
+
+ @param Controller The parent controller handle.
+ @param Uart Pointer to the UART device path node in RemainingDevicePath,
+ or NULL if RemainingDevicePath is NULL.
+ @param ParentDevicePath Pointer to the parent device path.
+ @param CreateControllerNode TRUE to create the controller node.
+ @param Instance Instance number of the serial device.
+ The value will be set to the controller node
+ if CreateControllerNode is TRUE.
+ @param ParentIo A union type pointer to either Sio or PciIo.
+ @param PciSerialParameter The PCI serial parameter to be used by current serial device.
+ NULL for SIO serial device.
+ @param PciDeviceInfo The PCI device info for the current serial device.
+ NULL for SIO serial device.
+
+ @retval EFI_SUCCESS The serial device was created successfully.
+ @retval others The serial device wasn't created.
+**/
+EFI_STATUS
+CreateSerialDevice (
+ IN EFI_HANDLE Controller,
+ IN UART_DEVICE_PATH *Uart,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN BOOLEAN CreateControllerNode,
+ IN UINT32 Instance,
+ IN PARENT_IO_PROTOCOL_PTR ParentIo,
+ IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL
+ IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ SERIAL_DEV *SerialDevice;
+ UINT8 BarIndex;
+ UINT64 Offset;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
+ UINT32 FlowControlMap;
+ ACPI_RESOURCE_HEADER_PTR Resources;
+ EFI_ACPI_IO_PORT_DESCRIPTOR *Io;
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ BarIndex = 0;
+ Offset = 0;
+ FlowControl = NULL;
+ FlowControlMap = 0;
+
+ //
+ // Initialize the serial device instance
+ //
+ SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate);
+ ASSERT (SerialDevice != NULL);
+
+ SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);
+ SerialDevice->ParentDevicePath = ParentDevicePath;
+ SerialDevice->PciDeviceInfo = PciDeviceInfo;
+ SerialDevice->Instance = Instance;
+
+ if (Uart != NULL) {
+ CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH));
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
+ if (IsUartFlowControlDevicePathNode (FlowControl)) {
+ FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
+ } else {
+ FlowControl = NULL;
+ }
+ }
+
+ //
+ // For PCI serial device, use the information from PCD
+ //
+ if (PciSerialParameter != NULL) {
+ BarIndex = (PciSerialParameter->BarIndex == MAX_UINT8) ? 0 : PciSerialParameter->BarIndex;
+ Offset = PciSerialParameter->Offset;
+ if (PciSerialParameter->RegisterStride != 0) {
+ SerialDevice->RegisterStride = PciSerialParameter->RegisterStride;
+ }
+ if (PciSerialParameter->ClockRate != 0) {
+ SerialDevice->ClockRate = PciSerialParameter->ClockRate;
+ }
+ if (PciSerialParameter->ReceiveFifoDepth != 0) {
+ SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth;
+ }
+ if (PciSerialParameter->TransmitFifoDepth != 0) {
+ SerialDevice->TransmitFifoDepth = PciSerialParameter->TransmitFifoDepth;
+ }
+ }
+
+ //
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
+ // DriverBindingStart() shouldn't create a handle with different UART device path.
+ //
+ if (!VerifyUartParameters (SerialDevice->ClockRate, SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits,
+ SerialDevice->UartDevicePath.Parity, SerialDevice->UartDevicePath.StopBits, NULL, NULL
+ )) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CreateError;
+ }
+
+ if (PciSerialParameter == NULL) {
+ Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources);
+ } else {
+ Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, NULL, (VOID **) &Resources);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the base address information from ACPI resource descriptor.
+ // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR are returned from Sio;
+ // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo.
+ //
+ while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && (SerialDevice->BaseAddress == 0)) {
+ switch (Resources.SmallHeader->Byte) {
+ case ACPI_IO_PORT_DESCRIPTOR:
+ Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
+ if (Io->Length != 0) {
+ SerialDevice->BaseAddress = Io->BaseAddressMin;
+ }
+ break;
+
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
+ FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
+ if (FixedIo->Length != 0) {
+ SerialDevice->BaseAddress = FixedIo->BaseAddress;
+ }
+ break;
+
+ case ACPI_ADDRESS_SPACE_DESCRIPTOR:
+ AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Resources.SmallHeader;
+ if (AddressSpace->AddrLen != 0) {
+ if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ SerialDevice->MmioAccess = TRUE;
+ }
+ SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset;
+ }
+ break;
+ }
+
+ if (Resources.SmallHeader->Bits.Type == 0) {
+ Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
+ + Resources.SmallHeader->Bits.Length
+ + sizeof (*Resources.SmallHeader));
+ } else {
+ Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
+ + Resources.LargeHeader->Length
+ + sizeof (*Resources.LargeHeader));
+ }
+ }
+ }
+
+ if (SerialDevice->BaseAddress == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CreateError;
+ }
+
+ 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,
+ SerialDevice->ParentDevicePath
+ );
+
+ if (!SerialPresent (SerialDevice)) {
+ Status = EFI_DEVICE_ERROR;
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->ParentDevicePath
+ );
+ goto CreateError;
+ }
+
+ //
+ // 1. Append Controller device path node.
+ //
+ if (CreateControllerNode) {
+ mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance;
+ SerialDevice->DevicePath = AppendDevicePathNode (
+ SerialDevice->ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &mControllerDevicePathTemplate
+ );
+ SerialDevice->ContainsControllerNode = TRUE;
+ }
+
+ //
+ // 2. Append UART device path node.
+ // The Uart setings are zero here.
+ // SetAttribute() will update them to match the default setings.
+ //
+ TempDevicePath = SerialDevice->DevicePath;
+ if (TempDevicePath != NULL) {
+ SerialDevice->DevicePath = AppendDevicePathNode (
+ TempDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
+ );
+ FreePool (TempDevicePath);
+ } else {
+ SerialDevice->DevicePath = AppendDevicePathNode (
+ SerialDevice->ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
+ );
+ }
+ //
+ // 3. Append the Flow Control device path node.
+ // 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);
+ }
+ }
+ ASSERT (SerialDevice->DevicePath != NULL);
+
+ //
+ // 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,
+ SerialDevice->DevicePath
+ );
+ goto CreateError;
+ }
+
+ AddName (SerialDevice, Instance);
+ //
+ // Install protocol interfaces for the serial device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &SerialDevice->Handle,
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto CreateError;
+ }
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
+ (VOID **) &ParentIo,
+ gSerialControllerDriver.DriverBindingHandle,
+ SerialDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ SerialDevice->Handle,
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
+ NULL
+ );
+ }
+
+CreateError:
+ if (EFI_ERROR (Status)) {
+ if (SerialDevice->DevicePath != NULL) {
+ FreePool (SerialDevice->DevicePath);
+ }
+ if (SerialDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
+ }
+ FreePool (SerialDevice);
+ }
+ return Status;
+}
+
+/**
+ Returns an array of pointers containing all the child serial device pointers.
+
+ @param Controller The parent controller handle.
+ @param IoProtocolGuid The protocol GUID, either equals to gEfiSioProtocolGuid
+ or equals to gEfiPciIoProtocolGuid.
+ @param Count Count of the serial devices.
+
+ @return An array of pointers containing all the child serial device pointers.
+**/
+SERIAL_DEV **
+GetChildSerialDevices (
+ IN EFI_HANDLE Controller,
+ IN EFI_GUID *IoProtocolGuid,
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ SERIAL_DEV **SerialDevices;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ BOOLEAN OpenByDriver;
+
+ *Count = 0;
+ //
+ // If the SerialIo instance specified by RemainingDevicePath is already created,
+ // update the attributes/control.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ IoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *));
+ ASSERT (SerialDevices != NULL);
+
+ *Count = 0;
+ OpenByDriver = FALSE;
+ 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,
+ gSerialControllerDriver.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo);
+ }
+ }
+
+
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ ASSERT (OpenInfoBuffer[Index].AgentHandle == gSerialControllerDriver.DriverBindingHandle);
+ OpenByDriver = TRUE;
+ }
+ }
+ if (OpenInfoBuffer != NULL) {
+ FreePool (OpenInfoBuffer);
+ }
+
+ ASSERT ((*Count == 0) || (OpenByDriver));
+
+ return SerialDevices;
+}
+
+/**
+ 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;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ UINT32 ControllerNumber;
+ UART_DEVICE_PATH *Uart;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
+ UINT32 Control;
+ PARENT_IO_PROTOCOL_PTR ParentIo;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_GUID *IoProtocolGuid;
+ PCI_SERIAL_PARAMETER *PciSerialParameter;
+ PCI_SERIAL_PARAMETER DefaultPciSerialParameter;
+ PCI_TYPE00 Pci;
+ UINT32 PciSerialCount;
+ SERIAL_DEV **SerialDevices;
+ UINTN SerialDeviceCount;
+ PCI_DEVICE_INFO *PciDeviceInfo;
+ UINT64 Supports;
+ BOOLEAN ContainsControllerNode;
+
+ //
+ // 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
+ //
+ IoProtocolGuid = &gEfiSioProtocolGuid;
+ Status = gBS->OpenProtocol (
+ Controller,
+ IoProtocolGuid,
+ (VOID **) &ParentIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ IoProtocolGuid = &gEfiPciIoProtocolGuid;
+ Status = gBS->OpenProtocol (
+ Controller,
+ IoProtocolGuid,
+ (VOID **) &ParentIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+ ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED);
+
+ //
+ // Do nothing for END device path node
+ //
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ ControllerNumber = 0;
+ ContainsControllerNode = FALSE;
+ SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, &SerialDeviceCount);
+
+ if (SerialDeviceCount != 0) {
+ if (RemainingDevicePath == NULL) {
+ //
+ // If the SerialIo instance is already created, NULL as RemainingDevicePath is treated
+ // as to create the same SerialIo instance.
+ //
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Update the attributes/control of the SerialIo instance specified by RemainingDevicePath.
+ //
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
+ for (Index = 0; Index < SerialDeviceCount; Index++) {
+ ASSERT ((SerialDevices != NULL) && (SerialDevices[Index] != NULL));
+ if ((!SerialDevices[Index]->ContainsControllerNode && !ContainsControllerNode) ||
+ (SerialDevices[Index]->ContainsControllerNode && ContainsControllerNode && SerialDevices[Index]->Instance == ControllerNumber)
+ ) {
+ SerialIo = &SerialDevices[Index]->SerialIo;
+ Status = EFI_INVALID_PARAMETER;
+ //
+ // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate degrade.
+ // DriverBindingStart() shouldn't create a handle with different UART device path.
+ //
+ if (VerifyUartParameters (SerialDevices[Index]->ClockRate, Uart->BaudRate, Uart->DataBits,
+ (EFI_PARITY_TYPE) Uart->Parity, (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) {
+ 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) && IsUartFlowControlDevicePathNode (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;
+ }
+ }
+ if (Index != SerialDeviceCount) {
+ //
+ // Directly return if the SerialIo instance specified by RemainingDevicePath is found and updated.
+ // Otherwise continue to create the instance specified by RemainingDevicePath.
+ //
+ if (SerialDevices != NULL) {
+ FreePool (SerialDevices);
+ }
+ return Status;
+ }
+ }
+ }
+
+ if (RemainingDevicePath != NULL) {
+ Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode (RemainingDevicePath, &ContainsControllerNode, &ControllerNumber);
+ } else {
+ Uart = NULL;
+ }
+
+ PciDeviceInfo = NULL;
+ if (IoProtocolGuid == &gEfiSioProtocolGuid) {
+ Status = EFI_NOT_FOUND;
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {
+ Node = ParentDevicePath;
+ do {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ Node = NextDevicePathNode (Node);
+ } while (!IsDevicePathEnd (Node));
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, Acpi->UID, ParentIo, NULL, NULL);
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - %r\n", Status));
+ }
+ } else {
+ Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
+ if (!EFI_ERROR (Status)) {
+ //
+ // PcdPciSerialParameters takes the higher priority.
+ //
+ PciSerialCount = 0;
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId)
+ ) {
+ PciSerialCount++;
+ }
+ }
+
+ if (SerialDeviceCount == 0) {
+ //
+ // Enable the IO & MEM decoding when creating the first child.
+ // Restore the PCI attributes when all children is destroyed (PciDeviceInfo->ChildCount == 0).
+ //
+ PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO));
+ ASSERT (PciDeviceInfo != NULL);
+ PciDeviceInfo->ChildCount = 0;
+ PciDeviceInfo->PciIo = ParentIo.PciIo;
+ Status = ParentIo.PciIo->Attributes (
+ ParentIo.PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &PciDeviceInfo->PciAttributes
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = ParentIo.PciIo->Attributes (
+ ParentIo.PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY);
+ Status = ParentIo.PciIo->Attributes (
+ ParentIo.PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ }
+ } else {
+ //
+ // Re-use the PciDeviceInfo stored in existing children.
+ //
+ ASSERT ((SerialDevices != NULL) && (SerialDevices[0] != NULL));
+ PciDeviceInfo = SerialDevices[0]->PciDeviceInfo;
+ ASSERT (PciDeviceInfo != NULL);
+ }
+
+ Status = EFI_NOT_FOUND;
+ if (PciSerialCount <= 1) {
+ //
+ // PCI serial device contains only one UART
+ //
+ if (RemainingDevicePath == NULL || !ContainsControllerNode) {
+ //
+ // This PCI serial device is matched by class code in Supported()
+ //
+ if (PciSerialCount == 0) {
+ DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId;
+ DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId;
+ DefaultPciSerialParameter.BarIndex = 0;
+ DefaultPciSerialParameter.Offset = 0;
+ DefaultPciSerialParameter.RegisterStride = 0;
+ DefaultPciSerialParameter.ClockRate = 0;
+ PciSerialParameter = &DefaultPciSerialParameter;
+ } else if (PciSerialCount == 1) {
+ PciSerialParameter = PcdGetPtr (PcdPciSerialParameters);
+ }
+
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo);
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (single) - %r\n", Status));
+ if (!EFI_ERROR (Status)) {
+ PciDeviceInfo->ChildCount++;
+ }
+ }
+ } else {
+ //
+ // PCI serial device contains multiple UARTs
+ //
+ if (RemainingDevicePath == NULL || ContainsControllerNode) {
+ PciSerialCount = 0;
+ for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) {
+ if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) &&
+ (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) &&
+ ((RemainingDevicePath == NULL) || (ControllerNumber == PciSerialCount))
+ ) {
+ //
+ // Create controller node when PCI serial device contains multiple UARTs
+ //
+ Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, PciDeviceInfo);
+ PciSerialCount++;
+ DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device (multiple) - %r\n", Status));
+ if (!EFI_ERROR (Status)) {
+ PciDeviceInfo->ChildCount++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (SerialDevices != NULL) {
+ FreePool (SerialDevices);
+ }
+
+ //
+ // For multiple PCI serial devices, set Status to SUCCESS if one child is created successfully
+ //
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) {
+ if (PciDeviceInfo != NULL) {
+ Status = ParentIo.PciIo->Attributes (
+ ParentIo.PciIo,
+ EfiPciIoAttributeOperationSet,
+ PciDeviceInfo->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (PciDeviceInfo);
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ IoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ 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;
+ VOID *IoProtocol;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PCI_DEVICE_INFO *PciDeviceInfo;
+
+ PciDeviceInfo = NULL;
+
+ 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
+ );
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ &IoProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ gBS->CloseProtocol (
+ Controller,
+ !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_SUCCESS;
+ }
+
+ 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);
+ ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == SerialDevice->PciDeviceInfo));
+ PciDeviceInfo = SerialDevice->PciDeviceInfo;
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath,
+ &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : &gEfiSioProtocolGuid,
+ &IoProtocol,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (SerialDevice->DevicePath);
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
+ FreePool (SerialDevice);
+
+ if (PciDeviceInfo != NULL) {
+ ASSERT (PciDeviceInfo->ChildCount != 0);
+ PciDeviceInfo->ChildCount--;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // If all children are destroyed, restore the PCI attributes.
+ //
+ if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) {
+ ASSERT (PciDeviceInfo->PciIo != NULL);
+ Status = PciDeviceInfo->PciIo->Attributes (
+ PciDeviceInfo->PciIo,
+ EfiPciIoAttributeOperationSet,
+ PciDeviceInfo->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (PciDeviceInfo);
+ }
+ return EFI_SUCCESS;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h
new file mode 100644
index 000000000..fa5aba07e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h
@@ -0,0 +1,783 @@
+/** @file
+ Header file for PciSioSerial Driver
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/SuperIo.h>
+#include <Protocol/PciIo.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>
+#include <Library/IoLib.h>
+#include <Library/PrintLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver;
+extern EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2;
+
+#define SIO_SERIAL_PORT_NAME L"SIO Serial Port #%d"
+#define PCI_SERIAL_PORT_NAME L"PCI Serial Port #%d"
+#define SERIAL_PORT_NAME_LEN (sizeof (SIO_SERIAL_PORT_NAME) / sizeof (CHAR16) + MAXIMUM_VALUE_CHARACTERS)
+
+//
+// Internal Data Structures
+//
+#define TIMEOUT_STALL_INTERVAL 10
+
+#pragma pack(1)
+///
+/// PcdPciSerialParameters contains zero or more instances of the below structure.
+/// If a PCI device contains multiple UARTs, PcdPciSerialParameters needs to contain
+/// two instances of the below structure, with the VendorId and DeviceId equals to the
+/// device ID and vendor ID of the device. If the PCI device uses the first two BARs
+/// to support multiple UARTs, BarIndex of first instance equals to 0 and BarIndex of
+/// second one equals to 1; if the PCI device uses the first BAR to support multiple
+/// UARTs, BarIndex of both instance equals to 0 and Offset of first instance equals
+/// to 0 while Offset of second one equals to some value bigger or equal to 8.
+/// For certain UART whose register needs to be accessed in DWORD aligned address,
+/// RegisterStride equals to 4.
+///
+typedef struct {
+ UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries.
+ UINT16 DeviceId; ///< Device ID to match the PCI device
+ UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz
+ UINT64 Offset; ///< The byte offset into to the BAR
+ UINT8 BarIndex; ///< Which BAR to get the UART base address
+ UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte.
+ UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.
+ UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.
+ UINT8 Reserved[2];
+} PCI_SERIAL_PARAMETER;
+#pragma pack()
+
+#define SERIAL_MAX_FIFO_SIZE 17 ///< Actual FIFO size is 16. FIFO based on circular wastes one unit.
+typedef struct {
+ UINT16 Head; ///< Head pointer of the FIFO. Empty when (Head == Tail).
+ UINT16 Tail; ///< Tail pointer of the FIFO. Full when ((Tail + 1) % SERIAL_MAX_FIFO_SIZE == Head).
+ UINT8 Data[SERIAL_MAX_FIFO_SIZE]; ///< Store the FIFO data.
+} SERIAL_DEV_FIFO;
+
+typedef union {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SIO_PROTOCOL *Sio;
+} PARENT_IO_PROTOCOL_PTR;
+
+typedef struct {
+ EFI_PCI_IO_PROTOCOL *PciIo; // Pointer to parent PciIo instance.
+ UINTN ChildCount; // Count of child SerialIo instance.
+ UINT64 PciAttributes; // Original PCI attributes.
+} PCI_DEVICE_INFO;
+
+typedef struct {
+ UINT32 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_PHYSICAL_ADDRESS BaseAddress; ///< UART base address
+ BOOLEAN MmioAccess; ///< TRUE for MMIO, FALSE for IO
+ UINT8 RegisterStride; ///< UART Register Stride
+ UINT32 ClockRate; ///< UART clock rate
+
+ UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes.
+ SERIAL_DEV_FIFO Receive; ///< The FIFO used to store received data
+
+ UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes.
+ SERIAL_DEV_FIFO Transmit; ///< The FIFO used to store to-transmit data
+
+ BOOLEAN SoftwareLoopbackEnable;
+ BOOLEAN HardwareFlowControl;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ BOOLEAN ContainsControllerNode; ///< TRUE if the device produced contains Controller node
+ UINT32 Instance;
+ PCI_DEVICE_INFO *PciDeviceInfo;
+} SERIAL_DEV;
+
+#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd')
+#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, SERIAL_DEV_SIGNATURE)
+
+//
+// Serial Driver Defaults
+//
+#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)
+
+#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)
+
+///
+/// Interrupt Enable Register
+///
+typedef union {
+ struct {
+ UINT8 Ravie : 1; ///< Receiver Data Available Interrupt Enable
+ UINT8 Theie : 1; ///< Transmistter Holding Register Empty Interrupt Enable
+ UINT8 Rie : 1; ///< Receiver Interrupt Enable
+ UINT8 Mie : 1; ///< Modem Interrupt Enable
+ UINT8 Reserved : 4;
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_IER;
+
+///
+/// FIFO Control Register
+///
+typedef union {
+ struct {
+ UINT8 TrFIFOE : 1; ///< Transmit and Receive FIFO Enable
+ UINT8 ResetRF : 1; ///< Reset Reciever FIFO
+ UINT8 ResetTF : 1; ///< Reset Transmistter FIFO
+ UINT8 Dms : 1; ///< DMA Mode Select
+ UINT8 Reserved : 1;
+ UINT8 TrFIFO64 : 1; ///< Enable 64 byte FIFO
+ UINT8 Rtb : 2; ///< Receive Trigger Bits
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_FCR;
+
+///
+/// Line Control Register
+///
+typedef union {
+ struct {
+ UINT8 SerialDB : 2; ///< Number of Serial Data Bits
+ UINT8 StopB : 1; ///< Number of Stop Bits
+ UINT8 ParEn : 1; ///< Parity Enable
+ UINT8 EvenPar : 1; ///< Even Parity Select
+ UINT8 SticPar : 1; ///< Sticky Parity
+ UINT8 BrCon : 1; ///< Break Control
+ UINT8 DLab : 1; ///< Divisor Latch Access Bit
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_LCR;
+
+///
+/// Modem Control Register
+///
+typedef union {
+ struct {
+ UINT8 DtrC : 1; ///< Data Terminal Ready Control
+ UINT8 Rts : 1; ///< Request To Send Control
+ UINT8 Out1 : 1; ///< Output1
+ UINT8 Out2 : 1; ///< Output2, used to disable interrupt
+ UINT8 Lme : 1; ///< Loopback Mode Enable
+ UINT8 Reserved : 3;
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_MCR;
+
+///
+/// Line Status Register
+///
+typedef union {
+ struct {
+ UINT8 Dr : 1; ///< Receiver Data Ready Status
+ UINT8 Oe : 1; ///< Overrun Error Status
+ UINT8 Pe : 1; ///< Parity Error Status
+ UINT8 Fe : 1; ///< Framing Error Status
+ UINT8 Bi : 1; ///< Break Interrupt Status
+ UINT8 Thre : 1; ///< Transmistter Holding Register Status
+ UINT8 Temt : 1; ///< Transmitter Empty Status
+ UINT8 FIFOe : 1; ///< FIFO Error Status
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_LSR;
+
+///
+/// Modem Status Register
+///
+typedef union {
+ struct {
+ UINT8 DeltaCTS : 1; ///< Delta Clear To Send Status
+ UINT8 DeltaDSR : 1; ///< Delta Data Set Ready Status
+ UINT8 TrailingEdgeRI : 1; ///< Trailing Edge of Ring Indicator Status
+ UINT8 DeltaDCD : 1; ///< Delta Data Carrier Detect Status
+ UINT8 Cts : 1; ///< Clear To Send Status
+ UINT8 Dsr : 1; ///< Data Set Ready Status
+ UINT8 Ri : 1; ///< Ring Indicator Status
+ UINT8 Dcd : 1; ///< Data Carrier Detect Status
+ } Bits;
+ UINT8 Data;
+} SERIAL_PORT_MSR;
+
+#pragma pack()
+//
+// Define serial register I/O macros
+//
+#define READ_RBR(S) SerialReadRegister (S, SERIAL_REGISTER_RBR)
+#define READ_DLL(S) SerialReadRegister (S, SERIAL_REGISTER_DLL)
+#define READ_DLM(S) SerialReadRegister (S, SERIAL_REGISTER_DLM)
+#define READ_IER(S) SerialReadRegister (S, SERIAL_REGISTER_IER)
+#define READ_IIR(S) SerialReadRegister (S, SERIAL_REGISTER_IIR)
+#define READ_LCR(S) SerialReadRegister (S, SERIAL_REGISTER_LCR)
+#define READ_MCR(S) SerialReadRegister (S, SERIAL_REGISTER_MCR)
+#define READ_LSR(S) SerialReadRegister (S, SERIAL_REGISTER_LSR)
+#define READ_MSR(S) SerialReadRegister (S, SERIAL_REGISTER_MSR)
+#define READ_SCR(S) SerialReadRegister (S, SERIAL_REGISTER_SCR)
+
+#define WRITE_THR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_THR, D)
+#define WRITE_DLL(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLL, D)
+#define WRITE_DLM(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLM, D)
+#define WRITE_IER(S, D) SerialWriteRegister (S, SERIAL_REGISTER_IER, D)
+#define WRITE_FCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_FCR, D)
+#define WRITE_LCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LCR, D)
+#define WRITE_MCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MCR, D)
+#define WRITE_LSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LSR, D)
+#define WRITE_MSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MSR, D)
+#define WRITE_SCR(S, D) SerialWriteRegister (S, 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
+SerialReset (
+ 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
+SerialSetAttributes (
+ 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
+SerialSetControl (
+ 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
+SerialGetControl (
+ 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
+SerialWrite (
+ 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
+SerialRead (
+ 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
+SerialPresent (
+ 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
+SerialFifoFull (
+ 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
+SerialFifoEmpty (
+ 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
+SerialFifoAdd (
+ 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
+SerialFifoRemove (
+ IN SERIAL_DEV_FIFO *Fifo,
+ OUT UINT8 *Data
+ );
+
+/**
+ Reads and writes all available 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
+SerialReceiveTransmit (
+ IN SERIAL_DEV *SerialDevice
+ );
+
+/**
+ Read serial port.
+
+ @param SerialDev Pointer to serial device
+ @param Offset Offset in register group
+
+ @return Data read from serial port
+**/
+UINT8
+SerialReadRegister (
+ IN SERIAL_DEV *SerialDev,
+ IN UINT32 Offset
+ );
+
+/**
+ Write serial port.
+
+ @param SerialDev Pointer to serial device
+ @param Offset Offset in register group
+ @param Data data which is to be written to some serial port register
+**/
+VOID
+SerialWriteRegister (
+ IN SERIAL_DEV *SerialDev,
+ 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
+SerialComponentNameGetDriverName (
+ 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
+SerialComponentNameGetControllerName (
+ 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 Uid Unique ID for the serial device.
+**/
+VOID
+AddName (
+ IN SERIAL_DEV *SerialDevice,
+ IN UINT32 Uid
+ );
+
+/**
+ Checks whether the UART parameters are valid and computes the Divisor.
+
+ @param ClockRate The clock rate of the serial device used to verify
+ the BaudRate. Do not verify the BaudRate if it's 0.
+ @param BaudRate The requested baudrate of the serial device.
+ @param DataBits Number of databits used in serial device.
+ @param Parity The type of parity used in serial device.
+ @param StopBits Number of stopbits used in serial device.
+ @param Divisor Return the divisor if ClockRate is not 0.
+ @param ActualBaudRate Return the actual supported baudrate without
+ exceeding BaudRate. NULL means baudrate degradation
+ is not allowed.
+ If the requested BaudRate is not supported, the routine
+ returns TRUE and the Actual Baud Rate when ActualBaudRate
+ is not NULL, returns FALSE when ActualBaudRate is NULL.
+
+ @retval TRUE The UART parameters are valid.
+ @retval FALSE The UART parameters are not valid.
+**/
+BOOLEAN
+VerifyUartParameters (
+ IN UINT32 ClockRate,
+ IN UINT64 BaudRate,
+ IN UINT8 DataBits,
+ IN EFI_PARITY_TYPE Parity,
+ IN EFI_STOP_BITS_TYPE StopBits,
+ OUT UINT64 *Divisor,
+ OUT UINT64 *ActualBaudRate
+ );
+
+/**
+ Skip the optional Controller device path node and return the
+ pointer to the next device path node.
+
+ @param DevicePath Pointer to the device path.
+ @param ContainsControllerNode Returns TRUE if the Controller device path exists.
+ @param ControllerNumber Returns the Controller Number if Controller device path exists.
+
+ @return Pointer to the next device path node.
+**/
+UART_DEVICE_PATH *
+SkipControllerDevicePathNode (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ BOOLEAN *ContainsControllerNode,
+ UINT32 *ControllerNumber
+ );
+
+/**
+ 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
+IsUartFlowControlDevicePathNode (
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c
new file mode 100644
index 000000000..8377ffa13
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c
@@ -0,0 +1,1289 @@
+/** @file
+ SerialIo implementation for PCI or SIO UARTs.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Serial.h"
+
+/**
+ Skip the optional Controller device path node and return the
+ pointer to the next device path node.
+
+ @param DevicePath Pointer to the device path.
+ @param ContainsControllerNode Returns TRUE if the Controller device path exists.
+ @param ControllerNumber Returns the Controller Number if Controller device path exists.
+
+ @return Pointer to the next device path node.
+**/
+UART_DEVICE_PATH *
+SkipControllerDevicePathNode (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ BOOLEAN *ContainsControllerNode,
+ UINT32 *ControllerNumber
+ )
+{
+ if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)
+ ) {
+ if (ContainsControllerNode != NULL) {
+ *ContainsControllerNode = TRUE;
+ }
+ if (ControllerNumber != NULL) {
+ *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ if (ContainsControllerNode != NULL) {
+ *ContainsControllerNode = FALSE;
+ }
+ }
+ return (UART_DEVICE_PATH *) DevicePath;
+}
+
+/**
+ Checks whether the UART parameters are valid and computes the Divisor.
+
+ @param ClockRate The clock rate of the serial device used to verify
+ the BaudRate. Do not verify the BaudRate if it's 0.
+ @param BaudRate The requested baudrate of the serial device.
+ @param DataBits Number of databits used in serial device.
+ @param Parity The type of parity used in serial device.
+ @param StopBits Number of stopbits used in serial device.
+ @param Divisor Return the divisor if ClockRate is not 0.
+ @param ActualBaudRate Return the actual supported baudrate without
+ exceeding BaudRate. NULL means baudrate degradation
+ is not allowed.
+ If the requested BaudRate is not supported, the routine
+ returns TRUE and the Actual Baud Rate when ActualBaudRate
+ is not NULL, returns FALSE when ActualBaudRate is NULL.
+
+ @retval TRUE The UART parameters are valid.
+ @retval FALSE The UART parameters are not valid.
+**/
+BOOLEAN
+VerifyUartParameters (
+ IN UINT32 ClockRate,
+ IN UINT64 BaudRate,
+ IN UINT8 DataBits,
+ IN EFI_PARITY_TYPE Parity,
+ IN EFI_STOP_BITS_TYPE StopBits,
+ OUT UINT64 *Divisor,
+ OUT UINT64 *ActualBaudRate
+ )
+{
+ UINT64 Remainder;
+ UINT32 ComputedBaudRate;
+ UINT64 ComputedDivisor;
+ UINT64 Percent;
+
+ if ((DataBits < 5) || (DataBits > 8) ||
+ (Parity < NoParity) || (Parity > SpaceParity) ||
+ (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||
+ ((DataBits == 5) && (StopBits == TwoStopBits)) ||
+ ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))
+ ) {
+ return FALSE;
+ }
+
+ //
+ // Do not verify the baud rate if clock rate is unknown (0).
+ //
+ if (ClockRate == 0) {
+ return TRUE;
+ }
+
+ //
+ // Compute divisor use to program the baud rate using a round determination
+ // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
+ // = ClockRate / (BaudRate << 4)
+ //
+ ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);
+ //
+ // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
+ // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
+ //
+ if (Remainder >= LShiftU64 (BaudRate, 3)) {
+ ComputedDivisor++;
+ }
+ //
+ // If the computed divisor is larger than the maximum value that can be programmed
+ // into the UART, then the requested baud rate can not be supported.
+ //
+ if (ComputedDivisor > MAX_UINT16) {
+ return FALSE;
+ }
+
+ //
+ // If the computed divisor is 0, then use a computed divisor of 1, which will select
+ // the maximum supported baud rate.
+ //
+ if (ComputedDivisor == 0) {
+ ComputedDivisor = 1;
+ }
+
+ //
+ // Actual baud rate that the serial port will be programmed for
+ // should be with in 4% of requested one.
+ //
+ ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
+ if (ComputedBaudRate == 0) {
+ return FALSE;
+ }
+
+ Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);
+ DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
+ DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
+ DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
+
+ //
+ // If the requested BaudRate is not supported:
+ // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
+ // Returns FALSE when ActualBaudRate is NULL.
+ //
+ if ((Percent >= 96) && (Percent <= 104)) {
+ if (ActualBaudRate != NULL) {
+ *ActualBaudRate = BaudRate;
+ }
+ if (Divisor != NULL) {
+ *Divisor = ComputedDivisor;
+ }
+ return TRUE;
+ }
+ if (ComputedBaudRate < BaudRate) {
+ if (ActualBaudRate != NULL) {
+ *ActualBaudRate = ComputedBaudRate;
+ }
+ if (Divisor != NULL) {
+ *Divisor = ComputedDivisor;
+ }
+ return TRUE;
+ }
+
+ //
+ // ActualBaudRate is higher than requested baud rate and more than 4%
+ // higher than the requested value. Increment Divisor if it is less
+ // than MAX_UINT16 and computed baud rate with new divisor.
+ //
+ if (ComputedDivisor == MAX_UINT16) {
+ return FALSE;
+ }
+ ComputedDivisor++;
+ ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
+ if (ComputedBaudRate == 0) {
+ return FALSE;
+ }
+
+ DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
+ DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
+ DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
+
+ if (ActualBaudRate != NULL) {
+ *ActualBaudRate = ComputedBaudRate;
+ }
+ if (Divisor != NULL) {
+ *Divisor = ComputedDivisor;
+ }
+ return TRUE;
+}
+
+/**
+ 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
+SerialFifoFull (
+ IN SERIAL_DEV_FIFO *Fifo
+ )
+{
+ return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);
+}
+
+/**
+ 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
+SerialFifoEmpty (
+ IN SERIAL_DEV_FIFO *Fifo
+ )
+
+{
+ return (BOOLEAN) (Fifo->Head == Fifo->Tail);
+}
+
+/**
+ 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
+SerialFifoAdd (
+ IN OUT SERIAL_DEV_FIFO *Fifo,
+ IN UINT8 Data
+ )
+{
+ //
+ // if FIFO full can not add data
+ //
+ if (SerialFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not full can add data
+ //
+ Fifo->Data[Fifo->Tail] = Data;
+ Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;
+ 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
+SerialFifoRemove (
+ IN OUT SERIAL_DEV_FIFO *Fifo,
+ OUT UINT8 *Data
+ )
+{
+ //
+ // if FIFO is empty, no data can remove
+ //
+ if (SerialFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not empty, can remove data
+ //
+ *Data = Fifo->Data[Fifo->Head];
+ Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads and writes all available data.
+
+ @param SerialDevice The device to transmit.
+
+ @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
+SerialReceiveTransmit (
+ 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 = SerialFifoFull (&SerialDevice->Receive);
+ if (!SerialFifoEmpty (&SerialDevice->Transmit)) {
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);
+ if (ReceiveFifoFull) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SerialFifoAdd (&SerialDevice->Receive, Data);
+ }
+ } while (!SerialFifoEmpty (&SerialDevice->Transmit));
+ } else {
+ ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
+ //
+ // For full handshake flow control, tell the peer to send data
+ // if receive buffer is available.
+ //
+ if (SerialDevice->HardwareFlowControl &&
+ !FeaturePcdGet(PcdSerialUseHalfHandshake)&&
+ !ReceiveFifoFull
+ ) {
+ Mcr.Data = READ_MCR (SerialDevice);
+ Mcr.Bits.Rts = 1;
+ WRITE_MCR (SerialDevice, Mcr.Data);
+ }
+ do {
+ Lsr.Data = READ_LSR (SerialDevice);
+
+ //
+ // Flush incomming data to prevent a an overrun during a long write
+ //
+ if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
+ ReceiveFifoFull = SerialFifoFull (&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);
+ continue;
+ }
+ }
+
+ Data = READ_RBR (SerialDevice);
+
+ SerialFifoAdd (&SerialDevice->Receive, Data);
+
+ //
+ // For full handshake flow control, if receive buffer full
+ // tell the peer to stop sending data.
+ //
+ if (SerialDevice->HardwareFlowControl &&
+ !FeaturePcdGet(PcdSerialUseHalfHandshake) &&
+ SerialFifoFull (&SerialDevice->Receive)
+ ) {
+ Mcr.Data = READ_MCR (SerialDevice);
+ Mcr.Bits.Rts = 0;
+ WRITE_MCR (SerialDevice, 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 && !SerialFifoEmpty (&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(PcdSerialUseHalfHandshake)) {
+ Mcr.Data = READ_MCR (SerialDevice);
+ Mcr.Bits.Rts= 0;
+ WRITE_MCR (SerialDevice, Mcr.Data);
+ }
+ //
+ // Wait for CTS
+ //
+ TimeOut = 0;
+ Msr.Data = READ_MSR (SerialDevice);
+ while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);
+ TimeOut++;
+ if (TimeOut > 5) {
+ break;
+ }
+
+ Msr.Data = READ_MSR (SerialDevice);
+ }
+
+ if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);
+ WRITE_THR (SerialDevice, Data);
+ }
+
+ //
+ // For half handshake flow control, tell DCE we are done.
+ //
+ if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
+ Mcr.Data = READ_MCR (SerialDevice);
+ Mcr.Bits.Rts = 1;
+ WRITE_MCR (SerialDevice, Mcr.Data);
+ }
+ } else {
+ SerialFifoRemove (&SerialDevice->Transmit, &Data);
+ WRITE_THR (SerialDevice, Data);
+ }
+ }
+ } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&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
+SerialReset (
+ 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);
+ Lcr.Bits.DLab = 0;
+ WRITE_LCR (SerialDevice, Lcr.Data);
+
+ //
+ // Turn off all interrupts
+ //
+ Ier.Data = READ_IER (SerialDevice);
+ Ier.Bits.Ravie = 0;
+ Ier.Bits.Theie = 0;
+ Ier.Bits.Rie = 0;
+ Ier.Bits.Mie = 0;
+ WRITE_IER (SerialDevice, Ier.Data);
+
+ //
+ // Reset the FIFO
+ //
+ Fcr.Data = 0;
+ Fcr.Bits.TrFIFOE = 0;
+ WRITE_FCR (SerialDevice, Fcr.Data);
+
+ //
+ // Turn off loopback and disable device interrupt.
+ //
+ Mcr.Data = READ_MCR (SerialDevice);
+ Mcr.Bits.Out1 = 0;
+ Mcr.Bits.Out2 = 0;
+ Mcr.Bits.Lme = 0;
+ WRITE_MCR (SerialDevice, Mcr.Data);
+
+ //
+ // Clear the scratch pad register
+ //
+ WRITE_SCR (SerialDevice, 0);
+
+ //
+ // Enable FIFO
+ //
+ Fcr.Bits.TrFIFOE = 1;
+ if (SerialDevice->ReceiveFifoDepth > 16) {
+ Fcr.Bits.TrFIFO64 = 1;
+ }
+ Fcr.Bits.ResetRF = 1;
+ Fcr.Bits.ResetTF = 1;
+ WRITE_FCR (SerialDevice, Fcr.Data);
+
+ //
+ // 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;
+ }
+
+ //
+ // Reset the software FIFO
+ //
+ SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;
+ SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;
+ 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
+SerialSetAttributes (
+ 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;
+ UINT64 Divisor;
+ 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 = SerialDevice->ReceiveFifoDepth;
+ }
+
+ 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);
+ }
+
+ if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Put serial port on Divisor Latch Mode
+ //
+ Lcr.Data = READ_LCR (SerialDevice);
+ Lcr.Bits.DLab = 1;
+ WRITE_LCR (SerialDevice, Lcr.Data);
+
+ //
+ // Write the divisor to the serial port
+ //
+ WRITE_DLL (SerialDevice, (UINT8) Divisor);
+ WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));
+
+ //
+ // 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, 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) {
+
+ //
+ // Skip the optional Controller device path node
+ //
+ Uart = SkipControllerDevicePathNode (
+ (EFI_DEVICE_PATH_PROTOCOL *) (
+ (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH
+ ),
+ NULL,
+ NULL
+ );
+ 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
+SerialSetControl (
+ 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);
+ 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, 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 (IsUartFlowControlDevicePathNode (FlowControl) &&
+ ((BOOLEAN) (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
+SerialGetControl (
+ 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);
+
+ 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);
+
+ 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;
+ }
+ //
+ // Update FIFO status
+ //
+ SerialReceiveTransmit (SerialDevice);
+
+ //
+ // See if the Transmit FIFO is empty
+ //
+ if (SerialFifoEmpty (&SerialDevice->Transmit)) {
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+ }
+
+ //
+ // See if the Receive FIFO is empty.
+ //
+ if (SerialFifoEmpty (&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
+SerialWrite (
+ 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 * (SerialDevice->TransmitFifoDepth + 1) * 1000000,
+ This->Mode->BaudRate,
+ NULL
+ )
+ );
+
+ for (Index = 0; Index < *BufferSize; Index++) {
+ SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
+
+ while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&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
+SerialRead (
+ 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 = SerialReceiveTransmit (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 (SerialFifoRemove (&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 = SerialReceiveTransmit (SerialDevice);
+ if (Status == EFI_DEVICE_ERROR) {
+ *BufferSize = Index;
+ gBS->RestoreTPL (Tpl);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Successful read so reset timeout
+ //
+ Elapsed = 0;
+ }
+
+ SerialReceiveTransmit (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
+SerialPresent (
+ IN SERIAL_DEV *SerialDevice
+ )
+
+{
+ UINT8 Temp;
+ BOOLEAN Status;
+
+ Status = TRUE;
+
+ //
+ // Save SCR reg
+ //
+ Temp = READ_SCR (SerialDevice);
+ WRITE_SCR (SerialDevice, 0xAA);
+
+ if (READ_SCR (SerialDevice) != 0xAA) {
+ Status = FALSE;
+ }
+
+ WRITE_SCR (SerialDevice, 0x55);
+
+ if (READ_SCR (SerialDevice) != 0x55) {
+ Status = FALSE;
+ }
+ //
+ // Restore SCR
+ //
+ WRITE_SCR (SerialDevice, Temp);
+ return Status;
+}
+
+/**
+ Read serial port.
+
+ @param SerialDev Pointer to serial device
+ @param Offset Offset in register group
+
+ @return Data read from serial port
+
+**/
+UINT8
+SerialReadRegister (
+ IN SERIAL_DEV *SerialDev,
+ IN UINT32 Offset
+ )
+{
+ UINT8 Data;
+ EFI_STATUS Status;
+
+ if (SerialDev->PciDeviceInfo == NULL) {
+ return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);
+ } else {
+ if (SerialDev->MmioAccess) {
+ Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
+ } else {
+ Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
+ }
+ ASSERT_EFI_ERROR (Status);
+ return Data;
+ }
+}
+
+/**
+ Write serial port.
+
+ @param SerialDev Pointer to serial device
+ @param Offset Offset in register group
+ @param Data data which is to be written to some serial port register
+**/
+VOID
+SerialWriteRegister (
+ IN SERIAL_DEV *SerialDev,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+
+ if (SerialDev->PciDeviceInfo == NULL) {
+ IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);
+ } else {
+ if (SerialDev->MmioAccess) {
+ Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
+ } else {
+ Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
+ SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
+ }
+ ASSERT_EFI_ERROR (Status);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/ComponentName.c
new file mode 100644
index 000000000..5086d7747
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/ComponentName.c
@@ -0,0 +1,171 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Sata Controller driver.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SataController.h"
+
+//
+/// EFI Component Name Protocol
+///
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSataControllerComponentName = {
+ SataControllerComponentNameGetDriverName,
+ SataControllerComponentNameGetControllerName,
+ "eng"
+};
+
+//
+/// EFI Component Name 2 Protocol
+///
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSataControllerComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SataControllerComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SataControllerComponentNameGetControllerName,
+ "en"
+};
+
+//
+/// Driver Name Strings
+///
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataControllerDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Sata Controller Init Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+///
+/// Controller Name Strings
+///
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataControllerControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Sata Controller"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the UEFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ @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
+SataControllerComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSataControllerDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSataControllerComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an UEFI Driver.
+
+ @param This A pointer to the 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 OPTIONAL 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 three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ @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 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 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
+SataControllerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSataControllerDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSataControllerControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSataControllerComponentName)
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.c b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.c
new file mode 100644
index 000000000..ab06e2833
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.c
@@ -0,0 +1,1108 @@
+/** @file
+ This driver module produces IDE_CONTROLLER_INIT protocol for Sata Controllers.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, ARM Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SataController.h"
+
+///
+/// EFI_DRIVER_BINDING_PROTOCOL instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gSataControllerDriverBinding = {
+ SataControllerSupported,
+ SataControllerStart,
+ SataControllerStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Read AHCI Operation register.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Offset The operation register offset.
+
+ @return The register content read.
+
+**/
+UINT32
+EFIAPI
+AhciReadReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ ASSERT (PciIo != NULL);
+
+ Data = 0;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ AHCI_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ This function is used to calculate the best PIO mode supported by specific IDE device
+
+ @param IdentifyData The identify data of specific IDE device.
+ @param DisPioMode Disqualified PIO modes collection.
+ @param SelectedMode Available PIO modes collection.
+
+ @retval EFI_SUCCESS Best PIO modes are returned.
+ @retval EFI_UNSUPPORTED The device doesn't support PIO mode,
+ or all supported modes have been disqualified.
+**/
+EFI_STATUS
+CalculateBestPioMode (
+ IN EFI_IDENTIFY_DATA *IdentifyData,
+ IN UINT16 *DisPioMode OPTIONAL,
+ OUT UINT16 *SelectedMode
+ )
+{
+ UINT16 PioMode;
+ UINT16 AdvancedPioMode;
+ UINT16 Temp;
+ UINT16 Index;
+ UINT16 MinimumPioCycleTime;
+
+ Temp = 0xff;
+
+ PioMode = (UINT8) (((ATA5_IDENTIFY_DATA *) (&(IdentifyData->AtaData)))->pio_cycle_timing >> 8);
+
+ //
+ // See whether Identify Data word 64 - 70 are valid
+ //
+ if ((IdentifyData->AtaData.field_validity & 0x02) == 0x02) {
+
+ AdvancedPioMode = IdentifyData->AtaData.advanced_pio_modes;
+ DEBUG ((EFI_D_INFO, "CalculateBestPioMode: AdvancedPioMode = %x\n", AdvancedPioMode));
+
+ for (Index = 0; Index < 8; Index++) {
+ if ((AdvancedPioMode & 0x01) != 0) {
+ Temp = Index;
+ }
+
+ AdvancedPioMode >>= 1;
+ }
+
+ //
+ // If Temp is modified, mean the advanced_pio_modes is not zero;
+ // if Temp is not modified, mean there is no advanced PIO mode supported,
+ // the best PIO Mode is the value in pio_cycle_timing.
+ //
+ if (Temp != 0xff) {
+ AdvancedPioMode = (UINT16) (Temp + 3);
+ } else {
+ AdvancedPioMode = PioMode;
+ }
+
+ //
+ // Limit the PIO mode to at most PIO4.
+ //
+ PioMode = (UINT16) MIN (AdvancedPioMode, 4);
+
+ MinimumPioCycleTime = IdentifyData->AtaData.min_pio_cycle_time_with_flow_control;
+
+ if (MinimumPioCycleTime <= 120) {
+ PioMode = (UINT16) MIN (4, PioMode);
+ } else if (MinimumPioCycleTime <= 180) {
+ PioMode = (UINT16) MIN (3, PioMode);
+ } else if (MinimumPioCycleTime <= 240) {
+ PioMode = (UINT16) MIN (2, PioMode);
+ } else {
+ PioMode = 0;
+ }
+
+ //
+ // Degrade the PIO mode if the mode has been disqualified
+ //
+ if (DisPioMode != NULL) {
+ if (*DisPioMode < 2) {
+ return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2
+ }
+
+ if (PioMode >= *DisPioMode) {
+ PioMode = (UINT16) (*DisPioMode - 1);
+ }
+ }
+
+ if (PioMode < 2) {
+ *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2;
+ } else {
+ *SelectedMode = PioMode; // ATA_PIO_MODE_2 to ATA_PIO_MODE_4;
+ }
+
+ } else {
+ //
+ // Identify Data word 64 - 70 are not valid
+ // Degrade the PIO mode if the mode has been disqualified
+ //
+ if (DisPioMode != NULL) {
+ if (*DisPioMode < 2) {
+ return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2
+ }
+
+ if (PioMode == *DisPioMode) {
+ PioMode--;
+ }
+ }
+
+ if (PioMode < 2) {
+ *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2;
+ } else {
+ *SelectedMode = 2; // ATA_PIO_MODE_2;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to calculate the best UDMA mode supported by specific IDE device
+
+ @param IdentifyData The identify data of specific IDE device.
+ @param DisUDmaMode Disqualified UDMA modes collection.
+ @param SelectedMode Available UDMA modes collection.
+
+ @retval EFI_SUCCESS Best UDMA modes are returned.
+ @retval EFI_UNSUPPORTED The device doesn't support UDMA mode,
+ or all supported modes have been disqualified.
+**/
+EFI_STATUS
+CalculateBestUdmaMode (
+ IN EFI_IDENTIFY_DATA *IdentifyData,
+ IN UINT16 *DisUDmaMode OPTIONAL,
+ OUT UINT16 *SelectedMode
+ )
+{
+ UINT16 TempMode;
+ UINT16 DeviceUDmaMode;
+
+ DeviceUDmaMode = 0;
+
+ //
+ // Check whether the WORD 88 (supported UltraDMA by drive) is valid
+ //
+ if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode;
+ DEBUG ((EFI_D_INFO, "CalculateBestUdmaMode: DeviceUDmaMode = %x\n", DeviceUDmaMode));
+ DeviceUDmaMode &= 0x3f;
+ TempMode = 0; // initialize it to UDMA-0
+
+ while ((DeviceUDmaMode >>= 1) != 0) {
+ TempMode++;
+ }
+
+ //
+ // Degrade the UDMA mode if the mode has been disqualified
+ //
+ if (DisUDmaMode != NULL) {
+ if (*DisUDmaMode == 0) {
+ *SelectedMode = 0;
+ return EFI_UNSUPPORTED; // no mode below ATA_UDMA_MODE_0
+ }
+
+ if (TempMode >= *DisUDmaMode) {
+ TempMode = (UINT16) (*DisUDmaMode - 1);
+ }
+ }
+
+ //
+ // Possible returned mode is between ATA_UDMA_MODE_0 and ATA_UDMA_MODE_5
+ //
+ *SelectedMode = TempMode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The Entry Point of module. It follows the standard UEFI driver model.
+
+ @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
+InitializeSataControllerDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSataControllerDriverBinding,
+ ImageHandle,
+ &gSataControllerComponentName,
+ &gSataControllerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Supported function of Driver Binding protocol for this driver.
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath A pointer to the device path.
+ it should be ignored by device driver.
+
+ @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
+SataControllerSupported (
+ 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 PciData;
+
+ //
+ // Attempt to open 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;
+ }
+
+ //
+ // Now further check the PCI header: Base Class (offset 0x0B) and
+ // Sub Class (offset 0x0A). This controller should be an SATA controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (PciData.Hdr.ClassCode),
+ PciData.Hdr.ClassCode
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (IS_PCI_IDE (&PciData) || IS_PCI_SATADPA (&PciData)) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This routine is called right after the .Supported() called and
+ Start this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath A pointer to the device path.
+ it should be ignored by device driver.
+
+ @retval EFI_SUCCESS This driver is added to this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other Some error occurs when binding this driver to this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SataControllerStart (
+ 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 PciData;
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+ UINT32 Data32;
+ UINTN TotalCount;
+ UINT64 Supports;
+ UINT8 MaxPortNumber;
+
+ DEBUG ((EFI_D_INFO, "SataControllerStart start\n"));
+
+ Private = NULL;
+
+ //
+ // Now test and open PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SataControllerStart error. return status = %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Allocate Sata Private Data structure
+ //
+ Private = AllocateZeroPool (sizeof (EFI_SATA_CONTROLLER_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize Sata Private Data
+ //
+ Private->Signature = SATA_CONTROLLER_SIGNATURE;
+ Private->PciIo = PciIo;
+ Private->IdeInit.GetChannelInfo = IdeInitGetChannelInfo;
+ Private->IdeInit.NotifyPhase = IdeInitNotifyPhase;
+ Private->IdeInit.SubmitData = IdeInitSubmitData;
+ Private->IdeInit.DisqualifyMode = IdeInitDisqualifyMode;
+ Private->IdeInit.CalculateMode = IdeInitCalculateMode;
+ Private->IdeInit.SetTiming = IdeInitSetTiming;
+ Private->IdeInit.EnumAll = SATA_ENUMER_ALL;
+ Private->PciAttributesChanged = FALSE;
+
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->OriginalPciAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ "Original PCI Attributes = 0x%llx\n",
+ Private->OriginalPciAttributes
+ ));
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, "Supported PCI Attributes = 0x%llx\n", Supports));
+
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, "Enabled PCI Attributes = 0x%llx\n", Supports));
+ Private->PciAttributesChanged = TRUE;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (PciData.Hdr.ClassCode),
+ PciData.Hdr.ClassCode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (FALSE);
+ goto Done;
+ }
+
+ if (IS_PCI_IDE (&PciData)) {
+ Private->IdeInit.ChannelCount = IDE_MAX_CHANNEL;
+ Private->DeviceCount = IDE_MAX_DEVICES;
+ } else if (IS_PCI_SATADPA (&PciData)) {
+ //
+ // Read Ports Implemented(PI) to calculate max port number (0 based).
+ //
+ Data32 = AhciReadReg (PciIo, R_AHCI_PI);
+ DEBUG ((DEBUG_INFO, "Ports Implemented(PI) = 0x%x\n", Data32));
+ if (Data32 == 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ MaxPortNumber = 31;
+ while (MaxPortNumber > 0) {
+ if ((Data32 & ((UINT32)1 << MaxPortNumber)) != 0) {
+ break;
+ }
+ MaxPortNumber--;
+ }
+ //
+ // Make the ChannelCount equal to the max port number (0 based) plus 1.
+ //
+ Private->IdeInit.ChannelCount = MaxPortNumber + 1;
+
+ //
+ // Read HBA Capabilities(CAP) to get Supports Port Multiplier(SPM).
+ //
+ Data32 = AhciReadReg (PciIo, R_AHCI_CAP);
+ DEBUG ((DEBUG_INFO, "HBA Capabilities(CAP) = 0x%x\n", Data32));
+ Private->DeviceCount = AHCI_MAX_DEVICES;
+ if ((Data32 & B_AHCI_CAP_SPM) == B_AHCI_CAP_SPM) {
+ Private->DeviceCount = AHCI_MULTI_MAX_DEVICES;
+ }
+ }
+
+ TotalCount = (UINTN) (Private->IdeInit.ChannelCount) * (UINTN) (Private->DeviceCount);
+ Private->DisqualifiedModes = AllocateZeroPool ((sizeof (EFI_ATA_COLLECTIVE_MODE)) * TotalCount);
+ if (Private->DisqualifiedModes == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->IdentifyData = AllocateZeroPool ((sizeof (EFI_IDENTIFY_DATA)) * TotalCount);
+ if (Private->IdentifyData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->IdentifyValid = AllocateZeroPool ((sizeof (BOOLEAN)) * TotalCount);
+ if (Private->IdentifyValid == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Install IDE Controller Init Protocol to this instance
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ &(Private->IdeInit),
+ NULL
+ );
+
+Done:
+ if (EFI_ERROR (Status)) {
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (Private != NULL) {
+ if (Private->DisqualifiedModes != NULL) {
+ FreePool (Private->DisqualifiedModes);
+ }
+ if (Private->IdentifyData != NULL) {
+ FreePool (Private->IdentifyData);
+ }
+ if (Private->IdentifyValid != NULL) {
+ FreePool (Private->IdentifyValid);
+ }
+ if (Private->PciAttributesChanged) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+ }
+ FreePool (Private);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "SataControllerStart end with %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller 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 from this device.
+ @retval other Some error occurs when removing this driver from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SataControllerStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+
+ //
+ // Open the produced protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (IdeInit);
+ ASSERT (Private != NULL);
+
+ //
+ // Uninstall the IDE Controller Init Protocol from this instance
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ &(Private->IdeInit),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private != NULL) {
+ if (Private->DisqualifiedModes != NULL) {
+ FreePool (Private->DisqualifiedModes);
+ }
+ if (Private->IdentifyData != NULL) {
+ FreePool (Private->IdentifyData);
+ }
+ if (Private->IdentifyValid != NULL) {
+ FreePool (Private->IdentifyValid);
+ }
+ if (Private->PciAttributesChanged) {
+ //
+ // Restore original PCI attributes
+ //
+ Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+ }
+ FreePool (Private);
+ }
+
+ //
+ // Close protocols opened by Sata Controller driver
+ //
+ return gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+}
+
+/**
+ Calculate the flat array subscript of a (Channel, Device) pair.
+
+ @param[in] Private The private data structure corresponding to the
+ SATA controller that attaches the device for
+ which the flat array subscript is being
+ calculated.
+
+ @param[in] Channel The channel (ie. port) number on the SATA
+ controller that the device is attached to.
+
+ @param[in] Device The device number on the channel.
+
+ @return The flat array subscript suitable for indexing DisqualifiedModes,
+ IdentifyData, and IdentifyValid.
+**/
+STATIC
+UINTN
+FlatDeviceIndex (
+ IN CONST EFI_SATA_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINTN Channel,
+ IN UINTN Device
+ )
+{
+ ASSERT (Private != NULL);
+ ASSERT (Channel < Private->IdeInit.ChannelCount);
+ ASSERT (Device < Private->DeviceCount);
+
+ return Channel * Private->DeviceCount + Device;
+}
+
+//
+// Interface functions of IDE_CONTROLLER_INIT protocol
+//
+/**
+ Returns the information about the specified IDE channel.
+
+ This function can be used to obtain information about a particular IDE channel.
+ The driver entity uses this information during the enumeration process.
+
+ If Enabled is set to FALSE, the driver entity will not scan the channel. Note
+ that it will not prevent an operating system driver from scanning the channel.
+
+ For most of today's controllers, MaxDevices will either be 1 or 2. For SATA
+ controllers, this value will always be 1. SATA configurations can contain SATA
+ port multipliers. SATA port multipliers behave like SATA bridges and can support
+ up to 16 devices on the other side. If a SATA port out of the IDE controller
+ is connected to a port multiplier, MaxDevices will be set to the number of SATA
+ devices that the port multiplier supports. Because today's port multipliers
+ support up to fifteen SATA devices, this number can be as large as fifteen. The IDE
+ bus driver is required to scan for the presence of port multipliers behind an SATA
+ controller and enumerate up to MaxDevices number of devices behind the port
+ multiplier.
+
+ In this context, the devices behind a port multiplier constitute a channel.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[out] Enabled TRUE if this channel is enabled. Disabled channels
+ are not scanned to see if any devices are present.
+ @param[out] MaxDevices The maximum number of IDE devices that the bus driver
+ can expect on this channel. For the ATA/ATAPI
+ specification, version 6, this number will either be
+ one or two. For Serial ATA (SATA) configurations with a
+ port multiplier, this number can be as large as fifteen.
+
+ @retval EFI_SUCCESS Information was returned without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitGetChannelInfo (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ OUT BOOLEAN *Enabled,
+ OUT UINT8 *MaxDevices
+ )
+{
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+ Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ if (Channel < This->ChannelCount) {
+ *Enabled = TRUE;
+ *MaxDevices = Private->DeviceCount;
+ return EFI_SUCCESS;
+ }
+
+ *Enabled = FALSE;
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ The notifications from the driver entity that it is about to enter a certain
+ phase of the IDE channel enumeration process.
+
+ This function can be used to notify the IDE controller driver to perform
+ specific actions, including any chipset-specific initialization, so that the
+ chipset is ready to enter the next phase. Seven notification points are defined
+ at this time.
+
+ More synchronization points may be added as required in the future.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL
+ instance.
+ @param[in] Phase The phase during enumeration.
+ @param[in] Channel Zero-based channel number.
+
+ @retval EFI_SUCCESS The notification was accepted without any errors.
+ @retval EFI_UNSUPPORTED Phase is not supported.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_NOT_READY This phase cannot be entered at this time; for
+ example, an attempt was made to enter a Phase
+ without having entered one or more previous
+ Phase.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitNotifyPhase (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase,
+ IN UINT8 Channel
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Submits the device information to the IDE controller driver.
+
+ This function is used by the driver entity to pass detailed information about
+ a particular device to the IDE controller driver. The driver entity obtains
+ this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData
+ is the pointer to the response data buffer. The IdentifyData buffer is owned
+ by the driver entity, and the IDE controller driver must make a local copy
+ of the entire buffer or parts of the buffer as needed. The original IdentifyData
+ buffer pointer may not be valid when
+
+ - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or
+ - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point.
+
+ The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to
+ compute the optimum mode for the device. These fields are not limited to the
+ timing information. For example, an implementation of the IDE controller driver
+ may examine the vendor and type/mode field to match known bad drives.
+
+ The driver entity may submit drive information in any order, as long as it
+ submits information for all the devices belonging to the enumeration group
+ before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device
+ in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ should be called with IdentifyData set to NULL. The IDE controller driver may
+ not have any other mechanism to know whether a device is present or not. Therefore,
+ setting IdentifyData to NULL does not constitute an error condition.
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a
+ given (Channel, Device) pair.
+
+ @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[in] Device Zero-based device number on the Channel.
+ @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command.
+
+ @retval EFI_SUCCESS The information was accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitSubmitData (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_IDENTIFY_DATA *IdentifyData
+ )
+{
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+ UINTN DeviceIndex;
+
+ Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ if ((Channel >= This->ChannelCount) || (Device >= Private->DeviceCount)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceIndex = FlatDeviceIndex (Private, Channel, Device);
+
+ //
+ // Make a local copy of device's IdentifyData and mark the valid flag
+ //
+ if (IdentifyData != NULL) {
+ CopyMem (
+ &(Private->IdentifyData[DeviceIndex]),
+ IdentifyData,
+ sizeof (EFI_IDENTIFY_DATA)
+ );
+
+ Private->IdentifyValid[DeviceIndex] = TRUE;
+ } else {
+ Private->IdentifyValid[DeviceIndex] = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disqualifies specific modes for an IDE device.
+
+ This function allows the driver entity or other drivers (such as platform
+ drivers) to reject certain timing modes and request the IDE controller driver
+ to recalculate modes. This function allows the driver entity and the IDE
+ controller driver to negotiate the timings on a per-device basis. This function
+ is useful in the case of drives that lie about their capabilities. An example
+ is when the IDE device fails to accept the timing modes that are calculated
+ by the IDE controller driver based on the response to the Identify Drive command.
+
+ If the driver entity does not want to limit the ATA timing modes and leave that
+ decision to the IDE controller driver, it can either not call this function for
+ the given device or call this function and set the Valid flag to FALSE for all
+ modes that are listed in EFI_ATA_COLLECTIVE_MODE.
+
+ The driver entity may disqualify modes for a device in any order and any number
+ of times.
+
+ This function can be called multiple times to invalidate multiple modes of the
+ same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI
+ specification for more information on PIO modes.
+
+ For Serial ATA (SATA) controllers, this member function can be used to disqualify
+ a higher transfer rate mode on a given channel. For example, a platform driver
+ may inform the IDE controller driver to not use second-generation (Gen2) speeds
+ for a certain SATA drive.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel The zero-based channel number.
+ @param[in] Device The zero-based device number on the Channel.
+ @param[in] BadModes The modes that the device does not support and that
+ should be disqualified.
+
+ @retval EFI_SUCCESS The modes were accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_INVALID_PARAMETER IdentifyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitDisqualifyMode (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_COLLECTIVE_MODE *BadModes
+ )
+{
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+ UINTN DeviceIndex;
+
+ Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ if ((Channel >= This->ChannelCount) || (BadModes == NULL) || (Device >= Private->DeviceCount)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DeviceIndex = FlatDeviceIndex (Private, Channel, Device);
+
+ //
+ // Record the disqualified modes per channel per device. From ATA/ATAPI spec,
+ // if a mode is not supported, the modes higher than it is also not supported.
+ //
+ CopyMem (
+ &(Private->DisqualifiedModes[DeviceIndex]),
+ BadModes,
+ sizeof (EFI_ATA_COLLECTIVE_MODE)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the information about the optimum modes for the specified IDE device.
+
+ This function is used by the driver entity to obtain the optimum ATA modes for
+ a specific device. The IDE controller driver takes into account the following
+ while calculating the mode:
+ - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode()
+
+ The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ for all the devices that belong to an enumeration group before calling
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group.
+
+ The IDE controller driver will use controller- and possibly platform-specific
+ algorithms to arrive at SupportedModes. The IDE controller may base its
+ decision on user preferences and other considerations as well. This function
+ may be called multiple times because the driver entity may renegotiate the mode
+ with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode().
+
+ The driver entity may collect timing information for various devices in any
+ order. The driver entity is responsible for making sure that all the dependencies
+ are satisfied. For example, the SupportedModes information for device A that
+ was previously returned may become stale after a call to
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B.
+
+ The buffer SupportedModes is allocated by the callee because the caller does
+ not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE
+ is defined in a way that allows for future extensibility and can be of variable
+ length. This memory pool should be deallocated by the caller when it is no
+ longer necessary.
+
+ The IDE controller driver for a Serial ATA (SATA) controller can use this
+ member function to force a lower speed (first-generation [Gen1] speeds on a
+ second-generation [Gen2]-capable hardware). The IDE controller driver can
+ also allow the driver entity to stay with the speed that has been negotiated
+ by the physical layer.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel A zero-based channel number.
+ @param[in] Device A zero-based device number on the Channel.
+ @param[out] SupportedModes The optimum modes for the device.
+
+ @retval EFI_SUCCESS SupportedModes was returned.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_INVALID_PARAMETER SupportedModes is NULL.
+ @retval EFI_NOT_READY Modes cannot be calculated due to a lack of
+ data. This error may happen if
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData()
+ were not called for at least one drive in the
+ same enumeration group.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitCalculateMode (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes
+ )
+{
+ EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_IDENTIFY_DATA *IdentifyData;
+ BOOLEAN IdentifyValid;
+ EFI_ATA_COLLECTIVE_MODE *DisqualifiedModes;
+ UINT16 SelectedMode;
+ EFI_STATUS Status;
+ UINTN DeviceIndex;
+
+ Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ if ((Channel >= This->ChannelCount) || (SupportedModes == NULL) || (Device >= Private->DeviceCount)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *SupportedModes = AllocateZeroPool (sizeof (EFI_ATA_COLLECTIVE_MODE));
+ if (*SupportedModes == NULL) {
+ ASSERT (*SupportedModes != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DeviceIndex = FlatDeviceIndex (Private, Channel, Device);
+
+ IdentifyData = &(Private->IdentifyData[DeviceIndex]);
+ IdentifyValid = Private->IdentifyValid[DeviceIndex];
+ DisqualifiedModes = &(Private->DisqualifiedModes[DeviceIndex]);
+
+ //
+ // Make sure we've got the valid identify data of the device from SubmitData()
+ //
+ if (!IdentifyValid) {
+ FreePool (*SupportedModes);
+ return EFI_NOT_READY;
+ }
+
+ Status = CalculateBestPioMode (
+ IdentifyData,
+ (DisqualifiedModes->PioMode.Valid ? ((UINT16 *) &(DisqualifiedModes->PioMode.Mode)) : NULL),
+ &SelectedMode
+ );
+ if (!EFI_ERROR (Status)) {
+ (*SupportedModes)->PioMode.Valid = TRUE;
+ (*SupportedModes)->PioMode.Mode = SelectedMode;
+
+ } else {
+ (*SupportedModes)->PioMode.Valid = FALSE;
+ }
+ DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: PioMode = %x\n", (*SupportedModes)->PioMode.Mode));
+
+ Status = CalculateBestUdmaMode (
+ IdentifyData,
+ (DisqualifiedModes->UdmaMode.Valid ? ((UINT16 *) &(DisqualifiedModes->UdmaMode.Mode)) : NULL),
+ &SelectedMode
+ );
+
+ if (!EFI_ERROR (Status)) {
+ (*SupportedModes)->UdmaMode.Valid = TRUE;
+ (*SupportedModes)->UdmaMode.Mode = SelectedMode;
+
+ } else {
+ (*SupportedModes)->UdmaMode.Valid = FALSE;
+ }
+ DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: UdmaMode = %x\n", (*SupportedModes)->UdmaMode.Mode));
+
+ //
+ // The modes other than PIO and UDMA are not supported
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Commands the IDE controller driver to program the IDE controller hardware
+ so that the specified device can operate at the specified mode.
+
+ This function is used by the driver entity to instruct the IDE controller
+ driver to program the IDE controller hardware to the specified modes. This
+ function can be called only once for a particular device. For a Serial ATA
+ (SATA) Advanced Host Controller Interface (AHCI) controller, no controller-
+ specific programming may be required.
+
+ @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[in] Device Zero-based device number on the Channel.
+ @param[in] Modes The modes to set.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data.
+ @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure.
+ The driver entity should not use this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitSetTiming (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_COLLECTIVE_MODE *Modes
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.h b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.h
new file mode 100644
index 000000000..7af3ad855
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.h
@@ -0,0 +1,543 @@
+/** @file
+ Header file for Sata Controller driver.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, ARM Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SATA_CONTROLLER_H_
+#define _SATA_CONTROLLER_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/IdeControllerInit.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+//
+// Global Variables definitions
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSataControllerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gSataControllerComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSataControllerComponentName2;
+
+#define AHCI_BAR_INDEX 0x05
+#define R_AHCI_CAP 0x0
+#define B_AHCI_CAP_NPS (BIT4 | BIT3 | BIT2 | BIT1 | BIT0) // Number of Ports
+#define B_AHCI_CAP_SPM BIT17 // Supports Port Multiplier
+#define R_AHCI_PI 0xC
+
+///
+/// AHCI each channel can have up to 1 device
+///
+#define AHCI_MAX_DEVICES 0x01
+
+///
+/// AHCI each channel can have 15 devices in the presence of a multiplier
+///
+#define AHCI_MULTI_MAX_DEVICES 0x0F
+
+///
+/// IDE supports 2 channel max
+///
+#define IDE_MAX_CHANNEL 0x02
+
+///
+/// IDE supports 2 devices max
+///
+#define IDE_MAX_DEVICES 0x02
+
+#define SATA_ENUMER_ALL FALSE
+
+//
+// Sata Controller driver private data structure
+//
+#define SATA_CONTROLLER_SIGNATURE SIGNATURE_32('S','A','T','A')
+
+typedef struct _EFI_SATA_CONTROLLER_PRIVATE_DATA {
+ //
+ // Standard signature used to identify Sata Controller private data
+ //
+ UINT32 Signature;
+
+ //
+ // Protocol instance of IDE_CONTROLLER_INIT produced by this driver
+ //
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL IdeInit;
+
+ //
+ // Copy of protocol pointers used by this driver
+ //
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // The number of devices that are supported by this channel
+ //
+ UINT8 DeviceCount;
+
+ //
+ // The highest disqulified mode for each attached device,
+ // From ATA/ATAPI spec, if a mode is not supported,
+ // the modes higher than it is also not supported
+ //
+ EFI_ATA_COLLECTIVE_MODE *DisqualifiedModes;
+
+ //
+ // A copy of EFI_IDENTIFY_DATA data for each attached SATA device and its flag
+ //
+ EFI_IDENTIFY_DATA *IdentifyData;
+ BOOLEAN *IdentifyValid;
+
+ //
+ // Track the state so that the PCI attributes that were modified
+ // can be restored to the original value later.
+ //
+ BOOLEAN PciAttributesChanged;
+
+ //
+ // Copy of the original PCI Attributes
+ //
+ UINT64 OriginalPciAttributes;
+} EFI_SATA_CONTROLLER_PRIVATE_DATA;
+
+#define SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_SATA_CONTROLLER_PRIVATE_DATA, IdeInit, SATA_CONTROLLER_SIGNATURE)
+
+//
+// Driver binding functions declaration
+//
+/**
+ Supported function of Driver Binding protocol for this driver.
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath A pointer to the device path. Should be ignored by
+ device driver.
+
+ @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
+SataControllerSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ This routine is called right after the .Supported() called and
+ Start this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath A pointer to the device path. Should be ignored by
+ device driver.
+
+ @retval EFI_SUCCESS This driver is added to this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other Some error occurs when binding this driver to this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SataControllerStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller 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 from this device.
+ @retval other Some error occurs when removing this driver from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SataControllerStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// IDE controller init functions declaration
+//
+/**
+ Returns the information about the specified IDE channel.
+
+ This function can be used to obtain information about a particular IDE channel.
+ The driver entity uses this information during the enumeration process.
+
+ If Enabled is set to FALSE, the driver entity will not scan the channel. Note
+ that it will not prevent an operating system driver from scanning the channel.
+
+ For most of today's controllers, MaxDevices will either be 1 or 2. For SATA
+ controllers, this value will always be 1. SATA configurations can contain SATA
+ port multipliers. SATA port multipliers behave like SATA bridges and can support
+ up to 16 devices on the other side. If a SATA port out of the IDE controller
+ is connected to a port multiplier, MaxDevices will be set to the number of SATA
+ devices that the port multiplier supports. Because today's port multipliers
+ support up to fifteen SATA devices, this number can be as large as fifteen. The IDE
+ bus driver is required to scan for the presence of port multipliers behind an SATA
+ controller and enumerate up to MaxDevices number of devices behind the port
+ multiplier.
+
+ In this context, the devices behind a port multiplier constitute a channel.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[out] Enabled TRUE if this channel is enabled. Disabled channels
+ are not scanned to see if any devices are present.
+ @param[out] MaxDevices The maximum number of IDE devices that the bus driver
+ can expect on this channel. For the ATA/ATAPI
+ specification, version 6, this number will either be
+ one or two. For Serial ATA (SATA) configurations with a
+ port multiplier, this number can be as large as fifteen.
+
+
+ @retval EFI_SUCCESS Information was returned without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitGetChannelInfo (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ OUT BOOLEAN *Enabled,
+ OUT UINT8 *MaxDevices
+ );
+
+/**
+ The notifications from the driver entity that it is about to enter a certain
+ phase of the IDE channel enumeration process.
+
+ This function can be used to notify the IDE controller driver to perform
+ specific actions, including any chipset-specific initialization, so that the
+ chipset is ready to enter the next phase. Seven notification points are defined
+ at this time.
+
+ More synchronization points may be added as required in the future.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL
+ instance.
+ @param[in] Phase The phase during enumeration.
+ @param[in] Channel Zero-based channel number.
+
+ @retval EFI_SUCCESS The notification was accepted without any errors.
+ @retval EFI_UNSUPPORTED Phase is not supported.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_NOT_READY This phase cannot be entered at this time; for
+ example, an attempt was made to enter a Phase
+ without having entered one or more previous
+ Phase.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitNotifyPhase (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase,
+ IN UINT8 Channel
+ );
+
+/**
+ Submits the device information to the IDE controller driver.
+
+ This function is used by the driver entity to pass detailed information about
+ a particular device to the IDE controller driver. The driver entity obtains
+ this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData
+ is the pointer to the response data buffer. The IdentifyData buffer is owned
+ by the driver entity, and the IDE controller driver must make a local copy
+ of the entire buffer or parts of the buffer as needed. The original IdentifyData
+ buffer pointer may not be valid when
+
+ - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or
+ - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point.
+
+ The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to
+ compute the optimum mode for the device. These fields are not limited to the
+ timing information. For example, an implementation of the IDE controller driver
+ may examine the vendor and type/mode field to match known bad drives.
+
+ The driver entity may submit drive information in any order, as long as it
+ submits information for all the devices belonging to the enumeration group
+ before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device
+ in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ should be called with IdentifyData set to NULL. The IDE controller driver may
+ not have any other mechanism to know whether a device is present or not. Therefore,
+ setting IdentifyData to NULL does not constitute an error condition.
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a
+ given (Channel, Device) pair.
+
+ @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[in] Device Zero-based device number on the Channel.
+ @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command.
+
+ @retval EFI_SUCCESS The information was accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitSubmitData (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_IDENTIFY_DATA *IdentifyData
+ );
+
+/**
+ Disqualifies specific modes for an IDE device.
+
+ This function allows the driver entity or other drivers (such as platform
+ drivers) to reject certain timing modes and request the IDE controller driver
+ to recalculate modes. This function allows the driver entity and the IDE
+ controller driver to negotiate the timings on a per-device basis. This function
+ is useful in the case of drives that lie about their capabilities. An example
+ is when the IDE device fails to accept the timing modes that are calculated
+ by the IDE controller driver based on the response to the Identify Drive command.
+
+ If the driver entity does not want to limit the ATA timing modes and leave that
+ decision to the IDE controller driver, it can either not call this function for
+ the given device or call this function and set the Valid flag to FALSE for all
+ modes that are listed in EFI_ATA_COLLECTIVE_MODE.
+
+ The driver entity may disqualify modes for a device in any order and any number
+ of times.
+
+ This function can be called multiple times to invalidate multiple modes of the
+ same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI
+ specification for more information on PIO modes.
+
+ For Serial ATA (SATA) controllers, this member function can be used to disqualify
+ a higher transfer rate mode on a given channel. For example, a platform driver
+ may inform the IDE controller driver to not use second-generation (Gen2) speeds
+ for a certain SATA drive.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel The zero-based channel number.
+ @param[in] Device The zero-based device number on the Channel.
+ @param[in] BadModes The modes that the device does not support and that
+ should be disqualified.
+
+ @retval EFI_SUCCESS The modes were accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_INVALID_PARAMETER IdentifyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitDisqualifyMode (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_COLLECTIVE_MODE *BadModes
+ );
+
+/**
+ Returns the information about the optimum modes for the specified IDE device.
+
+ This function is used by the driver entity to obtain the optimum ATA modes for
+ a specific device. The IDE controller driver takes into account the following
+ while calculating the mode:
+ - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode()
+
+ The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ for all the devices that belong to an enumeration group before calling
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group.
+
+ The IDE controller driver will use controller- and possibly platform-specific
+ algorithms to arrive at SupportedModes. The IDE controller may base its
+ decision on user preferences and other considerations as well. This function
+ may be called multiple times because the driver entity may renegotiate the mode
+ with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode().
+
+ The driver entity may collect timing information for various devices in any
+ order. The driver entity is responsible for making sure that all the dependencies
+ are satisfied. For example, the SupportedModes information for device A that
+ was previously returned may become stale after a call to
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B.
+
+ The buffer SupportedModes is allocated by the callee because the caller does
+ not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE
+ is defined in a way that allows for future extensibility and can be of variable
+ length. This memory pool should be deallocated by the caller when it is no
+ longer necessary.
+
+ The IDE controller driver for a Serial ATA (SATA) controller can use this
+ member function to force a lower speed (first-generation [Gen1] speeds on a
+ second-generation [Gen2]-capable hardware). The IDE controller driver can
+ also allow the driver entity to stay with the speed that has been negotiated
+ by the physical layer.
+
+ @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel A zero-based channel number.
+ @param[in] Device A zero-based device number on the Channel.
+ @param[out] SupportedModes The optimum modes for the device.
+
+ @retval EFI_SUCCESS SupportedModes was returned.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_INVALID_PARAMETER SupportedModes is NULL.
+ @retval EFI_NOT_READY Modes cannot be calculated due to a lack of
+ data. This error may happen if
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()
+ and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData()
+ were not called for at least one drive in the
+ same enumeration group.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitCalculateMode (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes
+ );
+
+/**
+ Commands the IDE controller driver to program the IDE controller hardware
+ so that the specified device can operate at the specified mode.
+
+ This function is used by the driver entity to instruct the IDE controller
+ driver to program the IDE controller hardware to the specified modes. This
+ function can be called only once for a particular device. For a Serial ATA
+ (SATA) Advanced Host Controller Interface (AHCI) controller, no controller-
+ specific programming may be required.
+
+ @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.
+ @param[in] Channel Zero-based channel number.
+ @param[in] Device Zero-based device number on the Channel.
+ @param[in] Modes The modes to set.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).
+ @retval EFI_INVALID_PARAMETER Device is invalid.
+ @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data.
+ @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure.
+ The driver entity should not use this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IdeInitSetTiming (
+ IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN EFI_ATA_COLLECTIVE_MODE *Modes
+ );
+
+//
+// Forward reference declaration
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the UEFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ @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
+SataControllerComponentNameGetDriverName (
+ 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 an UEFI Driver.
+
+ @param This A pointer to the 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 OPTIONAL 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 three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ @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 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 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
+SataControllerComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
new file mode 100644
index 000000000..488920a68
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
@@ -0,0 +1,51 @@
+## @file
+# SataController driver to manage SATA compliance IDE/AHCI host controllers.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SataController
+ MODULE_UNI_FILE = SataControllerDxe.uni
+ FILE_GUID = 820C59BB-274C-43B2-83EA-DAC673035A59
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSataControllerDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gSataControllerDriverBinding
+# COMPONENT_NAME = gSataControllerComponentName
+# COMPONENT_NAME2 = gSataControllerComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ SataController.c
+ SataController.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiIdeControllerInitProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SataControllerDxeExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.uni
new file mode 100644
index 000000000..2aaaab721
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The SataControllerDxe driver is responsible for managing the standard SATA controller.
+//
+// It consumes PciIo protocol and produces IdeControllerInit protocol for upper layer use.
+//
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the standard SATA controller"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Implements the IdeControllerInit protocol interface for upper layer use\n"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxeExtra.uni
new file mode 100644
index 000000000..047b3e7a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SataControllerDxe Localized Strings and Content
+//
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SATA Controller DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c
new file mode 100644
index 000000000..85a5ce841
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c
@@ -0,0 +1,205 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SD/MMC host controller driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {
+ SdMmcPciHcComponentNameGetDriverName,
+ SdMmcPciHcComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {
+ { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {
+ { "eng;en", L"Edkii Sd/Mmc Host 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
+SdMmcPciHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
+
+/**
+ 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 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 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
+SdMmcPciHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ 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;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSdMmcPciHcDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
new file mode 100644
index 000000000..8b5f8e8ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
@@ -0,0 +1,1363 @@
+/** @file
+ This file provides some helper functions which are specific for EMMC device.
+
+ Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+/**
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
+ make it go to Idle State.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The EMMC device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+EmmcReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+ SdMmcCmdBlk.ResponseType = 0;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ gBS->Stall (1000);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.
+ On output, the argument is the value of OCR register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetOcr (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN OUT UINT32 *Argument
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+ SdMmcCmdBlk.CommandArgument = *Argument;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Argument = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the
+ data of their CID registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetAllCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
+ Address (RCA).
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of this
+ buffer as the content of this byte is meaningless even
+ if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0x00000000;
+
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH to the EMMC device to switch the mode of operation of the
+ selected Device or modifies the EXT_CSD registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Access The access mode of SWTICH command.
+ @param[in] Index The offset of the field to be access.
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 Access,
+ IN UINT8 Index,
+ IN UINT8 Value,
+ IN UINT8 CmdSet
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed EMMC device to get its status register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[128];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ if (BusWidth == 8) {
+ Packet.InTransferLength = sizeof (TuningBlock);
+ } else {
+ Packet.InTransferLength = 64;
+ }
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the clock to get HS200 optimal sampling point.
+
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcTuningClkForHs200 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Check the SWITCH operation status.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number on which command should be sent.
+ @param[in] Rca The relative device address.
+
+ @retval EFI_SUCCESS The SWITCH finished siccessfully.
+ @retval others The SWITCH failed.
+**/
+EFI_STATUS
+EmmcCheckSwitchStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: Send status fails with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
+ Simplified Spec 3.0 Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
+ use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+ if (BusWidth == 4) {
+ Value = 1;
+ } else if (BusWidth == 8) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsDdr) {
+ Value += 4;
+ }
+
+ CmdSet = 0;
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));
+ return Status;
+ }
+
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the bus timing and clock frequency.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller
+ Simplified Spec 3.0 Figure 3-3 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] DriverStrength Driver strength to set for speed modes that support it.
+ @param[in] BusTiming The bus mode timing indicator.
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchBusTiming (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ UINT8 HostCtrl1;
+ BOOLEAN DelaySendStatus;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
+ CmdSet = 0;
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ Value = (UINT8)((DriverStrength.Emmc << 4) | 3);
+ break;
+ case SdMmcMmcHs200:
+ Value = (UINT8)((DriverStrength.Emmc << 4) | 2);
+ break;
+ case SdMmcMmcHsSdr:
+ case SdMmcMmcHsDdr:
+ Value = 1;
+ break;
+ case SdMmcMmcLegacy:
+ Value = 0;
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d)\n", BusTiming));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to bus timing %d fails with %r\n", BusTiming, Status));
+ return Status;
+ }
+
+ if (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcHsDdr) {
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ HostCtrl1 = (UINT8)~BIT2;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // For cases when we switch bus timing to higher mode from current we want to
+ // send SEND_STATUS at current, lower, frequency then the target frequency to avoid
+ // stability issues. It has been observed that some designs are unable to process the
+ // SEND_STATUS at higher frequency during switch to HS200 @200MHz irrespective of the number of retries
+ // and only running the clock tuning is able to make them work at target frequency.
+ //
+ // For cases when we are downgrading the frequency and current high frequency is invalid
+ // we have to first change the frequency to target frequency and then send the SEND_STATUS.
+ //
+ if (Private->Slot[Slot].CurrentFreq < (ClockFreq * 1000)) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DelaySendStatus = FALSE;
+ } else {
+ DelaySendStatus = TRUE;
+ }
+
+ //
+ // Convert the clock freq unit from MHz to KHz.
+ //
+ Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DelaySendStatus) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Switch to the High Speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHighSpeed (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsDdr;
+
+ if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr && BusMode->BusTiming != SdMmcMmcLegacy) ||
+ BusMode->ClockFreq > 52) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BusMode->BusTiming == SdMmcMmcHsDdr) {
+ IsDdr = TRUE;
+ } else {
+ IsDdr = FALSE;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+}
+
+/**
+ Switch to the HS200 timing. This function assumes that eMMC bus is still in legacy mode.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS200 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+
+ if (BusMode->BusTiming != SdMmcMmcHs200 ||
+ (BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode->BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch to the HS400 timing. This function assumes that eMMC bus is still in legacy mode.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS400 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_BUS_SETTINGS Hs200BusMode;
+ UINT32 HsFreq;
+
+ if (BusMode->BusTiming != SdMmcMmcHs400 ||
+ BusMode->BusWidth != 8) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hs200BusMode.BusTiming = SdMmcMmcHs200;
+ Hs200BusMode.BusWidth = BusMode->BusWidth;
+ Hs200BusMode.ClockFreq = BusMode->ClockFreq;
+ Hs200BusMode.DriverStrength = BusMode->DriverStrength;
+
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &Hs200BusMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set to High Speed timing and set the clock frequency to a value less than or equal to 52MHz.
+ // This step is necessary to be able to switch Bus into 8 bit DDR mode which is unsupported in HS200.
+ //
+ HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;
+ Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+}
+
+/**
+ Check if passed BusTiming is supported in both controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to the card's extended CSD
+ @param[in] BusTiming Bus timing to check
+
+ @retval TRUE Both card and controller support given BusTiming
+ @retval FALSE Card or controller doesn't support given BusTiming
+**/
+BOOLEAN
+EmmcIsBusTimingSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ BOOLEAN Supported;
+ SD_MMC_HC_SLOT_CAP *Capabilities;
+
+ Capabilities = &Private->Capability[SlotIndex];
+
+ Supported = FALSE;
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ if ((((ExtCsd->DeviceType & (BIT6 | BIT7)) != 0) && (Capabilities->Hs400 != 0)) && Capabilities->BusWidth8 != 0) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHs200:
+ if ((((ExtCsd->DeviceType & (BIT4 | BIT5)) != 0) && (Capabilities->Sdr104 != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHsDdr:
+ if ((((ExtCsd->DeviceType & (BIT2 | BIT3)) != 0) && (Capabilities->Ddr50 != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHsSdr:
+ if ((((ExtCsd->DeviceType & BIT1) != 0) && (Capabilities->HighSpeed != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcLegacy:
+ if ((ExtCsd->DeviceType & BIT0) != 0) {
+ Supported = TRUE;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return Supported;
+}
+
+/**
+ Get the target bus timing to set on the link. This function
+ will try to select highest bus timing supported by card, controller
+ and the driver.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to the card's extended CSD
+
+ @return Bus timing value that should be set on link
+**/
+SD_MMC_BUS_MODE
+EmmcGetTargetBusTiming (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd
+ )
+{
+ SD_MMC_BUS_MODE BusTiming;
+
+ //
+ // We start with highest bus timing that this driver currently supports and
+ // return as soon as we find supported timing.
+ //
+ BusTiming = SdMmcMmcHs400;
+ while (BusTiming > SdMmcMmcLegacy) {
+ if (EmmcIsBusTimingSupported (Private, SlotIndex, ExtCsd, BusTiming)) {
+ break;
+ }
+ BusTiming--;
+ }
+
+ return BusTiming;
+}
+
+/**
+ Check if the passed bus width is supported by controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing set on the link
+ @param[in] BusWidth Bus width to check
+
+ @retval TRUE Passed bus width is supported in current bus configuration
+ @retval FALSE Passed bus width is not supported in current bus configuration
+**/
+BOOLEAN
+EmmcIsBusWidthSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT16 BusWidth
+ )
+{
+ if (BusWidth == 8 && Private->Capability[SlotIndex].BusWidth8 != 0) {
+ return TRUE;
+ } else if (BusWidth == 4 && BusTiming != SdMmcMmcHs400) {
+ return TRUE;
+ } else if (BusWidth == 1 && (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcLegacy)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the target bus width to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Bus width to be set on the bus
+**/
+UINT8
+EmmcGetTargetBusWidth (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT8 BusWidth;
+ UINT8 PreferredBusWidth;
+
+ PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;
+
+ if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
+ EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, PreferredBusWidth)) {
+ BusWidth = PreferredBusWidth;
+ } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 8)) {
+ BusWidth = 8;
+ } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 4)) {
+ BusWidth = 4;
+ } else {
+ BusWidth = 1;
+ }
+
+ return BusWidth;
+}
+
+/**
+ Get the target clock frequency to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing to be set on the bus
+
+ @return Value of the clock frequency to be set on bus in MHz
+**/
+UINT32
+EmmcGetTargetClockFreq (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT32 PreferredClockFreq;
+ UINT32 MaxClockFreq;
+
+ PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;
+
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ case SdMmcMmcHs200:
+ MaxClockFreq = 200;
+ break;
+ case SdMmcMmcHsSdr:
+ case SdMmcMmcHsDdr:
+ MaxClockFreq = 52;
+ break;
+ default:
+ MaxClockFreq = 26;
+ break;
+ }
+
+ if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {
+ return PreferredClockFreq;
+ } else {
+ return MaxClockFreq;
+ }
+}
+
+/**
+ Get the driver strength to be set on bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Value of the driver strength to be set on the bus
+**/
+EDKII_SD_MMC_DRIVER_STRENGTH
+EmmcGetTargetDriverStrength (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+
+ PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;
+ DriverStrength.Emmc = EmmcDriverStrengthType0;
+
+ if (PreferredDriverStrength.Emmc != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
+ (ExtCsd->DriverStrength & (BIT0 << PreferredDriverStrength.Emmc))) {
+ DriverStrength.Emmc = PreferredDriverStrength.Emmc;
+ }
+
+ return DriverStrength;
+}
+
+/**
+ Get the target settings for the bus mode.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[out] BusMode Target configuration of the bus
+**/
+VOID
+EmmcGetTargetBusMode (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ OUT SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ BusMode->BusTiming = EmmcGetTargetBusTiming (Private, SlotIndex, ExtCsd);
+ BusMode->BusWidth = EmmcGetTargetBusWidth (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+ BusMode->ClockFreq = EmmcGetTargetClockFreq (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+ BusMode->DriverStrength = EmmcGetTargetDriverStrength (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetBusMode (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EMMC_CSD Csd;
+ EMMC_EXT_CSD ExtCsd;
+ SD_MMC_BUS_SETTINGS BusMode;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
+ return Status;
+ }
+
+ ASSERT (Private->BaseClkFreq[Slot] != 0);
+
+ //
+ // Get Device_Type from EXT_CSD register.
+ //
+ Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ EmmcGetTargetBusMode (Private, Slot, &ExtCsd, &BusMode);
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Target bus mode: timing = %d, width = %d, clock freq = %d, driver strength = %d\n",
+ BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Emmc));
+
+ if (BusMode.BusTiming == SdMmcMmcHs400) {
+ Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);
+ } else if (BusMode.BusTiming == SdMmcMmcHs200) {
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);
+ } else {
+ //
+ // Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy
+ // bus timing. This is because even though we might not want to
+ // change the timing itself we still want to allow customization of
+ // bus parameters such as clock frequency and bus width.
+ //
+ Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);
+ }
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (BusMode.BusTiming == SdMmcMmcHs400) ? "HS400" : ((BusMode.BusTiming == SdMmcMmcHs200) ? "HS200" : "HighSpeed"), Status));
+
+ return Status;
+}
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ UINTN Retry;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+
+ Status = EmmcReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = EmmcGetOcr (PassThru, Slot, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));
+ return Status;
+ }
+ Ocr |= BIT30;
+
+ if (Retry++ == 100) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ Status = EmmcGetAllCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Slot starts from 0 and valid RCA starts from 1.
+ // Here we takes a simple formula to calculate the RCA.
+ // Don't support multiple devices on the slot, that is
+ // shared bus slot feature.
+ //
+ Rca = Slot + 1;
+ Status = EmmcSetRca (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));
+ Private->Slot[Slot].CardType = EmmcCardType;
+
+ Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
new file mode 100644
index 000000000..b630daab7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
@@ -0,0 +1,1376 @@
+/** @file
+ This file provides some helper functions which are specific for SD card device.
+
+ Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+/**
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The SD device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+SdCardReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface
+ condition.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] SupplyVoltage The supplied voltage by the host.
+ @param[in] CheckPattern The check pattern to be sent to the device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageCheck (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 SupplyVoltage,
+ IN UINT8 CheckPattern
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
+ SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ if (!EFI_ERROR (Status)) {
+ if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdioSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
+
+ Switch = S18R ? BIT24 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+ @param[in] Xpc The boolean to show if it should provide 0.36w power control.
+ @param[in] Hcs The boolean to show if it support host capacity info.
+ @param[out] Ocr The buffer to store returned OCR register value.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R,
+ IN BOOLEAN Xpc,
+ IN BOOLEAN Hcs,
+ OUT UINT32 *Ocr
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+ UINT32 MaxPower;
+ UINT32 HostCapacity;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+
+ Switch = S18R ? BIT24 : 0;
+ MaxPower = Xpc ? BIT28 : 0;
+ HostCapacity = Hcs ? BIT30 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Ocr = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the
+ data of their CID registers.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardAllSendCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
+ Address (RCA).
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Rca The relative device address to assign.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ OUT UINT16 *Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ if (Rca != 0) {
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ }
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusWidth (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (BusWidth == 1) {
+ Value = 0;
+ } else if (BusWidth == 4) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdMmcCmdBlk.CommandArgument = Value & 0x3;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming Target bus timing based on which access group value will be set.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriverStrength The value for driver strength group.
+ @param[in] PowerLimit The value for power limit group.
+ @param[in] Mode Switch or check function.
+ @param[out] SwitchResp The return switch function status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT8 CommandSystem,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength,
+ IN UINT8 PowerLimit,
+ IN BOOLEAN Mode,
+ OUT UINT8 *SwitchResp
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 ModeValue;
+ UINT8 AccessMode;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ ModeValue = Mode ? BIT31 : 0;
+
+ switch (BusTiming) {
+ case SdMmcUhsDdr50:
+ AccessMode = 0x4;
+ break;
+ case SdMmcUhsSdr104:
+ AccessMode = 0x3;
+ break;
+ case SdMmcUhsSdr50:
+ AccessMode = 0x2;
+ break;
+ case SdMmcUhsSdr25:
+ case SdMmcSdHs:
+ AccessMode = 0x1;
+ break;
+ case SdMmcUhsSdr12:
+ case SdMmcSdDs:
+ AccessMode = 0;
+ break;
+ default:
+ AccessMode = 0xF;
+ }
+
+ SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((CommandSystem & 0xF) << 4) | \
+ ((DriverStrength & 0xF) << 8) | ((PowerLimit & 0xF) << 12) | \
+ ModeValue;
+
+ Packet.InDataBuffer = SwitchResp;
+ Packet.InTransferLength = 64;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Mode) {
+ if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode)) ||
+ (((CommandSystem & 0xF) != 0xF) && (((SwitchResp[16] >> 4) & 0xF) != CommandSystem)) ||
+ (((DriverStrength & 0xF) != 0xF) && ((SwitchResp[15] & 0xF) != DriverStrength)) ||
+ (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != PowerLimit))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed SD device to get its status register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[64];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ Packet.InTransferLength = sizeof (TuningBlock);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the sampling point of SDR104 or SDR50 bus speed mode.
+
+ Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardTuningClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = SdCardSendTuningBlk (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitchBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));
+ return Status;
+ }
+
+ Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus >> 16) != 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Check if passed BusTiming is supported in both controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I
+
+ @retval TRUE Both card and controller support given BusTiming
+ @retval FALSE Card or controller doesn't support given BusTiming
+**/
+BOOLEAN
+SdIsBusTimingSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedBusTimings,
+ IN BOOLEAN IsInUhsI,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ SD_MMC_HC_SLOT_CAP *Capability;
+
+ Capability = &Private->Capability[SlotIndex];
+
+ if (IsInUhsI) {
+ switch (BusTiming) {
+ case SdMmcUhsSdr104:
+ if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsDdr50:
+ if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr50:
+ if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr25:
+ if ((CardSupportedBusTimings & BIT1) != 0) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr12:
+ if ((CardSupportedBusTimings & BIT0) != 0) {
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (BusTiming) {
+ case SdMmcSdHs:
+ if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings & BIT1) != 0) {
+ return TRUE;
+ }
+ break;
+ case SdMmcSdDs:
+ if ((CardSupportedBusTimings & BIT0) != 0) {
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the target bus timing to set on the link. This function
+ will try to select highest bus timing supported by card, controller
+ and the driver.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I
+
+ @return Bus timing value that should be set on link
+**/
+SD_MMC_BUS_MODE
+SdGetTargetBusTiming (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedBusTimings,
+ IN BOOLEAN IsInUhsI
+ )
+{
+ SD_MMC_BUS_MODE BusTiming;
+
+ if (IsInUhsI) {
+ BusTiming = SdMmcUhsSdr104;
+ } else {
+ BusTiming = SdMmcSdHs;
+ }
+
+ while (BusTiming > SdMmcSdDs) {
+ if (SdIsBusTimingSupported (Private, SlotIndex, CardSupportedBusTimings, IsInUhsI, BusTiming)) {
+ break;
+ }
+ BusTiming--;
+ }
+
+ return BusTiming;
+}
+
+/**
+ Get the target bus width to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Bus width to be set on the bus
+**/
+UINT8
+SdGetTargetBusWidth (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT8 BusWidth;
+ UINT8 PreferredBusWidth;
+
+ PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;
+
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
+ if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
+ (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {
+ BusWidth = PreferredBusWidth;
+ } else {
+ BusWidth = 4;
+ }
+ } else {
+ //
+ // UHS-I modes support only 4-bit width.
+ // Switch to 4-bit has been done before calling this function anyway so
+ // this is purely informational.
+ //
+ BusWidth = 4;
+ }
+
+ return BusWidth;
+}
+
+/**
+ Get the target clock frequency to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing to be set on the bus
+
+ @return Value of the clock frequency to be set on bus in MHz
+**/
+UINT32
+SdGetTargetBusClockFreq (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT32 PreferredClockFreq;
+ UINT32 MaxClockFreq;
+
+ PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;
+
+ switch (BusTiming) {
+ case SdMmcUhsSdr104:
+ MaxClockFreq = 208;
+ break;
+ case SdMmcUhsSdr50:
+ MaxClockFreq = 100;
+ break;
+ case SdMmcUhsDdr50:
+ case SdMmcUhsSdr25:
+ case SdMmcSdHs:
+ MaxClockFreq = 50;
+ break;
+ case SdMmcUhsSdr12:
+ case SdMmcSdDs:
+ default:
+ MaxClockFreq = 25;
+ }
+
+ if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {
+ return PreferredClockFreq;
+ } else {
+ return MaxClockFreq;
+ }
+}
+
+/**
+ Get the driver strength to be set on bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedDriverStrengths Bitmask indicating which driver strengths are supported on the card
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Value of the driver strength to be set on the bus
+**/
+EDKII_SD_MMC_DRIVER_STRENGTH
+SdGetTargetDriverStrength (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedDriverStrengths,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
+ DriverStrength.Sd = SdDriverStrengthIgnore;
+ return DriverStrength;
+ }
+
+ PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;
+ DriverStrength.Sd = SdDriverStrengthTypeB;
+
+ if (PreferredDriverStrength.Sd != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
+ (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd))) {
+
+ if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&
+ (Private->Capability[SlotIndex].DriverTypeA != 0)) ||
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&
+ (Private->Capability[SlotIndex].DriverTypeC != 0)) ||
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&
+ (Private->Capability[SlotIndex].DriverTypeD != 0))) {
+ DriverStrength.Sd = PreferredDriverStrength.Sd;
+ }
+ }
+
+ return DriverStrength;
+}
+
+/**
+ Get the target settings for the bus mode.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] SwitchQueryResp Pointer to switch query response
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I mode
+ @param[out] BusMode Target configuration of the bus
+**/
+VOID
+SdGetTargetBusMode (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 *SwitchQueryResp,
+ IN BOOLEAN IsInUhsI,
+ OUT SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex, SwitchQueryResp[13], IsInUhsI);
+ BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex, BusMode->BusTiming);
+ BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex, BusMode->BusTiming);
+ BusMode->DriverStrength = SdGetTargetDriverStrength (Private, SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] S18A The boolean to show if it's a UHS-I SD card.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusMode (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN S18A
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_CAP *Capability;
+ UINT8 HostCtrl1;
+ UINT8 SwitchResp[64];
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_MMC_BUS_SETTINGS BusMode;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Capability = &Private->Capability[Slot];
+
+ Status = SdCardSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (S18A) {
+ //
+ // For UHS-I speed modes 4-bit data bus is requiered so we
+ // switch here irrespective of platform preference.
+ //
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, 4);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Get the supported bus speed from SWITCH cmd return data group #1.
+ //
+ Status = SdCardSwitch (PassThru, Slot, 0xFF, 0xF, SdDriverStrengthIgnore, 0xF, FALSE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdGetTargetBusMode (Private, Slot, SwitchResp, S18A, &BusMode);
+
+ DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Target bus mode: bus timing = %d, bus width = %d, clock freq[MHz] = %d, driver strength = %d\n",
+ BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Sd));
+
+ if (!S18A) {
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusMode.BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdCardSwitch (PassThru, Slot, BusMode.BusTiming, 0xF, BusMode.DriverStrength.Sd, 0xF, TRUE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcSetDriverStrength (Private->PciIo, Slot, BusMode.DriverStrength.Sd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set to High Speed timing
+ //
+ if (BusMode.BusTiming == SdMmcSdHs) {
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode.BusTiming);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcClockSupply (Private, Slot, BusMode.BusTiming, FALSE, BusMode.ClockFreq * 1000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) {
+ Status = SdCardTuningClock (PciIo, PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Execute SD device identification procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a SD card.
+ @retval Others There is not a SD card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ BOOLEAN Xpc;
+ BOOLEAN S18r;
+ UINT64 MaxCurrent;
+ UINT16 ControllerVer;
+ UINT8 PowerCtrl;
+ UINT32 PresentState;
+ UINT8 HostCtrl2;
+ UINTN Retry;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+ //
+ // 1. Send Cmd0 to the device
+ //
+ Status = SdCardReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 2. Send Cmd8 to the device
+ //
+ Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
+ //
+ Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 4. Send Acmd41 with voltage window 0 to the device
+ //
+ Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Private->Capability[Slot].Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MaxCurrent >= 150) {
+ Xpc = TRUE;
+ } else {
+ Xpc = FALSE;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((ControllerVer & 0xFF) >= SD_MMC_HC_CTRL_VER_300) &&
+ ((ControllerVer & 0xFF) <= SD_MMC_HC_CTRL_VER_420)) {
+ S18r = TRUE;
+ } else if (((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_100) || ((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_200)) {
+ S18r = FALSE;
+ } else {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 5. Repeatly send Acmd41 with supply voltage window to the device.
+ // Note here we only support the cards complied with SD physical
+ // layer simplified spec version 2.0 and version 3.0 and above.
+ //
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Retry++ == 100) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ //
+ // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the
+ // Capabilities register), switch its voltage to 1.8V.
+ //
+ if ((Private->Capability[Slot].Sdr50 != 0 ||
+ Private->Capability[Slot].Sdr104 != 0 ||
+ Private->Capability[Slot].Ddr50 != 0) &&
+ ((Ocr & BIT24) != 0)) {
+ Status = SdCardVoltageSwitch (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ } else {
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ HostCtrl2 = BIT3;
+ SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+
+ gBS->Stall (5000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if ((HostCtrl2 & BIT3) == 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ gBS->Stall (1000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0xF) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));
+ }
+
+ Status = SdCardAllSendCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdCardSetRca (PassThru, Slot, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));
+ Private->Slot[Slot].CardType = SdCardType;
+
+ Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));
+
+ return Status;
+
+Error:
+ //
+ // Set SD Bus Power = 0
+ //
+ PowerCtrl = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);
+ return EFI_DEVICE_ERROR;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
new file mode 100644
index 000000000..57f4cf329
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
@@ -0,0 +1,1423 @@
+/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit
+ System Addressing support in SD Host Controller Simplified Specification version
+ 4.20.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+EDKII_SD_MMC_OVERRIDE *mOverride;
+
+//
+// Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
+ SdMmcPciHcDriverBindingSupported,
+ SdMmcPciHcDriverBindingStart,
+ SdMmcPciHcDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, 0, \
+ {EDKII_SD_MMC_BUS_WIDTH_IGNORE,\
+ EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\
+ {EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}
+
+//
+// Template for SD/MMC host controller private data.
+//
+SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
+ SD_MMC_HC_PRIVATE_SIGNATURE, // Signature
+ NULL, // ControllerHandle
+ NULL, // PciIo
+ { // PassThru
+ sizeof (UINT32),
+ SdMmcPassThruPassThru,
+ SdMmcPassThruGetNextSlot,
+ SdMmcPassThruBuildDevicePath,
+ SdMmcPassThruGetSlotNumber,
+ SdMmcPassThruResetDevice
+ },
+ 0, // PciAttributes
+ 0, // PreviousSlot
+ NULL, // TimerEvent
+ NULL, // ConnectEvent
+ // Queue
+ INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),
+ { // Slot
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE
+ },
+ { // Capability
+ {0},
+ },
+ { // MaxCurrent
+ 0,
+ },
+ {
+ 0 // ControllerVersion
+ }
+};
+
+SD_DEVICE_PATH mSdDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_SD_DP,
+ {
+ (UINT8) (sizeof (SD_DEVICE_PATH)),
+ (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+EMMC_DEVICE_PATH mEmmcDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_EMMC_DP,
+ {
+ (UINT8) (sizeof (EMMC_DEVICE_PATH)),
+ (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+//
+// Prioritized function list to detect card type.
+// User could add other card detection logic here.
+//
+CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
+ EmmcIdentification,
+ SdCardIdentification,
+ NULL
+};
+
+/**
+ The entry point for SD host controller driver, used to install this driver on the ImageHandle.
+
+ @param[in] ImageHandle The firmware allocated handle for this driver image.
+ @param[in] SystemTable Pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdMmcPciHcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSdMmcPciHcDriverBinding,
+ ImageHandle,
+ &gSdMmcPciHcComponentName,
+ &gSdMmcPciHcComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN InfiniteWait;
+ EFI_EVENT TrbEvent;
+
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
+
+ //
+ // Check if the first entry in the async I/O queue is done or not.
+ //
+ Status = EFI_SUCCESS;
+ Trb = NULL;
+ Link = GetFirstNode (&Private->Queue);
+ if (!IsNull (&Private->Queue, Link)) {
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ if (!Private->Slot[Trb->Slot].MediaPresent) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+ if (!Trb->Started) {
+ //
+ // Check whether the cmd/data line is ready for transfer.
+ //
+ Status = SdMmcCheckTrbEnv (Private, Trb);
+ if (!EFI_ERROR (Status)) {
+ Trb->Started = TRUE;
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ goto Done;
+ }
+ }
+ Status = SdMmcCheckTrbResult (Private, Trb);
+ }
+
+Done:
+ if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
+ Packet = Trb->Packet;
+ if (Packet->Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+ if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_TIMEOUT;
+ TrbEvent = Trb->Event;
+ SdMmcFreeTrb (Trb);
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));
+ gBS->SignalEvent (TrbEvent);
+ return;
+ }
+ } else if ((Trb != NULL) && (Status == EFI_CRC_ERROR) && (Trb->Retries > 0)) {
+ Trb->Retries--;
+ Trb->Started = FALSE;
+ } else if ((Trb != NULL)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = Status;
+ TrbEvent = Trb->Event;
+ SdMmcFreeTrb (Trb);
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));
+ gBS->SignalEvent (TrbEvent);
+ }
+ return;
+}
+
+/**
+ Sd removable device enumeration callback function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+SdMmcPciHcEnumerateDevice (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINT8 Slot;
+ BOOLEAN MediaPresent;
+ UINT32 RoutineNum;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
+
+ for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {
+ if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {
+ Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);
+ if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));
+ Private->Slot[Slot].MediaPresent = FALSE;
+ Private->Slot[Slot].Initialized = FALSE;
+ //
+ // Signal all async task events at the slot with EFI_NO_MEDIA status.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ if (Trb->Slot == Slot) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = SdMmcHcReset (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Reinitialize slot and restart identification process for the new attached device
+ //
+ Status = SdMmcHcInitHost (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+
+ //
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ }
+ }
+
+ return;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingSupported (
+ 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;
+ PCI_TYPE00 PciData;
+
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+
+ //
+ // SdPciHcDxe is a device driver, and should ingore the
+ // "RemainingDevicePath" according to EFI spec.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error.
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Now test the EfiPciIoProtocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now further check the PCI header: Base class (offset 0x08) and
+ // Sub Class (offset 0x05). This controller should be an SD/MMC PCI
+ // Host Controller.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Since we already got the PciData, we can close protocol to avoid to carry it
+ // on for multiple exit points.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Examine SD PCI Host Controller PCI Configuration table fields.
+ //
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&
+ (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&
+ ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+SdMmcPciHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ UINT64 PciAttributes;
+ UINT8 SlotNum;
+ UINT8 FirstBar;
+ UINT8 Slot;
+ UINT8 Index;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINT32 RoutineNum;
+ BOOLEAN MediaPresent;
+ BOOLEAN Support64BitDma;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));
+
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ PciIo = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Enable the SD Host Controller MMIO space
+ //
+ Private = NULL;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &PciAttributes
+ );
+
+ 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
+ );
+ } else {
+ goto Done;
+ }
+
+ Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->ControllerHandle = Controller;
+ Private->PciIo = PciIo;
+ Private->PciAttributes = PciAttributes;
+ InitializeListHead (&Private->Queue);
+
+ //
+ // Get SD/MMC Pci Host Controller Slot info
+ //
+ Status = SdMmcHcGetSlotInfo (PciIo, &FirstBar, &SlotNum);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Attempt to locate the singleton instance of the SD/MMC override protocol,
+ // which implements platform specific workarounds for non-standard SDHCI
+ // implementations.
+ //
+ if (mOverride == NULL) {
+ Status = gBS->LocateProtocol (&gEdkiiSdMmcOverrideProtocolGuid, NULL,
+ (VOID **)&mOverride);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a: found SD/MMC override protocol\n",
+ __FUNCTION__));
+ }
+ }
+
+ Support64BitDma = TRUE;
+ for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {
+ Private->Slot[Slot].Enable = TRUE;
+ //
+ // Get SD/MMC Pci Host Controller Version
+ //
+ Status = SdMmcHcGetControllerVersion (PciIo, Slot, &Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->BaseClkFreq[Slot] = Private->Capability[Slot].BaseClkFreq;
+
+ if (mOverride != NULL) {
+ if (mOverride->Capability != NULL) {
+ Status = mOverride->Capability (
+ Controller,
+ Slot,
+ &Private->Capability[Slot],
+ &Private->BaseClkFreq[Slot]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: Failed to override capability - %r\n",
+ __FUNCTION__, Status));
+ continue;
+ }
+ }
+
+ if (mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Controller,
+ Slot,
+ EdkiiSdMmcGetOperatingParam,
+ (VOID*)&Private->Slot[Slot].OperatingParameters
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: Failed to get operating parameters, using defaults\n", __FUNCTION__));
+ }
+ }
+ }
+
+ DumpCapabilityReg (Slot, &Private->Capability[Slot]);
+ DEBUG ((
+ DEBUG_INFO,
+ "Slot[%d] Base Clock Frequency: %dMHz\n",
+ Slot,
+ Private->BaseClkFreq[Slot]
+ ));
+
+ //
+ // If any of the slots does not support 64b system bus
+ // do not enable 64b DMA in the PCI layer.
+ //
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300 &&
+ Private->Capability[Slot].SysBus64V3 == 0) ||
+ (Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400 &&
+ Private->Capability[Slot].SysBus64V3 == 0) ||
+ (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410 &&
+ Private->Capability[Slot].SysBus64V4 == 0)) {
+ Support64BitDma = FALSE;
+ }
+
+ Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;
+ if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));
+ continue;
+ }
+
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = SdMmcHcReset (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Check whether there is a SD/MMC card attached
+ //
+ if (Private->Slot[Slot].SlotType == RemovableSlot) {
+ Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);
+ if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {
+ continue;
+ } else if (!MediaPresent) {
+ DEBUG ((
+ DEBUG_INFO,
+ "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n",
+ Slot
+ ));
+ continue;
+ }
+ }
+
+ Status = SdMmcHcInitHost (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if (Support64BitDma) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));
+ }
+ }
+
+ //
+ // Start the asynchronous I/O monitor
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ProcessAsyncTaskList,
+ Private,
+ &Private->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Start the Sd removable device connection enumeration
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ SdMmcPciHcEnumerateDevice,
+ Private,
+ &Private->ConnectEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru),
+ NULL
+ );
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((Private != NULL) && (Private->PciAttributes != 0)) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if ((Private != NULL) && (Private->TimerEvent != NULL)) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ }
+
+ if (Private != NULL) {
+ FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+SdMmcPciHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Close Non-Blocking timer and free Task list.
+ //
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ Private->TimerEvent = NULL;
+ }
+ if (Private->ConnectEvent != NULL) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ Private->ConnectEvent = NULL;
+ }
+ //
+ // As the timer is closed, there is no needs to use TPL lock to
+ // protect the critical region "queue".
+ //
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+
+ //
+ // Uninstall Block I/O protocol from the device handle
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru)
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ //
+ // Restore original PCI attributes
+ //
+ PciIo = Private->PciIo;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Private);
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Execute TRB synchronously.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Trb Pointer to TRB to execute.
+
+ @retval EFI_SUCCESS TRB executed successfully.
+ @retval Other TRB failed.
+**/
+EFI_STATUS
+SdMmcPassThruExecSyncTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Wait async I/O list is empty before execute sync I/O operation.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&Private->Queue)) {
+ gBS->RestoreTPL (OldTpl);
+ break;
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ while (Trb->Retries) {
+ Status = SdMmcWaitTrbEnv (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcWaitTrbResult (Private, Trb);
+ if (Status == EFI_CRC_ERROR) {
+ Trb->Retries--;
+ } else {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD card
+ specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by SD card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_MMC_HC_TRB *Trb;
+
+ if ((This == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Immediately return for async I/O.
+ //
+ if (Event != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = SdMmcPassThruExecSyncTrb (Private, Trb);
+
+ SdMmcFreeTrb (Trb);
+
+ return Status;
+}
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The function
+ returns information about all available slots (populated or not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
+ is returned.
+
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
+ the slot number of the next slot on the SD controller is returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
+ EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.
+ On output, a pointer to the next slot number on the SD controller.
+ An input value of 0xFF retrieves the first slot number on the SD
+ controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
+ to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ UINT8 Index;
+
+ if ((This == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (*Slot == 0xFF) {
+ for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+ } else if (*Slot == Private->PreviousSlot) {
+ for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the SD
+ card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
+ is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
+ returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card for which a device
+ path node is to be allocated and built.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD
+ card specified by Slot. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by
+ Slot was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[Slot].CardType == SdCardType) {
+ SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
+ if (SdNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SdNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
+ } else if (Private->Slot[Slot].CardType == EmmcCardType) {
+ EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
+ if (EmmcNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EmmcNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
+ } else {
+ //
+ // Currently we only support SD and EMMC two device nodes.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified by
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,
+ EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes a SD
+ card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD card on
+ the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD
+ Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+ UINT8 SlotNumber;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ //
+ // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ ((DevicePath->SubType != MSG_SD_DP) &&
+ (DevicePath->SubType != MSG_EMMC_DP)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (DevicePath->SubType == MSG_SD_DP) {
+ SdNode = (SD_DEVICE_PATH *) DevicePath;
+ SlotNumber = SdNode->SlotNumber;
+ } else {
+ EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
+ SlotNumber = EmmcNode->SlotNumber;
+ }
+
+ if (SlotNumber >= SD_MMC_HC_MAX_SLOT) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[SlotNumber].Enable) {
+ *Slot = SlotNumber;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
+ returned.
+
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
+ is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card to be reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Free all async I/O requests in the queue
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
new file mode 100644
index 000000000..40e4373e5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
@@ -0,0 +1,864 @@
+/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MMC_PCI_HC_DXE_H_
+#define _SD_MMC_PCI_HC_DXE_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Emmc.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/SdMmcOverride.h>
+#include <Protocol/SdMmcPassThru.h>
+
+#include "SdMmcPciHci.h"
+
+extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding;
+
+extern EDKII_SD_MMC_OVERRIDE *mOverride;
+
+#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f')
+
+#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)
+
+//
+// Generic time out value, 1 microsecond as unit.
+//
+#define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000
+
+//
+// SD/MMC async transfer timer interval, set by experience.
+// The unit is 100us, takes 1ms as interval.
+//
+#define SD_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
+//
+// SD/MMC removable device enumeration timer interval, set by experience.
+// The unit is 100us, takes 100ms as interval.
+//
+#define SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
+
+typedef enum {
+ UnknownCardType,
+ SdCardType,
+ SdioCardType,
+ MmcCardType,
+ EmmcCardType
+} SD_MMC_CARD_TYPE;
+
+typedef enum {
+ RemovableSlot,
+ EmbeddedSlot,
+ SharedBusSlot,
+ UnknownSlot
+} EFI_SD_MMC_SLOT_TYPE;
+
+typedef struct {
+ BOOLEAN Enable;
+ EFI_SD_MMC_SLOT_TYPE SlotType;
+ BOOLEAN MediaPresent;
+ BOOLEAN Initialized;
+ SD_MMC_CARD_TYPE CardType;
+ UINT64 CurrentFreq;
+ EDKII_SD_MMC_OPERATING_PARAMETERS OperatingParameters;
+} SD_MMC_HC_SLOT;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE ControllerHandle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
+
+ UINT64 PciAttributes;
+ //
+ // The field is used to record the previous slot in GetNextSlot().
+ //
+ UINT8 PreviousSlot;
+ //
+ // For Non-blocking operation.
+ //
+ EFI_EVENT TimerEvent;
+ //
+ // For Sd removable device enumeration.
+ //
+ EFI_EVENT ConnectEvent;
+ LIST_ENTRY Queue;
+
+ SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT];
+ SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT];
+ UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT];
+ UINT16 ControllerVersion[SD_MMC_HC_MAX_SLOT];
+
+ //
+ // Some controllers may require to override base clock frequency
+ // value stored in Capabilities Register 1.
+ //
+ UINT32 BaseClkFreq[SD_MMC_HC_MAX_SLOT];
+} SD_MMC_HC_PRIVATE_DATA;
+
+typedef struct {
+ SD_MMC_BUS_MODE BusTiming;
+ UINT8 BusWidth;
+ UINT32 ClockFreq;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+} SD_MMC_BUS_SETTINGS;
+
+#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T')
+
+#define SD_MMC_TRB_RETRIES 5
+
+//
+// TRB (Transfer Request Block) contains information for the cmd request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY TrbList;
+
+ UINT8 Slot;
+ UINT16 BlockSize;
+
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ VOID *Data;
+ UINT32 DataLen;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS DataPhy;
+ VOID *DataMap;
+ SD_MMC_HC_TRANSFER_MODE Mode;
+ SD_MMC_HC_ADMA_LENGTH_MODE AdmaLengthMode;
+
+ EFI_EVENT Event;
+ BOOLEAN Started;
+ BOOLEAN CommandComplete;
+ UINT64 Timeout;
+ UINT32 Retries;
+
+ BOOLEAN PioModeTransferCompleted;
+ UINT32 PioBlockIndex;
+
+ SD_MMC_HC_ADMA_32_DESC_LINE *Adma32Desc;
+ SD_MMC_HC_ADMA_64_V3_DESC_LINE *Adma64V3Desc;
+ SD_MMC_HC_ADMA_64_V4_DESC_LINE *Adma64V4Desc;
+ EFI_PHYSICAL_ADDRESS AdmaDescPhy;
+ VOID *AdmaMap;
+ UINT32 AdmaPages;
+
+ SD_MMC_HC_PRIVATE_DATA *Private;
+} SD_MMC_HC_TRB;
+
+#define SD_MMC_HC_TRB_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG)
+
+//
+// Task for Non-blocking mode.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Slot;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN IsStart;
+ EFI_EVENT Event;
+ UINT64 RetryTimes;
+ BOOLEAN InfiniteWait;
+ VOID *Map;
+ VOID *MapAddress;
+} SD_MMC_HC_QUEUE;
+
+//
+// Prototypes
+//
+/**
+ Execute card identification procedure.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The card is identified correctly.
+ @retval Others The card can't be identified.
+
+**/
+typedef
+EFI_STATUS
+(*CARD_TYPE_DETECT_ROUTINE) (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD card
+ specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by SD card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The function
+ returns information about all available slots (populated or not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
+ is returned.
+
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
+ the slot number of the next slot on the SD controller is returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
+ EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.
+ On output, a pointer to the next slot number on the SD controller.
+ An input value of 0xFF retrieves the first slot number on the SD
+ controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
+ to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ );
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the SD
+ card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
+ is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
+ returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card for which a device
+ path node is to be allocated and built.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD
+ card specified by Slot. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by
+ Slot was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified by
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,
+ EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes a SD
+ card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD card on
+ the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD
+ Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ );
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
+ returned.
+
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
+ is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card to be reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ );
+
+//
+// Driver model protocol interfaces
+//
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+SdMmcPciHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+SdMmcPciHcDriverBindingStop (
+ 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
+SdMmcPciHcComponentNameGetDriverName (
+ 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 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 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
+SdMmcPciHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ );
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming BusTiming at which the frequency change is done.
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN BOOLEAN FirstTimeSetup,
+ IN UINT64 ClockFreq
+ );
+
+/**
+ Software reset the specified SD/MMC host controller.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdMmcHcReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
new file mode 100644
index 000000000..453ecde7f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+# Host Controller Simplified Specification version 3.0 plus the 64-bit System Addressing
+# support in SD Host Controller Simplified Specification version 4.20.
+#
+# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+# to specified devices from upper layer.
+#
+# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdMmcPciHcDxe
+ MODULE_UNI_FILE = SdMmcPciHcDxe.uni
+ FILE_GUID = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSdMmcPciHcDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gSdMmcPciHcDxeDriverBinding
+# COMPONENT_NAME = gSdMmcPciHcDxeComponentName
+# COMPONENT_NAME2 = gSdMmcPciHcDxeComponentName2
+#
+#
+
+[Sources]
+ SdMmcPciHcDxe.h
+ SdMmcPciHcDxe.c
+ EmmcDevice.c
+ SdDevice.c
+ SdMmcPciHci.h
+ SdMmcPciHci.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEdkiiSdMmcOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSdMmcPassThruProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SdMmcPciHcDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni
new file mode 100644
index 000000000..962e19c2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni
@@ -0,0 +1,19 @@
+// /** @file
+// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+// Host Controller Simplified Specification version 3.0 plus the 64-bit System Addressing
+// support in SD Host Controller Simplified Specification version 4.20.
+//
+// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+// to specified devices from upper layer.
+//
+// Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni
new file mode 100644
index 000000000..8dfbd86ae
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SdMmcPciHcDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SD/MMC Pci Host Controller Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
new file mode 100644
index 000000000..6548ef71d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
@@ -0,0 +1,2838 @@
+/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit
+ System Addressing support in SD Host Controller Simplified Specification version
+ 4.20.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ //
+ // Dump Capability Data
+ //
+ DEBUG ((DEBUG_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));
+ DEBUG ((DEBUG_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));
+ DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));
+ DEBUG ((DEBUG_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));
+ DEBUG ((DEBUG_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V4 64-bit Sys Bus %a\n", Capability->SysBus64V4 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V3 64-bit Sys Bus %a\n", Capability->SysBus64V3 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SlotType "));
+ if (Capability->SlotType == 0x00) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
+ } else if (Capability->SlotType == 0x01) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
+ } else if (Capability->SlotType == 0x02) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));
+ if (Capability->TimerCount == 0) {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));
+ } else {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));
+ DEBUG ((DEBUG_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));
+ DEBUG ((DEBUG_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));
+ return;
+}
+
+/**
+ Read SlotInfo register from SD/MMC host controller pci config space.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[out] FirstBar The buffer to store the first BAR value.
+ @param[out] SlotNum The buffer to store the supported slot number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_INFO SlotInfo;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ SD_MMC_HC_SLOT_OFFSET,
+ sizeof (SlotInfo),
+ &SlotInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *FirstBar = SlotInfo.FirstBar;
+ *SlotNum = SlotInfo.SlotNum + 1;
+ ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT);
+ return EFI_SUCCESS;
+}
+
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ if ((PciIo == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Count) {
+ case 1:
+ Width = EfiPciIoWidthUint8;
+ break;
+ case 2:
+ Width = EfiPciIoWidthUint16;
+ Count = 1;
+ break;
+ case 4:
+ Width = EfiPciIoWidthUint32;
+ Count = 1;
+ break;
+ case 8:
+ Width = EfiPciIoWidthUint32;
+ Count = 2;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Read) {
+ Status = PciIo->Mem.Read (
+ PciIo,
+ Width,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ } else {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ Width,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Or;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ Or = *(UINT8*) OrData;
+ } else if (Count == 2) {
+ Or = *(UINT16*) OrData;
+ } else if (Count == 4) {
+ Or = *(UINT32*) OrData;
+ } else if (Count == 8) {
+ Or = *(UINT64*) OrData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data |= Or;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 And;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ And = *(UINT8*) AndData;
+ } else if (Count == 2) {
+ And = *(UINT16*) AndData;
+ } else if (Count == 4) {
+ And = *(UINT32*) AndData;
+ } else if (Count == 8) {
+ And = *(UINT64*) AndData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data &= And;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcCheckMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Value;
+
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = 0;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ BarIndex,
+ Offset,
+ Count,
+ MaskValue,
+ TestValue
+ );
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get the controller version information from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Version The buffer to store the version information.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetControllerVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT16 *Version
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (UINT16), Version);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Version &= 0xFF;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Software reset the specified SD/MMC host controller and enable all interrupts.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdMmcHcReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SwReset;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // Notify the SD/MMC override protocol that we are about to reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ SwReset = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_SW_RST, sizeof (SwReset), &SwReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write SW Reset for All fails: %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ BIT0,
+ 0x00,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = SdMmcHcEnableInterrupt (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: SdMmcHcEnableInterrupt done with %r\n",
+ Status));
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we have just reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IntStatus;
+
+ //
+ // Enable all bits in Error Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Enable all bits in Normal Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+
+ return Status;
+}
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Cap;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Capability, &Cap, sizeof (Cap));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the maximum current capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent);
+
+ return Status;
+}
+
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data;
+ UINT32 PresentState;
+
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ *MediaPresent = TRUE;
+ } else {
+ *MediaPresent = FALSE;
+ }
+
+ //
+ // Check Normal Interrupt Status Register
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT6 | BIT7)) != 0) {
+ //
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
+ //
+ Data &= BIT6 | BIT7;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_MEDIA_CHANGED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PresentState;
+ UINT16 ClockCtrl;
+
+ //
+ // Ensure no SD transactions are occurring on the SD Bus by
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
+ // in the Present State register to be 0.
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ BIT0 | BIT1,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 0
+ //
+ ClockCtrl = (UINT16)~BIT2;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ Start the SD clock.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number.
+
+ @retval EFI_SUCCESS Succeeded to start the SD clock.
+ @retval Others Failed to start the SD clock.
+**/
+EFI_STATUS
+SdMmcHcStartSdClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ UINT16 ClockCtrl;
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ return SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+}
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming BusTiming at which the frequency change is done.
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN BOOLEAN FirstTimeSetup,
+ IN UINT64 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ClockCtrl;
+ UINT32 BaseClkFreq;
+ UINT16 ControllerVer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Private->PciIo;
+ BaseClkFreq = Private->BaseClkFreq[Slot];
+ ControllerVer = Private->ControllerVersion[Slot];
+
+ if (BaseClkFreq == 0 || ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq * 1000;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+
+ //
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
+ //
+ if ((ControllerVer >= SD_MMC_HC_CTRL_VER_300) &&
+ (ControllerVer <= SD_MMC_HC_CTRL_VER_420)) {
+ ASSERT (Divisor <= 0x3FF);
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
+ } else if ((ControllerVer == SD_MMC_HC_CTRL_VER_100) ||
+ (ControllerVer == SD_MMC_HC_CTRL_VER_200)) {
+ //
+ // Only the most significant bit can be used as divisor.
+ //
+ if (((Divisor - 1) & Divisor) != 0) {
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);
+ }
+ ASSERT (Divisor <= 0x80);
+ ClockCtrl = (Divisor & 0xFF) << 8;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Stop bus clock at first
+ //
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Supply clock frequency with specified divisor
+ //
+ ClockCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // We don't notify the platform on first time setup to avoid changing
+ // legacy behavior. During first time setup we also don't know what type
+ // of the card slot it is and which enum value of BusTiming applies.
+ //
+ if (!FirstTimeSetup && mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcSwitchClockFreqPost,
+ &BusTiming
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC switch clock freq post notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ Private->Slot[Slot].CurrentFreq = ClockFreq;
+
+ return Status;
+}
+
+/**
+ SD/MMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD/MMC card attached.
+ @retval FALSE There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clr SD Bus Power
+ //
+ PowerCtrl &= (UINT8)~BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ PowerCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+
+ return Status;
+}
+
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (BusWidth == 1) {
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 4) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 |= BIT1;
+ HostCtrl1 &= (UINT8)~BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 8) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 &= (UINT8)~BIT1;
+ HostCtrl1 |= BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Configure V4 controller enhancements at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+ @param[in] ControllerVer The version of host controller.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitV4Enhancements (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability,
+ IN UINT16 ControllerVer
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HostCtrl2;
+
+ //
+ // Check if controller version V4 or higher
+ //
+ if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {
+ HostCtrl2 = SD_MMC_HC_V4_EN;
+ //
+ // Check if controller version V4.0
+ //
+ if (ControllerVer == SD_MMC_HC_CTRL_VER_400) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V3 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ }
+ //
+ // Check if controller version V4.10 or higher
+ //
+ else if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V4 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ HostCtrl2 |= SD_MMC_HC_26_DATA_LEN_ADMA_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 26 bit data length ADMA support\n"));
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MaxVoltage;
+ UINT8 HostCtrl2;
+
+ //
+ // Calculate supported maximum voltage according to SD Bus Voltage Select
+ //
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxVoltage = 0x0E;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxVoltage = 0x0C;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxVoltage = 0x0A;
+ HostCtrl2 = BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ gBS->Stall (5000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage);
+
+ return Status;
+}
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Timeout;
+
+ Timeout = 0x0E;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
+
+ return Status;
+}
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ SD_MMC_HC_SLOT_CAP Capability;
+
+ //
+ // Notify the SD/MMC override protocol that we are about to initialize
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ Capability = Private->Capability[Slot];
+
+ Status = SdMmcHcInitV4Enhancements (PciIo, Slot, Capability, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Perform first time clock setup with 400 KHz frequency.
+ // We send the 0 as the BusTiming value because at this time
+ // we still do not know the slot type and which enum value will apply.
+ // Since it is a first time setup SdMmcHcClockSupply won't notify
+ // the platofrm driver anyway so it doesn't matter.
+ //
+ Status = SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we are have just initialized
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
+ return Status;
+}
+
+/**
+ Set SD Host Controler control 2 registry according to selected speed.
+
+ @param[in] ControllerHandle The handle of the controller.
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Timing The timing to select.
+
+ @retval EFI_SUCCESS The timing is set successfully.
+ @retval Others The timing isn't set successfully.
+**/
+EFI_STATUS
+SdMmcHcUhsSignaling (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE Timing
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+
+ HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Timing) {
+ case SdMmcUhsSdr12:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;
+ break;
+ case SdMmcUhsSdr25:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;
+ break;
+ case SdMmcUhsSdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;
+ break;
+ case SdMmcUhsSdr104:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;
+ break;
+ case SdMmcUhsDdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;
+ break;
+ case SdMmcMmcLegacy:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;
+ break;
+ case SdMmcMmcHsSdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;
+ break;
+ case SdMmcMmcHsDdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;
+ break;
+ case SdMmcMmcHs200:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;
+ break;
+ case SdMmcMmcHs400:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;
+ break;
+ default:
+ HostCtrl2 = 0;
+ break;
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ ControllerHandle,
+ Slot,
+ EdkiiSdMmcUhsSignaling,
+ &Timing
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC uhs signaling notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set driver strength in host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] SlotIndex The slot index of the card.
+ @param[in] DriverStrength DriverStrength to set in the controller.
+
+ @retval EFI_SUCCESS Driver strength programmed successfully.
+ @retval Others Failed to set driver strength.
+**/
+EFI_STATUS
+SdMmcSetDriverStrength (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 SlotIndex,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HostCtrl2;
+
+ if (DriverStrength == SdDriverStrengthIgnore) {
+ return EFI_SUCCESS;
+ }
+
+ HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostCtrl2 = (DriverStrength << 4) & SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+}
+
+/**
+ Turn on/off LED.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] On The boolean to turn on/off LED.
+
+ @retval EFI_SUCCESS The LED is turned on/off successfully.
+ @retval Others The LED isn't turned on/off successfully.
+
+**/
+EFI_STATUS
+SdMmcHcLedOnOff (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN On
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (On) {
+ HostCtrl1 = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ HostCtrl1 = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ }
+
+ return Status;
+}
+
+/**
+ Build ADMA descriptor table for transfer.
+
+ Refer to SD Host Controller Simplified spec 4.2 Section 1.13 for details.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] ControllerVer The version of host controller.
+
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
+ @retval Others The ADMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildAdmaDescTable (
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 ControllerVer
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINT64 Address;
+ UINTN TableSize;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINTN Bytes;
+ UINT32 AdmaMaxDataPerLine;
+ UINT32 DescSize;
+ VOID *AdmaDesc;
+
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_16B;
+ DescSize = sizeof (SD_MMC_HC_ADMA_32_DESC_LINE);
+ AdmaDesc = NULL;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ PciIo = Trb->Private->PciIo;
+
+ //
+ // Check for valid ranges in 32bit ADMA Descriptor Table
+ //
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check address field alignment
+ //
+ if (Trb->Mode != SdMmcAdma32bMode) {
+ //
+ // Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1 | BIT2)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 8 bytes boundary!\n", Data));
+ }
+ } else {
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+ }
+
+ //
+ // Configure 64b ADMA.
+ //
+ if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V3_DESC_LINE);
+ }else if (Trb->Mode == SdMmcAdma64bV4Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V4_DESC_LINE);
+ }
+ //
+ // Configure 26b data length.
+ //
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;
+ }
+
+ Entries = DivU64x32 ((DataLen + AdmaMaxDataPerLine - 1), AdmaMaxDataPerLine);
+ TableSize = (UINTN)MultU64x32 (Entries, DescSize);
+ Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (TableSize),
+ (VOID **)&AdmaDesc,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem (AdmaDesc, TableSize);
+ Bytes = TableSize;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ AdmaDesc,
+ &Bytes,
+ &Trb->AdmaDescPhy,
+ &Trb->AdmaMap
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != TableSize)) {
+ //
+ // Map error or unable to map the whole RFis buffer into a contiguous region.
+ //
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ AdmaDesc
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {
+ //
+ // The ADMA doesn't support 64bit addressing.
+ //
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ Trb->AdmaMap = NULL;
+
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ AdmaDesc
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ Remaining = DataLen;
+ Address = Data;
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc = AdmaDesc;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc = AdmaDesc;
+ } else {
+ Trb->Adma64V4Desc = AdmaDesc;
+ }
+
+ for (Index = 0; Index < Entries; Index++) {
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ break;
+ } else {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma32Desc[Index].LowerLength = 0;
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ }
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = 0;
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
+ } else {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = 0;
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
+ }
+
+ Remaining -= AdmaMaxDataPerLine;
+ Address += AdmaMaxDataPerLine;
+ }
+
+ //
+ // Set the last descriptor line as end of descriptor table
+ //
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc[Index].End = 1;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc[Index].End = 1;
+ } else {
+ Trb->Adma64V4Desc[Index].End = 1;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Prints the contents of the command packet to the debug port.
+
+ @param[in] DebugLevel Debug level at which the packet should be printed.
+ @param[in] Packet Pointer to packet to print.
+**/
+VOID
+SdMmcPrintPacket (
+ IN UINT32 DebugLevel,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ if (Packet == NULL) {
+ return;
+ }
+
+ DEBUG ((DebugLevel, "Printing EFI_SD_MMC_PASS_THRU_COMMAND_PACKET\n"));
+ if (Packet->SdMmcCmdBlk != NULL) {
+ DEBUG ((DebugLevel, "Command index: %d, argument: %X\n", Packet->SdMmcCmdBlk->CommandIndex, Packet->SdMmcCmdBlk->CommandArgument));
+ DEBUG ((DebugLevel, "Command type: %d, response type: %d\n", Packet->SdMmcCmdBlk->CommandType, Packet->SdMmcCmdBlk->ResponseType));
+ }
+ if (Packet->SdMmcStatusBlk != NULL) {
+ DEBUG ((DebugLevel, "Response 0: %X, 1: %X, 2: %X, 3: %X\n",
+ Packet->SdMmcStatusBlk->Resp0,
+ Packet->SdMmcStatusBlk->Resp1,
+ Packet->SdMmcStatusBlk->Resp2,
+ Packet->SdMmcStatusBlk->Resp3
+ ));
+ }
+ DEBUG ((DebugLevel, "Timeout: %ld\n", Packet->Timeout));
+ DEBUG ((DebugLevel, "InDataBuffer: %p\n", Packet->InDataBuffer));
+ DEBUG ((DebugLevel, "OutDataBuffer: %p\n", Packet->OutDataBuffer));
+ DEBUG ((DebugLevel, "InTransferLength: %d\n", Packet->InTransferLength));
+ DEBUG ((DebugLevel, "OutTransferLength: %d\n", Packet->OutTransferLength));
+ DEBUG ((DebugLevel, "TransactionStatus: %r\n", Packet->TransactionStatus));
+}
+
+/**
+ Prints the contents of the TRB to the debug port.
+
+ @param[in] DebugLevel Debug level at which the TRB should be printed.
+ @param[in] Trb Pointer to the TRB structure.
+**/
+VOID
+SdMmcPrintTrb (
+ IN UINT32 DebugLevel,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ if (Trb == NULL) {
+ return;
+ }
+
+ DEBUG ((DebugLevel, "Printing SD_MMC_HC_TRB\n"));
+ DEBUG ((DebugLevel, "Slot: %d\n", Trb->Slot));
+ DEBUG ((DebugLevel, "BlockSize: %d\n", Trb->BlockSize));
+ DEBUG ((DebugLevel, "Data: %p\n", Trb->Data));
+ DEBUG ((DebugLevel, "DataLen: %d\n", Trb->DataLen));
+ DEBUG ((DebugLevel, "Read: %d\n", Trb->Read));
+ DEBUG ((DebugLevel, "DataPhy: %lX\n", Trb->DataPhy));
+ DEBUG ((DebugLevel, "DataMap: %p\n", Trb->DataMap));
+ DEBUG ((DebugLevel, "Mode: %d\n", Trb->Mode));
+ DEBUG ((DebugLevel, "AdmaLengthMode: %d\n", Trb->AdmaLengthMode));
+ DEBUG ((DebugLevel, "Event: %p\n", Trb->Event));
+ DEBUG ((DebugLevel, "Started: %d\n", Trb->Started));
+ DEBUG ((DebugLevel, "CommandComplete: %d\n", Trb->CommandComplete));
+ DEBUG ((DebugLevel, "Timeout: %ld\n", Trb->Timeout));
+ DEBUG ((DebugLevel, "Retries: %d\n", Trb->Retries));
+ DEBUG ((DebugLevel, "PioModeTransferCompleted: %d\n", Trb->PioModeTransferCompleted));
+ DEBUG ((DebugLevel, "PioBlockIndex: %d\n", Trb->PioBlockIndex));
+ DEBUG ((DebugLevel, "Adma32Desc: %p\n", Trb->Adma32Desc));
+ DEBUG ((DebugLevel, "Adma64V3Desc: %p\n", Trb->Adma64V3Desc));
+ DEBUG ((DebugLevel, "Adma64V4Desc: %p\n", Trb->Adma64V4Desc));
+ DEBUG ((DebugLevel, "AdmaMap: %p\n", Trb->AdmaMap));
+ DEBUG ((DebugLevel, "AdmaPages: %X\n", Trb->AdmaPages));
+
+ SdMmcPrintPacket (DebugLevel, Trb->Packet);
+}
+
+/**
+ Sets up host memory to allow DMA transfer.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+
+ @retval EFI_SUCCESS Memory has been mapped for DMA transfer.
+ @retval Others Memory has not been mapped.
+**/
+EFI_STATUS
+SdMmcSetupMemoryForDmaTransfer (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN MapLength;
+ EFI_STATUS Status;
+
+ if (Trb->Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
+
+ PciIo = Private->PciIo;
+ if (Trb->Data != NULL && Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Trb->Data,
+ &MapLength,
+ &Trb->DataPhy,
+ &Trb->DataMap
+ );
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ if (Trb->Mode == SdMmcAdma32bMode ||
+ Trb->Mode == SdMmcAdma64bV3Mode ||
+ Trb->Mode == SdMmcAdma64bV4Mode) {
+ Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ )
+{
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Signature = SD_MMC_HC_TRB_SIG;
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Event = Event;
+ Trb->Started = FALSE;
+ Trb->CommandComplete = FALSE;
+ Trb->Timeout = Packet->Timeout;
+ Trb->Retries = SD_MMC_TRB_RETRIES;
+ Trb->PioModeTransferCompleted = FALSE;
+ Trb->PioBlockIndex = 0;
+ Trb->Private = Private;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
+ }
+
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ Trb->Mode = SdMmcPioMode;
+ } else {
+ if (Trb->DataLen == 0) {
+ Trb->Mode = SdMmcNoData;
+ } else if (Private->Capability[Slot].Adma2 != 0) {
+ Trb->Mode = SdMmcAdma32bMode;
+ Trb->AdmaLengthMode = SdMmcAdmaLen16b;
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) {
+ Trb->Mode = SdMmcAdma64bV3Mode;
+ } else if (((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) ||
+ ((Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) &&
+ (Private->Capability[Slot].SysBus64V4 == 1))) {
+ Trb->Mode = SdMmcAdma64bV4Mode;
+ }
+ if (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Trb->AdmaLengthMode = SdMmcAdmaLen26b;
+ }
+ Status = SdMmcSetupMemoryForDmaTransfer (Private, Slot, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else if (Private->Capability[Slot].Sdma != 0) {
+ Trb->Mode = SdMmcSdmaMode;
+ Status = SdMmcSetupMemoryForDmaTransfer (Private, Slot, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ Trb->Mode = SdMmcPioMode;
+ }
+ }
+
+ if (Event != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->Queue, &Trb->TrbList);
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Trb;
+
+Error:
+ SdMmcFreeTrb (Trb);
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Trb->Private->PciIo;
+
+ if (Trb->AdmaMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ }
+ if (Trb->Adma32Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma32Desc
+ );
+ }
+ if (Trb->Adma64V3Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma64V3Desc
+ );
+ }
+ if (Trb->Adma64V4Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma64V4Desc
+ );
+ }
+ if (Trb->DataMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->DataMap
+ );
+ }
+ FreePool (Trb);
+ return;
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 PresentState;
+
+ Packet = Trb->Packet;
+
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) {
+ //
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
+ // the Present State register to be 0
+ //
+ PresentState = BIT0 | BIT1;
+ } else {
+ //
+ // Wait Command Inhibit (CMD) in the Present State register
+ // to be 0
+ //
+ PresentState = BIT0;
+ }
+
+ PciIo = Private->PciIo;
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ Trb->Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ PresentState,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Packet = Trb->Packet;
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcCheckTrbEnv (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 Cmd;
+ UINT16 IntStatus;
+ UINT32 Argument;
+ UINT32 BlkCount;
+ UINT16 BlkSize;
+ UINT16 TransMode;
+ UINT8 HostCtrl1;
+ UINT64 SdmaAddr;
+ UINT64 AdmaAddr;
+ BOOLEAN AddressingMode64;
+
+ AddressingMode64 = FALSE;
+
+ Packet = Trb->Packet;
+ PciIo = Trb->Private->PciIo;
+ //
+ // Clear all bits in Error Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits.
+ //
+ IntStatus = 0xFF3F;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),
+ SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_64_ADDR_EN);
+ if (!EFI_ERROR (Status)) {
+ AddressingMode64 = TRUE;
+ }
+ }
+
+ //
+ // Set Host Control 1 register DMA Select field
+ //
+ if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
+ HostCtrl1 = BIT4;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ HostCtrl1 = BIT4|BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);
+
+ if (Trb->Mode == SdMmcSdmaMode) {
+ if ((!AddressingMode64) &&
+ ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdmaAddr = (UINT64)(UINTN)Trb->DataPhy;
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (UINT64), &SdmaAddr);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &SdmaAddr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV3Mode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlkSize = Trb->BlockSize;
+ if (Trb->Mode == SdMmcSdmaMode) {
+ //
+ // Set SDMA boundary to be 512K bytes.
+ //
+ BlkSize |= 0x7000;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkCount = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ //
+ // Calcuate Block Count.
+ //
+ BlkCount = (Trb->DataLen / Trb->BlockSize);
+ }
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &BlkCount);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (UINT16), &BlkCount);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransMode = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ if (Trb->Mode != SdMmcPioMode) {
+ TransMode |= BIT0;
+ }
+ if (Trb->Read) {
+ TransMode |= BIT4;
+ }
+ if (BlkCount > 1) {
+ TransMode |= BIT5 | BIT1;
+ }
+ //
+ // Only SD memory card needs to use AUTO CMD12 feature.
+ //
+ if (Private->Slot[Trb->Slot].CardType == SdCardType) {
+ if (BlkCount > 1) {
+ TransMode |= BIT2;
+ }
+ }
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8);
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) {
+ Cmd |= BIT5;
+ }
+ //
+ // Convert ResponseType to value
+ //
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR1:
+ case SdMmcResponseTypeR5:
+ case SdMmcResponseTypeR6:
+ case SdMmcResponseTypeR7:
+ Cmd |= (BIT1 | BIT3 | BIT4);
+ break;
+ case SdMmcResponseTypeR2:
+ Cmd |= (BIT0 | BIT3);
+ break;
+ case SdMmcResponseTypeR3:
+ case SdMmcResponseTypeR4:
+ Cmd |= BIT1;
+ break;
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR5b:
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ //
+ // Execute cmd
+ //
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
+ return Status;
+}
+
+/**
+ Performs SW reset based on passed error status mask.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot to reset.
+ @param[in] ErrIntStatus Error interrupt status mask.
+
+ @retval EFI_SUCCESS Software reset performed successfully.
+ @retval Other Software reset failed.
+**/
+EFI_STATUS
+SdMmcSoftwareReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 ErrIntStatus
+ )
+{
+ UINT8 SwReset;
+ EFI_STATUS Status;
+
+ SwReset = 0;
+ if ((ErrIntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((ErrIntStatus & 0x70) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks the error status in error status register
+ and issues appropriate software reset as described in
+ SD specification section 3.10.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot for device.
+ @param[in] IntStatus Normal interrupt status mask.
+
+ @retval EFI_CRC_ERROR CRC error happened during CMD execution.
+ @retval EFI_SUCCESS No error reported.
+ @retval Others Some other error happened.
+
+**/
+EFI_STATUS
+SdMmcCheckAndRecoverErrors (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 ErrIntStatus;
+ EFI_STATUS Status;
+ EFI_STATUS ErrorStatus;
+
+ if ((IntStatus & BIT15) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (ErrIntStatus),
+ &ErrIntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_ERROR, "Error reported by SDHCI\n"));
+ DEBUG ((DEBUG_ERROR, "Interrupt status = %X\n", IntStatus));
+ DEBUG ((DEBUG_ERROR, "Error interrupt status = %X\n", ErrIntStatus));
+
+ //
+ // If the data timeout error is reported
+ // but data transfer is signaled as completed we
+ // have to ignore data timeout. We also assume that no
+ // other error is present on the link since data transfer
+ // completed successfully. Error interrupt status
+ // register is going to be reset when the next command
+ // is started.
+ //
+ if (((ErrIntStatus & BIT4) != 0) && ((IntStatus & BIT1) != 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // We treat both CMD and DAT CRC errors and
+ // end bits errors as EFI_CRC_ERROR. This will
+ // let higher layer know that the error possibly
+ // happened due to random bus condition and the
+ // command can be retried.
+ //
+ if ((ErrIntStatus & (BIT1 | BIT2 | BIT5 | BIT6)) != 0) {
+ ErrorStatus = EFI_CRC_ERROR;
+ } else {
+ ErrorStatus = EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcSoftwareReset (Private, Slot, ErrIntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ErrorStatus;
+}
+
+/**
+ Reads the response data into the TRB buffer.
+ This function assumes that caller made sure that
+ command has completed.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS Response read successfully.
+ @retval Others Failed to get response.
+**/
+EFI_STATUS
+SdMmcGetResponse (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT8 Index;
+ UINT32 Response[4];
+ EFI_STATUS Status;
+
+ Packet = Trb->Packet;
+
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeBc) {
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0; Index < 4; Index++) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_RESPONSE + Index * 4,
+ TRUE,
+ sizeof (UINT32),
+ &Response[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks if the command completed. If the command
+ completed it gets the response and records the
+ command completion in the TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS Command completed successfully.
+ @retval EFI_NOT_READY Command completion still pending.
+ @retval Others Command failed to complete.
+**/
+EFI_STATUS
+SdMmcCheckCommandComplete (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 Data16;
+ EFI_STATUS Status;
+
+ if ((IntStatus & BIT0) != 0) {
+ Data16 = BIT0;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = SdMmcGetResponse (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->CommandComplete = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Transfers data from card using PIO method.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS PIO transfer completed successfully.
+ @retval EFI_NOT_READY PIO transfer completion still pending.
+ @retval Others PIO transfer failed to complete.
+**/
+EFI_STATUS
+SdMmcTransferDataWithPio (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data16;
+ UINT32 BlockCount;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+ UINTN Count;
+
+ BlockCount = (Trb->DataLen / Trb->BlockSize);
+ if (Trb->DataLen % Trb->BlockSize != 0) {
+ BlockCount += 1;
+ }
+
+ if (Trb->PioBlockIndex >= BlockCount) {
+ return EFI_SUCCESS;
+ }
+
+ switch (Trb->BlockSize % sizeof (UINT32)) {
+ case 0:
+ Width = EfiPciIoWidthFifoUint32;
+ Count = Trb->BlockSize / sizeof (UINT32);
+ break;
+ case 2:
+ Width = EfiPciIoWidthFifoUint16;
+ Count = Trb->BlockSize / sizeof (UINT16);
+ break;
+ case 1:
+ case 3:
+ default:
+ Width = EfiPciIoWidthFifoUint8;
+ Count = Trb->BlockSize;
+ break;
+ }
+
+ if (Trb->Read) {
+ if ((IntStatus & BIT5) == 0) {
+ return EFI_NOT_READY;
+ }
+ Data16 = BIT5;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
+
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ Width,
+ Trb->Slot,
+ SD_MMC_HC_BUF_DAT_PORT,
+ Count,
+ (VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->PioBlockIndex++;
+ } else {
+ if ((IntStatus & BIT4) == 0) {
+ return EFI_NOT_READY;
+ }
+ Data16 = BIT4;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
+
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ Width,
+ Trb->Slot,
+ SD_MMC_HC_BUF_DAT_PORT,
+ Count,
+ (VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->PioBlockIndex++;
+ }
+
+ if (Trb->PioBlockIndex >= BlockCount) {
+ Trb->PioModeTransferCompleted = TRUE;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Update the SDMA address on the SDMA buffer boundary interrupt.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS Updated SDMA buffer address.
+ @retval Others Failed to update SDMA buffer address.
+**/
+EFI_STATUS
+SdMmcUpdateSdmaAddress (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ UINT64 SdmaAddr;
+ EFI_STATUS Status;
+
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_ADMA_SYS_ADDR,
+ FALSE,
+ sizeof (UINT64),
+ &SdmaAddr
+ );
+ } else {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_SDMA_ADDR,
+ FALSE,
+ sizeof (UINT32),
+ &SdmaAddr
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trb->DataPhy = (UINT64)(UINTN)SdmaAddr;
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks if the data transfer completed and performs any actions
+ neccessary to continue the data transfer such as SDMA system
+ address fixup or PIO data transfer.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS Data transfer completed successfully.
+ @retval EFI_NOT_READY Data transfer completion still pending.
+ @retval Others Data transfer failed to complete.
+**/
+EFI_STATUS
+SdMmcCheckDataTransfer (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 Data16;
+ EFI_STATUS Status;
+
+ if ((IntStatus & BIT1) != 0) {
+ Data16 = BIT1;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ return Status;
+ }
+
+ if (Trb->Mode == SdMmcPioMode && !Trb->PioModeTransferCompleted) {
+ Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) != 0)) {
+ Data16 = BIT3;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = SdMmcUpdateSdmaAddress (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT16 IntStatus;
+
+ Packet = Trb->Packet;
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check if there are any errors reported by host controller
+ // and if neccessary recover the controller before next command is executed.
+ //
+ Status = SdMmcCheckAndRecoverErrors (Private, Trb->Slot, IntStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Tuning commands are the only ones that do not generate command
+ // complete interrupt. Process them here before entering the code
+ // that waits for command completion.
+ //
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
+ goto Done;
+ }
+
+ if (!Trb->CommandComplete) {
+ Status = SdMmcCheckCommandComplete (Private, Trb, IntStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc ||
+ Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b ||
+ Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b) {
+ Status = SdMmcCheckDataTransfer (Private, Trb, IntStatus);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ if (Status != EFI_NOT_READY) {
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TRB failed with %r\n", Status));
+ SdMmcPrintTrb (DEBUG_ERROR, Trb);
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "TRB success\n"));
+ SdMmcPrintTrb (DEBUG_VERBOSE, Trb);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ Packet = Trb->Packet;
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcCheckTrbResult (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
new file mode 100644
index 000000000..16229a846
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
@@ -0,0 +1,610 @@
+/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MMC_PCI_HCI_H_
+#define _SD_MMC_PCI_HCI_H_
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define SD_MMC_HC_SLOT_OFFSET 0x40
+
+#define SD_MMC_HC_MAX_SLOT 6
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define SD_MMC_HC_SDMA_ADDR 0x00
+#define SD_MMC_HC_ARG2 0x00
+#define SD_MMC_HC_BLK_SIZE 0x04
+#define SD_MMC_HC_BLK_COUNT 0x06
+#define SD_MMC_HC_ARG1 0x08
+#define SD_MMC_HC_TRANS_MOD 0x0C
+#define SD_MMC_HC_COMMAND 0x0E
+#define SD_MMC_HC_RESPONSE 0x10
+#define SD_MMC_HC_BUF_DAT_PORT 0x20
+#define SD_MMC_HC_PRESENT_STATE 0x24
+#define SD_MMC_HC_HOST_CTRL1 0x28
+#define SD_MMC_HC_POWER_CTRL 0x29
+#define SD_MMC_HC_BLK_GAP_CTRL 0x2A
+#define SD_MMC_HC_WAKEUP_CTRL 0x2B
+#define SD_MMC_HC_CLOCK_CTRL 0x2C
+#define SD_MMC_HC_TIMEOUT_CTRL 0x2E
+#define SD_MMC_HC_SW_RST 0x2F
+#define SD_MMC_HC_NOR_INT_STS 0x30
+#define SD_MMC_HC_ERR_INT_STS 0x32
+#define SD_MMC_HC_NOR_INT_STS_EN 0x34
+#define SD_MMC_HC_ERR_INT_STS_EN 0x36
+#define SD_MMC_HC_NOR_INT_SIG_EN 0x38
+#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A
+#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C
+#define SD_MMC_HC_HOST_CTRL2 0x3E
+#define SD_MMC_HC_CAP 0x40
+#define SD_MMC_HC_MAX_CURRENT_CAP 0x48
+#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50
+#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52
+#define SD_MMC_HC_ADMA_ERR_STS 0x54
+#define SD_MMC_HC_ADMA_SYS_ADDR 0x58
+#define SD_MMC_HC_PRESET_VAL 0x60
+#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0
+#define SD_MMC_HC_SLOT_INT_STS 0xFC
+#define SD_MMC_HC_CTRL_VER 0xFE
+
+//
+// SD Host Controller bits to HOST_CTRL2 register
+//
+#define SD_MMC_HC_CTRL_UHS_MASK 0x0007
+#define SD_MMC_HC_CTRL_UHS_SDR12 0x0000
+#define SD_MMC_HC_CTRL_UHS_SDR25 0x0001
+#define SD_MMC_HC_CTRL_UHS_SDR50 0x0002
+#define SD_MMC_HC_CTRL_UHS_SDR104 0x0003
+#define SD_MMC_HC_CTRL_UHS_DDR50 0x0004
+#define SD_MMC_HC_CTRL_MMC_LEGACY 0x0000
+#define SD_MMC_HC_CTRL_MMC_HS_SDR 0x0001
+#define SD_MMC_HC_CTRL_MMC_HS_DDR 0x0004
+#define SD_MMC_HC_CTRL_MMC_HS200 0x0003
+#define SD_MMC_HC_CTRL_MMC_HS400 0x0005
+
+#define SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK 0x0030
+
+//
+// The transfer modes supported by SD Host Controller
+//
+typedef enum {
+ SdMmcNoData,
+ SdMmcPioMode,
+ SdMmcSdmaMode,
+ SdMmcAdma32bMode,
+ SdMmcAdma64bV3Mode,
+ SdMmcAdma64bV4Mode
+} SD_MMC_HC_TRANSFER_MODE;
+
+//
+// The ADMA transfer lengths supported by SD Host Controller
+//
+typedef enum {
+ SdMmcAdmaLen16b,
+ SdMmcAdmaLen26b
+} SD_MMC_HC_ADMA_LENGTH_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE_16B SIZE_64KB
+#define ADMA_MAX_DATA_PER_LINE_26B SIZE_64MB
+
+//
+// ADMA descriptor for 32b addressing.
+//
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 Address;
+} SD_MMC_HC_ADMA_32_DESC_LINE;
+
+//
+// ADMA descriptor for 64b addressing.
+//
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 LowerAddress;
+ UINT32 UpperAddress;
+} SD_MMC_HC_ADMA_64_V3_DESC_LINE;
+
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 LowerAddress;
+ UINT32 UpperAddress;
+ UINT32 Reserved1;
+} SD_MMC_HC_ADMA_64_V4_DESC_LINE;
+
+#define SD_MMC_SDMA_BOUNDARY 512 * 1024
+#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
+
+typedef struct {
+ UINT8 FirstBar:3; // bit 0:2
+ UINT8 Reserved:1; // bit 3
+ UINT8 SlotNum:3; // bit 4:6
+ UINT8 Reserved1:1; // bit 7
+} SD_MMC_HC_SLOT_INFO;
+
+typedef struct {
+ UINT32 TimeoutFreq:6; // bit 0:5
+ UINT32 Reserved:1; // bit 6
+ UINT32 TimeoutUnit:1; // bit 7
+ UINT32 BaseClkFreq:8; // bit 8:15
+ UINT32 MaxBlkLen:2; // bit 16:17
+ UINT32 BusWidth8:1; // bit 18
+ UINT32 Adma2:1; // bit 19
+ UINT32 Reserved2:1; // bit 20
+ UINT32 HighSpeed:1; // bit 21
+ UINT32 Sdma:1; // bit 22
+ UINT32 SuspRes:1; // bit 23
+ UINT32 Voltage33:1; // bit 24
+ UINT32 Voltage30:1; // bit 25
+ UINT32 Voltage18:1; // bit 26
+ UINT32 SysBus64V4:1; // bit 27
+ UINT32 SysBus64V3:1; // bit 28
+ UINT32 AsyncInt:1; // bit 29
+ UINT32 SlotType:2; // bit 30:31
+ UINT32 Sdr50:1; // bit 32
+ UINT32 Sdr104:1; // bit 33
+ UINT32 Ddr50:1; // bit 34
+ UINT32 Reserved3:1; // bit 35
+ UINT32 DriverTypeA:1; // bit 36
+ UINT32 DriverTypeC:1; // bit 37
+ UINT32 DriverTypeD:1; // bit 38
+ UINT32 DriverType4:1; // bit 39
+ UINT32 TimerCount:4; // bit 40:43
+ UINT32 Reserved4:1; // bit 44
+ UINT32 TuningSDR50:1; // bit 45
+ UINT32 RetuningMod:2; // bit 46:47
+ UINT32 ClkMultiplier:8; // bit 48:55
+ UINT32 Reserved5:7; // bit 56:62
+ UINT32 Hs400:1; // bit 63
+} SD_MMC_HC_SLOT_CAP;
+
+//
+// SD Host controller version
+//
+#define SD_MMC_HC_CTRL_VER_100 0x00
+#define SD_MMC_HC_CTRL_VER_200 0x01
+#define SD_MMC_HC_CTRL_VER_300 0x02
+#define SD_MMC_HC_CTRL_VER_400 0x03
+#define SD_MMC_HC_CTRL_VER_410 0x04
+#define SD_MMC_HC_CTRL_VER_420 0x05
+
+//
+// SD Host controller V4 enhancements
+//
+#define SD_MMC_HC_V4_EN BIT12
+#define SD_MMC_HC_64_ADDR_EN BIT13
+#define SD_MMC_HC_26_DATA_LEN_ADMA_EN BIT10
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Read SlotInfo register from SD/MMC host controller pci config space.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[out] FirstBar The buffer to store the first BAR value.
+ @param[out] SlotNum The buffer to store the supported slot number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ );
+
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ );
+
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ );
+
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ );
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ );
+
+/**
+ Get the controller version information from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Version The buffer to store the version information.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetControllerVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT16 *Version
+ );
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Get the maximum current capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ );
+
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ );
+
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Start the SD clock.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number.
+
+ @retval EFI_SUCCESS Succeeded to start the SD clock.
+ @retval Others Failed to start the SD clock.
+**/
+EFI_STATUS
+SdMmcHcStartSdClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ SD/MMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD/MMC card attached.
+ @retval FALSE There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ );
+
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ );
+
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Set SD Host Controller control 2 registry according to selected speed.
+
+ @param[in] ControllerHandle The handle of the controller.
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Timing The timing to select.
+
+ @retval EFI_SUCCESS The timing is set successfully.
+ @retval Others The timing isn't set successfully.
+**/
+EFI_STATUS
+SdMmcHcUhsSignaling (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE Timing
+ );
+
+/**
+ Set driver strength in host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] SlotIndex The slot index of the card.
+ @param[in] DriverStrength DriverStrength to set in the controller.
+
+ @retval EFI_SUCCESS Driver strength programmed successfully.
+ @retval Others Failed to set driver strength.
+**/
+EFI_STATUS
+SdMmcSetDriverStrength (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 SlotIndex,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c
new file mode 100644
index 000000000..3aa11f8ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c
@@ -0,0 +1,206 @@
+/** @file
+ SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC
+ host controller MMIO base, to upper layer SD/MMC drivers.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcPei.h"
+
+EDKII_SD_MMC_HOST_CONTROLLER_PPI mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,
+ &mSdMmcHostControllerPpi
+};
+
+/**
+ Get the MMIO base address of SD/MMC host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the SD/MMC host controller.
+ @param[in,out] MmioBar The pointer to store the array of available
+ SD/MMC host controller slot MMIO base addresses.
+ The entry number of the array is specified by BarNum.
+ @param[out] BarNum The pointer to store the supported bar number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSdMmcHcMmioBar (
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ IN OUT UINTN **MmioBar,
+ OUT UINT8 *BarNum
+ )
+{
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);
+
+ if (ControllerId >= Private->TotalSdMmcHcs) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];
+ *BarNum = (UINT8)Private->MmioBar[ControllerId].SlotNum;
+ return EFI_SUCCESS;
+}
+
+/**
+ The user code starts with this function.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The driver is successfully initialized.
+ @retval Others Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdMmcHcPeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+ UINT16 Bus;
+ UINT16 Device;
+ UINT16 Function;
+ UINT32 Size;
+ UINT64 MmioSize;
+ UINT8 SubClass;
+ UINT8 BaseClass;
+ UINT8 SlotInfo;
+ UINT8 SlotNum;
+ UINT8 FirstBar;
+ UINT8 Index;
+ UINT8 Slot;
+ UINT32 BarAddr;
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ///
+ /// We do not expose this in S3 boot path, because it is only for recovery.
+ ///
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ return EFI_SUCCESS;
+ }
+
+ Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = SD_MMC_HC_PEI_SIGNATURE;
+ Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;
+ Private->PpiList = mPpiList;
+ Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi;
+
+ BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);
+ for (Bus = 0; Bus < 256; Bus++) {
+ for (Device = 0; Device < 32; Device++) {
+ for (Function = 0; Function < 8; Function++) {
+ SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
+ BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
+
+ if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {
+ //
+ // Get the SD/MMC Pci host controller's Slot Info.
+ //
+ SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));
+ FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;
+ SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;
+ ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);
+
+ for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {
+ //
+ // Get the SD/MMC Pci host controller's MMIO region size.
+ //
+ PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);
+ Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));
+
+ switch (Size & 0x07) {
+ case 0x0:
+ //
+ // Memory space: anywhere in 32 bit address space
+ //
+ MmioSize = (~(Size & 0xFFFFFFF0)) + 1;
+ break;
+ case 0x4:
+ //
+ // Memory space: anywhere in 64 bit address space
+ //
+ MmioSize = Size & 0xFFFFFFF0;
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
+ Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ //
+ // Fix the length to support some spefic 64 bit BAR
+ //
+ Size |= ((UINT32)(-1) << HighBitSet32 (Size));
+ //
+ // Calculate the size of 64bit bar
+ //
+ MmioSize |= LShiftU64 ((UINT64) Size, 32);
+ MmioSize = (~(MmioSize)) + 1;
+ //
+ // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.
+ //
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);
+ break;
+ default:
+ //
+ // Unknown BAR type
+ //
+ ASSERT (FALSE);
+ continue;
+ };
+ //
+ // Assign resource to the SdMmc Pci host controller's MMIO BAR.
+ // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.
+ //
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);
+ PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+ //
+ // Record the allocated Mmio base address.
+ //
+ Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;
+ Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;
+ BarAddr += (UINT32)MmioSize;
+ }
+ Private->TotalSdMmcHcs++;
+ ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Install SdMmc Host Controller PPI
+ ///
+ Status = PeiServicesInstallPpi (&Private->PpiList);
+
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h
new file mode 100644
index 000000000..ee04a6b89
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h
@@ -0,0 +1,80 @@
+/** @file
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_
+#define _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/MasterBootMode.h>
+#include <Ppi/SdMmcHostController.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define SD_MMC_HC_PEI_SIGNATURE SIGNATURE_32 ('S', 'D', 'M', 'C')
+
+#define MAX_SD_MMC_HCS 8
+#define MAX_SD_MMC_SLOTS 6
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define SD_MMC_HC_PEI_SLOT_OFFSET 0x40
+
+typedef struct {
+ UINT8 FirstBar:3; // bit 0:2
+ UINT8 Reserved:1; // bit 3
+ UINT8 SlotNum:3; // bit 4:6
+ UINT8 Reserved1:1; // bit 7
+} SD_MMC_HC_PEI_SLOT_INFO;
+
+typedef struct {
+ UINTN SlotNum;
+ UINTN MmioBarAddr[MAX_SD_MMC_SLOTS];
+} SD_MMC_HC_PEI_BAR;
+
+typedef struct {
+ UINTN Signature;
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI SdMmcHostControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiList;
+ UINTN TotalSdMmcHcs;
+ SD_MMC_HC_PEI_BAR MmioBar[MAX_SD_MMC_HCS];
+} SD_MMC_HC_PEI_PRIVATE_DATA;
+
+#define SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_MMC_HC_PEI_PRIVATE_DATA, SdMmcHostControllerPpi, SD_MMC_HC_PEI_SIGNATURE)
+
+/**
+ Get the MMIO base address of SD/MMC host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the SD/MMC host controller.
+ @param[in,out] MmioBar The pointer to store the array of available
+ SD/MMC host controller slot MMIO base addresses.
+ The entry number of the array is specified by BarNum.
+ @param[out] BarNum The pointer to store the supported bar number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSdMmcHcMmioBar (
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ IN OUT UINTN **MmioBar,
+ OUT UINT8 *BarNum
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf
new file mode 100644
index 000000000..687905530
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf
@@ -0,0 +1,51 @@
+## @file
+# Component Description File For SD/MMC Pci Host Controller Pei Module.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdMmcPciHcPei
+ MODULE_UNI_FILE = SdMmcPciHcPei.uni
+ FILE_GUID = 1BB737EF-427A-4144-8B3B-B76EF38515E6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeSdMmcHcPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ SdMmcPciHcPei.c
+ SdMmcPciHcPei.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PciLib
+ DebugLib
+ PeiServicesLib
+ MemoryAllocationLib
+ PeimEntryPoint
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase ## CONSUMES
+
+[Ppis]
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## PRODUCES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SdMmcPciHcPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni
new file mode 100644
index 000000000..bc2768648
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni
@@ -0,0 +1,15 @@
+// /** @file
+// The SdMmcPciHcPei driver is used by upper layer to retrieve mmio base address
+// of managed pci-based SD/MMC host controller at PEI phase.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Providing interface for upper layer to retrieve mmio base address of managed pci-based SD/MMC host controller at PEI phase."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interface of getting mmio base address of managed pci-based SD/MMC host controller at PEI phase."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni
new file mode 100644
index 000000000..9118ac3cd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SdMmcPciHcPei Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SD/MMC PCI-Based HC Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c
new file mode 100644
index 000000000..5dc67e890
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/ComponentName.c
@@ -0,0 +1,219 @@
+/** @file
+ UfsHcDxe driver produces EFI_UFS_HOST_CONTROLLER_PROTOCOL. The upper layer module
+ uses it to query the MMIO base address of the UFS host controller.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPciHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUfsHcComponentName = {
+ UfsHcComponentNameGetDriverName,
+ UfsHcComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUfsHcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UfsHcComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UfsHcComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsHcDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Universal Flash Storage (UFS) Pci Host Controller Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsHcControllerNameTable[] = {
+ {
+ "eng;en",
+ L"Universal Flash Storage (UFS) Pci Host 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
+UfsHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUfsHcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUfsHcComponentName)
+ );
+}
+
+/**
+ 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
+UfsHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ 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;
+ }
+
+ //
+ // Make sure this driver is currently managing Controller Handle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gUfsHcDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUfsHcControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUfsHcComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c
new file mode 100644
index 000000000..4be90d7a8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.c
@@ -0,0 +1,810 @@
+/** @file
+ UfsHcDxe driver is used to provide platform-dependent info, mainly UFS host controller
+ MMIO base, to upper layer UFS drivers.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPciHcDxe.h"
+
+//
+// NVM Express Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gUfsHcDriverBinding = {
+ UfsHcDriverBindingSupported,
+ UfsHcDriverBindingStart,
+ UfsHcDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for Ufs host controller private data.
+//
+UFS_HOST_CONTROLLER_PRIVATE_DATA gUfsHcTemplate = {
+ UFS_HC_PRIVATE_DATA_SIGNATURE, // Signature
+ { // UfsHcProtocol
+ UfsHcGetMmioBar,
+ UfsHcAllocateBuffer,
+ UfsHcFreeBuffer,
+ UfsHcMap,
+ UfsHcUnmap,
+ UfsHcFlush,
+ UfsHcMmioRead,
+ UfsHcMmioWrite
+ },
+ NULL, // PciIo
+ 0, // BarIndex
+ 0 // PciAttributes
+};
+
+/**
+ Get the MMIO base of the UFS host controller.
+
+ @param[in] This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param[out] MmioBar The MMIO base address of UFS host controller.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval others The operation fails.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcGetMmioBar (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ OUT UINTN *MmioBar
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT8 BarIndex;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
+
+ if ((This == NULL) || (MmioBar == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BarDesc = NULL;
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+ BarIndex = Private->BarIndex;
+
+ Status = PciIo->GetBarAttributes (
+ PciIo,
+ BarIndex,
+ NULL,
+ (VOID**) &BarDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MmioBar = (UINTN)BarDesc->AddrRangeMin;
+
+ FreePool (BarDesc);
+
+ return Status;
+}
+
+/**
+ Provides the UFS controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the UFS controller.
+ @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 UFS controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMap (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (HostAddress == NULL) || (NumberOfBytes == NULL) || (DeviceAddress == NULL) || (Mapping == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+
+ Status = PciIo->Map (PciIo, (EFI_PCI_IO_PROTOCOL_OPERATION)Operation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Mapping The mapping value returned from 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
+UfsHcUnmap (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (Mapping == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+
+ Status = PciIo->Unmap (PciIo, Mapping);
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcAllocateBuffer (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (HostAddress == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+
+ Status = PciIo->AllocateBuffer (PciIo, Type, MemoryType, Pages, HostAddress, Attributes);
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcFreeBuffer (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (HostAddress == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+
+ Status = PciIo->FreeBuffer (PciIo, Pages, HostAddress);
+ return Status;
+}
+
+/**
+ Flushes all posted write transactions from the UFS bus to attached UFS device.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The posted write transactions were flushed from the UFS bus
+ to attached UFS device.
+ @retval EFI_DEVICE_ERROR The posted write transactions were not flushed from the UFS
+ bus to attached UFS device due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcFlush (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+
+ Status = PciIo->Flush (PciIo);
+ return Status;
+}
+
+/**
+ Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
+
+ @param This A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the UFS Host Controller MMIO space to start the
+ memory operation.
+ @param Count The number of memory operations to perform.
+ @param 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 read from or written to the UFS host controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the UFS Host Controller memory space.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMmioRead (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT8 BarIndex;
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+ BarIndex = Private->BarIndex;
+
+ Status = PciIo->Mem.Read (PciIo, (EFI_PCI_IO_PROTOCOL_WIDTH)Width, BarIndex, Offset, Count, Buffer);
+
+ return Status;
+}
+
+/**
+ Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
+
+ @param This A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the UFS Host Controller MMIO space to start the
+ memory operation.
+ @param Count The number of memory operations to perform.
+ @param 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 read from or written to the UFS host controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the UFS Host Controller memory space.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMmioWrite (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT8 BarIndex;
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (This);
+ PciIo = Private->PciIo;
+ BarIndex = Private->BarIndex;
+
+ Status = PciIo->Mem.Write (PciIo, (EFI_PCI_IO_PROTOCOL_WIDTH)Width, BarIndex, Offset, Count, Buffer);
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN UfsHcFound;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciData;
+
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+ UfsHcFound = FALSE;
+
+ //
+ // UfsHcDxe is a device driver, and should ingore the
+ // "RemainingDevicePath" according to EFI spec
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Now test the EfiPciIoProtocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ 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 UFS controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Since we already got the PciData, we can close protocol to avoid to carry it on for multiple exit points.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Examine UFS Host Controller PCI Configuration table fields
+ //
+ if (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE) {
+ if (PciData.Hdr.ClassCode[1] == 0x09 ) { //UFS Controller Subclass
+ UfsHcFound = TRUE;
+ }
+ }
+
+ if (!UfsHcFound) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+UfsHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ UINT64 Supports;
+ UINT8 BarIndex;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
+
+ PciIo = NULL;
+ Private = NULL;
+ Supports = 0;
+ BarDesc = NULL;
+
+ //
+ // Now test and open the EfiPciIoProtocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ //
+ // Status == 0 - A normal execution flow, SUCCESS and the program proceeds.
+ // Status == ALREADY_STARTED - A non-zero Status code returned. It indicates
+ // that the protocol has been opened and should be treated as a
+ // normal condition and the program proceeds. The Protocol will not
+ // opened 'again' by this call.
+ // Status != ALREADY_STARTED - Error status, terminate program execution
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+
+ Private = AllocateCopyPool (sizeof (UFS_HOST_CONTROLLER_PRIVATE_DATA), &gUfsHcTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->PciIo = PciIo;
+
+ for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
+ Status = PciIo->GetBarAttributes (
+ PciIo,
+ BarIndex,
+ NULL,
+ (VOID**) &BarDesc
+ );
+ if (Status == EFI_UNSUPPORTED) {
+ continue;
+ } else if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ Private->BarIndex = BarIndex;
+ FreePool (BarDesc);
+ break;
+ }
+
+ FreePool (BarDesc);
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->PciAttributes
+ );
+
+ 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
+ );
+ } else {
+ goto Done;
+ }
+
+ ///
+ /// Install UFS_HOST_CONTROLLER protocol
+ ///
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID*)&(Private->UfsHc)
+ );
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((Private != NULL) && (Private->PciAttributes != 0)) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (Private != NULL) {
+ FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+UfsHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UFS_HOST_CONTROLLER_PRIVATE_DATA *Private;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+
+ ///
+ /// Get private data
+ ///
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ (VOID **) &UfsHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Private = UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC (UfsHc);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ &(Private->UfsHc)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Restore original PCI attributes
+ //
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close protocols opened by UFS host controller driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (Private);
+ }
+
+ return Status;
+}
+
+/**
+ The entry point for UFS host controller driver, used to install this driver on the ImageHandle.
+
+ @param[in] ImageHandle The firmware allocated handle for this driver image.
+ @param[in] SystemTable Pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUfsHcDriverBinding,
+ ImageHandle,
+ &gUfsHcComponentName,
+ &gUfsHcComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h
new file mode 100644
index 000000000..1cf114467
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.h
@@ -0,0 +1,503 @@
+/** @file
+ UfsHcDxe driver is used to provide platform-dependent info, mainly UFS host controller
+ MMIO base, to upper layer UFS drivers.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UFS_HOST_CONTROLLER_H_
+#define _EFI_UFS_HOST_CONTROLLER_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/UfsHostController.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+extern EFI_DRIVER_BINDING_PROTOCOL gUfsHcDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUfsHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUfsHcComponentName2;
+
+//
+// Unique signature for private data structure.
+//
+#define UFS_HC_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('U','F','S','H')
+
+typedef struct _UFS_HOST_CONTROLLER_PRIVATE_DATA UFS_HOST_CONTROLLER_PRIVATE_DATA;
+
+//
+// Ufs host controller private data structure.
+//
+struct _UFS_HOST_CONTROLLER_PRIVATE_DATA {
+ UINT32 Signature;
+
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL UfsHc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 BarIndex;
+ UINT64 PciAttributes;
+};
+
+#define UFS_HOST_CONTROLLER_PRIVATE_DATA_FROM_UFSHC(a) \
+ CR (a, \
+ UFS_HOST_CONTROLLER_PRIVATE_DATA, \
+ UfsHc, \
+ UFS_HC_PRIVATE_DATA_SIGNATURE \
+ )
+
+/**
+ 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
+UfsHcComponentNameGetDriverName (
+ 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
+UfsHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+UfsHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+UfsHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Get the MMIO base of the UFS host controller.
+
+ @param[in] This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param[out] MmioBar The MMIO base address of UFS host controller.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval others The operation fails.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcGetMmioBar (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ OUT UINTN *MmioBar
+ );
+
+/**
+ Provides the UFS controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the UFS controller.
+ @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 UFS controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMap (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Mapping The mapping value returned from 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
+UfsHcUnmap (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcAllocateBuffer (
+ IN EDKII_UFS_HOST_CONTROLLER_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 AllocateBuffer().
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcFreeBuffer (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all posted write transactions from the UFS bus to attached UFS device.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The posted write transactions were flushed from the UFS bus
+ to attached UFS device.
+ @retval EFI_DEVICE_ERROR The posted write transactions were not flushed from the UFS
+ bus to attached UFS device due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcFlush (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This
+ );
+
+/**
+ Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
+
+ @param This A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the UFS Host Controller MMIO space to start the
+ memory operation.
+ @param Count The number of memory operations to perform.
+ @param 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 read from or written to the UFS host controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the UFS Host Controller memory space.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMmioRead (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
+
+ @param This A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the UFS Host Controller MMIO space to start the
+ memory operation.
+ @param Count The number of memory operations to perform.
+ @param 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 read from or written to the UFS host controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the UFS Host Controller memory space.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsHcMmioWrite (
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
new file mode 100644
index 000000000..b1397daf9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
@@ -0,0 +1,50 @@
+## @file
+# Component Description File For Universal Flash Storage Pci Host Controller Module.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UfsPciHcDxe
+ MODULE_UNI_FILE = UfsPciHcDxe.uni
+ FILE_GUID = AF43E178-C2E9-4712-A7CD-08BFDAC7482C
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 0.9
+ ENTRY_POINT = UfsHcDriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUfsHcDriverBinding
+# COMPONENT_NAME = gUfsHcComponentName
+# COMPONENT_NAME2 = gUfsHcComponentName2
+
+[Sources]
+ ComponentName.c
+ UfsPciHcDxe.c
+ UfsPciHcDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEdkiiUfsHostControllerProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UfsPciHcDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni
new file mode 100644
index 000000000..84fb404fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// The UfsPciHcDxe driver is used by upper layer to retrieve mmio base address of managed pci-based Ufs host controller.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Providing interface for upper layer to retrieve mmio base address of managed pci-based Ufs host controller."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interface of getting mmio base address of managed pci-based Ufs host controller."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni
new file mode 100644
index 000000000..b19d774ad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UfsPciHcDxe Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UFS PCI-Based HC Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c
new file mode 100644
index 000000000..447a05b5b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.c
@@ -0,0 +1,146 @@
+/** @file
+ UfsPciHcPei driver is used to provide platform-dependent info, mainly UFS host controller
+ MMIO base, to upper layer UFS drivers.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPciHcPei.h"
+
+EDKII_UFS_HOST_CONTROLLER_PPI mUfsHostControllerPpi = { GetUfsHcMmioBar };
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiUfsHostControllerPpiGuid,
+ &mUfsHostControllerPpi
+};
+
+/**
+ Get the MMIO base address of UFS host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the UFS host controller.
+ @param[out] MmioBar Pointer to the UFS host controller MMIO base address.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUfsHcMmioBar (
+ IN EDKII_UFS_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *MmioBar
+ )
+{
+ UFS_HC_PEI_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || (MmioBar == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_HC_PEI_PRIVATE_DATA_FROM_THIS (This);
+
+ if (ControllerId >= Private->TotalUfsHcs) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *MmioBar = (UINTN)Private->UfsHcPciAddr[ControllerId];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user code starts with this function.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The driver is successfully initialized.
+ @retval Others Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUfsHcPeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+ UINT16 Bus;
+ UINT16 Device;
+ UINT16 Function;
+ UINT32 Size;
+ UINT8 SubClass;
+ UINT8 BaseClass;
+ UFS_HC_PEI_PRIVATE_DATA *Private;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ///
+ /// We do not export this in S3 boot path, because it is only for recovery.
+ ///
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ return EFI_SUCCESS;
+ }
+
+ Private = (UFS_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (UFS_HC_PEI_PRIVATE_DATA));
+ if (Private == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for UFS_HC_PEI_PRIVATE_DATA! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = UFS_HC_PEI_SIGNATURE;
+ Private->UfsHostControllerPpi = mUfsHostControllerPpi;
+ Private->PpiList = mPpiList;
+ Private->PpiList.Ppi = &Private->UfsHostControllerPpi;
+
+ for (Bus = 0; Bus < 256; Bus++) {
+ for (Device = 0; Device < 32; Device++) {
+ for (Function = 0; Function < 8; Function++) {
+ SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
+ BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
+
+ if ((SubClass == 0x09) && (BaseClass == PCI_CLASS_MASS_STORAGE)) {
+ //
+ // Get the Ufs Pci host controller's MMIO region size.
+ //
+ PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);
+ Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+ //
+ // Assign resource to the Ufs Pci host controller's MMIO BAR.
+ // Enable the Ufs Pci host controller by setting BME and MSE bits of PCI_CMD register.
+ //
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)(PcdGet32 (PcdUfsPciHostControllerMmioBase) + Size * Private->TotalUfsHcs));
+ PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+ //
+ // Record the allocated Mmio base address.
+ //
+ Private->UfsHcPciAddr[Private->TotalUfsHcs] = PcdGet32 (PcdUfsPciHostControllerMmioBase) + Size * Private->TotalUfsHcs;
+ Private->TotalUfsHcs++;
+ ASSERT (Private->TotalUfsHcs < MAX_UFS_HCS);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Install Ufs Host Controller PPI
+ ///
+ Status = PeiServicesInstallPpi (&Private->PpiList);
+
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h
new file mode 100644
index 000000000..48b42b883
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.h
@@ -0,0 +1,56 @@
+/** @file
+ Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_PCI_HOST_CONTROLLER_PEI_H_
+#define _UFS_PCI_HOST_CONTROLLER_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/MasterBootMode.h>
+#include <Ppi/UfsHostController.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define UFS_HC_PEI_SIGNATURE SIGNATURE_32 ('U', 'F', 'S', 'P')
+#define MAX_UFS_HCS 8
+
+typedef struct {
+ UINTN Signature;
+ EDKII_UFS_HOST_CONTROLLER_PPI UfsHostControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiList;
+ UINTN TotalUfsHcs;
+ UINTN UfsHcPciAddr[MAX_UFS_HCS];
+} UFS_HC_PEI_PRIVATE_DATA;
+
+#define UFS_HC_PEI_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_HC_PEI_PRIVATE_DATA, UfsHostControllerPpi, UFS_HC_PEI_SIGNATURE)
+
+/**
+ Get the MMIO base address of UFS host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the UFS host controller.
+ @param[out] MmioBar Pointer to the UFS host controller MMIO base address.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUfsHcMmioBar (
+ IN EDKII_UFS_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *MmioBar
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf
new file mode 100644
index 000000000..707ee05df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf
@@ -0,0 +1,51 @@
+## @file
+# Component Description File For Universal Flash Storage Pci Host Controller Pei Module.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UfsPciHcPei
+ MODULE_UNI_FILE = UfsPciHcPei.uni
+ FILE_GUID = 905DC1AD-C44D-4965-98AC-B6B4444BFD65
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 0.9
+
+ ENTRY_POINT = InitializeUfsHcPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UfsPciHcPei.c
+ UfsPciHcPei.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PciLib
+ DebugLib
+ PeiServicesLib
+ MemoryAllocationLib
+ PeimEntryPoint
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUfsPciHostControllerMmioBase ## CONSUMES
+
+[Ppis]
+ gEdkiiPeiUfsHostControllerPpiGuid ## PRODUCES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UfsPciHcPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni
new file mode 100644
index 000000000..622653869
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.uni
@@ -0,0 +1,15 @@
+// /** @file
+// The UfsPciHcPei driver is used by upper layer to retrieve mmio base address of managed
+// pci-based Ufs host controller at PEI phase.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Providing interface for upper layer to retrieve mmio base address of managed pci-based Ufs host controller at PEI phase."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interface of getting mmio base address of managed pci-based Ufs host controller at PEI phase."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni
new file mode 100644
index 000000000..421242ac3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UfsPciHcPei Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UFS PCI-Based HC Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c
new file mode 100644
index 000000000..572c11c28
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c
@@ -0,0 +1,225 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for UHCI driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+//
+// EFI Component Name Protocol
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName = {
+ UhciComponentNameGetDriverName,
+ UhciComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUhciComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UhciComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UhciComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUhciDriverNameTable[] = {
+ { "eng;en", L"Usb Uhci Driver" },
+ { NULL, NULL }
+};
+
+
+//
+// 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
+UhciComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUhciDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUhciComponentName)
+ );
+}
+
+/**
+ 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
+UhciComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB_HC_DEV *UhciDev;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gUhciDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ gUhciDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UhciDev = UHC_FROM_USB2_HC_PROTO (Usb2Hc);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ UhciDev->CtrlNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUhciComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.h
new file mode 100644
index 000000000..c3b5674e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.h
@@ -0,0 +1,139 @@
+/** @file
+
+ This file contains the delarations for componet name routines.
+
+Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_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
+UhciComponentNameGetDriverName (
+ 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
+UhciComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
new file mode 100644
index 000000000..3ec5ecf0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
@@ -0,0 +1,1883 @@
+/** @file
+
+ The UHCI driver model and HC protocol routines.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
+ UhciDriverBindingSupported,
+ UhciDriverBindingStart,
+ UhciDriverBindingStop,
+ 0x20,
+ NULL,
+ NULL
+};
+
+/**
+ Provides software reset for the USB host controller according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform. See
+ below for a list of the supported bit mask values.
+
+ @return EFI_SUCCESS The reset operation succeeded.
+ @return EFI_INVALID_PARAMETER Attributes is not valid.
+ @return EFI_UNSUPPORTED This type of reset is not currently supported.
+ @return EFI_DEVICE_ERROR Other errors.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2Reset (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ )
+{
+ USB_HC_DEV *Uhc;
+ EFI_TPL OldTpl;
+
+ if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
+ (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ if (Uhc->DevicePath != NULL) {
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
+ Uhc->DevicePath
+ );
+ }
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ switch (Attributes) {
+ case EFI_USB_HC_RESET_GLOBAL:
+ //
+ // Stop schedule and set the Global Reset bit in the command register
+ //
+ UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
+ UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
+
+ gBS->Stall (UHC_ROOT_PORT_RESET_STALL);
+
+ //
+ // Clear the Global Reset bit to zero.
+ //
+ UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
+
+ gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
+ break;
+
+ case EFI_USB_HC_RESET_HOST_CONTROLLER:
+ //
+ // Stop schedule and set Host Controller Reset bit to 1
+ //
+ UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
+ UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
+
+ gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
+ break;
+
+ default:
+ goto ON_INVAILD_PARAMETER;
+ }
+
+ //
+ // Delete all old transactions on the USB bus, then
+ // reinitialize the frame list
+ //
+ UhciFreeAllAsyncReq (Uhc);
+ UhciDestoryFrameList (Uhc);
+ UhciInitFrameList (Uhc);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ON_INVAILD_PARAMETER:
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_INVALID_PARAMETER;
+}
+
+
+/**
+ Retrieves current state of the USB host controller according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param State Variable to receive current device state.
+
+ @return EFI_SUCCESS The state is returned.
+ @return EFI_INVALID_PARAMETER State is not valid.
+ @return EFI_DEVICE_ERROR Other errors.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2GetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ )
+{
+ USB_HC_DEV *Uhc;
+ UINT16 UsbSts;
+ UINT16 UsbCmd;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
+ UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
+
+ if ((UsbCmd & USBCMD_EGSM) !=0 ) {
+ *State = EfiUsbHcStateSuspend;
+
+ } else if ((UsbSts & USBSTS_HCH) != 0) {
+ *State = EfiUsbHcStateHalt;
+
+ } else {
+ *State = EfiUsbHcStateOperational;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets the USB host controller to a specific state according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param State Indicates the state of the host controller that will
+ be set.
+
+ @return EFI_SUCCESS Host controller was successfully placed in the state.
+ @return EFI_INVALID_PARAMETER State is invalid.
+ @return EFI_DEVICE_ERROR Failed to set the state.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2SetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ )
+{
+ EFI_USB_HC_STATE CurState;
+ USB_HC_DEV *Uhc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINT16 UsbCmd;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+ Status = Uhci2GetState (This, &CurState);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (CurState == State) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ switch (State) {
+ case EfiUsbHcStateHalt:
+ Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbHcStateOperational:
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
+
+ if (CurState == EfiUsbHcStateHalt) {
+ //
+ // Set Run/Stop bit to 1, also set the bandwidht reclamation
+ // point to 64 bytes
+ //
+ UsbCmd |= USBCMD_RS | USBCMD_MAXP;
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
+
+ } else if (CurState == EfiUsbHcStateSuspend) {
+ //
+ // If FGR(Force Global Resume) bit is 0, set it
+ //
+ if ((UsbCmd & USBCMD_FGR) == 0) {
+ UsbCmd |= USBCMD_FGR;
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
+ }
+
+ //
+ // wait 20ms to let resume complete (20ms is specified by UHCI spec)
+ //
+ gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);
+
+ //
+ // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
+ //
+ UsbCmd &= ~USBCMD_FGR;
+ UsbCmd &= ~USBCMD_EGSM;
+ UsbCmd |= USBCMD_RS;
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
+ }
+
+ break;
+
+ case EfiUsbHcStateSuspend:
+ Status = Uhci2SetState (This, EfiUsbHcStateHalt);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ //
+ // Set Enter Global Suspend Mode bit to 1.
+ //
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
+ UsbCmd |= USBCMD_EGSM;
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param MaxSpeed A pointer to the max speed USB host controller
+ supports.
+ @param PortNumber A pointer to the number of root hub ports.
+ @param Is64BitCapable A pointer to an integer to show whether USB host
+ controller supports 64-bit memory addressing.
+
+ @return EFI_SUCCESS capabilities were retrieved successfully.
+ @return EFI_INVALID_PARAMETER MaxSpeed or PortNumber or Is64BitCapable is NULL.
+ @return EFI_DEVICE_ERROR An error was encountered.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2GetCapability (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *PortNumber,
+ OUT UINT8 *Is64BitCapable
+ )
+{
+ USB_HC_DEV *Uhc;
+ UINT32 Offset;
+ UINT16 PortSC;
+ UINT32 Index;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *MaxSpeed = EFI_USB_SPEED_FULL;
+ *Is64BitCapable = (UINT8) FALSE;
+
+ *PortNumber = 0;
+
+ for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
+ Offset = USBPORTSC_OFFSET + Index * 2;
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);
+
+ //
+ // Port status's bit 7 is reserved and always returns 1 if
+ // the port number is valid. Intel's UHCI (in EHCI controller)
+ // returns 0 in this bit if port number is invalid. Also, if
+ // PciIo IoRead returns error, 0xFFFF is returned to caller.
+ //
+ if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {
+ break;
+ }
+ (*PortNumber)++;
+ }
+
+ Uhc->RootPorts = *PortNumber;
+
+ DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL.
+ @param PortNumber The port to get status.
+ @param PortStatus A pointer to the current port status bits and port
+ status change bits.
+
+ @return EFI_SUCCESS status of the USB root hub port was returned in PortStatus.
+ @return EFI_INVALID_PARAMETER PortNumber is invalid.
+ @return EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2GetRootHubPortStatus (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB_HC_DEV *Uhc;
+ UINT32 Offset;
+ UINT16 PortSC;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PortNumber >= Uhc->RootPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);
+
+ if ((PortSC & USBPORTSC_CCS) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+
+ if ((PortSC & USBPORTSC_PED) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+
+ if ((PortSC & USBPORTSC_SUSP) != 0) {
+ DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+
+ if ((PortSC & USBPORTSC_PR) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+
+ if ((PortSC & USBPORTSC_LSDA) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+
+ //
+ // CHC will always return one in port owner bit
+ //
+ PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
+
+ if ((PortSC & USBPORTSC_CSC) != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+
+ if ((PortSC & USBPORTSC_PEDC) != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets a feature for the specified root hub port according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port whose feature is
+ requested to be set.
+ @param PortFeature Indicates the feature selector associated with the
+ feature set request.
+
+ @return EFI_SUCCESS PortFeature was set for the root port.
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @return EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2SetRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_HC_DEV *Uhc;
+ EFI_TPL OldTpl;
+ UINT32 Offset;
+ UINT16 PortSC;
+ UINT16 Command;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ if (PortNumber >= Uhc->RootPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);
+
+ switch (PortFeature) {
+ case EfiUsbPortSuspend:
+ Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
+ if ((Command & USBCMD_EGSM) == 0) {
+ //
+ // if global suspend is not active, can set port suspend
+ //
+ PortSC &= 0xfff5;
+ PortSC |= USBPORTSC_SUSP;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ PortSC &= 0xfff5;
+ PortSC |= USBPORTSC_PR;
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // No action
+ //
+ break;
+
+ case EfiUsbPortEnable:
+ PortSC &= 0xfff5;
+ PortSC |= USBPORTSC_PED;
+ break;
+
+ default:
+ gBS->RestoreTPL (OldTpl);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhciWriteReg (Uhc->PciIo, Offset, PortSC);
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Clears a feature for the specified root hub port according to Uefi 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @return EFI_SUCCESS PortFeature was cleared for the USB root hub port.
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @return EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2ClearRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_HC_DEV *Uhc;
+ EFI_TPL OldTpl;
+ UINT32 Offset;
+ UINT16 PortSC;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+ if (PortNumber >= Uhc->RootPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ PortSC &= 0xfff5;
+ PortSC &= ~USBPORTSC_PED;
+ break;
+
+ case EfiUsbPortSuspend:
+ //
+ // Cause a resume on the specified port if in suspend mode.
+ //
+ PortSC &= 0xfff5;
+ PortSC &= ~USBPORTSC_SUSP;
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // No action
+ //
+ break;
+
+ case EfiUsbPortReset:
+ PortSC &= 0xfff5;
+ PortSC &= ~USBPORTSC_PR;
+ break;
+
+ case EfiUsbPortConnectChange:
+ PortSC &= 0xfff5;
+ PortSC |= USBPORTSC_CSC;
+ break;
+
+ case EfiUsbPortEnableChange:
+ PortSC &= 0xfff5;
+ PortSC |= USBPORTSC_PEDC;
+ break;
+
+ case EfiUsbPortSuspendChange:
+ //
+ // Root hub does not support this
+ //
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ //
+ // Root hub does not support this
+ //
+ break;
+
+ case EfiUsbPortResetChange:
+ //
+ // Root hub does not support this
+ //
+ break;
+
+ default:
+ gBS->RestoreTPL (OldTpl);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhciWriteReg (Uhc->PciIo, Offset, PortSC);
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Submits control transfer to a target USB device according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param Request USB device request to send.
+ @param TransferDirection Data direction of the Data stage in control transfer.
+ @param Data Data to transmit/receive in data stage.
+ @param DataLength Length of the data.
+ @param TimeOut Maximum time, in microseconds, for transfer to complete.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_SUCCESS The control transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT Failed due to timeout.
+ @return EFI_DEVICE_ERROR Failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2ControlTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_HC_DEV *Uhc;
+ UHCI_TD_SW *TDs;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UHCI_QH_RESULT QhResult;
+ UINT8 PktId;
+ UINT8 *RequestPhy;
+ VOID *RequestMap;
+ UINT8 *DataPhy;
+ VOID *DataMap;
+ BOOLEAN IsSlowDevice;
+ UINTN TransferDataLength;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+ TDs = NULL;
+ DataPhy = NULL;
+ DataMap = NULL;
+ RequestPhy = NULL;
+ RequestMap = NULL;
+
+ IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
+
+ //
+ // Parameters Checking
+ //
+ if (Request == NULL || TransferResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsSlowDevice && (MaximumPacketLength != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (TransferDirection == EfiUsbNoData) {
+ TransferDataLength = 0;
+ } else {
+ TransferDataLength = *DataLength;
+ }
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // If errors exist that cause host controller halt,
+ // clear status then return EFI_DEVICE_ERROR.
+ //
+ UhciAckAllInterrupt (Uhc);
+
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ //
+ // Map the Request and data for bus master access,
+ // then create a list of TD for this transfer
+ //
+ Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
+
+ if (EFI_ERROR (Status)) {
+ Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
+ goto ON_EXIT;
+ }
+
+ TDs = UhciCreateCtrlTds (
+ Uhc,
+ DeviceAddress,
+ PktId,
+ (UINT8*)Request,
+ RequestPhy,
+ (UINT8*)Data,
+ DataPhy,
+ TransferDataLength,
+ (UINT8) MaximumPacketLength,
+ IsSlowDevice
+ );
+
+ if (TDs == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNMAP_DATA;
+ }
+
+ //
+ // According to the speed of the end point, link
+ // the TD to corrosponding queue head, then check
+ // the execution result
+ //
+ UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);
+ Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
+ UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
+
+ Uhc->PciIo->Flush (Uhc->PciIo);
+
+ *TransferResult = QhResult.Result;
+
+ if (DataLength != NULL) {
+ *DataLength = QhResult.Complete;
+ }
+
+ UhciDestoryTds (Uhc, TDs);
+
+UNMAP_DATA:
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
+ Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and direction.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data.
+ @param DataLength On input, size of the data buffer, On output,
+ actually transferred data size.
+ @param DataToggle On input, data toggle to use; On output, next data toggle.
+ @param TimeOut Maximum time out, in microseconds.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult Variable to receive transfer result.
+
+ @return EFI_SUCCESS The bulk transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT Failed due to timeout.
+ @return EFI_DEVICE_ERROR Failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2BulkTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ EFI_USB_DATA_DIRECTION Direction;
+ EFI_TPL OldTpl;
+ USB_HC_DEV *Uhc;
+ UHCI_TD_SW *TDs;
+ UHCI_QH_SW *BulkQh;
+ UHCI_QH_RESULT QhResult;
+ EFI_STATUS Status;
+ UINT8 PktId;
+ UINT8 *DataPhy;
+ VOID *DataMap;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+ DataPhy = NULL;
+ DataMap = NULL;
+
+ if (DeviceSpeed == EFI_USB_SPEED_LOW) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_OUT_OF_RESOURCES;
+
+ //
+ // If has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ UhciAckAllInterrupt (Uhc);
+
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ //
+ // Map the source data buffer for bus master access,
+ // then create a list of TDs
+ //
+ if ((EndPointAddress & 0x80) != 0) {
+ Direction = EfiUsbDataIn;
+ } else {
+ Direction = EfiUsbDataOut;
+ }
+
+ Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EFI_OUT_OF_RESOURCES;
+ TDs = UhciCreateBulkOrIntTds (
+ Uhc,
+ DeviceAddress,
+ EndPointAddress,
+ PktId,
+ (UINT8 *)*Data,
+ DataPhy,
+ *DataLength,
+ DataToggle,
+ (UINT8) MaximumPacketLength,
+ FALSE
+ );
+
+ if (TDs == NULL) {
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
+ goto ON_EXIT;
+ }
+
+
+ //
+ // Link the TDs to bulk queue head. According to the platfore
+ // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
+ // to do full speed bandwidth reclamation or not.
+ //
+ BulkQh = Uhc->BulkQh;
+
+ UhciLinkTdToQh (Uhc, BulkQh, TDs);
+ Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
+ UhciUnlinkTdFromQh (BulkQh, TDs);
+
+ Uhc->PciIo->Flush (Uhc->PciIo);
+
+ *TransferResult = QhResult.Result;
+ *DataToggle = QhResult.NextToggle;
+ *DataLength = QhResult.Complete;
+
+ UhciDestoryTds (Uhc, TDs);
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Submits an asynchronous interrupt transfer to an
+ interrupt endpoint of a USB device according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and direction.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param IsNewTransfer If TRUE, submit a new transfer, if FALSE cancel old transfer.
+ @param DataToggle On input, data toggle to use; On output, next data toggle.
+ @param PollingInterval Interrupt poll rate in milliseconds.
+ @param DataLength On input, size of the data buffer, On output,
+ actually transferred data size.
+ @param Translator A pointr to the transaction translator data.
+ @param CallBackFunction Function to call periodically.
+ @param Context User context.
+
+ @return EFI_SUCCESS Transfer was submitted.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_OUT_OF_RESOURCES Failed due to a lack of resources.
+ @return EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2AsyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context
+ )
+{
+ USB_HC_DEV *Uhc;
+ BOOLEAN IsSlowDevice;
+ UHCI_QH_SW *Qh;
+ UHCI_TD_SW *IntTds;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINT8 *DataPtr;
+ UINT8 *DataPhy;
+ UINT8 PktId;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+ Qh = NULL;
+ IntTds = NULL;
+ DataPtr = NULL;
+ DataPhy = NULL;
+
+ IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
+
+ if ((EndPointAddress & 0x80) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete Async interrupt transfer request
+ //
+ if (!IsNewTransfer) {
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+ Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+ }
+
+ if (PollingInterval < 1 || PollingInterval > 255) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ UhciAckAllInterrupt (Uhc);
+
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((EndPointAddress & 0x80) == 0) {
+ PktId = OUTPUT_PACKET_ID;
+ } else {
+ PktId = INPUT_PACKET_ID;
+ }
+
+ //
+ // Allocate and map source data buffer for bus master access.
+ //
+ DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);
+
+ if (DataPtr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Uhc->MemPool, DataPtr, DataLength);
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ Qh = UhciCreateQh (Uhc, PollingInterval);
+
+ if (Qh == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_DATA;
+ }
+
+ IntTds = UhciCreateBulkOrIntTds (
+ Uhc,
+ DeviceAddress,
+ EndPointAddress,
+ PktId,
+ DataPtr,
+ DataPhy,
+ DataLength,
+ DataToggle,
+ (UINT8) MaximumPacketLength,
+ IsSlowDevice
+ );
+
+ if (IntTds == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto DESTORY_QH;
+ }
+
+ UhciLinkTdToQh (Uhc, Qh, IntTds);
+
+ //
+ // Save QH-TD structures to async Interrupt transfer list,
+ // for monitor interrupt transfer execution routine use.
+ //
+ Status = UhciCreateAsyncReq (
+ Uhc,
+ Qh,
+ IntTds,
+ DeviceAddress,
+ EndPointAddress,
+ DataLength,
+ PollingInterval,
+ DataPtr,
+ CallBackFunction,
+ Context,
+ IsSlowDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto DESTORY_QH;
+ }
+
+ UhciLinkQhToFrameList (Uhc, Qh);
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+DESTORY_QH:
+ UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
+
+FREE_DATA:
+ UsbHcFreeMem (Uhc->MemPool, DataPtr, DataLength);
+ Uhc->PciIo->Flush (Uhc->PciIo);
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device according to UEFI 2.0 spec.
+
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and direction.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param Data Array of pointers to the buffers of data.
+ @param DataLength On input, size of the data buffer, On output,
+ actually transferred data size.
+ @param DataToggle On input, data toggle to use; On output, next data toggle.
+ @param TimeOut Maximum time out, in microseconds.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult Variable to receive transfer result.
+
+ @return EFI_SUCCESS The transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT Failed due to timeout.
+ @return EFI_DEVICE_ERROR Failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2SyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ EFI_STATUS Status;
+ USB_HC_DEV *Uhc;
+ UHCI_TD_SW *TDs;
+ UHCI_QH_RESULT QhResult;
+ EFI_TPL OldTpl;
+ UINT8 *DataPhy;
+ VOID *DataMap;
+ UINT8 PktId;
+ BOOLEAN IsSlowDevice;
+
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+ DataPhy = NULL;
+ DataMap = NULL;
+ TDs = NULL;
+
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
+
+ if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsSlowDevice && (MaximumPacketLength > 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+
+ UhciAckAllInterrupt (Uhc);
+
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ return Status;
+ }
+
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);
+
+ //
+ // Map the source data buffer for bus master access.
+ // Create Tds list, then link it to the UHC's interrupt list
+ //
+ Status = UhciMapUserData (
+ Uhc,
+ EfiUsbDataIn,
+ Data,
+ DataLength,
+ &PktId,
+ &DataPhy,
+ &DataMap
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ TDs = UhciCreateBulkOrIntTds (
+ Uhc,
+ DeviceAddress,
+ EndPointAddress,
+ PktId,
+ (UINT8 *)Data,
+ DataPhy,
+ *DataLength,
+ DataToggle,
+ (UINT8) MaximumPacketLength,
+ IsSlowDevice
+ );
+
+ if (TDs == NULL) {
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+
+ UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
+
+ Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
+
+ UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
+ Uhc->PciIo->Flush (Uhc->PciIo);
+
+ *TransferResult = QhResult.Result;
+ *DataToggle = QhResult.NextToggle;
+ *DataLength = QhResult.Complete;
+
+ UhciDestoryTds (Uhc, TDs);
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and direction.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data.
+ @param DataLength On input, size of the data buffer, On output,
+ actually transferred data size.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult Variable to receive transfer result.
+
+ @return EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2IsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and direction.
+ @param DeviceSpeed Device speed.
+ @param MaximumPacketLength Maximum packet size of the target endpoint.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data.
+ @param DataLength On input, size of the data buffer, On output,
+ actually transferred data size.
+ @param Translator A pointr to the transaction translator data.
+ @param IsochronousCallBack Function to call when the transfer complete.
+ @param Context Pass to the call back function as parameter.
+
+ @return EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+Uhci2AsyncIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Driver is successfully loaded.
+ @return Others Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUhciDriverBinding,
+ ImageHandle,
+ &gUhciComponentName,
+ &gUhciComponentName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has UsbHcProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS OpenStatus;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_CLASSC UsbClassCReg;
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ OpenStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (OpenStatus)) {
+ return OpenStatus;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Test whether the controller belongs to UHCI type
+ //
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
+ (UsbClassCReg.ProgInterface != PCI_IF_UHCI)
+ ) {
+
+ Status = EFI_UNSUPPORTED;
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+
+}
+
+
+/**
+ Allocate and initialize the empty UHCI device.
+
+ @param PciIo The PCIIO to use.
+ @param DevicePath The device path of host controller.
+ @param OriginalPciAttributes The original PCI attributes.
+
+ @return Allocated UHCI device. If err, return NULL.
+
+**/
+USB_HC_DEV *
+UhciAllocateDev (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT64 OriginalPciAttributes
+ )
+{
+ USB_HC_DEV *Uhc;
+ EFI_STATUS Status;
+
+ Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
+
+ if (Uhc == NULL) {
+ return NULL;
+ }
+
+ //
+ // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
+ // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
+ //
+ Uhc->Signature = USB_HC_DEV_SIGNATURE;
+ Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
+ Uhc->Usb2Hc.Reset = Uhci2Reset;
+ Uhc->Usb2Hc.GetState = Uhci2GetState;
+ Uhc->Usb2Hc.SetState = Uhci2SetState;
+ Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
+ Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
+ Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
+ Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
+ Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
+ Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
+ Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
+ Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
+ Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
+ Uhc->Usb2Hc.MajorRevision = 0x1;
+ Uhc->Usb2Hc.MinorRevision = 0x1;
+
+ Uhc->PciIo = PciIo;
+ Uhc->DevicePath = DevicePath;
+ Uhc->OriginalPciAttributes = OriginalPciAttributes;
+ Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
+
+ if (Uhc->MemPool == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ InitializeListHead (&Uhc->AsyncIntList);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UhciMonitorAsyncReqList,
+ Uhc,
+ &Uhc->AsyncIntMonitor
+ );
+
+ if (EFI_ERROR (Status)) {
+ UsbHcFreeMemPool (Uhc->MemPool);
+ goto ON_ERROR;
+ }
+
+ return Uhc;
+
+ON_ERROR:
+ FreePool (Uhc);
+ return NULL;
+}
+
+
+/**
+ Free the UHCI device and release its associated resources.
+
+ @param Uhc The UHCI device to release.
+
+**/
+VOID
+UhciFreeDev (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ if (Uhc->AsyncIntMonitor != NULL) {
+ gBS->CloseEvent (Uhc->AsyncIntMonitor);
+ }
+
+ if (Uhc->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (Uhc->ExitBootServiceEvent);
+ }
+
+ if (Uhc->MemPool != NULL) {
+ UsbHcFreeMemPool (Uhc->MemPool);
+ }
+
+ if (Uhc->CtrlNameTable != NULL) {
+ FreeUnicodeStringTable (Uhc->CtrlNameTable);
+ }
+
+ FreePool (Uhc);
+}
+
+
+/**
+ Uninstall all Uhci Interface.
+
+ @param Controller Controller handle.
+ @param This Protocol instance pointer.
+
+**/
+VOID
+UhciCleanDevUp (
+ IN EFI_HANDLE Controller,
+ IN EFI_USB2_HC_PROTOCOL *This
+ )
+{
+ USB_HC_DEV *Uhc;
+ EFI_STATUS Status;
+
+ //
+ // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
+ //
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);
+
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ &Uhc->Usb2Hc
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
+ UhciFreeAllAsyncReq (Uhc);
+ UhciDestoryFrameList (Uhc);
+
+ //
+ // Restore original PCI attributes
+ //
+ Uhc->PciIo->Attributes (
+ Uhc->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Uhc->OriginalPciAttributes,
+ NULL
+ );
+
+ UhciFreeDev (Uhc);
+}
+
+/**
+ One notified function to stop the Host Controller when gBS->ExitBootServices() called.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+UhcExitBootService (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ USB_HC_DEV *Uhc;
+
+ Uhc = (USB_HC_DEV *) Context;
+
+ //
+ // Stop the Host Controller
+ //
+ UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
+
+ //
+ // Reset the Host Controller
+ //
+ UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
+ gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
+}
+
+/**
+ Starting the Usb UHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_HC_DEV *Uhc;
+ UINT64 Supports;
+ UINT64 OriginalPciAttributes;
+ BOOLEAN PciAttributesSaved;
+ EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
+
+ //
+ // Open PCIIO, then enable the EHC device and turn off emulation
+ //
+ Uhc = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open Device Path Protocol for on USB host controller
+ //
+ HcDevicePath = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &HcDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ PciAttributesSaved = FALSE;
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ PciAttributesSaved = TRUE;
+
+ //
+ // Robustnesss improvement such as for UoL
+ // Default is not required.
+ //
+ if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
+ UhciTurnOffUsbEmulation (PciIo);
+ }
+
+ 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 CLOSE_PCIIO;
+ }
+
+ Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);
+
+ if (Uhc == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CLOSE_PCIIO;
+ }
+
+ //
+ // Allocate and Init Host Controller's Frame List Entry
+ //
+ Status = UhciInitFrameList (Uhc);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_UHC;
+ }
+
+ Status = gBS->SetTimer (
+ Uhc->AsyncIntMonitor,
+ TimerPeriodic,
+ UHC_ASYNC_POLL_INTERVAL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_UHC;
+ }
+
+ //
+ // Install USB2_HC_PROTOCOL
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiUsb2HcProtocolGuid,
+ &Uhc->Usb2Hc,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_UHC;
+ }
+
+ //
+ // Create event to stop the HC when exit boot service.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UhcExitBootService,
+ Uhc,
+ &gEfiEventExitBootServicesGuid,
+ &Uhc->ExitBootServiceEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto UNINSTALL_USBHC;
+ }
+
+ //
+ // Install the component name protocol
+ //
+ Uhc->CtrlNameTable = NULL;
+
+ AddUnicodeString2 (
+ "eng",
+ gUhciComponentName.SupportedLanguages,
+ &Uhc->CtrlNameTable,
+ L"Usb Universal Host Controller",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gUhciComponentName2.SupportedLanguages,
+ &Uhc->CtrlNameTable,
+ L"Usb Universal Host Controller",
+ FALSE
+ );
+
+
+ //
+ // Start the UHCI hardware, also set its reclamation point to 64 bytes
+ //
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
+
+ return EFI_SUCCESS;
+
+UNINSTALL_USBHC:
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ &Uhc->Usb2Hc,
+ NULL
+ );
+
+FREE_UHC:
+ UhciFreeDev (Uhc);
+
+CLOSE_PCIIO:
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalPciAttributes,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ //
+ // Test whether the Controller handler passed in is a valid
+ // Usb controller handle that should be supported, if not,
+ // return the error status directly
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UhciCleanDevUp (Controller, Usb2Hc);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h
new file mode 100644
index 000000000..882f5e55e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h
@@ -0,0 +1,215 @@
+/** @file
+
+ The definition for UHCI driver model and HC protocol routines.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UHCI_H_
+#define _EFI_UHCI_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/Usb2HostController.h>
+#include <Protocol/UsbHostController.h>
+#include <Protocol/PciIo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+typedef struct _USB_HC_DEV USB_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "UhciQueue.h"
+#include "UhciReg.h"
+#include "UhciSched.h"
+#include "UhciDebug.h"
+#include "ComponentName.h"
+
+//
+// UHC timeout experience values
+//
+
+#define UHC_1_MICROSECOND 1
+#define UHC_1_MILLISECOND (1000 * UHC_1_MICROSECOND)
+#define UHC_1_SECOND (1000 * UHC_1_MILLISECOND)
+
+//
+// UHCI register operation timeout, set by experience
+//
+#define UHC_GENERIC_TIMEOUT UHC_1_SECOND
+
+//
+// Wait for force global resume(FGR) complete, refers to
+// specification[UHCI11-2.1.1]
+//
+#define UHC_FORCE_GLOBAL_RESUME_STALL (20 * UHC_1_MILLISECOND)
+
+//
+// Wait for roothub port reset and recovery, reset stall
+// is set by experience, and recovery stall refers to
+// specification[UHCI11-2.1.1]
+//
+#define UHC_ROOT_PORT_RESET_STALL (50 * UHC_1_MILLISECOND)
+#define UHC_ROOT_PORT_RECOVERY_STALL (10 * UHC_1_MILLISECOND)
+
+//
+// Sync and Async transfer polling interval, set by experience,
+// and the unit of Async is 100us.
+//
+#define UHC_SYNC_POLL_INTERVAL (1 * UHC_1_MILLISECOND)
+#define UHC_ASYNC_POLL_INTERVAL EFI_TIMER_PERIOD_MILLISECONDS(1)
+
+//
+// UHC raises TPL to TPL_NOTIFY to serialize all its operations
+// to protect shared data structures.
+//
+#define UHCI_TPL TPL_NOTIFY
+
+#define USB_HC_DEV_SIGNATURE SIGNATURE_32 ('u', 'h', 'c', 'i')
+
+#pragma pack(1)
+typedef struct {
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+#pragma pack()
+
+#define UHC_FROM_USB2_HC_PROTO(This) CR(This, USB_HC_DEV, Usb2Hc, USB_HC_DEV_SIGNATURE)
+
+//
+// USB_HC_DEV support the UHCI hardware controller. It schedules
+// the asynchronous interrupt transfer with the same method as
+// EHCI: a reversed tree structure. For synchronous interrupt,
+// control and bulk transfer, it uses three static queue head to
+// schedule them. SyncIntQh is for interrupt transfer. LsCtrlQh is
+// for LOW speed control transfer, and FsCtrlBulkQh is for FULL
+// speed control or bulk transfer. This is because FULL speed contrl
+// or bulk transfer can reclaim the unused bandwidth. Some USB
+// device requires this bandwidth reclamation capability.
+//
+struct _USB_HC_DEV {
+ UINT32 Signature;
+ EFI_USB2_HC_PROTOCOL Usb2Hc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT64 OriginalPciAttributes;
+
+ //
+ // Schedule data structures
+ //
+ UINT32 *FrameBase; // the buffer pointed by this pointer is used to store pci bus address of the QH descriptor.
+ UINT32 *FrameBaseHostAddr; // the buffer pointed by this pointer is used to store host memory address of the QH descriptor.
+ UHCI_QH_SW *SyncIntQh;
+ UHCI_QH_SW *CtrlQh;
+ UHCI_QH_SW *BulkQh;
+
+ //
+ // Structures to maintain asynchronus interrupt transfers.
+ // When asynchronous interrutp transfer is unlinked from
+ // the frame list, the hardware may still hold a pointer
+ // to it. To synchronize with hardware, its resoureces are
+ // released in two steps using Recycle and RecycleWait.
+ // Check the asynchronous interrupt management routines.
+ //
+ LIST_ENTRY AsyncIntList;
+ EFI_EVENT AsyncIntMonitor;
+ UHCI_ASYNC_REQUEST *Recycle;
+ UHCI_ASYNC_REQUEST *RecycleWait;
+
+
+ UINTN RootPorts;
+ USBHC_MEM_POOL *MemPool;
+ EFI_UNICODE_STRING_TABLE *CtrlNameTable;
+ VOID *FrameMapping;
+
+ //
+ // ExitBootServicesEvent is used to stop the EHC DMA operation
+ // after exit boot service.
+ //
+ EFI_EVENT ExitBootServiceEvent;
+};
+
+extern EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUhciComponentName2;
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has UsbHcProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the Usb UHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+UhciDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c
new file mode 100644
index 000000000..517780a5f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c
@@ -0,0 +1,71 @@
+/** @file
+
+ This file provides the information dump support for Uhci when in debug mode.
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+/**
+ Dump the content of QH structure.
+
+ @param QhSw Pointer to software QH structure.
+
+**/
+VOID
+UhciDumpQh (
+ IN UHCI_QH_SW *QhSw
+ )
+{
+ DEBUG ((EFI_D_VERBOSE, "&QhSw @ 0x%p\n", QhSw));
+ DEBUG ((EFI_D_VERBOSE, "QhSw.NextQh - 0x%p\n", QhSw->NextQh));
+ DEBUG ((EFI_D_VERBOSE, "QhSw.TDs - 0x%p\n", QhSw->TDs));
+ DEBUG ((EFI_D_VERBOSE, "QhSw.QhHw:\n"));
+ DEBUG ((EFI_D_VERBOSE, " Horizon Link - %x\n", QhSw->QhHw.HorizonLink));
+ DEBUG ((EFI_D_VERBOSE, " Vertical Link - %x\n\n", QhSw->QhHw.VerticalLink));
+}
+
+
+/**
+ Dump the content of TD structure.
+
+ @param TdSw Pointer to software TD structure.
+
+**/
+VOID
+UhciDumpTds (
+ IN UHCI_TD_SW *TdSw
+ )
+{
+ UHCI_TD_SW *CurTdSw;
+
+ CurTdSw = TdSw;
+
+ while (CurTdSw != NULL) {
+ DEBUG ((EFI_D_VERBOSE, "TdSw @ 0x%p\n", CurTdSw));
+ DEBUG ((EFI_D_VERBOSE, "TdSw.NextTd - 0x%p\n", CurTdSw->NextTd));
+ DEBUG ((EFI_D_VERBOSE, "TdSw.DataLen - %d\n", CurTdSw->DataLen));
+ DEBUG ((EFI_D_VERBOSE, "TdSw.Data - 0x%p\n", CurTdSw->Data));
+ DEBUG ((EFI_D_VERBOSE, "TdHw:\n"));
+ DEBUG ((EFI_D_VERBOSE, " NextLink - 0x%x\n", CurTdSw->TdHw.NextLink));
+ DEBUG ((EFI_D_VERBOSE, " ActualLen - %d\n", CurTdSw->TdHw.ActualLen));
+ DEBUG ((EFI_D_VERBOSE, " Status - 0x%x\n", CurTdSw->TdHw.Status));
+ DEBUG ((EFI_D_VERBOSE, " IOC - %d\n", CurTdSw->TdHw.IntOnCpl));
+ DEBUG ((EFI_D_VERBOSE, " IsIsoCh - %d\n", CurTdSw->TdHw.IsIsoch));
+ DEBUG ((EFI_D_VERBOSE, " LowSpeed - %d\n", CurTdSw->TdHw.LowSpeed));
+ DEBUG ((EFI_D_VERBOSE, " ErrorCount - %d\n", CurTdSw->TdHw.ErrorCount));
+ DEBUG ((EFI_D_VERBOSE, " ShortPacket - %d\n", CurTdSw->TdHw.ShortPacket));
+ DEBUG ((EFI_D_VERBOSE, " PidCode - 0x%x\n", CurTdSw->TdHw.PidCode));
+ DEBUG ((EFI_D_VERBOSE, " DevAddr - %d\n", CurTdSw->TdHw.DeviceAddr));
+ DEBUG ((EFI_D_VERBOSE, " EndPoint - %d\n", CurTdSw->TdHw.EndPoint));
+ DEBUG ((EFI_D_VERBOSE, " DataToggle - %d\n", CurTdSw->TdHw.DataToggle));
+ DEBUG ((EFI_D_VERBOSE, " MaxPacketLen - %d\n", CurTdSw->TdHw.MaxPacketLen));
+ DEBUG ((EFI_D_VERBOSE, " DataBuffer - 0x%x\n\n",CurTdSw->TdHw.DataBuffer));
+
+ CurTdSw = CurTdSw->NextTd;
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h
new file mode 100644
index 000000000..34f8ea1ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h
@@ -0,0 +1,41 @@
+/** @file
+
+ This file contains the definination for host controller debug support routines
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UHCI_DEBUG_H_
+#define _EFI_UHCI_DEBUG_H_
+
+
+/**
+ Dump the content of QH structure.
+
+ @param QhSw Pointer to software QH structure.
+
+ @return None.
+
+**/
+VOID
+UhciDumpQh (
+ IN UHCI_QH_SW *QhSw
+ );
+
+
+/**
+ Dump the content of TD structure.
+
+ @param TdSw Pointer to software TD structure.
+
+ @return None.
+
+**/
+VOID
+UhciDumpTds (
+ IN UHCI_TD_SW *TdSw
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
new file mode 100644
index 000000000..a5da1a912
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
@@ -0,0 +1,80 @@
+## @file
+# The UhciDxe driver is responsible for managing the behavior of UHCI controller.
+# It implements the interfaces of monitoring the status of all ports and transferring
+# Control, Bulk, Interrupt and Isochronous requests to Usb1.x device
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UhciDxe
+ MODULE_UNI_FILE = UhciDxe.uni
+ FILE_GUID = 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = UhciDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gUhciDriverBinding
+# COMPONENT_NAME = gUhciComponentName
+# COMPONENT_NAME2 = gUhciComponentName2
+#
+
+[Sources]
+ UhciSched.c
+ UhciDebug.c
+ UsbHcMem.h
+ UhciDebug.h
+ UhciQueue.c
+ UhciReg.c
+ UsbHcMem.c
+ UhciQueue.h
+ Uhci.c
+ Uhci.h
+ UhciReg.h
+ UhciSched.h
+ ComponentName.c
+ ComponentName.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport ## CONSUMES
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ ReportStatusCodeLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiUsb2HcProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UhciDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.uni
new file mode 100644
index 000000000..e6ee3c304
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The UhciDxe driver is responsible for managing the behavior of UHCI controller.
+//
+// It implements the interfaces of monitoring the status of all ports and transferring
+// Control, Bulk, Interrupt and Isochronous requests to Usb1.x device
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the behavior of the UHCI controller"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interfaces of monitoring the status of all ports and transferring Control, Bulk, Interrupt and Isochronous requests to a Usb1.x device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxeExtra.uni
new file mode 100644
index 000000000..47eaa236d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UhciDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UHCI DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c
new file mode 100644
index 000000000..fb97326dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c
@@ -0,0 +1,701 @@
+/** @file
+
+ The UHCI register operation routines.
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+/**
+ Map address of request structure buffer.
+
+ @param Uhc The UHCI device.
+ @param Request The user request buffer.
+ @param MappedAddr Mapped address of request.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user request.
+
+**/
+EFI_STATUS
+UhciMapUserRequest (
+ IN USB_HC_DEV *Uhc,
+ IN OUT VOID *Request,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ )
+{
+ EFI_STATUS Status;
+ UINTN Len;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ Status = Uhc->PciIo->Map (
+ Uhc->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ Request,
+ &Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (!EFI_ERROR (Status)) {
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ }
+
+ return Status;
+}
+
+
+/**
+ Map address of user data buffer.
+
+ @param Uhc The UHCI device.
+ @param Direction Direction of the data transfer.
+ @param Data The user data buffer.
+ @param Len Length of the user data.
+ @param PktId Packet identificaion.
+ @param MappedAddr Mapped address to return.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user data.
+
+**/
+EFI_STATUS
+UhciMapUserData (
+ IN USB_HC_DEV *Uhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN OUT UINTN *Len,
+ OUT UINT8 *PktId,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Status = EFI_SUCCESS;
+
+ switch (Direction) {
+ case EfiUsbDataIn:
+ //
+ // BusMasterWrite means cpu read
+ //
+ *PktId = INPUT_PACKET_ID;
+ Status = Uhc->PciIo->Map (
+ Uhc->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ Data,
+ Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ break;
+
+ case EfiUsbDataOut:
+ *PktId = OUTPUT_PACKET_ID;
+ Status = Uhc->PciIo->Map (
+ Uhc->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ Data,
+ Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ break;
+
+ case EfiUsbNoData:
+ if ((Len != NULL) && (*Len != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ *PktId = OUTPUT_PACKET_ID;
+ *MappedAddr = NULL;
+ *Map = NULL;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+EXIT:
+ return Status;
+}
+
+
+/**
+ Link the TD To QH.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head for the TD to link to.
+ @param Td The TD to link.
+
+**/
+VOID
+UhciLinkTdToQh (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td
+ )
+{
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Td, sizeof (UHCI_TD_HW));
+
+ ASSERT ((Qh != NULL) && (Td != NULL));
+
+ Qh->QhHw.VerticalLink = QH_VLINK (PhyAddr, FALSE);
+ Qh->TDs = (VOID *) Td;
+}
+
+
+/**
+ Unlink TD from the QH.
+
+ @param Qh The queue head to unlink from.
+ @param Td The TD to unlink.
+
+**/
+VOID
+UhciUnlinkTdFromQh (
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td
+ )
+{
+ ASSERT ((Qh != NULL) && (Td != NULL));
+
+ Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
+ Qh->TDs = NULL;
+}
+
+
+/**
+ Append a new TD To the previous TD.
+
+ @param Uhc The UHCI device.
+ @param PrevTd Previous UHCI_TD_SW to be linked to.
+ @param ThisTd TD to link.
+
+**/
+VOID
+UhciAppendTd (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_TD_SW *PrevTd,
+ IN UHCI_TD_SW *ThisTd
+ )
+{
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_HW));
+
+ ASSERT ((PrevTd != NULL) && (ThisTd != NULL));
+
+ PrevTd->TdHw.NextLink = TD_LINK (PhyAddr, TRUE, FALSE);
+ PrevTd->NextTd = (VOID *) ThisTd;
+}
+
+
+/**
+ Delete a list of TDs.
+
+ @param Uhc The UHCI device.
+ @param FirstTd TD link list head.
+
+ @return None.
+
+**/
+VOID
+UhciDestoryTds (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_TD_SW *FirstTd
+ )
+{
+ UHCI_TD_SW *NextTd;
+ UHCI_TD_SW *ThisTd;
+
+ NextTd = FirstTd;
+
+ while (NextTd != NULL) {
+ ThisTd = NextTd;
+ NextTd = ThisTd->NextTd;
+ UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));
+ }
+}
+
+
+/**
+ Create an initialize a new queue head.
+
+ @param Uhc The UHCI device.
+ @param Interval The polling interval for the queue.
+
+ @return The newly created queue header.
+
+**/
+UHCI_QH_SW *
+UhciCreateQh (
+ IN USB_HC_DEV *Uhc,
+ IN UINTN Interval
+ )
+{
+ UHCI_QH_SW *Qh;
+
+ Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));
+
+ if (Qh == NULL) {
+ return NULL;
+ }
+
+ Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE);
+ Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
+ Qh->Interval = UhciConvertPollRate(Interval);
+ Qh->TDs = NULL;
+ Qh->NextQh = NULL;
+
+ return Qh;
+}
+
+
+/**
+ Create and intialize a TD.
+
+ @param Uhc The UHCI device.
+
+ @return The newly allocated and initialized TD.
+
+**/
+UHCI_TD_SW *
+UhciCreateTd (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ UHCI_TD_SW *Td;
+
+ Td = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));
+ if (Td == NULL) {
+ return NULL;
+ }
+
+ Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);
+ Td->NextTd = NULL;
+ Td->Data = NULL;
+ Td->DataLen = 0;
+
+ return Td;
+}
+
+
+/**
+ Create and initialize a TD for Setup Stage of a control transfer.
+
+ @param Uhc The UHCI device.
+ @param DevAddr Device address.
+ @param Request A pointer to cpu memory address of Device request.
+ @param RequestPhy A pointer to pci memory address of Device request.
+ @param IsLow Full speed or low speed.
+
+ @return The created setup Td Pointer.
+
+**/
+UHCI_TD_SW *
+UhciCreateSetupTd (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 *Request,
+ IN UINT8 *RequestPhy,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_TD_SW *Td;
+
+ Td = UhciCreateTd (Uhc);
+
+ if (Td == NULL) {
+ return NULL;
+ }
+
+ Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
+ Td->TdHw.ShortPacket = FALSE;
+ Td->TdHw.IsIsoch = FALSE;
+ Td->TdHw.IntOnCpl = FALSE;
+ Td->TdHw.ErrorCount = 0x03;
+ Td->TdHw.Status |= USBTD_ACTIVE;
+ Td->TdHw.DataToggle = 0;
+ Td->TdHw.EndPoint = 0;
+ Td->TdHw.LowSpeed = IsLow ? 1 : 0;
+ Td->TdHw.DeviceAddr = DevAddr & 0x7F;
+ Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);
+ Td->TdHw.PidCode = SETUP_PACKET_ID;
+ Td->TdHw.DataBuffer = (UINT32) (UINTN) RequestPhy;
+
+ Td->Data = Request;
+ Td->DataLen = (UINT16) sizeof (EFI_USB_DEVICE_REQUEST);
+
+ return Td;
+}
+
+
+/**
+ Create a TD for data.
+
+ @param Uhc The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param DataPtr A pointer to cpu memory address of Data buffer.
+ @param DataPhyPtr A pointer to pci memory address of Data buffer.
+ @param Len Data length.
+ @param PktId Packet ID.
+ @param Toggle Data toggle value.
+ @param IsLow Full speed or low speed.
+
+ @return Data Td pointer if success, otherwise NULL.
+
+**/
+UHCI_TD_SW *
+UhciCreateDataTd (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 *DataPtr,
+ IN UINT8 *DataPhyPtr,
+ IN UINTN Len,
+ IN UINT8 PktId,
+ IN UINT8 Toggle,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_TD_SW *Td;
+
+ //
+ // Code as length - 1, and the max valid length is 0x500
+ //
+ ASSERT (Len <= 0x500);
+
+ Td = UhciCreateTd (Uhc);
+
+ if (Td == NULL) {
+ return NULL;
+ }
+
+ Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
+ Td->TdHw.ShortPacket = FALSE;
+ Td->TdHw.IsIsoch = FALSE;
+ Td->TdHw.IntOnCpl = FALSE;
+ Td->TdHw.ErrorCount = 0x03;
+ Td->TdHw.Status = USBTD_ACTIVE;
+ Td->TdHw.LowSpeed = IsLow ? 1 : 0;
+ Td->TdHw.DataToggle = Toggle & 0x01;
+ Td->TdHw.EndPoint = Endpoint & 0x0F;
+ Td->TdHw.DeviceAddr = DevAddr & 0x7F;
+ Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);
+ Td->TdHw.PidCode = (UINT8) PktId;
+ Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPhyPtr;
+
+ Td->Data = DataPtr;
+ Td->DataLen = (UINT16) Len;
+
+ return Td;
+}
+
+
+/**
+ Create TD for the Status Stage of control transfer.
+
+ @param Uhc The UHCI device.
+ @param DevAddr Device address.
+ @param PktId Packet ID.
+ @param IsLow Full speed or low speed.
+
+ @return Status Td Pointer.
+
+**/
+UHCI_TD_SW *
+UhciCreateStatusTd (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 PktId,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_TD_SW *Td;
+
+ Td = UhciCreateTd (Uhc);
+
+ if (Td == NULL) {
+ return NULL;
+ }
+
+ Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
+ Td->TdHw.ShortPacket = FALSE;
+ Td->TdHw.IsIsoch = FALSE;
+ Td->TdHw.IntOnCpl = FALSE;
+ Td->TdHw.ErrorCount = 0x03;
+ Td->TdHw.Status |= USBTD_ACTIVE;
+ Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
+ Td->TdHw.DataToggle = 1;
+ Td->TdHw.EndPoint = 0;
+ Td->TdHw.LowSpeed = IsLow ? 1 : 0;
+ Td->TdHw.DeviceAddr = DevAddr & 0x7F;
+ Td->TdHw.PidCode = (UINT8) PktId;
+ Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL;
+
+ Td->Data = NULL;
+ Td->DataLen = 0;
+
+ return Td;
+}
+
+
+/**
+ Create Tds list for Control Transfer.
+
+ @param Uhc The UHCI device.
+ @param DeviceAddr The device address.
+ @param DataPktId Packet Identification of Data Tds.
+ @param Request A pointer to cpu memory address of request structure buffer to transfer.
+ @param RequestPhy A pointer to pci memory address of request structure buffer to transfer.
+ @param Data A pointer to cpu memory address of user data buffer to transfer.
+ @param DataPhy A pointer to pci memory address of user data buffer to transfer.
+ @param DataLen Length of user data to transfer.
+ @param MaxPacket Maximum packet size for control transfer.
+ @param IsLow Full speed or low speed.
+
+ @return The Td list head for the control transfer.
+
+**/
+UHCI_TD_SW *
+UhciCreateCtrlTds (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DeviceAddr,
+ IN UINT8 DataPktId,
+ IN UINT8 *Request,
+ IN UINT8 *RequestPhy,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN UINT8 MaxPacket,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_TD_SW *SetupTd;
+ UHCI_TD_SW *FirstDataTd;
+ UHCI_TD_SW *DataTd;
+ UHCI_TD_SW *PrevDataTd;
+ UHCI_TD_SW *StatusTd;
+ UINT8 DataToggle;
+ UINT8 StatusPktId;
+ UINTN ThisTdLen;
+
+
+ DataTd = NULL;
+ SetupTd = NULL;
+ FirstDataTd = NULL;
+ PrevDataTd = NULL;
+ StatusTd = NULL;
+
+ //
+ // Create setup packets for the transfer
+ //
+ SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, RequestPhy, IsLow);
+
+ if (SetupTd == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create data packets for the transfer
+ //
+ DataToggle = 1;
+
+ while (DataLen > 0) {
+ //
+ // PktSize is the data load size in each Td.
+ //
+ ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);
+
+ DataTd = UhciCreateDataTd (
+ Uhc,
+ DeviceAddr,
+ 0,
+ Data, //cpu memory address
+ DataPhy, //Pci memory address
+ ThisTdLen,
+ DataPktId,
+ DataToggle,
+ IsLow
+ );
+
+ if (DataTd == NULL) {
+ goto FREE_TD;
+ }
+
+ if (FirstDataTd == NULL) {
+ FirstDataTd = DataTd;
+ FirstDataTd->NextTd = NULL;
+ } else {
+ UhciAppendTd (Uhc, PrevDataTd, DataTd);
+ }
+
+ DataToggle ^= 1;
+ PrevDataTd = DataTd;
+ Data += ThisTdLen;
+ DataPhy += ThisTdLen;
+ DataLen -= ThisTdLen;
+ }
+
+ //
+ // Status packet is on the opposite direction to data packets
+ //
+ if (OUTPUT_PACKET_ID == DataPktId) {
+ StatusPktId = INPUT_PACKET_ID;
+ } else {
+ StatusPktId = OUTPUT_PACKET_ID;
+ }
+
+ StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);
+
+ if (StatusTd == NULL) {
+ goto FREE_TD;
+ }
+
+ //
+ // Link setup Td -> data Tds -> status Td together
+ //
+ if (FirstDataTd != NULL) {
+ UhciAppendTd (Uhc, SetupTd, FirstDataTd);
+ UhciAppendTd (Uhc, PrevDataTd, StatusTd);
+ } else {
+ UhciAppendTd (Uhc, SetupTd, StatusTd);
+ }
+
+ return SetupTd;
+
+FREE_TD:
+ if (SetupTd != NULL) {
+ UhciDestoryTds (Uhc, SetupTd);
+ }
+
+ if (FirstDataTd != NULL) {
+ UhciDestoryTds (Uhc, FirstDataTd);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Create Tds list for Bulk/Interrupt Transfer.
+
+ @param Uhc USB_HC_DEV.
+ @param DevAddr Address of Device.
+ @param EndPoint Endpoint Number.
+ @param PktId Packet Identification of Data Tds.
+ @param Data A pointer to cpu memory address of user data buffer to transfer.
+ @param DataPhy A pointer to pci memory address of user data buffer to transfer.
+ @param DataLen Length of user data to transfer.
+ @param DataToggle Data Toggle Pointer.
+ @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.
+ @param IsLow Is Low Speed Device.
+
+ @return The Tds list head for the bulk transfer.
+
+**/
+UHCI_TD_SW *
+UhciCreateBulkOrIntTds (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ IN UINT8 PktId,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN OUT UINT8 *DataToggle,
+ IN UINT8 MaxPacket,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_TD_SW *DataTd;
+ UHCI_TD_SW *FirstDataTd;
+ UHCI_TD_SW *PrevDataTd;
+ UINTN ThisTdLen;
+
+ DataTd = NULL;
+ FirstDataTd = NULL;
+ PrevDataTd = NULL;
+
+ //
+ // Create data packets for the transfer
+ //
+ while (DataLen > 0) {
+ //
+ // PktSize is the data load size that each Td.
+ //
+ ThisTdLen = DataLen;
+
+ if (DataLen > MaxPacket) {
+ ThisTdLen = MaxPacket;
+ }
+
+ DataTd = UhciCreateDataTd (
+ Uhc,
+ DevAddr,
+ EndPoint,
+ Data,
+ DataPhy,
+ ThisTdLen,
+ PktId,
+ *DataToggle,
+ IsLow
+ );
+
+ if (DataTd == NULL) {
+ goto FREE_TD;
+ }
+
+ if (PktId == INPUT_PACKET_ID) {
+ DataTd->TdHw.ShortPacket = TRUE;
+ }
+
+ if (FirstDataTd == NULL) {
+ FirstDataTd = DataTd;
+ FirstDataTd->NextTd = NULL;
+ } else {
+ UhciAppendTd (Uhc, PrevDataTd, DataTd);
+ }
+
+ *DataToggle ^= 1;
+ PrevDataTd = DataTd;
+ Data += ThisTdLen;
+ DataPhy += ThisTdLen;
+ DataLen -= ThisTdLen;
+ }
+
+ return FirstDataTd;
+
+FREE_TD:
+ if (FirstDataTd != NULL) {
+ UhciDestoryTds (Uhc, FirstDataTd);
+ }
+
+ return NULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h
new file mode 100644
index 000000000..594ea28ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h
@@ -0,0 +1,266 @@
+/** @file
+
+ The definition for UHCI register operation routines.
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UHCI_QUEUE_H_
+#define _EFI_UHCI_QUEUE_H_
+
+//
+// Macroes used to set various links in UHCI's driver.
+// In this UHCI driver, QH's horizontal link always pointers to other QH,
+// and its vertical link always pointers to TD. TD's next pointer always
+// pointers to other sibling TD. Frame link always pointers to QH because
+// ISO transfer isn't supported.
+//
+// We should use UINT32 to access these pointers to void race conditions
+// with hardware.
+//
+#define QH_HLINK(Pointer, Terminate) \
+ (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | 0x02 | ((Terminate) ? 0x01 : 0))
+
+#define QH_VLINK(Pointer, Terminate) \
+ (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | ((Terminate) ? 0x01 : 0))
+
+#define TD_LINK(Pointer, VertFirst, Terminate) \
+ (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | \
+ ((VertFirst) ? 0x04 : 0) | ((Terminate) ? 0x01 : 0))
+
+#define LINK_TERMINATED(Link) (((Link) & 0x01) != 0)
+
+#define UHCI_ADDR(QhOrTd) ((VOID *) (UINTN) ((QhOrTd) & 0xFFFFFFF0))
+
+#pragma pack(1)
+//
+// Both links in QH has this internal structure:
+// Next pointer: 28, Reserved: 2, NextIsQh: 1, Terminate: 1
+// This is the same as frame list entry.
+//
+typedef struct {
+ UINT32 HorizonLink;
+ UINT32 VerticalLink;
+} UHCI_QH_HW;
+
+//
+// Next link in TD has this internal structure:
+// Next pointer: 28, Reserved: 1, Vertical First: 1, NextIsQh: 1, Terminate: 1
+//
+typedef struct {
+ UINT32 NextLink;
+ UINT32 ActualLen : 11;
+ UINT32 Reserved1 : 5;
+ UINT32 Status : 8;
+ UINT32 IntOnCpl : 1;
+ UINT32 IsIsoch : 1;
+ UINT32 LowSpeed : 1;
+ UINT32 ErrorCount : 2;
+ UINT32 ShortPacket : 1;
+ UINT32 Reserved2 : 2;
+ UINT32 PidCode : 8;
+ UINT32 DeviceAddr : 7;
+ UINT32 EndPoint : 4;
+ UINT32 DataToggle : 1;
+ UINT32 Reserved3 : 1;
+ UINT32 MaxPacketLen: 11;
+ UINT32 DataBuffer;
+} UHCI_TD_HW;
+#pragma pack()
+
+typedef struct _UHCI_TD_SW UHCI_TD_SW;
+typedef struct _UHCI_QH_SW UHCI_QH_SW;
+
+struct _UHCI_QH_SW {
+ UHCI_QH_HW QhHw;
+ UHCI_QH_SW *NextQh;
+ UHCI_TD_SW *TDs;
+ UINTN Interval;
+};
+
+struct _UHCI_TD_SW {
+ UHCI_TD_HW TdHw;
+ UHCI_TD_SW *NextTd;
+ UINT8 *Data;
+ UINT16 DataLen;
+};
+
+
+/**
+ Link the TD To QH.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head for the TD to link to.
+ @param Td The TD to link.
+
+**/
+VOID
+UhciLinkTdToQh (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td
+ );
+
+
+/**
+ Unlink TD from the QH.
+
+ @param Qh The queue head to unlink from.
+ @param Td The TD to unlink.
+
+ @return None.
+
+**/
+VOID
+UhciUnlinkTdFromQh (
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td
+ );
+
+
+/**
+ Map address of request structure buffer.
+
+ @param Uhc The UHCI device.
+ @param Request The user request buffer.
+ @param MappedAddr Mapped address of request.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user request.
+
+**/
+EFI_STATUS
+UhciMapUserRequest (
+ IN USB_HC_DEV *Uhc,
+ IN OUT VOID *Request,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ );
+
+
+/**
+ Map address of user data buffer.
+
+ @param Uhc The UHCI device.
+ @param Direction Direction of the data transfer.
+ @param Data The user data buffer.
+ @param Len Length of the user data.
+ @param PktId Packet identificaion.
+ @param MappedAddr Mapped address to return.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user data.
+
+**/
+EFI_STATUS
+UhciMapUserData (
+ IN USB_HC_DEV *Uhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN OUT UINTN *Len,
+ OUT UINT8 *PktId,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ );
+
+
+/**
+ Delete a list of TDs.
+
+ @param Uhc The UHCI device.
+ @param FirstTd TD link list head.
+
+ @return None.
+
+**/
+VOID
+UhciDestoryTds (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_TD_SW *FirstTd
+ );
+
+
+/**
+ Create an initialize a new queue head.
+
+ @param Uhc The UHCI device.
+ @param Interval The polling interval for the queue.
+
+ @return The newly created queue header.
+
+**/
+UHCI_QH_SW *
+UhciCreateQh (
+ IN USB_HC_DEV *Uhc,
+ IN UINTN Interval
+ );
+
+
+/**
+ Create Tds list for Control Transfer.
+
+ @param Uhc The UHCI device.
+ @param DeviceAddr The device address.
+ @param DataPktId Packet Identification of Data Tds.
+ @param Request A pointer to cpu memory address of request structure buffer to transfer.
+ @param RequestPhy A pointer to pci memory address of request structure buffer to transfer.
+ @param Data A pointer to cpu memory address of user data buffer to transfer.
+ @param DataPhy A pointer to pci memory address of user data buffer to transfer.
+ @param DataLen Length of user data to transfer.
+ @param MaxPacket Maximum packet size for control transfer.
+ @param IsLow Full speed or low speed.
+
+ @return The Td list head for the control transfer.
+
+**/
+UHCI_TD_SW *
+UhciCreateCtrlTds (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DeviceAddr,
+ IN UINT8 DataPktId,
+ IN UINT8 *Request,
+ IN UINT8 *RequestPhy,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN UINT8 MaxPacket,
+ IN BOOLEAN IsLow
+ );
+
+
+/**
+ Create Tds list for Bulk/Interrupt Transfer.
+
+ @param Uhc USB_HC_DEV.
+ @param DevAddr Address of Device.
+ @param EndPoint Endpoint Number.
+ @param PktId Packet Identification of Data Tds.
+ @param Data A pointer to cpu memory address of user data buffer to transfer.
+ @param DataPhy A pointer to pci memory address of user data buffer to transfer.
+ @param DataLen Length of user data to transfer.
+ @param DataToggle Data Toggle Pointer.
+ @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.
+ @param IsLow Is Low Speed Device.
+
+ @return The Tds list head for the bulk transfer.
+
+**/
+UHCI_TD_SW *
+UhciCreateBulkOrIntTds (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ IN UINT8 PktId,
+ IN UINT8 *Data,
+ IN UINT8 *DataPhy,
+ IN UINTN DataLen,
+ IN OUT UINT8 *DataToggle,
+ IN UINT8 MaxPacket,
+ IN BOOLEAN IsLow
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c
new file mode 100644
index 000000000..582c25e78
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c
@@ -0,0 +1,275 @@
+/** @file
+
+ The UHCI register operation routines.
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+/**
+ Read a UHCI register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+
+ @return Content of register.
+
+**/
+UINT16
+UhciReadReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ )
+{
+ UINT16 Data;
+ EFI_STATUS Status;
+
+ Status = PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_BAR_INDEX,
+ Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UhciReadReg: PciIo Io.Read error: %r at offset %d\n", Status, Offset));
+
+ Data = 0xFFFF;
+ }
+
+ return Data;
+}
+
+
+/**
+ Write data to UHCI register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Data Data to write.
+
+**/
+VOID
+UhciWriteReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_BAR_INDEX,
+ Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UhciWriteReg: PciIo Io.Write error: %r at offset %d\n", Status, Offset));
+ }
+}
+
+
+/**
+ Set a bit of the UHCI Register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Bit The bit to set.
+
+**/
+VOID
+UhciSetRegBit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Bit
+ )
+{
+ UINT16 Data;
+
+ Data = UhciReadReg (PciIo, Offset);
+ Data = (UINT16) (Data |Bit);
+ UhciWriteReg (PciIo, Offset, Data);
+}
+
+
+/**
+ Clear a bit of the UHCI Register.
+
+ @param PciIo The PCI_IO protocol to access the PCI.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Bit The bit to clear.
+
+**/
+VOID
+UhciClearRegBit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Bit
+ )
+{
+ UINT16 Data;
+
+ Data = UhciReadReg (PciIo, Offset);
+ Data = (UINT16) (Data & ~Bit);
+ UhciWriteReg (PciIo, Offset, Data);
+}
+
+
+/**
+ Clear all the interrutp status bits, these bits
+ are Write-Clean.
+
+ @param Uhc The UHCI device.
+
+**/
+VOID
+UhciAckAllInterrupt (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F);
+
+ //
+ // If current HC is halted, re-enable it. Host Controller Process Error
+ // is a temporary error status.
+ //
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ DEBUG ((EFI_D_ERROR, "UhciAckAllInterrupt: re-enable the UHCI from system error\n"));
+ Uhc->Usb2Hc.SetState (&Uhc->Usb2Hc, EfiUsbHcStateOperational);
+ }
+}
+
+
+/**
+ Stop the host controller.
+
+ @param Uhc The UHCI device.
+ @param Timeout Max time allowed.
+
+ @retval EFI_SUCCESS The host controller is stopped.
+ @retval EFI_TIMEOUT Failed to stop the host controller.
+
+**/
+EFI_STATUS
+UhciStopHc (
+ IN USB_HC_DEV *Uhc,
+ IN UINTN Timeout
+ )
+{
+ UINT16 UsbSts;
+ UINTN Index;
+
+ UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS);
+
+ //
+ // ensure the HC is in halt status after send the stop command
+ // Timeout is in us unit.
+ //
+ for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
+ UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
+
+ if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (50);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Check whether the host controller operates well.
+
+ @param PciIo The PCI_IO protocol to use.
+
+ @retval TRUE Host controller is working.
+ @retval FALSE Host controller is halted or system error.
+
+**/
+BOOLEAN
+UhciIsHcWorking (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT16 UsbSts;
+
+ UsbSts = UhciReadReg (PciIo, USBSTS_OFFSET);
+
+ if ((UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
+ DEBUG ((EFI_D_ERROR, "UhciIsHcWorking: current USB state is %x\n", UsbSts));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Set the UHCI frame list base address. It can't use
+ UhciWriteReg which access memory in UINT16.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Addr Address to set.
+
+**/
+VOID
+UhciSetFrameListBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN VOID *Addr
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ Data = (UINT32) ((UINTN) Addr & 0xFFFFF000);
+
+ Status = PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ USB_BAR_INDEX,
+ (UINT64) USB_FRAME_BASE_OFFSET,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status));
+ }
+}
+
+
+/**
+ Disable USB Emulation.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL protocol to use.
+
+**/
+VOID
+UhciTurnOffUsbEmulation (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT16 Command;
+
+ Command = 0;
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_EMULATION_OFFSET,
+ 1,
+ &Command
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h
new file mode 100644
index 000000000..b39dcbbbe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h
@@ -0,0 +1,242 @@
+/** @file
+
+ The definition for UHCI register operation routines.
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UHCI_REG_H_
+#define _EFI_UHCI_REG_H_
+
+//
+// UHCI register offset
+//
+
+#define UHCI_FRAME_NUM 1024
+
+//
+// Register offset and PCI related staff
+//
+#define USB_BAR_INDEX 4
+
+#define USBCMD_OFFSET 0
+#define USBSTS_OFFSET 2
+#define USBINTR_OFFSET 4
+#define USBPORTSC_OFFSET 0x10
+#define USB_FRAME_NO_OFFSET 6
+#define USB_FRAME_BASE_OFFSET 8
+#define USB_EMULATION_OFFSET 0xC0
+
+//
+// Packet IDs
+//
+#define SETUP_PACKET_ID 0x2D
+#define INPUT_PACKET_ID 0x69
+#define OUTPUT_PACKET_ID 0xE1
+#define ERROR_PACKET_ID 0x55
+
+//
+// USB port status and control bit definition.
+//
+#define USBPORTSC_CCS BIT0 // Current Connect Status
+#define USBPORTSC_CSC BIT1 // Connect Status Change
+#define USBPORTSC_PED BIT2 // Port Enable / Disable
+#define USBPORTSC_PEDC BIT3 // Port Enable / Disable Change
+#define USBPORTSC_LSL BIT4 // Line Status Low BIT
+#define USBPORTSC_LSH BIT5 // Line Status High BIT
+#define USBPORTSC_RD BIT6 // Resume Detect
+#define USBPORTSC_LSDA BIT8 // Low Speed Device Attached
+#define USBPORTSC_PR BIT9 // Port Reset
+#define USBPORTSC_SUSP BIT12 // Suspend
+
+//
+// UHCI Spec said it must implement 2 ports each host at least,
+// and if more, check whether the bit7 of PORTSC is always 1.
+// So here assume the max of port number each host is 16.
+//
+#define USB_MAX_ROOTHUB_PORT 0x0F
+
+//
+// Command register bit definitions
+//
+#define USBCMD_RS BIT0 // Run/Stop
+#define USBCMD_HCRESET BIT1 // Host reset
+#define USBCMD_GRESET BIT2 // Global reset
+#define USBCMD_EGSM BIT3 // Global Suspend Mode
+#define USBCMD_FGR BIT4 // Force Global Resume
+#define USBCMD_SWDBG BIT5 // SW Debug mode
+#define USBCMD_CF BIT6 // Config Flag (sw only)
+#define USBCMD_MAXP BIT7 // Max Packet (0 = 32, 1 = 64)
+
+//
+// USB Status register bit definitions
+//
+#define USBSTS_USBINT BIT0 // Interrupt due to IOC
+#define USBSTS_ERROR BIT1 // Interrupt due to error
+#define USBSTS_RD BIT2 // Resume Detect
+#define USBSTS_HSE BIT3 // Host System Error
+#define USBSTS_HCPE BIT4 // Host Controller Process Error
+#define USBSTS_HCH BIT5 // HC Halted
+
+#define USBTD_ACTIVE BIT7 // TD is still active
+#define USBTD_STALLED BIT6 // TD is stalled
+#define USBTD_BUFFERR BIT5 // Buffer underflow or overflow
+#define USBTD_BABBLE BIT4 // Babble condition
+#define USBTD_NAK BIT3 // NAK is received
+#define USBTD_CRC BIT2 // CRC/Time out error
+#define USBTD_BITSTUFF BIT1 // Bit stuff error
+
+
+/**
+ Read a UHCI register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+
+ @return Content of register.
+
+**/
+UINT16
+UhciReadReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ );
+
+
+
+/**
+ Write data to UHCI register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Data Data to write.
+
+ @return None.
+
+**/
+VOID
+UhciWriteReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Data
+ );
+
+
+
+/**
+ Set a bit of the UHCI Register.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Bit The bit to set.
+
+ @return None.
+
+**/
+VOID
+UhciSetRegBit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Bit
+ );
+
+
+
+/**
+ Clear a bit of the UHCI Register.
+
+ @param PciIo The PCI_IO protocol to access the PCI.
+ @param Offset Register offset to USB_BAR_INDEX.
+ @param Bit The bit to clear.
+
+ @return None.
+
+**/
+VOID
+UhciClearRegBit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT16 Bit
+ );
+
+
+/**
+ Clear all the interrutp status bits, these bits
+ are Write-Clean.
+
+ @param Uhc The UHCI device.
+
+ @return None.
+
+**/
+VOID
+UhciAckAllInterrupt (
+ IN USB_HC_DEV *Uhc
+ );
+
+
+/**
+ Stop the host controller.
+
+ @param Uhc The UHCI device.
+ @param Timeout Max time allowed.
+
+ @retval EFI_SUCCESS The host controller is stopped.
+ @retval EFI_TIMEOUT Failed to stop the host controller.
+
+**/
+EFI_STATUS
+UhciStopHc (
+ IN USB_HC_DEV *Uhc,
+ IN UINTN Timeout
+ );
+
+
+
+/**
+ Check whether the host controller operates well.
+
+ @param PciIo The PCI_IO protocol to use.
+
+ @retval TRUE Host controller is working.
+ @retval FALSE Host controller is halted or system error.
+
+**/
+BOOLEAN
+UhciIsHcWorking (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+
+
+/**
+ Set the UHCI frame list base address. It can't use
+ UhciWriteReg which access memory in UINT16.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL to use.
+ @param Addr Address to set.
+
+ @return None.
+
+**/
+VOID
+UhciSetFrameListBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN VOID *Addr
+ );
+
+
+/**
+ Disable USB Emulation.
+
+ @param PciIo The EFI_PCI_IO_PROTOCOL protocol to use.
+
+ @return None.
+
+**/
+VOID
+UhciTurnOffUsbEmulation (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c
new file mode 100644
index 000000000..e21641884
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c
@@ -0,0 +1,1040 @@
+/** @file
+
+ The EHCI register operation routines.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+/**
+ Create Frame List Structure.
+
+ @param Uhc UHCI device.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_UNSUPPORTED Map memory fail.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+UhciInitFrameList (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ VOID *Buffer;
+ VOID *Mapping;
+ UINTN Pages;
+ UINTN Bytes;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ //
+ // The Frame List is a common buffer that will be
+ // accessed by both the cpu and the usb bus master
+ // at the same time. The Frame List ocupies 4K bytes,
+ // and must be aligned on 4-Kbyte boundaries.
+ //
+ Bytes = 4096;
+ Pages = EFI_SIZE_TO_PAGES (Bytes);
+
+ Status = Uhc->PciIo->AllocateBuffer (
+ Uhc->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &Buffer,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Uhc->PciIo->Map (
+ Uhc->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buffer,
+ &Bytes,
+ &MappedAddr,
+ &Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != 4096)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ Uhc->FrameBase = (UINT32 *) (UINTN) Buffer;
+ Uhc->FrameMapping = Mapping;
+
+ //
+ // Tell the Host Controller where the Frame List lies,
+ // by set the Frame List Base Address Register.
+ //
+ UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (UINTN) MappedAddr);
+
+ //
+ // Allocate the QH used by sync interrupt/control/bulk transfer.
+ // FS ctrl/bulk queue head is set to loopback so additional BW
+ // can be reclaimed. Notice, LS don't support bulk transfer and
+ // also doesn't support BW reclamation.
+ //
+ Uhc->SyncIntQh = UhciCreateQh (Uhc, 1);
+ Uhc->CtrlQh = UhciCreateQh (Uhc, 1);
+ Uhc->BulkQh = UhciCreateQh (Uhc, 1);
+
+ if ((Uhc->SyncIntQh == NULL) || (Uhc->CtrlQh == NULL) || (Uhc->BulkQh == NULL)) {
+ Uhc->PciIo->Unmap (Uhc->PciIo, Mapping);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // +-------------+
+ // | |
+ // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+
+ // Each frame entry is linked to this sequence of QH. These QH
+ // will remain on the schedul, never got removed
+ //
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_HW));
+ Uhc->SyncIntQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE);
+ Uhc->SyncIntQh->NextQh = Uhc->CtrlQh;
+
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_HW));
+ Uhc->CtrlQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE);
+ Uhc->CtrlQh->NextQh = Uhc->BulkQh;
+
+ //
+ // Some old platform such as Intel's Tiger 4 has a difficult time
+ // in supporting the full speed bandwidth reclamation in the previous
+ // mentioned form. Most new platforms don't suffer it.
+ //
+ Uhc->BulkQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE);
+
+ Uhc->BulkQh->NextQh = NULL;
+
+ Uhc->FrameBaseHostAddr = AllocateZeroPool (4096);
+ if (Uhc->FrameBaseHostAddr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_HW));
+ for (Index = 0; Index < UHCI_FRAME_NUM; Index++) {
+ Uhc->FrameBase[Index] = QH_HLINK (PhyAddr, FALSE);
+ Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Uhc->SyncIntQh;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ if (Uhc->SyncIntQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));
+ }
+
+ if (Uhc->CtrlQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));
+ }
+
+ if (Uhc->BulkQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));
+ }
+
+ Uhc->PciIo->FreeBuffer (Uhc->PciIo, Pages, Buffer);
+ return Status;
+}
+
+
+/**
+ Destory FrameList buffer.
+
+ @param Uhc The UHCI device.
+
+**/
+VOID
+UhciDestoryFrameList (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ //
+ // Unmap the common buffer for framelist entry,
+ // and free the common buffer.
+ // Uhci's frame list occupy 4k memory.
+ //
+ Uhc->PciIo->Unmap (Uhc->PciIo, Uhc->FrameMapping);
+
+ Uhc->PciIo->FreeBuffer (
+ Uhc->PciIo,
+ EFI_SIZE_TO_PAGES (4096),
+ (VOID *) Uhc->FrameBase
+ );
+
+ if (Uhc->FrameBaseHostAddr != NULL) {
+ FreePool (Uhc->FrameBaseHostAddr);
+ }
+
+ if (Uhc->SyncIntQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));
+ }
+
+ if (Uhc->CtrlQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));
+ }
+
+ if (Uhc->BulkQh != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));
+ }
+
+ Uhc->FrameBase = NULL;
+ Uhc->FrameBaseHostAddr = NULL;
+ Uhc->SyncIntQh = NULL;
+ Uhc->CtrlQh = NULL;
+ Uhc->BulkQh = NULL;
+}
+
+
+/**
+ Convert the poll rate to the maxium 2^n that is smaller
+ than Interval.
+
+ @param Interval The poll rate to convert.
+
+ @return The converted poll rate.
+
+**/
+UINTN
+UhciConvertPollRate (
+ IN UINTN Interval
+ )
+{
+ UINTN BitCount;
+
+ ASSERT (Interval != 0);
+
+ //
+ // Find the index (1 based) of the highest non-zero bit
+ //
+ BitCount = 0;
+
+ while (Interval != 0) {
+ Interval >>= 1;
+ BitCount++;
+ }
+
+ return (UINTN)1 << (BitCount - 1);
+}
+
+
+/**
+ Link a queue head (for asynchronous interrupt transfer) to
+ the frame list.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head to link into.
+
+**/
+VOID
+UhciLinkQhToFrameList (
+ USB_HC_DEV *Uhc,
+ UHCI_QH_SW *Qh
+ )
+{
+ UINTN Index;
+ UHCI_QH_SW *Prev;
+ UHCI_QH_SW *Next;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ EFI_PHYSICAL_ADDRESS QhPciAddr;
+
+ ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL));
+
+ QhPciAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_HW));
+
+ for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {
+ //
+ // First QH can't be NULL because we always keep static queue
+ // heads on the frame list
+ //
+ ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index]));
+ Next = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index];
+ Prev = NULL;
+
+ //
+ // Now, insert the queue head (Qh) into this frame:
+ // 1. Find a queue head with the same poll interval, just insert
+ // Qh after this queue head, then we are done.
+ //
+ // 2. Find the position to insert the queue head into:
+ // Previous head's interval is bigger than Qh's
+ // Next head's interval is less than Qh's
+ // Then, insert the Qh between then
+ //
+ // This method is very much the same as that used by EHCI.
+ // Because each QH's interval is round down to 2^n, poll
+ // rate is correct.
+ //
+ while (Next->Interval > Qh->Interval) {
+ Prev = Next;
+ Next = Next->NextQh;
+ ASSERT (Next != NULL);
+ }
+
+ //
+ // The entry may have been linked into the frame by early insertation.
+ // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
+ // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
+ // It isn't necessary to compare all the QH with the same interval to
+ // Qh. This is because if there is other QH with the same interval, Qh
+ // should has been inserted after that at FrameBase[0] and at FrameBase[0] it is
+ // impossible (Next == Qh)
+ //
+ if (Next == Qh) {
+ continue;
+ }
+
+ if (Next->Interval == Qh->Interval) {
+ //
+ // If there is a QH with the same interval, it locates at
+ // FrameBase[0], and we can simply insert it after this QH. We
+ // are all done.
+ //
+ ASSERT ((Index == 0) && (Qh->NextQh == NULL));
+
+ Prev = Next;
+ Next = Next->NextQh;
+
+ Qh->NextQh = Next;
+ Prev->NextQh = Qh;
+
+ Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;
+
+ Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE);
+ break;
+ }
+
+ //
+ // OK, find the right position, insert it in. If Qh's next
+ // link has already been set, it is in position. This is
+ // guarranted by 2^n polling interval.
+ //
+ if (Qh->NextQh == NULL) {
+ Qh->NextQh = Next;
+ PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Next, sizeof (UHCI_QH_HW));
+ Qh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE);
+ }
+
+ if (Prev == NULL) {
+ Uhc->FrameBase[Index] = QH_HLINK (QhPciAddr, FALSE);
+ Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh;
+ } else {
+ Prev->NextQh = Qh;
+ Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE);
+ }
+ }
+}
+
+
+/**
+ Unlink QH from the frame list is easier: find all
+ the precedence node, and pointer there next to QhSw's
+ next.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+UhciUnlinkQhFromFrameList (
+ USB_HC_DEV *Uhc,
+ UHCI_QH_SW *Qh
+ )
+{
+ UINTN Index;
+ UHCI_QH_SW *Prev;
+ UHCI_QH_SW *This;
+
+ ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL));
+
+ for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {
+ //
+ // Frame link can't be NULL because we always keep static
+ // queue heads on the frame list
+ //
+ ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index]));
+ This = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index];
+ Prev = NULL;
+
+ //
+ // Walk through the frame's QH list to find the
+ // queue head to remove
+ //
+ while ((This != NULL) && (This != Qh)) {
+ Prev = This;
+ This = This->NextQh;
+ }
+
+ //
+ // Qh may have already been unlinked from this frame
+ // by early action.
+ //
+ if (This == NULL) {
+ continue;
+ }
+
+ if (Prev == NULL) {
+ //
+ // Qh is the first entry in the frame
+ //
+ Uhc->FrameBase[Index] = Qh->QhHw.HorizonLink;
+ Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh->NextQh;
+ } else {
+ Prev->NextQh = Qh->NextQh;
+ Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;
+ }
+ }
+}
+
+
+/**
+ Check TDs Results.
+
+ @param Uhc This UHCI device.
+ @param Td UHCI_TD_SW to check.
+ @param IsLow Is Low Speed Device.
+ @param QhResult Return the result of this TD list.
+
+ @return Whether the TD's result is finialized.
+
+**/
+BOOLEAN
+UhciCheckTdStatus (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_TD_SW *Td,
+ IN BOOLEAN IsLow,
+ OUT UHCI_QH_RESULT *QhResult
+ )
+{
+ UINTN Len;
+ UINT8 State;
+ UHCI_TD_HW *TdHw;
+ BOOLEAN Finished;
+
+ Finished = TRUE;
+
+ //
+ // Initialize the data toggle to that of the first
+ // TD. The next toggle to use is either:
+ // 1. first TD's toggle if no TD is executed OK
+ // 2. the next toggle of last executed-OK TD
+ //
+ QhResult->Result = EFI_USB_NOERROR;
+ QhResult->NextToggle = (UINT8)Td->TdHw.DataToggle;
+ QhResult->Complete = 0;
+
+ while (Td != NULL) {
+ TdHw = &Td->TdHw;
+ State = (UINT8)TdHw->Status;
+
+ //
+ // UHCI will set STALLED bit when it abort the execution
+ // of TD list. There are several reasons:
+ // 1. BABBLE error happened
+ // 2. Received a STALL response
+ // 3. Error count decreased to zero.
+ //
+ // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error
+ // bits when corresponding conditions happen. But these
+ // conditions are not deadly, that is a TD can successfully
+ // completes even these bits are set. But it is likely that
+ // upper layer won't distinguish these condtions. So, only
+ // set these bits when TD is actually halted.
+ //
+ if ((State & USBTD_STALLED) != 0) {
+ if ((State & USBTD_BABBLE) != 0) {
+ QhResult->Result |= EFI_USB_ERR_BABBLE;
+
+ } else if (TdHw->ErrorCount != 0) {
+ QhResult->Result |= EFI_USB_ERR_STALL;
+ }
+
+ if ((State & USBTD_CRC) != 0) {
+ QhResult->Result |= EFI_USB_ERR_CRC;
+ }
+
+ if ((State & USBTD_BUFFERR) != 0) {
+ QhResult->Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if ((Td->TdHw.Status & USBTD_BITSTUFF) != 0) {
+ QhResult->Result |= EFI_USB_ERR_BITSTUFF;
+ }
+
+ if (TdHw->ErrorCount == 0) {
+ QhResult->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ Finished = TRUE;
+ goto ON_EXIT;
+
+ } else if ((State & USBTD_ACTIVE) != 0) {
+ //
+ // The TD is still active, no need to check further.
+ //
+ QhResult->Result |= EFI_USB_ERR_NOTEXECUTE;
+
+ Finished = FALSE;
+ goto ON_EXIT;
+
+ } else {
+ //
+ // Update the next data toggle, it is always the
+ // next to the last known-good TD's data toggle if
+ // any TD is executed OK
+ //
+ QhResult->NextToggle = (UINT8) (1 - (UINT8)TdHw->DataToggle);
+
+ //
+ // This TD is finished OK or met short packet read. Update the
+ // transfer length if it isn't a SETUP.
+ //
+ Len = (TdHw->ActualLen + 1) & 0x7FF;
+
+ if (TdHw->PidCode != SETUP_PACKET_ID) {
+ QhResult->Complete += Len;
+ }
+
+ //
+ // Short packet condition for full speed input TD, also
+ // terminate the transfer
+ //
+ if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) {
+ DEBUG ((DEBUG_VERBOSE, "UhciCheckTdStatus: short packet read occurred\n"));
+
+ Finished = TRUE;
+ goto ON_EXIT;
+ }
+ }
+
+ Td = Td->NextTd;
+ }
+
+ON_EXIT:
+ //
+ // Check whether HC is halted. Don't move this up. It must be
+ // called after data toggle is successfully updated.
+ //
+ if (!UhciIsHcWorking (Uhc->PciIo)) {
+ QhResult->Result |= EFI_USB_ERR_SYSTEM;
+ Finished = TRUE;
+ }
+
+ if (Finished) {
+ Uhc->PciIo->Flush (Uhc->PciIo);
+ }
+
+ UhciAckAllInterrupt (Uhc);
+ return Finished;
+}
+
+
+/**
+ Check the result of the transfer.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head of the transfer.
+ @param Td The first TDs of the transfer.
+ @param TimeOut TimeOut value in milliseconds.
+ @param IsLow Is Low Speed Device.
+ @param QhResult The variable to return result.
+
+ @retval EFI_SUCCESS The transfer finished with success.
+ @retval EFI_DEVICE_ERROR Transfer failed.
+
+**/
+EFI_STATUS
+UhciExecuteTransfer (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td,
+ IN UINTN TimeOut,
+ IN BOOLEAN IsLow,
+ OUT UHCI_QH_RESULT *QhResult
+ )
+{
+ UINTN Index;
+ UINTN Delay;
+ BOOLEAN Finished;
+ EFI_STATUS Status;
+ BOOLEAN InfiniteLoop;
+
+ Finished = FALSE;
+ Status = EFI_SUCCESS;
+ Delay = TimeOut * UHC_1_MILLISECOND;
+ InfiniteLoop = FALSE;
+
+ //
+ // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
+ // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
+ // is returned.
+ //
+ if (TimeOut == 0) {
+ InfiniteLoop = TRUE;
+ }
+
+ for (Index = 0; InfiniteLoop || (Index < Delay); Index++) {
+ Finished = UhciCheckTdStatus (Uhc, Td, IsLow, QhResult);
+
+ //
+ // Transfer is OK or some error occurred (TD inactive)
+ //
+ if (Finished) {
+ break;
+ }
+
+ gBS->Stall (UHC_1_MICROSECOND);
+ }
+
+ if (!Finished) {
+ DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution not finished for %dms\n", (UINT32)TimeOut));
+ UhciDumpQh (Qh);
+ UhciDumpTds (Td);
+
+ Status = EFI_TIMEOUT;
+
+ } else if (QhResult->Result != EFI_USB_NOERROR) {
+ DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution failed with result %x\n", QhResult->Result));
+ UhciDumpQh (Qh);
+ UhciDumpTds (Td);
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ Update Async Request, QH and TDs.
+
+ @param Uhc The UHCI device.
+ @param AsyncReq The UHCI asynchronous transfer to update.
+ @param Result Transfer reslut.
+ @param NextToggle The toggle of next data.
+
+**/
+VOID
+UhciUpdateAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_ASYNC_REQUEST *AsyncReq,
+ IN UINT32 Result,
+ IN UINT32 NextToggle
+ )
+{
+ UHCI_QH_SW *Qh;
+ UHCI_TD_SW *FirstTd;
+ UHCI_TD_SW *Td;
+
+ Qh = AsyncReq->QhSw;
+ FirstTd = AsyncReq->FirstTd;
+
+ if (Result == EFI_USB_NOERROR) {
+ //
+ // The last transfer succeeds. Then we need to update
+ // the Qh and Td for next round of transfer.
+ // 1. Update the TD's data toggle
+ // 2. Activate all the TDs
+ // 3. Link the TD to the queue head again since during
+ // execution, queue head's TD pointer is changed by
+ // hardware.
+ //
+ for (Td = FirstTd; Td != NULL; Td = Td->NextTd) {
+ Td->TdHw.DataToggle = NextToggle;
+ NextToggle ^= 1;
+ Td->TdHw.Status |= USBTD_ACTIVE;
+ }
+
+ UhciLinkTdToQh (Uhc, Qh, FirstTd);
+ return ;
+ }
+}
+
+
+/**
+ Create Async Request node, and Link to List.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head of the transfer.
+ @param FirstTd First TD of the transfer.
+ @param DevAddr Device Address.
+ @param EndPoint EndPoint Address.
+ @param DataLen Data length.
+ @param Interval Polling Interval when inserted to frame list.
+ @param Data Data buffer, unmapped.
+ @param Callback Callback after interrupt transfeer.
+ @param Context Callback Context passed as function parameter.
+ @param IsLow Is Low Speed.
+
+ @retval EFI_SUCCESS An asynchronous transfer is created.
+ @retval EFI_INVALID_PARAMETER Paremeter is error.
+ @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage.
+
+**/
+EFI_STATUS
+UhciCreateAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *FirstTd,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ IN UINTN DataLen,
+ IN UINTN Interval,
+ IN UINT8 *Data,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN BOOLEAN IsLow
+ )
+{
+ UHCI_ASYNC_REQUEST *AsyncReq;
+
+ AsyncReq = AllocatePool (sizeof (UHCI_ASYNC_REQUEST));
+
+ if (AsyncReq == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill Request field. Data is allocated host memory, not mapped
+ //
+ AsyncReq->Signature = UHCI_ASYNC_INT_SIGNATURE;
+ AsyncReq->DevAddr = DevAddr;
+ AsyncReq->EndPoint = EndPoint;
+ AsyncReq->DataLen = DataLen;
+ AsyncReq->Interval = UhciConvertPollRate(Interval);
+ AsyncReq->Data = Data;
+ AsyncReq->Callback = Callback;
+ AsyncReq->Context = Context;
+ AsyncReq->QhSw = Qh;
+ AsyncReq->FirstTd = FirstTd;
+ AsyncReq->IsLow = IsLow;
+
+ //
+ // Insert the new interrupt transfer to the head of the list.
+ // The interrupt transfer's monitor function scans the whole
+ // list from head to tail. The new interrupt transfer MUST be
+ // added to the head of the list.
+ //
+ InsertHeadList (&(Uhc->AsyncIntList), &(AsyncReq->Link));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Free an asynchronous request's resource such as memory.
+
+ @param Uhc The UHCI device.
+ @param AsyncReq The asynchronous request to free.
+
+**/
+VOID
+UhciFreeAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_ASYNC_REQUEST *AsyncReq
+ )
+{
+ ASSERT ((Uhc != NULL) && (AsyncReq != NULL));
+
+ UhciDestoryTds (Uhc, AsyncReq->FirstTd);
+ UsbHcFreeMem (Uhc->MemPool, AsyncReq->QhSw, sizeof (UHCI_QH_SW));
+
+ if (AsyncReq->Data != NULL) {
+ UsbHcFreeMem (Uhc->MemPool, AsyncReq->Data, AsyncReq->DataLen);
+ }
+
+ gBS->FreePool (AsyncReq);
+}
+
+
+/**
+ Unlink an asynchronous request's from UHC's asynchronus list.
+ also remove the queue head from the frame list. If FreeNow,
+ release its resource also. Otherwise, add the request to the
+ UHC's recycle list to wait for a while before release the memory.
+ Until then, hardware won't hold point to the request.
+
+ @param Uhc The UHCI device.
+ @param AsyncReq The asynchronous request to free.
+ @param FreeNow If TRUE, free the resource immediately, otherwise
+ add the request to recycle wait list.
+
+**/
+VOID
+UhciUnlinkAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_ASYNC_REQUEST *AsyncReq,
+ IN BOOLEAN FreeNow
+ )
+{
+ ASSERT ((Uhc != NULL) && (AsyncReq != NULL));
+
+ RemoveEntryList (&(AsyncReq->Link));
+ UhciUnlinkQhFromFrameList (Uhc, AsyncReq->QhSw);
+
+ if (FreeNow) {
+ UhciFreeAsyncReq (Uhc, AsyncReq);
+ } else {
+ //
+ // To sychronize with hardware, mark the queue head as inactive
+ // then add AsyncReq to UHC's recycle list
+ //
+ AsyncReq->QhSw->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
+ AsyncReq->Recycle = Uhc->RecycleWait;
+ Uhc->RecycleWait = AsyncReq;
+ }
+}
+
+
+/**
+ Delete Async Interrupt QH and TDs.
+
+ @param Uhc The UHCI device.
+ @param DevAddr Device Address.
+ @param EndPoint EndPoint Address.
+ @param Toggle The next data toggle to use.
+
+ @retval EFI_SUCCESS The request is deleted.
+ @retval EFI_INVALID_PARAMETER Paremeter is error.
+ @retval EFI_NOT_FOUND The asynchronous isn't found.
+
+**/
+EFI_STATUS
+UhciRemoveAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ OUT UINT8 *Toggle
+ )
+{
+ EFI_STATUS Status;
+ UHCI_ASYNC_REQUEST *AsyncReq;
+ UHCI_QH_RESULT QhResult;
+ LIST_ENTRY *Link;
+ BOOLEAN Found;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // If no asynchronous interrupt transaction exists
+ //
+ if (IsListEmpty (&(Uhc->AsyncIntList))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find the asynchronous transfer to this device/endpoint pair
+ //
+ Found = FALSE;
+ Link = Uhc->AsyncIntList.ForwardLink;
+
+ do {
+ AsyncReq = UHCI_ASYNC_INT_FROM_LINK (Link);
+ Link = Link->ForwardLink;
+
+ if ((AsyncReq->DevAddr == DevAddr) && (AsyncReq->EndPoint == EndPoint)) {
+ Found = TRUE;
+ break;
+ }
+
+ } while (Link != &(Uhc->AsyncIntList));
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check the result of the async transfer then update it
+ // to get the next data toggle to use.
+ //
+ UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);
+ *Toggle = QhResult.NextToggle;
+
+ //
+ // Don't release the request now, keep it to synchronize with hardware.
+ //
+ UhciUnlinkAsyncReq (Uhc, AsyncReq, FALSE);
+ return Status;
+}
+
+
+/**
+ Recycle the asynchronouse request. When a queue head
+ is unlinked from frame list, host controller hardware
+ may still hold a cached pointer to it. To synchronize
+ with hardware, the request is released in two steps:
+ first it is linked to the UHC's RecycleWait list. At
+ the next time UhciMonitorAsyncReqList is fired, it is
+ moved to UHC's Recylelist. Then, at another timer
+ activation, all the requests on Recycle list is freed.
+ This guarrantes that each unlink queue head keeps
+ existing for at least 50ms, far enough for the hardware
+ to clear its cache.
+
+ @param Uhc The UHCI device.
+
+**/
+VOID
+UhciRecycleAsyncReq (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ UHCI_ASYNC_REQUEST *Req;
+ UHCI_ASYNC_REQUEST *Next;
+
+ Req = Uhc->Recycle;
+
+ while (Req != NULL) {
+ Next = Req->Recycle;
+ UhciFreeAsyncReq (Uhc, Req);
+ Req = Next;
+ }
+
+ Uhc->Recycle = Uhc->RecycleWait;
+ Uhc->RecycleWait = NULL;
+}
+
+
+
+/**
+ Release all the asynchronous transfers on the lsit.
+
+ @param Uhc The UHCI device.
+
+**/
+VOID
+UhciFreeAllAsyncReq (
+ IN USB_HC_DEV *Uhc
+ )
+{
+ LIST_ENTRY *Head;
+ UHCI_ASYNC_REQUEST *AsyncReq;
+
+ //
+ // Call UhciRecycleAsyncReq twice. The requests on Recycle
+ // will be released at the first call; The requests on
+ // RecycleWait will be released at the second call.
+ //
+ UhciRecycleAsyncReq (Uhc);
+ UhciRecycleAsyncReq (Uhc);
+
+ Head = &(Uhc->AsyncIntList);
+
+ if (IsListEmpty (Head)) {
+ return;
+ }
+
+ while (!IsListEmpty (Head)) {
+ AsyncReq = UHCI_ASYNC_INT_FROM_LINK (Head->ForwardLink);
+ UhciUnlinkAsyncReq (Uhc, AsyncReq, TRUE);
+ }
+}
+
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event The event of the time.
+ @param Context Context of the event, pointer to USB_HC_DEV.
+
+**/
+VOID
+EFIAPI
+UhciMonitorAsyncReqList (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UHCI_ASYNC_REQUEST *AsyncReq;
+ LIST_ENTRY *Link;
+ USB_HC_DEV *Uhc;
+ VOID *Data;
+ BOOLEAN Finished;
+ UHCI_QH_RESULT QhResult;
+
+ Uhc = (USB_HC_DEV *) Context;
+
+ //
+ // Recycle the asynchronous requests expired, and promote
+ // requests waiting to be recycled the next time when this
+ // timer expires
+ //
+ UhciRecycleAsyncReq (Uhc);
+
+ if (IsListEmpty (&(Uhc->AsyncIntList))) {
+ return ;
+ }
+
+ //
+ // This loop must be delete safe
+ //
+ Link = Uhc->AsyncIntList.ForwardLink;
+
+ do {
+ AsyncReq = UHCI_ASYNC_INT_FROM_LINK (Link);
+ Link = Link->ForwardLink;
+
+ Finished = UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);
+
+ if (!Finished) {
+ continue;
+ }
+
+ //
+ // Copy the data to temporary buffer if there are some
+ // data transferred. We may have zero-length packet.
+ // Make sure the data received from HW is no more than expected.
+ //
+ Data = NULL;
+
+ if ((QhResult.Complete != 0) && (QhResult.Complete <= AsyncReq->DataLen)) {
+ Data = AllocatePool (QhResult.Complete);
+
+ if (Data == NULL) {
+ return ;
+ }
+
+ CopyMem (Data, AsyncReq->FirstTd->Data, QhResult.Complete);
+ }
+
+ UhciUpdateAsyncReq (Uhc, AsyncReq, QhResult.Result, QhResult.NextToggle);
+
+ //
+ // Now, either transfer is SUCCESS or met errors since
+ // we have skipped to next transfer earlier if current
+ // transfer is still active.
+ //
+ if (QhResult.Result == EFI_USB_NOERROR) {
+ AsyncReq->Callback (Data, QhResult.Complete, AsyncReq->Context, QhResult.Result);
+ } else {
+ //
+ // Leave error recovery to its related device driver.
+ // A common case of the error recovery is to re-submit
+ // the interrupt transfer. When an interrupt transfer
+ // is re-submitted, its position in the linked list is
+ // changed. It is inserted to the head of the linked
+ // list, while this function scans the whole list from
+ // head to tail. Thus, the re-submitted interrupt transfer's
+ // callback function will not be called again in this round.
+ //
+ AsyncReq->Callback (NULL, 0, AsyncReq->Context, QhResult.Result);
+ }
+
+ if (Data != NULL) {
+ gBS->FreePool (Data);
+ }
+ } while (Link != &(Uhc->AsyncIntList));
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h
new file mode 100644
index 000000000..5bcfad5c6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h
@@ -0,0 +1,265 @@
+/** @file
+
+ The definition for EHCI register operation routines.
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_UHCI_SCHED_H_
+#define _EFI_UHCI_SCHED_H_
+
+
+#define UHCI_ASYNC_INT_SIGNATURE SIGNATURE_32 ('u', 'h', 'c', 'a')
+//
+// The failure mask for USB transfer return status. If any of
+// these bit is set, the transfer failed. EFI_USB_ERR_NOEXECUTE
+// and EFI_USB_ERR_NAK are not considered as error condition:
+// the transfer is still going on.
+//
+#define USB_ERR_FAIL_MASK (EFI_USB_ERR_STALL | EFI_USB_ERR_BUFFER | \
+ EFI_USB_ERR_BABBLE | EFI_USB_ERR_CRC | \
+ EFI_USB_ERR_TIMEOUT | EFI_USB_ERR_BITSTUFF | \
+ EFI_USB_ERR_SYSTEM)
+
+
+//
+// Structure to return the result of UHCI QH execution.
+// Result is the final result of the QH's QTD. NextToggle
+// is the next data toggle to use. Complete is the actual
+// length of data transferred.
+//
+typedef struct {
+ UINT32 Result;
+ UINT8 NextToggle;
+ UINTN Complete;
+} UHCI_QH_RESULT;
+
+typedef struct _UHCI_ASYNC_REQUEST UHCI_ASYNC_REQUEST;
+
+//
+// Structure used to manager the asynchronous interrupt transfers.
+//
+struct _UHCI_ASYNC_REQUEST{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UHCI_ASYNC_REQUEST *Recycle;
+
+ //
+ // Endpoint attributes
+ //
+ UINT8 DevAddr;
+ UINT8 EndPoint;
+ BOOLEAN IsLow;
+ UINTN Interval;
+
+ //
+ // Data and UHC structures
+ //
+ UHCI_QH_SW *QhSw;
+ UHCI_TD_SW *FirstTd;
+ UINT8 *Data; // Allocated host memory, not mapped memory
+ UINTN DataLen;
+ VOID *Mapping;
+
+ //
+ // User callback and its context
+ //
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
+ VOID *Context;
+};
+
+#define UHCI_ASYNC_INT_FROM_LINK(a) \
+ CR (a, UHCI_ASYNC_REQUEST, Link, UHCI_ASYNC_INT_SIGNATURE)
+
+
+/**
+ Create Frame List Structure.
+
+ @param Uhc The UHCI device.
+
+ @return EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @return EFI_UNSUPPORTED Map memory fail.
+ @return EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+UhciInitFrameList (
+ IN USB_HC_DEV *Uhc
+ );
+
+/**
+ Destory FrameList buffer.
+
+ @param Uhc The UHCI device.
+
+ @return None.
+
+**/
+VOID
+UhciDestoryFrameList (
+ IN USB_HC_DEV *Uhc
+ );
+
+
+/**
+ Convert the poll rate to the maxium 2^n that is smaller
+ than Interval.
+
+ @param Interval The poll rate to convert.
+
+ @return The converted poll rate.
+
+**/
+UINTN
+UhciConvertPollRate (
+ IN UINTN Interval
+ );
+
+
+/**
+ Link a queue head (for asynchronous interrupt transfer) to
+ the frame list.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head to link into.
+
+**/
+VOID
+UhciLinkQhToFrameList (
+ USB_HC_DEV *Uhc,
+ UHCI_QH_SW *Qh
+ );
+
+
+/**
+ Unlink QH from the frame list is easier: find all
+ the precedence node, and pointer there next to QhSw's
+ next.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head to unlink.
+
+**/
+VOID
+UhciUnlinkQhFromFrameList (
+ USB_HC_DEV *Uhc,
+ UHCI_QH_SW *Qh
+ );
+
+
+/**
+ Check the result of the transfer.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head of the transfer.
+ @param Td The first TDs of the transfer.
+ @param TimeOut TimeOut value in milliseconds.
+ @param IsLow Is Low Speed Device.
+ @param QhResult The variable to return result.
+
+ @retval EFI_SUCCESS The transfer finished with success.
+ @retval EFI_DEVICE_ERROR Transfer failed.
+
+**/
+EFI_STATUS
+UhciExecuteTransfer (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *Td,
+ IN UINTN TimeOut,
+ IN BOOLEAN IsLow,
+ OUT UHCI_QH_RESULT *QhResult
+ );
+
+
+/**
+ Create Async Request node, and Link to List.
+
+ @param Uhc The UHCI device.
+ @param Qh The queue head of the transfer.
+ @param FirstTd First TD of the transfer.
+ @param DevAddr Device Address.
+ @param EndPoint EndPoint Address.
+ @param DataLen Data length.
+ @param Interval Polling Interval when inserted to frame list.
+ @param Data Data buffer, unmapped.
+ @param Callback Callback after interrupt transfeer.
+ @param Context Callback Context passed as function parameter.
+ @param IsLow Is Low Speed.
+
+ @retval EFI_SUCCESS An asynchronous transfer is created.
+ @retval EFI_INVALID_PARAMETER Paremeter is error.
+ @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage.
+
+**/
+EFI_STATUS
+UhciCreateAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UHCI_QH_SW *Qh,
+ IN UHCI_TD_SW *FirstTd,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ IN UINTN DataLen,
+ IN UINTN Interval,
+ IN UINT8 *Data,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context,
+ IN BOOLEAN IsLow
+ );
+
+
+/**
+ Delete Async Interrupt QH and TDs.
+
+ @param Uhc The UHCI device.
+ @param DevAddr Device Address.
+ @param EndPoint EndPoint Address.
+ @param Toggle The next data toggle to use.
+
+ @retval EFI_SUCCESS The request is deleted.
+ @retval EFI_INVALID_PARAMETER Paremeter is error.
+ @retval EFI_NOT_FOUND The asynchronous isn't found.
+
+**/
+EFI_STATUS
+UhciRemoveAsyncReq (
+ IN USB_HC_DEV *Uhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EndPoint,
+ OUT UINT8 *Toggle
+ );
+
+
+/**
+ Release all the asynchronous transfers on the lsit.
+
+ @param Uhc The UHCI device.
+
+ @return None.
+
+**/
+VOID
+UhciFreeAllAsyncReq (
+ IN USB_HC_DEV *Uhc
+ );
+
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event The event of the time.
+ @param Context Context of the event, pointer to USB_HC_DEV.
+
+ @return None.
+
+**/
+VOID
+EFIAPI
+UhciMonitorAsyncReqList (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
new file mode 100644
index 000000000..9aade19f8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
@@ -0,0 +1,558 @@
+/** @file
+
+ The routine procedure for uhci memory allocate/free.
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Uhci.h"
+
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ UINTN Bytes;
+ EFI_STATUS Status;
+
+ PciIo = Pool->PciIo;
+
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
+ if (Block == NULL) {
+ return NULL;
+ }
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+ Block->Bits = AllocateZeroPool (Block->BitsLen);
+
+ if (Block->Bits == NULL) {
+ gBS->FreePool (Block);
+ return NULL;
+ }
+
+ //
+ // Allocate the number of Pages of memory, then map it for
+ // bus master read and write.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &BufHost,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_BITARRAY;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ BufHost,
+ &Bytes,
+ &MappedAddr,
+ &Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+ goto FREE_BUFFER;
+ }
+
+ //
+ // Check whether the data structure used by the host controller
+ // should be restricted into the same 4G
+ //
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+ PciIo->Unmap (PciIo, Mapping);
+ goto FREE_BUFFER;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+
+ return Block;
+
+FREE_BUFFER:
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);
+
+FREE_BITARRAY:
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+ return NULL;
+}
+
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ PciIo = Pool->PciIo;
+
+ //
+ // Unmap the common buffer then free the structures
+ //
+ PciIo->Unmap (PciIo, Block->Mapping);
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
+
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+}
+
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return EFI_SUCCESS The needed memory is allocated.
+ @return EFI_NOT_FOUND Can't find the free memory.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @return TRUE The memory block is empty.
+ @return FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Unlink the memory block from the pool's list.
+
+ @param Head The block list head of the memory's pool.
+ @param BlockToUnlink The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *BlockToUnlink
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ if (Block->Next == BlockToUnlink) {
+ Block->Next = BlockToUnlink->Next;
+ BlockToUnlink->Next = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @return EFI_SUCCESS The memory pool is initialized.
+ @return EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+{
+ USBHC_MEM_POOL *Pool;
+
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
+
+ if (Pool == NULL) {
+ return Pool;
+ }
+
+ Pool->PciIo = PciIo;
+ Pool->Check4G = Check4G;
+ Pool->Which4G = Which4G;
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ gBS->FreePool (Pool);
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @return EFI_SUCCESS The memory pool is freed.
+ @return EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UsbHcUnlinkMemBlock (Pool->Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+ gBS->FreePool (Pool);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+ if (NewBlock == NULL) {
+ DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcUnlinkMemBlock (Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h
new file mode 100644
index 000000000..d202669c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h
@@ -0,0 +1,155 @@
+/** @file
+
+ This file contains the definination for host controller memory management routines
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EHCI_MEM_H_
+#define _EFI_EHCI_MEM_H_
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64) \
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ );
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @return EFI_SUCCESS The memory pool is freed.
+ @return EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ );
+
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+ @return None.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c
new file mode 100644
index 000000000..91e5bf567
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/DmaMem.c
@@ -0,0 +1,222 @@
+/** @file
+The DMA memory help functions.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UhcPeim.h"
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->Map (
+ IoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, Mapping);
+ *Mapping = NULL;
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuUnmap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN VOID *Mapping
+ )
+{
+ if (IoMmu != NULL) {
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);
+ IoMmu->Unmap (IoMmu, Mapping);
+ }
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ *Mapping = NULL;
+
+ if (IoMmu != NULL) {
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *HostAddress = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, *Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *Mapping = NULL;
+ *HostAddress = NULL;
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *) (UINTN) HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+
+
+/**
+ Initialize IOMMU.
+
+ @param IoMmu Pointer to pointer to IOMMU PPI.
+
+**/
+VOID
+IoMmuInit (
+ OUT EDKII_IOMMU_PPI **IoMmu
+ )
+{
+ *IoMmu = NULL;
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) IoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c
new file mode 100644
index 000000000..a05834da3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c
@@ -0,0 +1,3297 @@
+/** @file
+PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UhcPeim.h"
+
+/**
+ Stop the host controller.
+
+ @param Uhc The UHCI device.
+ @param Timeout Max time allowed.
+
+ @retval EFI_SUCCESS The host controller is stopped.
+ @retval EFI_TIMEOUT Failed to stop the host controller.
+
+**/
+EFI_STATUS
+UhciStopHc (
+ IN USB_UHC_DEV *Uhc,
+ IN UINTN Timeout
+ )
+{
+ UINT16 CommandContent;
+ UINT16 UsbSts;
+ UINTN Index;
+
+ CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);
+ CommandContent &= USBCMD_RS;
+ USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);
+
+ //
+ // ensure the HC is in halt status after send the stop command
+ // Timeout is in us unit.
+ //
+ for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
+ UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);
+
+ if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
+ return EFI_SUCCESS;
+ }
+
+ MicroSecondDelay (50);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ One notified function to stop the Host Controller at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+ @retval others
+**/
+EFI_STATUS
+EFIAPI
+UhcEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ USB_UHC_DEV *Uhc;
+
+ Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
+
+ //
+ // Stop the Host Controller
+ //
+ UhciStopHc (Uhc, 1000 * 1000);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes Usb Host Controller.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINTN ControllerType;
+ UINTN BaseAddress;
+ UINTN MemPages;
+ USB_UHC_DEV *UhcDev;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &ChipSetUsbControllerPpi
+ );
+ //
+ // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ Index = 0;
+ while (TRUE) {
+ Status = ChipSetUsbControllerPpi->GetUsbController (
+ (EFI_PEI_SERVICES **) PeiServices,
+ ChipSetUsbControllerPpi,
+ Index,
+ &ControllerType,
+ &BaseAddress
+ );
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // This PEIM is for UHC type controller.
+ //
+ if (ControllerType != PEI_UHCI_CONTROLLER) {
+ Index++;
+ continue;
+ }
+
+ MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ MemPages,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);
+ UhcDev->Signature = USB_UHC_DEV_SIGNATURE;
+ IoMmuInit (&UhcDev->IoMmu);
+ UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
+
+ //
+ // Init local memory management service
+ //
+ Status = InitializeMemoryManagement (UhcDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize Uhc's hardware
+ //
+ Status = InitializeUsbHC (UhcDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UhcDev->UsbHostControllerPpi.ControlTransfer = UhcControlTransfer;
+ UhcDev->UsbHostControllerPpi.BulkTransfer = UhcBulkTransfer;
+ UhcDev->UsbHostControllerPpi.GetRootHubPortNumber = UhcGetRootHubPortNumber;
+ UhcDev->UsbHostControllerPpi.GetRootHubPortStatus = UhcGetRootHubPortStatus;
+ UhcDev->UsbHostControllerPpi.SetRootHubPortFeature = UhcSetRootHubPortFeature;
+ UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature = UhcClearRootHubPortFeature;
+
+ UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ UhcDev->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;
+ UhcDev->PpiDescriptor.Ppi = &UhcDev->UsbHostControllerPpi;
+
+ Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ Index++;
+ continue;
+ }
+
+ UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
+ UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;
+
+ PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);
+
+ Index++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 StatusReg;
+ UINT8 PktID;
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+ TD_STRUCT *PtrSetupTD;
+ TD_STRUCT *PtrStatusTD;
+ EFI_STATUS Status;
+ UINT32 DataLen;
+ UINT8 DataToggle;
+ UINT8 *RequestPhy;
+ VOID *RequestMap;
+ UINT8 *DataPhy;
+ VOID *DataMap;
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+
+ StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;
+
+ PktID = INPUT_PACKET_ID;
+
+ RequestMap = NULL;
+
+ if (Request == NULL || TransferResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // if errors exist that cause host controller halt,
+ // then return EFI_DEVICE_ERROR.
+ //
+
+ if (!IsStatusOK (UhcDev, StatusReg)) {
+ ClearStatusReg (UhcDev, StatusReg);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (UhcDev, StatusReg);
+
+ //
+ // Map the Request and data for bus master access,
+ // then create a list of TD for this transfer
+ //
+ Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
+
+ if (EFI_ERROR (Status)) {
+ if (RequestMap != NULL) {
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);
+ }
+ return Status;
+ }
+
+ //
+ // generate Setup Stage TD
+ //
+
+ PtrQH = UhcDev->ConfigQH;
+
+ GenSetupStageTD (
+ UhcDev,
+ DeviceAddress,
+ 0,
+ DeviceSpeed,
+ (UINT8 *) Request,
+ RequestPhy,
+ (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),
+ &PtrSetupTD
+ );
+
+ //
+ // link setup TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrSetupTD);
+
+ PtrPreTD = PtrSetupTD;
+
+ //
+ // Data Stage of Control Transfer
+ //
+
+ if (TransferDirection == EfiUsbNoData) {
+ DataLen = 0;
+ } else {
+ DataLen = (UINT32) *DataLength;
+ }
+
+ DataToggle = 1;
+
+ PtrTD = PtrSetupTD;
+ while (DataLen > 0) {
+ //
+ // create TD structures and link together
+ //
+ UINT8 PacketSize;
+
+ //
+ // PacketSize is the data load size of each TD carries.
+ //
+ PacketSize = (UINT8) DataLen;
+ if (DataLen > MaximumPacketLength) {
+ PacketSize = MaximumPacketLength;
+ }
+
+ GenDataTD (
+ UhcDev,
+ DeviceAddress,
+ 0,
+ Data,
+ DataPhy,
+ PacketSize,
+ PktID,
+ DataToggle,
+ DeviceSpeed,
+ &PtrTD
+ );
+
+ //
+ // Link two TDs in vertical depth
+ //
+ LinkTDToTD (PtrPreTD, PtrTD);
+ PtrPreTD = PtrTD;
+
+ DataToggle ^= 1;
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);
+ DataPhy += PacketSize;
+ DataLen -= PacketSize;
+ }
+
+ //
+ // PtrPreTD points to the last TD before the Setup-Stage TD.
+ //
+ PtrPreTD = PtrTD;
+
+ //
+ // Status Stage of Control Transfer
+ //
+ if (PktID == OUTPUT_PACKET_ID) {
+ PktID = INPUT_PACKET_ID;
+ } else {
+ PktID = OUTPUT_PACKET_ID;
+ }
+ //
+ // create Status Stage TD structure
+ //
+ CreateStatusTD (
+ UhcDev,
+ DeviceAddress,
+ 0,
+ PktID,
+ DeviceSpeed,
+ &PtrStatusTD
+ );
+
+ LinkTDToTD (PtrPreTD, PtrStatusTD);
+
+ //
+ // Poll QH-TDs execution and get result.
+ // detail status is returned
+ //
+ Status = ExecuteControlTransfer (
+ UhcDev,
+ PtrSetupTD,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // TRUE means must search other framelistindex
+ //
+ SetQHVerticalValidorInvalid(PtrQH, FALSE);
+ DeleteQueuedTDs (UhcDev, PtrSetupTD);
+
+ //
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (UhcDev, StatusReg)) {
+ *TransferResult |= EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (UhcDev, StatusReg);
+
+ if (DataMap != NULL) {
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);
+ }
+ if (RequestMap != NULL) {
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);
+ }
+
+ return Status;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 StatusReg;
+
+ UINT32 DataLen;
+
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrFirstTD;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+
+ UINT8 PktID;
+
+ BOOLEAN IsFirstTD;
+
+ EFI_STATUS Status;
+
+ EFI_USB_DATA_DIRECTION TransferDirection;
+
+ BOOLEAN ShortPacketEnable;
+
+ UINT16 CommandContent;
+
+ UINT8 *DataPhy;
+ VOID *DataMap;
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+
+ //
+ // Enable the maximum packet size (64bytes)
+ // that can be used for full speed bandwidth reclamation
+ // at the end of a frame.
+ //
+ CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);
+ if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {
+ CommandContent |= USBCMD_MAXP;
+ USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);
+ }
+
+ StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;
+
+ //
+ // these code lines are added here per complier's strict demand
+ //
+ PktID = INPUT_PACKET_ID;
+ PtrTD = NULL;
+ PtrFirstTD = NULL;
+ PtrPreTD = NULL;
+ DataLen = 0;
+
+ ShortPacketEnable = FALSE;
+
+ if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MaximumPacketLength != 8 && MaximumPacketLength != 16
+ && MaximumPacketLength != 32 && MaximumPacketLength != 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (UhcDev, StatusReg)) {
+
+ ClearStatusReg (UhcDev, StatusReg);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (UhcDev, StatusReg);
+
+ //
+ // Map the source data buffer for bus master access,
+ // then create a list of TDs
+ //
+ if ((EndPointAddress & 0x80) != 0) {
+ TransferDirection = EfiUsbDataIn;
+ } else {
+ TransferDirection = EfiUsbDataOut;
+ }
+
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataLen = (UINT32) *DataLength;
+
+ PtrQH = UhcDev->BulkQH;
+
+ IsFirstTD = TRUE;
+ while (DataLen > 0) {
+ //
+ // create TD structures and link together
+ //
+ UINT8 PacketSize;
+
+ PacketSize = (UINT8) DataLen;
+ if (DataLen > MaximumPacketLength) {
+ PacketSize = MaximumPacketLength;
+ }
+
+ GenDataTD (
+ UhcDev,
+ DeviceAddress,
+ EndPointAddress,
+ Data,
+ DataPhy,
+ PacketSize,
+ PktID,
+ *DataToggle,
+ USB_FULL_SPEED_DEVICE,
+ &PtrTD
+ );
+
+ //
+ // Enable short packet detection.
+ // (default action is disabling short packet detection)
+ //
+ if (ShortPacketEnable) {
+ EnableorDisableTDShortPacket (PtrTD, TRUE);
+ }
+
+ if (IsFirstTD) {
+ PtrFirstTD = PtrTD;
+ PtrFirstTD->PtrNextTD = NULL;
+ IsFirstTD = FALSE;
+ } else {
+ //
+ // Link two TDs in vertical depth
+ //
+ LinkTDToTD (PtrPreTD, PtrTD);
+ }
+
+ PtrPreTD = PtrTD;
+
+ *DataToggle ^= 1;
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);
+ DataPhy += PacketSize;
+ DataLen -= PacketSize;
+ }
+ //
+ // link TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrFirstTD);
+
+ //
+ // Execute QH-TD and get result
+ //
+ //
+ // detail status is put into the Result field in the pIRP
+ // the Data Toggle value is also re-updated to the value
+ // of the last successful TD
+ //
+ Status = ExecBulkTransfer (
+ UhcDev,
+ PtrFirstTD,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // Delete Bulk transfer TD structure
+ //
+ DeleteQueuedTDs (UhcDev, PtrFirstTD);
+
+ //
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (UhcDev, StatusReg)) {
+ *TransferResult |= EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (UhcDev, StatusReg);
+
+ if (DataMap != NULL) {
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortControl;
+ UINT32 Index;
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+
+ if (PortNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PortNumber = 0;
+
+ for (Index = 0; Index < 2; Index++) {
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);
+ //
+ // Port Register content is valid
+ //
+ if (RHPortControl != 0xff) {
+ (*PortNumber)++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortStatus;
+ UINT8 TotalPortNumber;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
+ if (PortNumber > TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
+
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ RHPortStatus = USBReadPortW (UhcDev, PSAddr);
+
+ //
+ // Current Connect Status
+ //
+ if ((RHPortStatus & USBPORTSC_CCS) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ //
+ // Port Enabled/Disabled
+ //
+ if ((RHPortStatus & USBPORTSC_PED) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+ //
+ // Port Suspend
+ //
+ if ((RHPortStatus & USBPORTSC_SUSP) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+ //
+ // Port Reset
+ //
+ if ((RHPortStatus & USBPORTSC_PR) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+ //
+ // Low Speed Device Attached
+ //
+ if ((RHPortStatus & USBPORTSC_LSDA) != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+ //
+ // Fill Port Status Change bits
+ //
+ //
+ // Connect Status Change
+ //
+ if ((RHPortStatus & USBPORTSC_CSC) != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+ //
+ // Port Enabled/Disabled Change
+ //
+ if ((RHPortStatus & USBPORTSC_PEDC) != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 PSAddr;
+ UINT32 CommandRegAddr;
+ UINT16 RHPortControl;
+ UINT8 TotalPortNumber;
+
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
+ if (PortNumber > TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
+ CommandRegAddr = UhcDev->UsbHostControllerBaseAddress + USBCMD;
+
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);
+
+ switch (PortFeature) {
+
+ case EfiUsbPortSuspend:
+ if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {
+ //
+ // if global suspend is not active, can set port suspend
+ //
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_SUSP;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_PR;
+ //
+ // Set the reset bit
+ //
+ break;
+
+ case EfiUsbPortPower:
+ break;
+
+ case EfiUsbPortEnable:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_PED;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ USBWritePortW (UhcDev, PSAddr, RHPortControl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_UHC_DEV *UhcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortControl;
+ UINT8 TotalPortNumber;
+
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
+
+ if (PortNumber > TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
+
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);
+
+ switch (PortFeature) {
+ //
+ // clear PORT_ENABLE feature means disable port.
+ //
+ case EfiUsbPortEnable:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_PED;
+ break;
+
+ //
+ // clear PORT_SUSPEND feature means resume the port.
+ // (cause a resume on the specified port if in suspend mode)
+ //
+ case EfiUsbPortSuspend:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_SUSP;
+ break;
+
+ //
+ // no operation
+ //
+ case EfiUsbPortPower:
+ break;
+
+ //
+ // clear PORT_RESET means clear the reset signal.
+ //
+ case EfiUsbPortReset:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_PR;
+ break;
+
+ //
+ // clear connect status change
+ //
+ case EfiUsbPortConnectChange:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_CSC;
+ break;
+
+ //
+ // clear enable/disable status change
+ //
+ case EfiUsbPortEnableChange:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_PEDC;
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortSuspendChange:
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortOverCurrentChange:
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortResetChange:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ USBWritePortW (UhcDev, PSAddr, RHPortControl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UHCI.
+
+ @param UhcDev UHCI Device.
+
+ @retval EFI_SUCCESS UHCI successfully initialized.
+ @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN USB_UHC_DEV *UhcDev
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FrameListBaseAddrReg;
+ UINT32 CommandReg;
+ UINT16 Command;
+
+ //
+ // Create and Initialize Frame List For the Host Controller.
+ //
+ Status = CreateFrameList (UhcDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FrameListBaseAddrReg = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;
+ CommandReg = UhcDev->UsbHostControllerBaseAddress + USBCMD;
+
+ //
+ // Set Frame List Base Address to the specific register to inform the hardware.
+ //
+ SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32) (UINTN) (UhcDev->FrameListEntry));
+
+ Command = USBReadPortW (UhcDev, CommandReg);
+ Command |= USBCMD_GRESET;
+ USBWritePortW (UhcDev, CommandReg, Command);
+
+ MicroSecondDelay (50 * 1000);
+
+
+ Command &= ~USBCMD_GRESET;
+
+ USBWritePortW (UhcDev, CommandReg, Command);
+
+ //
+ //UHCI spec page120 reset recovery time
+ //
+ MicroSecondDelay (20 * 1000);
+
+ //
+ // Set Run/Stop bit to 1.
+ //
+ Command = USBReadPortW (UhcDev, CommandReg);
+ Command |= USBCMD_RS | USBCMD_MAXP;
+ USBWritePortW (UhcDev, CommandReg, Command);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create Frame List Structure.
+
+ @param UhcDev UHCI device.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateFrameList (
+ USB_UHC_DEV *UhcDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS FrameListBaseAddr;
+ FRAMELIST_ENTRY *FrameListPtr;
+ UINTN Index;
+
+ //
+ // The Frame List ocupies 4K bytes,
+ // and must be aligned on 4-Kbyte boundaries.
+ //
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ 1,
+ &FrameListBaseAddr
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ //Create Control QH and Bulk QH and link them into Framelist Entry
+ //
+ Status = CreateQH(UhcDev, &UhcDev->ConfigQH);
+ if (Status != EFI_SUCCESS) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (UhcDev->ConfigQH != NULL);
+
+ Status = CreateQH(UhcDev, &UhcDev->BulkQH);
+ if (Status != EFI_SUCCESS) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (UhcDev->BulkQH != NULL);
+
+ //
+ //Set the corresponding QH pointer
+ //
+ SetQHHorizontalLinkPtr(UhcDev->ConfigQH, UhcDev->BulkQH);
+ SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);
+ SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);
+
+ UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) FrameListBaseAddr);
+
+ FrameListPtr = UhcDev->FrameListEntry;
+
+ for (Index = 0; Index < 1024; Index++) {
+ FrameListPtr->FrameListPtrTerminate = 0;
+ FrameListPtr->FrameListPtr = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;
+ FrameListPtr->FrameListPtrQSelect = 1;
+ FrameListPtr->FrameListRsvd = 0;
+ FrameListPtr ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read a 16bit width data from Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+
+ @retval the register content read.
+
+**/
+UINT16
+USBReadPortW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port
+ )
+{
+ return IoRead16 (Port);
+}
+
+/**
+ Write a 16bit width data into Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+ @param Data The data written into the register.
+
+**/
+VOID
+USBWritePortW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port,
+ IN UINT16 Data
+ )
+{
+ IoWrite16 (Port, Data);
+}
+
+/**
+ Write a 32bit width data into Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+ @param Data The data written into the register.
+
+**/
+VOID
+USBWritePortDW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port,
+ IN UINT32 Data
+ )
+{
+ IoWrite32 (Port, Data);
+}
+
+/**
+ Clear the content of UHCI's Status Register.
+
+ @param UhcDev The UHCI device.
+ @param StatusAddr The IO space address of the register.
+
+**/
+VOID
+ClearStatusReg (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 StatusAddr
+ )
+{
+ //
+ // Clear the content of UHCI's Status Register
+ //
+ USBWritePortW (UhcDev, StatusAddr, 0x003F);
+}
+
+/**
+ Check whether the host controller operates well.
+
+ @param UhcDev The UHCI device.
+ @param StatusRegAddr The io address of status register.
+
+ @retval TRUE Host controller is working.
+ @retval FALSE Host controller is halted or system error.
+
+**/
+BOOLEAN
+IsStatusOK (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 StatusRegAddr
+ )
+{
+ UINT16 StatusValue;
+
+ StatusValue = USBReadPortW (UhcDev, StatusRegAddr);
+
+ if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+
+/**
+ Set Frame List Base Address.
+
+ @param UhcDev The UHCI device.
+ @param FrameListRegAddr The address of frame list register.
+ @param Addr The address of frame list table.
+
+**/
+VOID
+SetFrameListBaseAddress (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 FrameListRegAddr,
+ IN UINT32 Addr
+ )
+{
+ //
+ // Sets value in the USB Frame List Base Address register.
+ //
+ USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));
+}
+
+/**
+ Create QH and initialize.
+
+ @param UhcDev The UHCI device.
+ @param PtrQH Place to store QH_STRUCT pointer.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateQH (
+ IN USB_UHC_DEV *UhcDev,
+ OUT QH_STRUCT **PtrQH
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // allocate align memory for QH_STRUCT
+ //
+ Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // init each field of the QH_STRUCT
+ //
+ SetQHHorizontalValidorInvalid (*PtrQH, FALSE);
+ SetQHVerticalValidorInvalid (*PtrQH, FALSE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the horizontal link pointer in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrNext Place to the next QH_STRUCT.
+
+**/
+VOID
+SetQHHorizontalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *PtrNext
+ )
+{
+ //
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,
+ // Only the highest 28bit of the address is valid
+ // (take 32bit address as an example).
+ //
+ PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;
+}
+
+
+
+/**
+ Set a QH or TD horizontally to be connected with a specific QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetQHHorizontalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsQH
+ )
+{
+ //
+ // if QH is connected, the specified bit is set,
+ // if TD is connected, the specified bit is cleared.
+ //
+ PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;
+}
+
+/**
+ Set the horizontal validor bit in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsValid Specify the horizontal linker is valid or not.
+
+**/
+VOID
+SetQHHorizontalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsValid
+ )
+{
+ //
+ // Valid means the horizontal link pointer is valid,
+ // else, it's invalid.
+ //
+ PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;
+}
+
+/**
+ Set the vertical link pointer in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrNext Place to the next QH_STRUCT.
+
+**/
+VOID
+SetQHVerticalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *PtrNext
+ )
+{
+ //
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,
+ // Only the highest 28bit of the address is valid
+ // (take 32bit address as an example).
+ //
+ PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;
+}
+
+/**
+ Set a QH or TD vertically to be connected with a specific QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetQHVerticalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsQH
+ )
+{
+ //
+ // Set the specified bit if the Vertical Link Pointer pointing to a QH,
+ // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
+ //
+ PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;
+}
+
+/**
+ Set the vertical validor bit in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsValid Specify the vertical linker is valid or not.
+
+**/
+VOID
+SetQHVerticalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsValid
+ )
+{
+ //
+ // If TRUE, meaning the Vertical Link Pointer field is valid,
+ // else, the field is invalid.
+ //
+ PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;
+}
+
+
+
+/**
+ Allocate TD or QH Struct.
+
+ @param UhcDev The UHCI device.
+ @param Size The size of allocation.
+ @param PtrStruct Place to store TD_STRUCT pointer.
+
+ @return EFI_SUCCESS Allocate successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+AllocateTDorQHStruct (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Size,
+ OUT VOID **PtrStruct
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ *PtrStruct = NULL;
+
+ Status = UhcAllocatePool (
+ UhcDev,
+ (UINT8 **) PtrStruct,
+ Size
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (*PtrStruct, Size);
+
+ return Status;
+}
+
+/**
+ Create a TD Struct.
+
+ @param UhcDev The UHCI device.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+ @return EFI_SUCCESS Allocate successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+CreateTD (
+ IN USB_UHC_DEV *UhcDev,
+ OUT TD_STRUCT **PtrTD
+ )
+{
+ EFI_STATUS Status;
+ //
+ // create memory for TD_STRUCT, and align the memory.
+ //
+ Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Make TD ready.
+ //
+ SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate Setup Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param DeviceSpeed Device Speed.
+ @param DevRequest CPU memory address of request structure buffer to transfer.
+ @param RequestPhy PCI memory address of request structure buffer to transfer.
+ @param RequestLen Request length.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate setup stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+GenSetupStageTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 *DevRequest,
+ IN UINT8 *RequestPhy,
+ IN UINT8 RequestLen,
+ OUT TD_STRUCT **PtrTD
+ )
+{
+ TD_STRUCT *TdStruct;
+ EFI_STATUS Status;
+
+ Status = CreateTD (UhcDev, &TdStruct);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetTDLinkPtr (TdStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
+
+ //
+ // Disable Short Packet Detection by default
+ //
+ EnableorDisableTDShortPacket (TdStruct, FALSE);
+
+ //
+ // Max error counter is 3, retry 3 times when error encountered.
+ //
+ SetTDControlErrorCounter (TdStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ switch (DeviceSpeed) {
+ case USB_SLOW_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (TdStruct, TRUE);
+ break;
+
+ case USB_FULL_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (TdStruct, FALSE);
+ break;
+ }
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (TdStruct, FALSE);
+
+ //
+ // Interrupt On Complete bit be set to zero,
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (TdStruct, FALSE);
+
+ //
+ // Set TD Active bit
+ //
+ SetTDStatusActiveorInactive (TdStruct, TRUE);
+
+ SetTDTokenMaxLength (TdStruct, RequestLen);
+
+ SetTDTokenDataToggle0 (TdStruct);
+
+ SetTDTokenEndPoint (TdStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (TdStruct, DevAddr);
+
+ SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);
+
+ TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;
+ TdStruct->TDBufferLength = RequestLen;
+ //
+ // Set the beginning address of the buffer that will be used
+ // during the transaction.
+ //
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;
+
+ *PtrTD = TdStruct;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate Data Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param PtrData CPU memory address of user data buffer to transfer.
+ @param DataPhy PCI memory address of user data buffer to transfer.
+ @param Len Data length.
+ @param PktID PacketID.
+ @param Toggle Data toggle value.
+ @param DeviceSpeed Device Speed.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate data stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+GenDataTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 *PtrData,
+ IN UINT8 *DataPhy,
+ IN UINT8 Len,
+ IN UINT8 PktID,
+ IN UINT8 Toggle,
+ IN UINT8 DeviceSpeed,
+ OUT TD_STRUCT **PtrTD
+ )
+{
+ TD_STRUCT *TdStruct;
+ EFI_STATUS Status;
+
+ Status = CreateTD (UhcDev, &TdStruct);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetTDLinkPtr (TdStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
+
+ //
+ // Link pointer pointing to TD struct
+ //
+ SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
+
+ //
+ // Disable short packet detect
+ //
+ EnableorDisableTDShortPacket (TdStruct, FALSE);
+ //
+ // Max error counter is 3
+ //
+ SetTDControlErrorCounter (TdStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ switch (DeviceSpeed) {
+ case USB_SLOW_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (TdStruct, TRUE);
+ break;
+
+ case USB_FULL_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (TdStruct, FALSE);
+ break;
+ }
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (TdStruct, FALSE);
+
+ //
+ // Disable Interrupt On Complete
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (TdStruct, FALSE);
+
+ //
+ // Set Active bit
+ //
+ SetTDStatusActiveorInactive (TdStruct, TRUE);
+
+ SetTDTokenMaxLength (TdStruct, Len);
+
+ if (Toggle != 0) {
+ SetTDTokenDataToggle1 (TdStruct);
+ } else {
+ SetTDTokenDataToggle0 (TdStruct);
+ }
+
+ SetTDTokenEndPoint (TdStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (TdStruct, DevAddr);
+
+ SetTDTokenPacketID (TdStruct, PktID);
+
+ TdStruct->PtrTDBuffer = (UINT8 *) PtrData;
+ TdStruct->TDBufferLength = Len;
+ //
+ // Set the beginning address of the buffer that will be used
+ // during the transaction.
+ //
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;
+
+ *PtrTD = TdStruct;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate Status Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param PktID PacketID.
+ @param DeviceSpeed Device Speed.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate status stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+CreateStatusTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 PktID,
+ IN UINT8 DeviceSpeed,
+ OUT TD_STRUCT **PtrTD
+ )
+{
+ TD_STRUCT *PtrTDStruct;
+ EFI_STATUS Status;
+
+ Status = CreateTD (UhcDev, &PtrTDStruct);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetTDLinkPtr (PtrTDStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);
+
+ //
+ // Disable short packet detect
+ //
+ EnableorDisableTDShortPacket (PtrTDStruct, FALSE);
+
+ //
+ // Max error counter is 3
+ //
+ SetTDControlErrorCounter (PtrTDStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ switch (DeviceSpeed) {
+ case USB_SLOW_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);
+ break;
+
+ case USB_FULL_SPEED_DEVICE:
+ SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);
+ break;
+ }
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (PtrTDStruct, FALSE);
+
+ //
+ // Disable Interrupt On Complete
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (PtrTDStruct, FALSE);
+
+ //
+ // Set TD Active bit
+ //
+ SetTDStatusActiveorInactive (PtrTDStruct, TRUE);
+
+ SetTDTokenMaxLength (PtrTDStruct, 0);
+
+ SetTDTokenDataToggle1 (PtrTDStruct);
+
+ SetTDTokenEndPoint (PtrTDStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);
+
+ SetTDTokenPacketID (PtrTDStruct, PktID);
+
+ PtrTDStruct->PtrTDBuffer = NULL;
+ PtrTDStruct->TDBufferLength = 0;
+ //
+ // Set the beginning address of the buffer that will be used
+ // during the transaction.
+ //
+ PtrTDStruct->TDData.TDBufferPtr = 0;
+
+ *PtrTD = PtrTDStruct;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the link pointer validor bit in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsValid Specify the linker pointer is valid or not.
+
+**/
+VOID
+SetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsValid
+ )
+{
+ //
+ // Valid means the link pointer is valid,
+ // else, it's invalid.
+ //
+ PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);
+}
+
+/**
+ Set the Link Pointer pointing to a QH or TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetTDLinkPtrQHorTDSelect (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsQH
+ )
+{
+ //
+ // Indicate whether the Link Pointer pointing to a QH or TD
+ //
+ PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);
+}
+
+/**
+ Set the traverse is depth-first or breadth-first.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsDepth Specify the traverse is depth-first or breadth-first.
+
+**/
+VOID
+SetTDLinkPtrDepthorBreadth (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsDepth
+ )
+{
+ //
+ // If TRUE, indicating the host controller should process in depth first fashion,
+ // else, the host controller should process in breadth first fashion
+ //
+ PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);
+}
+
+/**
+ Set TD Link Pointer in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param PtrNext Place to the next TD_STRUCT.
+
+**/
+VOID
+SetTDLinkPtr (
+ IN TD_STRUCT *PtrTDStruct,
+ IN VOID *PtrNext
+ )
+{
+ //
+ // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
+ // only the highest 28 bits are valid. (if take 32bit address as an example)
+ //
+ PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;
+}
+
+/**
+ Get TD Link Pointer.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval Get TD Link Pointer in TD.
+
+**/
+VOID *
+GetTDLinkPtr (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ //
+ // Get TD Link Pointer. Restore it back to 32bit
+ // (if take 32bit address as an example)
+ //
+ return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);
+}
+
+
+
+/**
+ Enable/Disable short packet detection mechanism.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsEnable Enable or disable short packet detection mechanism.
+
+**/
+VOID
+EnableorDisableTDShortPacket (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsEnable
+ )
+{
+ //
+ // TRUE means enable short packet detection mechanism.
+ //
+ PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);
+}
+
+/**
+ Set the max error counter in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param MaxErrors The number of allowable error.
+
+**/
+VOID
+SetTDControlErrorCounter (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT8 MaxErrors
+ )
+{
+ //
+ // valid value of MaxErrors is 0,1,2,3
+ //
+ if (MaxErrors > 3) {
+ MaxErrors = 3;
+ }
+
+ PtrTDStruct->TDData.TDStatusErr = MaxErrors;
+}
+
+/**
+ Set the TD is targeting a low-speed device or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsLowSpeedDevice Whether The device is low-speed.
+
+**/
+VOID
+SetTDLoworFullSpeedDevice (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsLowSpeedDevice
+ )
+{
+ //
+ // TRUE means the TD is targeting at a Low-speed device
+ //
+ PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);
+}
+
+/**
+ Set the TD is isochronous transfer type or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsIsochronous Whether the transaction isochronous transfer type.
+
+**/
+VOID
+SetTDControlIsochronousorNot (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsIsochronous
+ )
+{
+ //
+ // TRUE means the TD belongs to Isochronous transfer type.
+ //
+ PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
+}
+
+/**
+ Set if UCHI should issue an interrupt on completion of the frame
+ in which this TD is executed
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsSet Whether HC should issue an interrupt on completion.
+
+**/
+VOID
+SetorClearTDControlIOC (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsSet
+ )
+{
+ //
+ // If this bit is set, it indicates that the host controller should issue
+ // an interrupt on completion of the frame in which this TD is executed.
+ //
+ PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
+}
+
+/**
+ Set if the TD is active and can be executed.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsActive Whether the TD is active and can be executed.
+
+**/
+VOID
+SetTDStatusActiveorInactive (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsActive
+ )
+{
+ //
+ // If this bit is set, it indicates that the TD is active and can be
+ // executed.
+ //
+ if (IsActive) {
+ PtrTDStruct->TDData.TDStatus |= 0x80;
+ } else {
+ PtrTDStruct->TDData.TDStatus &= 0x7F;
+ }
+}
+
+/**
+ Specifies the maximum number of data bytes allowed for the transfer.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param MaxLen The maximum number of data bytes allowed.
+
+ @retval The allowed maximum number of data.
+**/
+UINT16
+SetTDTokenMaxLength (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT16 MaxLen
+ )
+{
+ //
+ // Specifies the maximum number of data bytes allowed for the transfer.
+ // the legal value extent is 0 ~ 0x500.
+ //
+ if (MaxLen > 0x500) {
+ MaxLen = 0x500;
+ }
+
+ PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;
+
+ return MaxLen;
+}
+
+/**
+ Set the data toggle bit to DATA1.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+**/
+VOID
+SetTDTokenDataToggle1 (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ //
+ // Set the data toggle bit to DATA1
+ //
+ PtrTDStruct->TDData.TDTokenDataToggle = 1;
+}
+
+/**
+ Set the data toggle bit to DATA0.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+**/
+VOID
+SetTDTokenDataToggle0 (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ //
+ // Set the data toggle bit to DATA0
+ //
+ PtrTDStruct->TDData.TDTokenDataToggle = 0;
+}
+
+/**
+ Set EndPoint Number the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param EndPoint The Endport number of the target.
+
+**/
+VOID
+SetTDTokenEndPoint (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINTN EndPoint
+ )
+{
+ //
+ // Set EndPoint Number the TD is targeting at.
+ //
+ PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;
+}
+
+/**
+ Set Device Address the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param DevAddr The Device Address of the target.
+
+**/
+VOID
+SetTDTokenDeviceAddress (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINTN DevAddr
+ )
+{
+ //
+ // Set Device Address the TD is targeting at.
+ //
+ PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;
+}
+
+/**
+ Set Packet Identification the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param PacketID The Packet Identification of the target.
+
+**/
+VOID
+SetTDTokenPacketID (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT8 PacketID
+ )
+{
+ //
+ // Set the Packet Identification to be used for this transaction.
+ //
+ PtrTDStruct->TDData.TDTokenPID = PacketID;
+}
+
+/**
+ Detect whether the TD is active.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The TD is active or not.
+
+**/
+BOOLEAN
+IsTDStatusActive (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether the TD is active.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x80);
+}
+
+/**
+ Detect whether the TD is stalled.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The TD is stalled or not.
+
+**/
+BOOLEAN
+IsTDStatusStalled (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether the device/endpoint addressed by this TD is stalled.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x40);
+}
+
+/**
+ Detect whether Data Buffer Error is happened.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Data Buffer Error is happened or not.
+
+**/
+BOOLEAN
+IsTDStatusBufferError (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether Data Buffer Error is happened.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x20);
+}
+
+/**
+ Detect whether Babble Error is happened.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Babble Error is happened or not.
+
+**/
+BOOLEAN
+IsTDStatusBabbleError (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether Babble Error is happened.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x10);
+}
+
+/**
+ Detect whether NAK is received.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The NAK is received or not.
+
+**/
+BOOLEAN
+IsTDStatusNAKReceived (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether NAK is received.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x08);
+}
+
+/**
+ Detect whether CRC/Time Out Error is encountered.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The CRC/Time Out Error is encountered or not.
+
+**/
+BOOLEAN
+IsTDStatusCRCTimeOutError (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether CRC/Time Out Error is encountered.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x04);
+}
+
+/**
+ Detect whether Bitstuff Error is received.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Bitstuff Error is received or not.
+
+**/
+BOOLEAN
+IsTDStatusBitStuffError (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether Bitstuff Error is received.
+ //
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x02);
+}
+
+/**
+ Retrieve the actual number of bytes that were tansferred.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The actual number of bytes that were tansferred.
+
+**/
+UINT16
+GetTDStatusActualLength (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ //
+ // Retrieve the actual number of bytes that were tansferred.
+ // the value is encoded as n-1. so return the decoded value.
+ //
+ return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);
+}
+
+/**
+ Retrieve the information of whether the Link Pointer field is valid or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The linker pointer field is valid or not.
+
+**/
+BOOLEAN
+GetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *PtrTDStruct
+ )
+{
+ //
+ // Retrieve the information of whether the Link Pointer field
+ // is valid or not.
+ //
+ if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+}
+
+/**
+ Count TD Number from PtrFirstTD.
+
+ @param PtrFirstTD Place to store TD_STRUCT pointer.
+
+ @retval The queued TDs number.
+
+**/
+UINTN
+CountTDsNumber (
+ IN TD_STRUCT *PtrFirstTD
+ )
+{
+ UINTN Number;
+ TD_STRUCT *Ptr;
+
+ //
+ // Count the queued TDs number.
+ //
+ Number = 0;
+ Ptr = PtrFirstTD;
+ while (Ptr != 0) {
+ Ptr = (TD_STRUCT *) Ptr->PtrNextTD;
+ Number++;
+ }
+
+ return Number;
+}
+
+/**
+ Link TD To QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+LinkTDToQH (
+ IN QH_STRUCT *PtrQH,
+ IN TD_STRUCT *PtrTD
+ )
+{
+ if (PtrQH == NULL || PtrTD == NULL) {
+ return ;
+ }
+ //
+ // Validate QH Vertical Ptr field
+ //
+ SetQHVerticalValidorInvalid (PtrQH, TRUE);
+
+ //
+ // Vertical Ptr pointing to TD structure
+ //
+ SetQHVerticalQHorTDSelect (PtrQH, FALSE);
+
+ SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);
+
+ PtrQH->PtrDown = (VOID *) PtrTD;
+}
+
+/**
+ Link TD To TD.
+
+ @param PtrPreTD Place to store TD_STRUCT pointer.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+LinkTDToTD (
+ IN TD_STRUCT *PtrPreTD,
+ IN TD_STRUCT *PtrTD
+ )
+{
+ if (PtrPreTD == NULL || PtrTD == NULL) {
+ return ;
+ }
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);
+
+ //
+ // Link pointer pointing to TD struct
+ //
+ SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);
+
+ //
+ // Validate the link pointer valid bit
+ //
+ SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);
+
+ SetTDLinkPtr (PtrPreTD, PtrTD);
+
+ PtrPreTD->PtrNextTD = (VOID *) PtrTD;
+
+ PtrTD->PtrNextTD = NULL;
+}
+
+/**
+ Execute Control Transfer.
+
+ @param UhcDev The UCHI device.
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param ActualLen Actual transfer Length.
+ @param TimeOut TimeOut value.
+ @param TransferResult Transfer Result.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+ExecuteControlTransfer (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrTD,
+ OUT UINTN *ActualLen,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ UINTN ErrTDPos;
+ UINTN Delay;
+ BOOLEAN InfiniteLoop;
+
+ ErrTDPos = 0;
+ *TransferResult = EFI_USB_NOERROR;
+ *ActualLen = 0;
+ InfiniteLoop = FALSE;
+
+ Delay = TimeOut * STALL_1_MILLI_SECOND;
+ //
+ // If Timeout is 0, then the caller must wait for the function to be completed
+ // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ //
+ if (TimeOut == 0) {
+ InfiniteLoop = TRUE;
+ }
+
+ do {
+
+ CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
+
+ //
+ // TD is inactive, means the control transfer is end.
+ //
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
+ break;
+ }
+ MicroSecondDelay (STALL_1_MICRO_SECOND);
+ Delay--;
+
+ } while (InfiniteLoop || (Delay != 0));
+
+ if (*TransferResult != EFI_USB_NOERROR) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute Bulk Transfer.
+
+ @param UhcDev The UCHI device.
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param ActualLen Actual transfer Length.
+ @param DataToggle DataToggle value.
+ @param TimeOut TimeOut value.
+ @param TransferResult Transfer Result.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+ExecBulkTransfer (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrTD,
+ IN OUT UINTN *ActualLen,
+ IN UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ UINTN ErrTDPos;
+ UINTN ScrollNum;
+ UINTN Delay;
+ BOOLEAN InfiniteLoop;
+
+ ErrTDPos = 0;
+ *TransferResult = EFI_USB_NOERROR;
+ *ActualLen = 0;
+ InfiniteLoop = FALSE;
+
+ Delay = TimeOut * STALL_1_MILLI_SECOND;
+ //
+ // If Timeout is 0, then the caller must wait for the function to be completed
+ // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ //
+ if (TimeOut == 0) {
+ InfiniteLoop = TRUE;
+ }
+
+ do {
+
+ CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
+ //
+ // TD is inactive, thus meaning bulk transfer's end.
+ //
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
+ break;
+ }
+ MicroSecondDelay (STALL_1_MICRO_SECOND);
+ Delay--;
+
+ } while (InfiniteLoop || (Delay != 0));
+
+ //
+ // has error
+ //
+ if (*TransferResult != EFI_USB_NOERROR) {
+ //
+ // scroll the Data Toggle back to the last success TD
+ //
+ ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
+ if ((ScrollNum % 2) != 0) {
+ *DataToggle ^= 1;
+ }
+
+ //
+ // If error, wait 100ms to retry by upper layer
+ //
+ MicroSecondDelay (100 * 1000);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete Queued TDs.
+
+ @param UhcDev The UCHI device.
+ @param PtrFirstTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+DeleteQueuedTDs (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrFirstTD
+ )
+{
+ TD_STRUCT *Tptr1;
+
+ TD_STRUCT *Tptr2;
+
+ Tptr1 = PtrFirstTD;
+ //
+ // Delete all the TDs in a queue.
+ //
+ while (Tptr1 != NULL) {
+
+ Tptr2 = Tptr1;
+
+ if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
+ Tptr1 = NULL;
+ } else {
+ //
+ // has more than one TD in the queue.
+ //
+ Tptr1 = GetTDLinkPtr (Tptr2);
+ }
+
+ UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
+ }
+
+ return ;
+}
+
+/**
+ Check TDs Results.
+
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param Result The result to return.
+ @param ErrTDPos The Error TD position.
+ @param ActualTransferSize Actual transfer size.
+
+ @retval The TD is executed successfully or not.
+
+**/
+BOOLEAN
+CheckTDsResults (
+ IN TD_STRUCT *PtrTD,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualTransferSize
+ )
+{
+ UINTN Len;
+
+ *Result = EFI_USB_NOERROR;
+ *ErrTDPos = 0;
+
+ //
+ // Init to zero.
+ //
+ *ActualTransferSize = 0;
+
+ while (PtrTD != NULL) {
+
+ if (IsTDStatusActive (PtrTD)) {
+ *Result |= EFI_USB_ERR_NOTEXECUTE;
+ }
+
+ if (IsTDStatusStalled (PtrTD)) {
+ *Result |= EFI_USB_ERR_STALL;
+ }
+
+ if (IsTDStatusBufferError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if (IsTDStatusBabbleError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BABBLE;
+ }
+
+ if (IsTDStatusNAKReceived (PtrTD)) {
+ *Result |= EFI_USB_ERR_NAK;
+ }
+
+ if (IsTDStatusCRCTimeOutError (PtrTD)) {
+ *Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ if (IsTDStatusBitStuffError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BITSTUFF;
+ }
+ //
+ // Accumulate actual transferred data length in each TD.
+ //
+ Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
+ *ActualTransferSize += Len;
+
+ //
+ // if any error encountered, stop processing the left TDs.
+ //
+ if ((*Result) != 0) {
+ return FALSE;
+ }
+
+ PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);
+ //
+ // Record the first Error TD's position in the queue,
+ // this value is zero-based.
+ //
+ (*ErrTDPos)++;
+ }
+
+ return TRUE;
+}
+
+/**
+ Create Memory Block.
+
+ @param UhcDev The UCHI device.
+ @param MemoryHeader The Pointer to allocated memory block.
+ @param MemoryBlockSizeInPages The page size of memory block to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateMemoryBlock (
+ IN USB_UHC_DEV *UhcDev,
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,
+ IN UINTN MemoryBlockSizeInPages
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *TempPtr;
+ UINTN MemPages;
+ UINT8 *Ptr;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+
+ //
+ // Memory Block uses MemoryBlockSizeInPages pages,
+ // memory management header and bit array use 1 page
+ //
+ MemPages = MemoryBlockSizeInPages + 1;
+ Status = IoMmuAllocateBuffer (
+ UhcDev->IoMmu,
+ MemPages,
+ (VOID **) &TempPtr,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status) || (TempPtr == NULL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = TempPtr;
+
+ ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
+
+ *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;
+ //
+ // adjust Ptr pointer to the next empty memory
+ //
+ Ptr += sizeof (MEMORY_MANAGE_HEADER);
+ //
+ // Set Bit Array initial address
+ //
+ (*MemoryHeader)->BitArrayPtr = Ptr;
+
+ (*MemoryHeader)->Next = NULL;
+
+ //
+ // Memory block initial address
+ //
+ Ptr = TempPtr;
+ Ptr += EFI_PAGE_SIZE;
+ (*MemoryHeader)->MemoryBlockPtr = Ptr;
+ //
+ // set Memory block size
+ //
+ (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;
+ //
+ // each bit in Bit Array will manage 32byte memory in memory block
+ //
+ (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UHCI memory management.
+
+ @param UhcDev The UCHI device.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+InitializeMemoryManagement (
+ IN USB_UHC_DEV *UhcDev
+ )
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ EFI_STATUS Status;
+ UINTN MemPages;
+
+ MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
+ Status = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UhcDev->Header1 = MemoryHeader;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UHCI memory management.
+
+ @param UhcDev The UCHI device.
+ @param Pool Buffer pointer to store the buffer pointer.
+ @param AllocSize The size of the pool to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+UhcAllocatePool (
+ IN USB_UHC_DEV *UhcDev,
+ OUT UINT8 **Pool,
+ IN UINTN AllocSize
+ )
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+ MEMORY_MANAGE_HEADER *NewMemoryHeader;
+ UINTN RealAllocSize;
+ UINTN MemoryBlockSizeInPages;
+ EFI_STATUS Status;
+
+ *Pool = NULL;
+
+ MemoryHeader = UhcDev->Header1;
+
+ //
+ // allocate unit is 32 byte (align on 32 byte)
+ //
+ if ((AllocSize & 0x1F) != 0) {
+ RealAllocSize = (AllocSize / 32 + 1) * 32;
+ } else {
+ RealAllocSize = AllocSize;
+ }
+
+ Status = EFI_NOT_FOUND;
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
+
+ Status = AllocMemInMemoryBlock (
+ TempHeaderPtr,
+ (VOID **) Pool,
+ RealAllocSize / 32
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // There is no enough memory,
+ // Create a new Memory Block
+ //
+ //
+ // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
+ // just allocate a large enough memory block.
+ //
+ if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {
+ MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;
+ } else {
+ MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
+ }
+
+ Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Link the new Memory Block to the Memory Header list
+ //
+ InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
+
+ Status = AllocMemInMemoryBlock (
+ NewMemoryHeader,
+ (VOID **) Pool,
+ RealAllocSize / 32
+ );
+ return Status;
+}
+
+/**
+ Alloc Memory In MemoryBlock.
+
+ @param MemoryHeader The pointer to memory manage header.
+ @param Pool Buffer pointer to store the buffer pointer.
+ @param NumberOfMemoryUnit The size of the pool to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+AllocMemInMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ OUT VOID **Pool,
+ IN UINTN NumberOfMemoryUnit
+ )
+{
+ UINTN TempBytePos;
+ UINTN FoundBytePos;
+ UINT8 Index;
+ UINT8 FoundBitPos;
+ UINT8 ByteValue;
+ UINT8 BitValue;
+ UINTN NumberOfZeros;
+ UINTN Count;
+
+ FoundBytePos = 0;
+ FoundBitPos = 0;
+
+ ByteValue = MemoryHeader->BitArrayPtr[0];
+ NumberOfZeros = 0;
+ Index = 0;
+ for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
+ //
+ // Pop out BitValue from a byte in TempBytePos.
+ //
+ BitValue = (UINT8)(ByteValue & 0x1);
+
+ if (BitValue == 0) {
+ //
+ // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
+ //
+ NumberOfZeros++;
+ //
+ // Found enough consecutive free space, break the loop
+ //
+ if (NumberOfZeros >= NumberOfMemoryUnit) {
+ break;
+ }
+ } else {
+ //
+ // Encountering a '1', meant the bit is ocupied.
+ //
+ if (NumberOfZeros >= NumberOfMemoryUnit) {
+ //
+ // Found enough consecutive free space,break the loop
+ //
+ break;
+ } else {
+ //
+ // the NumberOfZeros only record the number of those consecutive zeros,
+ // so reset the NumberOfZeros to 0 when encountering '1' before finding
+ // enough consecutive '0's
+ //
+ NumberOfZeros = 0;
+ //
+ // reset the (FoundBytePos,FoundBitPos) to the position of '1'
+ //
+ FoundBytePos = TempBytePos;
+ FoundBitPos = Index;
+ }
+ }
+ //
+ // right shift the byte
+ //
+ ByteValue /= 2;
+
+ //
+ // step forward a bit
+ //
+ Index++;
+ if (Index == 8) {
+ //
+ // step forward a byte, getting the byte value,
+ // and reset the bit pos.
+ //
+ TempBytePos += 1;
+ ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
+ Index = 0;
+ }
+ }
+
+ if (NumberOfZeros < NumberOfMemoryUnit) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Found enough free space.
+ //
+ //
+ // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
+ // 1)(FoundBytePos,FoundBitPos) record the position
+ // of the last '1' before the consecutive '0's, it must
+ // be adjusted to the start position of the consecutive '0's.
+ // 2)the start address of the consecutive '0's is just the start of
+ // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
+ //
+ if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {
+ FoundBitPos += 1;
+ }
+ //
+ // Have the (FoundBytePos,FoundBitPos) make sense.
+ //
+ if (FoundBitPos > 7) {
+ FoundBytePos += 1;
+ FoundBitPos -= 8;
+ }
+ //
+ // Set the memory as allocated
+ //
+ for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
+
+ MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));
+ Index++;
+ if (Index == 8) {
+ TempBytePos += 1;
+ Index = 0;
+ }
+ }
+
+ *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Uhci Free Pool.
+
+ @param UhcDev The UHCI device.
+ @param Pool A pointer to store the buffer address.
+ @param AllocSize The size of the pool to be freed.
+
+**/
+VOID
+UhcFreePool (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 *Pool,
+ IN UINTN AllocSize
+ )
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+ UINTN StartBytePos;
+ UINTN Index;
+ UINT8 StartBitPos;
+ UINT8 Index2;
+ UINTN Count;
+ UINTN RealAllocSize;
+
+ MemoryHeader = UhcDev->Header1;
+
+ //
+ // allocate unit is 32 byte (align on 32 byte)
+ //
+ if ((AllocSize & 0x1F) != 0) {
+ RealAllocSize = (AllocSize / 32 + 1) * 32;
+ } else {
+ RealAllocSize = AllocSize;
+ }
+
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
+ TempHeaderPtr = TempHeaderPtr->Next) {
+
+ if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
+ ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +
+ TempHeaderPtr->MemoryBlockSizeInBytes))) {
+
+ //
+ // Pool is in the Memory Block area,
+ // find the start byte and bit in the bit array
+ //
+ StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
+ StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
+
+ TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));
+ Index2++;
+ if (Index2 == 8) {
+ Index += 1;
+ Index2 = 0;
+ }
+ }
+ //
+ // break the loop
+ //
+ break;
+ }
+ }
+
+}
+
+/**
+ Insert a new memory header into list.
+
+ @param MemoryHeader A pointer to the memory header list.
+ @param NewMemoryHeader A new memory header to be inserted into the list.
+
+**/
+VOID
+InsertMemoryHeaderToList (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader
+ )
+{
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
+ if (TempHeaderPtr->Next == NULL) {
+ TempHeaderPtr->Next = NewMemoryHeader;
+ break;
+ }
+ }
+}
+
+
+
+
+
+/**
+ Map address of request structure buffer.
+
+ @param Uhc The UHCI device.
+ @param Request The user request buffer.
+ @param MappedAddr Mapped address of request.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user request.
+
+**/
+EFI_STATUS
+UhciMapUserRequest (
+ IN USB_UHC_DEV *Uhc,
+ IN OUT VOID *Request,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ )
+{
+ EFI_STATUS Status;
+ UINTN Len;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);
+ Status = IoMmuMap (
+ Uhc->IoMmu,
+ EdkiiIoMmuOperationBusMasterRead,
+ Request,
+ &Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (!EFI_ERROR (Status)) {
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ }
+
+ return Status;
+}
+
+/**
+ Map address of user data buffer.
+
+ @param Uhc The UHCI device.
+ @param Direction Direction of the data transfer.
+ @param Data The user data buffer.
+ @param Len Length of the user data.
+ @param PktId Packet identificaion.
+ @param MappedAddr Mapped address to return.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user data.
+
+**/
+EFI_STATUS
+UhciMapUserData (
+ IN USB_UHC_DEV *Uhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN OUT UINTN *Len,
+ OUT UINT8 *PktId,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Status = EFI_SUCCESS;
+
+ switch (Direction) {
+ case EfiUsbDataIn:
+ //
+ // BusMasterWrite means cpu read
+ //
+ *PktId = INPUT_PACKET_ID;
+ Status = IoMmuMap (
+ Uhc->IoMmu,
+ EdkiiIoMmuOperationBusMasterWrite,
+ Data,
+ Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ break;
+
+ case EfiUsbDataOut:
+ *PktId = OUTPUT_PACKET_ID;
+ Status = IoMmuMap (
+ Uhc->IoMmu,
+ EdkiiIoMmuOperationBusMasterRead,
+ Data,
+ Len,
+ &PhyAddr,
+ Map
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
+ break;
+
+ case EfiUsbNoData:
+ if ((Len != NULL) && (*Len != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ *PktId = OUTPUT_PACKET_ID;
+ *MappedAddr = NULL;
+ *Map = NULL;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+EXIT:
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h
new file mode 100644
index 000000000..9100cbeab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h
@@ -0,0 +1,1390 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RECOVERY_UHC_H_
+#define _RECOVERY_UHC_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbController.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeiServicesLib.h>
+
+#define USB_SLOW_SPEED_DEVICE 0x01
+#define USB_FULL_SPEED_DEVICE 0x02
+
+//
+// One memory block uses 16 page
+//
+#define NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES 16
+
+#define USBCMD 0 /* Command Register Offset 00-01h */
+#define USBCMD_RS BIT0 /* Run/Stop */
+#define USBCMD_HCRESET BIT1 /* Host reset */
+#define USBCMD_GRESET BIT2 /* Global reset */
+#define USBCMD_EGSM BIT3 /* Global Suspend Mode */
+#define USBCMD_FGR BIT4 /* Force Global Resume */
+#define USBCMD_SWDBG BIT5 /* SW Debug mode */
+#define USBCMD_CF BIT6 /* Config Flag (sw only) */
+#define USBCMD_MAXP BIT7 /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2 /* Status Register Offset 02-03h */
+#define USBSTS_USBINT BIT0 /* Interrupt due to IOC */
+#define USBSTS_ERROR BIT1 /* Interrupt due to error */
+#define USBSTS_RD BIT2 /* Resume Detect */
+#define USBSTS_HSE BIT3 /* Host System Error - basically PCI problems */
+#define USBSTS_HCPE BIT4 /* Host Controller Process Error - the scripts were buggy */
+#define USBSTS_HCH BIT5 /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4 /* Interrupt Enable Register 04-05h */
+#define USBINTR_TIMEOUT BIT0 /* Timeout/CRC error enable */
+#define USBINTR_RESUME BIT1 /* Resume interrupt enable */
+#define USBINTR_IOC BIT2 /* Interrupt On Complete enable */
+#define USBINTR_SP BIT3 /* Short packet interrupt enable */
+
+/* Frame Number Register Offset 06-08h */
+#define USBFRNUM 6
+
+/* Frame List Base Address Register Offset 08-0Bh */
+#define USBFLBASEADD 8
+
+/* Start of Frame Modify Register Offset 0Ch */
+#define USBSOF 0x0c
+
+/* USB port status and control registers */
+#define USBPORTSC1 0x10 /*Port 1 offset 10-11h */
+#define USBPORTSC2 0x12 /*Port 2 offset 12-13h */
+
+#define USBPORTSC_CCS BIT0 /* Current Connect Status ("device present") */
+#define USBPORTSC_CSC BIT1 /* Connect Status Change */
+#define USBPORTSC_PED BIT2 /* Port Enable / Disable */
+#define USBPORTSC_PEDC BIT3 /* Port Enable / Disable Change */
+#define USBPORTSC_LSL BIT4 /* Line Status Low bit*/
+#define USBPORTSC_LSH BIT5 /* Line Status High bit*/
+#define USBPORTSC_RD BIT6 /* Resume Detect */
+#define USBPORTSC_LSDA BIT8 /* Low Speed Device Attached */
+#define USBPORTSC_PR BIT9 /* Port Reset */
+#define USBPORTSC_SUSP BIT12 /* Suspend */
+
+#define SETUP_PACKET_ID 0x2D
+#define INPUT_PACKET_ID 0x69
+#define OUTPUT_PACKET_ID 0xE1
+#define ERROR_PACKET_ID 0x55
+
+#define STALL_1_MICRO_SECOND 1
+#define STALL_1_MILLI_SECOND 1000
+
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 FrameListPtrTerminate : 1;
+ UINT32 FrameListPtrQSelect : 1;
+ UINT32 FrameListRsvd : 2;
+ UINT32 FrameListPtr : 28;
+} FRAMELIST_ENTRY;
+
+typedef struct {
+ UINT32 QHHorizontalTerminate : 1;
+ UINT32 QHHorizontalQSelect : 1;
+ UINT32 QHHorizontalRsvd : 2;
+ UINT32 QHHorizontalPtr : 28;
+ UINT32 QHVerticalTerminate : 1;
+ UINT32 QHVerticalQSelect : 1;
+ UINT32 QHVerticalRsvd : 2;
+ UINT32 QHVerticalPtr : 28;
+} QUEUE_HEAD;
+
+typedef struct {
+ QUEUE_HEAD QueueHead;
+ UINT32 Reserved1;
+ UINT32 Reserved2;
+ VOID *PtrNext;
+ VOID *PtrDown;
+ VOID *Reserved3;
+ UINT32 Reserved4;
+} QH_STRUCT;
+
+typedef struct {
+ UINT32 TDLinkPtrTerminate : 1;
+ UINT32 TDLinkPtrQSelect : 1;
+ UINT32 TDLinkPtrDepthSelect : 1;
+ UINT32 TDLinkPtrRsvd : 1;
+ UINT32 TDLinkPtr : 28;
+ UINT32 TDStatusActualLength : 11;
+ UINT32 TDStatusRsvd : 5;
+ UINT32 TDStatus : 8;
+ UINT32 TDStatusIOC : 1;
+ UINT32 TDStatusIOS : 1;
+ UINT32 TDStatusLS : 1;
+ UINT32 TDStatusErr : 2;
+ UINT32 TDStatusSPD : 1;
+ UINT32 TDStatusRsvd2 : 2;
+ UINT32 TDTokenPID : 8;
+ UINT32 TDTokenDevAddr : 7;
+ UINT32 TDTokenEndPt : 4;
+ UINT32 TDTokenDataToggle : 1;
+ UINT32 TDTokenRsvd : 1;
+ UINT32 TDTokenMaxLen : 11;
+ UINT32 TDBufferPtr;
+} TD;
+
+typedef struct {
+ TD TDData;
+ UINT8 *PtrTDBuffer;
+ VOID *PtrNextTD;
+ VOID *PtrNextQH;
+ UINT16 TDBufferLength;
+ UINT16 Reserved;
+} TD_STRUCT;
+
+#pragma pack()
+
+typedef struct _MEMORY_MANAGE_HEADER MEMORY_MANAGE_HEADER;
+
+struct _MEMORY_MANAGE_HEADER {
+ UINT8 *BitArrayPtr;
+ UINTN BitArraySizeInBytes;
+ UINT8 *MemoryBlockPtr;
+ UINTN MemoryBlockSizeInBytes;
+ MEMORY_MANAGE_HEADER *Next;
+};
+
+#define USB_UHC_DEV_SIGNATURE SIGNATURE_32 ('p', 'u', 'h', 'c')
+typedef struct {
+ UINTN Signature;
+ PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ //
+ // EndOfPei callback is used to stop the UHC DMA operation
+ // after exit PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ UINT32 UsbHostControllerBaseAddress;
+ FRAMELIST_ENTRY *FrameListEntry;
+ QH_STRUCT *ConfigQH;
+ QH_STRUCT *BulkQH;
+ //
+ // Header1 used for QH,TD memory blocks management
+ //
+ MEMORY_MANAGE_HEADER *Header1;
+
+} USB_UHC_DEV;
+
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a) CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY(a) CR (a, USB_UHC_DEV, EndOfPeiNotifyList, USB_UHC_DEV_SIGNATURE)
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST * Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ );
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UhcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Initialize UHCI.
+
+ @param UhcDev UHCI Device.
+
+ @retval EFI_SUCCESS UHCI successfully initialized.
+ @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN USB_UHC_DEV *UhcDev
+ );
+
+/**
+ Create Frame List Structure.
+
+ @param UhcDev UHCI device.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateFrameList (
+ USB_UHC_DEV *UhcDev
+ );
+
+/**
+ Read a 16bit width data from Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+
+ @retval the register content read.
+
+**/
+UINT16
+USBReadPortW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port
+ );
+
+/**
+ Write a 16bit width data into Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+ @param Data The data written into the register.
+
+**/
+VOID
+USBWritePortW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port,
+ IN UINT16 Data
+ );
+
+/**
+ Write a 32bit width data into Uhc HC IO space register.
+
+ @param UhcDev The UHCI device.
+ @param Port The IO space address of the register.
+ @param Data The data written into the register.
+
+**/
+VOID
+USBWritePortDW (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Port,
+ IN UINT32 Data
+ );
+
+/**
+ Clear the content of UHCI's Status Register.
+
+ @param UhcDev The UHCI device.
+ @param StatusAddr The IO space address of the register.
+
+**/
+VOID
+ClearStatusReg (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 StatusAddr
+ );
+
+/**
+ Check whether the host controller operates well.
+
+ @param UhcDev The UHCI device.
+ @param StatusRegAddr The io address of status register.
+
+ @retval TRUE Host controller is working.
+ @retval FALSE Host controller is halted or system error.
+
+**/
+BOOLEAN
+IsStatusOK (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 StatusRegAddr
+ );
+
+/**
+ Set Frame List Base Address.
+
+ @param UhcDev The UHCI device.
+ @param FrameListRegAddr The address of frame list register.
+ @param Addr The address of frame list table.
+
+**/
+VOID
+SetFrameListBaseAddress (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 FrameListRegAddr,
+ IN UINT32 Addr
+ );
+
+/**
+ Create QH and initialize.
+
+ @param UhcDev The UHCI device.
+ @param PtrQH Place to store QH_STRUCT pointer.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateQH (
+ IN USB_UHC_DEV *UhcDev,
+ OUT QH_STRUCT **PtrQH
+ );
+
+/**
+ Set the horizontal link pointer in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrNext Place to the next QH_STRUCT.
+
+**/
+VOID
+SetQHHorizontalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *PtrNext
+ );
+
+/**
+ Set a QH or TD horizontally to be connected with a specific QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetQHHorizontalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsQH
+ );
+
+/**
+ Set the horizontal validor bit in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsValid Specify the horizontal linker is valid or not.
+
+**/
+VOID
+SetQHHorizontalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsValid
+ );
+
+/**
+ Set the vertical link pointer in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrNext Place to the next QH_STRUCT.
+
+**/
+VOID
+SetQHVerticalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *PtrNext
+ );
+
+/**
+ Set a QH or TD vertically to be connected with a specific QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetQHVerticalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsQH
+ );
+
+/**
+ Set the vertical validor bit in QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param IsValid Specify the vertical linker is valid or not.
+
+**/
+VOID
+SetQHVerticalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsValid
+ );
+
+
+/**
+ Allocate TD or QH Struct.
+
+ @param UhcDev The UHCI device.
+ @param Size The size of allocation.
+ @param PtrStruct Place to store TD_STRUCT pointer.
+
+ @return EFI_SUCCESS Allocate successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+AllocateTDorQHStruct (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT32 Size,
+ OUT VOID **PtrStruct
+ );
+
+/**
+ Create a TD Struct.
+
+ @param UhcDev The UHCI device.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+ @return EFI_SUCCESS Allocate successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+CreateTD (
+ IN USB_UHC_DEV *UhcDev,
+ OUT TD_STRUCT **PtrTD
+ );
+
+/**
+ Generate Setup Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param DeviceSpeed Device Speed.
+ @param DevRequest CPU memory address of request structure buffer to transfer.
+ @param RequestPhy PCI memory address of request structure buffer to transfer.
+ @param RequestLen Request length.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate setup stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+GenSetupStageTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 *DevRequest,
+ IN UINT8 *RequestPhy,
+ IN UINT8 RequestLen,
+ OUT TD_STRUCT **PtrTD
+ );
+
+/**
+ Generate Data Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param PtrData CPU memory address of user data buffer to transfer.
+ @param DataPhy PCI memory address of user data buffer to transfer.
+ @param Len Data length.
+ @param PktID PacketID.
+ @param Toggle Data toggle value.
+ @param DeviceSpeed Device Speed.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate data stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+GenDataTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 *PtrData,
+ IN UINT8 *DataPhy,
+ IN UINT8 Len,
+ IN UINT8 PktID,
+ IN UINT8 Toggle,
+ IN UINT8 DeviceSpeed,
+ OUT TD_STRUCT **PtrTD
+ );
+
+/**
+ Generate Status Stage TD.
+
+ @param UhcDev The UHCI device.
+ @param DevAddr Device address.
+ @param Endpoint Endpoint number.
+ @param PktID PacketID.
+ @param DeviceSpeed Device Speed.
+ @param PtrTD TD_STRUCT generated.
+
+ @return EFI_SUCCESS Generate status stage TD successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+
+**/
+EFI_STATUS
+CreateStatusTD (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 PktID,
+ IN UINT8 DeviceSpeed,
+ OUT TD_STRUCT **PtrTD
+ );
+
+/**
+ Set the link pointer validor bit in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsValid Specify the linker pointer is valid or not.
+
+**/
+VOID
+SetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsValid
+ );
+
+/**
+ Set the Link Pointer pointing to a QH or TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsQH Specify QH or TD is connected.
+
+**/
+VOID
+SetTDLinkPtrQHorTDSelect (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsQH
+ );
+
+/**
+ Set the traverse is depth-first or breadth-first.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsDepth Specify the traverse is depth-first or breadth-first.
+
+**/
+VOID
+SetTDLinkPtrDepthorBreadth (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsDepth
+ );
+
+/**
+ Set TD Link Pointer in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param PtrNext Place to the next TD_STRUCT.
+
+**/
+VOID
+SetTDLinkPtr (
+ IN TD_STRUCT *PtrTDStruct,
+ IN VOID *PtrNext
+ );
+
+/**
+ Get TD Link Pointer.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval Get TD Link Pointer in TD.
+
+**/
+VOID*
+GetTDLinkPtr (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+
+/**
+ Enable/Disable short packet detection mechanism.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsEnable Enable or disable short packet detection mechanism.
+
+**/
+VOID
+EnableorDisableTDShortPacket (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsEnable
+ );
+
+/**
+ Set the max error counter in TD.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param MaxErrors The number of allowable error.
+
+**/
+VOID
+SetTDControlErrorCounter (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT8 MaxErrors
+ );
+
+/**
+ Set the TD is targeting a low-speed device or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsLowSpeedDevice Whether The device is low-speed.
+
+**/
+VOID
+SetTDLoworFullSpeedDevice (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsLowSpeedDevice
+ );
+
+/**
+ Set the TD is isochronous transfer type or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsIsochronous Whether the transaction isochronous transfer type.
+
+**/
+VOID
+SetTDControlIsochronousorNot (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsIsochronous
+ );
+
+/**
+ Set if UCHI should issue an interrupt on completion of the frame
+ in which this TD is executed
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsSet Whether HC should issue an interrupt on completion.
+
+**/
+VOID
+SetorClearTDControlIOC (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsSet
+ );
+
+/**
+ Set if the TD is active and can be executed.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param IsActive Whether the TD is active and can be executed.
+
+**/
+VOID
+SetTDStatusActiveorInactive (
+ IN TD_STRUCT *PtrTDStruct,
+ IN BOOLEAN IsActive
+ );
+
+/**
+ Specifies the maximum number of data bytes allowed for the transfer.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param MaxLen The maximum number of data bytes allowed.
+
+ @retval The allowed maximum number of data.
+**/
+UINT16
+SetTDTokenMaxLength (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT16 MaxLen
+ );
+
+/**
+ Set the data toggle bit to DATA1.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+**/
+VOID
+SetTDTokenDataToggle1 (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Set the data toggle bit to DATA0.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+**/
+VOID
+SetTDTokenDataToggle0 (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Set EndPoint Number the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param EndPoint The Endport number of the target.
+
+**/
+VOID
+SetTDTokenEndPoint (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINTN EndPoint
+ );
+
+/**
+ Set Device Address the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param DevAddr The Device Address of the target.
+
+**/
+VOID
+SetTDTokenDeviceAddress (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINTN DevAddr
+ );
+
+/**
+ Set Packet Identification the TD is targeting at.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+ @param PacketID The Packet Identification of the target.
+
+**/
+VOID
+SetTDTokenPacketID (
+ IN TD_STRUCT *PtrTDStruct,
+ IN UINT8 PacketID
+ );
+
+/**
+ Set the beginning address of the data buffer that will be used
+ during the transaction.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+**/
+VOID
+SetTDDataBuffer (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether the TD is active.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The TD is active or not.
+
+**/
+BOOLEAN
+IsTDStatusActive (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether the TD is stalled.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The TD is stalled or not.
+
+**/
+BOOLEAN
+IsTDStatusStalled (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether Data Buffer Error is happened.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Data Buffer Error is happened or not.
+
+**/
+BOOLEAN
+IsTDStatusBufferError (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether Babble Error is happened.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Babble Error is happened or not.
+
+**/
+BOOLEAN
+IsTDStatusBabbleError (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether NAK is received.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The NAK is received or not.
+
+**/
+BOOLEAN
+IsTDStatusNAKReceived (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether CRC/Time Out Error is encountered.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The CRC/Time Out Error is encountered or not.
+
+**/
+BOOLEAN
+IsTDStatusCRCTimeOutError (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Detect whether Bitstuff Error is received.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The Bitstuff Error is received or not.
+
+**/
+BOOLEAN
+IsTDStatusBitStuffError (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Retrieve the actual number of bytes that were tansferred.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The actual number of bytes that were tansferred.
+
+**/
+UINT16
+GetTDStatusActualLength (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Retrieve the information of whether the Link Pointer field is valid or not.
+
+ @param PtrTDStruct Place to store TD_STRUCT pointer.
+
+ @retval The linker pointer field is valid or not.
+
+**/
+BOOLEAN
+GetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *PtrTDStruct
+ );
+
+/**
+ Count TD Number from PtrFirstTD.
+
+ @param PtrFirstTD Place to store TD_STRUCT pointer.
+
+ @retval The queued TDs number.
+
+**/
+UINTN
+CountTDsNumber (
+ IN TD_STRUCT *PtrFirstTD
+ );
+
+/**
+ Link TD To QH.
+
+ @param PtrQH Place to store QH_STRUCT pointer.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+LinkTDToQH (
+ IN QH_STRUCT *PtrQH,
+ IN TD_STRUCT *PtrTD
+ );
+
+/**
+ Link TD To TD.
+
+ @param PtrPreTD Place to store TD_STRUCT pointer.
+ @param PtrTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+LinkTDToTD (
+ IN TD_STRUCT *PtrPreTD,
+ IN TD_STRUCT *PtrTD
+ );
+
+/**
+ Execute Control Transfer.
+
+ @param UhcDev The UCHI device.
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param ActualLen Actual transfer Length.
+ @param TimeOut TimeOut value.
+ @param TransferResult Transfer Result.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+ExecuteControlTransfer (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrTD,
+ OUT UINTN *ActualLen,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Execute Bulk Transfer.
+
+ @param UhcDev The UCHI device.
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param ActualLen Actual transfer Length.
+ @param DataToggle DataToggle value.
+ @param TimeOut TimeOut value.
+ @param TransferResult Transfer Result.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+ExecBulkTransfer (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrTD,
+ IN OUT UINTN *ActualLen,
+ IN UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Delete Queued TDs.
+
+ @param UhcDev The UCHI device.
+ @param PtrFirstTD Place to store TD_STRUCT pointer.
+
+**/
+VOID
+DeleteQueuedTDs (
+ IN USB_UHC_DEV *UhcDev,
+ IN TD_STRUCT *PtrFirstTD
+ );
+
+/**
+ Check TDs Results.
+
+ @param PtrTD A pointer to TD_STRUCT data.
+ @param Result The result to return.
+ @param ErrTDPos The Error TD position.
+ @param ActualTransferSize Actual transfer size.
+
+ @retval The TD is executed successfully or not.
+
+**/
+BOOLEAN
+CheckTDsResults (
+ IN TD_STRUCT *PtrTD,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualTransferSize
+ );
+
+/**
+ Create Memory Block.
+
+ @param UhcDev The UCHI device.
+ @param MemoryHeader The Pointer to allocated memory block.
+ @param MemoryBlockSizeInPages The page size of memory block to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+CreateMemoryBlock (
+ IN USB_UHC_DEV *UhcDev,
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,
+ IN UINTN MemoryBlockSizeInPages
+ );
+
+/**
+ Initialize UHCI memory management.
+
+ @param UhcDev The UCHI device.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+InitializeMemoryManagement (
+ IN USB_UHC_DEV *UhcDev
+ );
+
+/**
+ Initialize UHCI memory management.
+
+ @param UhcDev The UCHI device.
+ @param Pool Buffer pointer to store the buffer pointer.
+ @param AllocSize The size of the pool to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+UhcAllocatePool (
+ IN USB_UHC_DEV *UhcDev,
+ OUT UINT8 **Pool,
+ IN UINTN AllocSize
+ );
+
+/**
+ Alloc Memory In MemoryBlock.
+
+ @param MemoryHeader The pointer to memory manage header.
+ @param Pool Buffer pointer to store the buffer pointer.
+ @param NumberOfMemoryUnit The size of the pool to be allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_SUCCESS Success.
+
+**/
+EFI_STATUS
+AllocMemInMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ OUT VOID **Pool,
+ IN UINTN NumberOfMemoryUnit
+ );
+
+/**
+ Uhci Free Pool.
+
+ @param UhcDev The UHCI device.
+ @param Pool A pointer to store the buffer address.
+ @param AllocSize The size of the pool to be freed.
+
+**/
+VOID
+UhcFreePool (
+ IN USB_UHC_DEV *UhcDev,
+ IN UINT8 *Pool,
+ IN UINTN AllocSize
+ );
+
+/**
+ Insert a new memory header into list.
+
+ @param MemoryHeader A pointer to the memory header list.
+ @param NewMemoryHeader A new memory header to be inserted into the list.
+
+**/
+VOID
+InsertMemoryHeaderToList (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader
+ );
+
+
+/**
+ Map address of request structure buffer.
+
+ @param Uhc The UHCI device.
+ @param Request The user request buffer.
+ @param MappedAddr Mapped address of request.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user request.
+
+**/
+EFI_STATUS
+UhciMapUserRequest (
+ IN USB_UHC_DEV *Uhc,
+ IN OUT VOID *Request,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ );
+
+/**
+ Map address of user data buffer.
+
+ @param Uhc The UHCI device.
+ @param Direction Direction of the data transfer.
+ @param Data The user data buffer.
+ @param Len Length of the user data.
+ @param PktId Packet identificaion.
+ @param MappedAddr Mapped address to return.
+ @param Map Identificaion of this mapping to return.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail to map the user data.
+
+**/
+EFI_STATUS
+UhciMapUserData (
+ IN USB_UHC_DEV *Uhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN OUT UINTN *Len,
+ OUT UINT8 *PktId,
+ OUT UINT8 **MappedAddr,
+ OUT VOID **Map
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+IoMmuUnmap (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+
+/**
+ Initialize IOMMU.
+
+ @param IoMmu Pointer to pointer to IOMMU PPI.
+
+**/
+VOID
+IoMmuInit (
+ OUT EDKII_IOMMU_PPI **IoMmu
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf
new file mode 100644
index 000000000..06515b7ca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf
@@ -0,0 +1,60 @@
+## @file
+# The UhcPeim driver is responsible for managing the behavior of UHCI controller at PEI phase.
+#
+# It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used
+# to enable recovery function from USB Drivers.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UhciPei
+ MODULE_UNI_FILE = UhciPei.uni
+ FILE_GUID = C463CEAC-FC57-4f36-88B7-356C750C3BCA
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = UhcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UhcPeim.c
+ UhcPeim.h
+ DmaMem.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+
+
+[Ppis]
+ gPeiUsbHostControllerPpiGuid ## PRODUCES
+ gPeiUsbControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UhciPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.uni
new file mode 100644
index 000000000..04bdb8a25
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The UhcPeim driver is responsible for managing the behavior of UHCI controller at PEI phase.
+//
+// It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used
+// to enable recovery function from USB Drivers.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the behavior of UHCI controller at PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid, which is used to enable recovery function from USB Drivers."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPeiExtra.uni
new file mode 100644
index 000000000..4641a7b3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/UhciPei/UhciPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UhciPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UHCI PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c
new file mode 100644
index 000000000..9e2697b82
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c
@@ -0,0 +1,217 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for XHCI driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Xhci.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gXhciComponentName = {
+ XhciComponentNameGetDriverName,
+ XhciComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gXhciComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) XhciComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) XhciComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mXhciDriverNameTable[] = {
+ { "eng;en", L"Usb Xhci 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
+XhciComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mXhciDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gXhciComponentName)
+ );
+}
+
+/**
+ 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 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 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
+XhciComponentNameGetControllerName (
+ 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_USB2_HC_PROTOCOL *Usb2Hc;
+ USB_XHCI_INSTANCE *XhciDev;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gXhciDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ gXhciDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ XhciDev = XHC_FROM_THIS (Usb2Hc);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ XhciDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gXhciComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h
new file mode 100644
index 000000000..13fbde165
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h
@@ -0,0 +1,140 @@
+/** @file
+
+ This file contains the delarations for componet name routines.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_COMPONENT_NAME_H_
+#define _EFI_COMPONENT_NAME_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
+XhciComponentNameGetDriverName (
+ 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 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 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
+XhciComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c
new file mode 100644
index 000000000..aa69c47aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.c
@@ -0,0 +1,752 @@
+/** @file
+
+ Routine procedures for memory allocate/free.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Xhci.h"
+
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ UINTN Bytes;
+ EFI_STATUS Status;
+
+ PciIo = Pool->PciIo;
+
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
+ if (Block == NULL) {
+ return NULL;
+ }
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+ Block->Bits = AllocateZeroPool (Block->BitsLen);
+
+ if (Block->Bits == NULL) {
+ gBS->FreePool (Block);
+ return NULL;
+ }
+
+ //
+ // Allocate the number of Pages of memory, then map it for
+ // bus master read and write.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &BufHost,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_BITARRAY;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ BufHost,
+ &Bytes,
+ &MappedAddr,
+ &Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+ goto FREE_BUFFER;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+
+ return Block;
+
+FREE_BUFFER:
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);
+
+FREE_BITARRAY:
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+ return NULL;
+}
+
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ PciIo = Pool->PciIo;
+
+ //
+ // Unmap the common buffer then free the structures
+ //
+ PciIo->Unmap (PciIo, Block->Mapping);
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
+
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+}
+
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return The pci memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddrForHostAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+/**
+ Calculate the corresponding host address according to the pci address.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to pci memory.
+ @param Size The size of the memory region.
+
+ @return The host memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetHostAddrForPciAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS HostAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->Buf;
+ HostAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->BufHost + Offset);
+ return HostAddr;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Unlink the memory block from the pool's list.
+
+ @param Head The block list head of the memory's pool.
+ @param BlockToUnlink The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *BlockToUnlink
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ if (Block->Next == BlockToUnlink) {
+ Block->Next = BlockToUnlink->Next;
+ BlockToUnlink->Next = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ USBHC_MEM_POOL *Pool;
+
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
+
+ if (Pool == NULL) {
+ return Pool;
+ }
+
+ Pool->PciIo = PciIo;
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ gBS->FreePool (Pool);
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UsbHcUnlinkMemBlock (Pool->Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+ gBS->FreePool (Pool);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+ if (NewBlock == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbHcAllocateMem: failed to allocate block\n"));
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcUnlinkMemBlock (Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
+
+/**
+ Allocates pages at a specified alignment that are suitable for an EfiPciIoOperationBusMasterCommonBuffer mapping.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to
+ use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS Success to allocate aligned pages.
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
+
+
+**/
+EFI_STATUS
+UsbHcAllocateAlignedPages (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+ UINTN Bytes;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if ((Alignment & (Alignment - 1)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Pages == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ RealPages,
+ &Memory,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = PciIo->FreeBuffer (PciIo, UnalignedPages, Memory);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &Memory,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ (VOID *) AlignedMemory,
+ &Bytes,
+ DeviceAddress,
+ Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+ Status = PciIo->FreeBuffer (PciIo, Pages, (VOID *) AlignedMemory);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *HostAddress = (VOID *) AlignedMemory;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param Pages The number of 4 KB pages to free.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+UsbHcFreeAlignedPages (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN VOID *HostAddress,
+ IN UINTN Pages,
+ VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+
+ Status = PciIo->Unmap (PciIo, Mapping);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PciIo->FreeBuffer (
+ PciIo,
+ Pages,
+ HostAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.h
new file mode 100644
index 000000000..319110da3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/UsbHcMem.h
@@ -0,0 +1,207 @@
+/** @file
+
+ This file contains the definination for host controller memory management routines.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_XHCI_MEM_H_
+#define _EFI_XHCI_MEM_H_
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. XHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ );
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return The pci memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddrForHostAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding host address according to the pci address.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to pci memory.
+ @param Size The size of the memory region.
+
+ @return The host memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetHostAddrForPciAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Allocates pages at a specified alignment that are suitable for an EfiPciIoOperationBusMasterCommonBuffer mapping.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to
+ use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS Success to allocate aligned pages.
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
+
+
+**/
+EFI_STATUS
+UsbHcAllocateAlignedPages (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param Pages The number of pages to free.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+UsbHcFreeAlignedPages (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN VOID *HostAddress,
+ IN UINTN Pages,
+ VOID *Mapping
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
new file mode 100644
index 000000000..43c53bad4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
@@ -0,0 +1,2236 @@
+/** @file
+ The XHCI controller driver.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Xhci.h"
+
+//
+// Two arrays used to translate the XHCI port state (change)
+// to the UEFI protocol's port state (change).
+//
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {
+ {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
+ {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},
+ {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
+ {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
+};
+
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
+ {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
+ {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
+ {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
+ {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
+};
+
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
+ {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_PORTSC_PRC, EfiUsbPortResetChange}
+};
+
+USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
+ {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
+ {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
+ {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
+ {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
+};
+
+USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
+ {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
+ {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
+ {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
+ {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
+};
+
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
+ {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
+ {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {
+ XhcDriverBindingSupported,
+ XhcDriverBindingStart,
+ XhcDriverBindingStop,
+ 0x30,
+ NULL,
+ NULL
+};
+
+//
+// Template for Xhci's Usb2 Host Controller Protocol Instance.
+//
+EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = {
+ XhcGetCapability,
+ XhcReset,
+ XhcGetState,
+ XhcSetState,
+ XhcControlTransfer,
+ XhcBulkTransfer,
+ XhcAsyncInterruptTransfer,
+ XhcSyncInterruptTransfer,
+ XhcIsochronousTransfer,
+ XhcAsyncIsochronousTransfer,
+ XhcGetRootHubPortStatus,
+ XhcSetRootHubPortFeature,
+ XhcClearRootHubPortFeature,
+ 0x3,
+ 0x0
+};
+
+/**
+ Retrieves the capability of root hub ports.
+
+ @param This The EFI_USB2_HC_PROTOCOL instance.
+ @param MaxSpeed Max speed supported by the controller.
+ @param PortNumber Number of the root hub ports.
+ @param Is64BitCapable Whether the controller supports 64-bit memory
+ addressing.
+
+ @retval EFI_SUCCESS Host controller capability were retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetCapability (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *PortNumber,
+ OUT UINT8 *Is64BitCapable
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_TPL OldTpl;
+
+ if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+ *MaxSpeed = EFI_USB_SPEED_SUPER;
+ *PortNumber = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);
+ *Is64BitCapable = (UINT8) Xhc->Support64BitDma;
+ DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcReset (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ Xhc = XHC_FROM_THIS (This);
+
+ if (Xhc->DevicePath != NULL) {
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
+ Xhc->DevicePath
+ );
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ switch (Attributes) {
+ case EFI_USB_HC_RESET_GLOBAL:
+ //
+ // Flow through, same behavior as Host Controller Reset
+ //
+ case EFI_USB_HC_RESET_HOST_CONTROLLER:
+ if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&
+ ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0)) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+ //
+ // Host Controller must be Halt when Reset it
+ //
+ if (!XhcIsHalt (Xhc)) {
+ Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ }
+
+ Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
+ ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ //
+ // Clean up the asynchronous transfers, currently only
+ // interrupt supports asynchronous operation.
+ //
+ XhciDelAllAsyncIntTransfers (Xhc);
+ XhcFreeSched (Xhc);
+
+ XhcInitSched (Xhc);
+ break;
+
+ case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
+ case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcReset: status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Retrieve the current state of the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State Variable to return the current host controller
+ state.
+
+ @retval EFI_SUCCESS Host controller state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to
+ retrieve the host controller's current state.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_TPL OldTpl;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
+ *State = EfiUsbHcStateHalt;
+ } else {
+ *State = EfiUsbHcStateOperational;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcGetState: current state %d\n", *State));
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the USB host controller to a specific state.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State The state of the host controller that will be set.
+
+ @retval EFI_SUCCESS The USB host controller was successfully placed
+ in the state specified by State.
+ @retval EFI_INVALID_PARAMETER State is invalid.
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_STATUS Status;
+ EFI_USB_HC_STATE CurState;
+ EFI_TPL OldTpl;
+
+ Status = XhcGetState (This, &CurState);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (CurState == State) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ switch (State) {
+ case EfiUsbHcStateHalt:
+ Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbHcStateOperational:
+ if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ //
+ // Software must not write a one to this field unless the host controller
+ // is in the Halted state. Doing so will yield undefined results.
+ // refers to Spec[XHCI1.0-2.3.1]
+ //
+ if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbHcStateSuspend:
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcSetState: status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber The root hub port to retrieve the state from.
+ This value is zero-based.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetRootHubPortStatus (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ UINTN Index;
+ UINTN MapSize;
+ EFI_STATUS Status;
+ USB_DEV_ROUTE ParentRouteChart;
+ EFI_TPL OldTpl;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = Xhc->HcSParams1.Data.MaxPorts;
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ State = XhcReadOpReg (Xhc, Offset);
+
+ //
+ // According to XHCI 1.1 spec November 2017,
+ // bit 10~13 of the root port status register identifies the speed of the attached device.
+ //
+ switch ((State & XHC_PORTSC_PS) >> 10) {
+ case 2:
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ break;
+
+ case 3:
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ break;
+
+ case 4:
+ case 5:
+ PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // Convert the XHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
+ }
+ }
+ //
+ // Bit5~8 reflects its current link state.
+ //
+ if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
+ XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
+ }
+ }
+
+ //
+ // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
+ // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
+ //
+ ParentRouteChart.Dword = 0;
+ XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
+ State = XhcReadOpReg (Xhc, Offset);
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bit
+ //
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
+ // A port may be disabled by software writing a '1' to this flag.
+ //
+ Status = EFI_SUCCESS;
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= XHC_PORTSC_LWS;
+ XhcWriteOpReg (Xhc, Offset, State);
+ State &= ~XHC_PORTSC_PLS;
+ State |= (3 << 5) ;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ DEBUG ((EFI_D_INFO, "XhcUsbPortReset!\n"));
+ //
+ // Make sure Host Controller not halt before reset it
+ //
+ if (XhcIsHalt (Xhc)) {
+ Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
+ break;
+ }
+ }
+
+ //
+ // 4.3.1 Resetting a Root Hub Port
+ // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
+ //
+ State |= XHC_PORTSC_RESET;
+ XhcWriteOpReg (Xhc, Offset, State);
+ XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbPortPower:
+ //
+ // Not supported, ignore the operation
+ //
+ Status = EFI_SUCCESS;
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // XHCI root hub port don't has the owner bit, ignore the operation
+ //
+ Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcClearRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ UINT32 TotalPort;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
+
+ if (PortNumber >= TotalPort) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bit
+ //
+ State = XhcReadOpReg (Xhc, Offset);
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
+ // A port may be disabled by software writing a '1' to this flag.
+ //
+ State |= XHC_PORTSC_PED;
+ State &= ~XHC_PORTSC_RESET;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= XHC_PORTSC_LWS;
+ XhcWriteOpReg (Xhc, Offset, State);
+ State &= ~XHC_PORTSC_PLS;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
+ // Register bits indicate status when read, a clear bit may be set by
+ // writing a '1'. Writing a '0' to RW1S bits has no effect.
+ //
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // XHCI root hub port don't has the owner bit, ignore the operation
+ //
+ break;
+
+ case EfiUsbPortConnectChange:
+ //
+ // Clear connect status change
+ //
+ State |= XHC_PORTSC_CSC;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortEnableChange:
+ //
+ // Clear enable status change
+ //
+ State |= XHC_PORTSC_PEC;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ //
+ // Clear PortOverCurrent change
+ //
+ State |= XHC_PORTSC_OCC;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortResetChange:
+ //
+ // Clear Port Reset change
+ //
+ State |= XHC_PORTSC_PRC;
+ XhcWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortPower:
+ case EfiUsbPortSuspendChange:
+ //
+ // Not supported or not related operation
+ //
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Submits a new transaction to a target USB device.
+
+ @param Xhc The XHCI Instance.
+ @param DeviceAddress The target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Type The transaction type.
+ @param Request USB device request to send.
+ @param Data Data buffer to be transmitted or received from USB
+ device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param Timeout Indicates the maximum timeout, in millisecond.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+**/
+EFI_STATUS
+XhcTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *TransferResult
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS RecoveryStatus;
+ URB *Urb;
+
+ ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));
+ Urb = XhcCreateUrb (
+ Xhc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ Type,
+ Request,
+ Data,
+ *DataLength,
+ NULL,
+ NULL
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
+
+ if (Status == EFI_TIMEOUT) {
+ //
+ // The transfer timed out. Abort the transfer by dequeueing of the TD.
+ //
+ RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
+ if (RecoveryStatus == EFI_ALREADY_STARTED) {
+ //
+ // The URB is finished just before stopping endpoint.
+ // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.
+ //
+ ASSERT (Urb->Result == EFI_USB_NOERROR);
+ Status = EFI_SUCCESS;
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));
+ } else if (EFI_ERROR(RecoveryStatus)) {
+ DEBUG((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));
+ }
+ }
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
+ ASSERT (Status == EFI_DEVICE_ERROR);
+ RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
+ if (EFI_ERROR (RecoveryStatus)) {
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));
+ }
+ }
+
+ Xhc->PciIo->Flush (Xhc->PciIo);
+ XhcFreeUrb (Xhc, Urb);
+ return Status;
+}
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage
+ @param Data Data buffer to be transmitted or received from USB
+ device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param Timeout Indicates the maximum timeout, in millisecond.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcControlTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT8 Endpoint;
+ UINT8 Index;
+ UINT8 DescriptorType;
+ UINT8 SlotId;
+ UINT8 TTT;
+ UINT8 MTT;
+ UINT32 MaxPacket0;
+ EFI_USB_HUB_DESCRIPTOR *HubDesc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINTN MapSize;
+ EFI_USB_PORT_STATUS PortStatus;
+ UINT32 State;
+ EFI_USB_DEVICE_REQUEST ClearPortRequest;
+ UINTN Len;
+
+ //
+ // Validate parameters
+ //
+ if ((Request == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbDataIn) &&
+ (TransferDirection != EfiUsbDataOut) &&
+ (TransferDirection != EfiUsbNoData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection == EfiUsbNoData) &&
+ ((Data != NULL) || (*DataLength != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) &&
+ ((Data == NULL) || (*DataLength == 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
+ (MaximumPacketLength != 512)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ Status = EFI_DEVICE_ERROR;
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Len = 0;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Hook the Set_Address request from UsbBus.
+ // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
+ //
+ if ((Request->Request == USB_REQ_SET_ADDRESS) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
+ //
+ // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
+ // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) {
+ Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // The actual device address has been assigned by XHCI during initializing the device slot.
+ // So we just need establish the mapping relationship between the device address requested from UsbBus
+ // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface
+ // can find out the actual device address by it.
+ //
+ Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ // Note that we encode the direction in address although default control
+ // endpoint is bidirectional. XhcCreateUrb expects this
+ // combination of Ep addr and its direction.
+ //
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
+ Status = XhcTransfer (
+ Xhc,
+ DeviceAddress,
+ Endpoint,
+ DeviceSpeed,
+ MaximumPacketLength,
+ XHC_CTRL_TRANSFER,
+ Request,
+ Data,
+ DataLength,
+ Timeout,
+ TransferResult
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
+ // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.
+ //
+ if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
+ DescriptorType = (UINT8)(Request->Value >> 8);
+ if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
+ ASSERT (Data != NULL);
+ //
+ // Store a copy of device scriptor as hub device need this info to configure endpoint.
+ //
+ CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
+ if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
+ //
+ // If it's a usb3.0 device, then its max packet size is a 2^n.
+ //
+ MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
+ } else {
+ MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
+ }
+ Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);
+ } else {
+ Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);
+ }
+ } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
+ ASSERT (Data != NULL);
+ if (*DataLength == ((UINT16 *)Data)[1]) {
+ //
+ // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
+ //
+ Index = (UINT8)Request->Value;
+ ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
+ Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);
+ CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
+ //
+ // Default to use AlternateSetting 0 for all interfaces.
+ //
+ Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));
+ }
+ } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
+ (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
+ ASSERT (Data != NULL);
+ HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;
+ ASSERT (HubDesc->NumPorts <= 15);
+ //
+ // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
+ //
+ TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
+ if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
+ //
+ // Don't support multi-TT feature for super speed hub now.
+ //
+ MTT = 0;
+ DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
+ } else {
+ MTT = 0;
+ }
+
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
+ } else {
+ Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
+ }
+ }
+ } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
+ //
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.
+ //
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ } else {
+ Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ break;
+ }
+ }
+ } else if ((Request->Request == USB_REQ_SET_INTERFACE) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE))) {
+ //
+ // Hook Set_Interface request from UsbBus as we need configure interface setting.
+ // Request->Value indicates AlterlateSetting to set
+ // Request->Index indicates Interface to set
+ //
+ if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] != (UINT8) Request->Value) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
+ } else {
+ Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
+ }
+ }
+ } else if ((Request->Request == USB_REQ_GET_STATUS) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
+ ASSERT (Data != NULL);
+ //
+ // Hook Get_Status request from UsbBus to keep track of the port status change.
+ //
+ State = *(UINT32 *)Data;
+ PortStatus.PortStatus = 0;
+ PortStatus.PortChangeStatus = 0;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // For super speed hub, its bit10~12 presents the attached device speed.
+ //
+ if ((State & XHC_PORTSC_PS) >> 10 == 0) {
+ PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
+ }
+ } else {
+ //
+ // For high or full/low speed hub, its bit9~10 presents the attached device speed.
+ //
+ if (XHC_BIT_IS_SET (State, BIT9)) {
+ PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ } else if (XHC_BIT_IS_SET (State, BIT10)) {
+ PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ }
+ }
+
+ //
+ // Convert the XHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
+ PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
+ PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
+ ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+ ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
+ ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
+ ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
+ ClearPortRequest.Index = Request->Index;
+ ClearPortRequest.Length = 0;
+
+ XhcControlTransfer (
+ This,
+ DeviceAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ &ClearPortRequest,
+ EfiUsbNoData,
+ NULL,
+ &Len,
+ Timeout,
+ Translator,
+ TransferResult
+ );
+ }
+ }
+
+ XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
+
+ *(UINT32 *)Data = *(UINT32*)&PortStatus;
+ }
+
+ON_EXIT:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param DeviceSpeed Device speed, Low speed device doesn't support bulk
+ transfer.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to
+ use of the subsequent bulk transfer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcBulkTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT8 SlotId;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||
+ ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: HC is halted\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Status = XhcTransfer (
+ Xhc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ XHC_BULK_TRANSFER,
+ NULL,
+ Data[0],
+ DataLength,
+ Timeout,
+ TransferResult
+ );
+
+ON_EXIT:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Submits an asynchronous interrupt transfer to an
+ interrupt endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
+ transfer If FALSE, to remove the specified
+ asynchronous interrupt.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param PollingInterval The he interval, in milliseconds, that the transfer
+ is polled.
+ @param DataLength The length of data to receive at the rate specified
+ by PollingInterval.
+ @param Translator Transaction translator to use.
+ @param CallBackFunction Function to call at the rate specified by
+ PollingInterval.
+ @param Context Context to CallBackFunction.
+
+ @retval EFI_SUCCESS The request has been successfully submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcAsyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context OPTIONAL
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ URB *Urb;
+ EFI_STATUS Status;
+ UINT8 SlotId;
+ UINT8 Index;
+ EFI_TPL OldTpl;
+
+ //
+ // Validate parameters
+ //
+ if (!XHCI_IS_DATAIN (EndPointAddress)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsNewTransfer) {
+ if (DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((PollingInterval > 255) || (PollingInterval < 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ //
+ // Delete Async interrupt transfer request.
+ //
+ if (!IsNewTransfer) {
+ //
+ // The delete request may happen after device is detached.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {
+ break;
+ }
+ }
+
+ if (Index == 255) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
+ DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
+ goto ON_EXIT;
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ Urb = XhciInsertAsyncIntTransfer (
+ Xhc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ DataLength,
+ CallBackFunction,
+ Context
+ );
+ if (Urb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Ring the doorbell
+ //
+ Status = RingIntTransferDoorBell (Xhc, Urb);
+
+ON_EXIT:
+ Xhc->PciIo->Flush (Xhc->PciIo);
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ of sending or receiving.
+ @param Data Buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param DataLength On input, the size, in bytes, of the data buffer; On
+ output, the number of bytes transferred.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param Timeout Maximum time, in second, to complete.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_SUCCESS The transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT The transfer failed due to timeout.
+ @return EFI_DEVICE_ERROR The failed due to host controller or device error
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ UINT8 SlotId;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Validates parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = XHC_FROM_THIS (This);
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ Status = XhcTransfer (
+ Xhc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ XHC_INT_TRANSFER_SYNC,
+ NULL,
+ Data,
+ DataLength,
+ Timeout,
+ TransferResult
+ );
+
+ON_EXIT:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Submits isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Submits Async isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param IsochronousCallBack Function to be called when the transfer complete.
+ @param Context Context passed to the call back function as
+ parameter.
+
+ @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcAsyncIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Success.
+ @retval Others Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gXhciDriverBinding,
+ ImageHandle,
+ &gXhciComponentName,
+ &gXhciComponentName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has Usb2HcProtocol installed will
+ be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_CLASSC UsbClassCReg;
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Test whether the controller belongs to Xhci type
+ //
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
+ (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Create and initialize a USB_XHCI_INSTANCE structure.
+
+ @param PciIo The PciIo on this device.
+ @param DevicePath The device path of host controller.
+ @param OriginalPciAttributes Original PCI attributes.
+
+ @return The allocated and initialized USB_XHCI_INSTANCE structure if created,
+ otherwise NULL.
+
+**/
+USB_XHCI_INSTANCE*
+XhcCreateUsbHc (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT64 OriginalPciAttributes
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_STATUS Status;
+ UINT32 PageSize;
+ UINT16 ExtCapReg;
+ UINT8 ReleaseNumber;
+
+ Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));
+
+ if (Xhc == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initialize private data structure
+ //
+ Xhc->Signature = XHCI_INSTANCE_SIG;
+ Xhc->PciIo = PciIo;
+ Xhc->DevicePath = DevicePath;
+ Xhc->OriginalPciAttributes = OriginalPciAttributes;
+ CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ XHC_PCI_SBRN_OFFSET,
+ 1,
+ &ReleaseNumber
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;
+ Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);
+ }
+
+ InitializeListHead (&Xhc->AsyncIntTransfers);
+
+ //
+ // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
+ //
+ Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);
+ Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);
+ Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);
+ Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);
+ Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);
+ Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);
+
+ //
+ // This PageSize field defines the page size supported by the xHC implementation.
+ // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
+ // if bit 0 is Set, the xHC supports 4k byte page sizes.
+ //
+ PageSize = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
+ Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12);
+
+ ExtCapReg = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);
+ Xhc->ExtCapRegBase = ExtCapReg << 2;
+ Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);
+ Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);
+
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));
+
+ //
+ // Create AsyncRequest Polling Timer
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ XhcMonitorAsyncRequests,
+ Xhc,
+ &Xhc->PollTimer
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return Xhc;
+
+ON_ERROR:
+ FreePool (Xhc);
+ return NULL;
+}
+
+/**
+ One notified function to stop the Host Controller when gBS->ExitBootServices() called.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+XhcExitBootService (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+
+{
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ Xhc = (USB_XHCI_INSTANCE*) Context;
+ PciIo = Xhc->PciIo;
+
+ //
+ // Stop AsyncRequest Polling timer then stop the XHCI driver
+ // and uninstall the XHCI protocl.
+ //
+ gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
+ XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+
+ if (Xhc->PollTimer != NULL) {
+ gBS->CloseEvent (Xhc->PollTimer);
+ }
+
+ XhcClearBiosOwnership (Xhc);
+
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Xhc->OriginalPciAttributes,
+ NULL
+ );
+}
+
+/**
+ Starting the Usb XHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS supports this device.
+ @return EFI_UNSUPPORTED do not support this device.
+ @return EFI_DEVICE_ERROR cannot be started due to device Error.
+ @return EFI_OUT_OF_RESOURCES cannot allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ UINT64 OriginalPciAttributes;
+ BOOLEAN PciAttributesSaved;
+ USB_XHCI_INSTANCE *Xhc;
+ EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
+
+ //
+ // Open the PciIo Protocol, then enable the USB host controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open Device Path Protocol for on USB host controller
+ //
+ HcDevicePath = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &HcDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ PciAttributesSaved = FALSE;
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ PciAttributesSaved = TRUE;
+
+ 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)) {
+ DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));
+ goto CLOSE_PCIIO;
+ }
+
+ //
+ // Create then install USB2_HC_PROTOCOL
+ //
+ Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);
+
+ if (Xhc == NULL) {
+ DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if (Xhc->HcCParams.Data.Ac64 != 0) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Xhc->Support64BitDma = TRUE;
+ } else {
+ DEBUG ((EFI_D_WARN,
+ "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
+ __FUNCTION__, Controller, Status));
+ }
+ }
+
+ XhcSetBiosOwnership (Xhc);
+
+ XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
+ ASSERT (XhcIsHalt (Xhc));
+
+ //
+ // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
+ // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
+ //
+ ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
+
+ //
+ // Initialize the schedule
+ //
+ XhcInitSched (Xhc);
+
+ //
+ // Start the Host Controller
+ //
+ XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT);
+
+ //
+ // Start the asynchronous interrupt monitor
+ //
+ Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
+ XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+ goto FREE_POOL;
+ }
+
+ //
+ // Create event to stop the HC when exit boot service.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ XhcExitBootService,
+ Xhc,
+ &gEfiEventExitBootServicesGuid,
+ &Xhc->ExitBootServiceEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto FREE_POOL;
+ }
+
+ //
+ // Install the component name protocol, don't fail the start
+ // because of something for display.
+ //
+ AddUnicodeString2 (
+ "eng",
+ gXhciComponentName.SupportedLanguages,
+ &Xhc->ControllerNameTable,
+ L"eXtensible Host Controller (USB 3.0)",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gXhciComponentName2.SupportedLanguages,
+ &Xhc->ControllerNameTable,
+ L"eXtensible Host Controller (USB 3.0)",
+ FALSE
+ );
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiUsb2HcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Xhc->Usb2Hc
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
+ goto FREE_POOL;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));
+ return EFI_SUCCESS;
+
+FREE_POOL:
+ gBS->CloseEvent (Xhc->PollTimer);
+ XhcFreeSched (Xhc);
+ FreePool (Xhc);
+
+CLOSE_PCIIO:
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalPciAttributes,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_XHCI_INSTANCE *Xhc;
+ UINT8 Index;
+
+ //
+ // Test whether the Controller handler passed in is a valid
+ // Usb controller handle that should be supported, if not,
+ // return the error status directly
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ Usb2Hc
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Xhc = XHC_FROM_THIS (Usb2Hc);
+ PciIo = Xhc->PciIo;
+
+ //
+ // Stop AsyncRequest Polling timer then stop the XHCI driver
+ // and uninstall the XHCI protocl.
+ //
+ gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
+
+ //
+ // Disable the device slots occupied by these devices on its downstream ports.
+ // Entry 0 is reserved.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0)) {
+ continue;
+ }
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+ } else {
+ XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+ }
+ }
+
+ if (Xhc->PollTimer != NULL) {
+ gBS->CloseEvent (Xhc->PollTimer);
+ }
+
+ if (Xhc->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (Xhc->ExitBootServiceEvent);
+ }
+
+ XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+ XhcClearBiosOwnership (Xhc);
+ XhciDelAllAsyncIntTransfers (Xhc);
+ XhcFreeSched (Xhc);
+
+ if (Xhc->ControllerNameTable) {
+ FreeUnicodeStringTable (Xhc->ControllerNameTable);
+ }
+
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Xhc->OriginalPciAttributes,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (Xhc);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
new file mode 100644
index 000000000..3285eb879
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
@@ -0,0 +1,722 @@
+/** @file
+
+ Provides some data structure definitions used by the XHCI host controller driver.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_XHCI_H_
+#define _EFI_XHCI_H_
+
+#include <Uefi.h>
+
+#include <Protocol/Usb2HostController.h>
+#include <Protocol/PciIo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+typedef struct _USB_XHCI_INSTANCE USB_XHCI_INSTANCE;
+typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;
+
+#include "XhciReg.h"
+#include "XhciSched.h"
+#include "ComponentName.h"
+#include "UsbHcMem.h"
+
+//
+// The unit is microsecond, setting it as 1us.
+//
+#define XHC_1_MICROSECOND (1)
+//
+// The unit is microsecond, setting it as 1ms.
+//
+#define XHC_1_MILLISECOND (1000)
+//
+// XHC generic timeout experience values.
+// The unit is millisecond, setting it as 10s.
+//
+#define XHC_GENERIC_TIMEOUT (10 * 1000)
+//
+// XHC reset timeout experience values.
+// The unit is millisecond, setting it as 1s.
+//
+#define XHC_RESET_TIMEOUT (1000)
+//
+// TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5.
+// The unit is microsecond, setting it as 10ms.
+//
+#define XHC_RESET_RECOVERY_DELAY (10 * 1000)
+//
+// XHC async transfer timer interval, set by experience.
+// The unit is 100us, takes 1ms as interval.
+//
+#define XHC_ASYNC_TIMER_INTERVAL EFI_TIMER_PERIOD_MILLISECONDS(1)
+
+//
+// XHC raises TPL to TPL_NOTIFY to serialize all its operations
+// to protect shared data structures.
+//
+#define XHC_TPL TPL_NOTIFY
+
+#define CMD_RING_TRB_NUMBER 0x100
+#define TR_RING_TRB_NUMBER 0x100
+#define ERST_NUMBER 0x01
+#define EVENT_RING_TRB_NUMBER 0x200
+
+#define CMD_INTER 0
+#define CTRL_INTER 1
+#define BULK_INTER 2
+#define INT_INTER 3
+#define INT_INTER_ASYNC 4
+
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)
+
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define XHC_REG_BIT_IS_SET(Xhc, Offset, Bit) \
+ (XHC_BIT_IS_SET(XhcReadOpReg ((Xhc), (Offset)), (Bit)))
+
+#define XHCI_IS_DATAIN(EndpointAddr) XHC_BIT_IS_SET((EndpointAddr), 0x80)
+
+#define XHCI_INSTANCE_SIG SIGNATURE_32 ('x', 'h', 'c', 'i')
+#define XHC_FROM_THIS(a) CR(a, USB_XHCI_INSTANCE, Usb2Hc, XHCI_INSTANCE_SIG)
+
+#define USB_DESC_TYPE_HUB 0x29
+#define USB_DESC_TYPE_HUB_SUPER_SPEED 0x2a
+
+//
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
+// three fields: One bit direction, 2 bit type, and 5 bit
+// target.
+//
+#define USB_REQUEST_TYPE(Dir, Type, Target) \
+ ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))
+
+//
+// Xhci Data and Ctrl Structures
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 NumPorts;
+ UINT16 HubCharacter;
+ UINT8 PwrOn2PwrGood;
+ UINT8 HubContrCurrent;
+ UINT8 Filler[16];
+} EFI_USB_HUB_DESCRIPTOR;
+#pragma pack()
+
+struct _USB_DEV_CONTEXT {
+ //
+ // Whether this entry in UsbDevContext array is used or not.
+ //
+ BOOLEAN Enabled;
+ //
+ // The slot id assigned to the new device through XHCI's Enable_Slot cmd.
+ //
+ UINT8 SlotId;
+ //
+ // The route string presented an attached usb device.
+ //
+ USB_DEV_ROUTE RouteString;
+ //
+ // The route string of parent device if it exists. Otherwise it's zero.
+ //
+ USB_DEV_ROUTE ParentRouteString;
+ //
+ // The actual device address assigned by XHCI through Address_Device command.
+ //
+ UINT8 XhciDevAddr;
+ //
+ // The requested device address from UsbBus driver through Set_Address standard usb request.
+ // As XHCI spec replaces this request with Address_Device command, we have to record the
+ // requested device address and establish a mapping relationship with the actual device address.
+ // Then UsbBus driver just need to be aware of the requested device address to access usb device
+ // through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual
+ // device address and access the actual device.
+ //
+ UINT8 BusDevAddr;
+ //
+ // The pointer to the input device context.
+ //
+ VOID *InputContext;
+ //
+ // The pointer to the output device context.
+ //
+ VOID *OutputContext;
+ //
+ // The transfer queue for every endpoint.
+ //
+ VOID *EndpointTransferRing[31];
+ //
+ // The device descriptor which is stored to support XHCI's Evaluate_Context cmd.
+ //
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ //
+ // As a usb device may include multiple configuration descriptors, we dynamically allocate an array
+ // to store them.
+ // Note that every configuration descriptor stored here includes those lower level descriptors,
+ // such as Interface descriptor, Endpoint descriptor, and so on.
+ // These information is used to support XHCI's Config_Endpoint cmd.
+ //
+ EFI_USB_CONFIG_DESCRIPTOR **ConfDesc;
+ //
+ // A device has an active Configuration.
+ //
+ UINT8 ActiveConfiguration;
+ //
+ // Every interface has an active AlternateSetting.
+ //
+ UINT8 *ActiveAlternateSetting;
+};
+
+struct _USB_XHCI_INSTANCE {
+ UINT32 Signature;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 OriginalPciAttributes;
+ USBHC_MEM_POOL *MemPool;
+
+ EFI_USB2_HC_PROTOCOL Usb2Hc;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // ExitBootServicesEvent is used to set OS semaphore and
+ // stop the XHC DMA operation after exit boot service.
+ //
+ EFI_EVENT ExitBootServiceEvent;
+ EFI_EVENT PollTimer;
+ LIST_ENTRY AsyncIntTransfers;
+
+ UINT8 CapLength; ///< Capability Register Length
+ XHC_HCSPARAMS1 HcSParams1; ///< Structural Parameters 1
+ XHC_HCSPARAMS2 HcSParams2; ///< Structural Parameters 2
+ XHC_HCCPARAMS HcCParams; ///< Capability Parameters
+ UINT32 DBOff; ///< Doorbell Offset
+ UINT32 RTSOff; ///< Runtime Register Space Offset
+ UINT16 MaxInterrupt;
+ UINT32 PageSize;
+ UINT64 *ScratchBuf;
+ VOID *ScratchMap;
+ UINT32 MaxScratchpadBufs;
+ UINT64 *ScratchEntry;
+ UINTN *ScratchEntryMap;
+ UINT32 ExtCapRegBase;
+ UINT32 UsbLegSupOffset;
+ UINT32 DebugCapSupOffset;
+ UINT64 *DCBAA;
+ VOID *DCBAAMap;
+ UINT32 MaxSlotsEn;
+ URB *PendingUrb;
+ //
+ // Cmd Transfer Ring
+ //
+ TRANSFER_RING CmdRing;
+ //
+ // EventRing
+ //
+ EVENT_RING EventRing;
+ //
+ // Misc
+ //
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Store device contexts managed by XHCI instance
+ // The array supports up to 255 devices, entry 0 is reserved and should not be used.
+ //
+ USB_DEV_CONTEXT UsbDevContext[256];
+
+ BOOLEAN Support64BitDma; // Whether 64 bit DMA may be used with this device
+};
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gXhciComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gXhciComponentName2;
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has Usb2HcProtocol installed will
+ be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the Usb XHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS supports this device.
+ @return EFI_UNSUPPORTED do not support this device.
+ @return EFI_DEVICE_ERROR cannot be started due to device Error.
+ @return EFI_OUT_OF_RESOURCES cannot allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS Success.
+ @return EFI_DEVICE_ERROR Fail.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Retrieves the capability of root hub ports.
+
+ @param This The EFI_USB2_HC_PROTOCOL instance.
+ @param MaxSpeed Max speed supported by the controller.
+ @param PortNumber Number of the root hub ports.
+ @param Is64BitCapable Whether the controller supports 64-bit memory
+ addressing.
+
+ @retval EFI_SUCCESS Host controller capability were retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetCapability (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *PortNumber,
+ OUT UINT8 *Is64BitCapable
+ );
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcReset (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ );
+
+/**
+ Retrieve the current state of the USB host controller.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State Variable to return the current host controller
+ state.
+
+ @retval EFI_SUCCESS Host controller state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to
+ retrieve the host controller's current state.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ );
+
+/**
+ Sets the USB host controller to a specific state.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param State The state of the host controller that will be set.
+
+ @retval EFI_SUCCESS The USB host controller was successfully placed
+ in the state specified by State.
+ @retval EFI_INVALID_PARAMETER State is invalid.
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetState (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ );
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber The root hub port to retrieve the state from.
+ This value is zero-based.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcGetRootHubPortStatus (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Can't read register.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcClearRootHubPortFeature (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage
+ @param Data Data buffer to be transmitted or received from USB
+ device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param Timeout Indicates the maximum timeout, in millisecond.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcControlTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param DeviceSpeed Device speed, Low speed device doesn't support bulk
+ transfer.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to
+ use of the subsequent bulk transfer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcBulkTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Submits an asynchronous interrupt transfer to an
+ interrupt endpoint of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
+ transfer If FALSE, to remove the specified
+ asynchronous interrupt.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param PollingInterval The he interval, in milliseconds, that the transfer
+ is polled.
+ @param DataLength The length of data to receive at the rate specified
+ by PollingInterval.
+ @param Translator Transaction translator to use.
+ @param CallBackFunction Function to call at the rate specified by
+ PollingInterval.
+ @param Context Context to CallBackFunction.
+
+ @retval EFI_SUCCESS The request has been successfully submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcAsyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7
+ @param DeviceSpeed Indicates device speed.
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable
+ of sending or receiving.
+ @param Data Buffer of data that will be transmitted to USB
+ device or received from USB device.
+ @param DataLength On input, the size, in bytes, of the data buffer; On
+ output, the number of bytes transferred.
+ @param DataToggle On input, the initial data toggle to use; on output,
+ it is updated to indicate the next data toggle.
+ @param Timeout Maximum time, in second, to complete.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_SUCCESS The transfer was completed successfully.
+ @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @return EFI_INVALID_PARAMETER Some parameters are invalid.
+ @return EFI_TIMEOUT The transfer failed due to timeout.
+ @return EFI_DEVICE_ERROR The failed due to host controller or device error
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncInterruptTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN Timeout,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Submits isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param TransferResult Variable to receive the transfer result.
+
+ @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Submits Async isochronous transfer to a target USB device.
+
+ @param This This EFI_USB2_HC_PROTOCOL instance.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress End point address with its direction.
+ @param DeviceSpeed Device speed, Low speed device doesn't support this
+ type.
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of
+ sending or receiving.
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.
+ @param Data Array of pointers to the buffers of data that will
+ be transmitted to USB device or received from USB
+ device.
+ @param DataLength The size, in bytes, of the data buffer.
+ @param Translator Transaction translator to use.
+ @param IsochronousCallBack Function to be called when the transfer complete.
+ @param Context Context passed to the call back function as
+ parameter.
+
+ @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcAsyncIsochronousTransfer (
+ IN EFI_USB2_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN UINT8 DataBuffersNumber,
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
new file mode 100644
index 000000000..5865d8682
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# The XhciDxe driver is responsible for managing the behavior of XHCI controller.
+# It implements the interfaces of monitoring the status of all ports and transferring
+# Control, Bulk, Interrupt and Isochronous requests to those attached usb LS/FS/HS/SS devices.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = XhciDxe
+ MODULE_UNI_FILE = XhciDxe.uni
+ FILE_GUID = B7F50E91-A759-412c-ADE4-DCD03E7F7C28
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = XhcDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gXhciDriverBinding
+# COMPONENT_NAME = gXhciComponentName
+# COMPONENT_NAME2 = gXhciComponentName2
+#
+
+[Sources]
+ Xhci.c
+ XhciReg.c
+ XhciSched.c
+ UsbHcMem.c
+ UsbHcMem.h
+ ComponentName.c
+ ComponentName.h
+ Xhci.h
+ XhciReg.h
+ XhciSched.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ ReportStatusCodeLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiUsb2HcProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ XhciDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.uni
new file mode 100644
index 000000000..6081cbddf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The XhciDxe driver is responsible for managing the behavior of XHCI controller.
+//
+// It implements the interfaces of monitoring the status of all ports and transferring
+// Control, Bulk, Interrupt and Isochronous requests to those attached usb LS/FS/HS/SS devices.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the behavior of the XHCI controller"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interfaces of monitoring the status of all ports and transferring Control, Bulk, Interrupt and Isochronous requests to those attached USB LS/FS/HS/SS devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxeExtra.uni
new file mode 100644
index 000000000..b17479d7d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// XhciDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"XHCI DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
new file mode 100644
index 000000000..42b773ab3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
@@ -0,0 +1,718 @@
+/** @file
+
+ The XHCI register operation routines.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Xhci.h"
+
+/**
+ Read 1-byte width XHCI capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 1-byte width capability register.
+
+ @return The register content read.
+ @retval If err, return 0xFF.
+
+**/
+UINT8
+XhcReadCapReg8 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT8 Data;
+ EFI_STATUS Status;
+
+ Status = Xhc->PciIo->Mem.Read (
+ Xhc->PciIo,
+ EfiPciIoWidthUint8,
+ XHC_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
+ Data = 0xFF;
+ }
+
+ return Data;
+}
+
+/**
+ Read 4-bytes width XHCI capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width capability register.
+
+ @return The register content read.
+ @retval If err, return 0xFFFFFFFF.
+
+**/
+UINT32
+XhcReadCapReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = Xhc->PciIo->Mem.Read (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ (UINT64) Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFFFFFF;
+ }
+
+ return Data;
+}
+
+/**
+ Read 4-bytes width XHCI Operational register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width operational register.
+
+ @return The register content read.
+ @retval If err, return 0xFFFFFFFF.
+
+**/
+UINT32
+XhcReadOpReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->CapLength != 0);
+
+ Status = Xhc->PciIo->Mem.Read (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->CapLength + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFFFFFF;
+ }
+
+ return Data;
+}
+
+/**
+ Write the data to the 4-bytes width XHCI operational register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width operational register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteOpReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->CapLength != 0);
+
+ Status = Xhc->PciIo->Mem.Write (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->CapLength + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
+ }
+}
+
+
+
+
+
+/**
+ Write the data to the XHCI door bell register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the door bell register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDoorBellReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->DBOff != 0);
+
+ Status = Xhc->PciIo->Mem.Write (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->DBOff + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
+ }
+}
+
+/**
+ Read XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->RTSOff != 0);
+
+ Status = Xhc->PciIo->Mem.Read (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->RTSOff + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFFFFFF;
+ }
+
+ return Data;
+}
+
+/**
+ Write the data to the XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->RTSOff != 0);
+
+ Status = Xhc->PciIo->Mem.Write (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->RTSOff + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));
+ }
+}
+
+/**
+ Read XHCI extended capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the extended capability register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadExtCapReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->ExtCapRegBase != 0);
+
+ Status = Xhc->PciIo->Mem.Read (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->ExtCapRegBase + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));
+ Data = 0xFFFFFFFF;
+ }
+
+ return Data;
+}
+
+/**
+ Write the data to the XHCI extended capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the extended capability register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteExtCapReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Xhc->ExtCapRegBase != 0);
+
+ Status = Xhc->PciIo->Mem.Write (
+ Xhc->PciIo,
+ EfiPciIoWidthUint32,
+ XHC_BAR_INDEX,
+ Xhc->ExtCapRegBase + Offset,
+ 1,
+ &Data
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));
+ }
+}
+
+
+/**
+ Set one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetRuntimeRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadRuntimeReg (Xhc, Offset);
+ Data |= Bit;
+ XhcWriteRuntimeReg (Xhc, Offset, Data);
+}
+
+/**
+ Clear one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearRuntimeRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadRuntimeReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcWriteRuntimeReg (Xhc, Offset, Data);
+}
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadOpReg (Xhc, Offset);
+ Data |= Bit;
+ XhcWriteOpReg (Xhc, Offset, Data);
+}
+
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcClearOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadOpReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcWriteOpReg (Xhc, Offset, Data);
+}
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to become set (or clear).
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operation register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcWaitOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ )
+{
+ UINT32 Index;
+ UINT64 Loop;
+
+ Loop = Timeout * XHC_1_MILLISECOND;
+
+ for (Index = 0; Index < Loop; Index++) {
+ if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (XHC_1_MICROSECOND);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Set Bios Ownership
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcSetBiosOwnership (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ UINT32 Buffer;
+
+ if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
+ return;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
+
+ Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
+ Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
+ XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
+}
+
+/**
+ Clear Bios Ownership
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcClearBiosOwnership (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ UINT32 Buffer;
+
+ if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
+ return;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
+
+ Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
+ Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
+ XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
+}
+
+/**
+ Calculate the offset of the XHCI capability.
+
+ @param Xhc The XHCI Instance.
+ @param CapId The XHCI Capability ID.
+
+ @return The offset of XHCI legacy support capability register.
+
+**/
+UINT32
+XhcGetCapabilityAddr (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 CapId
+ )
+{
+ UINT32 ExtCapOffset;
+ UINT8 NextExtCapReg;
+ UINT32 Data;
+
+ ExtCapOffset = 0;
+
+ do {
+ //
+ // Check if the extended capability register's capability id is USB Legacy Support.
+ //
+ Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
+ if ((Data & 0xFF) == CapId) {
+ return ExtCapOffset;
+ }
+ //
+ // If not, then traverse all of the ext capability registers till finding out it.
+ //
+ NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
+ ExtCapOffset += (NextExtCapReg << 2);
+ } while (NextExtCapReg != 0);
+
+ return 0xFFFFFFFF;
+}
+
+/**
+ Whether the XHCI host controller is halted.
+
+ @param Xhc The XHCI Instance.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE It isn't halted.
+
+**/
+BOOLEAN
+XhcIsHalt (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
+}
+
+
+/**
+ Whether system error occurred.
+
+ @param Xhc The XHCI Instance.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+XhcIsSysError (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
+}
+
+/**
+ Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
+
+ The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
+ This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcSetHsee (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 XhciCmd;
+
+ PciIo = Xhc->PciIo;
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND_OFFSET,
+ sizeof (XhciCmd) / sizeof (UINT16),
+ &XhciCmd
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
+ XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
+ }
+ }
+}
+
+/**
+ Reset the XHCI host controller.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The XHCI host controller is reset.
+ @return Others Failed to reset the XHCI before Timeout.
+
+**/
+EFI_STATUS
+XhcResetHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ DEBUG ((EFI_D_INFO, "XhcResetHC!\n"));
+ //
+ // Host can only be reset when it is halt. If not so, halt it
+ //
+ if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
+ Status = XhcHaltHC (Xhc, Timeout);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
+ ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) {
+ XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
+ //
+ // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
+ // Otherwise there may have the timeout case happened.
+ // The below is a workaround to solve such problem.
+ //
+ gBS->Stall (XHC_1_MILLISECOND);
+ Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
+ // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
+ //
+ XhcSetHsee (Xhc);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Halt the XHCI host controller.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @return EFI_SUCCESS The XHCI host controller is halt.
+ @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
+
+**/
+EFI_STATUS
+XhcHaltHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
+ Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
+ return Status;
+}
+
+
+/**
+ Set the XHCI host controller to run.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @return EFI_SUCCESS The XHCI host controller is running.
+ @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
+
+**/
+EFI_STATUS
+XhcRunHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
+ Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
new file mode 100644
index 000000000..cc5c1bf09
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
@@ -0,0 +1,551 @@
+/** @file
+
+ This file contains the register definition of XHCI host controller.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_XHCI_REG_H_
+#define _EFI_XHCI_REG_H_
+
+#define PCI_IF_XHCI 0x30
+
+//
+// PCI Configuration Registers
+//
+#define XHC_BAR_INDEX 0x00
+
+#define XHC_PCI_BAR_OFFSET 0x10 // Memory Bar Register Offset
+#define XHC_PCI_BAR_MASK 0xFFFF // Memory Base Address Mask
+
+#define XHC_PCI_SBRN_OFFSET 0x60 // Serial Bus Release Number Register Offset
+
+#define USB_HUB_CLASS_CODE 0x09
+#define USB_HUB_SUBCLASS_CODE 0x00
+
+#define XHC_CAP_USB_LEGACY 0x01
+#define XHC_CAP_USB_DEBUG 0x0A
+
+//============================================//
+// XHCI register offset //
+//============================================//
+
+//
+// Capability registers offset
+//
+#define XHC_CAPLENGTH_OFFSET 0x00 // Capability register length offset
+#define XHC_HCIVERSION_OFFSET 0x02 // Interface Version Number 02-03h
+#define XHC_HCSPARAMS1_OFFSET 0x04 // Structural Parameters 1
+#define XHC_HCSPARAMS2_OFFSET 0x08 // Structural Parameters 2
+#define XHC_HCSPARAMS3_OFFSET 0x0c // Structural Parameters 3
+#define XHC_HCCPARAMS_OFFSET 0x10 // Capability Parameters
+#define XHC_DBOFF_OFFSET 0x14 // Doorbell Offset
+#define XHC_RTSOFF_OFFSET 0x18 // Runtime Register Space Offset
+
+//
+// Operational registers offset
+//
+#define XHC_USBCMD_OFFSET 0x0000 // USB Command Register Offset
+#define XHC_USBSTS_OFFSET 0x0004 // USB Status Register Offset
+#define XHC_PAGESIZE_OFFSET 0x0008 // USB Page Size Register Offset
+#define XHC_DNCTRL_OFFSET 0x0014 // Device Notification Control Register Offset
+#define XHC_CRCR_OFFSET 0x0018 // Command Ring Control Register Offset
+#define XHC_DCBAAP_OFFSET 0x0030 // Device Context Base Address Array Pointer Register Offset
+#define XHC_CONFIG_OFFSET 0x0038 // Configure Register Offset
+#define XHC_PORTSC_OFFSET 0x0400 // Port Status and Control Register Offset
+
+//
+// Runtime registers offset
+//
+#define XHC_MFINDEX_OFFSET 0x00 // Microframe Index Register Offset
+#define XHC_IMAN_OFFSET 0x20 // Interrupter X Management Register Offset
+#define XHC_IMOD_OFFSET 0x24 // Interrupter X Moderation Register Offset
+#define XHC_ERSTSZ_OFFSET 0x28 // Event Ring Segment Table Size Register Offset
+#define XHC_ERSTBA_OFFSET 0x30 // Event Ring Segment Table Base Address Register Offset
+#define XHC_ERDP_OFFSET 0x38 // Event Ring Dequeue Pointer Register Offset
+
+//
+// Debug registers offset
+//
+#define XHC_DC_DCCTRL 0x20
+
+#define USBLEGSP_BIOS_SEMAPHORE BIT16 // HC BIOS Owned Semaphore
+#define USBLEGSP_OS_SEMAPHORE BIT24 // HC OS Owned Semaphore
+
+#pragma pack (1)
+typedef struct {
+ UINT8 MaxSlots; // Number of Device Slots
+ UINT16 MaxIntrs:11; // Number of Interrupters
+ UINT16 Rsvd:5;
+ UINT8 MaxPorts; // Number of Ports
+} HCSPARAMS1;
+
+//
+// Structural Parameters 1 Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCSPARAMS1 Data;
+} XHC_HCSPARAMS1;
+
+typedef struct {
+ UINT32 Ist:4; // Isochronous Scheduling Threshold
+ UINT32 Erst:4; // Event Ring Segment Table Max
+ UINT32 Rsvd:13;
+ UINT32 ScratchBufHi:5; // Max Scratchpad Buffers Hi
+ UINT32 Spr:1; // Scratchpad Restore
+ UINT32 ScratchBufLo:5; // Max Scratchpad Buffers Lo
+} HCSPARAMS2;
+
+//
+// Structural Parameters 2 Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCSPARAMS2 Data;
+} XHC_HCSPARAMS2;
+
+typedef struct {
+ UINT16 Ac64:1; // 64-bit Addressing Capability
+ UINT16 Bnc:1; // BW Negotiation Capability
+ UINT16 Csz:1; // Context Size
+ UINT16 Ppc:1; // Port Power Control
+ UINT16 Pind:1; // Port Indicators
+ UINT16 Lhrc:1; // Light HC Reset Capability
+ UINT16 Ltc:1; // Latency Tolerance Messaging Capability
+ UINT16 Nss:1; // No Secondary SID Support
+ UINT16 Pae:1; // Parse All Event Data
+ UINT16 Rsvd:3;
+ UINT16 MaxPsaSize:4; // Maximum Primary Stream Array Size
+ UINT16 ExtCapReg; // xHCI Extended Capabilities Pointer
+} HCCPARAMS;
+
+//
+// Capability Parameters Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCCPARAMS Data;
+} XHC_HCCPARAMS;
+
+#pragma pack ()
+
+//
+// Register Bit Definition
+//
+#define XHC_USBCMD_RUN BIT0 // Run/Stop
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
+#define XHC_USBCMD_INTE BIT2 // Interrupter Enable
+#define XHC_USBCMD_HSEE BIT3 // Host System Error Enable
+
+#define XHC_USBSTS_HALT BIT0 // Host Controller Halted
+#define XHC_USBSTS_HSE BIT2 // Host System Error
+#define XHC_USBSTS_EINT BIT3 // Event Interrupt
+#define XHC_USBSTS_PCD BIT4 // Port Change Detect
+#define XHC_USBSTS_SSS BIT8 // Save State Status
+#define XHC_USBSTS_RSS BIT9 // Restore State Status
+#define XHC_USBSTS_SRE BIT10 // Save/Restore Error
+#define XHC_USBSTS_CNR BIT11 // Host Controller Not Ready
+#define XHC_USBSTS_HCE BIT12 // Host Controller Error
+
+#define XHC_PAGESIZE_MASK 0xFFFF // Page Size
+
+#define XHC_CRCR_RCS BIT0 // Ring Cycle State
+#define XHC_CRCR_CS BIT1 // Command Stop
+#define XHC_CRCR_CA BIT2 // Command Abort
+#define XHC_CRCR_CRR BIT3 // Command Ring Running
+
+#define XHC_CONFIG_MASK 0xFF // Command Ring Running
+
+#define XHC_PORTSC_CCS BIT0 // Current Connect Status
+#define XHC_PORTSC_PED BIT1 // Port Enabled/Disabled
+#define XHC_PORTSC_OCA BIT3 // Over-current Active
+#define XHC_PORTSC_RESET BIT4 // Port Reset
+#define XHC_PORTSC_PLS (BIT5|BIT6|BIT7|BIT8) // Port Link State
+#define XHC_PORTSC_PP BIT9 // Port Power
+#define XHC_PORTSC_PS (BIT10|BIT11|BIT12|BIT13) // Port Speed
+#define XHC_PORTSC_LWS BIT16 // Port Link State Write Strobe
+#define XHC_PORTSC_CSC BIT17 // Connect Status Change
+#define XHC_PORTSC_PEC BIT18 // Port Enabled/Disabled Change
+#define XHC_PORTSC_WRC BIT19 // Warm Port Reset Change
+#define XHC_PORTSC_OCC BIT20 // Over-Current Change
+#define XHC_PORTSC_PRC BIT21 // Port Reset Change
+#define XHC_PORTSC_PLC BIT22 // Port Link State Change
+#define XHC_PORTSC_CEC BIT23 // Port Config Error Change
+#define XHC_PORTSC_CAS BIT24 // Cold Attach Status
+
+#define XHC_HUB_PORTSC_CCS BIT0 // Hub's Current Connect Status
+#define XHC_HUB_PORTSC_PED BIT1 // Hub's Port Enabled/Disabled
+#define XHC_HUB_PORTSC_OCA BIT3 // Hub's Over-current Active
+#define XHC_HUB_PORTSC_RESET BIT4 // Hub's Port Reset
+#define XHC_HUB_PORTSC_PP BIT9 // Hub's Port Power
+#define XHC_HUB_PORTSC_CSC BIT16 // Hub's Connect Status Change
+#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change
+#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change
+#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change
+#define XHC_HUB_PORTSC_BHRC BIT21 // Hub's Port Warm Reset Change
+#define XHC_IMAN_IP BIT0 // Interrupt Pending
+#define XHC_IMAN_IE BIT1 // Interrupt Enable
+
+#define XHC_IMODI_MASK 0x0000FFFF // Interrupt Moderation Interval
+#define XHC_IMODC_MASK 0xFFFF0000 // Interrupt Moderation Counter
+
+//
+// Hub Class Feature Selector for Clear Port Feature Request
+// It's the extension of hub class feature selector of USB 2.0 in USB 3.0 Spec.
+// For more details, Please refer to USB 3.0 Spec Table 10-7.
+//
+typedef enum {
+ Usb3PortBHPortReset = 28,
+ Usb3PortBHPortResetChange = 29
+} XHC_PORT_FEATURE;
+
+//
+// Structure to map the hardware port states to the
+// UEFI's port states.
+//
+typedef struct {
+ UINT32 HwState;
+ UINT16 UefiState;
+} USB_PORT_STATE_MAP;
+
+//
+// Structure to map the hardware port states to feature selector for clear port feature request.
+//
+typedef struct {
+ UINT32 HwState;
+ UINT16 Selector;
+} USB_CLEAR_PORT_MAP;
+
+/**
+ Read 1-byte width XHCI capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 1-byte width capability register.
+
+ @return The register content read.
+ @retval If err, return 0xFFFF.
+
+**/
+UINT8
+XhcReadCapReg8 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Read 4-bytes width XHCI capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width capability register.
+
+ @return The register content read.
+ @retval If err, return 0xFFFFFFFF.
+
+**/
+UINT32
+XhcReadCapReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Read 4-bytes width XHCI Operational register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width operational register.
+
+ @return The register content read.
+ @retval If err, return 0xFFFFFFFF.
+
+**/
+UINT32
+XhcReadOpReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Write the data to the 4-bytes width XHCI operational register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the 4-bytes width operational register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteOpReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+
+/**
+ Read XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Write the data to the XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+
+/**
+ Write the data to the XHCI door bell register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the door bell register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDoorBellReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcClearOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to be set (or clear).
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcWaitOpRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ );
+
+/**
+ Read XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Write the data to the XHCI runtime register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteRuntimeReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Set one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetRuntimeRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearRuntimeRegBit (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Read XHCI extended capability register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the extended capability register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadExtCapReg (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Whether the XHCI host controller is halted.
+
+ @param Xhc The XHCI Instance.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE It isn't halted.
+
+**/
+BOOLEAN
+XhcIsHalt (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Whether system error occurred.
+
+ @param Xhc The XHCI Instance.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+XhcIsSysError (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Reset the XHCI host controller.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The XHCI host controller is reset.
+ @return Others Failed to reset the XHCI before Timeout.
+
+**/
+EFI_STATUS
+XhcResetHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ );
+
+/**
+ Halt the XHCI host controller.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @return EFI_SUCCESS The XHCI host controller is halt.
+ @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
+
+**/
+EFI_STATUS
+XhcHaltHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ );
+
+/**
+ Set the XHCI host controller to run.
+
+ @param Xhc The XHCI Instance.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @return EFI_SUCCESS The XHCI host controller is running.
+ @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
+
+**/
+EFI_STATUS
+XhcRunHC (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT32 Timeout
+ );
+
+/**
+ Calculate the offset of the XHCI capability.
+
+ @param Xhc The XHCI Instance.
+ @param CapId The XHCI Capability ID.
+
+ @return The offset of XHCI legacy support capability register.
+
+**/
+UINT32
+XhcGetCapabilityAddr (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 CapId
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
new file mode 100644
index 000000000..ab8957c54
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
@@ -0,0 +1,4065 @@
+/** @file
+
+ XHCI transfer scheduling routines.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Xhci.h"
+
+/**
+ Create a command transfer TRB to support XHCI command interfaces.
+
+ @param Xhc The XHCI Instance.
+ @param CmdTrb The cmd TRB to be executed.
+
+ @return Created URB or NULL.
+
+**/
+URB*
+XhcCreateCmdTrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN TRB_TEMPLATE *CmdTrb
+ )
+{
+ URB *Urb;
+
+ Urb = AllocateZeroPool (sizeof (URB));
+ if (Urb == NULL) {
+ return NULL;
+ }
+
+ Urb->Signature = XHC_URB_SIG;
+
+ Urb->Ring = &Xhc->CmdRing;
+ XhcSyncTrsRing (Xhc, Urb->Ring);
+ Urb->TrbNum = 1;
+ Urb->TrbStart = Urb->Ring->RingEnqueue;
+ CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
+ Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
+ Urb->TrbEnd = Urb->TrbStart;
+
+ return Urb;
+}
+
+/**
+ Execute a XHCI cmd TRB pointed by CmdTrb.
+
+ @param Xhc The XHCI Instance.
+ @param CmdTrb The cmd TRB to be executed.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param EvtTrb The event TRB corresponding to the cmd TRB.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCmdTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN TRB_TEMPLATE *CmdTrb,
+ IN UINTN Timeout,
+ OUT TRB_TEMPLATE **EvtTrb
+ )
+{
+ EFI_STATUS Status;
+ URB *Urb;
+
+ //
+ // Validate the parameters
+ //
+ if ((Xhc == NULL) || (CmdTrb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, then poll the execution status.
+ //
+ Urb = XhcCreateCmdTrb (Xhc, CmdTrb);
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);
+ *EvtTrb = Urb->EvtTrb;
+
+ if (Urb->Result == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ XhcFreeUrb (Xhc, Urb);
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Xhc The XHCI Instance
+ @param BusAddr The logical device address assigned by UsbBus driver
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param Type The transaction type
+ @param Request The standard USB request for control transfer
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcCreateUrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ )
+{
+ USB_ENDPOINT *Ep;
+ EFI_STATUS Status;
+ URB *Urb;
+
+ Urb = AllocateZeroPool (sizeof (URB));
+ if (Urb == NULL) {
+ return NULL;
+ }
+
+ Urb->Signature = XHC_URB_SIG;
+ InitializeListHead (&Urb->UrbList);
+
+ Ep = &Urb->Ep;
+ Ep->BusAddr = BusAddr;
+ Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
+ Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
+ Ep->DevSpeed = DevSpeed;
+ Ep->MaxPacket = MaxPacket;
+ Ep->Type = Type;
+
+ Urb->Request = Request;
+ Urb->Data = Data;
+ Urb->DataLen = DataLen;
+ Urb->Callback = Callback;
+ Urb->Context = Context;
+
+ Status = XhcCreateTransferTrb (Xhc, Urb);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));
+ FreePool (Urb);
+ Urb = NULL;
+ }
+
+ return Urb;
+}
+
+/**
+ Free an allocated URB.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+XhcFreeUrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ if ((Xhc == NULL) || (Urb == NULL)) {
+ return;
+ }
+
+ if (Urb->DataMap != NULL) {
+ Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);
+ }
+
+ FreePool (Urb);
+}
+
+/**
+ Create a transfer TRB.
+
+ @param Xhc The XHCI Instance
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcCreateTransferTrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ VOID *OutputContext;
+ TRANSFER_RING *EPRing;
+ UINT8 EPType;
+ UINT8 SlotId;
+ UINT8 Dci;
+ TRB *TrbStart;
+ UINTN TotalLen;
+ UINTN Len;
+ UINTN TrbNum;
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ EFI_STATUS Status;
+
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Urb->Finished = FALSE;
+ Urb->StartDone = FALSE;
+ Urb->EndDone = FALSE;
+ Urb->Completed = 0;
+ Urb->Result = EFI_USB_NOERROR;
+
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ ASSERT (Dci < 32);
+ EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
+ Urb->Ring = EPRing;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
+ } else {
+ EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
+ }
+
+ //
+ // No need to remap.
+ //
+ if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {
+ if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+
+ Len = Urb->DataLen;
+ Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
+ DEBUG ((EFI_D_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ }
+
+ //
+ // Construct the TRB
+ //
+ XhcSyncTrsRing (Xhc, EPRing);
+ Urb->TrbStart = EPRing->RingEnqueue;
+ switch (EPType) {
+ case ED_CONTROL_BIDIR:
+ //
+ // For control transfer, create SETUP_STAGE_TRB first.
+ //
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
+ TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
+ TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
+ TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
+ TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
+ TrbStart->TrbCtrSetup.Length = 8;
+ TrbStart->TrbCtrSetup.IntTarget = 0;
+ TrbStart->TrbCtrSetup.IOC = 1;
+ TrbStart->TrbCtrSetup.IDT = 1;
+ TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrSetup.TRT = 3;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrSetup.TRT = 2;
+ } else {
+ TrbStart->TrbCtrSetup.TRT = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
+ Urb->TrbNum++;
+
+ //
+ // For control transfer, create DATA_STAGE_TRB.
+ //
+ if (Urb->DataLen > 0) {
+ XhcSyncTrsRing (Xhc, EPRing);
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->DataPhy);
+ TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->DataPhy);
+ TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;
+ TrbStart->TrbCtrData.TDSize = 0;
+ TrbStart->TrbCtrData.IntTarget = 0;
+ TrbStart->TrbCtrData.ISP = 1;
+ TrbStart->TrbCtrData.IOC = 1;
+ TrbStart->TrbCtrData.IDT = 0;
+ TrbStart->TrbCtrData.CH = 0;
+ TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrData.DIR = 1;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrData.DIR = 0;
+ } else {
+ TrbStart->TrbCtrData.DIR = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
+ Urb->TrbNum++;
+ }
+ //
+ // For control transfer, create STATUS_STAGE_TRB.
+ // Get the pointer to next TRB for status stage use
+ //
+ XhcSyncTrsRing (Xhc, EPRing);
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbCtrStatus.IntTarget = 0;
+ TrbStart->TrbCtrStatus.IOC = 1;
+ TrbStart->TrbCtrStatus.CH = 0;
+ TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrStatus.DIR = 0;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrStatus.DIR = 1;
+ } else {
+ TrbStart->TrbCtrStatus.DIR = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
+ //
+ // Update the enqueue pointer
+ //
+ XhcSyncTrsRing (Xhc, EPRing);
+ Urb->TrbNum++;
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
+
+ break;
+
+ case ED_BULK_OUT:
+ case ED_BULK_IN:
+ TotalLen = 0;
+ Len = 0;
+ TrbNum = 0;
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ while (TotalLen < Urb->DataLen) {
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {
+ Len = Urb->DataLen - TotalLen;
+ } else {
+ Len = 0x10000;
+ }
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.Length = (UINT32) Len;
+ TrbStart->TrbNormal.TDSize = 0;
+ TrbStart->TrbNormal.IntTarget = 0;
+ TrbStart->TrbNormal.ISP = 1;
+ TrbStart->TrbNormal.IOC = 1;
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ XhcSyncTrsRing (Xhc, EPRing);
+ TrbNum++;
+ TotalLen += Len;
+ }
+
+ Urb->TrbNum = TrbNum;
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
+ break;
+
+ case ED_INTERRUPT_OUT:
+ case ED_INTERRUPT_IN:
+ TotalLen = 0;
+ Len = 0;
+ TrbNum = 0;
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ while (TotalLen < Urb->DataLen) {
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {
+ Len = Urb->DataLen - TotalLen;
+ } else {
+ Len = 0x10000;
+ }
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.Length = (UINT32) Len;
+ TrbStart->TrbNormal.TDSize = 0;
+ TrbStart->TrbNormal.IntTarget = 0;
+ TrbStart->TrbNormal.ISP = 1;
+ TrbStart->TrbNormal.IOC = 1;
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ XhcSyncTrsRing (Xhc, EPRing);
+ TrbNum++;
+ TotalLen += Len;
+ }
+
+ Urb->TrbNum = TrbNum;
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
+ break;
+
+ default:
+ DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
+ ASSERT (FALSE);
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize the XHCI host controller for schedule.
+
+ @param Xhc The XHCI Instance to be initialized.
+
+**/
+VOID
+XhcInitSched (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ VOID *Dcbaa;
+ EFI_PHYSICAL_ADDRESS DcbaaPhy;
+ UINT64 CmdRing;
+ EFI_PHYSICAL_ADDRESS CmdRingPhy;
+ UINTN Entries;
+ UINT32 MaxScratchpadBufs;
+ UINT64 *ScratchBuf;
+ EFI_PHYSICAL_ADDRESS ScratchPhy;
+ UINT64 *ScratchEntry;
+ EFI_PHYSICAL_ADDRESS ScratchEntryPhy;
+ UINT32 Index;
+ UINTN *ScratchEntryMap;
+ EFI_STATUS Status;
+
+ //
+ // Initialize memory management.
+ //
+ Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);
+ ASSERT (Xhc->MemPool != NULL);
+
+ //
+ // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
+ // to enable the device slots that system software is going to use.
+ //
+ Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
+ ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
+ XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);
+
+ //
+ // The Device Context Base Address Array entry associated with each allocated Device Slot
+ // shall contain a 64-bit pointer to the base of the associated Device Context.
+ // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
+ // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
+ //
+ Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);
+ Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);
+ ASSERT (Dcbaa != NULL);
+ ZeroMem (Dcbaa, Entries);
+
+ //
+ // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
+ // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
+ // mode (Run/Stop(R/S) ='1').
+ //
+ MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
+ Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
+ ASSERT (MaxScratchpadBufs <= 1023);
+ if (MaxScratchpadBufs != 0) {
+ //
+ // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
+ //
+ ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
+ ASSERT (ScratchEntryMap != NULL);
+ Xhc->ScratchEntryMap = ScratchEntryMap;
+
+ //
+ // Allocate the buffer to record the host address for each entry
+ //
+ ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
+ ASSERT (ScratchEntry != NULL);
+ Xhc->ScratchEntry = ScratchEntry;
+
+ ScratchPhy = 0;
+ Status = UsbHcAllocateAlignedPages (
+ Xhc->PciIo,
+ EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
+ Xhc->PageSize,
+ (VOID **) &ScratchBuf,
+ &ScratchPhy,
+ &Xhc->ScratchMap
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
+ Xhc->ScratchBuf = ScratchBuf;
+
+ //
+ // Allocate each scratch buffer
+ //
+ for (Index = 0; Index < MaxScratchpadBufs; Index++) {
+ ScratchEntryPhy = 0;
+ Status = UsbHcAllocateAlignedPages (
+ Xhc->PciIo,
+ EFI_SIZE_TO_PAGES (Xhc->PageSize),
+ Xhc->PageSize,
+ (VOID **) &ScratchEntry[Index],
+ &ScratchEntryPhy,
+ (VOID **) &ScratchEntryMap[Index]
+ );
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);
+ //
+ // Fill with the PCI device address
+ //
+ *ScratchBuf++ = ScratchEntryPhy;
+ }
+ //
+ // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
+ // Device Context Base Address Array points to the Scratchpad Buffer Array.
+ //
+ *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;
+ }
+
+ //
+ // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
+ // a 64-bit address pointing to where the Device Context Base Address Array is located.
+ //
+ Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);
+ XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));
+ XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
+
+ DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));
+
+ //
+ // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
+ // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
+ // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
+ // always be '0'.
+ //
+ CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
+ //
+ // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
+ // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
+ // So we set RCS as inverted PCS init value to let Command Ring empty
+ //
+ CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;
+ CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
+ ASSERT ((CmdRingPhy & 0x3F) == 0);
+ CmdRingPhy |= XHC_CRCR_RCS;
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));
+ XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
+
+ //
+ // Disable the 'interrupter enable' bit in USB_CMD
+ // and clear IE & IP bit in all Interrupter X Management Registers.
+ //
+ XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
+ for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
+ XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
+ XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
+ }
+
+ //
+ // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
+ //
+ CreateEventRing (Xhc, &Xhc->EventRing);
+ DEBUG ((DEBUG_INFO, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
+ Xhc->CmdRing.RingSeg0, (UINTN)Xhc->CmdRing.RingSeg0 + sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER,
+ Xhc->EventRing.EventRingSeg0, (UINTN)Xhc->EventRing.EventRingSeg0 + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
+ ));
+}
+
+/**
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
+ Stopped to the Running state.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The urb which makes the endpoint halted.
+
+ @retval EFI_SUCCESS The recovery is successful.
+ @retval Others Failed to recovery halted endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRecoverHaltedEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Dci;
+ UINT8 SlotId;
+
+ Status = EFI_SUCCESS;
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ ASSERT (Dci < 32);
+
+ DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));
+
+ //
+ // 1) Send Reset endpoint command to transit from halt to stop state
+ //
+ Status = XhcResetEndpoint(Xhc, SlotId, Dci);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 2)Set dequeue pointer
+ //
+ Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 3)Ring the doorbell to transit from stop to active
+ //
+ XhcRingDoorBell (Xhc, SlotId, Dci);
+
+Done:
+ return Status;
+}
+
+/**
+ System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
+ Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
+ the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
+ state.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The urb which doesn't get completed in a specified timeout range.
+
+ @retval EFI_SUCCESS The dequeuing of the TDs is successful.
+ @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.
+ @retval Others Failed to stop the endpoint and dequeue the TDs.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDequeueTrbFromEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Dci;
+ UINT8 SlotId;
+
+ Status = EFI_SUCCESS;
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ ASSERT (Dci < 32);
+
+ DEBUG ((EFI_D_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));
+
+ //
+ // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
+ //
+ Status = XhcStopEndpoint(Xhc, SlotId, Dci, Urb);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 2)Set dequeue pointer
+ //
+ if (Urb->Finished && Urb->Result == EFI_USB_NOERROR) {
+ //
+ // Return Already Started to indicate the pending URB is finished.
+ // This fixes BULK data loss when transfer is detected as timeout
+ // but finished just before stopping endpoint.
+ //
+ Status = EFI_ALREADY_STARTED;
+ DEBUG ((DEBUG_INFO, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb->Completed, Urb->DataLen));
+ } else {
+ Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));
+ goto Done;
+ }
+ }
+
+ //
+ // 3)Ring the doorbell to transit from stop to active
+ //
+ XhcRingDoorBell (Xhc, SlotId, Dci);
+
+Done:
+ return Status;
+}
+
+/**
+ Create XHCI event ring.
+
+ @param Xhc The XHCI Instance.
+ @param EventRing The created event ring.
+
+**/
+VOID
+CreateEventRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ OUT EVENT_RING *EventRing
+ )
+{
+ VOID *Buf;
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS ERSTPhy;
+ EFI_PHYSICAL_ADDRESS DequeuePhy;
+
+ ASSERT (EventRing != NULL);
+
+ Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, Size);
+
+ EventRing->EventRingSeg0 = Buf;
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
+ EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
+ EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
+
+ DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
+
+ //
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
+ //
+ EventRing->EventRingCCS = 1;
+
+ Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, Size);
+
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
+ EventRing->ERSTBase = ERSTBase;
+ ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
+
+ ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);
+
+ //
+ // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
+ //
+ XhcWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTSZ_OFFSET,
+ ERST_NUMBER
+ );
+ //
+ // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteRuntimeReg (
+ Xhc,
+ XHC_ERDP_OFFSET,
+ XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)
+ );
+ XhcWriteRuntimeReg (
+ Xhc,
+ XHC_ERDP_OFFSET + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)
+ );
+ //
+ // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTBA_OFFSET,
+ XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)
+ );
+ XhcWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTBA_OFFSET + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)
+ );
+ //
+ // Need set IMAN IE bit to enble the ring interrupt
+ //
+ XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
+}
+
+/**
+ Create XHCI transfer ring.
+
+ @param Xhc The XHCI Instance.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+CreateTransferRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINTN TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ )
+{
+ VOID *Buf;
+ LINK_TRB *EndTrb;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+
+ TransferRing->RingSeg0 = Buf;
+ TransferRing->TrbNumber = TrbNum;
+ TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
+ TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
+ TransferRing->RingPCS = 1;
+ //
+ // 4.9.2 Transfer Ring Management
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
+ // point to the first TRB in the ring.
+ //
+ EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
+ EndTrb->Type = TRB_TYPE_LINK;
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+ EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
+ EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ //
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
+ //
+ EndTrb->TC = 1;
+ //
+ // Set Cycle bit as other TRB PCS init value
+ //
+ EndTrb->CycleBit = 0;
+}
+
+/**
+ Free XHCI event ring.
+
+ @param Xhc The XHCI Instance.
+ @param EventRing The event ring to be freed.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcFreeEventRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN EVENT_RING *EventRing
+)
+{
+ if(EventRing->EventRingSeg0 == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Free EventRing Segment 0
+ //
+ UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+
+ //
+ // Free ESRT table
+ //
+ UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+ return EFI_SUCCESS;
+}
+
+/**
+ Free the resouce allocated at initializing schedule.
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcFreeSched (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ UINT32 Index;
+ UINT64 *ScratchEntry;
+
+ if (Xhc->ScratchBuf != NULL) {
+ ScratchEntry = Xhc->ScratchEntry;
+ for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
+ //
+ // Free Scratchpad Buffers
+ //
+ UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);
+ }
+ //
+ // Free Scratchpad Buffer Array
+ //
+ UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
+ FreePool (Xhc->ScratchEntryMap);
+ FreePool (Xhc->ScratchEntry);
+ }
+
+ if (Xhc->CmdRing.RingSeg0 != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
+ Xhc->CmdRing.RingSeg0 = NULL;
+ }
+
+ XhcFreeEventRing (Xhc,&Xhc->EventRing);
+
+ if (Xhc->DCBAA != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));
+ Xhc->DCBAA = NULL;
+ }
+
+ //
+ // Free memory pool at last
+ //
+ if (Xhc->MemPool != NULL) {
+ UsbHcFreeMemPool (Xhc->MemPool);
+ Xhc->MemPool = NULL;
+ }
+}
+
+/**
+ Check if the Trb is a transaction of the URB.
+
+ @param Xhc The XHCI Instance.
+ @param Trb The TRB to be checked
+ @param Urb The URB to be checked.
+
+ @retval TRUE It is a transaction of the URB.
+ @retval FALSE It is not any transaction of the URB.
+
+**/
+BOOLEAN
+IsTransferRingTrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN TRB_TEMPLATE *Trb,
+ IN URB *Urb
+ )
+{
+ LINK_TRB *LinkTrb;
+ TRB_TEMPLATE *CheckedTrb;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ CheckedTrb = Urb->TrbStart;
+ for (Index = 0; Index < Urb->TrbNum; Index++) {
+ if (Trb == CheckedTrb) {
+ return TRUE;
+ }
+ CheckedTrb++;
+ //
+ // If the checked TRB is the link TRB at the end of the transfer ring,
+ // recircle it to the head of the ring.
+ //
+ if (CheckedTrb->Type == TRB_TYPE_LINK) {
+ LinkTrb = (LINK_TRB *) CheckedTrb;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(LinkTrb->PtrLo | LShiftU64 ((UINT64) LinkTrb->PtrHi, 32));
+ CheckedTrb = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
+ ASSERT (CheckedTrb == Urb->Ring->RingSeg0);
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
+
+ @param Xhc The XHCI Instance.
+ @param Trb The TRB to be checked.
+ @param Urb The pointer to the matched Urb.
+
+ @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
+ @retval FALSE The Trb is not matched with any URBs in the async list.
+
+**/
+BOOLEAN
+IsAsyncIntTrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN TRB_TEMPLATE *Trb,
+ OUT URB **Urb
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ URB *CheckedUrb;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
+ CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+ if (IsTransferRingTrb (Xhc, Trb, CheckedUrb)) {
+ *Urb = CheckedUrb;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to check result.
+
+ @return Whether the result of URB transfer is finialized.
+
+**/
+BOOLEAN
+XhcCheckUrbResult (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EVT_TRB_TRANSFER *EvtTrb;
+ TRB_TEMPLATE *TRBPtr;
+ UINTN Index;
+ UINT8 TRBType;
+ EFI_STATUS Status;
+ URB *AsyncUrb;
+ URB *CheckedUrb;
+ UINT64 XhcDequeue;
+ UINT32 High;
+ UINT32 Low;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT ((Xhc != NULL) && (Urb != NULL));
+
+ Status = EFI_SUCCESS;
+ AsyncUrb = NULL;
+
+ if (Urb->Finished) {
+ goto EXIT;
+ }
+
+ EvtTrb = NULL;
+
+ if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
+ Urb->Result |= EFI_USB_ERR_SYSTEM;
+ goto EXIT;
+ }
+
+ //
+ // Traverse the event ring to find out all new events from the previous check.
+ //
+ XhcSyncEventRing (Xhc, &Xhc->EventRing);
+ for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
+ Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
+ if (Status == EFI_NOT_READY) {
+ //
+ // All new events are handled, return directly.
+ //
+ goto EXIT;
+ }
+
+ //
+ // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
+ //
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
+ continue;
+ }
+
+ //
+ // Need convert pci device address to host address
+ //
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
+ TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
+
+ //
+ // Update the status of URB including the pending URB, the URB that is currently checked,
+ // and URBs in the XHCI's async interrupt transfer list.
+ // This way is used to avoid that those completed async transfer events don't get
+ // handled in time and are flushed by newer coming events.
+ //
+ if (Xhc->PendingUrb != NULL && IsTransferRingTrb (Xhc, TRBPtr, Xhc->PendingUrb)) {
+ CheckedUrb = Xhc->PendingUrb;
+ } else if (IsTransferRingTrb (Xhc, TRBPtr, Urb)) {
+ CheckedUrb = Urb;
+ } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
+ CheckedUrb = AsyncUrb;
+ } else {
+ continue;
+ }
+
+ switch (EvtTrb->Completecode) {
+ case TRB_COMPLETION_STALL_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_STALL;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_BABBLE_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_DATA_BUFFER_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_USB_TRANSACTION_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_STOPPED:
+ case TRB_COMPLETION_STOPPED_LENGTH_INVALID:
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ //
+ // The pending URB is timeout and force stopped when stopping endpoint.
+ // Continue the loop to receive the Command Complete Event for stopping endpoint.
+ //
+ continue;
+
+ case TRB_COMPLETION_SHORT_PACKET:
+ case TRB_COMPLETION_SUCCESS:
+ if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
+ DEBUG ((EFI_D_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));
+ }
+
+ TRBType = (UINT8) (TRBPtr->Type);
+ if ((TRBType == TRB_TYPE_DATA_STAGE) ||
+ (TRBType == TRB_TYPE_NORMAL) ||
+ (TRBType == TRB_TYPE_ISOCH)) {
+ CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
+ }
+
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ goto EXIT;
+ }
+
+ //
+ // Only check first and end Trb event address
+ //
+ if (TRBPtr == CheckedUrb->TrbStart) {
+ CheckedUrb->StartDone = TRUE;
+ }
+
+ if (TRBPtr == CheckedUrb->TrbEnd) {
+ CheckedUrb->EndDone = TRUE;
+ }
+
+ if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
+ CheckedUrb->Finished = TRUE;
+ CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
+ }
+ }
+
+EXIT:
+
+ //
+ // Advance event ring to last available entry
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
+ High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
+ XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
+
+ if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
+ XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
+ }
+
+ return Urb->Finished;
+}
+
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Xhc The XHCI Instance.
+ @param CmdTransfer The executed URB is for cmd transfer or not.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+XhcExecTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN BOOLEAN CmdTransfer,
+ IN URB *Urb,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT64 Loop;
+ UINT8 SlotId;
+ UINT8 Dci;
+ BOOLEAN Finished;
+
+ if (CmdTransfer) {
+ SlotId = 0;
+ Dci = 0;
+ } else {
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ ASSERT (Dci < 32);
+ }
+
+ Status = EFI_SUCCESS;
+ Loop = Timeout * XHC_1_MILLISECOND;
+ if (Timeout == 0) {
+ Loop = 0xFFFFFFFF;
+ }
+
+ XhcRingDoorBell (Xhc, SlotId, Dci);
+
+ for (Index = 0; Index < Loop; Index++) {
+ Finished = XhcCheckUrbResult (Xhc, Urb);
+ if (Finished) {
+ break;
+ }
+ gBS->Stall (XHC_1_MICROSECOND);
+ }
+
+ if (Index == Loop) {
+ Urb->Result = EFI_USB_ERR_TIMEOUT;
+ Status = EFI_TIMEOUT;
+ } else if (Urb->Result != EFI_USB_NOERROR) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Xhc The XHCI Instance.
+ @param BusAddr The logical device address assigned by UsbBus driver.
+ @param EpNum The endpoint of the target.
+
+ @retval EFI_SUCCESS An asynchronous transfer is removed.
+ @retval EFI_NOT_FOUND No transfer for the device is found.
+
+**/
+EFI_STATUS
+XhciDelAsyncIntTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpNum
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ URB *Urb;
+ EFI_USB_DATA_DIRECTION Direction;
+ EFI_STATUS Status;
+
+ Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
+ EpNum &= 0x0F;
+
+ Urb = NULL;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+ if ((Urb->Ep.BusAddr == BusAddr) &&
+ (Urb->Ep.EpAddr == EpNum) &&
+ (Urb->Ep.Direction == Direction)) {
+ //
+ // Device doesn't finish the IntTransfer until real data comes
+ // So the TRB should be removed as well.
+ //
+ Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
+ }
+
+ RemoveEntryList (&Urb->UrbList);
+ FreePool (Urb->Data);
+ XhcFreeUrb (Xhc, Urb);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Remove all the asynchronous interrutp transfers.
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhciDelAllAsyncIntTransfers (
+ IN USB_XHCI_INSTANCE *Xhc
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ URB *Urb;
+ EFI_STATUS Status;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+
+ //
+ // Device doesn't finish the IntTransfer until real data comes
+ // So the TRB should be removed as well.
+ //
+ Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
+ }
+
+ RemoveEntryList (&Urb->UrbList);
+ FreePool (Urb->Data);
+ XhcFreeUrb (Xhc, Urb);
+ }
+}
+
+/**
+ Insert a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Xhc The XHCI Instance
+ @param BusAddr The logical device address assigned by UsbBus driver
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB *
+XhciInsertAsyncIntTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ )
+{
+ VOID *Data;
+ URB *Urb;
+
+ Data = AllocateZeroPool (DataLen);
+ if (Data == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));
+ return NULL;
+ }
+
+ Urb = XhcCreateUrb (
+ Xhc,
+ BusAddr,
+ EpAddr,
+ DevSpeed,
+ MaxPacket,
+ XHC_INT_TRANSFER_ASYNC,
+ NULL,
+ Data,
+ DataLen,
+ Callback,
+ Context
+ );
+ if (Urb == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));
+ FreePool (Data);
+ return NULL;
+ }
+
+ //
+ // New asynchronous transfer must inserted to the head.
+ // Check the comments in XhcMoniteAsyncRequests
+ //
+ InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);
+
+ return Urb;
+}
+
+/**
+ Update the queue head for next round of asynchronous transfer
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to update
+
+**/
+VOID
+XhcUpdateAsyncRequest (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+
+ if (Urb->Result == EFI_USB_NOERROR) {
+ Status = XhcCreateTransferTrb (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ Status = RingIntTransferDoorBell (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+}
+
+/**
+ Flush data from PCI controller specific address to mapped system
+ memory address.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to unmap.
+
+ @retval EFI_SUCCESS Success to flush data to mapped system memory.
+ @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
+
+**/
+EFI_STATUS
+XhcFlushAsyncIntMap (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Len;
+ VOID *Map;
+
+ PciIo = Xhc->PciIo;
+ Len = Urb->DataLen;
+
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+
+ if (Urb->DataMap != NULL) {
+ Status = PciIo->Unmap (PciIo, Urb->DataMap);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ Urb->DataMap = NULL;
+
+ Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
+ goto ON_ERROR;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event Interrupt event.
+ @param Context Pointer to USB_XHCI_INSTANCE.
+
+**/
+VOID
+EFIAPI
+XhcMonitorAsyncRequests (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_XHCI_INSTANCE *Xhc;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ UINT8 *ProcBuf;
+ URB *Urb;
+ UINT8 SlotId;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+
+ Xhc = (USB_XHCI_INSTANCE*) Context;
+
+ BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
+
+ //
+ // Make sure that the device is available before every check.
+ //
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ continue;
+ }
+
+ //
+ // Check the result of URB execution. If it is still
+ // active, check the next one.
+ //
+ XhcCheckUrbResult (Xhc, Urb);
+
+ if (!Urb->Finished) {
+ continue;
+ }
+
+ //
+ // Flush any PCI posted write transactions from a PCI host
+ // bridge to system memory.
+ //
+ Status = XhcFlushAsyncIntMap (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
+ }
+
+ //
+ // Allocate a buffer then copy the transferred data for user.
+ // If failed to allocate the buffer, update the URB for next
+ // round of transfer. Ignore the data of this round.
+ //
+ ProcBuf = NULL;
+ if (Urb->Result == EFI_USB_NOERROR) {
+ //
+ // Make sure the data received from HW is no more than expected.
+ //
+ if (Urb->Completed <= Urb->DataLen) {
+ ProcBuf = AllocateZeroPool (Urb->Completed);
+ }
+
+ if (ProcBuf == NULL) {
+ XhcUpdateAsyncRequest (Xhc, Urb);
+ continue;
+ }
+
+ CopyMem (ProcBuf, Urb->Data, Urb->Completed);
+ }
+
+ //
+ // Leave error recovery to its related device driver. A
+ // common case of the error recovery is to re-submit the
+ // interrupt transfer which is linked to the head of the
+ // list. This function scans from head to tail. So the
+ // re-submitted interrupt transfer's callback function
+ // will not be called again in this round. Don't touch this
+ // URB after the callback, it may have been removed by the
+ // callback.
+ //
+ if (Urb->Callback != NULL) {
+ //
+ // Restore the old TPL, USB bus maybe connect device in
+ // his callback. Some drivers may has a lower TPL restriction.
+ //
+ gBS->RestoreTPL (OldTpl);
+ (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
+ OldTpl = gBS->RaiseTPL (XHC_TPL);
+ }
+
+ if (ProcBuf != NULL) {
+ gBS->FreePool (ProcBuf);
+ }
+
+ XhcUpdateAsyncRequest (Xhc, Urb);
+ }
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device if it exists.
+ @param Port The port to be polled.
+ @param PortState The port state.
+
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
+ @retval Others Should not appear.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPollPortStatusChange (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_STATUS *PortState
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Speed;
+ UINT8 SlotId;
+ USB_DEV_ROUTE RouteChart;
+
+ Status = EFI_SUCCESS;
+
+ if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (ParentRouteChart.Dword == 0) {
+ RouteChart.Route.RouteString = 0;
+ RouteChart.Route.RootPortNum = Port + 1;
+ RouteChart.Route.TierNum = 1;
+ } else {
+ if(Port < 14) {
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
+ } else {
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
+ }
+ RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
+ RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
+ }
+
+ SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
+ if (SlotId != 0) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcDisableSlotCmd (Xhc, SlotId);
+ } else {
+ Status = XhcDisableSlotCmd64 (Xhc, SlotId);
+ }
+ }
+
+ if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
+ ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
+ //
+ // Has a device attached, Identify device speed after port is enabled.
+ //
+ Speed = EFI_USB_SPEED_FULL;
+ if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_LOW;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_HIGH;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_SUPER;
+ }
+ //
+ // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
+ //
+ SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
+ if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ } else {
+ Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Calculate the device context index by endpoint address and direction.
+
+ @param EpAddr The target endpoint number.
+ @param Direction The direction of the target endpoint.
+
+ @return The device context index of endpoint.
+
+**/
+UINT8
+XhcEndpointToDci (
+ IN UINT8 EpAddr,
+ IN UINT8 Direction
+ )
+{
+ UINT8 Index;
+
+ if (EpAddr == 0) {
+ return 1;
+ } else {
+ Index = (UINT8) (2 * EpAddr);
+ if (Direction == EfiUsbDataIn) {
+ Index += 1;
+ }
+ return Index;
+ }
+}
+
+/**
+ Find out the actual device address according to the requested device address from UsbBus.
+
+ @param Xhc The XHCI Instance.
+ @param BusDevAddr The requested device address by UsbBus upper driver.
+
+ @return The actual device address assigned to the device.
+
+**/
+UINT8
+EFIAPI
+XhcBusDevAddrToSlotId (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusDevAddr
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < 255; Index++) {
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
+ break;
+ }
+ }
+
+ if (Index == 255) {
+ return 0;
+ }
+
+ return Xhc->UsbDevContext[Index + 1].SlotId;
+}
+
+/**
+ Find out the slot id according to the device's route string.
+
+ @param Xhc The XHCI Instance.
+ @param RouteString The route string described the device location.
+
+ @return The slot id used by the device.
+
+**/
+UINT8
+EFIAPI
+XhcRouteStringToSlotId (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE RouteString
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < 255; Index++) {
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
+ (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
+ break;
+ }
+ }
+
+ if (Index == 255) {
+ return 0;
+ }
+
+ return Xhc->UsbDevContext[Index + 1].SlotId;
+}
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncEventRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN EVENT_RING *EvtRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *EvtTrb1;
+
+ ASSERT (EvtRing != NULL);
+
+ //
+ // Calculate the EventRingEnqueue and EventRingCCS.
+ // Note: only support single Segment
+ //
+ EvtTrb1 = EvtRing->EventRingDequeue;
+
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
+ if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
+ break;
+ }
+
+ EvtTrb1++;
+
+ if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtTrb1 = EvtRing->EventRingSeg0;
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
+ }
+ }
+
+ if (Index < EvtRing->TrbNumber) {
+ EvtRing->EventRingEnqueue = EvtTrb1;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncTrsRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN TRANSFER_RING *TrsRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *TrsTrb;
+
+ ASSERT (TrsRing != NULL);
+ //
+ // Calculate the latest RingEnqueue and RingPCS
+ //
+ TrsTrb = TrsRing->RingEnqueue;
+ ASSERT (TrsTrb != NULL);
+
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
+ break;
+ }
+ TrsTrb++;
+ if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
+ ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
+ //
+ // set cycle bit in Link TRB as normal
+ //
+ ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
+ //
+ // Toggle PCS maintained by software
+ //
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
+ TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address
+ }
+ }
+
+ ASSERT (Index != TrsRing->TrbNumber);
+
+ if (TrsTrb != TrsRing->RingEnqueue) {
+ TrsRing->RingEnqueue = TrsTrb;
+ }
+
+ //
+ // Clear the Trb context for enqueue, but reserve the PCS bit
+ //
+ TrsTrb->Parameter1 = 0;
+ TrsTrb->Parameter2 = 0;
+ TrsTrb->Status = 0;
+ TrsTrb->RsvdZ1 = 0;
+ TrsTrb->Type = 0;
+ TrsTrb->Control = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if there is a new generated event.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCheckNewEvent (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ )
+{
+ ASSERT (EvtRing != NULL);
+
+ *NewEvtTrb = EvtRing->EventRingDequeue;
+
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
+ return EFI_NOT_READY;
+ }
+
+ EvtRing->EventRingDequeue++;
+ //
+ // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
+ //
+ if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRingDoorBell (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ )
+{
+ if (SlotId == 0) {
+ XhcWriteDoorBellReg (Xhc, 0, 0);
+ } else {
+ XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed through URB.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to be rung.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+RingIntTransferDoorBell (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ UINT8 SlotId;
+ UINT8 Dci;
+
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ XhcRingDoorBell (Xhc, SlotId, Dci);
+ return EFI_SUCCESS;
+}
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcInitializeDeviceSlot (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
+ UINT8 DeviceAddress;
+ CMD_TRB_ENABLE_SLOT CmdTrb;
+ UINT8 SlotId;
+ UINT8 ParentSlotId;
+ DEVICE_CONTEXT *ParentDeviceContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
+ CmdTrb.CycleBit = 1;
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;
+
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
+ return Status;
+ }
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
+ DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
+ SlotId = (UINT8)EvtTrb->SlotId;
+ ASSERT (SlotId != 0);
+
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
+
+ //
+ // 4.3.3 Device Slot Initialization
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
+ //
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
+ ASSERT (InputContext != NULL);
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
+
+ //
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
+ // Context are affected by the command.
+ //
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
+
+ //
+ // 3) Initialize the Input Slot Context data structure
+ //
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;
+ InputContext->Slot.Speed = DeviceSpeed + 1;
+ InputContext->Slot.ContextEntries = 1;
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
+
+ if (RouteChart.Route.RouteString) {
+ //
+ // The device is behind of hub device.
+ //
+ ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
+ ASSERT (ParentSlotId != 0);
+ //
+ //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
+ //
+ ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
+ //
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling
+ // environment from Full/Low speed signaling environment for a device
+ //
+ InputContext->Slot.TTPortNum = ParentPort;
+ InputContext->Slot.TTHubSlotId = ParentSlotId;
+ }
+ } else {
+ //
+ // Inherit the TT parameters from parent device.
+ //
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
+ //
+ // If the device is a High speed device then down the speed to be the same as its parent Hub
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
+ }
+ }
+ }
+
+ //
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
+ //
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
+ //
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
+ //
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ InputContext->EP[0].MaxPacketSize = 512;
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->EP[0].MaxPacketSize = 64;
+ } else {
+ InputContext->EP[0].MaxPacketSize = 8;
+ }
+ //
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
+ // 1KB, and Bulk and Isoch endpoints 3KB.
+ //
+ InputContext->EP[0].AverageTRBLength = 8;
+ InputContext->EP[0].MaxBurstSize = 0;
+ InputContext->EP[0].Interval = 0;
+ InputContext->EP[0].MaxPStreams = 0;
+ InputContext->EP[0].Mult = 0;
+ InputContext->EP[0].CErr = 3;
+
+ //
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ //
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
+ //
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
+ ASSERT (OutputContext != NULL);
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
+
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
+ //
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
+ // a pointer to the Output Device Context data structure (6.2.1).
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
+ //
+ // Fill DCBAA with PCI device address
+ //
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
+
+ //
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
+ // Context data structure described above.
+ //
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
+ // to device.
+ //
+ gBS->Stall (XHC_RESET_RECOVERY_DELAY);
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbAddr.CycleBit = 1;
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (!EFI_ERROR (Status)) {
+ DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
+ DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
+ }
+
+ return Status;
+}
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcInitializeDeviceSlot64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
+ UINT8 DeviceAddress;
+ CMD_TRB_ENABLE_SLOT CmdTrb;
+ UINT8 SlotId;
+ UINT8 ParentSlotId;
+ DEVICE_CONTEXT_64 *ParentDeviceContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
+ CmdTrb.CycleBit = 1;
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;
+
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
+ return Status;
+ }
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
+ DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
+ SlotId = (UINT8)EvtTrb->SlotId;
+ ASSERT (SlotId != 0);
+
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
+
+ //
+ // 4.3.3 Device Slot Initialization
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
+ //
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
+ ASSERT (InputContext != NULL);
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
+
+ //
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
+ // Context are affected by the command.
+ //
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
+
+ //
+ // 3) Initialize the Input Slot Context data structure
+ //
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;
+ InputContext->Slot.Speed = DeviceSpeed + 1;
+ InputContext->Slot.ContextEntries = 1;
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
+
+ if (RouteChart.Route.RouteString) {
+ //
+ // The device is behind of hub device.
+ //
+ ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
+ ASSERT (ParentSlotId != 0);
+ //
+ //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
+ //
+ ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
+ //
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling
+ // environment from Full/Low speed signaling environment for a device
+ //
+ InputContext->Slot.TTPortNum = ParentPort;
+ InputContext->Slot.TTHubSlotId = ParentSlotId;
+ }
+ } else {
+ //
+ // Inherit the TT parameters from parent device.
+ //
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
+ //
+ // If the device is a High speed device then down the speed to be the same as its parent Hub
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
+ }
+ }
+ }
+
+ //
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
+ //
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
+ //
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
+ //
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ InputContext->EP[0].MaxPacketSize = 512;
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->EP[0].MaxPacketSize = 64;
+ } else {
+ InputContext->EP[0].MaxPacketSize = 8;
+ }
+ //
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
+ // 1KB, and Bulk and Isoch endpoints 3KB.
+ //
+ InputContext->EP[0].AverageTRBLength = 8;
+ InputContext->EP[0].MaxBurstSize = 0;
+ InputContext->EP[0].Interval = 0;
+ InputContext->EP[0].MaxPStreams = 0;
+ InputContext->EP[0].Mult = 0;
+ InputContext->EP[0].CErr = 3;
+
+ //
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ //
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
+ //
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
+ ASSERT (OutputContext != NULL);
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
+
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
+ //
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
+ // a pointer to the Output Device Context data structure (6.2.1).
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
+ //
+ // Fill DCBAA with PCI device address
+ //
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
+
+ //
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
+ // Context data structure described above.
+ //
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
+ // to device.
+ //
+ gBS->Stall (XHC_RESET_RECOVERY_DELAY);
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbAddr.CycleBit = 1;
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (!EFI_ERROR (Status)) {
+ DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
+ DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
+ }
+ return Status;
+}
+
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDisableSlotCmd (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId
+ )
+{
+ EFI_STATUS Status;
+ TRB_TEMPLATE *EvtTrb;
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
+ UINT8 Index;
+ VOID *RingSeg;
+
+ //
+ // Disable the device slots occupied by these devices on its downstream ports.
+ // Entry 0 is reserved.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
+ continue;
+ }
+
+ Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;
+ }
+ }
+
+ //
+ // Construct the disable slot command
+ //
+ DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
+
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
+ CmdTrbDisSlot.CycleBit = 1;
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
+ CmdTrbDisSlot.SlotId = SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Free the slot's device context entry
+ //
+ Xhc->DCBAA[SlotId] = 0;
+
+ //
+ // Free the slot related data structure
+ //
+ for (Index = 0; Index < 31; Index++) {
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
+ RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
+ }
+ }
+
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
+ }
+
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
+ }
+
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
+ }
+ //
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
+ // remove urb from XHCI's asynchronous transfer list.
+ //
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;
+ Xhc->UsbDevContext[SlotId].SlotId = 0;
+
+ return Status;
+}
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDisableSlotCmd64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId
+ )
+{
+ EFI_STATUS Status;
+ TRB_TEMPLATE *EvtTrb;
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
+ UINT8 Index;
+ VOID *RingSeg;
+
+ //
+ // Disable the device slots occupied by these devices on its downstream ports.
+ // Entry 0 is reserved.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
+ continue;
+ }
+
+ Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;
+ }
+ }
+
+ //
+ // Construct the disable slot command
+ //
+ DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
+
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
+ CmdTrbDisSlot.CycleBit = 1;
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
+ CmdTrbDisSlot.SlotId = SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Free the slot's device context entry
+ //
+ Xhc->DCBAA[SlotId] = 0;
+
+ //
+ // Free the slot related data structure
+ //
+ for (Index = 0; Index < 31; Index++) {
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
+ RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
+ }
+ }
+
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);
+ }
+
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
+ }
+
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
+ }
+ //
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
+ // remove urb from XHCI's asynchronous transfer list.
+ //
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;
+ Xhc->UsbDevContext[SlotId].SlotId = 0;
+
+ return Status;
+}
+
+/**
+ Initialize endpoint context in input context.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param InputContext The pointer to the input context.
+ @param IfDesc The pointer to the usb device interface descriptor.
+
+ @return The maximum device context index of endpoint.
+
+**/
+UINT8
+EFIAPI
+XhcInitializeEndpointContext (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN INPUT_CONTEXT *InputContext,
+ IN USB_INTERFACE_DESCRIPTOR *IfDesc
+ )
+{
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ UINT8 Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINT8 Interval;
+ TRANSFER_RING *EndpointTransferRing;
+
+ MaxDci = 0;
+
+ NumEp = IfDesc->NumEndpoints;
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcEndpointToDci (EpAddr, Direction);
+ ASSERT (Dci < 32);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
+ //
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ } else {
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ }
+
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
+ case USB_ENDPOINT_BULK:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
+ }
+
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
+ EpDesc->EndpointAddress,
+ EndpointTransferRing->RingSeg0,
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
+ ));
+ }
+
+ break;
+ case USB_ENDPOINT_ISO:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
+ }
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.
+ // Refer to XHCI 1.1 spec section 6.2.3.6.
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval + 2;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ //
+ // Do not support isochronous transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ case USB_ENDPOINT_INTERRUPT:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
+ }
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context
+ //
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
+ Interval = EpDesc->Interval;
+ //
+ // Calculate through the bInterval field of Endpoint descriptor.
+ //
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ //
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
+ //
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ InputContext->EP[Dci-1].CErr = 3;
+ }
+
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",
+ EpDesc->EndpointAddress,
+ EndpointTransferRing->RingSeg0,
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
+ ));
+ }
+ break;
+
+ case USB_ENDPOINT_CONTROL:
+ //
+ // Do not support control transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
+ default:
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ return MaxDci;
+}
+
+/**
+ Initialize endpoint context in input context.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param InputContext The pointer to the input context.
+ @param IfDesc The pointer to the usb device interface descriptor.
+
+ @return The maximum device context index of endpoint.
+
+**/
+UINT8
+EFIAPI
+XhcInitializeEndpointContext64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN INPUT_CONTEXT_64 *InputContext,
+ IN USB_INTERFACE_DESCRIPTOR *IfDesc
+ )
+{
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ UINT8 Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINT8 Interval;
+ TRANSFER_RING *EndpointTransferRing;
+
+ MaxDci = 0;
+
+ NumEp = IfDesc->NumEndpoints;
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcEndpointToDci (EpAddr, Direction);
+ ASSERT (Dci < 32);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
+ //
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ } else {
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ }
+
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
+ case USB_ENDPOINT_BULK:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
+ }
+
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
+ EpDesc->EndpointAddress,
+ EndpointTransferRing->RingSeg0,
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
+ ));
+ }
+
+ break;
+ case USB_ENDPOINT_ISO:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
+ }
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.
+ // Refer to XHCI 1.1 spec section 6.2.3.6.
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval + 2;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ //
+ // Do not support isochronous transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ case USB_ENDPOINT_INTERRUPT:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
+ }
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context
+ //
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
+ Interval = EpDesc->Interval;
+ //
+ // Calculate through the bInterval field of Endpoint descriptor.
+ //
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ //
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
+ //
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ InputContext->EP[Dci-1].CErr = 3;
+ }
+
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
+ EpDesc->EndpointAddress,
+ EndpointTransferRing->RingSeg0,
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)
+ ));
+ }
+ break;
+
+ case USB_ENDPOINT_CONTROL:
+ //
+ // Do not support control transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
+ default:
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ return MaxDci;
+}
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetConfigCmd (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ UINT8 Index;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ //
+ // 4.6.6 Configure Endpoint
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ continue;
+ }
+
+ Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // configure endpoint
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
+ } else {
+ Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
+ }
+
+ return Status;
+}
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetConfigCmd64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ UINT8 Index;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ //
+ // 4.6.6 Configure Endpoint
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ continue;
+ }
+
+ Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // configure endpoint
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
+ } else {
+ Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
+ }
+
+ return Status;
+}
+
+/**
+ Stop endpoint through XHCI's Stop_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+ @param PendingUrb The pending URB to check completion status when stopping the end point.
+
+ @retval EFI_SUCCESS Stop endpoint successfully.
+ @retval Others Failed to stop endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcStopEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *PendingUrb OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_TRB_STOP_ENDPOINT CmdTrbStopED;
+
+ DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+
+ //
+ // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
+ // the PendingUrb completion status, because it's possible that the PendingUrb is
+ // finished just before stopping the end point, but after the looping check.
+ //
+ // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
+ // through function parameter, but That will cause every consumer of XhcCmdTransfer,
+ // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
+ // But actually only XhcCheckUrbResult is aware of the PendingUrb.
+ // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
+ //
+ ASSERT (Xhc->PendingUrb == NULL);
+ Xhc->PendingUrb = PendingUrb;
+ //
+ // Reset the URB result from Timeout to NoError.
+ // The USB result will be:
+ // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
+ // remain NoError when Success/ShortPacket Transfer Event is received.
+ //
+ if (PendingUrb != NULL) {
+ PendingUrb->Result = EFI_USB_NOERROR;
+ }
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
+ CmdTrbStopED.CycleBit = 1;
+ CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;
+ CmdTrbStopED.EDID = Dci;
+ CmdTrbStopED.SlotId = SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
+ }
+
+ Xhc->PendingUrb = NULL;
+
+ return Status;
+}
+
+/**
+ Reset endpoint through XHCI's Reset_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+
+ @retval EFI_SUCCESS Reset endpoint successfully.
+ @retval Others Failed to reset endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcResetEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
+
+ DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
+ CmdTrbResetED.CycleBit = 1;
+ CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
+ CmdTrbResetED.EDID = Dci;
+ CmdTrbResetED.SlotId = SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+ @param Urb The dequeue pointer of the transfer ring specified
+ by the urb to be updated.
+
+ @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
+ @retval Others Failed to set transfer ring dequeue pointer.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetTrDequeuePointer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
+ CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
+ CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdSetTRDeq.CycleBit = 1;
+ CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
+ CmdSetTRDeq.Endpoint = Dci;
+ CmdSetTRDeq.SlotId = SlotId;
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Set interface through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+ @param Request USB device request to send.
+
+ @retval EFI_SUCCESS Successfully set interface.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetInterface (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDescActive;
+ USB_INTERFACE_DESCRIPTOR *IfDescSet;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ UINT8 Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *RingSeg;
+
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+
+ Status = EFI_SUCCESS;
+
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ //
+ // XHCI 4.6.6 Configure Endpoint
+ // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
+ // Context and Add Context flags as follows:
+ // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
+ // Context and Add Context flags to '0'.
+ //
+ // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
+ // So the default Drop Context and Add Context flags can be '0' to cover 1).
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDescActive = NULL;
+ IfDescSet = NULL;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
+ while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
+ if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
+ if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
+ if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
+ //
+ // Find out the active interface descriptor.
+ //
+ IfDescActive = IfDesc;
+ } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
+ //
+ // Find out the interface descriptor to set.
+ //
+ IfDescSet = IfDesc;
+ }
+ }
+ }
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ //
+ // XHCI 4.6.6 Configure Endpoint
+ // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
+ // Context and Add Context flags as follows:
+ // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
+ // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
+ // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
+ // the Drop Context flag to '1' and Add Context flag to '0'.
+ // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
+ // and Add Context flags shall be set to '1'.
+ //
+ // Below codes are to cover 2), 3) and 4).
+ //
+
+ if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
+ NumEp = IfDescActive->NumEndpoints;
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcEndpointToDci (EpAddr, Direction);
+ ASSERT (Dci < 32);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
+ //
+ Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
+ //
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
+ RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
+ }
+
+ //
+ // Set the Drop Context flag to '1'.
+ //
+ InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
+ // Interface setting, to '0'.
+ //
+ // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
+ //
+
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 4) For each endpoint enabled by the Configure Endpoint Command:
+ // a. Allocate a Transfer Ring.
+ // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
+ // c. Initialize the Endpoint Context data structure.
+ //
+ Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 5) Issue and successfully complete a Configure Endpoint Command.
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
+ } else {
+ //
+ // Update the active AlternateSetting.
+ //
+ Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set interface through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+ @param Request USB device request to send.
+
+ @retval EFI_SUCCESS Successfully set interface.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetInterface64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDescActive;
+ USB_INTERFACE_DESCRIPTOR *IfDescSet;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ UINT8 Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *RingSeg;
+
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+
+ Status = EFI_SUCCESS;
+
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ //
+ // XHCI 4.6.6 Configure Endpoint
+ // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
+ // Context and Add Context flags as follows:
+ // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
+ // Context and Add Context flags to '0'.
+ //
+ // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
+ // So the default Drop Context and Add Context flags can be '0' to cover 1).
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDescActive = NULL;
+ IfDescSet = NULL;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
+ while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {
+ if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {
+ if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {
+ if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {
+ //
+ // Find out the active interface descriptor.
+ //
+ IfDescActive = IfDesc;
+ } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {
+ //
+ // Find out the interface descriptor to set.
+ //
+ IfDescSet = IfDesc;
+ }
+ }
+ }
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ //
+ // XHCI 4.6.6 Configure Endpoint
+ // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
+ // Context and Add Context flags as follows:
+ // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
+ // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
+ // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
+ // the Drop Context flag to '1' and Add Context flag to '0'.
+ // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
+ // and Add Context flags shall be set to '1'.
+ //
+ // Below codes are to cover 2), 3) and 4).
+ //
+
+ if ((IfDescActive != NULL) && (IfDescSet != NULL)) {
+ NumEp = IfDescActive->NumEndpoints;
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcEndpointToDci (EpAddr, Direction);
+ ASSERT (Dci < 32);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
+ //
+ Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
+ //
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {
+ RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;
+ }
+
+ //
+ // Set the Drop Context flag to '1'.
+ //
+ InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ }
+
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
+ // Interface setting, to '0'.
+ //
+ // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
+ //
+
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 4) For each endpoint enabled by the Configure Endpoint Command:
+ // a. Allocate a Transfer Ring.
+ // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
+ // c. Initialize the Endpoint Context data structure.
+ //
+ Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // XHCI 4.3.6 - Setting Alternate Interfaces
+ // 5) Issue and successfully complete a Configure Endpoint Command.
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
+ } else {
+ //
+ // Update the active AlternateSetting.
+ //
+ Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcEvaluateContext (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ )
+{
+ EFI_STATUS Status;
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ InputContext->InputControlContext.Dword2 |= BIT1;
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;
+
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbEvalu.CycleBit = 1;
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Evaluate context\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcEvaluateContext64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ )
+{
+ EFI_STATUS Status;
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ InputContext->InputControlContext.Dword2 |= BIT1;
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;
+
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbEvalu.CycleBit = 1;
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Evaluate context\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcConfigHubContext (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+
+ //
+ // Copy the slot context from OutputContext to Input context
+ //
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
+ InputContext->Slot.Hub = 1;
+ InputContext->Slot.PortNum = PortNum;
+ InputContext->Slot.TTT = TTT;
+ InputContext->Slot.MTT = MTT;
+
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcConfigHubContext64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+
+ //
+ // Copy the slot context from OutputContext to Input context
+ //
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
+ InputContext->Slot.Hub = 1;
+ InputContext->Slot.PortNum = PortNum;
+ InputContext->Slot.TTT = TTT;
+ InputContext->Slot.MTT = MTT;
+
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
+ Status = XhcCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
new file mode 100644
index 000000000..2f1899502
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
@@ -0,0 +1,1487 @@
+/** @file
+
+ This file contains the definition for XHCI host controller schedule routines.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_XHCI_SCHED_H_
+#define _EFI_XHCI_SCHED_H_
+
+#define XHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define XHC_CTRL_TRANSFER 0x01
+#define XHC_BULK_TRANSFER 0x02
+#define XHC_INT_TRANSFER_SYNC 0x04
+#define XHC_INT_TRANSFER_ASYNC 0x08
+#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
+
+//
+// 6.4.6 TRB Types
+//
+#define TRB_TYPE_NORMAL 1
+#define TRB_TYPE_SETUP_STAGE 2
+#define TRB_TYPE_DATA_STAGE 3
+#define TRB_TYPE_STATUS_STAGE 4
+#define TRB_TYPE_ISOCH 5
+#define TRB_TYPE_LINK 6
+#define TRB_TYPE_EVENT_DATA 7
+#define TRB_TYPE_NO_OP 8
+#define TRB_TYPE_EN_SLOT 9
+#define TRB_TYPE_DIS_SLOT 10
+#define TRB_TYPE_ADDRESS_DEV 11
+#define TRB_TYPE_CON_ENDPOINT 12
+#define TRB_TYPE_EVALU_CONTXT 13
+#define TRB_TYPE_RESET_ENDPOINT 14
+#define TRB_TYPE_STOP_ENDPOINT 15
+#define TRB_TYPE_SET_TR_DEQUE 16
+#define TRB_TYPE_RESET_DEV 17
+#define TRB_TYPE_GET_PORT_BANW 21
+#define TRB_TYPE_FORCE_HEADER 22
+#define TRB_TYPE_NO_OP_COMMAND 23
+#define TRB_TYPE_TRANS_EVENT 32
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
+
+//
+// Endpoint Type (EP Type).
+//
+#define ED_NOT_VALID 0
+#define ED_ISOCH_OUT 1
+#define ED_BULK_OUT 2
+#define ED_INTERRUPT_OUT 3
+#define ED_CONTROL_BIDIR 4
+#define ED_ISOCH_IN 5
+#define ED_BULK_IN 6
+#define ED_INTERRUPT_IN 7
+
+//
+// 6.4.5 TRB Completion Codes
+//
+#define TRB_COMPLETION_INVALID 0
+#define TRB_COMPLETION_SUCCESS 1
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
+#define TRB_COMPLETION_BABBLE_ERROR 3
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
+#define TRB_COMPLETION_TRB_ERROR 5
+#define TRB_COMPLETION_STALL_ERROR 6
+#define TRB_COMPLETION_SHORT_PACKET 13
+#define TRB_COMPLETION_STOPPED 26
+#define TRB_COMPLETION_STOPPED_LENGTH_INVALID 27
+
+//
+// The topology string used to present usb device location
+//
+typedef struct _USB_DEV_TOPOLOGY {
+ //
+ // The tier concatenation of down stream port.
+ //
+ UINT32 RouteString:20;
+ //
+ // The root port number of the chain.
+ //
+ UINT32 RootPortNum:8;
+ //
+ // The Tier the device reside.
+ //
+ UINT32 TierNum:4;
+} USB_DEV_TOPOLOGY;
+
+//
+// USB Device's RouteChart
+//
+typedef union _USB_DEV_ROUTE {
+ UINT32 Dword;
+ USB_DEV_TOPOLOGY Route;
+} USB_DEV_ROUTE;
+
+//
+// Endpoint address and its capabilities
+//
+typedef struct _USB_ENDPOINT {
+ //
+ // Store logical device address assigned by UsbBus
+ // It's because some XHCI host controllers may assign the same physcial device
+ // address for those devices inserted at different root port.
+ //
+ UINT8 BusAddr;
+ UINT8 DevAddr;
+ UINT8 EpAddr;
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 DevSpeed;
+ UINTN MaxPacket;
+ UINTN Type;
+} USB_ENDPOINT;
+
+//
+// TRB Template
+//
+typedef struct _TRB_TEMPLATE {
+ UINT32 Parameter1;
+
+ UINT32 Parameter2;
+
+ UINT32 Status;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:9;
+ UINT32 Type:6;
+ UINT32 Control:16;
+} TRB_TEMPLATE;
+
+typedef struct _TRANSFER_RING {
+ VOID *RingSeg0;
+ UINTN TrbNumber;
+ TRB_TEMPLATE *RingEnqueue;
+ TRB_TEMPLATE *RingDequeue;
+ UINT32 RingPCS;
+} TRANSFER_RING;
+
+typedef struct _EVENT_RING {
+ VOID *ERSTBase;
+ VOID *EventRingSeg0;
+ UINTN TrbNumber;
+ TRB_TEMPLATE *EventRingEnqueue;
+ TRB_TEMPLATE *EventRingDequeue;
+ UINT32 EventRingCCS;
+} EVENT_RING;
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+typedef struct _URB {
+ UINT32 Signature;
+ LIST_ENTRY UrbList;
+ //
+ // Usb Device URB related information
+ //
+ USB_ENDPOINT Ep;
+ EFI_USB_DEVICE_REQUEST *Request;
+ VOID *Data;
+ UINTN DataLen;
+ VOID *DataPhy;
+ VOID *DataMap;
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
+ VOID *Context;
+ //
+ // Execute result
+ //
+ UINT32 Result;
+ //
+ // completed data length
+ //
+ UINTN Completed;
+ //
+ // Command/Tranfer Ring info
+ //
+ TRANSFER_RING *Ring;
+ TRB_TEMPLATE *TrbStart;
+ TRB_TEMPLATE *TrbEnd;
+ UINTN TrbNum;
+ BOOLEAN StartDone;
+ BOOLEAN EndDone;
+ BOOLEAN Finished;
+
+ TRB_TEMPLATE *EvtTrb;
+} URB;
+
+//
+// 6.5 Event Ring Segment Table
+// The Event Ring Segment Table is used to define multi-segment Event Rings and to enable runtime
+// expansion and shrinking of the Event Ring. The location of the Event Ring Segment Table is defined by the
+// Event Ring Segment Table Base Address Register (5.5.2.3.2). The size of the Event Ring Segment Table
+// is defined by the Event Ring Segment Table Base Size Register (5.5.2.3.1).
+//
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
+ UINT32 PtrLo;
+ UINT32 PtrHi;
+ UINT32 RingTrbSize:16;
+ UINT32 RsvdZ1:16;
+ UINT32 RsvdZ2;
+} EVENT_RING_SEG_TABLE_ENTRY;
+
+//
+// 6.4.1.1 Normal TRB
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
+// Rings, and to define the Data stage information for Control Transfer Rings.
+//
+typedef struct _TRANSFER_TRB_NORMAL {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:2;
+ UINT32 BEI:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ2:16;
+} TRANSFER_TRB_NORMAL;
+
+//
+// 6.4.1.2.1 Setup Stage TRB
+// A Setup Stage TRB is created by system software to initiate a USB Setup packet on a control endpoint.
+//
+typedef struct _TRANSFER_TRB_CONTROL_SETUP {
+ UINT32 bmRequestType:8;
+ UINT32 bRequest:8;
+ UINT32 wValue:16;
+
+ UINT32 wIndex:16;
+ UINT32 wLength:16;
+
+ UINT32 Length:17;
+ UINT32 RsvdZ1:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:4;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ3:3;
+ UINT32 Type:6;
+ UINT32 TRT:2;
+ UINT32 RsvdZ4:14;
+} TRANSFER_TRB_CONTROL_SETUP;
+
+//
+// 6.4.1.2.2 Data Stage TRB
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.
+//
+typedef struct _TRANSFER_TRB_CONTROL_DATA {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:3;
+ UINT32 Type:6;
+ UINT32 DIR:1;
+ UINT32 RsvdZ2:15;
+} TRANSFER_TRB_CONTROL_DATA;
+
+//
+// 6.4.1.2.2 Data Stage TRB
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.
+//
+typedef struct _TRANSFER_TRB_CONTROL_STATUS {
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 RsvdZ3:22;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 RsvdZ4:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ5:4;
+ UINT32 Type:6;
+ UINT32 DIR:1;
+ UINT32 RsvdZ6:15;
+} TRANSFER_TRB_CONTROL_STATUS;
+
+//
+// 6.4.2.1 Transfer Event TRB
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
+// for more information on the use and operation of Transfer Events.
+//
+typedef struct _EVT_TRB_TRANSFER {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:1;
+ UINT32 ED:1;
+ UINT32 RsvdZ2:7;
+ UINT32 Type:6;
+ UINT32 EndpointId:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} EVT_TRB_TRANSFER;
+
+//
+// 6.4.2.2 Command Completion Event TRB
+// A Command Completion Event TRB shall be generated by the xHC when a command completes on the
+// Command Ring. Refer to section 4.11.4 for more information on the use of Command Completion Events.
+//
+typedef struct _EVT_TRB_COMMAND_COMPLETION {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 RsvdZ2:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 VFID:8;
+ UINT32 SlotId:8;
+} EVT_TRB_COMMAND_COMPLETION;
+
+typedef union _TRB {
+ TRB_TEMPLATE TrbTemplate;
+ TRANSFER_TRB_NORMAL TrbNormal;
+ TRANSFER_TRB_CONTROL_SETUP TrbCtrSetup;
+ TRANSFER_TRB_CONTROL_DATA TrbCtrData;
+ TRANSFER_TRB_CONTROL_STATUS TrbCtrStatus;
+} TRB;
+
+//
+// 6.4.3.1 No Op Command TRB
+// The No Op Command TRB provides a simple means for verifying the operation of the Command Ring
+// mechanisms offered by the xHCI.
+//
+typedef struct _CMD_TRB_NO_OP {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} CMD_TRB_NO_OP;
+
+//
+// 6.4.3.2 Enable Slot Command TRB
+// The Enable Slot Command TRB causes the xHC to select an available Device Slot and return the ID of the
+// selected slot to the host in a Command Completion Event.
+//
+typedef struct _CMD_TRB_ENABLE_SLOT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} CMD_TRB_ENABLE_SLOT;
+
+//
+// 6.4.3.3 Disable Slot Command TRB
+// The Disable Slot Command TRB releases any bandwidth assigned to the disabled slot and frees any
+// internal xHC resources assigned to the slot.
+//
+typedef struct _CMD_TRB_DISABLE_SLOT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:8;
+ UINT32 SlotId:8;
+} CMD_TRB_DISABLE_SLOT;
+
+//
+// 6.4.3.4 Address Device Command TRB
+// The Address Device Command TRB transitions the selected Device Context from the Default to the
+// Addressed state and causes the xHC to select an address for the USB device in the Default State and
+// issue a SET_ADDRESS request to the USB device.
+//
+typedef struct _CMD_TRB_ADDRESS_DEVICE {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:8;
+ UINT32 BSR:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_ADDRESS_DEVICE;
+
+//
+// 6.4.3.5 Configure Endpoint Command TRB
+// The Configure Endpoint Command TRB evaluates the bandwidth and resource requirements of the
+// endpoints selected by the command.
+//
+typedef struct _CMD_TRB_CONFIG_ENDPOINT {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:8;
+ UINT32 DC:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_CONFIG_ENDPOINT;
+
+//
+// 6.4.3.6 Evaluate Context Command TRB
+// The Evaluate Context Command TRB is used by system software to inform the xHC that the selected
+// Context data structures in the Device Context have been modified by system software and that the xHC
+// shall evaluate any changes
+//
+typedef struct _CMD_TRB_EVALUATE_CONTEXT {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_EVALUATE_CONTEXT;
+
+//
+// 6.4.3.7 Reset Endpoint Command TRB
+// The Reset Endpoint Command TRB is used by system software to reset a specified Transfer Ring
+//
+typedef struct _CMD_TRB_RESET_ENDPOINT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:8;
+ UINT32 TSP:1;
+ UINT32 Type:6;
+ UINT32 EDID:5;
+ UINT32 RsvdZ4:3;
+ UINT32 SlotId:8;
+} CMD_TRB_RESET_ENDPOINT;
+
+//
+// 6.4.3.8 Stop Endpoint Command TRB
+// The Stop Endpoint Command TRB command allows software to stop the xHC execution of the TDs on a
+// Transfer Ring and temporarily take ownership of TDs that had previously been passed to the xHC.
+//
+typedef struct _CMD_TRB_STOP_ENDPOINT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 EDID:5;
+ UINT32 RsvdZ4:2;
+ UINT32 SP:1;
+ UINT32 SlotId:8;
+} CMD_TRB_STOP_ENDPOINT;
+
+//
+// 6.4.3.9 Set TR Dequeue Pointer Command TRB
+// The Set TR Dequeue Pointer Command TRB is used by system software to modify the TR Dequeue
+// Pointer and DCS fields of an Endpoint or Stream Context.
+//
+typedef struct _CMD_SET_TR_DEQ_POINTER {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:16;
+ UINT32 StreamID:16;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:9;
+ UINT32 Type:6;
+ UINT32 Endpoint:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} CMD_SET_TR_DEQ_POINTER;
+
+//
+// 6.4.4.1 Link TRB
+// A Link TRB provides support for non-contiguous TRB Rings.
+//
+typedef struct _LINK_TRB {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:22;
+ UINT32 InterTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 TC:1;
+ UINT32 RsvdZ2:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ3:4;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} LINK_TRB;
+
+//
+// 6.2.2 Slot Context
+//
+typedef struct _SLOT_CONTEXT {
+ UINT32 RouteString:20;
+ UINT32 Speed:4;
+ UINT32 RsvdZ1:1;
+ UINT32 MTT:1;
+ UINT32 Hub:1;
+ UINT32 ContextEntries:5;
+
+ UINT32 MaxExitLatency:16;
+ UINT32 RootHubPortNum:8;
+ UINT32 PortNum:8;
+
+ UINT32 TTHubSlotId:8;
+ UINT32 TTPortNum:8;
+ UINT32 TTT:2;
+ UINT32 RsvdZ2:4;
+ UINT32 InterTarget:10;
+
+ UINT32 DeviceAddress:8;
+ UINT32 RsvdZ3:19;
+ UINT32 SlotState:5;
+
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+} SLOT_CONTEXT;
+
+typedef struct _SLOT_CONTEXT_64 {
+ UINT32 RouteString:20;
+ UINT32 Speed:4;
+ UINT32 RsvdZ1:1;
+ UINT32 MTT:1;
+ UINT32 Hub:1;
+ UINT32 ContextEntries:5;
+
+ UINT32 MaxExitLatency:16;
+ UINT32 RootHubPortNum:8;
+ UINT32 PortNum:8;
+
+ UINT32 TTHubSlotId:8;
+ UINT32 TTPortNum:8;
+ UINT32 TTT:2;
+ UINT32 RsvdZ2:4;
+ UINT32 InterTarget:10;
+
+ UINT32 DeviceAddress:8;
+ UINT32 RsvdZ3:19;
+ UINT32 SlotState:5;
+
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+
+} SLOT_CONTEXT_64;
+
+
+//
+// 6.2.3 Endpoint Context
+//
+typedef struct _ENDPOINT_CONTEXT {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2;
+ UINT32 MaxPStreams:5;
+ UINT32 LSA:1;
+ UINT32 Interval:8;
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1;
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16;
+
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+} ENDPOINT_CONTEXT;
+
+typedef struct _ENDPOINT_CONTEXT_64 {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2;
+ UINT32 MaxPStreams:5;
+ UINT32 LSA:1;
+ UINT32 Interval:8;
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1;
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16;
+
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+
+} ENDPOINT_CONTEXT_64;
+
+
+//
+// 6.2.5.1 Input Control Context
+//
+typedef struct _INPUT_CONTRL_CONTEXT {
+ UINT32 Dword1;
+ UINT32 Dword2;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+ UINT32 RsvdZ3;
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+} INPUT_CONTRL_CONTEXT;
+
+typedef struct _INPUT_CONTRL_CONTEXT_64 {
+ UINT32 Dword1;
+ UINT32 Dword2;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+ UINT32 RsvdZ3;
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+} INPUT_CONTRL_CONTEXT_64;
+
+//
+// 6.2.1 Device Context
+//
+typedef struct _DEVICE_CONTEXT {
+ SLOT_CONTEXT Slot;
+ ENDPOINT_CONTEXT EP[31];
+} DEVICE_CONTEXT;
+
+typedef struct _DEVICE_CONTEXT_64 {
+ SLOT_CONTEXT_64 Slot;
+ ENDPOINT_CONTEXT_64 EP[31];
+} DEVICE_CONTEXT_64;
+
+//
+// 6.2.5 Input Context
+//
+typedef struct _INPUT_CONTEXT {
+ INPUT_CONTRL_CONTEXT InputControlContext;
+ SLOT_CONTEXT Slot;
+ ENDPOINT_CONTEXT EP[31];
+} INPUT_CONTEXT;
+
+typedef struct _INPUT_CONTEXT_64 {
+ INPUT_CONTRL_CONTEXT_64 InputControlContext;
+ SLOT_CONTEXT_64 Slot;
+ ENDPOINT_CONTEXT_64 EP[31];
+} INPUT_CONTEXT_64;
+
+
+/**
+ Initialize the XHCI host controller for schedule.
+
+ @param Xhc The XHCI Instance to be initialized.
+
+**/
+VOID
+XhcInitSched (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Free the resouce allocated at initializing schedule.
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcFreeSched (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed through URB.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to be rung.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+RingIntTransferDoorBell (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Xhc The XHCI Instance.
+ @param CmdTransfer The executed URB is for cmd transfer or not.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+XhcExecTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN BOOLEAN CmdTransfer,
+ IN URB *Urb,
+ IN UINTN Timeout
+ );
+
+/**
+ Delete a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Xhc The XHCI Instance.
+ @param BusAddr The logical device address assigned by UsbBus driver.
+ @param EpNum The endpoint of the target.
+
+ @retval EFI_SUCCESS An asynchronous transfer is removed.
+ @retval EFI_NOT_FOUND No transfer for the device is found.
+
+**/
+EFI_STATUS
+XhciDelAsyncIntTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpNum
+ );
+
+/**
+ Remove all the asynchronous interrupt transfers.
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhciDelAllAsyncIntTransfers (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Insert a single asynchronous interrupt transfer for
+ the device and endpoint.
+
+ @param Xhc The XHCI Instance
+ @param BusAddr The logical device address assigned by UsbBus driver
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB *
+XhciInsertAsyncIntTransfer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ );
+
+/**
+ Set Bios Ownership
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcSetBiosOwnership (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Clear Bios Ownership
+
+ @param Xhc The XHCI Instance.
+
+**/
+VOID
+XhcClearBiosOwnership (
+ IN USB_XHCI_INSTANCE *Xhc
+ );
+
+/**
+ Find out the slot id according to the device's route string.
+
+ @param Xhc The XHCI Instance.
+ @param RouteString The route string described the device location.
+
+ @return The slot id used by the device.
+
+**/
+UINT8
+EFIAPI
+XhcRouteStringToSlotId (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE RouteString
+ );
+
+/**
+ Calculate the device context index by endpoint address and direction.
+
+ @param EpAddr The target endpoint number.
+ @param Direction The direction of the target endpoint.
+
+ @return The device context index of endpoint.
+
+**/
+UINT8
+XhcEndpointToDci (
+ IN UINT8 EpAddr,
+ IN UINT8 Direction
+ );
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRingDoorBell (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ );
+
+/**
+ Interrupt transfer periodic check handler.
+
+ @param Event Interrupt event.
+ @param Context Pointer to USB_XHCI_INSTANCE.
+
+**/
+VOID
+EFIAPI
+XhcMonitorAsyncRequests (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device if it exists.
+ @param Port The port to be polled.
+ @param PortState The port state.
+
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
+ @retval Others Should not appear.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPollPortStatusChange (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_STATUS *PortState
+ );
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcConfigHubContext (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ );
+
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcConfigHubContext64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ );
+
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetConfigCmd (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ );
+
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetConfigCmd64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ );
+
+/**
+ Set interface through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+ @param Request USB device request to send.
+
+ @retval EFI_SUCCESS Successfully set interface.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetInterface (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ );
+
+/**
+ Set interface through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+ @param Request USB device request to send.
+
+ @retval EFI_SUCCESS Successfully set interface.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetInterface64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc,
+ IN EFI_USB_DEVICE_REQUEST *Request
+ );
+
+/**
+ Find out the actual device address according to the requested device address from UsbBus.
+
+ @param Xhc The XHCI Instance.
+ @param BusDevAddr The requested device address by UsbBus upper driver.
+
+ @return The actual device address assigned to the device.
+
+**/
+UINT8
+EFIAPI
+XhcBusDevAddrToSlotId (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 BusDevAddr
+ );
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcInitializeDeviceSlot (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ );
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI Instance.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcInitializeDeviceSlot64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ );
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcEvaluateContext (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ );
+
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcEvaluateContext64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ );
+
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDisableSlotCmd (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId
+ );
+
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDisableSlotCmd64 (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId
+ );
+
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncTrsRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ TRANSFER_RING *TrsRing
+ );
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncEventRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ EVENT_RING *EvtRing
+ );
+
+/**
+ Check if there is a new generated event.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCheckNewEvent (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ );
+
+/**
+ Create XHCI transfer ring.
+
+ @param Xhc The XHCI Instance.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+CreateTransferRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINTN TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ );
+
+/**
+ Create XHCI event ring.
+
+ @param Xhc The XHCI Instance.
+ @param EventRing The created event ring.
+
+**/
+VOID
+CreateEventRing (
+ IN USB_XHCI_INSTANCE *Xhc,
+ OUT EVENT_RING *EventRing
+ );
+
+/**
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
+ Stopped to the Running state.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The urb which makes the endpoint halted.
+
+ @retval EFI_SUCCESS The recovery is successful.
+ @retval Others Failed to recovery halted endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRecoverHaltedEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
+ Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
+ the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
+ state.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The urb which doesn't get completed in a specified timeout range.
+
+ @retval EFI_SUCCESS The dequeuing of the TDs is successful.
+ @retval Others Failed to stop the endpoint and dequeue the TDs.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDequeueTrbFromEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Stop endpoint through XHCI's Stop_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+ @param PendingUrb The pending URB to check completion status when stopping the end point.
+
+ @retval EFI_SUCCESS Stop endpoint successfully.
+ @retval Others Failed to stop endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcStopEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *PendingUrb OPTIONAL
+ );
+
+/**
+ Reset endpoint through XHCI's Reset_Endpoint cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+
+ @retval EFI_SUCCESS Reset endpoint successfully.
+ @retval Others Failed to reset endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcResetEndpoint (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ );
+
+/**
+ Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
+
+ @param Xhc The XHCI Instance.
+ @param SlotId The slot id to be configured.
+ @param Dci The device context index of endpoint.
+ @param Urb The dequeue pointer of the transfer ring specified
+ by the urb to be updated.
+
+ @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
+ @retval Others Failed to set transfer ring dequeue pointer.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSetTrDequeuePointer (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *Urb
+ );
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Xhc The XHCI Instance
+ @param DevAddr The device address
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param Type The transaction type
+ @param Request The standard USB request for control transfer
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcCreateUrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ );
+
+/**
+ Free an allocated URB.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+XhcFreeUrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Create a transfer TRB.
+
+ @param Xhc The XHCI Instance
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcCreateTransferTrb (
+ IN USB_XHCI_INSTANCE *Xhc,
+ IN URB *Urb
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
new file mode 100644
index 000000000..c4d93aea2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
@@ -0,0 +1,370 @@
+/** @file
+The DMA memory help function.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XhcPeim.h"
+
+EDKII_IOMMU_PPI *mIoMmu;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Map (
+ mIoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates aligned pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateAlignedBuffer (
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ AlignmentMask = Alignment - 1;
+
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ RealPages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Memory = *HostAddress;
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = mIoMmu->FreeBuffer (
+ mIoMmu,
+ UnalignedPages,
+ Memory);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = mIoMmu->FreeBuffer (
+ mIoMmu,
+ UnalignedPages,
+ Memory);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ *HostAddress = (VOID *) AlignedMemory;
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ RealPages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask);
+ *DeviceAddress = ((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&mIoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
new file mode 100644
index 000000000..01f422853
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
@@ -0,0 +1,631 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XhcPeim.h"
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pages How many pages to allocate.
+
+ @return Pointer to the allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ UINTN PageNumber;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK));
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (USBHC_MEM_BLOCK *) (UINTN) TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+
+ PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen);
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
+
+ Block->Bits = (UINT8 *) (UINTN) TempPtr;
+
+ Status = IoMmuAllocateBuffer (
+ Pages,
+ &BufHost,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *) (UINTN) BufHost, EFI_PAGES_TO_SIZE (Pages));
+
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+}
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+
+ //
+ // No free memory in PEI.
+ //
+}
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory.
+ If couldn't allocate the needed memory, the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return The pci memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddrForHostAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *) Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+/**
+ Calculate the corresponding host address according to the pci address.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to pci memory.
+ @param Size The size of the memory region.
+
+ @return The host memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetHostAddrForPciAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS HostAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the host memory address for pci memory address.
+ //
+ Offset = (UINT8 *) Mem - Block->Buf;
+ HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset);
+ return HostAddr;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @return Pointer to the allocated memory pool or NULL if failed.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ VOID
+ )
+{
+ USBHC_MEM_POOL *Pool;
+ UINTN PageNumber;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL));
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ PageNumber,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
+
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
+ Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ //
+ // No free memory in PEI.
+ //
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+**/
+VOID
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ //UsbHcUnlinkMemBlock (Pool->Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+}
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize);
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+ NewBlock = UsbHcAllocMemBlock (Pages);
+
+ if (NewBlock == NULL) {
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory pointer
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ //UsbHcUnlinkMemBlock (Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+}
+
+/**
+ Allocates pages at a specified alignment.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to
+ use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS Success to allocate aligned pages.
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
+
+**/
+EFI_STATUS
+UsbHcAllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+ EFI_PHYSICAL_ADDRESS DeviceMemory;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if ((Alignment & (Alignment - 1)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Pages == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Alignment > EFI_PAGE_SIZE) {
+ Status = IoMmuAllocateAlignedBuffer (
+ Pages,
+ Alignment,
+ &Memory,
+ &DeviceMemory,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = IoMmuAllocateBuffer (
+ Pages,
+ &Memory,
+ &DeviceMemory,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ *HostAddress = Memory;
+ *DeviceAddress = DeviceMemory;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().
+
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param Pages The number of pages to free.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+UsbHcFreeAlignedPages (
+ IN VOID *HostAddress,
+ IN UINTN Pages,
+ IN VOID *Mapping
+ )
+{
+ ASSERT (Pages != 0);
+
+ IoMmuFreeBuffer (Pages, HostAddress, Mapping);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
new file mode 100644
index 000000000..5aa41397f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
@@ -0,0 +1,140 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PEI_XHCI_MEM_H_
+#define _EFI_PEI_XHCI_MEM_H_
+
+#include <Uefi.h>
+
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. XHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return The pci memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddrForHostAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding host address according to the pci address.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to pci memory.
+ @param Size The size of the memory region.
+
+ @return The host memory address
+
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetHostAddrForPciAddr (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Allocates pages at a specified alignment.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to
+ use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS Success to allocate aligned pages.
+ @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
+
+**/
+EFI_STATUS
+UsbHcAllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with UsbHcAllocateAlignedPages().
+
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param Pages The number of pages to free.
+ @param Mapping The mapping value returned from Map().
+
+**/
+VOID
+UsbHcFreeAlignedPages (
+ IN VOID *HostAddress,
+ IN UINTN Pages,
+ IN VOID *Mapping
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
new file mode 100644
index 000000000..4b670ebed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
@@ -0,0 +1,1554 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XhcPeim.h"
+
+//
+// Two arrays used to translate the XHCI port state (change)
+// to the UEFI protocol's port state (change).
+//
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {
+ {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
+ {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},
+ {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
+ {XHC_PORTSC_PP, USB_PORT_STAT_POWER},
+ {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
+};
+
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
+ {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
+ {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
+ {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
+ {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
+};
+
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
+ {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_PORTSC_PRC, EfiUsbPortResetChange}
+};
+
+USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
+ {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
+ {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
+ {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
+ {XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER},
+ {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
+};
+
+USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
+ {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
+ {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
+ {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
+ {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
+};
+
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
+ {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
+ {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
+};
+
+/**
+ Read XHCI Operation register.
+
+ @param Xhc The XHCI device.
+ @param Offset The operation register offset.
+
+ @retval the register content read.
+
+**/
+UINT32
+XhcPeiReadOpReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ ASSERT (Xhc->CapLength != 0);
+
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);
+ return Data;
+}
+
+/**
+ Write the data to the XHCI operation register.
+
+ @param Xhc The XHCI device.
+ @param Offset The operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteOpReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Xhc->CapLength != 0);
+
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);
+}
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiSetOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcPeiReadOpReg (Xhc, Offset);
+ Data |= Bit;
+ XhcPeiWriteOpReg (Xhc, Offset, Data);
+}
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcPeiClearOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcPeiReadOpReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcPeiWriteOpReg (Xhc, Offset, Data);
+}
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to become set (or clear).
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcPeiWaitOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ )
+{
+ UINT64 Index;
+
+ for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {
+ if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
+ return EFI_SUCCESS;
+ }
+
+ MicroSecondDelay (XHC_1_MICROSECOND);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Read XHCI capability register.
+
+ @param Xhc The XHCI device.
+ @param Offset Capability register address.
+
+ @retval the register content read.
+
+**/
+UINT32
+XhcPeiReadCapRegister (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);
+
+ return Data;
+}
+
+
+
+/**
+ Write the data to the XHCI door bell register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the door bell register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteDoorBellReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Xhc->DBOff != 0);
+
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);
+}
+
+/**
+ Read XHCI runtime register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcPeiReadRuntimeReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ ASSERT (Xhc->RTSOff != 0);
+
+ Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);
+
+ return Data;
+}
+
+/**
+ Write the data to the XHCI runtime register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteRuntimeReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Xhc->RTSOff != 0);
+
+ MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);
+}
+
+/**
+ Set one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiSetRuntimeRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcPeiReadRuntimeReg (Xhc, Offset);
+ Data |= Bit;
+ XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
+}
+
+/**
+ Clear one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiClearRuntimeRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcPeiReadRuntimeReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcPeiWriteRuntimeReg (Xhc, Offset, Data);
+}
+
+/**
+ Check whether Xhc is halted.
+
+ @param Xhc The XHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE The controller isn't halted.
+
+**/
+BOOLEAN
+XhcPeiIsHalt (
+ IN PEI_XHC_DEV *Xhc
+ )
+{
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
+}
+
+/**
+ Check whether system error occurred.
+
+ @param Xhc The XHCI device.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+XhcPeiIsSysError (
+ IN PEI_XHC_DEV *Xhc
+ )
+{
+ return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
+}
+
+/**
+ Reset the host controller.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval Others Failed to reset the host.
+
+**/
+EFI_STATUS
+XhcPeiResetHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Host can only be reset when it is halt. If not so, halt it
+ //
+ if (!XhcPeiIsHalt (Xhc)) {
+ Status = XhcPeiHaltHC (Xhc, Timeout);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
+ //
+ // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
+ // Otherwise there may have the timeout case happened.
+ // The below is a workaround to solve such problem.
+ //
+ MicroSecondDelay (1000);
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));
+ return Status;
+}
+
+/**
+ Halt the host controller.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
+ @retval EFI_SUCCESS The XHCI is halt.
+
+**/
+EFI_STATUS
+XhcPeiHaltHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
+ DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));
+ return Status;
+}
+
+/**
+ Set the XHCI to run.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The XHCI is running.
+ @retval Others Failed to set the XHCI to run.
+
+**/
+EFI_STATUS
+XhcPeiRunHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
+ Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
+ DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));
+ return Status;
+}
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Translator Transaction translator to be used by this device.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ PEI_XHC_DEV *Xhc;
+ URB *Urb;
+ UINT8 Endpoint;
+ UINT8 Index;
+ UINT8 DescriptorType;
+ UINT8 SlotId;
+ UINT8 TTT;
+ UINT8 MTT;
+ UINT32 MaxPacket0;
+ EFI_USB_HUB_DESCRIPTOR *HubDesc;
+ EFI_STATUS Status;
+ EFI_STATUS RecoveryStatus;
+ UINTN MapSize;
+ EFI_USB_PORT_STATUS PortStatus;
+ UINT32 State;
+ EFI_USB_DEVICE_REQUEST ClearPortRequest;
+ UINTN Len;
+
+ //
+ // Validate parameters
+ //
+ if ((Request == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbDataIn) &&
+ (TransferDirection != EfiUsbDataOut) &&
+ (TransferDirection != EfiUsbNoData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection == EfiUsbNoData) &&
+ ((Data != NULL) || (*DataLength != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) &&
+ ((Data == NULL) || (*DataLength == 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
+ (MaximumPacketLength != 512)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+
+ Status = EFI_DEVICE_ERROR;
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Len = 0;
+
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Hook the Set_Address request from UsbBus.
+ // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
+ //
+ if ((Request->Request == USB_REQ_SET_ADDRESS) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
+ //
+ // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
+ // This way is used to clean the history to avoid using wrong device address afterwards.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {
+ Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
+ goto ON_EXIT;
+ }
+ //
+ // The actual device address has been assigned by XHCI during initializing the device slot.
+ // So we just need establish the mapping relationship between the device address requested from UsbBus
+ // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
+ // can find out the actual device address by it.
+ //
+ Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ // Note that we encode the direction in address although default control
+ // endpoint is bidirectional. XhcPeiCreateUrb expects this
+ // combination of Ep addr and its direction.
+ //
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
+ Urb = XhcPeiCreateUrb (
+ Xhc,
+ DeviceAddress,
+ Endpoint,
+ DeviceSpeed,
+ MaximumPacketLength,
+ XHC_CTRL_TRANSFER,
+ Request,
+ Data,
+ *DataLength,
+ NULL,
+ NULL
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
+
+ //
+ // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
+ // which is called by XhcPeiExecTransfer
+ //
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if (Status == EFI_TIMEOUT) {
+ //
+ // The transfer timed out. Abort the transfer by dequeueing of the TD.
+ //
+ RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
+ if (EFI_ERROR(RecoveryStatus)) {
+ DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
+ }
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
+ } else {
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
+ RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
+ if (EFI_ERROR (RecoveryStatus)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
+ }
+ Status = EFI_DEVICE_ERROR;
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
+ } else {
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
+ }
+ }
+ //
+ // Unmap data before consume.
+ //
+ XhcPeiFreeUrb (Xhc, Urb);
+
+ //
+ // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
+ // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.
+ //
+ if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
+ DescriptorType = (UINT8) (Request->Value >> 8);
+ if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
+ ASSERT (Data != NULL);
+ //
+ // Store a copy of device scriptor as hub device need this info to configure endpoint.
+ //
+ CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
+ if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
+ //
+ // If it's a usb3.0 device, then its max packet size is a 2^n.
+ //
+ MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
+ } else {
+ MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
+ }
+ Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
+ if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
+ } else {
+ Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);
+ }
+ } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
+ ASSERT (Data != NULL);
+ if (*DataLength == ((UINT16 *) Data)[1]) {
+ //
+ // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
+ //
+ Index = (UINT8) Request->Value;
+ ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
+ Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
+ }
+ } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
+ (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
+ ASSERT (Data != NULL);
+ HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;
+ ASSERT (HubDesc->NumPorts <= 15);
+ //
+ // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
+ //
+ TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
+ if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
+ //
+ // Don't support multi-TT feature for super speed hub now.
+ //
+ MTT = 0;
+ DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
+ } else {
+ MTT = 0;
+ }
+
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
+ } else {
+ Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
+ }
+ }
+ } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
+ //
+ // Hook Set_Config request from UsbBus as we need configure device endpoint.
+ //
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ } else {
+ Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ break;
+ }
+ }
+ } else if ((Request->Request == USB_REQ_GET_STATUS) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
+ ASSERT (Data != NULL);
+ //
+ // Hook Get_Status request from UsbBus to keep track of the port status change.
+ //
+ State = *(UINT32 *) Data;
+ PortStatus.PortStatus = 0;
+ PortStatus.PortChangeStatus = 0;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // For super speed hub, its bit10~12 presents the attached device speed.
+ //
+ if ((State & XHC_PORTSC_PS) >> 10 == 0) {
+ PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
+ }
+ } else {
+ //
+ // For high or full/low speed hub, its bit9~10 presents the attached device speed.
+ //
+ if (XHC_BIT_IS_SET (State, BIT9)) {
+ PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ } else if (XHC_BIT_IS_SET (State, BIT10)) {
+ PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ }
+ }
+
+ //
+ // Convert the XHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
+ PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
+ PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
+ ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+ ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
+ ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
+ ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
+ ClearPortRequest.Index = Request->Index;
+ ClearPortRequest.Length = 0;
+
+ XhcPeiControlTransfer (
+ PeiServices,
+ This,
+ DeviceAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ &ClearPortRequest,
+ EfiUsbNoData,
+ NULL,
+ &Len,
+ TimeOut,
+ Translator,
+ TransferResult
+ );
+ }
+ }
+
+ XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
+
+ *(UINT32 *) Data = *(UINT32 *) &PortStatus;
+ }
+
+ON_EXIT:
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ return Status;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param DeviceSpeed Device speed, Low speed device doesn't support
+ bulk transfer.
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for the function
+ to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Translator A pointr to the transaction translator data.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ )
+{
+ PEI_XHC_DEV *Xhc;
+ URB *Urb;
+ UINT8 SlotId;
+ EFI_STATUS Status;
+ EFI_STATUS RecoveryStatus;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||
+ ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if the device is still enabled before every transaction.
+ //
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);
+ if (SlotId == 0) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = XhcPeiCreateUrb (
+ Xhc,
+ DeviceAddress,
+ EndPointAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ XHC_BULK_TRANSFER,
+ NULL,
+ Data[0],
+ *DataLength,
+ NULL,
+ NULL
+ );
+
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if (Status == EFI_TIMEOUT) {
+ //
+ // The transfer timed out. Abort the transfer by dequeueing of the TD.
+ //
+ RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);
+ if (EFI_ERROR(RecoveryStatus)) {
+ DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
+ }
+ } else {
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ } else if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
+ RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);
+ if (EFI_ERROR (RecoveryStatus)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
+ }
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ XhcPeiFreeUrb (Xhc, Urb);
+
+ON_EXIT:
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ )
+{
+ PEI_XHC_DEV *XhcDev;
+ XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+
+ if (PortNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ PEI_XHC_DEV *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ EFI_STATUS Status;
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
+ State = XhcPeiReadOpReg (Xhc, Offset);
+ DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bits
+ //
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
+ // A port may be disabled by software writing a '1' to this flag.
+ //
+ State |= XHC_PORTSC_PED;
+ State &= ~XHC_PORTSC_RESET;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= XHC_PORTSC_LWS;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ State &= ~XHC_PORTSC_PLS;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
+ // Register bits indicate status when read, a clear bit may be set by
+ // writing a '1'. Writing a '0' to RW1S bits has no effect.
+ //
+ break;
+
+ case EfiUsbPortPower:
+ if (Xhc->HcCParams.Data.Ppc) {
+ //
+ // Port Power Control supported
+ //
+ State &= ~XHC_PORTSC_PP;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ }
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // XHCI root hub port don't has the owner bit, ignore the operation
+ //
+ break;
+
+ case EfiUsbPortConnectChange:
+ //
+ // Clear connect status change
+ //
+ State |= XHC_PORTSC_CSC;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortEnableChange:
+ //
+ // Clear enable status change
+ //
+ State |= XHC_PORTSC_PEC;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ //
+ // Clear PortOverCurrent change
+ //
+ State |= XHC_PORTSC_OCC;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortResetChange:
+ //
+ // Clear Port Reset change
+ //
+ State |= XHC_PORTSC_PRC;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortSuspendChange:
+ //
+ // Not supported or not related operation
+ //
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
+ return Status;
+}
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ PEI_XHC_DEV *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ EFI_STATUS Status;
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+ Status = EFI_SUCCESS;
+
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
+ State = XhcPeiReadOpReg (Xhc, Offset);
+ DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));
+
+ //
+ // Mask off the port status change bits, these bits are
+ // write clean bits
+ //
+ State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ //
+ // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
+ // A port may be disabled by software writing a '1' to this flag.
+ //
+ break;
+
+ case EfiUsbPortSuspend:
+ State |= XHC_PORTSC_LWS;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ State &= ~XHC_PORTSC_PLS;
+ State |= (3 << 5) ;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ break;
+
+ case EfiUsbPortReset:
+ //
+ // Make sure Host Controller not halt before reset it
+ //
+ if (XhcPeiIsHalt (Xhc)) {
+ Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // 4.3.1 Resetting a Root Hub Port
+ // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
+ // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
+ // bit in the PORTSC field is set to '1'.
+ //
+ State |= XHC_PORTSC_RESET;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
+ break;
+
+ case EfiUsbPortPower:
+ if (Xhc->HcCParams.Data.Ppc) {
+ //
+ // Port Power Control supported
+ //
+ State |= XHC_PORTSC_PP;
+ XhcPeiWriteOpReg (Xhc, Offset, State);
+ }
+ break;
+
+ case EfiUsbPortOwner:
+ //
+ // XHCI root hub port don't has the owner bit, ignore the operation
+ //
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ON_EXIT:
+ DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));
+ return Status;
+}
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ PEI_XHC_DEV *Xhc;
+ UINT32 Offset;
+ UINT32 State;
+ UINTN Index;
+ UINTN MapSize;
+ USB_DEV_ROUTE ParentRouteChart;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);
+
+ if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Clear port status.
+ //
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
+ State = XhcPeiReadOpReg (Xhc, Offset);
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));
+
+ //
+ // According to XHCI 1.1 spec November 2017,
+ // bit 10~13 of the root port status register identifies the speed of the attached device.
+ //
+ switch ((State & XHC_PORTSC_PS) >> 10) {
+ case 2:
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ break;
+
+ case 3:
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ break;
+
+ case 4:
+ case 5:
+ PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // Convert the XHCI port/port change state to UEFI status
+ //
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
+ }
+ }
+ //
+ // Bit5~8 reflects its current link state.
+ //
+ if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
+ }
+ }
+
+ MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
+ XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
+ }
+ }
+
+ //
+ // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
+ // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
+ //
+ ParentRouteChart.Dword = 0;
+ XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
+
+ DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));
+ return EFI_SUCCESS;
+}
+
+/**
+ One notified function to stop the Host Controller at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+ @retval others
+**/
+EFI_STATUS
+EFIAPI
+XhcEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_XHC_DEV *Xhc;
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);
+
+ XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+
+ XhcPeiFreeSched (Xhc);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PEI_USB_CONTROLLER_PPI *UsbControllerPpi;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINTN ControllerType;
+ UINTN BaseAddress;
+ UINTN MemPages;
+ PEI_XHC_DEV *XhcDev;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ UINT32 PageSize;
+
+ //
+ // Shadow this PEIM to run from memory.
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &UsbControllerPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IoMmuInit ();
+
+ Index = 0;
+ while (TRUE) {
+ Status = UsbControllerPpi->GetUsbController (
+ (EFI_PEI_SERVICES **) PeiServices,
+ UsbControllerPpi,
+ Index,
+ &ControllerType,
+ &BaseAddress
+ );
+ //
+ // When status is error, it means no controller is found.
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // This PEIM is for XHC type controller.
+ //
+ if (ControllerType != PEI_XHCI_CONTROLLER) {
+ Index++;
+ continue;
+ }
+
+ MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ MemPages,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));
+ XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);
+
+ XhcDev->Signature = USB_XHC_DEV_SIGNATURE;
+ XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
+ XhcDev->CapLength = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);
+ XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);
+ XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);
+ XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);
+ XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);
+ XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);
+
+ //
+ // This PageSize field defines the page size supported by the xHC implementation.
+ // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
+ // if bit 0 is Set, the xHC supports 4k byte page sizes.
+ //
+ PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
+ XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
+
+ DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));
+ DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));
+ DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));
+ DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));
+ DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));
+ DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));
+ DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));
+ DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));
+
+ XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);
+ ASSERT (XhcPeiIsHalt (XhcDev));
+
+ //
+ // Initialize the schedule
+ //
+ XhcPeiInitSched (XhcDev);
+
+ //
+ // Start the Host Controller
+ //
+ XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);
+
+ //
+ // Wait for root port state stable
+ //
+ MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);
+
+ XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;
+ XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;
+ XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;
+ XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;
+ XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;
+ XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;
+
+ XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
+ XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
+
+ XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
+ XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;
+
+ PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
+ PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);
+
+ Index++;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
new file mode 100644
index 000000000..03a55f3eb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
@@ -0,0 +1,373 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RECOVERY_XHC_H_
+#define _RECOVERY_XHC_H_
+
+#include <PiPei.h>
+
+#include <Ppi/UsbController.h>
+#include <Ppi/Usb2HostController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+typedef struct _PEI_XHC_DEV PEI_XHC_DEV;
+typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;
+
+#include "UsbHcMem.h"
+#include "XhciReg.h"
+#include "XhciSched.h"
+
+#define CMD_RING_TRB_NUMBER 0x100
+#define TR_RING_TRB_NUMBER 0x100
+#define ERST_NUMBER 0x01
+#define EVENT_RING_TRB_NUMBER 0x200
+
+#define XHC_1_MICROSECOND 1
+#define XHC_1_MILLISECOND (1000 * XHC_1_MICROSECOND)
+#define XHC_1_SECOND (1000 * XHC_1_MILLISECOND)
+
+//
+// XHC reset timeout experience values.
+// The unit is millisecond, setting it as 1s.
+//
+#define XHC_RESET_TIMEOUT (1000)
+
+//
+// TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5.
+// The unit is microsecond, setting it as 10ms.
+//
+#define XHC_RESET_RECOVERY_DELAY (10 * 1000)
+
+//
+// Wait for root port state stable.
+//
+#define XHC_ROOT_PORT_STATE_STABLE (200 * XHC_1_MILLISECOND)
+
+//
+// XHC generic timeout experience values.
+// The unit is millisecond, setting it as 10s.
+//
+#define XHC_GENERIC_TIMEOUT (10 * 1000)
+
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define XHC_REG_BIT_IS_SET(XHC, Offset, Bit) \
+ (XHC_BIT_IS_SET(XhcPeiReadOpReg ((XHC), (Offset)), (Bit)))
+
+#define USB_DESC_TYPE_HUB 0x29
+#define USB_DESC_TYPE_HUB_SUPER_SPEED 0x2a
+
+//
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
+// three fields: One bit direction, 2 bit type, and 5 bit
+// target.
+//
+#define USB_REQUEST_TYPE(Dir, Type, Target) \
+ ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))
+
+struct _USB_DEV_CONTEXT {
+ //
+ // Whether this entry in UsbDevContext array is used or not.
+ //
+ BOOLEAN Enabled;
+ //
+ // The slot id assigned to the new device through XHCI's Enable_Slot cmd.
+ //
+ UINT8 SlotId;
+ //
+ // The route string presented an attached usb device.
+ //
+ USB_DEV_ROUTE RouteString;
+ //
+ // The route string of parent device if it exists. Otherwise it's zero.
+ //
+ USB_DEV_ROUTE ParentRouteString;
+ //
+ // The actual device address assigned by XHCI through Address_Device command.
+ //
+ UINT8 XhciDevAddr;
+ //
+ // The requested device address from UsbBus driver through Set_Address standard usb request.
+ // As XHCI spec replaces this request with Address_Device command, we have to record the
+ // requested device address and establish a mapping relationship with the actual device address.
+ // Then UsbBus driver just need to be aware of the requested device address to access usb device
+ // through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual
+ // device address and access the actual device.
+ //
+ UINT8 BusDevAddr;
+ //
+ // The pointer to the input device context.
+ //
+ VOID *InputContext;
+ //
+ // The pointer to the output device context.
+ //
+ VOID *OutputContext;
+ //
+ // The transfer queue for every endpoint.
+ //
+ VOID *EndpointTransferRing[31];
+ //
+ // The device descriptor which is stored to support XHCI's Evaluate_Context cmd.
+ //
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ //
+ // As a usb device may include multiple configuration descriptors, we dynamically allocate an array
+ // to store them.
+ // Note that every configuration descriptor stored here includes those lower level descriptors,
+ // such as Interface descriptor, Endpoint descriptor, and so on.
+ // These information is used to support XHCI's Config_Endpoint cmd.
+ //
+ EFI_USB_CONFIG_DESCRIPTOR **ConfDesc;
+};
+
+#define USB_XHC_DEV_SIGNATURE SIGNATURE_32 ('x', 'h', 'c', 'i')
+
+struct _PEI_XHC_DEV {
+ UINTN Signature;
+ PEI_USB2_HOST_CONTROLLER_PPI Usb2HostControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ UINT32 UsbHostControllerBaseAddress;
+ USBHC_MEM_POOL *MemPool;
+
+ //
+ // EndOfPei callback is used to stop the XHC DMA operation
+ // after exit PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ //
+ // XHCI configuration data
+ //
+ UINT8 CapLength; ///< Capability Register Length
+ XHC_HCSPARAMS1 HcSParams1; ///< Structural Parameters 1
+ XHC_HCSPARAMS2 HcSParams2; ///< Structural Parameters 2
+ XHC_HCCPARAMS HcCParams; ///< Capability Parameters
+ UINT32 DBOff; ///< Doorbell Offset
+ UINT32 RTSOff; ///< Runtime Register Space Offset
+ UINT32 PageSize;
+ UINT32 MaxScratchpadBufs;
+ UINT64 *ScratchBuf;
+ VOID *ScratchMap;
+ UINT64 *ScratchEntry;
+ UINTN *ScratchEntryMap;
+ UINT64 *DCBAA;
+ UINT32 MaxSlotsEn;
+ //
+ // Cmd Transfer Ring
+ //
+ TRANSFER_RING CmdRing;
+ //
+ // EventRing
+ //
+ EVENT_RING EventRing;
+
+ //
+ // Store device contexts managed by XHCI device
+ // The array supports up to 255 devices, entry 0 is reserved and should not be used.
+ //
+ USB_DEV_CONTEXT UsbDevContext[256];
+};
+
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(a) CR (a, PEI_XHC_DEV, EndOfPeiNotifyList, USB_XHC_DEV_SIGNATURE)
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @return Pointer to the allocated memory pool or NULL if failed.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ VOID
+ )
+;
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+**/
+VOID
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+;
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+;
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+;
+
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates aligned pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateAlignedBuffer (
+ IN UINTN Pages,
+ IN UINTN Alignment,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
new file mode 100644
index 000000000..f216538f4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
@@ -0,0 +1,60 @@
+## @file
+# The XhcPeim driver is responsible for managing the behavior of XHCI controller at PEI phase.
+#
+# It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+# which is used to enable recovery function from USB Drivers.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = XhciPei
+ MODULE_UNI_FILE = XhciPei.uni
+ FILE_GUID = 65E5746E-9C14-467d-B5B3-932A66D59F79
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = XhcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ XhcPeim.c
+ XhcPeim.h
+ XhciSched.c
+ UsbHcMem.c
+ DmaMem.c
+ XhciReg.h
+ XhciSched.h
+ UsbHcMem.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+ MemoryAllocationLib
+
+[Ppis]
+ gPeiUsb2HostControllerPpiGuid ## PRODUCES
+ gPeiUsbControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ XhciPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.uni b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.uni
new file mode 100644
index 000000000..01ba07a76
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The XhcPeim driver is responsible for managing the behavior of XHCI controller at PEI phase.
+//
+// It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+// which is used to enable recovery function from USB Drivers.
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Responsible for managing the behavior of XHCI controller at PEI phase."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It produces gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid, which is used to enable recovery function from USB Drivers."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPeiExtra.uni
new file mode 100644
index 000000000..110fc1a87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// XhciPei Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"XHCI PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h
new file mode 100644
index 000000000..e98b451a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h
@@ -0,0 +1,450 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PEI_XHCI_REG_H_
+#define _EFI_PEI_XHCI_REG_H_
+
+//
+// Capability registers offset
+//
+#define XHC_CAPLENGTH_OFFSET 0x00 // Capability register length offset
+#define XHC_HCIVERSION_OFFSET 0x02 // Interface Version Number 02-03h
+#define XHC_HCSPARAMS1_OFFSET 0x04 // Structural Parameters 1
+#define XHC_HCSPARAMS2_OFFSET 0x08 // Structural Parameters 2
+#define XHC_HCSPARAMS3_OFFSET 0x0c // Structural Parameters 3
+#define XHC_HCCPARAMS_OFFSET 0x10 // Capability Parameters
+#define XHC_DBOFF_OFFSET 0x14 // Doorbell Offset
+#define XHC_RTSOFF_OFFSET 0x18 // Runtime Register Space Offset
+
+//
+// Operational registers offset
+//
+#define XHC_USBCMD_OFFSET 0x0000 // USB Command Register Offset
+#define XHC_USBSTS_OFFSET 0x0004 // USB Status Register Offset
+#define XHC_PAGESIZE_OFFSET 0x0008 // USB Page Size Register Offset
+#define XHC_DNCTRL_OFFSET 0x0014 // Device Notification Control Register Offset
+#define XHC_CRCR_OFFSET 0x0018 // Command Ring Control Register Offset
+#define XHC_DCBAAP_OFFSET 0x0030 // Device Context Base Address Array Pointer Register Offset
+#define XHC_CONFIG_OFFSET 0x0038 // Configure Register Offset
+#define XHC_PORTSC_OFFSET 0x0400 // Port Status and Control Register Offset
+
+//
+// Runtime registers offset
+//
+#define XHC_MFINDEX_OFFSET 0x00 // Microframe Index Register Offset
+#define XHC_IMAN_OFFSET 0x20 // Interrupter X Management Register Offset
+#define XHC_IMOD_OFFSET 0x24 // Interrupter X Moderation Register Offset
+#define XHC_ERSTSZ_OFFSET 0x28 // Event Ring Segment Table Size Register Offset
+#define XHC_ERSTBA_OFFSET 0x30 // Event Ring Segment Table Base Address Register Offset
+#define XHC_ERDP_OFFSET 0x38 // Event Ring Dequeue Pointer Register Offset
+
+//
+// Register Bit Definition
+//
+#define XHC_USBCMD_RUN BIT0 // Run/Stop
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
+#define XHC_USBCMD_INTE BIT2 // Interrupter Enable
+#define XHC_USBCMD_HSEE BIT3 // Host System Error Enable
+
+#define XHC_USBSTS_HALT BIT0 // Host Controller Halted
+#define XHC_USBSTS_HSE BIT2 // Host System Error
+#define XHC_USBSTS_EINT BIT3 // Event Interrupt
+#define XHC_USBSTS_PCD BIT4 // Port Change Detect
+#define XHC_USBSTS_SSS BIT8 // Save State Status
+#define XHC_USBSTS_RSS BIT9 // Restore State Status
+#define XHC_USBSTS_SRE BIT10 // Save/Restore Error
+#define XHC_USBSTS_CNR BIT11 // Host Controller Not Ready
+#define XHC_USBSTS_HCE BIT12 // Host Controller Error
+
+#define XHC_PAGESIZE_MASK 0xFFFF // Page Size
+
+#define XHC_CRCR_RCS BIT0 // Ring Cycle State
+#define XHC_CRCR_CS BIT1 // Command Stop
+#define XHC_CRCR_CA BIT2 // Command Abort
+#define XHC_CRCR_CRR BIT3 // Command Ring Running
+
+#define XHC_CONFIG_MASK 0xFF // Max Device Slots Enabled
+
+#define XHC_PORTSC_CCS BIT0 // Current Connect Status
+#define XHC_PORTSC_PED BIT1 // Port Enabled/Disabled
+#define XHC_PORTSC_OCA BIT3 // Over-current Active
+#define XHC_PORTSC_RESET BIT4 // Port Reset
+#define XHC_PORTSC_PLS (BIT5|BIT6|BIT7|BIT8) // Port Link State
+#define XHC_PORTSC_PP BIT9 // Port Power
+#define XHC_PORTSC_PS (BIT10|BIT11|BIT12|BIT13) // Port Speed
+#define XHC_PORTSC_LWS BIT16 // Port Link State Write Strobe
+#define XHC_PORTSC_CSC BIT17 // Connect Status Change
+#define XHC_PORTSC_PEC BIT18 // Port Enabled/Disabled Change
+#define XHC_PORTSC_WRC BIT19 // Warm Port Reset Change
+#define XHC_PORTSC_OCC BIT20 // Over-Current Change
+#define XHC_PORTSC_PRC BIT21 // Port Reset Change
+#define XHC_PORTSC_PLC BIT22 // Port Link State Change
+#define XHC_PORTSC_CEC BIT23 // Port Config Error Change
+#define XHC_PORTSC_CAS BIT24 // Cold Attach Status
+
+#define XHC_HUB_PORTSC_CCS BIT0 // Hub's Current Connect Status
+#define XHC_HUB_PORTSC_PED BIT1 // Hub's Port Enabled/Disabled
+#define XHC_HUB_PORTSC_OCA BIT3 // Hub's Over-current Active
+#define XHC_HUB_PORTSC_RESET BIT4 // Hub's Port Reset
+#define XHC_HUB_PORTSC_PP BIT9 // Hub's Port Power
+#define XHC_HUB_PORTSC_CSC BIT16 // Hub's Connect Status Change
+#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change
+#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change
+#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change
+#define XHC_HUB_PORTSC_BHRC BIT21 // Hub's Port Warm Reset Change
+
+#define XHC_IMAN_IP BIT0 // Interrupt Pending
+#define XHC_IMAN_IE BIT1 // Interrupt Enable
+
+#define XHC_IMODI_MASK 0x0000FFFF // Interrupt Moderation Interval
+#define XHC_IMODC_MASK 0xFFFF0000 // Interrupt Moderation Counter
+
+
+#pragma pack (1)
+typedef struct {
+ UINT8 MaxSlots; // Number of Device Slots
+ UINT16 MaxIntrs:11; // Number of Interrupters
+ UINT16 Rsvd:5;
+ UINT8 MaxPorts; // Number of Ports
+} HCSPARAMS1;
+
+//
+// Structural Parameters 1 Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCSPARAMS1 Data;
+} XHC_HCSPARAMS1;
+
+typedef struct {
+ UINT32 Ist:4; // Isochronous Scheduling Threshold
+ UINT32 Erst:4; // Event Ring Segment Table Max
+ UINT32 Rsvd:13;
+ UINT32 ScratchBufHi:5; // Max Scratchpad Buffers Hi
+ UINT32 Spr:1; // Scratchpad Restore
+ UINT32 ScratchBufLo:5; // Max Scratchpad Buffers Lo
+} HCSPARAMS2;
+
+//
+// Structural Parameters 2 Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCSPARAMS2 Data;
+} XHC_HCSPARAMS2;
+
+typedef struct {
+ UINT16 Ac64:1; // 64-bit Addressing Capability
+ UINT16 Bnc:1; // BW Negotiation Capability
+ UINT16 Csz:1; // Context Size
+ UINT16 Ppc:1; // Port Power Control
+ UINT16 Pind:1; // Port Indicators
+ UINT16 Lhrc:1; // Light HC Reset Capability
+ UINT16 Ltc:1; // Latency Tolerance Messaging Capability
+ UINT16 Nss:1; // No Secondary SID Support
+ UINT16 Pae:1; // Parse All Event Data
+ UINT16 Rsvd:3;
+ UINT16 MaxPsaSize:4; // Maximum Primary Stream Array Size
+ UINT16 ExtCapReg; // xHCI Extended Capabilities Pointer
+} HCCPARAMS;
+
+//
+// Capability Parameters Register Bitmap Definition
+//
+typedef union {
+ UINT32 Dword;
+ HCCPARAMS Data;
+} XHC_HCCPARAMS;
+
+#pragma pack ()
+
+//
+// XHCi Data and Ctrl Structures
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Pi;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 NumPorts;
+ UINT16 HubCharacter;
+ UINT8 PwrOn2PwrGood;
+ UINT8 HubContrCurrent;
+ UINT8 Filler[16];
+} EFI_USB_HUB_DESCRIPTOR;
+#pragma pack()
+
+//
+// Hub Class Feature Selector for Clear Port Feature Request
+// It's the extension of hub class feature selector of USB 2.0 in USB 3.0 Spec.
+// For more details, Please refer to USB 3.0 Spec Table 10-7.
+//
+typedef enum {
+ Usb3PortBHPortReset = 28,
+ Usb3PortBHPortResetChange = 29
+} XHC_PORT_FEATURE;
+
+//
+// Structure to map the hardware port states to the
+// UEFI's port states.
+//
+typedef struct {
+ UINT32 HwState;
+ UINT16 UefiState;
+} USB_PORT_STATE_MAP;
+
+//
+// Structure to map the hardware port states to feature selector for clear port feature request.
+//
+typedef struct {
+ UINT32 HwState;
+ UINT16 Selector;
+} USB_CLEAR_PORT_MAP;
+
+/**
+ Read XHCI Operation register.
+
+ @param Xhc The XHCI device.
+ @param Offset The operation register offset.
+
+ @retval the register content read.
+
+**/
+UINT32
+XhcPeiReadOpReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Write the data to the XHCI operation register.
+
+ @param Xhc The XHCI device.
+ @param Offset The operation register offset.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteOpReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiSetOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcPeiClearOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to be set (or clear).
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the operational register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcPeiWaitOpRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ );
+
+
+/**
+ Write the data to the XHCI door bell register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the door bell register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteDoorBellReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Read XHCI runtime register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcPeiReadRuntimeReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Write the data to the XHCI runtime register.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcPeiWriteRuntimeReg (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Set one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiSetRuntimeRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the runtime register while keeping other bits.
+
+ @param Xhc The XHCI device.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcPeiClearRuntimeRegBit (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Check whether Xhc is halted.
+
+ @param Xhc The XHCI device.
+
+ @retval TRUE The controller is halted.
+ @retval FALSE The controller isn't halted.
+
+**/
+BOOLEAN
+XhcPeiIsHalt (
+ IN PEI_XHC_DEV *Xhc
+ );
+
+/**
+ Check whether system error occurred.
+
+ @param Xhc The XHCI device.
+
+ @retval TRUE System error happened.
+ @retval FALSE No system error.
+
+**/
+BOOLEAN
+XhcPeiIsSysError (
+ IN PEI_XHC_DEV *Xhc
+ );
+
+/**
+ Reset the host controller.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort (in millisecond, ms).
+
+ @retval EFI_TIMEOUT The transfer failed due to time out.
+ @retval Others Failed to reset the host.
+
+**/
+EFI_STATUS
+XhcPeiResetHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ );
+
+/**
+ Halt the host controller.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
+ @retval EFI_SUCCESS The XHCI is halt.
+
+**/
+EFI_STATUS
+XhcPeiHaltHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ );
+
+/**
+ Set the XHCI to run.
+
+ @param Xhc The XHCI device.
+ @param Timeout Time to wait before abort.
+
+ @retval EFI_SUCCESS The XHCI is running.
+ @retval Others Failed to set the XHCI to run.
+
+**/
+EFI_STATUS
+XhcPeiRunHC (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT32 Timeout
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
new file mode 100644
index 000000000..32d72ef03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
@@ -0,0 +1,3029 @@
+/** @file
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
+which is used to enable recovery function from USB Drivers.
+
+Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XhcPeim.h"
+
+/**
+ Create a command transfer TRB to support XHCI command interfaces.
+
+ @param Xhc The XHCI device.
+ @param CmdTrb The cmd TRB to be executed.
+
+ @return Created URB or NULL.
+
+**/
+URB*
+XhcPeiCreateCmdTrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN TRB_TEMPLATE *CmdTrb
+ )
+{
+ URB *Urb;
+
+ Urb = AllocateZeroPool (sizeof (URB));
+ if (Urb == NULL) {
+ return NULL;
+ }
+
+ Urb->Signature = XHC_URB_SIG;
+
+ Urb->Ring = &Xhc->CmdRing;
+ XhcPeiSyncTrsRing (Xhc, Urb->Ring);
+ Urb->TrbNum = 1;
+ Urb->TrbStart = Urb->Ring->RingEnqueue;
+ CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
+ Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
+ Urb->TrbEnd = Urb->TrbStart;
+
+ return Urb;
+}
+
+/**
+ Execute a XHCI cmd TRB pointed by CmdTrb.
+
+ @param Xhc The XHCI device.
+ @param CmdTrb The cmd TRB to be executed.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param EvtTrb The event TRB corresponding to the cmd TRB.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+XhcPeiCmdTransfer (
+ IN PEI_XHC_DEV *Xhc,
+ IN TRB_TEMPLATE *CmdTrb,
+ IN UINTN Timeout,
+ OUT TRB_TEMPLATE **EvtTrb
+ )
+{
+ EFI_STATUS Status;
+ URB *Urb;
+
+ //
+ // Validate the parameters
+ //
+ if ((Xhc == NULL) || (CmdTrb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
+ goto ON_EXIT;
+ }
+
+ //
+ // Create a new URB, then poll the execution status.
+ //
+ Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);
+ if (Urb == NULL) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);
+ *EvtTrb = Urb->EvtTrb;
+
+ if (Urb->Result == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ XhcPeiFreeUrb (Xhc, Urb);
+
+ON_EXIT:
+ return Status;
+}
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Xhc The XHCI device
+ @param BusAddr The logical device address assigned by UsbBus driver
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param Type The transaction type
+ @param Request The standard USB request for control transfer
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcPeiCreateUrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 BusAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ )
+{
+ USB_ENDPOINT *Ep;
+ EFI_STATUS Status;
+ URB *Urb;
+
+ Urb = AllocateZeroPool (sizeof (URB));
+ if (Urb == NULL) {
+ return NULL;
+ }
+
+ Urb->Signature = XHC_URB_SIG;
+
+ Ep = &Urb->Ep;
+ Ep->BusAddr = BusAddr;
+ Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
+ Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
+ Ep->DevSpeed = DevSpeed;
+ Ep->MaxPacket = MaxPacket;
+ Ep->Type = Type;
+
+ Urb->Request = Request;
+ Urb->Data = Data;
+ Urb->DataLen = DataLen;
+ Urb->Callback = Callback;
+ Urb->Context = Context;
+
+ Status = XhcPeiCreateTransferTrb (Xhc, Urb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));
+ FreePool (Urb);
+ Urb = NULL;
+ }
+
+ return Urb;
+}
+
+/**
+ Free an allocated URB.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+XhcPeiFreeUrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ )
+{
+ if ((Xhc == NULL) || (Urb == NULL)) {
+ return;
+ }
+
+ IoMmuUnmap (Urb->DataMap);
+
+ FreePool (Urb);
+}
+
+/**
+ Create a transfer TRB.
+
+ @param Xhc The XHCI device
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcPeiCreateTransferTrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ )
+{
+ VOID *OutputContext;
+ TRANSFER_RING *EPRing;
+ UINT8 EPType;
+ UINT8 SlotId;
+ UINT8 Dci;
+ TRB *TrbStart;
+ UINTN TotalLen;
+ UINTN Len;
+ UINTN TrbNum;
+ EDKII_IOMMU_OPERATION MapOp;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ EFI_STATUS Status;
+
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Urb->Finished = FALSE;
+ Urb->StartDone = FALSE;
+ Urb->EndDone = FALSE;
+ Urb->Completed = 0;
+ Urb->Result = EFI_USB_NOERROR;
+
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ EPRing = (TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
+ Urb->Ring = EPRing;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
+ } else {
+ EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
+ }
+
+ //
+ // No need to remap.
+ //
+ if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {
+ if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ Len = Urb->DataLen;
+ Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
+ DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ }
+
+ //
+ // Construct the TRB
+ //
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ Urb->TrbStart = EPRing->RingEnqueue;
+ switch (EPType) {
+ case ED_CONTROL_BIDIR:
+ //
+ // For control transfer, create SETUP_STAGE_TRB first.
+ //
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
+ TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
+ TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
+ TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
+ TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
+ TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
+ TrbStart->TrbCtrSetup.Length = 8;
+ TrbStart->TrbCtrSetup.IntTarget = 0;
+ TrbStart->TrbCtrSetup.IOC = 1;
+ TrbStart->TrbCtrSetup.IDT = 1;
+ TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrSetup.TRT = 3;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrSetup.TRT = 2;
+ } else {
+ TrbStart->TrbCtrSetup.TRT = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
+ Urb->TrbNum++;
+
+ //
+ // For control transfer, create DATA_STAGE_TRB.
+ //
+ if (Urb->DataLen > 0) {
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
+ TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT (Urb->DataPhy);
+ TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT (Urb->DataPhy);
+ TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;
+ TrbStart->TrbCtrData.TDSize = 0;
+ TrbStart->TrbCtrData.IntTarget = 0;
+ TrbStart->TrbCtrData.ISP = 1;
+ TrbStart->TrbCtrData.IOC = 1;
+ TrbStart->TrbCtrData.IDT = 0;
+ TrbStart->TrbCtrData.CH = 0;
+ TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrData.DIR = 1;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrData.DIR = 0;
+ } else {
+ TrbStart->TrbCtrData.DIR = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
+ Urb->TrbNum++;
+ }
+ //
+ // For control transfer, create STATUS_STAGE_TRB.
+ // Get the pointer to next TRB for status stage use
+ //
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
+ TrbStart->TrbCtrStatus.IntTarget = 0;
+ TrbStart->TrbCtrStatus.IOC = 1;
+ TrbStart->TrbCtrStatus.CH = 0;
+ TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;
+ if (Urb->Ep.Direction == EfiUsbDataIn) {
+ TrbStart->TrbCtrStatus.DIR = 0;
+ } else if (Urb->Ep.Direction == EfiUsbDataOut) {
+ TrbStart->TrbCtrStatus.DIR = 1;
+ } else {
+ TrbStart->TrbCtrStatus.DIR = 0;
+ }
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
+ //
+ // Update the enqueue pointer
+ //
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ Urb->TrbNum++;
+ Urb->TrbEnd = (TRB_TEMPLATE *) (UINTN) TrbStart;
+
+ break;
+
+ case ED_BULK_OUT:
+ case ED_BULK_IN:
+ TotalLen = 0;
+ Len = 0;
+ TrbNum = 0;
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
+ while (TotalLen < Urb->DataLen) {
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {
+ Len = Urb->DataLen - TotalLen;
+ } else {
+ Len = 0x10000;
+ }
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.Length = (UINT32) Len;
+ TrbStart->TrbNormal.TDSize = 0;
+ TrbStart->TrbNormal.IntTarget = 0;
+ TrbStart->TrbNormal.ISP = 1;
+ TrbStart->TrbNormal.IOC = 1;
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ TrbNum++;
+ TotalLen += Len;
+ }
+
+ Urb->TrbNum = TrbNum;
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
+ break;
+
+ case ED_INTERRUPT_OUT:
+ case ED_INTERRUPT_IN:
+ TotalLen = 0;
+ Len = 0;
+ TrbNum = 0;
+ TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;
+ while (TotalLen < Urb->DataLen) {
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {
+ Len = Urb->DataLen - TotalLen;
+ } else {
+ Len = 0x10000;
+ }
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);
+ TrbStart->TrbNormal.Length = (UINT32) Len;
+ TrbStart->TrbNormal.TDSize = 0;
+ TrbStart->TrbNormal.IntTarget = 0;
+ TrbStart->TrbNormal.ISP = 1;
+ TrbStart->TrbNormal.IOC = 1;
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ XhcPeiSyncTrsRing (Xhc, EPRing);
+ TrbNum++;
+ TotalLen += Len;
+ }
+
+ Urb->TrbNum = TrbNum;
+ Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
+ break;
+
+ default:
+ DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
+ ASSERT (FALSE);
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
+ Stopped to the Running state.
+
+ @param Xhc The XHCI device.
+ @param Urb The urb which makes the endpoint halted.
+
+ @retval EFI_SUCCESS The recovery is successful.
+ @retval Others Failed to recovery halted endpoint.
+
+**/
+EFI_STATUS
+XhcPeiRecoverHaltedEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Dci;
+ UINT8 SlotId;
+
+ Status = EFI_SUCCESS;
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
+
+ DEBUG ((EFI_D_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));
+
+ //
+ // 1) Send Reset endpoint command to transit from halt to stop state
+ //
+ Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 2) Set dequeue pointer
+ //
+ Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 3) Ring the doorbell to transit from stop to active
+ //
+ XhcPeiRingDoorBell (Xhc, SlotId, Dci);
+
+Done:
+ return Status;
+}
+
+/**
+ System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
+ Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
+ the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
+ state.
+
+ @param Xhc The XHCI device.
+ @param Urb The urb which doesn't get completed in a specified timeout range.
+
+ @retval EFI_SUCCESS The dequeuing of the TDs is successful.
+ @retval Others Failed to stop the endpoint and dequeue the TDs.
+
+**/
+EFI_STATUS
+XhcPeiDequeueTrbFromEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Dci;
+ UINT8 SlotId;
+
+ Status = EFI_SUCCESS;
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));
+
+ DEBUG ((EFI_D_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));
+
+ //
+ // 1) Send Stop endpoint command to stop endpoint.
+ //
+ Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 2) Set dequeue pointer
+ //
+ Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // 3) Ring the doorbell to transit from stop to active
+ //
+ XhcPeiRingDoorBell (Xhc, SlotId, Dci);
+
+Done:
+ return Status;
+}
+
+/**
+ Check if the Trb is a transaction of the URB.
+
+ @param Trb The TRB to be checked
+ @param Urb The transfer ring to be checked.
+
+ @retval TRUE It is a transaction of the URB.
+ @retval FALSE It is not any transaction of the URB.
+
+**/
+BOOLEAN
+XhcPeiIsTransferRingTrb (
+ IN TRB_TEMPLATE *Trb,
+ IN URB *Urb
+ )
+{
+ TRB_TEMPLATE *CheckedTrb;
+ UINTN Index;
+
+ CheckedTrb = Urb->Ring->RingSeg0;
+
+ ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
+
+ for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
+ if (Trb == CheckedTrb) {
+ return TRUE;
+ }
+ CheckedTrb++;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to check result.
+
+ @return Whether the result of URB transfer is finialized.
+
+**/
+BOOLEAN
+XhcPeiCheckUrbResult (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ )
+{
+ EVT_TRB_TRANSFER *EvtTrb;
+ TRB_TEMPLATE *TRBPtr;
+ UINTN Index;
+ UINT8 TRBType;
+ EFI_STATUS Status;
+ URB *CheckedUrb;
+ UINT64 XhcDequeue;
+ UINT32 High;
+ UINT32 Low;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT ((Xhc != NULL) && (Urb != NULL));
+
+ Status = EFI_SUCCESS;
+
+ if (Urb->Finished) {
+ goto EXIT;
+ }
+
+ EvtTrb = NULL;
+
+ if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {
+ Urb->Result |= EFI_USB_ERR_SYSTEM;
+ goto EXIT;
+ }
+
+ //
+ // Traverse the event ring to find out all new events from the previous check.
+ //
+ XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);
+ for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
+ Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **) &EvtTrb));
+ if (Status == EFI_NOT_READY) {
+ //
+ // All new events are handled, return directly.
+ //
+ goto EXIT;
+ }
+
+ //
+ // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
+ //
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
+ continue;
+ }
+
+ //
+ // Need convert pci device address to host address
+ //
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
+ TRBPtr = (TRB_TEMPLATE *) (UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *) (UINTN) PhyAddr, sizeof (TRB_TEMPLATE));
+
+ //
+ // Update the status of Urb according to the finished event regardless of whether
+ // the urb is current checked one or in the XHCI's async transfer list.
+ // This way is used to avoid that those completed async transfer events don't get
+ // handled in time and are flushed by newer coming events.
+ //
+ if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {
+ CheckedUrb = Urb;
+ } else {
+ continue;
+ }
+
+ switch (EvtTrb->Completecode) {
+ case TRB_COMPLETION_STALL_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_STALL;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_BABBLE_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_DATA_BUFFER_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_USB_TRANSACTION_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));
+ goto EXIT;
+
+ case TRB_COMPLETION_SHORT_PACKET:
+ case TRB_COMPLETION_SUCCESS:
+ if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
+ DEBUG ((EFI_D_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));
+ }
+
+ TRBType = (UINT8) (TRBPtr->Type);
+ if ((TRBType == TRB_TYPE_DATA_STAGE) ||
+ (TRBType == TRB_TYPE_NORMAL) ||
+ (TRBType == TRB_TYPE_ISOCH)) {
+ CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
+ }
+
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ goto EXIT;
+ }
+
+ //
+ // Only check first and end Trb event address
+ //
+ if (TRBPtr == CheckedUrb->TrbStart) {
+ CheckedUrb->StartDone = TRUE;
+ }
+
+ if (TRBPtr == CheckedUrb->TrbEnd) {
+ CheckedUrb->EndDone = TRUE;
+ }
+
+ if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
+ CheckedUrb->Finished = TRUE;
+ CheckedUrb->EvtTrb = (TRB_TEMPLATE *) EvtTrb;
+ }
+ }
+
+EXIT:
+
+ //
+ // Advance event ring to last available entry
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ Low = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
+ High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
+ XhcDequeue = (UINT64) (LShiftU64((UINT64) High, 32) | Low);
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));
+
+ if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);
+ XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));
+ }
+
+ return Urb->Finished;
+}
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Xhc The XHCI device.
+ @param CmdTransfer The executed URB is for cmd transfer or not.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+XhcPeiExecTransfer (
+ IN PEI_XHC_DEV *Xhc,
+ IN BOOLEAN CmdTransfer,
+ IN URB *Urb,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT64 Loop;
+ UINT8 SlotId;
+ UINT8 Dci;
+ BOOLEAN Finished;
+
+ if (CmdTransfer) {
+ SlotId = 0;
+ Dci = 0;
+ } else {
+ SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
+ if (SlotId == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
+ }
+
+ Status = EFI_SUCCESS;
+ Loop = Timeout * XHC_1_MILLISECOND;
+ if (Timeout == 0) {
+ Loop = 0xFFFFFFFF;
+ }
+
+ XhcPeiRingDoorBell (Xhc, SlotId, Dci);
+
+ for (Index = 0; Index < Loop; Index++) {
+ Finished = XhcPeiCheckUrbResult (Xhc, Urb);
+ if (Finished) {
+ break;
+ }
+ MicroSecondDelay (XHC_1_MICROSECOND);
+ }
+
+ if (Index == Loop) {
+ Urb->Result = EFI_USB_ERR_TIMEOUT;
+ Status = EFI_TIMEOUT;
+ } else if (Urb->Result != EFI_USB_NOERROR) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device if it exists.
+ @param Port The port to be polled.
+ @param PortState The port state.
+
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
+ @retval Others Should not appear.
+
+**/
+EFI_STATUS
+XhcPeiPollPortStatusChange (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_STATUS *PortState
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Speed;
+ UINT8 SlotId;
+ USB_DEV_ROUTE RouteChart;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));
+
+ Status = EFI_SUCCESS;
+
+ if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (ParentRouteChart.Dword == 0) {
+ RouteChart.Route.RouteString = 0;
+ RouteChart.Route.RootPortNum = Port + 1;
+ RouteChart.Route.TierNum = 1;
+ } else {
+ if(Port < 14) {
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
+ } else {
+ RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
+ }
+ RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
+ RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
+ }
+
+ SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
+ if (SlotId != 0) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcPeiDisableSlotCmd (Xhc, SlotId);
+ } else {
+ Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);
+ }
+ }
+
+ if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
+ ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
+ //
+ // Has a device attached, Identify device speed after port is enabled.
+ //
+ Speed = EFI_USB_SPEED_FULL;
+ if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_LOW;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_HIGH;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_SUPER;
+ }
+ //
+ // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
+ //
+ SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);
+ if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ } else {
+ Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Calculate the device context index by endpoint address and direction.
+
+ @param EpAddr The target endpoint number.
+ @param Direction The direction of the target endpoint.
+
+ @return The device context index of endpoint.
+
+**/
+UINT8
+XhcPeiEndpointToDci (
+ IN UINT8 EpAddr,
+ IN EFI_USB_DATA_DIRECTION Direction
+ )
+{
+ UINT8 Index;
+
+ ASSERT (EpAddr <= 15);
+
+ if (EpAddr == 0) {
+ return 1;
+ } else {
+ Index = (UINT8) (2 * EpAddr);
+ if (Direction == EfiUsbDataIn) {
+ Index += 1;
+ }
+ return Index;
+ }
+}
+
+/**
+ Find out the actual device address according to the requested device address from UsbBus.
+
+ @param Xhc The XHCI device.
+ @param BusDevAddr The requested device address by UsbBus upper driver.
+
+ @return The actual device address assigned to the device.
+
+**/
+UINT8
+XhcPeiBusDevAddrToSlotId (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 BusDevAddr
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < 255; Index++) {
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
+ (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
+ break;
+ }
+ }
+
+ if (Index == 255) {
+ return 0;
+ }
+
+ return Xhc->UsbDevContext[Index + 1].SlotId;
+}
+
+/**
+ Find out the slot id according to the device's route string.
+
+ @param Xhc The XHCI device.
+ @param RouteString The route string described the device location.
+
+ @return The slot id used by the device.
+
+**/
+UINT8
+XhcPeiRouteStringToSlotId (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE RouteString
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < 255; Index++) {
+ if (Xhc->UsbDevContext[Index + 1].Enabled &&
+ (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
+ (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
+ break;
+ }
+ }
+
+ if (Index == 255) {
+ return 0;
+ }
+
+ return Xhc->UsbDevContext[Index + 1].SlotId;
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+**/
+VOID
+XhcPeiRingDoorBell (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ )
+{
+ if (SlotId == 0) {
+ XhcPeiWriteDoorBellReg (Xhc, 0, 0);
+ } else {
+ XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
+ }
+}
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+ @retval Others Fail to initialize device slot.
+
+**/
+EFI_STATUS
+XhcPeiInitializeDeviceSlot (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
+ UINT8 DeviceAddress;
+ CMD_TRB_ENABLE_SLOT CmdTrb;
+ UINT8 SlotId;
+ UINT8 ParentSlotId;
+ DEVICE_CONTEXT *ParentDeviceContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
+ CmdTrb.CycleBit = 1;
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;
+
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
+ return Status;
+ }
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
+ SlotId = (UINT8) EvtTrb->SlotId;
+ ASSERT (SlotId != 0);
+
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
+
+ //
+ // 4.3.3 Device Slot Initialization
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
+ //
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
+ ASSERT (InputContext != NULL);
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
+
+ //
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
+ // Context are affected by the command.
+ //
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
+
+ //
+ // 3) Initialize the Input Slot Context data structure
+ //
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;
+ InputContext->Slot.Speed = DeviceSpeed + 1;
+ InputContext->Slot.ContextEntries = 1;
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
+
+ if (RouteChart.Route.RouteString != 0) {
+ //
+ // The device is behind of hub device.
+ //
+ ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
+ ASSERT (ParentSlotId != 0);
+ //
+ // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
+ //
+ ParentDeviceContext = (DEVICE_CONTEXT *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
+ //
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling
+ // environment from Full/Low speed signaling environment for a device
+ //
+ InputContext->Slot.TTPortNum = ParentPort;
+ InputContext->Slot.TTHubSlotId = ParentSlotId;
+ }
+ } else {
+ //
+ // Inherit the TT parameters from parent device.
+ //
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
+ //
+ // If the device is a High speed device then down the speed to be the same as its parent Hub
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
+ }
+ }
+ }
+
+ //
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
+ //
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
+ //
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
+ //
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ InputContext->EP[0].MaxPacketSize = 512;
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->EP[0].MaxPacketSize = 64;
+ } else {
+ InputContext->EP[0].MaxPacketSize = 8;
+ }
+ //
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
+ // 1KB, and Bulk and Isoch endpoints 3KB.
+ //
+ InputContext->EP[0].AverageTRBLength = 8;
+ InputContext->EP[0].MaxBurstSize = 0;
+ InputContext->EP[0].Interval = 0;
+ InputContext->EP[0].MaxPStreams = 0;
+ InputContext->EP[0].Mult = 0;
+ InputContext->EP[0].CErr = 3;
+
+ //
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ //
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
+ //
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
+ ASSERT (OutputContext != NULL);
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
+
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
+ //
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
+ // a pointer to the Output Device Context data structure (6.2.1).
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));
+ //
+ // Fill DCBAA with PCI device address
+ //
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
+
+ //
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
+ // Context data structure described above.
+ //
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
+ // to device.
+ //
+ MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbAddr.CycleBit = 1;
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (!EFI_ERROR (Status)) {
+ DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+ @retval Others Fail to initialize device slot.
+
+**/
+EFI_STATUS
+XhcPeiInitializeDeviceSlot64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
+ UINT8 DeviceAddress;
+ CMD_TRB_ENABLE_SLOT CmdTrb;
+ UINT8 SlotId;
+ UINT8 ParentSlotId;
+ DEVICE_CONTEXT_64 *ParentDeviceContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
+ CmdTrb.CycleBit = 1;
+ CmdTrb.Type = TRB_TYPE_EN_SLOT;
+
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrb,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
+ return Status;
+ }
+ ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
+ SlotId = (UINT8)EvtTrb->SlotId;
+ ASSERT (SlotId != 0);
+
+ ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
+ Xhc->UsbDevContext[SlotId].Enabled = TRUE;
+ Xhc->UsbDevContext[SlotId].SlotId = SlotId;
+ Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
+ Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
+
+ //
+ // 4.3.3 Device Slot Initialization
+ // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
+ //
+ InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
+ ASSERT (InputContext != NULL);
+ ASSERT (((UINTN) InputContext & 0x3F) == 0);
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
+
+ //
+ // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
+ // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
+ // Context are affected by the command.
+ //
+ InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
+
+ //
+ // 3) Initialize the Input Slot Context data structure
+ //
+ InputContext->Slot.RouteString = RouteChart.Route.RouteString;
+ InputContext->Slot.Speed = DeviceSpeed + 1;
+ InputContext->Slot.ContextEntries = 1;
+ InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
+
+ if (RouteChart.Route.RouteString != 0) {
+ //
+ // The device is behind of hub device.
+ //
+ ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);
+ ASSERT (ParentSlotId != 0);
+ //
+ //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
+ //
+ ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;
+ if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
+ (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
+ if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
+ //
+ // Full/Low device attached to High speed hub port that isolates the high speed signaling
+ // environment from Full/Low speed signaling environment for a device
+ //
+ InputContext->Slot.TTPortNum = ParentPort;
+ InputContext->Slot.TTHubSlotId = ParentSlotId;
+ }
+ } else {
+ //
+ // Inherit the TT parameters from parent device.
+ //
+ InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
+ InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
+ //
+ // If the device is a High speed device then down the speed to be the same as its parent Hub
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
+ }
+ }
+ }
+
+ //
+ // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
+ //
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
+ XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
+ //
+ // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
+ //
+ InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ InputContext->EP[0].MaxPacketSize = 512;
+ } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ InputContext->EP[0].MaxPacketSize = 64;
+ } else {
+ InputContext->EP[0].MaxPacketSize = 8;
+ }
+ //
+ // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
+ // 1KB, and Bulk and Isoch endpoints 3KB.
+ //
+ InputContext->EP[0].AverageTRBLength = 8;
+ InputContext->EP[0].MaxBurstSize = 0;
+ InputContext->EP[0].Interval = 0;
+ InputContext->EP[0].MaxPStreams = 0;
+ InputContext->EP[0].Mult = 0;
+ InputContext->EP[0].CErr = 3;
+
+ //
+ // Init the DCS(dequeue cycle state) as the transfer ring's CCS
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;
+ InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ //
+ // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
+ //
+ OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
+ ASSERT (OutputContext != NULL);
+ ASSERT (((UINTN) OutputContext & 0x3F) == 0);
+ ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
+
+ Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
+ //
+ // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
+ // a pointer to the Output Device Context data structure (6.2.1).
+ //
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));
+ //
+ // Fill DCBAA with PCI device address
+ //
+ Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;
+
+ //
+ // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
+ // Context data structure described above.
+ //
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
+ // to device.
+ //
+ MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);
+ ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbAddr.CycleBit = 1;
+ CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
+ CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (!EFI_ERROR (Status)) {
+ DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));
+ Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
+ }
+
+ DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));
+ return Status;
+}
+
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+XhcPeiDisableSlotCmd (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId
+ )
+{
+ EFI_STATUS Status;
+ TRB_TEMPLATE *EvtTrb;
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
+ UINT8 Index;
+ VOID *RingSeg;
+
+ //
+ // Disable the device slots occupied by these devices on its downstream ports.
+ // Entry 0 is reserved.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
+ continue;
+ }
+
+ Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;
+ }
+ }
+
+ //
+ // Construct the disable slot command
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));
+
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
+ CmdTrbDisSlot.CycleBit = 1;
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
+ CmdTrbDisSlot.SlotId = SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Free the slot's device context entry
+ //
+ Xhc->DCBAA[SlotId] = 0;
+
+ //
+ // Free the slot related data structure
+ //
+ for (Index = 0; Index < 31; Index++) {
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
+ RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
+ }
+ }
+
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));
+ }
+
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));
+ }
+ //
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
+ // remove urb from XHCI's asynchronous transfer list.
+ //
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;
+ Xhc->UsbDevContext[SlotId].SlotId = 0;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+XhcPeiDisableSlotCmd64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId
+ )
+{
+ EFI_STATUS Status;
+ TRB_TEMPLATE *EvtTrb;
+ CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
+ UINT8 Index;
+ VOID *RingSeg;
+
+ //
+ // Disable the device slots occupied by these devices on its downstream ports.
+ // Entry 0 is reserved.
+ //
+ for (Index = 0; Index < 255; Index++) {
+ if (!Xhc->UsbDevContext[Index + 1].Enabled ||
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
+ (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
+ continue;
+ }
+
+ Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
+ Xhc->UsbDevContext[Index + 1].SlotId = 0;
+ }
+ }
+
+ //
+ // Construct the disable slot command
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));
+
+ ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
+ CmdTrbDisSlot.CycleBit = 1;
+ CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
+ CmdTrbDisSlot.SlotId = SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Free the slot's device context entry
+ //
+ Xhc->DCBAA[SlotId] = 0;
+
+ //
+ // Free the slot related data structure
+ //
+ for (Index = 0; Index < 31; Index++) {
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
+ RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
+ if (RingSeg != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);
+ }
+ FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;
+ }
+ }
+
+ for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
+ if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
+ FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
+ }
+ }
+
+ if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));
+ }
+
+ if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));
+ }
+ //
+ // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
+ // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
+ // remove urb from XHCI's asynchronous transfer list.
+ //
+ Xhc->UsbDevContext[SlotId].Enabled = FALSE;
+ Xhc->UsbDevContext[SlotId].SlotId = 0;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+XhcPeiSetConfigCmd (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINT8 Index;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINT8 Interval;
+
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ //
+ // 4.6.6 Configure Endpoint
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
+ }
+
+ NumEp = IfDesc->NumEndpoints;
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
+ }
+
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcPeiEndpointToDci (EpAddr, Direction);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
+ //
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ } else {
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ }
+
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
+ case USB_ENDPOINT_BULK:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
+ }
+
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ }
+
+ break;
+ case USB_ENDPOINT_ISO:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
+ }
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.
+ // Refer to XHCI 1.1 spec section 6.2.3.6.
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval + 2;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ //
+ // Do not support isochronous transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ case USB_ENDPOINT_INTERRUPT:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
+ }
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
+ //
+ // Get the bInterval from descriptor and init the interval field of endpoint context
+ //
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
+ Interval = EpDesc->Interval;
+ //
+ // Calculate through the bInterval field of Endpoint descriptor.
+ //
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ //
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
+ //
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ }
+ break;
+
+ case USB_ENDPOINT_CONTROL:
+ //
+ // Do not support control transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
+ default:
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
+ }
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // configure endpoint
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+XhcPeiSetConfigCmd64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ )
+{
+ EFI_STATUS Status;
+ USB_INTERFACE_DESCRIPTOR *IfDesc;
+ USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ UINT8 Index;
+ UINTN NumEp;
+ UINTN EpIndex;
+ UINT8 EpAddr;
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 Dci;
+ UINT8 MaxDci;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINT8 Interval;
+
+ TRANSFER_RING *EndpointTransferRing;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ //
+ // 4.6.6 Configure Endpoint
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+ CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
+
+ ASSERT (ConfigDesc != NULL);
+
+ MaxDci = 0;
+
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);
+ for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
+ while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);
+ }
+
+ NumEp = IfDesc->NumEndpoints;
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);
+ for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
+ while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);
+ }
+
+ EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);
+ Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
+
+ Dci = XhcPeiEndpointToDci (EpAddr, Direction);
+ ASSERT (Dci < 32);
+ if (Dci > MaxDci) {
+ MaxDci = Dci;
+ }
+
+ InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
+ InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
+
+ if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ //
+ // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
+ //
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ } else {
+ InputContext->EP[Dci-1].MaxBurstSize = 0x0;
+ }
+
+ switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
+ case USB_ENDPOINT_BULK:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
+ }
+
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ }
+
+ break;
+ case USB_ENDPOINT_ISO:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 0;
+ InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
+ }
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.
+ // Refer to XHCI 1.1 spec section 6.2.3.6.
+ //
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval + 2;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ //
+ // Do not support isochronous transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ case USB_ENDPOINT_INTERRUPT:
+ if (Direction == EfiUsbDataIn) {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
+ } else {
+ InputContext->EP[Dci-1].CErr = 3;
+ InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
+ }
+ InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
+ InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
+ //
+ // Get the bInterval from descriptor and init the the interval field of endpoint context
+ //
+ if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
+ Interval = EpDesc->Interval;
+ //
+ // Calculate through the bInterval field of Endpoint descriptor.
+ //
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
+ Interval = EpDesc->Interval;
+ ASSERT (Interval >= 1 && Interval <= 16);
+ //
+ // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
+ //
+ InputContext->EP[Dci-1].Interval = Interval - 1;
+ }
+
+ if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
+ EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
+ Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
+ XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
+ }
+ break;
+
+ case USB_ENDPOINT_CONTROL:
+ //
+ // Do not support control transfer now.
+ //
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
+ default:
+ DEBUG ((EFI_D_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
+ continue;
+ }
+
+ PhyAddr = UsbHcGetPciAddrForHostAddr (
+ Xhc->MemPool,
+ ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
+
+ InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);
+ InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);
+
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);
+ }
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);
+ }
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+ InputContext->Slot.ContextEntries = MaxDci;
+ //
+ // configure endpoint
+ //
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+XhcPeiEvaluateContext (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ )
+{
+ EFI_STATUS Status;
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ InputContext->InputControlContext.Dword2 |= BIT1;
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;
+
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbEvalu.CycleBit = 1;
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+XhcPeiEvaluateContext64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ )
+{
+ EFI_STATUS Status;
+ CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ InputContext->InputControlContext.Dword2 |= BIT1;
+ InputContext->EP[0].MaxPacketSize = MaxPacketSize;
+
+ ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbEvalu.CycleBit = 1;
+ CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
+ CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcPeiConfigHubContext (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT *InputContext;
+ DEVICE_CONTEXT *OutputContext;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+
+ //
+ // Copy the slot context from OutputContext to Input context
+ //
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
+ InputContext->Slot.Hub = 1;
+ InputContext->Slot.PortNum = PortNum;
+ InputContext->Slot.TTT = TTT;
+ InputContext->Slot.MTT = MTT;
+
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcPeiConfigHubContext64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ INPUT_CONTEXT_64 *InputContext;
+ DEVICE_CONTEXT_64 *OutputContext;
+ CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ InputContext = Xhc->UsbDevContext[SlotId].InputContext;
+ OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
+
+ //
+ // 4.6.7 Evaluate Context
+ //
+ ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
+
+ InputContext->InputControlContext.Dword2 |= BIT0;
+
+ //
+ // Copy the slot context from OutputContext to Input context
+ //
+ CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
+ InputContext->Slot.Hub = 1;
+ InputContext->Slot.PortNum = PortNum;
+ InputContext->Slot.TTT = TTT;
+ InputContext->Slot.MTT = MTT;
+
+ ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));
+ CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);
+ CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdTrbCfgEP.CycleBit = 1;
+ CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
+ CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
+ DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));
+ }
+ return Status;
+}
+
+/**
+ Stop endpoint through XHCI's Stop_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Stop endpoint successfully.
+ @retval Others Failed to stop endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiStopEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_TRB_STOP_ENDPOINT CmdTrbStopED;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));
+ CmdTrbStopED.CycleBit = 1;
+ CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;
+ CmdTrbStopED.EDID = Dci;
+ CmdTrbStopED.SlotId = SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Reset endpoint through XHCI's Reset_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Reset endpoint successfully.
+ @retval Others Failed to reset endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiResetEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
+ CmdTrbResetED.CycleBit = 1;
+ CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
+ CmdTrbResetED.EDID = Dci;
+ CmdTrbResetED.SlotId = SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+ @param Urb The dequeue pointer of the transfer ring specified
+ by the urb to be updated.
+
+ @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
+ @retval Others Failed to set transfer ring dequeue pointer.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiSetTrDequeuePointer (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *Urb
+ )
+{
+ EFI_STATUS Status;
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ DEBUG ((EFI_D_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
+
+ //
+ // Send stop endpoint command to transit Endpoint from running to stop state
+ //
+ ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));
+ CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;
+ CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ CmdSetTRDeq.CycleBit = 1;
+ CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
+ CmdSetTRDeq.Endpoint = Dci;
+ CmdSetTRDeq.SlotId = SlotId;
+ Status = XhcPeiCmdTransfer (
+ Xhc,
+ (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
+ XHC_GENERIC_TIMEOUT,
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Check if there is a new generated event.
+
+ @param Xhc The XHCI device.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+XhcPeiCheckNewEvent (
+ IN PEI_XHC_DEV *Xhc,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ )
+{
+ ASSERT (EvtRing != NULL);
+
+ *NewEvtTrb = EvtRing->EventRingDequeue;
+
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
+ return EFI_NOT_READY;
+ }
+
+ EvtRing->EventRingDequeue++;
+ //
+ // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
+ //
+ if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI device.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+XhcPeiSyncEventRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN EVENT_RING *EvtRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *EvtTrb;
+
+ ASSERT (EvtRing != NULL);
+
+ //
+ // Calculate the EventRingEnqueue and EventRingCCS.
+ // Note: only support single Segment
+ //
+ EvtTrb = EvtRing->EventRingDequeue;
+
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
+ if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {
+ break;
+ }
+
+ EvtTrb++;
+
+ if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtTrb = EvtRing->EventRingSeg0;
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
+ }
+ }
+
+ if (Index < EvtRing->TrbNumber) {
+ EvtRing->EventRingEnqueue = EvtTrb;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free XHCI event ring.
+
+ @param Xhc The XHCI device.
+ @param EventRing The event ring to be freed.
+
+**/
+VOID
+XhcPeiFreeEventRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN EVENT_RING *EventRing
+ )
+{
+ if(EventRing->EventRingSeg0 == NULL) {
+ return;
+ }
+
+ //
+ // Free EventRing Segment 0
+ //
+ UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+
+ //
+ // Free ERST table
+ //
+ UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+}
+
+/**
+ Create XHCI event ring.
+
+ @param Xhc The XHCI device.
+ @param EventRing The created event ring.
+
+**/
+VOID
+XhcPeiCreateEventRing (
+ IN PEI_XHC_DEV *Xhc,
+ OUT EVENT_RING *EventRing
+ )
+{
+ VOID *Buf;
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS ERSTPhy;
+ EFI_PHYSICAL_ADDRESS DequeuePhy;
+
+ ASSERT (EventRing != NULL);
+
+ Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, Size);
+
+ DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
+
+ EventRing->EventRingSeg0 = Buf;
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
+ EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
+ EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
+
+ //
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
+ //
+ EventRing->EventRingCCS = 1;
+
+ Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
+ Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, Size);
+
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
+ EventRing->ERSTBase = ERSTBase;
+ ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
+
+ ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);
+
+ //
+ // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
+ //
+ XhcPeiWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTSZ_OFFSET,
+ ERST_NUMBER
+ );
+ //
+ // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcPeiWriteRuntimeReg (
+ Xhc,
+ XHC_ERDP_OFFSET,
+ XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)
+ );
+ XhcPeiWriteRuntimeReg (
+ Xhc,
+ XHC_ERDP_OFFSET + 4,
+ XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)
+ );
+ //
+ // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcPeiWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTBA_OFFSET,
+ XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)
+ );
+ XhcPeiWriteRuntimeReg (
+ Xhc,
+ XHC_ERSTBA_OFFSET + 4,
+ XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)
+ );
+ //
+ // Need set IMAN IE bit to enable the ring interrupt
+ //
+ XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
+}
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI device.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+XhcPeiSyncTrsRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN TRANSFER_RING *TrsRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *TrsTrb;
+
+ ASSERT (TrsRing != NULL);
+ //
+ // Calculate the latest RingEnqueue and RingPCS
+ //
+ TrsTrb = TrsRing->RingEnqueue;
+ ASSERT (TrsTrb != NULL);
+
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
+ break;
+ }
+ TrsTrb++;
+ if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
+ ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);
+ //
+ // set cycle bit in Link TRB as normal
+ //
+ ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
+ //
+ // Toggle PCS maintained by software
+ //
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
+ TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address
+ }
+ }
+
+ ASSERT (Index != TrsRing->TrbNumber);
+
+ if (TrsTrb != TrsRing->RingEnqueue) {
+ TrsRing->RingEnqueue = TrsTrb;
+ }
+
+ //
+ // Clear the Trb context for enqueue, but reserve the PCS bit
+ //
+ TrsTrb->Parameter1 = 0;
+ TrsTrb->Parameter2 = 0;
+ TrsTrb->Status = 0;
+ TrsTrb->RsvdZ1 = 0;
+ TrsTrb->Type = 0;
+ TrsTrb->Control = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create XHCI transfer ring.
+
+ @param Xhc The XHCI Device.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+XhcPeiCreateTransferRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINTN TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ )
+{
+ VOID *Buf;
+ LINK_TRB *EndTrb;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+
+ Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+
+ TransferRing->RingSeg0 = Buf;
+ TransferRing->TrbNumber = TrbNum;
+ TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
+ TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
+ TransferRing->RingPCS = 1;
+ //
+ // 4.9.2 Transfer Ring Management
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
+ // point to the first TRB in the ring.
+ //
+ EndTrb = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
+ EndTrb->Type = TRB_TYPE_LINK;
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+ EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);
+ EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);
+ //
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
+ //
+ EndTrb->TC = 1;
+ //
+ // Set Cycle bit as other TRB PCS init value
+ //
+ EndTrb->CycleBit = 0;
+}
+
+/**
+ Initialize the XHCI host controller for schedule.
+
+ @param Xhc The XHCI device to be initialized.
+
+**/
+VOID
+XhcPeiInitSched (
+ IN PEI_XHC_DEV *Xhc
+ )
+{
+ VOID *Dcbaa;
+ EFI_PHYSICAL_ADDRESS DcbaaPhy;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS CmdRingPhy;
+ UINT32 MaxScratchpadBufs;
+ UINT64 *ScratchBuf;
+ EFI_PHYSICAL_ADDRESS ScratchPhy;
+ UINT64 *ScratchEntry;
+ EFI_PHYSICAL_ADDRESS ScratchEntryPhy;
+ UINT32 Index;
+ UINTN *ScratchEntryMap;
+ EFI_STATUS Status;
+
+ //
+ // Initialize memory management.
+ //
+ Xhc->MemPool = UsbHcInitMemPool ();
+ ASSERT (Xhc->MemPool != NULL);
+
+ //
+ // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
+ // to enable the device slots that system software is going to use.
+ //
+ Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
+ ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
+ XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);
+
+ //
+ // The Device Context Base Address Array entry associated with each allocated Device Slot
+ // shall contain a 64-bit pointer to the base of the associated Device Context.
+ // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
+ // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
+ //
+ Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
+ Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);
+ ASSERT (Dcbaa != NULL);
+
+ //
+ // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
+ // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
+ // mode (Run/Stop(R/S) ='1').
+ //
+ MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
+ Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
+ ASSERT (MaxScratchpadBufs <= 1023);
+ if (MaxScratchpadBufs != 0) {
+ //
+ // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
+ //
+ ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
+ ASSERT (ScratchEntryMap != NULL);
+ Xhc->ScratchEntryMap = ScratchEntryMap;
+
+ //
+ // Allocate the buffer to record the host address for each entry
+ //
+ ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
+ ASSERT (ScratchEntry != NULL);
+ Xhc->ScratchEntry = ScratchEntry;
+
+ ScratchPhy = 0;
+ Status = UsbHcAllocateAlignedPages (
+ EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
+ Xhc->PageSize,
+ (VOID **) &ScratchBuf,
+ &ScratchPhy,
+ &Xhc->ScratchMap
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
+ Xhc->ScratchBuf = ScratchBuf;
+
+ //
+ // Allocate each scratch buffer
+ //
+ for (Index = 0; Index < MaxScratchpadBufs; Index++) {
+ ScratchEntryPhy = 0;
+ Status = UsbHcAllocateAlignedPages (
+ EFI_SIZE_TO_PAGES (Xhc->PageSize),
+ Xhc->PageSize,
+ (VOID **) &ScratchEntry[Index],
+ &ScratchEntryPhy,
+ (VOID **) &ScratchEntryMap[Index]
+ );
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);
+ //
+ // Fill with the PCI device address
+ //
+ *ScratchBuf++ = ScratchEntryPhy;
+ }
+ //
+ // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
+ // Device Context Base Address Array points to the Scratchpad Buffer Array.
+ //
+ *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;
+ }
+
+ //
+ // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
+ // a 64-bit address pointing to where the Device Context Base Address Array is located.
+ //
+ Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);
+ XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));
+ XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));
+
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));
+
+ //
+ // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
+ // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
+ // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
+ // always be '0'.
+ //
+ XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
+ //
+ // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
+ // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
+ // So we set RCS as inverted PCS init value to let Command Ring empty
+ //
+ CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
+ ASSERT ((CmdRingPhy & 0x3F) == 0);
+ CmdRingPhy |= XHC_CRCR_RCS;
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));
+ XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));
+
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
+
+ //
+ // Disable the 'interrupter enable' bit in USB_CMD
+ // and clear IE & IP bit in all Interrupter X Management Registers.
+ //
+ XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
+ for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
+ XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
+ XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
+ }
+
+ //
+ // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
+ //
+ XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);
+ DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
+}
+
+/**
+ Free the resouce allocated at initializing schedule.
+
+ @param Xhc The XHCI device.
+
+**/
+VOID
+XhcPeiFreeSched (
+ IN PEI_XHC_DEV *Xhc
+ )
+{
+ UINT32 Index;
+ UINT64 *ScratchEntry;
+
+ if (Xhc->ScratchBuf != NULL) {
+ ScratchEntry = Xhc->ScratchEntry;
+ for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
+ //
+ // Free Scratchpad Buffers
+ //
+ UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);
+ }
+ //
+ // Free Scratchpad Buffer Array
+ //
+ UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
+ FreePool (Xhc->ScratchEntryMap);
+ FreePool (Xhc->ScratchEntry);
+ }
+
+ if (Xhc->CmdRing.RingSeg0 != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);
+ Xhc->CmdRing.RingSeg0 = NULL;
+ }
+
+ XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);
+
+ if (Xhc->DCBAA != NULL) {
+ UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));
+ Xhc->DCBAA = NULL;
+ }
+
+ //
+ // Free memory pool at last
+ //
+ if (Xhc->MemPool != NULL) {
+ UsbHcFreeMemPool (Xhc->MemPool);
+ Xhc->MemPool = NULL;
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
new file mode 100644
index 000000000..badc57a51
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
@@ -0,0 +1,1301 @@
+/** @file
+Private Header file for Usb Host Controller PEIM
+
+Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_PEI_XHCI_SCHED_H_
+#define _EFI_PEI_XHCI_SCHED_H_
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define XHC_CTRL_TRANSFER 0x01
+#define XHC_BULK_TRANSFER 0x02
+
+//
+// 6.4.6 TRB Types
+//
+#define TRB_TYPE_NORMAL 1
+#define TRB_TYPE_SETUP_STAGE 2
+#define TRB_TYPE_DATA_STAGE 3
+#define TRB_TYPE_STATUS_STAGE 4
+#define TRB_TYPE_ISOCH 5
+#define TRB_TYPE_LINK 6
+#define TRB_TYPE_EVENT_DATA 7
+#define TRB_TYPE_NO_OP 8
+#define TRB_TYPE_EN_SLOT 9
+#define TRB_TYPE_DIS_SLOT 10
+#define TRB_TYPE_ADDRESS_DEV 11
+#define TRB_TYPE_CON_ENDPOINT 12
+#define TRB_TYPE_EVALU_CONTXT 13
+#define TRB_TYPE_RESET_ENDPOINT 14
+#define TRB_TYPE_STOP_ENDPOINT 15
+#define TRB_TYPE_SET_TR_DEQUE 16
+#define TRB_TYPE_RESET_DEV 17
+#define TRB_TYPE_GET_PORT_BANW 21
+#define TRB_TYPE_FORCE_HEADER 22
+#define TRB_TYPE_NO_OP_COMMAND 23
+#define TRB_TYPE_TRANS_EVENT 32
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
+
+//
+// Endpoint Type (EP Type).
+//
+#define ED_NOT_VALID 0
+#define ED_ISOCH_OUT 1
+#define ED_BULK_OUT 2
+#define ED_INTERRUPT_OUT 3
+#define ED_CONTROL_BIDIR 4
+#define ED_ISOCH_IN 5
+#define ED_BULK_IN 6
+#define ED_INTERRUPT_IN 7
+
+//
+// 6.4.5 TRB Completion Codes
+//
+#define TRB_COMPLETION_INVALID 0
+#define TRB_COMPLETION_SUCCESS 1
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
+#define TRB_COMPLETION_BABBLE_ERROR 3
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
+#define TRB_COMPLETION_TRB_ERROR 5
+#define TRB_COMPLETION_STALL_ERROR 6
+#define TRB_COMPLETION_SHORT_PACKET 13
+
+//
+// The topology string used to present usb device location
+//
+typedef struct _USB_DEV_TOPOLOGY {
+ //
+ // The tier concatenation of down stream port.
+ //
+ UINT32 RouteString:20;
+ //
+ // The root port number of the chain.
+ //
+ UINT32 RootPortNum:8;
+ //
+ // The Tier the device reside.
+ //
+ UINT32 TierNum:4;
+} USB_DEV_TOPOLOGY;
+
+//
+// USB Device's RouteChart
+//
+typedef union _USB_DEV_ROUTE {
+ UINT32 Dword;
+ USB_DEV_TOPOLOGY Route;
+} USB_DEV_ROUTE;
+
+//
+// Endpoint address and its capabilities
+//
+typedef struct _USB_ENDPOINT {
+ //
+ // Store logical device address assigned by UsbBus
+ // It's because some XHCI host controllers may assign the same physcial device
+ // address for those devices inserted at different root port.
+ //
+ UINT8 BusAddr;
+ UINT8 DevAddr;
+ UINT8 EpAddr;
+ EFI_USB_DATA_DIRECTION Direction;
+ UINT8 DevSpeed;
+ UINTN MaxPacket;
+ UINTN Type;
+} USB_ENDPOINT;
+
+//
+// TRB Template
+//
+typedef struct _TRB_TEMPLATE {
+ UINT32 Parameter1;
+
+ UINT32 Parameter2;
+
+ UINT32 Status;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:9;
+ UINT32 Type:6;
+ UINT32 Control:16;
+} TRB_TEMPLATE;
+
+typedef struct _TRANSFER_RING {
+ VOID *RingSeg0;
+ UINTN TrbNumber;
+ TRB_TEMPLATE *RingEnqueue;
+ TRB_TEMPLATE *RingDequeue;
+ UINT32 RingPCS;
+} TRANSFER_RING;
+
+typedef struct _EVENT_RING {
+ VOID *ERSTBase;
+ VOID *EventRingSeg0;
+ UINTN TrbNumber;
+ TRB_TEMPLATE *EventRingEnqueue;
+ TRB_TEMPLATE *EventRingDequeue;
+ UINT32 EventRingCCS;
+} EVENT_RING;
+
+#define XHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+typedef struct _URB {
+ UINT32 Signature;
+ //
+ // Usb Device URB related information
+ //
+ USB_ENDPOINT Ep;
+ EFI_USB_DEVICE_REQUEST *Request;
+ VOID *Data;
+ UINTN DataLen;
+ VOID *DataPhy;
+ VOID *DataMap;
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
+ VOID *Context;
+ //
+ // Execute result
+ //
+ UINT32 Result;
+ //
+ // completed data length
+ //
+ UINTN Completed;
+ //
+ // Command/Tranfer Ring info
+ //
+ TRANSFER_RING *Ring;
+ TRB_TEMPLATE *TrbStart;
+ TRB_TEMPLATE *TrbEnd;
+ UINTN TrbNum;
+ BOOLEAN StartDone;
+ BOOLEAN EndDone;
+ BOOLEAN Finished;
+
+ TRB_TEMPLATE *EvtTrb;
+} URB;
+
+//
+// 6.5 Event Ring Segment Table
+// The Event Ring Segment Table is used to define multi-segment Event Rings and to enable runtime
+// expansion and shrinking of the Event Ring. The location of the Event Ring Segment Table is defined by the
+// Event Ring Segment Table Base Address Register (5.5.2.3.2). The size of the Event Ring Segment Table
+// is defined by the Event Ring Segment Table Base Size Register (5.5.2.3.1).
+//
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
+ UINT32 PtrLo;
+ UINT32 PtrHi;
+ UINT32 RingTrbSize:16;
+ UINT32 RsvdZ1:16;
+ UINT32 RsvdZ2;
+} EVENT_RING_SEG_TABLE_ENTRY;
+
+//
+// 6.4.1.1 Normal TRB
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
+// Rings, and to define the Data stage information for Control Transfer Rings.
+//
+typedef struct _TRANSFER_TRB_NORMAL {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:2;
+ UINT32 BEI:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ2:16;
+} TRANSFER_TRB_NORMAL;
+
+//
+// 6.4.1.2.1 Setup Stage TRB
+// A Setup Stage TRB is created by system software to initiate a USB Setup packet on a control endpoint.
+//
+typedef struct _TRANSFER_TRB_CONTROL_SETUP {
+ UINT32 bmRequestType:8;
+ UINT32 bRequest:8;
+ UINT32 wValue:16;
+
+ UINT32 wIndex:16;
+ UINT32 wLength:16;
+
+ UINT32 Length:17;
+ UINT32 RsvdZ1:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:4;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ3:3;
+ UINT32 Type:6;
+ UINT32 TRT:2;
+ UINT32 RsvdZ4:14;
+} TRANSFER_TRB_CONTROL_SETUP;
+
+//
+// 6.4.1.2.2 Data Stage TRB
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.
+//
+typedef struct _TRANSFER_TRB_CONTROL_DATA {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:3;
+ UINT32 Type:6;
+ UINT32 DIR:1;
+ UINT32 RsvdZ2:15;
+} TRANSFER_TRB_CONTROL_DATA;
+
+//
+// 6.4.1.2.2 Data Stage TRB
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.
+//
+typedef struct _TRANSFER_TRB_CONTROL_STATUS {
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 RsvdZ3:22;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 RsvdZ4:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ5:4;
+ UINT32 Type:6;
+ UINT32 DIR:1;
+ UINT32 RsvdZ6:15;
+} TRANSFER_TRB_CONTROL_STATUS;
+
+//
+// 6.4.2.1 Transfer Event TRB
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
+// for more information on the use and operation of Transfer Events.
+//
+typedef struct _EVT_TRB_TRANSFER {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:1;
+ UINT32 ED:1;
+ UINT32 RsvdZ2:7;
+ UINT32 Type:6;
+ UINT32 EndpointId:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} EVT_TRB_TRANSFER;
+
+//
+// 6.4.2.2 Command Completion Event TRB
+// A Command Completion Event TRB shall be generated by the xHC when a command completes on the
+// Command Ring. Refer to section 4.11.4 for more information on the use of Command Completion Events.
+//
+typedef struct _EVT_TRB_COMMAND_COMPLETION {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 RsvdZ2:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 VFID:8;
+ UINT32 SlotId:8;
+} EVT_TRB_COMMAND_COMPLETION;
+
+typedef union _TRB {
+ TRB_TEMPLATE TrbTemplate;
+ TRANSFER_TRB_NORMAL TrbNormal;
+ TRANSFER_TRB_CONTROL_SETUP TrbCtrSetup;
+ TRANSFER_TRB_CONTROL_DATA TrbCtrData;
+ TRANSFER_TRB_CONTROL_STATUS TrbCtrStatus;
+} TRB;
+
+//
+// 6.4.3.1 No Op Command TRB
+// The No Op Command TRB provides a simple means for verifying the operation of the Command Ring
+// mechanisms offered by the xHCI.
+//
+typedef struct _CMD_TRB_NO_OP {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} CMD_TRB_NO_OP;
+
+//
+// 6.4.3.2 Enable Slot Command TRB
+// The Enable Slot Command TRB causes the xHC to select an available Device Slot and return the ID of the
+// selected slot to the host in a Command Completion Event.
+//
+typedef struct _CMD_TRB_ENABLE_SLOT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} CMD_TRB_ENABLE_SLOT;
+
+//
+// 6.4.3.3 Disable Slot Command TRB
+// The Disable Slot Command TRB releases any bandwidth assigned to the disabled slot and frees any
+// internal xHC resources assigned to the slot.
+//
+typedef struct _CMD_TRB_DISABLE_SLOT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:8;
+ UINT32 SlotId:8;
+} CMD_TRB_DISABLE_SLOT;
+
+//
+// 6.4.3.4 Address Device Command TRB
+// The Address Device Command TRB transitions the selected Device Context from the Default to the
+// Addressed state and causes the xHC to select an address for the USB device in the Default State and
+// issue a SET_ADDRESS request to the USB device.
+//
+typedef struct _CMD_TRB_ADDRESS_DEVICE {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:8;
+ UINT32 BSR:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_ADDRESS_DEVICE;
+
+//
+// 6.4.3.5 Configure Endpoint Command TRB
+// The Configure Endpoint Command TRB evaluates the bandwidth and resource requirements of the
+// endpoints selected by the command.
+//
+typedef struct _CMD_TRB_CONFIG_ENDPOINT {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:8;
+ UINT32 DC:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_CONFIG_ENDPOINT;
+
+//
+// 6.4.3.6 Evaluate Context Command TRB
+// The Evaluate Context Command TRB is used by system software to inform the xHC that the selected
+// Context data structures in the Device Context have been modified by system software and that the xHC
+// shall evaluate any changes
+//
+typedef struct _CMD_TRB_EVALUATE_CONTEXT {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:9;
+ UINT32 Type:6;
+ UINT32 RsvdZ3:8;
+ UINT32 SlotId:8;
+} CMD_TRB_EVALUATE_CONTEXT;
+
+//
+// 6.4.3.7 Reset Endpoint Command TRB
+// The Reset Endpoint Command TRB is used by system software to reset a specified Transfer Ring
+//
+typedef struct _CMD_TRB_RESET_ENDPOINT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:8;
+ UINT32 TSP:1;
+ UINT32 Type:6;
+ UINT32 EDID:5;
+ UINT32 RsvdZ4:3;
+ UINT32 SlotId:8;
+} CMD_TRB_RESET_ENDPOINT;
+
+//
+// 6.4.3.8 Stop Endpoint Command TRB
+// The Stop Endpoint Command TRB command allows software to stop the xHC execution of the TDs on a
+// Transfer Ring and temporarily take ownership of TDs that had previously been passed to the xHC.
+//
+typedef struct _CMD_TRB_STOP_ENDPOINT {
+ UINT32 RsvdZ0;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ3:9;
+ UINT32 Type:6;
+ UINT32 EDID:5;
+ UINT32 RsvdZ4:2;
+ UINT32 SP:1;
+ UINT32 SlotId:8;
+} CMD_TRB_STOP_ENDPOINT;
+
+//
+// 6.4.3.9 Set TR Dequeue Pointer Command TRB
+// The Set TR Dequeue Pointer Command TRB is used by system software to modify the TR Dequeue
+// Pointer and DCS fields of an Endpoint or Stream Context.
+//
+typedef struct _CMD_SET_TR_DEQ_POINTER {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:16;
+ UINT32 StreamID:16;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ2:9;
+ UINT32 Type:6;
+ UINT32 Endpoint:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} CMD_SET_TR_DEQ_POINTER;
+
+//
+// 6.4.4.1 Link TRB
+// A Link TRB provides support for non-contiguous TRB Rings.
+//
+typedef struct _LINK_TRB {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:22;
+ UINT32 InterTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 TC:1;
+ UINT32 RsvdZ2:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ3:4;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} LINK_TRB;
+
+//
+// 6.2.2 Slot Context
+//
+typedef struct _SLOT_CONTEXT {
+ UINT32 RouteString:20;
+ UINT32 Speed:4;
+ UINT32 RsvdZ1:1;
+ UINT32 MTT:1;
+ UINT32 Hub:1;
+ UINT32 ContextEntries:5;
+
+ UINT32 MaxExitLatency:16;
+ UINT32 RootHubPortNum:8;
+ UINT32 PortNum:8;
+
+ UINT32 TTHubSlotId:8;
+ UINT32 TTPortNum:8;
+ UINT32 TTT:2;
+ UINT32 RsvdZ2:4;
+ UINT32 InterTarget:10;
+
+ UINT32 DeviceAddress:8;
+ UINT32 RsvdZ3:19;
+ UINT32 SlotState:5;
+
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+} SLOT_CONTEXT;
+
+typedef struct _SLOT_CONTEXT_64 {
+ UINT32 RouteString:20;
+ UINT32 Speed:4;
+ UINT32 RsvdZ1:1;
+ UINT32 MTT:1;
+ UINT32 Hub:1;
+ UINT32 ContextEntries:5;
+
+ UINT32 MaxExitLatency:16;
+ UINT32 RootHubPortNum:8;
+ UINT32 PortNum:8;
+
+ UINT32 TTHubSlotId:8;
+ UINT32 TTPortNum:8;
+ UINT32 TTT:2;
+ UINT32 RsvdZ2:4;
+ UINT32 InterTarget:10;
+
+ UINT32 DeviceAddress:8;
+ UINT32 RsvdZ3:19;
+ UINT32 SlotState:5;
+
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+
+} SLOT_CONTEXT_64;
+
+
+//
+// 6.2.3 Endpoint Context
+//
+typedef struct _ENDPOINT_CONTEXT {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2;
+ UINT32 MaxPStreams:5;
+ UINT32 LSA:1;
+ UINT32 Interval:8;
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1;
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16;
+
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+} ENDPOINT_CONTEXT;
+
+typedef struct _ENDPOINT_CONTEXT_64 {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2;
+ UINT32 MaxPStreams:5;
+ UINT32 LSA:1;
+ UINT32 Interval:8;
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1;
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16;
+
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+
+} ENDPOINT_CONTEXT_64;
+
+
+//
+// 6.2.5.1 Input Control Context
+//
+typedef struct _INPUT_CONTRL_CONTEXT {
+ UINT32 Dword1;
+ UINT32 Dword2;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+ UINT32 RsvdZ3;
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+} INPUT_CONTRL_CONTEXT;
+
+typedef struct _INPUT_CONTRL_CONTEXT_64 {
+ UINT32 Dword1;
+ UINT32 Dword2;
+ UINT32 RsvdZ1;
+ UINT32 RsvdZ2;
+ UINT32 RsvdZ3;
+ UINT32 RsvdZ4;
+ UINT32 RsvdZ5;
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+} INPUT_CONTRL_CONTEXT_64;
+
+//
+// 6.2.1 Device Context
+//
+typedef struct _DEVICE_CONTEXT {
+ SLOT_CONTEXT Slot;
+ ENDPOINT_CONTEXT EP[31];
+} DEVICE_CONTEXT;
+
+typedef struct _DEVICE_CONTEXT_64 {
+ SLOT_CONTEXT_64 Slot;
+ ENDPOINT_CONTEXT_64 EP[31];
+} DEVICE_CONTEXT_64;
+
+//
+// 6.2.5 Input Context
+//
+typedef struct _INPUT_CONTEXT {
+ INPUT_CONTRL_CONTEXT InputControlContext;
+ SLOT_CONTEXT Slot;
+ ENDPOINT_CONTEXT EP[31];
+} INPUT_CONTEXT;
+
+typedef struct _INPUT_CONTEXT_64 {
+ INPUT_CONTRL_CONTEXT_64 InputControlContext;
+ SLOT_CONTEXT_64 Slot;
+ ENDPOINT_CONTEXT_64 EP[31];
+} INPUT_CONTEXT_64;
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Xhc The XHCI device.
+ @param CmdTransfer The executed URB is for cmd transfer or not.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+XhcPeiExecTransfer (
+ IN PEI_XHC_DEV *Xhc,
+ IN BOOLEAN CmdTransfer,
+ IN URB *Urb,
+ IN UINTN Timeout
+ );
+
+/**
+ Find out the actual device address according to the requested device address from UsbBus.
+
+ @param Xhc The XHCI device.
+ @param BusDevAddr The requested device address by UsbBus upper driver.
+
+ @return The actual device address assigned to the device.
+
+**/
+UINT8
+XhcPeiBusDevAddrToSlotId (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 BusDevAddr
+ );
+
+/**
+ Find out the slot id according to the device's route string.
+
+ @param Xhc The XHCI device.
+ @param RouteString The route string described the device location.
+
+ @return The slot id used by the device.
+
+**/
+UINT8
+XhcPeiRouteStringToSlotId (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE RouteString
+ );
+
+/**
+ Calculate the device context index by endpoint address and direction.
+
+ @param EpAddr The target endpoint number.
+ @param Direction The direction of the target endpoint.
+
+ @return The device context index of endpoint.
+
+**/
+UINT8
+XhcPeiEndpointToDci (
+ IN UINT8 EpAddr,
+ IN EFI_USB_DATA_DIRECTION Direction
+ );
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+**/
+VOID
+XhcPeiRingDoorBell (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ );
+
+/**
+ Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device if it exists.
+ @param Port The port to be polled.
+ @param PortState The port state.
+
+ @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
+ @retval Others Should not appear.
+
+**/
+EFI_STATUS
+XhcPeiPollPortStatusChange (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_STATUS *PortState
+ );
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcPeiConfigHubContext (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ );
+
+/**
+ Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param PortNum The total number of downstream port supported by the hub.
+ @param TTT The TT think time of the hub device.
+ @param MTT The multi-TT of the hub device.
+
+ @retval EFI_SUCCESS Successfully configure the hub device's slot context.
+
+**/
+EFI_STATUS
+XhcPeiConfigHubContext64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 PortNum,
+ IN UINT8 TTT,
+ IN UINT8 MTT
+ );
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+XhcPeiSetConfigCmd (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ );
+
+/**
+ Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be configured.
+ @param DeviceSpeed The device's speed.
+ @param ConfigDesc The pointer to the usb device configuration descriptor.
+
+ @retval EFI_SUCCESS Successfully configure all the device endpoints.
+
+**/
+EFI_STATUS
+XhcPeiSetConfigCmd64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 DeviceSpeed,
+ IN USB_CONFIG_DESCRIPTOR *ConfigDesc
+ );
+
+/**
+ Stop endpoint through XHCI's Stop_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Stop endpoint successfully.
+ @retval Others Failed to stop endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiStopEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ );
+
+/**
+ Reset endpoint through XHCI's Reset_Endpoint cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+
+ @retval EFI_SUCCESS Reset endpoint successfully.
+ @retval Others Failed to reset endpoint.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiResetEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci
+ );
+
+/**
+ Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id of the target device.
+ @param Dci The device context index of the target slot or endpoint.
+ @param Urb The dequeue pointer of the transfer ring specified
+ by the urb to be updated.
+
+ @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
+ @retval Others Failed to set transfer ring dequeue pointer.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcPeiSetTrDequeuePointer (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT8 Dci,
+ IN URB *Urb
+ );
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+ @retval Others Fail to initialize device slot.
+
+**/
+EFI_STATUS
+XhcPeiInitializeDeviceSlot (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ );
+
+/**
+ Assign and initialize the device slot for a new device.
+
+ @param Xhc The XHCI device.
+ @param ParentRouteChart The route string pointed to the parent device.
+ @param ParentPort The port at which the device is located.
+ @param RouteChart The route string pointed to the device.
+ @param DeviceSpeed The device speed.
+
+ @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
+ @retval Others Fail to initialize device slot.
+
+**/
+EFI_STATUS
+XhcPeiInitializeDeviceSlot64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN USB_DEV_ROUTE ParentRouteChart,
+ IN UINT16 ParentPort,
+ IN USB_DEV_ROUTE RouteChart,
+ IN UINT8 DeviceSpeed
+ );
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+XhcPeiEvaluateContext (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ );
+
+/**
+ Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be evaluated.
+ @param MaxPacketSize The max packet size supported by the device control transfer.
+
+ @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
+
+**/
+EFI_STATUS
+XhcPeiEvaluateContext64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId,
+ IN UINT32 MaxPacketSize
+ );
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+XhcPeiDisableSlotCmd (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId
+ );
+
+/**
+ Disable the specified device slot.
+
+ @param Xhc The XHCI device.
+ @param SlotId The slot id to be disabled.
+
+ @retval EFI_SUCCESS Successfully disable the device slot.
+
+**/
+EFI_STATUS
+XhcPeiDisableSlotCmd64 (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 SlotId
+ );
+
+/**
+ System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
+ condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
+ Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
+ reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
+ Stopped to the Running state.
+
+ @param Xhc The XHCI device.
+ @param Urb The urb which makes the endpoint halted.
+
+ @retval EFI_SUCCESS The recovery is successful.
+ @retval Others Failed to recovery halted endpoint.
+
+**/
+EFI_STATUS
+XhcPeiRecoverHaltedEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
+ Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
+ the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
+ state.
+
+ @param Xhc The XHCI device.
+ @param Urb The urb which doesn't get completed in a specified timeout range.
+
+ @retval EFI_SUCCESS The dequeuing of the TDs is successful.
+ @retval Others Failed to stop the endpoint and dequeue the TDs.
+
+**/
+EFI_STATUS
+XhcPeiDequeueTrbFromEndpoint (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Xhc The XHCI device
+ @param DevAddr The device address
+ @param EpAddr Endpoint addrress
+ @param DevSpeed The device speed
+ @param MaxPacket The max packet length of the endpoint
+ @param Type The transaction type
+ @param Request The standard USB request for control transfer
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+ @param Callback The function to call when data is transferred
+ @param Context The context to the callback
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcPeiCreateUrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINTN Type,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN VOID *Data,
+ IN UINTN DataLen,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context
+ );
+
+/**
+ Free an allocated URB.
+
+ @param Xhc The XHCI device.
+ @param Urb The URB to free.
+
+**/
+VOID
+XhcPeiFreeUrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Create a transfer TRB.
+
+ @param Xhc The XHCI device
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcPeiCreateTransferTrb (
+ IN PEI_XHC_DEV *Xhc,
+ IN URB *Urb
+ );
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI device.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+XhcPeiSyncTrsRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN TRANSFER_RING *TrsRing
+ );
+
+/**
+ Create XHCI transfer ring.
+
+ @param Xhc The XHCI Device.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+XhcPeiCreateTransferRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN UINTN TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ );
+
+/**
+ Check if there is a new generated event.
+
+ @param Xhc The XHCI device.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+XhcPeiCheckNewEvent (
+ IN PEI_XHC_DEV *Xhc,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ );
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI device.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+XhcPeiSyncEventRing (
+ IN PEI_XHC_DEV *Xhc,
+ IN EVENT_RING *EvtRing
+ );
+
+/**
+ Create XHCI event ring.
+
+ @param Xhc The XHCI device.
+ @param EventRing The created event ring.
+
+**/
+VOID
+XhcPeiCreateEventRing (
+ IN PEI_XHC_DEV *Xhc,
+ OUT EVENT_RING *EventRing
+ );
+
+/**
+ Initialize the XHCI host controller for schedule.
+
+ @param Xhc The XHCI device to be initialized.
+
+**/
+VOID
+XhcPeiInitSched (
+ IN PEI_XHC_DEV *Xhc
+ );
+
+/**
+ Free the resouce allocated at initializing schedule.
+
+ @param Xhc The XHCI device.
+
+**/
+VOID
+XhcPeiFreeSched (
+ IN PEI_XHC_DEV *Xhc
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ComponentName.c
new file mode 100644
index 000000000..e56eefee3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ComponentName.c
@@ -0,0 +1,171 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SCSI bus driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "ScsiBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gScsiBusComponentName = {
+ ScsiBusComponentNameGetDriverName,
+ ScsiBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gScsiBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ScsiBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ScsiBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mScsiBusDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"SCSI 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 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
+ScsiBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mScsiBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gScsiBusComponentName)
+ );
+}
+
+/**
+ 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
+ScsiBusComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
new file mode 100644
index 000000000..27b554ad3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
@@ -0,0 +1,1520 @@
+/** @file
+ SCSI Bus driver that layers on every SCSI Pass Thru and
+ Extended SCSI Pass Thru protocol in the system.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "ScsiBus.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
+ SCSIBusDriverBindingSupported,
+ SCSIBusDriverBindingStart,
+ SCSIBusDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+VOID *mWorkingBuffer;
+
+/**
+ Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
+
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
+ @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiioToPassThruPacket (
+ IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
+ OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
+ );
+
+/**
+ Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
+
+ @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
+
+**/
+EFI_STATUS
+EFIAPI
+PassThruToScsiioPacket (
+ IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
+ OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
+ );
+
+/**
+ Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
+ SCSI IO Packet.
+
+ @param Event The instance of EFI_EVENT.
+ @param Context The parameter passed in.
+
+**/
+VOID
+EFIAPI
+NotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Allocates an aligned buffer for SCSI device.
+
+ This function allocates an aligned buffer for the SCSI device to perform
+ SCSI pass through operations. The alignment requirement is from SCSI pass
+ through interface.
+
+ @param ScsiIoDevice The SCSI child device involved for the operation.
+ @param BufferSize The request buffer size.
+
+ @return A pointer to the aligned buffer or NULL if the allocation fails.
+
+**/
+VOID *
+AllocateAlignedBuffer (
+ IN SCSI_IO_DEV *ScsiIoDevice,
+ IN UINTN BufferSize
+ )
+{
+ return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);
+}
+
+/**
+ Frees an aligned buffer for SCSI device.
+
+ This function frees an aligned buffer for the SCSI device to perform
+ SCSI pass through operations.
+
+ @param Buffer The aligned buffer to be freed.
+ @param BufferSize The request buffer size.
+
+**/
+VOID
+FreeAlignedBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ if (Buffer != NULL) {
+ FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+}
+
+/**
+ The user Entry Point for module ScsiBus. The user code starts with this function.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeScsiBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSCSIBusDriverBinding,
+ ImageHandle,
+ &gScsiBusComponentName,
+ &gScsiBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Supported() it must also follow these calling
+ restrictions.
+
+ @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
+SCSIBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
+ UINT64 Lun;
+ UINT8 *TargetId;
+ SCSI_TARGET_ID ScsiTargetId;
+
+ TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
+
+ //
+ // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
+ // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
+ // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **)&ExtPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ } else if (!EFI_ERROR(Status)) {
+ //
+ // Check if RemainingDevicePath is NULL or the End of Device Path Node,
+ // if yes, return EFI_SUCCESS.
+ //
+ if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // Close protocol regardless of RemainingDevicePath validation
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node, check its validation
+ //
+ Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);
+ //
+ // Close protocol regardless of RemainingDevicePath validation
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (!EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Come here in 2 condition:
+ // 1. ExtPassThru doesn't exist.
+ // 2. ExtPassThru exists but RemainingDevicePath is invalid.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **)&PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Test RemainingDevicePath is valid or not.
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+
+/**
+ Start this driver on ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Start() it must also follow these calling
+ restrictions.
+
+ @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
+SCSIBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ UINT64 Lun;
+ UINT8 *TargetId;
+ BOOLEAN ScanOtherPuns;
+ BOOLEAN FromFirstTarget;
+ BOOLEAN ExtScsiSupport;
+ EFI_STATUS Status;
+ EFI_STATUS DevicePathStatus;
+ EFI_STATUS PassThruStatus;
+ SCSI_BUS_DEVICE *ScsiBusDev;
+ SCSI_TARGET_ID ScsiTargetId;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;
+ EFI_SCSI_BUS_PROTOCOL *BusIdentify;
+
+ TargetId = NULL;
+ ScanOtherPuns = TRUE;
+ FromFirstTarget = FALSE;
+ ExtScsiSupport = FALSE;
+ PassThruStatus = EFI_SUCCESS;
+
+ TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
+ SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
+
+ DevicePathStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {
+ return DevicePathStatus;
+ }
+
+ //
+ // Report Status Code to indicate SCSI bus starts
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ //
+ // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
+ // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
+ // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **) &ExtScsiInterface,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ //
+ // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
+ //
+ if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &ScsiInterface,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ //
+ // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
+ //
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ if (!EFI_ERROR(DevicePathStatus)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+ }
+ } else {
+ //
+ // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
+ // with BY_DRIVER if it is also present on the handle. The intent is to prevent
+ // another SCSI Bus Driver to work on the same host handle.
+ //
+ ExtScsiSupport = TRUE;
+ PassThruStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &ScsiInterface,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ //
+ // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
+ // on this handle for this time. Then construct Host controller private data.
+ //
+ ScsiBusDev = NULL;
+ ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));
+ if (ScsiBusDev == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;
+ ScsiBusDev->ExtScsiSupport = ExtScsiSupport;
+ ScsiBusDev->DevicePath = ParentDevicePath;
+ if (ScsiBusDev->ExtScsiSupport) {
+ ScsiBusDev->ExtScsiInterface = ExtScsiInterface;
+ } else {
+ ScsiBusDev->ScsiInterface = ScsiInterface;
+ }
+
+ //
+ // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
+ // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
+ // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ &ScsiBusDev->BusIdentify
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+ } else {
+ //
+ // Go through here means Start() is re-invoked again, nothing special is required to do except
+ // picking up Host controller private information.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &BusIdentify,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
+ }
+
+ //
+ // Report Status Code to indicate detecting devices on bus
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),
+ ParentDevicePath
+ );
+
+ Lun = 0;
+ if (RemainingDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is NULL,
+ // must enumerate all SCSI devices anyway
+ //
+ FromFirstTarget = TRUE;
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // only scan the specified device by RemainingDevicePath
+ //
+ if (ScsiBusDev->ExtScsiSupport) {
+ Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
+ } else {
+ Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCCESS
+ //
+ ScanOtherPuns = FALSE;
+ }
+
+ while(ScanOtherPuns) {
+ if (FromFirstTarget) {
+ //
+ // Remaining Device Path is NULL, scan all the possible Puns in the
+ // SCSI Channel.
+ //
+ if (ScsiBusDev->ExtScsiSupport) {
+ Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
+ } else {
+ Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // no legal Pun and Lun found any more
+ //
+ break;
+ }
+ } else {
+ ScanOtherPuns = FALSE;
+ }
+ //
+ // Avoid creating handle for the host adapter.
+ //
+ if (ScsiBusDev->ExtScsiSupport) {
+ if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
+ continue;
+ }
+ } else {
+ if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
+ continue;
+ }
+ }
+ //
+ // Scan for the scsi device, if it attaches to the scsi bus,
+ // then create handle and install scsi i/o protocol.
+ //
+ Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
+ }
+ return EFI_SUCCESS;
+
+ErrorExit:
+
+ if (ScsiBusDev != NULL) {
+ FreePool (ScsiBusDev);
+ }
+
+ if (ExtScsiSupport) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (!EFI_ERROR (PassThruStatus)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ This service is called by the EFI boot service DisconnectController().
+ In order to make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController() must follow these
+ calling restrictions. If any other agent wishes to call Stop() it must also
+ follow these calling restrictions.
+
+ @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
+SCSIBusDriverBindingStop (
+ 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_SCSI_IO_PROTOCOL *ScsiIo;
+ SCSI_IO_DEV *ScsiIoDevice;
+ VOID *ScsiPassThru;
+ EFI_SCSI_BUS_PROTOCOL *Scsidentifier;
+ SCSI_BUS_DEVICE *ScsiBusDev;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Get the SCSI_BUS_DEVICE
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Scsidentifier,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
+
+ //
+ // Uninstall SCSI Bus Protocol
+ //
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiCallerIdGuid,
+ &ScsiBusDev->BusIdentify
+ );
+
+ //
+ // Close the bus driver
+ //
+ if (ScsiBusDev->ExtScsiSupport) {
+ //
+ // Close ExtPassThru Protocol from this controller handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ //
+ // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
+ // Its intent is to prevent another SCSI Bus Driver from working on the same host handle.
+ // So Stop() needs to try to close PassThru if present here.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (ScsiBusDev);
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiScsiIoProtocolGuid,
+ (VOID **) &ScsiIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
+ //
+ // Close the child handle
+ //
+ if (ScsiIoDevice->ExtScsiSupport) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ } else {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ ScsiIoDevice->DevicePath,
+ &gEfiScsiIoProtocolGuid,
+ &ScsiIoDevice->ScsiIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ if (ScsiIoDevice->ExtScsiSupport) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ &ScsiPassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ &ScsiPassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+ } else {
+ FreePool (ScsiIoDevice);
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves the device type information of the SCSI Controller.
+
+ @param This Protocol instance pointer.
+ @param DeviceType A pointer to the device type information retrieved from
+ the SCSI Controller.
+
+ @retval EFI_SUCCESS Retrieves the device type information successfully.
+ @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceType (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ OUT UINT8 *DeviceType
+ )
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ if (DeviceType == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+ *DeviceType = ScsiIoDevice->ScsiDeviceType;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves the device location in the SCSI channel.
+
+ @param This Protocol instance pointer.
+ @param Target A pointer to the Target ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of the SCSI device on
+ the SCSI channel.
+
+ @retval EFI_SUCCESS Retrieves the device location successfully.
+ @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceLocation (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ )
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ if (Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
+
+ *Lun = ScsiIoDevice->Lun;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets the SCSI Bus that the SCSI Controller is attached to.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The SCSI bus is reset successfully.
+ @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
+ @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
+ SCSI Host Controller.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset
+ the SCSI bus.
+**/
+EFI_STATUS
+EFIAPI
+ScsiResetBus (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ )
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+ ScsiIoDevice->ScsiBusDeviceData->DevicePath
+ );
+
+ if (ScsiIoDevice->ExtScsiSupport){
+ return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
+ } else {
+ return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
+ }
+}
+
+
+/**
+ Resets the SCSI Controller that the device handle specifies.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Reset the SCSI controller successfully.
+ @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
+ @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
+ SCSI Controller.
+**/
+EFI_STATUS
+EFIAPI
+ScsiResetDevice (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ )
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+ UINT8 Target[TARGET_MAX_BYTES];
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+
+ //
+ // Report Status Code to indicate reset happens
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+ ScsiIoDevice->ScsiBusDeviceData->DevicePath
+ );
+
+ CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
+
+
+ if (ScsiIoDevice->ExtScsiSupport) {
+ return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
+ ScsiIoDevice->ExtScsiPassThru,
+ Target,
+ ScsiIoDevice->Lun
+ );
+ } else {
+ return ScsiIoDevice->ScsiPassThru->ResetTarget (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun.ScsiId.Scsi,
+ ScsiIoDevice->Lun
+ );
+ }
+}
+
+
+/**
+ Sends a SCSI Request Packet to the SCSI Controller for execution.
+
+ @param This Protocol instance pointer.
+ @param CommandPacket The SCSI request packet to send to the SCSI
+ Controller specified by the device handle.
+ @param Event If the SCSI bus where the SCSI device is attached
+ does not support non-blocking I/O, then Event is
+ ignored, and blocking I/O is performed.
+ If Event is NULL, then blocking I/O is performed.
+ If Event is not NULL and non-blocking I/O is
+ supported, then non-blocking I/O is performed,
+ and Event will be signaled when the SCSI Request
+ Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
+ successfully, and TransferLength bytes were
+ transferred to/from DataBuffer.See
+ HostAdapterStatus, TargetStatus,
+ SenseDataLength, and SenseData in that order
+ for additional status information.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
+ but the entire DataBuffer could not be transferred.
+ The actual number of bytes transferred is returned
+ in TransferLength. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
+ there are too many SCSI Command Packets already
+ queued.The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
+ the SCSI Request Packet. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
+ The SCSI Request Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
+ is not supported by the SCSI initiator(i.e., SCSI
+ Host Controller). The SCSI Request Packet was not
+ sent, so no additional status information is
+ available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
+ Request Packet to execute. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+**/
+EFI_STATUS
+EFIAPI
+ScsiExecuteSCSICommand (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ SCSI_IO_DEV *ScsiIoDevice;
+ EFI_STATUS Status;
+ UINT8 Target[TARGET_MAX_BYTES];
+ EFI_EVENT PacketEvent;
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;
+ SCSI_EVENT_DATA EventData;
+
+ PacketEvent = NULL;
+
+ if (Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
+ CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
+
+ if (ScsiIoDevice->ExtScsiSupport) {
+ ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
+
+ if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
+ Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
+ ScsiIoDevice->ExtScsiPassThru,
+ Target,
+ ScsiIoDevice->Lun,
+ ExtRequestPacket,
+ Event
+ );
+ } else {
+ //
+ // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
+ // let the 'Event' parameter for PassThru() be NULL.
+ //
+ Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
+ ScsiIoDevice->ExtScsiPassThru,
+ Target,
+ ScsiIoDevice->Lun,
+ ExtRequestPacket,
+ NULL
+ );
+ if ((!EFI_ERROR(Status)) && (Event != NULL)) {
+ //
+ // Signal Event to tell caller to pick up the SCSI IO packet if the
+ // PassThru() succeeds.
+ //
+ gBS->SignalEvent (Event);
+ }
+ }
+ } else {
+
+ mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
+
+ if (mWorkingBuffer == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
+ //
+ Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);
+ if (EFI_ERROR(Status)) {
+ FreePool(mWorkingBuffer);
+ return Status;
+ }
+
+ if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
+ EventData.Data1 = (VOID*)Packet;
+ EventData.Data2 = Event;
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ NotifyFunction,
+ &EventData,
+ &PacketEvent
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(mWorkingBuffer);
+ return Status;
+ }
+
+ Status = ScsiIoDevice->ScsiPassThru->PassThru (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun.ScsiId.Scsi,
+ ScsiIoDevice->Lun,
+ mWorkingBuffer,
+ PacketEvent
+ );
+
+ if (EFI_ERROR(Status)) {
+ FreePool(mWorkingBuffer);
+ gBS->CloseEvent(PacketEvent);
+ return Status;
+ }
+
+ } else {
+ //
+ // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
+ // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
+ //
+ Status = ScsiIoDevice->ScsiPassThru->PassThru (
+ ScsiIoDevice->ScsiPassThru,
+ ScsiIoDevice->Pun.ScsiId.Scsi,
+ ScsiIoDevice->Lun,
+ mWorkingBuffer,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(mWorkingBuffer);
+ return Status;
+ }
+
+ PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);
+ //
+ // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
+ // free mWorkingBuffer.
+ //
+ FreePool(mWorkingBuffer);
+
+ //
+ // Signal Event to tell caller to pick up the SCSI IO Packet.
+ //
+ if (Event != NULL) {
+ gBS->SignalEvent (Event);
+ }
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
+
+ @param This Protocol instance pointer
+ @param Controller Controller handle
+ @param TargetId Target to be scanned
+ @param Lun The Lun of the SCSI device on the SCSI channel.
+ @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
+
+ @retval EFI_SUCCESS Successfully to discover the device and attach
+ ScsiIoProtocol to it.
+ @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiScanCreateDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN SCSI_TARGET_ID *TargetId,
+ IN UINT64 Lun,
+ IN OUT SCSI_BUS_DEVICE *ScsiBusDev
+ )
+{
+ EFI_STATUS Status;
+ SCSI_IO_DEV *ScsiIoDevice;
+ EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+
+ DevicePath = NULL;
+ RemainingDevicePath = NULL;
+ ScsiDevicePath = NULL;
+ ScsiIoDevice = NULL;
+
+ //
+ // Build Device Path
+ //
+ if (ScsiBusDev->ExtScsiSupport){
+ Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
+ ScsiBusDev->ExtScsiInterface,
+ &TargetId->ScsiId.ExtScsi[0],
+ Lun,
+ &ScsiDevicePath
+ );
+ } else {
+ Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
+ ScsiBusDev->ScsiInterface,
+ TargetId->ScsiId.Scsi,
+ Lun,
+ &ScsiDevicePath
+ );
+ }
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DevicePath = AppendDevicePathNode (
+ ScsiBusDev->DevicePath,
+ ScsiDevicePath
+ );
+
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ //
+ // The device has been started, directly return to fast boot.
+ //
+ Status = EFI_ALREADY_STARTED;
+ goto ErrorExit;
+ }
+
+ ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
+ if (ScsiIoDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
+ ScsiIoDevice->ScsiBusDeviceData = ScsiBusDev;
+ CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
+ ScsiIoDevice->Lun = Lun;
+
+ if (ScsiBusDev->ExtScsiSupport) {
+ ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;
+ ScsiIoDevice->ExtScsiSupport = TRUE;
+ ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
+
+ } else {
+ ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;
+ ScsiIoDevice->ExtScsiSupport = FALSE;
+ ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
+ }
+
+ ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;
+ ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;
+ ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;
+ ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
+ ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
+
+ //
+ // Report Status Code here since the new SCSI device will be discovered
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),
+ ScsiBusDev->DevicePath
+ );
+
+ if (!DiscoverScsiDevice (ScsiIoDevice)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ ScsiIoDevice->DevicePath = DevicePath;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ScsiIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ ScsiIoDevice->DevicePath,
+ &gEfiScsiIoProtocolGuid,
+ &ScsiIoDevice->ScsiIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ } else {
+ if (ScsiBusDev->ExtScsiSupport) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **) &(ScsiBusDev->ExtScsiInterface),
+ This->DriverBindingHandle,
+ ScsiIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &(ScsiBusDev->ScsiInterface),
+ This->DriverBindingHandle,
+ ScsiIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+ }
+ return EFI_SUCCESS;
+
+ErrorExit:
+
+ //
+ // The memory space for ScsiDevicePath is allocated in
+ // ScsiPassThru->BuildDevicePath() function; It is no longer used
+ // after AppendDevicePathNode,so free the memory it occupies.
+ //
+ FreePool (ScsiDevicePath);
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+
+ if (ScsiIoDevice != NULL) {
+ FreePool (ScsiIoDevice);
+ }
+
+ return Status;
+}
+
+
+/**
+ Discovery SCSI Device
+
+ @param ScsiIoDevice The pointer of SCSI_IO_DEV
+
+ @retval TRUE Find SCSI Device and verify it.
+ @retval FALSE Unable to find SCSI Device.
+
+**/
+BOOLEAN
+DiscoverScsiDevice (
+ IN OUT SCSI_IO_DEV *ScsiIoDevice
+ )
+{
+ EFI_STATUS Status;
+ UINT32 InquiryDataLength;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ EFI_SCSI_INQUIRY_DATA *InquiryData;
+ EFI_SCSI_SENSE_DATA *SenseData;
+ UINT8 MaxRetry;
+ UINT8 Index;
+ BOOLEAN ScsiDeviceFound;
+
+ HostAdapterStatus = 0;
+ TargetStatus = 0;
+ SenseData = NULL;
+
+ InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
+ if (InquiryData == NULL) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
+ SenseData = AllocateAlignedBuffer (
+ ScsiIoDevice,
+ sizeof (EFI_SCSI_SENSE_DATA)
+ );
+ if (SenseData == NULL) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
+ //
+ // Using Inquiry command to scan for the device
+ //
+ InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
+ SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
+ ZeroMem (InquiryData, InquiryDataLength);
+ ZeroMem (SenseData, SenseDataLength);
+
+ MaxRetry = 2;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ Status = ScsiInquiryCommand (
+ &ScsiIoDevice->ScsiIo,
+ SCSI_BUS_TIMEOUT,
+ SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) InquiryData,
+ &InquiryDataLength,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&
+ (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&
+ (SenseData->Error_Code == 0x70) &&
+ (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST)) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+ break;
+ }
+ if ((Status == EFI_BAD_BUFFER_SIZE) ||
+ (Status == EFI_INVALID_PARAMETER) ||
+ (Status == EFI_UNSUPPORTED)) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+ }
+
+ if (Index == MaxRetry) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
+ //
+ // Retrieved inquiry data successfully
+ //
+ if (InquiryData->Peripheral_Qualifier != 0) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
+ if ((InquiryData->Peripheral_Type >= EFI_SCSI_TYPE_RESERVED_LOW) &&
+ (InquiryData->Peripheral_Type <= EFI_SCSI_TYPE_RESERVED_HIGH)) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
+ //
+ // valid device type and peripheral qualifier combination.
+ //
+ ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type;
+ ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
+ if (InquiryData->Version == 0) {
+ ScsiIoDevice->ScsiVersion = 0;
+ } else {
+ //
+ // ANSI-approved version
+ //
+ ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);
+ }
+
+ ScsiDeviceFound = TRUE;
+
+Done:
+ FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));
+ FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
+
+ return ScsiDeviceFound;
+}
+
+
+/**
+ Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
+
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
+ @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiioToPassThruPacket (
+ IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
+ OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
+ )
+{
+ //
+ //EFI 1.10 doesn't support Bi-Direction Command.
+ //
+ if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
+
+ CommandPacket->Timeout = Packet->Timeout;
+ CommandPacket->Cdb = Packet->Cdb;
+ CommandPacket->CdbLength = Packet->CdbLength;
+ CommandPacket->DataDirection = Packet->DataDirection;
+ CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
+ CommandPacket->TargetStatus = Packet->TargetStatus;
+ CommandPacket->SenseData = Packet->SenseData;
+ CommandPacket->SenseDataLength = Packet->SenseDataLength;
+
+ if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
+ CommandPacket->DataBuffer = Packet->InDataBuffer;
+ CommandPacket->TransferLength = Packet->InTransferLength;
+ } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
+ CommandPacket->DataBuffer = Packet->OutDataBuffer;
+ CommandPacket->TransferLength = Packet->OutTransferLength;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
+
+ @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
+ @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
+
+**/
+EFI_STATUS
+EFIAPI
+PassThruToScsiioPacket (
+ IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
+ OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ Packet->Timeout = ScsiPacket->Timeout;
+ Packet->Cdb = ScsiPacket->Cdb;
+ Packet->CdbLength = ScsiPacket->CdbLength;
+ Packet->DataDirection = ScsiPacket->DataDirection;
+ Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
+ Packet->TargetStatus = ScsiPacket->TargetStatus;
+ Packet->SenseData = ScsiPacket->SenseData;
+ Packet->SenseDataLength = ScsiPacket->SenseDataLength;
+
+ if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
+ Packet->InDataBuffer = ScsiPacket->DataBuffer;
+ Packet->InTransferLength = ScsiPacket->TransferLength;
+ } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
+ Packet->OutDataBuffer = ScsiPacket->DataBuffer;
+ Packet->OutTransferLength = ScsiPacket->TransferLength;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
+ SCSI IO Packet.
+
+ @param Event The instance of EFI_EVENT.
+ @param Context The parameter passed in.
+
+**/
+VOID
+EFIAPI
+NotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;
+ EFI_EVENT CallerEvent;
+ SCSI_EVENT_DATA *PassData;
+
+ PassData = (SCSI_EVENT_DATA*)Context;
+ Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
+ ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;
+
+ //
+ // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
+ //
+ PassThruToScsiioPacket(ScsiPacket, Packet);
+
+ //
+ // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
+ // free mWorkingBuffer.
+ //
+ gBS->FreePool(mWorkingBuffer);
+
+ //
+ // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
+ //
+ CallerEvent = PassData->Data2;
+ gBS->CloseEvent(Event);
+ gBS->SignalEvent(CallerEvent);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.h b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.h
new file mode 100644
index 000000000..97581866b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.h
@@ -0,0 +1,486 @@
+/** @file
+ Header file for SCSI Bus Driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SCSI_BUS_H_
+#define _SCSI_BUS_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/ScsiPassThru.h>
+#include <Protocol/ScsiPassThruExt.h>
+#include <Protocol/ScsiIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.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/UefiScsiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Scsi.h>
+
+#define SCSI_IO_DEV_SIGNATURE SIGNATURE_32 ('s', 'c', 'i', 'o')
+
+typedef union {
+ UINT32 Scsi;
+ UINT8 ExtScsi[4];
+} SCSI_ID;
+
+typedef struct _SCSI_TARGET_ID {
+ SCSI_ID ScsiId;
+ UINT8 ExtScsiId[12];
+}SCSI_TARGET_ID;
+
+
+typedef struct {
+ VOID *Data1;
+ VOID *Data2;
+} SCSI_EVENT_DATA;
+
+//
+// SCSI Bus Controller device structure
+//
+#define SCSI_BUS_DEVICE_SIGNATURE SIGNATURE_32 ('s', 'c', 's', 'i')
+
+//
+// SCSI Bus Timeout Experience Value
+//
+#define SCSI_BUS_TIMEOUT EFI_TIMER_PERIOD_SECONDS (3)
+
+//
+// The ScsiBusProtocol is just used to locate ScsiBusDev
+// structure in the SCSIBusDriverBindingStop(). Then we can
+// Close all opened protocols and release this structure.
+// ScsiBusProtocol is the private protocol.
+// gEfiCallerIdGuid will be used as its protocol guid.
+//
+typedef struct _EFI_SCSI_BUS_PROTOCOL {
+ UINT64 Reserved;
+} EFI_SCSI_BUS_PROTOCOL;
+
+typedef struct _SCSI_BUS_DEVICE {
+ UINTN Signature;
+ EFI_SCSI_BUS_PROTOCOL BusIdentify;
+ BOOLEAN ExtScsiSupport;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} SCSI_BUS_DEVICE;
+
+#define SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS(a) CR (a, SCSI_BUS_DEVICE, BusIdentify, SCSI_BUS_DEVICE_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_SCSI_IO_PROTOCOL ScsiIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN ExtScsiSupport;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
+ SCSI_BUS_DEVICE *ScsiBusDeviceData;
+ SCSI_TARGET_ID Pun;
+ UINT64 Lun;
+ UINT8 ScsiDeviceType;
+ UINT8 ScsiVersion;
+ BOOLEAN RemovableDevice;
+} SCSI_IO_DEV;
+
+#define SCSI_IO_DEV_FROM_THIS(a) CR (a, SCSI_IO_DEV, ScsiIo, SCSI_IO_DEV_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gScsiBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gScsiBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gScsiBusComponentName2;
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Supported() it must also follow these calling
+ restrictions.
+
+ @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
+SCSIBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Start() it must also follow these calling
+ restrictions.
+
+ @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
+SCSIBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ This service is called by the EFI boot service DisconnectController().
+ In order to make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController() must follow these
+ calling restrictions. If any other agent wishes to call Stop() it must also
+ follow these calling restrictions.
+
+ @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
+SCSIBusDriverBindingStop (
+ 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
+ScsiBusComponentNameGetDriverName (
+ 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
+ScsiBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Retrieves the device type information of the SCSI Controller.
+
+ @param This Protocol instance pointer.
+ @param DeviceType A pointer to the device type information retrieved from
+ the SCSI Controller.
+
+ @retval EFI_SUCCESS Retrieves the device type information successfully.
+ @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceType (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ OUT UINT8 *DeviceType
+ );
+
+/**
+ Retrieves the device location in the SCSI channel.
+
+ @param This Protocol instance pointer.
+ @param Target A pointer to the Target ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of the SCSI device on
+ the SCSI channel.
+
+ @retval EFI_SUCCESS Retrieves the device location successfully.
+ @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiGetDeviceLocation (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ );
+
+/**
+ Resets the SCSI Bus that the SCSI Controller is attached to.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The SCSI bus is reset successfully.
+ @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
+ @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
+ SCSI Host Controller.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset
+ the SCSI bus.
+**/
+EFI_STATUS
+EFIAPI
+ScsiResetBus (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ );
+
+/**
+ Resets the SCSI Controller that the device handle specifies.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Reset the SCSI controller successfully.
+ @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
+ @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
+ SCSI Controller.
+**/
+EFI_STATUS
+EFIAPI
+ScsiResetDevice (
+ IN EFI_SCSI_IO_PROTOCOL *This
+ );
+
+/**
+ Sends a SCSI Request Packet to the SCSI Controller for execution.
+
+ @param This Protocol instance pointer.
+ @param CommandPacket The SCSI request packet to send to the SCSI
+ Controller specified by the device handle.
+ @param Event If the SCSI bus where the SCSI device is attached
+ does not support non-blocking I/O, then Event is
+ ignored, and blocking I/O is performed.
+ If Event is NULL, then blocking I/O is performed.
+ If Event is not NULL and non-blocking I/O is
+ supported, then non-blocking I/O is performed,
+ and Event will be signaled when the SCSI Request
+ Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
+ successfully, and TransferLength bytes were
+ transferred to/from DataBuffer.See
+ HostAdapterStatus, TargetStatus,
+ SenseDataLength, and SenseData in that order
+ for additional status information.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
+ but the entire DataBuffer could not be transferred.
+ The actual number of bytes transferred is returned
+ in TransferLength. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
+ there are too many SCSI Command Packets already
+ queued.The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
+ the SCSI Request Packet. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+ @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
+ The SCSI Request Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
+ is not supported by the SCSI initiator(i.e., SCSI
+ Host Controller). The SCSI Request Packet was not
+ sent, so no additional status information is
+ available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
+ Request Packet to execute. See HostAdapterStatus,
+ TargetStatus, SenseDataLength, and SenseData in
+ that order for additional status information.
+**/
+EFI_STATUS
+EFIAPI
+ScsiExecuteSCSICommand (
+ IN EFI_SCSI_IO_PROTOCOL *This,
+ IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
+
+ @param This Protocol instance pointer
+ @param Controller Controller handle
+ @param TargetId Target to be scanned
+ @param Lun The Lun of the SCSI device on the SCSI channel.
+ @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
+
+ @retval EFI_SUCCESS Successfully to discover the device and attach
+ ScsiIoProtocol to it.
+ @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiScanCreateDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN SCSI_TARGET_ID *TargetId,
+ IN UINT64 Lun,
+ IN OUT SCSI_BUS_DEVICE *ScsiBusDev
+ );
+
+/**
+ Discovery SCSI Device
+
+ @param ScsiIoDevice The pointer of SCSI_IO_DEV
+
+ @retval TRUE Find SCSI Device and verify it.
+ @retval FALSE Unable to find SCSI Device.
+
+**/
+BOOLEAN
+DiscoverScsiDevice (
+ IN OUT SCSI_IO_DEV *ScsiIoDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.uni b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.uni
new file mode 100644
index 000000000..e384c82ea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The SCSI bus driver scans all SCSI devices and creates a device handle for each of them.
+//
+// Note that the driver will install the Device Path Protocol and SCSI I/O Protocol on
+// these handles.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Scans all SCSI devices; Creates a device handle for each device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note that the driver will install the Device Path Protocol and SCSI I/O Protocol on these handles."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
new file mode 100644
index 000000000..807ce1320
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# The SCSI bus driver scans all SCSI devices and creates a device handle for each of them.
+# Note that the driver will install the Device Path Protocol and SCSI I/O Protocol on
+# these handles.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ScsiBus
+ MODULE_UNI_FILE = ScsiBus.uni
+ FILE_GUID = 0167CCC4-D0F7-4f21-A3EF-9E64B7CDCE8B
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeScsiBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gSCSIBusDriverBinding
+# COMPONENT_NAME = gScsiBusComponentName
+# COMPONENT_NAME2 = gScsiBusComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ ScsiBus.c
+ ScsiBus.h
+
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ UefiScsiLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+
+
+[Protocols]
+ gEfiScsiIoProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+ gEfiScsiPassThruProtocolGuid ## TO_START
+ gEfiExtScsiPassThruProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ScsiBusExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusExtra.uni b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusExtra.uni
new file mode 100644
index 000000000..df8a2019a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ScsiBus Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SCSI Bus DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c
new file mode 100644
index 000000000..b193de9ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SCSI disk driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "ScsiDisk.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gScsiDiskComponentName = {
+ ScsiDiskComponentNameGetDriverName,
+ ScsiDiskComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gScsiDiskComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ScsiDiskComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ScsiDiskComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mScsiDiskDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"Scsi Disk 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
+ScsiDiskComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mScsiDiskDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gScsiDiskComponentName)
+ );
+}
+
+/**
+ 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
+ScsiDiskComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gScsiDiskDriverBinding.DriverBindingHandle,
+ &gEfiScsiIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gScsiDiskDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlockIo);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ScsiDiskDevice->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gScsiDiskComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
new file mode 100644
index 000000000..c80e78fa8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -0,0 +1,6327 @@
+/** @file
+ SCSI disk driver that layers on every SCSI IO protocol in the system.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "ScsiDisk.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
+ ScsiDiskDriverBindingSupported,
+ ScsiDiskDriverBindingStart,
+ ScsiDiskDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
+ EFI_DISK_INFO_SCSI_INTERFACE_GUID,
+ ScsiDiskInfoInquiry,
+ ScsiDiskInfoIdentify,
+ ScsiDiskInfoSenseData,
+ ScsiDiskInfoWhichIde
+};
+
+/**
+ Allocates an aligned buffer for SCSI disk.
+
+ This function allocates an aligned buffer for the SCSI disk to perform
+ SCSI IO operations. The alignment requirement is from SCSI IO interface.
+
+ @param ScsiDiskDevice The SCSI disk involved for the operation.
+ @param BufferSize The request buffer size.
+
+ @return A pointer to the aligned buffer or NULL if the allocation fails.
+
+**/
+VOID *
+AllocateAlignedBuffer (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINTN BufferSize
+ )
+{
+ return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
+}
+
+/**
+ Frees an aligned buffer for SCSI disk.
+
+ This function frees an aligned buffer for the SCSI disk to perform
+ SCSI IO operations.
+
+ @param Buffer The aligned buffer to be freed.
+ @param BufferSize The request buffer size.
+
+**/
+VOID
+FreeAlignedBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ if (Buffer != NULL) {
+ FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+}
+
+/**
+ The user Entry Point for module ScsiDisk.
+
+ The user code starts with this function.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeScsiDisk(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gScsiDiskDriverBinding,
+ ImageHandle,
+ &gScsiDiskComponentName,
+ &gScsiDiskComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions.
+ If any other agent wishes to call Supported() it must also follow these
+ calling restrictions.
+
+ @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
+ScsiDiskDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SCSI_IO_PROTOCOL *ScsiIo;
+ UINT8 DeviceType;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ (VOID **) &ScsiIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
+ if (!EFI_ERROR (Status)) {
+ if ((DeviceType == EFI_SCSI_TYPE_DISK) ||
+ (DeviceType == EFI_SCSI_TYPE_CDROM) ||
+ (DeviceType == EFI_SCSI_TYPE_WLUN)) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+
+/**
+ Start this driver on ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Start() it must also follow these calling
+ restrictions.
+
+ @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
+ScsiDiskDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SCSI_IO_PROTOCOL *ScsiIo;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ BOOLEAN Temp;
+ UINT8 Index;
+ UINT8 MaxRetry;
+ BOOLEAN NeedRetry;
+ BOOLEAN MustReadCapacity;
+
+ MustReadCapacity = TRUE;
+
+ ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
+ if (ScsiDiskDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ (VOID **) &ScsiIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (ScsiDiskDevice);
+ return Status;
+ }
+
+ ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
+ ScsiDiskDevice->ScsiIo = ScsiIo;
+ ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
+ ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
+ ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign;
+ ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
+ ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
+ ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
+ ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
+ ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;
+ ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;
+ ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;
+ ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
+ ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
+ ScsiDiskDevice->StorageSecurity.ReceiveData = ScsiDiskReceiveData;
+ ScsiDiskDevice->StorageSecurity.SendData = ScsiDiskSendData;
+ ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
+ ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
+ ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks;
+ ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt = 1;
+ ScsiDiskDevice->BlockLimitsVpdSupported = FALSE;
+ ScsiDiskDevice->Handle = Controller;
+ InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);
+
+ ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
+ switch (ScsiDiskDevice->DeviceType) {
+ case EFI_SCSI_TYPE_DISK:
+ ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
+ MustReadCapacity = TRUE;
+ break;
+
+ case EFI_SCSI_TYPE_CDROM:
+ ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
+ ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
+ MustReadCapacity = FALSE;
+ break;
+
+ case EFI_SCSI_TYPE_WLUN:
+ MustReadCapacity = FALSE;
+ break;
+ }
+ //
+ // The Sense Data Array's initial size is 6
+ //
+ ScsiDiskDevice->SenseDataNumber = 6;
+ ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
+ sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
+ );
+ if (ScsiDiskDevice->SenseData == NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (ScsiDiskDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Retrieve device information
+ //
+ MaxRetry = 2;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (!NeedRetry) {
+ FreePool (ScsiDiskDevice->SenseData);
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (ScsiDiskDevice);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // The second parameter "TRUE" means must
+ // retrieve media capacity
+ //
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Determine if Block IO & Block IO2 should be produced on this controller
+ // handle
+ //
+ if (DetermineInstallBlockIo (Controller)) {
+ InitializeInstallDiskInfo (ScsiDiskDevice, Controller);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &ScsiDiskDevice->DiskInfo,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiEraseBlockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &ScsiDiskDevice->EraseBlock
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));
+ }
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) {
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status));
+ }
+ }
+ ScsiDiskDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gScsiDiskComponentName.SupportedLanguages,
+ &ScsiDiskDevice->ControllerNameTable,
+ L"SCSI Disk Device",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gScsiDiskComponentName2.SupportedLanguages,
+ &ScsiDiskDevice->ControllerNameTable,
+ L"SCSI Disk Device",
+ FALSE
+ );
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ gBS->FreePool (ScsiDiskDevice->SenseData);
+ gBS->FreePool (ScsiDiskDevice);
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+
+}
+
+
+/**
+ Stop this driver on ControllerHandle.
+
+ This service is called by the EFI boot service DisconnectController().
+ In order to make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController() must follow these
+ calling restrictions. If any other agent wishes to call Stop() it must
+ also follow these calling restrictions.
+
+ @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
+ScsiDiskDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ EFI_ERASE_BLOCK_PROTOCOL *EraseBlock;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
+
+ //
+ // Wait for the BlockIo2 requests queue to become empty
+ //
+ while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
+
+ //
+ // If Erase Block Protocol is installed, then uninstall this protocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiEraseBlockProtocolGuid,
+ (VOID **) &EraseBlock,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &gEfiDiskInfoProtocolGuid,
+ &ScsiDiskDevice->DiskInfo,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiScsiIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // errors met
+ //
+ return Status;
+}
+
+/**
+ Reset SCSI Disk.
+
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+ @param ExtendedVerification The flag about if extend verificate
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_TPL OldTpl;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
+
+ Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_UNSUPPORTED) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+
+ if (!ExtendedVerification) {
+ goto Done;
+ }
+
+ Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The function is to Read Block from SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected
+ @param Lba The logic block address
+ @param BufferSize The size of Buffer
+ @param Buffer The buffer to fill the read out data
+
+ @retval EFI_SUCCESS Successfully to read out block.
+ @retval EFI_DEVICE_ERROR Fail to detect media.
+ @retval EFI_NO_MEDIA Media is not present.
+ @retval EFI_MEDIA_CHANGED Media has changed.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+ //
+ // Get the intrinsic block size
+ //
+ BlockSize = Media->BlockSize;
+
+ if (BlockSize == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ if (Lba > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // If all the parameters are valid, then perform read sectors command
+ // to transfer data from device to host.
+ //
+ Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The function is to Write Block to SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+ @param MediaId The Id of Media detected
+ @param Lba The logic block address
+ @param BufferSize The size of Buffer
+ @param Buffer The buffer to fill the read out data
+
+ @retval EFI_SUCCESS Successfully to read out block.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR Fail to detect media.
+ @retval EFI_NO_MEDIA Media is not present.
+ @retval EFI_MEDIA_CHANGED Media has changed.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+ //
+ // Get the intrinsic block size
+ //
+ BlockSize = Media->BlockSize;
+
+ if (BlockSize == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Media->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ if (Lba > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // if all the parameters are valid, then perform read sectors command
+ // to transfer data from device to host.
+ //
+ Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Flush Block to Disk.
+
+ EFI_SUCCESS is returned directly.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_TPL OldTpl;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
+
+ Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_UNSUPPORTED) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+
+ if (!ExtendedVerification) {
+ goto Done;
+ }
+
+ Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The function is to Read Block from SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected.
+ @param Lba The logic block address.
+ @param Token A pointer to the token associated with the transaction.
+ @param BufferSize The size of Buffer.
+ @param Buffer The buffer to fill the read out data.
+
+ @retval EFI_SUCCESS The read request was queued if Token-> Event is
+ not NULL. The data was read correctly from the
+ device if theToken-> Event is NULL.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+ //
+ // Get the intrinsic block size
+ //
+ BlockSize = Media->BlockSize;
+
+ if (BlockSize == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ if (Lba > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // If all the parameters are valid, then perform read sectors command
+ // to transfer data from device to host.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ Status = ScsiDiskAsyncReadSectors (
+ ScsiDiskDevice,
+ Buffer,
+ Lba,
+ NumberOfBlocks,
+ Token
+ );
+ } else {
+ Status = ScsiDiskReadSectors (
+ ScsiDiskDevice,
+ Buffer,
+ Lba,
+ NumberOfBlocks
+ );
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The function is to Write Block to SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected.
+ @param Lba The logic block address.
+ @param Token A pointer to the token associated with the transaction.
+ @param BufferSize The size of Buffer.
+ @param Buffer The buffer to fill the read out data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot 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
+ScsiDiskWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+ //
+ // Get the intrinsic block size
+ //
+ BlockSize = Media->BlockSize;
+
+ if (BlockSize == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Media->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ if (Lba > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // if all the parameters are valid, then perform write sectors command
+ // to transfer data from device to host.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ Status = ScsiDiskAsyncWriteSectors (
+ ScsiDiskDevice,
+ Buffer,
+ Lba,
+ NumberOfBlocks,
+ Token
+ );
+ } else {
+ Status = ScsiDiskWriteSectors (
+ ScsiDiskDevice,
+ Buffer,
+ Lba,
+ NumberOfBlocks
+ );
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to
+ write data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (Media->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+
+ //
+ // Wait for the BlockIo2 requests queue to become empty
+ //
+ while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Signal caller event
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Internal helper notify function which process the result of an asynchronous
+ SCSI UNMAP Command and signal the event passed from EraseBlocks.
+
+ @param Event The instance of EFI_EVENT.
+ @param Context The parameter passed in.
+
+**/
+VOID
+EFIAPI
+ScsiDiskAsyncUnmapNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ SCSI_ERASEBLK_REQUEST *EraseBlkReq;
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
+ EFI_ERASE_BLOCK_TOKEN *Token;
+ EFI_STATUS Status;
+
+ gBS->CloseEvent (Event);
+
+ EraseBlkReq = (SCSI_ERASEBLK_REQUEST *) Context;
+ CommandPacket = &EraseBlkReq->CommandPacket;
+ Token = EraseBlkReq->Token;
+ Token->TransactionStatus = EFI_SUCCESS;
+
+ Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
+ CommandPacket->HostAdapterStatus
+ ));
+
+ Token->TransactionStatus = Status;
+ goto Done;
+ }
+
+ Status = CheckTargetStatus (CommandPacket->TargetStatus);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
+ CommandPacket->HostAdapterStatus
+ ));
+
+ Token->TransactionStatus = Status;
+ goto Done;
+ }
+
+Done:
+ RemoveEntryList (&EraseBlkReq->Link);
+ FreePool (CommandPacket->OutDataBuffer);
+ FreePool (EraseBlkReq->CommandPacket.Cdb);
+ FreePool (EraseBlkReq);
+
+ gBS->SignalEvent (Token->Event);
+}
+
+/**
+ Require the device server to cause one or more LBAs to be unmapped.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Lba The start block number.
+ @param Blocks Total block number to be unmapped.
+ @param Token The pointer to the token associated with the
+ non-blocking erase block request.
+
+ @retval EFI_SUCCESS Target blocks have been successfully unmapped.
+ @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
+
+**/
+EFI_STATUS
+ScsiDiskUnmap (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Lba,
+ IN UINTN Blocks,
+ IN EFI_ERASE_BLOCK_TOKEN *Token OPTIONAL
+ )
+{
+ EFI_SCSI_IO_PROTOCOL *ScsiIo;
+ SCSI_ERASEBLK_REQUEST *EraseBlkReq;
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
+ EFI_SCSI_DISK_UNMAP_BLOCK_DESP *BlkDespPtr;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINT8 *Cdb;
+ UINT32 MaxLbaCnt;
+ UINT32 MaxBlkDespCnt;
+ UINT32 BlkDespCnt;
+ UINT16 UnmapParamListLen;
+ VOID *UnmapParamList;
+ EFI_EVENT AsyncUnmapEvent;
+ EFI_TPL OldTpl;
+
+ ScsiIo = ScsiDiskDevice->ScsiIo;
+ MaxLbaCnt = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;
+ MaxBlkDespCnt = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;
+ EraseBlkReq = NULL;
+ UnmapParamList = NULL;
+ AsyncUnmapEvent = NULL;
+ ReturnStatus = EFI_SUCCESS;
+
+ if (Blocks / (UINTN) MaxLbaCnt > MaxBlkDespCnt) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));
+ if (EraseBlkReq == NULL) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);
+ if (EraseBlkReq->CommandPacket.Cdb == NULL) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ BlkDespCnt = (UINT32) ((Blocks - 1) / MaxLbaCnt + 1);
+ UnmapParamListLen = (UINT16) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)
+ + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));
+ UnmapParamList = AllocateZeroPool (UnmapParamListLen);
+ if (UnmapParamList == NULL) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ *((UINT16 *)UnmapParamList) = SwapBytes16 (UnmapParamListLen - 2);
+ *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
+
+ BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
+ while (Blocks > 0) {
+ if (Blocks > MaxLbaCnt) {
+ *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
+ *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);
+ Blocks -= MaxLbaCnt;
+ Lba += MaxLbaCnt;
+ } else {
+ *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
+ *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32) Blocks);
+ Blocks = 0;
+ }
+
+ BlkDespPtr++;
+ }
+
+ CommandPacket = &EraseBlkReq->CommandPacket;
+ CommandPacket->Timeout = SCSI_DISK_TIMEOUT;
+ CommandPacket->OutDataBuffer = UnmapParamList;
+ CommandPacket->OutTransferLength = UnmapParamListLen;
+ CommandPacket->CdbLength = 0xA;
+ CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;
+ //
+ // Fill Cdb for UNMAP Command
+ //
+ Cdb = CommandPacket->Cdb;
+ Cdb[0] = EFI_SCSI_OP_UNMAP;
+ WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // Non-blocking UNMAP request
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ScsiDiskAsyncUnmapNotify,
+ EraseBlkReq,
+ &AsyncUnmapEvent
+ );
+ if (EFI_ERROR(Status)) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ EraseBlkReq->Token = Token;
+
+ Status = ScsiIo->ExecuteScsiCommand (
+ ScsiIo,
+ CommandPacket,
+ AsyncUnmapEvent
+ );
+ if (EFI_ERROR(Status)) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ goto Done;
+ } else {
+ //
+ // Directly return if the non-blocking UNMAP request is queued.
+ //
+ return EFI_SUCCESS;
+ }
+ } else {
+ //
+ // Blocking UNMAP request
+ //
+ Status = ScsiIo->ExecuteScsiCommand (
+ ScsiIo,
+ CommandPacket,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+
+ //
+ // Only blocking UNMAP request will reach here.
+ //
+ Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
+ CommandPacket->HostAdapterStatus
+ ));
+
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Status = CheckTargetStatus (CommandPacket->TargetStatus);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
+ CommandPacket->HostAdapterStatus
+ ));
+
+ ReturnStatus = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ if (EraseBlkReq != NULL) {
+ if (EraseBlkReq->CommandPacket.Cdb != NULL) {
+ FreePool (EraseBlkReq->CommandPacket.Cdb);
+ }
+ FreePool (EraseBlkReq);
+ }
+
+ if (UnmapParamList != NULL) {
+ FreePool (UnmapParamList);
+ }
+
+ if (AsyncUnmapEvent != NULL) {
+ gBS->CloseEvent (AsyncUnmapEvent);
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+
+ MediaChange = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);
+
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+ }
+ //
+ // Get the intrinsic block size
+ //
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Media->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+
+ if (Size == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((Size % BlockSize) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ NumberOfBlocks = Size / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);
+ } else {
+ Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT if the
+ time required to execute the receive data command is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId OPTIONAL,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ VOID *AlignedBuffer;
+ BOOLEAN AlignedBufferAllocated;
+
+ AlignedBuffer = NULL;
+ MediaChange = FALSE;
+ AlignedBufferAllocated = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+
+ if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+
+ //
+ // Validate Media
+ //
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if ((MediaId != 0) && (MediaId != Media->MediaId)) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (PayloadBufferSize != 0) {
+ if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
+ if (AlignedBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ ZeroMem (AlignedBuffer, PayloadBufferSize);
+ AlignedBufferAllocated = TRUE;
+ } else {
+ AlignedBuffer = PayloadBuffer;
+ }
+ }
+
+ Status = ScsiSecurityProtocolInCommand (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ FALSE,
+ PayloadBufferSize,
+ AlignedBuffer,
+ PayloadTransferSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (AlignedBufferAllocated) {
+ CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
+ }
+
+ if (PayloadBufferSize < *PayloadTransferSize) {
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ if (AlignedBufferAllocated) {
+ ZeroMem (AlignedBuffer, PayloadBufferSize);
+ FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
+ }
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT if the
+ time required to execute the receive data command is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskSendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId OPTIONAL,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ BOOLEAN MediaChange;
+ EFI_TPL OldTpl;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ VOID *AlignedBuffer;
+ BOOLEAN AlignedBufferAllocated;
+
+ AlignedBuffer = NULL;
+ MediaChange = FALSE;
+ AlignedBufferAllocated = FALSE;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
+ Media = ScsiDiskDevice->BlkIo.Media;
+
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+
+ if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &ScsiDiskDevice->BlkIo,
+ &ScsiDiskDevice->BlkIo
+ );
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiBlockIo2ProtocolGuid,
+ &ScsiDiskDevice->BlkIo2,
+ &ScsiDiskDevice->BlkIo2
+ );
+ if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiEraseBlockProtocolGuid,
+ &ScsiDiskDevice->EraseBlock,
+ &ScsiDiskDevice->EraseBlock
+ );
+ }
+ if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
+ gBS->ReinstallProtocolInterface (
+ ScsiDiskDevice->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &ScsiDiskDevice->StorageSecurity,
+ &ScsiDiskDevice->StorageSecurity
+ );
+ }
+ if (Media->MediaPresent) {
+ Status = EFI_MEDIA_CHANGED;
+ } else {
+ Status = EFI_NO_MEDIA;
+ }
+ goto Done;
+ }
+ }
+
+ //
+ // Validate Media
+ //
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if ((MediaId != 0) && (MediaId != Media->MediaId)) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Media->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+
+ if (PayloadBufferSize != 0) {
+ if (PayloadBuffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
+ if (AlignedBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
+ AlignedBufferAllocated = TRUE;
+ } else {
+ AlignedBuffer = PayloadBuffer;
+ }
+ }
+
+ Status = ScsiSecurityProtocolOutCommand (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ FALSE,
+ PayloadBufferSize,
+ AlignedBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ if (AlignedBufferAllocated) {
+ ZeroMem (AlignedBuffer, PayloadBufferSize);
+ FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
+ }
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Detect Device and read out capacity ,if error occurs, parse the sense key.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param MustReadCapacity The flag about reading device capacity
+ @param MediaChange The pointer of flag indicates if media has changed
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to detect media
+
+**/
+EFI_STATUS
+ScsiDiskDetectMedia (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN BOOLEAN MustReadCapacity,
+ OUT BOOLEAN *MediaChange
+ )
+{
+ EFI_STATUS Status;
+ EFI_SCSI_SENSE_DATA *SenseData;
+ UINTN NumberOfSenseKeys;
+ BOOLEAN NeedRetry;
+ BOOLEAN NeedReadCapacity;
+ UINT8 Retry;
+ UINT8 MaxRetry;
+ EFI_BLOCK_IO_MEDIA OldMedia;
+ UINTN Action;
+ EFI_EVENT TimeoutEvt;
+
+ Status = EFI_SUCCESS;
+ SenseData = NULL;
+ NumberOfSenseKeys = 0;
+ Retry = 0;
+ MaxRetry = 3;
+ Action = ACTION_NO_ACTION;
+ NeedReadCapacity = FALSE;
+ *MediaChange = FALSE;
+ TimeoutEvt = NULL;
+
+ CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvt
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Sending Test_Unit cmd to poll device status.
+ // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
+ // We limit the upper boundary to 120 seconds.
+ //
+ while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
+ Status = ScsiDiskTestUnitReady (
+ ScsiDiskDevice,
+ &NeedRetry,
+ &SenseData,
+ &NumberOfSenseKeys
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = DetectMediaParsingSenseKeys (
+ ScsiDiskDevice,
+ SenseData,
+ NumberOfSenseKeys,
+ &Action
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ } else if (Action == ACTION_RETRY_COMMAND_LATER) {
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ Retry++;
+ if (!NeedRetry || (Retry >= MaxRetry)) {
+ goto EXIT;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // ACTION_NO_ACTION: need not read capacity
+ // other action code: need read capacity
+ //
+ if (Action == ACTION_READ_CAPACITY) {
+ NeedReadCapacity = TRUE;
+ }
+
+ //
+ // READ_CAPACITY command is not supported by any of the UFS WLUNs.
+ //
+ if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
+ NeedReadCapacity = FALSE;
+ MustReadCapacity = FALSE;
+ ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
+ }
+
+ //
+ // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
+ // retrieve capacity via Read Capacity command
+ //
+ if (NeedReadCapacity || MustReadCapacity) {
+ //
+ // retrieve media information
+ //
+ for (Retry = 0; Retry < MaxRetry; Retry++) {
+ Status = ScsiDiskReadCapacity (
+ ScsiDiskDevice,
+ &NeedRetry,
+ &SenseData,
+ &NumberOfSenseKeys
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // analyze sense key to action
+ //
+ Status = DetectMediaParsingSenseKeys (
+ ScsiDiskDevice,
+ SenseData,
+ NumberOfSenseKeys,
+ &Action
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if Status is error, it may indicate crisis error,
+ // so return without retry.
+ //
+ goto EXIT;
+ } else if (Action == ACTION_RETRY_COMMAND_LATER) {
+ Retry = 0;
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ Retry++;
+ if (!NeedRetry || (Retry >= MaxRetry)) {
+ goto EXIT;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+ }
+
+ if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
+ //
+ // Media change information got from the device
+ //
+ *MediaChange = TRUE;
+ }
+
+ if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
+ *MediaChange = TRUE;
+ ScsiDiskDevice->BlkIo.Media->MediaId += 1;
+ }
+
+ if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
+ *MediaChange = TRUE;
+ ScsiDiskDevice->BlkIo.Media->MediaId += 1;
+ }
+
+ if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
+ *MediaChange = TRUE;
+ ScsiDiskDevice->BlkIo.Media->MediaId += 1;
+ }
+
+ if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
+ if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
+ //
+ // when change from no media to media present, reset the MediaId to 1.
+ //
+ ScsiDiskDevice->BlkIo.Media->MediaId = 1;
+ } else {
+ //
+ // when no media, reset the MediaId to zero.
+ //
+ ScsiDiskDevice->BlkIo.Media->MediaId = 0;
+ }
+
+ *MediaChange = TRUE;
+ }
+
+EXIT:
+ if (TimeoutEvt != NULL) {
+ gBS->CloseEvent (TimeoutEvt);
+ }
+ return Status;
+}
+
+
+/**
+ Send out Inquiry command to Device.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry Indicates if needs try again when error happens
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to detect media
+
+**/
+EFI_STATUS
+ScsiDiskInquiryDevice (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry
+ )
+{
+ UINT32 InquiryDataLength;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ EFI_SCSI_SENSE_DATA *SenseDataArray;
+ UINTN NumberOfSenseKeys;
+ EFI_STATUS Status;
+ UINT8 MaxRetry;
+ UINT8 Index;
+ EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
+ EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
+ UINTN PageLength;
+
+ InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
+ SenseDataLength = 0;
+
+ Status = ScsiInquiryCommand (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) &(ScsiDiskDevice->InquiryData),
+ &InquiryDataLength,
+ FALSE
+ );
+ //
+ // no need to check HostAdapterStatus and TargetStatus
+ //
+ if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
+ ParseInquiryData (ScsiDiskDevice);
+
+ if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
+ //
+ // Check whether the device supports Block Limits VPD page (0xB0)
+ //
+ SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
+ if (SupportedVpdPages == NULL) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
+ InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
+ SenseDataLength = 0;
+ Status = ScsiInquiryCommandEx (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) SupportedVpdPages,
+ &InquiryDataLength,
+ TRUE,
+ EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
+ );
+ if (!EFI_ERROR (Status)) {
+ PageLength = (SupportedVpdPages->PageLength2 << 8)
+ | SupportedVpdPages->PageLength1;
+
+ //
+ // Sanity checks for coping with broken devices
+ //
+ if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
+ DEBUG ((EFI_D_WARN,
+ "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
+ __FUNCTION__, (UINT32)PageLength));
+ PageLength = 0;
+ }
+
+ if ((PageLength > 0) &&
+ (SupportedVpdPages->SupportedVpdPageList[0] !=
+ EFI_SCSI_PAGE_CODE_SUPPORTED_VPD)) {
+ DEBUG ((EFI_D_WARN,
+ "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
+ __FUNCTION__, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD));
+ PageLength = 0;
+ }
+
+ //
+ // Locate the code for the Block Limits VPD page
+ //
+ for (Index = 0; Index < PageLength; Index++) {
+ //
+ // Sanity check
+ //
+ if ((Index > 0) &&
+ (SupportedVpdPages->SupportedVpdPageList[Index] <=
+ SupportedVpdPages->SupportedVpdPageList[Index - 1])) {
+ DEBUG ((EFI_D_WARN,
+ "%a: non-ascending code in Supported VPD Pages page @ %u\n",
+ __FUNCTION__, Index));
+ Index = 0;
+ PageLength = 0;
+ break;
+ }
+
+ if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
+ break;
+ }
+ }
+
+ //
+ // Query the Block Limits VPD page
+ //
+ if (Index < PageLength) {
+ BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
+ if (BlockLimits == NULL) {
+ FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
+ InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
+ SenseDataLength = 0;
+ Status = ScsiInquiryCommandEx (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) BlockLimits,
+ &InquiryDataLength,
+ TRUE,
+ EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
+ );
+ if (!EFI_ERROR (Status)) {
+ ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
+ (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
+ BlockLimits->OptimalTransferLengthGranularity1;
+
+ ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
+ (BlockLimits->MaximumUnmapLbaCount4 << 24) |
+ (BlockLimits->MaximumUnmapLbaCount3 << 16) |
+ (BlockLimits->MaximumUnmapLbaCount2 << 8) |
+ BlockLimits->MaximumUnmapLbaCount1;
+ ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
+ (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
+ (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
+ (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8) |
+ BlockLimits->MaximumUnmapBlockDescriptorCount1;
+ ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
+ (BlockLimits->OptimalUnmapGranularity4 << 24) |
+ (BlockLimits->OptimalUnmapGranularity3 << 16) |
+ (BlockLimits->OptimalUnmapGranularity2 << 8) |
+ BlockLimits->OptimalUnmapGranularity1;
+ if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
+ ScsiDiskDevice->UnmapInfo.GranularityAlignment =
+ (BlockLimits->UnmapGranularityAlignment4 << 24) |
+ (BlockLimits->UnmapGranularityAlignment3 << 16) |
+ (BlockLimits->UnmapGranularityAlignment2 << 8) |
+ BlockLimits->UnmapGranularityAlignment1;
+ }
+
+ if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
+ //
+ // A value of 0 indicates that the optimal unmap granularity is
+ // not reported.
+ //
+ ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
+ }
+
+ ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
+ }
+
+ FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
+ }
+ }
+
+ FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+
+ } else if (Status == EFI_NOT_READY) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
+ //
+
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // if goes here, meant ScsiInquiryCommand() failed.
+ // if ScsiDiskRequestSenseKeys() succeeds at last,
+ // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
+ //
+ MaxRetry = 3;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ Status = ScsiDiskRequestSenseKeys (
+ ScsiDiskDevice,
+ NeedRetry,
+ &SenseDataArray,
+ &NumberOfSenseKeys,
+ TRUE
+ );
+ if (!EFI_ERROR (Status)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!*NeedRetry) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
+ // set *NeedRetry = FALSE to avoid the outside caller try again.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ To test device.
+
+ When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
+ When Test Unit Ready command encounters any error caused by host adapter or
+ target, return error without retrieving Sense Keys.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates try again
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The pointer of the number of sense data array
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to test unit
+
+**/
+EFI_STATUS
+ScsiDiskTestUnitReady (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINT8 Index;
+ UINT8 MaxRetry;
+
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+ *NumberOfSenseKeys = 0;
+
+ //
+ // Parameter 3 and 4: do not require sense data, retrieve it when needed.
+ //
+ Status = ScsiTestUnitReadyCommand (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus
+ );
+ //
+ // no need to check HostAdapterStatus and TargetStatus
+ //
+ if (Status == EFI_NOT_READY) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
+ //
+
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (SenseDataLength != 0) {
+ *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
+ *SenseDataArray = ScsiDiskDevice->SenseData;
+ return EFI_SUCCESS;
+ }
+
+ MaxRetry = 3;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ Status = ScsiDiskRequestSenseKeys (
+ ScsiDiskDevice,
+ NeedRetry,
+ SenseDataArray,
+ NumberOfSenseKeys,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!*NeedRetry) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
+ // set *NeedRetry = FALSE to avoid the outside caller try again.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Parsing Sense Keys which got from request sense command.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param NumberOfSenseKeys The number of sense key
+ @param Action The pointer of action which indicates what is need to do next
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to complete the parsing
+
+**/
+EFI_STATUS
+DetectMediaParsingSenseKeys (
+ OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN NumberOfSenseKeys,
+ OUT UINTN *Action
+ )
+{
+ BOOLEAN RetryLater;
+
+ //
+ // Default is to read capacity, unless..
+ //
+ *Action = ACTION_READ_CAPACITY;
+
+ if (NumberOfSenseKeys == 0) {
+ if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
+ *Action = ACTION_NO_ACTION;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
+ //
+ // No Sense Key returned from last submitted command
+ //
+ if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
+ *Action = ACTION_NO_ACTION;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
+ ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
+ ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
+ *Action = ACTION_NO_ACTION;
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
+ ScsiDiskDevice->BlkIo.Media->MediaId++;
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
+ *Action = ACTION_RETRY_COMMAND_LATER;
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
+ if (RetryLater) {
+ *Action = ACTION_RETRY_COMMAND_LATER;
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
+ return EFI_SUCCESS;
+ }
+ *Action = ACTION_NO_ACTION;
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send read capacity command to device and get the device parameter.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates if need a retry
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The number of sense key
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
+
+**/
+EFI_STATUS
+ScsiDiskReadCapacity (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys
+ )
+{
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ EFI_STATUS CommandStatus;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 MaxRetry;
+ UINT8 SenseDataLength;
+ UINT32 DataLength10;
+ UINT32 DataLength16;
+ EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
+ EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
+
+ CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
+ if (CapacityData10 == NULL) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+ if (CapacityData16 == NULL) {
+ FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ SenseDataLength = 0;
+ DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
+ DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
+ ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
+ ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+
+ *NumberOfSenseKeys = 0;
+ *NeedRetry = FALSE;
+
+ //
+ // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
+ // 16 byte command should be used to access large hard disk >2TB
+ //
+ CommandStatus = ScsiReadCapacityCommand (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) CapacityData10,
+ &DataLength10,
+ FALSE
+ );
+
+ ScsiDiskDevice->Cdb16Byte = FALSE;
+ if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
+ (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
+ //
+ // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
+ //
+ ScsiDiskDevice->Cdb16Byte = TRUE;
+ //
+ // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
+ // and LowestAlignedLba
+ //
+ CommandStatus = ScsiReadCapacity16Command (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) CapacityData16,
+ &DataLength16,
+ FALSE
+ );
+ }
+
+ //
+ // no need to check HostAdapterStatus and TargetStatus
+ //
+ if (CommandStatus == EFI_SUCCESS) {
+ GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
+ FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
+ FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+ return EFI_SUCCESS;
+ }
+
+ FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
+ FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+
+ if (CommandStatus == EFI_NOT_READY) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // if goes here, meant ScsiReadCapacityCommand() failed.
+ // if ScsiDiskRequestSenseKeys() succeeds at last,
+ // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
+ //
+ MaxRetry = 3;
+ for (Index = 0; Index < MaxRetry; Index++) {
+
+ Status = ScsiDiskRequestSenseKeys (
+ ScsiDiskDevice,
+ NeedRetry,
+ SenseDataArray,
+ NumberOfSenseKeys,
+ TRUE
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!*NeedRetry) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
+ // set *NeedRetry = FALSE to avoid the outside caller try again.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Check the HostAdapter status and re-interpret it in EFI_STATUS.
+
+ @param HostAdapterStatus Host Adapter status
+
+ @retval EFI_SUCCESS Host adapter is OK.
+ @retval EFI_TIMEOUT Timeout.
+ @retval EFI_NOT_READY Adapter NOT ready.
+ @retval EFI_DEVICE_ERROR Adapter device error.
+
+**/
+EFI_STATUS
+CheckHostAdapterStatus (
+ IN UINT8 HostAdapterStatus
+ )
+{
+ switch (HostAdapterStatus) {
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
+ return EFI_SUCCESS;
+
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
+ return EFI_TIMEOUT;
+
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
+ return EFI_NOT_READY;
+
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
+ case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Check the target status and re-interpret it in EFI_STATUS.
+
+ @param TargetStatus Target status
+
+ @retval EFI_NOT_READY Device is NOT ready.
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CheckTargetStatus (
+ IN UINT8 TargetStatus
+ )
+{
+ switch (TargetStatus) {
+ case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
+ case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
+ case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
+ return EFI_SUCCESS;
+
+ case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
+ case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
+ case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
+ case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
+ return EFI_NOT_READY;
+
+ case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Retrieve all sense keys from the device.
+
+ When encountering error during the process, if retrieve sense keys before
+ error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
+ and NeedRetry set to FALSE; otherwise, return the proper return status.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates if need a retry
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The number of sense key
+ @param AskResetIfError The flag indicates if need reset when error occurs
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to request sense key
+
+**/
+EFI_STATUS
+ScsiDiskRequestSenseKeys (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys,
+ IN BOOLEAN AskResetIfError
+ )
+{
+ EFI_SCSI_SENSE_DATA *PtrSenseData;
+ UINT8 SenseDataLength;
+ BOOLEAN SenseReq;
+ EFI_STATUS Status;
+ EFI_STATUS FallStatus;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+
+ FallStatus = EFI_SUCCESS;
+ SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
+
+ ZeroMem (
+ ScsiDiskDevice->SenseData,
+ sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
+ );
+
+ *NumberOfSenseKeys = 0;
+ *SenseDataArray = ScsiDiskDevice->SenseData;
+ Status = EFI_SUCCESS;
+ PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
+ if (PtrSenseData == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (SenseReq = TRUE; SenseReq;) {
+ ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
+ Status = ScsiRequestSenseCommand (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ PtrSenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus
+ );
+ if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
+ FallStatus = EFI_SUCCESS;
+
+ } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ FallStatus = EFI_DEVICE_ERROR;
+
+ } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ FallStatus = EFI_DEVICE_ERROR;
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ if (AskResetIfError) {
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ }
+
+ FallStatus = EFI_DEVICE_ERROR;
+ }
+
+ if (EFI_ERROR (FallStatus)) {
+ if (*NumberOfSenseKeys != 0) {
+ *NeedRetry = FALSE;
+ Status = EFI_SUCCESS;
+ goto EXIT;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ goto EXIT;
+ }
+ }
+
+ CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
+ (*NumberOfSenseKeys) += 1;
+
+ //
+ // no more sense key or number of sense keys exceeds predefined,
+ // skip the loop.
+ //
+ if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
+ (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
+ SenseReq = FALSE;
+ }
+ }
+
+EXIT:
+ FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
+ return Status;
+}
+
+
+/**
+ Get information from media read capacity command.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
+ @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
+
+**/
+VOID
+GetMediaInfo (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
+ IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
+ )
+{
+ UINT8 *Ptr;
+
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ ScsiDiskDevice->BlkIo.Media->LastBlock = ((UINT32) Capacity10->LastLba3 << 24) |
+ (Capacity10->LastLba2 << 16) |
+ (Capacity10->LastLba1 << 8) |
+ Capacity10->LastLba0;
+
+ ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
+ (Capacity10->BlockSize2 << 16) |
+ (Capacity10->BlockSize1 << 8) |
+ Capacity10->BlockSize0;
+ ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
+ ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
+ if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
+ ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
+ }
+ } else {
+ Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
+ *Ptr++ = Capacity16->LastLba0;
+ *Ptr++ = Capacity16->LastLba1;
+ *Ptr++ = Capacity16->LastLba2;
+ *Ptr++ = Capacity16->LastLba3;
+ *Ptr++ = Capacity16->LastLba4;
+ *Ptr++ = Capacity16->LastLba5;
+ *Ptr++ = Capacity16->LastLba6;
+ *Ptr = Capacity16->LastLba7;
+
+ ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
+ (Capacity16->BlockSize2 << 16) |
+ (Capacity16->BlockSize1 << 8) |
+ Capacity16->BlockSize0;
+
+ ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
+ Capacity16->LowestAlignLogic1;
+ ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
+ if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
+ if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32) -1) {
+ ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) -1;
+ } else {
+ ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
+ }
+ }
+ }
+
+ ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
+}
+
+/**
+ Parse Inquiry data.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+
+**/
+VOID
+ParseInquiryData (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice
+ )
+{
+ ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
+ ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
+}
+
+/**
+ Read sector from SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Buffer The buffer to fill in the read out data
+ @param Lba Logic block address
+ @param NumberOfBlocks The number of blocks to read
+
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskReadSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ UINTN BlocksRemaining;
+ UINT8 *PtrBuffer;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT32 MaxBlock;
+ UINT32 SectorCount;
+ UINT32 NextSectorCount;
+ UINT64 Timeout;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 MaxRetry;
+ BOOLEAN NeedRetry;
+
+ Status = EFI_SUCCESS;
+
+ BlocksRemaining = NumberOfBlocks;
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ MaxBlock = 0xFFFF;
+ } else {
+ MaxBlock = 0xFFFFFFFF;
+ }
+
+ PtrBuffer = Buffer;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+ SectorCount = (UINT32) BlocksRemaining;
+ }
+ } else {
+ SectorCount = MaxBlock;
+ }
+
+ ByteCount = SectorCount * BlockSize;
+ //
+ // |------------------------|-----------------|------------------|-----------------|
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ //
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
+ // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
+ // From the above table, we could know 2.1Mbytes per second is lowest one.
+ // The timeout value is rounded up to nearest integer and here an additional 30s is added
+ // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
+ // commands in the Standby/Idle mode.
+ //
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
+
+ MaxRetry = 2;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskRead10 (
+ ScsiDiskDevice,
+ &NeedRetry,
+ Timeout,
+ PtrBuffer,
+ &ByteCount,
+ (UINT32) Lba,
+ SectorCount
+ );
+ } else {
+ Status = ScsiDiskRead16 (
+ ScsiDiskDevice,
+ &NeedRetry,
+ Timeout,
+ PtrBuffer,
+ &ByteCount,
+ Lba,
+ SectorCount
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (!NeedRetry) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
+ // lowered ByteCount on output, we must make sure that we lower
+ // SectorCount accordingly. SectorCount will be encoded in the CDB, and
+ // it is invalid to request more sectors in the CDB than the entire
+ // transfer (ie. ByteCount) can carry.
+ //
+ // In addition, ByteCount is only expected to go down, or stay unchanged.
+ // Therefore we don't need to update Timeout: the original timeout should
+ // accommodate shorter transfers too.
+ //
+ NextSectorCount = ByteCount / BlockSize;
+ if (NextSectorCount < SectorCount) {
+ SectorCount = NextSectorCount;
+ //
+ // Account for any rounding down.
+ //
+ ByteCount = SectorCount * BlockSize;
+ }
+ }
+
+ if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // actual transferred sectors
+ //
+ SectorCount = ByteCount / BlockSize;
+
+ Lba += SectorCount;
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write sector to SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Buffer The buffer of data to be written into SCSI Disk
+ @param Lba Logic block address
+ @param NumberOfBlocks The number of blocks to read
+
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskWriteSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ UINTN BlocksRemaining;
+ UINT8 *PtrBuffer;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT32 MaxBlock;
+ UINT32 SectorCount;
+ UINT32 NextSectorCount;
+ UINT64 Timeout;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 MaxRetry;
+ BOOLEAN NeedRetry;
+
+ Status = EFI_SUCCESS;
+
+ BlocksRemaining = NumberOfBlocks;
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ MaxBlock = 0xFFFF;
+ } else {
+ MaxBlock = 0xFFFFFFFF;
+ }
+
+ PtrBuffer = Buffer;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+ SectorCount = (UINT32) BlocksRemaining;
+ }
+ } else {
+ SectorCount = MaxBlock;
+ }
+
+ ByteCount = SectorCount * BlockSize;
+ //
+ // |------------------------|-----------------|------------------|-----------------|
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ //
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
+ // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
+ // From the above table, we could know 2.1Mbytes per second is lowest one.
+ // The timeout value is rounded up to nearest integer and here an additional 30s is added
+ // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
+ // commands in the Standby/Idle mode.
+ //
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
+ MaxRetry = 2;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskWrite10 (
+ ScsiDiskDevice,
+ &NeedRetry,
+ Timeout,
+ PtrBuffer,
+ &ByteCount,
+ (UINT32) Lba,
+ SectorCount
+ );
+ } else {
+ Status = ScsiDiskWrite16 (
+ ScsiDiskDevice,
+ &NeedRetry,
+ Timeout,
+ PtrBuffer,
+ &ByteCount,
+ Lba,
+ SectorCount
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (!NeedRetry) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
+ // has lowered ByteCount on output, we must make sure that we lower
+ // SectorCount accordingly. SectorCount will be encoded in the CDB, and
+ // it is invalid to request more sectors in the CDB than the entire
+ // transfer (ie. ByteCount) can carry.
+ //
+ // In addition, ByteCount is only expected to go down, or stay unchanged.
+ // Therefore we don't need to update Timeout: the original timeout should
+ // accommodate shorter transfers too.
+ //
+ NextSectorCount = ByteCount / BlockSize;
+ if (NextSectorCount < SectorCount) {
+ SectorCount = NextSectorCount;
+ //
+ // Account for any rounding down.
+ //
+ ByteCount = SectorCount * BlockSize;
+ }
+ }
+
+ if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // actual transferred sectors
+ //
+ SectorCount = ByteCount / BlockSize;
+
+ Lba += SectorCount;
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Asynchronously read sector from SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param Buffer The buffer to fill in the read out data.
+ @param Lba Logic block address.
+ @param NumberOfBlocks The number of blocks to read.
+ @param Token A pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskAsyncReadSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ UINTN BlocksRemaining;
+ UINT8 *PtrBuffer;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT32 MaxBlock;
+ UINT32 SectorCount;
+ UINT64 Timeout;
+ SCSI_BLKIO2_REQUEST *BlkIo2Req;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if ((Token == NULL) || (Token->Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
+ if (BlkIo2Req == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo2Req->Token = Token;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ InitializeListHead (&BlkIo2Req->ScsiRWQueue);
+
+ Status = EFI_SUCCESS;
+
+ BlocksRemaining = NumberOfBlocks;
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
+
+ //
+ // Limit the data bytes that can be transferred by one Read(10) or Read(16)
+ // Command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ MaxBlock = 0xFFFF;
+ } else {
+ MaxBlock = 0xFFFFFFFF;
+ }
+
+ PtrBuffer = Buffer;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+ SectorCount = (UINT32) BlocksRemaining;
+ }
+ } else {
+ SectorCount = MaxBlock;
+ }
+
+ ByteCount = SectorCount * BlockSize;
+ //
+ // |------------------------|-----------------|------------------|-----------------|
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ //
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
+ // we have to use the lowest transfer rate to calculate the possible
+ // maximum timeout value for each operation.
+ // From the above table, we could know 2.1Mbytes per second is lowest one.
+ // The timeout value is rounded up to nearest integer and here an additional
+ // 30s is added to follow ATA spec in which it mentioned that the device
+ // may take up to 30s to respond commands in the Standby/Idle mode.
+ //
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
+
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncRead10 (
+ ScsiDiskDevice,
+ Timeout,
+ 0,
+ PtrBuffer,
+ ByteCount,
+ (UINT32) Lba,
+ SectorCount,
+ BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncRead16 (
+ ScsiDiskDevice,
+ Timeout,
+ 0,
+ PtrBuffer,
+ ByteCount,
+ Lba,
+ SectorCount,
+ BlkIo2Req,
+ Token
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
+ // length of a SCSI I/O command is too large.
+ // In this case, we retry sending the SCSI command with a data length
+ // half of its previous value.
+ //
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+ if ((MaxBlock > 1) && (SectorCount > 1)) {
+ MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
+ continue;
+ }
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+ //
+ // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
+ // SCSI sub-task running. Otherwise, it will be freed in the callback
+ // function ScsiDiskNotify().
+ //
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ BlkIo2Req = NULL;
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // It is safe to return error status to the caller, since there is no
+ // previous SCSI sub-task executing.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ } else {
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // There are previous SCSI commands still running, EFI_SUCCESS should
+ // be returned to make sure that the caller does not free resources
+ // still using by these SCSI commands.
+ //
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // Sectors submitted for transfer
+ //
+ SectorCount = ByteCount / BlockSize;
+
+ Lba += SectorCount;
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (BlkIo2Req != NULL) {
+ BlkIo2Req->LastScsiRW = TRUE;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ BlkIo2Req = NULL;
+
+ gBS->SignalEvent (Token->Event);
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Status;
+}
+
+/**
+ Asynchronously write sector to SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param Buffer The buffer of data to be written into SCSI Disk.
+ @param Lba Logic block address.
+ @param NumberOfBlocks The number of blocks to read.
+ @param Token A pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWriteSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ UINTN BlocksRemaining;
+ UINT8 *PtrBuffer;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT32 MaxBlock;
+ UINT32 SectorCount;
+ UINT64 Timeout;
+ SCSI_BLKIO2_REQUEST *BlkIo2Req;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if ((Token == NULL) || (Token->Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
+ if (BlkIo2Req == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo2Req->Token = Token;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ InitializeListHead (&BlkIo2Req->ScsiRWQueue);
+
+ Status = EFI_SUCCESS;
+
+ BlocksRemaining = NumberOfBlocks;
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
+
+ //
+ // Limit the data bytes that can be transferred by one Read(10) or Read(16)
+ // Command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ MaxBlock = 0xFFFF;
+ } else {
+ MaxBlock = 0xFFFFFFFF;
+ }
+
+ PtrBuffer = Buffer;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+ SectorCount = (UINT32) BlocksRemaining;
+ }
+ } else {
+ SectorCount = MaxBlock;
+ }
+
+ ByteCount = SectorCount * BlockSize;
+ //
+ // |------------------------|-----------------|------------------|-----------------|
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
+ // |------------------------|-----------------|------------------|-----------------|
+ //
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
+ // we have to use the lowest transfer rate to calculate the possible
+ // maximum timeout value for each operation.
+ // From the above table, we could know 2.1Mbytes per second is lowest one.
+ // The timeout value is rounded up to nearest integer and here an additional
+ // 30s is added to follow ATA spec in which it mentioned that the device
+ // may take up to 30s to respond commands in the Standby/Idle mode.
+ //
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
+
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncWrite10 (
+ ScsiDiskDevice,
+ Timeout,
+ 0,
+ PtrBuffer,
+ ByteCount,
+ (UINT32) Lba,
+ SectorCount,
+ BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncWrite16 (
+ ScsiDiskDevice,
+ Timeout,
+ 0,
+ PtrBuffer,
+ ByteCount,
+ Lba,
+ SectorCount,
+ BlkIo2Req,
+ Token
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
+ // length of a SCSI I/O command is too large.
+ // In this case, we retry sending the SCSI command with a data length
+ // half of its previous value.
+ //
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+ if ((MaxBlock > 1) && (SectorCount > 1)) {
+ MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
+ continue;
+ }
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+ //
+ // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
+ // SCSI sub-task running. Otherwise, it will be freed in the callback
+ // function ScsiDiskNotify().
+ //
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ BlkIo2Req = NULL;
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // It is safe to return error status to the caller, since there is no
+ // previous SCSI sub-task executing.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ } else {
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // There are previous SCSI commands still running, EFI_SUCCESS should
+ // be returned to make sure that the caller does not free resources
+ // still using by these SCSI commands.
+ //
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // Sectors submitted for transfer
+ //
+ SectorCount = ByteCount / BlockSize;
+
+ Lba += SectorCount;
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (BlkIo2Req != NULL) {
+ BlkIo2Req->LastScsiRW = TRUE;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+ RemoveEntryList (&BlkIo2Req->Link);
+ FreePool (BlkIo2Req);
+ BlkIo2Req = NULL;
+
+ gBS->SignalEvent (Token->Event);
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Status;
+}
+
+
+/**
+ Submit Read(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to read
+
+ @return EFI_STATUS is returned by calling ScsiRead10Command().
+**/
+EFI_STATUS
+ScsiDiskRead10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ OUT UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount
+ )
+{
+ UINT8 SenseDataLength;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINTN Action;
+
+ //
+ // Implement a backoff algorithm to resolve some compatibility issues that
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
+ // big data in a single operation.
+ // This algorithm will at first try to execute original request. If the request fails
+ // with media error sense data or else, it will reduce the transfer length to half and
+ // try again till the operation succeeds or fails with one sector transfer length.
+ //
+BackOff:
+ *NeedRetry = FALSE;
+ Action = ACTION_NO_ACTION;
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+ ReturnStatus = ScsiRead10Command (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ DataBuffer,
+ DataLength,
+ StartLba,
+ SectorCount
+ );
+
+ if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return ReturnStatus;
+ }
+
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
+ DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
+ Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
+ if (Action == ACTION_RETRY_COMMAND_LATER) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
+ if (SectorCount <= 1) {
+ //
+ // Jump out if the operation still fails with one sector transfer length.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Try again with half length if the sense data shows we need to retry.
+ //
+ SectorCount >>= 1;
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
+ goto BackOff;
+ } else {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Submit Write(10) Command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to write
+
+ @return EFI_STATUS is returned by calling ScsiWrite10Command().
+
+**/
+EFI_STATUS
+ScsiDiskWrite10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ IN UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINTN Action;
+
+ //
+ // Implement a backoff algorithm to resolve some compatibility issues that
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
+ // big data in a single operation.
+ // This algorithm will at first try to execute original request. If the request fails
+ // with media error sense data or else, it will reduce the transfer length to half and
+ // try again till the operation succeeds or fails with one sector transfer length.
+ //
+BackOff:
+ *NeedRetry = FALSE;
+ Action = ACTION_NO_ACTION;
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+ ReturnStatus = ScsiWrite10Command (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ DataBuffer,
+ DataLength,
+ StartLba,
+ SectorCount
+ );
+ if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return ReturnStatus;
+ }
+
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
+ DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
+ Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
+ if (Action == ACTION_RETRY_COMMAND_LATER) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
+ if (SectorCount <= 1) {
+ //
+ // Jump out if the operation still fails with one sector transfer length.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Try again with half length if the sense data shows we need to retry.
+ //
+ SectorCount >>= 1;
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
+ goto BackOff;
+ } else {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Submit Read(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to read
+
+ @return EFI_STATUS is returned by calling ScsiRead16Command().
+**/
+EFI_STATUS
+ScsiDiskRead16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ OUT UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount
+ )
+{
+ UINT8 SenseDataLength;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINTN Action;
+
+ //
+ // Implement a backoff algorithm to resolve some compatibility issues that
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
+ // big data in a single operation.
+ // This algorithm will at first try to execute original request. If the request fails
+ // with media error sense data or else, it will reduce the transfer length to half and
+ // try again till the operation succeeds or fails with one sector transfer length.
+ //
+BackOff:
+ *NeedRetry = FALSE;
+ Action = ACTION_NO_ACTION;
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+ ReturnStatus = ScsiRead16Command (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ DataBuffer,
+ DataLength,
+ StartLba,
+ SectorCount
+ );
+ if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return ReturnStatus;
+ }
+
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
+ DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
+ Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
+ if (Action == ACTION_RETRY_COMMAND_LATER) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
+ if (SectorCount <= 1) {
+ //
+ // Jump out if the operation still fails with one sector transfer length.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Try again with half length if the sense data shows we need to retry.
+ //
+ SectorCount >>= 1;
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
+ goto BackOff;
+ } else {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Submit Write(16) Command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to write
+
+ @return EFI_STATUS is returned by calling ScsiWrite16Command().
+
+**/
+EFI_STATUS
+ScsiDiskWrite16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ IN UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINTN Action;
+
+ //
+ // Implement a backoff algorithm to resolve some compatibility issues that
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
+ // big data in a single operation.
+ // This algorithm will at first try to execute original request. If the request fails
+ // with media error sense data or else, it will reduce the transfer length to half and
+ // try again till the operation succeeds or fails with one sector transfer length.
+ //
+BackOff:
+ *NeedRetry = FALSE;
+ Action = ACTION_NO_ACTION;
+ SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
+ ReturnStatus = ScsiWrite16Command (
+ ScsiDiskDevice->ScsiIo,
+ Timeout,
+ ScsiDiskDevice->SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ DataBuffer,
+ DataLength,
+ StartLba,
+ SectorCount
+ );
+ if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
+ *NeedRetry = FALSE;
+ return ReturnStatus;
+ }
+
+ //
+ // go ahead to check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+ Status = CheckHostAdapterStatus (HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckTargetStatus (TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
+ DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
+ Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
+ if (Action == ACTION_RETRY_COMMAND_LATER) {
+ *NeedRetry = TRUE;
+ return EFI_DEVICE_ERROR;
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
+ if (SectorCount <= 1) {
+ //
+ // Jump out if the operation still fails with one sector transfer length.
+ //
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Try again with half length if the sense data shows we need to retry.
+ //
+ SectorCount >>= 1;
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
+ goto BackOff;
+ } else {
+ *NeedRetry = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Internal helper notify function in which determine whether retry of a SCSI
+ Read/Write command is needed and signal the event passed from Block I/O(2) if
+ the SCSI I/O operation completes.
+
+ @param Event The instance of EFI_EVENT.
+ @param Context The parameter passed in.
+
+**/
+VOID
+EFIAPI
+ScsiDiskNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ SCSI_ASYNC_RW_REQUEST *Request;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ EFI_BLOCK_IO2_TOKEN *Token;
+ UINTN Action;
+ UINT32 OldDataLength;
+ UINT32 OldSectorCount;
+ UINT8 MaxRetry;
+
+ gBS->CloseEvent (Event);
+
+ Request = (SCSI_ASYNC_RW_REQUEST *) Context;
+ ScsiDiskDevice = Request->ScsiDiskDevice;
+ Token = Request->BlkIo2Req->Token;
+ OldDataLength = Request->DataLength;
+ OldSectorCount = Request->SectorCount;
+ MaxRetry = 2;
+
+ //
+ // If previous sub-tasks already fails, no need to process this sub-task.
+ //
+ if (Token->TransactionStatus != EFI_SUCCESS) {
+ goto Exit;
+ }
+
+ //
+ // Check HostAdapterStatus and TargetStatus
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
+ //
+ Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
+ if (++Request->TimesRetry > MaxRetry) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ } else {
+ goto Retry;
+ }
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // reset the scsi channel
+ //
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = CheckTargetStatus (Request->TargetStatus);
+ if (Status == EFI_NOT_READY) {
+ //
+ // reset the scsi device
+ //
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
+ if (++Request->TimesRetry > MaxRetry) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ } else {
+ goto Retry;
+ }
+ } else if (Status == EFI_DEVICE_ERROR) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
+ DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
+
+ Status = DetectMediaParsingSenseKeys (
+ ScsiDiskDevice,
+ Request->SenseData,
+ Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
+ &Action
+ );
+ if (Action == ACTION_RETRY_COMMAND_LATER) {
+ if (++Request->TimesRetry > MaxRetry) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ } else {
+ goto Retry;
+ }
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
+ if (Request->SectorCount <= 1) {
+ //
+ // Jump out if the operation still fails with one sector transfer
+ // length.
+ //
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Try again with two half length request if the sense data shows we need
+ // to retry.
+ //
+ Request->SectorCount >>= 1;
+ Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
+ Request->TimesRetry = 0;
+
+ goto Retry;
+ } else {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+
+ //
+ // This sub-task succeeds, no need to retry.
+ //
+ goto Exit;
+
+Retry:
+ if (Request->InBuffer != NULL) {
+ //
+ // SCSI read command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncRead10 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ Request->TimesRetry,
+ Request->InBuffer,
+ Request->DataLength,
+ (UINT32) Request->StartLba,
+ Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncRead16 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ Request->TimesRetry,
+ Request->InBuffer,
+ Request->DataLength,
+ Request->StartLba,
+ Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ } else if (OldSectorCount != Request->SectorCount) {
+ //
+ // Original sub-task will be split into two new sub-tasks with smaller
+ // DataLength
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncRead10 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ 0,
+ Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
+ OldDataLength - Request->DataLength,
+ (UINT32) Request->StartLba + Request->SectorCount,
+ OldSectorCount - Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncRead16 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ 0,
+ Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
+ OldDataLength - Request->DataLength,
+ Request->StartLba + Request->SectorCount,
+ OldSectorCount - Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ } else {
+ //
+ // SCSI write command
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncWrite10 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ Request->TimesRetry,
+ Request->OutBuffer,
+ Request->DataLength,
+ (UINT32) Request->StartLba,
+ Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncWrite16 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ Request->TimesRetry,
+ Request->OutBuffer,
+ Request->DataLength,
+ Request->StartLba,
+ Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ } else if (OldSectorCount != Request->SectorCount) {
+ //
+ // Original sub-task will be split into two new sub-tasks with smaller
+ // DataLength
+ //
+ if (!ScsiDiskDevice->Cdb16Byte) {
+ Status = ScsiDiskAsyncWrite10 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ 0,
+ Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
+ OldDataLength - Request->DataLength,
+ (UINT32) Request->StartLba + Request->SectorCount,
+ OldSectorCount - Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ } else {
+ Status = ScsiDiskAsyncWrite16 (
+ ScsiDiskDevice,
+ Request->Timeout,
+ 0,
+ Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
+ OldDataLength - Request->DataLength,
+ Request->StartLba + Request->SectorCount,
+ OldSectorCount - Request->SectorCount,
+ Request->BlkIo2Req,
+ Token
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ Token->TransactionStatus = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ }
+
+Exit:
+ RemoveEntryList (&Request->Link);
+ if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
+ (Request->BlkIo2Req->LastScsiRW)) {
+ //
+ // The last SCSI R/W command of a BlockIo2 request completes
+ //
+ RemoveEntryList (&Request->BlkIo2Req->Link);
+ FreePool (Request->BlkIo2Req); // Should be freed only once
+ gBS->SignalEvent (Token->Event);
+ }
+
+ FreePool (Request->SenseData);
+ FreePool (Request);
+}
+
+
+/**
+ Submit Async Read(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer to fill with the read out data.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to read.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiRead10CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncRead10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ OUT UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ SCSI_ASYNC_RW_REQUEST *Request;
+ EFI_EVENT AsyncIoEvent;
+ EFI_TPL OldTpl;
+
+ AsyncIoEvent = NULL;
+
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
+ if (Request == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
+ if (Request->SenseData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Request->ScsiDiskDevice = ScsiDiskDevice;
+ Request->Timeout = Timeout;
+ Request->TimesRetry = TimesRetry;
+ Request->InBuffer = DataBuffer;
+ Request->DataLength = DataLength;
+ Request->StartLba = StartLba;
+ Request->SectorCount = SectorCount;
+ Request->BlkIo2Req = BlkIo2Req;
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ScsiDiskNotify,
+ Request,
+ &AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ Status = ScsiRead10CommandEx (
+ ScsiDiskDevice->ScsiIo,
+ Request->Timeout,
+ Request->SenseData,
+ &Request->SenseDataLength,
+ &Request->HostAdapterStatus,
+ &Request->TargetStatus,
+ Request->InBuffer,
+ &Request->DataLength,
+ (UINT32) Request->StartLba,
+ Request->SectorCount,
+ AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (AsyncIoEvent != NULL) {
+ gBS->CloseEvent (AsyncIoEvent);
+ }
+
+ if (Request != NULL) {
+ if (Request->SenseData != NULL) {
+ FreePool (Request->SenseData);
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (Request);
+ }
+
+ return Status;
+}
+
+
+/**
+ Submit Async Write(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer contains the data to write.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to write.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiWrite10CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWrite10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ IN UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ SCSI_ASYNC_RW_REQUEST *Request;
+ EFI_EVENT AsyncIoEvent;
+ EFI_TPL OldTpl;
+
+ AsyncIoEvent = NULL;
+
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
+ if (Request == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
+ if (Request->SenseData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Request->ScsiDiskDevice = ScsiDiskDevice;
+ Request->Timeout = Timeout;
+ Request->TimesRetry = TimesRetry;
+ Request->OutBuffer = DataBuffer;
+ Request->DataLength = DataLength;
+ Request->StartLba = StartLba;
+ Request->SectorCount = SectorCount;
+ Request->BlkIo2Req = BlkIo2Req;
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ScsiDiskNotify,
+ Request,
+ &AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ Status = ScsiWrite10CommandEx (
+ ScsiDiskDevice->ScsiIo,
+ Request->Timeout,
+ Request->SenseData,
+ &Request->SenseDataLength,
+ &Request->HostAdapterStatus,
+ &Request->TargetStatus,
+ Request->OutBuffer,
+ &Request->DataLength,
+ (UINT32) Request->StartLba,
+ Request->SectorCount,
+ AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (AsyncIoEvent != NULL) {
+ gBS->CloseEvent (AsyncIoEvent);
+ }
+
+ if (Request != NULL) {
+ if (Request->SenseData != NULL) {
+ FreePool (Request->SenseData);
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (Request);
+ }
+
+ return Status;
+}
+
+
+/**
+ Submit Async Read(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer to fill with the read out data.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to read.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiRead16CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncRead16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ OUT UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ SCSI_ASYNC_RW_REQUEST *Request;
+ EFI_EVENT AsyncIoEvent;
+ EFI_TPL OldTpl;
+
+ AsyncIoEvent = NULL;
+
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
+ if (Request == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
+ if (Request->SenseData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Request->ScsiDiskDevice = ScsiDiskDevice;
+ Request->Timeout = Timeout;
+ Request->TimesRetry = TimesRetry;
+ Request->InBuffer = DataBuffer;
+ Request->DataLength = DataLength;
+ Request->StartLba = StartLba;
+ Request->SectorCount = SectorCount;
+ Request->BlkIo2Req = BlkIo2Req;
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ScsiDiskNotify,
+ Request,
+ &AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ Status = ScsiRead16CommandEx (
+ ScsiDiskDevice->ScsiIo,
+ Request->Timeout,
+ Request->SenseData,
+ &Request->SenseDataLength,
+ &Request->HostAdapterStatus,
+ &Request->TargetStatus,
+ Request->InBuffer,
+ &Request->DataLength,
+ Request->StartLba,
+ Request->SectorCount,
+ AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (AsyncIoEvent != NULL) {
+ gBS->CloseEvent (AsyncIoEvent);
+ }
+
+ if (Request != NULL) {
+ if (Request->SenseData != NULL) {
+ FreePool (Request->SenseData);
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (Request);
+ }
+
+ return Status;
+}
+
+
+/**
+ Submit Async Write(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer contains the data to write.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to write.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiWrite16CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWrite16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ IN UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ SCSI_ASYNC_RW_REQUEST *Request;
+ EFI_EVENT AsyncIoEvent;
+ EFI_TPL OldTpl;
+
+ AsyncIoEvent = NULL;
+
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
+ if (Request == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
+ if (Request->SenseData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ Request->ScsiDiskDevice = ScsiDiskDevice;
+ Request->Timeout = Timeout;
+ Request->TimesRetry = TimesRetry;
+ Request->OutBuffer = DataBuffer;
+ Request->DataLength = DataLength;
+ Request->StartLba = StartLba;
+ Request->SectorCount = SectorCount;
+ Request->BlkIo2Req = BlkIo2Req;
+
+ //
+ // Create Event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ScsiDiskNotify,
+ Request,
+ &AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ Status = ScsiWrite16CommandEx (
+ ScsiDiskDevice->ScsiIo,
+ Request->Timeout,
+ Request->SenseData,
+ &Request->SenseDataLength,
+ &Request->HostAdapterStatus,
+ &Request->TargetStatus,
+ Request->OutBuffer,
+ &Request->DataLength,
+ Request->StartLba,
+ Request->SectorCount,
+ AsyncIoEvent
+ );
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (AsyncIoEvent != NULL) {
+ gBS->CloseEvent (AsyncIoEvent);
+ }
+
+ if (Request != NULL) {
+ if (Request->SenseData != NULL) {
+ FreePool (Request->SenseData);
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&Request->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (Request);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check sense key to find if media presents.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE NOT any media
+ @retval FALSE Media presents
+**/
+BOOLEAN
+ScsiDiskIsNoMedia (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsNoMedia;
+
+ IsNoMedia = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
+ // Additional Sense Code is ASC_NO_MEDIA (0x3A)
+ //
+ if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
+ (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
+ IsNoMedia = TRUE;
+ }
+ SensePtr++;
+ }
+
+ return IsNoMedia;
+}
+
+
+/**
+ Parse sense key.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Error
+ @retval FALSE NOT error
+
+**/
+BOOLEAN
+ScsiDiskIsMediaError (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsError;
+
+ IsError = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->Sense_Key) {
+
+ case EFI_SCSI_SK_MEDIUM_ERROR:
+ //
+ // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
+ //
+ switch (SensePtr->Addnl_Sense_Code) {
+
+ //
+ // fall through
+ //
+ case EFI_SCSI_ASC_MEDIA_ERR1:
+
+ //
+ // fall through
+ //
+ case EFI_SCSI_ASC_MEDIA_ERR2:
+
+ //
+ // fall through
+ //
+ case EFI_SCSI_ASC_MEDIA_ERR3:
+ case EFI_SCSI_ASC_MEDIA_ERR4:
+ IsError = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case EFI_SCSI_SK_NOT_READY:
+ //
+ // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
+ //
+ switch (SensePtr->Addnl_Sense_Code) {
+ //
+ // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
+ //
+ case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
+ IsError = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return IsError;
+}
+
+
+/**
+ Check sense key to find if hardware error happens.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Hardware error exits.
+ @retval FALSE NO error.
+
+**/
+BOOLEAN
+ScsiDiskIsHardwareError (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsError;
+
+ IsError = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ //
+ // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
+ //
+ if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
+ IsError = TRUE;
+ }
+
+ SensePtr++;
+ }
+
+ return IsError;
+}
+
+
+/**
+ Check sense key to find if media has changed.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Media is changed.
+ @retval FALSE Media is NOT changed.
+**/
+BOOLEAN
+ScsiDiskIsMediaChange (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsMediaChanged;
+
+ IsMediaChanged = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
+ // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
+ //
+ if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
+ (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
+ IsMediaChanged = TRUE;
+ }
+
+ SensePtr++;
+ }
+
+ return IsMediaChanged;
+}
+
+/**
+ Check sense key to find if reset happens.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE It is reset before.
+ @retval FALSE It is NOT reset before.
+
+**/
+BOOLEAN
+ScsiDiskIsResetBefore (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsResetBefore;
+
+ IsResetBefore = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ //
+ // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
+ // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
+ //
+ if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
+ (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
+ IsResetBefore = TRUE;
+ }
+
+ SensePtr++;
+ }
+
+ return IsResetBefore;
+}
+
+/**
+ Check sense key to find if the drive is ready.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+ @param RetryLater The flag means if need a retry
+
+ @retval TRUE Drive is ready.
+ @retval FALSE Drive is NOT ready.
+
+**/
+BOOLEAN
+ScsiDiskIsDriveReady (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *RetryLater
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN IsReady;
+
+ IsReady = TRUE;
+ *RetryLater = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->Sense_Key) {
+
+ case EFI_SCSI_SK_NOT_READY:
+ //
+ // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
+ //
+ switch (SensePtr->Addnl_Sense_Code) {
+ case EFI_SCSI_ASC_NOT_READY:
+ //
+ // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
+ //
+ switch (SensePtr->Addnl_Sense_Code_Qualifier) {
+ case EFI_SCSI_ASCQ_IN_PROGRESS:
+ //
+ // Additional Sense Code Qualifier is
+ // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
+ //
+ IsReady = FALSE;
+ *RetryLater = TRUE;
+ break;
+
+ default:
+ IsReady = FALSE;
+ *RetryLater = FALSE;
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return IsReady;
+}
+
+/**
+ Check sense key to find if it has sense key.
+
+ @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts - The number of sense key
+
+ @retval TRUE It has sense key.
+ @retval FALSE It has NOT any sense key.
+
+**/
+BOOLEAN
+ScsiDiskHaveSenseKey (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ EFI_SCSI_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN HaveSenseKey;
+
+ if (SenseCounts == 0) {
+ HaveSenseKey = FALSE;
+ } else {
+ HaveSenseKey = TRUE;
+ }
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ //
+ // Sense Key is SK_NO_SENSE (0x0)
+ //
+ if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
+ (Index == 0)) {
+ HaveSenseKey = FALSE;
+ }
+
+ SensePtr++;
+ }
+
+ return HaveSenseKey;
+}
+
+/**
+ Release resource about disk device.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+
+**/
+VOID
+ReleaseScsiDiskDeviceResources (
+ IN SCSI_DISK_DEV *ScsiDiskDevice
+ )
+{
+ if (ScsiDiskDevice == NULL) {
+ return ;
+ }
+
+ if (ScsiDiskDevice->SenseData != NULL) {
+ FreePool (ScsiDiskDevice->SenseData);
+ ScsiDiskDevice->SenseData = NULL;
+ }
+
+ if (ScsiDiskDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
+ ScsiDiskDevice->ControllerNameTable = NULL;
+ }
+
+ FreePool (ScsiDiskDevice);
+
+ ScsiDiskDevice = NULL;
+}
+
+/**
+ Determine if Block Io & Block Io2 should be produced.
+
+
+ @param ChildHandle Child Handle to retrieve Parent information.
+
+ @retval TRUE Should produce Block Io & Block Io2.
+ @retval FALSE Should not produce Block Io & Block Io2.
+
+**/
+BOOLEAN
+DetermineInstallBlockIo (
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
+
+ //
+ // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
+ // check its attribute, logic or physical.
+ //
+ ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
+ if (ExtScsiPassThru != NULL) {
+ if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
+ return TRUE;
+ }
+ }
+
+ //
+ // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
+ // check its attribute, logic or physical.
+ //
+ ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
+ if (ScsiPassThru != NULL) {
+ if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Search protocol database and check to see if the protocol
+ specified by ProtocolGuid is present on a ControllerHandle and opened by
+ ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+ If the ControllerHandle is found, then the protocol specified by ProtocolGuid
+ will be opened on it.
+
+
+ @param ProtocolGuid ProtocolGuid pointer.
+ @param ChildHandle Child Handle to retrieve Parent information.
+
+**/
+VOID *
+EFIAPI
+GetParentProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ UINTN Index;
+ UINTN HandleCount;
+ VOID *Interface;
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+
+ //
+ // Retrieve the list of all handles from the handle database
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
+ if (!EFI_ERROR (Status)) {
+ gBS->FreePool (HandleBuffer);
+ return Interface;
+ }
+ }
+ }
+
+ gBS->FreePool (HandleBuffer);
+ return NULL;
+}
+
+/**
+ Determine if EFI Erase Block Protocol should be produced.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Handle of device.
+
+ @retval TRUE Should produce EFI Erase Block Protocol.
+ @retval FALSE Should not produce EFI Erase Block Protocol.
+
+**/
+BOOLEAN
+DetermineInstallEraseBlock (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ EFI_STATUS CommandStatus;
+ EFI_STATUS Status;
+ BOOLEAN UfsDevice;
+ BOOLEAN RetVal;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ UINT8 SenseDataLength;
+ UINT32 DataLength16;
+ EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
+
+ UfsDevice = FALSE;
+ RetVal = TRUE;
+ CapacityData16 = NULL;
+
+ //
+ // UNMAP command is not supported by any of the UFS WLUNs.
+ //
+ if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
+ RetVal = FALSE;
+ goto Done;
+ }
+
+ Status = gBS->HandleProtocol (
+ ChildHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePathNode
+ );
+ //
+ // Device Path protocol must be installed on the device handle.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ while (!IsDevicePathEndType (DevicePathNode)) {
+ //
+ // For now, only support Erase Block Protocol on UFS devices.
+ //
+ if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
+ (DevicePathNode->SubType == MSG_UFS_DP)) {
+ UfsDevice = TRUE;
+ break;
+ }
+
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ if (!UfsDevice) {
+ RetVal = FALSE;
+ goto Done;
+ }
+
+ //
+ // Check whether the erase functionality is enabled on the UFS device.
+ //
+ CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+ if (CapacityData16 == NULL) {
+ RetVal = FALSE;
+ goto Done;
+ }
+
+ SenseDataLength = 0;
+ DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
+ ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+
+ CommandStatus = ScsiReadCapacity16Command (
+ ScsiDiskDevice->ScsiIo,
+ SCSI_DISK_TIMEOUT,
+ NULL,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) CapacityData16,
+ &DataLength16,
+ FALSE
+ );
+
+ if (CommandStatus == EFI_SUCCESS) {
+ //
+ // Universal Flash Storage (UFS) Version 2.0
+ // Section 11.3.9.2
+ // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
+ //
+ if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
+ ((CapacityData16->LowestAlignLogic2 & BIT6) == 0)) {
+ DEBUG ((
+ EFI_D_VERBOSE,
+ "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
+ CapacityData16->LowestAlignLogic2
+ ));
+
+ RetVal = FALSE;
+ goto Done;
+ }
+ } else {
+ DEBUG ((
+ EFI_D_VERBOSE,
+ "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
+ CommandStatus
+ ));
+
+ RetVal = FALSE;
+ goto Done;
+ }
+
+ //
+ // Check whether the UFS device server implements the UNMAP command.
+ //
+ if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
+ (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0)) {
+ DEBUG ((
+ EFI_D_VERBOSE,
+ "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
+ ));
+
+ RetVal = FALSE;
+ goto Done;
+ }
+
+Done:
+ if (CapacityData16 != NULL) {
+ FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
+ }
+
+ return RetVal;
+}
+
+/**
+ Determine if EFI Storage Security Command Protocol should be produced.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Handle of device.
+
+ @retval TRUE Should produce EFI Storage Security Command Protocol.
+ @retval FALSE Should not produce EFI Storage Security Command Protocol.
+
+**/
+BOOLEAN
+DetermineInstallStorageSecurity (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ UFS_DEVICE_PATH *UfsDevice;
+ BOOLEAN RetVal;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+
+ UfsDevice = NULL;
+ RetVal = TRUE;
+
+ Status = gBS->HandleProtocol (
+ ChildHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePathNode
+ );
+ //
+ // Device Path protocol must be installed on the device handle.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ while (!IsDevicePathEndType (DevicePathNode)) {
+ //
+ // For now, only support Storage Security Command Protocol on UFS devices.
+ //
+ if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
+ (DevicePathNode->SubType == MSG_UFS_DP)) {
+ UfsDevice = (UFS_DEVICE_PATH *) DevicePathNode;
+ break;
+ }
+
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ if (UfsDevice == NULL) {
+ RetVal = FALSE;
+ goto Done;
+ }
+
+ if (UfsDevice->Lun != UFS_WLUN_RPMB) {
+ RetVal = FALSE;
+ }
+
+Done:
+ return RetVal;
+}
+
+/**
+ Provides inquiry information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
+ }
+ *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
+ return Status;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+ScsiDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ EFI_STATUS Status;
+ SCSI_DISK_DEV *ScsiDiskDevice;
+
+ if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
+ //
+ // Physical SCSI bus does not support this data class.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
+ }
+ *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
+ return Status;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskInfoSenseData (
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+ScsiDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ SCSI_DISK_DEV *ScsiDiskDevice;
+
+ if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
+ //
+ // This is not an IDE physical device.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
+ *IdeChannel = ScsiDiskDevice->Channel;
+ *IdeDevice = ScsiDiskDevice->Device;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
+
+ This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
+ implement Identify() interface for DiskInfo protocol. The ATA command is sent
+ via SCSI Request Packet.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+
+ @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
+ @retval others Some error occurred during the identification that ATAPI device.
+
+**/
+EFI_STATUS
+AtapiIdentifyDevice (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice
+ )
+{
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
+ UINT8 Cdb[6];
+
+ //
+ // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
+ //
+ ZeroMem (&CommandPacket, sizeof (CommandPacket));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
+ CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
+ CommandPacket.Cdb = Cdb;
+ CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
+ CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
+ CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
+
+ return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
+}
+
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
+ detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
+ to be IDE/AHCI interface GUID.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Child handle to install DiskInfo protocol.
+
+**/
+VOID
+InitializeInstallDiskInfo (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
+ ATAPI_DEVICE_PATH *AtapiDevicePath;
+ SATA_DEVICE_PATH *SataDevicePath;
+ UINTN IdentifyRetry;
+
+ Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
+ //
+ // Device Path protocol must be installed on the device handle.
+ //
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy the DiskInfo protocol template.
+ //
+ CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
+
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
+ (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
+ (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
+
+ IdentifyRetry = 3;
+ do {
+ //
+ // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
+ // with IDE/AHCI interface GUID.
+ //
+ Status = AtapiIdentifyDevice (ScsiDiskDevice);
+ if (!EFI_ERROR (Status)) {
+ if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
+ //
+ // We find the valid ATAPI device path
+ //
+ AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
+ ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
+ ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
+ //
+ // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
+ //
+ CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
+ } else {
+ //
+ // We find the valid SATA device path
+ //
+ SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
+ ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
+ ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
+ //
+ // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
+ //
+ CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
+ }
+ return;
+ }
+ } while (--IdentifyRetry > 0);
+ } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
+ CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
+ break;
+ }
+ DevicePathNode = ChildDevicePathNode;
+ }
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
new file mode 100644
index 000000000..ed9bbd6f8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -0,0 +1,1600 @@
+/** @file
+ Header file for SCSI Disk Driver.
+
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SCSI_DISK_H_
+#define _SCSI_DISK_H_
+
+
+#include <Uefi.h>
+
+
+#include <Protocol/ScsiIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/EraseBlock.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ScsiPassThruExt.h>
+#include <Protocol/ScsiPassThru.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/StorageSecurityCommand.h>
+
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiScsiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/Scsi.h>
+#include <IndustryStandard/Atapi.h>
+
+#define IS_DEVICE_FIXED(a) (a)->FixedDevice ? 1 : 0
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+#define UFS_WLUN_RPMB 0xC4
+
+typedef struct {
+ UINT32 MaxLbaCnt;
+ UINT32 MaxBlkDespCnt;
+ UINT32 GranularityAlignment;
+} SCSI_UNMAP_PARAM_INFO;
+
+#define SCSI_DISK_DEV_SIGNATURE SIGNATURE_32 ('s', 'c', 'd', 'k')
+
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+
+ EFI_BLOCK_IO_PROTOCOL BlkIo;
+ EFI_BLOCK_IO2_PROTOCOL BlkIo2;
+ EFI_BLOCK_IO_MEDIA BlkIoMedia;
+ EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
+ EFI_SCSI_IO_PROTOCOL *ScsiIo;
+ UINT8 DeviceType;
+ BOOLEAN FixedDevice;
+ UINT16 Reserved;
+
+ EFI_SCSI_SENSE_DATA *SenseData;
+ UINTN SenseDataNumber;
+ EFI_SCSI_INQUIRY_DATA InquiryData;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+
+ //
+ // The following fields are only valid for ATAPI/SATA device
+ //
+ UINT32 Channel;
+ UINT32 Device;
+ ATAPI_IDENTIFY_DATA IdentifyData;
+
+ //
+ // Scsi UNMAP command parameters information
+ //
+ SCSI_UNMAP_PARAM_INFO UnmapInfo;
+ BOOLEAN BlockLimitsVpdSupported;
+
+ //
+ // The flag indicates if 16-byte command can be used
+ //
+ BOOLEAN Cdb16Byte;
+
+ //
+ // The queue for asynchronous task requests
+ //
+ LIST_ENTRY AsyncTaskQueue;
+} SCSI_DISK_DEV;
+
+#define SCSI_DISK_DEV_FROM_BLKIO(a) CR (a, SCSI_DISK_DEV, BlkIo, SCSI_DISK_DEV_SIGNATURE)
+#define SCSI_DISK_DEV_FROM_BLKIO2(a) CR (a, SCSI_DISK_DEV, BlkIo2, SCSI_DISK_DEV_SIGNATURE)
+#define SCSI_DISK_DEV_FROM_ERASEBLK(a) CR (a, SCSI_DISK_DEV, EraseBlock, SCSI_DISK_DEV_SIGNATURE)
+#define SCSI_DISK_DEV_FROM_STORSEC(a) CR (a, SCSI_DISK_DEV, StorageSecurity, SCSI_DISK_DEV_SIGNATURE)
+
+#define SCSI_DISK_DEV_FROM_DISKINFO(a) CR (a, SCSI_DISK_DEV, DiskInfo, SCSI_DISK_DEV_SIGNATURE)
+
+//
+// Asynchronous I/O request
+//
+//
+// Private data structure for a BlockIo2 request
+//
+typedef struct {
+ EFI_BLOCK_IO2_TOKEN *Token;
+ //
+ // The flag indicates if the last Scsi Read/Write sub-task for a BlockIo2
+ // request is sent to device
+ //
+ BOOLEAN LastScsiRW;
+
+ //
+ // The queue for Scsi Read/Write sub-tasks of a BlockIo2 request
+ //
+ LIST_ENTRY ScsiRWQueue;
+
+ LIST_ENTRY Link;
+} SCSI_BLKIO2_REQUEST;
+
+//
+// Private data structure for a SCSI Read/Write request
+//
+typedef struct {
+ SCSI_DISK_DEV *ScsiDiskDevice;
+ UINT64 Timeout;
+ EFI_SCSI_SENSE_DATA *SenseData;
+ UINT8 SenseDataLength;
+ UINT8 HostAdapterStatus;
+ UINT8 TargetStatus;
+ UINT8 *InBuffer;
+ UINT8 *OutBuffer;
+ UINT32 DataLength;
+ UINT64 StartLba;
+ UINT32 SectorCount;
+ UINT8 TimesRetry;
+
+ //
+ // The BlockIo2 request this SCSI command belongs to
+ //
+ SCSI_BLKIO2_REQUEST *BlkIo2Req;
+
+ LIST_ENTRY Link;
+} SCSI_ASYNC_RW_REQUEST;
+
+//
+// Private data structure for an EraseBlock request
+//
+typedef struct {
+ EFI_ERASE_BLOCK_TOKEN *Token;
+
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
+
+ LIST_ENTRY Link;
+} SCSI_ERASEBLK_REQUEST;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gScsiDiskComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gScsiDiskComponentName2;
+//
+// action code used in detect media process
+//
+#define ACTION_NO_ACTION 0x00
+#define ACTION_READ_CAPACITY 0x01
+#define ACTION_RETRY_COMMAND_LATER 0x02
+#define ACTION_RETRY_WITH_BACKOFF_ALGO 0x03
+
+#define SCSI_COMMAND_VERSION_1 0x01
+#define SCSI_COMMAND_VERSION_2 0x02
+#define SCSI_COMMAND_VERSION_3 0x03
+
+//
+// SCSI Disk Timeout Experience Value
+//
+// As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, the timeout
+// value is updated to 30s to follow ATA/ATAPI spec in which the device may take up to 30s
+// to respond command.
+//
+#define SCSI_DISK_TIMEOUT EFI_TIMER_PERIOD_SECONDS (30)
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions.
+ If any other agent wishes to call Supported() it must also follow these
+ calling restrictions.
+
+ @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
+ScsiDiskDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle.
+
+ This service is called by the EFI boot service ConnectController(). In order
+ to make drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these calling restrictions. If
+ any other agent wishes to call Start() it must also follow these calling
+ restrictions.
+
+ @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
+ScsiDiskDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ This service is called by the EFI boot service DisconnectController().
+ In order to make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController() must follow these
+ calling restrictions. If any other agent wishes to call Stop() it must
+ also follow these calling restrictions.
+
+ @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
+ScsiDiskDriverBindingStop (
+ 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
+ScsiDiskComponentNameGetDriverName (
+ 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
+ScsiDiskComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Reset SCSI Disk.
+
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+ @param ExtendedVerification The flag about if extend verificate
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ The function is to Read Block from SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected
+ @param Lba The logic block address
+ @param BufferSize The size of Buffer
+ @param Buffer The buffer to fill the read out data
+
+ @retval EFI_SUCCESS Successfully to read out block.
+ @retval EFI_DEVICE_ERROR Fail to detect media.
+ @retval EFI_NO_MEDIA Media is not present.
+ @retval EFI_MEDIA_CHANGED Media has changed.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+
+/**
+ The function is to Write Block to SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+ @param MediaId The Id of Media detected
+ @param Lba The logic block address
+ @param BufferSize The size of Buffer
+ @param Buffer The buffer to fill the read out data
+
+ @retval EFI_SUCCESS Successfully to read out block.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR Fail to detect media.
+ @retval EFI_NO_MEDIA Media is not present.
+ @retval EFI_MEDIA_CHANGED Media has changed.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Flush Block to Disk.
+
+ EFI_SUCCESS is returned directly.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+
+/**
+ Reset SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ The function is to Read Block from SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected.
+ @param Lba The logic block address.
+ @param Token A pointer to the token associated with the transaction.
+ @param BufferSize The size of Buffer.
+ @param Buffer The buffer to fill the read out data.
+
+ @retval EFI_SUCCESS The read request was queued if Token-> Event is
+ not NULL. The data was read correctly from the
+ device if theToken-> Event is NULL.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ The function is to Write Block to SCSI Disk.
+
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
+ @param MediaId The Id of Media detected.
+ @param Lba The logic block address.
+ @param Token A pointer to the token associated with the transaction.
+ @param BufferSize The size of Buffer.
+ @param Buffer The buffer to fill the read out data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot 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
+ScsiDiskWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to
+ write data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ );
+
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT if the
+ time required to execute the receive data command is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId OPTIONAL,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT if the
+ time required to execute the receive data command is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskSendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId OPTIONAL,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer
+ );
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+
+/**
+ Provides identify information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+ScsiDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+
+/**
+ Provides sense data information for the controller type.
+
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskInfoSenseData (
+ 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[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+ScsiDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+
+/**
+ Detect Device and read out capacity ,if error occurs, parse the sense key.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param MustReadCapacity The flag about reading device capacity
+ @param MediaChange The pointer of flag indicates if media has changed
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to detect media
+
+**/
+EFI_STATUS
+ScsiDiskDetectMedia (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN BOOLEAN MustReadCapacity,
+ OUT BOOLEAN *MediaChange
+ );
+
+/**
+ To test device.
+
+ When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
+ When Test Unit Ready command encounters any error caused by host adapter or
+ target, return error without retrieving Sense Keys.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates try again
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The pointer of the number of sense data array
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to test unit
+
+**/
+EFI_STATUS
+ScsiDiskTestUnitReady (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys
+ );
+
+
+/**
+ Parsing Sense Keys which got from request sense command.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param NumberOfSenseKeys The number of sense key
+ @param Action The pointer of action which indicates what is need to do next
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to complete the parsing
+
+**/
+EFI_STATUS
+DetectMediaParsingSenseKeys (
+ OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN NumberOfSenseKeys,
+ OUT UINTN *Action
+ );
+
+
+/**
+ Send read capacity command to device and get the device parameter.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates if need a retry
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The number of sense key
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to read capacity
+
+**/
+EFI_STATUS
+ScsiDiskReadCapacity (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys
+ );
+
+/**
+ Check the HostAdapter status and re-interpret it in EFI_STATUS.
+
+ @param HostAdapterStatus Host Adapter status
+
+ @retval EFI_SUCCESS Host adapter is OK.
+ @retval EFI_TIMEOUT Timeout.
+ @retval EFI_NOT_READY Adapter NOT ready.
+ @retval EFI_DEVICE_ERROR Adapter device error.
+
+**/
+EFI_STATUS
+CheckHostAdapterStatus (
+ IN UINT8 HostAdapterStatus
+ );
+
+
+/**
+ Check the target status and re-interpret it in EFI_STATUS.
+
+ @param TargetStatus Target status
+
+ @retval EFI_NOT_READY Device is NOT ready.
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CheckTargetStatus (
+ IN UINT8 TargetStatus
+ );
+
+/**
+ Retrieve all sense keys from the device.
+
+ When encountering error during the process, if retrieve sense keys before
+ error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
+ and NeedRetry set to FALSE; otherwise, return the proper return status.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry The pointer of flag indicates if need a retry
+ @param SenseDataArray The pointer of an array of sense data
+ @param NumberOfSenseKeys The number of sense key
+ @param AskResetIfError The flag indicates if need reset when error occurs
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to request sense key
+
+**/
+EFI_STATUS
+ScsiDiskRequestSenseKeys (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
+ OUT UINTN *NumberOfSenseKeys,
+ IN BOOLEAN AskResetIfError
+ );
+
+/**
+ Send out Inquiry command to Device.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param NeedRetry Indicates if needs try again when error happens
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to detect media
+
+**/
+EFI_STATUS
+ScsiDiskInquiryDevice (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry
+ );
+
+/**
+ Parse Inquiry data.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+
+**/
+VOID
+ParseInquiryData (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice
+ );
+
+/**
+ Read sector from SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Buffer The buffer to fill in the read out data
+ @param Lba Logic block address
+ @param NumberOfBlocks The number of blocks to read
+
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskReadSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ );
+
+/**
+ Write sector to SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Buffer The buffer of data to be written into SCSI Disk
+ @param Lba Logic block address
+ @param NumberOfBlocks The number of blocks to read
+
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskWriteSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ );
+
+/**
+ Asynchronously read sector from SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param Buffer The buffer to fill in the read out data.
+ @param Lba Logic block address.
+ @param NumberOfBlocks The number of blocks to read.
+ @param Token A pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskAsyncReadSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Asynchronously write sector to SCSI Disk.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param Buffer The buffer of data to be written into SCSI Disk.
+ @param Lba Logic block address.
+ @param NumberOfBlocks The number of blocks to read.
+ @param Token A pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
+ @retval EFI_DEVICE_ERROR Indicates a device error.
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWriteSectors (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Submit Read(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to read
+
+ @return EFI_STATUS is returned by calling ScsiRead10Command().
+**/
+EFI_STATUS
+ScsiDiskRead10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ OUT UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount
+ );
+
+/**
+ Submit Write(10) Command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to write
+
+ @return EFI_STATUS is returned by calling ScsiWrite10Command().
+
+**/
+EFI_STATUS
+ScsiDiskWrite10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ IN UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount
+ );
+
+/**
+ Submit Read(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to read
+
+ @return EFI_STATUS is returned by calling ScsiRead16Command().
+**/
+EFI_STATUS
+ScsiDiskRead16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ OUT UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount
+ );
+
+/**
+ Submit Write(16) Command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice
+ @param NeedRetry The pointer of flag indicates if needs retry if error happens
+ @param Timeout The time to complete the command
+ @param DataBuffer The buffer to fill with the read out data
+ @param DataLength The length of buffer
+ @param StartLba The start logic block address
+ @param SectorCount The number of blocks to write
+
+ @return EFI_STATUS is returned by calling ScsiWrite16Command().
+
+**/
+EFI_STATUS
+ScsiDiskWrite16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ OUT BOOLEAN *NeedRetry,
+ IN UINT64 Timeout,
+ IN UINT8 *DataBuffer,
+ IN OUT UINT32 *DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount
+ );
+
+/**
+ Submit Async Read(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer to fill with the read out data.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to read.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiRead10CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncRead10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ OUT UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Submit Async Write(10) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer contains the data to write.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to write.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiWrite10CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWrite10 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ IN UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT32 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Submit Async Read(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer to fill with the read out data.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to read.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiRead16CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncRead16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ OUT UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Submit Async Write(16) command.
+
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.
+ @param Timeout The time to complete the command.
+ @param TimesRetry The number of times the command has been retried.
+ @param DataBuffer The buffer contains the data to write.
+ @param DataLength The length of buffer.
+ @param StartLba The start logic block address.
+ @param SectorCount The number of blocks to write.
+ @param BlkIo2Req The upstream BlockIo2 request.
+ @param Token The pointer to the token associated with the
+ non-blocking read request.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @return others Status returned by calling
+ ScsiWrite16CommandEx().
+
+**/
+EFI_STATUS
+ScsiDiskAsyncWrite16 (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN UINT64 Timeout,
+ IN UINT8 TimesRetry,
+ IN UINT8 *DataBuffer,
+ IN UINT32 DataLength,
+ IN UINT64 StartLba,
+ IN UINT32 SectorCount,
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Get information from media read capacity command.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+ @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
+ @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
+**/
+VOID
+GetMediaInfo (
+ IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
+ IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
+ );
+
+/**
+ Check sense key to find if media presents.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE NOT any media
+ @retval FALSE Media presents
+**/
+BOOLEAN
+ScsiDiskIsNoMedia (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Parse sense key.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Error
+ @retval FALSE NOT error
+
+**/
+BOOLEAN
+ScsiDiskIsMediaError (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check sense key to find if hardware error happens.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Hardware error exits.
+ @retval FALSE NO error.
+
+**/
+BOOLEAN
+ScsiDiskIsHardwareError (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check sense key to find if media has changed.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE Media is changed.
+ @retval FALSE Media is NOT changed.
+**/
+BOOLEAN
+ScsiDiskIsMediaChange (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check sense key to find if reset happens.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+
+ @retval TRUE It is reset before.
+ @retval FALSE It is NOT reset before.
+
+**/
+BOOLEAN
+ScsiDiskIsResetBefore (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check sense key to find if the drive is ready.
+
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts The number of sense key
+ @param RetryLater The flag means if need a retry
+
+ @retval TRUE Drive is ready.
+ @retval FALSE Drive is NOT ready.
+
+**/
+BOOLEAN
+ScsiDiskIsDriveReady (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *RetryLater
+ );
+
+/**
+ Check sense key to find if it has sense key.
+
+ @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
+ @param SenseCounts - The number of sense key
+
+ @retval TRUE It has sense key.
+ @retval FALSE It has NOT any sense key.
+
+**/
+BOOLEAN
+ScsiDiskHaveSenseKey (
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Release resource about disk device.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
+
+**/
+VOID
+ReleaseScsiDiskDeviceResources (
+ IN SCSI_DISK_DEV *ScsiDiskDevice
+ );
+
+/**
+ Determine if Block Io should be produced.
+
+
+ @param ChildHandle Child Handle to retrieve Parent information.
+
+ @retval TRUE Should produce Block Io.
+ @retval FALSE Should not produce Block Io.
+
+**/
+BOOLEAN
+DetermineInstallBlockIo (
+ IN EFI_HANDLE ChildHandle
+ );
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
+ detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
+ to be IDE/AHCI interface GUID.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Child handle to install DiskInfo protocol.
+
+**/
+VOID
+InitializeInstallDiskInfo (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ );
+
+/**
+ Search protocol database and check to see if the protocol
+ specified by ProtocolGuid is present on a ControllerHandle and opened by
+ ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+ If the ControllerHandle is found, then the protocol specified by ProtocolGuid
+ will be opened on it.
+
+
+ @param ProtocolGuid ProtocolGuid pointer.
+ @param ChildHandle Child Handle to retrieve Parent information.
+
+**/
+VOID *
+EFIAPI
+GetParentProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE ChildHandle
+ );
+
+/**
+ Determine if EFI Erase Block Protocol should be produced.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Handle of device.
+
+ @retval TRUE Should produce EFI Erase Block Protocol.
+ @retval FALSE Should not produce EFI Erase Block Protocol.
+
+**/
+BOOLEAN
+DetermineInstallEraseBlock (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ );
+
+/**
+ Determine if EFI Storage Security Command Protocol should be produced.
+
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
+ @param ChildHandle Handle of device.
+
+ @retval TRUE Should produce EFI Storage Security Command Protocol.
+ @retval FALSE Should not produce EFI Storage Security Command Protocol.
+
+**/
+BOOLEAN
+DetermineInstallStorageSecurity (
+ IN SCSI_DISK_DEV *ScsiDiskDevice,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.uni b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.uni
new file mode 100644
index 000000000..957513064
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The Scsi Disk driver is used to retrieve the media info in the attached SCSI disk.
+//
+// It detects the SCSI disk media and installs Block I/O Protocol on the device handle.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Used to retrieve the media information in the attached SCSI disk"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It detects the SCSI disk media and installs Block I/O Protocol on the device handle."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
new file mode 100644
index 000000000..40818e669
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# The Scsi Disk driver is used to retrieve the media info in the attached SCSI disk.
+# It detects the SCSI disk media and installs Block I/O and Block I/O2 Protocol on
+# the device handle.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ScsiDisk
+ MODULE_UNI_FILE = ScsiDisk.uni
+ FILE_GUID = 0A66E322-3740-4cce-AD62-BD172CECCA35
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeScsiDisk
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gScsiDiskDriverBinding
+# COMPONENT_NAME = gScsiDiskComponentName
+# COMPONENT_NAME2 = gScsiDiskComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ ScsiDisk.c
+ ScsiDisk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiScsiLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ DevicePathLib
+
+[Protocols]
+ gEfiDiskInfoProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ gEfiEraseBlockProtocolGuid ## BY_START
+ gEfiStorageSecurityCommandProtocolGuid ## BY_START
+ gEfiScsiIoProtocolGuid ## TO_START
+ gEfiScsiPassThruProtocolGuid ## TO_START
+ gEfiExtScsiPassThruProtocolGuid ## TO_START
+
+[Guids]
+ gEfiDiskInfoScsiInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+ gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+ gEfiDiskInfoAhciInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+ gEfiDiskInfoUfsInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ScsiDiskExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskExtra.uni b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskExtra.uni
new file mode 100644
index 000000000..b82516247
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ScsiDisk Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SCSI Disk DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c
new file mode 100644
index 000000000..2d8bfa1b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c
@@ -0,0 +1,242 @@
+/** @file
+ The DMA memory help function.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcBlockIoPei.h"
+
+EDKII_IOMMU_PPI *mIoMmu;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Map (
+ mIoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&mIoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c
new file mode 100644
index 000000000..267db4a89
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c
@@ -0,0 +1,843 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcBlockIoPei.h"
+
+//
+// Template for EMMC HC Slot Data.
+//
+EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = {
+ EMMC_PEIM_SLOT_SIG, // Signature
+ { // Media
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ {
+ MSG_EMMC_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ }
+ },
+ 0, // MediaNum
+ { // PartitionType
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown,
+ EmmcPartitionUnknown
+ },
+ 0, // EmmcHcBase
+ { // Capability
+ 0,
+ },
+ { // Csd
+ 0,
+ },
+ { // ExtCsd
+ {0},
+ },
+ TRUE, // SectorAddressing
+ NULL // Private
+};
+
+//
+// Template for EMMC HC Private Data.
+//
+EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {
+ EMMC_PEIM_SIG, // Signature
+ NULL, // Pool
+ { // BlkIoPpi
+ EmmcBlockIoPeimGetDeviceNo,
+ EmmcBlockIoPeimGetMediaInfo,
+ EmmcBlockIoPeimReadBlocks
+ },
+ { // BlkIo2Ppi
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
+ EmmcBlockIoPeimGetDeviceNo2,
+ EmmcBlockIoPeimGetMediaInfo2,
+ EmmcBlockIoPeimReadBlocks2
+ },
+ { // BlkIoPpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+ },
+ { // BlkIo2PpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+ },
+ { // EndOfPeiNotifyList
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EmmcBlockIoPeimEndOfPei
+ },
+ { // Slot
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ }
+ },
+ 0, // SlotNum
+ 0 // TotalBlkIoDevices
+};
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+ *NumberBlockDevices = Private->TotalBlkIoDevices;
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+ UINT8 SlotNum;
+ UINT8 MediaNum;
+ UINT8 Location;
+ BOOLEAN Found;
+
+ Found = FALSE;
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Location = 0;
+ MediaNum = 0;
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
+ Location ++;
+ if (Location == DeviceIndex) {
+ Found = TRUE;
+ break;
+ }
+ }
+ if (Found) {
+ break;
+ }
+ }
+
+ MediaInfo->DeviceType = EMMC;
+ MediaInfo->MediaPresent = TRUE;
+ MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;
+ MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
+
+ 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, 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
+EmmcBlockIoPeimReadBlocks (
+ 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_STATUS Status;
+ UINT32 BlockSize;
+ UINTN NumberOfBlocks;
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+ UINT8 SlotNum;
+ UINT8 MediaNum;
+ UINT8 Location;
+ UINT8 PartitionConfig;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ BOOLEAN Found;
+
+ Status = EFI_SUCCESS;
+ Found = FALSE;
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Check parameters
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Location = 0;
+ MediaNum = 0;
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
+ Location ++;
+ if (Location == DeviceIndex) {
+ Found = TRUE;
+ break;
+ }
+ }
+ if (Found) {
+ break;
+ }
+ }
+
+ BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];
+ Status = EmmcPeimSwitch (
+ &Private->Slot[SlotNum],
+ 0x3,
+ OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),
+ PartitionConfig,
+ 0x0
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;
+ }
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = NumberOfBlocks;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ NumberOfBlocks = Remaining;
+ } else {
+ NumberOfBlocks = MaxBlock;
+ }
+
+ Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferSize = NumberOfBlocks * BlockSize;
+ Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StartLBA += NumberOfBlocks;
+ Buffer = (UINT8*)Buffer + BufferSize;
+ Remaining -= NumberOfBlocks;
+ }
+ return Status;
+}
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+ *NumberBlockDevices = Private->TotalBlkIoDevices;
+
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ UINT8 SlotNum;
+ UINT8 MediaNum;
+ UINT8 Location;
+ BOOLEAN Found;
+
+ Found = FALSE;
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = EmmcBlockIoPeimGetMediaInfo (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ &Media
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Location = 0;
+ MediaNum = 0;
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
+ Location ++;
+ if (Location == DeviceIndex) {
+ Found = TRUE;
+ break;
+ }
+ }
+ if (Found) {
+ break;
+ }
+ }
+
+ CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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, 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
+EmmcBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = EmmcBlockIoPeimReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+ return Status;
+}
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+
+ if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
+ EmmcPeimFreeMemPool (Private->Pool);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user code starts with this function.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The driver is successfully initialized.
+ @retval Others Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEmmcBlockIoPeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
+ UINT32 Index;
+ UINT32 PartitionIndex;
+ UINTN *MmioBase;
+ UINT8 BarNum;
+ UINT8 SlotNum;
+ UINT8 MediaNum;
+ UINT8 Controller;
+ UINT64 Capacity;
+ EMMC_EXT_CSD *ExtCsd;
+ EMMC_HC_SLOT_CAP Capability;
+ EMMC_PEIM_HC_SLOT *Slot;
+ UINT32 SecCount;
+ UINT32 GpSizeMult;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // locate Emmc host controller PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SdMmcHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IoMmuInit ();
+
+ Controller = 0;
+ MmioBase = NULL;
+ while (TRUE) {
+ Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (BarNum == 0) {
+ Controller++;
+ continue;
+ }
+
+ Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;
+ Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
+ //
+ // Initialize the memory pool which will be used in all transactions.
+ //
+ Status = EmmcPeimInitMemPool (Private);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ for (Index = 0; Index < BarNum; Index++) {
+ Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (Capability.SlotType != 0x1) {
+ DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
+ Status = EFI_UNSUPPORTED;
+ continue;
+ }
+
+ Status = EmmcPeimHcReset (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = EmmcPeimHcCardDetect (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = EmmcPeimHcInitHost (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ SlotNum = Private->SlotNum;
+ Slot = &Private->Slot[SlotNum];
+ CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));
+ Slot->Private = Private;
+ Slot->EmmcHcBase = MmioBase[Index];
+ CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
+
+ Status = EmmcPeimIdentification (Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ExtCsd = &Slot->ExtCsd;
+ if (ExtCsd->ExtCsdRev < 5) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
+ Status = EFI_UNSUPPORTED;
+ continue;
+ }
+ if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
+ Status = EFI_UNSUPPORTED;
+ continue;
+ }
+
+ for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {
+ switch (PartitionIndex) {
+ case EmmcPartitionUserData:
+ SecCount = *(UINT32*)&ExtCsd->SecCount;
+ Capacity = MultU64x32 ((UINT64)SecCount, 0x200);
+ break;
+ case EmmcPartitionBoot1:
+ case EmmcPartitionBoot2:
+ Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionRPMB:
+ Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionGP1:
+ GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP2:
+ GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP3:
+ GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP4:
+ GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ default:
+ ASSERT (FALSE);
+ continue;
+ }
+
+ MediaNum = Slot->MediaNum;
+ if (Capacity != 0) {
+ Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;
+ Slot->PartitionType[MediaNum] = PartitionIndex;
+ Private->TotalBlkIoDevices++;
+ Slot->MediaNum++;
+ }
+ }
+ Private->SlotNum++;
+ }
+ Controller++;
+
+ if (!EFI_ERROR (Status)) {
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+ PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+ } else {
+ if (Private->Pool->Head != NULL) {
+ EmmcPeimFreeMemPool (Private->Pool);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h
new file mode 100644
index 000000000..774274e48
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h
@@ -0,0 +1,514 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_BLOCK_IO_PEI_H_
+#define _EMMC_BLOCK_IO_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/SdMmcHostController.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <IndustryStandard/Emmc.h>
+
+typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA;
+typedef struct _EMMC_PEIM_HC_SLOT EMMC_PEIM_HC_SLOT;
+typedef struct _EMMC_TRB EMMC_TRB;
+
+#include "EmmcHci.h"
+#include "EmmcHcMem.h"
+
+#define EMMC_PEIM_SIG SIGNATURE_32 ('E', 'M', 'C', 'P')
+#define EMMC_PEIM_SLOT_SIG SIGNATURE_32 ('E', 'M', 'C', 'S')
+
+#define EMMC_PEIM_MAX_SLOTS 6
+#define EMMC_PEIM_MAX_PARTITIONS 8
+
+struct _EMMC_PEIM_HC_SLOT {
+ UINT32 Signature;
+ EFI_PEI_BLOCK_IO2_MEDIA Media[EMMC_PEIM_MAX_PARTITIONS];
+ UINT8 MediaNum;
+ EMMC_PARTITION_TYPE PartitionType[EMMC_PEIM_MAX_PARTITIONS];
+
+ UINTN EmmcHcBase;
+ EMMC_HC_SLOT_CAP Capability;
+ EMMC_CSD Csd;
+ EMMC_EXT_CSD ExtCsd;
+ BOOLEAN SectorAddressing;
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;
+};
+
+struct _EMMC_PEIM_HC_PRIVATE_DATA {
+ UINT32 Signature;
+ EMMC_PEIM_MEM_POOL *Pool;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+
+ //
+ // EndOfPei callback is used to do the cleanups before exit of PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ EMMC_PEIM_HC_SLOT Slot[EMMC_PEIM_MAX_SLOTS];
+ UINT8 SlotNum;
+ UINT8 TotalBlkIoDevices;
+};
+
+#define EMMC_TIMEOUT MultU64x32((UINT64)(3), 1000000)
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG)
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG)
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, EMMC_PEIM_SIG)
+
+struct _EMMC_TRB {
+ EMMC_PEIM_HC_SLOT *Slot;
+ UINT16 BlockSize;
+
+ EMMC_COMMAND_PACKET *Packet;
+ VOID *Data;
+ UINT32 DataLen;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS DataPhy;
+ VOID *DataMap;
+ EMMC_HC_TRANSFER_MODE Mode;
+
+ UINT64 Timeout;
+
+ EMMC_HC_ADMA_DESC_LINE *AdmaDesc;
+ UINTN AdmaDescSize;
+};
+
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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, 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
+EmmcBlockIoPeimReadBlocks (
+ 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
+ );
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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, 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
+EmmcBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Emmc Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+EmmcPeimInitMemPool (
+ IN EMMC_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+EmmcPeimFreeMemPool (
+ IN EMMC_PEIM_MEM_POOL *Pool
+ );
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+EmmcPeimAllocateMem (
+ IN EMMC_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+EmmcPeimFreeMem (
+ IN EMMC_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcBlockIoPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf
new file mode 100644
index 000000000..8ab632eb3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf
@@ -0,0 +1,60 @@
+## @file
+# Description file for the Embedded MMC (eMMC) Peim driver.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EmmcBlockIoPei
+ MODULE_UNI_FILE = EmmcBlockIoPei.uni
+ FILE_GUID = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeEmmcBlockIoPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ EmmcBlockIoPei.c
+ EmmcBlockIoPei.h
+ EmmcHci.c
+ EmmcHci.h
+ EmmcHcMem.c
+ EmmcHcMem.h
+ DmaMem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EmmcBlockIoPeiExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni
new file mode 100644
index 000000000..8c4c79c1a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// The EmmcBlockIoPei driver is used to support recovery from EMMC device.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from EMMC devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni
new file mode 100644
index 000000000..feeb1b34f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EmmcBlockIoPei Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EMMC BlockIo Peim for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c
new file mode 100644
index 000000000..19a0afcb6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c
@@ -0,0 +1,429 @@
+/** @file
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcBlockIoPei.h"
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+EMMC_PEIM_MEM_BLOCK *
+EmmcPeimAllocMemBlock (
+ IN UINTN Pages
+ )
+{
+ EMMC_PEIM_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Block = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof(EMMC_PEIM_MEM_BLOCK), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(EMMC_PEIM_MEM_BLOCK));
+
+ //
+ // each bit in the bit array represents EMMC_PEIM_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (EMMC_PEIM_MEM_BLOCK*)(UINTN)TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);
+
+ Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);
+
+ Block->Bits = (UINT8*)(UINTN)TempPtr;
+
+ Status = IoMmuAllocateBuffer (
+ Pages,
+ &BufHost,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
+
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+}
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+EmmcPeimFreeMemBlock (
+ IN EMMC_PEIM_MEM_POOL *Pool,
+ IN EMMC_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+}
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+EmmcPeimAllocMemFromBlock (
+ IN EMMC_PEIM_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consecutive number of zero bit.
+ //
+ if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);
+
+ } else {
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) EMMC_PEIM_MEM_BIT (Bit));
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+EmmcPeimInsertMemBlockToPool (
+ IN EMMC_PEIM_MEM_BLOCK *Head,
+ IN EMMC_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+EmmcPeimIsMemBlockEmpty (
+ IN EMMC_PEIM_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Emmc Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+EmmcPeimInitMemPool (
+ IN EMMC_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EMMC_PEIM_MEM_POOL *Pool;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Pool = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));
+
+ Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);
+
+ Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Pool = Pool;
+ return EFI_SUCCESS;
+}
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+EmmcPeimFreeMemPool (
+ IN EMMC_PEIM_MEM_POOL *Pool
+ )
+{
+ EMMC_PEIM_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ EmmcPeimFreeMemBlock (Pool, Block);
+ }
+
+ EmmcPeimFreeMemBlock (Pool, Pool->Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+EmmcPeimAllocateMem (
+ IN EMMC_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ EMMC_PEIM_MEM_BLOCK *Head;
+ EMMC_PEIM_MEM_BLOCK *Block;
+ EMMC_PEIM_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = EMMC_PEIM_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = EmmcPeimAllocMemBlock (Pages);
+ if (NewBlock == NULL) {
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ EmmcPeimInsertMemBlockToPool (Head, NewBlock);
+ Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+EmmcPeimFreeMem (
+ IN EMMC_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ EMMC_PEIM_MEM_BLOCK *Head;
+ EMMC_PEIM_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = EMMC_PEIM_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {
+ ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {
+ EmmcPeimFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h
new file mode 100644
index 000000000..255ad345d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h
@@ -0,0 +1,56 @@
+/** @file
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_PEIM_MEM_H_
+#define _EMMC_PEIM_MEM_H_
+
+#define EMMC_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
+
+#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit)))
+
+typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK;
+
+struct _EMMC_PEIM_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ EMMC_PEIM_MEM_BLOCK *Next;
+};
+
+typedef struct _EMMC_PEIM_MEM_POOL {
+ EMMC_PEIM_MEM_BLOCK *Head;
+} EMMC_PEIM_MEM_POOL;
+
+//
+// Memory allocation unit, note that the value must meet EMMC spec alignment requirement.
+//
+#define EMMC_PEIM_MEM_UNIT 128
+
+#define EMMC_PEIM_MEM_UNIT_MASK (EMMC_PEIM_MEM_UNIT - 1)
+#define EMMC_PEIM_MEM_DEFAULT_PAGES 16
+
+#define EMMC_PEIM_MEM_ROUND(Len) (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define EMMC_PEIM_NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c
new file mode 100644
index 000000000..287a10266
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c
@@ -0,0 +1,2894 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcBlockIoPei.h"
+
+/**
+ Read/Write specified EMMC host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimHcRwMmio (
+ IN UINTN Address,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ )
+{
+ if ((Address == 0) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Count) {
+ case 1:
+ if (Read) {
+ *(UINT8*)Data = MmioRead8 (Address);
+ } else {
+ MmioWrite8 (Address, *(UINT8*)Data);
+ }
+ break;
+ case 2:
+ if (Read) {
+ *(UINT16*)Data = MmioRead16 (Address);
+ } else {
+ MmioWrite16 (Address, *(UINT16*)Data);
+ }
+ break;
+ case 4:
+ if (Read) {
+ *(UINT32*)Data = MmioRead32 (Address);
+ } else {
+ MmioWrite32 (Address, *(UINT32*)Data);
+ }
+ break;
+ case 8:
+ if (Read) {
+ *(UINT64*)Data = MmioRead64 (Address);
+ } else {
+ MmioWrite64 (Address, *(UINT64*)Data);
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do OR operation with the value of the specified EMMC host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimHcOrMmio (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN VOID *OrData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Or;
+
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ Or = *(UINT8*) OrData;
+ } else if (Count == 2) {
+ Or = *(UINT16*) OrData;
+ } else if (Count == 4) {
+ Or = *(UINT32*) OrData;
+ } else if (Count == 8) {
+ Or = *(UINT64*) OrData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data |= Or;
+ Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Do AND operation with the value of the specified EMMC host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimHcAndMmio (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN VOID *AndData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 And;
+
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ And = *(UINT8*) AndData;
+ } else if (Count == 2) {
+ And = *(UINT16*) AndData;
+ } else if (Count == 4) {
+ And = *(UINT32*) AndData;
+ } else if (Count == 8) {
+ And = *(UINT64*) AndData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data &= And;
+ Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] Address The address of the mmio register to be checked.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimHcCheckMmioSet (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Value;
+
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = 0;
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] Address The address of the mmio register to wait.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimHcWaitMmioSet (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ Status = EmmcPeimHcCheckMmioSet (
+ Address,
+ Count,
+ MaskValue,
+ TestValue
+ );
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Software reset the specified EMMC host controller and enable all interrupts.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcReset (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SwReset;
+
+ SwReset = 0xFF;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcPeimHcWaitMmioSet (
+ Bar + EMMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0x00,
+ EMMC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "EmmcPeimHcReset: reset done with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = EmmcPeimHcEnableInterrupt (Bar);
+
+ return Status;
+}
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcEnableInterrupt (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IntStatus;
+
+ //
+ // Enable all bits in Error Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Enable all bits in Normal Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+
+ return Status;
+}
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcGetCapability (
+ IN UINTN Bar,
+ OUT EMMC_HC_SLOT_CAP *Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Cap;
+
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Capability, &Cap, sizeof (Cap));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect whether there is a EMMC card attached at the specified EMMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS There is a EMMC card attached.
+ @retval EFI_NO_MEDIA There is not a EMMC card attached.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcCardDetect (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data;
+ UINT32 PresentState;
+
+ //
+ // Check Normal Interrupt Status Register
+ //
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT6 | BIT7)) != 0) {
+ //
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
+ //
+ Data &= BIT6 | BIT7;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NO_MEDIA;
+ }
+}
+
+/**
+ Stop EMMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS Succeed to stop EMMC clock.
+ @retval Others Fail to stop EMMC clock.
+
+**/
+EFI_STATUS
+EmmcPeimHcStopClock (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PresentState;
+ UINT16 ClockCtrl;
+
+ //
+ // Ensure no SD transactions are occurring on the SD Bus by
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
+ // in the Present State register to be 0.
+ //
+ Status = EmmcPeimHcWaitMmioSet (
+ Bar + EMMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ BIT0 | BIT1,
+ 0,
+ EMMC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 0
+ //
+ ClockCtrl = (UINT16)~BIT2;
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ EMMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcClockSupply (
+ IN UINTN Bar,
+ IN UINT64 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ EMMC_HC_SLOT_CAP Capability;
+ UINT32 BaseClkFreq;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ControllerVer;
+ UINT16 ClockCtrl;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (Capability.BaseClkFreq != 0);
+
+ BaseClkFreq = Capability.BaseClkFreq;
+
+ if (ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq * 1000;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
+ //
+ if ((ControllerVer & 0xFF) == 2) {
+ ASSERT (Divisor <= 0x3FF);
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ //
+ // Only the most significant bit can be used as divisor.
+ //
+ if (((Divisor - 1) & Divisor) != 0) {
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);
+ }
+ ASSERT (Divisor <= 0x80);
+ ClockCtrl = (Divisor & 0xFF) << 8;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Stop bus clock at first
+ //
+ Status = EmmcPeimHcStopClock (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Supply clock frequency with specified divisor
+ //
+ ClockCtrl |= BIT0;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1
+ //
+ Status = EmmcPeimHcWaitMmioSet (
+ Bar + EMMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ EMMC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ EMMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a EMMC card attached.
+ @retval FALSE There is no a EMMC card attached.
+
+**/
+EFI_STATUS
+EmmcPeimHcPowerControl (
+ IN UINTN Bar,
+ IN UINT8 PowerCtrl
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clr SD Bus Power
+ //
+ PowerCtrl &= (UINT8)~BIT0;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ PowerCtrl |= BIT0;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+
+ return Status;
+}
+
+/**
+ Set the EMMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] BusWidth The bus width used by the EMMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcSetBusWidth (
+ IN UINTN Bar,
+ IN UINT16 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (BusWidth == 1) {
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 4) {
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 |= BIT1;
+ HostCtrl1 &= (UINT8)~BIT5;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 8) {
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 &= (UINT8)~BIT1;
+ HostCtrl1 |= BIT5;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Supply EMMC card with lowest clock frequency at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcInitClockFreq (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ EMMC_HC_SLOT_CAP Capability;
+ UINT32 InitFreq;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Capability.BaseClkFreq == 0) {
+ //
+ // Don't support get Base Clock Frequency information via another method
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Supply 400KHz clock frequency at initialization phase.
+ //
+ InitFreq = 400;
+ Status = EmmcPeimHcClockSupply (Bar, InitFreq);
+ return Status;
+}
+
+/**
+ Supply EMMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcInitPowerVoltage (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ EMMC_HC_SLOT_CAP Capability;
+ UINT8 MaxVoltage;
+ UINT8 HostCtrl2;
+
+ //
+ // Get the support voltage of the Host Controller
+ //
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Calculate supported maximum voltage according to SD Bus Voltage Select
+ //
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxVoltage = 0x0E;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxVoltage = 0x0C;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxVoltage = 0x0A;
+ HostCtrl2 = BIT3;
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ MicroSecondDelay (5000);
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ Status = EmmcPeimHcPowerControl (Bar, MaxVoltage);
+
+ return Status;
+}
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcInitTimeoutCtrl (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Timeout;
+
+ Timeout = 0x0E;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
+
+ return Status;
+}
+
+/**
+ Initial EMMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcInitHost (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EmmcPeimHcInitClockFreq (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimHcInitPowerVoltage (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimHcInitTimeoutCtrl (Bar);
+ return Status;
+}
+
+/**
+ Turn on/off LED.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] On The boolean to turn on/off LED.
+
+ @retval EFI_SUCCESS The LED is turned on/off successfully.
+ @retval Others The LED isn't turned on/off successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcLedOnOff (
+ IN UINTN Bar,
+ IN BOOLEAN On
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (On) {
+ HostCtrl1 = BIT0;
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ HostCtrl1 = (UINT8)~BIT0;
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ }
+
+ return Status;
+}
+
+/**
+ Build ADMA descriptor table for transfer.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
+
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
+ @retval Others The ADMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildAdmaDescTable (
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINT32 Address;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ //
+ // Only support 32bit ADMA Descriptor Table
+ //
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ // for 32-bit address descriptor table.
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
+
+ Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE));
+ Trb->AdmaDesc = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);
+ if (Trb->AdmaDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Remaining = DataLen;
+ Address = (UINT32)Data;
+ for (Index = 0; Index < Entries; Index++) {
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
+ Trb->AdmaDesc[Index].Address = Address;
+ break;
+ } else {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = 0;
+ Trb->AdmaDesc[Index].Address = Address;
+ }
+
+ Remaining -= ADMA_MAX_DATA_PER_LINE;
+ Address += ADMA_MAX_DATA_PER_LINE;
+ }
+
+ //
+ // Set the last descriptor line as end of descriptor table
+ //
+ Trb->AdmaDesc[Index].End = 1;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the EMMC cmd request.
+
+ @param[in] Slot The slot number of the EMMC card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+
+ @return Created Trb or NULL.
+
+**/
+EMMC_TRB *
+EmmcPeimCreateTrb (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN EMMC_COMMAND_PACKET *Packet
+ )
+{
+ EMMC_TRB *Trb;
+ EFI_STATUS Status;
+ EMMC_HC_SLOT_CAP Capability;
+ EDKII_IOMMU_OPERATION MapOp;
+ UINTN MapLength;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Trb = AllocateZeroPool (sizeof (EMMC_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Timeout = Packet->Timeout;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
+ }
+
+ if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {
+ Trb->Mode = EmmcPioMode;
+ } else {
+ if (Trb->Read) {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ if (Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
+
+ if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) {
+ DEBUG ((DEBUG_ERROR, "EmmcPeimCreateTrb: Fail to map data buffer.\n"));
+ goto Error;
+ }
+ }
+
+ if (Trb->DataLen == 0) {
+ Trb->Mode = EmmcNoData;
+ } else if (Capability.Adma2 != 0) {
+ Trb->Mode = EmmcAdmaMode;
+ Status = BuildAdmaDescTable (Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else if (Capability.Sdma != 0) {
+ Trb->Mode = EmmcSdmaMode;
+ } else {
+ Trb->Mode = EmmcPioMode;
+ }
+ }
+ return Trb;
+
+Error:
+ EmmcPeimFreeTrb (Trb);
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+**/
+VOID
+EmmcPeimFreeTrb (
+ IN EMMC_TRB *Trb
+ )
+{
+ if ((Trb != NULL) && (Trb->DataMap != NULL)) {
+ IoMmuUnmap (Trb->DataMap);
+ }
+
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
+ EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);
+ }
+
+ if (Trb != NULL) {
+ FreePool (Trb);
+ }
+ return;
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+EmmcPeimCheckTrbEnv (
+ IN UINTN Bar,
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EMMC_COMMAND_PACKET *Packet;
+ UINT32 PresentState;
+
+ Packet = Trb->Packet;
+
+ if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) ||
+ (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) ||
+ (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b)) {
+ //
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
+ // the Present State register to be 0
+ //
+ PresentState = BIT0 | BIT1;
+ } else {
+ //
+ // Wait Command Inhibit (CMD) in the Present State register
+ // to be 0
+ //
+ PresentState = BIT0;
+ }
+
+ Status = EmmcPeimHcCheckMmioSet (
+ Bar + EMMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ PresentState,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+EmmcPeimWaitTrbEnv (
+ IN UINTN Bar,
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EMMC_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Packet = Trb->Packet;
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = EmmcPeimCheckTrbEnv (Bar, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+EmmcPeimExecTrb (
+ IN UINTN Bar,
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EMMC_COMMAND_PACKET *Packet;
+ UINT16 Cmd;
+ UINT16 IntStatus;
+ UINT32 Argument;
+ UINT16 BlkCount;
+ UINT16 BlkSize;
+ UINT16 TransMode;
+ UINT8 HostCtrl1;
+ UINT32 SdmaAddr;
+ UINT64 AdmaAddr;
+
+ Packet = Trb->Packet;
+ //
+ // Clear all bits in Error Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear all bits in Normal Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set Host Control 1 register DMA Select field
+ //
+ if (Trb->Mode == EmmcAdmaMode) {
+ HostCtrl1 = BIT4;
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ EmmcPeimHcLedOnOff (Bar, TRUE);
+
+ if (Trb->Mode == EmmcSdmaMode) {
+ if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Trb->Mode == EmmcAdmaMode) {
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlkSize = Trb->BlockSize;
+ if (Trb->Mode == EmmcSdmaMode) {
+ //
+ // Set SDMA boundary to be 512K bytes.
+ //
+ BlkSize |= 0x7000;
+ }
+
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkCount = 0;
+ if (Trb->Mode != EmmcNoData) {
+ //
+ // Calculate Block Count.
+ //
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
+ }
+
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Argument = Packet->EmmcCmdBlk->CommandArgument;
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransMode = 0;
+ if (Trb->Mode != EmmcNoData) {
+ if (Trb->Mode != EmmcPioMode) {
+ TransMode |= BIT0;
+ }
+ if (Trb->Read) {
+ TransMode |= BIT4;
+ }
+ if (BlkCount > 1) {
+ TransMode |= BIT5 | BIT1;
+ }
+ }
+
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Cmd = (UINT16)LShiftU64(Packet->EmmcCmdBlk->CommandIndex, 8);
+ if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) {
+ Cmd |= BIT5;
+ }
+ //
+ // Convert ResponseType to value
+ //
+ if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {
+ switch (Packet->EmmcCmdBlk->ResponseType) {
+ case EmmcResponceTypeR1:
+ case EmmcResponceTypeR5:
+ case EmmcResponceTypeR6:
+ case EmmcResponceTypeR7:
+ Cmd |= (BIT1 | BIT3 | BIT4);
+ break;
+ case EmmcResponceTypeR2:
+ Cmd |= (BIT0 | BIT3);
+ break;
+ case EmmcResponceTypeR3:
+ case EmmcResponceTypeR4:
+ Cmd |= BIT1;
+ break;
+ case EmmcResponceTypeR1b:
+ case EmmcResponceTypeR5b:
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ //
+ // Execute cmd
+ //
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
+ return Status;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+EmmcPeimCheckTrbResult (
+ IN UINTN Bar,
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EMMC_COMMAND_PACKET *Packet;
+ UINT16 IntStatus;
+ UINT32 Response[4];
+ UINT32 SdmaAddr;
+ UINT8 Index;
+ UINT8 SwReset;
+ UINT32 PioLength;
+
+ SwReset = 0;
+ Packet = Trb->Packet;
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check Transfer Complete bit is set or not.
+ //
+ if ((IntStatus & BIT1) == BIT1) {
+ if ((IntStatus & BIT15) == BIT15) {
+ //
+ // Read Error Interrupt Status register to check if the error is
+ // Data Timeout Error.
+ // If yes, treat it as success as Transfer Complete has higher
+ // priority than Data Timeout Error.
+ //
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((IntStatus & BIT4) == BIT4) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ goto Done;
+ }
+ //
+ // Check if there is a error happened during cmd execution.
+ // If yes, then do error recovery procedure to follow SD Host Controller
+ // Simplified Spec 3.0 section 3.10.1.
+ //
+ if ((IntStatus & BIT15) == BIT15) {
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if ((IntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((IntStatus & 0xF0) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Status = EmmcPeimHcWaitMmioSet (
+ Bar + EMMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ EMMC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ //
+ // Check if DMA interrupt is signalled for the SDMA transfer.
+ //
+ if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {
+ //
+ // Clear DMA interrupt bit.
+ //
+ IntStatus = BIT3;
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Update SDMA Address register.
+ //
+ SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, EMMC_SDMA_BOUNDARY);
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_SDMA_ADDR,
+ FALSE,
+ sizeof (UINT32),
+ &SdmaAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
+ }
+
+ if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) &&
+ (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) &&
+ (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b)) {
+ if ((IntStatus & BIT0) == BIT0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {
+ //
+ // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
+ // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
+ // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
+ //
+ if ((IntStatus & BIT5) == BIT5) {
+ //
+ // Clear Buffer Read Ready interrupt at first.
+ //
+ IntStatus = BIT5;
+ EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ //
+ // Read data out from Buffer Port register
+ //
+ for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
+ EmmcPeimHcRwMmio (Bar + EMMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);
+ }
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ Status = EFI_NOT_READY;
+Done:
+ //
+ // Get response data when the cmd is executed successfully.
+ //
+ if (!EFI_ERROR (Status)) {
+ if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {
+ for (Index = 0; Index < 4; Index++) {
+ Status = EmmcPeimHcRwMmio (
+ Bar + EMMC_HC_RESPONSE + Index * 4,
+ TRUE,
+ sizeof (UINT32),
+ &Response[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ EmmcPeimHcLedOnOff (Bar, FALSE);
+ return Status;
+ }
+ }
+ CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response));
+ }
+ }
+
+ if (Status != EFI_NOT_READY) {
+ EmmcPeimHcLedOnOff (Bar, FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+EmmcPeimWaitTrbResult (
+ IN UINTN Bar,
+ IN EMMC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EMMC_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ Packet = Trb->Packet;
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = EmmcPeimCheckTrbResult (Bar, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Sends EMMC command to an EMMC card that is attached to the EMMC controller.
+
+ If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in,out] Packet A pointer to the EMMC command data structure.
+
+ @retval EFI_SUCCESS The EMMC Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the EMMC Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by EMMC card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcPeimExecCmd (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN OUT EMMC_COMMAND_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ EMMC_TRB *Trb;
+
+ if (Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Trb = EmmcPeimCreateTrb (Slot, Packet);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ EmmcPeimFreeTrb (Trb);
+
+ return Status;
+}
+
+/**
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
+ make it go to Idle State.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+
+ @retval EFI_SUCCESS The EMMC device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+EmmcPeimReset (
+ IN EMMC_PEIM_HC_SLOT *Slot
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBc;
+ EmmcCmdBlk.ResponseType = 0;
+ EmmcCmdBlk.CommandArgument = 0;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.
+ On output, the argument is the value of OCR register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimGetOcr (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN OUT UINT32 *Argument
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR3;
+ EmmcCmdBlk.CommandArgument = *Argument;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Argument = EmmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the
+ data of their CID registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimGetAllCid (
+ IN EMMC_PEIM_HC_SLOT *Slot
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;
+ EmmcCmdBlk.CommandArgument = 0;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
+ Address (RCA).
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSetRca (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = Rca << 16;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of this
+ buffer as the content of this byte is meaningless even
+ if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimGetCsd (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;
+ EmmcCmdBlk.CommandArgument = Rca << 16;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSelect (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = Rca << 16;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimGetExtCsd (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = 0x00000000;
+
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+ return Status;
+}
+
+/**
+ Send command SWITCH to the EMMC device to switch the mode of operation of the
+ selected Device or modifies the EXT_CSD registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Access The access mode of SWITCH command.
+ @param[in] Index The offset of the field to be access.
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitch (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT8 Access,
+ IN UINT8 Index,
+ IN UINT8 Value,
+ IN UINT8 CmdSet
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b;
+ EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed EMMC device to get its status register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSendStatus (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = Rca << 16;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = EmmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
+ blocks for the following block read/write cmd.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] BlockCount The number of the logical block to access.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSetBlkCount (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT16 BlockCount
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = BlockCount;
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
+ to read/write the specified number of blocks.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified EMMC device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimRwMultiBlocks (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
+ // transfer speed (2.4MB/s).
+ // Refer to eMMC 5.0 spec section 6.9.1 for details.
+ //
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;
+
+ if (IsRead) {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = (UINT32)BufferSize;
+
+ EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ } else {
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = (UINT32)BufferSize;
+
+ EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ }
+
+ if (Slot->SectorAddressing) {
+ EmmcCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
+ }
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSendTuningBlk (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;
+ EMMC_STATUS_BLOCK EmmcStatusBlk;
+ EMMC_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[128];
+
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;
+ Packet.Timeout = EMMC_TIMEOUT;
+
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
+ EmmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ if (BusWidth == 8) {
+ Packet.InTransferLength = sizeof (TuningBlock);
+ } else {
+ Packet.InTransferLength = 64;
+ }
+
+ Status = EmmcPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Tuning the clock to get HS200 optimal sampling point.
+
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimTuningClkForHs200 (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = EmmcPeimSendTuningBlk (Slot, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((EFI_D_ERROR, "EmmcPeimTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
+ Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
+ use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitchBusWidth (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+ if (BusWidth == 4) {
+ Value = 1;
+ } else if (BusWidth == 8) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsDdr) {
+ Value += 4;
+ }
+
+ CmdSet = 0;
+ Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the clock frequency to the specified value.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller
+ Simplified Spec 3.0 section Figure 3-3 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitchClockFreq (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ IN UINT8 HsTiming,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
+ Value = HsTiming;
+ CmdSet = 0;
+
+ Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert the clock freq unit from MHz to KHz.
+ //
+ Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000);
+
+ return Status;
+}
+
+/**
+ Switch to the High Speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
+ use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitchToHighSpeed (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ IN UINT32 ClockFreq,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl1;
+ UINT8 HostCtrl2;
+
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to High Speed timing
+ //
+ HostCtrl1 = BIT2;
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostCtrl2 = (UINT8)~0x7;
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (IsDdr) {
+ HostCtrl2 = BIT2;
+ } else if (ClockFreq == 52) {
+ HostCtrl2 = BIT0;
+ } else {
+ HostCtrl2 = 0;
+ }
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HsTiming = 1;
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
+
+ return Status;
+}
+
+/**
+ Switch to the HS200 timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitchToHS200 (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ IN UINT32 ClockFreq,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl2;
+ UINT16 ClockCtrl;
+
+ if ((BusWidth != 4) && (BusWidth != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to HS200/SDR104 timing
+ //
+ //
+ // Stop bus clock at first
+ //
+ Status = EmmcPeimHcStopClock (Slot->EmmcHcBase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostCtrl2 = (UINT8)~0x7;
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl2 = BIT0 | BIT1;
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit
+ //
+ Status = EmmcPeimHcWaitMmioSet (
+ Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ EMMC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ HsTiming = 2;
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch to the HS400 timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitchToHS400 (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl2;
+
+ Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to High Speed timing and set the clock frequency to a value less than 52MHz.
+ //
+ HsTiming = 1;
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // HS400 mode must use 8 data lines.
+ //
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to HS400 timing
+ //
+ HostCtrl2 = (UINT8)~0x7;
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl2 = BIT0 | BIT2;
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HsTiming = 3;
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
+
+ return Status;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSetBusMode (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT32 Rca
+ )
+{
+ EFI_STATUS Status;
+ EMMC_HC_SLOT_CAP Capability;
+ UINT8 HsTiming;
+ BOOLEAN IsDdr;
+ UINT32 ClockFreq;
+ UINT8 BusWidth;
+
+ Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) {
+ Slot->SectorAddressing = TRUE;
+ } else {
+ Slot->SectorAddressing = FALSE;
+ }
+
+ Status = EmmcPeimSelect (Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status));
+ return Status;
+ }
+
+ ASSERT (Capability.BaseClkFreq != 0);
+ //
+ // Check if the Host Controller support 8bits bus width.
+ //
+ if (Capability.BusWidth8 != 0) {
+ BusWidth = 8;
+ } else {
+ BusWidth = 4;
+ }
+ //
+ // Get Device_Type from EXT_CSD register.
+ //
+ Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Calculate supported bus speed/bus width/clock frequency.
+ //
+ HsTiming = 0;
+ IsDdr = FALSE;
+ ClockFreq = 0;
+ if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Capability.Sdr104 != 0)) {
+ HsTiming = 2;
+ IsDdr = FALSE;
+ ClockFreq = 200;
+ } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Capability.Ddr50 != 0)) {
+ HsTiming = 1;
+ IsDdr = TRUE;
+ ClockFreq = 52;
+ } else if (((Slot->ExtCsd.DeviceType & BIT1) != 0) && (Capability.HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 52;
+ } else if (((Slot->ExtCsd.DeviceType & BIT0) != 0) && (Capability.HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 26;
+ }
+ //
+ // Check if both of the device and the host controller support HS400 DDR mode.
+ //
+ if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Capability.Hs400 != 0)) {
+ //
+ // The host controller supports 8bits bus.
+ //
+ ASSERT (BusWidth == 8);
+ HsTiming = 3;
+ IsDdr = TRUE;
+ ClockFreq = 200;
+ }
+
+ if ((ClockFreq == 0) || (HsTiming == 0)) {
+ //
+ // Continue using default setting.
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));
+
+ if (HsTiming == 3) {
+ //
+ // Execute HS400 timing switch procedure
+ //
+ Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq);
+ } else if (HsTiming == 2) {
+ //
+ // Execute HS200 timing switch procedure
+ //
+ Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth);
+ } else {
+ //
+ // Execute High Speed timing switch procedure
+ //
+ Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, IsDdr, BusWidth);
+ }
+
+ return Status;
+}
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcPeimIdentification (
+ IN EMMC_PEIM_HC_SLOT *Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Ocr;
+ UINT32 Rca;
+ UINTN Retry;
+
+ Status = EmmcPeimReset (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status));
+ return Status;
+ }
+
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = EmmcPeimGetOcr (Slot, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status));
+ return Status;
+ }
+
+ if (Retry++ == 100) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ MicroSecondDelay (10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ Status = EmmcPeimGetAllCid (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Don't support multiple devices on the slot, that is
+ // shared bus slot feature.
+ //
+ Rca = 1;
+ Status = EmmcPeimSetRca (Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((EFI_D_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));
+
+ Status = EmmcPeimSetBusMode (Slot, Rca);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h
new file mode 100644
index 000000000..4e3e51d14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h
@@ -0,0 +1,339 @@
+/** @file
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_HCI_H_
+#define _EMMC_HCI_H_
+
+//
+// EMMC Host Controller MMIO Register Offset
+//
+#define EMMC_HC_SDMA_ADDR 0x00
+#define EMMC_HC_ARG2 0x00
+#define EMMC_HC_BLK_SIZE 0x04
+#define EMMC_HC_BLK_COUNT 0x06
+#define EMMC_HC_ARG1 0x08
+#define EMMC_HC_TRANS_MOD 0x0C
+#define EMMC_HC_COMMAND 0x0E
+#define EMMC_HC_RESPONSE 0x10
+#define EMMC_HC_BUF_DAT_PORT 0x20
+#define EMMC_HC_PRESENT_STATE 0x24
+#define EMMC_HC_HOST_CTRL1 0x28
+#define EMMC_HC_POWER_CTRL 0x29
+#define EMMC_HC_BLK_GAP_CTRL 0x2A
+#define EMMC_HC_WAKEUP_CTRL 0x2B
+#define EMMC_HC_CLOCK_CTRL 0x2C
+#define EMMC_HC_TIMEOUT_CTRL 0x2E
+#define EMMC_HC_SW_RST 0x2F
+#define EMMC_HC_NOR_INT_STS 0x30
+#define EMMC_HC_ERR_INT_STS 0x32
+#define EMMC_HC_NOR_INT_STS_EN 0x34
+#define EMMC_HC_ERR_INT_STS_EN 0x36
+#define EMMC_HC_NOR_INT_SIG_EN 0x38
+#define EMMC_HC_ERR_INT_SIG_EN 0x3A
+#define EMMC_HC_AUTO_CMD_ERR_STS 0x3C
+#define EMMC_HC_HOST_CTRL2 0x3E
+#define EMMC_HC_CAP 0x40
+#define EMMC_HC_MAX_CURRENT_CAP 0x48
+#define EMMC_HC_FORCE_EVT_AUTO_CMD 0x50
+#define EMMC_HC_FORCE_EVT_ERR_INT 0x52
+#define EMMC_HC_ADMA_ERR_STS 0x54
+#define EMMC_HC_ADMA_SYS_ADDR 0x58
+#define EMMC_HC_PRESET_VAL 0x60
+#define EMMC_HC_SHARED_BUS_CTRL 0xE0
+#define EMMC_HC_SLOT_INT_STS 0xFC
+#define EMMC_HC_CTRL_VER 0xFE
+
+//
+// The transfer modes supported by SD Host Controller
+// Simplified Spec 3.0 Table 1-2
+//
+typedef enum {
+ EmmcNoData,
+ EmmcPioMode,
+ EmmcSdmaMode,
+ EmmcAdmaMode
+} EMMC_HC_TRANSFER_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE 0x10000
+#define EMMC_SDMA_BOUNDARY 512 * 1024
+#define EMMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
+
+typedef enum {
+ EmmcCommandTypeBc, // Broadcast commands, no response
+ EmmcCommandTypeBcr, // Broadcast commands with response
+ EmmcCommandTypeAc, // Addressed(point-to-point) commands
+ EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands
+} EMMC_COMMAND_TYPE;
+
+typedef enum {
+ EmmcResponceTypeR1,
+ EmmcResponceTypeR1b,
+ EmmcResponceTypeR2,
+ EmmcResponceTypeR3,
+ EmmcResponceTypeR4,
+ EmmcResponceTypeR5,
+ EmmcResponceTypeR5b,
+ EmmcResponceTypeR6,
+ EmmcResponceTypeR7
+} EMMC_RESPONSE_TYPE;
+
+typedef struct _EMMC_COMMAND_BLOCK {
+ UINT16 CommandIndex;
+ UINT32 CommandArgument;
+ UINT32 CommandType; // One of the EMMC_COMMAND_TYPE values
+ UINT32 ResponseType; // One of the EMMC_RESPONSE_TYPE values
+} EMMC_COMMAND_BLOCK;
+
+typedef struct _EMMC_STATUS_BLOCK {
+ UINT32 Resp0;
+ UINT32 Resp1;
+ UINT32 Resp2;
+ UINT32 Resp3;
+} EMMC_STATUS_BLOCK;
+
+typedef struct _EMMC_COMMAND_PACKET {
+ UINT64 Timeout;
+ EMMC_COMMAND_BLOCK *EmmcCmdBlk;
+ EMMC_STATUS_BLOCK *EmmcStatusBlk;
+ VOID *InDataBuffer;
+ VOID *OutDataBuffer;
+ UINT32 InTransferLength;
+ UINT32 OutTransferLength;
+} EMMC_COMMAND_PACKET;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 Reserved1:10;
+ UINT32 Length:16;
+ UINT32 Address;
+} EMMC_HC_ADMA_DESC_LINE;
+
+typedef struct {
+ UINT32 TimeoutFreq:6; // bit 0:5
+ UINT32 Reserved:1; // bit 6
+ UINT32 TimeoutUnit:1; // bit 7
+ UINT32 BaseClkFreq:8; // bit 8:15
+ UINT32 MaxBlkLen:2; // bit 16:17
+ UINT32 BusWidth8:1; // bit 18
+ UINT32 Adma2:1; // bit 19
+ UINT32 Reserved2:1; // bit 20
+ UINT32 HighSpeed:1; // bit 21
+ UINT32 Sdma:1; // bit 22
+ UINT32 SuspRes:1; // bit 23
+ UINT32 Voltage33:1; // bit 24
+ UINT32 Voltage30:1; // bit 25
+ UINT32 Voltage18:1; // bit 26
+ UINT32 Reserved3:1; // bit 27
+ UINT32 SysBus64:1; // bit 28
+ UINT32 AsyncInt:1; // bit 29
+ UINT32 SlotType:2; // bit 30:31
+ UINT32 Sdr50:1; // bit 32
+ UINT32 Sdr104:1; // bit 33
+ UINT32 Ddr50:1; // bit 34
+ UINT32 Reserved4:1; // bit 35
+ UINT32 DriverTypeA:1; // bit 36
+ UINT32 DriverTypeC:1; // bit 37
+ UINT32 DriverTypeD:1; // bit 38
+ UINT32 DriverType4:1; // bit 39
+ UINT32 TimerCount:4; // bit 40:43
+ UINT32 Reserved5:1; // bit 44
+ UINT32 TuningSDR50:1; // bit 45
+ UINT32 RetuningMod:2; // bit 46:47
+ UINT32 ClkMultiplier:8; // bit 48:55
+ UINT32 Reserved6:7; // bit 56:62
+ UINT32 Hs400:1; // bit 63
+} EMMC_HC_SLOT_CAP;
+
+#pragma pack()
+
+/**
+ Software reset the specified EMMC host controller and enable all interrupts.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcReset (
+ IN UINTN Bar
+ );
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcEnableInterrupt (
+ IN UINTN Bar
+ );
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcGetCapability (
+ IN UINTN Bar,
+ OUT EMMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Detect whether there is a EMMC card attached at the specified EMMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS There is a EMMC card attached.
+ @retval EFI_NO_MEDIA There is not a EMMC card attached.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+EmmcPeimHcCardDetect (
+ IN UINTN Bar
+ );
+
+/**
+ Initial EMMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+EmmcPeimHcInitHost (
+ IN UINTN Bar
+ );
+
+/**
+ Send command SWITCH to the EMMC device to switch the mode of operation of the
+ selected Device or modifies the EXT_CSD registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Access The access mode of SWITCH command.
+ @param[in] Index The offset of the field to be access.
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSwitch (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT8 Access,
+ IN UINT8 Index,
+ IN UINT8 Value,
+ IN UINT8 CmdSet
+ );
+
+/**
+ Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
+ blocks for the following block read/write cmd.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] BlockCount The number of the logical block to access.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimSetBlkCount (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN UINT16 BlockCount
+ );
+
+/**
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
+ to read/write the specified number of blocks.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified EMMC device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcPeimRwMultiBlocks (
+ IN EMMC_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Emmc card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcPeimIdentification (
+ IN EMMC_PEIM_HC_SLOT *Slot
+ );
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the EMMC_TRB instance.
+
+**/
+VOID
+EmmcPeimFreeTrb (
+ IN EMMC_TRB *Trb
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c
new file mode 100644
index 000000000..6a4d18d4d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c
@@ -0,0 +1,236 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for EmmcDxe driver.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeDriverNameTable[] = {
+ { "eng;en", L"Edkii Emmc Device Driver" },
+ { NULL , NULL }
+};
+
+//
+// Controller name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeControllerNameTable[] = {
+ { "eng;en", L"Edkii Emmc Host Controller" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName = {
+ EmmcDxeComponentNameGetDriverName,
+ EmmcDxeComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EmmcDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EmmcDxeComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+EmmcDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mEmmcDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gEmmcDxeComponentName)
+ );
+
+}
+
+/**
+ 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
+EmmcDxeComponentNameGetControllerName (
+ 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;
+ EMMC_DEVICE *Device;
+ EMMC_PARTITION *Partition;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gEmmcDxeDriverBinding.DriverBindingHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = mEmmcDxeControllerNameTable;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gEmmcDxeDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);
+ Device = Partition->Device;
+ ControllerNameTable = Device->ControllerNameTable;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gEmmcDxeComponentName)
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
new file mode 100644
index 000000000..afdc0a57e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
@@ -0,0 +1,2161 @@
+/** @file
+ The helper functions for BlockIo and BlockIo2 protocol.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+/**
+ Nonblocking I/O callback function when the event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncIoCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EMMC_REQUEST *Request;
+ EFI_STATUS Status;
+
+ Status = gBS->CloseEvent (Event);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Request = (EMMC_REQUEST *) Context;
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_INFO, "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
+ Request->Packet.TransactionStatus));
+ DEBUG_CODE_END ();
+
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
+ }
+
+ RemoveEntryList (&Request->Link);
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+}
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the EMMC_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Csd, sizeof (EMMC_CSD));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the EMMC_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCid (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CID *Cid
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Cid, sizeof (EMMC_CID));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EMMC_DEVICE *Device,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0x00000000;
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Set the specified EXT_CSD register field through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Offset The offset of the specified field in EXT_CSD register.
+ @param[in] Value The byte value written to the field specified by Offset.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSetExtCsd (
+ IN EMMC_PARTITION *Partition,
+ IN UINT8 Offset,
+ IN UINT8 Value,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *SetExtCsdReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 CommandArgument;
+ EFI_TPL OldTpl;
+
+ SetExtCsdReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (SetExtCsdReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ SetExtCsdReq->Packet.SdMmcCmdBlk = &SetExtCsdReq->SdMmcCmdBlk;
+ SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;
+ SetExtCsdReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SetExtCsdReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ //
+ // Write the Value to the field specified by Offset.
+ //
+ CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;
+ SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;
+
+ SetExtCsdReq->IsEnd = IsEnd;
+ SetExtCsdReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ SetExtCsdReq,
+ &SetExtCsdReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ SetExtCsdReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (SetExtCsdReq->Event != NULL) {
+ gBS->CloseEvent (SetExtCsdReq->Event);
+ }
+ FreePool (SetExtCsdReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (SetExtCsdReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (SetExtCsdReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the number of blocks for a block read/write cmd through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] BlockNum The number of blocks for transfer.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSetBlkCount (
+ IN EMMC_PARTITION *Partition,
+ IN UINT16 BlockNum,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *SetBlkCntReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ SetBlkCntReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (SetBlkCntReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ SetBlkCntReq->Packet.SdMmcCmdBlk = &SetBlkCntReq->SdMmcCmdBlk;
+ SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;
+ SetBlkCntReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
+ SetBlkCntReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;
+
+ SetBlkCntReq->IsEnd = IsEnd;
+ SetBlkCntReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ SetBlkCntReq,
+ &SetBlkCntReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ SetBlkCntReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (SetBlkCntReq->Event != NULL) {
+ gBS->CloseEvent (SetBlkCntReq->Event);
+ }
+ FreePool (SetBlkCntReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (SetBlkCntReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (SetBlkCntReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read blocks through security protocol cmds with the way of sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Timeout The timeout value, in 100ns units.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcProtocolInOut (
+ IN EMMC_PARTITION *Partition,
+ IN UINT8 SecurityProtocol,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ IN BOOLEAN IsRead,
+ IN UINT64 Timeout,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *ProtocolReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ ProtocolReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (ProtocolReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ ProtocolReq->Packet.SdMmcCmdBlk = &ProtocolReq->SdMmcCmdBlk;
+ ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;
+
+ if (IsRead) {
+ ProtocolReq->Packet.InDataBuffer = PayloadBuffer;
+ ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;
+
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ ProtocolReq->Packet.OutDataBuffer = PayloadBuffer;
+ ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;
+
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);
+ //
+ // Convert to 1 microsecond unit.
+ //
+ ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;
+
+ ProtocolReq->IsEnd = IsEnd;
+ ProtocolReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ ProtocolReq,
+ &ProtocolReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ ProtocolReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (ProtocolReq->Event != NULL) {
+ gBS->CloseEvent (ProtocolReq->Event);
+ }
+ FreePool (ProtocolReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (ProtocolReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (ProtocolReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read/write multiple blocks through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcRwMultiBlocks (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *RwMultiBlkReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ RwMultiBlkReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (RwMultiBlkReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
+ // transfer speed (2.4MB/s).
+ // Refer to eMMC 5.0 spec section 6.9.1 for details.
+ //
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
+
+ if (IsRead) {
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ if (Partition->Device->SectorAddressing) {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);
+ }
+
+ RwMultiBlkReq->IsEnd = IsEnd;
+ RwMultiBlkReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ RwMultiBlkReq,
+ &RwMultiBlkReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ RwMultiBlkReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (RwMultiBlkReq->Event != NULL) {
+ gBS->CloseEvent (RwMultiBlkReq->Event);
+ }
+ FreePool (RwMultiBlkReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (RwMultiBlkReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (RwMultiBlkReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function transfers data from/to EMMC device.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] MediaId The media ID that the read/write request is for.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS The data was read/written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match 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/write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EmmcReadWrite (
+ IN EMMC_PARTITION *Partition,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ UINTN IoAlign;
+ UINT8 PartitionConfig;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ BOOLEAN LastRw;
+
+ Status = EFI_SUCCESS;
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+ LastRw = FALSE;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!IsRead && Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BlockNum = BufferSize / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = BlockNum;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ BlockNum = Remaining;
+ LastRw = TRUE;
+ } else {
+ BlockNum = MaxBlock;
+ }
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferSize = BlockNum * BlockSize;
+ Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_BLKIO,
+ "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ IsRead ? "Read " : "Write", Partition->PartitionType, Lba, BlockNum,
+ (Token != NULL) ? Token->Event : NULL, Status));
+
+ Lba += BlockNum;
+ Buffer = (UINT8*)Buffer + BufferSize;
+ Remaining -= BlockNum;
+ }
+
+ return Status;
+}
+
+/**
+ 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
+EmmcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ PassThru = Partition->Device->Private->PassThru;
+ Status = PassThru->ResetDevice (PassThru, Partition->Device->Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ 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 match 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
+EmmcReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
+ 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_CHANGED The MediaId does not match 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
+EmmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
+ return Status;
+}
+
+/**
+ 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+EmmcResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EMMC_PARTITION *Partition;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ EMMC_REQUEST *Request;
+ EFI_TPL OldTpl;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Partition->Queue);
+ !IsNull (&Partition->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Partition->Queue, Link);
+ RemoveEntryList (Link);
+
+ Request = EMMC_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+EmmcWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ //
+ // Signal event and return directly.
+ //
+ if (Token != NULL && Token->Event != NULL) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId ID of the medium to receive data from.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolInOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize,
+ IN BOOLEAN IsRead
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ UINTN IoAlign;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ UINT8 PartitionConfig;
+
+ Status = EFI_SUCCESS;
+ Partition = EMMC_PARTITION_DATA_FROM_SSP (This);
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+
+ if (PayloadTransferSize != NULL) {
+ *PayloadTransferSize = 0;
+ }
+
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (PayloadBufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((PayloadBufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BlockNum = PayloadBufferSize / BlockSize;
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) PayloadBuffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Security protocol interface is synchronous transfer.
+ // Waiting for async I/O list to be empty before any operation.
+ //
+ while (!IsListEmpty (&Partition->Queue));
+
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = BlockNum;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ BlockNum = Remaining;
+ } else {
+ BlockNum = MaxBlock;
+ }
+
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PayloadBufferSize = BlockNum * BlockSize;
+ Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PayloadBuffer = (UINT8*)PayloadBuffer + PayloadBufferSize;
+ Remaining -= BlockNum;
+ if (PayloadTransferSize != NULL) {
+ *PayloadTransferSize += PayloadBufferSize;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolIn (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ EFI_STATUS Status;
+
+ if ((PayloadTransferSize == NULL) && PayloadBufferSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSecurityProtocolInOut (
+ This,
+ MediaId,
+ Timeout,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer,
+ PayloadTransferSize,
+ TRUE
+ );
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EmmcSecurityProtocolInOut (
+ This,
+ MediaId,
+ Timeout,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer,
+ NULL,
+ FALSE
+ );
+
+ return Status;
+}
+
+/**
+ Set the erase start address through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] StartLba The starting logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockStart (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA StartLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlockStart;
+ EFI_TPL OldTpl;
+
+ EraseBlockStart = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlockStart == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
+ EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
+ EraseBlockStart->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
+ EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
+ } else {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Partition->BlockMedia.BlockSize);
+ }
+
+ EraseBlockStart->IsEnd = IsEnd;
+ EraseBlockStart->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockStart,
+ &EraseBlockStart->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockStart->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockStart->Event != NULL) {
+ gBS->CloseEvent (EraseBlockStart->Event);
+ }
+ FreePool (EraseBlockStart);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockStart != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockStart);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the erase end address through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] EndLba The ending logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockEnd (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA EndLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlockEnd;
+ EFI_TPL OldTpl;
+
+ EraseBlockEnd = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlockEnd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
+ EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
+ EraseBlockEnd->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
+ EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
+ } else {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Partition->BlockMedia.BlockSize);
+ }
+
+ EraseBlockEnd->IsEnd = IsEnd;
+ EraseBlockEnd->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockEnd,
+ &EraseBlockEnd->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockEnd->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockEnd->Event != NULL) {
+ gBS->CloseEvent (EraseBlockEnd->Event);
+ }
+ FreePool (EraseBlockEnd);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockEnd != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockEnd);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Erase specified blocks through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlock (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlock;
+ EFI_TPL OldTpl;
+
+ EraseBlock = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
+ EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
+ EraseBlock->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
+ EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ if ((Device->ExtCsd.SecFeatureSupport & BIT4) != 0) {
+ //
+ // Perform a Trim operation which applies the erase operation to write blocks
+ // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,
+ // Section 6.6.10 and 6.10.4)
+ //
+ EraseBlock->SdMmcCmdBlk.CommandArgument = 1;
+ }
+
+ EraseBlock->IsEnd = IsEnd;
+ EraseBlock->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlock,
+ &EraseBlock->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlock->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlock->Event != NULL) {
+ gBS->CloseEvent (EraseBlock->Event);
+ }
+ FreePool (EraseBlock);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlock != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlock);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Write zeros to specified blocks.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] StartLba The starting logical block address to write zeros.
+ @param[in] Size The size in bytes to fill with zeros. This must be a multiple of
+ the physical block size of the device.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcWriteZeros (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA StartLba,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINT32 MediaId;
+
+ Buffer = AllocateZeroPool (Size);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MediaId = Partition->BlockMedia.MediaId;
+
+ Status = EmmcReadWrite (Partition, MediaId, StartLba, Buffer, Size, FALSE, NULL);
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ EFI_LBA FirstLba;
+ EFI_LBA LastLba;
+ EFI_LBA StartGroupLba;
+ EFI_LBA EndGroupLba;
+ UINT32 EraseGroupSize;
+ UINT32 Remainder;
+ UINTN WriteZeroSize;
+ UINT8 PartitionConfig;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+
+ Status = EFI_SUCCESS;
+ Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ BlockSize = Media->BlockSize;
+ if ((Size % BlockSize) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockNum = Size / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+
+ FirstLba = Lba;
+ LastLba = Lba + BlockNum - 1;
+
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+
+ if ((Device->ExtCsd.SecFeatureSupport & BIT4) == 0) {
+ //
+ // If the Trim operation is not supported by the device, handle the erase
+ // of blocks that do not form a complete erase group separately.
+ //
+ EraseGroupSize = This->EraseLengthGranularity;
+
+ DivU64x32Remainder (FirstLba, EraseGroupSize, &Remainder);
+ StartGroupLba = (Remainder == 0) ? FirstLba : (FirstLba + EraseGroupSize - Remainder);
+
+ DivU64x32Remainder (LastLba + 1, EraseGroupSize, &Remainder);
+ EndGroupLba = LastLba + 1 - Remainder;
+
+ //
+ // If the size to erase is smaller than the erase group size, the whole
+ // erase operation is performed by writing zeros.
+ //
+ if (BlockNum < EraseGroupSize) {
+ Status = EmmcWriteZeros (Partition, FirstLba, Size);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the starting LBA to erase is not aligned with the start of an erase
+ // group, write zeros to erase the data from starting LBA to the end of the
+ // current erase group.
+ //
+ if (StartGroupLba > FirstLba) {
+ WriteZeroSize = (UINTN)(StartGroupLba - FirstLba) * BlockSize;
+ Status = EmmcWriteZeros (Partition, FirstLba, WriteZeroSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // If the ending LBA to erase is not aligned with the end of an erase
+ // group, write zeros to erase the data from the start of the erase group
+ // to the ending LBA.
+ //
+ if (EndGroupLba <= LastLba) {
+ WriteZeroSize = (UINTN)(LastLba + 1 - EndGroupLba) * BlockSize;
+ Status = EmmcWriteZeros (Partition, EndGroupLba, WriteZeroSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Check whether there is erase group to erase.
+ //
+ if (EndGroupLba <= StartGroupLba) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ FirstLba = StartGroupLba;
+ LastLba = EndGroupLba - 1;
+ }
+
+ Status = EmmcEraseBlockStart (Partition, FirstLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
new file mode 100644
index 000000000..62e70ae91
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
@@ -0,0 +1,497 @@
+/** @file
+ Header file for EmmcDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_BLOCK_IO_H_
+#define _EMMC_BLOCK_IO_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
+EmmcReset (
+ 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 match 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
+EmmcReadBlocks (
+ 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_CHANGED The MediaId does not match 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
+EmmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+EmmcResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+EmmcWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId ID of the medium to receive data from.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolInOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize,
+ IN BOOLEAN IsRead
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolIn (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @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_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c
new file mode 100644
index 000000000..e9e31aa2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c
@@ -0,0 +1,134 @@
+/** @file
+ Implement the EFI_DISK_INFO_PROTOCOL interface on EMMC devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] 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 InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+
+ Partition = EMMC_PARTITION_DATA_FROM_DISKINFO (This);
+ Device = Partition->Device;
+
+ if (*InquiryDataSize >= sizeof (Device->Cid)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &Device->Cid, sizeof (Device->Cid));
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *InquiryDataSize = sizeof (Device->Cid);
+
+ return Status;
+}
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] 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
+EmmcDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+EmmcDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h
new file mode 100644
index 000000000..44e691ac3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h
@@ -0,0 +1,109 @@
+/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface on EMMC devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_DISKINFO_H_
+#define _EMMC_DISKINFO_H_
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] 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 InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] 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
+EmmcDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+EmmcDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
new file mode 100644
index 000000000..e9095b904
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
@@ -0,0 +1,1205 @@
+/** @file
+ The EmmcDxe driver is used to manage the EMMC device.
+
+ It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
+ access the EMMC device.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+//
+// EmmcDxe Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding = {
+ EmmcDxeDriverBindingSupported,
+ EmmcDxeDriverBindingStart,
+ EmmcDxeDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for Emmc Partitions.
+//
+EMMC_PARTITION mEmmcPartitionTemplate = {
+ EMMC_PARTITION_SIGNATURE, // Signature
+ FALSE, // Enable
+ EmmcPartitionUnknown, // PartitionType
+ NULL, // Handle
+ NULL, // DevicePath
+ { // BlockIo
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ NULL,
+ EmmcReset,
+ EmmcReadBlocks,
+ EmmcWriteBlocks,
+ EmmcFlushBlocks
+ },
+ { // BlockIo2
+ NULL,
+ EmmcResetEx,
+ EmmcReadBlocksEx,
+ EmmcWriteBlocksEx,
+ EmmcFlushBlocksEx
+ },
+ { // BlockMedia
+ 0, // MediaId
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicPartition
+ FALSE, // ReadOnly
+ FALSE, // WritingCache
+ 0x200, // BlockSize
+ 0, // IoAlign
+ 0 // LastBlock
+ },
+ { // StorageSecurity
+ EmmcSecurityProtocolIn,
+ EmmcSecurityProtocolOut
+ },
+ { // EraseBlock
+ EFI_ERASE_BLOCK_PROTOCOL_REVISION,
+ 1,
+ EmmcEraseBlocks
+ },
+ { // DiskInfo
+ EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,
+ EmmcDiskInfoInquiry,
+ EmmcDiskInfoIdentify,
+ EmmcDiskInfoSenseData,
+ EmmcDiskInfoWhichIde
+ },
+ {
+ NULL,
+ NULL
+ },
+ NULL // Device
+};
+
+/**
+ Decode and print EMMC CSD Register content.
+
+ @param[in] Csd Pointer to EMMC_CSD data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+DumpCsd (
+ IN EMMC_CSD *Csd
+ )
+{
+ DEBUG((DEBUG_INFO, "== Dump Emmc Csd Register==\n"));
+ DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));
+ DEBUG((DEBUG_INFO, " System specification version 0x%x\n", Csd->SpecVers));
+ DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));
+ DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));
+ DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));
+ DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));
+ DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));
+ DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));
+ DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));
+ DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));
+ DEBUG((DEBUG_INFO, " Device size multiplier 0x%x\n", Csd->CSizeMult));
+ DEBUG((DEBUG_INFO, " Erase group size 0x%x\n", Csd->EraseGrpSize));
+ DEBUG((DEBUG_INFO, " Erase group size multiplier 0x%x\n", Csd->EraseGrpMult));
+ DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));
+ DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));
+ DEBUG((DEBUG_INFO, " Manufacturer default ECC 0x%x\n", Csd->DefaultEcc));
+ DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));
+ DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));
+ DEBUG((DEBUG_INFO, " Content protection application 0x%x\n", Csd->ContentProtApp));
+ DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));
+ DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));
+ DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));
+ DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));
+ DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));
+ DEBUG((DEBUG_INFO, " ECC code 0x%x\n", Csd->Ecc));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Decode and print EMMC EXT_CSD Register content.
+
+ @param[in] ExtCsd Pointer to the EMMC_EXT_CSD data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+DumpExtCsd (
+ IN EMMC_EXT_CSD *ExtCsd
+ )
+{
+ DEBUG((DEBUG_INFO, "==Dump Emmc ExtCsd Register==\n"));
+ DEBUG((DEBUG_INFO, " Supported Command Sets 0x%x\n", ExtCsd->CmdSet));
+ DEBUG((DEBUG_INFO, " HPI features 0x%x\n", ExtCsd->HpiFeatures));
+ DEBUG((DEBUG_INFO, " Background operations support 0x%x\n", ExtCsd->BkOpsSupport));
+ DEBUG((DEBUG_INFO, " Background operations status 0x%x\n", ExtCsd->BkopsStatus));
+ DEBUG((DEBUG_INFO, " Number of correctly programmed sectors 0x%x\n", *((UINT32*)&ExtCsd->CorrectlyPrgSectorsNum[0])));
+ DEBUG((DEBUG_INFO, " Initialization time after partitioning 0x%x\n", ExtCsd->IniTimeoutAp));
+ DEBUG((DEBUG_INFO, " TRIM Multiplier 0x%x\n", ExtCsd->TrimMult));
+ DEBUG((DEBUG_INFO, " Secure Feature support 0x%x\n", ExtCsd->SecFeatureSupport));
+ DEBUG((DEBUG_INFO, " Secure Erase Multiplier 0x%x\n", ExtCsd->SecEraseMult));
+ DEBUG((DEBUG_INFO, " Secure TRIM Multiplier 0x%x\n", ExtCsd->SecTrimMult));
+ DEBUG((DEBUG_INFO, " Boot information 0x%x\n", ExtCsd->BootInfo));
+ DEBUG((DEBUG_INFO, " Boot partition size 0x%x\n", ExtCsd->BootSizeMult));
+ DEBUG((DEBUG_INFO, " Access size 0x%x\n", ExtCsd->AccSize));
+ DEBUG((DEBUG_INFO, " High-capacity erase unit size 0x%x\n", ExtCsd->HcEraseGrpSize));
+ DEBUG((DEBUG_INFO, " High-capacity erase timeout 0x%x\n", ExtCsd->EraseTimeoutMult));
+ DEBUG((DEBUG_INFO, " Reliable write sector count 0x%x\n", ExtCsd->RelWrSecC));
+ DEBUG((DEBUG_INFO, " High-capacity write protect group size 0x%x\n", ExtCsd->HcWpGrpSize));
+ DEBUG((DEBUG_INFO, " Sleep/awake timeout 0x%x\n", ExtCsd->SATimeout));
+ DEBUG((DEBUG_INFO, " Sector Count 0x%x\n", *((UINT32*)&ExtCsd->SecCount[0])));
+ DEBUG((DEBUG_INFO, " Partition switching timing 0x%x\n", ExtCsd->PartitionSwitchTime));
+ DEBUG((DEBUG_INFO, " Out-of-interrupt busy timing 0x%x\n", ExtCsd->OutOfInterruptTime));
+ DEBUG((DEBUG_INFO, " I/O Driver Strength 0x%x\n", ExtCsd->DriverStrength));
+ DEBUG((DEBUG_INFO, " Device type 0x%x\n", ExtCsd->DeviceType));
+ DEBUG((DEBUG_INFO, " CSD STRUCTURE 0x%x\n", ExtCsd->CsdStructure));
+ DEBUG((DEBUG_INFO, " Extended CSD revision 0x%x\n", ExtCsd->ExtCsdRev));
+ DEBUG((DEBUG_INFO, " Command set 0x%x\n", ExtCsd->CmdSet));
+ DEBUG((DEBUG_INFO, " Command set revision 0x%x\n", ExtCsd->CmdSetRev));
+ DEBUG((DEBUG_INFO, " Power class 0x%x\n", ExtCsd->PowerClass));
+ DEBUG((DEBUG_INFO, " High-speed interface timing 0x%x\n", ExtCsd->HsTiming));
+ DEBUG((DEBUG_INFO, " Bus width mode 0x%x\n", ExtCsd->BusWidth));
+ DEBUG((DEBUG_INFO, " Erased memory content 0x%x\n", ExtCsd->ErasedMemCont));
+ DEBUG((DEBUG_INFO, " Partition configuration 0x%x\n", ExtCsd->PartitionConfig));
+ DEBUG((DEBUG_INFO, " Boot config protection 0x%x\n", ExtCsd->BootConfigProt));
+ DEBUG((DEBUG_INFO, " Boot bus Conditions 0x%x\n", ExtCsd->BootBusConditions));
+ DEBUG((DEBUG_INFO, " High-density erase group definition 0x%x\n", ExtCsd->EraseGroupDef));
+ DEBUG((DEBUG_INFO, " Boot write protection status register 0x%x\n", ExtCsd->BootWpStatus));
+ DEBUG((DEBUG_INFO, " Boot area write protection register 0x%x\n", ExtCsd->BootWp));
+ DEBUG((DEBUG_INFO, " User area write protection register 0x%x\n", ExtCsd->UserWp));
+ DEBUG((DEBUG_INFO, " FW configuration 0x%x\n", ExtCsd->FwConfig));
+ DEBUG((DEBUG_INFO, " RPMB Size 0x%x\n", ExtCsd->RpmbSizeMult));
+ DEBUG((DEBUG_INFO, " H/W reset function 0x%x\n", ExtCsd->RstFunction));
+ DEBUG((DEBUG_INFO, " Partitioning Support 0x%x\n", ExtCsd->PartitioningSupport));
+ DEBUG((DEBUG_INFO, " Max Enhanced Area Size 0x%02x%02x%02x\n", \
+ ExtCsd->MaxEnhSizeMult[2], ExtCsd->MaxEnhSizeMult[1], ExtCsd->MaxEnhSizeMult[0]));
+ DEBUG((DEBUG_INFO, " Partitions attribute 0x%x\n", ExtCsd->PartitionsAttribute));
+ DEBUG((DEBUG_INFO, " Partitioning Setting 0x%x\n", ExtCsd->PartitionSettingCompleted));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 1 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[2], ExtCsd->GpSizeMult[1], ExtCsd->GpSizeMult[0]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 2 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[5], ExtCsd->GpSizeMult[4], ExtCsd->GpSizeMult[3]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 3 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[8], ExtCsd->GpSizeMult[7], ExtCsd->GpSizeMult[6]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 4 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[11], ExtCsd->GpSizeMult[10], ExtCsd->GpSizeMult[9]));
+ DEBUG((DEBUG_INFO, " Enhanced User Data Area Size 0x%02x%02x%02x\n", \
+ ExtCsd->EnhSizeMult[2], ExtCsd->EnhSizeMult[1], ExtCsd->EnhSizeMult[0]));
+ DEBUG((DEBUG_INFO, " Enhanced User Data Start Address 0x%x\n", *((UINT32*)&ExtCsd->EnhStartAddr[0])));
+ DEBUG((DEBUG_INFO, " Bad Block Management mode 0x%x\n", ExtCsd->SecBadBlkMgmnt));
+ DEBUG((DEBUG_INFO, " Native sector size 0x%x\n", ExtCsd->NativeSectorSize));
+ DEBUG((DEBUG_INFO, " Sector size emulation 0x%x\n", ExtCsd->UseNativeSector));
+ DEBUG((DEBUG_INFO, " Sector size 0x%x\n", ExtCsd->DataSectorSize));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get EMMC device model name.
+
+ @param[in, out] Device The pointer to the EMMC_DEVICE data structure.
+ @param[in] Cid Pointer to EMMC_CID data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+GetEmmcModelName (
+ IN OUT EMMC_DEVICE *Device,
+ IN EMMC_CID *Cid
+ )
+{
+ CHAR8 String[EMMC_MODEL_NAME_MAX_LEN];
+
+ ZeroMem (String, sizeof (String));
+ CopyMem (String, &Cid->OemId, sizeof (Cid->OemId));
+ String[sizeof (Cid->OemId)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));
+ String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));
+
+ AsciiStrToUnicodeStrS (String, Device->ModelName, sizeof (Device->ModelName) / sizeof (Device->ModelName[0]));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Discover all partitions in the EMMC device.
+
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.
+
+ @retval EFI_SUCCESS All the partitions in the device are successfully enumerated.
+ @return Others Some error occurs when enumerating the partitions.
+
+**/
+EFI_STATUS
+DiscoverAllPartitions (
+ IN EMMC_DEVICE *Device
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_CSD *Csd;
+ EMMC_CID *Cid;
+ EMMC_EXT_CSD *ExtCsd;
+ UINT8 Slot;
+ UINT64 Capacity;
+ UINT32 DevStatus;
+ UINT8 Index;
+ UINT32 SecCount;
+ UINT32 GpSizeMult;
+
+ Slot = Device->Slot;
+
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Deselect the device to force it enter stby mode before getting CSD
+ // register content.
+ // Note here we don't judge return status as some EMMC devices return
+ // error but the state has been stby.
+ //
+ EmmcSelect (Device, 0);
+
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Csd = &Device->Csd;
+ Status = EmmcGetCsd (Device, Slot + 1, Csd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DumpCsd (Csd);
+
+ if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) {
+ Device->SectorAddressing = TRUE;
+ } else {
+ Device->SectorAddressing = FALSE;
+ }
+
+ Cid = &Device->Cid;
+ Status = EmmcGetCid (Device, Slot + 1, Cid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSelect (Device, Slot + 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ExtCsd = &Device->ExtCsd;
+ Status = EmmcGetExtCsd (Device, ExtCsd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DumpExtCsd (ExtCsd);
+
+ if (ExtCsd->ExtCsdRev < 5) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {
+ Partition = &Device->Partition[Index];
+ CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION));
+ Partition->Device = Device;
+ InitializeListHead (&Partition->Queue);
+ Partition->BlockIo.Media = &Partition->BlockMedia;
+ Partition->BlockIo2.Media = &Partition->BlockMedia;
+ Partition->PartitionType = Index;
+ Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;
+ Partition->BlockMedia.BlockSize = 0x200;
+ Partition->BlockMedia.LastBlock = 0x00;
+ Partition->BlockMedia.RemovableMedia = FALSE;
+ Partition->BlockMedia.MediaPresent = TRUE;
+ Partition->BlockMedia.LogicalPartition = FALSE;
+
+ switch (Index) {
+ case EmmcPartitionUserData:
+ SecCount = *(UINT32*)&ExtCsd->SecCount;
+ Capacity = MultU64x32 ((UINT64) SecCount, 0x200);
+ break;
+ case EmmcPartitionBoot1:
+ case EmmcPartitionBoot2:
+ Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionRPMB:
+ Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionGP1:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP2:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP3:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP4:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Capacity != 0) {
+ Partition->Enable = TRUE;
+ Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;
+ }
+
+ if ((ExtCsd->EraseGroupDef & BIT0) == 0) {
+ if (Csd->WriteBlLen < 9) {
+ Partition->EraseBlock.EraseLengthGranularity = 1;
+ } else {
+ Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) * (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9));
+ }
+ } else {
+ Partition->EraseBlock.EraseLengthGranularity = 1024 * ExtCsd->HcEraseGrpSize;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install BlkIo, BlkIo2 and Ssp protocols for the specified partition in the EMMC device.
+
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.
+ @param[in] Index The index of the partition.
+
+ @retval EFI_SUCCESS The protocols are installed successfully.
+ @retval Others Some error occurs when installing the protocols.
+
+**/
+EFI_STATUS
+InstallProtocolOnPartition (
+ IN EMMC_DEVICE *Device,
+ IN UINT8 Index
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ CONTROLLER_DEVICE_PATH ControlNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+
+ //
+ // Build device path
+ //
+ ParentDevicePath = Device->DevicePath;
+
+ ControlNode.Header.Type = HARDWARE_DEVICE_PATH;
+ ControlNode.Header.SubType = HW_CONTROLLER_DP;
+ SetDevicePathNodeLength (&ControlNode.Header, sizeof (CONTROLLER_DEVICE_PATH));
+ ControlNode.ControllerNumber = Index;
+
+ DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&ControlNode);
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ goto Error;
+ }
+
+ Partition = &Device->Partition[Index];
+ Partition->DevicePath = DevicePath;
+ if (Partition->Enable) {
+ //
+ // Install BlkIo/BlkIo2/Ssp for the specified partition
+ //
+ if (Partition->PartitionType != EmmcPartitionRPMB) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Partition->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (((Partition->PartitionType == EmmcPartitionUserData) ||
+ (Partition->PartitionType == EmmcPartitionBoot1) ||
+ (Partition->PartitionType == EmmcPartitionBoot2)) &&
+ ((Device->Csd.Ccc & BIT10) != 0)) {
+ Status = gBS->InstallProtocolInterface (
+ &Partition->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Partition->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Partition->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ goto Error;
+ }
+ }
+
+ gBS->OpenProtocol (
+ Device->Private->Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &(Device->Private->PassThru),
+ Device->Private->DriverBindingHandle,
+ Partition->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Error:
+ if (EFI_ERROR (Status) && (DevicePath != NULL)) {
+ FreePool (DevicePath);
+ }
+
+ return Status;
+}
+
+/**
+ Scan EMMC Bus to discover the device.
+
+ @param[in] Private The EMMC driver private data structure.
+ @param[in] Slot The slot number to check device present.
+ @param[in] RemainingDevicePath The pointer to the remaining device path.
+
+ @retval EFI_SUCCESS Successfully to discover the device and attach
+ SdMmcIoProtocol to it.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+ @retval EFI_ALREADY_STARTED The device was discovered before.
+ @retval Others Fail to discover the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiscoverEmmcDevice (
+ IN EMMC_DRIVER_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingEmmcDevPath;
+ EFI_DEV_PATH *Node;
+ EFI_HANDLE DeviceHandle;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT8 Index;
+
+ Device = NULL;
+ DevicePath = NULL;
+ NewDevicePath = NULL;
+ RemainingDevicePath = NULL;
+ PassThru = Private->PassThru;
+ Device = &Private->Device[Slot];
+
+ //
+ // Build Device Path to check if the EMMC device present at the slot.
+ //
+ Status = PassThru->BuildDevicePath (
+ PassThru,
+ Slot,
+ &DevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (DevicePath->SubType != MSG_EMMC_DP) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+ NewDevicePath = AppendDevicePathNode (
+ Private->ParentDevicePath,
+ DevicePath
+ );
+ if (NewDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ DeviceHandle = NULL;
+ RemainingEmmcDevPath = NewDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingEmmcDevPath, &DeviceHandle);
+ //
+ // The device path to the EMMC device doesn't exist. It means the corresponding device private data hasn't been initialized.
+ //
+ if (EFI_ERROR (Status) || (DeviceHandle == NULL) || !IsDevicePathEnd (RemainingEmmcDevPath)) {
+ Device->DevicePath = NewDevicePath;
+ Device->Slot = Slot;
+ Device->Private = Private;
+ //
+ // Expose user area in the Sd memory card to upper layer.
+ //
+ Status = DiscoverAllPartitions (Device);
+ if (EFI_ERROR(Status)) {
+ FreePool (NewDevicePath);
+ goto Error;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Device->DevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool (NewDevicePath);
+ goto Error;
+ }
+
+ Device->ControllerNameTable = NULL;
+ GetEmmcModelName (Device, &Device->Cid);
+ AddUnicodeString2 (
+ "eng",
+ gEmmcDxeComponentName.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gEmmcDxeComponentName2.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ FALSE
+ );
+ }
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // Expose all partitions in the Emmc device to upper layer.
+ //
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {
+ InstallProtocolOnPartition (Device, Index);
+ }
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // Enumerate the specified partition
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ if ((DevicePathType (&Node->DevPath) != HARDWARE_DEVICE_PATH) ||
+ (DevicePathSubType (&Node->DevPath) != HW_CONTROLLER_DP) ||
+ (DevicePathNodeLength (&Node->DevPath) != sizeof (CONTROLLER_DEVICE_PATH))) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+
+ Index = (UINT8)Node->Controller.ControllerNumber;
+ if (Index >= EMMC_MAX_PARTITIONS) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+
+ Status = InstallProtocolOnPartition (Device, Index);
+ }
+
+Error:
+ FreePool (DevicePath);
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingSupported (
+ 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_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT8 Slot;
+
+ //
+ // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Test RemainingDevicePath is valid or not.
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ 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_GET_PROTOCOL
+ );
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+ UINT8 Slot;
+
+ Private = NULL;
+ PassThru = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Check EFI_ALREADY_STARTED to reuse the original EMMC_DRIVER_PRIVATE_DATA.
+ //
+ if (Status != EFI_ALREADY_STARTED) {
+ Private = AllocateZeroPool (sizeof (EMMC_DRIVER_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->PassThru = PassThru;
+ Private->Controller = Controller;
+ Private->ParentDevicePath = ParentDevicePath;
+ Private->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ Private
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ if (RemainingDevicePath == NULL) {
+ Slot = 0xFF;
+ while (TRUE) {
+ Status = PassThru->GetNextSlot (PassThru, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Cannot find more legal slots.
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ Status = DiscoverEmmcDevice (Private, Slot, NULL);
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ break;
+ }
+ }
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (!EFI_ERROR (Status)) {
+ Status = DiscoverEmmcDevice (Private, Slot, NextDevicePathNode (RemainingDevicePath));
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private,
+ NULL
+ );
+ FreePool (Private);
+ }
+ }
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+EmmcDxeDriverBindingStop (
+ 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_DEVICE_PATH_PROTOCOL *DevicePath;
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+ EMMC_DEVICE *Device;
+ EMMC_PARTITION *Partition;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ EMMC_REQUEST *Request;
+
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ if (NumberOfChildren == 0) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (Index = 0; Index < EMMC_MAX_DEVICES; Index++) {
+ Device = &Private->Device[Index];
+ Status = gBS->OpenProtocol (
+ Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (DevicePath == Device->DevicePath);
+ gBS->UninstallProtocolInterface (
+ Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ DevicePath
+ );
+ FreePool (Device->DevicePath);
+ }
+
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (Private);
+
+ return EFI_SUCCESS;
+ }
+
+ 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)) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ if (BlockIo != NULL) {
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);
+ } else {
+ ASSERT (BlockIo2 != NULL);
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (BlockIo2);
+ }
+
+ for (Link = GetFirstNode (&Partition->Queue);
+ !IsNull (&Partition->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Partition->Queue, Link);
+
+ RemoveEntryList (Link);
+ Request = EMMC_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **)&Partition->Device->Private->PassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ continue;
+ }
+
+ //
+ // If Storage Security Command Protocol is installed, then uninstall this protocol.
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **) &StorageSecurity,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallProtocolInterface (
+ ChildHandleBuffer[Index],
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &Partition->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &Partition->Device->Private->PassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ FreePool (Partition->DevicePath);
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module EmmcDxe. 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 errors occur when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEmmcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gEmmcDxeDriverBinding,
+ ImageHandle,
+ &gEmmcDxeComponentName,
+ &gEmmcDxeComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
new file mode 100644
index 000000000..5ecce41de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
@@ -0,0 +1,501 @@
+/** @file
+ Header file for EmmcDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_DXE_H_
+#define _EMMC_DXE_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Emmc.h>
+
+#include <Protocol/SdMmcPassThru.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/EraseBlock.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/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "EmmcBlockIo.h"
+#include "EmmcDiskInfo.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2;
+
+#define EMMC_PARTITION_SIGNATURE SIGNATURE_32 ('E', 'm', 'm', 'P')
+
+#define EMMC_PARTITION_DATA_FROM_BLKIO(a) \
+ CR(a, EMMC_PARTITION, BlockIo, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_BLKIO2(a) \
+ CR(a, EMMC_PARTITION, BlockIo2, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_SSP(a) \
+ CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_ERASEBLK(a) \
+ CR(a, EMMC_PARTITION, EraseBlock, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_DISKINFO(a) \
+ CR(a, EMMC_PARTITION, DiskInfo, EMMC_PARTITION_SIGNATURE)
+
+//
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
+//
+#define EMMC_GENERIC_TIMEOUT 2500 * 1000
+
+#define EMMC_REQUEST_SIGNATURE SIGNATURE_32 ('E', 'm', 'R', 'e')
+
+typedef struct _EMMC_DEVICE EMMC_DEVICE;
+typedef struct _EMMC_DRIVER_PRIVATE_DATA EMMC_DRIVER_PRIVATE_DATA;
+
+//
+// Asynchronous I/O request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ BOOLEAN IsEnd;
+
+ EFI_BLOCK_IO2_TOKEN *Token;
+ EFI_EVENT Event;
+} EMMC_REQUEST;
+
+#define EMMC_REQUEST_FROM_LINK(a) \
+ CR(a, EMMC_REQUEST, Link, EMMC_REQUEST_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ BOOLEAN Enable;
+ EMMC_PARTITION_TYPE PartitionType;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+ EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+
+ LIST_ENTRY Queue;
+
+ EMMC_DEVICE *Device;
+} EMMC_PARTITION;
+
+//
+// Up to 6 slots per EMMC PCI host controller
+//
+#define EMMC_MAX_DEVICES 6
+//
+// Up to 8 partitions per EMMC device.
+//
+#define EMMC_MAX_PARTITIONS 8
+#define EMMC_MODEL_NAME_MAX_LEN 32
+
+struct _EMMC_DEVICE {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT8 Slot;
+ BOOLEAN SectorAddressing;
+
+ EMMC_PARTITION Partition[EMMC_MAX_PARTITIONS];
+ EMMC_CSD Csd;
+ EMMC_CID Cid;
+ EMMC_EXT_CSD ExtCsd;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ //
+ // The model name consists of three fields in CID register
+ // 1) OEM/Application ID (2 bytes)
+ // 2) Product Name (5 bytes)
+ // 3) Product Serial Number (4 bytes)
+ // The delimiters of these fields are whitespace.
+ //
+ CHAR16 ModelName[EMMC_MODEL_NAME_MAX_LEN];
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+} ;
+
+//
+// EMMC DXE driver private data structure
+//
+struct _EMMC_DRIVER_PRIVATE_DATA {
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_HANDLE Controller;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_HANDLE DriverBindingHandle;
+
+ EMMC_DEVICE Device[EMMC_MAX_DEVICES];
+} ;
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+EmmcDxeDriverBindingStop (
+ 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
+EmmcDxeComponentNameGetDriverName (
+ 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
+EmmcDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca
+ );
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ );
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the EMMC_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ );
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the EMMC_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCid (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CID *Cid
+ );
+
+/**
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EMMC_DEVICE *Device,
+ OUT EMMC_EXT_CSD *ExtCsd
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
new file mode 100644
index 000000000..2afe4f42a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
@@ -0,0 +1,65 @@
+## @file
+# EmmcDxe driver is used to manage the EMMC device.
+#
+# It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
+# access the EMMC device.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EmmcDxe
+ MODULE_UNI_FILE = EmmcDxe.uni
+ FILE_GUID = 2145F72F-E6F1-4440-A828-59DC9AAB5F89
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEmmcDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gEmmcDxeDriverBinding
+# COMPONENT_NAME = gEmmcDxeComponentName
+# COMPONENT_NAME2 = gEmmcDxeComponentName2
+#
+
+[Sources.common]
+ ComponentName.c
+ EmmcDxe.c
+ EmmcDxe.h
+ EmmcBlockIo.c
+ EmmcBlockIo.h
+ EmmcDiskInfo.c
+ EmmcDiskInfo.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiSdMmcPassThruProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEraseBlockProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni
new file mode 100644
index 000000000..b47ce27bd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni
@@ -0,0 +1,15 @@
+// /** @file
+// EMMC device driver to manage the EMMC device and provide interface for upper layer
+// access.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EMMC device driver to manage the EMMC device and provide interface for upper layer access"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo/BlockIo2/StorageSecurity protocols for the EMMC device partitions."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni
new file mode 100644
index 000000000..0f75ea64c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EmmcDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EMMC Device Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c
new file mode 100644
index 000000000..63ad6ce46
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c
@@ -0,0 +1,242 @@
+/** @file
+ The DMA memory help function.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdBlockIoPei.h"
+
+EDKII_IOMMU_PPI *mIoMmu;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Map (
+ mIoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&mIoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
new file mode 100644
index 000000000..1d53fcd23
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
@@ -0,0 +1,653 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdBlockIoPei.h"
+
+//
+// Template for SD HC Slot Data.
+//
+SD_PEIM_HC_SLOT gSdHcSlotTemplate = {
+ SD_PEIM_SLOT_SIG, // Signature
+ { // Media
+ MSG_SD_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x200,
+ 0
+ },
+ 0, // SdHcBase
+ { // Capability
+ 0,
+ },
+ { // Csd
+ 0,
+ },
+ TRUE, // SectorAddressing
+ NULL // Private
+};
+
+//
+// Template for SD HC Private Data.
+//
+SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = {
+ SD_PEIM_SIG, // Signature
+ NULL, // Pool
+ { // BlkIoPpi
+ SdBlockIoPeimGetDeviceNo,
+ SdBlockIoPeimGetMediaInfo,
+ SdBlockIoPeimReadBlocks
+ },
+ { // BlkIo2Ppi
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
+ SdBlockIoPeimGetDeviceNo2,
+ SdBlockIoPeimGetMediaInfo2,
+ SdBlockIoPeimReadBlocks2
+ },
+ { // BlkIoPpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+ },
+ { // BlkIo2PpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ SdBlockIoPeimEndOfPei
+ },
+ { // Slot
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ },
+ {
+ 0,
+ }
+ },
+ 0, // SlotNum
+ 0 // TotalBlkIoDevices
+};
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+ *NumberBlockDevices = Private->TotalBlkIoDevices;
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MediaInfo->DeviceType = SD;
+ MediaInfo->MediaPresent = TRUE;
+ MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock;
+ MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
+
+ 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, 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
+SdBlockIoPeimReadBlocks (
+ 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_STATUS Status;
+ UINT32 BlockSize;
+ UINTN NumberOfBlocks;
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+
+ Status = EFI_SUCCESS;
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Check parameters
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = NumberOfBlocks;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ NumberOfBlocks = Remaining;
+ } else {
+ NumberOfBlocks = MaxBlock;
+ }
+
+ BufferSize = NumberOfBlocks * BlockSize;
+ if (NumberOfBlocks != 1) {
+ Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
+ } else {
+ Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StartLBA += NumberOfBlocks;
+ Buffer = (UINT8*)Buffer + BufferSize;
+ Remaining -= NumberOfBlocks;
+ }
+ return Status;
+}
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+ *NumberBlockDevices = Private->TotalBlkIoDevices;
+
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = SdBlockIoPeimGetMediaInfo (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ &Media
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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, 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
+SdBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = SdBlockIoPeimReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+ return Status;
+}
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+
+ if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
+ SdPeimFreeMemPool (Private->Pool);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user code starts with this function.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The driver is successfully initialized.
+ @retval Others Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdBlockIoPeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
+ UINT32 Index;
+ UINTN *MmioBase;
+ UINT8 BarNum;
+ UINT8 SlotNum;
+ UINT8 Controller;
+ UINT64 Capacity;
+ SD_HC_SLOT_CAP Capability;
+ SD_PEIM_HC_SLOT *Slot;
+ SD_CSD *Csd;
+ SD_CSD2 *Csd2;
+ UINT32 CSize;
+ UINT32 CSizeMul;
+ UINT32 ReadBlLen;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // locate Sd host controller PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SdMmcHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IoMmuInit ();
+
+ Controller = 0;
+ MmioBase = NULL;
+ while (TRUE) {
+ Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (BarNum == 0) {
+ Controller++;
+ continue;
+ }
+
+ Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;
+ Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
+ //
+ // Initialize the memory pool which will be used in all transactions.
+ //
+ Status = SdPeimInitMemPool (Private);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ for (Index = 0; Index < BarNum; Index++) {
+ Status = SdPeimHcGetCapability (MmioBase[Index], &Capability);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (Capability.SlotType != 0x1) {
+ DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
+ Status = EFI_UNSUPPORTED;
+ continue;
+ }
+
+ Status = SdPeimHcReset (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = SdPeimHcCardDetect (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = SdPeimHcInitHost (MmioBase[Index]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ SlotNum = Private->SlotNum;
+ Slot = &Private->Slot[SlotNum];
+ CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT));
+ Slot->Private = Private;
+ Slot->SdHcBase = MmioBase[Index];
+ CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
+
+ Status = SdPeimIdentification (Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Csd = &Slot->Csd;
+ if (Csd->CsdStructure == 0) {
+ Slot->SectorAddressing = FALSE;
+ CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
+ CSizeMul = (1 << (Csd->CSizeMul + 2));
+ ReadBlLen = (1 << (Csd->ReadBlLen));
+ Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
+ } else {
+ Slot->SectorAddressing = TRUE;
+ Csd2 = (SD_CSD2*)(VOID*)Csd;
+ CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
+ Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
+ }
+
+ Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1;
+
+ Private->TotalBlkIoDevices++;
+ Private->SlotNum++;
+ }
+
+ Controller++;
+ if (!EFI_ERROR (Status)) {
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+ PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+ } else {
+ if (Private->Pool->Head != NULL) {
+ SdPeimFreeMemPool (Private->Pool);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h
new file mode 100644
index 000000000..7fd6dba92
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h
@@ -0,0 +1,510 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_BLOCK_IO_PEI_H_
+#define _SD_BLOCK_IO_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/SdMmcHostController.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <IndustryStandard/Sd.h>
+
+typedef struct _SD_PEIM_HC_PRIVATE_DATA SD_PEIM_HC_PRIVATE_DATA;
+typedef struct _SD_PEIM_HC_SLOT SD_PEIM_HC_SLOT;
+typedef struct _SD_TRB SD_TRB;
+
+#include "SdHci.h"
+#include "SdHcMem.h"
+
+#define SD_PEIM_SIG SIGNATURE_32 ('S', 'D', 'C', 'P')
+#define SD_PEIM_SLOT_SIG SIGNATURE_32 ('S', 'D', 'C', 'S')
+
+#define SD_PEIM_MAX_SLOTS 6
+
+struct _SD_PEIM_HC_SLOT {
+ UINT32 Signature;
+ EFI_PEI_BLOCK_IO2_MEDIA Media;
+
+ UINTN SdHcBase;
+ SD_HC_SLOT_CAP Capability;
+ SD_CSD Csd;
+ BOOLEAN SectorAddressing;
+ SD_PEIM_HC_PRIVATE_DATA *Private;
+};
+
+struct _SD_PEIM_HC_PRIVATE_DATA {
+ UINT32 Signature;
+ SD_PEIM_MEM_POOL *Pool;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+
+ //
+ // EndOfPei callback is used to do the cleanups before exit of PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ SD_PEIM_HC_SLOT Slot[SD_PEIM_MAX_SLOTS];
+ UINT8 SlotNum;
+ UINT8 TotalBlkIoDevices;
+};
+
+#define SD_TIMEOUT MultU64x32((UINT64)(3), 1000000)
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIoPpi, SD_PEIM_SIG)
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, SD_PEIM_SIG)
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, SD_PEIM_SIG)
+
+struct _SD_TRB {
+ SD_PEIM_HC_SLOT *Slot;
+ UINT16 BlockSize;
+
+ SD_COMMAND_PACKET *Packet;
+ VOID *Data;
+ UINT32 DataLen;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS DataPhy;
+ VOID *DataMap;
+ SD_HC_TRANSFER_MODE Mode;
+
+ UINT64 Timeout;
+
+ SD_HC_ADMA_DESC_LINE *AdmaDesc;
+ UINTN AdmaDescSize;
+};
+
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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, 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
+SdBlockIoPeimReadBlocks (
+ 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
+ );
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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, 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
+SdBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Sd Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+SdPeimInitMemPool (
+ IN SD_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+SdPeimFreeMemPool (
+ IN SD_PEIM_MEM_POOL *Pool
+ );
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+SdPeimAllocateMem (
+ IN SD_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+SdPeimFreeMem (
+ IN SD_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SdBlockIoPeimEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
new file mode 100644
index 000000000..2647192e3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
@@ -0,0 +1,60 @@
+## @file
+# Description file for the SD memory card Peim driver.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdBlockIoPei
+ MODULE_UNI_FILE = SdBlockIoPei.uni
+ FILE_GUID = 17851FBF-45C4-4ff7-A2A0-C3B12D63C27E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeSdBlockIoPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ SdBlockIoPei.c
+ SdBlockIoPei.h
+ SdHci.c
+ SdHci.h
+ SdHcMem.c
+ SdHcMem.h
+ DmaMem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SdBlockIoPeiExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni
new file mode 100644
index 000000000..d2de43e5e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// The SdBlockIoPei driver is used to support recovery from SD memory card device.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from SD memory card devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The SdBlockIoPei driver is used to support recovery from SD memory card device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni
new file mode 100644
index 000000000..1bbdb8c71
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SdBlockIoPei Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SD BlockIo Peim for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
new file mode 100644
index 000000000..fb043c19f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
@@ -0,0 +1,429 @@
+/** @file
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdBlockIoPei.h"
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+SD_PEIM_MEM_BLOCK *
+SdPeimAllocMemBlock (
+ IN UINTN Pages
+ )
+{
+ SD_PEIM_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Block = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK));
+
+ //
+ // each bit in the bit array represents SD_PEIM_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);
+
+ Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);
+
+ Block->Bits = (UINT8*)(UINTN)TempPtr;
+
+ Status = IoMmuAllocateBuffer (
+ Pages,
+ &BufHost,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
+
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+}
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+SdPeimFreeMemBlock (
+ IN SD_PEIM_MEM_POOL *Pool,
+ IN SD_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+}
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+SdPeimAllocMemFromBlock (
+ IN SD_PEIM_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consecutive number of zero bit.
+ //
+ if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ SD_PEIM_NEXT_BIT (Byte, Bit);
+
+ } else {
+ SD_PEIM_NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) SD_PEIM_MEM_BIT (Bit));
+ SD_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+SdPeimInsertMemBlockToPool (
+ IN SD_PEIM_MEM_BLOCK *Head,
+ IN SD_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+SdPeimIsMemBlockEmpty (
+ IN SD_PEIM_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Sd Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+SdPeimInitMemPool (
+ IN SD_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ SD_PEIM_MEM_POOL *Pool;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Pool = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));
+
+ Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);
+
+ Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Pool = Pool;
+ return EFI_SUCCESS;
+}
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+SdPeimFreeMemPool (
+ IN SD_PEIM_MEM_POOL *Pool
+ )
+{
+ SD_PEIM_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ SdPeimFreeMemBlock (Pool, Block);
+ }
+
+ SdPeimFreeMemBlock (Pool, Pool->Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+SdPeimAllocateMem (
+ IN SD_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ SD_PEIM_MEM_BLOCK *Head;
+ SD_PEIM_MEM_BLOCK *Block;
+ SD_PEIM_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = SD_PEIM_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = SD_PEIM_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = SdPeimAllocMemBlock (Pages);
+ if (NewBlock == NULL) {
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ SdPeimInsertMemBlockToPool (Head, NewBlock);
+ Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+SdPeimFreeMem (
+ IN SD_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ SD_PEIM_MEM_BLOCK *Head;
+ SD_PEIM_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = SD_PEIM_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {
+ ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));
+ SD_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {
+ SdPeimFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h
new file mode 100644
index 000000000..c6bda2d1e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h
@@ -0,0 +1,56 @@
+/** @file
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_PEIM_MEM_H_
+#define _SD_PEIM_MEM_H_
+
+#define SD_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
+
+#define SD_PEIM_MEM_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & SD_PEIM_MEM_BIT(Bit)) == SD_PEIM_MEM_BIT(Bit)))
+
+typedef struct _SD_PEIM_MEM_BLOCK SD_PEIM_MEM_BLOCK;
+
+struct _SD_PEIM_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ SD_PEIM_MEM_BLOCK *Next;
+};
+
+typedef struct _SD_PEIM_MEM_POOL {
+ SD_PEIM_MEM_BLOCK *Head;
+} SD_PEIM_MEM_POOL;
+
+//
+// Memory allocation unit, note that the value must meet SD spec alignment requirement.
+//
+#define SD_PEIM_MEM_UNIT 128
+
+#define SD_PEIM_MEM_UNIT_MASK (SD_PEIM_MEM_UNIT - 1)
+#define SD_PEIM_MEM_DEFAULT_PAGES 16
+
+#define SD_PEIM_MEM_ROUND(Len) (((Len) + SD_PEIM_MEM_UNIT_MASK) & (~SD_PEIM_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define SD_PEIM_NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
new file mode 100644
index 000000000..756c3063b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
@@ -0,0 +1,2957 @@
+/** @file
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdBlockIoPei.h"
+
+/**
+ Read/Write specified SD host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimHcRwMmio (
+ IN UINTN Address,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ )
+{
+ if ((Address == 0) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Count) {
+ case 1:
+ if (Read) {
+ *(UINT8*)Data = MmioRead8 (Address);
+ } else {
+ MmioWrite8 (Address, *(UINT8*)Data);
+ }
+ break;
+ case 2:
+ if (Read) {
+ *(UINT16*)Data = MmioRead16 (Address);
+ } else {
+ MmioWrite16 (Address, *(UINT16*)Data);
+ }
+ break;
+ case 4:
+ if (Read) {
+ *(UINT32*)Data = MmioRead32 (Address);
+ } else {
+ MmioWrite32 (Address, *(UINT32*)Data);
+ }
+ break;
+ case 8:
+ if (Read) {
+ *(UINT64*)Data = MmioRead64 (Address);
+ } else {
+ MmioWrite64 (Address, *(UINT64*)Data);
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do OR operation with the value of the specified SD host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimHcOrMmio (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN VOID *OrData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Or;
+
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ Or = *(UINT8*) OrData;
+ } else if (Count == 2) {
+ Or = *(UINT16*) OrData;
+ } else if (Count == 4) {
+ Or = *(UINT32*) OrData;
+ } else if (Count == 8) {
+ Or = *(UINT64*) OrData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data |= Or;
+ Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Do AND operation with the value of the specified SD host controller mmio register.
+
+ @param[in] Address The address of the mmio register to be read/written.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimHcAndMmio (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN VOID *AndData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 And;
+
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ And = *(UINT8*) AndData;
+ } else if (Count == 2) {
+ And = *(UINT16*) AndData;
+ } else if (Count == 4) {
+ And = *(UINT32*) AndData;
+ } else if (Count == 8) {
+ And = *(UINT64*) AndData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data &= And;
+ Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] Address The address of the mmio register to be checked.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimHcCheckMmioSet (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Value;
+
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = 0;
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] Address The address of the mmio register to wait.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimHcWaitMmioSet (
+ IN UINTN Address,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ Status = SdPeimHcCheckMmioSet (
+ Address,
+ Count,
+ MaskValue,
+ TestValue
+ );
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Software reset the specified SD host controller and enable all interrupts.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdPeimHcReset (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SwReset;
+
+ SwReset = 0xFF;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimHcReset: write full 1 fails: %r\n", Status));
+ return Status;
+ }
+
+ Status = SdPeimHcWaitMmioSet (
+ Bar + SD_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0x00,
+ SD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "SdPeimHcReset: reset done with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = SdPeimHcEnableInterrupt (Bar);
+
+ return Status;
+}
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimHcEnableInterrupt (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IntStatus;
+
+ //
+ // Enable all bits in Error Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Enable all bits in Normal Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+
+ return Status;
+}
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimHcGetCapability (
+ IN UINTN Bar,
+ OUT SD_HC_SLOT_CAP *Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Cap;
+
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CAP, TRUE, sizeof (Cap), &Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Capability, &Cap, sizeof (Cap));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect whether there is a SD card attached at the specified SD host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS There is a SD card attached.
+ @retval EFI_NO_MEDIA There is not a SD card attached.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdPeimHcCardDetect (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data;
+ UINT32 PresentState;
+
+ //
+ // Check Normal Interrupt Status Register
+ //
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT6 | BIT7)) != 0) {
+ //
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
+ //
+ Data &= BIT6 | BIT7;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = SdPeimHcRwMmio (Bar + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NO_MEDIA;
+ }
+}
+
+/**
+ Stop SD card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS Succeed to stop SD clock.
+ @retval Others Fail to stop SD clock.
+
+**/
+EFI_STATUS
+SdPeimHcStopClock (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PresentState;
+ UINT16 ClockCtrl;
+
+ //
+ // Ensure no SD transactions are occurring on the SD Bus by
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
+ // in the Present State register to be 0.
+ //
+ Status = SdPeimHcWaitMmioSet (
+ Bar + SD_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ BIT0 | BIT1,
+ 0,
+ SD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 0
+ //
+ ClockCtrl = (UINT16)~BIT2;
+ Status = SdPeimHcAndMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ SD card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdPeimHcClockSupply (
+ IN UINTN Bar,
+ IN UINT64 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ SD_HC_SLOT_CAP Capability;
+ UINT32 BaseClkFreq;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ControllerVer;
+ UINT16 ClockCtrl;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = SdPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (Capability.BaseClkFreq != 0);
+
+ BaseClkFreq = Capability.BaseClkFreq;
+
+ if (ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq * 1000;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
+ //
+ if ((ControllerVer & 0xFF) == 2) {
+ ASSERT (Divisor <= 0x3FF);
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ //
+ // Only the most significant bit can be used as divisor.
+ //
+ if (((Divisor - 1) & Divisor) != 0) {
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);
+ }
+ ASSERT (Divisor <= 0x80);
+ ClockCtrl = (Divisor & 0xFF) << 8;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Stop bus clock at first
+ //
+ Status = SdPeimHcStopClock (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Supply clock frequency with specified divisor
+ //
+ ClockCtrl |= BIT0;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1
+ //
+ Status = SdPeimHcWaitMmioSet (
+ Bar + SD_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ SD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ Status = SdPeimHcOrMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ SD bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD card attached.
+ @retval FALSE There is no a SD card attached.
+
+**/
+EFI_STATUS
+SdPeimHcPowerControl (
+ IN UINTN Bar,
+ IN UINT8 PowerCtrl
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clr SD Bus Power
+ //
+ PowerCtrl &= (UINT8)~BIT0;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ PowerCtrl |= BIT0;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+
+ return Status;
+}
+
+/**
+ Set the SD bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] BusWidth The bus width used by the SD device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+SdPeimHcSetBusWidth (
+ IN UINTN Bar,
+ IN UINT16 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (BusWidth == 1) {
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);
+ Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 4) {
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 |= BIT1;
+ HostCtrl1 &= (UINT8)~BIT5;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 8) {
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 &= (UINT8)~BIT1;
+ HostCtrl1 |= BIT5;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Supply SD card with lowest clock frequency at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdPeimHcInitClockFreq (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ SD_HC_SLOT_CAP Capability;
+ UINT32 InitFreq;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = SdPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Capability.BaseClkFreq == 0) {
+ //
+ // Don't support get Base Clock Frequency information via another method
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Supply 400KHz clock frequency at initialization phase.
+ //
+ InitFreq = 400;
+ Status = SdPeimHcClockSupply (Bar, InitFreq);
+ return Status;
+}
+
+/**
+ Supply SD card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdPeimHcInitPowerVoltage (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ SD_HC_SLOT_CAP Capability;
+ UINT8 MaxVoltage;
+ UINT8 HostCtrl2;
+
+ //
+ // Get the support voltage of the Host Controller
+ //
+ Status = SdPeimHcGetCapability (Bar, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Calculate supported maximum voltage according to SD Bus Voltage Select
+ //
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxVoltage = 0x0E;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxVoltage = 0x0C;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxVoltage = 0x0A;
+ HostCtrl2 = BIT3;
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ MicroSecondDelay (5000);
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ Status = SdPeimHcPowerControl (Bar, MaxVoltage);
+
+ return Status;
+}
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+SdPeimHcInitTimeoutCtrl (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Timeout;
+
+ Timeout = 0x0E;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
+
+ return Status;
+}
+
+/**
+ Initial SD host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdPeimHcInitHost (
+ IN UINTN Bar
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdPeimHcInitClockFreq (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimHcInitPowerVoltage (Bar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimHcInitTimeoutCtrl (Bar);
+ return Status;
+}
+
+/**
+ Turn on/off LED.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] On The boolean to turn on/off LED.
+
+ @retval EFI_SUCCESS The LED is turned on/off successfully.
+ @retval Others The LED isn't turned on/off successfully.
+
+**/
+EFI_STATUS
+SdPeimHcLedOnOff (
+ IN UINTN Bar,
+ IN BOOLEAN On
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (On) {
+ HostCtrl1 = BIT0;
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ HostCtrl1 = (UINT8)~BIT0;
+ Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ }
+
+ return Status;
+}
+
+/**
+ Build ADMA descriptor table for transfer.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
+
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
+ @retval Others The ADMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildAdmaDescTable (
+ IN SD_TRB *Trb
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINT32 Address;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ //
+ // Only support 32bit ADMA Descriptor Table
+ //
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ // for 32-bit address descriptor table.
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
+
+ Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (SD_HC_ADMA_DESC_LINE));
+ Trb->AdmaDesc = SdPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);
+ if (Trb->AdmaDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Remaining = DataLen;
+ Address = (UINT32)Data;
+ for (Index = 0; Index < Entries; Index++) {
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
+ Trb->AdmaDesc[Index].Address = Address;
+ break;
+ } else {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = 0;
+ Trb->AdmaDesc[Index].Address = Address;
+ }
+
+ Remaining -= ADMA_MAX_DATA_PER_LINE;
+ Address += ADMA_MAX_DATA_PER_LINE;
+ }
+
+ //
+ // Set the last descriptor line as end of descriptor table
+ //
+ Trb->AdmaDesc[Index].End = 1;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the SD cmd request.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+
+ @return Created Trb or NULL.
+
+**/
+SD_TRB *
+SdPeimCreateTrb (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN SD_COMMAND_PACKET *Packet
+ )
+{
+ SD_TRB *Trb;
+ EFI_STATUS Status;
+ SD_HC_SLOT_CAP Capability;
+ EDKII_IOMMU_OPERATION MapOp;
+ UINTN MapLength;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Trb = AllocateZeroPool (sizeof (SD_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Timeout = Packet->Timeout;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
+ }
+
+ if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {
+ Trb->Mode = SdPioMode;
+ } else {
+ if (Trb->Read) {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ if (Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
+
+ if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) {
+ DEBUG ((DEBUG_ERROR, "SdPeimCreateTrb: Fail to map data buffer.\n"));
+ goto Error;
+ }
+ }
+
+ if (Trb->DataLen == 0) {
+ Trb->Mode = SdNoData;
+ } else if (Capability.Adma2 != 0) {
+ Trb->Mode = SdAdmaMode;
+ Status = BuildAdmaDescTable (Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else if (Capability.Sdma != 0) {
+ Trb->Mode = SdSdmaMode;
+ } else {
+ Trb->Mode = SdPioMode;
+ }
+ }
+ return Trb;
+
+Error:
+ SdPeimFreeTrb (Trb);
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+**/
+VOID
+SdPeimFreeTrb (
+ IN SD_TRB *Trb
+ )
+{
+ if ((Trb != NULL) && (Trb->DataMap != NULL)) {
+ IoMmuUnmap (Trb->DataMap);
+ }
+
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
+ SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);
+ }
+
+ if (Trb != NULL) {
+ FreePool (Trb);
+ }
+ return;
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdPeimCheckTrbEnv (
+ IN UINTN Bar,
+ IN SD_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ SD_COMMAND_PACKET *Packet;
+ UINT32 PresentState;
+
+ Packet = Trb->Packet;
+
+ if ((Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) ||
+ (Packet->SdCmdBlk->ResponseType == SdResponseTypeR1b) ||
+ (Packet->SdCmdBlk->ResponseType == SdResponseTypeR5b)) {
+ //
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
+ // the Present State register to be 0
+ //
+ PresentState = BIT0 | BIT1;
+ } else {
+ //
+ // Wait Command Inhibit (CMD) in the Present State register
+ // to be 0
+ //
+ PresentState = BIT0;
+ }
+
+ Status = SdPeimHcCheckMmioSet (
+ Bar + SD_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ PresentState,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdPeimWaitTrbEnv (
+ IN UINTN Bar,
+ IN SD_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ SD_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Packet = Trb->Packet;
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdPeimCheckTrbEnv (Bar, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+SdPeimExecTrb (
+ IN UINTN Bar,
+ IN SD_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ SD_COMMAND_PACKET *Packet;
+ UINT16 Cmd;
+ UINT16 IntStatus;
+ UINT32 Argument;
+ UINT16 BlkCount;
+ UINT16 BlkSize;
+ UINT16 TransMode;
+ UINT8 HostCtrl1;
+ UINT32 SdmaAddr;
+ UINT64 AdmaAddr;
+
+ Packet = Trb->Packet;
+ //
+ // Clear all bits in Error Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear all bits in Normal Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set Host Control 1 register DMA Select field
+ //
+ if (Trb->Mode == SdAdmaMode) {
+ HostCtrl1 = BIT4;
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ SdPeimHcLedOnOff (Bar, TRUE);
+
+ if (Trb->Mode == SdSdmaMode) {
+ if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Trb->Mode == SdAdmaMode) {
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlkSize = Trb->BlockSize;
+ if (Trb->Mode == SdSdmaMode) {
+ //
+ // Set SDMA boundary to be 512K bytes.
+ //
+ BlkSize |= 0x7000;
+ }
+
+ Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkCount = 0;
+ if (Trb->Mode != SdNoData) {
+ //
+ // Calculate Block Count.
+ //
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
+ }
+ Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Argument = Packet->SdCmdBlk->CommandArgument;
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ARG1, FALSE, sizeof (Argument), &Argument);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransMode = 0;
+ if (Trb->Mode != SdNoData) {
+ if (Trb->Mode != SdPioMode) {
+ TransMode |= BIT0;
+ }
+ if (Trb->Read) {
+ TransMode |= BIT4;
+ }
+ if (BlkCount > 1) {
+ TransMode |= BIT5 | BIT1;
+ }
+ //
+ // SD memory card needs to use AUTO CMD12 feature.
+ //
+ if (BlkCount > 1) {
+ TransMode |= BIT2;
+ }
+ }
+
+ Status = SdPeimHcRwMmio (Bar + SD_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Cmd = (UINT16)LShiftU64(Packet->SdCmdBlk->CommandIndex, 8);
+ if (Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) {
+ Cmd |= BIT5;
+ }
+ //
+ // Convert ResponseType to value
+ //
+ if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {
+ switch (Packet->SdCmdBlk->ResponseType) {
+ case SdResponseTypeR1:
+ case SdResponseTypeR5:
+ case SdResponseTypeR6:
+ case SdResponseTypeR7:
+ Cmd |= (BIT1 | BIT3 | BIT4);
+ break;
+ case SdResponseTypeR2:
+ Cmd |= (BIT0 | BIT3);
+ break;
+ case SdResponseTypeR3:
+ case SdResponseTypeR4:
+ Cmd |= BIT1;
+ break;
+ case SdResponseTypeR1b:
+ case SdResponseTypeR5b:
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ //
+ // Execute cmd
+ //
+ Status = SdPeimHcRwMmio (Bar + SD_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
+ return Status;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdPeimCheckTrbResult (
+ IN UINTN Bar,
+ IN SD_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ SD_COMMAND_PACKET *Packet;
+ UINT16 IntStatus;
+ UINT32 Response[4];
+ UINT32 SdmaAddr;
+ UINT8 Index;
+ UINT8 SwReset;
+ UINT32 PioLength;
+
+ SwReset = 0;
+ Packet = Trb->Packet;
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check Transfer Complete bit is set or not.
+ //
+ if ((IntStatus & BIT1) == BIT1) {
+ if ((IntStatus & BIT15) == BIT15) {
+ //
+ // Read Error Interrupt Status register to check if the error is
+ // Data Timeout Error.
+ // If yes, treat it as success as Transfer Complete has higher
+ // priority than Data Timeout Error.
+ //
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((IntStatus & BIT4) == BIT4) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ goto Done;
+ }
+ //
+ // Check if there is a error happened during cmd execution.
+ // If yes, then do error recovery procedure to follow SD Host Controller
+ // Simplified Spec 3.0 section 3.10.1.
+ //
+ if ((IntStatus & BIT15) == BIT15) {
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if ((IntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((IntStatus & 0xF0) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Status = SdPeimHcWaitMmioSet (
+ Bar + SD_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ SD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ //
+ // Check if DMA interrupt is signalled for the SDMA transfer.
+ //
+ if ((Trb->Mode == SdSdmaMode) && ((IntStatus & BIT3) == BIT3)) {
+ //
+ // Clear DMA interrupt bit.
+ //
+ IntStatus = BIT3;
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Update SDMA Address register.
+ //
+ SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_SDMA_BOUNDARY);
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_SDMA_ADDR,
+ FALSE,
+ sizeof (UINT32),
+ &SdmaAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
+ }
+
+ if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) &&
+ (Packet->SdCmdBlk->ResponseType != SdResponseTypeR1b) &&
+ (Packet->SdCmdBlk->ResponseType != SdResponseTypeR5b)) {
+ if ((IntStatus & BIT0) == BIT0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {
+ //
+ // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
+ // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
+ // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
+ //
+ if ((IntStatus & BIT5) == BIT5) {
+ //
+ // Clear Buffer Read Ready interrupt at first.
+ //
+ IntStatus = BIT5;
+ SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ //
+ // Read data out from Buffer Port register
+ //
+ for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
+ SdPeimHcRwMmio (Bar + SD_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);
+ }
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ Status = EFI_NOT_READY;
+Done:
+ //
+ // Get response data when the cmd is executed successfully.
+ //
+ if (!EFI_ERROR (Status)) {
+ if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {
+ for (Index = 0; Index < 4; Index++) {
+ Status = SdPeimHcRwMmio (
+ Bar + SD_HC_RESPONSE + Index * 4,
+ TRUE,
+ sizeof (UINT32),
+ &Response[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ SdPeimHcLedOnOff (Bar, FALSE);
+ return Status;
+ }
+ }
+ CopyMem (Packet->SdStatusBlk, Response, sizeof (Response));
+ }
+ }
+
+ if (Status != EFI_NOT_READY) {
+ SdPeimHcLedOnOff (Bar, FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdPeimWaitTrbResult (
+ IN UINTN Bar,
+ IN SD_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ SD_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ Packet = Trb->Packet;
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdPeimCheckTrbResult (Bar, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ MicroSecondDelay (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] Slot The slot number of the Sd card to send the command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by SD card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+SdPeimExecCmd (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN OUT SD_COMMAND_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ SD_TRB *Trb;
+
+ if (Packet == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SdCmdBlk == NULL) || (Packet->SdStatusBlk == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Trb = SdPeimCreateTrb (Slot, Packet);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = SdPeimWaitTrbEnv (Slot->SdHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = SdPeimExecTrb (Slot->SdHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = SdPeimWaitTrbResult (Slot->SdHcBase, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ SdPeimFreeTrb (Trb);
+
+ return Status;
+}
+
+/**
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The SD device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+SdPeimReset (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+ SdCmdBlk.CommandType = SdCommandTypeBc;
+ SdCmdBlk.ResponseType = 0;
+ SdCmdBlk.CommandArgument = 0;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface
+ condition.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] SupplyVoltage The supplied voltage by the host.
+ @param[in] CheckPattern The check pattern to be sent to the device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimVoltageCheck (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT8 SupplyVoltage,
+ IN UINT8 CheckPattern
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SEND_IF_COND;
+ SdCmdBlk.CommandType = SdCommandTypeBcr;
+ SdCmdBlk.ResponseType = SdResponseTypeR7;
+ SdCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ if (SdStatusBlk.Resp0 != SdCmdBlk.CommandArgument) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18r The boolean to show if it should switch to 1.8v.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdioSendOpCond (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18r
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
+ SdCmdBlk.CommandType = SdCommandTypeBcr;
+ SdCmdBlk.ResponseType = SdResponseTypeR4;
+
+ Switch = S18r ? BIT24 : 0;
+
+ SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18r The boolean to show if it should switch to 1.8v.
+ @param[in] Xpc The boolean to show if it should provide 0.36w power control.
+ @param[in] Hcs The boolean to show if it support host capacity info.
+ @param[out] Ocr The buffer to store returned OCR register value.
+
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSendOpCond (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18r,
+ IN BOOLEAN Xpc,
+ IN BOOLEAN Hcs,
+ OUT UINT32 *Ocr
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+ UINT32 MaxPower;
+ UINT32 HostCapacity;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_APP_CMD;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdCmdBlk.CommandIndex = SD_SEND_OP_COND;
+ SdCmdBlk.CommandType = SdCommandTypeBcr;
+ SdCmdBlk.ResponseType = SdResponseTypeR3;
+
+ Switch = S18r ? BIT24 : 0;
+ MaxPower = Xpc ? BIT28 : 0;
+ HostCapacity = Hcs ? BIT30 : 0;
+ SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Ocr = SdStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the
+ data of their CID registers.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimAllSendCid (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+ SdCmdBlk.CommandType = SdCommandTypeBcr;
+ SdCmdBlk.ResponseType = SdResponseTypeR2;
+ SdCmdBlk.CommandArgument = 0;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
+ Address (RCA).
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSetRca (
+ IN SD_PEIM_HC_SLOT *Slot,
+ OUT UINT16 *Rca
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdCmdBlk.CommandType = SdCommandTypeBcr;
+ SdCmdBlk.ResponseType = SdResponseTypeR6;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ *Rca = (UINT16)(SdStatusBlk.Resp0 >> 16);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of this
+ buffer as the content of this byte is meaningless even
+ if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimGetCsd (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ OUT SD_CSD *Csd
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SEND_CSD;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR2;
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdStatusBlk.Resp0, sizeof (SD_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSelect (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1b;
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimVoltageSwitch (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ SdCmdBlk.CommandArgument = 0;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSetBusWidth (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_APP_CMD;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+
+ if (BusWidth == 1) {
+ Value = 0;
+ } else if (BusWidth == 4) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ SdCmdBlk.CommandArgument = Value & 0x3;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] AccessMode The value for access mode group.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriveStrength The value for drive length group.
+ @param[in] PowerLimit The value for power limit group.
+ @param[in] Mode Switch or check function.
+ @param[out] SwitchResp The return switch function status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSwitch (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT8 AccessMode,
+ IN UINT8 CommandSystem,
+ IN UINT8 DriveStrength,
+ IN UINT8 PowerLimit,
+ IN BOOLEAN Mode,
+ OUT UINT8 *SwitchResp
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 ModeValue;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+
+ ModeValue = Mode ? BIT31 : 0;
+ SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
+ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
+ ModeValue;
+ Packet.InDataBuffer = SwitchResp;
+ Packet.InTransferLength = 64;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed SD device to get its status register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSendStatus (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdCmdBlk.CommandType = SdCommandTypeAc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device
+ to read/write the specified number of blocks.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified SD device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimRwSingleBlock (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor is because it's the lowest
+ // transfer speed of class 2.
+ //
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;
+
+ if (IsRead) {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = (UINT32)BufferSize;
+
+ SdCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ } else {
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = (UINT32)BufferSize;
+
+ SdCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ }
+
+ if (Slot->SectorAddressing) {
+ SdCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
+ }
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device
+ to read/write the specified number of blocks.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified SD device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimRwMultiBlocks (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor is because it's the lowest
+ // transfer speed of class 2.
+ //
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;
+
+ if (IsRead) {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = (UINT32)BufferSize;
+
+ SdCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ } else {
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = (UINT32)BufferSize;
+
+ SdCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ }
+
+ if (Slot->SectorAddressing) {
+ SdCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
+ }
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the SD device for SDR104/SDR50 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSendTuningBlk (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ SD_COMMAND_BLOCK SdCmdBlk;
+ SD_STATUS_BLOCK SdStatusBlk;
+ SD_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[64];
+
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdCmdBlk = &SdCmdBlk;
+ Packet.SdStatusBlk = &SdStatusBlk;
+ Packet.Timeout = SD_TIMEOUT;
+
+ SdCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;
+ SdCmdBlk.ResponseType = SdResponseTypeR1;
+ SdCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ Packet.InTransferLength = sizeof (TuningBlock);
+
+ Status = SdPeimExecCmd (Slot, &Packet);
+
+ return Status;
+}
+
+/**
+ Tuning the sampling point of SDR104 or SDR50 bus speed mode.
+
+ Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimTuningClock (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = SdPeimSendTuningBlk (Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((EFI_D_ERROR, "SdPeimTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSwitchBusWidth (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = SdPeimSetBusWidth (Slot, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimSendStatus (Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus >> 16) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdPeimHcSetBusWidth (Slot->SdHcBase, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] S18a The boolean to show if it's a UHS-I SD card.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSetBusMode (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN S18a
+ )
+{
+ EFI_STATUS Status;
+ SD_HC_SLOT_CAP Capability;
+ UINT32 ClockFreq;
+ UINT8 BusWidth;
+ UINT8 AccessMode;
+ UINT8 HostCtrl1;
+ UINT8 HostCtrl2;
+ UINT8 SwitchResp[64];
+
+ Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimGetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimSelect (Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSelect fails with %r\n", Status));
+ return Status;
+ }
+
+ BusWidth = 4;
+ Status = SdPeimSwitchBusWidth (Slot, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitchBusWidth fails with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Get the supported bus speed from SWITCH cmd return data group #1.
+ //
+ ZeroMem (SwitchResp, sizeof (SwitchResp));
+ Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Calculate supported bus speed/bus width/clock frequency by host and device capability.
+ //
+ ClockFreq = 0;
+ if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
+ ClockFreq = 208;
+ AccessMode = 3;
+ } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
+ ClockFreq = 100;
+ AccessMode = 2;
+ } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
+ ClockFreq = 50;
+ AccessMode = 4;
+ } else if ((SwitchResp[13] & BIT1) != 0) {
+ ClockFreq = 50;
+ AccessMode = 1;
+ } else {
+ ClockFreq = 25;
+ AccessMode = 0;
+ }
+
+ DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
+
+ Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));
+ return Status;
+ }
+
+ if ((SwitchResp[16] & 0xF) != AccessMode) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set to High Speed timing
+ //
+ if (AccessMode == 1) {
+ HostCtrl1 = BIT2;
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl2 = AccessMode;
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimHcClockSupply (Slot->SdHcBase, ClockFreq * 1000);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimHcClockSupply %r\n", Status));
+ return Status;
+ }
+
+ if ((AccessMode == 3) || ((AccessMode == 2) && (Capability.TuningSDR50 != 0))) {
+ Status = SdPeimTuningClock (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimTuningClock fails with %r\n", Status));
+ return Status;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: SdPeimSetBusMode %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Execute SD device identification procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a SD card.
+ @retval Others There is not a SD card.
+
+**/
+EFI_STATUS
+SdPeimIdentification (
+ IN SD_PEIM_HC_SLOT *Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Ocr;
+ UINT16 Rca;
+ BOOLEAN Xpc;
+ BOOLEAN S18r;
+ UINT64 MaxCurrent;
+ UINT64 Current;
+ UINT16 ControllerVer;
+ UINT8 PowerCtrl;
+ UINT32 PresentState;
+ UINT8 HostCtrl2;
+ SD_HC_SLOT_CAP Capability;
+ UINTN Retry;
+ //
+ // 1. Send Cmd0 to the device
+ //
+ Status = SdPeimReset (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 2. Send Cmd8 to the device
+ //
+ Status = SdPeimVoltageCheck (Slot, 0x1, 0xFF);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd8 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
+ //
+ Status = SdioSendOpCond (Slot, 0, FALSE);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Found SDIO device, ignore it as we don't support\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 4. Send Acmd41 with voltage window 0 to the device
+ //
+ Status = SdPeimSendOpCond (Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSendOpCond fails with %r\n", Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_MAX_CURRENT_CAP, TRUE, sizeof (Current), &Current);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxCurrent = ((UINT32)Current & 0xFF) * 4;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxCurrent = (((UINT32)Current >> 8) & 0xFF) * 4;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxCurrent = (((UINT32)Current >> 16) & 0xFF) * 4;
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MaxCurrent >= 150) {
+ Xpc = TRUE;
+ } else {
+ Xpc = FALSE;
+ }
+
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((ControllerVer & 0xFF) == 2) {
+ S18r = TRUE;
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ S18r = FALSE;
+ } else {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 5. Repeatly send Acmd41 with supply voltage window to the device.
+ // Note here we only support the cards complied with SD physical
+ // layer simplified spec version 2.0 and version 3.0 and above.
+ //
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Retry++ == 100) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ MicroSecondDelay (10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ //
+ // 6. If the S18a bit is set and the Host Controller supports 1.8V signaling
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the
+ // Capabilities register), switch its voltage to 1.8V.
+ //
+ if ((Capability.Sdr50 != 0 ||
+ Capability.Sdr104 != 0 ||
+ Capability.Ddr50 != 0) &&
+ ((Ocr & BIT24) != 0)) {
+ Status = SdPeimVoltageSwitch (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimVoltageSwitch fails with %r\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ } else {
+ Status = SdPeimHcStopClock (Slot->SdHcBase);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ HostCtrl2 = BIT3;
+ SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+
+ MicroSecondDelay (5000);
+
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if ((HostCtrl2 & BIT3) == 0) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdPeimHcInitClockFreq (Slot->SdHcBase);
+
+ MicroSecondDelay (1000);
+
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0xF) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "SdPeimIdentification: Switch to 1.8v signal voltage success\n"));
+ }
+
+ Status = SdPeimAllSendCid (Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimAllSendCid fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdPeimSetRca (Slot, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSetRca fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((EFI_D_INFO, "Found a SD device at slot [%d]\n", Slot));
+
+ Status = SdPeimSetBusMode (Slot, Rca, ((Ocr & BIT24) != 0));
+
+ return Status;
+
+Error:
+ //
+ // Set SD Bus Power = 0
+ //
+ PowerCtrl = (UINT8)~BIT0;
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);
+ return EFI_DEVICE_ERROR;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
new file mode 100644
index 000000000..c31297521
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
@@ -0,0 +1,350 @@
+/** @file
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_HCI_H_
+#define _SD_HCI_H_
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define SD_HC_SDMA_ADDR 0x00
+#define SD_HC_ARG2 0x00
+#define SD_HC_BLK_SIZE 0x04
+#define SD_HC_BLK_COUNT 0x06
+#define SD_HC_ARG1 0x08
+#define SD_HC_TRANS_MOD 0x0C
+#define SD_HC_COMMAND 0x0E
+#define SD_HC_RESPONSE 0x10
+#define SD_HC_BUF_DAT_PORT 0x20
+#define SD_HC_PRESENT_STATE 0x24
+#define SD_HC_HOST_CTRL1 0x28
+#define SD_HC_POWER_CTRL 0x29
+#define SD_HC_BLK_GAP_CTRL 0x2A
+#define SD_HC_WAKEUP_CTRL 0x2B
+#define SD_HC_CLOCK_CTRL 0x2C
+#define SD_HC_TIMEOUT_CTRL 0x2E
+#define SD_HC_SW_RST 0x2F
+#define SD_HC_NOR_INT_STS 0x30
+#define SD_HC_ERR_INT_STS 0x32
+#define SD_HC_NOR_INT_STS_EN 0x34
+#define SD_HC_ERR_INT_STS_EN 0x36
+#define SD_HC_NOR_INT_SIG_EN 0x38
+#define SD_HC_ERR_INT_SIG_EN 0x3A
+#define SD_HC_AUTO_CMD_ERR_STS 0x3C
+#define SD_HC_HOST_CTRL2 0x3E
+#define SD_HC_CAP 0x40
+#define SD_HC_MAX_CURRENT_CAP 0x48
+#define SD_HC_FORCE_EVT_AUTO_CMD 0x50
+#define SD_HC_FORCE_EVT_ERR_INT 0x52
+#define SD_HC_ADMA_ERR_STS 0x54
+#define SD_HC_ADMA_SYS_ADDR 0x58
+#define SD_HC_PRESET_VAL 0x60
+#define SD_HC_SHARED_BUS_CTRL 0xE0
+#define SD_HC_SLOT_INT_STS 0xFC
+#define SD_HC_CTRL_VER 0xFE
+
+//
+// The transfer modes supported by SD Host Controller
+// Simplified Spec 3.0 Table 1-2
+//
+typedef enum {
+ SdNoData,
+ SdPioMode,
+ SdSdmaMode,
+ SdAdmaMode
+} SD_HC_TRANSFER_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE 0x10000
+#define SD_SDMA_BOUNDARY 512 * 1024
+#define SD_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
+
+typedef enum {
+ SdCommandTypeBc, // Broadcast commands, no response
+ SdCommandTypeBcr, // Broadcast commands with response
+ SdCommandTypeAc, // Addressed(point-to-point) commands
+ SdCommandTypeAdtc // Addressed(point-to-point) data transfer commands
+} SD_COMMAND_TYPE;
+
+typedef enum {
+ SdResponseTypeR1,
+ SdResponseTypeR1b,
+ SdResponseTypeR2,
+ SdResponseTypeR3,
+ SdResponseTypeR4,
+ SdResponseTypeR5,
+ SdResponseTypeR5b,
+ SdResponseTypeR6,
+ SdResponseTypeR7
+} SD_RESPONSE_TYPE;
+
+typedef struct _SD_COMMAND_BLOCK {
+ UINT16 CommandIndex;
+ UINT32 CommandArgument;
+ UINT32 CommandType; // One of the SD_COMMAND_TYPE values
+ UINT32 ResponseType; // One of the SD_RESPONSE_TYPE values
+} SD_COMMAND_BLOCK;
+
+typedef struct _SD_STATUS_BLOCK {
+ UINT32 Resp0;
+ UINT32 Resp1;
+ UINT32 Resp2;
+ UINT32 Resp3;
+} SD_STATUS_BLOCK;
+
+typedef struct _SD_COMMAND_PACKET {
+ UINT64 Timeout;
+ SD_COMMAND_BLOCK *SdCmdBlk;
+ SD_STATUS_BLOCK *SdStatusBlk;
+ VOID *InDataBuffer;
+ VOID *OutDataBuffer;
+ UINT32 InTransferLength;
+ UINT32 OutTransferLength;
+} SD_COMMAND_PACKET;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 Reserved1:10;
+ UINT32 Length:16;
+ UINT32 Address;
+} SD_HC_ADMA_DESC_LINE;
+
+typedef struct {
+ UINT32 TimeoutFreq:6; // bit 0:5
+ UINT32 Reserved:1; // bit 6
+ UINT32 TimeoutUnit:1; // bit 7
+ UINT32 BaseClkFreq:8; // bit 8:15
+ UINT32 MaxBlkLen:2; // bit 16:17
+ UINT32 BusWidth8:1; // bit 18
+ UINT32 Adma2:1; // bit 19
+ UINT32 Reserved2:1; // bit 20
+ UINT32 HighSpeed:1; // bit 21
+ UINT32 Sdma:1; // bit 22
+ UINT32 SuspRes:1; // bit 23
+ UINT32 Voltage33:1; // bit 24
+ UINT32 Voltage30:1; // bit 25
+ UINT32 Voltage18:1; // bit 26
+ UINT32 Reserved3:1; // bit 27
+ UINT32 SysBus64:1; // bit 28
+ UINT32 AsyncInt:1; // bit 29
+ UINT32 SlotType:2; // bit 30:31
+ UINT32 Sdr50:1; // bit 32
+ UINT32 Sdr104:1; // bit 33
+ UINT32 Ddr50:1; // bit 34
+ UINT32 Reserved4:1; // bit 35
+ UINT32 DriverTypeA:1; // bit 36
+ UINT32 DriverTypeC:1; // bit 37
+ UINT32 DriverTypeD:1; // bit 38
+ UINT32 DriverType4:1; // bit 39
+ UINT32 TimerCount:4; // bit 40:43
+ UINT32 Reserved5:1; // bit 44
+ UINT32 TuningSDR50:1; // bit 45
+ UINT32 RetuningMod:2; // bit 46:47
+ UINT32 ClkMultiplier:8; // bit 48:55
+ UINT32 Reserved6:7; // bit 56:62
+ UINT32 Hs400:1; // bit 63
+} SD_HC_SLOT_CAP;
+
+#pragma pack()
+
+/**
+ Software reset the specified SD host controller and enable all interrupts.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdPeimHcReset (
+ IN UINTN Bar
+ );
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimHcEnableInterrupt (
+ IN UINTN Bar
+ );
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimHcGetCapability (
+ IN UINTN Bar,
+ OUT SD_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Detect whether there is a SD card attached at the specified SD host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS There is a SD card attached.
+ @retval EFI_NO_MEDIA There is not a SD card attached.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdPeimHcCardDetect (
+ IN UINTN Bar
+ );
+
+/**
+ Initial SD host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Bar The mmio base address of the slot to be accessed.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdPeimHcInitHost (
+ IN UINTN Bar
+ );
+
+/**
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] AccessMode The value for access mode group.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriveStrength The value for drive length group.
+ @param[in] PowerLimit The value for power limit group.
+ @param[in] Mode Switch or check function.
+ @param[out] SwitchResp The return switch function status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimSwitch (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN UINT8 AccessMode,
+ IN UINT8 CommandSystem,
+ IN UINT8 DriveStrength,
+ IN UINT8 PowerLimit,
+ IN BOOLEAN Mode,
+ OUT UINT8 *SwitchResp
+ );
+
+/**
+ Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device
+ to read/write the specified number of blocks.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified SD device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimRwSingleBlock (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ );
+
+/**
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device
+ to read/write the specified number of blocks.
+
+ Refer to SD Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] Slot The slot number of the Sd card to send the command to.
+ @param[in] Lba The logical block address of starting access.
+ @param[in] BlockSize The block size of specified SD device partition.
+ @param[in] Buffer The pointer to the transfer buffer.
+ @param[in] BufferSize The size of transfer buffer.
+ @param[in] IsRead Boolean to show the operation direction.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdPeimRwMultiBlocks (
+ IN SD_PEIM_HC_SLOT *Slot,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead
+ );
+
+/**
+ Execute SD device identification procedure.
+
+ Refer to SD Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Slot The slot number of the Sd card to send the command to.
+
+ @retval EFI_SUCCESS There is a SD card.
+ @retval Others There is not a SD card.
+
+**/
+EFI_STATUS
+SdPeimIdentification (
+ IN SD_PEIM_HC_SLOT *Slot
+ );
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_TRB instance.
+
+**/
+VOID
+SdPeimFreeTrb (
+ IN SD_TRB *Trb
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c
new file mode 100644
index 000000000..acd29d72c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c
@@ -0,0 +1,234 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SdDxe driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdDxe.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = {
+ { "eng;en", L"Edkii Sd Memory Card Device Driver" },
+ { NULL , NULL }
+};
+
+//
+// Controller name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = {
+ { "eng;en", L"Edkii Sd Host Controller" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName = {
+ SdDxeComponentNameGetDriverName,
+ SdDxeComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdDxeComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ 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
+SdDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSdDxeComponentName)
+ );
+
+}
+
+/**
+ 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
+SdDxeComponentNameGetControllerName (
+ 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;
+ SD_DEVICE *Device;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSdDxeDriverBinding.DriverBindingHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = mSdDxeControllerNameTable;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gSdDxeDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
+ ControllerNameTable = Device->ControllerNameTable;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSdDxeComponentName)
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
new file mode 100644
index 000000000..721f26437
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
@@ -0,0 +1,1381 @@
+/** @file
+ The helper functions for BlockIo and BlockIo2 protocol.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdDxe.h"
+
+/**
+ Nonblocking I/O callback function when the event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncIoCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ SD_REQUEST *Request;
+
+ gBS->CloseEvent (Event);
+
+ Request = (SD_REQUEST *) Context;
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
+ Request->Packet.TransactionStatus));
+ DEBUG_CODE_END ();
+
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
+ }
+
+ RemoveEntryList (&Request->Link);
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+}
+
+/**
+ Send command SET_RELATIVE_ADDRESS to the device to set the device address.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[out] Rca The relative device address to assign.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSetRca (
+ IN SD_DEVICE *Device,
+ OUT UINT16 *Rca
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSelect (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ if (Rca != 0) {
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ }
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSendStatus (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
+ }
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the SD_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdGetCsd (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT SD_CSD *Csd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Csd, sizeof (SD_CSD));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the SD_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdGetCid (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT SD_CID *Cid
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Cid, sizeof (SD_CID));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Read/write single block through sync or async I/O request.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdRwSingleBlock (
+ IN SD_DEVICE *Device,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_REQUEST *RwSingleBlkReq;
+ EFI_TPL OldTpl;
+
+ RwSingleBlkReq = NULL;
+ PassThru = Device->Private->PassThru;
+
+ RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
+ if (RwSingleBlkReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;
+ RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor as it's the lowest transfer speed
+ // above class 2.
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.
+ //
+ RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
+
+ if (IsRead) {
+ RwSingleBlkReq->Packet.InDataBuffer = Buffer;
+ RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
+
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ RwSingleBlkReq->Packet.OutDataBuffer = Buffer;
+ RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
+
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ if (Device->SectorAddressing) {
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
+ }
+
+ RwSingleBlkReq->IsEnd = IsEnd;
+ RwSingleBlkReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ RwSingleBlkReq,
+ &RwSingleBlkReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ RwSingleBlkReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwSingleBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (RwSingleBlkReq->Event != NULL) {
+ gBS->CloseEvent (RwSingleBlkReq->Event);
+ }
+ FreePool (RwSingleBlkReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (RwSingleBlkReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwSingleBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (RwSingleBlkReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read/write multiple blocks through sync or async I/O request.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdRwMultiBlocks (
+ IN SD_DEVICE *Device,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ SD_REQUEST *RwMultiBlkReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ RwMultiBlkReq = NULL;
+
+ PassThru = Device->Private->PassThru;
+
+ RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
+ if (RwMultiBlkReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor as it's the lowest transfer speed
+ // above class 2.
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.
+ //
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
+
+ if (IsRead) {
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ if (Device->SectorAddressing) {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
+ }
+
+ RwMultiBlkReq->IsEnd = IsEnd;
+ RwMultiBlkReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ RwMultiBlkReq,
+ &RwMultiBlkReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ RwMultiBlkReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (RwMultiBlkReq->Event != NULL) {
+ gBS->CloseEvent (RwMultiBlkReq->Event);
+ }
+ FreePool (RwMultiBlkReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (RwMultiBlkReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (RwMultiBlkReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function transfers data from/to the sd memory card device.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] MediaId The media ID that the read/write request is for.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS The data was read/written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match 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/write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+SdReadWrite (
+ IN SD_DEVICE *Device,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ UINTN IoAlign;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ BOOLEAN LastRw;
+
+ Status = EFI_SUCCESS;
+ Media = &Device->BlockMedia;
+ LastRw = FALSE;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!IsRead && Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BlockNum = BufferSize / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = BlockNum;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ BlockNum = Remaining;
+ LastRw = TRUE;
+ } else {
+ BlockNum = MaxBlock;
+ }
+
+ BufferSize = BlockNum * BlockSize;
+ if (BlockNum == 1) {
+ Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
+ } else {
+ Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ IsRead ? "Read" : "Write", Lba, BlockNum,
+ (Token != NULL) ? Token->Event : NULL, Status));
+ Lba += BlockNum;
+ Buffer = (UINT8*)Buffer + BufferSize;
+ Remaining -= BlockNum;
+ }
+
+ return Status;
+}
+
+/**
+ 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
+SdReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);
+
+ PassThru = Device->Private->PassThru;
+ Status = PassThru->ResetDevice (PassThru, Device->Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ 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 match 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
+SdReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);
+
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
+ 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_CHANGED The MediaId does not match 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
+SdWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);
+
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
+ return Status;
+}
+
+/**
+ 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+SdResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ SD_DEVICE *Device;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_REQUEST *Request;
+ EFI_TPL OldTpl;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Device->Queue);
+ !IsNull (&Device->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Device->Queue, Link);
+ RemoveEntryList (Link);
+
+ Request = SD_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+SdReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
+
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+SdWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
+
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ //
+ // Signal event and return directly.
+ //
+ if (Token != NULL && Token->Event != NULL) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the erase start address through sync or async I/O request.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] StartLba The starting logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlockStart (
+ IN SD_DEVICE *Device,
+ IN EFI_LBA StartLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_REQUEST *EraseBlockStart;
+ EFI_TPL OldTpl;
+
+ EraseBlockStart = NULL;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
+ if (EraseBlockStart == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->Queue, &EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
+ EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
+ EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
+ EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
+ } else {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
+ }
+
+ EraseBlockStart->IsEnd = IsEnd;
+ EraseBlockStart->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockStart,
+ &EraseBlockStart->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockStart->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockStart->Event != NULL) {
+ gBS->CloseEvent (EraseBlockStart->Event);
+ }
+ FreePool (EraseBlockStart);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockStart != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockStart);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the erase end address through sync or async I/O request.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] EndLba The ending logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlockEnd (
+ IN SD_DEVICE *Device,
+ IN EFI_LBA EndLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_REQUEST *EraseBlockEnd;
+ EFI_TPL OldTpl;
+
+ EraseBlockEnd = NULL;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
+ if (EraseBlockEnd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
+ EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
+ EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
+ EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
+ } else {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
+ }
+
+ EraseBlockEnd->IsEnd = IsEnd;
+ EraseBlockEnd->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockEnd,
+ &EraseBlockEnd->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockEnd->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockEnd->Event != NULL) {
+ gBS->CloseEvent (EraseBlockEnd->Event);
+ }
+ FreePool (EraseBlockEnd);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockEnd != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockEnd);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Erase specified blocks through sync or async I/O request.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlock (
+ IN SD_DEVICE *Device,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_REQUEST *EraseBlock;
+ EFI_TPL OldTpl;
+
+ EraseBlock = NULL;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
+ if (EraseBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlock->Signature = SD_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Device->Queue, &EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
+ EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
+ EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
+
+ EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
+ EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+
+ EraseBlock->IsEnd = IsEnd;
+ EraseBlock->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlock,
+ &EraseBlock->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlock->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlock->Event != NULL) {
+ gBS->CloseEvent (EraseBlock->Event);
+ }
+ FreePool (EraseBlock);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlock != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlock);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+SdEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ EFI_LBA LastLba;
+ SD_DEVICE *Device;
+
+ Status = EFI_SUCCESS;
+ Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
+ Media = &Device->BlockMedia;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ BlockSize = Media->BlockSize;
+ if ((Size % BlockSize) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockNum = Size / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+
+ LastLba = Lba + BlockNum - 1;
+
+ Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
new file mode 100644
index 000000000..b6b4c45f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
@@ -0,0 +1,252 @@
+/** @file
+ Header file for SdDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_BLOCK_IO_H_
+#define _SD_BLOCK_IO_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
+SdReset (
+ 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 match 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
+SdReadBlocks (
+ 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_CHANGED The MediaId does not match 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
+SdWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN 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 writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+SdResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+SdReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] 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_CHANGED The MediaId does not match 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
+SdWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+SdEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c
new file mode 100644
index 000000000..6563f7232
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c
@@ -0,0 +1,132 @@
+/** @file
+ Implement the EFI_DISK_INFO_PROTOCOL interface on SD memory card devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdDxe.h"
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] 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 InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+
+ Device = SD_DEVICE_DATA_FROM_DISKINFO (This);
+
+ if (*InquiryDataSize >= sizeof (Device->Cid)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &Device->Cid, sizeof (Device->Cid));
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *InquiryDataSize = sizeof (Device->Cid);
+
+ return Status;
+}
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] 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
+SdDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+SdDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h
new file mode 100644
index 000000000..64e2f77c9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h
@@ -0,0 +1,109 @@
+/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface on SD memory card devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_DISKINFO_H_
+#define _SD_DISKINFO_H_
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] 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 InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] 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
+SdDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+SdDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
new file mode 100644
index 000000000..73bcc181c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
@@ -0,0 +1,908 @@
+/** @file
+ The SdDxe driver is used to manage the SD memory card device.
+
+ It produces BlockIo and BlockIo2 protocols to allow upper layer
+ access the SD memory card device.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdDxe.h"
+
+//
+// SdDxe Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {
+ SdDxeDriverBindingSupported,
+ SdDxeDriverBindingStart,
+ SdDxeDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for SD_DEVICE data structure.
+//
+SD_DEVICE mSdDeviceTemplate = {
+ SD_DEVICE_SIGNATURE, // Signature
+ NULL, // Handle
+ NULL, // DevicePath
+ 0xFF, // Slot
+ FALSE, // SectorAddressing
+ { // BlockIo
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ NULL,
+ SdReset,
+ SdReadBlocks,
+ SdWriteBlocks,
+ SdFlushBlocks
+ },
+ { // BlockIo2
+ NULL,
+ SdResetEx,
+ SdReadBlocksEx,
+ SdWriteBlocksEx,
+ SdFlushBlocksEx
+ },
+ { // BlockMedia
+ 0, // MediaId
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicPartition
+ FALSE, // ReadOnly
+ FALSE, // WritingCache
+ 0x200, // BlockSize
+ 0, // IoAlign
+ 0 // LastBlock
+ },
+ { // EraseBlock
+ EFI_ERASE_BLOCK_PROTOCOL_REVISION,
+ 1,
+ SdEraseBlocks
+ },
+ { // DiskInfo
+ EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,
+ SdDiskInfoInquiry,
+ SdDiskInfoIdentify,
+ SdDiskInfoSenseData,
+ SdDiskInfoWhichIde
+ },
+ { // Queue
+ NULL,
+ NULL
+ },
+ { // Csd
+ 0,
+ },
+ { // Cid
+ 0,
+ },
+ NULL, // ControllerNameTable
+ { // ModelName
+ 0,
+ },
+ NULL // Private
+};
+
+/**
+ Decode and print SD CSD Register content.
+
+ @param[in] Csd Pointer to SD_CSD data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+DumpCsd (
+ IN SD_CSD *Csd
+ )
+{
+ SD_CSD2 *Csd2;
+
+ DEBUG((DEBUG_INFO, "== Dump Sd Csd Register==\n"));
+ DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));
+ DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));
+ DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));
+ DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));
+ DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));
+ DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));
+ DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));
+ DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));
+ DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));
+ if (Csd->CsdStructure == 0) {
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));
+ } else {
+ Csd2 = (SD_CSD2*)(VOID*)Csd;
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));
+ }
+ DEBUG((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize));
+ DEBUG((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn));
+ DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));
+ DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));
+ DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));
+ DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));
+ DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));
+ DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));
+ DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));
+ DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));
+ DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get SD device model name.
+
+ @param[in, out] Device The pointer to the SD_DEVICE data structure.
+ @param[in] Cid Pointer to SD_CID data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+GetSdModelName (
+ IN OUT SD_DEVICE *Device,
+ IN SD_CID *Cid
+ )
+{
+ CHAR8 String[SD_MODEL_NAME_MAX_LEN];
+
+ ZeroMem (String, sizeof (String));
+ CopyMem (String, Cid->OemId, sizeof (Cid->OemId));
+ String[sizeof (Cid->OemId)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));
+ String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));
+
+ AsciiStrToUnicodeStrS (String, Device->ModelName, sizeof (Device->ModelName) / sizeof (Device->ModelName[0]));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Discover user area partition in the SD device.
+
+ @param[in] Device The pointer to the SD_DEVICE data structure.
+
+ @retval EFI_SUCCESS The user area partition in the SD device is successfully identified.
+ @return Others Some error occurs when identifying the user area.
+
+**/
+EFI_STATUS
+DiscoverUserArea (
+ IN SD_DEVICE *Device
+ )
+{
+ EFI_STATUS Status;
+ SD_CSD *Csd;
+ SD_CSD2 *Csd2;
+ SD_CID *Cid;
+ UINT64 Capacity;
+ UINT32 DevStatus;
+ UINT16 Rca;
+ UINT32 CSize;
+ UINT32 CSizeMul;
+ UINT32 ReadBlLen;
+
+ //
+ // Deselect the device to force it enter stby mode.
+ // Note here we don't judge return status as some SD devices return
+ // error but the state has been stby.
+ //
+ SdSelect (Device, 0);
+
+ Status = SdSetRca (Device, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));
+ return Status;
+ }
+
+ Csd = &Device->Csd;
+ Status = SdGetCsd (Device, Rca, Csd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DumpCsd (Csd);
+
+ Cid = &Device->Cid;
+ Status = SdGetCid (Device, Rca, Cid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ GetSdModelName (Device, Cid);
+
+ Status = SdSelect (Device, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));
+ return Status;
+ }
+
+ Status = SdSendStatus (Device, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Csd->CsdStructure == 0) {
+ Device->SectorAddressing = FALSE;
+ CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
+ CSizeMul = (1 << (Csd->CSizeMul + 2));
+ ReadBlLen = (1 << (Csd->ReadBlLen));
+ Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
+ } else {
+ Device->SectorAddressing = TRUE;
+ Csd2 = (SD_CSD2*)(VOID*)Csd;
+ CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
+ Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
+ }
+
+ Device->BlockIo.Media = &Device->BlockMedia;
+ Device->BlockIo2.Media = &Device->BlockMedia;
+ Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;
+ Device->BlockMedia.BlockSize = 0x200;
+ Device->BlockMedia.LastBlock = 0x00;
+ Device->BlockMedia.RemovableMedia = TRUE;
+ Device->BlockMedia.MediaPresent = TRUE;
+ Device->BlockMedia.LogicalPartition = FALSE;
+ Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;
+
+ if (Csd->EraseBlkEn) {
+ Device->EraseBlock.EraseLengthGranularity = 1;
+ } else {
+ Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9));
+ }
+
+ return Status;
+}
+
+/**
+ Scan SD Bus to discover the device.
+
+ @param[in] Private The SD driver private data structure.
+ @param[in] Slot The slot number to check device present.
+
+ @retval EFI_SUCCESS Successfully to discover the device and attach
+ SdMmcIoProtocol to it.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+ @retval EFI_ALREADY_STARTED The device was discovered before.
+ @retval Others Fail to discover the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiscoverSdDevice (
+ IN SD_DRIVER_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ SD_DEVICE *Device;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+
+ Device = NULL;
+ DevicePath = NULL;
+ NewDevicePath = NULL;
+ RemainingDevicePath = NULL;
+ PassThru = Private->PassThru;
+
+ //
+ // Build Device Path
+ //
+ Status = PassThru->BuildDevicePath (
+ PassThru,
+ Slot,
+ &DevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (DevicePath->SubType != MSG_SD_DP) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+ NewDevicePath = AppendDevicePathNode (
+ Private->ParentDevicePath,
+ DevicePath
+ );
+
+ if (NewDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = NewDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ //
+ // The device has been started, directly return to fast boot.
+ //
+ Status = EFI_ALREADY_STARTED;
+ goto Error;
+ }
+
+ //
+ // Allocate buffer to store SD_DEVICE private data.
+ //
+ Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);
+ if (Device == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Device->DevicePath = NewDevicePath;
+ Device->Slot = Slot;
+ Device->Private = Private;
+ InitializeListHead (&Device->Queue);
+
+ //
+ // Expose user area in the Sd memory card to upper layer.
+ //
+ Status = DiscoverUserArea (Device);
+ if (EFI_ERROR(Status)) {
+ goto Error;
+ }
+
+ Device->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gSdDxeComponentName.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gSdDxeComponentName2.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ FALSE
+ );
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Device->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Device->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Device->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Device->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Device->DiskInfo,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Private->Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &(Private->PassThru),
+ Private->DriverBindingHandle,
+ Device->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+Error:
+ FreePool (DevicePath);
+
+ if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {
+ FreePool (NewDevicePath);
+ }
+
+ if (EFI_ERROR (Status) && (Device != NULL)) {
+ FreePool (Device);
+ }
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdDxeDriverBindingSupported (
+ 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_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT8 Slot;
+
+ //
+ // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Test RemainingDevicePath is valid or not.
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ 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_GET_PROTOCOL
+ );
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ SD_DRIVER_PRIVATE_DATA *Private;
+ UINT8 Slot;
+
+ Private = NULL;
+ PassThru = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Check EFI_ALREADY_STARTED to reuse the original SD_DRIVER_PRIVATE_DATA.
+ //
+ if (Status != EFI_ALREADY_STARTED) {
+ Private = AllocateZeroPool (sizeof (SD_DRIVER_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->PassThru = PassThru;
+ Private->Controller = Controller;
+ Private->ParentDevicePath = ParentDevicePath;
+ Private->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ Private
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ if (RemainingDevicePath == NULL) {
+ Slot = 0xFF;
+ while (TRUE) {
+ Status = PassThru->GetNextSlot (PassThru, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Cannot find more legal slots.
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ Status = DiscoverSdDevice (Private, Slot);
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ break;
+ }
+ }
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (!EFI_ERROR (Status)) {
+ Status = DiscoverSdDevice (Private, Slot);
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private,
+ NULL
+ );
+ FreePool (Private);
+ }
+ }
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+SdDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ SD_DRIVER_PRIVATE_DATA *Private;
+ SD_DEVICE *Device;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_REQUEST *Request;
+ EFI_TPL OldTpl;
+
+ if (NumberOfChildren == 0) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (Private);
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ if (BlockIo != NULL) {
+ Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
+ } else {
+ ASSERT (BlockIo2 != NULL);
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);
+ }
+
+ //
+ // Free all on-going async tasks.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Device->Queue);
+ !IsNull (&Device->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Device->Queue, Link);
+ RemoveEntryList (Link);
+
+ Request = SD_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Device->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Device->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Device->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Device->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Device->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **)&PassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Device->DevicePath);
+ FreeUnicodeStringTable (Device->ControllerNameTable);
+ FreePool (Device);
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module SdDxe. 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 errors occur when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSdDxeDriverBinding,
+ ImageHandle,
+ &gSdDxeComponentName,
+ &gSdDxeComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
new file mode 100644
index 000000000..ff740a521
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
@@ -0,0 +1,475 @@
+/** @file
+ Header file for SdDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_DXE_H_
+#define _SD_DXE_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Protocol/SdMmcPassThru.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/EraseBlock.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/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "SdBlockIo.h"
+#include "SdDiskInfo.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2;
+
+#define SD_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'D', 't', 'f')
+
+#define SD_DEVICE_DATA_FROM_BLKIO(a) \
+ CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE)
+
+#define SD_DEVICE_DATA_FROM_BLKIO2(a) \
+ CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)
+
+#define SD_DEVICE_DATA_FROM_ERASEBLK(a) \
+ CR(a, SD_DEVICE, EraseBlock, SD_DEVICE_SIGNATURE)
+
+#define SD_DEVICE_DATA_FROM_DISKINFO(a) \
+ CR(a, SD_DEVICE, DiskInfo, SD_DEVICE_SIGNATURE)
+
+//
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
+//
+#define SD_GENERIC_TIMEOUT 2500 * 1000
+
+#define SD_REQUEST_SIGNATURE SIGNATURE_32 ('S', 'D', 'R', 'E')
+
+#define SD_MODEL_NAME_MAX_LEN 32
+
+typedef struct _SD_DEVICE SD_DEVICE;
+typedef struct _SD_DRIVER_PRIVATE_DATA SD_DRIVER_PRIVATE_DATA;
+
+//
+// Asynchronous I/O request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ BOOLEAN IsEnd;
+
+ EFI_BLOCK_IO2_TOKEN *Token;
+
+ EFI_EVENT Event;
+} SD_REQUEST;
+
+#define SD_REQUEST_FROM_LINK(a) \
+ CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE)
+
+struct _SD_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT8 Slot;
+ BOOLEAN SectorAddressing;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+
+ LIST_ENTRY Queue;
+
+ SD_CSD Csd;
+ SD_CID Cid;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ //
+ // The model name consists of three fields in CID register
+ // 1) OEM/Application ID (2 bytes)
+ // 2) Product Name (5 bytes)
+ // 3) Product Serial Number (4 bytes)
+ // The delimiters of these fields are whitespace.
+ //
+ CHAR16 ModelName[SD_MODEL_NAME_MAX_LEN];
+ SD_DRIVER_PRIVATE_DATA *Private;
+} ;
+
+//
+// SD DXE driver private data structure
+//
+struct _SD_DRIVER_PRIVATE_DATA {
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_HANDLE Controller;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_HANDLE DriverBindingHandle;
+} ;
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+SdDxeDriverBindingStop (
+ 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
+SdDxeComponentNameGetDriverName (
+ 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
+SdDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Send command SET_RELATIVE_ADDRESS to the device to set the device address.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[out] Rca The relative device address to assign.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSetRca (
+ IN SD_DEVICE *Device,
+ OUT UINT16 *Rca
+ );
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSelect (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca
+ );
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdSendStatus (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ );
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the SD_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdGetCsd (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT SD_CSD *Csd
+ );
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the SD_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the SD_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdGetCid (
+ IN SD_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT SD_CID *Cid
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
new file mode 100644
index 000000000..69b856b66
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# SdDxe driver is used to manage the SD memory card device.
+#
+# It produces BlockIo and BlockIo2 protocols to allow upper layer
+# access the SD memory card device.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdDxe
+ MODULE_UNI_FILE = SdDxe.uni
+ FILE_GUID = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSdDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gSdDxeDriverBinding
+# COMPONENT_NAME = gSdDxeComponentName
+# COMPONENT_NAME2 = gSdDxeComponentName2
+#
+
+[Sources.common]
+ ComponentName.c
+ SdDxe.c
+ SdDxe.h
+ SdBlockIo.c
+ SdBlockIo.h
+ SdDiskInfo.c
+ SdDiskInfo.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiSdMmcPassThruProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ gEfiEraseBlockProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni
new file mode 100644
index 000000000..eb8ebd5a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni
@@ -0,0 +1,15 @@
+// /** @file
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer
+// access.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni
new file mode 100644
index 000000000..eb8ebd5a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni
@@ -0,0 +1,15 @@
+// /** @file
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer
+// access.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/DmaMem.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/DmaMem.c
new file mode 100644
index 000000000..61378a63c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/DmaMem.c
@@ -0,0 +1,242 @@
+/** @file
+ The DMA memory help function.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsBlockIoPei.h"
+
+EDKII_IOMMU_PPI *mIoMmu;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Map (
+ mIoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&mIoMmu
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
new file mode 100644
index 000000000..d79ca3904
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
@@ -0,0 +1,1150 @@
+/** @file
+
+ Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsBlockIoPei.h"
+
+//
+// Template for UFS HC Peim Private Data.
+//
+UFS_PEIM_HC_PRIVATE_DATA gUfsHcPeimTemplate = {
+ UFS_PEIM_HC_SIG, // Signature
+ NULL, // Controller
+ NULL, // Pool
+ { // BlkIoPpi
+ UfsBlockIoPeimGetDeviceNo,
+ UfsBlockIoPeimGetMediaInfo,
+ UfsBlockIoPeimReadBlocks
+ },
+ { // BlkIo2Ppi
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
+ UfsBlockIoPeimGetDeviceNo2,
+ UfsBlockIoPeimGetMediaInfo2,
+ UfsBlockIoPeimReadBlocks2
+ },
+ { // BlkIoPpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+ },
+ { // BlkIo2PpiList
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+ },
+ { // Media
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ },
+ {
+ MSG_UFS_DP,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0x1000,
+ 0
+ }
+ },
+ { // EndOfPeiNotifyList
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ UfsEndOfPei
+ },
+ 0, // UfsHcBase
+ 0, // Capabilities
+ 0, // TaskTag
+ 0, // UtpTrlBase
+ 0, // Nutrs
+ NULL, // TrlMapping
+ 0, // UtpTmrlBase
+ 0, // Nutmrs
+ NULL, // TmrlMapping
+ { // Luns
+ {
+ UFS_LUN_0, // Ufs Common Lun 0
+ UFS_LUN_1, // Ufs Common Lun 1
+ UFS_LUN_2, // Ufs Common Lun 2
+ UFS_LUN_3, // Ufs Common Lun 3
+ UFS_LUN_4, // Ufs Common Lun 4
+ UFS_LUN_5, // Ufs Common Lun 5
+ UFS_LUN_6, // Ufs Common Lun 6
+ UFS_LUN_7, // Ufs Common Lun 7
+ },
+ 0x0000, // By default exposing all Luns.
+ 0x0
+ }
+};
+
+
+
+/**
+ Execute TEST UNITY READY SCSI command on a specific UFS device.
+
+ @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The lun on which the SCSI cmd executed.
+ @param[out] SenseData A pointer to output sense data.
+ @param[out] SenseDataLength The length of output sense data.
+
+ @retval EFI_SUCCESS The command executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsPeimTestUnitReady (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINTN Lun,
+ OUT VOID *SenseData, OPTIONAL
+ OUT UINT8 *SenseDataLength
+ )
+{
+ UFS_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIX];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
+
+ Packet.Timeout = UFS_TIMEOUT;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = sizeof (Cdb);
+ Packet.DataDirection = UfsNoData;
+ Packet.SenseData = SenseData;
+ Packet.SenseDataLength = *SenseDataLength;
+
+ Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
+
+ if (*SenseDataLength != 0) {
+ *SenseDataLength = Packet.SenseDataLength;
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Execute READ CAPACITY(10) SCSI command on a specific UFS device.
+
+ @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The lun on which the SCSI cmd executed.
+ @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
+ @param[out] DataLength The length of output READ_CAPACITY data.
+ @param[out] SenseData A pointer to output sense data.
+ @param[out] SenseDataLength The length of output sense data.
+
+ @retval EFI_SUCCESS The command executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsPeimReadCapacity (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINTN Lun,
+ OUT VOID *DataBuffer,
+ OUT UINT32 *DataLength,
+ OUT VOID *SenseData, OPTIONAL
+ OUT UINT8 *SenseDataLength
+ )
+{
+ UFS_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
+
+ Packet.Timeout = UFS_TIMEOUT;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = sizeof (Cdb);
+ Packet.InDataBuffer = DataBuffer;
+ Packet.InTransferLength = *DataLength;
+ Packet.DataDirection = UfsDataIn;
+ Packet.SenseData = SenseData;
+ Packet.SenseDataLength = *SenseDataLength;
+
+ Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
+
+ if (*SenseDataLength != 0) {
+ *SenseDataLength = Packet.SenseDataLength;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ *DataLength = Packet.InTransferLength;
+ }
+
+ return Status;
+}
+
+/**
+ Execute READ CAPACITY(16) SCSI command on a specific UFS device.
+
+ @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The lun on which the SCSI cmd executed.
+ @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
+ @param[out] DataLength The length of output READ_CAPACITY data.
+ @param[out] SenseData A pointer to output sense data.
+ @param[out] SenseDataLength The length of output sense data.
+
+ @retval EFI_SUCCESS The command executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsPeimReadCapacity16 (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINTN Lun,
+ OUT VOID *DataBuffer,
+ OUT UINT32 *DataLength,
+ OUT VOID *SenseData, OPTIONAL
+ OUT UINT8 *SenseDataLength
+ )
+{
+ UFS_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
+ Cdb[1] = 0x10; // Service Action should be 0x10 for UFS device.
+ Cdb[13] = 0x20; // The maximum number of bytes for returned data.
+
+ Packet.Timeout = UFS_TIMEOUT;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = sizeof (Cdb);
+ Packet.InDataBuffer = DataBuffer;
+ Packet.InTransferLength = *DataLength;
+ Packet.DataDirection = UfsDataIn;
+ Packet.SenseData = SenseData;
+ Packet.SenseDataLength = *SenseDataLength;
+
+ Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
+
+ if (*SenseDataLength != 0) {
+ *SenseDataLength = Packet.SenseDataLength;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ *DataLength = Packet.InTransferLength;
+ }
+
+ return Status;
+}
+
+/**
+ Execute READ (10) SCSI command on a specific UFS device.
+
+ @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The lun on which the SCSI cmd executed.
+ @param[in] StartLba The start LBA.
+ @param[in] SectorNum The sector number to be read.
+ @param[out] DataBuffer A pointer to data buffer.
+ @param[out] DataLength The length of output data.
+ @param[out] SenseData A pointer to output sense data.
+ @param[out] SenseDataLength The length of output sense data.
+
+ @retval EFI_SUCCESS The command executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsPeimRead10 (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINTN Lun,
+ IN UINTN StartLba,
+ IN UINT32 SectorNum,
+ OUT VOID *DataBuffer,
+ OUT UINT32 *DataLength,
+ OUT VOID *SenseData, OPTIONAL
+ OUT UINT8 *SenseDataLength
+ )
+{
+ UFS_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = EFI_SCSI_OP_READ10;
+ WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));
+ WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));
+
+ Packet.Timeout = UFS_TIMEOUT;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = sizeof (Cdb);
+ Packet.InDataBuffer = DataBuffer;
+ Packet.InTransferLength = *DataLength;
+ Packet.DataDirection = UfsDataIn;
+ Packet.SenseData = SenseData;
+ Packet.SenseDataLength = *SenseDataLength;
+
+ Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
+
+ if (*SenseDataLength != 0) {
+ *SenseDataLength = Packet.SenseDataLength;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ *DataLength = Packet.InTransferLength;
+ }
+
+ return Status;
+}
+
+/**
+ Execute READ (16) SCSI command on a specific UFS device.
+
+ @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The lun on which the SCSI cmd executed.
+ @param[in] StartLba The start LBA.
+ @param[in] SectorNum The sector number to be read.
+ @param[out] DataBuffer A pointer to data buffer.
+ @param[out] DataLength The length of output data.
+ @param[out] SenseData A pointer to output sense data.
+ @param[out] SenseDataLength The length of output sense data.
+
+ @retval EFI_SUCCESS The command executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsPeimRead16 (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINTN Lun,
+ IN UINTN StartLba,
+ IN UINT32 SectorNum,
+ OUT VOID *DataBuffer,
+ OUT UINT32 *DataLength,
+ OUT VOID *SenseData, OPTIONAL
+ OUT UINT8 *SenseDataLength
+ )
+{
+ UFS_SCSI_REQUEST_PACKET Packet;
+ UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
+ EFI_STATUS Status;
+
+ ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
+ ZeroMem (Cdb, sizeof (Cdb));
+
+ Cdb[0] = EFI_SCSI_OP_READ16;
+ WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
+ WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));
+
+ Packet.Timeout = UFS_TIMEOUT;
+ Packet.Cdb = Cdb;
+ Packet.CdbLength = sizeof (Cdb);
+ Packet.InDataBuffer = DataBuffer;
+ Packet.InTransferLength = *DataLength;
+ Packet.DataDirection = UfsDataIn;
+ Packet.SenseData = SenseData;
+ Packet.SenseDataLength = *SenseDataLength;
+
+ Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
+
+ if (*SenseDataLength != 0) {
+ *SenseDataLength = Packet.SenseDataLength;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ *DataLength = Packet.InTransferLength;
+ }
+
+ return Status;
+}
+
+/**
+ Parsing Sense Keys from sense data.
+
+ @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
+ @param SenseData The pointer of EFI_SCSI_SENSE_DATA
+ @param NeedRetry The pointer of action which indicates what is need to retry
+
+ @retval EFI_DEVICE_ERROR Indicates that error occurs
+ @retval EFI_SUCCESS Successfully to complete the parsing
+
+**/
+EFI_STATUS
+UfsPeimParsingSenseKeys (
+ IN EFI_PEI_BLOCK_IO2_MEDIA *Media,
+ IN EFI_SCSI_SENSE_DATA *SenseData,
+ OUT BOOLEAN *NeedRetry
+ )
+{
+ if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
+ (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
+ Media->MediaPresent = FALSE;
+ *NeedRetry = FALSE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
+ (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
+ *NeedRetry = TRUE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));
+ return EFI_SUCCESS;
+ }
+
+ if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
+ (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
+ *NeedRetry = TRUE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
+ return EFI_SUCCESS;
+ }
+
+ if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) ||
+ ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
+ (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) {
+ *NeedRetry = FALSE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
+ *NeedRetry = FALSE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
+ (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NOT_READY) &&
+ (SenseData->Addnl_Sense_Code_Qualifier == EFI_SCSI_ASCQ_IN_PROGRESS)) {
+ *NeedRetry = TRUE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
+ return EFI_SUCCESS;
+ }
+
+ *NeedRetry = FALSE;
+ DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ //
+ // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
+ // At PEI phase, we will only expose normal Luns to user.
+ // For those disabled Lun, when user try to access it, the operation would fail.
+ //
+ *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+ EFI_SCSI_SENSE_DATA SenseData;
+ UINT8 SenseDataLength;
+ EFI_SCSI_DISK_CAPACITY_DATA Capacity;
+ EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16;
+ UINTN DataLength;
+ BOOLEAN NeedRetry;
+ UINTN Lun;
+
+ Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+ NeedRetry = TRUE;
+
+ if ((DeviceIndex == 0) || (DeviceIndex > UFS_PEIM_MAX_LUNS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Lun = DeviceIndex - 1;
+ if ((Private->Luns.BitMask & (BIT0 << Lun)) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ZeroMem (&SenseData, sizeof (SenseData));
+ ZeroMem (&Capacity, sizeof (Capacity));
+ ZeroMem (&Capacity16, sizeof (Capacity16));
+ SenseDataLength = sizeof (SenseData);
+ //
+ // First test unit ready
+ //
+ do {
+ Status = UfsPeimTestUnitReady (
+ Private,
+ Lun,
+ &SenseData,
+ &SenseDataLength
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (SenseDataLength == 0) {
+ continue;
+ }
+
+ Status = UfsPeimParsingSenseKeys (&(Private->Media[Lun]), &SenseData, &NeedRetry);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ } while (NeedRetry);
+
+ DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
+ SenseDataLength = 0;
+ Status = UfsPeimReadCapacity (Private, Lun, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&
+ (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {
+ DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
+ SenseDataLength = 0;
+ Status = UfsPeimReadCapacity16 (Private, Lun, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ Private->Media[Lun].LastBlock = ((UINT32)Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0;
+ Private->Media[Lun].LastBlock |= LShiftU64 ((UINT64)Capacity16.LastLba7, 56) | LShiftU64((UINT64)Capacity16.LastLba6, 48) | LShiftU64 ((UINT64)Capacity16.LastLba5, 40) | LShiftU64 ((UINT64)Capacity16.LastLba4, 32);
+ Private->Media[Lun].BlockSize = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0;
+ } else {
+ Private->Media[Lun].LastBlock = ((UINT32)Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0;
+ Private->Media[Lun].BlockSize = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0;
+ }
+
+ MediaInfo->DeviceType = UfsDevice;
+ MediaInfo->MediaPresent = Private->Media[Lun].MediaPresent;
+ MediaInfo->LastBlock = (UINTN)Private->Media[Lun].LastBlock;
+ MediaInfo->BlockSize = Private->Media[Lun].BlockSize;
+
+ 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, 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
+UfsBlockIoPeimReadBlocks (
+ 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_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+ EFI_SCSI_SENSE_DATA SenseData;
+ UINT8 SenseDataLength;
+ BOOLEAN NeedRetry;
+ UINTN Lun;
+
+ Status = EFI_SUCCESS;
+ NeedRetry = TRUE;
+ Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
+
+ ZeroMem (&SenseData, sizeof (SenseData));
+ SenseDataLength = sizeof (SenseData);
+
+ //
+ // Check parameters
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((DeviceIndex == 0) || (DeviceIndex > UFS_PEIM_MAX_LUNS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Lun = DeviceIndex - 1;
+ if ((Private->Luns.BitMask & (BIT0 << Lun)) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ BlockSize = Private->Media[Lun].BlockSize;
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > Private->Media[Lun].LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ do {
+ Status = UfsPeimTestUnitReady (
+ Private,
+ Lun,
+ &SenseData,
+ &SenseDataLength
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (SenseDataLength == 0) {
+ continue;
+ }
+
+ Status = UfsPeimParsingSenseKeys (&(Private->Media[Lun]), &SenseData, &NeedRetry);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ } while (NeedRetry);
+
+ SenseDataLength = 0;
+ if (Private->Media[Lun].LastBlock < 0xfffffffful) {
+ Status = UfsPeimRead10 (
+ Private,
+ Lun,
+ (UINT32)StartLBA,
+ (UINT32)NumberOfBlocks,
+ Buffer,
+ (UINT32 *)&BufferSize,
+ NULL,
+ &SenseDataLength
+ );
+ } else {
+ Status = UfsPeimRead16 (
+ Private,
+ Lun,
+ (UINT32)StartLBA,
+ (UINT32)NumberOfBlocks,
+ Buffer,
+ (UINT32 *)&BufferSize,
+ NULL,
+ &SenseDataLength
+ );
+ }
+ return Status;
+}
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ //
+ // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
+ // At PEI phase, we will only expose normal Luns to user.
+ // For those disabled Lun, when user try to access it, the operation would fail.
+ //
+ *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ UINTN Lun;
+
+ Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = UfsBlockIoPeimGetMediaInfo (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ &Media
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lun = DeviceIndex - 1;
+ CopyMem (MediaInfo, &(Private->Media[Lun]), sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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, 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
+UfsBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
+
+ Status = UfsBlockIoPeimReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+ return Status;
+}
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+UfsEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+
+ Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+
+ if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
+ UfsPeimFreeMemPool (Private->Pool);
+ }
+
+ if (Private->UtpTmrlBase != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
+ Private->UtpTmrlBase,
+ Private->TmrlMapping
+ );
+ }
+
+ if (Private->UtpTrlBase != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TRD)),
+ Private->UtpTrlBase,
+ Private->TrlMapping
+ );
+ }
+
+ UfsControllerStop (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user code starts with this function.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The driver is successfully initialized.
+ @retval Others Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUfsBlockIoPeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UFS_PEIM_HC_PRIVATE_DATA *Private;
+ EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;
+ UINT32 Index;
+ UFS_CONFIG_DESC Config;
+ UINTN MmioBase;
+ UINT8 Controller;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // locate ufs host controller PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiUfsHostControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &UfsHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IoMmuInit ();
+
+ Controller = 0;
+ MmioBase = 0;
+ while (TRUE) {
+ Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
+ Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
+ Private->UfsHcBase = MmioBase;
+
+ //
+ // Initialize the memory pool which will be used in all transactions.
+ //
+ Status = UfsPeimInitMemPool (Private);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize UFS Host Controller H/W.
+ //
+ Status = UfsControllerInit (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));
+ Controller++;
+ continue;
+ }
+
+ //
+ // UFS 2.0 spec Section 13.1.3.3:
+ // At the end of the UFS Interconnect Layer initialization on both host and device side,
+ // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
+ //
+ Status = UfsExecNopCmds (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
+ Controller++;
+ continue;
+ }
+
+ //
+ // The host enables the device initialization completion by setting fDeviceInit flag.
+ //
+ Status = UfsSetFlag (Private, UfsFlagDevInit);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
+ Controller++;
+ continue;
+ }
+
+ //
+ // Get Ufs Device's Lun Info by reading Configuration Descriptor.
+ //
+ Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));
+ Controller++;
+ continue;
+ }
+
+ for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) {
+ if (Config.UnitDescConfParams[Index].LunEn != 0) {
+ Private->Luns.BitMask |= (BIT0 << Index);
+ DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index));
+ }
+ }
+
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+ PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+ Controller++;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
new file mode 100644
index 000000000..6e2305aa2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
@@ -0,0 +1,693 @@
+/** @file
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_BLOCK_IO_PEI_H_
+#define _UFS_BLOCK_IO_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/UfsHostController.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <IndustryStandard/Scsi.h>
+
+#include "UfsHci.h"
+#include "UfsHcMem.h"
+
+#define UFS_PEIM_HC_SIG SIGNATURE_32 ('U', 'F', 'S', 'H')
+
+#define UFS_PEIM_MAX_LUNS 8
+
+typedef struct {
+ UINT8 Lun[UFS_PEIM_MAX_LUNS];
+ UINT16 BitMask:12; // Bit 0~7 is for common luns. Bit 8~11 is reserved for those well known luns
+ UINT16 Rsvd:4;
+} UFS_PEIM_EXPOSED_LUNS;
+
+typedef struct {
+ ///
+ /// The timeout, in 100 ns units, to use for the execution of this SCSI
+ /// Request Packet. A Timeout value of 0 means that this function
+ /// will wait indefinitely for the SCSI Request Packet to execute. If
+ /// Timeout is greater than zero, then this function will return
+ /// EFI_TIMEOUT if the time required to execute the SCSI
+ /// Request Packet is greater than Timeout.
+ ///
+ UINT64 Timeout;
+ ///
+ /// A pointer to the data buffer to transfer between the SCSI
+ /// controller and the SCSI device for read and bidirectional commands.
+ ///
+ VOID *InDataBuffer;
+ ///
+ /// A pointer to the data buffer to transfer between the SCSI
+ /// controller and the SCSI device for write or bidirectional commands.
+ ///
+ VOID *OutDataBuffer;
+ ///
+ /// A pointer to the sense data that was generated by the execution of
+ /// the SCSI Request Packet.
+ ///
+ VOID *SenseData;
+ ///
+ /// A pointer to buffer that contains the Command Data Block to
+ /// send to the SCSI device specified by Target and Lun.
+ ///
+ VOID *Cdb;
+ ///
+ /// On Input, the size, in bytes, of InDataBuffer. On output, the
+ /// number of bytes transferred between the SCSI controller and the SCSI device.
+ ///
+ UINT32 InTransferLength;
+ ///
+ /// On Input, the size, in bytes of OutDataBuffer. On Output, the
+ /// Number of bytes transferred between SCSI Controller and the SCSI device.
+ ///
+ UINT32 OutTransferLength;
+ ///
+ /// The length, in bytes, of the buffer Cdb. The standard values are 6,
+ /// 10, 12, and 16, but other values are possible if a variable length CDB is used.
+ ///
+ UINT8 CdbLength;
+ ///
+ /// The direction of the data transfer. 0 for reads, 1 for writes. A
+ /// value of 2 is Reserved for Bi-Directional SCSI commands.
+ ///
+ UINT8 DataDirection;
+ ///
+ /// On input, the length in bytes of the SenseData buffer. On
+ /// output, the number of bytes written to the SenseData buffer.
+ ///
+ UINT8 SenseDataLength;
+} UFS_SCSI_REQUEST_PACKET;
+
+typedef struct _UFS_PEIM_HC_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+
+ UFS_PEIM_MEM_POOL *Pool;
+
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+ EFI_PEI_BLOCK_IO2_MEDIA Media[UFS_PEIM_MAX_LUNS];
+
+ //
+ // EndOfPei callback is used to stop the UFS DMA operation
+ // after exit PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ UINTN UfsHcBase;
+ UINT32 Capabilities;
+
+ UINT8 TaskTag;
+
+ VOID *UtpTrlBase;
+ UINT8 Nutrs;
+ VOID *TrlMapping;
+ VOID *UtpTmrlBase;
+ UINT8 Nutmrs;
+ VOID *TmrlMapping;
+
+ UFS_PEIM_EXPOSED_LUNS Luns;
+} UFS_PEIM_HC_PRIVATE_DATA;
+
+#define UFS_TIMEOUT MultU64x32((UINT64)(3), 10000000)
+
+#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIoPpi, UFS_PEIM_HC_SIG)
+#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, UFS_PEIM_HC_SIG)
+#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, UFS_PEIM_HC_SIG)
+
+#define UFS_SCSI_OP_LENGTH_SIX 0x6
+#define UFS_SCSI_OP_LENGTH_TEN 0xa
+#define UFS_SCSI_OP_LENGTH_SIXTEEN 0x10
+
+typedef struct _UFS_DEVICE_MANAGEMENT_REQUEST_PACKET {
+ UINT64 Timeout;
+ VOID *InDataBuffer;
+ VOID *OutDataBuffer;
+ UINT8 Opcode;
+ UINT8 DescId;
+ UINT8 Index;
+ UINT8 Selector;
+ UINT32 InTransferLength;
+ UINT32 OutTransferLength;
+ UINT8 DataDirection;
+ UINT8 Ocs;
+} UFS_DEVICE_MANAGEMENT_REQUEST_PACKET;
+
+/**
+ Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
+ UFS device.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsExecScsiCmds (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN OUT UFS_SCSI_REQUEST_PACKET *Packet
+ );
+
+/**
+ Initialize the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+UfsControllerInit (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Stop the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
+ @retval Others A device error occurred while stopping the controller.
+
+**/
+EFI_STATUS
+UfsControllerStop (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Set specified flag to 1 on a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be set.
+
+ @retval EFI_SUCCESS The flag was set successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
+
+**/
+EFI_STATUS
+UfsSetFlag (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 FlagId
+ );
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in] DescSize The size of device descriptor buffer.
+
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
+
+**/
+EFI_STATUS
+UfsRwDeviceDesc (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT VOID *Descriptor,
+ IN UINT32 DescSize
+ );
+
+/**
+ Sends NOP IN cmd to a UFS device for initialization process request.
+ For more details, please refer to UFS 2.0 spec Figure 13.3.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
+ received successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
+
+**/
+EFI_STATUS
+UfsExecNopCmds (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ 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 The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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, 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
+UfsBlockIoPeimReadBlocks (
+ 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
+ );
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsBlockIoPeimGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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, 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
+UfsBlockIoPeimReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Ufs Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+UfsPeimInitMemPool (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+UfsPeimFreeMemPool (
+ IN UFS_PEIM_MEM_POOL *Pool
+ );
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UfsPeimAllocateMem (
+ IN UFS_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UfsPeimFreeMem (
+ IN UFS_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
+/**
+ One notified function to cleanup the allocated DMA buffers at the end of PEI.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
+ event that caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+UfsEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
new file mode 100644
index 000000000..6e1cbfde1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
@@ -0,0 +1,60 @@
+## @file
+# Description file for the Universal Flash Storage (UFS) Peim driver.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UfsBlockIoPei
+ MODULE_UNI_FILE = UfsBlockIoPei.uni
+ FILE_GUID = BE189D38-C963-41CF-B695-D90E9E545A13
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 0.9
+
+ ENTRY_POINT = InitializeUfsBlockIoPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UfsBlockIoPei.c
+ UfsBlockIoPei.h
+ UfsHci.c
+ UfsHci.h
+ UfsHcMem.c
+ UfsHcMem.h
+ DmaMem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
+ gEdkiiPeiUfsHostControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiUfsHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UfsBlockIoPeiExtra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni
new file mode 100644
index 000000000..51bbd7c89
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The UfsBlockIoPei driver is used to support recovery from UFS device.
+//
+// The UfsBlockIoPei driver is used to support recovery from UFS device.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from UFS devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The UfsBlockIoPei driver is used to support recovery from UFS device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni
new file mode 100644
index 000000000..f64657432
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UfsBlockIoPei Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UFS BlockIo Peim for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c
new file mode 100644
index 000000000..a4e731640
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.c
@@ -0,0 +1,429 @@
+/** @file
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsBlockIoPei.h"
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+UFS_PEIM_MEM_BLOCK *
+UfsPeimAllocMemBlock (
+ IN UINTN Pages
+ )
+{
+ UFS_PEIM_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Block = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof(UFS_PEIM_MEM_BLOCK), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(UFS_PEIM_MEM_BLOCK));
+
+ //
+ // each bit in the bit array represents UFS_PEIM_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (UFS_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (UFS_PEIM_MEM_BLOCK*)(UINTN)TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (UFS_PEIM_MEM_UNIT * 8);
+
+ Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);
+
+ Block->Bits = (UINT8*)(UINTN)TempPtr;
+
+ Status = IoMmuAllocateBuffer (
+ Pages,
+ &BufHost,
+ &MappedAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ZeroMem ((VOID*)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
+
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+}
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UfsPeimFreeMemBlock (
+ IN UFS_PEIM_MEM_POOL *Pool,
+ IN UFS_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+}
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UfsPeimAllocMemFromBlock (
+ IN UFS_PEIM_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ UFS_PEIM_NEXT_BIT (Byte, Bit);
+
+ } else {
+ UFS_PEIM_NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) UFS_PEIM_MEM_BIT (Bit));
+ UFS_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->Buf + (StartByte * 8 + StartBit) * UFS_PEIM_MEM_UNIT;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UfsPeimInsertMemBlockToPool (
+ IN UFS_PEIM_MEM_BLOCK *Head,
+ IN UFS_PEIM_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UfsPeimIsMemBlockEmpty (
+ IN UFS_PEIM_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param Private The Ufs Peim driver private data.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval Others Fail to init the memory pool.
+
+**/
+EFI_STATUS
+UfsPeimInitMemPool (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ UFS_PEIM_MEM_POOL *Pool;
+ EFI_STATUS Status;
+ VOID *TempPtr;
+
+ TempPtr = NULL;
+ Pool = NULL;
+
+ Status = PeiServicesAllocatePool (sizeof (UFS_PEIM_MEM_POOL), &TempPtr);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (UFS_PEIM_MEM_POOL));
+
+ Pool = (UFS_PEIM_MEM_POOL *)((UINTN)TempPtr);
+
+ Pool->Head = UfsPeimAllocMemBlock (UFS_PEIM_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Pool = Pool;
+ return EFI_SUCCESS;
+}
+
+/**
+ Release the memory management pool.
+
+ @param Pool The memory pool to free.
+
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.
+ @retval EFI_SUCCESS The memory pool is freed.
+
+**/
+EFI_STATUS
+UfsPeimFreeMemPool (
+ IN UFS_PEIM_MEM_POOL *Pool
+ )
+{
+ UFS_PEIM_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UfsPeimFreeMemBlock (Pool, Block);
+ }
+
+ UfsPeimFreeMemBlock (Pool, Pool->Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UfsPeimAllocateMem (
+ IN UFS_PEIM_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ UFS_PEIM_MEM_BLOCK *Head;
+ UFS_PEIM_MEM_BLOCK *Block;
+ UFS_PEIM_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = UFS_PEIM_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UfsPeimAllocMemFromBlock (Block, AllocSize / UFS_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (UFS_PEIM_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = UFS_PEIM_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UfsPeimAllocMemBlock (Pages);
+ if (NewBlock == NULL) {
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UfsPeimInsertMemBlockToPool (Head, NewBlock);
+ Mem = UfsPeimAllocMemFromBlock (NewBlock, AllocSize / UFS_PEIM_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UfsPeimFreeMem (
+ IN UFS_PEIM_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ UFS_PEIM_MEM_BLOCK *Head;
+ UFS_PEIM_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = UFS_PEIM_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->Buf) / UFS_PEIM_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit array
+ //
+ for (Count = 0; Count < (AllocSize / UFS_PEIM_MEM_UNIT); Count++) {
+ ASSERT (UFS_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ UFS_PEIM_MEM_BIT (Bit));
+ UFS_PEIM_NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UfsPeimIsMemBlockEmpty (Block)) {
+ UfsPeimFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h
new file mode 100644
index 000000000..b47d05a1a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHcMem.h
@@ -0,0 +1,56 @@
+/** @file
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_PEIM_MEM_H_
+#define _UFS_PEIM_MEM_H_
+
+#define UFS_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
+
+#define UFS_PEIM_MEM_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & UFS_PEIM_MEM_BIT(Bit)) == UFS_PEIM_MEM_BIT(Bit)))
+
+typedef struct _UFS_PEIM_MEM_BLOCK UFS_PEIM_MEM_BLOCK;
+
+struct _UFS_PEIM_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ UFS_PEIM_MEM_BLOCK *Next;
+};
+
+typedef struct _UFS_PEIM_MEM_POOL {
+ UFS_PEIM_MEM_BLOCK *Head;
+} UFS_PEIM_MEM_POOL;
+
+//
+// Memory allocation unit, note that the value must meet UFS spec alignment requirement.
+//
+#define UFS_PEIM_MEM_UNIT 128
+
+#define UFS_PEIM_MEM_UNIT_MASK (UFS_PEIM_MEM_UNIT - 1)
+#define UFS_PEIM_MEM_DEFAULT_PAGES 16
+
+#define UFS_PEIM_MEM_ROUND(Len) (((Len) + UFS_PEIM_MEM_UNIT_MASK) & (~UFS_PEIM_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define UFS_PEIM_NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
new file mode 100644
index 000000000..e450f6f49
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
@@ -0,0 +1,1668 @@
+/** @file
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsBlockIoPei.h"
+
+/**
+ Wait for the value of the specified system memory set to the test value.
+
+ @param Address The system memory address to test.
+ @param MaskValue The mask value of memory.
+ @param TestValue The test value of memory.
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsWaitMemSet (
+ IN UINTN Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 10) + 1;
+
+ do {
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = MmioRead32 (Address) & MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 1 microseconds.
+ //
+ MicroSecondDelay (1);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Dump UIC command execution result for debugging.
+
+ @param[in] UicOpcode The executed UIC opcode.
+ @param[in] Result The result to be parsed.
+
+**/
+VOID
+DumpUicCmdExecResult (
+ IN UINT8 UicOpcode,
+ IN UINT8 Result
+ )
+{
+ if (UicOpcode <= UfsUicDmePeerSet) {
+ switch (Result) {
+ case 0x00:
+ break;
+ case 0x01:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x02:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
+ break;
+ case 0x03:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x04:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x05:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
+ break;
+ case 0x06:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x07:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
+ break;
+ case 0x08:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
+ break;
+ case 0x09:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - BUSY\n"));
+ break;
+ case 0x0A:
+ DEBUG ((EFI_D_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+ } else {
+ switch (Result) {
+ case 0x00:
+ break;
+ case 0x01:
+ DEBUG ((EFI_D_VERBOSE, "UIC control command fails - FAILURE\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+ }
+}
+
+/**
+ Dump QUERY RESPONSE UPIU result for debugging.
+
+ @param[in] Result The result to be parsed.
+
+**/
+VOID
+DumpQueryResponseResult (
+ IN UINT8 Result
+ )
+{
+ switch (Result) {
+ case 0xF6:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Readable\n"));
+ break;
+ case 0xF7:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Not Writeable\n"));
+ break;
+ case 0xF8:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Parameter Already Written\n"));
+ break;
+ case 0xF9:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Length\n"));
+ break;
+ case 0xFA:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Value\n"));
+ break;
+ case 0xFB:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Selector\n"));
+ break;
+ case 0xFC:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Index\n"));
+ break;
+ case 0xFD:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Idn\n"));
+ break;
+ case 0xFE:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with Invalid Opcode\n"));
+ break;
+ case 0xFF:
+ DEBUG ((EFI_D_VERBOSE, "Query Response with General Failure\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Swap little endian to big endian.
+
+ @param[in, out] Buffer The data buffer. In input, it contains little endian data.
+ In output, it will become big endian.
+ @param[in] BufferSize The length of converted data.
+
+**/
+VOID
+SwapLittleEndianToBigEndian (
+ IN OUT UINT8 *Buffer,
+ IN UINT32 BufferSize
+ )
+{
+ UINT32 Index;
+ UINT8 Temp;
+ UINT32 SwapCount;
+
+ SwapCount = BufferSize / 2;
+ for (Index = 0; Index < SwapCount; Index++) {
+ Temp = Buffer[Index];
+ Buffer[Index] = Buffer[BufferSize - 1 - Index];
+ Buffer[BufferSize - 1 - Index] = Temp;
+ }
+}
+
+/**
+ Fill TSF field of QUERY REQUEST UPIU.
+
+ @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
+ @param[in] Opcode The opcode of request.
+ @param[in] DescId The descriptor ID of request.
+ @param[in] Index The index of request.
+ @param[in] Selector The selector of request.
+ @param[in] Length The length of transferred data. The maximum is 4.
+ @param[in] Value The value of transferred data.
+
+**/
+VOID
+UfsFillTsfOfQueryReqUpiu (
+ IN OUT UTP_UPIU_TSF *TsfBase,
+ IN UINT8 Opcode,
+ IN UINT8 DescId OPTIONAL,
+ IN UINT8 Index OPTIONAL,
+ IN UINT8 Selector OPTIONAL,
+ IN UINT16 Length OPTIONAL,
+ IN UINT32 Value OPTIONAL
+ )
+{
+ ASSERT (TsfBase != NULL);
+ ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
+
+ TsfBase->Opcode = Opcode;
+ if (Opcode != UtpQueryFuncOpcodeNop) {
+ TsfBase->DescId = DescId;
+ TsfBase->Index = Index;
+ TsfBase->Selector = Selector;
+
+ if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
+ SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
+ TsfBase->Length = Length;
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrAttr) {
+ SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
+ TsfBase->Value = Value;
+ }
+ }
+}
+
+/**
+ Initialize COMMAND UPIU.
+
+ @param[in, out] Command The base address of COMMAND UPIU.
+ @param[in] Lun The Lun on which the SCSI command is executed.
+ @param[in] TaskTag The task tag of request.
+ @param[in] Cdb The cdb buffer containing SCSI command.
+ @param[in] CdbLength The cdb length.
+ @param[in] DataDirection The direction of data transfer.
+ @param[in] ExpDataTranLen The expected transfer data length.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitCommandUpiu (
+ IN OUT UTP_COMMAND_UPIU *Command,
+ IN UINT8 Lun,
+ IN UINT8 TaskTag,
+ IN UINT8 *Cdb,
+ IN UINT8 CdbLength,
+ IN UFS_DATA_DIRECTION DataDirection,
+ IN UINT32 ExpDataTranLen
+ )
+{
+ UINT8 Flags;
+
+ ASSERT ((Command != NULL) && (Cdb != NULL));
+
+ //
+ // Task attribute is hard-coded to Ordered.
+ //
+ if (DataDirection == UfsDataIn) {
+ Flags = BIT0 | BIT6;
+ } else if (DataDirection == UfsDataOut) {
+ Flags = BIT0 | BIT5;
+ } else {
+ Flags = BIT0;
+ }
+
+ //
+ // Fill UTP COMMAND UPIU associated fields.
+ //
+ Command->TransCode = 0x01;
+ Command->Flags = Flags;
+ Command->Lun = Lun;
+ Command->TaskTag = TaskTag;
+ Command->CmdSet = 0x00;
+ SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
+ Command->ExpDataTranLen = ExpDataTranLen;
+
+ CopyMem (Command->Cdb, Cdb, CdbLength);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UTP PRDT for data transfer.
+
+ @param[in] Prdt The base address of PRDT.
+ @param[in] Buffer The buffer to be read or written.
+ @param[in] BufferSize The data size to be read or written.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitUtpPrdt (
+ IN UTP_TR_PRD *Prdt,
+ IN VOID *Buffer,
+ IN UINT32 BufferSize
+ )
+{
+ UINT32 PrdtIndex;
+ UINT32 RemainingLen;
+ UINT8 *Remaining;
+ UINTN PrdtNumber;
+
+ if ((BufferSize & (BIT0 | BIT1)) != 0) {
+ BufferSize &= ~(BIT0 | BIT1);
+ DEBUG ((EFI_D_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
+
+ RemainingLen = BufferSize;
+ Remaining = Buffer;
+ PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
+
+ for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
+ if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
+ Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
+ } else {
+ Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
+ }
+
+ Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
+ Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
+ RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
+ Remaining += UFS_MAX_DATA_LEN_PER_PRD;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize QUERY REQUEST UPIU.
+
+ @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
+ @param[in] TaskTag The task tag of request.
+ @param[in] Opcode The opcode of request.
+ @param[in] DescId The descriptor ID of request.
+ @param[in] Index The index of request.
+ @param[in] Selector The selector of request.
+ @param[in] DataSize The data size to be read or written.
+ @param[in] Data The buffer to be read or written.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitQueryRequestUpiu (
+ IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
+ IN UINT8 TaskTag,
+ IN UINT8 Opcode,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN UINTN DataSize OPTIONAL,
+ IN UINT8 *Data OPTIONAL
+ )
+{
+ ASSERT (QueryReq != NULL);
+
+ QueryReq->TransCode = 0x16;
+ QueryReq->TaskTag = TaskTag;
+ if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
+ QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
+ } else {
+ QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrAttr) {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
+ } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
+ } else {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrDesc) {
+ CopyMem (QueryReq + 1, Data, DataSize);
+
+ SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
+ QueryReq->DataSegLen = (UINT16)DataSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The Lun on which the SCSI command is executed.
+ @param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+ @param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsCreateScsiCommandDesc (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN UFS_SCSI_REQUEST_PACKET *Packet,
+ IN UTP_TRD *Trd,
+ OUT VOID **BufferMap
+ )
+{
+ UINT8 *CommandDesc;
+ UINTN TotalLen;
+ UINTN PrdtNumber;
+ VOID *Buffer;
+ UINT32 Length;
+ UTP_COMMAND_UPIU *CommandUpiu;
+ UTP_TR_PRD *PrdtBase;
+ UFS_DATA_DIRECTION DataDirection;
+ EFI_STATUS Status;
+ EDKII_IOMMU_OPERATION MapOp;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS BufferPhyAddr;
+
+ ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
+
+ BufferPhyAddr = 0;
+
+ if (Packet->DataDirection == UfsDataIn) {
+ Buffer = Packet->InDataBuffer;
+ Length = Packet->InTransferLength;
+ DataDirection = UfsDataIn;
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ Buffer = Packet->OutDataBuffer;
+ Length = Packet->OutTransferLength;
+ DataDirection = UfsDataOut;
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ if (Length == 0) {
+ DataDirection = UfsNoData;
+ } else {
+ MapLength = Length;
+ Status = IoMmuMap (MapOp, Buffer, &MapLength, &BufferPhyAddr, BufferMap);
+
+ if (EFI_ERROR (Status) || (MapLength != Length)) {
+ DEBUG ((DEBUG_ERROR, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
+
+ TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
+ CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
+ if (CommandDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CommandUpiu = (UTP_COMMAND_UPIU*)CommandDesc;
+ PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
+
+ UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
+ UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)BufferPhyAddr, Length);
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
+ // *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = DataDirection;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)CommandUpiu, 32);
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
+ Trd->PrdtL = (UINT16)PrdtNumber;
+ Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+ @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
+
+**/
+EFI_STATUS
+UfsCreateDMCommandDesc (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
+ IN UTP_TRD *Trd
+ )
+{
+ UINT8 *CommandDesc;
+ UINTN TotalLen;
+ UTP_QUERY_REQ_UPIU *QueryReqUpiu;
+ UINT8 Opcode;
+ UINT32 DataSize;
+ UINT8 *Data;
+ UINT8 DataDirection;
+
+ ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
+
+ Opcode = Packet->Opcode;
+ if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DataDirection = Packet->DataDirection;
+ if (DataDirection == UfsDataIn) {
+ DataSize = Packet->InTransferLength;
+ Data = Packet->InDataBuffer;
+ } else if (DataDirection == UfsDataOut) {
+ DataSize = Packet->OutTransferLength;
+ Data = Packet->OutDataBuffer;
+ } else {
+ DataSize = 0;
+ Data = NULL;
+ }
+
+ if (((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))
+ && ((DataSize == 0) || (Data == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))
+ && ((DataSize != 0) || (Data != NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Opcode == UtpQueryFuncOpcodeWrAttr) && (DataSize != sizeof (UINT32))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
+ TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
+ } else {
+ TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
+ }
+
+ CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
+ if (CommandDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize UTP QUERY REQUEST UPIU
+ //
+ QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)CommandDesc;
+ UfsInitQueryRequestUpiu (
+ QueryReqUpiu,
+ Private->TaskTag++,
+ Opcode,
+ Packet->DescId,
+ Packet->Index,
+ Packet->Selector,
+ DataSize,
+ Data
+ );
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = DataDirection;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)QueryReqUpiu, 32);
+ if (Opcode == UtpQueryFuncOpcodeWrDesc) {
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
+ } else {
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsCreateNopCommandDesc (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UTP_TRD *Trd
+ )
+{
+ UINT8 *CommandDesc;
+ UINTN TotalLen;
+ UTP_NOP_OUT_UPIU *NopOutUpiu;
+
+ ASSERT ((Private != NULL) && (Trd != NULL));
+
+ TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
+ CommandDesc = UfsPeimAllocateMem (Private->Pool, TotalLen);
+ if (CommandDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NopOutUpiu = (UTP_NOP_OUT_UPIU*)CommandDesc;
+
+ NopOutUpiu->TaskTag = Private->TaskTag++;
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = 0x00;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)(UINTN)NopOutUpiu, 32);
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find out available slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[out] Slot The available slot.
+
+ @retval EFI_SUCCESS The available slot was found successfully.
+
+**/
+EFI_STATUS
+UfsFindAvailableSlotInTrl (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ OUT UINT8 *Slot
+ )
+{
+ ASSERT ((Private != NULL) && (Slot != NULL));
+
+ //
+ // The simplest algo to always use slot 0.
+ // TODO: enhance it to support async transfer with multiple slot.
+ //
+ *Slot = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Start specified slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Slot The slot to be started.
+
+**/
+VOID
+UfsStartExecCmd (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ UINTN UfsHcBase;
+ UINTN Address;
+ UINT32 Data;
+
+ UfsHcBase = Private->UfsHcBase;
+
+ Address = UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
+ MmioWrite32 (Address, UFS_HC_UTRLRSR);
+ }
+
+ Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ MmioWrite32 (Address, BIT0 << Slot);
+}
+
+/**
+ Stop specified slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Slot The slot to be stop.
+
+**/
+VOID
+UfsStopExecCmd (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ UINTN UfsHcBase;
+ UINTN Address;
+ UINT32 Data;
+
+ UfsHcBase = Private->UfsHcBase;
+
+ Address = UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & (BIT0 << Slot)) != 0) {
+ Address = UfsHcBase + UFS_HC_UTRLCLR_OFFSET;
+ Data = MmioRead32 (Address);
+ MmioWrite32 (Address, (Data & ~(BIT0 << Slot)));
+ }
+}
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in] DescSize The size of device descriptor buffer.
+
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
+
+**/
+EFI_STATUS
+UfsRwDeviceDesc (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT VOID *Descriptor,
+ IN UINT32 DescSize
+ )
+{
+ EFI_STATUS Status;
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UINTN Address;
+ UTP_QUERY_RESP_UPIU *QueryResp;
+ UINT8 *CmdDescBase;
+ UINT32 CmdDescSize;
+ UINT16 ReturnDataSize;
+
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
+
+ if (Read) {
+ Packet.DataDirection = UfsDataIn;
+ Packet.InDataBuffer = Descriptor;
+ Packet.InTransferLength = DescSize;
+ Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
+ } else {
+ Packet.DataDirection = UfsDataOut;
+ Packet.OutDataBuffer = Descriptor;
+ Packet.OutTransferLength = DescSize;
+ Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
+ }
+ Packet.DescId = DescId;
+ Packet.Index = Index;
+ Packet.Selector = Selector;
+ Packet.Timeout = UFS_TIMEOUT;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ //
+ // Fill transfer request descriptor to this slot.
+ //
+ Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
+ QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
+ CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (QueryResp->QueryResp != 0) {
+ DumpQueryResponseResult (QueryResp->QueryResp);
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (Trd->Ocs == 0) {
+ ReturnDataSize = QueryResp->Tsf.Length;
+ SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
+
+ if (Read) {
+ //
+ // Make sure the hardware device does not return more data than expected.
+ //
+ if (ReturnDataSize > Packet.InTransferLength) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);
+ Packet.InTransferLength = ReturnDataSize;
+ } else {
+ Packet.OutTransferLength = ReturnDataSize;
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ UfsStopExecCmd (Private, Slot);
+ UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
+
+ return Status;
+}
+
+
+
+/**
+ Read or write specified flag of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] FlagId The ID of flag to be read or written.
+ @param[in, out] Value The value to set or clear flag.
+
+ @retval EFI_SUCCESS The flag was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
+
+**/
+EFI_STATUS
+UfsRwFlags (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 FlagId,
+ IN OUT UINT8 *Value
+ )
+{
+ EFI_STATUS Status;
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UINTN Address;
+ UTP_QUERY_RESP_UPIU *QueryResp;
+ UINT8 *CmdDescBase;
+ UINT32 CmdDescSize;
+
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
+
+ if (Read) {
+ ASSERT (Value != NULL);
+ Packet.DataDirection = UfsDataIn;
+ Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
+ } else {
+ Packet.DataDirection = UfsDataOut;
+ if (*Value == 1) {
+ Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
+ } else if (*Value == 0) {
+ Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ Packet.DescId = FlagId;
+ Packet.Index = 0;
+ Packet.Selector = 0;
+ Packet.Timeout = UFS_TIMEOUT;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill transfer request descriptor to this slot.
+ //
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
+ QueryResp = (UTP_QUERY_RESP_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
+ CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (QueryResp->QueryResp != 0) {
+ DumpQueryResponseResult (QueryResp->QueryResp);
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (Trd->Ocs == 0) {
+ //
+ // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
+ //
+ *Value = *((UINT8*)&(QueryResp->Tsf.Value) + 3);
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ UfsStopExecCmd (Private, Slot);
+ UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
+
+ return Status;
+}
+
+/**
+ Set specified flag to 1 on a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be set.
+
+ @retval EFI_SUCCESS The flag was set successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
+
+**/
+EFI_STATUS
+UfsSetFlag (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 FlagId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ Value = 1;
+ Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
+
+ return Status;
+}
+
+
+
+/**
+ Sends NOP IN cmd to a UFS device for initialization process request.
+ For more details, please refer to UFS 2.0 spec Figure 13.3.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
+ received successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
+
+**/
+EFI_STATUS
+UfsExecNopCmds (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UTP_NOP_IN_UPIU *NopInUpiu;
+ UINT8 *CmdDescBase;
+ UINT32 CmdDescSize;
+ UINTN Address;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ Status = UfsCreateNopCommandDesc (Private, Trd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
+ NopInUpiu = (UTP_NOP_IN_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
+ CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (NopInUpiu->Resp != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Exit:
+ UfsStopExecCmd (Private, Slot);
+ UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
+
+ return Status;
+}
+
+/**
+ Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
+ UFS device.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsExecScsiCmds (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN OUT UFS_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UINTN Address;
+ UINT8 *CmdDescBase;
+ UINT32 CmdDescSize;
+ UTP_RESPONSE_UPIU *Response;
+ UINT16 SenseDataLen;
+ UINT32 ResTranCount;
+ VOID *PacketBufferMap;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ PacketBufferMap = NULL;
+
+ //
+ // Fill transfer request descriptor to this slot.
+ //
+ Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CmdDescBase = (UINT8*)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));
+ CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof (UTP_TR_PRD);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;
+ Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet->Timeout);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Get sense data if exists
+ //
+ Response = (UTP_RESPONSE_UPIU*)(CmdDescBase + Trd->RuO * sizeof (UINT32));
+ SenseDataLen = Response->SenseDataLen;
+ SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
+
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
+ //
+ // Make sure the hardware device does not return more data than expected.
+ //
+ if (SenseDataLen <= Packet->SenseDataLength) {
+ CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
+ Packet->SenseDataLength = (UINT8)SenseDataLen;
+ } else {
+ Packet->SenseDataLength = 0;
+ }
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ if (Response->Response != 0) {
+ DEBUG ((EFI_D_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (Trd->Ocs == 0) {
+ if (Packet->DataDirection == UfsDataIn) {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->InTransferLength -= ResTranCount;
+ }
+ } else if (Packet->DataDirection == UfsDataOut) {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->OutTransferLength -= ResTranCount;
+ }
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ if (PacketBufferMap != NULL) {
+ IoMmuUnmap (PacketBufferMap);
+ }
+ UfsStopExecCmd (Private, Slot);
+ UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
+
+ return Status;
+}
+
+
+/**
+ Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] UicOpcode The opcode of the UIC command.
+ @param[in] Arg1 The value for 1st argument of the UIC command.
+ @param[in] Arg2 The value for 2nd argument of the UIC command.
+ @param[in] Arg3 The value for 3rd argument of the UIC command.
+
+ @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
+ @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
+ @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
+
+**/
+EFI_STATUS
+UfsExecUicCommands (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 UicOpcode,
+ IN UINT32 Arg1,
+ IN UINT32 Arg2,
+ IN UINT32 Arg3
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINT32 Data;
+ UINTN UfsHcBase;
+
+ UfsHcBase = Private->UfsHcBase;
+ Address = UfsHcBase + UFS_HC_IS_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
+ //
+ // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
+ //
+ MmioWrite32 (Address, Data);
+ }
+
+ //
+ // When programming UIC command registers, host software shall set the register UICCMD
+ // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
+ // are set.
+ //
+ Address = UfsHcBase + UFS_HC_UCMD_ARG1_OFFSET;
+ MmioWrite32 (Address, Arg1);
+
+ Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
+ MmioWrite32 (Address, Arg2);
+
+ Address = UfsHcBase + UFS_HC_UCMD_ARG3_OFFSET;
+ MmioWrite32 (Address, Arg3);
+
+ //
+ // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
+ //
+ Address = Private->UfsHcBase + UFS_HC_STATUS_OFFSET;
+ Status = UfsWaitMemSet (Address, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Address = UfsHcBase + UFS_HC_UIC_CMD_OFFSET;
+ MmioWrite32 (Address, (UINT32)UicOpcode);
+
+ //
+ // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
+ // This bit is set to '1' by the host controller upon completion of a UIC command.
+ //
+ Address = UfsHcBase + UFS_HC_IS_OFFSET;
+ Data = MmioRead32 (Address);
+ Status = UfsWaitMemSet (Address, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UicOpcode != UfsUicDmeReset) {
+ Address = UfsHcBase + UFS_HC_UCMD_ARG2_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & 0xFF) != 0) {
+ DEBUG_CODE_BEGIN();
+ DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));
+ DEBUG_CODE_END();
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Check value of HCS.DP and make sure that there is a device attached to the Link.
+ //
+ Address = UfsHcBase + UFS_HC_STATUS_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & UFS_HC_HCS_DP) == 0) {
+ Address = UfsHcBase + UFS_HC_IS_OFFSET;
+ Status = UfsWaitMemSet (Address, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((EFI_D_INFO, "UfsblockioPei: found a attached UFS device\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable the UFS host controller for accessing.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
+
+**/
+EFI_STATUS
+UfsEnableHostController (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINT32 Data;
+
+ //
+ // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
+ //
+ // Reinitialize the UFS host controller if HCE bit of HC register is set.
+ //
+ Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
+ Data = MmioRead32 (Address);
+ if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
+ //
+ // Write a 0 to the HCE register at first to disable the host controller.
+ //
+ MmioWrite32 (Address, 0);
+ //
+ // Wait until HCE is read as '0' before continuing.
+ //
+ Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Write a 1 to the HCE register to enable the UFS host controller.
+ //
+ MmioWrite32 (Address, UFS_HC_HCE_EN);
+ //
+ // Wait until HCE is read as '1' before continuing.
+ //
+ Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect if a UFS device attached.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS device detection was executed successfully.
+ @retval EFI_NOT_FOUND Not found a UFS device attached.
+ @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
+
+**/
+EFI_STATUS
+UfsDeviceDetection (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ UINTN Retry;
+ EFI_STATUS Status;
+
+ //
+ // Start UFS device detection.
+ // Try up to 3 times for establishing data link with device.
+ //
+ for (Retry = 0; Retry < 3; Retry++) {
+ Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ continue;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Retry == 3) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UFS task management request list related h/w context.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
+ @retval EFI_DEVICE_ERROR The initialization fails.
+
+**/
+EFI_STATUS
+UfsInitTaskManagementRequestList (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ UINTN Address;
+ UINT32 Data;
+ UINT8 Nutmrs;
+ VOID *CmdDescHost;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ VOID *CmdDescMapping;
+ EFI_STATUS Status;
+
+ //
+ // Initial h/w and s/w context for future operations.
+ //
+ Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
+ Data = MmioRead32 (Address);
+ Private->Capabilities = Data;
+
+ //
+ // Allocate and initialize UTP Task Management Request List.
+ //
+ Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
+ Status = IoMmuAllocateBuffer (
+ EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
+ &CmdDescHost,
+ &CmdDescPhyAddr,
+ &CmdDescMapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
+
+ //
+ // Program the UTP Task Management Request List Base Address and UTP Task Management
+ // Request List Base Address with a 64-bit address allocated at step 6.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
+ MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
+ Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
+ MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
+ Private->UtpTmrlBase = (VOID*)(UINTN)CmdDescHost;
+ Private->Nutmrs = Nutmrs;
+ Private->TmrlMapping = CmdDescMapping;
+
+ //
+ // Enable the UTP Task Management Request List by setting the UTP Task Management
+ // Request List RunStop Register (UTMRLRSR) to '1'.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
+ MmioWrite32 (Address, UFS_HC_UTMRLRSR);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UFS transfer request list related h/w context.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
+ @retval EFI_DEVICE_ERROR The initialization fails.
+
+**/
+EFI_STATUS
+UfsInitTransferRequestList (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ UINTN Address;
+ UINT32 Data;
+ UINT8 Nutrs;
+ VOID *CmdDescHost;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ VOID *CmdDescMapping;
+ EFI_STATUS Status;
+
+ //
+ // Initial h/w and s/w context for future operations.
+ //
+ Address = Private->UfsHcBase + UFS_HC_CAP_OFFSET;
+ Data = MmioRead32 (Address);
+ Private->Capabilities = Data;
+
+ //
+ // Allocate and initialize UTP Transfer Request List.
+ //
+ Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
+ Status = IoMmuAllocateBuffer (
+ EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
+ &CmdDescHost,
+ &CmdDescPhyAddr,
+ &CmdDescMapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
+
+ //
+ // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
+ // Base Address with a 64-bit address allocated at step 8.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
+ MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
+ Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
+ MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
+ Private->UtpTrlBase = (VOID*)(UINTN)CmdDescHost;
+ Private->Nutrs = Nutrs;
+ Private->TrlMapping = CmdDescMapping;
+
+ //
+ // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
+ // RunStop Register (UTRLRSR) to '1'.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
+ MmioWrite32 (Address, UFS_HC_UTRLRSR);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+UfsControllerInit (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UfsEnableHostController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UfsDevicePei: Enable Host Controller Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsDeviceDetection (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UfsDevicePei: Device Detection Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsInitTaskManagementRequestList (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UfsDevicePei: Task management list initialization Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsInitTransferRequestList (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
+
+ if (Private->TmrlMapping != NULL) {
+ IoMmuFreeBuffer (
+ EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
+ Private->UtpTmrlBase,
+ Private->TmrlMapping
+ );
+ Private->TmrlMapping = NULL;
+ }
+
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "UfsDevicePei Finished\n"));
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
+ @retval Others A device error occurred while stopping the controller.
+
+**/
+EFI_STATUS
+UfsControllerStop (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINT32 Data;
+
+ //
+ // Enable the UTP Task Management Request List by setting the UTP Task Management
+ // Request List RunStop Register (UTMRLRSR) to '1'.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTMRLRSR_OFFSET;
+ MmioWrite32 (Address, 0);
+
+ //
+ // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
+ // RunStop Register (UTRLRSR) to '1'.
+ //
+ Address = Private->UfsHcBase + UFS_HC_UTRLRSR_OFFSET;
+ MmioWrite32 (Address, 0);
+
+ //
+ // Write a 0 to the HCE register in order to disable the host controller.
+ //
+ Address = Private->UfsHcBase + UFS_HC_ENABLE_OFFSET;
+ Data = MmioRead32 (Address);
+ ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
+ MmioWrite32 (Address, 0);
+
+ //
+ // Wait until HCE is read as '0' before continuing.
+ //
+ Status = UfsWaitMemSet (Address, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "UfsDevicePei: Stop the UFS Host Controller\n"));
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h
new file mode 100644
index 000000000..e8b5aae70
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.h
@@ -0,0 +1,1339 @@
+/** @file
+ UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
+ for upper layer application to execute UFS-supported SCSI cmds.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_PASS_THRU_HCI_H_
+#define _UFS_PASS_THRU_HCI_H_
+
+//
+// Host Capabilities Register Offsets
+//
+#define UFS_HC_CAP_OFFSET 0x0000 // Controller Capabilities
+#define UFS_HC_VER_OFFSET 0x0008 // Version
+#define UFS_HC_DDID_OFFSET 0x0010 // Device ID and Device Class
+#define UFS_HC_PMID_OFFSET 0x0014 // Product ID and Manufacturer ID
+#define UFS_HC_AHIT_OFFSET 0x0018 // Auto-Hibernate Idle Timer
+//
+// Operation and Runtime Register Offsets
+//
+#define UFS_HC_IS_OFFSET 0x0020 // Interrupt Status
+#define UFS_HC_IE_OFFSET 0x0024 // Interrupt Enable
+#define UFS_HC_STATUS_OFFSET 0x0030 // Host Controller Status
+#define UFS_HC_ENABLE_OFFSET 0x0034 // Host Controller Enable
+#define UFS_HC_UECPA_OFFSET 0x0038 // Host UIC Error Code PHY Adapter Layer
+#define UFS_HC_UECDL_OFFSET 0x003c // Host UIC Error Code Data Link Layer
+#define UFS_HC_UECN_OFFSET 0x0040 // Host UIC Error Code Network Layer
+#define UFS_HC_UECT_OFFSET 0x0044 // Host UIC Error Code Transport Layer
+#define UFS_HC_UECDME_OFFSET 0x0048 // Host UIC Error Code DME
+#define UFS_HC_UTRIACR_OFFSET 0x004c // UTP Transfer Request Interrupt Aggregation Control Register
+//
+// UTP Transfer Register Offsets
+//
+#define UFS_HC_UTRLBA_OFFSET 0x0050 // UTP Transfer Request List Base Address
+#define UFS_HC_UTRLBAU_OFFSET 0x0054 // UTP Transfer Request List Base Address Upper 32-Bits
+#define UFS_HC_UTRLDBR_OFFSET 0x0058 // UTP Transfer Request List Door Bell Register
+#define UFS_HC_UTRLCLR_OFFSET 0x005c // UTP Transfer Request List CLear Register
+#define UFS_HC_UTRLRSR_OFFSET 0x0060 // UTP Transfer Request Run-Stop Register
+//
+// UTP Task Management Register Offsets
+//
+#define UFS_HC_UTMRLBA_OFFSET 0x0070 // UTP Task Management Request List Base Address
+#define UFS_HC_UTMRLBAU_OFFSET 0x0074 // UTP Task Management Request List Base Address Upper 32-Bits
+#define UFS_HC_UTMRLDBR_OFFSET 0x0078 // UTP Task Management Request List Door Bell Register
+#define UFS_HC_UTMRLCLR_OFFSET 0x007c // UTP Task Management Request List CLear Register
+#define UFS_HC_UTMRLRSR_OFFSET 0x0080 // UTP Task Management Run-Stop Register
+//
+// UIC Command Register Offsets
+//
+#define UFS_HC_UIC_CMD_OFFSET 0x0090 // UIC Command Register
+#define UFS_HC_UCMD_ARG1_OFFSET 0x0094 // UIC Command Argument 1
+#define UFS_HC_UCMD_ARG2_OFFSET 0x0098 // UIC Command Argument 2
+#define UFS_HC_UCMD_ARG3_OFFSET 0x009c // UIC Command Argument 3
+//
+// UMA Register Offsets
+//
+#define UFS_HC_UMA_OFFSET 0x00b0 // Reserved for Unified Memory Extension
+
+#define UFS_HC_HCE_EN BIT0
+#define UFS_HC_HCS_DP BIT0
+#define UFS_HC_HCS_UCRDY BIT3
+#define UFS_HC_IS_ULSS BIT8
+#define UFS_HC_IS_UCCS BIT10
+#define UFS_HC_CAP_64ADDR BIT24
+#define UFS_HC_CAP_NUTMRS (BIT16 | BIT17 | BIT18)
+#define UFS_HC_CAP_NUTRS (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)
+#define UFS_HC_UTMRLRSR BIT0
+#define UFS_HC_UTRLRSR BIT0
+
+//
+// The initial value of the OCS field of UTP TRD or TMRD descriptor
+// defined in JEDEC JESD223 specification
+//
+#define UFS_HC_TRD_OCS_INIT_VALUE 0x0F
+
+//
+// A maximum of length of 256KB is supported by PRDT entry
+//
+#define UFS_MAX_DATA_LEN_PER_PRD 0x40000
+
+#define UFS_STORAGE_COMMAND_TYPE 0x01
+
+#define UFS_REGULAR_COMMAND 0x00
+#define UFS_INTERRUPT_COMMAND 0x01
+
+#define UFS_LUN_0 0x00
+#define UFS_LUN_1 0x01
+#define UFS_LUN_2 0x02
+#define UFS_LUN_3 0x03
+#define UFS_LUN_4 0x04
+#define UFS_LUN_5 0x05
+#define UFS_LUN_6 0x06
+#define UFS_LUN_7 0x07
+#define UFS_WLUN_REPORT_LUNS 0x81
+#define UFS_WLUN_UFS_DEV 0xD0
+#define UFS_WLUN_BOOT 0xB0
+#define UFS_WLUN_RPMB 0xC4
+
+#pragma pack(1)
+
+//
+// UFSHCI 2.0 Spec Section 5.2.1 Offset 00h: CAP - Controller Capabilities
+//
+typedef struct {
+ UINT8 Nutrs:4; // Number of UTP Transfer Request Slots
+ UINT8 Rsvd1:4;
+
+ UINT8 NoRtt; // Number of outstanding READY TO TRANSFER (RTT) requests supported
+
+ UINT8 Nutmrs:3; // Number of UTP Task Management Request Slots
+ UINT8 Rsvd2:4;
+ UINT8 AutoHs:1; // Auto-Hibernation Support
+
+ UINT8 As64:1; // 64-bit addressing supported
+ UINT8 Oodds:1; // Out of order data delivery supported
+ UINT8 UicDmetms:1; // UIC DME_TEST_MODE command supported
+ UINT8 Ume:1; // Reserved for Unified Memory Extension
+ UINT8 Rsvd4:4;
+} UFS_HC_CAP;
+
+//
+// UFSHCI 2.0 Spec Section 5.2.2 Offset 08h: VER - UFS Version
+//
+typedef struct {
+ UINT8 Vs:4; // Version Suffix
+ UINT8 Mnr:4; // Minor version number
+
+ UINT8 Mjr; // Major version number
+
+ UINT16 Rsvd1;
+} UFS_HC_VER;
+
+//
+// UFSHCI 2.0 Spec Section 5.2.3 Offset 10h: HCPID - Host Controller Product ID
+//
+#define UFS_HC_PID UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.2.4 Offset 14h: HCMID - Host Controller Manufacturer ID
+//
+#define UFS_HC_MID UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.2.5 Offset 18h: AHIT - Auto-Hibernate Idle Timer
+//
+typedef struct {
+ UINT32 Ahitv:10; // Auto-Hibernate Idle Timer Value
+ UINT32 Ts:3; // Timer scale
+ UINT32 Rsvd1:19;
+} UFS_HC_AHIT;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.1 Offset 20h: IS - Interrupt Status
+//
+typedef struct {
+ UINT16 Utrcs:1; // UTP Transfer Request Completion Status
+ UINT16 Udepri:1; // UIC DME_ENDPOINT_RESET Indication
+ UINT16 Ue:1; // UIC Error
+ UINT16 Utms:1; // UIC Test Mode Status
+
+ UINT16 Upms:1; // UIC Power Mode Status
+ UINT16 Uhxs:1; // UIC Hibernate Exit Status
+ UINT16 Uhes:1; // UIC Hibernate Enter Status
+ UINT16 Ulls:1; // UIC Link Lost Status
+
+ UINT16 Ulss:1; // UIC Link Startup Status
+ UINT16 Utmrcs:1; // UTP Task Management Request Completion Status
+ UINT16 Uccs:1; // UIC Command Completion Status
+ UINT16 Dfes:1; // Device Fatal Error Status
+
+ UINT16 Utpes:1; // UTP Error Status
+ UINT16 Rsvd1:3;
+
+ UINT16 Hcfes:1; // Host Controller Fatal Error Status
+ UINT16 Sbfes:1; // System Bus Fatal Error Status
+ UINT16 Rsvd2:14;
+} UFS_HC_IS;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.2 Offset 24h: IE - Interrupt Enable
+//
+typedef struct {
+ UINT16 Utrce:1; // UTP Transfer Request Completion Enable
+ UINT16 Udeprie:1; // UIC DME_ENDPOINT_RESET Enable
+ UINT16 Uee:1; // UIC Error Enable
+ UINT16 Utmse:1; // UIC Test Mode Status Enable
+
+ UINT16 Upmse:1; // UIC Power Mode Status Enable
+ UINT16 Uhxse:1; // UIC Hibernate Exit Status Enable
+ UINT16 Uhese:1; // UIC Hibernate Enter Status Enable
+ UINT16 Ullse:1; // UIC Link Lost Status Enable
+
+ UINT16 Ulsse:1; // UIC Link Startup Status Enable
+ UINT16 Utmrce:1; // UTP Task Management Request Completion Enable
+ UINT16 Ucce:1; // UIC Command Completion Enable
+ UINT16 Dfee:1; // Device Fatal Error Enable
+
+ UINT16 Utpee:1; // UTP Error Enable
+ UINT16 Rsvd1:3;
+
+ UINT16 Hcfee:1; // Host Controller Fatal Error Enable
+ UINT16 Sbfee:1; // System Bus Fatal Error Enable
+ UINT16 Rsvd2:14;
+} UFS_HC_IE;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.3 Offset 30h: HCS - Host Controller Status
+//
+typedef struct {
+ UINT8 Dp:1; // Device Present
+ UINT8 UtrlRdy:1; // UTP Transfer Request List Ready
+ UINT8 UtmrlRdy:1; // UTP Task Management Request List Ready
+ UINT8 UcRdy:1; // UIC COMMAND Ready
+ UINT8 Rsvd1:4;
+
+ UINT8 Upmcrs:3; // UIC Power Mode Change Request Status
+ UINT8 Rsvd2:1; // UIC Hibernate Exit Status Enable
+ UINT8 Utpec:4; // UTP Error Code
+
+ UINT8 TtagUtpE; // Task Tag of UTP error
+ UINT8 TlunUtpE; // Target LUN of UTP error
+} UFS_HC_STATUS;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.4 Offset 34h: HCE - Host Controller Enable
+//
+typedef struct {
+ UINT32 Hce:1; // Host Controller Enable
+ UINT32 Rsvd1:31;
+} UFS_HC_ENABLE;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.5 Offset 38h: UECPA - Host UIC Error Code PHY Adapter Layer
+//
+typedef struct {
+ UINT32 Ec:5; // UIC PHY Adapter Layer Error Code
+ UINT32 Rsvd1:26;
+ UINT32 Err:1; // UIC PHY Adapter Layer Error
+} UFS_HC_UECPA;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.6 Offset 3ch: UECDL - Host UIC Error Code Data Link Layer
+//
+typedef struct {
+ UINT32 Ec:15; // UIC Data Link Layer Error Code
+ UINT32 Rsvd1:16;
+ UINT32 Err:1; // UIC Data Link Layer Error
+} UFS_HC_UECDL;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.7 Offset 40h: UECN - Host UIC Error Code Network Layer
+//
+typedef struct {
+ UINT32 Ec:3; // UIC Network Layer Error Code
+ UINT32 Rsvd1:28;
+ UINT32 Err:1; // UIC Network Layer Error
+} UFS_HC_UECN;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.8 Offset 44h: UECT - Host UIC Error Code Transport Layer
+//
+typedef struct {
+ UINT32 Ec:7; // UIC Transport Layer Error Code
+ UINT32 Rsvd1:24;
+ UINT32 Err:1; // UIC Transport Layer Error
+} UFS_HC_UECT;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.9 Offset 48h: UECDME - Host UIC Error Code
+//
+typedef struct {
+ UINT32 Ec:1; // UIC DME Error Code
+ UINT32 Rsvd1:30;
+ UINT32 Err:1; // UIC DME Error
+} UFS_HC_UECDME;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.10 Offset 4Ch: UTRIACR - UTP Transfer Request Interrupt Aggregation Control Register
+//
+typedef struct {
+ UINT8 IaToVal; // Interrupt aggregation timeout value
+
+ UINT8 IacTh:5; // Interrupt aggregation counter threshold
+ UINT8 Rsvd1:3;
+
+ UINT8 Ctr:1; // Counter and Timer Reset
+ UINT8 Rsvd2:3;
+ UINT8 Iasb:1; // Interrupt aggregation status bit
+ UINT8 Rsvd3:3;
+
+ UINT8 IapwEn:1; // Interrupt aggregation parameter write enable
+ UINT8 Rsvd4:6;
+ UINT8 IaEn:1; // Interrupt Aggregation Enable/Disable
+} UFS_HC_UTRIACR;
+
+//
+// UFSHCI 2.0 Spec Section 5.4.1 Offset 50h: UTRLBA - UTP Transfer Request List Base Address
+//
+typedef struct {
+ UINT32 Rsvd1:10;
+ UINT32 UtrlBa:22; // UTP Transfer Request List Base Address
+} UFS_HC_UTRLBA;
+
+//
+// UFSHCI 2.0 Spec Section 5.4.2 Offset 54h: UTRLBAU - UTP Transfer Request List Base Address Upper 32-bits
+//
+#define UFS_HC_UTRLBAU UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.4.3 Offset 58h: UTRLDBR - UTP Transfer Request List Door Bell Register
+//
+#define UFS_HC_UTRLDBR UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.4.4 Offset 5Ch: UTRLCLR - UTP Transfer Request List CLear Register
+//
+#define UFS_HC_UTRLCLR UINT32
+
+#if 0
+//
+// UFSHCI 2.0 Spec Section 5.4.5 Offset 60h: UTRLRSR - UTP Transfer Request List Run Stop Register
+//
+typedef struct {
+ UINT32 UtrlRsr:1; // UTP Transfer Request List Run-Stop Register
+ UINT32 Rsvd1:31;
+} UFS_HC_UTRLRSR;
+#endif
+
+//
+// UFSHCI 2.0 Spec Section 5.5.1 Offset 70h: UTMRLBA - UTP Task Management Request List Base Address
+//
+typedef struct {
+ UINT32 Rsvd1:10;
+ UINT32 UtmrlBa:22; // UTP Task Management Request List Base Address
+} UFS_HC_UTMRLBA;
+
+//
+// UFSHCI 2.0 Spec Section 5.5.2 Offset 74h: UTMRLBAU - UTP Task Management Request List Base Address Upper 32-bits
+//
+#define UFS_HC_UTMRLBAU UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.5.3 Offset 78h: UTMRLDBR - UTP Task Management Request List Door Bell Register
+//
+typedef struct {
+ UINT32 UtmrlDbr:8; // UTP Task Management Request List Door bell Register
+ UINT32 Rsvd1:24;
+} UFS_HC_UTMRLDBR;
+
+//
+// UFSHCI 2.0 Spec Section 5.5.4 Offset 7Ch: UTMRLCLR - UTP Task Management Request List CLear Register
+//
+typedef struct {
+ UINT32 UtmrlClr:8; // UTP Task Management List Clear Register
+ UINT32 Rsvd1:24;
+} UFS_HC_UTMRLCLR;
+
+#if 0
+//
+// UFSHCI 2.0 Spec Section 5.5.5 Offset 80h: UTMRLRSR - UTP Task Management Request List Run Stop Register
+//
+typedef struct {
+ UINT32 UtmrlRsr:1; // UTP Task Management Request List Run-Stop Register
+ UINT32 Rsvd1:31;
+} UFS_HC_UTMRLRSR;
+#endif
+
+//
+// UFSHCI 2.0 Spec Section 5.6.1 Offset 90h: UICCMD - UIC Command
+//
+typedef struct {
+ UINT32 CmdOp:8; // Command Opcode
+ UINT32 Rsvd1:24;
+} UFS_HC_UICCMD;
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 94h: UICCMDARG1 - UIC Command Argument 1
+//
+#define UFS_HC_UICCMD_ARG1 UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 98h: UICCMDARG2 - UIC Command Argument 2
+//
+#define UFS_HC_UICCMD_ARG2 UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 9ch: UICCMDARG3 - UIC Command Argument 3
+//
+#define UFS_HC_UICCMD_ARG3 UINT32
+
+//
+// UIC command opcodes
+//
+typedef enum {
+ UfsUicDmeGet = 0x01,
+ UfsUicDmeSet = 0x02,
+ UfsUicDmePeerGet = 0x03,
+ UfsUicDmePeerSet = 0x04,
+ UfsUicDmePwrOn = 0x10,
+ UfsUicDmePwrOff = 0x11,
+ UfsUicDmeEnable = 0x12,
+ UfsUicDmeReset = 0x14,
+ UfsUicDmeEndpointReset = 0x15,
+ UfsUicDmeLinkStartup = 0x16,
+ UfsUicDmeHibernateEnter = 0x17,
+ UfsUicDmeHibernateExit = 0x18,
+ UfsUicDmeTestMode = 0x1A
+} UFS_UIC_OPCODE;
+
+//
+// UTP Transfer Request Descriptor
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:24;
+ UINT32 Int:1; /* Interrupt */
+ UINT32 Dd:2; /* Data Direction */
+ UINT32 Rsvd2:1;
+ UINT32 Ct:4; /* Command Type */
+
+ //
+ // DW1
+ //
+ UINT32 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT32 Ocs:8; /* Overall Command Status */
+ UINT32 Rsvd4:24;
+
+ //
+ // DW3
+ //
+ UINT32 Rsvd5;
+
+ //
+ // DW4
+ //
+ UINT32 Rsvd6:7;
+ UINT32 UcdBa:25; /* UTP Command Descriptor Base Address */
+
+ //
+ // DW5
+ //
+ UINT32 UcdBaU; /* UTP Command Descriptor Base Address Upper 32-bits */
+
+ //
+ // DW6
+ //
+ UINT16 RuL; /* Response UPIU Length */
+ UINT16 RuO; /* Response UPIU Offset */
+
+ //
+ // DW7
+ //
+ UINT16 PrdtL; /* PRDT Length */
+ UINT16 PrdtO; /* PRDT Offset */
+} UTP_TRD;
+
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:2;
+ UINT32 DbAddr:30; /* Data Base Address */
+
+ //
+ // DW1
+ //
+ UINT32 DbAddrU; /* Data Base Address Upper 32-bits */
+
+ //
+ // DW2
+ //
+ UINT32 Rsvd2;
+
+ //
+ // DW3
+ //
+ UINT32 DbCount:18; /* Data Byte Count */
+ UINT32 Rsvd3:14;
+} UTP_TR_PRD;
+
+//
+// UFS 2.0 Spec Section 10.5.3 - UTP Command UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x01*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 CmdSet:4; /* Command Set Type */
+ UINT8 Rsvd1:4;
+ UINT8 Rsvd2;
+ UINT8 Rsvd3;
+ UINT8 Rsvd4;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd5;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 ExpDataTranLen; /* Expected Data Transfer Length - Big Endian */
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Cdb[16];
+} UTP_COMMAND_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.4 - UTP Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x21*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 CmdSet:4; /* Command Set Type */
+ UINT8 Rsvd1:4;
+ UINT8 Rsvd2;
+ UINT8 Response; /* Response */
+ UINT8 Status; /* Status */
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 ResTranCount; /* Residual Transfer Count - Big Endian */
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Rsvd3[16];
+
+ //
+ // Data Segment - Sense Data
+ //
+ UINT16 SenseDataLen; /* Sense Data Length - Big Endian */
+ UINT8 SenseData[18]; /* Sense Data */
+} UTP_RESPONSE_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.5 - UTP Data-Out UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x02*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be sent out
+ //
+ //UINT8 Data[]; /* Data to be sent out, maximum is 65535 bytes */
+} UTP_DATA_OUT_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.6 - UTP Data-In UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x22*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be read
+ //
+ //UINT8 Data[]; /* Data to be read, maximum is 65535 bytes */
+} UTP_DATA_IN_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.7 - UTP Ready-To-Transfer UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x31*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be read
+ //
+ //UINT8 Data[]; /* Data to be read, maximum is 65535 bytes */
+} UTP_RDY_TO_TRAN_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.8 - UTP Task Management Request UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x04*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1;
+ UINT8 TskManFunc; /* Task Management Function */
+ UINT8 Rsvd2[2];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 InputParam1; /* Input Parameter 1 - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 InputParam2; /* Input Parameter 2 - Big Endian */
+
+ //
+ // DW5
+ //
+ UINT32 InputParam3; /* Input Parameter 3 - Big Endian */
+
+ //
+ // DW6 - DW7
+ //
+ UINT8 Rsvd4[8];
+} UTP_TM_REQ_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.9 - UTP Task Management Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x24*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[2];
+ UINT8 Resp; /* Response */
+ UINT8 Rsvd2;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 OutputParam1; /* Output Parameter 1 - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 OutputParam2; /* Output Parameter 2 - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd4[12];
+} UTP_TM_RESP_UPIU;
+
+//
+// UTP Task Management Request Descriptor
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:24;
+ UINT32 Int:1; /* Interrupt */
+ UINT32 Rsvd2:7;
+
+ //
+ // DW1
+ //
+ UINT32 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT32 Ocs:8; /* Overall Command Status */
+ UINT32 Rsvd4:24;
+
+ //
+ // DW3
+ //
+ UINT32 Rsvd5;
+
+ //
+ // DW4 - DW11
+ //
+ UTP_TM_REQ_UPIU TmReq; /* Task Management Request UPIU */
+
+ //
+ // DW12 - DW19
+ //
+ UTP_TM_RESP_UPIU TmResp; /* Task Management Response UPIU */
+} UTP_TMRD;
+
+
+typedef struct {
+ UINT8 Opcode;
+ UINT8 DescId;
+ UINT8 Index;
+ UINT8 Selector;
+ UINT16 Rsvd1;
+ UINT16 Length;
+ UINT32 Value;
+ UINT32 Rsvd2;
+} UTP_UPIU_TSF;
+
+//
+// UFS 2.0 Spec Section 10.5.10 - UTP Query Request UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x16*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2;
+ UINT8 QueryFunc; /* Query Function */
+ UINT8 Rsvd3[2];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd4;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3 - 6
+ //
+ UTP_UPIU_TSF Tsf; /* Transaction Specific Fields */
+
+ //
+ // DW7
+ //
+ UINT8 Rsvd5[4];
+
+ //
+ // Data Segment - Data to be transferred
+ //
+ //UINT8 Data[]; /* Data to be transferred, maximum is 65535 bytes */
+} UTP_QUERY_REQ_UPIU;
+
+#define QUERY_FUNC_STD_READ_REQ 0x01
+#define QUERY_FUNC_STD_WRITE_REQ 0x81
+
+typedef enum {
+ UtpQueryFuncOpcodeNop = 0x00,
+ UtpQueryFuncOpcodeRdDesc = 0x01,
+ UtpQueryFuncOpcodeWrDesc = 0x02,
+ UtpQueryFuncOpcodeRdAttr = 0x03,
+ UtpQueryFuncOpcodeWrAttr = 0x04,
+ UtpQueryFuncOpcodeRdFlag = 0x05,
+ UtpQueryFuncOpcodeSetFlag = 0x06,
+ UtpQueryFuncOpcodeClrFlag = 0x07,
+ UtpQueryFuncOpcodeTogFlag = 0x08
+} UTP_QUERY_FUNC_OPCODE;
+
+//
+// UFS 2.0 Spec Section 10.5.11 - UTP Query Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x36*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2;
+ UINT8 QueryFunc; /* Query Function */
+ UINT8 QueryResp; /* Query Response */
+ UINT8 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3 - 6
+ //
+ UTP_UPIU_TSF Tsf; /* Transaction Specific Fields */
+
+ //
+ // DW7
+ //
+ UINT8 Rsvd4[4];
+
+ //
+ // Data Segment - Data to be transferred
+ //
+ //UINT8 Data[]; /* Data to be transferred, maximum is 65535 bytes */
+} UTP_QUERY_RESP_UPIU;
+
+typedef enum {
+ UfsUtpQueryResponseSuccess = 0x00,
+ UfsUtpQueryResponseParamNotReadable = 0xF6,
+ UfsUtpQueryResponseParamNotWriteable = 0xF7,
+ UfsUtpQueryResponseParamAlreadyWritten = 0xF8,
+ UfsUtpQueryResponseInvalidLen = 0xF9,
+ UfsUtpQueryResponseInvalidVal = 0xFA,
+ UfsUtpQueryResponseInvalidSelector = 0xFB,
+ UfsUtpQueryResponseInvalidIndex = 0xFC,
+ UfsUtpQueryResponseInvalidIdn = 0xFD,
+ UfsUtpQueryResponseInvalidOpc = 0xFE,
+ UfsUtpQueryResponseGeneralFailure = 0xFF
+} UTP_QUERY_RESP_CODE;
+
+//
+// UFS 2.0 Spec Section 10.5.12 - UTP Reject UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x3F*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[2];
+ UINT8 Response; /* Response - 0x01 */
+ UINT8 Rsvd2;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information - 0x00 */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT8 HdrSts; /* Basic Header Status */
+ UINT8 Rsvd3;
+ UINT8 E2ESts; /* End-to-End Status */
+ UINT8 Rsvd4;
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Rsvd5[16];
+} UTP_REJ_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.13 - UTP NOP OUT UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x00*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3 - DW7
+ //
+ UINT8 Rsvd4[20];
+} UTP_NOP_OUT_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.14 - UTP NOP IN UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x20*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2[2];
+ UINT8 Resp; /* Response - 0x00 */
+ UINT8 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information - 0x00 */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3 - DW7
+ //
+ UINT8 Rsvd4[20];
+} UTP_NOP_IN_UPIU;
+
+//
+// UFS Descriptors
+//
+typedef enum {
+ UfsDeviceDesc = 0x00,
+ UfsConfigDesc = 0x01,
+ UfsUnitDesc = 0x02,
+ UfsInterConnDesc = 0x04,
+ UfsStringDesc = 0x05,
+ UfsGeometryDesc = 0x07,
+ UfsPowerDesc = 0x08
+} UFS_DESC_IDN;
+
+//
+// UFS 2.0 Spec Section 14.1.6.2 - Device Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 Device;
+ UINT8 DevClass;
+ UINT8 DevSubClass;
+ UINT8 Protocol;
+ UINT8 NumLun;
+ UINT8 NumWLun;
+ UINT8 BootEn;
+ UINT8 DescAccessEn;
+ UINT8 InitPowerMode;
+ UINT8 HighPriorityLun;
+ UINT8 SecureRemovalType;
+ UINT8 SecurityLun;
+ UINT8 BgOpsTermLat;
+ UINT8 InitActiveIccLevel;
+ UINT16 SpecVersion;
+ UINT16 ManufactureDate;
+ UINT8 ManufacturerName;
+ UINT8 ProductName;
+ UINT8 SerialName;
+ UINT8 OemId;
+ UINT16 ManufacturerId;
+ UINT8 Ud0BaseOffset;
+ UINT8 Ud0ConfParamLen;
+ UINT8 DevRttCap;
+ UINT16 PeriodicRtcUpdate;
+ UINT8 Rsvd1[17];
+ UINT8 Rsvd2[16];
+} UFS_DEV_DESC;
+
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 Rsvd1;
+ UINT8 BootEn;
+ UINT8 DescAccessEn;
+ UINT8 InitPowerMode;
+ UINT8 HighPriorityLun;
+ UINT8 SecureRemovalType;
+ UINT8 InitActiveIccLevel;
+ UINT16 PeriodicRtcUpdate;
+ UINT8 Rsvd2[5];
+} UFS_CONFIG_DESC_GEN_HEADER;
+
+typedef struct {
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 MemType;
+ UINT32 NumAllocUnits;
+ UINT8 DataReliability;
+ UINT8 LogicBlkSize;
+ UINT8 ProvisionType;
+ UINT16 CtxCap;
+ UINT8 Rsvd1[3];
+} UFS_UNIT_DESC_CONFIG_PARAMS;
+
+//
+// UFS 2.0 Spec Section 14.1.6.3 - Configuration Descriptor
+//
+typedef struct {
+ UFS_CONFIG_DESC_GEN_HEADER Header;
+ UFS_UNIT_DESC_CONFIG_PARAMS UnitDescConfParams[8];
+} UFS_CONFIG_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.4 - Geometry Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 MediaTech;
+ UINT8 Rsvd1;
+ UINT64 TotalRawDevCapacity;
+ UINT8 Rsvd2;
+ UINT32 SegSize;
+ UINT8 AllocUnitSize;
+ UINT8 MinAddrBlkSize;
+ UINT8 OptReadBlkSize;
+ UINT8 OptWriteBlkSize;
+ UINT8 MaxInBufSize;
+ UINT8 MaxOutBufSize;
+ UINT8 RpmbRwSize;
+ UINT8 Rsvd3;
+ UINT8 DataOrder;
+ UINT8 MaxCtxIdNum;
+ UINT8 SysDataTagUnitSize;
+ UINT8 SysDataResUnitSize;
+ UINT8 SupSecRemovalTypes;
+ UINT16 SupMemTypes;
+ UINT32 SysCodeMaxNumAllocUnits;
+ UINT16 SupCodeCapAdjFac;
+ UINT32 NonPersMaxNumAllocUnits;
+ UINT16 NonPersCapAdjFac;
+ UINT32 Enhance1MaxNumAllocUnits;
+ UINT16 Enhance1CapAdjFac;
+ UINT32 Enhance2MaxNumAllocUnits;
+ UINT16 Enhance2CapAdjFac;
+ UINT32 Enhance3MaxNumAllocUnits;
+ UINT16 Enhance3CapAdjFac;
+ UINT32 Enhance4MaxNumAllocUnits;
+ UINT16 Enhance4CapAdjFac;
+} UFS_GEOMETRY_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.5 - Unit Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 UnitIdx;
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 LunQueueDep;
+ UINT8 Rsvd1;
+ UINT8 MemType;
+ UINT8 DataReliability;
+ UINT8 LogicBlkSize;
+ UINT64 LogicBlkCount;
+ UINT32 EraseBlkSize;
+ UINT8 ProvisionType;
+ UINT64 PhyMemResCount;
+ UINT16 CtxCap;
+ UINT8 LargeUnitGranularity;
+} UFS_UNIT_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.6 - RPMB Unit Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 UnitIdx;
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 LunQueueDep;
+ UINT8 Rsvd1;
+ UINT8 MemType;
+ UINT8 Rsvd2;
+ UINT8 LogicBlkSize;
+ UINT64 LogicBlkCount;
+ UINT32 EraseBlkSize;
+ UINT8 ProvisionType;
+ UINT64 PhyMemResCount;
+ UINT8 Rsvd3[3];
+} UFS_RPMB_UNIT_DESC;
+
+typedef struct {
+ UINT16 Value:10;
+ UINT16 Rsvd1:4;
+ UINT16 Unit:2;
+} UFS_POWER_PARAM_ELEMENT;
+
+//
+// UFS 2.0 Spec Section 14.1.6.7 - Power Parameter Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVcc[16];
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVccQ[16];
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVccQ2[16];
+} UFS_POWER_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.8 - InterConnect Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT16 UniProVer;
+ UINT16 MphyVer;
+} UFS_INTER_CONNECT_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.9 - 14.1.6.12 - String Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ CHAR16 Unicode[126];
+} UFS_STRING_DESC;
+
+//
+// UFS 2.0 Spec Section 14.2 - Flags
+//
+typedef enum {
+ UfsFlagDevInit = 0x01,
+ UfsFlagPermWpEn = 0x02,
+ UfsFlagPowerOnWpEn = 0x03,
+ UfsFlagBgOpsEn = 0x04,
+ UfsFlagPurgeEn = 0x06,
+ UfsFlagPhyResRemoval = 0x08,
+ UfsFlagBusyRtc = 0x09,
+ UfsFlagPermDisFwUpdate = 0x0B
+} UFS_FLAGS_IDN;
+
+//
+// UFS 2.0 Spec Section 14.2 - Attributes
+//
+typedef enum {
+ UfsAttrBootLunEn = 0x00,
+ UfsAttrCurPowerMode = 0x02,
+ UfsAttrActiveIccLevel = 0x03,
+ UfsAttrOutOfOrderDataEn = 0x04,
+ UfsAttrBgOpStatus = 0x05,
+ UfsAttrPurgeStatus = 0x06,
+ UfsAttrMaxDataInSize = 0x07,
+ UfsAttrMaxDataOutSize = 0x08,
+ UfsAttrDynCapNeeded = 0x09,
+ UfsAttrRefClkFreq = 0x0a,
+ UfsAttrConfigDescLock = 0x0b,
+ UfsAttrMaxNumOfRtt = 0x0c,
+ UfsAttrExceptionEvtCtrl = 0x0d,
+ UfsAttrExceptionEvtSts = 0x0e,
+ UfsAttrSecondsPassed = 0x0f,
+ UfsAttrContextConf = 0x10,
+ UfsAttrCorrPrgBlkNum = 0x11
+} UFS_ATTR_IDN;
+
+typedef enum {
+ UfsNoData = 0,
+ UfsDataOut = 1,
+ UfsDataIn = 2,
+ UfsDdReserved
+} UFS_DATA_DIRECTION;
+
+
+#pragma pack()
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c
new file mode 100644
index 000000000..aced63b49
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/ComponentName.c
@@ -0,0 +1,216 @@
+/** @file
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "UfsPassThru.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUfsPassThruComponentName = {
+ UfsPassThruComponentNameGetDriverName,
+ UfsPassThruComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UfsPassThruComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UfsPassThruComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsPassThruDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Universal Flash Storage (UFS) Pass Thru Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUfsPassThruControllerNameTable[] = {
+ {
+ "eng;en",
+ L"Universal Flash Storage (UFS) Host 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
+UfsPassThruComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUfsPassThruDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUfsPassThruComponentName)
+ );
+}
+
+/**
+ 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
+UfsPassThruComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ 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;
+ }
+
+ //
+ // Make sure this driver is currently managing Controller Handle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gUfsPassThruDriverBinding.DriverBindingHandle,
+ &gEdkiiUfsHostControllerProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUfsPassThruControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUfsPassThruComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsDevConfigProtocol.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsDevConfigProtocol.c
new file mode 100644
index 000000000..4730ecd90
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsDevConfigProtocol.c
@@ -0,0 +1,190 @@
+/** @file
+ The implementation of the EFI UFS Device Config Protocol.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPassThru.h"
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ The function is used to read/write UFS device descriptors. The consumer of this API is
+ responsible for allocating the data buffer pointed by Descriptor.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
+ of the data buffer specified by Descriptor. On output, the number
+ of bytes that were actually transferred.
+
+ @retval EFI_SUCCESS The device descriptor is read/written successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Descriptor is NULL or DescSize is NULL.
+ DescId, Index and Selector are invalid combination to point to a
+ type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR The device descriptor is not read/written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsDescriptor (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT8 *Descriptor,
+ IN OUT UINT32 *DescSize
+ )
+{
+ EFI_STATUS Status;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_DEV_CONFIG (This);
+
+ if ((This == NULL) || (Descriptor == NULL) || (DescSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UfsRwDeviceDesc (
+ Private,
+ Read,
+ DescId,
+ Index,
+ Selector,
+ Descriptor,
+ DescSize
+ );
+ if (Status == EFI_TIMEOUT) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+}
+
+/**
+ Read or write specified flag of a UFS device.
+
+ The function is used to read/write UFS flag descriptors. The consumer of this API is responsible
+ for allocating the buffer pointed by Flag. The buffer size is 1 byte as UFS flag descriptor is
+ just a single Boolean value that represents a TRUE or FALSE, '0' or '1', ON or OFF type of value.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] FlagId The ID of flag to be read or written.
+ @param[in, out] Flag The buffer to set or clear flag.
+
+ @retval EFI_SUCCESS The flag descriptor is set/clear successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Flag is NULL.
+ FlagId is an invalid UFS flag ID.
+ @retval EFI_DEVICE_ERROR The flag is not set/clear successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsFlag (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 FlagId,
+ IN OUT UINT8 *Flag
+ )
+{
+ EFI_STATUS Status;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_DEV_CONFIG (This);
+
+ if ((This == NULL) || (Flag == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UfsRwFlags (Private, Read, FlagId, Flag);
+ if (Status == EFI_TIMEOUT) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+}
+
+/**
+ Read or write specified attribute of a UFS device.
+
+ The function is used to read/write UFS attributes. The consumer of this API is responsible for
+ allocating the data buffer pointed by Attribute.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] AttrId The ID of Attribute.
+ @param[in] Index The Index of Attribute.
+ @param[in] Selector The Selector of Attribute.
+ @param[in, out] Attribute The buffer of Attribute to be read or written.
+ @param[in, out] AttrSize The size of Attribute buffer. On input, the size, in bytes, of the
+ data buffer specified by Attribute. On output, the number of bytes
+ that were actually transferred.
+
+ @retval EFI_SUCCESS The attribute is read/written successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Attribute is NULL or AttrSize is NULL.
+ AttrId, Index and Selector are invalid combination to point to a
+ type of UFS attribute.
+ @retval EFI_DEVICE_ERROR The attribute is not read/written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsAttribute (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 AttrId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT8 *Attribute,
+ IN OUT UINT32 *AttrSize
+ )
+{
+ EFI_STATUS Status;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ UINT32 Attribute32;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_DEV_CONFIG (This);
+ Attribute32 = 0;
+
+ if ((This == NULL) || (Attribute == NULL) || (AttrSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // According to UFS Version 2.1 Spec (JESD220C) Section 14.3, the size of a attribute will not
+ // exceed 32-bit.
+ //
+ if (*AttrSize > 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Read) {
+ CopyMem (&Attribute32, Attribute, *AttrSize);
+ }
+
+ Status = UfsRwAttributes (
+ Private,
+ Read,
+ AttrId,
+ Index,
+ Selector,
+ &Attribute32
+ );
+ if (!EFI_ERROR (Status)) {
+ if (Read) {
+ CopyMem (Attribute, &Attribute32, *AttrSize);
+ }
+ } else {
+ *AttrSize = 0;
+ if (Status == EFI_TIMEOUT) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
new file mode 100644
index 000000000..9768c2e6f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -0,0 +1,1187 @@
+/** @file
+
+ Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPassThru.h"
+
+//
+// Template for Ufs Pass Thru private data.
+//
+UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = {
+ UFS_PASS_THRU_SIG, // Signature
+ NULL, // Handle
+ { // ExtScsiPassThruMode
+ 0xFFFFFFFF,
+ EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO,
+ sizeof (UINTN)
+ },
+ { // ExtScsiPassThru
+ NULL,
+ UfsPassThruPassThru,
+ UfsPassThruGetNextTargetLun,
+ UfsPassThruBuildDevicePath,
+ UfsPassThruGetTargetLun,
+ UfsPassThruResetChannel,
+ UfsPassThruResetTargetLun,
+ UfsPassThruGetNextTarget
+ },
+ { // UfsDevConfig
+ UfsRwUfsDescriptor,
+ UfsRwUfsFlag,
+ UfsRwUfsAttribute
+ },
+ 0, // UfsHostController
+ 0, // UfsHcBase
+ {0, 0}, // UfsHcInfo
+ {NULL, NULL}, // UfsHcDriverInterface
+ 0, // TaskTag
+ 0, // UtpTrlBase
+ 0, // Nutrs
+ 0, // TrlMapping
+ 0, // UtpTmrlBase
+ 0, // Nutmrs
+ 0, // TmrlMapping
+ { // Luns
+ {
+ UFS_LUN_0, // Ufs Common Lun 0
+ UFS_LUN_1, // Ufs Common Lun 1
+ UFS_LUN_2, // Ufs Common Lun 2
+ UFS_LUN_3, // Ufs Common Lun 3
+ UFS_LUN_4, // Ufs Common Lun 4
+ UFS_LUN_5, // Ufs Common Lun 5
+ UFS_LUN_6, // Ufs Common Lun 6
+ UFS_LUN_7, // Ufs Common Lun 7
+ UFS_WLUN_REPORT_LUNS, // Ufs Reports Luns Well Known Lun
+ UFS_WLUN_UFS_DEV, // Ufs Device Well Known Lun
+ UFS_WLUN_BOOT, // Ufs Boot Well Known Lun
+ UFS_WLUN_RPMB // RPMB Well Known Lun
+ },
+ 0x0000, // By default don't expose any Luns.
+ 0x0
+ },
+ NULL, // TimerEvent
+ { // Queue
+ NULL,
+ NULL
+ }
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding = {
+ UfsPassThruDriverBindingSupported,
+ UfsPassThruDriverBindingStart,
+ UfsPassThruDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+UFS_DEVICE_PATH mUfsDevicePathTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UFS_DP,
+ {
+ (UINT8) (sizeof (UFS_DEVICE_PATH)),
+ (UINT8) ((sizeof (UFS_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0
+};
+
+UINT8 mUfsTargetId[TARGET_MAX_BYTES];
+
+GLOBAL_REMOVE_IF_UNREFERENCED EDKII_UFS_HC_PLATFORM_PROTOCOL *mUfsHcPlatform;
+
+/**
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
+ supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
+ nonblocking I/O functionality is optional.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it represents
+ the id of the SCSI device to send the SCSI Request Packet. Each
+ transport driver may choose to utilize a subset of this size to suit the needs
+ of transport target representation. For example, a Fibre Channel driver
+ may use only 8 bytes (WWN) to represent an FC target.
+ @param Lun The LUN of the SCSI device to send the SCSI Request Packet.
+ @param Packet A pointer to the SCSI Request Packet to send to the SCSI device
+ specified by Target and Lun.
+ @param Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed. The number of bytes that
+ could be transferred is returned in InTransferLength. For write
+ and bi-directional commands, OutTransferLength bytes were
+ transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
+ SCSI Request Packets already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported
+ by the host adapter. This includes the case of Bi-directional SCSI
+ commands not supported by the implementation. The SCSI Request
+ Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruPassThru (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ UINT8 UfsLun;
+ UINT16 Index;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((Packet == NULL) || (Packet->Cdb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Don't support variable length CDB
+ //
+ if ((Packet->CdbLength != 6) && (Packet->CdbLength != 10) &&
+ (Packet->CdbLength != 12) && (Packet->CdbLength != 16)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For UFS 2.0 compatible device, 0 is always used to represent the location of the UFS device.
+ //
+ SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);
+ if ((Target == NULL) || (CompareMem(Target, mUfsTargetId, TARGET_MAX_BYTES) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // UFS 2.0 spec Section 10.6.7 - Translation of 8-bit UFS LUN to 64-bit SCSI LUN Address
+ // 0xC1 in the first 8 bits of the 64-bit address indicates a well known LUN address in the SAM SCSI format.
+ // The second 8 bits of the 64-bit address saves the corresponding 8-bit UFS LUN.
+ //
+ if ((UINT8)Lun == UFS_WLUN_PREFIX) {
+ UfsLun = BIT7 | (((UINT8*)&Lun)[1] & 0xFF);
+ } else if ((UINT8)Lun == 0) {
+ UfsLun = ((UINT8*)&Lun)[1] & 0xFF;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < UFS_MAX_LUNS; Index++) {
+ if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {
+ continue;
+ }
+
+ if (Private->Luns.Lun[Index] == UfsLun) {
+ break;
+ }
+ }
+
+ if (Index == UFS_MAX_LUNS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UfsExecScsiCmds (Private, UfsLun, Packet, Event);
+
+ return Status;
+}
+
+/**
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These
+ can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal
+ Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the
+ Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI
+ channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target On input, a pointer to the Target ID (an array of size
+ TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+ @param Lun On input, a pointer to the LUN of a SCSI device present on the SCSI
+ channel. On output, a pointer to the LUN of the next SCSI device present
+ on a SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID and LUN of the next SCSI device on the SCSI
+ channel was returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were
+ not returned on a previous call to GetNextTargetLun().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ )
+{
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ UINT8 UfsLun;
+ UINT16 Index;
+ UINT16 Next;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UfsLun = 0;
+ SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0xFF);
+ if (CompareMem (*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {
+ //
+ // If the array is all 0xFF's, return the first exposed Lun to caller.
+ //
+ SetMem (*Target, TARGET_MAX_BYTES, 0x00);
+ for (Index = 0; Index < UFS_MAX_LUNS; Index++) {
+ if ((Private->Luns.BitMask & (BIT0 << Index)) != 0) {
+ UfsLun = Private->Luns.Lun[Index];
+ break;
+ }
+ }
+ if (Index != UFS_MAX_LUNS) {
+ *Lun = 0;
+ if ((UfsLun & BIT7) == BIT7) {
+ ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;
+ ((UINT8*)Lun)[1] = UfsLun & ~BIT7;
+ } else {
+ ((UINT8*)Lun)[1] = UfsLun;
+ }
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);
+ if (CompareMem (*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {
+ if (((UINT8*)Lun)[0] == UFS_WLUN_PREFIX) {
+ UfsLun = BIT7 | (((UINT8*)Lun)[1] & 0xFF);
+ } else if (((UINT8*)Lun)[0] == 0) {
+ UfsLun = ((UINT8*)Lun)[1] & 0xFF;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < UFS_MAX_LUNS; Index++) {
+ if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {
+ continue;
+ }
+
+ if (Private->Luns.Lun[Index] != UfsLun) {
+ continue;
+ }
+
+ for (Next = Index + 1; Next < UFS_MAX_LUNS; Next++) {
+ if ((Private->Luns.BitMask & (BIT0 << Next)) != 0) {
+ UfsLun = Private->Luns.Lun[Next];
+ break;
+ }
+ }
+
+ if (Next == UFS_MAX_LUNS) {
+ return EFI_NOT_FOUND;
+ } else {
+ break;
+ }
+ }
+
+ if (Index != UFS_MAX_LUNS) {
+ *Lun = 0;
+ if ((UfsLun & BIT7) == BIT7) {
+ ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;
+ ((UINT8*)Lun)[1] = UfsLun & ~BIT7;
+ } else {
+ ((UINT8*)Lun)[1] = UfsLun;
+ }
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Used to allocate and build a device path node for a SCSI device on a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it specifies the
+ Target ID of the SCSI device for which a device path node is to be
+ allocated and built. Transport drivers may chose to utilize a subset of
+ this size to suit the representation of targets. For example, a Fibre
+ Channel driver may use only 8 bytes (WWN) in the array to represent a
+ FC target.
+ @param Lun The LUN of the SCSI device for which a device path node is to be
+ allocated and built.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ specified by Target and Lun. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SCSI device specified by
+ Target and Lun was allocated and returned in
+ DevicePath.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist
+ on the SCSI channel.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ EFI_DEV_PATH *DevicePathNode;
+ UINT8 UfsLun;
+ UINT16 Index;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Validate parameters passed in.
+ //
+ SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0x00);
+ if (CompareMem (Target, mUfsTargetId, TARGET_MAX_BYTES) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT8)Lun == UFS_WLUN_PREFIX) {
+ UfsLun = BIT7 | (((UINT8*)&Lun)[1] & 0xFF);
+ } else if ((UINT8)Lun == 0) {
+ UfsLun = ((UINT8*)&Lun)[1] & 0xFF;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < UFS_MAX_LUNS; Index++) {
+ if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {
+ continue;
+ }
+
+ if (Private->Luns.Lun[Index] == UfsLun) {
+ break;
+ }
+ }
+
+ if (Index == UFS_MAX_LUNS) {
+ return EFI_NOT_FOUND;
+ }
+
+ DevicePathNode = AllocateCopyPool (sizeof (UFS_DEVICE_PATH), &mUfsDevicePathTemplate);
+ if (DevicePathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevicePathNode->Ufs.Pun = 0;
+ DevicePathNode->Ufs.Lun = UfsLun;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to translate a device path node to a Target ID and LUN.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ on the SCSI channel.
+ @param Target A pointer to the Target Array which represents the ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of a SCSI device on the SCSI channel.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a Target ID and
+ LUN, and they were returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target ID and LUN
+ does not exist.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ )
+{
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ EFI_DEV_PATH *DevicePathNode;
+ UINT8 Pun;
+ UINT8 UfsLun;
+ UINT16 Index;
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Validate parameters passed in.
+ //
+ if (DevicePath == NULL || Target == NULL || Lun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the DevicePath belongs to UFS_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || (DevicePath->SubType != MSG_UFS_DP) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(UFS_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DevicePathNode = (EFI_DEV_PATH *) DevicePath;
+
+ Pun = (UINT8) DevicePathNode->Ufs.Pun;
+ UfsLun = (UINT8) DevicePathNode->Ufs.Lun;
+
+ if (Pun != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < UFS_MAX_LUNS; Index++) {
+ if ((Private->Luns.BitMask & (BIT0 << Index)) == 0) {
+ continue;
+ }
+
+ if (Private->Luns.Lun[Index] == UfsLun) {
+ break;
+ }
+ }
+
+ if (Index == UFS_MAX_LUNS) {
+ return EFI_NOT_FOUND;
+ }
+
+ SetMem (*Target, TARGET_MAX_BYTES, 0x00);
+ *Lun = 0;
+ if ((UfsLun & BIT7) == BIT7) {
+ ((UINT8*)Lun)[0] = UFS_WLUN_PREFIX;
+ ((UINT8*)Lun)[1] = UfsLun & ~BIT7;
+ } else {
+ ((UINT8*)Lun)[1] = UfsLun;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SCSI channel was reset.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI channel.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a channel reset operation.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ )
+{
+ //
+ // Return success directly then upper layer driver could think reset channel operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a SCSI logical unit that is connected to a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTE and it represents the
+ target port ID of the SCSI device containing the SCSI logical unit to
+ reset. Transport drivers may chose to utilize a subset of this array to suit
+ the representation of their targets.
+ @param Lun The LUN of the SCSI device to reset.
+
+ @retval EFI_SUCCESS The SCSI device specified by Target and Lun was reset.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a target reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruResetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ )
+{
+ //
+ // Return success directly then upper layer driver could think reset target LUN operation is done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either
+ be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs
+ for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to
+ see if a SCSI device is actually present at that location on the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
+ channel was returned in Target.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
+ returned on a previous call to GetNextTarget().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ )
+{
+ if (Target == NULL || *Target == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SetMem (mUfsTargetId, TARGET_MAX_BYTES, 0xFF);
+ if (CompareMem(*Target, mUfsTargetId, TARGET_MAX_BYTES) == 0) {
+ SetMem (*Target, TARGET_MAX_BYTES, 0x00);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHostController;
+
+ //
+ // Ufs Pass Thru driver is a device driver, and should ingore the
+ // "RemainingDevicePath" according to UEFI spec
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ (VOID **) &UfsHostController,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error
+ //
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finishes device initialization by setting fDeviceInit flag and waiting untill device responds by
+ clearing it.
+
+ @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+UfsFinishDeviceInitialization (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceInitStatus;
+ UINT8 Timeout;
+
+ DeviceInitStatus = 0xFF;
+
+ //
+ // The host enables the device initialization completion by setting fDeviceInit flag.
+ //
+ Status = UfsSetFlag (Private, UfsFlagDevInit);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Timeout = 5;
+ do {
+ Status = UfsReadFlag (Private, UfsFlagDevInit, &DeviceInitStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ MicroSecondDelay (1);
+ Timeout--;
+ } while (DeviceInitStatus != 0 && Timeout != 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+UfsPassThruDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ UINTN UfsHcBase;
+ UINT32 Index;
+ UFS_UNIT_DESC UnitDescriptor;
+ UFS_DEV_DESC DeviceDescriptor;
+ UINT32 UnitDescriptorSize;
+ UINT32 DeviceDescriptorSize;
+
+ Status = EFI_SUCCESS;
+ UfsHc = NULL;
+ Private = NULL;
+ UfsHcBase = 0;
+
+ DEBUG ((DEBUG_INFO, "==UfsPassThru Start== Controller = %x\n", Controller));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ (VOID **) &UfsHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Open Ufs Host Controller Protocol Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ //
+ // Get the UFS Host Controller MMIO Bar Base Address.
+ //
+ Status = UfsHc->GetUfsHcMmioBar (UfsHc, &UfsHcBase);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Get Ufs Host Controller Mmio Bar Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ //
+ // Initialize Ufs Pass Thru private data for managed UFS Host Controller.
+ //
+ Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), &gUfsPassThruTemplate);
+ if (Private == NULL) {
+ DEBUG ((DEBUG_ERROR, "Unable to allocate Ufs Pass Thru private data\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
+ Private->UfsHostController = UfsHc;
+ Private->UfsHcBase = UfsHcBase;
+ Private->Handle = Controller;
+ Private->UfsHcDriverInterface.UfsHcProtocol = UfsHc;
+ Private->UfsHcDriverInterface.UfsExecUicCommand = UfsHcDriverInterfaceExecUicCommand;
+ InitializeListHead (&Private->Queue);
+
+ //
+ // This has to be done before initializing UfsHcInfo or calling the UfsControllerInit
+ //
+ if (mUfsHcPlatform == NULL) {
+ Status = gBS->LocateProtocol (&gEdkiiUfsHcPlatformProtocolGuid, NULL, (VOID**)&mUfsHcPlatform);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "No UfsHcPlatformProtocol present\n"));
+ }
+ }
+
+ Status = GetUfsHcInfo (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to initialize UfsHcInfo\n"));
+ goto Error;
+ }
+
+ //
+ // Initialize UFS Host Controller H/W.
+ //
+ Status = UfsControllerInit (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Ufs Host Controller Initialization Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ //
+ // UFS 2.0 spec Section 13.1.3.3:
+ // At the end of the UFS Interconnect Layer initialization on both host and device side,
+ // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
+ //
+ Status = UfsExecNopCmds (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ Status = UfsFinishDeviceInitialization (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Device failed to finish initialization, Status = %r\n", Status));
+ goto Error;
+ }
+
+ //
+ // Check if 8 common luns are active and set corresponding bit mask.
+ //
+ UnitDescriptorSize = sizeof (UFS_UNIT_DESC);
+ for (Index = 0; Index < 8; Index++) {
+ Status = UfsRwDeviceDesc (Private, TRUE, UfsUnitDesc, (UINT8) Index, 0, &UnitDescriptor, &UnitDescriptorSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read unit descriptor, index = %X, status = %r\n", Index, Status));
+ continue;
+ }
+ if (UnitDescriptor.LunEn == 0x1) {
+ DEBUG ((DEBUG_INFO, "UFS LUN %X is enabled\n", Index));
+ Private->Luns.BitMask |= (BIT0 << Index);
+ }
+ }
+
+ //
+ // Check if RPMB WLUN is supported and set corresponding bit mask.
+ //
+ DeviceDescriptorSize = sizeof (UFS_DEV_DESC);
+ Status = UfsRwDeviceDesc (Private, TRUE, UfsDeviceDesc, 0, 0, &DeviceDescriptor, &DeviceDescriptorSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read device descriptor, status = %r\n", Status));
+ } else {
+ if (DeviceDescriptor.SecurityLun == 0x1) {
+ DEBUG ((DEBUG_INFO, "UFS WLUN RPMB is supported\n"));
+ Private->Luns.BitMask |= BIT11;
+ }
+ }
+
+ //
+ // Start the asynchronous interrupt monitor
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ProcessAsyncTaskList,
+ Private,
+ &Private->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Ufs Create Async Tasks Event Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ Status = gBS->SetTimer (
+ Private->TimerEvent,
+ TimerPeriodic,
+ UFS_HC_ASYNC_TIMER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Ufs Set Periodic Timer Error, Status = %r\n", Status));
+ goto Error;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ &(Private->ExtScsiPassThru),
+ &gEfiUfsDeviceConfigProtocolGuid,
+ &(Private->UfsDevConfig),
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+Error:
+ if (Private != NULL) {
+ if (Private->TmrlMapping != NULL) {
+ UfsHc->Unmap (UfsHc, Private->TmrlMapping);
+ }
+ if (Private->UtpTmrlBase != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)), Private->UtpTmrlBase);
+ }
+
+ if (Private->TrlMapping != NULL) {
+ UfsHc->Unmap (UfsHc, Private->TrlMapping);
+ }
+ if (Private->UtpTrlBase != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
+ }
+
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ FreePool (Private);
+ }
+
+ if (UfsHc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+UfsPassThruDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ UFS_PASS_THRU_TRANS_REQ *TransReq;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+
+ DEBUG ((DEBUG_INFO, "==UfsPassThru Stop== Controller Controller = %x\n", Controller));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **) &ExtScsiPassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru);
+ UfsHc = Private->UfsHostController;
+
+ //
+ // Cleanup the resources of I/O requests in the async I/O queue
+ //
+ if (!IsListEmpty(&Private->Queue)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
+ TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
+
+ //
+ // TODO: Should find/add a proper host adapter return status for this
+ // case.
+ //
+ TransReq->Packet->HostAdapterStatus =
+ EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
+
+ SignalCallerEvent (Private, TransReq);
+ }
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ &(Private->ExtScsiPassThru),
+ &gEfiUfsDeviceConfigProtocolGuid,
+ &(Private->UfsDevConfig),
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Stop Ufs Host Controller
+ //
+ Status = UfsControllerStop (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Private->TmrlMapping != NULL) {
+ UfsHc->Unmap (UfsHc, Private->TmrlMapping);
+ }
+ if (Private->UtpTmrlBase != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)), Private->UtpTmrlBase);
+ }
+
+ if (Private->TrlMapping != NULL) {
+ UfsHc->Unmap (UfsHc, Private->TrlMapping);
+ }
+ if (Private->UtpTrlBase != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
+ }
+
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ FreePool (Private);
+
+ //
+ // Close protocols opened by UfsPassThru controller driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEdkiiUfsHostControllerProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ The user Entry Point for module UfsPassThru. 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
+InitializeUfsPassThru (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUfsPassThruDriverBinding,
+ ImageHandle,
+ &gUfsPassThruComponentName,
+ &gUfsPassThruComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
new file mode 100644
index 000000000..ef33250c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
@@ -0,0 +1,998 @@
+/** @file
+
+ Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_PASS_THRU_H_
+#define _UFS_PASS_THRU_H_
+
+#include <Uefi.h>
+
+#include <Protocol/ScsiPassThruExt.h>
+#include <Protocol/UfsDeviceConfig.h>
+#include <Protocol/UfsHostController.h>
+#include <Protocol/UfsHostControllerPlatform.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/DevicePathLib.h>
+#include <Library/TimerLib.h>
+
+#include "UfsPassThruHci.h"
+
+#define UFS_PASS_THRU_SIG SIGNATURE_32 ('U', 'F', 'S', 'P')
+
+//
+// Lun 0~7 is for 8 common luns.
+// Lun 8~11 is for those 4 well known luns (Refer to UFS 2.0 spec Table 10.58 for details):
+// Lun 8: REPORT LUNS
+// Lun 9: UFS DEVICE
+// Lun 10: BOOT
+// Lun 11: RPMB
+//
+#define UFS_MAX_LUNS 12
+#define UFS_WLUN_PREFIX 0xC1
+
+typedef struct {
+ UINT8 Lun[UFS_MAX_LUNS];
+ UINT16 BitMask:12; // Bit 0~7 is 1/1 mapping to common luns. Bit 8~11 is 1/1 mapping to well-known luns.
+ UINT16 Rsvd:4;
+} UFS_EXPOSED_LUNS;
+
+typedef struct _UFS_PASS_THRU_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_EXT_SCSI_PASS_THRU_MODE ExtScsiPassThruMode;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL ExtScsiPassThru;
+ EFI_UFS_DEVICE_CONFIG_PROTOCOL UfsDevConfig;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHostController;
+ UINTN UfsHcBase;
+ EDKII_UFS_HC_INFO UfsHcInfo;
+ EDKII_UFS_HC_DRIVER_INTERFACE UfsHcDriverInterface;
+
+ UINT8 TaskTag;
+
+ VOID *UtpTrlBase;
+ UINT8 Nutrs;
+ VOID *TrlMapping;
+ VOID *UtpTmrlBase;
+ UINT8 Nutmrs;
+ VOID *TmrlMapping;
+
+ UFS_EXPOSED_LUNS Luns;
+
+ //
+ // For Non-blocking operation.
+ //
+ EFI_EVENT TimerEvent;
+ LIST_ENTRY Queue;
+} UFS_PASS_THRU_PRIVATE_DATA;
+
+#define UFS_PASS_THRU_TRANS_REQ_SIG SIGNATURE_32 ('U', 'F', 'S', 'T')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY TransferList;
+
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UINT32 CmdDescSize;
+ VOID *CmdDescHost;
+ VOID *CmdDescMapping;
+ VOID *AlignedDataBuf;
+ UINTN AlignedDataBufSize;
+ VOID *DataBufMapping;
+
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
+ UINT64 TimeoutRemain;
+ EFI_EVENT CallerEvent;
+} UFS_PASS_THRU_TRANS_REQ;
+
+#define UFS_PASS_THRU_TRANS_REQ_FROM_THIS(a) \
+ CR(a, UFS_PASS_THRU_TRANS_REQ, TransferList, UFS_PASS_THRU_TRANS_REQ_SIG)
+
+#define UFS_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3)
+#define UFS_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
+
+#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+#define UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ UFS_PASS_THRU_PRIVATE_DATA, \
+ ExtScsiPassThru, \
+ UFS_PASS_THRU_SIG \
+ )
+
+#define UFS_PASS_THRU_PRIVATE_DATA_FROM_DEV_CONFIG(a) \
+ CR (a, \
+ UFS_PASS_THRU_PRIVATE_DATA, \
+ UfsDevConfig, \
+ UFS_PASS_THRU_SIG \
+ )
+
+#define UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF(a) \
+ CR (a, \
+ UFS_PASS_THRU_PRIVATE_DATA, \
+ UfsHcDriverInterface, \
+ UFS_PASS_THRU_SIG \
+ )
+
+typedef struct _UFS_DEVICE_MANAGEMENT_REQUEST_PACKET {
+ UINT64 Timeout;
+ VOID *DataBuffer;
+ UINT8 Opcode;
+ UINT8 DescId;
+ UINT8 Index;
+ UINT8 Selector;
+ UINT32 TransferLength;
+ UINT8 DataDirection;
+} UFS_DEVICE_MANAGEMENT_REQUEST_PACKET;
+
+//
+// function prototype
+//
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. 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. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ 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. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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
+UfsPassThruDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ 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
+UfsPassThruDriverBindingStop (
+ 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
+UfsPassThruComponentNameGetDriverName (
+ 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
+UfsPassThruComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
+ supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
+ nonblocking I/O functionality is optional.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it represents
+ the id of the SCSI device to send the SCSI Request Packet. Each
+ transport driver may choose to utilize a subset of this size to suit the needs
+ of transport target representation. For example, a Fibre Channel driver
+ may use only 8 bytes (WWN) to represent an FC target.
+ @param Lun The LUN of the SCSI device to send the SCSI Request Packet.
+ @param Packet A pointer to the SCSI Request Packet to send to the SCSI device
+ specified by Target and Lun.
+ @param Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed. The number of bytes that
+ could be transferred is returned in InTransferLength. For write
+ and bi-directional commands, OutTransferLength bytes were
+ transferred by OutDataBuffer.
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
+ SCSI Request Packets already queued. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported
+ by the host adapter. This includes the case of Bi-directional SCSI
+ commands not supported by the implementation. The SCSI Request
+ Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruPassThru (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These
+ can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal
+ Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the
+ Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI
+ channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target On input, a pointer to the Target ID (an array of size
+ TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+ @param Lun On input, a pointer to the LUN of a SCSI device present on the SCSI
+ channel. On output, a pointer to the LUN of the next SCSI device present
+ on a SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID and LUN of the next SCSI device on the SCSI
+ channel was returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were
+ not returned on a previous call to GetNextTargetLun().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ );
+
+/**
+ Used to allocate and build a device path node for a SCSI device on a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTES and it specifies the
+ Target ID of the SCSI device for which a device path node is to be
+ allocated and built. Transport drivers may chose to utilize a subset of
+ this size to suit the representation of targets. For example, a Fibre
+ Channel driver may use only 8 bytes (WWN) in the array to represent a
+ FC target.
+ @param Lun The LUN of the SCSI device for which a device path node is to be
+ allocated and built.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ specified by Target and Lun. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SCSI device specified by
+ Target and Lun was allocated and returned in
+ DevicePath.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist
+ on the SCSI channel.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Used to translate a device path node to a Target ID and LUN.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param DevicePath A pointer to a single device path node that describes the SCSI device
+ on the SCSI channel.
+ @param Target A pointer to the Target Array which represents the ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of a SCSI device on the SCSI channel.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a Target ID and
+ LUN, and they were returned in Target and Lun.
+ @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a Target ID and LUN
+ does not exist.
+ @retval EFI_UNSUPPORTED This driver does not support the device path node type in
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ );
+
+/**
+ Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SCSI channel was reset.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI channel.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a channel reset operation.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ );
+
+/**
+ Resets a SCSI logical unit that is connected to a SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target The Target is an array of size TARGET_MAX_BYTE and it represents the
+ target port ID of the SCSI device containing the SCSI logical unit to
+ reset. Transport drivers may chose to utilize a subset of this array to suit
+ the representation of their targets.
+ @param Lun The LUN of the SCSI device to reset.
+
+ @retval EFI_SUCCESS The SCSI device specified by Target and Lun was reset.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a target reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI device
+ specified by Target and Lun.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruResetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ );
+
+/**
+ Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either
+ be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs
+ for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to
+ see if a SCSI device is actually present at that location on the SCSI channel.
+
+ @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
+ @param Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.
+ On output, a pointer to the Target ID (an array of
+ TARGET_MAX_BYTES) of the next SCSI device present on a SCSI
+ channel. An input value of 0xF(all bytes in the array are 0xF) in the
+ Target array retrieves the Target ID of the first SCSI device present on a
+ SCSI channel.
+
+ @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
+ channel was returned in Target.
+ @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
+ @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
+ returned on a previous call to GetNextTarget().
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsPassThruGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ );
+
+/**
+ Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
+ UFS device.
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsExecScsiCmds (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Initialize the UFS host controller.
+
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+UfsControllerInit (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ );
+
+/**
+ Stop the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
+ @retval Others A device error occurred while stopping the controller.
+
+**/
+EFI_STATUS
+UfsControllerStop (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ );
+
+/**
+ Allocate common buffer for host and UFS bus master access simultaneously.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Size The length of buffer to be allocated.
+ @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
+ @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
+ @param[out] CmdDescMapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The common buffer was allocated successfully.
+ @retval EFI_DEVICE_ERROR The allocation fails.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsAllocateAlignCommonBuffer (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINTN Size,
+ OUT VOID **CmdDescHost,
+ OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
+ OUT VOID **CmdDescMapping
+ );
+
+/**
+ Set specified flag to 1 on a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be set.
+
+ @retval EFI_SUCCESS The flag was set successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
+
+**/
+EFI_STATUS
+UfsSetFlag (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 FlagId
+ );
+
+/**
+ Read specified flag from a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be read.
+ @param[out] Value The flag's value.
+
+ @retval EFI_SUCCESS The flag was read successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
+
+**/
+EFI_STATUS
+UfsReadFlag (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 FlagId,
+ OUT UINT8 *Value
+ );
+
+/**
+ Read or write specified flag of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] FlagId The ID of flag to be read or written.
+ @param[in, out] Value The value to set or clear flag.
+
+ @retval EFI_SUCCESS The flag was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
+
+**/
+EFI_STATUS
+UfsRwFlags (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 FlagId,
+ IN OUT UINT8 *Value
+ );
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
+ of the data buffer specified by Descriptor. On output, the number
+ of bytes that were actually transferred.
+
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
+
+**/
+EFI_STATUS
+UfsRwDeviceDesc (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT VOID *Descriptor,
+ IN OUT UINT32 *DescSize
+ );
+
+/**
+ Read or write specified attribute of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] AttrId The ID of Attribute.
+ @param[in] Index The Index of Attribute.
+ @param[in] Selector The Selector of Attribute.
+ @param[in, out] Attributes The value of Attribute to be read or written.
+
+ @retval EFI_SUCCESS The Attribute was read/written successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
+
+**/
+EFI_STATUS
+UfsRwAttributes (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 AttrId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT32 *Attributes
+ );
+
+/**
+ Sends NOP IN cmd to a UFS device for initialization process request.
+ For more details, please refer to UFS 2.0 spec Figure 13.3.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
+ received successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
+
+**/
+EFI_STATUS
+UfsExecNopCmds (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ );
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Internal helper function which will signal the caller event and clean up
+ resources.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
+ structure.
+ @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
+ structure.
+
+**/
+VOID
+EFIAPI
+SignalCallerEvent (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_PASS_THRU_TRANS_REQ *TransReq
+ );
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ The function is used to read/write UFS device descriptors. The consumer of this API is
+ responsible for allocating the data buffer pointed by Descriptor.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
+ of the data buffer specified by Descriptor. On output, the number
+ of bytes that were actually transferred.
+
+ @retval EFI_SUCCESS The device descriptor is read/written successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Descriptor is NULL or DescSize is NULL.
+ DescId, Index and Selector are invalid combination to point to a
+ type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR The device descriptor is not read/written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsDescriptor (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT8 *Descriptor,
+ IN OUT UINT32 *DescSize
+ );
+
+/**
+ Read or write specified flag of a UFS device.
+
+ The function is used to read/write UFS flag descriptors. The consumer of this API is responsible
+ for allocating the buffer pointed by Flag. The buffer size is 1 byte as UFS flag descriptor is
+ just a single Boolean value that represents a TRUE or FALSE, '0' or '1', ON or OFF type of value.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] FlagId The ID of flag to be read or written.
+ @param[in, out] Flag The buffer to set or clear flag.
+
+ @retval EFI_SUCCESS The flag descriptor is set/clear successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Flag is NULL.
+ FlagId is an invalid UFS flag ID.
+ @retval EFI_DEVICE_ERROR The flag is not set/clear successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsFlag (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 FlagId,
+ IN OUT UINT8 *Flag
+ );
+
+/**
+ Read or write specified attribute of a UFS device.
+
+ The function is used to read/write UFS attributes. The consumer of this API is responsible for
+ allocating the data buffer pointed by Attribute.
+
+ @param[in] This The pointer to the EFI_UFS_DEVICE_CONFIG_PROTOCOL instance.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] AttrId The ID of Attribute.
+ @param[in] Index The Index of Attribute.
+ @param[in] Selector The Selector of Attribute.
+ @param[in, out] Attribute The buffer of Attribute to be read or written.
+ @param[in, out] AttrSize The size of Attribute buffer. On input, the size, in bytes, of the
+ data buffer specified by Attribute. On output, the number of bytes
+ that were actually transferred.
+
+ @retval EFI_SUCCESS The attribute is read/written successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Attribute is NULL or AttrSize is NULL.
+ AttrId, Index and Selector are invalid combination to point to a
+ type of UFS attribute.
+ @retval EFI_DEVICE_ERROR The attribute is not read/written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UfsRwUfsAttribute (
+ IN EFI_UFS_DEVICE_CONFIG_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN UINT8 AttrId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT8 *Attribute,
+ IN OUT UINT32 *AttrSize
+ );
+
+/**
+ Execute UIC command.
+
+ @param[in] This Pointer to driver interface produced by the UFS controller.
+ @param[in, out] UicCommand Descriptor of the command that will be executed.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
+ @retval Others Command failed to execute.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcDriverInterfaceExecUicCommand (
+ IN EDKII_UFS_HC_DRIVER_INTERFACE *This,
+ IN OUT EDKII_UIC_COMMAND *UicCommand
+ );
+
+/**
+ Initializes UfsHcInfo field in private data.
+
+ @param[in] Private Pointer to host controller private data.
+
+ @retval EFI_SUCCESS UfsHcInfo initialized successfully.
+ @retval Others Failed to initalize UfsHcInfo.
+**/
+EFI_STATUS
+GetUfsHcInfo (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ );
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUfsPassThruComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding;
+extern EDKII_UFS_HC_PLATFORM_PROTOCOL *mUfsHcPlatform;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni
new file mode 100644
index 000000000..5aa4f587f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The UfsPassThruDxe driver is used to provide support on accessing UFS device.
+//
+// It produces an EFI_EXT_SCSI_PASS_THRU_PROTOCOL interface for upper layer to send
+// SCSI cmd to UFS device.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Used to provide support on accessing UFS device."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It produces an EFI_EXT_SCSI_PASS_THRU_PROTOCOL interface for upper layer to send SCSI cmd to UFS device."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
new file mode 100644
index 000000000..92dc25714
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# Description file for the Universal Flash Storage (UFS) Pass Thru driver.
+#
+# Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UfsPassThruDxe
+ MODULE_UNI_FILE = UfsPassThru.uni
+ FILE_GUID = E7F1DFF9-DAB6-498A-9ADF-57F344EDDF57
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeUfsPassThru
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUfsPassThruDriverBinding
+# COMPONENT_NAME = gUfsPassThruComponentName
+#
+
+[Sources]
+ ComponentName.c
+ UfsDevConfigProtocol.c
+ UfsPassThru.c
+ UfsPassThru.h
+ UfsPassThruHci.c
+ UfsPassThruHci.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+ DevicePathLib
+ TimerLib
+
+[Protocols]
+ gEfiExtScsiPassThruProtocolGuid ## BY_START
+ gEfiUfsDeviceConfigProtocolGuid ## BY_START
+ gEdkiiUfsHostControllerProtocolGuid ## TO_START
+ gEdkiiUfsHcPlatformProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UfsPassThruExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni
new file mode 100644
index 000000000..dd6d31526
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UfsPassThruDxe Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UFS PassThru UEFI Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
new file mode 100644
index 000000000..0b1030ab4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
@@ -0,0 +1,2454 @@
+/** @file
+ UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
+ for upper layer application to execute UFS-supported SCSI cmds.
+
+ Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UfsPassThru.h"
+
+/**
+ Read 32bits data from specified UFS MMIO register.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Offset The offset within the UFS Host Controller MMIO space to start
+ the memory operation.
+ @param[out] Value The data buffer to store.
+
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+UfsMmioRead32 (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINTN Offset,
+ OUT UINT32 *Value
+ )
+{
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ EFI_STATUS Status;
+
+ UfsHc = Private->UfsHostController;
+
+ Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);
+
+ return Status;
+}
+
+/**
+ Write 32bits data to specified UFS MMIO register.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Offset The offset within the UFS Host Controller MMIO space to start
+ the memory operation.
+ @param[in] Value The data to write.
+
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+UfsMmioWrite32 (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINTN Offset,
+ IN UINT32 Value
+ )
+{
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ EFI_STATUS Status;
+
+ UfsHc = Private->UfsHostController;
+
+ Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);
+
+ return Status;
+}
+
+/**
+ Wait for the value of the specified system memory set to the test value.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Offset The offset within the UFS Host Controller MMIO space to start
+ the memory operation.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+UfsWaitMemSet (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINTN Offset,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+ EFI_STATUS Status;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 10) + 1;
+
+ do {
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Status = UfsMmioRead32 (Private, Offset, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 1 microseconds.
+ //
+ MicroSecondDelay (1);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Dump UIC command execution result for debugging.
+
+ @param[in] UicOpcode The executed UIC opcode.
+ @param[in] Result The result to be parsed.
+
+**/
+VOID
+DumpUicCmdExecResult (
+ IN UINT8 UicOpcode,
+ IN UINT8 Result
+ )
+{
+ if (UicOpcode <= UfsUicDmePeerSet) {
+ switch (Result) {
+ case 0x00:
+ break;
+ case 0x01:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x02:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
+ break;
+ case 0x03:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x04:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x05:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));
+ break;
+ case 0x06:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
+ break;
+ case 0x07:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
+ break;
+ case 0x08:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
+ break;
+ case 0x09:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));
+ break;
+ case 0x0A:
+ DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+ } else {
+ switch (Result) {
+ case 0x00:
+ break;
+ case 0x01:
+ DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+ }
+}
+
+/**
+ Dump QUERY RESPONSE UPIU result for debugging.
+
+ @param[in] Result The result to be parsed.
+
+**/
+VOID
+DumpQueryResponseResult (
+ IN UINT8 Result
+ )
+{
+ switch (Result) {
+ case 0xF6:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));
+ break;
+ case 0xF7:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));
+ break;
+ case 0xF8:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));
+ break;
+ case 0xF9:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));
+ break;
+ case 0xFA:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));
+ break;
+ case 0xFB:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));
+ break;
+ case 0xFC:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));
+ break;
+ case 0xFD:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));
+ break;
+ case 0xFE:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));
+ break;
+ case 0xFF:
+ DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));
+ break;
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Swap little endian to big endian.
+
+ @param[in, out] Buffer The data buffer. In input, it contains little endian data.
+ In output, it will become big endian.
+ @param[in] BufferSize The length of converted data.
+
+**/
+VOID
+SwapLittleEndianToBigEndian (
+ IN OUT UINT8 *Buffer,
+ IN UINT32 BufferSize
+ )
+{
+ UINT32 Index;
+ UINT8 Temp;
+ UINT32 SwapCount;
+
+ SwapCount = BufferSize / 2;
+ for (Index = 0; Index < SwapCount; Index++) {
+ Temp = Buffer[Index];
+ Buffer[Index] = Buffer[BufferSize - 1 - Index];
+ Buffer[BufferSize - 1 - Index] = Temp;
+ }
+}
+
+/**
+ Fill TSF field of QUERY REQUEST UPIU.
+
+ @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
+ @param[in] Opcode The opcode of request.
+ @param[in] DescId The descriptor ID of request.
+ @param[in] Index The index of request.
+ @param[in] Selector The selector of request.
+ @param[in] Length The length of transferred data. The maximum is 4.
+ @param[in] Value The value of transferred data.
+
+**/
+VOID
+UfsFillTsfOfQueryReqUpiu (
+ IN OUT UTP_UPIU_TSF *TsfBase,
+ IN UINT8 Opcode,
+ IN UINT8 DescId OPTIONAL,
+ IN UINT8 Index OPTIONAL,
+ IN UINT8 Selector OPTIONAL,
+ IN UINT16 Length OPTIONAL,
+ IN UINT32 Value OPTIONAL
+ )
+{
+ ASSERT (TsfBase != NULL);
+ ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);
+
+ TsfBase->Opcode = Opcode;
+ if (Opcode != UtpQueryFuncOpcodeNop) {
+ TsfBase->DescId = DescId;
+ TsfBase->Index = Index;
+ TsfBase->Selector = Selector;
+
+ if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
+ SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));
+ TsfBase->Length = Length;
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrAttr) {
+ SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));
+ TsfBase->Value = Value;
+ }
+ }
+}
+
+/**
+ Initialize COMMAND UPIU.
+
+ @param[in, out] Command The base address of COMMAND UPIU.
+ @param[in] Lun The Lun on which the SCSI command is executed.
+ @param[in] TaskTag The task tag of request.
+ @param[in] Cdb The cdb buffer containing SCSI command.
+ @param[in] CdbLength The cdb length.
+ @param[in] DataDirection The direction of data transfer.
+ @param[in] ExpDataTranLen The expected transfer data length.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitCommandUpiu (
+ IN OUT UTP_COMMAND_UPIU *Command,
+ IN UINT8 Lun,
+ IN UINT8 TaskTag,
+ IN UINT8 *Cdb,
+ IN UINT8 CdbLength,
+ IN UFS_DATA_DIRECTION DataDirection,
+ IN UINT32 ExpDataTranLen
+ )
+{
+ UINT8 Flags;
+
+ ASSERT ((Command != NULL) && (Cdb != NULL));
+
+ //
+ // Task attribute is hard-coded to Ordered.
+ //
+ if (DataDirection == UfsDataIn) {
+ Flags = BIT0 | BIT6;
+ } else if (DataDirection == UfsDataOut) {
+ Flags = BIT0 | BIT5;
+ } else {
+ Flags = BIT0;
+ }
+
+ //
+ // Fill UTP COMMAND UPIU associated fields.
+ //
+ Command->TransCode = 0x01;
+ Command->Flags = Flags;
+ Command->Lun = Lun;
+ Command->TaskTag = TaskTag;
+ Command->CmdSet = 0x00;
+ SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));
+ Command->ExpDataTranLen = ExpDataTranLen;
+
+ CopyMem (Command->Cdb, Cdb, CdbLength);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UTP PRDT for data transfer.
+
+ @param[in] Prdt The base address of PRDT.
+ @param[in] Buffer The buffer to be read or written.
+ @param[in] BufferSize The data size to be read or written.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitUtpPrdt (
+ IN UTP_TR_PRD *Prdt,
+ IN VOID *Buffer,
+ IN UINT32 BufferSize
+ )
+{
+ UINT32 PrdtIndex;
+ UINT32 RemainingLen;
+ UINT8 *Remaining;
+ UINTN PrdtNumber;
+
+ ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);
+ ASSERT ((BufferSize & (BIT1 | BIT0)) == 0);
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ RemainingLen = BufferSize;
+ Remaining = Buffer;
+ PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
+
+ for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
+ if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {
+ Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;
+ } else {
+ Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;
+ }
+
+ Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);
+ Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);
+ RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;
+ Remaining += UFS_MAX_DATA_LEN_PER_PRD;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize QUERY REQUEST UPIU.
+
+ @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
+ @param[in] TaskTag The task tag of request.
+ @param[in] Opcode The opcode of request.
+ @param[in] DescId The descriptor ID of request.
+ @param[in] Index The index of request.
+ @param[in] Selector The selector of request.
+ @param[in] DataSize The data size to be read or written.
+ @param[in] Data The buffer to be read or written.
+
+ @retval EFI_SUCCESS The initialization succeed.
+
+**/
+EFI_STATUS
+UfsInitQueryRequestUpiu (
+ IN OUT UTP_QUERY_REQ_UPIU *QueryReq,
+ IN UINT8 TaskTag,
+ IN UINT8 Opcode,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN UINTN DataSize OPTIONAL,
+ IN UINT8 *Data OPTIONAL
+ )
+{
+ ASSERT (QueryReq != NULL);
+
+ QueryReq->TransCode = 0x16;
+ QueryReq->TaskTag = TaskTag;
+ if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {
+ QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;
+ } else {
+ QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrAttr) {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);
+ } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);
+ } else {
+ UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);
+ }
+
+ if (Opcode == UtpQueryFuncOpcodeWrDesc) {
+ CopyMem (QueryReq + 1, Data, DataSize);
+
+ SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));
+ QueryReq->DataSegLen = (UINT16)DataSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Lun The Lun on which the SCSI command is executed.
+ @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+ @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
+ @param[out] CmdDescMapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsCreateScsiCommandDesc (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN UTP_TRD *Trd,
+ OUT VOID **CmdDescHost,
+ OUT VOID **CmdDescMapping
+ )
+{
+ UINTN TotalLen;
+ UINTN PrdtNumber;
+ UTP_COMMAND_UPIU *CommandUpiu;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ EFI_STATUS Status;
+ UINT32 DataLen;
+ UFS_DATA_DIRECTION DataDirection;
+
+ ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
+
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ DataLen = Packet->InTransferLength;
+ DataDirection = UfsDataIn;
+ } else {
+ DataLen = Packet->OutTransferLength;
+ DataDirection = UfsDataOut;
+ }
+
+ if (DataLen == 0) {
+ DataDirection = UfsNoData;
+ }
+
+ PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
+
+ TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);
+
+ Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;
+
+ UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
+ // *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = DataDirection;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));
+ Trd->PrdtL = (UINT16)PrdtNumber;
+ Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+ @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
+ @param[out] CmdDescMapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+ @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
+
+**/
+EFI_STATUS
+UfsCreateDMCommandDesc (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
+ IN UTP_TRD *Trd,
+ OUT VOID **CmdDescHost,
+ OUT VOID **CmdDescMapping
+ )
+{
+ UINTN TotalLen;
+ UTP_QUERY_REQ_UPIU *QueryReqUpiu;
+ UINT8 Opcode;
+ UINT32 DataSize;
+ UINT8 *Data;
+ UINT8 DataDirection;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ EFI_STATUS Status;
+
+ ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
+
+ Opcode = Packet->Opcode;
+ if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DataDirection = Packet->DataDirection;
+ DataSize = Packet->TransferLength;
+ Data = Packet->DataBuffer;
+
+ if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {
+ if (DataSize == 0 || Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);
+ } else {
+ TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));
+ }
+
+ Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize UTP QUERY REQUEST UPIU
+ //
+ QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;
+ ASSERT (QueryReqUpiu != NULL);
+ UfsInitQueryRequestUpiu (
+ QueryReqUpiu,
+ Private->TaskTag++,
+ Opcode,
+ Packet->DescId,
+ Packet->Index,
+ Packet->Selector,
+ DataSize,
+ Data
+ );
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = DataDirection;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
+ if (Opcode == UtpQueryFuncOpcodeWrDesc) {
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
+ } else {
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
+ @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
+ @param[out] CmdDescMapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The creation succeed.
+ @retval EFI_DEVICE_ERROR The creation failed.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsCreateNopCommandDesc (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UTP_TRD *Trd,
+ OUT VOID **CmdDescHost,
+ OUT VOID **CmdDescMapping
+ )
+{
+ UINTN TotalLen;
+ UTP_NOP_OUT_UPIU *NopOutUpiu;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+
+ ASSERT ((Private != NULL) && (Trd != NULL));
+
+ TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));
+ Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;
+ ASSERT (NopOutUpiu != NULL);
+ NopOutUpiu->TaskTag = Private->TaskTag++;
+
+ //
+ // Fill UTP_TRD associated fields
+ // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
+ //
+ Trd->Int = UFS_INTERRUPT_COMMAND;
+ Trd->Dd = 0x00;
+ Trd->Ct = UFS_STORAGE_COMMAND_TYPE;
+ Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;
+ Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);
+ Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);
+ Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));
+ Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find out available slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[out] Slot The available slot.
+
+ @retval EFI_SUCCESS The available slot was found successfully.
+ @retval EFI_NOT_READY No slot is available at this moment.
+
+**/
+EFI_STATUS
+UfsFindAvailableSlotInTrl (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ OUT UINT8 *Slot
+ )
+{
+ UINT8 Nutrs;
+ UINT8 Index;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ ASSERT ((Private != NULL) && (Slot != NULL));
+
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);
+
+ for (Index = 0; Index < Nutrs; Index++) {
+ if ((Data & (BIT0 << Index)) == 0) {
+ *Slot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+
+/**
+ Start specified slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Slot The slot to be started.
+
+**/
+EFI_STATUS
+UfsStartExecCmd (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop specified slot in transfer list of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Slot The slot to be stop.
+
+**/
+EFI_STATUS
+UfsStopExecCmd (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT0 << Slot)) != 0) {
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Extracts return data from query response upiu.
+
+ @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
+ @param[in] QueryResp Pointer to the query response.
+
+ @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
+ @retval EFI_DEVICE_ERROR Data returned from device is invalid.
+ @retval EFI_SUCCESS Data extracted.
+
+**/
+EFI_STATUS
+UfsGetReturnDataFromQueryResponse (
+ IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,
+ IN UTP_QUERY_RESP_UPIU *QueryResp
+ )
+{
+ UINT16 ReturnDataSize;
+ UINT32 ReturnData;
+
+ if (Packet == NULL || QueryResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Packet->Opcode) {
+ case UtpQueryFuncOpcodeRdDesc:
+ ReturnDataSize = QueryResp->Tsf.Length;
+ SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
+ //
+ // Make sure the hardware device does not return more data than expected.
+ //
+ if (ReturnDataSize > Packet->TransferLength) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);
+ Packet->TransferLength = ReturnDataSize;
+ break;
+ case UtpQueryFuncOpcodeWrDesc:
+ ReturnDataSize = QueryResp->Tsf.Length;
+ SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));
+ Packet->TransferLength = ReturnDataSize;
+ break;
+ case UtpQueryFuncOpcodeRdFlag:
+ case UtpQueryFuncOpcodeSetFlag:
+ case UtpQueryFuncOpcodeClrFlag:
+ case UtpQueryFuncOpcodeTogFlag:
+ //
+ // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
+ //
+ *((UINT8*)(Packet->DataBuffer)) = *((UINT8*)&(QueryResp->Tsf.Value) + 3);
+ break;
+ case UtpQueryFuncOpcodeRdAttr:
+ case UtpQueryFuncOpcodeWrAttr:
+ ReturnData = QueryResp->Tsf.Value;
+ SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));
+ CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Creates Transfer Request descriptor and sends Query Request to the device.
+
+ @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
+ @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
+
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.
+ @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
+ combination to point to a type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
+
+**/
+EFI_STATUS
+UfsSendDmRequestRetry (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
+ )
+{
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ VOID *CmdDescHost;
+ VOID *CmdDescMapping;
+ UINT32 CmdDescSize;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ UTP_QUERY_RESP_UPIU *QueryResp;
+ EFI_STATUS Status;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ //
+ // Fill transfer request descriptor to this slot.
+ //
+ Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));
+ return Status;
+ }
+
+ UfsHc = Private->UfsHostController;
+ QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
+ ASSERT (QueryResp != NULL);
+ CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {
+ DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));
+ DumpQueryResponseResult (QueryResp->QueryResp);
+
+ if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||
+ (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||
+ (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ goto Exit;
+ }
+
+ Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));
+ goto Exit;
+ }
+
+Exit:
+ UfsHc->Flush (UfsHc);
+
+ UfsStopExecCmd (Private, Slot);
+
+ if (CmdDescMapping != NULL) {
+ UfsHc->Unmap (UfsHc, CmdDescMapping);
+ }
+ if (CmdDescHost != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
+ }
+
+ return Status;
+}
+
+/**
+ Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
+
+ @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
+ @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
+
+ @retval EFI_SUCCESS The device responded correctly to the Query request.
+ @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
+ combination to point to a type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
+
+**/
+EFI_STATUS
+UfsSendDmRequest (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Retry;
+
+ Status = EFI_SUCCESS;
+
+ for (Retry = 0; Retry < 5; Retry ++) {
+ Status = UfsSendDmRequestRetry (Private, Packet);
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));
+ return Status;
+}
+
+/**
+ Read or write specified device descriptor of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] DescId The ID of device descriptor.
+ @param[in] Index The Index of device descriptor.
+ @param[in] Selector The Selector of device descriptor.
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.
+ @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
+ of the data buffer specified by Descriptor. On output, the number
+ of bytes that were actually transferred.
+
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.
+ @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
+ type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
+
+**/
+EFI_STATUS
+UfsRwDeviceDesc (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 DescId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT VOID *Descriptor,
+ IN OUT UINT32 *DescSize
+ )
+{
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
+ EFI_STATUS Status;
+
+ if (DescSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
+
+ if (Read) {
+ Packet.DataDirection = UfsDataIn;
+ Packet.Opcode = UtpQueryFuncOpcodeRdDesc;
+ } else {
+ Packet.DataDirection = UfsDataOut;
+ Packet.Opcode = UtpQueryFuncOpcodeWrDesc;
+ }
+ Packet.DataBuffer = Descriptor;
+ Packet.TransferLength = *DescSize;
+ Packet.DescId = DescId;
+ Packet.Index = Index;
+ Packet.Selector = Selector;
+ Packet.Timeout = UFS_TIMEOUT;
+
+ Status = UfsSendDmRequest (Private, &Packet);
+ if (EFI_ERROR (Status)) {
+ *DescSize = 0;
+ } else {
+ *DescSize = Packet.TransferLength;
+ }
+
+ return Status;
+}
+
+/**
+ Read or write specified attribute of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] AttrId The ID of Attribute.
+ @param[in] Index The Index of Attribute.
+ @param[in] Selector The Selector of Attribute.
+ @param[in, out] Attributes The value of Attribute to be read or written.
+
+ @retval EFI_SUCCESS The Attribute was read/written successfully.
+ @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
+ type of UFS device descriptor.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
+
+**/
+EFI_STATUS
+UfsRwAttributes (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 AttrId,
+ IN UINT8 Index,
+ IN UINT8 Selector,
+ IN OUT UINT32 *Attributes
+ )
+{
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
+
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
+
+ if (Read) {
+ Packet.DataDirection = UfsDataIn;
+ Packet.Opcode = UtpQueryFuncOpcodeRdAttr;
+ } else {
+ Packet.DataDirection = UfsDataOut;
+ Packet.Opcode = UtpQueryFuncOpcodeWrAttr;
+ }
+ Packet.DataBuffer = Attributes;
+ Packet.DescId = AttrId;
+ Packet.Index = Index;
+ Packet.Selector = Selector;
+ Packet.Timeout = UFS_TIMEOUT;
+
+ return UfsSendDmRequest (Private, &Packet);
+}
+
+/**
+ Read or write specified flag of a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Read The boolean variable to show r/w direction.
+ @param[in] FlagId The ID of flag to be read or written.
+ @param[in, out] Value The value to set or clear flag.
+
+ @retval EFI_SUCCESS The flag was read/written successfully.
+ @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
+
+**/
+EFI_STATUS
+UfsRwFlags (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN BOOLEAN Read,
+ IN UINT8 FlagId,
+ IN OUT UINT8 *Value
+ )
+{
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;
+
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));
+
+ if (Read) {
+ ASSERT (Value != NULL);
+ Packet.DataDirection = UfsDataIn;
+ Packet.Opcode = UtpQueryFuncOpcodeRdFlag;
+ } else {
+ Packet.DataDirection = UfsDataOut;
+ if (*Value == 1) {
+ Packet.Opcode = UtpQueryFuncOpcodeSetFlag;
+ } else if (*Value == 0) {
+ Packet.Opcode = UtpQueryFuncOpcodeClrFlag;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ Packet.DataBuffer = Value;
+ Packet.DescId = FlagId;
+ Packet.Index = 0;
+ Packet.Selector = 0;
+ Packet.Timeout = UFS_TIMEOUT;
+
+ return UfsSendDmRequest (Private, &Packet);
+}
+
+/**
+ Set specified flag to 1 on a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be set.
+
+ @retval EFI_SUCCESS The flag was set successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
+
+**/
+EFI_STATUS
+UfsSetFlag (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 FlagId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ Value = 1;
+ Status = UfsRwFlags (Private, FALSE, FlagId, &Value);
+
+ return Status;
+}
+
+/**
+ Read specified flag from a UFS device.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be read.
+ @param[out] Value The flag's value.
+
+ @retval EFI_SUCCESS The flag was read successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
+
+**/
+EFI_STATUS
+UfsReadFlag (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 FlagId,
+ OUT UINT8 *Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UfsRwFlags (Private, TRUE, FlagId, Value);
+
+ return Status;
+}
+
+/**
+ Sends NOP IN cmd to a UFS device for initialization process request.
+ For more details, please refer to UFS 2.0 spec Figure 13.3.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
+ received successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
+
+**/
+EFI_STATUS
+UfsExecNopCmds (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Slot;
+ UTP_TRD *Trd;
+ UTP_NOP_IN_UPIU *NopInUpiu;
+ UINT32 CmdDescSize;
+ VOID *CmdDescHost;
+ VOID *CmdDescMapping;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+ Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ UfsHc = Private->UfsHostController;
+ NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));
+ ASSERT (NopInUpiu != NULL);
+ CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, Slot);
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (NopInUpiu->Resp != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Exit:
+ UfsHc->Flush (UfsHc);
+
+ UfsStopExecCmd (Private, Slot);
+
+ if (CmdDescMapping != NULL) {
+ UfsHc->Unmap (UfsHc, CmdDescMapping);
+ }
+ if (CmdDescHost != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
+ }
+
+ return Status;
+}
+
+/**
+ Cleanup data buffers after data transfer. This function
+ also takes care to copy all data to user memory pool for
+ unaligned data transfers.
+
+ @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
+ @param[in] TransReq Pointer to the transfer request
+**/
+VOID
+UfsReconcileDataTransferBuffer (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_PASS_THRU_TRANS_REQ *TransReq
+ )
+{
+ if (TransReq->DataBufMapping != NULL) {
+ Private->UfsHostController->Unmap (
+ Private->UfsHostController,
+ TransReq->DataBufMapping
+ );
+ }
+
+ //
+ // Check if unaligned transfer was performed. If it was and we read
+ // data from device copy memory to user data buffers before cleanup.
+ // The assumption is if auxiliary aligned data buffer is not NULL then
+ // unaligned transfer has been performed.
+ //
+ if (TransReq->AlignedDataBuf != NULL) {
+ if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength);
+ }
+ //
+ // Wipe out the transfer buffer in case it contains sensitive data.
+ //
+ ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);
+ FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));
+ TransReq->AlignedDataBuf = NULL;
+ }
+}
+
+/**
+ Prepare data buffer for transfer.
+
+ @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
+ @param[in, out] TransReq Pointer to the transfer request
+
+ @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
+ @retval EFI_SUCCESS Buffer ready for transfer
+**/
+EFI_STATUS
+UfsPrepareDataTransferBuffer (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq
+ )
+{
+ EFI_STATUS Status;
+ VOID *DataBuf;
+ UINT32 DataLen;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
+ EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
+ UTP_TR_PRD *PrdtBase;
+
+ DataBufPhyAddr = 0;
+ DataBuf = NULL;
+
+ //
+ // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
+ // When command is finished auxiliary memory pool is copied into actual user memory.
+ // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
+ //
+ if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) {
+ DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4));
+ DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);
+ if (DataBuf == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ ZeroMem (DataBuf, DataLen);
+ TransReq->AlignedDataBuf = DataBuf;
+ TransReq->AlignedDataBufSize = DataLen;
+ } else {
+ DataLen = TransReq->Packet->InTransferLength;
+ DataBuf = TransReq->Packet->InDataBuffer;
+ }
+ Flag = EdkiiUfsHcOperationBusMasterWrite;
+ } else {
+ if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) {
+ DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4));
+ DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);
+ if (DataBuf == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength);
+ TransReq->AlignedDataBuf = DataBuf;
+ TransReq->AlignedDataBufSize = DataLen;
+ } else {
+ DataLen = TransReq->Packet->OutTransferLength;
+ DataBuf = TransReq->Packet->OutDataBuffer;
+ }
+ Flag = EdkiiUfsHcOperationBusMasterRead;
+ }
+
+ if (DataLen != 0) {
+ MapLength = DataLen;
+ Status = Private->UfsHostController->Map (
+ Private->UfsHostController,
+ Flag,
+ DataBuf,
+ &MapLength,
+ &DataBufPhyAddr,
+ &TransReq->DataBufMapping
+ );
+
+ if (EFI_ERROR (Status) || (DataLen != MapLength)) {
+ if (TransReq->AlignedDataBuf != NULL) {
+ //
+ // Wipe out the transfer buffer in case it contains sensitive data.
+ //
+ ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);
+ FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));
+ TransReq->AlignedDataBuf = NULL;
+ }
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Fill PRDT table of Command UPIU for executed SCSI cmd.
+ //
+ PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
+ ASSERT (PrdtBase != NULL);
+ UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
+ @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
+ UFS device.
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
+ I/O is performed. If Event is NULL, then blocking I/O is performed. If
+ Event is not NULL and non blocking I/O is supported, then
+ nonblocking I/O is performed, and Event will be signaled when the
+ SCSI Request Packet completes.
+
+ @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
+ commands, InTransferLength bytes were transferred from
+ InDataBuffer. For write and bi-directional commands,
+ OutTransferLength bytes were transferred by
+ OutDataBuffer.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
+ Packet.
+ @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
+
+**/
+EFI_STATUS
+UfsExecScsiCmds (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINT8 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UTP_RESPONSE_UPIU *Response;
+ UINT16 SenseDataLen;
+ UINT32 ResTranCount;
+ EFI_TPL OldTpl;
+ UFS_PASS_THRU_TRANS_REQ *TransReq;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+
+ TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
+ if (TransReq == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
+ TransReq->TimeoutRemain = Packet->Timeout;
+ TransReq->Packet = Packet;
+
+ UfsHc = Private->UfsHostController;
+ //
+ // Find out which slot of transfer request list is available.
+ //
+ Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
+
+ //
+ // Fill transfer request descriptor to this slot.
+ //
+ Status = UfsCreateScsiCommandDesc (
+ Private,
+ Lun,
+ Packet,
+ TransReq->Trd,
+ &TransReq->CmdDescHost,
+ &TransReq->CmdDescMapping
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
+
+ Status = UfsPrepareDataTransferBuffer (Private, TransReq);
+ if (EFI_ERROR (Status)) {
+ goto Exit1;
+ }
+
+ //
+ // Insert the async SCSI cmd to the Async I/O list
+ //
+ if (Event != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ TransReq->CallerEvent = Event;
+ InsertTailList (&Private->Queue, &TransReq->TransferList);
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ //
+ // Start to execute the transfer request.
+ //
+ UfsStartExecCmd (Private, TransReq->Slot);
+
+ //
+ // Immediately return for async I/O.
+ //
+ if (Event != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Wait for the completion of the transfer request.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Get sense data if exists
+ //
+ Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
+ ASSERT (Response != NULL);
+ SenseDataLen = Response->SenseDataLen;
+ SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
+
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
+ //
+ // Make sure the hardware device does not return more data than expected.
+ //
+ if (SenseDataLen <= Packet->SenseDataLength) {
+ CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
+ Packet->SenseDataLength = (UINT8)SenseDataLen;
+ } else {
+ Packet->SenseDataLength = 0;
+ }
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ Packet->TargetStatus = Response->Status;
+ if (Response->Response != 0) {
+ DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (TransReq->Trd->Ocs == 0) {
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->InTransferLength -= ResTranCount;
+ }
+ } else {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->OutTransferLength -= ResTranCount;
+ }
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ UfsHc->Flush (UfsHc);
+
+ UfsStopExecCmd (Private, TransReq->Slot);
+
+ UfsReconcileDataTransferBuffer (Private, TransReq);
+
+Exit1:
+ if (TransReq->CmdDescMapping != NULL) {
+ UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
+ }
+ if (TransReq->CmdDescHost != NULL) {
+ UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
+ }
+ if (TransReq != NULL) {
+ FreePool (TransReq);
+ }
+ return Status;
+}
+
+/**
+ Send UIC command.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
+
+ @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
+ @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
+
+**/
+EFI_STATUS
+UfsExecUicCommands (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN OUT EDKII_UIC_COMMAND *UicCommand
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {
+ //
+ // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // When programming UIC command registers, host software shall set the register UICCMD
+ // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
+ // are set.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
+ // This bit is set to '1' by the host controller upon completion of a UIC command.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UicCommand->Opcode != UfsUicDmeReset) {
+ Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((UicCommand->Arg2 & 0xFF) != 0) {
+ DEBUG_CODE_BEGIN();
+ DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF));
+ DEBUG_CODE_END();
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate common buffer for host and UFS bus master access simultaneously.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+ @param[in] Size The length of buffer to be allocated.
+ @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
+ @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
+ @param[out] CmdDescMapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The common buffer was allocated successfully.
+ @retval EFI_DEVICE_ERROR The allocation fails.
+ @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
+
+**/
+EFI_STATUS
+UfsAllocateAlignCommonBuffer (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UINTN Size,
+ OUT VOID **CmdDescHost,
+ OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,
+ OUT VOID **CmdDescMapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN Bytes;
+ BOOLEAN Is32BitAddr;
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+
+ if ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {
+ Is32BitAddr = FALSE;
+ } else {
+ Is32BitAddr = TRUE;
+ }
+
+ UfsHc = Private->UfsHostController;
+ Status = UfsHc->AllocateBuffer (
+ UfsHc,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ CmdDescHost,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ *CmdDescMapping = NULL;
+ *CmdDescHost = NULL;
+ *CmdDescPhyAddr = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));
+ Status = UfsHc->Map (
+ UfsHc,
+ EdkiiUfsHcOperationBusMasterCommonBuffer,
+ *CmdDescHost,
+ &Bytes,
+ CmdDescPhyAddr,
+ CmdDescMapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {
+ UfsHc->FreeBuffer (
+ UfsHc,
+ EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
+ *CmdDescHost
+ );
+ *CmdDescHost = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {
+ //
+ // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
+ //
+ UfsHc->Unmap (
+ UfsHc,
+ *CmdDescMapping
+ );
+ UfsHc->FreeBuffer (
+ UfsHc,
+ EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),
+ *CmdDescHost
+ );
+ *CmdDescMapping = NULL;
+ *CmdDescHost = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable the UFS host controller for accessing.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
+
+**/
+EFI_STATUS
+UfsEnableHostController (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ if (mUfsHcPlatform != NULL && mUfsHcPlatform->Callback != NULL) {
+ Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPreHce, &Private->UfsHcDriverInterface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
+ //
+ // Reinitialize the UFS host controller if HCE bit of HC register is set.
+ //
+ Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {
+ //
+ // Write a 0 to the HCE register at first to disable the host controller.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Wait until HCE is read as '0' before continuing.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Write a 1 to the HCE register to enable the UFS host controller.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Wait until HCE is read as '1' before continuing.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mUfsHcPlatform != NULL && mUfsHcPlatform->Callback != NULL) {
+ Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPostHce, &Private->UfsHcDriverInterface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect if a UFS device attached.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS device detection was executed successfully.
+ @retval EFI_NOT_FOUND Not found a UFS device attached.
+ @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
+
+**/
+EFI_STATUS
+UfsDeviceDetection (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ UINTN Retry;
+ EFI_STATUS Status;
+ UINT32 Data;
+ EDKII_UIC_COMMAND LinkStartupCommand;
+
+ if (mUfsHcPlatform != NULL && mUfsHcPlatform->Callback != NULL) {
+ Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPreLinkStartup, &Private->UfsHcDriverInterface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Start UFS device detection.
+ // Try up to 3 times for establishing data link with device.
+ //
+ for (Retry = 0; Retry < 3; Retry++) {
+ LinkStartupCommand.Opcode = UfsUicDmeLinkStartup;
+ LinkStartupCommand.Arg1 = 0;
+ LinkStartupCommand.Arg2 = 0;
+ LinkStartupCommand.Arg3 = 0;
+ Status = UfsExecUicCommands (Private, &LinkStartupCommand);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Data & UFS_HC_HCS_DP) == 0) {
+ Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ } else {
+ if (mUfsHcPlatform != NULL && mUfsHcPlatform->Callback != NULL) {
+ Status = mUfsHcPlatform->Callback (Private->Handle, EdkiiUfsHcPostLinkStartup, &Private->UfsHcDriverInterface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failure from platform driver during EdkiiUfsHcPostLinkStartup, Status = %r\n", Status));
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize UFS task management request list related h/w context.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
+ @retval EFI_DEVICE_ERROR The initialization fails.
+
+**/
+EFI_STATUS
+UfsInitTaskManagementRequestList (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ UINT8 Nutmrs;
+ VOID *CmdDescHost;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ VOID *CmdDescMapping;
+ EFI_STATUS Status;
+
+ //
+ // Initial h/w and s/w context for future operations.
+ //
+ CmdDescHost = NULL;
+ CmdDescMapping = NULL;
+ CmdDescPhyAddr = 0;
+
+ //
+ // Allocate and initialize UTP Task Management Request List.
+ //
+ Nutmrs = (UINT8) (RShiftU64 ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
+ Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Program the UTP Task Management Request List Base Address and UTP Task Management
+ // Request List Base Address with a 64-bit address allocated at step 6.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Private->UtpTmrlBase = CmdDescHost;
+ Private->Nutmrs = Nutmrs;
+ Private->TmrlMapping = CmdDescMapping;
+
+ //
+ // Enable the UTP Task Management Request List by setting the UTP Task Management
+ // Request List RunStop Register (UTMRLRSR) to '1'.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize UFS transfer request list related h/w context.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
+ @retval EFI_DEVICE_ERROR The initialization fails.
+
+**/
+EFI_STATUS
+UfsInitTransferRequestList (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ UINT8 Nutrs;
+ VOID *CmdDescHost;
+ EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
+ VOID *CmdDescMapping;
+ EFI_STATUS Status;
+
+ //
+ // Initial h/w and s/w context for future operations.
+ //
+ CmdDescHost = NULL;
+ CmdDescMapping = NULL;
+ CmdDescPhyAddr = 0;
+
+ //
+ // Allocate and initialize UTP Transfer Request List.
+ //
+ Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);
+ Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
+ // Base Address with a 64-bit address allocated at step 8.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->UtpTrlBase = CmdDescHost;
+ Private->Nutrs = Nutrs;
+ Private->TrlMapping = CmdDescMapping;
+
+ //
+ // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
+ // RunStop Register (UTRLRSR) to '1'.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+UfsControllerInit (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UfsEnableHostController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsDeviceDetection (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsInitTaskManagementRequestList (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = UfsInitTransferRequestList (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop the UFS host controller.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
+ @retval Others A device error occurred while stopping the controller.
+
+**/
+EFI_STATUS
+UfsControllerStop (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ //
+ // Enable the UTP Task Management Request List by setting the UTP Task Management
+ // Request List RunStop Register (UTMRLRSR) to '1'.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
+ // RunStop Register (UTRLRSR) to '1'.
+ //
+ Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Write a 0 to the HCE register in order to disable the host controller.
+ //
+ Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);
+
+ Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Wait until HCE is read as '0' before continuing.
+ //
+ Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal helper function which will signal the caller event and clean up
+ resources.
+
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
+ structure.
+ @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
+ structure.
+
+**/
+VOID
+EFIAPI
+SignalCallerEvent (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,
+ IN UFS_PASS_THRU_TRANS_REQ *TransReq
+ )
+{
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ EFI_EVENT CallerEvent;
+
+ ASSERT ((Private != NULL) && (TransReq != NULL));
+
+ UfsHc = Private->UfsHostController;
+ CallerEvent = TransReq->CallerEvent;
+
+ RemoveEntryList (&TransReq->TransferList);
+
+ UfsHc->Flush (UfsHc);
+
+ UfsStopExecCmd (Private, TransReq->Slot);
+
+ UfsReconcileDataTransferBuffer (Private, TransReq);
+
+ if (TransReq->CmdDescMapping != NULL) {
+ UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
+ }
+ if (TransReq->CmdDescHost != NULL) {
+ UfsHc->FreeBuffer (
+ UfsHc,
+ EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
+ TransReq->CmdDescHost
+ );
+ }
+
+ FreePool (TransReq);
+
+ gBS->SignalEvent (CallerEvent);
+ return;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ UFS_PASS_THRU_TRANS_REQ *TransReq;
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;
+ UTP_RESPONSE_UPIU *Response;
+ UINT16 SenseDataLen;
+ UINT32 ResTranCount;
+ UINT32 SlotsMap;
+ UINT32 Value;
+ EFI_STATUS Status;
+
+ Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
+ SlotsMap = 0;
+
+ //
+ // Check the entries in the async I/O queue are done or not.
+ //
+ if (!IsListEmpty(&Private->Queue)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
+ TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
+ Packet = TransReq->Packet;
+
+ if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
+ return;
+ }
+ SlotsMap |= BIT0 << TransReq->Slot;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
+ if (EFI_ERROR (Status)) {
+ //
+ // TODO: Should find/add a proper host adapter return status for this
+ // case.
+ //
+ Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));
+ SignalCallerEvent (Private, TransReq);
+ continue;
+ }
+
+ if ((Value & (BIT0 << TransReq->Slot)) != 0) {
+ //
+ // Scsi cmd not finished yet.
+ //
+ if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
+ TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
+ continue;
+ } else {
+ //
+ // Timeout occurs.
+ //
+ Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));
+ SignalCallerEvent (Private, TransReq);
+ continue;
+ }
+ } else {
+ //
+ // Scsi cmd finished.
+ //
+ // Get sense data if exists
+ //
+ Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));
+ ASSERT (Response != NULL);
+ SenseDataLen = Response->SenseDataLen;
+ SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
+
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
+ //
+ // Make sure the hardware device does not return more data than expected.
+ //
+ if (SenseDataLen <= Packet->SenseDataLength) {
+ CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
+ Packet->SenseDataLength = (UINT8)SenseDataLen;
+ } else {
+ Packet->SenseDataLength = 0;
+ }
+ }
+
+ //
+ // Check the transfer request result.
+ //
+ Packet->TargetStatus = Response->Status;
+ if (Response->Response != 0) {
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));
+ SignalCallerEvent (Private, TransReq);
+ continue;
+ }
+
+ if (TransReq->Trd->Ocs == 0) {
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->InTransferLength -= ResTranCount;
+ }
+ } else {
+ if ((Response->Flags & BIT5) == BIT5) {
+ ResTranCount = Response->ResTranCount;
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));
+ Packet->OutTransferLength -= ResTranCount;
+ }
+ }
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));
+ SignalCallerEvent (Private, TransReq);
+ continue;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));
+ SignalCallerEvent (Private, TransReq);
+ }
+ }
+ }
+}
+
+/**
+ Execute UIC command.
+
+ @param[in] This Pointer to driver interface produced by the UFS controller.
+ @param[in, out] UicCommand Descriptor of the command that will be executed.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
+ @retval Others Command failed to execute.
+**/
+EFI_STATUS
+EFIAPI
+UfsHcDriverInterfaceExecUicCommand (
+ IN EDKII_UFS_HC_DRIVER_INTERFACE *This,
+ IN OUT EDKII_UIC_COMMAND *UicCommand
+ )
+{
+ UFS_PASS_THRU_PRIVATE_DATA *Private;
+
+ if (This == NULL || UicCommand == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF (This);
+
+ return UfsExecUicCommands (Private, UicCommand);
+}
+
+/**
+ Initializes UfsHcInfo field in private data.
+
+ @param[in] Private Pointer to host controller private data.
+
+ @retval EFI_SUCCESS UfsHcInfo initialized successfully.
+ @retval Others Failed to initalize UfsHcInfo.
+**/
+EFI_STATUS
+GetUfsHcInfo (
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private
+ )
+{
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_VER_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->UfsHcInfo.Version = Data;
+
+ Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->UfsHcInfo.Capabilities = Data;
+
+ if (mUfsHcPlatform != NULL && mUfsHcPlatform->OverrideHcInfo != NULL) {
+ Status = mUfsHcPlatform->OverrideHcInfo (Private->Handle, &Private->UfsHcInfo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failure from platform on OverrideHcInfo, Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h
new file mode 100644
index 000000000..e8b5aae70
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.h
@@ -0,0 +1,1339 @@
+/** @file
+ UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
+ for upper layer application to execute UFS-supported SCSI cmds.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UFS_PASS_THRU_HCI_H_
+#define _UFS_PASS_THRU_HCI_H_
+
+//
+// Host Capabilities Register Offsets
+//
+#define UFS_HC_CAP_OFFSET 0x0000 // Controller Capabilities
+#define UFS_HC_VER_OFFSET 0x0008 // Version
+#define UFS_HC_DDID_OFFSET 0x0010 // Device ID and Device Class
+#define UFS_HC_PMID_OFFSET 0x0014 // Product ID and Manufacturer ID
+#define UFS_HC_AHIT_OFFSET 0x0018 // Auto-Hibernate Idle Timer
+//
+// Operation and Runtime Register Offsets
+//
+#define UFS_HC_IS_OFFSET 0x0020 // Interrupt Status
+#define UFS_HC_IE_OFFSET 0x0024 // Interrupt Enable
+#define UFS_HC_STATUS_OFFSET 0x0030 // Host Controller Status
+#define UFS_HC_ENABLE_OFFSET 0x0034 // Host Controller Enable
+#define UFS_HC_UECPA_OFFSET 0x0038 // Host UIC Error Code PHY Adapter Layer
+#define UFS_HC_UECDL_OFFSET 0x003c // Host UIC Error Code Data Link Layer
+#define UFS_HC_UECN_OFFSET 0x0040 // Host UIC Error Code Network Layer
+#define UFS_HC_UECT_OFFSET 0x0044 // Host UIC Error Code Transport Layer
+#define UFS_HC_UECDME_OFFSET 0x0048 // Host UIC Error Code DME
+#define UFS_HC_UTRIACR_OFFSET 0x004c // UTP Transfer Request Interrupt Aggregation Control Register
+//
+// UTP Transfer Register Offsets
+//
+#define UFS_HC_UTRLBA_OFFSET 0x0050 // UTP Transfer Request List Base Address
+#define UFS_HC_UTRLBAU_OFFSET 0x0054 // UTP Transfer Request List Base Address Upper 32-Bits
+#define UFS_HC_UTRLDBR_OFFSET 0x0058 // UTP Transfer Request List Door Bell Register
+#define UFS_HC_UTRLCLR_OFFSET 0x005c // UTP Transfer Request List CLear Register
+#define UFS_HC_UTRLRSR_OFFSET 0x0060 // UTP Transfer Request Run-Stop Register
+//
+// UTP Task Management Register Offsets
+//
+#define UFS_HC_UTMRLBA_OFFSET 0x0070 // UTP Task Management Request List Base Address
+#define UFS_HC_UTMRLBAU_OFFSET 0x0074 // UTP Task Management Request List Base Address Upper 32-Bits
+#define UFS_HC_UTMRLDBR_OFFSET 0x0078 // UTP Task Management Request List Door Bell Register
+#define UFS_HC_UTMRLCLR_OFFSET 0x007c // UTP Task Management Request List CLear Register
+#define UFS_HC_UTMRLRSR_OFFSET 0x0080 // UTP Task Management Run-Stop Register
+//
+// UIC Command Register Offsets
+//
+#define UFS_HC_UIC_CMD_OFFSET 0x0090 // UIC Command Register
+#define UFS_HC_UCMD_ARG1_OFFSET 0x0094 // UIC Command Argument 1
+#define UFS_HC_UCMD_ARG2_OFFSET 0x0098 // UIC Command Argument 2
+#define UFS_HC_UCMD_ARG3_OFFSET 0x009c // UIC Command Argument 3
+//
+// UMA Register Offsets
+//
+#define UFS_HC_UMA_OFFSET 0x00b0 // Reserved for Unified Memory Extension
+
+#define UFS_HC_HCE_EN BIT0
+#define UFS_HC_HCS_DP BIT0
+#define UFS_HC_HCS_UCRDY BIT3
+#define UFS_HC_IS_ULSS BIT8
+#define UFS_HC_IS_UCCS BIT10
+#define UFS_HC_CAP_64ADDR BIT24
+#define UFS_HC_CAP_NUTMRS (BIT16 | BIT17 | BIT18)
+#define UFS_HC_CAP_NUTRS (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)
+#define UFS_HC_UTMRLRSR BIT0
+#define UFS_HC_UTRLRSR BIT0
+
+//
+// The initial value of the OCS field of UTP TRD or TMRD descriptor
+// defined in JEDEC JESD223 specification
+//
+#define UFS_HC_TRD_OCS_INIT_VALUE 0x0F
+
+//
+// A maximum of length of 256KB is supported by PRDT entry
+//
+#define UFS_MAX_DATA_LEN_PER_PRD 0x40000
+
+#define UFS_STORAGE_COMMAND_TYPE 0x01
+
+#define UFS_REGULAR_COMMAND 0x00
+#define UFS_INTERRUPT_COMMAND 0x01
+
+#define UFS_LUN_0 0x00
+#define UFS_LUN_1 0x01
+#define UFS_LUN_2 0x02
+#define UFS_LUN_3 0x03
+#define UFS_LUN_4 0x04
+#define UFS_LUN_5 0x05
+#define UFS_LUN_6 0x06
+#define UFS_LUN_7 0x07
+#define UFS_WLUN_REPORT_LUNS 0x81
+#define UFS_WLUN_UFS_DEV 0xD0
+#define UFS_WLUN_BOOT 0xB0
+#define UFS_WLUN_RPMB 0xC4
+
+#pragma pack(1)
+
+//
+// UFSHCI 2.0 Spec Section 5.2.1 Offset 00h: CAP - Controller Capabilities
+//
+typedef struct {
+ UINT8 Nutrs:4; // Number of UTP Transfer Request Slots
+ UINT8 Rsvd1:4;
+
+ UINT8 NoRtt; // Number of outstanding READY TO TRANSFER (RTT) requests supported
+
+ UINT8 Nutmrs:3; // Number of UTP Task Management Request Slots
+ UINT8 Rsvd2:4;
+ UINT8 AutoHs:1; // Auto-Hibernation Support
+
+ UINT8 As64:1; // 64-bit addressing supported
+ UINT8 Oodds:1; // Out of order data delivery supported
+ UINT8 UicDmetms:1; // UIC DME_TEST_MODE command supported
+ UINT8 Ume:1; // Reserved for Unified Memory Extension
+ UINT8 Rsvd4:4;
+} UFS_HC_CAP;
+
+//
+// UFSHCI 2.0 Spec Section 5.2.2 Offset 08h: VER - UFS Version
+//
+typedef struct {
+ UINT8 Vs:4; // Version Suffix
+ UINT8 Mnr:4; // Minor version number
+
+ UINT8 Mjr; // Major version number
+
+ UINT16 Rsvd1;
+} UFS_HC_VER;
+
+//
+// UFSHCI 2.0 Spec Section 5.2.3 Offset 10h: HCPID - Host Controller Product ID
+//
+#define UFS_HC_PID UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.2.4 Offset 14h: HCMID - Host Controller Manufacturer ID
+//
+#define UFS_HC_MID UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.2.5 Offset 18h: AHIT - Auto-Hibernate Idle Timer
+//
+typedef struct {
+ UINT32 Ahitv:10; // Auto-Hibernate Idle Timer Value
+ UINT32 Ts:3; // Timer scale
+ UINT32 Rsvd1:19;
+} UFS_HC_AHIT;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.1 Offset 20h: IS - Interrupt Status
+//
+typedef struct {
+ UINT16 Utrcs:1; // UTP Transfer Request Completion Status
+ UINT16 Udepri:1; // UIC DME_ENDPOINT_RESET Indication
+ UINT16 Ue:1; // UIC Error
+ UINT16 Utms:1; // UIC Test Mode Status
+
+ UINT16 Upms:1; // UIC Power Mode Status
+ UINT16 Uhxs:1; // UIC Hibernate Exit Status
+ UINT16 Uhes:1; // UIC Hibernate Enter Status
+ UINT16 Ulls:1; // UIC Link Lost Status
+
+ UINT16 Ulss:1; // UIC Link Startup Status
+ UINT16 Utmrcs:1; // UTP Task Management Request Completion Status
+ UINT16 Uccs:1; // UIC Command Completion Status
+ UINT16 Dfes:1; // Device Fatal Error Status
+
+ UINT16 Utpes:1; // UTP Error Status
+ UINT16 Rsvd1:3;
+
+ UINT16 Hcfes:1; // Host Controller Fatal Error Status
+ UINT16 Sbfes:1; // System Bus Fatal Error Status
+ UINT16 Rsvd2:14;
+} UFS_HC_IS;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.2 Offset 24h: IE - Interrupt Enable
+//
+typedef struct {
+ UINT16 Utrce:1; // UTP Transfer Request Completion Enable
+ UINT16 Udeprie:1; // UIC DME_ENDPOINT_RESET Enable
+ UINT16 Uee:1; // UIC Error Enable
+ UINT16 Utmse:1; // UIC Test Mode Status Enable
+
+ UINT16 Upmse:1; // UIC Power Mode Status Enable
+ UINT16 Uhxse:1; // UIC Hibernate Exit Status Enable
+ UINT16 Uhese:1; // UIC Hibernate Enter Status Enable
+ UINT16 Ullse:1; // UIC Link Lost Status Enable
+
+ UINT16 Ulsse:1; // UIC Link Startup Status Enable
+ UINT16 Utmrce:1; // UTP Task Management Request Completion Enable
+ UINT16 Ucce:1; // UIC Command Completion Enable
+ UINT16 Dfee:1; // Device Fatal Error Enable
+
+ UINT16 Utpee:1; // UTP Error Enable
+ UINT16 Rsvd1:3;
+
+ UINT16 Hcfee:1; // Host Controller Fatal Error Enable
+ UINT16 Sbfee:1; // System Bus Fatal Error Enable
+ UINT16 Rsvd2:14;
+} UFS_HC_IE;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.3 Offset 30h: HCS - Host Controller Status
+//
+typedef struct {
+ UINT8 Dp:1; // Device Present
+ UINT8 UtrlRdy:1; // UTP Transfer Request List Ready
+ UINT8 UtmrlRdy:1; // UTP Task Management Request List Ready
+ UINT8 UcRdy:1; // UIC COMMAND Ready
+ UINT8 Rsvd1:4;
+
+ UINT8 Upmcrs:3; // UIC Power Mode Change Request Status
+ UINT8 Rsvd2:1; // UIC Hibernate Exit Status Enable
+ UINT8 Utpec:4; // UTP Error Code
+
+ UINT8 TtagUtpE; // Task Tag of UTP error
+ UINT8 TlunUtpE; // Target LUN of UTP error
+} UFS_HC_STATUS;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.4 Offset 34h: HCE - Host Controller Enable
+//
+typedef struct {
+ UINT32 Hce:1; // Host Controller Enable
+ UINT32 Rsvd1:31;
+} UFS_HC_ENABLE;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.5 Offset 38h: UECPA - Host UIC Error Code PHY Adapter Layer
+//
+typedef struct {
+ UINT32 Ec:5; // UIC PHY Adapter Layer Error Code
+ UINT32 Rsvd1:26;
+ UINT32 Err:1; // UIC PHY Adapter Layer Error
+} UFS_HC_UECPA;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.6 Offset 3ch: UECDL - Host UIC Error Code Data Link Layer
+//
+typedef struct {
+ UINT32 Ec:15; // UIC Data Link Layer Error Code
+ UINT32 Rsvd1:16;
+ UINT32 Err:1; // UIC Data Link Layer Error
+} UFS_HC_UECDL;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.7 Offset 40h: UECN - Host UIC Error Code Network Layer
+//
+typedef struct {
+ UINT32 Ec:3; // UIC Network Layer Error Code
+ UINT32 Rsvd1:28;
+ UINT32 Err:1; // UIC Network Layer Error
+} UFS_HC_UECN;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.8 Offset 44h: UECT - Host UIC Error Code Transport Layer
+//
+typedef struct {
+ UINT32 Ec:7; // UIC Transport Layer Error Code
+ UINT32 Rsvd1:24;
+ UINT32 Err:1; // UIC Transport Layer Error
+} UFS_HC_UECT;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.9 Offset 48h: UECDME - Host UIC Error Code
+//
+typedef struct {
+ UINT32 Ec:1; // UIC DME Error Code
+ UINT32 Rsvd1:30;
+ UINT32 Err:1; // UIC DME Error
+} UFS_HC_UECDME;
+
+//
+// UFSHCI 2.0 Spec Section 5.3.10 Offset 4Ch: UTRIACR - UTP Transfer Request Interrupt Aggregation Control Register
+//
+typedef struct {
+ UINT8 IaToVal; // Interrupt aggregation timeout value
+
+ UINT8 IacTh:5; // Interrupt aggregation counter threshold
+ UINT8 Rsvd1:3;
+
+ UINT8 Ctr:1; // Counter and Timer Reset
+ UINT8 Rsvd2:3;
+ UINT8 Iasb:1; // Interrupt aggregation status bit
+ UINT8 Rsvd3:3;
+
+ UINT8 IapwEn:1; // Interrupt aggregation parameter write enable
+ UINT8 Rsvd4:6;
+ UINT8 IaEn:1; // Interrupt Aggregation Enable/Disable
+} UFS_HC_UTRIACR;
+
+//
+// UFSHCI 2.0 Spec Section 5.4.1 Offset 50h: UTRLBA - UTP Transfer Request List Base Address
+//
+typedef struct {
+ UINT32 Rsvd1:10;
+ UINT32 UtrlBa:22; // UTP Transfer Request List Base Address
+} UFS_HC_UTRLBA;
+
+//
+// UFSHCI 2.0 Spec Section 5.4.2 Offset 54h: UTRLBAU - UTP Transfer Request List Base Address Upper 32-bits
+//
+#define UFS_HC_UTRLBAU UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.4.3 Offset 58h: UTRLDBR - UTP Transfer Request List Door Bell Register
+//
+#define UFS_HC_UTRLDBR UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.4.4 Offset 5Ch: UTRLCLR - UTP Transfer Request List CLear Register
+//
+#define UFS_HC_UTRLCLR UINT32
+
+#if 0
+//
+// UFSHCI 2.0 Spec Section 5.4.5 Offset 60h: UTRLRSR - UTP Transfer Request List Run Stop Register
+//
+typedef struct {
+ UINT32 UtrlRsr:1; // UTP Transfer Request List Run-Stop Register
+ UINT32 Rsvd1:31;
+} UFS_HC_UTRLRSR;
+#endif
+
+//
+// UFSHCI 2.0 Spec Section 5.5.1 Offset 70h: UTMRLBA - UTP Task Management Request List Base Address
+//
+typedef struct {
+ UINT32 Rsvd1:10;
+ UINT32 UtmrlBa:22; // UTP Task Management Request List Base Address
+} UFS_HC_UTMRLBA;
+
+//
+// UFSHCI 2.0 Spec Section 5.5.2 Offset 74h: UTMRLBAU - UTP Task Management Request List Base Address Upper 32-bits
+//
+#define UFS_HC_UTMRLBAU UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.5.3 Offset 78h: UTMRLDBR - UTP Task Management Request List Door Bell Register
+//
+typedef struct {
+ UINT32 UtmrlDbr:8; // UTP Task Management Request List Door bell Register
+ UINT32 Rsvd1:24;
+} UFS_HC_UTMRLDBR;
+
+//
+// UFSHCI 2.0 Spec Section 5.5.4 Offset 7Ch: UTMRLCLR - UTP Task Management Request List CLear Register
+//
+typedef struct {
+ UINT32 UtmrlClr:8; // UTP Task Management List Clear Register
+ UINT32 Rsvd1:24;
+} UFS_HC_UTMRLCLR;
+
+#if 0
+//
+// UFSHCI 2.0 Spec Section 5.5.5 Offset 80h: UTMRLRSR - UTP Task Management Request List Run Stop Register
+//
+typedef struct {
+ UINT32 UtmrlRsr:1; // UTP Task Management Request List Run-Stop Register
+ UINT32 Rsvd1:31;
+} UFS_HC_UTMRLRSR;
+#endif
+
+//
+// UFSHCI 2.0 Spec Section 5.6.1 Offset 90h: UICCMD - UIC Command
+//
+typedef struct {
+ UINT32 CmdOp:8; // Command Opcode
+ UINT32 Rsvd1:24;
+} UFS_HC_UICCMD;
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 94h: UICCMDARG1 - UIC Command Argument 1
+//
+#define UFS_HC_UICCMD_ARG1 UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 98h: UICCMDARG2 - UIC Command Argument 2
+//
+#define UFS_HC_UICCMD_ARG2 UINT32
+
+//
+// UFSHCI 2.0 Spec Section 5.6.2 Offset 9ch: UICCMDARG3 - UIC Command Argument 3
+//
+#define UFS_HC_UICCMD_ARG3 UINT32
+
+//
+// UIC command opcodes
+//
+typedef enum {
+ UfsUicDmeGet = 0x01,
+ UfsUicDmeSet = 0x02,
+ UfsUicDmePeerGet = 0x03,
+ UfsUicDmePeerSet = 0x04,
+ UfsUicDmePwrOn = 0x10,
+ UfsUicDmePwrOff = 0x11,
+ UfsUicDmeEnable = 0x12,
+ UfsUicDmeReset = 0x14,
+ UfsUicDmeEndpointReset = 0x15,
+ UfsUicDmeLinkStartup = 0x16,
+ UfsUicDmeHibernateEnter = 0x17,
+ UfsUicDmeHibernateExit = 0x18,
+ UfsUicDmeTestMode = 0x1A
+} UFS_UIC_OPCODE;
+
+//
+// UTP Transfer Request Descriptor
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:24;
+ UINT32 Int:1; /* Interrupt */
+ UINT32 Dd:2; /* Data Direction */
+ UINT32 Rsvd2:1;
+ UINT32 Ct:4; /* Command Type */
+
+ //
+ // DW1
+ //
+ UINT32 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT32 Ocs:8; /* Overall Command Status */
+ UINT32 Rsvd4:24;
+
+ //
+ // DW3
+ //
+ UINT32 Rsvd5;
+
+ //
+ // DW4
+ //
+ UINT32 Rsvd6:7;
+ UINT32 UcdBa:25; /* UTP Command Descriptor Base Address */
+
+ //
+ // DW5
+ //
+ UINT32 UcdBaU; /* UTP Command Descriptor Base Address Upper 32-bits */
+
+ //
+ // DW6
+ //
+ UINT16 RuL; /* Response UPIU Length */
+ UINT16 RuO; /* Response UPIU Offset */
+
+ //
+ // DW7
+ //
+ UINT16 PrdtL; /* PRDT Length */
+ UINT16 PrdtO; /* PRDT Offset */
+} UTP_TRD;
+
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:2;
+ UINT32 DbAddr:30; /* Data Base Address */
+
+ //
+ // DW1
+ //
+ UINT32 DbAddrU; /* Data Base Address Upper 32-bits */
+
+ //
+ // DW2
+ //
+ UINT32 Rsvd2;
+
+ //
+ // DW3
+ //
+ UINT32 DbCount:18; /* Data Byte Count */
+ UINT32 Rsvd3:14;
+} UTP_TR_PRD;
+
+//
+// UFS 2.0 Spec Section 10.5.3 - UTP Command UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x01*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 CmdSet:4; /* Command Set Type */
+ UINT8 Rsvd1:4;
+ UINT8 Rsvd2;
+ UINT8 Rsvd3;
+ UINT8 Rsvd4;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd5;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 ExpDataTranLen; /* Expected Data Transfer Length - Big Endian */
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Cdb[16];
+} UTP_COMMAND_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.4 - UTP Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x21*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 CmdSet:4; /* Command Set Type */
+ UINT8 Rsvd1:4;
+ UINT8 Rsvd2;
+ UINT8 Response; /* Response */
+ UINT8 Status; /* Status */
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 ResTranCount; /* Residual Transfer Count - Big Endian */
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Rsvd3[16];
+
+ //
+ // Data Segment - Sense Data
+ //
+ UINT16 SenseDataLen; /* Sense Data Length - Big Endian */
+ UINT8 SenseData[18]; /* Sense Data */
+} UTP_RESPONSE_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.5 - UTP Data-Out UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x02*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be sent out
+ //
+ //UINT8 Data[]; /* Data to be sent out, maximum is 65535 bytes */
+} UTP_DATA_OUT_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.6 - UTP Data-In UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x22*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be read
+ //
+ //UINT8 Data[]; /* Data to be read, maximum is 65535 bytes */
+} UTP_DATA_IN_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.7 - UTP Ready-To-Transfer UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x31*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd2;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 DataBufOffset; /* Data Buffer Offset - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 DataTranCount; /* Data Transfer Count - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd3[12];
+
+ //
+ // Data Segment - Data to be read
+ //
+ //UINT8 Data[]; /* Data to be read, maximum is 65535 bytes */
+} UTP_RDY_TO_TRAN_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.8 - UTP Task Management Request UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x04*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1;
+ UINT8 TskManFunc; /* Task Management Function */
+ UINT8 Rsvd2[2];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 InputParam1; /* Input Parameter 1 - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 InputParam2; /* Input Parameter 2 - Big Endian */
+
+ //
+ // DW5
+ //
+ UINT32 InputParam3; /* Input Parameter 3 - Big Endian */
+
+ //
+ // DW6 - DW7
+ //
+ UINT8 Rsvd4[8];
+} UTP_TM_REQ_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.9 - UTP Task Management Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x24*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[2];
+ UINT8 Resp; /* Response */
+ UINT8 Rsvd2;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT32 OutputParam1; /* Output Parameter 1 - Big Endian */
+
+ //
+ // DW4
+ //
+ UINT32 OutputParam2; /* Output Parameter 2 - Big Endian */
+
+ //
+ // DW5 - DW7
+ //
+ UINT8 Rsvd4[12];
+} UTP_TM_RESP_UPIU;
+
+//
+// UTP Task Management Request Descriptor
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT32 Rsvd1:24;
+ UINT32 Int:1; /* Interrupt */
+ UINT32 Rsvd2:7;
+
+ //
+ // DW1
+ //
+ UINT32 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT32 Ocs:8; /* Overall Command Status */
+ UINT32 Rsvd4:24;
+
+ //
+ // DW3
+ //
+ UINT32 Rsvd5;
+
+ //
+ // DW4 - DW11
+ //
+ UTP_TM_REQ_UPIU TmReq; /* Task Management Request UPIU */
+
+ //
+ // DW12 - DW19
+ //
+ UTP_TM_RESP_UPIU TmResp; /* Task Management Response UPIU */
+} UTP_TMRD;
+
+
+typedef struct {
+ UINT8 Opcode;
+ UINT8 DescId;
+ UINT8 Index;
+ UINT8 Selector;
+ UINT16 Rsvd1;
+ UINT16 Length;
+ UINT32 Value;
+ UINT32 Rsvd2;
+} UTP_UPIU_TSF;
+
+//
+// UFS 2.0 Spec Section 10.5.10 - UTP Query Request UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x16*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2;
+ UINT8 QueryFunc; /* Query Function */
+ UINT8 Rsvd3[2];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd4;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3 - 6
+ //
+ UTP_UPIU_TSF Tsf; /* Transaction Specific Fields */
+
+ //
+ // DW7
+ //
+ UINT8 Rsvd5[4];
+
+ //
+ // Data Segment - Data to be transferred
+ //
+ //UINT8 Data[]; /* Data to be transferred, maximum is 65535 bytes */
+} UTP_QUERY_REQ_UPIU;
+
+#define QUERY_FUNC_STD_READ_REQ 0x01
+#define QUERY_FUNC_STD_WRITE_REQ 0x81
+
+typedef enum {
+ UtpQueryFuncOpcodeNop = 0x00,
+ UtpQueryFuncOpcodeRdDesc = 0x01,
+ UtpQueryFuncOpcodeWrDesc = 0x02,
+ UtpQueryFuncOpcodeRdAttr = 0x03,
+ UtpQueryFuncOpcodeWrAttr = 0x04,
+ UtpQueryFuncOpcodeRdFlag = 0x05,
+ UtpQueryFuncOpcodeSetFlag = 0x06,
+ UtpQueryFuncOpcodeClrFlag = 0x07,
+ UtpQueryFuncOpcodeTogFlag = 0x08
+} UTP_QUERY_FUNC_OPCODE;
+
+//
+// UFS 2.0 Spec Section 10.5.11 - UTP Query Response UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x36*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2;
+ UINT8 QueryFunc; /* Query Function */
+ UINT8 QueryResp; /* Query Response */
+ UINT8 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian */
+
+ //
+ // DW3 - 6
+ //
+ UTP_UPIU_TSF Tsf; /* Transaction Specific Fields */
+
+ //
+ // DW7
+ //
+ UINT8 Rsvd4[4];
+
+ //
+ // Data Segment - Data to be transferred
+ //
+ //UINT8 Data[]; /* Data to be transferred, maximum is 65535 bytes */
+} UTP_QUERY_RESP_UPIU;
+
+typedef enum {
+ UfsUtpQueryResponseSuccess = 0x00,
+ UfsUtpQueryResponseParamNotReadable = 0xF6,
+ UfsUtpQueryResponseParamNotWriteable = 0xF7,
+ UfsUtpQueryResponseParamAlreadyWritten = 0xF8,
+ UfsUtpQueryResponseInvalidLen = 0xF9,
+ UfsUtpQueryResponseInvalidVal = 0xFA,
+ UfsUtpQueryResponseInvalidSelector = 0xFB,
+ UfsUtpQueryResponseInvalidIndex = 0xFC,
+ UfsUtpQueryResponseInvalidIdn = 0xFD,
+ UfsUtpQueryResponseInvalidOpc = 0xFE,
+ UfsUtpQueryResponseGeneralFailure = 0xFF
+} UTP_QUERY_RESP_CODE;
+
+//
+// UFS 2.0 Spec Section 10.5.12 - UTP Reject UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x3F*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd1[2];
+ UINT8 Response; /* Response - 0x01 */
+ UINT8 Rsvd2;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information - 0x00 */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3
+ //
+ UINT8 HdrSts; /* Basic Header Status */
+ UINT8 Rsvd3;
+ UINT8 E2ESts; /* End-to-End Status */
+ UINT8 Rsvd4;
+
+ //
+ // DW4 - DW7
+ //
+ UINT8 Rsvd5[16];
+} UTP_REJ_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.13 - UTP NOP OUT UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x00*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2[4];
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 Rsvd3;
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3 - DW7
+ //
+ UINT8 Rsvd4[20];
+} UTP_NOP_OUT_UPIU;
+
+//
+// UFS 2.0 Spec Section 10.5.14 - UTP NOP IN UPIU
+//
+typedef struct {
+ //
+ // DW0
+ //
+ UINT8 TransCode:6; /* Transaction Type - 0x20*/
+ UINT8 Dd:1;
+ UINT8 Hd:1;
+ UINT8 Flags;
+ UINT8 Rsvd1;
+ UINT8 TaskTag; /* Task Tag */
+
+ //
+ // DW1
+ //
+ UINT8 Rsvd2[2];
+ UINT8 Resp; /* Response - 0x00 */
+ UINT8 Rsvd3;
+
+ //
+ // DW2
+ //
+ UINT8 EhsLen; /* Total EHS Length - 0x00 */
+ UINT8 DevInfo; /* Device Information - 0x00 */
+ UINT16 DataSegLen; /* Data Segment Length - Big Endian - 0x0000 */
+
+ //
+ // DW3 - DW7
+ //
+ UINT8 Rsvd4[20];
+} UTP_NOP_IN_UPIU;
+
+//
+// UFS Descriptors
+//
+typedef enum {
+ UfsDeviceDesc = 0x00,
+ UfsConfigDesc = 0x01,
+ UfsUnitDesc = 0x02,
+ UfsInterConnDesc = 0x04,
+ UfsStringDesc = 0x05,
+ UfsGeometryDesc = 0x07,
+ UfsPowerDesc = 0x08
+} UFS_DESC_IDN;
+
+//
+// UFS 2.0 Spec Section 14.1.6.2 - Device Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 Device;
+ UINT8 DevClass;
+ UINT8 DevSubClass;
+ UINT8 Protocol;
+ UINT8 NumLun;
+ UINT8 NumWLun;
+ UINT8 BootEn;
+ UINT8 DescAccessEn;
+ UINT8 InitPowerMode;
+ UINT8 HighPriorityLun;
+ UINT8 SecureRemovalType;
+ UINT8 SecurityLun;
+ UINT8 BgOpsTermLat;
+ UINT8 InitActiveIccLevel;
+ UINT16 SpecVersion;
+ UINT16 ManufactureDate;
+ UINT8 ManufacturerName;
+ UINT8 ProductName;
+ UINT8 SerialName;
+ UINT8 OemId;
+ UINT16 ManufacturerId;
+ UINT8 Ud0BaseOffset;
+ UINT8 Ud0ConfParamLen;
+ UINT8 DevRttCap;
+ UINT16 PeriodicRtcUpdate;
+ UINT8 Rsvd1[17];
+ UINT8 Rsvd2[16];
+} UFS_DEV_DESC;
+
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 Rsvd1;
+ UINT8 BootEn;
+ UINT8 DescAccessEn;
+ UINT8 InitPowerMode;
+ UINT8 HighPriorityLun;
+ UINT8 SecureRemovalType;
+ UINT8 InitActiveIccLevel;
+ UINT16 PeriodicRtcUpdate;
+ UINT8 Rsvd2[5];
+} UFS_CONFIG_DESC_GEN_HEADER;
+
+typedef struct {
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 MemType;
+ UINT32 NumAllocUnits;
+ UINT8 DataReliability;
+ UINT8 LogicBlkSize;
+ UINT8 ProvisionType;
+ UINT16 CtxCap;
+ UINT8 Rsvd1[3];
+} UFS_UNIT_DESC_CONFIG_PARAMS;
+
+//
+// UFS 2.0 Spec Section 14.1.6.3 - Configuration Descriptor
+//
+typedef struct {
+ UFS_CONFIG_DESC_GEN_HEADER Header;
+ UFS_UNIT_DESC_CONFIG_PARAMS UnitDescConfParams[8];
+} UFS_CONFIG_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.4 - Geometry Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 MediaTech;
+ UINT8 Rsvd1;
+ UINT64 TotalRawDevCapacity;
+ UINT8 Rsvd2;
+ UINT32 SegSize;
+ UINT8 AllocUnitSize;
+ UINT8 MinAddrBlkSize;
+ UINT8 OptReadBlkSize;
+ UINT8 OptWriteBlkSize;
+ UINT8 MaxInBufSize;
+ UINT8 MaxOutBufSize;
+ UINT8 RpmbRwSize;
+ UINT8 Rsvd3;
+ UINT8 DataOrder;
+ UINT8 MaxCtxIdNum;
+ UINT8 SysDataTagUnitSize;
+ UINT8 SysDataResUnitSize;
+ UINT8 SupSecRemovalTypes;
+ UINT16 SupMemTypes;
+ UINT32 SysCodeMaxNumAllocUnits;
+ UINT16 SupCodeCapAdjFac;
+ UINT32 NonPersMaxNumAllocUnits;
+ UINT16 NonPersCapAdjFac;
+ UINT32 Enhance1MaxNumAllocUnits;
+ UINT16 Enhance1CapAdjFac;
+ UINT32 Enhance2MaxNumAllocUnits;
+ UINT16 Enhance2CapAdjFac;
+ UINT32 Enhance3MaxNumAllocUnits;
+ UINT16 Enhance3CapAdjFac;
+ UINT32 Enhance4MaxNumAllocUnits;
+ UINT16 Enhance4CapAdjFac;
+} UFS_GEOMETRY_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.5 - Unit Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 UnitIdx;
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 LunQueueDep;
+ UINT8 Rsvd1;
+ UINT8 MemType;
+ UINT8 DataReliability;
+ UINT8 LogicBlkSize;
+ UINT64 LogicBlkCount;
+ UINT32 EraseBlkSize;
+ UINT8 ProvisionType;
+ UINT64 PhyMemResCount;
+ UINT16 CtxCap;
+ UINT8 LargeUnitGranularity;
+} UFS_UNIT_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.6 - RPMB Unit Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 UnitIdx;
+ UINT8 LunEn;
+ UINT8 BootLunId;
+ UINT8 LunWriteProt;
+ UINT8 LunQueueDep;
+ UINT8 Rsvd1;
+ UINT8 MemType;
+ UINT8 Rsvd2;
+ UINT8 LogicBlkSize;
+ UINT64 LogicBlkCount;
+ UINT32 EraseBlkSize;
+ UINT8 ProvisionType;
+ UINT64 PhyMemResCount;
+ UINT8 Rsvd3[3];
+} UFS_RPMB_UNIT_DESC;
+
+typedef struct {
+ UINT16 Value:10;
+ UINT16 Rsvd1:4;
+ UINT16 Unit:2;
+} UFS_POWER_PARAM_ELEMENT;
+
+//
+// UFS 2.0 Spec Section 14.1.6.7 - Power Parameter Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVcc[16];
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVccQ[16];
+ UFS_POWER_PARAM_ELEMENT ActiveIccLevelVccQ2[16];
+} UFS_POWER_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.8 - InterConnect Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT16 UniProVer;
+ UINT16 MphyVer;
+} UFS_INTER_CONNECT_DESC;
+
+//
+// UFS 2.0 Spec Section 14.1.6.9 - 14.1.6.12 - String Descriptor
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ CHAR16 Unicode[126];
+} UFS_STRING_DESC;
+
+//
+// UFS 2.0 Spec Section 14.2 - Flags
+//
+typedef enum {
+ UfsFlagDevInit = 0x01,
+ UfsFlagPermWpEn = 0x02,
+ UfsFlagPowerOnWpEn = 0x03,
+ UfsFlagBgOpsEn = 0x04,
+ UfsFlagPurgeEn = 0x06,
+ UfsFlagPhyResRemoval = 0x08,
+ UfsFlagBusyRtc = 0x09,
+ UfsFlagPermDisFwUpdate = 0x0B
+} UFS_FLAGS_IDN;
+
+//
+// UFS 2.0 Spec Section 14.2 - Attributes
+//
+typedef enum {
+ UfsAttrBootLunEn = 0x00,
+ UfsAttrCurPowerMode = 0x02,
+ UfsAttrActiveIccLevel = 0x03,
+ UfsAttrOutOfOrderDataEn = 0x04,
+ UfsAttrBgOpStatus = 0x05,
+ UfsAttrPurgeStatus = 0x06,
+ UfsAttrMaxDataInSize = 0x07,
+ UfsAttrMaxDataOutSize = 0x08,
+ UfsAttrDynCapNeeded = 0x09,
+ UfsAttrRefClkFreq = 0x0a,
+ UfsAttrConfigDescLock = 0x0b,
+ UfsAttrMaxNumOfRtt = 0x0c,
+ UfsAttrExceptionEvtCtrl = 0x0d,
+ UfsAttrExceptionEvtSts = 0x0e,
+ UfsAttrSecondsPassed = 0x0f,
+ UfsAttrContextConf = 0x10,
+ UfsAttrCorrPrgBlkNum = 0x11
+} UFS_ATTR_IDN;
+
+typedef enum {
+ UfsNoData = 0,
+ UfsDataOut = 1,
+ UfsDataIn = 2,
+ UfsDdReserved
+} UFS_DATA_DIRECTION;
+
+
+#pragma pack()
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
new file mode 100644
index 000000000..2b1ca20a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
@@ -0,0 +1,394 @@
+/** @file
+BOT Transportation implementation.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+#include "PeiUsbLib.h"
+
+/**
+ Reset the given usb device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+
+ @retval EFI_INVALID_PARAMETER Can not get usb io ppi.
+ @retval EFI_SUCCESS Failed to reset the given usb device.
+
+**/
+EFI_STATUS
+BotRecoveryReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 Timeout;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ EFI_STATUS Status;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ if (UsbIoPpi == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ DevReq.RequestType = 0x21;
+ DevReq.Request = 0xFF;
+ DevReq.Value = 0;
+ DevReq.Index = 0;
+ DevReq.Length = 0;
+
+ Timeout = 3000;
+
+ Status = UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0
+ );
+
+ //
+ // clear bulk in endpoint stall feature
+ //
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+
+ //
+ // clear bulk out endpoint stall feature
+ //
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+
+ return Status;
+}
+
+/**
+ Send the command to the device using Bulk-Out endpoint.
+
+ This function sends the command to the device using Bulk-Out endpoint.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Command phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param Command The command to transfer to device.
+ @param CommandSize The length of the command.
+ @param DataTransferLength The expected length of the data.
+ @param Direction The direction of the data.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to send the command to device.
+ @retval EFI_SUCCESS Failed to send the command to device.
+
+**/
+EFI_STATUS
+BotCommandPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN VOID *Command,
+ IN UINT8 CommandSize,
+ IN UINT32 DataTransferLength,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 Timeout
+ )
+{
+ CBW Cbw;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINTN DataSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ ZeroMem (&Cbw, sizeof (CBW));
+
+ //
+ // Fill the command block, detailed see BOT spec
+ //
+ Cbw.Signature = CBWSIG;
+ Cbw.Tag = 0x01;
+ Cbw.DataTransferLength = DataTransferLength;
+ Cbw.Flags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);
+ Cbw.Lun = 0;
+ Cbw.CmdLen = CommandSize;
+
+ CopyMem (Cbw.CmdBlock, Command, CommandSize);
+
+ DataSize = sizeof (CBW);
+
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ (PeiBotDev->BulkOutEndpoint)->EndpointAddress,
+ (UINT8 *) &Cbw,
+ &DataSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Command phase fail, we need to recovery reset this device
+ //
+ BotRecoveryReset (PeiServices, PeiBotDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer the data between the device and host.
+
+ This function transfers the data between the device and host.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Data phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param DataSize The length of the data.
+ @param DataBuffer The pointer to the data.
+ @param Direction The direction of the data.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to send the data to device.
+ @retval EFI_SUCCESS Failed to send the data to device.
+
+**/
+EFI_STATUS
+BotDataPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN UINT32 *DataSize,
+ IN OUT VOID *DataBuffer,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 Timeout
+ )
+{
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ UINTN Remain;
+ UINTN Increment;
+ UINT32 MaxPacketLen;
+ UINT8 *BufferPtr;
+ UINTN TransferredSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ Remain = *DataSize;
+ BufferPtr = (UINT8 *) DataBuffer;
+ TransferredSize = 0;
+
+ //
+ // retrieve the max packet length of the given endpoint
+ //
+ if (Direction == EfiUsbDataIn) {
+ MaxPacketLen = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+ } else {
+ MaxPacketLen = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
+ }
+
+ while (Remain > 0) {
+ //
+ // Using 15 packets to avoid Bitstuff error
+ //
+ if (Remain > 16 * MaxPacketLen) {
+ Increment = 16 * MaxPacketLen;
+ } else {
+ Increment = Remain;
+ }
+
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ EndpointAddr,
+ BufferPtr,
+ &Increment,
+ Timeout
+ );
+
+ TransferredSize += Increment;
+
+ if (EFI_ERROR (Status)) {
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+ return Status;
+ }
+
+ BufferPtr += Increment;
+ Remain -= Increment;
+ }
+
+ *DataSize = (UINT32) TransferredSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the command execution status from device.
+
+ This function gets the command execution status from device.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Status phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param TransferStatus The status of the transaction.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.
+ @retval EFI_SUCCESS Failed to get the status of device.
+
+**/
+EFI_STATUS
+BotStatusPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ OUT UINT8 *TransferStatus,
+ IN UINT16 Timeout
+ )
+{
+ CSW Csw;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ UINTN DataSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ ZeroMem (&Csw, sizeof (CSW));
+
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+
+ DataSize = sizeof (CSW);
+
+ //
+ // Get the status field from bulk transfer
+ //
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ EndpointAddr,
+ &Csw,
+ &DataSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Csw.Signature == CSWSIG) {
+ *TransferStatus = Csw.Status;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ATAPI command using BOT protocol.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param Command The command to be sent to ATAPI device.
+ @param CommandSize The length of the data to be sent.
+ @param DataBuffer The pointer to the data.
+ @param BufferLength The length of the data.
+ @param Direction The direction of the data.
+ @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.
+ @retval EFI_SUCCESS Failed to get the status of device.
+
+**/
+EFI_STATUS
+PeiAtapiCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN VOID *Command,
+ IN UINT8 CommandSize,
+ IN VOID *DataBuffer,
+ IN UINT32 BufferLength,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 TimeOutInMilliSeconds
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS BotDataStatus;
+ UINT8 TransferStatus;
+ UINT32 BufferSize;
+
+ BotDataStatus = EFI_SUCCESS;
+ //
+ // First send ATAPI command through Bot
+ //
+ Status = BotCommandPhase (
+ PeiServices,
+ PeiBotDev,
+ Command,
+ CommandSize,
+ BufferLength,
+ Direction,
+ TimeOutInMilliSeconds
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Send/Get Data if there is a Data Stage
+ //
+ switch (Direction) {
+ case EfiUsbDataIn:
+ case EfiUsbDataOut:
+ BufferSize = BufferLength;
+
+ BotDataStatus = BotDataPhase (
+ PeiServices,
+ PeiBotDev,
+ &BufferSize,
+ DataBuffer,
+ Direction,
+ TimeOutInMilliSeconds
+ );
+ break;
+
+ case EfiUsbNoData:
+ break;
+ }
+ //
+ // Status Phase
+ //
+ Status = BotStatusPhase (
+ PeiServices,
+ PeiBotDev,
+ &TransferStatus,
+ TimeOutInMilliSeconds
+ );
+ if (EFI_ERROR (Status)) {
+ BotRecoveryReset (PeiServices, PeiBotDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (TransferStatus == 0x01) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return BotDataStatus;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h
new file mode 100644
index 000000000..a4ad759b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h
@@ -0,0 +1,217 @@
+/** @file
+BOT Transportation implementation.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_BOT_PEIM_H_
+#define _PEI_BOT_PEIM_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/BlockIo.h>
+
+//#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <IndustryStandard/Atapi.h>
+
+#pragma pack(1)
+//
+// Bulk Only device protocol
+//
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataTransferLength;
+ UINT8 Flags;
+ UINT8 Lun;
+ UINT8 CmdLen;
+ UINT8 CmdBlock[16];
+} CBW;
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataResidue;
+ UINT8 Status;
+} CSW;
+
+#pragma pack()
+//
+// Status code, see Usb Bot device spec
+//
+#define CSWSIG 0x53425355
+#define CBWSIG 0x43425355
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will
+ return INQUIRY data of the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Inquiry command completes successfully.
+ @retval EFI_DEVICE_ERROR Inquiry command failed.
+
+**/
+EFI_STATUS
+PeiUsbInquiry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ );
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS TestUnit command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
+
+**/
+EFI_STATUS
+PeiUsbTestUnitReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ );
+
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param SenseCounts Length of sense buffer.
+ @param SenseKeyBuffer Pointer to sense buffer.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRequestSense (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ OUT UINTN *SenseCounts,
+ IN UINT8 *SenseKeyBuffer
+ );
+
+/**
+ 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.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ );
+
+/**
+ Sends out ATAPI Read Format Capacity Data Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadFormattedCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ );
+
+/**
+ Execute Read(10) ATAPI command on a specific SCSI target.
+
+ Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param Buffer The pointer to data buffer.
+ @param Lba The start logic block address of reading.
+ @param NumberOfBlocks The block number of reading.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRead10 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ );
+
+/**
+ Check if there is media according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE No media
+ @retval FALSE Media exists
+
+**/
+BOOLEAN
+IsNoMedia (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check if there is media error according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE Media error
+ @retval FALSE No media error
+
+**/
+BOOLEAN
+IsMediaError (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+/**
+ Check if media is changed according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE There is media change event.
+ @retval FALSE media is NOT changed.
+
+**/
+BOOLEAN
+IsMediaChange (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
new file mode 100644
index 000000000..41f782a78
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
@@ -0,0 +1,647 @@
+/** @file
+Pei USB ATAPI command implementations.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+
+#define MAXSENSEKEY 5
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will
+ return INQUIRY data of the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Inquiry command completes successfully.
+ @retval EFI_DEVICE_ERROR Inquiry command failed.
+
+**/
+EFI_STATUS
+PeiUsbInquiry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ ATAPI_INQUIRY_DATA Idata;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
+
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = 36;
+
+ //
+ // Send scsi INQUIRY command packet.
+ // According to SCSI Primary Commands-2 spec, host only needs to
+ // retrieve the first 36 bytes for standard INQUIRY data.
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ &Idata,
+ 36,
+ EfiUsbDataIn,
+ 2000
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Idata.peripheral_type & 0x1f) == 0x05) {
+ PeiBotDevice->DeviceType = USBCDROM;
+ PeiBotDevice->Media.BlockSize = 0x800;
+ PeiBotDevice->Media2.ReadOnly = TRUE;
+ PeiBotDevice->Media2.RemovableMedia = TRUE;
+ PeiBotDevice->Media2.BlockSize = 0x800;
+ } else {
+ PeiBotDevice->DeviceType = USBFLOPPY;
+ PeiBotDevice->Media.BlockSize = 0x200;
+ PeiBotDevice->Media2.ReadOnly = FALSE;
+ PeiBotDevice->Media2.RemovableMedia = TRUE;
+ PeiBotDevice->Media2.BlockSize = 0x200;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS TestUnit command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
+
+**/
+EFI_STATUS
+PeiUsbTestUnitReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ NULL,
+ 0,
+ EfiUsbNoData,
+ 2000
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param SenseCounts Length of sense buffer.
+ @param SenseKeyBuffer Pointer to sense buffer.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRequestSense (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ OUT UINTN *SenseCounts,
+ IN UINT8 *SenseKeyBuffer
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ UINT8 *Ptr;
+ BOOLEAN SenseReq;
+ ATAPI_REQUEST_SENSE_DATA *Sense;
+
+ *SenseCounts = 0;
+
+ //
+ // 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);
+
+ Ptr = SenseKeyBuffer;
+
+ SenseReq = TRUE;
+
+ //
+ // request sense data from device continuously
+ // until no sense data exists in the device.
+ //
+ while (SenseReq) {
+ Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense
+ // data form device.
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) Ptr,
+ sizeof (ATAPI_REQUEST_SENSE_DATA),
+ EfiUsbDataIn,
+ 2000
+ );
+
+ //
+ // failed to get Sense data
+ //
+ if (EFI_ERROR (Status)) {
+ if (*SenseCounts == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Sense->sense_key != ATA_SK_NO_SENSE) {
+
+ Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);
+ //
+ // Ptr is byte based pointer
+ //
+ (*SenseCounts)++;
+
+ if (*SenseCounts == MAXSENSEKEY) {
+ break;
+ }
+
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ SenseReq = FALSE;
+ }
+ }
+
+ 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.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ_CAPACITY_DATA Data;
+ UINT32 LastBlock;
+
+ ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) &Data,
+ sizeof (ATAPI_READ_CAPACITY_DATA),
+ EfiUsbDataIn,
+ 2000
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ LastBlock = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
+
+ if (LastBlock == 0xFFFFFFFF) {
+ DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
+ }
+
+ PeiBotDevice->Media.LastBlock = LastBlock;
+ PeiBotDevice->Media.MediaPresent = TRUE;
+
+ PeiBotDevice->Media2.LastBlock = LastBlock;
+ PeiBotDevice->Media2.MediaPresent = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Read Format Capacity Data Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadFormattedCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
+ UINT32 LastBlock;
+
+ ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) &FormatData,
+ sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
+ EfiUsbDataIn,
+ 2000
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (FormatData.DesCode == 3) {
+ //
+ // Media is not present
+ //
+ PeiBotDevice->Media.MediaPresent = FALSE;
+ PeiBotDevice->Media.LastBlock = 0;
+ PeiBotDevice->Media2.MediaPresent = FALSE;
+ PeiBotDevice->Media2.LastBlock = 0;
+
+ } else {
+ LastBlock = ((UINT32) FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
+ if (LastBlock == 0xFFFFFFFF) {
+ DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
+ }
+
+ PeiBotDevice->Media.LastBlock = LastBlock;
+
+ PeiBotDevice->Media.LastBlock--;
+
+ PeiBotDevice->Media.MediaPresent = TRUE;
+
+ PeiBotDevice->Media2.MediaPresent = TRUE;
+ PeiBotDevice->Media2.LastBlock = PeiBotDevice->Media.LastBlock;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute Read(10) ATAPI command on a specific SCSI target.
+
+ Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param Buffer The pointer to data buffer.
+ @param Lba The start logic block address of reading.
+ @param NumberOfBlocks The block number of reading.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRead10 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ10_CMD *Read10Packet;
+ UINT16 MaxBlock;
+ UINT16 BlocksRemaining;
+ UINT16 SectorCount;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ VOID *PtrBuffer;
+ EFI_STATUS Status;
+ UINT16 TimeOut;
+
+ //
+ // prepare command packet for the Inquiry Packet Command.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+ Lba32 = (UINT32) Lba;
+ PtrBuffer = Buffer;
+
+ BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;
+
+ MaxBlock = (UINT16) (65535 / BlockSize);
+ BlocksRemaining = (UINT16) NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+
+ SectorCount = 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;
+
+ TimeOut = (UINT16) (SectorCount * 2000);
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) PtrBuffer,
+ ByteCount,
+ EfiUsbDataIn,
+ TimeOut
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
+ }
+
+ return Status;
+}
+
+/**
+ Check if there is media according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE No media
+ @retval FALSE Media exists
+
+**/
+BOOLEAN
+IsNoMedia (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN NoMedia;
+
+ NoMedia = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ //
+ // if no media, fill IdeDev parameter with specific info.
+ //
+ case ATA_ASC_NO_MEDIA:
+ NoMedia = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return NoMedia;
+}
+
+/**
+ Check if there is media error according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE Media error
+ @retval FALSE No media error
+
+**/
+BOOLEAN
+IsMediaError (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN Error;
+
+ SensePtr = SenseData;
+ Error = FALSE;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+ //
+ // Medium error case
+ //
+ case ATA_SK_MEDIUM_ERROR:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_ERR1:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR2:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR3:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR4:
+ Error = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ //
+ // Medium upside-down case
+ //
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:
+ Error = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return Error;
+}
+
+/**
+ Check if media is changed according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE There is media change event.
+ @retval FALSE media is NOT changed.
+
+**/
+BOOLEAN
+IsMediaChange (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN MediaChange;
+
+ MediaChange = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // catch media change sense key and addition sense data
+ //
+ switch (SensePtr->sense_key) {
+ case ATA_SK_UNIT_ATTENTION:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_CHANGE:
+ MediaChange = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return MediaChange;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c
new file mode 100644
index 000000000..292682a2e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c
@@ -0,0 +1,134 @@
+/** @file
+Common Library for PEI USB.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbPeim.h"
+#include "PeiUsbLib.h"
+
+
+/**
+ Clear a given usb feature.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.
+ @param Value Request Value.
+ @param Target Request Index.
+
+ @retval EFI_SUCCESS Usb feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbClearDeviceFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN EFI_USB_RECIPIENT Recipient,
+ IN UINT16 Value,
+ IN UINT16 Target
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+
+ ASSERT (UsbIoPpi != NULL);
+
+ switch (Recipient) {
+ case EfiUsbDevice:
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;
+ break;
+
+ case EfiUsbInterface:
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;
+ break;
+
+ case EfiUsbEndpoint:
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;
+ break;
+ }
+
+ DevReq.Request = USB_DEV_CLEAR_FEATURE;
+ DevReq.Value = Value;
+ DevReq.Index = Target;
+ DevReq.Length = 0;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+
+/**
+ Clear Endpoint Halt.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param EndpointAddress The endpoint address.
+
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbClearEndpointHalt (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 EndpointAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
+ UINT8 EndpointIndex;
+
+
+ //
+ // Check its interface
+ //
+ Status = UsbIoPpi->UsbGetInterfaceDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ &InterfaceDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ for (EndpointIndex = 0; EndpointIndex < InterfaceDesc->NumEndpoints; EndpointIndex++) {
+ Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EndpointDescriptor->EndpointAddress == EndpointAddress) {
+ break;
+ }
+ }
+
+ if (EndpointIndex == InterfaceDesc->NumEndpoints) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PeiUsbClearDeviceFeature (
+ PeiServices,
+ UsbIoPpi,
+ EfiUsbEndpoint,
+ EfiUsbEndpointHalt,
+ EndpointAddress
+ );
+
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h
new file mode 100644
index 000000000..e06e2533a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h
@@ -0,0 +1,143 @@
+/** @file
+Common Library for PEI USB.
+
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_LIB_H_
+#define _PEI_USB_LIB_H_
+//
+// Standard device request and request type
+// By [Spec-USB20/Chapter-9.4]
+//
+#define USB_DEV_GET_STATUS 0x00
+#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device
+#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface
+#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint
+
+#define USB_DEV_CLEAR_FEATURE 0x01
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint
+
+#define USB_DEV_SET_FEATURE 0x03
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint
+
+#define USB_DEV_SET_ADDRESS 0x05
+#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00
+
+#define USB_DEV_GET_DESCRIPTOR 0x06
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80
+
+#define USB_DEV_SET_DESCRIPTOR 0x07
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00
+
+#define USB_DEV_GET_CONFIGURATION 0x08
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80
+
+#define USB_DEV_SET_CONFIGURATION 0x09
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00
+
+#define USB_DEV_GET_INTERFACE 0x0A
+#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81
+
+#define USB_DEV_SET_INTERFACE 0x0B
+#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01
+
+#define USB_DEV_SYNCH_FRAME 0x0C
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82
+
+//
+// USB Descriptor types
+//
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_HUB 0x29
+#define USB_DT_HID 0x21
+
+//
+// USB request type
+//
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+//
+// USB request targer device
+//
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+typedef enum {
+ EfiUsbEndpointHalt,
+ EfiUsbDeviceRemoteWakeup
+} EFI_USB_STANDARD_FEATURE_SELECTOR;
+
+//
+// Usb Data recipient type
+//
+typedef enum {
+ EfiUsbDevice,
+ EfiUsbInterface,
+ EfiUsbEndpoint
+} EFI_USB_RECIPIENT;
+
+
+/**
+ Clear a given usb feature.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.
+ @param Value Request Value.
+ @param Target Request Index.
+
+ @retval EFI_SUCCESS Usb feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbClearDeviceFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN EFI_USB_RECIPIENT Recipient,
+ IN UINT16 Value,
+ IN UINT16 Target
+ );
+
+
+/**
+ Clear Endpoint Halt.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param EndpointAddress The endpoint address.
+
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbClearEndpointHalt (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 EndpointAddress
+ );
+
+
+
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf
new file mode 100644
index 000000000..de2df5fe3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf
@@ -0,0 +1,62 @@
+## @file
+# The Usb mass storage device Peim driver is used to support recovery from USB device.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbBotPei
+ MODULE_UNI_FILE = UsbBotPei.uni
+ FILE_GUID = 8401A046-6F70-4505-8471-7015B40355E3
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimInitializeUsbBot
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PeiUsbLib.c
+ PeiAtapi.c
+ BotPeim.c
+ UsbBotPeim.c
+ UsbPeim.h
+ UsbBotPeim.h
+ PeiUsbLib.h
+ BotPeim.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue ## CONSUMES
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gPeiUsbIoPpiGuid
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbIoPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbBotPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.uni
new file mode 100644
index 000000000..f1b4316ba
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The Usb mass storage device Peim driver is used to support recovery from USB device.
+//
+// The USB mass storage device PEIM driver is used to support recovery from USB devices.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Used to support recovery from USB devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The USB mass storage device PEIM driver is used to support recovery from USB devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeiExtra.uni
new file mode 100644
index 000000000..58aadda2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbBotPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c
new file mode 100644
index 000000000..e11062688
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c
@@ -0,0 +1,915 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+
+//
+// Global function
+//
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiUsbIoPpiGuid,
+ NotifyOnUsbIoPpi
+};
+
+EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi = {
+ BotGetNumberOfBlockDevices,
+ BotGetMediaInfo,
+ BotReadBlocks
+};
+
+EFI_PEI_RECOVERY_BLOCK_IO2_PPI mRecoveryBlkIo2Ppi = {
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
+ BotGetNumberOfBlockDevices2,
+ BotGetMediaInfo2,
+ BotReadBlocks2
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList[2] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+ }
+};
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM.
+ @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+PeiBotDetectMedia (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev
+ );
+
+/**
+ Initializes the Usb Bot.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Usb bot driver is successfully initialized.
+ @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeUsbBot (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN UsbIoPpiInstance;
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
+ PEI_USB_IO_PPI *UsbIoPpi;
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // locate all usb io PPIs
+ //
+ for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) {
+
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbIoPpiGuid,
+ UsbIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &UsbIoPpi
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ //
+ // Register a notify function
+ //
+ return PeiServicesNotifyPpi (&mNotifyList);
+}
+
+/**
+ UsbIo installation notification function.
+
+ This function finds out all the current USB IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDesc Address of the notification descriptor data structure.
+ @param InvokePpi Address of the PPI that was invoked.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyOnUsbIoPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *InvokePpi
+ )
+{
+ PEI_USB_IO_PPI *UsbIoPpi;
+
+ UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi;
+
+ InitUsbBot (PeiServices, UsbIoPpi);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the usb bot device.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM.
+ @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS The usb bot device is initialized successfully.
+ @retval Other Failed to initialize media.
+
+**/
+EFI_STATUS
+InitUsbBot (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi
+ )
+{
+ PEI_BOT_DEVICE *PeiBotDevice;
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;
+ UINTN MemPages;
+ EFI_PHYSICAL_ADDRESS AllocateAddress;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc;
+ UINT8 Index;
+
+ //
+ // Check its interface
+ //
+ Status = UsbIoPpi->UsbGetInterfaceDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ &InterfaceDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check if it is the BOT device we support
+ //
+ if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) {
+
+ return EFI_NOT_FOUND;
+ }
+
+ MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiBotDevice = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress);
+
+ PeiBotDevice->Signature = PEI_BOT_DEVICE_SIGNATURE;
+ PeiBotDevice->UsbIoPpi = UsbIoPpi;
+ PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress;
+ PeiBotDevice->BotInterface = InterfaceDesc;
+
+ //
+ // Default value
+ //
+ PeiBotDevice->Media.DeviceType = UsbMassStorage;
+ PeiBotDevice->Media.BlockSize = 0x200;
+ PeiBotDevice->Media2.InterfaceType = MSG_USB_DP;
+ PeiBotDevice->Media2.BlockSize = 0x200;
+ PeiBotDevice->Media2.RemovableMedia = FALSE;
+ PeiBotDevice->Media2.ReadOnly = FALSE;
+
+ //
+ // Check its Bulk-in/Bulk-out endpoint
+ //
+ for (Index = 0; Index < 2; Index++) {
+ Status = UsbIoPpi->UsbGetEndpointDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ Index,
+ &EndpointDesc
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((EndpointDesc->EndpointAddress & 0x80) != 0) {
+ PeiBotDevice->BulkInEndpoint = EndpointDesc;
+ } else {
+ PeiBotDevice->BulkOutEndpoint = EndpointDesc;
+ }
+ }
+
+ CopyMem (
+ &(PeiBotDevice->BlkIoPpi),
+ &mRecoveryBlkIoPpi,
+ sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI)
+ );
+ CopyMem (
+ &(PeiBotDevice->BlkIo2Ppi),
+ &mRecoveryBlkIo2Ppi,
+ sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI)
+ );
+ CopyMem (
+ &(PeiBotDevice->BlkIoPpiList),
+ &mPpiList[0],
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ CopyMem (
+ &(PeiBotDevice->BlkIo2PpiList),
+ &mPpiList[1],
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ PeiBotDevice->BlkIoPpiList.Ppi = &PeiBotDevice->BlkIoPpi;
+ PeiBotDevice->BlkIo2PpiList.Ppi = &PeiBotDevice->BlkIo2Ppi;
+
+ Status = PeiUsbInquiry (PeiServices, PeiBotDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ 1,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress);
+
+ Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+BotGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ //
+ // For Usb devices, this value should be always 1
+ //
+ *NumberBlockDevices = 1;
+ 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.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ PEI_BOT_DEVICE *PeiBotDev;
+ EFI_STATUS Status;
+
+ PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
+
+ //
+ // First test unit ready
+ //
+ PeiUsbTestUnitReady (
+ PeiServices,
+ PeiBotDev
+ );
+
+ Status = PeiBotDetectMedia (
+ PeiServices,
+ PeiBotDev
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (
+ MediaInfo,
+ &(PeiBotDev->Media),
+ 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
+BotReadBlocks (
+ 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
+ )
+{
+ PEI_BOT_DEVICE *PeiBotDev;
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
+
+ //
+ // Check parameters
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (!PeiBotDev->Media.MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ BlockSize = PeiBotDev->Media.BlockSize;
+
+ if (BufferSize % BlockSize != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > PeiBotDev->Media2.LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize);
+
+ if (Status == EFI_SUCCESS) {
+
+ Status = PeiUsbTestUnitReady (
+ PeiServices,
+ PeiBotDev
+ );
+ if (Status == EFI_SUCCESS) {
+ Status = PeiUsbRead10 (
+ PeiServices,
+ PeiBotDev,
+ Buffer,
+ StartLBA,
+ 1
+ );
+ }
+ } else {
+ //
+ // To generate sense data for DetectMedia use.
+ //
+ PeiUsbTestUnitReady (
+ PeiServices,
+ PeiBotDev
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // if any error encountered, detect what happened to the media and
+ // update the media info accordingly.
+ //
+ Status = PeiBotDetectMedia (
+ PeiServices,
+ PeiBotDev
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize;
+
+ if (!(PeiBotDev->Media.MediaPresent)) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLBA > PeiBotDev->Media2.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media2.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PeiUsbRead10 (
+ PeiServices,
+ PeiBotDev,
+ Buffer,
+ StartLBA,
+ NumberOfBlocks
+ );
+
+ switch (Status) {
+
+ case EFI_SUCCESS:
+ return EFI_SUCCESS;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ } else {
+ StartLBA += 1;
+ NumberOfBlocks -= 1;
+ Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize;
+
+ if (NumberOfBlocks == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = PeiUsbRead10 (
+ PeiServices,
+ PeiBotDev,
+ Buffer,
+ StartLBA,
+ NumberOfBlocks
+ );
+ switch (Status) {
+
+ case EFI_SUCCESS:
+ return EFI_SUCCESS;
+
+ default:
+ return EFI_DEVICE_ERROR;
+
+ }
+ }
+}
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetNumberOfBlockDevices2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ //
+ // For Usb devices, this value should be always 1
+ //
+ *NumberBlockDevices = 1;
+ 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_IO2_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.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ PEI_BOT_DEVICE *PeiBotDev;
+ EFI_STATUS Status;
+
+ PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
+
+ Status = BotGetMediaInfo (
+ PeiServices,
+ &PeiBotDev->BlkIoPpi,
+ DeviceIndex,
+ &PeiBotDev->Media
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (
+ MediaInfo,
+ &(PeiBotDev->Media2),
+ sizeof (EFI_PEI_BLOCK_IO2_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_IO2_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
+BotReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PEI_BOT_DEVICE *PeiBotDev;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
+
+ Status = BotReadBlocks (
+ PeiServices,
+ &PeiBotDev->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+
+ return Status;
+}
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM.
+ @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+PeiBotDetectMedia (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS FloppyStatus;
+ UINTN SenseCounts;
+ BOOLEAN NeedReadCapacity;
+ EFI_PHYSICAL_ADDRESS AllocateAddress;
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Retry;
+
+ //
+ // if there is no media present,or media not changed,
+ // the request sense command will detect faster than read capacity command.
+ // read capacity command can be bypassed, thus improve performance.
+ //
+ SenseCounts = 0;
+ NeedReadCapacity = TRUE;
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ 1,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SensePtr = PeiBotDev->SensePtr;
+ ZeroMem (SensePtr, EFI_PAGE_SIZE);
+
+ Status = PeiUsbRequestSense (
+ PeiServices,
+ PeiBotDev,
+ &SenseCounts,
+ (UINT8 *) SensePtr
+ );
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // No Media
+ //
+ if (IsNoMedia (SensePtr, SenseCounts)) {
+ NeedReadCapacity = FALSE;
+ PeiBotDev->Media.MediaPresent = FALSE;
+ PeiBotDev->Media.LastBlock = 0;
+ PeiBotDev->Media2.MediaPresent = FALSE;
+ PeiBotDev->Media2.LastBlock = 0;
+ } else {
+ //
+ // Media Changed
+ //
+ if (IsMediaChange (SensePtr, SenseCounts)) {
+ PeiBotDev->Media.MediaPresent = TRUE;
+ PeiBotDev->Media2.MediaPresent = TRUE;
+ }
+ //
+ // Media Error
+ //
+ if (IsMediaError (SensePtr, SenseCounts)) {
+ //
+ // if media error encountered, make it look like no media present.
+ //
+ PeiBotDev->Media.MediaPresent = FALSE;
+ PeiBotDev->Media.LastBlock = 0;
+ PeiBotDev->Media2.MediaPresent = FALSE;
+ PeiBotDev->Media2.LastBlock = 0;
+ }
+
+ }
+
+ }
+
+ if (NeedReadCapacity) {
+ //
+ // Retry at most 4 times to detect media info
+ //
+ for (Retry = 0; Retry < 4; Retry++) {
+ switch (PeiBotDev->DeviceType) {
+ case USBCDROM:
+ Status = PeiUsbReadCapacity (
+ PeiServices,
+ PeiBotDev
+ );
+ break;
+
+ case USBFLOPPY2:
+ Status = PeiUsbReadFormattedCapacity (
+ PeiServices,
+ PeiBotDev
+ );
+ if (EFI_ERROR(Status)||
+ !PeiBotDev->Media.MediaPresent) {
+ //
+ // retry the ReadCapacity command
+ //
+ PeiBotDev->DeviceType = USBFLOPPY;
+ Status = EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case USBFLOPPY:
+ Status = PeiUsbReadCapacity (
+ PeiServices,
+ PeiBotDev
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // retry the ReadFormatCapacity command
+ //
+ PeiBotDev->DeviceType = USBFLOPPY2;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SenseCounts = 0;
+ ZeroMem (SensePtr, EFI_PAGE_SIZE);
+
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+
+ FloppyStatus = PeiUsbRequestSense (
+ PeiServices,
+ PeiBotDev,
+ &SenseCounts,
+ (UINT8 *) SensePtr
+ );
+
+ //
+ // If Request Sense data failed,retry.
+ //
+ if (EFI_ERROR (FloppyStatus)) {
+ continue;
+ }
+ //
+ // No Media
+ //
+ if (IsNoMedia (SensePtr, SenseCounts)) {
+ PeiBotDev->Media.MediaPresent = FALSE;
+ PeiBotDev->Media.LastBlock = 0;
+ PeiBotDev->Media2.MediaPresent = FALSE;
+ PeiBotDev->Media2.LastBlock = 0;
+ break;
+ }
+
+ if (IsMediaError (SensePtr, SenseCounts)) {
+ //
+ // if media error encountered, make it look like no media present.
+ //
+ PeiBotDev->Media.MediaPresent = FALSE;
+ PeiBotDev->Media.LastBlock = 0;
+ PeiBotDev->Media2.MediaPresent = FALSE;
+ PeiBotDev->Media2.LastBlock = 0;
+ break;
+ }
+ }
+ //
+ // ENDFOR
+ //
+ // tell whether the readcapacity process is successful or not
+ // ("Status" variable record the latest status returned
+ // by ReadCapacity )
+ //
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h
new file mode 100644
index 000000000..81ca4a2d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h
@@ -0,0 +1,339 @@
+/** @file
+Usb BOT Peim definition.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_BOT_PEIM_H_
+#define _PEI_USB_BOT_PEIM_H_
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Usb.h>
+#include <IndustryStandard/Atapi.h>
+
+#define PEI_FAT_MAX_USB_IO_PPI 127
+
+/**
+ 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
+BotGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ 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
+BotReadBlocks (
+ 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
+ );
+
+/**
+ 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_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetNumberOfBlockDevices2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ 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_IO2_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.
+
+**/
+EFI_STATUS
+EFIAPI
+BotGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ 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_IO2_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
+BotReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ UsbIo installation notification function.
+
+ This function finds out all the current USB IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDesc Address of the notification descriptor data structure.
+ @param InvokePpi Address of the PPI that was invoked.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyOnUsbIoPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *InvokePpi
+ );
+
+/**
+ Initialize the usb bot device.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM.
+ @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS The usb bot device is initialized successfully.
+ @retval Other Failed to initialize media.
+
+**/
+EFI_STATUS
+InitUsbBot (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi
+ );
+
+#define USBCDROM 1 // let the device type value equal to USBCDROM, which is defined by PI spec.
+ // Therefore the CdExpressPei module can do recovery on UsbCdrom.
+#define USBFLOPPY 2 // for those that use ReadCapacity(0x25) command to retrieve media capacity
+#define USBFLOPPY2 3 // for those that use ReadFormatCapacity(0x23) command to retrieve media capacity
+
+//
+// Bot device structure
+//
+#define PEI_BOT_DEVICE_SIGNATURE SIGNATURE_32 ('U', 'B', 'O', 'T')
+typedef struct {
+ UINTN Signature;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ EFI_PEI_BLOCK_IO2_MEDIA Media2;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ EFI_USB_INTERFACE_DESCRIPTOR *BotInterface;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
+ UINTN AllocateAddress;
+ UINTN DeviceType;
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+} PEI_BOT_DEVICE;
+
+#define PEI_BOT_DEVICE_FROM_THIS(a) CR (a, PEI_BOT_DEVICE, BlkIoPpi, PEI_BOT_DEVICE_SIGNATURE)
+#define PEI_BOT_DEVICE2_FROM_THIS(a) CR (a, PEI_BOT_DEVICE, BlkIo2Ppi, PEI_BOT_DEVICE_SIGNATURE)
+
+/**
+ Send ATAPI command using BOT protocol.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param Command The command to be sent to ATAPI device.
+ @param CommandSize The length of the data to be sent.
+ @param DataBuffer The pointer to the data.
+ @param BufferLength The length of the data.
+ @param Direction The direction of the data.
+ @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.
+ @retval EFI_SUCCESS Failed to get the status of device.
+
+**/
+EFI_STATUS
+PeiAtapiCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN VOID *Command,
+ IN UINT8 CommandSize,
+ IN VOID *DataBuffer,
+ IN UINT32 BufferLength,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 TimeOutInMilliSeconds
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h
new file mode 100644
index 000000000..cb93d7229
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h
@@ -0,0 +1,26 @@
+/** @file
+Usb Peim definition.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_PEIM_H_
+#define _PEI_USB_PEIM_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c
new file mode 100644
index 000000000..642f93641
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c
@@ -0,0 +1,303 @@
+/** @file
+
+ UEFI Component Name(2) protocol implementation for Usb Bus driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi.h>
+
+
+#include <Library/UefiLib.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
+UsbBusComponentNameGetDriverName (
+ 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
+UsbBusComponentNameGetControllerName (
+ 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 mUsbBusComponentName = {
+ UsbBusComponentNameGetDriverName,
+ UsbBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbBusDriverNameTable[] = {
+ { "eng;en", L"Usb 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
+UsbBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &mUsbBusComponentName)
+ );
+}
+
+/**
+ 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 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 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
+UsbBusComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
new file mode 100644
index 000000000..4b4915c01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
@@ -0,0 +1,1537 @@
+/** @file
+
+ Usb Bus Driver Binding and Bus IO Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBus.h"
+
+EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
+ UsbIoControlTransfer,
+ UsbIoBulkTransfer,
+ UsbIoAsyncInterruptTransfer,
+ UsbIoSyncInterruptTransfer,
+ UsbIoIsochronousTransfer,
+ UsbIoAsyncIsochronousTransfer,
+ UsbIoGetDeviceDescriptor,
+ UsbIoGetActiveConfigDescriptor,
+ UsbIoGetInterfaceDescriptor,
+ UsbIoGetEndpointDescriptor,
+ UsbIoGetStringDescriptor,
+ UsbIoGetSupportedLanguages,
+ UsbIoPortReset
+};
+
+EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {
+ UsbBusControllerDriverSupported,
+ UsbBusControllerDriverStart,
+ UsbBusControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ USB_IO function to execute a control transfer. This
+ function will execute the USB transfer. If transfer
+ successes, it will sync the internal state of USB bus
+ with device state.
+
+ @param This The USB_IO instance
+ @param Request The control transfer request
+ @param Direction Direction for data stage
+ @param Timeout The time to wait before timeout
+ @param Data The buffer holding the data
+ @param DataLength Then length of the data
+ @param UsbStatus USB result
+
+ @retval EFI_INVALID_PARAMETER The parameters are invalid
+ @retval EFI_SUCCESS The control transfer succeeded.
+ @retval Others Failed to execute the transfer
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoControlTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINTN RequestedDataLength;
+
+ if (UsbStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ RequestedDataLength = DataLength;
+ Status = UsbHcControlTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Dev->Speed,
+ Dev->MaxPacket0,
+ Request,
+ Direction,
+ Data,
+ &DataLength,
+ (UINTN) Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+ //
+ // If the request completed successfully and the Direction of the request is
+ // EfiUsbDataIn or EfiUsbDataOut, then make sure the actual number of bytes
+ // transferred is the same as the number of bytes requested. If a different
+ // number of bytes were transferred, then return EFI_DEVICE_ERROR.
+ //
+ if (!EFI_ERROR (Status)) {
+ if (Direction != EfiUsbNoData && DataLength != RequestedDataLength) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ }
+
+ if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
+ //
+ // Clear TT buffer when CTRL/BULK split transaction failes
+ // Clear the TRANSLATOR TT buffer, not parent's buffer
+ //
+ ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);
+ if (Dev->Translator.TranslatorHubAddress != 0) {
+ UsbHubCtrlClearTTBuffer (
+ Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
+ Dev->Translator.TranslatorPortNumber,
+ Dev->Address,
+ 0,
+ USB_ENDPOINT_CONTROL
+ );
+ }
+
+ goto ON_EXIT;
+ }
+
+ //
+ // Some control transfer will change the device's internal
+ // status, such as Set_Configuration and Set_Interface.
+ // We must synchronize the bus driver's status with that in
+ // device. We ignore the Set_Descriptor request because it's
+ // hardly used by any device, especially in pre-boot environment
+ //
+
+ //
+ // Reset the endpoint toggle when endpoint stall is cleared
+ //
+ if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_ENDPOINT)) &&
+ (Request->Value == USB_FEATURE_ENDPOINT_HALT)) {
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);
+
+ if (EpDesc != NULL) {
+ EpDesc->Toggle = 0;
+ }
+ }
+
+ //
+ // Select a new configuration. This is a dangerous action. Upper driver
+ // should stop use its current UsbIo after calling this driver. The old
+ // UsbIo will be uninstalled and new UsbIo be installed. We can't use
+ // ReinstallProtocol since interfaces in different configuration may be
+ // completely irrelevant.
+ //
+ if ((Request->Request == USB_REQ_SET_CONFIG) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_DEVICE))) {
+ //
+ // Don't re-create the USB interfaces if configuration isn't changed.
+ //
+ if ((Dev->ActiveConfig != NULL) &&
+ (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {
+
+ goto ON_EXIT;
+ }
+ DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));
+
+ if (Dev->ActiveConfig != NULL) {
+ UsbRemoveConfig (Dev);
+ }
+
+ if (Request->Value != 0) {
+ Status = UsbSelectConfig (Dev, (UINT8) Request->Value);
+ }
+
+ //
+ // Exit now, Old USB_IO is invalid now
+ //
+ goto ON_EXIT;
+ }
+
+ //
+ // A new alternative setting is selected for the interface.
+ // No need to reinstall UsbIo in this case because only
+ // underlying communication endpoints are changed. Functionality
+ // should remains the same.
+ //
+ if ((Request->Request == USB_REQ_SET_INTERFACE) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_INTERFACE)) &&
+ (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber)) {
+
+ Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
+ UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a bulk transfer to the device endpoint.
+
+ @param This The USB IO instance.
+ @param Endpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param Timeout Time to wait before timeout.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_SUCCESS The bulk transfer is OK.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoBulkTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ UINT8 BufNum;
+ UINT8 Toggle;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
+ (UsbStatus == NULL)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ BufNum = 1;
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcBulkTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ BufNum,
+ &Data,
+ DataLength,
+ &Toggle,
+ Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
+ //
+ // Clear TT buffer when CTRL/BULK split transaction failes.
+ // Clear the TRANSLATOR TT buffer, not parent's buffer
+ //
+ ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);
+ if (Dev->Translator.TranslatorHubAddress != 0) {
+ UsbHubCtrlClearTTBuffer (
+ Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
+ Dev->Translator.TranslatorPortNumber,
+ Dev->Address,
+ 0,
+ USB_ENDPOINT_BULK
+ );
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a synchronous interrupt transfer.
+
+ @param This The USB IO instance.
+ @param Endpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param Timeout Time to wait before timeout.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_SUCCESS The synchronous interrupt transfer is OK.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoSyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ UINT8 Toggle;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
+ (UsbStatus == NULL)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcSyncInterruptTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ Data,
+ DataLength,
+ &Toggle,
+ Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Queue a new asynchronous interrupt transfer, or remove the old
+ request if (IsNewTransfer == FALSE).
+
+ @param This The USB_IO instance.
+ @param Endpoint The device endpoint.
+ @param IsNewTransfer Whether this is a new request, if it's old, remove
+ the request.
+ @param PollInterval The interval to poll the transfer result, (in ms).
+ @param DataLength The length of perodic data transfer.
+ @param Callback The function to call periodically when transfer is
+ ready.
+ @param Context The context to the callback.
+
+ @retval EFI_SUCCESS New transfer is queued or old request is removed.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to queue the new request or remove the old
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoAsyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollInterval, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, OPTIONAL
+ IN VOID *Context OPTIONAL
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ UINT8 Toggle;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcAsyncInterruptTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ IsNewTransfer,
+ &Toggle,
+ PollInterval,
+ DataLength,
+ &Dev->Translator,
+ Callback,
+ Context
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a synchronous isochronous transfer.
+
+ @param This The USB IO instance.
+ @param DeviceEndpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ OUT UINT32 *Status
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Queue an asynchronous isochronous transfer.
+
+ @param This The USB_IO instance.
+ @param DeviceEndpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of perodic data transfer.
+ @param IsochronousCallBack The function to call periodically when transfer is
+ ready.
+ @param Context The context to the callback.
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoAsyncIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Retrieve the device descriptor of the device.
+
+ @param This The USB IO instance.
+ @param Descriptor The variable to receive the device descriptor.
+
+ @retval EFI_SUCCESS The device descriptor is returned.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetDeviceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the configuration descriptor of the current active configuration.
+
+ @param This The USB IO instance.
+ @param Descriptor The USB configuration descriptor.
+
+ @retval EFI_SUCCESS The active configuration descriptor is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+ @retval EFI_NOT_FOUND Currently no active configuration is selected.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetActiveConfigDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ if (Dev->ActiveConfig == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto ON_EXIT;
+ }
+
+ CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Retrieve the active interface setting descriptor for this USB IO instance.
+
+ @param This The USB IO instance.
+ @param Descriptor The variable to receive active interface setting.
+
+ @retval EFI_SUCCESS The active interface setting is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetInterfaceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor
+ )
+{
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve the endpoint descriptor from this interface setting.
+
+ @param This The USB IO instance.
+ @param Index The index (start from zero) of the endpoint to
+ retrieve.
+ @param Descriptor The variable to receive the descriptor.
+
+ @retval EFI_SUCCESS The endpoint descriptor is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetEndpointDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Index,
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor
+ )
+{
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+
+ if ((Descriptor == NULL) || (Index > 15)) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (
+ Descriptor,
+ &(UsbIf->IfSetting->Endpoints[Index]->Desc),
+ sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve the supported language ID table from the device.
+
+ @param This The USB IO instance.
+ @param LangIDTable The table to return the language IDs.
+ @param TableSize The size, in bytes, of the table LangIDTable.
+
+ @retval EFI_SUCCESS The language ID is return.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetSupportedLanguages (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT UINT16 **LangIDTable,
+ OUT UINT16 *TableSize
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ *LangIDTable = Dev->LangId;
+ *TableSize = (UINT16) (Dev->TotalLangId * sizeof (UINT16));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve an indexed string in the language of LangID.
+
+ @param This The USB IO instance.
+ @param LangID The language ID of the string to retrieve.
+ @param StringIndex The index of the string.
+ @param String The variable to receive the string.
+
+ @retval EFI_SUCCESS The string is returned.
+ @retval EFI_NOT_FOUND No such string existed.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetStringDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT16 LangID,
+ IN UINT8 StringIndex,
+ OUT CHAR16 **String
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_USB_STRING_DESCRIPTOR *StrDesc;
+ EFI_TPL OldTpl;
+ UINT8 *Buf;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ if ((StringIndex == 0) || (LangID == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ //
+ // Check whether language ID is supported
+ //
+ Status = EFI_NOT_FOUND;
+
+ for (Index = 0; Index < Dev->TotalLangId; Index++) {
+ ASSERT (Index < USB_MAX_LANG_ID);
+ if (Dev->LangId[Index] == LangID) {
+ break;
+ }
+ }
+
+ if (Index == Dev->TotalLangId) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Retrieve the string descriptor then allocate a buffer
+ // to hold the string itself.
+ //
+ StrDesc = UsbGetOneString (Dev, StringIndex, LangID);
+
+ if (StrDesc == NULL) {
+ goto ON_EXIT;
+ }
+
+ if (StrDesc->Length <= 2) {
+ goto FREE_STR;
+ }
+
+ Buf = AllocateZeroPool (StrDesc->Length);
+
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_STR;
+ }
+
+ CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);
+ *String = (CHAR16 *) Buf;
+ Status = EFI_SUCCESS;
+
+FREE_STR:
+ gBS->FreePool (StrDesc);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Reset the device, then if that succeeds, reconfigure the
+ device with its address and current active configuration.
+
+ @param This The USB IO instance.
+
+ @retval EFI_SUCCESS The device is reset and configured.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoPortReset (
+ IN EFI_USB_IO_PROTOCOL *This
+ )
+{
+ USB_INTERFACE *UsbIf;
+ USB_INTERFACE *HubIf;
+ USB_DEVICE *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINT8 DevAddress;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ if (UsbIf->IsHub) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ HubIf = Dev->ParentIf;
+ Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",
+ Dev->ParentPort, Dev->ParentAddr, Status));
+
+ goto ON_EXIT;
+ }
+
+ HubIf->HubApi->ClearPortChange (HubIf, Dev->ParentPort);
+
+ //
+ // Reset the device to its current address. The device now has an address
+ // of ZERO after port reset, so need to set Dev->Address to the device again for
+ // host to communicate with it.
+ //
+ DevAddress = Dev->Address;
+ Dev->Address = 0;
+ Status = UsbSetAddress (Dev, DevAddress);
+ Dev->Address = DevAddress;
+
+ gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // It may fail due to device disconnection or other reasons.
+ //
+ DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",
+ Dev->Address, Status));
+
+ goto ON_EXIT;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Dev->Address));
+
+ //
+ // Reset the current active configure, after this device
+ // is in CONFIGURED state.
+ //
+ if (Dev->ActiveConfig != NULL) {
+ Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",
+ Dev->Address, Status));
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Install Usb Bus Protocol on host controller, and start the Usb bus.
+
+ @param This The USB bus driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb bus.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusBuildProtocol (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ USB_BUS *UsbBus;
+ USB_DEVICE *RootHub;
+ USB_INTERFACE *RootIf;
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+
+ UsbBus = AllocateZeroPool (sizeof (USB_BUS));
+
+ if (UsbBus == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UsbBus->Signature = USB_BUS_SIGNATURE;
+ UsbBus->HostHandle = Controller;
+ UsbBus->MaxDevices = USB_MAX_DEVICES;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbBus->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));
+
+ FreePool (UsbBus);
+ return Status;
+ }
+
+ //
+ // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).
+ // This is for backward compatibility with EFI 1.x. In UEFI
+ // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2
+ // and USB_HC because EHCI driver will install both protocols
+ // (for the same reason). If we don't consume both of them,
+ // the unconsumed one may be opened by others.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &(UsbBus->Usb2Hc),
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ Status2 = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &(UsbBus->UsbHc),
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
+ DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));
+
+ Status = EFI_DEVICE_ERROR;
+ goto CLOSE_HC;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.
+ // Then its max supported devices are 256. Otherwise it's 128.
+ //
+ ASSERT (UsbBus->Usb2Hc != NULL);
+ if (UsbBus->Usb2Hc->MajorRevision == 0x3) {
+ UsbBus->MaxDevices = 256;
+ }
+ }
+
+ //
+ // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbBus->BusId
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));
+ goto CLOSE_HC;
+ }
+
+ //
+ // Initial the wanted child device path list, and add first RemainingDevicePath
+ //
+ InitializeListHead (&UsbBus->WantedUsbIoDPList);
+ Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);
+ ASSERT (!EFI_ERROR (Status));
+ //
+ // Create a fake usb device for root hub
+ //
+ RootHub = AllocateZeroPool (sizeof (USB_DEVICE));
+
+ if (RootHub == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNINSTALL_USBBUS;
+ }
+
+ RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));
+
+ if (RootIf == NULL) {
+ FreePool (RootHub);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_ROOTHUB;
+ }
+
+ RootHub->Bus = UsbBus;
+ RootHub->NumOfInterface = 1;
+ RootHub->Interfaces[0] = RootIf;
+ RootHub->Tier = 0;
+ RootIf->Signature = USB_INTERFACE_SIGNATURE;
+ RootIf->Device = RootHub;
+ RootIf->DevicePath = UsbBus->DevicePath;
+
+ //
+ // Report Status Code here since we will enumerate the USB devices
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_DETECT),
+ UsbBus->DevicePath
+ );
+
+ Status = mUsbRootHubApi.Init (RootIf);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));
+ goto FREE_ROOTHUB;
+ }
+
+ UsbBus->Devices[0] = RootHub;
+
+ DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));
+ return EFI_SUCCESS;
+
+FREE_ROOTHUB:
+ if (RootIf != NULL) {
+ FreePool (RootIf);
+ }
+ if (RootHub != NULL) {
+ FreePool (RootHub);
+ }
+
+UNINSTALL_USBBUS:
+ gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &UsbBus->BusId);
+
+CLOSE_HC:
+ if (UsbBus->Usb2Hc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ if (UsbBus->UsbHc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (UsbBus);
+
+ DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));
+ return Status;
+}
+
+
+/**
+ The USB bus driver entry pointer.
+
+ @param ImageHandle The driver image handle.
+ @param SystemTable The system table.
+
+ @return EFI_SUCCESS The component name protocol is installed.
+ @return Others Failed to init the usb driver.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mUsbBusDriverBinding,
+ ImageHandle,
+ &mUsbBusComponentName,
+ &mUsbBusComponentName2
+ );
+}
+
+
+/**
+ Check whether USB bus driver support this device.
+
+ @param This The USB bus driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The bus supports this controller.
+ @retval EFI_UNSUPPORTED This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_DEV_PATH_PTR DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+ EFI_STATUS Status;
+
+ //
+ // Check whether device path is valid
+ //
+ 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
+ //
+ DevicePathNode.DevPath = RemainingDevicePath;
+
+ if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||
+ (DevicePathNode.DevPath->SubType != MSG_USB_DP &&
+ DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP
+ && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP
+ )) {
+
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Check whether USB_HC2 protocol is installed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If failed to open USB_HC2, fall back to USB_HC
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &UsbHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the USB_HC used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ } else {
+
+ //
+ // Close the USB_HC2 used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ 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)) {
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+/**
+ Start to process the controller.
+
+ @param This The USB bus driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb bus.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
+ bus.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_USB_BUS_PROTOCOL *UsbBusId;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Report Status Code here since we will initialize the host controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ //
+ // Locate the USB bus protocol, if it is found, USB bus
+ // is already started on this controller.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &UsbBusId,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If first start, build the bus execute environment and install bus protocol
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));
+ Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Try get the Usb Bus protocol interface again
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &UsbBusId,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ } else {
+ //
+ // USB Bus driver need to control the recursive connect policy of the bus, only those wanted
+ // usb child device will be recursively connected.
+ // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.
+ // All wanted usb child devices will be remembered by the usb bus driver itself.
+ // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.
+ //
+ // Save the passed in RemainingDevicePath this time
+ //
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCCESS
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);
+ ASSERT (!EFI_ERROR (Status));
+ //
+ // Ensure all wanted child usb devices are fully recursively connected
+ //
+ Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Stop handle the controller by this USB bus driver.
+
+ @param This The USB bus driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The child of USB bus 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
+UsbBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ USB_BUS *Bus;
+ USB_DEVICE *RootHub;
+ USB_DEVICE *UsbDev;
+ USB_INTERFACE *RootIf;
+ USB_INTERFACE *UsbIf;
+ EFI_USB_BUS_PROTOCOL *BusId;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ Status = EFI_SUCCESS;
+
+ if (NumberOfChildren > 0) {
+ //
+ // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ ReturnStatus = EFI_SUCCESS;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // It is possible that the child has already been released:
+ // 1. For combo device, free one device will release others.
+ // 2. If a hub is released, all devices on its down facing
+ // ports are released also.
+ //
+ continue;
+ }
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);
+ UsbDev = UsbIf->Device;
+
+ ReturnStatus = UsbRemoveDevice (UsbDev);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return ReturnStatus;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));
+
+ //
+ // Locate USB_BUS for the current host controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &BusId,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bus = USB_BUS_FROM_THIS (BusId);
+
+ //
+ // Stop the root hub, then free all the devices
+ //
+ // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ RootHub = Bus->Devices[0];
+ RootIf = RootHub->Interfaces[0];
+
+ ASSERT (Bus->MaxDevices <= 256);
+ ReturnStatus = EFI_SUCCESS;
+ for (Index = 1; Index < Bus->MaxDevices; Index++) {
+ if (Bus->Devices[Index] != NULL) {
+ Status = UsbRemoveDevice (Bus->Devices[Index]);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ if (!EFI_ERROR (ReturnStatus)) {
+ mUsbRootHubApi.Release (RootIf);
+ gBS->FreePool (RootIf);
+ gBS->FreePool (RootHub);
+
+ Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);
+ ASSERT (!EFI_ERROR (Status));
+
+ //
+ // Uninstall the bus identifier and close USB_HC/USB2_HC protocols
+ //
+ gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &Bus->BusId);
+
+ if (Bus->Usb2Hc != NULL) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (Bus->UsbHc != NULL) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->FreePool (Bus);
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
new file mode 100644
index 000000000..c84a24df2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
@@ -0,0 +1,764 @@
+/** @file
+
+ Usb Bus Driver Binding and Bus IO Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_BUS_H_
+#define _EFI_USB_BUS_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/Usb2HostController.h>
+#include <Protocol/UsbHostController.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.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 <Library/ReportStatusCodeLib.h>
+
+
+#include <IndustryStandard/Usb.h>
+
+typedef struct _USB_DEVICE USB_DEVICE;
+typedef struct _USB_INTERFACE USB_INTERFACE;
+typedef struct _USB_BUS USB_BUS;
+typedef struct _USB_HUB_API USB_HUB_API;
+
+
+#include "UsbUtility.h"
+#include "UsbDesc.h"
+#include "UsbHub.h"
+#include "UsbEnumer.h"
+
+//
+// USB bus timeout experience values
+//
+
+#define USB_MAX_LANG_ID 16
+#define USB_MAX_INTERFACE 16
+#define USB_MAX_DEVICES 128
+
+#define USB_BUS_1_MILLISECOND 1000
+
+//
+// Roothub and hub's polling interval, set by experience,
+// The unit of roothub is 100us, means 100ms as interval, and
+// the unit of hub is 1ms, means 64ms as interval.
+//
+#define USB_ROOTHUB_POLL_INTERVAL (100 * 10000U)
+#define USB_HUB_POLL_INTERVAL 64
+
+//
+// Wait for port stable to work, refers to specification
+// [USB20-9.1.2]
+//
+#define USB_WAIT_PORT_STABLE_STALL (100 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for port statue reg change, set by experience
+//
+#define USB_WAIT_PORT_STS_CHANGE_STALL (100)
+
+//
+// Wait for set device address, refers to specification
+// [USB20-9.2.6.3, it says 2ms]
+//
+#define USB_SET_DEVICE_ADDRESS_STALL (2 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for retry max packet size, set by experience
+//
+#define USB_RETRY_MAX_PACK_SIZE_STALL (100 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for hub port power-on, refers to specification
+// [USB20-11.23.2]
+//
+#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for port reset, refers to specification
+// [USB20-7.1.7.5, it says 10ms for hub and 50ms for
+// root hub]
+//
+// According to USB2.0, Chapter 11.5.1.5 Resetting,
+// the worst case for TDRST is 20ms
+//
+#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
+#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for port recovery to accept SetAddress, refers to specification
+// [USB20-7.1.7.5, it says 10 ms for TRSTRCY]
+//
+#define USB_SET_PORT_RECOVERY_STALL (10 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for clear roothub port reset, set by experience
+//
+#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for set roothub port enable, set by experience
+//
+#define USB_SET_ROOT_PORT_ENABLE_STALL (20 * USB_BUS_1_MILLISECOND)
+
+//
+// Send general device request timeout.
+//
+// The USB Specification 2.0, section 11.24.1 recommends a value of
+// 50 milliseconds. We use a value of 500 milliseconds to work
+// around slower hubs and devices.
+//
+#define USB_GENERAL_DEVICE_REQUEST_TIMEOUT 500
+
+//
+// Send clear feature request timeout, set by experience
+//
+#define USB_CLEAR_FEATURE_REQUEST_TIMEOUT 10
+
+//
+// Bus raises TPL to TPL_NOTIFY to serialize all its operations
+// to protect shared data structures.
+//
+#define USB_BUS_TPL TPL_NOTIFY
+
+#define USB_INTERFACE_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'I')
+#define USB_BUS_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'B')
+
+#define USB_BIT(a) ((UINTN)(1 << (a)))
+#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define USB_INTERFACE_FROM_USBIO(a) \
+ CR(a, USB_INTERFACE, UsbIo, USB_INTERFACE_SIGNATURE)
+
+#define USB_BUS_FROM_THIS(a) \
+ CR(a, USB_BUS, BusId, USB_BUS_SIGNATURE)
+
+//
+// Used to locate USB_BUS
+// UsbBusProtocol is the private protocol.
+// gEfiCallerIdGuid will be used as its protocol guid.
+//
+typedef struct _EFI_USB_BUS_PROTOCOL {
+ UINT64 Reserved;
+} EFI_USB_BUS_PROTOCOL;
+
+
+//
+// Stands for the real USB device. Each device may
+// has several separately working interfaces.
+//
+struct _USB_DEVICE {
+ USB_BUS *Bus;
+
+ //
+ // Configuration information
+ //
+ UINT8 Speed;
+ UINT8 Address;
+ UINT32 MaxPacket0;
+
+ //
+ // The device's descriptors and its configuration
+ //
+ USB_DEVICE_DESC *DevDesc;
+ USB_CONFIG_DESC *ActiveConfig;
+
+ UINT16 LangId [USB_MAX_LANG_ID];
+ UINT16 TotalLangId;
+
+ UINT8 NumOfInterface;
+ USB_INTERFACE *Interfaces [USB_MAX_INTERFACE];
+
+ //
+ // Parent child relationship
+ //
+ EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
+
+ UINT8 ParentAddr;
+ USB_INTERFACE *ParentIf;
+ UINT8 ParentPort; // Start at 0
+ UINT8 Tier;
+ BOOLEAN DisconnectFail;
+};
+
+//
+// Stands for different functions of USB device
+//
+struct _USB_INTERFACE {
+ UINTN Signature;
+ USB_DEVICE *Device;
+ USB_INTERFACE_DESC *IfDesc;
+ USB_INTERFACE_SETTING *IfSetting;
+
+ //
+ // Handles and protocols
+ //
+ EFI_HANDLE Handle;
+ EFI_USB_IO_PROTOCOL UsbIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN IsManaged;
+
+ //
+ // Hub device special data
+ //
+ BOOLEAN IsHub;
+ USB_HUB_API *HubApi;
+ UINT8 NumOfPort;
+ EFI_EVENT HubNotify;
+
+ //
+ // Data used only by normal hub devices
+ //
+ USB_ENDPOINT_DESC *HubEp;
+ UINT8 *ChangeMap;
+
+ //
+ // Data used only by root hub to hand over device to
+ // companion UHCI driver if low/full speed devices are
+ // connected to EHCI.
+ //
+ UINT8 MaxSpeed;
+};
+
+//
+// Stands for the current USB Bus
+//
+struct _USB_BUS {
+ UINTN Signature;
+ EFI_USB_BUS_PROTOCOL BusId;
+
+ //
+ // Managed USB host controller
+ //
+ EFI_HANDLE HostHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+
+ //
+ // Recorded the max supported usb devices.
+ // XHCI can support up to 255 devices.
+ // EHCI/UHCI/OHCI supports up to 127 devices.
+ //
+ UINT32 MaxDevices;
+ //
+ // An array of device that is on the bus. Devices[0] is
+ // for root hub. Device with address i is at Devices[i].
+ //
+ USB_DEVICE *Devices[256];
+
+ //
+ // USB Bus driver need to control the recursive connect policy of the bus, only those wanted
+ // usb child device will be recursively connected.
+ //
+ // WantedUsbIoDPList tracks the Usb child devices which user want to recursively fully connecte,
+ // every wanted child device is stored in a item of the WantedUsbIoDPList, whose structure is
+ // DEVICE_PATH_LIST_ITEM
+ //
+ LIST_ENTRY WantedUsbIoDPList;
+
+};
+
+//
+// USB Hub Api
+//
+struct _USB_HUB_API{
+ USB_HUB_INIT Init;
+ USB_HUB_GET_PORT_STATUS GetPortStatus;
+ USB_HUB_CLEAR_PORT_CHANGE ClearPortChange;
+ USB_HUB_SET_PORT_FEATURE SetPortFeature;
+ USB_HUB_CLEAR_PORT_FEATURE ClearPortFeature;
+ USB_HUB_RESET_PORT ResetPort;
+ USB_HUB_RELEASE Release;
+};
+
+#define USB_US_LAND_ID 0x0409
+
+#define DEVICE_PATH_LIST_ITEM_SIGNATURE SIGNATURE_32('d','p','l','i')
+typedef struct _DEVICE_PATH_LIST_ITEM{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} DEVICE_PATH_LIST_ITEM;
+
+typedef struct {
+ USB_CLASS_DEVICE_PATH UsbClass;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} USB_CLASS_FORMAT_DEVICE_PATH;
+
+/**
+ Free a DEVICE_PATH_LIST_ITEM list.
+
+ @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list pointer.
+
+ @retval EFI_INVALID_PARAMETER If parameters are invalid, return this value.
+ @retval EFI_SUCCESS If free operation is successful, return this value.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusFreeUsbDPList (
+ IN LIST_ENTRY *UsbIoDPList
+ );
+
+/**
+ Store a wanted usb child device info (its Usb part of device path) which is indicated by
+ RemainingDevicePath in a Usb bus which is indicated by UsbBusId.
+
+ @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS Add operation is successful.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusAddWantedUsbIoDP (
+ IN EFI_USB_BUS_PROTOCOL *UsbBusId,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Check whether a usb child device is the wanted device in a bus.
+
+ @param Bus The Usb bus's private data pointer.
+ @param UsbIf The usb child device interface.
+
+ @retval True If a usb child device is the wanted device in a bus.
+ @retval False If a usb child device is *NOT* the wanted device in a bus.
+
+**/
+BOOLEAN
+EFIAPI
+UsbBusIsWantedUsbIO (
+ IN USB_BUS *Bus,
+ IN USB_INTERFACE *UsbIf
+ );
+
+/**
+ Recursively connect every wanted usb child device to ensure they all fully connected.
+ Check all the child Usb IO handles in this bus, recursively connecte if it is wanted usb child device.
+
+ @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
+
+ @retval EFI_SUCCESS Connect is done successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusRecursivelyConnectWantedUsbIo (
+ IN EFI_USB_BUS_PROTOCOL *UsbBusId
+ );
+
+/**
+ USB_IO function to execute a control transfer. This
+ function will execute the USB transfer. If transfer
+ successes, it will sync the internal state of USB bus
+ with device state.
+
+ @param This The USB_IO instance
+ @param Request The control transfer request
+ @param Direction Direction for data stage
+ @param Timeout The time to wait before timeout
+ @param Data The buffer holding the data
+ @param DataLength Then length of the data
+ @param UsbStatus USB result
+
+ @retval EFI_INVALID_PARAMETER The parameters are invalid
+ @retval EFI_SUCCESS The control transfer succeded.
+ @retval Others Failed to execute the transfer
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoControlTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ OUT UINT32 *UsbStatus
+ );
+
+/**
+ Execute a bulk transfer to the device endpoint.
+
+ @param This The USB IO instance.
+ @param Endpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param Timeout Time to wait before timeout.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_SUCCESS The bulk transfer is OK.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoBulkTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ );
+
+/**
+ Execute a synchronous interrupt transfer.
+
+ @param This The USB IO instance.
+ @param Endpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param Timeout Time to wait before timeout.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_SUCCESS The synchronous interrupt transfer is OK.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoSyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ );
+
+/**
+ Queue a new asynchronous interrupt transfer, or remove the old
+ request if (IsNewTransfer == FALSE).
+
+ @param This The USB_IO instance.
+ @param Endpoint The device endpoint.
+ @param IsNewTransfer Whether this is a new request, if it's old, remove
+ the request.
+ @param PollInterval The interval to poll the transfer result, (in ms).
+ @param DataLength The length of perodic data transfer.
+ @param Callback The function to call periodically when transfer is
+ ready.
+ @param Context The context to the callback.
+
+ @retval EFI_SUCCESS New transfer is queued or old request is removed.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval Others Failed to queue the new request or remove the old
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoAsyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollInterval, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, OPTIONAL
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Execute a synchronous isochronous transfer.
+
+ @param This The USB IO instance.
+ @param DeviceEndpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of the data to transfer.
+ @param UsbStatus The result of USB transfer.
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ OUT UINT32 *Status
+ );
+
+/**
+ Queue an asynchronous isochronous transfer.
+
+ @param This The USB_IO instance.
+ @param DeviceEndpoint The device endpoint.
+ @param Data The data to transfer.
+ @param DataLength The length of perodic data transfer.
+ @param IsochronousCallBack The function to call periodically when transfer is
+ ready.
+ @param Context The context to the callback.
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoAsyncIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Retrieve the device descriptor of the device.
+
+ @param This The USB IO instance.
+ @param Descriptor The variable to receive the device descriptor.
+
+ @retval EFI_SUCCESS The device descriptor is returned.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetDeviceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Return the configuration descriptor of the current active configuration.
+
+ @param This The USB IO instance.
+ @param Descriptor The USB configuration descriptor.
+
+ @retval EFI_SUCCESS The active configuration descriptor is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+ @retval EFI_NOT_FOUND Currently no active configuration is selected.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetActiveConfigDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Retrieve the active interface setting descriptor for this USB IO instance.
+
+ @param This The USB IO instance.
+ @param Descriptor The variable to receive active interface setting.
+
+ @retval EFI_SUCCESS The active interface setting is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetInterfaceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Retrieve the endpoint descriptor from this interface setting.
+
+ @param This The USB IO instance.
+ @param Index The index (start from zero) of the endpoint to
+ retrieve.
+ @param Descriptor The variable to receive the descriptor.
+
+ @retval EFI_SUCCESS The endpoint descriptor is returned.
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetEndpointDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Index,
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Retrieve the supported language ID table from the device.
+
+ @param This The USB IO instance.
+ @param LangIDTable The table to return the language IDs.
+ @param TableSize The size, in bytes, of the table LangIDTable.
+
+ @retval EFI_SUCCESS The language ID is return.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetSupportedLanguages (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT UINT16 **LangIDTable,
+ OUT UINT16 *TableSize
+ );
+
+/**
+ Retrieve an indexed string in the language of LangID.
+
+ @param This The USB IO instance.
+ @param LangID The language ID of the string to retrieve.
+ @param StringIndex The index of the string.
+ @param String The variable to receive the string.
+
+ @retval EFI_SUCCESS The string is returned.
+ @retval EFI_NOT_FOUND No such string existed.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoGetStringDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT16 LangID,
+ IN UINT8 StringIndex,
+ OUT CHAR16 **String
+ );
+
+/**
+ Reset the device, then if that succeeds, reconfigure the
+ device with its address and current active configuration.
+
+ @param This The USB IO instance.
+
+ @retval EFI_SUCCESS The device is reset and configured.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoPortReset (
+ IN EFI_USB_IO_PROTOCOL *This
+ );
+
+/**
+ Install Usb Bus Protocol on host controller, and start the Usb bus.
+
+ @param This The USB bus driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb bus.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusBuildProtocol (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ The USB bus driver entry pointer.
+
+ @param ImageHandle The driver image handle.
+ @param SystemTable The system table.
+
+ @return EFI_SUCCESS The component name protocol is installed.
+ @return Others Failed to init the usb driver.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Check whether USB bus driver support this device.
+
+ @param This The USB bus driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The bus supports this controller.
+ @retval EFI_UNSUPPORTED This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start to process the controller.
+
+ @param This The USB bus driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb bus.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
+ bus.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop handle the controller by this USB bus driver.
+
+ @param This The USB bus driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The child of USB bus 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
+UsbBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+extern EFI_USB_IO_PROTOCOL mUsbIoProtocol;
+extern EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL mUsbBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL mUsbBusComponentName2;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
new file mode 100644
index 000000000..dd8589434
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
@@ -0,0 +1,73 @@
+## @file
+# The Usb Bus Dxe driver is used to enumerate and manage all attached usb devices.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbBusDxe
+ MODULE_UNI_FILE = UsbBusDxe.uni
+ FILE_GUID = 240612B7-A063-11d4-9A3A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = UsbBusDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = mUsbBusDriverBinding
+# COMPONENT_NAME = mUsbBusComponentName
+# COMPONENT_NAME2 = mUsbBusComponentName2
+#
+
+[Sources]
+ UsbDesc.c
+ UsbEnumer.c
+ UsbEnumer.h
+ UsbBus.c
+ UsbHub.c
+ ComponentName.c
+ UsbUtility.h
+ UsbHub.h
+ UsbUtility.c
+ UsbDesc.h
+ UsbBus.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ ReportStatusCodeLib
+
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+ gEfiUsb2HcProtocolGuid ## TO_START
+ gEfiUsbHcProtocolGuid ## TO_START
+
+# [Event]
+#
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbBusDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.uni
new file mode 100644
index 000000000..1dea34ca4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The Usb Bus Dxe driver is used to enumerate and manage all attached usb devices.
+//
+// The USB Bus DXE driver is used to enumerate and manage all attached USB devices.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Enumerates and manages attached USB devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The USB Bus DXE driver is used to enumerate and manage all attached USB devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxeExtra.uni
new file mode 100644
index 000000000..c087fe503
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbBusDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Bus DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
new file mode 100644
index 000000000..b08188b1b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
@@ -0,0 +1,1017 @@
+/** @file
+
+ Manage Usb Descriptor List
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBus.h"
+
+
+/**
+ Free the interface setting descriptor.
+
+ @param Setting The descriptor to free.
+
+**/
+VOID
+UsbFreeInterfaceDesc (
+ IN USB_INTERFACE_SETTING *Setting
+ )
+{
+ USB_ENDPOINT_DESC *Ep;
+ UINTN Index;
+
+ if (Setting->Endpoints != NULL) {
+ //
+ // Each interface setting may have several endpoints, free them first.
+ //
+ for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
+ Ep = Setting->Endpoints[Index];
+
+ if (Ep != NULL) {
+ FreePool (Ep);
+ }
+ }
+
+ //
+ // Only call FreePool() if NumEndpoints > 0.
+ //
+ if (Setting->Desc.NumEndpoints > 0) {
+ FreePool (Setting->Endpoints);
+ }
+ }
+
+ FreePool (Setting);
+}
+
+
+/**
+ Free a configuration descriptor with its interface
+ descriptors. It may be initialized partially.
+
+ @param Config The configuration descriptor to free.
+
+**/
+VOID
+UsbFreeConfigDesc (
+ IN USB_CONFIG_DESC *Config
+ )
+{
+ USB_INTERFACE_DESC *Interface;
+ UINTN Index;
+ UINTN SetIndex;
+
+ if (Config->Interfaces != NULL) {
+ //
+ // A configuration may have several interfaces, free the interface
+ //
+ for (Index = 0; Index < Config->Desc.NumInterfaces; Index++) {
+ Interface = Config->Interfaces[Index];
+
+ if (Interface == NULL) {
+ continue;
+ }
+
+ //
+ // Each interface may have several settings, free the settings
+ //
+ for (SetIndex = 0; SetIndex < Interface->NumOfSetting; SetIndex++) {
+ if (Interface->Settings[SetIndex] != NULL) {
+ UsbFreeInterfaceDesc (Interface->Settings[SetIndex]);
+ }
+ }
+
+ FreePool (Interface);
+ }
+
+ FreePool (Config->Interfaces);
+ }
+
+ FreePool (Config);
+
+}
+
+
+/**
+ Free a device descriptor with its configurations.
+
+ @param DevDesc The device descriptor.
+
+**/
+VOID
+UsbFreeDevDesc (
+ IN USB_DEVICE_DESC *DevDesc
+ )
+{
+ UINTN Index;
+
+ if (DevDesc->Configs != NULL) {
+ for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
+ if (DevDesc->Configs[Index] != NULL) {
+ UsbFreeConfigDesc (DevDesc->Configs[Index]);
+ }
+ }
+
+ FreePool (DevDesc->Configs);
+ }
+
+ FreePool (DevDesc);
+}
+
+
+/**
+ Create a descriptor.
+
+ @param DescBuf The buffer of raw descriptor.
+ @param Len The length of the raw descriptor buffer.
+ @param Type The type of descriptor to create.
+ @param Consumed Number of bytes consumed.
+
+ @return Created descriptor or NULL.
+
+**/
+VOID *
+UsbCreateDesc (
+ IN UINT8 *DescBuf,
+ IN UINTN Len,
+ IN UINT8 Type,
+ OUT UINTN *Consumed
+ )
+{
+ USB_DESC_HEAD *Head;
+ UINTN DescLen;
+ UINTN CtrlLen;
+ UINTN Offset;
+ VOID *Desc;
+
+ DescLen = 0;
+ CtrlLen = 0;
+ *Consumed = 0;
+
+ switch (Type) {
+ case USB_DESC_TYPE_DEVICE:
+ DescLen = sizeof (EFI_USB_DEVICE_DESCRIPTOR);
+ CtrlLen = sizeof (USB_DEVICE_DESC);
+ break;
+
+ case USB_DESC_TYPE_CONFIG:
+ DescLen = sizeof (EFI_USB_CONFIG_DESCRIPTOR);
+ CtrlLen = sizeof (USB_CONFIG_DESC);
+ break;
+
+ case USB_DESC_TYPE_INTERFACE:
+ DescLen = sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
+ CtrlLen = sizeof (USB_INTERFACE_SETTING);
+ break;
+
+ case USB_DESC_TYPE_ENDPOINT:
+ DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
+ CtrlLen = sizeof (USB_ENDPOINT_DESC);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return NULL;
+ }
+
+ //
+ // Total length is too small that cannot hold the single descriptor header plus data.
+ //
+ if (Len <= sizeof (USB_DESC_HEAD)) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, total length = %d!\n", Len));
+ return NULL;
+ }
+
+ //
+ // All the descriptor has a common LTV (Length, Type, Value)
+ // format. Skip the descriptor that isn't of this Type
+ //
+ Offset = 0;
+ Head = (USB_DESC_HEAD *)DescBuf;
+ while (Offset < Len - sizeof (USB_DESC_HEAD)) {
+ //
+ // Above condition make sure Head->Len and Head->Type are safe to access
+ //
+ Head = (USB_DESC_HEAD *)&DescBuf[Offset];
+
+ if (Head->Len == 0) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n"));
+ return NULL;
+ }
+
+ //
+ // Make sure no overflow when adding Head->Len to Offset.
+ //
+ if (Head->Len > MAX_UINTN - Offset) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = %d!\n", Head->Len));
+ return NULL;
+ }
+
+ Offset += Head->Len;
+
+ if (Head->Type == Type) {
+ break;
+ }
+ }
+
+ //
+ // Head->Len is invalid resulting data beyond boundary, or
+ // Descriptor cannot be found: No such type.
+ //
+ if (Len < Offset) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Len));
+ return NULL;
+ }
+
+ if ((Head->Type != Type) || (Head->Len < DescLen)) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));
+ return NULL;
+ }
+
+ Desc = AllocateZeroPool ((UINTN) CtrlLen);
+ if (Desc == NULL) {
+ return NULL;
+ }
+
+ CopyMem (Desc, Head, (UINTN) DescLen);
+
+ *Consumed = Offset;
+
+ return Desc;
+}
+
+
+/**
+ Parse an interface descriptor and its endpoints.
+
+ @param DescBuf The buffer of raw descriptor.
+ @param Len The length of the raw descriptor buffer.
+ @param Consumed The number of raw descriptor consumed.
+
+ @return The create interface setting or NULL if failed.
+
+**/
+USB_INTERFACE_SETTING *
+UsbParseInterfaceDesc (
+ IN UINT8 *DescBuf,
+ IN UINTN Len,
+ OUT UINTN *Consumed
+ )
+{
+ USB_INTERFACE_SETTING *Setting;
+ USB_ENDPOINT_DESC *Ep;
+ UINTN Index;
+ UINTN NumEp;
+ UINTN Used;
+ UINTN Offset;
+
+ *Consumed = 0;
+ Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);
+
+ if (Setting == NULL) {
+ DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create interface descriptor\n"));
+ return NULL;
+ }
+
+ Offset = Used;
+
+ //
+ // Create an array to hold the interface's endpoints
+ //
+ NumEp = Setting->Desc.NumEndpoints;
+
+ DEBUG (( EFI_D_INFO, "UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",
+ Setting->Desc.InterfaceNumber, Setting->Desc.AlternateSetting, (UINT32)NumEp));
+
+ if (NumEp == 0) {
+ goto ON_EXIT;
+ }
+
+ Setting->Endpoints = AllocateZeroPool (sizeof (USB_ENDPOINT_DESC *) * NumEp);
+
+ if (Setting->Endpoints == NULL) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Create the endpoints for this interface
+ //
+ for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) {
+ Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);
+
+ if (Ep == NULL) {
+ DEBUG (( EFI_D_ERROR, "UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", (UINT32)Index));
+ goto ON_ERROR;
+ }
+
+ Setting->Endpoints[Index] = Ep;
+ Offset += Used;
+ }
+
+
+ON_EXIT:
+ *Consumed = Offset;
+ return Setting;
+
+ON_ERROR:
+ UsbFreeInterfaceDesc (Setting);
+ return NULL;
+}
+
+
+/**
+ Parse the configuration descriptor and its interfaces.
+
+ @param DescBuf The buffer of raw descriptor.
+ @param Len The length of the raw descriptor buffer.
+
+ @return The created configuration descriptor.
+
+**/
+USB_CONFIG_DESC *
+UsbParseConfigDesc (
+ IN UINT8 *DescBuf,
+ IN UINTN Len
+ )
+{
+ USB_CONFIG_DESC *Config;
+ USB_INTERFACE_SETTING *Setting;
+ USB_INTERFACE_DESC *Interface;
+ UINTN Index;
+ UINTN NumIf;
+ UINTN Consumed;
+
+ ASSERT (DescBuf != NULL);
+
+ Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed);
+
+ if (Config == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initialize an array of setting for the configuration's interfaces.
+ //
+ NumIf = Config->Desc.NumInterfaces;
+ Config->Interfaces = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf);
+
+ if (Config->Interfaces == NULL) {
+ goto ON_ERROR;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbParseConfigDesc: config %d has %d interfaces\n",
+ Config->Desc.ConfigurationValue, (UINT32)NumIf));
+
+ for (Index = 0; Index < NumIf; Index++) {
+ Interface = AllocateZeroPool (sizeof (USB_INTERFACE_DESC));
+
+ if (Interface == NULL) {
+ goto ON_ERROR;
+ }
+
+ Config->Interfaces[Index] = Interface;
+ }
+
+ //
+ // If a configuration has several interfaces, these interfaces are
+ // numbered from zero to n. If a interface has several settings,
+ // these settings are also number from zero to m. The interface
+ // setting must be organized as |interface 0, setting 0|interface 0
+ // setting 1|interface 1, setting 0|interface 2, setting 0|. Check
+ // USB2.0 spec, page 267.
+ //
+ DescBuf += Consumed;
+ Len -= Consumed;
+
+ //
+ // Make allowances for devices that return extra data at the
+ // end of their config descriptors
+ //
+ while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {
+ Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);
+
+ if (Setting == NULL) {
+ DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n"));
+ break;
+
+ } else if (Setting->Desc.InterfaceNumber >= NumIf) {
+ DEBUG (( DEBUG_ERROR, "UsbParseConfigDesc: malformatted interface descriptor\n"));
+
+ UsbFreeInterfaceDesc (Setting);
+ goto ON_ERROR;
+ }
+
+ //
+ // Insert the descriptor to the corresponding set.
+ //
+ Interface = Config->Interfaces[Setting->Desc.InterfaceNumber];
+
+ if (Interface->NumOfSetting >= USB_MAX_INTERFACE_SETTING) {
+ goto ON_ERROR;
+ }
+
+ Interface->Settings[Interface->NumOfSetting] = Setting;
+ Interface->NumOfSetting++;
+
+ DescBuf += Consumed;
+ Len -= Consumed;
+ }
+
+ return Config;
+
+ON_ERROR:
+ UsbFreeConfigDesc (Config);
+ return NULL;
+}
+
+
+/**
+ USB standard control transfer support routine. This
+ function is used by USB device. It is possible that
+ the device's interfaces are still waiting to be
+ enumerated.
+
+ @param UsbDev The usb device.
+ @param Direction The direction of data transfer.
+ @param Type Standard / class specific / vendor specific.
+ @param Target The receiving target.
+ @param Request Which request.
+ @param Value The wValue parameter of the request.
+ @param Index The wIndex parameter of the request.
+ @param Buf The buffer to receive data into / transmit from.
+ @param Length The length of the buffer.
+
+ @retval EFI_SUCCESS The control request is executed.
+ @retval EFI_DEVICE_ERROR Failed to execute the control transfer.
+
+**/
+EFI_STATUS
+UsbCtrlRequest (
+ IN USB_DEVICE *UsbDev,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINTN Type,
+ IN UINTN Target,
+ IN UINTN Request,
+ IN UINT16 Value,
+ IN UINT16 Index,
+ IN OUT VOID *Buf,
+ IN UINTN Length
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINTN Len;
+
+ ASSERT ((UsbDev != NULL) && (UsbDev->Bus != NULL));
+
+ DevReq.RequestType = USB_REQUEST_TYPE (Direction, Type, Target);
+ DevReq.Request = (UINT8) Request;
+ DevReq.Value = Value;
+ DevReq.Index = Index;
+ DevReq.Length = (UINT16) Length;
+
+ Len = Length;
+ Status = UsbHcControlTransfer (
+ UsbDev->Bus,
+ UsbDev->Address,
+ UsbDev->Speed,
+ UsbDev->MaxPacket0,
+ &DevReq,
+ Direction,
+ Buf,
+ &Len,
+ USB_GENERAL_DEVICE_REQUEST_TIMEOUT,
+ &UsbDev->Translator,
+ &Result
+ );
+
+ return Status;
+}
+
+
+/**
+ Get the standard descriptors.
+
+ @param UsbDev The USB device to read descriptor from.
+ @param DescType The type of descriptor to read.
+ @param DescIndex The index of descriptor to read.
+ @param LangId Language ID, only used to get string, otherwise set
+ it to 0.
+ @param Buf The buffer to hold the descriptor read.
+ @param Length The length of the buffer.
+
+ @retval EFI_SUCCESS The descriptor is read OK.
+ @retval Others Failed to retrieve the descriptor.
+
+**/
+EFI_STATUS
+UsbCtrlGetDesc (
+ IN USB_DEVICE *UsbDev,
+ IN UINTN DescType,
+ IN UINTN DescIndex,
+ IN UINT16 LangId,
+ OUT VOID *Buf,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ UsbDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_STANDARD,
+ USB_TARGET_DEVICE,
+ USB_REQ_GET_DESCRIPTOR,
+ (UINT16) ((DescType << 8) | DescIndex),
+ LangId,
+ Buf,
+ Length
+ );
+
+ return Status;
+}
+
+
+/**
+ Return the max packet size for endpoint zero. This function
+ is the first function called to get descriptors during bus
+ enumeration.
+
+ @param UsbDev The usb device.
+
+ @retval EFI_SUCCESS The max packet size of endpoint zero is retrieved.
+ @retval EFI_DEVICE_ERROR Failed to retrieve it.
+
+**/
+EFI_STATUS
+UsbGetMaxPacketSize0 (
+ IN USB_DEVICE *UsbDev
+ )
+{
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_STATUS Status;
+ UINTN Index;
+
+
+ //
+ // Get the first 8 bytes of the device descriptor which contains
+ // max packet size for endpoint 0, which is at least 8.
+ //
+ for (Index = 0; Index < 3; Index++) {
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);
+
+ if (!EFI_ERROR (Status)) {
+ if ((DevDesc.BcdUSB >= 0x0300) && (DevDesc.MaxPacketSize0 == 9)) {
+ UsbDev->MaxPacket0 = 1 << 9;
+ return EFI_SUCCESS;
+ }
+ UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (USB_RETRY_MAX_PACK_SIZE_STALL);
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Get the device descriptor for the device.
+
+ @param UsbDev The Usb device to retrieve descriptor from.
+
+ @retval EFI_SUCCESS The device descriptor is returned.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+
+**/
+EFI_STATUS
+UsbGetDevDesc (
+ IN USB_DEVICE *UsbDev
+ )
+{
+ USB_DEVICE_DESC *DevDesc;
+ EFI_STATUS Status;
+
+ DevDesc = AllocateZeroPool (sizeof (USB_DEVICE_DESC));
+
+ if (DevDesc == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UsbCtrlGetDesc (
+ UsbDev,
+ USB_DESC_TYPE_DEVICE,
+ 0,
+ 0,
+ DevDesc,
+ sizeof (EFI_USB_DEVICE_DESCRIPTOR)
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (DevDesc);
+ } else {
+ UsbDev->DevDesc = DevDesc;
+ }
+
+ return Status;
+}
+
+
+/**
+ Retrieve the indexed string for the language. It requires two
+ steps to get a string, first to get the string's length. Then
+ the string itself.
+
+ @param UsbDev The usb device.
+ @param Index The index the string to retrieve.
+ @param LangId Language ID.
+
+ @return The created string descriptor or NULL.
+
+**/
+EFI_USB_STRING_DESCRIPTOR *
+UsbGetOneString (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 Index,
+ IN UINT16 LangId
+ )
+{
+ EFI_USB_STRING_DESCRIPTOR Desc;
+ EFI_STATUS Status;
+ UINT8 *Buf;
+
+ //
+ // First get two bytes which contains the string length.
+ //
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);
+
+ //
+ // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.
+ //
+ if (EFI_ERROR (Status) ||
+ (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||
+ (Desc.Length % 2 != 0)
+ ) {
+ return NULL;
+ }
+
+ Buf = AllocateZeroPool (Desc.Length);
+
+ if (Buf == NULL) {
+ return NULL;
+ }
+
+ Status = UsbCtrlGetDesc (
+ UsbDev,
+ USB_DESC_TYPE_STRING,
+ Index,
+ LangId,
+ Buf,
+ Desc.Length
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ return NULL;
+ }
+
+ return (EFI_USB_STRING_DESCRIPTOR *) Buf;
+}
+
+
+/**
+ Build the language ID table for string descriptors.
+
+ @param UsbDev The Usb device.
+
+ @retval EFI_UNSUPPORTED This device doesn't support string table.
+
+**/
+EFI_STATUS
+UsbBuildLangTable (
+ IN USB_DEVICE *UsbDev
+ )
+{
+ EFI_USB_STRING_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Max;
+ UINT16 *Point;
+
+ //
+ // The string of language ID zero returns the supported languages
+ //
+ Desc = UsbGetOneString (UsbDev, 0, 0);
+
+ if (Desc == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Desc->Length < 4) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ Status = EFI_SUCCESS;
+
+ Max = (Desc->Length - 2) / 2;
+ Max = MIN(Max, USB_MAX_LANG_ID);
+
+ Point = Desc->String;
+ for (Index = 0; Index < Max; Index++) {
+ UsbDev->LangId[Index] = *Point;
+ Point++;
+ }
+
+ UsbDev->TotalLangId = (UINT16)Max;
+
+ON_EXIT:
+ gBS->FreePool (Desc);
+ return Status;
+}
+
+
+/**
+ Retrieve the indexed configure for the device. USB device
+ returns the configuration together with the interfaces for
+ this configuration. Configuration descriptor is also of
+ variable length.
+
+ @param UsbDev The Usb interface.
+ @param Index The index of the configuration.
+
+ @return The created configuration descriptor.
+
+**/
+EFI_USB_CONFIG_DESCRIPTOR *
+UsbGetOneConfig (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 Index
+ )
+{
+ EFI_USB_CONFIG_DESCRIPTOR Desc;
+ EFI_STATUS Status;
+ VOID *Buf;
+
+ //
+ // First get four bytes which contains the total length
+ // for this configuration.
+ //
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, &Desc, 8);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get descript length(%d) %r\n",
+ Desc.TotalLength, Status));
+
+ return NULL;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength));
+
+ //
+ // Reject if TotalLength even cannot cover itself.
+ //
+ if (Desc.TotalLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (Desc.TotalLength)) {
+ return NULL;
+ }
+
+ Buf = AllocateZeroPool (Desc.TotalLength);
+
+ if (Buf == NULL) {
+ return NULL;
+ }
+
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, Buf, Desc.TotalLength);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get full descript %r\n", Status));
+
+ FreePool (Buf);
+ return NULL;
+ }
+
+ return Buf;
+}
+
+
+/**
+ Build the whole array of descriptors. This function must
+ be called after UsbGetMaxPacketSize0 returns the max packet
+ size correctly for endpoint 0.
+
+ @param UsbDev The Usb device.
+
+ @retval EFI_SUCCESS The descriptor table is build.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor.
+
+**/
+EFI_STATUS
+UsbBuildDescTable (
+ IN USB_DEVICE *UsbDev
+ )
+{
+ EFI_USB_CONFIG_DESCRIPTOR *Config;
+ USB_DEVICE_DESC *DevDesc;
+ USB_CONFIG_DESC *ConfigDesc;
+ UINT8 NumConfig;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Get the device descriptor, then allocate the configure
+ // descriptor pointer array to hold configurations.
+ //
+ Status = UsbGetDevDesc (UsbDev);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get device descriptor - %r\n", Status));
+ return Status;
+ }
+
+ DevDesc = UsbDev->DevDesc;
+ NumConfig = DevDesc->Desc.NumConfigurations;
+ if (NumConfig == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));
+ if (DevDesc->Configs == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbBuildDescTable: device has %d configures\n", NumConfig));
+
+ //
+ // Read each configurations, then parse them
+ //
+ for (Index = 0; Index < NumConfig; Index++) {
+ Config = UsbGetOneConfig (UsbDev, Index);
+
+ if (Config == NULL) {
+ DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to get configure (index %d)\n", Index));
+
+ //
+ // If we can get the default descriptor, it is likely that the
+ // device is still operational.
+ //
+ if (Index == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ break;
+ }
+
+ ConfigDesc = UsbParseConfigDesc ((UINT8 *) Config, Config->TotalLength);
+
+ FreePool (Config);
+
+ if (ConfigDesc == NULL) {
+ DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to parse configure (index %d)\n", Index));
+
+ //
+ // If we can get the default descriptor, it is likely that the
+ // device is still operational.
+ //
+ if (Index == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ break;
+ }
+
+ DevDesc->Configs[Index] = ConfigDesc;
+ }
+
+ //
+ // Don't return error even this function failed because
+ // it is possible for the device to not support strings.
+ //
+ Status = UsbBuildLangTable (UsbDev);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_INFO, "UsbBuildDescTable: get language ID table %r\n", Status));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Set the device's address.
+
+ @param UsbDev The device to set address to.
+ @param Address The address to set.
+
+ @retval EFI_SUCCESS The device is set to the address.
+ @retval Others Failed to set the device address.
+
+**/
+EFI_STATUS
+UsbSetAddress (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 Address
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ UsbDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_STANDARD,
+ USB_TARGET_DEVICE,
+ USB_REQ_SET_ADDRESS,
+ Address,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Set the device's configuration. This function changes
+ the device's internal state. UsbSelectConfig changes
+ the Usb bus's internal state.
+
+ @param UsbDev The USB device to set configure to.
+ @param ConfigIndex The configure index to set.
+
+ @retval EFI_SUCCESS The device is configured now.
+ @retval Others Failed to set the device configure.
+
+**/
+EFI_STATUS
+UsbSetConfig (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 ConfigIndex
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ UsbDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_STANDARD,
+ USB_TARGET_DEVICE,
+ USB_REQ_SET_CONFIG,
+ ConfigIndex,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb UsbIo interface to clear the feature. This is should
+ only be used by HUB which is considered a device driver
+ on top of the UsbIo interface.
+
+ @param UsbIo The UsbIo interface.
+ @param Target The target of the transfer: endpoint/device.
+ @param Feature The feature to clear.
+ @param Index The wIndex parameter.
+
+ @retval EFI_SUCCESS The device feature is cleared.
+ @retval Others Failed to clear the feature.
+
+**/
+EFI_STATUS
+UsbIoClearFeature (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINTN Target,
+ IN UINT16 Feature,
+ IN UINT16 Index
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 UsbResult;
+ EFI_STATUS Status;
+
+ DevReq.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, Target);
+ DevReq.Request = USB_REQ_CLEAR_FEATURE;
+ DevReq.Value = Feature;
+ DevReq.Index = Index;
+ DevReq.Length = 0;
+
+ Status = UsbIo->UsbControlTransfer (
+ UsbIo,
+ &DevReq,
+ EfiUsbNoData,
+ USB_CLEAR_FEATURE_REQUEST_TIMEOUT,
+ NULL,
+ 0,
+ &UsbResult
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
new file mode 100644
index 000000000..7b0c77fdc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
@@ -0,0 +1,227 @@
+/** @file
+
+ Manage Usb Descriptor List
+
+Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_DESCRIPTOR_H_
+#define _USB_DESCRIPTOR_H_
+
+#define USB_MAX_INTERFACE_SETTING 256
+
+//
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
+// three fields: One bit direction, 2 bit type, and 5 bit
+// target.
+//
+#define USB_REQUEST_TYPE(Dir, Type, Target) \
+ ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))
+
+//
+// A common header for usb standard descriptor.
+// Each stand descriptor has a length and type.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Len;
+ UINT8 Type;
+} USB_DESC_HEAD;
+#pragma pack()
+
+
+//
+// Each USB device has a device descriptor. Each device may
+// have several configures. Each configure contains several
+// interfaces. Each interface may have several settings. Each
+// setting has several endpoints.
+//
+// EFI_USB_..._DESCRIPTOR must be the first member of the
+// structure.
+//
+typedef struct {
+ EFI_USB_ENDPOINT_DESCRIPTOR Desc;
+ UINT8 Toggle;
+} USB_ENDPOINT_DESC;
+
+typedef struct {
+ EFI_USB_INTERFACE_DESCRIPTOR Desc;
+ USB_ENDPOINT_DESC **Endpoints;
+} USB_INTERFACE_SETTING;
+
+//
+// An interface may have several settings. Use a
+// fixed max number of settings to simplify code.
+// It should sufice in most environments.
+//
+typedef struct {
+ USB_INTERFACE_SETTING* Settings[USB_MAX_INTERFACE_SETTING];
+ UINTN NumOfSetting;
+ UINTN ActiveIndex; // Index of active setting
+} USB_INTERFACE_DESC;
+
+typedef struct {
+ EFI_USB_CONFIG_DESCRIPTOR Desc;
+ USB_INTERFACE_DESC **Interfaces;
+} USB_CONFIG_DESC;
+
+typedef struct {
+ EFI_USB_DEVICE_DESCRIPTOR Desc;
+ USB_CONFIG_DESC **Configs;
+} USB_DEVICE_DESC;
+
+/**
+ USB standard control transfer support routine. This
+ function is used by USB device. It is possible that
+ the device's interfaces are still waiting to be
+ enumerated.
+
+ @param UsbDev The usb device.
+ @param Direction The direction of data transfer.
+ @param Type Standard / class specific / vendor specific.
+ @param Target The receiving target.
+ @param Request Which request.
+ @param Value The wValue parameter of the request.
+ @param Index The wIndex parameter of the request.
+ @param Buf The buffer to receive data into / transmit from.
+ @param Length The length of the buffer.
+
+ @retval EFI_SUCCESS The control request is executed.
+ @retval EFI_DEVICE_ERROR Failed to execute the control transfer.
+
+**/
+EFI_STATUS
+UsbCtrlRequest (
+ IN USB_DEVICE *UsbDev,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINTN Type,
+ IN UINTN Target,
+ IN UINTN Request,
+ IN UINT16 Value,
+ IN UINT16 Index,
+ IN OUT VOID *Buf,
+ IN UINTN Length
+ );
+
+/**
+ Return the max packet size for endpoint zero. This function
+ is the first function called to get descriptors during bus
+ enumeration.
+
+ @param UsbDev The usb device.
+
+ @retval EFI_SUCCESS The max packet size of endpoint zero is retrieved.
+ @retval EFI_DEVICE_ERROR Failed to retrieve it.
+
+**/
+EFI_STATUS
+UsbGetMaxPacketSize0 (
+ IN USB_DEVICE *UsbDev
+ );
+
+/**
+ Free a device descriptor with its configurations.
+
+ @param DevDesc The device descriptor.
+
+ @return None.
+
+**/
+VOID
+UsbFreeDevDesc (
+ IN USB_DEVICE_DESC *DevDesc
+ );
+
+/**
+ Retrieve the indexed string for the language. It requires two
+ steps to get a string, first to get the string's length. Then
+ the string itself.
+
+ @param UsbDev The usb device.
+ @param StringIndex The index of the string to retrieve.
+ @param LangId Language ID.
+
+ @return The created string descriptor or NULL.
+
+**/
+EFI_USB_STRING_DESCRIPTOR*
+UsbGetOneString (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 StringIndex,
+ IN UINT16 LangId
+ );
+
+/**
+ Build the whole array of descriptors. This function must
+ be called after UsbGetMaxPacketSize0 returns the max packet
+ size correctly for endpoint 0.
+
+ @param UsbDev The Usb device.
+
+ @retval EFI_SUCCESS The descriptor table is build.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor.
+
+**/
+EFI_STATUS
+UsbBuildDescTable (
+ IN USB_DEVICE *UsbDev
+ );
+
+/**
+ Set the device's address.
+
+ @param UsbDev The device to set address to.
+ @param Address The address to set.
+
+ @retval EFI_SUCCESS The device is set to the address.
+ @retval Others Failed to set the device address.
+
+**/
+EFI_STATUS
+UsbSetAddress (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 Address
+ );
+
+/**
+ Set the device's configuration. This function changes
+ the device's internal state. UsbSelectConfig changes
+ the Usb bus's internal state.
+
+ @param UsbDev The USB device to set configure to.
+ @param ConfigIndex The configure index to set.
+
+ @retval EFI_SUCCESS The device is configured now.
+ @retval Others Failed to set the device configure.
+
+**/
+EFI_STATUS
+UsbSetConfig (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 ConfigIndex
+ );
+
+/**
+ Usb UsbIo interface to clear the feature. This is should
+ only be used by HUB which is considered a device driver
+ on top of the UsbIo interface.
+
+ @param UsbIo The UsbIo interface.
+ @param Target The target of the transfer: endpoint/device.
+ @param Feature The feature to clear.
+ @param Index The wIndex parameter.
+
+ @retval EFI_SUCCESS The device feature is cleared.
+ @retval Others Failed to clear the feature.
+
+**/
+EFI_STATUS
+UsbIoClearFeature (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINTN Target,
+ IN UINT16 Feature,
+ IN UINT16 Index
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
new file mode 100644
index 000000000..d3e0cfa62
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
@@ -0,0 +1,1083 @@
+/** @file
+
+ Usb bus enumeration support.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBus.h"
+
+/**
+ Return the endpoint descriptor in this interface.
+
+ @param UsbIf The interface to search in.
+ @param EpAddr The address of the endpoint to return.
+
+ @return The endpoint descriptor or NULL.
+
+**/
+USB_ENDPOINT_DESC *
+UsbGetEndpointDesc (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 EpAddr
+ )
+{
+ USB_ENDPOINT_DESC *EpDesc;
+ UINT8 Index;
+ UINT8 NumEndpoints;
+
+ NumEndpoints = UsbIf->IfSetting->Desc.NumEndpoints;
+
+ for (Index = 0; Index < NumEndpoints; Index++) {
+ EpDesc = UsbIf->IfSetting->Endpoints[Index];
+
+ if (EpDesc->Desc.EndpointAddress == EpAddr) {
+ return EpDesc;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ Free the resource used by USB interface.
+
+ @param UsbIf The USB interface to free.
+
+ @retval EFI_ACCESS_DENIED The interface is still occupied.
+ @retval EFI_SUCCESS The interface is freed.
+**/
+EFI_STATUS
+UsbFreeInterface (
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_STATUS Status;
+
+ UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ UsbIf->Handle,
+ &gEfiDevicePathProtocolGuid, UsbIf->DevicePath,
+ &gEfiUsbIoProtocolGuid, &UsbIf->UsbIo,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ if (UsbIf->DevicePath != NULL) {
+ FreePool (UsbIf->DevicePath);
+ }
+ FreePool (UsbIf);
+ } else {
+ UsbOpenHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+ }
+ return Status;
+}
+
+
+/**
+ Create an interface for the descriptor IfDesc. Each
+ device's configuration can have several interfaces.
+
+ @param Device The device has the interface descriptor.
+ @param IfDesc The interface descriptor.
+
+ @return The created USB interface for the descriptor, or NULL.
+
+**/
+USB_INTERFACE *
+UsbCreateInterface (
+ IN USB_DEVICE *Device,
+ IN USB_INTERFACE_DESC *IfDesc
+ )
+{
+ USB_DEVICE_PATH UsbNode;
+ USB_INTERFACE *UsbIf;
+ USB_INTERFACE *HubIf;
+ EFI_STATUS Status;
+
+ UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
+
+ if (UsbIf == NULL) {
+ return NULL;
+ }
+
+ UsbIf->Signature = USB_INTERFACE_SIGNATURE;
+ UsbIf->Device = Device;
+ UsbIf->IfDesc = IfDesc;
+ ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
+ UsbIf->IfSetting = IfDesc->Settings[IfDesc->ActiveIndex];
+
+ CopyMem (
+ &(UsbIf->UsbIo),
+ &mUsbIoProtocol,
+ sizeof (EFI_USB_IO_PROTOCOL)
+ );
+
+ //
+ // Install protocols for USBIO and device path
+ //
+ UsbNode.Header.Type = MESSAGING_DEVICE_PATH;
+ UsbNode.Header.SubType = MSG_USB_DP;
+ UsbNode.ParentPortNumber = Device->ParentPort;
+ UsbNode.InterfaceNumber = UsbIf->IfSetting->Desc.InterfaceNumber;
+
+ SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
+
+ HubIf = Device->ParentIf;
+ ASSERT (HubIf != NULL);
+
+ UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
+
+ if (UsbIf->DevicePath == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to create device path\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &UsbIf->Handle,
+ &gEfiDevicePathProtocolGuid,
+ UsbIf->DevicePath,
+ &gEfiUsbIoProtocolGuid,
+ &UsbIf->UsbIo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ //
+ // Open USB Host Controller Protocol by Child
+ //
+ Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
+
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ UsbIf->Handle,
+ &gEfiDevicePathProtocolGuid,
+ UsbIf->DevicePath,
+ &gEfiUsbIoProtocolGuid,
+ &UsbIf->UsbIo,
+ NULL
+ );
+
+ DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ return UsbIf;
+
+ON_ERROR:
+ if (UsbIf->DevicePath != NULL) {
+ FreePool (UsbIf->DevicePath);
+ }
+
+ FreePool (UsbIf);
+ return NULL;
+}
+
+
+/**
+ Free the resource used by this USB device.
+
+ @param Device The USB device to free.
+
+**/
+VOID
+UsbFreeDevice (
+ IN USB_DEVICE *Device
+ )
+{
+ if (Device->DevDesc != NULL) {
+ UsbFreeDevDesc (Device->DevDesc);
+ }
+
+ gBS->FreePool (Device);
+}
+
+
+/**
+ Create a device which is on the parent's ParentPort port.
+
+ @param ParentIf The parent HUB interface.
+ @param ParentPort The port on the HUB this device is connected to.
+
+ @return Created USB device, Or NULL.
+
+**/
+USB_DEVICE *
+UsbCreateDevice (
+ IN USB_INTERFACE *ParentIf,
+ IN UINT8 ParentPort
+ )
+{
+ USB_DEVICE *Device;
+
+ ASSERT (ParentIf != NULL);
+
+ Device = AllocateZeroPool (sizeof (USB_DEVICE));
+
+ if (Device == NULL) {
+ return NULL;
+ }
+
+ Device->Bus = ParentIf->Device->Bus;
+ Device->MaxPacket0 = 8;
+ Device->ParentAddr = ParentIf->Device->Address;
+ Device->ParentIf = ParentIf;
+ Device->ParentPort = ParentPort;
+ Device->Tier = (UINT8)(ParentIf->Device->Tier + 1);
+ return Device;
+}
+
+
+/**
+ Connect the USB interface with its driver. EFI USB bus will
+ create a USB interface for each separate interface descriptor.
+
+ @param UsbIf The interface to connect driver to.
+
+ @return EFI_SUCCESS Interface is managed by some driver.
+ @return Others Failed to locate a driver for this interface.
+
+**/
+EFI_STATUS
+UsbConnectDriver (
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Hub is maintained by the USB bus driver. Otherwise try to
+ // connect drivers with this interface
+ //
+ if (UsbIsHubInterface (UsbIf)) {
+ DEBUG ((EFI_D_INFO, "UsbConnectDriver: found a hub device\n"));
+ Status = mUsbHubApi.Init (UsbIf);
+
+ } else {
+ //
+ // This function is called in both UsbIoControlTransfer and
+ // the timer callback in hub enumeration. So, at least it is
+ // called at TPL_CALLBACK. Some driver sitting on USB has
+ // twisted TPL used. It should be no problem for us to connect
+ // or disconnect at CALLBACK.
+ //
+
+ //
+ // Only recursively wanted usb child device
+ //
+ if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {
+ OldTpl = UsbGetCurrentTpl ();
+ DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
+
+ gBS->RestoreTPL (TPL_CALLBACK);
+
+ Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
+ UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl()));
+ ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
+
+ gBS->RaiseTPL (OldTpl);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Select an alternate setting for the interface.
+ Each interface can have several mutually exclusive
+ settings. Only one setting is active. It will
+ also reset its endpoints' toggle to zero.
+
+ @param IfDesc The interface descriptor to set.
+ @param Alternate The alternate setting number to locate.
+
+ @retval EFI_NOT_FOUND There is no setting with this alternate index.
+ @retval EFI_SUCCESS The interface is set to Alternate setting.
+
+**/
+EFI_STATUS
+UsbSelectSetting (
+ IN USB_INTERFACE_DESC *IfDesc,
+ IN UINT8 Alternate
+ )
+{
+ USB_INTERFACE_SETTING *Setting;
+ UINTN Index;
+
+ //
+ // Locate the active alternate setting
+ //
+ Setting = NULL;
+
+ for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {
+ ASSERT (Index < USB_MAX_INTERFACE_SETTING);
+ Setting = IfDesc->Settings[Index];
+
+ if (Setting->Desc.AlternateSetting == Alternate) {
+ break;
+ }
+ }
+
+ if (Index == IfDesc->NumOfSetting) {
+ return EFI_NOT_FOUND;
+ }
+
+ IfDesc->ActiveIndex = Index;
+
+ ASSERT (Setting != NULL);
+ DEBUG ((EFI_D_INFO, "UsbSelectSetting: setting %d selected for interface %d\n",
+ Alternate, Setting->Desc.InterfaceNumber));
+
+ //
+ // Reset the endpoint toggle to zero
+ //
+ for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
+ Setting->Endpoints[Index]->Toggle = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Select a new configuration for the device. Each
+ device may support several configurations.
+
+ @param Device The device to select configuration.
+ @param ConfigValue The index of the configuration ( != 0).
+
+ @retval EFI_NOT_FOUND There is no configuration with the index.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
+ @retval EFI_SUCCESS The configuration is selected.
+
+**/
+EFI_STATUS
+UsbSelectConfig (
+ IN USB_DEVICE *Device,
+ IN UINT8 ConfigValue
+ )
+{
+ USB_DEVICE_DESC *DevDesc;
+ USB_CONFIG_DESC *ConfigDesc;
+ USB_INTERFACE_DESC *IfDesc;
+ USB_INTERFACE *UsbIf;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Locate the active config, then set the device's pointer
+ //
+ DevDesc = Device->DevDesc;
+ ConfigDesc = NULL;
+
+ for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
+ ConfigDesc = DevDesc->Configs[Index];
+
+ if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
+ break;
+ }
+ }
+
+ if (Index == DevDesc->Desc.NumConfigurations) {
+ return EFI_NOT_FOUND;
+ }
+
+ Device->ActiveConfig = ConfigDesc;
+
+ DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n",
+ ConfigValue, Device->Address));
+
+ //
+ // Create interfaces for each USB interface descriptor.
+ //
+ for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
+ //
+ // First select the default interface setting, and reset
+ // the endpoint toggles to zero for its endpoints.
+ //
+ IfDesc = ConfigDesc->Interfaces[Index];
+ UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);
+
+ //
+ // Create a USB_INTERFACE and install USB_IO and other protocols
+ //
+ UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);
+
+ if (UsbIf == NULL) {
+ Device->NumOfInterface = Index;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ASSERT (Index < USB_MAX_INTERFACE);
+ Device->Interfaces[Index] = UsbIf;
+
+ //
+ // Connect the device to drivers, if it failed, ignore
+ // the error. Don't let the unsupported interfaces to block
+ // the supported interfaces.
+ //
+ Status = UsbConnectDriver (UsbIf);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_WARN,
+ "UsbSelectConfig: failed to connect driver %r, ignored\n",
+ Status
+ ));
+ }
+ }
+
+ Device->NumOfInterface = Index;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Disconnect the USB interface with its driver.
+
+ @param UsbIf The interface to disconnect driver from.
+
+**/
+EFI_STATUS
+UsbDisconnectDriver (
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Release the hub if it's a hub controller, otherwise
+ // disconnect the driver if it is managed by other drivers.
+ //
+ Status = EFI_SUCCESS;
+ if (UsbIf->IsHub) {
+ Status = UsbIf->HubApi->Release (UsbIf);
+
+ } else if (UsbIf->IsManaged) {
+ //
+ // This function is called in both UsbIoControlTransfer and
+ // the timer callback in hub enumeration. So, at least it is
+ // called at TPL_CALLBACK. Some driver sitting on USB has
+ // twisted TPL used. It should be no problem for us to connect
+ // or disconnect at CALLBACK.
+ //
+ OldTpl = UsbGetCurrentTpl ();
+ DEBUG ((EFI_D_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
+
+ gBS->RestoreTPL (TPL_CALLBACK);
+
+ Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ UsbIf->IsManaged = FALSE;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl(), Status));
+ ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
+
+ gBS->RaiseTPL (OldTpl);
+ }
+
+ return Status;
+}
+
+
+/**
+ Remove the current device configuration.
+
+ @param Device The USB device to remove configuration from.
+
+**/
+EFI_STATUS
+UsbRemoveConfig (
+ IN USB_DEVICE *Device
+ )
+{
+ USB_INTERFACE *UsbIf;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ //
+ // Remove each interface of the device
+ //
+ ReturnStatus = EFI_SUCCESS;
+ for (Index = 0; Index < Device->NumOfInterface; Index++) {
+ ASSERT (Index < USB_MAX_INTERFACE);
+ UsbIf = Device->Interfaces[Index];
+
+ if (UsbIf == NULL) {
+ continue;
+ }
+
+ Status = UsbDisconnectDriver (UsbIf);
+ if (!EFI_ERROR (Status)) {
+ Status = UsbFreeInterface (UsbIf);
+ if (EFI_ERROR (Status)) {
+ UsbConnectDriver (UsbIf);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Device->Interfaces[Index] = NULL;
+ } else {
+ ReturnStatus = Status;
+ }
+ }
+
+ Device->ActiveConfig = NULL;
+ return ReturnStatus;
+}
+
+
+/**
+ Remove the device and all its children from the bus.
+
+ @param Device The device to remove.
+
+ @retval EFI_SUCCESS The device is removed.
+
+**/
+EFI_STATUS
+UsbRemoveDevice (
+ IN USB_DEVICE *Device
+ )
+{
+ USB_BUS *Bus;
+ USB_DEVICE *Child;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINTN Index;
+
+ Bus = Device->Bus;
+
+ //
+ // Remove all the devices on its downstream ports. Search from devices[1].
+ // Devices[0] is the root hub.
+ //
+ ReturnStatus = EFI_SUCCESS;
+ for (Index = 1; Index < Bus->MaxDevices; Index++) {
+ Child = Bus->Devices[Index];
+
+ if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
+ continue;
+ }
+
+ Status = UsbRemoveDevice (Child);
+
+ if (!EFI_ERROR (Status)) {
+ Bus->Devices[Index] = NULL;
+ } else {
+ Bus->Devices[Index]->DisconnectFail = TRUE;
+ ReturnStatus = Status;
+ DEBUG ((EFI_D_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device));
+ }
+ }
+
+ if (EFI_ERROR (ReturnStatus)) {
+ return ReturnStatus;
+ }
+
+ Status = UsbRemoveConfig (Device);
+
+ if (!EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
+
+ ASSERT (Device->Address < Bus->MaxDevices);
+ Bus->Devices[Device->Address] = NULL;
+ UsbFreeDevice (Device);
+ } else {
+ Bus->Devices[Device->Address]->DisconnectFail = TRUE;
+ }
+ return Status;
+}
+
+
+/**
+ Find the child device on the hub's port.
+
+ @param HubIf The hub interface.
+ @param Port The port of the hub this child is connected to.
+
+ @return The device on the hub's port, or NULL if there is none.
+
+**/
+USB_DEVICE *
+UsbFindChild (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ USB_DEVICE *Device;
+ USB_BUS *Bus;
+ UINTN Index;
+
+ Bus = HubIf->Device->Bus;
+
+ //
+ // Start checking from device 1, device 0 is the root hub
+ //
+ for (Index = 1; Index < Bus->MaxDevices; Index++) {
+ Device = Bus->Devices[Index];
+
+ if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&
+ (Device->ParentPort == Port)) {
+
+ return Device;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ Enumerate and configure the new device on the port of this HUB interface.
+
+ @param HubIf The HUB that has the device connected.
+ @param Port The port index of the hub (started with zero).
+ @param ResetIsNeeded The boolean to control whether skip the reset of the port.
+
+ @retval EFI_SUCCESS The device is enumerated (added or removed).
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.
+ @retval Others Failed to enumerate the device.
+
+**/
+EFI_STATUS
+UsbEnumerateNewDev (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN BOOLEAN ResetIsNeeded
+ )
+{
+ USB_BUS *Bus;
+ USB_HUB_API *HubApi;
+ USB_DEVICE *Child;
+ USB_DEVICE *Parent;
+ EFI_USB_PORT_STATUS PortState;
+ UINTN Address;
+ UINT8 Config;
+ EFI_STATUS Status;
+
+ Parent = HubIf->Device;
+ Bus = Parent->Bus;
+ HubApi = HubIf->HubApi;
+ Address = Bus->MaxDevices;
+
+ gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
+
+ //
+ // Hub resets the device for at least 10 milliseconds.
+ // Host learns device speed. If device is of low/full speed
+ // and the hub is a EHCI root hub, ResetPort will release
+ // the device to its companion UHCI and return an error.
+ //
+ if (ResetIsNeeded) {
+ Status = HubApi->ResetPort (HubIf, Port);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
+
+ return Status;
+ }
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
+ } else {
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d reset is skipped\n", Port));
+ }
+
+ Child = UsbCreateDevice (HubIf, Port);
+
+ if (Child == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // OK, now identify the device speed. After reset, hub
+ // fully knows the actual device speed.
+ //
+ Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
+ goto ON_ERROR;
+ }
+
+ if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: No device present at port %d\n", Port));
+ Status = EFI_NOT_FOUND;
+ goto ON_ERROR;
+ } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
+ Child->Speed = EFI_USB_SPEED_SUPER;
+ Child->MaxPacket0 = 512;
+ } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
+ Child->Speed = EFI_USB_SPEED_HIGH;
+ Child->MaxPacket0 = 64;
+ } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
+ Child->Speed = EFI_USB_SPEED_LOW;
+ Child->MaxPacket0 = 8;
+ } else {
+ Child->Speed = EFI_USB_SPEED_FULL;
+ Child->MaxPacket0 = 8;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
+
+ if (((Child->Speed == EFI_USB_SPEED_LOW) || (Child->Speed == EFI_USB_SPEED_FULL)) &&
+ (Parent->Speed == EFI_USB_SPEED_HIGH)) {
+ //
+ // If the child is a low or full speed device, it is necessary to
+ // set the transaction translator. Port TT is 1-based.
+ // This is quite simple:
+ // 1. if parent is of high speed, then parent is our translator
+ // 2. otherwise use parent's translator.
+ //
+ Child->Translator.TranslatorHubAddress = Parent->Address;
+ Child->Translator.TranslatorPortNumber = (UINT8) (Port + 1);
+ } else {
+ Child->Translator = Parent->Translator;
+ }
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
+ Child->Translator.TranslatorHubAddress,
+ Child->Translator.TranslatorPortNumber));
+
+ //
+ // After port is reset, hub establishes a signal path between
+ // the device and host (DEFAULT state). Device's registers are
+ // reset, use default address 0 (host enumerates one device at
+ // a time) , and ready to respond to control transfer at EP 0.
+ //
+
+ //
+ // Host assigns an address to the device. Device completes the
+ // status stage with default address, then switches to new address.
+ // ADDRESS state. Address zero is reserved for root hub.
+ //
+ ASSERT (Bus->MaxDevices <= 256);
+ for (Address = 1; Address < Bus->MaxDevices; Address++) {
+ if (Bus->Devices[Address] == NULL) {
+ break;
+ }
+ }
+
+ if (Address >= Bus->MaxDevices) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
+
+ Status = EFI_ACCESS_DENIED;
+ goto ON_ERROR;
+ }
+
+ Status = UsbSetAddress (Child, (UINT8)Address);
+ Child->Address = (UINT8)Address;
+ Bus->Devices[Address] = Child;
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
+
+ DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
+
+ //
+ // Host sends a Get_Descriptor request to learn the max packet
+ // size of default pipe (only part of the device's descriptor).
+ //
+ Status = UsbGetMaxPacketSize0 (Child);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
+
+ //
+ // Host learns about the device's abilities by requesting device's
+ // entire descriptions.
+ //
+ Status = UsbBuildDescTable (Child);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ //
+ // Select a default configuration: UEFI must set the configuration
+ // before the driver can connect to the device.
+ //
+ Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
+ Status = UsbSetConfig (Child, Config);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
+ goto ON_ERROR;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
+
+ //
+ // Host assigns and loads a device driver.
+ //
+ Status = UsbSelectConfig (Child, Config);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ //
+ // Report Status Code to indicate USB device has been detected by hotplug
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG),
+ Bus->DevicePath
+ );
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ //
+ // If reach here, it means the enumeration process on a given port is interrupted due to error.
+ // The s/w resources, including the assigned address(Address) and the allocated usb device data
+ // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when
+ // the device is unplugged from the port or DriverBindingStop() is invoked.
+ //
+ // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.
+ // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine
+ // to keep track of the mapping between actual address and request address. If the request address
+ // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI
+ // host controller driver will have wrong information, which will cause further transaction error.
+ //
+ // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.
+ //
+ return Status;
+}
+
+
+/**
+ Process the events on the port.
+
+ @param HubIf The HUB that has the device connected.
+ @param Port The port index of the hub (started with zero).
+
+ @retval EFI_SUCCESS The device is enumerated (added or removed).
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.
+ @retval Others Failed to enumerate the device.
+
+**/
+EFI_STATUS
+UsbEnumeratePort (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ USB_HUB_API *HubApi;
+ USB_DEVICE *Child;
+ EFI_USB_PORT_STATUS PortState;
+ EFI_STATUS Status;
+
+ Child = NULL;
+ HubApi = HubIf->HubApi;
+
+ //
+ // Host learns of the new device by polling the hub for port changes.
+ //
+ Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
+ return Status;
+ }
+
+ //
+ // Only handle connection/enable/overcurrent/reset change.
+ // Usb super speed hub may report other changes, such as warm reset change. Ignore them.
+ //
+ if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
+ Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));
+
+ //
+ // This driver only process two kinds of events now: over current and
+ // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
+ // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
+ //
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
+
+ if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
+ //
+ // Case1:
+ // Both OverCurrent and OverCurrentChange set, means over current occurs,
+ // which probably is caused by short circuit. It has to wait system hardware
+ // to perform recovery.
+ //
+ DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
+ return EFI_DEVICE_ERROR;
+
+ }
+ //
+ // Case2:
+ // Only OverCurrentChange set, means system has been recoveried from
+ // over current. As a result, all ports are nearly power-off, so
+ // it's necessary to detach and enumerate all ports again.
+ //
+ DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
+ }
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
+ //
+ // Case3:
+ // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart
+ // on 2.0 roothub does. When over-current has influence on 1.1 device, the port
+ // would be disabled, so it's also necessary to detach and enumerate again.
+ //
+ DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
+ }
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
+ //
+ // Case4:
+ // Device connected or disconnected normally.
+ //
+ DEBUG ((EFI_D_INFO, "UsbEnumeratePort: Device Connect/Disconnect Normally\n", Port));
+ }
+
+ //
+ // Following as the above cases, it's safety to remove and create again.
+ //
+ Child = UsbFindChild (HubIf, Port);
+
+ if (Child != NULL) {
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf));
+ UsbRemoveDevice (Child);
+ }
+
+ if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
+ //
+ // Now, new device connected, enumerate and configure the device
+ //
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
+ Status = UsbEnumerateNewDev (HubIf, Port, FALSE);
+ } else {
+ Status = UsbEnumerateNewDev (HubIf, Port, TRUE);
+ }
+
+ } else {
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
+ }
+
+ HubApi->ClearPortChange (HubIf, Port);
+ return Status;
+}
+
+
+/**
+ Enumerate all the changed hub ports.
+
+ @param Event The event that is triggered.
+ @param Context The context to the event.
+
+**/
+VOID
+EFIAPI
+UsbHubEnumeration (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_INTERFACE *HubIf;
+ UINT8 Byte;
+ UINT8 Bit;
+ UINT8 Index;
+ USB_DEVICE *Child;
+
+ ASSERT (Context != NULL);
+
+ HubIf = (USB_INTERFACE *) Context;
+
+ for (Index = 0; Index < HubIf->NumOfPort; Index++) {
+ Child = UsbFindChild (HubIf, Index);
+ if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));
+ UsbRemoveDevice (Child);
+ }
+ }
+
+ if (HubIf->ChangeMap == NULL) {
+ return ;
+ }
+
+ //
+ // HUB starts its port index with 1.
+ //
+ Byte = 0;
+ Bit = 1;
+
+ for (Index = 0; Index < HubIf->NumOfPort; Index++) {
+ if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
+ UsbEnumeratePort (HubIf, Index);
+ }
+
+ USB_NEXT_BIT (Byte, Bit);
+ }
+
+ UsbHubAckHubStatus (HubIf->Device);
+
+ gBS->FreePool (HubIf->ChangeMap);
+ HubIf->ChangeMap = NULL;
+ return ;
+}
+
+
+/**
+ Enumerate all the changed hub ports.
+
+ @param Event The event that is triggered.
+ @param Context The context to the event.
+
+**/
+VOID
+EFIAPI
+UsbRootHubEnumeration (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_INTERFACE *RootHub;
+ UINT8 Index;
+ USB_DEVICE *Child;
+
+ RootHub = (USB_INTERFACE *) Context;
+
+ for (Index = 0; Index < RootHub->NumOfPort; Index++) {
+ Child = UsbFindChild (RootHub, Index);
+ if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
+ DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));
+ UsbRemoveDevice (Child);
+ }
+
+ UsbEnumeratePort (RootHub, Index);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
new file mode 100644
index 000000000..eaba243ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
@@ -0,0 +1,197 @@
+/** @file
+
+ USB bus enumeration interface.
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_ENUMERATION_H_
+#define _USB_ENUMERATION_H_
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define USB_NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+//
+// Common interface used by usb bus enumeration process.
+// This interface is defined to mask the difference between
+// the root hub and normal hub. So, bus enumeration code
+// can be shared by both root hub and normal hub
+//
+typedef
+EFI_STATUS
+(*USB_HUB_INIT) (
+ IN USB_INTERFACE *UsbIf
+ );
+
+//
+// Get the port status. This function is required to
+// ACK the port change bits although it will return
+// the port changes in PortState. Bus enumeration code
+// doesn't need to ACK the port change bits.
+//
+typedef
+EFI_STATUS
+(*USB_HUB_GET_PORT_STATUS) (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 Port,
+ OUT EFI_USB_PORT_STATUS *PortState
+ );
+
+typedef
+VOID
+(*USB_HUB_CLEAR_PORT_CHANGE) (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ );
+
+typedef
+EFI_STATUS
+(*USB_HUB_SET_PORT_FEATURE) (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ );
+
+typedef
+EFI_STATUS
+(*USB_HUB_CLEAR_PORT_FEATURE) (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ );
+
+typedef
+EFI_STATUS
+(*USB_HUB_RESET_PORT) (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 Port
+ );
+
+typedef
+EFI_STATUS
+(*USB_HUB_RELEASE) (
+ IN USB_INTERFACE *UsbIf
+ );
+
+/**
+ Return the endpoint descriptor in this interface.
+
+ @param UsbIf The interface to search in.
+ @param EpAddr The address of the endpoint to return.
+
+ @return The endpoint descriptor or NULL.
+
+**/
+USB_ENDPOINT_DESC*
+UsbGetEndpointDesc (
+ IN USB_INTERFACE *UsbIf,
+ IN UINT8 EpAddr
+ );
+
+/**
+ Select an alternate setting for the interface.
+ Each interface can have several mutually exclusive
+ settings. Only one setting is active. It will
+ also reset its endpoints' toggle to zero.
+
+ @param IfDesc The interface descriptor to set.
+ @param Alternate The alternate setting number to locate.
+
+ @retval EFI_NOT_FOUND There is no setting with this alternate index.
+ @retval EFI_SUCCESS The interface is set to Alternate setting.
+
+**/
+EFI_STATUS
+UsbSelectSetting (
+ IN USB_INTERFACE_DESC *IfDesc,
+ IN UINT8 Alternate
+ );
+
+/**
+ Select a new configuration for the device. Each
+ device may support several configurations.
+
+ @param Device The device to select configuration.
+ @param ConfigIndex The index of the configuration ( != 0).
+
+ @retval EFI_NOT_FOUND There is no configuration with the index.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
+ @retval EFI_SUCCESS The configuration is selected.
+
+**/
+EFI_STATUS
+UsbSelectConfig (
+ IN USB_DEVICE *Device,
+ IN UINT8 ConfigIndex
+ );
+
+/**
+ Remove the current device configuration.
+
+ @param Device The USB device to remove configuration from.
+
+ @return None.
+
+**/
+EFI_STATUS
+UsbRemoveConfig (
+ IN USB_DEVICE *Device
+ );
+
+/**
+ Remove the device and all its children from the bus.
+
+ @param Device The device to remove.
+
+ @retval EFI_SUCCESS The device is removed.
+
+**/
+EFI_STATUS
+UsbRemoveDevice (
+ IN USB_DEVICE *Device
+ );
+
+/**
+ Enumerate all the changed hub ports.
+
+ @param Event The event that is triggered.
+ @param Context The context to the event.
+
+ @return None.
+
+**/
+VOID
+EFIAPI
+UsbHubEnumeration (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Enumerate all the changed hub ports.
+
+ @param Event The event that is triggered.
+ @param Context The context to the event.
+
+ @return None.
+
+**/
+VOID
+EFIAPI
+UsbRootHubEnumeration (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
new file mode 100644
index 000000000..c5bd11251
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
@@ -0,0 +1,1285 @@
+/** @file
+
+ Unified interface for RootHub and Hub.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBus.h"
+
+//
+// Array that maps the change bit to feature value which is
+// used to clear these change bit. USB HUB API will clear
+// these change bit automatically. For non-root hub, these
+// bits determine whether hub will report the port in changed
+// bit maps.
+//
+USB_CHANGE_FEATURE_MAP mHubFeatureMap[] = {
+ {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},
+ {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},
+ {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},
+ {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
+ {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange}
+};
+
+USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[] = {
+ {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},
+ {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},
+ {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},
+ {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
+ {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange},
+};
+
+//
+// USB hub class specific requests. Although USB hub
+// is related to an interface, these requests are sent
+// to the control endpoint of the device.
+//
+/**
+ USB hub control transfer to set the hub depth.
+
+ @param HubDev The device of the hub.
+ @param Depth The depth to set.
+
+ @retval EFI_SUCCESS Depth of the hub is set.
+ @retval Others Failed to set the depth.
+
+**/
+EFI_STATUS
+UsbHubCtrlSetHubDepth (
+ IN USB_DEVICE *HubDev,
+ IN UINT16 Depth
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_SET_DEPTH,
+ Depth,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ USB hub control transfer to clear the hub feature.
+
+ @param HubDev The device of the hub.
+ @param Feature The feature to clear.
+
+ @retval EFI_SUCCESS Feature of the hub is cleared.
+ @retval Others Failed to clear the feature.
+
+**/
+EFI_STATUS
+UsbHubCtrlClearHubFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT16 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_CLEAR_FEATURE,
+ Feature,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Clear the feature of the device's port.
+
+ @param HubDev The hub device.
+ @param Port The port to clear feature.
+ @param Feature The feature to clear.
+
+ @retval EFI_SUCCESS The feature of the port is cleared.
+ @retval Others Failed to clear the feature.
+
+**/
+EFI_STATUS
+UsbHubCtrlClearPortFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT16 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_CLEAR_FEATURE,
+ Feature,
+ (UINT16) (Port + 1),
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Clear the transaction translate buffer if full/low
+ speed control/bulk transfer failed and the transfer
+ uses this hub as translator.Remember to clear the TT
+ buffer of transaction translator, not that of the
+ parent.
+
+ @param HubDev The hub device.
+ @param Port The port of the hub.
+ @param DevAddr Address of the failed transaction.
+ @param EpNum The endpoint number of the failed transaction.
+ @param EpType The type of failed transaction.
+
+ @retval EFI_SUCCESS The TT buffer is cleared.
+ @retval Others Failed to clear the TT buffer.
+
+**/
+EFI_STATUS
+UsbHubCtrlClearTTBuffer (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT16 DevAddr,
+ IN UINT16 EpNum,
+ IN UINT16 EpType
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Value;
+
+ //
+ // Check USB2.0 spec page 424 for wValue's encoding
+ //
+ Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |
+ ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_CLEAR_TT,
+ Value,
+ (UINT16) (Port + 1),
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Usb hub control transfer to get the (super speed) hub descriptor.
+
+ @param HubDev The hub device.
+ @param Buf The buffer to hold the descriptor.
+ @param Len The length to retrieve.
+
+ @retval EFI_SUCCESS The hub descriptor is retrieved.
+ @retval Others Failed to retrieve the hub descriptor.
+
+**/
+EFI_STATUS
+UsbHubCtrlGetHubDesc (
+ IN USB_DEVICE *HubDev,
+ OUT VOID *Buf,
+ IN UINTN Len
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DescType;
+
+ DescType = (HubDev->Speed == EFI_USB_SPEED_SUPER) ?
+ USB_DESC_TYPE_HUB_SUPER_SPEED :
+ USB_DESC_TYPE_HUB;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_GET_DESC,
+ (UINT16) (DescType << 8),
+ 0,
+ Buf,
+ Len
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to get the hub status.
+
+ @param HubDev The hub device.
+ @param State The variable to return the status.
+
+ @retval EFI_SUCCESS The hub status is returned in State.
+ @retval Others Failed to get the hub status.
+
+**/
+EFI_STATUS
+UsbHubCtrlGetHubStatus (
+ IN USB_DEVICE *HubDev,
+ OUT UINT32 *State
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_GET_STATUS,
+ 0,
+ 0,
+ State,
+ 4
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to get the port status.
+
+ @param HubDev The hub device.
+ @param Port The port of the hub.
+ @param State Variable to return the hub port state.
+
+ @retval EFI_SUCCESS The port state is returned in State.
+ @retval Others Failed to retrieve the port state.
+
+**/
+EFI_STATUS
+UsbHubCtrlGetPortStatus (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ OUT VOID *State
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ // No need to convert the hub bit to UEFI definition, they
+ // are the same
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_GET_STATUS,
+ 0,
+ (UINT16) (Port + 1),
+ State,
+ 4
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to set the port feature.
+
+ @param HubDev The Usb hub device.
+ @param Port The Usb port to set feature for.
+ @param Feature The feature to set.
+
+ @retval EFI_SUCCESS The feature is set for the port.
+ @retval Others Failed to set the feature.
+
+**/
+EFI_STATUS
+UsbHubCtrlSetPortFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT8 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_SET_FEATURE,
+ Feature,
+ (UINT16) (Port + 1),
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Read the whole usb hub descriptor. It is necessary
+ to do it in two steps because hub descriptor is of
+ variable length.
+
+ @param HubDev The hub device.
+ @param HubDesc The variable to return the descriptor.
+
+ @retval EFI_SUCCESS The hub descriptor is read.
+ @retval Others Failed to read the hub descriptor.
+
+**/
+EFI_STATUS
+UsbHubReadDesc (
+ IN USB_DEVICE *HubDev,
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDesc
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // First get the hub descriptor length
+ //
+ Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the whole hub descriptor
+ //
+ return UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
+}
+
+
+
+/**
+ Ack the hub change bits. If these bits are not ACKed, Hub will
+ always return changed bit map from its interrupt endpoint.
+
+ @param HubDev The hub device.
+
+ @retval EFI_SUCCESS The hub change status is ACKed.
+ @retval Others Failed to ACK the hub status.
+
+**/
+EFI_STATUS
+UsbHubAckHubStatus (
+ IN USB_DEVICE *HubDev
+ )
+{
+ EFI_USB_PORT_STATUS HubState;
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
+ UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
+ }
+
+ if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
+ UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test whether the interface is a hub interface.
+
+ @param UsbIf The interface to test.
+
+ @retval TRUE The interface is a hub interface.
+ @retval FALSE The interface isn't a hub interface.
+
+**/
+BOOLEAN
+UsbIsHubInterface (
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_USB_INTERFACE_DESCRIPTOR *Setting;
+
+ //
+ // If the hub is a high-speed hub with multiple TT,
+ // the hub will has a default setting of single TT.
+ //
+ Setting = &UsbIf->IfSetting->Desc;
+
+ if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
+ (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ The callback function to the USB hub status change
+ interrupt endpoint. It is called periodically by
+ the underlying host controller.
+
+ @param Data The data read.
+ @param DataLength The length of the data read.
+ @param Context The context.
+ @param Result The result of the last interrupt transfer.
+
+ @retval EFI_SUCCESS The process is OK.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbOnHubInterrupt (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_INTERFACE *HubIf;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ EFI_STATUS Status;
+
+ HubIf = (USB_INTERFACE *) Context;
+ UsbIo = &(HubIf->UsbIo);
+ EpDesc = &(HubIf->HubEp->Desc);
+
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // If endpoint is stalled, clear the stall. Use UsbIo to access
+ // the control transfer so internal status are maintained.
+ //
+ if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
+ UsbIoClearFeature (
+ UsbIo,
+ USB_TARGET_ENDPOINT,
+ USB_FEATURE_ENDPOINT_HALT,
+ EpDesc->EndpointAddress
+ );
+ }
+
+ //
+ // Delete and submit a new async interrupt
+ //
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
+ return Status;
+ }
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->EndpointAddress,
+ TRUE,
+ USB_HUB_POLL_INTERVAL,
+ HubIf->NumOfPort / 8 + 1,
+ UsbOnHubInterrupt,
+ HubIf
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
+ }
+
+ return Status;
+ }
+
+ if ((DataLength == 0) || (Data == NULL)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // OK, actually something is changed, save the change map
+ // then signal the HUB to do enumeration. This is a good
+ // practise since UsbOnHubInterrupt is called in the context
+ // of host controller's AsyncInterrupt monitor.
+ //
+ HubIf->ChangeMap = AllocateZeroPool (DataLength);
+
+ if (HubIf->ChangeMap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (HubIf->ChangeMap, Data, DataLength);
+ gBS->SignalEvent (HubIf->HubNotify);
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Initialize the device for a non-root hub.
+
+ @param HubIf The USB hub interface.
+
+ @retval EFI_SUCCESS The hub is initialized.
+ @retval EFI_DEVICE_ERROR Failed to initialize the hub.
+
+**/
+EFI_STATUS
+UsbHubInit (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ UINT8 HubDescBuffer[256];
+ EFI_USB_HUB_DESCRIPTOR *HubDesc;
+ USB_ENDPOINT_DESC *EpDesc;
+ USB_INTERFACE_SETTING *Setting;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_DEVICE *HubDev;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 NumEndpoints;
+ UINT16 Depth;
+
+ //
+ // Locate the interrupt endpoint for port change map
+ //
+ HubIf->IsHub = FALSE;
+ Setting = HubIf->IfSetting;
+ HubDev = HubIf->Device;
+ EpDesc = NULL;
+ NumEndpoints = Setting->Desc.NumEndpoints;
+
+ for (Index = 0; Index < NumEndpoints; Index++) {
+ ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
+
+ EpDesc = Setting->Endpoints[Index];
+
+ if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
+ (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
+ break;
+ }
+ }
+
+ if (Index == NumEndpoints) {
+ DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // The length field of descriptor is UINT8 type, so the buffer
+ // with 256 bytes is enough to hold the descriptor data.
+ //
+ HubDesc = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;
+ Status = UsbHubReadDesc (HubDev, HubDesc);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));
+ return Status;
+ }
+
+ HubIf->NumOfPort = HubDesc->NumPorts;
+
+ DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
+
+ //
+ // OK, set IsHub to TRUE. Now usb bus can handle this device
+ // as a working HUB. If failed earlier, bus driver will not
+ // recognize it as a hub. Other parts of the bus should be able
+ // to work.
+ //
+ HubIf->IsHub = TRUE;
+ HubIf->HubApi = &mUsbHubApi;
+ HubIf->HubEp = EpDesc;
+
+ if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
+ Depth = (UINT16)(HubIf->Device->Tier - 1);
+ DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
+ UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
+
+ for (Index = 0; Index < HubDesc->NumPorts; Index++) {
+ UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
+ }
+ } else {
+ //
+ // Feed power to all the hub ports. It should be ok
+ // for both gang/individual powered hubs.
+ //
+ for (Index = 0; Index < HubDesc->NumPorts; Index++) {
+ UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);
+ }
+
+ //
+ // Update for the usb hub has no power on delay requirement
+ //
+ if (HubDesc->PwrOn2PwrGood > 0) {
+ gBS->Stall (HubDesc->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
+ }
+ UsbHubAckHubStatus (HubIf->Device);
+ }
+
+ //
+ // Create an event to enumerate the hub's port. On
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ UsbHubEnumeration,
+ HubIf,
+ &HubIf->HubNotify
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",
+ HubDev->Address, Status));
+
+ return Status;
+ }
+
+ //
+ // Create AsyncInterrupt to query hub port change endpoint
+ // periodically. If the hub ports are changed, hub will return
+ // changed port map from the interrupt endpoint. The port map
+ // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
+ // host change status).
+ //
+ UsbIo = &HubIf->UsbIo;
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->Desc.EndpointAddress,
+ TRUE,
+ USB_HUB_POLL_INTERVAL,
+ HubIf->NumOfPort / 8 + 1,
+ UsbOnHubInterrupt,
+ HubIf
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
+ HubDev->Address, Status));
+
+ gBS->CloseEvent (HubIf->HubNotify);
+ HubIf->HubNotify = NULL;
+
+ return Status;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
+ return Status;
+}
+
+
+
+/**
+ Get the port status. This function is required to
+ ACK the port change bits although it will return
+ the port changes in PortState. Bus enumeration code
+ doesn't need to ACK the port change bits.
+
+ @param HubIf The hub interface.
+ @param Port The port of the hub to get state.
+ @param PortState Variable to return the port state.
+
+ @retval EFI_SUCCESS The port status is successfully returned.
+ @retval Others Failed to return the status.
+
+**/
+EFI_STATUS
+UsbHubGetPortStatus (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ OUT EFI_USB_PORT_STATUS *PortState
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
+
+ return Status;
+}
+
+
+
+/**
+ Clear the port change status.
+
+ @param HubIf The hub interface.
+ @param Port The hub port.
+
+**/
+VOID
+UsbHubClearPortChange (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ USB_CHANGE_FEATURE_MAP *Map;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // OK, get the usb port status, now ACK the change bits.
+ // Don't return error when failed to clear the change bits.
+ // It may lead to extra port state report. USB bus should
+ // be able to handle this.
+ //
+ for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {
+ Map = &mHubFeatureMap[Index];
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
+ UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);
+ }
+ }
+}
+
+
+
+/**
+ Function to set the port feature for non-root hub.
+
+ @param HubIf The hub interface.
+ @param Port The port of the hub.
+ @param Feature The feature of the port to set.
+
+ @retval EFI_SUCCESS The hub port feature is set.
+ @retval Others Failed to set the port feature.
+
+**/
+EFI_STATUS
+UsbHubSetPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface function to clear the port feature for non-root hub.
+
+ @param HubIf The hub interface.
+ @param Port The port of the hub to clear feature for.
+ @param Feature The feature to clear.
+
+ @retval EFI_SUCCESS The port feature is cleared.
+ @retval Others Failed to clear the port feature.
+
+**/
+EFI_STATUS
+UsbHubClearPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface function to reset the port.
+
+ @param HubIf The hub interface.
+ @param Port The port to reset.
+
+ @retval EFI_SUCCESS The hub port is reset.
+ @retval EFI_TIMEOUT Failed to reset the port in time.
+ @retval Others Failed to reset the port.
+
+**/
+EFI_STATUS
+UsbHubResetPort (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ gBS->Stall (USB_SET_PORT_RESET_STALL);
+
+ //
+ // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
+ //
+ ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
+ Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!EFI_ERROR (Status) &&
+ USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
+ gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Release the hub's control of the interface.
+
+ @param HubIf The hub interface.
+
+ @retval EFI_SUCCESS The interface is release of hub control.
+
+**/
+EFI_STATUS
+UsbHubRelease (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_STATUS Status;
+
+ UsbIo = &HubIf->UsbIo;
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ HubIf->HubEp->Desc.EndpointAddress,
+ FALSE,
+ USB_HUB_POLL_INTERVAL,
+ 0,
+ NULL,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseEvent (HubIf->HubNotify);
+
+ HubIf->IsHub = FALSE;
+ HubIf->HubApi = NULL;
+ HubIf->HubEp = NULL;
+ HubIf->HubNotify = NULL;
+
+ DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Initialize the interface for root hub.
+
+ @param HubIf The root hub interface.
+
+ @retval EFI_SUCCESS The interface is initialized for root hub.
+ @retval Others Failed to initialize the hub.
+
+**/
+EFI_STATUS
+UsbRootHubInit (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MaxSpeed;
+ UINT8 NumOfPort;
+ UINT8 Support64;
+
+ Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
+ HubIf, MaxSpeed, NumOfPort));
+
+ HubIf->IsHub = TRUE;
+ HubIf->HubApi = &mUsbRootHubApi;
+ HubIf->HubEp = NULL;
+ HubIf->MaxSpeed = MaxSpeed;
+ HubIf->NumOfPort = NumOfPort;
+ HubIf->HubNotify = NULL;
+
+ //
+ // Create a timer to poll root hub ports periodically
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ UsbRootHubEnumeration,
+ HubIf,
+ &HubIf->HubNotify
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // It should signal the event immediately here, or device detection
+ // by bus enumeration might be delayed by the timer interval.
+ //
+ gBS->SignalEvent (HubIf->HubNotify);
+
+ Status = gBS->SetTimer (
+ HubIf->HubNotify,
+ TimerPeriodic,
+ USB_ROOTHUB_POLL_INTERVAL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (HubIf->HubNotify);
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the port status. This function is required to
+ ACK the port change bits although it will return
+ the port changes in PortState. Bus enumeration code
+ doesn't need to ACK the port change bits.
+
+ @param HubIf The root hub interface.
+ @param Port The root hub port to get the state.
+ @param PortState Variable to return the port state.
+
+ @retval EFI_SUCCESS The port state is returned.
+ @retval Others Failed to retrieve the port state.
+
+**/
+EFI_STATUS
+UsbRootHubGetPortStatus (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ OUT EFI_USB_PORT_STATUS *PortState
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+
+ Bus = HubIf->Device->Bus;
+ Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
+
+ return Status;
+}
+
+
+/**
+ Clear the port change status.
+
+ @param HubIf The root hub interface.
+ @param Port The root hub port.
+
+**/
+VOID
+UsbRootHubClearPortChange (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ USB_CHANGE_FEATURE_MAP *Map;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // OK, get the usb port status, now ACK the change bits.
+ // Don't return error when failed to clear the change bits.
+ // It may lead to extra port state report. USB bus should
+ // be able to handle this.
+ //
+ for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {
+ Map = &mRootHubFeatureMap[Index];
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
+ UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);
+ }
+ }
+}
+
+
+/**
+ Set the root hub port feature.
+
+ @param HubIf The Usb hub interface.
+ @param Port The hub port.
+ @param Feature The feature to set.
+
+ @retval EFI_SUCCESS The root hub port is set with the feature.
+ @retval Others Failed to set the feature.
+
+**/
+EFI_STATUS
+UsbRootHubSetPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Clear the root hub port feature.
+
+ @param HubIf The root hub interface.
+ @param Port The root hub port.
+ @param Feature The feature to clear.
+
+ @retval EFI_SUCCESS The root hub port is cleared of the feature.
+ @retval Others Failed to clear the feature.
+
+**/
+EFI_STATUS
+UsbRootHubClearPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface function to reset the root hub port.
+
+ @param RootIf The root hub interface.
+ @param Port The port to reset.
+
+ @retval EFI_SUCCESS The hub port is reset.
+ @retval EFI_TIMEOUT Failed to reset the port in time.
+ @retval EFI_NOT_FOUND The low/full speed device connected to high speed.
+ root hub is released to the companion UHCI.
+ @retval Others Failed to reset the port.
+
+**/
+EFI_STATUS
+UsbRootHubResetPort (
+ IN USB_INTERFACE *RootIf,
+ IN UINT8 Port
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+ EFI_USB_PORT_STATUS PortState;
+ UINTN Index;
+
+ //
+ // Notice: although EHCI requires that ENABLED bit be cleared
+ // when reset the port, we don't need to care that here. It
+ // should be handled in the EHCI driver.
+ //
+ Bus = RootIf->Device->Bus;
+
+ Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
+ return Status;
+ }
+
+ //
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
+
+ Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
+ return Status;
+ }
+
+ gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
+
+ //
+ // USB host controller won't clear the RESET bit until
+ // reset is actually finished.
+ //
+ ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
+ Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
+ break;
+ }
+
+ gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
+ }
+
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
+ DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
+ return EFI_TIMEOUT;
+ }
+
+ if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
+ //
+ // OK, the port is reset. If root hub is of high speed and
+ // the device is of low/full speed, release the ownership to
+ // companion UHCI. If root hub is of full speed, it won't
+ // automatically enable the port, we need to enable it manually.
+ //
+ if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
+ DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
+
+ UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
+ return EFI_NOT_FOUND;
+
+ } else {
+
+ Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
+ return Status;
+ }
+
+ gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Release the root hub's control of the interface.
+
+ @param HubIf The root hub interface.
+
+ @retval EFI_SUCCESS The root hub's control of the interface is
+ released.
+
+**/
+EFI_STATUS
+UsbRootHubRelease (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
+
+ gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
+ gBS->CloseEvent (HubIf->HubNotify);
+
+ return EFI_SUCCESS;
+}
+
+USB_HUB_API mUsbHubApi = {
+ UsbHubInit,
+ UsbHubGetPortStatus,
+ UsbHubClearPortChange,
+ UsbHubSetPortFeature,
+ UsbHubClearPortFeature,
+ UsbHubResetPort,
+ UsbHubRelease
+};
+
+USB_HUB_API mUsbRootHubApi = {
+ UsbRootHubInit,
+ UsbRootHubGetPortStatus,
+ UsbRootHubClearPortChange,
+ UsbRootHubSetPortFeature,
+ UsbRootHubClearPortFeature,
+ UsbRootHubResetPort,
+ UsbRootHubRelease
+};
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h
new file mode 100644
index 000000000..6043b5b2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h
@@ -0,0 +1,181 @@
+/** @file
+
+ The definition for USB hub.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_HUB_H_
+#define _USB_HUB_H_
+
+#include <IndustryStandard/Usb.h>
+
+#define USB_ENDPOINT_ADDR(EpAddr) ((EpAddr) & 0x7F)
+#define USB_ENDPOINT_TYPE(Desc) ((Desc)->Attributes & USB_ENDPOINT_TYPE_MASK)
+
+
+#define USB_DESC_TYPE_HUB 0x29
+
+#define USB_DESC_TYPE_HUB_SUPER_SPEED 0x2a
+
+//
+// Hub class control transfer target
+//
+#define USB_HUB_TARGET_HUB 0
+#define USB_HUB_TARGET_PORT 3
+//
+// HUB class specific contrl transfer request type
+//
+#define USB_HUB_REQ_GET_STATUS 0
+#define USB_HUB_REQ_CLEAR_FEATURE 1
+#define USB_HUB_REQ_SET_FEATURE 3
+#define USB_HUB_REQ_GET_DESC 6
+#define USB_HUB_REQ_SET_DESC 7
+#define USB_HUB_REQ_CLEAR_TT 8
+#define USB_HUB_REQ_RESET_TT 9
+#define USB_HUB_REQ_GET_TT_STATE 10
+#define USB_HUB_REQ_STOP_TT 11
+
+#define USB_HUB_REQ_SET_DEPTH 12
+
+//
+// USB hub class feature selector
+//
+#define USB_HUB_C_HUB_LOCAL_POWER 0
+#define USB_HUB_C_HUB_OVER_CURRENT 1
+#define USB_HUB_PORT_CONNECTION 0
+#define USB_HUB_PORT_ENABLE 1
+#define USB_HUB_PORT_SUSPEND 2
+#define USB_HUB_PORT_OVER_CURRENT 3
+#define USB_HUB_PORT_RESET 4
+
+#define USB_HUB_PORT_LINK_STATE 5
+
+#define USB_HUB_PORT_POWER 8
+#define USB_HUB_PORT_LOW_SPEED 9
+#define USB_HUB_C_PORT_CONNECT 16
+#define USB_HUB_C_PORT_ENABLE 17
+#define USB_HUB_C_PORT_SUSPEND 18
+#define USB_HUB_C_PORT_OVER_CURRENT 19
+#define USB_HUB_C_PORT_RESET 20
+#define USB_HUB_PORT_TEST 21
+#define USB_HUB_PORT_INDICATOR 22
+
+#define USB_HUB_C_PORT_LINK_STATE 25
+#define USB_HUB_PORT_REMOTE_WAKE_MASK 27
+#define USB_HUB_BH_PORT_RESET 28
+#define USB_HUB_C_BH_PORT_RESET 29
+
+//
+// Constant value for Port Status & Port Change Status of SuperSpeed port
+//
+#define USB_SS_PORT_STAT_C_BH_RESET 0x0020
+#define USB_SS_PORT_STAT_C_PORT_LINK_STATE 0x0040
+//
+// USB hub power control method. In gang power control
+//
+#define USB_HUB_GANG_POWER_CTRL 0
+#define USB_HUB_PORT_POWER_CTRL 0x01
+//
+// USB hub status bits
+//
+#define USB_HUB_STAT_LOCAL_POWER 0x01
+#define USB_HUB_STAT_OVER_CURRENT 0x02
+#define USB_HUB_STAT_C_LOCAL_POWER 0x01
+#define USB_HUB_STAT_C_OVER_CURRENT 0x02
+
+#define USB_HUB_CLASS_CODE 0x09
+#define USB_HUB_SUBCLASS_CODE 0x00
+
+//
+// Host software return timeout if port status doesn't change
+// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience
+//
+#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000
+
+#pragma pack(1)
+//
+// Hub descriptor, the last two fields are of variable length.
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescType;
+ UINT8 NumPorts;
+ UINT16 HubCharacter;
+ UINT8 PwrOn2PwrGood;
+ UINT8 HubContrCurrent;
+ UINT8 Filler[16];
+} EFI_USB_HUB_DESCRIPTOR;
+
+#pragma pack()
+
+
+typedef struct {
+ UINT16 ChangedBit;
+ EFI_USB_PORT_FEATURE Feature;
+} USB_CHANGE_FEATURE_MAP;
+
+
+/**
+ Clear the transaction translate buffer if full/low
+ speed control/bulk transfer failed and the transfer
+ uses this hub as translator.Remember to clear the TT
+ buffer of transaction translator, not that of the
+ parent.
+
+ @param UsbDev The Usb device.
+ @param Port The port of the hub.
+ @param DevAddr Address of the failed transaction.
+ @param EpNum The endpoint number of the failed transaction.
+ @param EpType The type of failed transaction.
+
+ @retval EFI_SUCCESS The TT buffer is cleared.
+ @retval Others Failed to clear the TT buffer.
+
+**/
+EFI_STATUS
+UsbHubCtrlClearTTBuffer (
+ IN USB_DEVICE *UsbDev,
+ IN UINT8 Port,
+ IN UINT16 DevAddr,
+ IN UINT16 EpNum,
+ IN UINT16 EpType
+ );
+
+
+/**
+ Test whether the interface is a hub interface.
+
+ @param UsbIf The interface to test.
+
+ @retval TRUE The interface is a hub interface.
+ @retval FALSE The interface isn't a hub interface.
+
+**/
+BOOLEAN
+UsbIsHubInterface (
+ IN USB_INTERFACE *UsbIf
+ );
+
+
+/**
+ Ack the hub change bits. If these bits are not ACKed, Hub will
+ always return changed bit map from its interrupt endpoint.
+
+ @param UsbDev The Usb device.
+
+ @retval EFI_SUCCESS The hub change status is ACKed.
+ @retval Others Failed to ACK the hub status.
+
+**/
+EFI_STATUS
+UsbHubAckHubStatus (
+ IN USB_DEVICE *UsbDev
+ );
+
+extern USB_HUB_API mUsbHubApi;
+extern USB_HUB_API mUsbRootHubApi;
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c
new file mode 100644
index 000000000..7529e03e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c
@@ -0,0 +1,1227 @@
+/** @file
+
+ Wrapper function for usb host controller interface.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "UsbBus.h"
+
+//
+// if RemainingDevicePath== NULL, then all Usb child devices in this bus are wanted.
+// Use a shor form Usb class Device Path, which could match any usb device, in WantedUsbIoDPList to indicate all Usb devices
+// are wanted Usb devices
+//
+USB_CLASS_FORMAT_DEVICE_PATH mAllUsbClassDevicePath = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_USB_CLASS_DP,
+ {
+ (UINT8) (sizeof (USB_CLASS_DEVICE_PATH)),
+ (UINT8) ((sizeof (USB_CLASS_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0xffff, // VendorId
+ 0xffff, // ProductId
+ 0xff, // DeviceClass
+ 0xff, // DeviceSubClass
+ 0xff // DeviceProtocol
+ },
+
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+
+/**
+ Get the capability of the host controller.
+
+ @param UsbBus The usb driver.
+ @param MaxSpeed The maximum speed this host controller supports.
+ @param NumOfPort The number of the root hub port.
+ @param Is64BitCapable Whether this controller support 64 bit addressing.
+
+ @retval EFI_SUCCESS The host controller capability is returned.
+ @retval Others Failed to retrieve the host controller capability.
+
+**/
+EFI_STATUS
+UsbHcGetCapability (
+ IN USB_BUS *UsbBus,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *NumOfPort,
+ OUT UINT8 *Is64BitCapable
+ )
+{
+ EFI_STATUS Status;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->GetCapability (
+ UsbBus->Usb2Hc,
+ MaxSpeed,
+ NumOfPort,
+ Is64BitCapable
+ );
+
+ } else {
+ Status = UsbBus->UsbHc->GetRootHubPortNumber (UsbBus->UsbHc, NumOfPort);
+
+ *MaxSpeed = EFI_USB_SPEED_FULL;
+ *Is64BitCapable = (UINT8) FALSE;
+ }
+
+ return Status;
+}
+
+
+
+
+
+
+
+
+
+
+/**
+ Get the root hub port state.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The index of port.
+ @param PortStatus The variable to save port state.
+
+ @retval EFI_SUCCESS The root port state is returned in.
+ @retval Others Failed to get the root hub port state.
+
+**/
+EFI_STATUS
+UsbHcGetRootHubPortStatus (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ EFI_STATUS Status;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->GetRootHubPortStatus (UsbBus->Usb2Hc, PortIndex, PortStatus);
+ } else {
+ Status = UsbBus->UsbHc->GetRootHubPortStatus (UsbBus->UsbHc, PortIndex, PortStatus);
+ }
+
+ return Status;
+}
+
+
+/**
+ Set the root hub port feature.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The port index.
+ @param Feature The port feature to set.
+
+ @retval EFI_SUCCESS The port feature is set.
+ @retval Others Failed to set port feature.
+
+**/
+EFI_STATUS
+UsbHcSetRootHubPortFeature (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->SetRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
+ } else {
+ Status = UsbBus->UsbHc->SetRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
+ }
+
+ return Status;
+}
+
+
+/**
+ Clear the root hub port feature.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The port index.
+ @param Feature The port feature to clear.
+
+ @retval EFI_SUCCESS The port feature is clear.
+ @retval Others Failed to clear port feature.
+
+**/
+EFI_STATUS
+UsbHcClearRootHubPortFeature (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->ClearRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
+ } else {
+ Status = UsbBus->UsbHc->ClearRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute a control transfer to the device.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The device address.
+ @param DevSpeed The device speed.
+ @param MaxPacket Maximum packet size of endpoint 0.
+ @param Request The control transfer request.
+ @param Direction The direction of data stage.
+ @param Data The buffer holding data.
+ @param DataLength The length of the data.
+ @param TimeOut Timeout (in ms) to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of transfer.
+
+ @retval EFI_SUCCESS The control transfer finished without error.
+ @retval Others The control transfer failed, reason returned in UsbReslt.
+
+**/
+EFI_STATUS
+UsbHcControlTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsSlowDevice;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->ControlTransfer (
+ UsbBus->Usb2Hc,
+ DevAddr,
+ DevSpeed,
+ MaxPacket,
+ Request,
+ Direction,
+ Data,
+ DataLength,
+ TimeOut,
+ Translator,
+ UsbResult
+ );
+
+ } else {
+ IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
+ Status = UsbBus->UsbHc->ControlTransfer (
+ UsbBus->UsbHc,
+ DevAddr,
+ IsSlowDevice,
+ (UINT8) MaxPacket,
+ Request,
+ Direction,
+ Data,
+ DataLength,
+ TimeOut,
+ UsbResult
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute a bulk transfer to the device's endpoint.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param BufferNum The number of data buffer.
+ @param Data Array of pointers to data buffer.
+ @param DataLength The length of data buffer.
+ @param DataToggle On input, the initial data toggle to use, also return
+ the next toggle on output.
+ @param TimeOut The time to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of USB execution.
+
+ @retval EFI_SUCCESS The bulk transfer is finished without error.
+ @retval Others Failed to execute bulk transfer, result in UsbResult.
+
+**/
+EFI_STATUS
+UsbHcBulkTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINT8 BufferNum,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ )
+{
+ EFI_STATUS Status;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->BulkTransfer (
+ UsbBus->Usb2Hc,
+ DevAddr,
+ EpAddr,
+ DevSpeed,
+ MaxPacket,
+ BufferNum,
+ Data,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ Translator,
+ UsbResult
+ );
+ } else {
+ Status = UsbBus->UsbHc->BulkTransfer (
+ UsbBus->UsbHc,
+ DevAddr,
+ EpAddr,
+ (UINT8) MaxPacket,
+ *Data,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ UsbResult
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Queue or cancel an asynchronous interrupt transfer.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param IsNewTransfer Whether this is a new request. If not, cancel the old
+ request.
+ @param DataToggle Data toggle to use on input, next toggle on output.
+ @param PollingInterval The interval to poll the interrupt transfer (in ms).
+ @param DataLength The length of periodical data receive.
+ @param Translator The transaction translator for low/full speed device.
+ @param Callback Function to call when data is received.
+ @param Context The context to the callback.
+
+ @retval EFI_SUCCESS The asynchronous transfer is queued.
+ @retval Others Failed to queue the transfer.
+
+**/
+EFI_STATUS
+UsbHcAsyncInterruptTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsSlowDevice;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->AsyncInterruptTransfer (
+ UsbBus->Usb2Hc,
+ DevAddr,
+ EpAddr,
+ DevSpeed,
+ MaxPacket,
+ IsNewTransfer,
+ DataToggle,
+ PollingInterval,
+ DataLength,
+ Translator,
+ Callback,
+ Context
+ );
+ } else {
+ IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
+
+ Status = UsbBus->UsbHc->AsyncInterruptTransfer (
+ UsbBus->UsbHc,
+ DevAddr,
+ EpAddr,
+ IsSlowDevice,
+ (UINT8) MaxPacket,
+ IsNewTransfer,
+ DataToggle,
+ PollingInterval,
+ DataLength,
+ Callback,
+ Context
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute a synchronous interrupt transfer to the target endpoint.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param Data Pointer to data buffer.
+ @param DataLength The length of data buffer.
+ @param DataToggle On input, the initial data toggle to use, also return
+ the next toggle on output.
+ @param TimeOut The time to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of USB execution.
+
+ @retval EFI_SUCCESS The synchronous interrupt transfer is OK.
+ @retval Others Failed to execute the synchronous interrupt transfer.
+
+**/
+EFI_STATUS
+UsbHcSyncInterruptTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsSlowDevice;
+
+ if (UsbBus->Usb2Hc != NULL) {
+ Status = UsbBus->Usb2Hc->SyncInterruptTransfer (
+ UsbBus->Usb2Hc,
+ DevAddr,
+ EpAddr,
+ DevSpeed,
+ MaxPacket,
+ Data,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ Translator,
+ UsbResult
+ );
+ } else {
+ IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DevSpeed) ? TRUE : FALSE);
+ Status = UsbBus->UsbHc->SyncInterruptTransfer (
+ UsbBus->UsbHc,
+ DevAddr,
+ EpAddr,
+ IsSlowDevice,
+ (UINT8) MaxPacket,
+ Data,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ UsbResult
+ );
+ }
+
+ return Status;
+}
+
+
+
+
+
+
+
+
+/**
+ Open the USB host controller protocol BY_CHILD.
+
+ @param Bus The USB bus driver.
+ @param Child The child handle.
+
+ @return The open protocol return.
+
+**/
+EFI_STATUS
+UsbOpenHostProtoByChild (
+ IN USB_BUS *Bus,
+ IN EFI_HANDLE Child
+ )
+{
+ EFI_USB_HC_PROTOCOL *UsbHc;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_STATUS Status;
+
+ if (Bus->Usb2Hc != NULL) {
+ Status = gBS->OpenProtocol (
+ Bus->HostHandle,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ Child,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ } else {
+ Status = gBS->OpenProtocol (
+ Bus->HostHandle,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &UsbHc,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ Child,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Close the USB host controller protocol BY_CHILD.
+
+ @param Bus The USB bus driver.
+ @param Child The child handle.
+
+**/
+VOID
+UsbCloseHostProtoByChild (
+ IN USB_BUS *Bus,
+ IN EFI_HANDLE Child
+ )
+{
+ if (Bus->Usb2Hc != NULL) {
+ gBS->CloseProtocol (
+ Bus->HostHandle,
+ &gEfiUsb2HcProtocolGuid,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ Child
+ );
+
+ } else {
+ gBS->CloseProtocol (
+ Bus->HostHandle,
+ &gEfiUsbHcProtocolGuid,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ Child
+ );
+ }
+}
+
+
+/**
+ return the current TPL, copied from the EDKII glue lib.
+
+ @param VOID.
+
+ @return Current TPL.
+
+**/
+EFI_TPL
+UsbGetCurrentTpl (
+ VOID
+ )
+{
+ EFI_TPL Tpl;
+
+ Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (Tpl);
+
+ return Tpl;
+}
+
+/**
+ Create a new device path which only contain the first Usb part of the DevicePath.
+
+ @param DevicePath A full device path which contain the usb nodes.
+
+ @return A new device path which only contain the Usb part of the DevicePath.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+GetUsbDPFromFullDP (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathPtr;
+ EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathBeginPtr;
+ EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathEndPtr;
+ UINTN Size;
+
+ //
+ // Get the Usb part first Begin node in full device path
+ //
+ UsbDevicePathBeginPtr = DevicePath;
+ while ( (!IsDevicePathEnd (UsbDevicePathBeginPtr))&&
+ ((UsbDevicePathBeginPtr->Type != MESSAGING_DEVICE_PATH) ||
+ (UsbDevicePathBeginPtr->SubType != MSG_USB_DP &&
+ UsbDevicePathBeginPtr->SubType != MSG_USB_CLASS_DP
+ && UsbDevicePathBeginPtr->SubType != MSG_USB_WWID_DP
+ ))) {
+
+ UsbDevicePathBeginPtr = NextDevicePathNode(UsbDevicePathBeginPtr);
+ }
+
+ //
+ // Get the Usb part first End node in full device path
+ //
+ UsbDevicePathEndPtr = UsbDevicePathBeginPtr;
+ while ((!IsDevicePathEnd (UsbDevicePathEndPtr))&&
+ (UsbDevicePathEndPtr->Type == MESSAGING_DEVICE_PATH) &&
+ (UsbDevicePathEndPtr->SubType == MSG_USB_DP ||
+ UsbDevicePathEndPtr->SubType == MSG_USB_CLASS_DP
+ || UsbDevicePathEndPtr->SubType == MSG_USB_WWID_DP
+ )) {
+
+ UsbDevicePathEndPtr = NextDevicePathNode(UsbDevicePathEndPtr);
+ }
+
+ Size = GetDevicePathSize (UsbDevicePathBeginPtr);
+ Size -= GetDevicePathSize (UsbDevicePathEndPtr);
+ if (Size ==0){
+ //
+ // The passed in DevicePath does not contain the usb nodes
+ //
+ return NULL;
+ }
+
+ //
+ // Create a new device path which only contain the above Usb part
+ //
+ UsbDevicePathPtr = AllocateZeroPool (Size + sizeof (EFI_DEVICE_PATH_PROTOCOL));
+ ASSERT (UsbDevicePathPtr != NULL);
+ CopyMem (UsbDevicePathPtr, UsbDevicePathBeginPtr, Size);
+ //
+ // Append end device path node
+ //
+ UsbDevicePathEndPtr = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) UsbDevicePathPtr + Size);
+ SetDevicePathEndNode (UsbDevicePathEndPtr);
+ return UsbDevicePathPtr;
+}
+
+/**
+ Check whether a usb device path is in a DEVICE_PATH_LIST_ITEM list.
+
+ @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM.
+ @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list.
+
+ @retval TRUE there is a DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
+ @retval FALSE there is no DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
+
+**/
+BOOLEAN
+EFIAPI
+SearchUsbDPInList (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbDP,
+ IN LIST_ENTRY *UsbIoDPList
+ )
+{
+ LIST_ENTRY *ListIndex;
+ DEVICE_PATH_LIST_ITEM *ListItem;
+ BOOLEAN Found;
+ UINTN UsbDpDevicePathSize;
+
+ //
+ // Check that UsbDP and UsbIoDPList are valid
+ //
+ if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
+ return FALSE;
+ }
+
+ Found = FALSE;
+ ListIndex = UsbIoDPList->ForwardLink;
+ while (ListIndex != UsbIoDPList){
+ ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
+ //
+ // Compare DEVICE_PATH_LIST_ITEM.DevicePath[]
+ //
+ ASSERT (ListItem->DevicePath != NULL);
+
+ UsbDpDevicePathSize = GetDevicePathSize (UsbDP);
+ if (UsbDpDevicePathSize == GetDevicePathSize (ListItem->DevicePath)) {
+ if ((CompareMem (UsbDP, ListItem->DevicePath, UsbDpDevicePathSize)) == 0) {
+ Found = TRUE;
+ break;
+ }
+ }
+ ListIndex = ListIndex->ForwardLink;
+ }
+
+ return Found;
+}
+
+/**
+ Add a usb device path into the DEVICE_PATH_LIST_ITEM list.
+
+ @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM.
+ @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list.
+
+ @retval EFI_INVALID_PARAMETER If parameters are invalid, return this value.
+ @retval EFI_SUCCESS If Add operation is successful, return this value.
+
+**/
+EFI_STATUS
+EFIAPI
+AddUsbDPToList (
+ IN EFI_DEVICE_PATH_PROTOCOL *UsbDP,
+ IN LIST_ENTRY *UsbIoDPList
+ )
+{
+ DEVICE_PATH_LIST_ITEM *ListItem;
+
+ //
+ // Check that UsbDP and UsbIoDPList are valid
+ //
+ if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SearchUsbDPInList (UsbDP, UsbIoDPList)){
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Prepare the usbio device path DEVICE_PATH_LIST_ITEM structure.
+ //
+ ListItem = AllocateZeroPool (sizeof (DEVICE_PATH_LIST_ITEM));
+ ASSERT (ListItem != NULL);
+ ListItem->Signature = DEVICE_PATH_LIST_ITEM_SIGNATURE;
+ ListItem->DevicePath = DuplicateDevicePath (UsbDP);
+
+ InsertTailList (UsbIoDPList, &ListItem->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether usb device, whose interface is UsbIf, matches the usb class which indicated by
+ UsbClassDevicePathPtr whose is a short form usb class device path.
+
+ @param UsbClassDevicePathPtr a short form usb class device path.
+ @param UsbIf a usb device interface.
+
+ @retval TRUE the usb device match the usb class.
+ @retval FALSE the usb device does not match the usb class.
+
+**/
+BOOLEAN
+EFIAPI
+MatchUsbClass (
+ IN USB_CLASS_DEVICE_PATH *UsbClassDevicePathPtr,
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ USB_INTERFACE_DESC *IfDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc;
+ EFI_USB_DEVICE_DESCRIPTOR *DevDesc;
+
+
+ if ((UsbClassDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
+ (UsbClassDevicePathPtr->Header.SubType != MSG_USB_CLASS_DP)){
+ ASSERT (0);
+ return FALSE;
+ }
+
+ IfDesc = UsbIf->IfDesc;
+ ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
+ ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
+ DevDesc = &(UsbIf->Device->DevDesc->Desc);
+
+ //
+ // If connect class policy, determine whether to create device handle by the five fields
+ // in class device path node.
+ //
+ // In addition, hub interface is always matched for this policy.
+ //
+ if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
+ (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
+ return TRUE;
+ }
+
+ //
+ // If vendor id or product id is 0xffff, they will be ignored.
+ //
+ if ((UsbClassDevicePathPtr->VendorId == 0xffff || UsbClassDevicePathPtr->VendorId == DevDesc->IdVendor) &&
+ (UsbClassDevicePathPtr->ProductId == 0xffff || UsbClassDevicePathPtr->ProductId == DevDesc->IdProduct)) {
+
+ //
+ // If Class in Device Descriptor is set to 0, the counterparts in interface should be checked.
+ //
+ if (DevDesc->DeviceClass == 0) {
+ if ((UsbClassDevicePathPtr->DeviceClass == ActIfDesc->InterfaceClass ||
+ UsbClassDevicePathPtr->DeviceClass == 0xff) &&
+ (UsbClassDevicePathPtr->DeviceSubClass == ActIfDesc->InterfaceSubClass ||
+ UsbClassDevicePathPtr->DeviceSubClass == 0xff) &&
+ (UsbClassDevicePathPtr->DeviceProtocol == ActIfDesc->InterfaceProtocol ||
+ UsbClassDevicePathPtr->DeviceProtocol == 0xff)) {
+ return TRUE;
+ }
+
+ } else if ((UsbClassDevicePathPtr->DeviceClass == DevDesc->DeviceClass ||
+ UsbClassDevicePathPtr->DeviceClass == 0xff) &&
+ (UsbClassDevicePathPtr->DeviceSubClass == DevDesc->DeviceSubClass ||
+ UsbClassDevicePathPtr->DeviceSubClass == 0xff) &&
+ (UsbClassDevicePathPtr->DeviceProtocol == DevDesc->DeviceProtocol ||
+ UsbClassDevicePathPtr->DeviceProtocol == 0xff)) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether usb device, whose interface is UsbIf, matches the usb WWID requirement which indicated by
+ UsbWWIDDevicePathPtr whose is a short form usb WWID device path.
+
+ @param UsbWWIDDevicePathPtr a short form usb WWID device path.
+ @param UsbIf a usb device interface.
+
+ @retval TRUE the usb device match the usb WWID requirement.
+ @retval FALSE the usb device does not match the usb WWID requirement.
+
+**/
+BOOLEAN
+MatchUsbWwid (
+ IN USB_WWID_DEVICE_PATH *UsbWWIDDevicePathPtr,
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ USB_INTERFACE_DESC *IfDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc;
+ EFI_USB_DEVICE_DESCRIPTOR *DevDesc;
+ EFI_USB_STRING_DESCRIPTOR *StrDesc;
+ UINT16 Index;
+ CHAR16 *CompareStr;
+ UINTN CompareLen;
+ UINTN Length;
+
+ if ((UsbWWIDDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
+ (UsbWWIDDevicePathPtr->Header.SubType != MSG_USB_WWID_DP )){
+ ASSERT (0);
+ return FALSE;
+ }
+
+ IfDesc = UsbIf->IfDesc;
+ ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
+ ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
+ DevDesc = &(UsbIf->Device->DevDesc->Desc);
+
+ //
+ // In addition, Hub interface is always matched for this policy.
+ //
+ if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
+ (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
+ return TRUE;
+ }
+
+ //
+ // Check Vendor Id, Product Id and Interface Number.
+ //
+ if ((DevDesc->IdVendor != UsbWWIDDevicePathPtr->VendorId) ||
+ (DevDesc->IdProduct != UsbWWIDDevicePathPtr->ProductId) ||
+ (ActIfDesc->InterfaceNumber != UsbWWIDDevicePathPtr->InterfaceNumber)) {
+ return FALSE;
+ }
+
+ //
+ // Check SerialNumber.
+ //
+ if (DevDesc->StrSerialNumber == 0) {
+ return FALSE;
+ }
+
+ //
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
+ //
+ CompareStr = (CHAR16 *) (UINTN) (UsbWWIDDevicePathPtr + 1);
+ CompareLen = (DevicePathNodeLength (UsbWWIDDevicePathPtr) - 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 < UsbIf->Device->TotalLangId; Index++) {
+ StrDesc = UsbGetOneString (UsbIf->Device, DevDesc->StrSerialNumber, UsbIf->Device->LangId[Index]);
+ if (StrDesc == NULL) {
+ continue;
+ }
+
+ Length = (StrDesc->Length - 2) / sizeof (CHAR16);
+ if ((Length >= CompareLen) &&
+ (CompareMem (StrDesc->String + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Free a DEVICE_PATH_LIST_ITEM list.
+
+ @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list pointer.
+
+ @retval EFI_INVALID_PARAMETER If parameters are invalid, return this value.
+ @retval EFI_SUCCESS If free operation is successful, return this value.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusFreeUsbDPList (
+ IN LIST_ENTRY *UsbIoDPList
+ )
+{
+ LIST_ENTRY *ListIndex;
+ DEVICE_PATH_LIST_ITEM *ListItem;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (UsbIoDPList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ListIndex = UsbIoDPList->ForwardLink;
+ while (ListIndex != UsbIoDPList){
+ ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
+ //
+ // Free DEVICE_PATH_LIST_ITEM.DevicePath[]
+ //
+ if (ListItem->DevicePath != NULL){
+ FreePool(ListItem->DevicePath);
+ }
+ //
+ // Free DEVICE_PATH_LIST_ITEM itself
+ //
+ ListIndex = ListIndex->ForwardLink;
+ RemoveEntryList (&ListItem->Link);
+ FreePool (ListItem);
+ }
+
+ InitializeListHead (UsbIoDPList);
+ return EFI_SUCCESS;
+}
+
+/**
+ Store a wanted usb child device info (its Usb part of device path) which is indicated by
+ RemainingDevicePath in a Usb bus which is indicated by UsbBusId.
+
+ @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS Add operation is successful.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusAddWantedUsbIoDP (
+ IN EFI_USB_BUS_PROTOCOL *UsbBusId,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr;
+
+ //
+ // Check whether remaining device path is valid
+ //
+ if (RemainingDevicePath != NULL && !IsDevicePathEnd (RemainingDevicePath)) {
+ if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ (RemainingDevicePath->SubType != MSG_USB_DP &&
+ RemainingDevicePath->SubType != MSG_USB_CLASS_DP
+ && RemainingDevicePath->SubType != MSG_USB_WWID_DP
+ )) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (UsbBusId == NULL){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Bus = USB_BUS_FROM_THIS (UsbBusId);
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // RemainingDevicePath == NULL means all Usb devices in this bus are wanted.
+ // Here use a Usb class Device Path in WantedUsbIoDPList to indicate all Usb devices
+ // are wanted Usb devices
+ //
+ Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);
+ ASSERT (!EFI_ERROR (Status));
+ DevicePathPtr = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) &mAllUsbClassDevicePath);
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // Create new Usb device path according to the usb part in remaining device path
+ //
+ DevicePathPtr = GetUsbDPFromFullDP (RemainingDevicePath);
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCCESS
+ //
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (DevicePathPtr != NULL);
+ Status = AddUsbDPToList (DevicePathPtr, &Bus->WantedUsbIoDPList);
+ ASSERT (!EFI_ERROR (Status));
+ FreePool (DevicePathPtr);
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether a usb child device is the wanted device in a bus.
+
+ @param Bus The Usb bus's private data pointer.
+ @param UsbIf The usb child device interface.
+
+ @retval True If a usb child device is the wanted device in a bus.
+ @retval False If a usb child device is *NOT* the wanted device in a bus.
+
+**/
+BOOLEAN
+EFIAPI
+UsbBusIsWantedUsbIO (
+ IN USB_BUS *Bus,
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr;
+ LIST_ENTRY *WantedUsbIoDPListPtr;
+ LIST_ENTRY *WantedListIndex;
+ DEVICE_PATH_LIST_ITEM *WantedListItem;
+ BOOLEAN DoConvert;
+ UINTN FirstDevicePathSize;
+
+ //
+ // Check whether passed in parameters are valid
+ //
+ if ((UsbIf == NULL) || (Bus == NULL)) {
+ return FALSE;
+ }
+ //
+ // Check whether UsbIf is Hub
+ //
+ if (UsbIf->IsHub) {
+ return TRUE;
+ }
+
+ //
+ // Check whether all Usb devices in this bus are wanted
+ //
+ if (SearchUsbDPInList ((EFI_DEVICE_PATH_PROTOCOL *)&mAllUsbClassDevicePath, &Bus->WantedUsbIoDPList)){
+ return TRUE;
+ }
+
+ //
+ // Check whether the Usb device match any item in WantedUsbIoDPList
+ //
+ WantedUsbIoDPListPtr = &Bus->WantedUsbIoDPList;
+ //
+ // Create new Usb device path according to the usb part in UsbIo full device path
+ //
+ DevicePathPtr = GetUsbDPFromFullDP (UsbIf->DevicePath);
+ ASSERT (DevicePathPtr != NULL);
+
+ DoConvert = FALSE;
+ WantedListIndex = WantedUsbIoDPListPtr->ForwardLink;
+ while (WantedListIndex != WantedUsbIoDPListPtr){
+ WantedListItem = CR(WantedListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
+ ASSERT (WantedListItem->DevicePath->Type == MESSAGING_DEVICE_PATH);
+ switch (WantedListItem->DevicePath->SubType) {
+ case MSG_USB_DP:
+ FirstDevicePathSize = GetDevicePathSize (WantedListItem->DevicePath);
+ if (FirstDevicePathSize == GetDevicePathSize (DevicePathPtr)) {
+ if (CompareMem (
+ WantedListItem->DevicePath,
+ DevicePathPtr,
+ GetDevicePathSize (DevicePathPtr)) == 0
+ ) {
+ DoConvert = TRUE;
+ }
+ }
+ break;
+ case MSG_USB_CLASS_DP:
+ if (MatchUsbClass((USB_CLASS_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
+ DoConvert = TRUE;
+ }
+ break;
+ case MSG_USB_WWID_DP:
+ if (MatchUsbWwid((USB_WWID_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
+ DoConvert = TRUE;
+ }
+ break;
+ default:
+ ASSERT (0);
+ break;
+ }
+
+ if (DoConvert) {
+ break;
+ }
+
+ WantedListIndex = WantedListIndex->ForwardLink;
+ }
+ gBS->FreePool (DevicePathPtr);
+
+ //
+ // Check whether the new Usb device path is wanted
+ //
+ if (DoConvert){
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Recursively connect every wanted usb child device to ensure they all fully connected.
+ Check all the child Usb IO handles in this bus, recursively connecte if it is wanted usb child device.
+
+ @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
+
+ @retval EFI_SUCCESS Connect is done successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusRecursivelyConnectWantedUsbIo (
+ IN EFI_USB_BUS_PROTOCOL *UsbBusId
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_INTERFACE *UsbIf;
+ UINTN UsbIoHandleCount;
+ EFI_HANDLE *UsbIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+
+ if (UsbBusId == NULL){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Bus = USB_BUS_FROM_THIS (UsbBusId);
+
+ //
+ // Get all Usb IO handles in system
+ //
+ UsbIoHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
+ if (Status == EFI_NOT_FOUND || UsbIoHandleCount == 0) {
+ return EFI_SUCCESS;
+ }
+ ASSERT (!EFI_ERROR (Status));
+
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ //
+ // Check whether the USB IO handle is a child of this bus
+ // Note: The usb child handle maybe invalid because of hot plugged out during the loop
+ //
+ UsbIoDevicePath = NULL;
+ Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath);
+ if (EFI_ERROR (Status) || UsbIoDevicePath == NULL) {
+ continue;
+ }
+ if (CompareMem (
+ UsbIoDevicePath,
+ Bus->DevicePath,
+ (GetDevicePathSize (Bus->DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL))
+ ) != 0) {
+ continue;
+ }
+
+ //
+ // Get the child Usb IO interface
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);
+
+ if (UsbBusIsWantedUsbIO (Bus, UsbIf)) {
+ if (!UsbIf->IsManaged) {
+ //
+ // Recursively connect the wanted Usb Io handle
+ //
+ DEBUG ((EFI_D_INFO, "UsbBusRecursivelyConnectWantedUsbIo: TPL before connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
+ Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
+ UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "UsbBusRecursivelyConnectWantedUsbIo: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl()));
+ }
+ }
+ }
+
+ FreePool (UsbIoBuffer);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h
new file mode 100644
index 000000000..1d2b8a617
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h
@@ -0,0 +1,278 @@
+/** @file
+
+ Manage Usb Port/Hc/Etc.
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_UTILITY_H_
+#define _EFI_USB_UTILITY_H_
+
+/**
+ Get the capability of the host controller.
+
+ @param UsbBus The usb driver.
+ @param MaxSpeed The maximum speed this host controller supports.
+ @param NumOfPort The number of the root hub port.
+ @param Is64BitCapable Whether this controller support 64 bit addressing.
+
+ @retval EFI_SUCCESS The host controller capability is returned.
+ @retval Others Failed to retrieve the host controller capability.
+
+**/
+EFI_STATUS
+UsbHcGetCapability (
+ IN USB_BUS *UsbBus,
+ OUT UINT8 *MaxSpeed,
+ OUT UINT8 *NumOfPort,
+ OUT UINT8 *Is64BitCapable
+ );
+
+
+/**
+ Get the root hub port state.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The index of port.
+ @param PortStatus The variable to save port state.
+
+ @retval EFI_SUCCESS The root port state is returned in.
+ @retval Others Failed to get the root hub port state.
+
+**/
+EFI_STATUS
+UsbHcGetRootHubPortStatus (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+ Set the root hub port feature.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The port index.
+ @param Feature The port feature to set.
+
+ @retval EFI_SUCCESS The port feature is set.
+ @retval Others Failed to set port feature.
+
+**/
+EFI_STATUS
+UsbHcSetRootHubPortFeature (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ IN EFI_USB_PORT_FEATURE Feature
+ );
+
+/**
+ Clear the root hub port feature.
+
+ @param UsbBus The USB bus driver.
+ @param PortIndex The port index.
+ @param Feature The port feature to clear.
+
+ @retval EFI_SUCCESS The port feature is clear.
+ @retval Others Failed to clear port feature.
+
+**/
+EFI_STATUS
+UsbHcClearRootHubPortFeature (
+ IN USB_BUS *UsbBus,
+ IN UINT8 PortIndex,
+ IN EFI_USB_PORT_FEATURE Feature
+ );
+
+/**
+ Execute a control transfer to the device.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The device address.
+ @param DevSpeed The device speed.
+ @param MaxPacket Maximum packet size of endpoint 0.
+ @param Request The control transfer request.
+ @param Direction The direction of data stage.
+ @param Data The buffer holding data.
+ @param DataLength The length of the data.
+ @param TimeOut Timeout (in ms) to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of transfer.
+
+ @retval EFI_SUCCESS The control transfer finished without error.
+ @retval Others The control transfer failed, reason returned in UsbResult.
+
+**/
+EFI_STATUS
+UsbHcControlTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ );
+
+/**
+ Execute a bulk transfer to the device's endpoint.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param BufferNum The number of data buffer.
+ @param Data Array of pointers to data buffer.
+ @param DataLength The length of data buffer.
+ @param DataToggle On input, the initial data toggle to use, also return
+ the next toggle on output.
+ @param TimeOut The time to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of USB execution.
+
+ @retval EFI_SUCCESS The bulk transfer is finished without error.
+ @retval Others Failed to execute bulk transfer, result in UsbResult.
+
+**/
+EFI_STATUS
+UsbHcBulkTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN UINT8 BufferNum,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ );
+
+/**
+ Queue or cancel an asynchronous interrupt transfer.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param IsNewTransfer Whether this is a new request. If not, cancel the old
+ request.
+ @param DataToggle Data toggle to use on input, next toggle on output.
+ @param PollingInterval The interval to poll the interrupt transfer (in ms).
+ @param DataLength The length of periodical data receive.
+ @param Translator The transaction translator for low/full speed device.
+ @param Callback Function to call when data is received.
+ @param Context The context to the callback.
+
+ @retval EFI_SUCCESS The asynchronous transfer is queued.
+ @retval Others Failed to queue the transfer.
+
+**/
+EFI_STATUS
+UsbHcAsyncInterruptTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval,
+ IN UINTN DataLength,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Execute a synchronous interrupt transfer to the target endpoint.
+
+ @param UsbBus The USB bus driver.
+ @param DevAddr The target device address.
+ @param EpAddr The target endpoint address, with direction encoded in
+ bit 7.
+ @param DevSpeed The device's speed.
+ @param MaxPacket The endpoint's max packet size.
+ @param Data Pointer to data buffer.
+ @param DataLength The length of data buffer.
+ @param DataToggle On input, the initial data toggle to use, also return
+ the next toggle on output.
+ @param TimeOut The time to wait until timeout.
+ @param Translator The transaction translator for low/full speed device.
+ @param UsbResult The result of USB execution.
+
+ @retval EFI_SUCCESS The synchronous interrupt transfer is OK.
+ @retval Others Failed to execute the synchronous interrupt transfer.
+
+**/
+EFI_STATUS
+UsbHcSyncInterruptTransfer (
+ IN USB_BUS *UsbBus,
+ IN UINT8 DevAddr,
+ IN UINT8 EpAddr,
+ IN UINT8 DevSpeed,
+ IN UINTN MaxPacket,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *UsbResult
+ );
+
+
+/**
+ Open the USB host controller protocol BY_CHILD.
+
+ @param Bus The USB bus driver.
+ @param Child The child handle.
+
+ @return The open protocol return.
+
+**/
+EFI_STATUS
+UsbOpenHostProtoByChild (
+ IN USB_BUS *Bus,
+ IN EFI_HANDLE Child
+ );
+
+/**
+ Close the USB host controller protocol BY_CHILD.
+
+ @param Bus The USB bus driver.
+ @param Child The child handle.
+
+ @return None.
+
+**/
+VOID
+UsbCloseHostProtoByChild (
+ IN USB_BUS *Bus,
+ IN EFI_HANDLE Child
+ );
+
+/**
+ return the current TPL, copied from the EDKII glue lib.
+
+ @param VOID.
+
+ @return Current TPL.
+
+**/
+EFI_TPL
+UsbGetCurrentTpl (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
new file mode 100644
index 000000000..c44c40389
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
@@ -0,0 +1,586 @@
+/** @file
+Usb Hub Request Support In PEI Phase
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbPeim.h"
+#include "HubPeim.h"
+#include "PeiUsbLib.h"
+
+/**
+ Get a given hub port status.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param PortStatus Current Hub port status and change status.
+
+ @retval EFI_SUCCESS Port status is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubGetPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ OUT UINT32 *PortStatus
+ )
+{
+ EFI_USB_DEVICE_REQUEST DeviceRequest;
+
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;
+ DeviceRequest.Request = USB_HUB_GET_PORT_STATUS;
+ DeviceRequest.Index = Port;
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);
+
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DeviceRequest,
+ EfiUsbDataIn,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ PortStatus,
+ sizeof (UINT32)
+ );
+
+}
+
+/**
+ Set specified feature to a given hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param Value New feature value.
+
+ @retval EFI_SUCCESS Port feature is set successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubSetPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ IN UINT8 Value
+ )
+{
+ EFI_USB_DEVICE_REQUEST DeviceRequest;
+
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;
+ DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE;
+ DeviceRequest.Value = Value;
+ DeviceRequest.Index = Port;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DeviceRequest,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+/**
+ Clear specified feature on a given hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param Value Feature value that will be cleared from the hub port.
+
+ @retval EFI_SUCCESS Port feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubClearPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ IN UINT8 Value
+ )
+{
+ EFI_USB_DEVICE_REQUEST DeviceRequest;
+
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT;
+ DeviceRequest.Value = Value;
+ DeviceRequest.Index = Port;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DeviceRequest,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+/**
+ Get a given hub status.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param HubStatus Current Hub status and change status.
+
+ @retval EFI_SUCCESS Hub status is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubGetHubStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ OUT UINT32 *HubStatus
+ )
+{
+ EFI_USB_DEVICE_REQUEST DeviceRequest;
+
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;
+ DeviceRequest.Request = USB_HUB_GET_HUB_STATUS;
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DeviceRequest,
+ EfiUsbDataIn,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ HubStatus,
+ sizeof (UINT32)
+ );
+}
+
+
+
+/**
+ Clear specified feature on a given hub.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Value Feature value that will be cleared from the hub port.
+
+ @retval EFI_SUCCESS Hub feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubClearHubFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Value
+ )
+{
+ EFI_USB_DEVICE_REQUEST DeviceRequest;
+
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;
+ DeviceRequest.Value = Value;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DeviceRequest,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+/**
+ Get a given (SuperSpeed) hub descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicates the hub controller device.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param DescriptorSize The length of Hub Descriptor buffer.
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if
+ successfully returned.
+
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiGetHubDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINTN DescriptorSize,
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT8 DescType;
+
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?
+ USB_DT_SUPERSPEED_HUB :
+ USB_DT_HUB;
+
+ //
+ // Fill Device request packet
+ //
+ DevReq.RequestType = USB_RT_HUB | 0x80;
+ DevReq.Request = USB_HUB_GET_DESCRIPTOR;
+ DevReq.Value = (UINT16) (DescType << 8);
+ DevReq.Length = (UINT16) DescriptorSize;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbDataIn,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ HubDescriptor,
+ (UINT16)DescriptorSize
+ );
+}
+
+/**
+ Read the whole usb hub descriptor. It is necessary
+ to do it in two steps because hub descriptor is of
+ variable length.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicates the hub controller device.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if
+ successfully returned.
+
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbHubReadDesc (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // First get the hub descriptor length
+ //
+ Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the whole hub descriptor
+ //
+ return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
+}
+
+/**
+ USB hub control transfer to set the hub depth.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicates the hub controller device.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS Depth of the hub is set.
+ @retval Others Failed to set the depth.
+
+**/
+EFI_STATUS
+PeiUsbHubCtrlSetHubDepth (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN PEI_USB_IO_PPI *UsbIoPpi
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ //
+ // Fill Device request packet
+ //
+ DevReq.RequestType = USB_RT_HUB;
+ DevReq.Request = USB_HUB_REQ_SET_DEPTH;
+ DevReq.Value = PeiUsbDevice->Tier;
+ DevReq.Length = 0;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+/**
+ Configure a given hub.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicating the hub controller device that will be configured
+
+ @retval EFI_SUCCESS Hub configuration is done successfully.
+ @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.
+
+**/
+EFI_STATUS
+PeiDoHubConfig (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice
+ )
+{
+ UINT8 HubDescBuffer[256];
+ EFI_USB_HUB_DESCRIPTOR *HubDescriptor;
+ EFI_STATUS Status;
+ EFI_USB_HUB_STATUS HubStatus;
+ UINTN Index;
+ PEI_USB_IO_PPI *UsbIoPpi;
+
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
+
+ //
+ // The length field of descriptor is UINT8 type, so the buffer
+ // with 256 bytes is enough to hold the descriptor data.
+ //
+ HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;
+
+ //
+ // Get the hub descriptor
+ //
+ Status = PeiUsbHubReadDesc (
+ PeiServices,
+ PeiUsbDevice,
+ UsbIoPpi,
+ HubDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;
+
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
+ DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
+ PeiUsbHubCtrlSetHubDepth (
+ PeiServices,
+ PeiUsbDevice,
+ UsbIoPpi
+ );
+ } else {
+ //
+ // Power all the hub ports
+ //
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
+ Status = PeiHubSetPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ (UINT8) (Index + 1),
+ EfiUsbPortPower
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
+ continue;
+ }
+ }
+
+ DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));
+ if (HubDescriptor->PwrOn2PwrGood > 0) {
+ MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
+ }
+
+ //
+ // Clear Hub Status Change
+ //
+ Status = PeiHubGetHubStatus (
+ PeiServices,
+ UsbIoPpi,
+ (UINT32 *) &HubStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // Hub power supply change happens
+ //
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
+ PeiHubClearHubFeature (
+ PeiServices,
+ UsbIoPpi,
+ C_HUB_LOCAL_POWER
+ );
+ }
+ //
+ // Hub change overcurrent happens
+ //
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
+ PeiHubClearHubFeature (
+ PeiServices,
+ UsbIoPpi,
+ C_HUB_OVER_CURRENT
+ );
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send reset signal over the given root hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param PortNum Usb hub port number (starting from 1).
+
+**/
+VOID
+PeiResetHubPort (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 PortNum
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USB_PORT_STATUS HubPortStatus;
+
+ MicroSecondDelay (100 * 1000);
+
+ //
+ // reset root port
+ //
+ PeiHubSetPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ EfiUsbPortReset
+ );
+
+ //
+ // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ MicroSecondDelay (USB_SET_PORT_RESET_STALL);
+
+ //
+ // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
+ //
+ ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
+ Status = PeiHubGetPortStatus (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ (UINT32 *) &HubPortStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
+ break;
+ }
+
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
+ }
+
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
+ DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
+ return;
+ }
+
+ //
+ // clear reset change root port
+ //
+ PeiHubClearPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ EfiUsbPortResetChange
+ );
+
+ MicroSecondDelay (1 * 1000);
+
+ PeiHubClearPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ EfiUsbPortConnectChange
+ );
+
+ //
+ // Set port enable
+ //
+ PeiHubSetPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ EfiUsbPortEnable
+ );
+
+ //
+ // Clear any change status
+ //
+
+ PeiHubClearPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ PortNum,
+ EfiUsbPortEnableChange
+ );
+
+ MicroSecondDelay (10 * 1000);
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
new file mode 100644
index 000000000..2a6d911a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
@@ -0,0 +1,258 @@
+/** @file
+Constants definitions for Usb Hub Peim
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_HUB_PEIM_H_
+#define _PEI_HUB_PEIM_H_
+
+
+//
+// Hub feature numbers
+//
+#define C_HUB_LOCAL_POWER 0
+#define C_HUB_OVER_CURRENT 1
+
+//
+// Hub class code & sub class code
+//
+#define CLASS_CODE_HUB 0x09
+#define SUB_CLASS_CODE_HUB 0
+
+//
+// Hub Status & Hub Change bit masks
+//
+#define HUB_STATUS_LOCAL_POWER 0x0001
+#define HUB_STATUS_OVERCURRENT 0x0002
+
+#define HUB_CHANGE_LOCAL_POWER 0x0001
+#define HUB_CHANGE_OVERCURRENT 0x0002
+
+//
+// Hub Characteristics
+//
+#define HUB_CHAR_LPSM 0x0003
+#define HUB_CHAR_COMPOUND 0x0004
+#define HUB_CHAR_OCPM 0x0018
+
+//
+// Standard hub request and request type
+// By [Spec-USB20/Chapter-11.24]
+//
+#define USB_HUB_CLEAR_FEATURE 0x01
+#define USB_HUB_CLEAR_FEATURE_REQ_TYPE 0x20
+
+#define USB_HUB_CLEAR_FEATURE_PORT 0x01
+#define USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23
+
+#define USB_HUB_GET_BUS_STATE 0x02
+#define USB_HUB_GET_BUS_STATE_REQ_TYPE 0xA3
+
+#define USB_HUB_GET_DESCRIPTOR 0x06
+#define USB_HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0
+
+#define USB_HUB_GET_HUB_STATUS 0x00
+#define USB_HUB_GET_HUB_STATUS_REQ_TYPE 0xA0
+
+#define USB_HUB_GET_PORT_STATUS 0x00
+#define USB_HUB_GET_PORT_STATUS_REQ_TYPE 0xA3
+
+#define USB_HUB_SET_DESCRIPTOR 0x07
+#define USB_HUB_SET_DESCRIPTOR_REQ_TYPE 0x20
+
+#define USB_HUB_SET_HUB_FEATURE 0x03
+#define USB_HUB_SET_HUB_FEATURE_REQ_TYPE 0x20
+
+#define USB_HUB_SET_PORT_FEATURE 0x03
+#define USB_HUB_SET_PORT_FEATURE_REQ_TYPE 0x23
+
+#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+#define USB_HUB_REQ_SET_DEPTH 12
+
+#define MAXBYTES 8
+#pragma pack(1)
+//
+// Hub descriptor, the last two fields are of variable length.
+//
+typedef struct {
+ UINT8 Length;
+ UINT8 DescriptorType;
+ UINT8 NbrPorts;
+ UINT8 HubCharacteristics[2];
+ UINT8 PwrOn2PwrGood;
+ UINT8 HubContrCurrent;
+ UINT8 Filler[MAXBYTES];
+} EFI_USB_HUB_DESCRIPTOR;
+
+typedef struct {
+ UINT16 HubStatus;
+ UINT16 HubChangeStatus;
+} EFI_USB_HUB_STATUS;
+
+#pragma pack()
+/**
+ Get a given hub port status.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param PortStatus Current Hub port status and change status.
+
+ @retval EFI_SUCCESS Port status is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubGetPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ OUT UINT32 *PortStatus
+ );
+
+/**
+ Set specified feature to a given hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param Value New feature value.
+
+ @retval EFI_SUCCESS Port feature is set successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubSetPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ IN UINT8 Value
+ );
+
+
+/**
+ Get a given hub status.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param HubStatus Current Hub status and change status.
+
+ @retval EFI_SUCCESS Hub status is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubGetHubStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ OUT UINT32 *HubStatus
+ );
+
+/**
+ Clear specified feature on a given hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Port Usb hub port number (starting from 1).
+ @param Value Feature value that will be cleared from the hub port.
+
+ @retval EFI_SUCCESS Port feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubClearPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Port,
+ IN UINT8 Value
+ );
+
+/**
+ Clear specified feature on a given hub.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Value Feature value that will be cleared from the hub port.
+
+ @retval EFI_SUCCESS Hub feature is cleared successfully.
+ @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubClearHubFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 Value
+ );
+
+/**
+ Get a given hub descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicates the hub controller device.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param DescriptorSize The length of Hub Descriptor buffer.
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if
+ successfully returned.
+
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiGetHubDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINTN DescriptorSize,
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
+ );
+
+/**
+ Configure a given hub.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param PeiUsbDevice Indicating the hub controller device that will be configured
+
+ @retval EFI_SUCCESS Hub configuration is done successfully.
+ @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.
+
+**/
+EFI_STATUS
+PeiDoHubConfig (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice
+ );
+
+/**
+ Send reset signal over the given root hub port.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param PortNum Usb hub port number (starting from 1).
+
+**/
+VOID
+PeiResetHubPort (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT8 PortNum
+ );
+
+#endif
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
new file mode 100644
index 000000000..1385b0ab5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
@@ -0,0 +1,185 @@
+/** @file
+Common Library for PEI USB
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbPeim.h"
+#include "PeiUsbLib.h"
+
+/**
+ Get a given usb descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Value Request Value.
+ @param Index Request Index.
+ @param DescriptorLength Request descriptor Length.
+ @param Descriptor Request descriptor.
+
+
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbGetDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT16 Value,
+ IN UINT16 Index,
+ IN UINT16 DescriptorLength,
+ OUT VOID *Descriptor
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+
+ ASSERT (UsbIoPpi != NULL);
+
+ DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;
+ DevReq.Request = USB_DEV_GET_DESCRIPTOR;
+ DevReq.Value = Value;
+ DevReq.Index = Index;
+ DevReq.Length = DescriptorLength;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbDataIn,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ Descriptor,
+ DescriptorLength
+ );
+}
+
+/**
+ Set a usb device with a specified address.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param AddressValue The address to assign.
+
+ @retval EFI_SUCCESS Usb device address is set successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbSetDeviceAddress (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT16 AddressValue
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+
+ ASSERT (UsbIoPpi != NULL);
+
+ DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE;
+ DevReq.Request = USB_DEV_SET_ADDRESS;
+ DevReq.Value = AddressValue;
+ DevReq.Index = 0;
+ DevReq.Length = 0;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+
+
+/**
+ Configure a usb device to Configuration 1.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbSetConfiguration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE;
+ DevReq.Request = USB_DEV_SET_CONFIGURATION;
+ DevReq.Value = 1;
+
+ return UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ PcdGet32 (PcdUsbTransferTimeoutValue),
+ NULL,
+ 0
+ );
+}
+
+/**
+ Judge if the port is connected with a usb device or not.
+
+ @param PortStatus The usb port status gotten.
+
+ @retval TRUE A usb device is connected with the port.
+ @retval FALSE No usb device is connected with the port.
+
+**/
+BOOLEAN
+IsPortConnect (
+ IN UINT16 PortStatus
+ )
+{
+ //
+ // return the bit 0 value of PortStatus
+ //
+ if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get device speed according to port status.
+
+ @param PortStatus The usb port status gotten.
+
+ @return Device speed value.
+
+**/
+UINTN
+PeiUsbGetDeviceSpeed (
+ IN UINT16 PortStatus
+ )
+{
+ if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
+ return EFI_USB_SPEED_LOW;
+ } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){
+ return EFI_USB_SPEED_HIGH;
+ } else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
+ return EFI_USB_SPEED_SUPER;
+ } else {
+ return EFI_USB_SPEED_FULL;
+ }
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
new file mode 100644
index 000000000..48b8e594b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
@@ -0,0 +1,189 @@
+/** @file
+Common Library for PEI USB
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_LIB_H_
+#define _PEI_USB_LIB_H_
+
+
+//
+// Standard device request and request type
+// By [Spec-USB20/Chapter-9.4]
+//
+#define USB_DEV_GET_STATUS 0x00
+#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device
+#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface
+#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint
+
+#define USB_DEV_CLEAR_FEATURE 0x01
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint
+
+#define USB_DEV_SET_FEATURE 0x03
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint
+
+#define USB_DEV_SET_ADDRESS 0x05
+#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00
+
+#define USB_DEV_GET_DESCRIPTOR 0x06
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80
+
+#define USB_DEV_SET_DESCRIPTOR 0x07
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00
+
+#define USB_DEV_GET_CONFIGURATION 0x08
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80
+
+#define USB_DEV_SET_CONFIGURATION 0x09
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00
+
+#define USB_DEV_GET_INTERFACE 0x0A
+#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81
+
+#define USB_DEV_SET_INTERFACE 0x0B
+#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01
+
+#define USB_DEV_SYNCH_FRAME 0x0C
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82
+
+//
+// USB Descriptor types
+//
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_HUB 0x29
+#define USB_DT_SUPERSPEED_HUB 0x2A
+#define USB_DT_HID 0x21
+
+//
+// USB request type
+//
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+//
+// USB request targer device
+//
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+typedef enum {
+ EfiUsbEndpointHalt,
+ EfiUsbDeviceRemoteWakeup
+} EFI_USB_STANDARD_FEATURE_SELECTOR;
+
+//
+// Usb Data recipient type
+//
+typedef enum {
+ EfiUsbDevice,
+ EfiUsbInterface,
+ EfiUsbEndpoint
+} EFI_USB_RECIPIENT;
+
+/**
+ Get a given usb descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param Value Request Value.
+ @param Index Request Index.
+ @param DescriptorLength Request descriptor Length.
+ @param Descriptor Request descriptor.
+
+
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbGetDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT16 Value,
+ IN UINT16 Index,
+ IN UINT16 DescriptorLength,
+ OUT VOID *Descriptor
+ );
+
+/**
+ Set a usb device with a specified address.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+ @param AddressValue The address to assign.
+
+ @retval EFI_SUCCESS Usb device address is set successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbSetDeviceAddress (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi,
+ IN UINT16 AddressValue
+ );
+
+
+/**
+ Configure a usb device to Configuration 1.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbSetConfiguration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *UsbIoPpi
+ );
+
+/**
+ Judge if the port is connected with a usb device or not.
+
+ @param PortStatus The usb port status gotten.
+
+ @retval TRUE A usb device is connected with the port.
+ @retval FALSE No usb device is connected with the port.
+
+**/
+BOOLEAN
+IsPortConnect (
+ IN UINT16 PortStatus
+ );
+
+/**
+ Get device speed according to port status.
+
+ @param PortStatus The usb port status gotten.
+
+ @return Device speed value.
+
+**/
+UINTN
+PeiUsbGetDeviceSpeed (
+ IN UINT16 PortStatus
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf
new file mode 100644
index 000000000..31d7c2e2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf
@@ -0,0 +1,60 @@
+## @file
+# The Usb Bus Peim driver is used to support recovery from usb device.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbBusPei
+ MODULE_UNI_FILE = UsbBusPei.uni
+ FILE_GUID = 8401A045-6F70-4505-8471-7015B40355E3
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimInitializeUsb
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PeiUsbLib.c
+ HubPeim.c
+ UsbIoPeim.c
+ UsbPeim.c
+ UsbPeim.h
+ PeiUsbLib.h
+ HubPeim.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ TimerLib
+ BaseMemoryLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue ## CONSUMES
+
+[Ppis]
+ gPeiUsbIoPpiGuid ## PRODUCES
+ gPeiUsbHostControllerPpiGuid ## SOMETIMES_CONSUMES
+ gPeiUsb2HostControllerPpiGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsb2HostControllerPpiGuid OR gPeiUsbHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbBusPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni
new file mode 100644
index 000000000..92f8af732
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The Usb Bus Peim driver is used to support recovery from usb device.
+//
+// The USB Bus PEIM driver is used to support recovery from USB devices.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from USB devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The USB Bus PEIM driver is used to support recovery from USB devices."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni
new file mode 100644
index 000000000..8bd6c65e7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbBusPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Bus PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
new file mode 100644
index 000000000..fc04f834a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
@@ -0,0 +1,365 @@
+/** @file
+The module is used to implement Usb Io PPI interfaces.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbPeim.h"
+#include "PeiUsbLib.h"
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_IO_PPI.
+ @param Request USB device request to send.
+ @param Direction Specifies the data direction for the data stage.
+ @param Timeout Indicates the maximum timeout, in millisecond. If Timeout
+ is 0, then the caller must wait for the function to be
+ completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data, OPTIONAL
+ IN UINTN DataLength OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ PEI_USB_DEVICE *PeiUsbDev;
+ UINT32 TransferResult;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
+ UINT8 EndpointIndex;
+
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
+
+ EndpointDescriptor = NULL;
+ EndpointIndex = 0;
+
+ if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&
+ (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
+ (Request->Value == USB_FEATURE_ENDPOINT_HALT)) {
+ //
+ // Request->Index is the Endpoint Address, use it to get the Endpoint Index.
+ //
+ while (EndpointIndex < MAX_ENDPOINT) {
+ Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EndpointDescriptor->EndpointAddress == Request->Index) {
+ break;
+ }
+
+ EndpointIndex++;
+ }
+
+ if (EndpointIndex == MAX_ENDPOINT) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (PeiUsbDev->Usb2HcPpi != NULL) {
+ Status = PeiUsbDev->Usb2HcPpi->ControlTransfer (
+ PeiServices,
+ PeiUsbDev->Usb2HcPpi,
+ PeiUsbDev->DeviceAddress,
+ PeiUsbDev->DeviceSpeed,
+ PeiUsbDev->MaxPacketSize0,
+ Request,
+ Direction,
+ Data,
+ &DataLength,
+ Timeout,
+ &(PeiUsbDev->Translator),
+ &TransferResult
+ );
+ } else {
+ Status = PeiUsbDev->UsbHcPpi->ControlTransfer (
+ PeiServices,
+ PeiUsbDev->UsbHcPpi,
+ PeiUsbDev->DeviceAddress,
+ PeiUsbDev->DeviceSpeed,
+ (UINT8) PeiUsbDev->MaxPacketSize0,
+ Request,
+ Direction,
+ Data,
+ &DataLength,
+ Timeout,
+ &TransferResult
+ );
+ }
+
+ //
+ // Reset the endpoint toggle when endpoint stall is cleared
+ //
+ if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&
+ (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
+ (Request->Value == USB_FEATURE_ENDPOINT_HALT)) {
+ if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
+ PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));
+ return Status;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_IO_PPI.
+ @param DeviceEndpoint Endpoint number and its direction in bit 7.
+ @param Data A pointer to the buffer of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete. If Timeout is 0, then
+ the caller must wait for the function to be completed
+ until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+ PEI_USB_DEVICE *PeiUsbDev;
+ UINT32 TransferResult;
+ UINTN MaxPacketLength;
+ UINT8 DataToggle;
+ UINT8 OldToggle;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
+ UINT8 EndpointIndex;
+ VOID *Data2[EFI_USB_MAX_BULK_BUFFER_NUM];
+
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
+
+ EndpointDescriptor = NULL;
+ EndpointIndex = 0;
+ Data2[0] = Data;
+ Data2[1] = NULL;
+
+ while (EndpointIndex < MAX_ENDPOINT) {
+ Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) {
+ break;
+ }
+
+ EndpointIndex++;
+ }
+
+ if (EndpointIndex == MAX_ENDPOINT) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize;
+ if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
+ DataToggle = 1;
+ } else {
+ DataToggle = 0;
+ }
+
+ OldToggle = DataToggle;
+
+ if (PeiUsbDev->Usb2HcPpi != NULL) {
+ Status = PeiUsbDev->Usb2HcPpi->BulkTransfer (
+ PeiServices,
+ PeiUsbDev->Usb2HcPpi,
+ PeiUsbDev->DeviceAddress,
+ DeviceEndpoint,
+ PeiUsbDev->DeviceSpeed,
+ MaxPacketLength,
+ Data2,
+ DataLength,
+ &DataToggle,
+ Timeout,
+ &(PeiUsbDev->Translator),
+ &TransferResult
+ );
+ } else {
+ Status = PeiUsbDev->UsbHcPpi->BulkTransfer (
+ PeiServices,
+ PeiUsbDev->UsbHcPpi,
+ PeiUsbDev->DeviceAddress,
+ DeviceEndpoint,
+ (UINT8) MaxPacketLength,
+ Data,
+ DataLength,
+ &DataToggle,
+ Timeout,
+ &TransferResult
+ );
+ }
+
+ if (OldToggle != DataToggle) {
+ PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
+ }
+
+ DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));
+ return Status;
+}
+
+/**
+ Get the usb interface descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+ @param InterfaceDescriptor Request interface descriptor.
+
+
+ @retval EFI_SUCCESS Usb interface descriptor is obtained successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbGetInterfaceDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor
+ )
+{
+ PEI_USB_DEVICE *PeiUsbDev;
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
+ *InterfaceDescriptor = PeiUsbDev->InterfaceDesc;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the usb endpoint descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+ @param EndpointIndex The valid index of the specified endpoint.
+ @param EndpointDescriptor Request endpoint descriptor.
+
+ @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully.
+ @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbGetEndpointDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 EndpointIndex,
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor
+ )
+{
+ PEI_USB_DEVICE *PeiUsbDev;
+
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
+
+ ASSERT (EndpointDescriptor != NULL);
+
+ //
+ // The valid range of EndpointIndex is 0..15
+ // If EndpointIndex is lesser than 15 but larger than the number of interfaces,
+ // a EFI_NOT_FOUND should be returned
+ //
+ ASSERT (EndpointIndex <= 15);
+
+ if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) {
+ return EFI_NOT_FOUND;
+ }
+
+ *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the port and re-configure the usb device.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS Usb device is reset and configured successfully.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbPortReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This
+ )
+{
+ PEI_USB_DEVICE *PeiUsbDev;
+ EFI_STATUS Status;
+ UINT8 Address;
+
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
+
+ ResetRootPort (
+ PeiServices,
+ PeiUsbDev->UsbHcPpi,
+ PeiUsbDev->Usb2HcPpi,
+ PeiUsbDev->DeviceAddress,
+ 0
+ );
+
+ //
+ // Set address
+ //
+ Address = PeiUsbDev->DeviceAddress;
+ PeiUsbDev->DeviceAddress = 0;
+
+ Status = PeiUsbSetDeviceAddress (
+ PeiServices,
+ This,
+ Address
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiUsbDev->DeviceAddress = Address;
+
+ //
+ // Set default configuration
+ //
+ Status = PeiUsbSetConfiguration (
+ PeiServices,
+ This
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
new file mode 100644
index 000000000..45e48f472
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
@@ -0,0 +1,1243 @@
+/** @file
+The module to produce Usb Bus PPI.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbPeim.h"
+#include "HubPeim.h"
+#include "PeiUsbLib.h"
+
+//
+// UsbIo PPI interface function
+//
+PEI_USB_IO_PPI mUsbIoPpi = {
+ PeiUsbControlTransfer,
+ PeiUsbBulkTransfer,
+ PeiUsbGetInterfaceDescriptor,
+ PeiUsbGetEndpointDescriptor,
+ PeiUsbPortReset
+};
+
+EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPeiUsbIoPpiGuid,
+ NULL
+};
+
+/**
+ The enumeration routine to detect device change.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
+
+ @retval EFI_SUCCESS The usb is enumerated successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbEnumeration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
+ );
+
+/**
+ Configure new detected usb device.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
+ @param Port The port to be configured.
+ @param DeviceAddress The device address to be configured.
+
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiConfigureUsbDevice (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN UINT8 Port,
+ IN OUT UINT8 *DeviceAddress
+ );
+
+/**
+ Get all configurations from a detected usb device.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
+
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbGetAllConfiguration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice
+ );
+
+/**
+ Get the start position of next wanted descriptor.
+
+ @param Buffer Buffer containing data to parse.
+ @param Length Buffer length.
+ @param DescType Descriptor type.
+ @param DescLength Descriptor length.
+ @param ParsedBytes Bytes has been parsed.
+
+ @retval EFI_SUCCESS Get wanted descriptor successfully.
+ @retval EFI_DEVICE_ERROR Error occurred.
+
+**/
+EFI_STATUS
+GetExpectedDescriptor (
+ IN UINT8 *Buffer,
+ IN UINTN Length,
+ IN UINT8 DescType,
+ IN UINT8 DescLength,
+ OUT UINTN *ParsedBytes
+ );
+
+/**
+ The entrypoint of the module, it will enumerate all HCs.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Usb initialization is done successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval EFI_UNSUPPORTED Can't find required PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeUsb (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
+ PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
+
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not
+ // be produced at the same time
+ //
+ Index = 0;
+ while (TRUE) {
+ //
+ // Get UsbHcPpi at first.
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbHostControllerPpiGuid,
+ Index,
+ NULL,
+ (VOID **) &UsbHcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No more host controller, break out
+ //
+ break;
+ }
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);
+ Index++;
+ }
+
+ if (Index == 0) {
+ //
+ // Then try to get Usb2HcPpi.
+ //
+ while (TRUE) {
+ Status = PeiServicesLocatePpi (
+ &gPeiUsb2HostControllerPpiGuid,
+ Index,
+ NULL,
+ (VOID **) &Usb2HcPpi
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No more host controller, break out
+ //
+ break;
+ }
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi);
+ Index++;
+ }
+ }
+
+ if (Index == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The Hub Enumeration just scans the hub ports one time. It also
+ doesn't support hot-plug.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
+ @param CurrentAddress The DeviceAddress of usb device.
+
+ @retval EFI_SUCCESS The usb hub is enumerated successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiHubEnumeration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN UINT8 *CurrentAddress
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ EFI_USB_PORT_STATUS PortStatus;
+ UINTN MemPages;
+ EFI_PHYSICAL_ADDRESS AllocateAddress;
+ PEI_USB_DEVICE *NewPeiUsbDevice;
+ UINTN InterfaceIndex;
+ UINTN EndpointIndex;
+
+
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
+
+ DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));
+
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
+
+ Status = PeiHubGetPortStatus (
+ PeiServices,
+ UsbIoPpi,
+ (UINT8) (Index + 1),
+ (UINT32 *) &PortStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
+ //
+ // Only handle connection/enable/overcurrent/reset change.
+ //
+ if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ continue;
+ } else {
+ if (IsPortConnect (PortStatus.PortStatus)) {
+ //
+ // Begin to deal with the new device
+ //
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
+ ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
+
+ NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
+ NewPeiUsbDevice->DeviceAddress = 0;
+ NewPeiUsbDevice->MaxPacketSize0 = 8;
+ NewPeiUsbDevice->DataToggle = 0;
+ CopyMem (
+ &(NewPeiUsbDevice->UsbIoPpi),
+ &mUsbIoPpi,
+ sizeof (PEI_USB_IO_PPI)
+ );
+ CopyMem (
+ &(NewPeiUsbDevice->UsbIoPpiList),
+ &mUsbIoPpiList,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
+ NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
+ NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
+ NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
+ NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1);
+ NewPeiUsbDevice->IsHub = 0x0;
+ NewPeiUsbDevice->DownStreamPortNo = 0x0;
+
+ if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
+ ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
+ //
+ // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
+ //
+ PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
+
+ PeiHubGetPortStatus (
+ PeiServices,
+ UsbIoPpi,
+ (UINT8) (Index + 1),
+ (UINT32 *) &PortStatus
+ );
+ } else {
+ PeiHubClearPortFeature (
+ PeiServices,
+ UsbIoPpi,
+ (UINT8) (Index + 1),
+ EfiUsbPortResetChange
+ );
+ }
+
+ NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
+ DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
+
+ if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
+ NewPeiUsbDevice->MaxPacketSize0 = 512;
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
+ NewPeiUsbDevice->MaxPacketSize0 = 64;
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
+ NewPeiUsbDevice->MaxPacketSize0 = 8;
+ } else {
+ NewPeiUsbDevice->MaxPacketSize0 = 8;
+ }
+
+ if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
+ NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;
+ NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;
+ } else {
+ CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));
+ }
+ }
+
+ //
+ // Configure that Usb Device
+ //
+ Status = PeiConfigureUsbDevice (
+ PeiServices,
+ NewPeiUsbDevice,
+ (UINT8) (Index + 1),
+ CurrentAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));
+
+ Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
+
+ if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
+ NewPeiUsbDevice->IsHub = 0x1;
+
+ Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
+ }
+
+ for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
+ //
+ // Begin to deal with the new device
+ //
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
+ NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
+ NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
+ NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
+ NewPeiUsbDevice->InterfaceDesc = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex];
+ for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
+ NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
+ }
+
+ Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
+
+ if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
+ NewPeiUsbDevice->IsHub = 0x1;
+
+ Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
+ }
+ }
+ }
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The enumeration routine to detect device change.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
+
+ @retval EFI_SUCCESS The usb is enumerated successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbEnumeration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
+ )
+{
+ UINT8 NumOfRootPort;
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_USB_PORT_STATUS PortStatus;
+ PEI_USB_DEVICE *PeiUsbDevice;
+ UINTN MemPages;
+ EFI_PHYSICAL_ADDRESS AllocateAddress;
+ UINT8 CurrentAddress;
+ UINTN InterfaceIndex;
+ UINTN EndpointIndex;
+
+ CurrentAddress = 0;
+ if (Usb2HcPpi != NULL) {
+ Usb2HcPpi->GetRootHubPortNumber (
+ PeiServices,
+ Usb2HcPpi,
+ (UINT8 *) &NumOfRootPort
+ );
+ } else if (UsbHcPpi != NULL) {
+ UsbHcPpi->GetRootHubPortNumber (
+ PeiServices,
+ UsbHcPpi,
+ (UINT8 *) &NumOfRootPort
+ );
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
+
+ for (Index = 0; Index < NumOfRootPort; Index++) {
+ //
+ // First get root port status to detect changes happen
+ //
+ if (Usb2HcPpi != NULL) {
+ Usb2HcPpi->GetRootHubPortStatus (
+ PeiServices,
+ Usb2HcPpi,
+ (UINT8) Index,
+ &PortStatus
+ );
+ } else {
+ UsbHcPpi->GetRootHubPortStatus (
+ PeiServices,
+ UsbHcPpi,
+ (UINT8) Index,
+ &PortStatus
+ );
+ }
+ DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
+ //
+ // Only handle connection/enable/overcurrent/reset change.
+ //
+ if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ continue;
+ } else {
+ if (IsPortConnect (PortStatus.PortStatus)) {
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
+ ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
+
+ PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
+ PeiUsbDevice->DeviceAddress = 0;
+ PeiUsbDevice->MaxPacketSize0 = 8;
+ PeiUsbDevice->DataToggle = 0;
+ CopyMem (
+ &(PeiUsbDevice->UsbIoPpi),
+ &mUsbIoPpi,
+ sizeof (PEI_USB_IO_PPI)
+ );
+ CopyMem (
+ &(PeiUsbDevice->UsbIoPpiList),
+ &mUsbIoPpiList,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
+ PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
+ PeiUsbDevice->UsbHcPpi = UsbHcPpi;
+ PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
+ PeiUsbDevice->IsHub = 0x0;
+ PeiUsbDevice->DownStreamPortNo = 0x0;
+
+ if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
+ ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
+ //
+ // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
+ //
+ ResetRootPort (
+ PeiServices,
+ PeiUsbDevice->UsbHcPpi,
+ PeiUsbDevice->Usb2HcPpi,
+ Index,
+ 0
+ );
+
+ if (Usb2HcPpi != NULL) {
+ Usb2HcPpi->GetRootHubPortStatus (
+ PeiServices,
+ Usb2HcPpi,
+ (UINT8) Index,
+ &PortStatus
+ );
+ } else {
+ UsbHcPpi->GetRootHubPortStatus (
+ PeiServices,
+ UsbHcPpi,
+ (UINT8) Index,
+ &PortStatus
+ );
+ }
+ } else {
+ if (Usb2HcPpi != NULL) {
+ Usb2HcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ (UINT8) Index,
+ EfiUsbPortResetChange
+ );
+ } else {
+ UsbHcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ (UINT8) Index,
+ EfiUsbPortResetChange
+ );
+ }
+ }
+
+ PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
+ DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
+
+ if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
+ PeiUsbDevice->MaxPacketSize0 = 512;
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
+ PeiUsbDevice->MaxPacketSize0 = 64;
+ } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
+ PeiUsbDevice->MaxPacketSize0 = 8;
+ } else {
+ PeiUsbDevice->MaxPacketSize0 = 8;
+ }
+
+ //
+ // Configure that Usb Device
+ //
+ Status = PeiConfigureUsbDevice (
+ PeiServices,
+ PeiUsbDevice,
+ Index,
+ &CurrentAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
+
+ Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
+
+ if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
+ PeiUsbDevice->IsHub = 0x1;
+
+ Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
+ }
+
+ for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
+ //
+ // Begin to deal with the new device
+ //
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &AllocateAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
+ PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
+ PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
+ PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
+ PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
+ for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
+ PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
+ }
+
+ Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
+
+ if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
+ PeiUsbDevice->IsHub = 0x1;
+
+ Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
+ }
+ }
+ } else {
+ //
+ // Disconnect change happen, currently we don't support
+ //
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Configure new detected usb device.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
+ @param Port The port to be configured.
+ @param DeviceAddress The device address to be configured.
+
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiConfigureUsbDevice (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice,
+ IN UINT8 Port,
+ IN OUT UINT8 *DeviceAddress
+ )
+{
+ EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 Retry;
+
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
+ Status = EFI_SUCCESS;
+ ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
+ //
+ // Get USB device descriptor
+ //
+
+ for (Retry = 0; Retry < 3; Retry ++) {
+ Status = PeiUsbGetDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ (USB_DT_DEVICE << 8),
+ 0,
+ 8,
+ &DeviceDescriptor
+ );
+
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));
+ break;
+ }
+ }
+
+ if (Retry == 3) {
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));
+ return Status;
+ }
+
+ if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {
+ PeiUsbDevice->MaxPacketSize0 = 1 << 9;
+ } else {
+ PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
+ }
+
+ (*DeviceAddress) ++;
+
+ Status = PeiUsbSetDeviceAddress (
+ PeiServices,
+ UsbIoPpi,
+ *DeviceAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));
+ return Status;
+ }
+ MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL);
+
+ PeiUsbDevice->DeviceAddress = *DeviceAddress;
+
+ //
+ // Get whole USB device descriptor
+ //
+ Status = PeiUsbGetDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ (USB_DT_DEVICE << 8),
+ 0,
+ (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),
+ &DeviceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));
+ return Status;
+ }
+
+ //
+ // Get its default configuration and its first interface
+ //
+ Status = PeiUsbGetAllConfiguration (
+ PeiServices,
+ PeiUsbDevice
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
+
+ Status = PeiUsbSetConfiguration (
+ PeiServices,
+ UsbIoPpi
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get all configurations from a detected usb device.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
+
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+PeiUsbGetAllConfiguration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_DEVICE *PeiUsbDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT16 ConfigDescLength;
+ UINT8 *Ptr;
+ UINTN SkipBytes;
+ UINTN LengthLeft;
+ UINTN InterfaceIndex;
+ UINTN Index;
+ UINTN NumOfEndpoint;
+
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
+
+ //
+ // First get its 4-byte configuration descriptor
+ //
+ Status = PeiUsbGetDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ (USB_DT_CONFIG << 8), // Value
+ 0, // Index
+ 4, // Length
+ PeiUsbDevice->ConfigurationData
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));
+ return Status;
+ }
+ MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
+
+ ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;
+ ConfigDescLength = ConfigDesc->TotalLength;
+
+ //
+ // Reject if TotalLength even cannot cover itself.
+ //
+ if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData.
+ //
+ if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Then we get the total descriptors for this configuration
+ //
+ Status = PeiUsbGetDescriptor (
+ PeiServices,
+ UsbIoPpi,
+ (USB_DT_CONFIG << 8),
+ 0,
+ ConfigDescLength,
+ PeiUsbDevice->ConfigurationData
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));
+ return Status;
+ }
+ //
+ // Parse this configuration descriptor
+ // First get the current config descriptor;
+ //
+ Status = GetExpectedDescriptor (
+ PeiUsbDevice->ConfigurationData,
+ ConfigDescLength,
+ USB_DT_CONFIG,
+ (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),
+ &SkipBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;
+ PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;
+
+ Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);
+ LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);
+
+ for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
+
+ //
+ // Get the interface descriptor
+ //
+ Status = GetExpectedDescriptor (
+ Ptr,
+ LengthLeft,
+ USB_DT_INTERFACE,
+ (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
+ &SkipBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr += SkipBytes;
+ if (InterfaceIndex == 0) {
+ PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
+ }
+ PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
+
+ Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
+ LengthLeft -= SkipBytes;
+ LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
+
+ //
+ // Parse all the endpoint descriptor within this interface
+ //
+ NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints;
+ ASSERT (NumOfEndpoint <= MAX_ENDPOINT);
+
+ for (Index = 0; Index < NumOfEndpoint; Index++) {
+ //
+ // Get the endpoint descriptor
+ //
+ Status = GetExpectedDescriptor (
+ Ptr,
+ LengthLeft,
+ USB_DT_ENDPOINT,
+ (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),
+ &SkipBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr += SkipBytes;
+ if (InterfaceIndex == 0) {
+ PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
+ }
+ PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
+
+ Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
+ LengthLeft -= SkipBytes;
+ LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the start position of next wanted descriptor.
+
+ @param Buffer Buffer containing data to parse.
+ @param Length Buffer length.
+ @param DescType Descriptor type.
+ @param DescLength Descriptor length.
+ @param ParsedBytes Bytes has been parsed.
+
+ @retval EFI_SUCCESS Get wanted descriptor successfully.
+ @retval EFI_DEVICE_ERROR Error occurred.
+
+**/
+EFI_STATUS
+GetExpectedDescriptor (
+ IN UINT8 *Buffer,
+ IN UINTN Length,
+ IN UINT8 DescType,
+ IN UINT8 DescLength,
+ OUT UINTN *ParsedBytes
+ )
+{
+ USB_DESC_HEAD *Head;
+ UINTN Offset;
+
+ //
+ // Total length is too small that cannot hold the single descriptor header plus data.
+ //
+ if (Length <= sizeof (USB_DESC_HEAD)) {
+ DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, total length = %d!\n", Length));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // All the descriptor has a common LTV (Length, Type, Value)
+ // format. Skip the descriptor that isn't of this Type
+ //
+ Offset = 0;
+ Head = (USB_DESC_HEAD *)Buffer;
+ while (Offset < Length - sizeof (USB_DESC_HEAD)) {
+ //
+ // Above condition make sure Head->Len and Head->Type are safe to access
+ //
+ Head = (USB_DESC_HEAD *)&Buffer[Offset];
+
+ if (Head->Len == 0) {
+ DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Make sure no overflow when adding Head->Len to Offset.
+ //
+ if (Head->Len > MAX_UINTN - Offset) {
+ DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = %d!\n", Head->Len));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Head->Type == DescType) {
+ break;
+ }
+
+ Offset += Head->Len;
+ }
+
+ //
+ // Head->Len is invalid resulting data beyond boundary, or
+ // Descriptor cannot be found: No such type.
+ //
+ if (Length < Offset) {
+ DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Length));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Head->Type != DescType) || (Head->Len < DescLength)) {
+ DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));
+ return EFI_DEVICE_ERROR;
+ }
+
+ *ParsedBytes = Offset;
+ return EFI_SUCCESS;
+}
+
+/**
+ Send reset signal over the given root hub port.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
+ @param PortNum The port to be reset.
+ @param RetryIndex The retry times.
+
+**/
+VOID
+ResetRootPort (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
+ IN UINT8 PortNum,
+ IN UINT8 RetryIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USB_PORT_STATUS PortStatus;
+
+
+ if (Usb2HcPpi != NULL) {
+ MicroSecondDelay (200 * 1000);
+
+ //
+ // reset root port
+ //
+ Status = Usb2HcPpi->SetRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortReset
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
+ return;
+ }
+
+ //
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
+
+ //
+ // clear reset root port
+ //
+ Status = Usb2HcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortReset
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
+ return;
+ }
+
+ MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
+
+ //
+ // USB host controller won't clear the RESET bit until
+ // reset is actually finished.
+ //
+ ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
+ Status = Usb2HcPpi->GetRootHubPortStatus (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ &PortStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
+ break;
+ }
+
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
+ }
+
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
+ DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
+ return;
+ }
+
+ Usb2HcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortResetChange
+ );
+
+ Usb2HcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortConnectChange
+ );
+
+ //
+ // Set port enable
+ //
+ Usb2HcPpi->SetRootHubPortFeature(
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortEnable
+ );
+
+ Usb2HcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ Usb2HcPpi,
+ PortNum,
+ EfiUsbPortEnableChange
+ );
+
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
+ } else {
+ MicroSecondDelay (200 * 1000);
+
+ //
+ // reset root port
+ //
+ Status = UsbHcPpi->SetRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortReset
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
+ return;
+ }
+
+ //
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
+
+ //
+ // clear reset root port
+ //
+ Status = UsbHcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortReset
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
+ return;
+ }
+
+ MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
+
+ //
+ // USB host controller won't clear the RESET bit until
+ // reset is actually finished.
+ //
+ ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
+ Status = UsbHcPpi->GetRootHubPortStatus (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ &PortStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
+ break;
+ }
+
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
+ }
+
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
+ DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
+ return;
+ }
+
+ UsbHcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortResetChange
+ );
+
+ UsbHcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortConnectChange
+ );
+
+ //
+ // Set port enable
+ //
+ UsbHcPpi->SetRootHubPortFeature(
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortEnable
+ );
+
+ UsbHcPpi->ClearRootHubPortFeature (
+ PeiServices,
+ UsbHcPpi,
+ PortNum,
+ EfiUsbPortEnableChange
+ );
+
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
+ }
+ return;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
new file mode 100644
index 000000000..b55b97d87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
@@ -0,0 +1,257 @@
+/** @file
+Usb Peim definition.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_PEIM_H_
+#define _PEI_USB_PEIM_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbHostController.h>
+#include <Ppi/Usb2HostController.h>
+#include <Ppi/UsbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+//
+// A common header for usb standard descriptor.
+// Each stand descriptor has a length and type.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Len;
+ UINT8 Type;
+} USB_DESC_HEAD;
+#pragma pack()
+
+#define MAX_INTERFACE 8
+#define MAX_ENDPOINT 16
+
+#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')
+typedef struct {
+ UINTN Signature;
+ PEI_USB_IO_PPI UsbIoPpi;
+ EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;
+ UINT16 MaxPacketSize0;
+ UINT16 DataToggle;
+ UINT8 DeviceAddress;
+ UINT8 DeviceSpeed;
+ UINT8 IsHub;
+ UINT8 DownStreamPortNo;
+ UINTN AllocateAddress;
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
+ PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
+ UINT8 ConfigurationData[1024];
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescList[MAX_INTERFACE];
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescList[MAX_INTERFACE][MAX_ENDPOINT];
+ EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
+ UINT8 Tier;
+} PEI_USB_DEVICE;
+
+#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)
+
+#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define USB_BUS_1_MILLISECOND 1000
+
+//
+// Wait for port reset, refers to specification
+// [USB20-7.1.7.5, it says 10ms for hub and 50ms for
+// root hub]
+//
+// According to USB2.0, Chapter 11.5.1.5 Resetting,
+// the worst case for TDRST is 20ms
+//
+#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
+#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for clear roothub port reset, set by experience
+//
+#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for port statue reg change, set by experience
+//
+#define USB_WAIT_PORT_STS_CHANGE_STALL (100)
+
+//
+// Host software return timeout if port status doesn't change
+// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience
+//
+#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000
+
+//
+// Wait for hub port power-on, refers to specification
+// [USB20-11.23.2]
+//
+#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for set device address, refers to specification
+// [USB20-9.2.6.3, it says 2ms]
+//
+#define USB_SET_DEVICE_ADDRESS_STALL (2 * USB_BUS_1_MILLISECOND)
+
+//
+// Wait for get configuration descriptor, set by experience
+//
+#define USB_GET_CONFIG_DESCRIPTOR_STALL (1 * USB_BUS_1_MILLISECOND)
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_IO_PPI.
+ @param Request USB device request to send.
+ @param Direction Specifies the data direction for the data stage.
+ @param Timeout Indicates the maximum timeout, in millisecond. If Timeout
+ is 0, then the caller must wait for the function to be
+ completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data, OPTIONAL
+ IN UINTN DataLength OPTIONAL
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_IO_PPI.
+ @param DeviceEndpoint Endpoint number and its direction in bit 7.
+ @param Data A pointer to the buffer of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete. If Timeout is 0, then
+ the caller must wait for the function to be completed
+ until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ );
+
+/**
+ Get the usb interface descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+ @param InterfaceDescriptor Request interface descriptor.
+
+
+ @retval EFI_SUCCESS Usb interface descriptor is obtained successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbGetInterfaceDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor
+ );
+
+/**
+ Get the usb endpoint descriptor.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+ @param EndpointIndex The valid index of the specified endpoint.
+ @param EndpointDescriptor Request endpoint descriptor.
+
+ @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully.
+ @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbGetEndpointDescriptor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 EndpointIndex,
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor
+ );
+
+/**
+ Reset the port and re-configure the usb device.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the PEI_USB_IO_PPI instance.
+
+ @retval EFI_SUCCESS Usb device is reset and configured successfully.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiUsbPortReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This
+ );
+
+/**
+ Send reset signal over the given root hub port.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
+ @param PortNum The port to be reset.
+ @param RetryIndex The retry times.
+
+**/
+VOID
+ResetRootPort (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
+ IN UINT8 PortNum,
+ IN UINT8 RetryIndex
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/ComponentName.c
new file mode 100644
index 000000000..6af1d7809
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/ComponentName.c
@@ -0,0 +1,217 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for USB Keyboard driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "KeyBoard.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName = {
+ UsbKeyboardComponentNameGetDriverName,
+ UsbKeyboardComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbKeyboardComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbKeyboardComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbKeyboardComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbKeyboardDriverNameTable[] = {
+ { "eng;en", L"Usb 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 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
+UsbKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbKeyboardDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbKeyboardComponentName)
+ );
+}
+
+/**
+ 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
+UsbKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB_KB_DEV *UsbKbDev;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTxtIn;
+ EFI_USB_IO_PROTOCOL *UsbIoProtocol;
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIoProtocol,
+ gUsbKeyboardDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ gUsbKeyboardDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTxtIn,
+ gUsbKeyboardDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbKbDev = USB_KB_DEV_FROM_THIS (SimpleTxtIn);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ UsbKbDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUsbKeyboardComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
new file mode 100644
index 000000000..9d1798278
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
@@ -0,0 +1,1239 @@
+/** @file
+ USB Keyboard Driver that manages USB keyboard and produces Simple Text Input
+ Protocol and Simple Text Input Ex Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EfiKey.h"
+#include "KeyBoard.h"
+
+//
+// USB Keyboard Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
+ USBKeyboardDriverBindingSupported,
+ USBKeyboardDriverBindingStart,
+ USBKeyboardDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of USB Keyboard Driver.
+
+ This function is the entrypoint of USB Keyboard 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
+USBKeyboardDriverBindingEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUsbKeyboardDriverBinding,
+ ImageHandle,
+ &gUsbKeyboardComponentName,
+ &gUsbKeyboardComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether USB keyboard driver supports this device.
+
+ @param This The USB keyboard 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ //
+ // Check if USB I/O Protocol is attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Use the USB I/O Protocol interface to check whether Controller is
+ // a keyboard device that can be managed by this driver.
+ //
+ Status = EFI_SUCCESS;
+
+ if (!IsUSBKeyboard (UsbIo)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the keyboard device with this driver.
+
+ This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,
+ initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage
+ this keyboard device.
+
+ @param This The USB keyboard 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 usb keyboard driver.
+ @retval EFI_UNSUPPORTED No interrupt endpoint can be found.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_KB_DEV *UsbKeyboardDevice;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ UINT8 Index;
+ UINT8 EndpointAddr;
+ UINT8 PollingInterval;
+ UINT8 PacketSize;
+ BOOLEAN Found;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Open USB I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));
+ ASSERT (UsbKeyboardDevice != NULL);
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbKeyboardDevice->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+ //
+ // Report that the USB keyboard is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ //
+ // This is pretty close to keyboard detection, so log progress
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ UsbKeyboardDevice->UsbIo = UsbIo;
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &UsbKeyboardDevice->InterfaceDescriptor
+ );
+
+ EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;
+
+ //
+ // Traverse endpoints to find interrupt endpoint IN
+ //
+ Found = FALSE;
+ for (Index = 0; Index < EndpointNumber; Index++) {
+
+ UsbIo->UsbGetEndpointDescriptor (
+ UsbIo,
+ Index,
+ &EndpointDescriptor
+ );
+
+ if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
+ ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
+ //
+ // We only care interrupt endpoint here
+ //
+ CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ //
+ // Report Status Code to indicate that there is no USB keyboard
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)
+ );
+ //
+ // No interrupt endpoint found, then return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE;
+ UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset;
+ UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke;
+
+ UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx;
+ UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx;
+ UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState;
+ UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify;
+ UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;
+
+ InitializeListHead (&UsbKeyboardDevice->NotifyList);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ USBKeyboardTimerHandler,
+ UsbKeyboardDevice,
+ &UsbKeyboardDevice->TimerEvent
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL);
+ }
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ USBKeyboardWaitForKey,
+ UsbKeyboardDevice,
+ &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ USBKeyboardWaitForKey,
+ UsbKeyboardDevice,
+ &(UsbKeyboardDevice->SimpleInput.WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ KeyNotifyProcessHandler,
+ UsbKeyboardDevice,
+ &UsbKeyboardDevice->KeyNotifyProcessEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
+ // for the USB keyboard device.
+ // USB keyboard is a hot plug device, and expected to work immediately
+ // when plugging into system, other conventional console devices could
+ // distinguish it by its device path.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &UsbKeyboardDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &UsbKeyboardDevice->SimpleInputEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ UsbKeyboardDevice->ControllerHandle = Controller;
+ Status = InitKeyboardLayout (UsbKeyboardDevice);
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &UsbKeyboardDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &UsbKeyboardDevice->SimpleInputEx,
+ NULL
+ );
+ goto ErrorExit;
+ }
+
+
+ //
+ // Reset USB Keyboard Device exhaustively.
+ //
+ Status = UsbKeyboardDevice->SimpleInputEx.Reset (
+ &UsbKeyboardDevice->SimpleInputEx,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &UsbKeyboardDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &UsbKeyboardDevice->SimpleInputEx,
+ NULL
+ );
+ goto ErrorExit;
+ }
+
+ //
+ // Submit Asynchronous Interrupt Transfer to manage this device.
+ //
+ EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
+ PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
+ PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EndpointAddr,
+ TRUE,
+ PollingInterval,
+ PacketSize,
+ KeyboardHandler,
+ UsbKeyboardDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &UsbKeyboardDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &UsbKeyboardDevice->SimpleInputEx,
+ NULL
+ );
+ goto ErrorExit;
+ }
+
+ UsbKeyboardDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gUsbKeyboardComponentName.SupportedLanguages,
+ &UsbKeyboardDevice->ControllerNameTable,
+ L"Generic Usb Keyboard",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gUsbKeyboardComponentName2.SupportedLanguages,
+ &UsbKeyboardDevice->ControllerNameTable,
+ L"Generic Usb Keyboard",
+ FALSE
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+//
+// Error handler
+//
+ErrorExit:
+ if (UsbKeyboardDevice != NULL) {
+ if (UsbKeyboardDevice->TimerEvent != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
+ }
+ if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
+ }
+ if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
+ }
+ if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
+ }
+ if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {
+ ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
+ gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
+ }
+ FreePool (UsbKeyboardDevice);
+ UsbKeyboardDevice = NULL;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+
+/**
+ Stop the USB keyboard device handled by this driver.
+
+ @param This The USB keyboard 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_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
+ is not installed on Controller.
+ @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
+USBKeyboardDriverBindingStop (
+ 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 *SimpleInput;
+ USB_KB_DEV *UsbKeyboardDevice;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleInput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
+
+ //
+ // The key data input from this device will be disabled.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ //
+ // Delete the Asynchronous Interrupt Transfer from this device
+ //
+ UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
+ UsbKeyboardDevice->UsbIo,
+ UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ UsbKeyboardDevice->IntEndpointDescriptor.Interval,
+ 0,
+ NULL,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &UsbKeyboardDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &UsbKeyboardDevice->SimpleInputEx,
+ NULL
+ );
+ //
+ // Free all resources.
+ //
+ gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
+ gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
+ gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
+ gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
+ gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
+ gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
+ KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
+
+ ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
+ gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
+
+ if (UsbKeyboardDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
+ }
+
+ DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);
+ DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);
+ DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);
+
+ FreePool (UsbKeyboardDevice);
+
+ return Status;
+}
+
+/**
+ Internal function to read the next keystroke from the keyboard buffer.
+
+ @param UsbKeyboardDevice USB keyboard's private structure.
+ @param KeyData A pointer to buffer to hold the keystroke
+ data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+ @retval Others Fail to translate keycode into EFI_INPUT_KEY
+
+**/
+EFI_STATUS
+USBKeyboardReadKeyStrokeWorker (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState);
+ return EFI_NOT_READY;
+ }
+
+ Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the input device and optionally run diagnostics
+
+ There are 2 types of reset for USB keyboard.
+ For non-exhaustive reset, only keyboard buffer is cleared.
+ For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
+ is also re-initialized.
+
+ @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
+USBKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ USB_KB_DEV *UsbKeyboardDevice;
+
+ UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ //
+ // Non-exhaustive reset:
+ // only reset private data structures.
+ //
+ if (!ExtendedVerification) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
+ UsbKeyboardDevice->DevicePath
+ );
+ //
+ // Clear the key buffer of this USB keyboard
+ //
+ InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
+ InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
+ InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Exhaustive reset
+ //
+ Status = InitUSBKeyboard (UsbKeyboardDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reads the next keystroke from the input device.
+
+ @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
+ @param Key A pointer to a buffer that is filled in with the keystroke
+ information for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ UsbKeyboardDevice = USB_KB_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) {
+ Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // SimpleTextIn Protocol doesn't support partial keystroke;
+ //
+ if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_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 registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
+ and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
+
+ @param Event Event to be signaled when a key is pressed.
+ @param Context Points to USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_KEY_DATA KeyData;
+ EFI_TPL OldTpl;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // WaitforKey doesn't support 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 (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
+ //
+ // If there is pending key, signal the event.
+ //
+ CopyMem (
+ &KeyData,
+ UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
+ sizeof (EFI_KEY_DATA)
+ );
+ if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
+ Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
+ continue;
+ }
+ gBS->SignalEvent (Event);
+ break;
+ }
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Timer handler to convert the key from USB.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+USBKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ USB_KB_DEV *UsbKeyboardDevice;
+ UINT8 KeyCode;
+ EFI_KEY_DATA KeyData;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+
+ //
+ // Fetch raw data from the USB keyboard buffer,
+ // and translate it into USB keycode.
+ //
+ Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Translate saved USB keycode into EFI_INPUT_KEY
+ //
+ Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Insert to the EFI Key queue
+ //
+ Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
+}
+
+/**
+ Free keyboard notify list.
+
+ @param NotifyList The keyboard notify list to free.
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER NotifyList is NULL.
+
+**/
+EFI_STATUS
+KbdFreeNotifyList (
+ IN OUT LIST_ENTRY *NotifyList
+ )
+{
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+ LIST_ENTRY *Link;
+
+ if (NotifyList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (NotifyList)) {
+ Link = GetFirstNode (NotifyList);
+ NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
+ RemoveEntryList (Link);
+ FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the pressed key matches a registered key or not.
+
+ @param RegsiteredData A pointer to keystroke data for the key that was registered.
+ @param InputData A pointer to keystroke data for the key that was pressed.
+
+ @retval TRUE Key pressed matches a registered key.
+ @retval FALSE Key pressed does not matches a registered key.
+
+**/
+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;
+}
+
+//
+// Simple Text Input Ex protocol functions
+//
+/**
+ Resets the input device hardware.
+
+ The Reset() function resets the input device hardware. As part
+ of initialization process, the firmware/device will make a quick
+ but reasonable attempt to verify that the device is functioning.
+ If the ExtendedVerification flag is TRUE the firmware may take
+ an extended amount of time to verify the device is operating on
+ reset. Otherwise the reset operation is to occur as quickly as
+ possible. The hardware verification process is not defined by
+ this specification and is left up to the platform firmware or
+ driver to implement.
+
+ @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ USB_KB_DEV *UsbKeyboardDevice;
+
+ UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
+
+ Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Reads the next keystroke from the input device.
+
+ @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 available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
+
+ return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, 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 appropriately.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not support the ability to have its state set.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
+
+ if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
+ ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update the status light
+ //
+
+ UsbKeyboardDevice->ScrollOn = FALSE;
+ UsbKeyboardDevice->NumLockOn = FALSE;
+ UsbKeyboardDevice->CapsOn = FALSE;
+ UsbKeyboardDevice->IsSupportPartialKey = FALSE;
+
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
+ UsbKeyboardDevice->ScrollOn = TRUE;
+ }
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
+ UsbKeyboardDevice->NumLockOn = TRUE;
+ }
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
+ UsbKeyboardDevice->CapsOn = TRUE;
+ }
+ if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
+ UsbKeyboardDevice->IsSupportPartialKey = TRUE;
+ }
+
+ SetKeyLED (UsbKeyboardDevice);
+
+ UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ 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 for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 necessary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ NotifyList = &UsbKeyboardDevice->NotifyList;
+
+ for (Link = GetFirstNode (NotifyList);
+ !IsNull (NotifyList, Link);
+ Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (
+ Link,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+ NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
+
+
+ *NotifyHandle = NewNotify;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ 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
+USBKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
+
+ //
+ // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
+ //
+ NotifyList = &UsbKeyboardDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList);
+ !IsNull (NotifyList, Link);
+ Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (
+ Link,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ FreePool (CurrentNotify);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Cannot find the matching entry in database.
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_TPL OldTpl;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+
+ //
+ // Invoke notification functions.
+ //
+ NotifyList = &UsbKeyboardDevice->NotifyList;
+ while (TRUE) {
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));
+ //
+ // Leave critical section
+ //
+ gBS->RestoreTPL (OldTpl);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.h
new file mode 100644
index 000000000..852e43390
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.h
@@ -0,0 +1,613 @@
+/** @file
+ Header file for USB Keyboard Driver's Data Structures.
+
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _EFI_USB_KB_H_
+#define _EFI_USB_KB_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/HiiKeyBoardLayout.h>
+#include <Guid/UsbKeyBoardLayout.h>
+
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.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/PcdLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Library/HiiLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+
+#define MAX_KEY_ALLOWED 32
+
+#define HZ 1000 * 1000 * 10
+#define USBKBD_REPEAT_DELAY ((HZ) / 2)
+#define USBKBD_REPEAT_RATE ((HZ) / 50)
+
+#define CLASS_HID 3
+#define SUBCLASS_BOOT 1
+#define PROTOCOL_KEYBOARD 1
+
+#define BOOT_PROTOCOL 0
+#define REPORT_PROTOCOL 1
+
+typedef struct {
+ BOOLEAN Down;
+ UINT8 KeyCode;
+} USB_KEY;
+
+typedef struct {
+ VOID *Buffer[MAX_KEY_ALLOWED + 1];
+ UINTN Head;
+ UINTN Tail;
+ UINTN ItemSize;
+} USB_SIMPLE_QUEUE;
+
+#define USB_KB_DEV_SIGNATURE SIGNATURE_32 ('u', 'k', 'b', 'd')
+#define USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('u', 'k', 'b', 'x')
+
+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 USB_NS_KEY_SIGNATURE SIGNATURE_32 ('u', 'n', 's', 'k')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ //
+ // The number of EFI_NS_KEY_MODIFIER children definitions
+ //
+ UINTN KeyCount;
+
+ //
+ // NsKey[0] : Non-spacing key
+ // NsKey[1] ~ NsKey[KeyCount] : Physical keys
+ //
+ EFI_KEY_DESCRIPTOR *NsKey;
+} USB_NS_KEY;
+
+#define USB_NS_KEY_FORM_FROM_LINK(a) CR (a, USB_NS_KEY, Link, USB_NS_KEY_SIGNATURE)
+
+///
+/// Structure to describe USB keyboard device
+///
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE ControllerHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_EVENT DelayedRecoveryEvent;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleInput;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleInputEx;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor;
+
+ USB_SIMPLE_QUEUE UsbKeyQueue;
+ USB_SIMPLE_QUEUE EfiKeyQueue;
+ USB_SIMPLE_QUEUE EfiKeyQueueForNotify;
+ BOOLEAN CtrlOn;
+ BOOLEAN AltOn;
+ BOOLEAN ShiftOn;
+ BOOLEAN NumLockOn;
+ BOOLEAN CapsOn;
+ BOOLEAN ScrollOn;
+ UINT8 LastKeyCodeArray[8];
+ UINT8 CurKeyCode;
+
+ EFI_EVENT TimerEvent;
+
+ UINT8 RepeatKey;
+ EFI_EVENT RepeatTimer;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ BOOLEAN LeftCtrlOn;
+ BOOLEAN LeftAltOn;
+ BOOLEAN LeftShiftOn;
+ BOOLEAN LeftLogoOn;
+ BOOLEAN RightCtrlOn;
+ BOOLEAN RightAltOn;
+ BOOLEAN RightShiftOn;
+ BOOLEAN RightLogoOn;
+ BOOLEAN MenuKeyOn;
+ BOOLEAN SysReqOn;
+ BOOLEAN AltGrOn;
+
+ BOOLEAN IsSupportPartialKey;
+
+ EFI_KEY_STATE KeyState;
+ //
+ // Notification function list
+ //
+ LIST_ENTRY NotifyList;
+ EFI_EVENT KeyNotifyProcessEvent;
+
+ //
+ // Non-spacing key list
+ //
+ LIST_ENTRY NsKeyList;
+ USB_NS_KEY *CurrentNsKey;
+ EFI_KEY_DESCRIPTOR *KeyConvertionTable;
+ EFI_EVENT KeyboardLayoutEvent;
+} USB_KB_DEV;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbKeyboardComponentName2;
+
+#define USB_KB_DEV_FROM_THIS(a) \
+ CR(a, USB_KB_DEV, SimpleInput, USB_KB_DEV_SIGNATURE)
+#define TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS(a) \
+ CR(a, USB_KB_DEV, SimpleInputEx, USB_KB_DEV_SIGNATURE)
+
+//
+// According to Universal Serial Bus HID Usage Tables document ver 1.12,
+// a Boot Keyboard should support the keycode range from 0x0 to 0x65 and 0xE0 to 0xE7.
+// 0xE0 to 0xE7 are for modifier keys, and 0x0 to 0x3 are reserved for typical
+// keyboard status or keyboard errors.
+// So the number of valid non-modifier USB keycodes is 0x62, and the number of
+// valid keycodes is 0x6A.
+//
+#define NUMBER_OF_VALID_NON_MODIFIER_USB_KEYCODE 0x62
+#define NUMBER_OF_VALID_USB_KEYCODE 0x6A
+//
+// 0x0 to 0x3 are reserved for typical keyboard status or keyboard errors.
+//
+#define USBKBD_VALID_KEYCODE(Key) ((UINT8) (Key) > 3)
+
+typedef struct {
+ UINT8 NumLock : 1;
+ UINT8 CapsLock : 1;
+ UINT8 ScrollLock : 1;
+ UINT8 Resrvd : 5;
+} LED_MAP;
+
+//
+// Functions of Driver Binding Protocol
+//
+/**
+ Check whether USB keyboard driver supports this device.
+
+ @param This The USB keyboard 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the keyboard device with this driver.
+
+ This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,
+ initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage
+ this keyboard device.
+
+ @param This The USB keyboard 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 usb keyboard driver.
+ @retval EFI_UNSUPPORTED No interrupt endpoint can be found.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the USB keyboard device handled by this driver.
+
+ @param This The USB keyboard 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_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
+ is not installed on Controller.
+ @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
+USBKeyboardDriverBindingStop (
+ 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
+UsbKeyboardComponentNameGetDriverName (
+ 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 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 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
+UsbKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// Functions of Simple Text Input Protocol
+//
+/**
+ Reset the input device and optionally run diagnostics
+
+ There are 2 types of reset for USB keyboard.
+ For non-exhaustive reset, only keyboard buffer is cleared.
+ For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
+ is also re-initialized.
+
+ @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
+USBKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device.
+
+ @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
+ @param Key A pointer to a buffer that is filled in with the keystroke
+ information for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+//
+// Simple Text Input Ex protocol functions
+//
+/**
+ Resets the input device hardware.
+
+ The Reset() function resets the input device hardware. As part
+ of initialization process, the firmware/device will make a quick
+ but reasonable attempt to verify that the device is functioning.
+ If the ExtendedVerification flag is TRUE the firmware may take
+ an extended amount of time to verify the device is operating on
+ reset. Otherwise the reset operation is to occur as quickly as
+ possible. The hardware verification process is not defined by
+ this specification and is left up to the platform firmware or
+ driver to implement.
+
+ @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device.
+
+ @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 available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardReadKeyStrokeEx (
+ 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 appropriately.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not support the ability to have its state set.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardSetState (
+ 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 for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 necessary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardRegisterKeyNotify (
+ 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 Cannot find the matching entry in database.
+
+**/
+EFI_STATUS
+EFIAPI
+USBKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
+ and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
+
+ @param Event Event to be signaled when a key is pressed.
+ @param Context Points to USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Free keyboard notify list.
+
+ @param NotifyList The keyboard notify list to free.
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER NotifyList is NULL.
+
+**/
+EFI_STATUS
+KbdFreeNotifyList (
+ IN OUT LIST_ENTRY *NotifyList
+ );
+
+/**
+ Check whether the pressed key matches a registered key or not.
+
+ @param RegsiteredData A pointer to keystroke data for the key that was registered.
+ @param InputData A pointer to keystroke data for the key that was pressed.
+
+ @retval TRUE Key pressed matches a registered key.
+ @retval FALSE Key pressed does not match a registered key.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Timer handler to convert the key from USB.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+USBKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.c
new file mode 100644
index 000000000..5faf82ea5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.c
@@ -0,0 +1,1982 @@
+/** @file
+ Helper functions for USB Keyboard Driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "KeyBoard.h"
+
+USB_KEYBOARD_LAYOUT_PACK_BIN mUsbKeyboardLayoutBin = {
+ sizeof (USB_KEYBOARD_LAYOUT_PACK_BIN), // Binary size
+
+ //
+ // EFI_HII_PACKAGE_HEADER
+ //
+ {
+ sizeof (USB_KEYBOARD_LAYOUT_PACK_BIN) - sizeof (UINT32),
+ EFI_HII_PACKAGE_KEYBOARD_LAYOUT
+ },
+ 1, // LayoutCount
+ sizeof (USB_KEYBOARD_LAYOUT_PACK_BIN) - sizeof (UINT32) - sizeof (EFI_HII_PACKAGE_HEADER) - sizeof (UINT16), // LayoutLength
+ USB_KEYBOARD_LAYOUT_KEY_GUID, // KeyGuid
+ sizeof (UINT16) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (UINT8) + (USB_KEYBOARD_KEY_COUNT * sizeof (EFI_KEY_DESCRIPTOR)), // LayoutDescriptorStringOffset
+ USB_KEYBOARD_KEY_COUNT, // DescriptorCount
+ {
+ //
+ // EFI_KEY_DESCRIPTOR (total number is USB_KEYBOARD_KEY_COUNT)
+ //
+ {EfiKeyC1, 'a', 'A', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB5, 'b', 'B', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB3, 'c', 'C', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC3, 'd', 'D', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD3, 'e', 'E', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC4, 'f', 'F', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC5, 'g', 'G', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC6, 'h', 'H', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD8, 'i', 'I', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC7, 'j', 'J', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC8, 'k', 'K', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC9, 'l', 'L', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB7, 'm', 'M', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB6, 'n', 'N', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD9, 'o', 'O', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD10, 'p', 'P', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD1, 'q', 'Q', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD4, 'r', 'R', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyC2, 's', 'S', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD5, 't', 'T', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD7, 'u', 'U', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB4, 'v', 'V', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD2, 'w', 'W', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB2, 'x', 'X', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyD6, 'y', 'Y', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyB1, 'z', 'Z', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},
+ {EfiKeyE1, '1', '!', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE2, '2', '@', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE3, '3', '#', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE4, '4', '$', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE5, '5', '%', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE6, '6', '^', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE7, '7', '&', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE8, '8', '*', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE9, '9', '(', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE10, '0', ')', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyEnter, 0x0d, 0x0d, 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyEsc, 0x1b, 0x1b, 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyBackSpace, 0x08, 0x08, 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyTab, 0x09, 0x09, 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeySpaceBar, ' ', ' ', 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyE11, '-', '_', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE12, '=', '+', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyD11, '[', '{', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyD12, ']', '}', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyD13, '\\', '|', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyC12, '\\', '|', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyC10, ';', ':', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyC11, '\'', '"', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyE0, '`', '~', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyB8, ',', '<', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyB9, '.', '>', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyB10, '/', '?', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT},
+ {EfiKeyCapsLock, 0x00, 0x00, 0, 0, EFI_CAPS_LOCK_MODIFIER, 0},
+ {EfiKeyF1, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_ONE_MODIFIER, 0},
+ {EfiKeyF2, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_TWO_MODIFIER, 0},
+ {EfiKeyF3, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_THREE_MODIFIER, 0},
+ {EfiKeyF4, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_FOUR_MODIFIER, 0},
+ {EfiKeyF5, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_FIVE_MODIFIER, 0},
+ {EfiKeyF6, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_SIX_MODIFIER, 0},
+ {EfiKeyF7, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_SEVEN_MODIFIER, 0},
+ {EfiKeyF8, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_EIGHT_MODIFIER, 0},
+ {EfiKeyF9, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_NINE_MODIFIER, 0},
+ {EfiKeyF10, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_TEN_MODIFIER, 0},
+ {EfiKeyF11, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_ELEVEN_MODIFIER, 0},
+ {EfiKeyF12, 0x00, 0x00, 0, 0, EFI_FUNCTION_KEY_TWELVE_MODIFIER, 0},
+ {EfiKeyPrint, 0x00, 0x00, 0, 0, EFI_PRINT_MODIFIER, 0},
+ {EfiKeySLck, 0x00, 0x00, 0, 0, EFI_SCROLL_LOCK_MODIFIER, 0},
+ {EfiKeyPause, 0x00, 0x00, 0, 0, EFI_PAUSE_MODIFIER, 0},
+ {EfiKeyIns, 0x00, 0x00, 0, 0, EFI_INSERT_MODIFIER, 0},
+ {EfiKeyHome, 0x00, 0x00, 0, 0, EFI_HOME_MODIFIER, 0},
+ {EfiKeyPgUp, 0x00, 0x00, 0, 0, EFI_PAGE_UP_MODIFIER, 0},
+ {EfiKeyDel, 0x00, 0x00, 0, 0, EFI_DELETE_MODIFIER, 0},
+ {EfiKeyEnd, 0x00, 0x00, 0, 0, EFI_END_MODIFIER, 0},
+ {EfiKeyPgDn, 0x00, 0x00, 0, 0, EFI_PAGE_DOWN_MODIFIER, 0},
+ {EfiKeyRightArrow, 0x00, 0x00, 0, 0, EFI_RIGHT_ARROW_MODIFIER, 0},
+ {EfiKeyLeftArrow, 0x00, 0x00, 0, 0, EFI_LEFT_ARROW_MODIFIER, 0},
+ {EfiKeyDownArrow, 0x00, 0x00, 0, 0, EFI_DOWN_ARROW_MODIFIER, 0},
+ {EfiKeyUpArrow, 0x00, 0x00, 0, 0, EFI_UP_ARROW_MODIFIER, 0},
+ {EfiKeyNLck, 0x00, 0x00, 0, 0, EFI_NUM_LOCK_MODIFIER, 0},
+ {EfiKeySlash, '/', '/', 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyAsterisk, '*', '*', 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyMinus, '-', '-', 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyPlus, '+', '+', 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyEnter, 0x0d, 0x0d, 0, 0, EFI_NULL_MODIFIER, 0},
+ {EfiKeyOne, '1', '1', 0, 0, EFI_END_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyTwo, '2', '2', 0, 0, EFI_DOWN_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyThree, '3', '3', 0, 0, EFI_PAGE_DOWN_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyFour, '4', '4', 0, 0, EFI_LEFT_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyFive, '5', '5', 0, 0, EFI_NULL_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeySix, '6', '6', 0, 0, EFI_RIGHT_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeySeven, '7', '7', 0, 0, EFI_HOME_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyEight, '8', '8', 0, 0, EFI_UP_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyNine, '9', '9', 0, 0, EFI_PAGE_UP_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyZero, '0', '0', 0, 0, EFI_INSERT_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyPeriod, '.', '.', 0, 0, EFI_DELETE_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},
+ {EfiKeyA4, 0x00, 0x00, 0, 0, EFI_MENU_MODIFIER, 0},
+ {EfiKeyLCtrl, 0, 0, 0, 0, EFI_LEFT_CONTROL_MODIFIER, 0},
+ {EfiKeyLShift, 0, 0, 0, 0, EFI_LEFT_SHIFT_MODIFIER, 0},
+ {EfiKeyLAlt, 0, 0, 0, 0, EFI_LEFT_ALT_MODIFIER, 0},
+ {EfiKeyA0, 0, 0, 0, 0, EFI_LEFT_LOGO_MODIFIER, 0},
+ {EfiKeyRCtrl, 0, 0, 0, 0, EFI_RIGHT_CONTROL_MODIFIER, 0},
+ {EfiKeyRShift, 0, 0, 0, 0, EFI_RIGHT_SHIFT_MODIFIER, 0},
+ {EfiKeyA2, 0, 0, 0, 0, EFI_RIGHT_ALT_MODIFIER, 0},
+ {EfiKeyA3, 0, 0, 0, 0, EFI_RIGHT_LOGO_MODIFIER, 0},
+ },
+ 1, // DescriptionCount
+ {'e', 'n', '-', 'U', 'S'}, // RFC4646 language code
+ ' ', // Space
+ {'E', 'n', 'g', 'l', 'i', 's', 'h', ' ', 'K', 'e', 'y', 'b', 'o', 'a', 'r', 'd', '\0'}, // DescriptionString[]
+};
+
+//
+// EFI_KEY to USB Keycode conversion table
+// EFI_KEY is defined in UEFI spec.
+// USB Keycode is defined in USB HID Firmware spec.
+//
+UINT8 EfiKeyToUsbKeyCodeConvertionTable[] = {
+ 0xe0, // EfiKeyLCtrl
+ 0xe3, // EfiKeyA0
+ 0xe2, // EfiKeyLAlt
+ 0x2c, // EfiKeySpaceBar
+ 0xe6, // EfiKeyA2
+ 0xe7, // EfiKeyA3
+ 0x65, // EfiKeyA4
+ 0xe4, // EfiKeyRCtrl
+ 0x50, // EfiKeyLeftArrow
+ 0x51, // EfiKeyDownArrow
+ 0x4F, // EfiKeyRightArrow
+ 0x62, // EfiKeyZero
+ 0x63, // EfiKeyPeriod
+ 0x28, // EfiKeyEnter
+ 0xe1, // EfiKeyLShift
+ 0x64, // EfiKeyB0
+ 0x1D, // EfiKeyB1
+ 0x1B, // EfiKeyB2
+ 0x06, // EfiKeyB3
+ 0x19, // EfiKeyB4
+ 0x05, // EfiKeyB5
+ 0x11, // EfiKeyB6
+ 0x10, // EfiKeyB7
+ 0x36, // EfiKeyB8
+ 0x37, // EfiKeyB9
+ 0x38, // EfiKeyB10
+ 0xe5, // EfiKeyRShift
+ 0x52, // EfiKeyUpArrow
+ 0x59, // EfiKeyOne
+ 0x5A, // EfiKeyTwo
+ 0x5B, // EfiKeyThree
+ 0x39, // EfiKeyCapsLock
+ 0x04, // EfiKeyC1
+ 0x16, // EfiKeyC2
+ 0x07, // EfiKeyC3
+ 0x09, // EfiKeyC4
+ 0x0A, // EfiKeyC5
+ 0x0B, // EfiKeyC6
+ 0x0D, // EfiKeyC7
+ 0x0E, // EfiKeyC8
+ 0x0F, // EfiKeyC9
+ 0x33, // EfiKeyC10
+ 0x34, // EfiKeyC11
+ 0x32, // EfiKeyC12
+ 0x5C, // EfiKeyFour
+ 0x5D, // EfiKeyFive
+ 0x5E, // EfiKeySix
+ 0x57, // EfiKeyPlus
+ 0x2B, // EfiKeyTab
+ 0x14, // EfiKeyD1
+ 0x1A, // EfiKeyD2
+ 0x08, // EfiKeyD3
+ 0x15, // EfiKeyD4
+ 0x17, // EfiKeyD5
+ 0x1C, // EfiKeyD6
+ 0x18, // EfiKeyD7
+ 0x0C, // EfiKeyD8
+ 0x12, // EfiKeyD9
+ 0x13, // EfiKeyD10
+ 0x2F, // EfiKeyD11
+ 0x30, // EfiKeyD12
+ 0x31, // EfiKeyD13
+ 0x4C, // EfiKeyDel
+ 0x4D, // EfiKeyEnd
+ 0x4E, // EfiKeyPgDn
+ 0x5F, // EfiKeySeven
+ 0x60, // EfiKeyEight
+ 0x61, // EfiKeyNine
+ 0x35, // EfiKeyE0
+ 0x1E, // EfiKeyE1
+ 0x1F, // EfiKeyE2
+ 0x20, // EfiKeyE3
+ 0x21, // EfiKeyE4
+ 0x22, // EfiKeyE5
+ 0x23, // EfiKeyE6
+ 0x24, // EfiKeyE7
+ 0x25, // EfiKeyE8
+ 0x26, // EfiKeyE9
+ 0x27, // EfiKeyE10
+ 0x2D, // EfiKeyE11
+ 0x2E, // EfiKeyE12
+ 0x2A, // EfiKeyBackSpace
+ 0x49, // EfiKeyIns
+ 0x4A, // EfiKeyHome
+ 0x4B, // EfiKeyPgUp
+ 0x53, // EfiKeyNLck
+ 0x54, // EfiKeySlash
+ 0x55, // EfiKeyAsterisk
+ 0x56, // EfiKeyMinus
+ 0x29, // EfiKeyEsc
+ 0x3A, // EfiKeyF1
+ 0x3B, // EfiKeyF2
+ 0x3C, // EfiKeyF3
+ 0x3D, // EfiKeyF4
+ 0x3E, // EfiKeyF5
+ 0x3F, // EfiKeyF6
+ 0x40, // EfiKeyF7
+ 0x41, // EfiKeyF8
+ 0x42, // EfiKeyF9
+ 0x43, // EfiKeyF10
+ 0x44, // EfiKeyF11
+ 0x45, // EfiKeyF12
+ 0x46, // EfiKeyPrint
+ 0x47, // EfiKeySLck
+ 0x48 // EfiKeyPause
+};
+
+//
+// Keyboard modifier value to EFI Scan Code conversion table
+// EFI Scan Code and the modifier values are defined in UEFI spec.
+//
+UINT8 ModifierValueToEfiScanCodeConvertionTable[] = {
+ SCAN_NULL, // EFI_NULL_MODIFIER
+ SCAN_NULL, // EFI_LEFT_CONTROL_MODIFIER
+ SCAN_NULL, // EFI_RIGHT_CONTROL_MODIFIER
+ SCAN_NULL, // EFI_LEFT_ALT_MODIFIER
+ SCAN_NULL, // EFI_RIGHT_ALT_MODIFIER
+ SCAN_NULL, // EFI_ALT_GR_MODIFIER
+ SCAN_INSERT, // EFI_INSERT_MODIFIER
+ SCAN_DELETE, // EFI_DELETE_MODIFIER
+ SCAN_PAGE_DOWN, // EFI_PAGE_DOWN_MODIFIER
+ SCAN_PAGE_UP, // EFI_PAGE_UP_MODIFIER
+ SCAN_HOME, // EFI_HOME_MODIFIER
+ SCAN_END, // EFI_END_MODIFIER
+ SCAN_NULL, // EFI_LEFT_SHIFT_MODIFIER
+ SCAN_NULL, // EFI_RIGHT_SHIFT_MODIFIER
+ SCAN_NULL, // EFI_CAPS_LOCK_MODIFIER
+ SCAN_NULL, // EFI_NUM_LOCK_MODIFIER
+ SCAN_LEFT, // EFI_LEFT_ARROW_MODIFIER
+ SCAN_RIGHT, // EFI_RIGHT_ARROW_MODIFIER
+ SCAN_DOWN, // EFI_DOWN_ARROW_MODIFIER
+ SCAN_UP, // EFI_UP_ARROW_MODIFIER
+ SCAN_NULL, // EFI_NS_KEY_MODIFIER
+ SCAN_NULL, // EFI_NS_KEY_DEPENDENCY_MODIFIER
+ SCAN_F1, // EFI_FUNCTION_KEY_ONE_MODIFIER
+ SCAN_F2, // EFI_FUNCTION_KEY_TWO_MODIFIER
+ SCAN_F3, // EFI_FUNCTION_KEY_THREE_MODIFIER
+ SCAN_F4, // EFI_FUNCTION_KEY_FOUR_MODIFIER
+ SCAN_F5, // EFI_FUNCTION_KEY_FIVE_MODIFIER
+ SCAN_F6, // EFI_FUNCTION_KEY_SIX_MODIFIER
+ SCAN_F7, // EFI_FUNCTION_KEY_SEVEN_MODIFIER
+ SCAN_F8, // EFI_FUNCTION_KEY_EIGHT_MODIFIER
+ SCAN_F9, // EFI_FUNCTION_KEY_NINE_MODIFIER
+ SCAN_F10, // EFI_FUNCTION_KEY_TEN_MODIFIER
+ SCAN_F11, // EFI_FUNCTION_KEY_ELEVEN_MODIFIER
+ SCAN_F12, // EFI_FUNCTION_KEY_TWELVE_MODIFIER
+ //
+ // For Partial Keystroke support
+ //
+ SCAN_NULL, // EFI_PRINT_MODIFIER
+ SCAN_NULL, // EFI_SYS_REQUEST_MODIFIER
+ SCAN_NULL, // EFI_SCROLL_LOCK_MODIFIER
+ SCAN_PAUSE, // EFI_PAUSE_MODIFIER
+ SCAN_NULL, // EFI_BREAK_MODIFIER
+ SCAN_NULL, // EFI_LEFT_LOGO_MODIFIER
+ SCAN_NULL, // EFI_RIGHT_LOGO_MODIFER
+ SCAN_NULL, // EFI_MENU_MODIFER
+};
+
+/**
+ Initialize Key Convention Table by using default keyboard layout.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+ @retval EFI_SUCCESS The default keyboard layout was installed successfully
+ @retval Others Failure to install default keyboard layout.
+**/
+EFI_STATUS
+InstallDefaultKeyboardLayout (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_HANDLE HiiHandle;
+
+ //
+ // Locate Hii database protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Keyboard Layout package to HII database
+ //
+ HiiHandle = HiiAddPackages (
+ &gUsbKeyboardLayoutPackageGuid,
+ UsbKeyboardDevice->ControllerHandle,
+ &mUsbKeyboardLayoutBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set current keyboard layout
+ //
+ Status = HiiDatabase->SetKeyboardLayout (HiiDatabase, &gUsbKeyboardLayoutKeyGuid);
+
+ return Status;
+}
+
+
+/**
+ Uses USB I/O to check whether the device is a USB keyboard device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB keyboard device.
+ @retval FALSE Device is a not USB keyboard device.
+
+**/
+BOOLEAN
+IsUSBKeyboard (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ //
+ // Get the default interface descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &InterfaceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (InterfaceDescriptor.InterfaceClass == CLASS_HID &&
+ InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT &&
+ InterfaceDescriptor.InterfaceProtocol == PROTOCOL_KEYBOARD
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get current keyboard layout from HII database.
+
+ @return Pointer to HII Keyboard Layout.
+ NULL means failure occurred while trying to get keyboard layout.
+
+**/
+EFI_HII_KEYBOARD_LAYOUT *
+GetCurrentKeyboardLayout (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout;
+ UINT16 Length;
+
+ //
+ // Locate HII Database Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get current keyboard layout from HII database
+ //
+ Length = 0;
+ KeyboardLayout = NULL;
+ Status = HiiDatabase->GetKeyboardLayout (
+ HiiDatabase,
+ NULL,
+ &Length,
+ KeyboardLayout
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ KeyboardLayout = AllocatePool (Length);
+ ASSERT (KeyboardLayout != NULL);
+
+ Status = HiiDatabase->GetKeyboardLayout (
+ HiiDatabase,
+ NULL,
+ &Length,
+ KeyboardLayout
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (KeyboardLayout);
+ KeyboardLayout = NULL;
+ }
+ }
+
+ return KeyboardLayout;
+}
+
+/**
+ Find Key Descriptor in Key Convertion Table given its USB keycode.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyCode USB Keycode.
+
+ @return The Key Descriptor in Key Convertion Table.
+ NULL means not found.
+
+**/
+EFI_KEY_DESCRIPTOR *
+GetKeyDescriptor (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ IN UINT8 KeyCode
+ )
+{
+ UINT8 Index;
+
+ //
+ // Make sure KeyCode is in the range of [0x4, 0x65] or [0xe0, 0xe7]
+ //
+ if ((!USBKBD_VALID_KEYCODE (KeyCode)) || ((KeyCode > 0x65) && (KeyCode < 0xe0)) || (KeyCode > 0xe7)) {
+ return NULL;
+ }
+
+ //
+ // Calculate the index of Key Descriptor in Key Convertion Table
+ //
+ if (KeyCode <= 0x65) {
+ Index = (UINT8) (KeyCode - 4);
+ } else {
+ Index = (UINT8) (KeyCode - 0xe0 + NUMBER_OF_VALID_NON_MODIFIER_USB_KEYCODE);
+ }
+
+ return &UsbKeyboardDevice->KeyConvertionTable[Index];
+}
+
+/**
+ Find Non-Spacing key for given Key descriptor.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyDescriptor Key descriptor.
+
+ @return The Non-Spacing key corresponding to KeyDescriptor
+ NULL means not found.
+
+**/
+USB_NS_KEY *
+FindUsbNsKey (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ IN EFI_KEY_DESCRIPTOR *KeyDescriptor
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NsKeyList;
+ USB_NS_KEY *UsbNsKey;
+
+ NsKeyList = &UsbKeyboardDevice->NsKeyList;
+ Link = GetFirstNode (NsKeyList);
+ while (!IsNull (NsKeyList, Link)) {
+ UsbNsKey = USB_NS_KEY_FORM_FROM_LINK (Link);
+
+ if (UsbNsKey->NsKey[0].Key == KeyDescriptor->Key) {
+ return UsbNsKey;
+ }
+
+ Link = GetNextNode (NsKeyList, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Find physical key definition for a given key descriptor.
+
+ For a specified non-spacing key, there are a list of physical
+ keys following it. This function traverses the list of
+ physical keys and tries to find the physical key matching
+ the KeyDescriptor.
+
+ @param UsbNsKey The non-spacing key information.
+ @param KeyDescriptor The key descriptor.
+
+ @return The physical key definition.
+ If no physical key is found, parameter KeyDescriptor is returned.
+
+**/
+EFI_KEY_DESCRIPTOR *
+FindPhysicalKey (
+ IN USB_NS_KEY *UsbNsKey,
+ IN EFI_KEY_DESCRIPTOR *KeyDescriptor
+ )
+{
+ UINTN Index;
+ EFI_KEY_DESCRIPTOR *PhysicalKey;
+
+ PhysicalKey = &UsbNsKey->NsKey[1];
+ for (Index = 0; Index < UsbNsKey->KeyCount; Index++) {
+ if (KeyDescriptor->Key == PhysicalKey->Key) {
+ return PhysicalKey;
+ }
+
+ PhysicalKey++;
+ }
+
+ //
+ // No children definition matched, return original key
+ //
+ return KeyDescriptor;
+}
+
+/**
+ The notification function for EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID.
+
+ This function is registered to event of EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+ group type, which will be triggered by EFI_HII_DATABASE_PROTOCOL.SetKeyboardLayout().
+ It tries to get current keyboard layout from HII database.
+
+ @param Event Event being signaled.
+ @param Context Points to USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+SetKeyboardLayoutEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout;
+ EFI_KEY_DESCRIPTOR TempKey;
+ EFI_KEY_DESCRIPTOR *KeyDescriptor;
+ EFI_KEY_DESCRIPTOR *TableEntry;
+ EFI_KEY_DESCRIPTOR *NsKey;
+ USB_NS_KEY *UsbNsKey;
+ UINTN Index;
+ UINTN Index2;
+ UINTN KeyCount;
+ UINT8 KeyCode;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+ if (UsbKeyboardDevice->Signature != USB_KB_DEV_SIGNATURE) {
+ return;
+ }
+
+ //
+ // Try to get current keyboard layout from HII database
+ //
+ KeyboardLayout = GetCurrentKeyboardLayout ();
+ if (KeyboardLayout == NULL) {
+ return;
+ }
+
+ //
+ // Re-allocate resource for KeyConvertionTable
+ //
+ ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
+ UsbKeyboardDevice->KeyConvertionTable = AllocateZeroPool ((NUMBER_OF_VALID_USB_KEYCODE) * sizeof (EFI_KEY_DESCRIPTOR));
+ ASSERT (UsbKeyboardDevice->KeyConvertionTable != NULL);
+
+ //
+ // Traverse the list of key descriptors following the header of EFI_HII_KEYBOARD_LAYOUT
+ //
+ KeyDescriptor = (EFI_KEY_DESCRIPTOR *) (((UINT8 *) KeyboardLayout) + sizeof (EFI_HII_KEYBOARD_LAYOUT));
+ for (Index = 0; Index < KeyboardLayout->DescriptorCount; Index++) {
+ //
+ // Copy from HII keyboard layout package binary for alignment
+ //
+ CopyMem (&TempKey, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));
+
+ //
+ // Fill the key into KeyConvertionTable, whose index is calculated from USB keycode.
+ //
+ KeyCode = EfiKeyToUsbKeyCodeConvertionTable [(UINT8) (TempKey.Key)];
+ TableEntry = GetKeyDescriptor (UsbKeyboardDevice, KeyCode);
+ if (TableEntry == NULL) {
+ ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
+ FreePool (KeyboardLayout);
+ return;
+ }
+ CopyMem (TableEntry, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));
+
+ //
+ // For non-spacing key, create the list with a non-spacing key followed by physical keys.
+ //
+ if (TempKey.Modifier == EFI_NS_KEY_MODIFIER) {
+ UsbNsKey = AllocateZeroPool (sizeof (USB_NS_KEY));
+ ASSERT (UsbNsKey != NULL);
+
+ //
+ // Search for sequential children physical key definitions
+ //
+ KeyCount = 0;
+ NsKey = KeyDescriptor + 1;
+ for (Index2 = (UINT8) Index + 1; Index2 < KeyboardLayout->DescriptorCount; Index2++) {
+ CopyMem (&TempKey, NsKey, sizeof (EFI_KEY_DESCRIPTOR));
+ if (TempKey.Modifier == EFI_NS_KEY_DEPENDENCY_MODIFIER) {
+ KeyCount++;
+ } else {
+ break;
+ }
+ NsKey++;
+ }
+
+ UsbNsKey->Signature = USB_NS_KEY_SIGNATURE;
+ UsbNsKey->KeyCount = KeyCount;
+ UsbNsKey->NsKey = AllocateCopyPool (
+ (KeyCount + 1) * sizeof (EFI_KEY_DESCRIPTOR),
+ KeyDescriptor
+ );
+ InsertTailList (&UsbKeyboardDevice->NsKeyList, &UsbNsKey->Link);
+
+ //
+ // Skip over the child physical keys
+ //
+ Index += KeyCount;
+ KeyDescriptor += KeyCount;
+ }
+
+ KeyDescriptor++;
+ }
+
+ //
+ // There are two EfiKeyEnter, duplicate its key descriptor
+ //
+ TableEntry = GetKeyDescriptor (UsbKeyboardDevice, 0x58);
+ KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, 0x28);
+ CopyMem (TableEntry, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));
+
+ FreePool (KeyboardLayout);
+}
+
+/**
+ Destroy resources for keyboard layout.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+**/
+VOID
+ReleaseKeyboardLayoutResources (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice
+ )
+{
+ USB_NS_KEY *UsbNsKey;
+ LIST_ENTRY *Link;
+
+ if (UsbKeyboardDevice->KeyConvertionTable != NULL) {
+ FreePool (UsbKeyboardDevice->KeyConvertionTable);
+ }
+ UsbKeyboardDevice->KeyConvertionTable = NULL;
+
+ while (!IsListEmpty (&UsbKeyboardDevice->NsKeyList)) {
+ Link = GetFirstNode (&UsbKeyboardDevice->NsKeyList);
+ UsbNsKey = USB_NS_KEY_FORM_FROM_LINK (Link);
+ RemoveEntryList (&UsbNsKey->Link);
+
+ FreePool (UsbNsKey->NsKey);
+ FreePool (UsbNsKey);
+ }
+}
+
+/**
+ Initialize USB keyboard layout.
+
+ This function initializes Key Convertion Table for the USB keyboard device.
+ It first tries to retrieve layout from HII database. If failed and default
+ layout is enabled, then it just uses the default layout.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+ @retval EFI_SUCCESS Initialization succeeded.
+ @retval EFI_NOT_READY Keyboard layout cannot be retrieve from HII
+ database, and default layout is disabled.
+ @retval Other Fail to register event to EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group.
+
+**/
+EFI_STATUS
+InitKeyboardLayout (
+ OUT USB_KB_DEV *UsbKeyboardDevice
+ )
+{
+ EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout;
+ EFI_STATUS Status;
+
+ UsbKeyboardDevice->KeyConvertionTable = AllocateZeroPool ((NUMBER_OF_VALID_USB_KEYCODE) * sizeof (EFI_KEY_DESCRIPTOR));
+ ASSERT (UsbKeyboardDevice->KeyConvertionTable != NULL);
+
+ InitializeListHead (&UsbKeyboardDevice->NsKeyList);
+ UsbKeyboardDevice->CurrentNsKey = NULL;
+ UsbKeyboardDevice->KeyboardLayoutEvent = NULL;
+
+ //
+ // Register event to EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group,
+ // which will be triggered by EFI_HII_DATABASE_PROTOCOL.SetKeyboardLayout().
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SetKeyboardLayoutEvent,
+ UsbKeyboardDevice,
+ &gEfiHiiKeyBoardLayoutGuid,
+ &UsbKeyboardDevice->KeyboardLayoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyboardLayout = GetCurrentKeyboardLayout ();
+ if (KeyboardLayout != NULL) {
+ //
+ // If current keyboard layout is successfully retrieved from HII database,
+ // force to initialize the keyboard layout.
+ //
+ gBS->SignalEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
+ } else {
+ if (FeaturePcdGet (PcdDisableDefaultKeyboardLayoutInUsbKbDriver)) {
+ //
+ // If no keyboard layout can be retrieved from HII database, and default layout
+ // is disabled, then return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+ //
+ // If no keyboard layout can be retrieved from HII database, and default layout
+ // is enabled, then load the default keyboard layout.
+ //
+ InstallDefaultKeyboardLayout (UsbKeyboardDevice);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize USB keyboard device and all private data structures.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+ @retval EFI_SUCCESS Initialization is successful.
+ @retval EFI_DEVICE_ERROR Keyboard initialization failed.
+
+**/
+EFI_STATUS
+InitUSBKeyboard (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice
+ )
+{
+ UINT16 ConfigValue;
+ UINT8 Protocol;
+ EFI_STATUS Status;
+ UINT32 TransferResult;
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
+ InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
+ InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));
+
+ //
+ // Use the config out of the descriptor
+ // Assumed the first config is the correct one and this is not always the case
+ //
+ Status = UsbGetConfiguration (
+ UsbKeyboardDevice->UsbIo,
+ &ConfigValue,
+ &TransferResult
+ );
+ if (EFI_ERROR (Status)) {
+ ConfigValue = 0x01;
+ //
+ // Uses default configuration to configure the USB Keyboard device.
+ //
+ Status = UsbSetConfiguration (
+ UsbKeyboardDevice->UsbIo,
+ ConfigValue,
+ &TransferResult
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If configuration could not be set here, it means
+ // the keyboard interface has some errors and could
+ // not be initialized
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INTERFACE_ERROR),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ UsbGetProtocolRequest (
+ UsbKeyboardDevice->UsbIo,
+ UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
+ &Protocol
+ );
+ //
+ // Set boot protocol for the USB Keyboard.
+ // This driver only supports boot protocol.
+ //
+ if (Protocol != BOOT_PROTOCOL) {
+ UsbSetProtocolRequest (
+ UsbKeyboardDevice->UsbIo,
+ UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
+ BOOT_PROTOCOL
+ );
+ }
+
+ UsbKeyboardDevice->CtrlOn = FALSE;
+ UsbKeyboardDevice->AltOn = FALSE;
+ UsbKeyboardDevice->ShiftOn = FALSE;
+ UsbKeyboardDevice->NumLockOn = FALSE;
+ UsbKeyboardDevice->CapsOn = FALSE;
+ UsbKeyboardDevice->ScrollOn = FALSE;
+
+ UsbKeyboardDevice->LeftCtrlOn = FALSE;
+ UsbKeyboardDevice->LeftAltOn = FALSE;
+ UsbKeyboardDevice->LeftShiftOn = FALSE;
+ UsbKeyboardDevice->LeftLogoOn = FALSE;
+ UsbKeyboardDevice->RightCtrlOn = FALSE;
+ UsbKeyboardDevice->RightAltOn = FALSE;
+ UsbKeyboardDevice->RightShiftOn = FALSE;
+ UsbKeyboardDevice->RightLogoOn = FALSE;
+ UsbKeyboardDevice->MenuKeyOn = FALSE;
+ UsbKeyboardDevice->SysReqOn = FALSE;
+
+ UsbKeyboardDevice->AltGrOn = FALSE;
+
+ UsbKeyboardDevice->CurrentNsKey = NULL;
+
+ //
+ // Sync the initial state of lights on keyboard.
+ //
+ SetKeyLED (UsbKeyboardDevice);
+
+ ZeroMem (UsbKeyboardDevice->LastKeyCodeArray, sizeof (UINT8) * 8);
+
+ //
+ // Create event for repeat keys' generation.
+ //
+ if (UsbKeyboardDevice->RepeatTimer != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
+ UsbKeyboardDevice->RepeatTimer = NULL;
+ }
+
+ gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ USBKeyboardRepeatHandler,
+ UsbKeyboardDevice,
+ &UsbKeyboardDevice->RepeatTimer
+ );
+
+ //
+ // Create event for delayed recovery, which deals with device error.
+ //
+ if (UsbKeyboardDevice->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
+ UsbKeyboardDevice->DelayedRecoveryEvent = NULL;
+ }
+
+ gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ USBKeyboardRecoveryHandler,
+ UsbKeyboardDevice,
+ &UsbKeyboardDevice->DelayedRecoveryEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Handler function for USB keyboard's asynchronous interrupt transfer.
+
+ This function is the handler function for USB keyboard's asynchronous interrupt transfer
+ to manage the keyboard. It parses the USB keyboard input report, and inserts data to
+ keyboard buffer according to state of modifer keys and normal keys. Timer for repeat key
+ is also set accordingly.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardHandler (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 *CurKeyCodeBuffer;
+ UINT8 *OldKeyCodeBuffer;
+ UINT8 CurModifierMap;
+ UINT8 OldModifierMap;
+ UINT8 Mask;
+ UINTN Index;
+ UINT8 Index2;
+ BOOLEAN KeyRelease;
+ BOOLEAN KeyPress;
+ USB_KEY UsbKey;
+ UINT8 NewRepeatKey;
+ UINT32 UsbStatus;
+ EFI_KEY_DESCRIPTOR *KeyDescriptor;
+
+ ASSERT (Context != NULL);
+
+ NewRepeatKey = 0;
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+ UsbIo = UsbKeyboardDevice->UsbIo;
+
+ //
+ // Analyzes Result and performs corresponding action.
+ //
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // Some errors happen during the process
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INPUT_ERROR),
+ UsbKeyboardDevice->DevicePath
+ );
+
+ //
+ // Stop the repeat key generation if any
+ //
+ UsbKeyboardDevice->RepeatKey = 0;
+
+ gBS->SetTimer (
+ UsbKeyboardDevice->RepeatTimer,
+ TimerCancel,
+ USBKBD_REPEAT_RATE
+ );
+
+ if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
+ UsbClearEndpointHalt (
+ UsbIo,
+ UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
+ &UsbStatus
+ );
+ }
+
+ //
+ // Delete & Submit this interrupt again
+ // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ //
+ // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
+ //
+ gBS->SetTimer (
+ UsbKeyboardDevice->DelayedRecoveryEvent,
+ TimerRelative,
+ EFI_USB_INTERRUPT_DELAY
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If no error and no data, just return EFI_SUCCESS.
+ //
+ if (DataLength == 0 || Data == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Following code checks current keyboard input report against old key code buffer.
+ // According to USB HID Firmware Specification, the report consists of 8 bytes.
+ // Byte 0 is map of Modifier keys.
+ // Byte 1 is reserved.
+ // Bytes 2 to 7 are keycodes.
+ //
+ if (DataLength < 8) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CurKeyCodeBuffer = (UINT8 *) Data;
+ OldKeyCodeBuffer = UsbKeyboardDevice->LastKeyCodeArray;
+
+ //
+ // Checks for new key stroke.
+ //
+ for (Index = 0; Index < 8; Index++) {
+ if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) {
+ break;
+ }
+ }
+
+ //
+ // If no new key, return EFI_SUCCESS immediately.
+ //
+ if (Index == 8) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse the modifier key, which is the first byte of keyboard input report.
+ //
+ CurModifierMap = CurKeyCodeBuffer[0];
+ OldModifierMap = OldKeyCodeBuffer[0];
+
+ //
+ // Handle modifier key's pressing or releasing situation.
+ // According to USB HID Firmware spec, Byte 0 uses following map of Modifier keys:
+ // Bit0: Left Control, Keycode: 0xe0
+ // Bit1: Left Shift, Keycode: 0xe1
+ // Bit2: Left Alt, Keycode: 0xe2
+ // Bit3: Left GUI, Keycode: 0xe3
+ // Bit4: Right Control, Keycode: 0xe4
+ // Bit5: Right Shift, Keycode: 0xe5
+ // Bit6: Right Alt, Keycode: 0xe6
+ // Bit7: Right GUI, Keycode: 0xe7
+ //
+ for (Index = 0; Index < 8; Index++) {
+ Mask = (UINT8) (1 << Index);
+ if ((CurModifierMap & Mask) != (OldModifierMap & Mask)) {
+ //
+ // If current modifier key is up, then CurModifierMap & Mask = 0;
+ // otherwise it is a non-zero value.
+ // Insert the changed modifier key into key buffer.
+ //
+ UsbKey.KeyCode = (UINT8) (0xe0 + Index);
+ UsbKey.Down = (BOOLEAN) ((CurModifierMap & Mask) != 0);
+ Enqueue (&UsbKeyboardDevice->UsbKeyQueue, &UsbKey, sizeof (UsbKey));
+ }
+ }
+
+ //
+ // Handle normal key's releasing situation
+ // Bytes 2 to 7 are for normal keycodes
+ //
+ KeyRelease = FALSE;
+ for (Index = 2; Index < 8; Index++) {
+
+ if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) {
+ continue;
+ }
+ //
+ // For any key in old keycode buffer, if it is not in current keycode buffer,
+ // then it is released. Otherwise, it is not released.
+ //
+ KeyRelease = TRUE;
+ for (Index2 = 2; Index2 < 8; Index2++) {
+
+ if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index2])) {
+ continue;
+ }
+
+ if (OldKeyCodeBuffer[Index] == CurKeyCodeBuffer[Index2]) {
+ KeyRelease = FALSE;
+ break;
+ }
+ }
+
+ if (KeyRelease) {
+ UsbKey.KeyCode = OldKeyCodeBuffer[Index];
+ UsbKey.Down = FALSE;
+ Enqueue (&UsbKeyboardDevice->UsbKeyQueue, &UsbKey, sizeof (UsbKey));
+ //
+ // The original repeat key is released.
+ //
+ if (OldKeyCodeBuffer[Index] == UsbKeyboardDevice->RepeatKey) {
+ UsbKeyboardDevice->RepeatKey = 0;
+ }
+ }
+ }
+
+ //
+ // If original repeat key is released, cancel the repeat timer
+ //
+ if (UsbKeyboardDevice->RepeatKey == 0) {
+ gBS->SetTimer (
+ UsbKeyboardDevice->RepeatTimer,
+ TimerCancel,
+ USBKBD_REPEAT_RATE
+ );
+ }
+
+ //
+ // Handle normal key's pressing situation
+ //
+ KeyPress = FALSE;
+ for (Index = 2; Index < 8; Index++) {
+
+ if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index])) {
+ continue;
+ }
+ //
+ // For any key in current keycode buffer, if it is not in old keycode buffer,
+ // then it is pressed. Otherwise, it is not pressed.
+ //
+ KeyPress = TRUE;
+ for (Index2 = 2; Index2 < 8; Index2++) {
+
+ if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index2])) {
+ continue;
+ }
+
+ if (CurKeyCodeBuffer[Index] == OldKeyCodeBuffer[Index2]) {
+ KeyPress = FALSE;
+ break;
+ }
+ }
+
+ if (KeyPress) {
+ UsbKey.KeyCode = CurKeyCodeBuffer[Index];
+ UsbKey.Down = TRUE;
+ Enqueue (&UsbKeyboardDevice->UsbKeyQueue, &UsbKey, sizeof (UsbKey));
+
+ //
+ // Handle repeat key
+ //
+ KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, CurKeyCodeBuffer[Index]);
+ if (KeyDescriptor == NULL) {
+ continue;
+ }
+
+ if (KeyDescriptor->Modifier == EFI_NUM_LOCK_MODIFIER || KeyDescriptor->Modifier == EFI_CAPS_LOCK_MODIFIER) {
+ //
+ // For NumLock or CapsLock pressed, there is no need to handle repeat key for them.
+ //
+ UsbKeyboardDevice->RepeatKey = 0;
+ } else {
+ //
+ // Prepare new repeat key, and clear the original one.
+ //
+ NewRepeatKey = CurKeyCodeBuffer[Index];
+ UsbKeyboardDevice->RepeatKey = 0;
+ }
+ }
+ }
+
+ //
+ // Update LastKeycodeArray buffer in the UsbKeyboardDevice data structure.
+ //
+ for (Index = 0; Index < 8; Index++) {
+ UsbKeyboardDevice->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index];
+ }
+
+ //
+ // If there is new key pressed, update the RepeatKey value, and set the
+ // timer to repeate delay timer
+ //
+ if (NewRepeatKey != 0) {
+ //
+ // Sets trigger time to "Repeat Delay Time",
+ // to trigger the repeat timer when the key is hold long
+ // enough time.
+ //
+ gBS->SetTimer (
+ UsbKeyboardDevice->RepeatTimer,
+ TimerRelative,
+ USBKBD_REPEAT_DELAY
+ );
+ UsbKeyboardDevice->RepeatKey = NewRepeatKey;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves a USB keycode after parsing the raw data in keyboard buffer.
+
+ This function parses keyboard buffer. It updates state of modifier key for
+ USB_KB_DEV instancem, and returns keycode for output.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyCode Pointer to the USB keycode for output.
+
+ @retval EFI_SUCCESS Keycode successfully parsed.
+ @retval EFI_NOT_READY Keyboard buffer is not ready for a valid keycode
+
+**/
+EFI_STATUS
+USBParseKey (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice,
+ OUT UINT8 *KeyCode
+ )
+{
+ USB_KEY UsbKey;
+ EFI_KEY_DESCRIPTOR *KeyDescriptor;
+
+ *KeyCode = 0;
+
+ while (!IsQueueEmpty (&UsbKeyboardDevice->UsbKeyQueue)) {
+ //
+ // Pops one raw data off.
+ //
+ Dequeue (&UsbKeyboardDevice->UsbKeyQueue, &UsbKey, sizeof (UsbKey));
+
+ KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, UsbKey.KeyCode);
+ if (KeyDescriptor == NULL) {
+ continue;
+ }
+ if (!UsbKey.Down) {
+ //
+ // Key is released.
+ //
+ switch (KeyDescriptor->Modifier) {
+
+ //
+ // Ctrl release
+ //
+ case EFI_LEFT_CONTROL_MODIFIER:
+ UsbKeyboardDevice->LeftCtrlOn = FALSE;
+ UsbKeyboardDevice->CtrlOn = FALSE;
+ break;
+ case EFI_RIGHT_CONTROL_MODIFIER:
+ UsbKeyboardDevice->RightCtrlOn = FALSE;
+ UsbKeyboardDevice->CtrlOn = FALSE;
+ break;
+
+ //
+ // Shift release
+ //
+ case EFI_LEFT_SHIFT_MODIFIER:
+ UsbKeyboardDevice->LeftShiftOn = FALSE;
+ UsbKeyboardDevice->ShiftOn = FALSE;
+ break;
+ case EFI_RIGHT_SHIFT_MODIFIER:
+ UsbKeyboardDevice->RightShiftOn = FALSE;
+ UsbKeyboardDevice->ShiftOn = FALSE;
+ break;
+
+ //
+ // Alt release
+ //
+ case EFI_LEFT_ALT_MODIFIER:
+ UsbKeyboardDevice->LeftAltOn = FALSE;
+ UsbKeyboardDevice->AltOn = FALSE;
+ break;
+ case EFI_RIGHT_ALT_MODIFIER:
+ UsbKeyboardDevice->RightAltOn = FALSE;
+ UsbKeyboardDevice->AltOn = FALSE;
+ break;
+
+ //
+ // Left Logo release
+ //
+ case EFI_LEFT_LOGO_MODIFIER:
+ UsbKeyboardDevice->LeftLogoOn = FALSE;
+ break;
+
+ //
+ // Right Logo release
+ //
+ case EFI_RIGHT_LOGO_MODIFIER:
+ UsbKeyboardDevice->RightLogoOn = FALSE;
+ break;
+
+ //
+ // Menu key release
+ //
+ case EFI_MENU_MODIFIER:
+ UsbKeyboardDevice->MenuKeyOn = FALSE;
+ break;
+
+ //
+ // SysReq release
+ //
+ case EFI_PRINT_MODIFIER:
+ case EFI_SYS_REQUEST_MODIFIER:
+ UsbKeyboardDevice->SysReqOn = FALSE;
+ break;
+
+ //
+ // AltGr release
+ //
+ case EFI_ALT_GR_MODIFIER:
+ UsbKeyboardDevice->AltGrOn = FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ continue;
+ }
+
+ //
+ // Analyzes key pressing situation
+ //
+ switch (KeyDescriptor->Modifier) {
+
+ //
+ // Ctrl press
+ //
+ case EFI_LEFT_CONTROL_MODIFIER:
+ UsbKeyboardDevice->LeftCtrlOn = TRUE;
+ UsbKeyboardDevice->CtrlOn = TRUE;
+ break;
+ case EFI_RIGHT_CONTROL_MODIFIER:
+ UsbKeyboardDevice->RightCtrlOn = TRUE;
+ UsbKeyboardDevice->CtrlOn = TRUE;
+ break;
+
+ //
+ // Shift press
+ //
+ case EFI_LEFT_SHIFT_MODIFIER:
+ UsbKeyboardDevice->LeftShiftOn = TRUE;
+ UsbKeyboardDevice->ShiftOn = TRUE;
+ break;
+ case EFI_RIGHT_SHIFT_MODIFIER:
+ UsbKeyboardDevice->RightShiftOn = TRUE;
+ UsbKeyboardDevice->ShiftOn = TRUE;
+ break;
+
+ //
+ // Alt press
+ //
+ case EFI_LEFT_ALT_MODIFIER:
+ UsbKeyboardDevice->LeftAltOn = TRUE;
+ UsbKeyboardDevice->AltOn = TRUE;
+ break;
+ case EFI_RIGHT_ALT_MODIFIER:
+ UsbKeyboardDevice->RightAltOn = TRUE;
+ UsbKeyboardDevice->AltOn = TRUE;
+ break;
+
+ //
+ // Left Logo press
+ //
+ case EFI_LEFT_LOGO_MODIFIER:
+ UsbKeyboardDevice->LeftLogoOn = TRUE;
+ break;
+
+ //
+ // Right Logo press
+ //
+ case EFI_RIGHT_LOGO_MODIFIER:
+ UsbKeyboardDevice->RightLogoOn = TRUE;
+ break;
+
+ //
+ // Menu key press
+ //
+ case EFI_MENU_MODIFIER:
+ UsbKeyboardDevice->MenuKeyOn = TRUE;
+ break;
+
+ //
+ // SysReq press
+ //
+ case EFI_PRINT_MODIFIER:
+ case EFI_SYS_REQUEST_MODIFIER:
+ UsbKeyboardDevice->SysReqOn = TRUE;
+ break;
+
+ //
+ // AltGr press
+ //
+ case EFI_ALT_GR_MODIFIER:
+ UsbKeyboardDevice->AltGrOn = TRUE;
+ break;
+
+ case EFI_NUM_LOCK_MODIFIER:
+ //
+ // Toggle NumLock
+ //
+ UsbKeyboardDevice->NumLockOn = (BOOLEAN) (!(UsbKeyboardDevice->NumLockOn));
+ SetKeyLED (UsbKeyboardDevice);
+ break;
+
+ case EFI_CAPS_LOCK_MODIFIER:
+ //
+ // Toggle CapsLock
+ //
+ UsbKeyboardDevice->CapsOn = (BOOLEAN) (!(UsbKeyboardDevice->CapsOn));
+ SetKeyLED (UsbKeyboardDevice);
+ break;
+
+ case EFI_SCROLL_LOCK_MODIFIER:
+ //
+ // Toggle ScrollLock
+ //
+ UsbKeyboardDevice->ScrollOn = (BOOLEAN) (!(UsbKeyboardDevice->ScrollOn));
+ SetKeyLED (UsbKeyboardDevice);
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // When encountering Ctrl + Alt + Del, then warm reset.
+ //
+ if (KeyDescriptor->Modifier == EFI_DELETE_MODIFIER) {
+ if ((UsbKeyboardDevice->CtrlOn) && (UsbKeyboardDevice->AltOn)) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ }
+
+ *KeyCode = UsbKey.KeyCode;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Initialize the key state.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ OUT EFI_KEY_STATE *KeyState
+ )
+{
+ KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
+
+ if (UsbKeyboardDevice->LeftCtrlOn) {
+ KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
+ }
+ if (UsbKeyboardDevice->RightCtrlOn) {
+ KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if (UsbKeyboardDevice->LeftAltOn) {
+ KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
+ }
+ if (UsbKeyboardDevice->RightAltOn) {
+ KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
+ }
+ if (UsbKeyboardDevice->LeftShiftOn) {
+ KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+ if (UsbKeyboardDevice->RightShiftOn) {
+ KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+ if (UsbKeyboardDevice->LeftLogoOn) {
+ KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
+ }
+ if (UsbKeyboardDevice->RightLogoOn) {
+ KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
+ }
+ if (UsbKeyboardDevice->MenuKeyOn) {
+ KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
+ }
+ if (UsbKeyboardDevice->SysReqOn) {
+ KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
+ }
+
+ if (UsbKeyboardDevice->ScrollOn) {
+ KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
+ }
+ if (UsbKeyboardDevice->NumLockOn) {
+ KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
+ }
+ if (UsbKeyboardDevice->CapsOn) {
+ KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
+ }
+ if (UsbKeyboardDevice->IsSupportPartialKey) {
+ KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
+ }
+}
+
+/**
+ Converts USB Keycode ranging from 0x4 to 0x65 to EFI_INPUT_KEY.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyCode Indicates the key code that will be interpreted.
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information for the key that
+ was pressed.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER KeyCode is not in the range of 0x4 to 0x65.
+ @retval EFI_INVALID_PARAMETER Translated EFI_INPUT_KEY has zero for both ScanCode and UnicodeChar.
+ @retval EFI_NOT_READY KeyCode represents a dead key with EFI_NS_KEY_MODIFIER
+ @retval EFI_DEVICE_ERROR Keyboard layout is invalid.
+
+**/
+EFI_STATUS
+UsbKeyCodeToEfiInputKey (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ IN UINT8 KeyCode,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ EFI_KEY_DESCRIPTOR *KeyDescriptor;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ //
+ // KeyCode must in the range of [0x4, 0x65] or [0xe0, 0xe7].
+ //
+ KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, KeyCode);
+ if (KeyDescriptor == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (KeyDescriptor->Modifier == EFI_NS_KEY_MODIFIER) {
+ //
+ // If this is a dead key with EFI_NS_KEY_MODIFIER, then record it and return.
+ //
+ UsbKeyboardDevice->CurrentNsKey = FindUsbNsKey (UsbKeyboardDevice, KeyDescriptor);
+ return EFI_NOT_READY;
+ }
+
+ if (UsbKeyboardDevice->CurrentNsKey != NULL) {
+ //
+ // If this keystroke follows a non-spacing key, then find the descriptor for corresponding
+ // physical key.
+ //
+ KeyDescriptor = FindPhysicalKey (UsbKeyboardDevice->CurrentNsKey, KeyDescriptor);
+ UsbKeyboardDevice->CurrentNsKey = NULL;
+ }
+
+ //
+ // Make sure modifier of Key Descriptor is in the valid range according to UEFI spec.
+ //
+ if (KeyDescriptor->Modifier >= (sizeof (ModifierValueToEfiScanCodeConvertionTable) / sizeof (UINT8))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ KeyData->Key.ScanCode = ModifierValueToEfiScanCodeConvertionTable[KeyDescriptor->Modifier];
+ KeyData->Key.UnicodeChar = KeyDescriptor->Unicode;
+
+ if ((KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_STANDARD_SHIFT)!= 0) {
+ if (UsbKeyboardDevice->ShiftOn) {
+ KeyData->Key.UnicodeChar = KeyDescriptor->ShiftedUnicode;
+
+ //
+ // 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'
+ //
+ if ((KeyDescriptor->Unicode != CHAR_NULL) && (KeyDescriptor->ShiftedUnicode != CHAR_NULL) &&
+ (KeyDescriptor->Unicode != KeyDescriptor->ShiftedUnicode)) {
+ UsbKeyboardDevice->LeftShiftOn = FALSE;
+ UsbKeyboardDevice->RightShiftOn = FALSE;
+ }
+
+ if (UsbKeyboardDevice->AltGrOn) {
+ KeyData->Key.UnicodeChar = KeyDescriptor->ShiftedAltGrUnicode;
+ }
+ } else {
+ //
+ // Shift off
+ //
+ KeyData->Key.UnicodeChar = KeyDescriptor->Unicode;
+
+ if (UsbKeyboardDevice->AltGrOn) {
+ KeyData->Key.UnicodeChar = KeyDescriptor->AltGrUnicode;
+ }
+ }
+ }
+
+ if ((KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_CAPS_LOCK) != 0) {
+ if (UsbKeyboardDevice->CapsOn) {
+ if (KeyData->Key.UnicodeChar == KeyDescriptor->Unicode) {
+ KeyData->Key.UnicodeChar = KeyDescriptor->ShiftedUnicode;
+ } else if (KeyData->Key.UnicodeChar == KeyDescriptor->ShiftedUnicode) {
+ KeyData->Key.UnicodeChar = KeyDescriptor->Unicode;
+ }
+ }
+ }
+
+ if ((KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_NUM_LOCK) != 0) {
+ //
+ // For key affected by NumLock, if NumLock is on and Shift is not pressed, then it means
+ // normal key, instead of original control key. So the ScanCode should be cleaned.
+ // Otherwise, it means control key, so preserve the EFI Scan Code and clear the unicode keycode.
+ //
+ if ((UsbKeyboardDevice->NumLockOn) && (!(UsbKeyboardDevice->ShiftOn))) {
+ KeyData->Key.ScanCode = SCAN_NULL;
+ } else {
+ KeyData->Key.UnicodeChar = CHAR_NULL;
+ }
+ }
+
+ //
+ // Translate Unicode 0x1B (ESC) to EFI Scan Code
+ //
+ if (KeyData->Key.UnicodeChar == 0x1B && KeyData->Key.ScanCode == SCAN_NULL) {
+ KeyData->Key.ScanCode = SCAN_ESC;
+ KeyData->Key.UnicodeChar = CHAR_NULL;
+ }
+
+ //
+ // Not valid for key without both unicode key code and EFI Scan Code.
+ //
+ if (KeyData->Key.UnicodeChar == 0 && KeyData->Key.ScanCode == SCAN_NULL) {
+ if (!UsbKeyboardDevice->IsSupportPartialKey) {
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Save Shift/Toggle state
+ //
+ InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState);
+
+ //
+ // Signal KeyNotify process event if this key pressed matches any key registered.
+ //
+ NotifyList = &UsbKeyboardDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ //
+ // The key notification function needs to run at TPL_CALLBACK
+ // while current TPL is TPL_NOTIFY. It will be invoked in
+ // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+ //
+ Enqueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, KeyData, sizeof (*KeyData));
+ gBS->SignalEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create the queue.
+
+ @param Queue Points to the queue.
+ @param ItemSize Size of the single item.
+
+**/
+VOID
+InitQueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ IN UINTN ItemSize
+ )
+{
+ UINTN Index;
+
+ Queue->ItemSize = ItemSize;
+ Queue->Head = 0;
+ Queue->Tail = 0;
+
+ if (Queue->Buffer[0] != NULL) {
+ FreePool (Queue->Buffer[0]);
+ }
+
+ Queue->Buffer[0] = AllocatePool (sizeof (Queue->Buffer) / sizeof (Queue->Buffer[0]) * ItemSize);
+ ASSERT (Queue->Buffer[0] != NULL);
+
+ for (Index = 1; Index < sizeof (Queue->Buffer) / sizeof (Queue->Buffer[0]); Index++) {
+ Queue->Buffer[Index] = ((UINT8 *) Queue->Buffer[Index - 1]) + ItemSize;
+ }
+}
+
+/**
+ Destroy the queue
+
+ @param Queue Points to the queue.
+**/
+VOID
+DestroyQueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue
+ )
+{
+ FreePool (Queue->Buffer[0]);
+}
+
+
+/**
+ Check whether the queue is empty.
+
+ @param Queue Points to the queue.
+
+ @retval TRUE Queue is empty.
+ @retval FALSE Queue is not empty.
+
+**/
+BOOLEAN
+IsQueueEmpty (
+ IN USB_SIMPLE_QUEUE *Queue
+ )
+{
+ //
+ // Meet FIFO empty condition
+ //
+ return (BOOLEAN) (Queue->Head == Queue->Tail);
+}
+
+
+/**
+ Check whether the queue is full.
+
+ @param Queue Points to the queue.
+
+ @retval TRUE Queue is full.
+ @retval FALSE Queue is not full.
+
+**/
+BOOLEAN
+IsQueueFull (
+ IN USB_SIMPLE_QUEUE *Queue
+ )
+{
+ return (BOOLEAN) (((Queue->Tail + 1) % (MAX_KEY_ALLOWED + 1)) == Queue->Head);
+}
+
+
+/**
+ Enqueue the item to the queue.
+
+ @param Queue Points to the queue.
+ @param Item Points to the item to be enqueued.
+ @param ItemSize Size of the item.
+**/
+VOID
+Enqueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ IN VOID *Item,
+ IN UINTN ItemSize
+ )
+{
+ ASSERT (ItemSize == Queue->ItemSize);
+ //
+ // If keyboard buffer is full, throw the
+ // first key out of the keyboard buffer.
+ //
+ if (IsQueueFull (Queue)) {
+ Queue->Head = (Queue->Head + 1) % (MAX_KEY_ALLOWED + 1);
+ }
+
+ CopyMem (Queue->Buffer[Queue->Tail], Item, ItemSize);
+
+ //
+ // Adjust the tail pointer of the FIFO keyboard buffer.
+ //
+ Queue->Tail = (Queue->Tail + 1) % (MAX_KEY_ALLOWED + 1);
+}
+
+
+/**
+ Dequeue a item from the queue.
+
+ @param Queue Points to the queue.
+ @param Item Receives the item.
+ @param ItemSize Size of the item.
+
+ @retval EFI_SUCCESS Item was successfully dequeued.
+ @retval EFI_DEVICE_ERROR The queue is empty.
+
+**/
+EFI_STATUS
+Dequeue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ OUT VOID *Item,
+ IN UINTN ItemSize
+ )
+{
+ ASSERT (Queue->ItemSize == ItemSize);
+
+ if (IsQueueEmpty (Queue)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (Item, Queue->Buffer[Queue->Head], ItemSize);
+
+ //
+ // Adjust the head pointer of the FIFO keyboard buffer.
+ //
+ Queue->Head = (Queue->Head + 1) % (MAX_KEY_ALLOWED + 1);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets USB keyboard LED state.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+**/
+VOID
+SetKeyLED (
+ IN USB_KB_DEV *UsbKeyboardDevice
+ )
+{
+ LED_MAP Led;
+ UINT8 ReportId;
+
+ //
+ // Set each field in Led map.
+ //
+ Led.NumLock = (UINT8) ((UsbKeyboardDevice->NumLockOn) ? 1 : 0);
+ Led.CapsLock = (UINT8) ((UsbKeyboardDevice->CapsOn) ? 1 : 0);
+ Led.ScrollLock = (UINT8) ((UsbKeyboardDevice->ScrollOn) ? 1 : 0);
+ Led.Resrvd = 0;
+
+ ReportId = 0;
+ //
+ // Call Set_Report Request to lighten the LED.
+ //
+ UsbSetReportRequest (
+ UsbKeyboardDevice->UsbIo,
+ UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
+ ReportId,
+ HID_OUTPUT_REPORT,
+ 1,
+ (UINT8 *) &Led
+ );
+}
+
+
+/**
+ Handler for Repeat Key event.
+
+ This function is the handler for Repeat Key event triggered
+ by timer.
+ After a repeatable key is pressed, the event would be triggered
+ with interval of USBKBD_REPEAT_DELAY. Once the event is triggered,
+ following trigger will come with interval of USBKBD_REPEAT_RATE.
+
+ @param Event The Repeat Key event.
+ @param Context Points to the USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardRepeatHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_KB_DEV *UsbKeyboardDevice;
+ USB_KEY UsbKey;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+
+ //
+ // Do nothing when there is no repeat key.
+ //
+ if (UsbKeyboardDevice->RepeatKey != 0) {
+ //
+ // Inserts the repeat key into keyboard buffer,
+ //
+ UsbKey.KeyCode = UsbKeyboardDevice->RepeatKey;
+ UsbKey.Down = TRUE;
+ Enqueue (&UsbKeyboardDevice->UsbKeyQueue, &UsbKey, sizeof (UsbKey));
+
+ //
+ // Set repeat rate for next repeat key generation.
+ //
+ gBS->SetTimer (
+ UsbKeyboardDevice->RepeatTimer,
+ TimerRelative,
+ USBKBD_REPEAT_RATE
+ );
+ }
+}
+
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+
+ USB_KB_DEV *UsbKeyboardDevice;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 PacketSize;
+
+ UsbKeyboardDevice = (USB_KB_DEV *) Context;
+
+ UsbIo = UsbKeyboardDevice->UsbIo;
+
+ PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
+
+ //
+ // Re-submit Asynchronous Interrupt Transfer for recovery.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
+ TRUE,
+ UsbKeyboardDevice->IntEndpointDescriptor.Interval,
+ PacketSize,
+ KeyboardHandler,
+ UsbKeyboardDevice
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.h
new file mode 100644
index 000000000..811f136b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.h
@@ -0,0 +1,326 @@
+/** @file
+ Function prototype for USB Keyboard Driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_KEYBOARD_H_
+#define _EFI_KEYBOARD_H_
+
+
+#include "EfiKey.h"
+
+#define USB_KEYBOARD_KEY_COUNT 105
+
+#define USB_KEYBOARD_LANGUAGE_STR_LEN 5 // RFC4646 Language Code: "en-US"
+#define USB_KEYBOARD_DESCRIPTION_STR_LEN (16 + 1) // Description: "English Keyboard"
+
+#pragma pack (1)
+typedef struct {
+ //
+ // This 4-bytes total array length is required by PreparePackageList()
+ //
+ UINT32 Length;
+
+ //
+ // Keyboard Layout package definition
+ //
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT16 LayoutCount;
+
+ //
+ // EFI_HII_KEYBOARD_LAYOUT
+ //
+ UINT16 LayoutLength;
+ EFI_GUID Guid;
+ UINT32 LayoutDescriptorStringOffset;
+ UINT8 DescriptorCount;
+ EFI_KEY_DESCRIPTOR KeyDescriptor[USB_KEYBOARD_KEY_COUNT];
+ UINT16 DescriptionCount;
+ CHAR16 Language[USB_KEYBOARD_LANGUAGE_STR_LEN];
+ CHAR16 Space;
+ CHAR16 DescriptionString[USB_KEYBOARD_DESCRIPTION_STR_LEN];
+} USB_KEYBOARD_LAYOUT_PACK_BIN;
+#pragma pack()
+/**
+ Uses USB I/O to check whether the device is a USB keyboard device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB keyboard device.
+ @retval FALSE Device is a not USB keyboard device.
+
+**/
+BOOLEAN
+IsUSBKeyboard (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ );
+
+/**
+ Initialize USB keyboard device and all private data structures.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+ @retval EFI_SUCCESS Initialization is successful.
+ @retval EFI_DEVICE_ERROR Keyboard initialization failed.
+
+**/
+EFI_STATUS
+InitUSBKeyboard (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice
+ );
+
+/**
+ Initialize USB keyboard layout.
+
+ This function initializes Key Convertion Table for the USB keyboard device.
+ It first tries to retrieve layout from HII database. If failed and default
+ layout is enabled, then it just uses the default layout.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+ @retval EFI_SUCCESS Initialization succeeded.
+ @retval EFI_NOT_READY Keyboard layout cannot be retrieve from HII
+ database, and default layout is disabled.
+ @retval Other Fail to register event to EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group.
+
+**/
+EFI_STATUS
+InitKeyboardLayout (
+ OUT USB_KB_DEV *UsbKeyboardDevice
+ );
+
+/**
+ Destroy resources for keyboard layout.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+**/
+VOID
+ReleaseKeyboardLayoutResources (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice
+ );
+
+/**
+ Handler function for USB keyboard's asynchronous interrupt transfer.
+
+ This function is the handler function for USB keyboard's asynchronous interrupt transfer
+ to manage the keyboard. It parses the USB keyboard input report, and inserts data to
+ keyboard buffer according to state of modifier keys and normal keys. Timer for repeat key
+ is also set accordingly.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardHandler (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ );
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Retrieves a USB keycode after parsing the raw data in keyboard buffer.
+
+ This function parses keyboard buffer. It updates state of modifier key for
+ USB_KB_DEV instancem, and returns keycode for output.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyCode Pointer to the USB keycode for output.
+
+ @retval EFI_SUCCESS Keycode successfully parsed.
+ @retval EFI_NOT_READY Keyboard buffer is not ready for a valid keycode
+
+**/
+EFI_STATUS
+USBParseKey (
+ IN OUT USB_KB_DEV *UsbKeyboardDevice,
+ OUT UINT8 *KeyCode
+ );
+
+/**
+ Converts USB Keycode ranging from 0x4 to 0x65 to EFI_INPUT_KEY.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyCode Indicates the key code that will be interpreted.
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information for the key that
+ was pressed.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER KeyCode is not in the range of 0x4 to 0x65.
+ @retval EFI_INVALID_PARAMETER Translated EFI_INPUT_KEY has zero for both ScanCode and UnicodeChar.
+ @retval EFI_NOT_READY KeyCode represents a dead key with EFI_NS_KEY_MODIFIER
+ @retval EFI_DEVICE_ERROR Keyboard layout is invalid.
+
+**/
+EFI_STATUS
+UsbKeyCodeToEfiInputKey (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ IN UINT8 KeyCode,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+
+/**
+ Create the queue.
+
+ @param Queue Points to the queue.
+ @param ItemSize Size of the single item.
+
+**/
+VOID
+InitQueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ IN UINTN ItemSize
+ );
+
+/**
+ Destroy the queue
+
+ @param Queue Points to the queue.
+**/
+VOID
+DestroyQueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue
+ );
+
+
+/**
+ Check whether the queue is empty.
+
+ @param Queue Points to the queue.
+
+ @retval TRUE Queue is empty.
+ @retval FALSE Queue is not empty.
+
+**/
+BOOLEAN
+IsQueueEmpty (
+ IN USB_SIMPLE_QUEUE *Queue
+ );
+
+
+/**
+ Check whether the queue is full.
+
+ @param Queue Points to the queue.
+
+ @retval TRUE Queue is full.
+ @retval FALSE Queue is not full.
+
+**/
+BOOLEAN
+IsQueueFull (
+ IN USB_SIMPLE_QUEUE *Queue
+ );
+
+
+/**
+ Enqueue the item to the queue.
+
+ @param Queue Points to the queue.
+ @param Item Points to the item to be enqueued.
+ @param ItemSize Size of the item.
+**/
+VOID
+Enqueue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ IN VOID *Item,
+ IN UINTN ItemSize
+ );
+
+
+/**
+ Dequeue a item from the queue.
+
+ @param Queue Points to the queue.
+ @param Item Receives the item.
+ @param ItemSize Size of the item.
+
+ @retval EFI_SUCCESS Item was successfully dequeued.
+ @retval EFI_DEVICE_ERROR The queue is empty.
+
+**/
+EFI_STATUS
+Dequeue (
+ IN OUT USB_SIMPLE_QUEUE *Queue,
+ OUT VOID *Item,
+ IN UINTN ItemSize
+ );
+
+/**
+ Handler for Repeat Key event.
+
+ This function is the handler for Repeat Key event triggered
+ by timer.
+ After a repeatable key is pressed, the event would be triggered
+ with interval of USBKBD_REPEAT_DELAY. Once the event is triggered,
+ following trigger will come with interval of USBKBD_REPEAT_RATE.
+
+ @param Event The Repeat Key event.
+ @param Context Points to the USB_KB_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBKeyboardRepeatHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Sets USB keyboard LED state.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+
+**/
+VOID
+SetKeyLED (
+ IN USB_KB_DEV *UsbKeyboardDevice
+ );
+
+/**
+ Initialize the key state.
+
+ @param UsbKeyboardDevice The USB_KB_DEV instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN USB_KB_DEV *UsbKeyboardDevice,
+ OUT EFI_KEY_STATE *KeyState
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
new file mode 100644
index 000000000..e981a0afc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
@@ -0,0 +1,93 @@
+## @file
+# USB Keyboard Driver that manages USB keyboard and produces Simple Text Input(Ex) Protocol.
+#
+# USB Keyboard Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+# Simple Text Input Protocol and Simple Text Input Ex Protocol on USB keyboard devices.
+# It initializes the keyboard layout according to info retrieved from HII database.
+# If HII cannot provide the info, this module uses its carried default one if PCD allows.
+# It manages the USB keyboard device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+# and parses the data according to USB HID documents.
+# This module refers to following specifications:
+# 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+# 2. Universal Serial Bus HID Usage Tables, ver 1.12
+# 3. UEFI Specification, v2.1
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbKbDxe
+ MODULE_UNI_FILE = UsbKbDxe.uni
+ FILE_GUID = 2D2E62CF-9ECF-43b7-8219-94E7FC713DFE
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = USBKeyboardDriverBindingEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+# DRIVER_BINDING = gUsbKeyboardDriverBinding
+# COMPONENT_NAME = gUsbKeyboardComponentName
+# COMPONENT_NAME2 = gUsbKeyboardComponentName2
+#
+
+[Sources]
+ EfiKey.c
+ EfiKey.h
+ KeyBoard.c
+ ComponentName.c
+ KeyBoard.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ ReportStatusCodeLib
+ DebugLib
+ PcdLib
+ UefiUsbLib
+ HiiLib
+
+[Guids]
+ #
+ # Event registered to EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group,
+ # which will be triggered by EFI_HII_DATABASE_PROTOCOL.SetKeyboardLayout().
+ #
+ gEfiHiiKeyBoardLayoutGuid ## SOMETIMES_CONSUMES ## Event
+ gUsbKeyboardLayoutPackageGuid ## SOMETIMES_CONSUMES ## HII
+ gUsbKeyboardLayoutKeyGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ #
+ # If HII Database Protocol exists, then keyboard layout from HII database is used.
+ # Otherwise, USB keyboard module tries to use its carried default layout.
+ #
+ gEfiHiiDatabaseProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDisableDefaultKeyboardLayoutInUsbKbDriver ## CONSUMES
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbKbDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.uni
new file mode 100644
index 000000000..a5bd5e1ae
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.uni
@@ -0,0 +1,29 @@
+// /** @file
+// USB Keyboard Driver that manages USB keyboard and produces Simple Text Input(Ex) Protocol.
+//
+// USB Keyboard Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+// Simple Text Input Protocol and Simple Text Input Ex Protocol on USB keyboard devices.
+// It initializes the keyboard layout according to info retrieved from HII database.
+// If HII cannot provide the info, this module uses its carried default one if PCD allows.
+// It manages the USB keyboard device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+// and parses the data according to USB HID documents.
+// This module refers to following specifications:
+// 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+// 2. Universal Serial Bus HID Usage Tables, ver 1.12
+// 3. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB keyboard and produces Simple Text Input(Ex) Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "USB Keyboard Driver consumes USB I/O Protocol and Device Path Protocol, and produces Simple Text Input Protocol and Simple Text Input Ex Protocol on USB keyboard devices. It initializes the keyboard layout according to information retrieved from the HII database. If HII cannot provide the information, this module uses its carried default one if PCD allows. It manages the USB keyboard device via Asynchronous Interrupt Transfer of USB I/O Protocol, and parses the data according to USB HID documents.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. Universal Serial Bus HID Firmware Specification, ver 1.11<BR>\n"
+ "2. Universal Serial Bus HID Usage Tables, ver 1.12<BR>\n"
+ "3. UEFI Specification, v2.1<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxeExtra.uni
new file mode 100644
index 000000000..4cd2b7212
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbKbDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Keyboard DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c
new file mode 100644
index 000000000..dff3d3a7b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c
@@ -0,0 +1,156 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for USB Mass Storage Driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = {
+ UsbMassStorageGetDriverName,
+ UsbMassStorageGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbMassStorageGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbMassStorageGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
+mUsbMassStorageDriverNameTable[] = {
+ {"eng;en", L"Usb Mass Storage 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
+UsbMassStorageGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbMassStorageDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbMassStorageComponentName)
+ );
+}
+
+/**
+ 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
+UsbMassStorageGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h
new file mode 100644
index 000000000..fccb203a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h
@@ -0,0 +1,187 @@
+/** @file
+ Definition of USB Mass Storage Class and its value, USB Mass Transport Protocol,
+ and other common definitions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_H_
+#define _EFI_USBMASS_H_
+
+
+#include <Uefi.h>
+#include <IndustryStandard/Scsi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DiskInfo.h>
+#include <Library/BaseLib.h>
+#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 <Library/DevicePathLib.h>
+
+typedef struct _USB_MASS_TRANSPORT USB_MASS_TRANSPORT;
+typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE;
+
+#include "UsbMassBot.h"
+#include "UsbMassCbi.h"
+#include "UsbMassBoot.h"
+#include "UsbMassDiskInfo.h"
+#include "UsbMassImpl.h"
+
+#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == BIT7)
+#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == 0)
+#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)
+#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT)
+#define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0)
+
+#define USB_MASS_1_MILLISECOND 1000
+#define USB_MASS_1_SECOND (1000 * USB_MASS_1_MILLISECOND)
+
+#define USB_MASS_CMD_SUCCESS 0
+#define USB_MASS_CMD_FAIL 1
+#define USB_MASS_CMD_PERSISTENT 2
+
+/**
+ Initializes USB transport protocol.
+
+ This function initializes the USB mass storage class transport protocol.
+ It will save its context in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB transport initialization fails.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_INIT_TRANSPORT) (
+ IN EFI_USB_IO_PROTOCOL *Usb,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Execute USB mass storage command through the transport protocol.
+
+ @param Context The USB Transport Protocol.
+ @param Cmd The command to transfer to device
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of the buffer
+ @param Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_EXEC_COMMAND) (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by Transport protocol.
+
+ @param Context The USB Transport Protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_RESET) (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the transport protocol.
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_GET_MAX_LUN) (
+ IN VOID *Context,
+ IN UINT8 *MaxLun
+ );
+
+/**
+ Clean up the transport protocol's resource.
+
+ @param Context The instance of transport protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_CLEAN_UP) (
+ IN VOID *Context
+ );
+
+///
+/// This structure contains information necessary to select the
+/// proper transport protocol. The mass storage class defines
+/// two transport protocols. One is the CBI, and the other is BOT.
+/// CBI is being obseleted. The design is made modular by this
+/// structure so that the CBI protocol can be easily removed when
+/// it is no longer necessary.
+///
+struct _USB_MASS_TRANSPORT {
+ UINT8 Protocol;
+ USB_MASS_INIT_TRANSPORT Init; ///< Initialize the mass storage transport protocol
+ USB_MASS_EXEC_COMMAND ExecCommand; ///< Transport command to the device then get result
+ USB_MASS_RESET Reset; ///< Reset the device
+ USB_MASS_GET_MAX_LUN GetMaxLun; ///< Get max lun, only for bot
+ USB_MASS_CLEAN_UP CleanUp; ///< Clean up the resources.
+};
+
+struct _USB_MASS_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO_MEDIA BlockIoMedia;
+ BOOLEAN OpticalStorage;
+ UINT8 Lun; ///< Logical Unit Number
+ UINT8 Pdt; ///< Peripheral Device Type
+ USB_MASS_TRANSPORT *Transport; ///< USB mass storage transport protocol
+ VOID *Context;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ USB_BOOT_INQUIRY_DATA InquiryData;
+ BOOLEAN Cdb16Byte;
+};
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
new file mode 100644
index 000000000..aab4061e1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
@@ -0,0 +1,998 @@
+/** @file
+ Implementation of the command set of USB Mass Storage Specification
+ for Bootability, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+/**
+ Execute REQUEST SENSE Command to retrieve sense data from device.
+
+ @param UsbMass The device whose sense data is requested.
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval EFI_DEVICE_ERROR Failed to request sense.
+ @retval EFI_NO_RESPONSE The device media doesn't response this request.
+ @retval EFI_INVALID_PARAMETER The command has some invalid parameters.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_MEDIA_CHANGED The device media has been changed.
+
+**/
+EFI_STATUS
+UsbBootRequestSense (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_REQUEST_SENSE_CMD SenseCmd;
+ USB_BOOT_REQUEST_SENSE_DATA SenseData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+
+ Transport = UsbMass->Transport;
+
+ //
+ // Request the sense data from the device
+ //
+ ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
+ ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
+
+ SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;
+ SenseCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA);
+
+ Status = Transport->ExecCommand (
+ UsbMass->Context,
+ &SenseCmd,
+ sizeof (USB_BOOT_REQUEST_SENSE_CMD),
+ EfiUsbDataIn,
+ &SenseData,
+ sizeof (USB_BOOT_REQUEST_SENSE_DATA),
+ UsbMass->Lun,
+ USB_BOOT_GENERAL_CMD_TIMEOUT,
+ &CmdResult
+ );
+ if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+ }
+
+ //
+ // If sense data is retrieved successfully, interpret the sense data
+ // and update the media status if necessary.
+ //
+ Media = &UsbMass->BlockIoMedia;
+
+ switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
+
+ case USB_BOOT_SENSE_NO_SENSE:
+ if (SenseData.Asc == USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION) {
+ //
+ // It is not an error if a device does not have additional sense information
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NO_RESPONSE;
+ }
+ break;
+
+ case USB_BOOT_SENSE_RECOVERED:
+ //
+ // Suppose hardware can handle this case, and recover later by itself
+ //
+ Status = EFI_NOT_READY;
+ break;
+
+ case USB_BOOT_SENSE_NOT_READY:
+ Status = EFI_DEVICE_ERROR;
+ if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
+ Media->MediaPresent = FALSE;
+ Status = EFI_NO_MEDIA;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
+ Status = EFI_NOT_READY;
+ }
+ break;
+
+ case USB_BOOT_SENSE_ILLEGAL_REQUEST:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case USB_BOOT_SENSE_UNIT_ATTENTION:
+ Status = EFI_DEVICE_ERROR;
+ if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) {
+ //
+ // If MediaChange, reset ReadOnly and new MediaId
+ //
+ Status = EFI_MEDIA_CHANGED;
+ Media->ReadOnly = FALSE;
+ Media->MediaId++;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
+ Status = EFI_NOT_READY;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
+ Status = EFI_NOT_READY;
+ }
+ break;
+
+ case USB_BOOT_SENSE_DATA_PROTECT:
+ Status = EFI_WRITE_PROTECTED;
+ Media->ReadOnly = TRUE;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with error code (%x) sense key %x/%x/%x\n",
+ Status,
+ SenseData.ErrorCode,
+ USB_BOOT_SENSE_KEY (SenseData.SenseKey),
+ SenseData.Asc,
+ SenseData.Ascq
+ ));
+
+ return Status;
+}
+
+
+/**
+ Execute the USB mass storage bootability commands.
+
+ This function executes the USB mass storage bootability commands.
+ If execution failed, retrieve the error by REQUEST_SENSE, then
+ update the device's status, such as ReadyOnly.
+
+ @param UsbMass The device to issue commands to
+ @param Cmd The command to execute
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of expected data
+ @param Timeout The timeout used to transfer
+
+ @retval EFI_SUCCESS Command is executed successfully
+ @retval Others Command execution failed.
+
+**/
+EFI_STATUS
+UsbBootExecCmd (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout
+ )
+{
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+
+ Transport = UsbMass->Transport;
+ Status = Transport->ExecCommand (
+ UsbMass->Context,
+ Cmd,
+ CmdLen,
+ DataDir,
+ Data,
+ DataLen,
+ UsbMass->Lun,
+ Timeout,
+ &CmdResult
+ );
+
+ if (Status == EFI_TIMEOUT) {
+ DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd\n", Status, *(UINT8 *)Cmd));
+ return EFI_TIMEOUT;
+ }
+
+ //
+ // If ExecCommand() returns no error and CmdResult is success,
+ // then the command transfer is successful.
+ //
+ if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If command execution failed, then retrieve error info via sense request.
+ //
+ DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd (Result = %x)\n", Status, *(UINT8 *)Cmd, CmdResult));
+ return UsbBootRequestSense (UsbMass);
+}
+
+
+/**
+ Execute the USB mass storage bootability commands with retrial.
+
+ This function executes USB mass storage bootability commands.
+ If the device isn't ready, wait for it. If the device is ready
+ and error occurs, retry the command again until it exceeds the
+ limit of retrial times.
+
+ @param UsbMass The device to issue commands to
+ @param Cmd The command to execute
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of expected data
+ @param Timeout The timeout used to transfer
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval EFI_NO_MEDIA The device media is removed.
+ @retval Others Command execution failed after retrial.
+
+**/
+EFI_STATUS
+UsbBootExecCmdWithRetry (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINTN Retry;
+ EFI_EVENT TimeoutEvt;
+
+ Retry = 0;
+ Status = EFI_SUCCESS;
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvt
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60));
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Execute the cmd and retry if it fails.
+ //
+ while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
+ Status = UsbBootExecCmd (
+ UsbMass,
+ Cmd,
+ CmdLen,
+ DataDir,
+ Data,
+ DataLen,
+ Timeout
+ );
+ if (Status == EFI_SUCCESS || Status == EFI_NO_MEDIA) {
+ break;
+ }
+ //
+ // If the sense data shows the drive is not ready, we need execute the cmd again.
+ // We limit the upper boundary to 60 seconds.
+ //
+ if (Status == EFI_NOT_READY) {
+ continue;
+ }
+ //
+ // If the status is other error, then just retry 5 times.
+ //
+ if (Retry++ >= USB_BOOT_COMMAND_RETRY) {
+ break;
+ }
+ }
+
+EXIT:
+ if (TimeoutEvt != NULL) {
+ gBS->CloseEvent (TimeoutEvt);
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute TEST UNIT READY command to check if the device is ready.
+
+ @param UsbMass The device to test
+
+ @retval EFI_SUCCESS The device is ready.
+ @retval Others Device not ready.
+
+**/
+EFI_STATUS
+UsbBootIsUnitReady (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_TEST_UNIT_READY_CMD TestCmd;
+
+ ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
+
+ TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;
+ TestCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+
+ return UsbBootExecCmdWithRetry (
+ UsbMass,
+ &TestCmd,
+ (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
+ EfiUsbNoData,
+ NULL,
+ 0,
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+}
+
+
+/**
+ Execute INQUIRY Command to request information regarding parameters of
+ the device be sent to the host computer.
+
+ @param UsbMass The device to inquire.
+
+ @retval EFI_SUCCESS INQUIRY Command is executed successfully.
+ @retval Others INQUIRY Command is not executed successfully.
+
+**/
+EFI_STATUS
+UsbBootInquiry (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_INQUIRY_CMD InquiryCmd;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &(UsbMass->BlockIoMedia);
+
+ ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
+ ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
+
+ InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
+ InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &InquiryCmd,
+ (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),
+ EfiUsbDataIn,
+ &UsbMass->InquiryData,
+ sizeof (USB_BOOT_INQUIRY_DATA),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
+ // from the inquiry data.
+ //
+ UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));
+ Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));
+ //
+ // Set block size to the default value of 512 Bytes, in case no media is present at first time.
+ //
+ Media->BlockSize = 0x0200;
+
+ return Status;
+}
+
+/**
+ Execute READ CAPACITY 16 bytes command to request information regarding
+ the capacity of the installed medium of the device.
+
+ This function executes READ CAPACITY 16 bytes command to get the capacity
+ of the USB mass storage media, including the presence, block size,
+ and last block number.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk geometry is successfully retrieved.
+ @retval EFI_NOT_READY The returned block size is zero.
+ @retval Other READ CAPACITY 16 bytes command execution failed.
+
+**/
+EFI_STATUS
+UsbBootReadCapacity16 (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ UINT8 CapacityCmd[16];
+ EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ Media->MediaPresent = FALSE;
+ Media->LastBlock = 0;
+ Media->BlockSize = 0;
+
+ ZeroMem (CapacityCmd, sizeof (CapacityCmd));
+ ZeroMem (&CapacityData, sizeof (CapacityData));
+
+ CapacityCmd[0] = EFI_SCSI_OP_READ_CAPACITY16;
+ CapacityCmd[1] = 0x10;
+ //
+ // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO.
+ //
+ ZeroMem ((CapacityCmd + 2), 8);
+
+ CapacityCmd[13] = sizeof (CapacityData);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ CapacityCmd,
+ (UINT8) sizeof (CapacityCmd),
+ EfiUsbDataIn,
+ &CapacityData,
+ sizeof (CapacityData),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the information on media presence, block size, and last block number
+ // from READ CAPACITY data.
+ //
+ Media->MediaPresent = TRUE;
+ Media->LastBlock = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));
+
+ BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));
+
+ Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |
+ CapacityData.LowestAlignLogic1;
+ Media->LogicalBlocksPerPhysicalBlock = (1 << CapacityData.LogicPerPhysical);
+ if (BlockSize == 0) {
+ //
+ // Get sense data
+ //
+ return UsbBootRequestSense (UsbMass);
+ } else {
+ Media->BlockSize = BlockSize;
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute READ CAPACITY command to request information regarding
+ the capacity of the installed medium of the device.
+
+ This function executes READ CAPACITY command to get the capacity
+ of the USB mass storage media, including the presence, block size,
+ and last block number.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk geometry is successfully retrieved.
+ @retval EFI_NOT_READY The returned block size is zero.
+ @retval Other READ CAPACITY command execution failed.
+
+**/
+EFI_STATUS
+UsbBootReadCapacity (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_READ_CAPACITY_CMD CapacityCmd;
+ USB_BOOT_READ_CAPACITY_DATA CapacityData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
+ ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
+
+ CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
+ CapacityCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &CapacityCmd,
+ (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD),
+ EfiUsbDataIn,
+ &CapacityData,
+ sizeof (USB_BOOT_READ_CAPACITY_DATA),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the information on media presence, block size, and last block number
+ // from READ CAPACITY data.
+ //
+ Media->MediaPresent = TRUE;
+ Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
+
+ BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
+ if (BlockSize == 0) {
+ //
+ // Get sense data
+ //
+ return UsbBootRequestSense (UsbMass);
+ } else {
+ Media->BlockSize = BlockSize;
+ }
+
+ if (Media->LastBlock == 0xFFFFFFFF) {
+ Status = UsbBootReadCapacity16 (UsbMass);
+ if (!EFI_ERROR (Status)) {
+ UsbMass->Cdb16Byte = TRUE;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves SCSI mode sense information via MODE SENSE(6) command.
+
+ @param UsbMass The device whose sense data is requested.
+
+ @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.
+ @retval Other Command execution failed.
+
+**/
+EFI_STATUS
+UsbScsiModeSense (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_STATUS Status;
+ USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;
+ USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
+ EFI_BLOCK_IO_MEDIA *Media;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
+ ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
+
+ //
+ // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
+ //
+ ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;
+ ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
+ ModeSenseCmd.PageCode = 0x3F;
+ ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &ModeSenseCmd,
+ (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),
+ EfiUsbDataIn,
+ &ModeParaHeader,
+ sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+
+ //
+ // Format of device-specific parameter byte of the mode parameter header is defined in
+ // Section 8.2.10 of SCSI-2 Spec.
+ // BIT7 of this byte is indicates whether the medium is write protected.
+ //
+ if (!EFI_ERROR (Status)) {
+ Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the parameters for the USB mass storage media.
+
+ This function get the parameters for the USB mass storage media,
+ It is used both to initialize the media during the Start() phase
+ of Driver Binding Protocol and to re-initialize it when the media is
+ changed. Although the RemoveableMedia is unlikely to change,
+ it is also included here.
+
+ @param UsbMass The device to retrieve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval Other Failed to get the parameters.
+
+**/
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &(UsbMass->BlockIoMedia);
+
+ Status = UsbBootInquiry (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // According to USB Mass Storage Specification for Bootability, only following
+ // 4 Peripheral Device Types are in spec.
+ //
+ if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
+ (UsbMass->Pdt != USB_PDT_CDROM) &&
+ (UsbMass->Pdt != USB_PDT_OPTICAL) &&
+ (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Don't use the Removable bit in inquiry data to test whether the media
+ // is removable because many flash disks wrongly set this bit.
+ //
+ if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
+ //
+ // CD-Rom device and Non-CD optical device
+ //
+ UsbMass->OpticalStorage = TRUE;
+ //
+ // Default value 2048 Bytes, in case no media present at first time
+ //
+ Media->BlockSize = 0x0800;
+ }
+
+ Status = UsbBootDetectMedia (UsbMass);
+
+ return Status;
+}
+
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param UsbMass The device to check.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA OldMedia;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINT8 CmdSet;
+ EFI_STATUS Status;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
+
+ CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
+
+ Status = UsbBootIsUnitReady (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));
+ }
+
+ //
+ // Status could be:
+ // EFI_SUCCESS: all good.
+ // EFI_NO_MEDIA: media is not present.
+ // others: HW error.
+ // For either EFI_NO_MEDIA, or HW error, skip to get WriteProtected and capacity information.
+ //
+ if (!EFI_ERROR (Status)) {
+ if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
+ //
+ // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
+ // according to Section 4 of USB Mass Storage Specification for Bootability.
+ // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
+ // could get the information of Write Protected.
+ // Since not all device support this command, skip if fail.
+ //
+ UsbScsiModeSense (UsbMass);
+ }
+
+ Status = UsbBootReadCapacity (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
+ }
+ }
+
+ if (EFI_ERROR (Status) && Status != EFI_NO_MEDIA) {
+ //
+ // For NoMedia, BlockIo is still needed.
+ //
+ return Status;
+ }
+
+ //
+ // Simply reject device whose block size is unacceptable small (==0) or large (>64K).
+ //
+ if ((Media->BlockSize == 0) || (Media->BlockSize > USB_BOOT_MAX_CARRY_SIZE)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Detect whether it is necessary to reinstall the Block I/O Protocol.
+ //
+ // MediaId may change in RequestSense for MediaChanged
+ // MediaPresent may change in RequestSense for NoMedia
+ // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
+ // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
+ //
+ if ((Media->MediaId != OldMedia.MediaId) ||
+ (Media->MediaPresent != OldMedia.MediaPresent) ||
+ (Media->ReadOnly != OldMedia.ReadOnly) ||
+ (Media->BlockSize != OldMedia.BlockSize) ||
+ (Media->LastBlock != OldMedia.LastBlock)) {
+
+ //
+ // This function is called from:
+ // Block I/O Protocol APIs, which run at TPL_CALLBACK.
+ // DriverBindingStart(), which raises to TPL_CALLBACK.
+ ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
+
+ //
+ // When it is called from DriverBindingStart(), below reinstall fails.
+ // So ignore the return status check.
+ //
+ gBS->ReinstallProtocolInterface (
+ UsbMass->Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &UsbMass->BlockIo
+ );
+
+ //
+ // Reset MediaId after reinstalling Block I/O Protocol.
+ //
+ if (Media->MediaPresent != OldMedia.MediaPresent) {
+ if (Media->MediaPresent) {
+ Media->MediaId = 1;
+ } else {
+ Media->MediaId = 0;
+ }
+ }
+
+ if ((Media->ReadOnly != OldMedia.ReadOnly) ||
+ (Media->BlockSize != OldMedia.BlockSize) ||
+ (Media->LastBlock != OldMedia.LastBlock)) {
+ Media->MediaId++;
+ }
+
+ Status = Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA;
+ }
+
+ return Status;
+}
+
+
+/**
+ Read or write some blocks from the device.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ )
+{
+ USB_BOOT_READ_WRITE_10_CMD Cmd;
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINT32 CountMax;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ CountMax = USB_BOOT_MAX_CARRY_SIZE / BlockSize;
+ Status = EFI_SUCCESS;
+
+ while (TotalBlock > 0) {
+ //
+ // Split the total blocks into smaller pieces to ease the pressure
+ // on the device. We must split the total block because the READ10
+ // command only has 16 bit transfer length (in the unit of block).
+ //
+ Count = (UINT32)MIN (TotalBlock, CountMax);
+ Count = MIN (MAX_UINT16, Count);
+ ByteSize = Count * BlockSize;
+
+ //
+ // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
+ //
+ Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
+
+ //
+ // Fill in the command then execute
+ //
+ ZeroMem (&Cmd, sizeof (USB_BOOT_READ_WRITE_10_CMD));
+
+ Cmd.OpCode = Write ? USB_BOOT_WRITE10_OPCODE : USB_BOOT_READ10_OPCODE;
+ Cmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ WriteUnaligned32 ((UINT32 *) Cmd.Lba, SwapBytes32 (Lba));
+ WriteUnaligned16 ((UINT16 *) Cmd.TransferLen, SwapBytes16 ((UINT16)Count));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &Cmd,
+ (UINT8) sizeof (USB_BOOT_READ_WRITE_10_CMD),
+ Write ? EfiUsbDataOut : EfiUsbDataIn,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "UsbBoot%sBlocks: LBA (0x%lx), Blk (0x%x)\n",
+ Write ? L"Write" : L"Read",
+ Lba, Count
+ ));
+ Lba += Count;
+ Buffer += ByteSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+/**
+ Read or write some blocks from the device by SCSI 16 byte cmd.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks16 (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ )
+{
+ UINT8 Cmd[16];
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINT32 CountMax;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ CountMax = USB_BOOT_MAX_CARRY_SIZE / BlockSize;
+ Status = EFI_SUCCESS;
+
+ while (TotalBlock > 0) {
+ //
+ // Split the total blocks into smaller pieces.
+ //
+ Count = (UINT32)MIN (TotalBlock, CountMax);
+ ByteSize = Count * BlockSize;
+
+ //
+ // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
+ //
+ Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
+
+ //
+ // Fill in the command then execute
+ //
+ ZeroMem (Cmd, sizeof (Cmd));
+
+ Cmd[0] = Write ? EFI_SCSI_OP_WRITE16 : EFI_SCSI_OP_READ16;
+ Cmd[1] = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));
+ WriteUnaligned64 ((UINT64 *) &Cmd[2], SwapBytes64 (Lba));
+ WriteUnaligned32 ((UINT32 *) &Cmd[10], SwapBytes32 (Count));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ Cmd,
+ (UINT8) sizeof (Cmd),
+ Write ? EfiUsbDataOut : EfiUsbDataIn,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "UsbBoot%sBlocks16: LBA (0x%lx), Blk (0x%x)\n",
+ Write ? L"Write" : L"Read",
+ Lba, Count
+ ));
+ Lba += Count;
+ Buffer += ByteSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+/**
+ Use the USB clear feature control transfer to clear the endpoint stall condition.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param EndpointAddr The endpoint to clear stall for
+
+ @retval EFI_SUCCESS The endpoint stall condition is cleared.
+ @retval Others Failed to clear the endpoint stall condition.
+
+**/
+EFI_STATUS
+UsbClearEndpointStall (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINT8 EndpointAddr
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+ UINT32 Timeout;
+
+ Request.RequestType = 0x02;
+ Request.Request = USB_REQ_CLEAR_FEATURE;
+ Request.Value = USB_FEATURE_ENDPOINT_HALT;
+ Request.Index = EndpointAddr;
+ Request.Length = 0;
+ Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ Status = UsbIo->UsbControlTransfer (
+ UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &CmdResult
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h
new file mode 100644
index 000000000..f34a41284
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h
@@ -0,0 +1,338 @@
+/** @file
+ Definition of the command set of USB Mass Storage Specification
+ for Bootability, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_MASS_BOOT_H_
+#define _EFI_USB_MASS_BOOT_H_
+
+//
+// The opcodes of various USB boot commands:
+// INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified
+// by Multi-Media Commands (MMC) set.
+// Others are "Group 1 Timeout Commands". That is,
+// they should be retried if driver is ready.
+//
+#define USB_BOOT_INQUIRY_OPCODE 0x12
+#define USB_BOOT_REQUEST_SENSE_OPCODE 0x03
+#define USB_BOOT_MODE_SENSE10_OPCODE 0x5A
+#define USB_BOOT_READ_CAPACITY_OPCODE 0x25
+#define USB_BOOT_TEST_UNIT_READY_OPCODE 0x00
+#define USB_BOOT_READ10_OPCODE 0x28
+#define USB_BOOT_WRITE10_OPCODE 0x2A
+
+#define USB_SCSI_MODE_SENSE6_OPCODE 0x1A
+
+//
+// The Sense Key part of the sense data. Sense data has three levels:
+// Sense key, Additional Sense Code and Additional Sense Code Qualifier
+//
+#define USB_BOOT_SENSE_NO_SENSE 0x00 ///< No sense key
+#define USB_BOOT_SENSE_RECOVERED 0x01 ///< Last command succeed with recovery actions
+#define USB_BOOT_SENSE_NOT_READY 0x02 ///< Device not ready
+#define USB_BOOT_SNESE_MEDIUM_ERROR 0X03 ///< Failed probably because flaw in the media
+#define USB_BOOT_SENSE_HARDWARE_ERROR 0X04 ///< Non-recoverable hardware failure
+#define USB_BOOT_SENSE_ILLEGAL_REQUEST 0X05 ///< Illegal parameters in the request
+#define USB_BOOT_SENSE_UNIT_ATTENTION 0X06 ///< Removable medium may have been changed
+#define USB_BOOT_SENSE_DATA_PROTECT 0X07 ///< Write protected
+#define USB_BOOT_SENSE_BLANK_CHECK 0X08 ///< Blank/non-blank medium while reading/writing
+#define USB_BOOT_SENSE_VENDOR 0X09 ///< Vendor specific sense key
+#define USB_BOOT_SENSE_ABORTED 0X0B ///< Command aborted by the device
+#define USB_BOOT_SENSE_VOLUME_OVERFLOW 0x0D ///< Partition overflow
+#define USB_BOOT_SENSE_MISCOMPARE 0x0E ///< Source data mis-match while verfying.
+
+#define USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
+#define USB_BOOT_ASC_NOT_READY 0x04
+#define USB_BOOT_ASC_NO_MEDIA 0x3A
+#define USB_BOOT_ASC_MEDIA_CHANGE 0x28
+
+//
+// Supported PDT codes, or Peripheral Device Type
+//
+#define USB_PDT_DIRECT_ACCESS 0x00 ///< Direct access device
+#define USB_PDT_CDROM 0x05 ///< CDROM
+#define USB_PDT_OPTICAL 0x07 ///< Non-CD optical disks
+#define USB_PDT_SIMPLE_DIRECT 0x0E ///< Simplified direct access device
+
+//
+// Other parameters, Max carried size is 64KB.
+//
+#define USB_BOOT_MAX_CARRY_SIZE SIZE_64KB
+
+//
+// Retry mass command times, set by experience
+//
+#define USB_BOOT_COMMAND_RETRY 5
+
+//
+// Wait for unit ready command, set by experience
+//
+#define USB_BOOT_RETRY_UNIT_READY_STALL (500 * USB_MASS_1_MILLISECOND)
+
+//
+// Mass command timeout, refers to specification[USB20-9.2.6.1]
+//
+// USB2.0 Spec define the up-limit timeout 5s for all command. USB floppy,
+// USB CD-Rom and iPod devices are much slower than USB key when response
+// most of commands, So we set 5s as timeout here.
+//
+#define USB_BOOT_GENERAL_CMD_TIMEOUT (5 * USB_MASS_1_SECOND)
+
+//
+// The required commands are INQUIRY, READ CAPACITY, TEST UNIT READY,
+// READ10, WRITE10, and REQUEST SENSE. The BLOCK_IO protocol uses LBA
+// so it isn't necessary to issue MODE SENSE / READ FORMAT CAPACITY
+// command to retrieve the disk gemotrics.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; ///< Lun (high 3 bits)
+ UINT8 Reserved0[2];
+ UINT8 AllocLen;
+ UINT8 Reserved1;
+ UINT8 Pad[6];
+} USB_BOOT_INQUIRY_CMD;
+
+typedef struct {
+ UINT8 Pdt; ///< Peripheral Device Type (low 5 bits)
+ UINT8 Removable; ///< Removable Media (highest bit)
+ UINT8 Reserved0[2];
+ UINT8 AddLen; ///< Additional length
+ UINT8 Reserved1[3];
+ UINT8 VendorID[8];
+ UINT8 ProductID[16];
+ UINT8 ProductRevision[4];
+} USB_BOOT_INQUIRY_DATA;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 Reserved0[8];
+ UINT8 Pad[2];
+} USB_BOOT_READ_CAPACITY_CMD;
+
+typedef struct {
+ UINT8 LastLba[4];
+ UINT8 BlockLen[4];
+} USB_BOOT_READ_CAPACITY_DATA;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 Reserved[4];
+ UINT8 Pad[6];
+} USB_BOOT_TEST_UNIT_READY_CMD;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 PageCode;
+ UINT8 Reserved0[4];
+ UINT8 ParaListLenMsb;
+ UINT8 ParaListLenLsb;
+ UINT8 Reserved1;
+ UINT8 Pad[2];
+} USB_BOOT_MODE_SENSE10_CMD;
+
+typedef struct {
+ UINT8 ModeDataLenMsb;
+ UINT8 ModeDataLenLsb;
+ UINT8 Reserved0[4];
+ UINT8 BlkDesLenMsb;
+ UINT8 BlkDesLenLsb;
+} USB_BOOT_MODE_SENSE10_PARA_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; ///< Lun (High 3 bits)
+ UINT8 Lba[4]; ///< Logical block address
+ UINT8 Reserved0;
+ UINT8 TransferLen[2]; ///< Transfer length
+ UINT8 Reserverd1;
+ UINT8 Pad[2];
+} USB_BOOT_READ_WRITE_10_CMD;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; ///< Lun (High 3 bits)
+ UINT8 Reserved0[2];
+ UINT8 AllocLen; ///< Allocation length
+ UINT8 Reserved1;
+ UINT8 Pad[6];
+} USB_BOOT_REQUEST_SENSE_CMD;
+
+typedef struct {
+ UINT8 ErrorCode;
+ UINT8 Reserved0;
+ UINT8 SenseKey; ///< Sense key (low 4 bits)
+ UINT8 Infor[4];
+ UINT8 AddLen; ///< Additional Sense length, 10
+ UINT8 Reserved1[4];
+ UINT8 Asc; ///< Additional Sense Code
+ UINT8 Ascq; ///< Additional Sense Code Qualifier
+ UINT8 Reserverd2[4];
+} USB_BOOT_REQUEST_SENSE_DATA;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 PageCode;
+ UINT8 Reserved0;
+ UINT8 AllocateLen;
+ UINT8 Control;
+} USB_SCSI_MODE_SENSE6_CMD;
+
+typedef struct {
+ UINT8 ModeDataLen;
+ UINT8 MediumType;
+ UINT8 DevicePara;
+ UINT8 BlkDesLen;
+} USB_SCSI_MODE_SENSE6_PARA_HEADER;
+#pragma pack()
+
+//
+// Convert a LUN number to that in the command
+//
+#define USB_BOOT_LUN(Lun) ((Lun) << 5)
+
+//
+// Get the removable, PDT, and sense key bits from the command data
+//
+#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & BIT7) != 0)
+#define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f)
+#define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f)
+
+/**
+ Get the parameters for the USB mass storage media.
+
+ This function get the parameters for the USB mass storage media,
+ It is used both to initialize the media during the Start() phase
+ of Driver Binding Protocol and to re-initialize it when the media is
+ changed. Although the RemoveableMedia is unlikely to change,
+ it is also included here.
+
+ @param UsbMass The device to retrieve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval Other Failed to get the parameters.
+
+**/
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ Execute TEST UNIT READY command to check if the device is ready.
+
+ @param UsbMass The device to test
+
+ @retval EFI_SUCCESS The device is ready.
+ @retval Others Device not ready.
+
+**/
+EFI_STATUS
+UsbBootIsUnitReady (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param UsbMass The device to check.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ Read some blocks from the device.
+
+ @param UsbMass The USB mass storage device to read from
+ @param Lba The start block number
+ @param TotalBlock Total block number to read
+ @param Buffer The buffer to read to
+
+ @retval EFI_SUCCESS Data are read into the buffer
+ @retval Others Failed to read all the data
+
+**/
+EFI_STATUS
+UsbBootReadBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Read or write some blocks from the device.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ );
+
+/**
+ Read or write some blocks from the device by SCSI 16 byte cmd.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks16 (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ );
+
+/**
+ Use the USB clear feature control transfer to clear the endpoint stall condition.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param EndpointAddr The endpoint to clear stall for
+
+ @retval EFI_SUCCESS The endpoint stall condition is cleared.
+ @retval Others Failed to clear the endpoint stall condition.
+
+**/
+EFI_STATUS
+UsbClearEndpointStall (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINT8 EndpointAddr
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c
new file mode 100644
index 000000000..1e878a1bd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c
@@ -0,0 +1,607 @@
+/** @file
+ Implementation of the USB mass storage Bulk-Only Transport protocol,
+ according to USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// Definition of USB BOT Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbBotTransport = {
+ USB_MASS_STORE_BOT,
+ UsbBotInit,
+ UsbBotExecCommand,
+ UsbBotResetDevice,
+ UsbBotGetMaxLun,
+ UsbBotCleanUp
+};
+
+/**
+ Initializes USB BOT protocol.
+
+ This function initializes the USB mass storage class BOT protocol.
+ It will save its context which is a USB_BOT_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB BOT initialization fails.
+
+**/
+EFI_STATUS
+UsbBotInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Allocate the BOT context for USB_BOT_PROTOCOL and two endpoint descriptors.
+ //
+ UsbBot = AllocateZeroPool (sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));
+ ASSERT (UsbBot != NULL);
+
+ UsbBot->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it
+ // is a USB Mass Storage BOT interface.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Interface = &UsbBot->Interface;
+
+ if (Interface->InterfaceProtocol != USB_MASS_STORE_BOT) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // Locate and save the first bulk-in and bulk-out endpoint
+ //
+ for (Index = 0; Index < Interface->NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
+
+ if (EFI_ERROR (Status) || !USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
+ continue;
+ }
+
+ if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbBot->BulkInEndpoint == NULL)) {
+
+ UsbBot->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1);
+ CopyMem(UsbBot->BulkInEndpoint, &EndPoint, sizeof (EndPoint));
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbBot->BulkOutEndpoint == NULL)) {
+
+ UsbBot->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;
+ CopyMem (UsbBot->BulkOutEndpoint, &EndPoint, sizeof(EndPoint));
+ }
+ }
+
+ //
+ // If bulk-in or bulk-out endpoint is not found, report error.
+ //
+ if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // The USB BOT protocol uses CBWTag to match the CBW and CSW.
+ //
+ UsbBot->CbwTag = 0x01;
+
+ if (Context != NULL) {
+ *Context = UsbBot;
+ } else {
+ FreePool (UsbBot);
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ FreePool (UsbBot);
+ return Status;
+}
+
+/**
+ Send the command to the device using Bulk-Out endpoint.
+
+ This function sends the command to the device using Bulk-Out endpoint.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Command phase.
+
+ @param UsbBot The USB BOT device
+ @param Cmd The command to transfer to device
+ @param CmdLen The length of the command
+ @param DataDir The direction of the data
+ @param TransLen The expected length of the data
+ @param Lun The number of logic unit
+
+ @retval EFI_SUCCESS The command is sent to the device.
+ @retval EFI_NOT_READY The device return NAK to the transfer
+ @retval Others Failed to send the command to device
+
+**/
+EFI_STATUS
+UsbBotSendCommand (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN UINT8 *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN UINT32 TransLen,
+ IN UINT8 Lun
+ )
+{
+ USB_BOT_CBW Cbw;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINTN DataLen;
+ UINTN Timeout;
+
+ ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));
+
+ //
+ // Fill in the Command Block Wrapper.
+ //
+ Cbw.Signature = USB_BOT_CBW_SIGNATURE;
+ Cbw.Tag = UsbBot->CbwTag;
+ Cbw.DataLen = TransLen;
+ Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? BIT7 : 0);
+ Cbw.Lun = Lun;
+ Cbw.CmdLen = CmdLen;
+
+ ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);
+ CopyMem (Cbw.CmdBlock, Cmd, CmdLen);
+
+ Result = 0;
+ DataLen = sizeof (USB_BOT_CBW);
+ Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ //
+ // Use USB I/O Protocol to send the Command Block Wrapper to the device.
+ //
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ UsbBot->BulkOutEndpoint->EndpointAddress,
+ &Cbw,
+ &DataLen,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {
+ //
+ // Respond to Bulk-Out endpoint stall with a Reset Recovery,
+ // according to section 5.3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ UsbBotResetDevice (UsbBot, FALSE);
+ } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
+ Status = EFI_NOT_READY;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Transfer the data between the device and host.
+
+ This function transfers the data between the device and host.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Data phase.
+
+ @param UsbBot The USB BOT device
+ @param DataDir The direction of the data
+ @param Data The buffer to hold data
+ @param TransLen The expected length of the data
+ @param Timeout The time to wait the command to complete
+
+ @retval EFI_SUCCESS The data is transferred
+ @retval EFI_SUCCESS No data to transfer
+ @retval EFI_NOT_READY The device return NAK to the transfer
+ @retval Others Failed to transfer data
+
+**/
+EFI_STATUS
+UsbBotDataTransfer (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN OUT UINT8 *Data,
+ IN OUT UINTN *TransLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
+ EFI_STATUS Status;
+ UINT32 Result;
+
+ //
+ // If no data to transfer, just return EFI_SUCCESS.
+ //
+ if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Select the endpoint then issue the transfer
+ //
+ if (DataDir == EfiUsbDataIn) {
+ Endpoint = UsbBot->BulkInEndpoint;
+ } else {
+ Endpoint = UsbBot->BulkOutEndpoint;
+ }
+
+ Result = 0;
+ Timeout = Timeout / USB_MASS_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ Endpoint->EndpointAddress,
+ Data,
+ TransLen,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: (%r)\n", Status));
+ DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: DataIn Stall\n"));
+ UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);
+ } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
+ Status = EFI_NOT_READY;
+ } else {
+ DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status));
+ }
+ if(Status == EFI_TIMEOUT){
+ UsbBotResetDevice(UsbBot, FALSE);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the command execution status from device.
+
+ This function gets the command execution status from device.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Status phase.
+
+ This function returns the transfer status of the BOT's CSW status,
+ and returns the high level command execution result in Result. So
+ even if EFI_SUCCESS is returned, the command may still have failed.
+
+ @param UsbBot The USB BOT device.
+ @param TransLen The expected length of the data.
+ @param CmdStatus The result of the command execution.
+
+ @retval EFI_SUCCESS Command execute result is retrieved and in the Result.
+ @retval Other Error occurred when trying to get status.
+
+**/
+EFI_STATUS
+UsbBotGetStatus (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN UINT32 TransLen,
+ OUT UINT8 *CmdStatus
+ )
+{
+ USB_BOT_CSW Csw;
+ UINTN Len;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+ UINT32 Result;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 Index;
+ UINTN Timeout;
+
+ *CmdStatus = USB_BOT_COMMAND_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ Endpoint = UsbBot->BulkInEndpoint->EndpointAddress;
+ UsbIo = UsbBot->UsbIo;
+ Timeout = USB_BOT_RECV_CSW_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) {
+ //
+ // Attempt to the read Command Status Wrapper from bulk in endpoint
+ //
+ ZeroMem (&Csw, sizeof (USB_BOT_CSW));
+ Result = 0;
+ Len = sizeof (USB_BOT_CSW);
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ Endpoint,
+ &Csw,
+ &Len,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR(Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ UsbClearEndpointStall (UsbIo, Endpoint);
+ }
+ continue;
+ }
+
+ if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {
+ //
+ // CSW is invalid, so perform reset recovery
+ //
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {
+ //
+ // Respond phase error also needs reset recovery
+ //
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else {
+ *CmdStatus = Csw.CmdStatus;
+ break;
+ }
+ }
+ //
+ //The tag is increased even if there is an error.
+ //
+ UsbBot->CbwTag++;
+
+ return Status;
+}
+
+
+/**
+ Call the USB Mass Storage Class BOT protocol to issue
+ the command/data/status circle to execute the commands.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL
+ @param Cmd The high level command
+ @param CmdLen The command length
+ @param DataDir The direction of the data transfer
+ @param Data The buffer to hold data
+ @param DataLen The length of the data
+ @param Lun The number of logic unit
+ @param Timeout The time to wait command
+ @param CmdStatus The result of high level command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute command
+
+**/
+EFI_STATUS
+UsbBotExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_STATUS Status;
+ UINTN TransLen;
+ UINT8 Result;
+
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ //
+ // Send the command to the device. Return immediately if device
+ // rejects the command.
+ //
+ Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen, Lun);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Transfer the data. Don't return immediately even data transfer
+ // failed. The host should attempt to receive the CSW no matter
+ // whether it succeeds or fails.
+ //
+ TransLen = (UINTN) DataLen;
+ UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);
+
+ //
+ // Get the status, if that succeeds, interpret the result
+ //
+ Status = UsbBotGetStatus (UsbBot, DataLen, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));
+ return Status;
+ }
+
+ if (Result == 0) {
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the USB mass storage device by BOT protocol.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL.
+ @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
+ If TRUE, additionally reset parent hub port.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device..
+
+**/
+EFI_STATUS
+UsbBotResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINT32 Timeout;
+
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ if (ExtendedVerification) {
+ //
+ // If we need to do strictly reset, reset its parent hub port
+ //
+ Status = UsbBot->UsbIo->UsbPortReset (UsbBot->UsbIo);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Issue a class specific Bulk-Only Mass Storage Reset request,
+ // according to section 3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ Request.RequestType = 0x21;
+ Request.Request = USB_BOT_RESET_REQUEST;
+ Request.Value = 0;
+ Request.Index = UsbBot->Interface.InterfaceNumber;
+ Request.Length = 0;
+ Timeout = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbControlTransfer (
+ UsbBot->UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // The device shall NAK the host's request until the reset is
+ // complete. We can use this to sync the device and host. For
+ // now just stall 100ms to wait for the device.
+ //
+ gBS->Stall (USB_BOT_RESET_DEVICE_STALL);
+
+ //
+ // Clear the Bulk-In and Bulk-Out stall condition.
+ //
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);
+
+ return Status;
+}
+
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+EFI_STATUS
+UsbBotGetMaxLun (
+ IN VOID *Context,
+ OUT UINT8 *MaxLun
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINT32 Timeout;
+
+ if (Context == NULL || MaxLun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ //
+ // Issue a class specific Bulk-Only Mass Storage get max lun request.
+ // according to section 3.2 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ Request.RequestType = 0xA1;
+ Request.Request = USB_BOT_GETLUN_REQUEST;
+ Request.Value = 0;
+ Request.Index = UsbBot->Interface.InterfaceNumber;
+ Request.Length = 1;
+ Timeout = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbControlTransfer (
+ UsbBot->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ Timeout,
+ (VOID *) MaxLun,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status) || *MaxLun > USB_BOT_MAX_LUN) {
+ //
+ // If the Get LUN request returns an error or the MaxLun is larger than
+ // the maximum LUN value (0x0f) supported by the USB Mass Storage Class
+ // Bulk-Only Transport Spec, then set MaxLun to 0.
+ //
+ // This improves compatibility with USB FLASH drives that have a single LUN
+ // and either do not return a max LUN value or return an invalid maximum LUN
+ // value.
+ //
+ *MaxLun = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clean up the resource used by this BOT protocol.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbBotCleanUp (
+ IN VOID *Context
+ )
+{
+ FreePool (Context);
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h
new file mode 100644
index 000000000..3ef8f240a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h
@@ -0,0 +1,187 @@
+/** @file
+ Definition for the USB mass storage Bulk-Only Transport protocol,
+ based on the "Universal Serial Bus Mass Storage Class Bulk-Only
+ Transport" Revision 1.0, September 31, 1999.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_BOT_H_
+#define _EFI_USBMASS_BOT_H_
+
+extern USB_MASS_TRANSPORT mUsbBotTransport;
+
+//
+// Usb Bulk-Only class specific request
+//
+#define USB_BOT_RESET_REQUEST 0xFF ///< Bulk-Only Mass Storage Reset
+#define USB_BOT_GETLUN_REQUEST 0xFE ///< Get Max Lun
+#define USB_BOT_CBW_SIGNATURE 0x43425355 ///< dCBWSignature, tag the packet as CBW
+#define USB_BOT_CSW_SIGNATURE 0x53425355 ///< dCSWSignature, tag the packet as CSW
+#define USB_BOT_MAX_LUN 0x0F ///< Lun number is from 0 to 15
+#define USB_BOT_MAX_CMDLEN 16 ///< Maximum number of command from command set
+
+//
+// Usb BOT command block status values
+//
+#define USB_BOT_COMMAND_OK 0x00 ///< Command passed, good status
+#define USB_BOT_COMMAND_FAILED 0x01 ///< Command failed
+#define USB_BOT_COMMAND_ERROR 0x02 ///< Phase error, need to reset the device
+
+//
+// Usb Bot retry to get CSW, refers to specification[BOT10-5.3, it says 2 times]
+//
+#define USB_BOT_RECV_CSW_RETRY 3
+
+//
+// Usb Bot wait device reset complete, set by experience
+//
+#define USB_BOT_RESET_DEVICE_STALL (100 * USB_MASS_1_MILLISECOND)
+
+//
+// Usb Bot transport timeout, set by experience
+//
+#define USB_BOT_SEND_CBW_TIMEOUT (3 * USB_MASS_1_SECOND)
+#define USB_BOT_RECV_CSW_TIMEOUT (3 * USB_MASS_1_SECOND)
+#define USB_BOT_RESET_DEVICE_TIMEOUT (3 * USB_MASS_1_SECOND)
+
+#pragma pack(1)
+///
+/// The CBW (Command Block Wrapper) structures used by the USB BOT protocol.
+///
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataLen; ///< Length of data between CBW and CSW
+ UINT8 Flag; ///< Bit 7, 0 ~ Data-Out, 1 ~ Data-In
+ UINT8 Lun; ///< Lun number. Bits 0~3 are used
+ UINT8 CmdLen; ///< Length of the command. Bits 0~4 are used
+ UINT8 CmdBlock[USB_BOT_MAX_CMDLEN];
+} USB_BOT_CBW;
+
+///
+/// The and CSW (Command Status Wrapper) structures used by the USB BOT protocol.
+///
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataResidue;
+ UINT8 CmdStatus;
+} USB_BOT_CSW;
+#pragma pack()
+
+typedef struct {
+ //
+ // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
+ //
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
+ UINT32 CbwTag;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+} USB_BOT_PROTOCOL;
+
+/**
+ Initializes USB BOT protocol.
+
+ This function initializes the USB mass storage class BOT protocol.
+ It will save its context which is a USB_BOT_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB BOT initialization fails.
+
+**/
+EFI_STATUS
+UsbBotInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Call the USB Mass Storage Class BOT protocol to issue
+ the command/data/status circle to execute the commands.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL
+ @param Cmd The high level command
+ @param CmdLen The command length
+ @param DataDir The direction of the data transfer
+ @param Data The buffer to hold data
+ @param DataLen The length of the data
+ @param Lun The number of logic unit
+ @param Timeout The time to wait command
+ @param CmdStatus The result of high level command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute command
+
+**/
+EFI_STATUS
+UsbBotExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by BOT protocol.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL.
+ @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
+ If TRUE, additionally reset parent hub port.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device..
+
+**/
+EFI_STATUS
+UsbBotResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+EFI_STATUS
+UsbBotGetMaxLun (
+ IN VOID *Context,
+ OUT UINT8 *MaxLun
+ );
+
+/**
+ Clean up the resource used by this BOT protocol.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbBotCleanUp (
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c
new file mode 100644
index 000000000..477f0536d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c
@@ -0,0 +1,606 @@
+/** @file
+ Implementation of the USB mass storage Control/Bulk/Interrupt transport,
+ according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
+ Notice: it is being obsoleted by the standard body in favor of the BOT
+ (Bulk-Only Transport).
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// Definition of USB CBI0 Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbCbi0Transport = {
+ USB_MASS_STORE_CBI0,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ NULL,
+ UsbCbiCleanUp
+};
+
+//
+// Definition of USB CBI1 Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbCbi1Transport = {
+ USB_MASS_STORE_CBI1,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ NULL,
+ UsbCbiCleanUp
+};
+
+/**
+ Initializes USB CBI protocol.
+
+ This function initializes the USB mass storage class CBI protocol.
+ It will save its context which is a USB_CBI_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB CBI initialization fails.
+
+**/
+EFI_STATUS
+UsbCbiInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ )
+{
+ USB_CBI_PROTOCOL *UsbCbi;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Allocate the CBI context for USB_CBI_PROTOCOL and 3 endpoint descriptors.
+ //
+ UsbCbi = AllocateZeroPool (
+ sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+ ASSERT (UsbCbi != NULL);
+
+ UsbCbi->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it
+ // is a USB Mass Storage CBI interface.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Interface = &UsbCbi->Interface;
+ if ((Interface->InterfaceProtocol != USB_MASS_STORE_CBI0)
+ && (Interface->InterfaceProtocol != USB_MASS_STORE_CBI1)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // Locate and save the bulk-in, bulk-out, and interrupt endpoint
+ //
+ for (Index = 0; Index < Interface->NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
+ //
+ // Use the first Bulk-In and Bulk-Out endpoints
+ //
+ if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbCbi->BulkInEndpoint == NULL)) {
+
+ UsbCbi->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1);
+ CopyMem(UsbCbi->BulkInEndpoint, &EndPoint, sizeof (EndPoint));;
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbCbi->BulkOutEndpoint == NULL)) {
+
+ UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
+ CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint));
+ }
+ } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {
+ //
+ // Use the first interrupt endpoint if it is CBI0
+ //
+ if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) &&
+ (UsbCbi->InterruptEndpoint == NULL)) {
+
+ UsbCbi->InterruptEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 2;
+ CopyMem(UsbCbi->InterruptEndpoint, &EndPoint, sizeof (EndPoint));
+ }
+ }
+ }
+
+ if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+ if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ if (Context != NULL) {
+ *Context = UsbCbi;
+ } else {
+ FreePool (UsbCbi);
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ FreePool (UsbCbi);
+ return Status;
+}
+
+/**
+ Send the command to the device using class specific control transfer.
+
+ This function sends command to the device using class specific control transfer.
+ The CBI contains three phases: Command, Data, and Status. This is Command phase.
+
+ @param UsbCbi The USB CBI protocol
+ @param Cmd The high level command to transfer to device
+ @param CmdLen The length of the command
+ @param Timeout The time to wait the command to finish
+
+ @retval EFI_SUCCESS The command is sent to the device.
+ @retval Others The command failed to transfer to device
+
+**/
+EFI_STATUS
+UsbCbiSendCommand (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN UINT8 *Cmd,
+ IN UINT8 CmdLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ UINTN DataLen;
+ INTN Retry;
+
+ //
+ // Fill in the device request, CBI use the "Accept Device-Specific
+ // Cmd" (ADSC) class specific request to send commands.
+ //
+ Request.RequestType = 0x21;
+ Request.Request = 0;
+ Request.Value = 0;
+ Request.Index = UsbCbi->Interface.InterfaceNumber;
+ Request.Length = CmdLen;
+
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_1_MILLISECOND;
+
+ for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
+ //
+ // Use USB I/O Protocol to send the command to the device
+ //
+ TransStatus = 0;
+ DataLen = CmdLen;
+
+ Status = UsbCbi->UsbIo->UsbControlTransfer (
+ UsbCbi->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ Timeout,
+ Cmd,
+ DataLen,
+ &TransStatus
+ );
+ //
+ // The device can fail the command by STALL the control endpoint.
+ // It can delay the command by NAK the data or status stage, this
+ // is a "class-specific exemption to the USB specification". Retry
+ // if the command is NAKed.
+ //
+ if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
+ continue;
+ }
+
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Transfer data between the device and host.
+
+ This function transfers data between the device and host.
+ The CBI contains three phases: Command, Data, and Status. This is Data phase.
+
+ @param UsbCbi The USB CBI device
+ @param DataDir The direction of the data transfer
+ @param Data The buffer to hold the data for input or output.
+ @param TransLen On input, the expected transfer length.
+ On output, the length of data actually transferred.
+ @param Timeout The time to wait for the command to execute
+
+ @retval EFI_SUCCESS The data transferred successfully.
+ @retval EFI_SUCCESS No data to transfer
+ @retval Others Failed to transfer all the data
+
+**/
+EFI_STATUS
+UsbCbiDataTransfer (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN OUT UINT8 *Data,
+ IN OUT UINTN *TransLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ UINTN Remain;
+ UINTN Increment;
+ UINT8 *Next;
+ UINTN Retry;
+
+ //
+ // If no data to transfer, just return EFI_SUCCESS.
+ //
+ if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Select the endpoint then issue the transfer
+ //
+ if (DataDir == EfiUsbDataIn) {
+ Endpoint = UsbCbi->BulkInEndpoint;
+ } else {
+ Endpoint = UsbCbi->BulkOutEndpoint;
+ }
+
+ Next = Data;
+ Remain = *TransLen;
+ Retry = 0;
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_1_MILLISECOND;
+
+ //
+ // Transfer the data with a loop. The length of data transferred once is restricted.
+ //
+ while (Remain > 0) {
+ TransStatus = 0;
+
+ if (Remain > (UINTN) USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize) {
+ Increment = USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize;
+ } else {
+ Increment = Remain;
+ }
+
+ Status = UsbCbi->UsbIo->UsbBulkTransfer (
+ UsbCbi->UsbIo,
+ Endpoint->EndpointAddress,
+ Next,
+ &Increment,
+ Timeout,
+ &TransStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (TransStatus == EFI_USB_ERR_NAK) {
+ //
+ // The device can NAK the host if either the data/buffer isn't
+ // available or the command is in-progress.
+ // If data are partially transferred, we just ignore NAK and continue.
+ // If all data have been transferred and status is NAK, then we retry for several times.
+ // If retry exceeds the USB_CBI_MAX_RETRY, then return error status.
+ //
+ if (Increment == 0) {
+ if (++Retry > USB_CBI_MAX_RETRY) {
+ goto ON_EXIT;
+ }
+ } else {
+ Next += Increment;
+ Remain -= Increment;
+ Retry = 0;
+ }
+
+ continue;
+ }
+
+ //
+ // The device can fail the command by STALL the bulk endpoint.
+ // Clear the stall if that is the case.
+ //
+ if (TransStatus == EFI_USB_ERR_STALL) {
+ UsbClearEndpointStall (UsbCbi->UsbIo, Endpoint->EndpointAddress);
+ }
+
+ goto ON_EXIT;
+ }
+
+ Next += Increment;
+ Remain -= Increment;
+ }
+
+ON_EXIT:
+ *TransLen -= Remain;
+ return Status;
+}
+
+
+/**
+ Gets the result of high level command execution from interrupt endpoint.
+
+ This function returns the USB transfer status, and put the high level
+ command execution result in Result.
+ The CBI contains three phases: Command, Data, and Status. This is Status phase.
+
+ @param UsbCbi The USB CBI protocol
+ @param Timeout The time to wait for the command to execute
+ @param Result The result of the command execution.
+
+ @retval EFI_SUCCESS The high level command execution result is
+ retrieved in Result.
+ @retval Others Failed to retrieve the result.
+
+**/
+EFI_STATUS
+UsbCbiGetStatus (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN UINT32 Timeout,
+ OUT USB_CBI_STATUS *Result
+ )
+{
+ UINTN Len;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ INTN Retry;
+
+ Endpoint = UsbCbi->InterruptEndpoint->EndpointAddress;
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_1_MILLISECOND;
+
+ //
+ // Attempt to the read the result from interrupt endpoint
+ //
+ for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
+ TransStatus = 0;
+ Len = sizeof (USB_CBI_STATUS);
+
+ Status = UsbCbi->UsbIo->UsbSyncInterruptTransfer (
+ UsbCbi->UsbIo,
+ Endpoint,
+ Result,
+ &Len,
+ Timeout,
+ &TransStatus
+ );
+ //
+ // The CBI can NAK the interrupt endpoint if the command is in-progress.
+ //
+ if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
+ continue;
+ }
+
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute USB mass storage command through the CBI0/CBI1 transport protocol.
+
+ @param Context The USB CBI Protocol.
+ @param Cmd The command to transfer to device
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of the buffer
+ @param Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+EFI_STATUS
+UsbCbiExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ )
+{
+ USB_CBI_PROTOCOL *UsbCbi;
+ USB_CBI_STATUS Result;
+ EFI_STATUS Status;
+ UINTN TransLen;
+
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ UsbCbi = (USB_CBI_PROTOCOL *) Context;
+
+ //
+ // Send the command to the device. Return immediately if device
+ // rejects the command.
+ //
+ Status = UsbCbiSendCommand (UsbCbi, Cmd, CmdLen, Timeout);
+ if (EFI_ERROR (Status)) {
+ gBS->Stall(10 * USB_MASS_1_MILLISECOND);
+ DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status));
+ return Status;
+ }
+
+ //
+ // Transfer the data. Return this status if no interrupt endpoint
+ // is used to report the transfer status.
+ //
+ TransLen = (UINTN) DataLen;
+
+ Status = UsbCbiDataTransfer (UsbCbi, DataDir, Data, &TransLen, Timeout);
+ if (UsbCbi->InterruptEndpoint == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status));
+ return Status;
+ }
+
+ //
+ // Get the status. If it succeeds, interpret the result.
+ //
+ Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
+ return Status;
+ }
+
+ if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
+ //
+ // For UFI device, ASC and ASCQ are returned.
+ //
+ // Do not set the USB_MASS_CMD_FAIL for a request sense command
+ // as a bad result type doesn't mean a cmd failure
+ //
+ if (Result.Type != 0 && *(UINT8*)Cmd != 0x03) {
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ }
+ } else {
+ //
+ // Check page 27, CBI spec 1.1 for vaious reture status.
+ //
+ switch (Result.Value & 0x03) {
+ case 0x00:
+ //
+ // Pass
+ //
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ break;
+
+ case 0x02:
+ //
+ // Phase Error, response with reset.
+ // No break here to fall through to "Fail".
+ //
+ UsbCbiResetDevice (UsbCbi, FALSE);
+
+ case 0x01:
+ //
+ // Fail
+ //
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ break;
+
+ case 0x03:
+ //
+ // Persistent Fail. Need to send REQUEST SENSE.
+ //
+ *CmdStatus = USB_MASS_CMD_PERSISTENT;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the USB mass storage device by CBI protocol.
+
+ This function resets the USB mass storage device by CBI protocol.
+ The reset is defined as a non-data command. Don't use UsbCbiExecCommand
+ to send the command to device because that may introduce recursive loop.
+
+ @param Context The USB CBI protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+UsbCbiResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ UINT8 ResetCmd[USB_CBI_RESET_CMD_LEN];
+ USB_CBI_PROTOCOL *UsbCbi;
+ USB_CBI_STATUS Result;
+ EFI_STATUS Status;
+ UINT32 Timeout;
+
+ UsbCbi = (USB_CBI_PROTOCOL *) Context;
+
+ //
+ // Fill in the reset command.
+ //
+ SetMem (ResetCmd, USB_CBI_RESET_CMD_LEN, 0xFF);
+
+ ResetCmd[0] = 0x1D;
+ ResetCmd[1] = 0x04;
+ Timeout = USB_CBI_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ //
+ // Send the command to the device. Don't use UsbCbiExecCommand here.
+ //
+ Status = UsbCbiSendCommand (UsbCbi, ResetCmd, USB_CBI_RESET_CMD_LEN, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Just retrieve the status and ignore that. Then stall
+ // 50ms to wait for it to complete.
+ //
+ UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ gBS->Stall (USB_CBI_RESET_DEVICE_STALL);
+
+ //
+ // Clear the Bulk-In and Bulk-Out stall condition and init data toggle.
+ //
+ UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);
+ UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);
+
+ return Status;
+}
+
+
+/**
+ Clean up the CBI protocol's resource.
+
+ @param Context The instance of CBI protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbCbiCleanUp (
+ IN VOID *Context
+ )
+{
+ FreePool (Context);
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h
new file mode 100644
index 000000000..b79b9c243
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h
@@ -0,0 +1,134 @@
+/** @file
+ Definition for the USB mass storage Control/Bulk/Interrupt (CBI) transport,
+ according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_CBI_H_
+#define _EFI_USBMASS_CBI_H_
+
+extern USB_MASS_TRANSPORT mUsbCbi0Transport;
+extern USB_MASS_TRANSPORT mUsbCbi1Transport;
+
+#define USB_CBI_MAX_PACKET_NUM 16
+#define USB_CBI_RESET_CMD_LEN 12
+//
+// USB CBI retry C/B/I transport times, set by experience
+//
+#define USB_CBI_MAX_RETRY 3
+//
+// Time to wait for USB CBI reset to complete, set by experience
+//
+#define USB_CBI_RESET_DEVICE_STALL (50 * USB_MASS_1_MILLISECOND)
+//
+// USB CBI transport timeout, set by experience
+//
+#define USB_CBI_RESET_DEVICE_TIMEOUT (1 * USB_MASS_1_SECOND)
+
+typedef struct {
+ //
+ // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
+ //
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *InterruptEndpoint;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+} USB_CBI_PROTOCOL;
+
+#pragma pack(1)
+typedef struct {
+ UINT8 Type;
+ UINT8 Value;
+} USB_CBI_STATUS;
+#pragma pack()
+
+/**
+ Initializes USB CBI protocol.
+
+ This function initializes the USB mass storage class CBI protocol.
+ It will save its context which is a USB_CBI_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB CBI initialization fails.
+
+**/
+EFI_STATUS
+UsbCbiInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Execute USB mass storage command through the CBI0/CBI1 transport protocol.
+
+ @param Context The USB CBI Protocol.
+ @param Cmd The command to transfer to device
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of the buffer
+ @param Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+EFI_STATUS
+UsbCbiExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by CBI protocol.
+
+ This function resets the USB mass storage device by CBI protocol.
+ The reset is defined as a non-data command. Don't use UsbCbiExecCommand
+ to send the command to device because that may introduce recursive loop.
+
+ @param Context The USB CBI protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+UsbCbiResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Clean up the CBI protocol's resource.
+
+ @param Context The instance of CBI protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbCbiCleanUp (
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c
new file mode 100644
index 000000000..44e1d0c01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c
@@ -0,0 +1,156 @@
+/** @file
+ This file is used to implement the EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+EFI_DISK_INFO_PROTOCOL gUsbDiskInfoProtocolTemplate = {
+ EFI_DISK_INFO_USB_INTERFACE_GUID,
+ UsbDiskInfoInquiry,
+ UsbDiskInfoIdentify,
+ UsbDiskInfoSenseData,
+ UsbDiskInfoWhichIde
+};
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with USB interface GUID.
+
+ @param[in] UsbMass The pointer of USB_MASS_DEVICE.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ CopyMem (&UsbMass->DiskInfo, &gUsbDiskInfoProtocolTemplate, sizeof (gUsbDiskInfoProtocolTemplate));
+}
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ USB_MASS_DEVICE *UsbMass;
+
+ UsbMass = USB_MASS_DEVICE_FROM_DISK_INFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*InquiryDataSize >= sizeof (UsbMass->InquiryData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &UsbMass->InquiryData, sizeof (UsbMass->InquiryData));
+ }
+ *InquiryDataSize = sizeof (UsbMass->InquiryData);
+ return Status;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+UsbDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoSenseData (
+ 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 to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+UsbDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h
new file mode 100644
index 000000000..2571cc541
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h
@@ -0,0 +1,123 @@
+/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_DISKINFO_H_
+#define _EFI_USBMASS_DISKINFO_H_
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with USB interface GUID.
+
+ @param UsbMass The pointer of USB_MASS_DEVICE.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] 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 InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] 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
+UsbDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense 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 SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] 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
+UsbDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
new file mode 100644
index 000000000..bbd19e044
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
@@ -0,0 +1,1108 @@
+/** @file
+ USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+#define USB_MASS_TRANSPORT_COUNT 3
+//
+// Array of USB transport interfaces.
+//
+USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
+ &mUsbCbi0Transport,
+ &mUsbCbi1Transport,
+ &mUsbBotTransport,
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
+ USBMassDriverBindingSupported,
+ USBMassDriverBindingStart,
+ USBMassDriverBindingStop,
+ 0x11,
+ NULL,
+ NULL
+};
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to 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 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_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
+UsbMassReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINTN TotalBlock;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,
+ // need to detect the media before each read/write. While some of
+ // Usb-Flash is marked as removable media.
+ //
+ if (Media->RemovableMedia) {
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto ON_EXIT;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto ON_EXIT;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ //
+ // Make sure the range to read is valid.
+ //
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (UsbMass->Cdb16Byte) {
+ Status = UsbBootReadWriteBlocks16 (UsbMass, FALSE, Lba, TotalBlock, Buffer);
+ } else {
+ Status = UsbBootReadWriteBlocks (UsbMass, FALSE, (UINT32) Lba, TotalBlock, Buffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @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.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer 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 cannot 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
+UsbMassWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINTN TotalBlock;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,
+ // need to detect the media before each read/write. Some of
+ // USB Flash is marked as removable media.
+ //
+ if (Media->RemovableMedia) {
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto ON_EXIT;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto ON_EXIT;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ //
+ // Make sure the range to write is valid.
+ //
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // Try to write the data even the device is marked as ReadOnly,
+ // and clear the status should the write succeed.
+ //
+ if (UsbMass->Cdb16Byte) {
+ Status = UsbBootReadWriteBlocks16 (UsbMass, TRUE, Lba, TotalBlock, Buffer);
+ } else {
+ Status = UsbBootReadWriteBlocks (UsbMass, TRUE, (UINT32) Lba, TotalBlock, Buffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Flushes all modified data to a physical block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
+ USB mass storage device doesn't support write cache,
+ so return EFI_SUCCESS directly.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+
+ @param UsbMass The USB mass storage device
+
+ @retval EFI_SUCCESS The media parameters are updated successfully.
+ @retval Others Failed to get the media parameters.
+
+**/
+EFI_STATUS
+UsbMassInitMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
+ // section for Block I/O Protocol.
+ //
+ Media->MediaPresent = FALSE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = FALSE;
+ Media->WriteCaching = FALSE;
+ Media->IoAlign = 0;
+ Media->MediaId = 1;
+
+ Status = UsbBootGetParams (UsbMass);
+ DEBUG ((DEBUG_INFO, "UsbMassInitMedia: UsbBootGetParams (%r)\n", Status));
+ if (Status == EFI_MEDIA_CHANGED) {
+ //
+ // Some USB storage devices may report MEDIA_CHANGED sense key when hot-plugged.
+ // Treat it as SUCCESS
+ //
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize the USB Mass Storage transport.
+
+ This function tries to find the matching USB Mass Storage transport
+ protocol for USB device. If found, initializes the matching transport.
+
+ @param This The USB mass driver's driver binding.
+ @param Controller The device to test.
+ @param Transport The pointer to pointer to USB_MASS_TRANSPORT.
+ @param Context The parameter for USB_MASS_DEVICE.Context.
+ @param MaxLun Get the MaxLun if is BOT dev.
+
+ @retval EFI_SUCCESS The initialization is successful.
+ @retval EFI_UNSUPPORTED No matching transport protocol is found.
+ @retval Others Failed to initialize dev.
+
+**/
+EFI_STATUS
+UsbMassInitTransport (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ OUT USB_MASS_TRANSPORT **Transport,
+ OUT VOID **Context,
+ OUT UINT8 *MaxLun
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the
+ // matching transport protocol.
+ // If not found, return EFI_UNSUPPORTED.
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
+ //
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
+ *Transport = mUsbMassTransport[Index];
+
+ if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
+ Status = (*Transport)->Init (UsbIo, Context);
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // For BOT device, try to get its max LUN.
+ // If max LUN is 0, then it is a non-lun device.
+ // Otherwise, it is a multi-lun device.
+ //
+ if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
+ (*Transport)->GetMaxLun (*Context, MaxLun);
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+/**
+ Initialize data for device that supports multiple LUNSs.
+
+ @param This The Driver Binding Protocol instance.
+ @param Controller The device to initialize.
+ @param Transport Pointer to USB_MASS_TRANSPORT.
+ @param Context Parameter for USB_MASS_DEVICE.Context.
+ @param DevicePath The remaining device path.
+ @param MaxLun The max LUN number.
+
+ @retval EFI_SUCCESS At least one LUN is initialized successfully.
+ @retval EFI_NOT_FOUND Fail to initialize any of multiple LUNs.
+
+**/
+EFI_STATUS
+UsbMassInitMultiLun (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN USB_MASS_TRANSPORT *Transport,
+ IN VOID *Context,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT8 MaxLun
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
+ UINT8 Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ ASSERT (MaxLun > 0);
+ ReturnStatus = EFI_NOT_FOUND;
+
+ for (Index = 0; Index <= MaxLun; Index++) {
+
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
+
+ UsbIo = NULL;
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
+ ASSERT (UsbMass != NULL);
+
+ UsbMass->Signature = USB_MASS_SIGNATURE;
+ UsbMass->UsbIo = UsbIo;
+ UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
+ UsbMass->BlockIo.Reset = UsbMassReset;
+ UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
+ UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
+ UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
+ UsbMass->OpticalStorage = FALSE;
+ UsbMass->Transport = Transport;
+ UsbMass->Context = Context;
+ UsbMass->Lun = Index;
+
+ //
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+ //
+ Status = UsbMassInitMedia (UsbMass);
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
+ FreePool (UsbMass);
+ continue;
+ }
+
+ //
+ // Create a device path node for device logic unit, and append it.
+ //
+ LunNode.Header.Type = MESSAGING_DEVICE_PATH;
+ LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
+ LunNode.Lun = UsbMass->Lun;
+
+ SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
+
+ UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
+
+ if (UsbMass->DevicePath == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ FreePool (UsbMass);
+ continue;
+ }
+
+ InitializeDiskInfo (UsbMass);
+
+ //
+ // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &UsbMass->Controller,
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
+ FreePool (UsbMass->DevicePath);
+ FreePool (UsbMass);
+ continue;
+ }
+
+ //
+ // Open USB I/O Protocol by child to setup a parent-child relationship.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ UsbMass->Controller,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
+ gBS->UninstallMultipleProtocolInterfaces (
+ UsbMass->Controller,
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ FreePool (UsbMass->DevicePath);
+ FreePool (UsbMass);
+ continue;
+ }
+ ReturnStatus = EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Initialize data for device that does not support multiple LUNSs.
+
+ @param This The Driver Binding Protocol instance.
+ @param Controller The device to initialize.
+ @param Transport Pointer to USB_MASS_TRANSPORT.
+ @param Context Parameter for USB_MASS_DEVICE.Context.
+
+ @retval EFI_SUCCESS Initialization succeeds.
+ @retval Other Initialization fails.
+
+**/
+EFI_STATUS
+UsbMassInitNonLun (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN USB_MASS_TRANSPORT *Transport,
+ IN VOID *Context
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_STATUS Status;
+
+ UsbIo = NULL;
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
+ ASSERT (UsbMass != NULL);
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ UsbMass->Signature = USB_MASS_SIGNATURE;
+ UsbMass->Controller = Controller;
+ UsbMass->UsbIo = UsbIo;
+ UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
+ UsbMass->BlockIo.Reset = UsbMassReset;
+ UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
+ UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
+ UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
+ UsbMass->OpticalStorage = FALSE;
+ UsbMass->Transport = Transport;
+ UsbMass->Context = Context;
+
+ //
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+ //
+ Status = UsbMassInitMedia (UsbMass);
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ InitializeDiskInfo (UsbMass);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ if (UsbMass != NULL) {
+ FreePool (UsbMass);
+ }
+ if (UsbIo != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+
+/**
+ Check whether the controller is a supported USB mass storage.
+
+ @param This The USB mass storage 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the interface descriptor to check the USB class and find a transport
+ // protocol handler.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the
+ // matching transport method.
+ // If not found, return EFI_UNSUPPORTED.
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
+ //
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
+ Transport = mUsbMassTransport[Index];
+ if (Interface.InterfaceProtocol == Transport->Protocol) {
+ Status = Transport->Init (UsbIo, NULL);
+ break;
+ }
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the USB mass storage device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mass storage device,
+ installs Block I/O Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mass storage device.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The USB mass storage device to start on
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ USB_MASS_TRANSPORT *Transport;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ VOID *Context;
+ UINT8 MaxLun;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Transport = NULL;
+ Context = NULL;
+ MaxLun = 0;
+
+ Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
+ goto Exit;
+ }
+ if (MaxLun == 0) {
+ //
+ // Initialize data for device that does not support multiple LUNSs.
+ //
+ Status = UsbMassInitNonLun (This, Controller, Transport, Context);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
+ }
+ } else {
+ //
+ // Open device path to prepare for appending Device Logic Unit node.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ goto Exit;
+ }
+
+ //
+ // Initialize data for device that supports multiple LUNs.
+ // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
+ //
+ Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
+ }
+ }
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Stop controlling the device.
+
+ @param This The USB mass storage driver binding
+ @param Controller The device controller controlled by the driver.
+ @param NumberOfChildren The number of children of this device
+ @param ChildHandleBuffer The buffer of children handle.
+
+ @retval EFI_SUCCESS The driver stopped from controlling the device.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
+ @retval Others Failed to stop the driver
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ USB_MASS_DEVICE *UsbMass;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+
+ //
+ // This is a bus driver stop function since multi-lun is supported.
+ // There are three kinds of device handles that might be passed:
+ // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
+ // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
+ // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // A handle without any children, might be 1st and 2nd type.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ //
+ // This is a 2nd type handle(multi-lun root), it needs to close devicepath
+ // and usbio protocol.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is a 1st type handle(non-multi-lun), which only needs to uninstall
+ // Block I/O Protocol, close USB I/O Protocol and free mass device.
+ //
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
+
+ //
+ // Uninstall Block I/O protocol from the device handle,
+ // then call the transport protocol to stop itself.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ UsbMass->Transport->CleanUp (UsbMass->Context);
+ FreePool (UsbMass);
+
+ DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is a 3rd type handle(multi-lun), which needs uninstall
+ // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
+ // free mass device for all children.
+ //
+ 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)) {
+ AllChildrenStopped = FALSE;
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
+ continue;
+ }
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
+ //
+ AllChildrenStopped = FALSE;
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ //
+ // Succeed to stop this multi-lun handle, so go on with next child.
+ //
+ if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
+ UsbMass->Transport->CleanUp (UsbMass->Context);
+ }
+ FreePool (UsbMass);
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
+ return EFI_SUCCESS;
+}
+
+/**
+ Entrypoint of USB Mass Storage Driver.
+
+ This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
+ Protocol 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
+USBMassStorageEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver binding protocol
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUSBMassDriverBinding,
+ ImageHandle,
+ &gUsbMassStorageComponentName,
+ &gUsbMassStorageComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h
new file mode 100644
index 000000000..283bed705
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h
@@ -0,0 +1,327 @@
+/** @file
+ Definitions of functions for Driver Binding Protocol and Block I/O Protocol,
+ and other internal definitions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_IMPL_H_
+#define _EFI_USBMASS_IMPL_H_
+
+#define USB_MASS_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'M')
+
+#define USB_MASS_DEVICE_FROM_BLOCK_IO(a) \
+ CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE)
+
+#define USB_MASS_DEVICE_FROM_DISK_INFO(a) \
+ CR (a, USB_MASS_DEVICE, DiskInfo, USB_MASS_SIGNATURE)
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2;
+
+//
+// Functions for Driver Binding Protocol
+//
+
+/**
+ Check whether the controller is a supported USB mass storage.
+
+ @param This The USB mass storage 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the USB mass storage device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mass storage device,
+ installs Block I/O Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mass storage device.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The USB mass storage device to start on
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop controlling the device.
+
+ @param This The USB mass storage driver binding
+ @param Controller The device controller controlled by the driver.
+ @param NumberOfChildren The number of children of this device
+ @param ChildHandleBuffer The buffer of children handle.
+
+ @retval EFI_SUCCESS The driver stopped from controlling the device.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
+ @retval Others Failed to stop the driver
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Functions for Block I/O Protocol
+//
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to 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 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_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
+UsbMassReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @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.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer 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 cannot 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
+UsbMassWriteBlocks (
+ 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 device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
+ USB mass storage device doesn't support write cache,
+ so return EFI_SUCCESS directly.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+//
+// 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
+UsbMassStorageGetDriverName (
+ 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
+UsbMassStorageGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
new file mode 100644
index 000000000..54039389f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# USB Mass Storage Driver that manages USB mass storage devices and produces Block I/O Protocol.
+#
+# The USB mass storage class is specified in two layers: the bottom layer
+# is the transportation protocol. The top layer is the command set.
+# The transportation layer provides the transportation of the command, data and result.
+# The command set defines the command, data and result.
+# The Bulk-Only-Transport and Control/Bulk/Interrupt transport are two transportation protocol.
+# USB mass storage class adopts various industrial standard as its command set.
+# This module refers to following specifications:
+# 1. USB Mass Storage Specification for Bootability, Revision 1.0
+# 2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1
+# 3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+# 4. UEFI Specification, v2.1
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbMassStorageDxe
+ MODULE_UNI_FILE = UsbMassStorageDxe.uni
+ FILE_GUID = 9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = USBMassStorageEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUSBMassDriverBinding
+# COMPONENT_NAME = gUsbMassStorageComponentName
+# COMPONENT_NAME2 = gUsbMassStorageComponentName2
+#
+
+[Sources]
+ UsbMassBoot.h
+ UsbMassImpl.h
+ UsbMassBot.h
+ UsbMassBot.c
+ ComponentName.c
+ UsbMassImpl.c
+ UsbMassBoot.c
+ UsbMassCbi.h
+ UsbMass.h
+ UsbMassCbi.c
+ UsbMassDiskInfo.h
+ UsbMassDiskInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbMassStorageDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni
new file mode 100644
index 000000000..161395761
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni
@@ -0,0 +1,31 @@
+// /** @file
+// USB Mass Storage Driver that manages USB mass storage devices and produces Block I/O Protocol.
+//
+// The USB mass storage class is specified in two layers: the bottom layer
+// is the transportation protocol. The top layer is the command set.
+// The transportation layer provides the transportation of the command, data and result.
+// The command set defines the command, data and result.
+// The Bulk-Only-Transport and Control/Bulk/Interrupt transport are two transportation protocol.
+// USB mass storage class adopts various industrial standard as its command set.
+// This module refers to following specifications:
+// 1. USB Mass Storage Specification for Bootability, Revision 1.0
+// 2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1
+// 3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+// 4. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB mass storage devices and produces Block I/O Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The USB mass storage class is specified in two layers: the bottom layer is the transportation protocol. The top layer is the command set. The transportation layer provides the transportation of the command, data and result. The command set defines the command, data and result. The Bulk-Only-Transport and Control/Bulk/Interrupt transport are two transportation protocol. USB mass storage class adopts various industrial standard as its command set.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. USB Mass Storage Specification for Bootability, Revision 1.0<BR>\n"
+ "2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1<BR>\n"
+ "3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.<BR>\n"
+ "4. UEFI Specification, v2.1<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni
new file mode 100644
index 000000000..d5751e6b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbMassStorageDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Mass Storage DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/ComponentName.c
new file mode 100644
index 000000000..efad274fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for USB Mouse Absolute Pointer Driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "UsbMouseAbsolutePointer.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbMouseAbsolutePointerComponentName = {
+ UsbMouseAbsolutePointerComponentNameGetDriverName,
+ UsbMouseAbsolutePointerComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseAbsolutePointerComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbMouseAbsolutePointerComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbMouseAbsolutePointerComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbMouseAbsolutePointerDriverNameTable[] = {
+ { "eng;en", L"Usb Mouse Absolute Pointer 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
+UsbMouseAbsolutePointerComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbMouseAbsolutePointerDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbMouseAbsolutePointerComponentName)
+ );
+}
+
+/**
+ 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
+UsbMouseAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol;
+ EFI_USB_IO_PROTOCOL *UsbIoProtocol;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIoProtocol,
+ gUsbMouseAbsolutePointerDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ gUsbMouseAbsolutePointerDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointerProtocol,
+ gUsbMouseAbsolutePointerDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbMouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (AbsolutePointerProtocol);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ UsbMouseAbsolutePointerDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUsbMouseAbsolutePointerComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/MouseHid.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/MouseHid.c
new file mode 100644
index 000000000..10e18e58a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/MouseHid.c
@@ -0,0 +1,275 @@
+/** @file
+ Helper functions to parse HID report descriptor and items.
+
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMouseAbsolutePointer.h"
+
+
+/**
+ Get next HID item from report descriptor.
+
+ This function retrieves next HID item from report descriptor, according to
+ the start position.
+ According to USB HID Specification, An item is piece of information
+ about the device. All items have a one-byte prefix that contains
+ the item tag, item type, and item size.
+ There are two basic types of items: short items and long items.
+ If the item is a short item, its optional data size may be 0, 1, 2, or 4 bytes.
+ Only short item is supported here.
+
+ @param StartPos Start position of the HID item to get.
+ @param EndPos End position of the range to get the next HID item.
+ @param HidItem Buffer for the HID Item to return.
+
+ @return Pointer to end of the HID item returned.
+ NULL if no HID item retrieved.
+
+**/
+UINT8 *
+GetNextHidItem (
+ IN UINT8 *StartPos,
+ IN UINT8 *EndPos,
+ OUT HID_ITEM *HidItem
+ )
+{
+ UINT8 Temp;
+
+ if (EndPos <= StartPos) {
+ return NULL;
+ }
+
+ Temp = *StartPos;
+ StartPos++;
+
+ //
+ // Bit format of prefix byte:
+ // Bits 0-1: Size
+ // Bits 2-3: Type
+ // Bits 4-7: Tag
+ //
+ HidItem->Type = BitFieldRead8 (Temp, 2, 3);
+ HidItem->Tag = BitFieldRead8 (Temp, 4, 7);
+
+ if (HidItem->Tag == HID_ITEM_TAG_LONG) {
+ //
+ // Long Items are not supported, although we try to parse it.
+ //
+ HidItem->Format = HID_ITEM_FORMAT_LONG;
+
+ if ((EndPos - StartPos) >= 2) {
+ HidItem->Size = *StartPos++;
+ HidItem->Tag = *StartPos++;
+
+ if ((EndPos - StartPos) >= HidItem->Size) {
+ HidItem->Data.LongData = StartPos;
+ StartPos += HidItem->Size;
+ return StartPos;
+ }
+ }
+ } else {
+ HidItem->Format = HID_ITEM_FORMAT_SHORT;
+ HidItem->Size = BitFieldRead8 (Temp, 0, 1);
+
+ switch (HidItem->Size) {
+ case 0:
+ //
+ // No data
+ //
+ return StartPos;
+
+ case 1:
+ //
+ // 1-byte data
+ //
+ if ((EndPos - StartPos) >= 1) {
+ HidItem->Data.Uint8 = *StartPos++;
+ return StartPos;
+ }
+
+ case 2:
+ //
+ // 2-byte data
+ //
+ if ((EndPos - StartPos) >= 2) {
+ CopyMem (&HidItem->Data.Uint16, StartPos, sizeof (UINT16));
+ StartPos += 2;
+ return StartPos;
+ }
+
+ case 3:
+ //
+ // 4-byte data, adjust size
+ //
+ HidItem->Size = 4;
+ if ((EndPos - StartPos) >= 4) {
+ CopyMem (&HidItem->Data.Uint32, StartPos, sizeof (UINT32));
+ StartPos += 4;
+ return StartPos;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get data from HID item.
+
+ This function retrieves data from HID item.
+ It only supports short items, which has 4 types of data:
+ 0, 1, 2, or 4 bytes.
+
+ @param HidItem Pointer to the HID item.
+
+ @return The data of HID item.
+
+**/
+UINT32
+GetItemData (
+ IN HID_ITEM *HidItem
+ )
+{
+ //
+ // Get data from HID item.
+ //
+ switch (HidItem->Size) {
+ case 1:
+ return HidItem->Data.Uint8;
+ case 2:
+ return HidItem->Data.Uint16;
+ case 4:
+ return HidItem->Data.Uint32;
+ }
+ return 0;
+}
+
+/**
+ Parse HID item from report descriptor.
+
+ There are three item types: Main, Global, and Local.
+ This function parses these types of HID items according
+ to tag info.
+
+ @param UsbMouse The instance of USB_MOUSE_ABSOLUTE_POINTER_DEV
+ @param HidItem The HID item to parse
+
+**/
+VOID
+ParseHidItem (
+ IN USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouse,
+ IN HID_ITEM *HidItem
+ )
+{
+ UINT8 Data;
+
+ switch (HidItem->Type) {
+
+ case HID_ITEM_TYPE_MAIN:
+ //
+ // we don't care any main items, just skip
+ //
+ return ;
+
+ case HID_ITEM_TYPE_GLOBAL:
+ //
+ // For global items, we only care Usage Page tag for Button Page here
+ //
+ if (HidItem->Tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) {
+ Data = (UINT8) GetItemData (HidItem);
+ if (Data == 0x09) {
+ //
+ // Button Page
+ //
+ UsbMouse->PrivateData.ButtonDetected = TRUE;
+ }
+ }
+ return;
+
+ case HID_ITEM_TYPE_LOCAL:
+ if (HidItem->Size == 0) {
+ //
+ // No expected data for local item
+ //
+ return ;
+ }
+
+ Data = (UINT8) GetItemData (HidItem);
+
+ switch (HidItem->Tag) {
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ if (UsbMouse->PrivateData.ButtonDetected) {
+ UsbMouse->PrivateData.ButtonMinIndex = Data;
+ }
+ return ;
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ {
+ if (UsbMouse->PrivateData.ButtonDetected) {
+ UsbMouse->PrivateData.ButtonMaxIndex = Data;
+ }
+ return ;
+ }
+
+ default:
+ return ;
+ }
+ }
+}
+
+
+/**
+ Parse Mouse Report Descriptor.
+
+ According to USB HID Specification, report descriptors are
+ composed of pieces of information. Each piece of information
+ is called an Item. This function retrieves each item from
+ the report descriptor and updates USB_MOUSE_ABSOLUTE_POINTER_DEV.
+
+ @param UsbMouseAbsolutePointer The instance of USB_MOUSE_ABSOLUTE_POINTER_DEV
+ @param ReportDescriptor Report descriptor to parse
+ @param ReportSize Report descriptor size
+
+ @retval EFI_SUCCESS Report descriptor successfully parsed.
+ @retval EFI_UNSUPPORTED Report descriptor contains long item.
+
+**/
+EFI_STATUS
+ParseMouseReportDescriptor (
+ OUT USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointer,
+ IN UINT8 *ReportDescriptor,
+ IN UINTN ReportSize
+ )
+{
+ UINT8 *DescriptorEnd;
+ UINT8 *Ptr;
+ HID_ITEM HidItem;
+
+ DescriptorEnd = ReportDescriptor + ReportSize;
+
+ Ptr = GetNextHidItem (ReportDescriptor, DescriptorEnd, &HidItem);
+ while (Ptr != NULL) {
+ if (HidItem.Format != HID_ITEM_FORMAT_SHORT) {
+ //
+ // Long Item is not supported at current HID revision
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ ParseHidItem (UsbMouseAbsolutePointer, &HidItem);
+
+ Ptr = GetNextHidItem (Ptr, DescriptorEnd, &HidItem);
+ }
+
+ UsbMouseAbsolutePointer->NumberOfButtons = (UINT8) (UsbMouseAbsolutePointer->PrivateData.ButtonMaxIndex - UsbMouseAbsolutePointer->PrivateData.ButtonMinIndex + 1);
+ UsbMouseAbsolutePointer->XLogicMax = 1023;
+ UsbMouseAbsolutePointer->YLogicMax = 1023;
+ UsbMouseAbsolutePointer->XLogicMin = -1023;
+ UsbMouseAbsolutePointer->YLogicMin = -1023;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c
new file mode 100644
index 000000000..926e03f9c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.c
@@ -0,0 +1,1018 @@
+/** @file
+ USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMouseAbsolutePointer.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbMouseAbsolutePointerDriverBinding = {
+ USBMouseAbsolutePointerDriverBindingSupported,
+ USBMouseAbsolutePointerDriverBindingStart,
+ USBMouseAbsolutePointerDriverBindingStop,
+ 0x1,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of USB Mouse Absolute Pointer Driver.
+
+ This function is the entrypoint of USB Mouse 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
+USBMouseAbsolutePointerDriverBindingEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUsbMouseAbsolutePointerDriverBinding,
+ ImageHandle,
+ &gUsbMouseAbsolutePointerComponentName,
+ &gUsbMouseAbsolutePointerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether USB Mouse Absolute Pointer 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Use the USB I/O Protocol interface to check whether Controller is
+ // a mouse device that can be managed by this driver.
+ //
+ Status = EFI_SUCCESS;
+ if (!IsUsbMouse (UsbIo)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Starts the mouse device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mouse device,
+ installs Absolute Pointer Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mouse device.
+
+ @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 This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ UINT8 Index;
+ UINT8 EndpointAddr;
+ UINT8 PollingInterval;
+ UINT8 PacketSize;
+ BOOLEAN Found;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Open USB I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ UsbMouseAbsolutePointerDevice = AllocateZeroPool (sizeof (USB_MOUSE_ABSOLUTE_POINTER_DEV));
+ ASSERT (UsbMouseAbsolutePointerDevice != NULL);
+
+ UsbMouseAbsolutePointerDevice->UsbIo = UsbIo;
+ UsbMouseAbsolutePointerDevice->Signature = USB_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE;
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbMouseAbsolutePointerDevice->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse will be detected next.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &UsbMouseAbsolutePointerDevice->InterfaceDescriptor
+ );
+
+ EndpointNumber = UsbMouseAbsolutePointerDevice->InterfaceDescriptor.NumEndpoints;
+
+ //
+ // Traverse endpoints to find interrupt endpoint IN
+ //
+ Found = FALSE;
+ for (Index = 0; Index < EndpointNumber; Index++) {
+ UsbIo->UsbGetEndpointDescriptor (
+ UsbIo,
+ Index,
+ &EndpointDescriptor
+ );
+
+ if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
+ ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
+ //
+ // We only care interrupt endpoint here
+ //
+ CopyMem (&UsbMouseAbsolutePointerDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ //
+ // Report Status Code to indicate that there is no USB mouse
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED)
+ );
+ //
+ // No interrupt endpoint found, then return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse has be detected.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ Status = InitializeUsbMouseDevice (UsbMouseAbsolutePointerDevice);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to initialize USB mouse device.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize and install EFI Absolute Pointer Protocol.
+ //
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.GetState = GetMouseAbsolutePointerState;
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Reset = UsbMouseAbsolutePointerReset;
+ UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Mode = &UsbMouseAbsolutePointerDevice->Mode;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ UsbMouseAbsolutePointerWaitForInput,
+ UsbMouseAbsolutePointerDevice,
+ &((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device.
+ // After that we will be able to get key data from it. Thus this is deemed as
+ // the enable action of the mouse, so report status code accordingly.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Submit Asynchronous Interrupt Transfer to manage this device.
+ //
+ EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
+ PollingInterval = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval;
+ PacketSize = (UINT8) (UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.MaxPacketSize);
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EndpointAddr,
+ TRUE,
+ PollingInterval,
+ PacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseAbsolutePointerDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If submit error, uninstall that interface
+ //
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+ goto ErrorExit;
+ }
+
+ UsbMouseAbsolutePointerDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gUsbMouseAbsolutePointerComponentName.SupportedLanguages,
+ &UsbMouseAbsolutePointerDevice->ControllerNameTable,
+ L"Generic Usb Mouse Absolute Pointer",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gUsbMouseAbsolutePointerComponentName2.SupportedLanguages,
+ &UsbMouseAbsolutePointerDevice->ControllerNameTable,
+ L"Generic Usb Mouse Absolute Pointer",
+ FALSE
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+//
+// Error handler
+//
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (UsbMouseAbsolutePointerDevice != NULL) {
+ if ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput != NULL) {
+ gBS->CloseEvent ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput);
+ }
+
+ FreePool (UsbMouseAbsolutePointerDevice);
+ UsbMouseAbsolutePointerDevice = NULL;
+ }
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Stop the USB mouse 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_UNSUPPORTED Absolute Pointer Protocol is not installed on Controller.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointerProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (AbsolutePointerProtocol);
+
+ UsbIo = UsbMouseAbsolutePointerDevice->UsbIo;
+
+ //
+ // The key data input from this device will be disabled.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Delete the Asynchronous Interrupt Transfer from this device
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval,
+ 0,
+ NULL,
+ NULL
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free all resources.
+ //
+ gBS->CloseEvent (UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.WaitForInput);
+
+ if (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent);
+ UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent = NULL;
+ }
+
+ if (UsbMouseAbsolutePointerDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (UsbMouseAbsolutePointerDevice->ControllerNameTable);
+ }
+
+ FreePool (UsbMouseAbsolutePointerDevice);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Uses USB I/O to check whether the device is a USB mouse device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB mouse device.
+ @retval FALSE Device is a not USB mouse device.
+
+**/
+BOOLEAN
+IsUsbMouse (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ //
+ // Get the default interface descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &InterfaceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) &&
+ (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) &&
+ (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE)
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Initialize the USB mouse device.
+
+ This function retrieves and parses HID report descriptor, and
+ initializes state of USB_MOUSE_ABSOLUTE_POINTER_DEV. Then it sets indefinite idle
+ rate for the device. Finally it creates event for delayed recovery,
+ which deals with device error.
+
+ @param UsbMouseAbsolutePointerDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB mouse device successfully initialized.
+ @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor.
+ @retval Other USB mouse device was not initialized successfully.
+
+**/
+EFI_STATUS
+InitializeUsbMouseDevice (
+ IN USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 Protocol;
+ EFI_STATUS Status;
+ EFI_USB_HID_DESCRIPTOR *MouseHidDesc;
+ UINT8 *ReportDesc;
+ EFI_USB_CONFIG_DESCRIPTOR ConfigDesc;
+ VOID *Buf;
+ UINT32 TransferResult;
+ UINT16 Total;
+ USB_DESC_HEAD *Head;
+ BOOLEAN Start;
+
+ UsbIo = UsbMouseAbsolutePointerDev->UsbIo;
+
+ //
+ // Get the current configuration descriptor. Note that it doesn't include other descriptors.
+ //
+ Status = UsbIo->UsbGetConfigDescriptor (
+ UsbIo,
+ &ConfigDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor,
+ // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
+ //
+ Buf = AllocateZeroPool (ConfigDesc.TotalLength);
+ if (Buf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UsbGetDescriptor (
+ UsbIo,
+ (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)),
+ 0,
+ ConfigDesc.TotalLength,
+ Buf,
+ &TransferResult
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ return Status;
+ }
+
+ Total = 0;
+ Start = FALSE;
+ Head = (USB_DESC_HEAD *)Buf;
+ MouseHidDesc = NULL;
+
+ //
+ // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request.
+ // This algorithm is based on the fact that the HID descriptor shall be interleaved
+ // between the interface and endpoint descriptors for HID interfaces.
+ //
+ while (Total < ConfigDesc.TotalLength) {
+ if (Head->Type == USB_DESC_TYPE_INTERFACE) {
+ if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber) &&
+ (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseAbsolutePointerDev->InterfaceDescriptor.AlternateSetting)) {
+ Start = TRUE;
+ }
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) {
+ break;
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_HID)) {
+ MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head;
+ break;
+ }
+ Total = Total + (UINT16)Head->Len;
+ Head = (USB_DESC_HEAD*)((UINT8 *)Buf + Total);
+ }
+
+ if (MouseHidDesc == NULL) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get report descriptor
+ //
+ if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength);
+ ASSERT (ReportDesc != NULL);
+
+ Status = UsbGetReportDescriptor (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength,
+ ReportDesc
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ //
+ // Parse report descriptor
+ //
+ Status = ParseMouseReportDescriptor (
+ UsbMouseAbsolutePointerDev,
+ ReportDesc,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX = 1024;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY = 1024;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxZ = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY = 0;
+ UsbMouseAbsolutePointerDev->Mode.AbsoluteMinZ = 0;
+ UsbMouseAbsolutePointerDev->Mode.Attributes = 0x3;
+
+ //
+ // Let the cursor's starting position is in the center of the screen.
+ //
+ UsbMouseAbsolutePointerDev->State.CurrentX =
+ DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX, 2);
+ UsbMouseAbsolutePointerDev->State.CurrentY =
+ DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY, 2);
+
+ //
+ // Set boot protocol for the USB mouse.
+ // This driver only supports boot protocol.
+ //
+ UsbGetProtocolRequest (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ &Protocol
+ );
+ if (Protocol != BOOT_PROTOCOL) {
+ Status = UsbSetProtocolRequest (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
+ BOOT_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+ }
+
+ FreePool (Buf);
+ FreePool (ReportDesc);
+
+ //
+ // Create event for delayed recovery, which deals with device error.
+ //
+ if (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent);
+ UsbMouseAbsolutePointerDev->DelayedRecoveryEvent = 0;
+ }
+
+ gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ USBMouseRecoveryHandler,
+ UsbMouseAbsolutePointerDev,
+ &UsbMouseAbsolutePointerDev->DelayedRecoveryEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Handler function for USB mouse's asynchronous interrupt transfer.
+
+ This function is the handler function for USB mouse's asynchronous interrupt transfer
+ to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
+ get button and movement state.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+OnMouseInterruptComplete (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 EndpointAddr;
+ UINT32 UsbResult;
+
+ UsbMouseAbsolutePointerDevice = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+ UsbIo = UsbMouseAbsolutePointerDevice->UsbIo;
+
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // Some errors happen during the process
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
+ EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
+
+ UsbClearEndpointHalt (
+ UsbIo,
+ EndpointAddr,
+ &UsbResult
+ );
+ }
+
+ //
+ // Delete & Submit this interrupt again
+ // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ //
+ // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
+ //
+ gBS->SetTimer (
+ UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent,
+ TimerRelative,
+ EFI_USB_INTERRUPT_DELAY
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If no error and no data, just return EFI_SUCCESS.
+ //
+ if (DataLength == 0 || Data == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check mouse Data
+ // USB HID Specification specifies following data format:
+ // Byte Bits Description
+ // 0 0 Button 1
+ // 1 Button 2
+ // 2 Button 3
+ // 4 to 7 Device-specific
+ // 1 0 to 7 X displacement
+ // 2 0 to 7 Y displacement
+ // 3 to n 0 to 7 Device specific (optional)
+ //
+ if (DataLength < 3) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ UsbMouseAbsolutePointerDevice->StateChanged = TRUE;
+
+ UsbMouseAbsolutePointerDevice->State.ActiveButtons = *(UINT8 *) Data & (BIT0 | BIT1 | BIT2);
+
+ UsbMouseAbsolutePointerDevice->State.CurrentX =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentX + *((INT8 *) Data + 1),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX
+ );
+ UsbMouseAbsolutePointerDevice->State.CurrentY =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentY + *((INT8 *) Data + 2),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY
+ );
+ if (DataLength > 3) {
+ UsbMouseAbsolutePointerDevice->State.CurrentZ =
+ MIN (
+ MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentZ + *((INT8 *) Data + 1),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinZ),
+ (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxZ
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @param MouseState A pointer to the state information on the pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in State.
+ @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to
+ GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's
+ current state.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMouseAbsolutePointerState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ OUT EFI_ABSOLUTE_POINTER_STATE *State
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ if (!MouseAbsolutePointerDev->StateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Retrieve mouse state from USB_MOUSE_ABSOLUTE_POINTER_DEV,
+ // which was filled by OnMouseInterruptComplete()
+ //
+ CopyMem (
+ State,
+ &MouseAbsolutePointerDev->State,
+ sizeof (EFI_ABSOLUTE_POINTER_STATE)
+ );
+
+ MouseAbsolutePointerDev->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets the pointer device hardware.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMouseAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
+
+ UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
+ UsbMouseAbsolutePointerDevice->DevicePath
+ );
+
+ //
+ // Clear mouse state.
+ //
+ ZeroMem (
+ &UsbMouseAbsolutePointerDevice->State,
+ sizeof (EFI_ABSOLUTE_POINTER_STATE)
+ );
+
+ //
+ // Let the cursor's starting position is in the center of the screen.
+ //
+ UsbMouseAbsolutePointerDevice->State.CurrentX =
+ DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX, 2);
+ UsbMouseAbsolutePointerDevice->State.CurrentY =
+ DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY, 2);
+
+ UsbMouseAbsolutePointerDevice->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
+
+ @param Event Event to be signaled when there's input from mouse.
+ @param Context Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+UsbMouseAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
+
+ UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ //
+ // If there's input from mouse, signal the event.
+ //
+ if (UsbMouseAbsolutePointerDev->StateChanged) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBMouseRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ UsbIo = UsbMouseAbsolutePointerDev->UsbIo;
+
+ //
+ // Re-submit Asynchronous Interrupt Transfer for recovery.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.EndpointAddress,
+ TRUE,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.Interval,
+ UsbMouseAbsolutePointerDev->IntEndpointDescriptor.MaxPacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseAbsolutePointerDev
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.h
new file mode 100644
index 000000000..c9edc45e3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointer.h
@@ -0,0 +1,465 @@
+/** @file
+ Helper routine and corresponding data struct used by USB Mouse Absolute Pointer Driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_MOUSE_ABSOLUTE_POINTER_H_
+#define _USB_MOUSE_ABSOLUTE_POINTER_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/AbsolutePointer.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+#define CLASS_HID 3
+#define SUBCLASS_BOOT 1
+#define PROTOCOL_MOUSE 2
+
+#define BOOT_PROTOCOL 0
+#define REPORT_PROTOCOL 1
+
+#define USB_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE SIGNATURE_32 ('u', 'm', 's', 't')
+
+//
+// A common header for usb standard descriptor.
+// Each stand descriptor has a length and type.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Len;
+ UINT8 Type;
+} USB_DESC_HEAD;
+#pragma pack()
+
+///
+/// Button range and status
+///
+typedef struct {
+ BOOLEAN ButtonDetected;
+ UINT8 ButtonMinIndex;
+ UINT8 ButtonMaxIndex;
+ UINT8 Reserved;
+} USB_MOUSE_BUTTON_DATA;
+
+///
+/// Device instance of USB mouse.
+///
+typedef struct {
+ UINTN Signature;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_EVENT DelayedRecoveryEvent;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor;
+ UINT8 NumberOfButtons;
+ INT32 XLogicMax;
+ INT32 XLogicMin;
+ INT32 YLogicMax;
+ INT32 YLogicMin;
+ EFI_ABSOLUTE_POINTER_PROTOCOL AbsolutePointerProtocol;
+ EFI_ABSOLUTE_POINTER_STATE State;
+ EFI_ABSOLUTE_POINTER_MODE Mode;
+ BOOLEAN StateChanged;
+ USB_MOUSE_BUTTON_DATA PrivateData;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+} USB_MOUSE_ABSOLUTE_POINTER_DEV;
+
+///
+/// General HID Item structure
+///
+
+typedef union {
+ UINT8 Uint8;
+ UINT16 Uint16;
+ UINT32 Uint32;
+ INT8 Int8;
+ INT16 Int16;
+ INT32 Int32;
+ UINT8 *LongData;
+} HID_DATA;
+
+typedef struct {
+ UINT16 Format;
+ UINT8 Size;
+ UINT8 Type;
+ UINT8 Tag;
+ HID_DATA Data;
+} HID_ITEM;
+
+#define USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL(a) \
+ CR(a, USB_MOUSE_ABSOLUTE_POINTER_DEV, AbsolutePointerProtocol, USB_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gUsbMouseAbsolutePointerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbMouseAbsolutePointerComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseAbsolutePointerComponentName2;
+
+//
+// Functions of Driver Binding Protocol
+//
+
+/**
+ Check whether USB Mouse Absolute Pointer 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the mouse device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mouse device,
+ installs Absolute Pointer Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mouse device.
+
+ @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 This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the USB mouse 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_UNSUPPORTED Absolute Pointer Protocol is not installed on Controller.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseAbsolutePointerDriverBindingStop (
+ 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
+UsbMouseAbsolutePointerComponentNameGetDriverName (
+ 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
+UsbMouseAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// Functions of EFI_ABSOLUTE_POINTER_PROTOCOL
+//
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @param MouseState A pointer to the state information on the pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in State.
+ @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to
+ GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's
+ current state.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMouseAbsolutePointerState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ OUT EFI_ABSOLUTE_POINTER_STATE *State
+ );
+
+/**
+ Resets the pointer device hardware.
+
+ @param This A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMouseAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
+
+ @param Event Event to be signaled when there's input from mouse.
+ @param Context Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+UsbMouseAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Internal worker functions
+//
+
+/**
+ Uses USB I/O to check whether the device is a USB mouse device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB mouse device.
+ @retval FALSE Device is a not USB mouse device.
+
+**/
+BOOLEAN
+IsUsbMouse (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ );
+
+/**
+ Initialize the USB mouse device.
+
+ This function retrieves and parses HID report descriptor, and
+ initializes state of USB_MOUSE_ABSOLUTE_POINTER_DEV. Then it sets indefinite idle
+ rate for the device. Finally it creates event for delayed recovery,
+ which deals with device error.
+
+ @param UsbMouseAbsolutePointerDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB mouse device successfully initialized.
+ @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor.
+ @retval Other USB mouse device was not initialized successfully.
+
+**/
+EFI_STATUS
+InitializeUsbMouseDevice (
+ IN USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev
+ );
+
+/**
+ Handler function for USB mouse's asynchronous interrupt transfer.
+
+ This function is the handler function for USB mouse's asynchronous interrupt transfer
+ to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
+ get button and movement state.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+OnMouseInterruptComplete (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ );
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBMouseRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Parse Mouse Report Descriptor.
+
+ According to USB HID Specification, report descriptors are
+ composed of pieces of information. Each piece of information
+ is called an Item. This function retrieves each item from
+ the report descriptor and updates USB_MOUSE_ABSOLUTE_POINTER_DEV.
+
+ @param UsbMouseAbsolutePointer The instance of USB_MOUSE_ABSOLUTE_POINTER_DEV
+ @param ReportDescriptor Report descriptor to parse
+ @param ReportSize Report descriptor size
+
+ @retval EFI_SUCCESS Report descriptor successfully parsed.
+ @retval EFI_UNSUPPORTED Report descriptor contains long item.
+
+**/
+EFI_STATUS
+ParseMouseReportDescriptor (
+ OUT USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointer,
+ IN UINT8 *ReportDescriptor,
+ IN UINTN ReportSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf
new file mode 100644
index 000000000..00e061f56
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf
@@ -0,0 +1,66 @@
+## @file
+# USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
+#
+# USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+# Absolute Pointer Protocol on USB mouse devices.
+# It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+# and parses the data according to USB HID Specification.
+# This module refers to following specifications:
+# 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+# 2. UEFI Specification, v2.1
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbMouseAbsolutePointerDxe
+ MODULE_UNI_FILE = UsbMouseAbsolutePointerDxe.uni
+ FILE_GUID = 4EA43463-747C-46eb-97FB-B0E5C5F05306
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = USBMouseAbsolutePointerDriverBindingEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUsbMouseAbsolutePointerDriverBinding
+# COMPONENT_NAME = gUsbMouseAbsolutePointerComponentName
+# COMPONENT_NAME2 = gUsbMouseAbsolutePointerComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ MouseHid.c
+ UsbMouseAbsolutePointer.c
+ UsbMouseAbsolutePointer.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ ReportStatusCodeLib
+ UefiUsbLib
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiAbsolutePointerProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbMouseAbsolutePointerDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.uni
new file mode 100644
index 000000000..457693b15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.uni
@@ -0,0 +1,25 @@
+// /** @file
+// USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
+//
+// USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+// Absolute Pointer Protocol on USB mouse devices.
+// It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+// and parses the data according to USB HID Specification.
+// This module refers to following specifications:
+// 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+// 2. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB mouse and produces Absolute Pointer Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces Absolute Pointer Protocol on USB mouse devices. It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol, and parses the data according to USB HID Specification.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. Universal Serial Bus HID Firmware Specification, ver 1.11<BR>\n"
+ "2. UEFI Specification, v2.1<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxeExtra.uni
new file mode 100644
index 000000000..c34412c46
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbMouseAbsolutePointerDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Tablet Pointer DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c
new file mode 100644
index 000000000..7f4b3e821
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/ComponentName.c
@@ -0,0 +1,218 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for USB Mouse driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "UsbMouse.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName = {
+ UsbMouseComponentNameGetDriverName,
+ UsbMouseComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbMouseComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbMouseComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbMouseDriverNameTable[] = {
+ { "eng;en", L"Usb 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 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
+UsbMouseComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbMouseDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbMouseComponentName)
+ );
+}
+
+/**
+ 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
+UsbMouseComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB_MOUSE_DEV *UsbMouseDev;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
+ EFI_USB_IO_PROTOCOL *UsbIoProtocol;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIoProtocol,
+ gUsbMouseDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ gUsbMouseDriverBinding.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointerProtocol,
+ gUsbMouseDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbMouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ UsbMouseDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gUsbMouseComponentName)
+ );
+
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c
new file mode 100644
index 000000000..2b6d86030
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/MouseHid.c
@@ -0,0 +1,275 @@
+/** @file
+ Helper functions to parse HID report descriptor and items.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMouse.h"
+
+
+/**
+ Get next HID item from report descriptor.
+
+ This function retrieves next HID item from report descriptor, according to
+ the start position.
+ According to USB HID Specification, An item is piece of information
+ about the device. All items have a one-byte prefix that contains
+ the item tag, item type, and item size.
+ There are two basic types of items: short items and long items.
+ If the item is a short item, its optional data size may be 0, 1, 2, or 4 bytes.
+ Only short item is supported here.
+
+ @param StartPos Start position of the HID item to get.
+ @param EndPos End position of the range to get the next HID item.
+ @param HidItem Buffer for the HID Item to return.
+
+ @return Pointer to end of the HID item returned.
+ NULL if no HID item retrieved.
+
+**/
+UINT8 *
+GetNextHidItem (
+ IN UINT8 *StartPos,
+ IN UINT8 *EndPos,
+ OUT HID_ITEM *HidItem
+ )
+{
+ UINT8 Temp;
+
+ if (EndPos <= StartPos) {
+ return NULL;
+ }
+
+ Temp = *StartPos;
+ StartPos++;
+
+ //
+ // Bit format of prefix byte:
+ // Bits 0-1: Size
+ // Bits 2-3: Type
+ // Bits 4-7: Tag
+ //
+ HidItem->Type = BitFieldRead8 (Temp, 2, 3);
+ HidItem->Tag = BitFieldRead8 (Temp, 4, 7);
+
+ if (HidItem->Tag == HID_ITEM_TAG_LONG) {
+ //
+ // Long Items are not supported, although we try to parse it.
+ //
+ HidItem->Format = HID_ITEM_FORMAT_LONG;
+
+ if ((EndPos - StartPos) >= 2) {
+ HidItem->Size = *StartPos++;
+ HidItem->Tag = *StartPos++;
+
+ if ((EndPos - StartPos) >= HidItem->Size) {
+ HidItem->Data.LongData = StartPos;
+ StartPos += HidItem->Size;
+ return StartPos;
+ }
+ }
+ } else {
+ HidItem->Format = HID_ITEM_FORMAT_SHORT;
+ HidItem->Size = BitFieldRead8 (Temp, 0, 1);
+
+ switch (HidItem->Size) {
+ case 0:
+ //
+ // No data
+ //
+ return StartPos;
+
+ case 1:
+ //
+ // 1-byte data
+ //
+ if ((EndPos - StartPos) >= 1) {
+ HidItem->Data.Uint8 = *StartPos++;
+ return StartPos;
+ }
+
+ case 2:
+ //
+ // 2-byte data
+ //
+ if ((EndPos - StartPos) >= 2) {
+ CopyMem (&HidItem->Data.Uint16, StartPos, sizeof (UINT16));
+ StartPos += 2;
+ return StartPos;
+ }
+
+ case 3:
+ //
+ // 4-byte data, adjust size
+ //
+ HidItem->Size = 4;
+ if ((EndPos - StartPos) >= 4) {
+ CopyMem (&HidItem->Data.Uint32, StartPos, sizeof (UINT32));
+ StartPos += 4;
+ return StartPos;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get data from HID item.
+
+ This function retrieves data from HID item.
+ It only supports short items, which has 4 types of data:
+ 0, 1, 2, or 4 bytes.
+
+ @param HidItem Pointer to the HID item.
+
+ @return The data of HID item.
+
+**/
+UINT32
+GetItemData (
+ IN HID_ITEM *HidItem
+ )
+{
+ //
+ // Get data from HID item.
+ //
+ switch (HidItem->Size) {
+ case 1:
+ return HidItem->Data.Uint8;
+ case 2:
+ return HidItem->Data.Uint16;
+ case 4:
+ return HidItem->Data.Uint32;
+ }
+ return 0;
+}
+
+/**
+ Parse HID item from report descriptor.
+
+ There are three item types: Main, Global, and Local.
+ This function parses these types of HID items according
+ to tag info.
+
+ @param UsbMouse The instance of USB_MOUSE_DEV
+ @param HidItem The HID item to parse
+
+**/
+VOID
+ParseHidItem (
+ IN USB_MOUSE_DEV *UsbMouse,
+ IN HID_ITEM *HidItem
+ )
+{
+ UINT8 Data;
+
+ switch (HidItem->Type) {
+
+ case HID_ITEM_TYPE_MAIN:
+ //
+ // we don't care any main items, just skip
+ //
+ return;
+
+ case HID_ITEM_TYPE_GLOBAL:
+ //
+ // For global items, we only care Usage Page tag for Button Page here
+ //
+ if (HidItem->Tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) {
+ Data = (UINT8) GetItemData (HidItem);
+ if (Data == 0x09) {
+ //
+ // Button Page
+ //
+ UsbMouse->PrivateData.ButtonDetected = TRUE;
+ }
+ }
+ return;
+
+ case HID_ITEM_TYPE_LOCAL:
+ if (HidItem->Size == 0) {
+ //
+ // No expected data for local item
+ //
+ return ;
+ }
+
+ Data = (UINT8) GetItemData (HidItem);
+
+ switch (HidItem->Tag) {
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ if (UsbMouse->PrivateData.ButtonDetected) {
+ UsbMouse->PrivateData.ButtonMinIndex = Data;
+ }
+ return ;
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ {
+ if (UsbMouse->PrivateData.ButtonDetected) {
+ UsbMouse->PrivateData.ButtonMaxIndex = Data;
+ }
+ return ;
+ }
+
+ default:
+ return;
+ }
+ }
+}
+
+
+/**
+ Parse Mouse Report Descriptor.
+
+ According to USB HID Specification, report descriptors are
+ composed of pieces of information. Each piece of information
+ is called an Item. This function retrieves each item from
+ the report descriptor and updates USB_MOUSE_DEV.
+
+ @param UsbMouse The instance of USB_MOUSE_DEV
+ @param ReportDescriptor Report descriptor to parse
+ @param ReportSize Report descriptor size
+
+ @retval EFI_SUCCESS Report descriptor successfully parsed.
+ @retval EFI_UNSUPPORTED Report descriptor contains long item.
+
+**/
+EFI_STATUS
+ParseMouseReportDescriptor (
+ OUT USB_MOUSE_DEV *UsbMouse,
+ IN UINT8 *ReportDescriptor,
+ IN UINTN ReportSize
+ )
+{
+ UINT8 *DescriptorEnd;
+ UINT8 *Ptr;
+ HID_ITEM HidItem;
+
+ DescriptorEnd = ReportDescriptor + ReportSize;
+
+ Ptr = GetNextHidItem (ReportDescriptor, DescriptorEnd, &HidItem);
+ while (Ptr != NULL) {
+ if (HidItem.Format != HID_ITEM_FORMAT_SHORT) {
+ //
+ // Long Item is not supported at current HID revision
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ ParseHidItem (UsbMouse, &HidItem);
+
+ Ptr = GetNextHidItem (Ptr, DescriptorEnd, &HidItem);
+ }
+
+ UsbMouse->NumberOfButtons = (UINT8) (UsbMouse->PrivateData.ButtonMaxIndex - UsbMouse->PrivateData.ButtonMinIndex + 1);
+ UsbMouse->XLogicMax = 127;
+ UsbMouse->YLogicMax = 127;
+ UsbMouse->XLogicMin = -127;
+ UsbMouse->YLogicMin = -127;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c
new file mode 100644
index 000000000..9861c32d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.c
@@ -0,0 +1,999 @@
+/** @file
+ USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMouse.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = {
+ USBMouseDriverBindingSupported,
+ USBMouseDriverBindingStart,
+ USBMouseDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of USB Mouse Driver.
+
+ This function is the entrypoint of USB Mouse 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
+USBMouseDriverBindingEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUsbMouseDriverBinding,
+ ImageHandle,
+ &gUsbMouseComponentName,
+ &gUsbMouseComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether USB mouse driver supports this device.
+
+ @param This The USB mouse 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Use the USB I/O Protocol interface to check whether Controller is
+ // a mouse device that can be managed by this driver.
+ //
+ Status = EFI_SUCCESS;
+ if (!IsUsbMouse (UsbIo)) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Starts the mouse device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mouse device,
+ installs Simple Pointer Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mouse device.
+
+ @param This The USB mouse 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 This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_MOUSE_DEV *UsbMouseDevice;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ UINT8 Index;
+ UINT8 EndpointAddr;
+ UINT8 PollingInterval;
+ UINT8 PacketSize;
+ BOOLEAN Found;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Open USB I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV));
+ ASSERT (UsbMouseDevice != NULL);
+
+ UsbMouseDevice->UsbIo = UsbIo;
+ UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE;
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbMouseDevice->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse will be detected next.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT),
+ UsbMouseDevice->DevicePath
+ );
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &UsbMouseDevice->InterfaceDescriptor
+ );
+
+ EndpointNumber = UsbMouseDevice->InterfaceDescriptor.NumEndpoints;
+
+ //
+ // Traverse endpoints to find interrupt endpoint IN
+ //
+ Found = FALSE;
+ for (Index = 0; Index < EndpointNumber; Index++) {
+ UsbIo->UsbGetEndpointDescriptor (
+ UsbIo,
+ Index,
+ &EndpointDescriptor
+ );
+
+ if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
+ ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
+ //
+ // We only care interrupt endpoint here
+ //
+ CopyMem(&UsbMouseDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ //
+ // Report Status Code to indicate that there is no USB mouse
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED)
+ );
+ //
+ // No interrupt endpoint found, then return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto ErrorExit;
+ }
+
+ //
+ // Report Status Code here since USB mouse has be detected.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED),
+ UsbMouseDevice->DevicePath
+ );
+
+ Status = InitializeUsbMouseDevice (UsbMouseDevice);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to initialize USB mouse device.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR),
+ UsbMouseDevice->DevicePath
+ );
+
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize and install EFI Simple Pointer Protocol.
+ //
+ UsbMouseDevice->SimplePointerProtocol.GetState = GetMouseState;
+ UsbMouseDevice->SimplePointerProtocol.Reset = UsbMouseReset;
+ UsbMouseDevice->SimplePointerProtocol.Mode = &UsbMouseDevice->Mode;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ UsbMouseWaitForInput,
+ UsbMouseDevice,
+ &((UsbMouseDevice->SimplePointerProtocol).WaitForInput)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiSimplePointerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbMouseDevice->SimplePointerProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device.
+ // After that we will be able to get key data from it. Thus this is deemed as
+ // the enable action of the mouse, so report status code accordingly.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE),
+ UsbMouseDevice->DevicePath
+ );
+
+ //
+ // Submit Asynchronous Interrupt Transfer to manage this device.
+ //
+ EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
+ PollingInterval = UsbMouseDevice->IntEndpointDescriptor.Interval;
+ PacketSize = (UINT8) (UsbMouseDevice->IntEndpointDescriptor.MaxPacketSize);
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EndpointAddr,
+ TRUE,
+ PollingInterval,
+ PacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If submit error, uninstall that interface
+ //
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimplePointerProtocolGuid,
+ &UsbMouseDevice->SimplePointerProtocol
+ );
+ goto ErrorExit;
+ }
+
+ UsbMouseDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gUsbMouseComponentName.SupportedLanguages,
+ &UsbMouseDevice->ControllerNameTable,
+ L"Generic Usb Mouse",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gUsbMouseComponentName2.SupportedLanguages,
+ &UsbMouseDevice->ControllerNameTable,
+ L"Generic Usb Mouse",
+ FALSE
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+//
+// Error handler
+//
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (UsbMouseDevice != NULL) {
+ if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) {
+ gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput);
+ }
+
+ FreePool (UsbMouseDevice);
+ UsbMouseDevice = NULL;
+ }
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Stop the USB mouse device handled by this driver.
+
+ @param This The USB mouse 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_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ USB_MOUSE_DEV *UsbMouseDevice;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointerProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol);
+
+ UsbIo = UsbMouseDevice->UsbIo;
+
+ //
+ // The key data input from this device will be disabled.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE),
+ UsbMouseDevice->DevicePath
+ );
+
+ //
+ // Delete the Asynchronous Interrupt Transfer from this device
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ UsbMouseDevice->IntEndpointDescriptor.Interval,
+ 0,
+ NULL,
+ NULL
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimplePointerProtocolGuid,
+ &UsbMouseDevice->SimplePointerProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free all resources.
+ //
+ gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput);
+
+ if (UsbMouseDevice->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent);
+ UsbMouseDevice->DelayedRecoveryEvent = NULL;
+ }
+
+ if (UsbMouseDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable);
+ }
+
+ FreePool (UsbMouseDevice);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Uses USB I/O to check whether the device is a USB mouse device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB mouse device.
+ @retval FALSE Device is a not USB mouse device.
+
+**/
+BOOLEAN
+IsUsbMouse (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+ //
+ // Get the default interface descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &InterfaceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) &&
+ (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) &&
+ (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE)
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Initialize the USB mouse device.
+
+ This function retrieves and parses HID report descriptor, and
+ initializes state of USB_MOUSE_DEV. Then it sets indefinite idle
+ rate for the device. Finally it creates event for delayed recovery,
+ which deals with device error.
+
+ @param UsbMouseDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB mouse device successfully initialized..
+ @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor.
+ @retval Other USB mouse device was not initialized successfully.
+
+**/
+EFI_STATUS
+InitializeUsbMouseDevice (
+ IN OUT USB_MOUSE_DEV *UsbMouseDev
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 Protocol;
+ EFI_STATUS Status;
+ EFI_USB_HID_DESCRIPTOR *MouseHidDesc;
+ UINT8 *ReportDesc;
+ EFI_USB_CONFIG_DESCRIPTOR ConfigDesc;
+ VOID *Buf;
+ UINT32 TransferResult;
+ UINT16 Total;
+ USB_DESC_HEAD *Head;
+ BOOLEAN Start;
+
+ UsbIo = UsbMouseDev->UsbIo;
+
+ //
+ // Get the current configuration descriptor. Note that it doesn't include other descriptors.
+ //
+ Status = UsbIo->UsbGetConfigDescriptor (
+ UsbIo,
+ &ConfigDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor,
+ // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
+ //
+ Buf = AllocateZeroPool (ConfigDesc.TotalLength);
+ if (Buf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UsbGetDescriptor (
+ UsbIo,
+ (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)),
+ 0,
+ ConfigDesc.TotalLength,
+ Buf,
+ &TransferResult
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ return Status;
+ }
+
+ Total = 0;
+ Start = FALSE;
+ Head = (USB_DESC_HEAD *)Buf;
+ MouseHidDesc = NULL;
+
+ //
+ // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request.
+ // This algorithm is based on the fact that the HID descriptor shall be interleaved
+ // between the interface and endpoint descriptors for HID interfaces.
+ //
+ while (Total < ConfigDesc.TotalLength) {
+ if (Head->Type == USB_DESC_TYPE_INTERFACE) {
+ if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseDev->InterfaceDescriptor.InterfaceNumber) &&
+ (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseDev->InterfaceDescriptor.AlternateSetting)) {
+ Start = TRUE;
+ }
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) {
+ break;
+ }
+ if (Start && (Head->Type == USB_DESC_TYPE_HID)) {
+ MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head;
+ break;
+ }
+ Total = Total + (UINT16)Head->Len;
+ Head = (USB_DESC_HEAD*)((UINT8 *)Buf + Total);
+ }
+
+ if (MouseHidDesc == NULL) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get report descriptor
+ //
+ if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) {
+ FreePool (Buf);
+ return EFI_UNSUPPORTED;
+ }
+
+ ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength);
+ ASSERT (ReportDesc != NULL);
+
+ Status = UsbGetReportDescriptor (
+ UsbIo,
+ UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength,
+ ReportDesc
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ //
+ // Parse report descriptor
+ //
+ Status = ParseMouseReportDescriptor (
+ UsbMouseDev,
+ ReportDesc,
+ MouseHidDesc->HidClassDesc[0].DescriptorLength
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+
+ //
+ // Check the presence of left and right buttons,
+ // and initialize fields of EFI_SIMPLE_POINTER_MODE.
+ //
+ if (UsbMouseDev->NumberOfButtons >= 1) {
+ UsbMouseDev->Mode.LeftButton = TRUE;
+ }
+ if (UsbMouseDev->NumberOfButtons > 1) {
+ UsbMouseDev->Mode.RightButton = TRUE;
+ }
+ UsbMouseDev->Mode.ResolutionX = 8;
+ UsbMouseDev->Mode.ResolutionY = 8;
+ UsbMouseDev->Mode.ResolutionZ = 0;
+
+ //
+ // Set boot protocol for the USB mouse.
+ // This driver only supports boot protocol.
+ //
+ UsbGetProtocolRequest (
+ UsbIo,
+ UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
+ &Protocol
+ );
+ if (Protocol != BOOT_PROTOCOL) {
+ Status = UsbSetProtocolRequest (
+ UsbIo,
+ UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
+ BOOT_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ FreePool (ReportDesc);
+ return Status;
+ }
+ }
+
+ FreePool (Buf);
+ FreePool (ReportDesc);
+
+ //
+ // Create event for delayed recovery, which deals with device error.
+ //
+ if (UsbMouseDev->DelayedRecoveryEvent != NULL) {
+ gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent);
+ UsbMouseDev->DelayedRecoveryEvent = 0;
+ }
+
+ gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ USBMouseRecoveryHandler,
+ UsbMouseDev,
+ &UsbMouseDev->DelayedRecoveryEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Handler function for USB mouse's asynchronous interrupt transfer.
+
+ This function is the handler function for USB mouse's asynchronous interrupt transfer
+ to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
+ get button and movement state.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+OnMouseInterruptComplete (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_MOUSE_DEV *UsbMouseDevice;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 EndpointAddr;
+ UINT32 UsbResult;
+
+ UsbMouseDevice = (USB_MOUSE_DEV *) Context;
+ UsbIo = UsbMouseDevice->UsbIo;
+
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // Some errors happen during the process
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
+ UsbMouseDevice->DevicePath
+ );
+
+ if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
+ EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
+
+ UsbClearEndpointHalt (
+ UsbIo,
+ EndpointAddr,
+ &UsbResult
+ );
+ }
+
+ //
+ // Delete & Submit this interrupt again
+ // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+ //
+ // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
+ //
+ gBS->SetTimer (
+ UsbMouseDevice->DelayedRecoveryEvent,
+ TimerRelative,
+ EFI_USB_INTERRUPT_DELAY
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If no error and no data, just return EFI_SUCCESS.
+ //
+ if (DataLength == 0 || Data == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check mouse Data
+ // USB HID Specification specifies following data format:
+ // Byte Bits Description
+ // 0 0 Button 1
+ // 1 Button 2
+ // 2 Button 3
+ // 4 to 7 Device-specific
+ // 1 0 to 7 X displacement
+ // 2 0 to 7 Y displacement
+ // 3 to n 0 to 7 Device specific (optional)
+ //
+ if (DataLength < 3) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ UsbMouseDevice->StateChanged = TRUE;
+
+ UsbMouseDevice->State.LeftButton = (BOOLEAN) ((*(UINT8 *) Data & BIT0) != 0);
+ UsbMouseDevice->State.RightButton = (BOOLEAN) ((*(UINT8 *) Data & BIT1) != 0);
+ UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1);
+ UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2);
+
+ if (DataLength > 3) {
+ UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
+ @param MouseState A pointer to the state information on the pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in State.
+ @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to
+ GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's
+ current state.
+ @retval EFI_INVALID_PARAMETER MouseState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMouseState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ OUT EFI_SIMPLE_POINTER_STATE *MouseState
+ )
+{
+ USB_MOUSE_DEV *MouseDev;
+
+ if (MouseState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ if (!MouseDev->StateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Retrieve mouse state from USB_MOUSE_DEV, which was filled by OnMouseInterruptComplete()
+ //
+ CopyMem (
+ MouseState,
+ &MouseDev->State,
+ sizeof (EFI_SIMPLE_POINTER_STATE)
+ );
+
+ //
+ // Clear previous move state
+ //
+ MouseDev->State.RelativeMovementX = 0;
+ MouseDev->State.RelativeMovementY = 0;
+ MouseDev->State.RelativeMovementZ = 0;
+
+ MouseDev->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets the pointer device hardware.
+
+ @param This A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMouseReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MOUSE_DEV *UsbMouseDevice;
+
+ UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
+ UsbMouseDevice->DevicePath
+ );
+
+ //
+ // Clear mouse state.
+ //
+ ZeroMem (
+ &UsbMouseDevice->State,
+ sizeof (EFI_SIMPLE_POINTER_STATE)
+ );
+ UsbMouseDevice->StateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Event notification function for EFI_SIMPLE_POINTER_PROTOCOL.WaitForInput event.
+
+ @param Event Event to be signaled when there's input from mouse.
+ @param Context Points to USB_MOUSE_DEV instance.
+
+**/
+VOID
+EFIAPI
+UsbMouseWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_DEV *UsbMouseDev;
+
+ UsbMouseDev = (USB_MOUSE_DEV *) Context;
+
+ //
+ // If there's input from mouse, signal the event.
+ //
+ if (UsbMouseDev->StateChanged) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_MOUSE_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBMouseRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB_MOUSE_DEV *UsbMouseDev;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ UsbMouseDev = (USB_MOUSE_DEV *) Context;
+
+ UsbIo = UsbMouseDev->UsbIo;
+
+ //
+ // Re-submit Asynchronous Interrupt Transfer for recovery.
+ //
+ UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ UsbMouseDev->IntEndpointDescriptor.EndpointAddress,
+ TRUE,
+ UsbMouseDev->IntEndpointDescriptor.Interval,
+ UsbMouseDev->IntEndpointDescriptor.MaxPacketSize,
+ OnMouseInterruptComplete,
+ UsbMouseDev
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h
new file mode 100644
index 000000000..f46069602
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouse.h
@@ -0,0 +1,465 @@
+/** @file
+ Helper routine and corresponding data struct used by USB Mouse Driver.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_MOUSE_H_
+#define _EFI_USB_MOUSE_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/SimplePointer.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+#define CLASS_HID 3
+#define SUBCLASS_BOOT 1
+#define PROTOCOL_MOUSE 2
+
+#define BOOT_PROTOCOL 0
+#define REPORT_PROTOCOL 1
+
+#define USB_MOUSE_DEV_SIGNATURE SIGNATURE_32 ('u', 'm', 'o', 'u')
+
+//
+// A common header for usb standard descriptor.
+// Each stand descriptor has a length and type.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 Len;
+ UINT8 Type;
+} USB_DESC_HEAD;
+#pragma pack()
+
+///
+/// Button range and status
+///
+typedef struct {
+ BOOLEAN ButtonDetected;
+ UINT8 ButtonMinIndex;
+ UINT8 ButtonMaxIndex;
+ UINT8 Reserved;
+} USB_MOUSE_BUTTON_DATA;
+
+///
+/// Device instance of USB mouse.
+///
+typedef struct {
+ UINTN Signature;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_EVENT DelayedRecoveryEvent;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor;
+ UINT8 NumberOfButtons;
+ INT32 XLogicMax;
+ INT32 XLogicMin;
+ INT32 YLogicMax;
+ INT32 YLogicMin;
+ EFI_SIMPLE_POINTER_PROTOCOL SimplePointerProtocol;
+ EFI_SIMPLE_POINTER_STATE State;
+ EFI_SIMPLE_POINTER_MODE Mode;
+ BOOLEAN StateChanged;
+ USB_MOUSE_BUTTON_DATA PrivateData;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+} USB_MOUSE_DEV;
+
+///
+/// General HID Item structure
+///
+
+typedef union {
+ UINT8 Uint8;
+ UINT16 Uint16;
+ UINT32 Uint32;
+ INT8 Int8;
+ INT16 Int16;
+ INT32 Int32;
+ UINT8 *LongData;
+} HID_DATA;
+
+typedef struct {
+ UINT16 Format;
+ UINT8 Size;
+ UINT8 Type;
+ UINT8 Tag;
+ HID_DATA Data;
+} HID_ITEM;
+
+#define USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL(a) \
+ CR(a, USB_MOUSE_DEV, SimplePointerProtocol, USB_MOUSE_DEV_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMouseComponentName2;
+
+//
+// Functions of Driver Binding Protocol
+//
+
+/**
+ Check whether USB mouse driver supports this device.
+
+ @param This The USB mouse 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 other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the mouse device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mouse device,
+ installs Simple Pointer Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mouse device.
+
+ @param This The USB mouse 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 This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the USB mouse device handled by this driver.
+
+ @param This The USB mouse 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_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMouseDriverBindingStop (
+ 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
+UsbMouseComponentNameGetDriverName (
+ 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
+UsbMouseComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// Functions of EFI_SIMPLE_POINTER_PROTOCOL
+//
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
+ @param MouseState A pointer to the state information on the pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in State.
+ @retval EFI_NOT_READY The state of the pointer device has not changed since the last call to
+ GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to retrieve the pointer device's
+ current state.
+ @retval EFI_INVALID_PARAMETER MouseState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMouseState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ OUT EFI_SIMPLE_POINTER_STATE *MouseState
+ );
+
+/**
+ Resets the pointer device hardware.
+
+ @param This A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMouseReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Event notification function for SIMPLE_POINTER.WaitForInput event.
+
+ @param Event Event to be signaled when there's input from mouse.
+ @param Context Points to USB_MOUSE_DEV instance.
+
+**/
+VOID
+EFIAPI
+UsbMouseWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Internal worker functions
+//
+
+/**
+ Uses USB I/O to check whether the device is a USB mouse device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB mouse device.
+ @retval FALSE Device is a not USB mouse device.
+
+**/
+BOOLEAN
+IsUsbMouse (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ );
+
+/**
+ Initialize the USB mouse device.
+
+ This function retrieves and parses HID report descriptor, and
+ initializes state of USB_MOUSE_DEV. Then it sets indefinite idle
+ rate for the device. Finally it creates event for delayed recovery,
+ which deals with device error.
+
+ @param UsbMouseDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB mouse device successfully initialized..
+ @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor.
+ @retval Other USB mouse device was not initialized successfully.
+
+**/
+EFI_STATUS
+InitializeUsbMouseDevice (
+ IN OUT USB_MOUSE_DEV *UsbMouseDev
+ );
+
+/**
+ Handler function for USB mouse's asynchronous interrupt transfer.
+
+ This function is the handler function for USB mouse's asynchronous interrupt transfer
+ to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
+ get button and movement state.
+
+ @param Data A pointer to a buffer that is filled with key data which is
+ retrieved via asynchronous interrupt transfer.
+ @param DataLength Indicates the size of the data buffer.
+ @param Context Pointing to USB_KB_DEV instance.
+ @param Result Indicates the result of the asynchronous interrupt transfer.
+
+ @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully.
+ @retval EFI_DEVICE_ERROR Hardware error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+OnMouseInterruptComplete (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ );
+
+/**
+ Handler for Delayed Recovery event.
+
+ This function is the handler for Delayed Recovery event triggered
+ by timer.
+ After a device error occurs, the event would be triggered
+ with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
+ is defined in USB standard for error handling.
+
+ @param Event The Delayed Recovery event.
+ @param Context Points to the USB_MOUSE_DEV instance.
+
+**/
+VOID
+EFIAPI
+USBMouseRecoveryHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Parse Mouse Report Descriptor.
+
+ According to USB HID Specification, report descriptors are
+ composed of pieces of information. Each piece of information
+ is called an Item. This function retrieves each item from
+ the report descriptor and updates USB_MOUSE_DEV.
+
+ @param UsbMouse The instance of USB_MOUSE_DEV
+ @param ReportDescriptor Report descriptor to parse
+ @param ReportSize Report descriptor size
+
+ @retval EFI_SUCCESS Report descriptor successfully parsed.
+ @retval EFI_UNSUPPORTED Report descriptor contains long item.
+
+**/
+EFI_STATUS
+ParseMouseReportDescriptor (
+ OUT USB_MOUSE_DEV *UsbMouse,
+ IN UINT8 *ReportDescriptor,
+ IN UINTN ReportSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf
new file mode 100644
index 000000000..5221a4131
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf
@@ -0,0 +1,66 @@
+## @file
+# USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol.
+#
+# USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+# Simple Pointer Protocol on USB mouse devices.
+# It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+# and parses the data according to USB HID Specification.
+# This module refers to following specifications:
+# 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+# 2. UEFI Specification, v2.1
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbMouseDxe
+ MODULE_UNI_FILE = UsbMouseDxe.uni
+ FILE_GUID = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = USBMouseDriverBindingEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUsbMouseDriverBinding
+# COMPONENT_NAME = gUsbMouseComponentName
+# COMPONENT_NAME2 = gUsbMouseComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ MouseHid.c
+ UsbMouse.c
+ UsbMouse.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ ReportStatusCodeLib
+ UefiUsbLib
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiSimplePointerProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbMouseDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni
new file mode 100644
index 000000000..70df7c6c6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.uni
@@ -0,0 +1,25 @@
+// /** @file
+// USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol.
+//
+// USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces
+// Simple Pointer Protocol on USB mouse devices.
+// It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol,
+// and parses the data according to USB HID Specification.
+// This module refers to following specifications:
+// 1. Universal Serial Bus HID Firmware Specification, ver 1.11
+// 2. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB mouse and produces Simple Pointer Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "USB Mouse Driver consumes USB I/O Protocol and Device Path Protocol, and produces Simple Pointer Protocol on USB mouse devices. It manages the USB mouse device via Asynchronous Interrupt Transfer of USB I/O Protocol, and parses the data according to USB HID Specification.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. Universal Serial Bus HID Firmware Specification, ver 1.11<BR>\n"
+ "2. UEFI Specification, v2.1<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni
new file mode 100644
index 000000000..fcabd21aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// UsbMouseDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Mouse DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
new file mode 100644
index 000000000..89e540ba7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
@@ -0,0 +1,436 @@
+/** @file
+ DXE Dispatcher Dependency Evaluator.
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ schedulability is that the dependency expression is satisfied.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+//
+// Worker functions
+//
+
+
+/**
+ Grow size of the Depex stack
+
+ @retval EFI_SUCCESS Stack successfully growed.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+ VOID
+ )
+{
+ BOOLEAN *NewStack;
+ UINTN Size;
+
+ Size = DEPEX_STACK_SIZE_INCREMENT;
+ if (mDepexEvaluationStack != NULL) {
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDepexEvaluationStack != NULL) {
+ //
+ // Copy to Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ mDepexEvaluationStack,
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (mDepexEvaluationStack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
+ mDepexEvaluationStack = NewStack;
+ mDepexEvaluationStackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Value BOOLEAN to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushBool (
+ IN BOOLEAN Value
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowDepexStack ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ *mDepexEvaluationStackPointer = Value;
+ mDepexEvaluationStackPointer++;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Pop an element from the Boolean stack.
+
+ @param Value BOOLEAN to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
+
+**/
+EFI_STATUS
+PopBool (
+ OUT BOOLEAN *Value
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ mDepexEvaluationStackPointer--;
+ *Value = *mDepexEvaluationStackPointer;
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ if (*Iterator == EFI_DEP_SOR) {
+ DriverEntry->Unrequested = TRUE;
+ } else {
+ DriverEntry->Dependent = TRUE;
+ }
+
+ if (*Iterator == EFI_DEP_BEFORE) {
+ DriverEntry->Before = TRUE;
+ } else if (*Iterator == EFI_DEP_AFTER) {
+ DriverEntry->After = TRUE;
+ }
+
+ if (DriverEntry->Before || DriverEntry->After) {
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Iterator;
+ BOOLEAN Operator;
+ BOOLEAN Operator2;
+ EFI_GUID DriverGuid;
+ VOID *Interface;
+
+ Operator = FALSE;
+ Operator2 = FALSE;
+
+ if (DriverEntry->After || DriverEntry->Before) {
+ //
+ // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means treat the driver like an UEFI 2.0 thing.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ DEBUG ((DEBUG_DISPATCH, " All UEFI Services Available = "));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n RESULT = FALSE\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n RESULT = TRUE\n"));
+ return TRUE;
+ }
+
+ //
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+ // incorrectly formed DEPEX expressions
+ //
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+
+ Iterator = DriverEntry->Depex;
+
+ while (TRUE) {
+ //
+ // Check to see if we are attempting to fetch dependency expression instructions
+ // past the end of the dependency expression.
+ //
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
+ return FALSE;
+ }
+
+ //
+ // Look at the opcode of the dependency expression instruction.
+ //
+ switch (*Iterator) {
+ case EFI_DEP_BEFORE:
+ case EFI_DEP_AFTER:
+ //
+ // For a well-formed Dependency Expression, the code should never get here.
+ // The BEFORE and AFTER are processed prior to this routine's invocation.
+ // If the code flow arrives at this point, there was a BEFORE or AFTER
+ // that were not the first opcodes.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
+ ASSERT (FALSE);
+ case EFI_DEP_SOR:
+ //
+ // These opcodes can only appear once as the first opcode. If it is found
+ // at any other location, then the dependency expression evaluates to FALSE
+ //
+ if (Iterator != DriverEntry->Depex) {
+ DEBUG ((DEBUG_DISPATCH, " SOR\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected SOR opcode)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " SOR = Requested\n"));
+ //
+ // Otherwise, it is the first opcode and should be treated as a NOP.
+ //
+ break;
+
+ case EFI_DEP_PUSH:
+ //
+ // Push operator is followed by a GUID. Test to see if the GUID protocol
+ // is installed and push the boolean result on the stack.
+ //
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+
+ Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
+ Status = PushBool (FALSE);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ *Iterator = EFI_DEP_REPLACE_TRUE;
+ Status = PushBool (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ case EFI_DEP_AND:
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_OR:
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_NOT:
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(!Operator));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_TRUE:
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_FALSE:
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ Status = PushBool (FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_END:
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
+ return Operator;
+
+ case EFI_DEP_REPLACE_TRUE:
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
+ goto Done;
+ }
+
+ //
+ // Skip over the Dependency Op Code we just processed in the switch.
+ // The math is done out of order, but it should not matter. That is
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
+ // This is not an issue, since we just need the correct end result. You
+ // need to be careful using Iterator in the loop as it's intermediate value
+ // may be strange.
+ //
+ Iterator++;
+ }
+
+Done:
+ return FALSE;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
new file mode 100644
index 000000000..fed60c488
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
@@ -0,0 +1,1488 @@
+/** @file
+ DXE Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The SOR, Before, and After Depex are
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori
+ file exists in the FV those drivers are addeded to the
+ mScheduledQueue. The mFvHandleList is used to make sure a
+ FV is only processed once.
+
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
+ start it. After mScheduledQueue is drained check the
+ mDiscoveredList to see if any item has a Depex that is ready to
+ be placed on the mScheduledQueue.
+
+ Step #3 - Adding to the mScheduledQueue requires that you process Before
+ and After dependencies. This is done recursively as the call to add
+ to the mScheduledQueue checks for Before and recursively adds
+ all Befores. It then addes the item that was passed in and then
+ processess the After dependecies by recursively calling the routine.
+
+ Dispatcher Rules:
+ The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expresion.
+ SOR - Schedule On Request - Don't schedule if this bit is set.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
+//
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
+
+//
+// Queue of drivers that are ready to dispatch. This queue is a subset of the
+// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
+//
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
+
+//
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.
+//
+LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE
+
+//
+// Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
+//
+EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+
+//
+// Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Module globals to manage the FwVol registration notification event
+//
+EFI_EVENT mFwVolEvent;
+VOID *mFwVolEventRegistration;
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mDxeFileTypes[] = {
+ EFI_FV_FILETYPE_DRIVER,
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE,
+ EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+};
+
+typedef struct {
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FV_FILEPATH_DEVICE_PATH;
+
+FV_FILEPATH_DEVICE_PATH mFvDevicePath;
+
+//
+// Function Prototypes
+//
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ );
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ );
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ );
+
+
+/**
+ Enter critical section by gaining lock on mDispatcherLock.
+
+**/
+VOID
+CoreAcquireDispatcherLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mDispatcherLock);
+}
+
+
+/**
+ Exit critical section by releasing lock on mDispatcherLock.
+
+**/
+VOID
+CoreReleaseDispatcherLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mDispatcherLock);
+}
+
+
+/**
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction
+ protocol returns an error via ReadSection defer the reading of the Depex.
+
+ @param DriverEntry Driver to work on.
+
+ @retval EFI_SUCCESS Depex read and preprossesed
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
+ and Depex reading needs to be retried.
+ @retval Error DEPEX not found.
+
+**/
+EFI_STATUS
+CoreGetDepexSectionAndPreProccess (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+
+ Fv = DriverEntry->Fv;
+
+ //
+ // Grab Depex info, it will never be free'ed.
+ //
+ SectionType = EFI_SECTION_DXE_DEPEX;
+ Status = Fv->ReadSection (
+ DriverEntry->Fv,
+ &DriverEntry->FileName,
+ SectionType,
+ 0,
+ &DriverEntry->Depex,
+ (UINTN *)&DriverEntry->DepexSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_PROTOCOL_ERROR) {
+ //
+ // The section extraction protocol failed so set protocol error flag
+ //
+ DriverEntry->DepexProtocolError = TRUE;
+ } else {
+ //
+ // If no Depex assume UEFI 2.0 driver model
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before, After, and Unrequested state information based on Depex
+ // Driver will be put in Dependent or Unrequested state
+ //
+ CorePreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
+ DriverEntry->Unrequested &&
+ CompareGuid (DriverName, &DriverEntry->FileName)) {
+ //
+ // Move the driver from the Unrequested to the Dependent state
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Unrequested = FALSE;
+ DriverEntry->Dependent = TRUE;
+ CoreReleaseDispatcherLock ();
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
+
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
+ DriverEntry->Untrusted &&
+ CompareGuid (DriverName, &DriverEntry->FileName)) {
+ //
+ // Transition driver from Untrusted to Scheduled state.
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Untrusted = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+ EFI_EVENT DxeDispatchEvent;
+
+ PERF_FUNCTION_BEGIN ();
+
+ if (gDispatcherRunning) {
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gEfiEventDxeDispatchGuid,
+ &DxeDispatchEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReturnStatus = EFI_NOT_FOUND;
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_CORE_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_CORE_DRIVER_ENTRY_SIGNATURE
+ );
+
+ //
+ // Load the DXE Driver image into memory. If the Driver was transitioned from
+ // Untrused to Scheduled it would have already been loaded so we may need to
+ // skip the LoadImage
+ //
+ if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {
+ DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
+ Status = CoreLoadImage (
+ FALSE,
+ gDxeCoreImageHandle,
+ DriverEntry->FvFileDevicePath,
+ NULL,
+ 0,
+ &DriverEntry->ImageHandle
+ );
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ CoreAcquireDispatcherLock ();
+
+ if (Status == EFI_SECURITY_VIOLATION) {
+ //
+ // Take driver from Scheduled to Untrused state
+ //
+ DriverEntry->Untrusted = TRUE;
+ } else {
+ //
+ // The DXE Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
+ //
+ DriverEntry->Initialized = TRUE;
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ CoreAcquireDispatcherLock ();
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+
+ if (DriverEntry->IsFvImage) {
+ //
+ // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
+ //
+ Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
+ } else {
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ ASSERT (DriverEntry->ImageHandle != NULL);
+
+ Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ }
+
+ ReturnStatus = EFI_SUCCESS;
+ }
+
+ //
+ // Now DXE Dispatcher finished one round of dispatch, signal an event group
+ // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
+ // on UEFI protocols
+ //
+ if (!EFI_ERROR (ReturnStatus)) {
+ CoreSignalEvent (DxeDispatchEvent);
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+
+ if (DriverEntry->DepexProtocolError){
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (CoreIsSchedulable (DriverEntry)) {
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ } else {
+ if (DriverEntry->Unrequested) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // Close DXE dispatch Event
+ //
+ CoreCloseEvent (DxeDispatchEvent);
+
+ gDispatcherRunning = FALSE;
+
+ PERF_FUNCTION_END ();
+
+ return ReturnStatus;
+}
+
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process BEFORE
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+ CoreAcquireDispatcherLock ();
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process AFTER
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+}
+
+
+/**
+ Return TRUE if the Fv has been processed, FALSE if not.
+
+ @param FvHandle The handle of a FV that's being tested
+
+ @retval TRUE Fv protocol on FvHandle has been processed
+ @retval FALSE Fv protocol on FvHandle has not yet been processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (KnownHandle->Handle == FvHandle) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Remember that Fv protocol on FvHandle has had it's drivers placed on the
+ mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
+ entry is different from one in mFvHandleList by checking FvImage Guid.
+ Items are never removed/freed from the mFvHandleList.
+
+ @param FvHandle The handle of a FV that has been processed
+
+ @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
+ has been added, NULL will return.
+
+**/
+KNOWN_HANDLE *
+FvIsBeingProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID FvNameGuid;
+ BOOLEAN FvNameGuidIsFound;
+ UINT32 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ UINTN LbaOffset;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ FwVolHeader = NULL;
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ FvNameGuidIsFound = FALSE;
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the full FV header based on FVB protocol.
+ //
+ ASSERT (Fvb != NULL);
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FwVolHeader != NULL);
+ if (VerifyFvHeaderChecksum (FwVolHeader) && FwVolHeader->ExtHeaderOffset != 0) {
+ ExtHeaderOffset = (UINT32) FwVolHeader->ExtHeaderOffset;
+ BlockMap = FwVolHeader->BlockMap;
+ LbaIndex = 0;
+ LbaOffset = 0;
+ //
+ // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
+ //
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index ++) {
+ ExtHeaderOffset -= BlockMap->Length;
+ LbaIndex ++;
+ }
+ //
+ // Check whether FvExtHeader is crossing the multi block range.
+ //
+ if (Index < BlockMap->NumBlocks) {
+ LbaOffset = ExtHeaderOffset;
+ break;
+ }
+ BlockMap++;
+ }
+ //
+ // Read FvNameGuid from FV extension header.
+ //
+ Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid);
+ if (!EFI_ERROR (Status)) {
+ FvNameGuidIsFound = TRUE;
+ }
+ }
+ CoreFreePool (FwVolHeader);
+ }
+ }
+
+ if (FvNameGuidIsFound) {
+ //
+ // Check whether the FV image with the found FvNameGuid has been processed.
+ //
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
+ DEBUG ((EFI_D_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));
+ return NULL;
+ }
+ }
+ }
+
+ KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
+ ASSERT (KnownHandle != NULL);
+
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+ KnownHandle->Handle = FvHandle;
+ if (FvNameGuidIsFound) {
+ CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
+ }
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);
+ return KnownHandle;
+}
+
+
+
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
+
+ //
+ // Remember the device path of the FV
+ //
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ FileNameDevicePath = NULL;
+ } else {
+ //
+ // Build a device path to the file in the FV to pass into gBS->LoadImage
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ FileNameDevicePath = AppendDevicePath (
+ FvDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ }
+
+ return FileNameDevicePath;
+}
+
+
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ )
+{
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+ if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ DriverEntry->IsFvImage = TRUE;
+ }
+
+ DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FvHandle = FvHandle;
+ DriverEntry->Fv = Fv;
+ DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
+
+ CoreGetDepexSectionAndPreProccess (DriverEntry);
+
+ CoreAcquireDispatcherLock ();
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
+ described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
+
+ @param FvNameGuid The FV image guid specified.
+ @param DriverName The driver guid specified.
+
+ @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
+ Hob.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+FvFoundInHobFv2 (
+ IN CONST EFI_GUID *FvNameGuid,
+ IN CONST EFI_GUID *DriverName
+ )
+{
+ EFI_PEI_HOB_POINTERS HobFv2;
+
+ HobFv2.Raw = GetHobList ();
+
+ while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
+ //
+ // Compare parent FvNameGuid and FileGuid both.
+ //
+ if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
+ CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName)) {
+ return TRUE;
+ }
+ HobFv2.Raw = GET_NEXT_HOB (HobFv2);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
+
+ @param[in] FvHeader Pointer to FV header.
+ @param[out] FvUsedSize Pointer to FV used size returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+ @param[out] EraseByte Pointer to erase byte returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+
+ @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
+ FV used size and erase byte are returned.
+ @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
+
+**/
+BOOLEAN
+GetFvUsedSize (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ OUT UINT32 *FvUsedSize,
+ OUT UINT8 *EraseByte
+ )
+{
+ UINT16 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
+
+ ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
+ if (ExtHeaderOffset != 0) {
+ ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + ExtHeaderOffset);
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *) (ExtHeader + 1);
+ while ((UINTN) ExtEntryList < ((UINTN) ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
+ if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
+ //
+ // USED_SIZE FV_EXT_TYPE entry is found.
+ //
+ ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *) ExtEntryList;
+ *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
+ *EraseByte = 0xFF;
+ } else {
+ *EraseByte = 0;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
+ FvHeader,
+ *FvUsedSize,
+ *EraseByte
+ ));
+ return TRUE;
+ }
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
+ ((UINT8 *) ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
+ }
+ }
+
+ //
+ // No USED_SIZE FV_EXT_TYPE entry found.
+ //
+ return FALSE;
+}
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ VOID *Buffer;
+ VOID *AlignedBuffer;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINT32 FvAlignment;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ UINT32 FvUsedSize;
+ UINT8 EraseByte;
+ UINTN Index;
+
+ //
+ // Read firmware volume section(s)
+ //
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
+
+ Index = 0;
+ do {
+ FvHeader = NULL;
+ FvAlignment = 0;
+ Buffer = NULL;
+ BufferSize = 0;
+ AlignedBuffer = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ FileName,
+ SectionType,
+ Index,
+ &Buffer,
+ &BufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Evaluate the authentication status of the Firmware Volume through
+ // Security Architectural Protocol
+ //
+ if (gSecurity != NULL) {
+ FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);
+ Status = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ FvFileDevicePath
+ );
+ if (FvFileDevicePath != NULL) {
+ FreePool (FvFileDevicePath);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // Security check failed. The firmware volume should not be used for any purpose.
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+ break;
+ }
+ }
+
+ //
+ // FvImage should be at its required alignment.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->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;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
+ __FUNCTION__,
+ FvHeader,
+ FvAlignment
+ ));
+
+ //
+ // Check FvImage alignment.
+ //
+ if ((UINTN) FvHeader % FvAlignment != 0) {
+ //
+ // Allocate the aligned buffer for the FvImage.
+ //
+ AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
+ if (AlignedBuffer == NULL) {
+ FreePool (Buffer);
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ } else {
+ //
+ // Move FvImage into the aligned buffer and release the original buffer.
+ //
+ if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
+ //
+ // Copy the used bytes and fill the rest with the erase value.
+ //
+ CopyMem (AlignedBuffer, FvHeader, (UINTN) FvUsedSize);
+ SetMem (
+ (UINT8 *) AlignedBuffer + FvUsedSize,
+ (UINTN) (BufferSize - FvUsedSize),
+ EraseByte
+ );
+ } else {
+ CopyMem (AlignedBuffer, Buffer, BufferSize);
+ }
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) AlignedBuffer;
+ FreePool (Buffer);
+ Buffer = NULL;
+ }
+ }
+ }
+ //
+ // Produce a FVB protocol for the file
+ //
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ (UINT64)BufferSize,
+ FvHandle,
+ AuthenticationStatus,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // ReadSection or Produce FVB failed, Free data buffer
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ if (AlignedBuffer != NULL) {
+ FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+
+ break;
+ } else {
+ Index++;
+ }
+ } while (TRUE);
+
+ if (Index > 0) {
+ //
+ // At least one FvImage has been processed successfully.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS GetNextFileStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_HANDLE FvHandle;
+ UINTN BufferSize;
+ EFI_GUID NameGuid;
+ UINTN Key;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ EFI_GUID *AprioriFile;
+ UINTN AprioriEntryCount;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ UINT32 AuthenticationStatus;
+ UINTN SizeOfBuffer;
+ VOID *DepexBuffer;
+ KNOWN_HANDLE *KnownHandle;
+
+ FvHandle = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mFwVolEventRegistration,
+ &BufferSize,
+ &FvHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ if (FvHasBeenProcessed (FvHandle)) {
+ //
+ // This Fv has already been processed so lets skip it!
+ //
+ continue;
+ }
+
+ //
+ // Since we are about to process this Fv mark it as processed.
+ //
+ KnownHandle = FvIsBeingProcessed (FvHandle);
+ if (KnownHandle == NULL) {
+ //
+ // The FV with the same FV name guid has already been processed.
+ // So lets skip it!
+ //
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (EFI_ERROR (Status) || Fv == NULL) {
+ //
+ // FvHandle must have Firmware Volume2 protocol thus we should never get here.
+ //
+ ASSERT (FALSE);
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // The Firmware volume doesn't have device path, can't be dispatched.
+ //
+ continue;
+ }
+
+ //
+ // Discover Drivers in FV and add them to the Discovered Driver List.
+ // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
+ // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
+ //
+ for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
+ //
+ // Initialize the search key
+ //
+ Key = 0;
+ do {
+ Type = mDxeFileTypes[Index];
+ GetNextFileStatus = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &Type,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (!EFI_ERROR (GetNextFileStatus)) {
+ if (Type == EFI_FV_FILETYPE_DXE_CORE) {
+ //
+ // If this is the DXE core fill in it's DevicePath & DeviceHandle
+ //
+ if (gDxeCoreLoadedImage->FilePath == NULL) {
+ if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
+ //
+ // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ gDxeCoreLoadedImage->DeviceHandle = FvHandle;
+ }
+ }
+ } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
+ continue;
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_SMM_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SMM depex section is found, this FV image is invalid to be supported.
+ // ASSERT FALSE to report this FV image.
+ //
+ FreePool (DepexBuffer);
+ ASSERT (FALSE);
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_DXE_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
+ //
+ CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
+ } else {
+ //
+ // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
+ //
+ FreePool (DepexBuffer);
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ } else {
+ //
+ // Transition driver from Undiscovered to Discovered state
+ //
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ }
+ } while (!EFI_ERROR (GetNextFileStatus));
+ }
+
+ //
+ // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
+ //
+ AprioriFile = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &gAprioriGuid,
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **)&AprioriFile,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
+ } else {
+ AprioriEntryCount = 0;
+ }
+
+ //
+ // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
+ // drivers not in the current FV and these must be skipped since the a priori list
+ // is only valid for the FV that it resided in.
+ //
+
+ for (Index = 0; Index < AprioriEntryCount; Index++) {
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
+ (FvHandle == DriverEntry->FvHandle)) {
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Dependent = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ break;
+ }
+ }
+ }
+
+ //
+ // Free data allocated by Fv->ReadSection ()
+ //
+ CoreFreePool (AprioriFile);
+ }
+}
+
+
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ )
+{
+ PERF_FUNCTION_BEGIN ();
+
+ mFwVolEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ TPL_CALLBACK,
+ CoreFwVolEventProtocolNotify,
+ NULL,
+ &mFwVolEventRegistration
+ );
+
+ PERF_FUNCTION_END ();
+}
+
+//
+// Function only used in debug builds
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni
new file mode 100644
index 000000000..54b855281
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This is core module in DXE phase.
+//
+// It provides an implementation of DXE Core that is compliant with DXE CIS.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The core module in DXE phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It provides an implementation of DXE Core that is compliant with DXE CIS."
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
new file mode 100644
index 000000000..c9abba4f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DxeCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core DXE Services Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h
new file mode 100644
index 000000000..9bd3c0d08
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -0,0 +1,2940 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DxeCore module.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_MAIN_H_
+#define _DXE_MAIN_H_
+
+
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Runtime.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/PlatformDriverOverride.h>
+#include <Protocol/Variable.h>
+#include <Protocol/Timer.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/Bds.h>
+#include <Protocol/RealTimeClock.h>
+#include <Protocol/WatchdogTimer.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/MonotonicCounter.h>
+#include <Protocol/StatusCode.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/LoadPe32Image.h>
+#include <Protocol/Security.h>
+#include <Protocol/Security2.h>
+#include <Protocol/Reset.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/Metronome.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Capsule.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/DriverFamilyOverride.h>
+#include <Protocol/TcgService.h>
+#include <Protocol/HiiPackageList.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/PeCoffImageEmulator.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Guid/HobList.h>
+#include <Guid/DebugImageInfoTable.h>
+#include <Guid/FileInfo.h>
+#include <Guid/Apriori.h>
+#include <Guid/DxeServices.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/LoadModuleAtFixedAddress.h>
+#include <Guid/IdleLoopEvent.h>
+#include <Guid/VectorHandoffTable.h>
+#include <Ppi/VectorHandoffInfo.h>
+#include <Guid/MemoryProfile.h>
+
+#include <Library/DxeCoreEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiDecompressLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+//
+// range for memory mapped port I/O on IPF
+//
+#define EFI_MEMORY_PORT_IO 0x4000000000000000ULL
+
+
+///
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
+/// to save time. A EFI_DEP_PUSH is evaluated one an
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
+/// Driver Execution Environment Core Interface use 0xff
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
+/// defined to a new value that is not conflicting with PI spec.
+///
+#define EFI_DEP_REPLACE_TRUE 0xff
+
+///
+/// Define the initial size of the dependency expression evaluation stack
+///
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000
+
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ VOID **Protocol;
+ EFI_EVENT Event;
+ VOID *Registration;
+ BOOLEAN Present;
+} EFI_CORE_PROTOCOL_NOTIFY_ENTRY;
+
+//
+// DXE Dispatcher Data structures
+//
+
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFvHandleList
+ EFI_HANDLE Handle;
+ EFI_GUID FvNameGuid;
+} KNOWN_HANDLE;
+
+
+#define EFI_CORE_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('d','r','v','r')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_HANDLE FvHandle;
+ EFI_GUID FileName;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Unrequested;
+ BOOLEAN Scheduled;
+ BOOLEAN Untrusted;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ BOOLEAN IsFvImage;
+
+} EFI_CORE_DRIVER_ENTRY;
+
+//
+//The data structure of GCD memory map entry
+//
+#define EFI_GCD_MAP_SIGNATURE SIGNATURE_32('g','c','d','m')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 EndAddress;
+ UINT64 Capabilities;
+ UINT64 Attributes;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_MAP_ENTRY;
+
+
+#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i')
+
+typedef struct {
+ UINTN Signature;
+ /// Image handle
+ EFI_HANDLE Handle;
+ /// Image type
+ UINTN Type;
+ /// If entrypoint has been called
+ BOOLEAN Started;
+ /// The image's entry point
+ EFI_IMAGE_ENTRY_POINT EntryPoint;
+ /// loaded image protocol
+ EFI_LOADED_IMAGE_PROTOCOL Info;
+ /// Location in memory
+ EFI_PHYSICAL_ADDRESS ImageBasePage;
+ /// Number of pages
+ UINTN NumberOfPages;
+ /// Original fixup data
+ CHAR8 *FixupData;
+ /// Tpl of started image
+ EFI_TPL Tpl;
+ /// Status returned by started image
+ EFI_STATUS Status;
+ /// Size of ExitData from started image
+ UINTN ExitDataSize;
+ /// Pointer to exit data from started image
+ VOID *ExitData;
+ /// Pointer to pool allocation for context save/restore
+ VOID *JumpBuffer;
+ /// Pointer to buffer for context save/restore
+ BASE_LIBRARY_JUMP_BUFFER *JumpContext;
+ /// Machine type from PE image
+ UINT16 Machine;
+ /// PE/COFF Image Emulator Protocol pointer
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *PeCoffEmu;
+ /// Runtime image list
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
+ /// Pointer to Loaded Image Device Path Protocol
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ /// PeCoffLoader ImageContext
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ /// Status returned by LoadImage() service.
+ EFI_STATUS LoadImageStatus;
+} LOADED_IMAGE_PRIVATE_DATA;
+
+#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE)
+
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS CodeSegmentBase;
+ UINT64 CodeSegmentSize;
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;
+
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINTN CodeSegmentCount;
+ LIST_ENTRY CodeSegmentList;
+} IMAGE_PROPERTIES_RECORD;
+
+//
+// DXE Core Global Variables
+//
+extern EFI_SYSTEM_TABLE *gDxeCoreST;
+extern EFI_RUNTIME_SERVICES *gDxeCoreRT;
+extern EFI_DXE_SERVICES *gDxeCoreDS;
+extern EFI_HANDLE gDxeCoreImageHandle;
+
+extern BOOLEAN gMemoryMapTerminated;
+
+extern EFI_DECOMPRESS_PROTOCOL gEfiDecompress;
+
+extern EFI_RUNTIME_ARCH_PROTOCOL *gRuntime;
+extern EFI_CPU_ARCH_PROTOCOL *gCpu;
+extern EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
+extern EFI_METRONOME_ARCH_PROTOCOL *gMetronome;
+extern EFI_TIMER_ARCH_PROTOCOL *gTimer;
+extern EFI_SECURITY_ARCH_PROTOCOL *gSecurity;
+extern EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2;
+extern EFI_BDS_ARCH_PROTOCOL *gBds;
+extern EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
+
+extern EFI_TPL gEfiCurrentTpl;
+
+extern EFI_GUID *gDxeCoreFileName;
+extern EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1];
+
+extern BOOLEAN gDispatcherRunning;
+extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
+
+extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
+extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
+//
+// Service Initialization Functions
+//
+
+
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ );
+
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ );
+
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ );
+
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ );
+
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ );
+
+
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ );
+
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ );
+
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ );
+
+
+/**
+ Creates an event that is fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ );
+
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ );
+
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Called by the platform code to process a tick.
+
+ @param Duration The number of 100ns elapsed since the last call
+ to TimerTick
+
+**/
+VOID
+EFIAPI
+CoreTimerTick (
+ IN UINT64 Duration
+ );
+
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ );
+
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ );
+
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ );
+
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ );
+
+
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID not valid.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ );
+
+
+
+/**
+ Raise the task priority level to the new level.
+ High level is implemented by disabling processor interrupts.
+
+ @param NewTpl New task priority level
+
+ @return The previous task priority level
+
+**/
+EFI_TPL
+EFIAPI
+CoreRaiseTpl (
+ IN EFI_TPL NewTpl
+ );
+
+
+
+/**
+ Lowers the task priority to the previous value. If the new
+ priority unmasks events at a higher priority, they are dispatched.
+
+ @param NewTpl New, lower, task priority
+
+**/
+VOID
+EFIAPI
+CoreRestoreTpl (
+ IN EFI_TPL NewTpl
+ );
+
+
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ );
+
+
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ );
+
+
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to install the protocol handlers on,
+ or NULL if a new handle is to be allocated
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ );
+
+
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UnisatllProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to uninstall the protocol
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ );
+
+
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ );
+
+
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @return The requested protocol interface for the handle
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ );
+
+
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol
+ information in the form of
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ );
+
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ );
+
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ );
+
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+
+
+/**
+ Locates the handle to a device on the device path that best matches the specified protocol.
+
+ @param Protocol The protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device
+ path. On output, the device path pointer is
+ modified to point to the remaining part of the
+ devicepath.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles matched the search.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ );
+
+
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ );
+
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ );
+
+
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ );
+
+
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
+
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ );
+
+
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ );
+
+
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEvent (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN VOID *NotifyContext, OPTIONAL
+ OUT EFI_EVENT *Event
+ );
+
+
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventEx (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN CONST VOID *NotifyContext, OPTIONAL
+ IN CONST EFI_GUID *EventGroup, OPTIONAL
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Creates a general-purpose event structure
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventInternal (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN CONST VOID *NotifyContext, OPTIONAL
+ IN CONST EFI_GUID *EventGroup, OPTIONAL
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param UserEvent The timer event that is to be signaled at the
+ specified time
+ @param Type The type of time that is specified in
+ TriggerTime
+ @param TriggerTime The number of 100ns units until the timer
+ expires
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the
+ requested time
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetTimer (
+ IN EFI_EVENT UserEvent,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ );
+
+
+
+/**
+ Signals the event. Queues the event to be notified if needed.
+
+ @param UserEvent The event to signal .
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event was signaled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the UserEvents array
+ @param UserEvents An array of EFI_EVENT
+ @param UserIndex Pointer to the index of the event which
+ satisfied the wait condition
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
+ function or Event was not a valid type
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
+
+**/
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *UserEvents,
+ OUT UINTN *UserIndex
+ );
+
+
+
+/**
+ Closes an event and frees the event structure.
+
+ @param UserEvent Event to close
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event has been closed
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+
+
+/**
+ Check the status of an event.
+
+ @param UserEvent The event to check
+
+ @retval EFI_SUCCESS The event is in the signaled state
+ @retval EFI_NOT_READY The event is not in the signaled state
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ );
+
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ );
+
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ );
+
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ );
+
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ );
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+
+/**
+ This routine is the driver initialization entry point. It initializes the
+ libraries, and registers two notification functions. These notification
+ functions are responsible for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+/**
+ 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
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ );
+
+//
+//Functions used during debug buils
+//
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ );
+
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+
+/**
+ 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.
+
+ The GetInfo() function 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 EFI_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 EFI_SUCCESS is returned.
+ The GetInfo() 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.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @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 EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_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.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() 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 and SourceSize is
+ sucessfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ );
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @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 The section stream is created 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 UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ );
+
+
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @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
+ required 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 A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @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 section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ 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,
+ IN BOOLEAN IsFfs3Fv
+ );
+
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @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 UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ );
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+ Note:
+ This function allocates memory, frees it, and then allocates memory at an
+ address within the initial allocation. Since this function is called early
+ in DXE core initialization (before drivers are dispatched), this should not
+ be a problem.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ );
+
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ );
+
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ );
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ );
+
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ );
+
+
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ );
+
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ 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_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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ );
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ );
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ );
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN EFI_PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ );
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ );
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ );
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Protect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ );
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ );
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf
new file mode 100644
index 000000000..1d4b11dc7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -0,0 +1,201 @@
+## @file
+# This is core module in DXE phase.
+#
+# It provides an implementation of DXE Core that is compliant with DXE CIS.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCore
+ MODULE_UNI_FILE = DxeCore.uni
+ FILE_GUID = D6A2CB7F-6A18-4e2f-B43B-9920A733700A
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+
+
+ ENTRY_POINT = DxeMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ DxeMain.h
+ SectionExtraction/CoreSectionExtraction.c
+ Image/Image.c
+ Image/Image.h
+ Misc/DebugImageInfo.c
+ Misc/Stall.c
+ Misc/SetWatchdogTimer.c
+ Misc/InstallConfigurationTable.c
+ Misc/MemoryAttributesTable.c
+ Misc/MemoryProtection.c
+ Library/Library.c
+ Hand/DriverSupport.c
+ Hand/Notify.c
+ Hand/Locate.c
+ Hand/Handle.c
+ Hand/Handle.h
+ Gcd/Gcd.c
+ Gcd/Gcd.h
+ Mem/Pool.c
+ Mem/Page.c
+ Mem/MemData.c
+ Mem/Imem.h
+ Mem/MemoryProfileRecord.c
+ Mem/HeapGuard.c
+ Mem/HeapGuard.h
+ FwVolBlock/FwVolBlock.c
+ FwVolBlock/FwVolBlock.h
+ FwVol/FwVolWrite.c
+ FwVol/FwVolRead.c
+ FwVol/FwVolAttrib.c
+ FwVol/Ffs.c
+ FwVol/FwVol.c
+ FwVol/FwVolDriver.h
+ Event/Tpl.c
+ Event/Timer.c
+ Event/Event.c
+ Event/Event.h
+ Dispatcher/Dependency.c
+ Dispatcher/Dispatcher.c
+ DxeMain/DxeProtocolNotify.c
+ DxeMain/DxeMain.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ CacheMaintenanceLib
+ UefiDecompressLib
+ PerformanceLib
+ HobLib
+ BaseLib
+ UefiLib
+ DebugLib
+ DxeCoreEntryPoint
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+ ExtractGuidedSectionLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ DxeServicesLib
+ DebugAgentLib
+ CpuExceptionHandlerLib
+ PcdLib
+
+[Guids]
+ gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ ## CONSUMES ## Event
+ ## PRODUCES ## Event
+ gEfiEventExitBootServicesGuid
+ gEfiHobMemoryAllocModuleGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gEfiFirmwareFileSystem3Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiDebugImageInfoTableGuid ## PRODUCES ## SystemTable
+ gEfiHobListGuid ## PRODUCES ## SystemTable
+ gEfiDxeServicesTableGuid ## PRODUCES ## SystemTable
+ ## PRODUCES ## SystemTable
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiMemoryTypeInformationGuid
+ gEfiEventDxeDispatchGuid ## PRODUCES ## Event
+ gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ ## PRODUCES ## Event
+ ## CONSUMES ## Event
+ gIdleLoopEventGuid
+ gEventExitBootServicesFailedGuid ## SOMETIMES_PRODUCES ## Event
+ gEfiVectorHandoffTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEdkiiMemoryProfileGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ gEfiMemoryAttributesTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiHobMemoryAllocStackGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid ## UNDEFINED # HOB
+
+[Protocols]
+ ## PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiDecompressProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFile2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBusSpecificDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverFamilyOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPlatformDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolumeBlockProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolume2ProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ gEfiDevicePathProtocolGuid
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiLoadedImageDevicePathProtocolGuid ## PRODUCES
+ gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## SOMETIMES_CONSUMES
+
+ # Arch Protocols
+ gEfiBdsArchProtocolGuid ## CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiMetronomeArchProtocolGuid ## CONSUMES
+ gEfiMonotonicCounterArchProtocolGuid ## CONSUMES
+ gEfiRealTimeClockArchProtocolGuid ## CONSUMES
+ gEfiResetArchProtocolGuid ## CONSUMES
+ gEfiRuntimeArchProtocolGuid ## CONSUMES
+ gEfiSecurityArchProtocolGuid ## CONSUMES
+ gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTimerArchProtocolGuid ## CONSUMES
+ gEfiVariableWriteArchProtocolGuid ## CONSUMES
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEfiCapsuleArchProtocolGuid ## CONSUMES
+ gEfiWatchdogTimerArchProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+
+# [Hob]
+# RESOURCE_DESCRIPTOR ## CONSUMES
+# MEMORY_ALLOCATION ## CONSUMES
+# FIRMWARE_VOLUME ## CONSUMES
+# UNDEFINED ## CONSUMES # CPU
+#
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## PRODUCES # DxeCore signals timer event.
+# EVENT_TYPE_PERIODIC_TIMER ## PRODUCES # DxeCore signals timer event.
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DxeCoreExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
new file mode 100644
index 000000000..5ee4cd10b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -0,0 +1,938 @@
+/** @file
+ DXE Core Main Entry Point
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for Protocols from PEI
+//
+EFI_HANDLE mDecompressHandle = NULL;
+
+//
+// DXE Core globals for Architecture Protocols
+//
+EFI_SECURITY_ARCH_PROTOCOL *gSecurity = NULL;
+EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2 = NULL;
+EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;
+EFI_METRONOME_ARCH_PROTOCOL *gMetronome = NULL;
+EFI_TIMER_ARCH_PROTOCOL *gTimer = NULL;
+EFI_BDS_ARCH_PROTOCOL *gBds = NULL;
+EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer = NULL;
+
+//
+// DXE Core globals for optional protocol dependencies
+//
+EFI_SMM_BASE2_PROTOCOL *gSmmBase2 = NULL;
+
+//
+// DXE Core Global used to update core loaded image protocol handle
+//
+EFI_GUID *gDxeCoreFileName;
+EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+//
+// DXE Core Module Variables
+//
+EFI_BOOT_SERVICES mBootServices = {
+ {
+ EFI_BOOT_SERVICES_SIGNATURE, // Signature
+ EFI_BOOT_SERVICES_REVISION, // Revision
+ sizeof (EFI_BOOT_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_RAISE_TPL) CoreRaiseTpl, // RaiseTPL
+ (EFI_RESTORE_TPL) CoreRestoreTpl, // RestoreTPL
+ (EFI_ALLOCATE_PAGES) CoreAllocatePages, // AllocatePages
+ (EFI_FREE_PAGES) CoreFreePages, // FreePages
+ (EFI_GET_MEMORY_MAP) CoreGetMemoryMap, // GetMemoryMap
+ (EFI_ALLOCATE_POOL) CoreAllocatePool, // AllocatePool
+ (EFI_FREE_POOL) CoreFreePool, // FreePool
+ (EFI_CREATE_EVENT) CoreCreateEvent, // CreateEvent
+ (EFI_SET_TIMER) CoreSetTimer, // SetTimer
+ (EFI_WAIT_FOR_EVENT) CoreWaitForEvent, // WaitForEvent
+ (EFI_SIGNAL_EVENT) CoreSignalEvent, // SignalEvent
+ (EFI_CLOSE_EVENT) CoreCloseEvent, // CloseEvent
+ (EFI_CHECK_EVENT) CoreCheckEvent, // CheckEvent
+ (EFI_INSTALL_PROTOCOL_INTERFACE) CoreInstallProtocolInterface, // InstallProtocolInterface
+ (EFI_REINSTALL_PROTOCOL_INTERFACE) CoreReinstallProtocolInterface, // ReinstallProtocolInterface
+ (EFI_UNINSTALL_PROTOCOL_INTERFACE) CoreUninstallProtocolInterface, // UninstallProtocolInterface
+ (EFI_HANDLE_PROTOCOL) CoreHandleProtocol, // HandleProtocol
+ (VOID *) NULL, // Reserved
+ (EFI_REGISTER_PROTOCOL_NOTIFY) CoreRegisterProtocolNotify, // RegisterProtocolNotify
+ (EFI_LOCATE_HANDLE) CoreLocateHandle, // LocateHandle
+ (EFI_LOCATE_DEVICE_PATH) CoreLocateDevicePath, // LocateDevicePath
+ (EFI_INSTALL_CONFIGURATION_TABLE) CoreInstallConfigurationTable, // InstallConfigurationTable
+ (EFI_IMAGE_LOAD) CoreLoadImage, // LoadImage
+ (EFI_IMAGE_START) CoreStartImage, // StartImage
+ (EFI_EXIT) CoreExit, // Exit
+ (EFI_IMAGE_UNLOAD) CoreUnloadImage, // UnloadImage
+ (EFI_EXIT_BOOT_SERVICES) CoreExitBootServices, // ExitBootServices
+ (EFI_GET_NEXT_MONOTONIC_COUNT) CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount
+ (EFI_STALL) CoreStall, // Stall
+ (EFI_SET_WATCHDOG_TIMER) CoreSetWatchdogTimer, // SetWatchdogTimer
+ (EFI_CONNECT_CONTROLLER) CoreConnectController, // ConnectController
+ (EFI_DISCONNECT_CONTROLLER) CoreDisconnectController, // DisconnectController
+ (EFI_OPEN_PROTOCOL) CoreOpenProtocol, // OpenProtocol
+ (EFI_CLOSE_PROTOCOL) CoreCloseProtocol, // CloseProtocol
+ (EFI_OPEN_PROTOCOL_INFORMATION) CoreOpenProtocolInformation, // OpenProtocolInformation
+ (EFI_PROTOCOLS_PER_HANDLE) CoreProtocolsPerHandle, // ProtocolsPerHandle
+ (EFI_LOCATE_HANDLE_BUFFER) CoreLocateHandleBuffer, // LocateHandleBuffer
+ (EFI_LOCATE_PROTOCOL) CoreLocateProtocol, // LocateProtocol
+ (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces
+ (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces
+ (EFI_CALCULATE_CRC32) CoreEfiNotAvailableYetArg3, // CalculateCrc32
+ (EFI_COPY_MEM) CopyMem, // CopyMem
+ (EFI_SET_MEM) SetMem, // SetMem
+ (EFI_CREATE_EVENT_EX) CoreCreateEventEx // CreateEventEx
+};
+
+EFI_DXE_SERVICES mDxeServices = {
+ {
+ DXE_SERVICES_SIGNATURE, // Signature
+ DXE_SERVICES_REVISION, // Revision
+ sizeof (DXE_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_ADD_MEMORY_SPACE) CoreAddMemorySpace, // AddMemorySpace
+ (EFI_ALLOCATE_MEMORY_SPACE) CoreAllocateMemorySpace, // AllocateMemorySpace
+ (EFI_FREE_MEMORY_SPACE) CoreFreeMemorySpace, // FreeMemorySpace
+ (EFI_REMOVE_MEMORY_SPACE) CoreRemoveMemorySpace, // RemoveMemorySpace
+ (EFI_GET_MEMORY_SPACE_DESCRIPTOR) CoreGetMemorySpaceDescriptor, // GetMemorySpaceDescriptor
+ (EFI_SET_MEMORY_SPACE_ATTRIBUTES) CoreSetMemorySpaceAttributes, // SetMemorySpaceAttributes
+ (EFI_GET_MEMORY_SPACE_MAP) CoreGetMemorySpaceMap, // GetMemorySpaceMap
+ (EFI_ADD_IO_SPACE) CoreAddIoSpace, // AddIoSpace
+ (EFI_ALLOCATE_IO_SPACE) CoreAllocateIoSpace, // AllocateIoSpace
+ (EFI_FREE_IO_SPACE) CoreFreeIoSpace, // FreeIoSpace
+ (EFI_REMOVE_IO_SPACE) CoreRemoveIoSpace, // RemoveIoSpace
+ (EFI_GET_IO_SPACE_DESCRIPTOR) CoreGetIoSpaceDescriptor, // GetIoSpaceDescriptor
+ (EFI_GET_IO_SPACE_MAP) CoreGetIoSpaceMap, // GetIoSpaceMap
+ (EFI_DISPATCH) CoreDispatcher, // Dispatch
+ (EFI_SCHEDULE) CoreSchedule, // Schedule
+ (EFI_TRUST) CoreTrust, // Trust
+ (EFI_PROCESS_FIRMWARE_VOLUME) CoreProcessFirmwareVolume, // ProcessFirmwareVolume
+ (EFI_SET_MEMORY_SPACE_CAPABILITIES)CoreSetMemorySpaceCapabilities, // SetMemorySpaceCapabilities
+};
+
+EFI_SYSTEM_TABLE mEfiSystemTableTemplate = {
+ {
+ EFI_SYSTEM_TABLE_SIGNATURE, // Signature
+ EFI_SYSTEM_TABLE_REVISION, // Revision
+ sizeof (EFI_SYSTEM_TABLE), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ NULL, // FirmwareVendor
+ 0, // FirmwareRevision
+ NULL, // ConsoleInHandle
+ NULL, // ConIn
+ NULL, // ConsoleOutHandle
+ NULL, // ConOut
+ NULL, // StandardErrorHandle
+ NULL, // StdErr
+ NULL, // RuntimeServices
+ &mBootServices, // BootServices
+ 0, // NumberOfConfigurationTableEntries
+ NULL // ConfigurationTable
+};
+
+EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = {
+ {
+ EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
+ EFI_RUNTIME_SERVICES_REVISION, // Revision
+ sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_GET_TIME) CoreEfiNotAvailableYetArg2, // GetTime
+ (EFI_SET_TIME) CoreEfiNotAvailableYetArg1, // SetTime
+ (EFI_GET_WAKEUP_TIME) CoreEfiNotAvailableYetArg3, // GetWakeupTime
+ (EFI_SET_WAKEUP_TIME) CoreEfiNotAvailableYetArg2, // SetWakeupTime
+ (EFI_SET_VIRTUAL_ADDRESS_MAP) CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap
+ (EFI_CONVERT_POINTER) CoreEfiNotAvailableYetArg2, // ConvertPointer
+ (EFI_GET_VARIABLE) CoreEfiNotAvailableYetArg5, // GetVariable
+ (EFI_GET_NEXT_VARIABLE_NAME) CoreEfiNotAvailableYetArg3, // GetNextVariableName
+ (EFI_SET_VARIABLE) CoreEfiNotAvailableYetArg5, // SetVariable
+ (EFI_GET_NEXT_HIGH_MONO_COUNT) CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount
+ (EFI_RESET_SYSTEM) CoreEfiNotAvailableYetArg4, // ResetSystem
+ (EFI_UPDATE_CAPSULE) CoreEfiNotAvailableYetArg3, // UpdateCapsule
+ (EFI_QUERY_CAPSULE_CAPABILITIES) CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities
+ (EFI_QUERY_VARIABLE_INFO) CoreEfiNotAvailableYetArg4 // QueryVariableInfo
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate = {
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.ImageHead),
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.EventHead),
+
+ //
+ // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
+ EFI_MEMORY_DESCRIPTOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ FALSE,
+ FALSE
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = &gRuntimeTemplate;
+
+//
+// DXE Core Global Variables for the EFI System Table, Boot Services Table,
+// DXE Services Table, and Runtime Services Table
+//
+EFI_DXE_SERVICES *gDxeCoreDS = &mDxeServices;
+EFI_SYSTEM_TABLE *gDxeCoreST = NULL;
+
+//
+// For debug initialize gDxeCoreRT to template. gDxeCoreRT must be allocated from RT memory
+// but gDxeCoreRT is used for ASSERT () and DEBUG () type macros so lets give it
+// a value that will not cause debug infrastructure to crash early on.
+//
+EFI_RUNTIME_SERVICES *gDxeCoreRT = &mEfiRuntimeServicesTableTemplate;
+EFI_HANDLE gDxeCoreImageHandle = NULL;
+
+BOOLEAN gMemoryMapTerminated = FALSE;
+
+//
+// EFI Decompress Protocol
+//
+EFI_DECOMPRESS_PROTOCOL gEfiDecompress = {
+ DxeMainUefiDecompressGetInfo,
+ DxeMainUefiDecompress
+};
+
+//
+// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load
+// Runtime code&boot time code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable = {0, 0};
+
+// Main entry point to the DXE Core
+//
+
+/**
+ Main entry point to DXE Core.
+
+ @param HobStart Pointer to the beginning of the HOB List from PEI.
+
+ @return This function should never return.
+
+**/
+VOID
+EFIAPI
+DxeMain (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
+ UINT64 MemoryLength;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ VOID *EntryPoint;
+
+ //
+ // Setup the default exception handlers
+ //
+ VectorInfoList = NULL;
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
+ }
+ Status = InitializeCpuExceptionHandlersEx (VectorInfoList, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize Debug Agent to support source level debug in DXE phase
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
+
+ //
+ // Initialize Memory Services
+ //
+ CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
+
+ MemoryProfileInit (HobStart);
+
+ //
+ // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
+ // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
+ //
+ gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
+ ASSERT (gDxeCoreST != NULL);
+
+ gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
+ ASSERT (gDxeCoreRT != NULL);
+
+ gDxeCoreST->RuntimeServices = gDxeCoreRT;
+
+ //
+ // Start the Image Services.
+ //
+ Status = CoreInitializeImageServices (HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the Global Coherency Domain Services
+ //
+ Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call constructor for all libraries
+ //
+ ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
+ PERF_CROSSMODULE_END ("PEI");
+ PERF_CROSSMODULE_BEGIN ("DXE");
+
+ //
+ // Report DXE Core image information to the PE/COFF Extra Action Library
+ //
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*)(UINTN)ImageContext.ImageAddress);
+ ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID*)(UINTN)ImageContext.ImageAddress);
+ Status = PeCoffLoaderGetEntryPoint ((VOID*)(UINTN)ImageContext.ImageAddress, &EntryPoint);
+ if (Status == EFI_SUCCESS) {
+ ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+ }
+ ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+ //
+ // Install the DXE Services Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the HOB List into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Memory Type Information Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
+ // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
+ // Code and Tseg base to load SMM driver.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Report Status Code here for DXE_ENTRY_POINT once it is available
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
+ );
+
+ //
+ // Create the aligned system table pointer structure that is used by external
+ // debuggers to locate the system table... Also, install debug image info
+ // configuration table.
+ //
+ CoreInitializeDebugImageInfoTable ();
+ CoreNewDebugImageInfoEntry (
+ EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
+ gDxeCoreLoadedImage,
+ gDxeCoreImageHandle
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart));
+
+ DEBUG_CODE_BEGIN ();
+ EFI_PEI_HOB_POINTERS Hob;
+
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
+ }
+ }
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume->BaseAddress,
+ Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV2 Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume2->BaseAddress,
+ Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1
+ ));
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume2->FvName,
+ &Hob.FirmwareVolume2->FileName
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV3 Hob 0x%0lx - 0x%0lx - 0x%x - 0x%x\n",
+ Hob.FirmwareVolume3->BaseAddress,
+ Hob.FirmwareVolume3->BaseAddress + Hob.FirmwareVolume3->Length - 1,
+ Hob.FirmwareVolume3->AuthenticationStatus,
+ Hob.FirmwareVolume3->ExtractedFv
+ ));
+ if (Hob.FirmwareVolume3->ExtractedFv) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume3->FvName,
+ &Hob.FirmwareVolume3->FileName
+ ));
+ }
+ }
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Initialize the Event Services
+ //
+ Status = CoreInitializeEventServices ();
+ ASSERT_EFI_ERROR (Status);
+
+ MemoryProfileInstallProtocol ();
+
+ CoreInitializeMemoryAttributesTable ();
+ CoreInitializeMemoryProtection ();
+
+ //
+ // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,
+ // and install configuration table
+ //
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
+ VectorInfo = VectorInfoList;
+ Index = 1;
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ VectorInfo ++;
+ Index ++;
+ }
+ VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *) VectorInfoList);
+ ASSERT (VectorInfo != NULL);
+ Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) VectorInfo);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs
+ //
+ // These Protocols are not architectural. This implementation is sharing code between
+ // PEI and DXE in order to save FLASH space. These Protocols could also be implemented
+ // as part of the DXE Core. However, that would also require the DXE Core to be ported
+ // each time a different CPU is used, a different Decompression algorithm is used, or a
+ // different Image type is used. By placing these Protocols in PEI, the DXE Core remains
+ // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform,
+ // and from CPU to CPU.
+ //
+
+ //
+ // Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &mDecompressHandle,
+ &gEfiDecompressProtocolGuid, &gEfiDecompress,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the GUIDs of the Architectural Protocols, so the rest of the
+ // EFI Boot Services and EFI Runtime Services tables can be filled in.
+ // Also register for the GUIDs of optional protocols.
+ //
+ CoreNotifyOnProtocolInstallation ();
+
+ //
+ // Produce Firmware Volume Protocols, one for each FV in the HOB list.
+ //
+ Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Produce the Section Extraction Protocol
+ //
+ Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the DXE Dispatcher
+ //
+ CoreInitializeDispatcher ();
+
+ //
+ // Invoke the DXE Dispatcher
+ //
+ CoreDispatcher ();
+
+ //
+ // Display Architectural protocols that were not loaded if this is DEBUG build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayMissingArchProtocols ();
+ DEBUG_CODE_END ();
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayDiscoveredNotDispatched ();
+ DEBUG_CODE_END ();
+
+ //
+ // Assert if the Architectural Protocols are not present.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ if (EFI_ERROR(Status)) {
+ //
+ // Report Status code that some Architectural Protocols are not present.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH)
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Report Status code before transfer control to BDS
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)
+ );
+
+ //
+ // Transfer control to the BDS Architectural Protocol
+ //
+ gBds->Entry (gBds);
+
+ //
+ // BDS should never return
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+ UNREACHABLE ();
+}
+
+
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+
+ //
+ // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
+ // Crc will come back as zero if we set it to zero here
+ //
+ Crc = 0;
+ gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable Timer
+ //
+ gTimer->SetTimerPeriod (gTimer, 0);
+
+ //
+ // Terminate memory services if the MapKey matches
+ //
+ Status = CoreTerminateMemoryMap (MapKey);
+ if (EFI_ERROR (Status)) {
+ //
+ // Notify other drivers that ExitBootServices fail
+ //
+ CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
+ return Status;
+ }
+
+ gMemoryMapTerminated = TRUE;
+
+ //
+ // Notify other drivers that we are exiting boot services.
+ //
+ CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
+
+ //
+ // Report that ExitBootServices() has been called
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
+ );
+
+ MemoryProtectionExitBootServicesCallback();
+
+ //
+ // Disable interrupt of Debug timer.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // Disable CPU Interrupts
+ //
+ gCpu->DisableInterrupt (gCpu);
+
+ //
+ // Clear the non-runtime values of the EFI System Table
+ //
+ gDxeCoreST->BootServices = NULL;
+ gDxeCoreST->ConIn = NULL;
+ gDxeCoreST->ConsoleInHandle = NULL;
+ gDxeCoreST->ConOut = NULL;
+ gDxeCoreST->ConsoleOutHandle = NULL;
+ gDxeCoreST->StdErr = NULL;
+ gDxeCoreST->StandardErrorHandle = NULL;
+
+ //
+ // Recompute the 32-bit CRC of the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Zero out the Boot Service Table
+ //
+ ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
+ gBS = NULL;
+
+ //
+ // Update the AtRuntime field in Runtiem AP.
+ //
+ gRuntime->AtRuntime = TRUE;
+
+ return Status;
+}
+
+
+/**
+ 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.
+
+ The GetInfo() function 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 EFI_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 EFI_SUCCESS is returned.
+ The GetInfo() 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.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @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 EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_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.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ if (Source == NULL || DestinationSize == NULL || ScratchSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize);
+}
+
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() 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 and SourceSize is
+ successfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TestDestinationSize;
+ UINT32 TestScratchSize;
+
+ if (Source == NULL || Destination== NULL || Scratch == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UefiDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ScratchSize < TestScratchSize || DestinationSize < TestDestinationSize) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ return UefiDecompress (Source, Destination, Scratch);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
new file mode 100644
index 000000000..29a55d02e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
@@ -0,0 +1,279 @@
+/** @file
+ This file deals with Architecture Protocol (AP) registration in
+ the Dxe Core. The mArchProtocols[] array represents a list of
+ events that represent the Architectural Protocols.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for all of the Architectural Protocols.
+// If a protocol is installed mArchProtocols[].Present will be TRUE.
+//
+// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
+// and mArchProtocols[].Registration as it creates events for every array
+// entry.
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
+ { &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
+ { &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
+ { &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
+ { &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
+ { &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
+ { &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
+ { &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Optional protocols that the DXE Core will use if they are present
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mOptionalProtocols[] = {
+ { &gEfiSecurity2ArchProtocolGuid, (VOID **)&gSecurity2, NULL, NULL, FALSE },
+ { &gEfiSmmBase2ProtocolGuid, (VOID **)&gSmmBase2, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Following is needed to display missing architectural protocols in debug builds
+//
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ CHAR8 *GuidString;
+} GUID_TO_STRING_PROTOCOL_ENTRY;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST GUID_TO_STRING_PROTOCOL_ENTRY mMissingProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, "Security" },
+ { &gEfiCpuArchProtocolGuid, "CPU" },
+ { &gEfiMetronomeArchProtocolGuid, "Metronome" },
+ { &gEfiTimerArchProtocolGuid, "Timer" },
+ { &gEfiBdsArchProtocolGuid, "Bds" },
+ { &gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer" },
+ { &gEfiRuntimeArchProtocolGuid, "Runtime" },
+ { &gEfiVariableArchProtocolGuid, "Variable" },
+ { &gEfiVariableWriteArchProtocolGuid, "Variable Write" },
+ { &gEfiCapsuleArchProtocolGuid, "Capsule" },
+ { &gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter" },
+ { &gEfiResetArchProtocolGuid, "Reset" },
+ { &gEfiRealTimeClockArchProtocolGuid, "Real Time Clock" },
+ { NULL, "" }
+};
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Notification event handler registered by CoreNotifyOnArchProtocolInstallation ().
+ This notify function is registered for every architectural protocol. This handler
+ updates mArchProtocol[] array entry with protocol instance data and sets it's
+ present flag to TRUE. If any constructor is required it is executed. The EFI
+ System Table headers are updated.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+GenericProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ VOID *Protocol;
+ LIST_ENTRY *Link;
+ LIST_ENTRY TempLinkNode;
+
+ Protocol = NULL;
+
+ //
+ // Get Entry from Context
+ //
+ Entry = (EFI_CORE_PROTOCOL_NOTIFY_ENTRY *)Context;
+
+ //
+ // See if the expected protocol is present in the handle database
+ //
+ Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Mark the protocol as present
+ //
+ Entry->Present = TRUE;
+
+ //
+ // Update protocol global variable if one exists. Entry->Protocol points to a global variable
+ // if one exists in the DXE core for this Architectural Protocol
+ //
+ if (Entry->Protocol != NULL) {
+ *(Entry->Protocol) = Protocol;
+ }
+
+ //
+ // Do special operations for Architectural Protocols
+ //
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) {
+ //
+ // Register the Core timer tick handler with the Timer AP
+ //
+ gTimer->RegisterHandler (gTimer, CoreTimerTick);
+ }
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) {
+ //
+ // When runtime architectural protocol is available, updates CRC32 in the Debug Table
+ //
+ CoreUpdateDebugTableCrc32 ();
+
+ //
+ // Update the Runtime Architectural protocol with the template that the core was
+ // using so there would not need to be a dependency on the Runtime AP
+ //
+
+ //
+ // Copy all the registered Image to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof(LIST_ENTRY));
+ InsertTailList (&gRuntime->ImageHead, Link);
+ }
+ //
+ // Copy all the registered Event to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof(LIST_ENTRY));
+ InsertTailList (&gRuntime->EventHead, Link);
+ }
+
+ //
+ // Clean up gRuntimeTemplate
+ //
+ gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead;
+ gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead;
+ }
+
+ //
+ // It's over kill to do them all every time, but it saves a lot of code.
+ //
+ CalculateEfiHdrCrc (&gDxeCoreRT->Hdr);
+ CalculateEfiHdrCrc (&gBS->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreDS->Hdr);
+}
+
+/**
+ Creates an event for each entry in a table that is fired everytime a Protocol
+ of a specific type is installed.
+
+ @param Entry Pointer to EFI_CORE_PROTOCOL_NOTIFY_ENTRY.
+
+**/
+VOID
+CoreNotifyOnProtocolEntryTable (
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+
+ for (; Entry->ProtocolGuid != NULL; Entry++) {
+ //
+ // Create the event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ GenericProtocolNotify,
+ Entry,
+ &Entry->Event
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ Entry->ProtocolGuid,
+ Entry->Event,
+ &Entry->Registration
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+}
+
+/**
+ Creates an events for the Architectural Protocols and the optional protocols
+ that are fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ )
+{
+ CoreNotifyOnProtocolEntryTable (mArchProtocols);
+ CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
+}
+
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ CONST GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ for (MissingEntry = mMissingProtocols; MissingEntry->ProtocolGuid != NULL; MissingEntry++) {
+ if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) {
+ DEBUG ((DEBUG_ERROR, "\n%a Arch Protocol not present!!\n", MissingEntry->GuidString));
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c
new file mode 100644
index 000000000..c83c572c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c
@@ -0,0 +1,784 @@
+/** @file
+ UEFI Event support functions implemented in this file.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "Event.h"
+
+///
+/// gEfiCurrentTpl - Current Task priority level
+///
+EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
+
+///
+/// gEventQueueLock - Protects the event queues
+///
+EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+///
+/// gEventQueue - A list of event's to notify for each priority level
+///
+LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
+
+///
+/// gEventPending - A bitmask of the EventQueues that are pending
+///
+UINTN gEventPending = 0;
+
+///
+/// gEventSignalQueue - A list of events to signal based on EventGroup type
+///
+LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
+
+///
+/// Enumerate the valid types
+///
+UINT32 mEventTable[] = {
+ ///
+ /// 0x80000200 Timer event with a notification function that is
+ /// queue when the event is signaled with SignalEvent()
+ ///
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x80000000 Timer event without a notification function. It can be
+ /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
+ ///
+ EVT_TIMER,
+ ///
+ /// 0x00000100 Generic event with a notification function that
+ /// can be waited on with CheckEvent() or WaitForEvent()
+ ///
+ EVT_NOTIFY_WAIT,
+ ///
+ /// 0x00000200 Generic event with a notification function that
+ /// is queue when the event is signaled with SignalEvent()
+ ///
+ EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x00000201 ExitBootServicesEvent.
+ ///
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ ///
+ /// 0x60000202 SetVirtualAddressMapEvent.
+ ///
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+
+ ///
+ /// 0x00000000 Generic event without a notification function.
+ /// It can be signaled with SignalEvent() and checked with CheckEvent()
+ /// or WaitForEvent().
+ ///
+ 0x00000000,
+ ///
+ /// 0x80000100 Timer event with a notification function that can be
+ /// waited on with CheckEvent() or WaitForEvent()
+ ///
+ EVT_TIMER | EVT_NOTIFY_WAIT,
+};
+
+///
+/// gIdleLoopEvent - Event which is signalled when the core is idle
+///
+EFI_EVENT gIdleLoopEvent = NULL;
+
+
+/**
+ Enter critical section by acquiring the lock on gEventQueueLock.
+
+**/
+VOID
+CoreAcquireEventLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gEventQueueLock);
+}
+
+
+/**
+ Exit critical section by releasing the lock on gEventQueueLock.
+
+**/
+VOID
+CoreReleaseEventLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gEventQueueLock);
+}
+
+
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {
+ InitializeListHead (&gEventQueue[Index]);
+ }
+
+ CoreInitializeTimer ();
+
+ CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gIdleLoopEventGuid,
+ &gIdleLoopEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ )
+{
+ IEVENT *Event;
+ LIST_ENTRY *Head;
+
+ CoreAcquireEventLock ();
+ ASSERT (gEventQueueLock.OwnerTpl == Priority);
+ Head = &gEventQueue[Priority];
+
+ //
+ // Dispatch all the pending notifications
+ //
+ while (!IsListEmpty (Head)) {
+
+ Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
+ RemoveEntryList (&Event->NotifyLink);
+
+ Event->NotifyLink.ForwardLink = NULL;
+
+ //
+ // Only clear the SIGNAL status if it is a SIGNAL type event.
+ // WAIT type events are only cleared in CheckEvent()
+ //
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ Event->SignalCount = 0;
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Notify this event
+ //
+ ASSERT (Event->NotifyFunction != NULL);
+ Event->NotifyFunction (Event, Event->NotifyContext);
+
+ //
+ // Check for next pending event
+ //
+ CoreAcquireEventLock ();
+ }
+
+ gEventPending &= ~(UINTN)(1 << Priority);
+ CoreReleaseEventLock ();
+}
+
+
+
+/**
+ Queues the event's notification function to fire.
+
+ @param Event The Event to notify
+
+**/
+VOID
+CoreNotifyEvent (
+ IN IEVENT *Event
+ )
+{
+
+ //
+ // Event database must be locked
+ //
+ ASSERT_LOCKED (&gEventQueueLock);
+
+ //
+ // If the event is queued somewhere, remove it
+ //
+
+ if (Event->NotifyLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->NotifyLink);
+ Event->NotifyLink.ForwardLink = NULL;
+ }
+
+ //
+ // Queue the event to the pending notification list
+ //
+
+ InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
+ gEventPending |= (UINTN)(1 << Event->NotifyTpl);
+}
+
+
+
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ IEVENT *Event;
+
+ CoreAcquireEventLock ();
+
+ Head = &gEventSignalQueue;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
+ if (CompareGuid (&Event->EventGroup, EventGroup)) {
+ CoreNotifyEvent (Event);
+ }
+ }
+
+ CoreReleaseEventLock ();
+}
+
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEvent (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN VOID *NotifyContext, OPTIONAL
+ OUT EFI_EVENT *Event
+ )
+{
+ return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
+}
+
+
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventEx (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN CONST VOID *NotifyContext, OPTIONAL
+ IN CONST EFI_GUID *EventGroup, OPTIONAL
+ OUT EFI_EVENT *Event
+ )
+{
+ //
+ // If it's a notify type of event, check for invalid NotifyTpl
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ if (NotifyTpl != TPL_APPLICATION &&
+ NotifyTpl != TPL_CALLBACK &&
+ NotifyTpl != TPL_NOTIFY) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
+}
+
+/**
+ Creates a general-purpose event structure
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventInternal (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
+ IN CONST VOID *NotifyContext, OPTIONAL
+ IN CONST EFI_GUID *EventGroup, OPTIONAL
+ OUT EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ IEVENT *IEvent;
+ INTN Index;
+
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to make sure no reserved flags are set
+ //
+ Status = EFI_INVALID_PARAMETER;
+ for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
+ if (Type == mEventTable[Index]) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ if(EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert Event type for pre-defined Event groups
+ //
+ if (EventGroup != NULL) {
+ //
+ // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ // are not valid
+ //
+ if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
+ Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
+ } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
+ Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
+ }
+ } else {
+ //
+ // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
+ //
+ if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
+ EventGroup = &gEfiEventExitBootServicesGuid;
+ } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
+ EventGroup = &gEfiEventVirtualAddressChangeGuid;
+ }
+ }
+
+ //
+ // If it's a notify type of event, check its parameters
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ //
+ // Check for an invalid NotifyFunction or NotifyTpl
+ //
+ if ((NotifyFunction == NULL) ||
+ (NotifyTpl <= TPL_APPLICATION) ||
+ (NotifyTpl >= TPL_HIGH_LEVEL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ } else {
+ //
+ // No notification needed, zero ignored values
+ //
+ NotifyTpl = 0;
+ NotifyFunction = NULL;
+ NotifyContext = NULL;
+ }
+
+ //
+ // Allocate and initialize a new event structure.
+ //
+ if ((Type & EVT_RUNTIME) != 0) {
+ IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
+ } else {
+ IEvent = AllocateZeroPool (sizeof (IEVENT));
+ }
+ if (IEvent == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IEvent->Signature = EVENT_SIGNATURE;
+ IEvent->Type = Type;
+
+ IEvent->NotifyTpl = NotifyTpl;
+ IEvent->NotifyFunction = NotifyFunction;
+ IEvent->NotifyContext = (VOID *)NotifyContext;
+ if (EventGroup != NULL) {
+ CopyGuid (&IEvent->EventGroup, EventGroup);
+ IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
+ }
+
+ *Event = IEvent;
+
+ if ((Type & EVT_RUNTIME) != 0) {
+ //
+ // Keep a list of all RT events so we can tell the RT AP.
+ //
+ IEvent->RuntimeData.Type = Type;
+ IEvent->RuntimeData.NotifyTpl = NotifyTpl;
+ IEvent->RuntimeData.NotifyFunction = NotifyFunction;
+ IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;
+ //
+ // Work around the bug in the Platform Init specification (v1.7), reported
+ // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
+ // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
+ // as "The EFI_EVENT returned by CreateEvent()", but the type of the field
+ // doesn't match the natural language description. Therefore we need an
+ // explicit cast here.
+ //
+ IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;
+ InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
+ }
+
+ CoreAcquireEventLock ();
+
+ if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
+ //
+ // The Event's NotifyFunction must be queued whenever the event is signaled
+ //
+ InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Signals the event. Queues the event to be notified if needed.
+
+ @param UserEvent The event to signal .
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event was signaled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireEventLock ();
+
+ //
+ // If the event is not already signalled, do so
+ //
+
+ if (Event->SignalCount == 0x00000000) {
+ Event->SignalCount++;
+
+ //
+ // If signalling type is a notify function, queue it
+ //
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
+ //
+ // The CreateEventEx() style requires all members of the Event Group
+ // to be signaled.
+ //
+ CoreReleaseEventLock ();
+ CoreNotifySignalList (&Event->EventGroup);
+ CoreAcquireEventLock ();
+ } else {
+ CoreNotifyEvent (Event);
+ }
+ }
+ }
+
+ CoreReleaseEventLock ();
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Check the status of an event.
+
+ @param UserEvent The event to check
+
+ @retval EFI_SUCCESS The event is in the signaled state
+ @retval EFI_NOT_READY The event is not in the signaled state
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ IEVENT *Event;
+ EFI_STATUS Status;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_NOT_READY;
+
+ if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
+
+ //
+ // Queue the wait notify function
+ //
+ CoreAcquireEventLock ();
+ if (Event->SignalCount == 0) {
+ CoreNotifyEvent (Event);
+ }
+ CoreReleaseEventLock ();
+ }
+
+ //
+ // If the even looks signalled, get the lock and clear it
+ //
+
+ if (Event->SignalCount != 0) {
+ CoreAcquireEventLock ();
+
+ if (Event->SignalCount != 0) {
+ Event->SignalCount = 0;
+ Status = EFI_SUCCESS;
+ }
+
+ CoreReleaseEventLock ();
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the UserEvents array
+ @param UserEvents An array of EFI_EVENT
+ @param UserIndex Pointer to the index of the event which
+ satisfied the wait condition
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
+ function or Event was not a valid type
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
+
+**/
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *UserEvents,
+ OUT UINTN *UserIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ //
+ // Can only WaitForEvent at TPL_APPLICATION
+ //
+ if (gEfiCurrentTpl != TPL_APPLICATION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (NumberOfEvents == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (UserEvents == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for(;;) {
+
+ for(Index = 0; Index < NumberOfEvents; Index++) {
+
+ Status = CoreCheckEvent (UserEvents[Index]);
+
+ //
+ // provide index of event that caused problem
+ //
+ if (Status != EFI_NOT_READY) {
+ if (UserIndex != NULL) {
+ *UserIndex = Index;
+ }
+ return Status;
+ }
+ }
+
+ //
+ // Signal the Idle event
+ //
+ CoreSignalEvent (gIdleLoopEvent);
+ }
+}
+
+
+/**
+ Closes an event and frees the event structure.
+
+ @param UserEvent Event to close
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event has been closed
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ EFI_STATUS Status;
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If it's a timer event, make sure it's not pending
+ //
+ if ((Event->Type & EVT_TIMER) != 0) {
+ CoreSetTimer (Event, TimerCancel, 0);
+ }
+
+ CoreAcquireEventLock ();
+
+ //
+ // If the event is queued somewhere, remove it
+ //
+
+ if (Event->RuntimeData.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->RuntimeData.Link);
+ }
+
+ if (Event->NotifyLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->NotifyLink);
+ }
+
+ if (Event->SignalLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->SignalLink);
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // If the event is registered on a protocol notify, then remove it from the protocol database
+ //
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
+ CoreUnregisterProtocolNotify (Event);
+ }
+
+ //
+ // To avoid the Event to be signalled wrongly after closed,
+ // clear the Signature of Event before free pool.
+ //
+ Event->Signature = 0;
+ Status = CoreFreePool (Event);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h
new file mode 100644
index 000000000..8141c5003
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h
@@ -0,0 +1,91 @@
+/** @file
+ UEFI Event support functions and structure.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+
+#define VALID_TPL(a) ((a) <= TPL_HIGH_LEVEL)
+extern UINTN gEventPending;
+
+///
+/// Set if Event is part of an event group
+///
+#define EVT_EXFLAG_EVENT_GROUP 0x01
+///
+/// Set if Event is registered on a protocol notify
+///
+#define EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION 0x02
+
+//
+// EFI_EVENT
+//
+
+///
+/// Timer event information
+///
+typedef struct {
+ LIST_ENTRY Link;
+ UINT64 TriggerTime;
+ UINT64 Period;
+} TIMER_EVENT_INFO;
+
+#define EVENT_SIGNATURE SIGNATURE_32('e','v','n','t')
+typedef struct {
+ UINTN Signature;
+ UINT32 Type;
+ UINT32 SignalCount;
+ ///
+ /// Entry if the event is registered to be signalled
+ ///
+ LIST_ENTRY SignalLink;
+ ///
+ /// Notification information for this event
+ ///
+ EFI_TPL NotifyTpl;
+ EFI_EVENT_NOTIFY NotifyFunction;
+ VOID *NotifyContext;
+ EFI_GUID EventGroup;
+ LIST_ENTRY NotifyLink;
+ UINT8 ExFlag;
+ ///
+ /// A list of all runtime events
+ ///
+ EFI_RUNTIME_EVENT_ENTRY RuntimeData;
+ TIMER_EVENT_INFO Timer;
+} IEVENT;
+
+//
+// Internal prototypes
+//
+
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ );
+
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c
new file mode 100644
index 000000000..7a94712d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c
@@ -0,0 +1,295 @@
+/** @file
+ Core Timer Services
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "Event.h"
+
+//
+// Internal data
+//
+
+LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
+EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);
+EFI_EVENT mEfiCheckTimerEvent = NULL;
+
+EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+UINT64 mEfiSystemTime = 0;
+
+//
+// Timer functions
+//
+/**
+ Inserts the timer event.
+
+ @param Event Points to the internal structure of timer event
+ to be installed
+
+**/
+VOID
+CoreInsertEventTimer (
+ IN IEVENT *Event
+ )
+{
+ UINT64 TriggerTime;
+ LIST_ENTRY *Link;
+ IEVENT *Event2;
+
+ ASSERT_LOCKED (&mEfiTimerLock);
+
+ //
+ // Get the timer's trigger time
+ //
+ TriggerTime = Event->Timer.TriggerTime;
+
+ //
+ // Insert the timer into the timer database in assending sorted order
+ //
+ for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
+ Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event2->Timer.TriggerTime > TriggerTime) {
+ break;
+ }
+ }
+
+ InsertTailList (Link, &Event->Timer.Link);
+}
+
+/**
+ Returns the current system time.
+
+ @return The current system time
+
+**/
+UINT64
+CoreCurrentSystemTime (
+ VOID
+ )
+{
+ UINT64 SystemTime;
+
+ CoreAcquireLock (&mEfiSystemTimeLock);
+ SystemTime = mEfiSystemTime;
+ CoreReleaseLock (&mEfiSystemTimeLock);
+
+ return SystemTime;
+}
+
+/**
+ Checks the sorted timer list against the current system time.
+ Signals any expired event timer.
+
+ @param CheckEvent Not used
+ @param Context Not used
+
+**/
+VOID
+EFIAPI
+CoreCheckTimers (
+ IN EFI_EVENT CheckEvent,
+ IN VOID *Context
+ )
+{
+ UINT64 SystemTime;
+ IEVENT *Event;
+
+ //
+ // Check the timer database for expired timers
+ //
+ CoreAcquireLock (&mEfiTimerLock);
+ SystemTime = CoreCurrentSystemTime ();
+
+ while (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ //
+ // If this timer is not expired, then we're done
+ //
+ if (Event->Timer.TriggerTime > SystemTime) {
+ break;
+ }
+
+ //
+ // Remove this timer from the timer queue
+ //
+
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+
+ //
+ // Signal it
+ //
+ CoreSignalEvent (Event);
+
+ //
+ // If this is a periodic timer, set it
+ //
+ if (Event->Timer.Period != 0) {
+ //
+ // Compute the timers new trigger time
+ //
+ Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;
+
+ //
+ // If that's before now, then reset the timer to start from now
+ //
+ if (Event->Timer.TriggerTime <= SystemTime) {
+ Event->Timer.TriggerTime = SystemTime;
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+
+ //
+ // Add the timer
+ //
+ CoreInsertEventTimer (Event);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+}
+
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_HIGH_LEVEL - 1,
+ CoreCheckTimers,
+ NULL,
+ NULL,
+ &mEfiCheckTimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Called by the platform code to process a tick.
+
+ @param Duration The number of 100ns elapsed since the last call
+ to TimerTick
+
+**/
+VOID
+EFIAPI
+CoreTimerTick (
+ IN UINT64 Duration
+ )
+{
+ IEVENT *Event;
+
+ //
+ // Check runtiem flag in case there are ticks while exiting boot services
+ //
+ CoreAcquireLock (&mEfiSystemTimeLock);
+
+ //
+ // Update the system time
+ //
+ mEfiSystemTime += Duration;
+
+ //
+ // If the head of the list is expired, fire the timer event
+ // to process it
+ //
+ if (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event->Timer.TriggerTime <= mEfiSystemTime) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiSystemTimeLock);
+}
+
+
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param UserEvent The timer event that is to be signaled at the
+ specified time
+ @param Type The type of time that is specified in
+ TriggerTime
+ @param TriggerTime The number of 100ns units until the timer
+ expires
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the
+ requested time
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetTimer (
+ IN EFI_EVENT UserEvent,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ )
+{
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Type > TimerRelative || (Event->Type & EVT_TIMER) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mEfiTimerLock);
+
+ //
+ // If the timer is queued to the timer database, remove it
+ //
+ if (Event->Timer.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+ }
+
+ Event->Timer.TriggerTime = 0;
+ Event->Timer.Period = 0;
+
+ if (Type != TimerCancel) {
+
+ if (Type == TimerPeriodic) {
+ if (TriggerTime == 0) {
+ gTimer->GetTimerPeriod (gTimer, &TriggerTime);
+ }
+ Event->Timer.Period = TriggerTime;
+ }
+
+ Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
+ CoreInsertEventTimer (Event);
+
+ if (TriggerTime == 0) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c
new file mode 100644
index 000000000..5ff8eb55b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c
@@ -0,0 +1,148 @@
+/** @file
+ Task priority (TPL) functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Event.h"
+
+/**
+ Set Interrupt State.
+
+ @param Enable The state of enable or disable interrupt
+
+**/
+VOID
+CoreSetInterruptState (
+ IN BOOLEAN Enable
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InSmm;
+
+ if (gCpu == NULL) {
+ return;
+ }
+ if (!Enable) {
+ gCpu->DisableInterrupt (gCpu);
+ return;
+ }
+ if (gSmmBase2 == NULL) {
+ gCpu->EnableInterrupt (gCpu);
+ return;
+ }
+ Status = gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ if (!EFI_ERROR (Status) && !InSmm) {
+ gCpu->EnableInterrupt(gCpu);
+ }
+}
+
+
+/**
+ Raise the task priority level to the new level.
+ High level is implemented by disabling processor interrupts.
+
+ @param NewTpl New task priority level
+
+ @return The previous task priority level
+
+**/
+EFI_TPL
+EFIAPI
+CoreRaiseTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (OldTpl > NewTpl) {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR - RaiseTpl with OldTpl(0x%x) > NewTpl(0x%x)\n", OldTpl, NewTpl));
+ ASSERT (FALSE);
+ }
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If raising to high level, disable interrupts
+ //
+ if (NewTpl >= TPL_HIGH_LEVEL && OldTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (FALSE);
+ }
+
+ //
+ // Set the new value
+ //
+ gEfiCurrentTpl = NewTpl;
+
+ return OldTpl;
+}
+
+
+
+
+/**
+ Lowers the task priority to the previous value. If the new
+ priority unmasks events at a higher priority, they are dispatched.
+
+ @param NewTpl New, lower, task priority
+
+**/
+VOID
+EFIAPI
+CoreRestoreTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_TPL PendingTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (NewTpl > OldTpl) {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR - RestoreTpl with NewTpl(0x%x) > OldTpl(0x%x)\n", NewTpl, OldTpl));
+ ASSERT (FALSE);
+ }
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+
+ if (OldTpl >= TPL_HIGH_LEVEL && NewTpl < TPL_HIGH_LEVEL) {
+ gEfiCurrentTpl = TPL_HIGH_LEVEL;
+ }
+
+ //
+ // Dispatch any pending events
+ //
+ while (gEventPending != 0) {
+ PendingTpl = (UINTN) HighBitSet64 (gEventPending);
+ if (PendingTpl <= NewTpl) {
+ break;
+ }
+
+ gEfiCurrentTpl = PendingTpl;
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+ CoreDispatchEventNotifies (gEfiCurrentTpl);
+ }
+
+ //
+ // Set the new value
+ //
+
+ gEfiCurrentTpl = NewTpl;
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
new file mode 100644
index 000000000..199c7f821
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
@@ -0,0 +1,227 @@
+/** @file
+ FFS file access utilities.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+/**
+ 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;
+}
+
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer 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 VOID *InBuffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Count;
+ UINT8 EraseByte;
+ UINT8 *Buffer;
+
+ if(ErasePolarity == 1) {
+ EraseByte = 0xFF;
+ } else {
+ EraseByte = 0;
+ }
+
+ Buffer = InBuffer;
+ 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;
+ }
+}
+
+
+
+/**
+ 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
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ )
+{
+ *FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (*FileState) {
+ case EFI_FILE_HEADER_VALID:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ case EFI_FILE_DELETED:
+ //
+ // Here we need to verify header checksum
+ //
+ return VerifyHeaderChecksum (FfsHeader);
+
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ case EFI_FILE_HEADER_INVALID:
+ default:
+ return FALSE;
+ }
+}
+
+
+/**
+ 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 ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 DataCheckSum;
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+ switch (FileState) {
+
+ case EFI_FILE_DELETED:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ DataCheckSum = FFS_FIXED_CHECKSUM;
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof(EFI_FFS_FILE_HEADER2));
+ } else {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof(EFI_FFS_FILE_HEADER));
+ }
+ }
+ if (FfsHeader->IntegrityCheck.Checksum.File == DataCheckSum) {
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
new file mode 100644
index 000000000..cbf5c1c7b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
@@ -0,0 +1,729 @@
+/** @file
+ Firmware File System driver that produce Firmware Volume protocol.
+ Layers on top of Firmware Block protocol to produce a file abstraction
+ of FV based files.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+//
+// Protocol notify related globals
+//
+VOID *gEfiFwVolBlockNotifyReg;
+EFI_EVENT gEfiFwVolBlockEvent;
+
+FV_DEVICE mFvDevice = {
+ FV2_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FvGetVolumeAttributes,
+ FvSetVolumeAttributes,
+ FvReadFile,
+ FvReadFileSection,
+ FvWriteFile,
+ FvGetNextFile,
+ sizeof (UINTN),
+ NULL,
+ FvGetVolumeInfo,
+ FvSetVolumeInfo
+ },
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ { NULL, NULL },
+ 0,
+ 0,
+ FALSE,
+ FALSE
+};
+
+
+//
+// FFS helper functions
+//
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ )
+{
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN BlockIndex;
+ UINTN ReadDataSize;
+ EFI_STATUS Status;
+
+ //
+ // Try read data in current block
+ //
+ BlockIndex = 0;
+ ReadDataSize = DataSize;
+ Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
+ if (Status == EFI_SUCCESS) {
+ *Offset += DataSize;
+ return EFI_SUCCESS;
+ } else if (Status != EFI_BAD_BUFFER_SIZE) {
+ //
+ // other error will direct return
+ //
+ return Status;
+ }
+
+ //
+ // Data crosses the blocks, read data from next block
+ //
+ DataSize -= ReadDataSize;
+ Data += ReadDataSize;
+ *StartLba = *StartLba + 1;
+ while (DataSize > 0) {
+ Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read data from the crossing blocks
+ //
+ BlockIndex = 0;
+ while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Data += BlockSize;
+ DataSize -= BlockSize;
+ BlockIndex ++;
+ }
+
+ //
+ // Data doesn't exceed the current block range.
+ //
+ if (DataSize < BlockSize) {
+ break;
+ }
+
+ //
+ // Data must be got from the next block range.
+ //
+ *StartLba += NumberOfBlocks;
+ }
+
+ //
+ // read the remaining data
+ //
+ if (DataSize > 0) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Update Lba and Offset used by the following read.
+ //
+ *StartLba += BlockIndex;
+ *Offset = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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_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;
+ UINTN FvhLength;
+ EFI_LBA StartLba;
+ UINTN Offset;
+ UINT8 *Buffer;
+
+ //
+ // Read the standard FV header
+ //
+ StartLba = 0;
+ Offset = 0;
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 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;
+ }
+
+ //
+ // Allocate a buffer for the caller
+ //
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
+ if (*FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the standard header into the buffer
+ //
+ CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ //
+ // Read the rest of the header
+ //
+ FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
+ if (EFI_ERROR (Status)) {
+ //
+ // Read failed so free buffer
+ //
+ CoreFreePool (*FwVolHeader);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Free FvDevice resource when error happens
+
+ @param FvDevice pointer to the FvDevice to be freed.
+
+**/
+VOID
+FreeFvDeviceResource (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Free File List Entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+
+ if (FfsFileEntry->StreamHandle != 0) {
+ //
+ // Close stream and free resources from SEP
+ //
+ CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
+ }
+
+ if (FfsFileEntry->FileCached) {
+ //
+ // Free the cached file buffer.
+ //
+ CoreFreePool (FfsFileEntry->FfsHeader);
+ }
+
+ CoreFreePool (FfsFileEntry);
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
+ }
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Free the cached FV buffer.
+ //
+ CoreFreePool (FvDevice->CachedFv);
+ }
+
+ //
+ // Free Volume Header
+ //
+ CoreFreePool (FvDevice->FwVolHeader);
+
+ return;
+}
+
+
+
+/**
+ 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_SUCCESS FV is consistent and cache is allocated.
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.
+
+**/
+EFI_STATUS
+FvCheck (
+ IN OUT FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT8 *CacheLocation;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ UINTN Size;
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 *TopFvAddress;
+ UINTN TestLength;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ BOOLEAN FileCached;
+ UINTN WholeFileSize;
+ EFI_FFS_FILE_HEADER *CacheFfsHeader;
+
+ FileCached = FALSE;
+ CacheFfsHeader = NULL;
+
+ Fvb = FvDevice->Fvb;
+ FwVolHeader = FvDevice->FwVolHeader;
+
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = (UINTN) FwVolHeader->FvLength;
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ FvDevice->IsMemoryMapped = TRUE;
+
+ Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Don't cache memory mapped FV really.
+ //
+ FvDevice->CachedFv = (UINT8 *) (UINTN) PhysicalAddress;
+ } else {
+ FvDevice->IsMemoryMapped = FALSE;
+ FvDevice->CachedFv = AllocatePool (Size);
+
+ if (FvDevice->CachedFv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Remember a pointer to the end of the CachedFv
+ //
+ FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Copy FV into memory using the block map.
+ //
+ BlockMap = FwVolHeader->BlockMap;
+ CacheLocation = FvDevice->CachedFv;
+ LbaIndex = 0;
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ //
+ // read the FV data
+ //
+ Size = BlockMap->Length;
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ Status = Fvb->Read (
+ Fvb,
+ LbaIndex,
+ 0,
+ &Size,
+ CacheLocation
+ );
+
+ //
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
+ //
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ LbaIndex++;
+ CacheLocation += BlockMap->Length;
+ }
+
+ BlockMap++;
+ }
+ }
+
+ //
+ // Scan to check the free space & File list
+ //
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ FvDevice->ErasePolarity = 1;
+ } else {
+ FvDevice->ErasePolarity = 0;
+ }
+
+
+ //
+ // go through the whole FV cache, check the consistence of the FV.
+ // Make a linked list of all the Ffs file headers
+ //
+ Status = EFI_SUCCESS;
+ InitializeListHead (&FvDevice->FfsFileListHeader);
+
+ //
+ // Build FFS list
+ //
+ if (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 *) (FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv + FwVolHeader->HeaderLength);
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);
+ TopFvAddress = FvDevice->EndOfCachedFv;
+ while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
+
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+
+ TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
+ //
+ // We have found the free space so we are done!
+ //
+ goto Done;
+ }
+
+ if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
+ if ((FileState == EFI_FILE_HEADER_INVALID) ||
+ (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+ continue;
+ } else {
+ //
+ // File system is corrputed
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+ }
+
+ CacheFfsHeader = FfsHeader;
+ if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached.
+ // Here is to cache FFS file to memory buffer for following checksum calculating.
+ // And then, the cached file buffer can be also used for FvReadFile.
+ //
+ WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);
+ CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
+ if (CacheFfsHeader == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ FileCached = TRUE;
+ }
+ }
+
+ if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
+ //
+ // File system is corrupted
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);
+ continue;
+ }
+ }
+
+ FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
+
+ //
+ // 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) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ FfsFileEntry->FfsHeader = CacheFfsHeader;
+ FfsFileEntry->FileCached = FileCached;
+ FileCached = FALSE;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
+ }
+
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
+
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+ FreeFvDeviceResource (FvDevice);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This notification function is invoked when an instance of the
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
+ EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
+ the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
+
+ @param Event The event that occurred
+ @param Context For EFI compatiblity. Not used.
+
+**/
+VOID
+EFIAPI
+NotifyFwVolBlock (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ //
+ // Examine all new handles
+ //
+ for (;;) {
+ //
+ // Get the next handle
+ //
+ BufferSize = sizeof (Handle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ gEfiFwVolBlockNotifyReg,
+ &BufferSize,
+ &Handle
+ );
+
+ //
+ // If not found, we're done
+ //
+ if (EFI_NOT_FOUND == Status) {
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Fvb != NULL);
+
+ //
+ // Make sure the Fv Header is O.K.
+ //
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (FwVolHeader != NULL);
+
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {
+ CoreFreePool (FwVolHeader);
+ continue;
+ }
+
+ //
+ // Check if there is an FV protocol already installed in that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Fv to use a new Fvb
+ //
+ FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
+ if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
+ //
+ // Only write into our device structure if it's our device structure
+ //
+ FvDevice->Fvb = Fvb;
+ }
+
+ } else {
+ //
+ // No FwVol protocol on the handle so create a new one
+ //
+ FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
+ if (FvDevice == NULL) {
+ return;
+ }
+
+ FvDevice->Fvb = Fvb;
+ FvDevice->Handle = Handle;
+ FvDevice->FwVolHeader = FwVolHeader;
+ FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+ FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
+ //
+ // Inherit the authentication status from FVB.
+ //
+ FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
+
+ if (!EFI_ERROR (FvCheck (FvDevice))) {
+ //
+ // Install an New FV protocol on the existing handle
+ //
+ Status = CoreInstallProtocolInterface (
+ &Handle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FvDevice->Fv
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Free FvDevice Buffer for the corrupt FV image.
+ //
+ CoreFreePool (FvDevice);
+ }
+ }
+ }
+
+ return;
+}
+
+
+
+/**
+ This routine is the driver initialization entry point. It registers
+ a notification function. This notification function are responsible
+ for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ TPL_CALLBACK,
+ NotifyFwVolBlock,
+ NULL,
+ &gEfiFwVolBlockNotifyReg
+ );
+ return EFI_SUCCESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
new file mode 100644
index 000000000..ab7b3feff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
@@ -0,0 +1,129 @@
+/** @file
+ Implements get/set firmware volume attributes
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#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);
+
+ //
+ // Mask out Fvb bits that are not defined in FV
+ //
+ FvbAttributes &= 0xfffff0ff;
+
+ *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes;
+
+ return Status;
+}
+
+
+
+/**
+ Sets current attributes for volume
+
+ @param This Calling context
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ 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.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+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 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.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+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/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
new file mode 100644
index 000000000..19ad39871
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
@@ -0,0 +1,402 @@
+/** @file
+ Firmware File System 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>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FW_VOL_DRIVER_H_
+#define __FW_VOL_DRIVER_H_
+
+
+#define FV2_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '2')
+
+//
+// Used to track all non-deleted files
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN StreamHandle;
+ BOOLEAN FileCached;
+} FFS_FILE_LIST_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_HANDLE Handle;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
+
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *CachedFv;
+ UINT8 *EndOfCachedFv;
+
+ FFS_FILE_LIST_ENTRY *LastKey;
+
+ LIST_ENTRY FfsFileListHeader;
+
+ UINT32 AuthenticationStatus;
+ UINT8 ErasePolarity;
+ BOOLEAN IsFfs3Fv;
+ BOOLEAN IsMemoryMapped;
+} FV_DEVICE;
+
+#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV2_DEVICE_SIGNATURE)
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @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 Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV.
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+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 Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @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 Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @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 Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @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 Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @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.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+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 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.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ );
+
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer 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 VOID *InBuffer,
+ 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
+ );
+
+
+/**
+ Set the FFS file state.
+
+ @param State The state to be set.
+ @param FfsHeader Points to the FFS file header
+
+ @return None.
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ 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
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ );
+
+
+/**
+ 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 ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
new file mode 100644
index 000000000..2861cbf67
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
@@ -0,0 +1,536 @@
+/** @file
+ Implements functions to read firmware file
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
+(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
+1 0 0 0
+16 1 0 4
+128 2 0 7
+512 3 0 9
+1 KB 4 0 10
+4 KB 5 0 12
+32 KB 6 0 15
+64 KB 7 0 16
+128 KB 0 1 17
+256 KB 1 1 18
+512 KB 2 1 19
+1 MB 3 1 20
+2 MB 4 1 21
+4 MB 5 1 22
+8 MB 6 1 23
+16 MB 7 1 24
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};
+
+/**
+ 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);
+
+ if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];
+ } else {
+ 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 = FvGetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)){
+ return Status;
+ }
+
+ //
+ // 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;
+ }
+
+ KeyValue = (UINTN *)Key;
+ for (;;) {
+ if (*KeyValue == 0) {
+ //
+ // Search for 1st matching file
+ //
+ Link = &FvDevice->FfsFileListHeader;
+ } else {
+ //
+ // Key is pointer to FFsFileEntry, so get next one
+ //
+ Link = (LIST_ENTRY *)(*KeyValue);
+ }
+
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ //
+ // Next is end of list so we did not find data
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN)FfsFileEntry;
+
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // we ignore pad files
+ //
+ continue;
+ }
+
+ if (*FileType == EFI_FV_FILETYPE_ALL) {
+ //
+ // Process all file types so we have a match
+ //
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ //
+ // Found a matching file type
+ //
+ break;
+ }
+
+ }
+
+ //
+ // Return FileType, NameGuid, and Attributes
+ //
+ *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);
+ }
+
+ 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;
+ EFI_GUID SearchNameGuid;
+ EFI_FV_FILETYPE LocalFoundType;
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;
+ UINTN FileSize;
+ UINT8 *SrcPtr;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN InputBufferSize;
+ UINTN WholeFileSize;
+
+ if (NameGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+
+ //
+ // Keep looking until we find the matching NameGuid.
+ // The Key is really a FfsFileEntry
+ //
+ FvDevice->LastKey = 0;
+ do {
+ LocalFoundType = 0;
+ Status = FvGetNextFile (
+ This,
+ &FvDevice->LastKey,
+ &LocalFoundType,
+ &SearchNameGuid,
+ &LocalAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));
+
+ //
+ // Get a pointer to the header
+ //
+ FfsHeader = FvDevice->LastKey->FfsHeader;
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached, so here is to cache by file.
+ //
+ if (!FvDevice->LastKey->FileCached) {
+ //
+ // Cache FFS file to memory buffer.
+ //
+ WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader): FFS_FILE_SIZE (FfsHeader);
+ FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);
+ if (FfsHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Let FfsHeader in FfsFileEntry point to the cached file buffer.
+ //
+ FvDevice->LastKey->FfsHeader = FfsHeader;
+ FvDevice->LastKey->FileCached = TRUE;
+ }
+ }
+
+ //
+ // Remember callers buffer size
+ //
+ InputBufferSize = *BufferSize;
+
+ //
+ // Calculate return values
+ //
+ *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;
+ }
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus = FvDevice->AuthenticationStatus;
+ *BufferSize = FileSize;
+
+ if (Buffer == NULL) {
+ //
+ // If Buffer is NULL, we only want to get the information collected so far
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip over file header
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Status = EFI_SUCCESS;
+ if (*Buffer == NULL) {
+ //
+ // Caller passed in a pointer so allocate buffer for them
+ //
+ *Buffer = AllocatePool (FileSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (FileSize > InputBufferSize) {
+ //
+ // Callers buffer was not big enough
+ //
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ FileSize = InputBufferSize;
+ }
+
+ //
+ // Copy data into callers buffer
+ //
+ CopyMem (*Buffer, SrcPtr, FileSize);
+
+ return Status;
+}
+
+
+
+/**
+ 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_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ UINT8 *FileBuffer;
+ FFS_FILE_LIST_ENTRY *FfsEntry;
+
+ if (NameGuid == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // Read the file
+ //
+ Status = FvReadFile (
+ This,
+ NameGuid,
+ NULL,
+ &FileSize,
+ &FileType,
+ &FileAttributes,
+ AuthenticationStatus
+ );
+ //
+ // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
+ //
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->LastKey;
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {
+ FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ //
+ // Check to see that the file actually HAS sections before we go any further.
+ //
+ if (FileType == EFI_FV_FILETYPE_RAW) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Use FfsEntry to cache Section Extraction Protocol Information
+ //
+ if (FfsEntry->StreamHandle == 0) {
+ Status = OpenSectionStream (
+ FileSize,
+ FileBuffer,
+ &FfsEntry->StreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // If SectionType == 0 We need the whole section stream
+ //
+ Status = GetSection (
+ FfsEntry->StreamHandle,
+ (SectionType == 0) ? NULL : &SectionType,
+ NULL,
+ (SectionType == 0) ? 0 : SectionInstance,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus,
+ FvDevice->IsFfs3Fv
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus |= FvDevice->AuthenticationStatus;
+ }
+
+ //
+ // Close of stream defered to close of FfsHeader list to allow SEP to cache data
+ //
+
+Done:
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
new file mode 100644
index 000000000..3a3b569b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
@@ -0,0 +1,46 @@
+/** @file
+ Implements functions to write firmware file
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+/**
+ 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 EFI_UNSUPPORTED;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
new file mode 100644
index 000000000..95174c1e4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
@@ -0,0 +1,719 @@
+/** @file
+ Implementations for Firmware Volume Block protocol.
+
+ It consumes FV HOBs and creates read-only Firmare Volume Block protocol
+ instances for each of them.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolBlock.h"
+
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_MEMMAP_DP,
+ {
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
+ }
+ },
+ EfiMemoryMappedIO,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
+ {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_PIWG_FW_VOL_DP,
+ {
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
+ }
+ },
+ { 0 }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {
+ FVB_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FwVolBlockGetAttributes,
+ (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
+ FwVolBlockGetPhysicalAddress,
+ FwVolBlockGetBlockSize,
+ FwVolBlockReadBlock,
+ (EFI_FVB_WRITE)FwVolBlockWriteBlock,
+ (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
+ NULL
+ },
+ 0,
+ NULL,
+ 0,
+ 0,
+ 0
+};
+
+
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Since we are read only, it's safe to get attributes data from our in-memory copy.
+ //
+ *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *LbaOffset;
+ UINTN LbaStart;
+ UINTN NumOfBytesRead;
+ UINTN LbaIndex;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Check if This FW can be read
+ //
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ LbaIndex = (UINTN) Lba;
+ if (LbaIndex >= FvbDevice->NumBlocks) {
+ //
+ // Invalid Lba, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // all exceed boundary, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumOfBytesRead = *NumBytes;
+ if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // partial exceed boundary, read data from current postion to end.
+ //
+ NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
+ }
+
+ LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN) FvbDevice->BaseAddress);
+ LbaOffset = (UINT8 *) FwVolHeader + LbaStart + Offset;
+
+ //
+ // Perform read operation
+ //
+ CopyMem (Buffer, LbaOffset, NumOfBytesRead);
+
+ if (NumOfBytesRead == *NumBytes) {
+ return EFI_SUCCESS;
+ }
+
+ *NumBytes = NumOfBytesRead;
+ return EFI_BAD_BUFFER_SIZE;
+}
+
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ *Address = FvbDevice->BaseAddress;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ )
+{
+ UINTN TotalBlocks;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Do parameter checking
+ //
+ if (Lba >= FvbDevice->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
+
+ PtrBlockMapEntry = FwVolHeader->BlockMap;
+
+ //
+ // Search the block map for the given block
+ //
+ TotalBlocks = 0;
+ while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length !=0 )) {
+ TotalBlocks += PtrBlockMapEntry->NumBlocks;
+ if (Lba < TotalBlocks) {
+ //
+ // We find the range
+ //
+ break;
+ }
+
+ PtrBlockMapEntry++;
+ }
+
+ *BlockSize = PtrBlockMapEntry->Length;
+ *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT32 AuthenticationStatus;
+
+ AuthenticationStatus = 0;
+ FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
+ if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
+ AuthenticationStatus = FvbDevice->AuthenticationStatus;
+ }
+
+ return AuthenticationStatus;
+}
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDev;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BlockIndex;
+ UINTN BlockIndex2;
+ UINTN LinearOffset;
+ UINT32 FvAlignment;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+
+ FvAlignment = 0;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN) BaseAddress;
+ //
+ // Validate FV Header, if not as expected, return
+ //
+ if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ 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;
+ }
+ if ((UINTN)BaseAddress % FvAlignment != 0) {
+ //
+ // FvImage buffer is not at its required alignment.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
+ BaseAddress,
+ Length,
+ FvAlignment
+ ));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ //
+ // Allocate EFI_FW_VOL_BLOCK_DEVICE
+ //
+ FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
+ if (FvbDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvbDev->BaseAddress = BaseAddress;
+ FvbDev->FvbAttributes = FwVolHeader->Attributes;
+ FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
+ FvbDev->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Init the block caching fields of the device
+ // First, count the number of blocks
+ //
+ FvbDev->NumBlocks = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0;
+ PtrBlockMapEntry++) {
+ FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
+ }
+
+ //
+ // Second, allocate the cache
+ //
+ if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
+ if (FvbDev->LbaCache == NULL) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Last, fill in the cache with the linear address of the blocks
+ //
+ BlockIndex = 0;
+ LinearOffset = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+ for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+ FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
+ FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
+ LinearOffset += PtrBlockMapEntry->Length;
+ BlockIndex++;
+ }
+ }
+
+ //
+ // Judget whether FV name guid is produced in Fv extension header
+ //
+ if (FwVolHeader->ExtHeaderOffset == 0) {
+ //
+ // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
+ ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
+ } else {
+ //
+ // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyGuid (
+ &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
+ (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
+ );
+ }
+
+ //
+ //
+ // Attach FvVolBlock Protocol to new handle
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &FvbDev->Handle,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid, FvbDev->DevicePath,
+ NULL
+ );
+
+ //
+ // If they want the handle back, set it.
+ //
+ if (FvProtocol != NULL) {
+ *FvProtocol = FvbDev->Handle;
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PEI_HOB_POINTERS FvHob;
+ EFI_PEI_HOB_POINTERS Fv3Hob;
+ UINT32 AuthenticationStatus;
+
+ //
+ // Core Needs Firmware Volumes to function
+ //
+ FvHob.Raw = GetHobList ();
+ while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
+ AuthenticationStatus = 0;
+ //
+ // Get the authentication status propagated from PEI-phase to DXE.
+ //
+ Fv3Hob.Raw = GetHobList ();
+ while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {
+ if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&
+ (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length)) {
+ AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;
+ break;
+ }
+ Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);
+ }
+ //
+ // Produce an FVB protocol for it
+ //
+ ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);
+ FvHob.Raw = GET_NEXT_HOB (FvHob);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ Caution: The caller need validate the input firmware volume to follow
+ PI specification.
+ DxeCore will trust the input data and process firmware volume directly.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ )
+{
+ VOID *Ptr;
+ EFI_STATUS Status;
+
+ *FVProtocolHandle = NULL;
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ (UINT64)Size,
+ NULL,
+ 0,
+ FVProtocolHandle
+ );
+ //
+ // Since in our implementation we use register-protocol-notify to put a
+ // FV protocol on the FVB protocol handle, we can't directly verify that
+ // the FV protocol was produced. Therefore here we will check the handle
+ // and make sure an FV protocol is on it. This indicates that all went
+ // well. Otherwise we have to assume that the volume was corrupted
+ // somehow.
+ //
+ if (!EFI_ERROR(Status)) {
+ ASSERT (*FVProtocolHandle != NULL);
+ Ptr = NULL;
+ Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr);
+ if (EFI_ERROR(Status) || (Ptr == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
new file mode 100644
index 000000000..2205e9e77
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
@@ -0,0 +1,238 @@
+/** @file
+ Firmware Volume Block protocol functions.
+ Consumes FV hobs and creates appropriate block protocols.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FWVOL_BLOCK_H_
+#define _FWVOL_BLOCK_H_
+
+
+#define FVB_DEVICE_SIGNATURE SIGNATURE_32('_','F','V','B')
+
+
+typedef struct {
+ UINTN Base;
+ UINTN Length;
+} LBA_CACHE;
+
+typedef struct {
+ MEMMAP_DEVICE_PATH MemMapDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_MEMMAP_DEVICE_PATH;
+
+//
+// UEFI Specification define FV device path format if FV provide name guid in extension header
+//
+typedef struct {
+ MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_PIWG_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
+ UINTN NumBlocks;
+ LBA_CACHE *LbaCache;
+ UINT32 FvbAttributes;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 AuthenticationStatus;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+
+#define FVB_DEVICE_FROM_THIS(a) \
+ CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
+
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ );
+
+
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ );
+
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ );
+
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
new file mode 100644
index 000000000..2d8c076f7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -0,0 +1,2675 @@
+/** @file
+ The file contains the GCD related services in the EFI Boot Services Table.
+ The GCD services are used to manage the memory and I/O regions that
+ are accessible to the CPU that is executing the DXE core.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Gcd.h"
+#include "Mem/HeapGuard.h"
+
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
+
+#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
+
+#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED )
+
+#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
+
+#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
+
+//
+// Module Variables
+//
+EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
+LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
+
+EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ EfiGcdMemoryTypeNonExistent,
+ (EFI_GCD_IO_TYPE) 0,
+ NULL,
+ NULL
+};
+
+EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ (EFI_GCD_MEMORY_TYPE) 0,
+ EfiGcdIoTypeNonExistent,
+ NULL,
+ NULL
+};
+
+GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE, EFI_MEMORY_RP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
+ { 0, 0, FALSE }
+};
+
+///
+/// Lookup table used to print GCD Memory Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
+ "NonExist ", // EfiGcdMemoryTypeNonExistent
+ "Reserved ", // EfiGcdMemoryTypeReserved
+ "SystemMem", // EfiGcdMemoryTypeSystemMemory
+ "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
+ "PersisMem", // EfiGcdMemoryTypePersistent
+ "MoreRelia", // EfiGcdMemoryTypeMoreReliable
+ "Unknown " // EfiGcdMemoryTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD I/O Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = {
+ "NonExist", // EfiGcdIoTypeNonExistent
+ "Reserved", // EfiGcdIoTypeReserved
+ "I/O ", // EfiGcdIoTypeIo
+ "Unknown " // EfiGcdIoTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD Allocation Types
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = {
+ "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp
+ "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp
+ "AtAddress ", // EfiGcdAllocateAddress
+ "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown
+ "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown
+ "Unknown " // EfiGcdMaxAllocateType
+};
+
+/**
+ Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdMemorySpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE (
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));
+ }
+ DEBUG ((DEBUG_GCD, "GCDMemType Range Capabilities Attributes \n"));
+ DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((DEBUG_GCD, "%a %016lx-%016lx %016lx %016lx%c\n",
+ mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)],
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
+ MemorySpaceMap[Index].Capabilities,
+ MemorySpaceMap[Index].Attributes,
+ MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (MemorySpaceMap);
+ );
+}
+
+/**
+ Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdIoSpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE (
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;
+ UINTN Index;
+
+ Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
+ ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n"));
+ }
+
+ DEBUG ((DEBUG_GCD, "GCDIoType Range \n"));
+ DEBUG ((DEBUG_GCD, "========== =================================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((DEBUG_GCD, "%a %016lx-%016lx%c\n",
+ mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)],
+ IoSpaceMap[Index].BaseAddress,
+ IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1,
+ IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (IoSpaceMap);
+ );
+}
+
+/**
+ Validate resource descriptor HOB's attributes.
+
+ If Attributes includes some memory resource's settings, it should include
+ the corresponding capabilites also.
+
+ @param Attributes Resource descriptor HOB attributes.
+
+**/
+VOID
+CoreValidateResourceDescriptorHobAttributes (
+ IN UINT64 Attributes
+ )
+{
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0));
+}
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdMemorySpaceLock);
+}
+
+
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdMemorySpaceLock);
+}
+
+
+
+/**
+ Acquire memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreAcquireGcdIoLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdIoSpaceLock);
+}
+
+
+/**
+ Release memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreReleaseGcdIoLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdIoSpaceLock);
+}
+
+
+
+//
+// GCD Initialization Worker Functions
+//
+/**
+ Aligns a value to the specified boundary.
+
+ @param Value 64 bit value to align
+ @param Alignment Log base 2 of the boundary to align Value to
+ @param RoundUp TRUE if Value is to be rounded up to the nearest
+ aligned boundary. FALSE is Value is to be
+ rounded down to the nearest aligned boundary.
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+AlignValue (
+ IN UINT64 Value,
+ IN UINTN Alignment,
+ IN BOOLEAN RoundUp
+ )
+{
+ UINT64 AlignmentMask;
+
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+ if (RoundUp) {
+ Value += AlignmentMask;
+ }
+ return Value & (~AlignmentMask);
+}
+
+
+/**
+ Aligns address to the page boundary.
+
+ @param Value 64 bit address to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignAddress (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
+}
+
+
+/**
+ Aligns length to the page boundary.
+
+ @param Value 64 bit length to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignLength (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
+}
+
+//
+// GCD Memory Space Worker Functions
+//
+
+/**
+ Allocate pool for two entries.
+
+ @param TopEntry An entry of GCD map
+ @param BottomEntry An entry of GCD map
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Both entries successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateGcdMapEntry (
+ IN OUT EFI_GCD_MAP_ENTRY **TopEntry,
+ IN OUT EFI_GCD_MAP_ENTRY **BottomEntry
+ )
+{
+ //
+ // Set to mOnGuarding to TRUE before memory allocation. This will make sure
+ // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
+ // cause problem when it's freed (if HeapGuard is enabled).
+ //
+ mOnGuarding = TRUE;
+ *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*TopEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mOnGuarding = TRUE;
+ *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*BottomEntry == NULL) {
+ CoreFreePool (*TopEntry);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Internal function. Inserts a new descriptor into a sorted list
+
+ @param Link The linked list to insert the range BaseAddress
+ and Length into
+ @param Entry A pointer to the entry that is inserted
+ @param BaseAddress The base address of the new range
+ @param Length The length of the new range in bytes
+ @param TopEntry Top pad entry to insert if needed.
+ @param BottomEntry Bottom pad entry to insert if needed.
+
+ @retval EFI_SUCCESS The new range was inserted into the linked list
+
+**/
+EFI_STATUS
+CoreInsertGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry
+ )
+{
+ ASSERT (Length != 0);
+
+ if (BaseAddress > Entry->BaseAddress) {
+ ASSERT (BottomEntry->Signature == 0);
+
+ CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ Entry->BaseAddress = BaseAddress;
+ BottomEntry->EndAddress = BaseAddress - 1;
+ InsertTailList (Link, &BottomEntry->Link);
+ }
+
+ if ((BaseAddress + Length - 1) < Entry->EndAddress) {
+ ASSERT (TopEntry->Signature == 0);
+
+ CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ TopEntry->BaseAddress = BaseAddress + Length;
+ Entry->EndAddress = BaseAddress + Length - 1;
+ InsertHeadList (Link, &TopEntry->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Merge the Gcd region specified by Link and its adjacent entry.
+
+ @param Link Specify the entry to be merged (with its
+ adjacent entry).
+ @param Forward Direction (forward or backward).
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS Successfully returned.
+ @retval EFI_UNSUPPORTED These adjacent regions could not merge.
+
+**/
+EFI_STATUS
+CoreMergeGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN BOOLEAN Forward,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *AdjacentLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *AdjacentEntry;
+
+ //
+ // Get adjacent entry
+ //
+ if (Forward) {
+ AdjacentLink = Link->ForwardLink;
+ } else {
+ AdjacentLink = Link->BackLink;
+ }
+
+ //
+ // If AdjacentLink is the head of the list, then no merge can be performed
+ //
+ if (AdjacentLink == Map) {
+ return EFI_SUCCESS;
+ }
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->Capabilities != AdjacentEntry->Capabilities) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->Attributes != AdjacentEntry->Attributes) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Forward) {
+ Entry->EndAddress = AdjacentEntry->EndAddress;
+ } else {
+ Entry->BaseAddress = AdjacentEntry->BaseAddress;
+ }
+ RemoveEntryList (AdjacentLink);
+ CoreFreePool (AdjacentEntry);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Merge adjacent entries on total chain.
+
+ @param TopEntry Top entry of GCD map.
+ @param BottomEntry Bottom entry of GCD map.
+ @param StartLink Start link of the list for this loop.
+ @param EndLink End link of the list for this loop.
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS GCD map successfully cleaned up.
+
+**/
+EFI_STATUS
+CoreCleanupGcdMapEntry (
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry,
+ IN LIST_ENTRY *StartLink,
+ IN LIST_ENTRY *EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (TopEntry->Signature == 0) {
+ CoreFreePool (TopEntry);
+ }
+ if (BottomEntry->Signature == 0) {
+ CoreFreePool (BottomEntry);
+ }
+
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ CoreMergeGcdMapEntry (Link, FALSE, Map);
+ Link = Link->ForwardLink;
+ }
+ CoreMergeGcdMapEntry (EndLink, TRUE, Map);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Search a segment of memory space in GCD map. The result is a range of GCD entry list.
+
+ @param BaseAddress The start address of the segment.
+ @param Length The length of the segment.
+ @param StartLink The first GCD entry involves this segment of
+ memory space.
+ @param EndLink The first GCD entry involves this segment of
+ memory space.
+ @param Map Points to the start entry to search.
+
+ @retval EFI_SUCCESS Successfully found the entry.
+ @retval EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+CoreSearchGcdMapEntry (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT LIST_ENTRY **StartLink,
+ OUT LIST_ENTRY **EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ ASSERT (Length != 0);
+
+ *StartLink = NULL;
+ *EndLink = NULL;
+
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {
+ *StartLink = Link;
+ }
+ if (*StartLink != NULL) {
+ if ((BaseAddress + Length - 1) >= Entry->BaseAddress &&
+ (BaseAddress + Length - 1) <= Entry->EndAddress ) {
+ *EndLink = Link;
+ return EFI_SUCCESS;
+ }
+ }
+ Link = Link->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Count the amount of GCD map entries.
+
+ @param Map Points to the start entry to do the count loop.
+
+ @return The count.
+
+**/
+UINTN
+CoreCountGcdMapEntry (
+ IN LIST_ENTRY *Map
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+
+ Count = 0;
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Count++;
+ Link = Link->ForwardLink;
+ }
+
+ return Count;
+}
+
+
+
+/**
+ Return the memory attribute specified by Attributes
+
+ @param Attributes A num with some attribute bits on.
+
+ @return The enum value of memory attribute.
+
+**/
+UINT64
+ConverToCpuArchAttributes (
+ UINT64 Attributes
+ )
+{
+ UINT64 CpuArchAttributes;
+
+ CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
+
+ if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
+ CpuArchAttributes |= EFI_MEMORY_UC;
+ } else if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {
+ CpuArchAttributes |= EFI_MEMORY_WC;
+ } else if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {
+ CpuArchAttributes |= EFI_MEMORY_WT;
+ } else if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
+ CpuArchAttributes |= EFI_MEMORY_WB;
+ } else if ( (Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) {
+ CpuArchAttributes |= EFI_MEMORY_UCE;
+ } else if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
+ CpuArchAttributes |= EFI_MEMORY_WP;
+ }
+
+ return CpuArchAttributes;
+}
+
+
+/**
+ Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
+
+ @param Operation The type of the operation
+ @param GcdMemoryType Additional information for the operation
+ @param GcdIoType Additional information for the operation
+ @param BaseAddress Start address of the segment
+ @param Length length of the segment
+ @param Capabilities The alterable attributes of a newly added entry
+ @param Attributes The attributes needs to be set
+
+ @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
+ setting attribute.
+ @retval EFI_SUCCESS Action successfully done.
+ @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
+ segment or set an upsupported attribute.
+ @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
+ image.
+ @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
+ space, and so on.
+ @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
+ is not available yet.
+**/
+EFI_STATUS
+CoreConvertSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ UINT64 CpuArchAttributes;
+
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated non-existent memory.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
+ Entry->ImageHandle != NULL ) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case GCD_ADD_IO_OPERATION:
+ if (Entry->GcdIoType != EfiGcdIoTypeNonExistent ||
+ Entry->ImageHandle != NULL ) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ if (Entry->ImageHandle == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
+ if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ if ((Entry->Capabilities & Attributes) != Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+
+ goto Done;
+ }
+ //
+ // Current attributes must still be supported with new capabilities
+ //
+ if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ break;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
+ //
+ CpuArchAttributes = 0;
+ if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
+ //
+ // Call CPU Arch Protocol to attempt to set attributes on the range
+ //
+ CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
+ //
+ // CPU arch attributes include page attributes and cache attributes.
+ // Only page attributes supports to be cleared, but not cache attributes.
+ // Caller is expected to use GetMemorySpaceDescriptor() to get the current
+ // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
+ // to set the new attributes.
+ // So 0 CPU arch attributes should not happen as memory should always have
+ // a cache attribute (no matter UC or WB, etc).
+ //
+ // Here, 0 CPU arch attributes will be filtered to be compatible with the
+ // case that caller just calls SetMemorySpaceAttributes() with none CPU
+ // arch attributes (for example, RUNTIME) as the purpose of the case is not
+ // to clear CPU arch attributes.
+ //
+ if (CpuArchAttributes != 0) {
+ if (gCpu == NULL) {
+ Status = EFI_NOT_AVAILABLE_YET;
+ } else {
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ Length,
+ CpuArchAttributes
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (TopEntry);
+ CoreFreePool (BottomEntry);
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ Entry->GcdMemoryType = GcdMemoryType;
+ if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
+ } else {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
+ }
+ break;
+ case GCD_ADD_IO_OPERATION:
+ Entry->GcdIoType = GcdIoType;
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ Entry->ImageHandle = NULL;
+ Entry->DeviceHandle = NULL;
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ Entry->Capabilities = 0;
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ Entry->GcdIoType = EfiGcdIoTypeNonExistent;
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if (CpuArchAttributes == 0) {
+ //
+ // Keep original CPU arch attributes when caller just calls
+ // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
+ //
+ Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
+ Entry->Attributes = Attributes;
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ Entry->Capabilities = Capabilities;
+ break;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+ if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check whether an entry could be used to allocate space.
+
+ @param Operation Allocate memory or IO
+ @param Entry The entry to be tested
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+
+ @retval EFI_NOT_FOUND The memory type does not match or there's an
+ image handle on the entry.
+ @retval EFI_UNSUPPORTED The operation unsupported.
+ @retval EFI_SUCCESS It's ok for this entry to be used to allocate
+ space.
+
+**/
+EFI_STATUS
+CoreAllocateSpaceCheckEntry (
+ IN UINTN Operation,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType
+ )
+{
+ if (Entry->ImageHandle != NULL) {
+ return EFI_NOT_FOUND;
+ }
+ switch (Operation) {
+ case GCD_ALLOCATE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType != GcdMemoryType) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ case GCD_ALLOCATE_IO_OPERATION:
+ if (Entry->GcdIoType != GcdIoType) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate space on specified address and length.
+
+ @param Operation The type of operation (memory or IO)
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor for the desired space exists.
+ @retval EFI_SUCCESS Space successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AlignmentMask;
+ EFI_PHYSICAL_ADDRESS MaxAddress;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *SubLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ BOOLEAN Found;
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BaseAddress == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ImageHandle == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Alignment >= 64) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Found = FALSE;
+ StartLink = NULL;
+ EndLink = NULL;
+ //
+ // Compute alignment bit mask
+ //
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+
+ if (GcdAllocateType == EfiGcdAllocateAddress) {
+ //
+ // Verify that the BaseAddress passed in is aligned correctly
+ //
+ if ((*BaseAddress & AlignmentMask) != 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ Found = TRUE;
+ } else {
+
+ Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ //
+ // Compute the maximum address to use in the search algorithm
+ //
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
+ GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ) {
+ MaxAddress = *BaseAddress;
+ } else {
+ MaxAddress = Entry->EndAddress;
+ }
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
+ Link = Map->BackLink;
+ } else {
+ Link = Map->ForwardLink;
+ }
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
+ Link = Link->BackLink;
+ } else {
+ Link = Link->ForwardLink;
+ }
+
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
+ if ((Entry->BaseAddress + Length) > MaxAddress) {
+ continue;
+ }
+ if (Length > (Entry->EndAddress + 1)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->EndAddress > MaxAddress) {
+ *BaseAddress = MaxAddress;
+ } else {
+ *BaseAddress = Entry->EndAddress;
+ }
+ *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
+ } else {
+ *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
+ if ((*BaseAddress + Length - 1) > MaxAddress) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ Link = StartLink;
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Found = TRUE;
+ SubLink = StartLink;
+ while (SubLink != EndLink->ForwardLink) {
+ Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ Link = SubLink;
+ Found = FALSE;
+ break;
+ }
+ SubLink = SubLink->ForwardLink;
+ }
+ if (Found) {
+ break;
+ }
+ }
+ }
+ if (!Found) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
+ Entry->ImageHandle = ImageHandle;
+ Entry->DeviceHandle = DeviceHandle;
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r", Status));
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+ if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Add a segment of memory to GCD map.
+
+ @param GcdMemoryType Memory type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+ @param Capabilities alterable attributes of the segment.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameters.
+ @retval EFI_SUCCESS Successfully add a segment of memory space.
+
+**/
+EFI_STATUS
+CoreInternalAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ //
+ // Make sure parameters are valid
+ //
+ if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
+}
+
+//
+// GCD Core Services
+//
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_MEMORY_OPERATION,
+ GcdAllocateType,
+ GcdMemoryType,
+ (EFI_GCD_IO_TYPE) 0,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PageBaseAddress;
+ UINT64 PageLength;
+
+ Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
+
+ if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
+
+ PageBaseAddress = PageAlignAddress (BaseAddress);
+ PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
+
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ PageLength,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ RShiftU64 (PageLength, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+ } else {
+ for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ EFI_PAGE_SIZE,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ 1,
+ Capabilities
+ );
+ }
+ }
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Build a memory descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildMemoryDescriptor (
+ IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->Capabilities = Entry->Capabilities;
+ Descriptor->Attributes = Entry->Attributes;
+ Descriptor->GcdMemoryType = Entry->GcdMemoryType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ return Status;
+}
+
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
+
+ return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
+}
+
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
+ if (!EFI_ERROR(Status)) {
+ CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
+ }
+
+ return Status;
+}
+
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
+ UINTN DescriptorCount;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MemorySpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfDescriptors = 0;
+ *MemorySpaceMap = NULL;
+
+ //
+ // Take the lock, for entering the loop with the lock held.
+ //
+ CoreAcquireGcdMemoryLock ();
+ while (TRUE) {
+ //
+ // Count descriptors. It might be done more than once because the
+ // AllocatePool() called below has to be running outside the GCD lock.
+ //
+ DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
+ if (DescriptorCount == *NumberOfDescriptors && *MemorySpaceMap != NULL) {
+ //
+ // Fill in the MemorySpaceMap if no memory space map change.
+ //
+ Descriptor = *MemorySpaceMap;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+ //
+ // We're done; exit the loop with the lock held.
+ //
+ break;
+ }
+
+ //
+ // Release the lock before memory allocation, because it might cause
+ // GCD lock conflict in one of calling path in AllocatPool().
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ //
+ // Allocate memory to store the MemorySpaceMap. Note it might be already
+ // allocated if there's map descriptor change during memory allocation at
+ // last time.
+ //
+ if (*MemorySpaceMap != NULL) {
+ FreePool (*MemorySpaceMap);
+ }
+
+ *MemorySpaceMap = AllocatePool (DescriptorCount *
+ sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
+ if (*MemorySpaceMap == NULL) {
+ *NumberOfDescriptors = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save the descriptor count got before for another round of check to make
+ // sure we won't miss any, since we have code running outside the GCD lock.
+ //
+ *NumberOfDescriptors = DescriptorCount;
+ //
+ // Re-acquire the lock, for the next iteration.
+ //
+ CoreAcquireGcdMemoryLock ();
+ }
+ //
+ // We exited the loop with the lock held, release it.
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+
+ //
+ // Make sure parameters are valid
+ //
+ if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_IO_OPERATION,
+ GcdAllocateType,
+ (EFI_GCD_MEMORY_TYPE) 0,
+ GcdIoType,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Build a IO descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildIoDescriptor (
+ IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->GcdIoType = Entry->GcdIoType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdIoLock ();
+
+ return Status;
+}
+
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (IoSpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Count the number of descriptors
+ //
+ *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
+
+ //
+ // Allocate the IoSpaceMap
+ //
+ *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
+ if (*IoSpaceMap == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Fill in the IoSpaceMap
+ //
+ Descriptor = *IoSpaceMap;
+ Link = mGcdIoSpaceMap.ForwardLink;
+ while (Link != &mGcdIoSpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseGcdIoLock ();
+ return Status;
+}
+
+
+/**
+ Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
+ capabilities mask
+
+ @param GcdMemoryType Type of resource in the GCD memory map.
+ @param Attributes The attribute mask in the Resource Descriptor
+ HOB.
+
+ @return The capabilities mask for an EFI Memory Descriptor.
+
+**/
+UINT64
+CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ UINT64 Attributes
+ )
+{
+ UINT64 Capabilities;
+ GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
+ if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
+ if (Attributes & Conversion->Attribute) {
+ Capabilities |= Conversion->Capability;
+ }
+ }
+ }
+
+ return Capabilities;
+}
+
+/**
+ Calculate total memory bin size neeeded.
+
+ @return The total memory bin size neeeded.
+
+**/
+UINT64
+CalculateTotalMemoryBinSizeNeeded (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT64 TotalSize;
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ TotalSize = 0;
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
+ }
+
+ return TotalSize;
+}
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
+ UINTN DataSize;
+ BOOLEAN Found;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ UINT64 Attributes;
+ UINT64 Capabilities;
+ EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
+ UINT64 TestedMemoryLength;
+ EFI_PHYSICAL_ADDRESS HighAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT32 ReservedCodePageNumber;
+ UINT64 MinimalMemorySizeNeeded;
+
+ //
+ // Point at the first HOB. This must be the PHIT HOB.
+ //
+ Hob.Raw = *HobStart;
+ ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
+
+ //
+ // Initialize the spin locks and maps in the memory services.
+ // Also fill in the memory services into the EFI Boot Services Table
+ //
+ CoreInitializePool ();
+
+ //
+ // Initialize Local Variables
+ //
+ PhitResourceHob = NULL;
+ ResourceHob = NULL;
+ BaseAddress = 0;
+ Length = 0;
+ Attributes = 0;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = Hob.HandoffInformationTable;
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+
+ //
+ // cache the Top address for loading modules at Fixed Address
+ //
+ gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
+ + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
+ }
+ //
+ // See if a Memory Type Information HOB is available
+ //
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob != NULL) {
+ EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+ if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
+ CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
+ }
+ }
+
+ //
+ // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
+ //
+ MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
+
+ //
+ // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ Found = FALSE;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
+ continue;
+ }
+ if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
+ continue;
+ }
+
+ //
+ // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
+ //
+ PhitResourceHob = ResourceHob;
+ Found = TRUE;
+
+ //
+ // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
+ //
+ Attributes = PhitResourceHob->ResourceAttribute;
+ BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
+ Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
+ //
+ BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
+ Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
+ //
+ BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
+ }
+ }
+ break;
+ }
+
+ //
+ // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
+ //
+ ASSERT (Found);
+
+ //
+ // Take the range in the resource descriptor HOB for the memory region described
+ // by the PHIT as higher priority if it is big enough. It can make the memory bin
+ // allocated to be at the same memory region with PHIT that has more better compatibility
+ // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
+ //
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
+ // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
+ // The max address must be within the physically addressible range for the processor.
+ //
+ HighAddress = MAX_ALLOC_ADDRESS;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // Skip the Resource Descriptor HOB that contains the PHIT
+ //
+ if (Hob.ResourceDescriptor == PhitResourceHob) {
+ continue;
+ }
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+ if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
+ //
+ if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
+ //
+ TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
+ if (TestedMemoryLength < MinimalMemorySizeNeeded) {
+ continue;
+ }
+
+ //
+ // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
+ //
+ BaseAddress = TestedMemoryBaseAddress;
+ Length = TestedMemoryLength;
+ Attributes = ResourceHob->ResourceAttribute;
+ HighAddress = ResourceHob->PhysicalStart;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n"));
+ DEBUG ((EFI_D_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
+
+ //
+ // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
+ //
+ ASSERT (Length >= MinimalMemorySizeNeeded);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
+ } else {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
+ }
+
+ //
+ // Declare the very first memory region, so the EFI Memory Services are available.
+ //
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+
+ *MemoryBaseAddress = BaseAddress;
+ *MemoryLength = Length;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ VOID *NewHobList;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ UINT8 SizeOfMemorySpace;
+ UINT8 SizeOfIoSpace;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_STATUS Status;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+ UINT64 Capabilities;
+ EFI_HOB_CPU * CpuHob;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
+
+ //
+ // Get the number of address lines in the I/O and Memory space for the CPU
+ //
+ CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ ASSERT (CpuHob != NULL);
+ SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
+ SizeOfIoSpace = CpuHob->SizeOfIoSpace;
+
+ //
+ // Initialize the GCD Memory Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
+
+ InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
+
+ CoreDumpGcdMemorySpaceMap (TRUE);
+
+ //
+ // Initialize the GCD I/O Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
+
+ InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
+
+ CoreDumpGcdIoSpaceMap (TRUE);
+
+ //
+ // Walk the HOB list and add all resource descriptors to the GCD
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+
+ GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ GcdIoType = EfiGcdIoTypeNonExistent;
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+
+ switch (ResourceHob->ResourceType) {
+ case EFI_RESOURCE_SYSTEM_MEMORY:
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
+ GcdMemoryType = EfiGcdMemoryTypePersistent;
+ }
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO:
+ case EFI_RESOURCE_FIRMWARE_DEVICE:
+ GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
+ case EFI_RESOURCE_MEMORY_RESERVED:
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ break;
+ case EFI_RESOURCE_IO:
+ GcdIoType = EfiGcdIoTypeIo;
+ break;
+ case EFI_RESOURCE_IO_RESERVED:
+ GcdIoType = EfiGcdIoTypeReserved;
+ break;
+ }
+
+ if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
+ //
+ // Validate the Resource HOB Attributes
+ //
+ CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ GcdMemoryType,
+ ResourceHob->ResourceAttribute
+ );
+
+ Status = CoreInternalAddMemorySpace (
+ GcdMemoryType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength,
+ Capabilities
+ );
+ }
+
+ if (GcdIoType != EfiGcdIoTypeNonExistent) {
+ Status = CoreAddIoSpace (
+ GcdIoType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength
+ );
+ }
+ }
+ }
+
+ //
+ // Allocate first memory region from the GCD by the DXE core
+ //
+ Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryLength,
+ &MemoryBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ //
+ // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
+ // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryHob->AllocDescriptor.MemoryLength,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status) &&
+ ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
+ CoreAddMemoryDescriptor (
+ MemoryHob->AllocDescriptor.MemoryType,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
+ Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+ }
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ FirmwareVolumeHob = Hob.FirmwareVolume;
+ BaseAddress = FirmwareVolumeHob->BaseAddress;
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ FirmwareVolumeHob->Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+
+ //
+ // Add and allocate the remaining unallocated system memory to the memory services.
+ //
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS);
+
+ MemorySpaceMapHobList = NULL;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
+ if (MemorySpaceMap[Index].ImageHandle == NULL) {
+ BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
+ Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
+ if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
+ continue;
+ }
+ if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) &&
+ ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) {
+ //
+ // Skip the memory space that covers HOB List, it should be processed
+ // after HOB List relocation to avoid the resources allocated by others
+ // to corrupt HOB List before its relocation.
+ //
+ MemorySpaceMapHobList = &MemorySpaceMap[Index];
+ continue;
+ }
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMap[Index].GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+ }
+
+ //
+ // Relocate HOB List to an allocated pool buffer.
+ // The relocation should be at after all the tested memory resources added
+ // (except the memory space that covers HOB List) to the memory services,
+ // because the memory resource found in CoreInitializeMemoryServices()
+ // may have not enough remaining resource for HOB List.
+ //
+ NewHobList = AllocateCopyPool (
+ (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart),
+ *HobStart
+ );
+ ASSERT (NewHobList != NULL);
+
+ *HobStart = NewHobList;
+ gHobList = NewHobList;
+
+ if (MemorySpaceMapHobList != NULL) {
+ //
+ // Add and allocate the memory space that covers HOB List to the memory services
+ // after HOB List relocation.
+ //
+ BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
+ Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMapHobList->GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ CoreFreePool (MemorySpaceMap);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
new file mode 100644
index 000000000..715687b92
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
@@ -0,0 +1,40 @@
+/** @file
+ GCD Operations and data structure used to
+ convert from GCD attributes to EFI Memory Map attributes.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GCD_H_
+#define _GCD_H_
+
+//
+// GCD Operations
+//
+#define GCD_MEMORY_SPACE_OPERATION 0x20
+#define GCD_IO_SPACE_OPERATION 0x40
+
+#define GCD_ADD_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 1)
+#define GCD_FREE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 2)
+#define GCD_REMOVE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 3)
+#define GCD_SET_ATTRIBUTES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 4)
+#define GCD_SET_CAPABILITIES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 5)
+
+#define GCD_ADD_IO_OPERATION (GCD_IO_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 1)
+#define GCD_FREE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 2)
+#define GCD_REMOVE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 3)
+
+//
+// The data structure used to convert from GCD attributes to EFI Memory Map attributes
+//
+typedef struct {
+ UINT64 Attribute;
+ UINT64 Capability;
+ BOOLEAN Memory;
+} GCD_ATTRIBUTE_CONVERSION_ENTRY;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
new file mode 100644
index 000000000..feabf12fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
@@ -0,0 +1,958 @@
+/** @file
+ Support functions to connect/disconnect UEFI Driver model Protocol
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+
+//
+// Driver Support Functions
+//
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_DEVICE_PATH_PROTOCOL *AlignedRemainingDevicePath;
+ EFI_HANDLE *ChildHandleBuffer;
+ UINTN ChildHandleCount;
+ UINTN Index;
+ UINTN HandleFilePathSize;
+ UINTN RemainingDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Check whether the user has permission to start UEFI device drivers.
+ //
+ Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (HandleFilePath != NULL);
+ FilePath = HandleFilePath;
+ TempFilePath = NULL;
+ if (RemainingDevicePath != NULL && !Recursive) {
+ HandleFilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath);
+ TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize);
+ ASSERT (TempFilePath != NULL);
+ CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize);
+ CopyMem ((UINT8 *) TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize);
+ FilePath = TempFilePath;
+ }
+ Status = gSecurity2->FileAuthentication (
+ gSecurity2,
+ FilePath,
+ NULL,
+ 0,
+ FALSE
+ );
+ if (TempFilePath != NULL) {
+ FreePool (TempFilePath);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ Handle = ControllerHandle;
+
+ //
+ // Make a copy of RemainingDevicePath to guanatee it is aligned
+ //
+ AlignedRemainingDevicePath = NULL;
+ if (RemainingDevicePath != NULL) {
+ AlignedRemainingDevicePath = DuplicateDevicePath (RemainingDevicePath);
+
+ if (AlignedRemainingDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Connect all drivers to ControllerHandle
+ // If CoreConnectSingleController returns EFI_NOT_READY, then the number of
+ // Driver Binding Protocols in the handle database has increased during the call
+ // so the connect operation must be restarted
+ //
+ do {
+ ReturnStatus = CoreConnectSingleController (
+ ControllerHandle,
+ DriverImageHandle,
+ AlignedRemainingDevicePath
+ );
+ } while (ReturnStatus == EFI_NOT_READY);
+
+ //
+ // Free the aligned copy of RemainingDevicePath
+ //
+ if (AlignedRemainingDevicePath != NULL) {
+ CoreFreePool (AlignedRemainingDevicePath);
+ }
+
+ //
+ // If recursive, then connect all drivers to all of ControllerHandle's children
+ //
+ if (Recursive) {
+ //
+ // Acquire the protocol lock on the handle database so the child handles can be collected
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ return ReturnStatus;
+ }
+
+
+ //
+ // Count ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Allocate a handle buffer for ControllerHandle's children
+ //
+ ChildHandleBuffer = AllocatePool (ChildHandleCount * sizeof(EFI_HANDLE));
+ if (ChildHandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in a handle buffer with ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Recursively connect each child handle
+ //
+ for (Index = 0; Index < ChildHandleCount; Index++) {
+ CoreConnectController (
+ ChildHandleBuffer[Index],
+ NULL,
+ NULL,
+ TRUE
+ );
+ }
+
+ //
+ // Free the handle buffer of ControllerHandle's children
+ //
+ CoreFreePool (ChildHandleBuffer);
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Add Driver Binding Protocols from Context Driver Image Handles to sorted
+ Driver Binding Protocol list.
+
+ @param DriverBindingHandle Handle of the driver binding
+ protocol.
+ @param NumberOfSortedDriverBindingProtocols Number Of sorted driver binding
+ protocols
+ @param SortedDriverBindingProtocols The sorted protocol list.
+ @param DriverBindingHandleCount Driver Binding Handle Count.
+ @param DriverBindingHandleBuffer The buffer of driver binding
+ protocol to be modified.
+ @param IsImageHandle Indicate whether
+ DriverBindingHandle is an image
+ handle
+
+ @return None.
+
+**/
+VOID
+AddSortedDriverBindingProtocol (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN OUT UINTN *NumberOfSortedDriverBindingProtocols,
+ IN OUT EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols,
+ IN UINTN DriverBindingHandleCount,
+ IN OUT EFI_HANDLE *DriverBindingHandleBuffer,
+ IN BOOLEAN IsImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ UINTN Index;
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ Status = CoreValidateHandle (DriverBindingHandle);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // If IsImageHandle is TRUE, then DriverBindingHandle is an image handle
+ // Find all the DriverBindingHandles associated with that image handle and add them to the sorted list
+ //
+ if (IsImageHandle) {
+ //
+ // Loop through all the Driver Binding Handles
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ //
+ // Retrieve the Driver Binding Protocol associated with each Driver Binding Handle
+ //
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ continue;
+ }
+
+ //
+ // If the ImageHandle associated with DriverBinding matches DriverBindingHandle,
+ // then add the DriverBindingProtocol[Index] to the sorted list
+ //
+ if (DriverBinding->ImageHandle == DriverBindingHandle) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+ return;
+ }
+
+ //
+ // Retrieve the Driver Binding Protocol from DriverBindingHandle
+ //
+ Status = CoreHandleProtocol(
+ DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ //
+ // If DriverBindingHandle does not support the Driver Binding Protocol then return
+ //
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ return;
+ }
+
+ //
+ // See if DriverBinding is already in the sorted list
+ //
+ for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
+ if (DriverBinding == SortedDriverBindingProtocols[Index]) {
+ return;
+ }
+ }
+
+ //
+ // Add DriverBinding to the end of the list
+ //
+ if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
+ SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
+ }
+ *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;
+
+ //
+ // Mark the cooresponding handle in DriverBindingHandleBuffer as used
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
+ DriverBindingHandleBuffer[Index] = NULL;
+ }
+ }
+}
+
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE DriverImageHandle;
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ UINTN NewDriverBindingHandleCount;
+ EFI_HANDLE *NewDriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL *DriverFamilyOverride;
+ UINTN NumberOfSortedDriverBindingProtocols;
+ EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols;
+ UINT32 DriverFamilyOverrideVersion;
+ UINT32 HighestVersion;
+ UINTN HighestIndex;
+ UINTN SortIndex;
+ BOOLEAN OneStarted;
+ BOOLEAN DriverFound;
+
+ //
+ // Initialize local variables
+ //
+ DriverBindingHandleCount = 0;
+ DriverBindingHandleBuffer = NULL;
+ NumberOfSortedDriverBindingProtocols = 0;
+ SortedDriverBindingProtocols = NULL;
+ PlatformDriverOverride = NULL;
+ NewDriverBindingHandleBuffer = NULL;
+
+ //
+ // Get list of all Driver Binding Protocol Instances
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a duplicate array for the sorted Driver Binding Protocol Instances
+ //
+ SortedDriverBindingProtocols = AllocatePool (sizeof (VOID *) * DriverBindingHandleCount);
+ if (SortedDriverBindingProtocols == NULL) {
+ CoreFreePool (DriverBindingHandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add Driver Binding Protocols from Context Driver Image Handles first
+ //
+ if (ContextDriverImageHandles != NULL) {
+ for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) {
+ AddSortedDriverBindingProtocol (
+ ContextDriverImageHandles[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+
+ //
+ // Add the Platform Driver Override Protocol drivers for ControllerHandle next
+ //
+ Status = CoreLocateProtocol (
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = PlatformDriverOverride->GetDriver (
+ PlatformDriverOverride,
+ ControllerHandle,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Add the Driver Family Override Protocol drivers for ControllerHandle
+ //
+ while (TRUE) {
+ HighestIndex = DriverBindingHandleCount;
+ HighestVersion = 0;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverFamilyOverrideProtocolGuid,
+ (VOID **) &DriverFamilyOverride
+ );
+ if (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
+ DriverFamilyOverrideVersion = DriverFamilyOverride->GetVersion (DriverFamilyOverride);
+ if ((HighestIndex == DriverBindingHandleCount) || (DriverFamilyOverrideVersion > HighestVersion)) {
+ HighestVersion = DriverFamilyOverrideVersion;
+ HighestIndex = Index;
+ }
+ }
+ }
+
+ if (HighestIndex == DriverBindingHandleCount) {
+ break;
+ }
+
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[HighestIndex],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = CoreHandleProtocol (
+ ControllerHandle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Then add all the remaining Driver Binding Protocols
+ //
+ SortIndex = NumberOfSortedDriverBindingProtocols;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Free the Driver Binding Handle Buffer
+ //
+ CoreFreePool (DriverBindingHandleBuffer);
+
+ //
+ // If the number of Driver Binding Protocols has increased since this function started, then return
+ // EFI_NOT_READY, so it will be restarted
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &NewDriverBindingHandleCount,
+ &NewDriverBindingHandleBuffer
+ );
+ CoreFreePool (NewDriverBindingHandleBuffer);
+ if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Sort the remaining DriverBinding Protocol based on their Version field from
+ // highest to lowest.
+ //
+ for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
+ HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
+ HighestIndex = SortIndex;
+ for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
+ if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
+ HighestVersion = SortedDriverBindingProtocols[Index]->Version;
+ HighestIndex = Index;
+ }
+ }
+ if (SortIndex != HighestIndex) {
+ DriverBinding = SortedDriverBindingProtocols[SortIndex];
+ SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
+ SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
+ }
+ }
+
+ //
+ // Loop until no more drivers can be started on ControllerHandle
+ //
+ OneStarted = FALSE;
+ do {
+
+ //
+ // Loop through the sorted Driver Binding Protocol Instances in order, and see if
+ // any of the Driver Binding Protocols support the controller specified by
+ // ControllerHandle.
+ //
+ DriverBinding = NULL;
+ DriverFound = FALSE;
+ for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
+ if (SortedDriverBindingProtocols[Index] != NULL) {
+ DriverBinding = SortedDriverBindingProtocols[Index];
+ PERF_DRIVER_BINDING_SUPPORT_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Supported(
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_SUPPORT_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+ if (!EFI_ERROR (Status)) {
+ SortedDriverBindingProtocols[Index] = NULL;
+ DriverFound = TRUE;
+
+ //
+ // A driver was found that supports ControllerHandle, so attempt to start the driver
+ // on ControllerHandle.
+ //
+ PERF_DRIVER_BINDING_START_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Start (
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_START_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The driver was successfully started on ControllerHandle, so set a flag
+ //
+ OneStarted = TRUE;
+ }
+ }
+ }
+ }
+ } while (DriverFound);
+
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ //
+ // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS.
+ //
+ if (OneStarted) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
+ //
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ EFI_HANDLE *DriverImageHandleBuffer;
+ EFI_HANDLE *ChildBuffer;
+ UINTN Index;
+ UINTN HandleIndex;
+ UINTN DriverImageHandleCount;
+ UINTN ChildrenToStop;
+ UINTN ChildBufferCount;
+ UINTN StopCount;
+ BOOLEAN Duplicate;
+ BOOLEAN ChildHandleValid;
+ BOOLEAN DriverImageHandleValid;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ PROTOCOL_INTERFACE *Prot;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Make sure ChildHandle is valid if it is not NULL
+ //
+ if (ChildHandle != NULL) {
+ Status = CoreValidateHandle (ChildHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Handle = ControllerHandle;
+
+ //
+ // Get list of drivers that are currently managing ControllerHandle
+ //
+ DriverImageHandleBuffer = NULL;
+ DriverImageHandleCount = 1;
+
+ if (DriverImageHandle == NULL) {
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleCount++;
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+
+ //
+ // If there are no drivers managing this controller, then return EFI_SUCCESS
+ //
+ if (DriverImageHandleCount == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE) * DriverImageHandleCount);
+ if (DriverImageHandleBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Duplicate = FALSE;
+ for (Index = 0; Index< DriverImageHandleCount; Index++) {
+ if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+ if (!Duplicate) {
+ DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle;
+ DriverImageHandleCount++;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+ }
+
+ StopCount = 0;
+ for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) {
+
+ if (DriverImageHandleBuffer != NULL) {
+ DriverImageHandle = DriverImageHandleBuffer[HandleIndex];
+ }
+
+ //
+ // Get the Driver Binding Protocol of the driver that is managing this controller
+ //
+ Status = CoreHandleProtocol (
+ DriverImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding
+ );
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleValid = FALSE;
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if (OpenData->AgentHandle == DriverImageHandle) {
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildBufferCount++;
+ }
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleValid = TRUE;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+
+ if (DriverImageHandleValid) {
+ ChildHandleValid = FALSE;
+ ChildBuffer = NULL;
+ if (ChildBufferCount != 0) {
+ ChildBuffer = AllocatePool (sizeof (EFI_HANDLE) * ChildBufferCount);
+ if (ChildBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->AgentHandle == DriverImageHandle) &&
+ ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0)) {
+ Duplicate = FALSE;
+ for (Index = 0; Index < ChildBufferCount; Index++) {
+ if (ChildBuffer[Index] == OpenData->ControllerHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+ if (!Duplicate) {
+ ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle;
+ if (ChildHandle == ChildBuffer[ChildBufferCount]) {
+ ChildHandleValid = TRUE;
+ }
+ ChildBufferCount++;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+ }
+
+ if (ChildHandle == NULL || ChildHandleValid) {
+ ChildrenToStop = 0;
+ Status = EFI_SUCCESS;
+ if (ChildBufferCount > 0) {
+ if (ChildHandle != NULL) {
+ ChildrenToStop = 1;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle);
+ } else {
+ ChildrenToStop = ChildBufferCount;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer);
+ }
+ }
+ if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) {
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL);
+ }
+ if (!EFI_ERROR (Status)) {
+ StopCount++;
+ }
+ }
+
+ if (ChildBuffer != NULL) {
+ CoreFreePool (ChildBuffer);
+ }
+ }
+ }
+
+ if (StopCount > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+Done:
+
+ if (DriverImageHandleBuffer != NULL) {
+ CoreFreePool (DriverImageHandleBuffer);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c
new file mode 100644
index 000000000..6eccb41ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c
@@ -0,0 +1,1576 @@
+/** @file
+ UEFI handle & protocol handling.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase
+// gHandleDatabaseKey - The Key to show that the handle has been created/modified
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+UINT64 gHandleDatabaseKey = 0;
+
+
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gProtocolDatabaseLock);
+}
+
+
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gProtocolDatabaseLock);
+}
+
+
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ if (UserHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle == (IHANDLE *) UserHandle) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ ASSERT_LOCKED(&gProtocolDatabaseLock);
+
+ //
+ // Search the database for the matching GUID
+ //
+
+ ProtEntry = NULL;
+ for (Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {
+
+ //
+ // This is the protocol entry
+ //
+
+ ProtEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((ProtEntry == NULL) && Create) {
+ ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
+
+ if (ProtEntry != NULL) {
+ //
+ // Initialize new protocol entry structure
+ //
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
+ InitializeListHead (&ProtEntry->Protocols);
+ InitializeListHead (&ProtEntry->Notify);
+
+ //
+ // Add it to protocol database
+ //
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
+ }
+ }
+
+ return ProtEntry;
+}
+
+
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED(&gProtocolDatabaseLock);
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (ProtEntry != NULL) {
+
+ //
+ // Look at each protocol interface for any matches
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
+
+ //
+ // If this protocol interface matches, remove it
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
+ break;
+ }
+
+ Prot = NULL;
+ }
+ }
+
+ return Prot;
+}
+
+
+/**
+ Removes an event from a register protocol notify list on a protocol.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS if the event was found and removed.
+ @return EFI_NOT_FOUND if the event was not found in the protocl database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotifyEvent (
+ IN EFI_EVENT Event
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *NotifyLink;
+ PROTOCOL_NOTIFY *ProtNotify;
+
+ CoreAcquireProtocolLock ();
+
+ for ( Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ ProtEntry = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+
+ for ( NotifyLink = ProtEntry->Notify.ForwardLink;
+ NotifyLink != &ProtEntry->Notify;
+ NotifyLink = NotifyLink->ForwardLink) {
+
+ ProtNotify = CR(NotifyLink, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Event == Event) {
+ RemoveEntryList(&ProtNotify->Link);
+ CoreFreePool(ProtNotify);
+ CoreReleaseProtocolLock ();
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ Status = CoreUnregisterProtocolNotifyEvent (Event);
+ } while (!EFI_ERROR (Status));
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return CoreInstallProtocolInterfaceNotify (
+ UserHandle,
+ Protocol,
+ InterfaceType,
+ Interface,
+ TRUE
+ );
+}
+
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ IHANDLE *Handle;
+ EFI_STATUS Status;
+ VOID *ExistingInterface;
+
+ //
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
+ // Also added check for invalid UserHandle and Protocol pointers.
+ //
+ if (UserHandle == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print debug message
+ //
+ DEBUG((DEBUG_INFO, "InstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ //
+ // Allocate a new protocol interface structure
+ //
+ Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
+ if (Prot == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // If caller didn't supply a handle, allocate a new one
+ //
+ Handle = (IHANDLE *)*UserHandle;
+ if (Handle == NULL) {
+ Handle = AllocateZeroPool (sizeof(IHANDLE));
+ if (Handle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize new handler structure
+ //
+ Handle->Signature = EFI_HANDLE_SIGNATURE;
+ InitializeListHead (&Handle->Protocols);
+
+ //
+ // Initialize the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ } else {
+ Status = CoreValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
+ goto Done;
+ }
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // Initalize OpenProtocol Data base
+ //
+ InitializeListHead (&Prot->OpenList);
+ Prot->OpenListCount = 0;
+
+ //
+ // Add this protocol interface to the head of the supported
+ // protocol list for this handle
+ //
+ InsertHeadList (&Handle->Protocols, &Prot->Link);
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Notify the notification list for this protocol
+ //
+ if (Notify) {
+ CoreNotifyProtocolEntry (ProtEntry);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ CoreFreePool (Prot);
+ }
+ DEBUG((DEBUG_ERROR, "InstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
+ }
+
+ return Status;
+}
+
+
+
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The pointer to a handle to install the new
+ protocol interfaces on, or a pointer to NULL
+ if a new handle is to be allocated.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_STATUS Status;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_HANDLE OldHandle;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Syncronize with notifcations.
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ OldHandle = *Handle;
+
+ //
+ // Check for duplicate device path and install the protocol interfaces
+ //
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Make sure you are installing on top a device path that has already been added.
+ //
+ if (CompareGuid (Protocol, &gEfiDevicePathProtocolGuid)) {
+ DeviceHandle = NULL;
+ DevicePath = Interface;
+ Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(DevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ continue;
+ }
+ }
+
+ //
+ // Install it
+ //
+ Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+ VA_END (Args);
+
+ //
+ // If there was an error, remove all the interfaces that were installed without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for (; Index > 1; Index--) {
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ Interface = VA_ARG (Args, VOID *);
+ CoreUninstallProtocolInterface (*Handle, Protocol, Interface);
+ }
+ VA_END (Args);
+
+ *Handle = OldHandle;
+ }
+
+ //
+ // Done
+ //
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN ItemFound;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Attempt to disconnect all drivers from this protocol interface
+ //
+ do {
+ ItemFound = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ ItemFound = TRUE;
+ }
+ break;
+ }
+ }
+ } while (ItemFound);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items
+ //
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList;) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes &
+ (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) != 0) {
+ Link = RemoveEntryList (&OpenData->Link);
+ Prot->OpenListCount--;
+ CoreFreePool (OpenData);
+ } else {
+ Link = Link->ForwardLink;
+ }
+ }
+ }
+
+ //
+ // If there are errors or still has open items in the list, then reconnect all the drivers and return an error
+ //
+ if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) {
+ CoreReleaseProtocolLock ();
+ CoreConnectController (UserHandle, NULL, NULL, TRUE);
+ CoreAcquireProtocolLock ();
+ Status = EFI_ACCESS_DENIED;
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check that Protocol is valid
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that UserHandle is a valid handle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ CoreFreePool (Prot);
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // If there are no more handlers for the handle, free the handle
+ //
+ if (IsListEmpty (&Handle->Protocols)) {
+ Handle->Signature = 0;
+ RemoveEntryList (&Handle->AllHandles);
+ CoreFreePool (Handle);
+ }
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UninstallProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ If any errors are generated while the protocol interfaces are being
+ uninstalled, then the protocol interfaces uninstalled prior to the error will
+ be reinstalled and EFI_INVALID_PARAMETER will be returned.
+
+ @param Handle The handle to uninstall the protocol interfaces
+ from.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @retval EFI_SUCCESS if all protocol interfaces where uninstalled.
+ @retval EFI_INVALID_PARAMETER if any protocol interface could not be
+ uninstalled and an attempt was made to
+ reinstall previously uninstalled protocol
+ interfaces.
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ UINTN Index;
+
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Uninstall it
+ //
+ Status = CoreUninstallProtocolInterface (Handle, Protocol, Interface);
+ }
+ VA_END (Args);
+
+ //
+ // If there was an error, add all the interfaces that were
+ // uninstalled without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for (; Index > 1; Index--) {
+ Protocol = VA_ARG(Args, EFI_GUID *);
+ Interface = VA_ARG(Args, VOID *);
+ CoreInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+ VA_END (Args);
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+
+/**
+ Locate a certain GUID protocol interface in a Handle's protocols.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The GUID of the protocol
+
+ @return The requested protocol interface for the handle
+
+**/
+PROTOCOL_INTERFACE *
+CoreGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ //
+ // Look at each protocol interface for a match
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ ProtEntry = Prot->Protocol;
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
+ return Prot;
+ }
+ }
+ return NULL;
+}
+
+
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is NULL..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ return CoreOpenProtocol (
+ UserHandle,
+ Protocol,
+ Interface,
+ gDxeCoreImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+}
+
+
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ BOOLEAN ByDriver;
+ BOOLEAN Exclusive;
+ BOOLEAN Disconnect;
+ BOOLEAN ExactMatch;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if ((Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) && (Interface == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check for invalid Attributes
+ //
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (UserHandle == ControllerHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER :
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL :
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+
+ ByDriver = FALSE;
+ Exclusive = FALSE;
+ for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ ExactMatch = (BOOLEAN)((OpenData->AgentHandle == ImageHandle) &&
+ (OpenData->Attributes == Attributes) &&
+ (OpenData->ControllerHandle == ControllerHandle));
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ ByDriver = TRUE;
+ if (ExactMatch) {
+ Status = EFI_ALREADY_STARTED;
+ goto Done;
+ }
+ }
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) != 0) {
+ Exclusive = TRUE;
+ } else if (ExactMatch) {
+ OpenData->OpenCount++;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // ByDriver TRUE -> A driver is managing (UserHandle, Protocol)
+ // ByDriver FALSE -> There are no drivers managing (UserHandle, Protocol)
+ // Exclusive TRUE -> Something has exclusive access to (UserHandle, Protocol)
+ // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol)
+ //
+
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_DRIVER :
+ if (Exclusive || ByDriver) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ if (Exclusive) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ if (ByDriver) {
+ do {
+ Disconnect = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Disconnect = TRUE;
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ } else {
+ break;
+ }
+ }
+ }
+ } while (Disconnect);
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER :
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL :
+ break;
+ }
+
+ if (ImageHandle == NULL) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Create new entry
+ //
+ OpenData = AllocatePool (sizeof(OPEN_PROTOCOL_DATA));
+ if (OpenData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ OpenData->Signature = OPEN_PROTOCOL_DATA_SIGNATURE;
+ OpenData->AgentHandle = ImageHandle;
+ OpenData->ControllerHandle = ControllerHandle;
+ OpenData->Attributes = Attributes;
+ OpenData->OpenCount = 1;
+ InsertTailList (&Prot->OpenList, &OpenData->Link);
+ Prot->OpenListCount++;
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+
+ if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
+ //
+ // Keep Interface unmodified in case of any Error
+ // except EFI_ALREADY_STARTED and EFI_UNSUPPORTED.
+ //
+ if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) {
+ //
+ // According to above logic, if 'Prot' is NULL, then the 'Status' must be
+ // EFI_UNSUPPORTED. Here the 'Status' is not EFI_UNSUPPORTED, so 'Prot'
+ // must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (Prot != NULL);
+ //
+ // EFI_ALREADY_STARTED is not an error for bus driver.
+ // Return the corresponding protocol interface.
+ //
+ *Interface = Prot->Interface;
+ } else if (Status == EFI_UNSUPPORTED) {
+ //
+ // Return NULL Interface if Unsupported Protocol.
+ //
+ *Interface = NULL;
+ }
+ }
+
+ //
+ // Done. Release the database lock and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ //
+ // Check for invalid parameters
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (AgentHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (ControllerHandle != NULL) {
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Walk the Open data base looking for AgentHandle
+ //
+ Link = ProtocolInterface->OpenList.ForwardLink;
+ while (Link != &ProtocolInterface->OpenList) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ Link = Link->ForwardLink;
+ if ((OpenData->AgentHandle == AgentHandle) && (OpenData->ControllerHandle == ControllerHandle)) {
+ RemoveEntryList (&OpenData->Link);
+ ProtocolInterface->OpenListCount--;
+ CoreFreePool (OpenData);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+Done:
+ //
+ // Done. Release the database lock and return.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol information in the
+ form of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+ @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer,
+ and the number of entries was returned EntryCount.
+ @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Buffer;
+ UINTN Count;
+ UINTN Size;
+
+ *EntryBuffer = NULL;
+ *EntryCount = 0;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Count the number of Open Entries
+ //
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList) ;
+ Link = Link->ForwardLink ) {
+ Count++;
+ }
+
+ ASSERT (Count == ProtocolInterface->OpenListCount);
+
+ if (Count == 0) {
+ Size = sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ } else {
+ Size = Count * sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ }
+
+ Buffer = AllocatePool (Size);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList);
+ Link = Link->ForwardLink, Count++ ) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+
+ Buffer[Count].AgentHandle = OpenData->AgentHandle;
+ Buffer[Count].ControllerHandle = OpenData->ControllerHandle;
+ Buffer[Count].Attributes = OpenData->Attributes;
+ Buffer[Count].OpenCount = OpenData->OpenCount;
+ }
+
+ *EntryBuffer = Buffer;
+ *EntryCount = Count;
+
+Done:
+ //
+ // Done. Release the database lock.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ UINTN ProtocolCount;
+ EFI_GUID **Buffer;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ if (ProtocolBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProtocolBufferCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ProtocolBufferCount = 0;
+
+ ProtocolCount = 0;
+
+ CoreAcquireProtocolLock ();
+
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ ProtocolCount++;
+ }
+
+ //
+ // If there are no protocol interfaces installed on Handle, then Handle is not a valid EFI_HANDLE
+ //
+ if (ProtocolCount == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Buffer = AllocatePool (sizeof (EFI_GUID *) * ProtocolCount);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ *ProtocolBuffer = Buffer;
+ *ProtocolBufferCount = ProtocolCount;
+
+ for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0;
+ Link != &Handle->Protocols;
+ Link = Link->ForwardLink, ProtocolCount++) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ )
+{
+ return gHandleDatabaseKey;
+}
+
+
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+ EFI_HANDLE *HandleBuffer;
+ IHANDLE *Handle;
+ UINTN Index;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ Count++;
+ }
+ }
+
+ HandleBuffer = AllocatePool (Count * sizeof (EFI_HANDLE));
+ if (HandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return;
+ }
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ HandleBuffer[Count++] = Handle;
+ }
+ }
+
+ //
+ // Unlock the protocol database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Connect all handles whose Key value is greater than Key
+ //
+ for (Index = 0; Index < Count; Index++) {
+ CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ CoreFreePool(HandleBuffer);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h
new file mode 100644
index 000000000..83eb2b9f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h
@@ -0,0 +1,264 @@
+/** @file
+ Support functions for managing protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HAND_H_
+#define _HAND_H_
+
+
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+ /// The Handle Database Key value when this handle was last created or modified
+ UINT64 Key;
+} IHANDLE;
+
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
+
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registerd notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+ /// OPEN_PROTOCOL_DATA list
+ LIST_ENTRY OpenList;
+ UINTN OpenListCount;
+
+} PROTOCOL_INTERFACE;
+
+#define OPEN_PROTOCOL_DATA_SIGNATURE SIGNATURE_32('p','o','d','l')
+
+typedef struct {
+ UINTN Signature;
+ ///Link on PROTOCOL_INTERFACE.OpenList
+ LIST_ENTRY Link;
+
+ EFI_HANDLE AgentHandle;
+ EFI_HANDLE ControllerHandle;
+ UINT32 Attributes;
+ UINT32 OpenCount;
+} OPEN_PROTOCOL_DATA;
+
+
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')
+
+///
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol
+///
+typedef struct {
+ UINTN Signature;
+ PROTOCOL_ENTRY *Protocol;
+ /// All notifications for this protocol
+ LIST_ENTRY Link;
+ /// Event to notify
+ EFI_EVENT Event;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ );
+
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ );
+
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ );
+
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ );
+
+//
+// Externs
+//
+extern EFI_LOCK gProtocolDatabaseLock;
+extern LIST_ENTRY gHandleList;
+extern UINT64 gHandleDatabaseKey;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c
new file mode 100644
index 000000000..be17f4cbc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c
@@ -0,0 +1,702 @@
+/** @file
+ Locate handle functions
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+//
+// ProtocolRequest - Last LocateHandle request ID
+//
+UINTN mEfiLocateHandleRequest = 0;
+
+//
+// Internal prototypes
+//
+
+typedef struct {
+ EFI_GUID *Protocol;
+ VOID *SearchKey;
+ LIST_ENTRY *Position;
+ PROTOCOL_ENTRY *ProtEntry;
+} LOCATE_POSITION;
+
+typedef
+IHANDLE *
+(* CORE_GET_NEXT) (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ CORE_GET_NEXT GetNext;
+ UINTN ResultSize;
+ IHANDLE *Handle;
+ IHANDLE **ResultBuffer;
+ VOID *Interface;
+
+ if (BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*BufferSize > 0) && (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetNext = NULL;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = SearchKey;
+ Position.Position = &gHandleList;
+
+ ResultSize = 0;
+ ResultBuffer = (IHANDLE **) Buffer;
+ Status = EFI_SUCCESS;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Get the search function based on type
+ //
+ switch (SearchType) {
+ case AllHandles:
+ GetNext = CoreGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ GetNext = CoreGetNextLocateByRegisterNotify;
+ break;
+
+ case ByProtocol:
+ GetNext = CoreGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR(Status)) {
+ CoreReleaseProtocolLock ();
+ return Status;
+ }
+
+ ASSERT (GetNext != NULL);
+ //
+ // Enumerate out the matching handles
+ //
+ mEfiLocateHandleRequest += 1;
+ for (; ;) {
+ //
+ // Get the next handle. If no more handles, stop
+ //
+ Handle = GetNext (&Position, &Interface);
+ if (NULL == Handle) {
+ break;
+ }
+
+ //
+ // Increase the resulting buffer size, and if this handle
+ // fits return it
+ //
+ ResultSize += sizeof(Handle);
+ if (ResultSize <= *BufferSize) {
+ *ResultBuffer = Handle;
+ ResultBuffer += 1;
+ }
+ }
+
+ //
+ // If the result is a zero length buffer, then there were no
+ // matching handles
+ //
+ if (ResultSize == 0) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ //
+ // Return the resulting buffer size. If it's larger than what
+ // was passed, then set the error code
+ //
+ if (ResultSize > *BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ResultSize;
+
+ if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ASSERT (SearchKey != NULL);
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+
+ //
+ // Next handle
+ //
+ Position->Position = Position->Position->ForwardLink;
+
+ //
+ // If not at the end of the list, get the handle
+ //
+ Handle = NULL;
+ *Interface = NULL;
+ if (Position->Position != &gHandleList) {
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ }
+
+ return Handle;
+}
+
+
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+
+ Handle = NULL;
+ *Interface = NULL;
+ ProtNotify = Position->SearchKey;
+
+ //
+ // If this is the first request, get the next handle
+ //
+ if (ProtNotify != NULL) {
+ ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
+ Position->SearchKey = NULL;
+
+ //
+ // If not at the end of the list, get the next handle
+ //
+ Link = ProtNotify->Position->ForwardLink;
+ if (Link != &ProtNotify->Protocol->Protocols) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+ }
+ }
+
+ return Handle;
+}
+
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+ PROTOCOL_INTERFACE *Prot;
+
+ Handle = NULL;
+ *Interface = NULL;
+ for (; ;) {
+ //
+ // Next entry
+ //
+ Link = Position->Position->ForwardLink;
+ Position->Position = Link;
+
+ //
+ // If not at the end, return the handle
+ //
+ if (Link == &Position->ProtEntry->Protocols) {
+ Handle = NULL;
+ break;
+ }
+
+ //
+ // Get the handle
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+
+ //
+ // If this handle has not been returned this request, then
+ // return it now
+ //
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {
+ Handle->LocateRequest = mEfiLocateHandleRequest;
+ break;
+ }
+ }
+
+ return Handle;
+}
+
+
+/**
+ Locates the handle to a device on the device path that supports the specified protocol.
+
+ @param Protocol Specifies the protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
+ path pointer is modified to point to the remaining part of the device
+ path.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ )
+{
+ INTN SourceSize;
+ INTN Size;
+ INTN BestMatch;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ EFI_HANDLE Handle;
+ EFI_HANDLE BestDevice;
+ EFI_DEVICE_PATH_PROTOCOL *SourcePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Handles = NULL;
+ BestDevice = NULL;
+ SourcePath = *DevicePath;
+ TmpDevicePath = SourcePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ if (IsDevicePathEndInstance (TmpDevicePath)) {
+ //
+ // If DevicePath is a multi-instance device path,
+ // the function will operate on the first instance
+ //
+ break;
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ SourceSize = (UINTN) TmpDevicePath - (UINTN) SourcePath;
+
+ //
+ // Get a list of all handles that support the requested protocol
+ //
+ Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status) || HandleCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestMatch = -1;
+ for(Index = 0; Index < HandleCount; Index += 1) {
+ Handle = Handles[Index];
+ Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // If this handle doesn't support device path, then skip it
+ //
+ continue;
+ }
+
+ //
+ // Check if DevicePath is first part of SourcePath
+ //
+ Size = GetDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ ASSERT (Size >= 0);
+ if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, (UINTN) Size) == 0) {
+ //
+ // If the size is equal to the best match, then we
+ // have a duplicate device path for 2 different device
+ // handles
+ //
+ ASSERT (Size != BestMatch);
+
+ //
+ // We've got a match, see if it's the best match so far
+ //
+ if (Size > BestMatch) {
+ BestMatch = Size;
+ BestDevice = Handle;
+ }
+ }
+ }
+
+ CoreFreePool (Handles);
+
+ //
+ // If there wasn't any match, then no parts of the device path was found.
+ // Which is strange since there is likely a "root level" device path in the system.
+ //
+ if (BestMatch == -1) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Device == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Device = BestDevice;
+
+ //
+ // Return the remaining part of the device path
+ //
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ IHANDLE *Handle;
+
+ if ((Interface == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Interface = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = Registration;
+ Position.Position = &gHandleList;
+
+ //
+ // Lock the protocol database
+ //
+ Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = CoreGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
+ }
+
+ if (Handle == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else if (Registration != NULL) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = Registration;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if (NumberHandles == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = CoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from CoreLocateHandle().
+ //
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ Status = EFI_NOT_FOUND;
+ }
+ return Status;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = CoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR(Status)) {
+ *NumberHandles = 0;
+ }
+
+ return Status;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c
new file mode 100644
index 000000000..553413a35
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c
@@ -0,0 +1,285 @@
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+#include "Event.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ )
+{
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ CoreSignalEvent (ProtNotify->Event);
+ }
+}
+
+
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
+ if (Prot != NULL) {
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // If there's a protocol notify location pointing to this entry, back it up one
+ //
+ for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Position == &Prot->ByProtocol) {
+ ProtNotify->Position = Prot->ByProtocol.BackLink;
+ }
+ }
+
+ //
+ // Remove the protocol interface entry
+ //
+ RemoveEntryList (&Prot->ByProtocol);
+ }
+
+ return Prot;
+}
+
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ EFI_STATUS Status;
+
+ if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireProtocolLock ();
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry != NULL) {
+
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Event = Event;
+ //
+ // start at the begining
+ //
+ ProtNotify->Position = &ProtEntry->Protocols;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ //
+ // Done. If we have a protocol notify entry, then return it.
+ // Otherwise, we must have run out of resources trying to add one
+ //
+
+ Status = EFI_OUT_OF_RESOURCES;
+ if (ProtNotify != NULL) {
+ *Registration = ProtNotify;
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Handle = (IHANDLE *) UserHandle;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
+
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // Update the interface on the protocol
+ //
+ Prot->Interface = NewInterface;
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Release the lock and connect all drivers to UserHandle
+ //
+ CoreReleaseProtocolLock ();
+ //
+ // Return code is ignored on purpose.
+ //
+ CoreConnectController (
+ UserHandle,
+ NULL,
+ NULL,
+ TRUE
+ );
+ CoreAcquireProtocolLock ();
+
+ //
+ // Notify the notification list for this protocol
+ //
+ CoreNotifyProtocolEntry (ProtEntry);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c
new file mode 100644
index 000000000..d86da89ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -0,0 +1,1909 @@
+/** @file
+ Core image handling services to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Image.h"
+
+//
+// Module Globals
+//
+LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
+
+typedef struct {
+ LIST_ENTRY Link;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ UINT16 MachineType;
+} EMULATOR_ENTRY;
+
+STATIC LIST_ENTRY mAvailableEmulators;
+STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
+STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
+
+//
+// This code is needed to build the Image handle for the DXE Core
+//
+LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
+ LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // Image handle
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
+ TRUE, // If entrypoint has been called
+ NULL, // EntryPoint
+ {
+ EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
+ NULL, // Parent handle
+ NULL, // System handle
+
+ NULL, // Device handle
+ NULL, // File path
+ NULL, // Reserved
+
+ 0, // LoadOptionsSize
+ NULL, // LoadOptions
+
+ NULL, // ImageBase
+ 0, // ImageSize
+ EfiBootServicesCode, // ImageCodeType
+ EfiBootServicesData // ImageDataType
+ },
+ (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
+ 0, // NumberOfPages
+ NULL, // FixupData
+ 0, // Tpl
+ EFI_SUCCESS, // Status
+ 0, // ExitDataSize
+ NULL, // ExitData
+ NULL, // JumpBuffer
+ NULL, // JumpContext
+ 0, // Machine
+ NULL, // PeCoffEmu
+ NULL, // RuntimeData
+ NULL // LoadedImageDevicePath
+};
+//
+// The field is define for Loading modules at fixed address feature to tracker the PEI code
+// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
+// available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap=NULL;
+
+typedef struct {
+ UINT16 MachineType;
+ CHAR16 *MachineTypeName;
+} MACHINE_TYPE_INFO;
+
+GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {
+ {EFI_IMAGE_MACHINE_IA32, L"IA32"},
+ {EFI_IMAGE_MACHINE_IA64, L"IA64"},
+ {EFI_IMAGE_MACHINE_X64, L"X64"},
+ {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"},
+ {EFI_IMAGE_MACHINE_AARCH64, L"AARCH64"}
+};
+
+UINT16 mDxeCoreImageMachineType = 0;
+
+/**
+ Return machine type name.
+
+ @param MachineType The machine type
+
+ @return machine type name
+**/
+CHAR16 *
+GetMachineTypeName (
+ UINT16 MachineType
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {
+ if (mMachineTypeInfo[Index].MachineType == MachineType) {
+ return mMachineTypeInfo[Index].MachineTypeName;
+ }
+ }
+
+ return L"<Unknown>";
+}
+
+/**
+ Notification event handler registered by CoreInitializeImageServices () to
+ keep track of which PE/COFF image emulators are available.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+STATIC
+VOID
+EFIAPI
+PeCoffEmuProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE EmuHandle;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ EMULATOR_ENTRY *Entry;
+
+ EmuHandle = NULL;
+ Emulator = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EmuHandle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mPeCoffEmuProtocolNotifyRegistration,
+ &BufferSize,
+ &EmuHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ Status = CoreHandleProtocol (
+ EmuHandle,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ (VOID **)&Emulator
+ );
+ if (EFI_ERROR (Status) || Emulator == NULL) {
+ continue;
+ }
+
+ Entry = AllocateZeroPool (sizeof (*Entry));
+ ASSERT (Entry != NULL);
+
+ Entry->Emulator = Emulator;
+ Entry->MachineType = Entry->Emulator->MachineType;
+
+ InsertTailList (&mAvailableEmulators, &Entry->Link);
+ }
+}
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
+ UINT64 DxeCoreImageLength;
+ VOID *DxeCoreEntryPoint;
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
+ DxeCoreEntryPoint = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;
+ gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image = &mCorePrivateImage;
+
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
+ Image->ImageBasePage = DxeCoreImageBaseAddress;
+ Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));
+ Image->Tpl = gEfiCurrentTpl;
+ Image->Info.SystemTable = gDxeCoreST;
+ Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
+ Image->Info.ImageSize = DxeCoreImageLength;
+
+ //
+ // Install the protocol interfaces for this image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mCurrentImage = Image;
+
+ //
+ // Fill in DXE globals
+ //
+ mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
+ gDxeCoreImageHandle = Image->Handle;
+ gDxeCoreLoadedImage = &Image->Info;
+
+ //
+ // Create the PE/COFF emulator protocol registration event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PeCoffEmuProtocolNotify,
+ NULL,
+ &mPeCoffEmuProtocolRegistrationEvent
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ mPeCoffEmuProtocolRegistrationEvent,
+ &mPeCoffEmuProtocolNotifyRegistration
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ InitializeListHead (&mAvailableEmulators);
+
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ return Status;
+}
+
+/**
+ Read image file (specified by UserHandle) into user specified buffer with specified offset
+ and length.
+
+ @param UserHandle Image file handle
+ @param Offset Offset to the source file
+ @param ReadSize For input, pointer of size to read; For output,
+ pointer of size actually read.
+ @param Buffer Buffer to write into
+
+ @retval EFI_SUCCESS Successfully read the specified part of file
+ into buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReadImageFile (
+ IN VOID *UserHandle,
+ IN UINTN Offset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+ IMAGE_FILE_HANDLE *FHand;
+
+ if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - Offset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FHand = (IMAGE_FILE_HANDLE *)UserHandle;
+ ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
+
+ //
+ // Move data from our local copy of the file
+ //
+ EndPosition = Offset + *ReadSize;
+ if (EndPosition > FHand->SourceSize) {
+ *ReadSize = (UINT32)(FHand->SourceSize - Offset);
+ }
+ if (Offset >= FHand->SourceSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
+ return EFI_SUCCESS;
+}
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 DxeCodeSize;
+ EFI_PHYSICAL_ADDRESS DxeCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+ //
+ // The DXE code range includes RuntimeCodePage range and Boot time code range.
+ //
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber);
+ DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
+ mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));
+ }
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test the memory range for loading the image in the DXE code range.
+ //
+ if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize ||
+ DxeCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test if the memory is avalaible or not.
+ //
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ IMAGE_FILE_HANDLE *Handle;
+ UINT64 ValueInSectionHeader;
+
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
+ // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
+ // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
+ // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
+ // relative to top address
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {
+ ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
+ }
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
+ return Status;
+}
+
+/**
+ Decides whether a PE/COFF image can execute on this system, either natively
+ or via emulation/interpretation. In the latter case, the PeCoffEmu member
+ of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
+ to the emulator protocol that supports this image.
+
+ @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
+
+ @retval TRUE The image is supported
+ @retval FALSE The image is not supported
+
+**/
+STATIC
+BOOLEAN
+CoreIsImageTypeSupported (
+ IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
+ )
+{
+ LIST_ENTRY *Link;
+ EMULATOR_ENTRY *Entry;
+
+ for (Link = GetFirstNode (&mAvailableEmulators);
+ !IsNull (&mAvailableEmulators, Link);
+ Link = GetNextNode (&mAvailableEmulators, Link)) {
+
+ Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
+ if (Entry->MachineType != Image->ImageContext.Machine) {
+ continue;
+ }
+
+ if (Entry->Emulator->IsImageSupported (Entry->Emulator,
+ Image->ImageContext.ImageType,
+ Image->Info.FilePath)) {
+ Image->PeCoffEmu = Entry->Emulator;
+ return TRUE;
+ }
+ }
+
+ return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
+ EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
+}
+
+/**
+ Loads, relocates, and invokes a PE/COFF image
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param Pe32Handle The handle of PE32 image
+ @param Image PE image to be loaded
+ @param DstBuffer The buffer to store the image
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The file was loaded, relocated, and invoked
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
+ relocate the PE/COFF file
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
+
+**/
+EFI_STATUS
+CoreLoadPeImage (
+ IN BOOLEAN BootPolicy,
+ IN VOID *Pe32Handle,
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN DstBufAlocated;
+ UINTN Size;
+
+ ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
+
+ Image->ImageContext.Handle = Pe32Handle;
+ Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!CoreIsImageTypeSupported (Image)) {
+ //
+ // The PE/COFF loader can support loading image types that can be executed.
+ // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
+ //
+ DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",
+ GetMachineTypeName (Image->ImageContext.Machine),
+ GetMachineTypeName (mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set EFI memory type based on ImageType
+ //
+ switch (Image->ImageContext.ImageType) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
+ Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
+ break;
+ default:
+ Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate memory of the correct memory type aligned on the required image boundary
+ //
+ DstBufAlocated = FALSE;
+ if (DstBuffer == 0) {
+ //
+ // Allocate Destination Buffer as caller did not pass it in
+ //
+
+ if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
+ } else {
+ Size = (UINTN)Image->ImageContext.ImageSize;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
+
+ //
+ // If the image relocations have not been stripped, then load at any address.
+ // Otherwise load at the address at which it was linked.
+ //
+ // Memory below 1MB should be treated reserved for CSM and there should be
+ // no modules whose preferred load addresses are below 1MB.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ //
+ // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
+ // a specified address.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
+ //
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
+
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ } else {
+ if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DstBufAlocated = TRUE;
+ } else {
+ //
+ // Caller provided the destination buffer
+ //
+
+ if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
+ //
+ // If the image relocations were stripped, and the caller provided a
+ // destination buffer address that does not match the address that the
+ // image is linked at, then the image cannot be loaded.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Image->NumberOfPages != 0 &&
+ Image->NumberOfPages <
+ (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))) {
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ Image->ImageContext.ImageAddress = DstBuffer;
+ }
+
+ Image->ImageBasePage = Image->ImageContext.ImageAddress;
+ if (!Image->ImageContext.IsTeImage) {
+ Image->ImageContext.ImageAddress =
+ (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
+ ~((UINTN)Image->ImageContext.SectionAlignment - 1);
+ }
+
+ //
+ // Load the image from the file into the allocated memory
+ //
+ Status = PeCoffLoaderLoadImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If this is a Runtime Driver, then allocate memory for the FixupData that
+ // is used to relocate the image when SetVirtualAddressMap() is called. The
+ // relocation is done by the Runtime AP.
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
+ if (Image->ImageContext.FixupData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Relocate the image in memory
+ //
+ Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Flush the Instruction Cache
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
+
+ //
+ // Copy the machine type from the context to the image private data.
+ //
+ Image->Machine = Image->ImageContext.Machine;
+
+ //
+ // Get the image entry point.
+ //
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
+
+ //
+ // Fill in the image information for the Loaded Image Protocol
+ //
+ Image->Type = Image->ImageContext.ImageType;
+ Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
+ Image->Info.ImageSize = Image->ImageContext.ImageSize;
+ Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);
+ Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ //
+ // Make a list off all the RT images so we can let the RT AP know about them.
+ //
+ Image->RuntimeData = AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
+ if (Image->RuntimeData == NULL) {
+ goto Done;
+ }
+ Image->RuntimeData->ImageBase = Image->Info.ImageBase;
+ Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);
+ Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
+ Image->RuntimeData->Handle = Image->Handle;
+ InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
+ InsertImageRecord (Image->RuntimeData);
+ }
+ }
+
+ //
+ // Fill in the entry point of the image if it is available
+ //
+ if (EntryPoint != NULL) {
+ *EntryPoint = Image->ImageContext.EntryPoint;
+ }
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+
+ DEBUG_CODE_BEGIN ();
+
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,
+ "Loading driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN) Image->ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)));
+
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (Image->ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~255.
+ // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ return EFI_SUCCESS;
+
+Done:
+
+ //
+ // Free memory.
+ //
+
+ if (DstBufAlocated) {
+ CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
+ Image->ImageContext.ImageAddress = 0;
+ Image->ImageBasePage = 0;
+ }
+
+ if (Image->ImageContext.FixupData != NULL) {
+ CoreFreePool (Image->ImageContext.FixupData);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Get the image's private data from its handle.
+
+ @param ImageHandle The image handle
+
+ @return Return the image private data associated with ImageHandle.
+
+**/
+LOADED_IMAGE_PRIVATE_DATA *
+CoreLoadedImageInfo (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Status = CoreHandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
+ } else {
+ DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
+ Image = NULL;
+ }
+
+ return Image;
+}
+
+
+/**
+ Unloads EFI image from memory.
+
+ @param Image EFI image
+ @param FreePage Free allocated pages
+
+**/
+VOID
+CoreUnloadAndCloseImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN BOOLEAN FreePage
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleIndex;
+ EFI_GUID **ProtocolGuidArray;
+ UINTN ArrayCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
+ UINTN OpenInfoCount;
+ UINTN OpenInfoIndex;
+
+ HandleBuffer = NULL;
+ ProtocolGuidArray = NULL;
+
+ if (Image->Started) {
+ UnregisterMemoryProfileImage (Image);
+ }
+
+ UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ if (Image->PeCoffEmu != NULL) {
+ //
+ // If the PE/COFF Emulator protocol exists we must unregister the image.
+ //
+ Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
+ }
+
+ //
+ // Unload image, free Image->ImageContext->ModHandle
+ //
+ PeCoffLoaderUnloadImage (&Image->ImageContext);
+
+ //
+ // Free our references to the image handle
+ //
+ if (Image->Handle != NULL) {
+
+ Status = CoreLocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = CoreProtocolsPerHandle (
+ HandleBuffer[HandleIndex],
+ &ProtocolGuidArray,
+ &ArrayCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
+ Status = CoreOpenProtocolInformation (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ &OpenInfo,
+ &OpenInfoCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+ if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
+ Status = CoreCloseProtocol (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ Image->Handle,
+ OpenInfo[OpenInfoIndex].ControllerHandle
+ );
+ }
+ }
+ if (OpenInfo != NULL) {
+ CoreFreePool(OpenInfo);
+ }
+ }
+ }
+ if (ProtocolGuidArray != NULL) {
+ CoreFreePool(ProtocolGuidArray);
+ }
+ }
+ }
+ if (HandleBuffer != NULL) {
+ CoreFreePool (HandleBuffer);
+ }
+ }
+
+ CoreRemoveDebugImageInfoEntry (Image->Handle);
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ Image->LoadedImageDevicePath
+ );
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info
+ );
+
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ }
+
+ }
+
+ if (Image->RuntimeData != NULL) {
+ if (Image->RuntimeData->Link.ForwardLink != NULL) {
+ //
+ // Remove the Image from the Runtime Image list as we are about to Free it!
+ //
+ RemoveEntryList (&Image->RuntimeData->Link);
+ RemoveImageRecord (Image->RuntimeData);
+ }
+ CoreFreePool (Image->RuntimeData);
+ }
+
+ //
+ // Free the Image from memory
+ //
+ if ((Image->ImageBasePage != 0) && FreePage) {
+ CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
+ }
+
+ //
+ // Done with the Image structure
+ //
+ if (Image->Info.FilePath != NULL) {
+ CoreFreePool (Image->Info.FilePath);
+ }
+
+ if (Image->LoadedImageDevicePath != NULL) {
+ CoreFreePool (Image->LoadedImageDevicePath);
+ }
+
+ if (Image->FixupData != NULL) {
+ CoreFreePool (Image->FixupData);
+ }
+
+ CoreFreePool (Image);
+}
+
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param DstBuffer The buffer to store the image
+ @param NumberOfPages If not NULL, it inputs a pointer to the page
+ number of DstBuffer and outputs a pointer to
+ the page number of the image. If this number is
+ not enough, return EFI_BUFFER_TOO_SMALL and
+ this parameter contains the required number.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+CoreLoadImageCommon (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ IN OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *ParentImage;
+ IMAGE_FILE_HANDLE FHand;
+ EFI_STATUS Status;
+ EFI_STATUS SecurityStatus;
+ EFI_HANDLE DeviceHandle;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *InputFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ UINTN FilePathSize;
+ BOOLEAN ImageIsFromFv;
+ BOOLEAN ImageIsFromLoadFile;
+
+ SecurityStatus = EFI_SUCCESS;
+
+ ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
+ ParentImage = NULL;
+
+ //
+ // The caller must pass in a valid ParentImageHandle
+ //
+ if (ImageHandle == NULL || ParentImageHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ParentImage = CoreLoadedImageInfo (ParentImageHandle);
+ if (ParentImage == NULL) {
+ DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
+ FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;
+ OriginalFilePath = FilePath;
+ InputFilePath = FilePath;
+ HandleFilePath = FilePath;
+ DeviceHandle = NULL;
+ Status = EFI_SUCCESS;
+ AuthenticationStatus = 0;
+ ImageIsFromFv = FALSE;
+ ImageIsFromLoadFile = FALSE;
+
+ //
+ // If the caller passed a copy of the file, then just use it
+ //
+ if (SourceBuffer != NULL) {
+ FHand.Source = SourceBuffer;
+ FHand.SourceSize = SourceSize;
+ Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ DeviceHandle = NULL;
+ }
+ if (SourceSize > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ } else {
+ if (FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to get the image device handle by checking the match protocol.
+ //
+ Node = NULL;
+ Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromFv = TRUE;
+ } else {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ if (!BootPolicy) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ }
+ if (EFI_ERROR (Status)) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromLoadFile = TRUE;
+ Node = HandleFilePath;
+ }
+ }
+ }
+ }
+
+ //
+ // Get the source file buffer by its device path.
+ //
+ FHand.Source = GetFileBufferByFilePath (
+ BootPolicy,
+ FilePath,
+ &FHand.SourceSize,
+ &AuthenticationStatus
+ );
+ if (FHand.Source == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ FHand.FreeBuffer = TRUE;
+ if (ImageIsFromLoadFile) {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Image = NULL;
+ goto Done;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Verify File Authentication through the Security2 Architectural Protocol
+ //
+ SecurityStatus = gSecurity2->FileAuthentication (
+ gSecurity2,
+ OriginalFilePath,
+ FHand.Source,
+ FHand.SourceSize,
+ BootPolicy
+ );
+ if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
+ //
+ // When Security2 is installed, Security Architectural Protocol must be published.
+ //
+ ASSERT (gSecurity != NULL);
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ // Only on images that have been read using Firmware Volume protocol.
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+ } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+
+ //
+ // Check Security Status.
+ //
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
+ if (SecurityStatus == EFI_ACCESS_DENIED) {
+ //
+ // Image was not loaded because the platform policy prohibits the image from being loaded.
+ // It's the only place we could meet EFI_ACCESS_DENIED.
+ //
+ *ImageHandle = NULL;
+ }
+ Status = SecurityStatus;
+ Image = NULL;
+ goto Done;
+ }
+
+ //
+ // Allocate a new image structure
+ //
+ Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
+ //
+ FilePath = OriginalFilePath;
+ if (DeviceHandle != NULL) {
+ Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
+ }
+ }
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
+ Image->Info.SystemTable = gDxeCoreST;
+ Image->Info.DeviceHandle = DeviceHandle;
+ Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ Image->Info.FilePath = DuplicateDevicePath (FilePath);
+ Image->Info.ParentHandle = ParentImageHandle;
+
+
+ if (NumberOfPages != NULL) {
+ Image->NumberOfPages = *NumberOfPages ;
+ } else {
+ Image->NumberOfPages = 0 ;
+ }
+
+ //
+ // Install the protocol interfaces for this image
+ // don't fire notifications yet
+ //
+ Status = CoreInstallProtocolInterfaceNotify (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Load the image. If EntryPoint is Null, it will not be set.
+ //
+ Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+ }
+ goto Done;
+ }
+
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+
+ //
+ // Register the image in the Debug Image Info Table if the attribute is set
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
+ CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
+ }
+
+ //
+ //Reinstall loaded image protocol to fire any notifications
+ //
+ Status = CoreReinstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info,
+ &Image->Info
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
+ // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
+ //
+ if (OriginalFilePath != NULL) {
+ Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
+ }
+
+ //
+ // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Image->LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install HII Package List Protocol onto the image handle
+ //
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ //
+ // Success. Return the image handle
+ //
+ *ImageHandle = Image->Handle;
+
+Done:
+ //
+ // All done accessing the source file
+ // If we allocated the Source buffer, free it
+ //
+ if (FHand.FreeBuffer) {
+ CoreFreePool (FHand.Source);
+ }
+ if (OriginalFilePath != InputFilePath) {
+ CoreFreePool (OriginalFilePath);
+ }
+
+ //
+ // There was an error. If there's an Image structure, free it
+ //
+ if (EFI_ERROR (Status)) {
+ if (Image != NULL) {
+ CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
+ Image = NULL;
+ }
+ } else if (EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+
+ //
+ // Track the return status from LoadImage.
+ //
+ if (Image != NULL) {
+ Image->LoadImageStatus = Status;
+ }
+
+ return Status;
+}
+
+
+
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ PERF_LOAD_IMAGE_BEGIN (NULL);
+
+ Status = CoreLoadImageCommon (
+ BootPolicy,
+ ParentImageHandle,
+ FilePath,
+ SourceBuffer,
+ SourceSize,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,
+ NULL,
+ ImageHandle,
+ NULL,
+ EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
+ );
+
+ Handle = NULL;
+ if (!EFI_ERROR (Status)) {
+ //
+ // ImageHandle will be valid only Status is success.
+ //
+ Handle = *ImageHandle;
+ }
+
+ PERF_LOAD_IMAGE_END (Handle);
+
+ return Status;
+}
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *LastImage;
+ UINT64 HandleDatabaseKey;
+ UINTN SetJumpFlag;
+ EFI_HANDLE Handle;
+
+ Handle = ImageHandle;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL || Image->Started) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (EFI_ERROR (Image->LoadImageStatus)) {
+ return Image->LoadImageStatus;
+ }
+
+ //
+ // The image to be started must have the machine type supported by DxeCore.
+ //
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
+ Image->PeCoffEmu == NULL) {
+ //
+ // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
+ // But it can not be started.
+ //
+ DEBUG ((EFI_D_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine)));
+ DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Image->PeCoffEmu != NULL) {
+ Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,
+ Image->ImageBasePage,
+ EFI_PAGES_TO_SIZE (Image->NumberOfPages),
+ &Image->EntryPoint);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_LOAD | DEBUG_ERROR,
+ "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
+ Status));
+ return Status;
+ }
+ }
+
+ PERF_START_IMAGE_BEGIN (Handle);
+
+
+ //
+ // Push the current start image context, and
+ // link the current image to the head. This is the
+ // only image that can call Exit()
+ //
+ HandleDatabaseKey = CoreGetHandleDatabaseKey ();
+ LastImage = mCurrentImage;
+ mCurrentImage = Image;
+ Image->Tpl = gEfiCurrentTpl;
+
+ //
+ // Set long jump for Exit() support
+ // JumpContext must be aligned on a CPU specific boundary.
+ // Overallocate the buffer and force the required alignment
+ //
+ Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+ if (Image->JumpBuffer == NULL) {
+ //
+ // Image may be unloaded after return with failure,
+ // then ImageHandle may be invalid, so use NULL handle to record perf log.
+ //
+ PERF_START_IMAGE_END (NULL);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+
+ SetJumpFlag = SetJump (Image->JumpContext);
+ //
+ // The initial call to SetJump() must always return 0.
+ // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
+ //
+ if (SetJumpFlag == 0) {
+ RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
+ //
+ // Call the image's entry point
+ //
+ Image->Started = TRUE;
+ Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
+
+ //
+ // Add some debug information if the image returned with error.
+ // This make the user aware and check if the driver image have already released
+ // all the resource in this situation.
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EFI_ERROR (Image->Status)) {
+ DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // If the image returns, exit it through Exit()
+ //
+ CoreExit (ImageHandle, Image->Status, 0, NULL);
+ }
+
+ //
+ // Image has completed. Verify the tpl is the same
+ //
+ ASSERT (Image->Tpl == gEfiCurrentTpl);
+ CoreRestoreTpl (Image->Tpl);
+
+ CoreFreePool (Image->JumpBuffer);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ //
+ // UEFI Specification - StartImage() - EFI 1.10 Extension
+ // To maintain compatibility with UEFI drivers that are written to the EFI
+ // 1.02 Specification, StartImage() must monitor the handle database before
+ // and after each image is started. If any handles are created or modified
+ // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
+ // be called with the Recursive parameter set to TRUE for each of the newly
+ // created or modified handles before StartImage() returns.
+ //
+ if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreConnectHandlesByKey (HandleDatabaseKey);
+ }
+
+ //
+ // Handle the image's returned ExitData
+ //
+ DEBUG_CODE_BEGIN ();
+ if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
+
+ DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
+ if (Image->ExitData != NULL) {
+ DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));
+ }
+ DEBUG ((DEBUG_LOAD, "\n"));
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Return the exit data to the caller
+ //
+ if (ExitData != NULL && ExitDataSize != NULL) {
+ *ExitDataSize = Image->ExitDataSize;
+ *ExitData = Image->ExitData;
+ } else {
+ //
+ // Caller doesn't want the exit data, free it
+ //
+ CoreFreePool (Image->ExitData);
+ Image->ExitData = NULL;
+ }
+
+ //
+ // Save the Status because Image will get destroyed if it is unloaded.
+ //
+ Status = Image->Status;
+
+ //
+ // If the image returned an error, or if the image is an application
+ // unload it
+ //
+ if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreUnloadAndCloseImage (Image, TRUE);
+ //
+ // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
+ //
+ Handle = NULL;
+ }
+
+ //
+ // Done
+ //
+ PERF_START_IMAGE_END (Handle);
+ return Status;
+}
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_TPL OldTpl;
+
+ //
+ // Prevent possible reentrance to this function
+ // for the same ImageHandle
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (!Image->Started) {
+ //
+ // The image has not been started so just free its resources
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Image has been started, verify this image can exit
+ //
+ if (Image != mCurrentImage) {
+ DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Set status
+ //
+ Image->Status = Status;
+
+ //
+ // If there's ExitData info, move it
+ //
+ if (ExitData != NULL) {
+ Image->ExitDataSize = ExitDataSize;
+ Image->ExitData = AllocatePool (Image->ExitDataSize);
+ if (Image->ExitData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
+ }
+
+ CoreRestoreTpl (OldTpl);
+ //
+ // return to StartImage
+ //
+ LongJump (Image->JumpContext, (UINTN)-1);
+
+ //
+ // If we return from LongJump, then it is an error
+ //
+ ASSERT (FALSE);
+ Status = EFI_ACCESS_DENIED;
+Done:
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL ) {
+ //
+ // The image handle is not valid
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Image->Started) {
+ //
+ // The image has been started, request it to unload.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (Image->Info.Unload != NULL) {
+ Status = Image->Info.Unload (ImageHandle);
+ }
+
+ } else {
+ //
+ // This Image hasn't been started, thus it can be unloaded
+ //
+ Status = EFI_SUCCESS;
+ }
+
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // if the Image was not started or Unloaded O.K. then clean up
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ }
+
+Done:
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h
new file mode 100644
index 000000000..e9c44ab2a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h
@@ -0,0 +1,24 @@
+/** @file
+ Data structure and functions to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+//
+// Private Data Types
+//
+#define IMAGE_FILE_HANDLE_SIGNATURE SIGNATURE_32('i','m','g','f')
+typedef struct {
+ UINTN Signature;
+ BOOLEAN FreeBuffer;
+ VOID *Source;
+ UINTN SourceSize;
+} IMAGE_FILE_HANDLE;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c b/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c
new file mode 100644
index 000000000..b7f0781ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c
@@ -0,0 +1,100 @@
+/** @file
+ DXE Core library services.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Lock Stuff
+//
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock != EfiLockUninitialized);
+
+ if (Lock->Lock == EfiLockAcquired) {
+ //
+ // Lock is already owned, so bail out
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+
+ Lock->Lock = EfiLockAcquired;
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockReleased);
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+ Lock->Lock = EfiLockAcquired;
+}
+
+
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ EFI_TPL Tpl;
+
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockAcquired);
+
+ Tpl = Lock->OwnerTpl;
+
+ Lock->Lock = EfiLockReleased;
+
+ CoreRestoreTpl (Tpl);
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
new file mode 100644
index 000000000..b4cb48843
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
@@ -0,0 +1,1746 @@
+/** @file
+ UEFI Heap Guard functions.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+//
+// Global to avoid infinite reentrance of memory allocation when updating
+// page table attributes, which may need allocate pages for new PDE/PTE.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
+
+//
+// Pointer to table tracking the Guarded memory with bitmap, in which '1'
+// is used to indicate memory guarded. '0' might be free memory or Guard
+// page itself, depending on status of memory adjacent to it.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
+
+//
+// Current depth level of map table pointed by mGuardedMemoryMap.
+// mMapLevel must be initialized at least by 1. It will be automatically
+// updated according to the address of memory just tracked.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
+
+//
+// Shift and mask for each level of map table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+
+//
+// Used for promoting freed but not used pages.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mLastPromotedPage = BASE_4GB;
+
+/**
+ Set corresponding bits in bitmap table to 1 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+SetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
+ (UINT64)-1);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap |= (LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Set corresponding bits in bitmap table to 0 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+ClearBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Get corresponding bits in bitmap table according to the address.
+
+ The value of bit 0 corresponds to the status of memory at given Address.
+ No more than 64 bits can be retrieved in one call.
+
+ @param[in] Address Start address to retrieve bits for.
+ @param[in] BitNumber Number of bits to get.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return An integer containing the bits information.
+**/
+STATIC
+UINT64
+GetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN StartBit;
+ UINTN EndBit;
+ UINTN Lsbs;
+ UINTN Msbs;
+ UINT64 Result;
+
+ ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ }
+
+ if (StartBit == 0 && BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Result = *BitMap;
+ } else {
+ Result = RShiftU64((*BitMap), StartBit) & (LShiftU64(1, Msbs) - 1);
+ if (Lsbs > 0) {
+ BitMap += 1;
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ }
+ }
+
+ return Result;
+}
+
+/**
+ Locate the pointer of bitmap from the guarded memory bitmap tables, which
+ covers the given Address.
+
+ @param[in] Address Start address to search the bitmap for.
+ @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
+ @param[out] BitMap Pointer to bitmap which covers the Address.
+
+ @return The bit number from given Address to the end of current map table.
+**/
+UINTN
+FindGuardedMemoryMap (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN AllocMapUnit,
+ OUT UINT64 **BitMap
+ )
+{
+ UINTN Level;
+ UINT64 *GuardMap;
+ UINT64 MapMemory;
+ UINTN Index;
+ UINTN Size;
+ UINTN BitsToUnitEnd;
+ EFI_STATUS Status;
+
+ MapMemory = 0;
+
+ //
+ // Adjust current map table depth according to the address to access
+ //
+ while (AllocMapUnit &&
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
+ RShiftU64 (
+ Address,
+ mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
+ ) != 0) {
+
+ if (mGuardedMemoryMap != 0) {
+ Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
+ * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+
+ *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
+ mGuardedMemoryMap = MapMemory;
+ }
+
+ mMapLevel++;
+
+ }
+
+ GuardMap = &mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level) {
+
+ if (*GuardMap == 0) {
+ if (!AllocMapUnit) {
+ GuardMap = NULL;
+ break;
+ }
+
+ Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+ *GuardMap = MapMemory;
+ }
+
+ Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
+ Index &= mLevelMask[Level];
+ GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
+
+ }
+
+ BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
+ *BitMap = GuardMap;
+
+ return BitsToUnitEnd;
+}
+
+/**
+ Set corresponding bits in bitmap table to 1 according to given memory range.
+
+ @param[in] Address Memory address to guard from.
+ @param[in] NumberOfPages Number of pages to guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+SetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ SetBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Clear corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to unset from.
+ @param[in] NumberOfPages Number of pages to unset guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+ClearGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ ClearBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Retrieve corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to retrieve from.
+ @param[in] NumberOfPages Number of pages to retrieve.
+
+ @return An integer containing the guarded memory bitmap.
+**/
+UINT64
+GetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINT64 Result;
+ UINTN Shift;
+ UINTN BitsToUnitEnd;
+
+ ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ Result = 0;
+ Shift = 0;
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ if (BitMap != NULL) {
+ Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
+ }
+
+ Shift += Bits;
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+
+ return Result;
+}
+
+/**
+ Get bit value in bitmap table for the given address.
+
+ @param[in] Address The address to retrieve for.
+
+ @return 1 or 0.
+**/
+UINTN
+EFIAPI
+GetGuardMapBit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 *GuardMap;
+
+ FindGuardedMemoryMap (Address, FALSE, &GuardMap);
+ if (GuardMap != NULL) {
+ if (RShiftU64 (*GuardMap,
+ GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 BitMap;
+
+ //
+ // There must be at least one guarded page before and/or after given
+ // address if it's a Guard page. The bitmap pattern should be one of
+ // 001, 100 and 101
+ //
+ BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
+ return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
+}
+
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ return (GetGuardMapBit (Address) == 1);
+}
+
+/**
+ Set the page at the given address to be a Guard page.
+
+ This is done by changing the page table attribute to be NOT PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at
+
+ @return VOID
+**/
+VOID
+EFIAPI
+SetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Unset the Guard page at the given address to the normal memory.
+
+ This is done by changing the page table attribute to be PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+UnsetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Once the Guard page is unset, it will be freed back to memory pool. NX
+ // memory protection must be restored for this page if NX is enabled for free
+ // memory.
+ //
+ Attributes = 0;
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {
+ Attributes |= EFI_MEMORY_XP;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as memory protection (NX). Please make sure they are not enabled
+ // at the same time.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Check to see if the memory at the given address should be guarded or not.
+
+ @param[in] MemoryType Memory type to check.
+ @param[in] AllocateType Allocation type to check.
+ @param[in] PageOrPool Indicate a page allocation or pool allocation.
+
+
+ @return TRUE The given type of memory should be guarded.
+ @return FALSE The given type of memory should not be guarded.
+**/
+BOOLEAN
+IsMemoryTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN UINT8 PageOrPool
+ )
+{
+ UINT64 TestBit;
+ UINT64 ConfigBit;
+
+ if (AllocateType == AllocateAddress) {
+ return FALSE;
+ }
+
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) {
+ return FALSE;
+ }
+
+ if (PageOrPool == GUARD_HEAP_TYPE_POOL) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPoolType);
+ } else if (PageOrPool == GUARD_HEAP_TYPE_PAGE) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPageType);
+ } else {
+ ConfigBit = (UINT64)-1;
+ }
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else if (MemoryType < EfiMaxMemoryType) {
+ TestBit = LShiftU64 (1, MemoryType);
+ } else if (MemoryType == EfiMaxMemoryType) {
+ TestBit = (UINT64)-1;
+ } else {
+ TestBit = 0;
+ }
+
+ return ((ConfigBit & TestBit) != 0);
+}
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL);
+}
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
+}
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ )
+{
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages, GuardType);
+}
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+
+ //
+ // Set tail Guard
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ // Set head Guard
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ //
+ // Mark the memory range as Guarded
+ //
+ SetGuardedMemoryBits (Memory, NumberOfPages);
+}
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+ UINT64 GuardBitmap;
+
+ if (NumberOfPages == 0) {
+ return;
+ }
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // unset it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages before memory to free are still in Guard. It's a partial free
+ // case. Turn first page of memory block to free into a new Guard.
+ //
+ SetGuardPage (Memory);
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages after memory to free are still in Guard. It's a partial free
+ // case. We need to keep one page to be a head Guard.
+ //
+ SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
+ }
+
+ //
+ // No matter what, we just clear the mark of the Guarded memory.
+ //
+ ClearGuardedMemoryBits(Memory, NumberOfPages);
+}
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ )
+{
+ UINT64 Target;
+
+ //
+ // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
+ // indicated to put the pool near the Tail Guard, we need extra bytes to
+ // make sure alignment of the returned pool address.
+ //
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
+ SizeRequested = ALIGN_VALUE(SizeRequested, 8);
+ }
+
+ Target = Start + Size - SizeRequested;
+ ASSERT (Target >= Start);
+ if (Target == 0) {
+ return 0;
+ }
+
+ if (!IsGuardPage (Start + Size)) {
+ // No Guard at tail to share. One more page is needed.
+ Target -= EFI_PAGES_TO_SIZE (1);
+ }
+
+ // Out of range?
+ if (Target < Start) {
+ return 0;
+ }
+
+ // At the edge?
+ if (Target == Start) {
+ if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
+ // No enough space for a new head Guard if no Guard at head to share.
+ return 0;
+ }
+ }
+
+ // OK, we have enough pages for memory and its Guards. Return the End of the
+ // free space.
+ return Target + SizeRequested - 1;
+}
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS Start;
+ EFI_PHYSICAL_ADDRESS MemoryToTest;
+ UINTN PagesToFree;
+ UINT64 GuardBitmap;
+
+ if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
+ return;
+ }
+
+ Start = *Memory;
+ PagesToFree = *NumberOfPages;
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ Start -= EFI_PAGES_TO_SIZE (1);
+ PagesToFree += 1;
+ }
+ } else {
+ //
+ // No Head Guard, and pages before memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a tail Guard.
+ //
+ Start += EFI_PAGES_TO_SIZE (1);
+ PagesToFree -= 1;
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ PagesToFree += 1;
+ }
+ } else if (PagesToFree > 0) {
+ //
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a head Guard.
+ //
+ PagesToFree -= 1;
+ }
+
+ *Memory = Start;
+ *NumberOfPages = PagesToFree;
+}
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ //
+ // FindFreePages() has already taken the Guard into account. It's safe to
+ // adjust the start address and/or number of pages here, to make sure that
+ // the Guards are also "allocated".
+ //
+ if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
+ // No tail Guard, add one.
+ *NumberOfPages += 1;
+ }
+
+ if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
+ // No head Guard, add one.
+ *Memory -= EFI_PAGE_SIZE;
+ *NumberOfPages += 1;
+ }
+}
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ Size = ALIGN_VALUE (Size, 8);
+ return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
+}
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
+}
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ UINT64 OldStart;
+ UINTN OldPages;
+
+ if (NewType == EfiConventionalMemory) {
+ OldStart = Start;
+ OldPages = NumberOfPages;
+
+ AdjustMemoryF (&Start, &NumberOfPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (OldStart, OldPages);
+ if (NumberOfPages == 0) {
+ return EFI_SUCCESS;
+ }
+ } else {
+ AdjustMemoryA (&Start, &NumberOfPages);
+ }
+
+ return CoreConvertPages (Start, NumberOfPages, NewType);
+}
+
+/**
+ Set all Guard pages which cannot be set before CPU Arch Protocol installed.
+**/
+VOID
+SetAllGuardPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINTN Index;
+ BOOLEAN OnGuarding;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof(Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ OnGuarding = FALSE;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ OnGuarding = FALSE;
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+
+ } else {
+
+ Index = 0;
+ while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
+ if ((TableEntry & 1) == 1) {
+ if (OnGuarding) {
+ GuardPage = 0;
+ } else {
+ GuardPage = Address - EFI_PAGE_SIZE;
+ }
+ OnGuarding = TRUE;
+ } else {
+ if (OnGuarding) {
+ GuardPage = Address;
+ } else {
+ GuardPage = 0;
+ }
+ OnGuarding = FALSE;
+ }
+
+ if (GuardPage != 0) {
+ SetGuardPage (GuardPage);
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ TableEntry = RShiftU64 (TableEntry, 1);
+ Address += EFI_PAGE_SIZE;
+ Index += 1;
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
+/**
+ Find the address of top-most guarded free page.
+
+ @param[out] Address Start address of top-most guarded free page.
+
+ @return VOID.
+**/
+VOID
+GetLastGuardedFreePageAddress (
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_PHYSICAL_ADDRESS AddressGranularity;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN Level;
+ UINT64 Map;
+ INTN Index;
+
+ ASSERT (mMapLevel >= 1);
+
+ BaseAddress = 0;
+ Map = mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level) {
+ AddressGranularity = LShiftU64 (1, mLevelShift[Level]);
+
+ //
+ // Find the non-NULL entry at largest index.
+ //
+ for (Index = (INTN)mLevelMask[Level]; Index >= 0 ; --Index) {
+ if (((UINT64 *)(UINTN)Map)[Index] != 0) {
+ BaseAddress += MultU64x32 (AddressGranularity, (UINT32)Index);
+ Map = ((UINT64 *)(UINTN)Map)[Index];
+ break;
+ }
+ }
+ }
+
+ //
+ // Find the non-zero MSB then get the page address.
+ //
+ while (Map != 0) {
+ Map = RShiftU64 (Map, 1);
+ BaseAddress += EFI_PAGES_TO_SIZE (1);
+ }
+
+ *Address = BaseAddress;
+}
+
+/**
+ Record freed pages.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+MarkFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ SetGuardedMemoryBits (BaseAddress, Pages);
+}
+
+/**
+ Record freed pages as well as mark them as not-present.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Legacy memory lower than 1MB might be accessed with no allocation. Leave
+ // them alone.
+ //
+ if (BaseAddress < BASE_1MB) {
+ return;
+ }
+
+ MarkFreedPages (BaseAddress, Pages);
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ EFI_MEMORY_RP
+ );
+ //
+ // Normally we should ASSERT the returned Status. But there might be memory
+ // alloc/free involved in SetMemoryAttributes(), which might fail this
+ // calling. It's rare case so it's OK to let a few tiny holes be not-guarded.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Failed to guard freed pages: %p (%lu)\n", BaseAddress, (UINT64)Pages));
+ }
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardFreedPages (BaseAddress, Pages);
+ }
+}
+
+/**
+ Mark all pages freed before CPU Arch Protocol as not-present.
+
+**/
+VOID
+GuardAllFreedPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINT64 BitIndex;
+ UINTN GuardPageNumber;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof(Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ GuardPage = (UINT64)-1;
+ GuardPageNumber = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ BitIndex = 1;
+ while (BitIndex != 0) {
+ if ((TableEntry & BitIndex) != 0) {
+ if (GuardPage == (UINT64)-1) {
+ GuardPage = Address;
+ }
+ ++GuardPageNumber;
+ } else if (GuardPageNumber > 0) {
+ GuardFreedPages (GuardPage, GuardPageNumber);
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ Address += EFI_PAGES_TO_SIZE (1);
+ BitIndex = LShiftU64 (BitIndex, 1);
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
+
+ }
+
+ //
+ // Update the maximum address of freed page which can be used for memory
+ // promotion upon out-of-memory-space.
+ //
+ GetLastGuardedFreePageAddress (&Address);
+ if (Address != 0) {
+ mLastPromotedPage = Address;
+ }
+}
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ )
+{
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ UINT64 Bitmap;
+ INTN Pages;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ MemoryMapEntry->Type >= EfiMemoryMappedIO) {
+ return;
+ }
+
+ Bitmap = 0;
+ Pages = EFI_SIZE_TO_PAGES ((UINTN)(MaxAddress - MemoryMapEntry->PhysicalStart));
+ Pages -= (INTN)MemoryMapEntry->NumberOfPages;
+ while (Pages > 0) {
+ if (Bitmap == 0) {
+ EndAddress = MemoryMapEntry->PhysicalStart +
+ EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages);
+ Bitmap = GetGuardedMemoryBits (EndAddress, GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ if ((Bitmap & 1) == 0) {
+ break;
+ }
+
+ Pages--;
+ MemoryMapEntry->NumberOfPages++;
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+}
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN AvailablePages;
+ UINT64 Bitmap;
+ EFI_PHYSICAL_ADDRESS Start;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ return FALSE;
+ }
+
+ //
+ // Similar to memory allocation service, always search the freed pages in
+ // descending direction.
+ //
+ Start = mLastPromotedPage;
+ AvailablePages = 0;
+ while (AvailablePages == 0) {
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ //
+ // If the address wraps around, try the really freed pages at top.
+ //
+ if (Start > mLastPromotedPage) {
+ GetLastGuardedFreePageAddress (&Start);
+ ASSERT (Start != 0);
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ Bitmap = GetGuardedMemoryBits (Start, GUARDED_HEAP_MAP_ENTRY_BITS);
+ while (Bitmap > 0) {
+ if ((Bitmap & 1) != 0) {
+ ++AvailablePages;
+ } else if (AvailablePages == 0) {
+ Start += EFI_PAGES_TO_SIZE (1);
+ } else {
+ break;
+ }
+
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+ }
+
+ if (AvailablePages != 0) {
+ DEBUG ((DEBUG_INFO, "Promoted pages: %lX (%lx)\r\n", Start, (UINT64)AvailablePages));
+ ClearGuardedMemoryBits (Start, AvailablePages);
+
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ Status = gCpu->SetMemoryAttributes (gCpu, Start, EFI_PAGES_TO_SIZE(AvailablePages), 0);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+
+ mLastPromotedPage = Start;
+ *StartAddress = Start;
+ *EndAddress = Start + EFI_PAGES_TO_SIZE (AvailablePages) - 1;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Notify function used to set all Guard pages before CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ )
+{
+ ASSERT (gCpu != NULL);
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL) &&
+ IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ DEBUG ((DEBUG_ERROR, "Heap guard and freed memory guard cannot be enabled at the same time.\n"));
+ CpuDeadLoop ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ SetAllGuardPages ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardAllFreedPages ();
+ }
+}
+
+/**
+ Helper function to convert a UINT64 value in binary to a string.
+
+ @param[in] Value Value of a UINT64 integer.
+ @param[out] BinString String buffer to contain the conversion result.
+
+ @return VOID.
+**/
+VOID
+Uint64ToBinString (
+ IN UINT64 Value,
+ OUT CHAR8 *BinString
+ )
+{
+ UINTN Index;
+
+ if (BinString == NULL) {
+ return;
+ }
+
+ for (Index = 64; Index > 0; --Index) {
+ BinString[Index - 1] = '0' + (Value & 1);
+ Value = RShiftU64 (Value, 1);
+ }
+ BinString[64] = '\0';
+}
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ INTN Level;
+ UINTN RepeatZero;
+ CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
+ CHAR8 *Ruler1;
+ CHAR8 *Ruler2;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_ALL)) {
+ return;
+ }
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ Ruler1 = " 3 2 1 0";
+ Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
+
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
+ " Guarded Memory Bitmap "
+ "==============================\r\n"));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Indices, sizeof(Indices), 0);
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ RepeatZero = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+
+ Tables[Level] = 0;
+ Level -= 1;
+ RepeatZero = 0;
+
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "========================================="
+ "=========================================\r\n"
+ ));
+
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ if (RepeatZero == 0) {
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+ } else if (RepeatZero == 1) {
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
+ }
+ RepeatZero += 1;
+ }
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+ RepeatZero = 0;
+
+ continue;
+
+ } else {
+
+ RepeatZero = 0;
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
new file mode 100644
index 000000000..d6e4ed39d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
@@ -0,0 +1,467 @@
+/** @file
+ Data type, macros and function prototypes of heap guard feature.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HEAPGUARD_H_
+#define _HEAPGUARD_H_
+
+//
+// Following macros are used to define and access the guarded memory bitmap
+// table.
+//
+// To simplify the access and reduce the memory used for this table, the
+// table is constructed in the similar way as page table structure but in
+// reverse direction, i.e. from bottom growing up to top.
+//
+// - 1-bit tracks 1 page (4KB)
+// - 1-UINT64 map entry tracks 256KB memory
+// - 1K-UINT64 map table tracks 256MB memory
+// - Five levels of tables can track any address of memory of 64-bit
+// system, like below.
+//
+// 512 * 512 * 512 * 512 * 1K * 64b * 4K
+// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
+// 63 54 45 36 27 17 11 0
+// 9b 9b 9b 9b 10b 6b 12b
+// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
+// 1FF 1FF 1FF 1FF 3FF 3F FFF
+//
+// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
+// memory. Each table of L0-L3 will be allocated when its memory address
+// range is to be tracked. Only 1-page will be allocated each time. This
+// can save memories used to establish this map table.
+//
+// For a normal configuration of system with 4G memory, two levels of tables
+// can track the whole memory, because two levels (L3+L4) of map tables have
+// already coverred 37-bit of memory address. And for a normal UEFI BIOS,
+// less than 128M memory would be consumed during boot. That means we just
+// need
+//
+// 1-page (L3) + 2-page (L4)
+//
+// memory (3 pages) to track the memory allocation works. In this case,
+// there's no need to setup L0-L2 tables.
+//
+
+//
+// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
+// bits in address. (512 = 1 << 9)
+//
+#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
+
+#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
+ (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
+
+#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
+
+// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
+#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
+
+#define GUARDED_HEAP_MAP_ENTRY_BITS \
+ (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
+
+#define GUARDED_HEAP_MAP_ENTRY_BYTES \
+ (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
+
+// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
+#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_BITS \
+ - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
+ - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ - EFI_PAGE_SHIFT)
+
+// L4 table address mask: (1 << 10 - 1) = 0x3FF
+#define GUARDED_HEAP_MAP_ENTRY_MASK \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
+
+// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
+#define GUARDED_HEAP_MAP_SIZE \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
+#define GUARDED_HEAP_MAP_UNIT_SIZE \
+ (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
+
+// L4 table entry number: 8KB / 8 = 1024
+#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
+ (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// L4 table entry indexing
+#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
+ & GUARDED_HEAP_MAP_ENTRY_MASK)
+
+// L4 table entry bit indexing
+#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
+
+//
+// Total bits (pages) tracked by one L4 table (65536-bit)
+//
+#define GUARDED_HEAP_MAP_BITS \
+ (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
+
+//
+// Bit indexing inside the whole L4 table (0 - 65535)
+//
+#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
+
+//
+// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
+//
+#define GUARDED_HEAP_MAP_TABLE_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ + EFI_PAGE_SHIFT)
+
+//
+// Macro used to initialize the local array variable for map table traversing
+// {55, 46, 37, 28, 18}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
+ { \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT, \
+ EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ }
+
+//
+// Masks used to extract address range of each level of table
+// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
+ { \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
+ }
+
+//
+// Memory type to guard (matching the related PCD definition)
+//
+#define GUARD_HEAP_TYPE_PAGE BIT0
+#define GUARD_HEAP_TYPE_POOL BIT1
+#define GUARD_HEAP_TYPE_FREED BIT4
+#define GUARD_HEAP_TYPE_ALL \
+ (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_FREED)
+
+//
+// Debug message level
+//
+#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
+
+typedef struct {
+ UINT32 TailMark;
+ UINT32 HeadMark;
+ EFI_PHYSICAL_ADDRESS Address;
+ LIST_ENTRY Link;
+} HEAP_GUARD_NODE;
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned.
+ @param NumberOfPages The number of pages to convert.
+ @param NewType The new type for the memory range.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ );
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ );
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ );
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ );
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ );
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ );
+
+/**
+ Notify function used to set all Guard pages after CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ );
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ );
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ );
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ );
+
+extern BOOLEAN mOnGuarding;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h
new file mode 100644
index 000000000..090f3f089
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h
@@ -0,0 +1,182 @@
+/** @file
+ Data structure and functions to allocate and free memory space.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IMEM_H_
+#define _IMEM_H_
+
+//
+// +---------------------------------------------------+
+// | 0..(EfiMaxMemoryType - 1) - Normal memory type |
+// +---------------------------------------------------+
+// | EfiMaxMemoryType..0x6FFFFFFF - Invalid |
+// +---------------------------------------------------+
+// | 0x70000000..0x7FFFFFFF - OEM reserved |
+// +---------------------------------------------------+
+// | 0x80000000..0xFFFFFFFF - OS reserved |
+// +---------------------------------------------------+
+//
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OS_RESERVED_MAX 0xFFFFFFFF
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+#define MEMORY_TYPE_OEM_RESERVED_MAX 0x7FFFFFFF
+
+//
+// MEMORY_MAP_ENTRY
+//
+
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ BOOLEAN FromPages;
+
+ EFI_MEMORY_TYPE Type;
+ UINT64 Start;
+ UINT64 End;
+
+ UINT64 VirtualStart;
+ UINT64 Attribute;
+} MEMORY_MAP;
+
+//
+// Internal prototypes
+//
+
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ );
+
+
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ );
+
+
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ );
+
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ );
+
+//
+// Internal Global data
+//
+
+extern EFI_LOCK gMemoryLock;
+extern LIST_ENTRY gMemoryMap;
+extern LIST_ENTRY mGcdMemorySpaceMap;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c
new file mode 100644
index 000000000..67d886832
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c
@@ -0,0 +1,20 @@
+/** @file
+ Global data used in memory service
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+
+//
+// MemoryLock - synchronizes access to the memory map and pool lists
+//
+EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+//
+// MemoryMap - the current memory map
+//
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
new file mode 100644
index 000000000..2ca0417b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
@@ -0,0 +1,1759 @@
+/** @file
+ Support routines for UEFI memory profile.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+
+#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_CONTEXT Context;
+ LIST_ENTRY *DriverInfoList;
+} MEMORY_PROFILE_CONTEXT_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_DRIVER_INFO DriverInfo;
+ LIST_ENTRY *AllocInfoList;
+ CHAR8 *PdbString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_DRIVER_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_ALLOC_INFO AllocInfo;
+ CHAR8 *ActionString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_ALLOC_INFO_DATA;
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ {
+ {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ sizeof (MEMORY_PROFILE_CONTEXT),
+ MEMORY_PROFILE_CONTEXT_REVISION
+ },
+ 0,
+ 0,
+ {0},
+ {0},
+ 0,
+ 0,
+ 0
+ },
+ &mImageQueue,
+};
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileGettingStatus = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMemoryProfileDriverPathSize;
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ );
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCE No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ );
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ );
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ );
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
+ ProfileProtocolGetData,
+ ProfileProtocolRegisterImage,
+ ProfileProtocolUnregisterImage,
+ ProfileProtocolGetRecordingState,
+ ProfileProtocolSetRecordingState,
+ ProfileProtocolRecord,
+};
+
+/**
+ Acquire lock on mMemoryProfileLock.
+**/
+VOID
+CoreAcquireMemoryProfileLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryProfileLock);
+}
+
+/**
+ Release lock on mMemoryProfileLock.
+**/
+VOID
+CoreReleaseMemoryProfileLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryProfileLock);
+}
+
+/**
+ Return memory profile context.
+
+ @return Memory profile context.
+
+**/
+MEMORY_PROFILE_CONTEXT_DATA *
+GetMemoryProfileContext (
+ VOID
+ )
+{
+ return mMemoryProfileContextPtr;
+}
+
+/**
+ Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
+ If Pe32Data is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+
+ @return The Subsystem of the PE/COFF image.
+
+**/
+UINT16
+InternalPeCoffGetSubsystem (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT16 Magic;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ return Hdr.Te->Subsystem;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ Magic = Hdr.Pe32->OptionalHeader.Magic;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ return Hdr.Pe32->OptionalHeader.Subsystem;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ return Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ }
+ }
+
+ return 0x0000;
+}
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ ASSERT (Pe32Data != NULL);
+ ASSERT (EntryPoint != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ //
+ // Calculate the entry point relative to the start of the image.
+ // AddressOfEntryPoint is common for PE32 & PE32+
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
+ return RETURN_SUCCESS;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
+ return RETURN_SUCCESS;
+ }
+
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Build driver info.
+
+ @param ContextData Memory profile context.
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param EntryPoint Entry point of the image.
+ @param ImageSubsystem Image subsystem of the image.
+ @param FileType File type of the image.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+BuildDriverInfo (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN UINT16 ImageSubsystem,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ VOID *EntryPointInImage;
+ CHAR8 *PdbString;
+ UINTN PdbSize;
+ UINTN PdbOccupiedSize;
+
+ PdbSize = 0;
+ PdbOccupiedSize = 0;
+ PdbString = NULL;
+ if (ImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
+ if (PdbString != NULL) {
+ PdbSize = AsciiStrSize (PdbString);
+ PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
+ }
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
+ (VOID **) &DriverInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (DriverInfoData != NULL);
+
+ ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
+
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
+ DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
+ if (FileName != NULL) {
+ CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
+ }
+ DriverInfo->ImageBase = ImageBase;
+ DriverInfo->ImageSize = ImageSize;
+ DriverInfo->EntryPoint = EntryPoint;
+ DriverInfo->ImageSubsystem = ImageSubsystem;
+ if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+ }
+ DriverInfo->FileType = FileType;
+ DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
+ InitializeListHead (DriverInfoData->AllocInfoList);
+ DriverInfo->CurrentUsage = 0;
+ DriverInfo->PeakUsage = 0;
+ DriverInfo->AllocRecordCount = 0;
+ if (PdbSize != 0) {
+ DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
+ DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
+ CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
+ } else {
+ DriverInfo->PdbStringOffset = 0;
+ DriverInfoData->PdbString = NULL;
+ }
+
+ InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
+ ContextData->Context.ImageCount ++;
+ ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
+
+ return DriverInfoData;
+}
+
+/**
+ Return if record for this driver is needed..
+
+ @param DriverFilePath Driver file path.
+
+ @retval TRUE Record for this driver is needed.
+ @retval FALSE Record for this driver is not needed.
+
+**/
+BOOLEAN
+NeedRecordThisDriver (
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
+ UINTN DevicePathSize;
+ UINTN FilePathSize;
+
+ if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
+ //
+ // Invalid Device Path means record all.
+ //
+ return TRUE;
+ }
+
+ //
+ // Record FilePath without END node.
+ //
+ FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+
+ DevicePathInstance = mMemoryProfileDriverPath;
+ do {
+ //
+ // Find END node (it might be END_ENTIRE or END_INSTANCE).
+ //
+ TmpDevicePath = DevicePathInstance;
+ while (!IsDevicePathEndType (TmpDevicePath)) {
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ //
+ // Do not compare END node.
+ //
+ DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
+ if ((FilePathSize == DevicePathSize) &&
+ (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
+ return TRUE;
+ }
+
+ //
+ // Get next instance.
+ //
+ DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
+ } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
+
+ return FALSE;
+}
+
+/**
+ Register DXE Core to memory profile.
+
+ @param HobStart The start address of the HOB.
+ @param ContextData Memory profile context.
+
+ @retval TRUE Register success.
+ @retval FALSE Register fail.
+
+**/
+BOOLEAN
+RegisterDxeCore (
+ IN VOID *HobStart,
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
+ )
+{
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ ASSERT (ContextData != NULL);
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
+ return FALSE;
+ }
+
+ ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ &DxeCoreHob.MemoryAllocationModule->ModuleName,
+ ImageBase,
+ DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
+ DxeCoreHob.MemoryAllocationModule->EntryPoint,
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
+ EFI_FV_FILETYPE_DXE_CORE
+ );
+ if (DriverInfoData == NULL) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData != NULL) {
+ return;
+ }
+
+ mMemoryProfileGettingStatus = FALSE;
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+ } else {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
+ }
+ mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
+ mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
+ mMemoryProfileContextPtr = &mMemoryProfileContext;
+
+ RegisterDxeCore (HobStart, &mMemoryProfileContext);
+
+ DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
+}
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ Handle = NULL;
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiMemoryProfileGuid,
+ &mProfileProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the GUID file name from the file path.
+
+ @param FilePath File path.
+
+ @return The GUID file name from the file path.
+
+**/
+EFI_GUID *
+GetFileNameFromFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if (FilePath != NULL) {
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
+ while (!IsDevicePathEnd (ThisFilePath)) {
+ FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
+ if (FileName != NULL) {
+ break;
+ }
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
+ }
+ }
+
+ return FileName;
+}
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ GetFileNameFromFilePath (DriverEntry->Info.FilePath),
+ DriverEntry->ImageContext.ImageAddress,
+ DriverEntry->ImageContext.ImageSize,
+ DriverEntry->ImageContext.EntryPoint,
+ DriverEntry->ImageContext.ImageType,
+ FileType
+ );
+ if (DriverInfoData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search image from memory profile.
+
+ @param ContextData Memory profile context.
+ @param FileName Image file name.
+ @param Address Image Address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoByFileNameAndAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
+ (Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Search image from memory profile.
+ It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
+
+ @param ContextData Memory profile context.
+ @param Address Image or Function address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoFromAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ EFI_GUID *FileName;
+ PHYSICAL_ADDRESS ImageAddress;
+ VOID *EntryPointInImage;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = NULL;
+ FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
+ ImageAddress = DriverEntry->ImageContext.ImageAddress;
+ if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageAddress here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;
+ }
+ if (FileName != NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
+
+ // Keep the ImageBase for RVA calculation in Application.
+ //DriverInfoData->DriverInfo.ImageBase = 0;
+ DriverInfoData->DriverInfo.ImageSize = 0;
+
+ if (DriverInfoData->DriverInfo.PeakUsage == 0) {
+ ContextData->Context.ImageCount --;
+ RemoveEntryList (&DriverInfoData->Link);
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (DriverInfoData, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if this memory type needs to be recorded into memory profile.
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
+
+ @param MemoryType Memory type.
+
+ @retval TRUE This memory type need to be recorded.
+ @retval FALSE This memory type need not to be recorded.
+
+**/
+BOOLEAN
+CoreNeedRecordProfile (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Convert EFI memory type to profile memory index. The rule is:
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
+
+ @param MemoryType Memory type.
+
+ @return Profile memory index.
+
+**/
+UINTN
+GetProfileMemoryIndex (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ return EfiMaxMemoryType;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ return EfiMaxMemoryType + 1;
+ } else {
+ return MemoryType;
+ }
+}
+
+/**
+ Update memory profile Allocate information.
+
+ @param CallerAddress Address of caller who call Allocate.
+ @param Action This Allocate action.
+ @param MemoryType Memory type.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileAllocate (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size,
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ UINTN ActionStringSize;
+ UINTN ActionStringOccupiedSize;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+ if (DriverInfoData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ActionStringSize = 0;
+ ActionStringOccupiedSize = 0;
+ if (ActionString != NULL) {
+ ActionStringSize = AsciiStrSize (ActionString);
+ ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ AllocInfoData = NULL;
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*AllocInfoData) + ActionStringSize,
+ (VOID **) &AllocInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (AllocInfoData != NULL);
+
+ //
+ // Only update SequenceCount if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ContextData->Context.SequenceCount ++;
+ }
+
+ AllocInfo = &AllocInfoData->AllocInfo;
+ AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
+ AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
+ AllocInfo->CallerAddress = CallerAddress;
+ AllocInfo->SequenceId = ContextData->Context.SequenceCount;
+ AllocInfo->Action = Action;
+ AllocInfo->MemoryType = MemoryType;
+ AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
+ AllocInfo->Size = Size;
+ if (ActionString != NULL) {
+ AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
+ AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
+ CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
+ } else {
+ AllocInfo->ActionStringOffset = 0;
+ AllocInfoData->ActionString = NULL;
+ }
+
+ InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfo->AllocRecordCount ++;
+
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
+
+ DriverInfo->CurrentUsage += Size;
+ if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
+ DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
+ }
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
+ if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
+ DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
+ }
+
+ Context->CurrentTotalUsage += Size;
+ if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
+ Context->PeakTotalUsage = Context->CurrentTotalUsage;
+ }
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
+ if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
+ Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get memory profile alloc info from memory profile.
+
+ @param DriverInfoData Driver info.
+ @param BasicAction This Free basic action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return Pointer to memory profile alloc info.
+
+**/
+MEMORY_PROFILE_ALLOC_INFO_DATA *
+GetMemoryProfileAllocInfoFromAddress (
+ IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
+ IN MEMORY_PROFILE_ACTION BasicAction,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ AllocInfo = &AllocInfoData->AllocInfo;
+ if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
+ continue;
+ }
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
+ ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
+ return AllocInfoData;
+ }
+ break;
+ case MemoryProfileActionAllocatePool:
+ if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ return AllocInfoData;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Update memory profile Free information.
+
+ @param CallerAddress Address of caller who call Free.
+ @param Action This Free action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileFree (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ BOOLEAN Found;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+
+ //
+ // Do not return if DriverInfoData == NULL here,
+ // because driver A might free memory allocated by driver B.
+ //
+
+ //
+ // Need use do-while loop to find all possible records,
+ // because one address might be recorded multiple times.
+ //
+ Found = FALSE;
+ AllocInfoData = NULL;
+ do {
+ if (DriverInfoData != NULL) {
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ }
+ if (AllocInfoData == NULL) {
+ //
+ // Legal case, because driver A might free memory allocated by driver B, by some protocol.
+ //
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ ThisDriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ if (AllocInfoData != NULL) {
+ DriverInfoData = ThisDriverInfoData;
+ break;
+ }
+ }
+
+ if (AllocInfoData == NULL) {
+ //
+ // If (!Found), no matched allocate info is found for this free action.
+ // It is because the specified memory type allocate actions have been filtered by
+ // CoreNeedRecordProfile(), but free actions may have no memory type information,
+ // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
+ // filtered here.
+ //
+ // If (Found), it is normal exit path.
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+ }
+
+ ASSERT (DriverInfoData != NULL);
+ ASSERT (AllocInfoData != NULL);
+
+ Found = TRUE;
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ AllocInfo = &AllocInfoData->AllocInfo;
+
+ DriverInfo->AllocRecordCount --;
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
+
+ Context->CurrentTotalUsage -= AllocInfo->Size;
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+
+ DriverInfo->CurrentUsage -= AllocInfo->Size;
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+ }
+
+ RemoveEntryList (&AllocInfoData->Link);
+
+ if (BasicAction == MemoryProfileActionFreePages) {
+ if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
+ (VOID *) (UINTN) AllocInfo->Buffer,
+ AllocInfoData->ActionString
+ );
+ }
+ if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
+ (VOID *) ((UINTN) Buffer + Size),
+ AllocInfoData->ActionString
+ );
+ }
+ }
+
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (AllocInfoData, NULL);
+ } while (TRUE);
+}
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_ACTION BasicAction;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mMemoryProfileGettingStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (!mMemoryProfileRecordingEnable) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the basic action to know how to process the record
+ //
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ //
+ // EfiMaxMemoryType means the MemoryType is unknown.
+ //
+ if (MemoryType != EfiMaxMemoryType) {
+ //
+ // Only record limited MemoryType.
+ //
+ if (!CoreNeedRecordProfile (MemoryType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoreAcquireMemoryProfileLock ();
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePages:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
+ break;
+ case MemoryProfileActionAllocatePool:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePool:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ CoreReleaseMemoryProfileLock ();
+
+ return Status;
+}
+
+////////////////////
+
+/**
+ Get memory profile data size.
+
+ @return Memory profile data size.
+
+**/
+UINTN
+MemoryProfileGetDataSize (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN TotalSize;
+
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return 0;
+ }
+
+ TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ TotalSize += DriverInfoData->DriverInfo.Header.Length;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ TotalSize += AllocInfoData->AllocInfo.Header.Length;
+ }
+ }
+
+ return TotalSize;
+}
+
+/**
+ Copy memory profile data.
+
+ @param ProfileBuffer The buffer to hold memory profile data.
+
+**/
+VOID
+MemoryProfileCopyData (
+ IN VOID *ProfileBuffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN PdbSize;
+ UINTN ActionStringSize;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ Context = ProfileBuffer;
+ CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
+ if (DriverInfo->PdbStringOffset != 0) {
+ PdbSize = AsciiStrSize (DriverInfoData->PdbString);
+ CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
+ }
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
+ if (AllocInfo->ActionStringOffset != 0) {
+ ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
+ CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
+ }
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
+ }
+
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;
+ }
+}
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ )
+{
+ UINTN Size;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN MemoryProfileGettingStatus;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
+ mMemoryProfileGettingStatus = TRUE;
+
+ Size = MemoryProfileGetDataSize ();
+
+ if (*ProfileSize < Size) {
+ *ProfileSize = Size;
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *ProfileSize = Size;
+ MemoryProfileCopyData (ProfileBuffer);
+
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_SUCCESS;
+}
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+ DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);
+
+ return RegisterMemoryProfileImage (&DriverEntry, FileType);
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ return UnregisterMemoryProfileImage (&DriverEntry);
+}
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (RecordingState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *RecordingState = mMemoryProfileRecordingEnable;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mMemoryProfileRecordingEnable = RecordingState;
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+}
+
+////////////////////
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c
new file mode 100644
index 000000000..2c2c9cd6c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -0,0 +1,2105 @@
+/** @file
+ UEFI Memory page management functions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+//
+// Entry for tracking the memory regions for each memory type to coalesce similar memory types
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS MaximumAddress;
+ UINT64 CurrentNumberOfPages;
+ UINT64 NumberOfPages;
+ UINTN InformationIndex;
+ BOOLEAN Special;
+ BOOLEAN Runtime;
+} EFI_MEMORY_TYPE_STATISTICS;
+
+//
+// MemoryMap - The current memory map
+//
+UINTN mMemoryMapKey = 0;
+
+#define MAX_MAP_DEPTH 6
+
+///
+/// mMapDepth - depth of new descriptor stack
+///
+UINTN mMapDepth = 0;
+///
+/// mMapStack - space to use as temp storage to build new map descriptors
+///
+MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
+UINTN mFreeMapStack = 0;
+///
+/// This list maintain the free memory map list
+///
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
+BOOLEAN mMemoryTypeInformationInitialized = FALSE;
+
+EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
+};
+
+EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
+EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
+
+EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
+ { EfiReservedMemoryType, 0 },
+ { EfiLoaderCode, 0 },
+ { EfiLoaderData, 0 },
+ { EfiBootServicesCode, 0 },
+ { EfiBootServicesData, 0 },
+ { EfiRuntimeServicesCode, 0 },
+ { EfiRuntimeServicesData, 0 },
+ { EfiConventionalMemory, 0 },
+ { EfiUnusableMemory, 0 },
+ { EfiACPIReclaimMemory, 0 },
+ { EfiACPIMemoryNVS, 0 },
+ { EfiMemoryMappedIO, 0 },
+ { EfiMemoryMappedIOPortSpace, 0 },
+ { EfiPalCode, 0 },
+ { EfiPersistentMemory, 0 },
+ { EfiMaxMemoryType, 0 }
+};
+//
+// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
+// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
+// address assigned by DXE core.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gMemoryLock);
+}
+
+
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gMemoryLock);
+}
+
+
+
+
+/**
+ Internal function. Removes a descriptor entry.
+
+ @param Entry The entry to remove
+
+**/
+VOID
+RemoveMemoryMapEntry (
+ IN OUT MEMORY_MAP *Entry
+ )
+{
+ RemoveEntryList (&Entry->Link);
+ Entry->Link.ForwardLink = NULL;
+
+ if (Entry->FromPages) {
+ //
+ // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+}
+
+/**
+ Internal function. Adds a ranges to the memory map.
+ The range must not already exist in the map.
+
+ @param Type The type of memory range to add
+ @param Start The starting address in the memory range Must be
+ paged aligned
+ @param End The last address in the range Must be the last
+ byte of a page
+ @param Attribute The attributes of the memory range to add
+
+**/
+VOID
+CoreAddRange (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN EFI_PHYSICAL_ADDRESS End,
+ IN UINT64 Attribute
+ )
+{
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start) ;
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
+
+ //
+ // If memory of type EfiConventionalMemory is being added that includes the page
+ // starting at address 0, then zero the page starting at address 0. This has
+ // two benifits. It helps find NULL pointer bugs and it also maximizes
+ // compatibility with operating systems that may evaluate memory in this page
+ // for legacy data structures. If memory of any other type is added starting
+ // at address 0, then do not zero the page at address 0 because the page is being
+ // used for other purposes.
+ //
+ if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
+ SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
+ }
+ }
+
+ //
+ // Memory map being altered so updated key
+ //
+ mMemoryMapKey += 1;
+
+ //
+ // UEFI 2.0 added an event group for notificaiton on memory map changes.
+ // So we need to signal this Event Group every time the memory map changes.
+ // If we are in EFI 1.10 compatability mode no event groups will be
+ // found and nothing will happen we we call this function. These events
+ // will get signaled but since a lock is held around the call to this
+ // function the notificaiton events will only be called after this function
+ // returns and the lock is released.
+ //
+ CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
+
+ //
+ // Look for adjoining memory descriptor
+ //
+
+ // Two memory descriptors can only be merged if they have the same Type
+ // and the same Attribute
+ //
+
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ if (Entry->Type != Type) {
+ continue;
+ }
+
+ if (Entry->Attribute != Attribute) {
+ continue;
+ }
+
+ if (Entry->End + 1 == Start) {
+
+ Start = Entry->Start;
+ RemoveMemoryMapEntry (Entry);
+
+ } else if (Entry->Start == End + 1) {
+
+ End = Entry->End;
+ RemoveMemoryMapEntry (Entry);
+ }
+ }
+
+ //
+ // Add descriptor
+ //
+
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Type;
+ mMapStack[mMapDepth].Start = Start;
+ mMapStack[mMapDepth].End = End;
+ mMapStack[mMapDepth].VirtualStart = 0;
+ mMapStack[mMapDepth].Attribute = Attribute;
+ InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+
+ return ;
+}
+
+/**
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
+ If the list is emtry, then allocate a new page to refuel the list.
+ Please Note this algorithm to allocate the memory map descriptor has a property
+ that the memory allocated for memory entries always grows, and will never really be freed
+ For example, if the current boot uses 2000 memory map entries at the maximum point, but
+ ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
+ memory map entries is still allocated from EfiBootServicesMemory.
+
+
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
+
+**/
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+ VOID
+ )
+{
+ MEMORY_MAP* FreeDescriptorEntries;
+ MEMORY_MAP* Entry;
+ UINTN Index;
+
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {
+ //
+ // The list is empty, to allocate one page to refuel the list
+ //
+ FreeDescriptorEntries = CoreAllocatePoolPages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
+ DEFAULT_PAGE_ALLOCATION_GRANULARITY,
+ FALSE
+ );
+ if (FreeDescriptorEntries != NULL) {
+ //
+ // Enque the free memmory map entries into the list
+ //
+ for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
+ }
+ } else {
+ return NULL;
+ }
+ }
+ //
+ // dequeue the first descriptor from the list
+ //
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ RemoveEntryList (&Entry->Link);
+
+ return Entry;
+}
+
+
+/**
+ Internal function. Moves any memory descriptors that are on the
+ temporary descriptor stack to heap.
+
+**/
+VOID
+CoreFreeMemoryMapStack (
+ VOID
+ )
+{
+ MEMORY_MAP *Entry;
+ MEMORY_MAP *Entry2;
+ LIST_ENTRY *Link2;
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ //
+ // If already freeing the map stack, then return
+ //
+ if (mFreeMapStack != 0) {
+ return ;
+ }
+
+ //
+ // Move the temporary memory descriptor stack into pool
+ //
+ mFreeMapStack += 1;
+
+ while (mMapDepth != 0) {
+ //
+ // Deque an memory map entry from mFreeMemoryMapEntryList
+ //
+ Entry = AllocateMemoryMapEntry ();
+
+ ASSERT (Entry);
+
+ //
+ // Update to proper entry
+ //
+ mMapDepth -= 1;
+
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
+
+ //
+ // Move this entry to general memory
+ //
+ RemoveEntryList (&mMapStack[mMapDepth].Link);
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;
+
+ CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
+ Entry->FromPages = TRUE;
+
+ //
+ // Find insertion location
+ //
+ for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
+ Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry2->FromPages && Entry2->Start > Entry->Start) {
+ break;
+ }
+ }
+
+ InsertTailList (Link2, &Entry->Link);
+
+ } else {
+ //
+ // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
+ // so here no need to move it to memory.
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+ }
+
+ mFreeMapStack -= 1;
+}
+
+/**
+ Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
+
+**/
+BOOLEAN
+PromoteMemoryResource (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ BOOLEAN Promoted;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Promoted = FALSE;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ Entry->EndAddress < MAX_ALLOC_ADDRESS &&
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
+ //
+ // Update the GCD map
+ //
+ if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+ Entry->Capabilities |= EFI_MEMORY_TESTED;
+ Entry->ImageHandle = gDxeCoreImageHandle;
+ Entry->DeviceHandle = NULL;
+
+ //
+ // Add to allocable system memory resource
+ //
+
+ CoreAddRange (
+ EfiConventionalMemory,
+ Entry->BaseAddress,
+ Entry->EndAddress,
+ Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ CoreFreeMemoryMapStack ();
+
+ Promoted = TRUE;
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ if (!Promoted) {
+ //
+ // If freed-memory guard is enabled, we could promote pages from
+ // guarded free pages.
+ //
+ Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
+ if (Promoted) {
+ CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ CoreAddRange (
+ EfiConventionalMemory,
+ StartAddress,
+ EndAddress,
+ Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
+ EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+
+ return Promoted;
+}
+/**
+ This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
+ PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
+ size of boot time and runtime code.
+
+**/
+VOID
+CoreLoadingFixedAddressHook (
+ VOID
+ )
+{
+ UINT32 RuntimeCodePageNumber;
+ UINT32 BootTimeCodePageNumber;
+ EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
+ EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
+ EFI_STATUS Status;
+
+ //
+ // Make sure these 2 areas are not initialzied.
+ //
+ if (!gLoadFixedAddressCodeMemoryReady) {
+ RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
+ BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
+ //
+ // Try to allocate runtime memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ RuntimeCodePageNumber,
+ &RuntimeCodeBase
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // Runtime memory allocation failed
+ //
+ return;
+ }
+ //
+ // Try to allocate boot memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiBootServicesCode,
+ BootTimeCodePageNumber,
+ &BootTimeCodeBase
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // boot memory allocation failed. Free Runtime code range and will try the allocation again when
+ // new memory range is installed.
+ //
+ CoreFreePages (
+ RuntimeCodeBase,
+ RuntimeCodePageNumber
+ );
+ return;
+ }
+ gLoadFixedAddressCodeMemoryReady = TRUE;
+ }
+ return;
+}
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ )
+{
+ EFI_PHYSICAL_ADDRESS End;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN FreeIndex;
+
+ if ((Start & EFI_PAGE_MASK) != 0) {
+ return;
+ }
+
+ if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
+ return;
+ }
+ CoreAcquireMemoryLock ();
+ End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
+ CoreAddRange (Type, Start, End, Attribute);
+ CoreFreeMemoryMapStack ();
+ CoreReleaseMemoryLock ();
+
+ ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,
+ LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));
+
+ //
+ // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ CoreLoadingFixedAddressHook();
+ }
+
+ //
+ // Check to see if the statistics for the different memory types have already been established
+ //
+ if (mMemoryTypeInformationInitialized) {
+ return;
+ }
+
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ //
+ // Allocate pages for the current memory type from the top of available memory
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ Type,
+ gMemoryTypeInformation[Index].NumberOfPages,
+ &mMemoryTypeStatistics[Type].BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If an error occurs allocating the pages for the current memory type, then
+ // free all the pages allocates for the previous memory types and return. This
+ // operation with be retied when/if more memory is added to the system
+ //
+ for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[FreeIndex].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].BaseAddress = 0;
+ mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
+ }
+ }
+ return;
+ }
+
+ //
+ // Compute the address at the top of the current statistics
+ //
+ mMemoryTypeStatistics[Type].MaximumAddress =
+ mMemoryTypeStatistics[Type].BaseAddress +
+ LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
+
+ //
+ // If the current base address is the lowest address so far, then update the default
+ // maximum address
+ //
+ if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
+ mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
+ }
+ }
+ }
+
+ //
+ // There was enough system memory for all the the memory types were allocated. So,
+ // those memory areas can be freed for future allocations, and all future memory
+ // allocations can occur within their respective bins
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[Index].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
+ gMemoryTypeInformation[Index].NumberOfPages = 0;
+ }
+ }
+
+ //
+ // If the number of pages reserved for a memory type is 0, then all allocations for that type
+ // should be in the default range.
+ //
+ for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
+ mMemoryTypeStatistics[Type].InformationIndex = Index;
+ }
+ }
+ mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
+ if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
+ mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
+ }
+ }
+
+ mMemoryTypeInformationInitialized = TRUE;
+}
+
+
+/**
+ Internal function. Converts a memory range to the specified type or attributes.
+ The range must exist in the memory map. Either ChangingType or
+ ChangingAttributes must be set, but not both.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param ChangingType Boolean indicating that type value should be changed
+ @param NewType The new type for the memory range
+ @param ChangingAttributes Boolean indicating that attributes value should be changed
+ @param NewAttributes The new attributes for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPagesEx (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN BOOLEAN ChangingType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN BOOLEAN ChangingAttributes,
+ IN UINT64 NewAttributes
+ )
+{
+
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 RangeEnd;
+ UINT64 Attribute;
+ EFI_MEMORY_TYPE MemType;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Entry = NULL;
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ ASSERT (NumberOfPages);
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start) ;
+ ASSERT_LOCKED (&gMemoryLock);
+ ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
+
+ if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the entire range
+ //
+
+ while (Start < End) {
+
+ //
+ // Find the entry that the covers the range
+ //
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ if (Entry->Start <= Start && Entry->End > Start) {
+ break;
+ }
+ }
+
+ if (Link == &gMemoryMap) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If we are converting the type of the range from EfiConventionalMemory to
+ // another type, we have to ensure that the entire range is covered by a
+ // single entry.
+ //
+ if (ChangingType && (NewType != EfiConventionalMemory)) {
+ if (Entry->End < End) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Convert range to the end, or to the end of the descriptor
+ // if that's all we've got
+ //
+ RangeEnd = End;
+
+ ASSERT (Entry != NULL);
+ if (Entry->End < End) {
+ RangeEnd = Entry->End;
+ }
+
+ if (ChangingType) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
+ }
+ if (ChangingAttributes) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
+ }
+
+ if (ChangingType) {
+ //
+ // Debug code - verify conversion is allowed
+ //
+ if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
+ if (Entry->Type == EfiConventionalMemory) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update counters for the number of pages allocated to each memory type
+ //
+ if ((UINT32)Entry->Type < EfiMaxMemoryType) {
+ if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
+ (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
+ if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
+ } else {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
+ }
+ }
+ }
+
+ if ((UINT32)NewType < EfiMaxMemoryType) {
+ if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
+ (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
+ mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
+ if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
+ gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
+ }
+ }
+ }
+ }
+
+ //
+ // Pull range out of descriptor
+ //
+ if (Entry->Start == Start) {
+
+ //
+ // Clip start
+ //
+ Entry->Start = RangeEnd + 1;
+
+ } else if (Entry->End == RangeEnd) {
+
+ //
+ // Clip end
+ //
+ Entry->End = Start - 1;
+
+ } else {
+
+ //
+ // Pull it out of the center, clip current
+ //
+
+ //
+ // Add a new one
+ //
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Entry->Type;
+ mMapStack[mMapDepth].Start = RangeEnd+1;
+ mMapStack[mMapDepth].End = Entry->End;
+
+ //
+ // Inherit Attribute from the Memory Descriptor that is being clipped
+ //
+ mMapStack[mMapDepth].Attribute = Entry->Attribute;
+
+ Entry->End = Start - 1;
+ ASSERT (Entry->Start < Entry->End);
+
+ Entry = &mMapStack[mMapDepth];
+ InsertTailList (&gMemoryMap, &Entry->Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+ }
+
+ //
+ // The new range inherits the same Attribute as the Entry
+ // it is being cut out of unless attributes are being changed
+ //
+ if (ChangingType) {
+ Attribute = Entry->Attribute;
+ MemType = NewType;
+ } else {
+ Attribute = NewAttributes;
+ MemType = Entry->Type;
+ }
+
+ //
+ // If the descriptor is empty, then remove it from the map
+ //
+ if (Entry->Start == Entry->End + 1) {
+ RemoveMemoryMapEntry (Entry);
+ Entry = NULL;
+ }
+
+ //
+ // Add our new range in. Don't do this for freed pages if freed-memory
+ // guard is enabled.
+ //
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ !ChangingType ||
+ MemType != EfiConventionalMemory) {
+ CoreAddRange (MemType, Start, RangeEnd, Attribute);
+ }
+
+ if (ChangingType && (MemType == EfiConventionalMemory)) {
+ //
+ // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
+ // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
+ // that the page starting at address 0 is always filled with zeros.
+ //
+ if (Start == 0) {
+ if (RangeEnd > EFI_PAGE_SIZE) {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
+ }
+ } else {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
+ }
+ }
+
+ //
+ // Move any map descriptor stack to general pool
+ //
+ CoreFreeMemoryMapStack ();
+
+ //
+ // Bump the starting address, and convert the next range
+ //
+ Start = RangeEnd + 1;
+ }
+
+ //
+ // Converted the whole range, done
+ //
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewType The new type for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
+}
+
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ )
+{
+ CoreAcquireMemoryLock ();
+
+ //
+ // Update the attributes to the new value
+ //
+ CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
+
+ CoreReleaseMemoryLock ();
+}
+
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address.
+
+ @param MaxAddress The address that the range must be below
+ @param MinAddress The address that the range must be above
+ @param NumberOfPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found
+
+**/
+UINT64
+CoreFindFreePagesI (
+ IN UINT64 MaxAddress,
+ IN UINT64 MinAddress,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 NumberOfBytes;
+ UINT64 Target;
+ UINT64 DescStart;
+ UINT64 DescEnd;
+ UINT64 DescNumberOfBytes;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
+ return 0;
+ }
+
+ if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
+
+ //
+ // If MaxAddress is not aligned to the end of a page
+ //
+
+ //
+ // Change MaxAddress to be 1 page lower
+ //
+ MaxAddress -= (EFI_PAGE_MASK + 1);
+
+ //
+ // Set MaxAddress to a page boundary
+ //
+ MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
+
+ //
+ // Set MaxAddress to end of the page
+ //
+ MaxAddress |= EFI_PAGE_MASK;
+ }
+
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ Target = 0;
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ //
+ // If it's not a free entry, don't bother with it
+ //
+ if (Entry->Type != EfiConventionalMemory) {
+ continue;
+ }
+
+ DescStart = Entry->Start;
+ DescEnd = Entry->End;
+
+ //
+ // If desc is past max allowed address or below min allowed address, skip it
+ //
+ if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
+ continue;
+ }
+
+ //
+ // If desc ends past max allowed address, clip the end
+ //
+ if (DescEnd >= MaxAddress) {
+ DescEnd = MaxAddress;
+ }
+
+ DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
+
+ // Skip if DescEnd is less than DescStart after alignment clipping
+ if (DescEnd < DescStart) {
+ continue;
+ }
+
+ //
+ // Compute the number of bytes we can used from this
+ // descriptor, and see it's enough to satisfy the request
+ //
+ DescNumberOfBytes = DescEnd - DescStart + 1;
+
+ if (DescNumberOfBytes >= NumberOfBytes) {
+ //
+ // If the start of the allocated range is below the min address allowed, skip it
+ //
+ if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
+ continue;
+ }
+
+ //
+ // If this is the best match so far remember it
+ //
+ if (DescEnd > Target) {
+ if (NeedGuard) {
+ DescEnd = AdjustMemoryS (
+ DescEnd + 1 - DescNumberOfBytes,
+ DescNumberOfBytes,
+ NumberOfBytes
+ );
+ if (DescEnd == 0) {
+ continue;
+ }
+ }
+
+ Target = DescEnd;
+ }
+ }
+ }
+
+ //
+ // If this is a grow down, adjust target to be the allocation base
+ //
+ Target -= NumberOfBytes - 1;
+
+ //
+ // If we didn't find a match, return 0
+ //
+ if ((Target & EFI_PAGE_MASK) != 0) {
+ return 0;
+ }
+
+ return Target;
+}
+
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address
+
+ @param MaxAddress The address that the range must be below
+ @param NoPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found.
+
+**/
+UINT64
+FindFreePages (
+ IN UINT64 MaxAddress,
+ IN UINT64 NoPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Attempt to find free pages in the preferred bin based on the requested memory type
+ //
+ if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
+ Start = CoreFindFreePagesI (
+ mMemoryTypeStatistics[NewType].MaximumAddress,
+ mMemoryTypeStatistics[NewType].BaseAddress,
+ NoPages,
+ NewType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start != 0) {
+ return Start;
+ }
+ }
+
+ //
+ // Attempt to find free pages in the default allocation bin
+ //
+ if (MaxAddress >= mDefaultMaximumAddress) {
+ Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
+ Alignment, NeedGuard);
+ if (Start != 0) {
+ if (Start < mDefaultBaseAddress) {
+ mDefaultBaseAddress = Start;
+ }
+ return Start;
+ }
+ }
+
+ //
+ // The allocation did not succeed in any of the prefered bins even after
+ // promoting resources. Attempt to find free pages anywhere is the requested
+ // address range. If this allocation fails, then there are not enough
+ // resources anywhere to satisfy the request.
+ //
+ Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
+ NeedGuard);
+ if (Start != 0) {
+ return Start;
+ }
+
+ //
+ // If allocations from the preferred bins fail, then attempt to promote memory resources.
+ //
+ if (!PromoteMemoryResource ()) {
+ return 0;
+ }
+
+ //
+ // If any memory resources were promoted, then re-attempt the allocation
+ //
+ return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
+}
+
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Start;
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 MaxAddress;
+ UINTN Alignment;
+ EFI_MEMORY_TYPE CheckType;
+
+ if ((UINT32)Type >= MaxAllocateType) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
+ (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Memory == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ if (MemoryType == EfiACPIReclaimMemory ||
+ MemoryType == EfiACPIMemoryNVS ||
+ MemoryType == EfiRuntimeServicesCode ||
+ MemoryType == EfiRuntimeServicesData) {
+
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (Type == AllocateAddress) {
+ if ((*Memory & (Alignment - 1)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ //
+ // If this is for below a particular address, then
+ //
+ Start = *Memory;
+
+ //
+ // The max address is the max natively addressable address for the processor
+ //
+ MaxAddress = MAX_ALLOC_ADDRESS;
+
+ //
+ // Check for Type AllocateAddress,
+ // if NumberOfPages is 0 or
+ // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
+ // if (Start + NumberOfBytes) rolls over 0 or
+ // if Start is above MAX_ALLOC_ADDRESS or
+ // if End is above MAX_ALLOC_ADDRESS,
+ // if Start..End overlaps any tracked MemoryTypeStatistics range
+ // return EFI_NOT_FOUND.
+ //
+ if (Type == AllocateAddress) {
+ if ((NumberOfPages == 0) ||
+ (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
+ return EFI_NOT_FOUND;
+ }
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ if ((Start >= End) ||
+ (Start > MaxAddress) ||
+ (End > MaxAddress)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
+ // AllocatePage request the exact physical address if it is not used. The existing code
+ // will allow this request even in 'special' pages. The problem with this is that the
+ // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
+ // fragmented.
+ //
+
+ for (CheckType = (EFI_MEMORY_TYPE) 0; CheckType < EfiMaxMemoryType; CheckType++) {
+ if (MemoryType != CheckType &&
+ mMemoryTypeStatistics[CheckType].Special &&
+ mMemoryTypeStatistics[CheckType].NumberOfPages > 0) {
+ if (Start >= mMemoryTypeStatistics[CheckType].BaseAddress &&
+ Start <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ if (End >= mMemoryTypeStatistics[CheckType].BaseAddress &&
+ End <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ if (Start < mMemoryTypeStatistics[CheckType].BaseAddress &&
+ End > mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+ }
+
+ if (Type == AllocateMaxAddress) {
+ MaxAddress = Start;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // If not a specific address, then find an address to allocate
+ //
+ if (Type != AllocateAddress) {
+ Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
+ NeedGuard);
+ if (Start == 0) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ //
+ // Convert pages from FreeMemory to the requested type
+ //
+ if (NeedGuard) {
+ Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
+ } else {
+ Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ if (!EFI_ERROR (Status)) {
+ if (NeedGuard) {
+ SetGuardForMemory (Start, NumberOfPages);
+ }
+ *Memory = Start;
+ }
+
+ return Status;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
+ Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
+ NeedGuard);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) *Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages));
+ }
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+ @param MemoryType Pointer to memory type
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ UINTN Alignment;
+ BOOLEAN IsGuarded;
+
+ //
+ // Free the range
+ //
+ CoreAcquireMemoryLock ();
+
+ //
+ // Find the entry that the covers the range
+ //
+ IsGuarded = FALSE;
+ Entry = NULL;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry->Start <= Memory && Entry->End > Memory) {
+ break;
+ }
+ }
+ if (Link == &gMemoryMap) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ ASSERT (Entry != NULL);
+ if (Entry->Type == EfiACPIReclaimMemory ||
+ Entry->Type == EfiACPIMemoryNVS ||
+ Entry->Type == EfiRuntimeServicesCode ||
+ Entry->Type == EfiRuntimeServicesData) {
+
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+
+ }
+
+ if ((Memory & (Alignment - 1)) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ if (MemoryType != NULL) {
+ *MemoryType = Entry->Type;
+ }
+
+ IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
+ IsMemoryGuarded (Memory);
+ if (IsGuarded) {
+ Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
+ EfiConventionalMemory);
+ } else {
+ Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE MemoryType;
+
+ Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
+ if (!EFI_ERROR (Status)) {
+ GuardFreedPagesChecked (Memory, NumberOfPages);
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages));
+ }
+ return Status;
+}
+
+/**
+ This function checks to see if the last memory map descriptor in a memory map
+ can be merged with any of the other memory map descriptors in a memorymap.
+ Memory descriptors may be merged if they are adjacent and have the same type
+ and attributes.
+
+ @param MemoryMap A pointer to the start of the memory map.
+ @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
+ @param DescriptorSize The size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+
+ @return A pointer to the next available descriptor in MemoryMap
+
+**/
+EFI_MEMORY_DESCRIPTOR *
+MergeMemoryMapDescriptor (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
+ IN UINTN DescriptorSize
+ )
+{
+ //
+ // Traverse the array of descriptors in MemoryMap
+ //
+ for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
+ //
+ // Check to see if the Type fields are identical.
+ //
+ if (MemoryMap->Type != MemoryMapDescriptor->Type) {
+ continue;
+ }
+
+ //
+ // Check to see if the Attribute fields are identical.
+ //
+ if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
+ continue;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately above MemoryMap
+ //
+ if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately below MemoryMap
+ //
+ if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
+ MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+ }
+
+ //
+ // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
+ //
+ // Return the slot immediately after MemoryMapDescriptor as the next available
+ // slot in the MemoryMap array
+ //
+ return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
+}
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN BufferSize;
+ UINTN NumberOfEntries;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ EFI_GCD_MAP_ENTRY *GcdMapEntry;
+ EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
+ EFI_MEMORY_TYPE Type;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ //
+ // Make sure the parameters are valid
+ //
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Count the number of Reserved and runtime MMIO entries
+ // And, count the number of Persistent entries.
+ //
+ NumberOfEntries = 0;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
+ (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
+ NumberOfEntries ++;
+ }
+ }
+
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);
+
+ //
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ Size += sizeof(UINT64) - (Size % sizeof (UINT64));
+
+ if (DescriptorSize != NULL) {
+ *DescriptorSize = Size;
+ }
+
+ if (DescriptorVersion != NULL) {
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // Compute the buffer size needed to fit the entire map
+ //
+ BufferSize = Size * NumberOfEntries;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ BufferSize += Size;
+ }
+
+ if (*MemoryMapSize < BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ if (MemoryMap == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Build the map
+ //
+ ZeroMem (MemoryMap, BufferSize);
+ MemoryMapStart = MemoryMap;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ ASSERT (Entry->VirtualStart == 0);
+
+ //
+ // Convert internal map into an EFI_MEMORY_DESCRIPTOR
+ //
+ MemoryMap->Type = Entry->Type;
+ MemoryMap->PhysicalStart = Entry->Start;
+ MemoryMap->VirtualStart = Entry->VirtualStart;
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
+ //
+ // If the memory type is EfiConventionalMemory, then determine if the range is part of a
+ // memory type bin and needs to be converted to the same memory type as the rest of the
+ // memory type bin in order to minimize EFI Memory Map changes across reboots. This
+ // improves the chances for a successful S4 resume in the presence of minor page allocation
+ // differences across reboots.
+ //
+ if (MemoryMap->Type == EfiConventionalMemory) {
+ for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
+ if (mMemoryTypeStatistics[Type].Special &&
+ mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
+ Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
+ Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
+ MemoryMap->Type = Type;
+ }
+ }
+ }
+ MemoryMap->Attribute = Entry->Attribute;
+ if (MemoryMap->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
+ MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+
+ ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
+ GcdMapEntry = NULL;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
+ if (Link != &mGcdMemorySpaceMap) {
+ //
+ // Merge adjacent same type and attribute GCD memory range
+ //
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
+ (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
+ (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
+ (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
+ MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
+ continue;
+ }
+ }
+
+ if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
+ MemoryMap->Type = EfiReservedMemoryType;
+ } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
+ MemoryMap->Type = EfiMemoryMappedIOPortSpace;
+ } else {
+ MemoryMap->Type = EfiMemoryMappedIO;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ MemoryMap->Type = EfiPersistentMemory;
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+ if (Link == &mGcdMemorySpaceMap) {
+ //
+ // break loop when arrive at head.
+ //
+ break;
+ }
+ if (GcdMapEntry != NULL) {
+ //
+ // Copy new GCD map entry for the following GCD range merge
+ //
+ CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
+ }
+ }
+
+ //
+ // Compute the size of the buffer actually used after all memory map descriptor merge operations
+ //
+ BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
+
+ //
+ // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
+ // set attributes and change memory paging attribute accordingly.
+ // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
+ // value from Capabilities in GCD memory map. This might cause
+ // boot problems. Clearing all paging related capabilities can
+ // workaround it. Following code is supposed to be removed once
+ // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
+ // UEFI spec and adopted by both EDK-II Core and all supported
+ // OSs.
+ //
+ MemoryMapEnd = MemoryMap;
+ MemoryMap = MemoryMapStart;
+ while (MemoryMap < MemoryMapEnd) {
+ MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ATTRIBUTE_MASK;
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
+ }
+ MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Update the map key finally
+ //
+ if (MapKey != NULL) {
+ *MapKey = mMemoryMapKey;
+ }
+
+ CoreReleaseMemoryLock ();
+
+ CoreReleaseGcdMemoryLock ();
+
+ *MemoryMapSize = BufferSize;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ return Status;
+}
+
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Find the pages to convert
+ //
+ Start = FindFreePages (MAX_ALLOC_ADDRESS, NumberOfPages, PoolType, Alignment,
+ NeedGuard);
+
+ //
+ // Convert it to boot services data
+ //
+ if (Start == 0) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
+ } else {
+ if (NeedGuard) {
+ CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
+ } else {
+ CoreConvertPages (Start, NumberOfPages, PoolType);
+ }
+ }
+
+ return (VOID *)(UINTN) Start;
+}
+
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+}
+
+
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Status = EFI_SUCCESS;
+
+ CoreAcquireMemoryLock ();
+
+ if (MapKey == mMemoryMapKey) {
+
+ //
+ // Make sure the memory map is following all the construction rules
+ // This is the last chance we will be able to display any messages on
+ // the console devices.
+ //
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[Entry->Type].Runtime) {
+ ASSERT (Entry->Type != EfiACPIReclaimMemory);
+ ASSERT (Entry->Type != EfiACPIMemoryNVS);
+ if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ }
+ }
+
+ //
+ // The map key they gave us matches what we expect. Fall through and
+ // return success. In an ideal world we would clear out all of
+ // EfiBootServicesCode and EfiBootServicesData. However this function
+ // is not the last one called by ExitBootServices(), so we have to
+ // preserve the memory contents.
+ //
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ return Status;
+}
+
+
+
+
+
+
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c
new file mode 100644
index 000000000..734fc94bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c
@@ -0,0 +1,857 @@
+/** @file
+ UEFI Memory pool management functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Index;
+ LIST_ENTRY Link;
+} POOL_FREE;
+
+
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
+#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ EFI_MEMORY_TYPE Type;
+ UINTN Size;
+ CHAR8 Data[1];
+} POOL_HEAD;
+
+#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
+
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ UINTN Size;
+} POOL_TAIL;
+
+#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
+
+#define HEAD_TO_TAIL(a) \
+ ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
+
+//
+// Each element is the sum of the 2 previous ones: this allows us to migrate
+// blocks between bins by splitting them up, while not wasting too much memory
+// as we would in a strict power-of-2 sequence
+//
+STATIC CONST UINT16 mPoolSizeTable[] = {
+ 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
+};
+
+#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
+#define LIST_TO_SIZE(a) (mPoolSizeTable [a])
+
+#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
+
+#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
+
+//
+// Globals
+//
+
+#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
+typedef struct {
+ INTN Signature;
+ UINTN Used;
+ EFI_MEMORY_TYPE MemoryType;
+ LIST_ENTRY FreeList[MAX_POOL_LIST];
+ LIST_ENTRY Link;
+} POOL;
+
+//
+// Pool header for each memory type.
+//
+POOL mPoolHead[EfiMaxMemoryType];
+
+//
+// List of pool header to search for the appropriate memory type.
+//
+LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
+
+/**
+ Get pool size table index from the specified size.
+
+ @param Size The specified size to get index from pool table.
+
+ @return The index of pool size table.
+
+**/
+STATIC
+UINTN
+GetPoolIndexFromSize (
+ UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ if (mPoolSizeTable [Index] >= Size) {
+ return Index;
+ }
+ }
+ return MAX_POOL_LIST;
+}
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ )
+{
+ UINTN Type;
+ UINTN Index;
+
+ for (Type=0; Type < EfiMaxMemoryType; Type++) {
+ mPoolHead[Type].Signature = 0;
+ mPoolHead[Type].Used = 0;
+ mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
+ for (Index=0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);
+ }
+ }
+}
+
+
+/**
+ Look up pool head for specified memory type.
+
+ @param MemoryType Memory type of which pool head is looked for
+
+ @return Pointer of Corresponding pool head.
+
+**/
+POOL *
+LookupPoolHead (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ LIST_ENTRY *Link;
+ POOL *Pool;
+ UINTN Index;
+
+ if ((UINT32)MemoryType < EfiMaxMemoryType) {
+ return &mPoolHead[MemoryType];
+ }
+
+ //
+ // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
+ // OS loaders that are provided by operating system vendors.
+ // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
+ //
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+
+ for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
+ Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
+ if (Pool->MemoryType == MemoryType) {
+ return Pool;
+ }
+ }
+
+ Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
+ if (Pool == NULL) {
+ return NULL;
+ }
+
+ Pool->Signature = POOL_SIGNATURE;
+ Pool->Used = 0;
+ Pool->MemoryType = MemoryType;
+ for (Index=0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&Pool->FreeList[Index]);
+ }
+
+ InsertHeadList (&mPoolHeadList, &Pool->Link);
+
+ return Pool;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ //
+ // If it's not a valid type, fail it
+ //
+ if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
+ (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Buffer = NULL;
+
+ //
+ // If size is too large, fail it
+ // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
+ //
+ if (Size > MAX_POOL_SIZE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
+
+ //
+ // Acquire the memory lock and make the allocation
+ //
+ Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePool,
+ PoolType,
+ Size,
+ *Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NoPages No of pages to allocate
+ @param Granularity Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+STATIC
+VOID *
+CoreAllocatePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NoPages,
+ IN UINTN Granularity,
+ IN BOOLEAN NeedGuard
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = CoreAcquireLockOrFail (&gMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
+ CoreReleaseMemoryLock ();
+
+ if (Buffer != NULL) {
+ if (NeedGuard) {
+ SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
+ }
+ ApplyMemoryProtectionPolicy(EfiConventionalMemory, PoolType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));
+ }
+ return Buffer;
+}
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ )
+{
+ POOL *Pool;
+ POOL_FREE *Free;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ CHAR8 *NewPage;
+ VOID *Buffer;
+ UINTN Index;
+ UINTN FSize;
+ UINTN Offset, MaxOffset;
+ UINTN NoPages;
+ UINTN Granularity;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ if (PoolType == EfiACPIReclaimMemory ||
+ PoolType == EfiACPIMemoryNVS ||
+ PoolType == EfiRuntimeServicesCode ||
+ PoolType == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ //
+ // Adjust the size by the pool header & tail overhead
+ //
+
+ HasPoolTail = !(NeedGuard &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
+
+ //
+ // Adjusting the Size to be of proper alignment so that
+ // we don't get an unaligned access fault later when
+ // pool_Tail is being initialized
+ //
+ Size = ALIGN_VARIABLE (Size);
+
+ Size += POOL_OVERHEAD;
+ Index = SIZE_TO_LIST(Size);
+ Pool = LookupPoolHead (PoolType);
+ if (Pool== NULL) {
+ return NULL;
+ }
+ Head = NULL;
+
+ //
+ // If allocation is over max size, just allocate pages for the request
+ // (slow)
+ //
+ if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard || PageAsPool) {
+ if (!HasPoolTail) {
+ Size -= sizeof (POOL_TAIL);
+ }
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
+ if (NeedGuard) {
+ Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
+ }
+ goto Done;
+ }
+
+ //
+ // If there's no free pool in the proper list size, go get some more pages
+ //
+ if (IsListEmpty (&Pool->FreeList[Index])) {
+
+ Offset = LIST_TO_SIZE (Index);
+ MaxOffset = Granularity;
+
+ //
+ // Check the bins holding larger blocks, and carve one up if needed
+ //
+ while (++Index < SIZE_TO_LIST (Granularity)) {
+ if (!IsListEmpty (&Pool->FreeList[Index])) {
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+ NewPage = (VOID *) Free;
+ MaxOffset = LIST_TO_SIZE (Index);
+ goto Carve;
+ }
+ }
+
+ //
+ // Get another page
+ //
+ NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity),
+ Granularity, NeedGuard);
+ if (NewPage == NULL) {
+ goto Done;
+ }
+
+ //
+ // Serve the allocation request from the head of the allocated block
+ //
+Carve:
+ Head = (POOL_HEAD *) NewPage;
+
+ //
+ // Carve up remaining space into free pool blocks
+ //
+ Index--;
+ while (Offset < MaxOffset) {
+ ASSERT (Index < MAX_POOL_LIST);
+ FSize = LIST_TO_SIZE(Index);
+
+ while (Offset + FSize <= MaxOffset) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+ Offset += FSize;
+ }
+ Index -= 1;
+ }
+
+ ASSERT (Offset == MaxOffset);
+ goto Done;
+ }
+
+ //
+ // Remove entry from free pool list
+ //
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+
+ Head = (POOL_HEAD *) Free;
+
+Done:
+ Buffer = NULL;
+
+ if (Head != NULL) {
+
+ //
+ // Account the allocation
+ //
+ Pool->Used += Size;
+
+ //
+ // If we have a pool buffer, fill in the header & tail info
+ //
+ Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
+ Head->Size = Size;
+ Head->Type = (EFI_MEMORY_TYPE) PoolType;
+ Buffer = Head->Data;
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ Tail->Signature = POOL_TAIL_SIGNATURE;
+ Tail->Size = Size;
+
+ Size -= POOL_OVERHEAD;
+ } else {
+ Size -= SIZE_OF_POOL_HEAD;
+ }
+
+ DEBUG_CLEAR_MEMORY (Buffer, Size);
+
+ DEBUG ((
+ DEBUG_POOL,
+ "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,
+ Buffer,
+ (UINT64)Size,
+ (UINT64) Pool->Used
+ ));
+
+
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));
+ }
+
+ return Buffer;
+}
+
+
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mPoolMemoryLock);
+ Status = CoreFreePoolI (Buffer, PoolType);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE PoolType;
+
+ Status = CoreInternalFreePool (Buffer, &PoolType);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePool,
+ PoolType,
+ 0,
+ Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ CoreAcquireMemoryLock ();
+ CoreFreePoolPages (Memory, NoPages);
+ CoreReleaseMemoryLock ();
+
+ GuardFreedPagesChecked (Memory, NoPages);
+ ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));
+}
+
+/**
+ Internal function. Frees guarded pool pages.
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesWithGuard (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryGuarded;
+ UINTN NoPagesGuarded;
+
+ MemoryGuarded = Memory;
+ NoPagesGuarded = NoPages;
+
+ AdjustMemoryF (&Memory, &NoPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
+ if (NoPages > 0) {
+ CoreFreePoolPagesI (PoolType, Memory, NoPages);
+ }
+}
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ POOL *Pool;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ POOL_FREE *Free;
+ UINTN Index;
+ UINTN NoPages;
+ UINTN Size;
+ CHAR8 *NewPage;
+ UINTN Offset;
+ BOOLEAN AllFree;
+ UINTN Granularity;
+ BOOLEAN IsGuarded;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT(Buffer != NULL);
+ //
+ // Get the head & tail of the pool entry
+ //
+ Head = BASE_CR (Buffer, POOL_HEAD, Data);
+ ASSERT(Head != NULL);
+
+ if (Head->Signature != POOL_HEAD_SIGNATURE &&
+ Head->Signature != POOLPAGE_HEAD_SIGNATURE) {
+ ASSERT (Head->Signature == POOL_HEAD_SIGNATURE ||
+ Head->Signature == POOLPAGE_HEAD_SIGNATURE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IsGuarded = IsPoolTypeToGuard (Head->Type) &&
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ HasPoolTail = !(IsGuarded &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ ASSERT (Tail != NULL);
+
+ //
+ // Debug
+ //
+ ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
+ ASSERT (Head->Size == Tail->Size);
+
+ if (Tail->Signature != POOL_TAIL_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Head->Size != Tail->Size) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ //
+ // Determine the pool type and account for it
+ //
+ Size = Head->Size;
+ Pool = LookupPoolHead (Head->Type);
+ if (Pool == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Pool->Used -= Size;
+ DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));
+
+ if (Head->Type == EfiACPIReclaimMemory ||
+ Head->Type == EfiACPIMemoryNVS ||
+ Head->Type == EfiRuntimeServicesCode ||
+ Head->Type == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (PoolType != NULL) {
+ *PoolType = Head->Type;
+ }
+
+ //
+ // Determine the pool list
+ //
+ Index = SIZE_TO_LIST(Size);
+ DEBUG_CLEAR_MEMORY (Head, Size);
+
+ //
+ // If it's not on the list, it must be pool pages
+ //
+ if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded || PageAsPool) {
+
+ //
+ // Return the memory pages back to free memory
+ //
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ if (IsGuarded) {
+ Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ CoreFreePoolPagesWithGuard (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ } else {
+ CoreFreePoolPagesI (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ }
+
+ } else {
+
+ //
+ // Put the pool entry onto the free pool list
+ //
+ Free = (POOL_FREE *) Head;
+ ASSERT(Free != NULL);
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+
+ //
+ // See if all the pool entries in the same page as Free are freed pool
+ // entries
+ //
+ NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
+ Free = (POOL_FREE *) &NewPage[0];
+ ASSERT(Free != NULL);
+
+ if (Free->Signature == POOL_FREE_SIGNATURE) {
+
+ AllFree = TRUE;
+ Offset = 0;
+
+ while ((Offset < Granularity) && (AllFree)) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ if (Free->Signature != POOL_FREE_SIGNATURE) {
+ AllFree = FALSE;
+ }
+ Offset += LIST_TO_SIZE(Free->Index);
+ }
+
+ if (AllFree) {
+
+ //
+ // All of the pool entries in the same page as Free are free pool
+ // entries
+ // Remove all of these pool entries from the free loop lists.
+ //
+ Free = (POOL_FREE *) &NewPage[0];
+ ASSERT(Free != NULL);
+ Offset = 0;
+
+ while (Offset < Granularity) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ RemoveEntryList (&Free->Link);
+ Offset += LIST_TO_SIZE(Free->Index);
+ }
+
+ //
+ // Free the page
+ //
+ CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,
+ EFI_SIZE_TO_PAGES (Granularity));
+ }
+ }
+ }
+
+ //
+ // If this is an OS/OEM specific memory type, then check to see if the last
+ // portion of that memory type has been freed. If it has, then free the
+ // list entry for that memory type
+ //
+ if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {
+ RemoveEntryList (&Pool->Link);
+ CoreFreePoolI (Pool, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
new file mode 100644
index 000000000..a75d41582
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
@@ -0,0 +1,282 @@
+/** @file
+ Support functions for managing debug image info table when loading and unloading
+ images.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = {
+ 0, // volatile UINT32 UpdateStatus;
+ 0, // UINT32 TableSize;
+ NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
+};
+
+UINTN mMaxTableEntries = 0;
+
+EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL;
+
+#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *))
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Allocate 4M aligned page for the structure and fill in the data.
+ // Ideally we would update the CRC now as well, but the service may not yet be available.
+ // See comments in the CoreUpdateDebugTableCrc32() function below for details.
+ //
+ Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));
+ AlignmentMask = SIZE_4MB - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);
+
+ //
+ // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress
+ // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below
+ // MAX_ADDRESS
+ //
+ Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);
+ if (Memory == 0) {
+ Memory = MAX_ADDRESS;
+ }
+ Status = CoreAllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ if (EFI_ERROR (Status)) {
+ if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {
+ DEBUG ((EFI_D_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \
+ Retry to allocate memroy as close to the top of memory as feasible.\n"));
+ }
+ //
+ // If the initial memory allocation fails, then reattempt allocation
+ // as close to the top of memory as feasible.
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ //
+ // Free overallocated pages
+ //
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Set mDebugTable to the 4MB aligned allocated pages
+ //
+ mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory);
+ ASSERT (mDebugTable != NULL);
+
+ //
+ // Initialize EFI_SYSTEM_TABLE_POINTER structure
+ //
+ mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE;
+ mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) gDxeCoreST;
+ mDebugTable->Crc32 = 0;
+
+ //
+ // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System
+ // Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ )
+{
+ ASSERT(mDebugTable != NULL);
+ mDebugTable->Crc32 = 0;
+ gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32);
+}
+
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ EFI_DEBUG_IMAGE_INFO *NewTable;
+ UINTN Index;
+ UINTN TableSize;
+
+ //
+ // Set the flag indicating that we're in the process of updating the table.
+ //
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) {
+ //
+ // We still have empty entires in the Table, find the first empty entry.
+ //
+ Index = 0;
+ while (Table[Index].NormalImage != NULL) {
+ Index++;
+ }
+ //
+ // There must be an empty entry in the in the table.
+ //
+ ASSERT (Index < mMaxTableEntries);
+ } else {
+ //
+ // Table is full, so re-allocate another page for a larger table...
+ //
+ TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;
+ NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);
+ if (NewTable == NULL) {
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+ return;
+ }
+ //
+ // Copy the old table into the new one
+ //
+ CopyMem (NewTable, Table, TableSize);
+ //
+ // Free the old table
+ //
+ CoreFreePool (Table);
+ //
+ // Update the table header
+ //
+ Table = NewTable;
+ mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;
+ //
+ // Enlarge the max table entries and set the first empty entry index to
+ // be the original max table entries.
+ //
+ Index = mMaxTableEntries;
+ mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;
+ }
+
+ //
+ // Allocate data for new entry
+ //
+ Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));
+ if (Table[Index].NormalImage != NULL) {
+ //
+ // Update the entry
+ //
+ Table[Index].NormalImage->ImageInfoType = (UINT32) ImageInfoType;
+ Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;
+ Table[Index].NormalImage->ImageHandle = ImageHandle;
+ //
+ // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize++;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ }
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
+
+
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ UINTN Index;
+
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ for (Index = 0; Index < mMaxTableEntries; Index++) {
+ if (Table[Index].NormalImage != NULL && Table[Index].NormalImage->ImageHandle == ImageHandle) {
+ //
+ // Found a match. Free up the record, then NULL the pointer to indicate the slot
+ // is free.
+ //
+ CoreFreePool (Table[Index].NormalImage);
+ Table[Index].NormalImage = NULL;
+ //
+ // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize--;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ break;
+ }
+ }
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
new file mode 100755
index 000000000..ba4e55fcd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
@@ -0,0 +1,181 @@
+/** @file
+ UEFI Miscellaneous boot Services InstallConfigurationTable service
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mSystemTableAllocateSize = 0;
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID is NULL.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gDxeCoreST->NumberOfTableEntries) {
+ //
+ // A match was found, so this is either a modify or a delete operation
+ //
+ if (Table != NULL) {
+ //
+ // If Table is not NULL, then this is a modify operation.
+ // Modify the table entry and return.
+ //
+ gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gDxeCoreST->NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(EfiConfigurationTable[Index]),
+ &(gDxeCoreST->ConfigurationTable[Index + 1]),
+ (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ } else {
+
+ //
+ // No matching GUIDs were found, so this is an add operation.
+ //
+
+ if (Table == NULL) {
+ //
+ // If Table is NULL on an add operation, then return an error.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Assume that Index == gDxeCoreST->NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
+ if (EfiConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gDxeCoreST->ConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ EfiConfigurationTable,
+ gDxeCoreST->ConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
+ // in its calling stack, updating System table to the new table pointer must
+ // be done before calling CoreFreePool() to free the old table.
+ // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
+ // and avoid the errors of use-after-free to the old table by the reenter of
+ // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ CoreFreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
+ EfiConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gDxeCoreST->NumberOfTableEntries++;
+ }
+
+ //
+ // Fix up the CRC-32 in the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
new file mode 100644
index 000000000..45356130b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
@@ -0,0 +1,1514 @@
+/** @file
+ UEFI MemoryAttributesTable support
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Guid/MemoryAttributesTable.h>
+
+#include "DxeMain.h"
+#include "HeapGuard.h"
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN ImageRecordCount;
+ UINTN CodeSegmentCountMax;
+ LIST_ENTRY ImageRecordList;
+} IMAGE_PROPERTIES_PRIVATE_DATA;
+
+STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
+ IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
+ 0,
+ 0,
+ INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
+};
+
+STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+BOOLEAN mMemoryAttributesTableEnable = TRUE;
+BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE;
+EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL;
+BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE;
+
+/**
+ Install MemoryAttributesTable.
+
+**/
+VOID
+InstallMemoryAttributesTable (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 RuntimeEntryCount;
+ EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
+ EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
+
+ if (gMemoryMapTerminated) {
+ //
+ // Directly return after MemoryMap terminated.
+ //
+ return;
+ }
+
+ if (!mMemoryAttributesTableEnable) {
+ DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table "));
+ DEBUG ((EFI_D_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ return ;
+ }
+
+ if (mMemoryAttributesTable == NULL) {
+ //
+ // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
+ // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
+ // memory for the new entry.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *) (UINTN) MAX_ADDRESS);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ MemoryMap = AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ MemoryMapStart = MemoryMap;
+ RuntimeEntryCount = 0;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ RuntimeEntryCount ++;
+ break;
+ }
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
+ }
+
+ //
+ // Allocate MemoryAttributesTable
+ //
+ MemoryAttributesTable = AllocatePool (sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
+ ASSERT (MemoryAttributesTable != NULL);
+ MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
+ MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
+ MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
+ MemoryAttributesTable->Reserved = 0;
+ DEBUG ((EFI_D_VERBOSE, "MemoryAttributesTable:\n"));
+ DEBUG ((EFI_D_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version));
+ DEBUG ((EFI_D_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
+ DEBUG ((EFI_D_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
+ MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
+ MemoryMap = MemoryMapStart;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
+ MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
+ DEBUG ((EFI_D_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
+ DEBUG ((EFI_D_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type));
+ DEBUG ((EFI_D_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
+ DEBUG ((EFI_D_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
+ DEBUG ((EFI_D_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
+ DEBUG ((EFI_D_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));
+ MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);
+ break;
+ }
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
+ }
+ MemoryMap = MemoryMapStart;
+ FreePool (MemoryMap);
+
+ //
+ // Update configuratoin table for MemoryAttributesTable.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
+ ASSERT_EFI_ERROR (Status);
+
+ if (mMemoryAttributesTable != NULL) {
+ FreePool (mMemoryAttributesTable);
+ }
+ mMemoryAttributesTable = MemoryAttributesTable;
+}
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ //
+ // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
+ //
+ if (mMemoryAttributesTableReadyToBoot &&
+ ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData))) {
+ InstallMemoryAttributesTable ();
+ }
+}
+
+/**
+ Install MemoryAttributesTable on ReadyToBoot.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ InstallMemoryAttributesTable ();
+ mMemoryAttributesTableReadyToBoot = TRUE;
+}
+
+/**
+ Install initial MemoryAttributesTable on EndOfDxe.
+ Then SMM can consume this information.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mMemoryAttributesTableEndOfDxe = TRUE;
+ InstallMemoryAttributesTable ();
+}
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
+
+ //
+ // Construct the table at ReadyToBoot.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InstallMemoryAttributesTableOnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Construct the initial table at EndOfDxe,
+ // then SMM can consume this information.
+ // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
+ // can run after it.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ InstallMemoryAttributesTableOnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ return ;
+}
+
+//
+// Below functions are for MemoryMap
+//
+
+/**
+ Converts a number of EFI_PAGEs to a size in bytes.
+
+ NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
+
+ @param Pages The number of EFI_PAGES.
+
+ @return The number of bytes associated with the number of EFI_PAGEs specified
+ by Pages.
+**/
+STATIC
+UINT64
+EfiPagesToSize (
+ IN UINT64 Pages
+ )
+{
+ return LShiftU64 (Pages, EFI_PAGE_SHIFT);
+}
+
+/**
+ Converts a size, in bytes, to a number of EFI_PAGESs.
+
+ NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
+
+ @param Size A size in bytes.
+
+ @return The number of EFI_PAGESs associated with the number of bytes specified
+ by Size.
+
+**/
+STATIC
+UINT64
+EfiSizeToPages (
+ IN UINT64 Size
+ )
+{
+ return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
+}
+
+/**
+ Acquire memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreAcquiremMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Release memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreReleasemMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart);
+ MemoryBlockLength = (UINT64) (EfiPagesToSize (NewMemoryMapEntry->NumberOfPages));
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
+ (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
+ ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return ;
+}
+
+/**
+ Enforce memory map attributes.
+ This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+EnforceMemoryMapAttribute (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ switch (MemoryMapEntry->Type) {
+ case EfiRuntimeServicesCode:
+ // do nothing
+ break;
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
+ break;
+ case EfiReservedMemoryType:
+ case EfiACPIMemoryNVS:
+ break;
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
+
+ @param Buffer Start Address
+ @param Length Address length
+
+ @return first image record covered by [buffer, length]
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+GetImageRecordByAddress (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((Buffer <= ImageRecord->ImageBase) &&
+ (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Set the memory map to new entries, according to one old entry,
+ based upon PE code section and data section in image record
+
+ @param ImageRecord An image record whose [ImageBase, ImageSize] covered
+ by old memory map entry.
+ @param NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param OldRecord A pointer to one old memory map entry.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+UINTN
+SetNewRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINTN NewRecordCount;
+ UINT64 PhysicalEnd;
+ UINT64 ImageEnd;
+
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+ NewRecordCount = 0;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ //
+ // CODE
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);
+ NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));
+ TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);
+ if (TempRecord.NumberOfPages == 0) {
+ break;
+ }
+ }
+ }
+
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ //
+ // Final DATA
+ //
+ if (TempRecord.PhysicalStart < ImageEnd) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ NewRecordCount ++;
+ }
+
+ return NewRecordCount;
+}
+
+/**
+ Return the max number of new splitted entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param OldRecord A pointer to one old memory map entry.
+
+ @retval 0 no entry need to be splitted.
+ @return the max number of new splitted entries
+**/
+STATIC
+UINTN
+GetMaxSplitRecordCount (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINTN SplitRecordCount;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+
+ SplitRecordCount = 0;
+ PhysicalStart = OldRecord->PhysicalStart;
+ PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);
+
+ do {
+ ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (ImageRecord == NULL) {
+ break;
+ }
+ SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ if (SplitRecordCount != 0) {
+ SplitRecordCount--;
+ }
+
+ return SplitRecordCount;
+}
+
+/**
+ Split the memory map to new entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param OldRecord A pointer to one old memory map entry.
+ @param NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param MaxSplitRecordCount The max number of splitted entries
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+
+ @retval 0 no entry is splitted.
+ @return the real number of splitted record.
+**/
+STATIC
+UINTN
+SplitRecord (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN UINTN MaxSplitRecordCount,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NewImageRecord;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+ UINTN NewRecordCount;
+ UINTN TotalNewRecordCount;
+ BOOLEAN IsLastRecordData;
+
+ if (MaxSplitRecordCount == 0) {
+ CopyMem (NewRecord, OldRecord, DescriptorSize);
+ return 0;
+ }
+
+ TotalNewRecordCount = 0;
+
+ //
+ // Override previous record
+ //
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalStart = TempRecord.PhysicalStart;
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+
+ ImageRecord = NULL;
+ do {
+ NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (NewImageRecord == NULL) {
+ //
+ // No more image covered by this range, stop
+ //
+ if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {
+ //
+ // If this is still address in this record, need record.
+ //
+ NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ IsLastRecordData = FALSE;
+ if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) {
+ IsLastRecordData = TRUE;
+ }
+ if (IsLastRecordData) {
+ //
+ // Last record is DATA, just merge it.
+ //
+ NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);
+ } else {
+ //
+ // Last record is CODE, create a new DATA entry.
+ //
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = TempRecord.NumberOfPages;
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ TotalNewRecordCount ++;
+ }
+ }
+ break;
+ }
+ ImageRecord = NewImageRecord;
+
+ //
+ // Set new record
+ //
+ NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
+ TotalNewRecordCount += NewRecordCount;
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
+
+ //
+ // Update PhysicalStart, in order to exclude the image buffer already splitted.
+ //
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ TempRecord.PhysicalStart = PhysicalStart;
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ //
+ // The logic in function SplitTable() ensures that TotalNewRecordCount will not be zero if the
+ // code reaches here.
+ //
+ ASSERT (TotalNewRecordCount != 0);
+ return TotalNewRecordCount - 1;
+}
+
+/**
+ Split the original memory map, and add more entries to describe PE code section and data section.
+ This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
+ This function will merge entries with same attributes finally.
+
+ NOTE: It assumes PE code/data section are page aligned.
+ NOTE: It assumes enough entry is prepared for new memory map.
+
+ Split table:
+ +---------------+
+ | Record X |
+ +---------------+
+ | Record RtCode |
+ +---------------+
+ | Record Y |
+ +---------------+
+ ==>
+ +---------------+
+ | Record X |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF1
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF2
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record Y |
+ +---------------+
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ old MemoryMap before split. The actual buffer
+ size of MemoryMap is MemoryMapSize +
+ (AdditionalRecordCount * DescriptorSize) calculated
+ below. On output, it is the size of new MemoryMap
+ after split.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SplitTable (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN DescriptorSize
+ )
+{
+ INTN IndexOld;
+ INTN IndexNew;
+ UINTN MaxSplitRecordCount;
+ UINTN RealSplitRecordCount;
+ UINTN TotalSplitRecordCount;
+ UINTN AdditionalRecordCount;
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ TotalSplitRecordCount = 0;
+ //
+ // Let old record point to end of valid MemoryMap buffer.
+ //
+ IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
+ //
+ // Let new record point to end of full MemoryMap buffer.
+ //
+ IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;
+ for (; IndexOld >= 0; IndexOld--) {
+ MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));
+ //
+ // Split this MemoryMap record
+ //
+ IndexNew -= MaxSplitRecordCount;
+ RealSplitRecordCount = SplitRecord (
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ MaxSplitRecordCount,
+ DescriptorSize
+ );
+ //
+ // Adjust IndexNew according to real split.
+ //
+ CopyMem (
+ ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),
+ ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ RealSplitRecordCount * DescriptorSize
+ );
+ IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;
+ TotalSplitRecordCount += RealSplitRecordCount;
+ IndexNew --;
+ }
+ //
+ // Move all records to the beginning.
+ //
+ CopyMem (
+ MemoryMap,
+ (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,
+ (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
+ );
+
+ *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
+
+ //
+ // Sort from low to high (Just in case)
+ //
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Set RuntimeData to XP
+ //
+ EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Merge same type to save entry size
+ //
+ MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);
+
+ return ;
+}
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN OldMemoryMapSize;
+ UINTN AdditionalRecordCount;
+
+ //
+ // If PE code/data is not aligned, just return.
+ //
+ if (!mMemoryAttributesTableEnable) {
+ return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ }
+
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquiremMemoryAttributesTableLock ();
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ OldMemoryMapSize = *MemoryMapSize;
+ Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ } else if (Status == EFI_SUCCESS) {
+ ASSERT (MemoryMap != NULL);
+ if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ //
+ // Need update status to buffer too small
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Split PE code/data
+ //
+ SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);
+ }
+ }
+
+ CoreReleasemMemoryAttributesTableLock ();
+ return Status;
+}
+
+//
+// Below functions are for ImageRecord
+//
+
+/**
+ Set MemoryAttributesTable according to PE/COFF image section alignment.
+
+ @param SectionAlignment PE/COFF section alignment
+**/
+STATIC
+VOID
+SetMemoryAttributesTableSectionAlignment (
+ IN UINT32 SectionAlignment
+ )
+{
+ if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) &&
+ mMemoryAttributesTableEnable) {
+ DEBUG ((DEBUG_VERBOSE, "SetMemoryAttributesTableSectionAlignment - Clear\n"));
+ mMemoryAttributesTableEnable = FALSE;
+ }
+}
+
+/**
+ Swap two code sections in image record.
+
+ @param FirstImageRecordCodeSection first code section in image record
+ @param SecondImageRecordCodeSection second code section in image record
+**/
+STATIC
+VOID
+SwapImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
+
+ TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
+ TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
+
+ FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
+ FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
+
+ SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
+ SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
+}
+
+/**
+ Sort code section in image record, based upon CodeSegmentBase from low to high.
+
+ @param ImageRecord image record to be sorted
+**/
+VOID
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *NextImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ NextImageRecordCodeSection = CR (
+ NextImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
+ SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
+ }
+ NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+}
+
+/**
+ Check if code section in image record is valid.
+
+ @param ImageRecord image record to be checked
+
+ @retval TRUE image record is valid
+ @retval FALSE image record is invalid
+**/
+BOOLEAN
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ LastImageRecordCodeSection = NULL;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentSize == 0) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
+ return FALSE;
+ }
+ if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return FALSE;
+ }
+ if (LastImageRecordCodeSection != NULL) {
+ if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
+ return FALSE;
+ }
+ }
+
+ LastImageRecordCodeSection = ImageRecordCodeSection;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ return TRUE;
+}
+
+/**
+ Swap two image records.
+
+ @param FirstImageRecord first image record.
+ @param SecondImageRecord second image record.
+**/
+STATIC
+VOID
+SwapImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
+ IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD TempImageRecord;
+
+ TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
+ TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
+ TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
+
+ FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
+ FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
+ FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
+
+ SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
+ SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
+ SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
+
+ SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
+}
+
+/**
+ Sort image record based upon the ImageBase from low to high.
+**/
+STATIC
+VOID
+SortImageRecord (
+ VOID
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NextImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *NextImageRecordLink;
+ LIST_ENTRY *ImageRecordEndLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ ImageRecordLink = ImageRecordList->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ ImageRecordEndLink = ImageRecordList;
+ while (ImageRecordLink != ImageRecordEndLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ while (NextImageRecordLink != ImageRecordEndLink) {
+ NextImageRecord = CR (
+ NextImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
+ SwapImageRecord (ImageRecord, NextImageRecord);
+ }
+ NextImageRecordLink = NextImageRecordLink->ForwardLink;
+ }
+
+ ImageRecordLink = ImageRecordLink->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ }
+}
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ VOID *ImageAddress;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ UINT32 SectionAlignment;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT8 *Name;
+ UINTN Index;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
+ DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
+ return ;
+ }
+
+ ImageRecord = AllocatePool (sizeof(*ImageRecord));
+ if (ImageRecord == NULL) {
+ return ;
+ }
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
+
+ //
+ // Step 1: record whole region
+ //
+ ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;
+ ImageRecord->ImageSize = RuntimeImage->ImageSize;
+
+ ImageAddress = RuntimeImage->ImageBase;
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
+ }
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ // It might be image in SMM.
+ goto Finish;
+ }
+
+ //
+ // Get SectionAlignment
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ SetMemoryAttributesTableSectionAlignment (SectionAlignment);
+ if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",
+ SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
+ DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ //
+ // Step 2: record code section
+ //
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ return ;
+ }
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
+ ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ SetMemoryAttributesTableSectionAlignment (1);
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ //
+ // Final
+ //
+ SortImageRecordCodeSection (ImageRecord);
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ goto Finish;
+ }
+
+ InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
+ mImagePropertiesPrivateData.ImageRecordCount++;
+
+ if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
+ mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
+ }
+
+ SortImageRecord ();
+
+Finish:
+ return ;
+}
+
+/**
+ Find image record according to image base and size.
+
+ @param ImageBase Base of PE image
+ @param ImageSize Size of PE image
+
+ @return image record
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+FindImageRecord (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((ImageBase == ImageRecord->ImageBase) &&
+ (ImageSize == ImageRecord->ImageSize)) {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
+ return ;
+ }
+
+ ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);
+ if (ImageRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
+ return ;
+ }
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+
+ RemoveEntryList (&ImageRecord->Link);
+ FreePool (ImageRecord);
+ mImagePropertiesPrivateData.ImageRecordCount--;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
new file mode 100644
index 000000000..7d1daf0b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
@@ -0,0 +1,1284 @@
+/** @file
+ UEFI Memory Protection support.
+
+ If the UEFI image is page aligned, the image code section is set to read only
+ and the image data section is set to non-executable.
+
+ 1) This policy is applied for all UEFI image including boot service driver,
+ runtime driver or application.
+ 2) This policy is applied only if the UEFI image meets the page alignment
+ requirement.
+ 3) This policy is applied only if the Source UEFI image matches the
+ PcdImageProtectionPolicy definition.
+ 4) This policy is not applied to the non-PE image region.
+
+ The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect
+ the image. If the CpuArch protocol is not installed yet, the DxeCore
+ enqueues the protection request. Once the CpuArch is installed, the
+ DxeCore dequeues the protection request and applies policy.
+
+ Once the image is unloaded, the protection is removed automatically.
+
+Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MemoryAttributesTable.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include "DxeMain.h"
+#include "Mem/HeapGuard.h"
+
+//
+// Image type definitions
+//
+#define IMAGE_UNKNOWN 0x00000001
+#define IMAGE_FROM_FV 0x00000002
+
+//
+// Protection policy bit definition
+//
+#define DO_NOT_PROTECT 0x00000000
+#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
+
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+UINT32 mImageProtectionPolicy;
+
+extern LIST_ENTRY mGcdMemorySpaceMap;
+
+STATIC LIST_ENTRY mProtectedImageRecordList;
+
+/**
+ Sort code section in image record, based upon CodeSegmentBase from low to high.
+
+ @param ImageRecord image record to be sorted
+**/
+VOID
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ );
+
+/**
+ Check if code section in image record is valid.
+
+ @param ImageRecord image record to be checked
+
+ @retval TRUE image record is valid
+ @retval FALSE image record is invalid
+**/
+BOOLEAN
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ );
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched.
+
+ @return UINT32 Image Type
+**/
+UINT32
+GetImageType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ if (File == NULL) {
+ return IMAGE_UNKNOWN;
+ }
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return IMAGE_FROM_FV;
+ }
+ }
+ return IMAGE_UNKNOWN;
+}
+
+/**
+ Get UEFI image protection policy based upon image type.
+
+ @param[in] ImageType The UEFI image type
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetProtectionPolicyFromImageType (
+ IN UINT32 ImageType
+ )
+{
+ if ((ImageType & mImageProtectionPolicy) == 0) {
+ return DO_NOT_PROTECT;
+ } else {
+ return PROTECT_IF_ALIGNED_ELSE_ALLOW;
+ }
+}
+
+/**
+ Get UEFI image protection policy based upon loaded image device path.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetUefiImageProtectionPolicy (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ BOOLEAN InSmm;
+ UINT32 ImageType;
+ UINT32 ProtectionPolicy;
+
+ //
+ // Check SMM
+ //
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+ if (InSmm) {
+ return FALSE;
+ }
+
+ //
+ // Check DevicePath
+ //
+ if (LoadedImage == gDxeCoreLoadedImage) {
+ ImageType = IMAGE_FROM_FV;
+ } else {
+ ImageType = GetImageType (LoadedImageDevicePath);
+ }
+ ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);
+ return ProtectionPolicy;
+}
+
+
+/**
+ Set UEFI image memory attributes.
+
+ @param[in] BaseAddress Specified start address
+ @param[in] Length Specified length
+ @param[in] Attributes Specified attributes
+**/
+VOID
+SetUefiImageMemoryAttributes (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 FinalAttributes;
+
+ Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);
+ ASSERT_EFI_ERROR(Status);
+
+ FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
+
+ DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
+
+ ASSERT(gCpu != NULL);
+ gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);
+}
+
+/**
+ Set UEFI image protection attributes.
+
+ @param[in] ImageRecord A UEFI image record
+**/
+VOID
+SetUefiImageProtectionAttributes (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINT64 CurrentBase;
+ UINT64 ImageEnd;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ CurrentBase = ImageRecord->ImageBase;
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);
+ if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+ //
+ // CODE
+ //
+ SetUefiImageMemoryAttributes (
+ ImageRecordCodeSection->CodeSegmentBase,
+ ImageRecordCodeSection->CodeSegmentSize,
+ EFI_MEMORY_RO
+ );
+ CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
+ }
+ //
+ // Last DATA
+ //
+ ASSERT (CurrentBase <= ImageEnd);
+ if (CurrentBase < ImageEnd) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageEnd - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+ return ;
+}
+
+/**
+ Return if the PE image section is aligned.
+
+ @param[in] SectionAlignment PE/COFF section alignment
+ @param[in] MemoryType PE/COFF image memory type
+
+ @retval TRUE The PE image section is aligned.
+ @retval FALSE The PE image section is not aligned.
+**/
+BOOLEAN
+IsMemoryProtectionSectionAligned (
+ IN UINT32 SectionAlignment,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT32 PageAlignment;
+
+ switch (MemoryType) {
+ case EfiRuntimeServicesCode:
+ case EfiACPIMemoryNVS:
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiRuntimeServicesData:
+ case EfiACPIReclaimMemory:
+ ASSERT (FALSE);
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiBootServicesCode:
+ case EfiLoaderCode:
+ case EfiReservedMemoryType:
+ PageAlignment = EFI_PAGE_SIZE;
+ break;
+ default:
+ ASSERT (FALSE);
+ PageAlignment = EFI_PAGE_SIZE;
+ break;
+ }
+
+ if ((SectionAlignment & (PageAlignment - 1)) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Free Image record.
+
+ @param[in] ImageRecord A UEFI image record
+**/
+VOID
+FreeImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+
+ if (ImageRecord->Link.ForwardLink != NULL) {
+ RemoveEntryList (&ImageRecord->Link);
+ }
+ FreePool (ImageRecord);
+}
+
+/**
+ Protect UEFI PE/COFF image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ VOID *ImageAddress;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ UINT32 SectionAlignment;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT8 *Name;
+ UINTN Index;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ BOOLEAN IsAligned;
+ UINT32 ProtectionPolicy;
+
+ DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
+ DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
+
+ if (gCpu == NULL) {
+ return ;
+ }
+
+ ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
+ switch (ProtectionPolicy) {
+ case DO_NOT_PROTECT:
+ return ;
+ case PROTECT_IF_ALIGNED_ELSE_ALLOW:
+ break;
+ default:
+ ASSERT(FALSE);
+ return ;
+ }
+
+ ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));
+ if (ImageRecord == NULL) {
+ return ;
+ }
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+
+ //
+ // Step 1: record whole region
+ //
+ ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;
+ ImageRecord->ImageSize = LoadedImage->ImageSize;
+
+ ImageAddress = LoadedImage->ImageBase;
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
+ }
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ // It might be image in SMM.
+ goto Finish;
+ }
+
+ //
+ // Get SectionAlignment
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);
+ if (!IsAligned) {
+ DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",
+ SectionAlignment));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ //
+ // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE
+ // can always be mapped read-only, classify a section as a code section only
+ // if it has the executable attribute set and the writable attribute cleared.
+ //
+ // This adheres more closely to the PE/COFF spec, and avoids issues with
+ // Linux OS loaders that may consist of a single read/write/execute section.
+ //
+ if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {
+ DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ //
+ // Step 2: record code section
+ //
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ return ;
+ }
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
+ ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ //
+ // If a UEFI executable consists of a single read+write+exec PE/COFF
+ // section, that isn't actually an error. The image can be launched
+ // alright, only image protection cannot be applied to it fully.
+ //
+ // One example that elicits this is (some) Linux kernels (with the EFI stub
+ // of course).
+ //
+ DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ //
+ // Final
+ //
+ SortImageRecordCodeSection (ImageRecord);
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ goto Finish;
+ }
+
+ //
+ // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
+ // Given that the loader always allocates full pages, we know the space after the image is not used.
+ //
+ ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);
+
+ //
+ // CPU ARCH present. Update memory attribute directly.
+ //
+ SetUefiImageProtectionAttributes (ImageRecord);
+
+ //
+ // Record the image record in the list so we can undo the protections later
+ //
+ InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
+
+Finish:
+ return ;
+}
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+
+ if (PcdGet32(PcdImageProtectionPolicy) != 0) {
+ for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
+ ImageRecordLink != &mProtectedImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
+ SetUefiImageMemoryAttributes (ImageRecord->ImageBase,
+ ImageRecord->ImageSize,
+ 0);
+ FreeImageRecord (ImageRecord);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ Return the EFI memory permission attribute associated with memory
+ type 'MemoryType' under the configured DXE memory protection policy.
+
+ @param MemoryType Memory type.
+**/
+STATIC
+UINT64
+GetPermissionAttributeForMemoryType (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
+ return EFI_MEMORY_XP;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+}
+
+/**
+ Merge adjacent memory map entries if they use the same memory protection policy
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+MergeMemoryMapForProtectionPolicy (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ UINT64 Attributes;
+
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ if (NewMemoryMapEntry != MemoryMapEntry) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return ;
+}
+
+
+/**
+ Remove exec permissions from all regions whose type is identified by
+ PcdDxeNxMemoryProtectionPolicy.
+**/
+STATIC
+VOID
+InitializeDxeNxMemoryProtectionPolicy (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_STATUS Status;
+ UINT64 Attributes;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_PHYSICAL_ADDRESS StackBase;
+
+ //
+ // Get the EFI memory map.
+ //
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ do {
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+ ASSERT_EFI_ERROR (Status);
+
+ StackBase = 0;
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ //
+ // Get the base of stack from Hob.
+ //
+ Hob.Raw = GetHobList ();
+ while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
+ MemoryHob = Hob.MemoryAllocation;
+ if (CompareGuid(&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
+ __FUNCTION__,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ MemoryHob->AllocDescriptor.MemoryLength
+ ));
+
+ StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ //
+ // Ensure the base of the stack is page-size aligned.
+ //
+ ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ //
+ // Ensure the base of stack can be found from Hob when stack guard is
+ // enabled.
+ //
+ ASSERT (StackBase != 0);
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to active memory regions\n",
+ __FUNCTION__
+ ));
+
+ MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
+
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+ if (Attributes != 0) {
+ SetUefiImageMemoryAttributes (
+ MemoryMapEntry->PhysicalStart,
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
+ Attributes);
+
+ //
+ // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
+ // enabled.
+ //
+ if (MemoryMapEntry->PhysicalStart == 0 &&
+ PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0) {
+
+ ASSERT (MemoryMapEntry->NumberOfPages > 0);
+ SetUefiImageMemoryAttributes (
+ 0,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes);
+ }
+
+ //
+ // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
+ // guard is enabled.
+ //
+ if (StackBase != 0 &&
+ (StackBase >= MemoryMapEntry->PhysicalStart &&
+ StackBase < MemoryMapEntry->PhysicalStart +
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT)) &&
+ PcdGetBool (PcdCpuStackGuard)) {
+
+ SetUefiImageMemoryAttributes (
+ StackBase,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes);
+ }
+
+ }
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+ FreePool (MemoryMap);
+
+ //
+ // Apply the policy for RAM regions that we know are present and
+ // accessible, but have not been added to the UEFI memory map (yet).
+ //
+ if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to inactive memory regions\n",
+ __FUNCTION__
+ ));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ Entry->EndAddress < MAX_ADDRESS &&
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
+
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
+ (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
+
+ DEBUG ((DEBUG_INFO,
+ "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
+ Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,
+ Attributes));
+
+ ASSERT(gCpu != NULL);
+ gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,
+ Entry->EndAddress - Entry->BaseAddress + 1, Attributes);
+ }
+
+ Link = Link->ForwardLink;
+ }
+ CoreReleaseGcdMemoryLock ();
+ }
+}
+
+
+/**
+ A notification for CPU_ARCH protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+MemoryProtectionCpuArchProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
+ Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Apply the memory protection policy on non-BScode/RTcode regions.
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
+ InitializeDxeNxMemoryProtectionPolicy ();
+ }
+
+ //
+ // Call notify function meant for Heap Guard.
+ //
+ HeapGuardCpuArchProtocolNotify ();
+
+ if (mImageProtectionPolicy == 0) {
+ goto Done;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **)&LoadedImageDevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ LoadedImageDevicePath = NULL;
+ }
+
+ ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
+ }
+ FreePool (HandleBuffer);
+
+Done:
+ CoreCloseEvent (Event);
+}
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ )
+{
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
+ LIST_ENTRY *Link;
+
+ //
+ // We need remove the RT protection, because RT relocation need write code segment
+ // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
+ //
+ // Firmware does not own page tables after ExitBootServices(), so the OS would
+ // have to relax protection of RT code pages across SetVirtualAddressMap(), or
+ // delay setting protections on RT code pages until after SetVirtualAddressMap().
+ // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
+ //
+ if (mImageProtectionPolicy != 0) {
+ for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
+ RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
+ SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
+ }
+ }
+}
+
+/**
+ Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
+ order to skip unfixable NULL pointer access issues detected in OptionROM or
+ boot loaders.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+DisableNullDetectionAtTheEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
+
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
+ //
+ // Disable NULL pointer detection by enabling first 4K page
+ //
+ Status = CoreGetMemorySpaceDescriptor (0, &Desc);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
+ Status = CoreSetMemorySpaceCapabilities (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Capabilities | EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = CoreSetMemorySpaceAttributes (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Attributes & ~EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Page 0 might have be allocated to avoid misuses. Free it here anyway.
+ //
+ CoreFreePages (0, 1);
+
+ CoreCloseEvent (Event);
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
+
+ return;
+}
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ EFI_EVENT EndOfDxeEvent;
+ VOID *Registration;
+
+ mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);
+
+ InitializeListHead (&mProtectedImageRecordList);
+
+ //
+ // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
+ // - code regions should have no EFI_MEMORY_XP attribute
+ // - EfiConventionalMemory and EfiBootServicesData should use the
+ // same attribute
+ //
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
+ ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
+ GetPermissionAttributeForMemoryType (EfiConventionalMemory));
+
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ MemoryProtectionCpuArchProtocolNotify,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEfiCpuArchProtocolGuid,
+ Event,
+ &Registration
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register a callback to disable NULL pointer detection at EndOfDxe
+ //
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
+ == (BIT0|BIT7)) {
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DisableNullDetectionAtTheEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return ;
+}
+
+/**
+ Returns whether we are currently executing in SMM mode.
+**/
+STATIC
+BOOLEAN
+IsInSmm (
+ VOID
+ )
+{
+ BOOLEAN InSmm;
+
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+ return InSmm;
+}
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
+ are updated in this case
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ )
+{
+ UINT64 OldAttributes;
+ UINT64 NewAttributes;
+
+ //
+ // The policy configured in PcdDxeNxMemoryProtectionPolicy
+ // does not apply to allocations performed in SMM mode.
+ //
+ if (IsInSmm ()) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the CPU arch protocol is not installed yet, we cannot manage memory
+ // permission attributes, and it is the job of the driver that installs this
+ // protocol to set the permissions on existing allocations.
+ //
+ if (gCpu == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if a DXE memory protection policy has been configured
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Don't overwrite Guard pages, which should be the first and/or last page,
+ // if any.
+ //
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ if (IsGuardPage (Memory)) {
+ Memory += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Update the executable permissions according to the DXE memory
+ // protection policy, but only if
+ // - the policy is different between the old and the new type, or
+ // - this is a newly added region (OldType == EfiMaxMemoryType)
+ //
+ NewAttributes = GetPermissionAttributeForMemoryType (NewType);
+
+ if (OldType != EfiMaxMemoryType) {
+ OldAttributes = GetPermissionAttributeForMemoryType (OldType);
+ if (OldAttributes == NewAttributes) {
+ // policy is the same between OldType and NewType
+ return EFI_SUCCESS;
+ }
+ } else if (NewAttributes == 0) {
+ // newly added region of a type that does not require protection
+ return EFI_SUCCESS;
+ }
+
+ return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
new file mode 100644
index 000000000..a9bf1284f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
@@ -0,0 +1,66 @@
+/** @file
+ UEFI Miscellaneous boot Services SetWatchdogTimer service implementation
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check our architectural protocol
+ //
+ if (gWatchdogTimer == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Attempt to set the timeout
+ //
+ Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
+
+ //
+ // Check for errors
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c
new file mode 100644
index 000000000..6ecc708ac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c
@@ -0,0 +1,107 @@
+/** @file
+ UEFI Miscellaneous boot Services Stall service implementation
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include statements
+//
+
+#include "DxeMain.h"
+
+/**
+ Internal worker function to call the Metronome Architectural Protocol for
+ the number of ticks specified by the UINT64 Counter value. WaitForTick()
+ service of the Metronome Architectural Protocol uses a UINT32 for the number
+ of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
+
+ @param Counter Number of ticks to wait.
+
+**/
+VOID
+CoreInternalWaitForTick (
+ IN UINT64 Counter
+ )
+{
+ while (RShiftU64 (Counter, 32) > 0) {
+ gMetronome->WaitForTick (gMetronome, 0xffffffff);
+ Counter -= 0xffffffff;
+ }
+ gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
+}
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ )
+{
+ UINT64 Counter;
+ UINT32 Remainder;
+ UINTN Index;
+
+ if (gMetronome == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Counter = Microseconds * 10 / gMetronome->TickPeriod
+ // 0x1999999999999999 = (2^64 - 1) / 10
+ //
+ if ((UINT64) Microseconds > 0x1999999999999999ULL) {
+ //
+ // Microseconds is too large to multiple by 10 first. Perform the divide
+ // operation first and loop 10 times to avoid 64-bit math overflow.
+ //
+ Counter = DivU64x32Remainder (
+ Microseconds,
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ for (Index = 0; Index < 10; Index++) {
+ CoreInternalWaitForTick (Counter);
+ }
+
+ if (Remainder != 0) {
+ //
+ // If Remainder was not zero, then normally, Counter would be rounded
+ // up by 1 tick. In this case, since a loop for 10 counts was used
+ // to emulate the multiply by 10 operation, Counter needs to be rounded
+ // up by 10 counts.
+ //
+ CoreInternalWaitForTick (10);
+ }
+ } else {
+ //
+ // Calculate the number of ticks by dividing the number of microseconds by
+ // the TickPeriod. Calculation is based on 100ns unit.
+ //
+ Counter = DivU64x32Remainder (
+ MultU64x32 (Microseconds, 10),
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, then round Counter up by one tick.
+ //
+ Counter++;
+ }
+ CoreInternalWaitForTick (Counter);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
new file mode 100644
index 000000000..d678166db
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
@@ -0,0 +1,1601 @@
+/** @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 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Local defines and typedefs
+//
+#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
+#define CHILD_SECTION_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_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;
+} CORE_SECTION_CHILD_NODE;
+
+#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
+#define STREAM_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_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;
+} CORE_SECTION_STREAM_NODE;
+
+#define NULL_STREAM_HANDLE 0
+
+typedef struct {
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ParentStream;
+ VOID *Registration;
+} RPN_EVENT_CONTEXT;
+
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+//
+// Module globals
+//
+LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
+
+EFI_HANDLE mSectionExtractionHandle = NULL;
+
+EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
+ CustomGuidedSectionExtract
+};
+
+
+/**
+ 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
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ Status = EFI_SUCCESS;
+ //
+ // Install custom guided extraction protocol
+ //
+ while (ExtractHandlerNumber-- > 0) {
+ Status = CoreInstallProtocolInterface (
+ &mSectionExtractionHandle,
+ &ExtractHandlerGuidTable [ExtractHandlerNumber],
+ EFI_NATIVE_INTERFACE,
+ &mCustomGuidedSectionExtractionProtocol
+ );
+ 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. AuthenticationStatus- Indicates the
+ default authentication status for the new
+ stream.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @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
+ )
+{
+ CORE_SECTION_STREAM_NODE *NewStream;
+ EFI_TPL OldTpl;
+
+ //
+ // Allocate a new stream
+ //
+ NewStream = AllocatePool (sizeof (CORE_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) {
+ CoreFreePool (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 = CORE_SECTION_STREAM_SIGNATURE;
+ NewStream->StreamHandle = (UINTN) NewStream;
+ NewStream->StreamLength = SectionStreamLength;
+ InitializeListHead (&NewStream->Children);
+ NewStream->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Add new stream to stream list
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ InsertTailList (&mStreamRoot, &NewStream->Link);
+ CoreRestoreTpl (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 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 The section stream is created 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 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,
+ FALSE,
+ 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 CORE_SECTION_STREAM_NODE *Stream,
+ IN CORE_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);
+ }
+}
+
+/**
+ 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;
+
+ Interface = NULL;
+
+ //
+ // 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 = CoreLocateProtocol (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. Initializes the section stream
+ when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
+
+ @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;
+
+ 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);
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Context->ChildNode->EncapsulatedStreamHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close the event when done.
+ //
+ gBS->CloseEvent (Event);
+ Context->ChildNode->Event = NULL;
+ FreePool (Context);
+}
+
+/**
+ Constructor for RPN event 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 CORE_SECTION_STREAM_NODE *ParentStream,
+ IN CORE_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 = EfiCreateProtocolNotifyEvent (
+ Context->ChildNode->EncapsulationGuid,
+ TPL_NOTIFY,
+ NotifyGuidedExtraction,
+ Context,
+ &Context->Registration
+ );
+}
+
+/**
+ 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.
+ 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 CORE_SECTION_STREAM_NODE *Stream,
+ IN UINT32 ChildOffset,
+ OUT CORE_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;
+
+ CORE_SECTION_CHILD_NODE *Node;
+
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
+
+ //
+ // Allocate a new node
+ //
+ *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
+ Node = *ChildNode;
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Now initialize it
+ //
+ Node->Signature = CORE_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)) {
+ CoreFreePool (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) {
+ CoreFreePool (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 = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Decompress != NULL);
+
+ Status = Decompress->GetInfo (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ (UINT32 *)&NewStreamBufferSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+ return Status;
+ }
+
+ ScratchBuffer = AllocatePool (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ NewStreamBuffer,
+ (UINT32)NewStreamBufferSize,
+ ScratchBuffer,
+ ScratchSize
+ );
+ CoreFreePool (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ }
+ } else {
+ NewStreamBuffer = NULL;
+ NewStreamBufferSize = 0;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ Stream->AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (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)) {
+ CoreFreePool (*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) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Stream->AuthenticationStatus & EFI_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)) {
+ CoreFreePool (*ChildNode);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ } else {
+ //
+ // There's no GUIDed section extraction protocol available.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ 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) {
+ AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
+ }
+
+ 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)) {
+ CoreFreePool (Node);
+ return Status;
+ }
+ }
+ }
+
+ 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.
+ 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 CORE_SECTION_STREAM_NODE *SourceStream,
+ IN EFI_SECTION_TYPE SearchType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_GUID *SectionDefinitionGuid,
+ OUT CORE_SECTION_CHILD_NODE **FoundChild,
+ OUT CORE_SECTION_STREAM_NODE **FoundStream,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ CORE_SECTION_CHILD_NODE *CurrentChildNode;
+ CORE_SECTION_CHILD_NODE *RecursedChildNode;
+ CORE_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 (
+ (CORE_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 CORE_SECTION_STREAM_NODE **FoundStream
+ )
+{
+ CORE_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 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
+ required 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 A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @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 section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ 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,
+ IN BOOLEAN IsFfs3Fv
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ChildStreamNode;
+ UINTN CopySize;
+ UINT32 ExtractedAuthenticationStatus;
+ UINTN Instance;
+ UINT8 *CopyBuffer;
+ UINTN SectionSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+
+ ChildStreamNode = NULL;
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ Instance = SectionInstance + 1;
+
+ //
+ // 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;
+ }
+
+ Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
+
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
+ Status = EFI_NOT_FOUND;
+ goto GetSection_Done;
+ }
+ 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:
+ CoreRestoreTpl (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Worker function. Destructor for child nodes.
+
+ @param ChildNode Indicates the node to destroy
+
+**/
+VOID
+FreeChildNode (
+ IN CORE_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ ASSERT (ChildNode->Signature == CORE_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 (ChildNode->EncapsulatedStreamHandle, TRUE);
+ }
+
+ if (ChildNode->Event != NULL) {
+ gBS->CloseEvent (ChildNode->Event);
+ }
+
+ //
+ // Last, free the child node itself
+ //
+ CoreFreePool (ChildNode);
+}
+
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @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 UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+
+ OldTpl = CoreRaiseTpl (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);
+ }
+ if (FreeStreamBuffer) {
+ CoreFreePool (StreamNode->StreamBuffer);
+ }
+ CoreFreePool (StreamNode);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ VOID *ScratchBuffer;
+ VOID *AllocatedOutputBuffer;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+ AllocatedOutputBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize > 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePool (ScratchBufferSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
+ if (AllocatedOutputBuffer == NULL) {
+ if (ScratchBuffer != NULL) {
+ FreePool (ScratchBuffer);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Call decode function to extract raw data from the guided section.
+ //
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ if (AllocatedOutputBuffer != NULL) {
+ CoreFreePool (AllocatedOutputBuffer);
+ }
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (*OutputBuffer != AllocatedOutputBuffer) {
+ //
+ // OutputBuffer was returned as a different value,
+ // so copy section contents to the allocated memory buffer.
+ //
+ CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Set real size of output buffer.
+ //
+ *OutputSize = (UINTN) OutputBufferSize;
+
+ //
+ // Free unused scratch buffer.
+ //
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Arm/DxeLoadFunc.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Arm/DxeLoadFunc.c
new file mode 100644
index 000000000..6619a6506
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Arm/DxeLoadFunc.c
@@ -0,0 +1,71 @@
+/** @file
+ ARM specifc functionality for DxeLoad.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+
+#include <Library/ArmMmuLib.h>
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ EFI_STATUS Status;
+
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
+ ASSERT (BaseOfStack != NULL);
+
+ if (PcdGetBool (PcdSetNxForStack)) {
+ Status = ArmSetMemoryRegionNoExec ((UINTN)BaseOfStack, STACK_SIZE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // End of PEI phase singal
+ //
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE);
+
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ TopOfStack
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h
new file mode 100644
index 000000000..bc0d41f40
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.h
@@ -0,0 +1,237 @@
+/** @file
+ Master header file for DxeIpl PEIM. All source files in this module should
+ include this file for common definitions.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PEI_DXEIPL_H__
+#define __PEI_DXEIPL_H__
+
+#include <PiPei.h>
+#include <Ppi/DxeIpl.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/Decompress.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/GuidedSectionExtraction.h>
+#include <Ppi/LoadFile.h>
+#include <Ppi/S3Resume2.h>
+#include <Ppi/RecoveryModule.h>
+#include <Ppi/CapsuleOnDisk.h>
+#include <Ppi/VectorHandoffInfo.h>
+
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Guid/FirmwareFileSystem2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiDecompressLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PerformanceLib.h>
+
+#define STACK_SIZE 0x20000
+#define BSP_STORE_SIZE 0x4000
+
+
+//
+// This PPI is installed to indicate the end of the PEI usage of memory
+//
+extern CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi;
+
+/**
+ This function installs the PPIs that require permanent memory.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @return EFI_SUCCESS The PPIs were installed successfully.
+ @return Others Some error occurs during the execution of this function.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallIplPermanentMemoryPpis (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Searches DxeCore in all firmware Volumes and loads the first
+ instance that contains DxeCore.
+
+ @return FileHandle of DxeCore to load DxeCore.
+
+**/
+EFI_PEI_FILE_HANDLE
+DxeIplFindDxeCore (
+ VOID
+ );
+
+
+/**
+ Main entry point to last PEIM
+
+ @param This Entry point for DXE IPL PPI
+ @param PeiServices General purpose services available to every PEIM.
+ @param HobList Address to the Pei HOB list
+
+ @return EFI_SUCCESS DXE core was successfully loaded.
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeLoadCore (
+ IN CONST EFI_DXE_IPL_PPI *This,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_HOB_POINTERS HobList
+ );
+
+
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ );
+
+
+
+/**
+ Updates the Stack HOB passed to DXE phase.
+
+ This function traverses the whole HOB list and update the stack HOB to
+ reflect the real stack that is used by DXE core.
+
+ @param BaseAddress The lower address of stack used by DxeCore.
+ @param Length The length of stack used by DxeCore.
+
+**/
+VOID
+UpdateStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ The ExtractSection() function processes the input section and
+ returns a pointer to the section contents. If the section being
+ extracted does not require processing (if the section
+ GuidedSectionHeader.Attributes has the
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
+ OutputBuffer is just updated to point to the start of the
+ section's contents. Otherwise, *Buffer must be allocated
+ from PEI permanent memory.
+
+ @param This Indicates the
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
+ Buffer containing the input GUIDed section to be
+ processed. OutputBuffer OutputBuffer is
+ allocated from PEI permanent memory and contains
+ the new section stream.
+ @param InputSection A pointer to the input buffer, which contains
+ the input section to be processed.
+ @param OutputBuffer A pointer to a caller-allocated buffer, whose
+ size is specified by the contents of OutputSize.
+ @param OutputSize A pointer to a caller-allocated
+ UINTN in which the size of *OutputBuffer
+ allocation is stored. If the function
+ returns anything other than EFI_SUCCESS,
+ the value of OutputSize is undefined.
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's GuidedSectionHeader.
+ Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear,
+ AuthenticationStatus must return
+ zero. These bits reflect the
+ status of the extraction
+ operation. If the function
+ returns anything other than
+ EFI_SUCCESS, the value of
+ AuthenticationStatus is
+ undefined.
+
+ @retval EFI_SUCCESS The InputSection was
+ successfully processed and the
+ section contents were returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+
+/**
+ Decompresses a section to the output buffer.
+
+ This function looks up the compression type field in the input section and
+ applies the appropriate compression algorithm to compress the section to a
+ callee allocated buffer.
+
+ @param This Points to this instance of the
+ EFI_PEI_DECOMPRESS_PEI PPI.
+ @param CompressionSection Points to the compressed section.
+ @param OutputBuffer Holds the returned pointer to the decompressed
+ sections.
+ @param OutputSize Holds the returned size of the decompress
+ section streams.
+
+ @retval EFI_SUCCESS The section was decompressed successfully.
+ OutputBuffer contains the resulting data and
+ OutputSize contains the resulting size.
+
+**/
+EFI_STATUS
+EFIAPI
+Decompress (
+ IN CONST EFI_PEI_DECOMPRESS_PPI *This,
+ IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
new file mode 100644
index 000000000..19b8a4c8a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -0,0 +1,145 @@
+## @file
+# Last PEIM executed in PEI phase to load DXE Core from a Firmware Volume.
+#
+# This module produces a special PPI named the DXE Initial Program Load (IPL)
+# PPI to discover and dispatch the DXE Foundation and components that are
+# needed to run the DXE Foundation.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeIpl
+ MODULE_UNI_FILE = DxeIpl.uni
+ FILE_GUID = 86D70125-BAA3-4296-A62F-602BEBBB9081
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimInitializeDxeIpl
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only) AARCH64 RISCV64
+#
+
+[Sources]
+ DxeIpl.h
+ DxeLoad.c
+
+[Sources.Ia32]
+ X64/VirtualMemory.h
+ X64/VirtualMemory.c
+ Ia32/DxeLoadFunc.c
+ Ia32/IdtVectorAsm.nasm
+
+[Sources.X64]
+ X64/VirtualMemory.h
+ X64/VirtualMemory.c
+ X64/DxeLoadFunc.c
+
+[Sources.EBC]
+ Ebc/DxeLoadFunc.c
+
+[Sources.ARM, Sources.AARCH64]
+ Arm/DxeLoadFunc.c
+
+[Sources.RISCV64]
+ RiscV64/DxeLoadFunc.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Packages.ARM, Packages.AARCH64]
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ PcdLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+ UefiDecompressLib
+ ReportStatusCodeLib
+ PeiServicesLib
+ HobLib
+ BaseLib
+ PeimEntryPoint
+ DebugLib
+ DebugAgentLib
+ PeiServicesTablePointerLib
+ PerformanceLib
+
+[LibraryClasses.ARM, LibraryClasses.AARCH64]
+ ArmMmuLib
+
+[Ppis]
+ gEfiDxeIplPpiGuid ## PRODUCES
+ gEfiPeiDecompressPpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_PRODUCES # Not produced on S3 boot path
+ gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiLoadFilePpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiS3Resume2PpiGuid ## SOMETIMES_CONSUMES # Consumed on S3 boot path
+ gEfiPeiRecoveryModulePpiGuid ## SOMETIMES_CONSUMES # Consumed on recovery boot path
+ ## SOMETIMES_CONSUMES
+ ## UNDEFINED # HOB
+ gEfiVectorHandoffInfoPpiGuid
+ gEfiPeiMemoryDiscoveredPpiGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeiBootInCapsuleOnDiskModePpiGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeiCapsuleOnDiskPpiGuid ## SOMETIMES_CONSUMES # Consumed on firmware update boot path
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryTypeInformation"
+ ## SOMETIMES_PRODUCES ## HOB
+ gEfiMemoryTypeInformationGuid
+
+[FeaturePcd.IA32]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[FeaturePcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress ## CONSUMES
+
+[Pcd.IA32,Pcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES
+
+[Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
+
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+# RECOVERY_FULL ## SOMETIMES_CONSUMES
+#
+#
+# [Hob]
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES # MEMORY_ALLOCATION_MODULE for DxeCore
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES # New Stack HoB
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES # Old Stack HOB
+#
+# [Hob.IPF]
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES # MEMORY_ALLOCATION_BSP_STORE
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DxeIplExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.uni b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.uni
new file mode 100644
index 000000000..035706602
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIpl.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Last PEIM executed in PEI phase to load DXE Core from a Firmware Volume.
+//
+// This module produces a special PPI named the DXE Initial Program Load (IPL)
+// PPI to discover and dispatch the DXE Foundation and components that are
+// needed to run the DXE Foundation.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Last PEIM executed in PEI phase to load DXE Core from a Firmware Volume"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces a special PPI named the DXE Initial Program Load (IPL) PPI to discover and dispatch the DXE Foundation and components that are needed to run the DXE Foundation."
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIplExtra.uni b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIplExtra.uni
new file mode 100644
index 000000000..b888e7eb2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeIplExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DxeIpl Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core DXE Services Initial Program Loader"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
new file mode 100644
index 000000000..d48028cea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
@@ -0,0 +1,835 @@
+/** @file
+ Last PEIM.
+ Responsibility of this module is to load the DXE Core from a Firmware Volume.
+
+Copyright (c) 2016 HP Development Company, L.P.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+
+
+//
+// Module Globals used in the DXE to PEI hand off
+// These must be module globals, so the stack can be switched
+//
+CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
+ DxeLoadCore
+};
+
+CONST EFI_PEI_PPI_DESCRIPTOR mDxeIplPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiDxeIplPpiGuid,
+ (VOID *) &mDxeIplPpi
+};
+
+CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
+ CustomGuidedSectionExtract
+};
+
+CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
+ Decompress
+};
+
+CONST EFI_PEI_PPI_DESCRIPTOR mDecompressPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiDecompressPpiGuid,
+ (VOID *) &mDecompressPpi
+};
+
+CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ NULL
+};
+
+CONST EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ InstallIplPermanentMemoryPpis
+};
+
+/**
+ Entry point of DXE IPL PEIM.
+
+ This function installs DXE IPL PPI. It also reloads
+ itself to memory on non-S3 resume boot path.
+
+ @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.
+ @retval Others Some error occurs during the execution of this function.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeDxeIpl (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ VOID *Dummy;
+
+ BootMode = GetBootModeHob ();
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = PeiServicesRegisterForShadow (FileHandle);
+ if (Status == EFI_SUCCESS) {
+ //
+ // EFI_SUCESS means it is the first time to call register for shadow.
+ //
+ return Status;
+ }
+
+ //
+ // Ensure that DXE IPL is shadowed to permanent memory.
+ //
+ ASSERT (Status == EFI_ALREADY_STARTED);
+
+ //
+ // DXE core load requires permanent memory.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &Dummy
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now the permanent memory exists, install the PPIs for decompression
+ // and section extraction.
+ //
+ Status = InstallIplPermanentMemoryPpis (NULL, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install memory discovered PPI notification to install PPIs for
+ // decompression and section extraction.
+ //
+ Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Install DxeIpl PPI.
+ //
+ Status = PeiServicesInstallPpi (&mDxeIplPpiList);
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
+
+/**
+ This function installs the PPIs that require permanent memory.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @return EFI_SUCCESS The PPIs were installed successfully.
+ @return Others Some error occurs during the execution of this function.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallIplPermanentMemoryPpis (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+ EFI_PEI_PPI_DESCRIPTOR *GuidPpi;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ //
+ // Install custom guided section extraction PPI
+ //
+ if (ExtractHandlerNumber > 0) {
+ GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
+ ASSERT (GuidPpi != NULL);
+ while (ExtractHandlerNumber-- > 0) {
+ GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+ GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi;
+ GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber];
+ Status = PeiServicesInstallPpi (GuidPpi++);
+ ASSERT_EFI_ERROR(Status);
+ }
+ }
+
+ //
+ // Install Decompress PPI.
+ //
+ Status = PeiServicesInstallPpi (&mDecompressPpiList);
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
+
+/**
+ Validate variable data for the MemoryTypeInformation.
+
+ @param MemoryData Variable data.
+ @param MemoryDataSize Variable data length.
+
+ @return TRUE The variable data is valid.
+ @return FALSE The variable data is invalid.
+
+**/
+BOOLEAN
+ValidateMemoryTypeInfoVariable (
+ IN EFI_MEMORY_TYPE_INFORMATION *MemoryData,
+ IN UINTN MemoryDataSize
+ )
+{
+ UINTN Count;
+ UINTN Index;
+
+ // Check the input parameter.
+ if (MemoryData == NULL) {
+ return FALSE;
+ }
+
+ // Get Count
+ Count = MemoryDataSize / sizeof (*MemoryData);
+
+ // Check Size
+ if (Count * sizeof(*MemoryData) != MemoryDataSize) {
+ return FALSE;
+ }
+
+ // Check last entry type filed.
+ if (MemoryData[Count - 1].Type != EfiMaxMemoryType) {
+ return FALSE;
+ }
+
+ // Check the type filed.
+ for (Index = 0; Index < Count - 1; Index++) {
+ if (MemoryData[Index].Type >= EfiMaxMemoryType) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Main entry point to last PEIM.
+
+ This function finds DXE Core in the firmware volume and transfer the control to
+ DXE core.
+
+ @param This Entry point for DXE IPL PPI.
+ @param PeiServices General purpose services available to every PEIM.
+ @param HobList Address to the Pei HOB list.
+
+ @return EFI_SUCCESS DXE core was successfully loaded.
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeLoadCore (
+ IN CONST EFI_DXE_IPL_PPI *This,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_FILE_INFO DxeCoreFileInfo;
+ EFI_PHYSICAL_ADDRESS DxeCoreAddress;
+ UINT64 DxeCoreSize;
+ EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
+ EFI_BOOT_MODE BootMode;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ UINTN Instance;
+ UINT32 AuthenticationState;
+ UINTN DataSize;
+ EFI_PEI_S3_RESUME2_PPI *S3Resume;
+ EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;
+ EDKII_PEI_CAPSULE_ON_DISK_PPI *PeiCapsuleOnDisk;
+ EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1];
+ VOID *CapsuleOnDiskModePpi;
+
+ //
+ // if in S3 Resume, restore configure
+ //
+ BootMode = GetBootModeHob ();
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiS3Resume2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &S3Resume
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status code that S3Resume PPI can not be found
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND)
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Status = S3Resume->S3RestoreConfig2 (S3Resume);
+ ASSERT_EFI_ERROR (Status);
+ } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_RECOVERY_BEGIN));
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiRecoveryModulePpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PeiRecovery
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate Recovery PPI Failed.(Status = %r)\n", Status));
+ //
+ // Report Status code the failure of locating Recovery PPI
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)
+ );
+ CpuDeadLoop ();
+ }
+
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_LOAD));
+ Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
+ //
+ // Report Status code that recovery image can not be found
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)
+ );
+ CpuDeadLoop ();
+ }
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_START));
+ //
+ // Now should have a HOB with the DXE core
+ //
+ } else if (BootMode == BOOT_ON_FLASH_UPDATE) {
+ //
+ // If Capsule On Disk mode, call storage stack to read Capsule Relocation file
+ // IoMmmu is highly recommmended to enable before reading
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiBootInCapsuleOnDiskModePpiGuid,
+ 0,
+ NULL,
+ &CapsuleOnDiskModePpi
+ );
+ if (!EFI_ERROR(Status)) {
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiCapsuleOnDiskPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PeiCapsuleOnDisk
+ );
+
+ //
+ // Whether failed, still goes to Firmware Update boot path. BDS will clear corresponding indicator and reboot later on
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = PeiCapsuleOnDisk->LoadCapsuleOnDisk (PeiServices, PeiCapsuleOnDisk);
+ }
+ }
+ }
+
+ if (GetFirstGuidHob ((CONST EFI_GUID *)&gEfiMemoryTypeInformationGuid) == NULL) {
+ //
+ // Don't build GuidHob if GuidHob has been installed.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Variable
+ );
+ if (!EFI_ERROR (Status)) {
+ DataSize = sizeof (MemoryData);
+ Status = Variable->GetVariable (
+ Variable,
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ NULL,
+ &DataSize,
+ &MemoryData
+ );
+ if (!EFI_ERROR (Status) && ValidateMemoryTypeInfoVariable(MemoryData, DataSize)) {
+ //
+ // Build the GUID'd HOB for DXE
+ //
+ BuildGuidDataHob (
+ &gEfiMemoryTypeInformationGuid,
+ MemoryData,
+ DataSize
+ );
+ }
+ }
+ }
+
+ //
+ // Look in all the FVs present in PEI and find the DXE Core FileHandle
+ //
+ FileHandle = DxeIplFindDxeCore ();
+
+ //
+ // Load the DXE Core from a Firmware Volume.
+ //
+ Instance = 0;
+ do {
+ Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **) &LoadFile);
+ //
+ // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &DxeCoreAddress,
+ &DxeCoreSize,
+ &DxeCoreEntryPoint,
+ &AuthenticationState
+ );
+ } while (EFI_ERROR (Status));
+
+ //
+ // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
+ //
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Add HOB for the DXE Core
+ //
+ BuildModuleHob (
+ &DxeCoreFileInfo.FileName,
+ DxeCoreAddress,
+ ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
+ DxeCoreEntryPoint
+ );
+
+ //
+ // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT));
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)DxeCoreAddress, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)));
+
+ //
+ // Transfer control to the DXE Core
+ // The hand off state is simply a pointer to the HOB list
+ //
+ HandOffToDxeCore (DxeCoreEntryPoint, HobList);
+ //
+ // If we get here, then the DXE Core returned. This is an error
+ // DxeCore should not return.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+
+/**
+ Searches DxeCore in all firmware Volumes and loads the first
+ instance that contains DxeCore.
+
+ @return FileHandle of DxeCore to load DxeCore.
+
+**/
+EFI_PEI_FILE_HANDLE
+DxeIplFindDxeCore (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+
+ Instance = 0;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances
+ //
+ Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+ //
+ // If some error occurs here, then we cannot find any firmware
+ // volume that may contain DxeCore.
+ //
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_EC_DXE_CORRUPT));
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find the DxeCore file type from the beginning in this firmware volume.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
+ // return the FileHandle.
+ //
+ return FileHandle;
+ }
+ //
+ // We cannot find DxeCore in this firmware volume, then search the next volume.
+ //
+ Instance++;
+ }
+}
+
+
+
+/**
+ The ExtractSection() function processes the input section and
+ returns a pointer to the section contents. If the section being
+ extracted does not require processing (if the section
+ GuidedSectionHeader.Attributes has the
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
+ OutputBuffer is just updated to point to the start of the
+ section's contents. Otherwise, *Buffer must be allocated
+ from PEI permanent memory.
+
+ @param This Indicates the
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
+ Buffer containing the input GUIDed section to be
+ processed. OutputBuffer OutputBuffer is
+ allocated from PEI permanent memory and contains
+ the new section stream.
+ @param InputSection A pointer to the input buffer, which contains
+ the input section to be processed.
+ @param OutputBuffer A pointer to a caller-allocated buffer, whose
+ size is specified by the contents of OutputSize.
+ @param OutputSize A pointer to a caller-allocated
+ UINTN in which the size of *OutputBuffer
+ allocation is stored. If the function
+ returns anything other than EFI_SUCCESS,
+ the value of OutputSize is undefined.
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's GuidedSectionHeader.
+ Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear,
+ AuthenticationStatus must return
+ zero. These bits reflect the
+ status of the extraction
+ operation. If the function
+ returns anything other than
+ EFI_SUCCESS, the value of
+ AuthenticationStatus is
+ undefined.
+
+ @retval EFI_SUCCESS The InputSection was
+ successfully processed and the
+ section contents were returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+)
+{
+ EFI_STATUS Status;
+ UINT8 *ScratchBuffer;
+ UINT32 ScratchBufferSize;
+ UINT32 OutputBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize != 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize));
+ if (*OutputBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
+ }
+
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ *OutputSize = (UINTN) OutputBufferSize;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Decompresses a section to the output buffer.
+
+ This function looks up the compression type field in the input section and
+ applies the appropriate compression algorithm to compress the section to a
+ callee allocated buffer.
+
+ @param This Points to this instance of the
+ EFI_PEI_DECOMPRESS_PEI PPI.
+ @param CompressionSection Points to the compressed section.
+ @param OutputBuffer Holds the returned pointer to the decompressed
+ sections.
+ @param OutputSize Holds the returned size of the decompress
+ section streams.
+
+ @retval EFI_SUCCESS The section was decompressed successfully.
+ OutputBuffer contains the resulting data and
+ OutputSize contains the resulting size.
+
+**/
+EFI_STATUS
+EFIAPI
+Decompress (
+ IN CONST EFI_PEI_DECOMPRESS_PPI *This,
+ IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *DstBuffer;
+ UINT8 *ScratchBuffer;
+ UINT32 DstBufferSize;
+ UINT32 ScratchBufferSize;
+ VOID *CompressionSource;
+ UINT32 CompressionSourceSize;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+
+ if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IS_SECTION2 (CompressionSection)) {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));
+ CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));
+ UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType;
+ } else {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION));
+ CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));
+ UncompressedLength = CompressionSection->UncompressedLength;
+ CompressionType = CompressionSection->CompressionType;
+ }
+
+ //
+ // This is a compression set, expand it
+ //
+ switch (CompressionType) {
+ case EFI_STANDARD_COMPRESSION:
+ if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress)) {
+ //
+ // Load EFI standard compression.
+ // For compressed data, decompress them to destination buffer.
+ //
+ Status = UefiDecompressGetInfo (
+ CompressionSource,
+ CompressionSourceSize,
+ &DstBufferSize,
+ &ScratchBufferSize
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // GetInfo failed
+ //
+ DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocate destination buffer
+ //
+ DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
+ if (DstBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Call decompress function
+ //
+ Status = UefiDecompress (
+ CompressionSource,
+ DstBuffer,
+ ScratchBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decompress failed
+ //
+ DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ break;
+ } else {
+ //
+ // PcdDxeIplSupportUefiDecompress is FALSE
+ // Don't support UEFI decompression algorithm.
+ //
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ case EFI_NOT_COMPRESSED:
+ //
+ // Allocate destination buffer
+ //
+ DstBufferSize = UncompressedLength;
+ DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
+ if (DstBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // stream is not actually compressed, just encapsulated. So just copy it.
+ //
+ CopyMem (DstBuffer, CompressionSource, DstBufferSize);
+ break;
+
+ default:
+ //
+ // Don't support other unknown compression type.
+ //
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ *OutputSize = DstBufferSize;
+ *OutputBuffer = DstBuffer;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Updates the Stack HOB passed to DXE phase.
+
+ This function traverses the whole HOB list and update the stack HOB to
+ reflect the real stack that is used by DXE core.
+
+ @param BaseAddress The lower address of stack used by DxeCore.
+ @param Length The length of stack used by DxeCore.
+
+**/
+VOID
+UpdateStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+ while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
+ if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
+ //
+ // Build a new memory allocation HOB with old stack info with EfiBootServicesData type. Need to
+ // avoid this region be reclaimed by DXE core as the IDT built in SEC might be on stack, and some
+ // PEIMs may also keep key information on stack
+ //
+ BuildMemoryAllocationHob (
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
+ EfiBootServicesData
+ );
+ //
+ // Update the BSP Stack Hob to reflect the new stack info.
+ //
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ebc/DxeLoadFunc.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ebc/DxeLoadFunc.c
new file mode 100644
index 000000000..5da42ff4d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ebc/DxeLoadFunc.c
@@ -0,0 +1,67 @@
+/** @file
+ EBC-specific functionality for DxeLoad.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+
+
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ EFI_STATUS Status;
+
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
+ ASSERT (BaseOfStack != NULL);
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // End of PEI phase signal
+ //
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE);
+
+ //
+ // Transfer the control to the entry point of DxeCore.
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ TopOfStack
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
new file mode 100644
index 000000000..284b34818
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -0,0 +1,465 @@
+/** @file
+ Ia32-specific functionality for DxeLoad.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+#include "VirtualMemory.h"
+
+#define IDT_ENTRY_COUNT 32
+
+typedef struct _X64_IDT_TABLE {
+ //
+ // Reserved 4 bytes preceding PeiService and IdtTable,
+ // since IDT base address should be 8-byte alignment.
+ //
+ UINT32 Reserved;
+ CONST EFI_PEI_SERVICES **PeiService;
+ X64_IDT_GATE_DESCRIPTOR IdtTable[IDT_ENTRY_COUNT];
+} X64_IDT_TABLE;
+
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries[] = {
+/* selector { Global Segment Descriptor } */
+/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
+/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
+/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
+/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
+/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
+/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR gGdt = {
+ sizeof (gGdtEntries) - 1,
+ (UINTN) gGdtEntries
+ };
+
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor = {
+ sizeof (X64_IDT_GATE_DESCRIPTOR) * IDT_ENTRY_COUNT - 1,
+ 0
+};
+
+/**
+ Allocates and fills in the Page Directory and Page Table Entries to
+ establish a 4G page table.
+
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+
+ @return The address of page table.
+
+**/
+UINTN
+Create4GPageTablesIa32Pae (
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize
+ )
+{
+ UINT8 PhysicalAddressBits;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINTN IndexOfPdpEntries;
+ UINTN IndexOfPageDirectoryEntries;
+ UINT32 NumberOfPdpEntriesNeeded;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINTN TotalPagesNum;
+ UINTN PageAddress;
+ UINT64 AddressEncMask;
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field
+ //
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ PhysicalAddressBits = 32;
+
+ //
+ // Calculate the table entries needed.
+ //
+ NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, (PhysicalAddressBits - 30));
+
+ TotalPagesNum = NumberOfPdpEntriesNeeded + 1;
+ PageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);
+ ASSERT (PageAddress != 0);
+
+ PageMap = (VOID *) PageAddress;
+ PageAddress += SIZE_4KB;
+
+ PageDirectoryPointerEntry = PageMap;
+ PhysicalAddress = 0;
+
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+ //
+ // Each Directory Pointer entries points to a page of Page Directory entires.
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
+ //
+ PageDirectoryEntry = (VOID *) PageAddress;
+ PageAddress += SIZE_4KB;
+
+ //
+ // Fill in a Page Directory Pointer Entries
+ //
+ PageDirectoryPointerEntry->Uint64 = (UINT64) (UINTN) PageDirectoryEntry | AddressEncMask;
+ PageDirectoryPointerEntry->Bits.Present = 1;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {
+ if ((IsNullDetectionEnabled () && PhysicalAddress == 0)
+ || ((PhysicalAddress < StackBase + StackSize)
+ && ((PhysicalAddress + SIZE_2MB) > StackBase))) {
+ //
+ // Need to split this 2M page that covers stack range.
+ //
+ Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress | AddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+ }
+
+ for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+ ZeroMem (
+ PageDirectoryPointerEntry,
+ sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
+ );
+ }
+
+ //
+ // Protect the page table by marking the memory used for page table to be
+ // read-only.
+ //
+ EnablePageTableProtection ((UINTN)PageMap, FALSE);
+
+ return (UINTN) PageMap;
+}
+
+/**
+ The function will check if IA32 PAE is supported.
+
+ @retval TRUE IA32 PAE is supported.
+ @retval FALSE IA32 PAE is not supported.
+
+**/
+BOOLEAN
+IsIa32PaeSupport (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ BOOLEAN Ia32PaeSupport;
+
+ Ia32PaeSupport = FALSE;
+ AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x1) {
+ AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT6) != 0) {
+ Ia32PaeSupport = TRUE;
+ }
+ }
+
+ return Ia32PaeSupport;
+}
+
+/**
+ The function will check if page table should be setup or not.
+
+ @retval TRUE Page table should be created.
+ @retval FALSE Page table should not be created.
+
+**/
+BOOLEAN
+ToBuildPageTable (
+ VOID
+ )
+{
+ if (!IsIa32PaeSupport ()) {
+ return FALSE;
+ }
+
+ if (IsNullDetectionEnabled ()) {
+ return TRUE;
+ }
+
+ if (PcdGet8 (PcdHeapGuardPropertyMask) != 0) {
+ return TRUE;
+ }
+
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ return TRUE;
+ }
+
+ if (IsEnableNonExecNeeded ()) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS BaseOfStack;
+ EFI_PHYSICAL_ADDRESS TopOfStack;
+ UINTN PageTables;
+ X64_IDT_GATE_DESCRIPTOR *IdtTable;
+ UINTN SizeOfTemplate;
+ VOID *TemplateBase;
+ EFI_PHYSICAL_ADDRESS VectorAddress;
+ UINT32 Index;
+ X64_IDT_TABLE *IdtTableForX64;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
+ BOOLEAN BuildPageTablesIa32Pae;
+
+ //
+ // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
+ //
+ if (IsNullDetectionEnabled ()) {
+ ClearFirst4KPage (HobList.Raw);
+ BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
+ }
+
+ Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {
+ //
+ // Compute the top of the stack we were allocated, which is used to load X64 dxe core.
+ // Pre-allocate a 32 bytes which confroms to x64 calling convention.
+ //
+ // The first four parameters to a function are passed in rcx, rdx, r8 and r9.
+ // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the
+ // register parameters is reserved on the stack, in case the called function
+ // wants to spill them; this is important if the function is variadic.
+ //
+ TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;
+
+ //
+ // x64 Calling Conventions requires that the stack must be aligned to 16 bytes
+ //
+ TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);
+
+ //
+ // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA
+ // memory, it may be corrupted when copying FV to high-end memory
+ //
+ AsmWriteGdtr (&gGdt);
+ //
+ // Create page table and save PageMapLevel4 to CR3
+ //
+ PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
+
+ //
+ // End of PEI phase signal
+ //
+ PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid);
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Paging might be already enabled. To avoid conflict configuration,
+ // disable paging first anyway.
+ //
+ AsmWriteCr0 (AsmReadCr0 () & (~BIT31));
+ AsmWriteCr3 (PageTables);
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob (BaseOfStack, STACK_SIZE);
+
+ SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase);
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT),
+ &VectorAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that
+ // it may not be gotten correctly after IDT register is re-written.
+ //
+ IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress;
+ IdtTableForX64->PeiService = GetPeiServicesTablePointer ();
+
+ VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1);
+ IdtTable = IdtTableForX64->IdtTable;
+ for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) {
+ IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e;
+ IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0;
+ IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL;
+
+ IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress;
+ IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16));
+ IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32));
+ IdtTable[Index].Reserved = 0;
+
+ CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate);
+ AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index);
+
+ VectorAddress += SizeOfTemplate;
+ }
+
+ gLidtDescriptor.Base = (UINTN) IdtTable;
+
+ //
+ // Disable interrupt of Debug timer, since new IDT table cannot handle it.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ AsmWriteIdtr (&gLidtDescriptor);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",
+ __FUNCTION__,
+ BaseOfStack,
+ STACK_SIZE
+ ));
+
+ //
+ // Go to Long Mode and transfer control to DxeCore.
+ // Interrupts will not get turned on until the CPU AP is loaded.
+ // Call x64 drivers passing in single argument, a pointer to the HOBs.
+ //
+ AsmEnablePaging64 (
+ SYS_CODE64_SEL,
+ DxeCoreEntryPoint,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),
+ 0,
+ TopOfStack
+ );
+ } else {
+ //
+ // Get Vector Hand-off Info PPI and build Guided HOB
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiVectorHandoffInfoPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&VectorHandoffInfoPpi
+ );
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));
+ VectorInfo = VectorHandoffInfoPpi->Info;
+ Index = 1;
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ VectorInfo ++;
+ Index ++;
+ }
+ BuildGuidDataHob (
+ &gEfiVectorHandoffInfoPpiGuid,
+ VectorHandoffInfoPpi->Info,
+ sizeof (EFI_VECTOR_HANDOFF_INFO) * Index
+ );
+ }
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;
+ TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ PageTables = 0;
+ BuildPageTablesIa32Pae = ToBuildPageTable ();
+ if (BuildPageTablesIa32Pae) {
+ PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
+ if (IsEnableNonExecNeeded ()) {
+ EnableExecuteDisableBit();
+ }
+ }
+
+ //
+ // End of PEI phase signal
+ //
+ PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid);
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid);
+ ASSERT_EFI_ERROR (Status);
+
+ if (BuildPageTablesIa32Pae) {
+ //
+ // Paging might be already enabled. To avoid conflict configuration,
+ // disable paging first anyway.
+ //
+ AsmWriteCr0 (AsmReadCr0 () & (~BIT31));
+ AsmWriteCr3 (PageTables);
+ //
+ // Set Physical Address Extension (bit 5 of CR4).
+ //
+ AsmWriteCr4 (AsmReadCr4 () | BIT5);
+ }
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob (BaseOfStack, STACK_SIZE);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",
+ __FUNCTION__,
+ BaseOfStack,
+ STACK_SIZE
+ ));
+
+ //
+ // Transfer the control to the entry point of DxeCore.
+ //
+ if (BuildPageTablesIa32Pae) {
+ AsmEnablePaging32 (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ (VOID *) (UINTN) TopOfStack
+ );
+ } else {
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ (VOID *) (UINTN) TopOfStack
+ );
+ }
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/IdtVectorAsm.nasm b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/IdtVectorAsm.nasm
new file mode 100644
index 000000000..4f9b98f18
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/Ia32/IdtVectorAsm.nasm
@@ -0,0 +1,71 @@
+;/** @file
+;
+; IDT vector entry.
+;
+; Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+ SECTION .text
+
+;
+;------------------------------------------------------------------------------
+; Generic IDT Vector Handlers for the Host.
+;
+;------------------------------------------------------------------------------
+
+ALIGN 8
+global ASM_PFX(AsmGetVectorTemplatInfo)
+global ASM_PFX(AsmVectorFixup)
+
+@VectorTemplateBase:
+ push eax
+ db 0x6a ; push #VectorNumber
+@VectorNum:
+ db 0
+ mov eax, CommonInterruptEntry
+ jmp eax
+@VectorTemplateEnd:
+
+global ASM_PFX(AsmGetVectorTemplatInfo)
+ASM_PFX(AsmGetVectorTemplatInfo):
+ mov ecx, [esp + 4]
+ mov dword [ecx], @VectorTemplateBase
+ mov eax, (@VectorTemplateEnd - @VectorTemplateBase)
+ ret
+
+global ASM_PFX(AsmVectorFixup)
+ASM_PFX(AsmVectorFixup):
+ mov eax, dword [esp + 8]
+ mov ecx, [esp + 4]
+ mov [ecx + (@VectorNum - @VectorTemplateBase)], al
+ ret
+
+;---------------------------------------;
+; CommonInterruptEntry ;
+;---------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+
+CommonInterruptEntry:
+ cli
+
+ jmp $
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/RiscV64/DxeLoadFunc.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/RiscV64/DxeLoadFunc.c
new file mode 100644
index 000000000..2ce52eb0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/RiscV64/DxeLoadFunc.c
@@ -0,0 +1,74 @@
+/** @file
+ RISC-V specific functionality for DxeLoad.
+
+ Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ EFI_STATUS Status;
+ //
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
+ if (BaseOfStack == NULL) {
+ DEBUG((DEBUG_ERROR, "%a: Can't allocate memory for stack.", __FUNCTION__));
+ ASSERT(FALSE);
+ }
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *)((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // End of PEI phase signal
+ //
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a: Fail to signal End of PEI event.", __FUNCTION__));
+ ASSERT(FALSE);
+ }
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE);
+
+ DEBUG ((DEBUG_INFO, "DXE Core new stack at %x, stack pointer at %x\n", BaseOfStack, TopOfStack));
+
+ //
+ // Transfer the control to the entry point of DxeCore.
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ TopOfStack
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
new file mode 100644
index 000000000..156a477d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
@@ -0,0 +1,132 @@
+/** @file
+ x64-specifc functionality for DxeLoad.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeIpl.h"
+#include "X64/VirtualMemory.h"
+
+
+
+/**
+ Transfers control to DxeCore.
+
+ This function performs a CPU architecture specific operations to execute
+ the entry point of DxeCore with the parameters of HobList.
+ It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
+
+ @param DxeCoreEntryPoint The entry point of DxeCore.
+ @param HobList The start of HobList passed to DxeCore.
+
+**/
+VOID
+HandOffToDxeCore (
+ IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
+ IN EFI_PEI_HOB_POINTERS HobList
+ )
+{
+ VOID *BaseOfStack;
+ VOID *TopOfStack;
+ EFI_STATUS Status;
+ UINTN PageTables;
+ UINT32 Index;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
+ VOID *GhcbBase;
+ UINTN GhcbSize;
+
+ //
+ // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
+ //
+ if (IsNullDetectionEnabled ()) {
+ ClearFirst4KPage (HobList.Raw);
+ BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
+ }
+
+ //
+ // Get Vector Hand-off Info PPI and build Guided HOB
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiVectorHandoffInfoPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&VectorHandoffInfoPpi
+ );
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));
+ VectorInfo = VectorHandoffInfoPpi->Info;
+ Index = 1;
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ VectorInfo ++;
+ Index ++;
+ }
+ BuildGuidDataHob (
+ &gEfiVectorHandoffInfoPpiGuid,
+ VectorHandoffInfoPpi->Info,
+ sizeof (EFI_VECTOR_HANDOFF_INFO) * Index
+ );
+ }
+
+ //
+ // Allocate 128KB for the Stack
+ //
+ BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
+ ASSERT (BaseOfStack != NULL);
+
+ //
+ // Compute the top of the stack we were allocated. Pre-allocate a UINTN
+ // for safety.
+ //
+ TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // Get the address and size of the GHCB pages
+ //
+ GhcbBase = (VOID *) PcdGet64 (PcdGhcbBase);
+ GhcbSize = PcdGet64 (PcdGhcbSize);
+
+ PageTables = 0;
+ if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
+ //
+ // Create page table and save PageMapLevel4 to CR3
+ //
+ PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) GhcbBase, GhcbSize);
+ } else {
+ //
+ // Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
+ // for the DxeIpl and the DxeCore are both X64.
+ //
+ ASSERT (PcdGetBool (PcdSetNxForStack) == FALSE);
+ ASSERT (PcdGetBool (PcdCpuStackGuard) == FALSE);
+ }
+
+ //
+ // End of PEI phase signal
+ //
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet (PcdDxeIplBuildPageTables)) {
+ AsmWriteCr3 (PageTables);
+ }
+
+ //
+ // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
+ //
+ UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE);
+
+ //
+ // Transfer the control to the entry point of DxeCore.
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
+ HobList.Raw,
+ NULL,
+ TopOfStack
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
new file mode 100644
index 000000000..6831946c5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -0,0 +1,933 @@
+/** @file
+ x64 Virtual Memory Management Services in the form of an IA-32 driver.
+ Used to establish a 1:1 Virtual to Physical Mapping that is required to
+ enter Long Mode (x64 64-bit mode).
+
+ While we make a 1:1 mapping (identity mapping) for all physical pages
+ we still need to use the MTRR's to ensure that the cachability attributes
+ for all memory regions is correct.
+
+ The basic idea is to use 2MB page table entries where ever possible. If
+ more granularity of cachability is required then 4K page tables are used.
+
+ References:
+ 1) IA-32 Intel(R) Architecture Software Developer's Manual Volume 1:Basic Architecture, Intel
+ 2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
+ 3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/Intel/Cpuid.h>
+#include "DxeIpl.h"
+#include "VirtualMemory.h"
+
+//
+// Global variable to keep track current available memory used as page table.
+//
+PAGE_TABLE_POOL *mPageTablePool = NULL;
+
+/**
+ Clear legacy memory located at the first 4K-page, if available.
+
+ This function traverses the whole HOB list to check if memory from 0 to 4095
+ exists and has not been allocated, and then clear it if so.
+
+ @param HobStart The start of HobList passed to DxeCore.
+
+**/
+VOID
+ClearFirst4KPage (
+ IN VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS RscHob;
+ EFI_PEI_HOB_POINTERS MemHob;
+ BOOLEAN DoClear;
+
+ RscHob.Raw = HobStart;
+ MemHob.Raw = HobStart;
+ DoClear = FALSE;
+
+ //
+ // Check if page 0 exists and free
+ //
+ while ((RscHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
+ RscHob.Raw)) != NULL) {
+ if (RscHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ RscHob.ResourceDescriptor->PhysicalStart == 0) {
+ DoClear = TRUE;
+ //
+ // Make sure memory at 0-4095 has not been allocated.
+ //
+ while ((MemHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION,
+ MemHob.Raw)) != NULL) {
+ if (MemHob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress
+ < EFI_PAGE_SIZE) {
+ DoClear = FALSE;
+ break;
+ }
+ MemHob.Raw = GET_NEXT_HOB (MemHob);
+ }
+ break;
+ }
+ RscHob.Raw = GET_NEXT_HOB (RscHob);
+ }
+
+ if (DoClear) {
+ DEBUG ((DEBUG_INFO, "Clearing first 4K-page!\r\n"));
+ SetMem (NULL, EFI_PAGE_SIZE, 0);
+ }
+
+ return;
+}
+
+/**
+ Return configure status of NULL pointer detection feature.
+
+ @return TRUE NULL pointer detection feature is enabled
+ @return FALSE NULL pointer detection feature is disabled
+
+**/
+BOOLEAN
+IsNullDetectionEnabled (
+ VOID
+ )
+{
+ return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
+}
+
+/**
+ The function will check if Execute Disable Bit is available.
+
+ @retval TRUE Execute Disable Bit is available.
+ @retval FALSE Execute Disable Bit is not available.
+
+**/
+BOOLEAN
+IsExecuteDisableBitAvailable (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ BOOLEAN Available;
+
+ Available = FALSE;
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT20) != 0) {
+ //
+ // Bit 20: Execute Disable Bit available.
+ //
+ Available = TRUE;
+ }
+ }
+
+ return Available;
+}
+
+/**
+ Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
+
+ @retval TRUE IA32_EFER.NXE should be enabled.
+ @retval FALSE IA32_EFER.NXE should not be enabled.
+
+**/
+BOOLEAN
+IsEnableNonExecNeeded (
+ VOID
+ )
+{
+ if (!IsExecuteDisableBitAvailable ()) {
+ return FALSE;
+ }
+
+ //
+ // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
+ // Features controlled by Following PCDs need this feature to be enabled.
+ //
+ return (PcdGetBool (PcdSetNxForStack) ||
+ PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
+ PcdGet32 (PcdImageProtectionPolicy) != 0);
+}
+
+/**
+ Enable Execute Disable Bit.
+
+**/
+VOID
+EnableExecuteDisableBit (
+ VOID
+ )
+{
+ UINT64 MsrRegisters;
+
+ MsrRegisters = AsmReadMsr64 (0xC0000080);
+ MsrRegisters |= BIT11;
+ AsmWriteMsr64 (0xC0000080, MsrRegisters);
+}
+
+/**
+ The function will check if page table entry should be splitted to smaller
+ granularity.
+
+ @param Address Physical memory address.
+ @param Size Size of the given physical memory.
+ @param StackBase Base address of stack.
+ @param StackSize Size of stack.
+ @param GhcbBase Base address of GHCB pages.
+ @param GhcbSize Size of GHCB area.
+
+ @retval TRUE Page table should be split.
+ @retval FALSE Page table should not be split.
+**/
+BOOLEAN
+ToSplitPageTable (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN Size,
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
+ )
+{
+ if (IsNullDetectionEnabled () && Address == 0) {
+ return TRUE;
+ }
+
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ if (StackBase >= Address && StackBase < (Address + Size)) {
+ return TRUE;
+ }
+ }
+
+ if (PcdGetBool (PcdSetNxForStack)) {
+ if ((Address < StackBase + StackSize) && ((Address + Size) > StackBase)) {
+ return TRUE;
+ }
+ }
+
+ if (GhcbBase != 0) {
+ if ((Address < GhcbBase + GhcbSize) && ((Address + Size) > GhcbBase)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+/**
+ Initialize a buffer pool for page table use only.
+
+ To reduce the potential split operation on page table, the pages reserved for
+ page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
+ at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
+ initialized with number of pages greater than or equal to the given PoolPages.
+
+ Once the pages in the pool are used up, this method should be called again to
+ reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. But usually this won't
+ happen in practice.
+
+ @param PoolPages The least page number of the pool to be created.
+
+ @retval TRUE The pool is initialized successfully.
+ @retval FALSE The memory is out of resource.
+**/
+BOOLEAN
+InitializePageTablePool (
+ IN UINTN PoolPages
+ )
+{
+ VOID *Buffer;
+
+ //
+ // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
+ // header.
+ //
+ PoolPages += 1; // Add one page for header.
+ PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
+ PAGE_TABLE_POOL_UNIT_PAGES;
+ Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
+ if (Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
+ return FALSE;
+ }
+
+ //
+ // Link all pools into a list for easier track later.
+ //
+ if (mPageTablePool == NULL) {
+ mPageTablePool = Buffer;
+ mPageTablePool->NextPool = mPageTablePool;
+ } else {
+ ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
+ mPageTablePool->NextPool = Buffer;
+ mPageTablePool = Buffer;
+ }
+
+ //
+ // Reserve one page for pool header.
+ //
+ mPageTablePool->FreePages = PoolPages - 1;
+ mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
+
+ return TRUE;
+}
+
+/**
+ This API provides a way to allocate memory for page table.
+
+ This API can be called more than once to allocate memory for page tables.
+
+ Allocates the number of 4KB pages and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary.
+
+ If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+AllocatePageTableMemory (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ //
+ // Renew the pool if necessary.
+ //
+ if (mPageTablePool == NULL ||
+ Pages > mPageTablePool->FreePages) {
+ if (!InitializePageTablePool (Pages)) {
+ return NULL;
+ }
+ }
+
+ Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
+
+ mPageTablePool->Offset += EFI_PAGES_TO_SIZE (Pages);
+ mPageTablePool->FreePages -= Pages;
+
+ return Buffer;
+}
+
+/**
+ Split 2M page to 4K.
+
+ @param[in] PhysicalAddress Start physical address the 2M page covered.
+ @param[in, out] PageEntry2M Pointer to 2M page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
+
+**/
+VOID
+Split2MPageTo4K (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry2M,
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS PhysicalAddress4K;
+ UINTN IndexOfPageTableEntries;
+ PAGE_TABLE_4K_ENTRY *PageTableEntry;
+ UINT64 AddressEncMask;
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field
+ //
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ PageTableEntry = AllocatePageTableMemory (1);
+ ASSERT (PageTableEntry != NULL);
+
+ //
+ // Fill in 2M page entry.
+ //
+ *PageEntry2M = (UINT64) (UINTN) PageTableEntry | AddressEncMask | IA32_PG_P | IA32_PG_RW;
+
+ PhysicalAddress4K = PhysicalAddress;
+ for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) {
+ //
+ // Fill in the Page Table entries
+ //
+ PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
+
+ //
+ // The GHCB range consists of two pages per CPU, the GHCB and a
+ // per-CPU variable page. The GHCB page needs to be mapped as an
+ // unencrypted page while the per-CPU variable page needs to be
+ // mapped encrypted. These pages alternate in assignment.
+ //
+ if ((GhcbBase == 0)
+ || (PhysicalAddress4K < GhcbBase)
+ || (PhysicalAddress4K >= GhcbBase + GhcbSize)
+ || (((PhysicalAddress4K - GhcbBase) & SIZE_4KB) != 0)) {
+ PageTableEntry->Uint64 |= AddressEncMask;
+ }
+ PageTableEntry->Bits.ReadWrite = 1;
+
+ if ((IsNullDetectionEnabled () && PhysicalAddress4K == 0) ||
+ (PcdGetBool (PcdCpuStackGuard) && PhysicalAddress4K == StackBase)) {
+ PageTableEntry->Bits.Present = 0;
+ } else {
+ PageTableEntry->Bits.Present = 1;
+ }
+
+ if (PcdGetBool (PcdSetNxForStack)
+ && (PhysicalAddress4K >= StackBase)
+ && (PhysicalAddress4K < StackBase + StackSize)) {
+ //
+ // Set Nx bit for stack.
+ //
+ PageTableEntry->Bits.Nx = 1;
+ }
+ }
+}
+
+/**
+ Split 1G page to 2M.
+
+ @param[in] PhysicalAddress Start physical address the 1G page covered.
+ @param[in, out] PageEntry1G Pointer to 1G page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
+
+**/
+VOID
+Split1GPageTo2M (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry1G,
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS PhysicalAddress2M;
+ UINTN IndexOfPageDirectoryEntries;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINT64 AddressEncMask;
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field
+ //
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ PageDirectoryEntry = AllocatePageTableMemory (1);
+ ASSERT (PageDirectoryEntry != NULL);
+
+ //
+ // Fill in 1G page entry.
+ //
+ *PageEntry1G = (UINT64) (UINTN) PageDirectoryEntry | AddressEncMask | IA32_PG_P | IA32_PG_RW;
+
+ PhysicalAddress2M = PhysicalAddress;
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
+ if (ToSplitPageTable (PhysicalAddress2M, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
+ //
+ // Need to split this 2M page that covers NULL or stack range.
+ //
+ Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | AddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+}
+
+/**
+ Set one page of page table pool memory to be read-only.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Address Start address of a page to be set as read-only.
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+VOID
+SetPageTablePoolReadOnly (
+ IN UINTN PageTableBase,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN Level4Paging
+ )
+{
+ UINTN Index;
+ UINTN EntryIndex;
+ UINT64 AddressEncMask;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT64 *PageTable;
+ UINT64 *NewPageTable;
+ UINT64 PageAttr;
+ UINT64 LevelSize[5];
+ UINT64 LevelMask[5];
+ UINTN LevelShift[5];
+ UINTN Level;
+ UINT64 PoolUnitSize;
+
+ ASSERT (PageTableBase != 0);
+
+ //
+ // Since the page table is always from page table pool, which is always
+ // located at the boundary of PcdPageTablePoolAlignment, we just need to
+ // set the whole pool unit to be read-only.
+ //
+ Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
+
+ LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
+ LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
+ LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
+ LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
+
+ LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
+ LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
+ LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
+ LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
+
+ LevelSize[1] = SIZE_4KB;
+ LevelSize[2] = SIZE_2MB;
+ LevelSize[3] = SIZE_1GB;
+ LevelSize[4] = SIZE_512GB;
+
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
+ PAGING_1G_ADDRESS_MASK_64;
+ PageTable = (UINT64 *)(UINTN)PageTableBase;
+ PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
+
+ for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
+ Index = ((UINTN)RShiftU64 (Address, LevelShift[Level]));
+ Index &= PAGING_PAE_INDEX_MASK;
+
+ PageAttr = PageTable[Index];
+ if ((PageAttr & IA32_PG_PS) == 0) {
+ //
+ // Go to next level of table.
+ //
+ PageTable = (UINT64 *)(UINTN)(PageAttr & ~AddressEncMask &
+ PAGING_4K_ADDRESS_MASK_64);
+ continue;
+ }
+
+ if (PoolUnitSize >= LevelSize[Level]) {
+ //
+ // Clear R/W bit if current page granularity is not larger than pool unit
+ // size.
+ //
+ if ((PageAttr & IA32_PG_RW) != 0) {
+ while (PoolUnitSize > 0) {
+ //
+ // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
+ // one page (2MB). Then we don't need to update attributes for pages
+ // crossing page directory. ASSERT below is for that purpose.
+ //
+ ASSERT (Index < EFI_PAGE_SIZE/sizeof (UINT64));
+
+ PageTable[Index] &= ~(UINT64)IA32_PG_RW;
+ PoolUnitSize -= LevelSize[Level];
+
+ ++Index;
+ }
+ }
+
+ break;
+
+ } else {
+ //
+ // The smaller granularity of page must be needed.
+ //
+ ASSERT (Level > 1);
+
+ NewPageTable = AllocatePageTableMemory (1);
+ ASSERT (NewPageTable != NULL);
+
+ PhysicalAddress = PageAttr & LevelMask[Level];
+ for (EntryIndex = 0;
+ EntryIndex < EFI_PAGE_SIZE/sizeof (UINT64);
+ ++EntryIndex) {
+ NewPageTable[EntryIndex] = PhysicalAddress | AddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ if (Level > 2) {
+ NewPageTable[EntryIndex] |= IA32_PG_PS;
+ }
+ PhysicalAddress += LevelSize[Level - 1];
+ }
+
+ PageTable[Index] = (UINT64)(UINTN)NewPageTable | AddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ PageTable = NewPageTable;
+ }
+ }
+}
+
+/**
+ Prevent the memory pages used for page table from been overwritten.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+VOID
+EnablePageTableProtection (
+ IN UINTN PageTableBase,
+ IN BOOLEAN Level4Paging
+ )
+{
+ PAGE_TABLE_POOL *HeadPool;
+ PAGE_TABLE_POOL *Pool;
+ UINT64 PoolSize;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ if (mPageTablePool == NULL) {
+ return;
+ }
+
+ //
+ // Disable write protection, because we need to mark page table to be write
+ // protected.
+ //
+ AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
+
+ //
+ // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
+ // remember original one in advance.
+ //
+ HeadPool = mPageTablePool;
+ Pool = HeadPool;
+ do {
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
+ PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
+
+ //
+ // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE, which
+ // is one of page size of the processor (2MB by default). Let's apply the
+ // protection to them one by one.
+ //
+ while (PoolSize > 0) {
+ SetPageTablePoolReadOnly(PageTableBase, Address, Level4Paging);
+ Address += PAGE_TABLE_POOL_UNIT_SIZE;
+ PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE;
+ }
+
+ Pool = Pool->NextPool;
+ } while (Pool != HeadPool);
+
+ //
+ // Enable write protection, after page table attribute updated.
+ //
+ AsmWriteCr0 (AsmReadCr0() | CR0_WP);
+}
+
+/**
+ Allocates and fills in the Page Directory and Page Table Entries to
+ establish a 1:1 Virtual to Physical mapping.
+
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB base address.
+ @param[in] GhcbSize GHCB size.
+
+ @return The address of 4 level page map.
+
+**/
+UINTN
+CreateIdentityMappingPageTables (
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
+ )
+{
+ UINT32 RegEax;
+ CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX EcxFlags;
+ UINT32 RegEdx;
+ UINT8 PhysicalAddressBits;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ UINTN IndexOfPml5Entries;
+ UINTN IndexOfPml4Entries;
+ UINTN IndexOfPdpEntries;
+ UINTN IndexOfPageDirectoryEntries;
+ UINT32 NumberOfPml5EntriesNeeded;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel5Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINTN TotalPagesNum;
+ UINTN BigPageAddress;
+ VOID *Hob;
+ BOOLEAN Page5LevelSupport;
+ BOOLEAN Page1GSupport;
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
+ UINT64 AddressEncMask;
+ IA32_CR4 Cr4;
+
+ //
+ // Set PageMapLevel5Entry to suppress incorrect compiler/analyzer warnings
+ //
+ PageMapLevel5Entry = NULL;
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field
+ //
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ 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;
+ }
+ }
+
+ Page5LevelSupport = FALSE;
+ if (PcdGetBool (PcdUse5LevelPageTable)) {
+ AsmCpuidEx (
+ CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO, NULL,
+ &EcxFlags.Uint32, NULL, NULL
+ );
+ if (EcxFlags.Bits.FiveLevelPage != 0) {
+ Page5LevelSupport = TRUE;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "AddressBits=%u 5LevelPaging=%u 1GPage=%u\n", PhysicalAddressBits, Page5LevelSupport, Page1GSupport));
+
+ //
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses
+ // when 5-Level Paging is disabled,
+ // due to either unsupported by HW, or disabled by PCD.
+ //
+ ASSERT (PhysicalAddressBits <= 52);
+ if (!Page5LevelSupport && PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
+ }
+
+ //
+ // Calculate the table entries needed.
+ //
+ NumberOfPml5EntriesNeeded = 1;
+ if (PhysicalAddressBits > 48) {
+ NumberOfPml5EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 48);
+ PhysicalAddressBits = 48;
+ }
+
+ NumberOfPml4EntriesNeeded = 1;
+ if (PhysicalAddressBits > 39) {
+ NumberOfPml4EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 39);
+ PhysicalAddressBits = 39;
+ }
+
+ NumberOfPdpEntriesNeeded = 1;
+ ASSERT (PhysicalAddressBits > 30);
+ NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 30);
+
+ //
+ // Pre-allocate big pages to avoid later allocations.
+ //
+ if (!Page1GSupport) {
+ TotalPagesNum = ((NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;
+ } else {
+ TotalPagesNum = (NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;
+ }
+
+ //
+ // Substract the one page occupied by PML5 entries if 5-Level Paging is disabled.
+ //
+ if (!Page5LevelSupport) {
+ TotalPagesNum--;
+ }
+
+ DEBUG ((DEBUG_INFO, "Pml5=%u Pml4=%u Pdp=%u TotalPage=%Lu\n",
+ NumberOfPml5EntriesNeeded, NumberOfPml4EntriesNeeded,
+ NumberOfPdpEntriesNeeded, (UINT64)TotalPagesNum));
+
+ BigPageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);
+ ASSERT (BigPageAddress != 0);
+
+ //
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+ //
+ PageMap = (VOID *) BigPageAddress;
+ if (Page5LevelSupport) {
+ //
+ // By architecture only one PageMapLevel5 exists - so lets allocate storage for it.
+ //
+ PageMapLevel5Entry = PageMap;
+ BigPageAddress += SIZE_4KB;
+ }
+ PageAddress = 0;
+
+ for ( IndexOfPml5Entries = 0
+ ; IndexOfPml5Entries < NumberOfPml5EntriesNeeded
+ ; IndexOfPml5Entries++) {
+ //
+ // Each PML5 entry points to a page of PML4 entires.
+ // So lets allocate space for them and fill them in in the IndexOfPml4Entries loop.
+ // When 5-Level Paging is disabled, below allocation happens only once.
+ //
+ PageMapLevel4Entry = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ if (Page5LevelSupport) {
+ //
+ // Make a PML5 Entry
+ //
+ PageMapLevel5Entry->Uint64 = (UINT64) (UINTN) PageMapLevel4Entry | AddressEncMask;
+ PageMapLevel5Entry->Bits.ReadWrite = 1;
+ PageMapLevel5Entry->Bits.Present = 1;
+ PageMapLevel5Entry++;
+ }
+
+ for ( IndexOfPml4Entries = 0
+ ; IndexOfPml4Entries < (NumberOfPml5EntriesNeeded == 1 ? NumberOfPml4EntriesNeeded : 512)
+ ; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+ //
+ // Each PML4 entry points to a page of Page Directory Pointer entires.
+ // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
+ //
+ PageDirectoryPointerEntry = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ //
+ // Make a PML4 Entry
+ //
+ PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;
+ PageMapLevel4Entry->Bits.ReadWrite = 1;
+ PageMapLevel4Entry->Bits.Present = 1;
+
+ if (Page1GSupport) {
+ PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
+ if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
+ Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
+ PageDirectory1GEntry->Bits.ReadWrite = 1;
+ PageDirectory1GEntry->Bits.Present = 1;
+ PageDirectory1GEntry->Bits.MustBe1 = 1;
+ }
+ }
+ } else {
+ for ( IndexOfPdpEntries = 0
+ ; IndexOfPdpEntries < (NumberOfPml4EntriesNeeded == 1 ? NumberOfPdpEntriesNeeded : 512)
+ ; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+ //
+ // Each Directory Pointer entries points to a page of Page Directory entires.
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
+ //
+ PageDirectoryEntry = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ //
+ // Fill in a Page Directory Pointer Entries
+ //
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;
+ PageDirectoryPointerEntry->Bits.ReadWrite = 1;
+ PageDirectoryPointerEntry->Bits.Present = 1;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
+ if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize, GhcbBase, GhcbSize)) {
+ //
+ // Need to split this 2M page that covers NULL or stack range.
+ //
+ Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+ }
+
+ //
+ // Fill with null entry for unused PDPTE
+ //
+ ZeroMem (PageDirectoryPointerEntry, (512 - IndexOfPdpEntries) * sizeof(PAGE_MAP_AND_DIRECTORY_POINTER));
+ }
+ }
+
+ //
+ // For the PML4 entries we are not using fill in a null entry.
+ //
+ ZeroMem (PageMapLevel4Entry, (512 - IndexOfPml4Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));
+ }
+
+ if (Page5LevelSupport) {
+ Cr4.UintN = AsmReadCr4 ();
+ Cr4.Bits.LA57 = 1;
+ AsmWriteCr4 (Cr4.UintN);
+ //
+ // For the PML5 entries we are not using fill in a null entry.
+ //
+ ZeroMem (PageMapLevel5Entry, (512 - IndexOfPml5Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));
+ }
+
+ //
+ // Protect the page table by marking the memory used for page table to be
+ // read-only.
+ //
+ EnablePageTableProtection ((UINTN)PageMap, TRUE);
+
+ //
+ // Set IA32_EFER.NXE if necessary.
+ //
+ if (IsEnableNonExecNeeded ()) {
+ EnableExecuteDisableBit ();
+ }
+
+ return (UINTN)PageMap;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
new file mode 100644
index 000000000..6b7c38a44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
@@ -0,0 +1,330 @@
+/** @file
+ x64 Long Mode Virtual Memory Management Definitions
+
+ References:
+ 1) IA-32 Intel(R) Architecture Software Developer's Manual Volume 1:Basic Architecture, Intel
+ 2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
+ 3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
+ 4) AMD64 Architecture Programmer's Manual Volume 2: System Programming
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _VIRTUAL_MEMORY_H_
+#define _VIRTUAL_MEMORY_H_
+
+
+#define SYS_CODE64_SEL 0x38
+
+
+#pragma pack(1)
+
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+
+typedef struct {
+ IA32_IDT_GATE_DESCRIPTOR Ia32IdtEntry;
+ UINT32 Offset32To63;
+ UINT32 Reserved;
+} X64_IDT_GATE_DESCRIPTOR;
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 4KB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 PAT:1; //
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:17; // Must be zero;
+ UINT64 PageTableBaseAddress:22; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+#define CR0_WP BIT16
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+#define PAGING_PAE_INDEX_MASK 0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGING_L1_ADDRESS_SHIFT 12
+#define PAGING_L2_ADDRESS_SHIFT 21
+#define PAGING_L3_ADDRESS_SHIFT 30
+#define PAGING_L4_ADDRESS_SHIFT 39
+
+#define PAGING_PML4E_NUMBER 4
+
+#define PAGE_TABLE_POOL_ALIGNMENT BASE_2MB
+#define PAGE_TABLE_POOL_UNIT_SIZE SIZE_2MB
+#define PAGE_TABLE_POOL_UNIT_PAGES EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
+#define PAGE_TABLE_POOL_ALIGN_MASK \
+ (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
+
+typedef struct {
+ VOID *NextPool;
+ UINTN Offset;
+ UINTN FreePages;
+} PAGE_TABLE_POOL;
+
+/**
+ Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
+
+ @retval TRUE IA32_EFER.NXE should be enabled.
+ @retval FALSE IA32_EFER.NXE should not be enabled.
+
+**/
+BOOLEAN
+IsEnableNonExecNeeded (
+ VOID
+ );
+
+/**
+ Enable Execute Disable Bit.
+
+**/
+VOID
+EnableExecuteDisableBit (
+ VOID
+ );
+
+/**
+ Split 2M page to 4K.
+
+ @param[in] PhysicalAddress Start physical address the 2M page covered.
+ @param[in, out] PageEntry2M Pointer to 2M page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
+
+**/
+VOID
+Split2MPageTo4K (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry2M,
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbSize
+ );
+
+/**
+ Allocates and fills in the Page Directory and Page Table Entries to
+ establish a 1:1 Virtual to Physical mapping.
+
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+ @param[in] GhcbBase GHCB page area base address.
+ @param[in] GhcbSize GHCB page area size.
+
+ @return The address of 4 level page map.
+
+**/
+UINTN
+CreateIdentityMappingPageTables (
+ IN EFI_PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN EFI_PHYSICAL_ADDRESS GhcbBase,
+ IN UINTN GhcbkSize
+ );
+
+
+/**
+
+ Fix up the vector number in the vector code.
+
+ @param VectorBase Base address of the vector handler.
+ @param VectorNum Index of vector.
+
+**/
+VOID
+EFIAPI
+AsmVectorFixup (
+ VOID *VectorBase,
+ UINT8 VectorNum
+ );
+
+
+/**
+
+ Get the information of vector template.
+
+ @param TemplateBase Base address of the template code.
+
+ @return Size of the Template code.
+
+**/
+UINTN
+EFIAPI
+AsmGetVectorTemplatInfo (
+ OUT VOID **TemplateBase
+ );
+
+/**
+ Clear legacy memory located at the first 4K-page.
+
+ This function traverses the whole HOB list to check if memory from 0 to 4095
+ exists and has not been allocated, and then clear it if so.
+
+ @param HobStart The start of HobList passed to DxeCore.
+
+**/
+VOID
+ClearFirst4KPage (
+ IN VOID *HobStart
+ );
+
+/**
+ Return configure status of NULL pointer detection feature.
+
+ @return TRUE NULL pointer detection feature is enabled
+ @return FALSE NULL pointer detection feature is disabled
+**/
+BOOLEAN
+IsNullDetectionEnabled (
+ VOID
+ );
+
+/**
+ Prevent the memory pages used for page table from been overwritten.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+VOID
+EnablePageTableProtection (
+ IN UINTN PageTableBase,
+ IN BOOLEAN Level4Paging
+ );
+
+/**
+ This API provides a way to allocate memory for page table.
+
+ This API can be called more than once to allocate memory for page tables.
+
+ Allocates the number of 4KB pages and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary.
+
+ If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+AllocatePageTableMemory (
+ IN UINTN Pages
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/BootMode/BootMode.c b/roms/edk2/MdeModulePkg/Core/Pei/BootMode/BootMode.c
new file mode 100644
index 000000000..37a49c4a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/BootMode/BootMode.c
@@ -0,0 +1,80 @@
+/** @file
+ This module provide function for ascertaining and updating the boot mode:
+ GetBootMode()
+ SetBootMode()
+ See PI Specification volume I, chapter 9 Boot Paths for additional information
+ on the boot mode.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+ This service enables PEIMs to ascertain the present value of the boot mode.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode A pointer to contain the value of the boot mode.
+
+ @retval EFI_SUCCESS The boot mode was returned successfully.
+ @retval EFI_INVALID_PARAMETER BootMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT EFI_BOOT_MODE *BootMode
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+
+ if (BootMode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ HandOffHob = (PrivateData->HobList.HandoffInformationTable);
+
+ *BootMode = HandOffHob->BootMode;
+
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This service enables PEIMs to update the boot mode variable.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode The value of the boot mode to set.
+
+ @return EFI_SUCCESS The value was successfully updated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ HandOffHob = (PrivateData->HobList.HandoffInformationTable);
+
+ HandOffHob->BootMode = BootMode;
+
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c b/roms/edk2/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c
new file mode 100644
index 000000000..3c62d7b60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/CpuIo/CpuIo.c
@@ -0,0 +1,535 @@
+/** @file
+ The default version of EFI_PEI_CPU_IO_PPI support published by PeiServices in
+ PeiCore initialization phase.
+
+ EFI_PEI_CPU_IO_PPI is installed by some platform or chipset-specific PEIM that
+ abstracts the processor-visible I/O operations. When PeiCore is started, the
+ default version of EFI_PEI_CPU_IO_PPI will be assigned to PeiServices table.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+///
+/// This default instance of EFI_PEI_CPU_IO_PPI install assigned to EFI_PEI_SERVICE.CpuIo
+/// when PeiCore's initialization.
+///
+EFI_PEI_CPU_IO_PPI gPeiDefaultCpuIoPpi = {
+ {
+ PeiDefaultMemRead,
+ PeiDefaultMemWrite
+ },
+ {
+ PeiDefaultIoRead,
+ PeiDefaultIoWrite
+ },
+ PeiDefaultIoRead8,
+ PeiDefaultIoRead16,
+ PeiDefaultIoRead32,
+ PeiDefaultIoRead64,
+ PeiDefaultIoWrite8,
+ PeiDefaultIoWrite16,
+ PeiDefaultIoWrite32,
+ PeiDefaultIoWrite64,
+ PeiDefaultMemRead8,
+ PeiDefaultMemRead16,
+ PeiDefaultMemRead32,
+ PeiDefaultMemRead64,
+ PeiDefaultMemWrite8,
+ PeiDefaultMemWrite16,
+ PeiDefaultMemWrite32,
+ PeiDefaultMemWrite64
+};
+
+/**
+ Memory-based read services.
+
+ This function is to perform the Memory Access Read service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Memory-based write services.
+
+ This function is to perform the Memory Access Write service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ IO-based read services.
+
+ This function is to perform the IO-base read service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ IO-based write services.
+
+ This function is to perform the IO-base write service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ 8-bit I/O read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the I/O space.
+**/
+UINT8
+EFIAPI
+PeiDefaultIoRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 16-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 16-bit value returned from the I/O space.
+**/
+UINT16
+EFIAPI
+PeiDefaultIoRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 32-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 32-bit value returned from the I/O space.
+**/
+UINT32
+EFIAPI
+PeiDefaultIoRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ Reads an 64-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 64-bit value returned from the I/O space.
+**/
+UINT64
+EFIAPI
+PeiDefaultIoRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 8-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ )
+{
+}
+
+/**
+ 16-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ )
+{
+}
+
+/**
+ 32-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ )
+{
+}
+
+/**
+ 64-bit I/O write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ )
+{
+}
+
+/**
+ 8-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the memory space.
+
+**/
+UINT8
+EFIAPI
+PeiDefaultMemRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 16-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 16-bit value returned from the memory space.
+
+**/
+UINT16
+EFIAPI
+PeiDefaultMemRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 32-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 32-bit value returned from the memory space.
+
+**/
+UINT32
+EFIAPI
+PeiDefaultMemRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 64-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 64-bit value returned from the memory space.
+
+**/
+UINT64
+EFIAPI
+PeiDefaultMemRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ )
+{
+ return 0;
+}
+
+/**
+ 8-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ )
+{
+}
+
+/**
+ 16-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ )
+{
+}
+
+/**
+ 32-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ )
+{
+}
+
+/**
+ 64-bit memory write operations.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then do
+ nothing.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ )
+{
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.c b/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.c
new file mode 100644
index 000000000..b53e5f268
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.c
@@ -0,0 +1,247 @@
+/** @file
+ PEI Dispatcher Dependency Evaluator
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria to be scheduled is
+ that the dependency expression is satisfied.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+#include "Dependency.h"
+
+/**
+
+ This routine determines if a PPI has been installed.
+ The truth value of a GUID is determined by if the PPI has
+ been published and can be queried from the PPI database.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Stack Reference to EVAL_STACK_ENTRY that contains PPI GUID to check
+
+ @retval TRUE if the PPI is already installed.
+ @retval FALSE if the PPI has yet to be installed.
+
+**/
+BOOLEAN
+IsPpiInstalled (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EVAL_STACK_ENTRY *Stack
+ )
+{
+ VOID *PeiInstance;
+ EFI_STATUS Status;
+ EFI_GUID PpiGuid;
+
+ //
+ // If there is no GUID to evaluate, just return current result on stack.
+ //
+ if (Stack->Operator == NULL) {
+ return Stack->Result;
+ }
+
+ //
+ // Copy the GUID into a local variable so that there are no
+ // possibilities of alignment faults for cross-compilation
+ // environments such as Intel?Itanium(TM).
+ //
+ CopyMem(&PpiGuid, Stack->Operator, sizeof(EFI_GUID));
+
+ //
+ // Check if the PPI is installed.
+ //
+ Status = PeiServicesLocatePpi(
+ &PpiGuid, // GUID
+ 0, // INSTANCE
+ NULL, // EFI_PEI_PPI_DESCRIPTOR
+ &PeiInstance // PPI
+ );
+
+ if (EFI_ERROR(Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This is the POSTFIX version of the dependency evaluator. When a
+ PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on
+ the evaluation stack. When that entry is popped from the evaluation
+ stack, the PPI is checked if it is installed. This method allows
+ some time savings as not all PPIs must be checked for certain
+ operation types (AND, OR).
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param DependencyExpression Pointer to a dependency expression. The Grammar adheres to
+ the BNF described above and is stored in postfix notation.
+
+ @retval TRUE if it is a well-formed Grammar
+ @retval FALSE if the dependency expression overflows the evaluation stack
+ if the dependency expression underflows the evaluation stack
+ if the dependency expression is not a well-formed Grammar.
+
+**/
+BOOLEAN
+PeimDispatchReadiness (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *DependencyExpression
+ )
+{
+ DEPENDENCY_EXPRESSION_OPERAND *Iterator;
+ EVAL_STACK_ENTRY *StackPtr;
+ EVAL_STACK_ENTRY EvalStack[MAX_GRAMMAR_SIZE];
+
+ Iterator = DependencyExpression;
+
+ StackPtr = EvalStack;
+
+ while (TRUE) {
+
+ switch (*(Iterator++)) {
+
+ //
+ // For performance reason we put the frequently used items in front of
+ // the rarely used items
+ //
+
+ case (EFI_DEP_PUSH):
+ //
+ // Check to make sure the dependency grammar doesn't overflow the
+ // EvalStack on the push
+ //
+ if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+
+ //
+ // Push the pointer to the PUSH opcode operator (pointer to PPI GUID)
+ // We will evaluate if the PPI is installed on the POP operation.
+ //
+ StackPtr->Operator = (VOID *) Iterator;
+ Iterator = Iterator + sizeof (EFI_GUID);
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = %a\n", StackPtr->Operator, IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
+ StackPtr++;
+ break;
+
+ case (EFI_DEP_AND):
+ case (EFI_DEP_OR):
+ if (*(Iterator - 1) == EFI_DEP_AND) {
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ }
+ //
+ // Check to make sure the dependency grammar doesn't underflow the
+ // EvalStack on the two POPs for the AND operation. Don't need to
+ // check for the overflow on PUSHing the result since we already
+ // did two POPs.
+ //
+ if (StackPtr < &EvalStack[2]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+
+ //
+ // Evaluate the first POPed operator only. If the operand is
+ // EFI_DEP_AND and the POPed operator evaluates to FALSE, or the
+ // operand is EFI_DEP_OR and the POPed operator evaluates to TRUE,
+ // we don't need to check the second operator, and the result will be
+ // evaluation of the POPed operator. Otherwise, don't POP the second
+ // operator since it will now evaluate to the final result on the
+ // next operand that causes a POP.
+ //
+ StackPtr--;
+ //
+ // Iterator has increased by 1 after we retrieve the operand, so here we
+ // should get the value pointed by (Iterator - 1), in order to obtain the
+ // same operand.
+ //
+ if (*(Iterator - 1) == EFI_DEP_AND) {
+ if (!(IsPpiInstalled (PeiServices, StackPtr))) {
+ (StackPtr-1)->Result = FALSE;
+ (StackPtr-1)->Operator = NULL;
+ }
+ } else {
+ if (IsPpiInstalled (PeiServices, StackPtr)) {
+ (StackPtr-1)->Result = TRUE;
+ (StackPtr-1)->Operator = NULL;
+ }
+ }
+ break;
+
+ case (EFI_DEP_END):
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ StackPtr--;
+ //
+ // Check to make sure EvalStack is balanced. If not, then there is
+ // an error in the dependency grammar, so return EFI_INVALID_PARAMETER.
+ //
+ if (StackPtr != &EvalStack[0]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
+ return IsPpiInstalled (PeiServices, StackPtr);
+
+ case (EFI_DEP_NOT):
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ //
+ // Check to make sure the dependency grammar doesn't underflow the
+ // EvalStack on the POP for the NOT operation. Don't need to
+ // check for the overflow on PUSHing the result since we already
+ // did a POP.
+ //
+ if (StackPtr < &EvalStack[1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ (StackPtr-1)->Result = (BOOLEAN) !IsPpiInstalled (PeiServices, (StackPtr-1));
+ (StackPtr-1)->Operator = NULL;
+ break;
+
+ case (EFI_DEP_TRUE):
+ case (EFI_DEP_FALSE):
+ if (*(Iterator - 1) == EFI_DEP_TRUE) {
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ }
+ //
+ // Check to make sure the dependency grammar doesn't overflow the
+ // EvalStack on the push
+ //
+ if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Underflow Error)\n"));
+ return FALSE;
+ }
+ //
+ // Iterator has increased by 1 after we retrieve the operand, so here we
+ // should get the value pointed by (Iterator - 1), in order to obtain the
+ // same operand.
+ //
+ if (*(Iterator - 1) == EFI_DEP_TRUE) {
+ StackPtr->Result = TRUE;
+ } else {
+ StackPtr->Result = FALSE;
+ }
+ StackPtr->Operator = NULL;
+ StackPtr++;
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Invalid opcode)\n"));
+ //
+ // The grammar should never arrive here
+ //
+ return FALSE;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.h b/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.h
new file mode 100644
index 000000000..ae066aee1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Dependency/Dependency.h
@@ -0,0 +1,26 @@
+/** @file
+ This module contains data specific to dependency expressions
+ and local function prototypes.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_DEPENDENCY_H_
+#define _PEI_DEPENDENCY_H_
+
+
+#define MAX_GRAMMAR_SIZE 64
+
+//
+// type definitions
+//
+typedef UINT8 DEPENDENCY_EXPRESSION_OPERAND;
+
+typedef struct {
+ BOOLEAN Result;
+ VOID *Operator;
+} EVAL_STACK_ENTRY;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/roms/edk2/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
new file mode 100644
index 000000000..b9a279ec7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -0,0 +1,1828 @@
+/** @file
+ EFI PEI Core dispatch services
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Discover all PEIMs and optional Apriori file in one FV. There is at most one
+ Apriori file in one FV.
+
+
+ @param Private Pointer to the private data passed in from caller
+ @param CoreFileHandle The instance of PEI_CORE_FV_HANDLE.
+
+**/
+VOID
+DiscoverPeimsAndOrderWithApriori (
+ IN PEI_CORE_INSTANCE *Private,
+ IN PEI_CORE_FV_HANDLE *CoreFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ EFI_PEI_FILE_HANDLE AprioriFileHandle;
+ EFI_GUID *Apriori;
+ UINTN Index;
+ UINTN Index2;
+ UINTN PeimIndex;
+ UINTN PeimCount;
+ EFI_GUID *Guid;
+ EFI_PEI_FILE_HANDLE *TempFileHandles;
+ EFI_GUID *TempFileGuid;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_FV_FILE_INFO FileInfo;
+
+ FvPpi = CoreFileHandle->FvPpi;
+
+ //
+ // Walk the FV and find all the PEIMs and the Apriori file.
+ //
+ AprioriFileHandle = NULL;
+ Private->CurrentFvFileHandles = NULL;
+ Guid = NULL;
+
+ //
+ // If the current FV has been scanned, directly get its cached records.
+ //
+ if (CoreFileHandle->ScanFv) {
+ Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
+ return;
+ }
+
+ TempFileHandles = Private->TempFileHandles;
+ TempFileGuid = Private->TempFileGuid;
+
+ //
+ // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.
+ //
+ PeimCount = 0;
+ FileHandle = NULL;
+ do {
+ Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ if (PeimCount >= Private->TempPeimCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempFileHandles = AllocatePool (
+ sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP));
+ ASSERT (TempFileHandles != NULL);
+ CopyMem (
+ TempFileHandles,
+ Private->TempFileHandles,
+ sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount
+ );
+ Private->TempFileHandles = TempFileHandles;
+ TempFileGuid = AllocatePool (
+ sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP));
+ ASSERT (TempFileGuid != NULL);
+ CopyMem (
+ TempFileGuid,
+ Private->TempFileGuid,
+ sizeof (EFI_GUID) * Private->TempPeimCount
+ );
+ Private->TempFileGuid = TempFileGuid;
+ Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;
+ }
+
+ TempFileHandles[PeimCount++] = FileHandle;
+ }
+ } while (!EFI_ERROR (Status));
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a(): Found 0x%x PEI FFS files in the %dth FV\n",
+ __FUNCTION__,
+ PeimCount,
+ Private->CurrentPeimFvCount
+ ));
+
+ if (PeimCount == 0) {
+ //
+ // No PEIM FFS file is found, set ScanFv flag and return.
+ //
+ CoreFileHandle->ScanFv = TRUE;
+ return;
+ }
+
+ //
+ // Record PeimCount, allocate buffer for PeimState and FvFileHandles.
+ //
+ CoreFileHandle->PeimCount = PeimCount;
+ CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);
+ ASSERT (CoreFileHandle->PeimState != NULL);
+ CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
+ ASSERT (CoreFileHandle->FvFileHandles != NULL);
+
+ //
+ // Get Apriori File handle
+ //
+ Private->AprioriCount = 0;
+ Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
+ if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {
+ //
+ // Read the Apriori file
+ //
+ Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Calculate the number of PEIMs in the Apriori file
+ //
+ Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+ Private->AprioriCount = FileInfo.BufferSize;
+ if (IS_SECTION2 (FileInfo.Buffer)) {
+ Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+ Private->AprioriCount /= sizeof (EFI_GUID);
+
+ for (Index = 0; Index < PeimCount; Index++) {
+ //
+ // Make an array of file name GUIDs that matches the FileHandle array so we can convert
+ // quickly from file name to file handle
+ //
+ Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));
+ }
+
+ //
+ // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.
+ // Add available PEIMs in Apriori file into FvFileHandles array.
+ //
+ Index = 0;
+ for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {
+ Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);
+ if (Guid != NULL) {
+ PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);
+ CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];
+
+ //
+ // Since we have copied the file handle we can remove it from this list.
+ //
+ TempFileHandles[PeimIndex] = NULL;
+ }
+ }
+
+ //
+ // Update valid AprioriCount
+ //
+ Private->AprioriCount = Index;
+
+ //
+ // Add in any PEIMs not in the Apriori file
+ //
+ for (Index2 = 0; Index2 < PeimCount; Index2++) {
+ if (TempFileHandles[Index2] != NULL) {
+ CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];
+ TempFileHandles[Index2] = NULL;
+ }
+ }
+ ASSERT (Index == PeimCount);
+ }
+ } else {
+ CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
+ }
+
+ //
+ // The current FV File Handles have been cached. So that we don't have to scan the FV again.
+ // Instead, we can retrieve the file handles within this FV from cached records.
+ //
+ CoreFileHandle->ScanFv = TRUE;
+ Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
+}
+
+//
+// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
+// This part of memory still need reserved on the very top of memory so that the DXE Core could
+// use these memory for data initialization. This macro should be sync with the same marco
+// defined in DXE Core.
+//
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
+/**
+ This function is to test if the memory range described in resource HOB is available or not.
+
+ This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
+ memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
+ available or not.
+
+ @param PrivateData Pointer to the private data passed in from caller
+ @param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB
+**/
+BOOLEAN
+PeiLoadFixAddressIsMemoryRangeAvailable (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ BOOLEAN IsAvailable;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ IsAvailable = TRUE;
+ if (PrivateData == NULL || ResourceHob == NULL) {
+ return FALSE;
+ }
+ //
+ // test if the memory range describe in the HOB is already allocated.
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a memory allocation HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ if(MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart &&
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength) {
+ IsAvailable = FALSE;
+ break;
+ }
+ }
+ }
+
+ return IsAvailable;
+
+}
+/**
+ Hook function for Loading Module at Fixed Address feature
+
+ This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
+ configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
+ feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general.
+ And also the function will re-install PEI memory.
+
+ @param PrivateData Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiLoadFixAddressHook(
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PHYSICAL_ADDRESS TopLoadingAddress;
+ UINT64 PeiMemorySize;
+ UINT64 TotalReservedMemorySize;
+ UINT64 MemoryRangeEnd;
+ EFI_PHYSICAL_ADDRESS HighAddress;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;
+ EFI_PEI_HOB_POINTERS CurrentHob;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_HOB_POINTERS NextHob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ //
+ // Initialize Local Variables
+ //
+ CurrentResourceHob = NULL;
+ ResourceHob = NULL;
+ NextResourceHob = NULL;
+ HighAddress = 0;
+ TopLoadingAddress = 0;
+ MemoryRangeEnd = 0;
+ CurrentHob.Raw = PrivateData->HobList.Raw;
+ PeiMemorySize = PrivateData->PhysicalMemoryLength;
+ //
+ // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE
+ // then RuntimeCodePage range and Boot time code range.
+ //
+ TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber));
+ TotalReservedMemorySize+= EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)) ;
+ //
+ // PEI memory range lies below the top reserved memory
+ //
+ TotalReservedMemorySize += PeiMemorySize;
+
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
+ //
+ // Loop through the system memory typed HOB to merge the adjacent memory range
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
+ //
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY ||
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS) {
+ continue;
+ }
+
+ for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
+ if (NextHob.Raw == Hob.Raw){
+ continue;
+ }
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ NextResourceHob = NextHob.ResourceDescriptor;
+ //
+ // test if range described in this NextResourceHob is system memory and have the same attribute.
+ // Note: Here is a assumption that system memory should always be healthy even without test.
+ //
+ if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){
+
+ //
+ // See if the memory range described in ResourceHob and NextResourceHob is adjacent
+ //
+ if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)||
+ (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&
+ ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {
+
+ MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
+
+ ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
+ ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
+
+
+ ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
+
+ ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
+ //
+ // Delete the NextResourceHob by marking it as unused.
+ //
+ GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ //
+ // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
+ // the allocated memory range
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a memory allocation HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ NextResourceHob = NextHob.ResourceDescriptor;
+ //
+ // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
+ //
+ if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) {
+ continue;
+ }
+ //
+ // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB
+ //
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart &&
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
+ //
+ // Build separate resource HOB for this allocated range
+ //
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ NextResourceHob->ResourceAttribute,
+ NextResourceHob->PhysicalStart,
+ (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
+ );
+ }
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ NextResourceHob->ResourceAttribute,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
+ (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
+ );
+ }
+ NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Try to find and validate the TOP address.
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
+ //
+ // The LMFA feature is enabled as load module at fixed absolute address.
+ //
+ TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64(PcdLoadModuleAtFixAddressEnable);
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
+ //
+ // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
+ //
+ if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
+ ASSERT (FALSE);
+ }
+ //
+ // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
+ //
+ // See if Top address specified by user is valid.
+ //
+ if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress &&
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress &&
+ PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ CurrentResourceHob = ResourceHob;
+ CurrentHob = Hob;
+ break;
+ }
+ }
+ }
+ }
+ if (CurrentResourceHob != NULL) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));
+ TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
+ } else {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
+ //
+ // Print the recommended Top address range.
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
+ //
+ // See if Top address specified by user is valid.
+ //
+ if (ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n",
+ (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
+ ));
+ }
+ }
+ }
+ }
+ //
+ // Assert here
+ //
+ ASSERT (FALSE);
+ return;
+ }
+ } else {
+ //
+ // The LMFA feature is enabled as load module at fixed offset relative to TOLM
+ // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
+ //
+ //
+ // Search for a tested memory region that is below MAX_ADDRESS
+ //
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // See if this is a resource descriptor HOB
+ //
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+ //
+ // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
+ //
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&
+ ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
+ //
+ // See if this is the highest largest system memory region below MaxAddress
+ //
+ if (ResourceHob->PhysicalStart > HighAddress) {
+ CurrentResourceHob = ResourceHob;
+ CurrentHob = Hob;
+ HighAddress = CurrentResourceHob->PhysicalStart;
+ }
+ }
+ }
+ }
+ if (CurrentResourceHob == NULL) {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
+ //
+ // Assert here
+ //
+ ASSERT (FALSE);
+ return;
+ } else {
+ TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ;
+ }
+ }
+
+ if (CurrentResourceHob != NULL) {
+ //
+ // rebuild resource HOB for PEI memory and reserved memory
+ //
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_TESTED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ (TopLoadingAddress - TotalReservedMemorySize),
+ TotalReservedMemorySize
+ );
+ //
+ // rebuild resource for the remain memory if necessary
+ //
+ if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ CurrentResourceHob->PhysicalStart,
+ (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
+ );
+ }
+ if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ ),
+ TopLoadingAddress,
+ (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress)
+ );
+ }
+ //
+ // Delete CurrentHob by marking it as unused since the memory range described by is rebuilt.
+ //
+ GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
+ }
+
+ //
+ // Cache the top address for Loading Module at Fixed Address feature
+ //
+ PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));
+ //
+ // reinstall the PEI memory relative to TopLoadingAddress
+ //
+ PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;
+ PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
+}
+
+/**
+ This routine is invoked in switch stack as PeiCore Entry.
+
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+ @param Private Pointer to old core data that is used to initialize the
+ core's data areas.
+**/
+VOID
+EFIAPI
+PeiCoreEntry (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ //
+ // Entry PEI Phase 2
+ //
+ PeiCore (SecCoreData, NULL, Private);
+}
+
+/**
+ Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
+
+ @param[in] SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+ @param[in] Private Pointer to the private data passed in from caller.
+
+**/
+VOID
+PeiCheckAndSwitchStack (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ VOID *LoadFixPeiCodeBegin;
+ EFI_STATUS Status;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ UINT64 NewStackSize;
+ EFI_PHYSICAL_ADDRESS TopOfOldStack;
+ EFI_PHYSICAL_ADDRESS TopOfNewStack;
+ UINTN StackOffset;
+ BOOLEAN StackOffsetPositive;
+ EFI_PHYSICAL_ADDRESS TemporaryRamBase;
+ UINTN TemporaryRamSize;
+ UINTN TemporaryStackSize;
+ VOID *TemporaryStackBase;
+ UINTN PeiTemporaryRamSize;
+ VOID *PeiTemporaryRamBase;
+ EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
+ EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
+ EFI_PHYSICAL_ADDRESS HoleMemBase;
+ UINTN HoleMemSize;
+ UINTN HeapTemporaryRamSize;
+ EFI_PHYSICAL_ADDRESS TempBase1;
+ UINTN TempSize1;
+ EFI_PHYSICAL_ADDRESS TempBase2;
+ UINTN TempSize2;
+ UINTN Index;
+
+ PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
+
+ if (Private->SwitchStackSignal) {
+ //
+ // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
+ // usage in temporary memory for debugging.
+ //
+ DEBUG_CODE_BEGIN ();
+ UINT32 *StackPointer;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ for (StackPointer = (UINT32*)SecCoreData->StackBase;
+ (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
+ && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
+ StackPointer ++) {
+ }
+
+ DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
+ DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
+ DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
+ DEBUG ((DEBUG_INFO, " temporary memory stack ever used: %d bytes.\n",
+ (UINT32)(SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
+ ));
+ DEBUG ((DEBUG_INFO, " temporary memory heap used for HobList: %d bytes.\n",
+ (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
+ ));
+ DEBUG ((DEBUG_INFO, " temporary memory heap occupied by memory pages: %d bytes.\n",
+ (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
+ ));
+ for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ DEBUG ((DEBUG_INFO, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
+ }
+ }
+ DEBUG_CODE_END ();
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ //
+ // Loading Module at Fixed Address is enabled
+ //
+ PeiLoadFixAddressHook (Private);
+
+ //
+ // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
+ //
+ LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
+ }
+
+ //
+ // Reserve the size of new stack at bottom of physical memory
+ //
+ // The size of new stack in permanent memory must be the same size
+ // or larger than the size of old stack in temporary memory.
+ // But if new stack is smaller than the size of old stack, we also reserve
+ // the size of old stack at bottom of permanent memory.
+ //
+ NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
+ NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
+ NewStackSize = MIN (PcdGet32(PcdPeiCoreMaxPeiStackSize), NewStackSize);
+ DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
+ ASSERT (NewStackSize >= SecCoreData->StackSize);
+
+ //
+ // Calculate stack offset and heap offset between temporary memory and new permanent
+ // memory separately.
+ //
+ TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
+ TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
+ if (TopOfNewStack >= TopOfOldStack) {
+ StackOffsetPositive = TRUE;
+ StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
+ } else {
+ StackOffsetPositive = FALSE;
+ StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
+ }
+ Private->StackOffsetPositive = StackOffsetPositive;
+ Private->StackOffset = StackOffset;
+
+ //
+ // Build Stack HOB that describes the permanent memory stack
+ //
+ DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
+ BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
+
+ //
+ // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
+ //
+ TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
+ TemporaryRamSize = SecCoreData->TemporaryRamSize;
+ TemporaryStackSize = SecCoreData->StackSize;
+ TemporaryStackBase = SecCoreData->StackBase;
+ PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
+ PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
+
+ //
+ // TemporaryRamSupportPpi is produced by platform's SEC
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiTemporaryRamSupportPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&TemporaryRamSupportPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Heap Offset
+ //
+ BaseOfNewHeap = TopOfNewStack;
+ if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
+ Private->HeapOffsetPositive = TRUE;
+ Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
+ } else {
+ Private->HeapOffsetPositive = FALSE;
+ Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
+ }
+
+ DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
+
+ //
+ // Calculate new HandOffTable and PrivateData address in permanent memory's stack
+ //
+ if (StackOffsetPositive) {
+ SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
+ Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
+ } else {
+ SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
+ Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
+ }
+
+ //
+ // Temporary Ram Support PPI is provided by platform, it will copy
+ // temporary memory to permanent memory and do stack switching.
+ // After invoking Temporary Ram Support PPI, the following code's
+ // stack is in permanent memory.
+ //
+ TemporaryRamSupportPpi->TemporaryRamMigration (
+ PeiServices,
+ TemporaryRamBase,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
+ TemporaryRamSize
+ );
+
+ //
+ // Migrate memory pages allocated in pre-memory phase.
+ // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
+ // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
+ //
+ MigrateMemoryPages (Private, TRUE);
+
+ //
+ // Entry PEI Phase 2
+ //
+ PeiCore (SecCoreData, NULL, Private);
+ } else {
+ //
+ // Migrate memory pages allocated in pre-memory phase.
+ //
+ MigrateMemoryPages (Private, FALSE);
+
+ //
+ // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
+ //
+ MigratePeiServicesTablePointer ();
+
+ //
+ // Heap Offset
+ //
+ BaseOfNewHeap = TopOfNewStack;
+ HoleMemBase = TopOfNewStack;
+ HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
+ if (HoleMemSize != 0) {
+ //
+ // Make sure HOB List start address is 8 byte alignment.
+ //
+ BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
+ }
+ if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
+ Private->HeapOffsetPositive = TRUE;
+ Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
+ } else {
+ Private->HeapOffsetPositive = FALSE;
+ Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
+ }
+
+ DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
+
+ //
+ // Migrate Heap
+ //
+ HeapTemporaryRamSize = (UINTN) (Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
+ ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
+ CopyMem ((UINT8 *) (UINTN) BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
+
+ //
+ // Migrate Stack
+ //
+ CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
+
+ //
+ // Copy Hole Range Data
+ //
+ if (HoleMemSize != 0) {
+ //
+ // Prepare Hole
+ //
+ if (PeiTemporaryRamBase < TemporaryStackBase) {
+ TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
+ TempSize1 = PeiTemporaryRamSize;
+ TempBase2 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
+ TempSize2 = TemporaryStackSize;
+ } else {
+ TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
+ TempSize1 = TemporaryStackSize;
+ TempBase2 =(EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
+ TempSize2 = PeiTemporaryRamSize;
+ }
+ if (TemporaryRamBase < TempBase1) {
+ Private->HoleData[0].Base = TemporaryRamBase;
+ Private->HoleData[0].Size = (UINTN) (TempBase1 - TemporaryRamBase);
+ }
+ if (TempBase1 + TempSize1 < TempBase2) {
+ Private->HoleData[1].Base = TempBase1 + TempSize1;
+ Private->HoleData[1].Size = (UINTN) (TempBase2 - TempBase1 - TempSize1);
+ }
+ if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
+ Private->HoleData[2].Base = TempBase2 + TempSize2;
+ Private->HoleData[2].Size = (UINTN) (TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
+ }
+
+ //
+ // Copy Hole Range data.
+ //
+ for (Index = 0; Index < HOLE_MAX_NUMBER; Index ++) {
+ if (Private->HoleData[Index].Size > 0) {
+ if (HoleMemBase > Private->HoleData[Index].Base) {
+ Private->HoleData[Index].OffsetPositive = TRUE;
+ Private->HoleData[Index].Offset = (UINTN) (HoleMemBase - Private->HoleData[Index].Base);
+ } else {
+ Private->HoleData[Index].OffsetPositive = FALSE;
+ Private->HoleData[Index].Offset = (UINTN) (Private->HoleData[Index].Base - HoleMemBase);
+ }
+ CopyMem ((VOID *) (UINTN) HoleMemBase, (VOID *) (UINTN) Private->HoleData[Index].Base, Private->HoleData[Index].Size);
+ HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
+ }
+ }
+ }
+
+ //
+ // Switch new stack
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
+ (VOID *) SecCoreData,
+ (VOID *) Private,
+ (VOID *) (UINTN) TopOfNewStack
+ );
+ }
+
+ //
+ // Code should not come here
+ //
+ ASSERT (FALSE);
+ }
+}
+
+/**
+ Migrate a PEIM from temporary RAM to permanent memory.
+
+ @param PeimFileHandle Pointer to the FFS file header of the image.
+ @param MigratedFileHandle Pointer to the FFS file header of the migrated image.
+
+ @retval EFI_SUCCESS Sucessfully migrated the PEIM to permanent memory.
+
+**/
+EFI_STATUS
+EFIAPI
+MigratePeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN EFI_PEI_FILE_HANDLE MigratedFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ VOID *Pe32Data;
+ VOID *ImageAddress;
+ CHAR8 *AsciiString;
+ UINTN Index;
+
+ Status = EFI_SUCCESS;
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileHandle;
+ ASSERT (!IS_FFS_FILE2 (FileHeader));
+
+ ImageAddress = NULL;
+ PeiGetPe32Data (MigratedFileHandle, &ImageAddress);
+ if (ImageAddress != NULL) {
+ DEBUG_CODE_BEGIN ();
+ AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
+ AsciiString = AsciiString + Index + 1;
+ Index = 0;
+ } else if (AsciiString[Index] == '.') {
+ AsciiString[Index] = 0;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "%a", AsciiString));
+ DEBUG_CODE_END ();
+
+ Pe32Data = (VOID *) ((UINTN) ImageAddress - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
+ Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+/**
+ Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.
+
+ @param OrgFvHandle Address of FV handle in temporary memory.
+ @param FvHandle Address of FV handle in permanent memory.
+ @param FvSize Size of the FV.
+
+**/
+VOID
+ConvertStatusCodeCallbacks (
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle,
+ IN UINTN FvSize
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN *NumberOfEntries;
+ UINTN *CallbackEntry;
+ UINTN Index;
+
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
+ while (Hob.Raw != NULL) {
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);
+ CallbackEntry = NumberOfEntries + 1;
+ for (Index = 0; Index < *NumberOfEntries; Index++) {
+ if (((VOID *) CallbackEntry[Index]) != NULL) {
+ if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {
+ DEBUG ((
+ DEBUG_INFO,
+ "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",
+ (UINT64)Index,
+ (sizeof CallbackEntry[Index]) * 2,
+ (UINT64)CallbackEntry[Index]
+ ));
+ if (OrgFvHandle > FvHandle) {
+ CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);
+ } else {
+ CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "0x%0*Lx\n",
+ (sizeof CallbackEntry[Index]) * 2,
+ (UINT64)CallbackEntry[Index]
+ ));
+ }
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
+ }
+}
+
+/**
+ Migrates SEC modules in the given firmware volume.
+
+ Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch.
+
+ This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has
+ been updated.
+
+ @param Private Pointer to the PeiCore's private data structure.
+ @param FvIndex The firmware volume index to migrate.
+ @param OrgFvHandle The handle to the firmware volume in temporary memory.
+
+ @retval EFI_SUCCESS SEC modules were migrated successfully
+ @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
+ @retval EFI_NOT_FOUND Can't find valid FFS header.
+
+**/
+EFI_STATUS
+EFIAPI
+MigrateSecModulesInFv (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN FvIndex,
+ IN UINTN OrgFvHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS FindFileStatus;
+ EFI_PEI_FILE_HANDLE MigratedFileHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ UINT32 SectionAuthenticationStatus;
+ UINT32 FileSize;
+ VOID *OrgPe32SectionData;
+ VOID *Pe32SectionData;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ EFI_COMMON_SECTION_HEADER *Section;
+ BOOLEAN IsFfs3Fv;
+ UINTN SectionInstance;
+
+ if (Private == NULL || FvIndex >= Private->FvCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ do {
+ FindFileStatus = PeiFfsFindNextFile (
+ GetPeiServicesTablePointer (),
+ EFI_FV_FILETYPE_SECURITY_CORE,
+ Private->Fv[FvIndex].FvHandle,
+ &MigratedFileHandle
+ );
+ if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) {
+ FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle;
+
+ DEBUG ((DEBUG_VERBOSE, " Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle));
+ DEBUG ((DEBUG_VERBOSE, " FileHandle at 0x%x.\n", (UINTN) FileHandle));
+
+ IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ return EFI_NOT_FOUND;
+ }
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ SectionInstance = 1;
+ SectionAuthenticationStatus = 0;
+ Status = ProcessSection (
+ GetPeiServicesTablePointer (),
+ EFI_SECTION_PE32,
+ &SectionInstance,
+ Section,
+ FileSize,
+ &Pe32SectionData,
+ &SectionAuthenticationStatus,
+ IsFfs3Fv
+ );
+
+ if (!EFI_ERROR (Status)) {
+ OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
+ DEBUG ((DEBUG_VERBOSE, " PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData));
+ DEBUG ((DEBUG_VERBOSE, " PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData));
+ Status = LoadAndRelocatePeCoffImageInPlace (OrgPe32SectionData, Pe32SectionData);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ } while (!EFI_ERROR (FindFileStatus));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Migrates PEIMs in the given firmware volume.
+
+ @param Private Pointer to the PeiCore's private data structure.
+ @param FvIndex The firmware volume index to migrate.
+ @param OrgFvHandle The handle to the firmware volume in temporary memory.
+ @param FvHandle The handle to the firmware volume in permanent memory.
+
+ @retval EFI_SUCCESS The PEIMs in the FV were migrated successfully
+ @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+MigratePeimsInFv (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN FvIndex,
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle
+ )
+{
+ EFI_STATUS Status;
+ volatile UINTN FileIndex;
+ EFI_PEI_FILE_HANDLE MigratedFileHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+
+ if (Private == NULL || FvIndex >= Private->FvCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->Fv[FvIndex].ScanFv) {
+ for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {
+ if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {
+ FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];
+
+ MigratedFileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) FileHandle - OrgFvHandle + FvHandle);
+
+ DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex));
+ Status = MigratePeim (FileHandle, MigratedFileHandle);
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;
+ if (FvIndex == Private->CurrentPeimFvCount) {
+ Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Migrate FVs out of temporary RAM before the cache is flushed.
+
+ @param Private PeiCore's private data structure
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+
+ @retval EFI_SUCCESS Succesfully migrated installed FVs from temporary RAM to permanent memory.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.
+
+**/
+EFI_STATUS
+EFIAPI
+EvacuateTempRam (
+ IN PEI_CORE_INSTANCE *Private,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ EFI_STATUS Status;
+ volatile UINTN FvIndex;
+ volatile UINTN FvChildIndex;
+ UINTN ChildFvOffset;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *RawDataFvHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader;
+
+ PEI_CORE_FV_HANDLE PeiCoreFvHandle;
+ EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;
+ EDKII_MIGRATED_FV_INFO MigratedFvInfo;
+
+ ASSERT (Private->PeiMemoryInstalled);
+
+ DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));
+
+ //
+ // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.
+ //
+ Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **) &Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **) &PeiCoreFvLocationPpi);
+ if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) PeiCoreFvLocationPpi->PeiCoreFvLocation;
+ } else {
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) SecCoreData->BootFirmwareVolumeBase;
+ }
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
+ if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
+ PeiCoreFvHandle = Private->Fv[FvIndex];
+ break;
+ }
+ }
+ Status = EFI_SUCCESS;
+
+ ConvertPeiCorePpiPointers (Private, PeiCoreFvHandle);
+
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
+ FvHeader = Private->Fv[FvIndex].FvHeader;
+ ASSERT (FvHeader != NULL);
+ ASSERT (FvIndex < Private->FvCount);
+
+ DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN) FvHeader));
+ if (
+ !(
+ ((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader >= Private->PhysicalMemoryBegin) &&
+ (((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)
+ )
+ ) {
+ //
+ // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.
+ //
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),
+ (EFI_PHYSICAL_ADDRESS *) &MigratedFvHeader
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate pool to save the raw PEIMs, which is used to keep consistent context across
+ // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.
+ //
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),
+ (EFI_PHYSICAL_ADDRESS *) &RawDataFvHeader
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Migrating FV[%d] from 0x%08X to 0x%08X\n",
+ FvIndex,
+ (UINTN) FvHeader,
+ (UINTN) MigratedFvHeader
+ ));
+
+ //
+ // Copy the context to the rebased pages and raw pages, and create hob to save the
+ // information. The MigratedFvInfo HOB will never be produced when
+ // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the
+ // feature.
+ //
+ CopyMem (MigratedFvHeader, FvHeader, (UINTN) FvHeader->FvLength);
+ CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN) FvHeader->FvLength);
+ MigratedFvInfo.FvOrgBase = (UINT32) (UINTN) FvHeader;
+ MigratedFvInfo.FvNewBase = (UINT32) (UINTN) MigratedFvHeader;
+ MigratedFvInfo.FvDataBase = (UINT32) (UINTN) RawDataFvHeader;
+ MigratedFvInfo.FvLength = (UINT32) (UINTN) FvHeader->FvLength;
+ BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));
+
+ //
+ // Migrate any children for this FV now
+ //
+ for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {
+ ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;
+ if (
+ ((UINTN) ChildFvHeader > (UINTN) FvHeader) &&
+ (((UINTN) ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN) FvHeader) + FvHeader->FvLength)
+ ) {
+ DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex));
+ ChildFvOffset = (UINTN) ChildFvHeader - (UINTN) FvHeader;
+ DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset));
+ MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) MigratedFvHeader + ChildFvOffset);
+ Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;
+ Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedChildFvHeader;
+ DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN) MigratedChildFvHeader));
+
+ Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
+ ASSERT_EFI_ERROR (Status);
+
+ ConvertPpiPointersFv (
+ Private,
+ (UINTN) ChildFvHeader,
+ (UINTN) MigratedChildFvHeader,
+ (UINTN) ChildFvHeader->FvLength - 1
+ );
+
+ ConvertStatusCodeCallbacks (
+ (UINTN) ChildFvHeader,
+ (UINTN) MigratedChildFvHeader,
+ (UINTN) ChildFvHeader->FvLength - 1
+ );
+
+ ConvertFvHob (Private, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
+ }
+ }
+ Private->Fv[FvIndex].FvHeader = MigratedFvHeader;
+ Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedFvHeader;
+
+ Status = MigratePeimsInFv (Private, FvIndex, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
+ ASSERT_EFI_ERROR (Status);
+
+ ConvertPpiPointersFv (
+ Private,
+ (UINTN) FvHeader,
+ (UINTN) MigratedFvHeader,
+ (UINTN) FvHeader->FvLength - 1
+ );
+
+ ConvertStatusCodeCallbacks (
+ (UINTN) FvHeader,
+ (UINTN) MigratedFvHeader,
+ (UINTN) FvHeader->FvLength - 1
+ );
+
+ ConvertFvHob (Private, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
+ }
+ }
+
+ RemoveFvHobsInTemporaryMemory (Private);
+
+ return Status;
+}
+
+/**
+ Conduct PEIM dispatch.
+
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+ @param Private Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiDispatcher (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index1;
+ UINT32 Index2;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_PEI_FILE_HANDLE PeimFileHandle;
+ UINTN FvCount;
+ UINTN PeimCount;
+ UINT32 AuthenticationState;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
+ UINTN SaveCurrentPeimCount;
+ UINTN SaveCurrentFvCount;
+ EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
+ EFI_FV_FILE_INFO FvFileInfo;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
+ PeimEntryPoint = NULL;
+ PeimFileHandle = NULL;
+ EntryPoint = 0;
+
+ if ((Private->PeiMemoryInstalled) &&
+ (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
+ PcdGetBool (PcdShadowPeimOnS3Boot))
+ ) {
+ //
+ // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
+ // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.
+ //
+ SaveCurrentPeimCount = Private->CurrentPeimCount;
+ SaveCurrentFvCount = Private->CurrentPeimFvCount;
+ SaveCurrentFileHandle = Private->CurrentFileHandle;
+
+ for (Index1 = 0; Index1 < Private->FvCount; Index1++) {
+ for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {
+ if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {
+ PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
+ Private->CurrentFileHandle = PeimFileHandle;
+ Private->CurrentPeimFvCount = Index1;
+ Private->CurrentPeimCount = Index2;
+ Status = PeiLoadImage (
+ (CONST EFI_PEI_SERVICES **) &Private->Ps,
+ PeimFileHandle,
+ PEIM_STATE_REGISTER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
+ //
+ Private->Fv[Index1].PeimState[Index2]++;
+ //
+ // Call the PEIM entry point
+ //
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+
+ PERF_START_IMAGE_BEGIN (PeimFileHandle);
+ PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
+ PERF_START_IMAGE_END (PeimFileHandle);
+ }
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessDispatchNotifyList (Private);
+ }
+ }
+ }
+ Private->CurrentFileHandle = SaveCurrentFileHandle;
+ Private->CurrentPeimFvCount = SaveCurrentFvCount;
+ Private->CurrentPeimCount = SaveCurrentPeimCount;
+ }
+
+ //
+ // This is the main dispatch loop. It will search known FVs for PEIMs and
+ // attempt to dispatch them. If any PEIM gets dispatched through a single
+ // pass of the dispatcher, it will start over from the BFV again to see
+ // if any new PEIMs dependencies got satisfied. With a well ordered
+ // FV where PEIMs are found in the order their dependencies are also
+ // satisfied, this dispatcher should run only once.
+ //
+ do {
+ //
+ // In case that reenter PeiCore happens, the last pass record is still available.
+ //
+ if (!Private->PeimDispatcherReenter) {
+ Private->PeimNeedingDispatch = FALSE;
+ Private->PeimDispatchOnThisPass = FALSE;
+ } else {
+ Private->PeimDispatcherReenter = FALSE;
+ }
+
+ for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
+ CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
+ ASSERT (CoreFvHandle != NULL);
+
+ //
+ // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
+ //
+ if (CoreFvHandle->FvPpi == NULL) {
+ continue;
+ }
+
+ Private->CurrentPeimFvCount = FvCount;
+
+ if (Private->CurrentPeimCount == 0) {
+ //
+ // When going through each FV, at first, search Apriori file to
+ // reorder all PEIMs to ensure the PEIMs in Apriori file to get
+ // dispatch at first.
+ //
+ DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
+ }
+
+ //
+ // Start to dispatch all modules within the current FV.
+ //
+ for (PeimCount = Private->CurrentPeimCount;
+ PeimCount < Private->Fv[FvCount].PeimCount;
+ PeimCount++) {
+ Private->CurrentPeimCount = PeimCount;
+ PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
+
+ if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
+ if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
+ Private->PeimNeedingDispatch = TRUE;
+ } else {
+ Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
+ ASSERT_EFI_ERROR (Status);
+ if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // For FV type file, Produce new FvInfo PPI and FV HOB
+ //
+ Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
+ if (Status == EFI_SUCCESS) {
+ //
+ // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+ Private->PeimDispatchOnThisPass = TRUE;
+ } else {
+ //
+ // The related GuidedSectionExtraction/Decompress PPI for the
+ // encapsulated FV image section may be installed in the rest
+ // of this do-while loop, so need to make another pass.
+ //
+ Private->PeimNeedingDispatch = TRUE;
+ }
+ } else {
+ //
+ // For PEIM driver, Load its entry point
+ //
+ Status = PeiLoadImage (
+ PeiServices,
+ PeimFileHandle,
+ PEIM_STATE_NOT_DISPATCHED,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // The PEIM has its dependencies satisfied, and its entry point
+ // has been found, so invoke it.
+ //
+ PERF_START_IMAGE_BEGIN (PeimFileHandle);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
+ (VOID *)(&PeimFileHandle),
+ sizeof (PeimFileHandle)
+ );
+
+ Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
+ if (Status != EFI_SECURITY_VIOLATION) {
+ //
+ // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+ //
+ // Call the PEIM entry point for PEIM driver
+ //
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+ PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
+ Private->PeimDispatchOnThisPass = TRUE;
+ } else {
+ //
+ // The related GuidedSectionExtraction PPI for the
+ // signed PEIM image section may be installed in the rest
+ // of this do-while loop, so need to make another pass.
+ //
+ Private->PeimNeedingDispatch = TRUE;
+ }
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
+ (VOID *)(&PeimFileHandle),
+ sizeof (PeimFileHandle)
+ );
+ PERF_START_IMAGE_END (PeimFileHandle);
+
+ }
+ }
+
+ PeiCheckAndSwitchStack (SecCoreData, Private);
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessDispatchNotifyList (Private);
+
+ //
+ // Recheck SwitchStackSignal after ProcessDispatchNotifyList()
+ // in case PeiInstallPeiMemory() is done in a callback with
+ // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
+ //
+ PeiCheckAndSwitchStack (SecCoreData, Private);
+
+ if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
+ (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
+ PcdGetBool (PcdShadowPeimOnS3Boot))
+ ) {
+ //
+ // If memory is available we shadow images by default for performance reasons.
+ // We call the entry point a 2nd time so the module knows it's shadowed.
+ //
+ //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
+ if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
+ !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
+ //
+ // Load PEIM into Memory for Register for shadow PEIM.
+ //
+ Status = PeiLoadImage (
+ PeiServices,
+ PeimFileHandle,
+ PEIM_STATE_REGISTER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ if (Status == EFI_SUCCESS) {
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
+ }
+ }
+ ASSERT (PeimEntryPoint != NULL);
+ PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
+ //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
+
+ //
+ // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
+ //
+ Private->Fv[FvCount].PeimState[PeimCount]++;
+
+ //
+ // Process the Notify list and dispatch any notifies for
+ // newly installed PPIs.
+ //
+ ProcessDispatchNotifyList (Private);
+ }
+ }
+ }
+ }
+
+ //
+ // Before walking through the next FV, we should set them to NULL/0 to
+ // start at the beginning of the next FV.
+ //
+ Private->CurrentFileHandle = NULL;
+ Private->CurrentPeimCount = 0;
+ Private->CurrentFvFileHandles = NULL;
+ }
+
+ //
+ // Before making another pass, we should set it to 0 to
+ // go through all the FVs.
+ //
+ Private->CurrentPeimFvCount = 0;
+
+ //
+ // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
+ // dispatched. So we need to make another pass
+ //
+ // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
+ // pass. If we did not dispatch a PEIM/FV there is no point in trying again
+ // as it will fail the next time too (nothing has changed).
+ //
+ } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
+
+}
+
+/**
+ Initialize the Dispatcher's data members
+
+ @param PrivateData PeiCore's private data structure
+ @param OldCoreData Old data from SecCore
+ NULL if being run in non-permanent memory mode.
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+
+ @return None.
+
+**/
+VOID
+InitializeDispatcherData (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ PrivateData->PeimDispatcherReenter = FALSE;
+ PeiInitializeFv (PrivateData, SecCoreData);
+ } else {
+ PeiReinitializeFv (PrivateData);
+ }
+
+ return;
+}
+
+/**
+ This routine parses the Dependency Expression, if available, and
+ decides if the module can be executed.
+
+
+ @param Private PeiCore's private data structure
+ @param FileHandle PEIM's file handle
+ @param PeimCount Peim count in all dispatched PEIMs.
+
+ @retval TRUE Can be dispatched
+ @retval FALSE Cannot be dispatched
+
+**/
+BOOLEAN
+DepexSatisfied (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN PeimCount
+ )
+{
+ EFI_STATUS Status;
+ VOID *DepexData;
+ EFI_FV_FILE_INFO FileInfo;
+
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
+ }
+
+ if (PeimCount < Private->AprioriCount) {
+ //
+ // If it's in the Apriori file then we set DEPEX to TRUE
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ return TRUE;
+ }
+
+ //
+ // Depex section not in the encapsulated section.
+ //
+ Status = PeiServicesFfsFindSectionData (
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID **)&DepexData
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If there is no DEPEX, assume the module can be executed
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n"));
+ return TRUE;
+ }
+
+ //
+ // Evaluate a given DEPEX
+ //
+ return PeimDispatchReadiness (&Private->Ps, DepexData);
+}
+
+/**
+ This routine enables a PEIM to register itself for shadow when the PEI Foundation
+ discovers permanent memory.
+
+ @param FileHandle File handle of a PEIM.
+
+ @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
+ @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
+ @retval EFI_SUCCESS Successfully to register itself.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterForShadow (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ PEI_CORE_INSTANCE *Private;
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ if (Private->CurrentFileHandle != FileHandle) {
+ //
+ // The FileHandle must be for the current PEIM
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) {
+ //
+ // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW;
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.c b/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.c
new file mode 100644
index 000000000..fa1a3d3ac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.c
@@ -0,0 +1,2434 @@
+/** @file
+ Pei Core Firmware File System service routines.
+
+Copyright (c) 2015 HP Development Company, L.P.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FwVol.h"
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolumeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolumeInfoPpiNotifyCallback
+ }
+};
+
+PEI_FW_VOL_INSTANCE mPeiFfs2FwVol = {
+ PEI_FW_VOL_SIGNATURE,
+ FALSE,
+ {
+ PeiFfsFvPpiProcessVolume,
+ PeiFfsFvPpiFindFileByType,
+ PeiFfsFvPpiFindFileByName,
+ PeiFfsFvPpiGetFileInfo,
+ PeiFfsFvPpiGetVolumeInfo,
+ PeiFfsFvPpiFindSectionByType,
+ PeiFfsFvPpiGetFileInfo2,
+ PeiFfsFvPpiFindSectionByType2,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
+ }
+};
+
+PEI_FW_VOL_INSTANCE mPeiFfs3FwVol = {
+ PEI_FW_VOL_SIGNATURE,
+ TRUE,
+ {
+ PeiFfsFvPpiProcessVolume,
+ PeiFfsFvPpiFindFileByType,
+ PeiFfsFvPpiFindFileByName,
+ PeiFfsFvPpiGetFileInfo,
+ PeiFfsFvPpiGetVolumeInfo,
+ PeiFfsFvPpiFindSectionByType,
+ PeiFfsFvPpiGetFileInfo2,
+ PeiFfsFvPpiFindSectionByType2,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
+ EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
+ }
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiFfs2FvPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiFirmwareFileSystem2Guid,
+ &mPeiFfs2FwVol.Fv
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiFfs3FvPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiFirmwareFileSystem3Guid,
+ &mPeiFfs3FwVol.Fv
+};
+
+/**
+Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
+(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
+1 0 0 0
+16 1 0 4
+128 2 0 7
+512 3 0 9
+1 KB 4 0 10
+4 KB 5 0 12
+32 KB 6 0 15
+64 KB 7 0 16
+128 KB 0 1 17
+256 KB 1 1 18
+512 KB 2 1 19
+1 MB 3 1 20
+2 MB 4 1 21
+4 MB 5 1 22
+8 MB 6 1 23
+16 MB 7 1 24
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};
+
+/**
+ 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);
+
+ if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];
+ } else {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
+ }
+
+ if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
+ FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
+ }
+
+ return FileAttribute;
+}
+
+/**
+ Returns the file state set by the highest zero bit in the State field
+
+ @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
+ in the Attributes field.
+ @param FfsHeader Pointer to FFS File Header.
+
+ @retval EFI_FFS_FILE_STATE File state is set by the highest none zero bit
+ in the header State field.
+**/
+EFI_FFS_FILE_STATE
+GetFileState(
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_STATE HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ //
+ // Get file state set by its highest none zero bit.
+ //
+ HighestBit = 0x80;
+ while (HighestBit != 0 && (HighestBit & FileState) == 0) {
+ HighestBit >>= 1;
+ }
+
+ return HighestBit;
+}
+
+/**
+ Calculates the checksum of the header of a file.
+
+ @param FileHeader Pointer to FFS File Header.
+
+ @return Checksum of the header.
+ Zero means the header is good.
+ Non-zero means the header is bad.
+**/
+UINT8
+CalculateHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FileHeader
+ )
+{
+ EFI_FFS_FILE_HEADER2 TestFileHeader;
+
+ if (IS_FFS_FILE2 (FileHeader)) {
+ CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ //
+ // Ignore State and File field in FFS header.
+ //
+ TestFileHeader.State = 0;
+ TestFileHeader.IntegrityCheck.Checksum.File = 0;
+
+ return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER));
+ //
+ // Ignore State and File field in FFS header.
+ //
+ TestFileHeader.State = 0;
+ TestFileHeader.IntegrityCheck.Checksum.File = 0;
+
+ return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER));
+ }
+}
+
+/**
+ Find FV handler according to FileHandle in that FV.
+
+ @param FileHandle Handle of file image
+
+ @return Pointer to instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE*
+FileHandleToVolume (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ UINTN Index;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BestIndex;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+ BestIndex = PrivateData->FvCount;
+
+ //
+ // Find the best matched FV image that includes this FileHandle.
+ // FV may include the child FV, and they are in the same continuous space.
+ // If FileHandle is from the child FV, the updated logic can find its matched FV.
+ //
+ for (Index = 0; Index < PrivateData->FvCount; Index++) {
+ FwVolHeader = PrivateData->Fv[Index].FvHeader;
+ if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
+ ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
+ if (BestIndex == PrivateData->FvCount) {
+ BestIndex = Index;
+ } else {
+ if ((UINT64) (UINTN) PrivateData->Fv[BestIndex].FvHeader < (UINT64) (UINTN) FwVolHeader) {
+ BestIndex = Index;
+ }
+ }
+ }
+ }
+
+ if (BestIndex < PrivateData->FvCount) {
+ return &PrivateData->Fv[BestIndex];
+ }
+
+ return NULL;
+}
+
+/**
+ Given the input file pointer, search for the first matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+ If SearchType is EFI_FV_FILETYPE_ALL, the first FFS file will return without check its file type.
+ If SearchType is PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
+ the first PEIM, or COMBINED PEIM or FV file type FFS file will return.
+
+ @param FvHandle Pointer to the FV header of the volume to search
+ @param FileName File name
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FileHandle This parameter must point to a valid FFS volume.
+ @param AprioriFile Pointer to AprioriFile image in this FV if has
+
+ @return EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+FindFileEx (
+ IN CONST EFI_PEI_FV_HANDLE FvHandle,
+ IN CONST EFI_GUID *FileName, OPTIONAL
+ IN EFI_FV_FILETYPE SearchType,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *AprioriFile OPTIONAL
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FFS_FILE_HEADER **FileHeader;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+ UINT32 FileOffset;
+ UINT64 FvLength;
+ UINT8 ErasePolarity;
+ UINT8 FileState;
+ UINT8 DataCheckSum;
+ BOOLEAN IsFfs3Fv;
+
+ //
+ // Convert the handle of FV to FV header for memory-mapped firmware volume
+ //
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvHandle;
+ FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
+
+ IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+
+ FvLength = FwVolHeader->FvLength;
+ if ((FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // If FileHeader is not specified (NULL) or FileName is not NULL,
+ // start with the first file in the firmware volume. Otherwise,
+ // start from the FileHeader.
+ //
+ if ((*FileHeader == NULL) || (FileName != NULL)) {
+ if (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 *) ((UINT8 *) FwVolHeader + FwVolHeader->ExtHeaderOffset);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
+ } else {
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
+ }
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsFileHeader, 8);
+ } else {
+ if (IS_FFS_FILE2 (*FileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &(*FileHeader)->Name));
+ }
+ FileLength = FFS_FILE2_SIZE (*FileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ } else {
+ FileLength = FFS_FILE_SIZE (*FileHeader);
+ }
+ //
+ // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
+ }
+
+ FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
+ ASSERT (FileOffset <= 0xFFFFFFFF);
+
+ while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, FfsFileHeader);
+ switch (FileState) {
+
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ case EFI_FILE_HEADER_INVALID:
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ }
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER2);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+ break;
+
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
+ ASSERT (FALSE);
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ FileLength = FFS_FILE2_SIZE (FfsFileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ break;
+ }
+ } else {
+ FileLength = FFS_FILE_SIZE (FfsFileHeader);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ }
+
+ DataCheckSum = FFS_FIXED_CHECKSUM;
+ if ((FfsFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FileLength - sizeof(EFI_FFS_FILE_HEADER2));
+ } else {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER), FileLength - sizeof(EFI_FFS_FILE_HEADER));
+ }
+ }
+ if (FfsFileHeader->IntegrityCheck.Checksum.File != DataCheckSum) {
+ ASSERT (FALSE);
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (FileName != NULL) {
+ if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+ } else if (SearchType == PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE) {
+ if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) ||
+ (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) ||
+ (FfsFileHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {
+
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ } else if (AprioriFile != NULL) {
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FREEFORM) {
+ if (CompareGuid (&FfsFileHeader->Name, &gPeiAprioriFileNameGuid)) {
+ *AprioriFile = (EFI_PEI_FILE_HANDLE)FfsFileHeader;
+ }
+ }
+ }
+ } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
+ (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+ *FileHeader = FfsFileHeader;
+ return EFI_SUCCESS;
+ }
+
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ case EFI_FILE_DELETED:
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ }
+ FileLength = FFS_FILE2_SIZE (FfsFileHeader);
+ ASSERT (FileLength > 0x00FFFFFF);
+ } else {
+ FileLength = FFS_FILE_SIZE (FfsFileHeader);
+ }
+ FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
+ break;
+
+ default:
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ *FileHeader = NULL;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize PeiCore FV List.
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
+**/
+VOID
+PeiInitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_PEI_FV_HANDLE FvHandle;
+ EFI_FIRMWARE_VOLUME_HEADER *BfvHeader;
+
+ //
+ // Install FV_PPI for FFS2 file system.
+ //
+ PeiServicesInstallPpi (&mPeiFfs2FvPpiList);
+
+ //
+ // Install FV_PPI for FFS3 file system.
+ //
+ PeiServicesInstallPpi (&mPeiFfs3FvPpiList);
+
+ BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+
+ //
+ // The FV_PPI in BFV's format should be installed.
+ //
+ Status = PeiServicesLocatePpi (
+ &BfvHeader->FileSystemGuid,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get handle of BFV
+ //
+ Status = FvPpi->ProcessVolume (
+ FvPpi,
+ SecCoreData->BootFirmwareVolumeBase,
+ (UINTN)BfvHeader->FvLength,
+ &FvHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PrivateData->Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * FV_GROWTH_STEP);
+ ASSERT (PrivateData->Fv != NULL);
+ PrivateData->MaxFvCount = FV_GROWTH_STEP;
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) PrivateData->FvCount,
+ (VOID *) BfvHeader,
+ (UINT32) BfvHeader->FvLength,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
+ // additional FVs to PeiCore.
+ //
+ Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
+ ASSERT_EFI_ERROR (Status);
+
+}
+
+/**
+ Process Firmware Volume Information once FvInfoPPI or FvInfo2PPI install.
+ The FV Info will be registered into PeiCore private data structure.
+ And search the inside FV image, if found, the new FV INFO(2) PPI will be installed.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
+ @return if not EFI_SUCCESS, fail to verify FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolumeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI FvInfo2Ppi;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE FvHandle;
+ UINTN FvIndex;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *DepexData;
+ BOOLEAN IsFvInfo2;
+ UINTN CurFvCount;
+ VOID *TempPtr;
+
+ Status = EFI_SUCCESS;
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiFirmwareVolumeInfo2PpiGuid)) {
+ //
+ // It is FvInfo2PPI.
+ //
+ CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI));
+ IsFvInfo2 = TRUE;
+ } else {
+ //
+ // It is FvInfoPPI.
+ //
+ CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI));
+ FvInfo2Ppi.AuthenticationStatus = 0;
+ IsFvInfo2 = FALSE;
+ }
+
+ if (CompareGuid (&FvInfo2Ppi.FvFormat, &gEfiFirmwareFileSystem2Guid)) {
+ //
+ // gEfiFirmwareFileSystem2Guid is specified for FvFormat, then here to check the
+ // FileSystemGuid pointed by FvInfo against gEfiFirmwareFileSystem2Guid to make sure
+ // FvInfo has the firmware file system 2 format.
+ //
+ // If the ASSERT really appears, FvFormat needs to be specified correctly, for example,
+ // gEfiFirmwareFileSystem3Guid can be used for firmware file system 3 format, or
+ // ((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo)->FileSystemGuid can be just used for both
+ // firmware file system 2 and 3 format.
+ //
+ ASSERT (CompareGuid (&(((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo2Ppi.FvInfo)->FileSystemGuid), &gEfiFirmwareFileSystem2Guid));
+ }
+
+ //
+ // Locate the corresponding FV_PPI according to the format GUID of the FV found
+ //
+ Status = PeiServicesLocatePpi (
+ &FvInfo2Ppi.FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Process new found FV and get FV handle.
+ //
+ Status = FvPpi->ProcessVolume (FvPpi, FvInfo2Ppi.FvInfo, FvInfo2Ppi.FvInfoSize, &FvHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to process new found FV, FV may be corrupted!\n"));
+ return Status;
+ }
+
+ //
+ // Check whether the FV has already been processed.
+ //
+ for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
+ if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
+ if (IsFvInfo2 && (FvInfo2Ppi.AuthenticationStatus != PrivateData->Fv[FvIndex].AuthenticationStatus)) {
+ PrivateData->Fv[FvIndex].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
+ DEBUG ((EFI_D_INFO, "Update AuthenticationStatus of the %dth FV to 0x%x!\n", FvIndex, FvInfo2Ppi.AuthenticationStatus));
+ }
+ DEBUG ((DEBUG_INFO, "The FV %p has already been processed!\n", FvInfo2Ppi.FvInfo));
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (PrivateData->FvCount >= PrivateData->MaxFvCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_CORE_FV_HANDLE) * (PrivateData->MaxFvCount + FV_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ PrivateData->Fv,
+ sizeof (PEI_CORE_FV_HANDLE) * PrivateData->MaxFvCount
+ );
+ PrivateData->Fv = TempPtr;
+ PrivateData->MaxFvCount = PrivateData->MaxFvCount + FV_GROWTH_STEP;
+ }
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo2Ppi.FvInfo;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
+ CurFvCount = PrivateData->FvCount;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) CurFvCount,
+ (VOID *) FvInfo2Ppi.FvInfo,
+ FvInfo2Ppi.FvInfoSize,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Scan and process the new discovered FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+ FileHandle = NULL;
+ do {
+ Status = FvPpi->FindFileByType (
+ FvPpi,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+ FvHandle,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FvPpi->FindSectionByType (
+ FvPpi,
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID**)&DepexData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!PeimDispatchReadiness (PeiServices, DepexData)) {
+ //
+ // Dependency is not satisfied.
+ //
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
+ }
+ } while (FileHandle != NULL);
+ } else {
+ DEBUG ((EFI_D_ERROR, "Fail to process FV %p because no corresponding EFI_FIRMWARE_VOLUME_PPI is found!\n", FvInfo2Ppi.FvInfo));
+
+ AddUnknownFormatFvInfo (PrivateData, &FvInfo2Ppi);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verify the Guided Section GUID by checking if there is the Guided Section GUID HOB recorded the GUID itself.
+
+ @param GuidedSectionGuid The Guided Section GUID.
+ @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Ppi
+ for the Guided Section.
+
+ @return TRUE The GuidedSectionGuid could be identified, and the pointer to
+ the Guided Section Extraction Ppi will be returned to *GuidedSectionExtraction.
+ @return FALSE The GuidedSectionGuid could not be identified, or
+ the Guided Section Extraction Ppi has not been installed yet.
+
+**/
+BOOLEAN
+VerifyGuidedSectionGuid (
+ IN EFI_GUID *GuidedSectionGuid,
+ OUT EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI **GuidedSectionExtraction
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_GUID *GuidRecorded;
+ VOID *Interface;
+ EFI_STATUS Status;
+
+ //
+ // Check if there is the Guided Section GUID HOB recorded the GUID itself.
+ //
+ Hob.Raw = GetFirstGuidHob (GuidedSectionGuid);
+ if (Hob.Raw != NULL) {
+ GuidRecorded = (EFI_GUID *) GET_GUID_HOB_DATA (Hob);
+ if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
+ //
+ // Found the recorded GuidedSectionGuid.
+ //
+ Status = PeiServicesLocatePpi (GuidedSectionGuid, 0, NULL, (VOID **) &Interface);
+ if (!EFI_ERROR (Status) && Interface != NULL) {
+ //
+ // Found the supported Guided Section Extraction Ppi for the Guided Section.
+ //
+ *GuidedSectionExtraction = (EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *) Interface;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Go through the file to search SectionType section.
+ Search within encapsulation sections (compression and GUIDed) recursively,
+ until the match section is found.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType Filter to find only section of this type.
+ @param SectionInstance Pointer to the filter to find the specific instance of section.
+ @param Section From where to search.
+ @param SectionSize The file size to search.
+ @param OutputBuffer A pointer to the discovered section, if successful.
+ NULL if section not found
+ @param AuthenticationStatus Updated upon return to point to the authentication status for this section.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @return EFI_NOT_FOUND The match section is not found.
+ @return EFI_SUCCESS The match section is found.
+
+**/
+EFI_STATUS
+ProcessSection (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_COMMON_SECTION_HEADER *Section,
+ IN UINTN SectionSize,
+ OUT VOID **OutputBuffer,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
+ EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
+ VOID *PpiOutput;
+ UINTN PpiOutputSize;
+ UINTN Index;
+ UINT32 Authentication;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_GUID *SectionDefinitionGuid;
+ BOOLEAN SectionCached;
+ VOID *TempOutputBuffer;
+ UINT32 TempAuthenticationStatus;
+ UINT16 GuidedSectionAttributes;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ *OutputBuffer = NULL;
+ ParsedLength = 0;
+ Index = 0;
+ Status = EFI_NOT_FOUND;
+ PpiOutput = NULL;
+ PpiOutputSize = 0;
+ while (ParsedLength < SectionSize) {
+
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
+ SectionLength = SECTION2_SIZE (Section);
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
+ continue;
+ }
+ }
+
+ if (Section->Type == SectionType) {
+ //
+ // The type matches, so check the instance count to see if it's the one we want.
+ //
+ (*SectionInstance)--;
+ if (*SectionInstance == 0) {
+ //
+ // Got it!
+ //
+ if (IS_SECTION2 (Section)) {
+ *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
+ } else {
+ *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (IS_SECTION2 (Section)) {
+ SectionLength = SECTION2_SIZE (Section);
+ } else {
+ SectionLength = SECTION_SIZE (Section);
+ }
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
+ continue;
+ }
+ } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
+ //
+ // Check the encapsulated section is extracted into the cache data.
+ //
+ SectionCached = FALSE;
+ for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
+ if (Section == PrivateData->CacheSection.Section[Index]) {
+ SectionCached = TRUE;
+ PpiOutput = PrivateData->CacheSection.SectionData[Index];
+ PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
+ Authentication = PrivateData->CacheSection.AuthenticationStatus[Index];
+ //
+ // Search section directly from the cache data.
+ //
+ TempAuthenticationStatus = 0;
+ Status = ProcessSection (
+ PeiServices,
+ SectionType,
+ SectionInstance,
+ PpiOutput,
+ PpiOutputSize,
+ &TempOutputBuffer,
+ &TempAuthenticationStatus,
+ IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ *OutputBuffer = TempOutputBuffer;
+ *AuthenticationStatus = TempAuthenticationStatus | Authentication;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // If SectionCached is TRUE, the section data has been cached and scanned.
+ //
+ if (!SectionCached) {
+ Status = EFI_NOT_FOUND;
+ Authentication = 0;
+ if (Section->Type == EFI_SECTION_GUID_DEFINED) {
+ if (IS_SECTION2 (Section)) {
+ SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)Section)->Attributes;
+ } else {
+ SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION *)Section)->Attributes;
+ }
+ if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
+ Status = GuidSectionPpi->ExtractSection (
+ GuidSectionPpi,
+ Section,
+ &PpiOutput,
+ &PpiOutputSize,
+ &Authentication
+ );
+ } else if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ //
+ // Figure out the proper authentication status for GUIDED section without processing required
+ //
+ Status = EFI_SUCCESS;
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ Authentication |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
+ }
+ if (IS_SECTION2 (Section)) {
+ PpiOutputSize = SECTION2_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
+ PpiOutput = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
+ } else {
+ PpiOutputSize = SECTION_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
+ PpiOutput = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
+ }
+ }
+ } else if (Section->Type == EFI_SECTION_COMPRESSION) {
+ Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
+ if (!EFI_ERROR (Status)) {
+ Status = DecompressPpi->Decompress (
+ DecompressPpi,
+ (CONST EFI_COMPRESSION_SECTION*) Section,
+ &PpiOutput,
+ &PpiOutputSize
+ );
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if ((Authentication & EFI_AUTH_STATUS_NOT_TESTED) == 0) {
+ //
+ // Update cache section data.
+ //
+ if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
+ PrivateData->CacheSection.AllSectionCount ++;
+ }
+ PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
+ PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
+ PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
+ PrivateData->CacheSection.AuthenticationStatus [PrivateData->CacheSection.SectionIndex] = Authentication;
+ PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
+ }
+
+ TempAuthenticationStatus = 0;
+ Status = ProcessSection (
+ PeiServices,
+ SectionType,
+ SectionInstance,
+ PpiOutput,
+ PpiOutputSize,
+ &TempOutputBuffer,
+ &TempAuthenticationStatus,
+ IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ *OutputBuffer = TempOutputBuffer;
+ *AuthenticationStatus = TempAuthenticationStatus | Authentication;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (IS_SECTION2 (Section)) {
+ SectionLength = SECTION2_SIZE (Section);
+ } else {
+ SectionLength = SECTION_SIZE (Section);
+ }
+ //
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+ ASSERT (SectionLength != 0);
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param SectionType Filter to find only sections of this type.
+ @param FileHandle Pointer to the current file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ NULL if section not found
+
+ @retval EFI_NOT_FOUND The section was not found.
+ @retval EFI_SUCCESS The section was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindSectionByType (CoreFvHandle->FvPpi, SectionType, FileHandle, SectionData);
+}
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType The value of the section type to find.
+ @param SectionInstance Section instance to find.
+ @param FileHandle Handle of the firmware file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ @param AuthenticationStatus A pointer to the authentication status for this section.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData3 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
+ }
+ //
+ // The old FvPpi doesn't support to find section by section instance
+ // and return authentication status, so return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Searches for the next matching file in the firmware volume.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FvHandle Handle of firmware volume in which to search.
+ @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
+ at the beginning of the firmware volume. On exit, points the file handle of the next file
+ in the volume or NULL if there are no more files.
+
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+ @retval EFI_SUCCESS The file was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextFile (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ CoreFvHandle = FvHandleToCoreHandle (FvHandle);
+
+ if ((CoreFvHandle == NULL) || CoreFvHandle->FvPpi == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindFileByType (CoreFvHandle->FvPpi, SearchType, FvHandle, FileHandle);
+}
+
+
+/**
+ Search the firmware volumes by index
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
+ Volume (BFV).
+ @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
+ @retval EFI_NOT_FOUND The volume was not found.
+ @retval EFI_SUCCESS The volume was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextVolume (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ )
+{
+ PEI_CORE_INSTANCE *Private;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if (VolumeHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ CoreFvHandle = FindNextCoreFvHandle (Private, Instance);
+ if (CoreFvHandle == NULL) {
+ *VolumeHandle = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ *VolumeHandle = CoreFvHandle->FvHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find a file within a volume by its name.
+
+ @param FileName A pointer to the name of the file to find within the firmware volume.
+ @param VolumeHandle The firmware volume to search
+ @param FileHandle Upon exit, points to the found file's handle
+ or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreFvHandle = FvHandleToCoreHandle (VolumeHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return CoreFvHandle->FvPpi->FindFileByName (CoreFvHandle->FvPpi, FileName, &VolumeHandle, FileHandle);
+}
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, FileHandle, FileInfo);
+}
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo2 (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ return CoreFvHandle->FvPpi->GetFileInfo2 (CoreFvHandle->FvPpi, FileHandle, FileInfo);
+ }
+ //
+ // The old FvPpi doesn't support to return file info with authentication status,
+ // so return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Returns information about the specified volume.
+
+ This function returns information about a specific firmware
+ volume, including its name, type, attributes, starting address
+ and size.
+
+ @param VolumeHandle Handle of the volume.
+ @param VolumeInfo Upon exit, points to the volume's information.
+
+ @retval EFI_SUCCESS Volume information returned.
+ @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
+ @retval EFI_INVALID_PARAMETER If VolumeHandle is NULL.
+ @retval EFI_SUCCESS Information successfully returned.
+ @retval EFI_INVALID_PARAMETER The volume designated by the VolumeHandle is not available.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ )
+{
+ PEI_CORE_FV_HANDLE *CoreHandle;
+
+ if ((VolumeInfo == NULL) || (VolumeHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreHandle = FvHandleToCoreHandle (VolumeHandle);
+
+ if ((CoreHandle == NULL) || (CoreHandle->FvPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreHandle->FvPpi->GetVolumeInfo (CoreHandle->FvPpi, VolumeHandle, VolumeInfo);
+}
+
+/**
+ Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
+
+ @param[in] FvHeader Pointer to FV header.
+ @param[out] FvUsedSize Pointer to FV used size returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+ @param[out] EraseByte Pointer to erase byte returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+
+ @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
+ FV used size and erase byte are returned.
+ @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
+
+**/
+BOOLEAN
+GetFvUsedSize (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ OUT UINT32 *FvUsedSize,
+ OUT UINT8 *EraseByte
+ )
+{
+ UINT16 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
+
+ ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
+ if (ExtHeaderOffset != 0) {
+ ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + ExtHeaderOffset);
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *) (ExtHeader + 1);
+ while ((UINTN) ExtEntryList < ((UINTN) ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
+ if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
+ //
+ // USED_SIZE FV_EXT_TYPE entry is found.
+ //
+ ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *) ExtEntryList;
+ *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
+ *EraseByte = 0xFF;
+ } else {
+ *EraseByte = 0;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
+ FvHeader,
+ *FvUsedSize,
+ *EraseByte
+ ));
+ return TRUE;
+ }
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
+ ((UINT8 *) ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
+ }
+ }
+
+ //
+ // No USED_SIZE FV_EXT_TYPE entry found.
+ //
+ return FALSE;
+}
+
+/**
+ Get FV image(s) from the FV type file, then install FV INFO(2) PPI, Build FV(2, 3) HOB.
+
+ @param PrivateData PeiCore's private data structure
+ @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent FV image that contain this FV image.
+ @param ParentFvFileHandle File handle of a FV type file that contain this FV image.
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
+
+**/
+EFI_STATUS
+ProcessFvFile (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
+ IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_INFO ParentFvImageInfo;
+ UINT32 FvAlignment;
+ VOID *NewFvBuffer;
+ EFI_PEI_HOB_POINTERS HobPtr;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *ParentFvPpi;
+ EFI_PEI_FV_HANDLE ParentFvHandle;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FV_FILE_INFO FileInfo;
+ UINT64 FvLength;
+ UINT32 AuthenticationStatus;
+ UINT32 FvUsedSize;
+ UINT8 EraseByte;
+ UINTN Index;
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ HobPtr.Raw = GetHobList ();
+ while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
+ if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
+ //
+ // this FILE has been dispatched, it will not be dispatched again.
+ //
+ DEBUG ((EFI_D_INFO, "FV file %p has been dispatched!\r\n", ParentFvFileHandle));
+ return EFI_SUCCESS;
+ }
+ HobPtr.Raw = GET_NEXT_HOB (HobPtr);
+ }
+
+ ParentFvHandle = ParentFvCoreHandle->FvHandle;
+ ParentFvPpi = ParentFvCoreHandle->FvPpi;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Find FvImage(s) in FvFile
+ //
+ Index = 0;
+ do {
+ AuthenticationStatus = 0;
+ if ((ParentFvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
+ (ParentFvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
+ Status = ParentFvPpi->FindSectionByType2 (
+ ParentFvPpi,
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+ Index,
+ ParentFvFileHandle,
+ (VOID **)&FvHeader,
+ &AuthenticationStatus
+ );
+ } else {
+ //
+ // Old FvPpi has no parameter to input SearchInstance,
+ // only one instance is supported.
+ //
+ if (Index > 0) {
+ break;
+ }
+ Status = ParentFvPpi->FindSectionByType (
+ ParentFvPpi,
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+ ParentFvFileHandle,
+ (VOID **)&FvHeader
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = VerifyPeim (PrivateData, ParentFvHandle, ParentFvFileHandle, AuthenticationStatus);
+ if (Status == EFI_SECURITY_VIOLATION) {
+ break;
+ }
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
+ __FUNCTION__,
+ FvHeader,
+ FvAlignment
+ ));
+
+ //
+ // Check FvImage alignment.
+ //
+ if ((UINTN) FvHeader % FvAlignment != 0) {
+ FvLength = ReadUnaligned64 (&FvHeader->FvLength);
+ NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvLength), FvAlignment);
+ if (NewFvBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
+ //
+ // Copy the used bytes and fill the rest with the erase value.
+ //
+ CopyMem (NewFvBuffer, FvHeader, (UINTN) FvUsedSize);
+ SetMem (
+ (UINT8 *) NewFvBuffer + FvUsedSize,
+ (UINTN) (FvLength - FvUsedSize),
+ EraseByte
+ );
+ } else {
+ CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
+ }
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
+ }
+ }
+
+ Status = ParentFvPpi->GetVolumeInfo (ParentFvPpi, ParentFvHandle, &ParentFvImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ParentFvPpi->GetFileInfo (ParentFvPpi, ParentFvFileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install FvInfo(2) Ppi
+ // NOTE: FvInfo2 must be installed before FvInfo so that recursive processing of encapsulated
+ // FVs inherit the proper AuthenticationStatus.
+ //
+ PeiServicesInstallFvInfo2Ppi(
+ &FvHeader->FileSystemGuid,
+ (VOID**)FvHeader,
+ (UINT32)FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName,
+ AuthenticationStatus
+ );
+
+ PeiServicesInstallFvInfoPpi (
+ &FvHeader->FileSystemGuid,
+ (VOID**) FvHeader,
+ (UINT32) FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ //
+ // Expose the extracted FvImage to the FV HOB consumer phase, i.e. DXE phase
+ //
+ BuildFvHob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength
+ );
+
+ //
+ // Makes the encapsulated volume show up in DXE phase to skip processing of
+ // encapsulated file again.
+ //
+ BuildFv2Hob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ //
+ // Build FV3 HOB with authentication status to be propagated to DXE.
+ //
+ BuildFv3Hob (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ FvHeader->FvLength,
+ AuthenticationStatus,
+ TRUE,
+ &ParentFvImageInfo.FvName,
+ &FileInfo.FileName
+ );
+
+ Index++;
+ } while (TRUE);
+
+ if (Index > 0) {
+ //
+ // At least one FvImage has been processed successfully.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+/**
+ Process a firmware volume and create a volume handle.
+
+ Create a volume handle from the information in the buffer. For
+ memory-mapped firmware volumes, Buffer and BufferSize refer to
+ the start of the firmware volume and the firmware volume size.
+ For non memory-mapped firmware volumes, this points to a
+ buffer which contains the necessary information for creating
+ the firmware volume handle. Normally, these values are derived
+ from the EFI_FIRMWARE_VOLUME_INFO_PPI.
+
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param Buffer Points to the start of the buffer.
+ @param BufferSize Size of the buffer.
+ @param FvHandle Points to the returned firmware volume
+ handle. The firmware volume handle must
+ be unique within the system.
+
+ @retval EFI_SUCCESS Firmware volume handle created.
+ @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiProcessVolume (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_PEI_FV_HANDLE *FvHandle
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FvHandle != NULL);
+
+ if (Buffer == NULL) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
+ // FV image and the handle is pointed to FV image's buffer.
+ //
+ *FvHandle = (EFI_PEI_FV_HANDLE) Buffer;
+
+ //
+ // Do verify for given FV buffer.
+ //
+ Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*) Buffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds the next file of the specified type.
+
+ This service enables PEI modules to discover additional firmware files.
+ The FileHandle must be unique within the system.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only files of this type. Type
+ EFI_FV_FILETYPE_ALL causes no filtering to be
+ done.
+ @param FvHandle Handle of firmware volume in which to
+ search.
+ @param FileHandle Points to the current handle from which to
+ begin searching or NULL to start at the
+ beginning of the firmware volume. Updated
+ upon return to reflect the file found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
+}
+
+/**
+ Find a file within a volume by its name.
+
+ This service searches for files with a specific name, within
+ either the specified firmware volume or all firmware volumes.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileName A pointer to the name of the file to find
+ within the firmware volume.
+ @param FvHandle Upon entry, the pointer to the firmware
+ volume to search or NULL if all firmware
+ volumes should be searched. Upon exit, the
+ actual firmware volume in which the file was
+ found.
+ @param FileHandle Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
+ FileName was NULL.
+
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByName (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE *FvHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_INSTANCE *PrivateData;
+ UINTN Index;
+
+ if ((FvHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*FvHandle != NULL) {
+ Status = FindFileEx (*FvHandle, FileName, 0, FileHandle, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ *FileHandle = NULL;
+ }
+ } else {
+ //
+ // If *FvHandle = NULL, so search all FV for given filename
+ //
+ Status = EFI_NOT_FOUND;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ //
+ // Only search the FV which is associated with a EFI_PEI_FIRMWARE_VOLUME_PPI instance.
+ //
+ if (PrivateData->Fv[Index].FvPpi != NULL) {
+ Status = FindFileEx (PrivateData->Fv[Index].FvHandle, FileName, 0, FileHandle, NULL);
+ if (!EFI_ERROR (Status)) {
+ *FvHandle = PrivateData->Fv[Index].FvHandle;
+ break;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address and size.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ )
+{
+ UINT8 FileState;
+ UINT8 ErasePolarity;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+ PEI_FW_VOL_INSTANCE *FwVolInstance;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
+
+ if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
+
+ switch (FileState) {
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
+ if (IS_FFS_FILE2 (FileHeader)) {
+ ASSERT (FFS_FILE2_SIZE (FileHeader) > 0x00FFFFFF);
+ if (!FwVolInstance->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FileHeader->Name));
+ return EFI_INVALID_PARAMETER;
+ }
+ FileInfo->BufferSize = FFS_FILE2_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileInfo->BufferSize = FFS_FILE_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
+ FileInfo->FileType = FileHeader->Type;
+ FileInfo->FileAttributes = FfsAttributes2FvFileAttributes (FileHeader->Attributes);
+ if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ FileInfo->FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address, size and authentication status.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+
+ if ((FileHandle == NULL) || (FileInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PeiFfsFvPpiGetFileInfo (This, FileHandle, (EFI_FV_FILE_INFO *) FileInfo);
+ if (!EFI_ERROR (Status)) {
+ FileInfo->AuthenticationStatus = CoreFvHandle->AuthenticationStatus;
+ }
+
+ return Status;
+}
+
+/**
+ This function returns information about the firmware volume.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FvHandle Handle to the firmware handle.
+ @param VolumeInfo Points to the returned firmware volume
+ information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
+ firmware volume or VolumeInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetVolumeInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
+
+ if ((VolumeInfo == NULL) || (FvHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // VolumeHandle may not align at 8 byte,
+ // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
+ // So, Copy FvHeader into the local FvHeader structure.
+ //
+ CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ //
+ // Check FV Image Signature
+ //
+ if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
+ VolumeInfo->FvAttributes = FwVolHeader.Attributes;
+ VolumeInfo->FvStart = (VOID *) FvHandle;
+ VolumeInfo->FvSize = FwVolHeader.FvLength;
+ CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
+
+ if (FwVolHeader.ExtHeaderOffset != 0) {
+ FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)FvHandle) + FwVolHeader.ExtHeaderOffset);
+ CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ )
+{
+ UINT32 AuthenticationStatus;
+ return PeiFfsFvPpiFindSectionByType2 (This, SearchType, 0, FileHandle, SectionData, &AuthenticationStatus);
+}
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given instance and type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param SearchInstance A filter to find the specific instance
+ of sections.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+ @param AuthenticationStatus Updated upon return to point to the
+ authentication status for this section.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN UINTN SearchInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ PEI_FW_VOL_INSTANCE *FwVolInstance;
+ PEI_CORE_FV_HANDLE *CoreFvHandle;
+ UINTN Instance;
+ UINT32 ExtractedAuthenticationStatus;
+
+ if (SectionData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
+
+ //
+ // Retrieve the FirmwareVolume which the file resides in.
+ //
+ CoreFvHandle = FileHandleToVolume (FileHandle);
+ if (CoreFvHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
+
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
+ if (!FwVolInstance->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
+ return EFI_NOT_FOUND;
+ }
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Instance = SearchInstance + 1;
+ ExtractedAuthenticationStatus = 0;
+ Status = ProcessSection (
+ GetPeiServicesTablePointer (),
+ SearchType,
+ &Instance,
+ Section,
+ FileSize,
+ SectionData,
+ &ExtractedAuthenticationStatus,
+ FwVolInstance->IsFfs3Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus = ExtractedAuthenticationStatus | CoreFvHandle->AuthenticationStatus;
+ }
+ return Status;
+}
+
+/**
+ Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
+
+ @param FvHandle The handle of a FV.
+
+ @retval NULL if can not find.
+ @return Pointer of corresponding PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FvHandleToCoreHandle (
+ IN EFI_PEI_FV_HANDLE FvHandle
+ )
+{
+ UINTN Index;
+ PEI_CORE_INSTANCE *PrivateData;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ if (FvHandle == PrivateData->Fv[Index].FvHandle) {
+ return &PrivateData->Fv[Index];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Gets a PEI_CORE_FV_HANDLE instance for the next volume according to the given index.
+
+ This routine also will install an instance of the FvInfo PPI for the FV HOB
+ as defined in the PI specification.
+
+ @param Private Pointer of PEI_CORE_INSTANCE
+ @param Instance Index of the FV to search
+
+ @return Instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FindNextCoreFvHandle (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN Instance
+ )
+{
+ if (Instance >= Private->FvCount) {
+ return NULL;
+ }
+
+ return &Private->Fv[Instance];
+}
+
+/**
+ After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
+ be re-installed with the instance in permanent memory and all cached FvPpi pointers in
+ PrivateData->Fv[] array should be fixed up to be pointed to the one in permanent
+ memory.
+
+ @param PrivateData Pointer to PEI_CORE_INSTANCE.
+**/
+VOID
+PeiReinitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ VOID *OldFfsFvPpi;
+ EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Locate old build-in Ffs2 EFI_PEI_FIRMWARE_VOLUME_PPI which
+ // in flash.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiFirmwareFileSystem2Guid,
+ 0,
+ &OldDescriptor,
+ &OldFfsFvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs2
+ // which is shadowed from flash to permanent memory within PeiCore image.
+ //
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs2FvPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
+ //
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
+ PrivateData->Fv[Index].FvPpi = &mPeiFfs2FwVol.Fv;
+ }
+ }
+
+ //
+ // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which
+ // in flash.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiFirmwareFileSystem3Guid,
+ 0,
+ &OldDescriptor,
+ &OldFfsFvPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3
+ // which is shadowed from flash to permanent memory within PeiCore image.
+ //
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
+ //
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
+ PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;
+ }
+ }
+}
+
+/**
+ Report the information for a newly discovered FV in an unknown format.
+
+ If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for a third-party FV format, but
+ the FV has been discovered, then the information of this FV will be cached into PEI_CORE_INSTANCE's
+ UnknownFvInfo array.
+
+ Also a notification would be installed for unknown FV format GUID, if EFI_PEI_FIRMWARE_VOLUME_PPI
+ is installed later by platform's PEIM, the original unknown FV will be processed by
+ using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param FvInfo2Ppi Point to FvInfo2 PPI.
+
+ @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
+ @retval EFI_SUCCESS Success to add the information for unknown FV.
+**/
+EFI_STATUS
+AddUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI *FvInfo2Ppi
+ )
+{
+ PEI_CORE_UNKNOW_FORMAT_FV_INFO *NewUnknownFv;
+ VOID *TempPtr;
+
+ if (PrivateData->UnknownFvInfoCount >= PrivateData->MaxUnknownFvInfoCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO) * (PrivateData->MaxUnknownFvInfoCount + FV_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ PrivateData->UnknownFvInfo,
+ sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO) * PrivateData->MaxUnknownFvInfoCount
+ );
+ PrivateData->UnknownFvInfo = TempPtr;
+ PrivateData->MaxUnknownFvInfoCount = PrivateData->MaxUnknownFvInfoCount + FV_GROWTH_STEP;
+ }
+
+ NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];
+ PrivateData->UnknownFvInfoCount ++;
+
+ CopyGuid (&NewUnknownFv->FvFormat, &FvInfo2Ppi->FvFormat);
+ NewUnknownFv->FvInfo = FvInfo2Ppi->FvInfo;
+ NewUnknownFv->FvInfoSize = FvInfo2Ppi->FvInfoSize;
+ NewUnknownFv->AuthenticationStatus = FvInfo2Ppi->AuthenticationStatus;
+ NewUnknownFv->NotifyDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ NewUnknownFv->NotifyDescriptor.Guid = &NewUnknownFv->FvFormat;
+ NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;
+
+ PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the FV information according to third-party FV format GUID.
+
+ This routine also will remove the FV information found by given FV format GUID from
+ PrivateData->UnknownFvInfo[].
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param Format Point to given FV format GUID
+ @param FvInfo On return, the pointer of FV information buffer
+ @param FvInfoSize On return, the size of FV information buffer.
+ @param AuthenticationStatus On return, the authentication status of FV information buffer.
+
+ @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
+ @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+**/
+EFI_STATUS
+FindUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_GUID *Format,
+ OUT VOID **FvInfo,
+ OUT UINT32 *FvInfoSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+
+ Index = 0;
+ for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {
+ if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {
+ break;
+ }
+ }
+
+ if (Index == PrivateData->UnknownFvInfoCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ *FvInfo = PrivateData->UnknownFvInfo[Index].FvInfo;
+ *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;
+ *AuthenticationStatus = PrivateData->UnknownFvInfo[Index].AuthenticationStatus;
+
+ //
+ // Remove an entry from UnknownFvInfo array.
+ //
+ Index2 = Index + 1;
+ for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {
+ CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));
+ }
+ PrivateData->UnknownFvInfoCount --;
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
+ routine is called to process all discovered FVs in this format.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The notification callback is processed correctly.
+**/
+EFI_STATUS
+EFIAPI
+ThirdPartyFvPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ VOID *FvInfo;
+ UINT32 FvInfoSize;
+ UINT32 AuthenticationStatus;
+ EFI_STATUS Status;
+ EFI_PEI_FV_HANDLE FvHandle;
+ BOOLEAN IsProcessed;
+ UINTN FvIndex;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *DepexData;
+ UINTN CurFvCount;
+ VOID *TempPtr;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;
+
+ do {
+ Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize, &AuthenticationStatus);
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Process new found FV and get FV handle.
+ //
+ Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));
+ continue;
+ }
+
+ //
+ // Check whether the FV has already been processed.
+ //
+ IsProcessed = FALSE;
+ for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
+ if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
+ DEBUG ((DEBUG_INFO, "The FV %p has already been processed!\n", FvInfo));
+ IsProcessed = TRUE;
+ break;
+ }
+ }
+
+ if (IsProcessed) {
+ continue;
+ }
+
+ if (PrivateData->FvCount >= PrivateData->MaxFvCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_CORE_FV_HANDLE) * (PrivateData->MaxFvCount + FV_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ PrivateData->Fv,
+ sizeof (PEI_CORE_FV_HANDLE) * PrivateData->MaxFvCount
+ );
+ PrivateData->Fv = TempPtr;
+ PrivateData->MaxFvCount = PrivateData->MaxFvCount + FV_GROWTH_STEP;
+ }
+
+ //
+ // Update internal PEI_CORE_FV array.
+ //
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = AuthenticationStatus;
+ CurFvCount = PrivateData->FvCount;
+ DEBUG ((
+ EFI_D_INFO,
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
+ (UINT32) CurFvCount,
+ (VOID *) FvInfo,
+ FvInfoSize,
+ FvHandle
+ ));
+ PrivateData->FvCount ++;
+
+ //
+ // Scan and process the new discovered FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+ FileHandle = NULL;
+ do {
+ Status = FvPpi->FindFileByType (
+ FvPpi,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+ FvHandle,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FvPpi->FindSectionByType (
+ FvPpi,
+ EFI_SECTION_PEI_DEPEX,
+ FileHandle,
+ (VOID**)&DepexData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!PeimDispatchReadiness (PeiServices, DepexData)) {
+ //
+ // Dependency is not satisfied.
+ //
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
+ ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
+ }
+ } while (FileHandle != NULL);
+ } while (TRUE);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.h b/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.h
new file mode 100644
index 000000000..7241c01b8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/FwVol/FwVol.h
@@ -0,0 +1,372 @@
+/** @file
+ The internal header file for firmware volume related definitions.
+
+Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FWVOL_H_
+#define _FWVOL_H_
+
+#include "PeiMain.h"
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+
+#define PEI_FW_VOL_SIGNATURE SIGNATURE_32('P','F','W','V')
+
+typedef struct {
+ UINTN Signature;
+ BOOLEAN IsFfs3Fv;
+ EFI_PEI_FIRMWARE_VOLUME_PPI Fv;
+} PEI_FW_VOL_INSTANCE;
+
+#define PEI_FW_VOL_INSTANCE_FROM_FV_THIS(a) \
+ CR(a, PEI_FW_VOL_INSTANCE, Fv, PEI_FW_VOL_SIGNATURE)
+
+
+/**
+ Process a firmware volume and create a volume handle.
+
+ Create a volume handle from the information in the buffer. For
+ memory-mapped firmware volumes, Buffer and BufferSize refer to
+ the start of the firmware volume and the firmware volume size.
+ For non memory-mapped firmware volumes, this points to a
+ buffer which contains the necessary information for creating
+ the firmware volume handle. Normally, these values are derived
+ from the EFI_FIRMWARE_VOLUME_INFO_PPI.
+
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param Buffer Points to the start of the buffer.
+ @param BufferSize Size of the buffer.
+ @param FvHandle Points to the returned firmware volume
+ handle. The firmware volume handle must
+ be unique within the system.
+
+ @retval EFI_SUCCESS Firmware volume handle created.
+ @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiProcessVolume (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_PEI_FV_HANDLE *FvHandle
+ );
+
+/**
+ Finds the next file of the specified type.
+
+ This service enables PEI modules to discover additional firmware files.
+ The FileHandle must be unique within the system.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only files of this type. Type
+ EFI_FV_FILETYPE_ALL causes no filtering to be
+ done.
+ @param FvHandle Handle of firmware volume in which to
+ search.
+ @param FileHandle Points to the current handle from which to
+ begin searching or NULL to start at the
+ beginning of the firmware volume. Updated
+ upon return to reflect the file found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Find a file within a volume by its name.
+
+ This service searches for files with a specific name, within
+ either the specified firmware volume or all firmware volumes.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileName A pointer to the name of the file to find
+ within the firmware volume.
+ @param FvHandle Upon entry, the pointer to the firmware
+ volume to search or NULL if all firmware
+ volumes should be searched. Upon exit, the
+ actual firmware volume in which the file was
+ found.
+ @param FileHandle Upon exit, points to the found file's
+ handle or NULL if it could not be found.
+
+ @retval EFI_SUCCESS File was found.
+ @retval EFI_NOT_FOUND File was not found.
+ @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
+ FileName was NULL.
+
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindFileByName (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE *FvHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ );
+
+/**
+ Find the next matching section in the firmware file.
+
+ This service enables PEI modules to discover sections
+ of a given instance and type within a valid file.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param SearchType A filter to find only sections of this
+ type.
+ @param SearchInstance A filter to find the specific instance
+ of sections.
+ @param FileHandle Handle of firmware file in which to
+ search.
+ @param SectionData Updated upon return to point to the
+ section found.
+ @param AuthenticationStatus Updated upon return to point to the
+ authentication status for this section.
+
+ @retval EFI_SUCCESS Section was found.
+ @retval EFI_NOT_FOUND Section of the specified type was not
+ found. SectionData contains NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiFindSectionByType2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_SECTION_TYPE SearchType,
+ IN UINTN SearchInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address and size.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ );
+
+/**
+ Returns information about a specific file.
+
+ This function returns information about a specific
+ file, including its file name, type, attributes, starting
+ address, size and authentication status.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's
+ information.
+
+ @retval EFI_SUCCESS File information returned.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not
+ represent a valid file.
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetFileInfo2 (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ );
+
+/**
+ This function returns information about the firmware volume.
+
+ @param This Points to this instance of the
+ EFI_PEI_FIRMWARE_VOLUME_PPI.
+ @param FvHandle Handle to the firmware handle.
+ @param VolumeInfo Points to the returned firmware volume
+ information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
+ firmware volume or VolumeInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFvPpiGetVolumeInfo (
+ IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ );
+
+/**
+ Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
+
+ @param FvHandle The handle of a FV.
+
+ @retval NULL if can not find.
+ @return Pointer of corresponding PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FvHandleToCoreHandle (
+ IN EFI_PEI_FV_HANDLE FvHandle
+ );
+
+/**
+ Given the input file pointer, search for the next matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+
+
+ @param FvHandle Pointer to the FV header of the volume to search
+ @param FileName File name
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FileHandle This parameter must point to a valid FFS volume.
+ @param AprioriFile Pointer to AprioriFile image in this FV if has
+
+ @return EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+FindFileEx (
+ IN CONST EFI_PEI_FV_HANDLE FvHandle,
+ IN CONST EFI_GUID *FileName, OPTIONAL
+ IN EFI_FV_FILETYPE SearchType,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *AprioriFile OPTIONAL
+ );
+
+/**
+ Report the information for a newly discovered FV in an unknown format.
+
+ If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for a third-party FV format, but
+ the FV has been discovered, then the information of this FV will be cached into PEI_CORE_INSTANCE's
+ UnknownFvInfo array.
+
+ Also a notification would be installed for unknown FV format GUID, if EFI_PEI_FIRMWARE_VOLUME_PPI
+ is installed later by platform's PEIM, the original unknown FV will be processed by
+ using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param FvInfo2Ppi Point to FvInfo2 PPI.
+
+ @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
+ @retval EFI_SUCCESS Success to add the information for unknown FV.
+**/
+EFI_STATUS
+AddUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI *FvInfo2Ppi
+ );
+
+/**
+ Find the FV information according to FV format GUID.
+
+ This routine also will remove the FV information found by given FV format GUID from
+ PrivateData->UnknownFvInfo[].
+
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE
+ @param Format Point to given FV format GUID
+ @param FvInfo On return, the pointer of FV information buffer in given FV format GUID
+ @param FvInfoSize On return, the size of FV information buffer.
+ @param AuthenticationStatus On return, the authentication status of FV information buffer.
+
+ @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
+ @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
+**/
+EFI_STATUS
+FindUnknownFormatFvInfo (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_GUID *Format,
+ OUT VOID **FvInfo,
+ OUT UINT32 *FvInfoSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
+
+ When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
+ routine is called to process all discovered FVs in this format.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The notification callback is processed correctly.
+**/
+EFI_STATUS
+EFIAPI
+ThirdPartyFvPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Hob/Hob.c b/roms/edk2/MdeModulePkg/Core/Pei/Hob/Hob.c
new file mode 100644
index 000000000..4d8db2e7a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Hob/Hob.c
@@ -0,0 +1,234 @@
+/** @file
+ This module provide Hand-Off Block manipulation.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Gets the pointer to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param HobList Pointer to the HOB List.
+
+ @retval EFI_SUCCESS Get the pointer of HOB List
+ @retval EFI_NOT_AVAILABLE_YET the HOB List is not yet published
+ @retval EFI_INVALID_PARAMETER HobList is NULL (in debug mode)
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetHobList (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **HobList
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ //
+ // Only check this parameter in debug mode
+ //
+
+ DEBUG_CODE_BEGIN ();
+ if (HobList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ DEBUG_CODE_END ();
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ *HobList = PrivateData->HobList.Raw;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add a new HOB to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Type Type of the new HOB.
+ @param Length Length of the new HOB to allocate.
+ @param Hob Pointer to the new HOB.
+
+ @return EFI_SUCCESS Success to create HOB.
+ @retval EFI_INVALID_PARAMETER if Hob is NULL
+ @retval EFI_NOT_AVAILABLE_YET if HobList is still not available.
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCreateHob (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT16 Type,
+ IN UINT16 Length,
+ IN OUT VOID **Hob
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+
+
+ Status = PeiGetHobList (PeiServices, Hob);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ HandOffHob = *Hob;
+
+ //
+ // Check Length to avoid data overflow.
+ //
+ if (0x10000 - Length <= 0x7) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Length = (UINT16)((Length + 0x7) & (~0x7));
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop -
+ HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < Length) {
+ DEBUG ((EFI_D_ERROR, "PeiCreateHob fail: Length - 0x%08x\n", (UINTN)Length));
+ DEBUG ((EFI_D_ERROR, " FreeMemoryTop - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryTop));
+ DEBUG ((EFI_D_ERROR, " FreeMemoryBottom - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryBottom));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobType = Type;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->HobLength = Length;
+ ((EFI_HOB_GENERIC_HEADER*) *Hob)->Reserved = 0;
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN) *Hob + Length);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install SEC HOB data to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SecHobList Pointer to SEC HOB List.
+
+ @return EFI_SUCCESS Success to install SEC HOB data.
+ @retval EFI_OUT_OF_RESOURCES If there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+PeiInstallSecHobData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_HOB_GENERIC_HEADER *SecHobList
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_PEI_HOB_POINTERS HobStart;
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN SecHobListLength;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ HandOffHob = NULL;
+ Status = PeiGetHobList (PeiServices, (VOID **) &HandOffHob);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ ASSERT (HandOffHob != NULL);
+
+ HobStart.Raw = (UINT8 *) SecHobList;
+ //
+ // The HobList must not contain a EFI_HOB_HANDOFF_INFO_TABLE HOB (PHIT) HOB.
+ //
+ ASSERT (HobStart.Header->HobType != EFI_HOB_TYPE_HANDOFF);
+ //
+ // Calculate the SEC HOB List length,
+ // not including the terminated HOB(EFI_HOB_TYPE_END_OF_HOB_LIST).
+ //
+ for (Hob.Raw = HobStart.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob));
+ SecHobListLength = (UINTN) Hob.Raw - (UINTN) HobStart.Raw;
+ //
+ // The length must be 8-bytes aligned.
+ //
+ ASSERT ((SecHobListLength & 0x7) == 0);
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop -
+ HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < SecHobListLength) {
+ DEBUG ((DEBUG_ERROR, "PeiInstallSecHobData fail: SecHobListLength - 0x%08x\n", SecHobListLength));
+ DEBUG ((DEBUG_ERROR, " FreeMemoryTop - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryTop));
+ DEBUG ((DEBUG_ERROR, " FreeMemoryBottom - 0x%08x\n", (UINTN)HandOffHob->EfiFreeMemoryBottom));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Hob.Raw = (UINT8 *) (UINTN) HandOffHob->EfiEndOfHobList;
+ CopyMem (Hob.Raw, HobStart.Raw, SecHobListLength);
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER *) ((UINTN) Hob.Raw + SecHobListLength);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Builds a Handoff Information Table HOB
+
+ @param BootMode - Current Bootmode
+ @param MemoryBegin - Start Memory Address.
+ @param MemoryLength - Length of Memory.
+
+ @return EFI_SUCCESS Always success to initialize HOB.
+
+**/
+EFI_STATUS
+PeiCoreBuildHobHandoffInfoTable (
+ IN EFI_BOOT_MODE BootMode,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *Hob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ Hob = (VOID *)(UINTN)MemoryBegin;
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) (Hob+1);
+ Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
+ Hob->Header.HobLength = (UINT16) sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
+ Hob->Header.Reserved = 0;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = (UINT16) sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+
+ Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
+ Hob->BootMode = BootMode;
+
+ Hob->EfiMemoryTop = MemoryBegin + MemoryLength;
+ Hob->EfiMemoryBottom = MemoryBegin;
+ Hob->EfiFreeMemoryTop = MemoryBegin + MemoryLength;
+ Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) (HobEnd + 1);
+ Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Image/Image.c b/roms/edk2/MdeModulePkg/Core/Pei/Image/Image.c
new file mode 100644
index 000000000..1d1577452
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Image/Image.c
@@ -0,0 +1,970 @@
+/** @file
+ Pei Core Load Image Support
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+
+EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
+ PeiLoadImageLoadImageWrapper
+};
+
+
+EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiLoadFilePpiGuid,
+ &mPeiLoadImagePpi
+};
+
+/**
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
+ The function is used for XIP code to have optimized memory copy.
+
+ @param FileHandle - The handle to the PE/COFF file
+ @param FileOffset - The offset, in bytes, into the file to read
+ @param ReadSize - The number of bytes to read from the file starting at FileOffset
+ @param Buffer - A pointer to the buffer to read the data into.
+
+ @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+**/
+EFI_STATUS
+EFIAPI
+PeiImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ if (Destination8 != Source8) {
+ CopyMem (Destination8, Source8, *ReadSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param Private Pointer to the private data passed in from caller
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT32 ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 ReservedCodeSize;
+ EFI_PHYSICAL_ADDRESS PeiCodeBase;
+ UINT32 BaseOffsetPageNumber;
+ UINT32 TopOffsetPageNumber;
+ UINT32 Index;
+ UINT64 *MemoryUsageBitMap;
+
+
+ //
+ // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
+ //
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
+
+ //
+ // Test the memory range for loading the image in the PEI code range.
+ //
+ if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||
+ (PeiCodeBase > ImageBase)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is available or not.
+ //
+ MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap;
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @param Private Pointer to the private data passed in from caller
+
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ if (ImageContext->IsTeImage) {
+ //
+ // for TE image, the fix loading address is saved in first section header that doesn't point
+ // to code section.
+ //
+ SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
+ NumberOfSections = ImgHdr->Te.NumberOfSections;
+ } else {
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+ }
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
+ // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
+ // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
+ // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a
+ // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
+ // else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section.
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {
+ //
+ // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the absolute address of image base running in memory
+ //
+ FixLoadingAddress = ValueInSectionHeader;
+ } else {
+ //
+ // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the offset relative to a platform-specific top address.
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
+ }
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32) ImageContext->ImageSize);
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status));
+ return Status;
+}
+/**
+
+ Loads and relocates a PE/COFF image into memory.
+ If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
+
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress - The base address of the relocated PE/COFF image
+ @param ImageSize - The size of the relocated PE/COFF image
+ @param EntryPoint - The entry point of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImage (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN VOID *Pe32Data,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
+ OUT UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PEI_CORE_INSTANCE *Private;
+ UINT64 AlignImageSize;
+ BOOLEAN IsXipImage;
+ EFI_STATUS ReturnStatus;
+ BOOLEAN IsS3Boot;
+ BOOLEAN IsPeiModule;
+ BOOLEAN IsRegisterForShadow;
+ EFI_FV_FILE_INFO FileInfo;
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ ReturnStatus = EFI_SUCCESS;
+ IsXipImage = FALSE;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+ ImageContext.ImageRead = PeiImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize local IsS3Boot and IsRegisterForShadow variable
+ //
+ IsS3Boot = FALSE;
+ if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
+ IsS3Boot = TRUE;
+ }
+ IsRegisterForShadow = FALSE;
+ if ((Private->CurrentFileHandle == FileHandle)
+ && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW)) {
+ IsRegisterForShadow = TRUE;
+ }
+
+ //
+ // XIP image that ImageAddress is same to Image handle.
+ //
+ if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ IsXipImage = TRUE;
+ }
+
+ //
+ // Get file type first
+ //
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check whether the file type is PEI module.
+ //
+ IsPeiModule = FALSE;
+ if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE ||
+ FileInfo.FileType == EFI_FV_FILETYPE_PEIM ||
+ FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) {
+ IsPeiModule = TRUE;
+ }
+
+ //
+ // When Image has no reloc section, it can't be relocated into memory.
+ //
+ if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
+ ) {
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
+ }
+
+ //
+ // Set default base address to current image address.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
+
+ //
+ // Allocate Memory for the image when memory is ready, and image is relocatable.
+ // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
+ // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
+ //
+ if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
+ ) {
+ //
+ // Allocate more buffer to avoid buffer overflow.
+ //
+ if (ImageContext.IsTeImage) {
+ AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
+ } else {
+ AlignImageSize = ImageContext.ImageSize;
+ }
+
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ AlignImageSize += ImageContext.SectionAlignment;
+ }
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
+ if (EFI_ERROR (Status)){
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // The PEIM is not assigned valid address, try to allocate page to load it.
+ //
+ Status = PeiServicesAllocatePages (EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize),
+ &ImageContext.ImageAddress);
+ }
+ } else {
+ Status = PeiServicesAllocatePages (EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize),
+ &ImageContext.ImageAddress);
+ }
+ if (!EFI_ERROR (Status)) {
+ //
+ // Adjust the Image Address to make sure it is section alignment.
+ //
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ ImageContext.ImageAddress =
+ (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
+ ~((UINTN)ImageContext.SectionAlignment - 1);
+ }
+ //
+ // Fix alignment requirement when Load IPF TeImage into memory.
+ // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
+ //
+ if (ImageContext.IsTeImage) {
+ ImageContext.ImageAddress = ImageContext.ImageAddress +
+ ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
+ sizeof (EFI_TE_IMAGE_HEADER);
+ }
+ } else {
+ //
+ // No enough memory resource.
+ //
+ if (IsXipImage) {
+ //
+ // XIP image can still be invoked.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
+ ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Non XIP image can't be loaded because no enough memory is allocated.
+ //
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) {
+ DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID*)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment));
+ }
+ return Status;
+ }
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ }
+
+ *ImageAddress = ImageContext.ImageAddress;
+ *ImageSize = ImageContext.ImageSize;
+ *EntryPoint = ImageContext.EntryPoint;
+
+ return ReturnStatus;
+}
+
+/**
+ Loads and relocates a PE/COFF image in place.
+
+ @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress The base address of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated.
+ @retval Others The file not be loaded and error occurred.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImageInPlace (
+ IN VOID *Pe32Data,
+ IN VOID *ImageAddress
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+ ImageContext.ImageRead = PeiImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN) ImageAddress;
+
+ //
+ // Load the image in place
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Relocate the image in place
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ }
+
+ return Status;
+}
+
+/**
+ Find the PE32 Data for an FFS file.
+
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate PE32 Data.
+
+**/
+EFI_STATUS
+PeiGetPe32Data (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **Pe32Data
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SearchType1;
+ EFI_SECTION_TYPE SearchType2;
+ UINT32 AuthenticationState;
+
+ *Pe32Data = NULL;
+
+ if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
+ SearchType1 = EFI_SECTION_TE;
+ SearchType2 = EFI_SECTION_PE32;
+ } else {
+ SearchType1 = EFI_SECTION_PE32;
+ SearchType2 = EFI_SECTION_TE;
+ }
+
+ //
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // is true, TE will be searched first).
+ //
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType1,
+ 0,
+ FileHandle,
+ Pe32Data,
+ &AuthenticationState
+ );
+ //
+ // If we didn't find a first exe section, try to find the second exe section.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType2,
+ 0,
+ FileHandle,
+ Pe32Data,
+ &AuthenticationState
+ );
+ }
+ return Status;
+}
+
+/**
+ Loads a PEIM into memory for subsequent execution. If there are compressed
+ images or images that need to be relocated into memory for performance reasons,
+ this service performs that transformation.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param ImageAddressArg Pointer to PE/TE image.
+ @param ImageSizeArg Size of PE/TE image.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate necessary PPI.
+ @retval EFI_UNSUPPORTED Image Machine Type is not supported.
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+PeiLoadImageLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS Status;
+ VOID *Pe32Data;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ EFI_PHYSICAL_ADDRESS ImageEntryPoint;
+ UINT16 Machine;
+ EFI_SECTION_TYPE SearchType1;
+ EFI_SECTION_TYPE SearchType2;
+
+ *EntryPoint = 0;
+ ImageSize = 0;
+ *AuthenticationState = 0;
+
+ if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
+ SearchType1 = EFI_SECTION_TE;
+ SearchType2 = EFI_SECTION_PE32;
+ } else {
+ SearchType1 = EFI_SECTION_PE32;
+ SearchType2 = EFI_SECTION_TE;
+ }
+
+ //
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // is true, TE will be searched first).
+ //
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType1,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ //
+ // If we didn't find a first exe section, try to find the second exe section.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType2,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // PEI core only carry the loader function for TE and PE32 executables
+ // If this two section does not exist, just return.
+ //
+ return Status;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "Loading PEIM %g\n", FileHandle));
+
+ //
+ // If memory is installed, perform the shadow operations
+ //
+ Status = LoadAndRelocatePeCoffImage (
+ FileHandle,
+ Pe32Data,
+ &ImageAddress,
+ &ImageSize,
+ &ImageEntryPoint
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Got the entry point from the loaded Pe32Data
+ //
+ Pe32Data = (VOID *) ((UINTN) ImageAddress);
+ *EntryPoint = ImageEntryPoint;
+
+ Machine = PeCoffLoaderGetMachineType (Pe32Data);
+
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
+ if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (ImageAddressArg != NULL) {
+ *ImageAddressArg = ImageAddress;
+ }
+
+ if (ImageSizeArg != NULL) {
+ *ImageSizeArg = ImageSize;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR8 *AsciiString;
+ CHAR8 EfiFileName[512];
+ INT32 Index;
+ INT32 StartIndex;
+
+ //
+ // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
+ //
+ if (Machine != EFI_IMAGE_MACHINE_IA64) {
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
+ } else {
+ //
+ // For IPF Image, the real entry point should be print.
+ //
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
+ }
+
+ //
+ // Print Module Name by PeImage PDB file name.
+ //
+ AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
+
+ if (AsciiString != NULL) {
+ StartIndex = 0;
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~511.
+ // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = AsciiString[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
+ }
+
+ DEBUG_CODE_END ();
+
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ The wrapper function of PeiLoadImageLoadImage().
+
+ @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param ImageAddressArg - Pointer to PE/TE image.
+ @param ImageSizeArg - Size of PE/TE image.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @return Status of PeiLoadImageLoadImage().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadImageLoadImageWrapper (
+ IN CONST EFI_PEI_LOAD_FILE_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ return PeiLoadImageLoadImage (
+ GetPeiServicesTablePointer (),
+ FileHandle,
+ ImageAddressArg,
+ ImageSizeArg,
+ EntryPoint,
+ AuthenticationState
+ );
+}
+
+/**
+ Check whether the input image has the relocation.
+
+ @param Pe32Data Pointer to the PE/COFF or TE image.
+
+ @retval TRUE Relocation is stripped.
+ @retval FALSE Relocation is not stripped.
+
+**/
+BOOLEAN
+RelocationIsStrip (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
+ }
+
+ //
+ // Three cases with regards to relocations:
+ // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
+ // has no base relocs to apply
+ // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
+ //
+ // Look at the file header to determine if relocations have been stripped, and
+ // save this info in the image context for later use.
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Routine to load image file for subsequent execution by LoadFile Ppi.
+ If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
+ XIP image format is used.
+
+ @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param PeimState - The dispatch state of the input PEIM handle.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS - Image is successfully loaded.
+ @retval EFI_NOT_FOUND - Fail to locate necessary PPI
+ @retval Others - Fail to load file.
+
+**/
+EFI_STATUS
+PeiLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT8 PeimState,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS PpiStatus;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ BOOLEAN IsStrip;
+
+ IsStrip = FALSE;
+ //
+ // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
+ // one at a time, until one reports EFI_SUCCESS.
+ //
+ Index = 0;
+ do {
+ PpiStatus = PeiServicesLocatePpi (
+ &gEfiPeiLoadFilePpiGuid,
+ Index,
+ NULL,
+ (VOID **)&LoadFile
+ );
+ if (!EFI_ERROR (PpiStatus)) {
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &ImageAddress,
+ &ImageSize,
+ EntryPoint,
+ AuthenticationState
+ );
+ if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) {
+ //
+ // The shadowed PEIM must be relocatable.
+ //
+ if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) {
+ IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
+ ASSERT (!IsStrip);
+ if (IsStrip) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // The image to be started must have the machine type supported by PeiCore.
+ //
+ ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ Index++;
+ } while (!EFI_ERROR (PpiStatus));
+
+ return PpiStatus;
+}
+
+
+/**
+
+ Install Pei Load File PPI.
+
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
+
+**/
+VOID
+InitializeImageServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ //
+ // The first time we are XIP (running from FLASH). We need to remember the
+ // FLASH address so we can reinstall the memory version that runs faster
+ //
+ PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
+ PeiServicesInstallPpi (PrivateData->XipLoadFile);
+ } else {
+ //
+ // 2nd time we are running from memory so replace the XIP version with the
+ // new memory version.
+ //
+ PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
+ }
+}
+
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/roms/edk2/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
new file mode 100644
index 000000000..9d933f039
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
@@ -0,0 +1,895 @@
+/** @file
+ EFI PEI Core memory services
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Initialize the memory services.
+
+ @param PrivateData Points to PeiCore's private instance data.
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+ @param OldCoreData Pointer to the PEI Core data.
+ NULL if being run in non-permanent memory mode.
+
+**/
+VOID
+InitializeMemoryServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+
+ PrivateData->SwitchStackSignal = FALSE;
+
+ //
+ // First entering PeiCore, following code will initialized some field
+ // in PeiCore's private data according to hand off data from SEC core.
+ //
+ if (OldCoreData == NULL) {
+
+ PrivateData->PeiMemoryInstalled = FALSE;
+ PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;
+
+ PeiCoreBuildHobHandoffInfoTable (
+ BOOT_WITH_FULL_CONFIGURATION,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
+ (UINTN) SecCoreData->PeiTemporaryRamSize
+ );
+
+ //
+ // Set Ps to point to ServiceTableShadow in Cache
+ //
+ PrivateData->Ps = &(PrivateData->ServiceTableShadow);
+ }
+
+ return;
+}
+
+/**
+
+ This function registers the found memory configuration with the PEI Foundation.
+
+ The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
+ This routine will hold discoveried memory information into PeiCore's private data,
+ and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
+ PeiDispatcher will migrate temporary memory to permanent memory.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryBegin Start of memory address.
+ @param MemoryLength Length of memory.
+
+ @return EFI_SUCCESS Always success.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPeiMemory (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ //
+ // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
+ // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
+ // simply return EFI_SUCCESS in release tip to ignore it.
+ //
+ if (PrivateData->PeiMemoryInstalled) {
+ DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+ }
+
+ PrivateData->PhysicalMemoryBegin = MemoryBegin;
+ PrivateData->PhysicalMemoryLength = MemoryLength;
+ PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
+
+ PrivateData->SwitchStackSignal = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Migrate memory pages allocated in pre-memory phase.
+ Copy memory pages at temporary heap top to permanent heap top.
+
+ @param[in] Private Pointer to the private data passed in from caller.
+ @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
+
+**/
+VOID
+MigrateMemoryPages (
+ IN PEI_CORE_INSTANCE *Private,
+ IN BOOLEAN TemporaryRamMigrated
+ )
+{
+ EFI_PHYSICAL_ADDRESS NewMemPagesBase;
+ EFI_PHYSICAL_ADDRESS MemPagesBase;
+
+ Private->MemoryPages.Size = (UINTN) (Private->HobList.HandoffInformationTable->EfiMemoryTop -
+ Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
+ if (Private->MemoryPages.Size == 0) {
+ //
+ // No any memory page allocated in pre-memory phase.
+ //
+ return;
+ }
+ Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;
+
+ ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);
+ NewMemPagesBase = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;
+ NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;
+ ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);
+ //
+ // Copy memory pages at temporary heap top to permanent heap top.
+ //
+ if (TemporaryRamMigrated) {
+ //
+ // Memory pages at temporary heap top has been migrated to permanent heap,
+ // Here still needs to copy them from permanent heap to permanent heap top.
+ //
+ MemPagesBase = Private->MemoryPages.Base;
+ if (Private->HeapOffsetPositive) {
+ MemPagesBase += Private->HeapOffset;
+ } else {
+ MemPagesBase -= Private->HeapOffset;
+ }
+ CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
+ } else {
+ CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
+ }
+
+ if (NewMemPagesBase >= Private->MemoryPages.Base) {
+ Private->MemoryPages.OffsetPositive = TRUE;
+ Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
+ } else {
+ Private->MemoryPages.OffsetPositive = FALSE;
+ Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
+ }
+
+ DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64) Private->MemoryPages.Offset));
+
+ Private->FreePhysicalMemoryTop = NewMemPagesBase;
+}
+
+/**
+ Removes any FV HOBs whose base address is not in PEI installed memory.
+
+ @param[in] Private Pointer to PeiCore's private data structure.
+
+**/
+VOID
+RemoveFvHobsInTemporaryMemory (
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
+
+ DEBUG ((DEBUG_INFO, "Removing FVs in FV HOB not already migrated to permanent memory.\n"));
+
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV || GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2 || GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
+ FirmwareVolumeHob = Hob.FirmwareVolume;
+ DEBUG ((DEBUG_INFO, " Found FV HOB.\n"));
+ DEBUG ((
+ DEBUG_INFO,
+ " BA=%016lx L=%016lx\n",
+ FirmwareVolumeHob->BaseAddress,
+ FirmwareVolumeHob->Length
+ ));
+ if (
+ !(
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) FirmwareVolumeHob->BaseAddress >= Private->PhysicalMemoryBegin) &&
+ (((EFI_PHYSICAL_ADDRESS) (UINTN) FirmwareVolumeHob->BaseAddress + (FirmwareVolumeHob->Length - 1)) < Private->FreePhysicalMemoryTop)
+ )
+ ) {
+ DEBUG ((DEBUG_INFO, " Removing FV HOB to an FV in T-RAM (was not migrated).\n"));
+ Hob.Header->HobType = EFI_HOB_TYPE_UNUSED;
+ }
+ }
+ }
+}
+
+/**
+ Migrate the base address in firmware volume allocation HOBs
+ from temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+ @param[in] OrgFvHandle Address of FV Handle in temporary memory.
+ @param[in] FvHandle Address of FV Handle in permanent memory.
+
+**/
+VOID
+ConvertFvHob (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
+ EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2Hob;
+ EFI_HOB_FIRMWARE_VOLUME3 *FirmwareVolume3Hob;
+
+ DEBUG ((DEBUG_INFO, "Converting FVs in FV HOB.\n"));
+
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ FirmwareVolumeHob = Hob.FirmwareVolume;
+ if (FirmwareVolumeHob->BaseAddress == OrgFvHandle) {
+ FirmwareVolumeHob->BaseAddress = FvHandle;
+ }
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
+ FirmwareVolume2Hob = Hob.FirmwareVolume2;
+ if (FirmwareVolume2Hob->BaseAddress == OrgFvHandle) {
+ FirmwareVolume2Hob->BaseAddress = FvHandle;
+ }
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
+ FirmwareVolume3Hob = Hob.FirmwareVolume3;
+ if (FirmwareVolume3Hob->BaseAddress == OrgFvHandle) {
+ FirmwareVolume3Hob->BaseAddress = FvHandle;
+ }
+ }
+ }
+}
+
+/**
+ Migrate MemoryBaseAddress in memory allocation HOBs
+ from the temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertMemoryAllocationHobs (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ EFI_PHYSICAL_ADDRESS OldMemPagesBase;
+ UINTN OldMemPagesSize;
+
+ if (PrivateData->MemoryPages.Size == 0) {
+ //
+ // No any memory page allocated in pre-memory phase.
+ //
+ return;
+ }
+
+ OldMemPagesBase = PrivateData->MemoryPages.Base;
+ OldMemPagesSize = PrivateData->MemoryPages.Size;
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ if ((MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress >= OldMemPagesBase) &&
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress < (OldMemPagesBase + OldMemPagesSize))
+ ) {
+ if (PrivateData->MemoryPages.OffsetPositive) {
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;
+ } else {
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;
+ }
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+}
+
+/**
+ Internal function to build a HOB for the memory allocation.
+ It will search and reuse the unused(freed) memory allocation HOB,
+ or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.
+
+ @param[in] BaseAddress The 64 bit physical address of the memory.
+ @param[in] Length The length of the memory allocation in bytes.
+ @param[in] MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+InternalBuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ //
+ // Search unused(freed) memory allocation HOB.
+ //
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_UNUSED);
+ while (Hob.Raw != NULL) {
+ if (Hob.Header->HobLength == sizeof (EFI_HOB_MEMORY_ALLOCATION)) {
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ //
+ // Reuse the unused(freed) memory allocation HOB.
+ //
+ MemoryAllocationHob->Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION;
+ ZeroMem (&(MemoryAllocationHob->AllocDescriptor.Name), sizeof (EFI_GUID));
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ MemoryAllocationHob->AllocDescriptor.MemoryLength = Length;
+ MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));
+ } else {
+ //
+ // No unused(freed) memory allocation HOB found.
+ // Build memory allocation HOB normally.
+ //
+ BuildMemoryAllocationHob (
+ BaseAddress,
+ Length,
+ MemoryType
+ );
+ }
+}
+
+/**
+ Update or split memory allocation HOB for memory pages allocate and free.
+
+ @param[in, out] MemoryAllocationHob Pointer to the memory allocation HOB
+ that needs to be updated or split.
+ On output, it will be filled with
+ the input Memory, Bytes and MemoryType.
+ @param[in] Memory Memory to allocate or free.
+ @param[in] Bytes Bytes to allocate or free.
+ @param[in] MemoryType EfiConventionalMemory for pages free,
+ others for pages allocate.
+
+**/
+VOID
+UpdateOrSplitMemoryAllocationHob (
+ IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Bytes,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ if ((Memory + Bytes) <
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength)) {
+ //
+ // Last pages need to be split out.
+ //
+ InternalBuildMemoryAllocationHob (
+ Memory + Bytes,
+ (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),
+ MemoryAllocationHob->AllocDescriptor.MemoryType
+ );
+ }
+
+ if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+ //
+ // First pages need to be split out.
+ //
+ InternalBuildMemoryAllocationHob (
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
+ Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
+ MemoryAllocationHob->AllocDescriptor.MemoryType
+ );
+ }
+
+ //
+ // Update the memory allocation HOB.
+ //
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;
+ MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;
+ MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
+}
+
+/**
+ Merge adjacent free memory ranges in memory allocation HOBs.
+
+ @retval TRUE There are free memory ranges merged.
+ @retval FALSE No free memory ranges merged.
+
+**/
+BOOLEAN
+MergeFreeMemoryInMemoryAllocationHob (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_HOB_POINTERS Hob2;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob2;
+ UINT64 Start;
+ UINT64 End;
+ BOOLEAN Merged;
+
+ Merged = FALSE;
+
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {
+ MemoryHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ Start = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ End = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
+
+ Hob2.Raw = GET_NEXT_HOB (Hob);
+ Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ while (Hob2.Raw != NULL) {
+ if (Hob2.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {
+ MemoryHob2 = (EFI_HOB_MEMORY_ALLOCATION *) Hob2.Raw;
+ if (Start == (MemoryHob2->AllocDescriptor.MemoryBaseAddress + MemoryHob2->AllocDescriptor.MemoryLength)) {
+ //
+ // Merge adjacent two free memory ranges.
+ //
+ MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
+ Merged = TRUE;
+ //
+ // Mark MemoryHob to be unused(freed).
+ //
+ MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
+ break;
+ } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {
+ //
+ // Merge adjacent two free memory ranges.
+ //
+ MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
+ Merged = TRUE;
+ //
+ // Mark MemoryHob to be unused(freed).
+ //
+ MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
+ break;
+ }
+ }
+ Hob2.Raw = GET_NEXT_HOB (Hob2);
+ Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ return Merged;
+}
+
+/**
+ Find free memory by searching memory allocation HOBs.
+
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of contiguous 4 KB pages to allocate.
+ @param[in] Granularity Page allocation granularity.
+ @param[out] Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_NOT_FOUND No memory allocation HOB with big enough free memory found.
+
+**/
+EFI_STATUS
+FindFreeMemoryFromMemoryAllocationHob (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Granularity,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+ UINT64 Bytes;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
+
+ BaseAddress = 0;
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&
+ (Hob.MemoryAllocation->AllocDescriptor.MemoryLength >= Bytes)) {
+ //
+ // Found one memory allocation HOB with big enough free memory.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ BaseAddress = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +
+ MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;
+ //
+ // Make sure the granularity could be satisfied.
+ //
+ BaseAddress &= ~((EFI_PHYSICAL_ADDRESS) Granularity - 1);
+ if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+ break;
+ }
+ BaseAddress = 0;
+ MemoryAllocationHob = NULL;
+ }
+ //
+ // Continue to find.
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);
+ *Memory = BaseAddress;
+ return EFI_SUCCESS;
+ } else {
+ if (MergeFreeMemoryInMemoryAllocationHob ()) {
+ //
+ // Retry if there are free memory ranges merged.
+ //
+ return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
+ }
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ The purpose of the service is to publish an interface that allows
+ PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+ Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+ After InstallPeiMemory() is called, PEI will allocate pages within the region
+ of memory provided by InstallPeiMemory() service in a best-effort fashion.
+ Location-specific allocations are not managed by the PEI foundation code.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+ EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+ EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ PEI_CORE_INSTANCE *PrivateData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;
+ UINTN RemainingPages;
+ UINTN Granularity;
+ UINTN Padding;
+
+ if ((MemoryType != EfiLoaderCode) &&
+ (MemoryType != EfiLoaderData) &&
+ (MemoryType != EfiRuntimeServicesCode) &&
+ (MemoryType != EfiRuntimeServicesData) &&
+ (MemoryType != EfiBootServicesCode) &&
+ (MemoryType != EfiBootServicesData) &&
+ (MemoryType != EfiACPIReclaimMemory) &&
+ (MemoryType != EfiReservedMemoryType) &&
+ (MemoryType != EfiACPIMemoryNVS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (Hob.Raw == NULL) {
+ //
+ // HOB is not initialized yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ if (RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY &&
+ (MemoryType == EfiACPIReclaimMemory ||
+ MemoryType == EfiACPIMemoryNVS ||
+ MemoryType == EfiRuntimeServicesCode ||
+ MemoryType == EfiRuntimeServicesData)) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+
+ DEBUG ((DEBUG_INFO, "AllocatePages: aligning allocation to %d KB\n",
+ Granularity / SIZE_1KB));
+ }
+
+ if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
+ //
+ // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
+ // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
+ //
+ FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
+ FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);
+ } else {
+ FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
+ FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
+ }
+
+ //
+ // Check to see if on correct boundary for the memory type.
+ // If not aligned, make the allocation aligned.
+ //
+ Padding = *(FreeMemoryTop) & (Granularity - 1);
+ if ((UINTN) (*FreeMemoryTop - *FreeMemoryBottom) < Padding) {
+ DEBUG ((DEBUG_ERROR, "AllocatePages failed: Out of space after padding.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(FreeMemoryTop) -= Padding;
+ if (Padding >= EFI_PAGE_SIZE) {
+ //
+ // Create a memory allocation HOB to cover
+ // the pages that we will lose to rounding
+ //
+ InternalBuildMemoryAllocationHob (
+ *(FreeMemoryTop),
+ Padding & ~(UINTN)EFI_PAGE_MASK,
+ EfiConventionalMemory
+ );
+ }
+
+ //
+ // Verify that there is sufficient memory to satisfy the allocation.
+ //
+ RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;
+ //
+ // The number of remaining pages needs to be greater than or equal to that of the request pages.
+ //
+ Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));
+ if (RemainingPages < Pages) {
+ //
+ // Try to find free memory by searching memory allocation HOBs.
+ //
+ Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64) Pages));
+ DEBUG ((EFI_D_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64) RemainingPages));
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Update the PHIT to reflect the memory usage
+ //
+ *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
+
+ //
+ // Update the value for the caller
+ //
+ *Memory = *(FreeMemoryTop);
+
+ //
+ // Create a memory allocation HOB.
+ //
+ InternalBuildMemoryAllocationHob (
+ *(FreeMemoryTop),
+ Pages * EFI_PAGE_SIZE,
+ MemoryType
+ );
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
+ if MemoryBaseAddress == *FreeMemoryTop.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+ @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
+
+**/
+VOID
+FreeMemoryAllocationHob (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHobToFree
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
+ //
+ // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
+ // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.
+ //
+ FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
+ } else {
+ FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
+ }
+
+ if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {
+ //
+ // Update *FreeMemoryTop.
+ //
+ *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;
+ //
+ // Mark the memory allocation HOB to be unused(freed).
+ //
+ MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&
+ (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop)) {
+ //
+ // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
+ // MemoryBaseAddress == new *FreeMemoryTop.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+ //
+ // Free memory allocation HOB iteratively.
+ //
+ if (MemoryAllocationHob != NULL) {
+ FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
+ }
+ }
+}
+
+/**
+ Frees memory pages.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] Memory The base physical address of the pages to be freed.
+ @param[in] Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFreePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ UINT64 Bytes;
+ UINT64 Start;
+ UINT64 End;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
+
+ Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
+ Start = Memory;
+ End = Start + Bytes - 1;
+
+ if (Pages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+ Hob.Raw = PrivateData->HobList.Raw;
+
+ if (Hob.Raw == NULL) {
+ //
+ // HOB is not initialized yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ MemoryAllocationHob = NULL;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+ while (Hob.Raw != NULL) {
+ if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType != EfiConventionalMemory) &&
+ (Memory >= Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress) &&
+ ((Memory + Bytes) <= (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength))) {
+ //
+ // Found the memory allocation HOB that includes the memory pages to be freed.
+ //
+ MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+ }
+
+ if (MemoryAllocationHob != NULL) {
+ UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);
+ FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+
+ Pool allocation service. Before permanent memory is discovered, the pool will
+ be allocated in the heap in temporary memory. Generally, the size of the heap in temporary
+ memory does not exceed 64K, so the biggest pool size could be allocated is
+ 64K.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Size Amount of memory required
+ @param Buffer Address of pointer to the buffer
+
+ @retval EFI_SUCCESS The allocation was successful
+ @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
+ to allocate the requested size.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePool (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_MEMORY_POOL *Hob;
+
+ //
+ // If some "post-memory" PEIM wishes to allocate larger pool,
+ // it should use AllocatePages service instead.
+ //
+
+ //
+ // Generally, the size of heap in temporary memory does not exceed 64K,
+ // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
+ //
+ if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = PeiServicesCreateHob (
+ EFI_HOB_TYPE_MEMORY_POOL,
+ (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
+ (VOID **)&Hob
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ *Buffer = NULL;
+ } else {
+ *Buffer = Hob + 1;
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c b/roms/edk2/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c
new file mode 100644
index 000000000..3dfc59567
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PciCfg2/PciCfg2.c
@@ -0,0 +1,122 @@
+/** @file
+ The default version of EFI_PEI_PCI_CFG2_PPI support published by PeiServices in
+ PeiCore initialization phase.
+
+ EFI_PEI_PCI_CFG2_PPI is installed by the PEIM which supports a PCI root bridge.
+ When PeiCore is started, the default version of EFI_PEI_PCI_CFG2_PPI will be assigned
+ to PeiServices table.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+///
+/// This default instance of EFI_PEI_PCI_CFG2_PPI install assigned to EFI_PEI_SERVICE.PciCfg
+/// when PeiCore's initialization.
+///
+EFI_PEI_PCI_CFG2_PPI gPeiDefaultPciCfg2Ppi = {
+ PeiDefaultPciCfg2Read,
+ PeiDefaultPciCfg2Write,
+ PeiDefaultPciCfg2Modify
+};
+
+/**
+ Reads from a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Read (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Write to a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Write (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ This function performs a read-modify-write operation on the contents from a given
+ location in the PCI configuration space.
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes. Type
+ EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
+ @param Address The physical address of the access.
+ @param SetBits Points to value to bitwise-OR with the read configuration value.
+ The size of the value is determined by Width.
+ @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
+ The size of the value is determined by Width.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Modify (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *SetBits,
+ IN VOID *ClearBits
+ )
+{
+ return EFI_NOT_AVAILABLE_YET;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PeiCore.uni b/roms/edk2/MdeModulePkg/Core/Pei/PeiCore.uni
new file mode 100644
index 000000000..1ddf2b9a8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PeiCore.uni
@@ -0,0 +1,22 @@
+// /** @file
+// PeiMain module is core module in PEI phase.
+//
+// It takes responsibilities of:
+// 1) Initialize memory, PPI, image services etc, to establish PEIM runtime environment.
+// 2) Dispatch PEIM from discovered FV.
+// 3) Handoff control to DxeIpl to load DXE core and enter DXE phase.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Core module in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It takes responsibilities of:<BR>\n"
+ "1) Initializing memory, PPI, image services etc., to establish the PEIM runtime environment.<BR>\n"
+ "2) Dispatches PEIM from discovered FV.<BR>\n"
+ "3) Handsoff control to DxeIpl to load DXE core and enters DXE phase.<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PeiCoreExtra.uni b/roms/edk2/MdeModulePkg/Core/Pei/PeiCoreExtra.uni
new file mode 100644
index 000000000..b9e4f9790
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PeiCoreExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PeiCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core PEI Services Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.h b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.h
new file mode 100644
index 000000000..c27e8fc33
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.h
@@ -0,0 +1,2037 @@
+/** @file
+ Definition of Pei Core Structures and Services
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_MAIN_H_
+#define _PEI_MAIN_H_
+
+#include <PiPei.h>
+#include <Ppi/DxeIpl.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/StatusCode.h>
+#include <Ppi/Reset.h>
+#include <Ppi/Reset2.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/Decompress.h>
+#include <Ppi/GuidedSectionExtraction.h>
+#include <Ppi/LoadFile.h>
+#include <Ppi/Security2.h>
+#include <Ppi/TemporaryRamSupport.h>
+#include <Ppi/TemporaryRamDone.h>
+#include <Ppi/SecHobData.h>
+#include <Ppi/PeiCoreFvLocation.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiCoreEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Guid/AprioriFileName.h>
+#include <Guid/MigratedFvInfo.h>
+
+///
+/// It is an FFS type extension used for PeiFindFileEx. It indicates current
+/// FFS searching is for all PEIMs can be dispatched by PeiCore.
+///
+#define PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE 0xff
+
+///
+/// Pei Core private data structures
+///
+typedef union {
+ EFI_PEI_PPI_DESCRIPTOR *Ppi;
+ EFI_PEI_NOTIFY_DESCRIPTOR *Notify;
+ VOID *Raw;
+} PEI_PPI_LIST_POINTERS;
+
+///
+/// Number of PEI_PPI_LIST_POINTERS to grow by each time we run out of room
+///
+#define PPI_GROWTH_STEP 64
+#define CALLBACK_NOTIFY_GROWTH_STEP 32
+#define DISPATCH_NOTIFY_GROWTH_STEP 8
+
+typedef struct {
+ UINTN CurrentCount;
+ UINTN MaxCount;
+ UINTN LastDispatchedCount;
+ ///
+ /// MaxCount number of entries.
+ ///
+ PEI_PPI_LIST_POINTERS *PpiPtrs;
+} PEI_PPI_LIST;
+
+typedef struct {
+ UINTN CurrentCount;
+ UINTN MaxCount;
+ ///
+ /// MaxCount number of entries.
+ ///
+ PEI_PPI_LIST_POINTERS *NotifyPtrs;
+} PEI_CALLBACK_NOTIFY_LIST;
+
+typedef struct {
+ UINTN CurrentCount;
+ UINTN MaxCount;
+ UINTN LastDispatchedCount;
+ ///
+ /// MaxCount number of entries.
+ ///
+ PEI_PPI_LIST_POINTERS *NotifyPtrs;
+} PEI_DISPATCH_NOTIFY_LIST;
+
+///
+/// PPI database structure which contains three links:
+/// PpiList, CallbackNotifyList and DispatchNotifyList.
+///
+typedef struct {
+ ///
+ /// PPI List.
+ ///
+ PEI_PPI_LIST PpiList;
+ ///
+ /// Notify List at dispatch level.
+ ///
+ PEI_CALLBACK_NOTIFY_LIST CallbackNotifyList;
+ ///
+ /// Notify List at callback level.
+ ///
+ PEI_DISPATCH_NOTIFY_LIST DispatchNotifyList;
+} PEI_PPI_DATABASE;
+
+//
+// PEI_CORE_FV_HANDLE.PeimState
+// Do not change these values as there is code doing math to change states.
+// Look for Private->Fv[FvCount].PeimState[PeimCount]++;
+//
+#define PEIM_STATE_NOT_DISPATCHED 0x00
+#define PEIM_STATE_DISPATCHED 0x01
+#define PEIM_STATE_REGISTER_FOR_SHADOW 0x02
+#define PEIM_STATE_DONE 0x03
+
+//
+// Number of FV instances to grow by each time we run out of room
+//
+#define FV_GROWTH_STEP 8
+
+typedef struct {
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ EFI_PEI_FV_HANDLE FvHandle;
+ UINTN PeimCount;
+ //
+ // Pointer to the buffer with the PeimCount number of Entries.
+ //
+ UINT8 *PeimState;
+ //
+ // Pointer to the buffer with the PeimCount number of Entries.
+ //
+ EFI_PEI_FILE_HANDLE *FvFileHandles;
+ BOOLEAN ScanFv;
+ UINT32 AuthenticationStatus;
+} PEI_CORE_FV_HANDLE;
+
+typedef struct {
+ EFI_GUID FvFormat;
+ VOID *FvInfo;
+ UINT32 FvInfoSize;
+ UINT32 AuthenticationStatus;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;
+} PEI_CORE_UNKNOW_FORMAT_FV_INFO;
+
+#define CACHE_SETION_MAX_NUMBER 0x10
+typedef struct {
+ EFI_COMMON_SECTION_HEADER* Section[CACHE_SETION_MAX_NUMBER];
+ VOID* SectionData[CACHE_SETION_MAX_NUMBER];
+ UINTN SectionSize[CACHE_SETION_MAX_NUMBER];
+ UINT32 AuthenticationStatus[CACHE_SETION_MAX_NUMBER];
+ UINTN AllSectionCount;
+ UINTN SectionIndex;
+} CACHE_SECTION_DATA;
+
+#define HOLE_MAX_NUMBER 0x3
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Base;
+ UINTN Size;
+ UINTN Offset;
+ BOOLEAN OffsetPositive;
+} HOLE_MEMORY_DATA;
+
+///
+/// Forward declaration for PEI_CORE_INSTANCE
+///
+typedef struct _PEI_CORE_INSTANCE PEI_CORE_INSTANCE;
+
+
+/**
+ Function Pointer type for PeiCore function.
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. As part of its initialization
+ phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database such
+ that both the PEI Foundation and any modules can leverage the associated service
+ calls and/or code in these early PPIs
+ @param OldCoreData Pointer to old core data that is used to initialize the
+ core's data areas.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEICORE_FUNCTION_POINTER)(
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+//
+// Number of files to grow by each time we run out of room
+//
+#define TEMP_FILE_GROWTH_STEP 32
+
+#define PEI_CORE_HANDLE_SIGNATURE SIGNATURE_32('P','e','i','C')
+
+///
+/// Pei Core private data structure instance
+///
+struct _PEI_CORE_INSTANCE {
+ UINTN Signature;
+
+ ///
+ /// Point to ServiceTableShadow
+ ///
+ EFI_PEI_SERVICES *Ps;
+ PEI_PPI_DATABASE PpiData;
+
+ ///
+ /// The count of FVs which contains FFS and could be dispatched by PeiCore.
+ ///
+ UINTN FvCount;
+
+ ///
+ /// The max count of FVs which contains FFS and could be dispatched by PeiCore.
+ ///
+ UINTN MaxFvCount;
+
+ ///
+ /// Pointer to the buffer with the MaxFvCount number of entries.
+ /// Each entry is for one FV which contains FFS and could be dispatched by PeiCore.
+ ///
+ PEI_CORE_FV_HANDLE *Fv;
+
+ ///
+ /// Pointer to the buffer with the MaxUnknownFvInfoCount number of entries.
+ /// Each entry is for one FV which could not be dispatched by PeiCore.
+ ///
+ PEI_CORE_UNKNOW_FORMAT_FV_INFO *UnknownFvInfo;
+ UINTN MaxUnknownFvInfoCount;
+ UINTN UnknownFvInfoCount;
+
+ ///
+ /// Pointer to the buffer FvFileHandlers in PEI_CORE_FV_HANDLE specified by CurrentPeimFvCount.
+ ///
+ EFI_PEI_FILE_HANDLE *CurrentFvFileHandles;
+ UINTN AprioriCount;
+ UINTN CurrentPeimFvCount;
+ UINTN CurrentPeimCount;
+ EFI_PEI_FILE_HANDLE CurrentFileHandle;
+ BOOLEAN PeimNeedingDispatch;
+ BOOLEAN PeimDispatchOnThisPass;
+ BOOLEAN PeimDispatcherReenter;
+ EFI_PEI_HOB_POINTERS HobList;
+ BOOLEAN SwitchStackSignal;
+ BOOLEAN PeiMemoryInstalled;
+ VOID *CpuIo;
+ EFI_PEI_SECURITY2_PPI *PrivateSecurityPpi;
+ EFI_PEI_SERVICES ServiceTableShadow;
+ EFI_PEI_PPI_DESCRIPTOR *XipLoadFile;
+ EFI_PHYSICAL_ADDRESS PhysicalMemoryBegin;
+ UINT64 PhysicalMemoryLength;
+ EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;
+ UINTN HeapOffset;
+ BOOLEAN HeapOffsetPositive;
+ UINTN StackOffset;
+ BOOLEAN StackOffsetPositive;
+ //
+ // Information for migrating memory pages allocated in pre-memory phase.
+ //
+ HOLE_MEMORY_DATA MemoryPages;
+ PEICORE_FUNCTION_POINTER ShadowedPeiCore;
+ CACHE_SECTION_DATA CacheSection;
+ //
+ // For Loading modules at fixed address feature to cache the top address below which the
+ // Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field
+ // and Ps should not be changed since maybe user could get this top address by using the offset to Ps.
+ //
+ EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress;
+ //
+ // The field is define for Loading modules at fixed address feature to tracker the PEI code
+ // memory range usage. It is a bit mapped array in which every bit indicates the corresponding memory page
+ // available or not.
+ //
+ UINT64 *PeiCodeMemoryRangeUsageBitMap;
+ //
+ // This field points to the shadowed image read function
+ //
+ PE_COFF_LOADER_READ_FILE ShadowedImageRead;
+
+ UINTN TempPeimCount;
+
+ //
+ // Pointer to the temp buffer with the TempPeimCount number of entries.
+ //
+ EFI_PEI_FILE_HANDLE *TempFileHandles;
+ //
+ // Pointer to the temp buffer with the TempPeimCount number of entries.
+ //
+ EFI_GUID *TempFileGuid;
+
+ //
+ // Temp Memory Range is not covered by PeiTempMem and Stack.
+ // Those Memory Range will be migrated into physical memory.
+ //
+ HOLE_MEMORY_DATA HoleData[HOLE_MAX_NUMBER];
+};
+
+///
+/// Pei Core Instance Data Macros
+///
+#define PEI_CORE_INSTANCE_FROM_PS_THIS(a) \
+ CR(a, PEI_CORE_INSTANCE, Ps, PEI_CORE_HANDLE_SIGNATURE)
+
+///
+/// Union of temporarily used function pointers (to save stack space)
+///
+typedef union {
+ PEICORE_FUNCTION_POINTER PeiCore;
+ EFI_PEIM_ENTRY_POINT2 PeimEntry;
+ EFI_PEIM_NOTIFY_ENTRY_POINT PeimNotifyEntry;
+ EFI_DXE_IPL_PPI *DxeIpl;
+ EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
+ VOID *Raw;
+} PEI_CORE_TEMP_POINTERS;
+
+typedef struct {
+ CONST EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_PEI_PPI_DESCRIPTOR *PpiList;
+ VOID *Data;
+} PEI_CORE_PARAMETERS;
+
+//
+// PeiCore function
+//
+/**
+
+ The entry routine to Pei Core, invoked by PeiMain during transition
+ from SEC to PEI. After switching stack in the PEI core, it will restart
+ with the old core data.
+
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. As part of its initialization
+ phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database such
+ that both the PEI Foundation and any modules can leverage the associated service
+ calls and/or code in these early PPIs
+ @param Data Pointer to old core data that is used to initialize the
+ core's data areas.
+
+**/
+VOID
+EFIAPI
+PeiCore (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN VOID *Data
+ );
+
+//
+// Dispatcher support functions
+//
+
+/**
+
+ This is the POSTFIX version of the dependency evaluator. When a
+ PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on
+ the evaluation stack. When that entry is popped from the evaluation
+ stack, the PPI is checked if it is installed. This method allows
+ some time savings as not all PPIs must be checked for certain
+ operation types (AND, OR).
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param DependencyExpression Pointer to a dependency expression. The Grammar adheres to
+ the BNF described above and is stored in postfix notation.
+
+ @retval TRUE if it is a well-formed Grammar
+ @retval FALSE if the dependency expression overflows the evaluation stack
+ if the dependency expression underflows the evaluation stack
+ if the dependency expression is not a well-formed Grammar.
+
+**/
+BOOLEAN
+PeimDispatchReadiness (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *DependencyExpression
+ );
+
+/**
+ Migrate a PEIM from temporary RAM to permanent memory.
+
+ @param PeimFileHandle Pointer to the FFS file header of the image.
+ @param MigratedFileHandle Pointer to the FFS file header of the migrated image.
+
+ @retval EFI_SUCCESS Sucessfully migrated the PEIM to permanent memory.
+
+**/
+EFI_STATUS
+EFIAPI
+MigratePeim (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN EFI_PEI_FILE_HANDLE MigratedFileHandle
+ );
+
+/**
+ Migrate FVs out of temporary RAM before the cache is flushed.
+
+ @param Private PeiCore's private data structure
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+
+ @retval EFI_SUCCESS Succesfully migrated installed FVs from temporary RAM to permanent memory.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.
+
+**/
+EFI_STATUS
+EFIAPI
+EvacuateTempRam (
+ IN PEI_CORE_INSTANCE *Private,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ );
+
+/**
+ Conduct PEIM dispatch.
+
+ @param SecCoreData Pointer to the data structure containing SEC to PEI handoff data
+ @param PrivateData Pointer to the private data passed in from caller
+
+**/
+VOID
+PeiDispatcher (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+ Initialize the Dispatcher's data members
+
+ @param PrivateData PeiCore's private data structure
+ @param OldCoreData Old data from SecCore
+ NULL if being run in non-permanent memory mode.
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+
+**/
+VOID
+InitializeDispatcherData (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ );
+
+/**
+ This routine parses the Dependency Expression, if available, and
+ decides if the module can be executed.
+
+
+ @param Private PeiCore's private data structure
+ @param FileHandle PEIM's file handle
+ @param PeimCount The index of last dispatched PEIM.
+
+ @retval TRUE Can be dispatched
+ @retval FALSE Cannot be dispatched
+
+**/
+BOOLEAN
+DepexSatisfied (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINTN PeimCount
+ );
+
+//
+// PPI support functions
+//
+/**
+
+ Initialize PPI services.
+
+ @param PrivateData Pointer to the PEI Core data.
+ @param OldCoreData Pointer to old PEI Core data.
+ NULL if being run in non-permanent memory mode.
+
+**/
+VOID
+InitializePpiServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+
+ Migrate the Hob list from the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertPpiPointers (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+
+ Migrate Notify Pointers inside an FV from temporary memory to permanent memory.
+
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param OrgFvHandle Address of FV Handle in temporary memory.
+ @param FvHandle Address of FV Handle in permanent memory.
+ @param FvSize Size of the FV.
+
+**/
+VOID
+ConvertPpiPointersFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle,
+ IN UINTN FvSize
+ );
+
+/**
+
+ Migrate PPI Pointers of PEI_CORE from temporary memory to permanent memory.
+
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param CoreFvHandle Address of PEI_CORE FV Handle in temporary memory.
+
+**/
+VOID
+ConvertPeiCorePpiPointers (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ PEI_CORE_FV_HANDLE CoreFvHandle
+ );
+
+/**
+
+ Dumps the PPI lists to debug output.
+
+ @param PrivateData Points to PeiCore's private instance data.
+
+**/
+VOID
+DumpPpiList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+
+ Install PPI services. It is implementation of EFI_PEI_SERVICE.InstallPpi.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to PPI array that want to be installed.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ );
+
+/**
+
+ Re-Install PPI services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldPpi Pointer to the old PEI PPI Descriptors.
+ @param NewPpi Pointer to the new PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if the operation was successful
+ @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
+ if NewPpi is not valid
+ @retval EFI_NOT_FOUND if the PPI was not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
+ );
+
+/**
+
+ Locate a given named PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Guid Pointer to GUID of the PPI.
+ @param Instance Instance Number to discover.
+ @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
+ returns a pointer to the descriptor (includes flags, etc)
+ @param Ppi Pointer to reference the found PPI
+
+ @retval EFI_SUCCESS if the PPI is in the database
+ @retval EFI_NOT_FOUND if the PPI is not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLocatePpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ IN OUT VOID **Ppi
+ );
+
+/**
+
+ Install a notification for a given PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+EFIAPI
+PeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
+ );
+
+/**
+
+ Process the Notify List at dispatch level.
+
+ @param PrivateData PeiCore's private data structure.
+
+**/
+VOID
+ProcessDispatchNotifyList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+
+ Process notifications.
+
+ @param PrivateData PeiCore's private data structure
+ @param NotifyType Type of notify to fire.
+ @param InstallStartIndex Install Beginning index.
+ @param InstallStopIndex Install Ending index.
+ @param NotifyStartIndex Notify Beginning index.
+ @param NotifyStopIndex Notify Ending index.
+
+**/
+VOID
+ProcessNotify (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN NotifyType,
+ IN INTN InstallStartIndex,
+ IN INTN InstallStopIndex,
+ IN INTN NotifyStartIndex,
+ IN INTN NotifyStopIndex
+ );
+
+/**
+ Process PpiList from SEC phase.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ These PPI's will be installed and/or immediately signaled if they are notification type.
+
+**/
+VOID
+ProcessPpiListFromSec (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ );
+
+//
+// Boot mode support functions
+//
+/**
+ This service enables PEIMs to ascertain the present value of the boot mode.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode A pointer to contain the value of the boot mode.
+
+ @retval EFI_SUCCESS The boot mode was returned successfully.
+ @retval EFI_INVALID_PARAMETER BootMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT EFI_BOOT_MODE *BootMode
+ );
+
+/**
+ This service enables PEIMs to update the boot mode variable.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param BootMode The value of the boot mode to set.
+
+ @return EFI_SUCCESS The value was successfully updated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSetBootMode (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_BOOT_MODE BootMode
+ );
+
+//
+// Security support functions
+//
+/**
+
+ Initialize the security services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldCoreData Pointer to the old core data.
+ NULL if being run in non-permanent memory mode.
+
+**/
+VOID
+InitializeSecurityServices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+ Verify a Firmware volume.
+
+ @param CurrentFvAddress Pointer to the current Firmware Volume under consideration
+
+ @retval EFI_SUCCESS Firmware Volume is legal
+ @retval EFI_SECURITY_VIOLATION Firmware Volume fails integrity test
+
+**/
+EFI_STATUS
+VerifyFv (
+ IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress
+ );
+
+/**
+ Provide a callout to the security verification service.
+
+ @param PrivateData PeiCore's private data structure
+ @param VolumeHandle Handle of FV
+ @param FileHandle Handle of PEIM's FFS
+ @param AuthenticationStatus Authentication status
+
+ @retval EFI_SUCCESS Image is OK
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval EFI_NOT_FOUND If security PPI is not installed.
+**/
+EFI_STATUS
+VerifyPeim (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT32 AuthenticationStatus
+ );
+
+/**
+
+ Gets the pointer to the HOB List.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param HobList Pointer to the HOB List.
+
+ @retval EFI_SUCCESS Get the pointer of HOB List
+ @retval EFI_NOT_AVAILABLE_YET the HOB List is not yet published
+ @retval EFI_INVALID_PARAMETER HobList is NULL (in debug mode)
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetHobList (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **HobList
+ );
+
+/**
+ Add a new HOB to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Type Type of the new HOB.
+ @param Length Length of the new HOB to allocate.
+ @param Hob Pointer to the new HOB.
+
+ @return EFI_SUCCESS Success to create HOB.
+ @retval EFI_INVALID_PARAMETER if Hob is NULL
+ @retval EFI_NOT_AVAILABLE_YET if HobList is still not available.
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCreateHob (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT16 Type,
+ IN UINT16 Length,
+ IN OUT VOID **Hob
+ );
+
+/**
+
+ Builds a Handoff Information Table HOB
+
+ @param BootMode - Current Bootmode
+ @param MemoryBegin - Start Memory Address.
+ @param MemoryLength - Length of Memory.
+
+ @return EFI_SUCCESS Always success to initialize HOB.
+
+**/
+EFI_STATUS
+PeiCoreBuildHobHandoffInfoTable (
+ IN EFI_BOOT_MODE BootMode,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ );
+
+/**
+ Install SEC HOB data to the HOB List.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SecHobList Pointer to SEC HOB List.
+
+ @return EFI_SUCCESS Success to install SEC HOB data.
+ @retval EFI_OUT_OF_RESOURCES If there is no more memory to grow the Hoblist.
+
+**/
+EFI_STATUS
+PeiInstallSecHobData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_HOB_GENERIC_HEADER *SecHobList
+ );
+
+
+//
+// FFS Fw Volume support functions
+//
+/**
+ Searches for the next matching file in the firmware volume.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FvHandle Handle of firmware volume in which to search.
+ @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
+ at the beginning of the firmware volume. On exit, points the file handle of the next file
+ in the volume or NULL if there are no more files.
+
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_NOT_FOUND The header checksum was not zero.
+ @retval EFI_SUCCESS The file was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextFile (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 SearchType,
+ IN EFI_PEI_FV_HANDLE FvHandle,
+ IN OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Go through the file to search SectionType section.
+ Search within encapsulation sections (compression and GUIDed) recursively,
+ until the match section is found.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType Filter to find only section of this type.
+ @param SectionInstance Pointer to the filter to find the specific instance of section.
+ @param Section From where to search.
+ @param SectionSize The file size to search.
+ @param OutputBuffer A pointer to the discovered section, if successful.
+ NULL if section not found.
+ @param AuthenticationStatus Updated upon return to point to the authentication status for this section.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @return EFI_NOT_FOUND The match section is not found.
+ @return EFI_SUCCESS The match section is found.
+
+**/
+EFI_STATUS
+ProcessSection (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_COMMON_SECTION_HEADER *Section,
+ IN UINTN SectionSize,
+ OUT VOID **OutputBuffer,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ );
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param SectionType Filter to find only sections of this type.
+ @param FileHandle Pointer to the current file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ NULL if section not found
+
+ @retval EFI_NOT_FOUND The section was not found.
+ @retval EFI_SUCCESS The section was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData
+ );
+
+/**
+ Searches for the next matching section within the specified file.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param SectionType The value of the section type to find.
+ @param SectionInstance Section instance to find.
+ @param FileHandle Handle of the firmware file to search.
+ @param SectionData A pointer to the discovered section, if successful.
+ @param AuthenticationStatus A pointer to the authentication status for this section.
+
+ @retval EFI_SUCCESS The section was found.
+ @retval EFI_NOT_FOUND The section was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindSectionData3 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **SectionData,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Search the firmware volumes by index
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
+ Volume (BFV).
+ @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
+
+ @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
+ @retval EFI_NOT_FOUND The volume was not found.
+ @retval EFI_SUCCESS The volume was found.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindNextVolume (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
+ );
+
+//
+// Memory support functions
+//
+/**
+
+ Initialize the memory services.
+
+ @param PrivateData PeiCore's private data structure
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param OldCoreData Pointer to the PEI Core data.
+ NULL if being run in non-permanent memory mode.
+
+**/
+VOID
+InitializeMemoryServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+
+ Install the permanent memory is now available.
+ Creates HOB (PHIT and Stack).
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryBegin Start of memory address.
+ @param MemoryLength Length of memory.
+
+ @return EFI_SUCCESS Always success.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPeiMemory (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,
+ IN UINT64 MemoryLength
+ );
+
+/**
+ Migrate memory pages allocated in pre-memory phase.
+ Copy memory pages at temporary heap top to permanent heap top.
+
+ @param[in] Private Pointer to the private data passed in from caller.
+ @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
+
+**/
+VOID
+MigrateMemoryPages (
+ IN PEI_CORE_INSTANCE *Private,
+ IN BOOLEAN TemporaryRamMigrated
+ );
+
+/**
+ Removes any FV HOBs whose base address is not in PEI installed memory.
+
+ @param[in] Private Pointer to PeiCore's private data structure.
+
+**/
+VOID
+RemoveFvHobsInTemporaryMemory (
+ IN PEI_CORE_INSTANCE *Private
+ );
+
+/**
+ Migrate the base address in firmware volume allocation HOBs
+ from temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+ @param[in] OrgFvHandle Address of FV Handle in temporary memory.
+ @param[in] FvHandle Address of FV Handle in permanent memory.
+
+**/
+VOID
+ConvertFvHob (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle
+ );
+
+/**
+ Migrate MemoryBaseAddress in memory allocation HOBs
+ from the temporary memory to PEI installed memory.
+
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertMemoryAllocationHobs (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+/**
+ The purpose of the service is to publish an interface that allows
+ PEIMs to allocate memory ranges that are managed by the PEI Foundation.
+
+ Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
+ After InstallPeiMemory() is called, PEI will allocate pages within the region
+ of memory provided by InstallPeiMemory() service in a best-effort fashion.
+ Location-specific allocations are not managed by the PEI foundation code.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On output, the address is set to the base
+ of the page range that was allocated.
+
+ @retval EFI_SUCCESS The memory range was successfully allocated.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
+ EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
+ EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees memory pages.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] Memory The base physical address of the pages to be freed.
+ @param[in] Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFreePages (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ );
+
+/**
+
+ Memory allocation service on the temporary memory.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Size Amount of memory required
+ @param Buffer Address of pointer to the buffer
+
+ @retval EFI_SUCCESS The allocation was successful
+ @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
+ to allocate the requested size.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiAllocatePool (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+
+ Routine for load image file.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param PeimState The dispatch state of the input PEIM handle.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate necessary PPI
+ @retval Others Fail to load file.
+
+**/
+EFI_STATUS
+PeiLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT8 PeimState,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ );
+
+/**
+
+ Core version of the Status Code reporter
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Type of Status Code.
+ @param Value Value to output for Status Code.
+ @param Instance Instance Number of this status code.
+ @param CallerId ID of the caller of this status code.
+ @param Data Optional data associated with this status code.
+
+ @retval EFI_SUCCESS if status code is successfully reported
+ @retval EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReportStatusCode (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+/**
+
+ Core version of the Reset System
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+
+ @retval EFI_NOT_AVAILABLE_YET PPI not available yet.
+ @retval EFI_DEVICE_ERROR Did not reset system.
+ Otherwise, resets the system.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiResetSystem (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+
+**/
+VOID
+EFIAPI
+PeiResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ );
+
+/**
+
+ Initialize PeiCore FV List.
+
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
+
+**/
+VOID
+PeiInitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
+ );
+
+/**
+ Process Firmware Volume Information once FvInfoPPI install.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS if the interface could be successfully installed
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolumeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+
+ Given the input VolumeHandle, search for the next matching name file.
+
+ @param FileName File name to search.
+ @param VolumeHandle The current FV to search.
+ @param FileHandle Pointer to the file matching name in VolumeHandle.
+ NULL if file not found
+
+ @retval EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS Success to search given file
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsFindFileByName (
+ IN CONST EFI_GUID *FileName,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_PEI_FILE_HANDLE *FileHandle
+ );
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO *FileInfo
+ );
+
+/**
+ Returns information about a specific file.
+
+ @param FileHandle Handle of the file.
+ @param FileInfo Upon exit, points to the file's information.
+
+ @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
+ @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
+ @retval EFI_SUCCESS File information returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetFileInfo2 (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_FV_FILE_INFO2 *FileInfo
+ );
+
+/**
+ Returns information about the specified volume.
+
+ @param VolumeHandle Handle of the volume.
+ @param VolumeInfo Upon exit, points to the volume's information.
+
+ @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
+ @retval EFI_INVALID_PARAMETER If VolumeInfo is NULL.
+ @retval EFI_SUCCESS Volume information returned.
+**/
+EFI_STATUS
+EFIAPI
+PeiFfsGetVolumeInfo (
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ OUT EFI_FV_INFO *VolumeInfo
+ );
+
+/**
+ This routine enables a PEIM to register itself for shadow when the PEI Foundation
+ discovers permanent memory.
+
+ @param FileHandle File handle of a PEIM.
+
+ @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
+ @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
+ @retval EFI_SUCCESS Successfully to register itself.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterForShadow (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ );
+
+/**
+ Initialize image service that install PeiLoadFilePpi.
+
+ @param PrivateData Pointer to PeiCore's private data structure PEI_CORE_INSTANCE.
+ @param OldCoreData Pointer to Old PeiCore's private data.
+ If NULL, PeiCore is entered at first time, stack/heap in temporary memory.
+ If not NULL, PeiCore is entered at second time, stack/heap has been moved
+ to permanent memory.
+
+**/
+VOID
+InitializeImageServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ );
+
+/**
+ Loads and relocates a PE/COFF image in place.
+
+ @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress The base address of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated
+ @retval Others The file not be loaded and error occurred.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImageInPlace (
+ IN VOID *Pe32Data,
+ IN VOID *ImageAddress
+ );
+
+/**
+ Find the PE32 Data for an FFS file.
+
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate PE32 Data.
+
+**/
+EFI_STATUS
+PeiGetPe32Data (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **Pe32Data
+ );
+
+/**
+ The wrapper function of PeiLoadImageLoadImage().
+
+ @param This Pointer to EFI_PEI_LOAD_FILE_PPI.
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param ImageAddressArg Pointer to PE/TE image.
+ @param ImageSizeArg Size of PE/TE image.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState Pointer to attestation authentication state of image.
+
+ @return Status of PeiLoadImageLoadImage().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadImageLoadImageWrapper (
+ IN CONST EFI_PEI_LOAD_FILE_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
+ OUT UINT64 *ImageSizeArg, OPTIONAL
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ );
+
+/**
+
+ Provide a callback for when the security PPI is installed.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor The descriptor for the notification event.
+ @param Ppi Pointer to the PPI in question.
+
+ @return Always success
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Get FV image(s) from the FV type file, then install FV INFO(2) PPI, Build FV(2, 3) HOB.
+
+ @param PrivateData PeiCore's private data structure
+ @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent FV image that contain this FV image.
+ @param ParentFvFileHandle File handle of a FV type file that contain this FV image.
+
+ @retval EFI_NOT_FOUND FV image can't be found.
+ @retval EFI_SUCCESS Successfully to process it.
+ @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
+
+**/
+EFI_STATUS
+ProcessFvFile (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
+ IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
+ );
+
+/**
+ Gets a PEI_CORE_FV_HANDLE instance for the next volume according to the given index.
+
+ This routine also will install an instance of the FvInfo PPI for the FV HOB
+ as defined in the PI specification.
+
+ @param Private Pointer of PEI_CORE_INSTANCE
+ @param Instance Index of the FV to search
+
+ @return Instance of PEI_CORE_FV_HANDLE.
+**/
+PEI_CORE_FV_HANDLE *
+FindNextCoreFvHandle (
+ IN PEI_CORE_INSTANCE *Private,
+ IN UINTN Instance
+ );
+
+//
+// Default EFI_PEI_CPU_IO_PPI support for EFI_PEI_SERVICES table when PeiCore initialization.
+//
+
+/**
+ Memory-based read services.
+
+ This function is to perform the Memory Access Read service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Memory-based write services.
+
+ This function is to perform the Memory Access Write service based on installed
+ instance of the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultMemWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ IO-based read services.
+
+ This function is to perform the IO-base read service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoRead (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ IO-based write services.
+
+ This function is to perform the IO-base write service for the EFI_PEI_CPU_IO_PPI.
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ @param Address The physical address of the access.
+ @param Count The number of accesses to perform.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_YET_AVAILABLE The service has not been installed.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultIoWrite (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN EFI_PEI_CPU_IO_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ 8-bit I/O read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the I/O space.
+**/
+UINT8
+EFIAPI
+PeiDefaultIoRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 16-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 16-bit value returned from the I/O space.
+**/
+UINT16
+EFIAPI
+PeiDefaultIoRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 32-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 32-bit value returned from the I/O space.
+**/
+UINT32
+EFIAPI
+PeiDefaultIoRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ Reads an 64-bit I/O port.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return A 64-bit value returned from the I/O space.
+**/
+UINT64
+EFIAPI
+PeiDefaultIoRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 8-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ );
+
+/**
+ 16-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ );
+
+/**
+ 32-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ );
+
+/**
+ 64-bit I/O write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+**/
+VOID
+EFIAPI
+PeiDefaultIoWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ );
+
+/**
+ 8-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 8-bit value returned from the memory space.
+
+**/
+UINT8
+EFIAPI
+PeiDefaultMemRead8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 16-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 16-bit value returned from the memory space.
+
+**/
+UINT16
+EFIAPI
+PeiDefaultMemRead16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 32-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 32-bit value returned from the memory space.
+
+**/
+UINT32
+EFIAPI
+PeiDefaultMemRead32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 64-bit memory read operations.
+
+ If the EFI_PEI_CPU_IO_PPI is not installed by platform/chipset PEIM, then
+ return 0.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+
+ @return An 64-bit value returned from the memory space.
+
+**/
+UINT64
+EFIAPI
+PeiDefaultMemRead64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address
+ );
+
+/**
+ 8-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite8 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT8 Data
+ );
+
+/**
+ 16-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite16 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT16 Data
+ );
+
+/**
+ 32-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite32 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT32 Data
+ );
+
+/**
+ 64-bit memory write operations.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Address The physical address of the access.
+ @param Data The data to write.
+
+**/
+VOID
+EFIAPI
+PeiDefaultMemWrite64 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_CPU_IO_PPI *This,
+ IN UINT64 Address,
+ IN UINT64 Data
+ );
+
+extern EFI_PEI_CPU_IO_PPI gPeiDefaultCpuIoPpi;
+
+//
+// Default EFI_PEI_PCI_CFG2_PPI support for EFI_PEI_SERVICES table when PeiCore initialization.
+//
+
+/**
+ Reads from a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Read (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Write to a given location in the PCI configuration space.
+
+ If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM, then
+ return EFI_NOT_YET_AVAILABLE.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Write (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ This function performs a read-modify-write operation on the contents from a given
+ location in the PCI configuration space.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes. Type
+ EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
+ @param Address The physical address of the access.
+ @param SetBits Points to value to bitwise-OR with the read configuration value.
+ The size of the value is determined by Width.
+ @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
+ The size of the value is determined by Width.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+ @retval EFI_NOT_YET_AVAILABLE If the EFI_PEI_PCI_CFG2_PPI is not installed by platform/chipset PEIM.
+**/
+EFI_STATUS
+EFIAPI
+PeiDefaultPciCfg2Modify (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *SetBits,
+ IN VOID *ClearBits
+ );
+
+extern EFI_PEI_PCI_CFG2_PPI gPeiDefaultPciCfg2Ppi;
+
+/**
+ After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
+ be re-installed with the instance in permanent memory and all cached FvPpi pointers in
+ PrivateData->Fv[] array should be fixed up to be pointed to the one in permanent
+ memory.
+
+ @param PrivateData Pointer to PEI_CORE_INSTANCE.
+**/
+VOID
+PeiReinitializeFv (
+ IN PEI_CORE_INSTANCE *PrivateData
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.inf b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.inf
new file mode 100644
index 000000000..0cf357371
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -0,0 +1,131 @@
+## @file
+# PeiMain module is core module in PEI phase.
+#
+# It takes responsibilities of:
+# 1) Initialize memory, PPI, image services etc, to establish PEIM runtime environment.
+# 2) Dispatch PEIM from discovered FV.
+# 3) Handoff control to DxeIpl to load DXE core and enter DXE phase.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCore
+ MODULE_UNI_FILE = PeiCore.uni
+ FILE_GUID = 52C05B14-0B98-496c-BC3B-04B50211D680
+ MODULE_TYPE = PEI_CORE
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeiCore
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ StatusCode/StatusCode.c
+ Security/Security.c
+ Reset/Reset.c
+ Ppi/Ppi.c
+ PeiMain/PeiMain.c
+ Memory/MemoryServices.c
+ Image/Image.c
+ Hob/Hob.c
+ FwVol/FwVol.c
+ FwVol/FwVol.h
+ Dispatcher/Dispatcher.c
+ Dependency/Dependency.c
+ Dependency/Dependency.h
+ BootMode/BootMode.c
+ CpuIo/CpuIo.c
+ PciCfg2/PciCfg2.c
+ PeiMain.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PeCoffGetEntryPointLib
+ ReportStatusCodeLib
+ PeiServicesLib
+ PerformanceLib
+ HobLib
+ BaseLib
+ PeiCoreEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ CacheMaintenanceLib
+ PeCoffLib
+ PeiServicesTablePointerLib
+ PcdLib
+
+[Guids]
+ gPeiAprioriFileNameGuid ## SOMETIMES_CONSUMES ## File
+ ## PRODUCES ## UNDEFINED # Install PPI
+ ## CONSUMES ## UNDEFINED # Locate PPI
+ gEfiFirmwareFileSystem2Guid
+ ## PRODUCES ## UNDEFINED # Install PPI
+ ## CONSUMES ## UNDEFINED # Locate PPI
+ ## CONSUMES ## GUID # Used to compare with FV's file system GUID and get the FV's file system format
+ gEfiFirmwareFileSystem3Guid
+ gStatusCodeCallbackGuid
+ gEdkiiMigratedFvInfoGuid ## SOMETIMES_PRODUCES ## HOB
+
+[Ppis]
+ gEfiPeiStatusCodePpiGuid ## SOMETIMES_CONSUMES # PeiReportStatusService is not ready if this PPI doesn't exist
+ gEfiPeiResetPpiGuid ## SOMETIMES_CONSUMES # PeiResetService is not ready if this PPI doesn't exist
+ gEfiDxeIplPpiGuid ## CONSUMES
+ gEfiPeiMemoryDiscoveredPpiGuid ## PRODUCES
+ gEfiPeiDecompressPpiGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_PRODUCES # Produce FvInfoPpi if the encapsulated FvImage is found
+ gEfiPeiFirmwareVolumeInfoPpiGuid
+ ## NOTIFY
+ ## SOMETIMES_PRODUCES # Produce FvInfoPpi2 if the encapsulated FvImage is found
+ gEfiPeiFirmwareVolumeInfo2PpiGuid
+ ## PRODUCES
+ ## CONSUMES
+ gEfiPeiLoadFilePpiGuid
+ gEfiPeiSecurity2PpiGuid ## NOTIFY
+ gEfiTemporaryRamSupportPpiGuid ## SOMETIMES_CONSUMES
+ gEfiTemporaryRamDonePpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiReset2PpiGuid ## SOMETIMES_CONSUMES
+ gEfiSecHobDataPpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiCoreFvLocationPpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnS3Boot ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolumes ## CONSUMES
+
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+
+# [Hob]
+# PHIT ## PRODUCES
+# RESOURCE_DESCRIPTOR ## SOMETIMES_PRODUCES
+# RESOURCE_DESCRIPTOR ## SOMETIMES_CONSUMES
+# MEMORY_ALLOCATION ## SOMETIMES_CONSUMES
+# FIRMWARE_VOLUME ## SOMETIMES_PRODUCES
+# FIRMWARE_VOLUME ## SOMETIMES_CONSUMES
+# MEMORY_ALLOCATION ## SOMETIMES_PRODUCES
+# MEMORY_ALLOCATION ## PRODUCES # MEMORY_ALLOCATION_STACK
+# UNDEFINED ## PRODUCES # MEMORY_POOL
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiCoreExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
new file mode 100644
index 000000000..2ad08878d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
@@ -0,0 +1,524 @@
+/** @file
+ Pei Core Main Entry Point
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+EFI_PEI_PPI_DESCRIPTOR mMemoryDiscoveredPpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ NULL
+};
+
+///
+/// Pei service instance
+///
+EFI_PEI_SERVICES gPs = {
+ {
+ PEI_SERVICES_SIGNATURE,
+ PEI_SERVICES_REVISION,
+ sizeof (EFI_PEI_SERVICES),
+ 0,
+ 0
+ },
+ PeiInstallPpi,
+ PeiReInstallPpi,
+ PeiLocatePpi,
+ PeiNotifyPpi,
+
+ PeiGetBootMode,
+ PeiSetBootMode,
+
+ PeiGetHobList,
+ PeiCreateHob,
+
+ PeiFfsFindNextVolume,
+ PeiFfsFindNextFile,
+ PeiFfsFindSectionData,
+
+ PeiInstallPeiMemory,
+ PeiAllocatePages,
+ PeiAllocatePool,
+ (EFI_PEI_COPY_MEM)CopyMem,
+ (EFI_PEI_SET_MEM)SetMem,
+
+ PeiReportStatusCode,
+ PeiResetSystem,
+
+ &gPeiDefaultCpuIoPpi,
+ &gPeiDefaultPciCfg2Ppi,
+
+ PeiFfsFindFileByName,
+ PeiFfsGetFileInfo,
+ PeiFfsGetVolumeInfo,
+ PeiRegisterForShadow,
+ PeiFfsFindSectionData3,
+ PeiFfsGetFileInfo2,
+ PeiResetSystem2,
+ PeiFreePages,
+};
+
+/**
+ Shadow PeiCore module from flash to installed memory.
+
+ @param PrivateData PeiCore's private data structure
+
+ @return PeiCore function address after shadowing.
+**/
+PEICORE_FUNCTION_POINTER
+ShadowPeiCore (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_STATUS Status;
+ UINT32 AuthenticationState;
+ UINTN Index;
+ EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;
+ UINTN PeiCoreFvIndex;
+
+ PeiCoreFileHandle = NULL;
+ //
+ // Default PeiCore is in BFV
+ //
+ PeiCoreFvIndex = 0;
+ //
+ // Find the PEI Core either from EFI_PEI_CORE_FV_LOCATION_PPI indicated FV or BFV
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiCoreFvLocationPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PeiCoreFvLocationPpi
+ );
+ if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
+ //
+ // If PeiCoreFvLocation present, the PEI Core should be found from indicated FV
+ //
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {
+ if (PrivateData->Fv[Index].FvHandle == PeiCoreFvLocationPpi->PeiCoreFvLocation) {
+ PeiCoreFvIndex = Index;
+ break;
+ }
+ }
+ ASSERT (Index < PrivateData->FvCount);
+ }
+ //
+ // Find PEI Core from the given FV index
+ //
+ Status = PrivateData->Fv[PeiCoreFvIndex].FvPpi->FindFileByType (
+ PrivateData->Fv[PeiCoreFvIndex].FvPpi,
+ EFI_FV_FILETYPE_PEI_CORE,
+ PrivateData->Fv[PeiCoreFvIndex].FvHandle,
+ &PeiCoreFileHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Shadow PEI Core into memory so it will run faster
+ //
+ Status = PeiLoadImage (
+ GetPeiServicesTablePointer (),
+ *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle),
+ PEIM_STATE_REGISTER_FOR_SHADOW,
+ &EntryPoint,
+ &AuthenticationState
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Compute the PeiCore's function address after shadowed PeiCore.
+ // _ModuleEntryPoint is PeiCore main function entry
+ //
+ return (PEICORE_FUNCTION_POINTER)((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);
+}
+
+/**
+ This routine is invoked by main entry of PeiMain module during transition
+ from SEC to PEI. After switching stack in the PEI core, it will restart
+ with the old core data.
+
+ @param SecCoreDataPtr Points to a data structure containing information about the PEI core's operating
+ environment, such as the size and location of temporary RAM, the stack location and
+ the BFV location.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ An empty PPI list consists of a single descriptor with the end-tag
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. As part of its initialization
+ phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database such
+ that both the PEI Foundation and any modules can leverage the associated service
+ calls and/or code in these early PPIs
+ @param Data Pointer to old core data that is used to initialize the
+ core's data areas.
+ If NULL, it is first PeiCore entering.
+
+**/
+VOID
+EFIAPI
+PeiCore (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreDataPtr,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN VOID *Data
+ )
+{
+ PEI_CORE_INSTANCE PrivateData;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_SEC_PEI_HAND_OFF NewSecCoreData;
+ EFI_STATUS Status;
+ PEI_CORE_TEMP_POINTERS TempPtr;
+ PEI_CORE_INSTANCE *OldCoreData;
+ EFI_PEI_CPU_IO_PPI *CpuIo;
+ EFI_PEI_PCI_CFG2_PPI *PciCfg;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
+ EFI_PEI_TEMPORARY_RAM_DONE_PPI *TemporaryRamDonePpi;
+ UINTN Index;
+
+ //
+ // Retrieve context passed into PEI Core
+ //
+ OldCoreData = (PEI_CORE_INSTANCE *) Data;
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *) SecCoreDataPtr;
+
+ //
+ // Perform PEI Core phase specific actions.
+ //
+ if (OldCoreData == NULL) {
+ //
+ // If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
+ //
+ ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
+ PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
+ CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
+ } else {
+ //
+ // Memory is available to the PEI Core. See if the PEI Core has been shadowed to memory yet.
+ //
+ if (OldCoreData->ShadowedPeiCore == NULL) {
+ //
+ // Fixup the PeiCore's private data
+ //
+ OldCoreData->Ps = &OldCoreData->ServiceTableShadow;
+ OldCoreData->CpuIo = &OldCoreData->ServiceTableShadow.CpuIo;
+ if (OldCoreData->HeapOffsetPositive) {
+ OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw + OldCoreData->HeapOffset);
+ if (OldCoreData->UnknownFvInfo != NULL) {
+ OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo + OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->CurrentFvFileHandles != NULL) {
+ OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles + OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
+ OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiList.PpiPtrs + OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
+ OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
+ OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
+ }
+ OldCoreData->Fv = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv + OldCoreData->HeapOffset);
+ for (Index = 0; Index < OldCoreData->FvCount; Index ++) {
+ if (OldCoreData->Fv[Index].PeimState != NULL) {
+ OldCoreData->Fv[Index].PeimState = (UINT8 *) OldCoreData->Fv[Index].PeimState + OldCoreData->HeapOffset;
+ }
+ if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
+ OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles + OldCoreData->HeapOffset);
+ }
+ }
+ OldCoreData->TempFileGuid = (EFI_GUID *) ((UINT8 *) OldCoreData->TempFileGuid + OldCoreData->HeapOffset);
+ OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->TempFileHandles + OldCoreData->HeapOffset);
+ } else {
+ OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw - OldCoreData->HeapOffset);
+ if (OldCoreData->UnknownFvInfo != NULL) {
+ OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo - OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->CurrentFvFileHandles != NULL) {
+ OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles - OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
+ OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiList.PpiPtrs - OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
+ OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
+ }
+ if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
+ OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
+ }
+ OldCoreData->Fv = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv - OldCoreData->HeapOffset);
+ for (Index = 0; Index < OldCoreData->FvCount; Index ++) {
+ if (OldCoreData->Fv[Index].PeimState != NULL) {
+ OldCoreData->Fv[Index].PeimState = (UINT8 *) OldCoreData->Fv[Index].PeimState - OldCoreData->HeapOffset;
+ }
+ if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
+ OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles - OldCoreData->HeapOffset);
+ }
+ }
+ OldCoreData->TempFileGuid = (EFI_GUID *) ((UINT8 *) OldCoreData->TempFileGuid - OldCoreData->HeapOffset);
+ OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
+ }
+
+ //
+ // Fixup for PeiService's address
+ //
+ SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
+
+ //
+ // Update HandOffHob for new installed permanent memory
+ //
+ HandoffInformationTable = OldCoreData->HobList.HandoffInformationTable;
+ if (OldCoreData->HeapOffsetPositive) {
+ HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList + OldCoreData->HeapOffset;
+ } else {
+ HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList - OldCoreData->HeapOffset;
+ }
+ HandoffInformationTable->EfiMemoryTop = OldCoreData->PhysicalMemoryBegin + OldCoreData->PhysicalMemoryLength;
+ HandoffInformationTable->EfiMemoryBottom = OldCoreData->PhysicalMemoryBegin;
+ HandoffInformationTable->EfiFreeMemoryTop = OldCoreData->FreePhysicalMemoryTop;
+ HandoffInformationTable->EfiFreeMemoryBottom = HandoffInformationTable->EfiEndOfHobList + sizeof (EFI_HOB_GENERIC_HEADER);
+
+ //
+ // We need convert MemoryBaseAddress in memory allocation HOBs
+ //
+ ConvertMemoryAllocationHobs (OldCoreData);
+
+ //
+ // We need convert the PPI descriptor's pointer
+ //
+ ConvertPpiPointers (SecCoreData, OldCoreData);
+
+ //
+ // After the whole temporary memory is migrated, then we can allocate page in
+ // permanent memory.
+ //
+ OldCoreData->PeiMemoryInstalled = TRUE;
+
+ //
+ // Indicate that PeiCore reenter
+ //
+ OldCoreData->PeimDispatcherReenter = TRUE;
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (OldCoreData->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ //
+ // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.
+ // Every bit in the array indicate the status of the corresponding memory page available or not
+ //
+ OldCoreData->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32(PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof(UINT64));
+ }
+
+ //
+ // Shadow PEI Core. When permanent memory is available, shadow
+ // PEI Core and PEIMs to get high performance.
+ //
+ OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER) (UINTN) PeiCore;
+ if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnS3Boot)) ||
+ (HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnBoot))) {
+ OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
+ }
+
+ //
+ // PEI Core has now been shadowed to memory. Restart PEI Core in memory.
+ //
+ OldCoreData->ShadowedPeiCore (SecCoreData, PpiList, OldCoreData);
+
+ //
+ // Should never reach here.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop();
+
+ UNREACHABLE ();
+ }
+
+ //
+ // Memory is available to the PEI Core and the PEI Core has been shadowed to memory.
+ //
+ CopyMem (&NewSecCoreData, SecCoreDataPtr, sizeof (NewSecCoreData));
+ SecCoreData = &NewSecCoreData;
+
+ CopyMem (&PrivateData, OldCoreData, sizeof (PrivateData));
+
+ CpuIo = (VOID*)PrivateData.ServiceTableShadow.CpuIo;
+ PciCfg = (VOID*)PrivateData.ServiceTableShadow.PciCfg;
+
+ CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
+
+ PrivateData.ServiceTableShadow.CpuIo = CpuIo;
+ PrivateData.ServiceTableShadow.PciCfg = PciCfg;
+ }
+
+ //
+ // Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
+ //
+ PrivateData.Ps = &PrivateData.ServiceTableShadow;
+
+ //
+ // Save PeiServicePointer so that it can be retrieved anywhere.
+ //
+ SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
+
+ //
+ // Initialize libraries that the PEI Core is linked against
+ //
+ ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
+
+ //
+ // Initialize PEI Core Services
+ //
+ InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
+
+ //
+ // Update performance measurements
+ //
+ if (OldCoreData == NULL) {
+ PERF_EVENT ("SEC"); // Means the end of SEC phase.
+
+ //
+ // If first pass, start performance measurement.
+ //
+ PERF_CROSSMODULE_BEGIN ("PEI");
+ PERF_INMODULE_BEGIN ("PreMem");
+
+ } else {
+ PERF_INMODULE_END ("PreMem");
+ PERF_INMODULE_BEGIN ("PostMem");
+ }
+
+ //
+ // Complete PEI Core Service initialization
+ //
+ InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
+ InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);
+ InitializeImageServices (&PrivateData, OldCoreData);
+
+ //
+ // Perform PEI Core Phase specific actions
+ //
+ if (OldCoreData == NULL) {
+ //
+ // Report Status Code EFI_SW_PC_INIT
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
+ );
+
+ //
+ // If SEC provided the PpiList, process it.
+ //
+ if (PpiList != NULL) {
+ ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **) &PrivateData.Ps, PpiList);
+ }
+ } else {
+ if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
+ //
+ // When PcdMigrateTemporaryRamFirmwareVolumes is TRUE, alway shadow all
+ // PEIMs no matter the condition of PcdShadowPeimOnBoot and PcdShadowPeimOnS3Boot
+ //
+ DEBUG ((DEBUG_VERBOSE, "PPI lists before temporary RAM evacuation:\n"));
+ DumpPpiList (&PrivateData);
+
+ //
+ // Migrate installed content from Temporary RAM to Permanent RAM
+ //
+ EvacuateTempRam (&PrivateData, SecCoreData);
+
+ DEBUG ((DEBUG_VERBOSE, "PPI lists after temporary RAM evacuation:\n"));
+ DumpPpiList (&PrivateData);
+ }
+
+ //
+ // Try to locate Temporary RAM Done Ppi.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiTemporaryRamDonePpiGuid,
+ 0,
+ NULL,
+ (VOID**)&TemporaryRamDonePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Disable the use of Temporary RAM after the transition from Temporary RAM to Permanent RAM is complete.
+ //
+ TemporaryRamDonePpi->TemporaryRamDone ();
+ }
+
+ //
+ // Alert any listeners that there is permanent memory available
+ //
+ PERF_INMODULE_BEGIN ("DisMem");
+ Status = PeiServicesInstallPpi (&mMemoryDiscoveredPpi);
+
+ //
+ // Process the Notify list and dispatch any notifies for the Memory Discovered PPI
+ //
+ ProcessDispatchNotifyList (&PrivateData);
+
+ PERF_INMODULE_END ("DisMem");
+ }
+
+ //
+ // Call PEIM dispatcher
+ //
+ PeiDispatcher (SecCoreData, &PrivateData);
+
+ if (PrivateData.HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) {
+ //
+ // Check if InstallPeiMemory service was called on non-S3 resume boot path.
+ //
+ ASSERT(PrivateData.PeiMemoryInstalled == TRUE);
+ }
+
+ //
+ // Measure PEI Core execution time.
+ //
+ PERF_INMODULE_END ("PostMem");
+
+ //
+ // Lookup DXE IPL PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiDxeIplPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&TempPtr.DxeIpl
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Report status code to indicate DXE IPL PPI could not be found.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND)
+ );
+ CpuDeadLoop ();
+ }
+
+ //
+ // Enter DxeIpl to load Dxe core.
+ //
+ DEBUG ((EFI_D_INFO, "DXE IPL Entry\n"));
+ Status = TempPtr.DxeIpl->Entry (
+ TempPtr.DxeIpl,
+ &PrivateData.Ps,
+ PrivateData.HobList
+ );
+ //
+ // Should never reach here.
+ //
+ ASSERT_EFI_ERROR (Status);
+ CpuDeadLoop();
+
+ UNREACHABLE ();
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Ppi/Ppi.c b/roms/edk2/MdeModulePkg/Core/Pei/Ppi/Ppi.c
new file mode 100644
index 000000000..541047d98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Ppi/Ppi.c
@@ -0,0 +1,1118 @@
+/** @file
+ EFI PEI Core PPI services
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Migrate Pointer from the temporary memory to PEI installed memory.
+
+ @param Pointer Pointer to the Pointer needs to be converted.
+ @param TempBottom Base of old temporary memory
+ @param TempTop Top of old temporary memory
+ @param Offset Offset of new memory to old temporary memory.
+ @param OffsetPositive Positive flag of Offset value.
+
+**/
+VOID
+ConvertPointer (
+ IN OUT VOID **Pointer,
+ IN UINTN TempBottom,
+ IN UINTN TempTop,
+ IN UINTN Offset,
+ IN BOOLEAN OffsetPositive
+ )
+{
+ if (((UINTN) *Pointer < TempTop) &&
+ ((UINTN) *Pointer >= TempBottom)) {
+ if (OffsetPositive) {
+ *Pointer = (VOID *) ((UINTN) *Pointer + Offset);
+ } else {
+ *Pointer = (VOID *) ((UINTN) *Pointer - Offset);
+ }
+ }
+}
+
+/**
+
+ Migrate Pointer in ranges of the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param Pointer Pointer to the Pointer needs to be converted.
+
+**/
+VOID
+ConvertPointerInRanges (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN OUT VOID **Pointer
+ )
+{
+ UINT8 IndexHole;
+
+ if (PrivateData->MemoryPages.Size != 0) {
+ //
+ // Convert PPI pointer in old memory pages
+ // It needs to be done before Convert PPI pointer in old Heap
+ //
+ ConvertPointer (
+ Pointer,
+ (UINTN)PrivateData->MemoryPages.Base,
+ (UINTN)PrivateData->MemoryPages.Base + PrivateData->MemoryPages.Size,
+ PrivateData->MemoryPages.Offset,
+ PrivateData->MemoryPages.OffsetPositive
+ );
+ }
+
+ //
+ // Convert PPI pointer in old Heap
+ //
+ ConvertPointer (
+ Pointer,
+ (UINTN)SecCoreData->PeiTemporaryRamBase,
+ (UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
+ PrivateData->HeapOffset,
+ PrivateData->HeapOffsetPositive
+ );
+
+ //
+ // Convert PPI pointer in old Stack
+ //
+ ConvertPointer (
+ Pointer,
+ (UINTN)SecCoreData->StackBase,
+ (UINTN)SecCoreData->StackBase + SecCoreData->StackSize,
+ PrivateData->StackOffset,
+ PrivateData->StackOffsetPositive
+ );
+
+ //
+ // Convert PPI pointer in old TempRam Hole
+ //
+ for (IndexHole = 0; IndexHole < HOLE_MAX_NUMBER; IndexHole ++) {
+ if (PrivateData->HoleData[IndexHole].Size == 0) {
+ continue;
+ }
+
+ ConvertPointer (
+ Pointer,
+ (UINTN)PrivateData->HoleData[IndexHole].Base,
+ (UINTN)PrivateData->HoleData[IndexHole].Base + PrivateData->HoleData[IndexHole].Size,
+ PrivateData->HoleData[IndexHole].Offset,
+ PrivateData->HoleData[IndexHole].OffsetPositive
+ );
+ }
+}
+
+/**
+
+ Migrate Single PPI Pointer from the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param PpiPointer Pointer to Ppi
+
+**/
+VOID
+ConvertSinglePpiPointer (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_PPI_LIST_POINTERS *PpiPointer
+ )
+{
+ //
+ // 1. Convert the pointer to the PPI descriptor from the old TempRam
+ // to the relocated physical memory.
+ // It (for the pointer to the PPI descriptor) needs to be done before 2 (for
+ // the pointer to the GUID) and 3 (for the pointer to the PPI interface structure).
+ //
+ ConvertPointerInRanges (SecCoreData, PrivateData, &PpiPointer->Raw);
+ //
+ // 2. Convert the pointer to the GUID in the PPI or NOTIFY descriptor
+ // from the old TempRam to the relocated physical memory.
+ //
+ ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **) &PpiPointer->Ppi->Guid);
+ //
+ // 3. Convert the pointer to the PPI interface structure in the PPI descriptor
+ // from the old TempRam to the relocated physical memory.
+ //
+ ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **) &PpiPointer->Ppi->Ppi);
+}
+
+/**
+
+ Migrate PPI Pointers from the temporary memory to PEI installed memory.
+
+ @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
+ and location of temporary RAM, the stack location and the BFV location.
+ @param PrivateData Pointer to PeiCore's private data structure.
+
+**/
+VOID
+ConvertPpiPointers (
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ UINT8 Index;
+
+ //
+ // Convert normal PPIs.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
+ ConvertSinglePpiPointer (
+ SecCoreData,
+ PrivateData,
+ &PrivateData->PpiData.PpiList.PpiPtrs[Index]
+ );
+ }
+
+ //
+ // Convert Callback Notification PPIs.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
+ ConvertSinglePpiPointer (
+ SecCoreData,
+ PrivateData,
+ &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index]
+ );
+ }
+
+ //
+ // Convert Dispatch Notification PPIs.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
+ ConvertSinglePpiPointer (
+ SecCoreData,
+ PrivateData,
+ &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index]
+ );
+ }
+}
+
+/**
+
+ Migrate Notify Pointers inside an FV from temporary memory to permanent memory.
+
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param OrgFvHandle Address of FV Handle in temporary memory.
+ @param FvHandle Address of FV Handle in permanent memory.
+ @param FvSize Size of the FV.
+
+**/
+VOID
+ConvertPpiPointersFv (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN OrgFvHandle,
+ IN UINTN FvHandle,
+ IN UINTN FvSize
+ )
+{
+ UINT8 Index;
+ UINTN Offset;
+ BOOLEAN OffsetPositive;
+ EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
+ UINT8 GuidIndex;
+ EFI_GUID *Guid;
+ EFI_GUID *GuidCheckList[2];
+
+ GuidCheckList[0] = &gEfiPeiFirmwareVolumeInfoPpiGuid;
+ GuidCheckList[1] = &gEfiPeiFirmwareVolumeInfo2PpiGuid;
+
+ if (FvHandle > OrgFvHandle) {
+ OffsetPositive = TRUE;
+ Offset = FvHandle - OrgFvHandle;
+ } else {
+ OffsetPositive = FALSE;
+ Offset = OrgFvHandle - FvHandle;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Converting PPI pointers in FV.\n"));
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " OrgFvHandle at 0x%08x. FvHandle at 0x%08x. FvSize = 0x%x\n",
+ (UINTN) OrgFvHandle,
+ (UINTN) FvHandle,
+ FvSize
+ ));
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " OrgFvHandle range: 0x%08x - 0x%08x\n",
+ OrgFvHandle,
+ OrgFvHandle + FvSize
+ ));
+
+ for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Notify,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ }
+
+ for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Notify,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ }
+
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ ConvertPointer (
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+
+ Guid = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid;
+ for (GuidIndex = 0; GuidIndex < ARRAY_SIZE (GuidCheckList); ++GuidIndex) {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID as INT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)Guid)[0] == ((INT32 *)GuidCheckList[GuidIndex])[0]) &&
+ (((INT32 *)Guid)[1] == ((INT32 *)GuidCheckList[GuidIndex])[1]) &&
+ (((INT32 *)Guid)[2] == ((INT32 *)GuidCheckList[GuidIndex])[2]) &&
+ (((INT32 *)Guid)[3] == ((INT32 *)GuidCheckList[GuidIndex])[3])) {
+ FvInfoPpi = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi;
+ DEBUG ((DEBUG_VERBOSE, " FvInfo: %p -> ", FvInfoPpi->FvInfo));
+ if ((UINTN)FvInfoPpi->FvInfo == OrgFvHandle) {
+ ConvertPointer (
+ (VOID **)&FvInfoPpi->FvInfo,
+ OrgFvHandle,
+ OrgFvHandle + FvSize,
+ Offset,
+ OffsetPositive
+ );
+ DEBUG ((DEBUG_VERBOSE, "%p", FvInfoPpi->FvInfo));
+ }
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+ break;
+ }
+ }
+ }
+}
+
+/**
+
+ Dumps the PPI lists to debug output.
+
+ @param PrivateData Points to PeiCore's private instance data.
+
+**/
+VOID
+DumpPpiList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ UINTN Index;
+
+ if (PrivateData == NULL) {
+ return;
+ }
+
+ for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "CallbackNotify[%2d] {%g} at 0x%x (%a)\n",
+ Index,
+ PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
+ (UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
+ (
+ !(
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
+ )
+ ? "CAR" : "Post-Memory"
+ )
+ ));
+ }
+ for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE,
+ "DispatchNotify[%2d] {%g} at 0x%x (%a)\n",
+ Index,
+ PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
+ (UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
+ (
+ !(
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw >=PrivateData->PhysicalMemoryBegin) &&
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
+ )
+ ? "CAR" : "Post-Memory"
+ )
+ ));
+ }
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE,
+ "PPI[%2d] {%g} at 0x%x (%a)\n",
+ Index,
+ PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
+ (UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
+ (
+ !(
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw) + sizeof (EFI_PEI_PPI_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
+ )
+ ? "CAR" : "Post-Memory"
+ )
+ ));
+ }
+ DEBUG_CODE_END ();
+}
+
+/**
+
+ This function installs an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties
+ can use to call additional PEIMs.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to a list of PEI PPI Descriptors.
+ @param Single TRUE if only single entry in the PpiList.
+ FALSE if the PpiList is ended with an entry which has the
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+InternalPeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
+ IN BOOLEAN Single
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ PEI_PPI_LIST *PpiListPointer;
+ UINTN Index;
+ UINTN LastCount;
+ VOID *TempPtr;
+
+ if (PpiList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ PpiListPointer = &PrivateData->PpiData.PpiList;
+ Index = PpiListPointer->CurrentCount;
+ LastCount = Index;
+
+ //
+ // This is loop installs all PPI descriptors in the PpiList. It is terminated
+ // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
+ // EFI_PEI_PPI_DESCRIPTOR in the list.
+ //
+
+ for (;;) {
+ //
+ // Check if it is a valid PPI.
+ // If not, rollback list to exclude all in this list.
+ // Try to indicate which item failed.
+ //
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
+ PpiListPointer->CurrentCount = LastCount;
+ DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Index >= PpiListPointer->MaxCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_PPI_LIST_POINTERS) * (PpiListPointer->MaxCount + PPI_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ PpiListPointer->PpiPtrs,
+ sizeof (PEI_PPI_LIST_POINTERS) * PpiListPointer->MaxCount
+ );
+ PpiListPointer->PpiPtrs = TempPtr;
+ PpiListPointer->MaxCount = PpiListPointer->MaxCount + PPI_GROWTH_STEP;
+ }
+
+ DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
+ PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) PpiList;
+ Index++;
+ PpiListPointer->CurrentCount++;
+
+ if (Single) {
+ //
+ // Only single entry in the PpiList.
+ //
+ break;
+ } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the PPI List.
+ //
+ break;
+ }
+ //
+ // Go to the next descriptor.
+ //
+ PpiList++;
+ }
+
+ //
+ // Process any callback level notifies for newly installed PPIs.
+ //
+ ProcessNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ LastCount,
+ PpiListPointer->CurrentCount,
+ 0,
+ PrivateData->PpiData.CallbackNotifyList.CurrentCount
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function installs an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties
+ can use to call additional PEIMs.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Pointer to a list of PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
+ @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
+ if any PPI in PpiList is not valid
+ @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PeiInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ )
+{
+ return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
+}
+
+/**
+
+ This function reinstalls an interface in the PEI PPI database by GUID.
+ The purpose of the service is to publish an interface that other parties can
+ use to replace an interface of the same name in the protocol database with a
+ different interface.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldPpi Pointer to the old PEI PPI Descriptors.
+ @param NewPpi Pointer to the new PEI PPI Descriptors.
+
+ @retval EFI_SUCCESS if the operation was successful
+ @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
+ @retval EFI_INVALID_PARAMETER if NewPpi is not valid
+ @retval EFI_NOT_FOUND if the PPI was not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReInstallPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ UINTN Index;
+
+
+ if ((OldPpi == NULL) || (NewPpi == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ //
+ // Find the old PPI instance in the database. If we can not find it,
+ // return the EFI_NOT_FOUND error.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
+ if (OldPpi == PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi) {
+ break;
+ }
+ }
+ if (Index == PrivateData->PpiData.PpiList.CurrentCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Replace the old PPI with the new one.
+ //
+ DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
+ PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) NewPpi;
+
+ //
+ // Process any callback level notifies for the newly installed PPI.
+ //
+ ProcessNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ Index,
+ Index+1,
+ 0,
+ PrivateData->PpiData.CallbackNotifyList.CurrentCount
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Locate a given named PPI.
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param Guid Pointer to GUID of the PPI.
+ @param Instance Instance Number to discover.
+ @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
+ returns a pointer to the descriptor (includes flags, etc)
+ @param Ppi Pointer to reference the found PPI
+
+ @retval EFI_SUCCESS if the PPI is in the database
+ @retval EFI_NOT_FOUND if the PPI is not in the database
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLocatePpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ IN OUT VOID **Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ UINTN Index;
+ EFI_GUID *CheckGuid;
+ EFI_PEI_PPI_DESCRIPTOR *TempPtr;
+
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ //
+ // Search the data base for the matching instance of the GUIDed PPI.
+ //
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
+ TempPtr = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
+ CheckGuid = TempPtr->Guid;
+
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID as INT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
+ (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
+ (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
+ (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3])) {
+ if (Instance == 0) {
+
+ if (PpiDescriptor != NULL) {
+ *PpiDescriptor = TempPtr;
+ }
+
+ if (Ppi != NULL) {
+ *Ppi = TempPtr->Ppi;
+ }
+
+
+ return EFI_SUCCESS;
+ }
+ Instance--;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ This function installs a notification service to be called back when a given
+ interface is installed or reinstalled. The purpose of the service is to publish
+ an interface that other parties can use to call additional PPIs that may materialize later.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+ @param Single TRUE if only single entry in the NotifyList.
+ FALSE if the NotifyList is ended with an entry which has the
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+InternalPeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
+ IN BOOLEAN Single
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ PEI_CALLBACK_NOTIFY_LIST *CallbackNotifyListPointer;
+ UINTN CallbackNotifyIndex;
+ UINTN LastCallbackNotifyCount;
+ PEI_DISPATCH_NOTIFY_LIST *DispatchNotifyListPointer;
+ UINTN DispatchNotifyIndex;
+ UINTN LastDispatchNotifyCount;
+ VOID *TempPtr;
+
+ if (NotifyList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
+ CallbackNotifyIndex = CallbackNotifyListPointer->CurrentCount;
+ LastCallbackNotifyCount = CallbackNotifyIndex;
+
+ DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
+ DispatchNotifyIndex = DispatchNotifyListPointer->CurrentCount;
+ LastDispatchNotifyCount = DispatchNotifyIndex;
+
+ //
+ // This is loop installs all Notify descriptors in the NotifyList. It is
+ // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
+ // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
+ //
+
+ for (;;) {
+ //
+ // If some of the PPI data is invalid restore original Notify PPI database value
+ //
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
+ CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
+ DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
+ DEBUG((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
+ if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_PPI_LIST_POINTERS) * (CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ CallbackNotifyListPointer->NotifyPtrs,
+ sizeof (PEI_PPI_LIST_POINTERS) * CallbackNotifyListPointer->MaxCount
+ );
+ CallbackNotifyListPointer->NotifyPtrs = TempPtr;
+ CallbackNotifyListPointer->MaxCount = CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP;
+ }
+ CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
+ CallbackNotifyIndex++;
+ CallbackNotifyListPointer->CurrentCount++;
+ } else {
+ if (DispatchNotifyIndex >= DispatchNotifyListPointer->MaxCount) {
+ //
+ // Run out of room, grow the buffer.
+ //
+ TempPtr = AllocateZeroPool (
+ sizeof (PEI_PPI_LIST_POINTERS) * (DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP)
+ );
+ ASSERT (TempPtr != NULL);
+ CopyMem (
+ TempPtr,
+ DispatchNotifyListPointer->NotifyPtrs,
+ sizeof (PEI_PPI_LIST_POINTERS) * DispatchNotifyListPointer->MaxCount
+ );
+ DispatchNotifyListPointer->NotifyPtrs = TempPtr;
+ DispatchNotifyListPointer->MaxCount = DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP;
+ }
+ DispatchNotifyListPointer->NotifyPtrs[DispatchNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
+ DispatchNotifyIndex++;
+ DispatchNotifyListPointer->CurrentCount++;
+ }
+
+ DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
+
+ if (Single) {
+ //
+ // Only single entry in the NotifyList.
+ //
+ break;
+ } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the Notify List.
+ //
+ break;
+ }
+ //
+ // Go to the next descriptor.
+ //
+ NotifyList++;
+ }
+
+ //
+ // Process any callback level notifies for all previously installed PPIs.
+ //
+ ProcessNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ 0,
+ PrivateData->PpiData.PpiList.CurrentCount,
+ LastCallbackNotifyCount,
+ CallbackNotifyListPointer->CurrentCount
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function installs a notification service to be called back when a given
+ interface is installed or reinstalled. The purpose of the service is to publish
+ an interface that other parties can use to call additional PPIs that may materialize later.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyList Pointer to list of Descriptors to notify upon.
+
+ @retval EFI_SUCCESS if successful
+ @retval EFI_OUT_OF_RESOURCES if no space in the database
+ @retval EFI_INVALID_PARAMETER if not a good descriptor
+
+**/
+EFI_STATUS
+EFIAPI
+PeiNotifyPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
+ )
+{
+ return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
+}
+
+/**
+
+ Process the Notify List at dispatch level.
+
+ @param PrivateData PeiCore's private data structure.
+
+**/
+VOID
+ProcessDispatchNotifyList (
+ IN PEI_CORE_INSTANCE *PrivateData
+ )
+{
+ UINTN TempValue;
+
+ while (TRUE) {
+ //
+ // Check if the PEIM that was just dispatched resulted in any
+ // Notifies getting installed. If so, go process any dispatch
+ // level Notifies that match the previously installed PPIs.
+ // Use "while" instead of "if" since ProcessNotify can modify
+ // DispatchNotifyList.CurrentCount (with NotifyPpi) so we have
+ // to iterate until the same.
+ //
+ while (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount != PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
+ TempValue = PrivateData->PpiData.DispatchNotifyList.CurrentCount;
+ ProcessNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ 0,
+ PrivateData->PpiData.PpiList.LastDispatchedCount,
+ PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount,
+ PrivateData->PpiData.DispatchNotifyList.CurrentCount
+ );
+ PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount = TempValue;
+ }
+
+ //
+ // Check if the PEIM that was just dispatched resulted in any
+ // PPIs getting installed. If so, go process any dispatch
+ // level Notifies that match the installed PPIs.
+ // Use "while" instead of "if" since ProcessNotify can modify
+ // PpiList.CurrentCount (with InstallPpi) so we have to iterate
+ // until the same.
+ //
+ while (PrivateData->PpiData.PpiList.LastDispatchedCount != PrivateData->PpiData.PpiList.CurrentCount) {
+ TempValue = PrivateData->PpiData.PpiList.CurrentCount;
+ ProcessNotify (
+ PrivateData,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ PrivateData->PpiData.PpiList.LastDispatchedCount,
+ PrivateData->PpiData.PpiList.CurrentCount,
+ 0,
+ PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount
+ );
+ PrivateData->PpiData.PpiList.LastDispatchedCount = TempValue;
+ }
+
+ if (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount == PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
+ break;
+ }
+ }
+ return;
+}
+
+/**
+
+ Process notifications.
+
+ @param PrivateData PeiCore's private data structure
+ @param NotifyType Type of notify to fire.
+ @param InstallStartIndex Install Beginning index.
+ @param InstallStopIndex Install Ending index.
+ @param NotifyStartIndex Notify Beginning index.
+ @param NotifyStopIndex Notify Ending index.
+
+**/
+VOID
+ProcessNotify (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN UINTN NotifyType,
+ IN INTN InstallStartIndex,
+ IN INTN InstallStopIndex,
+ IN INTN NotifyStartIndex,
+ IN INTN NotifyStopIndex
+ )
+{
+ INTN Index1;
+ INTN Index2;
+ EFI_GUID *SearchGuid;
+ EFI_GUID *CheckGuid;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
+
+ for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
+ if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
+ NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
+ } else {
+ NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
+ }
+
+ CheckGuid = NotifyDescriptor->Guid;
+
+ for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
+ SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi->Guid;
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID as INT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
+ (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
+ (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
+ (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3])) {
+ DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
+ SearchGuid,
+ NotifyDescriptor->Notify
+ ));
+ NotifyDescriptor->Notify (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ NotifyDescriptor,
+ (PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
+ );
+ }
+ }
+ }
+}
+
+/**
+ Process PpiList from SEC phase.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
+ These PPI's will be installed and/or immediately signaled if they are notification type.
+
+**/
+VOID
+ProcessPpiListFromSec (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
+ )
+{
+ EFI_STATUS Status;
+ EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
+ EFI_HOB_GENERIC_HEADER *SecHobList;
+
+ for (;;) {
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
+ //
+ // It is a notification PPI.
+ //
+ Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *) PpiList, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // It is a normal PPI.
+ //
+ Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ //
+ // Continue until the end of the PPI List.
+ //
+ break;
+ }
+
+ PpiList++;
+ }
+
+ //
+ // If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
+ // the PEI Foundation will call the GetHobs() member function and install all HOBs
+ // returned into the HOB list. It does this after installing all PPIs passed from SEC
+ // into the PPI database and before dispatching any PEIMs.
+ //
+ Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **) &SecHobDataPpi);
+ if (!EFI_ERROR (Status)) {
+ Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
+ if (!EFI_ERROR (Status)) {
+ Status = PeiInstallSecHobData (PeiServices, SecHobList);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+
+ Migrate PPI Pointers of PEI_CORE from temporary memory to permanent memory.
+
+ @param PrivateData Pointer to PeiCore's private data structure.
+ @param CoreFvHandle Address of PEI_CORE FV Handle in temporary memory.
+
+**/
+VOID
+ConvertPeiCorePpiPointers (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ PEI_CORE_FV_HANDLE CoreFvHandle
+ )
+{
+ EFI_FV_FILE_INFO FileInfo;
+ EFI_PHYSICAL_ADDRESS OrgImageBase;
+ EFI_PHYSICAL_ADDRESS MigratedImageBase;
+ UINTN PeiCoreModuleSize;
+ EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
+ VOID *PeiCoreImageBase;
+ VOID *PeiCoreEntryPoint;
+ EFI_STATUS Status;
+
+ PeiCoreFileHandle = NULL;
+
+ //
+ // Find the PEI Core in the BFV in temporary memory.
+ //
+ Status = CoreFvHandle.FvPpi->FindFileByType (
+ CoreFvHandle.FvPpi,
+ EFI_FV_FILETYPE_PEI_CORE,
+ CoreFvHandle.FvHandle,
+ &PeiCoreFileHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ Status = CoreFvHandle.FvPpi->GetFileInfo (CoreFvHandle.FvPpi, PeiCoreFileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiGetPe32Data (PeiCoreFileHandle, &PeiCoreImageBase);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find PEI Core EntryPoint in the BFV in temporary memory.
+ //
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, &PeiCoreEntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ OrgImageBase = (UINTN) PeiCoreImageBase;
+ MigratedImageBase = (UINTN) _ModuleEntryPoint - ((UINTN) PeiCoreEntryPoint - (UINTN) PeiCoreImageBase);
+
+ //
+ // Size of loaded PEI_CORE in permanent memory.
+ //
+ PeiCoreModuleSize = (UINTN)FileInfo.BufferSize - ((UINTN) OrgImageBase - (UINTN) FileInfo.Buffer);
+
+ //
+ // Migrate PEI_CORE PPI pointers from temporary memory to newly
+ // installed PEI_CORE in permanent memory.
+ //
+ ConvertPpiPointersFv (PrivateData, (UINTN) OrgImageBase, (UINTN) MigratedImageBase, PeiCoreModuleSize);
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Reset/Reset.c b/roms/edk2/MdeModulePkg/Core/Pei/Reset/Reset.c
new file mode 100644
index 000000000..0c3cfad03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Reset/Reset.c
@@ -0,0 +1,111 @@
+/** @file
+ Pei Core Reset System Support
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Core version of the Reset System
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+
+ @retval EFI_NOT_AVAILABLE_YET PPI not available yet.
+ @retval EFI_DEVICE_ERROR Did not reset system.
+ Otherwise, resets the system.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiResetSystem (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RESET_PPI *ResetPpi;
+
+ //
+ // Attempt to use newer ResetSystem2(). If this returns, then ResetSystem2()
+ // is not available.
+ //
+ PeiResetSystem2 (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ //
+ // Look for PEI Reset System PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiResetPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&ResetPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ return ResetPpi->ResetSystem (PeiServices);
+ }
+
+ //
+ // Report Status Code that Reset PPI is not available.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PS_EC_RESET_NOT_AVAILABLE)
+ );
+
+ //
+ // No reset PPIs are available yet.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+
+**/
+VOID
+EFIAPI
+PeiResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RESET2_PPI *Reset2Ppi;
+
+ //
+ // Look for PEI Reset System 2 PPI
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReset2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Reset2Ppi
+ );
+ if (!EFI_ERROR (Status)) {
+ Reset2Ppi->ResetSystem (ResetType, ResetStatus, DataSize, ResetData);
+ return;
+ }
+
+ //
+ // Report Status Code that Reset2 PPI is not available.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_PEI_CORE | EFI_SW_PS_EC_RESET_NOT_AVAILABLE)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/Security/Security.c b/roms/edk2/MdeModulePkg/Core/Pei/Security/Security.c
new file mode 100644
index 000000000..8c18ed6cc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/Security/Security.c
@@ -0,0 +1,145 @@
+/** @file
+ EFI PEI Core Security services
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiSecurity2PpiGuid,
+ SecurityPpiNotifyCallback
+};
+
+/**
+ Initialize the security services.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param OldCoreData Pointer to the old core data.
+ NULL if being run in non-permanent memory mode.
+
+**/
+VOID
+InitializeSecurityServices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ PeiServicesNotifyPpi (&mNotifyList);
+ }
+ return;
+}
+
+/**
+
+ Provide a callback for when the security PPI is installed.
+ This routine will cache installed security PPI into PeiCore's private data.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param NotifyDescriptor The descriptor for the notification event.
+ @param Ppi Pointer to the PPI in question.
+
+ @return Always success
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ //
+ // Get PEI Core private data
+ //
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
+
+ //
+ // If there isn't a security PPI installed, use the one from notification
+ //
+ if (PrivateData->PrivateSecurityPpi == NULL) {
+ PrivateData->PrivateSecurityPpi = (EFI_PEI_SECURITY2_PPI *)Ppi;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Provide a callout to the security verification service.
+
+ @param PrivateData PeiCore's private data structure
+ @param VolumeHandle Handle of FV
+ @param FileHandle Handle of PEIM's FFS
+ @param AuthenticationStatus Authentication status
+
+ @retval EFI_SUCCESS Image is OK
+ @retval EFI_SECURITY_VIOLATION Image is illegal
+ @retval EFI_NOT_FOUND If security PPI is not installed.
+**/
+EFI_STATUS
+VerifyPeim (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN EFI_PEI_FV_HANDLE VolumeHandle,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT32 AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN DeferExecution;
+
+ Status = EFI_NOT_FOUND;
+ if (PrivateData->PrivateSecurityPpi == NULL) {
+ //
+ // Check AuthenticationStatus first.
+ //
+ if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) {
+ if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ }
+ } else {
+ //
+ // Check to see if the image is OK
+ //
+ Status = PrivateData->PrivateSecurityPpi->AuthenticationState (
+ (CONST EFI_PEI_SERVICES **) &PrivateData->Ps,
+ PrivateData->PrivateSecurityPpi,
+ AuthenticationStatus,
+ VolumeHandle,
+ FileHandle,
+ &DeferExecution
+ );
+ if (DeferExecution) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Verify a Firmware volume.
+
+ @param CurrentFvAddress Pointer to the current Firmware Volume under consideration
+
+ @retval EFI_SUCCESS Firmware Volume is legal
+
+**/
+EFI_STATUS
+VerifyFv (
+ IN EFI_FIRMWARE_VOLUME_HEADER *CurrentFvAddress
+ )
+{
+ //
+ // Right now just pass the test. Future can authenticate and/or check the
+ // FV-header or other metric for goodness of binary.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c b/roms/edk2/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c
new file mode 100644
index 000000000..482f8d8a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Pei/StatusCode/StatusCode.c
@@ -0,0 +1,68 @@
+/** @file
+ Pei Core Status Code Support
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+/**
+
+ Core version of the Status Code reporter
+
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Type of Status Code.
+ @param Value Value to output for Status Code.
+ @param Instance Instance Number of this status code.
+ @param CallerId ID of the caller of this status code.
+ @param Data Optional data associated with this status code.
+
+ @retval EFI_SUCCESS if status code is successfully reported
+ @retval EFI_NOT_AVAILABLE_YET if StatusCodePpi has not been installed
+
+**/
+EFI_STATUS
+EFIAPI
+PeiReportStatusCode (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PROGRESS_CODE_PPI *StatusCodePpi;
+
+ //
+ // Locate StatusCode Ppi.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiStatusCodePpiGuid,
+ 0,
+ NULL,
+ (VOID **)&StatusCodePpi
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = StatusCodePpi->ReportStatusCode (
+ PeiServices,
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+
+ return Status;
+ }
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dependency.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dependency.c
new file mode 100644
index 000000000..1167807b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dependency.c
@@ -0,0 +1,382 @@
+/** @file
+ SMM Driver Dispatcher Dependency Evaluator
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ schedulability is that the dependency expression is satisfied.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+///
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
+/// to save time. A EFI_DEP_PUSH is evaluated one an
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
+/// Driver Execution Environment Core Interface use 0xff
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
+/// defined to a new value that is not conflicting with PI spec.
+///
+#define EFI_DEP_REPLACE_TRUE 0xff
+
+///
+/// Define the initial size of the dependency expression evaluation stack
+///
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+/**
+ Grow size of the Depex stack
+
+ @retval EFI_SUCCESS Stack successfully growed.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+ VOID
+ )
+{
+ BOOLEAN *NewStack;
+ UINTN Size;
+
+ Size = DEPEX_STACK_SIZE_INCREMENT;
+ if (mDepexEvaluationStack != NULL) {
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDepexEvaluationStack != NULL) {
+ //
+ // Copy to Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ mDepexEvaluationStack,
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (mDepexEvaluationStack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
+ mDepexEvaluationStack = NewStack;
+ mDepexEvaluationStackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Value BOOLEAN to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushBool (
+ IN BOOLEAN Value
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowDepexStack ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ *mDepexEvaluationStackPointer = Value;
+ mDepexEvaluationStackPointer++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pop an element from the Boolean stack.
+
+ @param Value BOOLEAN to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
+
+**/
+EFI_STATUS
+PopBool (
+ OUT BOOLEAN *Value
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ mDepexEvaluationStackPointer--;
+ *Value = *mDepexEvaluationStackPointer;
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+SmmIsSchedulable (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Iterator;
+ BOOLEAN Operator;
+ BOOLEAN Operator2;
+ EFI_GUID DriverGuid;
+ VOID *Interface;
+
+ Operator = FALSE;
+ Operator2 = FALSE;
+
+ if (DriverEntry->After || DriverEntry->Before) {
+ //
+ // If Before or After Depex skip as SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means that the SMM driver is not built correctly.
+ // All SMM drivers must have a valid depex expression.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Depex is empty)\n"));
+ ASSERT (FALSE);
+ return FALSE;
+ }
+
+ //
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+ // incorrectly formed DEPEX expressions
+ //
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+
+ Iterator = DriverEntry->Depex;
+
+ while (TRUE) {
+ //
+ // Check to see if we are attempting to fetch dependency expression instructions
+ // past the end of the dependency expression.
+ //
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
+ return FALSE;
+ }
+
+ //
+ // Look at the opcode of the dependency expression instruction.
+ //
+ switch (*Iterator) {
+ case EFI_DEP_BEFORE:
+ case EFI_DEP_AFTER:
+ //
+ // For a well-formed Dependency Expression, the code should never get here.
+ // The BEFORE and AFTER are processed prior to this routine's invocation.
+ // If the code flow arrives at this point, there was a BEFORE or AFTER
+ // that were not the first opcodes.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
+ ASSERT (FALSE);
+
+ case EFI_DEP_PUSH:
+ //
+ // Push operator is followed by a GUID. Test to see if the GUID protocol
+ // is installed and push the boolean result on the stack.
+ //
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+
+ Status = SmmLocateProtocol (&DriverGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ //
+ // For SMM Driver, it may depend on uefi protocols
+ //
+ Status = gBS->LocateProtocol (&DriverGuid, NULL, &Interface);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
+ Status = PushBool (FALSE);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ *Iterator = EFI_DEP_REPLACE_TRUE;
+ Status = PushBool (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ case EFI_DEP_AND:
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_OR:
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_NOT:
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(!Operator));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_TRUE:
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_FALSE:
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ Status = PushBool (FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_END:
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
+ return Operator;
+
+ case EFI_DEP_REPLACE_TRUE:
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
+ goto Done;
+ }
+
+ //
+ // Skip over the Dependency Op Code we just processed in the switch.
+ // The math is done out of order, but it should not matter. That is
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
+ // This is not an issue, since we just need the correct end result. You
+ // need to be careful using Iterator in the loop as its intermediate value
+ // may be strange.
+ //
+ Iterator++;
+ }
+
+Done:
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
new file mode 100644
index 000000000..76ee9e0b8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
@@ -0,0 +1,1499 @@
+/** @file
+ SMM Driver Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The Before, and After Depex are
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori
+ file exists in the FV those drivers are addeded to the
+ mScheduledQueue. The mFvHandleList is used to make sure a
+ FV is only processed once.
+
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
+ start it. After mScheduledQueue is drained check the
+ mDiscoveredList to see if any item has a Depex that is ready to
+ be placed on the mScheduledQueue.
+
+ Step #3 - Adding to the mScheduledQueue requires that you process Before
+ and After dependencies. This is done recursively as the call to add
+ to the mScheduledQueue checks for Before and recursively adds
+ all Befores. It then addes the item that was passed in and then
+ processes the After dependencies by recursively calling the routine.
+
+ Dispatcher Rules:
+ The rules for the dispatcher are similar to the DXE dispatcher.
+
+ The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expression.
+
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+//
+// SMM Dispatcher Data structures
+//
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFvHandleList
+ EFI_HANDLE Handle;
+} KNOWN_HANDLE;
+
+//
+// Function Prototypes
+//
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY
+//
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
+
+//
+// Queue of drivers that are ready to dispatch. This queue is a subset of the
+// mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.
+//
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
+
+//
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.
+//
+LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);
+
+//
+// Flag for the SMM Dispatcher. TRUE if dispatcher is executing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Flag for the SMM Dispatcher. TRUE if there is one or more SMM drivers ready to be dispatched
+//
+BOOLEAN gRequestDispatch = FALSE;
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mSmmFileTypes[] = {
+ EFI_FV_FILETYPE_SMM,
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE,
+ EFI_FV_FILETYPE_SMM_CORE,
+ //
+ // Note: DXE core will process the FV image file, so skip it in SMM core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+};
+
+typedef struct {
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FV_FILEPATH_DEVICE_PATH;
+
+FV_FILEPATH_DEVICE_PATH mFvDevicePath;
+
+//
+// DXE Architecture Protocols
+//
+EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL;
+EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL;
+
+//
+// The global variable is defined for Loading modules at fixed address feature to track the SMM code
+// memory range usage. It is a bit mapped array in which every bit indicates the corresponding
+// memory page available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap=NULL;
+
+/**
+ To check memory usage bit map array to figure out if the memory range in which the image will be loaded is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 SmmCodePageNumber;
+ UINT64 SmmCodeSize;
+ EFI_PHYSICAL_ADDRESS SmmCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+ //
+ SmmCodePageNumber = PcdGet32(PcdLoadFixAddressSmmCodePageNumber);
+ SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);
+ SmmCodeBase = gLoadModuleAtFixAddressSmramBase;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
+ mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((SmmCodePageNumber / 64) + 1)*sizeof(UINT64));
+ }
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // see if the memory range for loading the image is in the SMM code range.
+ //
+ if (SmmCodeBase + SmmCodeSize < ImageBase + ImageSize || SmmCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test if the memory is available or not.
+ //
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mSmmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled,
+ // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields
+ // should not be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section in which build tool saves the
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader);
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status));
+ return Status;
+}
+/**
+ Loads an EFI image into SMRAM.
+
+ @param DriverEntry EFI_SMM_DRIVER_ENTRY instance
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLoadImage (
+ IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT32 AuthenticationStatus;
+ UINTN FilePathSize;
+ VOID *Buffer;
+ UINTN Size;
+ UINTN PageCount;
+ EFI_GUID *NameGuid;
+ EFI_STATUS Status;
+ EFI_STATUS SecurityStatus;
+ EFI_HANDLE DeviceHandle;
+ EFI_PHYSICAL_ADDRESS DstBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);
+
+ Buffer = NULL;
+ Size = 0;
+ Fv = DriverEntry->Fv;
+ NameGuid = &DriverEntry->FileName;
+ FilePath = DriverEntry->FvFileDevicePath;
+
+ OriginalFilePath = FilePath;
+ HandleFilePath = FilePath;
+ DeviceHandle = NULL;
+ SecurityStatus = EFI_SUCCESS;
+ Status = EFI_SUCCESS;
+ AuthenticationStatus = 0;
+
+ //
+ // Try to get the image device handle by checking the match protocol.
+ //
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
+ //
+ if (mSecurity2 == NULL) {
+ gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID**)&mSecurity2);
+ }
+ if (mSecurity == NULL) {
+ gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);
+ }
+ //
+ // When Security2 is installed, Security Architectural Protocol must be published.
+ //
+ ASSERT (mSecurity2 == NULL || mSecurity != NULL);
+
+ //
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
+ //
+ FilePath = OriginalFilePath;
+ Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
+ }
+
+ //
+ // Try reading PE32 section firstly
+ //
+ Status = Fv->ReadSection (
+ Fv,
+ NameGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Try reading TE section secondly
+ //
+ Buffer = NULL;
+ Size = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ NameGuid,
+ EFI_SECTION_TE,
+ 0,
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+
+ //
+ // Verify File Authentication through the Security2 Architectural Protocol
+ //
+ if (mSecurity2 != NULL) {
+ SecurityStatus = mSecurity2->FileAuthentication (
+ mSecurity2,
+ OriginalFilePath,
+ Buffer,
+ Size,
+ FALSE
+ );
+ }
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ // Only on images that have been read using Firmware Volume protocol.
+ // All SMM images are from FV protocol.
+ //
+ if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) {
+ SecurityStatus = mSecurity->FileAuthenticationState (
+ mSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
+ Status = SecurityStatus;
+ return Status;
+ }
+
+ //
+ // Initialize ImageContext
+ //
+ ImageContext.Handle = Buffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+ //
+ // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE
+ // to hold the Smm driver code
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Get the fixed loading address assigned by Build tool
+ //
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range
+ // following statements is to bypass SmmFreePages
+ //
+ PageCount = 0;
+ DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;
+ } else {
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // allocate the memory to load the SMM driver
+ //
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = SmmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
+ }
+ } else {
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = SmmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
+ }
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data are written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);
+
+ //
+ // Save Image EntryPoint in DriverEntry
+ //
+ DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
+ DriverEntry->ImageBuffer = DstBuffer;
+ DriverEntry->NumberOfPage = PageCount;
+
+ //
+ // Allocate a Loaded Image Protocol in EfiBootServicesData
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
+ //
+ // Fill in the remaining fields of the Loaded Image Protocol instance.
+ // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
+ //
+ DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
+ DriverEntry->LoadedImage->SystemTable = gST;
+ DriverEntry->LoadedImage->DeviceHandle = DeviceHandle;
+
+ DriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
+ DriverEntry->SmmLoadedImage.SystemTable = gST;
+ DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle;
+
+ //
+ // Make an EfiBootServicesData buffer copy of FilePath
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+ CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));
+
+ DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN) ImageContext.ImageAddress;
+ DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
+ DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
+ DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
+
+ //
+ // Make a buffer copy of FilePath
+ //
+ Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize(FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ gBS->FreePool (Buffer);
+ }
+ gBS->FreePool (DriverEntry->LoadedImage->FilePath);
+ SmmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+ CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize(FilePath));
+
+ DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN) ImageContext.ImageAddress;
+ DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize;
+ DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
+ DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
+
+ //
+ // Create a new image handle in the UEFI handle database for the SMM Driver
+ //
+ DriverEntry->ImageHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverEntry->ImageHandle,
+ &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage,
+ NULL
+ );
+
+ //
+ // Create a new image handle in the SMM handle database for the SMM Driver
+ //
+ DriverEntry->SmmImageHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &DriverEntry->SmmImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &DriverEntry->SmmLoadedImage
+ );
+
+ PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+
+ DEBUG_CODE_BEGIN ();
+
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,
+ "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN) ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));
+
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~255.
+ // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ //
+ // Free buffer allocated by Fv->ReadSection.
+ //
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+ // used the UEFI Boot Services AllocatePool() function
+ //
+ Status = gBS->FreePool(Buffer);
+ if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+ return Status;
+}
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before and After dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+SmmPreProcessDepex (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ DriverEntry->Dependent = TRUE;
+
+ if (*Iterator == EFI_DEP_BEFORE) {
+ DriverEntry->Before = TRUE;
+ } else if (*Iterator == EFI_DEP_AFTER) {
+ DriverEntry->After = TRUE;
+ }
+
+ if (DriverEntry->Before || DriverEntry->After) {
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction
+ protocol returns an error via ReadSection defer the reading of the Depex.
+
+ @param DriverEntry Driver to work on.
+
+ @retval EFI_SUCCESS Depex read and preprocessed
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
+ and Depex reading needs to be retried.
+ @retval Error DEPEX not found.
+
+**/
+EFI_STATUS
+SmmGetDepexSectionAndPreProccess (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ Fv = DriverEntry->Fv;
+
+ //
+ // Grab Depex info, it will never be free'ed.
+ // (Note: DriverEntry->Depex is in DXE memory)
+ //
+ SectionType = EFI_SECTION_SMM_DEPEX;
+ Status = Fv->ReadSection (
+ DriverEntry->Fv,
+ &DriverEntry->FileName,
+ SectionType,
+ 0,
+ &DriverEntry->Depex,
+ (UINTN *)&DriverEntry->DepexSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_PROTOCOL_ERROR) {
+ //
+ // The section extraction protocol failed so set protocol error flag
+ //
+ DriverEntry->DepexProtocolError = TRUE;
+ } else {
+ //
+ // If no Depex assume depend on all architectural protocols
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before and After state information based on Depex
+ // Driver will be put in Dependent state
+ //
+ SmmPreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+/**
+ This is the main Dispatcher for SMM and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function.
+
+ @retval EFI_SUCCESS All of the SMM Drivers that could be dispatched
+ have been run and the SMM Entry Point has been
+ registered.
+ @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point
+ was just dispatched.
+ @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.
+ @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running
+
+**/
+EFI_STATUS
+SmmDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+ BOOLEAN PreviousSmmEntryPointRegistered;
+
+ if (!gRequestDispatch) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (gDispatcherRunning) {
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_SMM_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_SMM_DRIVER_ENTRY_SIGNATURE
+ );
+
+ //
+ // Load the SMM Driver image into memory. If the Driver was transitioned from
+ // Untrused to Scheduled it would have already been loaded so we may need to
+ // skip the LoadImage
+ //
+ if (DriverEntry->ImageHandle == NULL) {
+ Status = SmmLoadImage (DriverEntry);
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // The SMM Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ DriverEntry->Initialized = TRUE;
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+
+ //
+ // Cache state of SmmEntryPointRegistered before calling entry point
+ //
+ PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
+
+ //
+ // For each SMM driver, pass NULL as ImageHandle
+ //
+ RegisterSmramProfileImage (DriverEntry, TRUE);
+ PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
+ PERF_START_IMAGE_END (DriverEntry->ImageHandle);
+ if (EFI_ERROR(Status)){
+ DEBUG ((
+ DEBUG_ERROR,
+ "Error: SMM image at %11p start failed: %r\n",
+ DriverEntry->SmmLoadedImage.ImageBase,
+ Status
+ ));
+ UnregisterSmramProfileImage (DriverEntry, TRUE);
+ SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
+ //
+ // Uninstall LoadedImage
+ //
+ Status = gBS->UninstallProtocolInterface (
+ DriverEntry->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ DriverEntry->LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ if (DriverEntry->LoadedImage->FilePath != NULL) {
+ gBS->FreePool (DriverEntry->LoadedImage->FilePath);
+ }
+ gBS->FreePool (DriverEntry->LoadedImage);
+ }
+ Status = SmmUninstallProtocolInterface (
+ DriverEntry->SmmImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ &DriverEntry->SmmLoadedImage
+ );
+ if (!EFI_ERROR(Status)) {
+ if (DriverEntry->SmmLoadedImage.FilePath != NULL) {
+ SmmFreePool (DriverEntry->SmmLoadedImage.FilePath);
+ }
+ }
+ }
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+
+ if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
+ //
+ // Return immediately if the SMM Entry Point was registered by the SMM
+ // Driver that was just dispatched. The SMM IPL will reinvoke the SMM
+ // Core Dispatcher. This is required so SMM Mode may be enabled as soon
+ // as all the dependent SMM Drivers for SMM Mode have been dispatched.
+ // Once the SMM Entry Point has been registered, then SMM Mode will be
+ // used.
+ //
+ gRequestDispatch = TRUE;
+ gDispatcherRunning = FALSE;
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+
+ if (DriverEntry->DepexProtocolError){
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (SmmIsSchedulable (DriverEntry)) {
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // If there is no more SMM driver to dispatch, stop the dispatch request
+ //
+ gRequestDispatch = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+
+ if (!DriverEntry->Initialized){
+ //
+ // We have SMM driver pending to dispatch
+ //
+ gRequestDispatch = TRUE;
+ break;
+ }
+ }
+
+ gDispatcherRunning = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process BEFORE
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process AFTER
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+}
+
+/**
+ Return TRUE if the Fv has been processed, FALSE if not.
+
+ @param FvHandle The handle of a FV that's being tested
+
+ @retval TRUE Fv protocol on FvHandle has been processed
+ @retval FALSE Fv protocol on FvHandle has not yet been
+ processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (KnownHandle->Handle == FvHandle) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Remember that Fv protocol on FvHandle has had its drivers placed on the
+ mDiscoveredList. This function adds entries on the mFvHandleList. Items are
+ never removed/freed from the mFvHandleList.
+
+ @param FvHandle The handle of a FV that has been processed
+
+**/
+VOID
+FvIsBeingProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ KNOWN_HANDLE *KnownHandle;
+
+ KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
+ ASSERT (KnownHandle != NULL);
+
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+ KnownHandle->Handle = FvHandle;
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);
+}
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_SMM_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+SmmFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
+
+ //
+ // Remember the device path of the FV
+ //
+ Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ FileNameDevicePath = NULL;
+ } else {
+ //
+ // Build a device path to the file in the FV to pass into gBS->LoadImage
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ //
+ // Note: FileNameDevicePath is in DXE memory
+ //
+ FileNameDevicePath = AppendDevicePath (
+ FvDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ }
+ return FileNameDevicePath;
+}
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initialize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible SMM driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_SMM_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+SmmAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+
+ DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FvHandle = FvHandle;
+ DriverEntry->Fv = Fv;
+ DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);
+
+ SmmGetDepexSectionAndPreProccess (DriverEntry);
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+ gRequestDispatch = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on SmmLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the SMM driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmDriverDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS GetNextFileStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_HANDLE FvHandle;
+ EFI_GUID NameGuid;
+ UINTN Key;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;
+ EFI_GUID *AprioriFile;
+ UINTN AprioriEntryCount;
+ UINTN HandleIndex;
+ UINTN SmmTypeIndex;
+ UINTN AprioriIndex;
+ LIST_ENTRY *Link;
+ UINT32 AuthenticationStatus;
+ UINTN SizeOfBuffer;
+
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ FvHandle = HandleBuffer[HandleIndex];
+
+ if (FvHasBeenProcessed (FvHandle)) {
+ //
+ // This Fv has already been processed so lets skip it!
+ //
+ continue;
+ }
+
+ //
+ // Since we are about to process this Fv mark it as processed.
+ //
+ FvIsBeingProcessed (FvHandle);
+
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (EFI_ERROR (Status)) {
+ //
+ // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.
+ //
+ ASSERT (FALSE);
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // The Firmware volume doesn't have device path, can't be dispatched.
+ //
+ continue;
+ }
+
+ //
+ // Discover Drivers in FV and add them to the Discovered Driver List.
+ // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
+ // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
+ //
+ for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) {
+ //
+ // Initialize the search key
+ //
+ Key = 0;
+ do {
+ Type = mSmmFileTypes[SmmTypeIndex];
+ GetNextFileStatus = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &Type,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (!EFI_ERROR (GetNextFileStatus)) {
+ if (Type == EFI_FV_FILETYPE_SMM_CORE) {
+ //
+ // If this is the SMM core fill in it's DevicePath & DeviceHandle
+ //
+ if (mSmmCoreLoadedImage->FilePath == NULL) {
+ //
+ // Maybe one special FV contains only one SMM_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ //
+ // Make an EfiBootServicesData buffer copy of FilePath
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
+ (VOID **)&mSmmCoreLoadedImage->FilePath
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
+
+ mSmmCoreLoadedImage->DeviceHandle = FvHandle;
+ }
+ if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) {
+ //
+ // Maybe one special FV contains only one SMM_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ //
+ // Make a buffer copy FilePath
+ //
+ Status = SmmAllocatePool (
+ EfiRuntimeServicesData,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
+ (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
+
+ mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle;
+ }
+ } else {
+ SmmAddToDriverList (Fv, FvHandle, &NameGuid);
+ }
+ }
+ } while (!EFI_ERROR (GetNextFileStatus));
+ }
+
+ //
+ // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
+ // (Note: AprioriFile is in DXE memory)
+ //
+ AprioriFile = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &gAprioriGuid,
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **)&AprioriFile,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
+ } else {
+ AprioriEntryCount = 0;
+ }
+
+ //
+ // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
+ // drivers not in the current FV and these must be skipped since the a priori list
+ // is only valid for the FV that it resided in.
+ //
+
+ for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) {
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) &&
+ (FvHandle == DriverEntry->FvHandle)) {
+ DriverEntry->Dependent = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ break;
+ }
+ }
+ }
+
+ //
+ // Free data allocated by Fv->ReadSection ()
+ //
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+ // used the UEFI Boot Services AllocatePool() function
+ //
+ gBS->FreePool (AprioriFile);
+ }
+
+ //
+ // Execute the SMM Dispatcher on any newly discovered FVs and previously
+ // discovered SMM drivers that have been discovered but not dispatched.
+ //
+ Status = SmmDispatcher ();
+
+ //
+ // Check to see if CommBuffer and CommBufferSize are valid
+ //
+ if (CommBuffer != NULL && CommBufferSize != NULL) {
+ if (*CommBufferSize > 0) {
+ if (Status == EFI_NOT_READY) {
+ //
+ // If a the SMM Core Entry Point was just registered, then set flag to
+ // request the SMM Dispatcher to be restarted.
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;
+ } else if (!EFI_ERROR (Status)) {
+ //
+ // Set the flag to show that the SMM Dispatcher executed without errors
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;
+ } else {
+ //
+ // Set the flag to show that the SMM Dispatcher encountered an error
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency expressions evaluated to false.
+
+**/
+VOID
+SmmDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Handle.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Handle.c
new file mode 100644
index 000000000..f8dbe4644
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Handle.c
@@ -0,0 +1,528 @@
+/** @file
+ SMM handle & protocol handling.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+SmmValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+
+ Handle = (IHANDLE *)UserHandle;
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+SmmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ //
+ // Search the database for the matching GUID
+ //
+
+ ProtEntry = NULL;
+ for (Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {
+ //
+ // This is the protocol entry
+ //
+ ProtEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((ProtEntry == NULL) && Create) {
+ ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
+ if (ProtEntry != NULL) {
+ //
+ // Initialize new protocol entry structure
+ //
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
+ InitializeListHead (&ProtEntry->Protocols);
+ InitializeListHead (&ProtEntry->Notify);
+
+ //
+ // Add it to protocol database
+ //
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
+ }
+ }
+ return ProtEntry;
+}
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+SmmFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+ ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ //
+ // Look at each protocol interface for any matches
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
+ //
+ // If this protocol interface matches, remove it
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
+ break;
+ }
+ Prot = NULL;
+ }
+ }
+ return Prot;
+}
+
+/**
+ Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return SmmInstallProtocolInterfaceNotify (
+ UserHandle,
+ Protocol,
+ InterfaceType,
+ Interface,
+ TRUE
+ );
+}
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+SmmInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ IHANDLE *Handle;
+ EFI_STATUS Status;
+ VOID *ExistingInterface;
+
+ //
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
+ // Also added check for invalid UserHandle and Protocol pointers.
+ //
+ if (UserHandle == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print debug message
+ //
+ DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ //
+ // Allocate a new protocol interface structure
+ //
+ Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
+ if (Prot == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // If caller didn't supply a handle, allocate a new one
+ //
+ Handle = (IHANDLE *)*UserHandle;
+ if (Handle == NULL) {
+ Handle = AllocateZeroPool (sizeof(IHANDLE));
+ if (Handle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize new handler structure
+ //
+ Handle->Signature = EFI_HANDLE_SIGNATURE;
+ InitializeListHead (&Handle->Protocols);
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ } else {
+ Status = SmmValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SmmInstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
+ goto Done;
+ }
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // Add this protocol interface to the head of the supported
+ // protocol list for this handle
+ //
+ InsertHeadList (&Handle->Protocols, &Prot->Link);
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Notify the notification list for this protocol
+ //
+ if (Notify) {
+ SmmNotifyProtocol (Prot);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ FreePool (Prot);
+ }
+ DEBUG((DEBUG_ERROR, "SmmInstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
+ }
+ return Status;
+}
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check that Protocol is valid
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that UserHandle is a valid handle
+ //
+ Status = SmmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ FreePool (Prot);
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // If there are no more handlers for the handle, free the handle
+ //
+ if (IsListEmpty (&Handle->Protocols)) {
+ Handle->Signature = 0;
+ RemoveEntryList (&Handle->AllHandles);
+ FreePool (Handle);
+ }
+ return Status;
+}
+
+/**
+ Locate a certain GUID protocol interface in a Handle's protocols.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The GUID of the protocol
+
+ @return The requested protocol interface for the handle
+
+**/
+PROTOCOL_INTERFACE *
+SmmGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Status = SmmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ //
+ // Look at each protocol interface for a match
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ ProtEntry = Prot->Protocol;
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
+ return Prot;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if (Interface == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ *Interface = NULL;
+ }
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = SmmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = SmmGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // This is the protocol interface entry for this protocol
+ //
+ *Interface = Prot->Interface;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.c
new file mode 100644
index 000000000..b0d0f7204
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.c
@@ -0,0 +1,1404 @@
+/** @file
+ UEFI Heap Guard functions.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "HeapGuard.h"
+
+//
+// Global to avoid infinite reentrance of memory allocation when updating
+// page table attributes, which may need allocating pages for new PDE/PTE.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
+
+//
+// Pointer to table tracking the Guarded memory with bitmap, in which '1'
+// is used to indicate memory guarded. '0' might be free memory or Guard
+// page itself, depending on status of memory adjacent to it.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
+
+//
+// Current depth level of map table pointed by mGuardedMemoryMap.
+// mMapLevel must be initialized at least by 1. It will be automatically
+// updated according to the address of memory just tracked.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
+
+//
+// Shift and mask for each level of map table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+
+//
+// SMM memory attribute protocol
+//
+EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *mSmmMemoryAttribute = NULL;
+
+/**
+ Set corresponding bits in bitmap table to 1 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID
+**/
+STATIC
+VOID
+SetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
+ (UINT64)-1);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap |= (LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Set corresponding bits in bitmap table to 0 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+ClearBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Get corresponding bits in bitmap table according to the address.
+
+ The value of bit 0 corresponds to the status of memory at given Address.
+ No more than 64 bits can be retrieved in one call.
+
+ @param[in] Address Start address to retrieve bits for.
+ @param[in] BitNumber Number of bits to get.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return An integer containing the bits information.
+**/
+STATIC
+UINT64
+GetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN StartBit;
+ UINTN EndBit;
+ UINTN Lsbs;
+ UINTN Msbs;
+ UINT64 Result;
+
+ ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ }
+
+ if (StartBit == 0 && BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Result = *BitMap;
+ } else {
+ Result = RShiftU64((*BitMap), StartBit) & (LShiftU64(1, Msbs) - 1);
+ if (Lsbs > 0) {
+ BitMap += 1;
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ }
+ }
+
+ return Result;
+}
+
+/**
+ Helper function to allocate pages without Guard for internal uses.
+
+ @param[in] Pages Page number.
+
+ @return Address of memory allocated.
+**/
+VOID *
+PageAlloc (
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData,
+ Pages, &Memory, FALSE);
+ if (EFI_ERROR (Status)) {
+ Memory = 0;
+ }
+
+ return (VOID *)(UINTN)Memory;
+}
+
+/**
+ Locate the pointer of bitmap from the guarded memory bitmap tables, which
+ covers the given Address.
+
+ @param[in] Address Start address to search the bitmap for.
+ @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
+ @param[out] BitMap Pointer to bitmap which covers the Address.
+
+ @return The bit number from given Address to the end of current map table.
+**/
+UINTN
+FindGuardedMemoryMap (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN AllocMapUnit,
+ OUT UINT64 **BitMap
+ )
+{
+ UINTN Level;
+ UINT64 *GuardMap;
+ UINT64 MapMemory;
+ UINTN Index;
+ UINTN Size;
+ UINTN BitsToUnitEnd;
+
+ //
+ // Adjust current map table depth according to the address to access
+ //
+ while (AllocMapUnit &&
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
+ RShiftU64 (
+ Address,
+ mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
+ ) != 0) {
+
+ if (mGuardedMemoryMap != 0) {
+ Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
+ * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+
+ *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
+ mGuardedMemoryMap = MapMemory;
+ }
+
+ mMapLevel++;
+
+ }
+
+ GuardMap = &mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level) {
+
+ if (*GuardMap == 0) {
+ if (!AllocMapUnit) {
+ GuardMap = NULL;
+ break;
+ }
+
+ Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+ *GuardMap = MapMemory;
+ }
+
+ Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
+ Index &= mLevelMask[Level];
+ GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
+
+ }
+
+ BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
+ *BitMap = GuardMap;
+
+ return BitsToUnitEnd;
+}
+
+/**
+ Set corresponding bits in bitmap table to 1 according to given memory range.
+
+ @param[in] Address Memory address to guard from.
+ @param[in] NumberOfPages Number of pages to guard.
+
+ @return VOID
+**/
+VOID
+EFIAPI
+SetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ SetBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Clear corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to unset from.
+ @param[in] NumberOfPages Number of pages to unset guard.
+
+ @return VOID
+**/
+VOID
+EFIAPI
+ClearGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ ClearBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Retrieve corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to retrieve from.
+ @param[in] NumberOfPages Number of pages to retrieve.
+
+ @return An integer containing the guarded memory bitmap.
+**/
+UINTN
+GetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN Result;
+ UINTN Shift;
+ UINTN BitsToUnitEnd;
+
+ ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ Result = 0;
+ Shift = 0;
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ if (BitMap != NULL) {
+ Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
+ }
+
+ Shift += Bits;
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+
+ return Result;
+}
+
+/**
+ Get bit value in bitmap table for the given address.
+
+ @param[in] Address The address to retrieve for.
+
+ @return 1 or 0.
+**/
+UINTN
+EFIAPI
+GetGuardMapBit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 *GuardMap;
+
+ FindGuardedMemoryMap (Address, FALSE, &GuardMap);
+ if (GuardMap != NULL) {
+ if (RShiftU64 (*GuardMap,
+ GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+)
+{
+ UINTN BitMap;
+
+ //
+ // There must be at least one guarded page before and/or after given
+ // address if it's a Guard page. The bitmap pattern should be one of
+ // 001, 100 and 101
+ //
+ BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
+ return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
+}
+
+
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ return (GetGuardMapBit (Address) == 1);
+}
+
+/**
+ Set the page at the given address to be a Guard page.
+
+ This is done by changing the page table attribute to be NOT PRESENT.
+
+ @param[in] BaseAddress Page address to Guard at.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+SetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (mSmmMemoryAttribute != NULL) {
+ mOnGuarding = TRUE;
+ Status = mSmmMemoryAttribute->SetMemoryAttributes (
+ mSmmMemoryAttribute,
+ BaseAddress,
+ EFI_PAGE_SIZE,
+ EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Unset the Guard page at the given address to the normal memory.
+
+ This is done by changing the page table attribute to be PRESENT.
+
+ @param[in] BaseAddress Page address to Guard at.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+UnsetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (mSmmMemoryAttribute != NULL) {
+ mOnGuarding = TRUE;
+ Status = mSmmMemoryAttribute->ClearMemoryAttributes (
+ mSmmMemoryAttribute,
+ BaseAddress,
+ EFI_PAGE_SIZE,
+ EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Check to see if the memory at the given address should be guarded or not.
+
+ @param[in] MemoryType Memory type to check.
+ @param[in] AllocateType Allocation type to check.
+ @param[in] PageOrPool Indicate a page allocation or pool allocation.
+
+
+ @return TRUE The given type of memory should be guarded.
+ @return FALSE The given type of memory should not be guarded.
+**/
+BOOLEAN
+IsMemoryTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN UINT8 PageOrPool
+ )
+{
+ UINT64 TestBit;
+ UINT64 ConfigBit;
+
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0
+ || mOnGuarding
+ || AllocateType == AllocateAddress) {
+ return FALSE;
+ }
+
+ ConfigBit = 0;
+ if ((PageOrPool & GUARD_HEAP_TYPE_POOL) != 0) {
+ ConfigBit |= PcdGet64 (PcdHeapGuardPoolType);
+ }
+
+ if ((PageOrPool & GUARD_HEAP_TYPE_PAGE) != 0) {
+ ConfigBit |= PcdGet64 (PcdHeapGuardPageType);
+ }
+
+ if (MemoryType == EfiRuntimeServicesData ||
+ MemoryType == EfiRuntimeServicesCode) {
+ TestBit = LShiftU64 (1, MemoryType);
+ } else if (MemoryType == EfiMaxMemoryType) {
+ TestBit = (UINT64)-1;
+ } else {
+ TestBit = 0;
+ }
+
+ return ((ConfigBit & TestBit) != 0);
+}
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL);
+}
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
+}
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ VOID
+ )
+{
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE);
+}
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+
+ //
+ // Set tail Guard
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ // Set head Guard
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ //
+ // Mark the memory range as Guarded
+ //
+ SetGuardedMemoryBits (Memory, NumberOfPages);
+}
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+ UINT64 GuardBitmap;
+
+ if (NumberOfPages == 0) {
+ return;
+ }
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // unset it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages before memory to free are still in Guard. It's a partial free
+ // case. Turn first page of memory block to free into a new Guard.
+ //
+ SetGuardPage (Memory);
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages after memory to free are still in Guard. It's a partial free
+ // case. We need to keep one page to be a head Guard.
+ //
+ SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
+ }
+
+ //
+ // No matter what, we just clear the mark of the Guarded memory.
+ //
+ ClearGuardedMemoryBits(Memory, NumberOfPages);
+}
+
+
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS Start;
+ EFI_PHYSICAL_ADDRESS MemoryToTest;
+ UINTN PagesToFree;
+ UINT64 GuardBitmap;
+ UINT64 Attributes;
+
+ if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
+ return;
+ }
+
+ Start = *Memory;
+ PagesToFree = *NumberOfPages;
+
+ //
+ // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
+ //
+ if (mSmmMemoryAttribute != NULL) {
+ Attributes = 0;
+ mSmmMemoryAttribute->GetMemoryAttributes (
+ mSmmMemoryAttribute,
+ Start,
+ EFI_PAGES_TO_SIZE (PagesToFree),
+ &Attributes
+ );
+ if ((Attributes & EFI_MEMORY_RO) != 0) {
+ mSmmMemoryAttribute->ClearMemoryAttributes (
+ mSmmMemoryAttribute,
+ Start,
+ EFI_PAGES_TO_SIZE (PagesToFree),
+ EFI_MEMORY_RO
+ );
+ }
+ }
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ Start -= EFI_PAGES_TO_SIZE (1);
+ PagesToFree += 1;
+ }
+ } else {
+ //
+ // No Head Guard, and pages before memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a tail Guard.
+ //
+ Start += EFI_PAGES_TO_SIZE (1);
+ PagesToFree -= 1;
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ PagesToFree += 1;
+ }
+ } else if (PagesToFree > 0) {
+ //
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a head Guard.
+ //
+ PagesToFree -= 1;
+ }
+
+ *Memory = Start;
+ *NumberOfPages = PagesToFree;
+}
+
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ Size = ALIGN_VALUE (Size, 8);
+ return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
+}
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
+}
+
+/**
+ Helper function of memory allocation with Guard pages.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+ @param MemoryType Type of memory requested.
+
+ @return Memory address of allocated pages.
+**/
+UINTN
+InternalAllocMaxAddressWithGuard (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress,
+ IN EFI_MEMORY_TYPE MemoryType
+
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+ UINTN PagesToAlloc;
+ UINTN HeadGuard;
+ UINTN TailGuard;
+ UINTN Address;
+
+ for (Node = FreePageList->BackLink; Node != FreePageList;
+ Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Pages->NumberOfPages >= NumberOfPages &&
+ (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
+
+ //
+ // We may need 1 or 2 more pages for Guard. Check it out.
+ //
+ PagesToAlloc = NumberOfPages;
+ TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
+ if (!IsGuardPage (TailGuard)) {
+ //
+ // Add one if no Guard at the end of current free memory block.
+ //
+ PagesToAlloc += 1;
+ TailGuard = 0;
+ }
+
+ HeadGuard = (UINTN)Pages +
+ EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) -
+ EFI_PAGE_SIZE;
+ if (!IsGuardPage (HeadGuard)) {
+ //
+ // Add one if no Guard at the page before the address to allocate
+ //
+ PagesToAlloc += 1;
+ HeadGuard = 0;
+ }
+
+ if (Pages->NumberOfPages < PagesToAlloc) {
+ // Not enough space to allocate memory with Guards? Try next block.
+ continue;
+ }
+
+ Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress);
+ ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc, FALSE);
+ CoreFreeMemoryMapStack();
+ if (HeadGuard == 0) {
+ // Don't pass the Guard page to user.
+ Address += EFI_PAGE_SIZE;
+ }
+ SetGuardForMemory (Address, NumberOfPages);
+ return Address;
+ }
+ }
+
+ return (UINTN)(-1);
+}
+
+/**
+ Helper function of memory free with Guard pages.
+
+ @param[in] Memory Base address of memory being freed.
+ @param[in] NumberOfPages The number of pages to free.
+ @param[in] AddRegion If this memory is new added region.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+**/
+EFI_STATUS
+SmmInternalFreePagesExWithGuard (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryToFree;
+ UINTN PagesToFree;
+
+ if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MemoryToFree = Memory;
+ PagesToFree = NumberOfPages;
+
+ AdjustMemoryF (&MemoryToFree, &PagesToFree);
+ UnsetGuardForMemory (Memory, NumberOfPages);
+ if (PagesToFree == 0) {
+ return EFI_SUCCESS;
+ }
+
+ return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion);
+}
+
+/**
+ Set all Guard pages which cannot be set during the non-SMM mode time.
+**/
+VOID
+SetAllGuardPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINTN Index;
+ BOOLEAN OnGuarding;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof(Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ OnGuarding = FALSE;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ OnGuarding = FALSE;
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+
+ } else {
+
+ Index = 0;
+ while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
+ if ((TableEntry & 1) == 1) {
+ if (OnGuarding) {
+ GuardPage = 0;
+ } else {
+ GuardPage = Address - EFI_PAGE_SIZE;
+ }
+ OnGuarding = TRUE;
+ } else {
+ if (OnGuarding) {
+ GuardPage = Address;
+ } else {
+ GuardPage = 0;
+ }
+ OnGuarding = FALSE;
+ }
+
+ if (GuardPage != 0) {
+ SetGuardPage (GuardPage);
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ TableEntry = RShiftU64 (TableEntry, 1);
+ Address += EFI_PAGE_SIZE;
+ Index += 1;
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
+/**
+ Hook function used to set all Guard pages after entering SMM mode.
+**/
+VOID
+SmmEntryPointMemoryManagementHook (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mSmmMemoryAttribute == NULL) {
+ Status = SmmLocateProtocol (
+ &gEdkiiSmmMemoryAttributeProtocolGuid,
+ NULL,
+ (VOID **)&mSmmMemoryAttribute
+ );
+ if (!EFI_ERROR(Status)) {
+ SetAllGuardPages ();
+ }
+ }
+}
+
+/**
+ Helper function to convert a UINT64 value in binary to a string.
+
+ @param[in] Value Value of a UINT64 integer.
+ @param[out] BinString String buffer to contain the conversion result.
+
+ @return VOID.
+**/
+VOID
+Uint64ToBinString (
+ IN UINT64 Value,
+ OUT CHAR8 *BinString
+ )
+{
+ UINTN Index;
+
+ if (BinString == NULL) {
+ return;
+ }
+
+ for (Index = 64; Index > 0; --Index) {
+ BinString[Index - 1] = '0' + (Value & 1);
+ Value = RShiftU64 (Value, 1);
+ }
+ BinString[64] = '\0';
+}
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ INTN Level;
+ UINTN RepeatZero;
+ CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
+ CHAR8 *Ruler1;
+ CHAR8 *Ruler2;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ Ruler1 = " 3 2 1 0";
+ Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
+
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
+ " Guarded Memory Bitmap "
+ "==============================\r\n"));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Indices, sizeof(Indices), 0);
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ RepeatZero = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+
+ Tables[Level] = 0;
+ Level -= 1;
+ RepeatZero = 0;
+
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "========================================="
+ "=========================================\r\n"
+ ));
+
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ if (RepeatZero == 0) {
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+ } else if (RepeatZero == 1) {
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
+ }
+ RepeatZero += 1;
+ }
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+ RepeatZero = 0;
+
+ continue;
+
+ } else {
+
+ RepeatZero = 0;
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
+/**
+ Debug function used to verify if the Guard page is well set or not.
+
+ @param[in] BaseAddress Address of memory to check.
+ @param[in] NumberOfPages Size of memory in pages.
+
+ @return TRUE The head Guard and tail Guard are both well set.
+ @return FALSE The head Guard and/or tail Guard are not well set.
+**/
+BOOLEAN
+VerifyMemoryGuard (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ if (mSmmMemoryAttribute == NULL) {
+ return TRUE;
+ }
+
+ Attribute = 0;
+ Address = BaseAddress - EFI_PAGE_SIZE;
+ Status = mSmmMemoryAttribute->GetMemoryAttributes (
+ mSmmMemoryAttribute,
+ Address,
+ EFI_PAGE_SIZE,
+ &Attribute
+ );
+ if (EFI_ERROR (Status) || (Attribute & EFI_MEMORY_RP) == 0) {
+ DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
+ Address, Attribute));
+ DumpGuardedMemoryBitmap ();
+ return FALSE;
+ }
+
+ Attribute = 0;
+ Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages);
+ Status = mSmmMemoryAttribute->GetMemoryAttributes (
+ mSmmMemoryAttribute,
+ Address,
+ EFI_PAGE_SIZE,
+ &Attribute
+ );
+ if (EFI_ERROR (Status) || (Attribute & EFI_MEMORY_RP) == 0) {
+ DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
+ Address, Attribute));
+ DumpGuardedMemoryBitmap ();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.h b/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.h
new file mode 100644
index 000000000..1b5c0f2a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/HeapGuard.h
@@ -0,0 +1,392 @@
+/** @file
+ Data structure and functions to allocate and free memory space.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HEAPGUARD_H_
+#define _HEAPGUARD_H_
+
+#include "PiSmmCore.h"
+
+//
+// Following macros are used to define and access the guarded memory bitmap
+// table.
+//
+// To simplify the access and reduce the memory used for this table, the
+// table is constructed in the similar way as page table structure but in
+// reverse direction, i.e. from bottom growing up to top.
+//
+// - 1-bit tracks 1 page (4KB)
+// - 1-UINT64 map entry tracks 256KB memory
+// - 1K-UINT64 map table tracks 256MB memory
+// - Five levels of tables can track any address of memory of 64-bit
+// system, like below.
+//
+// 512 * 512 * 512 * 512 * 1K * 64b * 4K
+// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
+// 63 54 45 36 27 17 11 0
+// 9b 9b 9b 9b 10b 6b 12b
+// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
+// 1FF 1FF 1FF 1FF 3FF 3F FFF
+//
+// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
+// memory. Each table of L0-L3 will be allocated when its memory address
+// range is to be tracked. Only 1-page will be allocated each time. This
+// can save memories used to establish this map table.
+//
+// For a normal configuration of system with 4G memory, two levels of tables
+// can track the whole memory, because two levels (L3+L4) of map tables have
+// already covered 37-bit of memory address. And for a normal UEFI BIOS,
+// less than 128M memory would be consumed during boot. That means we just
+// need
+//
+// 1-page (L3) + 2-page (L4)
+//
+// memory (3 pages) to track the memory allocation works. In this case,
+// there's no need to setup L0-L2 tables.
+//
+
+//
+// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
+// bits in address. (512 = 1 << 9)
+//
+#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
+
+#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
+ (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
+
+#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
+
+// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
+#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
+
+#define GUARDED_HEAP_MAP_ENTRY_BITS \
+ (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
+
+#define GUARDED_HEAP_MAP_ENTRY_BYTES \
+ (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
+
+// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
+#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_BITS \
+ - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
+ - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ - EFI_PAGE_SHIFT)
+
+// L4 table address mask: (1 << 10 - 1) = 0x3FF
+#define GUARDED_HEAP_MAP_ENTRY_MASK \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
+
+// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
+#define GUARDED_HEAP_MAP_SIZE \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
+#define GUARDED_HEAP_MAP_UNIT_SIZE \
+ (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
+
+// L4 table entry number: 8KB / 8 = 1024
+#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
+ (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// L4 table entry indexing
+#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
+ & GUARDED_HEAP_MAP_ENTRY_MASK)
+
+// L4 table entry bit indexing
+#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
+
+//
+// Total bits (pages) tracked by one L4 table (65536-bit)
+//
+#define GUARDED_HEAP_MAP_BITS \
+ (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
+
+//
+// Bit indexing inside the whole L4 table (0 - 65535)
+//
+#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
+
+//
+// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
+//
+#define GUARDED_HEAP_MAP_TABLE_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ + EFI_PAGE_SHIFT)
+
+//
+// Macro used to initialize the local array variable for map table traversing
+// {55, 46, 37, 28, 18}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
+ { \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT, \
+ EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ }
+
+//
+// Masks used to extract address range of each level of table
+// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
+ { \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
+ }
+
+//
+// Memory type to guard (matching the related PCD definition)
+//
+#define GUARD_HEAP_TYPE_PAGE BIT2
+#define GUARD_HEAP_TYPE_POOL BIT3
+
+//
+// Debug message level
+//
+#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
+
+typedef struct {
+ UINT32 TailMark;
+ UINT32 HeadMark;
+ EFI_PHYSICAL_ADDRESS Address;
+ LIST_ENTRY Link;
+} HEAP_GUARD_NODE;
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ );
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ );
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ );
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ );
+
+/**
+ Helper function of memory allocation with Guard pages.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+ @param MemoryType Type of memory requested.
+
+ @return Memory address of allocated pages.
+**/
+UINTN
+InternalAllocMaxAddressWithGuard (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress,
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Helper function of memory free with Guard pages.
+
+ @param[in] Memory Base address of memory being freed.
+ @param[in] NumberOfPages The number of pages to free.
+ @param[in] AddRegion If this memory is new added region.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or
+ NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+**/
+EFI_STATUS
+SmmInternalFreePagesExWithGuard (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ );
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ VOID
+ );
+
+/**
+ Debug function used to verify if the Guard page is well set or not.
+
+ @param[in] BaseAddress Address of memory to check.
+ @param[in] NumberOfPages Size of memory in pages.
+
+ @return TRUE The head Guard and tail Guard are both well set.
+ @return FALSE The head Guard and/or tail Guard are not well set.
+**/
+BOOLEAN
+VerifyMemoryGuard (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumberOfPages
+ );
+
+extern BOOLEAN mOnGuarding;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c
new file mode 100644
index 000000000..57f31fa98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c
@@ -0,0 +1,171 @@
+/** @file
+ System Management System Table Services SmmInstallConfigurationTable service
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mSmmSystemTableAllocateSize = 0;
+
+/**
+ The SmmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the SMM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallConfigurationTable (
+ IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigurationTable = gSmmCoreSmst.SmmConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gSmmCoreSmst.NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gSmmCoreSmst.NumberOfTableEntries) {
+ //
+ // A match was found, so this is either a modify or a delete operation
+ //
+ if (Table != NULL) {
+ //
+ // If Table is not NULL, then this is a modify operation.
+ // Modify the table entry and return.
+ //
+ ConfigurationTable[Index].VendorTable = Table;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gSmmCoreSmst.NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(ConfigurationTable[Index]),
+ &(ConfigurationTable[Index + 1]),
+ (gSmmCoreSmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ } else {
+ //
+ // No matching GUIDs were found, so this is an add operation.
+ //
+ if (Table == NULL) {
+ //
+ // If Table is NULL on an add operation, then return an error.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Assume that Index == gSmmCoreSmst.NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSmmSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mSmmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ ConfigurationTable = AllocatePool (mSmmSystemTableAllocateSize);
+ if (ConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gSmmCoreSmst.SmmConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ ConfigurationTable,
+ gSmmCoreSmst.SmmConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gSmmCoreSmst.SmmConfigurationTable;
+
+ //
+ // As the SmmInstallConfigurationTable() may be re-entered by FreePool() in
+ // its calling stack, updating System table to the new table pointer must
+ // be done before calling FreePool() to free the old table.
+ // It can make sure the gSmmCoreSmst.SmmConfigurationTable point to the new
+ // table and avoid the errors of use-after-free to the old table by the
+ // reenter of SmmInstallConfigurationTable() in FreePool()'s calling stack.
+ //
+ gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ FreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);
+ ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gSmmCoreSmst.NumberOfTableEntries++;
+ }
+
+ //
+ // CRC-32 field is ignorable for SMM System Table and should be set to zero
+ //
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Locate.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Locate.c
new file mode 100644
index 000000000..8458199ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Locate.c
@@ -0,0 +1,489 @@
+/** @file
+ Locate handle functions
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+//
+// ProtocolRequest - Last LocateHandle request ID
+//
+UINTN mEfiLocateHandleRequest = 0;
+
+//
+// Internal prototypes
+//
+
+typedef struct {
+ EFI_GUID *Protocol;
+ VOID *SearchKey;
+ LIST_ENTRY *Position;
+ PROTOCOL_ENTRY *ProtEntry;
+} LOCATE_POSITION;
+
+typedef
+IHANDLE *
+(* CORE_GET_NEXT) (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to search for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+SmmGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+
+ //
+ // Next handle
+ //
+ Position->Position = Position->Position->ForwardLink;
+
+ //
+ // If not at the end of the list, get the handle
+ //
+ Handle = NULL;
+ *Interface = NULL;
+ if (Position->Position != &gHandleList) {
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ }
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to search for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+SmmGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+
+ Handle = NULL;
+ *Interface = NULL;
+ ProtNotify = Position->SearchKey;
+
+ //
+ // If this is the first request, get the next handle
+ //
+ if (ProtNotify != NULL) {
+ ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
+ Position->SearchKey = NULL;
+
+ //
+ // If not at the end of the list, get the next handle
+ //
+ Link = ProtNotify->Position->ForwardLink;
+ if (Link != &ProtNotify->Protocol->Protocols) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+ }
+ }
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to search for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+SmmGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+ PROTOCOL_INTERFACE *Prot;
+
+ Handle = NULL;
+ *Interface = NULL;
+ for (; ;) {
+ //
+ // Next entry
+ //
+ Link = Position->Position->ForwardLink;
+ Position->Position = Link;
+
+ //
+ // If not at the end, return the handle
+ //
+ if (Link == &Position->ProtEntry->Protocols) {
+ Handle = NULL;
+ break;
+ }
+
+ //
+ // Get the handle
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+
+ //
+ // If this handle has not been returned this request, then
+ // return it now
+ //
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {
+ Handle->LocateRequest = mEfiLocateHandleRequest;
+ break;
+ }
+ }
+ return Handle;
+}
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is pasased in return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ IHANDLE *Handle;
+
+ if ((Interface == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Interface = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = Registration;
+ Position.Position = &gHandleList;
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = SmmGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);
+ }
+
+ if (Handle == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else if (Registration != NULL) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = Registration;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+
+ return Status;
+}
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ CORE_GET_NEXT GetNext;
+ UINTN ResultSize;
+ IHANDLE *Handle;
+ IHANDLE **ResultBuffer;
+ VOID *Interface;
+
+ if (BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*BufferSize > 0) && (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetNext = NULL;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = SearchKey;
+ Position.Position = &gHandleList;
+
+ ResultSize = 0;
+ ResultBuffer = (IHANDLE **) Buffer;
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the search function based on type
+ //
+ switch (SearchType) {
+ case AllHandles:
+ GetNext = SmmGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ GetNext = SmmGetNextLocateByRegisterNotify;
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ break;
+
+ case ByProtocol:
+ GetNext = SmmGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Enumerate out the matching handles
+ //
+ mEfiLocateHandleRequest += 1;
+ for (; ;) {
+ //
+ // Get the next handle. If no more handles, stop
+ //
+ Handle = GetNext (&Position, &Interface);
+ if (NULL == Handle) {
+ break;
+ }
+
+ //
+ // Increase the resulting buffer size, and if this handle
+ // fits return it
+ //
+ ResultSize += sizeof(Handle);
+ if (ResultSize <= *BufferSize) {
+ *ResultBuffer = Handle;
+ ResultBuffer += 1;
+ }
+ }
+
+ //
+ // If the result is a zero length buffer, then there were no
+ // matching handles
+ //
+ if (ResultSize == 0) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ //
+ // Return the resulting buffer size. If it's larger than what
+ // was passed, then set the error code
+ //
+ if (ResultSize > *BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ResultSize;
+
+ if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
+ ASSERT (SearchKey != NULL);
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of SmmLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if (NumberHandles == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = SmmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from SmmLocateHandle().
+ //
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ Status = EFI_NOT_FOUND;
+ }
+ return Status;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = SmmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR(Status)) {
+ *NumberHandles = 0;
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c
new file mode 100644
index 000000000..de8262ecb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c
@@ -0,0 +1,1368 @@
+/** @file
+ PI SMM MemoryAttributes support
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+
+#include <Guid/PiSmmMemoryAttributesTable.h>
+
+#include "PiSmmCore.h"
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS CodeSegmentBase;
+ UINT64 CodeSegmentSize;
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;
+
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINTN CodeSegmentCount;
+ LIST_ENTRY CodeSegmentList;
+} IMAGE_PROPERTIES_RECORD;
+
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN ImageRecordCount;
+ UINTN CodeSegmentCountMax;
+ LIST_ENTRY ImageRecordList;
+} IMAGE_PROPERTIES_PRIVATE_DATA;
+
+IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
+ IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
+ 0,
+ 0,
+ INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
+};
+
+#define EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA BIT0
+
+UINT64 mMemoryProtectionAttribute = EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA;
+
+//
+// Below functions are for MemoryMap
+//
+
+/**
+ Converts a number of EFI_PAGEs to a size in bytes.
+
+ NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
+
+ @param[in] Pages The number of EFI_PAGES.
+
+ @return The number of bytes associated with the number of EFI_PAGEs specified
+ by Pages.
+**/
+STATIC
+UINT64
+EfiPagesToSize (
+ IN UINT64 Pages
+ )
+{
+ return LShiftU64 (Pages, EFI_PAGE_SHIFT);
+}
+
+/**
+ Converts a size, in bytes, to a number of EFI_PAGESs.
+
+ NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
+
+ @param[in] Size A size in bytes.
+
+ @return The number of EFI_PAGESs associated with the number of bytes specified
+ by Size.
+
+**/
+STATIC
+UINT64
+EfiSizeToPages (
+ IN UINT64 Size
+ )
+{
+ return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
+}
+
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param[in,out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Merge continuous memory map entries whose have same attributes.
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
+ (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ if (NewMemoryMapEntry != MemoryMapEntry) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return ;
+}
+
+/**
+ Enforce memory map attributes.
+ This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+EnforceMemoryMapAttribute (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ if (MemoryMapEntry->Attribute != 0) {
+ // It is PE image, the attribute is already set.
+ } else {
+ switch (MemoryMapEntry->Type) {
+ case EfiRuntimeServicesCode:
+ MemoryMapEntry->Attribute = EFI_MEMORY_RO;
+ break;
+ case EfiRuntimeServicesData:
+ default:
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
+ break;
+ }
+ }
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
+
+ @param[in] Buffer Start Address
+ @param[in] Length Address length
+
+ @return first image record covered by [buffer, length]
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+GetImageRecordByAddress (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((Buffer <= ImageRecord->ImageBase) &&
+ (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Set the memory map to new entries, according to one old entry,
+ based upon PE code section and data section in image record
+
+ @param[in] ImageRecord An image record whose [ImageBase, ImageSize] covered
+ by old memory map entry.
+ @param[in, out] NewRecord A pointer to several new memory map entries.
+ The caller guarantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param[in] OldRecord A pointer to one old memory map entry.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+UINTN
+SetNewRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINTN NewRecordCount;
+ UINT64 PhysicalEnd;
+ UINT64 ImageEnd;
+
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+ NewRecordCount = 0;
+
+ //
+ // Always create a new entry for non-PE image record
+ //
+ if (ImageRecord->ImageBase > TempRecord.PhysicalStart) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecord->ImageBase - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute;
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ TempRecord.PhysicalStart = ImageRecord->ImageBase;
+ TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);
+ }
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ NewRecord->Type = EfiRuntimeServicesData;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ //
+ // CODE
+ //
+ NewRecord->Type = EfiRuntimeServicesCode;
+ NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);
+ NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));
+ TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);
+ if (TempRecord.NumberOfPages == 0) {
+ break;
+ }
+ }
+ }
+
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ //
+ // Final DATA
+ //
+ if (TempRecord.PhysicalStart < ImageEnd) {
+ NewRecord->Type = EfiRuntimeServicesData;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ NewRecordCount ++;
+ }
+
+ return NewRecordCount;
+}
+
+/**
+ Return the max number of new splitted entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param[in] OldRecord A pointer to one old memory map entry.
+
+ @retval 0 no entry need to be splitted.
+ @return the max number of new splitted entries
+**/
+STATIC
+UINTN
+GetMaxSplitRecordCount (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINTN SplitRecordCount;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+
+ SplitRecordCount = 0;
+ PhysicalStart = OldRecord->PhysicalStart;
+ PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);
+
+ do {
+ ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (ImageRecord == NULL) {
+ break;
+ }
+ SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 2);
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ return SplitRecordCount;
+}
+
+/**
+ Split the memory map to new entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param[in] OldRecord A pointer to one old memory map entry.
+ @param[in, out] NewRecord A pointer to several new memory map entries.
+ The caller guarantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param[in] MaxSplitRecordCount The max number of splitted entries
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+
+ @retval 0 no entry is splitted.
+ @return the real number of splitted record.
+**/
+STATIC
+UINTN
+SplitRecord (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN UINTN MaxSplitRecordCount,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NewImageRecord;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+ UINTN NewRecordCount;
+ UINTN TotalNewRecordCount;
+
+ if (MaxSplitRecordCount == 0) {
+ CopyMem (NewRecord, OldRecord, DescriptorSize);
+ return 0;
+ }
+
+ TotalNewRecordCount = 0;
+
+ //
+ // Override previous record
+ //
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalStart = TempRecord.PhysicalStart;
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+
+ ImageRecord = NULL;
+ do {
+ NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (NewImageRecord == NULL) {
+ //
+ // No more image covered by this range, stop
+ //
+ if (PhysicalEnd > PhysicalStart) {
+ //
+ // Always create a new entry for non-PE image record
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = TempRecord.NumberOfPages;
+ NewRecord->Attribute = TempRecord.Attribute;
+ TotalNewRecordCount ++;
+ }
+ break;
+ }
+ ImageRecord = NewImageRecord;
+
+ //
+ // Set new record
+ //
+ NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
+ TotalNewRecordCount += NewRecordCount;
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
+
+ //
+ // Update PhysicalStart, in order to exclude the image buffer already splitted.
+ //
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ TempRecord.PhysicalStart = PhysicalStart;
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ return TotalNewRecordCount - 1;
+}
+
+/**
+ Split the original memory map, and add more entries to describe PE code section and data section.
+ This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
+ This function will merge entries with same attributes finally.
+
+ NOTE: It assumes PE code/data section are page aligned.
+ NOTE: It assumes enough entry is prepared for new memory map.
+
+ Split table:
+ +---------------+
+ | Record X |
+ +---------------+
+ | Record RtCode |
+ +---------------+
+ | Record Y |
+ +---------------+
+ ==>
+ +---------------+
+ | Record X |
+ +---------------+
+ | Record RtCode |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF1
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record RtCode |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF2
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record RtCode |
+ +---------------+
+ | Record Y |
+ +---------------+
+
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ old MemoryMap before split. The actual buffer
+ size of MemoryMap is MemoryMapSize +
+ (AdditionalRecordCount * DescriptorSize) calculated
+ below. On output, it is the size of new MemoryMap
+ after split.
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SplitTable (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN DescriptorSize
+ )
+{
+ INTN IndexOld;
+ INTN IndexNew;
+ UINTN MaxSplitRecordCount;
+ UINTN RealSplitRecordCount;
+ UINTN TotalSplitRecordCount;
+ UINTN AdditionalRecordCount;
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 2) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ TotalSplitRecordCount = 0;
+ //
+ // Let old record point to end of valid MemoryMap buffer.
+ //
+ IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
+ //
+ // Let new record point to end of full MemoryMap buffer.
+ //
+ IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;
+ for (; IndexOld >= 0; IndexOld--) {
+ MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));
+ //
+ // Split this MemoryMap record
+ //
+ IndexNew -= MaxSplitRecordCount;
+ RealSplitRecordCount = SplitRecord (
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ MaxSplitRecordCount,
+ DescriptorSize
+ );
+ //
+ // Adjust IndexNew according to real split.
+ //
+ if (MaxSplitRecordCount != RealSplitRecordCount) {
+ CopyMem (
+ ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),
+ ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ (RealSplitRecordCount + 1) * DescriptorSize
+ );
+ }
+ IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;
+ TotalSplitRecordCount += RealSplitRecordCount;
+ IndexNew --;
+ }
+ //
+ // Move all records to the beginning.
+ //
+ CopyMem (
+ MemoryMap,
+ (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,
+ (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
+ );
+
+ *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
+
+ //
+ // Sort from low to high (Just in case)
+ //
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Set RuntimeData to XP
+ //
+ EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Merge same type to save entry size
+ //
+ MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);
+
+ return ;
+}
+
+/**
+ This function for GetMemoryMap() with memory attributes table.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data separation.
+
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[out] MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param[out] DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param[out] DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+SmmCoreGetMemoryMapMemoryAttributesTable (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN OldMemoryMapSize;
+ UINTN AdditionalRecordCount;
+
+ //
+ // If PE code/data is not aligned, just return.
+ //
+ if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
+ return SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ }
+
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 2) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ OldMemoryMapSize = *MemoryMapSize;
+ Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ } else if (Status == EFI_SUCCESS) {
+ if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ //
+ // Need update status to buffer too small
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Split PE code/data
+ //
+ ASSERT(MemoryMap != NULL);
+ SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);
+ }
+ }
+
+ return Status;
+}
+
+//
+// Below functions are for ImageRecord
+//
+
+/**
+ Set MemoryProtectionAttribute according to PE/COFF image section alignment.
+
+ @param[in] SectionAlignment PE/COFF section alignment
+**/
+STATIC
+VOID
+SetMemoryAttributesTableSectionAlignment (
+ IN UINT32 SectionAlignment
+ )
+{
+ if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) &&
+ ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {
+ DEBUG ((DEBUG_VERBOSE, "SMM SetMemoryAttributesTableSectionAlignment - Clear\n"));
+ mMemoryProtectionAttribute &= ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
+ }
+}
+
+/**
+ Swap two code sections in image record.
+
+ @param[in] FirstImageRecordCodeSection first code section in image record
+ @param[in] SecondImageRecordCodeSection second code section in image record
+**/
+STATIC
+VOID
+SwapImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
+
+ TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
+ TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
+
+ FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
+ FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
+
+ SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
+ SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
+}
+
+/**
+ Sort code section in image record, based upon CodeSegmentBase from low to high.
+
+ @param[in] ImageRecord image record to be sorted
+**/
+STATIC
+VOID
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *NextImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ NextImageRecordCodeSection = CR (
+ NextImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
+ SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
+ }
+ NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+}
+
+/**
+ Check if code section in image record is valid.
+
+ @param[in] ImageRecord image record to be checked
+
+ @retval TRUE image record is valid
+ @retval FALSE image record is invalid
+**/
+STATIC
+BOOLEAN
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ LastImageRecordCodeSection = NULL;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentSize == 0) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
+ return FALSE;
+ }
+ if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return FALSE;
+ }
+ if (LastImageRecordCodeSection != NULL) {
+ if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
+ return FALSE;
+ }
+ }
+
+ LastImageRecordCodeSection = ImageRecordCodeSection;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ return TRUE;
+}
+
+/**
+ Swap two image records.
+
+ @param[in] FirstImageRecord first image record.
+ @param[in] SecondImageRecord second image record.
+**/
+STATIC
+VOID
+SwapImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
+ IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD TempImageRecord;
+
+ TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
+ TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
+ TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
+
+ FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
+ FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
+ FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
+
+ SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
+ SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
+ SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
+
+ SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
+}
+
+/**
+ Sort image record based upon the ImageBase from low to high.
+**/
+STATIC
+VOID
+SortImageRecord (
+ VOID
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NextImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *NextImageRecordLink;
+ LIST_ENTRY *ImageRecordEndLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ ImageRecordLink = ImageRecordList->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ ImageRecordEndLink = ImageRecordList;
+ while (ImageRecordLink != ImageRecordEndLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ while (NextImageRecordLink != ImageRecordEndLink) {
+ NextImageRecord = CR (
+ NextImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
+ SwapImageRecord (ImageRecord, NextImageRecord);
+ }
+ NextImageRecordLink = NextImageRecordLink->ForwardLink;
+ }
+
+ ImageRecordLink = ImageRecordLink->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ }
+}
+
+/**
+ Dump image record.
+**/
+STATIC
+VOID
+DumpImageRecord (
+ VOID
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+ UINTN Index;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ DEBUG ((DEBUG_VERBOSE, "SMM Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));
+ }
+}
+
+/**
+ Insert image record.
+
+ @param[in] DriverEntry Driver information
+**/
+VOID
+SmmInsertImageRecord (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ VOID *ImageAddress;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ UINT32 SectionAlignment;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT8 *Name;
+ UINTN Index;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry));
+ DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%016lx - 0x%08x\n", DriverEntry->ImageBuffer, DriverEntry->NumberOfPage));
+
+ ImageRecord = AllocatePool (sizeof(*ImageRecord));
+ if (ImageRecord == NULL) {
+ return ;
+ }
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
+
+ //
+ // Step 1: record whole region
+ //
+ ImageRecord->ImageBase = DriverEntry->ImageBuffer;
+ ImageRecord->ImageSize = EfiPagesToSize(DriverEntry->NumberOfPage);
+
+ ImageAddress = (VOID *)(UINTN)DriverEntry->ImageBuffer;
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer));
+ }
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "SMM Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ goto Finish;
+ }
+
+ //
+ // Get SectionAlignment
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ SetMemoryAttributesTableSectionAlignment (SectionAlignment);
+ if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG ((DEBUG_WARN, "SMM !!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",
+ SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_WARN, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "SMM Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
+ DEBUG ((DEBUG_VERBOSE, "SMM VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, "SMM VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, "SMM SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, "SMM NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, "SMM NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, "SMM Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ //
+ // Step 2: record code section
+ //
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ return ;
+ }
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
+ ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
+
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ SetMemoryAttributesTableSectionAlignment (1);
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ //
+ // Final
+ //
+ SortImageRecordCodeSection (ImageRecord);
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n"));
+ goto Finish;
+ }
+
+ InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
+ mImagePropertiesPrivateData.ImageRecordCount++;
+
+ if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
+ mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
+ }
+
+ SortImageRecord ();
+
+Finish:
+ return ;
+}
+
+
+/**
+ Publish MemoryAttributesTable to SMM configuration table.
+**/
+VOID
+PublishMemoryAttributesTable (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN RuntimeEntryCount;
+ EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
+ EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
+ UINTN MemoryAttributesTableSize;
+
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ Status = SmmCoreGetMemoryMapMemoryAttributesTable (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ DEBUG ((DEBUG_INFO, "MemoryMapSize - 0x%x\n", MemoryMapSize));
+ MemoryMap = AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ DEBUG ((DEBUG_INFO, "MemoryMap - 0x%x\n", MemoryMap));
+
+ Status = SmmCoreGetMemoryMapMemoryAttributesTable (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ //
+ // Allocate MemoryAttributesTable
+ //
+ RuntimeEntryCount = MemoryMapSize/DescriptorSize;
+ MemoryAttributesTableSize = sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount;
+ MemoryAttributesTable = AllocatePool (sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
+ ASSERT (MemoryAttributesTable != NULL);
+ MemoryAttributesTable->Version = EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION;
+ MemoryAttributesTable->NumberOfEntries = (UINT32)RuntimeEntryCount;
+ MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
+ MemoryAttributesTable->Reserved = 0;
+ DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));
+ DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));
+ DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
+ DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
+ MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
+ DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryAttributesEntry));
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryAttributesEntry->Type));
+ DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
+ DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
+ DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
+ DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));
+ MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
+ }
+
+ Status = gSmst->SmmInstallConfigurationTable (gSmst, &gEdkiiPiSmmMemoryAttributesTableGuid, MemoryAttributesTable, MemoryAttributesTableSize);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ This function installs all SMM image record information.
+**/
+VOID
+SmmInstallImageRecord (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN Index;
+ EFI_SMM_DRIVER_ENTRY DriverEntry;
+
+ Status = SmmLocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gSmst->SmmHandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize));
+ {
+ VOID *PdbPointer;
+ PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer));
+ }
+ }
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+ ZeroMem (&DriverEntry, sizeof(DriverEntry));
+ DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase;
+ DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES((UINTN)LoadedImage->ImageSize);
+ SmmInsertImageRecord (&DriverEntry);
+ }
+
+ FreePool (HandleBuffer);
+}
+
+/**
+ Install MemoryAttributesTable.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallMemoryAttributesTable (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ SmmInstallImageRecord ();
+
+ DEBUG ((DEBUG_INFO, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute));
+ if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "SMM Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
+ DEBUG ((DEBUG_VERBOSE, "SMM Dump ImageRecord:\n"));
+ DumpImageRecord ();
+
+ PublishMemoryAttributesTable ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize MemoryAttributesTable support.
+**/
+VOID
+EFIAPI
+SmmCoreInitializeMemoryAttributesTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmInstallMemoryAttributesTable,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Notify.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Notify.c
new file mode 100644
index 000000000..8e078f757
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Notify.c
@@ -0,0 +1,196 @@
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+SmmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ProtEntry = Prot->Protocol;
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
+ }
+}
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+SmmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = SmmFindProtocolInterface (Handle, Protocol, Interface);
+ if (Prot != NULL) {
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // If there's a protocol notify location pointing to this entry, back it up one
+ //
+ for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Position == &Prot->ByProtocol) {
+ ProtNotify->Position = Prot->ByProtocol.BackLink;
+ }
+ }
+
+ //
+ // Remove the protocol interface entry
+ //
+ RemoveEntryList (&Prot->ByProtocol);
+ }
+
+ return Prot;
+}
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Function Points to the notification function
+ @param Registration Returns the registration record
+
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added or unhooked
+ @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL
+ @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request
+ @retval EFI_NOT_FOUND If the registration is not found when Function == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_SMM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (Protocol == NULL || Registration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Function == NULL) {
+ //
+ // Get the protocol entry per Protocol
+ //
+ ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+ //
+ // Compare the notification record
+ //
+ if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){
+ //
+ // If Registration is an existing registration, then unhook it
+ //
+ ProtNotify->Signature = 0;
+ RemoveEntryList (&ProtNotify->Link);
+ FreePool (ProtNotify);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ //
+ // If the registration is not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+ ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
+ if (ProtEntry != NULL) {
+ //
+ // Find whether notification already exist
+ //
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
+ (ProtNotify->Function == Function)) {
+
+ //
+ // Notification already exist
+ //
+ *Registration = ProtNotify;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Function = Function;
+ //
+ // Start at the ending
+ //
+ ProtNotify->Position = ProtEntry->Protocols.BackLink;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ //
+ // Done. If we have a protocol notify entry, then return it.
+ // Otherwise, we must have run out of resources trying to add one
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ if (ProtNotify != NULL) {
+ *Registration = ProtNotify;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Page.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Page.c
new file mode 100644
index 000000000..d886187d9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Page.c
@@ -0,0 +1,1071 @@
+/** @file
+ SMM Memory page management functions.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+#include <Library/SmmServicesTableLib.h>
+
+#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
+
+LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);
+
+//
+// For GetMemoryMap()
+//
+
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ BOOLEAN FromStack;
+ EFI_MEMORY_TYPE Type;
+ UINT64 Start;
+ UINT64 End;
+
+} MEMORY_MAP;
+
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
+
+
+#define MAX_MAP_DEPTH 6
+
+///
+/// mMapDepth - depth of new descriptor stack
+///
+UINTN mMapDepth = 0;
+///
+/// mMapStack - space to use as temp storage to build new map descriptors
+///
+MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
+UINTN mFreeMapStack = 0;
+///
+/// This list maintain the free memory map list
+///
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
+
+/**
+ Allocates pages from the memory map.
+
+ @param[in] Type The type of allocation to perform.
+ @param[in] MemoryType The type of memory to turn the allocated pages
+ into.
+ @param[in] NumberOfPages The number of pages to allocate.
+ @param[out] Memory A pointer to receive the base allocated memory
+ address.
+ @param[in] AddRegion If this memory is new added region.
+ @param[in] NeedGuard Flag to indicate Guard page is needed
+ or not
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+SmmInternalAllocatePagesEx (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN AddRegion,
+ IN BOOLEAN NeedGuard
+ );
+
+/**
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
+ If the list is emtry, then allocate a new page to refuel the list.
+ Please Note this algorithm to allocate the memory map descriptor has a property
+ that the memory allocated for memory entries always grows, and will never really be freed.
+
+ @return The Memory map descriptor dequeued from the mFreeMemoryMapEntryList
+
+**/
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS Mem;
+ EFI_STATUS Status;
+ MEMORY_MAP* FreeDescriptorEntries;
+ MEMORY_MAP* Entry;
+ UINTN Index;
+
+ //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));
+
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {
+ //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));
+ //
+ // The list is empty, to allocate one page to refuel the list
+ //
+ Status = SmmInternalAllocatePagesEx (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
+ &Mem,
+ TRUE,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ if(!EFI_ERROR (Status)) {
+ FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;
+ //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));
+ //
+ // Enqueue the free memory map entries into the list
+ //
+ for (Index = 0; Index< RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
+ }
+ } else {
+ return NULL;
+ }
+ }
+ //
+ // dequeue the first descriptor from the list
+ //
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ RemoveEntryList (&Entry->Link);
+
+ return Entry;
+}
+
+
+/**
+ Internal function. Moves any memory descriptors that are on the
+ temporary descriptor stack to heap.
+
+**/
+VOID
+CoreFreeMemoryMapStack (
+ VOID
+ )
+{
+ MEMORY_MAP *Entry;
+
+ //
+ // If already freeing the map stack, then return
+ //
+ if (mFreeMapStack != 0) {
+ ASSERT (FALSE);
+ return ;
+ }
+
+ //
+ // Move the temporary memory descriptor stack into pool
+ //
+ mFreeMapStack += 1;
+
+ while (mMapDepth != 0) {
+ //
+ // Deque an memory map entry from mFreeMemoryMapEntryList
+ //
+ Entry = AllocateMemoryMapEntry ();
+ ASSERT (Entry);
+
+ //
+ // Update to proper entry
+ //
+ mMapDepth -= 1;
+
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
+
+ CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
+ Entry->FromStack = FALSE;
+
+ //
+ // Move this entry to general memory
+ //
+ InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);
+ RemoveEntryList (&mMapStack[mMapDepth].Link);
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;
+ }
+ }
+
+ mFreeMapStack -= 1;
+}
+
+/**
+ Insert new entry from memory map.
+
+ @param[in] Link The old memory map entry to be linked.
+ @param[in] Start The start address of new memory map entry.
+ @param[in] End The end address of new memory map entry.
+ @param[in] Type The type of new memory map entry.
+ @param[in] Next If new entry is inserted to the next of old entry.
+ @param[in] AddRegion If this memory is new added region.
+**/
+VOID
+InsertNewEntry (
+ IN LIST_ENTRY *Link,
+ IN UINT64 Start,
+ IN UINT64 End,
+ IN EFI_MEMORY_TYPE Type,
+ IN BOOLEAN Next,
+ IN BOOLEAN AddRegion
+ )
+{
+ MEMORY_MAP *Entry;
+
+ Entry = &mMapStack[mMapDepth];
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+ Entry->FromStack = TRUE;
+
+ Entry->Signature = MEMORY_MAP_SIGNATURE;
+ Entry->Type = Type;
+ Entry->Start = Start;
+ Entry->End = End;
+ if (Next) {
+ InsertHeadList (Link, &Entry->Link);
+ } else {
+ InsertTailList (Link, &Entry->Link);
+ }
+}
+
+/**
+ Remove old entry from memory map.
+
+ @param[in] Entry Memory map entry to be removed.
+**/
+VOID
+RemoveOldEntry (
+ IN MEMORY_MAP *Entry
+ )
+{
+ RemoveEntryList (&Entry->Link);
+ Entry->Link.ForwardLink = NULL;
+
+ if (!Entry->FromStack) {
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+}
+
+/**
+ Update SMM memory map entry.
+
+ @param[in] Type The type of allocation to perform.
+ @param[in] Memory The base of memory address.
+ @param[in] NumberOfPages The number of pages to allocate.
+ @param[in] AddRegion If this memory is new added region.
+**/
+VOID
+ConvertSmmMemoryMapEntry (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ )
+{
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ MEMORY_MAP *NextEntry;
+ LIST_ENTRY *NextLink;
+ MEMORY_MAP *PreviousEntry;
+ LIST_ENTRY *PreviousLink;
+ EFI_PHYSICAL_ADDRESS Start;
+ EFI_PHYSICAL_ADDRESS End;
+
+ Start = Memory;
+ End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;
+
+ //
+ // Exclude memory region
+ //
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ //
+ // ---------------------------------------------------
+ // | +----------+ +------+ +------+ +------+ |
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
+ // +----------+ ^ +------+ +------+ +------+
+ // |
+ // +------+
+ // |EntryX|
+ // +------+
+ //
+ if (Entry->Start > End) {
+ if ((Entry->Start == End + 1) && (Entry->Type == Type)) {
+ Entry->Start = Start;
+ return ;
+ }
+ InsertNewEntry (
+ &Entry->Link,
+ Start,
+ End,
+ Type,
+ FALSE,
+ AddRegion
+ );
+ return ;
+ }
+
+ if ((Entry->Start <= Start) && (Entry->End >= End)) {
+ if (Entry->Type != Type) {
+ if (Entry->Start < Start) {
+ //
+ // ---------------------------------------------------
+ // | +----------+ +------+ +------+ +------+ |
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
+ // +----------+ +------+ ^ +------+ +------+
+ // |
+ // +------+
+ // |EntryA|
+ // +------+
+ //
+ InsertNewEntry (
+ &Entry->Link,
+ Entry->Start,
+ Start - 1,
+ Entry->Type,
+ FALSE,
+ AddRegion
+ );
+ }
+ if (Entry->End > End) {
+ //
+ // ---------------------------------------------------
+ // | +----------+ +------+ +------+ +------+ |
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
+ // +----------+ +------+ +------+ ^ +------+
+ // |
+ // +------+
+ // |EntryZ|
+ // +------+
+ //
+ InsertNewEntry (
+ &Entry->Link,
+ End + 1,
+ Entry->End,
+ Entry->Type,
+ TRUE,
+ AddRegion
+ );
+ }
+ //
+ // Update this node
+ //
+ Entry->Start = Start;
+ Entry->End = End;
+ Entry->Type = Type;
+
+ //
+ // Check adjacent
+ //
+ NextLink = Entry->Link.ForwardLink;
+ if (NextLink != &gMemoryMap) {
+ NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ //
+ // ---------------------------------------------------
+ // | +----------+ +------+ +-----------------+ |
+ // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---
+ // +----------+ +------+ +-----------------+
+ //
+ if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {
+ Entry->End = NextEntry->End;
+ RemoveOldEntry (NextEntry);
+ }
+ }
+ PreviousLink = Entry->Link.BackLink;
+ if (PreviousLink != &gMemoryMap) {
+ PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ //
+ // ---------------------------------------------------
+ // | +----------+ +-----------------+ +------+ |
+ // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---
+ // +----------+ +-----------------+ +------+
+ //
+ if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {
+ PreviousEntry->End = Entry->End;
+ RemoveOldEntry (Entry);
+ }
+ }
+ }
+ return ;
+ }
+ }
+
+ //
+ // ---------------------------------------------------
+ // | +----------+ +------+ +------+ +------+ |
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
+ // +----------+ +------+ +------+ +------+ ^
+ // |
+ // +------+
+ // |EntryX|
+ // +------+
+ //
+ Link = gMemoryMap.BackLink;
+ if (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {
+ Entry->End = End;
+ return ;
+ }
+ }
+ InsertNewEntry (
+ &gMemoryMap,
+ Start,
+ End,
+ Type,
+ FALSE,
+ AddRegion
+ );
+ return ;
+}
+
+/**
+ Return the count of Smm memory map entry.
+
+ @return The count of Smm memory map entry.
+**/
+UINTN
+GetSmmMemoryMapEntryCount (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN Count;
+
+ Count = 0;
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Link = Link->ForwardLink;
+ Count++;
+ }
+ return Count;
+}
+
+
+
+/**
+ Internal Function. Allocate n pages from given free page node.
+
+ @param Pages The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocPagesOnOneNode (
+ IN OUT FREE_PAGE_LIST *Pages,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ UINTN Top;
+ UINTN Bottom;
+ FREE_PAGE_LIST *Node;
+
+ Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
+ if (Top > Pages->NumberOfPages) {
+ Top = Pages->NumberOfPages;
+ }
+ Bottom = Top - NumberOfPages;
+
+ if (Top < Pages->NumberOfPages) {
+ Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
+ Node->NumberOfPages = Pages->NumberOfPages - Top;
+ InsertHeadList (&Pages->Link, &Node->Link);
+ }
+
+ if (Bottom > 0) {
+ Pages->NumberOfPages = Bottom;
+ } else {
+ RemoveEntryList (&Pages->Link);
+ }
+
+ return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list below MaxAddress.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocMaxAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Pages->NumberOfPages >= NumberOfPages &&
+ (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
+ }
+ }
+ return (UINTN)(-1);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list at given address.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN Address
+ )
+{
+ UINTN EndAddress;
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if ((Address & EFI_PAGE_MASK) != 0) {
+ return ~Address;
+ }
+
+ EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
+ for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages <= Address) {
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
+ break;
+ }
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
+ }
+ }
+ return ~Address;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param[in] Type The type of allocation to perform.
+ @param[in] MemoryType The type of memory to turn the allocated pages
+ into.
+ @param[in] NumberOfPages The number of pages to allocate.
+ @param[out] Memory A pointer to receive the base allocated memory
+ address.
+ @param[in] AddRegion If this memory is new added region.
+ @param[in] NeedGuard Flag to indicate Guard page is needed
+ or not
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+SmmInternalAllocatePagesEx (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN AddRegion,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINTN RequestedAddress;
+
+ if (MemoryType != EfiRuntimeServicesCode &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // We don't track memory type in SMM
+ //
+ RequestedAddress = (UINTN)*Memory;
+ switch (Type) {
+ case AllocateAnyPages:
+ RequestedAddress = (UINTN)(-1);
+ case AllocateMaxAddress:
+ if (NeedGuard) {
+ *Memory = InternalAllocMaxAddressWithGuard (
+ &mSmmMemoryMap,
+ NumberOfPages,
+ RequestedAddress,
+ MemoryType
+ );
+ if (*Memory == (UINTN)-1) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
+ return EFI_SUCCESS;
+ }
+ }
+
+ *Memory = InternalAllocMaxAddress (
+ &mSmmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory == (UINTN)-1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ break;
+ case AllocateAddress:
+ *Memory = InternalAllocAddress (
+ &mSmmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory != RequestedAddress) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update SmmMemoryMap here.
+ //
+ ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);
+ if (!AddRegion) {
+ CoreFreeMemoryMapStack();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param[in] Type The type of allocation to perform.
+ @param[in] MemoryType The type of memory to turn the allocated pages
+ into.
+ @param[in] NumberOfPages The number of pages to allocate.
+ @param[out] Memory A pointer to receive the base allocated memory
+ address.
+ @param[in] NeedGuard Flag to indicate Guard page is needed
+ or not
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ )
+{
+ return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,
+ FALSE, NeedGuard);
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform.
+ @param MemoryType The type of memory to turn the allocated pages
+ into.
+ @param NumberOfPages The number of pages to allocate.
+ @param Memory A pointer to receive the base allocated memory
+ address.
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ NeedGuard = IsPageTypeToGuard (MemoryType, Type);
+ Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
+ NeedGuard);
+ if (!EFI_ERROR (Status)) {
+ SmmCoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) *Memory,
+ NULL
+ );
+ }
+ return Status;
+}
+
+/**
+ Internal Function. Merge two adjacent nodes.
+
+ @param First The first of two nodes to merge.
+
+ @return Pointer to node after merge (if success) or pointer to next node (if fail).
+
+**/
+FREE_PAGE_LIST *
+InternalMergeNodes (
+ IN FREE_PAGE_LIST *First
+ )
+{
+ FREE_PAGE_LIST *Next;
+
+ Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
+ ASSERT (
+ TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);
+
+ if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
+ First->NumberOfPages += Next->NumberOfPages;
+ RemoveEntryList (&Next->Link);
+ Next = First;
+ }
+ return Next;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param[in] Memory Base address of memory being freed.
+ @param[in] NumberOfPages The number of pages to free.
+ @param[in] AddRegion If this memory is new added region.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+SmmInternalFreePagesEx (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Pages = NULL;
+ Node = mSmmMemoryMap.ForwardLink;
+ while (Node != &mSmmMemoryMap) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Memory < (UINTN)Pages) {
+ break;
+ }
+ Node = Node->ForwardLink;
+ }
+
+ if (Node != &mSmmMemoryMap &&
+ Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Node->BackLink != &mSmmMemoryMap) {
+ Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Pages = (FREE_PAGE_LIST*)(UINTN)Memory;
+ Pages->NumberOfPages = NumberOfPages;
+ InsertTailList (Node, &Pages->Link);
+
+ if (Pages->Link.BackLink != &mSmmMemoryMap) {
+ Pages = InternalMergeNodes (
+ BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
+ );
+ }
+
+ if (Node != &mSmmMemoryMap) {
+ InternalMergeNodes (Pages);
+ }
+
+ //
+ // Update SmmMemoryMap here.
+ //
+ ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);
+ if (!AddRegion) {
+ CoreFreeMemoryMapStack();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param[in] Memory Base address of memory being freed.
+ @param[in] NumberOfPages The number of pages to free.
+ @param[in] IsGuarded Is the memory to free guarded or not.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN IsGuarded
+ )
+{
+ if (IsGuarded) {
+ return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
+ }
+ return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
+}
+
+/**
+ Check whether the input range is in memory map.
+
+ @param Memory Base address of memory being inputed.
+ @param NumberOfPages The number of pages.
+
+ @retval TRUE In memory map.
+ @retval FALSE Not in memory map.
+
+**/
+BOOLEAN
+InMemMap (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ EFI_PHYSICAL_ADDRESS Last;
+
+ Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;
+
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ if ((Entry->Start <= Memory) && (Entry->End >= Last)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed.
+ @param NumberOfPages The number of pages to free.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsGuarded;
+
+ if (!InMemMap(Memory, NumberOfPages)) {
+ return EFI_NOT_FOUND;
+ }
+
+ IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
+ Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
+ if (!EFI_ERROR (Status)) {
+ SmmCoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePages,
+ EfiMaxMemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) Memory,
+ NULL
+ );
+ }
+ return Status;
+}
+
+/**
+ Add free SMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+SmmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ )
+{
+ UINTN AlignedMemBase;
+
+ //
+ // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
+ //
+ if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ Type = EfiRuntimeServicesData;
+ } else {
+ Type = EfiConventionalMemory;
+ }
+
+ DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));
+ DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));
+ DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));
+
+ //
+ // Align range on an EFI_PAGE_SIZE boundary
+ //
+ AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ MemLength -= AlignedMemBase - MemBase;
+ if (Type == EfiConventionalMemory) {
+ SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
+ } else {
+ ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
+ }
+
+ CoreFreeMemoryMapStack ();
+}
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[out] MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param[out] DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param[out] DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ UINTN Size;
+ UINTN BufferSize;
+
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);
+
+ //
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ Size += sizeof(UINT64) - (Size % sizeof (UINT64));
+
+ if (DescriptorSize != NULL) {
+ *DescriptorSize = Size;
+ }
+
+ if (DescriptorVersion != NULL) {
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
+ }
+
+ Count = GetSmmMemoryMapEntryCount ();
+ BufferSize = Size * Count;
+ if (*MemoryMapSize < BufferSize) {
+ *MemoryMapSize = BufferSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *MemoryMapSize = BufferSize;
+ if (MemoryMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (MemoryMap, BufferSize);
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ MemoryMap->Type = Entry->Type;
+ MemoryMap->PhysicalStart = Entry->Start;
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
new file mode 100644
index 000000000..cfa9922cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
@@ -0,0 +1,920 @@
+/** @file
+ SMM Core Main Entry Point
+
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+//
+// Physical pointer to private structure shared between SMM IPL and the SMM Core
+//
+SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;
+
+//
+// SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM.
+//
+EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = {
+ {
+ SMM_SMST_SIGNATURE,
+ EFI_SMM_SYSTEM_TABLE2_REVISION,
+ sizeof (gSmmCoreSmst.Hdr)
+ },
+ NULL, // SmmFirmwareVendor
+ 0, // SmmFirmwareRevision
+ SmmInstallConfigurationTable,
+ {
+ {
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5, // SmmMemRead
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5 // SmmMemWrite
+ },
+ {
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5, // SmmIoRead
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5 // SmmIoWrite
+ }
+ },
+ SmmAllocatePool,
+ SmmFreePool,
+ SmmAllocatePages,
+ SmmFreePages,
+ NULL, // SmmStartupThisAp
+ 0, // CurrentlyExecutingCpu
+ 0, // NumberOfCpus
+ NULL, // CpuSaveStateSize
+ NULL, // CpuSaveState
+ 0, // NumberOfTableEntries
+ NULL, // SmmConfigurationTable
+ SmmInstallProtocolInterface,
+ SmmUninstallProtocolInterface,
+ SmmHandleProtocol,
+ SmmRegisterProtocolNotify,
+ SmmLocateHandle,
+ SmmLocateProtocol,
+ SmiManage,
+ SmiHandlerRegister,
+ SmiHandlerUnRegister
+};
+
+//
+// Flag to determine if the platform has performed a legacy boot.
+// If this flag is TRUE, then the runtime code and runtime data associated with the
+// SMM IPL are converted to free memory, so the SMM Core must guarantee that is
+// does not touch of the code/data associated with the SMM IPL if this flag is TRUE.
+//
+BOOLEAN mInLegacyBoot = FALSE;
+
+//
+// Flag to determine if it is during S3 resume.
+// It will be set in S3 entry callback and cleared at EndOfS3Resume.
+//
+BOOLEAN mDuringS3Resume = FALSE;
+
+//
+// Flag to determine if platform enabled S3.
+// Get the value from PcdAcpiS3Enable.
+//
+BOOLEAN mAcpiS3Enable = FALSE;
+
+//
+// Table of SMI Handlers that are registered by the SMM Core when it is initialized
+//
+SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = {
+ { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE },
+ { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, TRUE },
+ { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE },
+ { SmmExitBootServicesHandler, &gEfiEventExitBootServicesGuid, NULL, FALSE },
+ { SmmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE },
+ { SmmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, TRUE },
+ { NULL, NULL, NULL, FALSE }
+};
+
+//
+// Table of SMI Handlers that are registered by the SMM Core when it is initialized
+//
+SMM_CORE_SMI_HANDLERS mSmmCoreS3SmiHandlers[] = {
+ { SmmS3SmmInitDoneHandler, &gEdkiiS3SmmInitDoneGuid, NULL, FALSE },
+ { SmmEndOfS3ResumeHandler, &gEdkiiEndOfS3ResumeGuid, NULL, FALSE },
+ { NULL, NULL, NULL, FALSE }
+};
+
+UINTN mFullSmramRangeCount;
+EFI_SMRAM_DESCRIPTOR *mFullSmramRanges;
+
+EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;
+
+EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;
+
+/**
+ Place holder function until all the SMM System Table Service are available.
+
+ Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Software SMI handler that is called when a Legacy Boot event is signalled. The SMM
+ Core uses this signal to know that a Legacy Boot has been performed and that
+ gSmmCorePrivate that is shared between the UEFI and SMM execution environments can
+ not be accessed from SMM anymore since that structure is considered free memory by
+ a legacy OS. Then the SMM Core also install SMM Legacy Boot protocol to notify SMM
+ driver that system enter legacy boot.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLegacyBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+ UINTN Index;
+
+ //
+ // Install SMM Legacy Boot protocol.
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEdkiiSmmLegacyBootProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ mInLegacyBoot = TRUE;
+
+ SmiHandlerUnRegister (DispatchHandle);
+
+ //
+ // It is legacy boot, unregister ExitBootService SMI handler.
+ //
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
+ if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventExitBootServicesGuid)) {
+ SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Software SMI handler that is called when an Exit Boot Services event is signalled.
+ Then the SMM Core also install SMM Exit Boot Services protocol to notify SMM driver
+ that system enter exit boot services.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmExitBootServicesHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+ UINTN Index;
+
+ //
+ // Install SMM Exit Boot Services protocol.
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ SmiHandlerUnRegister (DispatchHandle);
+
+ //
+ // It is UEFI boot, unregister LegacyBoot SMI handler.
+ //
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
+ if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventLegacyBootGuid)) {
+ SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Main entry point for an SMM handler dispatch or communicate-based callback.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in,out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmS3EntryCallBack (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ mDuringS3Resume = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Software SMI handler that is called when an Ready To Boot event is signalled.
+ Then the SMM Core also install SMM Ready To Boot protocol to notify SMM driver
+ that system enter ready to boot.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+
+ //
+ // Install SMM Ready To Boot protocol.
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEdkiiSmmReadyToBootProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ SmiHandlerUnRegister (DispatchHandle);
+
+ return Status;
+}
+
+/**
+ Software SMI handler that is called when the DxeSmmReadyToLock protocol is added
+ or if gEfiEventReadyToBootGuid is signalled. This function unregisters the
+ Software SMIs that are nor required after SMRAM is locked and installs the
+ SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about
+ to be locked. It also verifies the SMM CPU I/O 2 Protocol has been installed
+ and NULLs gBS and gST because they can not longer be used after SMRAM is locked.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE SmmHandle;
+ VOID *Interface;
+
+ //
+ // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped
+ //
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
+ if (mSmmCoreSmiHandlers[Index].UnRegister) {
+ SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
+ }
+ }
+
+ //
+ // Install SMM Ready to lock protocol
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEfiSmmReadyToLockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Make sure SMM CPU I/O 2 Protocol has been installed into the handle database
+ //
+ Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface);
+
+ //
+ // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Assert if the CPU I/O 2 Protocol is not installed
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ DEBUG_CODE_BEGIN ();
+ SmmDisplayDiscoveredNotDispatched ();
+ DEBUG_CODE_END ();
+
+ //
+ // Not allowed to use gST or gBS after lock
+ //
+ gST = NULL;
+ gBS = NULL;
+
+ SmramProfileReadyToLock ();
+
+ return Status;
+}
+
+/**
+ Software SMI handler that is called when the EndOfDxe event is signalled.
+ This function installs the SMM EndOfDxe Protocol so SMM Drivers are informed that
+ platform code will invoke 3rd part code.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+ EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
+ EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
+ EFI_HANDLE S3EntryHandle;
+
+ DEBUG ((EFI_D_INFO, "SmmEndOfDxeHandler\n"));
+
+ //
+ // Install SMM EndOfDxe protocol
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEfiSmmEndOfDxeProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ if (mAcpiS3Enable) {
+ //
+ // Locate SmmSxDispatch2 protocol.
+ //
+ Status = SmmLocateProtocol (
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ NULL,
+ (VOID **)&SxDispatch
+ );
+ if (!EFI_ERROR (Status) && (SxDispatch != NULL)) {
+ //
+ // Register a S3 entry callback function to
+ // determine if it will be during S3 resume.
+ //
+ EntryRegisterContext.Type = SxS3;
+ EntryRegisterContext.Phase = SxEntry;
+ Status = SxDispatch->Register (
+ SxDispatch,
+ SmmS3EntryCallBack,
+ &EntryRegisterContext,
+ &S3EntryHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Software SMI handler that is called when the S3SmmInitDone signal is triggered.
+ This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that
+ S3 SMM initialization has been done.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmS3SmmInitDoneHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+
+ DEBUG ((DEBUG_INFO, "SmmS3SmmInitDoneHandler\n"));
+
+ if (!mDuringS3Resume) {
+ DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Install SMM S3SmmInitDone protocol
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEdkiiS3SmmInitDoneGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Uninstall the protocol here because the comsumer just hook the
+ // installation event.
+ //
+ Status = SmmUninstallProtocolInterface (
+ SmmHandle,
+ &gEdkiiS3SmmInitDoneGuid,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Software SMI handler that is called when the EndOfS3Resume signal is triggered.
+ This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that
+ S3 resume has finished.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfS3ResumeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SmmHandle;
+
+ DEBUG ((DEBUG_INFO, "SmmEndOfS3ResumeHandler\n"));
+
+ if (!mDuringS3Resume) {
+ DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Install SMM EndOfS3Resume protocol
+ //
+ SmmHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &SmmHandle,
+ &gEdkiiEndOfS3ResumeGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Uninstall the protocol here because the consumer just hook the
+ // installation event.
+ //
+ Status = SmmUninstallProtocolInterface (
+ SmmHandle,
+ &gEdkiiEndOfS3ResumeGuid,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mDuringS3Resume = FALSE;
+ return Status;
+}
+
+/**
+ Determine if two buffers overlap in memory.
+
+ @param[in] Buff1 Pointer to first buffer
+ @param[in] Size1 Size of Buff1
+ @param[in] Buff2 Pointer to second buffer
+ @param[in] Size2 Size of Buff2
+
+ @retval TRUE Buffers overlap in memory.
+ @retval FALSE Buffer doesn't overlap.
+
+**/
+BOOLEAN
+InternalIsBufferOverlapped (
+ IN UINT8 *Buff1,
+ IN UINTN Size1,
+ IN UINT8 *Buff2,
+ IN UINTN Size2
+ )
+{
+ //
+ // If buff1's end is less than the start of buff2, then it's ok.
+ // Also, if buff1's start is beyond buff2's end, then it's ok.
+ //
+ if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ The main entry point to SMM Foundation.
+
+ Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.
+
+ @param SmmEntryContext Processor information and functionality
+ needed by SMM Foundation.
+
+**/
+VOID
+EFIAPI
+SmmEntryPoint (
+ IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext
+)
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
+ BOOLEAN InLegacyBoot;
+ BOOLEAN IsOverlapped;
+ VOID *CommunicationBuffer;
+ UINTN BufferSize;
+
+ //
+ // Update SMST with contents of the SmmEntryContext structure
+ //
+ gSmmCoreSmst.SmmStartupThisAp = SmmEntryContext->SmmStartupThisAp;
+ gSmmCoreSmst.CurrentlyExecutingCpu = SmmEntryContext->CurrentlyExecutingCpu;
+ gSmmCoreSmst.NumberOfCpus = SmmEntryContext->NumberOfCpus;
+ gSmmCoreSmst.CpuSaveStateSize = SmmEntryContext->CpuSaveStateSize;
+ gSmmCoreSmst.CpuSaveState = SmmEntryContext->CpuSaveState;
+
+ //
+ // Call platform hook before Smm Dispatch
+ //
+ PlatformHookBeforeSmmDispatch ();
+
+ //
+ // Call memory management hook function
+ //
+ SmmEntryPointMemoryManagementHook ();
+
+ //
+ // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
+ //
+ InLegacyBoot = mInLegacyBoot;
+ if (!InLegacyBoot) {
+ //
+ // Mark the InSmm flag as TRUE, it will be used by SmmBase2 protocol
+ //
+ gSmmCorePrivate->InSmm = TRUE;
+
+ //
+ // Check to see if this is a Synchronous SMI sent through the SMM Communication
+ // Protocol or an Asynchronous SMI
+ //
+ CommunicationBuffer = gSmmCorePrivate->CommunicationBuffer;
+ BufferSize = gSmmCorePrivate->BufferSize;
+ if (CommunicationBuffer != NULL) {
+ //
+ // Synchronous SMI for SMM Core or request from Communicate protocol
+ //
+ IsOverlapped = InternalIsBufferOverlapped (
+ (UINT8 *) CommunicationBuffer,
+ BufferSize,
+ (UINT8 *) gSmmCorePrivate,
+ sizeof (*gSmmCorePrivate)
+ );
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicationBuffer, BufferSize) || IsOverlapped) {
+ //
+ // If CommunicationBuffer is not in valid address scope,
+ // or there is overlap between gSmmCorePrivate and CommunicationBuffer,
+ // return EFI_INVALID_PARAMETER
+ //
+ gSmmCorePrivate->CommunicationBuffer = NULL;
+ gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED;
+ } else {
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicationBuffer;
+ BufferSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
+ Status = SmiManage (
+ &CommunicateHeader->HeaderGuid,
+ NULL,
+ CommunicateHeader->Data,
+ &BufferSize
+ );
+ //
+ // Update CommunicationBuffer, BufferSize and ReturnStatus
+ // Communicate service finished, reset the pointer to CommBuffer to NULL
+ //
+ gSmmCorePrivate->BufferSize = BufferSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
+ gSmmCorePrivate->CommunicationBuffer = NULL;
+ gSmmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ //
+ // Process Asynchronous SMI sources
+ //
+ SmiManage (NULL, NULL, NULL, NULL);
+
+ //
+ // Call platform hook after Smm Dispatch
+ //
+ PlatformHookAfterSmmDispatch ();
+
+ //
+ // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
+ //
+ if (!InLegacyBoot) {
+ //
+ // Clear the InSmm flag as we are going to leave SMM
+ //
+ gSmmCorePrivate->InSmm = FALSE;
+ }
+}
+
+/**
+ Install LoadedImage protocol for SMM Core.
+**/
+VOID
+SmmCoreInstallLoadedImage (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Allocate a Loaded Image Protocol in EfiBootServicesData
+ //
+ Status = gBS->AllocatePool (EfiBootServicesData, sizeof(EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage);
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (mSmmCoreLoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
+ //
+ // Fill in the remaining fields of the Loaded Image Protocol instance.
+ // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
+ //
+ mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
+ mSmmCoreLoadedImage->SystemTable = gST;
+
+ mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
+ mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
+ mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode;
+ mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData;
+
+ //
+ // Create a new image handle in the UEFI handle database for the SMM Driver
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiLoadedImageProtocolGuid, mSmmCoreLoadedImage,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate a Loaded Image Protocol in SMM
+ //
+ Status = SmmAllocatePool (EfiRuntimeServicesData, sizeof(EFI_SMM_DRIVER_ENTRY), (VOID **)&mSmmCoreDriverEntry);
+ ASSERT_EFI_ERROR(Status);
+
+ ZeroMem (mSmmCoreDriverEntry, sizeof(EFI_SMM_DRIVER_ENTRY));
+ //
+ // Fill in the remaining fields of the Loaded Image Protocol instance.
+ //
+ mSmmCoreDriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
+ mSmmCoreDriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ mSmmCoreDriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
+ mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST;
+
+ mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
+ mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
+ mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
+ mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
+
+ mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint;
+ mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase;
+ mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES((UINTN)gSmmCorePrivate->PiSmmCoreImageSize);
+
+ //
+ // Create a new image handle in the SMM handle database for the SMM Driver
+ //
+ mSmmCoreDriverEntry->SmmImageHandle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &mSmmCoreDriverEntry->SmmImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmCoreDriverEntry->SmmLoadedImage
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ return ;
+}
+
+/**
+ The Entry Point for SMM Core
+
+ Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core
+ EntryPoint on the SMI vector.
+
+ Note: This function is called for both DXE invocation and SMRAM invocation.
+
+ @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.
+ @retval Other Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ //
+ // Get SMM Core Private context passed in from SMM IPL in ImageHandle.
+ //
+ gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;
+
+ //
+ // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point.
+ //
+ gSmmCorePrivate->Smst = &gSmmCoreSmst;
+ gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;
+
+ //
+ // No need to initialize memory service.
+ // It is done in constructor of PiSmmCoreMemoryAllocationLib(),
+ // so that the library linked with PiSmmCore can use AllocatePool() in constructor.
+ //
+
+ SmramProfileInit ();
+
+ //
+ // Copy FullSmramRanges to SMRAM
+ //
+ mFullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;
+ mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
+ ASSERT (mFullSmramRanges != NULL);
+ CopyMem (mFullSmramRanges, gSmmCorePrivate->SmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
+
+ //
+ // Register all SMI Handlers required by the SMM Core
+ //
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
+ Status = SmiHandlerRegister (
+ mSmmCoreSmiHandlers[Index].Handler,
+ mSmmCoreSmiHandlers[Index].HandlerType,
+ &mSmmCoreSmiHandlers[Index].DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable);
+ if (mAcpiS3Enable) {
+ //
+ // Register all S3 related SMI Handlers required by the SMM Core
+ //
+ for (Index = 0; mSmmCoreS3SmiHandlers[Index].HandlerType != NULL; Index++) {
+ Status = SmiHandlerRegister (
+ mSmmCoreS3SmiHandlers[Index].Handler,
+ mSmmCoreS3SmiHandlers[Index].HandlerType,
+ &mSmmCoreS3SmiHandlers[Index].DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ RegisterSmramProfileHandler ();
+ SmramProfileInstallProtocol ();
+
+ SmmCoreInstallLoadedImage ();
+
+ SmmCoreInitializeMemoryAttributesTable ();
+
+ SmmCoreInitializeSmiHandlerProfile ();
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
new file mode 100644
index 000000000..50a7fc000
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
@@ -0,0 +1,1353 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by SmmCore module.
+
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_CORE_H_
+#define _SMM_CORE_H_
+
+#include <PiSmm.h>
+
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmEndOfDxe.h>
+#include <Protocol/CpuIo2.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Security.h>
+#include <Protocol/Security2.h>
+#include <Protocol/SmmExitBootServices.h>
+#include <Protocol/SmmLegacyBoot.h>
+#include <Protocol/SmmReadyToBoot.h>
+#include <Protocol/SmmMemoryAttribute.h>
+#include <Protocol/SmmSxDispatch2.h>
+
+#include <Guid/Apriori.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/MemoryProfile.h>
+#include <Guid/LoadModuleAtFixedAddress.h>
+#include <Guid/SmiHandlerProfile.h>
+#include <Guid/EndOfS3Resume.h>
+#include <Guid/S3SmmInitDone.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmmCorePlatformHookLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/HobLib.h>
+#include <Library/SmmMemLib.h>
+
+#include "PiSmmCorePrivateData.h"
+#include "HeapGuard.h"
+
+//
+// Used to build a table of SMI Handlers that the SMM Core registers
+//
+typedef struct {
+ EFI_SMM_HANDLER_ENTRY_POINT2 Handler;
+ EFI_GUID *HandlerType;
+ EFI_HANDLE DispatchHandle;
+ BOOLEAN UnRegister;
+} SMM_CORE_SMI_HANDLERS;
+
+//
+// SMM_HANDLER - used for each SMM handler
+//
+
+#define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e')
+
+ typedef struct {
+ UINTN Signature;
+ LIST_ENTRY AllEntries; // All entries
+
+ EFI_GUID HandlerType; // Type of interrupt
+ LIST_ENTRY SmiHandlers; // All handlers
+} SMI_ENTRY;
+
+#define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h')
+
+ typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // Link on SMI_ENTRY.SmiHandlers
+ EFI_SMM_HANDLER_ENTRY_POINT2 Handler; // The smm handler's entry point
+ UINTN CallerAddr; // The address of caller who register the SMI handler.
+ SMI_ENTRY *SmiEntry;
+ VOID *Context; // for profile
+ UINTN ContextSize; // for profile
+} SMI_HANDLER;
+
+//
+// Structure for recording the state of an SMM Driver
+//
+#define EFI_SMM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_HANDLE FvHandle;
+ EFI_GUID FileName;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Scheduled;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ //
+ // Image EntryPoint in SMRAM
+ //
+ PHYSICAL_ADDRESS ImageEntryPoint;
+ //
+ // Image Buffer in SMRAM
+ //
+ PHYSICAL_ADDRESS ImageBuffer;
+ //
+ // Image Page Number
+ //
+ UINTN NumberOfPage;
+ EFI_HANDLE SmmImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL SmmLoadedImage;
+} EFI_SMM_DRIVER_ENTRY;
+
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('s','h','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+} IHANDLE;
+
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
+
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('s','p','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registered notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('s','p','i','f')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+} PROTOCOL_INTERFACE;
+
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('s','p','t','n')
+
+///
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol
+///
+typedef struct {
+ UINTN Signature;
+ PROTOCOL_ENTRY *Protocol;
+ /// All notifications for this protocol
+ LIST_ENTRY Link;
+ /// Notification function
+ EFI_SMM_NOTIFY_FN Function;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+//
+// SMM Core Global Variables
+//
+extern SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;
+extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst;
+extern LIST_ENTRY gHandleList;
+extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase;
+
+/**
+ Called to initialize the memory service.
+
+ @param SmramRangeCount Number of SMRAM Regions
+ @param SmramRanges Pointer to SMRAM Descriptors
+
+**/
+VOID
+SmmInitializeMemoryServices (
+ IN UINTN SmramRangeCount,
+ IN EFI_SMRAM_DESCRIPTOR *SmramRanges
+ );
+
+/**
+ The SmmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the SMM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallConfigurationTable (
+ IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ );
+
+/**
+ Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+ @param IsGuarded Flag to indicate if the memory is guarded
+ or not
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN IsGuarded
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+SmmInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @return The requested protocol interface for the handle
+
+**/
+EFI_STATUS
+EFIAPI
+SmmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Function Points to the notification function
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_SMM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ );
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is pasased in return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of SmmLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+/**
+ Manage SMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Registers a handler to execute within SMM.
+
+ @param Handler Handler service function pointer.
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerRegister (
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ );
+
+/**
+ Unregister a handler in SMM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmDriverDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLegacyBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmExitBootServicesHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Software SMI handler that is called when the S3SmmInitDone signal is triggered.
+ This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that
+ S3 SMM initialization has been done.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmS3SmmInitDoneHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Software SMI handler that is called when the EndOfS3Resume event is trigged.
+ This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that
+ S3 resume has finished.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfS3ResumeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Place holder function until all the SMM System Table Service are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+//
+//Functions used during debug builds
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency expressions evaluated to false.
+
+**/
+VOID
+SmmDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+/**
+ Add free SMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+SmmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ );
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+SmmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+SmmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+SmmFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+SmmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+SmmIsSchedulable (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry
+ );
+
+//
+// SmramProfile
+//
+
+/**
+ Initialize SMRAM profile.
+
+**/
+VOID
+SmramProfileInit (
+ VOID
+ );
+
+/**
+ Install SMRAM profile protocol.
+
+**/
+VOID
+SmramProfileInstallProtocol (
+ VOID
+ );
+
+/**
+ Register SMM image to SMRAM profile.
+
+ @param DriverEntry SMM image info.
+ @param RegisterToDxe Register image to DXE.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterSmramProfileImage (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
+ IN BOOLEAN RegisterToDxe
+ );
+
+/**
+ Unregister image from SMRAM profile.
+
+ @param DriverEntry SMM image info.
+ @param UnregisterToDxe Unregister image from DXE.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterSmramProfileImage (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
+ IN BOOLEAN UnregisterToDxe
+ );
+
+/**
+ Update SMRAM profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+/**
+ Register SMRAM profile handler.
+
+**/
+VOID
+RegisterSmramProfileHandler (
+ VOID
+ );
+
+/**
+ SMRAM profile ready to lock callback function.
+
+**/
+VOID
+SmramProfileReadyToLock (
+ VOID
+ );
+
+/**
+ Initialize MemoryAttributes support.
+**/
+VOID
+EFIAPI
+SmmCoreInitializeMemoryAttributesTable (
+ VOID
+ );
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[out] MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param[out] DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param[out] DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+/**
+ Initialize SmiHandler profile feature.
+**/
+VOID
+SmmCoreInitializeSmiHandlerProfile (
+ VOID
+ );
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ a new SMI handler is registered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param CallerAddress The address of the module who registers the SMI handler.
+ @param Context The context of the SMI handler.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+ @param ContextSize The size of the context in bytes.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+
+ @retval EFI_SUCCESS The information is recorded.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileRegisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ );
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ an existing SMI handler is unregistered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param Context The context of the SMI handler.
+ If it is NOT NULL, it will be used to check what is registered.
+ @param ContextSize The size of the context in bytes.
+ If Context is NOT NULL, it will be used to check what is registered.
+
+ @retval EFI_SUCCESS The original record is removed.
+ @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileUnregisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ );
+
+extern UINTN mFullSmramRangeCount;
+extern EFI_SMRAM_DESCRIPTOR *mFullSmramRanges;
+
+extern EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;
+
+extern EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;
+
+//
+// Page management
+//
+
+typedef struct {
+ LIST_ENTRY Link;
+ UINTN NumberOfPages;
+} FREE_PAGE_LIST;
+
+extern LIST_ENTRY mSmmMemoryMap;
+
+//
+// Pool management
+//
+
+//
+// MIN_POOL_SHIFT must not be less than 5
+//
+#define MIN_POOL_SHIFT 6
+#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)
+
+//
+// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1
+//
+#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)
+#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)
+
+//
+// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes
+//
+#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)
+
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('s','p','h','d')
+
+typedef struct {
+ UINT32 Signature;
+ BOOLEAN Available;
+ EFI_MEMORY_TYPE Type;
+ UINTN Size;
+} POOL_HEADER;
+
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('s','p','t','l')
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ UINTN Size;
+} POOL_TAIL;
+
+#define POOL_OVERHEAD (sizeof(POOL_HEADER) + sizeof(POOL_TAIL))
+
+#define HEAD_TO_TAIL(a) \
+ ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
+
+typedef struct {
+ POOL_HEADER Header;
+ LIST_ENTRY Link;
+} FREE_POOL_HEADER;
+
+typedef enum {
+ SmmPoolTypeCode,
+ SmmPoolTypeData,
+ SmmPoolTypeMax,
+} SMM_POOL_TYPE;
+
+extern LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
+
+/**
+ Internal Function. Allocate n pages from given free page node.
+
+ @param Pages The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocPagesOnOneNode (
+ IN OUT FREE_PAGE_LIST *Pages,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ );
+
+/**
+ Update SMM memory map entry.
+
+ @param[in] Type The type of allocation to perform.
+ @param[in] Memory The base of memory address.
+ @param[in] NumberOfPages The number of pages to allocate.
+ @param[in] AddRegion If this memory is new added region.
+**/
+VOID
+ConvertSmmMemoryMapEntry (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ );
+
+/**
+ Internal function. Moves any memory descriptors that are on the
+ temporary descriptor stack to heap.
+
+**/
+VOID
+CoreFreeMemoryMapStack (
+ VOID
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param[in] Memory Base address of memory being freed.
+ @param[in] NumberOfPages The number of pages to free.
+ @param[in] AddRegion If this memory is new added region.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+SmmInternalFreePagesEx (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ IN BOOLEAN AddRegion
+ );
+
+/**
+ Hook function used to set all Guard pages after entering SMM mode.
+**/
+VOID
+SmmEntryPointMemoryManagementHook (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
new file mode 100644
index 000000000..c8bfae386
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
@@ -0,0 +1,123 @@
+## @file
+# This module provide an SMM CIS compliant implementation of SMM Core.
+#
+# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCore
+ MODULE_UNI_FILE = PiSmmCore.uni
+ FILE_GUID = E94F54CD-81EB-47ed-AEC3-856F5DC157A9
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SmmMain
+
+# VALID_ARCHITECTURES = IA32 X64
+
+[Sources]
+ PiSmmCore.c
+ PiSmmCore.h
+ PiSmmCorePrivateData.h
+ Page.c
+ Pool.c
+ Handle.c
+ Locate.c
+ Notify.c
+ Dependency.c
+ Dispatcher.c
+ Smi.c
+ InstallConfigurationTable.c
+ SmramProfileRecord.c
+ MemoryAttributesTable.c
+ SmiHandlerProfile.c
+ HeapGuard.c
+ HeapGuard.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ CacheMaintenanceLib
+ DebugLib
+ ReportStatusCodeLib
+ DevicePathLib
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ PcdLib
+ SmmCorePlatformHookLib
+ PerformanceLib
+ HobLib
+ SmmMemLib
+
+[Protocols]
+ gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister
+ gEfiSmmReadyToLockProtocolGuid ## PRODUCES
+ gEfiSmmCpuIo2ProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiSmmEndOfDxeProtocolGuid ## PRODUCES
+ gEfiSecurityArchProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEdkiiSmmExitBootServicesProtocolGuid ## SOMETIMES_PRODUCES
+ gEdkiiSmmLegacyBootProtocolGuid ## SOMETIMES_PRODUCES
+ gEdkiiSmmReadyToBootProtocolGuid ## PRODUCES
+
+ gEfiSmmSwDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmPowerButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmStandbyButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiSmmMemoryAttributeProtocolGuid ## CONSUMES
+ gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+
+[Guids]
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEventLegacyBootGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEventExitBootServicesGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEventReadyToBootGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+ ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
+ gEdkiiMemoryProfileGuid
+ ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ gEdkiiSmmMemoryProfileGuid
+ gEdkiiPiSmmMemoryAttributesTableGuid ## PRODUCES ## SystemTable
+ ## SOMETIMES_CONSUMES ## SystemTable
+ gLoadFixedAddressConfigurationTableGuid
+ ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
+ gSmiHandlerProfileGuid
+ gEdkiiEndOfS3ResumeGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ gEdkiiS3SmmInitDoneGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PiSmmCoreExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni
new file mode 100644
index 000000000..9f11394c4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This module provide an SMM CIS compliant implementation of SMM Core.
+//
+// This module provide an SMM CIS compliant implementation of SMM Core.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM Core."
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni
new file mode 100644
index 000000000..44bf418ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PiSmmCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core SMM Services Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h
new file mode 100644
index 000000000..28f95d9b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h
@@ -0,0 +1,119 @@
+/** @file
+ The internal header file that declared a data structure that is shared
+ between the SMM IPL and the SMM Core.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_SMM_CORE_PRIVATE_DATA_H_
+#define _PI_SMM_CORE_PRIVATE_DATA_H_
+
+///
+/// Define values for the communications buffer used when gEfiEventDxeDispatchGuid is
+/// event signaled. This event is signaled by the DXE Core each time the DXE Core
+/// dispatcher has completed its work. When this event is signaled, the SMM Core
+/// if notified, so the SMM Core can dispatch SMM drivers. If COMM_BUFFER_SMM_DISPATCH_ERROR
+/// is returned in the communication buffer, then an error occurred dispatching SMM
+/// Drivers. If COMM_BUFFER_SMM_DISPATCH_SUCCESS is returned, then the SMM Core
+/// dispatched all the drivers it could. If COMM_BUFFER_SMM_DISPATCH_RESTART is
+/// returned, then the SMM Core just dispatched the SMM Driver that registered
+/// the SMM Entry Point enabling the use of SMM Mode. In this case, the SMM Core
+/// should be notified again to dispatch more SMM Drivers using SMM Mode.
+///
+#define COMM_BUFFER_SMM_DISPATCH_ERROR 0x00
+#define COMM_BUFFER_SMM_DISPATCH_SUCCESS 0x01
+#define COMM_BUFFER_SMM_DISPATCH_RESTART 0x02
+
+///
+/// Signature for the private structure shared between the SMM IPL and the SMM Core
+///
+#define SMM_CORE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'm', 'm', 'c')
+
+///
+/// Private structure that is used to share information between the SMM IPL and
+/// the SMM Core. This structure is allocated from memory of type EfiRuntimeServicesData.
+/// Since runtime memory types are converted to available memory when a legacy boot
+/// is performed, the SMM Core must not access any fields of this structure if a legacy
+/// boot is performed. As a result, the SMM IPL must create an event notification
+/// for the Legacy Boot event and notify the SMM Core that a legacy boot is being
+/// performed. The SMM Core can then use this information to filter accesses to
+/// thos structure.
+///
+typedef struct {
+ UINTN Signature;
+
+ ///
+ /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle
+ /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded
+ /// Image Protocol for each SMM Driver that is dispatched by the SMM Core.
+ ///
+ EFI_HANDLE SmmIplImageHandle;
+
+ ///
+ /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
+ ///
+ UINTN SmramRangeCount;
+
+ ///
+ /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
+ ///
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;
+
+ ///
+ /// The SMM Foundation Entry Point. The SMM Core fills in this field when the
+ /// SMM Core is initialized. The SMM IPL is responsible for registering this entry
+ /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may
+ /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL
+ /// sets up a protocol notification on the SMM Configuration Protocol and registers
+ /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is
+ /// available.
+ ///
+ EFI_SMM_ENTRY_POINT SmmEntryPoint;
+
+ ///
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
+ ///
+ BOOLEAN SmmEntryPointRegistered;
+
+ ///
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
+ ///
+ BOOLEAN InSmm;
+
+ ///
+ /// This field is set by the SMM Core then the SMM Core is initialized. This field is
+ /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in
+ /// the SMM IPL.
+ ///
+ EFI_SMM_SYSTEM_TABLE2 *Smst;
+
+ ///
+ /// This field is used by the SMM Communication Protocol to pass a buffer into
+ /// a software SMI handler and for the software SMI handler to pass a buffer back to
+ /// the caller of the SMM Communication Protocol.
+ ///
+ VOID *CommunicationBuffer;
+
+ ///
+ /// This field is used by the SMM Communication Protocol to pass the size of a buffer,
+ /// in bytes, into a software SMI handler and for the software SMI handler to pass the
+ /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.
+ ///
+ UINTN BufferSize;
+
+ ///
+ /// This field is used by the SMM Communication Protocol to pass the return status from
+ /// a software SMI handler back to the caller of the SMM Communication Protocol.
+ ///
+ EFI_STATUS ReturnStatus;
+
+ EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase;
+ UINT64 PiSmmCoreImageSize;
+ EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint;
+} SMM_CORE_PRIVATE_DATA;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
new file mode 100644
index 000000000..599a0cd01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
@@ -0,0 +1,1865 @@
+/** @file
+ SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmConfiguration.h>
+#include <Protocol/SmmControl2.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/Cpu.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/LoadModuleAtFixedAddress.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include "PiSmmCorePrivateData.h"
+
+#define SMRAM_CAPABILITIES (EFI_MEMORY_WB | EFI_MEMORY_UC)
+
+//
+// Function prototypes from produced protocols
+//
+
+/**
+ Indicate whether the driver is currently executing in the SMM Initialization phase.
+
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.
+ @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
+ inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
+
+ @retval EFI_INVALID_PARAMETER InSmram was NULL.
+ @retval EFI_SUCCESS The call returned successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBase2InSmram (
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,
+ OUT BOOLEAN *InSmram
+ );
+
+/**
+ Retrieves the location of the System Management System Table (SMST).
+
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.
+ @param Smst On return, points to a pointer to the System Management Service Table (SMST).
+
+ @retval EFI_INVALID_PARAMETER Smst or This was invalid.
+ @retval EFI_SUCCESS The memory was returned to the system.
+ @retval EFI_UNSUPPORTED Not in SMM.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBase2GetSmstLocation (
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,
+ OUT EFI_SMM_SYSTEM_TABLE2 **Smst
+ );
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered
+ UEFI service. This function is part of the SMM Communication Protocol that may
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
+ after SetVirtualAddressMap().
+
+ @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
+ @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
+ If this error is returned, the MessageLength field
+ in the CommBuffer header or the integer pointed by
+ CommSize, are updated to reflect the maximum payload
+ size the implementation can accommodate.
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
+ if not omitted, are in address range that cannot be
+ accessed by the MM environment.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCommunicationCommunicate (
+ IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize OPTIONAL
+ );
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered UEFI service.
+
+ @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
+ @param[in] CommBufferPhysical Physical address of the MM communication buffer
+ @param[in] CommBufferVirtual Virtual address of the MM communication buffer
+ @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
+ If this error is returned, the MessageLength field
+ in the CommBuffer header or the integer pointed by
+ CommSize, are updated to reflect the maximum payload
+ size the implementation can accommodate.
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
+ if not omitted, are in address range that cannot be
+ accessed by the MM environment.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCommunicationMmCommunicate2 (
+ IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,
+ IN OUT VOID *CommBufferPhysical,
+ IN OUT VOID *CommBufferVirtual,
+ IN OUT UINTN *CommSize OPTIONAL
+ );
+
+/**
+ Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplSmmConfigurationEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification that is fired every time a DxeSmmReadyToLock protocol is added
+ or if gEfiEventReadyToBootGuid is signalled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplReadyToLockEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification that is fired when DxeDispatch Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplDxeDispatchEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification that is fired when a GUIDed Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplGuidedEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification that is fired when EndOfDxe Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplEndOfDxeEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmIplSetVirtualAddressNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Data structure used to declare a table of protocol notifications and event
+// notifications required by the SMM IPL
+//
+typedef struct {
+ BOOLEAN Protocol;
+ BOOLEAN CloseOnLock;
+ EFI_GUID *Guid;
+ EFI_EVENT_NOTIFY NotifyFunction;
+ VOID *NotifyContext;
+ EFI_TPL NotifyTpl;
+ EFI_EVENT Event;
+} SMM_IPL_EVENT_NOTIFICATION;
+
+//
+// Handle to install the SMM Base2 Protocol and the SMM Communication Protocol
+//
+EFI_HANDLE mSmmIplHandle = NULL;
+
+//
+// SMM Base 2 Protocol instance
+//
+EFI_SMM_BASE2_PROTOCOL mSmmBase2 = {
+ SmmBase2InSmram,
+ SmmBase2GetSmstLocation
+};
+
+//
+// SMM Communication Protocol instance
+//
+EFI_SMM_COMMUNICATION_PROTOCOL mSmmCommunication = {
+ SmmCommunicationCommunicate
+};
+
+//
+// PI 1.7 MM Communication Protocol 2 instance
+//
+EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {
+ SmmCommunicationMmCommunicate2
+};
+
+//
+// SMM Core Private Data structure that contains the data shared between
+// the SMM IPL and the SMM Core.
+//
+SMM_CORE_PRIVATE_DATA mSmmCorePrivateData = {
+ SMM_CORE_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // SmmIplImageHandle
+ 0, // SmramRangeCount
+ NULL, // SmramRanges
+ NULL, // SmmEntryPoint
+ FALSE, // SmmEntryPointRegistered
+ FALSE, // InSmm
+ NULL, // Smst
+ NULL, // CommunicationBuffer
+ 0, // BufferSize
+ EFI_SUCCESS // ReturnStatus
+};
+
+//
+// Global pointer used to access mSmmCorePrivateData from outside and inside SMM
+//
+SMM_CORE_PRIVATE_DATA *gSmmCorePrivate = &mSmmCorePrivateData;
+
+//
+// SMM IPL global variables
+//
+EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2;
+EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess;
+EFI_SMRAM_DESCRIPTOR *mCurrentSmramRange;
+BOOLEAN mSmmLocked = FALSE;
+BOOLEAN mEndOfDxe = FALSE;
+EFI_PHYSICAL_ADDRESS mSmramCacheBase;
+UINT64 mSmramCacheSize;
+
+EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader;
+EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *mLMFAConfigurationTable = NULL;
+
+//
+// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires
+//
+SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = {
+ //
+ // Declare protocol notification on the SMM Configuration protocol. When this notification is established,
+ // the associated event is immediately signalled, so the notification function will be executed and the
+ // SMM Configuration Protocol will be found if it is already in the handle database.
+ //
+ { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL },
+ //
+ // Declare protocol notification on DxeSmmReadyToLock protocols. When this notification is established,
+ // the associated event is immediately signalled, so the notification function will be executed and the
+ // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.
+ //
+ { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on EndOfDxe event. When this notification is established,
+ // the associated event is immediately signalled, so the notification function will be executed and the
+ // SMM End Of Dxe Protocol will be found if it is already in the handle database.
+ //
+ { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag.
+ //
+ { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplEndOfDxeEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core
+ // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core
+ // if notified, so the SMM Core can dispatch SMM drivers.
+ //
+ { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is
+ // used to make sure SMRAM is locked before any boot options are processed.
+ //
+ { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform
+ // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core
+ // must guarantee that it does not access any UEFI related structures outside of SMRAM.
+ // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot.
+ //
+ { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on Exit Boot Services Event Group. This is used to inform the SMM Core
+ // to notify SMM driver that system enter exit boot services.
+ //
+ { FALSE, FALSE, &gEfiEventExitBootServicesGuid, SmmIplGuidedEventNotify, &gEfiEventExitBootServicesGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on Ready To Boot Event Group. This is used to inform the SMM Core
+ // to notify SMM driver that system enter ready to boot.
+ //
+ { FALSE, FALSE, &gEfiEventReadyToBootGuid, SmmIplGuidedEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
+ //
+ // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate
+ // and mSmmControl2 from physical addresses to virtual addresses.
+ //
+ { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL },
+ //
+ // Terminate the table of event notifications
+ //
+ { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL }
+};
+
+/**
+ Find the maximum SMRAM cache range that covers the range specified by SmramRange.
+
+ This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
+
+ @param SmramRange The SMRAM range to search from.
+ @param SmramCacheBase The returned cache range base.
+ @param SmramCacheSize The returned cache range size.
+
+**/
+VOID
+GetSmramCacheRange (
+ IN EFI_SMRAM_DESCRIPTOR *SmramRange,
+ OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,
+ OUT UINT64 *SmramCacheSize
+ )
+{
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS RangeCpuStart;
+ UINT64 RangePhysicalSize;
+ BOOLEAN FoundAjacentRange;
+
+ *SmramCacheBase = SmramRange->CpuStart;
+ *SmramCacheSize = SmramRange->PhysicalSize;
+
+ do {
+ FoundAjacentRange = FALSE;
+ for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
+ RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart;
+ RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
+ if (RangeCpuStart < *SmramCacheBase && *SmramCacheBase == (RangeCpuStart + RangePhysicalSize)) {
+ *SmramCacheBase = RangeCpuStart;
+ *SmramCacheSize += RangePhysicalSize;
+ FoundAjacentRange = TRUE;
+ } else if ((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart && RangePhysicalSize > 0) {
+ *SmramCacheSize += RangePhysicalSize;
+ FoundAjacentRange = TRUE;
+ }
+ }
+ } while (FoundAjacentRange);
+
+}
+
+/**
+ Indicate whether the driver is currently executing in the SMM Initialization phase.
+
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.
+ @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
+ inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
+
+ @retval EFI_INVALID_PARAMETER InSmram was NULL.
+ @retval EFI_SUCCESS The call returned successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBase2InSmram (
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,
+ OUT BOOLEAN *InSmram
+ )
+{
+ if (InSmram == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *InSmram = gSmmCorePrivate->InSmm;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the location of the System Management System Table (SMST).
+
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.
+ @param Smst On return, points to a pointer to the System Management Service Table (SMST).
+
+ @retval EFI_INVALID_PARAMETER Smst or This was invalid.
+ @retval EFI_SUCCESS The memory was returned to the system.
+ @retval EFI_UNSUPPORTED Not in SMM.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBase2GetSmstLocation (
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,
+ OUT EFI_SMM_SYSTEM_TABLE2 **Smst
+ )
+{
+ if ((This == NULL) ||(Smst == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!gSmmCorePrivate->InSmm) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Smst = gSmmCorePrivate->Smst;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered
+ UEFI service. This function is part of the SMM Communication Protocol that may
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
+ after SetVirtualAddressMap().
+
+ @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
+ @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
+ If this error is returned, the MessageLength field
+ in the CommBuffer header or the integer pointed by
+ CommSize, are updated to reflect the maximum payload
+ size the implementation can accommodate.
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
+ if not omitted, are in address range that cannot be
+ accessed by the MM environment.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCommunicationCommunicate (
+ IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
+ BOOLEAN OldInSmm;
+ UINTN TempCommSize;
+
+ //
+ // Check parameters
+ //
+ if (CommBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
+
+ if (CommSize == NULL) {
+ TempCommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength;
+ } else {
+ TempCommSize = *CommSize;
+ //
+ // CommSize must hold HeaderGuid and MessageLength
+ //
+ if (TempCommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // If not already in SMM, then generate a Software SMI
+ //
+ if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {
+ //
+ // Put arguments for Software SMI in gSmmCorePrivate
+ //
+ gSmmCorePrivate->CommunicationBuffer = CommBuffer;
+ gSmmCorePrivate->BufferSize = TempCommSize;
+
+ //
+ // Generate Software SMI
+ //
+ Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Return status from software SMI
+ //
+ if (CommSize != NULL) {
+ *CommSize = gSmmCorePrivate->BufferSize;
+ }
+ return gSmmCorePrivate->ReturnStatus;
+ }
+
+ //
+ // If we are in SMM, then the execution mode must be physical, which means that
+ // OS established virtual addresses can not be used. If SetVirtualAddressMap()
+ // has been called, then a direct invocation of the Software SMI is not allowed,
+ // so return EFI_INVALID_PARAMETER.
+ //
+ if (EfiGoneVirtual()) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.
+ //
+ if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Save current InSmm state and set InSmm state to TRUE
+ //
+ OldInSmm = gSmmCorePrivate->InSmm;
+ gSmmCorePrivate->InSmm = TRUE;
+
+ //
+ // Before SetVirtualAddressMap(), we are in SMM or SMRAM is open and unlocked, call SmiManage() directly.
+ //
+ TempCommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
+ Status = gSmmCorePrivate->Smst->SmiManage (
+ &CommunicateHeader->HeaderGuid,
+ NULL,
+ CommunicateHeader->Data,
+ &TempCommSize
+ );
+ TempCommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
+ if (CommSize != NULL) {
+ *CommSize = TempCommSize;
+ }
+
+ //
+ // Restore original InSmm state
+ //
+ gSmmCorePrivate->InSmm = OldInSmm;
+
+ return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered UEFI service.
+
+ @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
+ @param[in] CommBufferPhysical Physical address of the MM communication buffer
+ @param[in] CommBufferVirtual Virtual address of the MM communication buffer
+ @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
+ If this error is returned, the MessageLength field
+ in the CommBuffer header or the integer pointed by
+ CommSize, are updated to reflect the maximum payload
+ size the implementation can accommodate.
+ @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
+ if not omitted, are in address range that cannot be
+ accessed by the MM environment.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCommunicationMmCommunicate2 (
+ IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,
+ IN OUT VOID *CommBufferPhysical,
+ IN OUT VOID *CommBufferVirtual,
+ IN OUT UINTN *CommSize OPTIONAL
+ )
+{
+ return SmmCommunicationCommunicate (&mSmmCommunication,
+ CommBufferPhysical,
+ CommSize);
+}
+
+/**
+ Event notification that is fired when GUIDed Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplGuidedEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Size;
+
+ //
+ // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
+ //
+ CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
+ mCommunicateHeader.MessageLength = 1;
+ mCommunicateHeader.Data[0] = 0;
+
+ //
+ // Generate the Software SMI and return the result
+ //
+ Size = sizeof (mCommunicateHeader);
+ SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
+}
+
+/**
+ Event notification that is fired when EndOfDxe Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplEndOfDxeEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
+
+/**
+ Event notification that is fired when DxeDispatch Event Group is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplDxeDispatchEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+
+ //
+ // Keep calling the SMM Core Dispatcher until there is no request to restart it.
+ //
+ while (TRUE) {
+ //
+ // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
+ // Clear the buffer passed into the Software SMI. This buffer will return
+ // the status of the SMM Core Dispatcher.
+ //
+ CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
+ mCommunicateHeader.MessageLength = 1;
+ mCommunicateHeader.Data[0] = 0;
+
+ //
+ // Generate the Software SMI and return the result
+ //
+ Size = sizeof (mCommunicateHeader);
+ SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
+
+ //
+ // Return if there is no request to restart the SMM Core Dispatcher
+ //
+ if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {
+ return;
+ }
+
+ //
+ // Close all SMRAM ranges to protect SMRAM
+ // NOTE: SMRR is enabled by CPU SMM driver by calling SmmCpuFeaturesInitializeProcessor() from SmmCpuFeaturesLib
+ // so no need to reset the SMRAM to UC in MTRR.
+ //
+ Status = mSmmAccess->Close (mSmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Print debug message that the SMRAM window is now closed.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
+ }
+}
+
+/**
+ Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplSmmConfigurationEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
+
+ //
+ // Make sure this notification is for this handler
+ //
+ Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Register the SMM Entry Point provided by the SMM Core with the SMM Configuration protocol
+ //
+ Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set flag to indicate that the SMM Entry Point has been registered which
+ // means that SMIs are now fully operational.
+ //
+ gSmmCorePrivate->SmmEntryPointRegistered = TRUE;
+
+ //
+ // Print debug message showing SMM Core entry point address.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));
+}
+
+/**
+ Event notification that is fired every time a DxeSmmReadyToLock protocol is added
+ or if gEfiEventReadyToBootGuid is signaled.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+SmmIplReadyToLockEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ UINTN Index;
+
+ //
+ // See if we are already locked
+ //
+ if (mSmmLocked) {
+ return;
+ }
+
+ //
+ // Make sure this notification is for this handler
+ //
+ if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ } else {
+ //
+ // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being
+ // signaled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.
+ // Print a warning on debug builds.
+ //
+ DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));
+ }
+
+ if (!mEndOfDxe) {
+ DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+ (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)
+ );
+ ASSERT (FALSE);
+ }
+
+ //
+ // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)
+ //
+ mSmmAccess->Lock (mSmmAccess);
+
+ //
+ // Close protocol and event notification events that do not apply after the
+ // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot
+ // event has been signalled.
+ //
+ for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
+ if (mSmmIplEvents[Index].CloseOnLock) {
+ gBS->CloseEvent (mSmmIplEvents[Index].Event);
+ }
+ }
+
+ //
+ // Inform SMM Core that the DxeSmmReadyToLock protocol was installed
+ //
+ SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);
+
+ //
+ // Print debug message that the SMRAM window is now locked.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));
+
+ //
+ // Set flag so this operation will not be performed again
+ //
+ mSmmLocked = TRUE;
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmIplSetVirtualAddressNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **)&mSmmControl2);
+}
+
+/**
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ EFI_PHYSICAL_ADDRESS SmramBase;
+ UINT64 SmmCodeSize;
+ UINT64 ValueInSectionHeader;
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+ //
+ SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber));
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+ SmramBase = mLMFAConfigurationTable->SmramBase;
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the
+ // first section header that doesn't point to code section in image header. And there is an assumption that when the
+ // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers
+ // fields should NOT be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section in which build tool saves the
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);
+
+ if (SmramBase + SmmCodeSize > FixLoadingAddress && SmramBase <= FixLoadingAddress) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ Status = EFI_SUCCESS;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status));
+ return Status;
+}
+/**
+ Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.
+
+ @param[in, out] SmramRange Descriptor for the range of SMRAM to reload the
+ currently executing image, the rang of SMRAM to
+ hold SMM Core will be excluded.
+ @param[in, out] SmramRangeSmmCore Descriptor for the range of SMRAM to hold SMM Core.
+
+ @param[in] Context Context to pass into SMM Core
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+ExecuteSmmCoreFromSmram (
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramRange,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramRangeSmmCore,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *SourceBuffer;
+ UINTN SourceSize;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN PageCount;
+ EFI_IMAGE_ENTRY_POINT EntryPoint;
+
+ //
+ // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
+ //
+ Status = GetSectionFromAnyFvByFileType (
+ EFI_FV_FILETYPE_SMM_CORE,
+ 0,
+ EFI_SECTION_PE32,
+ 0,
+ &SourceBuffer,
+ &SourceSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize ImageContext
+ //
+ ImageContext.Handle = SourceBuffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
+ // the address assigned by build tool.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Get the fixed loading address assigned by Build tool
+ //
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
+ //
+ PageCount = 0;
+ //
+ // Reserved Smram Region for SmmCore is not used, and remove it from SmramRangeCount.
+ //
+ gSmmCorePrivate->SmramRangeCount --;
+ } else {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
+ //
+ // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
+ // specified by SmramRange
+ //
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+
+ ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
+ ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
+
+ SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
+ SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
+ SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
+ SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
+ SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
+
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
+ }
+ } else {
+ //
+ // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
+ // specified by SmramRange
+ //
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+
+ ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
+ ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
+
+ SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
+ SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
+ SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
+ SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
+ SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
+
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
+ }
+
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+ //
+ // Print debug message showing SMM Core load address.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Flush the instruction cache so the image data are written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ //
+ // Print debug message showing SMM Core entry point address.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
+
+ gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;
+ gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;
+ DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));
+ DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));
+
+ gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;
+
+ //
+ // Execute image
+ //
+ EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
+ Status = EntryPoint ((EFI_HANDLE)Context, gST);
+ }
+ }
+
+ //
+ // Always free memory allocated by GetFileBufferByFilePath ()
+ //
+ FreePool (SourceBuffer);
+
+ return Status;
+}
+
+/**
+ SMM split SMRAM entry.
+
+ @param[in, out] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.
+ @param[in, out] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
+ @param[out] Ranges Output pointer to hold split EFI_SMRAM_DESCRIPTOR entry.
+ @param[in, out] RangeCount Pointer to range count.
+ @param[out] ReservedRanges Output pointer to hold split EFI_SMM_RESERVED_SMRAM_REGION entry.
+ @param[in, out] ReservedRangeCount Pointer to reserved range count.
+ @param[out] FinalRanges Output pointer to hold split final EFI_SMRAM_DESCRIPTOR entry
+ that no need to be split anymore.
+ @param[in, out] FinalRangeCount Pointer to final range count.
+
+**/
+VOID
+SmmSplitSmramEntry (
+ IN OUT EFI_SMRAM_DESCRIPTOR *RangeToCompare,
+ IN OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare,
+ OUT EFI_SMRAM_DESCRIPTOR *Ranges,
+ IN OUT UINTN *RangeCount,
+ OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRanges,
+ IN OUT UINTN *ReservedRangeCount,
+ OUT EFI_SMRAM_DESCRIPTOR *FinalRanges,
+ IN OUT UINTN *FinalRangeCount
+ )
+{
+ UINT64 RangeToCompareEnd;
+ UINT64 ReservedRangeToCompareEnd;
+
+ RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;
+ ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;
+
+ if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
+ (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) {
+ if (RangeToCompareEnd < ReservedRangeToCompareEnd) {
+ //
+ // RangeToCompare ReservedRangeToCompare
+ // ---- ---- --------------------------------------
+ // | | | | -> 1. ReservedRangeToCompare
+ // ---- | | |--| --------------------------------------
+ // | | | | | |
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
+ // | | | | | | RangeToCompare->PhysicalSize = 0
+ // ---- | | |--| --------------------------------------
+ // | | | | -> 3. ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount
+ // ---- ---- --------------------------------------
+ //
+
+ //
+ // 1. Update ReservedRangeToCompare.
+ //
+ ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
+ //
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
+ // Zero RangeToCompare->PhysicalSize.
+ //
+ FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
+ FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompare->PhysicalSize;
+ *FinalRangeCount += 1;
+ RangeToCompare->PhysicalSize = 0;
+ //
+ // 3. Update ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount.
+ //
+ ReservedRanges[*ReservedRangeCount].SmramReservedStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ ReservedRanges[*ReservedRangeCount].SmramReservedSize = ReservedRangeToCompareEnd - RangeToCompareEnd;
+ *ReservedRangeCount += 1;
+ } else {
+ //
+ // RangeToCompare ReservedRangeToCompare
+ // ---- ---- --------------------------------------
+ // | | | | -> 1. ReservedRangeToCompare
+ // ---- | | |--| --------------------------------------
+ // | | | | | |
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
+ // | | | | | |
+ // | | ---- |--| --------------------------------------
+ // | | | | -> 3. RangeToCompare
+ // ---- ---- --------------------------------------
+ //
+
+ //
+ // 1. Update ReservedRangeToCompare.
+ //
+ ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
+ //
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
+ //
+ FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
+ FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompareEnd - RangeToCompare->CpuStart;
+ *FinalRangeCount += 1;
+ //
+ // 3. Update RangeToCompare.
+ //
+ RangeToCompare->CpuStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ RangeToCompare->PhysicalStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ RangeToCompare->PhysicalSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ }
+ } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
+ (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) {
+ if (ReservedRangeToCompareEnd < RangeToCompareEnd) {
+ //
+ // RangeToCompare ReservedRangeToCompare
+ // ---- ---- --------------------------------------
+ // | | | | -> 1. RangeToCompare
+ // | | ---- |--| --------------------------------------
+ // | | | | | |
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
+ // | | | | | | ReservedRangeToCompare->SmramReservedSize = 0
+ // | | ---- |--| --------------------------------------
+ // | | | | -> 3. Ranges[*RangeCount] and increment *RangeCount
+ // ---- ---- --------------------------------------
+ //
+
+ //
+ // 1. Update RangeToCompare.
+ //
+ RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
+ //
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
+ // ReservedRangeToCompare->SmramReservedSize = 0
+ //
+ FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
+ FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompare->SmramReservedSize;
+ *FinalRangeCount += 1;
+ ReservedRangeToCompare->SmramReservedSize = 0;
+ //
+ // 3. Update Ranges[*RangeCount] and increment *RangeCount.
+ //
+ Ranges[*RangeCount].CpuStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ Ranges[*RangeCount].PhysicalStart = FinalRanges[*FinalRangeCount - 1].PhysicalStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ Ranges[*RangeCount].RegionState = RangeToCompare->RegionState;
+ Ranges[*RangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompareEnd;
+ *RangeCount += 1;
+ } else {
+ //
+ // RangeToCompare ReservedRangeToCompare
+ // ---- ---- --------------------------------------
+ // | | | | -> 1. RangeToCompare
+ // | | ---- |--| --------------------------------------
+ // | | | | | |
+ // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
+ // | | | | | |
+ // ---- | | |--| --------------------------------------
+ // | | | | -> 3. ReservedRangeToCompare
+ // ---- ---- --------------------------------------
+ //
+
+ //
+ // 1. Update RangeToCompare.
+ //
+ RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
+ //
+ // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
+ // ReservedRangeToCompare->SmramReservedSize = 0
+ //
+ FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;
+ FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
+ FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
+ FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompare->SmramReservedStart;
+ *FinalRangeCount += 1;
+ //
+ // 3. Update ReservedRangeToCompare.
+ //
+ ReservedRangeToCompare->SmramReservedStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ ReservedRangeToCompare->SmramReservedSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
+ }
+ }
+}
+
+/**
+ Returns if SMRAM range and SMRAM reserved range are overlapped.
+
+ @param[in] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.
+ @param[in] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
+
+ @retval TRUE There is overlap.
+ @retval FALSE There is no overlap.
+
+**/
+BOOLEAN
+SmmIsSmramOverlap (
+ IN EFI_SMRAM_DESCRIPTOR *RangeToCompare,
+ IN EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare
+ )
+{
+ UINT64 RangeToCompareEnd;
+ UINT64 ReservedRangeToCompareEnd;
+
+ RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;
+ ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;
+
+ if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
+ (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) {
+ return TRUE;
+ } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
+ (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Get full SMRAM ranges.
+
+ It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from
+ SmmConfiguration protocol, split the entries if there is overlap between them.
+ It will also reserve one entry for SMM core.
+
+ @param[out] FullSmramRangeCount Output pointer to full SMRAM range count.
+
+ @return Pointer to full SMRAM ranges.
+
+**/
+EFI_SMRAM_DESCRIPTOR *
+GetFullSmramRanges (
+ OUT UINTN *FullSmramRangeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
+ UINTN Size;
+ UINTN Index;
+ UINTN Index2;
+ EFI_SMRAM_DESCRIPTOR *FullSmramRanges;
+ UINTN TempSmramRangeCount;
+ UINTN AdditionSmramRangeCount;
+ EFI_SMRAM_DESCRIPTOR *TempSmramRanges;
+ UINTN SmramRangeCount;
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;
+ UINTN SmramReservedCount;
+ EFI_SMM_RESERVED_SMRAM_REGION *SmramReservedRanges;
+ UINTN MaxCount;
+ BOOLEAN Rescan;
+
+ //
+ // Get SMM Configuration Protocol if it is present.
+ //
+ SmmConfiguration = NULL;
+ Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);
+
+ //
+ // Get SMRAM information.
+ //
+ Size = 0;
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+
+ //
+ // Get SMRAM reserved region count.
+ //
+ SmramReservedCount = 0;
+ if (SmmConfiguration != NULL) {
+ while (SmmConfiguration->SmramReservedRegions[SmramReservedCount].SmramReservedSize != 0) {
+ SmramReservedCount++;
+ }
+ }
+
+ //
+ // Reserve one entry for SMM Core in the full SMRAM ranges.
+ //
+ AdditionSmramRangeCount = 1;
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Reserve two entries for all SMM drivers and SMM Core in the full SMRAM ranges.
+ //
+ AdditionSmramRangeCount = 2;
+ }
+
+ if (SmramReservedCount == 0) {
+ //
+ // No reserved SMRAM entry from SMM Configuration Protocol.
+ //
+ *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
+ Size = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
+ FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocateZeroPool (Size);
+ ASSERT (FullSmramRanges != NULL);
+
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, FullSmramRanges);
+ ASSERT_EFI_ERROR (Status);
+
+ return FullSmramRanges;
+ }
+
+ //
+ // Why MaxCount = X + 2 * Y?
+ // Take Y = 1 as example below, Y > 1 case is just the iteration of Y = 1.
+ //
+ // X = 1 Y = 1 MaxCount = 3 = 1 + 2 * 1
+ // ---- ----
+ // | | ---- |--|
+ // | | | | -> | |
+ // | | ---- |--|
+ // ---- ----
+ //
+ // X = 2 Y = 1 MaxCount = 4 = 2 + 2 * 1
+ // ---- ----
+ // | | | |
+ // | | ---- |--|
+ // | | | | | |
+ // |--| | | -> |--|
+ // | | | | | |
+ // | | ---- |--|
+ // | | | |
+ // ---- ----
+ //
+ // X = 3 Y = 1 MaxCount = 5 = 3 + 2 * 1
+ // ---- ----
+ // | | | |
+ // | | ---- |--|
+ // |--| | | |--|
+ // | | | | -> | |
+ // |--| | | |--|
+ // | | ---- |--|
+ // | | | |
+ // ---- ----
+ //
+ // ......
+ //
+ MaxCount = SmramRangeCount + 2 * SmramReservedCount;
+
+ Size = MaxCount * sizeof (EFI_SMM_RESERVED_SMRAM_REGION);
+ SmramReservedRanges = (EFI_SMM_RESERVED_SMRAM_REGION *) AllocatePool (Size);
+ ASSERT (SmramReservedRanges != NULL);
+ for (Index = 0; Index < SmramReservedCount; Index++) {
+ CopyMem (&SmramReservedRanges[Index], &SmmConfiguration->SmramReservedRegions[Index], sizeof (EFI_SMM_RESERVED_SMRAM_REGION));
+ }
+
+ Size = MaxCount * sizeof (EFI_SMRAM_DESCRIPTOR);
+ TempSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
+ ASSERT (TempSmramRanges != NULL);
+ TempSmramRangeCount = 0;
+
+ SmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
+ ASSERT (SmramRanges != NULL);
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, SmramRanges);
+ ASSERT_EFI_ERROR (Status);
+
+ do {
+ Rescan = FALSE;
+ for (Index = 0; (Index < SmramRangeCount) && !Rescan; Index++) {
+ //
+ // Skip zero size entry.
+ //
+ if (SmramRanges[Index].PhysicalSize != 0) {
+ for (Index2 = 0; (Index2 < SmramReservedCount) && !Rescan; Index2++) {
+ //
+ // Skip zero size entry.
+ //
+ if (SmramReservedRanges[Index2].SmramReservedSize != 0) {
+ if (SmmIsSmramOverlap (
+ &SmramRanges[Index],
+ &SmramReservedRanges[Index2]
+ )) {
+ //
+ // There is overlap, need to split entry and then rescan.
+ //
+ SmmSplitSmramEntry (
+ &SmramRanges[Index],
+ &SmramReservedRanges[Index2],
+ SmramRanges,
+ &SmramRangeCount,
+ SmramReservedRanges,
+ &SmramReservedCount,
+ TempSmramRanges,
+ &TempSmramRangeCount
+ );
+ Rescan = TRUE;
+ }
+ }
+ }
+ if (!Rescan) {
+ //
+ // No any overlap, copy the entry to the temp SMRAM ranges.
+ // Zero SmramRanges[Index].PhysicalSize = 0;
+ //
+ CopyMem (&TempSmramRanges[TempSmramRangeCount++], &SmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
+ SmramRanges[Index].PhysicalSize = 0;
+ }
+ }
+ }
+ } while (Rescan);
+ ASSERT (TempSmramRangeCount <= MaxCount);
+
+ //
+ // Sort the entries
+ //
+ FullSmramRanges = AllocateZeroPool ((TempSmramRangeCount + AdditionSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR));
+ ASSERT (FullSmramRanges != NULL);
+ *FullSmramRangeCount = 0;
+ do {
+ for (Index = 0; Index < TempSmramRangeCount; Index++) {
+ if (TempSmramRanges[Index].PhysicalSize != 0) {
+ break;
+ }
+ }
+ ASSERT (Index < TempSmramRangeCount);
+ for (Index2 = 0; Index2 < TempSmramRangeCount; Index2++) {
+ if ((Index2 != Index) && (TempSmramRanges[Index2].PhysicalSize != 0) && (TempSmramRanges[Index2].CpuStart < TempSmramRanges[Index].CpuStart)) {
+ Index = Index2;
+ }
+ }
+ CopyMem (&FullSmramRanges[*FullSmramRangeCount], &TempSmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
+ *FullSmramRangeCount += 1;
+ TempSmramRanges[Index].PhysicalSize = 0;
+ } while (*FullSmramRangeCount < TempSmramRangeCount);
+ ASSERT (*FullSmramRangeCount == TempSmramRangeCount);
+ *FullSmramRangeCount += AdditionSmramRangeCount;
+
+ FreePool (SmramRanges);
+ FreePool (SmramReservedRanges);
+ FreePool (TempSmramRanges);
+
+ return FullSmramRanges;
+}
+
+/**
+ The Entry Point for SMM IPL
+
+ Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install
+ SMM Base 2 Protocol and SMM Communication Protocol, and register for the
+ critical events required to coordinate between DXE and SMM environments.
+
+ @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.
+ @retval Other Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmIplEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT64 MaxSize;
+ VOID *Registration;
+ UINT64 SmmCodeSize;
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ EFI_STATUS SetAttrStatus;
+ EFI_SMRAM_DESCRIPTOR *SmramRangeSmmDriver;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
+
+ //
+ // Fill in the image handle of the SMM IPL so the SMM Core can use this as the
+ // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded
+ // by the SMM Core
+ //
+ mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;
+
+ //
+ // Get SMM Access Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get SMM Control2 Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
+ ASSERT_EFI_ERROR (Status);
+
+ gSmmCorePrivate->SmramRanges = GetFullSmramRanges (&gSmmCorePrivate->SmramRangeCount);
+
+ //
+ // Open all SMRAM ranges
+ //
+ Status = mSmmAccess->Open (mSmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Print debug message that the SMRAM window is now open.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
+
+ //
+ // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
+ //
+ mCurrentSmramRange = NULL;
+ for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
+ //
+ // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
+ //
+ if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ continue;
+ }
+
+ if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {
+ if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {
+ if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {
+ MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
+ mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];
+ }
+ }
+ }
+ }
+
+ if (mCurrentSmramRange != NULL) {
+ //
+ // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n",
+ (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
+ (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
+ ));
+
+ GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
+ //
+ // Make sure we can change the desired memory attributes.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (
+ mSmramCacheBase,
+ &MemDesc
+ );
+ ASSERT_EFI_ERROR (Status);
+ if ((MemDesc.Capabilities & SMRAM_CAPABILITIES) != SMRAM_CAPABILITIES) {
+ gDS->SetMemorySpaceCapabilities (
+ mSmramCacheBase,
+ mSmramCacheSize,
+ MemDesc.Capabilities | SMRAM_CAPABILITIES
+ );
+ }
+ //
+ // If CPU AP is present, attempt to set SMRAM cacheability to WB and clear
+ // all paging attributes.
+ // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP
+ // is not available here.
+ //
+ CpuArch = NULL;
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
+ if (!EFI_ERROR (Status)) {
+ MemDesc.Attributes &= ~(EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK);
+ MemDesc.Attributes |= EFI_MEMORY_WB;
+ Status = gDS->SetMemorySpaceAttributes (
+ mSmramCacheBase,
+ mSmramCacheSize,
+ MemDesc.Attributes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));
+ }
+
+ DEBUG_CODE (
+ gDS->GetMemorySpaceDescriptor (
+ mSmramCacheBase,
+ &MemDesc
+ );
+ DEBUG ((DEBUG_INFO, "SMRAM attributes: %016lx\n", MemDesc.Attributes));
+ ASSERT ((MemDesc.Attributes & EFI_MEMORY_ATTRIBUTE_MASK) == 0);
+ );
+ }
+ //
+ // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
+ // Modules At Fixed Address Configuration Table.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+ //
+ SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
+ //
+ // The SMRAM available memory is assumed to be larger than SmmCodeSize
+ //
+ ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
+ //
+ // Retrieve Load modules At fixed address configuration table and save the SMRAM base.
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gLoadFixedAddressConfigurationTableGuid,
+ (VOID **) &mLMFAConfigurationTable
+ );
+ if (!EFI_ERROR (Status) && mLMFAConfigurationTable != NULL) {
+ mLMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;
+ //
+ // Print the SMRAM base
+ //
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", mLMFAConfigurationTable->SmramBase));
+ }
+
+ //
+ // Fill the Smram range for all SMM code
+ //
+ SmramRangeSmmDriver = &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 2];
+ SmramRangeSmmDriver->CpuStart = mCurrentSmramRange->CpuStart;
+ SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange->PhysicalStart;
+ SmramRangeSmmDriver->RegionState = mCurrentSmramRange->RegionState | EFI_ALLOCATED;
+ SmramRangeSmmDriver->PhysicalSize = SmmCodeSize;
+
+ mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
+ mCurrentSmramRange->CpuStart = mCurrentSmramRange->CpuStart + SmmCodeSize;
+ mCurrentSmramRange->PhysicalStart = mCurrentSmramRange->PhysicalStart + SmmCodeSize;
+ }
+ //
+ // Load SMM Core into SMRAM and execute it from SMRAM
+ //
+ Status = ExecuteSmmCoreFromSmram (
+ mCurrentSmramRange,
+ &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 1],
+ gSmmCorePrivate
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Print error message that the SMM Core failed to be loaded and executed.
+ //
+ DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
+
+ //
+ // Attempt to reset SMRAM cacheability to UC
+ //
+ if (CpuArch != NULL) {
+ SetAttrStatus = gDS->SetMemorySpaceAttributes(
+ mSmramCacheBase,
+ mSmramCacheSize,
+ EFI_MEMORY_UC
+ );
+ if (EFI_ERROR (SetAttrStatus)) {
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
+ }
+ }
+ }
+ } else {
+ //
+ // Print error message that there are not enough SMRAM resources to load the SMM Core.
+ //
+ DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
+ }
+
+ //
+ // If the SMM Core could not be loaded then close SMRAM window, free allocated
+ // resources, and return an error so SMM IPL will be unloaded.
+ //
+ if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {
+ //
+ // Close all SMRAM ranges
+ //
+ Status = mSmmAccess->Close (mSmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Print debug message that the SMRAM window is now closed.
+ //
+ DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
+
+ //
+ // Free all allocated resources
+ //
+ FreePool (gSmmCorePrivate->SmramRanges);
+
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Install SMM Base2 Protocol and SMM Communication Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSmmIplHandle,
+ &gEfiSmmBase2ProtocolGuid, &mSmmBase2,
+ &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,
+ &gEfiMmCommunication2ProtocolGuid, &mMmCommunication2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Create the set of protocol and event notifications that the SMM IPL requires
+ //
+ for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
+ if (mSmmIplEvents[Index].Protocol) {
+ mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (
+ mSmmIplEvents[Index].Guid,
+ mSmmIplEvents[Index].NotifyTpl,
+ mSmmIplEvents[Index].NotifyFunction,
+ mSmmIplEvents[Index].NotifyContext,
+ &Registration
+ );
+ } else {
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ mSmmIplEvents[Index].NotifyTpl,
+ mSmmIplEvents[Index].NotifyFunction,
+ mSmmIplEvents[Index].NotifyContext,
+ mSmmIplEvents[Index].Guid,
+ &mSmmIplEvents[Index].Event
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
new file mode 100644
index 000000000..6109d6b54
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
@@ -0,0 +1,91 @@
+## @file
+# This module provide an SMM CIS compliant implementation of SMM IPL.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmIpl
+ MODULE_UNI_FILE = PiSmmIpl.uni
+ FILE_GUID = 2FA2A6DA-11D5-4dc3-999A-749648B03C56
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SmmIplEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmIpl.c
+ PiSmmCorePrivateData.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ PeCoffLib
+ CacheMaintenanceLib
+ MemoryAllocationLib
+ DebugLib
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ UefiLib
+ UefiRuntimeLib
+ DxeServicesLib
+ PcdLib
+ ReportStatusCodeLib
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## PRODUCES
+ gEfiSmmCommunicationProtocolGuid ## PRODUCES
+ gEfiMmCommunication2ProtocolGuid ## PRODUCES
+ gEfiSmmAccess2ProtocolGuid ## CONSUMES
+ ## NOTIFY
+ ## CONSUMES
+ gEfiSmmConfigurationProtocolGuid
+ gEfiSmmControl2ProtocolGuid ## CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ ## UNDEFINED # Used to do smm communication
+ gEfiDxeSmmReadyToLockProtocolGuid
+ gEfiCpuArchProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## CONSUMES ## Event
+ ## PRODUCES ## UNDEFINED # Used to do smm communication
+ gEfiEventDxeDispatchGuid
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+ ## SOMETIMES_CONSUMES ## Event
+ ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
+ gEfiEventLegacyBootGuid
+ ## SOMETIMES_CONSUMES ## Event
+ ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
+ gEfiEventExitBootServicesGuid
+ ## SOMETIMES_CONSUMES ## Event
+ ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
+ gEfiEventReadyToBootGuid
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+
+[Depex]
+ gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PiSmmIplExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni
new file mode 100644
index 000000000..a2796854e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This module provide an SMM CIS compliant implementation of SMM IPL.
+//
+// This module provide an SMM CIS compliant implementation of SMM IPL.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM IPL"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM IPL."
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni
new file mode 100644
index 000000000..d7674de9a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PiSmmIpl Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core SMM Services Initial Program Loader"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Pool.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Pool.c
new file mode 100644
index 000000000..a503ff51f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Pool.c
@@ -0,0 +1,449 @@
+/** @file
+ SMM Memory pool management functions.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
+//
+// To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
+// all module is assigned an offset relative the SMRAM base in build time.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;
+
+/**
+ Convert a UEFI memory type to SMM pool type.
+
+ @param[in] MemoryType Type of pool to allocate.
+
+ @return SMM pool type
+**/
+SMM_POOL_TYPE
+UefiMemoryTypeToSmmPoolType (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));
+ switch (MemoryType) {
+ case EfiRuntimeServicesCode:
+ return SmmPoolTypeCode;
+ case EfiRuntimeServicesData:
+ return SmmPoolTypeData;
+ default:
+ return SmmPoolTypeMax;
+ }
+}
+
+
+/**
+ Called to initialize the memory service.
+
+ @param SmramRangeCount Number of SMRAM Regions
+ @param SmramRanges Pointer to SMRAM Descriptors
+
+**/
+VOID
+SmmInitializeMemoryServices (
+ IN UINTN SmramRangeCount,
+ IN EFI_SMRAM_DESCRIPTOR *SmramRanges
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN SmmPoolTypeIndex;
+ EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
+
+ //
+ // Initialize Pool list
+ //
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
+ for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
+ InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
+ }
+ }
+
+ Status = EfiGetSystemConfigurationTable (
+ &gLoadFixedAddressConfigurationTableGuid,
+ (VOID **) &LMFAConfigurationTable
+ );
+ if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
+ gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;
+ }
+
+ //
+ // Add Free SMRAM regions
+ // Need add Free memory at first, to let gSmmMemoryMap record data
+ //
+ for (Index = 0; Index < SmramRangeCount; Index++) {
+ if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ continue;
+ }
+ SmmAddMemoryRegion (
+ SmramRanges[Index].CpuStart,
+ SmramRanges[Index].PhysicalSize,
+ EfiConventionalMemory,
+ SmramRanges[Index].RegionState
+ );
+ }
+
+ //
+ // Add the allocated SMRAM regions
+ //
+ for (Index = 0; Index < SmramRangeCount; Index++) {
+ if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
+ continue;
+ }
+ SmmAddMemoryRegion (
+ SmramRanges[Index].CpuStart,
+ SmramRanges[Index].PhysicalSize,
+ EfiConventionalMemory,
+ SmramRanges[Index].RegionState
+ );
+ }
+
+}
+
+/**
+ Internal Function. Allocate a pool by specified PoolIndex.
+
+ @param PoolType Type of pool to allocate.
+ @param PoolIndex Index which indicate the Pool size.
+ @param FreePoolHdr The returned Free pool.
+
+ @retval EFI_OUT_OF_RESOURCES Allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+InternalAllocPoolByIndex (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN PoolIndex,
+ OUT FREE_POOL_HEADER **FreePoolHdr
+ )
+{
+ EFI_STATUS Status;
+ FREE_POOL_HEADER *Hdr;
+ POOL_TAIL *Tail;
+ EFI_PHYSICAL_ADDRESS Address;
+ SMM_POOL_TYPE SmmPoolType;
+
+ Address = 0;
+ SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);
+
+ ASSERT (PoolIndex <= MAX_POOL_INDEX);
+ Status = EFI_SUCCESS;
+ Hdr = NULL;
+ if (PoolIndex == MAX_POOL_INDEX) {
+ Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,
+ EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
+ &Address, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
+ } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
+ Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
+ RemoveEntryList (&Hdr->Link);
+ } else {
+ Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Signature = 0;
+ Hdr->Header.Size >>= 1;
+ Hdr->Header.Available = TRUE;
+ Hdr->Header.Type = 0;
+ Tail = HEAD_TO_TAIL(&Hdr->Header);
+ Tail->Signature = 0;
+ Tail->Size = 0;
+ InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
+ Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Signature = POOL_HEAD_SIGNATURE;
+ Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
+ Hdr->Header.Available = FALSE;
+ Hdr->Header.Type = PoolType;
+ Tail = HEAD_TO_TAIL(&Hdr->Header);
+ Tail->Signature = POOL_TAIL_SIGNATURE;
+ Tail->Size = Hdr->Header.Size;
+ }
+
+ *FreePoolHdr = Hdr;
+ return Status;
+}
+
+/**
+ Internal Function. Free a pool by specified PoolIndex.
+
+ @param FreePoolHdr The pool to free.
+ @param PoolTail The pointer to the pool tail.
+
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+InternalFreePoolByIndex (
+ IN FREE_POOL_HEADER *FreePoolHdr,
+ IN POOL_TAIL *PoolTail
+ )
+{
+ UINTN PoolIndex;
+ SMM_POOL_TYPE SmmPoolType;
+
+ ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
+
+ SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);
+
+ PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
+ FreePoolHdr->Header.Signature = 0;
+ FreePoolHdr->Header.Available = TRUE;
+ FreePoolHdr->Header.Type = 0;
+ PoolTail->Signature = 0;
+ PoolTail->Size = 0;
+ ASSERT (PoolIndex < MAX_POOL_INDEX);
+ InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate.
+ @param Size The amount of pool to allocate.
+ @param Buffer The address to return a pointer to the allocated
+ pool.
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ POOL_HEADER *PoolHdr;
+ POOL_TAIL *PoolTail;
+ FREE_POOL_HEADER *FreePoolHdr;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN PoolIndex;
+ BOOLEAN HasPoolTail;
+ BOOLEAN NeedGuard;
+ UINTN NoPages;
+
+ Address = 0;
+
+ if (PoolType != EfiRuntimeServicesCode &&
+ PoolType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NeedGuard = IsPoolTypeToGuard (PoolType);
+ HasPoolTail = !(NeedGuard &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+
+ //
+ // Adjust the size by the pool header & tail overhead
+ //
+ Size += POOL_OVERHEAD;
+ if (Size > MAX_POOL_SIZE || NeedGuard) {
+ if (!HasPoolTail) {
+ Size -= sizeof (POOL_TAIL);
+ }
+
+ NoPages = EFI_SIZE_TO_PAGES (Size);
+ Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, NoPages,
+ &Address, NeedGuard);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (NeedGuard) {
+ ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (
+ Address,
+ NoPages,
+ Size
+ );
+ }
+
+ PoolHdr = (POOL_HEADER*)(UINTN)Address;
+ PoolHdr->Signature = POOL_HEAD_SIGNATURE;
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);
+ PoolHdr->Available = FALSE;
+ PoolHdr->Type = PoolType;
+
+ if (HasPoolTail) {
+ PoolTail = HEAD_TO_TAIL (PoolHdr);
+ PoolTail->Signature = POOL_TAIL_SIGNATURE;
+ PoolTail->Size = PoolHdr->Size;
+ }
+
+ *Buffer = PoolHdr + 1;
+ return Status;
+ }
+
+ Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
+ PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
+ if ((Size & (Size - 1)) != 0) {
+ PoolIndex++;
+ }
+
+ Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);
+ if (!EFI_ERROR(Status)) {
+ *Buffer = &FreePoolHdr->Header + 1;
+ }
+ return Status;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate.
+ @param Size The amount of pool to allocate.
+ @param Buffer The address to return a pointer to the allocated
+ pool.
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
+ if (!EFI_ERROR (Status)) {
+ SmmCoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePool,
+ PoolType,
+ Size,
+ *Buffer,
+ NULL
+ );
+ }
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free.
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmInternalFreePool (
+ IN VOID *Buffer
+ )
+{
+ FREE_POOL_HEADER *FreePoolHdr;
+ POOL_TAIL *PoolTail;
+ BOOLEAN HasPoolTail;
+ BOOLEAN MemoryGuarded;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MemoryGuarded = IsHeapGuardEnabled () &&
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);
+ HasPoolTail = !(MemoryGuarded &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+
+ FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
+ ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);
+ ASSERT (!FreePoolHdr->Header.Available);
+ if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HasPoolTail) {
+ PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);
+ ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
+ ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
+ if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FreePoolHdr->Header.Size != PoolTail->Size) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ PoolTail = NULL;
+ }
+
+ if (MemoryGuarded) {
+ Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
+ return SmmInternalFreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
+ TRUE
+ );
+ }
+
+ if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
+ ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
+ ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
+ return SmmInternalFreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
+ FALSE
+ );
+ }
+ return InternalFreePoolByIndex (FreePoolHdr, PoolTail);
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free.
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SmmInternalFreePool (Buffer);
+ if (!EFI_ERROR (Status)) {
+ SmmCoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePool,
+ EfiMaxMemoryType,
+ 0,
+ Buffer,
+ NULL
+ );
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/Smi.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Smi.c
new file mode 100644
index 000000000..aeefb392f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/Smi.c
@@ -0,0 +1,333 @@
+/** @file
+ SMI management.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);
+
+SMI_ENTRY mRootSmiEntry = {
+ SMI_ENTRY_SIGNATURE,
+ INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries),
+ {0},
+ INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers),
+};
+
+/**
+ Finds the SMI entry for the requested handler type.
+
+ @param HandlerType The type of the interrupt
+ @param Create Create a new entry if not found
+
+ @return SMI entry
+
+**/
+SMI_ENTRY *
+EFIAPI
+SmmCoreFindSmiEntry (
+ IN EFI_GUID *HandlerType,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ SMI_ENTRY *Item;
+ SMI_ENTRY *SmiEntry;
+
+ //
+ // Search the SMI entry list for the matching GUID
+ //
+ SmiEntry = NULL;
+ for (Link = mSmiEntryList.ForwardLink;
+ Link != &mSmiEntryList;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {
+ //
+ // This is the SMI entry
+ //
+ SmiEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((SmiEntry == NULL) && Create) {
+ SmiEntry = AllocatePool (sizeof(SMI_ENTRY));
+ if (SmiEntry != NULL) {
+ //
+ // Initialize new SMI entry structure
+ //
+ SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
+ InitializeListHead (&SmiEntry->SmiHandlers);
+
+ //
+ // Add it to SMI entry list
+ //
+ InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);
+ }
+ }
+ return SmiEntry;
+}
+
+/**
+ Manage SMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
+ @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
+ @retval EFI_SUCCESS Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ SMI_ENTRY *SmiEntry;
+ SMI_HANDLER *SmiHandler;
+ BOOLEAN SuccessReturn;
+ EFI_STATUS Status;
+
+ Status = EFI_NOT_FOUND;
+ SuccessReturn = FALSE;
+ if (HandlerType == NULL) {
+ //
+ // Root SMI handler
+ //
+ SmiEntry = &mRootSmiEntry;
+ } else {
+ //
+ // Non-root SMI handler
+ //
+ SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, FALSE);
+ if (SmiEntry == NULL) {
+ //
+ // There is no handler registered for this interrupt source
+ //
+ return Status;
+ }
+ }
+ Head = &SmiEntry->SmiHandlers;
+
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+
+ Status = SmiHandler->Handler (
+ (EFI_HANDLE) SmiHandler,
+ Context,
+ CommBuffer,
+ CommBufferSize
+ );
+
+ switch (Status) {
+ case EFI_INTERRUPT_PENDING:
+ //
+ // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
+ // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
+ //
+ if (HandlerType != NULL) {
+ return EFI_INTERRUPT_PENDING;
+ }
+ break;
+
+ case EFI_SUCCESS:
+ //
+ // If at least one of the handlers returns EFI_SUCCESS then the function will return
+ // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
+ // additional handlers will be processed.
+ //
+ if (HandlerType != NULL) {
+ return EFI_SUCCESS;
+ }
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
+ //
+ // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
+ // then the function will return EFI_SUCCESS.
+ //
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_PENDING:
+ //
+ // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
+ // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
+ //
+ break;
+
+ default:
+ //
+ // Unexpected status code returned.
+ //
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ if (SuccessReturn) {
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Registers a handler to execute within SMM.
+
+ @param Handler Handler service function pointer.
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerRegister (
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+{
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ LIST_ENTRY *List;
+
+ if (Handler == NULL || DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
+ if (SmiHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
+ SmiHandler->Handler = Handler;
+ SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);
+
+ if (HandlerType == NULL) {
+ //
+ // This is root SMI handler
+ //
+ SmiEntry = &mRootSmiEntry;
+ } else {
+ //
+ // None root SMI handler
+ //
+ SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, TRUE);
+ if (SmiEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ List = &SmiEntry->SmiHandlers;
+
+ SmiHandler->SmiEntry = SmiEntry;
+ InsertTailList (List, &SmiHandler->Link);
+
+ *DispatchHandle = (EFI_HANDLE) SmiHandler;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister a handler in SMM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ LIST_ENTRY *EntryLink;
+ LIST_ENTRY *HandlerLink;
+
+ if (DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Look for it in root SMI handlers
+ //
+ SmiHandler = NULL;
+ for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers)
+ ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE) SmiHandler != DispatchHandle)
+ ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink)
+ ) {
+ SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ }
+
+ //
+ // Look for it in non-root SMI handlers
+ //
+ for ( EntryLink = GetFirstNode (&mSmiEntryList)
+ ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE) SmiHandler != DispatchHandle)
+ ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink)
+ ) {
+ SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers)
+ ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE) SmiHandler != DispatchHandle)
+ ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink)
+ ) {
+ SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ }
+ }
+
+ if ((EFI_HANDLE) SmiHandler != DispatchHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiEntry = SmiHandler->SmiEntry;
+
+ RemoveEntryList (&SmiHandler->Link);
+ FreePool (SmiHandler);
+
+ if (SmiEntry == NULL) {
+ //
+ // This is root SMI handler
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (IsListEmpty (&SmiEntry->SmiHandlers)) {
+ //
+ // No handler registered for this interrupt now, remove the SMI_ENTRY
+ //
+ RemoveEntryList (&SmiEntry->AllEntries);
+
+ FreePool (SmiEntry);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
new file mode 100644
index 000000000..0323617dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
@@ -0,0 +1,1367 @@
+/** @file
+ SMI handler profile support.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmEndOfDxe.h>
+
+#include <Guid/SmiHandlerProfile.h>
+
+#include "PiSmmCore.h"
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ EFI_GUID FileGuid;
+ PHYSICAL_ADDRESS EntryPoint;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINT32 ImageRef;
+ UINT16 PdbStringSize;
+ CHAR8 *PdbString;
+} IMAGE_STRUCT;
+
+/**
+ Register SMI handler profile handler.
+**/
+VOID
+RegisterSmiHandlerProfileHandler(
+ VOID
+ );
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ );
+
+extern LIST_ENTRY mSmiEntryList;
+extern LIST_ENTRY mHardwareSmiEntryList;
+extern SMI_ENTRY mRootSmiEntry;
+
+extern SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile;
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mHardwareSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mHardwareSmiEntryList);
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mRootSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntryList);
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreRootSmiEntryList = &mRootSmiEntryList;
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreSmiEntryList = &mSmiEntryList;
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreHardwareSmiEntryList = &mHardwareSmiEntryList;
+
+GLOBAL_REMOVE_IF_UNREFERENCED IMAGE_STRUCT *mImageStruct;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCountMax;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCount;
+
+GLOBAL_REMOVE_IF_UNREFERENCED VOID *mSmiHandlerProfileDatabase;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmiHandlerProfileDatabaseSize;
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmImageDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmRootSmiDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmSmiDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmHardwareSmiDatabaseSize;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmiHandlerProfileRecordingStatus;
+
+GLOBAL_REMOVE_IF_UNREFERENCED SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile = {
+ SmiHandlerProfileRegisterHandler,
+ SmiHandlerProfileUnregisterHandler,
+};
+
+/**
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index]));
+ }
+}
+
+/**
+ Get GUID name for an image.
+
+ @param[in] LoadedImage LoadedImage protocol.
+ @param[out] Guid Guid of the FFS
+**/
+VOID
+GetDriverGuid (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ OUT EFI_GUID *Guid
+ )
+{
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if ((DevicePathType(LoadedImage->FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType(LoadedImage->FilePath) == MEDIA_PIWG_FW_FILE_DP)) {
+ FileName = &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath)->FvFileName;
+ }
+ if (FileName != NULL) {
+ CopyGuid(Guid, FileName);
+ } else {
+ ZeroMem(Guid, sizeof(EFI_GUID));
+ }
+}
+
+/**
+ Add image structure.
+
+ @param ImageBase image base
+ @param ImageSize image size
+ @param EntryPoint image entry point
+ @param Guid FFS GUID of the image
+ @param PdbString image PDB string
+**/
+VOID
+AddImageStruct(
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN EFI_GUID *Guid,
+ IN CHAR8 *PdbString
+ )
+{
+ UINTN PdbStringSize;
+
+ if (mImageStructCount >= mImageStructCountMax) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ CopyGuid(&mImageStruct[mImageStructCount].FileGuid, Guid);
+ mImageStruct[mImageStructCount].ImageRef = mImageStructCount;
+ mImageStruct[mImageStructCount].ImageBase = ImageBase;
+ mImageStruct[mImageStructCount].ImageSize = ImageSize;
+ mImageStruct[mImageStructCount].EntryPoint = EntryPoint;
+ if (PdbString != NULL) {
+ PdbStringSize = AsciiStrSize(PdbString);
+ mImageStruct[mImageStructCount].PdbString = AllocateCopyPool (PdbStringSize, PdbString);
+ if (mImageStruct[mImageStructCount].PdbString != NULL) {
+ mImageStruct[mImageStructCount].PdbStringSize = (UINT16) PdbStringSize;
+ }
+ }
+
+ mImageStructCount++;
+}
+
+/**
+ return an image structure based upon image address.
+
+ @param Address image address
+
+ @return image structure
+**/
+IMAGE_STRUCT *
+AddressToImageStruct(
+ IN UINTN Address
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ if ((Address >= mImageStruct[Index].ImageBase) &&
+ (Address < mImageStruct[Index].ImageBase + mImageStruct[Index].ImageSize)) {
+ return &mImageStruct[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+ return an image reference index based upon image address.
+
+ @param Address image address
+
+ @return image reference index
+**/
+UINT32
+AddressToImageRef(
+ IN UINTN Address
+ )
+{
+ IMAGE_STRUCT *ImageStruct;
+
+ ImageStruct = AddressToImageStruct(Address);
+ if (ImageStruct != NULL) {
+ return ImageStruct->ImageRef;
+ }
+ return (UINT32)-1;
+}
+
+/**
+ Collect SMM image information based upon loaded image protocol.
+**/
+VOID
+GetSmmLoadedImage(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NoHandles;
+ UINTN HandleBufferSize;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ CHAR16 *PathStr;
+ EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate;
+ PHYSICAL_ADDRESS EntryPoint;
+ VOID *EntryPointInImage;
+ EFI_GUID Guid;
+ CHAR8 *PdbString;
+ PHYSICAL_ADDRESS RealImageBase;
+
+ HandleBufferSize = 0;
+ HandleBuffer = NULL;
+ Status = gSmst->SmmLocateHandle(
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &HandleBufferSize,
+ HandleBuffer
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return;
+ }
+ HandleBuffer = AllocateZeroPool (HandleBufferSize);
+ if (HandleBuffer == NULL) {
+ return;
+ }
+ Status = gSmst->SmmLocateHandle(
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &HandleBufferSize,
+ HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+
+ NoHandles = HandleBufferSize/sizeof(EFI_HANDLE);
+ mImageStructCountMax = (UINT32) NoHandles;
+ mImageStruct = AllocateZeroPool(mImageStructCountMax * sizeof(IMAGE_STRUCT));
+ if (mImageStruct == NULL) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gSmst->SmmHandleProtocol(
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ PathStr = ConvertDevicePathToText(LoadedImage->FilePath, TRUE, TRUE);
+ GetDriverGuid(LoadedImage, &Guid);
+ DEBUG ((DEBUG_INFO, "Image: %g ", &Guid));
+
+ EntryPoint = 0;
+ LoadedImagePrivate = BASE_CR(LoadedImage, EFI_SMM_DRIVER_ENTRY, SmmLoadedImage);
+ RealImageBase = (UINTN)LoadedImage->ImageBase;
+ if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) {
+ EntryPoint = LoadedImagePrivate->ImageEntryPoint;
+ if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint(LoadedImage->ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR(Status);
+ RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "(0x%lx - 0x%lx", RealImageBase, LoadedImage->ImageSize));
+ if (EntryPoint != 0) {
+ DEBUG ((DEBUG_INFO, ", EntryPoint:0x%lx", EntryPoint));
+ }
+ DEBUG ((DEBUG_INFO, ")\n"));
+
+ if (RealImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) RealImageBase);
+ DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString));
+ } else {
+ PdbString = NULL;
+ }
+ DEBUG ((DEBUG_INFO, " (%s)\n", PathStr));
+
+ AddImageStruct(RealImageBase, LoadedImage->ImageSize, EntryPoint, &Guid, PdbString);
+ }
+
+Done:
+ FreePool(HandleBuffer);
+ return;
+}
+
+/**
+ Dump SMI child context.
+
+ @param HandlerType the handler type
+ @param Context the handler context
+ @param ContextSize the handler context size
+**/
+VOID
+DumpSmiChildContext (
+ IN EFI_GUID *HandlerType,
+ IN VOID *Context,
+ IN UINTN ContextSize
+ )
+{
+ CHAR16 *Str;
+
+ if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " SwSmi - 0x%lx\n", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue));
+ } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " SxType - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type));
+ DEBUG ((DEBUG_INFO, " SxPhase - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " PowerButtonPhase - 0x%x\n", ((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " StandbyButtonPhase - 0x%x\n", ((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " PeriodicTimerPeriod - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period));
+ DEBUG ((DEBUG_INFO, " PeriodicTimerSmiTickInterval - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval));
+ } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " GpiNum - 0x%lx\n", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum));
+ } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " IoTrapAddress - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address));
+ DEBUG ((DEBUG_INFO, " IoTrapLength - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length));
+ DEBUG ((DEBUG_INFO, " IoTrapType - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type));
+ } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " UsbType - 0x%x\n", ((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type));
+ Str = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE);
+ DEBUG ((DEBUG_INFO, " UsbDevicePath - %s\n", Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, " Context - "));
+ InternalDumpData (Context, ContextSize);
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+}
+
+/**
+ Dump all SMI handlers associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+**/
+VOID
+DumpSmiHandlerOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ IMAGE_STRUCT *ImageStruct;
+
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ ImageStruct = AddressToImageStruct((UINTN)SmiHandler->Handler);
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " Module - %g", &ImageStruct->FileGuid));
+ }
+ if ((ImageStruct != NULL) && (ImageStruct->PdbString[0] != 0)) {
+ DEBUG ((DEBUG_INFO, " (Pdb - %a)", ImageStruct->PdbString));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ if (SmiHandler->ContextSize != 0) {
+ DumpSmiChildContext (&SmiEntry->HandlerType, SmiHandler->Context, SmiHandler->ContextSize);
+ }
+ DEBUG ((DEBUG_INFO, " Handler - 0x%x", SmiHandler->Handler));
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", (UINTN)SmiHandler->Handler - (UINTN) ImageStruct->ImageBase));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ DEBUG ((DEBUG_INFO, " CallerAddr - 0x%x", SmiHandler->CallerAddr));
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", SmiHandler->CallerAddr - (UINTN) ImageStruct->ImageBase));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+
+ return;
+}
+
+/**
+ Dump all SMI entry on the list.
+
+ @param SmiEntryList a list of SMI entry.
+**/
+VOID
+DumpSmiEntryList(
+ IN LIST_ENTRY *SmiEntryList
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, "SmiEntry - %g\n", &SmiEntry->HandlerType));
+ DumpSmiHandlerOnSmiEntry(SmiEntry);
+ }
+
+ return;
+}
+
+/**
+ SMM Ready To Lock event notification handler.
+
+ This function collects all SMM image information and build SmiHandleProfile database,
+ and register SmiHandlerProfile SMI handler.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockInSmiHandlerProfile (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ //
+ // Dump all image
+ //
+ DEBUG ((DEBUG_INFO, "##################\n"));
+ DEBUG ((DEBUG_INFO, "# IMAGE DATABASE #\n"));
+ DEBUG ((DEBUG_INFO, "##################\n"));
+ GetSmmLoadedImage ();
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ //
+ // Dump SMI Handler
+ //
+ DEBUG ((DEBUG_INFO, "########################\n"));
+ DEBUG ((DEBUG_INFO, "# SMI Handler DATABASE #\n"));
+ DEBUG ((DEBUG_INFO, "########################\n"));
+
+ DEBUG ((DEBUG_INFO, "# 1. ROOT SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreRootSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "# 2. GUID SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "# 3. Hardware SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreHardwareSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ RegisterSmiHandlerProfileHandler();
+
+ if (mImageStruct != NULL) {
+ FreePool(mImageStruct);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ returns SMM image data base size.
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmImageDatabaseSize(
+ VOID
+ )
+{
+ UINTN Size;
+ UINT32 Index;
+
+ Size = 0;
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ Size += sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
+ }
+ return Size;
+}
+
+/**
+ returns all SMI handlers' size associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+
+ @return all SMI handlers' size associated with SmiEntry.
+**/
+UINTN
+GetSmmSmiHandlerSizeOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ UINTN Size;
+
+ Size = 0;
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
+ }
+
+ return Size;
+}
+
+/**
+ return all SMI handler database size on the SMI entry list.
+
+ @param SmiEntryList a list of SMI entry.
+
+ @return all SMI handler database size on the SMI entry list.
+**/
+UINTN
+GetSmmSmiDatabaseSize(
+ IN LIST_ENTRY *SmiEntryList
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+ UINTN Size;
+
+ Size = 0;
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ Size += GetSmmSmiHandlerSizeOnSmiEntry(SmiEntry);
+ }
+ return Size;
+}
+
+/**
+ return SMI handler profile database size.
+
+ @return SMI handler profile database size.
+**/
+UINTN
+GetSmiHandlerProfileDatabaseSize (
+ VOID
+ )
+{
+ mSmmImageDatabaseSize = GetSmmImageDatabaseSize();
+ mSmmRootSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreRootSmiEntryList);
+ mSmmSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreSmiEntryList);
+ mSmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreHardwareSmiEntryList);
+
+ return mSmmImageDatabaseSize + mSmmSmiDatabaseSize + mSmmRootSmiDatabaseSize + mSmmHardwareSmiDatabaseSize;
+}
+
+/**
+ get SMM image database.
+
+ @param Data The buffer to hold SMM image database
+ @param ExpectedSize The expected size of the SMM image database
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmImageDatabaseData (
+ IN OUT VOID *Data,
+ IN UINTN ExpectedSize
+ )
+{
+ SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
+ UINTN Size;
+ UINTN Index;
+
+ ImageStruct = Data;
+ Size = 0;
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ if (Size >= ExpectedSize) {
+ return 0;
+ }
+ if (sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)) > ExpectedSize - Size) {
+ return 0;
+ }
+ ImageStruct->Header.Signature = SMM_CORE_IMAGE_DATABASE_SIGNATURE;
+ ImageStruct->Header.Length = (UINT32)(sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)));
+ ImageStruct->Header.Revision = SMM_CORE_IMAGE_DATABASE_REVISION;
+ CopyGuid(&ImageStruct->FileGuid, &mImageStruct[Index].FileGuid);
+ ImageStruct->ImageRef = mImageStruct[Index].ImageRef;
+ ImageStruct->EntryPoint = mImageStruct[Index].EntryPoint;
+ ImageStruct->ImageBase = mImageStruct[Index].ImageBase;
+ ImageStruct->ImageSize = mImageStruct[Index].ImageSize;
+ if (mImageStruct[Index].PdbStringSize != 0) {
+ ImageStruct->PdbStringOffset = sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE);
+ CopyMem ((VOID *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset), mImageStruct[Index].PdbString, mImageStruct[Index].PdbStringSize);
+ } else {
+ ImageStruct->PdbStringOffset = 0;
+ }
+ ImageStruct = (SMM_CORE_IMAGE_DATABASE_STRUCTURE *)((UINTN)ImageStruct + ImageStruct->Header.Length);
+ Size += sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
+ }
+
+ if (ExpectedSize != Size) {
+ return 0;
+ }
+ return Size;
+}
+
+/**
+ get all SMI handler data associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+ @param Data The buffer to hold all SMI handler data
+ @param MaxSize The max size of the SMM image database
+ @param Count The count of the SMI handler.
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmSmiHandlerDataOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry,
+ IN OUT VOID *Data,
+ IN UINTN MaxSize,
+ OUT UINT32 *Count
+ )
+{
+ SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct;
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ UINTN Size;
+
+ SmiHandlerStruct = Data;
+ Size = 0;
+ *Count = 0;
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ if (Size >= MaxSize) {
+ *Count = 0;
+ return 0;
+ }
+ if (sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)) > MaxSize - Size) {
+ *Count = 0;
+ return 0;
+ }
+ SmiHandlerStruct->Length = (UINT32)(sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)));
+ SmiHandlerStruct->CallerAddr = (UINTN)SmiHandler->CallerAddr;
+ SmiHandlerStruct->Handler = (UINTN)SmiHandler->Handler;
+ SmiHandlerStruct->ImageRef = AddressToImageRef((UINTN)SmiHandler->Handler);
+ SmiHandlerStruct->ContextBufferSize = (UINT32)SmiHandler->ContextSize;
+ if (SmiHandler->ContextSize != 0) {
+ SmiHandlerStruct->ContextBufferOffset = sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE);
+ CopyMem ((UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandler->Context, SmiHandler->ContextSize);
+ } else {
+ SmiHandlerStruct->ContextBufferOffset = 0;
+ }
+ Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
+ SmiHandlerStruct = (SMM_CORE_SMI_HANDLER_STRUCTURE *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length);
+ *Count = *Count + 1;
+ }
+
+ return Size;
+}
+
+/**
+ get all SMI handler database on the SMI entry list.
+
+ @param SmiEntryList a list of SMI entry.
+ @param HandlerCategory The handler category
+ @param Data The buffer to hold all SMI handler database
+ @param ExpectedSize The expected size of the SMM image database
+
+ @return all SMI database size on the SMI entry list.
+**/
+UINTN
+GetSmmSmiDatabaseData(
+ IN LIST_ENTRY *SmiEntryList,
+ IN UINT32 HandlerCategory,
+ IN OUT VOID *Data,
+ IN UINTN ExpectedSize
+ )
+{
+ SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct;
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+ UINTN Size;
+ UINTN SmiHandlerSize;
+ UINT32 SmiHandlerCount;
+
+ SmiStruct = Data;
+ Size = 0;
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ if (Size >= ExpectedSize) {
+ return 0;
+ }
+ if (sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE) > ExpectedSize - Size) {
+ return 0;
+ }
+
+ SmiStruct->Header.Signature = SMM_CORE_SMI_DATABASE_SIGNATURE;
+ SmiStruct->Header.Length = sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ SmiStruct->Header.Revision = SMM_CORE_SMI_DATABASE_REVISION;
+ SmiStruct->HandlerCategory = HandlerCategory;
+ CopyGuid(&SmiStruct->HandlerType, &SmiEntry->HandlerType);
+ Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ SmiHandlerSize = GetSmmSmiHandlerDataOnSmiEntry(SmiEntry, (UINT8 *)SmiStruct + SmiStruct->Header.Length, ExpectedSize - Size, &SmiHandlerCount);
+ SmiStruct->HandlerCount = SmiHandlerCount;
+ Size += SmiHandlerSize;
+ SmiStruct->Header.Length += (UINT32)SmiHandlerSize;
+ SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length);
+ }
+ if (ExpectedSize != Size) {
+ return 0;
+ }
+ return Size;
+}
+
+/**
+ Get SMI handler profile database.
+
+ @param Data the buffer to hold SMI handler profile database
+
+ @retval EFI_SUCCESS the database is got.
+ @retval EFI_INVALID_PARAMETER the database size mismatch.
+**/
+EFI_STATUS
+GetSmiHandlerProfileDatabaseData(
+ IN OUT VOID *Data
+ )
+{
+ UINTN SmmImageDatabaseSize;
+ UINTN SmmSmiDatabaseSize;
+ UINTN SmmRootSmiDatabaseSize;
+ UINTN SmmHardwareSmiDatabaseSize;
+
+ DEBUG((DEBUG_VERBOSE, "GetSmiHandlerProfileDatabaseData\n"));
+ SmmImageDatabaseSize = GetSmmImageDatabaseData(Data, mSmmImageDatabaseSize);
+ if (SmmImageDatabaseSize != mSmmImageDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmImageDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmRootSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreRootSmiEntryList, SmmCoreSmiHandlerCategoryRootHandler, (UINT8 *)Data + SmmImageDatabaseSize, mSmmRootSmiDatabaseSize);
+ if (SmmRootSmiDatabaseSize != mSmmRootSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmRootSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreSmiEntryList, SmmCoreSmiHandlerCategoryGuidHandler, (UINT8 *)Data + SmmImageDatabaseSize + mSmmRootSmiDatabaseSize, mSmmSmiDatabaseSize);
+ if (SmmSmiDatabaseSize != mSmmSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreHardwareSmiEntryList, SmmCoreSmiHandlerCategoryHardwareHandler, (UINT8 *)Data + SmmImageDatabaseSize + SmmRootSmiDatabaseSize + SmmSmiDatabaseSize, mSmmHardwareSmiDatabaseSize);
+ if (SmmHardwareSmiDatabaseSize != mSmmHardwareSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmHardwareSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ build SMI handler profile database.
+**/
+VOID
+BuildSmiHandlerProfileDatabase(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ mSmiHandlerProfileDatabaseSize = GetSmiHandlerProfileDatabaseSize();
+ mSmiHandlerProfileDatabase = AllocatePool(mSmiHandlerProfileDatabaseSize);
+ if (mSmiHandlerProfileDatabase == NULL) {
+ return;
+ }
+ Status = GetSmiHandlerProfileDatabaseData(mSmiHandlerProfileDatabase);
+ if (EFI_ERROR(Status)) {
+ FreePool(mSmiHandlerProfileDatabase);
+ mSmiHandlerProfileDatabase = NULL;
+ }
+}
+
+/**
+ Copy SMI handler profile data.
+
+ @param DataBuffer The buffer to hold SMI handler profile data.
+ @param DataSize On input, data buffer size.
+ On output, actual data buffer size copied.
+ @param DataOffset On input, data buffer offset to copy.
+ On output, next time data buffer offset to copy.
+
+**/
+VOID
+SmiHandlerProfileCopyData(
+ OUT VOID *DataBuffer,
+ IN OUT UINT64 *DataSize,
+ IN OUT UINT64 *DataOffset
+ )
+{
+ if (*DataOffset >= mSmiHandlerProfileDatabaseSize) {
+ *DataOffset = mSmiHandlerProfileDatabaseSize;
+ return;
+ }
+ if (mSmiHandlerProfileDatabaseSize - *DataOffset < *DataSize) {
+ *DataSize = mSmiHandlerProfileDatabaseSize - *DataOffset;
+ }
+
+ CopyMem(
+ DataBuffer,
+ (UINT8 *)mSmiHandlerProfileDatabase + *DataOffset,
+ (UINTN)*DataSize
+ );
+ *DataOffset = *DataOffset + *DataSize;
+}
+
+/**
+ SMI handler profile handler to get info.
+
+ @param SmiHandlerProfileParameterGetInfo The parameter of SMI handler profile get info.
+
+**/
+VOID
+SmiHandlerProfileHandlerGetInfo(
+ IN SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *SmiHandlerProfileParameterGetInfo
+ )
+{
+ BOOLEAN SmiHandlerProfileRecordingStatus;
+
+ SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
+ mSmiHandlerProfileRecordingStatus = FALSE;
+
+ SmiHandlerProfileParameterGetInfo->DataSize = mSmiHandlerProfileDatabaseSize;
+ SmiHandlerProfileParameterGetInfo->Header.ReturnStatus = 0;
+
+ mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
+}
+
+/**
+ SMI handler profile handler to get data by offset.
+
+ @param SmiHandlerProfileParameterGetDataByOffset The parameter of SMI handler profile get data by offset.
+
+**/
+VOID
+SmiHandlerProfileHandlerGetDataByOffset(
+ IN SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *SmiHandlerProfileParameterGetDataByOffset
+ )
+{
+ SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET SmiHandlerProfileGetDataByOffset;
+ BOOLEAN SmiHandlerProfileRecordingStatus;
+
+ SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
+ mSmiHandlerProfileRecordingStatus = FALSE;
+
+ CopyMem(&SmiHandlerProfileGetDataByOffset, SmiHandlerProfileParameterGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid((UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, (UINTN)SmiHandlerProfileGetDataByOffset.DataSize)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset: SMI handler profile get data in SMRAM or overflow!\n"));
+ SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ SmiHandlerProfileCopyData((VOID *)(UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, &SmiHandlerProfileGetDataByOffset.DataSize, &SmiHandlerProfileGetDataByOffset.DataOffset);
+ CopyMem(SmiHandlerProfileParameterGetDataByOffset, &SmiHandlerProfileGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));
+ SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
+
+Done:
+ mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
+}
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS Command is handled successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileHandler(
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ SMI_HANDLER_PROFILE_PARAMETER_HEADER *SmiHandlerProfileParameterHeader;
+ UINTN TempCommBufferSize;
+
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Enter\n"));
+
+ if (mSmiHandlerProfileDatabase == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < sizeof(SMI_HANDLER_PROFILE_PARAMETER_HEADER)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmiHandlerProfileParameterHeader = (SMI_HANDLER_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer);
+ SmiHandlerProfileParameterHeader->ReturnStatus = (UINT64)-1;
+
+ switch (SmiHandlerProfileParameterHeader->Command) {
+ case SMI_HANDLER_PROFILE_COMMAND_GET_INFO:
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetInfo\n"));
+ if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmiHandlerProfileHandlerGetInfo((SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)(UINTN)CommBuffer);
+ break;
+ case SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET:
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset\n"));
+ if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmiHandlerProfileHandlerGetDataByOffset((SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)(UINTN)CommBuffer);
+ break;
+ default:
+ break;
+ }
+
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Exit\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register SMI handler profile handler.
+**/
+VOID
+RegisterSmiHandlerProfileHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+
+ Status = gSmst->SmiHandlerRegister (
+ SmiHandlerProfileHandler,
+ &gSmiHandlerProfileGuid,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ BuildSmiHandlerProfileDatabase();
+}
+
+/**
+ Finds the SMI entry for the requested handler type.
+
+ @param HandlerType The type of the interrupt
+ @param Create Create a new entry if not found
+
+ @return SMI entry
+**/
+SMI_ENTRY *
+SmmCoreFindHardwareSmiEntry (
+ IN EFI_GUID *HandlerType,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ SMI_ENTRY *Item;
+ SMI_ENTRY *SmiEntry;
+
+ //
+ // Search the SMI entry list for the matching GUID
+ //
+ SmiEntry = NULL;
+ for (Link = mHardwareSmiEntryList.ForwardLink;
+ Link != &mHardwareSmiEntryList;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {
+ //
+ // This is the SMI entry
+ //
+ SmiEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((SmiEntry == NULL) && Create) {
+ SmiEntry = AllocatePool (sizeof(SMI_ENTRY));
+ if (SmiEntry != NULL) {
+ //
+ // Initialize new SMI entry structure
+ //
+ SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
+ InitializeListHead (&SmiEntry->SmiHandlers);
+
+ //
+ // Add it to SMI entry list
+ //
+ InsertTailList (&mHardwareSmiEntryList, &SmiEntry->AllEntries);
+ }
+ }
+ return SmiEntry;
+}
+
+/**
+ Convert EFI_SMM_USB_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT.
+
+ @param UsbContext A pointer to EFI_SMM_USB_REGISTER_CONTEXT
+ @param UsbContextSize The size of EFI_SMM_USB_REGISTER_CONTEXT in bytes
+ @param SmiHandlerUsbContextSize The size of SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT in bytes
+
+ @return SmiHandlerUsbContext A pointer to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT
+**/
+SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *
+ConvertSmiHandlerUsbContext (
+ IN EFI_SMM_USB_REGISTER_CONTEXT *UsbContext,
+ IN UINTN UsbContextSize,
+ OUT UINTN *SmiHandlerUsbContextSize
+ )
+{
+ UINTN DevicePathSize;
+ SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *SmiHandlerUsbContext;
+
+ ASSERT (UsbContextSize == sizeof(EFI_SMM_USB_REGISTER_CONTEXT));
+
+ DevicePathSize = GetDevicePathSize (UsbContext->Device);
+ SmiHandlerUsbContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize);
+ if (SmiHandlerUsbContext == NULL) {
+ *SmiHandlerUsbContextSize = 0;
+ return NULL;
+ }
+ SmiHandlerUsbContext->Type = UsbContext->Type;
+ SmiHandlerUsbContext->DevicePathSize = (UINT32)DevicePathSize;
+ CopyMem (SmiHandlerUsbContext + 1, UsbContext->Device, DevicePathSize);
+ *SmiHandlerUsbContextSize = sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize;
+ return SmiHandlerUsbContext;
+}
+
+/**
+ Convert EFI_SMM_SW_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT.
+
+ @param SwContext A pointer to EFI_SMM_SW_REGISTER_CONTEXT
+ @param SwContextSize The size of EFI_SMM_SW_REGISTER_CONTEXT in bytes
+ @param SmiHandlerSwContextSize The size of SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT in bytes
+
+ @return SmiHandlerSwContext A pointer to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT
+**/
+SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *
+ConvertSmiHandlerSwContext (
+ IN EFI_SMM_SW_REGISTER_CONTEXT *SwContext,
+ IN UINTN SwContextSize,
+ OUT UINTN *SmiHandlerSwContextSize
+ )
+{
+ SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *SmiHandlerSwContext;
+
+ ASSERT (SwContextSize == sizeof(EFI_SMM_SW_REGISTER_CONTEXT));
+
+ SmiHandlerSwContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT));
+ if (SmiHandlerSwContext == NULL) {
+ *SmiHandlerSwContextSize = 0;
+ return NULL;
+ }
+ SmiHandlerSwContext->SwSmiInputValue = SwContext->SwSmiInputValue;
+ *SmiHandlerSwContextSize = sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT);
+ return SmiHandlerSwContext;
+}
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ a new SMI handler is registered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param CallerAddress The address of the module who registers the SMI handler.
+ @param Context The context of the SMI handler.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+ @param ContextSize The size of the context in bytes.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+
+ @retval EFI_SUCCESS The information is recorded.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileRegisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ LIST_ENTRY *List;
+
+ if (((ContextSize == 0) && (Context != NULL)) ||
+ ((ContextSize != 0) && (Context == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
+ if (SmiHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
+ SmiHandler->Handler = Handler;
+ SmiHandler->CallerAddr = (UINTN)CallerAddress;
+ SmiHandler->Context = Context;
+ SmiHandler->ContextSize = ContextSize;
+
+ if (Context != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ SmiHandler->Context = ConvertSmiHandlerUsbContext (Context, ContextSize, &SmiHandler->ContextSize);
+ } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ SmiHandler->Context = ConvertSmiHandlerSwContext (Context, ContextSize, &SmiHandler->ContextSize);
+ } else {
+ SmiHandler->Context = AllocateCopyPool (ContextSize, Context);
+ }
+ }
+ if (SmiHandler->Context == NULL) {
+ SmiHandler->ContextSize = 0;
+ }
+
+ SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, TRUE);
+ if (SmiEntry == NULL) {
+ if (SmiHandler->Context != NULL) {
+ FreePool (SmiHandler->Context);
+ }
+ FreePool (SmiHandler);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ List = &SmiEntry->SmiHandlers;
+
+ SmiHandler->SmiEntry = SmiEntry;
+ InsertTailList (List, &SmiHandler->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ an existing SMI handler is unregistered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param Context The context of the SMI handler.
+ If it is NOT NULL, it will be used to check what is registered.
+ @param ContextSize The size of the context in bytes.
+ If Context is NOT NULL, it will be used to check what is registered.
+
+ @retval EFI_SUCCESS The original record is removed.
+ @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileUnregisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ SMI_HANDLER *TargetSmiHandler;
+ VOID *SearchContext;
+ UINTN SearchContextSize;
+
+ if (((ContextSize == 0) && (Context != NULL)) ||
+ ((ContextSize != 0) && (Context == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, FALSE);
+ if (SmiEntry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ SearchContext = Context;
+ SearchContextSize = ContextSize;
+ if (Context != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ SearchContext = ConvertSmiHandlerUsbContext (Context, ContextSize, &SearchContextSize);
+ } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ SearchContext = ConvertSmiHandlerSwContext (Context, ContextSize, &SearchContextSize);
+ }
+ }
+
+ TargetSmiHandler = NULL;
+ Head = &SmiEntry->SmiHandlers;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ if (SmiHandler->Handler == Handler) {
+ if ((SearchContext == NULL) ||
+ ((SearchContextSize == SmiHandler->ContextSize) && (CompareMem (SearchContext, SmiHandler->Context, SearchContextSize) == 0))) {
+ TargetSmiHandler = SmiHandler;
+ break;
+ }
+ }
+ }
+
+ if (SearchContext != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ FreePool (SearchContext);
+ }
+ }
+
+ if (TargetSmiHandler == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ SmiHandler = TargetSmiHandler;
+
+ RemoveEntryList (&SmiHandler->Link);
+ if (SmiHandler->Context != NULL) {
+ FreePool (SmiHandler->Context);
+ }
+ FreePool (SmiHandler);
+
+ if (IsListEmpty (&SmiEntry->SmiHandlers)) {
+ RemoveEntryList (&SmiEntry->AllEntries);
+ FreePool (SmiEntry);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize SmiHandler profile feature.
+**/
+VOID
+SmmCoreInitializeSmiHandlerProfile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+ EFI_HANDLE Handle;
+
+ if ((PcdGet8 (PcdSmiHandlerProfilePropertyMask) & 0x1) != 0) {
+ InsertTailList (&mRootSmiEntryList, &mRootSmiEntry.AllEntries);
+
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ SmmReadyToLockInSmiHandlerProfile,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Handle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gSmiHandlerProfileGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmiHandlerProfile
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c
new file mode 100644
index 000000000..1b302c810
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c
@@ -0,0 +1,2817 @@
+/** @file
+ Support routines for SMRAM profile.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCore.h"
+
+#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)
+#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_CONTEXT Context;
+ LIST_ENTRY *DriverInfoList;
+} MEMORY_PROFILE_CONTEXT_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_DRIVER_INFO DriverInfo;
+ LIST_ENTRY *AllocInfoList;
+ CHAR8 *PdbString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_DRIVER_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_ALLOC_INFO AllocInfo;
+ CHAR8 *ActionString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_ALLOC_INFO_DATA;
+
+//
+// When free memory less than 4 pages, dump it.
+//
+#define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4
+
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {
+ {
+ MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,
+ sizeof (MEMORY_PROFILE_FREE_MEMORY),
+ MEMORY_PROFILE_FREE_MEMORY_REVISION
+ },
+ 0,
+ 0
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ {
+ {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ sizeof (MEMORY_PROFILE_CONTEXT),
+ MEMORY_PROFILE_CONTEXT_REVISION
+ },
+ 0,
+ 0,
+ {0},
+ {0},
+ 0,
+ 0,
+ 0
+ },
+ &mImageQueue,
+};
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramReadyToLock;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileGettingStatus = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmramProfileDriverPathSize;
+
+/**
+ Dump SMRAM information.
+
+**/
+VOID
+DumpSmramInfo (
+ VOID
+ );
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolGetData (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ );
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCE No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolRegisterImage (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolUnregisterImage (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ );
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolGetRecordingState (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ );
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolSetRecordingState (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ );
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolRecord (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = {
+ SmramProfileProtocolGetData,
+ SmramProfileProtocolRegisterImage,
+ SmramProfileProtocolUnregisterImage,
+ SmramProfileProtocolGetRecordingState,
+ SmramProfileProtocolSetRecordingState,
+ SmramProfileProtocolRecord,
+};
+
+/**
+ Return SMRAM profile context.
+
+ @return SMRAM profile context.
+
+**/
+MEMORY_PROFILE_CONTEXT_DATA *
+GetSmramProfileContext (
+ VOID
+ )
+{
+ return mSmramProfileContextPtr;
+}
+
+/**
+ Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
+ If Pe32Data is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+
+ @return The Subsystem of the PE/COFF image.
+
+**/
+UINT16
+InternalPeCoffGetSubsystem (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT16 Magic;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ return Hdr.Te->Subsystem;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ Magic = Hdr.Pe32->OptionalHeader.Magic;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ return Hdr.Pe32->OptionalHeader.Subsystem;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ return Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ }
+ }
+
+ return 0x0000;
+}
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ ASSERT (Pe32Data != NULL);
+ ASSERT (EntryPoint != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ //
+ // Calculate the entry point relative to the start of the image.
+ // AddressOfEntryPoint is common for PE32 & PE32+
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
+ return RETURN_SUCCESS;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
+ return RETURN_SUCCESS;
+ }
+
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Build driver info.
+
+ @param ContextData Memory profile context.
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param EntryPoint Entry point of the image.
+ @param ImageSubsystem Image subsystem of the image.
+ @param FileType File type of the image.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+BuildDriverInfo (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN UINT16 ImageSubsystem,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ VOID *EntryPointInImage;
+ CHAR8 *PdbString;
+ UINTN PdbSize;
+ UINTN PdbOccupiedSize;
+
+ PdbSize = 0;
+ PdbOccupiedSize = 0;
+ PdbString = NULL;
+ if (ImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
+ if (PdbString != NULL) {
+ PdbSize = AsciiStrSize (PdbString);
+ PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
+ }
+ }
+
+ //
+ // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ Status = SmmInternalAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
+ (VOID **) &DriverInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (DriverInfoData != NULL);
+
+ ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
+
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
+ DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
+ if (FileName != NULL) {
+ CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
+ }
+ DriverInfo->ImageBase = ImageBase;
+ DriverInfo->ImageSize = ImageSize;
+ DriverInfo->EntryPoint = EntryPoint;
+ DriverInfo->ImageSubsystem = ImageSubsystem;
+ if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+ }
+ DriverInfo->FileType = FileType;
+ DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
+ InitializeListHead (DriverInfoData->AllocInfoList);
+ DriverInfo->CurrentUsage = 0;
+ DriverInfo->PeakUsage = 0;
+ DriverInfo->AllocRecordCount = 0;
+ if (PdbSize != 0) {
+ DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
+ DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
+ CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
+ } else {
+ DriverInfo->PdbStringOffset = 0;
+ DriverInfoData->PdbString = NULL;
+ }
+
+ InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
+ ContextData->Context.ImageCount ++;
+ ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
+
+ return DriverInfoData;
+}
+
+/**
+ Register image to DXE.
+
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param FileType File type of the image.
+
+**/
+VOID
+RegisterImageToDxe (
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+
+ if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
+ if (!EFI_ERROR (Status)) {
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ Status = ProfileProtocol->RegisterImage (
+ ProfileProtocol,
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
+ ImageBase,
+ ImageSize,
+ FileType
+ );
+ }
+ }
+}
+
+/**
+ Unregister image from DXE.
+
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+
+**/
+VOID
+UnregisterImageFromDxe (
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+
+ if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);
+ if (!EFI_ERROR (Status)) {
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ Status = ProfileProtocol->UnregisterImage (
+ ProfileProtocol,
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
+ ImageBase,
+ ImageSize
+ );
+ }
+ }
+}
+
+/**
+ Return if record for this driver is needed..
+
+ @param DriverFilePath Driver file path.
+
+ @retval TRUE Record for this driver is needed.
+ @retval FALSE Record for this driver is not needed.
+
+**/
+BOOLEAN
+NeedRecordThisDriver (
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
+ UINTN DevicePathSize;
+ UINTN FilePathSize;
+
+ if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) {
+ //
+ // Invalid Device Path means record all.
+ //
+ return TRUE;
+ }
+
+ //
+ // Record FilePath without end node.
+ //
+ FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+
+ DevicePathInstance = mSmramProfileDriverPath;
+ do {
+ //
+ // Find End node (it might be END_ENTIRE or END_INSTANCE)
+ //
+ TmpDevicePath = DevicePathInstance;
+ while (!IsDevicePathEndType (TmpDevicePath)) {
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ //
+ // Do not compare END node
+ //
+ DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
+ if ((FilePathSize == DevicePathSize) &&
+ (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
+ return TRUE;
+ }
+
+ //
+ // Get next instance
+ //
+ DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
+ } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
+
+ return FALSE;
+}
+
+/**
+ Register SMM Core to SMRAM profile.
+
+ @param ContextData SMRAM profile context.
+
+ @retval TRUE Register success.
+ @retval FALSE Register fail.
+
+**/
+BOOLEAN
+RegisterSmmCore (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
+ return FALSE;
+ }
+
+ ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ &gEfiCallerIdGuid,
+ ImageBase,
+ gSmmCorePrivate->PiSmmCoreImageSize,
+ gSmmCorePrivate->PiSmmCoreEntryPoint,
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
+ EFI_FV_FILETYPE_SMM_CORE
+ );
+ if (DriverInfoData == NULL) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize SMRAM profile.
+
+**/
+VOID
+SmramProfileInit (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;
+
+ RegisterImageToDxe (
+ &gEfiCallerIdGuid,
+ gSmmCorePrivate->PiSmmCoreImageBase,
+ gSmmCorePrivate->PiSmmCoreImageSize,
+ EFI_FV_FILETYPE_SMM_CORE
+ );
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return;
+ }
+
+ SmramProfileContext = GetSmramProfileContext ();
+ if (SmramProfileContext != NULL) {
+ return;
+ }
+
+ mSmramProfileGettingStatus = FALSE;
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
+ mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+ } else {
+ mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
+ }
+ mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
+ mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
+ mSmramProfileContextPtr = &mSmramProfileContext;
+
+ RegisterSmmCore (&mSmramProfileContext);
+
+ DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
+}
+
+/**
+ Install SMRAM profile protocol.
+
+**/
+VOID
+SmramProfileInstallProtocol (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return;
+ }
+
+ Handle = NULL;
+ Status = SmmInstallProtocolInterface (
+ &Handle,
+ &gEdkiiSmmMemoryProfileGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmProfileProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the GUID file name from the file path.
+
+ @param FilePath File path.
+
+ @return The GUID file name from the file path.
+
+**/
+EFI_GUID *
+GetFileNameFromFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if (FilePath != NULL) {
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
+ while (!IsDevicePathEnd (ThisFilePath)) {
+ FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
+ if (FileName != NULL) {
+ break;
+ }
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
+ }
+ }
+
+ return FileName;
+}
+
+/**
+ Register SMM image to SMRAM profile.
+
+ @param DriverEntry SMM image info.
+ @param RegisterToDxe Register image to DXE.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterSmramProfileImage (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
+ IN BOOLEAN RegisterToDxe
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ if (RegisterToDxe) {
+ RegisterImageToDxe (
+ &DriverEntry->FileName,
+ DriverEntry->ImageBuffer,
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
+ EFI_FV_FILETYPE_SMM
+ );
+ }
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ &DriverEntry->FileName,
+ DriverEntry->ImageBuffer,
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
+ DriverEntry->ImageEntryPoint,
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),
+ EFI_FV_FILETYPE_SMM
+ );
+ if (DriverInfoData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search image from memory profile.
+
+ @param ContextData Memory profile context.
+ @param FileName Image file name.
+ @param Address Image Address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoByFileNameAndAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
+ (Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Search image from memory profile.
+ It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)
+
+ @param ContextData Memory profile context.
+ @param Address Image or Function address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoFromAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Unregister image from SMRAM profile.
+
+ @param DriverEntry SMM image info.
+ @param UnregisterFromDxe Unregister image from DXE.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterSmramProfileImage (
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
+ IN BOOLEAN UnregisterFromDxe
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ EFI_GUID *FileName;
+ PHYSICAL_ADDRESS ImageAddress;
+ VOID *EntryPointInImage;
+ UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ if (UnregisterFromDxe) {
+ UnregisterImageFromDxe (
+ &DriverEntry->FileName,
+ DriverEntry->ImageBuffer,
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
+ );
+ }
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = NULL;
+ FileName = &DriverEntry->FileName;
+ ImageAddress = DriverEntry->ImageBuffer;
+ if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageAddress here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;
+ }
+ if (FileName != NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
+
+ // Keep the ImageBase for RVA calculation in Application.
+ //DriverInfoData->DriverInfo.ImageBase = 0;
+ DriverInfoData->DriverInfo.ImageSize = 0;
+
+ if (DriverInfoData->DriverInfo.PeakUsage == 0) {
+ ContextData->Context.ImageCount --;
+ RemoveEntryList (&DriverInfoData->Link);
+ //
+ // Use SmmInternalFreePool() that will not update profile for this FreePool action.
+ //
+ SmmInternalFreePool (DriverInfoData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if this memory type needs to be recorded into memory profile.
+ Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile.
+
+ @param MemoryType Memory type.
+
+ @retval TRUE This memory type need to be recorded.
+ @retval FALSE This memory type need not to be recorded.
+
+**/
+BOOLEAN
+SmmCoreNeedRecordProfile (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if (MemoryType != EfiRuntimeServicesCode &&
+ MemoryType != EfiRuntimeServicesData) {
+ return FALSE;
+ }
+
+ TestBit = LShiftU64 (1, MemoryType);
+
+ if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Convert EFI memory type to profile memory index. The rule is:
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
+ As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData,
+ so return input memory type directly.
+
+ @param MemoryType Memory type.
+
+ @return EFI memory type as profile memory index.
+
+**/
+EFI_MEMORY_TYPE
+GetProfileMemoryIndex (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ return MemoryType;
+}
+
+/**
+ Update SMRAM profile FreeMemoryPages information
+
+ @param ContextData Memory profile context.
+
+**/
+VOID
+SmramProfileUpdateFreePages (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+ LIST_ENTRY *FreePageList;
+ UINTN NumberOfPages;
+
+ NumberOfPages = 0;
+ FreePageList = &mSmmMemoryMap;
+ for (Node = FreePageList->BackLink;
+ Node != FreePageList;
+ Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ NumberOfPages += Pages->NumberOfPages;
+ }
+
+ mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;
+
+ if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {
+ DumpSmramInfo ();
+ }
+}
+
+/**
+ Update SMRAM profile Allocate information.
+
+ @param CallerAddress Address of caller who call Allocate.
+ @param Action This Allocate action.
+ @param MemoryType Memory type.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+
+**/
+EFI_STATUS
+SmmCoreUpdateProfileAllocate (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size,
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ EFI_MEMORY_TYPE ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ UINTN ActionStringSize;
+ UINTN ActionStringOccupiedSize;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+ if (DriverInfoData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ActionStringSize = 0;
+ ActionStringOccupiedSize = 0;
+ if (ActionString != NULL) {
+ ActionStringSize = AsciiStrSize (ActionString);
+ ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
+ }
+
+ //
+ // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ AllocInfoData = NULL;
+ Status = SmmInternalAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (*AllocInfoData) + ActionStringSize,
+ (VOID **) &AllocInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (AllocInfoData != NULL);
+
+ //
+ // Only update SequenceCount if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ContextData->Context.SequenceCount ++;
+ }
+
+ AllocInfo = &AllocInfoData->AllocInfo;
+ AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
+ AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
+ AllocInfo->CallerAddress = CallerAddress;
+ AllocInfo->SequenceId = ContextData->Context.SequenceCount;
+ AllocInfo->Action = Action;
+ AllocInfo->MemoryType = MemoryType;
+ AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
+ AllocInfo->Size = Size;
+ if (ActionString != NULL) {
+ AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
+ AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
+ CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
+ } else {
+ AllocInfo->ActionStringOffset = 0;
+ AllocInfoData->ActionString = NULL;
+ }
+
+ InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfo->AllocRecordCount ++;
+
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
+
+ DriverInfo->CurrentUsage += Size;
+ if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
+ DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
+ }
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
+ if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
+ DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
+ }
+
+ Context->CurrentTotalUsage += Size;
+ if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
+ Context->PeakTotalUsage = Context->CurrentTotalUsage;
+ }
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
+ if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
+ Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
+ }
+
+ SmramProfileUpdateFreePages (ContextData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get memory profile alloc info from memory profile
+
+ @param DriverInfoData Driver info
+ @param BasicAction This Free basic action
+ @param Size Buffer size
+ @param Buffer Buffer address
+
+ @return Pointer to memory profile alloc info.
+**/
+MEMORY_PROFILE_ALLOC_INFO_DATA *
+GetMemoryProfileAllocInfoFromAddress (
+ IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
+ IN MEMORY_PROFILE_ACTION BasicAction,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ AllocInfo = &AllocInfoData->AllocInfo;
+ if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
+ continue;
+ }
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
+ ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
+ return AllocInfoData;
+ }
+ break;
+ case MemoryProfileActionAllocatePool:
+ if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ return AllocInfoData;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Update SMRAM profile Free information.
+
+ @param CallerAddress Address of caller who call Free.
+ @param Action This Free action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+SmmCoreUpdateProfileFree (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ EFI_MEMORY_TYPE ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ BOOLEAN Found;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+
+ //
+ // Do not return if DriverInfoData == NULL here,
+ // because driver A might free memory allocated by driver B.
+ //
+
+ //
+ // Need use do-while loop to find all possible record,
+ // because one address might be recorded multiple times.
+ //
+ Found = FALSE;
+ AllocInfoData = NULL;
+ do {
+ if (DriverInfoData != NULL) {
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ }
+ if (AllocInfoData == NULL) {
+ //
+ // Legal case, because driver A might free memory allocated by driver B, by some protocol.
+ //
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ ThisDriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ if (AllocInfoData != NULL) {
+ DriverInfoData = ThisDriverInfoData;
+ break;
+ }
+ }
+
+ if (AllocInfoData == NULL) {
+ //
+ // If (!Found), no matched allocate info is found for this free action.
+ // It is because the specified memory type allocate actions have been filtered by
+ // CoreNeedRecordProfile(), but free actions have no memory type information,
+ // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
+ // filtered here.
+ //
+ // If (Found), it is normal exit path.
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+ }
+
+ ASSERT (DriverInfoData != NULL);
+ ASSERT (AllocInfoData != NULL);
+
+ Found = TRUE;
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ AllocInfo = &AllocInfoData->AllocInfo;
+
+ DriverInfo->AllocRecordCount --;
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
+
+ Context->CurrentTotalUsage -= AllocInfo->Size;
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+
+ DriverInfo->CurrentUsage -= AllocInfo->Size;
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+ }
+
+ RemoveEntryList (&AllocInfoData->Link);
+
+ if (BasicAction == MemoryProfileActionFreePages) {
+ if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ SmmCoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
+ (VOID *) (UINTN) AllocInfo->Buffer,
+ AllocInfoData->ActionString
+ );
+ }
+ if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
+ SmmCoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
+ (VOID *) ((UINTN) Buffer + Size),
+ AllocInfoData->ActionString
+ );
+ }
+ }
+
+ //
+ // Use SmmInternalFreePool() that will not update profile for this FreePool action.
+ //
+ SmmInternalFreePool (AllocInfoData);
+ } while (TRUE);
+}
+
+/**
+ Update SMRAM profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_ACTION BasicAction;
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mSmramProfileGettingStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (!mSmramProfileRecordingEnable) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the basic action to know how to process the record
+ //
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ //
+ // Free operations have no memory type information, so skip the check.
+ //
+ if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) {
+ //
+ // Only record limited MemoryType.
+ //
+ if (!SmmCoreNeedRecordProfile (MemoryType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePages:
+ Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
+ break;
+ case MemoryProfileActionAllocatePool:
+ Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePool:
+ Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ SMRAM profile ready to lock callback function.
+
+**/
+VOID
+SmramProfileReadyToLock (
+ VOID
+ )
+{
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return;
+ }
+
+ DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));
+ mSmramReadyToLock = TRUE;
+}
+
+////////////////////
+
+/**
+ Get SMRAM profile data size.
+
+ @return SMRAM profile data size.
+
+**/
+UINTN
+SmramProfileGetDataSize (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN TotalSize;
+ LIST_ENTRY *Node;
+ LIST_ENTRY *FreePageList;
+ LIST_ENTRY *FreePoolList;
+ FREE_POOL_HEADER *Pool;
+ UINTN PoolListIndex;
+ UINTN Index;
+ UINTN SmmPoolTypeIndex;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return 0;
+ }
+
+ TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ TotalSize += DriverInfoData->DriverInfo.Header.Length;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ TotalSize += AllocInfoData->AllocInfo.Header.Length;
+ }
+ }
+
+
+ Index = 0;
+ FreePageList = &mSmmMemoryMap;
+ for (Node = FreePageList->BackLink;
+ Node != FreePageList;
+ Node = Node->BackLink) {
+ Index++;
+ }
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
+ FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
+ for (Node = FreePoolList->BackLink;
+ Node != FreePoolList;
+ Node = Node->BackLink) {
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
+ if (Pool->Header.Available) {
+ Index++;
+ }
+ }
+ }
+ }
+
+ TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));
+ TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));
+
+ return TotalSize;
+}
+
+/**
+ Copy SMRAM profile data.
+
+ @param ProfileBuffer The buffer to hold SMRAM profile data.
+ @param ProfileSize On input, profile buffer size.
+ On output, actual profile data size copied.
+ @param ProfileOffset On input, profile buffer offset to copy.
+ On output, next time profile buffer offset to copy.
+
+**/
+VOID
+SmramProfileCopyData (
+ OUT VOID *ProfileBuffer,
+ IN OUT UINT64 *ProfileSize,
+ IN OUT UINT64 *ProfileOffset
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+ LIST_ENTRY *FreePageList;
+ LIST_ENTRY *FreePoolList;
+ FREE_POOL_HEADER *Pool;
+ UINTN PoolListIndex;
+ UINT32 Index;
+ MEMORY_PROFILE_FREE_MEMORY *FreeMemory;
+ MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;
+ MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor;
+ UINT64 Offset;
+ UINT64 RemainingSize;
+ UINTN PdbSize;
+ UINTN ActionStringSize;
+ UINTN SmmPoolTypeIndex;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ RemainingSize = *ProfileSize;
+ Offset = 0;
+
+ if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) {
+ Context = ProfileBuffer;
+ CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
+ RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_CONTEXT);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ if (*ProfileOffset < (Offset + DriverInfoData->DriverInfo.Header.Length)) {
+ if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) {
+ DriverInfo = ProfileBuffer;
+ CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
+ if (DriverInfo->PdbStringOffset != 0) {
+ PdbSize = AsciiStrSize (DriverInfoData->PdbString);
+ CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
+ }
+ RemainingSize -= DriverInfo->Header.Length;
+ ProfileBuffer = (UINT8 *) ProfileBuffer + DriverInfo->Header.Length;
+ } else {
+ goto Done;
+ }
+ }
+ Offset += DriverInfoData->DriverInfo.Header.Length;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ if (*ProfileOffset < (Offset + AllocInfoData->AllocInfo.Header.Length)) {
+ if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) {
+ AllocInfo = ProfileBuffer;
+ CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
+ if (AllocInfo->ActionStringOffset) {
+ ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
+ CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
+ }
+ RemainingSize -= AllocInfo->Header.Length;
+ ProfileBuffer = (UINT8 *) ProfileBuffer + AllocInfo->Header.Length;
+ } else {
+ goto Done;
+ }
+ }
+ Offset += AllocInfoData->AllocInfo.Header.Length;
+ }
+ }
+
+
+ if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) {
+ FreeMemory = ProfileBuffer;
+ CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));
+ Index = 0;
+ FreePageList = &mSmmMemoryMap;
+ for (Node = FreePageList->BackLink;
+ Node != FreePageList;
+ Node = Node->BackLink) {
+ Index++;
+ }
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
+ FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
+ for (Node = FreePoolList->BackLink;
+ Node != FreePoolList;
+ Node = Node->BackLink) {
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
+ if (Pool->Header.Available) {
+ Index++;
+ }
+ }
+ }
+ }
+ FreeMemory->FreeMemoryEntryCount = Index;
+
+ RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY);
+ FreePageList = &mSmmMemoryMap;
+ for (Node = FreePageList->BackLink;
+ Node != FreePageList;
+ Node = Node->BackLink) {
+ if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ MemoryProfileDescriptor = ProfileBuffer;
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
+ MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;
+ MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
+
+ RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ }
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
+ FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
+ for (Node = FreePoolList->BackLink;
+ Node != FreePoolList;
+ Node = Node->BackLink) {
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
+ if (Pool->Header.Available) {
+ if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
+ MemoryProfileDescriptor = ProfileBuffer;
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
+ MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;
+ MemoryProfileDescriptor->Size = Pool->Header.Size;
+
+ RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ }
+ }
+ }
+ }
+
+ if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) {
+ MemoryRange = ProfileBuffer;
+ MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;
+ MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);
+ MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;
+ MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;
+
+ RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE);
+ for (Index = 0; Index < mFullSmramRangeCount; Index++) {
+ if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
+ if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
+ MemoryProfileDescriptor = ProfileBuffer;
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
+ MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;
+ MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;
+
+ RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ } else {
+ goto Done;
+ }
+ }
+ Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
+ }
+
+Done:
+ //
+ // On output, actual profile data size copied.
+ //
+ *ProfileSize -= RemainingSize;
+ //
+ // On output, next time profile buffer offset to copy.
+ //
+ *ProfileOffset = Offset;
+}
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolGetData (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ )
+{
+ UINT64 Size;
+ UINT64 Offset;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ Size = SmramProfileGetDataSize ();
+
+ if (*ProfileSize < Size) {
+ *ProfileSize = Size;
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Offset = 0;
+ SmramProfileCopyData (ProfileBuffer, &Size, &Offset);
+ *ProfileSize = Size;
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+ return EFI_SUCCESS;
+}
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolRegisterImage (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_DRIVER_ENTRY DriverEntry;
+ VOID *EntryPointInImage;
+ EFI_GUID *Name;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ Name = GetFileNameFromFilePath (FilePath);
+ if (Name != NULL) {
+ CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
+ }
+ DriverEntry.ImageBuffer = ImageBase;
+ DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ return RegisterSmramProfileImage (&DriverEntry, FALSE);
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolUnregisterImage (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_DRIVER_ENTRY DriverEntry;
+ VOID *EntryPointInImage;
+ EFI_GUID *Name;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ Name = GetFileNameFromFilePath (FilePath);
+ if (Name != NULL) {
+ CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
+ }
+ DriverEntry.ImageBuffer = ImageBase;
+ DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ return UnregisterSmramProfileImage (&DriverEntry, FALSE);
+}
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolGetRecordingState (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (RecordingState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *RecordingState = mSmramProfileRecordingEnable;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolSetRecordingState (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mSmramProfileRecordingEnable = RecordingState;
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileProtocolRecord (
+ IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+}
+
+/**
+ SMRAM profile handler to get profile info.
+
+ @param SmramProfileParameterGetInfo The parameter of SMM profile get size.
+
+**/
+VOID
+SmramProfileHandlerGetInfo (
+ IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();
+ SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ SMRAM profile handler to get profile data.
+
+ @param SmramProfileParameterGetData The parameter of SMM profile get data.
+
+**/
+VOID
+SmramProfileHandlerGetData (
+ IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData
+ )
+{
+ UINT64 ProfileSize;
+ UINT64 ProfileOffset;
+ SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+
+ CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));
+
+ ProfileSize = SmramProfileGetDataSize();
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;
+ SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ if (SmramProfileGetData.ProfileSize < ProfileSize) {
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;
+ SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ ProfileOffset = 0;
+ SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset);
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;
+ SmramProfileParameterGetData->Header.ReturnStatus = 0;
+
+Done:
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ SMRAM profile handler to get profile data by offset.
+
+ @param SmramProfileParameterGetDataByOffset The parameter of SMM profile get data by offset.
+
+**/
+VOID
+SmramProfileHandlerGetDataByOffset (
+ IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *SmramProfileParameterGetDataByOffset
+ )
+{
+ SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET SmramProfileGetDataByOffset;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+
+ CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetDataByOffset.ProfileBuffer, (UINTN) SmramProfileGetDataByOffset.ProfileSize)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n"));
+ SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset);
+ CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
+ SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
+
+Done:
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ SMRAM profile handler to register SMM image.
+
+ @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.
+
+**/
+VOID
+SmramProfileHandlerRegisterImage (
+ IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_DRIVER_ENTRY DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));
+ DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;
+ DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ Status = RegisterSmramProfileImage (&DriverEntry, FALSE);
+ if (!EFI_ERROR (Status)) {
+ SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;
+ }
+}
+
+/**
+ SMRAM profile handler to unregister SMM image.
+
+ @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.
+
+**/
+VOID
+SmramProfileHandlerUnregisterImage (
+ IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_DRIVER_ENTRY DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));
+ DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;
+ DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ Status = UnregisterSmramProfileImage (&DriverEntry, FALSE);
+ if (!EFI_ERROR (Status)) {
+ SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;
+ }
+}
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS Command is handled successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SmramProfileHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader;
+ UINTN TempCommBufferSize;
+ SMRAM_PROFILE_PARAMETER_RECORDING_STATE *ParameterRecordingState;
+
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);
+
+ SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;
+
+ if (GetSmramProfileContext () == NULL) {
+ SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;
+ return EFI_SUCCESS;
+ }
+
+ switch (SmramProfileParameterHeader->Command) {
+ case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);
+ break;
+ case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);
+ break;
+ case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) (UINTN) CommBuffer);
+ break;
+ case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ if (mSmramReadyToLock) {
+ return EFI_SUCCESS;
+ }
+ SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);
+ break;
+ case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ if (mSmramReadyToLock) {
+ return EFI_SUCCESS;
+ }
+ SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);
+ break;
+ case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetRecordingState\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
+ ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable;
+ ParameterRecordingState->Header.ReturnStatus = 0;
+ break;
+ case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE:
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerSetRecordingState\n"));
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
+ mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState;
+ ParameterRecordingState->Header.ReturnStatus = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register SMRAM profile handler.
+
+**/
+VOID
+RegisterSmramProfileHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+
+ if (!IS_SMRAM_PROFILE_ENABLED) {
+ return;
+ }
+
+ Status = SmiHandlerRegister (
+ SmramProfileHandler,
+ &gEdkiiMemoryProfileGuid,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+////////////////////
+
+/**
+ Dump SMRAM range.
+
+**/
+VOID
+DumpSmramRange (
+ VOID
+ )
+{
+ UINTN Index;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));
+
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
+
+ DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));
+ for (Index = 0; Index < mFullSmramRangeCount; Index++) {
+ DEBUG ((EFI_D_INFO, " FullSmramRange (0x%x)\n", Index));
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));
+ DEBUG ((EFI_D_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));
+ DEBUG ((EFI_D_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));
+ DEBUG ((EFI_D_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState));
+ }
+
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ Dump SMRAM free page list.
+
+**/
+VOID
+DumpFreePagesList (
+ VOID
+ )
+{
+ LIST_ENTRY *FreePageList;
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+ UINTN Index;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
+
+ DEBUG ((EFI_D_INFO, "FreePagesList:\n"));
+ FreePageList = &mSmmMemoryMap;
+ for (Node = FreePageList->BackLink, Index = 0;
+ Node != FreePageList;
+ Node = Node->BackLink, Index++) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));
+ DEBUG ((EFI_D_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages));
+ }
+
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ Dump SMRAM free pool list.
+
+**/
+VOID
+DumpFreePoolList (
+ VOID
+ )
+{
+ LIST_ENTRY *FreePoolList;
+ LIST_ENTRY *Node;
+ FREE_POOL_HEADER *Pool;
+ UINTN Index;
+ UINTN PoolListIndex;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN SmramProfileGettingStatus;
+ UINTN SmmPoolTypeIndex;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
+
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
+ DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex));
+ FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
+ for (Node = FreePoolList->BackLink, Index = 0;
+ Node != FreePoolList;
+ Node = Node->BackLink, Index++) {
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
+ DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index));
+ DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));
+ DEBUG ((DEBUG_INFO, " Size - 0x%08x\n", Pool->Header.Size));
+ DEBUG ((DEBUG_INFO, " Available - 0x%02x\n", Pool->Header.Available));
+ }
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = {
+ "SmmUnknown",
+ "gSmst->SmmAllocatePages",
+ "gSmst->SmmFreePages",
+ "gSmst->SmmAllocatePool",
+ "gSmst->SmmFreePool",
+};
+
+typedef struct {
+ MEMORY_PROFILE_ACTION Action;
+ CHAR8 *String;
+} ACTION_STRING;
+
+GLOBAL_REMOVE_IF_UNREFERENCED ACTION_STRING mExtActionString[] = {
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool"},
+ {MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool"},
+ {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool"},
+};
+
+typedef struct {
+ EFI_MEMORY_TYPE MemoryType;
+ CHAR8 *MemoryTypeStr;
+} PROFILE_MEMORY_TYPE_STRING;
+
+GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
+ {EfiRuntimeServicesCode, "EfiRuntimeServicesCode"},
+ {EfiRuntimeServicesData, "EfiRuntimeServicesData"}
+};
+
+/**
+ Memory type to string.
+
+ @param[in] MemoryType Memory type.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+ProfileMemoryTypeToStr (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) {
+ if (mMemoryTypeString[Index].MemoryType == MemoryType) {
+ return mMemoryTypeString[Index].MemoryTypeStr;
+ }
+ }
+
+ return "UnexpectedMemoryType";
+}
+
+/**
+ Action to string.
+
+ @param[in] Action Profile action.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+ProfileActionToStr (
+ IN MEMORY_PROFILE_ACTION Action
+ )
+{
+ UINTN Index;
+ UINTN ActionStringCount;
+ CHAR8 **ActionString;
+
+ ActionString = mSmmActionString;
+ ActionStringCount = ARRAY_SIZE (mSmmActionString);
+
+ if ((UINTN) (UINT32) Action < ActionStringCount) {
+ return ActionString[Action];
+ }
+ for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
+ if (mExtActionString[Index].Action == Action) {
+ return mExtActionString[Index].String;
+ }
+ }
+
+ return ActionString[0];
+}
+
+/**
+ Dump SMRAM profile.
+
+**/
+VOID
+DumpSmramProfile (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *SmramDriverInfoList;
+ UINTN DriverIndex;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ UINTN AllocIndex;
+ LIST_ENTRY *AllocLink;
+ BOOLEAN SmramProfileGettingStatus;
+ UINTN TypeIndex;
+
+ ContextData = GetSmramProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ SmramProfileGettingStatus = mSmramProfileGettingStatus;
+ mSmramProfileGettingStatus = TRUE;
+
+ Context = &ContextData->Context;
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
+ DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));
+
+ DEBUG ((EFI_D_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage));
+ DEBUG ((EFI_D_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage));
+ for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
+ if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
+ (Context->PeakTotalUsageByType[TypeIndex] != 0)) {
+ DEBUG ((EFI_D_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
+ DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
+ }
+ }
+ DEBUG ((EFI_D_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize));
+ DEBUG ((EFI_D_INFO, " ImageCount - 0x%08x\n", Context->ImageCount));
+ DEBUG ((EFI_D_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount));
+
+ SmramDriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;
+ DriverLink != SmramDriverInfoList;
+ DriverLink = DriverLink->ForwardLink, DriverIndex++) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));
+ DEBUG ((EFI_D_INFO, " FileName - %g\n", &DriverInfo->FileName));
+ DEBUG ((EFI_D_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase));
+ DEBUG ((EFI_D_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize));
+ DEBUG ((EFI_D_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint));
+ DEBUG ((EFI_D_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem));
+ DEBUG ((EFI_D_INFO, " FileType - 0x%02x\n", DriverInfo->FileType));
+ DEBUG ((EFI_D_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage));
+ DEBUG ((EFI_D_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage));
+ for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
+ if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
+ (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {
+ DEBUG ((EFI_D_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
+ DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
+ }
+ }
+ DEBUG ((EFI_D_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount));
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink, AllocIndex++) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ AllocInfo = &AllocInfoData->AllocInfo;
+ DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));
+ DEBUG ((EFI_D_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));
+ DEBUG ((EFI_D_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId));
+ if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
+ if (AllocInfoData->ActionString != NULL) {
+ DEBUG ((EFI_D_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString));
+ } else {
+ DEBUG ((EFI_D_INFO, " Action - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action));
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action)));
+ }
+ DEBUG ((EFI_D_INFO, " MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType)));
+ DEBUG ((EFI_D_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer));
+ DEBUG ((EFI_D_INFO, " Size - 0x%016lx\n", AllocInfo->Size));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
+
+ mSmramProfileGettingStatus = SmramProfileGettingStatus;
+}
+
+/**
+ Dump SMRAM information.
+
+**/
+VOID
+DumpSmramInfo (
+ VOID
+ )
+{
+ DEBUG_CODE (
+ if (IS_SMRAM_PROFILE_ENABLED) {
+ DumpSmramProfile ();
+ DumpFreePagesList ();
+ DumpFreePoolList ();
+ DumpSmramRange ();
+ }
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Crc32.c b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Crc32.c
new file mode 100644
index 000000000..6a4677dab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Crc32.c
@@ -0,0 +1,45 @@
+/** @file
+ This file implements CalculateCrc32 Boot Services as defined in
+ Platform Initialization specification 1.0 VOLUME 2 DXE Core Interface.
+
+ This Boot Services is in the Runtime Driver because this service is
+ also required by SetVirtualAddressMap() when the EFI System Table and
+ EFI Runtime Services Table are converted from physical address to
+ virtual addresses. This requires that the 32-bit CRC be recomputed.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+
+/**
+ Calculate CRC32 for target data.
+
+ @param Data The target data.
+ @param DataSize The target data size.
+ @param CrcOut The CRC32 for target data.
+
+ @retval EFI_SUCCESS The CRC32 for target data is calculated successfully.
+ @retval EFI_INVALID_PARAMETER Some parameter is not valid, so the CRC32 is not
+ calculated.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverCalculateCrc32 (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *CrcOut
+ )
+{
+ if (Data == NULL || DataSize == 0 || CrcOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *CrcOut = CalculateCrc32 (Data, DataSize);
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.c b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.c
new file mode 100644
index 000000000..f7220a205
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.c
@@ -0,0 +1,424 @@
+/** @file
+ This file implements Runtime Architectural Protocol as defined in the
+ Platform Initialization specification 1.0 VOLUME 2 DXE Core Interface.
+
+ This code is used to produce the EFI runtime virtual switch over
+
+ THIS IS VERY DANGEROUS CODE BE VERY CAREFUL IF YOU CHANGE IT
+
+ The transition for calling EFI Runtime functions in physical mode to calling
+ them in virtual mode is very very complex. Every pointer in needs to be
+ converted from physical mode to virtual mode. Be very careful walking linked
+ lists! Then to make it really hard the code it's self needs be relocated into
+ the new virtual address space.
+
+ So here is the concept. The code in this module will never ever be called in
+ virtual mode. This is the code that collects the information needed to convert
+ to virtual mode (DXE core registers runtime stuff with this code). Since this
+ code is used to fix up all runtime images, it CAN NOT fix it's self up. So some
+ code has to stay behind and that is us.
+
+ Also you need to be careful about when you allocate memory, as once we are in
+ runtime (including our EVT_SIGNAL_EXIT_BOOT_SERVICES event) you can no longer
+ allocate memory.
+
+ Any runtime driver that gets loaded before us will not be callable in virtual
+ mode. This is due to the fact that the DXE core can not register the info
+ needed with us. This is good, since it keeps the code in this file from
+ getting registered.
+
+
+Revision History:
+
+ - Move the CalculateCrc32 function from Runtime Arch Protocol to Boot Service.
+ Runtime Arch Protocol definition no longer contains CalculateCrc32. Boot Service
+ Table now contains an item named CalculateCrc32.
+
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Runtime.h"
+
+//
+// Global Variables
+//
+EFI_MEMORY_DESCRIPTOR *mVirtualMap = NULL;
+UINTN mVirtualMapDescriptorSize;
+UINTN mVirtualMapMaxIndex;
+VOID *mMyImageBase;
+
+//
+// The handle onto which the Runtime Architectural Protocol instance is installed
+//
+EFI_HANDLE mRuntimeHandle = NULL;
+
+//
+// The Runtime Architectural Protocol instance produced by this driver
+//
+EFI_RUNTIME_ARCH_PROTOCOL mRuntime = {
+ INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.ImageHead),
+ INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.EventHead),
+
+ //
+ // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
+ EFI_MEMORY_DESCRIPTOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ FALSE,
+ FALSE
+};
+
+//
+// Worker Functions
+//
+/**
+
+ Calculate the 32-bit CRC in a EFI table using the Runtime Drivers
+ internal function. The EFI Boot Services Table can not be used because
+ the EFI Boot Services Table was destroyed at ExitBootServices().
+ This is a internal function.
+
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+RuntimeDriverCalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+
+ Crc = 0;
+ RuntimeDriverCalculateCrc32 ((UINT8 *) Hdr, Hdr->HeaderSize, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+/**
+
+ Determines the new virtual address that is to be used on subsequent memory accesses.
+
+
+ @param DebugDisposition Supplies type information for the pointer being converted.
+ @param ConvertAddress A pointer to a pointer that is to be fixed to be the value needed
+ for the new virtual address mappings being applied.
+
+ @retval EFI_SUCCESS The pointer pointed to by Address was modified.
+ @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part
+ of the current memory map. This is normally fatal.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverConvertPointer (
+ IN UINTN DebugDisposition,
+ IN OUT VOID **ConvertAddress
+ )
+{
+ UINTN Address;
+ UINT64 VirtEndOfRange;
+ EFI_MEMORY_DESCRIPTOR *VirtEntry;
+ UINTN Index;
+
+ //
+ // Make sure ConvertAddress is a valid pointer
+ //
+ if (ConvertAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get the address to convert
+ //
+ Address = (UINTN) *ConvertAddress;
+
+ //
+ // If this is a null pointer, return if it's allowed
+ //
+ if (Address == 0) {
+ if ((DebugDisposition & EFI_OPTIONAL_PTR) != 0) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VirtEntry = mVirtualMap;
+ for (Index = 0; Index < mVirtualMapMaxIndex; Index++) {
+ //
+ // To prevent the inclusion of 64-bit math functions a UINTN was placed in
+ // front of VirtEntry->NumberOfPages to cast it to a 32-bit thing on IA-32
+ // platforms. If you get this ASSERT remove the UINTN and do a 64-bit
+ // multiply.
+ //
+ ASSERT (((UINTN) VirtEntry->NumberOfPages < 0xffffffff) || (sizeof (UINTN) > 4));
+
+ if ((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
+ if (Address >= VirtEntry->PhysicalStart) {
+ VirtEndOfRange = VirtEntry->PhysicalStart + (((UINTN) VirtEntry->NumberOfPages) * EFI_PAGE_SIZE);
+ if (Address < VirtEndOfRange) {
+ //
+ // Compute new address
+ //
+ *ConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ VirtEntry = NEXT_MEMORY_DESCRIPTOR (VirtEntry, mVirtualMapDescriptorSize);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ Determines the new virtual address that is to be used on subsequent memory accesses
+ for internal pointers.
+ This is a internal function.
+
+
+ @param ConvertAddress A pointer to a pointer that is to be fixed to be the value needed
+ for the new virtual address mappings being applied.
+
+ @retval EFI_SUCCESS The pointer pointed to by Address was modified.
+ @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part
+ of the current memory map. This is normally fatal.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+RuntimeDriverConvertInternalPointer (
+ IN OUT VOID **ConvertAddress
+ )
+{
+ return RuntimeDriverConvertPointer (0x0, ConvertAddress);
+}
+
+/**
+
+ Changes the runtime addressing mode of EFI firmware from physical to virtual.
+
+
+ @param MemoryMapSize The size in bytes of VirtualMap.
+ @param DescriptorSize The size in bytes of an entry in the VirtualMap.
+ @param DescriptorVersion The version of the structure entries in VirtualMap.
+ @param VirtualMap An array of memory descriptors which contain new virtual
+ address mapping information for all runtime ranges.
+
+ @retval EFI_SUCCESS The virtual address map has been applied.
+ @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in
+ virtual address mapped mode.
+ @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid.
+ @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory
+ map that requires a mapping.
+ @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found
+ in the memory map.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverSetVirtualAddressMap (
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize,
+ IN UINT32 DescriptorVersion,
+ IN EFI_MEMORY_DESCRIPTOR *VirtualMap
+ )
+{
+ EFI_STATUS Status;
+ EFI_RUNTIME_EVENT_ENTRY *RuntimeEvent;
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
+ LIST_ENTRY *Link;
+ EFI_PHYSICAL_ADDRESS VirtImageBase;
+
+ //
+ // Can only switch to virtual addresses once the memory map is locked down,
+ // and can only set it once
+ //
+ if (!mRuntime.AtRuntime || mRuntime.VirtualMode) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Only understand the original descriptor format
+ //
+ if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We are now committed to go to virtual mode, so lets get to it!
+ //
+ mRuntime.VirtualMode = TRUE;
+
+ //
+ // ConvertPointer() needs this mVirtualMap to do the conversion. So set up
+ // globals we need to parse the virtual address map.
+ //
+ mVirtualMapDescriptorSize = DescriptorSize;
+ mVirtualMapMaxIndex = MemoryMapSize / DescriptorSize;
+ mVirtualMap = VirtualMap;
+
+ //
+ // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP));
+
+ //
+ // Report Status Code here since EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event will be signalled.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_VIRTUAL_ADDRESS_CHANGE_EVENT));
+
+ //
+ // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events.
+ // All runtime events are stored in a list in Runtime AP.
+ //
+ for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) {
+ RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link);
+ if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
+ //
+ // Work around the bug in the Platform Init specification (v1.7),
+ // reported as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have
+ // type EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field
+ // correctly as "The EFI_EVENT returned by CreateEvent()", but the type
+ // of the field doesn't match the natural language description. Therefore
+ // we need an explicit cast here.
+ //
+ RuntimeEvent->NotifyFunction (
+ (EFI_EVENT) RuntimeEvent->Event,
+ RuntimeEvent->NotifyContext
+ );
+ }
+ }
+
+ //
+ // Relocate runtime images. All runtime images are stored in a list in Runtime AP.
+ //
+ for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) {
+ RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
+ //
+ // We don't want to relocate our selves, as we only run in physical mode.
+ //
+ if (mMyImageBase != RuntimeImage->ImageBase) {
+
+ VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase;
+ Status = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);
+ ASSERT_EFI_ERROR (Status);
+
+ PeCoffLoaderRelocateImageForRuntime (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,
+ VirtImageBase,
+ (UINTN) RuntimeImage->ImageSize,
+ RuntimeImage->RelocationData
+ );
+
+ InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize);
+ }
+ }
+
+ //
+ // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap()
+ // and recompute the CRC-32
+ //
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities);
+ RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr);
+
+ //
+ // UEFI don't require System Configuration Tables Conversion.
+ //
+
+ //
+ // Convert the runtime fields of the EFI System Table and recompute the CRC-32
+ //
+ RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable);
+ RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices);
+ RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr);
+
+ //
+ // At this point, gRT and gST are physical pointers, but the contents of these tables
+ // have been converted to runtime.
+ //
+ //
+ // mVirtualMap is only valid during SetVirtualAddressMap() call
+ //
+ mVirtualMap = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry Point for Runtime driver.
+
+ This function installs Runtime Architectural Protocol and registers CalculateCrc32 boot services table,
+ SetVirtualAddressMap & ConvertPointer runtime services table.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable a Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS Runtime Driver Architectural Protocol is successfully installed
+ @return Others Some error occurs when installing Runtime Driver Architectural Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *MyLoadedImage;
+
+ //
+ // This image needs to be excluded from relocation for virtual mode, so cache
+ // a copy of the Loaded Image protocol to test later.
+ //
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**)&MyLoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+ mMyImageBase = MyLoadedImage->ImageBase;
+
+ //
+ // Fill in the entries of the EFI Boot Services and EFI Runtime Services Tables
+ //
+ gBS->CalculateCrc32 = RuntimeDriverCalculateCrc32;
+ gRT->SetVirtualAddressMap = RuntimeDriverSetVirtualAddressMap;
+ gRT->ConvertPointer = RuntimeDriverConvertPointer;
+
+ //
+ // Install the Runtime Architectural Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mRuntimeHandle,
+ &gEfiRuntimeArchProtocolGuid,
+ &mRuntime,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.h b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.h
new file mode 100644
index 000000000..019a0cb14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/Runtime.h
@@ -0,0 +1,119 @@
+/** @file
+ Runtime Architectural Protocol as defined in the DXE CIS.
+
+ This code is used to produce the EFI runtime architectural protocol.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RUNTIME_H_
+#define _RUNTIME_H_
+
+#include <PiDxe.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/Runtime.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PeCoffLib.h>
+
+
+//
+// Function Prototypes
+//
+/**
+ Calculate CRC32 for target data.
+
+ @param Data The target data.
+ @param DataSize The target data size.
+ @param CrcOut The CRC32 for target data.
+
+ @retval EFI_SUCCESS The CRC32 for target data is calculated successfully.
+ @retval EFI_INVALID_PARAMETER Some parameter is not valid, so the CRC32 is not
+ calculated.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverCalculateCrc32 (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *CrcOut
+ );
+
+/**
+ Determines the new virtual address that is to be used on subsequent memory accesses.
+
+
+ @param DebugDisposition Supplies type information for the pointer being converted.
+ @param ConvertAddress A pointer to a pointer that is to be fixed to be the value needed
+ for the new virtual address mappings being applied.
+
+ @retval EFI_SUCCESS The pointer pointed to by Address was modified.
+ @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part
+ of the current memory map. This is normally fatal.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverConvertPointer (
+ IN UINTN DebugDisposition,
+ IN OUT VOID **ConvertAddress
+ );
+
+/**
+ Changes the runtime addressing mode of EFI firmware from physical to virtual.
+
+ @param MemoryMapSize The size in bytes of VirtualMap.
+ @param DescriptorSize The size in bytes of an entry in the VirtualMap.
+ @param DescriptorVersion The version of the structure entries in VirtualMap.
+ @param VirtualMap An array of memory descriptors which contain new virtual
+ address mapping information for all runtime ranges.
+
+ @retval EFI_SUCCESS The virtual address map has been applied.
+ @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in
+ virtual address mapped mode.
+ @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid.
+ @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory
+ map that requires a mapping.
+ @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found
+ in the memory map.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverSetVirtualAddressMap (
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize,
+ IN UINT32 DescriptorVersion,
+ IN EFI_MEMORY_DESCRIPTOR *VirtualMap
+ );
+
+/**
+ Install Runtime AP. This code includes the EfiRuntimeLib, but it only
+ functions at RT in physical mode.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS Runtime Driver Architectural Protocol Installed
+ @return Other value if gBS->InstallMultipleProtocolInterfaces fails. Check
+ gBS->InstallMultipleProtocolInterfaces for details.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
new file mode 100644
index 000000000..694c7690f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# Module that produces EFI runtime virtual switch over services.
+#
+# This runtime module installs Runtime Architectural Protocol and registers
+# CalculateCrc32 boot services table, SetVirtualAddressMap & ConvertPointer
+# runtime services table.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RuntimeDxe
+ MODULE_UNI_FILE = RuntimeDxe.uni
+ FILE_GUID = B601F8C4-43B7-4784-95B1-F4226CB40CEE
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = RuntimeDriverInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Crc32.c
+ Runtime.h
+ Runtime.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ PeCoffLib
+ CacheMaintenanceLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ DebugLib
+ UefiDriverEntryPoint
+ BaseLib
+
+[Protocols]
+ gEfiRuntimeArchProtocolGuid ## PRODUCES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+
+[depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ RuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.uni b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.uni
new file mode 100644
index 000000000..e5dcf451a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Module that produces EFI runtime virtual switch over services.
+//
+// This runtime module installs Runtime Architectural Protocol and registers
+// CalculateCrc32 boot services table, SetVirtualAddressMap & ConvertPointer
+// runtime services table.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Module that produces EFI runtime virtual switchover services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This runtime module installs Runtime Architectural Protocol and registers the CalculateCrc32 boot services table, and SetVirtualAddressMap and ConvertPointer runtime services table."
+
diff --git a/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxeExtra.uni
new file mode 100644
index 000000000..eca04e74f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/RuntimeDxe/RuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// RuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core Runtime Services Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/AcpiS3Context.h b/roms/edk2/MdeModulePkg/Include/Guid/AcpiS3Context.h
new file mode 100644
index 000000000..72eb2cb27
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/AcpiS3Context.h
@@ -0,0 +1,66 @@
+/** @file
+ Definitions for data structures used in S3 resume.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ACPI_S3_DATA_H_
+#define _ACPI_S3_DATA_H_
+
+#include <Library/BaseLib.h>
+
+#define SMM_S3_RESUME_SMM_32 SIGNATURE_64 ('S','M','M','S','3','_','3','2')
+#define SMM_S3_RESUME_SMM_64 SIGNATURE_64 ('S','M','M','S','3','_','6','4')
+
+#pragma pack(1)
+
+typedef struct {
+ UINT64 Signature;
+ EFI_PHYSICAL_ADDRESS SmmS3ResumeEntryPoint;
+ EFI_PHYSICAL_ADDRESS SmmS3StackBase;
+ UINT64 SmmS3StackSize;
+ UINT64 SmmS3Cr0;
+ UINT64 SmmS3Cr3;
+ UINT64 SmmS3Cr4;
+ UINT16 ReturnCs;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ EFI_PHYSICAL_ADDRESS ReturnContext1;
+ EFI_PHYSICAL_ADDRESS ReturnContext2;
+ EFI_PHYSICAL_ADDRESS ReturnStackPointer;
+ EFI_PHYSICAL_ADDRESS Smst;
+} SMM_S3_RESUME_STATE;
+
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS AcpiFacsTable;
+ EFI_PHYSICAL_ADDRESS IdtrProfile;
+ EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
+ EFI_PHYSICAL_ADDRESS BootScriptStackBase;
+ UINT64 BootScriptStackSize;
+ EFI_PHYSICAL_ADDRESS S3DebugBufferAddress;
+} ACPI_S3_CONTEXT;
+
+typedef struct {
+ UINT16 ReturnCs;
+ UINT64 ReturnStatus;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ EFI_PHYSICAL_ADDRESS ReturnStackPointer;
+ EFI_PHYSICAL_ADDRESS AsmTransferControl;
+ IA32_DESCRIPTOR Idtr;
+} PEI_S3_RESUME_STATE;
+
+#pragma pack()
+
+#define EFI_ACPI_S3_CONTEXT_GUID \
+ { \
+ 0xef98d3a, 0x3e33, 0x497a, {0xa4, 0x1, 0x77, 0xbe, 0x3e, 0xb7, 0x4f, 0x38} \
+ }
+
+extern EFI_GUID gEfiAcpiS3ContextGuid;
+
+extern EFI_GUID gEfiAcpiVariableGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h b/roms/edk2/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h
new file mode 100644
index 000000000..8eca78583
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/BootScriptExecutorVariable.h
@@ -0,0 +1,42 @@
+/** @file
+ Define Name, GUID and data format for an EFI Variable that is used to save the entry point
+ of a code segment which will be loaded and executed by a standalone boot script
+ executor on S3 boot path.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_SCRIPT_EXECUTOR_VARIABLE_H_
+#define _BOOT_SCRIPT_EXECUTOR_VARIABLE_H_
+
+#define EFI_BOOT_SCRIPT_EXECUTOR_VARIABLE_GUID \
+ { \
+ 0x3079818c, 0x46d4, 0x4a73, {0xae, 0xf3, 0xe3, 0xe4, 0x6c, 0xf1, 0xee, 0xdb} \
+ }
+
+//
+// The following structure boosts performance by combining structure all ACPI related variables into one.
+//
+#pragma pack(1)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BootScriptExecutorEntrypoint;
+} BOOT_SCRIPT_EXECUTOR_VARIABLE;
+
+#pragma pack()
+
+#define BOOT_SCRIPT_EXECUTOR_VARIABLE_NAME L"BootScriptExecutorVariable"
+
+extern EFI_GUID gEfiBootScriptExecutorVariableGuid;
+
+#define EFI_BOOT_SCRIPT_EXECUTOR_CONTEXT_GUID \
+ { \
+ 0x79cb58c4, 0xac51, 0x442f, {0xaf, 0xd7, 0x98, 0xe4, 0x7d, 0x2e, 0x99, 0x8} \
+ }
+
+extern EFI_GUID gEfiBootScriptExecutorContextGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/CapsuleVendor.h b/roms/edk2/MdeModulePkg/Include/Guid/CapsuleVendor.h
new file mode 100644
index 000000000..aaa4369af
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/CapsuleVendor.h
@@ -0,0 +1,59 @@
+/** @file
+ This file defines:
+ * the capsule vendor GUID for capsule variables and the HOB.
+ * the capsule variable name.
+ * the capsule GUID HOB data structure.
+ The capsule HOB and variable can be used to store the capsule image start address and length.
+ They are used by EDKII implementation of capsule update across a system reset.
+
+ @par Note: EDKII implementation of capsule updating has discarded this capsule GUID HOB data
+ structure and used one UEFI Capsule HOB (defined in PI Specification 1.2) instead.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_CAPSULE_VENDOR_GUID_H__
+#define __EFI_CAPSULE_VENDOR_GUID_H__
+
+///
+/// This guid is used as a variable GUID for the capsule variable
+/// if the capsule pointer is passed through reset via a variable.
+///
+/// This guid is also used as a hob GUID for the capsule data
+/// when the capsule pointer is passed from PEI phase to DXE phase.
+///
+#define EFI_CAPSULE_VENDOR_GUID \
+ { 0x711C703F, 0xC285, 0x4B10, { 0xA3, 0xB0, 0x36, 0xEC, 0xBD, 0x3C, 0x8B, 0xE2 } }
+
+///
+/// Name of capsule variable.
+///
+#define EFI_CAPSULE_VARIABLE_NAME L"CapsuleUpdateData"
+
+///
+/// The data structure of the capsule guid hob entry.
+/// Note: EDKII implementation has discarded this structure and used
+/// UEFI_CAPSULE_HOB instead.
+///
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BaseAddress; ///< Capsule data start address.
+ UINT32 Length; ///< Length of capsule data.
+} CAPSULE_HOB_INFO;
+
+//
+// The variable describes the long mode buffer used by IA32 Capsule PEIM
+// to call X64 CapsuleCoalesce code to handle >4GB capsule blocks.
+//
+#define EFI_CAPSULE_LONG_MODE_BUFFER_NAME L"CapsuleLongModeBuffer"
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS PageTableAddress;
+ EFI_PHYSICAL_ADDRESS StackBaseAddress;
+ UINT64 StackSize;
+} EFI_CAPSULE_LONG_MODE_BUFFER;
+
+extern EFI_GUID gEfiCapsuleVendorGuid;
+
+#endif // #ifndef _EFI_CAPSULE_VENDOR_GUID_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/ConnectConInEvent.h b/roms/edk2/MdeModulePkg/Include/Guid/ConnectConInEvent.h
new file mode 100644
index 000000000..3deaa16e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/ConnectConInEvent.h
@@ -0,0 +1,18 @@
+/** @file
+ GUID for an event that is signaled on the first attempt to check for a keystroke
+ from the ConIn device.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CONNECT_CONIN_EVENT_GUID_H__
+#define __CONNECT_CONIN_EVENT_GUID_H__
+
+#define CONNECT_CONIN_EVENT_GUID \
+ { 0xdb4e8151, 0x57ed, 0x4bed, { 0x88, 0x33, 0x67, 0x51, 0xb5, 0xd1, 0xa8, 0xd7 }}
+
+extern EFI_GUID gConnectConInEventGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/ConsoleInDevice.h b/roms/edk2/MdeModulePkg/Include/Guid/ConsoleInDevice.h
new file mode 100644
index 000000000..9df4962b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/ConsoleInDevice.h
@@ -0,0 +1,18 @@
+/** @file
+ This GUID can be installed to the device handle to specify that the device is the console-in device.
+
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CONSOLE_IN_DEVICE_H__
+#define __CONSOLE_IN_DEVICE_H__
+
+#define EFI_CONSOLE_IN_DEVICE_GUID \
+ { 0xd3b36f2b, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
+
+extern EFI_GUID gEfiConsoleInDeviceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/ConsoleOutDevice.h b/roms/edk2/MdeModulePkg/Include/Guid/ConsoleOutDevice.h
new file mode 100644
index 000000000..b65e02637
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/ConsoleOutDevice.h
@@ -0,0 +1,17 @@
+/** @file
+ This GUID can be installed to the device handle to specify that the device is the console-out device.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CONSOLE_OUT_DEVICE_H__
+#define __CONSOLE_OUT_DEVICE_H__
+
+#define EFI_CONSOLE_OUT_DEVICE_GUID \
+ { 0xd3b36f2c, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
+
+extern EFI_GUID gEfiConsoleOutDeviceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/Crc32GuidedSectionExtraction.h b/roms/edk2/MdeModulePkg/Include/Guid/Crc32GuidedSectionExtraction.h
new file mode 100644
index 000000000..32d71e2d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/Crc32GuidedSectionExtraction.h
@@ -0,0 +1,18 @@
+/** @file
+ This file defines CRC32 GUID to specify the CRC32
+ encapsulation scheme for the GUIDed section.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CRC32_GUIDED_SECTION_EXTRACTION_H__
+#define __CRC32_GUIDED_SECTION_EXTRACTION_H__
+
+#define EFI_CRC32_GUIDED_SECTION_EXTRACTION_GUID \
+ { 0xFC1BCDB0, 0x7D31, 0x49aa, {0x93, 0x6A, 0xA4, 0x60, 0x0D, 0x9D, 0xD0, 0x83 } }
+
+extern EFI_GUID gEfiCrc32GuidedSectionExtractionGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/DebugMask.h b/roms/edk2/MdeModulePkg/Include/Guid/DebugMask.h
new file mode 100644
index 000000000..4ea1981f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/DebugMask.h
@@ -0,0 +1,68 @@
+/** @file
+
+ Debug Mask Protocol.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DEBUG_MASK_H__
+#define __DEBUG_MASK_H__
+
+///
+/// Protocol GUID for DXE Phase Debug Mask support
+///
+#define EFI_DEBUG_MASK_PROTOCOL_GUID \
+ { 0x4c8a2451, 0xc207, 0x405b, {0x96, 0x94, 0x99, 0xea, 0x13, 0x25, 0x13, 0x41} }
+
+///
+/// Forward reference for pure ANSI compatability
+///
+typedef struct _EFI_DEBUG_MASK_PROTOCOL EFI_DEBUG_MASK_PROTOCOL;
+
+///
+///
+///
+#define EFI_DEBUG_MASK_REVISION 0x00010000
+
+//
+// DebugMask member functions definition
+//
+typedef
+EFI_STATUS
+(EFIAPI * EFI_GET_DEBUG_MASK) (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN OUT UINTN *CurrentDebugMask
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_DEBUG_MASK) (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN UINTN NewDebugMask
+ );
+
+///
+/// DebugMask protocol definition
+///
+struct _EFI_DEBUG_MASK_PROTOCOL {
+ INT64 Revision;
+ EFI_GET_DEBUG_MASK GetDebugMask;
+ EFI_SET_DEBUG_MASK SetDebugMask;
+};
+
+extern EFI_GUID gEfiDebugMaskProtocolGuid;
+
+///
+/// GUID used to store the global debug mask in an the "EFIDebug" EFI Variabe
+/// Also used as a GUIDed HOB that contains a UINT32 debug mask default value
+///
+#define EFI_GENERIC_VARIABLE_GUID \
+ { 0x59d1c24f, 0x50f1, 0x401a, {0xb1, 0x01, 0xf3, 0x3e, 0x0d, 0xae, 0xd4, 0x43} }
+
+#define DEBUG_MASK_VARIABLE_NAME L"EFIDebug"
+
+extern EFI_GUID gEfiGenericVariableGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/DriverSampleHii.h b/roms/edk2/MdeModulePkg/Include/Guid/DriverSampleHii.h
new file mode 100644
index 000000000..434ae91a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/DriverSampleHii.h
@@ -0,0 +1,31 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in Driver Sample driver.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DRIVER_SAMPLE_HII_GUID_H__
+#define __DRIVER_SAMPLE_HII_GUID_H__
+
+#define DRIVER_SAMPLE_FORMSET_GUID \
+ { \
+ 0xA04A27f4, 0xDF00, 0x4D42, {0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D} \
+ }
+
+#define DRIVER_SAMPLE_INVENTORY_GUID \
+ { \
+ 0xb3f56470, 0x6141, 0x4621, {0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8} \
+ }
+
+#define EFI_IFR_REFRESH_ID_OP_GUID \
+ { \
+ 0xF5E655D9, 0x02A6, 0x46f2, {0x9E, 0x76, 0xB8, 0xBE, 0x8E, 0x60, 0xAB, 0x22} \
+ }
+
+extern EFI_GUID gDriverSampleFormSetGuid;
+extern EFI_GUID gDriverSampleInventoryGuid;
+extern EFI_GUID gEfiIfrRefreshIdOpGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/EndOfS3Resume.h b/roms/edk2/MdeModulePkg/Include/Guid/EndOfS3Resume.h
new file mode 100644
index 000000000..c823ec855
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/EndOfS3Resume.h
@@ -0,0 +1,20 @@
+/** @file
+ This GUID will be installed at the end of S3 resume phase as protocol in SMM environment.
+ It allows for SMM drivers to hook this point and do the required tasks.
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __END_OF_S3_RESUME_H__
+#define __END_OF_S3_RESUME_H__
+
+#define EDKII_END_OF_S3_RESUME_GUID \
+ { \
+ 0x96f5296d, 0x05f7, 0x4f3c, {0x84, 0x67, 0xe4, 0x56, 0x89, 0x0e, 0x0c, 0xb5 } \
+ }
+
+extern EFI_GUID gEdkiiEndOfS3ResumeGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/EventExitBootServiceFailed.h b/roms/edk2/MdeModulePkg/Include/Guid/EventExitBootServiceFailed.h
new file mode 100644
index 000000000..8bc2cfb06
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/EventExitBootServiceFailed.h
@@ -0,0 +1,18 @@
+/** @file
+ GUID is the name of events used with ExitBootServices in order to be notified
+ when this ExitBootServices Call is failed.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EVENT_EXIT_BOOT_FAILED_GUID_H__
+#define __EVENT_EXIT_BOOT_FAILED_GUID_H__
+
+#define EVENT_GROUP_EXIT_BOOT_SERVICES_FAILED \
+ { 0x4f6c5507, 0x232f, 0x4787, { 0xb9, 0x5e, 0x72, 0xf8, 0x62, 0x49, 0xc, 0xb1 } }
+
+extern EFI_GUID gEventExitBootServicesFailedGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h b/roms/edk2/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h
new file mode 100644
index 000000000..c04f79c6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h
@@ -0,0 +1,254 @@
+/** @file
+ This file defines edk2 extended firmware performance records.
+ These records will be added into ACPI FPDT Firmware Basic Boot Performance Table.
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EXTENDED_FIRMWARE_PERFORMANCE_H__
+#define __EXTENDED_FIRMWARE_PERFORMANCE_H__
+
+#include <IndustryStandard/Acpi.h>
+
+//
+// Known performance tokens
+//
+#define SEC_TOK "SEC" ///< SEC Phase
+#define DXE_TOK "DXE" ///< DXE Phase
+#define PEI_TOK "PEI" ///< PEI Phase
+#define BDS_TOK "BDS" ///< BDS Phase
+#define DRIVERBINDING_START_TOK "DB:Start:" ///< Driver Binding Start() function call
+#define DRIVERBINDING_SUPPORT_TOK "DB:Support:" ///< Driver Binding Support() function call
+#define DRIVERBINDING_STOP_TOK "DB:Stop:" ///< Driver Binding Stop() function call
+#define LOAD_IMAGE_TOK "LoadImage:" ///< Load a dispatched module
+#define START_IMAGE_TOK "StartImage:" ///< Dispatched Modules Entry Point execution
+#define PEIM_TOK "PEIM" ///< PEIM Modules Entry Point execution
+
+//
+// Misc defines
+//
+#define FPDT_RECORD_REVISION_1 (0x01)
+
+//
+// Length field in EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER is a UINT8, thus:
+//
+#define FPDT_MAX_PERF_RECORD_SIZE (MAX_UINT8)
+
+//
+// FPDT Record Types
+//
+#define FPDT_GUID_EVENT_TYPE 0x1010
+#define FPDT_DYNAMIC_STRING_EVENT_TYPE 0x1011
+#define FPDT_DUAL_GUID_STRING_EVENT_TYPE 0x1012
+#define FPDT_GUID_QWORD_EVENT_TYPE 0x1013
+#define FPDT_GUID_QWORD_STRING_EVENT_TYPE 0x1014
+
+//
+// EDKII extended Fpdt record structures
+//
+#define FPDT_STRING_EVENT_RECORD_NAME_LENGTH 24
+
+#pragma pack(1)
+//
+// FPDT Boot Performance Guid Event Record Structure
+//
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ UINT16 ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as 0.
+ ///
+ UINT32 ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion of processor reset.
+ ///
+ UINT64 Timestamp;
+ ///
+ /// If ProgressID < 0x10, GUID of the referenced module; otherwise, GUID of the module logging the event.
+ ///
+ EFI_GUID Guid;
+} FPDT_GUID_EVENT_RECORD;
+
+//
+// FPDT Boot Performance Dynamic String Event Record Structure
+//
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ UINT16 ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as 0.
+ ///
+ UINT32 ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion of processor reset.
+ ///
+ UINT64 Timestamp;
+ ///
+ /// If ProgressID < 0x10, GUID of the referenced module; otherwise, GUID of the module logging the event.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with null characters (0x00).
+ /// It may be module name, function name, or token name.
+ ///
+ CHAR8 String[0];
+} FPDT_DYNAMIC_STRING_EVENT_RECORD;
+
+//
+// FPDT Boot Performance Dual GUID String Event Record Structure
+//
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ UINT16 ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as 0.
+ ///
+ UINT32 ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion of processor reset.
+ ///
+ UINT64 Timestamp;
+ ///
+ /// GUID of the module logging the event.
+ ///
+ EFI_GUID Guid1;
+ ///
+ /// Event or Ppi or Protocol GUID for Callback.
+ ///
+ EFI_GUID Guid2;
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with null characters (0x00).
+ /// It is the function name.
+ ///
+ CHAR8 String[0];
+} FPDT_DUAL_GUID_STRING_EVENT_RECORD;
+
+//
+// FPDT Boot Performance GUID Qword Event Record Structure
+//
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ UINT16 ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as 0.
+ ///
+ UINT32 ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion of processor reset.
+ ///
+ UINT64 Timestamp;
+ ///
+ /// GUID of the module logging the event
+ ///
+ EFI_GUID Guid;
+ ///
+ /// Qword of misc data, meaning depends on the ProgressId
+ ///
+ UINT64 Qword;
+} FPDT_GUID_QWORD_EVENT_RECORD;
+
+//
+// FPDT Boot Performance GUID Qword String Event Record Structure
+//
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header;
+ ///
+ /// ProgressID < 0x10 are reserved for core performance entries.
+ /// Start measurement point shall have lowered one nibble set to zero and
+ /// corresponding end points shall have lowered one nibble set to non-zero value;
+ /// keeping other nibbles same as start point.
+ ///
+ UINT16 ProgressID;
+ ///
+ /// APIC ID for the processor in the system used as a timestamp clock source.
+ /// If only one timestamp clock source is used, this field is Reserved and populated as 0.
+ ///
+ UINT32 ApicID;
+ ///
+ /// 64-bit value (nanosecond) describing elapsed time since the most recent deassertion of processor reset.
+ ///
+ UINT64 Timestamp;
+ ///
+ /// GUID of the module logging the event
+ ///
+ EFI_GUID Guid;
+ ///
+ /// Qword of misc data, meaning depends on the ProgressId
+ ///
+ UINT64 Qword;
+ ///
+ /// ASCII string describing the module. Padding supplied at the end if necessary with null characters (0x00).
+ ///
+ CHAR8 String[0];
+} FPDT_GUID_QWORD_STRING_EVENT_RECORD;
+
+#pragma pack()
+
+//
+// Union of all FPDT records
+//
+typedef union {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER RecordHeader;
+ FPDT_GUID_EVENT_RECORD GuidEvent;
+ FPDT_DYNAMIC_STRING_EVENT_RECORD DynamicStringEvent;
+ FPDT_DUAL_GUID_STRING_EVENT_RECORD DualGuidStringEvent;
+ FPDT_GUID_QWORD_EVENT_RECORD GuidQwordEvent;
+ FPDT_GUID_QWORD_STRING_EVENT_RECORD GuidQwordStringEvent;
+} FPDT_RECORD;
+
+//
+// Union of all pointers to FPDT records
+//
+typedef union {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;
+ FPDT_GUID_EVENT_RECORD *GuidEvent;
+ FPDT_DYNAMIC_STRING_EVENT_RECORD *DynamicStringEvent;
+ FPDT_DUAL_GUID_STRING_EVENT_RECORD *DualGuidStringEvent;
+ FPDT_GUID_QWORD_EVENT_RECORD *GuidQwordEvent;
+ FPDT_GUID_QWORD_STRING_EVENT_RECORD *GuidQwordStringEvent;
+} FPDT_RECORD_PTR;
+
+///
+/// Hob:
+/// GUID - gEdkiiFpdtExtendedFirmwarePerformanceGuid;
+/// Data - FPDT_PEI_EXT_PERF_HEADER + one or more FPDT records
+///
+typedef struct {
+ UINT32 SizeOfAllEntries;
+ UINT32 LoadImageCount;
+ UINT32 HobIsFull;
+} FPDT_PEI_EXT_PERF_HEADER;
+
+extern EFI_GUID gEdkiiFpdtExtendedFirmwarePerformanceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/FaultTolerantWrite.h b/roms/edk2/MdeModulePkg/Include/Guid/FaultTolerantWrite.h
new file mode 100644
index 000000000..da716ed14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/FaultTolerantWrite.h
@@ -0,0 +1,48 @@
+/** @file
+ Define the GUID gEdkiiFaultTolerantWriteGuid that will be used to build
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob and install PPI to inform the check
+ for FTW last write data has been done. The GUID hob will be only built if FTW last write was
+ still in progress with SpareComplete set and DestinationComplete not set.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FAULT_TOLERANT_WRITE_H_
+#define _FAULT_TOLERANT_WRITE_H_
+
+#define EDKII_FAULT_TOLERANT_WRITE_GUID \
+ { \
+ 0x1d3e9cb8, 0x43af, 0x490b, { 0x83, 0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 } \
+ }
+
+//
+// FTW Last write data. It will be used as gEdkiiFaultTolerantWriteGuid GUID hob data.
+//
+typedef struct {
+ ///
+ /// Target address to be updated in FTW last write.
+ ///
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ ///
+ /// Spare address to back up the updated buffer.
+ ///
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ ///
+ /// The length of data that have been backed up in spare block.
+ /// It is also the length of target block that has been erased.
+ ///
+ UINT64 Length;
+} FAULT_TOLERANT_WRITE_LAST_WRITE_DATA;
+
+//
+// This GUID will be used to install PPI to inform the check for FTW last write data has been done.
+// The related FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob will be only built if
+// FTW last write was still in progress with SpareComplete set and DestinationComplete not set.
+// It means the target buffer has been backed up in spare block, then target block has been erased,
+// but the target buffer has not been writen in target block from spare block.
+//
+extern EFI_GUID gEdkiiFaultTolerantWriteGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/FirmwarePerformance.h b/roms/edk2/MdeModulePkg/Include/Guid/FirmwarePerformance.h
new file mode 100644
index 000000000..e101ddd98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/FirmwarePerformance.h
@@ -0,0 +1,139 @@
+/** @file
+ ACPI Firmware Performance Data Table (FPDT) implementation specific definitions.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FIRMWARE_PERFORMANCE_GUID_H_
+#define _FIRMWARE_PERFORMANCE_GUID_H_
+
+#include <PiPei.h>
+#include <IndustryStandard/Acpi.h>
+#include <Ppi/SecPerformance.h>
+
+///
+/// This GUID is used for FPDT implementation specific EFI Variable, LockBox and Hob.
+///
+/// EFI Variable:
+/// GUID - gEfiFirmwarePerformanceGuid
+/// Name - EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME
+/// Data - FIRMWARE_PERFORMANCE_VARIABLE
+///
+/// LockBox:
+/// GUID - gEfiFirmwarePerformanceGuid
+/// Data - EFI_ACPI_BASIC_S3_SUSPEND_PERFORMANCE_RECORD
+///
+/// Hob:
+/// GUID - gEfiFirmwarePerformanceGuid
+/// Data - FIRMWARE_SEC_PERFORMANCE (defined in <Ppi/SecPerformance.h>)
+///
+/// SMI:
+/// GUID - gEfiFirmwarePerformanceGuid
+/// Data - SMM_BOOT_RECORD_COMMUNICATE
+///
+/// StatusCodeData:
+/// Type - gEfiFirmwarePerformanceGuid
+/// Data - One or more boot record
+///
+#define EFI_FIRMWARE_PERFORMANCE_GUID \
+ { \
+ 0xc095791a, 0x3001, 0x47b2, {0x80, 0xc9, 0xea, 0xc7, 0x31, 0x9f, 0x2f, 0xa4 } \
+ }
+
+#define EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME L"FirmwarePerformance"
+
+/// LockBox:
+/// GUID - gFirmwarePerformanceS3PointerGuid
+/// Data - S3 performance table pointer
+///
+#define FIRMWARE_PERFORMANCE_S3_POINTER_GUID \
+ { \
+ 0xdc65adc, 0xa973, 0x4130, { 0x8d, 0xf0, 0x2a, 0xdb, 0xeb, 0x9e, 0x4a, 0x31 } \
+ }
+
+#pragma pack(1)
+
+///
+/// Firmware Performance Data Table.
+/// This structure will be installed into ACPI table as FPDT in normal boot path.
+///
+typedef struct {
+ EFI_ACPI_DESCRIPTION_HEADER Header; ///< Common ACPI description table header.
+ EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD BootPointerRecord; ///< Basic Boot Performance Table Pointer record.
+ EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD S3PointerRecord; ///< S3 Performance Table Pointer record.
+} FIRMWARE_PERFORMANCE_TABLE;
+
+///
+/// S3 Performance Data Table.
+/// This structure contains S3 performance records which will be updated in S3
+/// suspend and S3 resume boot path.
+///
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER Header; ///< Common ACPI table header.
+ EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD S3Resume; ///< Basic S3 Resume performance record.
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3Suspend; ///< Basic S3 Suspend performance record.
+} S3_PERFORMANCE_TABLE;
+
+///
+/// Basic Boot Performance Data Table.
+/// This structure contains BasicBoot performance record.
+///
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER Header; ///< Common ACPI table header.
+ EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD BasicBoot; ///< Basic Boot Resume performance record.
+ //
+ // one or more boot performance records.
+ //
+} BOOT_PERFORMANCE_TABLE;
+
+///
+/// Boot performance table for the performance record in SMM phase.
+///
+///
+typedef struct {
+ EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER Header; ///< Common ACPI table header.
+ //
+ // one or more boot performance records.
+ //
+} SMM_BOOT_PERFORMANCE_TABLE;
+
+///
+/// Performance data pointed by Performance Pointer Record.
+///
+typedef struct {
+ BOOT_PERFORMANCE_TABLE BootPerformance; ///< Basic Boot Performance.
+ S3_PERFORMANCE_TABLE S3Performance; ///< S3 performance.
+} FIRMWARE_PERFORMANCE_RUNTIME_DATA;
+
+///
+/// Variable defined for FPDT implementation.
+/// This Variable is produced by FPDT DXE module.
+///
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BootPerformanceTablePointer; ///< Pointer to Boot Performance Table.
+ EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer; ///< Pointer to S3 Performance Table.
+} FIRMWARE_PERFORMANCE_VARIABLE;
+
+#pragma pack()
+
+//
+// Log BOOT RECORD from SMM driver on boot time.
+//
+#define SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE 1
+#define SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA 2
+#define SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET 3
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINTN BootRecordSize;
+ VOID *BootRecordData;
+ UINTN BootRecordOffset;
+} SMM_BOOT_RECORD_COMMUNICATE;
+
+extern EFI_GUID gEfiFirmwarePerformanceGuid;
+extern EFI_GUID gFirmwarePerformanceS3PointerGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/HiiBootMaintenanceFormset.h b/roms/edk2/MdeModulePkg/Include/Guid/HiiBootMaintenanceFormset.h
new file mode 100644
index 000000000..154ef5266
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/HiiBootMaintenanceFormset.h
@@ -0,0 +1,22 @@
+/** @file
+ Guid definition for Boot Maintainence Formset.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __HII_BOOT_MAINTENANCE_FORMSET_H__
+#define __HII_BOOT_MAINTENANCE_FORMSET_H__
+
+///
+/// Guid define to group the item show on the Boot Menaintenance Manager Menu.
+///
+#define EFI_IFR_BOOT_MAINTENANCE_GUID \
+ { 0xb2dedc91, 0xd59f, 0x48d2, { 0x89, 0x8a, 0x12, 0x49, 0xc, 0x74, 0xa4, 0xe0 } }
+
+
+extern EFI_GUID gEfiIfrBootMaintenanceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/HiiResourceSampleHii.h b/roms/edk2/MdeModulePkg/Include/Guid/HiiResourceSampleHii.h
new file mode 100644
index 000000000..e6ee4d282
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/HiiResourceSampleHii.h
@@ -0,0 +1,17 @@
+/** @file
+ GUID used as HII FormSet GUID in HII Resource Sample driver.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HII_RESOURCE_SAMPLE_HII_GUID_H__
+#define __HII_RESOURCE_SAMPLE_HII_GUID_H__
+
+#define HII_RESOURCE_SAMPLE_FORM_SET_GUID \
+ { 0x4f4ef7f0, 0xaa29, 0x4ce9, { 0xba, 0x41, 0x64, 0x3e, 0x1, 0x23, 0xa9, 0x9f }}
+
+extern EFI_GUID gHiiResourceSamleFormSetGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/IdleLoopEvent.h b/roms/edk2/MdeModulePkg/Include/Guid/IdleLoopEvent.h
new file mode 100644
index 000000000..50613d7be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/IdleLoopEvent.h
@@ -0,0 +1,18 @@
+/** @file
+ GUID is the name of events used with CreateEventEx in order to be notified
+ when the DXE Core is idle.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __IDLE_LOOP_EVENT_GUID_H__
+#define __IDLE_LOOP_EVENT_GUID_H__
+
+#define IDLE_LOOP_EVENT_GUID \
+ { 0x3c8d294c, 0x5fc3, 0x4451, { 0xbb, 0x31, 0xc4, 0xc0, 0x32, 0x29, 0x5e, 0x6c } }
+
+extern EFI_GUID gIdleLoopEventGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h b/roms/edk2/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h
new file mode 100644
index 000000000..6d73bf383
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h
@@ -0,0 +1,28 @@
+/** @file
+ This file defines a configuration Table Guid for Load module at fixed address.
+
+ This configuration table is to hold the top address below which the Dxe runtime code and
+ boot time code will be loaded and Tseg base. When this feature is enabled, Build tools will assigned
+ module loading address relative to these two addresses.
+
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__
+#define __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__
+
+#define EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE_GUID \
+ { 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9} }
+
+
+extern EFI_GUID gLoadFixedAddressConfigurationTableGuid;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS DxeCodeTopAddress; ///< The top address below which the Dxe runtime code and below which the Dxe runtime/boot code and PEI code.
+ EFI_PHYSICAL_ADDRESS SmramBase; ///< SMRAM base address. The build tool assigns an offset relative to the SMRAM base for a SMM driver.
+} EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/LzmaDecompress.h b/roms/edk2/MdeModulePkg/Include/Guid/LzmaDecompress.h
new file mode 100644
index 000000000..24099eb36
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/LzmaDecompress.h
@@ -0,0 +1,29 @@
+/** @file
+ Lzma Custom decompress algorithm Guid definition.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LZMA_DECOMPRESS_GUID_H__
+#define __LZMA_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 LZMA.
+///
+#define LZMA_CUSTOM_DECOMPRESS_GUID \
+ { 0xEE4E5898, 0x3914, 0x4259, { 0x9D, 0x6E, 0xDC, 0x7B, 0xD7, 0x94, 0x03, 0xCF } }
+
+///
+/// The Global ID used to identify a section of an FFS file of type
+/// EFI_SECTION_GUID_DEFINED, whose contents have been compressed using LZMA with X86 code Converter.
+///
+#define LZMAF86_CUSTOM_DECOMPRESS_GUID \
+ { 0xD42AE6BD, 0x1352, 0x4bfb, { 0x90, 0x9A, 0xCA, 0x72, 0xA6, 0xEA, 0xE8, 0x89 } }
+
+extern GUID gLzmaCustomDecompressGuid;
+extern GUID gLzmaF86CustomDecompressGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MdeModuleHii.h b/roms/edk2/MdeModulePkg/Include/Guid/MdeModuleHii.h
new file mode 100644
index 000000000..2de384639
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MdeModuleHii.h
@@ -0,0 +1,232 @@
+/** @file
+ EDKII extented HII IFR guid opcodes.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MDEMODULE_HII_H__
+#define __MDEMODULE_HII_H__
+
+#define NARROW_CHAR 0xFFF0
+#define WIDE_CHAR 0xFFF1
+#define NON_BREAKING_CHAR 0xFFF2
+
+///
+/// State defined for password statemachine .
+///
+#define BROWSER_STATE_VALIDATE_PASSWORD 0
+#define BROWSER_STATE_SET_PASSWORD 1
+
+///
+/// GUIDed opcodes defined for EDKII implementation.
+///
+#define EFI_IFR_TIANO_GUID \
+ { 0xf0b1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce} }
+
+#pragma pack(1)
+
+///
+/// EDKII implementation extension opcodes, new extension can be added here later.
+///
+#define EFI_IFR_EXTEND_OP_LABEL 0x0
+#define EFI_IFR_EXTEND_OP_BANNER 0x1
+#define EFI_IFR_EXTEND_OP_TIMEOUT 0x2
+#define EFI_IFR_EXTEND_OP_CLASS 0x3
+#define EFI_IFR_EXTEND_OP_SUBCLASS 0x4
+
+///
+/// Label opcode.
+///
+typedef struct _EFI_IFR_GUID_LABEL {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_TIANO_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_LABEL.
+ ///
+ UINT8 ExtendOpCode;
+ ///
+ /// Label Number.
+ ///
+ UINT16 Number;
+} EFI_IFR_GUID_LABEL;
+
+#define EFI_IFR_BANNER_ALIGN_LEFT 0
+#define EFI_IFR_BANNER_ALIGN_CENTER 1
+#define EFI_IFR_BANNER_ALIGN_RIGHT 2
+
+///
+/// Banner opcode.
+///
+typedef struct _EFI_IFR_GUID_BANNER {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_TIANO_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_BANNER
+ ///
+ UINT8 ExtendOpCode;
+ EFI_STRING_ID Title; ///< The string token for the banner title.
+ UINT16 LineNumber; ///< 1-based line number.
+ UINT8 Alignment; ///< left, center, or right-aligned.
+} EFI_IFR_GUID_BANNER;
+
+///
+/// Timeout opcode.
+///
+typedef struct _EFI_IFR_GUID_TIMEOUT {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_TIANO_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_TIMEOUT.
+ ///
+ UINT8 ExtendOpCode;
+ UINT16 TimeOut; ///< TimeOut Value.
+} EFI_IFR_GUID_TIMEOUT;
+
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+///
+/// Device Class opcode.
+///
+typedef struct _EFI_IFR_GUID_CLASS {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_TIANO_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_CLASS.
+ ///
+ UINT8 ExtendOpCode;
+ UINT16 Class; ///< Device Class from the above.
+} EFI_IFR_GUID_CLASS;
+
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+///
+/// SubClass opcode
+///
+typedef struct _EFI_IFR_GUID_SUBCLASS {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_TIANO_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_SUBCLASS.
+ ///
+ UINT8 ExtendOpCode;
+ UINT16 SubClass; ///< Sub Class type from the above.
+} EFI_IFR_GUID_SUBCLASS;
+
+///
+/// GUIDed opcodes support for framework vfr.
+///
+#define EFI_IFR_FRAMEWORK_GUID \
+ { 0x31ca5d1a, 0xd511, 0x4931, { 0xb7, 0x82, 0xae, 0x6b, 0x2b, 0x17, 0x8c, 0xd7 } }
+
+///
+/// Two extended opcodes are added, and new extensions can be added here later.
+/// One is for framework OneOf question Option Key value;
+/// another is for framework vareqval.
+///
+#define EFI_IFR_EXTEND_OP_OPTIONKEY 0x0
+#define EFI_IFR_EXTEND_OP_VAREQNAME 0x1
+
+///
+/// Store the framework vfr option key value.
+///
+typedef struct _EFI_IFR_GUID_OPTIONKEY {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_FRAMEWORK_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_OPTIONKEY.
+ ///
+ UINT8 ExtendOpCode;
+ ///
+ /// OneOf Questiond ID binded by OneOf Option.
+ ///
+ EFI_QUESTION_ID QuestionId;
+ ///
+ /// The OneOf Option Value.
+ ///
+ EFI_IFR_TYPE_VALUE OptionValue;
+ ///
+ /// The Framework OneOf Option Key Value.
+ ///
+ UINT16 KeyValue;
+} EFI_IFR_GUID_OPTIONKEY;
+
+///
+/// Store the framework vfr vareqval name number.
+///
+typedef struct _EFI_IFR_GUID_VAREQNAME {
+ EFI_IFR_OP_HEADER Header;
+ ///
+ /// EFI_IFR_FRAMEWORK_GUID.
+ ///
+ EFI_GUID Guid;
+ ///
+ /// EFI_IFR_EXTEND_OP_VAREQNAME.
+ ///
+ UINT8 ExtendOpCode;
+ ///
+ /// Question ID of the Numeric Opcode created.
+ ///
+ EFI_QUESTION_ID QuestionId;
+ ///
+ /// For vareqval (0x100), NameId is 0x100.
+ /// This value will convert to a Unicode String following this rule;
+ /// sprintf(StringBuffer, "%d", NameId) .
+ /// The the Unicode String will be used as a EFI Variable Name.
+ ///
+ UINT16 NameId;
+} EFI_IFR_GUID_VAREQNAME;
+
+///
+/// EDKII implementation extension GUID, used to indaicate there are bit fields in the varstore.
+///
+#define EDKII_IFR_BIT_VARSTORE_GUID \
+ {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60,0xA7, 0x1D}}
+
+///
+/// EDKII implementation extension flags, used to indaicate the disply style and bit width for bit filed storage.
+/// Two high bits for display style and the low six bits for bit width.
+///
+#define EDKII_IFR_DISPLAY_BIT 0xC0
+#define EDKII_IFR_DISPLAY_INT_DEC_BIT 0x00
+#define EDKII_IFR_DISPLAY_UINT_DEC_BIT 0x40
+#define EDKII_IFR_DISPLAY_UINT_HEX_BIT 0x80
+
+#define EDKII_IFR_NUMERIC_SIZE_BIT 0x3F
+
+#pragma pack()
+
+extern EFI_GUID gEfiIfrTianoGuid;
+extern EFI_GUID gEfiIfrFrameworkGuid;
+extern EFI_GUID gEdkiiIfrBitVarstoreGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MdeModulePkgTokenSpace.h b/roms/edk2/MdeModulePkg/Include/Guid/MdeModulePkgTokenSpace.h
new file mode 100644
index 000000000..e3822be3c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MdeModulePkgTokenSpace.h
@@ -0,0 +1,19 @@
+/** @file
+ GUID for MdeModulePkg PCD Token Space.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MDEMODULEPKG_TOKEN_SPACE_GUID_H_
+#define _MDEMODULEPKG_TOKEN_SPACE_GUID_H_
+
+#define MDEMODULEPKG_TOKEN_SPACE_GUID \
+ { \
+ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC } \
+ }
+
+extern EFI_GUID gEfiMdeModulePkgTokenSpaceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MemoryProfile.h b/roms/edk2/MdeModulePkg/Include/Guid/MemoryProfile.h
new file mode 100644
index 000000000..eee3b9125
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MemoryProfile.h
@@ -0,0 +1,468 @@
+/** @file
+ Memory profile data structure.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MEMORY_PROFILE_H_
+#define _MEMORY_PROFILE_H_
+
+#include <Pi/PiFirmwareFile.h>
+
+//
+// For BIOS MemoryType (0 ~ EfiMaxMemoryType - 1), it is recorded in UsageByType[MemoryType]. (Each valid entry has one entry)
+// For OS MemoryType (0x80000000 ~ 0xFFFFFFFF), it is recorded in UsageByType[EfiMaxMemoryType]. (All types are combined into one entry)
+// For OEM MemoryType (0x70000000 ~ 0x7FFFFFFF), it is recorded in UsageByType[EfiMaxMemoryType + 1]. (All types are combined into one entry)
+//
+
+typedef struct {
+ UINT32 Signature;
+ UINT16 Length;
+ UINT16 Revision;
+} MEMORY_PROFILE_COMMON_HEADER;
+
+#define MEMORY_PROFILE_CONTEXT_SIGNATURE SIGNATURE_32 ('M','P','C','T')
+#define MEMORY_PROFILE_CONTEXT_REVISION 0x0002
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ UINT64 CurrentTotalUsage;
+ UINT64 PeakTotalUsage;
+ UINT64 CurrentTotalUsageByType[EfiMaxMemoryType + 2];
+ UINT64 PeakTotalUsageByType[EfiMaxMemoryType + 2];
+ UINT64 TotalImageSize;
+ UINT32 ImageCount;
+ UINT32 SequenceCount;
+} MEMORY_PROFILE_CONTEXT;
+
+#define MEMORY_PROFILE_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('M','P','D','I')
+#define MEMORY_PROFILE_DRIVER_INFO_REVISION 0x0003
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ EFI_GUID FileName;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ PHYSICAL_ADDRESS EntryPoint;
+ UINT16 ImageSubsystem;
+ EFI_FV_FILETYPE FileType;
+ UINT8 Reserved[1];
+ UINT32 AllocRecordCount;
+ UINT64 CurrentUsage;
+ UINT64 PeakUsage;
+ UINT64 CurrentUsageByType[EfiMaxMemoryType + 2];
+ UINT64 PeakUsageByType[EfiMaxMemoryType + 2];
+ UINT16 PdbStringOffset;
+ UINT8 Reserved2[6];
+//CHAR8 PdbString[];
+} MEMORY_PROFILE_DRIVER_INFO;
+
+typedef enum {
+ MemoryProfileActionAllocatePages = 1,
+ MemoryProfileActionFreePages = 2,
+ MemoryProfileActionAllocatePool = 3,
+ MemoryProfileActionFreePool = 4,
+} MEMORY_PROFILE_ACTION;
+
+//
+// Below is the detailed MEMORY_PROFILE_ACTION definition.
+//
+// 31 15 9 8 8 7 7 6 6 5-4 3 - 0
+// +----------------------------------------------+
+// |User | |Lib| |Re|Copy|Zero|Align|Type|Basic|
+// +----------------------------------------------+
+//
+
+//
+// Basic Action
+// 1 : AllocatePages
+// 2 : FreePages
+// 3 : AllocatePool
+// 4 : FreePool
+//
+#define MEMORY_PROFILE_ACTION_BASIC_MASK 0xF
+
+//
+// Extension
+//
+#define MEMORY_PROFILE_ACTION_EXTENSION_MASK 0xFFF0
+#define MEMORY_PROFILE_ACTION_EXTENSION_LIB_MASK 0x8000
+#define MEMORY_PROFILE_ACTION_EXTENSION_REALLOC_MASK 0x0200
+#define MEMORY_PROFILE_ACTION_EXTENSION_COPY_MASK 0x0100
+#define MEMORY_PROFILE_ACTION_EXTENSION_ZERO_MASK 0x0080
+#define MEMORY_PROFILE_ACTION_EXTENSION_ALIGN_MASK 0x0040
+#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_MASK 0x0030
+#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_BASIC 0x0000
+#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_RUNTIME 0x0010
+#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_RESERVED 0x0020
+
+//
+// Extension (used by memory allocation lib)
+//
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES 0x8001
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES 0x8011
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES 0x8021
+#define MEMORY_PROFILE_ACTION_LIB_FREE_PAGES 0x8002
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES 0x8041
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES 0x8051
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES 0x8061
+#define MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES 0x8042
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL 0x8003
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL 0x8013
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL 0x8023
+#define MEMORY_PROFILE_ACTION_LIB_FREE_POOL 0x8004
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL 0x8083
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL 0x8093
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL 0x80a3
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL 0x8103
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL 0x8113
+#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL 0x8123
+#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL 0x8203
+#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL 0x8213
+#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL 0x8223
+
+//
+// User defined: 0x80000000~0xFFFFFFFF
+//
+// NOTE: User defined action MUST OR the basic action,
+// so that core can know the action is allocate or free,
+// and the type is pages (can be freed partially)
+// or pool (cannot be freed partially).
+//
+#define MEMORY_PROFILE_ACTION_USER_DEFINED_MASK 0x80000000
+
+#define MEMORY_PROFILE_ALLOC_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','I')
+#define MEMORY_PROFILE_ALLOC_INFO_REVISION 0x0002
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ PHYSICAL_ADDRESS CallerAddress;
+ UINT32 SequenceId;
+ UINT8 Reserved[2];
+ UINT16 ActionStringOffset;
+ MEMORY_PROFILE_ACTION Action;
+ EFI_MEMORY_TYPE MemoryType;
+ PHYSICAL_ADDRESS Buffer;
+ UINT64 Size;
+//CHAR8 ActionString[];
+} MEMORY_PROFILE_ALLOC_INFO;
+
+#define MEMORY_PROFILE_DESCRIPTOR_SIGNATURE SIGNATURE_32 ('M','P','D','R')
+#define MEMORY_PROFILE_DESCRIPTOR_REVISION 0x0001
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ PHYSICAL_ADDRESS Address;
+ UINT64 Size;
+} MEMORY_PROFILE_DESCRIPTOR;
+
+#define MEMORY_PROFILE_FREE_MEMORY_SIGNATURE SIGNATURE_32 ('M','P','R','M')
+#define MEMORY_PROFILE_FREE_MEMORY_REVISION 0x0001
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ UINT64 TotalFreeMemoryPages;
+ UINT32 FreeMemoryEntryCount;
+ UINT8 Reserved[4];
+ //MEMORY_PROFILE_DESCRIPTOR MemoryDescriptor[FreeMemoryEntryCount];
+} MEMORY_PROFILE_FREE_MEMORY;
+
+#define MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE SIGNATURE_32 ('M','P','M','R')
+#define MEMORY_PROFILE_MEMORY_RANGE_REVISION 0x0001
+
+typedef struct {
+ MEMORY_PROFILE_COMMON_HEADER Header;
+ UINT32 MemoryRangeCount;
+ UINT8 Reserved[4];
+ //MEMORY_PROFILE_DESCRIPTOR MemoryDescriptor[MemoryRangeCount];
+} MEMORY_PROFILE_MEMORY_RANGE;
+
+//
+// UEFI memory profile layout:
+// +--------------------------------+
+// | CONTEXT |
+// +--------------------------------+
+// | DRIVER_INFO(1) |
+// +--------------------------------+
+// | ALLOC_INFO(1, 1) |
+// +--------------------------------+
+// | ALLOC_INFO(1, m1) |
+// +--------------------------------+
+// | DRIVER_INFO(n) |
+// +--------------------------------+
+// | ALLOC_INFO(n, 1) |
+// +--------------------------------+
+// | ALLOC_INFO(n, mn) |
+// +--------------------------------+
+//
+
+typedef struct _EDKII_MEMORY_PROFILE_PROTOCOL EDKII_MEMORY_PROFILE_PROTOCOL;
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_GET_DATA)(
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ );
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_REGISTER_IMAGE)(
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE)(
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ );
+
+#define MEMORY_PROFILE_RECORDING_ENABLE TRUE
+#define MEMORY_PROFILE_RECORDING_DISABLE FALSE
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_GET_RECORDING_STATE) (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ );
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_SET_RECORDING_STATE) (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ );
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_MEMORY_PROFILE_RECORD) (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+struct _EDKII_MEMORY_PROFILE_PROTOCOL {
+ EDKII_MEMORY_PROFILE_GET_DATA GetData;
+ EDKII_MEMORY_PROFILE_REGISTER_IMAGE RegisterImage;
+ EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE UnregisterImage;
+ EDKII_MEMORY_PROFILE_GET_RECORDING_STATE GetRecordingState;
+ EDKII_MEMORY_PROFILE_SET_RECORDING_STATE SetRecordingState;
+ EDKII_MEMORY_PROFILE_RECORD Record;
+};
+
+//
+// SMRAM profile layout:
+// +--------------------------------+
+// | CONTEXT |
+// +--------------------------------+
+// | DRIVER_INFO(1) |
+// +--------------------------------+
+// | ALLOC_INFO(1, 1) |
+// +--------------------------------+
+// | ALLOC_INFO(1, m1) |
+// +--------------------------------+
+// | DRIVER_INFO(n) |
+// +--------------------------------+
+// | ALLOC_INFO(n, 1) |
+// +--------------------------------+
+// | ALLOC_INFO(n, mn) |
+// +--------------------------------+
+// | FREE_MEMORY |
+// +--------------------------------+
+// | FREE MEMORY DESCRIPTOR(1) |
+// +--------------------------------+
+// | FREE MEMORY DESCRIPTOR(p) |
+// +--------------------------------+
+// | MEMORY_RANGE |
+// +--------------------------------+
+// | MEMORY RANGE DESCRIPTOR(1) |
+// +--------------------------------+
+// | MEMORY RANGE DESCRIPTOR(q) |
+// +--------------------------------+
+//
+
+//
+// SMRAM profile command
+//
+#define SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO 0x1
+#define SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA 0x2
+//
+// Below 2 commands are now used by ECP only and only valid before SmmReadyToLock
+//
+#define SMRAM_PROFILE_COMMAND_REGISTER_IMAGE 0x3
+#define SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE 0x4
+
+#define SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET 0x5
+#define SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE 0x6
+#define SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE 0x7
+
+typedef struct {
+ UINT32 Command;
+ UINT32 DataLength;
+ UINT64 ReturnStatus;
+} SMRAM_PROFILE_PARAMETER_HEADER;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ UINT64 ProfileSize;
+} SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ UINT64 ProfileSize;
+ PHYSICAL_ADDRESS ProfileBuffer;
+} SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ //
+ // On input, profile buffer size.
+ // On output, actual profile data size copied.
+ //
+ UINT64 ProfileSize;
+ PHYSICAL_ADDRESS ProfileBuffer;
+ //
+ // On input, profile buffer offset to copy.
+ // On output, next time profile buffer offset to copy.
+ //
+ UINT64 ProfileOffset;
+} SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ BOOLEAN RecordingState;
+} SMRAM_PROFILE_PARAMETER_RECORDING_STATE;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ EFI_GUID FileName;
+ PHYSICAL_ADDRESS ImageBuffer;
+ UINT64 NumberOfPage;
+} SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE;
+
+typedef struct {
+ SMRAM_PROFILE_PARAMETER_HEADER Header;
+ EFI_GUID FileName;
+ PHYSICAL_ADDRESS ImageBuffer;
+ UINT64 NumberOfPage;
+} SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE;
+
+
+#define EDKII_MEMORY_PROFILE_GUID { \
+ 0x821c9a09, 0x541a, 0x40f6, { 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe } \
+}
+
+extern EFI_GUID gEdkiiMemoryProfileGuid;
+
+typedef EDKII_MEMORY_PROFILE_PROTOCOL EDKII_SMM_MEMORY_PROFILE_PROTOCOL;
+
+#define EDKII_SMM_MEMORY_PROFILE_GUID { \
+ 0xe22bbcca, 0x516a, 0x46a8, { 0x80, 0xe2, 0x67, 0x45, 0xe8, 0x36, 0x93, 0xbd } \
+}
+
+extern EFI_GUID gEdkiiSmmMemoryProfileGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MemoryStatusCodeRecord.h b/roms/edk2/MdeModulePkg/Include/Guid/MemoryStatusCodeRecord.h
new file mode 100644
index 000000000..8dafc6945
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MemoryStatusCodeRecord.h
@@ -0,0 +1,97 @@
+/** @file
+ GUID used to identify status code records HOB that originate from the PEI status code.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MEMORY_STATUS_CODE_RECORD_H__
+#define __MEMORY_STATUS_CODE_RECORD_H__
+
+///
+/// Global ID used to identify GUIDed HOBs that start with a structure of type
+/// MEMORY_STATUSCODE_PACKET_HEADER, followed by an array of structures of type
+/// MEMORY_STATUSCODE_RECORD. These GUIDed HOBs record all the information
+/// passed into the ReportStatusCode() service of PEI Services Table.
+///
+/// <pre>
+/// Memory status code records packet structure :
+/// +---------------+----------+----------+-----+----------+-----+----------+
+/// | Packet Header | Record 1 | Record 2 | ... + Record n | ... | Record m |
+/// +---------------+----------+----------+-----+----------+-----+----------+
+/// ^ ^ ^
+/// +--------- RecordIndex -----------+ |
+/// +---------------- MaxRecordsNumber----------------------+
+/// </pre>
+///
+#define MEMORY_STATUS_CODE_RECORD_GUID \
+ { \
+ 0x60cc026, 0x4c0d, 0x4dda, {0x8f, 0x41, 0x59, 0x5f, 0xef, 0x0, 0xa5, 0x2} \
+ }
+
+///
+/// A header structure that is followed by an array of records that contain the
+/// parameters passed into the ReportStatusCode() service in the PEI Services Table.
+///
+typedef struct {
+ ///
+ /// Index of the packet.
+ ///
+ UINT16 PacketIndex;
+ ///
+ /// The number of active records in the packet.
+ ///
+ UINT16 RecordIndex;
+ ///
+ /// The maximum number of records that the packet can store.
+ ///
+ UINT32 MaxRecordsNumber;
+} MEMORY_STATUSCODE_PACKET_HEADER;
+
+///
+/// A header structure that is followed by an array of records that contain the
+/// parameters passed into the ReportStatusCode() service in the DXE Services Table.
+///
+typedef struct {
+ ///
+ /// The index pointing to the last recored being stored.
+ ///
+ UINT32 RecordIndex;
+ ///
+ /// The number of records being stored.
+ ///
+ UINT32 NumberOfRecords;
+ ///
+ /// The maximum number of records that can be stored.
+ ///
+ UINT32 MaxRecordsNumber;
+} RUNTIME_MEMORY_STATUSCODE_HEADER;
+
+///
+/// A structure that contains the parameters passed into the ReportStatusCode()
+/// service in the PEI Services Table.
+///
+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 the number 1.
+ ///
+ UINT32 Instance;
+} MEMORY_STATUSCODE_RECORD;
+
+extern EFI_GUID gMemoryStatusCodeRecordGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MemoryTypeInformation.h b/roms/edk2/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
new file mode 100644
index 000000000..eba509f0f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
@@ -0,0 +1,30 @@
+/** @file
+ This file defines:
+ * Memory Type Information GUID for HOB and Variable.
+ * Memory Type Information Variable Name.
+ * Memory Type Information GUID HOB data structure.
+
+ The memory type information HOB and variable can
+ be used to store the information for each memory type in Variable or HOB.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MEMORY_TYPE_INFORMATION_GUID_H__
+#define __MEMORY_TYPE_INFORMATION_GUID_H__
+
+#define EFI_MEMORY_TYPE_INFORMATION_GUID \
+ { 0x4c19049f,0x4137,0x4dd3, { 0x9c,0x10,0x8b,0x97,0xa8,0x3f,0xfd,0xfa } }
+
+#define EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME L"MemoryTypeInformation"
+
+extern EFI_GUID gEfiMemoryTypeInformationGuid;
+
+typedef struct {
+ UINT32 Type; ///< EFI memory type defined in UEFI specification.
+ UINT32 NumberOfPages; ///< The pages of this type memory.
+} EFI_MEMORY_TYPE_INFORMATION;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MigratedFvInfo.h b/roms/edk2/MdeModulePkg/Include/Guid/MigratedFvInfo.h
new file mode 100644
index 000000000..061c17ed0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MigratedFvInfo.h
@@ -0,0 +1,22 @@
+/** @file
+ Migrated FV information
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EDKII_MIGRATED_FV_INFO_GUID_H__
+#define __EDKII_MIGRATED_FV_INFO_GUID_H__
+
+typedef struct {
+ UINT32 FvOrgBase; // original FV address
+ UINT32 FvNewBase; // new FV address
+ UINT32 FvDataBase; // original FV data
+ UINT32 FvLength; // Fv Length
+} EDKII_MIGRATED_FV_INFO;
+
+extern EFI_GUID gEdkiiMigratedFvInfoGuid;
+
+#endif // #ifndef __EDKII_MIGRATED_FV_INFO_GUID_H__
+
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/MtcVendor.h b/roms/edk2/MdeModulePkg/Include/Guid/MtcVendor.h
new file mode 100644
index 000000000..3104c21d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/MtcVendor.h
@@ -0,0 +1,25 @@
+/** @file
+ GUID is for MTC variable.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MTC_VENDOR_GUID_H__
+#define __MTC_VENDOR_GUID_H__
+
+//
+// Vendor GUID of the variable for the high part of monotonic counter (UINT32).
+//
+#define MTC_VENDOR_GUID \
+ { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } }
+
+//
+// Name of the variable for the high part of monotonic counter
+//
+#define MTC_VARIABLE_NAME L"MTC"
+
+extern EFI_GUID gMtcVendorGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/NonDiscoverableDevice.h b/roms/edk2/MdeModulePkg/Include/Guid/NonDiscoverableDevice.h
new file mode 100644
index 000000000..e277c0b87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/NonDiscoverableDevice.h
@@ -0,0 +1,52 @@
+/** @file
+ GUIDs to identify devices that are not on a discoverable bus but can be
+ controlled by a standard class driver
+
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __NON_DISCOVERABLE_DEVICE_GUID_H__
+#define __NON_DISCOVERABLE_DEVICE_GUID_H__
+
+#define EDKII_NON_DISCOVERABLE_AHCI_DEVICE_GUID \
+ { 0xC7D35798, 0xE4D2, 0x4A93, {0xB1, 0x45, 0x54, 0x88, 0x9F, 0x02, 0x58, 0x4B } }
+
+#define EDKII_NON_DISCOVERABLE_AMBA_DEVICE_GUID \
+ { 0x94440339, 0xCC93, 0x4506, {0xB4, 0xC6, 0xEE, 0x8D, 0x0F, 0x4C, 0xA1, 0x91 } }
+
+#define EDKII_NON_DISCOVERABLE_EHCI_DEVICE_GUID \
+ { 0xEAEE5615, 0x0CFD, 0x45FC, {0x87, 0x69, 0xA0, 0xD8, 0x56, 0x95, 0xAF, 0x85 } }
+
+#define EDKII_NON_DISCOVERABLE_NVME_DEVICE_GUID \
+ { 0xC5F25542, 0x2A79, 0x4A26, {0x81, 0xBB, 0x4E, 0xA6, 0x32, 0x33, 0xB3, 0x09 } }
+
+#define EDKII_NON_DISCOVERABLE_OHCI_DEVICE_GUID \
+ { 0xB20005B0, 0xBB2D, 0x496F, {0x86, 0x9C, 0x23, 0x0B, 0x44, 0x79, 0xE7, 0xD1 } }
+
+#define EDKII_NON_DISCOVERABLE_SDHCI_DEVICE_GUID \
+ { 0x1DD1D619, 0xF9B8, 0x463E, {0x86, 0x81, 0xD1, 0xDC, 0x7C, 0x07, 0xB7, 0x2C } }
+
+#define EDKII_NON_DISCOVERABLE_UFS_DEVICE_GUID \
+ { 0x2EA77912, 0x80A8, 0x4947, {0xBE, 0x69, 0xCD, 0xD0, 0x0A, 0xFB, 0xE5, 0x56 } }
+
+#define EDKII_NON_DISCOVERABLE_UHCI_DEVICE_GUID \
+ { 0xA8CDA0A2, 0x4F37, 0x4A1B, {0x8E, 0x10, 0x8E, 0xF3, 0xCC, 0x3B, 0xF3, 0xA8 } }
+
+#define EDKII_NON_DISCOVERABLE_XHCI_DEVICE_GUID \
+ { 0xB1BE0BC5, 0x6C28, 0x442D, {0xAA, 0x37, 0x15, 0x1B, 0x42, 0x57, 0xBD, 0x78 } }
+
+
+extern EFI_GUID gEdkiiNonDiscoverableAhciDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableAmbaDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableEhciDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableNvmeDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableOhciDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableSdhciDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableUfsDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableUhciDeviceGuid;
+extern EFI_GUID gEdkiiNonDiscoverableXhciDeviceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseHobGuid.h b/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseHobGuid.h
new file mode 100644
index 000000000..3db8b6494
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseHobGuid.h
@@ -0,0 +1,19 @@
+/** @file
+ Hob guid for Pcd DataBase.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCD_DATABASE_HOB_GUID_H_
+#define _PCD_DATABASE_HOB_GUID_H_
+
+#define PCD_DATABASE_HOB_GUID \
+ { \
+ 0xEA296D92, 0x0B69, 0x423C, { 0x8C, 0x28, 0x33, 0xB4, 0xE0, 0xA9, 0x12, 0x68 } \
+ }
+
+extern EFI_GUID gPcdDataBaseHobGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseSignatureGuid.h b/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseSignatureGuid.h
new file mode 100644
index 000000000..7802d5497
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PcdDataBaseSignatureGuid.h
@@ -0,0 +1,228 @@
+/** @file
+ Guid for Pcd DataBase Signature.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCD_DATABASE_SIGNATURE_GUID_H_
+#define _PCD_DATABASE_SIGNATURE_GUID_H_
+
+#define PCD_DATA_BASE_SIGNATURE_GUID \
+{ 0x3c7d193c, 0x682c, 0x4c14, { 0xa6, 0x8f, 0x55, 0x2d, 0xea, 0x4f, 0x43, 0x7e } }
+
+extern EFI_GUID gPcdDataBaseSignatureGuid;
+
+//
+// Common definitions
+//
+typedef UINT64 SKU_ID;
+
+#define PCD_TYPE_SHIFT 28
+
+#define PCD_TYPE_DATA (0x0U << PCD_TYPE_SHIFT)
+#define PCD_TYPE_HII (0x8U << PCD_TYPE_SHIFT)
+#define PCD_TYPE_VPD (0x4U << PCD_TYPE_SHIFT)
+#define PCD_TYPE_STRING (0x1U << PCD_TYPE_SHIFT)
+
+#define PCD_TYPE_ALL_SET (PCD_TYPE_DATA | PCD_TYPE_HII | PCD_TYPE_VPD | PCD_TYPE_STRING)
+
+#define PCD_DATUM_TYPE_SHIFT 24
+
+#define PCD_DATUM_TYPE_POINTER (0x0U << PCD_DATUM_TYPE_SHIFT)
+#define PCD_DATUM_TYPE_UINT8 (0x1U << PCD_DATUM_TYPE_SHIFT)
+#define PCD_DATUM_TYPE_UINT16 (0x2U << PCD_DATUM_TYPE_SHIFT)
+#define PCD_DATUM_TYPE_UINT32 (0x4U << PCD_DATUM_TYPE_SHIFT)
+#define PCD_DATUM_TYPE_UINT64 (0x8U << PCD_DATUM_TYPE_SHIFT)
+
+#define PCD_DATUM_TYPE_ALL_SET (PCD_DATUM_TYPE_POINTER | \
+ PCD_DATUM_TYPE_UINT8 | \
+ PCD_DATUM_TYPE_UINT16 | \
+ PCD_DATUM_TYPE_UINT32 | \
+ PCD_DATUM_TYPE_UINT64)
+
+#define PCD_DATUM_TYPE_SHIFT2 20
+
+#define PCD_DATUM_TYPE_UINT8_BOOLEAN (0x1U << PCD_DATUM_TYPE_SHIFT2)
+
+#define PCD_DATABASE_OFFSET_MASK (~(PCD_TYPE_ALL_SET | PCD_DATUM_TYPE_ALL_SET | PCD_DATUM_TYPE_UINT8_BOOLEAN))
+
+typedef struct {
+ UINT32 ExTokenNumber;
+ UINT16 TokenNumber; // Token Number for Dynamic-Ex PCD.
+ UINT16 ExGuidIndex; // Index of GuidTable in units of GUID.
+} DYNAMICEX_MAPPING;
+
+typedef struct {
+ UINT32 StringIndex; // Offset in String Table in units of UINT8.
+ UINT32 DefaultValueOffset; // Offset of the Default Value.
+ UINT16 GuidTableIndex; // Offset in Guid Table in units of GUID.
+ UINT16 Offset; // Offset in Variable.
+ UINT32 Attributes; // Variable attributes.
+ UINT16 Property; // Variable property.
+ UINT16 Reserved;
+} VARIABLE_HEAD;
+
+typedef struct {
+ UINT32 Offset;
+} VPD_HEAD;
+
+typedef UINT32 STRING_HEAD;
+
+typedef UINT16 SIZE_INFO;
+
+typedef struct {
+ UINT32 TokenSpaceCNameIndex; // Offset in String Table in units of UINT8.
+ UINT32 PcdCNameIndex; // Offset in String Table in units of UINT8.
+} PCD_NAME_INDEX;
+
+typedef UINT32 TABLE_OFFSET;
+
+typedef struct {
+ GUID Signature; // PcdDataBaseGuid.
+ UINT32 BuildVersion;
+ UINT32 Length; // Length of DEFAULT SKU PCD DB
+ SKU_ID SystemSkuId; // Current SkuId value.
+ UINT32 LengthForAllSkus; // Length of all SKU PCD DB
+ UINT32 UninitDataBaseSize; // Total size for PCD those default value with 0.
+ TABLE_OFFSET LocalTokenNumberTableOffset;
+ TABLE_OFFSET ExMapTableOffset;
+ TABLE_OFFSET GuidTableOffset;
+ TABLE_OFFSET StringTableOffset;
+ TABLE_OFFSET SizeTableOffset;
+ TABLE_OFFSET SkuIdTableOffset;
+ TABLE_OFFSET PcdNameTableOffset;
+ UINT16 LocalTokenCount; // LOCAL_TOKEN_NUMBER for all.
+ UINT16 ExTokenCount; // EX_TOKEN_NUMBER for DynamicEx.
+ UINT16 GuidTableCount; // The Number of Guid in GuidTable.
+ UINT8 Pad[6]; // Pad bytes to satisfy the alignment.
+
+ //
+ // Default initialized external PCD database binary structure
+ //
+ // Padding is needed to keep necessary alignment
+ //
+ //SKU_ID SkuIdTable[]; // SkuIds system supports.
+ //UINT64 ValueUint64[];
+ //UINT32 ValueUint32[];
+ //VPD_HEAD VpdHead[]; // VPD Offset
+ //DYNAMICEX_MAPPING ExMapTable[]; // DynamicEx PCD mapped to LocalIndex in LocalTokenNumberTable. It can be accessed by the ExMapTableOffset.
+ //UINT32 LocalTokenNumberTable[]; // Offset | DataType | PCD Type. It can be accessed by LocalTokenNumberTableOffset.
+ //GUID GuidTable[]; // GUID for DynamicEx and HII PCD variable Guid. It can be accessed by the GuidTableOffset.
+ //STRING_HEAD StringHead[]; // String PCD
+ //PCD_NAME_INDEX PcdNameTable[]; // PCD name index info. It can be accessed by the PcdNameTableOffset.
+ //VARIABLE_HEAD VariableHead[]; // HII PCD
+ //UINT8 StringTable[]; // String for String PCD value and HII PCD Variable Name. It can be accessed by StringTableOffset.
+ //SIZE_INFO SizeTable[]; // MaxSize and CurSize for String PCD. It can be accessed by SizeTableOffset.
+ //UINT16 ValueUint16[];
+ //UINT8 ValueUint8[];
+ //BOOLEAN ValueBoolean[];
+
+} PCD_DATABASE_INIT;
+
+//
+// PEI and DXE Pcd driver use the same PCD database
+//
+typedef PCD_DATABASE_INIT PEI_PCD_DATABASE;
+typedef PCD_DATABASE_INIT DXE_PCD_DATABASE;
+
+
+typedef struct {
+ PEI_PCD_DATABASE *PeiDb;
+ DXE_PCD_DATABASE *DxeDb;
+} PCD_DATABASE;
+
+typedef struct {
+ UINT32 Offset:24;
+ UINT32 Value:8;
+} PCD_DATA_DELTA;
+
+typedef struct {
+ SKU_ID SkuId;
+ UINT16 DefaultId;
+ UINT8 Reserved[6];
+} PCD_DEFAULT_INFO;
+
+typedef struct {
+ //
+ // Full size, it must be at 8 byte alignment.
+ //
+ UINT32 DataSize;
+ //
+ // HeaderSize includes HeaderSize fields and DefaultInfo arrays
+ //
+ UINT32 HeaderSize;
+ //
+ // DefaultInfo arrays those have the same default setting.
+ //
+ PCD_DEFAULT_INFO DefaultInfo[1];
+ //
+ // Default data is stored as variable storage or the array of DATA_DELTA.
+ //
+} PCD_DEFAULT_DATA;
+
+#define PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE SIGNATURE_32('N', 'S', 'D', 'B')
+
+typedef struct {
+ //
+ // PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE
+ //
+ UINT32 Signature;
+ //
+ // Length of the taken default buffer
+ //
+ UINT32 Length;
+ //
+ // Length of the total reserved buffer
+ //
+ UINT32 MaxLength;
+ //
+ // Reserved for 8 byte alignment
+ //
+ UINT32 Reserved;
+ // one or more PCD_DEFAULT_DATA
+} PCD_NV_STORE_DEFAULT_BUFFER_HEADER;
+
+//
+// NvStoreDefaultValueBuffer layout:
+// +-------------------------------------+
+// | PCD_NV_STORE_DEFAULT_BUFFER_HEADER |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | PCD_DATA_DELTA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (SKU A, Standard) |
+// +-------------------------------------+
+// | PCD_DATA_DELTA (SKU A, Standard) |
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+//
+
+#pragma pack(1)
+typedef struct {
+ SKU_ID SkuId;
+ SKU_ID SkuIdCompared;
+ UINT32 Length;
+ // PCD_DATA_DELTA DeltaData[]
+} PCD_DATABASE_SKU_DELTA;
+
+//
+// PCD database layout:
+// +---------------------------------+
+// | PCD_DATABASE_INIT (DEFAULT SKU) |
+// +---------------------------------+
+// | PCD_DATABASE_SKU_DELTA (SKU A) |
+// +---------------------------------+
+// | PCD_DATABASE_SKU_DELTA (SKU B) |
+// +---------------------------------+
+// | ...... |
+// +---------------------------------+
+//
+#pragma pack()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/Performance.h b/roms/edk2/MdeModulePkg/Include/Guid/Performance.h
new file mode 100644
index 000000000..9d7b3ad32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/Performance.h
@@ -0,0 +1,337 @@
+/** @file
+ This file defines performance-related definitions, including the format of:
+ * performance GUID HOB.
+ * performance protocol interfaces.
+ * performance variables.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PERFORMANCE_DATA_H__
+#define __PERFORMANCE_DATA_H__
+
+#define PERFORMANCE_PROPERTY_REVISION 0x1
+
+typedef struct {
+ UINT32 Revision;
+ UINT32 Reserved;
+ UINT64 Frequency;
+ UINT64 TimerStartValue;
+ UINT64 TimerEndValue;
+} PERFORMANCE_PROPERTY;
+
+//
+// PEI_PERFORMANCE_STRING_SIZE must be a multiple of 8.
+//
+#define PEI_PERFORMANCE_STRING_SIZE 8
+#define PEI_PERFORMANCE_STRING_LENGTH (PEI_PERFORMANCE_STRING_SIZE - 1)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Handle;
+ CHAR8 Token[PEI_PERFORMANCE_STRING_SIZE]; ///< Measured token string name.
+ CHAR8 Module[PEI_PERFORMANCE_STRING_SIZE]; ///< Module string name.
+ UINT64 StartTimeStamp; ///< Start time point.
+ UINT64 EndTimeStamp; ///< End time point.
+} PEI_PERFORMANCE_LOG_ENTRY;
+
+//
+// The header must be aligned at 8 bytes.
+//
+typedef struct {
+ UINT32 NumberOfEntries; ///< The number of all performance log entries.
+ UINT32 Reserved;
+} PEI_PERFORMANCE_LOG_HEADER;
+
+
+#define PERFORMANCE_PROTOCOL_GUID \
+ { 0x76b6bdfa, 0x2acd, 0x4462, { 0x9E, 0x3F, 0xcb, 0x58, 0xC9, 0x69, 0xd9, 0x37 } }
+
+#define PERFORMANCE_EX_PROTOCOL_GUID \
+ { 0x1ea81bec, 0xf01a, 0x4d98, { 0xa2, 0x1, 0x4a, 0x61, 0xce, 0x2f, 0xc0, 0x22 } }
+
+//
+// Forward reference for pure ANSI compatibility
+//
+typedef struct _PERFORMANCE_PROTOCOL PERFORMANCE_PROTOCOL;
+typedef struct _PERFORMANCE_EX_PROTOCOL PERFORMANCE_EX_PROTOCOL;
+
+//
+// DXE_PERFORMANCE_STRING_SIZE must be a multiple of 8.
+//
+#define DXE_PERFORMANCE_STRING_SIZE 32
+#define DXE_PERFORMANCE_STRING_LENGTH (DXE_PERFORMANCE_STRING_SIZE - 1)
+
+//
+// The default guage entries number for DXE phase.
+//
+#define INIT_DXE_GAUGE_DATA_ENTRIES 800
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Handle;
+ CHAR8 Token[DXE_PERFORMANCE_STRING_SIZE]; ///< Measured token string name.
+ CHAR8 Module[DXE_PERFORMANCE_STRING_SIZE]; ///< Module string name.
+ UINT64 StartTimeStamp; ///< Start time point.
+ UINT64 EndTimeStamp; ///< End time point.
+} GAUGE_DATA_ENTRY;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Handle;
+ CHAR8 Token[DXE_PERFORMANCE_STRING_SIZE]; ///< Measured token string name.
+ CHAR8 Module[DXE_PERFORMANCE_STRING_SIZE]; ///< Module string name.
+ UINT64 StartTimeStamp; ///< Start time point.
+ UINT64 EndTimeStamp; ///< End time point.
+ UINT32 Identifier; ///< Identifier.
+} GAUGE_DATA_ENTRY_EX;
+
+//
+// The header must be aligned at 8 bytes
+//
+typedef struct {
+ UINT32 NumberOfEntries; ///< The number of all performance gauge entries.
+ UINT32 Reserved;
+} GAUGE_DATA_HEADER;
+
+//
+// SMM Performance Protocol definitions
+//
+
+#define SMM_PERFORMANCE_PROTOCOL_GUID \
+ { 0xf866226a, 0xeaa5, 0x4f5a, { 0xa9, 0xa, 0x6c, 0xfb, 0xa5, 0x7c, 0x58, 0x8e } }
+
+#define SMM_PERFORMANCE_EX_PROTOCOL_GUID \
+ { 0x931fc048, 0xc71d, 0x4455, { 0x89, 0x30, 0x47, 0x6, 0x30, 0xe3, 0xe, 0xe5 } }
+
+//
+// SMM_PERFORMANCE_STRING_SIZE.
+//
+#define SMM_PERFORMANCE_STRING_SIZE 32
+#define SMM_PERFORMANCE_STRING_LENGTH (SMM_PERFORMANCE_STRING_SIZE - 1)
+
+//
+// The default guage entries number for SMM phase.
+//
+#define INIT_SMM_GAUGE_DATA_ENTRIES 200
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINTN NumberOfEntries;
+ UINTN LogEntryKey;
+ GAUGE_DATA_ENTRY *GaugeData;
+} SMM_PERF_COMMUNICATE;
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINTN NumberOfEntries;
+ UINTN LogEntryKey;
+ GAUGE_DATA_ENTRY_EX *GaugeDataEx;
+} SMM_PERF_COMMUNICATE_EX;
+
+#define SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER 1
+#define SMM_PERF_FUNCTION_GET_GAUGE_DATA 2
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ The added record contains the Handle, Token, and Module.
+ The end time of the new record is not recorded, so it is set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle The pointer to environment specific context used
+ to identify the component being measured.
+ @param Token The pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module The pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp The 64-bit time stamp.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_START_GAUGE)(
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module, and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle The pointer to environment specific context used
+ to identify the component being measured.
+ @param Token The pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module The pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp The 64-bit time stamp.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_END_GAUGE)(
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
+ and then eliminate the Identifier.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntry stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntry Out parameter for the indirect pointer to the gauge data entry specified by LogEntryKey.
+
+ @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND There is no entry after the measurement referred to by LogEntryKey.
+ @retval EFI_INVALID_PARAMETER The LogEntryKey is not a valid entry, or GaugeDataEntry is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_GET_GAUGE)(
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY **GaugeDataEntry
+ );
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ The added record contains the Handle, Token, Module and Identifier.
+ The end time of the new record is not recorded, so it is set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle The pointer to environment specific context used
+ to identify the component being measured.
+ @param Token The pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module The pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp The 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_START_GAUGE_EX)(
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier, and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle The pointer to environment specific context used
+ to identify the component being measured.
+ @param Token The pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module The pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp The 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_END_GAUGE_EX)(
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
+ and then assign the Identifier with 0.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntryEx stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntryEx Out parameter for the indirect pointer to the extented gauge data entry specified by LogEntryKey.
+
+ @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND There is no entry after the measurement referred to by LogEntryKey.
+ @retval EFI_INVALID_PARAMETER The LogEntryKey is not a valid entry, or GaugeDataEntryEx is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * PERFORMANCE_GET_GAUGE_EX)(
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
+ );
+
+struct _PERFORMANCE_PROTOCOL {
+ PERFORMANCE_START_GAUGE StartGauge;
+ PERFORMANCE_END_GAUGE EndGauge;
+ PERFORMANCE_GET_GAUGE GetGauge;
+};
+
+struct _PERFORMANCE_EX_PROTOCOL {
+ PERFORMANCE_START_GAUGE_EX StartGaugeEx;
+ PERFORMANCE_END_GAUGE_EX EndGaugeEx;
+ PERFORMANCE_GET_GAUGE_EX GetGaugeEx;
+};
+
+extern EFI_GUID gPerformanceProtocolGuid;
+extern EFI_GUID gSmmPerformanceProtocolGuid;
+extern EFI_GUID gPerformanceExProtocolGuid;
+extern EFI_GUID gSmmPerformanceExProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PerformanceMeasurement.h b/roms/edk2/MdeModulePkg/Include/Guid/PerformanceMeasurement.h
new file mode 100644
index 000000000..016f21a86
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PerformanceMeasurement.h
@@ -0,0 +1,72 @@
+/** @file
+
+Performance measurement protocol, allows logging performance data.
+
+Copyright (c) 2017, Microsoft Corporation<BR>
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PERFORMANCE_MEASUREMENT_H_
+#define _PERFORMANCE_MEASUREMENT_H_
+
+//
+// GUID for Performance measurement Protocol
+//
+#define PERFORMANCE_MEASUREMENT_PROTOCOL_GUID \
+ { 0xc85d06be, 0x5f75, 0x48ce, {0xa8, 0x0f, 0x12, 0x36, 0xba, 0x3b, 0x87, 0xb1 } }
+
+#define SMM_PERFORMANCE_MEASUREMENT_PROTOCOL_GUID \
+ { 0xd56b6d73, 0x1a7b, 0x4015, {0x9b, 0xb4, 0x7b, 0x07, 0x17, 0x29, 0xed, 0x24 } }
+
+typedef struct _EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL;
+
+typedef enum {
+ PerfStartEntry, // used in StartPerformanceMeasurement()/StartPerformanceMeasurementEx()
+ // (map to PERF_START/PERF_START_EX)
+ PerfEndEntry, // used in EndPerformanceMeasurement()/EndPerformanceMeasurementEx()
+ // (map to PERF_END/PERF_END_EX)
+ PerfEntry // used in LogPerformanceMeasurement()
+ // (map to other Perf macros except above 4 macros)
+} PERF_MEASUREMENT_ATTRIBUTE;
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *CREATE_PERFORMANCE_MEASUREMENT)(
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 TimeStamp, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ );
+
+struct _EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL {
+ CREATE_PERFORMANCE_MEASUREMENT CreatePerformanceMeasurement;
+};
+
+extern EFI_GUID gEdkiiPerformanceMeasurementProtocolGuid;
+extern EFI_GUID gEdkiiSmmPerformanceMeasurementProtocolGuid;
+
+#endif // _PERFORMANCE_MEASUREMENT_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PiSmmCommunicationRegionTable.h b/roms/edk2/MdeModulePkg/Include/Guid/PiSmmCommunicationRegionTable.h
new file mode 100644
index 000000000..595003bfb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PiSmmCommunicationRegionTable.h
@@ -0,0 +1,57 @@
+/** @file
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_SMM_COMMUNICATION_REGION_TABLE_H_
+#define _PI_SMM_COMMUNICATION_REGION_TABLE_H_
+
+#define EDKII_PI_SMM_COMMUNICATION_REGION_TABLE_GUID {\
+ 0x4e28ca50, 0xd582, 0x44ac, {0xa1, 0x1f, 0xe3, 0xd5, 0x65, 0x26, 0xdb, 0x34} \
+}
+
+//
+// This table to declare the generic SMM communication buffer location.
+// If this table is present, it means the SMM communication buffer is restricted to
+// EfiReservedMemoryType, EfiACPIMemoryNVS, or EfiRuntimeServicesData.
+//
+// This table is installed to UEFI configuration table by generic driver
+// or platform driver, at early DXE phase.
+//
+// The EFI_MEMORY_DESCRIPTOR entry must contain at least one entry.
+// The entries must be normal memory region in EfiReservedMemoryType, EfiACPIMemoryNVS,
+// or EfiRuntimeServicesData.
+// If the Entry.Type is EfiConventionalMemory, it means this entry is free to use.
+// If the Entry.Type is other, it means this entry is occupied.
+//
+// Any non-SMM component may put communication data there, then use
+// UEFI defined SMM Communication ACPI Table, or PI defined EFI_SMM_COMMUNICATION_PROTOCOL
+// to communicate with SMI handler. The process is:
+// 1) Find an entry whose type is EfiConventional.
+// 2) Change type to be EfiReservedMemoryType before use.
+// 3) Use it.
+// 4) Restore type be EfiConventional.
+// The step 2) must be performed as an atomic transaction, if there might be conflict during runtime.
+// For example, on IA-32/x64 platforms, this can be done using the CMPXCHG CPU instruction.
+// If there is guarantee on no conflict during boot time, these steps can be skipped.
+// For example, DXE, UEFI driver and UEFI application runs in sequence.
+//
+// For example, FPDT driver can use this communication buffer to get SMM
+// performance data in SMM. Profile driver can use this communication buffer
+// to get SMM profile data in SMM.
+//
+typedef struct {
+ UINT32 Version;
+ UINT32 NumberOfEntries;
+ UINT32 DescriptorSize;
+ UINT32 Reserved;
+//EFI_MEMORY_DESCRIPTOR Entry[1];
+} EDKII_PI_SMM_COMMUNICATION_REGION_TABLE;
+
+#define EDKII_PI_SMM_COMMUNICATION_REGION_TABLE_VERSION 0x00000001
+
+extern EFI_GUID gEdkiiPiSmmCommunicationRegionTableGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PiSmmMemoryAttributesTable.h b/roms/edk2/MdeModulePkg/Include/Guid/PiSmmMemoryAttributesTable.h
new file mode 100644
index 000000000..63da8e77e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PiSmmMemoryAttributesTable.h
@@ -0,0 +1,45 @@
+/** @file
+ Define the GUID of the EDKII PI SMM memory attribute table, which
+ is published by PI SMM Core.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_SMM_MEMORY_ATTRIBUTES_TABLE_H_
+#define _PI_SMM_MEMORY_ATTRIBUTES_TABLE_H_
+
+#define EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_GUID {\
+ 0x6b9fd3f7, 0x16df, 0x45e8, {0xbd, 0x39, 0xb9, 0x4a, 0x66, 0x54, 0x1a, 0x5d} \
+}
+
+//
+// The PI SMM memory attribute table contains the SMM memory map for SMM image.
+//
+// This table is installed to SMST as SMM configuration table.
+//
+// This table is published at gEfiSmmEndOfDxeProtocolGuid notification, because
+// there should be no more SMM driver loaded after that. The EfiRuntimeServicesCode
+// region should not be changed any more.
+//
+// This table is published, if and only if all SMM PE/COFF have aligned section
+// as specified in UEFI specification Section 2.3. For example, IA32/X64 alignment is 4KiB.
+//
+// If this table is published, the EfiRuntimeServicesCode contains code only
+// and it is EFI_MEMORY_RO; the EfiRuntimeServicesData contains data only
+// and it is EFI_MEMORY_XP.
+//
+typedef struct {
+ UINT32 Version;
+ UINT32 NumberOfEntries;
+ UINT32 DescriptorSize;
+ UINT32 Reserved;
+//EFI_MEMORY_DESCRIPTOR Entry[1];
+} EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE;
+
+#define EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION 0x00000001
+
+extern EFI_GUID gEdkiiPiSmmMemoryAttributesTableGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PlatDriOverrideHii.h b/roms/edk2/MdeModulePkg/Include/Guid/PlatDriOverrideHii.h
new file mode 100644
index 000000000..457f17a7d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PlatDriOverrideHii.h
@@ -0,0 +1,19 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in PlatDriOverride driver.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_DRIVER_OVERRIDE_HII_GUID_H__
+#define __PLATFORM_DRIVER_OVERRIDE_HII_GUID_H__
+
+#define PLAT_OVER_MNGR_GUID \
+ { \
+ 0x8614567d, 0x35be, 0x4415, {0x8d, 0x88, 0xbd, 0x7d, 0xc, 0x9c, 0x70, 0xc0} \
+ }
+
+extern EFI_GUID gPlatformOverridesManagerGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/PlatformHasAcpi.h b/roms/edk2/MdeModulePkg/Include/Guid/PlatformHasAcpi.h
new file mode 100644
index 000000000..1f107abd0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/PlatformHasAcpi.h
@@ -0,0 +1,29 @@
+/** @file
+ EDKII Platform Has ACPI GUID
+
+ A NULL protocol instance with this GUID in the DXE protocol database, and/or
+ a NULL PPI with this GUID in the PPI database, implies that the platform
+ provides the operating system with an ACPI-based hardware description. Note
+ that this is not necessarily exclusive with different kinds of hardware
+ description (for example, a Device Tree-based one). A platform driver and/or
+ PEIM is supposed to produce a single instance of the protocol and/or PPI
+ (with NULL contents), if appropriate.
+
+ Copyright (C) 2017, Red Hat, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+
+#ifndef __EDKII_PLATFORM_HAS_ACPI_H__
+#define __EDKII_PLATFORM_HAS_ACPI_H__
+
+#define EDKII_PLATFORM_HAS_ACPI_GUID \
+ { \
+ 0xf0966b41, 0xc23f, 0x41b9, \
+ { 0x96, 0x04, 0x0f, 0xf7, 0xe1, 0x11, 0x96, 0x5a } \
+ }
+
+extern EFI_GUID gEdkiiPlatformHasAcpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/RamDiskHii.h b/roms/edk2/MdeModulePkg/Include/Guid/RamDiskHii.h
new file mode 100644
index 000000000..69e5badb0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/RamDiskHii.h
@@ -0,0 +1,19 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __RAM_DISK_HII_GUID_H__
+#define __RAM_DISK_HII_GUID_H__
+
+#define RAM_DISK_FORM_SET_GUID \
+ { \
+ 0x2a46715f, 0x3581, 0x4a55, {0x8e, 0x73, 0x2b, 0x76, 0x9a, 0xaa, 0x30, 0xc5} \
+ }
+
+extern EFI_GUID gRamDiskFormSetGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/RecoveryDevice.h b/roms/edk2/MdeModulePkg/Include/Guid/RecoveryDevice.h
new file mode 100644
index 000000000..868fe7076
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/RecoveryDevice.h
@@ -0,0 +1,62 @@
+/** @file
+ Defines Name GUIDs to represent a Recovery Capsule loaded from a recovery device.
+
+ These are contracts between the recovery module and device recovery module
+ that convey the name of a given recovery module type.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RECOVERY_DEVICE_H_
+#define _RECOVERY_DEVICE_H_
+
+///
+/// The Global ID used to identify a recovery capsule that was loaded from a CD/DVD device.
+///
+#define RECOVERY_ON_DATA_CD_GUID \
+ { \
+ 0x5cac0099, 0x0dc9, 0x48e5, {0x80, 0x68, 0xbb, 0x95, 0xf5, 0x40, 0x0a, 0x9f } \
+ }
+
+///
+/// The Global ID used to identify a recovery capsule that was loaded from floppy device.
+///
+#define RECOVERY_ON_FAT_FLOPPY_DISK_GUID \
+ { \
+ 0x2e3d2e75, 0x9b2e, 0x412d, {0xb4, 0xb1, 0x70, 0x41, 0x6b, 0x87, 0x0, 0xff } \
+ }
+
+///
+/// The Global ID used to identify a recovery capsule that was loaded from IDE hard drive.
+///
+#define RECOVERY_ON_FAT_IDE_DISK_GUID \
+ { \
+ 0xb38573b6, 0x6200, 0x4ac5, {0xb5, 0x1d, 0x82, 0xe6, 0x59, 0x38, 0xd7, 0x83 } \
+ }
+
+///
+/// The Global ID used to identify a recovery capsule that was loaded from USB BOT device.
+///
+#define RECOVERY_ON_FAT_USB_DISK_GUID \
+ { \
+ 0x0ffbce19, 0x324c, 0x4690, {0xa0, 0x09, 0x98, 0xc6, 0xae, 0x2e, 0xb1, 0x86 } \
+ }
+
+///
+/// The Global ID used to identify a recovery capsule that was loaded from NVM Express device.
+///
+#define RECOVERY_ON_FAT_NVME_DISK_GUID \
+ { \
+ 0xc770a27f, 0x956a, 0x497a, {0x85, 0x48, 0xe0, 0x61, 0x97, 0x58, 0x8b, 0xf6 } \
+ }
+
+extern EFI_GUID gRecoveryOnDataCdGuid;
+extern EFI_GUID gRecoveryOnFatFloppyDiskGuid;
+extern EFI_GUID gRecoveryOnFatIdeDiskGuid;
+extern EFI_GUID gRecoveryOnFatUsbDiskGuid;
+extern EFI_GUID gRecoveryOnFatNvmeDiskGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/S3SmmInitDone.h b/roms/edk2/MdeModulePkg/Include/Guid/S3SmmInitDone.h
new file mode 100644
index 000000000..f1ad496bc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/S3SmmInitDone.h
@@ -0,0 +1,21 @@
+/** @file
+ After S3 SMM initialization is done and before S3 boot script is executed,
+ this GUID is installed as PPI in PEI and protocol in SMM environment.
+ It allows for PEIMs or SMM drivers to hook this point and do the required tasks.
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __S3_SMM_INIT_DONE_H__
+#define __S3_SMM_INIT_DONE_H__
+
+#define EDKII_S3_SMM_INIT_DONE_GUID \
+ { \
+ 0x8f9d4825, 0x797d, 0x48fc, { 0x84, 0x71, 0x84, 0x50, 0x25, 0x79, 0x2e, 0xf6 } \
+ }
+
+extern EFI_GUID gEdkiiS3SmmInitDoneGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h b/roms/edk2/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h
new file mode 100644
index 000000000..c1bfaa41e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h
@@ -0,0 +1,57 @@
+/** @file
+ Define the LockBox GUID for list of storage devices need to be initialized in
+ S3.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __S3_STORAGE_DEVICE_INIT_LIST_H__
+#define __S3_STORAGE_DEVICE_INIT_LIST_H__
+
+#define S3_STORAGE_DEVICE_INIT_LIST \
+ { \
+ 0x310e9b8c, 0xcf90, 0x421e, { 0x8e, 0x9b, 0x9e, 0xef, 0xb6, 0x17, 0xc8, 0xef } \
+ }
+
+//
+// The LockBox will store a DevicePath structure that contains one or more
+// DevicePath instances. Each instance denotes a storage device that needs to
+// get initialized during the S3 resume.
+//
+// For example, if there is only one storage device stored in the list, the
+// content of this LockBox will be:
+//
+// +-------------------------------------------------------+
+// | DevPath Instance #1 |
+// | (Terminated by an End of Hardware Device Path node |
+// | with an End Entire Device Path sub-type) |
+// +-------------------------------------------------------+
+//
+// If there are n (n > 1) storage devices in the list, the content of this
+// LockBox will be:
+//
+// +-------------------------------------------------------+
+// | DevPath Instance #1 |
+// | (Terminated by an End of Hardware Device Path node |
+// | with an End This Instance of a Device Path sub-type) |
+// +-------------------------------------------------------+
+// | DevPath Instance #2 |
+// | (Terminated by an End of Hardware Device Path node |
+// | with an End This Instance of a Device Path sub-type) |
+// +-------------------------------------------------------+
+// | ... |
+// +-------------------------------------------------------+
+// | DevPath Instance #n |
+// | (Terminated by an End of Hardware Device Path node |
+// | with an End Entire Device Path sub-type) |
+// +-------------------------------------------------------+
+//
+// The attribute of the LockBox should be set to
+// 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY'.
+//
+extern EFI_GUID gS3StorageDeviceInitListGuid;
+
+#endif // __S3_STORAGE_DEVICE_INIT_LIST_H__
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/SerialPortLibVendor.h b/roms/edk2/MdeModulePkg/Include/Guid/SerialPortLibVendor.h
new file mode 100644
index 000000000..887f96c30
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/SerialPortLibVendor.h
@@ -0,0 +1,19 @@
+/** @file
+ Define the SerialDxe GUID.
+
+ Copyright (c) 2019, Citrix Systems, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __SERIAL_PORT_LIB_VENDOR_H__
+#define __SERIAL_PORT_LIB_VENDOR_H__
+
+#define EDKII_SERIAL_PORT_LIB_VENDOR_GUID { \
+ 0xD3987D4B, 0x971A, 0x435F, \
+ { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
+ }
+
+extern EFI_GUID gEdkiiSerialPortLibVendorGuid;
+
+#endif // __SERIAL_PORT_LIB_VENDOR_H__
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/SmiHandlerProfile.h b/roms/edk2/MdeModulePkg/Include/Guid/SmiHandlerProfile.h
new file mode 100644
index 000000000..ff6bddeb5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/SmiHandlerProfile.h
@@ -0,0 +1,211 @@
+/** @file
+ Header file for SMI handler profile definition.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMI_HANDLER_PROFILE_H_
+#define _SMI_HANDLER_PROFILE_H_
+
+#include <PiSmm.h>
+#include <Protocol/SmmGpiDispatch2.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <Protocol/SmmPeriodicTimerDispatch2.h>
+#include <Protocol/SmmPowerButtonDispatch2.h>
+#include <Protocol/SmmStandbyButtonDispatch2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmUsbDispatch2.h>
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 Length;
+ UINT32 Revision;
+ UINT8 Reserved[4];
+} SMM_CORE_DATABASE_COMMON_HEADER;
+
+#define SMM_CORE_IMAGE_DATABASE_SIGNATURE SIGNATURE_32 ('S','C','I','D')
+#define SMM_CORE_IMAGE_DATABASE_REVISION 0x0001
+
+typedef struct {
+ SMM_CORE_DATABASE_COMMON_HEADER Header;
+ EFI_GUID FileGuid;
+ PHYSICAL_ADDRESS EntryPoint;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINT32 ImageRef;
+ UINT16 PdbStringOffset;
+ UINT8 Reserved[2];
+//CHAR8 PdbString[];
+} SMM_CORE_IMAGE_DATABASE_STRUCTURE;
+
+#define SMM_CORE_SMI_DATABASE_SIGNATURE SIGNATURE_32 ('S','C','S','D')
+#define SMM_CORE_SMI_DATABASE_REVISION 0x0001
+
+typedef enum {
+ SmmCoreSmiHandlerCategoryRootHandler,
+ SmmCoreSmiHandlerCategoryGuidHandler,
+ SmmCoreSmiHandlerCategoryHardwareHandler,
+} SMM_CORE_SMI_HANDLER_CATEGORY;
+
+//
+// Context for SmmCoreSmiHandlerCategoryRootHandler:
+// NULL
+// Context for SmmCoreSmiHandlerCategoryGuidHandler:
+// NULL
+// Context for SmmCoreSmiHandlerCategoryHardwareHandler:
+// (NOTE: The context field should NOT include any data pointer.)
+// gEfiSmmSwDispatch2ProtocolGuid: (EFI_SMM_SW_REGISTER_CONTEXT => SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT)
+// gEfiSmmSxDispatch2ProtocolGuid: EFI_SMM_SX_REGISTER_CONTEXT
+// gEfiSmmPowerButtonDispatch2ProtocolGuid: EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT
+// gEfiSmmStandbyButtonDispatch2ProtocolGuid: EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT
+// gEfiSmmPeriodicTimerDispatch2ProtocolGuid: EFI_SMM_PERIODIC_TIMER_CONTEXT
+// gEfiSmmGpiDispatch2ProtocolGuid: EFI_SMM_GPI_REGISTER_CONTEXT
+// gEfiSmmIoTrapDispatch2ProtocolGuid: EFI_SMM_IO_TRAP_REGISTER_CONTEXT
+// gEfiSmmUsbDispatch2ProtocolGuid: (EFI_SMM_USB_REGISTER_CONTEXT => SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT)
+// Other: GUID specific
+
+typedef struct {
+ EFI_USB_SMI_TYPE Type;
+ UINT32 DevicePathSize;
+//UINT8 DevicePath[DevicePathSize];
+} SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT;
+
+typedef struct {
+ UINT64 SwSmiInputValue;
+} SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT;
+
+typedef struct {
+ UINT32 Length;
+ UINT32 ImageRef;
+ PHYSICAL_ADDRESS CallerAddr;
+ PHYSICAL_ADDRESS Handler;
+ UINT16 ContextBufferOffset;
+ UINT8 Reserved[2];
+ UINT32 ContextBufferSize;
+//UINT8 ContextBuffer[];
+} SMM_CORE_SMI_HANDLER_STRUCTURE;
+
+typedef struct {
+ SMM_CORE_DATABASE_COMMON_HEADER Header;
+ EFI_GUID HandlerType;
+ UINT32 HandlerCategory;
+ UINT32 HandlerCount;
+//SMM_CORE_SMI_HANDLER_STRUCTURE Handler[HandlerCount];
+} SMM_CORE_SMI_DATABASE_STRUCTURE;
+
+//
+// Layout:
+// +-------------------------------------+
+// | SMM_CORE_IMAGE_DATABASE_STRUCTURE |
+// +-------------------------------------+
+// | SMM_CORE_SMI_DATABASE_STRUCTURE |
+// +-------------------------------------+
+//
+
+
+
+//
+// SMM_CORE dump command
+//
+#define SMI_HANDLER_PROFILE_COMMAND_GET_INFO 0x1
+#define SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET 0x2
+
+typedef struct {
+ UINT32 Command;
+ UINT32 DataLength;
+ UINT64 ReturnStatus;
+} SMI_HANDLER_PROFILE_PARAMETER_HEADER;
+
+typedef struct {
+ SMI_HANDLER_PROFILE_PARAMETER_HEADER Header;
+ UINT64 DataSize;
+} SMI_HANDLER_PROFILE_PARAMETER_GET_INFO;
+
+typedef struct {
+ SMI_HANDLER_PROFILE_PARAMETER_HEADER Header;
+ //
+ // On input, data buffer size.
+ // On output, actual data buffer size copied.
+ //
+ UINT64 DataSize;
+ PHYSICAL_ADDRESS DataBuffer;
+ //
+ // On input, data buffer offset to copy.
+ // On output, next time data buffer offset to copy.
+ //
+ UINT64 DataOffset;
+} SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET;
+
+#define SMI_HANDLER_PROFILE_GUID {0x49174342, 0x7108, 0x409b, {0x8b, 0xbe, 0x65, 0xfd, 0xa8, 0x53, 0x89, 0xf5}}
+
+extern EFI_GUID gSmiHandlerProfileGuid;
+
+typedef struct _SMI_HANDLER_PROFILE_PROTOCOL SMI_HANDLER_PROFILE_PROTOCOL;
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ a new SMI handler is registered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param CallerAddress The address of the module who registers the SMI handler.
+ @param Context The context of the SMI handler.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+ @param ContextSize The size of the context in bytes.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+
+ @retval EFI_SUCCESS The information is recorded.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMI_HANDLER_PROFILE_REGISTER_HANDLER) (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ );
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ an existing SMI handler is unregistered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param Context The context of the SMI handler.
+ If it is NOT NULL, it will be used to check what is registered.
+ @param ContextSize The size of the context in bytes.
+ If Context is NOT NULL, it will be used to check what is registered.
+
+ @retval EFI_SUCCESS The original record is removed.
+ @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMI_HANDLER_PROFILE_UNREGISTER_HANDLER) (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ );
+
+struct _SMI_HANDLER_PROFILE_PROTOCOL {
+ SMI_HANDLER_PROFILE_REGISTER_HANDLER RegisterHandler;
+ SMI_HANDLER_PROFILE_UNREGISTER_HANDLER UnregisterHandler;
+};
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/SmmLockBox.h b/roms/edk2/MdeModulePkg/Include/Guid/SmmLockBox.h
new file mode 100644
index 000000000..0297ba93c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/SmmLockBox.h
@@ -0,0 +1,66 @@
+/** @file
+ SmmLockBox guid header file.
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_LOCK_BOX_GUID_H_
+#define _SMM_LOCK_BOX_GUID_H_
+
+#define EFI_SMM_LOCK_BOX_COMMUNICATION_GUID \
+ {0x2a3cfebd, 0x27e8, 0x4d0a, {0x8b, 0x79, 0xd6, 0x88, 0xc2, 0xa3, 0xe1, 0xc0}}
+
+//
+// Below data structure is used for communication between PEI/DXE to SMM.
+//
+
+#define EFI_SMM_LOCK_BOX_COMMAND_SAVE 0x1
+#define EFI_SMM_LOCK_BOX_COMMAND_UPDATE 0x2
+#define EFI_SMM_LOCK_BOX_COMMAND_RESTORE 0x3
+#define EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES 0x4
+#define EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE 0x5
+
+typedef struct {
+ UINT32 Command;
+ UINT32 DataLength;
+ UINT64 ReturnStatus;
+} EFI_SMM_LOCK_BOX_PARAMETER_HEADER;
+
+typedef struct {
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER Header;
+ GUID Guid;
+ PHYSICAL_ADDRESS Buffer;
+ UINT64 Length;
+} EFI_SMM_LOCK_BOX_PARAMETER_SAVE;
+
+typedef struct {
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER Header;
+ GUID Guid;
+ UINT64 Offset;
+ PHYSICAL_ADDRESS Buffer;
+ UINT64 Length;
+} EFI_SMM_LOCK_BOX_PARAMETER_UPDATE;
+
+typedef struct {
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER Header;
+ GUID Guid;
+ PHYSICAL_ADDRESS Buffer;
+ UINT64 Length;
+} EFI_SMM_LOCK_BOX_PARAMETER_RESTORE;
+
+typedef struct {
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER Header;
+ GUID Guid;
+ UINT64 Attributes;
+} EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES;
+
+typedef struct {
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER Header;
+} EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE;
+
+extern EFI_GUID gEfiSmmLockBoxCommunicationGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/SmmVariableCommon.h b/roms/edk2/MdeModulePkg/Include/Guid/SmmVariableCommon.h
new file mode 100644
index 000000000..8ddc94b92
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/SmmVariableCommon.h
@@ -0,0 +1,150 @@
+/** @file
+ The file defined some common structures used for communicating between SMM variable module and SMM variable wrapper module.
+
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_VARIABLE_COMMON_H_
+#define _SMM_VARIABLE_COMMON_H_
+
+#include <Guid/VariableFormat.h>
+#include <Protocol/VarCheck.h>
+
+#define EFI_SMM_VARIABLE_WRITE_GUID \
+ { 0x93ba1826, 0xdffb, 0x45dd, { 0x82, 0xa7, 0xe7, 0xdc, 0xaa, 0x3b, 0xbd, 0xf3 } }
+
+extern EFI_GUID gSmmVariableWriteGuid;
+
+//
+// This structure is used for SMM variable. the collected statistics data is saved in SMRAM. It can be got from
+// SMI handler. The communication buffer should be:
+// EFI_MM_COMMUNICATE_HEADER + SMM_VARIABLE_COMMUNICATE_HEADER + payload.
+//
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINT8 Data[1];
+} SMM_VARIABLE_COMMUNICATE_HEADER;
+
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.
+//
+#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME.
+//
+#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.
+//
+#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO.
+//
+#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4
+//
+// It is a notify event, no extra payload for this function.
+//
+#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5
+//
+// It is a notify event, no extra payload for this function.
+//
+#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6
+//
+// The payload for this function is VARIABLE_INFO_ENTRY. The GUID in EFI_MM_COMMUNICATE_HEADER
+// is gEfiSmmVariableProtocolGuid.
+//
+#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
+//
+#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8
+
+#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET 9
+
+#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10
+
+#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
+//
+#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12
+
+#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13
+//
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
+//
+#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14
+
+///
+/// Size of SMM communicate header, without including the payload.
+///
+#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data))
+
+///
+/// Size of SMM variable communicate header, without including the payload.
+///
+#define SMM_VARIABLE_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data))
+
+///
+/// This structure is used to communicate with SMI handler by SetVariable and GetVariable.
+///
+typedef struct {
+ EFI_GUID Guid;
+ UINTN DataSize;
+ UINTN NameSize;
+ UINT32 Attributes;
+ CHAR16 Name[1];
+} SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE;
+
+///
+/// This structure is used to communicate with SMI handler by GetNextVariableName.
+///
+typedef struct {
+ EFI_GUID Guid;
+ UINTN NameSize; // Return name buffer size
+ CHAR16 Name[1];
+} SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME;
+
+///
+/// This structure is used to communicate with SMI handler by QueryVariableInfo.
+///
+typedef struct {
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINT32 Attributes;
+} SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO;
+
+typedef SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE;
+
+typedef struct {
+ EFI_GUID Guid;
+ UINTN NameSize;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+ CHAR16 Name[1];
+} SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY;
+
+typedef struct {
+ UINTN VariablePayloadSize;
+} SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE;
+
+typedef struct {
+ BOOLEAN *ReadLock;
+ BOOLEAN *PendingUpdate;
+ BOOLEAN *HobFlushComplete;
+ VARIABLE_STORE_HEADER *RuntimeHobCache;
+ VARIABLE_STORE_HEADER *RuntimeNvCache;
+ VARIABLE_STORE_HEADER *RuntimeVolatileCache;
+} SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT;
+
+typedef struct {
+ UINTN TotalHobStorageSize;
+ UINTN TotalNvStorageSize;
+ UINTN TotalVolatileStorageSize;
+ BOOLEAN AuthenticatedVariableUsage;
+} SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO;
+
+#endif // _SMM_VARIABLE_COMMON_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/StandardErrorDevice.h b/roms/edk2/MdeModulePkg/Include/Guid/StandardErrorDevice.h
new file mode 100644
index 000000000..c15a00e71
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/StandardErrorDevice.h
@@ -0,0 +1,18 @@
+/** @file
+ This GUID is installed to the device handler to specify that the device is a StdErr device.
+
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __STANDARD_ERROR_DEVICE_H__
+#define __STANDARD_ERROR_DEVICE_H__
+
+#define EFI_STANDARD_ERROR_DEVICE_GUID \
+ { 0xd3b36f2d, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
+
+extern EFI_GUID gEfiStandardErrorDeviceGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeCallbackGuid.h b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeCallbackGuid.h
new file mode 100644
index 000000000..6730a0090
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeCallbackGuid.h
@@ -0,0 +1,20 @@
+/** @file
+ GUID used to identify HOB for pointers to callback functios registered on
+ PEI report status code router.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __STATUS_CODE_CALLBACK_H__
+#define __STATUS_CODE_CALLBACK_H__
+
+#define STATUS_CODE_CALLBACK_GUID \
+ { \
+ 0xe701458c, 0x4900, 0x4ca5, {0xb7, 0x72, 0x3d, 0x37, 0x94, 0x9f, 0x79, 0x27} \
+ }
+
+extern EFI_GUID gStatusCodeCallbackGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeDebug.h b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeDebug.h
new file mode 100644
index 000000000..e511c2d61
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeDebug.h
@@ -0,0 +1,43 @@
+/** @file
+ This file defines the GUID and data structure used to pass DEBUG() macro
+ information to the Status Code Protocol and Status Code PPI.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _STATUS_CODE_DATA_TYPE_DEBUG_H_
+#define _STATUS_CODE_DATA_TYPE_DEBUG_H_
+
+///
+/// The Global ID used to identify a structure of type EFI_DEBUG_INFO.
+///
+#define EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID \
+ { \
+ 0x9A4E9246, 0xD553, 0x11D5, { 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xb9 } \
+ }
+
+///
+/// The maximum size of an EFI_DEBUG_INFO structure.
+///
+#define EFI_STATUS_CODE_DATA_MAX_SIZE 200
+
+///
+/// This structure contains the ErrorLevel passed into the DEBUG() macro, followed
+/// by a 96-byte buffer that contains the variable argument list passed to the
+/// DEBUG() macro that has been converted to a BASE_LIST. The 96-byte buffer is
+/// followed by a Null-terminated ASCII string that is the Format string passed
+/// to the DEBUG() macro. The maximum size of this structure is defined by
+/// EFI_STATUS_CODE_DATA_MAX_SIZE.
+///
+typedef struct {
+ ///
+ /// The debug error level passed into a DEBUG() macro.
+ ///
+ UINT32 ErrorLevel;
+} EFI_DEBUG_INFO;
+
+extern EFI_GUID gEfiStatusCodeDataTypeDebugGuid;
+
+#endif // _STATUS_CODE_DATA_TYPE_DEBUG_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeVariable.h b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeVariable.h
new file mode 100644
index 000000000..466307002
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/StatusCodeDataTypeVariable.h
@@ -0,0 +1,34 @@
+/** @file
+ This file defines the GUID and data structure used to pass variable setting
+ failure information to the Status Code Protocol.
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _STATUS_CODE_DATA_TYPE_VARIABLE_H_
+#define _STATUS_CODE_DATA_TYPE_VARIABLE_H_
+
+///
+/// The Global ID used to identify a structure of type EDKII_SET_VARIABLE_STATUS.
+/// The status code value is PcdGet32 (PcdErrorCodeSetVariable).
+///
+#define EDKII_STATUS_CODE_DATA_TYPE_VARIABLE_GUID \
+ { \
+ 0xf6ee6dbb, 0xd67f, 0x4ea0, { 0x8b, 0x96, 0x6a, 0x71, 0xb1, 0x9d, 0x84, 0xad } \
+ }
+
+typedef struct {
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN DataSize;
+ EFI_STATUS SetStatus;
+ UINT32 Attributes;
+ // CHAR16 Name[];
+ // UINT8 Data[];
+} EDKII_SET_VARIABLE_STATUS;
+
+extern EFI_GUID gEdkiiStatusCodeDataTypeVariableGuid;
+
+#endif // _STATUS_CODE_DATA_TYPE_VARIABLE_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/SystemNvDataGuid.h b/roms/edk2/MdeModulePkg/Include/Guid/SystemNvDataGuid.h
new file mode 100644
index 000000000..57b457bfa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/SystemNvDataGuid.h
@@ -0,0 +1,111 @@
+/** @file
+ This file defines NvDataFv GUID and FTW working block structures.
+ The NvDataFv GUID can be used as FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER if
+ this FV image contains NV data, such as NV variable data.
+ This file also defines WorkingBlockSignature GUID for FTW working block signature.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SYSTEM_NV_DATA_GUID_H__
+#define __SYSTEM_NV_DATA_GUID_H__
+
+#define EFI_SYSTEM_NV_DATA_FV_GUID \
+ {0xfff12b8d, 0x7696, 0x4c8b, {0xa9, 0x85, 0x27, 0x47, 0x7, 0x5b, 0x4f, 0x50} }
+
+#define EDKII_WORKING_BLOCK_SIGNATURE_GUID \
+ {0x9e58292b, 0x7c68, 0x497d, {0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95} }
+
+extern EFI_GUID gEfiSystemNvDataFvGuid;
+extern EFI_GUID gEdkiiWorkingBlockSignatureGuid;
+
+#define WORKING_BLOCK_VALID 0x1
+#define WORKING_BLOCK_INVALID 0x2
+
+///
+/// The EDKII Fault tolerant working block header.
+/// The header is immediately followed by the write queue data.
+///
+typedef struct {
+ ///
+ /// FTW working block signature.
+ /// Its value has be updated from gEfiSystemNvDataFvGuid to gEdkiiWorkingBlockSignatureGuid,
+ /// because its write queue data format has been updated to support the crossing archs.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// 32bit CRC calculated for this header.
+ ///
+ UINT32 Crc;
+ ///
+ /// Working block valid bit.
+ ///
+ UINT8 WorkingBlockValid : 1;
+ UINT8 WorkingBlockInvalid : 1;
+ UINT8 Reserved : 6;
+ UINT8 Reserved3[3];
+ ///
+ /// Total size of the following write queue range.
+ ///
+ UINT64 WriteQueueSize;
+ ///
+ /// Write Queue data.
+ ///
+ /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader;
+ /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord[FtwHeader.NumberOfWrites]
+ /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader2;
+ /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord2[FtwHeader2.NumberOfWrites]
+ /// ...
+ ///
+} EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER;
+
+#define FTW_VALID_STATE 0
+#define FTW_INVALID_STATE 1
+
+//
+// EFI Fault tolerant block update write queue entry.
+//
+typedef struct {
+ UINT8 HeaderAllocated : 1;
+ UINT8 WritesAllocated : 1;
+ UINT8 Complete : 1;
+ UINT8 Reserved : 5;
+ EFI_GUID CallerId;
+ UINT64 NumberOfWrites;
+ UINT64 PrivateDataSize;
+} EFI_FAULT_TOLERANT_WRITE_HEADER;
+
+//
+// EFI Fault tolerant block update write queue record.
+//
+typedef struct {
+ UINT8 BootBlockUpdate : 1;
+ UINT8 SpareComplete : 1;
+ UINT8 DestinationComplete : 1;
+ UINT8 Reserved : 5;
+ EFI_LBA Lba;
+ UINT64 Offset;
+ UINT64 Length;
+ //
+ // Relative offset to spare block.
+ //
+ INT64 RelativeOffset;
+ //
+ // UINT8 PrivateData[PrivateDataSize]
+ //
+} EFI_FAULT_TOLERANT_WRITE_RECORD;
+
+#define FTW_RECORD_SIZE(PrivateDataSize) (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize)
+
+#define FTW_RECORD_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \
+ ((UINTN) (NumberOfWrites) * (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize))
+
+#define FTW_WRITE_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \
+ ( \
+ sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + (UINTN) (NumberOfWrites) * \
+ (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize) \
+ )
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/TtyTerm.h b/roms/edk2/MdeModulePkg/Include/Guid/TtyTerm.h
new file mode 100644
index 000000000..a87c1e8b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/TtyTerm.h
@@ -0,0 +1,36 @@
+/** @file
+GUID definition for TtyTerm terminal type. The TtyTerm terminal aims to
+provide support for modern *nix terminals.
+
+
+Copyright (c) 2015 Linaro Ltd.
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TTYTERM_H__
+#define __TTYTERM_H__
+
+#define EFI_TTY_TERM_GUID \
+ {0x7d916d80, 0x5bb1, 0x458c, {0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94 } }
+
+#define EDKII_LINUX_TERM_GUID \
+ {0xe4364a7f, 0xf825, 0x430e, {0x9d, 0x3a, 0x9c, 0x9b, 0xe6, 0x81, 0x7c, 0xa5 } }
+
+#define EDKII_XTERM_R6_GUID \
+ {0xfbfca56b, 0xbb36, 0x4b78, {0xaa, 0xab, 0xbe, 0x1b, 0x97, 0xec, 0x7c, 0xcb } }
+
+#define EDKII_VT400_GUID \
+ {0x8e46dddd, 0x3d49, 0x4a9d, {0xb8, 0x75, 0x3c, 0x08, 0x6f, 0x6a, 0xa2, 0xbd } }
+
+#define EDKII_SCO_TERM_GUID \
+ {0xfc7dd6e0, 0x813c, 0x434d, {0xb4, 0xda, 0x3b, 0xd6, 0x49, 0xe9, 0xe1, 0x5a } }
+
+extern EFI_GUID gEfiTtyTermGuid;
+extern EFI_GUID gEdkiiLinuxTermGuid;
+extern EFI_GUID gEdkiiXtermR6Guid;
+extern EFI_GUID gEdkiiVT400Guid;
+extern EFI_GUID gEdkiiSCOTermGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/UsbKeyBoardLayout.h b/roms/edk2/MdeModulePkg/Include/Guid/UsbKeyBoardLayout.h
new file mode 100644
index 000000000..c43f0656e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/UsbKeyBoardLayout.h
@@ -0,0 +1,31 @@
+/** @file
+ USB KeyBoard Layout GUIDs
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB_KEYBOARD_LAYOUT_GUID_H__
+#define __USB_KEYBOARD_LAYOUT_GUID_H__
+
+//
+// GUID for USB keyboard HII package list.
+//
+#define USB_KEYBOARD_LAYOUT_PACKAGE_GUID \
+ { \
+ 0xc0f3b43, 0x44de, 0x4907, { 0xb4, 0x78, 0x22, 0x5f, 0x6f, 0x62, 0x89, 0xdc } \
+ }
+
+//
+// GUID for USB keyboard layout
+//
+#define USB_KEYBOARD_LAYOUT_KEY_GUID \
+ { \
+ 0x3a4d7a7c, 0x18a, 0x4b42, { 0x81, 0xb3, 0xdc, 0x10, 0xe3, 0xb5, 0x91, 0xbd } \
+ }
+
+extern EFI_GUID gUsbKeyboardLayoutPackageGuid;
+extern EFI_GUID gUsbKeyboardLayoutKeyGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/VarErrorFlag.h b/roms/edk2/MdeModulePkg/Include/Guid/VarErrorFlag.h
new file mode 100644
index 000000000..cc12222ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/VarErrorFlag.h
@@ -0,0 +1,35 @@
+/** @file
+ Variable error flag definitions.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_ERROR_FLAG_H_
+#define _VARIABLE_ERROR_FLAG_H_
+
+//
+// Before EndOfDxe, the variable indicates the last boot variable error flag,
+// then it means the last boot variable error flag must be got before EndOfDxe.
+// After EndOfDxe, the variable indicates the current boot variable error flag,
+// then it means the current boot variable error flag must be got after EndOfDxe.
+//
+// If the variable is not present, it has the same meaning with VAR_ERROR_FLAG_NO_ERROR.
+//
+#define VAR_ERROR_FLAG_NAME L"VarErrorFlag"
+
+#define VAR_ERROR_FLAG_NO_ERROR 0xFF // 1111-1111
+#define VAR_ERROR_FLAG_SYSTEM_ERROR 0xEF // 1110-1111
+#define VAR_ERROR_FLAG_USER_ERROR 0xFE // 1111-1110
+
+typedef UINT8 VAR_ERROR_FLAG;
+
+#define EDKII_VAR_ERROR_FLAG_GUID { \
+ 0x4b37fe8, 0xf6ae, 0x480b, { 0xbd, 0xd5, 0x37, 0xd9, 0x8c, 0x5e, 0x89, 0xaa } \
+};
+
+extern EFI_GUID gEdkiiVarErrorFlagGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/VariableFormat.h b/roms/edk2/MdeModulePkg/Include/Guid/VariableFormat.h
new file mode 100644
index 000000000..a5574fe82
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/VariableFormat.h
@@ -0,0 +1,221 @@
+/** @file
+ The variable data structures are related to EDK II-specific implementation of UEFI variables.
+ VariableFormat.h defines variable data headers and variable storage region headers.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_FORMAT_H__
+#define __VARIABLE_FORMAT_H__
+
+#define EFI_VARIABLE_GUID \
+ { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }
+
+#define EFI_AUTHENTICATED_VARIABLE_GUID \
+ { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+extern EFI_GUID gEfiVariableGuid;
+extern EFI_GUID gEfiAuthenticatedVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1.
+///
+#define ALIGNMENT 1
+
+//
+// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+//
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region.
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region.
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+#define AUTHENTICATED_VARIABLE_STORE_SIGNATURE EFI_AUTHENTICATED_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State.
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header.
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags.
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition.
+#define VAR_DELETED 0xfd ///< Variable is obsolete.
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid.
+#define VAR_ADDED 0x3f ///< Variable has been completely added.
+
+///
+/// Variable Attribute combinations.
+///
+#define VARIABLE_ATTRIBUTE_NV_BS (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
+#define VARIABLE_ATTRIBUTE_BS_RT (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)
+#define VARIABLE_ATTRIBUTE_BS_RT_AT (VARIABLE_ATTRIBUTE_BS_RT | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+#define VARIABLE_ATTRIBUTE_NV_BS_RT (VARIABLE_ATTRIBUTE_BS_RT | EFI_VARIABLE_NON_VOLATILE)
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_HR (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_AT (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+#define VARIABLE_ATTRIBUTE_AT EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_HR_AT (VARIABLE_ATTRIBUTE_NV_BS_RT_HR | VARIABLE_ATTRIBUTE_AT)
+///
+/// EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated and should be considered as reserved
+///
+#define VARIABLE_ATTRIBUTE_AT_AW (EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_AW (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_HR_AT_AW (VARIABLE_ATTRIBUTE_NV_BS_RT_HR | VARIABLE_ATTRIBUTE_AT_AW)
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI specification.
+ ///
+ UINT32 Attributes;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+///
+/// Single Authenticated Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI specification.
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Associated TimeStamp value against replay attack.
+ ///
+ EFI_TIME TimeStamp;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} AUTHENTICATED_VARIABLE_HEADER;
+
+typedef struct {
+ EFI_GUID *Guid;
+ CHAR16 *Name;
+ UINTN VariableSize;
+} VARIABLE_ENTRY_CONSISTENCY;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI specification.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/VariableIndexTable.h b/roms/edk2/MdeModulePkg/Include/Guid/VariableIndexTable.h
new file mode 100644
index 000000000..5d6123330
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/VariableIndexTable.h
@@ -0,0 +1,41 @@
+/** @file
+ The variable data structures are related to EDK II-specific implementation of UEFI variables.
+ VariableFormat.h defines variable data headers and variable storage region headers.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_INDEX_TABLE_H__
+#define __VARIABLE_INDEX_TABLE_H__
+
+typedef struct {
+ VARIABLE_HEADER *CurrPtr;
+ VARIABLE_HEADER *EndPtr;
+ VARIABLE_HEADER *StartPtr;
+} VARIABLE_POINTER_TRACK;
+
+#define VARIABLE_INDEX_TABLE_VOLUME 122
+
+#define EFI_VARIABLE_INDEX_TABLE_GUID \
+ { 0x8cfdb8c8, 0xd6b2, 0x40f3, { 0x8e, 0x97, 0x02, 0x30, 0x7c, 0xc9, 0x8b, 0x7c } }
+
+extern EFI_GUID gEfiVariableIndexTableGuid;
+
+///
+/// Use this data structure to store variable-related info, which can decrease
+/// the cost of access to NV.
+///
+typedef struct {
+ UINT16 Length;
+ UINT16 GoneThrough;
+ VARIABLE_HEADER *EndPtr;
+ VARIABLE_HEADER *StartPtr;
+ ///
+ /// This field is used to store the distance of two neighbouring VAR_ADDED type variables.
+ /// The meaning of the field is implement-dependent.
+ UINT16 Index[VARIABLE_INDEX_TABLE_VOLUME];
+} VARIABLE_INDEX_TABLE;
+
+#endif // __VARIABLE_INDEX_TABLE_H__
diff --git a/roms/edk2/MdeModulePkg/Include/Guid/ZeroGuid.h b/roms/edk2/MdeModulePkg/Include/Guid/ZeroGuid.h
new file mode 100644
index 000000000..a3b31ed70
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Guid/ZeroGuid.h
@@ -0,0 +1,19 @@
+/** @file
+ GUID has all zero values.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __ZERO_GUID_H__
+#define __ZERO_GUID_H__
+
+#define ZERO_GUID \
+ { \
+ 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} \
+ }
+
+extern EFI_GUID gZeroGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/AuthVariableLib.h b/roms/edk2/MdeModulePkg/Include/Library/AuthVariableLib.h
new file mode 100644
index 000000000..76a8c8bd5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/AuthVariableLib.h
@@ -0,0 +1,254 @@
+/** @file
+ Provides services to initialize and process authenticated variables.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AUTH_VARIABLE_LIB_H_
+#define _AUTH_VARIABLE_LIB_H_
+
+#include <Protocol/VarCheck.h>
+
+///
+/// Size of AuthInfo prior to the data payload.
+///
+#define AUTHINFO_SIZE ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
+ sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))
+
+#define AUTHINFO2_SIZE(VarAuth2) ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
+ (UINTN) ((EFI_VARIABLE_AUTHENTICATION_2 *) (VarAuth2))->AuthInfo.Hdr.dwLength)
+
+#define OFFSET_OF_AUTHINFO2_CERT_DATA ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+ UINT32 Attributes;
+ UINTN DataSize;
+ VOID *Data;
+ UINT32 PubKeyIndex;
+ UINT64 MonotonicCount;
+ EFI_TIME *TimeStamp;
+} AUTH_VARIABLE_INFO;
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the variable found.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *AUTH_VAR_LIB_FIND_VARIABLE) (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the next variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *AUTH_VAR_LIB_FIND_NEXT_VARIABLE) (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *AUTH_VAR_LIB_UPDATE_VARIABLE) (
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Get scratch buffer.
+
+ @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+ the maximum supported buffer size, this value contains
+ the maximum supported buffer size as output.
+ @param[out] ScratchBuffer Pointer to scratch buffer address.
+
+ @retval EFI_SUCCESS Get scratch buffer successfully.
+ @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *AUTH_VAR_LIB_GET_SCRATCH_BUFFER) (
+ IN OUT UINTN *ScratchBufferSize,
+ OUT VOID **ScratchBuffer
+ );
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *AUTH_VAR_LIB_CHECK_REMAINING_SPACE) (
+ IN UINT32 Attributes,
+ ...
+ );
+
+/**
+ Return TRUE if at OS runtime.
+
+ @retval TRUE If at OS runtime.
+ @retval FALSE If at boot time.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *AUTH_VAR_LIB_AT_RUNTIME) (
+ VOID
+ );
+
+#define AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION 0x01
+
+typedef struct {
+ UINTN StructVersion;
+ UINTN StructSize;
+ //
+ // Reflect the overhead associated with the saving
+ // of a single EFI authenticated variable with the exception
+ // of the overhead associated with the length
+ // of the string name of the EFI variable.
+ //
+ UINTN MaxAuthVariableSize;
+ AUTH_VAR_LIB_FIND_VARIABLE FindVariable;
+ AUTH_VAR_LIB_FIND_NEXT_VARIABLE FindNextVariable;
+ AUTH_VAR_LIB_UPDATE_VARIABLE UpdateVariable;
+ AUTH_VAR_LIB_GET_SCRATCH_BUFFER GetScratchBuffer;
+ AUTH_VAR_LIB_CHECK_REMAINING_SPACE CheckRemainingSpaceForConsistency;
+ AUTH_VAR_LIB_AT_RUNTIME AtRuntime;
+} AUTH_VAR_LIB_CONTEXT_IN;
+
+#define AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION 0x01
+
+typedef struct {
+ UINTN StructVersion;
+ UINTN StructSize;
+ //
+ // Caller needs to set variable property for the variables.
+ //
+ VARIABLE_ENTRY_PROPERTY *AuthVarEntry;
+ UINTN AuthVarEntryCount;
+ //
+ // Caller needs to ConvertPointer() for the pointers.
+ //
+ VOID ***AddressPointer;
+ UINTN AddressPointerCount;
+} AUTH_VAR_LIB_CONTEXT_OUT;
+
+/**
+ Initialization for authenticated varibale services.
+ If this initialization returns error status, other APIs will not work
+ and expect to be not called then.
+
+ @param[in] AuthVarLibContextIn Pointer to input auth variable lib context.
+ @param[out] AuthVarLibContextOut Pointer to output auth variable lib context.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibInitialize (
+ IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn,
+ OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut
+ );
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/BmpSupportLib.h b/roms/edk2/MdeModulePkg/Include/Library/BmpSupportLib.h
new file mode 100644
index 000000000..3f1f4beae
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/BmpSupportLib.h
@@ -0,0 +1,89 @@
+/** @file
+
+Provides services to convert a BMP graphics image to a GOP BLT buffer
+and to convert a GOP BLT buffer to a BMP graphics image.
+
+Copyright (c) 2016, Microsoft Corporation
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __BMP_SUPPORT_LIB_H__
+#define __BMP_SUPPORT_LIB_H__
+
+#include <Protocol/GraphicsOutput.h>
+
+/**
+ Translate 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 using
+ EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be
+ used if it is big enough.
+
+ @param [in] BmpImage Pointer to BMP file.
+ @param [in] BmpImageSize Number of bytes in BmpImage.
+ @param [in, out] GopBlt Buffer containing GOP version of BmpImage.
+ @param [in, out] GopBltSize Size of GopBlt in bytes.
+ @param [out] PixelHeight Height of GopBlt/BmpImage in pixels.
+ @param [out] PixelWidth Width of GopBlt/BmpImage in pixels.
+
+ @retval RETURN_SUCCESS GopBlt and GopBltSize are returned.
+ @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
+ @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
+ @retval RETURN_INVALID_PARAMETER GopBltSize is NULL.
+ @retval RETURN_INVALID_PARAMETER PixelHeight is NULL.
+ @retval RETURN_INVALID_PARAMETER PixelWidth is NULL.
+ @retval RETURN_UNSUPPORTED BmpImage is not a valid *.BMP image.
+ @retval RETURN_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big
+ enough. The required size is returned in
+ GopBltSize.
+ @retval RETURN_OUT_OF_RESOURCES The GopBlt buffer could not be allocated.
+
+**/
+RETURN_STATUS
+EFIAPI
+TranslateBmpToGopBlt (
+ IN VOID *BmpImage,
+ IN UINTN BmpImageSize,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt,
+ IN OUT UINTN *GopBltSize,
+ OUT UINTN *PixelHeight,
+ OUT UINTN *PixelWidth
+ );
+
+/**
+ Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics
+ image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by
+ this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is
+ passed in it will be used if it is big enough.
+
+ @param [in] GopBlt Pointer to GOP blt buffer.
+ @param [in] PixelHeight Height of GopBlt/BmpImage in pixels.
+ @param [in] PixelWidth Width of GopBlt/BmpImage in pixels.
+ @param [in, out] BmpImage Buffer containing BMP version of GopBlt.
+ @param [in, out] BmpImageSize Size of BmpImage in bytes.
+
+ @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned.
+ @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
+ @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
+ @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL.
+ @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image.
+ @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big
+ enough. The required size is returned in
+ BmpImageSize.
+ @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated.
+
+**/
+RETURN_STATUS
+EFIAPI
+TranslateGopBltToBmp (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt,
+ IN UINT32 PixelHeight,
+ IN UINT32 PixelWidth,
+ IN OUT VOID **BmpImage,
+ IN OUT UINT32 *BmpImageSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/BootLogoLib.h b/roms/edk2/MdeModulePkg/Include/Library/BootLogoLib.h
new file mode 100644
index 000000000..afd895b25
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/BootLogoLib.h
@@ -0,0 +1,64 @@
+/** @file
+ This library is only intended to be used by PlatformBootManagerLib
+ to show progress bar and LOGO.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_LOGO_LIB_H_
+#define _BOOT_LOGO_LIB_H_
+
+#include <Protocol/PlatformLogo.h>
+#include <Protocol/GraphicsOutput.h>
+
+/**
+ Show LOGO returned from Edkii Platform Logo protocol on all consoles.
+**/
+EFI_STATUS
+EFIAPI
+BootLogoEnableLogo (
+ VOID
+ );
+
+
+/**
+ 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
+BootLogoDisableLogo (
+ VOID
+ );
+
+/**
+
+ Update 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 Successly update the progress bar
+
+**/
+EFI_STATUS
+EFIAPI
+BootLogoUpdateProgress (
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/CapsuleLib.h b/roms/edk2/MdeModulePkg/Include/Library/CapsuleLib.h
new file mode 100644
index 000000000..0f4164257
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/CapsuleLib.h
@@ -0,0 +1,160 @@
+/** @file
+
+ This library class defines a set of interfaces for how to process capsule image updates.
+
+Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CAPSULE_LIB_H__
+#define __CAPSULE_LIB_H__
+
+//
+// BOOLEAN Variable to indicate whether system is in the capsule on disk state.
+//
+#define COD_RELOCATION_INFO_VAR_NAME L"CodRelocationInfo"
+
+/**
+ The firmware checks whether the capsule image is supported
+ by the CapsuleGuid in CapsuleHeader or if there is other specific information in
+ the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param CapsuleHeader Pointer to the UEFI capsule image to be checked.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ The firmware-specific implementation processes the capsule image
+ if it recognized the format of this capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param CapsuleHeader Pointer to the UEFI capsule image to be processed.
+
+ @retval EFI_SUCESS Capsule Image processed successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+
+ This routine is called to process capsules.
+
+ Caution: This function may receive untrusted input.
+
+ The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+ If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
+
+ This routine should be called twice in BDS.
+ 1) The first call must be before EndOfDxe. The system capsules is processed.
+ If device capsule FMP protocols are exposted at this time and device FMP
+ capsule has zero EmbeddedDriverCount, the device capsules are processed.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule and
+ all capsules are processed.
+ If not all capsules are processed, reset will be defered to second call.
+
+ 2) The second call must be after EndOfDxe and after ConnectAll, so that all
+ device capsule FMP protocols are exposed.
+ The system capsules are skipped. If the device capsules are NOT processed
+ in first call, they are processed here.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule
+ processed in first call and second call.
+
+ @retval EFI_SUCCESS There is no error when processing capsules.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+ VOID
+ );
+
+/**
+ This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
+ is enabled.
+
+ @retval TRUE Flag is enabled
+ @retval FALSE Flag is not enabled
+
+**/
+BOOLEAN
+EFIAPI
+CoDCheckCapsuleOnDiskFlag(
+ VOID
+ );
+
+/**
+ This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
+
+ @retval EFI_SUCCESS All Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+EFIAPI
+CoDClearCapsuleOnDiskFlag(
+ VOID
+ );
+
+/**
+ Relocate Capsule on Disk from EFI system partition.
+
+ Two solution to deliver Capsule On Disk:
+ Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
+ Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
+ device with BlockIo protocol.
+
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
+ Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
+ systems of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRelocateCapsule(
+ UINTN MaxRetry
+ );
+
+/**
+ Remove the temp file from the root of EFI System Partition.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Remove the temp file successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRemoveTempFile (
+ UINTN MaxRetry
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/CpuExceptionHandlerLib.h b/roms/edk2/MdeModulePkg/Include/Library/CpuExceptionHandlerLib.h
new file mode 100644
index 000000000..2c18dacf5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/CpuExceptionHandlerLib.h
@@ -0,0 +1,200 @@
+/** @file
+ CPU Exception library provides the default CPU interrupt/exception handler.
+ It also provides capability to register user interrupt/exception handler.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CPU_EXCEPTION_HANDLER_LIB_H__
+#define __CPU_EXCEPTION_HANDLER_LIB_H__
+
+#include <Ppi/VectorHandoffInfo.h>
+#include <Protocol/Cpu.h>
+
+#define CPU_EXCEPTION_INIT_DATA_REV 1
+
+typedef union {
+ struct {
+ //
+ // Revision number of this structure.
+ //
+ UINT32 Revision;
+ //
+ // The address of top of known good stack reserved for *ALL* exceptions
+ // listed in field StackSwitchExceptions.
+ //
+ UINTN KnownGoodStackTop;
+ //
+ // The size of known good stack for *ONE* exception only.
+ //
+ UINTN KnownGoodStackSize;
+ //
+ // Buffer of exception vector list for stack switch.
+ //
+ UINT8 *StackSwitchExceptions;
+ //
+ // Number of exception vectors in StackSwitchExceptions.
+ //
+ UINTN StackSwitchExceptionNumber;
+ //
+ // Buffer of IDT table. It must be type of IA32_IDT_GATE_DESCRIPTOR.
+ // Normally there's no need to change IDT table size.
+ //
+ VOID *IdtTable;
+ //
+ // Size of buffer for IdtTable.
+ //
+ UINTN IdtTableSize;
+ //
+ // Buffer of GDT table. It must be type of IA32_SEGMENT_DESCRIPTOR.
+ //
+ VOID *GdtTable;
+ //
+ // Size of buffer for GdtTable.
+ //
+ UINTN GdtTableSize;
+ //
+ // Pointer to start address of descriptor of exception task gate in the
+ // GDT table. It must be type of IA32_TSS_DESCRIPTOR.
+ //
+ VOID *ExceptionTssDesc;
+ //
+ // Size of buffer for ExceptionTssDesc.
+ //
+ UINTN ExceptionTssDescSize;
+ //
+ // Buffer of task-state segment for exceptions. It must be type of
+ // IA32_TASK_STATE_SEGMENT.
+ //
+ VOID *ExceptionTss;
+ //
+ // Size of buffer for ExceptionTss.
+ //
+ UINTN ExceptionTssSize;
+ //
+ // Flag to indicate if default handlers should be initialized or not.
+ //
+ BOOLEAN InitDefaultHandlers;
+ } Ia32, X64;
+} CPU_EXCEPTION_INIT_DATA;
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ );
+
+/**
+ Initializes all CPU exceptions entries with optional extra initializations.
+
+ By default, this method should include all functionalities implemented by
+ InitializeCpuExceptionHandlers(), plus extra initialization works, if any.
+ This could be done by calling InitializeCpuExceptionHandlers() directly
+ in this method besides the extra works.
+
+ InitData is optional and its use and content are processor arch dependent.
+ The typical usage of it is to convey resources which have to be reserved
+ elsewhere and are necessary for the extra initializations of exception.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data optional for extra initializations
+ of exception.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ );
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ );
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+/**
+ Display processor context.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Processor context to be display.
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/CustomizedDisplayLib.h b/roms/edk2/MdeModulePkg/Include/Library/CustomizedDisplayLib.h
new file mode 100644
index 000000000..b9ae15524
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/CustomizedDisplayLib.h
@@ -0,0 +1,350 @@
+/** @file
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CUSTOMIZED_DISPLAY_LIB_H__
+#define __CUSTOMIZED_DISPLAY_LIB_H__
+
+#include <Protocol/DisplayProtocol.h>
+
+/**
++------------------------------------------------------------------------------+
+| Setup Page |
++------------------------------------------------------------------------------+
+
+Statement
+Statement
+Statement
+
+
+
+
+
++------------------------------------------------------------------------------+
+| F9=Reset to Defaults F10=Save |
+| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Exit |
++------------------------------------------------------------------------------+
+ StatusBar
+**/
+
+/**
+ This funtion defines Page Frame and Backgroud.
+
+ Based on the above layout, it will be responsible for HeaderHeight, FooterHeight,
+ StatusBarHeight and Backgroud. And, it will reserve Screen for Statement.
+
+ @param[in] FormData Form Data to be shown in Page.
+ @param[out] ScreenForStatement Screen to be used for Statement. (Prompt, Value and Help)
+
+ @return Status
+**/
+EFI_STATUS
+EFIAPI
+DisplayPageFrame (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT EFI_SCREEN_DESCRIPTOR *ScreenForStatement
+ );
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+ClearDisplayPage (
+ VOID
+ );
+
+/**
+ This function updates customized key panel's help information.
+ The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-.
+ and arrange them in Footer panel.
+
+ @param[in] FormData Form Data to be shown in Page. FormData has the highlighted statement.
+ @param[in] Statement The statement current selected.
+ @param[in] Selected Whether or not a tag be selected. TRUE means Enter has hit this question.
+**/
+VOID
+EFIAPI
+RefreshKeyHelp (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN BOOLEAN Selected
+ );
+
+/**
+ Update status bar.
+
+ This function updates the status bar on the bottom of menu screen. It just shows StatusBar.
+ Original logic in this function should be splitted out.
+
+ @param[in] MessageType The type of message to be shown. InputError or Configuration Changed.
+ @param[in] State Show or Clear Message.
+**/
+VOID
+EFIAPI
+UpdateStatusBar (
+ IN UINTN MessageType,
+ IN BOOLEAN State
+ );
+
+/**
+ Create popup window.
+
+ This function draws OEM/Vendor specific pop up windows.
+
+ @param[out] Key User Input Key
+ @param ... String to be shown in Popup. The variable argument list is terminated by a NULL.
+
+**/
+VOID
+EFIAPI
+CreateDialog (
+ OUT EFI_INPUT_KEY *Key, OPTIONAL
+ ...
+ );
+
+/**
+ Confirm how to handle the changed data.
+
+ @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.
+**/
+UINTN
+EFIAPI
+ConfirmDataChange (
+ VOID
+ );
+
+/**
+ OEM specifies whether Setup exits Page by ESC key.
+
+ This function customized the behavior that whether Setup exits Page so that
+ system able to boot when configuration is not changed.
+
+ @retval TRUE Exits FrontPage
+ @retval FALSE Don't exit FrontPage.
+**/
+BOOLEAN
+EFIAPI
+FormExitPolicy (
+ VOID
+ );
+
+/**
+ Set Timeout value for a ceratain Form to get user response.
+
+ This function allows to set timeout value on a ceratain form if necessary.
+ If timeout is not zero, the form will exit if user has no response in timeout.
+
+ @param[in] FormData Form Data to be shown in Page
+
+ @return 0 No timeout for this form.
+ @return > 0 Timeout value in 100 ns units.
+**/
+UINT64
+EFIAPI
+FormExitTimeout (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+//
+// Print Functions
+//
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String
+ );
+
+
+/**
+ Prints a unicode string with the specified width to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+ @param Width Width for String to be printed. If the print length of String < Width,
+ Space char (L' ') will be used to append String.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAtWithWidth (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String,
+ IN UINTN Width
+ );
+
+/**
+ Prints a character to the default console, at
+ the supplied cursor position, using L"%c" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param Character Character to print.
+
+ @return Length of string printed to the console.
+
+**/
+UINTN
+EFIAPI
+PrintCharAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ CHAR16 Character
+ );
+
+/**
+ Clear retangle with specified text attribute.
+
+ @param LeftColumn Left column of retangle.
+ @param RightColumn Right column of retangle.
+ @param TopRow Start row of retangle.
+ @param BottomRow End row of retangle.
+ @param TextAttribute The character foreground and background.
+
+**/
+VOID
+EFIAPI
+ClearLines (
+ IN UINTN LeftColumn,
+ IN UINTN RightColumn,
+ IN UINTN TopRow,
+ IN UINTN BottomRow,
+ IN UINTN TextAttribute
+ );
+
+//
+// Color Setting Functions
+//
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup color.
+**/
+UINT8
+EFIAPI
+GetPopupColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup inverse color.
+**/
+UINT8
+EFIAPI
+GetPopupInverseColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific PickList color attribute.
+
+ @retval Byte code color setting for pick list color.
+**/
+UINT8
+EFIAPI
+GetPickListColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific arrow color attribute.
+
+ @retval Byte code color setting for arrow color.
+**/
+UINT8
+EFIAPI
+GetArrowColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific info text color attribute.
+
+ @retval Byte code color setting for info text color.
+**/
+UINT8
+EFIAPI
+GetInfoTextColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific help text color attribute.
+
+ @retval Byte code color setting for help text color.
+**/
+UINT8
+EFIAPI
+GetHelpTextColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific grayed out text color attribute.
+
+ @retval Byte code color setting for grayed out text color.
+**/
+UINT8
+EFIAPI
+GetGrayedTextColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific highlighted text color attribute.
+
+ @retval Byte code color setting for highlight text color.
+**/
+UINT8
+EFIAPI
+GetHighlightTextColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific field text color attribute.
+
+ @retval Byte code color setting for field text color.
+**/
+UINT8
+EFIAPI
+GetFieldTextColor (
+ VOID
+ );
+
+/**
+ Get OEM/Vendor specific subtitle text color attribute.
+
+ @retval Byte code color setting for subtitle text color.
+**/
+UINT8
+EFIAPI
+GetSubTitleTextColor (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/DebugAgentLib.h b/roms/edk2/MdeModulePkg/Include/Library/DebugAgentLib.h
new file mode 100644
index 000000000..b0c5de39e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/DebugAgentLib.h
@@ -0,0 +1,97 @@
+/** @file
+ Debug Agent Library provide source-level debug capability.
+
+Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DEBUG_AGENT_LIB_H__
+#define __DEBUG_AGENT_LIB_H__
+
+#define DEBUG_AGENT_INIT_PREMEM_SEC 1
+#define DEBUG_AGENT_INIT_POSTMEM_SEC 2
+#define DEBUG_AGENT_INIT_DXE_CORE 3
+#define DEBUG_AGENT_INIT_SMM 4
+#define DEBUG_AGENT_INIT_ENTER_SMI 5
+#define DEBUG_AGENT_INIT_EXIT_SMI 6
+#define DEBUG_AGENT_INIT_S3 7
+#define DEBUG_AGENT_INIT_DXE_AP 8
+#define DEBUG_AGENT_INIT_PEI 9
+#define DEBUG_AGENT_INIT_DXE_LOAD 10
+#define DEBUG_AGENT_INIT_DXE_UNLOAD 11
+#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64 12
+
+//
+// Context for DEBUG_AGENT_INIT_POSTMEM_SEC
+//
+typedef struct {
+ UINTN HeapMigrateOffset;
+ UINTN StackMigrateOffset;
+} DEBUG_AGENT_CONTEXT_POSTMEM_SEC;
+
+/**
+ Caller provided function to be invoked at the end of InitializeDebugAgent().
+
+ Refer to the description for InitializeDebugAgent() for more details.
+
+ @param[in] Context The first input parameter of InitializeDebugAgent().
+
+**/
+typedef
+VOID
+(EFIAPI * DEBUG_AGENT_CONTINUE)(
+ IN VOID *Context
+ );
+
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment to support source level debugging.
+ If certain Debug Agent Library instance has to save some private data in the stack,
+ this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
+ function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
+ responsible to invoke the passing-in function at the end of InitializeDebugAgent().
+
+ If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
+ passing in the Context to be its parameter.
+
+ If Function() is NULL, Debug Agent Library instance will return after setup debug
+ environment.
+
+ @param[in] InitFlag Init flag is used to decide the initialize process.
+ @param[in] Context Context needed according to InitFlag; it was optional.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ );
+
+/**
+ Enable/Disable the interrupt of debug timer and return the interrupt state
+ prior to the operation.
+
+ If EnableStatus is TRUE, enable the interrupt of debug timer.
+ If EnableStatus is FALSE, disable the interrupt of debug timer.
+
+ @param[in] EnableStatus Enable/Disable.
+
+ @retval TRUE Debug timer interrupt were enabled on entry to this call.
+ @retval FALSE Debug timer interrupt were disabled on entry to this call.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt (
+ IN BOOLEAN EnableStatus
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/DisplayUpdateProgressLib.h b/roms/edk2/MdeModulePkg/Include/Library/DisplayUpdateProgressLib.h
new file mode 100644
index 000000000..bb2624138
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/DisplayUpdateProgressLib.h
@@ -0,0 +1,48 @@
+/** @file
+ Provides services to display completion progress when processing a
+ firmware update that updates the firmware image in a firmware device.
+ A platform may provide its own instance of this library class to custoimize
+ how a user is informed of completion progress.
+
+ Copyright (c) 2016, Microsoft Corporation
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DISPLAY_PROGRESS_LIB__
+#define __DISPLAY_PROGRESS_LIB__
+
+#include <Protocol/GraphicsOutput.h>
+
+/**
+ Indicates the current completion progress of a firmware update.
+
+ @param[in] Completion A value between 0 and 100 indicating the current
+ completion progress of a firmware update. This
+ value must the the same or higher than previous
+ calls to this service. The first call of 0 or a
+ value of 0 after reaching a value of 100 resets
+ the progress indicator to 0.
+ @param[in] Color Color of the progress indicator. Only used when
+ Completion is 0 to set the color of the progress
+ indicator. If Color is NULL, then the default color
+ is used.
+
+ @retval EFI_SUCCESS Progress displayed successfully.
+ @retval EFI_INVALID_PARAMETER Completion is not in range 0..100.
+ @retval EFI_INVALID_PARAMETER Completion is less than Completion value from
+ a previous call to this service.
+ @retval EFI_NOT_READY The device used to indicate progress is not
+ available.
+**/
+EFI_STATUS
+EFIAPI
+DisplayUpdateProgress (
+ IN UINTN Completion,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/FileExplorerLib.h b/roms/edk2/MdeModulePkg/Include/Library/FileExplorerLib.h
new file mode 100644
index 000000000..75523d4c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/FileExplorerLib.h
@@ -0,0 +1,41 @@
+/** @file
+
+ This library class defines a set of interfaces for how to do file explorer.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FILE_EXPLORER_LIB_H__
+#define __FILE_EXPLORER_LIB_H__
+
+#include <Protocol/FileExplorer.h>
+
+/**
+ Choose a file in the specified directory.
+
+ If user input NULL for the RootDirectory, will choose file in the system.
+
+ If user input *File != NULL, function will return the allocate device path
+ info for the choosed file, caller has to free the memory after use it.
+
+ @param RootDirectory Pointer to the root directory.
+ @param FileType The file type need to choose.
+ @param ChooseHandler Function pointer to the extra task need to do
+ after choose one file.
+ @param File Return the device path for the last time chosed file.
+
+ @retval EFI_SUCESS Choose the file success.
+ @retval Other errors Choose the file failed.
+**/
+EFI_STATUS
+EFIAPI
+ChooseFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
+ IN CHAR16 *FileType, OPTIONAL
+ IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
+ OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/FmpAuthenticationLib.h b/roms/edk2/MdeModulePkg/Include/Library/FmpAuthenticationLib.h
new file mode 100644
index 000000000..480e6a101
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/FmpAuthenticationLib.h
@@ -0,0 +1,60 @@
+/** @file
+ FMP capsule authenitcation Library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __FMP_AUTHENTICATION_LIB_H__
+#define __FMP_AUTHENTICATION_LIB_H__
+
+#include <Protocol/FirmwareManagement.h>
+
+/**
+ The function is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION,
+ followed by the payload.
+
+ If the return status is RETURN_SUCCESS, the caller may continue the rest
+ FMP update process.
+ If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP
+ update process and convert the return status to LastAttemptStatus
+ to indicate that FMP update fails.
+ The LastAttemptStatus can be got from ESRT table or via
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo().
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED Image or ImageSize is invalid.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+EFIAPI
+AuthenticateFmpImage (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Library/FrameBufferBltLib.h b/roms/edk2/MdeModulePkg/Include/Library/FrameBufferBltLib.h
new file mode 100644
index 000000000..689aeebf1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/FrameBufferBltLib.h
@@ -0,0 +1,87 @@
+/** @file
+ Library for performing UEFI GOP Blt operations on a framebuffer
+
+ Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FRAMEBUFFER_BLT_LIB__
+#define __FRAMEBUFFER_BLT_LIB__
+
+#include <Protocol/GraphicsOutput.h>
+
+//
+// Opaque structure for the frame buffer configure.
+//
+typedef struct FRAME_BUFFER_CONFIGURE FRAME_BUFFER_CONFIGURE;
+
+/**
+ Create the configuration for a video frame buffer.
+
+ The configuration is returned in the caller provided buffer.
+
+ @param[in] FrameBuffer Pointer to the start of the frame buffer.
+ @param[in] FrameBufferInfo Describes the frame buffer characteristics.
+ @param[in,out] Configure The created configuration information.
+ @param[in,out] ConfigureSize Size of the configuration information.
+
+ @retval RETURN_SUCCESS The configuration was successful created.
+ @retval RETURN_BUFFER_TOO_SMALL The Configure is to too small. The required
+ size is returned in ConfigureSize.
+ @retval RETURN_UNSUPPORTED The requested mode is not supported by
+ this implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+FrameBufferBltConfigure (
+ IN VOID *FrameBuffer,
+ IN EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo,
+ IN OUT FRAME_BUFFER_CONFIGURE *Configure,
+ IN OUT UINTN *ConfigureSize
+ );
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt operation.
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[in,out] BltBuffer The data to transfer to screen.
+ @param[in] BltOperation The operation to perform.
+ @param[in] SourceX The X coordinate of the source for BltOperation.
+ @param[in] SourceY The Y coordinate of the source for BltOperation.
+ @param[in] DestinationX The X coordinate of the destination for
+ BltOperation.
+ @param[in] DestinationY The Y coordinate of the destination for
+ BltOperation.
+ @param[in] Width The width of a rectangle in the blt rectangle
+ in pixels.
+ @param[in] Height The height of a rectangle in the blt rectangle
+ in pixels.
+ @param[in] 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 RETURN_INVALID_PARAMETER Invalid parameter were passed in.
+ @retval RETURN_SUCCESS The Blt operation was performed successfully.
+**/
+RETURN_STATUS
+EFIAPI
+FrameBufferBlt (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ IN OUT 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/HiiLib.h b/roms/edk2/MdeModulePkg/Include/Library/HiiLib.h
new file mode 100644
index 000000000..c475cb74a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/HiiLib.h
@@ -0,0 +1,1113 @@
+/** @file
+ Public include file for the HII Library
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HII_LIB_H__
+#define __HII_LIB_H__
+
+////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////
+// HiiLib Functions
+////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////
+
+/**
+ Registers a list of packages in the HII Database and returns the HII Handle
+ associated with that registration. If an HII Handle has already been registered
+ with the same PackageListGuid and DeviceHandle, then NULL is returned. If there
+ are not enough resources to perform the registration, then NULL is returned.
+ If an empty list of packages is passed in, then NULL is returned. If the size of
+ the list of package is 0, then NULL is returned.
+
+ The variable arguments are pointers that point to package headers defined
+ by UEFI VFR compiler and StringGather tool.
+
+ #pragma pack (push, 1)
+ typedef struct {
+ UINT32 BinaryLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ } EDKII_AUTOGEN_PACKAGES_HEADER;
+ #pragma pack (pop)
+
+ @param[in] PackageListGuid The GUID of the package list.
+ @param[in] DeviceHandle If not NULL, the Device Handle on which
+ an instance of DEVICE_PATH_PROTOCOL is installed.
+ This Device Handle uniquely defines the device that
+ the added packages are associated with.
+ @param[in] ... The variable argument list that contains pointers
+ to packages terminated by a NULL.
+
+ @retval NULL An HII Handle has already been registered in the HII Database with
+ the same PackageListGuid and DeviceHandle.
+ @retval NULL The HII Handle could not be created.
+ @retval NULL An empty list of packages was passed in.
+ @retval NULL All packages are empty.
+ @retval Other The HII Handle associated with the newly registered package list.
+
+**/
+EFI_HII_HANDLE
+EFIAPI
+HiiAddPackages (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_HANDLE DeviceHandle OPTIONAL,
+ ...
+ )
+;
+
+/**
+ Removes a package list from the HII database.
+
+ If HiiHandle is NULL, then ASSERT().
+ If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT().
+
+ @param[in] HiiHandle The handle that was previously registered in the HII database
+
+**/
+VOID
+EFIAPI
+HiiRemovePackages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+;
+
+/**
+ This function creates a new string in String Package or updates an existing
+ string in a String Package. If StringId is 0, then a new string is added to
+ a String Package. If StringId is not zero, then a string in String Package is
+ updated. If SupportedLanguages is NULL, then the string is added or updated
+ for all the languages that the String Package supports. If SupportedLanguages
+ is not NULL, then the string is added or updated for the set of languages
+ specified by SupportedLanguages.
+
+ If HiiHandle is NULL, then ASSERT().
+ If String is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the
+ HII Database.
+ @param[in] StringId If zero, then a new string is created in the
+ String Package associated with HiiHandle. If
+ non-zero, then the string specified by StringId
+ is updated in the String Package associated
+ with HiiHandle.
+ @param[in] String A pointer to the Null-terminated Unicode string
+ to add or update in the String Package associated
+ with HiiHandle.
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string of
+ language codes. If this parameter is NULL, then
+ String is added or updated in the String Package
+ associated with HiiHandle for all the languages
+ that the String Package supports. If this
+ parameter is not NULL, then String is added
+ or updated in the String Package associated with
+ HiiHandle for the set of languages specified by
+ SupportedLanguages. The format of
+ SupportedLanguages must follow the language
+ format assumed in the HII Database.
+
+ @retval 0 The string could not be added or updated in the String Package.
+ @retval Other The EFI_STRING_ID of the newly added or updated string.
+
+**/
+EFI_STRING_ID
+EFIAPI
+HiiSetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST CHAR8 *SupportedLanguages OPTIONAL
+ )
+;
+
+/**
+ Retrieves a string from a string package in a specific language. If the language
+ is not specified, then a string from a string package in the current platform
+ language is retrieved. If the string cannot be retrieved using the specified
+ language or the current platform language, then the string is retrieved from
+ the string package in the first language the string package supports. The
+ returned string is allocated using AllocatePool(). The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+ @param[in] Language The language of the string to retrieve. If this parameter
+ is NULL, then the current platform language is used. The
+ format of Language must follow the language format assumed in
+ the HII Database.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+;
+
+/**
+ Retrieves a string from a string package named by GUID, in the specified language.
+ If the language is not specified, then a string from a string package in the
+ current platform language is retrieved. If the string cannot be retrieved
+ using the specified language or the current platform language, then the string
+ is retrieved from the string package in the first language the string package
+ supports. The returned string is allocated using AllocatePool(). The caller
+ is responsible for freeing the allocated buffer using FreePool().
+
+ If PackageListGuid is NULL, then ASSERT().
+ If StringId is 0, then ASSERT().
+
+ @param[in] PackageListGuid The GUID of a package list that was previously
+ registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the
+ string package associated with PackageListGuid.
+ @param[in] Language The language of the string to retrieve. If this
+ parameter is NULL, then the current platform
+ language is used. The format of Language must
+ follow the language format assumed in the HII Database.
+
+ @retval NULL The package list specified by PackageListGuid is not present in the
+ HII Database.
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetPackageString (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+;
+
+/**
+ Retrieves the array of all the HII Handles or the HII handles of a specific
+ package list GUID in the HII Database.
+ This array is terminated with a NULL HII Handle.
+ This function allocates the returned array using AllocatePool().
+ The caller is responsible for freeing the array with FreePool().
+
+ @param[in] PackageListGuid An optional parameter that is used to request
+ HII Handles associated with a specific
+ Package List GUID. If this parameter is NULL,
+ then all the HII Handles in the HII Database
+ are returned. If this parameter is not NULL,
+ then zero or more HII Handles associated with
+ PackageListGuid are returned.
+
+ @retval NULL No HII handles were found in the HII database
+ @retval NULL The array of HII Handles could not be retrieved
+ @retval Other A pointer to the NULL terminated array of HII Handles
+
+**/
+EFI_HII_HANDLE *
+EFIAPI
+HiiGetHiiHandles (
+ IN CONST EFI_GUID *PackageListGuid OPTIONAL
+ )
+;
+
+/**
+ This function allows a caller to extract the form set opcode form the Hii Handle.
+ The returned buffer is allocated using AllocatePool().The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ @param Handle The HII handle.
+ @param Buffer On return, points to a pointer which point to the buffer that contain the formset opcode.
+ @param BufferSize On return, points to the length of the buffer.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
+ @retval EFI_NOT_FOUND Can't find the package data for the input Handle.
+ @retval EFI_INVALID_PARAMETER The input parameters are not correct.
+ @retval EFI_SUCCESS Get the formset opcode from the hii handle successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetFormSetFromHiiHandle(
+ IN EFI_HII_HANDLE Handle,
+ OUT EFI_IFR_FORM_SET **Buffer,
+ OUT UINTN *BufferSize
+ );
+
+/**
+ Retrieves a pointer to a Null-terminated ASCII string containing the list
+ of languages that an HII handle in the HII Database supports. The returned
+ string is allocated using AllocatePool(). The caller is responsible for freeing
+ the returned string using FreePool(). The format of the returned string follows
+ the language format assumed in the HII Database.
+
+ If HiiHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+
+ @retval NULL HiiHandle is not registered in the HII database
+ @retval NULL There are not enough resources available to retrieve the supported
+ languages.
+ @retval NULL The list of supported languages could not be retrieved.
+ @retval Other A pointer to the Null-terminated ASCII string of supported languages.
+
+**/
+CHAR8 *
+EFIAPI
+HiiGetSupportedLanguages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+;
+
+/**
+ Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
+ information that includes a GUID, an optional Unicode string name, and a device
+ path. The string returned is allocated with AllocatePool(). The caller is
+ responsible for freeing the allocated string with FreePool().
+
+ The format of a <ConfigHdr> is as follows:
+
+ GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
+
+ @param[in] Guid The pointer to an EFI_GUID that is the routing information
+ GUID. Each of the 16 bytes in Guid is converted to
+ a 2 Unicode character hexadecimal string. This is
+ an optional parameter that may be NULL.
+ @param[in] Name The pointer to a Null-terminated Unicode string that is
+ the routing information NAME. This is an optional
+ parameter that may be NULL. Each 16-bit Unicode
+ character in Name is converted to a 4 character Unicode
+ hexadecimal string.
+ @param[in] DriverHandle The driver handle that supports a Device Path Protocol
+ that is the routing information PATH. Each byte of
+ the Device Path associated with DriverHandle is converted
+ to a two (Unicode) character hexadecimal string.
+
+ @retval NULL DriverHandle does not support the Device Path Protocol.
+ @retval NULL DriverHandle does not support the Device Path Protocol.
+ @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
+
+**/
+EFI_STRING
+EFIAPI
+HiiConstructConfigHdr (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name, OPTIONAL
+ IN EFI_HANDLE DriverHandle
+ );
+
+/**
+ Reset the default value specified by DefaultId to the driver
+ configuration specified by the Request string.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all configurations for the
+ entirety of the current HII database will be reset.
+ @param DefaultId Specifies the type of defaults to retrieve.
+
+ @retval TRUE The default value was set successfully.
+ @retval FALSE The default value was not found.
+**/
+BOOLEAN
+EFIAPI
+HiiSetToDefaults (
+ IN CONST EFI_STRING Request, OPTIONAL
+ IN UINT16 DefaultId
+ );
+
+/**
+ Validate the current configuration by parsing the IFR opcode in HII form.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in the UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all current configurations for the
+ entirety of the current HII database will be validated.
+
+ @retval TRUE The current configuration is valid.
+ @retval FALSE The current configuration is invalid.
+**/
+BOOLEAN
+EFIAPI
+HiiValidateSettings (
+ IN CONST EFI_STRING Request OPTIONAL
+ );
+
+/**
+ Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
+
+ If ConfigHdr is NULL, then ASSERT().
+
+ @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
+ @param[in] Guid The GUID of the storage.
+ @param[in] Name The NAME of the storage.
+
+ @retval TRUE Routing information matches <ConfigHdr>.
+ @retval FALSE Routing information does not match <ConfigHdr>.
+
+**/
+BOOLEAN
+EFIAPI
+HiiIsConfigHdrMatch (
+ IN CONST EFI_STRING ConfigHdr,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name OPTIONAL
+ );
+
+/**
+ Retrieves uncommitted data from the Form Browser and converts it to a binary
+ buffer.
+
+ @param[in] VariableGuid The pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName The pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize The length in bytes of buffer to hold retrieved data.
+ @param[out] Buffer The buffer of data to be updated.
+
+ @retval FALSE The uncommitted data could not be retrieved.
+ @retval TRUE The uncommitted data was retrieved.
+
+**/
+BOOLEAN
+EFIAPI
+HiiGetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Updates uncommitted data in the Form Browser.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param[in] VariableGuid The pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName The pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize The length, in bytes, of Buffer.
+ @param[in] Buffer The buffer of data to commit.
+ @param[in] RequestElement An optional field to specify which part of the
+ buffer data will be send back to Browser. If NULL,
+ the whole buffer of data will be committed to
+ Browser.
+ <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
+
+ @retval FALSE The uncommitted data could not be updated.
+ @retval TRUE The uncommitted data was updated.
+
+**/
+BOOLEAN
+EFIAPI
+HiiSetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ IN CONST UINT8 *Buffer,
+ IN CONST CHAR16 *RequestElement OPTIONAL
+ );
+
+/////////////////////////////////////////
+/////////////////////////////////////////
+/// IFR Functions
+/////////////////////////////////////////
+/////////////////////////////////////////
+
+/**
+ Returns a UINT64 value that contains bitfields for Hour, Minute, and Second.
+ The lower 8-bits of Hour are placed in bits 0..7. The lower 8-bits of Minute
+ are placed in bits 8..15, and the lower 8-bits of Second are placed in bits
+ 16..23. This format was selected because it can be easily translated to
+ an EFI_HII_TIME structure in an EFI_IFR_TYPE_VALUE union.
+
+ @param Hour The hour value to be encoded.
+ @param Minute The minute value to be encoded.
+ @param Second The second value to be encoded.
+
+ @return A 64-bit containing Hour, Minute, and Second.
+**/
+#define EFI_HII_TIME_UINT64(Hour, Minute, Second) \
+ (UINT64)((Hour & 0xff) | ((Minute & 0xff) << 8) | ((Second & 0xff) << 16))
+
+/**
+ Returns a UINT64 value that contains bit fields for Year, Month, and Day.
+ The lower 16-bits of Year are placed in bits 0..15. The lower 8-bits of Month
+ are placed in bits 16..23, and the lower 8-bits of Day are placed in bits
+ 24..31. This format was selected because it can be easily translated to
+ an EFI_HII_DATE structure in an EFI_IFR_TYPE_VALUE union.
+
+ @param Year The year value to be encoded.
+ @param Month The month value to be encoded.
+ @param Day The day value to be encoded.
+
+ @return A 64-bit containing Year, Month, and Day.
+**/
+#define EFI_HII_DATE_UINT64(Year, Month, Day) \
+ (UINT64)((Year & 0xffff) | ((Month & 0xff) << 16) | ((Day & 0xff) << 24))
+
+/**
+ Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
+ HiiFreeOpCodeHandle().
+
+ @retval NULL There are not enough resources to allocate a new OpCode Handle.
+ @retval Other A new OpCode handle.
+
+**/
+VOID *
+EFIAPI
+HiiAllocateOpCodeHandle (
+ VOID
+ );
+
+/**
+ Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
+ When an OpCode Handle is freed, all of the opcodes associated with the OpCode
+ Handle are also freed.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+
+**/
+VOID
+EFIAPI
+HiiFreeOpCodeHandle (
+ VOID *OpCodeHandle
+ );
+
+/**
+ Append raw opcodes to an OpCodeHandle.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If RawBuffer is NULL, then ASSERT();
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] RawBuffer The buffer of opcodes to append.
+ @param[in] RawBufferSize The size, in bytes, of Buffer.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the appended opcodes.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateRawOpCodes (
+ IN VOID *OpCodeHandle,
+ IN UINT8 *RawBuffer,
+ IN UINTN RawBufferSize
+ );
+
+/**
+ Create EFI_IFR_END_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateEndOpCode (
+ IN VOID *OpCodeHandle
+ );
+
+/**
+ Create EFI_IFR_ONE_OF_OPTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+ If Flags is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] StringId StringId for the option.
+ @param[in] Flags The flags for the option.
+ @param[in] Type The type for the option.
+ @param[in] Value The value for the option.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOptionOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 StringId,
+ IN UINT8 Flags,
+ IN UINT8 Type,
+ IN UINT64 Value
+ );
+
+/**
+ Create EFI_IFR_DEFAULT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] DefaultId The DefaultId for the default.
+ @param[in] Type The type for the default.
+ @param[in] Value The value for the default.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDefaultOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 DefaultId,
+ IN UINT8 Type,
+ IN UINT64 Value
+ );
+
+/**
+ Create EFI_IFR_GUID opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+ If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] Guid The pointer to EFI_GUID of this guided opcode.
+ @param[in] GuidOpCode The pointer to an EFI_IFR_GUID opcode. This is an
+ optional parameter that may be NULL. If this
+ parameter is NULL, then the GUID extension
+ region of the created opcode is filled with zeros.
+ If this parameter is not NULL, then the GUID
+ extension region of GuidData will be copied to
+ the GUID extension region of the created opcode.
+ @param[in] OpCodeSize The size, in bytes, of created opcode. This value
+ must be >= sizeof(EFI_IFR_GUID).
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGuidOpCode (
+ IN VOID *OpCodeHandle,
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *GuidOpCode, OPTIONAL
+ IN UINTN OpCodeSize
+ );
+
+/**
+ Create EFI_IFR_ACTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The Question ID.
+ @param[in] Prompt The String ID for Prompt.
+ @param[in] Help The String ID for Help.
+ @param[in] QuestionFlags The flags in the Question Header.
+ @param[in] QuestionConfig The String ID for the configuration.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateActionOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_STRING_ID QuestionConfig
+ );
+
+/**
+ Create EFI_IFR_SUBTITLE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in Flags, then ASSERT().
+ If Scope > 1, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] Flags The subtitle opcode flags.
+ @param[in] Scope 1 if this opcode is the beginning of a new scope.
+ 0 if this opcode is within the current scope.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateSubTitleOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 Flags,
+ IN UINT8 Scope
+ );
+
+/**
+ Create EFI_IFR_REF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] FormId The Destination Form ID.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header
+ @param[in] QuestionId Question ID.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID FormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId
+ );
+
+/**
+ Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
+
+ When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
+ When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] RefFormId The Destination Form ID.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header
+ @param[in] QuestionId Question ID.
+ @param[in] RefQuestionId The question on the form to which this link is referring.
+ If its value is zero, then the link refers to the top of the form.
+ @param[in] RefFormSetId The form set to which this link is referring. If its value is NULL, and RefDevicePath is
+ zero, then the link is to the current form set.
+ @param[in] RefDevicePath The string identifier that specifies the string containing the text representation of
+ the device path to which the form set containing the form specified by FormId.
+ If its value is zero, then the link refers to the current page.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoExOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID RefFormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_QUESTION_ID RefQuestionId,
+ IN EFI_GUID *RefFormSetId, OPTIONAL
+ IN EFI_STRING_ID RefDevicePath
+ );
+
+/**
+ Create EFI_IFR_CHECKBOX_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in CheckBoxFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The question ID.
+ @param[in] VarStoreId The storage ID.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header.
+ @param[in] CheckBoxFlags The flags for checkbox opcode.
+ @param[in] DefaultsOpCodeHandle The handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateCheckBoxOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 CheckBoxFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_NUMERIC_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in NumericFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The question ID.
+ @param[in] VarStoreId The storage ID.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header.
+ @param[in] NumericFlags The flags for a numeric opcode.
+ @param[in] Minimum The numeric minimum value.
+ @param[in] Maximum The numeric maximum value.
+ @param[in] Step The numeric step for edit.
+ @param[in] DefaultsOpCodeHandle The handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateNumericOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 NumericFlags,
+ IN UINT64 Minimum,
+ IN UINT64 Maximum,
+ IN UINT64 Step,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_STRING_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in StringFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The question ID.
+ @param[in] VarStoreId The storage ID.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header.
+ @param[in] StringFlags The flags for a string opcode.
+ @param[in] MinSize The string minimum length.
+ @param[in] MaxSize The string maximum length.
+ @param[in] DefaultsOpCodeHandle The handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateStringOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 StringFlags,
+ IN UINT8 MinSize,
+ IN UINT8 MaxSize,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_ONE_OF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OneOfFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The question ID.
+ @param[in] VarStoreId The storage ID.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header.
+ @param[in] OneOfFlags The flags for a oneof opcode.
+ @param[in] OptionsOpCodeHandle The handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle The handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OneOfFlags,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_ORDERED_LIST_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OrderedListFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] QuestionId The question ID.
+ @param[in] VarStoreId The storage ID.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header.
+ @param[in] OrderedListFlags The flags for an ordered list opcode.
+ @param[in] DataType The type for option value.
+ @param[in] MaxContainers Maximum count for options in this ordered list
+ @param[in] OptionsOpCodeHandle The handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOrderedListOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OrderedListFlags,
+ IN UINT8 DataType,
+ IN UINT8 MaxContainers,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_TEXT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Prompt String ID for Prompt.
+ @param[in] Help String ID for Help.
+ @param[in] TextTwo String ID for TextTwo.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTextOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN EFI_STRING_ID TextTwo
+ );
+
+/**
+ Create EFI_IFR_DATE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in DateFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] DateFlags Flags for date opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDateOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 DateFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ Create EFI_IFR_TIME_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in TimeFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] TimeFlags Flags for time opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTimeOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 TimeFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ );
+
+/**
+ This function updates a form that has previously been registered with the HII
+ Database. This function will perform at most one update operation.
+
+ The form to update is specified by Handle, FormSetGuid, and FormId. Binary
+ comparisons of IFR opcodes are performed from the beginning of the form being
+ updated until an IFR opcode is found that exactly matches the first IFR opcode
+ specified by StartOpCodeHandle. The following rules are used to determine if
+ an insert, replace, or delete operation is performed:
+
+ 1) If no matches are found, then NULL is returned.
+ 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching IFR opcode in the form to be updated.
+ 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
+ from the matching IFR opcode until an IFR opcode exactly matches the first
+ IFR opcode specified by EndOpCodeHandle. If no match is found for the first
+ IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
+ is found, then all of the IFR opcodes between the start match and the end
+ match are deleted from the form being updated and all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching start IFR opcode. If StartOpCcodeHandle only contains one
+ IFR instruction, then the result of this operation will delete all of the IFR
+ opcodes between the start end matches.
+
+ If HiiHandle is NULL, then ASSERT().
+ If StartOpCodeHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] FormSetGuid The Formset GUID of the form to update. This
+ is an optional parameter that may be NULL.
+ If it is NULL, all FormSet will be updated.
+ @param[in] FormId The ID of the form to update.
+ @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
+ opcodes to be inserted or replaced in the form.
+ The first IFR instruction in StartOpCodeHandle
+ is used to find matching IFR opcode in the
+ form.
+ @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
+ that marks the end of a replace operation in
+ the form. This is an optional parameter that
+ may be NULL. If it is NULL, then the IFR
+ opcodes specified by StartOpCodeHandle are
+ inserted into the form.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough memory resources are allocated.
+ @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND:
+ 1) The form specified by HiiHandle, FormSetGuid,
+ and FormId could not be found in the HII Database.
+ 2) No IFR opcodes in the target form match the first
+ IFR opcode in StartOpCodeHandle.
+ 3) EndOpCOde is not NULL, and no IFR opcodes in the
+ target form following a matching start opcode match
+ the first IFR opcode in EndOpCodeHandle.
+ @retval EFI_SUCCESS The matched form is updated by StartOpcode.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdateForm (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN EFI_FORM_ID FormId,
+ IN VOID *StartOpCodeHandle,
+ IN VOID *EndOpCodeHandle OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/IpmiLib.h b/roms/edk2/MdeModulePkg/Include/Library/IpmiLib.h
new file mode 100644
index 000000000..4b5c11bcf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/IpmiLib.h
@@ -0,0 +1,45 @@
+/** @file
+ This library abstract how to access IPMI device via IPMI command.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IPMI_LIB_H_
+#define _IPMI_LIB_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Ipmi.h>
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/LockBoxLib.h b/roms/edk2/MdeModulePkg/Include/Library/LockBoxLib.h
new file mode 100644
index 000000000..9dcd715d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/LockBoxLib.h
@@ -0,0 +1,137 @@
+/** @file
+ This library is only intended to be used by DXE modules that need save
+ confidential information to LockBox and get it by PEI modules in S3 phase.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LOCK_BOX_LIB_H_
+#define _LOCK_BOX_LIB_H_
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ );
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ );
+
+//
+// With this flag, this LockBox can be restored to this Buffer
+// with RestoreAllLockBoxInPlace()
+//
+#define LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE BIT0
+//
+// With this flag, this LockBox can be restored in S3 resume only.
+// This LockBox can not be restored after SmmReadyToLock in normal boot
+// and after EndOfS3Resume in S3 resume.
+// It can not be set together with LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE.
+//
+#define LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY BIT1
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ the original buffer to too small to hold new information.
+ @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ );
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ );
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/MemoryProfileLib.h b/roms/edk2/MdeModulePkg/Include/Library/MemoryProfileLib.h
new file mode 100644
index 000000000..beb637e1a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/MemoryProfileLib.h
@@ -0,0 +1,47 @@
+/** @file
+ Provides services to record memory profile of multilevel caller.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MEMORY_PROFILE_LIB_H_
+#define _MEMORY_PROFILE_LIB_H_
+
+#include <Guid/MemoryProfile.h>
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/NonDiscoverableDeviceRegistrationLib.h b/roms/edk2/MdeModulePkg/Include/Library/NonDiscoverableDeviceRegistrationLib.h
new file mode 100644
index 000000000..b2300c964
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/NonDiscoverableDeviceRegistrationLib.h
@@ -0,0 +1,58 @@
+/** @file
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __NON_DISCOVERABLE_DEVICE_REGISTRATION_LIB_H__
+#define __NON_DISCOVERABLE_DEVICE_REGISTRATION_LIB_H__
+
+#include <Protocol/NonDiscoverableDevice.h>
+
+typedef enum {
+ NonDiscoverableDeviceTypeAhci,
+ NonDiscoverableDeviceTypeAmba,
+ NonDiscoverableDeviceTypeEhci,
+ NonDiscoverableDeviceTypeNvme,
+ NonDiscoverableDeviceTypeOhci,
+ NonDiscoverableDeviceTypeSdhci,
+ NonDiscoverableDeviceTypeUfs,
+ NonDiscoverableDeviceTypeUhci,
+ NonDiscoverableDeviceTypeXhci,
+ NonDiscoverableDeviceTypeMax,
+} NON_DISCOVERABLE_DEVICE_TYPE;
+
+/**
+ Register a non-discoverable MMIO device
+
+ @param[in] Type The type of non-discoverable device
+ @param[in] DmaType Whether the device is DMA coherent
+ @param[in] InitFunc Initialization routine to be invoked when
+ the device is enabled
+ @param[in,out] Handle The handle onto which to install the
+ non-discoverable device protocol.
+ If Handle is NULL or *Handle is NULL, a
+ new handle will be allocated.
+ @param[in] NumMmioResources The number of UINTN base/size pairs that
+ follow, each describing an MMIO region
+ owned by the device
+ @param[in] ... The variable argument list which contains the
+ info about MmioResources.
+
+ @retval EFI_SUCCESS The registration succeeded.
+ @retval Other The registration failed.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterNonDiscoverableMmioDevice (
+ IN NON_DISCOVERABLE_DEVICE_TYPE Type,
+ IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,
+ IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,
+ IN OUT EFI_HANDLE *Handle OPTIONAL,
+ IN UINTN NumMmioResources,
+ ...
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/OemHookStatusCodeLib.h b/roms/edk2/MdeModulePkg/Include/Library/OemHookStatusCodeLib.h
new file mode 100644
index 000000000..b13c38d2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/OemHookStatusCodeLib.h
@@ -0,0 +1,73 @@
+/** @file
+ OEM hook status code library. Platform can implement an instance to
+ initialize the OEM devices to report status code information.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __OEM_HOOK_STATUSCODE_LIB__
+#define __OEM_HOOK_STATUSCODE_LIB__
+
+/**
+
+ Initialize OEM status code device.
+
+
+ @return Status of initialization of OEM status code device.
+
+**/
+EFI_STATUS
+EFIAPI
+OemHookStatusCodeInitialize (
+ VOID
+ );
+
+/**
+ Report status code to OEM 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 both an operation and classification information
+ about the class and subclass.
+ 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.
+ Specific values are discussed in the Intel Platform Innovation
+ Framework for EFI Status Code Specification.
+
+ @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.
+ Type EFI_GUID is defined in InstallProtocolInterface()
+ in the UEFI 2.0 Specification.
+
+
+ @param Data This optional parameter may be used to pass additional data.
+
+ @return The function always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OemHookStatusCodeReport (
+ 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
+ );
+
+#endif // __OEM_HOOK_STATUSCODE_LIB__
+
diff --git a/roms/edk2/MdeModulePkg/Include/Library/PciHostBridgeLib.h b/roms/edk2/MdeModulePkg/Include/Library/PciHostBridgeLib.h
new file mode 100644
index 000000000..160658935
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/PciHostBridgeLib.h
@@ -0,0 +1,115 @@
+/** @file
+ PCI Host Bridge Library consumed by PciHostBridgeDxe driver returning
+ the platform specific information about the PCI Host Bridge.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __PCI_HOST_BRIDGE_LIB_H__
+#define __PCI_HOST_BRIDGE_LIB_H__
+
+//
+// (Base > Limit) indicates an aperture is not available.
+//
+typedef struct {
+ //
+ // Base and Limit are the device address instead of host address when
+ // Translation is not zero
+ //
+ UINT64 Base;
+ UINT64 Limit;
+ //
+ // According to UEFI 2.7, Device Address = Host Address + Translation,
+ // so Translation = Device Address - Host Address.
+ // On platforms where Translation is not zero, the subtraction is probably to
+ // be performed with UINT64 wrap-around semantics, for we may translate an
+ // above-4G host address into a below-4G device address for legacy PCIe device
+ // compatibility.
+ //
+ // NOTE: The alignment of Translation is required to be larger than any BAR
+ // alignment in the same root bridge, so that the same alignment can be
+ // applied to both device address and host address, which simplifies the
+ // situation and makes the current resource allocation code in generic PCI
+ // host bridge driver still work.
+ //
+ UINT64 Translation;
+} PCI_ROOT_BRIDGE_APERTURE;
+
+typedef struct {
+ UINT32 Segment; ///< Segment number.
+ UINT64 Supports; ///< Supported attributes.
+ ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes()
+ ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ UINT64 Attributes; ///< Initial attributes.
+ ///< Refer to EFI_PCI_ATTRIBUTE_xxx used by GetAttributes()
+ ///< and SetAttributes() in EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ BOOLEAN DmaAbove4G; ///< DMA above 4GB memory.
+ ///< Set to TRUE when root bridge supports DMA above 4GB memory.
+ BOOLEAN NoExtendedConfigSpace; ///< When FALSE, the root bridge supports
+ ///< Extended (4096-byte) Configuration Space.
+ ///< When TRUE, the root bridge supports
+ ///< 256-byte Configuration Space only.
+ BOOLEAN ResourceAssigned; ///< Resource assignment status of the root bridge.
+ ///< Set to TRUE if Bus/IO/MMIO resources for root bridge have been assigned.
+ UINT64 AllocationAttributes; ///< Allocation attributes.
+ ///< Refer to EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM and
+ ///< EFI_PCI_HOST_BRIDGE_MEM64_DECODE used by GetAllocAttributes()
+ ///< in EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+ PCI_ROOT_BRIDGE_APERTURE Bus; ///< Bus aperture which can be used by the root bridge.
+ PCI_ROOT_BRIDGE_APERTURE Io; ///< IO aperture which can be used by the root bridge.
+ PCI_ROOT_BRIDGE_APERTURE Mem; ///< MMIO aperture below 4GB which can be used by the root bridge.
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G; ///< MMIO aperture above 4GB which can be used by the root bridge.
+ PCI_ROOT_BRIDGE_APERTURE PMem; ///< Prefetchable MMIO aperture below 4GB which can be used by the root bridge.
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G; ///< Prefetchable MMIO aperture above 4GB which can be used by the root bridge.
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath; ///< Device path.
+} PCI_ROOT_BRIDGE;
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ );
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ );
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource descriptors.
+ The Configuration contains the resources for all the
+ root bridges. The resource for each root bridge is
+ terminated with END descriptor and an additional END
+ is appended indicating the end of the entire resources.
+ The resource descriptor field values follow the description
+ in EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/PlatformBootManagerLib.h b/roms/edk2/MdeModulePkg/Include/Library/PlatformBootManagerLib.h
new file mode 100644
index 000000000..5d3062e9d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/PlatformBootManagerLib.h
@@ -0,0 +1,69 @@
+/** @file
+ Platform Boot Manager library definition. A platform can implement
+ instances to support platform-specific behavior.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __PLATFORM_BOOT_MANAGER_LIB_H_
+#define __PLATFORM_BOOT_MANAGER_LIB_H_
+#include <Library/UefiBootManagerLib.h>
+
+/**
+ Do the platform specific action before the console is connected.
+
+ Such as:
+ Update console variable;
+ Register new Driver#### or Boot####;
+ Signal ReadyToLock event.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ );
+
+/**
+ Do the platform specific action after the console is connected.
+
+ Such as:
+ Dynamically switch output mode;
+ Signal console ready platform customized event;
+ Run diagnostics like memory testing;
+ Connect certain devices;
+ Dispatch aditional option roms.
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ );
+
+/**
+ This function is called each second during the boot manager waits the timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ );
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/PlatformHookLib.h b/roms/edk2/MdeModulePkg/Include/Library/PlatformHookLib.h
new file mode 100644
index 000000000..bc8035570
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/PlatformHookLib.h
@@ -0,0 +1,32 @@
+/** @file
+ Platform hook library. Platform can provide an implementation of this
+ library class to provide hooks that may be required for some type of
+ platform initialization.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_HOOK_LIB__
+#define __PLATFORM_HOOK_LIB__
+
+/**
+ Performs platform specific initialization required for the CPU to access
+ the hardware associated with a SerialPortLib instance. This function does
+ not intiailzie the serial port hardware itself. Instead, it initializes
+ hardware devices that are required for the CPU to access the serial port
+ hardware. This function may be called more than once.
+
+ @retval RETURN_SUCCESS The platform specific initialization succeeded.
+ @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ );
+
+#endif // __PLATFORM_HOOK_LIB__
+
diff --git a/roms/edk2/MdeModulePkg/Include/Library/PlatformVarCleanupLib.h b/roms/edk2/MdeModulePkg/Include/Library/PlatformVarCleanupLib.h
new file mode 100644
index 000000000..bf0ad06be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/PlatformVarCleanupLib.h
@@ -0,0 +1,56 @@
+/** @file
+ The library class provides platform variable cleanup services.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_VARIABLE_CLEANUP_LIB_
+#define _PLATFORM_VARIABLE_CLEANUP_LIB_
+
+#include <Guid/VarErrorFlag.h>
+
+typedef enum {
+ VarCleanupAll,
+ VarCleanupManually,
+ VarCleanupMax,
+} VAR_CLEANUP_TYPE;
+
+/**
+ Get last boot variable error flag.
+
+ @return Last boot variable error flag.
+
+**/
+VAR_ERROR_FLAG
+EFIAPI
+GetLastBootVarErrorFlag (
+ VOID
+ );
+
+/**
+ Platform variable cleanup.
+
+ @param[in] Flag Variable error flag.
+ @param[in] Type Variable cleanup type.
+ If it is VarCleanupManually, the interface must be called after console connected.
+
+ @retval EFI_SUCCESS No error or error processed.
+ @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
+ For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
+ Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
+ @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanup (
+ IN VAR_ERROR_FLAG Flag,
+ IN VAR_CLEANUP_TYPE Type
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Library/ResetSystemLib.h b/roms/edk2/MdeModulePkg/Include/Library/ResetSystemLib.h
new file mode 100644
index 000000000..09ee14540
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/ResetSystemLib.h
@@ -0,0 +1,93 @@
+/** @file
+ System reset Library Services. This library class defines a set of
+ methods that reset the whole system.
+
+Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __RESET_SYSTEM_LIB_H__
+#define __RESET_SYSTEM_LIB_H__
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiMultiPhase.h>
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ );
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ );
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shutdown reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ );
+
+/**
+ This function causes a systemwide reset. The exact type of the reset is
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+ the platform must pick a supported reset type to perform.The platform may
+ optionally log the parameters from any non-normal reset that occurs.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData The data buffer starts with a Null-terminated string,
+ followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+ IN UINTN DataSize,
+ IN VOID *ResetData
+ );
+
+/**
+ The ResetSystem function resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/ResetUtilityLib.h b/roms/edk2/MdeModulePkg/Include/Library/ResetUtilityLib.h
new file mode 100644
index 000000000..656703e78
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/ResetUtilityLib.h
@@ -0,0 +1,130 @@
+/** @file
+ This header describes various helper functions for resetting the system.
+
+ Copyright (c) 2017 - 2019 Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 Microsoft Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _RESET_UTILITY_LIB_H_
+#define _RESET_UTILITY_LIB_H_
+
+#include <Uefi/UefiMultiPhase.h>
+
+/**
+ This is a shorthand helper function to reset with reset type and a subtype
+ so that the caller doesn't have to bother with a function that has half
+ a dozen parameters.
+
+ This will generate a reset with status EFI_SUCCESS, a NULL string, and
+ no custom data. The subtype will be formatted in such a way that it can be
+ picked up by notification registrations and custom handlers.
+
+ NOTE: This call will fail if the architectural ResetSystem underpinnings
+ are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
+ to your DEPEX.
+
+ @param[in] ResetType The default EFI_RESET_TYPE of the reset.
+ @param[in] ResetSubtype GUID pointer for the reset subtype to be used.
+
+**/
+VOID
+EFIAPI
+ResetSystemWithSubtype (
+ IN EFI_RESET_TYPE ResetType,
+ IN CONST GUID *ResetSubtype
+ );
+
+/**
+ This is a shorthand helper function to reset with the reset type
+ 'EfiResetPlatformSpecific' and a subtype so that the caller doesn't
+ have to bother with a function that has half a dozen parameters.
+
+ This will generate a reset with status EFI_SUCCESS, a NULL string, and
+ no custom data. The subtype will be formatted in such a way that it can be
+ picked up by notification registrations and custom handlers.
+
+ NOTE: This call will fail if the architectural ResetSystem underpinnings
+ are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
+ to your DEPEX.
+
+ @param[in] ResetSubtype GUID pointer for the reset subtype to be used.
+
+**/
+VOID
+EFIAPI
+ResetPlatformSpecificGuid (
+ IN CONST GUID *ResetSubtype
+ );
+
+/**
+ This function examines the DataSize and ResetData parameters passed to
+ to ResetSystem() and detemrines if the ResetData contains a Null-terminated
+ Unicode string followed by a GUID specific subtype. If the GUID specific
+ subtype is present, then a pointer to the GUID value in ResetData is returned.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData Pointer to the data buffer passed into ResetSystem().
+
+ @retval Pointer Pointer to the GUID value in ResetData.
+ @retval NULL ResetData is NULL.
+ @retval NULL ResetData does not start with a Null-terminated
+ Unicode string.
+ @retval NULL A Null-terminated Unicode string is present, but there
+ are less than sizeof (GUID) bytes after the string.
+ @retval NULL No subtype is found.
+
+**/
+GUID *
+EFIAPI
+GetResetPlatformSpecificGuid (
+ IN UINTN DataSize,
+ IN CONST VOID *ResetData
+ );
+
+/**
+ This is a helper function that creates the reset data buffer that can be
+ passed into ResetSystem().
+
+ The reset data buffer is returned in ResetData and contains ResetString
+ followed by the ResetSubtype GUID followed by the ExtraData.
+
+ NOTE: Strings are internally limited by MAX_UINT16.
+
+ @param[in, out] ResetDataSize On input, the size of the ResetData buffer. On
+ output, either the total number of bytes
+ copied, or the required buffer size.
+ @param[in, out] ResetData A pointer to the buffer in which to place the
+ final structure.
+ @param[in] ResetSubtype Pointer to the GUID specific subtype. This
+ parameter is optional and may be NULL.
+ @param[in] ResetString Pointer to a Null-terminated Unicode string
+ that describes the reset. This parameter is
+ optional and may be NULL.
+ @param[in] ExtraDataSize The size, in bytes, of ExtraData buffer.
+ @param[in] ExtraData Pointer to a buffer of extra data. This
+ parameter is optional and may be NULL.
+
+ @retval RETURN_SUCCESS ResetDataSize and ResetData are updated.
+ @retval RETURN_INVALID_PARAMETER ResetDataSize is NULL.
+ @retval RETURN_INVALID_PARAMETER ResetData is NULL.
+ @retval RETURN_INVALID_PARAMETER ExtraData was provided without a
+ ResetSubtype. This is not supported by the
+ UEFI spec.
+ @retval RETURN_BUFFER_TOO_SMALL An insufficient buffer was provided.
+ ResetDataSize is updated with minimum size
+ required.
+**/
+RETURN_STATUS
+EFIAPI
+BuildResetData (
+ IN OUT UINTN *ResetDataSize,
+ IN OUT VOID *ResetData,
+ IN CONST GUID *ResetSubtype OPTIONAL,
+ IN CONST CHAR16 *ResetString OPTIONAL,
+ IN UINTN ExtraDataSize OPTIONAL,
+ IN CONST VOID *ExtraData OPTIONAL
+ );
+
+#endif // _RESET_UTILITY_LIB_H_
diff --git a/roms/edk2/MdeModulePkg/Include/Library/SecurityManagementLib.h b/roms/edk2/MdeModulePkg/Include/Library/SecurityManagementLib.h
new file mode 100644
index 000000000..9bb29121a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/SecurityManagementLib.h
@@ -0,0 +1,270 @@
+/** @file
+ This library class defines a set of interfaces to abstract the policy of
+ security measurement by managing the different security measurement services.
+ The library instances can be implemented according to the different security policy.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SECURITY_MANAGEMENT_LIB_H__
+#define __SECURITY_MANAGEMENT_LIB_H__
+
+//
+// Authentication Operation defintions for User Identity (UID), Measured and Secure boot.
+//
+#define EFI_AUTH_OPERATION_NONE 0x00
+#define EFI_AUTH_OPERATION_VERIFY_IMAGE 0x01
+#define EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD 0x02
+#define EFI_AUTH_OPERATION_MEASURE_IMAGE 0x04
+#define EFI_AUTH_OPERATION_CONNECT_POLICY 0x08
+//
+// Authentication State Operation will check the authentication status of a file.
+//
+#define EFI_AUTH_OPERATION_AUTHENTICATION_STATE 0x10
+
+///
+/// Image buffer is required by the security handler.
+///
+#define EFI_AUTH_OPERATION_IMAGE_REQUIRED 0x80000000
+
+/**
+ The security handler is used to abstract platform-specific policy
+ from the DXE core response to an attempt to use a file that returns a
+ given status for the authentication check from the section extraction protocol.
+
+ The possible responses in a given SAP implementation may include locking
+ flash upon failure to authenticate, attestation logging for all signed drivers,
+ and other exception operations. The File parameter allows for possible logging
+ within the SAP of the driver.
+
+ If File is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
+ then EFI_ACCESS_DENIED is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use at the time, but it
+ might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
+ returned.
+
+ FileBuffer will be NULL and FileSize will be 0 if the handler being called
+ did not set EFI_AUTH_OPERATION_IMAGE_REQUIRED when it was registered.
+
+ @param[in] AuthenticationStatus
+ The authentication status returned from the security
+ measurement services for the input file.
+ @param[in] File The pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer The file buffer matches the input file device path.
+ @param[in] FileSize The size of File buffer matches the input file device path.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER The file is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SECURITY_FILE_AUTHENTICATION_STATE_HANDLER)(
+ IN OUT UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ );
+
+/**
+ Register security measurement handler with its operation type. Different
+ handlers with the same operation can all be registered.
+
+ If SecurityHandler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] SecurityHandler The security measurement service handler to be registered.
+ @param[in] AuthenticationOperation Theoperation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurityHandler (
+ IN SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler,
+ IN UINT32 AuthenticationOperation
+ );
+
+/**
+ Execute registered handlers until one returns an error and that error is returned.
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+
+ Before exectue handler, get the image buffer by file device path if a handler
+ requires the image file. And return the image buffer to each handler when exectue handler.
+
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationStatus
+ This is the authentication type returned from the Section
+ Extraction protocol. See the Section Extraction Protocol
+ Specification for details on this type.
+ @param[in] FilePath This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+
+ @retval EFI_SUCCESS The file specified by File authenticated when more
+ than one security handler services were registered,
+ or the file did not authenticate when no security
+ handler service was registered. And the platform policy
+ dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurityHandlers (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ The security handler is used to abstracts security-specific functions from the DXE
+ Foundation of UEFI Image Verification, Trusted Computing Group (TCG) measured boot,
+ User Identity policy for image loading and consoles, and for purposes of
+ handling GUIDed section encapsulations.
+
+ @param[in] AuthenticationStatus
+ The authentication status for the input file.
+ @param[in] File The pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer A pointer to the buffer with the UEFI file image
+ @param[in] FileSize The size of File buffer.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SECURITY_VIOLATION The file specified by DevicePath and FileBuffer did not
+ authenticate, and the platform policy dictates that the file should be
+ placed in the untrusted state. The image has been added to the file
+ execution table.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation may not use File.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SECURITY2_FILE_AUTHENTICATION_HANDLER) (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ );
+
+/**
+ Register security measurement handler with its operation type. Different
+ handlers with the same operation can all be registered.
+
+ If SecurityHandler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] Security2Handler The security measurement service handler to be registered.
+ @param[in] AuthenticationOperation The operation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurity2Handler (
+ IN SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler,
+ IN UINT32 AuthenticationOperation
+ );
+
+/**
+ Execute registered handlers based on input AuthenticationOperation until
+ one returns an error and that error is returned.
+
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+ The handlers those satisfy AuthenticationOperation will only be executed.
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationOperation
+ The operation type specifies which handlers will be executed.
+ @param[in] AuthenticationStatus
+ The authentication status for the input file.
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer A pointer to the buffer with the UEFI file image
+ @param[in] FileSize The size of File buffer.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SECURITY_VIOLATION The file specified by DevicePath and FileBuffer did not
+ authenticate, and the platform policy dictates that the file should be
+ placed in the untrusted state. The image has been added to the file
+ execution table.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation may not use File.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+ @retval EFI_INVALID_PARAMETER File and FileBuffer are both NULL.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurity2Handlers (
+ IN UINT32 AuthenticationOperation,
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/SmmCorePlatformHookLib.h b/roms/edk2/MdeModulePkg/Include/Library/SmmCorePlatformHookLib.h
new file mode 100644
index 000000000..ca4180aa2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/SmmCorePlatformHookLib.h
@@ -0,0 +1,44 @@
+/** @file
+ Smm Core Platform Hook Library. This library class defines a set of platform
+ hooks called by the SMM Core.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_CORE_PLATFORM_HOOK_LIB__
+#define __SMM_CORE_PLATFORM_HOOK_LIB__
+
+/**
+ Performs platform specific tasks before invoking registered SMI handlers.
+
+ This function performs platform specific tasks before invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookBeforeSmmDispatch (
+ VOID
+ );
+
+
+/**
+ Performs platform specific tasks after invoking registered SMI handlers.
+
+ This function performs platform specific tasks after invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookAfterSmmDispatch (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/SortLib.h b/roms/edk2/MdeModulePkg/Include/Library/SortLib.h
new file mode 100644
index 000000000..70789709a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/SortLib.h
@@ -0,0 +1,107 @@
+/** @file
+ Library used for sorting and comparison routines.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __SORT_LIB_H__
+#define __SORT_LIB_H__
+
+/**
+ Prototype for comparison function for any two element types.
+
+ @param[in] Buffer1 The pointer to first buffer.
+ @param[in] Buffer2 The pointer to second buffer.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return <0 Buffer1 is less than Buffer2.
+ @return >0 Buffer1 is greater than Buffer2.
+**/
+typedef
+INTN
+(EFIAPI *SORT_COMPARE)(
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ );
+
+/**
+ Function to perform a Quick Sort on a buffer of comparable elements.
+
+ Each element must be equally sized.
+
+ If BufferToSort is NULL, then ASSERT.
+ If CompareFunction is NULL, then ASSERT.
+
+ If Count is < 2 , then perform no action.
+ If Size is < 1 , then perform no action.
+
+ @param[in, out] BufferToSort On call, a Buffer of (possibly sorted) elements;
+ on return, a buffer of sorted elements.
+ @param[in] Count The number of elements in the buffer to sort.
+ @param[in] ElementSize The size of an element in bytes.
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any two elements.
+**/
+VOID
+EFIAPI
+PerformQuickSort (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction
+ );
+
+
+/**
+ Function to compare 2 device paths for use as CompareFunction.
+
+ @param[in] Buffer1 The pointer to Device Path to compare.
+ @param[in] Buffer2 The pointer to second DevicePath to compare.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+DevicePathCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ );
+
+/**
+ Function to compare 2 strings without regard to case of the characters.
+
+ @param[in] Buffer1 The pointer to String to compare (CHAR16**).
+ @param[in] Buffer2 The pointer to second String to compare (CHAR16**).
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringNoCaseCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ );
+
+/**
+ Function to compare 2 strings.
+
+ @param[in] Buffer1 The pointer to String to compare (CHAR16**).
+ @param[in] Buffer2 The pointer to second String to compare (CHAR16**).
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ );
+
+#endif //__SORT_LIB_H__
diff --git a/roms/edk2/MdeModulePkg/Include/Library/TpmMeasurementLib.h b/roms/edk2/MdeModulePkg/Include/Library/TpmMeasurementLib.h
new file mode 100644
index 000000000..ddf6723f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/TpmMeasurementLib.h
@@ -0,0 +1,38 @@
+/** @file
+ This library is used by other modules to measure data to TPM.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TPM_MEASUREMENT_LIB_H_
+#define _TPM_MEASUREMENT_LIB_H_
+
+/**
+ Tpm measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+TpmMeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h b/roms/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
new file mode 100644
index 000000000..0b69a6021
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
@@ -0,0 +1,817 @@
+/** @file
+ Provide Boot Manager related library APIs.
+
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _UEFI_BOOT_MANAGER_LIB_H_
+#define _UEFI_BOOT_MANAGER_LIB_H_
+
+#include <Protocol/DriverHealth.h>
+#include <Library/SortLib.h>
+
+//
+// Boot Manager load option library functions.
+//
+
+//
+// Load Option Type
+//
+typedef enum {
+ LoadOptionTypeDriver,
+ LoadOptionTypeSysPrep,
+ LoadOptionTypeBoot,
+ LoadOptionTypePlatformRecovery,
+ LoadOptionTypeMax
+} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;
+
+typedef enum {
+ LoadOptionNumberMax = 0x10000,
+ LoadOptionNumberUnassigned = LoadOptionNumberMax
+} EFI_BOOT_MANAGER_LOAD_OPTION_NUMBER;
+
+//
+// Common structure definition for DriverOption and BootOption
+//
+typedef struct {
+ //
+ // Data read from UEFI NV variables
+ //
+ UINTN OptionNumber; // #### numerical value, could be LoadOptionNumberUnassigned
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; // LoadOptionTypeBoot or LoadOptionTypeDriver
+ UINT32 Attributes; // Load Option Attributes
+ CHAR16 *Description; // Load Option Description
+ EFI_DEVICE_PATH_PROTOCOL *FilePath; // Load Option Device Path
+ UINT8 *OptionalData; // Load Option optional data to pass into image
+ UINT32 OptionalDataSize; // Load Option size of OptionalData
+ EFI_GUID VendorGuid;
+
+ //
+ // Used at runtime
+ //
+ EFI_STATUS Status; // Status returned from boot attempt gBS->StartImage ()
+ CHAR16 *ExitData; // Exit data returned from gBS->StartImage ()
+ UINTN ExitDataSize; // Size of ExitData
+} EFI_BOOT_MANAGER_LOAD_OPTION;
+
+/**
+ Returns an array of load options based on the EFI variable
+ L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
+ #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
+
+ @param LoadOptionCount Returns number of entries in the array.
+ @param LoadOptionType The type of the load option.
+
+ @retval NULL No load options exist.
+ @retval !NULL Array of load option entries.
+
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+EFIAPI
+EfiBootManagerGetLoadOptions (
+ OUT UINTN *LoadOptionCount,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
+ );
+
+/**
+ Free an array of load options returned from EfiBootManagerGetLoadOptions().
+
+ @param LoadOptions Pointer to the array of load options to free.
+ @param LoadOptionCount Number of array entries in LoadOptions.
+
+ @return EFI_SUCCESS LoadOptions was freed.
+ @return EFI_INVALID_PARAMETER LoadOptions is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,
+ IN UINTN LoadOptionCount
+ );
+
+/**
+ Initialize a load option.
+
+ @param Option Pointer to the load option to be initialized.
+ @param OptionNumber Option number of the load option.
+ @param OptionType Type of the load option.
+ @param Attributes Attributes of the load option.
+ @param Description Description of the load option.
+ @param FilePath Device path of the load option.
+ @param OptionalData Optional data of the load option.
+ @param OptionalDataSize Size of the optional data of the load option.
+
+ @retval EFI_SUCCESS The load option was initialized successfully.
+ @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerInitializeLoadOption (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ IN UINT32 Attributes,
+ IN CHAR16 *Description,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN UINT8 *OptionalData,
+ IN UINT32 OptionalDataSize
+ );
+
+/**
+ Free a load option created by EfiBootManagerInitializeLoadOption()
+ or EfiBootManagerVariableToLoadOption().
+
+ @param LoadOption Pointer to the load option to free.
+ CONCERN: Check Boot#### instead of BootOrder, optimize, spec clarify
+ @return EFI_SUCCESS LoadOption was freed.
+ @return EFI_INVALID_PARAMETER LoadOption is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ );
+
+/**
+ Initialize the load option from the VariableName.
+
+ @param VariableName EFI Variable name which could be Boot#### or
+ Driver####
+ @param LoadOption Pointer to the load option to be initialized
+
+ @retval EFI_SUCCESS The option was created
+ @retval EFI_INVALID_PARAMETER VariableName or LoadOption is NULL.
+ @retval EFI_NOT_FOUND The variable specified by VariableName cannot be found.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOption (
+ IN CHAR16 *VariableName,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ );
+
+/**
+ Create the Boot#### or Driver#### variable from the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_SUCCESS The variable was created.
+ @retval Others Error status returned by RT->SetVariable.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerLoadOptionToVariable (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ );
+
+/**
+ This function will register the new Boot####, Driver#### or SysPrep#### option.
+ After the *#### is updated, the *Order will also be updated.
+
+ @param Option Pointer to load option to add. If on input
+ Option->OptionNumber is LoadOptionNumberUnassigned,
+ then on output Option->OptionNumber is updated to
+ the number of the new Boot####,
+ Driver#### or SysPrep#### option.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The *#### have been successfully registered.
+ @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ Note: this API only adds new load option, no replacement support.
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
+ option number specified in the Option is LoadOptionNumberUnassigned.
+ @return Status codes of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddLoadOptionVariable (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN Position
+ );
+
+/**
+ Delete the load option according to the OptionNumber and OptionType.
+
+ Only the BootOrder/DriverOrder is updated to remove the reference of the OptionNumber.
+
+ @param OptionNumber Option number of the load option.
+ @param OptionType Type of the load option.
+
+ @retval EFI_NOT_FOUND The load option cannot be found.
+ @retval EFI_SUCCESS The load option was deleted.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteLoadOptionVariable (
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
+ );
+
+/**
+ Sort the load options. The DriverOrder/BootOrder variables will be re-created to
+ reflect the new order.
+
+ @param OptionType The type of the load option.
+ @param CompareFunction The comparator function pointer.
+**/
+VOID
+EFIAPI
+EfiBootManagerSortLoadOptionVariable (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ IN SORT_COMPARE CompareFunction
+ );
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param Key Pointer to the load option to be found.
+ @param Array Pointer to the array of load options to be found.
+ @param Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+EFIAPI
+EfiBootManagerFindLoadOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ );
+
+//
+// Boot Manager hot key library functions.
+//
+
+#pragma pack(1)
+///
+/// EFI Key Option.
+///
+typedef struct {
+ ///
+ /// Specifies options about how the key will be processed.
+ ///
+ EFI_BOOT_KEY_DATA KeyData;
+ ///
+ /// The CRC-32 which should match the CRC-32 of the entire EFI_LOAD_OPTION to
+ /// which BootOption refers. If the CRC-32s do not match this value, then this key
+ /// option is ignored.
+ ///
+ UINT32 BootOptionCrc;
+ ///
+ /// The Boot#### option which will be invoked if this key is pressed and the boot option
+ /// is active (LOAD_OPTION_ACTIVE is set).
+ ///
+ UINT16 BootOption;
+ ///
+ /// The key codes to compare against those returned by the
+ /// EFI_SIMPLE_TEXT_INPUT and EFI_SIMPLE_TEXT_INPUT_EX protocols.
+ /// The number of key codes (0-3) is specified by the EFI_KEY_CODE_COUNT field in KeyOptions.
+ ///
+ EFI_INPUT_KEY Keys[3];
+ UINT16 OptionNumber;
+} EFI_BOOT_MANAGER_KEY_OPTION;
+#pragma pack()
+
+/**
+ Start the hot key service so that the key press can trigger the boot option.
+
+ @param HotkeyTriggered Return the waitable event and it will be signaled
+ when a valid hot key is pressed.
+
+ @retval EFI_SUCCESS The hot key service is started.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerStartHotkeyService (
+ IN EFI_EVENT *HotkeyTriggered
+ );
+
+//
+// Modifier for EfiBootManagerAddKeyOptionVariable and EfiBootManagerDeleteKeyOptionVariable
+//
+#define EFI_BOOT_MANAGER_SHIFT_PRESSED 0x00000001
+#define EFI_BOOT_MANAGER_CONTROL_PRESSED 0x00000002
+#define EFI_BOOT_MANAGER_ALT_PRESSED 0x00000004
+#define EFI_BOOT_MANAGER_LOGO_PRESSED 0x00000008
+#define EFI_BOOT_MANAGER_MENU_KEY_PRESSED 0x00000010
+#define EFI_BOOT_MANAGER_SYS_REQ_PRESSED 0x00000020
+
+/**
+ Add the key option.
+ It adds the key option variable and the key option takes affect immediately.
+
+ @param AddedOption Return the added key option.
+ @param BootOptionNumber The boot option number for the key option.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is added.
+ @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddKeyOptionVariable (
+ OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption, OPTIONAL
+ IN UINT16 BootOptionNumber,
+ IN UINT32 Modifier,
+ ...
+ );
+
+/**
+ Delete the Key Option variable and unregister the hot key
+
+ @param DeletedOption Return the deleted key options.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is deleted.
+ @retval EFI_NOT_FOUND The key option cannot be found.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteKeyOptionVariable (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
+ IN UINT32 Modifier,
+ ...
+ );
+
+/**
+ Register the key option to exit the waiting of the Boot Manager timeout.
+ Platform should ensure that the continue key option isn't conflict with
+ other boot key options.
+
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS Successfully register the continue key option.
+ @retval EFI_ALREADY_STARTED The continue key option is already registered.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterContinueKeyOption (
+ IN UINT32 Modifier,
+ ...
+ );
+
+/**
+ Try to boot the boot option triggered by hot key.
+**/
+VOID
+EFIAPI
+EfiBootManagerHotkeyBoot (
+ VOID
+ );
+//
+// Boot Manager boot library functions.
+//
+
+/**
+ The function creates boot options for all possible bootable medias in the following order:
+ 1. Removable BlockIo - The boot option only points to the removable media
+ device, like USB key, DVD, Floppy etc.
+ 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
+ like HardDisk.
+ 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
+ SimpleFileSystem Protocol, but not supporting BlockIo
+ protocol.
+ 4. LoadFile - The boot option points to the media supporting
+ LoadFile protocol.
+ Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
+
+ The function won't delete the boot option not added by itself.
+**/
+VOID
+EFIAPI
+EfiBootManagerRefreshAllBootOption (
+ VOID
+ );
+
+/**
+ Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
+ signals the EFI ready to boot event. If the device path for the option starts
+ with a BBS device path a legacy boot is attempted. Short form device paths are
+ also supported via this rountine. A device path starting with
+ MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP, MSG_USB_CLASS_DP gets expaned out
+ to find the first device that matches. If the BootOption Device Path
+ fails the removable media boot algorithm is attempted (\EFI\BOOTIA32.EFI,
+ \EFI\BOOTX64.EFI,... only one file type is tried per processor type)
+
+ @param BootOption Boot Option to try and boot.
+ On return, BootOption->Status contains the boot status:
+ EFI_SUCCESS BootOption was booted
+ EFI_UNSUPPORTED BootOption isn't supported.
+ EFI_NOT_FOUND The BootOption was not found on the system
+ Others BootOption failed with this error status
+
+**/
+VOID
+EFIAPI
+EfiBootManagerBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ );
+
+/**
+ Return the boot option corresponding to the Boot Manager Menu.
+ It may automatically create one if the boot option hasn't been created yet.
+
+ @param BootOption Return the Boot Manager Menu.
+
+ @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
+ @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
+ @retval others Return status of gRT->SetVariable (). BootOption still points
+ to the Boot Manager Menu even the Status is not EFI_SUCCESS
+ and EFI_NOT_FOUND.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerGetBootManagerMenu (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ );
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+ BmGetNextLoadOptionBuffer() guarantees.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+EfiBootManagerGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ );
+
+/**
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+EFIAPI
+EfiBootManagerGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ );
+
+/**
+ The function enumerates all the legacy boot options, creates them and
+ registers them in the BootOrder variable.
+**/
+typedef
+VOID
+(EFIAPI *EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION) (
+ VOID
+ );
+
+/**
+ The function boots a legacy boot option.
+**/
+typedef
+VOID
+(EFIAPI *EFI_BOOT_MANAGER_LEGACY_BOOT) (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ );
+
+/**
+ The function registers the legacy boot support capabilities.
+
+ @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
+ @param LegacyBoot The function pointer to boot the legacy boot option.
+**/
+VOID
+EFIAPI
+EfiBootManagerRegisterLegacyBootSupport (
+ EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
+ EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
+ );
+
+/**
+ Return the platform provided boot option description for the controller.
+
+ @param Handle Controller handle.
+ @param DefaultDescription Default boot description provided by core.
+
+ @return The callee allocated description string
+ or NULL if the handler wants to use DefaultDescription.
+**/
+typedef
+CHAR16 *
+(EFIAPI *EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER) (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *DefaultDescription
+ );
+
+/**
+ Register the platform provided boot description handler.
+
+ @param Handler The platform provided boot description handler
+
+ @retval EFI_SUCCESS The handler was registered successfully.
+ @retval EFI_ALREADY_STARTED The handler was already registered.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterBootDescriptionHandler (
+ IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
+ );
+
+//
+// Boot Manager connect and disconnect library functions
+//
+
+/**
+ 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
+EfiBootManagerConnectAll (
+ 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 which will be connected, it can be
+ a multi-instance device path
+ @param MatchingHandle Return the controller handle closest to the DevicePathToConnect
+
+ @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.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect,
+ OUT EFI_HANDLE *MatchingHandle OPTIONAL
+ );
+
+/**
+ 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().
+**/
+VOID
+EFIAPI
+EfiBootManagerDisconnectAll (
+ VOID
+ );
+
+
+//
+// Boot Manager console library functions
+//
+
+typedef enum {
+ ConIn,
+ ConOut,
+ ErrOut,
+ ConInDev,
+ ConOutDev,
+ ErrOutDev,
+ ConsoleTypeMax
+} CONSOLE_TYPE;
+
+/**
+ This function will connect all the console devices base on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectAllDefaultConsoles (
+ VOID
+ );
+
+/**
+ This function updates the console variable based on ConVarName. It can
+ add or remove one specific console device path from the variable
+
+ @param ConsoleType ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
+ @param CustomizedConDevicePath The console device path to be added to
+ the console variable. Cannot be multi-instance.
+ @param ExclusiveDevicePath The console device path to be removed
+ from the console variable. 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
+EfiBootManagerUpdateConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType,
+ 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, if
+ anyone of the instances is connected success, then this function
+ will return success.
+
+ @param ConsoleType ConIn, ConOut or 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
+EfiBootManagerConnectConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType
+ );
+
+/**
+ Query all the children of VideoController and return the device paths of all the
+ children that support GraphicsOutput protocol.
+
+ @param VideoController PCI handle of video controller.
+
+ @return Device paths of all the children that support GraphicsOutput protocol.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+EfiBootManagerGetGopDevicePath (
+ IN EFI_HANDLE VideoController
+ );
+
+/**
+ Connect the platform active active video controller.
+
+ @param VideoController PCI handle of video controller.
+
+ @retval EFI_NOT_FOUND There is no active video controller.
+ @retval EFI_SUCCESS The video controller is connected.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectVideoController (
+ EFI_HANDLE VideoController OPTIONAL
+ );
+
+//
+// Boot Manager driver health library functions.
+//
+
+typedef struct {
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+
+ ///
+ /// Driver relative handles
+ ///
+ EFI_HANDLE DriverHealthHandle;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE ChildHandle;
+
+ ///
+ /// Driver health messages of the specify Driver
+ ///
+ EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
+
+ ///
+ /// HII relative handles
+ ///
+ EFI_HII_HANDLE HiiHandle;
+
+ ///
+ /// Driver Health status
+ ///
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+} EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO;
+
+/**
+ Return all the Driver Health information.
+
+ When the cumulative health status of all the controllers managed by the
+ driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
+ EFI_DRIVER_HEALTH_PROTOCOL instance.
+ Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
+ entry. Additionally every child controller creates one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
+
+ @param Count Return the count of the Driver Health information.
+
+ @retval NULL No Driver Health information is returned.
+ @retval !NULL Pointer to the Driver Health information array.
+**/
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
+EFIAPI
+EfiBootManagerGetDriverHealthInfo (
+ UINTN *Count
+ );
+
+/**
+ Free the Driver Health information array.
+
+ @param DriverHealthInfo Pointer to array of the Driver Health information.
+ @param Count Count of the array.
+
+ @retval EFI_SUCCESS The array is freed.
+ @retval EFI_INVALID_PARAMETER The array is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeDriverHealthInfo (
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,
+ UINTN Count
+ );
+
+/**
+ Process (load and execute) the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,
+ or the load option file path doesn't point to a valid file.
+ @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
+ @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ );
+
+/**
+ Check whether the VariableName is a valid load option variable name
+ and return the load option type and option number.
+
+ @param VariableName The name of the load option variable.
+ @param OptionType Return the load option type.
+ @param OptionNumber Return the load option number.
+
+ @retval TRUE The variable name is valid; The load option type and
+ load option number are returned.
+ @retval FALSE The variable name is NOT valid.
+**/
+BOOLEAN
+EFIAPI
+EfiBootManagerIsValidLoadOptionVariableName (
+ IN CHAR16 *VariableName,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL,
+ OUT UINT16 *OptionNumber OPTIONAL
+ );
+
+
+/**
+ Dispatch the deferred images that are returned from all DeferredImageLoad instances.
+
+ @retval EFI_SUCCESS At least one deferred image is loaded successfully and started.
+ @retval EFI_NOT_FOUND There is no deferred image.
+ @retval EFI_ACCESS_DENIED There are deferred images but all of them are failed to load.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDispatchDeferredImages (
+ VOID
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/UefiHiiServicesLib.h b/roms/edk2/MdeModulePkg/Include/Library/UefiHiiServicesLib.h
new file mode 100644
index 000000000..36bbd45bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/UefiHiiServicesLib.h
@@ -0,0 +1,46 @@
+/** @file
+ Provides global variables that are pointers to the UEFI HII related protocols.
+ All of the UEFI HII related protocols are optional, so the consumers of this
+ library class must verify that the global variable pointers are not NULL before
+ use.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __UEFI_HII_SERVICES_LIB_H__
+#define __UEFI_HII_SERVICES_LIB_H__
+
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiConfigRouting.h>
+
+///
+/// The pointer to the UEFI HII Font Protocol.
+///
+extern EFI_HII_FONT_PROTOCOL *gHiiFont;
+
+///
+/// The pointer to the UEFI HII String Protocol.
+///
+extern EFI_HII_STRING_PROTOCOL *gHiiString;
+
+///
+/// The pointer to the UEFI HII Image Protocol.
+///
+extern EFI_HII_IMAGE_PROTOCOL *gHiiImage;
+
+///
+/// The pointer to the UEFI HII Database Protocol.
+///
+extern EFI_HII_DATABASE_PROTOCOL *gHiiDatabase;
+
+///
+/// The pointer to the UEFI HII Config Rounting Protocol.
+///
+extern EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Library/VarCheckLib.h b/roms/edk2/MdeModulePkg/Include/Library/VarCheckLib.h
new file mode 100644
index 000000000..b2b296506
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Library/VarCheckLib.h
@@ -0,0 +1,174 @@
+/** @file
+ Provides variable check services and database management.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_CHECK_LIB_H_
+#define _VARIABLE_CHECK_LIB_H_
+
+#include <Protocol/VarCheck.h>
+
+typedef enum {
+ VarCheckRequestReserved0 = 0,
+ VarCheckRequestReserved1 = 1,
+ VarCheckFromTrusted = 2,
+ VarCheckFromUntrusted = 3,
+} VAR_CHECK_REQUEST_SOURCE;
+
+typedef
+VOID
+(EFIAPI *VAR_CHECK_END_OF_DXE_CALLBACK) (
+ VOID
+ );
+
+/**
+ Register END_OF_DXE callback.
+ The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] Callback END_OF_DXE callback.
+
+ @retval EFI_SUCCESS The callback was registered successfully.
+ @retval EFI_INVALID_PARAMETER Callback is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterEndOfDxeCallback (
+ IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
+ );
+
+/**
+ Var check initialize at END_OF_DXE.
+
+ This function needs to be called at END_OF_DXE.
+ Address pointers may be returned,
+ and caller needs to ConvertPointer() for the pointers.
+
+ @param[in, out] AddressPointerCount Output pointer to address pointer count.
+
+ @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
+
+**/
+VOID ***
+EFIAPI
+VarCheckLibInitializeAtEndOfDxe (
+ IN OUT UINTN *AddressPointerCount OPTIONAL
+ );
+
+/**
+ Register address pointer.
+ The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] AddressPointer Address pointer.
+
+ @retval EFI_SUCCESS The address pointer was registered successfully.
+ @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterAddressPointer (
+ IN VOID **AddressPointer
+ );
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ );
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ SetVariable check.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @param[in] RequestSource Request source.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
+ DataSize and Data value was supplied.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval Others The other return status from check handler.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibSetVariableCheck (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data,
+ IN VAR_CHECK_REQUEST_SOURCE RequestSource
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/AtaAhciController.h b/roms/edk2/MdeModulePkg/Include/Ppi/AtaAhciController.h
new file mode 100644
index 000000000..07a2c8c28
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/AtaAhciController.h
@@ -0,0 +1,83 @@
+/** @file
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_H_
+#define _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_H_
+
+#include <Protocol/DevicePath.h>
+
+///
+/// Global ID for the EDKII_ATA_AHCI_HOST_CONTROLLER_PPI.
+///
+#define EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } \
+ }
+
+//
+// Forward declaration for the EDKII_ATA_AHCI_HOST_CONTROLLER_PPI.
+//
+typedef struct _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI EDKII_ATA_AHCI_HOST_CONTROLLER_PPI;
+
+/**
+ Get the MMIO base address of ATA AHCI host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] ControllerId The ID of the ATA AHCI host controller.
+ @param[out] MmioBar The MMIO base address of the controller.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_NOT_FOUND The specified ATA AHCI host controller not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_ATA_AHCI_HC_GET_MMIO_BAR) (
+ IN EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *MmioBar
+ );
+
+/**
+ Get the device path of ATA AHCI host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] ControllerId The ID of the ATA AHCI host controller.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of ATA AHCI host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_NOT_FOUND The specified ATA AHCI host controller not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_ATA_AHCI_HC_GET_DEVICE_PATH) (
+ IN EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+//
+// This PPI contains a set of services to interact with the ATA AHCI host controller.
+//
+struct _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI {
+ EDKII_ATA_AHCI_HC_GET_MMIO_BAR GetAhciHcMmioBar;
+ EDKII_ATA_AHCI_HC_GET_DEVICE_PATH GetAhciHcDevicePath;
+};
+
+extern EFI_GUID gEdkiiPeiAtaAhciHostControllerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/AtaController.h b/roms/edk2/MdeModulePkg/Include/Ppi/AtaController.h
new file mode 100644
index 000000000..2c17f31c3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/AtaController.h
@@ -0,0 +1,155 @@
+/** @file
+ Define the PPI to abstract the functions that enable IDE and SATA channels, and to retrieve
+ the base I/O port address for each of the enabled IDE and SATA channels.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_ATA_CONTROLLER_PPI_H_
+#define _PEI_ATA_CONTROLLER_PPI_H_
+
+///
+/// Global ID for the PEI_ATA_CONTROLLER_PPI.
+///
+#define PEI_ATA_CONTROLLER_PPI_GUID \
+ { \
+ 0xa45e60d1, 0xc719, 0x44aa, {0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d } \
+ }
+
+///
+/// Forward declaration for the PEI_ATA_CONTROLLER_PPI.
+///
+typedef struct _PEI_ATA_CONTROLLER_PPI PEI_ATA_CONTROLLER_PPI;
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// disable the IDE channels.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_IDE_NONE 0x00
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// enable the Primary IDE channel.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_IDE_PRIMARY 0x01
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// enable the Secondary IDE channel.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_IDE_SECONDARY 0x02
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// disable the SATA channel.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_SATA_NONE 0x04
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// enable the Primary SATA channel.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_SATA_PRIMARY 0x08
+
+///
+/// This bit is used in the ChannelMask parameter of EnableAtaChannel() to
+/// enable the Secondary SATA channel.
+/// This is designed for old generation chipset with PATA/SATA controllers.
+/// It may be ignored in PPI implementation for new generation chipset without PATA controller.
+///
+#define PEI_ICH_SATA_SECONDARY 0x010
+
+///
+/// Structure that contains the base addresses for the IDE registers
+///
+typedef struct {
+ ///
+ /// Base I/O port address of the IDE controller's command block
+ ///
+ UINT16 CommandBlockBaseAddr;
+ ///
+ /// Base I/O port address of the IDE controller's control block
+ ///
+ UINT16 ControlBlockBaseAddr;
+} IDE_REGS_BASE_ADDR;
+
+/**
+ Sets IDE and SATA channels to an enabled or disabled state.
+
+ This service enables or disables the IDE and SATA channels specified by ChannelMask.
+ It may ignore ChannelMask setting to enable or disable IDE and SATA channels based on the platform policy.
+ The number of the enabled channels will be returned by GET_IDE_REGS_BASE_ADDR() function.
+
+ If the new state is set, then EFI_SUCCESS is returned. If the new state can
+ not be set, then EFI_DEVICE_ERROR is returned.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_ATA_CONTROLLER_PPI.
+ @param[in] ChannelMask The bitmask that identifies the IDE and SATA channels to
+ enable or disable. This parameter is optional.
+
+ @retval EFI_SUCCESS The IDE or SATA channels were enabled or disabled successfully.
+ @retval EFI_DEVICE_ERROR The IDE or SATA channels could not be enabled or disabled.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_ENABLE_ATA)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_ATA_CONTROLLER_PPI *This,
+ IN UINT8 ChannelMask
+ );
+
+/**
+ Retrieves the I/O port base addresses for command and control registers of the
+ enabled IDE/SATA channels.
+
+ This service fills in the structure poionted to by IdeRegsBaseAddr with the I/O
+ port base addresses for the command and control registers of the IDE and SATA
+ channels that were previously enabled in EnableAtaChannel(). The number of
+ enabled IDE and SATA channels is returned.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_ATA_CONTROLLER_PPI.
+ @param[out] IdeRegsBaseAddr The pointer to caller allocated space to return the
+ I/O port base addresses of the IDE and SATA channels
+ that were previosuly enabled with EnableAtaChannel().
+
+ @return The number of enabled IDE and SATA channels in the platform.
+
+**/
+typedef
+UINT32
+(EFIAPI *GET_IDE_REGS_BASE_ADDR)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_ATA_CONTROLLER_PPI *This,
+ OUT IDE_REGS_BASE_ADDR *IdeRegsBaseAddr
+ );
+
+///
+/// This PPI contains services to enable and disable IDE and SATA channels and
+/// retrieves the base I/O port addresses to the enabled IDE and SATA channels.
+///
+struct _PEI_ATA_CONTROLLER_PPI {
+ PEI_ENABLE_ATA EnableAtaChannel;
+ GET_IDE_REGS_BASE_ADDR GetIdeRegsBaseAddr;
+};
+
+extern EFI_GUID gPeiAtaControllerPpiGuid;
+
+#endif
+
+
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/AtaPassThru.h b/roms/edk2/MdeModulePkg/Include/Ppi/AtaPassThru.h
new file mode 100644
index 000000000..f8ebe56df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/AtaPassThru.h
@@ -0,0 +1,213 @@
+/** @file
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_ATA_PASS_THRU_PPI_H_
+#define _EDKII_ATA_PASS_THRU_PPI_H_
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/AtaPassThru.h>
+
+///
+/// Global ID for the EDKII_PEI_ATA_PASS_THRU_PPI.
+///
+#define EDKII_PEI_ATA_PASS_THRU_PPI_GUID \
+ { \
+ 0xa16473fd, 0xd474, 0x4c89, { 0xae, 0xc7, 0x90, 0xb8, 0x3c, 0x73, 0x86, 0x9 } \
+ }
+
+//
+// Forward declaration for the EDKII_PEI_ATA_PASS_THRU_PPI.
+//
+typedef struct _EDKII_PEI_ATA_PASS_THRU_PPI EDKII_PEI_ATA_PASS_THRU_PPI;
+
+//
+// Revision The revision to which the ATA Pass Thru PPI interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_PEI_ATA_PASS_THRU_PPI_REVISION 0x00010000
+
+
+/**
+ Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number of the ATA device to send
+ the command.
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA
+ device to send the command.
+ If there is no port multiplier, then specify
+ 0xFFFF.
+ @param[in,out] Packet A pointer to the ATA command to send to
+ the ATA device specified by Port and
+ PortMultiplierPort.
+
+ @retval EFI_SUCCESS The ATA command was sent by the host. For
+ bi-directional commands, InTransferLength bytes
+ were transferred from InDataBuffer. For write
+ and bi-directional commands, OutTransferLength
+ bytes were transferred by OutDataBuffer.
+ @retval EFI_NOT_FOUND The specified ATA device is not found.
+ @retval EFI_INVALID_PARAMETER The contents of Acb are invalid. The ATA command
+ was not sent, so no additional status information
+ is available.
+ @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
+ of bytes that could be transferred is returned
+ in InTransferLength. For write and bi-directional
+ commands, OutTransferLength bytes were transferred
+ by OutDataBuffer.
+ @retval EFI_NOT_READY The ATA command could not be sent because there
+ are too many ATA commands already queued. The
+ caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ send the ATA command.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_PASSTHRU) (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN UINT16 PortMultiplierPort,
+ IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+/**
+ Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+ These can either be the list of ports where ATA devices are actually present or the
+ list of legal port numbers for the ATA controller. Regardless, the caller of this
+ function must probe the port number returned to see if an ATA device is actually
+ present at that location on the ATA controller.
+
+ The GetNextPort() function retrieves the port number on an ATA controller. If on
+ input Port is 0xFFFF, then the port number of the first port on the ATA controller
+ is returned in Port and EFI_SUCCESS is returned.
+
+ If Port is a port number that was returned on a previous call to GetNextPort(),
+ then the port number of the next port on the ATA controller is returned in Port,
+ and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+ a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+ If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] Port On input, a pointer to the port number on the ATA controller.
+ On output, a pointer to the next port number on the ATA
+ controller. An input value of 0xFFFF retrieves the first
+ port number on the ATA controller.
+
+ @retval EFI_SUCCESS The next port number on the ATA controller was
+ returned in Port.
+ @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
+ @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned
+ on a previous call to GetNextPort().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_THRU_GET_NEXT_PORT) (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN OUT UINT16 *Port
+ );
+
+/**
+ Used to retrieve the list of legal port multiplier port numbers for ATA devices
+ on a port of an ATA controller. These can either be the list of port multiplier
+ ports where ATA devices are actually present on port or the list of legal port
+ multiplier ports on that port. Regardless, the caller of this function must probe
+ the port number and port multiplier port number returned to see if an ATA device
+ is actually present.
+
+ The GetNextDevice() function retrieves the port multiplier port number of an ATA
+ device present on a port of an ATA controller.
+
+ If PortMultiplierPort points to a port multiplier port number value that was
+ returned on a previous call to GetNextDevice(), then the port multiplier port
+ number of the next ATA device on the port of the ATA controller is returned in
+ PortMultiplierPort, and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+ of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+ and EFI_SUCCESS is returned.
+
+ If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+ was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+ is returned.
+
+ If PortMultiplierPort is the port multiplier port number of the last ATA device
+ on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Port The port number present on the ATA controller.
+ @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier
+ port number of an ATA device present on the
+ ATA controller. If on input a PortMultiplierPort
+ of 0xFFFF is specified, then the port multiplier
+ port number of the first ATA device is returned.
+ On output, a pointer to the port multiplier port
+ number of the next ATA device present on an ATA
+ controller.
+
+ @retval EFI_SUCCESS The port multiplier port number of the next ATA
+ device on the port of the ATA controller was
+ returned in PortMultiplierPort.
+ @retval EFI_NOT_FOUND There are no more ATA devices on this port of
+ the ATA controller.
+ @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+ was not returned on a previous call to GetNextDevice().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_GET_NEXT_DEVICE) (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ IN UINT16 Port,
+ IN OUT UINT16 *PortMultiplierPort
+ );
+
+/**
+ Gets the device path information of the underlying ATA host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying ATA host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The device path of the ATA host controller has
+ been successfully returned.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to return the device path.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_GET_DEVICE_PATH) (
+ IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+//
+// EDKII_PEI_ATA_PASS_THRU_PPI provides the services that are required to send
+// ATA commands to an ATA device during PEI.
+//
+struct _EDKII_PEI_ATA_PASS_THRU_PPI {
+ UINT64 Revision;
+ EFI_ATA_PASS_THRU_MODE *Mode;
+ EDKII_PEI_ATA_PASS_THRU_PASSTHRU PassThru;
+ EDKII_PEI_ATA_PASS_THRU_THRU_GET_NEXT_PORT GetNextPort;
+ EDKII_PEI_ATA_PASS_THRU_GET_NEXT_DEVICE GetNextDevice;
+ EDKII_PEI_ATA_PASS_THRU_GET_DEVICE_PATH GetDevicePath;
+};
+
+extern EFI_GUID gEdkiiPeiAtaPassThruPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/CapsuleOnDisk.h b/roms/edk2/MdeModulePkg/Include/Ppi/CapsuleOnDisk.h
new file mode 100644
index 000000000..8ff2ba4b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/CapsuleOnDisk.h
@@ -0,0 +1,55 @@
+/** @file
+ This file declares Capsule On Disk PPI. This PPI is used to find and load the
+ capsule on files that are relocated into a temp file under rootdir.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PEI_CAPSULE_ON_DISK_PPI_H__
+#define __PEI_CAPSULE_ON_DISK_PPI_H__
+
+#define EDKII_PEI_CAPSULE_ON_DISK_PPI_GUID \
+ { \
+ 0x71a9ea61, 0x5a35, 0x4a5d, {0xac, 0xef, 0x9c, 0xf8, 0x6d, 0x6d, 0x67, 0xe0 } \
+ }
+
+typedef struct _EDKII_PEI_CAPSULE_ON_DISK_PPI EDKII_PEI_CAPSULE_ON_DISK_PPI;
+
+/**
+ Loads a DXE capsule from some media into memory and updates the HOB table
+ with the DXE firmware volume information.
+
+ @param PeiServices General-purpose services that are available to every PEIM.
+ @param This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_LOAD_CAPSULE_ON_DISK)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This
+ );
+
+///
+/// Finds and loads the recovery files.
+///
+struct _EDKII_PEI_CAPSULE_ON_DISK_PPI {
+ EDKII_PEI_LOAD_CAPSULE_ON_DISK LoadCapsuleOnDisk; ///< Loads a DXE binary capsule into memory.
+};
+
+extern EFI_GUID gEdkiiPeiCapsuleOnDiskPpiGuid;
+
+#define EDKII_PEI_BOOT_IN_CAPSULE_ON_DISK_MODE_PPI \
+ { \
+ 0xb08a11e4, 0xe2b7, 0x4b75, { 0xb5, 0x15, 0xaf, 0x61, 0x6, 0x68, 0xbf, 0xd1 } \
+ }
+
+extern EFI_GUID gEdkiiPeiBootInCapsuleOnDiskModePpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/Debug.h b/roms/edk2/MdeModulePkg/Include/Ppi/Debug.h
new file mode 100644
index 000000000..d14caa2bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/Debug.h
@@ -0,0 +1,75 @@
+/** @file
+ Define the EDKII_DEBUG_PPI that PEIMs can use to dump info to debug port.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EDKII_DEBUG_PPI_H__
+#define __EDKII_DEBUG_PPI_H__
+
+#include <Pi/PiPeiCis.h>
+
+//
+// Global ID for the EDKII_DEBUG_PPI
+//
+#define EDKII_DEBUG_PPI_GUID \
+ { \
+ 0x999e699c, 0xb013, 0x475e, {0xb1, 0x7b, 0xf3, 0xa8, 0xae, 0x5c, 0x48, 0x75} \
+ }
+
+///
+/// Forward declaration for the PEI_DEBUG_LIB_DEBUG_PPI EDKII_DEBUG_PPI
+///
+typedef struct _EDKII_DEBUG_PPI EDKII_DEBUG_PPI;
+
+/**
+ Print a debug message to debug output device if the specified error level
+ is enabled.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] Marker BASE_LIST marker for the variable argument list.
+
+**/
+typedef
+VOID
+(EFIAPI *EDKII_DEBUG_BPRINT)(
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Print an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ @param[in] FileName The pointer to the name of the source file that
+ generated the assert condition.
+ @param[in] LineNumber The line number in the source file that generated
+ the assert condition
+ @param[in] Description The pointer to the description of the assert condition.
+
+**/
+typedef
+VOID
+(EFIAPI *EDKII_DEBUG_ASSERT)(
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ );
+
+///
+/// This PPI contains a set of services to print message to debug output device
+///
+struct _EDKII_DEBUG_PPI {
+ EDKII_DEBUG_BPRINT DebugBPrint;
+ EDKII_DEBUG_ASSERT DebugAssert;
+};
+
+extern EFI_GUID gEdkiiDebugPpiGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/IoMmu.h b/roms/edk2/MdeModulePkg/Include/Ppi/IoMmu.h
new file mode 100644
index 000000000..34d7f0534
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/IoMmu.h
@@ -0,0 +1,201 @@
+/** @file
+ PEI IOMMU PPI.
+
+Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __PEI_IOMMU_H__
+#define __PEI_IOMMU_H__
+
+//
+// for EFI_ALLOCATE_TYPE
+//
+#include <Uefi.h>
+
+//
+// Include protocol for common definition
+// EDKII_IOMMU_ACCESS_xxx
+// EDKII_IOMMU_OPERATION
+//
+#include <Protocol/IoMmu.h>
+
+//
+// IOMMU Ppi GUID value
+//
+#define EDKII_IOMMU_PPI_GUID \
+ { \
+ 0x70b0af26, 0xf847, 0x4bb6, { 0xaa, 0xb9, 0xcd, 0xe8, 0x4f, 0xc6, 0x14, 0x31 } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EDKII_IOMMU_PPI EDKII_IOMMU_PPI;
+
+//
+// Revision The revision to which the IOMMU interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_IOMMU_PPI_REVISION 0x00010000
+
+/**
+ Set IOMMU attribute for a system memory.
+
+ If the IOMMU PPI exists, the system memory cannot be used
+ for DMA by default.
+
+ When a device requests a DMA access for a system memory,
+ the device driver need use SetAttribute() to update the IOMMU
+ attribute to request DMA access (read and/or write).
+
+ @param[in] This The PPI instance pointer.
+ @param[in] Mapping The mapping value returned from Map().
+ @param[in] IoMmuAccess The IOMMU access.
+
+ @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
+ @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
+ @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
+ @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
+ @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+ not available to be allocated yet.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_IOMMU_SET_ATTRIBUTE)(
+ IN EDKII_IOMMU_PPI *This,
+ IN VOID *Mapping,
+ IN UINT64 IoMmuAccess
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param This The PPI instance pointer.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+ not available to be allocated yet.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_IOMMU_MAP)(
+ IN EDKII_IOMMU_PPI *This,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This The PPI instance pointer.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+ @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+ not available to be allocated yet.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_IOMMU_UNMAP)(
+ IN EDKII_IOMMU_PPI *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param This The PPI instance pointer.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+ @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+ not available to be allocated yet.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_IOMMU_ALLOCATE_BUFFER)(
+ IN EDKII_IOMMU_PPI *This,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This The PPI instance pointer.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+ @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+ not available to be allocated yet.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_IOMMU_FREE_BUFFER)(
+ IN EDKII_IOMMU_PPI *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+///
+/// IOMMU PPI structure.
+///
+struct _EDKII_IOMMU_PPI {
+ UINT64 Revision;
+ EDKII_PEI_IOMMU_SET_ATTRIBUTE SetAttribute;
+ EDKII_PEI_IOMMU_MAP Map;
+ EDKII_PEI_IOMMU_UNMAP Unmap;
+ EDKII_PEI_IOMMU_ALLOCATE_BUFFER AllocateBuffer;
+ EDKII_PEI_IOMMU_FREE_BUFFER FreeBuffer;
+};
+
+///
+/// IOMMU PPI GUID variable.
+///
+extern EFI_GUID gEdkiiIoMmuPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/IpmiPpi.h b/roms/edk2/MdeModulePkg/Include/Ppi/IpmiPpi.h
new file mode 100644
index 000000000..c3412e17b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/IpmiPpi.h
@@ -0,0 +1,59 @@
+/** @file
+ Ppi for Ipmi of SMS.
+
+ Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IPMI_PPI_H_
+#define _IPMI_PPI_H_
+
+typedef struct _PEI_IPMI_PPI PEI_IPMI_PPI;
+
+#define PEI_IPMI_PPI_GUID \
+ { \
+ 0xa9731431, 0xd968, 0x4277, 0xb7, 0x52, 0xa3, 0xa9, 0xa6, 0xae, 0x18, 0x98 \
+ }
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] This This point for PEI_IPMI_PPI structure.
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_IPMI_SUBMIT_COMMAND) (
+ IN PEI_IPMI_PPI *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ );
+
+//
+// IPMI PPI
+//
+struct _PEI_IPMI_PPI {
+ PEI_IPMI_SUBMIT_COMMAND IpmiSubmitCommand;
+};
+
+extern EFI_GUID gPeiIpmiPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressHostController.h b/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressHostController.h
new file mode 100644
index 000000000..3a88180aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressHostController.h
@@ -0,0 +1,86 @@
+/** @file
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI_H_
+#define _EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI_H_
+
+#include <Protocol/DevicePath.h>
+
+///
+/// Global ID for the EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI.
+///
+#define EDKII_NVME_EXPRESS_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0xcae3aa63, 0x676f, 0x4da3, { 0xbd, 0x50, 0x6c, 0xc5, 0xed, 0xde, 0x9a, 0xad } \
+ }
+
+//
+// Forward declaration for the EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI.
+//
+typedef struct _EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI;
+
+/**
+ Get the MMIO base address of NVM Express host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] ControllerId The ID of the NVM Express host controller.
+ @param[out] MmioBar The MMIO base address of the controller.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_NOT_FOUND The specified NVM Express host controller not
+ found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_NVM_EXPRESS_HC_GET_MMIO_BAR) (
+ IN EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *MmioBar
+ );
+
+/**
+ Get the device path of NVM Express host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] ControllerId The ID of the NVM Express host controller.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of NVM Express host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+ @retval EFI_NOT_FOUND The specified NVM Express host controller not
+ found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_NVM_EXPRESS_HC_GET_DEVICE_PATH) (
+ IN EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+//
+// This PPI contains a set of services to interact with the NVM Express host
+// controller.
+//
+struct _EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI {
+ EDKII_NVM_EXPRESS_HC_GET_MMIO_BAR GetNvmeHcMmioBar;
+ EDKII_NVM_EXPRESS_HC_GET_DEVICE_PATH GetNvmeHcDevicePath;
+};
+
+extern EFI_GUID gEdkiiPeiNvmExpressHostControllerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressPassThru.h b/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressPassThru.h
new file mode 100644
index 000000000..cb5b3b3b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/NvmExpressPassThru.h
@@ -0,0 +1,156 @@
+/** @file
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_NVME_PASS_THRU_PPI_H_
+#define _EDKII_NVME_PASS_THRU_PPI_H_
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/NvmExpressPassthru.h>
+
+///
+/// Global ID for the EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI.
+///
+#define EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_GUID \
+ { \
+ 0x6af31b2c, 0x3be, 0x46c1, { 0xb1, 0x2d, 0xea, 0x4a, 0x36, 0xdf, 0xa7, 0x4c } \
+ }
+
+//
+// Forward declaration for the EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI.
+//
+typedef struct _EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI;
+
+//
+// Revision The revision to which the Nvme Pass Thru PPI interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION 0x00010000
+
+/**
+ Gets the device path information of the underlying NVM Express host controller.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of the underlying NVM Express
+ host controller.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_NVME_PASS_THRU_GET_DEVICE_PATH) (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Used to retrieve the next namespace ID for this NVM Express controller.
+
+ If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first
+ valid namespace ID defined on the NVM Express controller is returned in the
+ location pointed to by NamespaceId and a status of EFI_SUCCESS is returned.
+
+ If on input the value pointed to by NamespaceId is an invalid namespace ID
+ other than 0xFFFFFFFF, then EFI_INVALID_PARAMETER is returned.
+
+ If on input the value pointed to by NamespaceId is a valid namespace ID, then
+ the next valid namespace ID on the NVM Express controller is returned in the
+ location pointed to by NamespaceId, and EFI_SUCCESS is returned.
+
+ If the value pointed to by NamespaceId is the namespace ID of the last
+ namespace on the NVM Express controller, then EFI_NOT_FOUND is returned.
+
+ @param[in] This The PPI instance pointer.
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId
+ for an NVM Express namespace present on the
+ NVM Express controller. On output, a pointer
+ to the next NamespaceId of an NVM Express
+ namespace on an NVM Express controller. An
+ input value of 0xFFFFFFFF retrieves the
+ first NamespaceId for an NVM Express
+ namespace present on an NVM Express
+ controller.
+
+ @retval EFI_SUCCESS The Namespace ID of the next Namespace was
+ returned.
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this
+ controller.
+ @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than
+ 0xFFFFFFFF.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_NVME_PASS_THRU_GET_NEXT_NAMESPACE)(
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN OUT UINT32 *NamespaceId
+ );
+
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
+ supports blocking execution of the command.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Nvm Express command packet will
+ be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
+ the namespace ID specifies that the command packet should be sent to all
+ valid namespaces.
+ @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
+ to the NVMe namespace specified by NamespaceId.
+
+ @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
+ TransferLength bytes were transferred to, or from DataBuffer.
+ @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
+ the controller is not ready. The caller may retry again later.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
+ Express Command Packet.
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
+ are invalid.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
+ is not supported by the host adapter.
+ The EDKII PEI NVM Express Command Packet was not sent, so no
+ additional status information is available.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
+ Packet to execute.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_NVME_PASS_THRU_PASSTHRU) (
+ IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+//
+// This PPI contains a set of services to send commands
+// to a mass storage device.
+//
+struct _EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI {
+ UINT64 Revision;
+ EFI_NVM_EXPRESS_PASS_THRU_MODE *Mode;
+ EDKII_PEI_NVME_PASS_THRU_GET_DEVICE_PATH GetDevicePath;
+ EDKII_PEI_NVME_PASS_THRU_GET_NEXT_NAMESPACE GetNextNameSpace;
+ EDKII_PEI_NVME_PASS_THRU_PASSTHRU PassThru;
+};
+
+extern EFI_GUID gEdkiiPeiNvmExpressPassThruPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetFilter.h b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetFilter.h
new file mode 100644
index 000000000..b5ee324db
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetFilter.h
@@ -0,0 +1,25 @@
+/** @file
+ This PPI provides services to register a platform specific reset filter
+ for ResetSystem(). A reset filter evaluates the parameters passed to
+ ResetSystem() and converts a ResetType of EfiResetPlatformSpecific to a
+ non-platform specific reset type. The registered filters are processed before
+ EDKII_PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI handlers.
+
+ Copyright (c) 2017 - 2018 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_RESET_FILTER_PPI_H_
+#define _PLATFORM_SPECIFIC_RESET_FILTER_PPI_H_
+
+#include <Protocol/ResetNotification.h>
+
+#define EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI_GUID \
+ { 0x8c9f4de3, 0x7b90, 0x47ef, { 0x93, 0x8, 0x28, 0x7c, 0xec, 0xd6, 0x6d, 0xe8 } }
+
+typedef EFI_RESET_NOTIFICATION_PROTOCOL EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI;
+
+extern EFI_GUID gEdkiiPlatformSpecificResetFilterPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetHandler.h b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetHandler.h
new file mode 100644
index 000000000..069a4f707
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetHandler.h
@@ -0,0 +1,23 @@
+/** @file
+ This PPI provides services to register a platform specific handler for
+ ResetSystem(). The registered handlers are processed after
+ EDKII_PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI notifications.
+
+ Copyright (c) 2017 - 2018 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_RESET_HANDLER_PPI_H_
+#define _PLATFORM_SPECIFIC_RESET_HANDLER_PPI_H_
+
+#include <Protocol/ResetNotification.h>
+
+#define EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PPI_GUID \
+ { 0x75cf14ae, 0x3441, 0x49dc, { 0xaa, 0x10, 0xbb, 0x35, 0xa7, 0xba, 0x8b, 0xab } }
+
+typedef EFI_RESET_NOTIFICATION_PROTOCOL EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PPI;
+
+extern EFI_GUID gEdkiiPlatformSpecificResetHandlerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetNotification.h b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetNotification.h
new file mode 100644
index 000000000..f97e46f5e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/PlatformSpecificResetNotification.h
@@ -0,0 +1,26 @@
+/** @file
+ This PPI provides services to register a platform specific notification callback for
+ ResetSystem(). The registered handlers are processed after
+ EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI notifications and before
+ EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PPI notifications.
+
+ Copyright (c) 2017 - 2018 Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017 Microsoft Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI_H_
+#define _PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI_H_
+
+#include <Protocol/ResetNotification.h>
+
+#define EDKII_PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI_GUID \
+ { 0xe09f355d, 0xdae8, 0x4910, { 0xb1, 0x4a, 0x92, 0x78, 0x0f, 0xdc, 0xf7, 0xcb } }
+
+typedef EFI_RESET_NOTIFICATION_PROTOCOL EDKII_PLATFORM_SPECIFIC_RESET_NOTIFICATION_PPI;
+
+extern EFI_GUID gEdkiiPlatformSpecificResetNotificationPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/PostBootScriptTable.h b/roms/edk2/MdeModulePkg/Include/Ppi/PostBootScriptTable.h
new file mode 100644
index 000000000..09327c0d5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/PostBootScriptTable.h
@@ -0,0 +1,20 @@
+/** @file
+ POST BootScript Table PPI definition.
+
+ This PPI is used to be notification after boot script table execution.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_POST_BOOT_SCRIPT_TABLE_H_
+#define _PEI_POST_BOOT_SCRIPT_TABLE_H_
+
+#define PEI_POST_BOOT_SCRIPT_TABLE_PPI_GUID \
+ {0x88c9d306, 0x900, 0x4eb5, 0x82, 0x60, 0x3e, 0x2d, 0xbe, 0xda, 0x1f, 0x89};
+
+extern EFI_GUID gPeiPostScriptTablePpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SdMmcHostController.h b/roms/edk2/MdeModulePkg/Include/Ppi/SdMmcHostController.h
new file mode 100644
index 000000000..f224f2546
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SdMmcHostController.h
@@ -0,0 +1,57 @@
+/** @file
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_
+#define _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_
+
+///
+/// Global ID for the EDKII_SD_MMC_HOST_CONTROLLER_PPI.
+///
+#define EDKII_SD_MMC_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 } \
+ }
+
+///
+/// Forward declaration for the SD_MMC_HOST_CONTROLLER_PPI.
+///
+typedef struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI EDKII_SD_MMC_HOST_CONTROLLER_PPI;
+
+/**
+ Get the MMIO base address of SD/MMC host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the SD/MMC host controller.
+ @param[in,out] MmioBar The pointer to store the array of available
+ SD/MMC host controller slot MMIO base addresses.
+ The entry number of the array is specified by BarNum.
+ @param[out] BarNum The pointer to store the supported bar number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_SD_MMC_HC_GET_MMIO_BAR)(
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ IN OUT UINTN **MmioBar,
+ OUT UINT8 *BarNum
+ );
+
+///
+/// This PPI contains a set of services to interact with the SD_MMC host controller.
+///
+struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI {
+ EDKII_SD_MMC_HC_GET_MMIO_BAR GetSdMmcHcMmioBar;
+};
+
+extern EFI_GUID gEdkiiPeiSdMmcHostControllerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SecPerformance.h b/roms/edk2/MdeModulePkg/Include/Ppi/SecPerformance.h
new file mode 100644
index 000000000..cbdaccdb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SecPerformance.h
@@ -0,0 +1,60 @@
+/** @file
+ Defines the interface to convey performance information from SEC phase to PEI.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_SEC_PERFORMANCE_PPI_H_
+#define _PEI_SEC_PERFORMANCE_PPI_H_
+
+#define PEI_SEC_PERFORMANCE_PPI_GUID \
+ { \
+ 0x0ecc666b, 0x4662, 0x47f9, {0x9d, 0xd5, 0xd0, 0x96, 0xff, 0x7d, 0xa4, 0x9e } \
+ }
+
+typedef struct _PEI_SEC_PERFORMANCE_PPI PEI_SEC_PERFORMANCE_PPI;
+
+///
+/// Performance data collected in SEC phase.
+///
+typedef struct {
+ UINT64 ResetEnd; ///< Timer value logged at the beginning of firmware image execution, in unit of nanosecond.
+} FIRMWARE_SEC_PERFORMANCE;
+
+/**
+ This interface conveys performance information out of the Security (SEC) phase into PEI.
+
+ This service is published by the SEC phase. The SEC phase handoff has an optional
+ EFI_PEI_PPI_DESCRIPTOR list as its final argument when control is passed from SEC into the
+ PEI Foundation. As such, if the platform supports collecting performance data in SEC,
+ this information is encapsulated into the data structure abstracted by this service.
+ This information is collected for the boot-strap processor (BSP) on IA-32.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_SEC_PERFORMANCE_PPI.
+ @param[out] Performance The pointer to performance data collected in SEC phase.
+
+ @retval EFI_SUCCESS The performance data was successfully returned.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *GET_SEC_PERFORMANCE) (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SEC_PERFORMANCE_PPI *This,
+ OUT FIRMWARE_SEC_PERFORMANCE *Performance
+ );
+
+///
+/// This PPI provides function to get performance data collected in SEC phase.
+///
+struct _PEI_SEC_PERFORMANCE_PPI {
+ GET_SEC_PERFORMANCE GetPerformance;
+};
+
+extern EFI_GUID gPeiSecPerformancePpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SerialPortPei.h b/roms/edk2/MdeModulePkg/Include/Ppi/SerialPortPei.h
new file mode 100644
index 000000000..001611492
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SerialPortPei.h
@@ -0,0 +1,20 @@
+/** @file
+ PPI that is installed after the initialization of a serial stream device
+ is complete.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PEI_SERIAL_PORT_PPI_H__
+#define __PEI_SERIAL_PORT_PPI_H__
+
+#define PEI_SERIAL_PORT_PPI \
+ { \
+ 0x490e9d85, 0x8aef, 0x4193, { 0x8e, 0x56, 0xf7, 0x34, 0xa9, 0xff, 0xac, 0x8b } \
+ }
+
+extern EFI_GUID gPeiSerialPortPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SmmAccess.h b/roms/edk2/MdeModulePkg/Include/Ppi/SmmAccess.h
new file mode 100644
index 000000000..b920f599c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SmmAccess.h
@@ -0,0 +1,139 @@
+/** @file
+ EFI SMM Access PPI definition.
+
+ This PPI is used to control the visibility of the SMRAM on the platform.
+ It abstracts the location and characteristics of SMRAM. The expectation is
+ that the north bridge or memory controller would publish this PPI.
+
+ The principal functionality found in the memory controller includes the following:
+ - Exposing the SMRAM to all non-SMM agents, or the "open" state
+ - Shrouding the SMRAM to all but the SMM agents, or the "closed" state
+ - Preserving the system integrity, or "locking" the SMRAM, such that the settings cannot be
+ perturbed by either boot service or runtime agents
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_ACCESS_PPI_H_
+#define _SMM_ACCESS_PPI_H_
+
+#define PEI_SMM_ACCESS_PPI_GUID \
+ { 0x268f33a9, 0xcccd, 0x48be, { 0x88, 0x17, 0x86, 0x5, 0x3a, 0xc3, 0x2e, 0xd6 }}
+
+typedef struct _PEI_SMM_ACCESS_PPI PEI_SMM_ACCESS_PPI;
+
+/**
+ Opens the SMRAM area to be accessible by a PEIM driver.
+
+ This function "opens" SMRAM so that it is visible while not inside of SMM. The function should
+ return EFI_UNSUPPORTED if the hardware does not support hiding of SMRAM. The function
+ should return EFI_DEVICE_ERROR if the SMRAM configuration is locked.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The pointer to the SMM Access Interface.
+ @param DescriptorIndex The region of SMRAM to Open.
+
+ @retval EFI_SUCCESS The region was successfully opened.
+ @retval EFI_DEVICE_ERROR The region could not be opened because locked by chipset.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_OPEN)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Inhibits access to the SMRAM.
+
+ This function "closes" SMRAM so that it is not visible while outside of SMM. The function should
+ return EFI_UNSUPPORTED if the hardware does not support hiding of SMRAM.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The pointer to the SMM Access Interface.
+ @param DescriptorIndex The region of SMRAM to Close.
+
+ @retval EFI_SUCCESS The region was successfully closed.
+ @retval EFI_DEVICE_ERROR The region could not be closed because locked by chipset.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_CLOSE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Inhibits access to the SMRAM.
+
+ This function prohibits access to the SMRAM region. This function is usually implemented such
+ that it is a write-once operation.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The pointer to the SMM Access Interface.
+ @param DescriptorIndex The region of SMRAM to Close.
+
+ @retval EFI_SUCCESS The region was successfully locked.
+ @retval EFI_DEVICE_ERROR The region could not be locked because at least
+ one range is still open.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_LOCK)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Queries the memory controller for the possible regions that will support SMRAM.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The pointer to the SmmAccessPpi Interface.
+ @param SmramMapSize The pointer to the variable containing size of the
+ buffer to contain the description information.
+ @param SmramMap The buffer containing the data describing the Smram
+ region descriptors.
+
+ @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buffer.
+ @retval EFI_SUCCESS The user provided a sufficiently-sized buffer.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_CAPABILITIES)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN OUT UINTN *SmramMapSize,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
+ );
+
+///
+/// EFI SMM Access PPI is used to control the visibility of the SMRAM on the platform.
+/// It abstracts the location and characteristics of SMRAM. The platform should report
+/// all MMRAM via PEI_SMM_ACCESS_PPI. The expectation is that the north bridge or
+/// memory controller would publish this PPI.
+///
+struct _PEI_SMM_ACCESS_PPI {
+ PEI_SMM_OPEN Open;
+ PEI_SMM_CLOSE Close;
+ PEI_SMM_LOCK Lock;
+ PEI_SMM_CAPABILITIES GetCapabilities;
+ BOOLEAN LockState;
+ BOOLEAN OpenState;
+};
+
+extern EFI_GUID gPeiSmmAccessPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SmmCommunication.h b/roms/edk2/MdeModulePkg/Include/Ppi/SmmCommunication.h
new file mode 100644
index 000000000..30922cf32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SmmCommunication.h
@@ -0,0 +1,57 @@
+/** @file
+ EFI SMM Communication PPI definition.
+
+ This Ppi provides a means of communicating between PEIM and SMI
+ handlers inside of SMM.
+ This Ppi is produced and consumed only in S3 resume boot path.
+ It is NOT available in normal boot path.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _SMM_COMMUNICATION_PPI_H_
+#define _SMM_COMMUNICATION_PPI_H_
+
+#define EFI_PEI_SMM_COMMUNICATION_PPI_GUID \
+ { \
+ 0xae933e1c, 0xcc47, 0x4e38, { 0x8f, 0xe, 0xe2, 0xf6, 0x1d, 0x26, 0x5, 0xdf } \
+ }
+
+typedef struct _EFI_PEI_SMM_COMMUNICATION_PPI EFI_PEI_SMM_COMMUNICATION_PPI;
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered UEFI service.
+
+ @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
+ @param[in] CommBuffer A pointer to the buffer to convey into SMRAM.
+ @param[in] CommSize The size of the data buffer being passed in.On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PEI_SMM_COMMUNICATE)(
+ IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize
+ );
+
+///
+/// EFI SMM Communication Protocol provides runtime services for communicating
+/// between DXE drivers and a registered SMI handler.
+///
+struct _EFI_PEI_SMM_COMMUNICATION_PPI {
+ EFI_PEI_SMM_COMMUNICATE Communicate;
+};
+
+extern EFI_GUID gEfiPeiSmmCommunicationPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/SmmControl.h b/roms/edk2/MdeModulePkg/Include/Ppi/SmmControl.h
new file mode 100644
index 000000000..855cfec6b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/SmmControl.h
@@ -0,0 +1,89 @@
+/** @file
+ EFI SMM Control PPI definition.
+
+ This PPI is used to initiate SMI/PMI activations. This protocol could be published by either:
+ - A processor driver to abstract the SMI/PMI IPI
+ - The driver that abstracts the ASIC that is supporting the APM port, such as the ICH in an
+ Intel chipset
+ Because of the possibility of performing SMI or PMI IPI transactions, the ability to generate this
+ event from a platform chipset agent is an optional capability for both IA-32 and Itanium-based
+ systems.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _SMM_CONTROL_PPI_H_
+#define _SMM_CONTROL_PPI_H_
+
+#define PEI_SMM_CONTROL_PPI_GUID \
+ { 0x61c68702, 0x4d7e, 0x4f43, 0x8d, 0xef, 0xa7, 0x43, 0x5, 0xce, 0x74, 0xc5 }
+
+typedef struct _PEI_SMM_CONTROL_PPI PEI_SMM_CONTROL_PPI;
+
+/**
+ Invokes SMI activation from either the preboot or runtime environment.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The PEI_SMM_CONTROL_PPI instance.
+ @param ArgumentBuffer The optional sized data to pass into the protocol activation.
+ @param ArgumentBufferSize The optional size of the data.
+ @param Periodic An optional mechanism to periodically repeat activation.
+ @param ActivationInterval An optional parameter to repeat at this period one
+ time or, if the Periodic Boolean is set, periodically.
+
+ @retval EFI_SUCCESS The SMI/PMI has been engendered.
+ @retval EFI_DEVICE_ERROR The timing is unsupported.
+ @retval EFI_INVALID_PARAMETER The activation period is unsupported.
+ @retval EFI_NOT_STARTED The SMM base service has not been initialized.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_ACTIVATE) (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI * This,
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN UINTN ActivationInterval OPTIONAL
+ );
+
+/**
+ Clears any system state that was created in response to the Active call.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param This The PEI_SMM_CONTROL_PPI instance.
+ @param Periodic Optional parameter to repeat at this period one
+ time or, if the Periodic Boolean is set, periodically.
+
+ @retval EFI_SUCCESS The SMI/PMI has been engendered.
+ @retval EFI_DEVICE_ERROR The source could not be cleared.
+ @retval EFI_INVALID_PARAMETER The service did not support the Periodic input argument.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_DEACTIVATE) (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI * This,
+ IN BOOLEAN Periodic OPTIONAL
+ );
+
+///
+/// PEI SMM Control PPI is used to initiate SMI/PMI activations. This protocol could be published by either:
+/// - A processor driver to abstract the SMI/PMI IPI
+/// - The driver that abstracts the ASIC that is supporting the APM port, such as the ICH in an
+/// Intel chipset
+///
+struct _PEI_SMM_CONTROL_PPI {
+ PEI_SMM_ACTIVATE Trigger;
+ PEI_SMM_DEACTIVATE Clear;
+};
+
+extern EFI_GUID gPeiSmmControlPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h b/roms/edk2/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h
new file mode 100644
index 000000000..89c7edea9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h
@@ -0,0 +1,277 @@
+/** @file
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_STORAGE_SECURITY_COMMAND_PPI_H_
+#define _EDKII_STORAGE_SECURITY_COMMAND_PPI_H_
+
+#include <Protocol/DevicePath.h>
+
+///
+/// Global ID for the EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
+///
+#define EDKII_PEI_STORAGE_SECURITY_CMD_PPI_GUID \
+ { \
+ 0x35de0b4e, 0x30fb, 0x46c3, { 0xbd, 0x84, 0x1f, 0xdb, 0xa1, 0x58, 0xbb, 0x56 } \
+ }
+
+//
+// Forward declaration for the EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
+//
+typedef struct _EDKII_PEI_STORAGE_SECURITY_CMD_PPI EDKII_PEI_STORAGE_SECURITY_CMD_PPI;
+
+//
+// Revision The revision to which the Storage Security Command interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_STORAGE_SECURITY_PPI_REVISION 0x00010000
+
+
+/**
+ Gets the count of storage security devices that one specific driver detects.
+
+ @param[in] This The PPI instance pointer.
+ @param[out] NumberofDevices The number of storage security devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_GET_NUMBER_DEVICES) (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ OUT UINTN *NumberofDevices
+ );
+
+/**
+ Gets the device path of a specific storage security device.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which
+ the function wants to talk. Because the driver
+ that implements Storage Security Command PPIs
+ will manage multiple storage 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 NumberofDevices.
+ @param[out] DevicePathLength The length of the device path in bytes specified
+ by DevicePath.
+ @param[out] DevicePath The device path of storage security device.
+ This field re-uses EFI Device Path Protocol as
+ defined by Section 10.2 EFI Device Path Protocol
+ of UEFI 2.7 Specification.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
+ @retval EFI_NOT_FOUND The specified storage security device not found.
+ @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_GET_DEVICE_PATH) (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT UINTN *DevicePathLength,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given DeviceIndex.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex Specifies the storage security device to which the
+ function wants to talk. Because the driver that
+ implements Storage Security Command PPIs will manage
+ multiple storage 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 NumberofDevices.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize
+ Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command. The caller is
+ responsible for having either implicit or explicit
+ ownership of the buffer.
+ @param[out] PayloadTransferSize
+ A pointer to a buffer to store the size in bytes
+ of the data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed
+ successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to
+ store the available data from the device.
+ The PayloadBuffer contains the truncated
+ data.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support
+ security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed
+ with an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize
+ is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the
+ security protocol command to execute.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_RECEIVE_DATA) (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is
+ sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is
+ sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command
+ is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given DeviceIndex does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error,
+ the functio shall return EFI_DEVICE_ERROR.
+
+ @param[in] This The PPI instance pointer.
+ @param[in] DeviceIndex The ID of the device.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value
+ of 0 means that this function will wait indefinitely
+ for the security protocol command to execute. If
+ Timeout is greater than zero, then this function
+ will return EFI_TIMEOUT if the time required to
+ execute the receive data command is greater than
+ Timeout.
+ @param[in] SecurityProtocolId
+ The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData
+ The value of the "Security Protocol Specific"
+ parameter of the security protocol command to be
+ sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[in] PayloadBuffer A pointer to a destination buffer to store the
+ security protocol command specific payload data
+ for the security protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given DeviceIndex does not support security
+ protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with
+ an error.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize
+ is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_SEND_DATA) (
+ IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *This,
+ IN UINTN DeviceIndex,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+//
+// EDKII_PEI_STORAGE_SECURITY_CMD_PPI contains a set of services to send security
+// protocol commands to a mass storage device. Two types of security protocol
+// commands are supported. SendData sends a command with data to a device.
+// ReceiveData sends a command that receives data and/or the result of one or
+// more commands sent by SendData.
+//
+struct _EDKII_PEI_STORAGE_SECURITY_CMD_PPI {
+ UINT64 Revision;
+ EDKII_PEI_STORAGE_SECURITY_GET_NUMBER_DEVICES GetNumberofDevices;
+ EDKII_PEI_STORAGE_SECURITY_GET_DEVICE_PATH GetDevicePath;
+ EDKII_PEI_STORAGE_SECURITY_RECEIVE_DATA ReceiveData;
+ EDKII_PEI_STORAGE_SECURITY_SEND_DATA SendData;
+};
+
+extern EFI_GUID gEdkiiPeiStorageSecurityCommandPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/UfsHostController.h b/roms/edk2/MdeModulePkg/Include/Ppi/UfsHostController.h
new file mode 100644
index 000000000..84ee785ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/UfsHostController.h
@@ -0,0 +1,53 @@
+/** @file
+
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EDKII_PEI_UFS_HOST_CONTROLLER_PPI_H_
+#define _EDKII_PEI_UFS_HOST_CONTROLLER_PPI_H_
+
+///
+/// Global ID for the EDKII_UFS_HOST_CONTROLLER_PPI.
+///
+#define EDKII_UFS_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0xdc54b283, 0x1a77, 0x4cd6, { 0x83, 0xbb, 0xfd, 0xda, 0x46, 0x9a, 0x2e, 0xc6 } \
+ }
+
+///
+/// Forward declaration for the UFS_HOST_CONTROLLER_PPI.
+///
+typedef struct _EDKII_UFS_HOST_CONTROLLER_PPI EDKII_UFS_HOST_CONTROLLER_PPI;
+
+/**
+ Get the MMIO base address of UFS host controller.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] ControllerId The ID of the UFS host controller.
+ @param[out] MmioBar Pointer to the UFS host controller MMIO base address.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_GET_MMIO_BAR)(
+ IN EDKII_UFS_HOST_CONTROLLER_PPI *This,
+ IN UINT8 ControllerId,
+ OUT UINTN *MmioBar
+ );
+
+///
+/// This PPI contains a set of services to interact with the UFS host controller.
+///
+struct _EDKII_UFS_HOST_CONTROLLER_PPI {
+ EDKII_UFS_HC_GET_MMIO_BAR GetUfsHcMmioBar;
+};
+
+extern EFI_GUID gEdkiiPeiUfsHostControllerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/Usb2HostController.h b/roms/edk2/MdeModulePkg/Include/Ppi/Usb2HostController.h
new file mode 100644
index 000000000..f93af9ae0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/Usb2HostController.h
@@ -0,0 +1,262 @@
+/** @file
+ Defines the USB Host Controller PPI that provides I/O services for a USB Host
+ Controller that may be used to access recovery devices. These interfaces are
+ modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.
+ Refer to section 16.1 of the UEFI 2.3 Specification for more information on
+ these interfaces.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB2_HOST_CONTROLLER_PPI_H_
+#define _PEI_USB2_HOST_CONTROLLER_PPI_H_
+
+#include <Protocol/Usb2HostController.h>
+
+///
+/// Global ID for the PEI_USB2_HOST_CONTROLLER_PPI.
+///
+#define PEI_USB2_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0xa7d09fe1, 0x74d4, 0x4ba5, { 0x84, 0x7c, 0x12, 0xed, 0x5b, 0x19, 0xad, 0xe4 } \
+ }
+
+///
+/// Forward declaration for the PEI_USB2_HOST_CONTROLLER_PPI.
+///
+typedef struct _PEI_USB2_HOST_CONTROLLER_PPI PEI_USB2_HOST_CONTROLLER_PPI;
+
+/**
+ Initiate a USB control transfer using a specific USB Host controller on the USB bus.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[in] DeviceAddress Represents the address of the target device
+ on the USB.
+ @param[in] DeviceSpeed Indicates device speed.
+ @param[in] MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer
+ endpoint is capable of sending or receiving.
+ @param[in] Request A pointer to the USB device request that
+ will be sent to the USB device.
+ @param[in] TransferDirection Specifies the data direction for the transfer.
+ There are three values available:
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.
+ @param[in,out] Data A pointer to the buffer of data that will
+ be transmitted to USB device or
+ received from USB device.
+ @param[in,out] DataLength On input, indicates the size, in bytes, of
+ the data buffer specified by Data.
+ On output, indicates the amount of data
+ actually transferred.
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,
+ that the transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for
+ the function to be completed until EFI_SUCCESS
+ or EFI_DEVICE_ERROR is returned.
+ @param[in] Translator A pointer to the transaction translator data.
+ @param[out] TransferResult A pointer to the detailed result information
+ generated by this control transfer.
+
+ @retval EFI_SUCCESS The control transfer was completed successfully.
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller
+ or device error.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Initiate a USB bulk transfer using a specific USB Host controller on the USB bus.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[in] DeviceAddress Represents the address of the target device
+ on the USB.
+ @param[in] EndPointAddress The combination of an endpoint number and
+ an endpoint direction of the target USB device.
+ @param[in] DeviceSpeed Indicates device speed.
+ @param[in] MaximumPacketLength Indicates the maximum packet size the target
+ endpoint is capable of sending or receiving.
+ @param[in,out] Data Array of pointers to the buffers of data
+ that will be transmitted to USB device or
+ received from USB device.
+ @param[in,out] DataLength When input, indicates the size, in bytes, of
+ the data buffers specified by Data. When output,
+ indicates the data size actually transferred.
+ @param[in,out] DataToggle A pointer to the data toggle value.
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,
+ in which the transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for
+ the function to be completed until EFI_SUCCESS
+ or EFI_DEVICE_ERROR is returned.
+ @param[in] Translator A pointer to the transaction translator data.
+ @param[out] TransferResult A pointer to the detailed result information
+ of the bulk transfer.
+
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
+ Caller should check TransferResult for detailed error information.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to a lack of resources.
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINTN MaximumPacketLength,
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ );
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port from which the status is
+ to be retrieved.
+ This value is zero based.
+ @param[out] PortStatus A pointer to the current port status bits and port
+ status change bits.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified by
+ PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port whose feature is requested
+ to be set. This value is zero based.
+ @param[in] PortFeature Indicates the feature selector associated with the feature
+ set request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for
+ the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid
+ for this function.
+ @retval EFI_TIMEOUT The time out occurred
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB2_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param[in] PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @return EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+///
+/// This PPI contains a set of services to interact with the USB host controller.
+/// These interfaces are modeled on the UEFI 2.3 specification protocol
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL. Refer to section 16.1 of the UEFI 2.3
+/// Specification for more information on these interfaces.
+///
+struct _PEI_USB2_HOST_CONTROLLER_PPI {
+ PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER ControlTransfer;
+ PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER BulkTransfer;
+ PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER GetRootHubPortNumber;
+ PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS GetRootHubPortStatus;
+ PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE SetRootHubPortFeature;
+ PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE ClearRootHubPortFeature;
+};
+
+extern EFI_GUID gPeiUsb2HostControllerPpiGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/UsbController.h b/roms/edk2/MdeModulePkg/Include/Ppi/UsbController.h
new file mode 100644
index 000000000..664c7a21a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/UsbController.h
@@ -0,0 +1,87 @@
+/** @file
+ Define APIs to retrieve USB Host Controller Info such as controller type and
+ I/O Port Base Address.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_CONTROLLER_PPI_H_
+#define _PEI_USB_CONTROLLER_PPI_H_
+
+///
+/// Global ID for the PEI_USB_CONTROLLER_PPI.
+///
+#define PEI_USB_CONTROLLER_PPI_GUID \
+ { \
+ 0x3bc1f6de, 0x693e, 0x4547,{ 0xa3, 0x0, 0x21, 0x82, 0x3c, 0xa4, 0x20, 0xb2} \
+ }
+
+///
+/// Forward declaration for the PEI_USB_CONTROLLER_PPI.
+///
+typedef struct _PEI_USB_CONTROLLER_PPI PEI_USB_CONTROLLER_PPI;
+
+///
+/// This bit is used in the ControllerType return parameter of GetUsbController()
+/// to identify the USB Host Controller type as UHCI
+///
+#define PEI_UHCI_CONTROLLER 0x01
+
+///
+/// This bit is used in the ControllerType return parameter of GetUsbController()
+/// to identify the USB Host Controller type as OHCI
+///
+#define PEI_OHCI_CONTROLLER 0x02
+
+///
+/// This bit is used in the ControllerType return parameter of GetUsbController()
+/// to identify the USB Host Controller type as EHCI
+///
+#define PEI_EHCI_CONTROLLER 0x03
+
+///
+/// This bit is used in the ControllerType return parameter of GetUsbController()
+/// to identify the USB Host Controller type as XHCI
+///
+#define PEI_XHCI_CONTROLLER 0x04
+
+/**
+ Retrieve USB Host Controller Info such as controller type and I/O Base Address.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_CONTROLLER_PPI.
+ @param[in] ControllerId The ID of the USB controller.
+ @param[out] ControllerType On output, returns the type of the USB controller.
+ @param[out] BaseAddress On output, returns the base address of UHCI's I/O ports
+ if UHCI is enabled or the base address of EHCI's MMIO
+ if EHCI is enabled.
+
+ @retval EFI_SUCCESS USB controller attributes were returned successfully.
+ @retval EFI_INVALID_PARAMETER ControllerId is greater than the maximum number
+ of USB controller supported by this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_GET_USB_CONTROLLER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_CONTROLLER_PPI *This,
+ IN UINT8 UsbControllerId,
+ OUT UINTN *ControllerType,
+ OUT UINTN *BaseAddress
+ );
+
+///
+/// This PPI contains a single service to retrieve the USB Host Controller type
+/// and the base address of the I/O ports used to access the USB Host Controller.
+///
+struct _PEI_USB_CONTROLLER_PPI {
+ PEI_GET_USB_CONTROLLER GetUsbController;
+};
+
+extern EFI_GUID gPeiUsbControllerPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/UsbHostController.h b/roms/edk2/MdeModulePkg/Include/Ppi/UsbHostController.h
new file mode 100644
index 000000000..4dbdb4456
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/UsbHostController.h
@@ -0,0 +1,250 @@
+/** @file
+ Defines the USB Host Controller PPI that provides I/O services for a USB Host
+ Controller that may be used to access recovery devices. These interfaces are
+ modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.
+ Refer to section 16.1 of the UEFI 2.3 Specification for more information on
+ these interfaces.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_HOST_CONTROLLER_PPI_H_
+#define _PEI_USB_HOST_CONTROLLER_PPI_H_
+
+#include <Protocol/Usb2HostController.h>
+
+///
+/// Global ID for the PEI_USB_HOST_CONTROLLER_PPI.
+///
+#define PEI_USB_HOST_CONTROLLER_PPI_GUID \
+ { \
+ 0x652b38a9, 0x77f4, 0x453f, { 0x89, 0xd5, 0xe7, 0xbd, 0xc3, 0x52, 0xfc, 0x53} \
+ }
+
+///
+/// Forward declaration for the PEI_USB_HOST_CONTROLLER_PPI.
+///
+typedef struct _PEI_USB_HOST_CONTROLLER_PPI PEI_USB_HOST_CONTROLLER_PPI;
+
+/**
+ Initiate a USB control transfer using a specific USB Host controller on the USB bus.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[in] DeviceAddress Represents the address of the target device
+ on the USB.
+ @param[in] DeviceSpeed Indicates device speed.
+ @param[in] MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer
+ endpoint is capable of sending or receiving.
+ @param[in] Request A pointer to the USB device request that
+ will be sent to the USB device.
+ @param[in] TransferDirection Specifies the data direction for the transfer.
+ There are three values available:
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.
+ @param[in,out] Data A pointer to the buffer of data that will
+ be transmitted to USB device or
+ received from USB device.
+ @param[in,out] DataLength On input, indicates the size, in bytes, of
+ the data buffer specified by Data.
+ On output, indicates the amount of data
+ actually transferred.
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,
+ that the transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for
+ the function to be completed until EFI_SUCCESS
+ or EFI_DEVICE_ERROR is returned.
+ @param[out] TransferResult A pointer to the detailed result information
+ generated by this control transfer.
+
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller
+ or device error.
+ @retval EFI_SUCCESS The control transfer was completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaximumPacketLength,
+ IN USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Initiate a USB bulk transfer using a specific USB Host controller on the USB bus.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[in] DeviceAddress Represents the address of the target device
+ on the USB.
+ @param[in] EndPointAddress The combination of an endpoint number and
+ an endpoint direction of the target USB device.
+ @param[in] MaximumPacketLength Indicates the maximum packet size the target
+ endpoint is capable of sending or receiving.
+ @param[in,out] Data Array of pointers to the buffers of data
+ that will be transmitted to USB device or
+ received from USB device.
+ @param[in,out] DataLength When input, indicates the size, in bytes, of
+ the data buffers specified by Data. When output,
+ indicates the data size actually transferred.
+ @param[in,out] DataToggle A pointer to the data toggle value.
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,
+ in which the transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for
+ the function to be completed until EFI_SUCCESS
+ or EFI_DEVICE_ERROR is returned.
+ @param[out] TransferResult A pointer to the detailed result information
+ of the bulk transfer.
+
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
+ Caller should check TransferResult for detailed error information.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_BULK_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[out] PortNumber The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to retrieve
+ the port number.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber
+ );
+
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port from which the status is
+ to be retrieved.
+ This value is zero based.
+ @param[out] PortStatus A pointer to the current port status bits and port
+ status change bits.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified by
+ PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+ Sets a feature for the specified root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port whose feature is requested
+ to be set. This value is zero based.
+ @param[in] PortFeature Indicates the feature selector associated with the feature
+ set request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for
+ the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid
+ for this function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[in] PortNumber Specifies the root hub port whose feature is
+ requested to be cleared.
+ @param[in] PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @return EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @return EFI_DEVICE_ERROR Can't read the register.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+///
+/// This PPI contains a set of services to interact with the USB host controller.
+/// These interfaces are modeled on the UEFI 2.3 specification protocol
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL. Refer to section 16.1 of the UEFI 2.3
+/// Specification for more information on these interfaces.
+///
+struct _PEI_USB_HOST_CONTROLLER_PPI {
+ PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER ControlTransfer;
+ PEI_USB_HOST_CONTROLLER_BULK_TRANSFER BulkTransfer;
+ PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER GetRootHubPortNumber;
+ PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS GetRootHubPortStatus;
+ PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE SetRootHubPortFeature;
+ PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE ClearRootHubPortFeature;
+};
+
+extern EFI_GUID gPeiUsbHostControllerPpiGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Ppi/UsbIo.h b/roms/edk2/MdeModulePkg/Include/Ppi/UsbIo.h
new file mode 100644
index 000000000..71f52f086
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Ppi/UsbIo.h
@@ -0,0 +1,189 @@
+/** @file
+ Defines the PEI_USB_IO_PPI that the USB-related PEIM can use for I/O operations
+ on the USB BUS. This interface enables recovery from a
+ USB-class storage device, such as USB CD/DVD, USB hard drive, or USB FLASH
+ drive. These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.
+ Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on
+ these interfaces.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_USB_IO_PPI_H_
+#define _PEI_USB_IO_PPI_H_
+
+#include <Protocol/Usb2HostController.h>
+
+///
+/// Global ID for the PEI_USB_IO_PPI.
+///
+#define PEI_USB_IO_PPI_GUID \
+ { \
+ 0x7c29785c, 0x66b9, 0x49fc, { 0xb7, 0x97, 0x1c, 0xa5, 0x55, 0xe, 0xf2, 0x83} \
+ }
+
+///
+/// Forward declaration for the PEI_USB_IO_PPI.
+///
+typedef struct _PEI_USB_IO_PPI PEI_USB_IO_PPI;
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.
+ @param[in] Request A pointer to the USB device request that will be
+ sent to the USB device.
+ @param[in] Direction Specifies the data direction for the transfer. There
+ are three values available:
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.
+ @param[in] Timeout Indicates the maximum time, in milliseconds, that
+ the transfer is allowed to complete.
+ If Timeout is 0, then the caller must wait for the
+ function to be completed until EFI_SUCCESS or
+ EFI_DEVICE_ERROR is returned.
+ @param[in,out] Data A pointer to the buffer of data that will be
+ transmitted to or received from the USB device.
+ @param[in] DataLength On input, indicates the size, in bytes, of the data
+ buffer specified by Data.
+
+ @retval EFI_SUCCESS The control transfer was completed successfully.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due
+ to a lack of resources.
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller
+ or device error.
+ Caller should check TransferResult for detailed
+ error information.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_CONTROL_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data OPTIONAL,
+ IN UINTN DataLength OPTIONAL
+ );
+
+/**
+ Submits bulk transfer to a target USB device.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.
+ @param[in] DeviceEndpoint The endpoint address.
+ @param[in] Data The data buffer to be transfered.
+ @param[in] DataLength The length of data buffer.
+ @param[in] Timeout The timeout for the transfer, in milliseconds.
+ If Timeout is 0, then the caller must wait for the
+ function to be completed until EFI_SUCCESS or
+ EFI_DEVICE_ERROR is returned.
+
+ @retval EFI_SUCCESS The bulk transfer completed successfully.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be completed due to
+ a lack of resources.
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller
+ or device error.
+ Caller should check TransferResult for detailed
+ error information.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_BULK_TRANSFER)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ );
+
+/**
+ Get interface descriptor from a USB device.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.
+ @param[in] InterfaceDescriptor The interface descriptor.
+
+ @retval EFI_SUCCESS The interface descriptor was returned.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_DEVICE_ERROR A device error occurred, the function failed to
+ get the interface descriptor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_GET_INTERFACE_DESCRIPTOR)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor
+ );
+
+/**
+ Get endpoint descriptor from a USB device.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.
+ @param[in] EndPointIndex The index of the end point.
+ @param[in] EndpointDescriptor The endpoint descriptor.
+
+ @retval EFI_SUCCESS The endpoint descriptor was returned.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_DEVICE_ERROR A device error occurred, the function failed to
+ get the endpoint descriptor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_GET_ENDPOINT_DESCRIPTOR)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This,
+ IN UINT8 EndpointIndex,
+ IN EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor
+ );
+
+/**
+ Issue a port reset to the device.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.
+
+ @retval EFI_SUCCESS The port reset was issued successfully.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_DEVICE_ERROR Device error occurred.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_USB_PORT_RESET)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_IO_PPI *This
+ );
+
+///
+/// This PPI contains a set of services to interact with the USB host controller.
+/// These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.
+/// Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on
+/// these interfaces.
+///
+struct _PEI_USB_IO_PPI {
+ PEI_USB_CONTROL_TRANSFER UsbControlTransfer;
+ PEI_USB_BULK_TRANSFER UsbBulkTransfer;
+ PEI_USB_GET_INTERFACE_DESCRIPTOR UsbGetInterfaceDescriptor;
+ PEI_USB_GET_ENDPOINT_DESCRIPTOR UsbGetEndpointDescriptor;
+ PEI_USB_PORT_RESET UsbPortReset;
+};
+
+extern EFI_GUID gPeiUsbIoPpiGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/AtaAtapiPolicy.h b/roms/edk2/MdeModulePkg/Include/Protocol/AtaAtapiPolicy.h
new file mode 100644
index 000000000..5013eefa9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/AtaAtapiPolicy.h
@@ -0,0 +1,53 @@
+/** @file
+ ATA ATAPI Policy protocol is produced by platform and consumed by AtaAtapiPassThruDxe
+ driver.
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __ATA_ATAPI_POLICY_H__
+#define __ATA_ATAPI_POLICY_H__
+
+#define EDKII_ATA_ATAPI_POLICY_PROTOCOL_GUID \
+ { \
+ 0xe59cd769, 0x5083, 0x4f26,{ 0x90, 0x94, 0x6c, 0x91, 0x9f, 0x91, 0x6c, 0x4e } \
+ }
+
+typedef struct {
+ ///
+ /// Protocol version.
+ ///
+ UINT32 Version;
+
+ ///
+ /// 0: Disable Power-up in Standby;
+ /// 1: Enable Power-up in Standby;
+ /// others: Since PUIS setting is non-volatile, platform can use other value than 0/1 to keep hardware PUIS setting.
+ ///
+ UINT8 PuisEnable;
+
+ ///
+ /// 0: Disable Device Sleep;
+ /// 1: Enable Device Sleep;
+ /// others: Ignored.
+ ///
+ UINT8 DeviceSleepEnable;
+
+ ///
+ /// 0: Disable Aggressive Device Sleep;
+ /// 1: Enable Aggressive Device Sleep;
+ /// others: Ignored.
+ ///
+ UINT8 AggressiveDeviceSleepEnable;
+
+ UINT8 Reserved;
+} EDKII_ATA_ATAPI_POLICY_PROTOCOL;
+
+#define EDKII_ATA_ATAPI_POLICY_VERSION 0x00010000
+
+
+extern EFI_GUID gEdkiiAtaAtapiPolicyProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo.h b/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo.h
new file mode 100644
index 000000000..5dfd7840b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo.h
@@ -0,0 +1,59 @@
+/** @file
+ Boot Logo protocol is used to convey information of Logo dispayed during boot.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_LOGO_H_
+#define _BOOT_LOGO_H_
+
+#include <Protocol/GraphicsOutput.h>
+
+#define EFI_BOOT_LOGO_PROTOCOL_GUID \
+ { \
+ 0xcdea2bd3, 0xfc25, 0x4c1c, { 0xb9, 0x7c, 0xb3, 0x11, 0x86, 0x6, 0x49, 0x90 } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_BOOT_LOGO_PROTOCOL EFI_BOOT_LOGO_PROTOCOL;
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param This The pointer to the Boot Logo protocol instance.
+ @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_BOOT_LOGO)(
+ IN EFI_BOOT_LOGO_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ );
+
+struct _EFI_BOOT_LOGO_PROTOCOL {
+ EFI_SET_BOOT_LOGO SetBootLogo;
+};
+
+extern EFI_GUID gEfiBootLogoProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo2.h b/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo2.h
new file mode 100644
index 000000000..b7b52d121
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/BootLogo2.h
@@ -0,0 +1,101 @@
+/** @file
+Boot Logo 2 Protocol is used to convey information of Logo dispayed during boot.
+
+The Boot Logo 2 Protocol is a replacement for the Boot Logo Protocol. If a
+platform produces both the Boot Logo 2 Protocol and the Boot Logo Protocol
+then the Boot Logo 2 Protocol must be used instead of the Boot Logo Protocol.
+
+Copyright (c) 2016, Microsoft Corporation
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_LOGO2_H_
+#define _BOOT_LOGO2_H_
+
+#include <Protocol/GraphicsOutput.h>
+
+#define EDKII_BOOT_LOGO2_PROTOCOL_GUID \
+ { \
+ 0x4b5dc1df, 0x1eaa, 0x48b2, { 0xa7, 0xe9, 0xea, 0xc4, 0x89, 0xa0, 0xb, 0x5c } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EDKII_BOOT_LOGO2_PROTOCOL EDKII_BOOT_LOGO2_PROTOCOL;
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param[in] This The pointer to the Boot Logo protocol 2 instance.
+ @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param[in] DestinationX X coordinate of destination for the BltBuffer.
+ @param[in] DestinationY Y coordinate of destination for the BltBuffer.
+ @param[in] Width Width of rectangle in BltBuffer in pixels.
+ @param[in] Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_SET_BOOT_LOGO2)(
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ );
+
+/**
+ Get the location of the boot logo on the screen.
+
+ @param[in] This The pointer to the Boot Logo Protocol 2 instance
+ @param[out] BltBuffer Returns pointer to the GOP BLT buffer that was
+ previously registered with SetBootLogo2(). The
+ buffer returned must not be modified or freed.
+ @param[out] DestinationX Returns the X start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] DestinationY Returns the Y start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Width Returns the width of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Height Returns the height of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+
+ @retval EFI_SUCCESS The location of the boot logo was returned.
+ @retval EFI_NOT_READY The boot logo has not been set.
+ @retval EFI_INVALID_PARAMETER BltBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationX is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationY is NULL.
+ @retval EFI_INVALID_PARAMETER Width is NULL.
+ @retval EFI_INVALID_PARAMETER Height is NULL.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_GET_BOOT_LOGO2)(
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
+ OUT UINTN *DestinationX,
+ OUT UINTN *DestinationY,
+ OUT UINTN *Width,
+ OUT UINTN *Height
+ );
+
+struct _EDKII_BOOT_LOGO2_PROTOCOL {
+ EDKII_SET_BOOT_LOGO2 SetBootLogo;
+ EDKII_GET_BOOT_LOGO2 GetBootLogo;
+};
+
+extern EFI_GUID gEdkiiBootLogo2ProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/DebuggerConfiguration.h b/roms/edk2/MdeModulePkg/Include/Protocol/DebuggerConfiguration.h
new file mode 100644
index 000000000..d91c90b32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/DebuggerConfiguration.h
@@ -0,0 +1,25 @@
+/** @file
+ EBC Debugger configuration protocol.
+
+ Copyright (c) 2007-2016, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_DEBUGGER_CONFIGURATION_H__
+#define __EFI_DEBUGGER_CONFIGURATION_H__
+
+#define EFI_DEBUGGER_CONFIGURATION_PROTOCOL_GUID \
+ { 0x577d959c, 0xe967, 0x4546, 0x86, 0x20, 0xc7, 0x78, 0xfa, 0xe5, 0xda, 0x5 }
+
+#define EFI_DEBUGGER_CONFIGURATION_VERSION 0x00000001
+
+typedef struct _EFI_DEBUGGER_CONFIGURATION_PROTOCOL {
+ UINT32 DebuggerConfigurationRevision;
+ VOID *DebuggerPrivateData;
+} EFI_DEBUGGER_CONFIGURATION_PROTOCOL;
+
+extern EFI_GUID gEfiDebuggerConfigurationProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/DeviceSecurity.h b/roms/edk2/MdeModulePkg/Include/Protocol/DeviceSecurity.h
new file mode 100644
index 000000000..c3bf624ca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/DeviceSecurity.h
@@ -0,0 +1,162 @@
+/** @file
+ Device Security Protocol definition.
+
+ It is used to authenticate a device based upon the platform policy.
+ It is similar to the EFI_SECURITY_ARCH_PROTOCOL, which is used to verify a image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __DEVICE_SECURITY_H__
+#define __DEVICE_SECURITY_H__
+
+//
+// Device Security Protocol GUID value
+//
+#define EDKII_DEVICE_SECURITY_PROTOCOL_GUID \
+ { \
+ 0x5d6b38c8, 0x5510, 0x4458, { 0xb4, 0x8d, 0x95, 0x81, 0xcf, 0xa7, 0xb0, 0xd } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EDKII_DEVICE_SECURITY_PROTOCOL EDKII_DEVICE_SECURITY_PROTOCOL;
+
+//
+// Revision The revision to which the DEVICE_SECURITY interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_DEVICE_SECURITY_PROTOCOL_REVISION 0x00010000
+
+//
+// The device identifier.
+//
+typedef struct {
+ ///
+ /// Version of this data structure.
+ ///
+ UINT32 Version;
+ ///
+ /// Type of the device.
+ /// This field is also served as a device Access protocol GUID.
+ /// The device access protocol is installed on the DeviceHandle.
+ /// The device access protocol is device specific.
+ /// EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID means the device access protocol is PciIo.
+ /// EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID means the device access protocol is UsbIo.
+ ///
+ EFI_GUID DeviceType;
+ ///
+ /// The handle created for this device.
+ /// NOTE: This might be a temporary handle.
+ /// If the device is not authenticated, this handle shall be uninstalled.
+ ///
+ /// As minimal requirement, there should be 2 protocols installed on the device handle.
+ /// 1) An EFI_DEVICE_PATH_PROTOCOL with EFI_DEVICE_PATH_PROTOCOL_GUID.
+ /// 2) A device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID.
+ /// If the device is PCI device, the EFI_PCI_IO_PROTOCOL is installed with
+ /// EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID.
+ /// If the device is USB device, the EFI_USB_IO_PROTOCOL is installed with
+ /// EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID.
+ ///
+ /// The device access protocol is required, because the verifier need have a way
+ /// to communciate with the device hardware to get the measurement or do the
+ /// challenge/response for the device authentication.
+ ///
+ /// NOTE: We don't use EFI_PCI_IO_PROTOCOL_GUID or EFI_USB_IO_PROTOCOL_GUID here,
+ /// because we don't want to expose a real protocol. A platform may have driver
+ /// register a protocol notify function. Installing a real protocol may cause
+ /// the callback function being executed before the device is authenticated.
+ ///
+ EFI_HANDLE DeviceHandle;
+} EDKII_DEVICE_IDENTIFIER;
+
+//
+// Revision The revision to which the DEVICE_IDENTIFIER interface adheres.
+// All future revisions must be backwards compatible.
+//
+#define EDKII_DEVICE_IDENTIFIER_REVISION 0x00010000
+
+//
+// Device Identifier GUID value
+//
+#define EDKII_DEVICE_IDENTIFIER_TYPE_PCI_GUID \
+ { \
+ 0x2509b2f1, 0xa022, 0x4cca, { 0xaf, 0x70, 0xf9, 0xd3, 0x21, 0xfb, 0x66, 0x49 } \
+ }
+
+#define EDKII_DEVICE_IDENTIFIER_TYPE_USB_GUID \
+ { \
+ 0x7394f350, 0x394d, 0x488c, { 0xbb, 0x75, 0xc, 0xab, 0x7b, 0x12, 0xa, 0xc5 } \
+ }
+
+/**
+ The device driver uses this service to measure and/or verify a device.
+
+ The flow in device driver is:
+ 1) Device driver discovers a new device.
+ 2) Device driver creates an EFI_DEVICE_PATH_PROTOCOL.
+ 3) Device driver creates a device access protocol. e.g.
+ EFI_PCI_IO_PROTOCOL for PCI device.
+ EFI_USB_IO_PROTOCOL for USB device.
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL for SCSI device.
+ EFI_ATA_PASS_THRU_PROTOCOL for ATA device.
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL for NVMe device.
+ EFI_SD_MMC_PASS_THRU_PROTOCOL for SD/MMC device.
+ 4) Device driver installs the EFI_DEVICE_PATH_PROTOCOL with EFI_DEVICE_PATH_PROTOCOL_GUID,
+ and the device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID.
+ Once it is done, a DeviceHandle is returned.
+ 5) Device driver creates EDKII_DEVICE_IDENTIFIER with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID
+ and the DeviceHandle.
+ 6) Device driver calls DeviceAuthenticate().
+ 7) If DeviceAuthenticate() returns EFI_SECURITY_VIOLATION, the device driver uninstalls
+ all protocols on this handle.
+ 8) If DeviceAuthenticate() returns EFI_SUCCESS, the device driver installs the device access
+ protocol with a real protocol GUID. e.g.
+ EFI_PCI_IO_PROTOCOL with EFI_PCI_IO_PROTOCOL_GUID.
+ EFI_USB_IO_PROTOCOL with EFI_USB_IO_PROTOCOL_GUID.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] DeviceId The Identifier for the device.
+
+ @retval EFI_SUCCESS The device specified by the DeviceId passed the measurement
+ and/or authentication based upon the platform policy.
+ If TCG measurement is required, the measurement is extended to TPM PCR.
+ @retval EFI_SECURITY_VIOLATION The device fails to return the measurement data.
+ @retval EFI_SECURITY_VIOLATION The device fails to response the authentication request.
+ @retval EFI_SECURITY_VIOLATION The system fails to verify the device based upon the authentication response.
+ @retval EFI_SECURITY_VIOLATION The system fails to extend the measurement to TPM PCR.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_DEVICE_AUTHENTICATE)(
+ IN EDKII_DEVICE_SECURITY_PROTOCOL *This,
+ IN EDKII_DEVICE_IDENTIFIER *DeviceId
+ );
+
+///
+/// Device Security Protocol structure.
+/// It is similar to the EFI_SECURITY_ARCH_PROTOCOL, which is used to verify a image.
+/// This protocol is used to authenticate a device based upon the platform policy.
+///
+struct _EDKII_DEVICE_SECURITY_PROTOCOL {
+ UINT64 Revision;
+ EDKII_DEVICE_AUTHENTICATE DeviceAuthenticate;
+};
+
+///
+/// Device Security Protocol GUID variable.
+///
+extern EFI_GUID gEdkiiDeviceSecurityProtocolGuid;
+
+///
+/// Device Identifier tpye GUID variable.
+///
+extern EFI_GUID gEdkiiDeviceIdentifierTypePciGuid;
+extern EFI_GUID gEdkiiDeviceIdentifierTypeUsbGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/DisplayProtocol.h b/roms/edk2/MdeModulePkg/Include/Protocol/DisplayProtocol.h
new file mode 100644
index 000000000..748ceed17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/DisplayProtocol.h
@@ -0,0 +1,352 @@
+/** @file
+ FormDiplay protocol to show Form
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DISPLAY_PROTOCOL_H__
+#define __DISPLAY_PROTOCOL_H__
+
+#include <Protocol/FormBrowser2.h>
+
+#define EDKII_FORM_DISPLAY_ENGINE_PROTOCOL_GUID \
+ { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } }
+
+//
+// Do nothing.
+//
+#define BROWSER_ACTION_NONE BIT16
+//
+// ESC Exit
+//
+#define BROWSER_ACTION_FORM_EXIT BIT17
+
+#define BROWSER_SUCCESS 0x0
+#define BROWSER_ERROR BIT31
+#define BROWSER_SUBMIT_FAIL BROWSER_ERROR | 0x01
+#define BROWSER_NO_SUBMIT_IF BROWSER_ERROR | 0x02
+#define BROWSER_FORM_NOT_FOUND BROWSER_ERROR | 0x03
+#define BROWSER_FORM_SUPPRESS BROWSER_ERROR | 0x04
+#define BROWSER_PROTOCOL_NOT_FOUND BROWSER_ERROR | 0x05
+#define BROWSER_INCONSISTENT_IF BROWSER_ERROR | 0x06
+#define BROWSER_WARNING_IF BROWSER_ERROR | 0x07
+#define BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF BROWSER_ERROR | 0x08
+#define BROWSER_RECONNECT_REQUIRED BROWSER_ERROR | 0x09
+#define BROWSER_RECONNECT_FAIL BROWSER_ERROR | 0x0A
+#define BROWSER_RECONNECT_SAVE_CHANGES BROWSER_ERROR | 0x0B
+
+#define FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1 0x10000
+#define FORM_DISPLAY_ENGINE_VERSION_1 0x10000
+
+typedef struct {
+ //
+ // HII Data Type
+ //
+ UINT8 Type;
+ //
+ // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING
+ //
+ UINT8 *Buffer;
+ UINT16 BufferLen;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_HII_VALUE;
+
+#define DISPLAY_QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ //
+ // OneOfOption Data
+ //
+ EFI_IFR_ONE_OF_OPTION *OptionOpCode;
+ //
+ // Option ImageId and AnimationId
+ //
+ EFI_IMAGE_ID ImageId;
+ EFI_ANIMATION_ID AnimationId;
+} DISPLAY_QUESTION_OPTION;
+
+#define DISPLAY_QUESTION_OPTION_FROM_LINK(a) CR (a, DISPLAY_QUESTION_OPTION, Link, DISPLAY_QUESTION_OPTION_SIGNATURE)
+
+typedef struct _FORM_DISPLAY_ENGINE_STATEMENT FORM_DISPLAY_ENGINE_STATEMENT;
+typedef struct _FORM_DISPLAY_ENGINE_FORM FORM_DISPLAY_ENGINE_FORM;
+
+#define STATEMENT_VALID 0x0
+#define STATEMENT_INVALID BIT31
+
+#define INCOSISTENT_IF_TRUE STATEMENT_INVALID | 0x01
+#define WARNING_IF_TRUE STATEMENT_INVALID | 0x02
+#define STRING_TOO_LONG STATEMENT_INVALID | 0x03
+// ... to be extended.
+
+typedef struct {
+ //
+ // StringId for INCONSITENT_IF or WARNING_IF
+ //
+ EFI_STRING_ID StringId;
+ //
+ // TimeOut for WARNING_IF
+ //
+ UINT8 TimeOut;
+} STATEMENT_ERROR_INFO;
+
+/**
+ Perform value check for a question.
+
+ @param Form Form where Statement is in.
+ @param Statement Value will check for it.
+ @param Value New value will be checked.
+
+ @retval Status Value Status
+
+**/
+typedef
+UINT32
+(EFIAPI *VALIDATE_QUESTION) (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_HII_VALUE *Value,
+ OUT STATEMENT_ERROR_INFO *ErrorInfo
+ );
+
+/**
+ Perform Password check.
+ Passwork may be encrypted by driver that requires the specific check.
+
+ @param Form Form where Password Statement is in.
+ @param Statement Password statement
+ @param PasswordString Password string to be checked. It may be NULL.
+ NULL means to restore password.
+ "" string can be used to checked whether old password does exist.
+
+ @return Status Status of Password check.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PASSWORD_CHECK) (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_STRING PasswordString OPTIONAL
+ );
+
+#define FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A')
+
+//
+// Attribute for Statement and Form
+//
+#define HII_DISPLAY_NONE 0
+#define HII_DISPLAY_GRAYOUT BIT0
+#define HII_DISPLAY_LOCK BIT1
+#define HII_DISPLAY_READONLY BIT2
+#define HII_DISPLAY_MODAL BIT3
+#define HII_DISPLAY_SUPPRESS BIT4
+
+struct _FORM_DISPLAY_ENGINE_STATEMENT{
+ UINTN Signature;
+ //
+ // Version for future structure extension
+ //
+ UINTN Version;
+ //
+ // link to all the statement which will show in the display form.
+ //
+ LIST_ENTRY DisplayLink;
+ //
+ // Pointer to statement opcode.
+ // for Guided Opcode. All buffers will be here if GUIDED opcode scope is set.
+ //
+ EFI_IFR_OP_HEADER *OpCode;
+ //
+ // Question CurrentValue
+ //
+ EFI_HII_VALUE CurrentValue;
+ //
+ // Flag to describe whether setting is changed or not.
+ // Displayer may depend on it to show it with the different color.
+ //
+ BOOLEAN SettingChangedFlag;
+ //
+ // nested Statement list inside of EFI_IFR_SUBTITLE
+ //
+ LIST_ENTRY NestStatementList;
+ //
+ // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
+ //
+ LIST_ENTRY OptionListHead;
+ //
+ // Statement attributes: GRAYOUT, LOCK and READONLY
+ //
+ UINT32 Attribute;
+
+ //
+ // ValidateQuestion to do InconsistIf check
+ // It may be NULL if any value is valid.
+ //
+ VALIDATE_QUESTION ValidateQuestion;
+
+ //
+ // Password additional check. It may be NULL when the additional check is not required.
+ //
+ PASSWORD_CHECK PasswordCheck;
+
+ //
+ // Statement ImageId and AnimationId
+ //
+ EFI_IMAGE_ID ImageId;
+ EFI_ANIMATION_ID AnimationId;
+};
+
+#define FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK(a) CR (a, FORM_DISPLAY_ENGINE_STATEMENT, DisplayLink, FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE)
+
+#define BROWSER_HOT_KEY_SIGNATURE SIGNATURE_32 ('B', 'H', 'K', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_INPUT_KEY *KeyData;
+ //
+ // Action is Discard, Default, Submit, Reset and Exit.
+ //
+ UINT32 Action;
+ UINT16 DefaultId;
+ //
+ // HotKey Help String
+ //
+ EFI_STRING HelpString;
+} BROWSER_HOT_KEY;
+
+#define BROWSER_HOT_KEY_FROM_LINK(a) CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE)
+
+#define FORM_DISPLAY_ENGINE_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M')
+
+struct _FORM_DISPLAY_ENGINE_FORM {
+ UINTN Signature;
+ //
+ // Version for future structure extension
+ //
+ UINTN Version;
+ //
+ // Statement List inside of Form
+ //
+ LIST_ENTRY StatementListHead;
+ //
+ // Statement List outside of Form
+ //
+ LIST_ENTRY StatementListOSF;
+ //
+ // The input screen dimenstions info.
+ //
+ EFI_SCREEN_DESCRIPTOR *ScreenDimensions;
+ //
+ // FormSet information
+ //
+ EFI_GUID FormSetGuid;
+ //
+ // HiiHandle can be used to get String, Image or Animation
+ //
+ EFI_HII_HANDLE HiiHandle;
+
+ //
+ // Form ID and Title.
+ //
+ UINT16 FormId;
+ EFI_STRING_ID FormTitle;
+ //
+ // Form Attributes: Lock, Modal.
+ //
+ UINT32 Attribute;
+ //
+ // Flag to describe whether setting is changed or not.
+ // Displayer depends on it to show ChangedFlag.
+ //
+ BOOLEAN SettingChangedFlag;
+
+ //
+ // Statement to be HighLighted
+ //
+ FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement;
+ //
+ // Event to notify Displayer that FormData is updated to be refreshed.
+ //
+ EFI_EVENT FormRefreshEvent;
+ //
+ // Additional Hotkey registered by BrowserEx protocol.
+ //
+ LIST_ENTRY HotKeyListHead;
+
+ //
+ // Form ImageId and AnimationId
+ //
+ EFI_IMAGE_ID ImageId;
+ EFI_ANIMATION_ID AnimationId;
+
+ //
+ // If Status is error, display needs to handle it.
+ //
+ UINT32 BrowserStatus;
+ //
+ // String for error status. It may be NULL.
+ //
+ EFI_STRING ErrorString;
+};
+
+#define FORM_DISPLAY_ENGINE_FORM_FROM_LINK(a) CR (a, FORM_DISPLAY_ENGINE_FORM, Link, FORM_DISPLAY_ENGINE_FORM_SIGNATURE)
+
+typedef struct {
+ FORM_DISPLAY_ENGINE_STATEMENT *SelectedStatement; // Selected Statement and InputValue
+
+ EFI_HII_VALUE InputValue;
+
+ UINT32 Action; // If SelectedStatement is NULL, Action will be used.
+ // Trig Action (Discard, Default, Submit, Reset and Exit)
+ UINT16 DefaultId;
+} USER_INPUT;
+
+/**
+ Display one form, and return user input.
+
+ @param FormData Form Data to be shown.
+ @param UserInputData User input data.
+
+ @retval EFI_SUCCESS Form Data is shown, and user input is got.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *FORM_DISPLAY) (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+);
+
+/**
+ Exit Display and Clear Screen to the original state.
+
+**/
+typedef
+VOID
+(EFIAPI *EXIT_DISPLAY) (
+ VOID
+);
+
+/**
+ Confirm how to handle the changed data.
+
+ @return Action of Submit, Discard and None
+**/
+typedef
+UINTN
+(EFIAPI *CONFIRM_DATA_CHANGE) (
+ VOID
+);
+
+typedef struct {
+ FORM_DISPLAY FormDisplay;
+ EXIT_DISPLAY ExitDisplay;
+ CONFIRM_DATA_CHANGE ConfirmDataChange;
+} EDKII_FORM_DISPLAY_ENGINE_PROTOCOL;
+
+extern EFI_GUID gEdkiiFormDisplayEngineProtocolGuid;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/EbcSimpleDebugger.h b/roms/edk2/MdeModulePkg/Include/Protocol/EbcSimpleDebugger.h
new file mode 100644
index 000000000..bb257826b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/EbcSimpleDebugger.h
@@ -0,0 +1,117 @@
+/** @file
+ EBC Simple Debugger protocol for debug EBC code.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_SIMPLE_DEBUGGER_PROTOCOL_H_
+#define _EBC_SIMPLE_DEBUGGER_PROTOCOL_H_
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/EbcVmTest.h>
+
+#define EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID \
+ { \
+ 0x2a72d11e, 0x7376, 0x40f6, { 0x9c, 0x68, 0x23, 0xfa, 0x2f, 0xe3, 0x63, 0xf1 } \
+ }
+
+//
+// Defines for a simple EBC debugger interface
+//
+typedef struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL;
+
+/**
+ Trig Exception on EBC VM.
+
+ @param[in] This A pointer to the EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL structure.
+ @param[in] VmPtr A pointer to a VM context.
+ @param[in] ExceptionType Exception to be trigged.
+
+ @retval EFI_UNSUPPORTED No support for it.
+ @retval EFI_SUCCESS Exception is trigged.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EBC_DEBUGGER_SIGNAL_EXCEPTION) (
+ IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Given a pointer to a new VM context, debug one or more instructions.
+
+ @param[in] This A pointer to the EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL structure.
+ @param[in] VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED No support for it.
+ @retval EFI_SUCCESS Debug one or more instructions.
+
+**/
+typedef
+VOID
+(EFIAPI *EBC_DEBUGGER_DEBUG) (
+ IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Given a pointer to a new VM context, dump one or more instructions.
+
+ @param[in] This A pointer to the EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL structure.
+ @param[in] VmPtr A pointer to a VM context.
+ @param[in] DasmString Dump string buffer.
+ @param[in] DasmStringSize Dump string size.
+
+ @retval EFI_UNSUPPORTED No support for it.
+ @retval EFI_SUCCESS Dump one or more instructions.
+
+**/
+typedef
+UINT32
+(EFIAPI *EBC_DEBUGGER_DASM) (
+ IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN UINT16 *DasmString OPTIONAL,
+ IN UINT32 DasmStringSize
+ );
+
+/**
+ This interface allows you to configure the EBC debug support
+ driver. For example, turn on or off saving and printing of
+ delta VM even if called. Or to even disable the entire interface,
+ in which case all functions become no-ops.
+
+ @param[in] This A pointer to the EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL structure.
+ @param[in] ConfigId ID to be configured.
+ @param[in] ConfigValue Value to be set.
+
+ @retval EFI_UNSUPPORTED No support for it.
+ @retval EFI_SUCCESS Configure EBC debug.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EBC_DEBUGGER_CONFIGURE) (
+ IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *This,
+ IN UINT32 ConfigId,
+ IN UINTN ConfigValue
+ );
+
+//
+// Prototype for the actual EBC debug support protocol interface
+//
+struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL {
+ EBC_DEBUGGER_DEBUG Debugger;
+ EBC_DEBUGGER_SIGNAL_EXCEPTION SignalException;
+ EBC_DEBUGGER_DASM Dasm;
+ EBC_DEBUGGER_CONFIGURE Configure;
+};
+
+extern EFI_GUID gEfiEbcSimpleDebuggerProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/EbcVmTest.h b/roms/edk2/MdeModulePkg/Include/Protocol/EbcVmTest.h
new file mode 100644
index 000000000..55628a209
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/EbcVmTest.h
@@ -0,0 +1,184 @@
+/** @file
+ EBC VM Test protocol for test purposes.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_VM_TEST_PROTOCOL_H_
+#define _EBC_VM_TEST_PROTOCOL_H_
+
+//
+// Define a protocol for an EBC VM test interface.
+//
+#define EFI_EBC_VM_TEST_PROTOCOL_GUID \
+ { \
+ 0xAAEACCFD, 0xF27B, 0x4C17, { 0xB6, 0x10, 0x75, 0xCA, 0x1F, 0x2D, 0xFB, 0x52 } \
+ }
+
+//
+// Define for forward reference.
+//
+typedef struct _EFI_EBC_VM_TEST_PROTOCOL EFI_EBC_VM_TEST_PROTOCOL;
+
+//
+// VM major/minor version
+//
+#define VM_MAJOR_VERSION 1
+#define VM_MINOR_VERSION 0
+
+//
+// Bits in the VM->StopFlags field
+//
+#define STOPFLAG_APP_DONE 0x0001
+#define STOPFLAG_BREAKPOINT 0x0002
+#define STOPFLAG_INVALID_BREAK 0x0004
+#define STOPFLAG_BREAK_ON_CALLEX 0x0008
+
+//
+// Masks for working with the VM flags register
+//
+#define VMFLAGS_CC 0x0001 // condition flag
+#define VMFLAGS_STEP 0x0002 // step instruction mode
+#define VMFLAGS_ALL_VALID (VMFLAGS_CC | VMFLAGS_STEP)
+
+//
+// Macros for operating on the VM flags register
+//
+#define VMFLAG_SET(pVM, Flag) (pVM->Flags |= (Flag))
+#define VMFLAG_ISSET(pVM, Flag) ((pVM->Flags & (Flag)) ? 1 : 0)
+#define VMFLAG_CLEAR(pVM, Flag) (pVM->Flags &= ~(Flag))
+
+//
+// Define a macro to get the operand. Then we can change it to be either a
+// direct read or have it call a function to read memory.
+//
+#define GETOPERANDS(pVM) (UINT8) (*(UINT8 *) (pVM->Ip + 1))
+#define GETOPCODE(pVM) (UINT8) (*(UINT8 *) pVM->Ip)
+
+//
+// Macros for operating on the VM GP registers
+//
+#define OPERAND1_REGDATA(pVM, Op) pVM->Gpr[OPERAND1_REGNUM (Op)]
+#define OPERAND2_REGDATA(pVM, Op) pVM->Gpr[OPERAND2_REGNUM (Op)]
+
+//
+// Bits of exception flags field of VM context
+//
+#define EXCEPTION_FLAG_FATAL 0x80000000 // can't continue
+#define EXCEPTION_FLAG_ERROR 0x40000000 // bad, but try to continue
+#define EXCEPTION_FLAG_WARNING 0x20000000 // harmless problem
+#define EXCEPTION_FLAG_NONE 0x00000000 // for normal return
+
+///
+/// instruction pointer for the VM
+///
+typedef UINT8 *VMIP;
+
+typedef INT64 VM_REGISTER;
+typedef UINT32 EXCEPTION_FLAGS;
+
+typedef struct {
+ VM_REGISTER Gpr[8]; ///< General purpose registers.
+ ///< Flags register:
+ ///< 0 Set to 1 if the result of the last compare was true
+ ///< 1 Set to 1 if stepping
+ UINT64 Flags; ///< 2..63 Reserved.
+ VMIP Ip; ///< Instruction pointer.
+ UINTN LastException;
+ EXCEPTION_FLAGS ExceptionFlags; ///< to keep track of exceptions
+ UINT32 StopFlags;
+ UINT32 CompilerVersion; ///< via break(6)
+ UINTN HighStackBottom; ///< bottom of the upper stack
+ UINTN LowStackTop; ///< top of the lower stack
+ UINT64 StackRetAddr; ///< location of final return address on stack
+ UINTN *StackMagicPtr; ///< pointer to magic value on stack to detect corruption
+ EFI_HANDLE ImageHandle; ///< for this EBC driver
+ EFI_SYSTEM_TABLE *SystemTable; ///< for debugging only
+ UINTN LastAddrConverted; ///< for debug
+ UINTN LastAddrConvertedValue; ///< for debug
+ VOID *FramePtr;
+ VOID *EntryPoint; ///< entry point of EBC image
+ UINTN ImageBase;
+ VOID *StackPool;
+ VOID *StackTop;
+} VM_CONTEXT;
+
+/**
+ Given a pointer to a new VM context, execute one or more instructions. This
+ function is only used for test purposes.
+
+ @param[in] This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param[in] VmPtr A pointer to a VM context.
+ @param[in, out] InstructionCount A pointer to a UINTN value holding the number of
+ instructions to execute. If it holds value of 0,
+ then the instruction to be executed is 1.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EBC_VM_TEST_EXECUTE) (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN OUT UINTN *InstructionCount
+ );
+
+/**
+ Convert AsmText to the instruction. This function is only used for test purposes.
+
+ @param[in] This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param[in] AsmText A pointer to EBC ASM text code.
+ @param[out] Buffer Buffer to store the instruction.
+ @param[out] BufferLen Size of buffer that is required to store data.
+
+ @retval EFI_UNSUPPORTED This functionality is unsupported.
+ @retval EFI_SUCCESS Successfully convert AsmText to the instruction.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EBC_VM_TEST_ASM) (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN CHAR16 *AsmText,
+ IN OUT INT8 *Buffer,
+ IN OUT UINTN *BufferLen
+ );
+
+/**
+ Dump the executed instruction. This function is only used for test purposes.
+
+ @param[in] This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param[out] AsmText Contain the disasm text.
+ @param[out] Buffer Buffer to store the instruction.
+ @param[out] BufferLen Size of buffer that is required to store data.
+
+ @retval EFI_UNSUPPORTED This functionality is unsupported.
+ @retval EFI_SUCCESS Successfully dump the executed instruction.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EBC_VM_TEST_DASM) (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN OUT CHAR16 *AsmText,
+ IN OUT INT8 *Buffer,
+ IN OUT UINTN *Len
+ );
+
+//
+// Prototype for the actual EBC test protocol interface
+//
+struct _EFI_EBC_VM_TEST_PROTOCOL {
+ EBC_VM_TEST_EXECUTE Execute;
+ EBC_VM_TEST_ASM Assemble;
+ EBC_VM_TEST_DASM Disassemble;
+};
+
+extern EFI_GUID gEfiEbcVmTestProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/EsrtManagement.h b/roms/edk2/MdeModulePkg/Include/Protocol/EsrtManagement.h
new file mode 100644
index 000000000..e5afb8388
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/EsrtManagement.h
@@ -0,0 +1,138 @@
+/** @file
+ The Esrt Management Protocol used to register/set/update an updatable firmware resource .
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ESRT_MANAGEMENT_H_
+#define _ESRT_MANAGEMENT_H_
+
+#include <Guid/SystemResourceTable.h>
+
+///
+/// Global ID for the ESRT_MANAGEMENT_PROTOCOL.
+///
+#define ESRT_MANAGEMENT_PROTOCOL_GUID \
+ { \
+ 0xa340c064, 0x723c, 0x4a9c, { 0xa4, 0xdd, 0xd5, 0xb4, 0x7a, 0x26, 0xfb, 0xb0 } \
+ }
+
+///
+/// Forward declaration for the _ESRT_MANAGEMENT_PROTOCOL.
+///
+typedef struct _ESRT_MANAGEMENT_PROTOCOL ESRT_MANAGEMENT_PROTOCOL;
+
+/**
+ Get Variable name and data by Esrt Entry FwClass
+
+ @param[in] FwClass FwClass of Esrt entry to get
+ @param[in out] Entry Esrt entry returned
+
+ @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
+ @retval EF_NOT_FOUND No correct variable found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *GET_ESRT_ENTRY)(
+ IN EFI_GUID *FwClass,
+ IN OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+
+/**
+ Update one ESRT entry in ESRT Cache.
+
+ @param[in] Entry Esrt entry to be updated
+
+ @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
+ @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
+ @retval EFI_WRITE_PROTECTED ESRT Cache repositoy is locked
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *UPDATE_ESRT_ENTRY)(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+
+/**
+ Non-FMP instance to unregister Esrt Entry from ESRT Cache.
+
+ @param[in] FwClass FwClass of Esrt entry to Unregister
+
+ @retval EFI_SUCCESS Insert all entries Successfully
+ @retval EFI_NOT_FOUND FwClass does not exsit
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *UNREGISTER_ESRT_ENTRY)(
+ IN EFI_GUID *FwClass
+ );
+
+
+/**
+ Non-FMP instance to register one ESRT entry into ESRT Cache.
+
+ @param[in] Entry Esrt entry to be set
+
+ @retval EFI_SUCCESS Successfully set a variable.
+ @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
+ @retval EFI_OUT_OF_RESOURCES Non-FMP ESRT repository is full
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *REGISTER_ESRT_ENTRY)(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+
+/**
+ This function syn up Cached ESRT with data from FMP instances
+ Function should be called after Connect All in order to locate all FMP protocols
+ installed
+
+ @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
+ @retval EFI_NOT_FOUND No FMP Instance are found
+ @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SYNC_ESRT_FMP)(
+ VOID
+ );
+
+
+/**
+ This function locks up Esrt repository to be readonly. It should be called
+ before gEfiEndOfDxeEventGroupGuid event signaled
+
+ @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *LOCK_ESRT_REPOSITORY)(
+ VOID
+ );
+
+
+struct _ESRT_MANAGEMENT_PROTOCOL {
+ GET_ESRT_ENTRY GetEsrtEntry;
+ UPDATE_ESRT_ENTRY UpdateEsrtEntry;
+ REGISTER_ESRT_ENTRY RegisterEsrtEntry;
+ UNREGISTER_ESRT_ENTRY UnRegisterEsrtEntry;
+ SYNC_ESRT_FMP SyncEsrtFmp;
+ LOCK_ESRT_REPOSITORY LockEsrtRepository;
+};
+
+extern EFI_GUID gEsrtManagementProtocolGuid;
+
+#endif // #ifndef _ESRT_MANAGEMENT_H_
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/FaultTolerantWrite.h b/roms/edk2/MdeModulePkg/Include/Protocol/FaultTolerantWrite.h
new file mode 100644
index 000000000..cf7026169
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/FaultTolerantWrite.h
@@ -0,0 +1,201 @@
+/** @file
+ Fault Tolerant Write protocol provides boot-time service for fault tolerant
+ write capability for block devices. The protocol provides for non-volatile
+ storage of the intermediate data and private information a caller would need to
+ recover from a critical fault, such as a power failure.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FW_FAULT_TOLERANT_WRITE_PROTOCOL_H_
+#define _FW_FAULT_TOLERANT_WRITE_PROTOCOL_H_
+
+#define EFI_FAULT_TOLERANT_WRITE_PROTOCOL_GUID \
+ { \
+ 0x3ebd9e82, 0x2c78, 0x4de6, {0x97, 0x86, 0x8d, 0x4b, 0xfc, 0xb7, 0xc8, 0x81 } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_FAULT_TOLERANT_WRITE_PROTOCOL EFI_FAULT_TOLERANT_WRITE_PROTOCOL;
+
+/**
+ Get the size of the largest block that can be updated in a fault-tolerant manner.
+
+ @param This Indicates a pointer to the calling context.
+ @param BlockSize A pointer to a caller-allocated UINTN that is
+ updated to indicate the size of the largest block
+ that can be updated.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_GET_MAX_BLOCK_SIZE)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,
+ OUT UINTN *BlockSize
+ );
+
+/**
+ Allocates space for the protocol to maintain information about writes.
+ Since writes must be completed in a fault-tolerant manner and multiple
+ writes require more resources to be successful, this function
+ enables the protocol to ensure that enough space exists to track
+ information about upcoming writes.
+
+ @param This A pointer to the calling context.
+ @param CallerId The GUID identifying the write.
+ @param PrivateDataSize The size of the caller's private data that must be
+ recorded for each write.
+ @param NumberOfWrites The number of fault tolerant block writes that will
+ need to occur.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED Not all allocated writes have been completed. All
+ writes must be completed or aborted before another
+ fault tolerant write can occur.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_ALLOCATE)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,
+ IN EFI_GUID * CallerId,
+ IN UINTN PrivateDataSize,
+ IN UINTN NumberOfWrites
+ );
+
+/**
+ Starts a target block update. This records information about the write
+ in fault tolerant storage, and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param This The calling context.
+ @param Lba The logical block address of the target block.
+ @param Offset The offset within the target block to place the
+ data.
+ @param Length The number of bytes to write to the target block.
+ @param PrivateData A pointer to private data that the caller requires
+ to complete any pending writes in the event of a
+ fault.
+ @param FvBlockHandle The handle of FVB protocol that provides services
+ for reading, writing, and erasing the target block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write would span a block boundary, which is not
+ a valid action.
+ @retval EFI_ACCESS_DENIED No writes have been allocated.
+ @retval EFI_NOT_READY The last write has not been completed. Restart()
+ must be called to complete it.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_WRITE)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN VOID *PrivateData,
+ IN EFI_HANDLE FvbHandle,
+ IN VOID *Buffer
+ );
+
+/**
+ Restarts a previously interrupted write. The caller must provide the
+ block protocol needed to complete the interrupted write.
+
+ @param This The calling context.
+ @param FvBlockProtocol The handle of FVB protocol that provides services.
+ for reading, writing, and erasing the target block.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED No pending writes exist.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_RESTART)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,
+ IN EFI_HANDLE FvbHandle
+ );
+
+/**
+ Aborts all previously allocated writes.
+
+ @param This The calling context.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_ABORT)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This
+ );
+
+/**
+ Starts a target block update. This function records information about the write
+ in fault-tolerant storage and completes the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param This Indicates a pointer to the calling context.
+ @param CallerId The GUID identifying the last write.
+ @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 PrivateDataSize On input, the size of the PrivateData buffer. On
+ output, the size of the private data stored for
+ this write.
+ @param PrivateData A pointer to a buffer. The function will copy
+ PrivateDataSize bytes from the private data stored
+ for this write.
+ @param Complete A Boolean value with TRUE indicating that the write
+ was completed.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FAULT_TOLERANT_WRITE_GET_LAST_WRITE)(
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,
+ OUT EFI_GUID * CallerId,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset,
+ OUT UINTN *Length,
+ IN OUT UINTN *PrivateDataSize,
+ OUT VOID *PrivateData,
+ OUT BOOLEAN *Complete
+ );
+
+//
+// Protocol declaration
+//
+struct _EFI_FAULT_TOLERANT_WRITE_PROTOCOL {
+ EFI_FAULT_TOLERANT_WRITE_GET_MAX_BLOCK_SIZE GetMaxBlockSize;
+ EFI_FAULT_TOLERANT_WRITE_ALLOCATE Allocate;
+ EFI_FAULT_TOLERANT_WRITE_WRITE Write;
+ EFI_FAULT_TOLERANT_WRITE_RESTART Restart;
+ EFI_FAULT_TOLERANT_WRITE_ABORT Abort;
+ EFI_FAULT_TOLERANT_WRITE_GET_LAST_WRITE GetLastWrite;
+};
+
+extern EFI_GUID gEfiFaultTolerantWriteProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/FileExplorer.h b/roms/edk2/MdeModulePkg/Include/Protocol/FileExplorer.h
new file mode 100644
index 000000000..43f1f398f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/FileExplorer.h
@@ -0,0 +1,69 @@
+/** @file
+
+ This file explorer protocol defines defines a set of interfaces for
+ how to do file explorer.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FILE_EXPLORER_H__
+#define __FILE_EXPLORER_H__
+
+#define EFI_FILE_EXPLORER_PROTOCOL_GUID \
+ { 0x2C03C536, 0x4594, 0x4515, { 0x9E, 0x7A, 0xD3, 0xD2, 0x04, 0xFE, 0x13, 0x63 } }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_FILE_EXPLORER_PROTOCOL EFI_FILE_EXPLORER_PROTOCOL;
+
+/**
+ Prototype for the next process after user chosed one file.
+
+ @param[in] FilePath The device path of the find file.
+
+ @retval TRUE Need exit file explorer after do the extra task.
+ @retval FALSE Not need to exit file explorer after do the extra task.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CHOOSE_HANDLER)(
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Choose a file in the specified directory.
+
+ If user input NULL for the RootDirectory, will choose file in the system.
+
+ If user input *File != NULL, function will return the allocate device path
+ info for the choosed file, caller has to free the memory after use it.
+
+ @param RootDirectory Pointer to the root directory.
+ @param FileType The file type need to choose.
+ @param ChooseHandler Function pointer to the extra task need to do
+ after choose one file.
+ @param File Return the device path for the last time chosed file.
+
+ @retval EFI_SUCESS Choose the file success.
+ @retval Other errors Choose the file failed.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *CHOOSE_FILE) (
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
+ IN CHAR16 *FileType, OPTIONAL
+ IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
+ OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
+ );
+
+struct _EFI_FILE_EXPLORER_PROTOCOL {
+ CHOOSE_FILE ChooseFile;
+};
+
+extern EFI_GUID gEfiFileExplorerProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/FirmwareManagementProgress.h b/roms/edk2/MdeModulePkg/Include/Protocol/FirmwareManagementProgress.h
new file mode 100644
index 000000000..8e89bfec6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/FirmwareManagementProgress.h
@@ -0,0 +1,49 @@
+/** @file
+ EDK II Firmware Management Progress Protocol.
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL_H__
+#define __EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL_H__
+
+#include <Protocol/GraphicsOutput.h>
+
+///
+/// EDK II Firmware Management Progress Protocol GUID value
+///
+#define EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL_GUID \
+ { \
+ 0x1849bda2, 0x6952, 0x4e86, { 0xa1, 0xdb, 0x55, 0x9a, 0x3c, 0x47, 0x9d, 0xf1 } \
+ }
+
+///
+/// EDK II Firmware Management Progress Protocol structure
+///
+typedef struct {
+ ///
+ /// The version of this structure. Initial version value is 0x00000001.
+ ///
+ UINT32 Version;
+ ///
+ /// The foreground color of a progress bar that is used by the Progress()
+ /// function that is passed into the Firmware Management Protocol SetImage()
+ /// service is called.
+ ///
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION ProgressBarForegroundColor;
+ ///
+ /// The time in seconds to arm the watchdog timer each time the Progress()
+ /// function passed into the Firmware Management Protocol SetImage() service
+ /// is called.
+ ///
+ UINTN WatchdogSeconds;
+} EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL;
+
+///
+/// EDK II Firmware Management Progress Protocol GUID variable.
+///
+extern EFI_GUID gEdkiiFirmwareManagementProgressProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx.h b/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx.h
new file mode 100644
index 000000000..e7e7cd18a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx.h
@@ -0,0 +1,149 @@
+/** @file
+ Extension Form Browser Protocol provides the services that can be used to
+ register the different hot keys for the standard Browser actions described in UEFI specification.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FORM_BROWSER_EXTENSION_H__
+#define __FORM_BROWSER_EXTENSION_H__
+
+#define FORM_BROWSER_EXTENSION_PROTOCOL_GUID \
+ { 0x1f73b18d, 0x4630, 0x43c1, { 0xa1, 0xde, 0x6f, 0x80, 0x85, 0x5d, 0x7d, 0xa4 } }
+
+typedef struct _EDKII_FORM_BROWSER_EXTENSION_PROTOCOL EDKII_FORM_BROWSER_EXTENSION_PROTOCOL;
+
+//
+// To be compatible, keep EFI_FORM_BROWSER_EXTENSION_PROTOCOL definition
+//
+typedef EDKII_FORM_BROWSER_EXTENSION_PROTOCOL EFI_FORM_BROWSER_EXTENSION_PROTOCOL;
+
+//
+// Return value of SAVE_REMINDER() that describes whether the changed data is saved or discarded.
+//
+#define BROWSER_NO_CHANGES 0
+#define BROWSER_SAVE_CHANGES 1
+#define BROWSER_DISCARD_CHANGES 2
+#define BROWSER_KEEP_CURRENT 3
+
+//
+// Browser actions. They can be cominbed together.
+// If more than one actions are specified, the action with low bit will be executed first.
+//
+#define BROWSER_ACTION_UNREGISTER 0
+#define BROWSER_ACTION_DISCARD BIT0
+#define BROWSER_ACTION_DEFAULT BIT1
+#define BROWSER_ACTION_SUBMIT BIT2
+#define BROWSER_ACTION_RESET BIT3
+#define BROWSER_ACTION_EXIT BIT4
+#define BROWSER_ACTION_GOTO BIT5
+
+//
+// Scope for Browser action. It may be Form, FormSet or System level.
+//
+typedef enum {
+ FormLevel,
+ FormSetLevel,
+ SystemLevel,
+ MaxLevel
+} BROWSER_SETTING_SCOPE;
+
+/**
+ Configure what scope the hot key will impact.
+ All hot keys have the same scope. The mixed hot keys with the different level are not supported.
+ If no scope is set, the default scope will be FormSet level.
+ After all registered hot keys are removed, previous Scope can reset to another level.
+
+ @param[in] Scope Scope level to be set.
+
+ @retval EFI_SUCCESS Scope is set correctly.
+ @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
+ @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SET_SCOPE) (
+ IN BROWSER_SETTING_SCOPE Scope
+ );
+
+/**
+ Register the hot key with its browser action, or unregistered the hot key.
+ If the action value is zero, the hot key will be unregistered if it has been registered.
+ If the same hot key has been registered, the new action and help string will override the previous ones.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key. Its type is EFI_INPUT_KEY to
+ be supported by all ConsoleIn devices.
+ @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
+ @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
+ @param[in] HelpString Help string that describes the hot key information.
+ Its value may be NULL for the unregistered hot key.
+
+ @retval EFI_SUCCESS Hot key is registered or unregistered.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *REGISTER_HOT_KEY) (
+ IN EFI_INPUT_KEY *KeyData,
+ IN UINT32 Action,
+ IN UINT16 DefaultId,
+ IN EFI_STRING HelpString OPTIONAL
+ );
+
+/**
+ This handler is responsbile for the left things on normal boot after all UI forms are closed.
+ For example, it can continue to boot the first boot option.
+
+ It will be used only when EXIT action is trigged as system level.
+**/
+typedef
+VOID
+(EFIAPI *EXIT_HANDLER) (
+ VOID
+ );
+
+/**
+ Register Exit handler function.
+ When more than one handler function is registered, the latter one will override the previous one.
+ When NULL handler is specified, the previous Exit handler will be unregistered.
+
+ @param[in] Handler Pointer to handler function.
+
+**/
+typedef
+VOID
+(EFIAPI *REGISTER_EXIT_HANDLER) (
+ IN EXIT_HANDLER Handler
+ );
+
+/**
+ Create reminder to let user to choose save or discard the changed browser data.
+ Caller can use it to actively check the changed browser data.
+
+ @retval BROWSER_NO_CHANGES No browser data is changed.
+ @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
+ @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
+ @retval BROWSER_KEEP_CURRENT Browser keep current changes.
+
+**/
+typedef
+UINT32
+(EFIAPI *SAVE_REMINDER)(
+ VOID
+ );
+
+struct _EDKII_FORM_BROWSER_EXTENSION_PROTOCOL {
+ SET_SCOPE SetScope;
+ REGISTER_HOT_KEY RegisterHotKey;
+ REGISTER_EXIT_HANDLER RegiserExitHandler;
+ SAVE_REMINDER SaveReminder;
+};
+
+extern EFI_GUID gEdkiiFormBrowserExProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx2.h b/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx2.h
new file mode 100644
index 000000000..438c8ee3e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/FormBrowserEx2.h
@@ -0,0 +1,119 @@
+/** @file
+ Extension Form Browser Protocol provides the services that can be used to
+ register the different hot keys for the standard Browser actions described in UEFI specification.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FORM_BROWSER_EXTENSION2_H__
+#define __FORM_BROWSER_EXTENSION2_H__
+
+#include <Protocol/FormBrowserEx.h>
+
+#define EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL_GUID \
+ { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb }}
+
+typedef struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL;
+
+#define BROWSER_EXTENSION2_VERSION_1 0x10000
+#define BROWSER_EXTENSION2_VERSION_1_1 0x10001
+
+/**
+ Check whether the browser data has been modified.
+
+ @retval TRUE Browser data is modified.
+ @retval FALSE No browser data is modified.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *IS_BROWSER_DATA_MODIFIED) (
+ VOID
+ );
+
+/**
+ Execute the action requested by the Action parameter.
+
+ @param[in] Action Execute the request action.
+ @param[in] DefaultId The default Id info when need to load default value.
+
+ @retval EFI_SUCCESS Execute the request action succss.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EXECUTE_ACTION) (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ );
+
+/**
+ Check whether required reset when exit the browser
+
+ @retval TRUE Browser required to reset after exit.
+ @retval FALSE Browser not need to reset after exit.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *IS_RESET_REQUIRED) (
+ VOID
+ );
+
+#define FORM_ENTRY_INFO_SIGNATURE SIGNATURE_32 ('f', 'e', 'i', 's')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_HII_HANDLE HiiHandle;
+ EFI_GUID FormSetGuid;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+} FORM_ENTRY_INFO;
+
+#define FORM_ENTRY_INFO_FROM_LINK(a) CR (a, FORM_ENTRY_INFO, Link, FORM_ENTRY_INFO_SIGNATURE)
+
+#define FORM_QUESTION_ATTRIBUTE_OVERRIDE_SIGNATURE SIGNATURE_32 ('f', 'q', 'o', 's')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_QUESTION_ID QuestionId; // Find the question
+ EFI_FORM_ID FormId; // Find the form
+ EFI_GUID FormSetGuid; // Find the formset.
+ EFI_HII_HANDLE HiiHandle; // Find the HII handle
+ UINT32 Attribute; // Hide or grayout ...
+} QUESTION_ATTRIBUTE_OVERRIDE;
+
+#define FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK(a) CR (a, QUESTION_ATTRIBUTE_OVERRIDE, Link, FORM_QUESTION_ATTRIBUTE_OVERRIDE_SIGNATURE)
+
+struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL {
+ ///
+ /// Version for protocol future extension.
+ ///
+ UINT32 Version;
+ SET_SCOPE SetScope;
+ REGISTER_HOT_KEY RegisterHotKey;
+ REGISTER_EXIT_HANDLER RegiserExitHandler;
+ IS_BROWSER_DATA_MODIFIED IsBrowserDataModified;
+ EXECUTE_ACTION ExecuteAction;
+ ///
+ /// A list of type FORMID_INFO is Browser View Form History List.
+ ///
+ LIST_ENTRY FormViewHistoryHead;
+ ///
+ /// A list of type QUESTION_ATTRIBUTE_OVERRIDE.
+ ///
+ LIST_ENTRY OverrideQestListHead;
+
+ IS_RESET_REQUIRED IsResetRequired;
+};
+
+extern EFI_GUID gEdkiiFormBrowserEx2ProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/GenericMemoryTest.h b/roms/edk2/MdeModulePkg/Include/Protocol/GenericMemoryTest.h
new file mode 100644
index 000000000..08157f35f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/GenericMemoryTest.h
@@ -0,0 +1,120 @@
+/** @file
+ This protocol defines the generic memory test interfaces in Dxe phase.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GENERIC_MEMORY_TEST_H__
+#define __GENERIC_MEMORY_TEST_H__
+
+#define EFI_GENERIC_MEMORY_TEST_PROTOCOL_GUID \
+ { 0x309de7f1, 0x7f5e, 0x4ace, {0xb4, 0x9c, 0x53, 0x1b, 0xe5, 0xaa, 0x95, 0xef} }
+
+typedef struct _EFI_GENERIC_MEMORY_TEST_PROTOCOL EFI_GENERIC_MEMORY_TEST_PROTOCOL;
+
+///
+/// Memory test coverage level.
+/// Ignore chooses not to test memory. Quick and Sparse test some memory, and Extensive performs a detailed memory test.
+///
+typedef enum {
+ IGNORE,
+ QUICK,
+ SPARSE,
+ EXTENSIVE,
+ MAXLEVEL
+} EXTENDMEM_COVERAGE_LEVEL;
+
+
+/**
+ Initialize the generic memory test.
+
+ @param This The protocol instance pointer.
+ @param Level The coverage level of the memory test.
+ @param RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test is initialized correctly.
+ @retval EFI_NO_MEDIA The system had no memory to be tested.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MEMORY_TEST_INIT)(
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ );
+
+
+/**
+ Perform the memory test.
+
+ @param This The protocol instance pointer.
+ @param TestedMemorySize Return the tested extended memory size.
+ @param TotalMemorySize Return the whole system physical memory size.
+ The total memory size does not include memory in a slot with a disabled DIMM.
+ @param ErrorOut TRUE if the memory error occurred.
+ @param IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.
+
+ @retval EFI_SUCCESS One block of memory passed the test.
+ @retval EFI_NOT_FOUND All memory blocks have already been tested.
+ @retval EFI_DEVICE_ERROR Memory device error occurred, and no agent can handle it.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PERFORM_MEMORY_TEST)(
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN IfTestAbort
+ );
+
+
+/**
+ Finish the memory test.
+
+ @param This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Success. All resources used in the memory test are freed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MEMORY_TEST_FINISHED)(
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ );
+
+/**
+ Provides the capability to test the compatible range used by some special drivers.
+
+ @param This The protocol instance pointer.
+ @param StartAddress The start address of the compatible memory range that
+ must be below 16M.
+ @param Length The compatible memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_MEMORY_TEST_COMPATIBLE_RANGE)(
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ );
+
+struct _EFI_GENERIC_MEMORY_TEST_PROTOCOL {
+ EFI_MEMORY_TEST_INIT MemoryTestInit;
+ EFI_PERFORM_MEMORY_TEST PerformMemoryTest;
+ EFI_MEMORY_TEST_FINISHED Finished;
+ EFI_MEMORY_TEST_COMPATIBLE_RANGE CompatibleRangeTest;
+};
+
+extern EFI_GUID gEfiGenericMemTestProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/IoMmu.h b/roms/edk2/MdeModulePkg/Include/Protocol/IoMmu.h
new file mode 100644
index 000000000..3fd35b8b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/IoMmu.h
@@ -0,0 +1,253 @@
+/** @file
+ EFI IOMMU Protocol.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __IOMMU_H__
+#define __IOMMU_H__
+
+//
+// IOMMU Protocol GUID value
+//
+#define EDKII_IOMMU_PROTOCOL_GUID \
+ { \
+ 0x4e939de9, 0xd948, 0x4b0f, { 0x88, 0xed, 0xe6, 0xe1, 0xce, 0x51, 0x7c, 0x1e } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EDKII_IOMMU_PROTOCOL EDKII_IOMMU_PROTOCOL;
+
+//
+// Revision The revision to which the IOMMU interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_IOMMU_PROTOCOL_REVISION 0x00010000
+
+//
+// IOMMU Access for SetAttribute
+//
+// These types can be "ORed" together as needed.
+// Any undefined bits are reserved and must be zero.
+//
+#define EDKII_IOMMU_ACCESS_READ 0x1
+#define EDKII_IOMMU_ACCESS_WRITE 0x2
+
+//
+// IOMMU Operation for Map
+//
+typedef enum {
+ ///
+ /// A read operation from system memory by a bus master that is not capable of producing
+ /// PCI dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterRead,
+ ///
+ /// A write operation from system memory by a bus master that is not capable of producing
+ /// PCI dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterWrite,
+ ///
+ /// Provides both read and write access to system memory by both the processor and a bus
+ /// master that is not capable of producing PCI dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ ///
+ /// A read operation from system memory by a bus master that is capable of producing PCI
+ /// dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterRead64,
+ ///
+ /// A write operation to system memory by a bus master that is capable of producing PCI
+ /// dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterWrite64,
+ ///
+ /// Provides both read and write access to system memory by both the processor and a bus
+ /// master that is capable of producing PCI dual address cycles.
+ ///
+ EdkiiIoMmuOperationBusMasterCommonBuffer64,
+ EdkiiIoMmuOperationMaximum
+} EDKII_IOMMU_OPERATION;
+
+//
+// IOMMU attribute for AllocateBuffer
+// Any undefined bits are reserved and must be zero.
+//
+#define EDKII_IOMMU_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+
+#define EDKII_IOMMU_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EDKII_IOMMU_ATTRIBUTE_MEMORY_WRITE_COMBINE | EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED | EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EDKII_IOMMU_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER)
+
+/**
+ Set IOMMU attribute for a system memory.
+
+ If the IOMMU protocol exists, the system memory cannot be used
+ for DMA by default.
+
+ When a device requests a DMA access for a system memory,
+ the device driver need use SetAttribute() to update the IOMMU
+ attribute to request DMA access (read and/or write).
+
+ The DeviceHandle is used to identify which device submits the request.
+ The IOMMU implementation need translate the device path to an IOMMU device ID,
+ and set IOMMU hardware register accordingly.
+ 1) DeviceHandle can be a standard PCI device.
+ The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+ The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+ The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+ After the memory is used, the memory need set 0 to keep it being protected.
+ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDKII_IOMMU_ACCESS_WRITE.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] DeviceHandle The device who initiates the DMA access request.
+ @param[in] Mapping The mapping value returned from Map().
+ @param[in] IoMmuAccess The IOMMU access.
+
+ @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+ @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
+ @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
+ @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
+ @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
+ @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IOMMU_SET_ATTRIBUTE)(
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN VOID *Mapping,
+ IN UINT64 IoMmuAccess
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param This The protocol instance pointer.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @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 PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IOMMU_MAP)(
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This The protocol instance pointer.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IOMMU_UNMAP)(
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param This The protocol instance pointer.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IOMMU_ALLOCATE_BUFFER)(
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This The protocol instance pointer.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IOMMU_FREE_BUFFER)(
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+///
+/// IOMMU Protocol structure.
+///
+struct _EDKII_IOMMU_PROTOCOL {
+ UINT64 Revision;
+ EDKII_IOMMU_SET_ATTRIBUTE SetAttribute;
+ EDKII_IOMMU_MAP Map;
+ EDKII_IOMMU_UNMAP Unmap;
+ EDKII_IOMMU_ALLOCATE_BUFFER AllocateBuffer;
+ EDKII_IOMMU_FREE_BUFFER FreeBuffer;
+};
+
+///
+/// IOMMU Protocol GUID variable.
+///
+extern EFI_GUID gEdkiiIoMmuProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/IpmiProtocol.h b/roms/edk2/MdeModulePkg/Include/Protocol/IpmiProtocol.h
new file mode 100644
index 000000000..41db3bcbb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/IpmiProtocol.h
@@ -0,0 +1,66 @@
+/** @file
+ Protocol of Ipmi for both SMS and SMM.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IPMI_PROTOCOL_H_
+#define _IPMI_PROTOCOL_H_
+
+typedef struct _IPMI_PROTOCOL IPMI_PROTOCOL;
+
+#define IPMI_PROTOCOL_GUID \
+ { \
+ 0xdbc6381f, 0x5554, 0x4d14, 0x8f, 0xfd, 0x76, 0xd7, 0x87, 0xb8, 0xac, 0xbf \
+ }
+
+#define SMM_IPMI_PROTOCOL_GUID \
+ { \
+ 0x5169af60, 0x8c5a, 0x4243, 0xb3, 0xe9, 0x56, 0xc5, 0x6d, 0x18, 0xee, 0x26 \
+ }
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] This This point for IPMI_PROTOCOL structure.
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *IPMI_SUBMIT_COMMAND) (
+ IN IPMI_PROTOCOL *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ );
+
+//
+// IPMI COMMAND PROTOCOL
+//
+struct _IPMI_PROTOCOL{
+ IPMI_SUBMIT_COMMAND IpmiSubmitCommand;
+};
+
+extern EFI_GUID gIpmiProtocolGuid;
+extern EFI_GUID gSmmIpmiProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/LoadPe32Image.h b/roms/edk2/MdeModulePkg/Include/Protocol/LoadPe32Image.h
new file mode 100644
index 000000000..f71e92ca0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/LoadPe32Image.h
@@ -0,0 +1,97 @@
+/** @file
+
+ Load Pe32 Image protocol enables loading and unloading EFI images into memory and executing those images.
+ This protocol uses File Device Path to get an EFI image.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LOAD_PE32_IMAGE_H__
+#define __LOAD_PE32_IMAGE_H__
+
+#define PE32_IMAGE_PROTOCOL_GUID \
+ {0x5cb5c776,0x60d5,0x45ee,{0x88,0x3c,0x45,0x27,0x8,0xcd,0x74,0x3f }}
+
+#define EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE 0x00
+#define EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION 0x01
+#define EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION 0x02
+
+typedef struct _EFI_PE32_IMAGE_PROTOCOL EFI_PE32_IMAGE_PROTOCOL;
+
+/**
+
+ Loads an EFI image into memory and returns a handle to the image with extended parameters.
+
+ @param This The pointer to the LoadPe32Image protocol instance
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location containing a copy of
+ the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param DstBuffer The buffer to store the image.
+ @param NumberOfPages For input, specifies the space size of the image by caller if not NULL.
+ For output, specifies the actual space size needed.
+ @param ImageHandle The image handle for output.
+ @param EntryPoint The image entry point for output.
+ @param Attribute The bit mask of attributes to set for the load PE image.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device path cannot be
+ parsed to locate the proper protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES The image was not loaded due to insufficient memory resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *LOAD_PE_IMAGE)(
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ IN OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ );
+
+/**
+
+ Unload the specified image.
+
+ @param This The pointer to the LoadPe32Image protocol instance
+ @param ImageHandle The specified image handle to be unloaded.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL.
+ @retval EFI_UNSUPPORTED Attempted to unload an unsupported image.
+ @retval EFI_SUCCESS The image successfully unloaded.
+
+--*/
+typedef
+EFI_STATUS
+(EFIAPI *UNLOAD_PE_IMAGE)(
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ );
+
+struct _EFI_PE32_IMAGE_PROTOCOL {
+ LOAD_PE_IMAGE LoadPeImage;
+ UNLOAD_PE_IMAGE UnLoadPeImage;
+};
+
+extern EFI_GUID gEfiLoadPeImageProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/LockBox.h b/roms/edk2/MdeModulePkg/Include/Protocol/LockBox.h
new file mode 100644
index 000000000..9453650ef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/LockBox.h
@@ -0,0 +1,24 @@
+/** @file
+ LockBox protocol header file.
+ This is used to resolve dependency problem. The LockBox implementation
+ install this to broadcast that LockBox API is ready. The driver who will
+ use LockBox at its ENTRYPOINT should add this dependency.
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LOCK_BOX_PROTOCOL_H_
+#define _LOCK_BOX_PROTOCOL_H_
+
+///
+/// Global ID for the EFI LOCK BOX Protocol.
+///
+#define EFI_LOCK_BOX_PROTOCOL_GUID \
+ { 0xbd445d79, 0xb7ad, 0x4f04, { 0x9a, 0xd8, 0x29, 0xbd, 0x20, 0x40, 0xeb, 0x3c }}
+
+extern EFI_GUID gEfiLockBoxProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/NonDiscoverableDevice.h b/roms/edk2/MdeModulePkg/Include/Protocol/NonDiscoverableDevice.h
new file mode 100644
index 000000000..53ab804f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/NonDiscoverableDevice.h
@@ -0,0 +1,71 @@
+/** @file
+ Protocol to describe devices that are not on a discoverable bus
+
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __NON_DISCOVERABLE_DEVICE_H__
+#define __NON_DISCOVERABLE_DEVICE_H__
+
+#include <IndustryStandard/Acpi.h>
+
+#define EDKII_NON_DISCOVERABLE_DEVICE_PROTOCOL_GUID \
+ { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a } }
+
+//
+// Protocol interface structure
+//
+typedef struct _NON_DISCOVERABLE_DEVICE NON_DISCOVERABLE_DEVICE;
+
+//
+// Data Types
+//
+typedef enum {
+ NonDiscoverableDeviceDmaTypeCoherent,
+ NonDiscoverableDeviceDmaTypeNonCoherent,
+ NonDiscoverableDeviceDmaTypeMax,
+} NON_DISCOVERABLE_DEVICE_DMA_TYPE;
+
+//
+// Function Prototypes
+//
+
+/**
+ Perform device specific initialization before the device is started
+
+ @param This The non-discoverable device protocol pointer
+
+ @retval EFI_SUCCESS Initialization successful, the device may be used
+ @retval Other Initialization failed, device should not be started
+**/
+typedef
+EFI_STATUS
+(EFIAPI *NON_DISCOVERABLE_DEVICE_INIT) (
+ IN NON_DISCOVERABLE_DEVICE *This
+ );
+
+struct _NON_DISCOVERABLE_DEVICE {
+ //
+ // The type of device
+ //
+ CONST EFI_GUID *Type;
+ //
+ // Whether this device is DMA coherent
+ //
+ NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType;
+ //
+ // Initialization function for the device
+ //
+ NON_DISCOVERABLE_DEVICE_INIT Initialize;
+ //
+ // The MMIO and I/O regions owned by the device
+ //
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
+};
+
+extern EFI_GUID gEdkiiNonDiscoverableDeviceProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/PeCoffImageEmulator.h b/roms/edk2/MdeModulePkg/Include/Protocol/PeCoffImageEmulator.h
new file mode 100644
index 000000000..c7f287d77
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/PeCoffImageEmulator.h
@@ -0,0 +1,100 @@
+/** @file
+ Copyright (c) 2019, Linaro, Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PECOFF_IMAGE_EMULATOR_PROTOCOL_GUID_H_
+#define _PECOFF_IMAGE_EMULATOR_PROTOCOL_GUID_H_
+
+#define EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL_GUID \
+ { 0x96F46153, 0x97A7, 0x4793, { 0xAC, 0xC1, 0xFA, 0x19, 0xBF, 0x78, 0xEA, 0x97 } }
+
+typedef struct _EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL;
+
+/**
+ Check whether the emulator supports executing a certain PE/COFF image
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageType Whether the image is an application, a boot time
+ driver or a runtime driver.
+ @param[in] DevicePath Path to device where the image originated
+ (e.g., a PCI option ROM)
+
+ @retval TRUE The image is supported by the emulator
+ @retval FALSE The image is not supported by the emulator.
+**/
+typedef
+BOOLEAN
+(EFIAPI *EDKII_PECOFF_IMAGE_EMULATOR_IS_IMAGE_SUPPORTED) (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN UINT16 ImageType,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
+ );
+
+/**
+ Register a supported PE/COFF image with the emulator. After this call
+ completes successfully, the PE/COFF image may be started as usual, and
+ it is the responsibility of the emulator implementation that any branch
+ into the code section of the image (including returns from functions called
+ from the foreign code) is executed as if it were running on the machine
+ type it was built for.
+
+ @param[in] This This pointer for
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+ @param[in] ImageSize The size in memory of the PE/COFF image
+ @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
+ reference so that the emulator may modify it.
+
+ @retval EFI_SUCCESS The image was registered with the emulator and
+ can be started as usual.
+ @retval other The image could not be registered.
+
+ If the PE/COFF machine type or image type are not supported by the emulator,
+ then ASSERT().
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PECOFF_IMAGE_EMULATOR_REGISTER_IMAGE) (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
+ );
+
+/**
+ Unregister a PE/COFF image that has been registered with the emulator.
+ This should be done before the image is unloaded from memory.
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+
+ @retval EFI_SUCCESS The image was unregistered with the emulator.
+ @retval other Image could not be unloaded.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PECOFF_IMAGE_EMULATOR_UNREGISTER_IMAGE) (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase
+ );
+
+#define EDKII_PECOFF_IMAGE_EMULATOR_VERSION 0x1
+
+typedef struct _EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL {
+ EDKII_PECOFF_IMAGE_EMULATOR_IS_IMAGE_SUPPORTED IsImageSupported;
+ EDKII_PECOFF_IMAGE_EMULATOR_REGISTER_IMAGE RegisterImage;
+ EDKII_PECOFF_IMAGE_EMULATOR_UNREGISTER_IMAGE UnregisterImage;
+
+ // Protocol version implemented by the emulator
+ UINT32 Version;
+ // The machine type implemented by the emulator
+ UINT16 MachineType;
+} EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL;
+
+extern EFI_GUID gEdkiiPeCoffImageEmulatorProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/PlatformBootManager.h b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformBootManager.h
new file mode 100644
index 000000000..26b9ce48a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformBootManager.h
@@ -0,0 +1,82 @@
+/** @file
+
+ Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_BOOT_MANAGER_PROTOCOL_H__
+#define __PLATFORM_BOOT_MANAGER_PROTOCOL_H__
+
+#include <Library/UefiBootManagerLib.h>
+
+//
+// Platform Boot Manager Protocol GUID value
+//
+#define EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL_GUID \
+ { \
+ 0xaa17add4, 0x756c, 0x460d, { 0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } \
+ }
+
+//
+// Protocol interface structure
+//
+typedef struct _EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL;
+
+//
+// Revision The revision to which the protocol interface adheres.
+// All future revisions must be backwards compatible.
+// If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL_REVISION 0x00000001
+
+//
+// Function Prototypes
+//
+
+/*
+ This function allows platform to refresh all boot options specific to the platform. Within
+ this function, platform can make modifications to the auto enumerated platform boot options
+ as well as NV boot options.
+
+ @param[in const] BootOptions An array of auto enumerated platform boot options.
+ This array will be freed by caller upon successful
+ exit of this function and output array would be used.
+
+ @param[in const] BootOptionsCount The number of elements in BootOptions.
+
+ @param[out] UpdatedBootOptions An array of boot options that have been customized
+ for the platform on top of input boot options. This
+ array would be allocated by REFRESH_ALL_BOOT_OPTIONS
+ and would be freed by caller after consuming it.
+
+ @param[out] UpdatedBootOptionsCount The number of elements in UpdatedBootOptions.
+
+
+ @retval EFI_SUCCESS Platform refresh to input BootOptions and
+ BootCount have been done.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+
+ @retval EFI_INVALID_PARAMETER Input is not correct.
+
+ @retval EFI_UNSUPPORTED Platform specific overrides are not supported.
+*/
+typedef
+EFI_STATUS
+(EFIAPI *PLATFORM_BOOT_MANAGER_REFRESH_ALL_BOOT_OPTIONS) (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ IN CONST UINTN BootOptionsCount,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION **UpdatedBootOptions,
+ OUT UINTN *UpdatedBootOptionsCount
+ );
+
+struct _EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL {
+ UINT64 Revision;
+ PLATFORM_BOOT_MANAGER_REFRESH_ALL_BOOT_OPTIONS RefreshAllBootOptions;
+};
+
+extern EFI_GUID gEdkiiPlatformBootManagerProtocolGuid;
+
+#endif /* __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ */
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/PlatformLogo.h b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformLogo.h
new file mode 100644
index 000000000..55c9e0869
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformLogo.h
@@ -0,0 +1,67 @@
+/** @file
+ The Platform Logo Protocol defines the interface to get the Platform logo
+ image with the display attribute.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_LOGO_H__
+#define __PLATFORM_LOGO_H__
+
+#include <Protocol/HiiImage.h>
+
+//
+// GUID for EDKII Platform Logo Protocol
+//
+#define EDKII_PLATFORM_LOGO_PROTOCOL_GUID \
+ { 0x53cd299f, 0x2bc1, 0x40c0, { 0x8c, 0x07, 0x23, 0xf6, 0x4f, 0xdb, 0x30, 0xe0 } }
+
+typedef struct _EDKII_PLATFORM_LOGO_PROTOCOL EDKII_PLATFORM_LOGO_PROTOCOL;
+
+typedef enum {
+ EdkiiPlatformLogoDisplayAttributeLeftTop,
+ EdkiiPlatformLogoDisplayAttributeCenterTop,
+ EdkiiPlatformLogoDisplayAttributeRightTop,
+ EdkiiPlatformLogoDisplayAttributeCenterRight,
+ EdkiiPlatformLogoDisplayAttributeRightBottom,
+ EdkiiPlatformLogoDisplayAttributeCenterBottom,
+ EdkiiPlatformLogoDisplayAttributeLeftBottom,
+ EdkiiPlatformLogoDisplayAttributeCenterLeft,
+ EdkiiPlatformLogoDisplayAttributeCenter
+} EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE;
+
+/**
+ Load a platform logo image and return its data and attributes.
+
+ @param This The pointer to this protocol instance.
+ @param Instance The visible image instance is found.
+ @param Image Points to the image.
+ @param Attribute The display attributes of the image returned.
+ @param OffsetX The X offset of the image regarding the Attribute.
+ @param OffsetY The Y offset of the image regarding the Attribute.
+
+ @retval EFI_SUCCESS The image was fetched successfully.
+ @retval EFI_NOT_FOUND The specified image could not be found.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_LOGO_GET_IMAGE)(
+ IN EDKII_PLATFORM_LOGO_PROTOCOL *This,
+ IN OUT UINT32 *Instance,
+ OUT EFI_IMAGE_INPUT *Image,
+ OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute,
+ OUT INTN *OffsetX,
+ OUT INTN *OffsetY
+ );
+
+
+struct _EDKII_PLATFORM_LOGO_PROTOCOL {
+ EDKII_PLATFORM_LOGO_GET_IMAGE GetImage;
+};
+
+
+extern EFI_GUID gEdkiiPlatformLogoProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetFilter.h b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetFilter.h
new file mode 100644
index 000000000..4a55a3a4d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetFilter.h
@@ -0,0 +1,25 @@
+/** @file
+ This Protocol provides services to register a platform specific reset filter
+ for ResetSystem(). A reset filter evaluates the parameters passed to
+ ResetSystem() and converts a ResetType of EfiResetPlatformSpecific to a
+ non-platform specific reset type. The registered filters are processed before
+ the UEFI 2.7 Reset Notifications.
+
+ Copyright (c) 2017 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL_H_
+#define _PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL_H_
+
+#include <Protocol/ResetNotification.h>
+
+#define EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL_GUID \
+ { 0x695d7835, 0x8d47, 0x4c11, { 0xab, 0x22, 0xfa, 0x8a, 0xcc, 0xe7, 0xae, 0x7a } }
+
+typedef EFI_RESET_NOTIFICATION_PROTOCOL EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL;
+
+extern EFI_GUID gEdkiiPlatformSpecificResetFilterProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetHandler.h b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetHandler.h
new file mode 100644
index 000000000..a2e936b8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/PlatformSpecificResetHandler.h
@@ -0,0 +1,23 @@
+/** @file
+ This protocol provides services to register a platform specific handler for
+ ResetSystem(). The registered handlers are called after the UEFI 2.7 Reset
+ Notifications are processed
+
+ Copyright (c) 2017 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL_H_
+#define _PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL_H_
+
+#include <Protocol/ResetNotification.h>
+
+#define EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL_GUID \
+ { 0x2df6ba0b, 0x7092, 0x440d, { 0xbd, 0x4, 0xfb, 0x9, 0x1e, 0xc3, 0xf3, 0xc1 } }
+
+typedef EFI_RESET_NOTIFICATION_PROTOCOL EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL;
+
+extern EFI_GUID gEdkiiPlatformSpecificResetHandlerProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/Print2.h b/roms/edk2/MdeModulePkg/Include/Protocol/Print2.h
new file mode 100644
index 000000000..9f15d5990
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/Print2.h
@@ -0,0 +1,657 @@
+/** @file
+
+ Produces EFI_PRINT2_PROTOCOL and EFI_PRINT2S_PROTOCOL.
+ These protocols define basic print functions to print the format unicode and
+ ascii string.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PPRINT2_H__
+#define __PPRINT2_H__
+
+#define EFI_PRINT2_PROTOCOL_GUID \
+ { 0xf05976ef, 0x83f1, 0x4f3d, { 0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38 } }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_PRINT2_PROTOCOL EFI_PRINT2_PROTOCOL;
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then the output buffer is unmodified and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *UNICODE_BS_PRINT)(
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then the output buffer is unmodified and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *UNICODE_S_PRINT)(
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ );
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *UNICODE_BS_PRINT_ASCII_FORMAT)(
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *UNICODE_S_PRINT_ASCII_FORMAT)(
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ Converts a decimal value to a Null-terminated Unicode string.
+
+ Converts the decimal number specified by Value to a Null-terminated Unicode
+ string specified by Buffer containing at most Width characters. No padding of spaces
+ is ever performed. If Width is 0, then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ This function returns the number of Unicode characters in Buffer, not including
+ the Null-terminator.
+ If the conversion contains more than Width characters, this function returns
+ the first Width characters in the conversion, along with the total number of characters in the conversion.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+ If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer The pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of Unicode characters in Buffer not including the Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *UNICODE_VALUE_TO_STRING)(
+ IN OUT CHAR16 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ );
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *ASCII_BS_PRINT)(
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *ASCII_S_PRINT)(
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ Unicode format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *ASCII_BS_PRINT_UNICODE_FORMAT)(
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *ASCII_S_PRINT_UNICODE_FORMAT)(
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ );
+
+/**
+ Converts a decimal value to a Null-terminated ASCII string.
+
+ Converts the decimal number specified by Value to a Null-terminated ASCII string
+ specified by Buffer containing at most Width characters. No padding of spaces is ever performed.
+ If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ The number of ASCII characters in Buffer is returned not including the Null-terminator.
+ If the conversion contains more than Width characters, then only the first Width
+ characters are returned, and the total number of characters required to perform
+ the conversion is returned.
+ Additional conversion parameters are specified in Flags.
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+
+ If Buffer is NULL, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer The pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of ASCII characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of ASCII characters in Buffer not including the Null-terminator.
+
+**/
+typedef
+UINTN
+(EFIAPI *ASCII_VALUE_TO_STRING)(
+ OUT CHAR8 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ );
+
+struct _EFI_PRINT2_PROTOCOL {
+ UNICODE_BS_PRINT UnicodeBSPrint;
+ UNICODE_S_PRINT UnicodeSPrint;
+ UNICODE_BS_PRINT_ASCII_FORMAT UnicodeBSPrintAsciiFormat;
+ UNICODE_S_PRINT_ASCII_FORMAT UnicodeSPrintAsciiFormat;
+ UNICODE_VALUE_TO_STRING UnicodeValueToString;
+ ASCII_BS_PRINT AsciiBSPrint;
+ ASCII_S_PRINT AsciiSPrint;
+ ASCII_BS_PRINT_UNICODE_FORMAT AsciiBSPrintUnicodeFormat;
+ ASCII_S_PRINT_UNICODE_FORMAT AsciiSPrintUnicodeFormat;
+ ASCII_VALUE_TO_STRING AsciiValueToString;
+};
+
+extern EFI_GUID gEfiPrint2ProtocolGuid;
+
+
+#define EFI_PRINT2S_PROTOCOL_GUID \
+ { 0xcc252d2, 0xc106, 0x4661, { 0xb5, 0xbd, 0x31, 0x47, 0xa4, 0xf8, 0x1f, 0x92 } }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_PRINT2S_PROTOCOL EFI_PRINT2S_PROTOCOL;
+
+/**
+ Converts a decimal value to a Null-terminated Unicode string.
+
+ Converts the decimal number specified by Value to a Null-terminated Unicode
+ string specified by Buffer containing at most Width characters. No padding of
+ spaces is ever performed. If Width is 0 then a width of
+ MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more than
+ Width characters, then only the first Width characters are placed in Buffer.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and
+ commas are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be formatted in
+ hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in
+ Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, then
+ Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the
+ Null-terminator add up to Width characters.
+
+ If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+ If an error would be returned, then the function will also ASSERT().
+
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Unicode string.
+ @param BufferSize The size of Buffer in bytes, including the
+ Null-terminator.
+ @param Flags The bitmask of flags that specify left justification,
+ zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in
+ Buffer, not including the Null-terminator.
+
+ @retval RETURN_SUCCESS The decimal value is converted.
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted
+ value.
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
+ If PcdMaximumUnicodeStringLength is not
+ zero, and BufferSize is greater than
+ (PcdMaximumUnicodeStringLength *
+ sizeof (CHAR16) + 1).
+ If unsupported bits are set in Flags.
+ If both COMMA_TYPE and RADIX_HEX are set in
+ Flags.
+ If Width >= MAXIMUM_VALUE_CHARACTERS.
+
+**/
+typedef
+RETURN_STATUS
+(EFIAPI *UNICODE_VALUE_TO_STRING_S)(
+ IN OUT CHAR16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ );
+
+/**
+ Converts a decimal value to a Null-terminated Ascii string.
+
+ Converts the decimal number specified by Value to a Null-terminated Ascii
+ string specified by Buffer containing at most Width characters. No padding of
+ spaces is ever performed. If Width is 0 then a width of
+ MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more than
+ Width characters, then only the first Width characters are placed in Buffer.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and
+ commas are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be formatted in
+ hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in
+ Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, then
+ Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the
+ Null-terminator add up to Width characters.
+
+ If an error would be returned, then the function will ASSERT().
+
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Ascii string.
+ @param BufferSize The size of Buffer in bytes, including the
+ Null-terminator.
+ @param Flags The bitmask of flags that specify left justification,
+ zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Ascii characters to place in
+ Buffer, not including the Null-terminator.
+
+ @retval RETURN_SUCCESS The decimal value is converted.
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted
+ value.
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
+ If PcdMaximumAsciiStringLength is not
+ zero, and BufferSize is greater than
+ PcdMaximumAsciiStringLength.
+ If unsupported bits are set in Flags.
+ If both COMMA_TYPE and RADIX_HEX are set in
+ Flags.
+ If Width >= MAXIMUM_VALUE_CHARACTERS.
+
+**/
+typedef
+RETURN_STATUS
+(EFIAPI *ASCII_VALUE_TO_STRING_S)(
+ IN OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ );
+
+struct _EFI_PRINT2S_PROTOCOL {
+ UNICODE_BS_PRINT UnicodeBSPrint;
+ UNICODE_S_PRINT UnicodeSPrint;
+ UNICODE_BS_PRINT_ASCII_FORMAT UnicodeBSPrintAsciiFormat;
+ UNICODE_S_PRINT_ASCII_FORMAT UnicodeSPrintAsciiFormat;
+ UNICODE_VALUE_TO_STRING_S UnicodeValueToStringS;
+ ASCII_BS_PRINT AsciiBSPrint;
+ ASCII_S_PRINT AsciiSPrint;
+ ASCII_BS_PRINT_UNICODE_FORMAT AsciiBSPrintUnicodeFormat;
+ ASCII_S_PRINT_UNICODE_FORMAT AsciiSPrintUnicodeFormat;
+ ASCII_VALUE_TO_STRING_S AsciiValueToStringS;
+};
+
+extern EFI_GUID gEfiPrint2SProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/Ps2Policy.h b/roms/edk2/MdeModulePkg/Include/Protocol/Ps2Policy.h
new file mode 100644
index 000000000..35ff6e074
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/Ps2Policy.h
@@ -0,0 +1,35 @@
+/** @file
+ PS/2 policy protocol abstracts the specific platform initialization and settings.
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#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/roms/edk2/MdeModulePkg/Include/Protocol/SdMmcOverride.h b/roms/edk2/MdeModulePkg/Include/Protocol/SdMmcOverride.h
new file mode 100644
index 000000000..d44027260
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SdMmcOverride.h
@@ -0,0 +1,160 @@
+/** @file
+ Protocol to describe overrides required to support non-standard SDHCI
+ implementations
+
+ Copyright (c) 2017 - 2018, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SD_MMC_OVERRIDE_H__
+#define __SD_MMC_OVERRIDE_H__
+
+#include <Protocol/SdMmcPassThru.h>
+
+#define EDKII_SD_MMC_OVERRIDE_PROTOCOL_GUID \
+ { 0xeaf9e3c1, 0xc9cd, 0x46db, { 0xa5, 0xe5, 0x5a, 0x12, 0x4c, 0x83, 0x23, 0x23 } }
+
+#define EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION 0x3
+
+typedef struct _EDKII_SD_MMC_OVERRIDE EDKII_SD_MMC_OVERRIDE;
+
+#define EDKII_SD_MMC_BUS_WIDTH_IGNORE MAX_UINT8
+#define EDKII_SD_MMC_CLOCK_FREQ_IGNORE MAX_UINT32
+#define EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE MAX_UINT8
+
+typedef enum {
+ SdDriverStrengthTypeB = 0,
+ SdDriverStrengthTypeA,
+ SdDriverStrengthTypeC,
+ SdDriverStrengthTypeD,
+ SdDriverStrengthIgnore = EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE
+} SD_DRIVER_STRENGTH_TYPE;
+
+typedef enum {
+ EmmcDriverStrengthType0 = 0,
+ EmmcDriverStrengthType1,
+ EmmcDriverStrengthType2,
+ EmmcDriverStrengthType3,
+ EmmcDriverStrengthType4,
+ EmmcDriverStrengthIgnore = EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE
+} EMMC_DRIVER_STRENGTH_TYPE;
+
+typedef union {
+ SD_DRIVER_STRENGTH_TYPE Sd;
+ EMMC_DRIVER_STRENGTH_TYPE Emmc;
+} EDKII_SD_MMC_DRIVER_STRENGTH;
+
+typedef struct {
+ //
+ // The target width of the bus. If user tells driver to ignore it
+ // or specifies unsupported width driver will choose highest supported
+ // bus width for a given mode.
+ //
+ UINT8 BusWidth;
+ //
+ // The target clock frequency of the bus in MHz. If user tells driver to ignore
+ // it or specifies unsupported frequency driver will choose highest supported
+ // clock frequency for a given mode.
+ //
+ UINT32 ClockFreq;
+ //
+ // The target driver strength of the bus. If user tells driver to
+ // ignore it or specifies unsupported driver strength, driver will
+ // default to Type0 for eMMC cards and TypeB for SD cards. Driver strength
+ // setting is only considered if chosen bus timing supports them.
+ //
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+} EDKII_SD_MMC_OPERATING_PARAMETERS;
+
+typedef enum {
+ SdMmcSdDs,
+ SdMmcSdHs,
+ SdMmcUhsSdr12,
+ SdMmcUhsSdr25,
+ SdMmcUhsSdr50,
+ SdMmcUhsDdr50,
+ SdMmcUhsSdr104,
+ SdMmcMmcLegacy,
+ SdMmcMmcHsSdr,
+ SdMmcMmcHsDdr,
+ SdMmcMmcHs200,
+ SdMmcMmcHs400,
+} SD_MMC_BUS_MODE;
+
+typedef enum {
+ EdkiiSdMmcResetPre,
+ EdkiiSdMmcResetPost,
+ EdkiiSdMmcInitHostPre,
+ EdkiiSdMmcInitHostPost,
+ EdkiiSdMmcUhsSignaling,
+ EdkiiSdMmcSwitchClockFreqPost,
+ EdkiiSdMmcGetOperatingParam
+} EDKII_SD_MMC_PHASE_TYPE;
+
+/**
+ Override function for SDHCI capability bits
+
+ @param[in] ControllerHandle The EFI_HANDLE of the controller.
+ @param[in] Slot The 0 based slot index.
+ @param[in,out] SdMmcHcSlotCapability The SDHCI capability structure.
+ @param[in,out] BaseClkFreq The base clock frequency value that
+ optionally can be updated.
+
+ @retval EFI_SUCCESS The override function completed successfully.
+ @retval EFI_NOT_FOUND The specified controller or slot does not exist.
+ @retval EFI_INVALID_PARAMETER SdMmcHcSlotCapability is NULL
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_SD_MMC_CAPABILITY) (
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT8 Slot,
+ IN OUT VOID *SdMmcHcSlotCapability,
+ IN OUT UINT32 *BaseClkFreq
+ );
+
+/**
+ Override function for SDHCI controller operations
+
+ @param[in] ControllerHandle The EFI_HANDLE of the controller.
+ @param[in] Slot The 0 based slot index.
+ @param[in] PhaseType The type of operation and whether the
+ hook is invoked right before (pre) or
+ right after (post)
+ @param[in,out] PhaseData The pointer to a phase-specific data.
+
+ @retval EFI_SUCCESS The override function completed successfully.
+ @retval EFI_NOT_FOUND The specified controller or slot does not exist.
+ @retval EFI_INVALID_PARAMETER PhaseType is invalid
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_SD_MMC_NOTIFY_PHASE) (
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT8 Slot,
+ IN EDKII_SD_MMC_PHASE_TYPE PhaseType,
+ IN OUT VOID *PhaseData
+ );
+
+struct _EDKII_SD_MMC_OVERRIDE {
+ //
+ // Protocol version of this implementation
+ //
+ UINTN Version;
+ //
+ // Callback to override SD/MMC host controller capability bits
+ //
+ EDKII_SD_MMC_CAPABILITY Capability;
+ //
+ // Callback to invoke SD/MMC override hooks
+ //
+ EDKII_SD_MMC_NOTIFY_PHASE NotifyPhase;
+};
+
+extern EFI_GUID gEdkiiSdMmcOverrideProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmExitBootServices.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmExitBootServices.h
new file mode 100644
index 000000000..27d8b5e6f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmExitBootServices.h
@@ -0,0 +1,23 @@
+/** @file
+ EDKII SMM Exit Boot Services protocol.
+
+ This SMM protocol is to be published by the SMM Foundation code to associate
+ with EFI_EVENT_GROUP_EXIT_BOOT_SERVICES to notify SMM driver that system enter
+ exit boot services.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_EXIT_BOOT_SERVICES_H_
+#define _SMM_EXIT_BOOT_SERVICES_H_
+
+#define EDKII_SMM_EXIT_BOOT_SERVICES_PROTOCOL_GUID \
+ { \
+ 0x296eb418, 0xc4c8, 0x4e05, { 0xab, 0x59, 0x39, 0xe8, 0xaf, 0x56, 0xf0, 0xa } \
+ }
+
+extern EFI_GUID gEdkiiSmmExitBootServicesProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h
new file mode 100644
index 000000000..63bc3a16c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h
@@ -0,0 +1,32 @@
+/** @file
+ SMM Fault Tolerant Write protocol is related to EDK II-specific implementation of FTW,
+ provides boot-time service for fault tolerant write capability for block devices in
+ EFI SMM environment. The protocol provides for non-volatile storage of the intermediate
+ data and private information a caller would need to recover from a critical fault,
+ such as a power failure.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_FAULT_TOLERANT_WRITE_H__
+#define __SMM_FAULT_TOLERANT_WRITE_H__
+
+#include <Protocol/FaultTolerantWrite.h>
+
+#define EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL_GUID \
+ { \
+ 0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d } \
+ }
+
+//
+// SMM Fault Tolerant Write protocol structure is the same as Fault Tolerant Write protocol.
+// The SMM one is intend to run in SMM environment, which means it can be used by
+// SMM drivers after ExitPmAuth.
+//
+typedef EFI_FAULT_TOLERANT_WRITE_PROTOCOL EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL;
+
+extern EFI_GUID gEfiSmmFaultTolerantWriteProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h
new file mode 100644
index 000000000..d18c2dc11
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h
@@ -0,0 +1,30 @@
+/** @file
+ SMM Firmware Volume Block protocol is related to EDK II-specific implementation of
+ FVB driver, provides control over block-oriented firmware devices and is intended
+ to use in the EFI SMM environment.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_FIRMWARE_VOLUME_BLOCK_H__
+#define __SMM_FIRMWARE_VOLUME_BLOCK_H__
+
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#define EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID \
+ { \
+ 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 } \
+ }
+
+//
+// SMM Firmware Volume Block protocol structure is the same as Firmware Volume Block
+// protocol. The SMM one is intend to run in SMM environment, which means it can be
+// used by SMM drivers after ExitPmAuth.
+//
+typedef EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL;
+
+extern EFI_GUID gEfiSmmFirmwareVolumeBlockProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmLegacyBoot.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmLegacyBoot.h
new file mode 100644
index 000000000..ecff9ab41
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmLegacyBoot.h
@@ -0,0 +1,22 @@
+/** @file
+ EDKII SMM Legacy Boot protocol.
+
+ This SMM protocol is to be published by the SMM Foundation code to associate
+ with EFI_EVENT_LEGACY_BOOT_GUID to notify SMM driver that system enter legacy boot.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_LEGACY_BOOT_H_
+#define _SMM_LEGACY_BOOT_H_
+
+#define EDKII_SMM_LEGACY_BOOT_PROTOCOL_GUID \
+ { \
+ 0x85a8ab57, 0x644, 0x4110, { 0x85, 0xf, 0x98, 0x13, 0x22, 0x4, 0x70, 0x70 } \
+ }
+
+extern EFI_GUID gEdkiiSmmLegacyBootProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmMemoryAttribute.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmMemoryAttribute.h
new file mode 100644
index 000000000..7e45fb907
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmMemoryAttribute.h
@@ -0,0 +1,127 @@
+/** @file
+ SMM Memory Attribute Protocol provides retrieval and update service
+ for memory attributes in EFI SMM environment.
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_MEMORYATTRIBUTE_H__
+#define __SMM_MEMORYATTRIBUTE_H__
+
+//{69B792EA-39CE-402D-A2A6-F721DE351DFE}
+#define EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
+ { \
+ 0x69b792ea, 0x39ce, 0x402d, { 0xa2, 0xa6, 0xf7, 0x21, 0xde, 0x35, 0x1d, 0xfe } \
+ }
+
+typedef struct _EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL;
+
+/**
+ This function set given attributes of the memory region specified by
+ BaseAddress and Length.
+
+ @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of
+ a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory
+ region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ Attributes specified an illegal combination of
+ attributes that cannot be set together.
+ @retval EFI_UNSUPPORTED The processor does not support one or more
+ bytes of the memory resource range specified
+ by BaseAddress and Length.
+ The bit mask of attributes is not supported for
+ the memory resource range specified by
+ BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_SMM_SET_MEMORY_ATTRIBUTES)(
+ IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+/**
+ This function clears given attributes of the memory region specified by
+ BaseAddress and Length.
+
+ @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of
+ a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to clear for the memory
+ region.
+
+ @retval EFI_SUCCESS The attributes were cleared for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ Attributes specified an illegal combination of
+ attributes that cannot be cleared together.
+ @retval EFI_UNSUPPORTED The processor does not support one or more
+ bytes of the memory resource range specified
+ by BaseAddress and Length.
+ The bit mask of attributes is not supported for
+ the memory resource range specified by
+ BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_SMM_CLEAR_MEMORY_ATTRIBUTES)(
+ IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+/**
+ This function retrieves the attributes of the memory region specified by
+ BaseAddress and Length. If different attributes are got from different part
+ of the memory region, EFI_NO_MAPPING will be returned.
+
+ @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of
+ a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes Pointer to attributes returned.
+
+ @retval EFI_SUCCESS The attributes got for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ Attributes is NULL.
+ @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
+ region.
+ @retval EFI_UNSUPPORTED The processor does not support one or more
+ bytes of the memory resource range specified
+ by BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_SMM_GET_MEMORY_ATTRIBUTES)(
+ IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT UINT64 *Attributes
+ );
+
+///
+/// SMM Memory Attribute Protocol provides services to retrieve or update
+/// attribute of memory in the EFI SMM environment.
+///
+struct _EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL {
+ EDKII_SMM_GET_MEMORY_ATTRIBUTES GetMemoryAttributes;
+ EDKII_SMM_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
+ EDKII_SMM_CLEAR_MEMORY_ATTRIBUTES ClearMemoryAttributes;
+};
+
+extern EFI_GUID gEdkiiSmmMemoryAttributeProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmReadyToBoot.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmReadyToBoot.h
new file mode 100644
index 000000000..0b499529a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmReadyToBoot.h
@@ -0,0 +1,23 @@
+/** @file
+ EDKII SMM Ready To Boot protocol.
+
+ This SMM protocol is to be published by the SMM Foundation code to associate
+ with EFI_EVENT_GROUP_READY_TO_BOOT to notify SMM driver that system enter
+ ready to boot.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_READY_TO_BOOT_H_
+#define _SMM_READY_TO_BOOT_H_
+
+#define EDKII_SMM_READY_TO_BOOT_PROTOCOL_GUID \
+ { \
+ 0x6e057ecf, 0xfa99, 0x4f39, { 0x95, 0xbc, 0x59, 0xf9, 0x92, 0x1d, 0x17, 0xe4 } \
+ }
+
+extern EFI_GUID gEdkiiSmmReadyToBootProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h
new file mode 100644
index 000000000..d2c9fc554
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h
@@ -0,0 +1,34 @@
+/** @file
+ The EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL is related to EDK II-specific implementation
+ and used to abstract the swap operation of boot block and backup block of FV in EFI
+ SMM environment. This swap is especially needed when updating the boot block of FV.
+ If a power failure happens during the boot block update, the swapped backup block
+ (now the boot block) can boot the machine with the old boot block backed up in it.
+ The swap operation is platform dependent, so other protocols such as SMM FTW (Fault
+ Tolerant Write) should use this protocol instead of handling hardware directly.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_SWAP_ADDRESS_RANGE_H__
+#define __SMM_SWAP_ADDRESS_RANGE_H__
+
+#include <Protocol/SwapAddressRange.h>
+
+#define EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL_GUID \
+ { \
+ 0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 } \
+ }
+
+//
+// SMM Swap Address Range protocol structure is the same as Swap Address Range protocol.
+// The SMM one is intend to run in SMM environment, which means it can be used by
+// SMM drivers after ExitPmAuth.
+//
+typedef EFI_SWAP_ADDRESS_RANGE_PROTOCOL EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL;
+
+extern EFI_GUID gEfiSmmSwapAddressRangeProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmVarCheck.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmVarCheck.h
new file mode 100644
index 000000000..269a407fc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmVarCheck.h
@@ -0,0 +1,30 @@
+/** @file
+ SMM variable check definitions, it reuses the interface definitions of variable check.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_VAR_CHECK_H__
+#define __SMM_VAR_CHECK_H__
+
+#include <Protocol/VarCheck.h>
+
+#define EDKII_SMM_VAR_CHECK_PROTOCOL_GUID \
+ { \
+ 0xb0d8f3c1, 0xb7de, 0x4c11, { 0xbc, 0x89, 0x2f, 0xb5, 0x62, 0xc8, 0xc4, 0x11 } \
+ };
+
+typedef struct _EDKII_SMM_VAR_CHECK_PROTOCOL EDKII_SMM_VAR_CHECK_PROTOCOL;
+
+struct _EDKII_SMM_VAR_CHECK_PROTOCOL {
+ EDKII_VAR_CHECK_REGISTER_SET_VARIABLE_CHECK_HANDLER SmmRegisterSetVariableCheckHandler;
+ EDKII_VAR_CHECK_VARIABLE_PROPERTY_SET SmmVariablePropertySet;
+ EDKII_VAR_CHECK_VARIABLE_PROPERTY_GET SmmVariablePropertyGet;
+};
+
+extern EFI_GUID gEdkiiSmmVarCheckProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SmmVariable.h b/roms/edk2/MdeModulePkg/Include/Protocol/SmmVariable.h
new file mode 100644
index 000000000..9d5734377
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SmmVariable.h
@@ -0,0 +1,33 @@
+/** @file
+ EFI SMM Variable Protocol is related to EDK II-specific implementation of variables
+ and intended for use as a means to store data in the EFI SMM environment.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_VARIABLE_H__
+#define __SMM_VARIABLE_H__
+
+#define EFI_SMM_VARIABLE_PROTOCOL_GUID \
+ { \
+ 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 } \
+ }
+
+typedef struct _EFI_SMM_VARIABLE_PROTOCOL EFI_SMM_VARIABLE_PROTOCOL;
+
+///
+/// EFI SMM Variable Protocol is intended for use as a means
+/// to store data in the EFI SMM environment.
+///
+struct _EFI_SMM_VARIABLE_PROTOCOL {
+ EFI_GET_VARIABLE SmmGetVariable;
+ EFI_GET_NEXT_VARIABLE_NAME SmmGetNextVariableName;
+ EFI_SET_VARIABLE SmmSetVariable;
+ EFI_QUERY_VARIABLE_INFO SmmQueryVariableInfo;
+};
+
+extern EFI_GUID gEfiSmmVariableProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/SwapAddressRange.h b/roms/edk2/MdeModulePkg/Include/Protocol/SwapAddressRange.h
new file mode 100644
index 000000000..fb01dbf3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/SwapAddressRange.h
@@ -0,0 +1,168 @@
+/** @file
+The EFI_SWAP_ADDRESS_RANGE_PROTOCOL is used to abstract the swap operation of boot block
+and backup block of FV. This swap is especially needed when updating the boot block of FV. If a
+power failure happens during the boot block update, the swapped backup block (now the boot block)
+can boot the machine with the old boot block backed up in it. The swap operation is platform dependent, so
+other protocols such as FTW (Fault Tolerant Write) should use this protocol instead of handling hardware directly.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_SWAP_ADDRESS_RANGE_PROTOCOL_H_
+#define _EFI_SWAP_ADDRESS_RANGE_PROTOCOL_H_
+
+#define EFI_SWAP_ADDRESS_RANGE_PROTOCOL_GUID \
+ { \
+ 0x1259f60d, 0xb754, 0x468e, {0xa7, 0x89, 0x4d, 0xb8, 0x5d, 0x55, 0xe8, 0x7e } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EFI_SWAP_ADDRESS_RANGE_PROTOCOL EFI_SWAP_ADDRESS_RANGE_PROTOCOL;
+
+#define EFI_UNSUPPORT_LOCK 0
+#define EFI_SOFTWARE_LOCK 1
+#define EFI_HARDWARE_LOCK 2
+
+typedef UINT8 EFI_SWAP_LOCK_CAPABILITY;
+
+//
+// Protocol APIs
+//
+
+/**
+ This function gets the address range location of
+ boot block and backup block.
+
+ @param This Indicates the calling context.
+ @param BootBlockBase The base address of current boot block.
+ @param BootBlockSize The size (in bytes) of current boot block.
+ @param BackupBlockBase The base address of current backup block.
+ @param BackupBlockSize The size (in bytes) of current backup block.
+
+ @retval EFI_SUCCESS The call was successful.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_RANGE_LOCATION)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *BootBlockBase,
+ OUT UINTN *BootBlockSize,
+ OUT EFI_PHYSICAL_ADDRESS *BackupBlockBase,
+ OUT UINTN *BackupBlockSize
+ );
+
+/**
+ This service checks if the boot block and backup block has been swapped.
+
+ @param This Indicates the calling context.
+ @param SwapState True if the boot block and backup block has been swapped.
+ False if the boot block and backup block has not been swapped.
+
+ @retval EFI_SUCCESS The call was successful.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_SWAP_STATE)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ OUT BOOLEAN *SwapState
+ );
+
+/**
+ This service swaps the boot block and backup block, or swaps them back.
+
+ It also acquires and releases software swap lock during operation. The setting of the new swap state
+ is not affected by the old swap state.
+
+ @param This Indicates the calling context.
+ @param NewSwapState True to swap real boot block and backup block, False to swap them back.
+
+ @retval EFI_SUCCESS The call was successful.
+ @retval EFI_ABORTED Set swap state error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_SWAP_STATE)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ IN BOOLEAN NewSwapState
+ );
+
+
+
+/**
+ This service checks if a Real Time Clock (RTC) power failure happened.
+
+ If parameter RtcPowerFailed is true after the function returns, RTC power supply failed or was removed.
+ It is recommended to check RTC power status before calling GetSwapState().
+
+ @param This Indicates the calling context.
+ @param RtcPowerFailed True if the RTC (Real Time Clock) power failed or was removed.
+
+ @retval EFI_SUCCESS The call was successful.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_RTC_POWER_STATUS)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ OUT BOOLEAN *RtcPowerFailed
+ );
+
+/**
+ This service returns all lock methods for swap operations that the current platform
+ supports. Could be software lock, hardware lock, or unsupport lock.
+ Note that software and hardware lock methods can be used simultaneously.
+
+ @param This Indicates the calling context.
+ @param LockCapability The current lock method for swap operations.
+
+ @retval EFI_SUCCESS The call was successful.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_SWAP_LOCK_CAPABILITY)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ OUT EFI_SWAP_LOCK_CAPABILITY *LockCapability
+ );
+
+
+
+/**
+ This service is used to acquire or release appointed kind of lock for Swap Address Range operations.
+
+ Note that software and hardware lock mothod can be used simultaneously.
+
+ @param This Indicates the calling context.
+ @param LockCapability Indicates which lock to acquire or release.
+ @param NewLockState True to acquire lock; False to release lock.
+
+ @retval EFI_SUCCESS The call was successful.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_SWAP_LOCK)(
+ IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
+ IN EFI_SWAP_LOCK_CAPABILITY LockCapability,
+ IN BOOLEAN NewLockState
+ );
+
+struct _EFI_SWAP_ADDRESS_RANGE_PROTOCOL {
+ EFI_GET_RANGE_LOCATION GetRangeLocation; // has output parameters for base and length
+ EFI_GET_SWAP_STATE GetSwapState; // are ranges swapped or not
+ EFI_SET_SWAP_STATE SetSwapState; // swap or unswap ranges
+ EFI_GET_RTC_POWER_STATUS GetRtcPowerStatus; // checks RTC battery, or whatever...
+ EFI_GET_SWAP_LOCK_CAPABILITY GetSwapLockCapability; // Get TOP_SWAP lock capability,
+ EFI_SET_SWAP_LOCK SetSwapLock; // Set TOP_SWAP lock state
+};
+
+extern EFI_GUID gEfiSwapAddressRangeProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostController.h b/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostController.h
new file mode 100644
index 000000000..ba5193871
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostController.h
@@ -0,0 +1,237 @@
+/** @file
+
+ EDKII Universal Flash Storage Host Controller Protocol.
+
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __EDKII_UFS_HC_PROTOCOL_H__
+#define __EDKII_UFS_HC_PROTOCOL_H__
+
+//
+// UFS Host Controller Protocol GUID value
+//
+#define EDKII_UFS_HOST_CONTROLLER_PROTOCOL_GUID \
+ { \
+ 0xebc01af5, 0x7a9, 0x489e, { 0xb7, 0xce, 0xdc, 0x8, 0x9e, 0x45, 0x9b, 0x2f } \
+ }
+
+//
+// Forward reference for pure ANSI compatability
+//
+typedef struct _EDKII_UFS_HOST_CONTROLLER_PROTOCOL EDKII_UFS_HOST_CONTROLLER_PROTOCOL;
+
+
+/**
+ Get the MMIO base address of UFS host controller.
+
+ @param This The protocol instance pointer.
+ @param MmioBar Pointer to the UFS host controller MMIO base address.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_GET_MMIO_BAR)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ OUT UINTN *MmioBar
+ );
+
+///
+/// *******************************************************
+/// EFI_UFS_HOST_CONTROLLER_OPERATION
+/// *******************************************************
+///
+typedef enum {
+ ///
+ /// A read operation from system memory by a bus master.
+ ///
+ EdkiiUfsHcOperationBusMasterRead,
+ ///
+ /// A write operation from system memory by a bus master.
+ ///
+ EdkiiUfsHcOperationBusMasterWrite,
+ ///
+ /// 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.
+ ///
+ EdkiiUfsHcOperationBusMasterCommonBuffer,
+ EdkiiUfsHcOperationMaximum
+} EDKII_UFS_HOST_CONTROLLER_OPERATION;
+
+/**
+ Provides the UFS controller-specific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the UFS controller.
+ @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 UFS controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_MAP)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_UNMAP)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiUfsHcOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_ALLOCATE_BUFFER)(
+ IN EDKII_UFS_HOST_CONTROLLER_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 AllocateBuffer().
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_FREE_BUFFER)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all posted write transactions from the UFS bus to attached UFS device.
+
+ @param This A pointer to the EFI_UFS_HOST_CONTROLLER_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The posted write transactions were flushed from the UFS bus
+ to attached UFS device.
+ @retval EFI_DEVICE_ERROR The posted write transactions were not flushed from the UFS
+ bus to attached UFS device due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_FLUSH)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This
+ );
+
+typedef enum {
+ EfiUfsHcWidthUint8 = 0,
+ EfiUfsHcWidthUint16,
+ EfiUfsHcWidthUint32,
+ EfiUfsHcWidthUint64,
+ EfiUfsHcWidthMaximum
+} EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH;
+
+/**
+ Enable a UFS bus driver to access UFS MMIO registers in the UFS Host Controller memory space.
+
+ @param This A pointer to the EDKII_UFS_HOST_CONTROLLER_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the UFS Host Controller MMIO space to start the
+ memory operation.
+ @param Count The number of memory operations to perform.
+ @param 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 read from or written to the UFS host controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the UFS Host Controller memory space.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_MMIO_READ_WRITE)(
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL *This,
+ IN EDKII_UFS_HOST_CONTROLLER_PROTOCOL_WIDTH Width,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+///
+/// UFS Host Controller Protocol structure.
+///
+struct _EDKII_UFS_HOST_CONTROLLER_PROTOCOL {
+ EDKII_UFS_HC_GET_MMIO_BAR GetUfsHcMmioBar;
+ EDKII_UFS_HC_ALLOCATE_BUFFER AllocateBuffer;
+ EDKII_UFS_HC_FREE_BUFFER FreeBuffer;
+ EDKII_UFS_HC_MAP Map;
+ EDKII_UFS_HC_UNMAP Unmap;
+ EDKII_UFS_HC_FLUSH Flush;
+ EDKII_UFS_HC_MMIO_READ_WRITE Read;
+ EDKII_UFS_HC_MMIO_READ_WRITE Write;
+};
+
+///
+/// UFS Host Controller Protocol GUID variable.
+///
+extern EFI_GUID gEdkiiUfsHostControllerProtocolGuid;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostControllerPlatform.h b/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostControllerPlatform.h
new file mode 100644
index 000000000..0f6732a1f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/UfsHostControllerPlatform.h
@@ -0,0 +1,124 @@
+/** @file
+ EDKII_UFS_HC_PLATFORM_PROTOCOL definition.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EDKII_UFS_HC_PLATFORM_PROTOCOL_H__
+#define __EDKII_UFS_HC_PLATFORM_PROTOCOL_H__
+
+#include <Protocol/UfsHostController.h>
+
+#define EDKII_UFS_HC_PLATFORM_PROTOCOL_VERSION 1
+
+extern EFI_GUID gEdkiiUfsHcPlatformProtocolGuid;
+
+typedef struct _EDKII_UFS_HC_PLATFORM_PROTOCOL EDKII_UFS_HC_PLATFORM_PROTOCOL;
+
+typedef struct _EDKII_UFS_HC_DRIVER_INTERFACE EDKII_UFS_HC_DRIVER_INTERFACE;
+
+typedef struct {
+ UINT32 Opcode;
+ UINT32 Arg1;
+ UINT32 Arg2;
+ UINT32 Arg3;
+} EDKII_UIC_COMMAND;
+
+/**
+ Execute UIC command
+
+ @param[in] This Pointer to driver interface produced by the UFS controller.
+ @param[in, out] UicCommand Descriptor of the command that will be executed.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
+ @retval Others Command failed to execute.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_EXEC_UIC_COMMAND) (
+ IN EDKII_UFS_HC_DRIVER_INTERFACE *This,
+ IN OUT EDKII_UIC_COMMAND *UicCommand
+);
+
+struct _EDKII_UFS_HC_DRIVER_INTERFACE {
+ ///
+ /// Protocol to accesss host controller MMIO and PCI registers.
+ ///
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHcProtocol;
+ ///
+ /// Function implementing UIC command execution.
+ ///
+ EDKII_UFS_EXEC_UIC_COMMAND UfsExecUicCommand;
+};
+
+typedef struct {
+ UINT32 Capabilities;
+ UINT32 Version;
+} EDKII_UFS_HC_INFO;
+
+/**
+ Allows platform protocol to override host controller information
+
+ @param[in] ControllerHandle Handle of the UFS controller.
+ @param[in, out] HcInfo Pointer EDKII_UFS_HC_INFO associated with host controller.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_INVALID_PARAMETER HcInfo is NULL.
+ @retval Others Function failed to complete.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_PLATFORM_OVERRIDE_HC_INFO) (
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EDKII_UFS_HC_INFO *HcInfo
+);
+
+typedef enum {
+ EdkiiUfsHcPreHce,
+ EdkiiUfsHcPostHce,
+ EdkiiUfsHcPreLinkStartup,
+ EdkiiUfsHcPostLinkStartup
+} EDKII_UFS_HC_PLATFORM_CALLBACK_PHASE;
+
+/**
+ Callback function for platform driver.
+
+ @param[in] ControllerHandle Handle of the UFS controller.
+ @param[in] CallbackPhase Specifies when the platform protocol is called
+ @param[in, out] CallbackData Data specific to the callback phase.
+ For PreHce and PostHce - EDKII_UFS_HC_DRIVER_INTERFACE.
+ For PreLinkStartup and PostLinkStartup - EDKII_UFS_HC_DRIVER_INTERFACE.
+
+ @retval EFI_SUCCESS Override function completed successfully.
+ @retval EFI_INVALID_PARAMETER CallbackPhase is invalid or CallbackData is NULL when phase expects valid data.
+ @retval Others Function failed to complete.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_UFS_HC_PLATFORM_CALLBACK) (
+ IN EFI_HANDLE ControllerHandle,
+ IN EDKII_UFS_HC_PLATFORM_CALLBACK_PHASE CallbackPhase,
+ IN OUT VOID *CallbackData
+);
+
+struct _EDKII_UFS_HC_PLATFORM_PROTOCOL {
+ ///
+ /// Version of the protocol.
+ ///
+ UINT32 Version;
+ ///
+ /// Allows platform driver to override host controller information.
+ ///
+ EDKII_UFS_HC_PLATFORM_OVERRIDE_HC_INFO OverrideHcInfo;
+ ///
+ /// Allows platform driver to implement platform specific flows
+ /// for host controller.
+ ///
+ EDKII_UFS_HC_PLATFORM_CALLBACK Callback;
+};
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/VarCheck.h b/roms/edk2/MdeModulePkg/Include/Protocol/VarCheck.h
new file mode 100644
index 000000000..013ec6fbb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/VarCheck.h
@@ -0,0 +1,120 @@
+/** @file
+ Variable check definitions.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_CHECK_H_
+#define _VARIABLE_CHECK_H_
+
+#include <Uefi/UefiSpec.h>
+
+typedef struct _EDKII_VAR_CHECK_PROTOCOL EDKII_VAR_CHECK_PROTOCOL;
+
+#define EDKII_VAR_CHECK_PROTOCOL_GUID { \
+ 0xaf23b340, 0x97b4, 0x4685, { 0x8d, 0x4f, 0xa3, 0xf2, 0x81, 0x69, 0xb2, 0x1d } \
+};
+
+typedef EFI_SET_VARIABLE VAR_CHECK_SET_VARIABLE_CHECK_HANDLER;
+
+/**
+ Register SetVariable check handler.
+ Variable driver will call the handler to do check before
+ really setting the variable into variable storage.
+
+ @param[in] Handler Pointer to the check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_VAR_CHECK_REGISTER_SET_VARIABLE_CHECK_HANDLER) (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ );
+
+#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001
+//
+// 1. Set by VariableLock PROTOCOL
+// 2. Set by VarCheck PROTOCOL
+//
+// If set, other fields for check will be ignored.
+//
+#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT0
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 Property;
+ UINT32 Attributes;
+ UINTN MinSize;
+ UINTN MaxSize;
+} VAR_CHECK_VARIABLE_PROPERTY;
+
+typedef struct {
+ EFI_GUID *Guid;
+ CHAR16 *Name;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+} VARIABLE_ENTRY_PROPERTY;
+
+/**
+ Variable property set.
+ Variable driver will do check according to the VariableProperty before
+ really setting the variable into variable storage.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_VAR_CHECK_VARIABLE_PROPERTY_SET) (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_VAR_CHECK_VARIABLE_PROPERTY_GET) (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+struct _EDKII_VAR_CHECK_PROTOCOL {
+ EDKII_VAR_CHECK_REGISTER_SET_VARIABLE_CHECK_HANDLER RegisterSetVariableCheckHandler;
+ EDKII_VAR_CHECK_VARIABLE_PROPERTY_SET VariablePropertySet;
+ EDKII_VAR_CHECK_VARIABLE_PROPERTY_GET VariablePropertyGet;
+};
+
+extern EFI_GUID gEdkiiVarCheckProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Include/Protocol/VariableLock.h b/roms/edk2/MdeModulePkg/Include/Protocol/VariableLock.h
new file mode 100644
index 000000000..eaffd5b10
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Include/Protocol/VariableLock.h
@@ -0,0 +1,57 @@
+/** @file
+ Variable Lock Protocol is related to EDK II-specific implementation of variables
+ and intended for use as a means to mark a variable read-only after the event
+ EFI_END_OF_DXE_EVENT_GUID is signaled.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_LOCK_H__
+#define __VARIABLE_LOCK_H__
+
+#define EDKII_VARIABLE_LOCK_PROTOCOL_GUID \
+ { \
+ 0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 } \
+ }
+
+typedef struct _EDKII_VARIABLE_LOCK_PROTOCOL EDKII_VARIABLE_LOCK_PROTOCOL;
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+ Write request coming from SMM environment through EFI_SMM_VARIABLE_PROTOCOL is allowed.
+
+ @param[in] This The EDKII_VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK) (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+///
+/// Variable Lock Protocol is related to EDK II-specific implementation of variables
+/// and intended for use as a means to mark a variable read-only after the event
+/// EFI_END_OF_DXE_EVENT_GUID is signaled.
+///
+struct _EDKII_VARIABLE_LOCK_PROTOCOL {
+ EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK RequestToLock;
+};
+
+extern EFI_GUID gEdkiiVariableLockProtocolGuid;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c
new file mode 100644
index 000000000..b6922d3dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c
@@ -0,0 +1,71 @@
+/** @file
+ Implements NULL authenticated variable services.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/AuthVariableLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Initialization for authenticated varibale services.
+ If this initialization returns error status, other APIs will not work
+ and expect to be not called then.
+
+ @param[in] AuthVarLibContextIn Pointer to input auth variable lib context.
+ @param[out] AuthVarLibContextOut Pointer to output auth variable lib context.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibInitialize (
+ IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn,
+ OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut
+ )
+{
+ //
+ // Do nothing, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
new file mode 100644
index 000000000..ec49fd77e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# Provides NULL authenticated variable services.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AuthVariableLibNull
+ MODULE_UNI_FILE = AuthVariableLibNull.uni
+ FILE_GUID = 435CB0E4-7C9A-4BB7-9907-8FD4643E978A
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = AuthVariableLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER MM_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ AuthVariableLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni
new file mode 100644
index 000000000..ae148f918
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Provides NULL authenticated variable services.
+//
+// Provides NULL authenticated variable services.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides NULL authenticated variable services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides NULL authenticated variable services."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
new file mode 100644
index 000000000..a289ff8de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
@@ -0,0 +1,33 @@
+## @file
+# Base library to support BMP graphics image conversion.
+#
+# Provides services to convert a BMP graphics image to a GOP BLT buffer and
+# from a GOP BLT buffer to a BMP graphics image.
+#
+# Copyright (c) 2017, Microsoft Corporation
+#
+# All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = BaseBmpSupportLib
+ MODULE_UNI_FILE = BaseBmpSupportLib.uni
+ FILE_GUID = CF5F650B-C208-409A-B889-0755172E2B0C
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = BmpSupportLib
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ SafeIntLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+ BmpSupportLib.c
diff --git a/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.uni b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.uni
new file mode 100644
index 000000000..a818cac75
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base library to support BMP graphics image conversion.
+//
+// Provides services to convert a BMP graphics image to a GOP BLT buffer and
+// from a GOP BLT buffer to a BMP graphics image.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "BmpSupportLib instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "BmpSupportLib instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c
new file mode 100644
index 000000000..3ac31f672
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c
@@ -0,0 +1,575 @@
+/** @file
+
+ Provides services to convert a BMP graphics image to a GOP BLT buffer and
+ from a GOP BLT buffer to a BMP graphics image.
+
+ Caution: This module requires additional review when modified.
+ This module processes external input - BMP image.
+ This external input must be validated carefully to avoid security issue such
+ as buffer overflow, integer overflow.
+
+ TranslateBmpToGopBlt() receives untrusted input and performs basic validation.
+
+ Copyright (c) 2016-2017, Microsoft Corporation
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SafeIntLib.h>
+#include <IndustryStandard/Bmp.h>
+
+#include <Library/BmpSupportLib.h>
+
+//
+// BMP Image header for an uncompressed 24-bit per pixel BMP image.
+//
+const BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
+ 'B', // CharB
+ 'M', // CharM
+ 0, // Size will be updated at runtime
+ {0, 0}, // Reserved
+ sizeof (BMP_IMAGE_HEADER), // ImageOffset
+ sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
+ 0, // PixelWidth will be updated at runtime
+ 0, // PixelHeight will be updated at runtime
+ 1, // Planes
+ 24, // BitPerPixel
+ 0, // CompressionType
+ 0, // ImageSize will be updated at runtime
+ 0, // XPixelsPerMeter
+ 0, // YPixelsPerMeter
+ 0, // NumberOfColors
+ 0 // ImportantColors
+};
+
+/**
+ Translate 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 using
+ EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be
+ used if it is big enough.
+
+ @param[in] BmpImage Pointer to BMP file.
+ @param[in] BmpImageSize Number of bytes in BmpImage.
+ @param[in, out] GopBlt Buffer containing GOP version of BmpImage.
+ @param[in, out] GopBltSize Size of GopBlt in bytes.
+ @param[out] PixelHeight Height of GopBlt/BmpImage in pixels.
+ @param[out] PixelWidth Width of GopBlt/BmpImage in pixels.
+
+ @retval RETURN_SUCCESS GopBlt and GopBltSize are returned.
+ @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
+ @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
+ @retval RETURN_INVALID_PARAMETER GopBltSize is NULL.
+ @retval RETURN_INVALID_PARAMETER PixelHeight is NULL.
+ @retval RETURN_INVALID_PARAMETER PixelWidth is NULL.
+ @retval RETURN_UNSUPPORTED BmpImage is not a valid *.BMP image.
+ @retval RETURN_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big
+ enough. The required size is returned in
+ GopBltSize.
+ @retval RETURN_OUT_OF_RESOURCES The GopBlt buffer could not be allocated.
+
+**/
+RETURN_STATUS
+EFIAPI
+TranslateBmpToGopBlt (
+ IN VOID *BmpImage,
+ IN UINTN BmpImageSize,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **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;
+ UINT32 BltBufferSize;
+ UINTN Index;
+ UINTN Height;
+ UINTN Width;
+ UINTN ImageIndex;
+ UINT32 DataSizePerLine;
+ BOOLEAN IsAllocated;
+ UINT32 ColorMapNum;
+ RETURN_STATUS Status;
+ UINT32 DataSize;
+ UINT32 Temp;
+
+ if (BmpImage == NULL || GopBlt == NULL || GopBltSize == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (PixelHeight == NULL || PixelWidth == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n"));
+ return RETURN_UNSUPPORTED;
+ }
+
+ BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;
+
+ if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+ DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n"));
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Doesn't support compress.
+ //
+ if (BmpHeader->CompressionType != 0) {
+ DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n"));
+ return RETURN_UNSUPPORTED;
+ }
+
+ if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) {
+ DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n"));
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Only support BITMAPINFOHEADER format.
+ // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
+ //
+ if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n",
+ BmpHeader->HeaderSize
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // The data size in each line must be 4 byte alignment.
+ //
+ Status = SafeUint32Mult (
+ BmpHeader->PixelWidth,
+ BmpHeader->BitPerPixel,
+ &DataSizePerLine
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",
+ BmpHeader->PixelWidth,
+ BmpHeader->BitPerPixel
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+
+ Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",
+ DataSizePerLine
+ ));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);
+ Status = SafeUint32Mult (
+ DataSizePerLine,
+ BmpHeader->PixelHeight,
+ &BltBufferSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",
+ DataSizePerLine, BmpHeader->PixelHeight
+ ));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ Status = SafeUint32Mult (
+ BmpHeader->PixelHeight,
+ DataSizePerLine,
+ &DataSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",
+ BmpHeader->PixelHeight, DataSizePerLine
+ ));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ if ((BmpHeader->Size != BmpImageSize) ||
+ (BmpHeader->Size < BmpHeader->ImageOffset) ||
+ (BmpHeader->Size - BmpHeader->ImageOffset != DataSize)) {
+
+ DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));
+ DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size));
+ DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));
+ DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));
+ DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // 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 RETURN_UNSUPPORTED;
+ }
+
+ 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 RETURN_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Calculate graphics image data address in the image
+ //
+ Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;
+ ImageHeader = Image;
+
+ //
+ // Calculate the BltBuffer needed size.
+ //
+ Status = SafeUint32Mult (
+ BmpHeader->PixelWidth,
+ BmpHeader->PixelHeight,
+ &BltBufferSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",
+ BmpHeader->PixelWidth, BmpHeader->PixelHeight
+ ));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ Temp = BltBufferSize;
+ Status = SafeUint32Mult (
+ BltBufferSize,
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
+ &BltBufferSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n",
+ Temp, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ ));
+
+ return RETURN_UNSUPPORTED;
+ }
+
+ IsAllocated = FALSE;
+ if (*GopBlt == NULL) {
+ //
+ // GopBlt is not allocated by caller.
+ //
+ DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));
+ *GopBltSize = (UINTN)BltBufferSize;
+ *GopBlt = AllocatePool (*GopBltSize);
+ IsAllocated = TRUE;
+ if (*GopBlt == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // GopBlt has been allocated by caller.
+ //
+ if (*GopBltSize < (UINTN)BltBufferSize) {
+ *GopBltSize = (UINTN)BltBufferSize;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ }
+
+ *PixelWidth = BmpHeader->PixelWidth;
+ *PixelHeight = BmpHeader->PixelHeight;
+ DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));
+ DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));
+ DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));
+ DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));
+ DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));
+ DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));
+ DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));
+
+ //
+ // Translate 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:
+ //
+ // Translate 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:
+ //
+ // Translate 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:
+ //
+ // Translate 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;
+
+ case 32:
+ //
+ //Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel
+ Blt->Blue = *Image++;
+ Blt->Green = *Image++;
+ Blt->Red = *Image++;
+ break;
+
+ default:
+ //
+ // Other bit format BMP is not supported.
+ //
+ if (IsAllocated) {
+ FreePool (*GopBlt);
+ *GopBlt = NULL;
+ }
+ DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel));
+ return RETURN_UNSUPPORTED;
+ break;
+ };
+
+ }
+
+ ImageIndex = (UINTN)Image - (UINTN)ImageHeader;
+ if ((ImageIndex % 4) != 0) {
+ //
+ // Bmp Image starts each row on a 32-bit boundary!
+ //
+ Image = Image + (4 - (ImageIndex % 4));
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics
+ image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by
+ this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is
+ passed in it will be used if it is big enough.
+
+ @param [in] GopBlt Pointer to GOP blt buffer.
+ @param [in] PixelHeight Height of GopBlt/BmpImage in pixels.
+ @param [in] PixelWidth Width of GopBlt/BmpImage in pixels.
+ @param [in, out] BmpImage Buffer containing BMP version of GopBlt.
+ @param [in, out] BmpImageSize Size of BmpImage in bytes.
+
+ @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned.
+ @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
+ @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
+ @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL.
+ @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image.
+ @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big
+ enough. The required size is returned in
+ BmpImageSize.
+ @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated.
+
+**/
+RETURN_STATUS
+EFIAPI
+TranslateGopBltToBmp (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt,
+ IN UINT32 PixelHeight,
+ IN UINT32 PixelWidth,
+ IN OUT VOID **BmpImage,
+ IN OUT UINT32 *BmpImageSize
+ )
+{
+ RETURN_STATUS Status;
+ UINT32 PaddingSize;
+ UINT32 BmpSize;
+ BMP_IMAGE_HEADER *BmpImageHeader;
+ UINT8 *Image;
+ UINTN Col;
+ UINTN Row;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
+
+ if (GopBlt == NULL || BmpImage == NULL || BmpImageSize == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if ((PixelHeight == 0) || (PixelWidth == 0)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Allocate memory for BMP file.
+ //
+ PaddingSize = PixelWidth & 0x3;
+
+ //
+ // First check PixelWidth * 3 + PaddingSize doesn't overflow
+ //
+ Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
+ PixelHeight,
+ PixelWidth
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+ Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
+ PixelHeight,
+ PixelWidth
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
+ //
+ Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
+ PixelHeight,
+ PixelWidth
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+ Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
+ PixelHeight,
+ PixelWidth
+ ));
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // The image should be stored in EfiBootServicesData, allowing the system to
+ // reclaim the memory
+ //
+ if (*BmpImage == NULL) {
+ *BmpImage = AllocateZeroPool (BmpSize);
+ if (*BmpImage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *BmpImageSize = BmpSize;
+ } else if (*BmpImageSize < BmpSize) {
+ *BmpImageSize = BmpSize;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+
+ BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;
+ CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
+ BmpImageHeader->Size = *BmpImageSize;
+ BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);
+ BmpImageHeader->PixelWidth = PixelWidth;
+ BmpImageHeader->PixelHeight = PixelHeight;
+
+ //
+ // Convert BLT buffer to BMP file.
+ //
+ Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);
+ for (Row = 0; Row < PixelHeight; Row++) {
+ BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];
+
+ for (Col = 0; Col < PixelWidth; Col++) {
+ *Image++ = BltPixel->Blue;
+ *Image++ = BltPixel->Green;
+ *Image++ = BltPixel->Red;
+ BltPixel++;
+ }
+
+ //
+ // Padding for 4 byte alignment.
+ //
+ Image += PaddingSize;
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.c b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.c
new file mode 100644
index 000000000..f740195ef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.c
@@ -0,0 +1,536 @@
+/** @file
+ Provide Hob Library functions for build testing only.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Pi/PiMultiPhase.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+
+/**
+ Returns the pointer to the HOB list.
+
+ This function returns the pointer to first HOB in the list.
+ For PEI phase, the PEI service GetHobList() can be used to retrieve the pointer
+ to the HOB list. For the DXE phase, the HOB list pointer can be retrieved through
+ the EFI System Table by looking up theHOB list GUID in the System Configuration Table.
+ Since the System Configuration Table does not exist that the time the DXE Core is
+ launched, the DXE Core uses a global variable from the DXE Core Entry Point Library
+ to manage the pointer to the HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @return The pointer to the HOB list.
+
+**/
+VOID *
+EFIAPI
+GetHobList (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Returns the next instance of a HOB type from the starting HOB.
+
+ This function searches the first instance of a HOB type from the starting HOB pointer.
+ If there does not exist such HOB type from the starting HOB pointer, it will return NULL.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If HobStart is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+ @param HobStart The starting HOB pointer to search from.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextHob (
+ IN UINT16 Type,
+ IN CONST VOID *HobStart
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Returns the first instance of a HOB type among the whole HOB list.
+
+ This function searches the first instance of a HOB type among the whole HOB list.
+ If there does not exist such HOB type in the HOB list, it will return NULL.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetFirstHob (
+ IN UINT16 Type
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Returns the next instance of the matched GUID HOB from the starting HOB.
+
+ This function searches the first instance of a HOB from the starting HOB pointer.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If there does not exist such HOB from the starting HOB pointer, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If Guid is NULL, then ASSERT().
+ If HobStart is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+ @param HobStart A pointer to a Guid.
+
+ @return The next instance of the matched GUID HOB from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *HobStart
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Returns the first instance of the matched GUID HOB among the whole HOB list.
+
+ This function searches the first instance of a HOB among the whole HOB list.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If there does not exist such HOB from the starting HOB pointer, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+
+ @return The first instance of the matched GUID HOB among the whole HOB list.
+
+**/
+VOID *
+EFIAPI
+GetFirstGuidHob (
+ IN CONST EFI_GUID *Guid
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Get the system boot mode from the HOB list.
+
+ This function returns the system boot mode information from the
+ PHIT HOB in HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param VOID.
+
+ @return The Boot Mode.
+
+**/
+EFI_BOOT_MODE
+EFIAPI
+GetBootModeHob (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return MAX_UINT32;
+}
+
+/**
+ Builds a HOB for a loaded PE32 module.
+
+ This function builds a HOB for a loaded PE32 module.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If ModuleName is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ModuleName The GUID File Name of the module.
+ @param MemoryAllocationModule The 64 bit physical address of the module.
+ @param ModuleLength The length of the module in bytes.
+ @param EntryPoint The 64 bit physical address of the module entry point.
+
+**/
+VOID
+EFIAPI
+BuildModuleHob (
+ IN CONST EFI_GUID *ModuleName,
+ IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
+ IN UINT64 ModuleLength,
+ IN EFI_PHYSICAL_ADDRESS EntryPoint
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory with Owner GUID.
+
+ This function builds a HOB that describes a chunk of system memory.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+ @param OwnerGUID GUID for the owner of this resource.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorWithOwnerHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_GUID *OwnerGUID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory.
+
+ This function builds a HOB that describes a chunk of system memory.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a customized HOB tagged with a GUID for identification and returns
+ the start address of GUID HOB data.
+
+ This function builds a customized HOB tagged with a GUID for identification
+ and returns the start address of GUID HOB data so that caller can fill the customized data.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If Guid is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN DataLength
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Builds a customized HOB tagged with a GUID for identification, copies the input data to the HOB
+ data field, and returns the start address of the GUID HOB data.
+
+ This function builds a customized HOB tagged with a GUID for identification and copies the input
+ data to the HOB data field and returns the start address of the GUID HOB data. It can only be
+ invoked during PEI phase; for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If Guid is NULL, then ASSERT().
+ If Data is NULL and DataLength > 0, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param Data The data to be copied into the data field of the GUID HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidDataHob (
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN DataLength
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Builds a Firmware Volume HOB.
+
+ This function builds a Firmware Volume HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV2 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV2 HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param FvName The name of the Firmware Volume.
+ @param FileName The name of the file.
+
+**/
+VOID
+EFIAPI
+BuildFv2Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN CONST EFI_GUID *FvName,
+ IN CONST EFI_GUID *FileName
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV3 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV3 HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param AuthenticationStatus The authentication status.
+ @param ExtractedFv TRUE if the FV was extracted as a file within
+ another firmware volume. FALSE otherwise.
+ @param FvName The name of the Firmware Volume.
+ Valid only if IsExtractedFv is TRUE.
+ @param FileName The name of the file.
+ Valid only if IsExtractedFv is TRUE.
+
+**/
+VOID
+EFIAPI
+BuildFv3Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT32 AuthenticationStatus,
+ IN BOOLEAN ExtractedFv,
+ IN CONST EFI_GUID *FvName, OPTIONAL
+ IN CONST EFI_GUID *FileName OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a Capsule Volume HOB.
+
+ This function builds a Capsule Volume HOB.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If the platform does not support Capsule Volume HOBs, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Capsule Volume.
+ @param Length The size of the Capsule Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildCvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the CPU.
+
+ This function builds a HOB for the CPU.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param SizeOfMemorySpace The maximum physical memory addressability of the processor.
+ @param SizeOfIoSpace The maximum physical I/O addressability of the processor.
+
+**/
+VOID
+EFIAPI
+BuildCpuHob (
+ IN UINT8 SizeOfMemorySpace,
+ IN UINT8 SizeOfIoSpace
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the Stack.
+
+ This function builds a HOB for the stack.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+EFIAPI
+BuildStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the BSP store.
+
+ This function builds a HOB for BSP store.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the BSP.
+ @param Length The length of the BSP store in bytes.
+ @param MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildBspStoreHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the memory allocation.
+
+ This function builds a HOB for the memory allocation.
+ It can only be invoked during PEI phase;
+ for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the memory.
+ @param Length The length of the memory allocation in bytes.
+ @param MemoryType The type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
new file mode 100644
index 000000000..5faf742c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# Null instance of HOB Library.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = BaseHobLibNull
+ MODULE_UNI_FILE = BaseHobLibNull.uni
+ FILE_GUID = a89dea6f-c9a0-40be-903c-7cac2ef8a0e7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HobLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ BaseHobLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.uni b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.uni
new file mode 100644
index 000000000..cb32f0005
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Null instance of HOB Library.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+// Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of HOB Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "HOB Library implementation for build testing only."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c
new file mode 100644
index 000000000..44ad5ed5b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c
@@ -0,0 +1,47 @@
+/** @file
+ A emptry template implementation of Ipmi Library.
+
+ Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IpmiLib.h>
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ //
+ // Do nothing, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
new file mode 100644
index 000000000..bcc80c1f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# Null Instance of IPMI Library.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseIpmiLibNull
+ MODULE_UNI_FILE = BaseIpmiLibNull.uni
+ FILE_GUID = 46805D61-0BB8-4680-A9BE-C96C751AB5A4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ BaseIpmiLibNull.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.uni b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.uni
new file mode 100644
index 000000000..0020578e1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Null Instance of IPMI Library.
+//
+// Null Instance of IPMI Library.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Null Instance of IPMI Library."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Null Instance of IPMI Library."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.c b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.c
new file mode 100644
index 000000000..4079472e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.c
@@ -0,0 +1,569 @@
+/** @file
+ Dummy support routines for memory allocation
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf
new file mode 100644
index 000000000..00a2b7809
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# Null instance of Memory Allocation Library.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = BaseMemoryAllocationLibNull
+ MODULE_UNI_FILE = BaseMemoryAllocationLibNull.uni
+ FILE_GUID = fd56f5d6-f194-448f-be69-c0cbb0c281af
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ BaseMemoryAllocationLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.uni b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.uni
new file mode 100644
index 000000000..3ca0b3612
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Null instance of Memory Allocation Library
+//
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+// Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of Memory Allocation Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Memory Allocation Library for build testing only."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c
new file mode 100644
index 000000000..a33f1ddd7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c
@@ -0,0 +1,31 @@
+/** @file
+ Null Platform Hook Library instance.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/PlatformHookLib.h>
+
+/**
+ Performs platform specific initialization required for the CPU to access
+ the hardware associated with a SerialPortLib instance. This function does
+ not intiailzie the serial port hardware itself. Instead, it initializes
+ hardware devices that are required for the CPU to access the serial port
+ hardware. This function may be called more than once.
+
+ @retval RETURN_SUCCESS The platform specific initialization succeeded.
+ @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
new file mode 100644
index 000000000..e61c20229
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
@@ -0,0 +1,30 @@
+## @file
+# Null Platform Hook Library instance.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BasePlatformHookLibNull
+ MODULE_UNI_FILE = BasePlatformHookLibNull.uni
+ FILE_GUID = EBC3AEAD-CC13-49b0-A678-5BED93956955
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BasePlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni
new file mode 100644
index 000000000..78d19cbfc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null Platform Hook Library instance.
+//
+// Null Platform Hook Library instance.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null Platform Hook Library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null Platform Hook Library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c
new file mode 100644
index 000000000..33a896bee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c
@@ -0,0 +1,105 @@
+/** @file
+ Null Reset System Library instance that only generates ASSERT() conditions.
+
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <Library/ResetSystemLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes a systemwide reset. The exact type of the reset is
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+ the platform must pick a supported reset type to perform.The platform may
+ optionally log the parameters from any non-normal reset that occurs.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData The data buffer starts with a Null-terminated string,
+ followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+ IN UINTN DataSize,
+ IN VOID *ResetData
+ )
+{
+ ResetCold ();
+}
+
+/**
+ The ResetSystem function resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
new file mode 100644
index 000000000..6a318861d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# Null Reset System Library instance that only generates ASSERT() conditions.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseResetSystemLibNull
+ MODULE_UNI_FILE = BaseResetSystemLibNull.uni
+ FILE_GUID = 667A8B1C-9C97-4b2a-AE7E-568772FE45F3
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ResetSystemLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BaseResetSystemLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni
new file mode 100644
index 000000000..f633c8236
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null Reset System Library instance that only generates ASSERT() conditions.
+//
+// Null Reset System Library instance that only generates ASSERT() conditions.
+//
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null Reset System Library instance that only generates ASSERT() conditions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null Reset System Library instance that only generates ASSERT() conditions."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
new file mode 100644
index 000000000..9cb50dd80
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
@@ -0,0 +1,1104 @@
+/** @file
+ 16550 UART Serial Port library functions
+
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PlatformHookLib.h>
+#include <Library/BaseLib.h>
+
+//
+// PCI Defintions.
+//
+#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
+
+//
+// 16550 UART register offsets and bitfields
+//
+#define R_UART_RXBUF 0 // LCR_DLAB = 0
+#define R_UART_TXBUF 0 // LCR_DLAB = 0
+#define R_UART_BAUD_LOW 0 // LCR_DLAB = 1
+#define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1
+#define R_UART_IER 1 // LCR_DLAB = 0
+#define R_UART_FCR 2
+#define B_UART_FCR_FIFOE BIT0
+#define B_UART_FCR_FIFO64 BIT5
+#define R_UART_LCR 3
+#define B_UART_LCR_DLAB BIT7
+#define R_UART_MCR 4
+#define B_UART_MCR_DTRC BIT0
+#define B_UART_MCR_RTS BIT1
+#define R_UART_LSR 5
+#define B_UART_LSR_RXRDY BIT0
+#define B_UART_LSR_TXRDY BIT5
+#define B_UART_LSR_TEMT BIT6
+#define R_UART_MSR 6
+#define B_UART_MSR_CTS BIT4
+#define B_UART_MSR_DSR BIT5
+#define B_UART_MSR_RI BIT6
+#define B_UART_MSR_DCD BIT7
+
+//
+// 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
+//
+typedef struct {
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 PowerManagementStatusAndControlRegister;
+} PCI_UART_DEVICE_INFO;
+
+/**
+ Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
+ width and defaults to 8 bit access, and supports 8 or 32 bit access.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to read.
+
+ @return The value read from the 16550 register.
+
+**/
+UINT8
+SerialPortReadRegister (
+ UINTN Base,
+ UINTN Offset
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (PcdGet8 (PcdSerialRegisterAccessWidth) == 32) {
+ return (UINT8) MmioRead32 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ }
+ return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ } else {
+ return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ }
+}
+
+/**
+ Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
+ width and defaults to 8 bit access, and supports 8 or 32 bit access.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to write.
+ @param Value The value to write to the 16550 register specified by Offset.
+
+ @return The value written to the 16550 register.
+
+**/
+UINT8
+SerialPortWriteRegister (
+ UINTN Base,
+ UINTN Offset,
+ UINT8 Value
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (PcdGet8 (PcdSerialRegisterAccessWidth) == 32) {
+ return (UINT8) MmioWrite32 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), (UINT8)Value);
+ }
+ return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ } else {
+ return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ }
+}
+
+/**
+ Update the value of an 16-bit PCI configuration register in a PCI device. If the
+ PCI Configuration register specified by PciAddress is already programmed with a
+ non-zero value, then return the current value. Otherwise update the PCI configuration
+ register specified by PciAddress with the value specified by Value and return the
+ value programmed into the PCI configuration register. All values must be masked
+ using the bitmask specified by Mask.
+
+ @param PciAddress PCI Library address of the PCI Configuration register to update.
+ @param Value The value to program into the PCI Configuration Register.
+ @param Mask Bitmask of the bits to check and update in the PCI configuration register.
+
+**/
+UINT16
+SerialPortLibUpdatePciRegister16 (
+ UINTN PciAddress,
+ UINT16 Value,
+ UINT16 Mask
+ )
+{
+ UINT16 CurrentValue;
+
+ CurrentValue = PciRead16 (PciAddress) & Mask;
+ if (CurrentValue != 0) {
+ return CurrentValue;
+ }
+ return PciWrite16 (PciAddress, Value & Mask);
+}
+
+/**
+ Update the value of an 32-bit PCI configuration register in a PCI device. If the
+ PCI Configuration register specified by PciAddress is already programmed with a
+ non-zero value, then return the current value. Otherwise update the PCI configuration
+ register specified by PciAddress with the value specified by Value and return the
+ value programmed into the PCI configuration register. All values must be masked
+ using the bitmask specified by Mask.
+
+ @param PciAddress PCI Library address of the PCI Configuration register to update.
+ @param Value The value to program into the PCI Configuration Register.
+ @param Mask Bitmask of the bits to check and update in the PCI configuration register.
+
+ @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
+
+**/
+UINT32
+SerialPortLibUpdatePciRegister32 (
+ UINTN PciAddress,
+ UINT32 Value,
+ UINT32 Mask
+ )
+{
+ UINT32 CurrentValue;
+
+ CurrentValue = PciRead32 (PciAddress) & Mask;
+ if (CurrentValue != 0) {
+ return CurrentValue;
+ }
+ return PciWrite32 (PciAddress, Value & Mask);
+}
+
+/**
+ Retrieve the I/O or MMIO base address register for the PCI UART device.
+
+ This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
+ Device if they are not already enabled.
+
+ @return The base address register of the UART device.
+
+**/
+UINTN
+GetSerialRegisterBase (
+ VOID
+ )
+{
+ UINTN PciLibAddress;
+ UINTN BusNumber;
+ UINTN SubordinateBusNumber;
+ UINT32 ParentIoBase;
+ UINT32 ParentIoLimit;
+ UINT16 ParentMemoryBase;
+ UINT16 ParentMemoryLimit;
+ UINT32 IoBase;
+ UINT32 IoLimit;
+ UINT16 MemoryBase;
+ UINT16 MemoryLimit;
+ UINTN SerialRegisterBase;
+ UINTN BarIndex;
+ UINT32 RegisterBaseMask;
+ PCI_UART_DEVICE_INFO *DeviceInfo;
+
+ //
+ // Get PCI Device Info
+ //
+ DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
+
+ //
+ // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
+ //
+ if (DeviceInfo->Device == 0xff) {
+ return (UINTN)PcdGet64 (PcdSerialRegisterBase);
+ }
+
+ //
+ // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
+ //
+ ParentMemoryBase = 0 >> 16;
+ ParentMemoryLimit = 0xfff00000 >> 16;
+ ParentIoBase = 0 >> 12;
+ ParentIoLimit = 0xf000 >> 12;
+
+ //
+ // Enable I/O and MMIO in PCI Bridge
+ // Assume Root Bus Numer is Zero.
+ //
+ for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
+ //
+ // Compute PCI Lib Address to PCI to PCI Bridge
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Retrieve and verify the bus numbers in the PCI to PCI Bridge
+ //
+ BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
+ return 0;
+ }
+
+ //
+ // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
+ //
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
+ MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;
+
+ //
+ // If PCI Bridge MMIO window is disabled, then return 0
+ //
+ if (MemoryLimit < MemoryBase) {
+ return 0;
+ }
+
+ //
+ // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
+ //
+ if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
+ return 0;
+ }
+ ParentMemoryBase = MemoryBase;
+ ParentMemoryLimit = MemoryLimit;
+ } else {
+ IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
+ if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
+ IoLimit = IoLimit >> 4;
+ } else {
+ IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
+ }
+ IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
+ if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
+ IoBase = IoBase >> 4;
+ } else {
+ IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
+ }
+
+ //
+ // If PCI Bridge I/O window is disabled, then return 0
+ //
+ if (IoLimit < IoBase) {
+ return 0;
+ }
+
+ //
+ // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
+ //
+ if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
+ return 0;
+ }
+ ParentIoBase = IoBase;
+ ParentIoLimit = IoLimit;
+ }
+ }
+
+ //
+ // Compute PCI Lib Address to PCI UART
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Find the first IO or MMIO BAR
+ //
+ RegisterBaseMask = 0xFFFFFFF0;
+ for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
+ SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
+ if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
+ //
+ // MMIO BAR is found
+ //
+ RegisterBaseMask = 0xFFFFFFF0;
+ break;
+ }
+
+ if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
+ //
+ // IO BAR is found
+ //
+ RegisterBaseMask = 0xFFFFFFF8;
+ break;
+ }
+ }
+
+ //
+ // MMIO or IO BAR is not found.
+ //
+ if (BarIndex == PCI_MAX_BAR) {
+ return 0;
+ }
+
+ //
+ // Program UART BAR
+ //
+ SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
+ PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
+ (UINT32)PcdGet64 (PcdSerialRegisterBase),
+ RegisterBaseMask
+ );
+
+ //
+ // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
+ //
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
+ return 0;
+ }
+ } else {
+ if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
+ return 0;
+ }
+ }
+
+ //
+ // Enable I/O and MMIO in PCI UART Device if they are not already enabled
+ //
+ PciOr16 (
+ PciLibAddress + PCI_COMMAND_OFFSET,
+ PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
+ );
+
+ //
+ // Force D0 state if a Power Management and Status Register is specified
+ //
+ if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
+ if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
+ PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
+ //
+ // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
+ }
+ }
+
+ //
+ // Get PCI Device Info
+ //
+ DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
+
+ //
+ // Enable I/O or MMIO in PCI Bridge
+ // Assume Root Bus Numer is Zero.
+ //
+ for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
+ //
+ // Compute PCI Lib Address to PCI to PCI Bridge
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
+ //
+ PciOr16 (
+ PciLibAddress + PCI_COMMAND_OFFSET,
+ PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
+ );
+
+ //
+ // Force D0 state if a Power Management and Status Register is specified
+ //
+ if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
+ if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
+ PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
+ }
+ }
+
+ BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ }
+
+ return SerialRegisterBase;
+}
+
+/**
+ Return whether the hardware flow control signal allows writing.
+
+ @param SerialRegisterBase The base address register of UART device.
+
+ @retval TRUE The serial port is writable.
+ @retval FALSE The serial port is not writable.
+**/
+BOOLEAN
+SerialPortWritable (
+ UINTN SerialRegisterBase
+ )
+{
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ if (PcdGetBool (PcdSerialDetectCable)) {
+ //
+ // Wait for both DSR and CTS to be set
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Wait
+ // 0 1 No cable connected. Wait
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clear to send. Transmit
+ //
+ return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
+ } else {
+ //
+ // Wait for both DSR and CTS to be set OR for DSR to be clear.
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Transmit
+ // 0 1 No cable connected. Transmit
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clar to send. Transmit
+ //
+ return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize the serial device hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ RETURN_STATUS Status;
+ UINTN SerialRegisterBase;
+ UINT32 Divisor;
+ UINT32 CurrentDivisor;
+ BOOLEAN Initialized;
+
+ //
+ // Perform platform specific initialization required to enable use of the 16550 device
+ // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
+ //
+ Status = PlatformHookSerialPortInitialize ();
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
+ Divisor++;
+ }
+
+ //
+ // Get the base address of the serial port in either I/O or MMIO space
+ //
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // See if the serial port is already initialized
+ //
+ Initialized = TRUE;
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
+ Initialized = FALSE;
+ }
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
+ CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
+ CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
+ if (CurrentDivisor != Divisor) {
+ Initialized = FALSE;
+ }
+ if (Initialized) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Wait for the serial port to be ready.
+ // Verify that both the transmit FIFO and the shift register are empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from PcdSerialLineControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
+
+ //
+ // Enable and reset FIFOs
+ // Strip reserved bits from PcdSerialFifoControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
+
+ //
+ // Set FIFO Polled Mode by clearing IER after setting FCR
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_IER, 0x00);
+
+ //
+ // Put Modem Control Register(MCR) into its reset state of 0x00.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Write data from buffer to serial device.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+
+ If Buffer is NULL, then ASSERT().
+
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINTN Index;
+ UINTN FifoSize;
+
+ if (Buffer == NULL) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return 0;
+ }
+
+ if (NumberOfBytes == 0) {
+ //
+ // Flush the hardware
+ //
+
+ //
+ // Wait for both the transmit FIFO and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
+
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase));
+ return 0;
+ }
+
+ //
+ // Compute the maximum size of the Tx FIFO
+ //
+ FifoSize = 1;
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
+ FifoSize = 16;
+ } else {
+ FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
+ }
+ }
+
+ Result = NumberOfBytes;
+ while (NumberOfBytes != 0) {
+ //
+ // Wait for the serial port to be ready, to make sure both the transmit FIFO
+ // and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
+
+ //
+ // Fill then entire Tx FIFO
+ //
+ for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase));
+
+ //
+ // Write byte to the transmit buffer.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
+ }
+ }
+ return Result;
+}
+
+/**
+ Reads data from a serial device into a buffer.
+
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.
+ @param NumberOfBytes Number of bytes to read from the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes read from the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINT8 Mcr;
+
+ if (NULL == Buffer) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return 0;
+ }
+
+ Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
+
+ for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
+ //
+ // Wait for the serial port to have some data.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
+ }
+ }
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+ }
+
+ //
+ // Read byte from the receive buffer.
+ //
+ *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
+ }
+
+ return Result;
+}
+
+
+/**
+ Polls a serial device to see if there is any data waiting to be read.
+
+ Polls aserial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+ VOID
+ )
+{
+ UINTN SerialRegisterBase;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return FALSE;
+ }
+
+ //
+ // Read the serial port status
+ //
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
+ }
+ return TRUE;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
+ }
+
+ return FALSE;
+}
+
+/**
+ Sets the control bits on a serial device.
+
+ @param Control Sets the bits of Control that are settable.
+
+ @retval RETURN_SUCCESS The new control bits were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+ IN UINT32 Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Mcr;
+
+ //
+ // First determine the parameter is invalid.
+ //
+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+ Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
+
+ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
+ Mcr |= B_UART_MCR_DTRC;
+ }
+
+ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
+ Mcr |= B_UART_MCR_RTS;
+ }
+
+ //
+ // Write the Modem Control Register.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Retrieve the status of the control bits on a serial device.
+
+ @param Control A pointer to return the current control signals from the serial device.
+
+ @retval RETURN_SUCCESS The control bits were read from the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+ OUT UINT32 *Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Msr;
+ UINT8 Mcr;
+ UINT8 Lsr;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ *Control = 0;
+
+ //
+ // Read the Modem Status Register.
+ //
+ Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
+
+ if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;
+ }
+
+ if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
+ *Control |= EFI_SERIAL_DATA_SET_READY;
+ }
+
+ if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
+ *Control |= EFI_SERIAL_RING_INDICATE;
+ }
+
+ if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
+ *Control |= EFI_SERIAL_CARRIER_DETECT;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+
+ if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
+ }
+
+ if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+
+ //
+ // Read the Line Status Register.
+ //
+ Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
+
+ if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+ }
+
+ if ((Lsr & B_UART_LSR_RXRDY) == 0) {
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+ data bits, and stop bits on a serial device.
+
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
+ device's default interface speed.
+ On output, the value actually set.
+ @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
+ serial interface. A ReceiveFifoDepth value of 0 will use
+ the device's default FIFO depth.
+ On output, the value actually set.
+ @param Timeout The requested time out for a single character in microseconds.
+ This timeout applies to both the transmit and receive side of the
+ interface. A Timeout value of 0 will use the device's default time
+ out value.
+ On output, the value actually set.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ On output, the value actually set.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ vaule of 0 will use the device's default data bit setting.
+ On output, the value actually set.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+ On output, the value actually set.
+
+ @retval RETURN_SUCCESS The new attributes were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+ IN OUT UINT64 *BaudRate,
+ IN OUT UINT32 *ReceiveFifoDepth,
+ IN OUT UINT32 *Timeout,
+ IN OUT EFI_PARITY_TYPE *Parity,
+ IN OUT UINT8 *DataBits,
+ IN OUT EFI_STOP_BITS_TYPE *StopBits
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT32 SerialBaudRate;
+ UINTN Divisor;
+ UINT8 Lcr;
+ UINT8 LcrData;
+ UINT8 LcrParity;
+ UINT8 LcrStop;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Check for default settings and fill in actual values.
+ //
+ if (*BaudRate == 0) {
+ *BaudRate = PcdGet32 (PcdSerialBaudRate);
+ }
+ SerialBaudRate = (UINT32) *BaudRate;
+
+ if (*DataBits == 0) {
+ LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
+ *DataBits = LcrData + 5;
+ } else {
+ if ((*DataBits < 5) || (*DataBits > 8)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Map 5..8 to 0..3
+ //
+ LcrData = (UINT8) (*DataBits - (UINT8) 5);
+ }
+
+ if (*Parity == DefaultParity) {
+ LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
+ switch (LcrParity) {
+ case 0:
+ *Parity = NoParity;
+ break;
+
+ case 3:
+ *Parity = EvenParity;
+ break;
+
+ case 1:
+ *Parity = OddParity;
+ break;
+
+ case 7:
+ *Parity = SpaceParity;
+ break;
+
+ case 5:
+ *Parity = MarkParity;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (*Parity) {
+ case NoParity:
+ LcrParity = 0;
+ break;
+
+ case EvenParity:
+ LcrParity = 3;
+ break;
+
+ case OddParity:
+ LcrParity = 1;
+ break;
+
+ case SpaceParity:
+ LcrParity = 7;
+ break;
+
+ case MarkParity:
+ LcrParity = 5;
+ break;
+
+ default:
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+
+ if (*StopBits == DefaultStopBits) {
+ LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
+ switch (LcrStop) {
+ case 0:
+ *StopBits = OneStopBit;
+ break;
+
+ case 1:
+ if (*DataBits == 5) {
+ *StopBits = OneFiveStopBits;
+ } else {
+ *StopBits = TwoStopBits;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (*StopBits) {
+ case OneStopBit:
+ LcrStop = 0;
+ break;
+
+ case OneFiveStopBits:
+ case TwoStopBits:
+ LcrStop = 1;
+ break;
+
+ default:
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
+ Divisor++;
+ }
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from line control value
+ //
+ Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
+
+ return RETURN_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
new file mode 100644
index 000000000..8b4ae3f1d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
@@ -0,0 +1,43 @@
+## @file
+# SerialPortLib instance for 16550 UART.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseSerialPortLib16550
+ MODULE_UNI_FILE = BaseSerialPortLib16550.uni
+ FILE_GUID = 9E7C00CF-355A-4d4e-BF60-0428CFF95540
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = SerialPortLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ IoLib
+ PlatformHookLib
+ PciLib
+
+[Sources]
+ BaseSerialPortLib16550.c
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterAccessWidth ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni
new file mode 100644
index 000000000..0717b59cc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SerialPortLib instance for 16550 UART.
+//
+// SerialPortLib instance for 16550 UART.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SerialPortLib instance for 16550 UART"
+
+#string STR_MODULE_DESCRIPTION #language en-US "SerialPortLib instance for 16550 UART."
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c
new file mode 100644
index 000000000..a12c7bc0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c
@@ -0,0 +1,228 @@
+/** @file
+ Library used for sorting routines.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SortLib.h>
+
+/**
+ Worker function for QuickSorting. This function is identical to PerformQuickSort,
+ except that is uses the pre-allocated buffer so the in place sorting does not need to
+ allocate and free buffers constantly.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+ if Buffer is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+ @param[in] Buffer Buffer of size ElementSize for use in swapping
+**/
+VOID
+EFIAPI
+QuickSortWorker (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction,
+ IN VOID *Buffer
+ )
+{
+ VOID *Pivot;
+ UINTN LoopCount;
+ UINTN NextSwapLocation;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+ ASSERT(Buffer != NULL);
+
+ if ( Count < 2
+ || ElementSize < 1
+ ){
+ return;
+ }
+
+ NextSwapLocation = 0;
+
+ //
+ // pick a pivot (we choose last element)
+ //
+ Pivot = ((UINT8*)BufferToSort+((Count-1)*ElementSize));
+
+ //
+ // Now get the pivot such that all on "left" are below it
+ // and everything "right" are above it
+ //
+ for ( LoopCount = 0
+ ; LoopCount < Count -1
+ ; LoopCount++
+ ){
+ //
+ // if the element is less than the pivot
+ //
+ if (CompareFunction((VOID*)((UINT8*)BufferToSort+((LoopCount)*ElementSize)),Pivot) <= 0){
+ //
+ // swap
+ //
+ CopyMem (Buffer, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), (UINT8*)BufferToSort+((LoopCount)*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+((LoopCount)*ElementSize), Buffer, ElementSize);
+
+ //
+ // increment NextSwapLocation
+ //
+ NextSwapLocation++;
+ }
+ }
+ //
+ // swap pivot to it's final position (NextSwapLocaiton)
+ //
+ CopyMem (Buffer, Pivot, ElementSize);
+ CopyMem (Pivot, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), Buffer, ElementSize);
+
+ //
+ // Now recurse on 2 paritial lists. neither of these will have the 'pivot' element
+ // IE list is sorted left half, pivot element, sorted right half...
+ //
+ if (NextSwapLocation >= 2) {
+ QuickSortWorker(
+ BufferToSort,
+ NextSwapLocation,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ if ((Count - NextSwapLocation - 1) >= 2) {
+ QuickSortWorker(
+ (UINT8 *)BufferToSort + (NextSwapLocation+1) * ElementSize,
+ Count - NextSwapLocation - 1,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+ return;
+}
+/**
+ Function to perform a Quick Sort alogrithm on a buffer of comparable elements.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+**/
+VOID
+EFIAPI
+PerformQuickSort (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction
+ )
+{
+ VOID *Buffer;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+
+ Buffer = AllocateZeroPool(ElementSize);
+ ASSERT(Buffer != NULL);
+
+ QuickSortWorker(
+ BufferToSort,
+ Count,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+
+ FreePool(Buffer);
+ return;
+}
+
+/**
+ Not supported in Base version.
+
+ @param[in] Buffer1 Ignored.
+ @param[in] Buffer2 Ignored.
+
+ ASSERT and return 0.
+**/
+INTN
+EFIAPI
+DevicePathCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+/**
+ Not supported in Base version.
+
+ @param[in] Buffer1 Ignored.
+ @param[in] Buffer2 Ignored.
+
+ ASSERT and return 0.
+**/
+INTN
+EFIAPI
+StringNoCaseCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+
+/**
+ Not supported in Base version.
+
+ @param[in] Buffer1 Ignored.
+ @param[in] Buffer2 Ignored.
+
+ ASSERT and return 0.
+**/
+INTN
+EFIAPI
+StringCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
new file mode 100644
index 000000000..308e891e2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Library used for sorting routines.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = BaseSortLib
+ MODULE_UNI_FILE = BaseSortLib.uni
+ FILE_GUID = 03F3331B-F12D-494f-BF37-E55A657F2497
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SortLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ BaseSortLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni
new file mode 100644
index 000000000..42bc43a1c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Library used for sorting routines.
+//
+// Library used for sorting routines.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Library used for sorting routines."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Library used for sorting routines."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c
new file mode 100644
index 000000000..134660f28
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.c
@@ -0,0 +1,551 @@
+/** @file
+ This library is only intended to be used by PlatformBootManagerLib
+ to show progress bar and LOGO.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016, Microsoft Corporation<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/PlatformLogo.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/BootLogo.h>
+#include <Protocol/BootLogo2.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Show LOGO returned from Edkii Platform Logo protocol on all consoles.
+
+ @retval EFI_SUCCESS Logo was displayed.
+ @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed.
+**/
+EFI_STATUS
+EFIAPI
+BootLogoEnableLogo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo;
+ EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute;
+ INTN OffsetX;
+ INTN OffsetY;
+ UINT32 SizeOfX;
+ UINT32 SizeOfY;
+ INTN DestX;
+ INTN DestY;
+ UINT32 Instance;
+ EFI_IMAGE_INPUT Image;
+ 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;
+ EDKII_BOOT_LOGO2_PROTOCOL *BootLogo2;
+ UINTN NumberOfLogos;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
+ UINTN LogoDestX;
+ UINTN LogoDestY;
+ UINTN LogoHeight;
+ UINTN LogoWidth;
+ UINTN NewDestX;
+ UINTN NewDestY;
+ UINTN BufferSize;
+
+ Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ 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)) {
+ UgaDraw = NULL;
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open Boot Logo Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (EFI_ERROR (Status)) {
+ BootLogo = NULL;
+ }
+
+ //
+ // Try to open Boot Logo 2 Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiBootLogo2ProtocolGuid, NULL, (VOID **) &BootLogo2);
+ if (EFI_ERROR (Status)) {
+ BootLogo2 = NULL;
+ }
+
+ //
+ // Erase Cursor from screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+
+ } else {
+ ASSERT (UgaDraw != NULL);
+ Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Blt = NULL;
+ NumberOfLogos = 0;
+ LogoDestX = 0;
+ LogoDestY = 0;
+ LogoHeight = 0;
+ LogoWidth = 0;
+ NewDestX = 0;
+ NewDestY = 0;
+ Instance = 0;
+ DestX = 0;
+ DestY = 0;
+ while (TRUE) {
+ //
+ // Get image from PlatformLogo protocol.
+ //
+ Status = PlatformLogo->GetImage (
+ PlatformLogo,
+ &Instance,
+ &Image,
+ &Attribute,
+ &OffsetX,
+ &OffsetY
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+ Blt = Image.Bitmap;
+
+ //
+ // Calculate the display position according to Attribute.
+ //
+ switch (Attribute) {
+ case EdkiiPlatformLogoDisplayAttributeLeftTop:
+ DestX = 0;
+ DestY = 0;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeCenterTop:
+ DestX = (SizeOfX - Image.Width) / 2;
+ DestY = 0;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeRightTop:
+ DestX = SizeOfX - Image.Width;
+ DestY = 0;
+ break;
+
+ case EdkiiPlatformLogoDisplayAttributeCenterLeft:
+ DestX = 0;
+ DestY = (SizeOfY - Image.Height) / 2;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeCenter:
+ DestX = (SizeOfX - Image.Width) / 2;
+ DestY = (SizeOfY - Image.Height) / 2;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeCenterRight:
+ DestX = SizeOfX - Image.Width;
+ DestY = (SizeOfY - Image.Height) / 2;
+ break;
+
+ case EdkiiPlatformLogoDisplayAttributeLeftBottom:
+ DestX = 0;
+ DestY = SizeOfY - Image.Height;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeCenterBottom:
+ DestX = (SizeOfX - Image.Width) / 2;
+ DestY = SizeOfY - Image.Height;
+ break;
+ case EdkiiPlatformLogoDisplayAttributeRightBottom:
+ DestX = SizeOfX - Image.Width;
+ DestY = SizeOfY - Image.Height;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ continue;
+ break;
+ }
+
+ DestX += OffsetX;
+ DestY += OffsetY;
+
+ if ((DestX >= 0) && (DestY >= 0)) {
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Image.Width,
+ Image.Height,
+ Image.Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else {
+ ASSERT (UgaDraw != NULL);
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) Blt,
+ EfiUgaBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Image.Width,
+ Image.Height,
+ Image.Width * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+
+ //
+ // Report displayed Logo information.
+ //
+ if (!EFI_ERROR (Status)) {
+ NumberOfLogos++;
+
+ if (NumberOfLogos == 1) {
+ //
+ // The first Logo.
+ //
+ LogoDestX = (UINTN) DestX;
+ LogoDestY = (UINTN) DestY;
+ LogoWidth = Image.Width;
+ LogoHeight = Image.Height;
+ } else {
+ //
+ // Merge new logo with old one.
+ //
+ NewDestX = MIN ((UINTN) DestX, LogoDestX);
+ NewDestY = MIN ((UINTN) DestY, LogoDestY);
+ LogoWidth = MAX ((UINTN) DestX + Image.Width, LogoDestX + LogoWidth) - NewDestX;
+ LogoHeight = MAX ((UINTN) DestY + Image.Height, LogoDestY + LogoHeight) - NewDestY;
+
+ LogoDestX = NewDestX;
+ LogoDestY = NewDestY;
+ }
+ }
+ }
+ }
+
+ if ((BootLogo == NULL && BootLogo2 == 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 * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
+ return EFI_UNSUPPORTED;
+ }
+ BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ LogoBlt = AllocatePool (BufferSize);
+ 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 {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) LogoBlt,
+ EfiUgaVideoToBltBuffer,
+ LogoDestX,
+ LogoDestY,
+ 0,
+ 0,
+ LogoWidth,
+ LogoHeight,
+ LogoWidth * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Attempt to register logo with Boot Logo 2 Protocol first
+ //
+ if (BootLogo2 != NULL) {
+ Status = BootLogo2->SetBootLogo (BootLogo2, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
+ }
+ //
+ // If Boot Logo 2 Protocol is not available or registration with Boot Logo 2
+ // Protocol failed, then attempt to register logo with Boot Logo Protocol
+ //
+ if (EFI_ERROR (Status) && BootLogo != NULL) {
+ Status = BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
+ }
+ //
+ // Status of this function is EFI_SUCCESS even if registration with Boot
+ // Logo 2 Protocol or Boot Logo Protocol fails.
+ //
+ Status = EFI_SUCCESS;
+ }
+ 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
+BootLogoDisableLogo (
+ VOID
+ )
+{
+
+ //
+ // Enable Cursor on Screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Update 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
+EFIAPI
+BootLogoUpdateProgress (
+ 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)) {
+ UgaDraw = NULL;
+ }
+ }
+ 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;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
new file mode 100644
index 000000000..7d50f2dfa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
@@ -0,0 +1,52 @@
+## @file
+# This library is only intended to be used by PlatformBootManagerLib
+# to show progress bar and logo.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Microsoft Corporation<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootLogoLib
+ MODULE_UNI_FILE = BootLogoLib.uni
+ FILE_GUID = 85CDAFAD-13BE-422A-A8E5-55A249600DC3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BootLogoLib|DXE_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootLogoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ PcdLib
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport ## SOMETIMES_CONSUMES
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiBootLogo2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUserManagerProtocolGuid ## CONSUMES
+ gEdkiiPlatformLogoProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.uni b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.uni
new file mode 100644
index 000000000..73399c9d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootLogoLib/BootLogoLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// This library is only intended to be used by PlatformBootManagerLib
+//
+// to show progress bar and logo.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"This library is only intended to be used by PlatformBootManagerLib"
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"to show progress bar and logo."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BmLib.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BmLib.c
new file mode 100644
index 000000000..4a1905a1c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BmLib.c
@@ -0,0 +1,83 @@
+/** @file
+Utility routines used by boot maintenance modules.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+/**
+ 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_NOT_FOUND The variable was not found
+
+**/
+EFI_STATUS
+EfiLibDeleteVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VarGuid
+ )
+{
+ return gRT->SetVariable (
+ VarName,
+ VarGuid,
+ 0,
+ 0,
+ NULL
+ );
+}
+
+/**
+ 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;
+}
+
+/**
+ 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;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenance.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenance.c
new file mode 100644
index 000000000..28592f9f4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenance.c
@@ -0,0 +1,1770 @@
+/** @file
+The functions for Boot Maintainence Main menu.
+
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+#define FRONT_PAGE_KEY_OFFSET 0x4000
+//
+// Boot video resolution and text mode.
+//
+UINT32 mBmmBootHorizontalResolution = 0;
+UINT32 mBmmBootVerticalResolution = 0;
+UINT32 mBmmBootTextModeColumn = 0;
+UINT32 mBmmBootTextModeRow = 0;
+//
+// BIOS setup video resolution and text mode.
+//
+UINT32 mBmmSetupTextModeColumn = 0;
+UINT32 mBmmSetupTextModeRow = 0;
+UINT32 mBmmSetupHorizontalResolution = 0;
+UINT32 mBmmSetupVerticalResolution = 0;
+
+BOOLEAN mBmmModeInitialized = FALSE;
+
+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)
+ }
+ },
+ //
+ // {165A028F-0BB2-4b5f-8747-77592E3F6499}
+ //
+ { 0x165a028f, 0xbb2, 0x4b5f, { 0x87, 0x47, 0x77, 0x59, 0x2e, 0x3f, 0x64, 0x99 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_GUID mBootMaintGuid = BOOT_MAINT_FORMSET_GUID;
+
+CHAR16 mBootMaintStorageName[] = L"BmmData";
+BMM_CALLBACK_DATA gBootMaintenancePrivate = {
+ BMM_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ BootMaintExtractConfig,
+ BootMaintRouteConfig,
+ BootMaintCallback
+ }
+};
+
+BMM_CALLBACK_DATA *mBmmCallbackInfo = &gBootMaintenancePrivate;
+BOOLEAN mAllMenuInit = FALSE;
+BOOLEAN mFirstEnterBMMForm = FALSE;
+
+/**
+ 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
+ );
+
+/**
+
+ Update the menus in the BMM page.
+
+**/
+VOID
+CustomizeMenus (
+ VOID
+ );
+
+/**
+ 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
+BmmSetConsoleMode (
+ 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 required resolution and text mode is setup mode.
+ //
+ NewHorizontalResolution = mBmmSetupHorizontalResolution;
+ NewVerticalResolution = mBmmSetupVerticalResolution;
+ NewColumns = mBmmSetupTextModeColumn;
+ NewRows = mBmmSetupTextModeRow;
+ } else {
+ //
+ // The required resolution and text mode is boot mode.
+ //
+ NewHorizontalResolution = mBmmBootHorizontalResolution;
+ NewVerticalResolution = mBmmBootVerticalResolution;
+ NewColumns = mBmmBootTextModeColumn;
+ NewRows = mBmmBootTextModeRow;
+ }
+
+ 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 required 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, mBmmSetupTextModeColumn);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdConOutRow, mBmmSetupTextModeRow);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ if (Index == MaxTextMode) {
+ //
+ // If required 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;
+}
+
+/**
+ 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 *
+UiDevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ToText;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+
+ if (DevPath == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevPathToText
+ );
+ ASSERT_EFI_ERROR (Status);
+ ToText = DevPathToText->ConvertDevicePathToText (
+ DevPath,
+ FALSE,
+ TRUE
+ );
+ ASSERT (ToText != NULL);
+ return ToText;
+}
+
+/**
+ Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
+ The caller is responsible for freeing the allocated buffer using FreePool().
+
+ @param DevicePath Device path.
+
+ @return A new allocated string that represents the file name.
+
+**/
+CHAR16 *
+ExtractFileNameFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *String;
+ CHAR16 *MatchString;
+ CHAR16 *LastMatch;
+ CHAR16 *FileName;
+ UINTN Length;
+
+ ASSERT(DevicePath != NULL);
+
+ String = UiDevicePathToStr(DevicePath);
+ MatchString = String;
+ LastMatch = String;
+ FileName = NULL;
+
+ while(MatchString != NULL){
+ LastMatch = MatchString + 1;
+ MatchString = StrStr(LastMatch,L"\\");
+ }
+
+ Length = StrLen(LastMatch);
+ FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
+ if (FileName != NULL) {
+ *(FileName + Length) = 0;
+ }
+
+ FreePool(String);
+
+ return FileName;
+}
+
+/**
+ Extract device path for given HII handle and class guid.
+
+ @param Handle The HII handle.
+
+ @retval NULL Fail to get the device path string.
+ @return PathString Get the device path string.
+
+**/
+CHAR16 *
+BmmExtractDevicePathFromHiiHandle (
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ ASSERT (Handle != NULL);
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get device path string.
+ //
+ return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
+
+}
+
+/**
+ Converts the unicode character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+HiiToLower (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+}
+
+/**
+ Update the progress string through the offset value.
+
+ @param Offset The offset value
+ @param Configuration Point to the configuration string.
+
+**/
+EFI_STRING
+UpdateProgress(
+ IN UINTN Offset,
+ IN EFI_STRING Configuration
+)
+{
+ UINTN Length;
+ EFI_STRING StringPtr;
+ EFI_STRING ReturnString;
+
+ StringPtr = NULL;
+ ReturnString = NULL;
+
+ //
+ // &OFFSET=XXXX followed by a Null-terminator.
+ // Length = StrLen (L"&OFFSET=") + 4 + 1
+ //
+ Length = StrLen (L"&OFFSET=") + 4 + 1;
+
+ StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
+
+ if (StringPtr == NULL) {
+ return NULL;
+ }
+
+ UnicodeSPrint (
+ StringPtr,
+ (8 + 4 + 1) * sizeof (CHAR16),
+ L"&OFFSET=%04x",
+ Offset
+ );
+
+ ReturnString = StrStr (Configuration, StringPtr);
+
+ if (ReturnString == NULL) {
+ //
+ // If doesn't find the string in Configuration, convert the string to lower case then search again.
+ //
+ HiiToLower (StringPtr);
+ ReturnString = StrStr (Configuration, StringPtr);
+ }
+
+ FreePool (StringPtr);
+
+ return ReturnString;
+}
+
+/**
+ Update the terminal content in TerminalMenu.
+
+ @param BmmData The BMM fake NV data.
+
+**/
+VOID
+UpdateTerminalContent (
+ IN BMM_FAKE_NV_DATA *BmmData
+ )
+{
+ UINT16 Index;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ ASSERT (NewMenuEntry != NULL);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ NewTerminalContext->BaudRateIndex = BmmData->COMBaudRate[Index];
+ ASSERT (BmmData->COMBaudRate[Index] < (ARRAY_SIZE (BaudRateList)));
+ NewTerminalContext->BaudRate = BaudRateList[BmmData->COMBaudRate[Index]].Value;
+ NewTerminalContext->DataBitsIndex = BmmData->COMDataRate[Index];
+ ASSERT (BmmData->COMDataRate[Index] < (ARRAY_SIZE (DataBitsList)));
+ NewTerminalContext->DataBits = (UINT8) DataBitsList[BmmData->COMDataRate[Index]].Value;
+ NewTerminalContext->StopBitsIndex = BmmData->COMStopBits[Index];
+ ASSERT (BmmData->COMStopBits[Index] < (ARRAY_SIZE (StopBitsList)));
+ NewTerminalContext->StopBits = (UINT8) StopBitsList[BmmData->COMStopBits[Index]].Value;
+ NewTerminalContext->ParityIndex = BmmData->COMParity[Index];
+ ASSERT (BmmData->COMParity[Index] < (ARRAY_SIZE (ParityList)));
+ NewTerminalContext->Parity = (UINT8) ParityList[BmmData->COMParity[Index]].Value;
+ NewTerminalContext->TerminalType = BmmData->COMTerminalType[Index];
+ NewTerminalContext->FlowControl = BmmData->COMFlowControl[Index];
+ ChangeTerminalDevicePath (
+ NewTerminalContext->DevicePath,
+ FALSE
+ );
+ }
+}
+
+/**
+ Update the console content in ConsoleMenu.
+
+ @param ConsoleName The name for the console device type.
+ @param BmmData The BMM fake NV data.
+
+**/
+VOID
+UpdateConsoleContent(
+ IN CHAR16 *ConsoleName,
+ IN BMM_FAKE_NV_DATA *BmmData
+ )
+{
+ UINT16 Index;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ if (StrCmp (ConsoleName, L"ConIn") == 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 = BmmData->ConsoleInCheck[Index];
+ }
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleInpMenu.MenuNumber < MAX_MENU_NUMBER);
+ NewTerminalContext->IsConIn = BmmData->ConsoleInCheck[Index + ConsoleInpMenu.MenuNumber];
+ }
+ }
+
+ if (StrCmp (ConsoleName, L"ConOut") == 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 = BmmData->ConsoleOutCheck[Index];
+ }
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleOutMenu.MenuNumber < MAX_MENU_NUMBER);
+ NewTerminalContext->IsConOut = BmmData->ConsoleOutCheck[Index + ConsoleOutMenu.MenuNumber];
+ }
+ }
+ if (StrCmp (ConsoleName, L"ErrOut") == 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 = BmmData->ConsoleErrCheck[Index];
+ }
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleErrMenu.MenuNumber < MAX_MENU_NUMBER);
+ NewTerminalContext->IsStdErr = BmmData->ConsoleErrCheck[Index + ConsoleErrMenu.MenuNumber];
+ }
+ }
+}
+
+/**
+ 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, &mBootMaintGuid, 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 (&mBootMaintGuid, 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_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+ BOOLEAN TerminalAttChange;
+ BMM_CALLBACK_DATA *Private;
+ UINTN Offset;
+
+ 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, &mBootMaintGuid, 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;
+ Offset = 0;
+ //
+ // 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->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) {
+ Status = Var_UpdateBootNext (Private);
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootNext);
+ goto Exit;
+ }
+ }
+
+ //
+ // 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;
+ }
+
+ Status = Var_DelBootOption ();
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionDel);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) {
+ Status = Var_UpdateBootOrder (Private);
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionOrder);
+ goto Exit;
+ }
+ }
+
+ 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)
+ );
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootTimeOut);
+ goto Exit;
+ }
+ Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut;
+ }
+
+ //
+ // 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;
+ }
+ Status = Var_DelDriverOption ();
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionDel);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) {
+ Status = Var_UpdateDriverOrder (Private);
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionOrder);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0){
+ Status = Var_UpdateConMode(Private);
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutMode);
+ goto Exit;
+ }
+ }
+
+ 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;
+ }
+
+ TerminalAttChange = TRUE;
+ }
+ if (TerminalAttChange) {
+ if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMBaudRate);
+ } else if (CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMDataRate);
+ } else if (CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMStopBits);
+ } else if (CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMParity);
+ } else if (CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMTerminalType);
+ } else if (CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMFlowControl);
+ }
+ Status = Var_UpdateConsoleInpOption ();
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ Status = Var_UpdateConsoleOutOption ();
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ Status = Var_UpdateErrorOutOption ();
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+ //
+ // Check data which located in Console Options Menu and save the settings if need
+ //
+ if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0){
+ Status = Var_UpdateConsoleInpOption();
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleInCheck);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0){
+ Status = Var_UpdateConsoleOutOption();
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutCheck);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0){
+ Status = Var_UpdateErrorOutOption();
+ if (EFI_ERROR (Status)) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleErrCheck);
+ goto Exit;
+ }
+ }
+
+ if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0 ||
+ CompareMem (NewBmmData->BootOptionalData, OldBmmData->BootOptionalData, sizeof (NewBmmData->BootOptionalData)) != 0) {
+ Status = Var_UpdateBootOption (Private);
+ NewBmmData->BootOptionChanged = FALSE;
+ if (EFI_ERROR (Status)) {
+ if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootDescriptionData);
+ } else {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionalData);
+ }
+ goto Exit;
+ }
+ BOpt_GetBootOptions (Private);
+ }
+
+ if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0 ||
+ CompareMem (NewBmmData->DriverOptionalData, OldBmmData->DriverOptionalData, sizeof (NewBmmData->DriverOptionalData)) != 0) {
+ Status = Var_UpdateDriverOption (
+ Private,
+ Private->BmmHiiHandle,
+ NewBmmData->DriverDescriptionData,
+ NewBmmData->DriverOptionalData,
+ NewBmmData->ForceReconnect
+ );
+ NewBmmData->DriverOptionChanged = FALSE;
+ NewBmmData->ForceReconnect = TRUE;
+ if (EFI_ERROR (Status)) {
+ if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0) {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverDescriptionData);
+ } else {
+ Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionalData);
+ }
+ goto Exit;
+ }
+
+ BOpt_GetDriverOptions (Private);
+ }
+
+ //
+ // After user do the save action, need to update OldBmmData.
+ //
+ CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA));
+
+ return EFI_SUCCESS;
+
+Exit:
+ //
+ // Fail to save the data, update the progress string.
+ //
+ *Progress = UpdateProgress (Offset, Configuration);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ return Status;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ 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;
+ BMM_FAKE_NV_DATA *OldFakeNVMap;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL * File;
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_FORM_OPEN) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_VALUE_TRIGGER_FORM_OPEN_ACTION) {
+ if (!mFirstEnterBMMForm) {
+ //
+ // BMMUiLib depends on LegacyUi library to show legacy menus.
+ // If we want to show Legacy menus correctly in BMM page,
+ // we must do it after the LegacyUi library has already been initialized.
+ // Opening the BMM form is the appropriate time that the LegacyUi library has already been initialized.
+ // So we do the tasks which are related to legacy menus here.
+ // 1. Update the menus (including legacy munu) show in BootMiantenanceManager page.
+ // 2. Re-scan the BootOption menus (including the legacy boot option).
+ //
+ CustomizeMenus ();
+ EfiBootManagerRefreshAllBootOption ();
+ BOpt_GetBootOptions (Private);
+ mFirstEnterBMMForm = TRUE;
+ }
+ }
+ }
+ //
+ // Retrieve uncommitted data from Form Browser
+ //
+ CurrentFakeNVMap = &Private->BmmFakeNvData;
+ OldFakeNVMap = &Private->BmmOldFakeNVData;
+ HiiGetBrowserData (&mBootMaintGuid, 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 FORM_BOOT_ADD_ID:
+ // Leave BMM and enter FileExplorer.
+ ChooseFile (NULL, L".efi", CreateBootOptionFromFile, &File);
+ break;
+
+ case FORM_DRV_ADD_FILE_ID:
+ // Leave BMM and enter FileExplorer.
+ ChooseFile (NULL, L".efi", CreateDriverOptionFromFile, &File);
+ 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_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;
+
+ default:
+ break;
+ }
+ } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
+ Index = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
+ Private->CurrentTerminal = Index;
+
+ CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
+ UpdateTerminalPage (Private);
+
+ } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
+ Index = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
+
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index);
+ 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);
+ }
+ }
+ if (QuestionId == KEY_VALUE_BOOT_FROM_FILE){
+ // Leave BMM and enter FileExplorer.
+ ChooseFile (NULL, L".efi", BootFromFile, &File);
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) {
+ CleanUselessBeforeSubmit (Private);
+ CurrentFakeNVMap->BootOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) {
+ CleanUselessBeforeSubmit (Private);
+ CurrentFakeNVMap->DriverOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) {
+ //
+ // Discard changes and exit formset
+ //
+ ZeroMem (CurrentFakeNVMap->DriverOptionalData, sizeof (CurrentFakeNVMap->DriverOptionalData));
+ ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
+ ZeroMem (OldFakeNVMap->DriverOptionalData, sizeof (OldFakeNVMap->DriverOptionalData));
+ ZeroMem (OldFakeNVMap->DriverDescriptionData, sizeof (OldFakeNVMap->DriverDescriptionData));
+ CurrentFakeNVMap->DriverOptionChanged = FALSE;
+ CurrentFakeNVMap->ForceReconnect = TRUE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) {
+ //
+ // Discard changes and exit formset
+ //
+ ZeroMem (CurrentFakeNVMap->BootOptionalData, sizeof (CurrentFakeNVMap->BootOptionalData));
+ ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
+ ZeroMem (OldFakeNVMap->BootOptionalData, sizeof (OldFakeNVMap->BootOptionalData));
+ ZeroMem (OldFakeNVMap->BootDescriptionData, sizeof (OldFakeNVMap->BootDescriptionData));
+ CurrentFakeNVMap->BootOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ } else if (QuestionId == KEY_VALUE_BOOT_DESCRIPTION || QuestionId == KEY_VALUE_BOOT_OPTION) {
+ CurrentFakeNVMap->BootOptionChanged = TRUE;
+ } else if (QuestionId == KEY_VALUE_DRIVER_DESCRIPTION || QuestionId == KEY_VALUE_DRIVER_OPTION) {
+ CurrentFakeNVMap->DriverOptionChanged = TRUE;
+ }
+
+ 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 {
+ switch (QuestionId) {
+ case KEY_VALUE_SAVE_AND_EXIT:
+ case KEY_VALUE_NO_SAVE_AND_EXIT:
+ if (QuestionId == KEY_VALUE_SAVE_AND_EXIT) {
+ CleanUselessBeforeSubmit (Private);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT) {
+ 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;
+ }
+ }
+ //
+ // Update the content in Terminal menu and Console menu here.
+ //
+ if (QuestionId == COM_BAUD_RATE_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_DATA_RATE_QUESTION_ID + Private->CurrentTerminal ||
+ QuestionId == COM_PARITY_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_STOP_BITS_QUESTION_ID + Private->CurrentTerminal ||
+ QuestionId == COM_TERMINAL_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_FLOWCONTROL_QUESTION_ID + Private->CurrentTerminal
+ ) {
+ UpdateTerminalContent(CurrentFakeNVMap);
+ }
+ if ((QuestionId >= CON_IN_DEVICE_QUESTION_ID) && (QuestionId < CON_IN_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
+ UpdateConsoleContent (L"ConIn",CurrentFakeNVMap);
+ } else if ((QuestionId >= CON_OUT_DEVICE_QUESTION_ID) && (QuestionId < CON_OUT_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
+ UpdateConsoleContent (L"ConOut", CurrentFakeNVMap);
+ } else if ((QuestionId >= CON_ERR_DEVICE_QUESTION_ID) && (QuestionId < CON_ERR_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
+ UpdateConsoleContent (L"ErrOut", CurrentFakeNVMap);
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ HiiSetBrowserData (&mBootMaintGuid, 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;
+ }
+ 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;
+ }
+ 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;
+ }
+}
+
+/**
+ This function is to clean some useless data before submit changes.
+
+ @param Private The BMM context data.
+
+**/
+VOID
+CleanUselessBeforeSubmit (
+ IN BMM_CALLBACK_DATA *Private
+ )
+{
+ UINT16 Index;
+ if (Private->BmmPreviousPageId != FORM_BOOT_DEL_ID) {
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ if (Private->BmmFakeNvData.BootOptionDel[Index] && !Private->BmmFakeNvData.BootOptionDelMark[Index]) {
+ Private->BmmFakeNvData.BootOptionDel[Index] = FALSE;
+ Private->BmmOldFakeNVData.BootOptionDel[Index] = FALSE;
+ }
+ }
+ }
+ if (Private->BmmPreviousPageId != FORM_DRV_DEL_ID) {
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ if (Private->BmmFakeNvData.DriverOptionDel[Index] && !Private->BmmFakeNvData.DriverOptionDelMark[Index]) {
+ Private->BmmFakeNvData.DriverOptionDel[Index] = FALSE;
+ Private->BmmOldFakeNVData.DriverOptionDel[Index] = FALSE;
+ }
+ }
+ }
+}
+
+/**
+
+ Update the menus in the BMM page.
+
+**/
+VOID
+CustomizeMenus (
+ VOID
+ )
+{
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartGuidLabel;
+ EFI_IFR_GUID_LABEL *EndGuidLabel;
+
+ //
+ // 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
+ //
+ StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartGuidLabel->Number = LABEL_FORM_MAIN_START;
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndGuidLabel->Number = LABEL_FORM_MAIN_END;
+
+ //
+ //Updata Front Page form
+ //
+ UiCustomizeBMMPage (
+ mBmmCallbackInfo->BmmHiiHandle,
+ StartOpCodeHandle
+ );
+
+ HiiUpdateForm (
+ mBmmCallbackInfo->BmmHiiHandle,
+ &mBootMaintGuid,
+ FORM_MAIN_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+/**
+ Create dynamic code for BMM and initialize all of BMM configuration data in BmmFakeNvData and
+ BmmOldFakeNVData member in BMM context data.
+
+ @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 = NONE_BOOTNEXT_VALUE;
+ 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);
+
+ //
+ // 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);
+
+ CallbackData->BmmFakeNvData.ForceReconnect = TRUE;
+
+ //
+ // Backup Initialize BMM configuartion data to BmmOldFakeNVData
+ //
+ CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA));
+}
+
+/**
+ 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_FindDrivers ();
+ InitializeListHead (&ConsoleInpMenu.Head);
+ InitializeListHead (&ConsoleOutMenu.Head);
+ InitializeListHead (&ConsoleErrMenu.Head);
+ InitializeListHead (&TerminalMenu.Head);
+ LocateSerialIo ();
+ GetAllConsoles ();
+ mAllMenuInit = TRUE;
+}
+
+/**
+ Free up all Menu Option list.
+
+**/
+VOID
+FreeAllMenu (
+ VOID
+ )
+{
+ if (!mAllMenuInit){
+ return;
+ }
+ BOpt_FreeMenu (&BootOptionMenu);
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_FreeMenu (&DriverMenu);
+ FreeAllConsoles ();
+ mAllMenuInit = FALSE;
+}
+
+/**
+ Initial the boot mode related parameters.
+
+**/
+VOID
+BmmInitialBootModeInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN BootTextColumn;
+ UINTN BootTextRow;
+
+ if (mBmmModeInitialized) {
+ return;
+ }
+
+ //
+ // 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.
+ //
+ mBmmBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
+ mBmmBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
+ }
+
+ if (SimpleTextOut != NULL) {
+ Status = SimpleTextOut->QueryMode (
+ SimpleTextOut,
+ SimpleTextOut->Mode->Mode,
+ &BootTextColumn,
+ &BootTextRow
+ );
+ mBmmBootTextModeColumn = (UINT32)BootTextColumn;
+ mBmmBootTextModeRow = (UINT32)BootTextRow;
+ }
+
+ //
+ // Get user defined text mode for setup.
+ //
+ mBmmSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
+ mBmmSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
+ mBmmSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);
+ mBmmSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);
+
+ mBmmModeInitialized = TRUE;
+}
+
+/**
+
+ Install Boot Maintenance 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
+BootMaintenanceManagerUiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mBmmCallbackInfo->BmmDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBmmHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mBmmCallbackInfo->BmmConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Post our Boot Maint VFR binary to the HII database.
+ //
+ mBmmCallbackInfo->BmmHiiHandle = HiiAddPackages (
+ &mBootMaintGuid,
+ mBmmCallbackInfo->BmmDriverHandle,
+ BootMaintenanceManagerBin,
+ BootMaintenanceManagerUiLibStrings,
+ NULL
+ );
+ ASSERT (mBmmCallbackInfo->BmmHiiHandle != NULL);
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mBmmCallbackInfo->FormBrowser2);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // 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));
+ ASSERT (Ptr != NULL);
+
+ //
+ // Initialize Bmm callback data.
+ //
+ mBmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_LOAD_CONTEXT);
+
+ mBmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_FILE_CONTEXT);
+
+ mBmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_HANDLE_CONTEXT);
+
+ mBmmCallbackInfo->MenuEntry = (BM_MENU_ENTRY *) Ptr;
+
+ mBmmCallbackInfo->BmmPreviousPageId = FORM_MAIN_ID;
+ mBmmCallbackInfo->BmmCurrentPageId = FORM_MAIN_ID;
+
+ InitAllMenu (mBmmCallbackInfo);
+
+ CreateUpdateData();
+ //
+ // Update boot maintenance manager page
+ //
+ InitializeBmmConfig(mBmmCallbackInfo);
+
+ BmmInitialBootModeInfo();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+
+**/
+EFI_STATUS
+EFIAPI
+BootMaintenanceManagerUiLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+
+{
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ if (mEndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mEndOpCodeHandle);
+ }
+
+ FreeAllMenu ();
+
+ //
+ // Remove our IFR data from HII database
+ //
+ HiiRemovePackages (mBmmCallbackInfo->BmmHiiHandle);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ mBmmCallbackInfo->BmmDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBmmHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mBmmCallbackInfo->BmmConfigAccess,
+ NULL
+ );
+
+ FreePool (mBmmCallbackInfo->LoadContext);
+ mBmmCallbackInfo->BmmDriverHandle = NULL;
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.h b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.h
new file mode 100644
index 000000000..67847d8bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.h
@@ -0,0 +1,1328 @@
+/** @file
+Header file for boot maintenance module.
+
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_MAINT_H_
+#define _BOOT_MAINT_H_
+
+#include "FormGuid.h"
+
+#include <Guid/TtyTerm.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/HiiBootMaintenanceFormset.h>
+
+#include <Protocol/LoadFile.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FormBrowserEx2.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/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/FileExplorerLib.h>
+#include "BootMaintenanceManagerCustomizedUi.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()
+
+//
+// Constants which are variable names used to access variables
+//
+
+#define VAR_CON_OUT_MODE L"ConOutMode"
+
+//
+// Variable created with this flag will be "Efi:...."
+//
+#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+extern EFI_GUID mBootMaintGuid;
+extern CHAR16 mBootMaintStorageName[];
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 BootMaintenanceManagerBin[];
+
+//
+// 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)
+
+//
+// Enumeration type definition
+//
+typedef UINT8 BBS_TYPE;
+
+typedef enum _TYPE_OF_TERMINAL {
+ TerminalTypePcAnsi = 0,
+ TerminalTypeVt100,
+ TerminalTypeVt100Plus,
+ TerminalTypeVtUtf8,
+ TerminalTypeTtyTerm,
+ TerminalTypeLinux,
+ TerminalTypeXtermR6,
+ TerminalTypeVt400,
+ TerminalTypeSCO
+} TYPE_OF_TERMINAL;
+
+//
+// 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
+
+//
+// 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_OFFSET 0x8000
+#define FILE_OPTION_MASK 0x7FFF
+#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_DEVICE_VAR_OFFSET VAR_OFFSET (ConsoleCheck)
+#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 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_DEVICE_QUESTION_ID QUESTION_ID (ConsoleCheck)
+#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 STRING_DEPOSITORY_NUMBER 8
+
+#define NONE_BOOTNEXT_VALUE (0xFFFF + 1)
+
+///
+/// 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 Deleted;
+
+ BOOLEAN IsLegacy;
+
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ UINT16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathList;
+ UINT8 *OptionalData;
+} BM_LOAD_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 {
+
+ UINTN Signature;
+
+ EFI_HII_HANDLE BmmHiiHandle;
+ EFI_HANDLE BmmDriverHandle;
+ ///
+ /// Boot Maintenance Manager Produced protocols
+ ///
+ EFI_HII_CONFIG_ACCESS_PROTOCOL BmmConfigAccess;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ 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_FORM_ID BmmCurrentPageId;
+ EFI_FORM_ID BmmPreviousPageId;
+ BOOLEAN BmmAskSaveOrNot;
+ BMM_FAKE_NV_DATA BmmFakeNvData;
+ BMM_FAKE_NV_DATA BmmOldFakeNVData;
+
+} BMM_CALLBACK_DATA;
+
+/**
+
+ 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
+ );
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param FreeMenu Menu to be freed
+
+**/
+VOID
+BOpt_FreeMenu (
+ BM_MENU_OPTION *FreeMenu
+ );
+
+/**
+
+ 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
+ );
+
+/**
+ 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
+ );
+
+//
+// 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.
+
+ @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
+ );
+
+/**
+ Delete Boot Option that represent a Deleted state in BootOptionMenu.
+
+ @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
+ );
+
+/**
+ 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 DriverOptionMenu.
+
+ @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
+ );
+
+/**
+ 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
+ );
+
+/**
+ This function delete and build Out of Band console device.
+
+ @param MenuIndex Menu index which user select in the terminal menu list.
+
+ @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_UpdateOutOfBandOption (
+ IN UINT16 MenuIndex
+ );
+
+/**
+ 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 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
+//
+/**
+ Create the global UpdateData structure.
+
+**/
+VOID
+CreateUpdateData (
+ VOID
+ );
+
+/**
+ 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 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
+ );
+
+/**
+ Update add boot/driver option page.
+
+ @param CallbackData The BMM context data.
+ @param FormId The form ID to be updated.
+ @param DevicePath Device path.
+
+**/
+VOID
+UpdateOptionPage(
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_FORM_ID FormId,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Get the index number (#### in Boot####) for the boot option pointed to a BBS legacy device type
+ specified by DeviceType.
+
+ @param DeviceType The legacy device type. It can be floppy, network, harddisk, cdrom,
+ etc.
+ @param OptionIndex Returns the index number (#### in Boot####).
+ @param OptionSize Return the size of the Boot### variable.
+
+**/
+VOID *
+GetLegacyBootOptionVar (
+ IN UINTN DeviceType,
+ OUT UINTN *OptionIndex,
+ OUT UINTN *OptionSize
+ );
+
+/**
+ 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
+ );
+
+
+/**
+ This function is to clean some useless data before submit changes.
+
+ @param Private The BMM context data.
+
+**/
+VOID
+CleanUselessBeforeSubmit (
+ IN BMM_CALLBACK_DATA *Private
+ );
+
+/**
+ 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
+ );
+
+/**
+ Remove the installed BootMaint and FileExplorer HiiPackages.
+
+**/
+VOID
+FreeBMPackage(
+ VOID
+ );
+
+/**
+ Install BootMaint and FileExplorer HiiPackages.
+
+**/
+VOID
+InitBootMaintenance(
+ VOID
+ );
+
+/**
+
+ 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
+ );
+
+/**
+ 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
+BmmSetConsoleMode (
+ BOOLEAN IsSetupMode
+ );
+
+
+/**
+ 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 *
+UiDevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+/**
+ Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
+ The caller is responsible for freeing the allocated buffer using FreePool().
+
+ @param DevicePath Device path.
+
+ @return A new allocated string that represents the file name.
+
+**/
+CHAR16 *
+ExtractFileNameFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Create boot option base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+
+**/
+BOOLEAN
+EFIAPI
+CreateBootOptionFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Create driver option base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+CreateDriverOptionFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Boot the file specified by the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+
+**/
+BOOLEAN
+EFIAPI
+BootFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+//
+// Global variable in this program (defined in data.c)
+//
+extern BM_MENU_OPTION BootOptionMenu;
+extern BM_MENU_OPTION DriverOptionMenu;
+extern BM_MENU_OPTION ConsoleInpMenu;
+extern BM_MENU_OPTION ConsoleOutMenu;
+extern BM_MENU_OPTION ConsoleErrMenu;
+extern BM_MENU_OPTION DriverMenu;
+extern BM_MENU_OPTION TerminalMenu;
+extern UINT16 TerminalType[9];
+extern COM_ATTR BaudRateList[19];
+extern COM_ATTR DataBitsList[4];
+extern COM_ATTR ParityList[5];
+extern COM_ATTR StopBitsList[3];
+extern EFI_GUID TerminalTypeGuid[9];
+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;
+extern BMM_CALLBACK_DATA gBootMaintenancePrivate;
+extern BMM_CALLBACK_DATA *mBmmCallbackInfo;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.vfr b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.vfr
new file mode 100644
index 000000000..69fb60632
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManager.vfr
@@ -0,0 +1,354 @@
+///** @file
+// Boot Maintenance Utility Formset
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#include "FormGuid.h"
+
+formset
+ guid = BOOT_MAINT_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_MAIN_TITLE),
+ help = STRING_TOKEN(STR_BOOT_MAINT_MANAGER_HELP),
+ classguid = gEfiIfrFrontPageGuid,
+
+ 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);
+ //
+ // Add this invisible text in order to indicate enter Boot Maintenance Manager form.
+ // To trigger the form open action.
+ //
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_NONE),
+ text = STRING_TOKEN(STR_NONE),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_TRIGGER_FORM_OPEN_ACTION;
+ endif;
+
+ label LABEL_FORM_MAIN_START;
+ //
+ // This is where we will dynamically add a Action type op-code to show
+ // the platform information.
+ //
+ label LABEL_FORM_MAIN_END;
+
+ 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_SETUP_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;
+ 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_ADD_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_DESC_TITLE);
+
+ label FORM_BOOT_ADD_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = BmmData.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 = BmmData.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_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_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_DRIVER_SETUP_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_ADD_FILE_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE);
+
+ label FORM_DRV_ADD_FILE_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = BmmData.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 = BmmData.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 = BmmData.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;
+
+ 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;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.c
new file mode 100644
index 000000000..ff5e9f8f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.c
@@ -0,0 +1,93 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Protocol/HiiConfigAccess.h>
+#include "BootMaintenanceManagerCustomizedUiSupport.h"
+
+/**
+ Customize menus in the page.
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] StartOpCodeHandle The context used to insert opcode.
+ @param[in] CustomizePageType The page type need to be customized.
+
+**/
+VOID
+UiCustomizeBMMPage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ //
+ // Create "Boot Option" menu.
+ //
+ BmmCreateBootOptionMenu(HiiHandle, StartOpCodeHandle);
+ //
+ // Create "Driver Option" menu.
+ //
+ BmmCreateDriverOptionMenu(HiiHandle, StartOpCodeHandle);
+ //
+ // Create "Com Option" menu.
+ //
+ BmmCreateComOptionMenu(HiiHandle, StartOpCodeHandle);
+ //
+ // Create "Boot From File" menu.
+ //
+ BmmCreateBootFromFileMenu(HiiHandle, StartOpCodeHandle);
+
+ //
+ // Find third party drivers which need to be shown in the Bmm page.
+ //
+ BmmListThirdPartyDrivers (HiiHandle, &gEfiIfrBootMaintenanceGuid, NULL, StartOpCodeHandle);
+
+ //
+ // Create empty line.
+ //
+ BmmCreateEmptyLine (HiiHandle, StartOpCodeHandle);
+
+ //
+ // Create "Boot Next" menu.
+ //
+ BmmCreateBootNextMenu (HiiHandle, StartOpCodeHandle);
+ //
+ // Create "Time Out" menu.
+ //
+ BmmCreateTimeOutMenu (HiiHandle, StartOpCodeHandle);
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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
+UiBMMCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.h b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.h
new file mode 100644
index 000000000..f1074c3b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUi.h
@@ -0,0 +1,54 @@
+/** @file
+ This library class defines a set of interfaces to customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CUSTOMIZED_UI_H__
+#define __CUSTOMIZED_UI_H__
+
+
+/**
+ Customize menus in the page.
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] StartOpCodeHandle The context used to insert opcode.
+
+**/
+VOID
+UiCustomizeBMMPage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param HiiHandle Points to the hii handle for this formset.
+ @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
+UiBMMCallbackHandler (
+ IN EFI_HII_HANDLE HiiHandle,
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.c
new file mode 100644
index 000000000..656106fc2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.c
@@ -0,0 +1,469 @@
+/** @file
+The functions for Boot Maintainence Main menu.
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "BootMaintenanceManager.h"
+#include "BootMaintenanceManagerCustomizedUiSupport.h"
+
+#define UI_HII_DRIVER_LIST_SIZE 0x8
+
+typedef struct {
+ EFI_STRING_ID PromptId;
+ EFI_STRING_ID HelpId;
+ EFI_STRING_ID DevicePathId;
+ EFI_GUID FormSetGuid;
+ BOOLEAN EmptyLineAfter;
+} UI_HII_DRIVER_INSTANCE;
+
+STATIC UI_HII_DRIVER_INSTANCE *gHiiDriverList;
+
+
+/**
+ Create the dynamic item to allow user to set the "BootNext" vaule.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootNextMenu(
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+ VOID *OptionsOpCodeHandle;
+ UINT32 BootNextIndex;
+
+ if (BootOptionMenu.MenuNumber == 0) {
+ return;
+ }
+
+ BootNextIndex = NONE_BOOTNEXT_VALUE;
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ 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_32,
+ Index
+ );
+ BootNextIndex = Index;
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_32,
+ Index
+ );
+ }
+ }
+
+ if (BootNextIndex == NONE_BOOTNEXT_VALUE) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NONE),
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_TYPE_NUM_SIZE_32,
+ NONE_BOOTNEXT_VALUE
+ );
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NONE),
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_32,
+ NONE_BOOTNEXT_VALUE
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ (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_4,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+}
+
+/**
+ Create Time Out Menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateTimeOutMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateNumericOpCode (
+ StartOpCodeHandle,
+ (EFI_QUESTION_ID) FORM_TIME_OUT_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ BOOT_TIME_OUT_VAR_OFFSET,
+ STRING_TOKEN(STR_NUM_AUTO_BOOT),
+ STRING_TOKEN(STR_HLP_AUTO_BOOT),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_2 | EFI_IFR_DISPLAY_UINT_DEC,
+ 0,
+ 65535,
+ 0,
+ NULL
+ );
+}
+
+/**
+ Create Boot Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ FORM_BOOT_SETUP_ID,
+ STRING_TOKEN (STR_FORM_BOOT_SETUP_TITLE),
+ STRING_TOKEN (STR_FORM_BOOT_SETUP_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_BOOT_SETUP_ID
+ );
+}
+
+/**
+ Create Driver Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateDriverOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ FORM_DRIVER_SETUP_ID,
+ STRING_TOKEN (STR_FORM_DRIVER_SETUP_TITLE),
+ STRING_TOKEN (STR_FORM_DRIVER_SETUP_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_DRIVER_SETUP_ID
+ );
+}
+
+/**
+ Create Com Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateComOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ FORM_CON_MAIN_ID,
+ STRING_TOKEN (STR_FORM_CON_MAIN_TITLE),
+ STRING_TOKEN (STR_FORM_CON_MAIN_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_CON_MAIN_ID
+ );
+}
+
+/**
+ Create Com Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootFromFileMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ FORM_MAIN_ID,
+ STRING_TOKEN (STR_BOOT_FROM_FILE),
+ STRING_TOKEN (STR_BOOT_FROM_FILE_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ KEY_VALUE_BOOT_FROM_FILE
+ );
+}
+
+/**
+ Create empty line menu in the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateEmptyLine (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0);
+}
+
+/**
+ Extract device path for given HII handle and class guid.
+
+ @param Handle The HII handle.
+
+ @retval NULL Fail to get the device path string.
+ @return PathString Get the device path string.
+
+**/
+CHAR16 *
+ExtractDevicePathFromHandle (
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ ASSERT (Handle != NULL);
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
+}
+
+/**
+ Check whether this driver need to be shown in the front page.
+
+ @param HiiHandle The hii handle for the driver.
+ @param Guid The special guid for the driver which is the target.
+ @param PromptId Return the prompt string id.
+ @param HelpId Return the help string id.
+ @param FormsetGuid Return the formset guid info.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+BOOLEAN
+IsRequiredDriver (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *Guid,
+ OUT EFI_STRING_ID *PromptId,
+ OUT EFI_STRING_ID *HelpId,
+ OUT VOID *FormsetGuid
+ )
+{
+ EFI_STATUS Status;
+ UINT8 ClassGuidNum;
+ EFI_GUID *ClassGuid;
+ EFI_IFR_FORM_SET *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ UINTN TempSize;
+ BOOLEAN RetVal;
+
+ Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+ TempSize = 0;
+ Ptr = (UINT8 *) Buffer;
+ while(TempSize < BufferSize) {
+ TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+
+ if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
+ Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+ continue;
+ }
+
+ ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0) {
+ if (!CompareGuid (Guid, ClassGuid)){
+ ClassGuid ++;
+ continue;
+ }
+
+ *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle;
+ *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help;
+ CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
+ RetVal = TRUE;
+ }
+ }
+
+ FreePool (Buffer);
+
+ return RetVal;
+}
+
+/**
+ Search the drivers in the system which need to show in the front page
+ and insert the menu to the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param ClassGuid The class guid for the driver which is the target.
+ @param SpecialHandlerFn The pointer to the specail handler function, if any.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+EFI_STATUS
+BmmListThirdPartyDrivers (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *ClassGuid,
+ IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
+ IN VOID *StartOpCodeHandle
+ )
+{
+ UINTN Index;
+ EFI_STRING String;
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ EFI_HII_HANDLE *HiiHandles;
+ CHAR16 *DevicePathStr;
+ UINTN Count;
+ UINTN CurrentSize;
+ UI_HII_DRIVER_INSTANCE *DriverListPtr;
+ EFI_STRING NewName;
+ BOOLEAN EmptyLineAfter;
+
+ if (gHiiDriverList != NULL) {
+ FreePool (gHiiDriverList);
+ }
+
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE));
+ ASSERT (gHiiDriverList != NULL);
+ DriverListPtr = gHiiDriverList;
+ CurrentSize = UI_HII_DRIVER_LIST_SIZE;
+
+ for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) {
+ if (!IsRequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) {
+ continue;
+ }
+
+ String = HiiGetString (HiiHandles[Index], Token, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ } else if (SpecialHandlerFn != NULL) {
+ //
+ // Check whether need to rename the driver name.
+ //
+ EmptyLineAfter = FALSE;
+ if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) {
+ FreePool (String);
+ String = NewName;
+ DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter;
+ }
+ }
+ DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ String = HiiGetString (HiiHandles[Index], TokenHelp, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ }
+ DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ DevicePathStr = ExtractDevicePathFromHandle(HiiHandles[Index]);
+ if (DevicePathStr != NULL){
+ DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
+ FreePool (DevicePathStr);
+ } else {
+ DriverListPtr[Count].DevicePathId = 0;
+ }
+
+ Count++;
+ if (Count >= CurrentSize) {
+ DriverListPtr = ReallocatePool (
+ CurrentSize * sizeof (UI_HII_DRIVER_INSTANCE),
+ (Count + UI_HII_DRIVER_LIST_SIZE)
+ * sizeof (UI_HII_DRIVER_INSTANCE),
+ gHiiDriverList
+ );
+ ASSERT (DriverListPtr != NULL);
+ gHiiDriverList = DriverListPtr;
+ CurrentSize += UI_HII_DRIVER_LIST_SIZE;
+ }
+ }
+
+ FreePool (HiiHandles);
+
+ Index = 0;
+ while (gHiiDriverList[Index].PromptId != 0) {
+ HiiCreateGotoExOpCode (
+ StartOpCodeHandle,
+ 0,
+ gHiiDriverList[Index].PromptId,
+ gHiiDriverList[Index].HelpId,
+ 0,
+ 0,
+ 0,
+ &gHiiDriverList[Index].FormSetGuid,
+ gHiiDriverList[Index].DevicePathId
+ );
+
+ if (gHiiDriverList[Index].EmptyLineAfter) {
+ BmmCreateEmptyLine (HiiHandle, StartOpCodeHandle);
+ }
+
+ Index ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.h b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.h
new file mode 100644
index 000000000..0dff6e556
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerCustomizedUiSupport.h
@@ -0,0 +1,141 @@
+/** @file
+ This library class defines a set of interfaces to be used by customize Ui module
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __BOOT_MAINTENANCE_MANAGER_UI_LIB_H__
+#define __BOOT_MAINTENANCE_MANAGER_UI_LIB_H__
+
+/**
+ Create Time Out Menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateTimeOutMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create the dynamic item to allow user to set the "BootNext" vaule.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootNextMenu(
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Boot Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Driver Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateDriverOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Com Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateComOptionMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create Com Option menu in the page.
+
+ @param[in] HiiHandle The hii handle for the Uiapp driver.
+ @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateBootFromFileMenu (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Create empty line menu in the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+**/
+VOID
+BmmCreateEmptyLine (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN VOID *StartOpCodeHandle
+ );
+
+/**
+ Rename the driver name if necessary.
+
+ @param DriverName Input the driver name.
+ @param NewDriverName Return the new driver name.
+ @param EmptyLineAfter Whether need to insert empty line.
+
+ @retval New driver name if compared, else NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *DRIVER_SPECIAL_HANDLER)(
+ IN CHAR16 *DriverName,
+ OUT CHAR16 **NewName,
+ OUT BOOLEAN *EmptyLineAfter
+);
+
+/**
+ Search the drivers in the system which need to show in the front page
+ and insert the menu to the front page.
+
+ @param HiiHandle The hii handle for the Uiapp driver.
+ @param ClassGuid The class guid for the driver which is the target.
+ @param SpecialHandlerFn The pointer to the specail handler function, if any.
+ @param StartOpCodeHandle The opcode handle to save the new opcode.
+
+ @retval EFI_SUCCESS Search the driver success
+
+**/
+EFI_STATUS
+BmmListThirdPartyDrivers (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *ClassGuid,
+ IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
+ IN VOID *StartOpCodeHandle
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerStrings.uni b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerStrings.uni
new file mode 100644
index 000000000..3d47473e6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerStrings.uni
@@ -0,0 +1,284 @@
+///** @file
+// String definitions for Boot Maintenance Utility.
+//
+// Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_NULL_STRING #language en-US " "
+ #language fr-FR " "
+#string STR_NONE #language en-US "NONE"
+ #language fr-FR "NONE"
+#string STR_MISSING_STRING #language en-US "Missing String"
+ #language fr-FR "Missing String"
+#string STR_FORM_MAIN_TITLE #language en-US "Boot Maintenance Manager"
+ #language fr-FR "Boot Maintenance Manager"
+#string STR_FORM_BOOT_SETUP_TITLE #language en-US "Boot Options"
+ #language fr-FR "Boot Options"
+#string STR_BOOT_MAINT_MANAGER_HELP #language en-US "This selection will take you to the Boot Maintenance Manager"
+ #language fr-FR "This selection will take you to the Boot Maintenance Manager"
+#string STR_FORM_BOOT_SETUP_HELP #language en-US "Modify system boot options"
+ #language fr-FR "Modify system boot options"
+#string STR_FORM_DRIVER_SETUP_TITLE #language en-US "Driver Options"
+ #language fr-FR "Driver Options"
+#string STR_FORM_DRIVER_SETUP_HELP #language en-US "Modify boot driver options"
+ #language fr-FR "Modify boot driver options"
+#string STR_FORM_BOOT_ADD_TITLE #language en-US "Add Boot Option"
+ #language fr-FR "Add Boot Option"
+#string STR_FORM_BOOT_ADD_HELP #language en-US "Add EFI Application or Removable Fs as Boot Option"
+ #language fr-FR "Add EFI Application or Removable Fs as Boot Option"
+#string STR_FORM_BOOT_DEL_TITLE #language en-US "Delete Boot Option"
+ #language fr-FR "Delete Boot Option"
+#string STR_FORM_BOOT_IMMEDIATE_HELP #language en-US "Will be valid immediately"
+ #language fr-FR "Will be valid immediately"
+#string STR_FORM_BOOT_CHG_TITLE #language en-US "Change Boot Order"
+ #language fr-FR "Change Boot Order"
+#string STR_FORM_DRV_ADD_TITLE #language en-US "Add Driver Option"
+ #language fr-FR "Add Driver Option"
+#string STR_FORM_DRV_ADD_HELP #language en-US "Add .EFI Driver as Driver Option"
+ #language fr-FR "Add .EFI Driver as Driver Option"
+#string STR_FORM_DRV_DEL_TITLE #language en-US "Delete Driver Option"
+ #language fr-FR "Delete Driver Option"
+#string STR_FORM_DRV_CHG_TITLE #language en-US "Change Driver Order"
+ #language fr-FR "Change Driver Order"
+#string STR_FORM_NEXT_BOOT_HELP #language en-US "Will be valid on next boot"
+ #language fr-FR "Will be valid on next boot"
+#string STR_FORM_BOOT_NEXT_TITLE #language en-US "Set Boot Next Value"
+ #language fr-FR "Set Boot Next Value"
+#string STR_FORM_BOOT_NEXT_HELP #language en-US "Modify next boot behavior"
+ #language fr-FR "Modify next boot behavior"
+#string STR_FORM_TIME_OUT_TITLE #language en-US "Set Time Out Value"
+ #language fr-FR "Set Time Out Value"
+#string STR_FORM_TIME_OUT_HELP #language en-US "Modify automatic boot time-out value"
+ #language fr-FR "Modify automatic boot time-out value"
+#string STR_FORM_MEMORY_CHECK_TITLE #language en-US "Set Memory Check Type"
+ #language fr-FR "Set Memory Check Type"
+#string STR_FORM_MEMORY_CHECK_HELP #language en-US "Modify the type of memory checking"
+ #language fr-FR "Modify the type of memory checking"
+#string STR_FORM_UEFI_OPTIMIZED_BOOT_TITLE #language en-US "UEFI Optimized Boot"
+ #language fr-FR "UEFI Optimized Boot"
+#string STR_FORM_UEFI_OPTIMIZED_BOOT_HELP #language en-US "Modify the UEFI Optimized Boot setting"
+ #language fr-FR "Modify the UEFI Optimized Boot setting"
+#string UEFI_OPTIMIZED_BOOT_DESCRIPTION #language en-US "UEFI Optimized Boot"
+ #language fr-FR "UEFI Optimized Boot"
+#string UEFI_OPTIMIZED_BOOT_HELP #language en-US "Check to enable UEFI Optimized Boot"
+ #language fr-FR "Check to enable UEFI Optimized Boot"
+#string STR_FORM_CON_MAIN_TITLE #language en-US "Console Options"
+ #language fr-FR "Console Options"
+#string STR_FORM_CON_MAIN_HELP #language en-US "Modify system console options"
+ #language fr-FR "Modify system console options"
+#string STR_FORM_CON_IN_TITLE #language en-US "Console Input Device Select"
+ #language fr-FR "Console Input Device Select"
+#string STR_FORM_CON_IN_HELP #language en-US "Enable console device as ConIn"
+ #language fr-FR "Enable console device as ConIn"
+#string STR_FORM_SET_FD_ORDER_TITLE #language en-US "Set Legacy Floppy Drive Order"
+ #language fr-FR "Set Legacy Floppy Drive Order"
+#string STR_FORM_SET_HD_ORDER_TITLE #language en-US "Set Legacy HardDisk Drive Order"
+ #language fr-FR "Set Legacy HardDisk Drive Order"
+#string STR_FORM_SET_CD_ORDER_TITLE #language en-US "Set Legacy CD-ROM Drive Order"
+ #language fr-FR "Set Legacy CD-ROM Drive Order"
+#string STR_FORM_SET_NET_ORDER_TITLE #language en-US "Set Legacy NET Drive Order"
+ #language fr-FR "Set Legacy NET Drive Order"
+#string STR_FORM_SET_BEV_ORDER_TITLE #language en-US "Set Legacy BEV Drive Order"
+ #language fr-FR "Set Legacy BEV Drive Order"
+#string STR_FORM_GOTO_SETTING #language en-US "Go Back To Setting Page"
+ #language fr-FR "Go Back To Setting Page"
+#string STR_COM1 #language en-US "COM1"
+ #language fr-FR "COM1"
+#string STR_COM2 #language en-US "COM2"
+ #language fr-FR "COM2"
+#string STR_COM_AS_CONSOLE_OPTION #language en-US "Select this COM port as Console"
+ #language fr-FR "Select this COM port as Console"
+#string STR_FORM_CON_OUT_TITLE #language en-US "Console Output Device Select"
+ #language fr-FR "Console Output Device Select"
+#string STR_FORM_CON_OUT_HELP #language en-US "Enable console device as ConOut"
+ #language fr-FR "Enable console device as ConOut"
+#string STR_FORM_STD_ERR_TITLE #language en-US "Console Standard Error Device Select"
+ #language fr-FR "Console Standard Error Device Select"
+#string STR_FORM_STD_ERR_HELP #language en-US "Enable console device as StdErr"
+ #language fr-FR "Enable console device as StdErr"
+#string STR_FORM_MODE_TITLE #language en-US "Console Output Mode Select"
+ #language fr-FR "Console Output Mode Select"
+#string STR_FORM_MODE_HELP #language en-US "Select Console Output Mode: 80x25, 100x31, etc."
+ #language fr-FR "Select Console Output Mode: 80x25, 100x31, etc."
+#string STR_FORM_COM_TITLE #language en-US "COM Attribute Setup Page"
+ #language fr-FR "COM Attribute Setup Page"
+#string STR_FORM_COM_HELP #language en-US "Setup ComPort BaudRate, DataBits, StopBits, Parity and TerminalType"
+ #language fr-FR "Setup ComPort BaudRate, DataBits, StopBits, Parity and TerminalType"
+#string STR_FORM_DRV_ADD_FILE_TITLE #language en-US "Add Driver Option Using File"
+ #language fr-FR "Add Driver Option Using File"
+#string STR_FORM_DRV_ADD_HANDLE_TITLE #language en-US "Add Driver Option Using Handle"
+ #language fr-FR "Add Driver Option Using Handle"
+#string STR_FORM_BOOT_ADD_DESC_TITLE #language en-US "Modify Boot Option Description"
+ #language fr-FR "Modify Boot Option Description"
+#string STR_FORM_DRV_ADD_DESC_TITLE #language en-US "Modify Driver Option Description"
+ #language fr-FR "Modify Driver Option Description"
+#string STR_NUM_AUTO_BOOT #language en-US "Auto Boot Time-out"
+ #language fr-FR "Auto Boot Time-out"
+#string STR_HLP_AUTO_BOOT #language en-US "Range: 0 to 65535 seconds, 0 means no wait, 65535 means waiting for key"
+ #language fr-FR "Range: 0 to 65535 seconds, 0 means no wait, 65535 means waiting for key"
+#string STR_BOOT_NEXT #language en-US "Boot Next Value"
+ #language fr-FR "Boot Next Value"
+#string STR_BOOT_NEXT_HELP #language en-US "Next boot use this boot option"
+ #language fr-FR "Next boot use this boot option"
+#string STR_LOAD_OPTION_DEVPATH #language en-US "This is the devicepath"
+ #language fr-FR "This is the devicepath"
+#string STR_LOAD_OPTION_DESC #language en-US "Input the description"
+ #language fr-FR "Input the description"
+#string STR_LOAD_OPTION_ACTIVE #language en-US "Load Option Active"
+ #language fr-FR "Load Option Active"
+#string STR_LOAD_OPTION_FORCE_RECON #language en-US "Load Option Reconnect"
+ #language fr-FR "Load Option Reconnect"
+#string STR_SAVE_AND_EXIT #language en-US "Commit Changes and Exit"
+ #language fr-FR "Commit Changes and Exit"
+#string STR_NO_SAVE_AND_EXIT #language en-US "Discard Changes and Exit"
+ #language fr-FR "Discard Changes and Exit"
+#string STR_CON_IN_SETUP #language en-US "Set Console Input Device"
+ #language fr-FR "Set Console Input Device"
+#string STR_CON_OUT_SETUP #language en-US "Set Console Output Device"
+ #language fr-FR "Set Console Output Device"
+#string STR_CON_ERR_SETUP #language en-US "Set Error Output Device"
+ #language fr-FR "Set Error Output Device"
+#string STR_CON_MODE_SETUP #language en-US "Set Console Output Mode"
+ #language fr-FR "Set Console Output Mode"
+#string STR_CON_COM_SETUP #language en-US "Set COM Attributes"
+ #language fr-FR "Set COM Attributes"
+#string STR_COM_TERMI_TYPE #language en-US "Set COM Terminal Type"
+ #language fr-FR "Set COM Terminal Type"
+#string STR_COM_FLOW_CONTROL #language en-US "Set COM Flow Control"
+ #language fr-FR "Set COM Flow Control"
+#string STR_COM_BAUD_RATE #language en-US "Set COM Baud Rate"
+ #language fr-FR "Set COM Baud Rate"
+#string STR_COM_DATA_BITS #language en-US "Set COM Data Bits"
+ #language fr-FR "Set COM Data Bits"
+#string STR_COM_PARITY #language en-US "Set COM Parity"
+ #language fr-FR "Set COM Parity"
+#string STR_COM_STOP_BITS #language en-US "Set COM Stop Bits"
+ #language fr-FR "Set COM Stop Bits"
+#string STR_COM_BAUD_RATE_0 #language en-US "115200"
+ #language fr-FR "115200"
+#string STR_COM_BAUD_RATE_1 #language en-US "57600"
+ #language fr-FR "57600"
+#string STR_COM_BAUD_RATE_2 #language en-US "38400"
+ #language fr-FR "38400"
+#string STR_COM_BAUD_RATE_3 #language en-US "19200"
+ #language fr-FR "19200"
+#string STR_COM_BAUD_RATE_4 #language en-US "9600"
+ #language fr-FR "9600"
+#string STR_COM_BAUD_RATE_5 #language en-US "7200"
+ #language fr-FR "7200"
+#string STR_COM_BAUD_RATE_6 #language en-US "4800"
+ #language fr-FR "4800"
+#string STR_COM_BAUD_RATE_7 #language en-US "3600"
+ #language fr-FR "3600"
+#string STR_COM_BAUD_RATE_8 #language en-US "2400"
+ #language fr-FR "2400"
+#string STR_COM_BAUD_RATE_9 #language en-US "2000"
+ #language fr-FR "2000"
+#string STR_COM_BAUD_RATE_10 #language en-US "1800"
+ #language fr-FR "1800"
+#string STR_COM_BAUD_RATE_11 #language en-US "1200"
+ #language fr-FR "1200"
+#string STR_COM_BAUD_RATE_12 #language en-US "600"
+ #language fr-FR "600"
+#string STR_COM_BAUD_RATE_13 #language en-US "300"
+ #language fr-FR "300"
+#string STR_COM_BAUD_RATE_14 #language en-US "150"
+ #language fr-FR "150"
+#string STR_COM_BAUD_RATE_15 #language en-US "134"
+ #language fr-FR "134"
+#string STR_COM_BAUD_RATE_16 #language en-US "110"
+ #language fr-FR "110"
+#string STR_COM_BAUD_RATE_17 #language en-US "75"
+ #language fr-FR "75"
+#string STR_COM_BAUD_RATE_18 #language en-US "50"
+ #language fr-FR "50"
+#string STR_COM_DATA_BITS_0 #language en-US "5"
+ #language fr-FR "5"
+#string STR_COM_DATA_BITS_1 #language en-US "6"
+ #language fr-FR "6"
+#string STR_COM_DATA_BITS_2 #language en-US "7"
+ #language fr-FR "7"
+#string STR_COM_DATA_BITS_3 #language en-US "8"
+ #language fr-FR "8"
+#string STR_COM_PAR_0 #language en-US "None"
+ #language fr-FR "None"
+#string STR_COM_PAR_1 #language en-US "Even"
+ #language fr-FR "Even"
+#string STR_COM_PAR_2 #language en-US "Odd"
+ #language fr-FR "Odd"
+#string STR_COM_PAR_3 #language en-US "Mark"
+ #language fr-FR "Mark"
+#string STR_COM_PAR_4 #language en-US "Space"
+ #language fr-FR "Space"
+#string STR_COM_STOP_BITS_0 #language en-US "One"
+ #language fr-FR "One"
+#string STR_COM_STOP_BITS_1 #language en-US "One And A Half"
+ #language fr-FR "One And A Half"
+#string STR_COM_STOP_BITS_2 #language en-US "Two"
+ #language fr-FR "Two"
+#string STR_COM_TYPE_0 #language en-US "PC_ANSI"
+ #language fr-FR "PC_ANSI"
+#string STR_COM_TYPE_1 #language en-US "VT_100"
+ #language fr-FR "VT_100"
+#string STR_COM_TYPE_2 #language en-US "VT_100_PLUS"
+ #language fr-FR "VT_100_PLUS"
+#string STR_COM_TYPE_3 #language en-US "VT_UTF8"
+ #language fr-FR "VT_UTF8"
+#string STR_COM_TYPE_4 #language en-US "TTY_TERM"
+ #language fr-FR "TTY_TERM"
+#string STR_COM_TYPE_5 #language en-US "LINUX"
+ #language fr-FR "LINUX"
+#string STR_COM_TYPE_6 #language en-US "XTERM_R6"
+ #language fr-FR "XTERM_R6"
+#string STR_COM_TYPE_7 #language en-US "VT_400"
+ #language fr-FR "VT_400"
+#string STR_COM_TYPE_8 #language en-US "SCO"
+ #language fr-FR "SCO"
+#string STR_RESET #language en-US "Reset System"
+ #language fr-FR "Reset System"
+#string STR_FORM_GOTO_MAIN #language en-US "Go Back To Main Page"
+ #language fr-FR "Go Back To Main Page"
+#string STR_BOOT_FROM_FILE #language en-US "Boot From File"
+ #language fr-FR "Boot From File"
+#string STR_BOOT_FROM_FILE_HELP #language en-US "Boot system from a file or device"
+ #language fr-FR "Boot system from a file or device"
+#string STR_OPTIONAL_DATA #language en-US "Input Optional Data"
+ #language fr-FR "Input Optional Data"
+#string STR_CHANGE_ORDER #language en-US "Change the order"
+ #language fr-FR "Change the order"
+#string STR_BOOT_LEGACY #language en-US "Boot Legacy System"
+ #language fr-FR "Boot Legacy System"
+#string STR_BOOT_LEGACY_HELP #language en-US "Supports boot from legacy FD, HD, CD, PCMCIA, USB, and Network"
+ #language fr-FR "Supports boot from legacy FD, HD, CD, PCMCIA, USB, and Network"
+#string STR_BOOT_LEGACY_FLOPPY #language en-US "Boot From Floppy"
+ #language fr-FR "Boot From Floppy"
+#string STR_BOOT_LEGACY_HARDDRIVE #language en-US "Boot From Hard Drive"
+ #language fr-FR "Boot From Hard Drive"
+#string STR_BOOT_LEGACY_CDROM #language en-US "Boot From CD Rom"
+ #language fr-FR "Boot From CD Rom"
+#string STR_BOOT_LEGACY_PCMCIA #language en-US "Boot From PCMCIA"
+ #language fr-FR "Boot From PCMCIA"
+#string STR_BOOT_LEGACY_USB #language en-US "Boot From USB Device"
+ #language fr-FR "Boot From USB Device"
+#string STR_BOOT_LEGACY_NETWORK #language en-US "Boot From Network"
+ #language fr-FR "Boot From Network"
+#string STR_DISABLE_LEGACY_DEVICE #language en-US "Disabled"
+ #language fr-FR "Disabled"
+#string STR_FILE_EXPLORER_TITLE #language en-US "File Explorer"
+ #language fr-FR "File Explorer"
+#string STR_OUT_OF_BAND_PORT #language fr-FR "Out-Of-Band Mgmt Port"
+ #language en-US "Out-Of-Band Mgmt Port"
+#string STR_HARDWARE_FLOW_CONTROL #language fr-FR "Hardware"
+ #language en-US "Hardware"
+#string STR_NONE_FLOW_CONTROL #language fr-FR "None"
+ #language en-US "None"
+//
+// BugBug : need someone to translate these strings to french
+//
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
new file mode 100644
index 000000000..a056dc3e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
@@ -0,0 +1,99 @@
+## @file
+# Boot Maintenance Manager Library used by UiApp.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootMaintenanceManagerUiLib
+ MODULE_UNI_FILE = BootMaintenanceManagerUiLib.uni
+ FILE_GUID = CA9E4824-4198-4715-AA22-E2935E703A07
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = BootMaintenanceManagerUiLibConstructor
+ DESTRUCTOR = BootMaintenanceManagerUiLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootMaintenanceManager.h
+ BootMaintenanceManager.vfr
+ BootMaintenanceManagerStrings.uni
+ BootMaintenance.c
+ FormGuid.h
+ BootOption.c
+ ConsoleOption.c
+ Data.c
+ Variable.c
+ UpdatePage.c
+ BmLib.c
+ BootMaintenanceManagerCustomizedUi.c
+ BootMaintenanceManagerCustomizedUi.h
+ BootMaintenanceManagerCustomizedUiSupport.c
+ BootMaintenanceManagerCustomizedUiSupport.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiHiiServicesLib
+ UefiBootManagerLib
+ FileExplorerLib
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"BootNext" (The number of next boot option)
+ ## SOMETIMES_PRODUCES ## Variable:L"BootXX" (Boot option variable)
+ ## 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"KeyXX" (Hotkey option variable)
+ ## PRODUCES ## Variable:L"HwErrRecSupport" (The level of platform supported hardware Error Record Persistence)
+ ## 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 (not PcdUefiVariableDefaultLangDeprecate)## Variable:L"LangCodes" (Value of PcdUefiVariableDefaultLangCodes)
+ ## PRODUCES ## Variable:L"PlatformLangCodes" (Value of PcdUefiVariableDefaultPlatformLangCodes)
+ ## PRODUCES ## Variable:L"Timeout" (The time out value in second of showing progress bar)
+ ## 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_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## GUID (Extended IFR Guid Opcode)
+ gEfiIfrFrontPageGuid ## CONSUMES ## GUID
+ gEfiIfrBootMaintenanceGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## CONSUMES
+ gEfiLoadFileProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## CONSUMES
+ gEfiSerialIoProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES
+ gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.uni b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.uni
new file mode 100644
index 000000000..47a0ab5bc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Boot Maintenance Manager Library used by UiApp.
+//
+// Boot Maintenance Manager Library used by UiApp.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Boot Maintenance Manager Library used by UiApp."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Boot Maintenance Manager Library used by UiApp."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
new file mode 100644
index 000000000..53f0ef3d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
@@ -0,0 +1,1005 @@
+/** @file
+ Provide boot option support for Application "BootMaint"
+
+ Include file system navigation, system handle selection
+
+ Boot option manipulation
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+///
+/// Define the maximum characters that will be accepted.
+///
+#define MAX_CHAR 480
+
+/**
+
+ Check whether a reset is needed, if reset is needed, Popup a menu to notice user.
+
+**/
+VOID
+BmmSetupResetReminder (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *StringBuffer1;
+ CHAR16 *StringBuffer2;
+ EFI_STATUS Status;
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
+
+ //
+ // Use BrowserEx2 protocol to check whether reset is required.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);
+
+ //
+ //check any reset required change is applied? if yes, reset system
+ //
+ if (!EFI_ERROR(Status) && FormBrowserEx2->IsResetRequired()) {
+ StringBuffer1 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
+ ASSERT (StringBuffer1 != NULL);
+ StringBuffer2 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
+ ASSERT (StringBuffer2 != NULL);
+ StrCpyS (StringBuffer1, MAX_CHAR, L"Configuration changed. Reset to apply it Now.");
+ StrCpyS (StringBuffer2, MAX_CHAR, 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);
+ }
+}
+
+/**
+ 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;
+
+ 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;
+
+ //
+ // 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);
+ 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;
+
+ 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;
+}
+
+/**
+ 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;
+}
+
+/**
+
+ 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;
+ 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;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+
+ MenuCount = 0;
+ BootOrderListSize = 0;
+ BootNextSize = 0;
+ BootOrderList = NULL;
+ BootNext = NULL;
+ LoadOptionFromVar = NULL;
+ BOpt_FreeMenu (&BootOptionMenu);
+ InitializeListHead (&BootOptionMenu.Head);
+
+ //
+ // Get the BootOrder from the Var
+ //
+ GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);
+ if (BootOrderList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the BootNext from the Var
+ //
+ GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);
+ if (BootNext != NULL) {
+ if (BootNextSize != sizeof (UINT16)) {
+ FreePool (BootNext);
+ BootNext = NULL;
+ }
+ }
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ //
+ // Don't display the hidden/inactive boot option
+ //
+ if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
+ continue;
+ }
+
+ UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
+ //
+ // Get all loadoptions from the VAR
+ //
+ GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);
+ if (LoadOptionFromVar == NULL) {
+ continue;
+ }
+
+ if (BootNext != NULL) {
+ BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
+ } else {
+ BootNextFlag = FALSE;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ ASSERT (NULL != NewMenuEntry);
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ LoadOptionPtr = LoadOptionFromVar;
+ LoadOptionEnd = LoadOptionFromVar + BootOptionSize;
+
+ NewMenuEntry->OptionNumber = BootOrderList[Index];
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->IsBootNext = BootNextFlag;
+
+ //
+ // Is a Legacy Device?
+ //
+ Ptr = (UINT8 *) LoadOptionFromVar;
+
+ //
+ // 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->Attributes = *(UINT32 *) LoadOptionPtr;
+
+ LoadOptionPtr += sizeof (UINT32);
+
+ NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
+ LoadOptionPtr += sizeof (UINT16);
+
+ StringSize = StrSize((UINT16*)LoadOptionPtr);
+
+ NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));
+ ASSERT (NewLoadContext->Description != NULL);
+ StrCpyS (NewLoadContext->Description, StrSize((UINT16*)LoadOptionPtr) / sizeof (UINT16), (UINT16*)LoadOptionPtr);
+
+ ASSERT (NewLoadContext->Description != NULL);
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ 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
+ );
+ }
+
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ MenuCount++;
+ FreePool (LoadOptionFromVar);
+ }
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+ if (BootNext != NULL) {
+ FreePool (BootNext);
+ }
+ if (BootOrderList != NULL) {
+ FreePool (BootOrderList);
+ }
+
+ BootOptionMenu.MenuNumber = MenuCount;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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 = UiDevicePathToStr (NewHandleContext->DevicePath);
+ NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle,0,NewMenuEntry->DisplayString,NULL);
+ NewMenuEntry->HelpString = NULL;
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ 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);
+
+ GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &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));
+ GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &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;
+ 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
+ //
+ GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &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
+ //
+ GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);
+ if (LoadOptionFromVar == NULL) {
+ continue;
+ }
+
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ LoadOptionPtr = LoadOptionFromVar;
+ LoadOptionEnd = LoadOptionFromVar + DriverOptionSize;
+ NewMenuEntry->OptionNumber = DriverOrderList[Index];
+ 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->Attributes = *(UINT32 *) LoadOptionPtr;
+
+ 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;
+ NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ 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
+ );
+
+ }
+
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+ FreePool (LoadOptionFromVar);
+
+ }
+
+ 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);
+ }
+}
+
+/**
+ 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);
+ }
+}
+
+/**
+ Boot the file specified by the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+BootFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+ CHAR16 *FileName;
+
+ FileName = NULL;
+
+ FileName = ExtractFileNameFromDevicePath(FilePath);
+ if (FileName != NULL) {
+ EfiBootManagerInitializeLoadOption (
+ &BootOption,
+ 0,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ FileName,
+ FilePath,
+ NULL,
+ 0
+ );
+ //
+ // Since current no boot from removable media directly is allowed */
+ //
+ gST->ConOut->ClearScreen (gST->ConOut);
+ //
+ // Check whether need to reset system.
+ //
+ BmmSetupResetReminder ();
+
+ BmmSetConsoleMode (FALSE);
+ EfiBootManagerBoot (&BootOption);
+ BmmSetConsoleMode (TRUE);
+
+ FreePool(FileName);
+
+ EfiBootManagerFreeLoadOption (&BootOption);
+ }
+
+ return FALSE;
+}
+
+/**
+ Display the form base on the selected file.
+
+ @param FilePath Point to the file path.
+ @param FormId The form need to display.
+
+**/
+BOOLEAN
+ReSendForm(
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_FORM_ID FormId
+ )
+{
+ gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;
+
+ UpdateOptionPage(&gBootMaintenancePrivate, FormId, FilePath);
+
+ gBootMaintenancePrivate.FormBrowser2->SendForm (
+ gBootMaintenancePrivate.FormBrowser2,
+ &gBootMaintenancePrivate.BmmHiiHandle,
+ 1,
+ &mBootMaintGuid,
+ FormId,
+ NULL,
+ NULL
+ );
+ return TRUE;
+}
+
+/**
+ Create boot option base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+CreateBootOptionFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return ReSendForm(FilePath, FORM_BOOT_ADD_ID);
+}
+
+/**
+ Create driver option base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+
+**/
+BOOLEAN
+EFIAPI
+CreateDriverOptionFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return ReSendForm(FilePath, FORM_DRV_ADD_FILE_ID);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/ConsoleOption.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/ConsoleOption.c
new file mode 100644
index 000000000..5d1c6d34e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/ConsoleOption.c
@@ -0,0 +1,1166 @@
+/** @file
+handles console redirection from boot manager
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+/**
+ 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
+MatchDevicePaths (
+ 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;
+}
+
+/**
+ 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;
+
+ 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)
+ );
+ //
+ // 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;
+
+ //
+ // 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 = UiDevicePathToStr (DevicePath);
+ }
+
+ NewMenuEntry->HelpString = NULL;
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+
+ 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)
+ );
+ InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);
+ TerminalMenu.MenuNumber++;
+ }
+ }
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ //
+ // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
+ //
+ GetEfiGlobalVariable2 (L"ConOut", (VOID**)&OutDevicePath, NULL);
+ GetEfiGlobalVariable2 (L"ConIn", (VOID**)&InpDevicePath, NULL);
+ GetEfiGlobalVariable2 (L"ErrOut", (VOID**)&ErrDevicePath, NULL);
+ 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 < (ARRAY_SIZE (TerminalTypeGuid)); 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 = UiDevicePathToStr (NewDevicePath);
+ // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
+ //
+ NewMenuEntry->HelpString = NULL;
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+
+ if (MatchDevicePaths (OutDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConOut = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (MatchDevicePaths (InpDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConIn = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (MatchDevicePaths (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;
+
+ 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)
+ );
+
+ 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)
+ );
+
+ 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;
+ GetEfiGlobalVariable2 (L"ConIn", (VOID**)&DevicePath, NULL);
+ GetEfiGlobalVariable2 (L"ConInDev", (VOID**)&AllDevicePath, NULL);
+ break;
+
+ case BM_CONSOLE_OUT_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleOutMenu;
+ GetEfiGlobalVariable2 (L"ConOut", (VOID**)&DevicePath, NULL);
+ GetEfiGlobalVariable2 (L"ConOutDev", (VOID**)&AllDevicePath, NULL);
+ break;
+
+ case BM_CONSOLE_ERR_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleErrMenu;
+ GetEfiGlobalVariable2 (L"ErrOut", (VOID**)&DevicePath, NULL);
+ GetEfiGlobalVariable2 (L"ErrOutDev", (VOID**)&AllDevicePath, NULL);
+ 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 = UiDevicePathToStr (NewConsoleContext->DevicePath);
+ }
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ if (NULL == NewMenuEntry->HelpString) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ NewMenuEntry->HelpStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
+ }
+
+ NewConsoleContext->IsTerminal = IsTerminalDevicePath (
+ NewConsoleContext->DevicePath,
+ &Terminal,
+ &Com
+ );
+
+ NewConsoleContext->IsActive = MatchDevicePaths (
+ 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;
+ UINTN Index;
+
+ 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 9 kinds of Terminal types
+ // check to see whether this devicepath
+ // is one of that type
+ //
+ for (Index = 0; Index < ARRAY_SIZE (TerminalTypeGuid); Index++) {
+ if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[Index])) {
+ *Termi = Index;
+ IsTerminal = TRUE;
+ break;
+ }
+ }
+
+ if (Index == ARRAY_SIZE (TerminalTypeGuid)) {
+ 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;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+
+ 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;
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleInpMenu.MenuNumber < MAX_MENU_NUMBER);
+ ConInCheck[Index + ConsoleInpMenu.MenuNumber] = NewTerminalContext->IsConIn;
+ }
+}
+
+/**
+
+ 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;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+
+ 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;
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleOutMenu.MenuNumber < MAX_MENU_NUMBER);
+ ConOutCheck[Index + ConsoleOutMenu.MenuNumber] = NewTerminalContext->IsConOut;
+ }
+}
+
+/**
+
+ 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;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+
+ 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;
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index + ConsoleErrMenu.MenuNumber < MAX_MENU_NUMBER);
+ ConErrCheck[Index + ConsoleErrMenu.MenuNumber] = NewTerminalContext->IsStdErr;
+ }
+}
+
+/**
+
+ 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 < ARRAY_SIZE (DataBitsList); AttributeIndex++) {
+ if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) {
+ NewTerminalContext->DataBitsIndex = AttributeIndex;
+ break;
+ }
+ }
+
+ for (AttributeIndex = 0; AttributeIndex < ARRAY_SIZE (ParityList); AttributeIndex++) {
+ if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) {
+ NewTerminalContext->ParityIndex = AttributeIndex;
+ break;
+ }
+ }
+
+ for (AttributeIndex = 0; AttributeIndex < ARRAY_SIZE (StopBitsList); 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/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Data.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Data.c
new file mode 100644
index 000000000..21c4ef3d5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Data.c
@@ -0,0 +1,265 @@
+/** @file
+Define some data used for Boot Maint
+
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+VOID *mStartOpCodeHandle = NULL;
+VOID *mEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mEndLabel = NULL;
+
+///
+/// Terminal type string token storage
+///
+UINT16 TerminalType[9] = {
+ STRING_TOKEN(STR_COM_TYPE_0),
+ STRING_TOKEN(STR_COM_TYPE_1),
+ STRING_TOKEN(STR_COM_TYPE_2),
+ STRING_TOKEN(STR_COM_TYPE_3),
+ STRING_TOKEN(STR_COM_TYPE_4),
+ STRING_TOKEN(STR_COM_TYPE_5),
+ STRING_TOKEN(STR_COM_TYPE_6),
+ STRING_TOKEN(STR_COM_TYPE_7),
+ STRING_TOKEN(STR_COM_TYPE_8),
+};
+
+///
+/// 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
+};
+
+///
+/// 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
+};
+
+///
+/// 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[9] = {
+ DEVICE_PATH_MESSAGING_PC_ANSI,
+ DEVICE_PATH_MESSAGING_VT_100,
+ DEVICE_PATH_MESSAGING_VT_100_PLUS,
+ DEVICE_PATH_MESSAGING_VT_UTF8,
+ EFI_TTY_TERM_GUID,
+ EDKII_LINUX_TERM_GUID,
+ EDKII_XTERM_R6_GUID,
+ EDKII_VT400_GUID,
+ EDKII_SCO_TERM_GUID
+};
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/FormGuid.h b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/FormGuid.h
new file mode 100644
index 000000000..303124292
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/FormGuid.h
@@ -0,0 +1,206 @@
+/** @file
+Formset guids, form id and VarStore data structure for Boot Maintenance Manager.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _FORM_GUID_H_
+#define _FORM_GUID_H_
+
+#define BOOT_MAINT_FORMSET_GUID \
+ { \
+ 0x642237c7, 0x35d4, 0x472d, {0x83, 0x65, 0x12, 0xe0, 0xcc, 0xf2, 0x7a, 0x22} \
+ }
+
+#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_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_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 0x1024
+
+
+#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 FORM_RESET 0x110E
+#define KEY_VALUE_BOOT_DESCRIPTION 0x110F
+#define KEY_VALUE_BOOT_OPTION 0x1110
+#define KEY_VALUE_DRIVER_DESCRIPTION 0x1111
+#define KEY_VALUE_DRIVER_OPTION 0x1112
+#define KEY_VALUE_SAVE_AND_EXIT_BOOT 0x1113
+#define KEY_VALUE_NO_SAVE_AND_EXIT_BOOT 0x1114
+#define KEY_VALUE_SAVE_AND_EXIT_DRIVER 0x1115
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER 0x1116
+#define KEY_VALUE_TRIGGER_FORM_OPEN_ACTION 0x1117
+
+#define MAXIMUM_NORMAL_KEY_VALUE 0x11FF
+
+//
+// Varstore ID defined for Buffer Storage
+//
+#define VARSTORE_ID_BOOT_MAINT 0x1000
+
+//
+// End Label
+//
+#define LABEL_FORM_MAIN_START 0xfffc
+#define LABEL_FORM_MAIN_END 0xfffd
+
+#define LABEL_BMM_PLATFORM_INFORMATION 0xfffe
+#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;
+ UINT32 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 or 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 BootOptionOrder[MAX_MENU_NUMBER];
+ UINT32 DriverOptionOrder[MAX_MENU_NUMBER];
+ //
+ // Boot or Driver Option Delete storage
+ //
+ BOOLEAN BootOptionDel[MAX_MENU_NUMBER];
+ BOOLEAN DriverOptionDel[MAX_MENU_NUMBER];
+ BOOLEAN BootOptionDelMark[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];
+
+ //
+ // 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];
+ //
+
+ UINT16 BootDescriptionData[MAX_MENU_NUMBER];
+ UINT16 BootOptionalData[127];
+ UINT16 DriverDescriptionData[MAX_MENU_NUMBER];
+ UINT16 DriverOptionalData[127];
+ BOOLEAN BootOptionChanged;
+ BOOLEAN DriverOptionChanged;
+ UINT8 Active;
+ UINT8 ForceReconnect;
+} BMM_FAKE_NV_DATA;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/UpdatePage.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/UpdatePage.c
new file mode 100644
index 000000000..e2b444cc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/UpdatePage.c
@@ -0,0 +1,1150 @@
+/** @file
+Dynamically update the pages.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+/**
+ Create the global UpdateData structure.
+
+**/
+VOID
+CreateUpdateData (
+ VOID
+ )
+{
+ //
+ // Init OpCode Handle and Allocate space for creation of Buffer
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (mStartOpCodeHandle != NULL);
+
+ mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (mEndOpCodeHandle != NULL);
+
+ //
+ // 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;
+}
+
+/**
+ 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,
+ &mBootMaintGuid,
+ 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,
+ &mBootMaintGuid,
+ LabelId,
+ mStartOpCodeHandle, // Label LabelId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ 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 = TRUE;
+
+ 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 list 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);
+
+ 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;
+ CallbackData->BmmOldFakeNVData.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);
+
+ 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;
+ CallbackData->BmmOldFakeNVData.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;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ UINT16 Index;
+ UINT16 Index2;
+ UINT8 CheckFlags;
+ UINT8 *ConsoleCheck;
+ EFI_QUESTION_ID QuestionIdBase;
+ UINT16 VariableOffsetBase;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ 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;
+ NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewConsoleContext->IsActive) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ ConsoleCheck[Index] = TRUE;
+ } else {
+ ConsoleCheck[Index] = FALSE;
+ }
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (QuestionIdBase + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (VariableOffsetBase + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ CheckFlags,
+ NULL
+ );
+ }
+
+ for (Index2 = 0; ((Index2 < TerminalMenu.MenuNumber) && \
+ (Index2 < MAX_MENU_NUMBER)); Index2++) {
+ CheckFlags = 0;
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index2);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ ASSERT (Index < MAX_MENU_NUMBER);
+ 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))
+ ) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ ConsoleCheck[Index] = TRUE;
+ } else {
+ ConsoleCheck[Index] = FALSE;
+ }
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (QuestionIdBase + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (VariableOffsetBase + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ CheckFlags,
+ NULL
+ );
+
+ Index++;
+ }
+
+ 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;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+ UpdatePageStart (CallbackData);
+
+ OptionOrder = NULL;
+ QuestionId = 0;
+ VarOffset = 0;
+ switch (UpdatePageId) {
+
+ case FORM_BOOT_CHG_ID:
+ //
+ // If the BootOptionOrder in the BmmFakeNvData are same with the date in the BmmOldFakeNVData,
+ // means all Boot Options has been save in BootOptionMenu, we can get the date from the menu.
+ // else means browser maintains some uncommitted date which are not saved in BootOptionMenu,
+ // so we should not get the data from BootOptionMenu to show it.
+ //
+ if (CompareMem (CallbackData->BmmFakeNvData.BootOptionOrder, CallbackData->BmmOldFakeNVData.BootOptionOrder, sizeof (CallbackData->BmmFakeNvData.BootOptionOrder)) == 0) {
+ GetBootOrder (CallbackData);
+ }
+ OptionOrder = CallbackData->BmmFakeNvData.BootOptionOrder;
+ QuestionId = BOOT_OPTION_ORDER_QUESTION_ID;
+ VarOffset = BOOT_OPTION_ORDER_VAR_OFFSET;
+ break;
+
+ case FORM_DRV_CHG_ID:
+ //
+ // If the DriverOptionOrder in the BmmFakeNvData are same with the date in the BmmOldFakeNVData,
+ // means all Driver Options has been save in DriverOptionMenu, we can get the DriverOptionOrder from the menu.
+ // else means browser maintains some uncommitted date which are not saved in DriverOptionMenu,
+ // so we should not get the data from DriverOptionMenu to show it.
+ //
+ if (CompareMem (CallbackData->BmmFakeNvData.DriverOptionOrder, CallbackData->BmmOldFakeNVData.DriverOptionOrder, sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder)) == 0) {
+ 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; (OptionOrder[OptionIndex] != 0 && OptionIndex < MAX_MENU_NUMBER); 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);
+
+}
+
+/**
+ 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
+ //
+ UnicodeValueToStringS (ModeString, sizeof (ModeString), 0, Col, 0);
+ PStr = &ModeString[0];
+ StrnCatS (PStr, ARRAY_SIZE (ModeString), L" x ", StrLen(L" x ") + 1);
+ PStr = PStr + StrLen (PStr);
+ UnicodeValueToStringS (
+ PStr,
+ sizeof (ModeString) - ((UINTN)PStr - (UINTN)&ModeString[0]),
+ 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;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < ARRAY_SIZE (DataBitsList); 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < ARRAY_SIZE (ParityList); 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < ARRAY_SIZE (StopBitsList); 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < ARRAY_SIZE (TerminalType); 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < ARRAY_SIZE (mFlowControlType); 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),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+Update add boot/driver option page.
+
+@param CallbackData The BMM context data.
+@param FormId The form ID to be updated.
+@param DevicePath Device path.
+
+**/
+VOID
+UpdateOptionPage(
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_FORM_ID FormId,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *String;
+ EFI_STRING_ID StringToken;
+
+ String = NULL;
+
+ if (DevicePath != NULL){
+ String = ExtractFileNameFromDevicePath(DevicePath);
+ }
+ if (String == NULL) {
+ String = HiiGetString (CallbackData->BmmHiiHandle, STRING_TOKEN (STR_NULL_STRING), NULL);
+ ASSERT (String != NULL);
+ }
+
+ StringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ if(FormId == FORM_BOOT_ADD_ID){
+ if (!CallbackData->BmmFakeNvData.BootOptionChanged) {
+ ZeroMem (CallbackData->BmmFakeNvData.BootOptionalData, sizeof (CallbackData->BmmFakeNvData.BootOptionalData));
+ ZeroMem (CallbackData->BmmFakeNvData.BootDescriptionData, sizeof (CallbackData->BmmFakeNvData.BootDescriptionData));
+ ZeroMem (CallbackData->BmmOldFakeNVData.BootOptionalData, sizeof (CallbackData->BmmOldFakeNVData.BootOptionalData));
+ ZeroMem (CallbackData->BmmOldFakeNVData.BootDescriptionData, sizeof (CallbackData->BmmOldFakeNVData.BootDescriptionData));
+ }
+ } else if (FormId == FORM_DRV_ADD_FILE_ID){
+ if (!CallbackData->BmmFakeNvData.DriverOptionChanged) {
+ ZeroMem (CallbackData->BmmFakeNvData.DriverOptionalData, sizeof (CallbackData->BmmFakeNvData.DriverOptionalData));
+ ZeroMem (CallbackData->BmmFakeNvData.DriverDescriptionData, sizeof (CallbackData->BmmFakeNvData.DriverDescriptionData));
+ ZeroMem (CallbackData->BmmOldFakeNVData.DriverOptionalData, sizeof (CallbackData->BmmOldFakeNVData.DriverOptionalData));
+ ZeroMem (CallbackData->BmmOldFakeNVData.DriverDescriptionData, sizeof (CallbackData->BmmOldFakeNVData.DriverDescriptionData));
+ }
+ }
+
+ RefreshUpdateData();
+ mStartLabel->Number = FormId;
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ StringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiUpdateForm (
+ CallbackData->BmmHiiHandle,
+ &mBootMaintGuid,
+ FormId,
+ mStartOpCodeHandle,// Label FormId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ 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;
+ }
+}
+
+/**
+ 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
+ )
+{
+ 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/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Variable.c b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Variable.c
new file mode 100644
index 000000000..e28f76b8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootMaintenanceManagerUiLib/Variable.c
@@ -0,0 +1,731 @@
+/** @file
+Variable operation that will be used by bootmaint
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootMaintenanceManager.h"
+
+/**
+ Delete Boot Option that represent a Deleted state in BootOptionMenu.
+
+ @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;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ 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;
+ }
+
+ Status = EfiBootManagerDeleteLoadOptionVariable (NewMenuEntry->OptionNumber,LoadOptionTypeBoot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ 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;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete Load Option that represent a Deleted state in DriverOptionMenu.
+
+ @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;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ 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;
+ }
+ Status = EfiBootManagerDeleteLoadOptionVariable (NewMenuEntry->OptionNumber,LoadOptionTypeDriver);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Index2++;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ NewMenuEntry = NULL;
+ }
+
+ DriverOptionMenu.MenuNumber -= Index2;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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;
+
+ GetEfiGlobalVariable2 (ConsoleName, (VOID**)&ConDevicePath, NULL);
+ 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 < (ARRAY_SIZE (TerminalTypeGuid)));
+ 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,
+ VAR_FLAG,
+ 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 other Contain some errors when excuting this function.See function
+ EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
+ for detail return information.
+ @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 DriverString[12];
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;
+ UINT8 *OptionalDesData;
+ UINT32 OptionalDataSize;
+
+ OptionalDataExist = FALSE;
+ OptionalDesData = NULL;
+ OptionalDataSize = 0;
+
+ Index = BOpt_GetDriverOptionNumber ();
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ Index
+ );
+
+ if (*DescriptionData == 0x0000) {
+ StrCpyS (DescriptionData, MAX_MENU_NUMBER, DriverString);
+ }
+
+ if (*OptionalData != 0x0000) {
+ OptionalDataExist = TRUE;
+ OptionalDesData = (UINT8 *)OptionalData;
+ OptionalDataSize = (UINT32)StrSize (OptionalData);
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &LoadOption,
+ Index,
+ LoadOptionTypeDriver,
+ LOAD_OPTION_ACTIVE | (ForceReconnect << 1),
+ DescriptionData,
+ CallbackData->LoadContext->FilePathList,
+ OptionalDesData,
+ OptionalDataSize
+ );
+ if (EFI_ERROR (Status)){
+ return Status;
+ }
+
+ Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
+ if (EFI_ERROR (Status)) {
+ EfiBootManagerFreeLoadOption(&LoadOption);
+ return Status;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->Attributes = LoadOption.Attributes;
+ NewLoadContext->FilePathListLength = (UINT16)GetDevicePathSize (LoadOption.FilePath);
+
+ NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ CopyMem (
+ NewLoadContext->Description,
+ LoadOption.Description,
+ StrSize (DescriptionData)
+ );
+
+ NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ LoadOption.FilePath,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+ NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ if (OptionalDataExist) {
+ NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOption.OptionalData,
+ LoadOption.OptionalDataSize
+ );
+ }
+
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+ DriverOptionMenu.MenuNumber++;
+
+ EfiBootManagerFreeLoadOption(&LoadOption);
+
+ 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.
+
+ @retval other Contain some errors when excuting this function. See function
+ EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
+ for detail return information.
+ @retval EFI_SUCCESS If function completes successfully.
+
+**/
+EFI_STATUS
+Var_UpdateBootOption (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 BootString[10];
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+ BMM_FAKE_NV_DATA *NvRamMap;
+ EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;
+ UINT8 *OptionalData;
+ UINT32 OptionalDataSize;
+
+ OptionalDataExist = FALSE;
+ NvRamMap = &CallbackData->BmmFakeNvData;
+ OptionalData = NULL;
+ OptionalDataSize = 0;
+
+ 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);
+ }
+
+ if (NvRamMap->BootOptionalData[0] != 0x0000) {
+ OptionalDataExist = TRUE;
+ OptionalData = (UINT8 *)NvRamMap->BootOptionalData;
+ OptionalDataSize = (UINT32)StrSize (NvRamMap->BootOptionalData);
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &LoadOption,
+ Index,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ NvRamMap->BootDescriptionData,
+ CallbackData->LoadContext->FilePathList,
+ OptionalData,
+ OptionalDataSize
+ );
+ if (EFI_ERROR (Status)){
+ return Status;
+ }
+
+ Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
+ if (EFI_ERROR (Status)) {
+ EfiBootManagerFreeLoadOption(&LoadOption);
+ return Status;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->Attributes = LoadOption.Attributes;
+ NewLoadContext->FilePathListLength = (UINT16) GetDevicePathSize (LoadOption.FilePath);
+
+ NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+
+ CopyMem (
+ NewLoadContext->Description,
+ LoadOption.Description,
+ StrSize (NvRamMap->BootDescriptionData)
+ );
+
+ NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ LoadOption.FilePath,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+ NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ if (OptionalDataExist) {
+ NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOption.OptionalData,
+ LoadOption.OptionalDataSize
+ );
+ }
+
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ BootOptionMenu.MenuNumber++;
+
+ EfiBootManagerFreeLoadOption(&LoadOption);
+
+ 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 == NONE_BOOTNEXT_VALUE) {
+ 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,
+ VAR_FLAG,
+ 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 *BootOrder;
+ UINTN BootOrderSize;
+ UINT16 OptionNumber;
+
+ //
+ // First check whether BootOrder is present in current configuration
+ //
+ GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
+ if (BootOrder == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
+
+ //
+ // OptionOrder is subset of BootOrder
+ //
+ for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
+ for (Index = OrderIndex; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if ((BootOrder[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
+ OptionNumber = BootOrder[Index];
+ CopyMem (&BootOrder[OrderIndex + 1], &BootOrder[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
+ BootOrder[OrderIndex] = OptionNumber;
+ }
+ }
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderSize,
+ BootOrder
+ );
+ FreePool (BootOrder);
+
+ 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
+ //
+ GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &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,
+ VAR_FLAG,
+ DriverOrderListSize,
+ NewDriverOrderList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_GetDriverOptions (CallbackData);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.c b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.c
new file mode 100644
index 000000000..4b2c4c77a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.c
@@ -0,0 +1,929 @@
+/** @file
+ The boot manager reference implementation
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BootManager.h"
+
+UINT16 mKeyInput;
+EFI_GUID mBootManagerGuid = BOOT_MANAGER_FORMSET_GUID;
+//
+// Boot video resolution and text mode.
+//
+UINT32 mBmBootHorizontalResolution = 0;
+UINT32 mBmBootVerticalResolution = 0;
+UINT32 mBmBootTextModeColumn = 0;
+UINT32 mBmBootTextModeRow = 0;
+//
+// BIOS setup video resolution and text mode.
+//
+UINT32 mBmSetupTextModeColumn = 0;
+UINT32 mBmSetupTextModeRow = 0;
+UINT32 mBmSetupHorizontalResolution = 0;
+UINT32 mBmSetupVerticalResolution = 0;
+
+BOOLEAN mBmModeInitialized = FALSE;
+
+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)
+ }
+ },
+ //
+ // {1DDDBE15-481D-4d2b-8277-B191EAF66525}
+ //
+ { 0x1dddbe15, 0x481d, 0x4d2b, { 0x82, 0x77, 0xb1, 0x91, 0xea, 0xf6, 0x65, 0x25 } }
+ },
+ {
+ 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,
+ {
+ BootManagerExtractConfig,
+ BootManagerRouteConfig,
+ BootManagerCallback
+ }
+};
+
+/**
+ 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
+BmSetConsoleMode (
+ 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 required resolution and text mode is setup mode.
+ //
+ NewHorizontalResolution = mBmSetupHorizontalResolution;
+ NewVerticalResolution = mBmSetupVerticalResolution;
+ NewColumns = mBmSetupTextModeColumn;
+ NewRows = mBmSetupTextModeRow;
+ } else {
+ //
+ // The required resolution and text mode is boot mode.
+ //
+ NewHorizontalResolution = mBmBootHorizontalResolution;
+ NewVerticalResolution = mBmBootVerticalResolution;
+ NewColumns = mBmBootTextModeColumn;
+ NewRows = mBmBootTextModeRow;
+ }
+
+ 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 required 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, mBmSetupTextModeColumn);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdConOutRow, mBmSetupTextModeRow);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ if (Index == MaxTextMode) {
+ //
+ // If required 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;
+}
+
+/**
+
+ Check whether a reset is needed,if reset is needed, Popup a menu to notice user.
+
+**/
+VOID
+BmSetupResetReminder (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *StringBuffer1;
+ CHAR16 *StringBuffer2;
+ EFI_STATUS Status;
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
+
+ //
+ // Use BrowserEx2 protocol to check whether reset is required.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);
+ //
+ //check any reset required change is applied? if yes, reset system
+ //
+ if (!EFI_ERROR(Status) && FormBrowserEx2->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);
+ }
+}
+
+/**
+ 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####")];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff);
+
+ GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
+ if (BootOrder == NULL) {
+ return;
+ }
+
+ 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
+ //
+ DEBUG ((EFI_D_ERROR, "[BootManagerDxe] ==== Find Legacy Boot Option 0x%x! ==== \n", Index));
+ ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType & 0xF) < ARRAY_SIZE (DeviceTypeIndex));
+ NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->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 < ARRAY_SIZE (DeviceTypeIndex); DeviceIndex++) {
+ if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
+ DeviceTypeIndex[DeviceIndex]++;
+ }
+ }
+ }
+ }
+ EfiBootManagerFreeLoadOption (&BootOption);
+ }
+
+ gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderSize,
+ BootOrder
+ );
+ FreePool (BootOrder);
+}
+
+/**
+ 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 *
+BmDevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ToText;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+
+ if (DevPath == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevPathToText
+ );
+ ASSERT_EFI_ERROR (Status);
+ ToText = DevPathToText->ConvertDevicePathToText (
+ DevPath,
+ FALSE,
+ TRUE
+ );
+ ASSERT (ToText != NULL);
+ return ToText;
+}
+
+/**
+ This function invokes Boot Manager. 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
+UpdateBootManager (
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ EFI_STRING_ID Token;
+ CHAR16 *HelpString;
+ EFI_STRING_ID HelpToken;
+ UINT16 *TempStr;
+ EFI_HII_HANDLE HiiHandle;
+ UINTN TempSize;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ UINT16 DeviceType;
+ BOOLEAN IsLegacyOption;
+ BOOLEAN NeedEndOp;
+ UINTN MaxLen;
+
+ DeviceType = (UINT16) -1;
+
+ //
+ // 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 ();
+
+ //
+ // BdsDxe doesn't group the legacy boot options for the same device type
+ // It's UI's choice.
+ //
+ GroupMultipleLegacyBootOption4SameType ();
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ 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 (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // At this stage we are creating a menu entry, thus the Keys are reproduceable
+ //
+ mKeyInput++;
+
+ //
+ // Don't display hidden boot options, but retain inactive ones.
+ //
+ if ((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) {
+ continue;
+ }
+
+ //
+ // Group the legacy boot option in the sub title created dynamically
+ //
+ IsLegacyOption = (BOOLEAN) (
+ (DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)
+ );
+
+ if (!IsLegacyOption && NeedEndOp) {
+ NeedEndOp = FALSE;
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
+ if (NeedEndOp) {
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ DeviceType = ((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType;
+ Token = HiiSetString (
+ HiiHandle,
+ 0,
+ mDeviceTypeStr[
+ MIN (DeviceType & 0xF, ARRAY_SIZE (mDeviceTypeStr) - 1)
+ ],
+ NULL
+ );
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
+ NeedEndOp = TRUE;
+ }
+
+ ASSERT (BootOption[Index].Description != NULL);
+
+ Token = HiiSetString (HiiHandle, 0, BootOption[Index].Description, NULL);
+
+ TempStr = BmDevicePathToStr (BootOption[Index].FilePath);
+ TempSize = StrSize (TempStr);
+ HelpString = AllocateZeroPool (TempSize + StrSize (L"Device Path : "));
+ MaxLen = (TempSize + StrSize (L"Device Path : "))/sizeof(CHAR16);
+ ASSERT (HelpString != NULL);
+ StrCatS (HelpString, MaxLen, L"Device Path : ");
+ StrCatS (HelpString, MaxLen, TempStr);
+
+ HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ mKeyInput,
+ Token,
+ HelpToken,
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ }
+
+ if (NeedEndOp) {
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &mBootManagerGuid,
+ BOOT_MANAGER_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+}
+
+/**
+ 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
+BootManagerExtractConfig (
+ 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
+BootManagerRouteConfig (
+ 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;
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initial the boot mode related parameters.
+
+**/
+VOID
+BmInitialBootModeInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN BootTextColumn;
+ UINTN BootTextRow;
+
+ if (mBmModeInitialized) {
+ return;
+ }
+
+ //
+ // 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.
+ //
+ mBmBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
+ mBmBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
+ }
+
+ if (SimpleTextOut != NULL) {
+ Status = SimpleTextOut->QueryMode (
+ SimpleTextOut,
+ SimpleTextOut->Mode->Mode,
+ &BootTextColumn,
+ &BootTextRow
+ );
+ mBmBootTextModeColumn = (UINT32)BootTextColumn;
+ mBmBootTextModeRow = (UINT32)BootTextRow;
+ }
+
+ //
+ // Get user defined text mode for setup.
+ //
+ mBmSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
+ mBmSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
+ mBmSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);
+ mBmSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);
+
+ mBmModeInitialized = TRUE;
+}
+
+/**
+ 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
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ EFI_INPUT_KEY Key;
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ //
+ //Means enter the boot manager form.
+ //Update the boot manage page,because the boot option may changed.
+ //
+ if (QuestionId == 0x1212){
+ UpdateBootManager();
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // 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;
+ }
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ //
+ // Clear the screen before.
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ //
+ //check any reset required change is applied? if yes, reset system
+ //
+ BmSetupResetReminder ();
+
+ //
+ // parse the selected option
+ //
+ BmSetConsoleMode (FALSE);
+ EfiBootManagerBoot (&BootOption[QuestionId - 1]);
+ BmSetConsoleMode (TRUE);
+
+ if (EFI_ERROR (BootOption[QuestionId - 1].Status)) {
+ gST->ConOut->OutputString (
+ gST->ConOut,
+ HiiGetString (gBootManagerPrivate.HiiHandle, STRING_TOKEN (STR_ANY_KEY_CONTINUE), NULL)
+ );
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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
+BootManagerUiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ gBootManagerPrivate.DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gBootManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBootManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gBootManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ gBootManagerPrivate.HiiHandle = HiiAddPackages (
+ &mBootManagerGuid,
+ gBootManagerPrivate.DriverHandle,
+ BootManagerVfrBin,
+ BootManagerUiLibStrings,
+ NULL
+ );
+ ASSERT (gBootManagerPrivate.HiiHandle != NULL);
+
+ BmInitialBootModeInfo ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+ @param[in] SystemTable System Table
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+BootManagerUiLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gBootManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBootManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gBootManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HiiRemovePackages (gBootManagerPrivate.HiiHandle);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.h b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.h
new file mode 100644
index 000000000..f1ee922b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManager.h
@@ -0,0 +1,166 @@
+/** @file
+ The boot manager reference implementation
+
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_BOOT_MANAGER_H_
+#define _EFI_BOOT_MANAGER_H_
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FormBrowserEx2.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/UefiRuntimeServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.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()
+
+//
+// These are defined as the same with vfr file
+//
+#define BOOT_MANAGER_FORMSET_GUID \
+ { \
+ 0x847bc3fe, 0xb974, 0x446d, {0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b} \
+ }
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+#define LABEL_BOOT_OPTION_END 0x01
+#define MAX_STRING_LEN 200
+
+//
+// Variable created with this flag will be "Efi:...."
+//
+#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+//
+// 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
+ );
+
+/**
+ 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
+BootManagerExtractConfig (
+ 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
+BootManagerRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerStrings.uni b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerStrings.uni
new file mode 100644
index 000000000..2fcb9a29c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerStrings.uni
@@ -0,0 +1,36 @@
+///** @file
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// BootManagerStrings.uni
+//
+// Abstract:
+//
+// String definitions for Boot Manager formset.
+//
+// Revision History:
+//
+// --*/
+
+/=#
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_BM_BANNER #language en-US "Boot Manager"
+ #language fr-FR "Boot Manager"
+#string STR_BOOT_MANAGER_HELP #language en-US "This selection will take you to the Boot Manager"
+ #language fr-FR "This selection will take you to the Boot Manager"
+#string STR_HELP_FOOTER #language en-US "Use the <↑> and <↓> keys to choose a boot option, the <Enter> key to select a boot option, and the <Esc> key to exit the Boot Manager Menu."
+ #language fr-FR "<↑> pour <↓> changer l'option, <ENTRER> choisir une option, <ESC> pour sortir"
+#string STR_AND #language en-US " and "
+ #language fr-FR " et "
+#string STR_BOOT_OPTION_BANNER #language en-US "Boot Manager Menu"
+ #language fr-FR "le Menu d'Option de Botte"
+#string STR_ANY_KEY_CONTINUE #language en-US "Press any key to continue..."
+ #language fr-FR "Appuie n'importe quelle pour continuer..."
+#string STR_LAST_STRING #language en-US ""
+ #language fr-FR ""
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
new file mode 100644
index 000000000..020cf7505
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
@@ -0,0 +1,65 @@
+## @file
+# Boot Manager Library used by UiApp.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootManagerUiLib
+ MODULE_UNI_FILE = BootManagerUiLib.uni
+ FILE_GUID = CCB2DCE1-4FC8-41CB-88C5-D349E134C9FC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = BootManagerUiLibConstructor
+ DESTRUCTOR = BootManagerUiLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootManager.h
+ BootManagerVfr.Vfr
+ BootManagerStrings.uni
+ BootManager.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiBootManagerLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode)
+ gEfiIfrFrontPageGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES
+ gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## CONSUMES ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## CONSUMES ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.uni b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.uni
new file mode 100644
index 000000000..9d2ff3ba8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Boot Manager Library used by UiApp.
+//
+// Boot Manager Library used by UiApp.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Boot Manager Library used by UiApp."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Boot Manager Library used by UiApp."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerVfr.Vfr b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerVfr.Vfr
new file mode 100644
index 000000000..4049fe677
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BootManagerUiLib/BootManagerVfr.Vfr
@@ -0,0 +1,51 @@
+///** @file
+//
+// Boot Manager formset.
+//
+// Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+#define FORMSET_GUID { 0x847bc3fe, 0xb974, 0x446d, 0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b }
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+#define LABEL_BOOT_OPTION_END 0x01
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_BM_BANNER),
+ help = STRING_TOKEN(STR_BOOT_MANAGER_HELP),
+ classguid = gEfiIfrFrontPageGuid,
+
+ 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);
+
+ //
+ //Add this invisable text in order to indicate enter Boot Manager form.
+ //
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_LAST_STRING ),
+ text = STRING_TOKEN(STR_LAST_STRING ),
+ flags = INTERACTIVE,
+ key = 0x1212;
+ endif;
+
+ //
+ // 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/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf
new file mode 100644
index 000000000..525e92408
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf
@@ -0,0 +1,73 @@
+## @file
+# BrotliCustomDecompressLib produces BROTLI custom decompression algorithm.
+#
+# It is based on the Brotli v0.5.2.
+# Brotli was released on the website https://github.com/google/brotli.
+#
+# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BrotliDecompressLib
+ MODULE_UNI_FILE = BrotliDecompressLib.uni
+ FILE_GUID = 69EC7DB2-B0DD-493A-963A-C5F330131BAA
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = BrotliDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ GuidedSectionExtraction.c
+ BrotliDecUefiSupport.c
+ BrotliDecUefiSupport.h
+ BrotliDecompress.c
+ BrotliDecompressLibInternal.h
+ # Wrapper header files start #
+ stddef.h
+ stdint.h
+ stdlib.h
+ string.h
+ # Wrapper header files end #
+ brotli/c/common/dictionary.c
+ brotli/c/common/transform.c
+ brotli/c/dec/bit_reader.c
+ brotli/c/dec/decode.c
+ brotli/c/dec/huffman.c
+ brotli/c/dec/state.c
+ brotli/c/include/brotli/decode.h
+ brotli/c/include/brotli/port.h
+ brotli/c/include/brotli/types.h
+ brotli/c/common/constants.h
+ brotli/c/common/context.h
+ brotli/c/common/dictionary.h
+ brotli/c/common/platform.h
+ brotli/c/common/transform.h
+ brotli/c/common/version.h
+ brotli/c/dec/bit_reader.h
+ brotli/c/dec/huffman.h
+ brotli/c/dec/state.h
+ brotli/c/dec/prefix.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids]
+ gBrotliCustomDecompressGuid ## PRODUCES ## UNDEFINED # specifies BROTLI custom decompress algorithm.
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.c
new file mode 100644
index 000000000..102146535
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.c
@@ -0,0 +1,31 @@
+/** @file
+ Implements for functions declared in BrotliDecUefiSupport.h
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <BrotliDecUefiSupport.h>
+
+/**
+ Dummy malloc function for compiler.
+**/
+VOID *
+BrDummyMalloc (
+ IN size_t Size
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Dummy free function for compiler.
+**/
+VOID
+BrDummyFree (
+ IN VOID * Ptr
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.h
new file mode 100644
index 000000000..9f8434767
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecUefiSupport.h
@@ -0,0 +1,43 @@
+/** @file
+ BROTLI UEFI header file for definitions
+
+ Allows BROTLI code to build under UEFI (edk2) build environment
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __BROTLI_DECOMPRESS_UEFI_SUP_H__
+#define __BROTLI_DECOMPRESS_UEFI_SUP_H__
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#define memcpy CopyMem
+#define memmove CopyMem
+#define memset(dest,ch,count) SetMem(dest,(UINTN)(count),(UINT8)(ch))
+#define malloc BrDummyMalloc
+#define free BrDummyFree
+
+typedef INT8 int8_t;
+typedef INT16 int16_t;
+typedef INT32 int32_t;
+typedef INT64 int64_t;
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
+typedef UINTN size_t;
+
+VOID *
+BrDummyMalloc (
+ IN size_t Size
+ );
+
+VOID
+BrDummyFree (
+ IN VOID * Ptr
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompress.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompress.c
new file mode 100644
index 000000000..512518699
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompress.c
@@ -0,0 +1,316 @@
+/** @file
+ Brotli Decompress interfaces
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <BrotliDecompressLibInternal.h>
+
+/**
+ Dummy malloc function for compiler.
+**/
+VOID *
+BrDummyMalloc (
+ IN size_t Size
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Dummy free function for compiler.
+**/
+VOID
+BrDummyFree (
+ IN VOID * Ptr
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Allocation routine used by BROTLI decompression.
+
+ @param Ptr Pointer to the BROTLI_BUFF instance.
+ @param Size The size in bytes to be allocated.
+
+ @return The allocated pointer address, or NULL on failure
+**/
+VOID *
+BrAlloc (
+ IN VOID * Ptr,
+ IN size_t Size
+ )
+{
+ VOID *Addr;
+ BROTLI_BUFF *Private;
+
+ Private = (BROTLI_BUFF *)Ptr;
+
+ if (Private->BuffSize >= Size) {
+ Addr = Private->Buff;
+ Private->Buff = (VOID *) ((UINT8 *)Addr + Size);
+ Private->BuffSize -= Size;
+ return Addr;
+ } else {
+ ASSERT (FALSE);
+ return NULL;
+ }
+}
+
+/**
+ Free routine used by BROTLI decompression.
+
+ @param Ptr Pointer to the BROTLI_BUFF instance
+ @param Address The address to be freed
+**/
+VOID
+BrFree (
+ IN VOID * Ptr,
+ IN 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.
+ //
+}
+
+/**
+ Decompresses a Brotli compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then EFI_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then EFI_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 DestSize The destination buffer size.
+ @param BuffInfo The pointer to the BROTLI_BUFF instance.
+
+ @retval EFI_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+EFI_STATUS
+BrotliDecompress (
+ IN CONST VOID* Source,
+ IN UINTN SourceSize,
+ IN OUT VOID* Destination,
+ IN OUT UINTN DestSize,
+ IN VOID * BuffInfo
+ )
+{
+ UINT8 * Input;
+ UINT8 * Output;
+ const UINT8 * NextIn;
+ UINT8 * NextOut;
+ size_t TotalOut;
+ size_t AvailableIn;
+ size_t AvailableOut;
+ VOID * Temp;
+ BrotliDecoderResult Result;
+ BrotliDecoderState * BroState;
+
+ TotalOut = 0;
+ AvailableOut = FILE_BUFFER_SIZE;
+ Result = BROTLI_DECODER_RESULT_ERROR;
+ BroState = BrotliDecoderCreateInstance(BrAlloc, BrFree, BuffInfo);
+ Temp = Destination;
+
+ if (BroState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Input = (UINT8 *)BrAlloc(BuffInfo, FILE_BUFFER_SIZE);
+ Output = (UINT8 *)BrAlloc(BuffInfo, FILE_BUFFER_SIZE);
+ if ((Input==NULL) || (Output==NULL)) {
+ BrFree(BuffInfo, Input);
+ BrFree(BuffInfo, Output);
+ BrotliDecoderDestroyInstance(BroState);
+ return EFI_INVALID_PARAMETER;
+ }
+ NextOut = Output;
+ Result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
+ while (1) {
+ if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
+ if (SourceSize == 0) {
+ break;
+ }
+ if (SourceSize >= FILE_BUFFER_SIZE) {
+ AvailableIn = FILE_BUFFER_SIZE;
+ }else{
+ AvailableIn = SourceSize;
+ }
+ CopyMem(Input, Source, AvailableIn);
+ Source = (VOID *)((UINT8 *)Source + AvailableIn);
+ SourceSize -= AvailableIn;
+ NextIn = Input;
+ } else if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ CopyMem(Temp, Output, FILE_BUFFER_SIZE);
+ AvailableOut = FILE_BUFFER_SIZE;
+ Temp = (VOID *)((UINT8 *)Temp +FILE_BUFFER_SIZE);
+ NextOut = Output;
+ } else {
+ break; /* Error or success. */
+ }
+ Result = BrotliDecoderDecompressStream(
+ BroState,
+ &AvailableIn,
+ &NextIn,
+ &AvailableOut,
+ &NextOut,
+ &TotalOut
+ );
+ }
+ if (NextOut != Output) {
+ CopyMem(Temp, Output, (size_t)(NextOut - Output));
+ }
+
+ DestSize = TotalOut;
+
+ BrFree(BuffInfo, Input);
+ BrFree(BuffInfo, Output);
+ BrotliDecoderDestroyInstance(BroState);
+ return (Result == BROTLI_DECODER_RESULT_SUCCESS) ? EFI_SUCCESS : EFI_INVALID_PARAMETER;
+}
+
+/**
+ Get the size of the uncompressed buffer by parsing EncodeData header.
+
+ @param EncodedData Pointer to the compressed data.
+ @param StartOffset Start offset of the compressed data.
+ @param EndOffset End offset of the compressed data.
+
+ @return The size of the uncompressed buffer.
+**/
+UINT64
+BrGetDecodedSizeOfBuf(
+ IN UINT8 * EncodedData,
+ IN UINT8 StartOffset,
+ IN UINT8 EndOffset
+ )
+{
+ UINT64 DecodedSize;
+ INTN Index;
+
+ /* Parse header */
+ DecodedSize = 0;
+ for (Index = EndOffset - 1; Index >= StartOffset; Index--)
+ DecodedSize = LShiftU64(DecodedSize, 8) + EncodedData[Index];
+
+ return DecodedSize;
+}
+
+/**
+ Given a Brotli 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 EFI_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 BROTLI_SCRATCH_MAX beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If SourceSize is less than BROTLI_SCRATCH_MAX, 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 EFI_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+**/
+EFI_STATUS
+EFIAPI
+BrotliUefiDecompressGetInfo (
+ IN CONST VOID * Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 * DestinationSize,
+ OUT UINT32 * ScratchSize
+ )
+{
+ UINT64 GetSize;
+ UINT8 MaxOffset;
+
+ ASSERT(SourceSize >= BROTLI_SCRATCH_MAX);
+
+ MaxOffset = BROTLI_DECODE_MAX;
+ GetSize = BrGetDecodedSizeOfBuf((UINT8 *)Source, MaxOffset - BROTLI_INFO_SIZE, MaxOffset);
+ *DestinationSize = (UINT32)GetSize;
+ MaxOffset = BROTLI_SCRATCH_MAX;
+ GetSize = BrGetDecodedSizeOfBuf((UINT8 *)Source, MaxOffset - BROTLI_INFO_SIZE, MaxOffset);
+ *ScratchSize = (UINT32)GetSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Decompresses a Brotli 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 EFI_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+EFI_STATUS
+EFIAPI
+BrotliUefiDecompress (
+ IN CONST VOID * Source,
+ IN UINTN SourceSize,
+ IN OUT VOID * Destination,
+ IN OUT VOID * Scratch
+ )
+{
+ UINTN DestSize = 0;
+ EFI_STATUS Status;
+ BROTLI_BUFF BroBuff;
+ UINT64 GetSize;
+ UINT8 MaxOffset;
+
+ MaxOffset = BROTLI_SCRATCH_MAX;
+ GetSize = BrGetDecodedSizeOfBuf((UINT8 *)Source, MaxOffset - BROTLI_INFO_SIZE, MaxOffset);
+
+ BroBuff.Buff = Scratch;
+ BroBuff.BuffSize = (UINTN)GetSize;
+
+ Status = BrotliDecompress(
+ (VOID *)((UINT8 *)Source + BROTLI_SCRATCH_MAX),
+ SourceSize - BROTLI_SCRATCH_MAX,
+ Destination,
+ DestSize,
+ (VOID *)(&BroBuff)
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLib.uni b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLib.uni
new file mode 100644
index 000000000..22f9d9add
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// BrotliCustomDecompressLib produces BROTLI custom decompression algorithm.
+//
+// It is based on the Brotli v0.5.2.
+// Brotli was released on the website https://github.com/google/brotli.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "BrotliCustomDecompressLib produces BROTLI custom decompression algorithm"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It is based on the Brotli v0.5.2. Brotli was released on the website https://github.com/google/brotli."
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLibInternal.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLibInternal.h
new file mode 100644
index 000000000..8f91829a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliDecompressLibInternal.h
@@ -0,0 +1,48 @@
+/** @file
+ BROTLI UEFI header file
+
+ Allows BROTLI code to build under UEFI (edk2) build environment
+
+ Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __BROTLI_DECOMPRESS_INTERNAL_H__
+#define __BROTLI_DECOMPRESS_INTERNAL_H__
+
+#include <PiPei.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <brotli/c/include/brotli/types.h>
+#include <brotli/c/include/brotli/decode.h>
+
+typedef struct
+{
+ VOID *Buff;
+ UINTN BuffSize;
+} BROTLI_BUFF;
+
+#define FILE_BUFFER_SIZE 65536
+#define BROTLI_INFO_SIZE 8
+#define BROTLI_DECODE_MAX 8
+#define BROTLI_SCRATCH_MAX 16
+
+EFI_STATUS
+EFIAPI
+BrotliUefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+EFI_STATUS
+EFIAPI
+BrotliUefiDecompress (
+ IN CONST VOID *Source,
+ IN UINTN SourceSize,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/GuidedSectionExtraction.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/GuidedSectionExtraction.c
new file mode 100644
index 000000000..bb7665f82
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/GuidedSectionExtraction.c
@@ -0,0 +1,191 @@
+/** @file
+ BROTLI Decompress GUIDed Section Extraction Library.
+ It wraps Brotli decompress interfaces to GUIDed Section Extraction interfaces
+ and registers them into GUIDed handler table.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BrotliDecompressLibInternal.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
+BrotliGuidedSectionGetInfo (
+ 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 (
+ &gBrotliCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ return BrotliUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gBrotliCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ return BrotliUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a BROTLI 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
+BrotliGuidedSectionExtraction (
+ 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 (
+ &gBrotliCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return BrotliUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ } else {
+ if (!CompareGuid (
+ &gBrotliCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return BrotliUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ }
+}
+
+/**
+ Register BrotliDecompress and BrotliDecompressGetInfo handlers with BrotliCustomerDecompressGuid.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+EFI_STATUS
+EFIAPI
+BrotliDecompressLibConstructor (
+ VOID
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gBrotliCustomDecompressGuid,
+ BrotliGuidedSectionGetInfo,
+ BrotliGuidedSectionExtraction
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.editorconfig b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.editorconfig
new file mode 100644
index 000000000..17ed3c197
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.editorconfig
@@ -0,0 +1,40 @@
+# http://editorconfig.org
+# Consistent coding style across different editors.
+
+# Top-most file
+root = true
+
+# Global styles:
+# - indent 2 spaces
+# - add final new line
+# - trim trailing whitespace
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# BUILD:
+# - indent 4 spaces
+[BUILD]
+indent_size = 4
+
+# Makefile:
+# - indent 1 tab
+[Makefile]
+indent_size = tab
+indent_style = tab
+
+# Markdown:
+# - indent 4 spaces
+# - trailing whitespace is significant
+[*.md]
+indent_size = 4
+trim_trailing_whitespace = false
+
+# Python
+# - indent 4 spaces
+[*.py]
+indent_size = 4
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitattributes b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitattributes
new file mode 100644
index 000000000..a1665dacc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitattributes
@@ -0,0 +1 @@
+tests/testdata/* binary
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitignore b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitignore
new file mode 100644
index 000000000..e3a69e62c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitignore
@@ -0,0 +1,18 @@
+# C
+*.o
+bin/
+buildfiles/
+**/obj/
+dist/
+**/bazel-*
+
+# Python
+__pycache__/
+*.py[cod]
+*.so
+*.egg-info/
+
+# Tests
+*.txt.uncompressed
+*.br
+*.unbr
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitmodules b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitmodules
new file mode 100644
index 000000000..3ec8760a5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "research/esaxx"]
+ path = research/esaxx
+ url = https://github.com/hillbig/esaxx
+[submodule "research/libdivsufsort"]
+ path = research/libdivsufsort
+ url = https://github.com/y-256/libdivsufsort.git
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.travis.yml b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.travis.yml
new file mode 100644
index 000000000..930bd6346
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/.travis.yml
@@ -0,0 +1,229 @@
+language: c
+sudo: false
+branches:
+ only:
+ - master
+matrix:
+ include:
+ ###
+ ## Linux builds using various versions of GCC.
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=gcc-7 CXX_COMPILER=g++-7
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-7
+ - g++-7
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.4 CXX_COMPILER=g++-4.4
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-4.4
+ - g++-4.4
+
+ ###
+ ## Test that Autotools build works.
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=autotools C_COMPILER=gcc-5 CXX_COMPILER=g++-5
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-5
+ - g++-5
+
+ ###
+ ## Test that fuzzer is compiling / working.
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=fuzz C_COMPILER=clang-7 CXX_COMPILER=clang++-7 ASAN_OPTIONS=detect_leaks=0
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-xenial-7
+ packages:
+ - clang-7
+
+ ###
+ ## clang on Linux
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=clang-7 CXX_COMPILER=clang++-7
+ addons:
+ apt:
+ sources:
+ - llvm-toolchain-xenial-7
+ - ubuntu-toolchain-r-test
+ packages:
+ - clang-7
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=clang-3.5 CXX_COMPILER=clang++-3.5
+ addons:
+ apt:
+ sources:
+ - llvm-toolchain-trusty-3.5
+ - ubuntu-toolchain-r-test
+ packages:
+ - clang-3.5
+
+ ###
+ ## testing arm via qemu on Linux
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=arm-linux-gnueabihf-gcc CXX_COMPILER=arm-linux-gnueabihf-g++ CFLAGS="-march=armv7-a -mfloat-abi=hard -mfpu=neon"
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - qemu
+ - gcc-arm-linux-gnueabihf
+ - libc6-dev-armhf-cross
+
+ ###
+ ## PGI Community Edition on Linux
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=pgcc CXX_COMPILER=pgc++
+
+ ###
+ ## Python 2.7 and 3.6 builds on Linux
+ ###
+ - os: linux
+ language: python
+ python: 2.7
+ env: BUILD_SYSTEM=python C_COMPILER=gcc-5 CXX_COMPILER=g++-5
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-5
+ - g++-5
+ - os: linux
+ language: python
+ python: 3.6
+ env: BUILD_SYSTEM=python C_COMPILER=gcc-5 CXX_COMPILER=g++-5
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-5
+ - g++-5
+
+ ###
+ ## CMake on OS X
+ ##
+ ## These all work, but it seems unnecessary to actually build them
+ ## all since we already test all these versions of GCC on Linux.
+ ## We'll just test 4.4 and the most recent version.
+ ###
+ - os: osx
+ env: BUILD_SYSTEM=cmake C_COMPILER=gcc CXX_COMPILER=g++
+ - os: osx
+ env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
+ - os: osx
+ env: BUILD_SYSTEM=cmake
+
+ ###
+ ## Python 2.7 OS X build (using the system /usr/bin/python)
+ ###
+ - os: osx
+ env: BUILD_SYSTEM=python C_COMPILER=gcc CXX_COMPILER=g++
+
+ ###
+ ## Sanitizers
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=clang-7 CXX_COMPILER=clang++-7 SANITIZER=address ASAN_OPTIONS=detect_leaks=0
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-xenial-7
+ packages:
+ - clang-7
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=clang-7 CXX_COMPILER=clang++-7 SANITIZER=thread
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-xenial-7
+ packages:
+ - clang-7
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=clang-7 CXX_COMPILER=clang++-7 SANITIZER=undefined CFLAGS="-fno-sanitize-recover=undefined,integer"
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-xenial-7
+ packages:
+ - clang-7
+
+ - os: linux
+ env: BUILD_SYSTEM=maven
+ jdk:
+ # maven + jdk11 + javadoc == trouble
+ - openjdk10
+ language: java
+
+ - os: linux
+ sudo: required
+ language: java
+ jdk: oraclejdk9
+ env: BUILD_SYSTEM=bazel
+ addons:
+ apt:
+ sources:
+ - sourceline: "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8"
+ key_url: "https://storage.googleapis.com/bazel-apt/doc/apt-key.pub.gpg"
+ - ubuntu-toolchain-r-test
+ packages:
+ - bazel
+
+ - os: osx
+ env: BUILD_SYSTEM=bazel
+ # Latest image with Java 1.8 (required to install Bazel).
+ osx_image: xcode9.3
+ language: java
+
+before_install:
+###
+## If we use the matrix to set CC/CXX Travis, overwrites the values,
+## so instead we use C/CXX_COMPILER, then copy the values to CC/CXX
+## here (after Travis has set CC/CXX).
+###
+- if [ -n "${C_COMPILER}" ]; then export CC="${C_COMPILER}"; fi
+- if [ -n "${CXX_COMPILER}" ]; then export CXX="${CXX_COMPILER}"; fi
+- scripts/.travis.sh before_install
+install:
+- scripts/.travis.sh install
+script:
+- scripts/.travis.sh script
+after_success:
+- scripts/.travis.sh after_success
+
+before_deploy:
+- scripts/.travis.sh before_deploy
+
+deploy:
+- provider: bintray
+ file: "scripts/.bintray.json"
+ user: "eustas"
+ key:
+ secure: "Kbam/lTAdz72fZivbs6riJT+Y4PbuKP7r6t5PAWxJxAAykjwnYTRe3zF472g9HCE14KYMsdB+KSYSgg6TGJnqGC9gL9xhhGU9U/WmA+vbMWS/MSnMWpK9IRpp77pM2i2NKZD4v33JuEwKFCBJP3Vj6QQ5Qd1NKdobuXJyznhgnw="
+ on:
+ condition: "${BUILD_SYSTEM} = bazel"
+ skip_cleanup: true
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/BUILD
new file mode 100644
index 000000000..4c9b57ac9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/BUILD
@@ -0,0 +1,144 @@
+# Description:
+# Brotli is a generic-purpose lossless compression algorithm.
+
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"]) # MIT
+
+exports_files(["LICENSE"])
+
+config_setting(
+ name = "darwin",
+ values = {"cpu": "darwin"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "darwin_x86_64",
+ values = {"cpu": "darwin_x86_64"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "windows",
+ values = {"cpu": "x64_windows"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "windows_msvc",
+ values = {"cpu": "x64_windows_msvc"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "windows_msys",
+ values = {"cpu": "x64_windows_msys"},
+ visibility = ["//visibility:public"],
+)
+
+load(":compiler_config_setting.bzl", "create_msvc_config")
+
+create_msvc_config()
+
+STRICT_C_OPTIONS = select({
+ ":msvc": [],
+ "//conditions:default": [
+ "--pedantic-errors",
+ "-Wall",
+ "-Wconversion",
+ "-Werror",
+ "-Wextra",
+ "-Wlong-long",
+ "-Wmissing-declarations",
+ "-Wmissing-prototypes",
+ "-Wno-strict-aliasing",
+ "-Wshadow",
+ "-Wsign-compare",
+ ],
+})
+
+filegroup(
+ name = "public_headers",
+ srcs = glob(["c/include/brotli/*.h"]),
+)
+
+filegroup(
+ name = "common_headers",
+ srcs = glob(["c/common/*.h"]),
+)
+
+filegroup(
+ name = "common_sources",
+ srcs = glob(["c/common/*.c"]),
+)
+
+filegroup(
+ name = "dec_headers",
+ srcs = glob(["c/dec/*.h"]),
+)
+
+filegroup(
+ name = "dec_sources",
+ srcs = glob(["c/dec/*.c"]),
+)
+
+filegroup(
+ name = "enc_headers",
+ srcs = glob(["c/enc/*.h"]),
+)
+
+filegroup(
+ name = "enc_sources",
+ srcs = glob(["c/enc/*.c"]),
+)
+
+cc_library(
+ name = "brotli_inc",
+ hdrs = [":public_headers"],
+ copts = STRICT_C_OPTIONS,
+ strip_include_prefix = "c/include",
+)
+
+cc_library(
+ name = "brotlicommon",
+ srcs = [":common_sources"],
+ hdrs = [":common_headers"],
+ copts = STRICT_C_OPTIONS,
+ deps = [":brotli_inc"],
+)
+
+cc_library(
+ name = "brotlidec",
+ srcs = [":dec_sources"],
+ hdrs = [":dec_headers"],
+ copts = STRICT_C_OPTIONS,
+ deps = [":brotlicommon"],
+)
+
+cc_library(
+ name = "brotlienc",
+ srcs = [":enc_sources"],
+ hdrs = [":enc_headers"],
+ copts = STRICT_C_OPTIONS,
+ linkopts = ["-lm"],
+ deps = [":brotlicommon"],
+)
+
+cc_binary(
+ name = "brotli",
+ srcs = ["c/tools/brotli.c"],
+ copts = STRICT_C_OPTIONS,
+ linkstatic = 1,
+ deps = [
+ ":brotlidec",
+ ":brotlienc",
+ ],
+)
+
+filegroup(
+ name = "dictionary",
+ srcs = ["c/common/dictionary.bin"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CMakeLists.txt
new file mode 100644
index 000000000..a8ea87231
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CMakeLists.txt
@@ -0,0 +1,407 @@
+# Ubuntu 12.04 LTS has CMake 2.8.7, and is an important target since
+# several CI services, such as Travis and Drone, use it. Solaris 11
+# has 2.8.6, and it's not difficult to support if you already have to
+# support 2.8.7.
+cmake_minimum_required(VERSION 2.8.6)
+
+project(brotli C)
+
+include(CheckCSourceCompiles)
+check_c_source_compiles(
+ "#if defined(__EMSCRIPTEN__)
+ int main() {return 0;}
+ #endif"
+ BROTLI_EMSCRIPTEN
+)
+if (BROTLI_EMSCRIPTEN)
+ message("-- Compiler is EMSCRIPTEN")
+else()
+ message("-- Compiler is not EMSCRIPTEN")
+endif()
+
+# If Brotli is being bundled in another project, we don't want to
+# install anything. However, we want to let people override this, so
+# we'll use the BROTLI_BUNDLED_MODE variable to let them do that; just
+# set it to OFF in your project before you add_subdirectory(brotli).
+get_directory_property(BROTLI_PARENT_DIRECTORY PARENT_DIRECTORY)
+if(NOT DEFINED BROTLI_BUNDLED_MODE)
+ # Bundled mode hasn't been set one way or the other, set the default
+ # depending on whether or not we are the top-level project.
+ if(BROTLI_PARENT_DIRECTORY)
+ set(BROTLI_BUNDLED_MODE ON)
+ else()
+ set(BROTLI_BUNDLED_MODE OFF)
+ endif()
+endif()
+mark_as_advanced(BROTLI_BUNDLED_MODE)
+
+include(GNUInstallDirs)
+
+# Parse version information from common/version.h. Normally we would
+# define these values here and write them out to configuration file(s)
+# (i.e., config.h), but in this case we parse them from
+# common/version.h to be less intrusive.
+function(hex_to_dec HEXADECIMAL DECIMAL)
+ string(TOUPPER "${HEXADECIMAL}" _tail)
+ set(_decimal 0)
+ string(LENGTH "${_tail}" _tail_length)
+ while (_tail_length GREATER 0)
+ math(EXPR _decimal "${_decimal} * 16")
+ string(SUBSTRING "${_tail}" 0 1 _digit)
+ string(SUBSTRING "${_tail}" 1 -1 _tail)
+ if (_digit STREQUAL "A")
+ math(EXPR _decimal "${_decimal} + 10")
+ elseif (_digit STREQUAL "B")
+ math(EXPR _decimal "${_decimal} + 11")
+ elseif (_digit STREQUAL "C")
+ math(EXPR _decimal "${_decimal} + 12")
+ elseif (_digit STREQUAL "D")
+ math(EXPR _decimal "${_decimal} + 13")
+ elseif (_digit STREQUAL "E")
+ math(EXPR _decimal "${_decimal} + 14")
+ elseif (_digit STREQUAL "F")
+ math(EXPR _decimal "${_decimal} + 15")
+ else()
+ math(EXPR _decimal "${_decimal} + ${_digit}")
+ endif()
+ string(LENGTH "${_tail}" _tail_length)
+ endwhile()
+ set(${DECIMAL} ${_decimal} PARENT_SCOPE)
+endfunction(hex_to_dec)
+
+# Version information
+file(STRINGS "c/common/version.h" _brotli_version_line REGEX "^#define BROTLI_VERSION (0x[0-9a-fA-F]+)$")
+string(REGEX REPLACE "^#define BROTLI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_version_hex "${_brotli_version_line}")
+hex_to_dec("${_brotli_version_hex}" _brotli_version)
+math(EXPR BROTLI_VERSION_MAJOR "${_brotli_version} >> 24")
+math(EXPR BROTLI_VERSION_MINOR "(${_brotli_version} >> 12) & 4095")
+math(EXPR BROTLI_VERSION_PATCH "${_brotli_version} & 4095")
+set(BROTLI_VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_PATCH}")
+mark_as_advanced(BROTLI_VERSION BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_PATCH)
+
+# ABI Version information
+file(STRINGS "c/common/version.h" _brotli_abi_info_line REGEX "^#define BROTLI_ABI_VERSION (0x[0-9a-fA-F]+)$")
+string(REGEX REPLACE "^#define BROTLI_ABI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_abi_info_hex "${_brotli_abi_info_line}")
+hex_to_dec("${_brotli_abi_info_hex}" _brotli_abi_info)
+math(EXPR BROTLI_ABI_CURRENT "${_brotli_abi_info} >> 24")
+math(EXPR BROTLI_ABI_REVISION "(${_brotli_abi_info} >> 12) & 4095")
+math(EXPR BROTLI_ABI_AGE "${_brotli_abi_info} & 4095")
+math(EXPR BROTLI_ABI_COMPATIBILITY "${BROTLI_ABI_CURRENT} - ${BROTLI_ABI_AGE}")
+mark_as_advanced(BROTLI_ABI_CURRENT BROTLI_ABI_REVISION BROTLI_ABI_AGE BROTLI_ABI_COMPATIBILITY)
+
+if (ENABLE_SANITIZER)
+ set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
+ set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
+
+ # By default, brotli depends on undefined behavior, but setting
+ # BROTLI_BUILD_PORTABLE should result in a build which does not.
+ if(ENABLE_SANITIZER STREQUAL "undefined")
+ add_definitions(-DBROTLI_BUILD_PORTABLE)
+ endif()
+endif ()
+
+include(CheckFunctionExists)
+set(LIBM_LIBRARY)
+CHECK_FUNCTION_EXISTS(log2 LOG2_RES)
+if(NOT LOG2_RES)
+ set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}")
+ set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m")
+ CHECK_FUNCTION_EXISTS(log2 LOG2_LIBM_RES)
+ if(LOG2_LIBM_RES)
+ set(LIBM_LIBRARY "m")
+ else()
+ message(FATAL_ERROR "log2() not found")
+ endif()
+
+ set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}")
+ unset(LOG2_LIBM_RES)
+ unset(orig_req_libs)
+endif()
+unset(LOG2_RES)
+
+set(BROTLI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/c/include")
+mark_as_advanced(BROTLI_INCLUDE_DIRS)
+
+set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon)
+set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY})
+mark_as_advanced(BROTLI_LIBRARIES)
+
+set(BROTLI_LIBRARIES_CORE_STATIC brotlienc-static brotlidec-static brotlicommon-static)
+set(BROTLI_LIBRARIES_STATIC ${BROTLI_LIBRARIES_CORE_STATIC} ${LIBM_LIBRARY})
+mark_as_advanced(BROTLI_LIBRARIES_STATIC)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ add_definitions(-DOS_LINUX)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+ add_definitions(-DOS_FREEBSD)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ add_definitions(-DOS_MACOSX)
+endif()
+
+function(transform_sources_list INPUT_FILE OUTPUT_FILE)
+ file(READ ${INPUT_FILE} TEXT)
+ string(REGEX REPLACE "\\\\\n" "~continuation~" TEXT ${TEXT})
+ string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" TEXT ${TEXT})
+ string(REPLACE "~continuation~" "\n" TEXT ${TEXT})
+ file(WRITE ${OUTPUT_FILE} ${TEXT})
+endfunction()
+
+transform_sources_list("scripts/sources.lst" "${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake")
+include("${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake")
+
+if(BROTLI_EMSCRIPTEN)
+ set(BROTLI_SHARED_LIBS "")
+else()
+ set(BROTLI_SHARED_LIBS brotlicommon brotlidec brotlienc)
+ add_library(brotlicommon SHARED ${BROTLI_COMMON_C})
+ add_library(brotlidec SHARED ${BROTLI_DEC_C})
+ add_library(brotlienc SHARED ${BROTLI_ENC_C})
+endif()
+
+set(BROTLI_STATIC_LIBS brotlicommon-static brotlidec-static brotlienc-static)
+add_library(brotlicommon-static STATIC ${BROTLI_COMMON_C})
+add_library(brotlidec-static STATIC ${BROTLI_DEC_C})
+add_library(brotlienc-static STATIC ${BROTLI_ENC_C})
+
+# Older CMake versions does not understand INCLUDE_DIRECTORIES property.
+include_directories(${BROTLI_INCLUDE_DIRS})
+
+foreach(lib IN LISTS BROTLI_SHARED_LIBS)
+ target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION" )
+ string(TOUPPER "${lib}" LIB)
+ set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION")
+endforeach()
+
+foreach(lib IN LISTS BROTLI_SHARED_LIBS BROTLI_STATIC_LIBS)
+ target_link_libraries(${lib} ${LIBM_LIBRARY})
+ set_property(TARGET ${lib} APPEND PROPERTY INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIRS})
+ set_target_properties(${lib} PROPERTIES
+ VERSION "${BROTLI_ABI_COMPATIBILITY}.${BROTLI_ABI_AGE}.${BROTLI_ABI_REVISION}"
+ SOVERSION "${BROTLI_ABI_COMPATIBILITY}")
+ if(NOT BROTLI_EMSCRIPTEN)
+ set_target_properties(${lib} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+ endif()
+ set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${BROTLI_INCLUDE_DIRS}")
+endforeach()
+
+if(NOT BROTLI_EMSCRIPTEN)
+target_link_libraries(brotlidec brotlicommon)
+target_link_libraries(brotlienc brotlicommon)
+endif()
+
+target_link_libraries(brotlidec-static brotlicommon-static)
+target_link_libraries(brotlienc-static brotlicommon-static)
+
+# For projects stuck on older versions of CMake, this will set the
+# BROTLI_INCLUDE_DIRS and BROTLI_LIBRARIES variables so they still
+# have a relatively easy way to use Brotli:
+#
+# include_directories(${BROTLI_INCLUDE_DIRS})
+# target_link_libraries(foo ${BROTLI_LIBRARIES})
+if(BROTLI_PARENT_DIRECTORY)
+ set(BROTLI_INCLUDE_DIRS "${BROTLI_INCLUDE_DIRS}" PARENT_SCOPE)
+ set(BROTLI_LIBRARIES "${BROTLI_LIBRARIES}" PARENT_SCOPE)
+endif()
+
+# Build the brotli executable
+add_executable(brotli ${BROTLI_CLI_C})
+target_link_libraries(brotli ${BROTLI_LIBRARIES_STATIC})
+
+# Installation
+if(NOT BROTLI_EMSCRIPTEN)
+if(NOT BROTLI_BUNDLED_MODE)
+ install(
+ TARGETS brotli
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ )
+
+ install(
+ TARGETS ${BROTLI_LIBRARIES_CORE}
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ )
+
+ install(
+ TARGETS ${BROTLI_LIBRARIES_CORE_STATIC}
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ )
+
+ install(
+ DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ )
+endif() # BROTLI_BUNDLED_MODE
+endif() # BROTLI_EMSCRIPTEN
+
+# Tests
+
+# If we're targeting Windows but not running on Windows, we need Wine
+# to run the tests...
+if(NOT BROTLI_DISABLE_TESTS)
+ if(WIN32 AND NOT CMAKE_HOST_WIN32)
+ find_program(BROTLI_WRAPPER NAMES wine)
+
+ if(NOT BROTLI_WRAPPER)
+ message(STATUS "wine not found, disabling tests")
+ set(BROTLI_DISABLE_TESTS TRUE)
+ endif()
+ endif()
+endif()
+
+# If our compiler is a cross-compiler that we know about (arm/aarch64),
+# then we need to use qemu to execute the tests.
+if(NOT BROTLI_DISABLE_TESTS)
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabihf-.*$")
+ message(STATUS "Detected arm-linux-gnueabihf cross-compilation")
+ set(BROTLI_WRAPPER "qemu-arm")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabihf")
+ endif()
+
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabi-.*$")
+ message(STATUS "Detected arm-linux-gnueabi cross-compilation")
+ set(BROTLI_WRAPPER "qemu-arm")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabi")
+ endif()
+
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/aarch64-linux-gnu-.*$")
+ message(STATUS "Detected aarch64-linux-gnu cross-compilation")
+ set(BROTLI_WRAPPER "qemu-aarch64")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/aarch64-linux-gnu")
+ endif()
+endif()
+
+if(NOT BROTLI_DISABLE_TESTS)
+ include(CTest)
+ enable_testing()
+
+ set(ROUNDTRIP_INPUTS
+ tests/testdata/alice29.txt
+ tests/testdata/asyoulik.txt
+ tests/testdata/lcet10.txt
+ tests/testdata/plrabn12.txt
+ c/enc/encode.c
+ c/common/dictionary.h
+ c/dec/decode.c)
+
+ foreach(INPUT ${ROUNDTRIP_INPUTS})
+ get_filename_component(OUTPUT_NAME "${INPUT}" NAME)
+
+ set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}")
+ set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
+
+ foreach(quality 1 6 9 11)
+ add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
+ COMMAND "${CMAKE_COMMAND}"
+ -DBROTLI_WRAPPER=${BROTLI_WRAPPER}
+ -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
+ -DBROTLI_CLI=$<TARGET_FILE:brotli>
+ -DQUALITY=${quality}
+ -DINPUT=${INPUT_FILE}
+ -DOUTPUT=${OUTPUT_FILE}.${quality}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake)
+ endforeach()
+ endforeach()
+
+ file(GLOB_RECURSE
+ COMPATIBILITY_INPUTS
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ tests/testdata/*.compressed*)
+
+ foreach(INPUT ${COMPATIBILITY_INPUTS})
+ add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
+ COMMAND "${CMAKE_COMMAND}"
+ -DBROTLI_WRAPPER=${BROTLI_WRAPPER}
+ -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
+ -DBROTLI_CLI=$<TARGET_FILE:brotli>
+ -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
+ endforeach()
+endif()
+
+# Generate a pkg-config files
+
+function(generate_pkg_config_path outvar path)
+ string(LENGTH "${path}" path_length)
+
+ set(path_args ${ARGV})
+ list(REMOVE_AT path_args 0 1)
+ list(LENGTH path_args path_args_remaining)
+
+ set("${outvar}" "${path}")
+
+ while(path_args_remaining GREATER 1)
+ list(GET path_args 0 name)
+ list(GET path_args 1 value)
+
+ get_filename_component(value_full "${value}" ABSOLUTE)
+ string(LENGTH "${value}" value_length)
+
+ if(path_length EQUAL value_length AND path STREQUAL value)
+ set("${outvar}" "\${${name}}")
+ break()
+ elseif(path_length GREATER value_length)
+ # We might be in a subdirectory of the value, but we have to be
+ # careful about a prefix matching but not being a subdirectory
+ # (for example, /usr/lib64 is not a subdirectory of /usr/lib).
+ # We'll do this by making sure the next character is a directory
+ # separator.
+ string(SUBSTRING "${path}" ${value_length} 1 sep)
+ if(sep STREQUAL "/")
+ string(SUBSTRING "${path}" 0 ${value_length} s)
+ if(s STREQUAL value)
+ string(SUBSTRING "${path}" "${value_length}" -1 suffix)
+ set("${outvar}" "\${${name}}${suffix}")
+ break()
+ endif()
+ endif()
+ endif()
+
+ list(REMOVE_AT path_args 0 1)
+ list(LENGTH path_args path_args_remaining)
+ endwhile()
+
+ set("${outvar}" "${${outvar}}" PARENT_SCOPE)
+endfunction(generate_pkg_config_path)
+
+function(transform_pc_file INPUT_FILE OUTPUT_FILE VERSION)
+ file(READ ${INPUT_FILE} TEXT)
+
+ set(PREFIX "${CMAKE_INSTALL_PREFIX}")
+ string(REGEX REPLACE "@prefix@" "${PREFIX}" TEXT ${TEXT})
+ string(REGEX REPLACE "@exec_prefix@" "${PREFIX}" TEXT ${TEXT})
+
+ generate_pkg_config_path(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" prefix "${PREFIX}")
+ string(REGEX REPLACE "@libdir@" "${LIBDIR}" TEXT ${TEXT})
+
+ generate_pkg_config_path(INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}" prefix "${PREFIX}")
+ string(REGEX REPLACE "@includedir@" "${INCLUDEDIR}" TEXT ${TEXT})
+
+ string(REGEX REPLACE "@PACKAGE_VERSION@" "${VERSION}" TEXT ${TEXT})
+
+ file(WRITE ${OUTPUT_FILE} ${TEXT})
+endfunction()
+
+transform_pc_file("scripts/libbrotlicommon.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc" "${BROTLI_VERSION}")
+
+transform_pc_file("scripts/libbrotlidec.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc" "${BROTLI_VERSION}")
+
+transform_pc_file("scripts/libbrotlienc.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" "${BROTLI_VERSION}")
+
+if(NOT BROTLI_EMSCRIPTEN)
+if(NOT BROTLI_BUNDLED_MODE)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif() # BROTLI_BUNDLED_MODE
+endif() # BROTLI_EMSCRIPTEN
+
+if (ENABLE_COVERAGE STREQUAL "yes")
+ SETUP_TARGET_FOR_COVERAGE(coverage test coverage)
+endif ()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CONTRIBUTING.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CONTRIBUTING.md
new file mode 100644
index 000000000..a00e37d17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/CONTRIBUTING.md
@@ -0,0 +1,27 @@
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement]
+(https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the [Software Grant and Corporate Contributor License Agreement]
+(https://cla.developers.google.com/about/google-corporate).
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/LICENSE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/LICENSE
new file mode 100644
index 000000000..33b7cdd2d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/MANIFEST.in b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/MANIFEST.in
new file mode 100644
index 000000000..b7b8e7244
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/MANIFEST.in
@@ -0,0 +1,17 @@
+include CONTRIBUTING.md
+include c/common/*.c
+include c/common/*.h
+include c/dec/*.c
+include c/dec/*.h
+include c/enc/*.c
+include c/enc/*.h
+include c/include/brotli/*.h
+include LICENSE
+include MANIFEST.in
+include python/_brotli.cc
+include python/bro.py
+include python/brotli.py
+include python/README.md
+include README.md
+include setup.py
+include c/tools/brotli.c
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile
new file mode 100644
index 000000000..489094090
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile
@@ -0,0 +1,55 @@
+OS := $(shell uname)
+LIBSOURCES = $(wildcard c/common/*.c) $(wildcard c/dec/*.c) \
+ $(wildcard c/enc/*.c)
+SOURCES = $(LIBSOURCES) c/tools/brotli.c
+BINDIR = bin
+OBJDIR = $(BINDIR)/obj
+LIBOBJECTS = $(addprefix $(OBJDIR)/, $(LIBSOURCES:.c=.o))
+OBJECTS = $(addprefix $(OBJDIR)/, $(SOURCES:.c=.o))
+LIB_A = libbrotli.a
+EXECUTABLE = brotli
+DIRS = $(OBJDIR)/c/common $(OBJDIR)/c/dec $(OBJDIR)/c/enc \
+ $(OBJDIR)/c/tools $(BINDIR)/tmp
+CFLAGS += -O2
+ifeq ($(os), Darwin)
+ CPPFLAGS += -DOS_MACOSX
+endif
+
+ifneq ($(strip $(CROSS_COMPILE)), )
+ CC=$(CROSS_COMPILE)-gcc
+ ARCH=$(firstword $(subst -, ,$(CROSS_COMPILE)))
+ BROTLI_WRAPPER="qemu-$(ARCH) -L /usr/$(CROSS_COMPILE)"
+endif
+
+# The arm-linux-gnueabi compiler defaults to Armv5. Since we only support Armv7
+# and beyond, we need to select Armv7 explicitly with march.
+ifeq ($(ARCH), arm)
+ CFLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon
+endif
+
+all: test
+ @:
+
+.PHONY: all clean test
+
+$(DIRS):
+ mkdir -p $@
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -lm -o $(BINDIR)/$(EXECUTABLE)
+
+lib: $(LIBOBJECTS)
+ rm -f $(LIB_A)
+ ar -crs $(LIB_A) $(LIBOBJECTS)
+
+test: $(EXECUTABLE)
+ tests/compatibility_test.sh $(BROTLI_WRAPPER)
+ tests/roundtrip_test.sh $(BROTLI_WRAPPER)
+
+clean:
+ rm -rf $(BINDIR) $(LIB_A)
+
+.SECONDEXPANSION:
+$(OBJECTS): $$(patsubst %.o,%.c,$$(patsubst $$(OBJDIR)/%,%,$$@)) | $(DIRS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) -Ic/include \
+ -c $(patsubst %.o,%.c,$(patsubst $(OBJDIR)/%,%,$@)) -o $@
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile.am b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile.am
new file mode 100644
index 000000000..ace7a8506
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/Makefile.am
@@ -0,0 +1,38 @@
+AUTOMAKE_OPTIONS = foreign nostdinc subdir-objects
+
+ACLOCAL_AMFLAGS = -I m4
+
+# Actual ABI version is substituted by bootstrap
+LIBBROTLI_VERSION_INFO = -version-info 0:0:0
+
+bin_PROGRAMS = brotli
+lib_LTLIBRARIES = libbrotlicommon.la libbrotlidec.la libbrotlienc.la
+
+include scripts/sources.lst
+
+brotliincludedir = $(includedir)/brotli
+brotliinclude_HEADERS = $(BROTLI_INCLUDE)
+
+AM_CFLAGS = -I$(top_srcdir)/c/include
+
+brotli_SOURCES = $(BROTLI_CLI_C)
+brotli_LDADD = libbrotlidec.la libbrotlienc.la libbrotlicommon.la -lm
+#brotli_LDFLAGS = -static
+
+libbrotlicommon_la_SOURCES = $(BROTLI_COMMON_C) $(BROTLI_COMMON_H)
+libbrotlicommon_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
+libbrotlidec_la_SOURCES = $(BROTLI_DEC_C) $(BROTLI_DEC_H)
+libbrotlidec_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
+libbrotlidec_la_LIBADD = libbrotlicommon.la -lm
+libbrotlienc_la_SOURCES = $(BROTLI_ENC_C) $(BROTLI_ENC_H)
+libbrotlienc_la_LDFLAGS = $(AM_LDFLAGS) $(LIBBROTLI_VERSION_INFO) $(LDFLAGS)
+libbrotlienc_la_LIBADD = libbrotlicommon.la -lm
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = \
+ scripts/libbrotlicommon.pc \
+ scripts/libbrotlidec.pc \
+ scripts/libbrotlienc.pc
+pkgincludedir= $(brotliincludedir)
+
+dist_doc_DATA = README
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README
new file mode 100644
index 000000000..dea729130
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README
@@ -0,0 +1,15 @@
+BROTLI DATA COMPRESSION LIBRARY
+
+Brotli is a generic-purpose lossless compression algorithm that compresses data
+using a combination of a modern variant of the LZ77 algorithm, Huffman coding
+and 2nd order context modeling, with a compression ratio comparable to the best
+currently available general-purpose compression methods. It is similar in speed
+with deflate but offers more dense compression.
+
+The specification of the Brotli Compressed Data Format is defined in RFC 7932
+https://tools.ietf.org/html/rfc7932
+
+Brotli is open-sourced under the MIT License, see the LICENSE file.
+
+Brotli mailing list:
+https://groups.google.com/forum/#!forum/brotli
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README.md
new file mode 100644
index 000000000..017173c4e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/README.md
@@ -0,0 +1,98 @@
+<p align="center"><img src="https://brotli.org/brotli.svg" alt="Brotli" width="64"></p>
+
+### Introduction
+
+Brotli is a generic-purpose lossless compression algorithm that compresses data
+using a combination of a modern variant of the LZ77 algorithm, Huffman coding
+and 2nd order context modeling, with a compression ratio comparable to the best
+currently available general-purpose compression methods. It is similar in speed
+with deflate but offers more dense compression.
+
+The specification of the Brotli Compressed Data Format is defined in [RFC 7932](https://tools.ietf.org/html/rfc7932).
+
+Brotli is open-sourced under the MIT License, see the LICENSE file.
+
+Brotli mailing list:
+https://groups.google.com/forum/#!forum/brotli
+
+[![TravisCI Build Status](https://travis-ci.org/google/brotli.svg?branch=master)](https://travis-ci.org/google/brotli)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/google/brotli?branch=master&svg=true)](https://ci.appveyor.com/project/szabadka/brotli)
+[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/brotli.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#brotli)
+
+### Build instructions
+
+#### Vcpkg
+
+You can download and install brotli using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
+
+ git clone https://github.com/Microsoft/vcpkg.git
+ cd vcpkg
+ ./bootstrap-vcpkg.sh
+ ./vcpkg integrate install
+ vcpkg install brotli
+
+The brotli port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
+
+#### Autotools-style CMake
+
+[configure-cmake](https://github.com/nemequ/configure-cmake) is an
+autotools-style configure script for CMake-based projects (not supported on Windows).
+
+The basic commands to build, test and install brotli are:
+
+ $ mkdir out && cd out
+ $ ../configure-cmake
+ $ make
+ $ make test
+ $ make install
+
+By default, debug binaries are built. To generate "release" `Makefile` specify `--disable-debug` option to `configure-cmake`.
+
+#### Bazel
+
+See [Bazel](http://www.bazel.build/)
+
+#### CMake
+
+The basic commands to build and install brotli are:
+
+ $ mkdir out && cd out
+ $ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed ..
+ $ cmake --build . --config Release --target install
+
+You can use other [CMake](https://cmake.org/) configuration.
+
+#### Premake5
+
+See [Premake5](https://premake.github.io/)
+
+#### Python
+
+To install the latest release of the Python module, run the following:
+
+ $ pip install brotli
+
+To install the tip-of-the-tree version, run:
+
+ $ pip install --upgrade git+https://github.com/google/brotli
+
+See the [Python readme](python/README.md) for more details on installing
+from source, development, and testing.
+
+### Benchmarks
+* [Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/) / [Unstable Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/unstable/)
+* [Large Text Compression Benchmark](http://mattmahoney.net/dc/text.html)
+* [Lzturbo Benchmark](https://sites.google.com/site/powturbo/home/benchmark)
+
+### Related projects
+> **Disclaimer:** Brotli authors take no responsibility for the third party projects mentioned in this section.
+
+Independent [decoder](https://github.com/madler/brotli) implementation by Mark Adler, based entirely on format specification.
+
+JavaScript port of brotli [decoder](https://github.com/devongovett/brotli.js). Could be used directly via `npm install brotli`
+
+Hand ported [decoder / encoder](https://github.com/dominikhlbg/BrotliHaxe) in haxe by Dominik Homberger. Output source code: JavaScript, PHP, Python, Java and C#
+
+7Zip [plugin](https://github.com/mcmilk/7-Zip-Zstd)
+
+Dart [native bindings](https://github.com/thosakwe/brotli)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/WORKSPACE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/WORKSPACE
new file mode 100644
index 000000000..75f376828
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/WORKSPACE
@@ -0,0 +1,21 @@
+workspace(name = "org_brotli")
+
+local_repository(
+ name = "ignore_org_brotli_go",
+ path = "go",
+)
+
+local_repository(
+ name = "ignore_org_brotli_java",
+ path = "java",
+)
+
+local_repository(
+ name = "ignore_org_brotli_js",
+ path = "js",
+)
+
+local_repository(
+ name = "ignore_org_brotli_research",
+ path = "research",
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/bootstrap b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/bootstrap
new file mode 100755
index 000000000..64aca2c40
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/bootstrap
@@ -0,0 +1,31 @@
+# !/bin/sh -e
+
+REQUIRED='is required, but not installed.'
+bc -v >/dev/null 2>&1 || { echo >&2 "'bc' $REQUIRED"; exit 1; }
+if [ `uname -s` != "FreeBSD" ]; then
+sed --version >/dev/null 2>&1 || { echo >&2 "'sed' $REQUIRED"; exit 1; }
+fi
+autoreconf --version >/dev/null 2>&1 || { echo >&2 "'autoconf' $REQUIRED"; exit 1; }
+
+# If libtool is not installed -> "error: Libtool library used but 'LIBTOOL' is undefined"
+
+mkdir m4 2>/dev/null
+
+BROTLI_ABI_HEX=`sed -n 's/#define BROTLI_ABI_VERSION 0x//p' c/common/version.h`
+BROTLI_ABI_INT=`echo "ibase=16;$BROTLI_ABI_HEX" | bc`
+BROTLI_ABI_CURRENT=`expr $BROTLI_ABI_INT / 16777216`
+BROTLI_ABI_REVISION=`expr $BROTLI_ABI_INT / 4096 % 4096`
+BROTLI_ABI_AGE=`expr $BROTLI_ABI_INT % 4096`
+BROTLI_ABI_INFO="$BROTLI_ABI_CURRENT:$BROTLI_ABI_REVISION:$BROTLI_ABI_AGE"
+
+BROTLI_VERSION_HEX=`sed -n 's/#define BROTLI_VERSION 0x//p' c/common/version.h`
+BROTLI_VERSION_INT=`echo "ibase=16;$BROTLI_VERSION_HEX" | bc`
+BROTLI_VERSION_MAJOR=`expr $BROTLI_VERSION_INT / 16777216`
+BROTLI_VERSION_MINOR=`expr $BROTLI_VERSION_INT / 4096 % 4096`
+BROTLI_VERSION_PATCH=`expr $BROTLI_VERSION_INT % 4096`
+BROTLI_VERSION="$BROTLI_VERSION_MAJOR.$BROTLI_VERSION_MINOR.$BROTLI_VERSION_PATCH"
+
+sed -i.bak -r "s/[0-9]+:[0-9]+:[0-9]+/$BROTLI_ABI_INFO/" Makefile.am
+sed -i.bak -r "s/\[[0-9]+\.[0-9]+\.[0-9]+\]/[$BROTLI_VERSION]/" configure.ac
+
+autoreconf --install --force --symlink || exit $
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/constants.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/constants.h
new file mode 100644
index 000000000..f6e44dc7b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/constants.h
@@ -0,0 +1,184 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/**
+ * @file
+ * Common constants used in decoder and encoder API.
+ */
+
+#ifndef BROTLI_COMMON_CONSTANTS_H_
+#define BROTLI_COMMON_CONSTANTS_H_
+
+#include "./platform.h"
+#include <brotli/types.h>
+
+/* Specification: 7.3. Encoding of the context map */
+#define BROTLI_CONTEXT_MAP_MAX_RLE 16
+
+/* Specification: 2. Compressed representation overview */
+#define BROTLI_MAX_NUMBER_OF_BLOCK_TYPES 256
+
+/* Specification: 3.3. Alphabet sizes: insert-and-copy length */
+#define BROTLI_NUM_LITERAL_SYMBOLS 256
+#define BROTLI_NUM_COMMAND_SYMBOLS 704
+#define BROTLI_NUM_BLOCK_LEN_SYMBOLS 26
+#define BROTLI_MAX_CONTEXT_MAP_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + \
+ BROTLI_CONTEXT_MAP_MAX_RLE)
+#define BROTLI_MAX_BLOCK_TYPE_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 2)
+
+/* Specification: 3.5. Complex prefix codes */
+#define BROTLI_REPEAT_PREVIOUS_CODE_LENGTH 16
+#define BROTLI_REPEAT_ZERO_CODE_LENGTH 17
+#define BROTLI_CODE_LENGTH_CODES (BROTLI_REPEAT_ZERO_CODE_LENGTH + 1)
+/* "code length of 8 is repeated" */
+#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
+
+/* "Large Window Brotli" */
+
+/**
+ * The theoretical maximum number of distance bits specified for large window
+ * brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
+ * encoders and decoders only support up to 30 max distance bits, the value is
+ * set to 62 because it affects the large window brotli file format.
+ * Specifically, it affects the encoding of simple huffman tree for distances,
+ * see Specification RFC 7932 chapter 3.4.
+ */
+#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
+#define BROTLI_LARGE_MIN_WBITS 10
+/**
+ * The maximum supported large brotli window bits by the encoder and decoder.
+ * Large window brotli allows up to 62 bits, however the current encoder and
+ * decoder, designed for 32-bit integers, only support up to 30 bits maximum.
+ */
+#define BROTLI_LARGE_MAX_WBITS 30
+
+/* Specification: 4. Encoding of distances */
+#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
+/**
+ * Maximal number of "postfix" bits.
+ *
+ * Number of "postfix" bits is stored as 2 bits in meta-block header.
+ */
+#define BROTLI_MAX_NPOSTFIX 3
+#define BROTLI_MAX_NDIRECT 120
+#define BROTLI_MAX_DISTANCE_BITS 24U
+#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \
+ BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \
+ ((MAXNBITS) << ((NPOSTFIX) + 1)))
+/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */
+#define BROTLI_NUM_DISTANCE_SYMBOLS \
+ BROTLI_DISTANCE_ALPHABET_SIZE( \
+ BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
+
+/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
+ brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
+ NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
+#define BROTLI_MAX_DISTANCE 0x3FFFFFC
+
+/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
+ allows safe distance calculation without overflows, given the distance
+ alphabet size is limited to corresponding size
+ (see kLargeWindowDistanceCodeLimits). */
+#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
+
+/* 7.1. Context modes and context ID lookup for literals */
+/* "context IDs for literals are in the range of 0..63" */
+#define BROTLI_LITERAL_CONTEXT_BITS 6
+
+/* 7.2. Context ID for distances */
+#define BROTLI_DISTANCE_CONTEXT_BITS 2
+
+/* 9.1. Format of the Stream Header */
+/* Number of slack bytes for window size. Don't confuse
+ with BROTLI_NUM_DISTANCE_SHORT_CODES. */
+#define BROTLI_WINDOW_GAP 16
+#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
+
+typedef struct BrotliDistanceCodeLimit {
+ uint32_t max_alphabet_size;
+ uint32_t max_distance;
+} BrotliDistanceCodeLimit;
+
+/* This function calculates maximal size of distance alphabet, such that the
+ distances greater than the given values can not be represented.
+
+ This limits are designed to support fast and safe 32-bit decoders.
+ "32-bit" means that signed integer values up to ((1 << 31) - 1) could be
+ safely expressed.
+
+ Brotli distance alphabet symbols do not represent consecutive distance
+ ranges. Each distance alphabet symbol (excluding direct distances and short
+ codes), represent interleaved (for NPOSTFIX > 0) range of distances.
+ A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
+ range. Two consecutive groups require the same amount of "extra bits".
+
+ It is important that distance alphabet represents complete "groups".
+ To avoid complex logic on encoder side about interleaved ranges
+ it was decided to restrict both sides to complete distance code "groups".
+ */
+BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
+ uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
+ BrotliDistanceCodeLimit result;
+ /* Marking this function as unused, because not all files
+ including "constants.h" use it -> compiler warns about that. */
+ BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
+ if (max_distance <= ndirect) {
+ /* This case never happens / exists only for the sake of completeness. */
+ result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
+ result.max_distance = max_distance;
+ return result;
+ } else {
+ /* The first prohibited value. */
+ uint32_t forbidden_distance = max_distance + 1;
+ /* Subtract "directly" encoded region. */
+ uint32_t offset = forbidden_distance - ndirect - 1;
+ uint32_t ndistbits = 0;
+ uint32_t tmp;
+ uint32_t half;
+ uint32_t group;
+ /* Postfix for the last dcode in the group. */
+ uint32_t postfix = (1u << npostfix) - 1;
+ uint32_t extra;
+ uint32_t start;
+ /* Remove postfix and "head-start". */
+ offset = (offset >> npostfix) + 4;
+ /* Calculate the number of distance bits. */
+ tmp = offset / 2;
+ /* Poor-man's log2floor, to avoid extra dependencies. */
+ while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
+ /* One bit is covered with subrange addressing ("half"). */
+ ndistbits--;
+ /* Find subrange. */
+ half = (offset >> ndistbits) & 1;
+ /* Calculate the "group" part of dcode. */
+ group = ((ndistbits - 1) << 1) | half;
+ /* Calculated "group" covers the prohibited distance value. */
+ if (group == 0) {
+ /* This case is added for correctness; does not occur for limit > 128. */
+ result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
+ result.max_distance = ndirect;
+ return result;
+ }
+ /* Decrement "group", so it is the last permitted "group". */
+ group--;
+ /* After group was decremented, ndistbits and half must be recalculated. */
+ ndistbits = (group >> 1) + 1;
+ /* The last available distance in the subrange has all extra bits set. */
+ extra = (1u << ndistbits) - 1;
+ /* Calculate region start. NB: ndistbits >= 1. */
+ start = (1u << (ndistbits + 1)) - 4;
+ /* Move to subregion. */
+ start += (group & 1) << ndistbits;
+ /* Calculate the alphabet size. */
+ result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
+ BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
+ /* Calculate the maximal distance representable by alphabet. */
+ result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
+ return result;
+ }
+}
+
+#endif /* BROTLI_COMMON_CONSTANTS_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/context.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/context.h
new file mode 100755
index 000000000..24b3eb48f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/context.h
@@ -0,0 +1,261 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Lookup table to map the previous two bytes to a context id.
+
+ There are four different context modeling modes defined here:
+ CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
+ CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
+ CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
+ CONTEXT_SIGNED: second-order context model tuned for signed integers.
+
+ If |p1| and |p2| are the previous two bytes, and |mode| is current context
+ mode, we calculate the context as:
+
+ context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
+
+ For CONTEXT_UTF8 mode, if the previous two bytes are ASCII characters
+ (i.e. < 128), this will be equivalent to
+
+ context = 4 * context1(p1) + context2(p2),
+
+ where context1 is based on the previous byte in the following way:
+
+ 0 : non-ASCII control
+ 1 : \t, \n, \r
+ 2 : space
+ 3 : other punctuation
+ 4 : " '
+ 5 : %
+ 6 : ( < [ {
+ 7 : ) > ] }
+ 8 : , ; :
+ 9 : .
+ 10 : =
+ 11 : number
+ 12 : upper-case vowel
+ 13 : upper-case consonant
+ 14 : lower-case vowel
+ 15 : lower-case consonant
+
+ and context2 is based on the second last byte:
+
+ 0 : control, space
+ 1 : punctuation
+ 2 : upper-case letter, number
+ 3 : lower-case letter
+
+ If the last byte is ASCII, and the second last byte is not (in a valid UTF8
+ stream it will be a continuation byte, value between 128 and 191), the
+ context is the same as if the second last byte was an ASCII control or space.
+
+ If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
+ be a continuation byte and the context id is 2 or 3 depending on the LSB of
+ the last byte and to a lesser extent on the second last byte if it is ASCII.
+
+ If the last byte is a UTF8 continuation byte, the second last byte can be:
+ - continuation byte: the next byte is probably ASCII or lead byte (assuming
+ 4-byte UTF8 characters are rare) and the context id is 0 or 1.
+ - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
+ - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
+
+ The possible value combinations of the previous two bytes, the range of
+ context ids and the type of the next byte is summarized in the table below:
+
+ |--------\-----------------------------------------------------------------|
+ | \ Last byte |
+ | Second \---------------------------------------------------------------|
+ | last byte \ ASCII | cont. byte | lead byte |
+ | \ (0-127) | (128-191) | (192-) |
+ |=============|===================|=====================|==================|
+ | ASCII | next: ASCII/lead | not valid | next: cont. |
+ | (0-127) | context: 4 - 63 | | context: 2 - 3 |
+ |-------------|-------------------|---------------------|------------------|
+ | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
+ | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
+ |-------------|-------------------|---------------------|------------------|
+ | lead byte | not valid | next: ASCII/lead | not valid |
+ | (192-207) | | context: 0 - 1 | |
+ |-------------|-------------------|---------------------|------------------|
+ | lead byte | not valid | next: cont. | not valid |
+ | (208-) | | context: 2 - 3 | |
+ |-------------|-------------------|---------------------|------------------|
+*/
+
+#ifndef BROTLI_COMMON_CONTEXT_H_
+#define BROTLI_COMMON_CONTEXT_H_
+
+#include <brotli/types.h>
+
+typedef enum ContextType {
+ CONTEXT_LSB6 = 0,
+ CONTEXT_MSB6 = 1,
+ CONTEXT_UTF8 = 2,
+ CONTEXT_SIGNED = 3
+} ContextType;
+
+/* Common context lookup table for all context modes. */
+static const uint8_t kContextLookup[2048] = {
+ /* CONTEXT_LSB6, last byte. */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+
+ /* CONTEXT_LSB6, second last byte, */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* CONTEXT_MSB6, last byte. */
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+ 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+ 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+ 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
+ 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
+ 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
+ 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
+
+ /* CONTEXT_MSB6, second last byte, */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* CONTEXT_UTF8, last byte. */
+ /* ASCII range. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
+ 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
+ 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
+ 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
+ 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
+ /* UTF8 continuation byte range. */
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ /* UTF8 lead byte range. */
+ 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+ 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+
+ /* CONTEXT_UTF8 second last byte. */
+ /* ASCII range. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
+ /* UTF8 continuation byte range. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* UTF8 lead byte range. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+
+ /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
+ 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
+
+ /* CONTEXT_SIGNED, second last byte. */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+};
+
+typedef const uint8_t* ContextLut;
+
+/* typeof(MODE) == ContextType; returns ContextLut */
+#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
+
+/* typeof(LUT) == ContextLut */
+#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
+
+#endif /* BROTLI_COMMON_CONTEXT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.bin b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.bin
new file mode 100644
index 000000000..a585c0e29
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.bin
@@ -0,0 +1,432 @@
+timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid="sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$("#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS"agedgreyGET"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:å*/
+ 100hall.
+
+A7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,
+
+coolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px''););">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarm’sboys[0].');"POSTbearkids);}}marytend(UK)quadzh:æ-siz----prop'); liftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene —softrometillross<h3>pourfadepink<tr>mini)|!(minezh:èbarshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json', 'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:ä'));puremageparatonebond:37Z_of_']);000,zh:çtankyardbowlbush:56ZJava30px
+|}
+%C3%:34ZjeffEXPIcashvisagolfsnowzh:équer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;
+}
+exit:35Zvarsbeat'});diet999;anne}}</[i].Langkm²wiretoysaddssealalex;
+ }echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}
+dustclip).
+
+70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}
+HEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-
+!002)ndow[1];[];
+Log salt
+ bangtrimbath){
+00px
+});ko:ìfeesad> s:// [];tollplug(){
+{
+ .js'200pdualboat.JPG);
+}quot);
+
+');
+
+} 201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomásesteestaperotodohacecadaañobiendíaasívidacasootroforosolootracualdijosidograntipotemadebealgoquéestonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiзанаомрарутанепоотизнодотожеонихÐаеебымыВыÑовывоÐообПолиниРФÐеМытыОнимдаЗаДаÐуОбтеИзейнуммТыужÙيأنمامعكلأوردياÙىهولملكاولهبسالإنهيأيقدهلثمبهلوليبلايبكشيامأمنتبيلنحبهممشوشfirstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue"crossspentblogsbox">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow">genretrucklooksValueFrame.net/-->
+<try {
+var makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top">
+<!--POST"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url="parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();" Blocklinuxjonespixel');">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar">.src=toweralt="cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});
+bandsqueue= {};80px;cking{
+ aheadclockirishlike ratiostatsForm"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg"spainbeachtaxesmicroangel--></giftssteve-linkbody.});
+ mount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:ã‚simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/"1.jpgwmodeparamSTARTleft idden, 201);
+}
+form.viruschairtransworstPagesitionpatch<!--
+o-cacfirmstours,000 asiani++){adobe')[0]id=10both;menu .2.mi.png"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120" sweettr>
+name=diegopage swiss-->
+
+#fff;">Log.com"treatsheet) && 14px;sleepntentfiledja:ãƒid="cName"worseshots-box-delta
+&lt;bears:48Z<data-rural</a> spendbakershops= "";php">ction13px;brianhellosize=o=%2F joinmaybe<img img">, fjsimg" ")[0]MTopBType"newlyDanskczechtrailknows</h5>faq">zh-cn10);
+-1");type=bluestrulydavis.js';>
+<!steel you h2>
+form jesus100% menu.
+
+walesrisksumentddingb-likteachgif" vegasdanskeestishqipsuomisobredesdeentretodospuedeañosestátienehastaotrospartedondenuevohacerformamismomejormundoaquídíassóloayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaísnuevasaludforosmedioquienmesespoderchileserávecesdecirjoséestarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocómoenerojuegoperúhaberestoynuncamujervalorfueralibrogustaigualvotoscasosguíapuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleónplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenáreadiscopedrocercapuedapapelmenorútilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniñoquedapasarbancohijosviajepabloéstevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallíjovendichaestantalessalirsuelopesosfinesllamabuscoéstalleganegroplazahumorpagarjuntadobleislasbolsabañohablaluchaÃreadicenjugarnotasvalleallácargadolorabajoestégustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother" id="marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo" bottomlist">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename="amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.
+
+Onejoinedmenu">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo">beyond-scaleacceptservedmarineFootercamera</h1>
+_form"leavesstress" />
+.gif" onloadloaderOxfordsistersurvivlistenfemaleDesignsize="appealtext">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main">inlinesundaywrap">failedcensusminutebeaconquotes150px|estateremoteemail"linkedright;signalformal1.htmlsignupprincefloat:.png" forum.AccesspaperssoundsextendHeightsliderUTF-8"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome">headerensurebranchpiecesblock;statedtop"><racingresize--&gt;pacitysexualbureau.jpg" 10,000obtaintitlesamount, Inc.comedymenu" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline">body">
+* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox">
+System DavidcancertablesprovedApril reallydriveritem">more">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php" assumelayerswilsonstoresreliefswedenCustomeasily your String
+
+Whiltaylorclear:resortfrenchthough") + "<body>buyingbrandsMembername">oppingsector5px;">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink">Images=falsewhile hspace0&amp;
+
+In powerPolski-colorjordanBottomStart -count2.htmlnews">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml" rights.html-blockregExp:hoverwithinvirginphones</tr> using
+ var >');
+ </td>
+</tr>
+bahasabrasilgalegomagyarpolskisrpskiردو中文简体ç¹é«”ä¿¡æ¯ä¸­å›½æˆ‘们一个公å¸ç®¡ç†è®ºå›å¯ä»¥æœåŠ¡æ—¶é—´ä¸ªäººäº§å“自己ä¼ä¸šæŸ¥çœ‹å·¥ä½œè”系没有网站所有评论中心文章用户首页作者技术问题相关下载æœç´¢ä½¿ç”¨è½¯ä»¶åœ¨çº¿ä¸»é¢˜èµ„料视频回å¤æ³¨å†Œç½‘络收è—内容推è市场消æ¯ç©ºé—´å‘布什么好å‹ç”Ÿæ´»å›¾ç‰‡å‘展如果手机新闻最新方å¼åŒ—京æ供关于更多这个系统知é“游æˆå¹¿å‘Šå…¶ä»–å‘表安全第一会员进行点击版æƒç”µå­ä¸–界设计å…费教育加入活动他们商å“åšå®¢çŽ°åœ¨ä¸Šæµ·å¦‚何已ç»ç•™è¨€è¯¦ç»†ç¤¾åŒºç™»å½•æœ¬ç«™éœ€è¦ä»·æ ¼æ”¯æŒå›½é™…链接国家建设朋å‹é˜…读法律ä½ç½®ç»æµŽé€‰æ‹©è¿™æ ·å½“å‰åˆ†ç±»æŽ’行因为交易最åŽéŸ³ä¹ä¸èƒ½é€šè¿‡è¡Œä¸šç§‘技å¯èƒ½è®¾å¤‡åˆä½œå¤§å®¶ç¤¾ä¼šç ”究专业全部项目这里还是开始情况电脑文件å“牌帮助文化资æºå¤§å­¦å­¦ä¹ åœ°å€æµè§ˆæŠ•èµ„工程è¦æ±‚怎么时候功能主è¦ç›®å‰èµ„讯城市方法电影招è˜å£°æ˜Žä»»ä½•å¥åº·æ•°æ®ç¾Žå›½æ±½è½¦ä»‹ç»ä½†æ˜¯äº¤æµç”Ÿäº§æ‰€ä»¥ç”µè¯æ˜¾ç¤ºä¸€äº›å•ä½äººå‘˜åˆ†æžåœ°å›¾æ—…游工具学生系列网å‹å¸–å­å¯†ç é¢‘é“控制地区基本全国网上é‡è¦ç¬¬äºŒå–œæ¬¢è¿›å…¥å‹æƒ…这些考试å‘现培训以上政府æˆä¸ºçŽ¯å¢ƒé¦™æ¸¯åŒæ—¶å¨±ä¹å‘é€ä¸€å®šå¼€å‘作å“标准欢迎解决地方一下以åŠè´£ä»»æˆ–者客户代表积分女人数ç é”€å”®å‡ºçŽ°ç¦»çº¿åº”用列表ä¸åŒç¼–辑统计查询ä¸è¦æœ‰å…³æœºæž„很多播放组织政策直接能力æ¥æºæ™‚間看到热门关键专区éžå¸¸è‹±è¯­ç™¾åº¦å¸Œæœ›ç¾Žå¥³æ¯”较知识规定建议部门æ„è§ç²¾å½©æ—¥æœ¬æ高å‘言方é¢åŸºé‡‘处ç†æƒé™å½±ç‰‡é“¶è¡Œè¿˜æœ‰åˆ†äº«ç‰©å“ç»è¥æ·»åŠ ä¸“家这ç§è¯é¢˜èµ·æ¥ä¸šåŠ¡å…¬å‘Šè®°å½•ç®€ä»‹è´¨é‡ç”·äººå½±å“引用报告部分快速咨询时尚注æ„申请学校应该历å²åªæ˜¯è¿”回购买å称为了æˆåŠŸè¯´æ˜Žä¾›åº”å­©å­ä¸“题程åºä¸€èˆ¬æœƒå“¡åªæœ‰å…¶å®ƒä¿æŠ¤è€Œä¸”今天窗å£åŠ¨æ€çŠ¶æ€ç‰¹åˆ«è®¤ä¸ºå¿…须更新å°è¯´æˆ‘們作为媒体包括那么一样国内是å¦æ ¹æ®ç”µè§†å­¦é™¢å…·æœ‰è¿‡ç¨‹ç”±äºŽäººæ‰å‡ºæ¥ä¸è¿‡æ­£åœ¨æ˜Žæ˜Ÿæ•…事关系标题商务输入一直基础教学了解建筑结果全çƒé€šçŸ¥è®¡åˆ’对于艺术相册å‘生真的建立等级类型ç»éªŒå®žçŽ°åˆ¶ä½œæ¥è‡ªæ ‡ç­¾ä»¥ä¸‹åŽŸåˆ›æ— æ³•å…¶ä¸­å€‹äººä¸€åˆ‡æŒ‡å—关闭集团第三关注因此照片深圳商业广州日期高级最近综åˆè¡¨ç¤ºä¸“辑行为交通评价觉得精åŽå®¶åº­å®Œæˆæ„Ÿè§‰å®‰è£…得到邮件制度食å“虽然转载报价记者方案行政人民用å“东西æ出酒店然åŽä»˜æ¬¾çƒ­ç‚¹ä»¥å‰å®Œå…¨å‘帖设置领导工业医院看看ç»å…¸åŽŸå› å¹³å°å„ç§å¢žåŠ æ料新增之åŽèŒä¸šæ•ˆæžœä»Šå¹´è®ºæ–‡æˆ‘国告诉版主修改å‚与打å°å¿«ä¹æœºæ¢°è§‚点存在精神获得利用继续你们这么模å¼è¯­è¨€èƒ½å¤Ÿé›…虎æ“作风格一起科学体育短信æ¡ä»¶æ²»ç–—è¿åŠ¨äº§ä¸šä¼šè®®å¯¼èˆªå…ˆç”Ÿè”盟å¯æ˜¯å•é¡Œç»“构作用调查資料自动负责农业访问实施接å—讨论那个å馈加强女性范围æœå‹™ä¼‘闲今日客æœè§€çœ‹å‚加的è¯ä¸€ç‚¹ä¿è¯å›¾ä¹¦æœ‰æ•ˆæµ‹è¯•ç§»åŠ¨æ‰èƒ½å†³å®šè‚¡ç¥¨ä¸æ–­éœ€æ±‚ä¸å¾—办法之间采用è¥é”€æŠ•è¯‰ç›®æ ‡çˆ±æƒ…摄影有些複製文学机会数字装修购物农æ‘å…¨é¢ç²¾å“其实事情水平æ示上市谢谢普通教师上传类别歌曲拥有创新é…件åªè¦æ—¶ä»£è³‡è¨Šè¾¾åˆ°äººç”Ÿè®¢é˜…è€å¸ˆå±•ç¤ºå¿ƒç†è´´å­ç¶²ç«™ä¸»é¡Œè‡ªç„¶çº§åˆ«ç®€å•æ”¹é©é‚£äº›æ¥è¯´æ‰“开代ç åˆ é™¤è¯åˆ¸èŠ‚ç›®é‡ç‚¹æ¬¡æ•¸å¤šå°‘规划资金找到以åŽå¤§å…¨ä¸»é¡µæœ€ä½³å›žç­”天下ä¿éšœçŽ°ä»£æ£€æŸ¥æŠ•ç¥¨å°æ—¶æ²’有正常甚至代ç†ç›®å½•å…¬å¼€å¤åˆ¶é‡‘èžå¹¸ç¦ç‰ˆæœ¬å½¢æˆå‡†å¤‡è¡Œæƒ…回到æ€æƒ³æ€Žæ ·å议认è¯æœ€å¥½äº§ç”ŸæŒ‰ç…§æœè£…广东动漫采购新手组图é¢æ¿å‚考政治容易天地努力人们å‡çº§é€Ÿåº¦äººç‰©è°ƒæ•´æµè¡Œé€ æˆæ–‡å­—韩国贸易开展相關表现影视如此美容大å°æŠ¥é“æ¡æ¬¾å¿ƒæƒ…许多法规家居书店连接立å³ä¸¾æŠ¥æŠ€å·§å¥¥è¿ç™»å…¥ä»¥æ¥ç†è®ºäº‹ä»¶è‡ªç”±ä¸­åŽåŠžå…¬å¦ˆå¦ˆçœŸæ­£ä¸é”™å…¨æ–‡åˆåŒä»·å€¼åˆ«äººç›‘ç£å…·ä½“世纪团队创业承担增长有人ä¿æŒå•†å®¶ç»´ä¿®å°æ¹¾å·¦å³è‚¡ä»½ç­”案实际电信ç»ç†ç”Ÿå‘½å®£ä¼ ä»»åŠ¡æ­£å¼ç‰¹è‰²ä¸‹æ¥å会åªèƒ½å½“然é‡æ–°å…§å®¹æŒ‡å¯¼è¿è¡Œæ—¥å¿—賣家超过土地浙江支付推出站长æ­å·žæ‰§è¡Œåˆ¶é€ ä¹‹ä¸€æŽ¨å¹¿çŽ°åœºæè¿°å˜åŒ–传统歌手ä¿é™©è¯¾ç¨‹åŒ»ç–—ç»è¿‡è¿‡åŽ»ä¹‹å‰æ”¶å…¥å¹´åº¦æ‚志美丽最高登陆未æ¥åŠ å·¥å…责教程版å—身体é‡åº†å‡ºå”®æˆæœ¬å½¢å¼åœŸè±†å‡ºåƒ¹ä¸œæ–¹é‚®ç®±å—京求èŒå–å¾—èŒä½ç›¸ä¿¡é¡µé¢åˆ†é’Ÿç½‘页确定图例网å€ç§¯æžé”™è¯¯ç›®çš„å®è´æœºå…³é£Žé™©æŽˆæƒç—…毒宠物除了評論疾病åŠæ—¶æ±‚购站点儿童æ¯å¤©ä¸­å¤®è®¤è¯†æ¯ä¸ªå¤©æ´¥å­—体å°ç£ç»´æŠ¤æœ¬é¡µä¸ªæ€§å®˜æ–¹å¸¸è§ç›¸æœºæˆ˜ç•¥åº”当律师方便校园股市房屋æ ç›®å‘˜å·¥å¯¼è‡´çªç„¶é“具本网结åˆæ¡£æ¡ˆåŠ³åŠ¨å¦å¤–美元引起改å˜ç¬¬å››ä¼šè®¡èªªæ˜Žéšç§å®å®è§„范消费共åŒå¿˜è®°ä½“系带æ¥å字發表开放加盟å—到二手大é‡æˆäººæ•°é‡å…±äº«åŒºåŸŸå¥³å­©åŽŸåˆ™æ‰€åœ¨ç»“æŸé€šä¿¡è¶…级é…置当时优秀性感房产éŠæˆ²å‡ºå£æ交就业ä¿å¥ç¨‹åº¦å‚数事业整个山东情感特殊分類æœå°‹å±žäºŽé—¨æˆ·è´¢åŠ¡å£°éŸ³åŠå…¶è´¢ç»åšæŒå¹²éƒ¨æˆç«‹åˆ©ç›Šè€ƒè™‘æˆéƒ½åŒ…装用戶比赛文明招商完整真是眼ç›ä¼™ä¼´å¨æœ›é¢†åŸŸå«ç”Ÿä¼˜æƒ è«–壇公共良好充分符åˆé™„件特点ä¸å¯è‹±æ–‡èµ„产根本明显密碼公众民æ—更加享å—åŒå­¦å¯åŠ¨é€‚åˆåŽŸæ¥é—®ç­”本文美食绿色稳定终于生物供求æœç‹åŠ›é‡ä¸¥é‡æ°¸è¿œå†™çœŸæœ‰é™ç«žäº‰å¯¹è±¡è´¹ç”¨ä¸å¥½ç»å¯¹å分促进点评影音优势ä¸å°‘欣èµå¹¶ä¸”有点方å‘全新信用设施形象资格çªç ´éšç€é‡å¤§äºŽæ˜¯æ¯•ä¸šæ™ºèƒ½åŒ–工完美商城统一出版打造產å“概况用于ä¿ç•™å› ç´ ä¸­åœ‹å­˜å‚¨è´´å›¾æœ€æ„›é•¿æœŸå£ä»·ç†è´¢åŸºåœ°å®‰æŽ’武汉里é¢åˆ›å»ºå¤©ç©ºé¦–先完善驱动下é¢ä¸å†è¯šä¿¡æ„义阳光英国漂亮军事玩家群众农民å³å¯å稱家具动画想到注明å°å­¦æ€§èƒ½è€ƒç ”硬件观看清楚æžç¬‘首é é»„金适用江è‹çœŸå®žä¸»ç®¡é˜¶æ®µè¨»å†Šç¿»è¯‘æƒåˆ©åšå¥½ä¼¼ä¹Žé€šè®¯æ–½å·¥ç‹€æ…‹ä¹Ÿè®¸çŽ¯ä¿åŸ¹å…»æ¦‚念大型机票ç†è§£åŒ¿åcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestánnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegúnbuenosvolverpuntossemanahabíaagostonuevosunidoscarlosequiponiñosmuchosalgunacorreoimagenpartirarribamaríahombreempleoverdadcambiomuchasfueronpasadolíneaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposseráneuropamediosfrenteacercademásofertacochesmodeloitalialetrasalgúncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrápuestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosúnicocaminositiosrazóndebidopruebatoledoteníajesúsesperococinaorigentiendacientocádizhablarseríalatinafuerzaestiloguerraentraréxitolópezagendavídeoevitarpaginametrosjavierpadresfácilcabezaáreassalidaenvíojapónabusosbienestextosllevarpuedanfuertecomúnclaseshumanotenidobilbaounidadestáseditarcreadoдлÑчтокакилиÑтовÑеегопритакещеужеКакбезбылониВÑеподЭтотомчемнетлетразонагдемнеДлÑПринаÑнихтемктогодвоттамСШÐмаÑЧтоваÑвамемуТакдванамÑтиÑтуВамтехпротутнадднÑВоттринейВаÑнимÑамтотрубОнимирнееОООлицÑтаОнанемдоммойдвеоноÑудकेहैकीसेकाकोऔरपरनेà¤à¤•à¤•à¤¿à¤­à¥€à¤‡à¤¸à¤•à¤°à¤¤à¥‹à¤¹à¥‹à¤†à¤ªà¤¹à¥€à¤¯à¤¹à¤¯à¤¾à¤¤à¤•à¤¥à¤¾jagranआजजोअबदोगईजागà¤à¤¹à¤®à¤‡à¤¨à¤µà¤¹à¤¯à¥‡à¤¥à¥‡à¤¥à¥€à¤˜à¤°à¤œà¤¬à¤¦à¥€à¤•à¤ˆà¤œà¥€à¤µà¥‡à¤¨à¤ˆà¤¨à¤à¤¹à¤°à¤‰à¤¸à¤®à¥‡à¤•à¤®à¤µà¥‹à¤²à¥‡à¤¸à¤¬à¤®à¤ˆà¤¦à¥‡à¤“रआमबसभरबनचलमनआगसीलीعلىإلىهذاآخرعددالىهذهصورغيركانولابينعرضذلكهنايومقالعليانالكنحتىقبلوحةاخرÙقطعبدركنإذاكمااحدإلاÙيهبعضكيÙبحثومنوهوأناجدالهاسلمعندليسعبرصلىمنذبهاأنهمثلكنتالاحيثمصرشرححولوÙياذالكلمرةانتالÙأبوخاصأنتانهاليعضووقدابنخيربنتلكمشاءوهيابوقصصومارقمأحدنحنعدمرأياحةكتبدونيجبمنهتحتجهةسنةيتمكرةغزةنÙسبيتللهلناتلكقلبلماعنهأولشيءنورأماÙيكبكلذاترتببأنهمسانكبيعÙقدحسنلهمشعرأهلشهرقطرطلبprofileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>
+wrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle="Mobile killingshowingItaliandroppedheavilyeffects-1']);
+confirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.
+
+The but notdensityBritainChineselack oftributeIreland" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang="return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue="complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role="missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();
+paymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen
+
+When observe</h2>
+Modern provide" alt="borders.
+
+For
+
+Many artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>
+ Countryignoredloss ofjust asGeorgiastrange<head><stopped1']);
+islandsnotableborder:list ofcarried100,000</h3>
+ severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id="foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login">convertviolententeredfirst">circuitFinlandchemistshe was10px;">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title">tooltipSectiondesignsTurkishyounger.match(})();
+
+burningoperatedegreessource=Richardcloselyplasticentries</tr>
+color:#ul id="possessrollingphysicsfailingexecutecontestlink toDefault<br />
+: true,chartertourismclassicproceedexplain</h1>
+online.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src="/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e&quot;tradingleft">
+personsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy
+ <!--Daniel bindingblock">imposedutilizeAbraham(except{width:putting).html(|| [];
+DATA[ *kitchenmountedactual dialectmainly _blank'installexpertsif(typeIt also&copy; ">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref="/" rel="developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in
+ <!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday's.html" target=wearingAll Rig;
+})();raising Also, crucialabout">declare-->
+<scfirefoxas muchappliesindex, s, but type =
+
+<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>
+ returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of
+
+Some 'click'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion="pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major":"httpin his menu">
+monthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>
+evidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>
+ he left).val()false);logicalbankinghome tonaming Arizonacredits);
+});
+founderin turnCollinsbefore But thechargedTitle">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered']);
+ has theunclearEvent',both innot all
+
+<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage" linear painterand notrarely acronymdelivershorter00&amp;as manywidth="/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don'tretreat. Some ww.");
+bombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft"><comScorAll thejQuery.touristClassicfalse" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>
+
+. When in bothdismissExplorealways via thespañolwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>
+ it intoranked rate oful>
+ attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped").css(hostilelead tolittle groups,Picture-->
+
+ rows=" objectinverse<footerCustomV><\/scrsolvingChamberslaverywoundedwhereas!= 'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead')[0Criticsstudios>&copy;group">assemblmaking pressedwidget.ps:" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass="but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + "gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(" />
+ here isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();
+ is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded="true"spacingis mosta more totallyfall of});
+ immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace">header-well asStanleybridges/globalCroatia About [0];
+ it, andgroupedbeing a){throwhe madelighterethicalFFFFFF"bottom"like a employslive inas seenprintermost ofub-linkrejectsand useimage">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older">us.js"> Since universlarger open to!-- endlies in']);
+ marketwho is ("DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting
+ var March 2grew upClimate.removeskilledway the</head>face ofacting right">to workreduceshas haderectedshow();action=book ofan area== "htt<header
+<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage">MobilClements" id="as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;">
+pushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>
+people.in one =windowfooter_a good reklamaothers,to this_cookiepanel">London,definescrushedbaptismcoastalstatus title" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />
+AtlantanucleusCounty,purely count">easily build aonclicka givenpointerh&quot;events else {
+ditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium"DO NOT France,with a war andsecond take a >
+
+
+market.highwaydone inctivity"last">obligedrise to"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right" bicycleacing="day andstatingRather,higher Office are nowtimes, when a pay foron this-link">;borderaround annual the Newput the.com" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks">
+();" rea place\u003Caabout atr>
+ ccount gives a<SCRIPTRailwaythemes/toolboxById("xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>
+<ustomVa;&gt;</importsor thatmostly &amp;re size="</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>
+
+<!organis <br />Beijingcatalàdeutscheuropeueuskaragaeilgesvenskaespañamensajeusuariotrabajoméxicopáginasiempresistemaoctubreduranteañadirempresamomentonuestroprimeratravésgraciasnuestraprocesoestadoscalidadpersonanúmeroacuerdomúsicamiembroofertasalgunospaísesejemploderechoademásprivadoagregarenlacesposiblehotelessevillaprimeroúltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseñoturismocódigoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastítuloconocersegundoconsejofranciaminutossegundatenemosefectosmálagasesiónrevistagranadacompraringresogarcíaacciónecuadorquienesinclusodeberámateriahombresmuestrapodríamañanaúltimaestamosoficialtambienningúnsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo"><adaughterauthor" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id="discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive">somewhatvictoriaWestern title="LocationcontractvisitorsDownloadwithout right">
+measureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg" />machines</h2>
+ keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow" valuable</label>relativebringingincreasegovernorplugins/List of Header">" name=" (&quot;graduate</head>
+commercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>
+ <select citizensclothingwatching<li id="specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split("lizationOctober ){returnimproved--&gt;
+
+coveragechairman.png" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css" /> websitereporteddefault"/></a>
+electricscotlandcreationquantity. ISBN 0did not instance-search-" lang="speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: 'http:'script'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id="William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout="approved maximumheader"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=""intervalwirelessentitledagenciesSearch" measuredthousandspending&hellip;new Date" size="pageNamemiddle" " /></a>hidden">sequencepersonaloverflowopinionsillinoislinks">
+ <title>versionssaturdayterminalitempropengineersectionsdesignerproposal="false"Españolreleasessubmit" er&quot;additionsymptomsorientedresourceright"><pleasurestationshistory.leaving border=contentscenter">.
+
+Some directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal"><span>search">operatorrequestsa &quot;allowingDocumentrevision.
+
+The yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1"indicatefamiliar qualitymargin:0 contentviewportcontacts-title">portable.length eligibleinvolvesatlanticonload="default.suppliedpaymentsglossary
+
+After guidance</td><tdencodingmiddle">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>
+ affectedsupportspointer;toString</small>oklahomawill be investor0" alt="holidaysResourcelicensed (which . After considervisitingexplorerprimary search" android"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions"campbell<!-- end</span><<br />
+_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=" Companyexamples<iframe believespresentsmarshallpart of properly).
+
+The taxonomymuch of </span>
+" data-srtuguêsscrollTo project<head>
+attorneyemphasissponsorsfancyboxworld's wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix
+<head>
+article <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth="2lazyloadnovemberused in height="cript">
+&nbsp;</<tr><td height:2/productcountry include footer" &lt;!-- title"></jquery.</form>
+(简体)(ç¹é«”)hrvatskiitalianoromânătürkçeاردوtambiénnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuésdeportesproyectoproductopúbliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniónimprimirmientrasaméricavendedorsociedadrespectorealizarregistropalabrasinterésentoncesespecialmiembrosrealidadcórdobazaragozapáginassocialesbloqueargestiónalquilersistemascienciascompletoversióncompletaestudiospúblicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayoríaalemaniafunciónúltimoshaciendoaquellosediciónfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojóvenesdistritotécnicaconjuntoenergíatrabajarasturiasrecienteutilizarboletínsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallapróximoalmeríaanimalesquiénescorazónsecciónbuscandoopcionesexteriorconceptotodavíagaleríaescribirmedicinalicenciaconsultaaspectoscríticadólaresjusticiadeberánperíodonecesitamantenerpequeñorecibidatribunaltenerifecancióncanariasdescargadiversosmallorcarequieretécnicodeberíaviviendafinanzasadelantefuncionaconsejosdifícilciudadesantiguasavanzadatérminounidadessánchezcampañasoftonicrevistascontienesectoresmomentosfacultadcréditodiversassupuestofactoressegundospequeñaгодаеÑлиеÑтьбылобытьÑтомЕÑлитогоменÑвÑехÑтойдажебылигодуденьÑтотбылаÑебÑодинÑебенадоÑайтфотонегоÑвоиÑвойигрытожевÑемÑвоюлишьÑтихпокаднейдомамиралиботемухотÑдвухÑетилюдиделомиретебÑÑвоевидечегоÑтимÑчеттемыценыÑталведьтемеводытебевышенамитипатомуправлицаоднагодызнаюмогудругвÑейидеткиноодноделаделеÑрокиюнÑвеÑьЕÑтьразанашиاللهالتيجميعخاصةالذيعليهجديدالآنالردتحكمصÙحةكانتاللييكونشبكةÙيهابناتحواءأكثرخلالالحبدليلدروساضغطتكونهناكساحةناديالطبعليكشكرايمكنمنهاشركةرئيسنشيطماذاالÙنشبابتعبررحمةكاÙةيقولمركزكلمةأحمدقلبييعنيصورةطريقشاركجوالأخرىمعناابحثعروضبشكلمسجلبنانخالدكتابكليةبدونأيضايوجدÙريقكتبتأÙضلمطبخاكثرباركاÙضلاحلىنÙسهأيامردودأنهاديناالانمعرضتعلمداخلممكن
+ 
+ ÿÿÿÿ
+statementattentionBiography} else {
+solutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter">
+exceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick="biographyotherwisepermanentFrançaisHollywoodexpansionstandards</style>
+reductionDecember preferredCambridgeopponentsBusiness confusion>
+<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>
+mountainslike the essentialfinancialselectionaction="/abandonedEducationparseInt(stabilityunable to</title>
+relationsNote thatefficientperformedtwo yearsSince thethereforewrapper">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>
+suspectedmargin: 0spiritual</head>
+
+microsoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header">February numerous overflow:componentfragmentsexcellentcolspan="technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>
+ sponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting" width=".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper"enough toalong thedelivered-->
+<!--American protectedNovember </style><furnitureInternet onblur="suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir="ltr"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;
+
+southwestthe rightradiationmay have unescape(spoken in" href="/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>
+came fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8" /><![CDATA[">ContactSouthern bgcolor="series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->
+<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id="precedingTechnicalphysicistoccurs innavigatorsection">span id="sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt="in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id="right">
+residenceleave thecontent">are often })();
+probably Professor-button" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor
+&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved
+
+In the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also
+<head>
+<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained"></div>
+</a></td>depend onsearch">
+pieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue="">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.
+
+After , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover" style="states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of
+<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href="y:inline;Church ofthe eventvery highofficial -height: content="/cgi-bin/to createafrikaansesperantofrançaislatvieÅ¡ulietuviųČeÅ¡tinaÄeÅ¡tinaไทย日本語简体字ç¹é«”字한국어为什么计算机笔记本討論å€æœåŠ¡å™¨äº’è”网房地产俱ä¹éƒ¨å‡ºç‰ˆç¤¾æŽ’行榜部è½æ ¼è¿›ä¸€æ­¥æ”¯ä»˜å®éªŒè¯ç å§”员会数æ®åº“消费者办公室讨论区深圳市播放器北京市大学生越æ¥è¶Šç®¡ç†å‘˜ä¿¡æ¯ç½‘serviciosartículoargentinabarcelonacualquierpublicadoproductospolíticarespuestawikipediasiguientebúsquedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciónnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomíaimágenescontactardescargarnecesarioatenciónteléfonocomisióncancionescapacidadencontraranálisisfavoritostérminosprovinciaetiquetaselementosfuncionesresultadocarácterpropiedadprincipionecesidadmunicipalcreacióndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzálezdocumentopelícularecientesgeneralestarragonaprácticanovedadespropuestapacientestécnicasobjetivoscontactosमेंलिà¤à¤¹à¥ˆà¤‚गयासाथà¤à¤µà¤‚रहेकोईकà¥à¤›à¤°à¤¹à¤¾à¤¬à¤¾à¤¦à¤•à¤¹à¤¾à¤¸à¤­à¥€à¤¹à¥à¤à¤°à¤¹à¥€à¤®à¥ˆà¤‚दिनबातdiplodocsसमयरूपनामपताफिरऔसततरहलोगहà¥à¤†à¤¬à¤¾à¤°à¤¦à¥‡à¤¶à¤¹à¥à¤ˆà¤–ेलयदिकामवेबतीनबीचमौतसाललेखजॉबमददतथानहीशहरअलगकभीनगरपासरातकिà¤à¤‰à¤¸à¥‡à¤—यीहूà¤à¤†à¤—ेटीमखोजकारअभीगयेतà¥à¤®à¤µà¥‹à¤Ÿà¤¦à¥‡à¤‚अगरà¤à¤¸à¥‡à¤®à¥‡à¤²à¤²à¤—ाहालऊपरचारà¤à¤¸à¤¾à¤¦à¥‡à¤°à¤œà¤¿à¤¸à¤¦à¤¿à¤²à¤¬à¤‚दबनाहूंलाखजीतबटनमिलइसेआनेनयाकà¥à¤²à¤²à¥‰à¤—भागरेलजगहरामलगेपेजहाथइसीसहीकलाठीकहाà¤à¤¦à¥‚रतहतसातयादआयापाककौनशामदेखयहीरायखà¥à¤¦à¤²à¤—ीcategoriesexperience</title>
+Copyright javascriptconditionseverything<p class="technologybackground<a class="management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox" techniquesprotectionapparentlyas well asunt', 'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor="#especially content="productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=".indexOf("conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus="<form id="processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png" (document,boundariesexpressionsettlementBackgroundout of theenterprise("https:" unescape("password" democratic<a href="/wrapper">
+membershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick="considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic" height="link rel=".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class="0px;marginmechanicalstatisticscelebratedGovernment
+
+During tdevelopersartificialequivalentoriginatedCommissionattachment<span id="there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang="en" </style>
+absolute; supportingextremely mainstream</strong> popularityemployment</table>
+ colspan="</form>
+ conversionabout the </p></div>integrated" lang="enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class="<a title="(includingparametersprohibited= "http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0" class="completelyillustratefive yearsinstrumentPublishing1" class="psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;
+function it was theConventionautomobileProtestantaggressiveafter the Similarly," /></div>collection
+functionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>
+</.indexOf('i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }
+</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt="adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css" function innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>
+ diplomaticcontainingperformingextensionsmay not beconcept of onclick="It is alsofinancial making theLuxembourgadditionalare calledengaged in"script");but it waselectroniconsubmit="
+<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences
+</head>
+recognisedinitializelimited toAlexandriaretirementAdventuresfour years
+
+&lt;!-- increasingdecorationh3 class="origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews" width="1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class="Scientificclass="no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional
+<head>
+<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix">the publicmany yearswhich wereover time,synonymouscontent">
+presumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan="only a fewmeant thatled to the-->
+<div <fieldset>Archbishop class="nobeing usedapproachesprivilegesnoscript>
+results inmay be theEaster eggmechanismsreasonablePopulationCollectionselected">noscript> /index.phparrival of-jssdk'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>
+ complaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype="absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>
+percentagebest-knowncreating a" dir="ltrLieutenant
+<div id="they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.
+
+In the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/" class="geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid="searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured">is said tostructuralreferendummost oftena separate->
+<div id Official worldwide.aria-labelthe planetand it wasd" value="looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id="opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/" title=".com/indextaking thepittsburghcontent"> <script>(fturned outhaving the</span>
+ occasionalbecause itstarted tophysically></div>
+ created byCurrently, bgcolor="tabindex="disastrousAnalytics also has a><div id="</style>
+<called forsinger and.src = "//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportuguêsעבריתÙارسیdesarrollocomentarioeducaciónseptiembreregistradodirecciónubicaciónpublicidadrespuestasresultadosimportantereservadosartículosdiferentessiguientesrepúblicasituaciónministerioprivacidaddirectorioformaciónpoblaciónpresidentecontenidosaccesoriostechnoratipersonalescategoríaespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopolíticasanterioresdocumentosnaturalezamaterialesdiferenciaeconómicatransporterodríguezparticiparencuentrandiscusiónestructurafundaciónfrecuentespermanentetotalmenteможнобудетможетвремÑтакжечтобыболееоченьÑтогокогдапоÑлевÑегоÑайтечерезмогутÑайтажизнимеждубудутПоиÑкздеÑьвидеоÑвÑзинужноÑвоейлюдейпорномногодетейÑвоихправатакоймеÑтоимеетжизньоднойлучшепередчаÑтичаÑтьработновыхправоÑобойпотомменеечиÑленовыеуÑлугоколоназадтакоетогдапочтиПоÑлетакиеновыйÑтоиттакихÑразуСанктфорумКогдакнигиÑлованашейнайтиÑвоимÑвÑзьлюбойчаÑтоÑредиКромеФорумрынкеÑталипоиÑктыÑÑчмеÑÑццентртрудаÑамыхрынкаÐовыйчаÑовмеÑтафильммартаÑтранмеÑтетекÑтнашихминутимениимеютномергородÑамомÑтомуконцеÑвоемкакойÐрхивمنتدىإرسالرسالةالعامكتبهابرامجاليومالصورجديدةالعضوإضاÙةالقسمالعابتحميلملÙاتملتقىتعديلالشعرأخبارتطويرعليكمإرÙاقطلباتاللغةترتيبالناسالشيخمنتديالعربالقصصاÙلامعليهاتحديثاللهمالعملمكتبةيمكنكالطÙÙ„ÙيديوإدارةتاريخالصحةتسجيلالوقتعندمامدينةتصميمأرشيÙالذينعربيةبوابةألعابالسÙرمشاكلتعالىالأولالسنةجامعةالصحÙالدينكلماتالخاصالملÙأعضاءكتابةالخيررسائلالقلبالأدبمقاطعمراسلمنطقةالكتبالرجلاشتركالقدميعطيكsByTagName(.jpg" alt="1px solid #.gif" alt="transparentinformationapplication" onclick="establishedadvertising.png" alt="environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright">0" height="even thoughreplacementdestinationCorporation<ul class="AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class="hundreds of
+
+However, compositionclear:both;cooperationwithin the label for="border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength="switzerlandDevelopmentessentially
+
+Although </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics
+ <div id="illustratedengineeringterritoriesauthoritiesdistributed6" height="sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class="more recentit has beeninvasion of).getTime()fundamentalDespite the"><div id="inspirationexaminationpreparationexplanation<input id="</a></span>versions ofinstrumentsbefore the = 'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content">
+<td class="undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src="/<h1 class="publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=";width:100%independent<h3 class=" onchange=").addClass(interactionOne of the daughter ofaccessoriesbranches of
+<div id="the largestdeclarationregulationsInformationtranslationdocumentaryin order to">
+<head>
+<" height="1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class="distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>
+</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>
+ selected="high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex="it could be<noscript>
+having been
+<head>
+< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval"></span></in New Yorkadditional compression
+
+<div id="incorporate;</script><attachEventbecame the " target="_carried outSome of thescience andthe time ofContainer">maintainingChristopherMuch of thewritings of" height="2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit="director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class="Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the" height="3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>
+Continentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name="TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel="This is the <a href="/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og="><a class="class="textConversion may be usedmanufactureafter beingclearfix">
+question ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period" name="q" confined toa result ofvalue="" />is actuallyEnvironment
+</head>
+Conversely,>
+<div id="0" width="1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious">this is notthe presentif they areand finallya matter of
+ </div>
+
+</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer" class="frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>
+<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger
+ </script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>
+ they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight="0" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class="btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world'scan lead torefers to aborder="0" government winning theresulted in while the Washington,the subjectcity in the></div>
+ reflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=""><a href="themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href="/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in <div id="it" value="language ofas they areproduced inis that theexplain thediv></div>
+However thelead to the <a href="/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldslovenÄinacomentariosuniversidadcondicionesactividadesexperienciatecnologíaproducciónpuntuaciónaplicacióncontraseñacategoríasregistrarseprofesionaltratamientoregístratesecretaríaprincipalesprotecciónimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociacióndisponiblesevaluaciónestudiantesresponsableresoluciónguadalajararegistradosoportunidadcomercialesfotografíaautoridadesingenieríatelevisióncompetenciaoperacionesestablecidosimplementeactualmentenavegaciónconformidadline-height:font-family:" : "http://applicationslink" href="specifically//<![CDATA[
+Organizationdistribution0px; height:relationshipdevice-width<div class="<label for="registration</noscript>
+/index.html"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name="intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class="organisationcivilization19th centuryarchitectureincorporated20th century-container">most notably/></a></div>notification'undefined')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang="&lt;/sup&gt;dealing withphiladelphiahistorically);</script>
+padding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd">
+<htgeographicalConstitution', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style="Encyclopediaiframe src="demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence" tabindex="float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time"><a class="In addition,description+conversationcontact withis generallyr" content="representing&lt;math&gt;presentationoccasionally<img width="navigation">compensationchampionshipmedia="all" violation ofreference toreturn true;Strict//EN" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}
+</script>
+Christianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=""><a href="/introductionbelonging toclaimed thatconsequences<meta name="Guide to theoverwhelmingagainst the concentrated,
+.nontouch observations</a>
+</div>
+f (document.border: 1px {font-size:1treatment of0" height="1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript" neverthelesssignificanceBroadcasting>&nbsp;</td>container">
+such as the influence ofa particularsrc='http://navigation" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite" xml:lang="deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype="image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet <ul class="installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures
+ <a href="close to theexamples of is about the(see below)." id="searchprofessionalis availablethe official </script>
+
+ <div id="accelerationthrough the Hall of Famedescriptionstranslationsinterference type='text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the <li class="instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class="aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc="http://px; height: available tomanufacturerhuman rightslink href="/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>
+consider thean estimatedthe National<div id="pagresulting incommissionedanalogous toare required/ul>
+</div>
+was based onand became a&nbsp;&nbsp;t" value="" was capturedno more thanrespectivelycontinue to >
+<head>
+<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml" title="weight:bold;creating thedisplay:nonereplaced the<img src="/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css" media="People from available onproved to besuggestions"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class="evidence forexplanationsenvironments"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign="top"principle ofat the time,</noscript> said to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style="input name="the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class="lastworking with'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the
+</script>
+
+an effort toincrease theto the southspacing="0">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>
+thought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds" content="authority ofnorthwestern</div>
+<div "></div>
+ consultationcommunity ofthe nationalit should beparticipants align="leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class="splace in thewhere he was<li class="fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class="effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previousconsistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\s+|\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers <link rel="provided thethe story ofcompetitionsenglish (UK)english (US)МонголСрпÑкиÑрпÑкиÑрпÑкоلعربية正體中文简体中文ç¹ä½“中文有é™å…¬å¸äººæ°‘政府阿里巴巴社会主义æ“作系统政策法规informaciónherramientaselectrónicodescripciónclasificadosconocimientopublicaciónrelacionadasinformáticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecontáctenoshabitacionescumplimientorestaurantesdisposiciónconsecuenciaelectrónicaaplicacionesdesconectadoinstalaciónrealizaciónutilizaciónenciclopediaenfermedadesinstrumentosexperienciasinstituciónparticularessubcategoriaтолькоРоÑÑииработыбольшепроÑтоможетедругихÑлучаеÑейчаÑвÑегдаРоÑÑиÑМоÑкведругиегородавопроÑданныхдолжныименноМоÑквырублейМоÑкваÑтраныничегоработедолженуÑлугитеперьОднакопотомуработуапрелÑвообщеодногоÑвоегоÑтатьидругойфорумехорошопротивÑÑылкакаждыйвлаÑтигруппывмеÑтеработаÑказалпервыйделатьденьгипериодбизнеÑоÑновемоменткупитьдолжнарамкахначалоРаботаТолькоÑовÑемвторойначалаÑпиÑокÑлужбыÑиÑтемпечатиновогопомощиÑайтовпочемупомощьдолжноÑÑылкибыÑтроданныемногиепроектСейчаÑмоделитакогоонлайнгородеверÑиÑÑтранефильмыуровнÑразныхиÑкатьнеделюÑнварÑменьшемногихданнойзначитнельзÑфорумаТеперьмеÑÑцазащитыЛучшиеनहींकरनेअपनेकियाकरेंअनà¥à¤¯à¤•à¥à¤¯à¤¾à¤—ाइडबारेकिसीदियापहलेसिंहभारतअपनीवालेसेवाकरतेमेरेहोनेसकतेबहà¥à¤¤à¤¸à¤¾à¤‡à¤Ÿà¤¹à¥‹à¤—ाजानेमिनटकरताकरनाउनकेयहाà¤à¤¸à¤¬à¤¸à¥‡à¤­à¤¾à¤·à¤¾à¤†à¤ªà¤•à¥‡à¤²à¤¿à¤¯à¥‡à¤¶à¥à¤°à¥‚इसकेघंटेमेरीसकतामेरालेकरअधिकअपनासमाजमà¥à¤à¥‡à¤•à¤¾à¤°à¤£à¤¹à¥‹à¤¤à¤¾à¤•à¤¡à¤¼à¥€à¤¯à¤¹à¤¾à¤‚होटलशबà¥à¤¦à¤²à¤¿à¤¯à¤¾à¤œà¥€à¤µà¤¨à¤œà¤¾à¤¤à¤¾à¤•à¥ˆà¤¸à¥‡à¤†à¤ªà¤•à¤¾à¤µà¤¾à¤²à¥€à¤¦à¥‡à¤¨à¥‡à¤ªà¥‚रीपानीउसकेहोगीबैठकआपकीवरà¥à¤·à¤—ांवआपकोजिलाजानासहमतहमेंउनकीयाहूदरà¥à¤œà¤¸à¥‚चीपसंदसवालहोनाहोतीजैसेवापसजनतानेताजारीघायलजिलेनीचेजांचपतà¥à¤°à¤—ूगलजातेबाहरआपनेवाहनइसकासà¥à¤¬à¤¹à¤°à¤¹à¤¨à¥‡à¤‡à¤¸à¤¸à¥‡à¤¸à¤¹à¤¿à¤¤à¤¬à¤¡à¤¼à¥‡à¤˜à¤Ÿà¤¨à¤¾à¤¤à¤²à¤¾à¤¶à¤ªà¤¾à¤‚चशà¥à¤°à¥€à¤¬à¤¡à¤¼à¥€à¤¹à¥‹à¤¤à¥‡à¤¸à¤¾à¤ˆà¤Ÿà¤¶à¤¾à¤¯à¤¦à¤¸à¤•à¤¤à¥€à¤œà¤¾à¤¤à¥€à¤µà¤¾à¤²à¤¾à¤¹à¤œà¤¾à¤°à¤ªà¤Ÿà¤¨à¤¾à¤°à¤–नेसड़कमिलाउसकीकेवललगताखानाअरà¥à¤¥à¤œà¤¹à¤¾à¤‚देखापहलीनियमबिनाबैंककहींकहनादेताहमलेकाफीजबकितà¥à¤°à¤¤à¤®à¤¾à¤‚गवहींरोज़मिलीआरोपसेनायादवलेनेखाताकरीबउनकाजवाबपूराबड़ासौदाशेयरकियेकहांअकसरबनाà¤à¤µà¤¹à¤¾à¤‚सà¥à¤¥à¤²à¤®à¤¿à¤²à¥‡à¤²à¥‡à¤–कविषयकà¥à¤°à¤‚समूहथानाتستطيعمشاركةبواسطةالصÙحةمواضيعالخاصةالمزيدالعامةالكاتبالردودبرنامجالدولةالعالمالموقعالعربيالسريعالجوالالذهابالحياةالحقوقالكريمالعراقمحÙوظةالثانيمشاهدةالمرأةالقرآنالشبابالحوارالجديدالأسرةالعلوممجموعةالرحمنالنقاطÙلسطينالكويتالدنيابركاتهالرياضتحياتيبتوقيتالأولىالبريدالكلامالرابطالشخصيسياراتالثالثالصلاةالحديثالزوارالخليجالجميعالعامهالجمالالساعةمشاهدهالرئيسالدخولالÙنيةالكتابالدوريالدروساستغرقتصاميمالبناتالعظيمentertainmentunderstanding = function().jpg" width="configuration.png" width="<body class="Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=""><img src="/distinguishedthousands of communicationclear"></div>investigationfavicon.ico" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch" type="form method="as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of" maxlength="return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type="the number ofthe original comprehensiverefers to the</ul>
+</div>
+philosophicallocation.hrefwas publishedSan Francisco(function(){
+<div id="mainsophisticatedmathematical /head>
+<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder="; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript" src="/(function() {are available
+ <link rel=" src='http://interested inconventional " alt="" /></are generallyhas also beenmost popular correspondingcredited withtyle="border:</a></span></.gif" width="<iframe src="table class="inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name="or" content="controversialproperty="og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style="known as the shortly afterfor instance,described as /head>
+<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant" border="0">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name="searchattributed tocourse of themathematicianby the end ofat the end of" border="0" technological.removeClass(branch of theevidence that![endif]-->
+Institute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href="confused with<link href="/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>
+</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription" determine theavailable forAccording to wide range of <div class="more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover="because they async = true;problems withseems to havethe result of src="http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld's firstclassified asbottom of the(particularlyalign="left" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout="New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to <meta name="are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to <ul class="visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style="equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these
+<div class="input class="replaced withis one of theeducation andinfluenced byreputation as
+<meta name="accommodation</div>
+</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the
+<div style="almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in" value="" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class="mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass="headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;
+</script>
+<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle="marginincluding thebahasa Melayunorsk bokmÃ¥lnorsk nynorskslovenÅ¡Äinainternacionalcalificacióncomunicaciónconstrucción"><div class="disambiguationDomainName', 'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->
+</><meta name="implementationinfrastructurerepresentationborder-bottom:</head>
+<body>=http%3A%2F%2F<form method="method="post" /favicon.ico" });
+</script>
+.setAttribute(Administration= new Array();<![endif]-->
+display:block;Unfortunately,">&nbsp;</div>/favicon.ico">='stylesheet' identification, for example,<li><a href="/an alternativeas a result ofpt"></script>
+type="submit"
+(function() {recommendationform action="/transformationreconstruction.style.display According to hidden" name="along with thedocument.body.approximately Communicationspost" action="meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover="the governmenthref="https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->
+
+depends on theUniversity of in contrast to placeholder="in the case ofinternational constitutionalstyle="border-: function() {Because of the-strict.dtd">
+<table class="accompanied byaccount of the<script src="/nature of the the people in in addition tos); js.id = id" width="100%"regarding the Roman Catholican independentfollowing the .gif" width="1the following discriminationarchaeologicalprime minister.js"></script>combination of marginwidth="createElement(w.attachEvent(</a></td></tr>src="https://aIn particular, align="left" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html" title="(function () {comes from theapplication of<span class="sbelieved to beement('script'</a>
+</li>
+<livery different><span class="option value="(also known as <li><a href="><input name="separated fromreferred to as valign="top">founder of theattempting to carbon dioxide
+
+<div class="class="search-/body>
+</html>opportunity tocommunications</head>
+<body style="width:Tiếng Việtchanges in theborder-color:#0" border="0" </span></div><was discovered" type="text" );
+</script>
+
+Department of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>
+
+<div iwas consideredpercent of the" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href='http://whether or notThere are alsothere are manya small numberother parts ofimpossible to class="buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=" method="post"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign="right">many countriesfor many yearsearliest knownbecause it waspt"></script> valign="top" inhabitants offollowing year
+<div class="million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style="color:although therebest known forsubmit" name="multiplicationmore than one recognition ofCouncil of theedition of the <meta name="Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class="descendants of<span class="i align="right"</head>
+<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the <span class="is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class="<span class="t(Math.random()most prominentdescription ofConstantinoplewere published<div class="seappears in the1" height="1" most importantwhich includeswhich had beendestruction ofthe population
+ <div class="possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle="clear:b
+</script>
+<was founded ininterview with_id" content="capital of the
+<link rel="srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class="cperformance of(function() { if and only ifregions of theleading to therelations withUnited Nationsstyle="height:other than theype" content="Association of
+</head>
+<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>
+<link rel=" return false;the purpose ofthe ability to;color:#fff}
+.
+<span class="the subject ofdefinitions of>
+<link rel="claim that thehave developed<table width="celebration ofFollowing the to distinguish<span class="btakes place inunder the namenoted that the><![endif]-->
+style="margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id="was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>
+
+environmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made" src="http://interpreted assecond half ofcrolling="no" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class="footerand especiallytype="button" </span></span>which included>
+<meta name="considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process <div class="the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class="ptext" name="q" <div class="the scientificrepresented bymathematicianselected by thethat have been><div class="cdiv id="headerin particular,converted into);
+</script>
+<philosophical srpskohrvatskitiếng ViệtРуÑÑкийруÑÑкийinvestigaciónparticipaciónкоторыеоблаÑтикоторыйчеловекÑиÑтемыÐовоÑтикоторыхоблаÑтьвременикотораÑÑегоднÑÑкачатьновоÑтиУкраинывопроÑыкоторойÑделатьпомощьюÑредÑтвобразомÑтороныучаÑтиетечениеГлавнаÑиÑторииÑиÑтемарешениÑСкачатьпоÑтомуÑледуетÑказатьтоваровконечнорешениекотороеоргановкоторомРекламаالمنتدىمنتدياتالموضوعالبرامجالمواقعالرسائلمشاركاتالأعضاءالرياضةالتصميمالاعضاءالنتائجالألعابالتسجيلالأقسامالضغطاتالÙيديوالترحيبالجديدةالتعليمالأخبارالاÙلامالأÙلامالتاريخالتقنيةالالعابالخواطرالمجتمعالديكورالسياحةعبداللهالتربيةالروابطالأدبيةالاخبارالمتحدةالاغانيcursor:pointer;</title>
+<meta " href="http://"><span class="members of the window.locationvertical-align:/a> | <a href="<!doctype html>media="screen" <option value="favicon.ico" />
+ <div class="characteristics" method="get" /body>
+</html>
+shortcut icon" document.write(padding-bottom:representativessubmit" value="align="center" throughout the science fiction
+ <div class="submit" class="one of the most valign="top"><was established);
+</script>
+return false;">).style.displaybecause of the document.cookie<form action="/}body{margin:0;Encyclopedia ofversion of the .createElement(name" content="</div>
+</div>
+
+administrative </body>
+</html>history of the "><input type="portion of the as part of the &nbsp;<a href="other countries">
+<div class="</span></span><In other words,display: block;control of the introduction of/>
+<meta name="as well as the in recent years
+ <div class="</div>
+ </div>
+inspired by thethe end of the compatible withbecame known as style="margin:.js"></script>< International there have beenGerman language style="color:#Communist Partyconsistent withborder="0" cell marginheight="the majority of" align="centerrelated to the many different Orthodox Churchsimilar to the />
+<link rel="swas one of the until his death})();
+</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling="no" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign="center">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style="width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>
+ <div class="consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method="post" was followed by&amp;mdash; thethe applicationjs"></script>
+ul></div></div>after the deathwith respect tostyle="padding:is particularlydisplay:inline; type="submit" is divided into中文 (简体)responsabilidadadministracióninternacionalescorrespondienteउपयोगपूरà¥à¤µà¤¹à¤®à¤¾à¤°à¥‡à¤²à¥‹à¤—ोंचà¥à¤¨à¤¾à¤µà¤²à¥‡à¤•à¤¿à¤¨à¤¸à¤°à¤•à¤¾à¤°à¤ªà¥à¤²à¤¿à¤¸à¤–ोजेंचाहिà¤à¤­à¥‡à¤œà¥‡à¤‚शामिलहमारीजागरणबनानेकà¥à¤®à¤¾à¤°à¤¬à¥à¤²à¥‰à¤—मालिकमहिलापृषà¥à¤ à¤¬à¤¢à¤¼à¤¤à¥‡à¤­à¤¾à¤œà¤ªà¤¾à¤•à¥à¤²à¤¿à¤•à¤Ÿà¥à¤°à¥‡à¤¨à¤–िलाफदौरानमामलेमतदानबाजारविकासकà¥à¤¯à¥‹à¤‚चाहतेपहà¥à¤à¤šà¤¬à¤¤à¤¾à¤¯à¤¾à¤¸à¤‚वाददेखनेपिछलेविशेषराजà¥à¤¯à¤‰à¤¤à¥à¤¤à¤°à¤®à¥à¤‚बईदोनोंउपकरणपढ़ेंसà¥à¤¥à¤¿à¤¤à¤«à¤¿à¤²à¥à¤®à¤®à¥à¤–à¥à¤¯à¤…चà¥à¤›à¤¾à¤›à¥‚टतीसंगीतजाà¤à¤—ाविभागघणà¥à¤Ÿà¥‡à¤¦à¥‚सरेदिनोंहतà¥à¤¯à¤¾à¤¸à¥‡à¤•à¥à¤¸à¤—ांधीविशà¥à¤µà¤°à¤¾à¤¤à¥‡à¤‚दैटà¥à¤¸à¤¨à¤•à¥à¤¶à¤¾à¤¸à¤¾à¤®à¤¨à¥‡à¤…दालतबिजलीपà¥à¤°à¥‚षहिंदीमितà¥à¤°à¤•à¤µà¤¿à¤¤à¤¾à¤°à¥à¤ªà¤¯à¥‡à¤¸à¥à¤¥à¤¾à¤¨à¤•à¤°à¥‹à¤¡à¤¼à¤®à¥à¤•à¥à¤¤à¤¯à¥‹à¤œà¤¨à¤¾à¤•à¥ƒà¤ªà¤¯à¤¾à¤ªà¥‹à¤¸à¥à¤Ÿà¤˜à¤°à¥‡à¤²à¥‚कारà¥à¤¯à¤µà¤¿à¤šà¤¾à¤°à¤¸à¥‚चनामूलà¥à¤¯à¤¦à¥‡à¤–ेंहमेशासà¥à¤•à¥‚लमैंनेतैयारजिसकेrss+xml" title="-type" content="title" content="at the same time.js"></script>
+<" method="post" </span></a></li>vertical-align:t/jquery.min.js">.click(function( style="padding-})();
+</script>
+</span><a href="<a href="http://); return false;text-decoration: scrolling="no" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif" border="0"</body>
+</html>
+overflow:hidden;img src="http://addEventListenerresponsible for s.js"></script>
+/favicon.ico" />operating system" style="width:1target="_blank">State Universitytext-align:left;
+document.write(, including the around the world);
+</script>
+<" style="height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>
+ </div>
+display: none;">" />
+<link rel="
+ (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the align="center">University Pressdominated by theSecond World Wardistribution of style="position:the rest of the characterized by rel="nofollow">derives from therather than the a combination ofstyle="width:100English-speakingcomputer scienceborder="0" alt="the existence ofDemocratic Party" style="margin-For this reason,.js"></script>
+ sByTagName(s)[0]js"></script>
+<.js"></script>
+link rel="icon" ' alt='' class='formation of theversions of the </a></div></div>/page>
+ <page>
+<div class="contbecame the firstbahasa Indonesiaenglish (simple)ΕλληνικάхрватÑкикомпанииÑвлÑетÑÑДобавитьчеловекаразвитиÑИнтернетОтветитьнапримеринтернеткоторогоÑтраницыкачеÑтвеуÑловиÑхпроблемыполучитьÑвлÑÑŽÑ‚ÑÑнаиболеекомпаниÑвниманиеÑредÑтваالمواضيعالرئيسيةالانتقالمشاركاتكالسياراتالمكتوبةالسعوديةاحصائياتالعالميةالصوتياتالانترنتالتصاميمالإسلاميالمشاركةالمرئياتrobots" content="<div id="footer">the United States<img src="http://.jpg|right|thumb|.js"></script>
+<location.protocolframeborder="0" s" />
+<meta name="</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:" rel="nofollow" President of the twentieth centuryevision>
+ </pageInternet Explorera.async = true;
+information about<div id="header">" action="http://<a href="https://<div id="content"</div>
+</div>
+<derived from the <img src='http://according to the
+</body>
+</html>
+style="font-size:script language="Arial, Helvetica,</a><span class="</script><script political partiestd></tr></table><href="http://www.interpretation ofrel="stylesheet" document.write('<charset="utf-8">
+beginning of the revealed that thetelevision series" rel="nofollow"> target="_blank">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass="clearfix">/div>
+</div>
+
+three-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class="in some countriesmin.js"></script>of the populationofficial language<img src="images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>
+</html> Ελληνικά
+take advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class="headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype="text/css">
+the InternationalAccording to the pe="text/css" />
+coincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;" target="_blank" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type="application/anguage" content="<meta http-equiv="Privacy Policy</a>e("%3Cscript src='" target="_blank">On the other hand,.jpg|thumb|right|2</div><div class="<div style="float:nineteenth century</body>
+</html>
+<img src="http://s;text-align:centerfont-weight: bold; According to the difference between" frameborder="0" " style="position:link href="http://html4/loose.dtd">
+during this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type="text" <span style="font-onreadystatechange <div class="cleardocument.location. For example, the a wide variety of <!DOCTYPE html>
+<&nbsp;&nbsp;&nbsp;"><a href="http://style="float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype="text/css" />it is possible to Harvard Universitytylesheet" href="/the main characterOxford University name="keywords" cstyle="text-align:the United Kingdomfederal government<div style="margin depending on the description of the<div class="header.min.js"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc="http://staticsuggested that the" src="http://www.a large number of Telecommunications" rel="nofollow" tHoly Roman Emperoralmost exclusively" border="0" alt="Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle="background-<li><em><a href="/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src="http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref="https://www.recent developmentBoard of Directors<div class="search| <a href="http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>
+</div>
+
+<a href="index.phpwas established inmin.js"></script>
+participate in thea strong influencestyle="margin-top:represented by thegraduated from theTraditionally, theElement("script");However, since the/div>
+</div>
+<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype="image/x-icon/div>
+<div class=" class="clearfix"><div class="footer </div>
+ </div>
+the motion pictureБългарÑкибългарÑкиФедерациинеÑколькоÑообщениеÑообщениÑпрограммыОтправитьбеÑплатноматериалыпозволÑетпоÑледниеразличныхпродукциипрограммаполноÑтьюнаходитÑÑизбранноенаÑелениÑизменениÑкатегорииÐлекÑандрदà¥à¤µà¤¾à¤°à¤¾à¤®à¥ˆà¤¨à¥à¤…लपà¥à¤°à¤¦à¤¾à¤¨à¤­à¤¾à¤°à¤¤à¥€à¤¯à¤…नà¥à¤¦à¥‡à¤¶à¤¹à¤¿à¤¨à¥à¤¦à¥€à¤‡à¤‚डियादिलà¥à¤²à¥€à¤…धिकारवीडियोचिटà¥à¤ à¥‡à¤¸à¤®à¤¾à¤šà¤¾à¤°à¤œà¤‚कà¥à¤¶à¤¨à¤¦à¥à¤¨à¤¿à¤¯à¤¾à¤ªà¥à¤°à¤¯à¥‹à¤—अनà¥à¤¸à¤¾à¤°à¤‘नलाइनपारà¥à¤Ÿà¥€à¤¶à¤°à¥à¤¤à¥‹à¤‚लोकसभाफ़à¥à¤²à¥ˆà¤¶à¤¶à¤°à¥à¤¤à¥‡à¤‚पà¥à¤°à¤¦à¥‡à¤¶à¤ªà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤‚दà¥à¤°à¤¸à¥à¤¥à¤¿à¤¤à¤¿à¤‰à¤¤à¥à¤ªà¤¾à¤¦à¤‰à¤¨à¥à¤¹à¥‡à¤‚चिटà¥à¤ à¤¾à¤¯à¤¾à¤¤à¥à¤°à¤¾à¤œà¥à¤¯à¤¾à¤¦à¤¾à¤ªà¥à¤°à¤¾à¤¨à¥‡à¤œà¥‹à¤¡à¤¼à¥‡à¤‚अनà¥à¤µà¤¾à¤¦à¤¶à¥à¤°à¥‡à¤£à¥€à¤¶à¤¿à¤•à¥à¤·à¤¾à¤¸à¤°à¤•à¤¾à¤°à¥€à¤¸à¤‚गà¥à¤°à¤¹à¤ªà¤°à¤¿à¤£à¤¾à¤®à¤¬à¥à¤°à¤¾à¤‚डबचà¥à¤šà¥‹à¤‚उपलबà¥à¤§à¤®à¤‚तà¥à¤°à¥€à¤¸à¤‚परà¥à¤•à¤‰à¤®à¥à¤®à¥€à¤¦à¤®à¤¾à¤§à¥à¤¯à¤®à¤¸à¤¹à¤¾à¤¯à¤¤à¤¾à¤¶à¤¬à¥à¤¦à¥‹à¤‚मीडियाआईपीà¤à¤²à¤®à¥‹à¤¬à¤¾à¤‡à¤²à¤¸à¤‚खà¥à¤¯à¤¾à¤†à¤ªà¤°à¥‡à¤¶à¤¨à¤…नà¥à¤¬à¤‚धबाज़ारनवीनतमपà¥à¤°à¤®à¥à¤–पà¥à¤°à¤¶à¥à¤¨à¤ªà¤°à¤¿à¤µà¤¾à¤°à¤¨à¥à¤•à¤¸à¤¾à¤¨à¤¸à¤®à¤°à¥à¤¥à¤¨à¤†à¤¯à¥‹à¤œà¤¿à¤¤à¤¸à¥‹à¤®à¤µà¤¾à¤°Ø§Ù„مشاركاتالمنتدياتالكمبيوترالمشاهداتعددالزوارعددالردودالإسلاميةالÙوتوشوبالمسابقاتالمعلوماتالمسلسلاتالجراÙيكسالاسلاميةالاتصالاتkeywords" content="w3.org/1999/xhtml"><a target="_blank" text/html; charset=" target="_blank"><table cellpadding="autocomplete="off" text-align: center;to last version by background-color: #" href="http://www./div></div><div id=<a href="#" class=""><img src="http://cript" src="http://
+<script language="//EN" "http://www.wencodeURIComponent(" href="javascript:<div class="contentdocument.write('<scposition: absolute;script src="http:// style="margin-top:.min.js"></script>
+</div>
+<div class="w3.org/1999/xhtml"
+
+</body>
+</html>distinction between/" target="_blank"><link href="http://encoding="utf-8"?>
+w.addEventListener?action="http://www.icon" href="http:// style="background:type="text/css" />
+meta property="og:t<input type="text" style="text-align:the development of tylesheet" type="tehtml; charset=utf-8is considered to betable width="100%" In addition to the contributed to the differences betweendevelopment of the It is important to </script>
+
+<script style="font-size:1></span><span id=gbLibrary of Congress<img src="http://imEnglish translationAcademy of Sciencesdiv style="display:construction of the.getElementById(id)in conjunction withElement('script'); <meta property="og:БългарÑки
+ type="text" name=">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src="http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style="background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet" href="/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland
+</script>
+<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv="X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0" cellpadding="0" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E"));<a href="http://www.<li><a href="http://site_name" content="text-decoration:nonestyle="display: none<meta http-equiv="X-new Date().getTime() type="image/x-icon"</span><span class="language="javascriptwindow.location.href<a href="javascript:-->
+<script type="t<a href='http://www.hortcut icon" href="</div>
+<div class="<script src="http://" rel="stylesheet" t</div>
+<script type=/a> <a href="http:// allowTransparency="X-UA-Compatible" conrelationship between
+</script>
+<script </a></li></ul></div>associated with the programming language</a><a href="http://</a></li><li class="form action="http://<div style="display:type="text" name="q"<table width="100%" background-position:" border="0" width="rel="shortcut icon" h6><ul><li><a href=" <meta http-equiv="css" media="screen" responsible for the " type="application/" style="background-html; charset=utf-8" allowtransparency="stylesheet" type="te
+<meta http-equiv="></span><span class="0" cellspacing="0">;
+</script>
+<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type="hidden" name="javascript:void(0);"effectiveness of the autocomplete="off" generally considered><input type="text" "></script>
+<scriptthroughout the worldcommon misconceptionassociation with the</div>
+</div>
+<div cduring his lifetime,corresponding to thetype="image/x-icon" an increasing numberdiplomatic relationsare often consideredmeta charset="utf-8" <input type="text" examples include the"><img src="http://iparticipation in thethe establishment of
+</div>
+<div class="&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset="utf-8"> type="text/css" />
+interchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type="text/csstype="submit" name="families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportuguês (Europeu)УкраїнÑькаукраїнÑькаРоÑÑийÑкойматериаловинформацииуправлениÑнеобходимоинформациÑИнформациÑРеÑпубликиколичеÑтвоинформациютерриториидоÑтаточноالمتواجدونالاشتراكاتالاقتراحاتhtml; charset=UTF-8" setTimeout(function()display:inline-block;<input type="submit" type = 'text/javascri<img src="http://www." "http://www.w3.org/shortcut icon" href="" autocomplete="off" </a></div><div class=</a></li>
+<li class="css" type="text/css" <form action="http://xt/css" href="http://link rel="alternate"
+<script type="text/ onclick="javascript:(new Date).getTime()}height="1" width="1" People's Republic of <a href="http://www.text-decoration:underthe beginning of the </div>
+</div>
+</div>
+establishment of the </div></div></div></d#viewport{min-height:
+<script src="http://option><option value=often referred to as /option>
+<option valu<!DOCTYPE html>
+<!--[International Airport>
+<a href="http://www</a><a href="http://wภาษาไทยქáƒáƒ áƒ—ული正體中文 (ç¹é«”)निरà¥à¤¦à¥‡à¤¶à¤¡à¤¾à¤‰à¤¨à¤²à¥‹à¤¡à¤•à¥à¤·à¥‡à¤¤à¥à¤°à¤œà¤¾à¤¨à¤•à¤¾à¤°à¥€à¤¸à¤‚बंधितसà¥à¤¥à¤¾à¤ªà¤¨à¤¾à¤¸à¥à¤µà¥€à¤•à¤¾à¤°à¤¸à¤‚सà¥à¤•à¤°à¤£à¤¸à¤¾à¤®à¤—à¥à¤°à¥€à¤šà¤¿à¤Ÿà¥à¤ à¥‹à¤‚विजà¥à¤žà¤¾à¤¨à¤…मेरिकाविभिनà¥à¤¨à¤—ाडियाà¤à¤•à¥à¤¯à¥‹à¤‚किसà¥à¤°à¤•à¥à¤·à¤¾à¤ªà¤¹à¥à¤à¤šà¤¤à¥€à¤ªà¥à¤°à¤¬à¤‚धनटिपà¥à¤ªà¤£à¥€à¤•à¥à¤°à¤¿à¤•à¥‡à¤Ÿà¤ªà¥à¤°à¤¾à¤°à¤‚भपà¥à¤°à¤¾à¤ªà¥à¤¤à¤®à¤¾à¤²à¤¿à¤•à¥‹à¤‚रफ़à¥à¤¤à¤¾à¤°à¤¨à¤¿à¤°à¥à¤®à¤¾à¤£à¤²à¤¿à¤®à¤¿à¤Ÿà¥‡à¤¡description" content="document.location.prot.getElementsByTagName(<!DOCTYPE html>
+<html <meta charset="utf-8">:url" content="http://.css" rel="stylesheet"style type="text/css">type="text/css" href="w3.org/1999/xhtml" xmltype="text/javascript" method="get" action="link rel="stylesheet" = document.getElementtype="image/x-icon" />cellpadding="0" cellsp.css" type="text/css" </a></li><li><a href="" width="1" height="1""><a href="http://www.style="display:none;">alternate" type="appli-//W3C//DTD XHTML 1.0 ellspacing="0" cellpad type="hidden" value="/a>&nbsp;<span role="s
+<input type="hidden" language="JavaScript" document.getElementsBg="0" cellspacing="0" ype="text/css" media="type='text/javascript'with the exception of ype="text/css" rel="st height="1" width="1" ='+encodeURIComponent(<link rel="alternate"
+body, tr, input, textmeta name="robots" conmethod="post" action=">
+<a href="http://www.css" rel="stylesheet" </div></div><div classlanguage="javascript">aria-hidden="true">·<ript" type="text/javasl=0;})();
+(function(){background-image: url(/a></li><li><a href="h <li><a href="http://ator" aria-hidden="tru> <a href="http://www.language="javascript" /option>
+<option value/div></div><div class=rator" aria-hidden="tre=(new Date).getTime()português (do Brasil)организациивозможноÑтьобразованиÑрегиÑтрациивозможноÑтиобÑзательна<!DOCTYPE html PUBLIC "nt-Type" content="text/<meta http-equiv="Conteransitional//EN" "http:<html xmlns="http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = 'text/javascript';<meta name="descriptionparentNode.insertBefore<input type="hidden" najs" type="text/javascri(document).ready(functiscript type="text/javasimage" content="http://UA-Compatible" content=tml; charset=utf-8" />
+link rel="shortcut icon<link rel="stylesheet" </script>
+<script type== document.createElemen<a target="_blank" href= document.getElementsBinput type="text" name=a.type = 'text/javascrinput type="hidden" namehtml; charset=utf-8" />dtd">
+<html xmlns="http-//W3C//DTD HTML 4.01 TentsByTagName('script')input type="hidden" nam<script type="text/javas" style="display:none;">document.getElementById(=document.createElement(' type='text/javascript'input type="text" name="d.getElementsByTagName(snical" href="http://www.C//DTD HTML 4.01 Transit<style type="text/css">
+
+<style type="text/css">ional.dtd">
+<html xmlns=http-equiv="Content-Typeding="0" cellspacing="0"html; charset=utf-8" />
+ style="display:none;"><<li><a href="http://www. type='text/javascript'>деÑтельноÑтиÑоответÑтвиипроизводÑтвабезопаÑноÑтиपà¥à¤¸à¥à¤¤à¤¿à¤•à¤¾à¤•à¤¾à¤‚गà¥à¤°à¥‡à¤¸à¤‰à¤¨à¥à¤¹à¥‹à¤‚नेविधानसभाफिकà¥à¤¸à¤¿à¤‚गसà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤•à¥‰à¤ªà¥€à¤°à¤¾à¤‡à¤Ÿà¤µà¤¿à¤œà¥à¤žà¤¾à¤ªà¤¨à¤•à¤¾à¤°à¥à¤°à¤µà¤¾à¤ˆà¤¸à¤•à¥à¤°à¤¿à¤¯à¤¤à¤¾ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.c
new file mode 100644
index 000000000..f9e30417c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.c
@@ -0,0 +1,5914 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./dictionary.h"
+#include "./platform.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
+static const uint8_t kBrotliDictionaryData[] =
+{
+116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
+111,100,101,100,97,116,97,115,104,111,119,111,110,108,121,115,105,116,101,99,105
+,116,121,111,112,101,110,106,117,115,116,108,105,107,101,102,114,101,101,119,111
+,114,107,116,101,120,116,121,101,97,114,111,118,101,114,98,111,100,121,108,111,
+118,101,102,111,114,109,98,111,111,107,112,108,97,121,108,105,118,101,108,105,
+110,101,104,101,108,112,104,111,109,101,115,105,100,101,109,111,114,101,119,111,
+114,100,108,111,110,103,116,104,101,109,118,105,101,119,102,105,110,100,112,97,
+103,101,100,97,121,115,102,117,108,108,104,101,97,100,116,101,114,109,101,97,99,
+104,97,114,101,97,102,114,111,109,116,114,117,101,109,97,114,107,97,98,108,101,
+117,112,111,110,104,105,103,104,100,97,116,101,108,97,110,100,110,101,119,115,
+101,118,101,110,110,101,120,116,99,97,115,101,98,111,116,104,112,111,115,116,117
+,115,101,100,109,97,100,101,104,97,110,100,104,101,114,101,119,104,97,116,110,97
+,109,101,76,105,110,107,98,108,111,103,115,105,122,101,98,97,115,101,104,101,108
+,100,109,97,107,101,109,97,105,110,117,115,101,114,39,41,32,43,104,111,108,100,
+101,110,100,115,119,105,116,104,78,101,119,115,114,101,97,100,119,101,114,101,
+115,105,103,110,116,97,107,101,104,97,118,101,103,97,109,101,115,101,101,110,99,
+97,108,108,112,97,116,104,119,101,108,108,112,108,117,115,109,101,110,117,102,
+105,108,109,112,97,114,116,106,111,105,110,116,104,105,115,108,105,115,116,103,
+111,111,100,110,101,101,100,119,97,121,115,119,101,115,116,106,111,98,115,109,
+105,110,100,97,108,115,111,108,111,103,111,114,105,99,104,117,115,101,115,108,97
+,115,116,116,101,97,109,97,114,109,121,102,111,111,100,107,105,110,103,119,105,
+108,108,101,97,115,116,119,97,114,100,98,101,115,116,102,105,114,101,80,97,103,
+101,107,110,111,119,97,119,97,121,46,112,110,103,109,111,118,101,116,104,97,110,
+108,111,97,100,103,105,118,101,115,101,108,102,110,111,116,101,109,117,99,104,
+102,101,101,100,109,97,110,121,114,111,99,107,105,99,111,110,111,110,99,101,108,
+111,111,107,104,105,100,101,100,105,101,100,72,111,109,101,114,117,108,101,104,
+111,115,116,97,106,97,120,105,110,102,111,99,108,117,98,108,97,119,115,108,101,
+115,115,104,97,108,102,115,111,109,101,115,117,99,104,122,111,110,101,49,48,48,
+37,111,110,101,115,99,97,114,101,84,105,109,101,114,97,99,101,98,108,117,101,102
+,111,117,114,119,101,101,107,102,97,99,101,104,111,112,101,103,97,118,101,104,97
+,114,100,108,111,115,116,119,104,101,110,112,97,114,107,107,101,112,116,112,97,
+115,115,115,104,105,112,114,111,111,109,72,84,77,76,112,108,97,110,84,121,112,
+101,100,111,110,101,115,97,118,101,107,101,101,112,102,108,97,103,108,105,110,
+107,115,111,108,100,102,105,118,101,116,111,111,107,114,97,116,101,116,111,119,
+110,106,117,109,112,116,104,117,115,100,97,114,107,99,97,114,100,102,105,108,101
+,102,101,97,114,115,116,97,121,107,105,108,108,116,104,97,116,102,97,108,108,97,
+117,116,111,101,118,101,114,46,99,111,109,116,97,108,107,115,104,111,112,118,111
+,116,101,100,101,101,112,109,111,100,101,114,101,115,116,116,117,114,110,98,111,
+114,110,98,97,110,100,102,101,108,108,114,111,115,101,117,114,108,40,115,107,105
+,110,114,111,108,101,99,111,109,101,97,99,116,115,97,103,101,115,109,101,101,116
+,103,111,108,100,46,106,112,103,105,116,101,109,118,97,114,121,102,101,108,116,
+116,104,101,110,115,101,110,100,100,114,111,112,86,105,101,119,99,111,112,121,49
+,46,48,34,60,47,97,62,115,116,111,112,101,108,115,101,108,105,101,115,116,111,
+117,114,112,97,99,107,46,103,105,102,112,97,115,116,99,115,115,63,103,114,97,121
+,109,101,97,110,38,103,116,59,114,105,100,101,115,104,111,116,108,97,116,101,115
+,97,105,100,114,111,97,100,118,97,114,32,102,101,101,108,106,111,104,110,114,105
+,99,107,112,111,114,116,102,97,115,116,39,85,65,45,100,101,97,100,60,47,98,62,
+112,111,111,114,98,105,108,108,116,121,112,101,85,46,83,46,119,111,111,100,109,
+117,115,116,50,112,120,59,73,110,102,111,114,97,110,107,119,105,100,101,119,97,
+110,116,119,97,108,108,108,101,97,100,91,48,93,59,112,97,117,108,119,97,118,101,
+115,117,114,101,36,40,39,35,119,97,105,116,109,97,115,115,97,114,109,115,103,111
+,101,115,103,97,105,110,108,97,110,103,112,97,105,100,33,45,45,32,108,111,99,107
+,117,110,105,116,114,111,111,116,119,97,108,107,102,105,114,109,119,105,102,101,
+120,109,108,34,115,111,110,103,116,101,115,116,50,48,112,120,107,105,110,100,114
+,111,119,115,116,111,111,108,102,111,110,116,109,97,105,108,115,97,102,101,115,
+116,97,114,109,97,112,115,99,111,114,101,114,97,105,110,102,108,111,119,98,97,98
+,121,115,112,97,110,115,97,121,115,52,112,120,59,54,112,120,59,97,114,116,115,
+102,111,111,116,114,101,97,108,119,105,107,105,104,101,97,116,115,116,101,112,
+116,114,105,112,111,114,103,47,108,97,107,101,119,101,97,107,116,111,108,100,70,
+111,114,109,99,97,115,116,102,97,110,115,98,97,110,107,118,101,114,121,114,117,
+110,115,106,117,108,121,116,97,115,107,49,112,120,59,103,111,97,108,103,114,101,
+119,115,108,111,119,101,100,103,101,105,100,61,34,115,101,116,115,53,112,120,59,
+46,106,115,63,52,48,112,120,105,102,32,40,115,111,111,110,115,101,97,116,110,111
+,110,101,116,117,98,101,122,101,114,111,115,101,110,116,114,101,101,100,102,97,
+99,116,105,110,116,111,103,105,102,116,104,97,114,109,49,56,112,120,99,97,109,
+101,104,105,108,108,98,111,108,100,122,111,111,109,118,111,105,100,101,97,115,
+121,114,105,110,103,102,105,108,108,112,101,97,107,105,110,105,116,99,111,115,
+116,51,112,120,59,106,97,99,107,116,97,103,115,98,105,116,115,114,111,108,108,
+101,100,105,116,107,110,101,119,110,101,97,114,60,33,45,45,103,114,111,119,74,83
+,79,78,100,117,116,121,78,97,109,101,115,97,108,101,121,111,117,32,108,111,116,
+115,112,97,105,110,106,97,122,122,99,111,108,100,101,121,101,115,102,105,115,104
+,119,119,119,46,114,105,115,107,116,97,98,115,112,114,101,118,49,48,112,120,114,
+105,115,101,50,53,112,120,66,108,117,101,100,105,110,103,51,48,48,44,98,97,108,
+108,102,111,114,100,101,97,114,110,119,105,108,100,98,111,120,46,102,97,105,114,
+108,97,99,107,118,101,114,115,112,97,105,114,106,117,110,101,116,101,99,104,105,
+102,40,33,112,105,99,107,101,118,105,108,36,40,34,35,119,97,114,109,108,111,114,
+100,100,111,101,115,112,117,108,108,44,48,48,48,105,100,101,97,100,114,97,119,
+104,117,103,101,115,112,111,116,102,117,110,100,98,117,114,110,104,114,101,102,
+99,101,108,108,107,101,121,115,116,105,99,107,104,111,117,114,108,111,115,115,
+102,117,101,108,49,50,112,120,115,117,105,116,100,101,97,108,82,83,83,34,97,103,
+101,100,103,114,101,121,71,69,84,34,101,97,115,101,97,105,109,115,103,105,114,
+108,97,105,100,115,56,112,120,59,110,97,118,121,103,114,105,100,116,105,112,115,
+35,57,57,57,119,97,114,115,108,97,100,121,99,97,114,115,41,59,32,125,112,104,112
+,63,104,101,108,108,116,97,108,108,119,104,111,109,122,104,58,229,42,47,13,10,32
+,49,48,48,104,97,108,108,46,10,10,65,55,112,120,59,112,117,115,104,99,104,97,116
+,48,112,120,59,99,114,101,119,42,47,60,47,104,97,115,104,55,53,112,120,102,108,
+97,116,114,97,114,101,32,38,38,32,116,101,108,108,99,97,109,112,111,110,116,111,
+108,97,105,100,109,105,115,115,115,107,105,112,116,101,110,116,102,105,110,101,
+109,97,108,101,103,101,116,115,112,108,111,116,52,48,48,44,13,10,13,10,99,111,
+111,108,102,101,101,116,46,112,104,112,60,98,114,62,101,114,105,99,109,111,115,
+116,103,117,105,100,98,101,108,108,100,101,115,99,104,97,105,114,109,97,116,104,
+97,116,111,109,47,105,109,103,38,35,56,50,108,117,99,107,99,101,110,116,48,48,48
+,59,116,105,110,121,103,111,110,101,104,116,109,108,115,101,108,108,100,114,117,
+103,70,82,69,69,110,111,100,101,110,105,99,107,63,105,100,61,108,111,115,101,110
+,117,108,108,118,97,115,116,119,105,110,100,82,83,83,32,119,101,97,114,114,101,
+108,121,98,101,101,110,115,97,109,101,100,117,107,101,110,97,115,97,99,97,112,
+101,119,105,115,104,103,117,108,102,84,50,51,58,104,105,116,115,115,108,111,116,
+103,97,116,101,107,105,99,107,98,108,117,114,116,104,101,121,49,53,112,120,39,39
+,41,59,41,59,34,62,109,115,105,101,119,105,110,115,98,105,114,100,115,111,114,
+116,98,101,116,97,115,101,101,107,84,49,56,58,111,114,100,115,116,114,101,101,
+109,97,108,108,54,48,112,120,102,97,114,109,226,128,153,115,98,111,121,115,91,48
+,93,46,39,41,59,34,80,79,83,84,98,101,97,114,107,105,100,115,41,59,125,125,109,
+97,114,121,116,101,110,100,40,85,75,41,113,117,97,100,122,104,58,230,45,115,105,
+122,45,45,45,45,112,114,111,112,39,41,59,13,108,105,102,116,84,49,57,58,118,105,
+99,101,97,110,100,121,100,101,98,116,62,82,83,83,112,111,111,108,110,101,99,107,
+98,108,111,119,84,49,54,58,100,111,111,114,101,118,97,108,84,49,55,58,108,101,
+116,115,102,97,105,108,111,114,97,108,112,111,108,108,110,111,118,97,99,111,108,
+115,103,101,110,101,32,226,128,148,115,111,102,116,114,111,109,101,116,105,108,
+108,114,111,115,115,60,104,51,62,112,111,117,114,102,97,100,101,112,105,110,107,
+60,116,114,62,109,105,110,105,41,124,33,40,109,105,110,101,122,104,58,232,98,97,
+114,115,104,101,97,114,48,48,41,59,109,105,108,107,32,45,45,62,105,114,111,110,
+102,114,101,100,100,105,115,107,119,101,110,116,115,111,105,108,112,117,116,115,
+47,106,115,47,104,111,108,121,84,50,50,58,73,83,66,78,84,50,48,58,97,100,97,109,
+115,101,101,115,60,104,50,62,106,115,111,110,39,44,32,39,99,111,110,116,84,50,49
+,58,32,82,83,83,108,111,111,112,97,115,105,97,109,111,111,110,60,47,112,62,115,
+111,117,108,76,73,78,69,102,111,114,116,99,97,114,116,84,49,52,58,60,104,49,62,
+56,48,112,120,33,45,45,60,57,112,120,59,84,48,52,58,109,105,107,101,58,52,54,90,
+110,105,99,101,105,110,99,104,89,111,114,107,114,105,99,101,122,104,58,228,39,41
+,41,59,112,117,114,101,109,97,103,101,112,97,114,97,116,111,110,101,98,111,110,
+100,58,51,55,90,95,111,102,95,39,93,41,59,48,48,48,44,122,104,58,231,116,97,110,
+107,121,97,114,100,98,111,119,108,98,117,115,104,58,53,54,90,74,97,118,97,51,48,
+112,120,10,124,125,10,37,67,51,37,58,51,52,90,106,101,102,102,69,88,80,73,99,97,
+115,104,118,105,115,97,103,111,108,102,115,110,111,119,122,104,58,233,113,117,
+101,114,46,99,115,115,115,105,99,107,109,101,97,116,109,105,110,46,98,105,110,
+100,100,101,108,108,104,105,114,101,112,105,99,115,114,101,110,116,58,51,54,90,
+72,84,84,80,45,50,48,49,102,111,116,111,119,111,108,102,69,78,68,32,120,98,111,
+120,58,53,52,90,66,79,68,89,100,105,99,107,59,10,125,10,101,120,105,116,58,51,53
+,90,118,97,114,115,98,101,97,116,39,125,41,59,100,105,101,116,57,57,57,59,97,110
+,110,101,125,125,60,47,91,105,93,46,76,97,110,103,107,109,194,178,119,105,114,
+101,116,111,121,115,97,100,100,115,115,101,97,108,97,108,101,120,59,10,9,125,101
+,99,104,111,110,105,110,101,46,111,114,103,48,48,53,41,116,111,110,121,106,101,
+119,115,115,97,110,100,108,101,103,115,114,111,111,102,48,48,48,41,32,50,48,48,
+119,105,110,101,103,101,97,114,100,111,103,115,98,111,111,116,103,97,114,121,99,
+117,116,115,116,121,108,101,116,101,109,112,116,105,111,110,46,120,109,108,99,
+111,99,107,103,97,110,103,36,40,39,46,53,48,112,120,80,104,46,68,109,105,115,99,
+97,108,97,110,108,111,97,110,100,101,115,107,109,105,108,101,114,121,97,110,117,
+110,105,120,100,105,115,99,41,59,125,10,100,117,115,116,99,108,105,112,41,46,10,
+10,55,48,112,120,45,50,48,48,68,86,68,115,55,93,62,60,116,97,112,101,100,101,109
+,111,105,43,43,41,119,97,103,101,101,117,114,111,112,104,105,108,111,112,116,115
+,104,111,108,101,70,65,81,115,97,115,105,110,45,50,54,84,108,97,98,115,112,101,
+116,115,85,82,76,32,98,117,108,107,99,111,111,107,59,125,13,10,72,69,65,68,91,48
+,93,41,97,98,98,114,106,117,97,110,40,49,57,56,108,101,115,104,116,119,105,110,
+60,47,105,62,115,111,110,121,103,117,121,115,102,117,99,107,112,105,112,101,124,
+45,10,33,48,48,50,41,110,100,111,119,91,49,93,59,91,93,59,10,76,111,103,32,115,
+97,108,116,13,10,9,9,98,97,110,103,116,114,105,109,98,97,116,104,41,123,13,10,48
+,48,112,120,10,125,41,59,107,111,58,236,102,101,101,115,97,100,62,13,115,58,47,
+47,32,91,93,59,116,111,108,108,112,108,117,103,40,41,123,10,123,13,10,32,46,106,
+115,39,50,48,48,112,100,117,97,108,98,111,97,116,46,74,80,71,41,59,10,125,113,
+117,111,116,41,59,10,10,39,41,59,10,13,10,125,13,50,48,49,52,50,48,49,53,50,48,
+49,54,50,48,49,55,50,48,49,56,50,48,49,57,50,48,50,48,50,48,50,49,50,48,50,50,50
+,48,50,51,50,48,50,52,50,48,50,53,50,48,50,54,50,48,50,55,50,48,50,56,50,48,50,
+57,50,48,51,48,50,48,51,49,50,48,51,50,50,48,51,51,50,48,51,52,50,48,51,53,50,48
+,51,54,50,48,51,55,50,48,49,51,50,48,49,50,50,48,49,49,50,48,49,48,50,48,48,57,
+50,48,48,56,50,48,48,55,50,48,48,54,50,48,48,53,50,48,48,52,50,48,48,51,50,48,48
+,50,50,48,48,49,50,48,48,48,49,57,57,57,49,57,57,56,49,57,57,55,49,57,57,54,49,
+57,57,53,49,57,57,52,49,57,57,51,49,57,57,50,49,57,57,49,49,57,57,48,49,57,56,57
+,49,57,56,56,49,57,56,55,49,57,56,54,49,57,56,53,49,57,56,52,49,57,56,51,49,57,
+56,50,49,57,56,49,49,57,56,48,49,57,55,57,49,57,55,56,49,57,55,55,49,57,55,54,49
+,57,55,53,49,57,55,52,49,57,55,51,49,57,55,50,49,57,55,49,49,57,55,48,49,57,54,
+57,49,57,54,56,49,57,54,55,49,57,54,54,49,57,54,53,49,57,54,52,49,57,54,51,49,57
+,54,50,49,57,54,49,49,57,54,48,49,57,53,57,49,57,53,56,49,57,53,55,49,57,53,54,
+49,57,53,53,49,57,53,52,49,57,53,51,49,57,53,50,49,57,53,49,49,57,53,48,49,48,48
+,48,49,48,50,52,49,51,57,52,48,48,48,48,57,57,57,57,99,111,109,111,109,195,161,
+115,101,115,116,101,101,115,116,97,112,101,114,111,116,111,100,111,104,97,99,101
+,99,97,100,97,97,195,177,111,98,105,101,110,100,195,173,97,97,115,195,173,118,
+105,100,97,99,97,115,111,111,116,114,111,102,111,114,111,115,111,108,111,111,116
+,114,97,99,117,97,108,100,105,106,111,115,105,100,111,103,114,97,110,116,105,112
+,111,116,101,109,97,100,101,98,101,97,108,103,111,113,117,195,169,101,115,116,
+111,110,97,100,97,116,114,101,115,112,111,99,111,99,97,115,97,98,97,106,111,116,
+111,100,97,115,105,110,111,97,103,117,97,112,117,101,115,117,110,111,115,97,110,
+116,101,100,105,99,101,108,117,105,115,101,108,108,97,109,97,121,111,122,111,110
+,97,97,109,111,114,112,105,115,111,111,98,114,97,99,108,105,99,101,108,108,111,
+100,105,111,115,104,111,114,97,99,97,115,105,208,183,208,176,208,189,208,176,208
+,190,208,188,209,128,208,176,209,128,209,131,209,130,208,176,208,189,208,181,208
+,191,208,190,208,190,209,130,208,184,208,183,208,189,208,190,208,180,208,190,209
+,130,208,190,208,182,208,181,208,190,208,189,208,184,209,133,208,157,208,176,208
+,181,208,181,208,177,209,139,208,188,209,139,208,146,209,139,209,129,208,190,208
+,178,209,139,208,178,208,190,208,157,208,190,208,190,208,177,208,159,208,190,208
+,187,208,184,208,189,208,184,208,160,208,164,208,157,208,181,208,156,209,139,209
+,130,209,139,208,158,208,189,208,184,208,188,208,180,208,176,208,151,208,176,208
+,148,208,176,208,157,209,131,208,158,208,177,209,130,208,181,208,152,208,183,208
+,181,208,185,208,189,209,131,208,188,208,188,208,162,209,139,209,131,208,182,217
+,129,217,138,216,163,217,134,217,133,216,167,217,133,216,185,217,131,217,132,216
+,163,217,136,216,177,216,175,217,138,216,167,217,129,217,137,217,135,217,136,217
+,132,217,133,217,132,217,131,216,167,217,136,217,132,217,135,216,168,216,179,216
+,167,217,132,216,165,217,134,217,135,217,138,216,163,217,138,217,130,216,175,217
+,135,217,132,216,171,217,133,216,168,217,135,217,132,217,136,217,132,217,138,216
+,168,217,132,216,167,217,138,216,168,217,131,216,180,217,138,216,167,217,133,216
+,163,217,133,217,134,216,170,216,168,217,138,217,132,217,134,216,173,216,168,217
+,135,217,133,217,133,216,180,217,136,216,180,102,105,114,115,116,118,105,100,101
+,111,108,105,103,104,116,119,111,114,108,100,109,101,100,105,97,119,104,105,116,
+101,99,108,111,115,101,98,108,97,99,107,114,105,103,104,116,115,109,97,108,108,
+98,111,111,107,115,112,108,97,99,101,109,117,115,105,99,102,105,101,108,100,111,
+114,100,101,114,112,111,105,110,116,118,97,108,117,101,108,101,118,101,108,116,
+97,98,108,101,98,111,97,114,100,104,111,117,115,101,103,114,111,117,112,119,111,
+114,107,115,121,101,97,114,115,115,116,97,116,101,116,111,100,97,121,119,97,116,
+101,114,115,116,97,114,116,115,116,121,108,101,100,101,97,116,104,112,111,119,
+101,114,112,104,111,110,101,110,105,103,104,116,101,114,114,111,114,105,110,112,
+117,116,97,98,111,117,116,116,101,114,109,115,116,105,116,108,101,116,111,111,
+108,115,101,118,101,110,116,108,111,99,97,108,116,105,109,101,115,108,97,114,103
+,101,119,111,114,100,115,103,97,109,101,115,115,104,111,114,116,115,112,97,99,
+101,102,111,99,117,115,99,108,101,97,114,109,111,100,101,108,98,108,111,99,107,
+103,117,105,100,101,114,97,100,105,111,115,104,97,114,101,119,111,109,101,110,97
+,103,97,105,110,109,111,110,101,121,105,109,97,103,101,110,97,109,101,115,121,
+111,117,110,103,108,105,110,101,115,108,97,116,101,114,99,111,108,111,114,103,
+114,101,101,110,102,114,111,110,116,38,97,109,112,59,119,97,116,99,104,102,111,
+114,99,101,112,114,105,99,101,114,117,108,101,115,98,101,103,105,110,97,102,116,
+101,114,118,105,115,105,116,105,115,115,117,101,97,114,101,97,115,98,101,108,111
+,119,105,110,100,101,120,116,111,116,97,108,104,111,117,114,115,108,97,98,101,
+108,112,114,105,110,116,112,114,101,115,115,98,117,105,108,116,108,105,110,107,
+115,115,112,101,101,100,115,116,117,100,121,116,114,97,100,101,102,111,117,110,
+100,115,101,110,115,101,117,110,100,101,114,115,104,111,119,110,102,111,114,109,
+115,114,97,110,103,101,97,100,100,101,100,115,116,105,108,108,109,111,118,101,
+100,116,97,107,101,110,97,98,111,118,101,102,108,97,115,104,102,105,120,101,100,
+111,102,116,101,110,111,116,104,101,114,118,105,101,119,115,99,104,101,99,107,
+108,101,103,97,108,114,105,118,101,114,105,116,101,109,115,113,117,105,99,107,
+115,104,97,112,101,104,117,109,97,110,101,120,105,115,116,103,111,105,110,103,
+109,111,118,105,101,116,104,105,114,100,98,97,115,105,99,112,101,97,99,101,115,
+116,97,103,101,119,105,100,116,104,108,111,103,105,110,105,100,101,97,115,119,
+114,111,116,101,112,97,103,101,115,117,115,101,114,115,100,114,105,118,101,115,
+116,111,114,101,98,114,101,97,107,115,111,117,116,104,118,111,105,99,101,115,105
+,116,101,115,109,111,110,116,104,119,104,101,114,101,98,117,105,108,100,119,104,
+105,99,104,101,97,114,116,104,102,111,114,117,109,116,104,114,101,101,115,112,
+111,114,116,112,97,114,116,121,67,108,105,99,107,108,111,119,101,114,108,105,118
+,101,115,99,108,97,115,115,108,97,121,101,114,101,110,116,114,121,115,116,111,
+114,121,117,115,97,103,101,115,111,117,110,100,99,111,117,114,116,121,111,117,
+114,32,98,105,114,116,104,112,111,112,117,112,116,121,112,101,115,97,112,112,108
+,121,73,109,97,103,101,98,101,105,110,103,117,112,112,101,114,110,111,116,101,
+115,101,118,101,114,121,115,104,111,119,115,109,101,97,110,115,101,120,116,114,
+97,109,97,116,99,104,116,114,97,99,107,107,110,111,119,110,101,97,114,108,121,98
+,101,103,97,110,115,117,112,101,114,112,97,112,101,114,110,111,114,116,104,108,
+101,97,114,110,103,105,118,101,110,110,97,109,101,100,101,110,100,101,100,84,101
+,114,109,115,112,97,114,116,115,71,114,111,117,112,98,114,97,110,100,117,115,105
+,110,103,119,111,109,97,110,102,97,108,115,101,114,101,97,100,121,97,117,100,105
+,111,116,97,107,101,115,119,104,105,108,101,46,99,111,109,47,108,105,118,101,100
+,99,97,115,101,115,100,97,105,108,121,99,104,105,108,100,103,114,101,97,116,106,
+117,100,103,101,116,104,111,115,101,117,110,105,116,115,110,101,118,101,114,98,
+114,111,97,100,99,111,97,115,116,99,111,118,101,114,97,112,112,108,101,102,105,
+108,101,115,99,121,99,108,101,115,99,101,110,101,112,108,97,110,115,99,108,105,
+99,107,119,114,105,116,101,113,117,101,101,110,112,105,101,99,101,101,109,97,105
+,108,102,114,97,109,101,111,108,100,101,114,112,104,111,116,111,108,105,109,105,
+116,99,97,99,104,101,99,105,118,105,108,115,99,97,108,101,101,110,116,101,114,
+116,104,101,109,101,116,104,101,114,101,116,111,117,99,104,98,111,117,110,100,
+114,111,121,97,108,97,115,107,101,100,119,104,111,108,101,115,105,110,99,101,115
+,116,111,99,107,32,110,97,109,101,102,97,105,116,104,104,101,97,114,116,101,109,
+112,116,121,111,102,102,101,114,115,99,111,112,101,111,119,110,101,100,109,105,
+103,104,116,97,108,98,117,109,116,104,105,110,107,98,108,111,111,100,97,114,114,
+97,121,109,97,106,111,114,116,114,117,115,116,99,97,110,111,110,117,110,105,111,
+110,99,111,117,110,116,118,97,108,105,100,115,116,111,110,101,83,116,121,108,101
+,76,111,103,105,110,104,97,112,112,121,111,99,99,117,114,108,101,102,116,58,102,
+114,101,115,104,113,117,105,116,101,102,105,108,109,115,103,114,97,100,101,110,
+101,101,100,115,117,114,98,97,110,102,105,103,104,116,98,97,115,105,115,104,111,
+118,101,114,97,117,116,111,59,114,111,117,116,101,46,104,116,109,108,109,105,120
+,101,100,102,105,110,97,108,89,111,117,114,32,115,108,105,100,101,116,111,112,
+105,99,98,114,111,119,110,97,108,111,110,101,100,114,97,119,110,115,112,108,105,
+116,114,101,97,99,104,82,105,103,104,116,100,97,116,101,115,109,97,114,99,104,
+113,117,111,116,101,103,111,111,100,115,76,105,110,107,115,100,111,117,98,116,97
+,115,121,110,99,116,104,117,109,98,97,108,108,111,119,99,104,105,101,102,121,111
+,117,116,104,110,111,118,101,108,49,48,112,120,59,115,101,114,118,101,117,110,
+116,105,108,104,97,110,100,115,67,104,101,99,107,83,112,97,99,101,113,117,101,
+114,121,106,97,109,101,115,101,113,117,97,108,116,119,105,99,101,48,44,48,48,48,
+83,116,97,114,116,112,97,110,101,108,115,111,110,103,115,114,111,117,110,100,101
+,105,103,104,116,115,104,105,102,116,119,111,114,116,104,112,111,115,116,115,108
+,101,97,100,115,119,101,101,107,115,97,118,111,105,100,116,104,101,115,101,109,
+105,108,101,115,112,108,97,110,101,115,109,97,114,116,97,108,112,104,97,112,108,
+97,110,116,109,97,114,107,115,114,97,116,101,115,112,108,97,121,115,99,108,97,
+105,109,115,97,108,101,115,116,101,120,116,115,115,116,97,114,115,119,114,111,
+110,103,60,47,104,51,62,116,104,105,110,103,46,111,114,103,47,109,117,108,116,
+105,104,101,97,114,100,80,111,119,101,114,115,116,97,110,100,116,111,107,101,110
+,115,111,108,105,100,40,116,104,105,115,98,114,105,110,103,115,104,105,112,115,
+115,116,97,102,102,116,114,105,101,100,99,97,108,108,115,102,117,108,108,121,102
+,97,99,116,115,97,103,101,110,116,84,104,105,115,32,47,47,45,45,62,97,100,109,
+105,110,101,103,121,112,116,69,118,101,110,116,49,53,112,120,59,69,109,97,105,
+108,116,114,117,101,34,99,114,111,115,115,115,112,101,110,116,98,108,111,103,115
+,98,111,120,34,62,110,111,116,101,100,108,101,97,118,101,99,104,105,110,97,115,
+105,122,101,115,103,117,101,115,116,60,47,104,52,62,114,111,98,111,116,104,101,
+97,118,121,116,114,117,101,44,115,101,118,101,110,103,114,97,110,100,99,114,105,
+109,101,115,105,103,110,115,97,119,97,114,101,100,97,110,99,101,112,104,97,115,
+101,62,60,33,45,45,101,110,95,85,83,38,35,51,57,59,50,48,48,112,120,95,110,97,
+109,101,108,97,116,105,110,101,110,106,111,121,97,106,97,120,46,97,116,105,111,
+110,115,109,105,116,104,85,46,83,46,32,104,111,108,100,115,112,101,116,101,114,
+105,110,100,105,97,110,97,118,34,62,99,104,97,105,110,115,99,111,114,101,99,111,
+109,101,115,100,111,105,110,103,112,114,105,111,114,83,104,97,114,101,49,57,57,
+48,115,114,111,109,97,110,108,105,115,116,115,106,97,112,97,110,102,97,108,108,
+115,116,114,105,97,108,111,119,110,101,114,97,103,114,101,101,60,47,104,50,62,97
+,98,117,115,101,97,108,101,114,116,111,112,101,114,97,34,45,47,47,87,99,97,114,
+100,115,104,105,108,108,115,116,101,97,109,115,80,104,111,116,111,116,114,117,
+116,104,99,108,101,97,110,46,112,104,112,63,115,97,105,110,116,109,101,116,97,
+108,108,111,117,105,115,109,101,97,110,116,112,114,111,111,102,98,114,105,101,
+102,114,111,119,34,62,103,101,110,114,101,116,114,117,99,107,108,111,111,107,115
+,86,97,108,117,101,70,114,97,109,101,46,110,101,116,47,45,45,62,10,60,116,114,
+121,32,123,10,118,97,114,32,109,97,107,101,115,99,111,115,116,115,112,108,97,105
+,110,97,100,117,108,116,113,117,101,115,116,116,114,97,105,110,108,97,98,111,114
+,104,101,108,112,115,99,97,117,115,101,109,97,103,105,99,109,111,116,111,114,116
+,104,101,105,114,50,53,48,112,120,108,101,97,115,116,115,116,101,112,115,67,111,
+117,110,116,99,111,117,108,100,103,108,97,115,115,115,105,100,101,115,102,117,
+110,100,115,104,111,116,101,108,97,119,97,114,100,109,111,117,116,104,109,111,
+118,101,115,112,97,114,105,115,103,105,118,101,115,100,117,116,99,104,116,101,
+120,97,115,102,114,117,105,116,110,117,108,108,44,124,124,91,93,59,116,111,112,
+34,62,10,60,33,45,45,80,79,83,84,34,111,99,101,97,110,60,98,114,47,62,102,108,
+111,111,114,115,112,101,97,107,100,101,112,116,104,32,115,105,122,101,98,97,110,
+107,115,99,97,116,99,104,99,104,97,114,116,50,48,112,120,59,97,108,105,103,110,
+100,101,97,108,115,119,111,117,108,100,53,48,112,120,59,117,114,108,61,34,112,97
+,114,107,115,109,111,117,115,101,77,111,115,116,32,46,46,46,60,47,97,109,111,110
+,103,98,114,97,105,110,98,111,100,121,32,110,111,110,101,59,98,97,115,101,100,99
+,97,114,114,121,100,114,97,102,116,114,101,102,101,114,112,97,103,101,95,104,111
+,109,101,46,109,101,116,101,114,100,101,108,97,121,100,114,101,97,109,112,114,
+111,118,101,106,111,105,110,116,60,47,116,114,62,100,114,117,103,115,60,33,45,45
+,32,97,112,114,105,108,105,100,101,97,108,97,108,108,101,110,101,120,97,99,116,
+102,111,114,116,104,99,111,100,101,115,108,111,103,105,99,86,105,101,119,32,115,
+101,101,109,115,98,108,97,110,107,112,111,114,116,115,32,40,50,48,48,115,97,118,
+101,100,95,108,105,110,107,103,111,97,108,115,103,114,97,110,116,103,114,101,101
+,107,104,111,109,101,115,114,105,110,103,115,114,97,116,101,100,51,48,112,120,59
+,119,104,111,115,101,112,97,114,115,101,40,41,59,34,32,66,108,111,99,107,108,105
+,110,117,120,106,111,110,101,115,112,105,120,101,108,39,41,59,34,62,41,59,105,
+102,40,45,108,101,102,116,100,97,118,105,100,104,111,114,115,101,70,111,99,117,
+115,114,97,105,115,101,98,111,120,101,115,84,114,97,99,107,101,109,101,110,116,
+60,47,101,109,62,98,97,114,34,62,46,115,114,99,61,116,111,119,101,114,97,108,116
+,61,34,99,97,98,108,101,104,101,110,114,121,50,52,112,120,59,115,101,116,117,112
+,105,116,97,108,121,115,104,97,114,112,109,105,110,111,114,116,97,115,116,101,
+119,97,110,116,115,116,104,105,115,46,114,101,115,101,116,119,104,101,101,108,
+103,105,114,108,115,47,99,115,115,47,49,48,48,37,59,99,108,117,98,115,115,116,
+117,102,102,98,105,98,108,101,118,111,116,101,115,32,49,48,48,48,107,111,114,101
+,97,125,41,59,13,10,98,97,110,100,115,113,117,101,117,101,61,32,123,125,59,56,48
+,112,120,59,99,107,105,110,103,123,13,10,9,9,97,104,101,97,100,99,108,111,99,107
+,105,114,105,115,104,108,105,107,101,32,114,97,116,105,111,115,116,97,116,115,70
+,111,114,109,34,121,97,104,111,111,41,91,48,93,59,65,98,111,117,116,102,105,110,
+100,115,60,47,104,49,62,100,101,98,117,103,116,97,115,107,115,85,82,76,32,61,99,
+101,108,108,115,125,41,40,41,59,49,50,112,120,59,112,114,105,109,101,116,101,108
+,108,115,116,117,114,110,115,48,120,54,48,48,46,106,112,103,34,115,112,97,105,
+110,98,101,97,99,104,116,97,120,101,115,109,105,99,114,111,97,110,103,101,108,45
+,45,62,60,47,103,105,102,116,115,115,116,101,118,101,45,108,105,110,107,98,111,
+100,121,46,125,41,59,10,9,109,111,117,110,116,32,40,49,57,57,70,65,81,60,47,114,
+111,103,101,114,102,114,97,110,107,67,108,97,115,115,50,56,112,120,59,102,101,
+101,100,115,60,104,49,62,60,115,99,111,116,116,116,101,115,116,115,50,50,112,120
+,59,100,114,105,110,107,41,32,124,124,32,108,101,119,105,115,115,104,97,108,108,
+35,48,51,57,59,32,102,111,114,32,108,111,118,101,100,119,97,115,116,101,48,48,
+112,120,59,106,97,58,227,130,115,105,109,111,110,60,102,111,110,116,114,101,112,
+108,121,109,101,101,116,115,117,110,116,101,114,99,104,101,97,112,116,105,103,
+104,116,66,114,97,110,100,41,32,33,61,32,100,114,101,115,115,99,108,105,112,115,
+114,111,111,109,115,111,110,107,101,121,109,111,98,105,108,109,97,105,110,46,78,
+97,109,101,32,112,108,97,116,101,102,117,110,110,121,116,114,101,101,115,99,111,
+109,47,34,49,46,106,112,103,119,109,111,100,101,112,97,114,97,109,83,84,65,82,84
+,108,101,102,116,32,105,100,100,101,110,44,32,50,48,49,41,59,10,125,10,102,111,
+114,109,46,118,105,114,117,115,99,104,97,105,114,116,114,97,110,115,119,111,114,
+115,116,80,97,103,101,115,105,116,105,111,110,112,97,116,99,104,60,33,45,45,10,
+111,45,99,97,99,102,105,114,109,115,116,111,117,114,115,44,48,48,48,32,97,115,
+105,97,110,105,43,43,41,123,97,100,111,98,101,39,41,91,48,93,105,100,61,49,48,98
+,111,116,104,59,109,101,110,117,32,46,50,46,109,105,46,112,110,103,34,107,101,
+118,105,110,99,111,97,99,104,67,104,105,108,100,98,114,117,99,101,50,46,106,112,
+103,85,82,76,41,43,46,106,112,103,124,115,117,105,116,101,115,108,105,99,101,104
+,97,114,114,121,49,50,48,34,32,115,119,101,101,116,116,114,62,13,10,110,97,109,
+101,61,100,105,101,103,111,112,97,103,101,32,115,119,105,115,115,45,45,62,10,10,
+35,102,102,102,59,34,62,76,111,103,46,99,111,109,34,116,114,101,97,116,115,104,
+101,101,116,41,32,38,38,32,49,52,112,120,59,115,108,101,101,112,110,116,101,110,
+116,102,105,108,101,100,106,97,58,227,131,105,100,61,34,99,78,97,109,101,34,119,
+111,114,115,101,115,104,111,116,115,45,98,111,120,45,100,101,108,116,97,10,38,
+108,116,59,98,101,97,114,115,58,52,56,90,60,100,97,116,97,45,114,117,114,97,108,
+60,47,97,62,32,115,112,101,110,100,98,97,107,101,114,115,104,111,112,115,61,32,
+34,34,59,112,104,112,34,62,99,116,105,111,110,49,51,112,120,59,98,114,105,97,110
+,104,101,108,108,111,115,105,122,101,61,111,61,37,50,70,32,106,111,105,110,109,
+97,121,98,101,60,105,109,103,32,105,109,103,34,62,44,32,102,106,115,105,109,103,
+34,32,34,41,91,48,93,77,84,111,112,66,84,121,112,101,34,110,101,119,108,121,68,
+97,110,115,107,99,122,101,99,104,116,114,97,105,108,107,110,111,119,115,60,47,
+104,53,62,102,97,113,34,62,122,104,45,99,110,49,48,41,59,10,45,49,34,41,59,116,
+121,112,101,61,98,108,117,101,115,116,114,117,108,121,100,97,118,105,115,46,106,
+115,39,59,62,13,10,60,33,115,116,101,101,108,32,121,111,117,32,104,50,62,13,10,
+102,111,114,109,32,106,101,115,117,115,49,48,48,37,32,109,101,110,117,46,13,10,9
+,13,10,119,97,108,101,115,114,105,115,107,115,117,109,101,110,116,100,100,105,
+110,103,98,45,108,105,107,116,101,97,99,104,103,105,102,34,32,118,101,103,97,115
+,100,97,110,115,107,101,101,115,116,105,115,104,113,105,112,115,117,111,109,105,
+115,111,98,114,101,100,101,115,100,101,101,110,116,114,101,116,111,100,111,115,
+112,117,101,100,101,97,195,177,111,115,101,115,116,195,161,116,105,101,110,101,
+104,97,115,116,97,111,116,114,111,115,112,97,114,116,101,100,111,110,100,101,110
+,117,101,118,111,104,97,99,101,114,102,111,114,109,97,109,105,115,109,111,109,
+101,106,111,114,109,117,110,100,111,97,113,117,195,173,100,195,173,97,115,115,
+195,179,108,111,97,121,117,100,97,102,101,99,104,97,116,111,100,97,115,116,97,
+110,116,111,109,101,110,111,115,100,97,116,111,115,111,116,114,97,115,115,105,
+116,105,111,109,117,99,104,111,97,104,111,114,97,108,117,103,97,114,109,97,121,
+111,114,101,115,116,111,115,104,111,114,97,115,116,101,110,101,114,97,110,116,
+101,115,102,111,116,111,115,101,115,116,97,115,112,97,195,173,115,110,117,101,
+118,97,115,97,108,117,100,102,111,114,111,115,109,101,100,105,111,113,117,105,
+101,110,109,101,115,101,115,112,111,100,101,114,99,104,105,108,101,115,101,114,
+195,161,118,101,99,101,115,100,101,99,105,114,106,111,115,195,169,101,115,116,97
+,114,118,101,110,116,97,103,114,117,112,111,104,101,99,104,111,101,108,108,111,
+115,116,101,110,103,111,97,109,105,103,111,99,111,115,97,115,110,105,118,101,108
+,103,101,110,116,101,109,105,115,109,97,97,105,114,101,115,106,117,108,105,111,
+116,101,109,97,115,104,97,99,105,97,102,97,118,111,114,106,117,110,105,111,108,
+105,98,114,101,112,117,110,116,111,98,117,101,110,111,97,117,116,111,114,97,98,
+114,105,108,98,117,101,110,97,116,101,120,116,111,109,97,114,122,111,115,97,98,
+101,114,108,105,115,116,97,108,117,101,103,111,99,195,179,109,111,101,110,101,
+114,111,106,117,101,103,111,112,101,114,195,186,104,97,98,101,114,101,115,116,
+111,121,110,117,110,99,97,109,117,106,101,114,118,97,108,111,114,102,117,101,114
+,97,108,105,98,114,111,103,117,115,116,97,105,103,117,97,108,118,111,116,111,115
+,99,97,115,111,115,103,117,195,173,97,112,117,101,100,111,115,111,109,111,115,97
+,118,105,115,111,117,115,116,101,100,100,101,98,101,110,110,111,99,104,101,98,
+117,115,99,97,102,97,108,116,97,101,117,114,111,115,115,101,114,105,101,100,105,
+99,104,111,99,117,114,115,111,99,108,97,118,101,99,97,115,97,115,108,101,195,179
+,110,112,108,97,122,111,108,97,114,103,111,111,98,114,97,115,118,105,115,116,97,
+97,112,111,121,111,106,117,110,116,111,116,114,97,116,97,118,105,115,116,111,99,
+114,101,97,114,99,97,109,112,111,104,101,109,111,115,99,105,110,99,111,99,97,114
+,103,111,112,105,115,111,115,111,114,100,101,110,104,97,99,101,110,195,161,114,
+101,97,100,105,115,99,111,112,101,100,114,111,99,101,114,99,97,112,117,101,100,
+97,112,97,112,101,108,109,101,110,111,114,195,186,116,105,108,99,108,97,114,111,
+106,111,114,103,101,99,97,108,108,101,112,111,110,101,114,116,97,114,100,101,110
+,97,100,105,101,109,97,114,99,97,115,105,103,117,101,101,108,108,97,115,115,105,
+103,108,111,99,111,99,104,101,109,111,116,111,115,109,97,100,114,101,99,108,97,
+115,101,114,101,115,116,111,110,105,195,177,111,113,117,101,100,97,112,97,115,97
+,114,98,97,110,99,111,104,105,106,111,115,118,105,97,106,101,112,97,98,108,111,
+195,169,115,116,101,118,105,101,110,101,114,101,105,110,111,100,101,106,97,114,
+102,111,110,100,111,99,97,110,97,108,110,111,114,116,101,108,101,116,114,97,99,
+97,117,115,97,116,111,109,97,114,109,97,110,111,115,108,117,110,101,115,97,117,
+116,111,115,118,105,108,108,97,118,101,110,100,111,112,101,115,97,114,116,105,
+112,111,115,116,101,110,103,97,109,97,114,99,111,108,108,101,118,97,112,97,100,
+114,101,117,110,105,100,111,118,97,109,111,115,122,111,110,97,115,97,109,98,111,
+115,98,97,110,100,97,109,97,114,105,97,97,98,117,115,111,109,117,99,104,97,115,
+117,98,105,114,114,105,111,106,97,118,105,118,105,114,103,114,97,100,111,99,104,
+105,99,97,97,108,108,195,173,106,111,118,101,110,100,105,99,104,97,101,115,116,
+97,110,116,97,108,101,115,115,97,108,105,114,115,117,101,108,111,112,101,115,111
+,115,102,105,110,101,115,108,108,97,109,97,98,117,115,99,111,195,169,115,116,97,
+108,108,101,103,97,110,101,103,114,111,112,108,97,122,97,104,117,109,111,114,112
+,97,103,97,114,106,117,110,116,97,100,111,98,108,101,105,115,108,97,115,98,111,
+108,115,97,98,97,195,177,111,104,97,98,108,97,108,117,99,104,97,195,129,114,101,
+97,100,105,99,101,110,106,117,103,97,114,110,111,116,97,115,118,97,108,108,101,
+97,108,108,195,161,99,97,114,103,97,100,111,108,111,114,97,98,97,106,111,101,115
+,116,195,169,103,117,115,116,111,109,101,110,116,101,109,97,114,105,111,102,105,
+114,109,97,99,111,115,116,111,102,105,99,104,97,112,108,97,116,97,104,111,103,97
+,114,97,114,116,101,115,108,101,121,101,115,97,113,117,101,108,109,117,115,101,
+111,98,97,115,101,115,112,111,99,111,115,109,105,116,97,100,99,105,101,108,111,
+99,104,105,99,111,109,105,101,100,111,103,97,110,97,114,115,97,110,116,111,101,
+116,97,112,97,100,101,98,101,115,112,108,97,121,97,114,101,100,101,115,115,105,
+101,116,101,99,111,114,116,101,99,111,114,101,97,100,117,100,97,115,100,101,115,
+101,111,118,105,101,106,111,100,101,115,101,97,97,103,117,97,115,38,113,117,111,
+116,59,100,111,109,97,105,110,99,111,109,109,111,110,115,116,97,116,117,115,101,
+118,101,110,116,115,109,97,115,116,101,114,115,121,115,116,101,109,97,99,116,105
+,111,110,98,97,110,110,101,114,114,101,109,111,118,101,115,99,114,111,108,108,
+117,112,100,97,116,101,103,108,111,98,97,108,109,101,100,105,117,109,102,105,108
+,116,101,114,110,117,109,98,101,114,99,104,97,110,103,101,114,101,115,117,108,
+116,112,117,98,108,105,99,115,99,114,101,101,110,99,104,111,111,115,101,110,111,
+114,109,97,108,116,114,97,118,101,108,105,115,115,117,101,115,115,111,117,114,99
+,101,116,97,114,103,101,116,115,112,114,105,110,103,109,111,100,117,108,101,109,
+111,98,105,108,101,115,119,105,116,99,104,112,104,111,116,111,115,98,111,114,100
+,101,114,114,101,103,105,111,110,105,116,115,101,108,102,115,111,99,105,97,108,
+97,99,116,105,118,101,99,111,108,117,109,110,114,101,99,111,114,100,102,111,108,
+108,111,119,116,105,116,108,101,62,101,105,116,104,101,114,108,101,110,103,116,
+104,102,97,109,105,108,121,102,114,105,101,110,100,108,97,121,111,117,116,97,117
+,116,104,111,114,99,114,101,97,116,101,114,101,118,105,101,119,115,117,109,109,
+101,114,115,101,114,118,101,114,112,108,97,121,101,100,112,108,97,121,101,114,
+101,120,112,97,110,100,112,111,108,105,99,121,102,111,114,109,97,116,100,111,117
+,98,108,101,112,111,105,110,116,115,115,101,114,105,101,115,112,101,114,115,111,
+110,108,105,118,105,110,103,100,101,115,105,103,110,109,111,110,116,104,115,102,
+111,114,99,101,115,117,110,105,113,117,101,119,101,105,103,104,116,112,101,111,
+112,108,101,101,110,101,114,103,121,110,97,116,117,114,101,115,101,97,114,99,104
+,102,105,103,117,114,101,104,97,118,105,110,103,99,117,115,116,111,109,111,102,
+102,115,101,116,108,101,116,116,101,114,119,105,110,100,111,119,115,117,98,109,
+105,116,114,101,110,100,101,114,103,114,111,117,112,115,117,112,108,111,97,100,
+104,101,97,108,116,104,109,101,116,104,111,100,118,105,100,101,111,115,115,99,
+104,111,111,108,102,117,116,117,114,101,115,104,97,100,111,119,100,101,98,97,116
+,101,118,97,108,117,101,115,79,98,106,101,99,116,111,116,104,101,114,115,114,105
+,103,104,116,115,108,101,97,103,117,101,99,104,114,111,109,101,115,105,109,112,
+108,101,110,111,116,105,99,101,115,104,97,114,101,100,101,110,100,105,110,103,
+115,101,97,115,111,110,114,101,112,111,114,116,111,110,108,105,110,101,115,113,
+117,97,114,101,98,117,116,116,111,110,105,109,97,103,101,115,101,110,97,98,108,
+101,109,111,118,105,110,103,108,97,116,101,115,116,119,105,110,116,101,114,70,
+114,97,110,99,101,112,101,114,105,111,100,115,116,114,111,110,103,114,101,112,
+101,97,116,76,111,110,100,111,110,100,101,116,97,105,108,102,111,114,109,101,100
+,100,101,109,97,110,100,115,101,99,117,114,101,112,97,115,115,101,100,116,111,
+103,103,108,101,112,108,97,99,101,115,100,101,118,105,99,101,115,116,97,116,105,
+99,99,105,116,105,101,115,115,116,114,101,97,109,121,101,108,108,111,119,97,116,
+116,97,99,107,115,116,114,101,101,116,102,108,105,103,104,116,104,105,100,100,
+101,110,105,110,102,111,34,62,111,112,101,110,101,100,117,115,101,102,117,108,
+118,97,108,108,101,121,99,97,117,115,101,115,108,101,97,100,101,114,115,101,99,
+114,101,116,115,101,99,111,110,100,100,97,109,97,103,101,115,112,111,114,116,115
+,101,120,99,101,112,116,114,97,116,105,110,103,115,105,103,110,101,100,116,104,
+105,110,103,115,101,102,102,101,99,116,102,105,101,108,100,115,115,116,97,116,
+101,115,111,102,102,105,99,101,118,105,115,117,97,108,101,100,105,116,111,114,
+118,111,108,117,109,101,82,101,112,111,114,116,109,117,115,101,117,109,109,111,
+118,105,101,115,112,97,114,101,110,116,97,99,99,101,115,115,109,111,115,116,108,
+121,109,111,116,104,101,114,34,32,105,100,61,34,109,97,114,107,101,116,103,114,
+111,117,110,100,99,104,97,110,99,101,115,117,114,118,101,121,98,101,102,111,114,
+101,115,121,109,98,111,108,109,111,109,101,110,116,115,112,101,101,99,104,109,
+111,116,105,111,110,105,110,115,105,100,101,109,97,116,116,101,114,67,101,110,
+116,101,114,111,98,106,101,99,116,101,120,105,115,116,115,109,105,100,100,108,
+101,69,117,114,111,112,101,103,114,111,119,116,104,108,101,103,97,99,121,109,97,
+110,110,101,114,101,110,111,117,103,104,99,97,114,101,101,114,97,110,115,119,101
+,114,111,114,105,103,105,110,112,111,114,116,97,108,99,108,105,101,110,116,115,
+101,108,101,99,116,114,97,110,100,111,109,99,108,111,115,101,100,116,111,112,105
+,99,115,99,111,109,105,110,103,102,97,116,104,101,114,111,112,116,105,111,110,
+115,105,109,112,108,121,114,97,105,115,101,100,101,115,99,97,112,101,99,104,111,
+115,101,110,99,104,117,114,99,104,100,101,102,105,110,101,114,101,97,115,111,110
+,99,111,114,110,101,114,111,117,116,112,117,116,109,101,109,111,114,121,105,102,
+114,97,109,101,112,111,108,105,99,101,109,111,100,101,108,115,78,117,109,98,101,
+114,100,117,114,105,110,103,111,102,102,101,114,115,115,116,121,108,101,115,107,
+105,108,108,101,100,108,105,115,116,101,100,99,97,108,108,101,100,115,105,108,
+118,101,114,109,97,114,103,105,110,100,101,108,101,116,101,98,101,116,116,101,
+114,98,114,111,119,115,101,108,105,109,105,116,115,71,108,111,98,97,108,115,105,
+110,103,108,101,119,105,100,103,101,116,99,101,110,116,101,114,98,117,100,103,
+101,116,110,111,119,114,97,112,99,114,101,100,105,116,99,108,97,105,109,115,101,
+110,103,105,110,101,115,97,102,101,116,121,99,104,111,105,99,101,115,112,105,114
+,105,116,45,115,116,121,108,101,115,112,114,101,97,100,109,97,107,105,110,103,
+110,101,101,100,101,100,114,117,115,115,105,97,112,108,101,97,115,101,101,120,
+116,101,110,116,83,99,114,105,112,116,98,114,111,107,101,110,97,108,108,111,119,
+115,99,104,97,114,103,101,100,105,118,105,100,101,102,97,99,116,111,114,109,101,
+109,98,101,114,45,98,97,115,101,100,116,104,101,111,114,121,99,111,110,102,105,
+103,97,114,111,117,110,100,119,111,114,107,101,100,104,101,108,112,101,100,67,
+104,117,114,99,104,105,109,112,97,99,116,115,104,111,117,108,100,97,108,119,97,
+121,115,108,111,103,111,34,32,98,111,116,116,111,109,108,105,115,116,34,62,41,
+123,118,97,114,32,112,114,101,102,105,120,111,114,97,110,103,101,72,101,97,100,
+101,114,46,112,117,115,104,40,99,111,117,112,108,101,103,97,114,100,101,110,98,
+114,105,100,103,101,108,97,117,110,99,104,82,101,118,105,101,119,116,97,107,105,
+110,103,118,105,115,105,111,110,108,105,116,116,108,101,100,97,116,105,110,103,
+66,117,116,116,111,110,98,101,97,117,116,121,116,104,101,109,101,115,102,111,114
+,103,111,116,83,101,97,114,99,104,97,110,99,104,111,114,97,108,109,111,115,116,
+108,111,97,100,101,100,67,104,97,110,103,101,114,101,116,117,114,110,115,116,114
+,105,110,103,114,101,108,111,97,100,77,111,98,105,108,101,105,110,99,111,109,101
+,115,117,112,112,108,121,83,111,117,114,99,101,111,114,100,101,114,115,118,105,
+101,119,101,100,38,110,98,115,112,59,99,111,117,114,115,101,65,98,111,117,116,32
+,105,115,108,97,110,100,60,104,116,109,108,32,99,111,111,107,105,101,110,97,109,
+101,61,34,97,109,97,122,111,110,109,111,100,101,114,110,97,100,118,105,99,101,
+105,110,60,47,97,62,58,32,84,104,101,32,100,105,97,108,111,103,104,111,117,115,
+101,115,66,69,71,73,78,32,77,101,120,105,99,111,115,116,97,114,116,115,99,101,
+110,116,114,101,104,101,105,103,104,116,97,100,100,105,110,103,73,115,108,97,110
+,100,97,115,115,101,116,115,69,109,112,105,114,101,83,99,104,111,111,108,101,102
+,102,111,114,116,100,105,114,101,99,116,110,101,97,114,108,121,109,97,110,117,97
+,108,83,101,108,101,99,116,46,10,10,79,110,101,106,111,105,110,101,100,109,101,
+110,117,34,62,80,104,105,108,105,112,97,119,97,114,100,115,104,97,110,100,108,
+101,105,109,112,111,114,116,79,102,102,105,99,101,114,101,103,97,114,100,115,107
+,105,108,108,115,110,97,116,105,111,110,83,112,111,114,116,115,100,101,103,114,
+101,101,119,101,101,107,108,121,32,40,101,46,103,46,98,101,104,105,110,100,100,
+111,99,116,111,114,108,111,103,103,101,100,117,110,105,116,101,100,60,47,98,62,
+60,47,98,101,103,105,110,115,112,108,97,110,116,115,97,115,115,105,115,116,97,
+114,116,105,115,116,105,115,115,117,101,100,51,48,48,112,120,124,99,97,110,97,
+100,97,97,103,101,110,99,121,115,99,104,101,109,101,114,101,109,97,105,110,66,
+114,97,122,105,108,115,97,109,112,108,101,108,111,103,111,34,62,98,101,121,111,
+110,100,45,115,99,97,108,101,97,99,99,101,112,116,115,101,114,118,101,100,109,97
+,114,105,110,101,70,111,111,116,101,114,99,97,109,101,114,97,60,47,104,49,62,10,
+95,102,111,114,109,34,108,101,97,118,101,115,115,116,114,101,115,115,34,32,47,62
+,13,10,46,103,105,102,34,32,111,110,108,111,97,100,108,111,97,100,101,114,79,120
+,102,111,114,100,115,105,115,116,101,114,115,117,114,118,105,118,108,105,115,116
+,101,110,102,101,109,97,108,101,68,101,115,105,103,110,115,105,122,101,61,34,97,
+112,112,101,97,108,116,101,120,116,34,62,108,101,118,101,108,115,116,104,97,110,
+107,115,104,105,103,104,101,114,102,111,114,99,101,100,97,110,105,109,97,108,97,
+110,121,111,110,101,65,102,114,105,99,97,97,103,114,101,101,100,114,101,99,101,
+110,116,80,101,111,112,108,101,60,98,114,32,47,62,119,111,110,100,101,114,112,
+114,105,99,101,115,116,117,114,110,101,100,124,124,32,123,125,59,109,97,105,110,
+34,62,105,110,108,105,110,101,115,117,110,100,97,121,119,114,97,112,34,62,102,97
+,105,108,101,100,99,101,110,115,117,115,109,105,110,117,116,101,98,101,97,99,111
+,110,113,117,111,116,101,115,49,53,48,112,120,124,101,115,116,97,116,101,114,101
+,109,111,116,101,101,109,97,105,108,34,108,105,110,107,101,100,114,105,103,104,
+116,59,115,105,103,110,97,108,102,111,114,109,97,108,49,46,104,116,109,108,115,
+105,103,110,117,112,112,114,105,110,99,101,102,108,111,97,116,58,46,112,110,103,
+34,32,102,111,114,117,109,46,65,99,99,101,115,115,112,97,112,101,114,115,115,111
+,117,110,100,115,101,120,116,101,110,100,72,101,105,103,104,116,115,108,105,100,
+101,114,85,84,70,45,56,34,38,97,109,112,59,32,66,101,102,111,114,101,46,32,87,
+105,116,104,115,116,117,100,105,111,111,119,110,101,114,115,109,97,110,97,103,
+101,112,114,111,102,105,116,106,81,117,101,114,121,97,110,110,117,97,108,112,97,
+114,97,109,115,98,111,117,103,104,116,102,97,109,111,117,115,103,111,111,103,108
+,101,108,111,110,103,101,114,105,43,43,41,32,123,105,115,114,97,101,108,115,97,
+121,105,110,103,100,101,99,105,100,101,104,111,109,101,34,62,104,101,97,100,101,
+114,101,110,115,117,114,101,98,114,97,110,99,104,112,105,101,99,101,115,98,108,
+111,99,107,59,115,116,97,116,101,100,116,111,112,34,62,60,114,97,99,105,110,103,
+114,101,115,105,122,101,45,45,38,103,116,59,112,97,99,105,116,121,115,101,120,
+117,97,108,98,117,114,101,97,117,46,106,112,103,34,32,49,48,44,48,48,48,111,98,
+116,97,105,110,116,105,116,108,101,115,97,109,111,117,110,116,44,32,73,110,99,46
+,99,111,109,101,100,121,109,101,110,117,34,32,108,121,114,105,99,115,116,111,100
+,97,121,46,105,110,100,101,101,100,99,111,117,110,116,121,95,108,111,103,111,46,
+70,97,109,105,108,121,108,111,111,107,101,100,77,97,114,107,101,116,108,115,101,
+32,105,102,80,108,97,121,101,114,116,117,114,107,101,121,41,59,118,97,114,32,102
+,111,114,101,115,116,103,105,118,105,110,103,101,114,114,111,114,115,68,111,109,
+97,105,110,125,101,108,115,101,123,105,110,115,101,114,116,66,108,111,103,60,47,
+102,111,111,116,101,114,108,111,103,105,110,46,102,97,115,116,101,114,97,103,101
+,110,116,115,60,98,111,100,121,32,49,48,112,120,32,48,112,114,97,103,109,97,102,
+114,105,100,97,121,106,117,110,105,111,114,100,111,108,108,97,114,112,108,97,99,
+101,100,99,111,118,101,114,115,112,108,117,103,105,110,53,44,48,48,48,32,112,97,
+103,101,34,62,98,111,115,116,111,110,46,116,101,115,116,40,97,118,97,116,97,114,
+116,101,115,116,101,100,95,99,111,117,110,116,102,111,114,117,109,115,115,99,104
+,101,109,97,105,110,100,101,120,44,102,105,108,108,101,100,115,104,97,114,101,
+115,114,101,97,100,101,114,97,108,101,114,116,40,97,112,112,101,97,114,83,117,98
+,109,105,116,108,105,110,101,34,62,98,111,100,121,34,62,10,42,32,84,104,101,84,
+104,111,117,103,104,115,101,101,105,110,103,106,101,114,115,101,121,78,101,119,
+115,60,47,118,101,114,105,102,121,101,120,112,101,114,116,105,110,106,117,114,
+121,119,105,100,116,104,61,67,111,111,107,105,101,83,84,65,82,84,32,97,99,114,
+111,115,115,95,105,109,97,103,101,116,104,114,101,97,100,110,97,116,105,118,101,
+112,111,99,107,101,116,98,111,120,34,62,10,83,121,115,116,101,109,32,68,97,118,
+105,100,99,97,110,99,101,114,116,97,98,108,101,115,112,114,111,118,101,100,65,
+112,114,105,108,32,114,101,97,108,108,121,100,114,105,118,101,114,105,116,101,
+109,34,62,109,111,114,101,34,62,98,111,97,114,100,115,99,111,108,111,114,115,99,
+97,109,112,117,115,102,105,114,115,116,32,124,124,32,91,93,59,109,101,100,105,97
+,46,103,117,105,116,97,114,102,105,110,105,115,104,119,105,100,116,104,58,115,
+104,111,119,101,100,79,116,104,101,114,32,46,112,104,112,34,32,97,115,115,117,
+109,101,108,97,121,101,114,115,119,105,108,115,111,110,115,116,111,114,101,115,
+114,101,108,105,101,102,115,119,101,100,101,110,67,117,115,116,111,109,101,97,
+115,105,108,121,32,121,111,117,114,32,83,116,114,105,110,103,10,10,87,104,105,
+108,116,97,121,108,111,114,99,108,101,97,114,58,114,101,115,111,114,116,102,114,
+101,110,99,104,116,104,111,117,103,104,34,41,32,43,32,34,60,98,111,100,121,62,98
+,117,121,105,110,103,98,114,97,110,100,115,77,101,109,98,101,114,110,97,109,101,
+34,62,111,112,112,105,110,103,115,101,99,116,111,114,53,112,120,59,34,62,118,115
+,112,97,99,101,112,111,115,116,101,114,109,97,106,111,114,32,99,111,102,102,101,
+101,109,97,114,116,105,110,109,97,116,117,114,101,104,97,112,112,101,110,60,47,
+110,97,118,62,107,97,110,115,97,115,108,105,110,107,34,62,73,109,97,103,101,115,
+61,102,97,108,115,101,119,104,105,108,101,32,104,115,112,97,99,101,48,38,97,109,
+112,59,32,10,10,73,110,32,32,112,111,119,101,114,80,111,108,115,107,105,45,99,
+111,108,111,114,106,111,114,100,97,110,66,111,116,116,111,109,83,116,97,114,116,
+32,45,99,111,117,110,116,50,46,104,116,109,108,110,101,119,115,34,62,48,49,46,
+106,112,103,79,110,108,105,110,101,45,114,105,103,104,116,109,105,108,108,101,
+114,115,101,110,105,111,114,73,83,66,78,32,48,48,44,48,48,48,32,103,117,105,100,
+101,115,118,97,108,117,101,41,101,99,116,105,111,110,114,101,112,97,105,114,46,
+120,109,108,34,32,32,114,105,103,104,116,115,46,104,116,109,108,45,98,108,111,99
+,107,114,101,103,69,120,112,58,104,111,118,101,114,119,105,116,104,105,110,118,
+105,114,103,105,110,112,104,111,110,101,115,60,47,116,114,62,13,117,115,105,110,
+103,32,10,9,118,97,114,32,62,39,41,59,10,9,60,47,116,100,62,10,60,47,116,114,62,
+10,98,97,104,97,115,97,98,114,97,115,105,108,103,97,108,101,103,111,109,97,103,
+121,97,114,112,111,108,115,107,105,115,114,112,115,107,105,216,177,216,175,217,
+136,228,184,173,230,150,135,231,174,128,228,189,147,231,185,129,233,171,148,228,
+191,161,230,129,175,228,184,173,229,155,189,230,136,145,228,187,172,228,184,128,
+228,184,170,229,133,172,229,143,184,231,174,161,231,144,134,232,174,186,229,157,
+155,229,143,175,228,187,165,230,156,141,229,138,161,230,151,182,233,151,180,228,
+184,170,228,186,186,228,186,167,229,147,129,232,135,170,229,183,177,228,188,129,
+228,184,154,230,159,165,231,156,139,229,183,165,228,189,156,232,129,148,231,179,
+187,230,178,161,230,156,137,231,189,145,231,171,153,230,137,128,230,156,137,232,
+175,132,232,174,186,228,184,173,229,191,131,230,150,135,231,171,160,231,148,168,
+230,136,183,233,166,150,233,161,181,228,189,156,232,128,133,230,138,128,230,156,
+175,233,151,174,233,162,152,231,155,184,229,133,179,228,184,139,232,189,189,230,
+144,156,231,180,162,228,189,191,231,148,168,232,189,175,228,187,182,229,156,168,
+231,186,191,228,184,187,233,162,152,232,181,132,230,150,153,232,167,134,233,162,
+145,229,155,158,229,164,141,230,179,168,229,134,140,231,189,145,231,187,156,230,
+148,182,232,151,143,229,134,133,229,174,185,230,142,168,232,141,144,229,184,130,
+229,156,186,230,182,136,230,129,175,231,169,186,233,151,180,229,143,145,229,184,
+131,228,187,128,228,185,136,229,165,189,229,143,139,231,148,159,230,180,187,229,
+155,190,231,137,135,229,143,145,229,177,149,229,166,130,230,158,156,230,137,139,
+230,156,186,230,150,176,233,151,187,230,156,128,230,150,176,230,150,185,229,188,
+143,229,140,151,228,186,172,230,143,144,228,190,155,229,133,179,228,186,142,230,
+155,180,229,164,154,232,191,153,228,184,170,231,179,187,231,187,159,231,159,165,
+233,129,147,230,184,184,230,136,143,229,185,191,229,145,138,229,133,182,228,187,
+150,229,143,145,232,161,168,229,174,137,229,133,168,231,172,172,228,184,128,228,
+188,154,229,145,152,232,191,155,232,161,140,231,130,185,229,135,187,231,137,136,
+230,157,131,231,148,181,229,173,144,228,184,150,231,149,140,232,174,190,232,174,
+161,229,133,141,232,180,185,230,149,153,232,130,178,229,138,160,229,133,165,230,
+180,187,229,138,168,228,187,150,228,187,172,229,149,134,229,147,129,229,141,154,
+229,174,162,231,142,176,229,156,168,228,184,138,230,181,183,229,166,130,228,189,
+149,229,183,178,231,187,143,231,149,153,232,168,128,232,175,166,231,187,134,231,
+164,190,229,140,186,231,153,187,229,189,149,230,156,172,231,171,153,233,156,128,
+232,166,129,228,187,183,230,160,188,230,148,175,230,140,129,229,155,189,233,153,
+133,233,147,190,230,142,165,229,155,189,229,174,182,229,187,186,232,174,190,230,
+156,139,229,143,139,233,152,133,232,175,187,230,179,149,229,190,139,228,189,141,
+231,189,174,231,187,143,230,181,142,233,128,137,230,139,169,232,191,153,230,160,
+183,229,189,147,229,137,141,229,136,134,231,177,187,230,142,146,232,161,140,229,
+155,160,228,184,186,228,186,164,230,152,147,230,156,128,229,144,142,233,159,179,
+228,185,144,228,184,141,232,131,189,233,128,154,232,191,135,232,161,140,228,184,
+154,231,167,145,230,138,128,229,143,175,232,131,189,232,174,190,229,164,135,229,
+144,136,228,189,156,229,164,167,229,174,182,231,164,190,228,188,154,231,160,148,
+231,169,182,228,184,147,228,184,154,229,133,168,233,131,168,233,161,185,231,155,
+174,232,191,153,233,135,140,232,191,152,230,152,175,229,188,128,229,167,139,230,
+131,133,229,134,181,231,148,181,232,132,145,230,150,135,228,187,182,229,147,129,
+231,137,140,229,184,174,229,138,169,230,150,135,229,140,150,232,181,132,230,186,
+144,229,164,167,229,173,166,229,173,166,228,185,160,229,156,176,229,157,128,230,
+181,143,232,167,136,230,138,149,232,181,132,229,183,165,231,168,139,232,166,129,
+230,177,130,230,128,142,228,185,136,230,151,182,229,128,153,229,138,159,232,131,
+189,228,184,187,232,166,129,231,155,174,229,137,141,232,181,132,232,174,175,229,
+159,142,229,184,130,230,150,185,230,179,149,231,148,181,229,189,177,230,139,155,
+232,129,152,229,163,176,230,152,142,228,187,187,228,189,149,229,129,165,229,186,
+183,230,149,176,230,141,174,231,190,142,229,155,189,230,177,189,232,189,166,228,
+187,139,231,187,141,228,189,134,230,152,175,228,186,164,230,181,129,231,148,159,
+228,186,167,230,137,128,228,187,165,231,148,181,232,175,157,230,152,190,231,164,
+186,228,184,128,228,186,155,229,141,149,228,189,141,228,186,186,229,145,152,229,
+136,134,230,158,144,229,156,176,229,155,190,230,151,133,230,184,184,229,183,165,
+229,133,183,229,173,166,231,148,159,231,179,187,229,136,151,231,189,145,229,143,
+139,229,184,150,229,173,144,229,175,134,231,160,129,233,162,145,233,129,147,230,
+142,167,229,136,182,229,156,176,229,140,186,229,159,186,230,156,172,229,133,168,
+229,155,189,231,189,145,228,184,138,233,135,141,232,166,129,231,172,172,228,186,
+140,229,150,156,230,172,162,232,191,155,229,133,165,229,143,139,230,131,133,232,
+191,153,228,186,155,232,128,131,232,175,149,229,143,145,231,142,176,229,159,185,
+232,174,173,228,187,165,228,184,138,230,148,191,229,186,156,230,136,144,228,184,
+186,231,142,175,229,162,131,233,166,153,230,184,175,229,144,140,230,151,182,229,
+168,177,228,185,144,229,143,145,233,128,129,228,184,128,229,174,154,229,188,128,
+229,143,145,228,189,156,229,147,129,230,160,135,229,135,134,230,172,162,232,191,
+142,232,167,163,229,134,179,229,156,176,230,150,185,228,184,128,228,184,139,228,
+187,165,229,143,138,232,180,163,228,187,187,230,136,150,232,128,133,229,174,162,
+230,136,183,228,187,163,232,161,168,231,167,175,229,136,134,229,165,179,228,186,
+186,230,149,176,231,160,129,233,148,128,229,148,174,229,135,186,231,142,176,231,
+166,187,231,186,191,229,186,148,231,148,168,229,136,151,232,161,168,228,184,141,
+229,144,140,231,188,150,232,190,145,231,187,159,232,174,161,230,159,165,232,175,
+162,228,184,141,232,166,129,230,156,137,229,133,179,230,156,186,230,158,132,229,
+190,136,229,164,154,230,146,173,230,148,190,231,187,132,231,187,135,230,148,191,
+231,173,150,231,155,180,230,142,165,232,131,189,229,138,155,230,157,165,230,186,
+144,230,153,130,233,150,147,231,156,139,229,136,176,231,131,173,233,151,168,229,
+133,179,233,148,174,228,184,147,229,140,186,233,157,158,229,184,184,232,139,177,
+232,175,173,231,153,190,229,186,166,229,184,140,230,156,155,231,190,142,229,165,
+179,230,175,148,232,190,131,231,159,165,232,175,134,232,167,132,229,174,154,229,
+187,186,232,174,174,233,131,168,233,151,168,230,132,143,232,167,129,231,178,190,
+229,189,169,230,151,165,230,156,172,230,143,144,233,171,152,229,143,145,232,168,
+128,230,150,185,233,157,162,229,159,186,233,135,145,229,164,132,231,144,134,230,
+157,131,233,153,144,229,189,177,231,137,135,233,147,182,232,161,140,232,191,152,
+230,156,137,229,136,134,228,186,171,231,137,169,229,147,129,231,187,143,232,144,
+165,230,183,187,229,138,160,228,184,147,229,174,182,232,191,153,231,167,141,232,
+175,157,233,162,152,232,181,183,230,157,165,228,184,154,229,138,161,229,133,172,
+229,145,138,232,174,176,229,189,149,231,174,128,228,187,139,232,180,168,233,135,
+143,231,148,183,228,186,186,229,189,177,229,147,141,229,188,149,231,148,168,230,
+138,165,229,145,138,233,131,168,229,136,134,229,191,171,233,128,159,229,146,168,
+232,175,162,230,151,182,229,176,154,230,179,168,230,132,143,231,148,179,232,175,
+183,229,173,166,230,160,161,229,186,148,232,175,165,229,142,134,229,143,178,229,
+143,170,230,152,175,232,191,148,229,155,158,232,180,173,228,185,176,229,144,141,
+231,167,176,228,184,186,228,186,134,230,136,144,229,138,159,232,175,180,230,152,
+142,228,190,155,229,186,148,229,173,169,229,173,144,228,184,147,233,162,152,231,
+168,139,229,186,143,228,184,128,232,136,172,230,156,131,229,147,161,229,143,170,
+230,156,137,229,133,182,229,174,131,228,191,157,230,138,164,232,128,140,228,184,
+148,228,187,138,229,164,169,231,170,151,229,143,163,229,138,168,230,128,129,231,
+138,182,230,128,129,231,137,185,229,136,171,232,174,164,228,184,186,229,191,133,
+233,161,187,230,155,180,230,150,176,229,176,143,232,175,180,230,136,145,229,128,
+145,228,189,156,228,184,186,229,170,146,228,189,147,229,140,133,230,139,172,233,
+130,163,228,185,136,228,184,128,230,160,183,229,155,189,229,134,133,230,152,175,
+229,144,166,230,160,185,230,141,174,231,148,181,232,167,134,229,173,166,233,153,
+162,229,133,183,230,156,137,232,191,135,231,168,139,231,148,177,228,186,142,228,
+186,186,230,137,141,229,135,186,230,157,165,228,184,141,232,191,135,230,173,163,
+229,156,168,230,152,142,230,152,159,230,149,133,228,186,139,229,133,179,231,179,
+187,230,160,135,233,162,152,229,149,134,229,138,161,232,190,147,229,133,165,228,
+184,128,231,155,180,229,159,186,231,161,128,230,149,153,229,173,166,228,186,134,
+232,167,163,229,187,186,231,173,145,231,187,147,230,158,156,229,133,168,231,144,
+131,233,128,154,231,159,165,232,174,161,229,136,146,229,175,185,228,186,142,232,
+137,186,230,156,175,231,155,184,229,134,140,229,143,145,231,148,159,231,156,159,
+231,154,132,229,187,186,231,171,139,231,173,137,231,186,167,231,177,187,229,158,
+139,231,187,143,233,170,140,229,174,158,231,142,176,229,136,182,228,189,156,230,
+157,165,232,135,170,230,160,135,231,173,190,228,187,165,228,184,139,229,142,159,
+229,136,155,230,151,160,230,179,149,229,133,182,228,184,173,229,128,139,228,186,
+186,228,184,128,229,136,135,230,140,135,229,141,151,229,133,179,233,151,173,233,
+155,134,229,155,162,231,172,172,228,184,137,229,133,179,230,179,168,229,155,160,
+230,173,164,231,133,167,231,137,135,230,183,177,229,156,179,229,149,134,228,184,
+154,229,185,191,229,183,158,230,151,165,230,156,159,233,171,152,231,186,167,230,
+156,128,232,191,145,231,187,188,229,144,136,232,161,168,231,164,186,228,184,147,
+232,190,145,232,161,140,228,184,186,228,186,164,233,128,154,232,175,132,228,187,
+183,232,167,137,229,190,151,231,178,190,229,141,142,229,174,182,229,186,173,229,
+174,140,230,136,144,230,132,159,232,167,137,229,174,137,232,163,133,229,190,151,
+229,136,176,233,130,174,228,187,182,229,136,182,229,186,166,233,163,159,229,147,
+129,232,153,189,231,132,182,232,189,172,232,189,189,230,138,165,228,187,183,232,
+174,176,232,128,133,230,150,185,230,161,136,232,161,140,230,148,191,228,186,186,
+230,176,145,231,148,168,229,147,129,228,184,156,232,165,191,230,143,144,229,135,
+186,233,133,146,229,186,151,231,132,182,229,144,142,228,187,152,230,172,190,231,
+131,173,231,130,185,228,187,165,229,137,141,229,174,140,229,133,168,229,143,145,
+229,184,150,232,174,190,231,189,174,233,162,134,229,175,188,229,183,165,228,184,
+154,229,140,187,233,153,162,231,156,139,231,156,139,231,187,143,229,133,184,229,
+142,159,229,155,160,229,185,179,229,143,176,229,144,132,231,167,141,229,162,158,
+229,138,160,230,157,144,230,150,153,230,150,176,229,162,158,228,185,139,229,144,
+142,232,129,140,228,184,154,230,149,136,230,158,156,228,187,138,229,185,180,232,
+174,186,230,150,135,230,136,145,229,155,189,229,145,138,232,175,137,231,137,136,
+228,184,187,228,191,174,230,148,185,229,143,130,228,184,142,230,137,147,229,141,
+176,229,191,171,228,185,144,230,156,186,230,162,176,232,167,130,231,130,185,229,
+173,152,229,156,168,231,178,190,231,165,158,232,142,183,229,190,151,229,136,169,
+231,148,168,231,187,167,231,187,173,228,189,160,228,187,172,232,191,153,228,185,
+136,230,168,161,229,188,143,232,175,173,232,168,128,232,131,189,229,164,159,233,
+155,133,232,153,142,230,147,141,228,189,156,233,163,142,230,160,188,228,184,128,
+232,181,183,231,167,145,229,173,166,228,189,147,232,130,178,231,159,173,228,191,
+161,230,157,161,228,187,182,230,178,187,231,150,151,232,191,144,229,138,168,228,
+186,167,228,184,154,228,188,154,232,174,174,229,175,188,232,136,170,229,133,136,
+231,148,159,232,129,148,231,155,159,229,143,175,230,152,175,229,149,143,233,161,
+140,231,187,147,230,158,132,228,189,156,231,148,168,232,176,131,230,159,165,232,
+179,135,230,150,153,232,135,170,229,138,168,232,180,159,232,180,163,229,134,156,
+228,184,154,232,174,191,233,151,174,229,174,158,230,150,189,230,142,165,229,143,
+151,232,174,168,232,174,186,233,130,163,228,184,170,229,143,141,233,166,136,229,
+138,160,229,188,186,229,165,179,230,128,167,232,140,131,229,155,180,230,156,141,
+229,139,153,228,188,145,233,151,178,228,187,138,230,151,165,229,174,162,230,156,
+141,232,167,128,231,156,139,229,143,130,229,138,160,231,154,132,232,175,157,228,
+184,128,231,130,185,228,191,157,232,175,129,229,155,190,228,185,166,230,156,137,
+230,149,136,230,181,139,232,175,149,231,167,187,229,138,168,230,137,141,232,131,
+189,229,134,179,229,174,154,232,130,161,231,165,168,228,184,141,230,150,173,233,
+156,128,230,177,130,228,184,141,229,190,151,229,138,158,230,179,149,228,185,139,
+233,151,180,233,135,135,231,148,168,232,144,165,233,148,128,230,138,149,232,175,
+137,231,155,174,230,160,135,231,136,177,230,131,133,230,145,132,229,189,177,230,
+156,137,228,186,155,232,164,135,232,163,189,230,150,135,229,173,166,230,156,186,
+228,188,154,230,149,176,229,173,151,232,163,133,228,191,174,232,180,173,231,137,
+169,229,134,156,230,157,145,229,133,168,233,157,162,231,178,190,229,147,129,229,
+133,182,229,174,158,228,186,139,230,131,133,230,176,180,229,185,179,230,143,144,
+231,164,186,228,184,138,229,184,130,232,176,162,232,176,162,230,153,174,233,128,
+154,230,149,153,229,184,136,228,184,138,228,188,160,231,177,187,229,136,171,230,
+173,140,230,155,178,230,139,165,230,156,137,229,136,155,230,150,176,233,133,141,
+228,187,182,229,143,170,232,166,129,230,151,182,228,187,163,232,179,135,232,168,
+138,232,190,190,229,136,176,228,186,186,231,148,159,232,174,162,233,152,133,232,
+128,129,229,184,136,229,177,149,231,164,186,229,191,131,231,144,134,232,180,180,
+229,173,144,231,182,178,231,171,153,228,184,187,233,161,140,232,135,170,231,132,
+182,231,186,167,229,136,171,231,174,128,229,141,149,230,148,185,233,157,169,233,
+130,163,228,186,155,230,157,165,232,175,180,230,137,147,229,188,128,228,187,163,
+231,160,129,229,136,160,233,153,164,232,175,129,229,136,184,232,138,130,231,155,
+174,233,135,141,231,130,185,230,172,161,230,149,184,229,164,154,229,176,145,232,
+167,132,229,136,146,232,181,132,233,135,145,230,137,190,229,136,176,228,187,165,
+229,144,142,229,164,167,229,133,168,228,184,187,233,161,181,230,156,128,228,189,
+179,229,155,158,231,173,148,229,164,169,228,184,139,228,191,157,233,154,156,231,
+142,176,228,187,163,230,163,128,230,159,165,230,138,149,231,165,168,229,176,143,
+230,151,182,230,178,146,230,156,137,230,173,163,229,184,184,231,148,154,232,135,
+179,228,187,163,231,144,134,231,155,174,229,189,149,229,133,172,229,188,128,229,
+164,141,229,136,182,233,135,145,232,158,141,229,185,184,231,166,143,231,137,136,
+230,156,172,229,189,162,230,136,144,229,135,134,229,164,135,232,161,140,230,131,
+133,229,155,158,229,136,176,230,128,157,230,131,179,230,128,142,230,160,183,229,
+141,143,232,174,174,232,174,164,232,175,129,230,156,128,229,165,189,228,186,167,
+231,148,159,230,140,137,231,133,167,230,156,141,232,163,133,229,185,191,228,184,
+156,229,138,168,230,188,171,233,135,135,232,180,173,230,150,176,230,137,139,231,
+187,132,229,155,190,233,157,162,230,157,191,229,143,130,232,128,131,230,148,191,
+230,178,187,229,174,185,230,152,147,229,164,169,229,156,176,229,138,170,229,138,
+155,228,186,186,228,187,172,229,141,135,231,186,167,233,128,159,229,186,166,228,
+186,186,231,137,169,232,176,131,230,149,180,230,181,129,232,161,140,233,128,160,
+230,136,144,230,150,135,229,173,151,233,159,169,229,155,189,232,180,184,230,152,
+147,229,188,128,229,177,149,231,155,184,233,151,156,232,161,168,231,142,176,229,
+189,177,232,167,134,229,166,130,230,173,164,231,190,142,229,174,185,229,164,167,
+229,176,143,230,138,165,233,129,147,230,157,161,230,172,190,229,191,131,230,131,
+133,232,174,184,229,164,154,230,179,149,232,167,132,229,174,182,229,177,133,228,
+185,166,229,186,151,232,191,158,230,142,165,231,171,139,229,141,179,228,184,190,
+230,138,165,230,138,128,229,183,167,229,165,165,232,191,144,231,153,187,229,133,
+165,228,187,165,230,157,165,231,144,134,232,174,186,228,186,139,228,187,182,232,
+135,170,231,148,177,228,184,173,229,141,142,229,138,158,229,133,172,229,166,136,
+229,166,136,231,156,159,230,173,163,228,184,141,233,148,153,229,133,168,230,150,
+135,229,144,136,229,144,140,228,187,183,229,128,188,229,136,171,228,186,186,231,
+155,145,231,157,163,229,133,183,228,189,147,228,184,150,231,186,170,229,155,162,
+233,152,159,229,136,155,228,184,154,230,137,191,230,139,133,229,162,158,233,149,
+191,230,156,137,228,186,186,228,191,157,230,140,129,229,149,134,229,174,182,231,
+187,180,228,191,174,229,143,176,230,185,190,229,183,166,229,143,179,232,130,161,
+228,187,189,231,173,148,230,161,136,229,174,158,233,153,133,231,148,181,228,191,
+161,231,187,143,231,144,134,231,148,159,229,145,189,229,174,163,228,188,160,228,
+187,187,229,138,161,230,173,163,229,188,143,231,137,185,232,137,178,228,184,139,
+230,157,165,229,141,143,228,188,154,229,143,170,232,131,189,229,189,147,231,132,
+182,233,135,141,230,150,176,229,133,167,229,174,185,230,140,135,229,175,188,232,
+191,144,232,161,140,230,151,165,229,191,151,232,179,163,229,174,182,232,182,133,
+232,191,135,229,156,159,229,156,176,230,181,153,230,177,159,230,148,175,228,187,
+152,230,142,168,229,135,186,231,171,153,233,149,191,230,157,173,229,183,158,230,
+137,167,232,161,140,229,136,182,233,128,160,228,185,139,228,184,128,230,142,168,
+229,185,191,231,142,176,229,156,186,230,143,143,232,191,176,229,143,152,229,140,
+150,228,188,160,231,187,159,230,173,140,230,137,139,228,191,157,233,153,169,232,
+175,190,231,168,139,229,140,187,231,150,151,231,187,143,232,191,135,232,191,135,
+229,142,187,228,185,139,229,137,141,230,148,182,229,133,165,229,185,180,229,186,
+166,230,157,130,229,191,151,231,190,142,228,184,189,230,156,128,233,171,152,231,
+153,187,233,153,134,230,156,170,230,157,165,229,138,160,229,183,165,229,133,141,
+232,180,163,230,149,153,231,168,139,231,137,136,229,157,151,232,186,171,228,189,
+147,233,135,141,229,186,134,229,135,186,229,148,174,230,136,144,230,156,172,229,
+189,162,229,188,143,229,156,159,232,177,134,229,135,186,229,131,185,228,184,156,
+230,150,185,233,130,174,231,174,177,229,141,151,228,186,172,230,177,130,232,129,
+140,229,143,150,229,190,151,232,129,140,228,189,141,231,155,184,228,191,161,233,
+161,181,233,157,162,229,136,134,233,146,159,231,189,145,233,161,181,231,161,174,
+229,174,154,229,155,190,228,190,139,231,189,145,229,157,128,231,167,175,230,158,
+129,233,148,153,232,175,175,231,155,174,231,154,132,229,174,157,232,180,157,230,
+156,186,229,133,179,233,163,142,233,153,169,230,142,136,230,157,131,231,151,133,
+230,175,146,229,174,160,231,137,169,233,153,164,228,186,134,232,169,149,232,171,
+150,231,150,190,231,151,133,229,143,138,230,151,182,230,177,130,232,180,173,231,
+171,153,231,130,185,229,132,191,231,171,165,230,175,143,229,164,169,228,184,173,
+229,164,174,232,174,164,232,175,134,230,175,143,228,184,170,229,164,169,230,180,
+165,229,173,151,228,189,147,229,143,176,231,129,163,231,187,180,230,138,164,230,
+156,172,233,161,181,228,184,170,230,128,167,229,174,152,230,150,185,229,184,184,
+232,167,129,231,155,184,230,156,186,230,136,152,231,149,165,229,186,148,229,189,
+147,229,190,139,229,184,136,230,150,185,228,190,191,230,160,161,229,155,173,232,
+130,161,229,184,130,230,136,191,229,177,139,230,160,143,231,155,174,229,145,152,
+229,183,165,229,175,188,232,135,180,231,170,129,231,132,182,233,129,147,229,133,
+183,230,156,172,231,189,145,231,187,147,229,144,136,230,161,163,230,161,136,229,
+138,179,229,138,168,229,143,166,229,164,150,231,190,142,229,133,131,229,188,149,
+232,181,183,230,148,185,229,143,152,231,172,172,229,155,155,228,188,154,232,174,
+161,232,170,170,230,152,142,233,154,144,231,167,129,229,174,157,229,174,157,232,
+167,132,232,140,131,230,182,136,232,180,185,229,133,177,229,144,140,229,191,152,
+232,174,176,228,189,147,231,179,187,229,184,166,230,157,165,229,144,141,229,173,
+151,231,153,188,232,161,168,229,188,128,230,148,190,229,138,160,231,155,159,229,
+143,151,229,136,176,228,186,140,230,137,139,229,164,167,233,135,143,230,136,144,
+228,186,186,230,149,176,233,135,143,229,133,177,228,186,171,229,140,186,229,159,
+159,229,165,179,229,173,169,229,142,159,229,136,153,230,137,128,229,156,168,231,
+187,147,230,157,159,233,128,154,228,191,161,232,182,133,231,186,167,233,133,141,
+231,189,174,229,189,147,230,151,182,228,188,152,231,167,128,230,128,167,230,132,
+159,230,136,191,228,186,167,233,129,138,230,136,178,229,135,186,229,143,163,230,
+143,144,228,186,164,229,176,177,228,184,154,228,191,157,229,129,165,231,168,139,
+229,186,166,229,143,130,230,149,176,228,186,139,228,184,154,230,149,180,228,184,
+170,229,177,177,228,184,156,230,131,133,230,132,159,231,137,185,230,174,138,229,
+136,134,233,161,158,230,144,156,229,176,139,229,177,158,228,186,142,233,151,168,
+230,136,183,232,180,162,229,138,161,229,163,176,233,159,179,229,143,138,229,133,
+182,232,180,162,231,187,143,229,157,154,230,140,129,229,185,178,233,131,168,230,
+136,144,231,171,139,229,136,169,231,155,138,232,128,131,232,153,145,230,136,144,
+233,131,189,229,140,133,232,163,133,231,148,168,230,136,182,230,175,148,232,181,
+155,230,150,135,230,152,142,230,139,155,229,149,134,229,174,140,230,149,180,231,
+156,159,230,152,175,231,156,188,231,157,155,228,188,153,228,188,180,229,168,129,
+230,156,155,233,162,134,229,159,159,229,141,171,231,148,159,228,188,152,230,131,
+160,232,171,150,229,163,135,229,133,172,229,133,177,232,137,175,229,165,189,229,
+133,133,229,136,134,231,172,166,229,144,136,233,153,132,228,187,182,231,137,185,
+231,130,185,228,184,141,229,143,175,232,139,177,230,150,135,232,181,132,228,186,
+167,230,160,185,230,156,172,230,152,142,230,152,190,229,175,134,231,162,188,229,
+133,172,228,188,151,230,176,145,230,151,143,230,155,180,229,138,160,228,186,171,
+229,143,151,229,144,140,229,173,166,229,144,175,229,138,168,233,128,130,229,144,
+136,229,142,159,230,157,165,233,151,174,231,173,148,230,156,172,230,150,135,231,
+190,142,233,163,159,231,187,191,232,137,178,231,168,179,229,174,154,231,187,136,
+228,186,142,231,148,159,231,137,169,228,190,155,230,177,130,230,144,156,231,139,
+144,229,138,155,233,135,143,228,184,165,233,135,141,230,176,184,232,191,156,229,
+134,153,231,156,159,230,156,137,233,153,144,231,171,158,228,186,137,229,175,185,
+232,177,161,232,180,185,231,148,168,228,184,141,229,165,189,231,187,157,229,175,
+185,229,141,129,229,136,134,228,191,131,232,191,155,231,130,185,232,175,132,229,
+189,177,233,159,179,228,188,152,229,138,191,228,184,141,229,176,145,230,172,163,
+232,181,143,229,185,182,228,184,148,230,156,137,231,130,185,230,150,185,229,144,
+145,229,133,168,230,150,176,228,191,161,231,148,168,232,174,190,230,150,189,229,
+189,162,232,177,161,232,181,132,230,160,188,231,170,129,231,160,180,233,154,143,
+231,157,128,233,135,141,229,164,167,228,186,142,230,152,175,230,175,149,228,184,
+154,230,153,186,232,131,189,229,140,150,229,183,165,229,174,140,231,190,142,229,
+149,134,229,159,142,231,187,159,228,184,128,229,135,186,231,137,136,230,137,147,
+233,128,160,231,148,162,229,147,129,230,166,130,229,134,181,231,148,168,228,186,
+142,228,191,157,231,149,153,229,155,160,231,180,160,228,184,173,229,156,139,229,
+173,152,229,130,168,232,180,180,229,155,190,230,156,128,230,132,155,233,149,191,
+230,156,159,229,143,163,228,187,183,231,144,134,232,180,162,229,159,186,229,156,
+176,229,174,137,230,142,146,230,173,166,230,177,137,233,135,140,233,157,162,229,
+136,155,229,187,186,229,164,169,231,169,186,233,166,150,229,133,136,229,174,140,
+229,150,132,233,169,177,229,138,168,228,184,139,233,157,162,228,184,141,229,134,
+141,232,175,154,228,191,161,230,132,143,228,185,137,233,152,179,229,133,137,232,
+139,177,229,155,189,230,188,130,228,186,174,229,134,155,228,186,139,231,142,169,
+229,174,182,231,190,164,228,188,151,229,134,156,230,176,145,229,141,179,229,143,
+175,229,144,141,231,168,177,229,174,182,229,133,183,229,138,168,231,148,187,230,
+131,179,229,136,176,230,179,168,230,152,142,229,176,143,229,173,166,230,128,167,
+232,131,189,232,128,131,231,160,148,231,161,172,228,187,182,232,167,130,231,156,
+139,230,184,133,230,165,154,230,144,158,231,172,145,233,166,150,233,160,129,233,
+187,132,233,135,145,233,128,130,231,148,168,230,177,159,232,139,143,231,156,159,
+229,174,158,228,184,187,231,174,161,233,152,182,230,174,181,232,168,187,229,134,
+138,231,191,187,232,175,145,230,157,131,229,136,169,229,129,154,229,165,189,228,
+188,188,228,185,142,233,128,154,232,174,175,230,150,189,229,183,165,231,139,128,
+230,133,139,228,185,159,232,174,184,231,142,175,228,191,157,229,159,185,229,133,
+187,230,166,130,229,191,181,229,164,167,229,158,139,230,156,186,231,165,168,231,
+144,134,232,167,163,229,140,191,229,144,141,99,117,97,110,100,111,101,110,118,
+105,97,114,109,97,100,114,105,100,98,117,115,99,97,114,105,110,105,99,105,111,
+116,105,101,109,112,111,112,111,114,113,117,101,99,117,101,110,116,97,101,115,
+116,97,100,111,112,117,101,100,101,110,106,117,101,103,111,115,99,111,110,116,
+114,97,101,115,116,195,161,110,110,111,109,98,114,101,116,105,101,110,101,110,
+112,101,114,102,105,108,109,97,110,101,114,97,97,109,105,103,111,115,99,105,117,
+100,97,100,99,101,110,116,114,111,97,117,110,113,117,101,112,117,101,100,101,115
+,100,101,110,116,114,111,112,114,105,109,101,114,112,114,101,99,105,111,115,101,
+103,195,186,110,98,117,101,110,111,115,118,111,108,118,101,114,112,117,110,116,
+111,115,115,101,109,97,110,97,104,97,98,195,173,97,97,103,111,115,116,111,110,
+117,101,118,111,115,117,110,105,100,111,115,99,97,114,108,111,115,101,113,117,
+105,112,111,110,105,195,177,111,115,109,117,99,104,111,115,97,108,103,117,110,97
+,99,111,114,114,101,111,105,109,97,103,101,110,112,97,114,116,105,114,97,114,114
+,105,98,97,109,97,114,195,173,97,104,111,109,98,114,101,101,109,112,108,101,111,
+118,101,114,100,97,100,99,97,109,98,105,111,109,117,99,104,97,115,102,117,101,
+114,111,110,112,97,115,97,100,111,108,195,173,110,101,97,112,97,114,101,99,101,
+110,117,101,118,97,115,99,117,114,115,111,115,101,115,116,97,98,97,113,117,105,
+101,114,111,108,105,98,114,111,115,99,117,97,110,116,111,97,99,99,101,115,111,
+109,105,103,117,101,108,118,97,114,105,111,115,99,117,97,116,114,111,116,105,101
+,110,101,115,103,114,117,112,111,115,115,101,114,195,161,110,101,117,114,111,112
+,97,109,101,100,105,111,115,102,114,101,110,116,101,97,99,101,114,99,97,100,101,
+109,195,161,115,111,102,101,114,116,97,99,111,99,104,101,115,109,111,100,101,108
+,111,105,116,97,108,105,97,108,101,116,114,97,115,97,108,103,195,186,110,99,111,
+109,112,114,97,99,117,97,108,101,115,101,120,105,115,116,101,99,117,101,114,112,
+111,115,105,101,110,100,111,112,114,101,110,115,97,108,108,101,103,97,114,118,
+105,97,106,101,115,100,105,110,101,114,111,109,117,114,99,105,97,112,111,100,114
+,195,161,112,117,101,115,116,111,100,105,97,114,105,111,112,117,101,98,108,111,
+113,117,105,101,114,101,109,97,110,117,101,108,112,114,111,112,105,111,99,114,
+105,115,105,115,99,105,101,114,116,111,115,101,103,117,114,111,109,117,101,114,
+116,101,102,117,101,110,116,101,99,101,114,114,97,114,103,114,97,110,100,101,101
+,102,101,99,116,111,112,97,114,116,101,115,109,101,100,105,100,97,112,114,111,
+112,105,97,111,102,114,101,99,101,116,105,101,114,114,97,101,45,109,97,105,108,
+118,97,114,105,97,115,102,111,114,109,97,115,102,117,116,117,114,111,111,98,106,
+101,116,111,115,101,103,117,105,114,114,105,101,115,103,111,110,111,114,109,97,
+115,109,105,115,109,111,115,195,186,110,105,99,111,99,97,109,105,110,111,115,105
+,116,105,111,115,114,97,122,195,179,110,100,101,98,105,100,111,112,114,117,101,
+98,97,116,111,108,101,100,111,116,101,110,195,173,97,106,101,115,195,186,115,101
+,115,112,101,114,111,99,111,99,105,110,97,111,114,105,103,101,110,116,105,101,
+110,100,97,99,105,101,110,116,111,99,195,161,100,105,122,104,97,98,108,97,114,
+115,101,114,195,173,97,108,97,116,105,110,97,102,117,101,114,122,97,101,115,116,
+105,108,111,103,117,101,114,114,97,101,110,116,114,97,114,195,169,120,105,116,
+111,108,195,179,112,101,122,97,103,101,110,100,97,118,195,173,100,101,111,101,
+118,105,116,97,114,112,97,103,105,110,97,109,101,116,114,111,115,106,97,118,105,
+101,114,112,97,100,114,101,115,102,195,161,99,105,108,99,97,98,101,122,97,195,
+161,114,101,97,115,115,97,108,105,100,97,101,110,118,195,173,111,106,97,112,195,
+179,110,97,98,117,115,111,115,98,105,101,110,101,115,116,101,120,116,111,115,108
+,108,101,118,97,114,112,117,101,100,97,110,102,117,101,114,116,101,99,111,109,
+195,186,110,99,108,97,115,101,115,104,117,109,97,110,111,116,101,110,105,100,111
+,98,105,108,98,97,111,117,110,105,100,97,100,101,115,116,195,161,115,101,100,105
+,116,97,114,99,114,101,97,100,111,208,180,208,187,209,143,209,135,209,130,208,
+190,208,186,208,176,208,186,208,184,208,187,208,184,209,141,209,130,208,190,208,
+178,209,129,208,181,208,181,208,179,208,190,208,191,209,128,208,184,209,130,208,
+176,208,186,208,181,209,137,208,181,209,131,208,182,208,181,208,154,208,176,208,
+186,208,177,208,181,208,183,208,177,209,139,208,187,208,190,208,189,208,184,208,
+146,209,129,208,181,208,191,208,190,208,180,208,173,209,130,208,190,209,130,208,
+190,208,188,209,135,208,181,208,188,208,189,208,181,209,130,208,187,208,181,209,
+130,209,128,208,176,208,183,208,190,208,189,208,176,208,179,208,180,208,181,208,
+188,208,189,208,181,208,148,208,187,209,143,208,159,209,128,208,184,208,189,208,
+176,209,129,208,189,208,184,209,133,209,130,208,181,208,188,208,186,209,130,208,
+190,208,179,208,190,208,180,208,178,208,190,209,130,209,130,208,176,208,188,208,
+161,208,168,208,144,208,188,208,176,209,143,208,167,209,130,208,190,208,178,208,
+176,209,129,208,178,208,176,208,188,208,181,208,188,209,131,208,162,208,176,208,
+186,208,180,208,178,208,176,208,189,208,176,208,188,209,141,209,130,208,184,209,
+141,209,130,209,131,208,146,208,176,208,188,209,130,208,181,209,133,208,191,209,
+128,208,190,209,130,209,131,209,130,208,189,208,176,208,180,208,180,208,189,209,
+143,208,146,208,190,209,130,209,130,209,128,208,184,208,189,208,181,208,185,208,
+146,208,176,209,129,208,189,208,184,208,188,209,129,208,176,208,188,209,130,208,
+190,209,130,209,128,209,131,208,177,208,158,208,189,208,184,208,188,208,184,209,
+128,208,189,208,181,208,181,208,158,208,158,208,158,208,187,208,184,209,134,209,
+141,209,130,208,176,208,158,208,189,208,176,208,189,208,181,208,188,208,180,208,
+190,208,188,208,188,208,190,208,185,208,180,208,178,208,181,208,190,208,189,208,
+190,209,129,209,131,208,180,224,164,149,224,165,135,224,164,185,224,165,136,224,
+164,149,224,165,128,224,164,184,224,165,135,224,164,149,224,164,190,224,164,149,
+224,165,139,224,164,148,224,164,176,224,164,170,224,164,176,224,164,168,224,165,
+135,224,164,143,224,164,149,224,164,149,224,164,191,224,164,173,224,165,128,224,
+164,135,224,164,184,224,164,149,224,164,176,224,164,164,224,165,139,224,164,185,
+224,165,139,224,164,134,224,164,170,224,164,185,224,165,128,224,164,175,224,164,
+185,224,164,175,224,164,190,224,164,164,224,164,149,224,164,165,224,164,190,106,
+97,103,114,97,110,224,164,134,224,164,156,224,164,156,224,165,139,224,164,133,
+224,164,172,224,164,166,224,165,139,224,164,151,224,164,136,224,164,156,224,164,
+190,224,164,151,224,164,143,224,164,185,224,164,174,224,164,135,224,164,168,224,
+164,181,224,164,185,224,164,175,224,165,135,224,164,165,224,165,135,224,164,165,
+224,165,128,224,164,152,224,164,176,224,164,156,224,164,172,224,164,166,224,165,
+128,224,164,149,224,164,136,224,164,156,224,165,128,224,164,181,224,165,135,224,
+164,168,224,164,136,224,164,168,224,164,143,224,164,185,224,164,176,224,164,137,
+224,164,184,224,164,174,224,165,135,224,164,149,224,164,174,224,164,181,224,165,
+139,224,164,178,224,165,135,224,164,184,224,164,172,224,164,174,224,164,136,224,
+164,166,224,165,135,224,164,147,224,164,176,224,164,134,224,164,174,224,164,172,
+224,164,184,224,164,173,224,164,176,224,164,172,224,164,168,224,164,154,224,164,
+178,224,164,174,224,164,168,224,164,134,224,164,151,224,164,184,224,165,128,224,
+164,178,224,165,128,216,185,217,132,217,137,216,165,217,132,217,137,217,135,216,
+176,216,167,216,162,216,174,216,177,216,185,216,175,216,175,216,167,217,132,217,
+137,217,135,216,176,217,135,216,181,217,136,216,177,216,186,217,138,216,177,217,
+131,216,167,217,134,217,136,217,132,216,167,216,168,217,138,217,134,216,185,216,
+177,216,182,216,176,217,132,217,131,217,135,217,134,216,167,217,138,217,136,217,
+133,217,130,216,167,217,132,216,185,217,132,217,138,216,167,217,134,216,167,217,
+132,217,131,217,134,216,173,216,170,217,137,217,130,216,168,217,132,217,136,216,
+173,216,169,216,167,216,174,216,177,217,129,217,130,216,183,216,185,216,168,216,
+175,216,177,217,131,217,134,216,165,216,176,216,167,217,131,217,133,216,167,216,
+167,216,173,216,175,216,165,217,132,216,167,217,129,217,138,217,135,216,168,216,
+185,216,182,217,131,217,138,217,129,216,168,216,173,216,171,217,136,217,133,217,
+134,217,136,217,135,217,136,216,163,217,134,216,167,216,172,216,175,216,167,217,
+132,217,135,216,167,216,179,217,132,217,133,216,185,217,134,216,175,217,132,217,
+138,216,179,216,185,216,168,216,177,216,181,217,132,217,137,217,133,217,134,216,
+176,216,168,217,135,216,167,216,163,217,134,217,135,217,133,216,171,217,132,217,
+131,217,134,216,170,216,167,217,132,216,167,216,173,217,138,216,171,217,133,216,
+181,216,177,216,180,216,177,216,173,216,173,217,136,217,132,217,136,217,129,217,
+138,216,167,216,176,216,167,217,132,217,131,217,132,217,133,216,177,216,169,216,
+167,217,134,216,170,216,167,217,132,217,129,216,163,216,168,217,136,216,174,216,
+167,216,181,216,163,217,134,216,170,216,167,217,134,217,135,216,167,217,132,217,
+138,216,185,216,182,217,136,217,136,217,130,216,175,216,167,216,168,217,134,216,
+174,217,138,216,177,216,168,217,134,216,170,217,132,217,131,217,133,216,180,216,
+167,216,161,217,136,217,135,217,138,216,167,216,168,217,136,217,130,216,181,216,
+181,217,136,217,133,216,167,216,177,217,130,217,133,216,163,216,173,216,175,217,
+134,216,173,217,134,216,185,216,175,217,133,216,177,216,163,217,138,216,167,216,
+173,216,169,217,131,216,170,216,168,216,175,217,136,217,134,217,138,216,172,216,
+168,217,133,217,134,217,135,216,170,216,173,216,170,216,172,217,135,216,169,216,
+179,217,134,216,169,217,138,216,170,217,133,217,131,216,177,216,169,216,186,216,
+178,216,169,217,134,217,129,216,179,216,168,217,138,216,170,217,132,217,132,217,
+135,217,132,217,134,216,167,216,170,217,132,217,131,217,130,217,132,216,168,217,
+132,217,133,216,167,216,185,217,134,217,135,216,163,217,136,217,132,216,180,217,
+138,216,161,217,134,217,136,216,177,216,163,217,133,216,167,217,129,217,138,217,
+131,216,168,217,131,217,132,216,176,216,167,216,170,216,177,216,170,216,168,216,
+168,216,163,217,134,217,135,217,133,216,179,216,167,217,134,217,131,216,168,217,
+138,216,185,217,129,217,130,216,175,216,173,216,179,217,134,217,132,217,135,217,
+133,216,180,216,185,216,177,216,163,217,135,217,132,216,180,217,135,216,177,217,
+130,216,183,216,177,216,183,217,132,216,168,112,114,111,102,105,108,101,115,101,
+114,118,105,99,101,100,101,102,97,117,108,116,104,105,109,115,101,108,102,100,
+101,116,97,105,108,115,99,111,110,116,101,110,116,115,117,112,112,111,114,116,
+115,116,97,114,116,101,100,109,101,115,115,97,103,101,115,117,99,99,101,115,115,
+102,97,115,104,105,111,110,60,116,105,116,108,101,62,99,111,117,110,116,114,121,
+97,99,99,111,117,110,116,99,114,101,97,116,101,100,115,116,111,114,105,101,115,
+114,101,115,117,108,116,115,114,117,110,110,105,110,103,112,114,111,99,101,115,
+115,119,114,105,116,105,110,103,111,98,106,101,99,116,115,118,105,115,105,98,108
+,101,119,101,108,99,111,109,101,97,114,116,105,99,108,101,117,110,107,110,111,
+119,110,110,101,116,119,111,114,107,99,111,109,112,97,110,121,100,121,110,97,109
+,105,99,98,114,111,119,115,101,114,112,114,105,118,97,99,121,112,114,111,98,108,
+101,109,83,101,114,118,105,99,101,114,101,115,112,101,99,116,100,105,115,112,108
+,97,121,114,101,113,117,101,115,116,114,101,115,101,114,118,101,119,101,98,115,
+105,116,101,104,105,115,116,111,114,121,102,114,105,101,110,100,115,111,112,116,
+105,111,110,115,119,111,114,107,105,110,103,118,101,114,115,105,111,110,109,105,
+108,108,105,111,110,99,104,97,110,110,101,108,119,105,110,100,111,119,46,97,100,
+100,114,101,115,115,118,105,115,105,116,101,100,119,101,97,116,104,101,114,99,
+111,114,114,101,99,116,112,114,111,100,117,99,116,101,100,105,114,101,99,116,102
+,111,114,119,97,114,100,121,111,117,32,99,97,110,114,101,109,111,118,101,100,115
+,117,98,106,101,99,116,99,111,110,116,114,111,108,97,114,99,104,105,118,101,99,
+117,114,114,101,110,116,114,101,97,100,105,110,103,108,105,98,114,97,114,121,108
+,105,109,105,116,101,100,109,97,110,97,103,101,114,102,117,114,116,104,101,114,
+115,117,109,109,97,114,121,109,97,99,104,105,110,101,109,105,110,117,116,101,115
+,112,114,105,118,97,116,101,99,111,110,116,101,120,116,112,114,111,103,114,97,
+109,115,111,99,105,101,116,121,110,117,109,98,101,114,115,119,114,105,116,116,
+101,110,101,110,97,98,108,101,100,116,114,105,103,103,101,114,115,111,117,114,99
+,101,115,108,111,97,100,105,110,103,101,108,101,109,101,110,116,112,97,114,116,
+110,101,114,102,105,110,97,108,108,121,112,101,114,102,101,99,116,109,101,97,110
+,105,110,103,115,121,115,116,101,109,115,107,101,101,112,105,110,103,99,117,108,
+116,117,114,101,38,113,117,111,116,59,44,106,111,117,114,110,97,108,112,114,111,
+106,101,99,116,115,117,114,102,97,99,101,115,38,113,117,111,116,59,101,120,112,
+105,114,101,115,114,101,118,105,101,119,115,98,97,108,97,110,99,101,69,110,103,
+108,105,115,104,67,111,110,116,101,110,116,116,104,114,111,117,103,104,80,108,
+101,97,115,101,32,111,112,105,110,105,111,110,99,111,110,116,97,99,116,97,118,
+101,114,97,103,101,112,114,105,109,97,114,121,118,105,108,108,97,103,101,83,112,
+97,110,105,115,104,103,97,108,108,101,114,121,100,101,99,108,105,110,101,109,101
+,101,116,105,110,103,109,105,115,115,105,111,110,112,111,112,117,108,97,114,113,
+117,97,108,105,116,121,109,101,97,115,117,114,101,103,101,110,101,114,97,108,115
+,112,101,99,105,101,115,115,101,115,115,105,111,110,115,101,99,116,105,111,110,
+119,114,105,116,101,114,115,99,111,117,110,116,101,114,105,110,105,116,105,97,
+108,114,101,112,111,114,116,115,102,105,103,117,114,101,115,109,101,109,98,101,
+114,115,104,111,108,100,105,110,103,100,105,115,112,117,116,101,101,97,114,108,
+105,101,114,101,120,112,114,101,115,115,100,105,103,105,116,97,108,112,105,99,
+116,117,114,101,65,110,111,116,104,101,114,109,97,114,114,105,101,100,116,114,97
+,102,102,105,99,108,101,97,100,105,110,103,99,104,97,110,103,101,100,99,101,110,
+116,114,97,108,118,105,99,116,111,114,121,105,109,97,103,101,115,47,114,101,97,
+115,111,110,115,115,116,117,100,105,101,115,102,101,97,116,117,114,101,108,105,
+115,116,105,110,103,109,117,115,116,32,98,101,115,99,104,111,111,108,115,86,101,
+114,115,105,111,110,117,115,117,97,108,108,121,101,112,105,115,111,100,101,112,
+108,97,121,105,110,103,103,114,111,119,105,110,103,111,98,118,105,111,117,115,
+111,118,101,114,108,97,121,112,114,101,115,101,110,116,97,99,116,105,111,110,115
+,60,47,117,108,62,13,10,119,114,97,112,112,101,114,97,108,114,101,97,100,121,99,
+101,114,116,97,105,110,114,101,97,108,105,116,121,115,116,111,114,97,103,101,97,
+110,111,116,104,101,114,100,101,115,107,116,111,112,111,102,102,101,114,101,100,
+112,97,116,116,101,114,110,117,110,117,115,117,97,108,68,105,103,105,116,97,108,
+99,97,112,105,116,97,108,87,101,98,115,105,116,101,102,97,105,108,117,114,101,99
+,111,110,110,101,99,116,114,101,100,117,99,101,100,65,110,100,114,111,105,100,
+100,101,99,97,100,101,115,114,101,103,117,108,97,114,32,38,97,109,112,59,32,97,
+110,105,109,97,108,115,114,101,108,101,97,115,101,65,117,116,111,109,97,116,103,
+101,116,116,105,110,103,109,101,116,104,111,100,115,110,111,116,104,105,110,103,
+80,111,112,117,108,97,114,99,97,112,116,105,111,110,108,101,116,116,101,114,115,
+99,97,112,116,117,114,101,115,99,105,101,110,99,101,108,105,99,101,110,115,101,
+99,104,97,110,103,101,115,69,110,103,108,97,110,100,61,49,38,97,109,112,59,72,
+105,115,116,111,114,121,32,61,32,110,101,119,32,67,101,110,116,114,97,108,117,
+112,100,97,116,101,100,83,112,101,99,105,97,108,78,101,116,119,111,114,107,114,
+101,113,117,105,114,101,99,111,109,109,101,110,116,119,97,114,110,105,110,103,67
+,111,108,108,101,103,101,116,111,111,108,98,97,114,114,101,109,97,105,110,115,98
+,101,99,97,117,115,101,101,108,101,99,116,101,100,68,101,117,116,115,99,104,102,
+105,110,97,110,99,101,119,111,114,107,101,114,115,113,117,105,99,107,108,121,98,
+101,116,119,101,101,110,101,120,97,99,116,108,121,115,101,116,116,105,110,103,
+100,105,115,101,97,115,101,83,111,99,105,101,116,121,119,101,97,112,111,110,115,
+101,120,104,105,98,105,116,38,108,116,59,33,45,45,67,111,110,116,114,111,108,99,
+108,97,115,115,101,115,99,111,118,101,114,101,100,111,117,116,108,105,110,101,97
+,116,116,97,99,107,115,100,101,118,105,99,101,115,40,119,105,110,100,111,119,112
+,117,114,112,111,115,101,116,105,116,108,101,61,34,77,111,98,105,108,101,32,107,
+105,108,108,105,110,103,115,104,111,119,105,110,103,73,116,97,108,105,97,110,100
+,114,111,112,112,101,100,104,101,97,118,105,108,121,101,102,102,101,99,116,115,
+45,49,39,93,41,59,10,99,111,110,102,105,114,109,67,117,114,114,101,110,116,97,
+100,118,97,110,99,101,115,104,97,114,105,110,103,111,112,101,110,105,110,103,100
+,114,97,119,105,110,103,98,105,108,108,105,111,110,111,114,100,101,114,101,100,
+71,101,114,109,97,110,121,114,101,108,97,116,101,100,60,47,102,111,114,109,62,
+105,110,99,108,117,100,101,119,104,101,116,104,101,114,100,101,102,105,110,101,
+100,83,99,105,101,110,99,101,99,97,116,97,108,111,103,65,114,116,105,99,108,101,
+98,117,116,116,111,110,115,108,97,114,103,101,115,116,117,110,105,102,111,114,
+109,106,111,117,114,110,101,121,115,105,100,101,98,97,114,67,104,105,99,97,103,
+111,104,111,108,105,100,97,121,71,101,110,101,114,97,108,112,97,115,115,97,103,
+101,44,38,113,117,111,116,59,97,110,105,109,97,116,101,102,101,101,108,105,110,
+103,97,114,114,105,118,101,100,112,97,115,115,105,110,103,110,97,116,117,114,97,
+108,114,111,117,103,104,108,121,46,10,10,84,104,101,32,98,117,116,32,110,111,116
+,100,101,110,115,105,116,121,66,114,105,116,97,105,110,67,104,105,110,101,115,
+101,108,97,99,107,32,111,102,116,114,105,98,117,116,101,73,114,101,108,97,110,
+100,34,32,100,97,116,97,45,102,97,99,116,111,114,115,114,101,99,101,105,118,101,
+116,104,97,116,32,105,115,76,105,98,114,97,114,121,104,117,115,98,97,110,100,105
+,110,32,102,97,99,116,97,102,102,97,105,114,115,67,104,97,114,108,101,115,114,97
+,100,105,99,97,108,98,114,111,117,103,104,116,102,105,110,100,105,110,103,108,97
+,110,100,105,110,103,58,108,97,110,103,61,34,114,101,116,117,114,110,32,108,101,
+97,100,101,114,115,112,108,97,110,110,101,100,112,114,101,109,105,117,109,112,97
+,99,107,97,103,101,65,109,101,114,105,99,97,69,100,105,116,105,111,110,93,38,113
+,117,111,116,59,77,101,115,115,97,103,101,110,101,101,100,32,116,111,118,97,108,
+117,101,61,34,99,111,109,112,108,101,120,108,111,111,107,105,110,103,115,116,97,
+116,105,111,110,98,101,108,105,101,118,101,115,109,97,108,108,101,114,45,109,111
+,98,105,108,101,114,101,99,111,114,100,115,119,97,110,116,32,116,111,107,105,110
+,100,32,111,102,70,105,114,101,102,111,120,121,111,117,32,97,114,101,115,105,109
+,105,108,97,114,115,116,117,100,105,101,100,109,97,120,105,109,117,109,104,101,
+97,100,105,110,103,114,97,112,105,100,108,121,99,108,105,109,97,116,101,107,105,
+110,103,100,111,109,101,109,101,114,103,101,100,97,109,111,117,110,116,115,102,
+111,117,110,100,101,100,112,105,111,110,101,101,114,102,111,114,109,117,108,97,
+100,121,110,97,115,116,121,104,111,119,32,116,111,32,83,117,112,112,111,114,116,
+114,101,118,101,110,117,101,101,99,111,110,111,109,121,82,101,115,117,108,116,
+115,98,114,111,116,104,101,114,115,111,108,100,105,101,114,108,97,114,103,101,
+108,121,99,97,108,108,105,110,103,46,38,113,117,111,116,59,65,99,99,111,117,110,
+116,69,100,119,97,114,100,32,115,101,103,109,101,110,116,82,111,98,101,114,116,
+32,101,102,102,111,114,116,115,80,97,99,105,102,105,99,108,101,97,114,110,101,
+100,117,112,32,119,105,116,104,104,101,105,103,104,116,58,119,101,32,104,97,118,
+101,65,110,103,101,108,101,115,110,97,116,105,111,110,115,95,115,101,97,114,99,
+104,97,112,112,108,105,101,100,97,99,113,117,105,114,101,109,97,115,115,105,118,
+101,103,114,97,110,116,101,100,58,32,102,97,108,115,101,116,114,101,97,116,101,
+100,98,105,103,103,101,115,116,98,101,110,101,102,105,116,100,114,105,118,105,
+110,103,83,116,117,100,105,101,115,109,105,110,105,109,117,109,112,101,114,104,
+97,112,115,109,111,114,110,105,110,103,115,101,108,108,105,110,103,105,115,32,
+117,115,101,100,114,101,118,101,114,115,101,118,97,114,105,97,110,116,32,114,111
+,108,101,61,34,109,105,115,115,105,110,103,97,99,104,105,101,118,101,112,114,111
+,109,111,116,101,115,116,117,100,101,110,116,115,111,109,101,111,110,101,101,120
+,116,114,101,109,101,114,101,115,116,111,114,101,98,111,116,116,111,109,58,101,
+118,111,108,118,101,100,97,108,108,32,116,104,101,115,105,116,101,109,97,112,101
+,110,103,108,105,115,104,119,97,121,32,116,111,32,32,65,117,103,117,115,116,115,
+121,109,98,111,108,115,67,111,109,112,97,110,121,109,97,116,116,101,114,115,109,
+117,115,105,99,97,108,97,103,97,105,110,115,116,115,101,114,118,105,110,103,125,
+41,40,41,59,13,10,112,97,121,109,101,110,116,116,114,111,117,98,108,101,99,111,
+110,99,101,112,116,99,111,109,112,97,114,101,112,97,114,101,110,116,115,112,108,
+97,121,101,114,115,114,101,103,105,111,110,115,109,111,110,105,116,111,114,32,39
+,39,84,104,101,32,119,105,110,110,105,110,103,101,120,112,108,111,114,101,97,100
+,97,112,116,101,100,71,97,108,108,101,114,121,112,114,111,100,117,99,101,97,98,
+105,108,105,116,121,101,110,104,97,110,99,101,99,97,114,101,101,114,115,41,46,32
+,84,104,101,32,99,111,108,108,101,99,116,83,101,97,114,99,104,32,97,110,99,105,
+101,110,116,101,120,105,115,116,101,100,102,111,111,116,101,114,32,104,97,110,
+100,108,101,114,112,114,105,110,116,101,100,99,111,110,115,111,108,101,69,97,115
+,116,101,114,110,101,120,112,111,114,116,115,119,105,110,100,111,119,115,67,104,
+97,110,110,101,108,105,108,108,101,103,97,108,110,101,117,116,114,97,108,115,117
+,103,103,101,115,116,95,104,101,97,100,101,114,115,105,103,110,105,110,103,46,
+104,116,109,108,34,62,115,101,116,116,108,101,100,119,101,115,116,101,114,110,99
+,97,117,115,105,110,103,45,119,101,98,107,105,116,99,108,97,105,109,101,100,74,
+117,115,116,105,99,101,99,104,97,112,116,101,114,118,105,99,116,105,109,115,84,
+104,111,109,97,115,32,109,111,122,105,108,108,97,112,114,111,109,105,115,101,112
+,97,114,116,105,101,115,101,100,105,116,105,111,110,111,117,116,115,105,100,101,
+58,102,97,108,115,101,44,104,117,110,100,114,101,100,79,108,121,109,112,105,99,
+95,98,117,116,116,111,110,97,117,116,104,111,114,115,114,101,97,99,104,101,100,
+99,104,114,111,110,105,99,100,101,109,97,110,100,115,115,101,99,111,110,100,115,
+112,114,111,116,101,99,116,97,100,111,112,116,101,100,112,114,101,112,97,114,101
+,110,101,105,116,104,101,114,103,114,101,97,116,108,121,103,114,101,97,116,101,
+114,111,118,101,114,97,108,108,105,109,112,114,111,118,101,99,111,109,109,97,110
+,100,115,112,101,99,105,97,108,115,101,97,114,99,104,46,119,111,114,115,104,105,
+112,102,117,110,100,105,110,103,116,104,111,117,103,104,116,104,105,103,104,101,
+115,116,105,110,115,116,101,97,100,117,116,105,108,105,116,121,113,117,97,114,
+116,101,114,67,117,108,116,117,114,101,116,101,115,116,105,110,103,99,108,101,97
+,114,108,121,101,120,112,111,115,101,100,66,114,111,119,115,101,114,108,105,98,
+101,114,97,108,125,32,99,97,116,99,104,80,114,111,106,101,99,116,101,120,97,109,
+112,108,101,104,105,100,101,40,41,59,70,108,111,114,105,100,97,97,110,115,119,
+101,114,115,97,108,108,111,119,101,100,69,109,112,101,114,111,114,100,101,102,
+101,110,115,101,115,101,114,105,111,117,115,102,114,101,101,100,111,109,83,101,
+118,101,114,97,108,45,98,117,116,116,111,110,70,117,114,116,104,101,114,111,117,
+116,32,111,102,32,33,61,32,110,117,108,108,116,114,97,105,110,101,100,68,101,110
+,109,97,114,107,118,111,105,100,40,48,41,47,97,108,108,46,106,115,112,114,101,
+118,101,110,116,82,101,113,117,101,115,116,83,116,101,112,104,101,110,10,10,87,
+104,101,110,32,111,98,115,101,114,118,101,60,47,104,50,62,13,10,77,111,100,101,
+114,110,32,112,114,111,118,105,100,101,34,32,97,108,116,61,34,98,111,114,100,101
+,114,115,46,10,10,70,111,114,32,10,10,77,97,110,121,32,97,114,116,105,115,116,
+115,112,111,119,101,114,101,100,112,101,114,102,111,114,109,102,105,99,116,105,
+111,110,116,121,112,101,32,111,102,109,101,100,105,99,97,108,116,105,99,107,101,
+116,115,111,112,112,111,115,101,100,67,111,117,110,99,105,108,119,105,116,110,
+101,115,115,106,117,115,116,105,99,101,71,101,111,114,103,101,32,66,101,108,103,
+105,117,109,46,46,46,60,47,97,62,116,119,105,116,116,101,114,110,111,116,97,98,
+108,121,119,97,105,116,105,110,103,119,97,114,102,97,114,101,32,79,116,104,101,
+114,32,114,97,110,107,105,110,103,112,104,114,97,115,101,115,109,101,110,116,105
+,111,110,115,117,114,118,105,118,101,115,99,104,111,108,97,114,60,47,112,62,13,
+10,32,67,111,117,110,116,114,121,105,103,110,111,114,101,100,108,111,115,115,32,
+111,102,106,117,115,116,32,97,115,71,101,111,114,103,105,97,115,116,114,97,110,
+103,101,60,104,101,97,100,62,60,115,116,111,112,112,101,100,49,39,93,41,59,13,10
+,105,115,108,97,110,100,115,110,111,116,97,98,108,101,98,111,114,100,101,114,58,
+108,105,115,116,32,111,102,99,97,114,114,105,101,100,49,48,48,44,48,48,48,60,47,
+104,51,62,10,32,115,101,118,101,114,97,108,98,101,99,111,109,101,115,115,101,108
+,101,99,116,32,119,101,100,100,105,110,103,48,48,46,104,116,109,108,109,111,110,
+97,114,99,104,111,102,102,32,116,104,101,116,101,97,99,104,101,114,104,105,103,
+104,108,121,32,98,105,111,108,111,103,121,108,105,102,101,32,111,102,111,114,32,
+101,118,101,110,114,105,115,101,32,111,102,38,114,97,113,117,111,59,112,108,117,
+115,111,110,101,104,117,110,116,105,110,103,40,116,104,111,117,103,104,68,111,
+117,103,108,97,115,106,111,105,110,105,110,103,99,105,114,99,108,101,115,70,111,
+114,32,116,104,101,65,110,99,105,101,110,116,86,105,101,116,110,97,109,118,101,
+104,105,99,108,101,115,117,99,104,32,97,115,99,114,121,115,116,97,108,118,97,108
+,117,101,32,61,87,105,110,100,111,119,115,101,110,106,111,121,101,100,97,32,115,
+109,97,108,108,97,115,115,117,109,101,100,60,97,32,105,100,61,34,102,111,114,101
+,105,103,110,32,65,108,108,32,114,105,104,111,119,32,116,104,101,68,105,115,112,
+108,97,121,114,101,116,105,114,101,100,104,111,119,101,118,101,114,104,105,100,
+100,101,110,59,98,97,116,116,108,101,115,115,101,101,107,105,110,103,99,97,98,
+105,110,101,116,119,97,115,32,110,111,116,108,111,111,107,32,97,116,99,111,110,
+100,117,99,116,103,101,116,32,116,104,101,74,97,110,117,97,114,121,104,97,112,
+112,101,110,115,116,117,114,110,105,110,103,97,58,104,111,118,101,114,79,110,108
+,105,110,101,32,70,114,101,110,99,104,32,108,97,99,107,105,110,103,116,121,112,
+105,99,97,108,101,120,116,114,97,99,116,101,110,101,109,105,101,115,101,118,101,
+110,32,105,102,103,101,110,101,114,97,116,100,101,99,105,100,101,100,97,114,101,
+32,110,111,116,47,115,101,97,114,99,104,98,101,108,105,101,102,115,45,105,109,97
+,103,101,58,108,111,99,97,116,101,100,115,116,97,116,105,99,46,108,111,103,105,
+110,34,62,99,111,110,118,101,114,116,118,105,111,108,101,110,116,101,110,116,101
+,114,101,100,102,105,114,115,116,34,62,99,105,114,99,117,105,116,70,105,110,108,
+97,110,100,99,104,101,109,105,115,116,115,104,101,32,119,97,115,49,48,112,120,59
+,34,62,97,115,32,115,117,99,104,100,105,118,105,100,101,100,60,47,115,112,97,110
+,62,119,105,108,108,32,98,101,108,105,110,101,32,111,102,97,32,103,114,101,97,
+116,109,121,115,116,101,114,121,47,105,110,100,101,120,46,102,97,108,108,105,110
+,103,100,117,101,32,116,111,32,114,97,105,108,119,97,121,99,111,108,108,101,103,
+101,109,111,110,115,116,101,114,100,101,115,99,101,110,116,105,116,32,119,105,
+116,104,110,117,99,108,101,97,114,74,101,119,105,115,104,32,112,114,111,116,101,
+115,116,66,114,105,116,105,115,104,102,108,111,119,101,114,115,112,114,101,100,
+105,99,116,114,101,102,111,114,109,115,98,117,116,116,111,110,32,119,104,111,32,
+119,97,115,108,101,99,116,117,114,101,105,110,115,116,97,110,116,115,117,105,99,
+105,100,101,103,101,110,101,114,105,99,112,101,114,105,111,100,115,109,97,114,
+107,101,116,115,83,111,99,105,97,108,32,102,105,115,104,105,110,103,99,111,109,
+98,105,110,101,103,114,97,112,104,105,99,119,105,110,110,101,114,115,60,98,114,
+32,47,62,60,98,121,32,116,104,101,32,78,97,116,117,114,97,108,80,114,105,118,97,
+99,121,99,111,111,107,105,101,115,111,117,116,99,111,109,101,114,101,115,111,108
+,118,101,83,119,101,100,105,115,104,98,114,105,101,102,108,121,80,101,114,115,
+105,97,110,115,111,32,109,117,99,104,67,101,110,116,117,114,121,100,101,112,105,
+99,116,115,99,111,108,117,109,110,115,104,111,117,115,105,110,103,115,99,114,105
+,112,116,115,110,101,120,116,32,116,111,98,101,97,114,105,110,103,109,97,112,112
+,105,110,103,114,101,118,105,115,101,100,106,81,117,101,114,121,40,45,119,105,
+100,116,104,58,116,105,116,108,101,34,62,116,111,111,108,116,105,112,83,101,99,
+116,105,111,110,100,101,115,105,103,110,115,84,117,114,107,105,115,104,121,111,
+117,110,103,101,114,46,109,97,116,99,104,40,125,41,40,41,59,10,10,98,117,114,110
+,105,110,103,111,112,101,114,97,116,101,100,101,103,114,101,101,115,115,111,117,
+114,99,101,61,82,105,99,104,97,114,100,99,108,111,115,101,108,121,112,108,97,115
+,116,105,99,101,110,116,114,105,101,115,60,47,116,114,62,13,10,99,111,108,111,
+114,58,35,117,108,32,105,100,61,34,112,111,115,115,101,115,115,114,111,108,108,
+105,110,103,112,104,121,115,105,99,115,102,97,105,108,105,110,103,101,120,101,99
+,117,116,101,99,111,110,116,101,115,116,108,105,110,107,32,116,111,68,101,102,97
+,117,108,116,60,98,114,32,47,62,10,58,32,116,114,117,101,44,99,104,97,114,116,
+101,114,116,111,117,114,105,115,109,99,108,97,115,115,105,99,112,114,111,99,101,
+101,100,101,120,112,108,97,105,110,60,47,104,49,62,13,10,111,110,108,105,110,101
+,46,63,120,109,108,32,118,101,104,101,108,112,105,110,103,100,105,97,109,111,110
+,100,117,115,101,32,116,104,101,97,105,114,108,105,110,101,101,110,100,32,45,45,
+62,41,46,97,116,116,114,40,114,101,97,100,101,114,115,104,111,115,116,105,110,
+103,35,102,102,102,102,102,102,114,101,97,108,105,122,101,86,105,110,99,101,110,
+116,115,105,103,110,97,108,115,32,115,114,99,61,34,47,80,114,111,100,117,99,116,
+100,101,115,112,105,116,101,100,105,118,101,114,115,101,116,101,108,108,105,110,
+103,80,117,98,108,105,99,32,104,101,108,100,32,105,110,74,111,115,101,112,104,32
+,116,104,101,97,116,114,101,97,102,102,101,99,116,115,60,115,116,121,108,101,62,
+97,32,108,97,114,103,101,100,111,101,115,110,39,116,108,97,116,101,114,44,32,69,
+108,101,109,101,110,116,102,97,118,105,99,111,110,99,114,101,97,116,111,114,72,
+117,110,103,97,114,121,65,105,114,112,111,114,116,115,101,101,32,116,104,101,115
+,111,32,116,104,97,116,77,105,99,104,97,101,108,83,121,115,116,101,109,115,80,
+114,111,103,114,97,109,115,44,32,97,110,100,32,32,119,105,100,116,104,61,101,38,
+113,117,111,116,59,116,114,97,100,105,110,103,108,101,102,116,34,62,10,112,101,
+114,115,111,110,115,71,111,108,100,101,110,32,65,102,102,97,105,114,115,103,114,
+97,109,109,97,114,102,111,114,109,105,110,103,100,101,115,116,114,111,121,105,
+100,101,97,32,111,102,99,97,115,101,32,111,102,111,108,100,101,115,116,32,116,
+104,105,115,32,105,115,46,115,114,99,32,61,32,99,97,114,116,111,111,110,114,101,
+103,105,115,116,114,67,111,109,109,111,110,115,77,117,115,108,105,109,115,87,104
+,97,116,32,105,115,105,110,32,109,97,110,121,109,97,114,107,105,110,103,114,101,
+118,101,97,108,115,73,110,100,101,101,100,44,101,113,117,97,108,108,121,47,115,
+104,111,119,95,97,111,117,116,100,111,111,114,101,115,99,97,112,101,40,65,117,
+115,116,114,105,97,103,101,110,101,116,105,99,115,121,115,116,101,109,44,73,110,
+32,116,104,101,32,115,105,116,116,105,110,103,72,101,32,97,108,115,111,73,115,
+108,97,110,100,115,65,99,97,100,101,109,121,10,9,9,60,33,45,45,68,97,110,105,101
+,108,32,98,105,110,100,105,110,103,98,108,111,99,107,34,62,105,109,112,111,115,
+101,100,117,116,105,108,105,122,101,65,98,114,97,104,97,109,40,101,120,99,101,
+112,116,123,119,105,100,116,104,58,112,117,116,116,105,110,103,41,46,104,116,109
+,108,40,124,124,32,91,93,59,10,68,65,84,65,91,32,42,107,105,116,99,104,101,110,
+109,111,117,110,116,101,100,97,99,116,117,97,108,32,100,105,97,108,101,99,116,
+109,97,105,110,108,121,32,95,98,108,97,110,107,39,105,110,115,116,97,108,108,101
+,120,112,101,114,116,115,105,102,40,116,121,112,101,73,116,32,97,108,115,111,38,
+99,111,112,121,59,32,34,62,84,101,114,109,115,98,111,114,110,32,105,110,79,112,
+116,105,111,110,115,101,97,115,116,101,114,110,116,97,108,107,105,110,103,99,111
+,110,99,101,114,110,103,97,105,110,101,100,32,111,110,103,111,105,110,103,106,
+117,115,116,105,102,121,99,114,105,116,105,99,115,102,97,99,116,111,114,121,105,
+116,115,32,111,119,110,97,115,115,97,117,108,116,105,110,118,105,116,101,100,108
+,97,115,116,105,110,103,104,105,115,32,111,119,110,104,114,101,102,61,34,47,34,
+32,114,101,108,61,34,100,101,118,101,108,111,112,99,111,110,99,101,114,116,100,
+105,97,103,114,97,109,100,111,108,108,97,114,115,99,108,117,115,116,101,114,112,
+104,112,63,105,100,61,97,108,99,111,104,111,108,41,59,125,41,40,41,59,117,115,
+105,110,103,32,97,62,60,115,112,97,110,62,118,101,115,115,101,108,115,114,101,
+118,105,118,97,108,65,100,100,114,101,115,115,97,109,97,116,101,117,114,97,110,
+100,114,111,105,100,97,108,108,101,103,101,100,105,108,108,110,101,115,115,119,
+97,108,107,105,110,103,99,101,110,116,101,114,115,113,117,97,108,105,102,121,109
+,97,116,99,104,101,115,117,110,105,102,105,101,100,101,120,116,105,110,99,116,68
+,101,102,101,110,115,101,100,105,101,100,32,105,110,10,9,60,33,45,45,32,99,117,
+115,116,111,109,115,108,105,110,107,105,110,103,76,105,116,116,108,101,32,66,111
+,111,107,32,111,102,101,118,101,110,105,110,103,109,105,110,46,106,115,63,97,114
+,101,32,116,104,101,107,111,110,116,97,107,116,116,111,100,97,121,39,115,46,104,
+116,109,108,34,32,116,97,114,103,101,116,61,119,101,97,114,105,110,103,65,108,
+108,32,82,105,103,59,10,125,41,40,41,59,114,97,105,115,105,110,103,32,65,108,115
+,111,44,32,99,114,117,99,105,97,108,97,98,111,117,116,34,62,100,101,99,108,97,
+114,101,45,45,62,10,60,115,99,102,105,114,101,102,111,120,97,115,32,109,117,99,
+104,97,112,112,108,105,101,115,105,110,100,101,120,44,32,115,44,32,98,117,116,32
+,116,121,112,101,32,61,32,10,13,10,60,33,45,45,116,111,119,97,114,100,115,82,101
+,99,111,114,100,115,80,114,105,118,97,116,101,70,111,114,101,105,103,110,80,114,
+101,109,105,101,114,99,104,111,105,99,101,115,86,105,114,116,117,97,108,114,101,
+116,117,114,110,115,67,111,109,109,101,110,116,80,111,119,101,114,101,100,105,
+110,108,105,110,101,59,112,111,118,101,114,116,121,99,104,97,109,98,101,114,76,
+105,118,105,110,103,32,118,111,108,117,109,101,115,65,110,116,104,111,110,121,
+108,111,103,105,110,34,32,82,101,108,97,116,101,100,69,99,111,110,111,109,121,
+114,101,97,99,104,101,115,99,117,116,116,105,110,103,103,114,97,118,105,116,121,
+108,105,102,101,32,105,110,67,104,97,112,116,101,114,45,115,104,97,100,111,119,
+78,111,116,97,98,108,101,60,47,116,100,62,13,10,32,114,101,116,117,114,110,115,
+116,97,100,105,117,109,119,105,100,103,101,116,115,118,97,114,121,105,110,103,
+116,114,97,118,101,108,115,104,101,108,100,32,98,121,119,104,111,32,97,114,101,
+119,111,114,107,32,105,110,102,97,99,117,108,116,121,97,110,103,117,108,97,114,
+119,104,111,32,104,97,100,97,105,114,112,111,114,116,116,111,119,110,32,111,102,
+10,10,83,111,109,101,32,39,99,108,105,99,107,39,99,104,97,114,103,101,115,107,
+101,121,119,111,114,100,105,116,32,119,105,108,108,99,105,116,121,32,111,102,40,
+116,104,105,115,41,59,65,110,100,114,101,119,32,117,110,105,113,117,101,32,99,
+104,101,99,107,101,100,111,114,32,109,111,114,101,51,48,48,112,120,59,32,114,101
+,116,117,114,110,59,114,115,105,111,110,61,34,112,108,117,103,105,110,115,119,
+105,116,104,105,110,32,104,101,114,115,101,108,102,83,116,97,116,105,111,110,70,
+101,100,101,114,97,108,118,101,110,116,117,114,101,112,117,98,108,105,115,104,
+115,101,110,116,32,116,111,116,101,110,115,105,111,110,97,99,116,114,101,115,115
+,99,111,109,101,32,116,111,102,105,110,103,101,114,115,68,117,107,101,32,111,102
+,112,101,111,112,108,101,44,101,120,112,108,111,105,116,119,104,97,116,32,105,
+115,104,97,114,109,111,110,121,97,32,109,97,106,111,114,34,58,34,104,116,116,112
+,105,110,32,104,105,115,32,109,101,110,117,34,62,10,109,111,110,116,104,108,121,
+111,102,102,105,99,101,114,99,111,117,110,99,105,108,103,97,105,110,105,110,103,
+101,118,101,110,32,105,110,83,117,109,109,97,114,121,100,97,116,101,32,111,102,
+108,111,121,97,108,116,121,102,105,116,110,101,115,115,97,110,100,32,119,97,115,
+101,109,112,101,114,111,114,115,117,112,114,101,109,101,83,101,99,111,110,100,32
+,104,101,97,114,105,110,103,82,117,115,115,105,97,110,108,111,110,103,101,115,
+116,65,108,98,101,114,116,97,108,97,116,101,114,97,108,115,101,116,32,111,102,32
+,115,109,97,108,108,34,62,46,97,112,112,101,110,100,100,111,32,119,105,116,104,
+102,101,100,101,114,97,108,98,97,110,107,32,111,102,98,101,110,101,97,116,104,68
+,101,115,112,105,116,101,67,97,112,105,116,97,108,103,114,111,117,110,100,115,41
+,44,32,97,110,100,32,112,101,114,99,101,110,116,105,116,32,102,114,111,109,99,
+108,111,115,105,110,103,99,111,110,116,97,105,110,73,110,115,116,101,97,100,102,
+105,102,116,101,101,110,97,115,32,119,101,108,108,46,121,97,104,111,111,46,114,
+101,115,112,111,110,100,102,105,103,104,116,101,114,111,98,115,99,117,114,101,
+114,101,102,108,101,99,116,111,114,103,97,110,105,99,61,32,77,97,116,104,46,101,
+100,105,116,105,110,103,111,110,108,105,110,101,32,112,97,100,100,105,110,103,97
+,32,119,104,111,108,101,111,110,101,114,114,111,114,121,101,97,114,32,111,102,
+101,110,100,32,111,102,32,98,97,114,114,105,101,114,119,104,101,110,32,105,116,
+104,101,97,100,101,114,32,104,111,109,101,32,111,102,114,101,115,117,109,101,100
+,114,101,110,97,109,101,100,115,116,114,111,110,103,62,104,101,97,116,105,110,
+103,114,101,116,97,105,110,115,99,108,111,117,100,102,114,119,97,121,32,111,102,
+32,77,97,114,99,104,32,49,107,110,111,119,105,110,103,105,110,32,112,97,114,116,
+66,101,116,119,101,101,110,108,101,115,115,111,110,115,99,108,111,115,101,115,
+116,118,105,114,116,117,97,108,108,105,110,107,115,34,62,99,114,111,115,115,101,
+100,69,78,68,32,45,45,62,102,97,109,111,117,115,32,97,119,97,114,100,101,100,76,
+105,99,101,110,115,101,72,101,97,108,116,104,32,102,97,105,114,108,121,32,119,
+101,97,108,116,104,121,109,105,110,105,109,97,108,65,102,114,105,99,97,110,99,
+111,109,112,101,116,101,108,97,98,101,108,34,62,115,105,110,103,105,110,103,102,
+97,114,109,101,114,115,66,114,97,115,105,108,41,100,105,115,99,117,115,115,114,
+101,112,108,97,99,101,71,114,101,103,111,114,121,102,111,110,116,32,99,111,112,
+117,114,115,117,101,100,97,112,112,101,97,114,115,109,97,107,101,32,117,112,114,
+111,117,110,100,101,100,98,111,116,104,32,111,102,98,108,111,99,107,101,100,115,
+97,119,32,116,104,101,111,102,102,105,99,101,115,99,111,108,111,117,114,115,105,
+102,40,100,111,99,117,119,104,101,110,32,104,101,101,110,102,111,114,99,101,112,
+117,115,104,40,102,117,65,117,103,117,115,116,32,85,84,70,45,56,34,62,70,97,110,
+116,97,115,121,105,110,32,109,111,115,116,105,110,106,117,114,101,100,85,115,117
+,97,108,108,121,102,97,114,109,105,110,103,99,108,111,115,117,114,101,111,98,106
+,101,99,116,32,100,101,102,101,110,99,101,117,115,101,32,111,102,32,77,101,100,
+105,99,97,108,60,98,111,100,121,62,10,101,118,105,100,101,110,116,98,101,32,117,
+115,101,100,107,101,121,67,111,100,101,115,105,120,116,101,101,110,73,115,108,97
+,109,105,99,35,48,48,48,48,48,48,101,110,116,105,114,101,32,119,105,100,101,108,
+121,32,97,99,116,105,118,101,32,40,116,121,112,101,111,102,111,110,101,32,99,97,
+110,99,111,108,111,114,32,61,115,112,101,97,107,101,114,101,120,116,101,110,100,
+115,80,104,121,115,105,99,115,116,101,114,114,97,105,110,60,116,98,111,100,121,
+62,102,117,110,101,114,97,108,118,105,101,119,105,110,103,109,105,100,100,108,
+101,32,99,114,105,99,107,101,116,112,114,111,112,104,101,116,115,104,105,102,116
+,101,100,100,111,99,116,111,114,115,82,117,115,115,101,108,108,32,116,97,114,103
+,101,116,99,111,109,112,97,99,116,97,108,103,101,98,114,97,115,111,99,105,97,108
+,45,98,117,108,107,32,111,102,109,97,110,32,97,110,100,60,47,116,100,62,10,32,
+104,101,32,108,101,102,116,41,46,118,97,108,40,41,102,97,108,115,101,41,59,108,
+111,103,105,99,97,108,98,97,110,107,105,110,103,104,111,109,101,32,116,111,110,
+97,109,105,110,103,32,65,114,105,122,111,110,97,99,114,101,100,105,116,115,41,59
+,10,125,41,59,10,102,111,117,110,100,101,114,105,110,32,116,117,114,110,67,111,
+108,108,105,110,115,98,101,102,111,114,101,32,66,117,116,32,116,104,101,99,104,
+97,114,103,101,100,84,105,116,108,101,34,62,67,97,112,116,97,105,110,115,112,101
+,108,108,101,100,103,111,100,100,101,115,115,84,97,103,32,45,45,62,65,100,100,
+105,110,103,58,98,117,116,32,119,97,115,82,101,99,101,110,116,32,112,97,116,105,
+101,110,116,98,97,99,107,32,105,110,61,102,97,108,115,101,38,76,105,110,99,111,
+108,110,119,101,32,107,110,111,119,67,111,117,110,116,101,114,74,117,100,97,105,
+115,109,115,99,114,105,112,116,32,97,108,116,101,114,101,100,39,93,41,59,10,32,
+32,104,97,115,32,116,104,101,117,110,99,108,101,97,114,69,118,101,110,116,39,44,
+98,111,116,104,32,105,110,110,111,116,32,97,108,108,10,10,60,33,45,45,32,112,108
+,97,99,105,110,103,104,97,114,100,32,116,111,32,99,101,110,116,101,114,115,111,
+114,116,32,111,102,99,108,105,101,110,116,115,115,116,114,101,101,116,115,66,101
+,114,110,97,114,100,97,115,115,101,114,116,115,116,101,110,100,32,116,111,102,97
+,110,116,97,115,121,100,111,119,110,32,105,110,104,97,114,98,111,117,114,70,114,
+101,101,100,111,109,106,101,119,101,108,114,121,47,97,98,111,117,116,46,46,115,
+101,97,114,99,104,108,101,103,101,110,100,115,105,115,32,109,97,100,101,109,111,
+100,101,114,110,32,111,110,108,121,32,111,110,111,110,108,121,32,116,111,105,109
+,97,103,101,34,32,108,105,110,101,97,114,32,112,97,105,110,116,101,114,97,110,
+100,32,110,111,116,114,97,114,101,108,121,32,97,99,114,111,110,121,109,100,101,
+108,105,118,101,114,115,104,111,114,116,101,114,48,48,38,97,109,112,59,97,115,32
+,109,97,110,121,119,105,100,116,104,61,34,47,42,32,60,33,91,67,116,105,116,108,
+101,32,61,111,102,32,116,104,101,32,108,111,119,101,115,116,32,112,105,99,107,
+101,100,32,101,115,99,97,112,101,100,117,115,101,115,32,111,102,112,101,111,112,
+108,101,115,32,80,117,98,108,105,99,77,97,116,116,104,101,119,116,97,99,116,105,
+99,115,100,97,109,97,103,101,100,119,97,121,32,102,111,114,108,97,119,115,32,111
+,102,101,97,115,121,32,116,111,32,119,105,110,100,111,119,115,116,114,111,110,
+103,32,32,115,105,109,112,108,101,125,99,97,116,99,104,40,115,101,118,101,110,
+116,104,105,110,102,111,98,111,120,119,101,110,116,32,116,111,112,97,105,110,116
+,101,100,99,105,116,105,122,101,110,73,32,100,111,110,39,116,114,101,116,114,101
+,97,116,46,32,83,111,109,101,32,119,119,46,34,41,59,10,98,111,109,98,105,110,103
+,109,97,105,108,116,111,58,109,97,100,101,32,105,110,46,32,77,97,110,121,32,99,
+97,114,114,105,101,115,124,124,123,125,59,119,105,119,111,114,107,32,111,102,115
+,121,110,111,110,121,109,100,101,102,101,97,116,115,102,97,118,111,114,101,100,
+111,112,116,105,99,97,108,112,97,103,101,84,114,97,117,110,108,101,115,115,32,
+115,101,110,100,105,110,103,108,101,102,116,34,62,60,99,111,109,83,99,111,114,65
+,108,108,32,116,104,101,106,81,117,101,114,121,46,116,111,117,114,105,115,116,67
+,108,97,115,115,105,99,102,97,108,115,101,34,32,87,105,108,104,101,108,109,115,
+117,98,117,114,98,115,103,101,110,117,105,110,101,98,105,115,104,111,112,115,46,
+115,112,108,105,116,40,103,108,111,98,97,108,32,102,111,108,108,111,119,115,98,
+111,100,121,32,111,102,110,111,109,105,110,97,108,67,111,110,116,97,99,116,115,
+101,99,117,108,97,114,108,101,102,116,32,116,111,99,104,105,101,102,108,121,45,
+104,105,100,100,101,110,45,98,97,110,110,101,114,60,47,108,105,62,10,10,46,32,87
+,104,101,110,32,105,110,32,98,111,116,104,100,105,115,109,105,115,115,69,120,112
+,108,111,114,101,97,108,119,97,121,115,32,118,105,97,32,116,104,101,115,112,97,
+195,177,111,108,119,101,108,102,97,114,101,114,117,108,105,110,103,32,97,114,114
+,97,110,103,101,99,97,112,116,97,105,110,104,105,115,32,115,111,110,114,117,108,
+101,32,111,102,104,101,32,116,111,111,107,105,116,115,101,108,102,44,61,48,38,97
+,109,112,59,40,99,97,108,108,101,100,115,97,109,112,108,101,115,116,111,32,109,
+97,107,101,99,111,109,47,112,97,103,77,97,114,116,105,110,32,75,101,110,110,101,
+100,121,97,99,99,101,112,116,115,102,117,108,108,32,111,102,104,97,110,100,108,
+101,100,66,101,115,105,100,101,115,47,47,45,45,62,60,47,97,98,108,101,32,116,111
+,116,97,114,103,101,116,115,101,115,115,101,110,99,101,104,105,109,32,116,111,32
+,105,116,115,32,98,121,32,99,111,109,109,111,110,46,109,105,110,101,114,97,108,
+116,111,32,116,97,107,101,119,97,121,115,32,116,111,115,46,111,114,103,47,108,97
+,100,118,105,115,101,100,112,101,110,97,108,116,121,115,105,109,112,108,101,58,
+105,102,32,116,104,101,121,76,101,116,116,101,114,115,97,32,115,104,111,114,116,
+72,101,114,98,101,114,116,115,116,114,105,107,101,115,32,103,114,111,117,112,115
+,46,108,101,110,103,116,104,102,108,105,103,104,116,115,111,118,101,114,108,97,
+112,115,108,111,119,108,121,32,108,101,115,115,101,114,32,115,111,99,105,97,108,
+32,60,47,112,62,10,9,9,105,116,32,105,110,116,111,114,97,110,107,101,100,32,114,
+97,116,101,32,111,102,117,108,62,13,10,32,32,97,116,116,101,109,112,116,112,97,
+105,114,32,111,102,109,97,107,101,32,105,116,75,111,110,116,97,107,116,65,110,
+116,111,110,105,111,104,97,118,105,110,103,32,114,97,116,105,110,103,115,32,97,
+99,116,105,118,101,115,116,114,101,97,109,115,116,114,97,112,112,101,100,34,41,
+46,99,115,115,40,104,111,115,116,105,108,101,108,101,97,100,32,116,111,108,105,
+116,116,108,101,32,103,114,111,117,112,115,44,80,105,99,116,117,114,101,45,45,62
+,13,10,13,10,32,114,111,119,115,61,34,32,111,98,106,101,99,116,105,110,118,101,
+114,115,101,60,102,111,111,116,101,114,67,117,115,116,111,109,86,62,60,92,47,115
+,99,114,115,111,108,118,105,110,103,67,104,97,109,98,101,114,115,108,97,118,101,
+114,121,119,111,117,110,100,101,100,119,104,101,114,101,97,115,33,61,32,39,117,
+110,100,102,111,114,32,97,108,108,112,97,114,116,108,121,32,45,114,105,103,104,
+116,58,65,114,97,98,105,97,110,98,97,99,107,101,100,32,99,101,110,116,117,114,
+121,117,110,105,116,32,111,102,109,111,98,105,108,101,45,69,117,114,111,112,101,
+44,105,115,32,104,111,109,101,114,105,115,107,32,111,102,100,101,115,105,114,101
+,100,67,108,105,110,116,111,110,99,111,115,116,32,111,102,97,103,101,32,111,102,
+32,98,101,99,111,109,101,32,110,111,110,101,32,111,102,112,38,113,117,111,116,59
+,77,105,100,100,108,101,32,101,97,100,39,41,91,48,67,114,105,116,105,99,115,115,
+116,117,100,105,111,115,62,38,99,111,112,121,59,103,114,111,117,112,34,62,97,115
+,115,101,109,98,108,109,97,107,105,110,103,32,112,114,101,115,115,101,100,119,
+105,100,103,101,116,46,112,115,58,34,32,63,32,114,101,98,117,105,108,116,98,121,
+32,115,111,109,101,70,111,114,109,101,114,32,101,100,105,116,111,114,115,100,101
+,108,97,121,101,100,67,97,110,111,110,105,99,104,97,100,32,116,104,101,112,117,
+115,104,105,110,103,99,108,97,115,115,61,34,98,117,116,32,97,114,101,112,97,114,
+116,105,97,108,66,97,98,121,108,111,110,98,111,116,116,111,109,32,99,97,114,114,
+105,101,114,67,111,109,109,97,110,100,105,116,115,32,117,115,101,65,115,32,119,
+105,116,104,99,111,117,114,115,101,115,97,32,116,104,105,114,100,100,101,110,111
+,116,101,115,97,108,115,111,32,105,110,72,111,117,115,116,111,110,50,48,112,120,
+59,34,62,97,99,99,117,115,101,100,100,111,117,98,108,101,32,103,111,97,108,32,
+111,102,70,97,109,111,117,115,32,41,46,98,105,110,100,40,112,114,105,101,115,116
+,115,32,79,110,108,105,110,101,105,110,32,74,117,108,121,115,116,32,43,32,34,103
+,99,111,110,115,117,108,116,100,101,99,105,109,97,108,104,101,108,112,102,117,
+108,114,101,118,105,118,101,100,105,115,32,118,101,114,121,114,39,43,39,105,112,
+116,108,111,115,105,110,103,32,102,101,109,97,108,101,115,105,115,32,97,108,115,
+111,115,116,114,105,110,103,115,100,97,121,115,32,111,102,97,114,114,105,118,97,
+108,102,117,116,117,114,101,32,60,111,98,106,101,99,116,102,111,114,99,105,110,
+103,83,116,114,105,110,103,40,34,32,47,62,10,9,9,104,101,114,101,32,105,115,101,
+110,99,111,100,101,100,46,32,32,84,104,101,32,98,97,108,108,111,111,110,100,111,
+110,101,32,98,121,47,99,111,109,109,111,110,98,103,99,111,108,111,114,108,97,119
+,32,111,102,32,73,110,100,105,97,110,97,97,118,111,105,100,101,100,98,117,116,32
+,116,104,101,50,112,120,32,51,112,120,106,113,117,101,114,121,46,97,102,116,101,
+114,32,97,112,111,108,105,99,121,46,109,101,110,32,97,110,100,102,111,111,116,
+101,114,45,61,32,116,114,117,101,59,102,111,114,32,117,115,101,115,99,114,101,
+101,110,46,73,110,100,105,97,110,32,105,109,97,103,101,32,61,102,97,109,105,108,
+121,44,104,116,116,112,58,47,47,32,38,110,98,115,112,59,100,114,105,118,101,114,
+115,101,116,101,114,110,97,108,115,97,109,101,32,97,115,110,111,116,105,99,101,
+100,118,105,101,119,101,114,115,125,41,40,41,59,10,32,105,115,32,109,111,114,101
+,115,101,97,115,111,110,115,102,111,114,109,101,114,32,116,104,101,32,110,101,
+119,105,115,32,106,117,115,116,99,111,110,115,101,110,116,32,83,101,97,114,99,
+104,119,97,115,32,116,104,101,119,104,121,32,116,104,101,115,104,105,112,112,101
+,100,98,114,62,60,98,114,62,119,105,100,116,104,58,32,104,101,105,103,104,116,61
+,109,97,100,101,32,111,102,99,117,105,115,105,110,101,105,115,32,116,104,97,116,
+97,32,118,101,114,121,32,65,100,109,105,114,97,108,32,102,105,120,101,100,59,110
+,111,114,109,97,108,32,77,105,115,115,105,111,110,80,114,101,115,115,44,32,111,
+110,116,97,114,105,111,99,104,97,114,115,101,116,116,114,121,32,116,111,32,105,
+110,118,97,100,101,100,61,34,116,114,117,101,34,115,112,97,99,105,110,103,105,
+115,32,109,111,115,116,97,32,109,111,114,101,32,116,111,116,97,108,108,121,102,
+97,108,108,32,111,102,125,41,59,13,10,32,32,105,109,109,101,110,115,101,116,105,
+109,101,32,105,110,115,101,116,32,111,117,116,115,97,116,105,115,102,121,116,111
+,32,102,105,110,100,100,111,119,110,32,116,111,108,111,116,32,111,102,32,80,108,
+97,121,101,114,115,105,110,32,74,117,110,101,113,117,97,110,116,117,109,110,111,
+116,32,116,104,101,116,105,109,101,32,116,111,100,105,115,116,97,110,116,70,105,
+110,110,105,115,104,115,114,99,32,61,32,40,115,105,110,103,108,101,32,104,101,
+108,112,32,111,102,71,101,114,109,97,110,32,108,97,119,32,97,110,100,108,97,98,
+101,108,101,100,102,111,114,101,115,116,115,99,111,111,107,105,110,103,115,112,
+97,99,101,34,62,104,101,97,100,101,114,45,119,101,108,108,32,97,115,83,116,97,
+110,108,101,121,98,114,105,100,103,101,115,47,103,108,111,98,97,108,67,114,111,
+97,116,105,97,32,65,98,111,117,116,32,91,48,93,59,10,32,32,105,116,44,32,97,110,
+100,103,114,111,117,112,101,100,98,101,105,110,103,32,97,41,123,116,104,114,111,
+119,104,101,32,109,97,100,101,108,105,103,104,116,101,114,101,116,104,105,99,97,
+108,70,70,70,70,70,70,34,98,111,116,116,111,109,34,108,105,107,101,32,97,32,101,
+109,112,108,111,121,115,108,105,118,101,32,105,110,97,115,32,115,101,101,110,112
+,114,105,110,116,101,114,109,111,115,116,32,111,102,117,98,45,108,105,110,107,
+114,101,106,101,99,116,115,97,110,100,32,117,115,101,105,109,97,103,101,34,62,
+115,117,99,99,101,101,100,102,101,101,100,105,110,103,78,117,99,108,101,97,114,
+105,110,102,111,114,109,97,116,111,32,104,101,108,112,87,111,109,101,110,39,115,
+78,101,105,116,104,101,114,77,101,120,105,99,97,110,112,114,111,116,101,105,110,
+60,116,97,98,108,101,32,98,121,32,109,97,110,121,104,101,97,108,116,104,121,108,
+97,119,115,117,105,116,100,101,118,105,115,101,100,46,112,117,115,104,40,123,115
+,101,108,108,101,114,115,115,105,109,112,108,121,32,84,104,114,111,117,103,104,
+46,99,111,111,107,105,101,32,73,109,97,103,101,40,111,108,100,101,114,34,62,117,
+115,46,106,115,34,62,32,83,105,110,99,101,32,117,110,105,118,101,114,115,108,97,
+114,103,101,114,32,111,112,101,110,32,116,111,33,45,45,32,101,110,100,108,105,
+101,115,32,105,110,39,93,41,59,13,10,32,32,109,97,114,107,101,116,119,104,111,32
+,105,115,32,40,34,68,79,77,67,111,109,97,110,97,103,101,100,111,110,101,32,102,
+111,114,116,121,112,101,111,102,32,75,105,110,103,100,111,109,112,114,111,102,
+105,116,115,112,114,111,112,111,115,101,116,111,32,115,104,111,119,99,101,110,
+116,101,114,59,109,97,100,101,32,105,116,100,114,101,115,115,101,100,119,101,114
+,101,32,105,110,109,105,120,116,117,114,101,112,114,101,99,105,115,101,97,114,
+105,115,105,110,103,115,114,99,32,61,32,39,109,97,107,101,32,97,32,115,101,99,
+117,114,101,100,66,97,112,116,105,115,116,118,111,116,105,110,103,32,10,9,9,118,
+97,114,32,77,97,114,99,104,32,50,103,114,101,119,32,117,112,67,108,105,109,97,
+116,101,46,114,101,109,111,118,101,115,107,105,108,108,101,100,119,97,121,32,116
+,104,101,60,47,104,101,97,100,62,102,97,99,101,32,111,102,97,99,116,105,110,103,
+32,114,105,103,104,116,34,62,116,111,32,119,111,114,107,114,101,100,117,99,101,
+115,104,97,115,32,104,97,100,101,114,101,99,116,101,100,115,104,111,119,40,41,59
+,97,99,116,105,111,110,61,98,111,111,107,32,111,102,97,110,32,97,114,101,97,61,
+61,32,34,104,116,116,60,104,101,97,100,101,114,10,60,104,116,109,108,62,99,111,
+110,102,111,114,109,102,97,99,105,110,103,32,99,111,111,107,105,101,46,114,101,
+108,121,32,111,110,104,111,115,116,101,100,32,46,99,117,115,116,111,109,104,101,
+32,119,101,110,116,98,117,116,32,102,111,114,115,112,114,101,97,100,32,70,97,109
+,105,108,121,32,97,32,109,101,97,110,115,111,117,116,32,116,104,101,102,111,114,
+117,109,115,46,102,111,111,116,97,103,101,34,62,77,111,98,105,108,67,108,101,109
+,101,110,116,115,34,32,105,100,61,34,97,115,32,104,105,103,104,105,110,116,101,
+110,115,101,45,45,62,60,33,45,45,102,101,109,97,108,101,32,105,115,32,115,101,
+101,110,105,109,112,108,105,101,100,115,101,116,32,116,104,101,97,32,115,116,97,
+116,101,97,110,100,32,104,105,115,102,97,115,116,101,115,116,98,101,115,105,100,
+101,115,98,117,116,116,111,110,95,98,111,117,110,100,101,100,34,62,60,105,109,
+103,32,73,110,102,111,98,111,120,101,118,101,110,116,115,44,97,32,121,111,117,
+110,103,97,110,100,32,97,114,101,78,97,116,105,118,101,32,99,104,101,97,112,101,
+114,84,105,109,101,111,117,116,97,110,100,32,104,97,115,101,110,103,105,110,101,
+115,119,111,110,32,116,104,101,40,109,111,115,116,108,121,114,105,103,104,116,58
+,32,102,105,110,100,32,97,32,45,98,111,116,116,111,109,80,114,105,110,99,101,32,
+97,114,101,97,32,111,102,109,111,114,101,32,111,102,115,101,97,114,99,104,95,110
+,97,116,117,114,101,44,108,101,103,97,108,108,121,112,101,114,105,111,100,44,108
+,97,110,100,32,111,102,111,114,32,119,105,116,104,105,110,100,117,99,101,100,112
+,114,111,118,105,110,103,109,105,115,115,105,108,101,108,111,99,97,108,108,121,
+65,103,97,105,110,115,116,116,104,101,32,119,97,121,107,38,113,117,111,116,59,
+112,120,59,34,62,13,10,112,117,115,104,101,100,32,97,98,97,110,100,111,110,110,
+117,109,101,114,97,108,67,101,114,116,97,105,110,73,110,32,116,104,105,115,109,
+111,114,101,32,105,110,111,114,32,115,111,109,101,110,97,109,101,32,105,115,97,
+110,100,44,32,105,110,99,114,111,119,110,101,100,73,83,66,78,32,48,45,99,114,101
+,97,116,101,115,79,99,116,111,98,101,114,109,97,121,32,110,111,116,99,101,110,
+116,101,114,32,108,97,116,101,32,105,110,68,101,102,101,110,99,101,101,110,97,99
+,116,101,100,119,105,115,104,32,116,111,98,114,111,97,100,108,121,99,111,111,108
+,105,110,103,111,110,108,111,97,100,61,105,116,46,32,84,104,101,114,101,99,111,
+118,101,114,77,101,109,98,101,114,115,104,101,105,103,104,116,32,97,115,115,117,
+109,101,115,60,104,116,109,108,62,10,112,101,111,112,108,101,46,105,110,32,111,
+110,101,32,61,119,105,110,100,111,119,102,111,111,116,101,114,95,97,32,103,111,
+111,100,32,114,101,107,108,97,109,97,111,116,104,101,114,115,44,116,111,32,116,
+104,105,115,95,99,111,111,107,105,101,112,97,110,101,108,34,62,76,111,110,100,
+111,110,44,100,101,102,105,110,101,115,99,114,117,115,104,101,100,98,97,112,116,
+105,115,109,99,111,97,115,116,97,108,115,116,97,116,117,115,32,116,105,116,108,
+101,34,32,109,111,118,101,32,116,111,108,111,115,116,32,105,110,98,101,116,116,
+101,114,32,105,109,112,108,105,101,115,114,105,118,97,108,114,121,115,101,114,
+118,101,114,115,32,83,121,115,116,101,109,80,101,114,104,97,112,115,101,115,32,
+97,110,100,32,99,111,110,116,101,110,100,102,108,111,119,105,110,103,108,97,115,
+116,101,100,32,114,105,115,101,32,105,110,71,101,110,101,115,105,115,118,105,101
+,119,32,111,102,114,105,115,105,110,103,32,115,101,101,109,32,116,111,98,117,116
+,32,105,110,32,98,97,99,107,105,110,103,104,101,32,119,105,108,108,103,105,118,
+101,110,32,97,103,105,118,105,110,103,32,99,105,116,105,101,115,46,102,108,111,
+119,32,111,102,32,76,97,116,101,114,32,97,108,108,32,98,117,116,72,105,103,104,
+119,97,121,111,110,108,121,32,98,121,115,105,103,110,32,111,102,104,101,32,100,
+111,101,115,100,105,102,102,101,114,115,98,97,116,116,101,114,121,38,97,109,112,
+59,108,97,115,105,110,103,108,101,115,116,104,114,101,97,116,115,105,110,116,101
+,103,101,114,116,97,107,101,32,111,110,114,101,102,117,115,101,100,99,97,108,108
+,101,100,32,61,85,83,38,97,109,112,83,101,101,32,116,104,101,110,97,116,105,118,
+101,115,98,121,32,116,104,105,115,115,121,115,116,101,109,46,104,101,97,100,32,
+111,102,58,104,111,118,101,114,44,108,101,115,98,105,97,110,115,117,114,110,97,
+109,101,97,110,100,32,97,108,108,99,111,109,109,111,110,47,104,101,97,100,101,
+114,95,95,112,97,114,97,109,115,72,97,114,118,97,114,100,47,112,105,120,101,108,
+46,114,101,109,111,118,97,108,115,111,32,108,111,110,103,114,111,108,101,32,111,
+102,106,111,105,110,116,108,121,115,107,121,115,99,114,97,85,110,105,99,111,100,
+101,98,114,32,47,62,13,10,65,116,108,97,110,116,97,110,117,99,108,101,117,115,67
+,111,117,110,116,121,44,112,117,114,101,108,121,32,99,111,117,110,116,34,62,101,
+97,115,105,108,121,32,98,117,105,108,100,32,97,111,110,99,108,105,99,107,97,32,
+103,105,118,101,110,112,111,105,110,116,101,114,104,38,113,117,111,116,59,101,
+118,101,110,116,115,32,101,108,115,101,32,123,10,100,105,116,105,111,110,115,110
+,111,119,32,116,104,101,44,32,119,105,116,104,32,109,97,110,32,119,104,111,111,
+114,103,47,87,101,98,111,110,101,32,97,110,100,99,97,118,97,108,114,121,72,101,
+32,100,105,101,100,115,101,97,116,116,108,101,48,48,44,48,48,48,32,123,119,105,
+110,100,111,119,104,97,118,101,32,116,111,105,102,40,119,105,110,100,97,110,100,
+32,105,116,115,115,111,108,101,108,121,32,109,38,113,117,111,116,59,114,101,110,
+101,119,101,100,68,101,116,114,111,105,116,97,109,111,110,103,115,116,101,105,
+116,104,101,114,32,116,104,101,109,32,105,110,83,101,110,97,116,111,114,85,115,
+60,47,97,62,60,75,105,110,103,32,111,102,70,114,97,110,99,105,115,45,112,114,111
+,100,117,99,104,101,32,117,115,101,100,97,114,116,32,97,110,100,104,105,109,32,
+97,110,100,117,115,101,100,32,98,121,115,99,111,114,105,110,103,97,116,32,104,
+111,109,101,116,111,32,104,97,118,101,114,101,108,97,116,101,115,105,98,105,108,
+105,116,121,102,97,99,116,105,111,110,66,117,102,102,97,108,111,108,105,110,107,
+34,62,60,119,104,97,116,32,104,101,102,114,101,101,32,116,111,67,105,116,121,32,
+111,102,99,111,109,101,32,105,110,115,101,99,116,111,114,115,99,111,117,110,116,
+101,100,111,110,101,32,100,97,121,110,101,114,118,111,117,115,115,113,117,97,114
+,101,32,125,59,105,102,40,103,111,105,110,32,119,104,97,116,105,109,103,34,32,97
+,108,105,115,32,111,110,108,121,115,101,97,114,99,104,47,116,117,101,115,100,97,
+121,108,111,111,115,101,108,121,83,111,108,111,109,111,110,115,101,120,117,97,
+108,32,45,32,60,97,32,104,114,109,101,100,105,117,109,34,68,79,32,78,79,84,32,70
+,114,97,110,99,101,44,119,105,116,104,32,97,32,119,97,114,32,97,110,100,115,101,
+99,111,110,100,32,116,97,107,101,32,97,32,62,13,10,13,10,13,10,109,97,114,107,
+101,116,46,104,105,103,104,119,97,121,100,111,110,101,32,105,110,99,116,105,118,
+105,116,121,34,108,97,115,116,34,62,111,98,108,105,103,101,100,114,105,115,101,
+32,116,111,34,117,110,100,101,102,105,109,97,100,101,32,116,111,32,69,97,114,108
+,121,32,112,114,97,105,115,101,100,105,110,32,105,116,115,32,102,111,114,32,104,
+105,115,97,116,104,108,101,116,101,74,117,112,105,116,101,114,89,97,104,111,111,
+33,32,116,101,114,109,101,100,32,115,111,32,109,97,110,121,114,101,97,108,108,
+121,32,115,46,32,84,104,101,32,97,32,119,111,109,97,110,63,118,97,108,117,101,61
+,100,105,114,101,99,116,32,114,105,103,104,116,34,32,98,105,99,121,99,108,101,97
+,99,105,110,103,61,34,100,97,121,32,97,110,100,115,116,97,116,105,110,103,82,97,
+116,104,101,114,44,104,105,103,104,101,114,32,79,102,102,105,99,101,32,97,114,
+101,32,110,111,119,116,105,109,101,115,44,32,119,104,101,110,32,97,32,112,97,121
+,32,102,111,114,111,110,32,116,104,105,115,45,108,105,110,107,34,62,59,98,111,
+114,100,101,114,97,114,111,117,110,100,32,97,110,110,117,97,108,32,116,104,101,
+32,78,101,119,112,117,116,32,116,104,101,46,99,111,109,34,32,116,97,107,105,110,
+32,116,111,97,32,98,114,105,101,102,40,105,110,32,116,104,101,103,114,111,117,
+112,115,46,59,32,119,105,100,116,104,101,110,122,121,109,101,115,115,105,109,112
+,108,101,32,105,110,32,108,97,116,101,123,114,101,116,117,114,110,116,104,101,
+114,97,112,121,97,32,112,111,105,110,116,98,97,110,110,105,110,103,105,110,107,
+115,34,62,10,40,41,59,34,32,114,101,97,32,112,108,97,99,101,92,117,48,48,51,67,
+97,97,98,111,117,116,32,97,116,114,62,13,10,9,9,99,99,111,117,110,116,32,103,105
+,118,101,115,32,97,60,83,67,82,73,80,84,82,97,105,108,119,97,121,116,104,101,109
+,101,115,47,116,111,111,108,98,111,120,66,121,73,100,40,34,120,104,117,109,97,
+110,115,44,119,97,116,99,104,101,115,105,110,32,115,111,109,101,32,105,102,32,40
+,119,105,99,111,109,105,110,103,32,102,111,114,109,97,116,115,32,85,110,100,101,
+114,32,98,117,116,32,104,97,115,104,97,110,100,101,100,32,109,97,100,101,32,98,
+121,116,104,97,110,32,105,110,102,101,97,114,32,111,102,100,101,110,111,116,101,
+100,47,105,102,114,97,109,101,108,101,102,116,32,105,110,118,111,108,116,97,103,
+101,105,110,32,101,97,99,104,97,38,113,117,111,116,59,98,97,115,101,32,111,102,
+73,110,32,109,97,110,121,117,110,100,101,114,103,111,114,101,103,105,109,101,115
+,97,99,116,105,111,110,32,60,47,112,62,13,10,60,117,115,116,111,109,86,97,59,38,
+103,116,59,60,47,105,109,112,111,114,116,115,111,114,32,116,104,97,116,109,111,
+115,116,108,121,32,38,97,109,112,59,114,101,32,115,105,122,101,61,34,60,47,97,62
+,60,47,104,97,32,99,108,97,115,115,112,97,115,115,105,118,101,72,111,115,116,32,
+61,32,87,104,101,116,104,101,114,102,101,114,116,105,108,101,86,97,114,105,111,
+117,115,61,91,93,59,40,102,117,99,97,109,101,114,97,115,47,62,60,47,116,100,62,
+97,99,116,115,32,97,115,73,110,32,115,111,109,101,62,13,10,13,10,60,33,111,114,
+103,97,110,105,115,32,60,98,114,32,47,62,66,101,105,106,105,110,103,99,97,116,97
+,108,195,160,100,101,117,116,115,99,104,101,117,114,111,112,101,117,101,117,115,
+107,97,114,97,103,97,101,105,108,103,101,115,118,101,110,115,107,97,101,115,112,
+97,195,177,97,109,101,110,115,97,106,101,117,115,117,97,114,105,111,116,114,97,
+98,97,106,111,109,195,169,120,105,99,111,112,195,161,103,105,110,97,115,105,101,
+109,112,114,101,115,105,115,116,101,109,97,111,99,116,117,98,114,101,100,117,114
+,97,110,116,101,97,195,177,97,100,105,114,101,109,112,114,101,115,97,109,111,109
+,101,110,116,111,110,117,101,115,116,114,111,112,114,105,109,101,114,97,116,114,
+97,118,195,169,115,103,114,97,99,105,97,115,110,117,101,115,116,114,97,112,114,
+111,99,101,115,111,101,115,116,97,100,111,115,99,97,108,105,100,97,100,112,101,
+114,115,111,110,97,110,195,186,109,101,114,111,97,99,117,101,114,100,111,109,195
+,186,115,105,99,97,109,105,101,109,98,114,111,111,102,101,114,116,97,115,97,108,
+103,117,110,111,115,112,97,195,173,115,101,115,101,106,101,109,112,108,111,100,
+101,114,101,99,104,111,97,100,101,109,195,161,115,112,114,105,118,97,100,111,97,
+103,114,101,103,97,114,101,110,108,97,99,101,115,112,111,115,105,98,108,101,104,
+111,116,101,108,101,115,115,101,118,105,108,108,97,112,114,105,109,101,114,111,
+195,186,108,116,105,109,111,101,118,101,110,116,111,115,97,114,99,104,105,118,
+111,99,117,108,116,117,114,97,109,117,106,101,114,101,115,101,110,116,114,97,100
+,97,97,110,117,110,99,105,111,101,109,98,97,114,103,111,109,101,114,99,97,100,
+111,103,114,97,110,100,101,115,101,115,116,117,100,105,111,109,101,106,111,114,
+101,115,102,101,98,114,101,114,111,100,105,115,101,195,177,111,116,117,114,105,
+115,109,111,99,195,179,100,105,103,111,112,111,114,116,97,100,97,101,115,112,97,
+99,105,111,102,97,109,105,108,105,97,97,110,116,111,110,105,111,112,101,114,109,
+105,116,101,103,117,97,114,100,97,114,97,108,103,117,110,97,115,112,114,101,99,
+105,111,115,97,108,103,117,105,101,110,115,101,110,116,105,100,111,118,105,115,
+105,116,97,115,116,195,173,116,117,108,111,99,111,110,111,99,101,114,115,101,103
+,117,110,100,111,99,111,110,115,101,106,111,102,114,97,110,99,105,97,109,105,110
+,117,116,111,115,115,101,103,117,110,100,97,116,101,110,101,109,111,115,101,102,
+101,99,116,111,115,109,195,161,108,97,103,97,115,101,115,105,195,179,110,114,101
+,118,105,115,116,97,103,114,97,110,97,100,97,99,111,109,112,114,97,114,105,110,
+103,114,101,115,111,103,97,114,99,195,173,97,97,99,99,105,195,179,110,101,99,117
+,97,100,111,114,113,117,105,101,110,101,115,105,110,99,108,117,115,111,100,101,
+98,101,114,195,161,109,97,116,101,114,105,97,104,111,109,98,114,101,115,109,117,
+101,115,116,114,97,112,111,100,114,195,173,97,109,97,195,177,97,110,97,195,186,
+108,116,105,109,97,101,115,116,97,109,111,115,111,102,105,99,105,97,108,116,97,
+109,98,105,101,110,110,105,110,103,195,186,110,115,97,108,117,100,111,115,112,
+111,100,101,109,111,115,109,101,106,111,114,97,114,112,111,115,105,116,105,111,
+110,98,117,115,105,110,101,115,115,104,111,109,101,112,97,103,101,115,101,99,117
+,114,105,116,121,108,97,110,103,117,97,103,101,115,116,97,110,100,97,114,100,99,
+97,109,112,97,105,103,110,102,101,97,116,117,114,101,115,99,97,116,101,103,111,
+114,121,101,120,116,101,114,110,97,108,99,104,105,108,100,114,101,110,114,101,
+115,101,114,118,101,100,114,101,115,101,97,114,99,104,101,120,99,104,97,110,103,
+101,102,97,118,111,114,105,116,101,116,101,109,112,108,97,116,101,109,105,108,
+105,116,97,114,121,105,110,100,117,115,116,114,121,115,101,114,118,105,99,101,
+115,109,97,116,101,114,105,97,108,112,114,111,100,117,99,116,115,122,45,105,110,
+100,101,120,58,99,111,109,109,101,110,116,115,115,111,102,116,119,97,114,101,99,
+111,109,112,108,101,116,101,99,97,108,101,110,100,97,114,112,108,97,116,102,111,
+114,109,97,114,116,105,99,108,101,115,114,101,113,117,105,114,101,100,109,111,
+118,101,109,101,110,116,113,117,101,115,116,105,111,110,98,117,105,108,100,105,
+110,103,112,111,108,105,116,105,99,115,112,111,115,115,105,98,108,101,114,101,
+108,105,103,105,111,110,112,104,121,115,105,99,97,108,102,101,101,100,98,97,99,
+107,114,101,103,105,115,116,101,114,112,105,99,116,117,114,101,115,100,105,115,
+97,98,108,101,100,112,114,111,116,111,99,111,108,97,117,100,105,101,110,99,101,
+115,101,116,116,105,110,103,115,97,99,116,105,118,105,116,121,101,108,101,109,
+101,110,116,115,108,101,97,114,110,105,110,103,97,110,121,116,104,105,110,103,97
+,98,115,116,114,97,99,116,112,114,111,103,114,101,115,115,111,118,101,114,118,
+105,101,119,109,97,103,97,122,105,110,101,101,99,111,110,111,109,105,99,116,114,
+97,105,110,105,110,103,112,114,101,115,115,117,114,101,118,97,114,105,111,117,
+115,32,60,115,116,114,111,110,103,62,112,114,111,112,101,114,116,121,115,104,111
+,112,112,105,110,103,116,111,103,101,116,104,101,114,97,100,118,97,110,99,101,
+100,98,101,104,97,118,105,111,114,100,111,119,110,108,111,97,100,102,101,97,116,
+117,114,101,100,102,111,111,116,98,97,108,108,115,101,108,101,99,116,101,100,76,
+97,110,103,117,97,103,101,100,105,115,116,97,110,99,101,114,101,109,101,109,98,
+101,114,116,114,97,99,107,105,110,103,112,97,115,115,119,111,114,100,109,111,100
+,105,102,105,101,100,115,116,117,100,101,110,116,115,100,105,114,101,99,116,108,
+121,102,105,103,104,116,105,110,103,110,111,114,116,104,101,114,110,100,97,116,
+97,98,97,115,101,102,101,115,116,105,118,97,108,98,114,101,97,107,105,110,103,
+108,111,99,97,116,105,111,110,105,110,116,101,114,110,101,116,100,114,111,112,
+100,111,119,110,112,114,97,99,116,105,99,101,101,118,105,100,101,110,99,101,102,
+117,110,99,116,105,111,110,109,97,114,114,105,97,103,101,114,101,115,112,111,110
+,115,101,112,114,111,98,108,101,109,115,110,101,103,97,116,105,118,101,112,114,
+111,103,114,97,109,115,97,110,97,108,121,115,105,115,114,101,108,101,97,115,101,
+100,98,97,110,110,101,114,34,62,112,117,114,99,104,97,115,101,112,111,108,105,99
+,105,101,115,114,101,103,105,111,110,97,108,99,114,101,97,116,105,118,101,97,114
+,103,117,109,101,110,116,98,111,111,107,109,97,114,107,114,101,102,101,114,114,
+101,114,99,104,101,109,105,99,97,108,100,105,118,105,115,105,111,110,99,97,108,
+108,98,97,99,107,115,101,112,97,114,97,116,101,112,114,111,106,101,99,116,115,99
+,111,110,102,108,105,99,116,104,97,114,100,119,97,114,101,105,110,116,101,114,
+101,115,116,100,101,108,105,118,101,114,121,109,111,117,110,116,97,105,110,111,
+98,116,97,105,110,101,100,61,32,102,97,108,115,101,59,102,111,114,40,118,97,114,
+32,97,99,99,101,112,116,101,100,99,97,112,97,99,105,116,121,99,111,109,112,117,
+116,101,114,105,100,101,110,116,105,116,121,97,105,114,99,114,97,102,116,101,109
+,112,108,111,121,101,100,112,114,111,112,111,115,101,100,100,111,109,101,115,116
+,105,99,105,110,99,108,117,100,101,115,112,114,111,118,105,100,101,100,104,111,
+115,112,105,116,97,108,118,101,114,116,105,99,97,108,99,111,108,108,97,112,115,
+101,97,112,112,114,111,97,99,104,112,97,114,116,110,101,114,115,108,111,103,111,
+34,62,60,97,100,97,117,103,104,116,101,114,97,117,116,104,111,114,34,32,99,117,
+108,116,117,114,97,108,102,97,109,105,108,105,101,115,47,105,109,97,103,101,115,
+47,97,115,115,101,109,98,108,121,112,111,119,101,114,102,117,108,116,101,97,99,
+104,105,110,103,102,105,110,105,115,104,101,100,100,105,115,116,114,105,99,116,
+99,114,105,116,105,99,97,108,99,103,105,45,98,105,110,47,112,117,114,112,111,115
+,101,115,114,101,113,117,105,114,101,115,101,108,101,99,116,105,111,110,98,101,
+99,111,109,105,110,103,112,114,111,118,105,100,101,115,97,99,97,100,101,109,105,
+99,101,120,101,114,99,105,115,101,97,99,116,117,97,108,108,121,109,101,100,105,
+99,105,110,101,99,111,110,115,116,97,110,116,97,99,99,105,100,101,110,116,77,97,
+103,97,122,105,110,101,100,111,99,117,109,101,110,116,115,116,97,114,116,105,110
+,103,98,111,116,116,111,109,34,62,111,98,115,101,114,118,101,100,58,32,38,113,
+117,111,116,59,101,120,116,101,110,100,101,100,112,114,101,118,105,111,117,115,
+83,111,102,116,119,97,114,101,99,117,115,116,111,109,101,114,100,101,99,105,115,
+105,111,110,115,116,114,101,110,103,116,104,100,101,116,97,105,108,101,100,115,
+108,105,103,104,116,108,121,112,108,97,110,110,105,110,103,116,101,120,116,97,
+114,101,97,99,117,114,114,101,110,99,121,101,118,101,114,121,111,110,101,115,116
+,114,97,105,103,104,116,116,114,97,110,115,102,101,114,112,111,115,105,116,105,
+118,101,112,114,111,100,117,99,101,100,104,101,114,105,116,97,103,101,115,104,
+105,112,112,105,110,103,97,98,115,111,108,117,116,101,114,101,99,101,105,118,101
+,100,114,101,108,101,118,97,110,116,98,117,116,116,111,110,34,32,118,105,111,108
+,101,110,99,101,97,110,121,119,104,101,114,101,98,101,110,101,102,105,116,115,
+108,97,117,110,99,104,101,100,114,101,99,101,110,116,108,121,97,108,108,105,97,
+110,99,101,102,111,108,108,111,119,101,100,109,117,108,116,105,112,108,101,98,
+117,108,108,101,116,105,110,105,110,99,108,117,100,101,100,111,99,99,117,114,114
+,101,100,105,110,116,101,114,110,97,108,36,40,116,104,105,115,41,46,114,101,112,
+117,98,108,105,99,62,60,116,114,62,60,116,100,99,111,110,103,114,101,115,115,114
+,101,99,111,114,100,101,100,117,108,116,105,109,97,116,101,115,111,108,117,116,
+105,111,110,60,117,108,32,105,100,61,34,100,105,115,99,111,118,101,114,72,111,
+109,101,60,47,97,62,119,101,98,115,105,116,101,115,110,101,116,119,111,114,107,
+115,97,108,116,104,111,117,103,104,101,110,116,105,114,101,108,121,109,101,109,
+111,114,105,97,108,109,101,115,115,97,103,101,115,99,111,110,116,105,110,117,101
+,97,99,116,105,118,101,34,62,115,111,109,101,119,104,97,116,118,105,99,116,111,
+114,105,97,87,101,115,116,101,114,110,32,32,116,105,116,108,101,61,34,76,111,99,
+97,116,105,111,110,99,111,110,116,114,97,99,116,118,105,115,105,116,111,114,115,
+68,111,119,110,108,111,97,100,119,105,116,104,111,117,116,32,114,105,103,104,116
+,34,62,10,109,101,97,115,117,114,101,115,119,105,100,116,104,32,61,32,118,97,114
+,105,97,98,108,101,105,110,118,111,108,118,101,100,118,105,114,103,105,110,105,
+97,110,111,114,109,97,108,108,121,104,97,112,112,101,110,101,100,97,99,99,111,
+117,110,116,115,115,116,97,110,100,105,110,103,110,97,116,105,111,110,97,108,82,
+101,103,105,115,116,101,114,112,114,101,112,97,114,101,100,99,111,110,116,114,
+111,108,115,97,99,99,117,114,97,116,101,98,105,114,116,104,100,97,121,115,116,
+114,97,116,101,103,121,111,102,102,105,99,105,97,108,103,114,97,112,104,105,99,
+115,99,114,105,109,105,110,97,108,112,111,115,115,105,98,108,121,99,111,110,115,
+117,109,101,114,80,101,114,115,111,110,97,108,115,112,101,97,107,105,110,103,118
+,97,108,105,100,97,116,101,97,99,104,105,101,118,101,100,46,106,112,103,34,32,47
+,62,109,97,99,104,105,110,101,115,60,47,104,50,62,10,32,32,107,101,121,119,111,
+114,100,115,102,114,105,101,110,100,108,121,98,114,111,116,104,101,114,115,99,
+111,109,98,105,110,101,100,111,114,105,103,105,110,97,108,99,111,109,112,111,115
+,101,100,101,120,112,101,99,116,101,100,97,100,101,113,117,97,116,101,112,97,107
+,105,115,116,97,110,102,111,108,108,111,119,34,32,118,97,108,117,97,98,108,101,
+60,47,108,97,98,101,108,62,114,101,108,97,116,105,118,101,98,114,105,110,103,105
+,110,103,105,110,99,114,101,97,115,101,103,111,118,101,114,110,111,114,112,108,
+117,103,105,110,115,47,76,105,115,116,32,111,102,32,72,101,97,100,101,114,34,62,
+34,32,110,97,109,101,61,34,32,40,38,113,117,111,116,59,103,114,97,100,117,97,116
+,101,60,47,104,101,97,100,62,10,99,111,109,109,101,114,99,101,109,97,108,97,121,
+115,105,97,100,105,114,101,99,116,111,114,109,97,105,110,116,97,105,110,59,104,
+101,105,103,104,116,58,115,99,104,101,100,117,108,101,99,104,97,110,103,105,110,
+103,98,97,99,107,32,116,111,32,99,97,116,104,111,108,105,99,112,97,116,116,101,
+114,110,115,99,111,108,111,114,58,32,35,103,114,101,97,116,101,115,116,115,117,
+112,112,108,105,101,115,114,101,108,105,97,98,108,101,60,47,117,108,62,10,9,9,60
+,115,101,108,101,99,116,32,99,105,116,105,122,101,110,115,99,108,111,116,104,105
+,110,103,119,97,116,99,104,105,110,103,60,108,105,32,105,100,61,34,115,112,101,
+99,105,102,105,99,99,97,114,114,121,105,110,103,115,101,110,116,101,110,99,101,
+60,99,101,110,116,101,114,62,99,111,110,116,114,97,115,116,116,104,105,110,107,
+105,110,103,99,97,116,99,104,40,101,41,115,111,117,116,104,101,114,110,77,105,99
+,104,97,101,108,32,109,101,114,99,104,97,110,116,99,97,114,111,117,115,101,108,
+112,97,100,100,105,110,103,58,105,110,116,101,114,105,111,114,46,115,112,108,105
+,116,40,34,108,105,122,97,116,105,111,110,79,99,116,111,98,101,114,32,41,123,114
+,101,116,117,114,110,105,109,112,114,111,118,101,100,45,45,38,103,116,59,10,10,
+99,111,118,101,114,97,103,101,99,104,97,105,114,109,97,110,46,112,110,103,34,32,
+47,62,115,117,98,106,101,99,116,115,82,105,99,104,97,114,100,32,119,104,97,116,
+101,118,101,114,112,114,111,98,97,98,108,121,114,101,99,111,118,101,114,121,98,
+97,115,101,98,97,108,108,106,117,100,103,109,101,110,116,99,111,110,110,101,99,
+116,46,46,99,115,115,34,32,47,62,32,119,101,98,115,105,116,101,114,101,112,111,
+114,116,101,100,100,101,102,97,117,108,116,34,47,62,60,47,97,62,13,10,101,108,
+101,99,116,114,105,99,115,99,111,116,108,97,110,100,99,114,101,97,116,105,111,
+110,113,117,97,110,116,105,116,121,46,32,73,83,66,78,32,48,100,105,100,32,110,
+111,116,32,105,110,115,116,97,110,99,101,45,115,101,97,114,99,104,45,34,32,108,
+97,110,103,61,34,115,112,101,97,107,101,114,115,67,111,109,112,117,116,101,114,
+99,111,110,116,97,105,110,115,97,114,99,104,105,118,101,115,109,105,110,105,115,
+116,101,114,114,101,97,99,116,105,111,110,100,105,115,99,111,117,110,116,73,116,
+97,108,105,97,110,111,99,114,105,116,101,114,105,97,115,116,114,111,110,103,108,
+121,58,32,39,104,116,116,112,58,39,115,99,114,105,112,116,39,99,111,118,101,114,
+105,110,103,111,102,102,101,114,105,110,103,97,112,112,101,97,114,101,100,66,114
+,105,116,105,115,104,32,105,100,101,110,116,105,102,121,70,97,99,101,98,111,111,
+107,110,117,109,101,114,111,117,115,118,101,104,105,99,108,101,115,99,111,110,99
+,101,114,110,115,65,109,101,114,105,99,97,110,104,97,110,100,108,105,110,103,100
+,105,118,32,105,100,61,34,87,105,108,108,105,97,109,32,112,114,111,118,105,100,
+101,114,95,99,111,110,116,101,110,116,97,99,99,117,114,97,99,121,115,101,99,116,
+105,111,110,32,97,110,100,101,114,115,111,110,102,108,101,120,105,98,108,101,67,
+97,116,101,103,111,114,121,108,97,119,114,101,110,99,101,60,115,99,114,105,112,
+116,62,108,97,121,111,117,116,61,34,97,112,112,114,111,118,101,100,32,109,97,120
+,105,109,117,109,104,101,97,100,101,114,34,62,60,47,116,97,98,108,101,62,83,101,
+114,118,105,99,101,115,104,97,109,105,108,116,111,110,99,117,114,114,101,110,116
+,32,99,97,110,97,100,105,97,110,99,104,97,110,110,101,108,115,47,116,104,101,109
+,101,115,47,47,97,114,116,105,99,108,101,111,112,116,105,111,110,97,108,112,111,
+114,116,117,103,97,108,118,97,108,117,101,61,34,34,105,110,116,101,114,118,97,
+108,119,105,114,101,108,101,115,115,101,110,116,105,116,108,101,100,97,103,101,
+110,99,105,101,115,83,101,97,114,99,104,34,32,109,101,97,115,117,114,101,100,116
+,104,111,117,115,97,110,100,115,112,101,110,100,105,110,103,38,104,101,108,108,
+105,112,59,110,101,119,32,68,97,116,101,34,32,115,105,122,101,61,34,112,97,103,
+101,78,97,109,101,109,105,100,100,108,101,34,32,34,32,47,62,60,47,97,62,104,105,
+100,100,101,110,34,62,115,101,113,117,101,110,99,101,112,101,114,115,111,110,97,
+108,111,118,101,114,102,108,111,119,111,112,105,110,105,111,110,115,105,108,108,
+105,110,111,105,115,108,105,110,107,115,34,62,10,9,60,116,105,116,108,101,62,118
+,101,114,115,105,111,110,115,115,97,116,117,114,100,97,121,116,101,114,109,105,
+110,97,108,105,116,101,109,112,114,111,112,101,110,103,105,110,101,101,114,115,
+101,99,116,105,111,110,115,100,101,115,105,103,110,101,114,112,114,111,112,111,
+115,97,108,61,34,102,97,108,115,101,34,69,115,112,97,195,177,111,108,114,101,108
+,101,97,115,101,115,115,117,98,109,105,116,34,32,101,114,38,113,117,111,116,59,
+97,100,100,105,116,105,111,110,115,121,109,112,116,111,109,115,111,114,105,101,
+110,116,101,100,114,101,115,111,117,114,99,101,114,105,103,104,116,34,62,60,112,
+108,101,97,115,117,114,101,115,116,97,116,105,111,110,115,104,105,115,116,111,
+114,121,46,108,101,97,118,105,110,103,32,32,98,111,114,100,101,114,61,99,111,110
+,116,101,110,116,115,99,101,110,116,101,114,34,62,46,10,10,83,111,109,101,32,100
+,105,114,101,99,116,101,100,115,117,105,116,97,98,108,101,98,117,108,103,97,114,
+105,97,46,115,104,111,119,40,41,59,100,101,115,105,103,110,101,100,71,101,110,
+101,114,97,108,32,99,111,110,99,101,112,116,115,69,120,97,109,112,108,101,115,
+119,105,108,108,105,97,109,115,79,114,105,103,105,110,97,108,34,62,60,115,112,97
+,110,62,115,101,97,114,99,104,34,62,111,112,101,114,97,116,111,114,114,101,113,
+117,101,115,116,115,97,32,38,113,117,111,116,59,97,108,108,111,119,105,110,103,
+68,111,99,117,109,101,110,116,114,101,118,105,115,105,111,110,46,32,10,10,84,104
+,101,32,121,111,117,114,115,101,108,102,67,111,110,116,97,99,116,32,109,105,99,
+104,105,103,97,110,69,110,103,108,105,115,104,32,99,111,108,117,109,98,105,97,
+112,114,105,111,114,105,116,121,112,114,105,110,116,105,110,103,100,114,105,110,
+107,105,110,103,102,97,99,105,108,105,116,121,114,101,116,117,114,110,101,100,67
+,111,110,116,101,110,116,32,111,102,102,105,99,101,114,115,82,117,115,115,105,97
+,110,32,103,101,110,101,114,97,116,101,45,56,56,53,57,45,49,34,105,110,100,105,
+99,97,116,101,102,97,109,105,108,105,97,114,32,113,117,97,108,105,116,121,109,97
+,114,103,105,110,58,48,32,99,111,110,116,101,110,116,118,105,101,119,112,111,114
+,116,99,111,110,116,97,99,116,115,45,116,105,116,108,101,34,62,112,111,114,116,
+97,98,108,101,46,108,101,110,103,116,104,32,101,108,105,103,105,98,108,101,105,
+110,118,111,108,118,101,115,97,116,108,97,110,116,105,99,111,110,108,111,97,100,
+61,34,100,101,102,97,117,108,116,46,115,117,112,112,108,105,101,100,112,97,121,
+109,101,110,116,115,103,108,111,115,115,97,114,121,10,10,65,102,116,101,114,32,
+103,117,105,100,97,110,99,101,60,47,116,100,62,60,116,100,101,110,99,111,100,105
+,110,103,109,105,100,100,108,101,34,62,99,97,109,101,32,116,111,32,100,105,115,
+112,108,97,121,115,115,99,111,116,116,105,115,104,106,111,110,97,116,104,97,110,
+109,97,106,111,114,105,116,121,119,105,100,103,101,116,115,46,99,108,105,110,105
+,99,97,108,116,104,97,105,108,97,110,100,116,101,97,99,104,101,114,115,60,104,
+101,97,100,62,10,9,97,102,102,101,99,116,101,100,115,117,112,112,111,114,116,115
+,112,111,105,110,116,101,114,59,116,111,83,116,114,105,110,103,60,47,115,109,97,
+108,108,62,111,107,108,97,104,111,109,97,119,105,108,108,32,98,101,32,105,110,
+118,101,115,116,111,114,48,34,32,97,108,116,61,34,104,111,108,105,100,97,121,115
+,82,101,115,111,117,114,99,101,108,105,99,101,110,115,101,100,32,40,119,104,105,
+99,104,32,46,32,65,102,116,101,114,32,99,111,110,115,105,100,101,114,118,105,115
+,105,116,105,110,103,101,120,112,108,111,114,101,114,112,114,105,109,97,114,121,
+32,115,101,97,114,99,104,34,32,97,110,100,114,111,105,100,34,113,117,105,99,107,
+108,121,32,109,101,101,116,105,110,103,115,101,115,116,105,109,97,116,101,59,114
+,101,116,117,114,110,32,59,99,111,108,111,114,58,35,32,104,101,105,103,104,116,
+61,97,112,112,114,111,118,97,108,44,32,38,113,117,111,116,59,32,99,104,101,99,
+107,101,100,46,109,105,110,46,106,115,34,109,97,103,110,101,116,105,99,62,60,47,
+97,62,60,47,104,102,111,114,101,99,97,115,116,46,32,87,104,105,108,101,32,116,
+104,117,114,115,100,97,121,100,118,101,114,116,105,115,101,38,101,97,99,117,116,
+101,59,104,97,115,67,108,97,115,115,101,118,97,108,117,97,116,101,111,114,100,
+101,114,105,110,103,101,120,105,115,116,105,110,103,112,97,116,105,101,110,116,
+115,32,79,110,108,105,110,101,32,99,111,108,111,114,97,100,111,79,112,116,105,
+111,110,115,34,99,97,109,112,98,101,108,108,60,33,45,45,32,101,110,100,60,47,115
+,112,97,110,62,60,60,98,114,32,47,62,13,10,95,112,111,112,117,112,115,124,115,99
+,105,101,110,99,101,115,44,38,113,117,111,116,59,32,113,117,97,108,105,116,121,
+32,87,105,110,100,111,119,115,32,97,115,115,105,103,110,101,100,104,101,105,103,
+104,116,58,32,60,98,32,99,108,97,115,115,108,101,38,113,117,111,116,59,32,118,97
+,108,117,101,61,34,32,67,111,109,112,97,110,121,101,120,97,109,112,108,101,115,
+60,105,102,114,97,109,101,32,98,101,108,105,101,118,101,115,112,114,101,115,101,
+110,116,115,109,97,114,115,104,97,108,108,112,97,114,116,32,111,102,32,112,114,
+111,112,101,114,108,121,41,46,10,10,84,104,101,32,116,97,120,111,110,111,109,121
+,109,117,99,104,32,111,102,32,60,47,115,112,97,110,62,10,34,32,100,97,116,97,45,
+115,114,116,117,103,117,195,170,115,115,99,114,111,108,108,84,111,32,112,114,111
+,106,101,99,116,60,104,101,97,100,62,13,10,97,116,116,111,114,110,101,121,101,
+109,112,104,97,115,105,115,115,112,111,110,115,111,114,115,102,97,110,99,121,98,
+111,120,119,111,114,108,100,39,115,32,119,105,108,100,108,105,102,101,99,104,101
+,99,107,101,100,61,115,101,115,115,105,111,110,115,112,114,111,103,114,97,109,
+109,112,120,59,102,111,110,116,45,32,80,114,111,106,101,99,116,106,111,117,114,
+110,97,108,115,98,101,108,105,101,118,101,100,118,97,99,97,116,105,111,110,116,
+104,111,109,112,115,111,110,108,105,103,104,116,105,110,103,97,110,100,32,116,
+104,101,32,115,112,101,99,105,97,108,32,98,111,114,100,101,114,61,48,99,104,101,
+99,107,105,110,103,60,47,116,98,111,100,121,62,60,98,117,116,116,111,110,32,67,
+111,109,112,108,101,116,101,99,108,101,97,114,102,105,120,10,60,104,101,97,100,
+62,10,97,114,116,105,99,108,101,32,60,115,101,99,116,105,111,110,102,105,110,100
+,105,110,103,115,114,111,108,101,32,105,110,32,112,111,112,117,108,97,114,32,32,
+79,99,116,111,98,101,114,119,101,98,115,105,116,101,32,101,120,112,111,115,117,
+114,101,117,115,101,100,32,116,111,32,32,99,104,97,110,103,101,115,111,112,101,
+114,97,116,101,100,99,108,105,99,107,105,110,103,101,110,116,101,114,105,110,103
+,99,111,109,109,97,110,100,115,105,110,102,111,114,109,101,100,32,110,117,109,98
+,101,114,115,32,32,60,47,100,105,118,62,99,114,101,97,116,105,110,103,111,110,83
+,117,98,109,105,116,109,97,114,121,108,97,110,100,99,111,108,108,101,103,101,115
+,97,110,97,108,121,116,105,99,108,105,115,116,105,110,103,115,99,111,110,116,97,
+99,116,46,108,111,103,103,101,100,73,110,97,100,118,105,115,111,114,121,115,105,
+98,108,105,110,103,115,99,111,110,116,101,110,116,34,115,38,113,117,111,116,59,
+41,115,46,32,84,104,105,115,32,112,97,99,107,97,103,101,115,99,104,101,99,107,98
+,111,120,115,117,103,103,101,115,116,115,112,114,101,103,110,97,110,116,116,111,
+109,111,114,114,111,119,115,112,97,99,105,110,103,61,105,99,111,110,46,112,110,
+103,106,97,112,97,110,101,115,101,99,111,100,101,98,97,115,101,98,117,116,116,
+111,110,34,62,103,97,109,98,108,105,110,103,115,117,99,104,32,97,115,32,44,32,
+119,104,105,108,101,32,60,47,115,112,97,110,62,32,109,105,115,115,111,117,114,
+105,115,112,111,114,116,105,110,103,116,111,112,58,49,112,120,32,46,60,47,115,
+112,97,110,62,116,101,110,115,105,111,110,115,119,105,100,116,104,61,34,50,108,
+97,122,121,108,111,97,100,110,111,118,101,109,98,101,114,117,115,101,100,32,105,
+110,32,104,101,105,103,104,116,61,34,99,114,105,112,116,34,62,10,38,110,98,115,
+112,59,60,47,60,116,114,62,60,116,100,32,104,101,105,103,104,116,58,50,47,112,
+114,111,100,117,99,116,99,111,117,110,116,114,121,32,105,110,99,108,117,100,101,
+32,102,111,111,116,101,114,34,32,38,108,116,59,33,45,45,32,116,105,116,108,101,
+34,62,60,47,106,113,117,101,114,121,46,60,47,102,111,114,109,62,10,40,231,174,
+128,228,189,147,41,40,231,185,129,233,171,148,41,104,114,118,97,116,115,107,105,
+105,116,97,108,105,97,110,111,114,111,109,195,162,110,196,131,116,195,188,114,
+107,195,167,101,216,167,216,177,216,175,217,136,116,97,109,98,105,195,169,110,
+110,111,116,105,99,105,97,115,109,101,110,115,97,106,101,115,112,101,114,115,111
+,110,97,115,100,101,114,101,99,104,111,115,110,97,99,105,111,110,97,108,115,101,
+114,118,105,99,105,111,99,111,110,116,97,99,116,111,117,115,117,97,114,105,111,
+115,112,114,111,103,114,97,109,97,103,111,98,105,101,114,110,111,101,109,112,114
+,101,115,97,115,97,110,117,110,99,105,111,115,118,97,108,101,110,99,105,97,99,
+111,108,111,109,98,105,97,100,101,115,112,117,195,169,115,100,101,112,111,114,
+116,101,115,112,114,111,121,101,99,116,111,112,114,111,100,117,99,116,111,112,
+195,186,98,108,105,99,111,110,111,115,111,116,114,111,115,104,105,115,116,111,
+114,105,97,112,114,101,115,101,110,116,101,109,105,108,108,111,110,101,115,109,
+101,100,105,97,110,116,101,112,114,101,103,117,110,116,97,97,110,116,101,114,105
+,111,114,114,101,99,117,114,115,111,115,112,114,111,98,108,101,109,97,115,97,110
+,116,105,97,103,111,110,117,101,115,116,114,111,115,111,112,105,110,105,195,179,
+110,105,109,112,114,105,109,105,114,109,105,101,110,116,114,97,115,97,109,195,
+169,114,105,99,97,118,101,110,100,101,100,111,114,115,111,99,105,101,100,97,100,
+114,101,115,112,101,99,116,111,114,101,97,108,105,122,97,114,114,101,103,105,115
+,116,114,111,112,97,108,97,98,114,97,115,105,110,116,101,114,195,169,115,101,110
+,116,111,110,99,101,115,101,115,112,101,99,105,97,108,109,105,101,109,98,114,111
+,115,114,101,97,108,105,100,97,100,99,195,179,114,100,111,98,97,122,97,114,97,
+103,111,122,97,112,195,161,103,105,110,97,115,115,111,99,105,97,108,101,115,98,
+108,111,113,117,101,97,114,103,101,115,116,105,195,179,110,97,108,113,117,105,
+108,101,114,115,105,115,116,101,109,97,115,99,105,101,110,99,105,97,115,99,111,
+109,112,108,101,116,111,118,101,114,115,105,195,179,110,99,111,109,112,108,101,
+116,97,101,115,116,117,100,105,111,115,112,195,186,98,108,105,99,97,111,98,106,
+101,116,105,118,111,97,108,105,99,97,110,116,101,98,117,115,99,97,100,111,114,99
+,97,110,116,105,100,97,100,101,110,116,114,97,100,97,115,97,99,99,105,111,110,
+101,115,97,114,99,104,105,118,111,115,115,117,112,101,114,105,111,114,109,97,121
+,111,114,195,173,97,97,108,101,109,97,110,105,97,102,117,110,99,105,195,179,110,
+195,186,108,116,105,109,111,115,104,97,99,105,101,110,100,111,97,113,117,101,108
+,108,111,115,101,100,105,99,105,195,179,110,102,101,114,110,97,110,100,111,97,
+109,98,105,101,110,116,101,102,97,99,101,98,111,111,107,110,117,101,115,116,114,
+97,115,99,108,105,101,110,116,101,115,112,114,111,99,101,115,111,115,98,97,115,
+116,97,110,116,101,112,114,101,115,101,110,116,97,114,101,112,111,114,116,97,114
+,99,111,110,103,114,101,115,111,112,117,98,108,105,99,97,114,99,111,109,101,114,
+99,105,111,99,111,110,116,114,97,116,111,106,195,179,118,101,110,101,115,100,105
+,115,116,114,105,116,111,116,195,169,99,110,105,99,97,99,111,110,106,117,110,116
+,111,101,110,101,114,103,195,173,97,116,114,97,98,97,106,97,114,97,115,116,117,
+114,105,97,115,114,101,99,105,101,110,116,101,117,116,105,108,105,122,97,114,98,
+111,108,101,116,195,173,110,115,97,108,118,97,100,111,114,99,111,114,114,101,99,
+116,97,116,114,97,98,97,106,111,115,112,114,105,109,101,114,111,115,110,101,103,
+111,99,105,111,115,108,105,98,101,114,116,97,100,100,101,116,97,108,108,101,115,
+112,97,110,116,97,108,108,97,112,114,195,179,120,105,109,111,97,108,109,101,114,
+195,173,97,97,110,105,109,97,108,101,115,113,117,105,195,169,110,101,115,99,111,
+114,97,122,195,179,110,115,101,99,99,105,195,179,110,98,117,115,99,97,110,100,
+111,111,112,99,105,111,110,101,115,101,120,116,101,114,105,111,114,99,111,110,99
+,101,112,116,111,116,111,100,97,118,195,173,97,103,97,108,101,114,195,173,97,101
+,115,99,114,105,98,105,114,109,101,100,105,99,105,110,97,108,105,99,101,110,99,
+105,97,99,111,110,115,117,108,116,97,97,115,112,101,99,116,111,115,99,114,195,
+173,116,105,99,97,100,195,179,108,97,114,101,115,106,117,115,116,105,99,105,97,
+100,101,98,101,114,195,161,110,112,101,114,195,173,111,100,111,110,101,99,101,
+115,105,116,97,109,97,110,116,101,110,101,114,112,101,113,117,101,195,177,111,
+114,101,99,105,98,105,100,97,116,114,105,98,117,110,97,108,116,101,110,101,114,
+105,102,101,99,97,110,99,105,195,179,110,99,97,110,97,114,105,97,115,100,101,115
+,99,97,114,103,97,100,105,118,101,114,115,111,115,109,97,108,108,111,114,99,97,
+114,101,113,117,105,101,114,101,116,195,169,99,110,105,99,111,100,101,98,101,114
+,195,173,97,118,105,118,105,101,110,100,97,102,105,110,97,110,122,97,115,97,100,
+101,108,97,110,116,101,102,117,110,99,105,111,110,97,99,111,110,115,101,106,111,
+115,100,105,102,195,173,99,105,108,99,105,117,100,97,100,101,115,97,110,116,105,
+103,117,97,115,97,118,97,110,122,97,100,97,116,195,169,114,109,105,110,111,117,
+110,105,100,97,100,101,115,115,195,161,110,99,104,101,122,99,97,109,112,97,195,
+177,97,115,111,102,116,111,110,105,99,114,101,118,105,115,116,97,115,99,111,110,
+116,105,101,110,101,115,101,99,116,111,114,101,115,109,111,109,101,110,116,111,
+115,102,97,99,117,108,116,97,100,99,114,195,169,100,105,116,111,100,105,118,101,
+114,115,97,115,115,117,112,117,101,115,116,111,102,97,99,116,111,114,101,115,115
+,101,103,117,110,100,111,115,112,101,113,117,101,195,177,97,208,179,208,190,208,
+180,208,176,208,181,209,129,208,187,208,184,208,181,209,129,209,130,209,140,208,
+177,209,139,208,187,208,190,208,177,209,139,209,130,209,140,209,141,209,130,208,
+190,208,188,208,149,209,129,208,187,208,184,209,130,208,190,208,179,208,190,208,
+188,208,181,208,189,209,143,208,178,209,129,208,181,209,133,209,141,209,130,208,
+190,208,185,208,180,208,176,208,182,208,181,208,177,209,139,208,187,208,184,208,
+179,208,190,208,180,209,131,208,180,208,181,208,189,209,140,209,141,209,130,208,
+190,209,130,208,177,209,139,208,187,208,176,209,129,208,181,208,177,209,143,208,
+190,208,180,208,184,208,189,209,129,208,181,208,177,208,181,208,189,208,176,208,
+180,208,190,209,129,208,176,208,185,209,130,209,132,208,190,209,130,208,190,208,
+189,208,181,208,179,208,190,209,129,208,178,208,190,208,184,209,129,208,178,208,
+190,208,185,208,184,208,179,209,128,209,139,209,130,208,190,208,182,208,181,208,
+178,209,129,208,181,208,188,209,129,208,178,208,190,209,142,208,187,208,184,209,
+136,209,140,209,141,209,130,208,184,209,133,208,191,208,190,208,186,208,176,208,
+180,208,189,208,181,208,185,208,180,208,190,208,188,208,176,208,188,208,184,209,
+128,208,176,208,187,208,184,208,177,208,190,209,130,208,181,208,188,209,131,209,
+133,208,190,209,130,209,143,208,180,208,178,209,131,209,133,209,129,208,181,209,
+130,208,184,208,187,209,142,208,180,208,184,208,180,208,181,208,187,208,190,208,
+188,208,184,209,128,208,181,209,130,208,181,208,177,209,143,209,129,208,178,208,
+190,208,181,208,178,208,184,208,180,208,181,209,135,208,181,208,179,208,190,209,
+141,209,130,208,184,208,188,209,129,209,135,208,181,209,130,209,130,208,181,208,
+188,209,139,209,134,208,181,208,189,209,139,209,129,209,130,208,176,208,187,208,
+178,208,181,208,180,209,140,209,130,208,181,208,188,208,181,208,178,208,190,208,
+180,209,139,209,130,208,181,208,177,208,181,208,178,209,139,209,136,208,181,208,
+189,208,176,208,188,208,184,209,130,208,184,208,191,208,176,209,130,208,190,208,
+188,209,131,208,191,209,128,208,176,208,178,208,187,208,184,209,134,208,176,208,
+190,208,180,208,189,208,176,208,179,208,190,208,180,209,139,208,183,208,189,208,
+176,209,142,208,188,208,190,208,179,209,131,208,180,209,128,209,131,208,179,208,
+178,209,129,208,181,208,185,208,184,208,180,208,181,209,130,208,186,208,184,208,
+189,208,190,208,190,208,180,208,189,208,190,208,180,208,181,208,187,208,176,208,
+180,208,181,208,187,208,181,209,129,209,128,208,190,208,186,208,184,209,142,208,
+189,209,143,208,178,208,181,209,129,209,140,208,149,209,129,209,130,209,140,209,
+128,208,176,208,183,208,176,208,189,208,176,209,136,208,184,216,167,217,132,217,
+132,217,135,216,167,217,132,216,170,217,138,216,172,217,133,217,138,216,185,216,
+174,216,167,216,181,216,169,216,167,217,132,216,176,217,138,216,185,217,132,217,
+138,217,135,216,172,216,175,217,138,216,175,216,167,217,132,216,162,217,134,216,
+167,217,132,216,177,216,175,216,170,216,173,217,131,217,133,216,181,217,129,216,
+173,216,169,217,131,216,167,217,134,216,170,216,167,217,132,217,132,217,138,217,
+138,217,131,217,136,217,134,216,180,216,168,217,131,216,169,217,129,217,138,217,
+135,216,167,216,168,217,134,216,167,216,170,216,173,217,136,216,167,216,161,216,
+163,217,131,216,171,216,177,216,174,217,132,216,167,217,132,216,167,217,132,216,
+173,216,168,216,175,217,132,217,138,217,132,216,175,216,177,217,136,216,179,216,
+167,216,182,216,186,216,183,216,170,217,131,217,136,217,134,217,135,217,134,216,
+167,217,131,216,179,216,167,216,173,216,169,217,134,216,167,216,175,217,138,216,
+167,217,132,216,183,216,168,216,185,217,132,217,138,217,131,216,180,217,131,216,
+177,216,167,217,138,217,133,217,131,217,134,217,133,217,134,217,135,216,167,216,
+180,216,177,217,131,216,169,216,177,216,166,217,138,216,179,217,134,216,180,217,
+138,216,183,217,133,216,167,216,176,216,167,216,167,217,132,217,129,217,134,216,
+180,216,168,216,167,216,168,216,170,216,185,216,168,216,177,216,177,216,173,217,
+133,216,169,217,131,216,167,217,129,216,169,217,138,217,130,217,136,217,132,217,
+133,216,177,217,131,216,178,217,131,217,132,217,133,216,169,216,163,216,173,217,
+133,216,175,217,130,217,132,216,168,217,138,217,138,216,185,217,134,217,138,216,
+181,217,136,216,177,216,169,216,183,216,177,217,138,217,130,216,180,216,167,216,
+177,217,131,216,172,217,136,216,167,217,132,216,163,216,174,216,177,217,137,217,
+133,216,185,217,134,216,167,216,167,216,168,216,173,216,171,216,185,216,177,217,
+136,216,182,216,168,216,180,217,131,217,132,217,133,216,179,216,172,217,132,216,
+168,217,134,216,167,217,134,216,174,216,167,217,132,216,175,217,131,216,170,216,
+167,216,168,217,131,217,132,217,138,216,169,216,168,216,175,217,136,217,134,216,
+163,217,138,216,182,216,167,217,138,217,136,216,172,216,175,217,129,216,177,217,
+138,217,130,217,131,216,170,216,168,216,170,216,163,217,129,216,182,217,132,217,
+133,216,183,216,168,216,174,216,167,217,131,216,171,216,177,216,168,216,167,216,
+177,217,131,216,167,217,129,216,182,217,132,216,167,216,173,217,132,217,137,217,
+134,217,129,216,179,217,135,216,163,217,138,216,167,217,133,216,177,216,175,217,
+136,216,175,216,163,217,134,217,135,216,167,216,175,217,138,217,134,216,167,216,
+167,217,132,216,167,217,134,217,133,216,185,216,177,216,182,216,170,216,185,217,
+132,217,133,216,175,216,167,216,174,217,132,217,133,217,133,217,131,217,134,0,0,
+0,0,0,0,0,0,1,0,1,0,1,0,1,0,2,0,2,0,2,0,2,0,4,0,4,0,4,0,4,0,0,1,2,3,4,5,6,7,7,6,
+5,4,3,2,1,0,8,9,10,11,12,13,14,15,15,14,13,12,11,10,9,8,16,17,18,19,20,21,22,23,
+23,22,21,20,19,18,17,16,24,25,26,27,28,29,30,31,31,30,29,28,27,26,25,24,255,255,
+255,255,0,0,0,0,0,0,0,0,255,255,255,255,1,0,0,0,2,0,0,0,2,0,0,0,1,0,0,0,1,0,0,0,
+3,0,0,0,255,255,0,1,0,0,0,1,0,0,255,255,0,1,0,0,0,8,0,8,0,8,0,8,0,0,0,1,0,2,0,3,
+0,4,0,5,0,6,0,7,114,101,115,111,117,114,99,101,115,99,111,117,110,116,114,105,
+101,115,113,117,101,115,116,105,111,110,115,101,113,117,105,112,109,101,110,116,
+99,111,109,109,117,110,105,116,121,97,118,97,105,108,97,98,108,101,104,105,103,
+104,108,105,103,104,116,68,84,68,47,120,104,116,109,108,109,97,114,107,101,116,
+105,110,103,107,110,111,119,108,101,100,103,101,115,111,109,101,116,104,105,110,
+103,99,111,110,116,97,105,110,101,114,100,105,114,101,99,116,105,111,110,115,117
+,98,115,99,114,105,98,101,97,100,118,101,114,116,105,115,101,99,104,97,114,97,99
+,116,101,114,34,32,118,97,108,117,101,61,34,60,47,115,101,108,101,99,116,62,65,
+117,115,116,114,97,108,105,97,34,32,99,108,97,115,115,61,34,115,105,116,117,97,
+116,105,111,110,97,117,116,104,111,114,105,116,121,102,111,108,108,111,119,105,
+110,103,112,114,105,109,97,114,105,108,121,111,112,101,114,97,116,105,111,110,99
+,104,97,108,108,101,110,103,101,100,101,118,101,108,111,112,101,100,97,110,111,
+110,121,109,111,117,115,102,117,110,99,116,105,111,110,32,102,117,110,99,116,105
+,111,110,115,99,111,109,112,97,110,105,101,115,115,116,114,117,99,116,117,114,
+101,97,103,114,101,101,109,101,110,116,34,32,116,105,116,108,101,61,34,112,111,
+116,101,110,116,105,97,108,101,100,117,99,97,116,105,111,110,97,114,103,117,109,
+101,110,116,115,115,101,99,111,110,100,97,114,121,99,111,112,121,114,105,103,104
+,116,108,97,110,103,117,97,103,101,115,101,120,99,108,117,115,105,118,101,99,111
+,110,100,105,116,105,111,110,60,47,102,111,114,109,62,13,10,115,116,97,116,101,
+109,101,110,116,97,116,116,101,110,116,105,111,110,66,105,111,103,114,97,112,104
+,121,125,32,101,108,115,101,32,123,10,115,111,108,117,116,105,111,110,115,119,
+104,101,110,32,116,104,101,32,65,110,97,108,121,116,105,99,115,116,101,109,112,
+108,97,116,101,115,100,97,110,103,101,114,111,117,115,115,97,116,101,108,108,105
+,116,101,100,111,99,117,109,101,110,116,115,112,117,98,108,105,115,104,101,114,
+105,109,112,111,114,116,97,110,116,112,114,111,116,111,116,121,112,101,105,110,
+102,108,117,101,110,99,101,38,114,97,113,117,111,59,60,47,101,102,102,101,99,116
+,105,118,101,103,101,110,101,114,97,108,108,121,116,114,97,110,115,102,111,114,
+109,98,101,97,117,116,105,102,117,108,116,114,97,110,115,112,111,114,116,111,114
+,103,97,110,105,122,101,100,112,117,98,108,105,115,104,101,100,112,114,111,109,
+105,110,101,110,116,117,110,116,105,108,32,116,104,101,116,104,117,109,98,110,97
+,105,108,78,97,116,105,111,110,97,108,32,46,102,111,99,117,115,40,41,59,111,118,
+101,114,32,116,104,101,32,109,105,103,114,97,116,105,111,110,97,110,110,111,117,
+110,99,101,100,102,111,111,116,101,114,34,62,10,101,120,99,101,112,116,105,111,
+110,108,101,115,115,32,116,104,97,110,101,120,112,101,110,115,105,118,101,102,
+111,114,109,97,116,105,111,110,102,114,97,109,101,119,111,114,107,116,101,114,
+114,105,116,111,114,121,110,100,105,99,97,116,105,111,110,99,117,114,114,101,110
+,116,108,121,99,108,97,115,115,78,97,109,101,99,114,105,116,105,99,105,115,109,
+116,114,97,100,105,116,105,111,110,101,108,115,101,119,104,101,114,101,65,108,
+101,120,97,110,100,101,114,97,112,112,111,105,110,116,101,100,109,97,116,101,114
+,105,97,108,115,98,114,111,97,100,99,97,115,116,109,101,110,116,105,111,110,101,
+100,97,102,102,105,108,105,97,116,101,60,47,111,112,116,105,111,110,62,116,114,
+101,97,116,109,101,110,116,100,105,102,102,101,114,101,110,116,47,100,101,102,97
+,117,108,116,46,80,114,101,115,105,100,101,110,116,111,110,99,108,105,99,107,61,
+34,98,105,111,103,114,97,112,104,121,111,116,104,101,114,119,105,115,101,112,101
+,114,109,97,110,101,110,116,70,114,97,110,195,167,97,105,115,72,111,108,108,121,
+119,111,111,100,101,120,112,97,110,115,105,111,110,115,116,97,110,100,97,114,100
+,115,60,47,115,116,121,108,101,62,10,114,101,100,117,99,116,105,111,110,68,101,
+99,101,109,98,101,114,32,112,114,101,102,101,114,114,101,100,67,97,109,98,114,
+105,100,103,101,111,112,112,111,110,101,110,116,115,66,117,115,105,110,101,115,
+115,32,99,111,110,102,117,115,105,111,110,62,10,60,116,105,116,108,101,62,112,
+114,101,115,101,110,116,101,100,101,120,112,108,97,105,110,101,100,100,111,101,
+115,32,110,111,116,32,119,111,114,108,100,119,105,100,101,105,110,116,101,114,
+102,97,99,101,112,111,115,105,116,105,111,110,115,110,101,119,115,112,97,112,101
+,114,60,47,116,97,98,108,101,62,10,109,111,117,110,116,97,105,110,115,108,105,
+107,101,32,116,104,101,32,101,115,115,101,110,116,105,97,108,102,105,110,97,110,
+99,105,97,108,115,101,108,101,99,116,105,111,110,97,99,116,105,111,110,61,34,47,
+97,98,97,110,100,111,110,101,100,69,100,117,99,97,116,105,111,110,112,97,114,115
+,101,73,110,116,40,115,116,97,98,105,108,105,116,121,117,110,97,98,108,101,32,
+116,111,60,47,116,105,116,108,101,62,10,114,101,108,97,116,105,111,110,115,78,
+111,116,101,32,116,104,97,116,101,102,102,105,99,105,101,110,116,112,101,114,102
+,111,114,109,101,100,116,119,111,32,121,101,97,114,115,83,105,110,99,101,32,116,
+104,101,116,104,101,114,101,102,111,114,101,119,114,97,112,112,101,114,34,62,97,
+108,116,101,114,110,97,116,101,105,110,99,114,101,97,115,101,100,66,97,116,116,
+108,101,32,111,102,112,101,114,99,101,105,118,101,100,116,114,121,105,110,103,32
+,116,111,110,101,99,101,115,115,97,114,121,112,111,114,116,114,97,121,101,100,
+101,108,101,99,116,105,111,110,115,69,108,105,122,97,98,101,116,104,60,47,105,
+102,114,97,109,101,62,100,105,115,99,111,118,101,114,121,105,110,115,117,114,97,
+110,99,101,115,46,108,101,110,103,116,104,59,108,101,103,101,110,100,97,114,121,
+71,101,111,103,114,97,112,104,121,99,97,110,100,105,100,97,116,101,99,111,114,
+112,111,114,97,116,101,115,111,109,101,116,105,109,101,115,115,101,114,118,105,
+99,101,115,46,105,110,104,101,114,105,116,101,100,60,47,115,116,114,111,110,103,
+62,67,111,109,109,117,110,105,116,121,114,101,108,105,103,105,111,117,115,108,
+111,99,97,116,105,111,110,115,67,111,109,109,105,116,116,101,101,98,117,105,108,
+100,105,110,103,115,116,104,101,32,119,111,114,108,100,110,111,32,108,111,110,
+103,101,114,98,101,103,105,110,110,105,110,103,114,101,102,101,114,101,110,99,
+101,99,97,110,110,111,116,32,98,101,102,114,101,113,117,101,110,99,121,116,121,
+112,105,99,97,108,108,121,105,110,116,111,32,116,104,101,32,114,101,108,97,116,
+105,118,101,59,114,101,99,111,114,100,105,110,103,112,114,101,115,105,100,101,
+110,116,105,110,105,116,105,97,108,108,121,116,101,99,104,110,105,113,117,101,
+116,104,101,32,111,116,104,101,114,105,116,32,99,97,110,32,98,101,101,120,105,
+115,116,101,110,99,101,117,110,100,101,114,108,105,110,101,116,104,105,115,32,
+116,105,109,101,116,101,108,101,112,104,111,110,101,105,116,101,109,115,99,111,
+112,101,112,114,97,99,116,105,99,101,115,97,100,118,97,110,116,97,103,101,41,59,
+114,101,116,117,114,110,32,70,111,114,32,111,116,104,101,114,112,114,111,118,105
+,100,105,110,103,100,101,109,111,99,114,97,99,121,98,111,116,104,32,116,104,101,
+32,101,120,116,101,110,115,105,118,101,115,117,102,102,101,114,105,110,103,115,
+117,112,112,111,114,116,101,100,99,111,109,112,117,116,101,114,115,32,102,117,
+110,99,116,105,111,110,112,114,97,99,116,105,99,97,108,115,97,105,100,32,116,104
+,97,116,105,116,32,109,97,121,32,98,101,69,110,103,108,105,115,104,60,47,102,114
+,111,109,32,116,104,101,32,115,99,104,101,100,117,108,101,100,100,111,119,110,
+108,111,97,100,115,60,47,108,97,98,101,108,62,10,115,117,115,112,101,99,116,101,
+100,109,97,114,103,105,110,58,32,48,115,112,105,114,105,116,117,97,108,60,47,104
+,101,97,100,62,10,10,109,105,99,114,111,115,111,102,116,103,114,97,100,117,97,
+108,108,121,100,105,115,99,117,115,115,101,100,104,101,32,98,101,99,97,109,101,
+101,120,101,99,117,116,105,118,101,106,113,117,101,114,121,46,106,115,104,111,
+117,115,101,104,111,108,100,99,111,110,102,105,114,109,101,100,112,117,114,99,
+104,97,115,101,100,108,105,116,101,114,97,108,108,121,100,101,115,116,114,111,
+121,101,100,117,112,32,116,111,32,116,104,101,118,97,114,105,97,116,105,111,110,
+114,101,109,97,105,110,105,110,103,105,116,32,105,115,32,110,111,116,99,101,110,
+116,117,114,105,101,115,74,97,112,97,110,101,115,101,32,97,109,111,110,103,32,
+116,104,101,99,111,109,112,108,101,116,101,100,97,108,103,111,114,105,116,104,
+109,105,110,116,101,114,101,115,116,115,114,101,98,101,108,108,105,111,110,117,
+110,100,101,102,105,110,101,100,101,110,99,111,117,114,97,103,101,114,101,115,
+105,122,97,98,108,101,105,110,118,111,108,118,105,110,103,115,101,110,115,105,
+116,105,118,101,117,110,105,118,101,114,115,97,108,112,114,111,118,105,115,105,
+111,110,40,97,108,116,104,111,117,103,104,102,101,97,116,117,114,105,110,103,99,
+111,110,100,117,99,116,101,100,41,44,32,119,104,105,99,104,32,99,111,110,116,105
+,110,117,101,100,45,104,101,97,100,101,114,34,62,70,101,98,114,117,97,114,121,32
+,110,117,109,101,114,111,117,115,32,111,118,101,114,102,108,111,119,58,99,111,
+109,112,111,110,101,110,116,102,114,97,103,109,101,110,116,115,101,120,99,101,
+108,108,101,110,116,99,111,108,115,112,97,110,61,34,116,101,99,104,110,105,99,97
+,108,110,101,97,114,32,116,104,101,32,65,100,118,97,110,99,101,100,32,115,111,
+117,114,99,101,32,111,102,101,120,112,114,101,115,115,101,100,72,111,110,103,32,
+75,111,110,103,32,70,97,99,101,98,111,111,107,109,117,108,116,105,112,108,101,32
+,109,101,99,104,97,110,105,115,109,101,108,101,118,97,116,105,111,110,111,102,
+102,101,110,115,105,118,101,60,47,102,111,114,109,62,10,9,115,112,111,110,115,
+111,114,101,100,100,111,99,117,109,101,110,116,46,111,114,32,38,113,117,111,116,
+59,116,104,101,114,101,32,97,114,101,116,104,111,115,101,32,119,104,111,109,111,
+118,101,109,101,110,116,115,112,114,111,99,101,115,115,101,115,100,105,102,102,
+105,99,117,108,116,115,117,98,109,105,116,116,101,100,114,101,99,111,109,109,101
+,110,100,99,111,110,118,105,110,99,101,100,112,114,111,109,111,116,105,110,103,
+34,32,119,105,100,116,104,61,34,46,114,101,112,108,97,99,101,40,99,108,97,115,
+115,105,99,97,108,99,111,97,108,105,116,105,111,110,104,105,115,32,102,105,114,
+115,116,100,101,99,105,115,105,111,110,115,97,115,115,105,115,116,97,110,116,105
+,110,100,105,99,97,116,101,100,101,118,111,108,117,116,105,111,110,45,119,114,97
+,112,112,101,114,34,101,110,111,117,103,104,32,116,111,97,108,111,110,103,32,116
+,104,101,100,101,108,105,118,101,114,101,100,45,45,62,13,10,60,33,45,45,65,109,
+101,114,105,99,97,110,32,112,114,111,116,101,99,116,101,100,78,111,118,101,109,
+98,101,114,32,60,47,115,116,121,108,101,62,60,102,117,114,110,105,116,117,114,
+101,73,110,116,101,114,110,101,116,32,32,111,110,98,108,117,114,61,34,115,117,
+115,112,101,110,100,101,100,114,101,99,105,112,105,101,110,116,98,97,115,101,100
+,32,111,110,32,77,111,114,101,111,118,101,114,44,97,98,111,108,105,115,104,101,
+100,99,111,108,108,101,99,116,101,100,119,101,114,101,32,109,97,100,101,101,109,
+111,116,105,111,110,97,108,101,109,101,114,103,101,110,99,121,110,97,114,114,97,
+116,105,118,101,97,100,118,111,99,97,116,101,115,112,120,59,98,111,114,100,101,
+114,99,111,109,109,105,116,116,101,100,100,105,114,61,34,108,116,114,34,101,109,
+112,108,111,121,101,101,115,114,101,115,101,97,114,99,104,46,32,115,101,108,101,
+99,116,101,100,115,117,99,99,101,115,115,111,114,99,117,115,116,111,109,101,114,
+115,100,105,115,112,108,97,121,101,100,83,101,112,116,101,109,98,101,114,97,100,
+100,67,108,97,115,115,40,70,97,99,101,98,111,111,107,32,115,117,103,103,101,115,
+116,101,100,97,110,100,32,108,97,116,101,114,111,112,101,114,97,116,105,110,103,
+101,108,97,98,111,114,97,116,101,83,111,109,101,116,105,109,101,115,73,110,115,
+116,105,116,117,116,101,99,101,114,116,97,105,110,108,121,105,110,115,116,97,108
+,108,101,100,102,111,108,108,111,119,101,114,115,74,101,114,117,115,97,108,101,
+109,116,104,101,121,32,104,97,118,101,99,111,109,112,117,116,105,110,103,103,101
+,110,101,114,97,116,101,100,112,114,111,118,105,110,99,101,115,103,117,97,114,97
+,110,116,101,101,97,114,98,105,116,114,97,114,121,114,101,99,111,103,110,105,122
+,101,119,97,110,116,101,100,32,116,111,112,120,59,119,105,100,116,104,58,116,104
+,101,111,114,121,32,111,102,98,101,104,97,118,105,111,117,114,87,104,105,108,101
+,32,116,104,101,101,115,116,105,109,97,116,101,100,98,101,103,97,110,32,116,111,
+32,105,116,32,98,101,99,97,109,101,109,97,103,110,105,116,117,100,101,109,117,
+115,116,32,104,97,118,101,109,111,114,101,32,116,104,97,110,68,105,114,101,99,
+116,111,114,121,101,120,116,101,110,115,105,111,110,115,101,99,114,101,116,97,
+114,121,110,97,116,117,114,97,108,108,121,111,99,99,117,114,114,105,110,103,118,
+97,114,105,97,98,108,101,115,103,105,118,101,110,32,116,104,101,112,108,97,116,
+102,111,114,109,46,60,47,108,97,98,101,108,62,60,102,97,105,108,101,100,32,116,
+111,99,111,109,112,111,117,110,100,115,107,105,110,100,115,32,111,102,32,115,111
+,99,105,101,116,105,101,115,97,108,111,110,103,115,105,100,101,32,45,45,38,103,
+116,59,10,10,115,111,117,116,104,119,101,115,116,116,104,101,32,114,105,103,104,
+116,114,97,100,105,97,116,105,111,110,109,97,121,32,104,97,118,101,32,117,110,
+101,115,99,97,112,101,40,115,112,111,107,101,110,32,105,110,34,32,104,114,101,
+102,61,34,47,112,114,111,103,114,97,109,109,101,111,110,108,121,32,116,104,101,
+32,99,111,109,101,32,102,114,111,109,100,105,114,101,99,116,111,114,121,98,117,
+114,105,101,100,32,105,110,97,32,115,105,109,105,108,97,114,116,104,101,121,32,
+119,101,114,101,60,47,102,111,110,116,62,60,47,78,111,114,119,101,103,105,97,110
+,115,112,101,99,105,102,105,101,100,112,114,111,100,117,99,105,110,103,112,97,
+115,115,101,110,103,101,114,40,110,101,119,32,68,97,116,101,116,101,109,112,111,
+114,97,114,121,102,105,99,116,105,111,110,97,108,65,102,116,101,114,32,116,104,
+101,101,113,117,97,116,105,111,110,115,100,111,119,110,108,111,97,100,46,114,101
+,103,117,108,97,114,108,121,100,101,118,101,108,111,112,101,114,97,98,111,118,
+101,32,116,104,101,108,105,110,107,101,100,32,116,111,112,104,101,110,111,109,
+101,110,97,112,101,114,105,111,100,32,111,102,116,111,111,108,116,105,112,34,62,
+115,117,98,115,116,97,110,99,101,97,117,116,111,109,97,116,105,99,97,115,112,101
+,99,116,32,111,102,65,109,111,110,103,32,116,104,101,99,111,110,110,101,99,116,
+101,100,101,115,116,105,109,97,116,101,115,65,105,114,32,70,111,114,99,101,115,
+121,115,116,101,109,32,111,102,111,98,106,101,99,116,105,118,101,105,109,109,101
+,100,105,97,116,101,109,97,107,105,110,103,32,105,116,112,97,105,110,116,105,110
+,103,115,99,111,110,113,117,101,114,101,100,97,114,101,32,115,116,105,108,108,
+112,114,111,99,101,100,117,114,101,103,114,111,119,116,104,32,111,102,104,101,97
+,100,101,100,32,98,121,69,117,114,111,112,101,97,110,32,100,105,118,105,115,105,
+111,110,115,109,111,108,101,99,117,108,101,115,102,114,97,110,99,104,105,115,101
+,105,110,116,101,110,116,105,111,110,97,116,116,114,97,99,116,101,100,99,104,105
+,108,100,104,111,111,100,97,108,115,111,32,117,115,101,100,100,101,100,105,99,97
+,116,101,100,115,105,110,103,97,112,111,114,101,100,101,103,114,101,101,32,111,
+102,102,97,116,104,101,114,32,111,102,99,111,110,102,108,105,99,116,115,60,47,97
+,62,60,47,112,62,10,99,97,109,101,32,102,114,111,109,119,101,114,101,32,117,115,
+101,100,110,111,116,101,32,116,104,97,116,114,101,99,101,105,118,105,110,103,69,
+120,101,99,117,116,105,118,101,101,118,101,110,32,109,111,114,101,97,99,99,101,
+115,115,32,116,111,99,111,109,109,97,110,100,101,114,80,111,108,105,116,105,99,
+97,108,109,117,115,105,99,105,97,110,115,100,101,108,105,99,105,111,117,115,112,
+114,105,115,111,110,101,114,115,97,100,118,101,110,116,32,111,102,85,84,70,45,56
+,34,32,47,62,60,33,91,67,68,65,84,65,91,34,62,67,111,110,116,97,99,116,83,111,
+117,116,104,101,114,110,32,98,103,99,111,108,111,114,61,34,115,101,114,105,101,
+115,32,111,102,46,32,73,116,32,119,97,115,32,105,110,32,69,117,114,111,112,101,
+112,101,114,109,105,116,116,101,100,118,97,108,105,100,97,116,101,46,97,112,112,
+101,97,114,105,110,103,111,102,102,105,99,105,97,108,115,115,101,114,105,111,117
+,115,108,121,45,108,97,110,103,117,97,103,101,105,110,105,116,105,97,116,101,100
+,101,120,116,101,110,100,105,110,103,108,111,110,103,45,116,101,114,109,105,110,
+102,108,97,116,105,111,110,115,117,99,104,32,116,104,97,116,103,101,116,67,111,
+111,107,105,101,109,97,114,107,101,100,32,98,121,60,47,98,117,116,116,111,110,62
+,105,109,112,108,101,109,101,110,116,98,117,116,32,105,116,32,105,115,105,110,99
+,114,101,97,115,101,115,100,111,119,110,32,116,104,101,32,114,101,113,117,105,
+114,105,110,103,100,101,112,101,110,100,101,110,116,45,45,62,10,60,33,45,45,32,
+105,110,116,101,114,118,105,101,119,87,105,116,104,32,116,104,101,32,99,111,112,
+105,101,115,32,111,102,99,111,110,115,101,110,115,117,115,119,97,115,32,98,117,
+105,108,116,86,101,110,101,122,117,101,108,97,40,102,111,114,109,101,114,108,121
+,116,104,101,32,115,116,97,116,101,112,101,114,115,111,110,110,101,108,115,116,
+114,97,116,101,103,105,99,102,97,118,111,117,114,32,111,102,105,110,118,101,110,
+116,105,111,110,87,105,107,105,112,101,100,105,97,99,111,110,116,105,110,101,110
+,116,118,105,114,116,117,97,108,108,121,119,104,105,99,104,32,119,97,115,112,114
+,105,110,99,105,112,108,101,67,111,109,112,108,101,116,101,32,105,100,101,110,
+116,105,99,97,108,115,104,111,119,32,116,104,97,116,112,114,105,109,105,116,105,
+118,101,97,119,97,121,32,102,114,111,109,109,111,108,101,99,117,108,97,114,112,
+114,101,99,105,115,101,108,121,100,105,115,115,111,108,118,101,100,85,110,100,
+101,114,32,116,104,101,118,101,114,115,105,111,110,61,34,62,38,110,98,115,112,59
+,60,47,73,116,32,105,115,32,116,104,101,32,84,104,105,115,32,105,115,32,119,105,
+108,108,32,104,97,118,101,111,114,103,97,110,105,115,109,115,115,111,109,101,32,
+116,105,109,101,70,114,105,101,100,114,105,99,104,119,97,115,32,102,105,114,115,
+116,116,104,101,32,111,110,108,121,32,102,97,99,116,32,116,104,97,116,102,111,
+114,109,32,105,100,61,34,112,114,101,99,101,100,105,110,103,84,101,99,104,110,
+105,99,97,108,112,104,121,115,105,99,105,115,116,111,99,99,117,114,115,32,105,
+110,110,97,118,105,103,97,116,111,114,115,101,99,116,105,111,110,34,62,115,112,
+97,110,32,105,100,61,34,115,111,117,103,104,116,32,116,111,98,101,108,111,119,32
+,116,104,101,115,117,114,118,105,118,105,110,103,125,60,47,115,116,121,108,101,
+62,104,105,115,32,100,101,97,116,104,97,115,32,105,110,32,116,104,101,99,97,117,
+115,101,100,32,98,121,112,97,114,116,105,97,108,108,121,101,120,105,115,116,105,
+110,103,32,117,115,105,110,103,32,116,104,101,119,97,115,32,103,105,118,101,110,
+97,32,108,105,115,116,32,111,102,108,101,118,101,108,115,32,111,102,110,111,116,
+105,111,110,32,111,102,79,102,102,105,99,105,97,108,32,100,105,115,109,105,115,
+115,101,100,115,99,105,101,110,116,105,115,116,114,101,115,101,109,98,108,101,
+115,100,117,112,108,105,99,97,116,101,101,120,112,108,111,115,105,118,101,114,
+101,99,111,118,101,114,101,100,97,108,108,32,111,116,104,101,114,103,97,108,108,
+101,114,105,101,115,123,112,97,100,100,105,110,103,58,112,101,111,112,108,101,32
+,111,102,114,101,103,105,111,110,32,111,102,97,100,100,114,101,115,115,101,115,
+97,115,115,111,99,105,97,116,101,105,109,103,32,97,108,116,61,34,105,110,32,109,
+111,100,101,114,110,115,104,111,117,108,100,32,98,101,109,101,116,104,111,100,32
+,111,102,114,101,112,111,114,116,105,110,103,116,105,109,101,115,116,97,109,112,
+110,101,101,100,101,100,32,116,111,116,104,101,32,71,114,101,97,116,114,101,103,
+97,114,100,105,110,103,115,101,101,109,101,100,32,116,111,118,105,101,119,101,
+100,32,97,115,105,109,112,97,99,116,32,111,110,105,100,101,97,32,116,104,97,116,
+116,104,101,32,87,111,114,108,100,104,101,105,103,104,116,32,111,102,101,120,112
+,97,110,100,105,110,103,84,104,101,115,101,32,97,114,101,99,117,114,114,101,110,
+116,34,62,99,97,114,101,102,117,108,108,121,109,97,105,110,116,97,105,110,115,99
+,104,97,114,103,101,32,111,102,67,108,97,115,115,105,99,97,108,97,100,100,114,
+101,115,115,101,100,112,114,101,100,105,99,116,101,100,111,119,110,101,114,115,
+104,105,112,60,100,105,118,32,105,100,61,34,114,105,103,104,116,34,62,13,10,114,
+101,115,105,100,101,110,99,101,108,101,97,118,101,32,116,104,101,99,111,110,116,
+101,110,116,34,62,97,114,101,32,111,102,116,101,110,32,32,125,41,40,41,59,13,10,
+112,114,111,98,97,98,108,121,32,80,114,111,102,101,115,115,111,114,45,98,117,116
+,116,111,110,34,32,114,101,115,112,111,110,100,101,100,115,97,121,115,32,116,104
+,97,116,104,97,100,32,116,111,32,98,101,112,108,97,99,101,100,32,105,110,72,117,
+110,103,97,114,105,97,110,115,116,97,116,117,115,32,111,102,115,101,114,118,101,
+115,32,97,115,85,110,105,118,101,114,115,97,108,101,120,101,99,117,116,105,111,
+110,97,103,103,114,101,103,97,116,101,102,111,114,32,119,104,105,99,104,105,110,
+102,101,99,116,105,111,110,97,103,114,101,101,100,32,116,111,104,111,119,101,118
+,101,114,44,32,112,111,112,117,108,97,114,34,62,112,108,97,99,101,100,32,111,110
+,99,111,110,115,116,114,117,99,116,101,108,101,99,116,111,114,97,108,115,121,109
+,98,111,108,32,111,102,105,110,99,108,117,100,105,110,103,114,101,116,117,114,
+110,32,116,111,97,114,99,104,105,116,101,99,116,67,104,114,105,115,116,105,97,
+110,112,114,101,118,105,111,117,115,32,108,105,118,105,110,103,32,105,110,101,97
+,115,105,101,114,32,116,111,112,114,111,102,101,115,115,111,114,10,38,108,116,59
+,33,45,45,32,101,102,102,101,99,116,32,111,102,97,110,97,108,121,116,105,99,115,
+119,97,115,32,116,97,107,101,110,119,104,101,114,101,32,116,104,101,116,111,111,
+107,32,111,118,101,114,98,101,108,105,101,102,32,105,110,65,102,114,105,107,97,
+97,110,115,97,115,32,102,97,114,32,97,115,112,114,101,118,101,110,116,101,100,
+119,111,114,107,32,119,105,116,104,97,32,115,112,101,99,105,97,108,60,102,105,
+101,108,100,115,101,116,67,104,114,105,115,116,109,97,115,82,101,116,114,105,101
+,118,101,100,10,10,73,110,32,116,104,101,32,98,97,99,107,32,105,110,116,111,110,
+111,114,116,104,101,97,115,116,109,97,103,97,122,105,110,101,115,62,60,115,116,
+114,111,110,103,62,99,111,109,109,105,116,116,101,101,103,111,118,101,114,110,
+105,110,103,103,114,111,117,112,115,32,111,102,115,116,111,114,101,100,32,105,
+110,101,115,116,97,98,108,105,115,104,97,32,103,101,110,101,114,97,108,105,116,
+115,32,102,105,114,115,116,116,104,101,105,114,32,111,119,110,112,111,112,117,
+108,97,116,101,100,97,110,32,111,98,106,101,99,116,67,97,114,105,98,98,101,97,
+110,97,108,108,111,119,32,116,104,101,100,105,115,116,114,105,99,116,115,119,105
+,115,99,111,110,115,105,110,108,111,99,97,116,105,111,110,46,59,32,119,105,100,
+116,104,58,32,105,110,104,97,98,105,116,101,100,83,111,99,105,97,108,105,115,116
+,74,97,110,117,97,114,121,32,49,60,47,102,111,111,116,101,114,62,115,105,109,105
+,108,97,114,108,121,99,104,111,105,99,101,32,111,102,116,104,101,32,115,97,109,
+101,32,115,112,101,99,105,102,105,99,32,98,117,115,105,110,101,115,115,32,84,104
+,101,32,102,105,114,115,116,46,108,101,110,103,116,104,59,32,100,101,115,105,114
+,101,32,116,111,100,101,97,108,32,119,105,116,104,115,105,110,99,101,32,116,104,
+101,117,115,101,114,65,103,101,110,116,99,111,110,99,101,105,118,101,100,105,110
+,100,101,120,46,112,104,112,97,115,32,38,113,117,111,116,59,101,110,103,97,103,
+101,32,105,110,114,101,99,101,110,116,108,121,44,102,101,119,32,121,101,97,114,
+115,119,101,114,101,32,97,108,115,111,10,60,104,101,97,100,62,10,60,101,100,105,
+116,101,100,32,98,121,97,114,101,32,107,110,111,119,110,99,105,116,105,101,115,
+32,105,110,97,99,99,101,115,115,107,101,121,99,111,110,100,101,109,110,101,100,
+97,108,115,111,32,104,97,118,101,115,101,114,118,105,99,101,115,44,102,97,109,
+105,108,121,32,111,102,83,99,104,111,111,108,32,111,102,99,111,110,118,101,114,
+116,101,100,110,97,116,117,114,101,32,111,102,32,108,97,110,103,117,97,103,101,
+109,105,110,105,115,116,101,114,115,60,47,111,98,106,101,99,116,62,116,104,101,
+114,101,32,105,115,32,97,32,112,111,112,117,108,97,114,115,101,113,117,101,110,
+99,101,115,97,100,118,111,99,97,116,101,100,84,104,101,121,32,119,101,114,101,97
+,110,121,32,111,116,104,101,114,108,111,99,97,116,105,111,110,61,101,110,116,101
+,114,32,116,104,101,109,117,99,104,32,109,111,114,101,114,101,102,108,101,99,116
+,101,100,119,97,115,32,110,97,109,101,100,111,114,105,103,105,110,97,108,32,97,
+32,116,121,112,105,99,97,108,119,104,101,110,32,116,104,101,121,101,110,103,105,
+110,101,101,114,115,99,111,117,108,100,32,110,111,116,114,101,115,105,100,101,
+110,116,115,119,101,100,110,101,115,100,97,121,116,104,101,32,116,104,105,114,
+100,32,112,114,111,100,117,99,116,115,74,97,110,117,97,114,121,32,50,119,104,97,
+116,32,116,104,101,121,97,32,99,101,114,116,97,105,110,114,101,97,99,116,105,111
+,110,115,112,114,111,99,101,115,115,111,114,97,102,116,101,114,32,104,105,115,
+116,104,101,32,108,97,115,116,32,99,111,110,116,97,105,110,101,100,34,62,60,47,
+100,105,118,62,10,60,47,97,62,60,47,116,100,62,100,101,112,101,110,100,32,111,
+110,115,101,97,114,99,104,34,62,10,112,105,101,99,101,115,32,111,102,99,111,109,
+112,101,116,105,110,103,82,101,102,101,114,101,110,99,101,116,101,110,110,101,
+115,115,101,101,119,104,105,99,104,32,104,97,115,32,118,101,114,115,105,111,110,
+61,60,47,115,112,97,110,62,32,60,60,47,104,101,97,100,101,114,62,103,105,118,101
+,115,32,116,104,101,104,105,115,116,111,114,105,97,110,118,97,108,117,101,61,34,
+34,62,112,97,100,100,105,110,103,58,48,118,105,101,119,32,116,104,97,116,116,111
+,103,101,116,104,101,114,44,116,104,101,32,109,111,115,116,32,119,97,115,32,102,
+111,117,110,100,115,117,98,115,101,116,32,111,102,97,116,116,97,99,107,32,111,
+110,99,104,105,108,100,114,101,110,44,112,111,105,110,116,115,32,111,102,112,101
+,114,115,111,110,97,108,32,112,111,115,105,116,105,111,110,58,97,108,108,101,103
+,101,100,108,121,67,108,101,118,101,108,97,110,100,119,97,115,32,108,97,116,101,
+114,97,110,100,32,97,102,116,101,114,97,114,101,32,103,105,118,101,110,119,97,
+115,32,115,116,105,108,108,115,99,114,111,108,108,105,110,103,100,101,115,105,
+103,110,32,111,102,109,97,107,101,115,32,116,104,101,109,117,99,104,32,108,101,
+115,115,65,109,101,114,105,99,97,110,115,46,10,10,65,102,116,101,114,32,44,32,98
+,117,116,32,116,104,101,77,117,115,101,117,109,32,111,102,108,111,117,105,115,
+105,97,110,97,40,102,114,111,109,32,116,104,101,109,105,110,110,101,115,111,116,
+97,112,97,114,116,105,99,108,101,115,97,32,112,114,111,99,101,115,115,68,111,109
+,105,110,105,99,97,110,118,111,108,117,109,101,32,111,102,114,101,116,117,114,
+110,105,110,103,100,101,102,101,110,115,105,118,101,48,48,112,120,124,114,105,
+103,104,109,97,100,101,32,102,114,111,109,109,111,117,115,101,111,118,101,114,34
+,32,115,116,121,108,101,61,34,115,116,97,116,101,115,32,111,102,40,119,104,105,
+99,104,32,105,115,99,111,110,116,105,110,117,101,115,70,114,97,110,99,105,115,99
+,111,98,117,105,108,100,105,110,103,32,119,105,116,104,111,117,116,32,97,119,105
+,116,104,32,115,111,109,101,119,104,111,32,119,111,117,108,100,97,32,102,111,114
+,109,32,111,102,97,32,112,97,114,116,32,111,102,98,101,102,111,114,101,32,105,
+116,107,110,111,119,110,32,97,115,32,32,83,101,114,118,105,99,101,115,108,111,99
+,97,116,105,111,110,32,97,110,100,32,111,102,116,101,110,109,101,97,115,117,114,
+105,110,103,97,110,100,32,105,116,32,105,115,112,97,112,101,114,98,97,99,107,118
+,97,108,117,101,115,32,111,102,13,10,60,116,105,116,108,101,62,61,32,119,105,110
+,100,111,119,46,100,101,116,101,114,109,105,110,101,101,114,38,113,117,111,116,
+59,32,112,108,97,121,101,100,32,98,121,97,110,100,32,101,97,114,108,121,60,47,99
+,101,110,116,101,114,62,102,114,111,109,32,116,104,105,115,116,104,101,32,116,
+104,114,101,101,112,111,119,101,114,32,97,110,100,111,102,32,38,113,117,111,116,
+59,105,110,110,101,114,72,84,77,76,60,97,32,104,114,101,102,61,34,121,58,105,110
+,108,105,110,101,59,67,104,117,114,99,104,32,111,102,116,104,101,32,101,118,101,
+110,116,118,101,114,121,32,104,105,103,104,111,102,102,105,99,105,97,108,32,45,
+104,101,105,103,104,116,58,32,99,111,110,116,101,110,116,61,34,47,99,103,105,45,
+98,105,110,47,116,111,32,99,114,101,97,116,101,97,102,114,105,107,97,97,110,115,
+101,115,112,101,114,97,110,116,111,102,114,97,110,195,167,97,105,115,108,97,116,
+118,105,101,197,161,117,108,105,101,116,117,118,105,197,179,196,140,101,197,161,
+116,105,110,97,196,141,101,197,161,116,105,110,97,224,185,132,224,184,151,224,
+184,162,230,151,165,230,156,172,232,170,158,231,174,128,228,189,147,229,173,151,
+231,185,129,233,171,148,229,173,151,237,149,156,234,181,173,236,150,180,228,184,
+186,228,187,128,228,185,136,232,174,161,231,174,151,230,156,186,231,172,148,232,
+174,176,230,156,172,232,168,142,232,171,150,229,141,128,230,156,141,229,138,161,
+229,153,168,228,186,146,232,129,148,231,189,145,230,136,191,229,156,176,228,186,
+167,228,191,177,228,185,144,233,131,168,229,135,186,231,137,136,231,164,190,230,
+142,146,232,161,140,230,166,156,233,131,168,232,144,189,230,160,188,232,191,155,
+228,184,128,230,173,165,230,148,175,228,187,152,229,174,157,233,170,140,232,175,
+129,231,160,129,229,167,148,229,145,152,228,188,154,230,149,176,230,141,174,229,
+186,147,230,182,136,232,180,185,232,128,133,229,138,158,229,133,172,229,174,164,
+232,174,168,232,174,186,229,140,186,230,183,177,229,156,179,229,184,130,230,146,
+173,230,148,190,229,153,168,229,140,151,228,186,172,229,184,130,229,164,167,229,
+173,166,231,148,159,232,182,138,230,157,165,232,182,138,231,174,161,231,144,134,
+229,145,152,228,191,161,230,129,175,231,189,145,115,101,114,118,105,99,105,111,
+115,97,114,116,195,173,99,117,108,111,97,114,103,101,110,116,105,110,97,98,97,
+114,99,101,108,111,110,97,99,117,97,108,113,117,105,101,114,112,117,98,108,105,
+99,97,100,111,112,114,111,100,117,99,116,111,115,112,111,108,195,173,116,105,99,
+97,114,101,115,112,117,101,115,116,97,119,105,107,105,112,101,100,105,97,115,105
+,103,117,105,101,110,116,101,98,195,186,115,113,117,101,100,97,99,111,109,117,
+110,105,100,97,100,115,101,103,117,114,105,100,97,100,112,114,105,110,99,105,112
+,97,108,112,114,101,103,117,110,116,97,115,99,111,110,116,101,110,105,100,111,
+114,101,115,112,111,110,100,101,114,118,101,110,101,122,117,101,108,97,112,114,
+111,98,108,101,109,97,115,100,105,99,105,101,109,98,114,101,114,101,108,97,99,
+105,195,179,110,110,111,118,105,101,109,98,114,101,115,105,109,105,108,97,114,
+101,115,112,114,111,121,101,99,116,111,115,112,114,111,103,114,97,109,97,115,105
+,110,115,116,105,116,117,116,111,97,99,116,105,118,105,100,97,100,101,110,99,117
+,101,110,116,114,97,101,99,111,110,111,109,195,173,97,105,109,195,161,103,101,
+110,101,115,99,111,110,116,97,99,116,97,114,100,101,115,99,97,114,103,97,114,110
+,101,99,101,115,97,114,105,111,97,116,101,110,99,105,195,179,110,116,101,108,195
+,169,102,111,110,111,99,111,109,105,115,105,195,179,110,99,97,110,99,105,111,110
+,101,115,99,97,112,97,99,105,100,97,100,101,110,99,111,110,116,114,97,114,97,110
+,195,161,108,105,115,105,115,102,97,118,111,114,105,116,111,115,116,195,169,114,
+109,105,110,111,115,112,114,111,118,105,110,99,105,97,101,116,105,113,117,101,
+116,97,115,101,108,101,109,101,110,116,111,115,102,117,110,99,105,111,110,101,
+115,114,101,115,117,108,116,97,100,111,99,97,114,195,161,99,116,101,114,112,114,
+111,112,105,101,100,97,100,112,114,105,110,99,105,112,105,111,110,101,99,101,115
+,105,100,97,100,109,117,110,105,99,105,112,97,108,99,114,101,97,99,105,195,179,
+110,100,101,115,99,97,114,103,97,115,112,114,101,115,101,110,99,105,97,99,111,
+109,101,114,99,105,97,108,111,112,105,110,105,111,110,101,115,101,106,101,114,99
+,105,99,105,111,101,100,105,116,111,114,105,97,108,115,97,108,97,109,97,110,99,
+97,103,111,110,122,195,161,108,101,122,100,111,99,117,109,101,110,116,111,112,
+101,108,195,173,99,117,108,97,114,101,99,105,101,110,116,101,115,103,101,110,101
+,114,97,108,101,115,116,97,114,114,97,103,111,110,97,112,114,195,161,99,116,105,
+99,97,110,111,118,101,100,97,100,101,115,112,114,111,112,117,101,115,116,97,112,
+97,99,105,101,110,116,101,115,116,195,169,99,110,105,99,97,115,111,98,106,101,
+116,105,118,111,115,99,111,110,116,97,99,116,111,115,224,164,174,224,165,135,224
+,164,130,224,164,178,224,164,191,224,164,143,224,164,185,224,165,136,224,164,130
+,224,164,151,224,164,175,224,164,190,224,164,184,224,164,190,224,164,165,224,164
+,143,224,164,181,224,164,130,224,164,176,224,164,185,224,165,135,224,164,149,224
+,165,139,224,164,136,224,164,149,224,165,129,224,164,155,224,164,176,224,164,185
+,224,164,190,224,164,172,224,164,190,224,164,166,224,164,149,224,164,185,224,164
+,190,224,164,184,224,164,173,224,165,128,224,164,185,224,165,129,224,164,143,224
+,164,176,224,164,185,224,165,128,224,164,174,224,165,136,224,164,130,224,164,166
+,224,164,191,224,164,168,224,164,172,224,164,190,224,164,164,100,105,112,108,111
+,100,111,99,115,224,164,184,224,164,174,224,164,175,224,164,176,224,165,130,224,
+164,170,224,164,168,224,164,190,224,164,174,224,164,170,224,164,164,224,164,190,
+224,164,171,224,164,191,224,164,176,224,164,148,224,164,184,224,164,164,224,164,
+164,224,164,176,224,164,185,224,164,178,224,165,139,224,164,151,224,164,185,224,
+165,129,224,164,134,224,164,172,224,164,190,224,164,176,224,164,166,224,165,135,
+224,164,182,224,164,185,224,165,129,224,164,136,224,164,150,224,165,135,224,164,
+178,224,164,175,224,164,166,224,164,191,224,164,149,224,164,190,224,164,174,224,
+164,181,224,165,135,224,164,172,224,164,164,224,165,128,224,164,168,224,164,172,
+224,165,128,224,164,154,224,164,174,224,165,140,224,164,164,224,164,184,224,164,
+190,224,164,178,224,164,178,224,165,135,224,164,150,224,164,156,224,165,137,224,
+164,172,224,164,174,224,164,166,224,164,166,224,164,164,224,164,165,224,164,190,
+224,164,168,224,164,185,224,165,128,224,164,182,224,164,185,224,164,176,224,164,
+133,224,164,178,224,164,151,224,164,149,224,164,173,224,165,128,224,164,168,224,
+164,151,224,164,176,224,164,170,224,164,190,224,164,184,224,164,176,224,164,190,
+224,164,164,224,164,149,224,164,191,224,164,143,224,164,137,224,164,184,224,165,
+135,224,164,151,224,164,175,224,165,128,224,164,185,224,165,130,224,164,129,224,
+164,134,224,164,151,224,165,135,224,164,159,224,165,128,224,164,174,224,164,150,
+224,165,139,224,164,156,224,164,149,224,164,190,224,164,176,224,164,133,224,164,
+173,224,165,128,224,164,151,224,164,175,224,165,135,224,164,164,224,165,129,224,
+164,174,224,164,181,224,165,139,224,164,159,224,164,166,224,165,135,224,164,130,
+224,164,133,224,164,151,224,164,176,224,164,144,224,164,184,224,165,135,224,164,
+174,224,165,135,224,164,178,224,164,178,224,164,151,224,164,190,224,164,185,224,
+164,190,224,164,178,224,164,138,224,164,170,224,164,176,224,164,154,224,164,190,
+224,164,176,224,164,144,224,164,184,224,164,190,224,164,166,224,165,135,224,164,
+176,224,164,156,224,164,191,224,164,184,224,164,166,224,164,191,224,164,178,224,
+164,172,224,164,130,224,164,166,224,164,172,224,164,168,224,164,190,224,164,185,
+224,165,130,224,164,130,224,164,178,224,164,190,224,164,150,224,164,156,224,165,
+128,224,164,164,224,164,172,224,164,159,224,164,168,224,164,174,224,164,191,224,
+164,178,224,164,135,224,164,184,224,165,135,224,164,134,224,164,168,224,165,135,
+224,164,168,224,164,175,224,164,190,224,164,149,224,165,129,224,164,178,224,164,
+178,224,165,137,224,164,151,224,164,173,224,164,190,224,164,151,224,164,176,224,
+165,135,224,164,178,224,164,156,224,164,151,224,164,185,224,164,176,224,164,190,
+224,164,174,224,164,178,224,164,151,224,165,135,224,164,170,224,165,135,224,164,
+156,224,164,185,224,164,190,224,164,165,224,164,135,224,164,184,224,165,128,224,
+164,184,224,164,185,224,165,128,224,164,149,224,164,178,224,164,190,224,164,160,
+224,165,128,224,164,149,224,164,185,224,164,190,224,164,129,224,164,166,224,165,
+130,224,164,176,224,164,164,224,164,185,224,164,164,224,164,184,224,164,190,224,
+164,164,224,164,175,224,164,190,224,164,166,224,164,134,224,164,175,224,164,190,
+224,164,170,224,164,190,224,164,149,224,164,149,224,165,140,224,164,168,224,164,
+182,224,164,190,224,164,174,224,164,166,224,165,135,224,164,150,224,164,175,224,
+164,185,224,165,128,224,164,176,224,164,190,224,164,175,224,164,150,224,165,129,
+224,164,166,224,164,178,224,164,151,224,165,128,99,97,116,101,103,111,114,105,
+101,115,101,120,112,101,114,105,101,110,99,101,60,47,116,105,116,108,101,62,13,
+10,67,111,112,121,114,105,103,104,116,32,106,97,118,97,115,99,114,105,112,116,99
+,111,110,100,105,116,105,111,110,115,101,118,101,114,121,116,104,105,110,103,60,
+112,32,99,108,97,115,115,61,34,116,101,99,104,110,111,108,111,103,121,98,97,99,
+107,103,114,111,117,110,100,60,97,32,99,108,97,115,115,61,34,109,97,110,97,103,
+101,109,101,110,116,38,99,111,112,121,59,32,50,48,49,106,97,118,97,83,99,114,105
+,112,116,99,104,97,114,97,99,116,101,114,115,98,114,101,97,100,99,114,117,109,98
+,116,104,101,109,115,101,108,118,101,115,104,111,114,105,122,111,110,116,97,108,
+103,111,118,101,114,110,109,101,110,116,67,97,108,105,102,111,114,110,105,97,97,
+99,116,105,118,105,116,105,101,115,100,105,115,99,111,118,101,114,101,100,78,97,
+118,105,103,97,116,105,111,110,116,114,97,110,115,105,116,105,111,110,99,111,110
+,110,101,99,116,105,111,110,110,97,118,105,103,97,116,105,111,110,97,112,112,101
+,97,114,97,110,99,101,60,47,116,105,116,108,101,62,60,109,99,104,101,99,107,98,
+111,120,34,32,116,101,99,104,110,105,113,117,101,115,112,114,111,116,101,99,116,
+105,111,110,97,112,112,97,114,101,110,116,108,121,97,115,32,119,101,108,108,32,
+97,115,117,110,116,39,44,32,39,85,65,45,114,101,115,111,108,117,116,105,111,110,
+111,112,101,114,97,116,105,111,110,115,116,101,108,101,118,105,115,105,111,110,
+116,114,97,110,115,108,97,116,101,100,87,97,115,104,105,110,103,116,111,110,110,
+97,118,105,103,97,116,111,114,46,32,61,32,119,105,110,100,111,119,46,105,109,112
+,114,101,115,115,105,111,110,38,108,116,59,98,114,38,103,116,59,108,105,116,101,
+114,97,116,117,114,101,112,111,112,117,108,97,116,105,111,110,98,103,99,111,108,
+111,114,61,34,35,101,115,112,101,99,105,97,108,108,121,32,99,111,110,116,101,110
+,116,61,34,112,114,111,100,117,99,116,105,111,110,110,101,119,115,108,101,116,
+116,101,114,112,114,111,112,101,114,116,105,101,115,100,101,102,105,110,105,116,
+105,111,110,108,101,97,100,101,114,115,104,105,112,84,101,99,104,110,111,108,111
+,103,121,80,97,114,108,105,97,109,101,110,116,99,111,109,112,97,114,105,115,111,
+110,117,108,32,99,108,97,115,115,61,34,46,105,110,100,101,120,79,102,40,34,99,
+111,110,99,108,117,115,105,111,110,100,105,115,99,117,115,115,105,111,110,99,111
+,109,112,111,110,101,110,116,115,98,105,111,108,111,103,105,99,97,108,82,101,118
+,111,108,117,116,105,111,110,95,99,111,110,116,97,105,110,101,114,117,110,100,
+101,114,115,116,111,111,100,110,111,115,99,114,105,112,116,62,60,112,101,114,109
+,105,115,115,105,111,110,101,97,99,104,32,111,116,104,101,114,97,116,109,111,115
+,112,104,101,114,101,32,111,110,102,111,99,117,115,61,34,60,102,111,114,109,32,
+105,100,61,34,112,114,111,99,101,115,115,105,110,103,116,104,105,115,46,118,97,
+108,117,101,103,101,110,101,114,97,116,105,111,110,67,111,110,102,101,114,101,
+110,99,101,115,117,98,115,101,113,117,101,110,116,119,101,108,108,45,107,110,111
+,119,110,118,97,114,105,97,116,105,111,110,115,114,101,112,117,116,97,116,105,
+111,110,112,104,101,110,111,109,101,110,111,110,100,105,115,99,105,112,108,105,
+110,101,108,111,103,111,46,112,110,103,34,32,40,100,111,99,117,109,101,110,116,
+44,98,111,117,110,100,97,114,105,101,115,101,120,112,114,101,115,115,105,111,110
+,115,101,116,116,108,101,109,101,110,116,66,97,99,107,103,114,111,117,110,100,
+111,117,116,32,111,102,32,116,104,101,101,110,116,101,114,112,114,105,115,101,40
+,34,104,116,116,112,115,58,34,32,117,110,101,115,99,97,112,101,40,34,112,97,115,
+115,119,111,114,100,34,32,100,101,109,111,99,114,97,116,105,99,60,97,32,104,114,
+101,102,61,34,47,119,114,97,112,112,101,114,34,62,10,109,101,109,98,101,114,115,
+104,105,112,108,105,110,103,117,105,115,116,105,99,112,120,59,112,97,100,100,105
+,110,103,112,104,105,108,111,115,111,112,104,121,97,115,115,105,115,116,97,110,
+99,101,117,110,105,118,101,114,115,105,116,121,102,97,99,105,108,105,116,105,101
+,115,114,101,99,111,103,110,105,122,101,100,112,114,101,102,101,114,101,110,99,
+101,105,102,32,40,116,121,112,101,111,102,109,97,105,110,116,97,105,110,101,100,
+118,111,99,97,98,117,108,97,114,121,104,121,112,111,116,104,101,115,105,115,46,
+115,117,98,109,105,116,40,41,59,38,97,109,112,59,110,98,115,112,59,97,110,110,
+111,116,97,116,105,111,110,98,101,104,105,110,100,32,116,104,101,70,111,117,110,
+100,97,116,105,111,110,112,117,98,108,105,115,104,101,114,34,97,115,115,117,109,
+112,116,105,111,110,105,110,116,114,111,100,117,99,101,100,99,111,114,114,117,
+112,116,105,111,110,115,99,105,101,110,116,105,115,116,115,101,120,112,108,105,
+99,105,116,108,121,105,110,115,116,101,97,100,32,111,102,100,105,109,101,110,115
+,105,111,110,115,32,111,110,67,108,105,99,107,61,34,99,111,110,115,105,100,101,
+114,101,100,100,101,112,97,114,116,109,101,110,116,111,99,99,117,112,97,116,105,
+111,110,115,111,111,110,32,97,102,116,101,114,105,110,118,101,115,116,109,101,
+110,116,112,114,111,110,111,117,110,99,101,100,105,100,101,110,116,105,102,105,
+101,100,101,120,112,101,114,105,109,101,110,116,77,97,110,97,103,101,109,101,110
+,116,103,101,111,103,114,97,112,104,105,99,34,32,104,101,105,103,104,116,61,34,
+108,105,110,107,32,114,101,108,61,34,46,114,101,112,108,97,99,101,40,47,100,101,
+112,114,101,115,115,105,111,110,99,111,110,102,101,114,101,110,99,101,112,117,
+110,105,115,104,109,101,110,116,101,108,105,109,105,110,97,116,101,100,114,101,
+115,105,115,116,97,110,99,101,97,100,97,112,116,97,116,105,111,110,111,112,112,
+111,115,105,116,105,111,110,119,101,108,108,32,107,110,111,119,110,115,117,112,
+112,108,101,109,101,110,116,100,101,116,101,114,109,105,110,101,100,104,49,32,99
+,108,97,115,115,61,34,48,112,120,59,109,97,114,103,105,110,109,101,99,104,97,110
+,105,99,97,108,115,116,97,116,105,115,116,105,99,115,99,101,108,101,98,114,97,
+116,101,100,71,111,118,101,114,110,109,101,110,116,10,10,68,117,114,105,110,103,
+32,116,100,101,118,101,108,111,112,101,114,115,97,114,116,105,102,105,99,105,97,
+108,101,113,117,105,118,97,108,101,110,116,111,114,105,103,105,110,97,116,101,
+100,67,111,109,109,105,115,115,105,111,110,97,116,116,97,99,104,109,101,110,116,
+60,115,112,97,110,32,105,100,61,34,116,104,101,114,101,32,119,101,114,101,78,101
+,100,101,114,108,97,110,100,115,98,101,121,111,110,100,32,116,104,101,114,101,
+103,105,115,116,101,114,101,100,106,111,117,114,110,97,108,105,115,116,102,114,
+101,113,117,101,110,116,108,121,97,108,108,32,111,102,32,116,104,101,108,97,110,
+103,61,34,101,110,34,32,60,47,115,116,121,108,101,62,13,10,97,98,115,111,108,117
+,116,101,59,32,115,117,112,112,111,114,116,105,110,103,101,120,116,114,101,109,
+101,108,121,32,109,97,105,110,115,116,114,101,97,109,60,47,115,116,114,111,110,
+103,62,32,112,111,112,117,108,97,114,105,116,121,101,109,112,108,111,121,109,101
+,110,116,60,47,116,97,98,108,101,62,13,10,32,99,111,108,115,112,97,110,61,34,60,
+47,102,111,114,109,62,10,32,32,99,111,110,118,101,114,115,105,111,110,97,98,111,
+117,116,32,116,104,101,32,60,47,112,62,60,47,100,105,118,62,105,110,116,101,103,
+114,97,116,101,100,34,32,108,97,110,103,61,34,101,110,80,111,114,116,117,103,117
+,101,115,101,115,117,98,115,116,105,116,117,116,101,105,110,100,105,118,105,100,
+117,97,108,105,109,112,111,115,115,105,98,108,101,109,117,108,116,105,109,101,
+100,105,97,97,108,109,111,115,116,32,97,108,108,112,120,32,115,111,108,105,100,
+32,35,97,112,97,114,116,32,102,114,111,109,115,117,98,106,101,99,116,32,116,111,
+105,110,32,69,110,103,108,105,115,104,99,114,105,116,105,99,105,122,101,100,101,
+120,99,101,112,116,32,102,111,114,103,117,105,100,101,108,105,110,101,115,111,
+114,105,103,105,110,97,108,108,121,114,101,109,97,114,107,97,98,108,101,116,104,
+101,32,115,101,99,111,110,100,104,50,32,99,108,97,115,115,61,34,60,97,32,116,105
+,116,108,101,61,34,40,105,110,99,108,117,100,105,110,103,112,97,114,97,109,101,
+116,101,114,115,112,114,111,104,105,98,105,116,101,100,61,32,34,104,116,116,112,
+58,47,47,100,105,99,116,105,111,110,97,114,121,112,101,114,99,101,112,116,105,
+111,110,114,101,118,111,108,117,116,105,111,110,102,111,117,110,100,97,116,105,
+111,110,112,120,59,104,101,105,103,104,116,58,115,117,99,99,101,115,115,102,117,
+108,115,117,112,112,111,114,116,101,114,115,109,105,108,108,101,110,110,105,117,
+109,104,105,115,32,102,97,116,104,101,114,116,104,101,32,38,113,117,111,116,59,
+110,111,45,114,101,112,101,97,116,59,99,111,109,109,101,114,99,105,97,108,105,
+110,100,117,115,116,114,105,97,108,101,110,99,111,117,114,97,103,101,100,97,109,
+111,117,110,116,32,111,102,32,117,110,111,102,102,105,99,105,97,108,101,102,102,
+105,99,105,101,110,99,121,82,101,102,101,114,101,110,99,101,115,99,111,111,114,
+100,105,110,97,116,101,100,105,115,99,108,97,105,109,101,114,101,120,112,101,100
+,105,116,105,111,110,100,101,118,101,108,111,112,105,110,103,99,97,108,99,117,
+108,97,116,101,100,115,105,109,112,108,105,102,105,101,100,108,101,103,105,116,
+105,109,97,116,101,115,117,98,115,116,114,105,110,103,40,48,34,32,99,108,97,115,
+115,61,34,99,111,109,112,108,101,116,101,108,121,105,108,108,117,115,116,114,97,
+116,101,102,105,118,101,32,121,101,97,114,115,105,110,115,116,114,117,109,101,
+110,116,80,117,98,108,105,115,104,105,110,103,49,34,32,99,108,97,115,115,61,34,
+112,115,121,99,104,111,108,111,103,121,99,111,110,102,105,100,101,110,99,101,110
+,117,109,98,101,114,32,111,102,32,97,98,115,101,110,99,101,32,111,102,102,111,99
+,117,115,101,100,32,111,110,106,111,105,110,101,100,32,116,104,101,115,116,114,
+117,99,116,117,114,101,115,112,114,101,118,105,111,117,115,108,121,62,60,47,105,
+102,114,97,109,101,62,111,110,99,101,32,97,103,97,105,110,98,117,116,32,114,97,
+116,104,101,114,105,109,109,105,103,114,97,110,116,115,111,102,32,99,111,117,114
+,115,101,44,97,32,103,114,111,117,112,32,111,102,76,105,116,101,114,97,116,117,
+114,101,85,110,108,105,107,101,32,116,104,101,60,47,97,62,38,110,98,115,112,59,
+10,102,117,110,99,116,105,111,110,32,105,116,32,119,97,115,32,116,104,101,67,111
+,110,118,101,110,116,105,111,110,97,117,116,111,109,111,98,105,108,101,80,114,
+111,116,101,115,116,97,110,116,97,103,103,114,101,115,115,105,118,101,97,102,116
+,101,114,32,116,104,101,32,83,105,109,105,108,97,114,108,121,44,34,32,47,62,60,
+47,100,105,118,62,99,111,108,108,101,99,116,105,111,110,13,10,102,117,110,99,116
+,105,111,110,118,105,115,105,98,105,108,105,116,121,116,104,101,32,117,115,101,
+32,111,102,118,111,108,117,110,116,101,101,114,115,97,116,116,114,97,99,116,105,
+111,110,117,110,100,101,114,32,116,104,101,32,116,104,114,101,97,116,101,110,101
+,100,42,60,33,91,67,68,65,84,65,91,105,109,112,111,114,116,97,110,99,101,105,110
+,32,103,101,110,101,114,97,108,116,104,101,32,108,97,116,116,101,114,60,47,102,
+111,114,109,62,10,60,47,46,105,110,100,101,120,79,102,40,39,105,32,61,32,48,59,
+32,105,32,60,100,105,102,102,101,114,101,110,99,101,100,101,118,111,116,101,100,
+32,116,111,116,114,97,100,105,116,105,111,110,115,115,101,97,114,99,104,32,102,
+111,114,117,108,116,105,109,97,116,101,108,121,116,111,117,114,110,97,109,101,
+110,116,97,116,116,114,105,98,117,116,101,115,115,111,45,99,97,108,108,101,100,
+32,125,10,60,47,115,116,121,108,101,62,101,118,97,108,117,97,116,105,111,110,101
+,109,112,104,97,115,105,122,101,100,97,99,99,101,115,115,105,98,108,101,60,47,
+115,101,99,116,105,111,110,62,115,117,99,99,101,115,115,105,111,110,97,108,111,
+110,103,32,119,105,116,104,77,101,97,110,119,104,105,108,101,44,105,110,100,117,
+115,116,114,105,101,115,60,47,97,62,60,98,114,32,47,62,104,97,115,32,98,101,99,
+111,109,101,97,115,112,101,99,116,115,32,111,102,84,101,108,101,118,105,115,105,
+111,110,115,117,102,102,105,99,105,101,110,116,98,97,115,107,101,116,98,97,108,
+108,98,111,116,104,32,115,105,100,101,115,99,111,110,116,105,110,117,105,110,103
+,97,110,32,97,114,116,105,99,108,101,60,105,109,103,32,97,108,116,61,34,97,100,
+118,101,110,116,117,114,101,115,104,105,115,32,109,111,116,104,101,114,109,97,
+110,99,104,101,115,116,101,114,112,114,105,110,99,105,112,108,101,115,112,97,114
+,116,105,99,117,108,97,114,99,111,109,109,101,110,116,97,114,121,101,102,102,101
+,99,116,115,32,111,102,100,101,99,105,100,101,100,32,116,111,34,62,60,115,116,
+114,111,110,103,62,112,117,98,108,105,115,104,101,114,115,74,111,117,114,110,97,
+108,32,111,102,100,105,102,102,105,99,117,108,116,121,102,97,99,105,108,105,116,
+97,116,101,97,99,99,101,112,116,97,98,108,101,115,116,121,108,101,46,99,115,115,
+34,9,102,117,110,99,116,105,111,110,32,105,110,110,111,118,97,116,105,111,110,62
+,67,111,112,121,114,105,103,104,116,115,105,116,117,97,116,105,111,110,115,119,
+111,117,108,100,32,104,97,118,101,98,117,115,105,110,101,115,115,101,115,68,105,
+99,116,105,111,110,97,114,121,115,116,97,116,101,109,101,110,116,115,111,102,116
+,101,110,32,117,115,101,100,112,101,114,115,105,115,116,101,110,116,105,110,32,
+74,97,110,117,97,114,121,99,111,109,112,114,105,115,105,110,103,60,47,116,105,
+116,108,101,62,10,9,100,105,112,108,111,109,97,116,105,99,99,111,110,116,97,105,
+110,105,110,103,112,101,114,102,111,114,109,105,110,103,101,120,116,101,110,115,
+105,111,110,115,109,97,121,32,110,111,116,32,98,101,99,111,110,99,101,112,116,32
+,111,102,32,111,110,99,108,105,99,107,61,34,73,116,32,105,115,32,97,108,115,111,
+102,105,110,97,110,99,105,97,108,32,109,97,107,105,110,103,32,116,104,101,76,117
+,120,101,109,98,111,117,114,103,97,100,100,105,116,105,111,110,97,108,97,114,101
+,32,99,97,108,108,101,100,101,110,103,97,103,101,100,32,105,110,34,115,99,114,
+105,112,116,34,41,59,98,117,116,32,105,116,32,119,97,115,101,108,101,99,116,114,
+111,110,105,99,111,110,115,117,98,109,105,116,61,34,10,60,33,45,45,32,69,110,100
+,32,101,108,101,99,116,114,105,99,97,108,111,102,102,105,99,105,97,108,108,121,
+115,117,103,103,101,115,116,105,111,110,116,111,112,32,111,102,32,116,104,101,
+117,110,108,105,107,101,32,116,104,101,65,117,115,116,114,97,108,105,97,110,79,
+114,105,103,105,110,97,108,108,121,114,101,102,101,114,101,110,99,101,115,10,60,
+47,104,101,97,100,62,13,10,114,101,99,111,103,110,105,115,101,100,105,110,105,
+116,105,97,108,105,122,101,108,105,109,105,116,101,100,32,116,111,65,108,101,120
+,97,110,100,114,105,97,114,101,116,105,114,101,109,101,110,116,65,100,118,101,
+110,116,117,114,101,115,102,111,117,114,32,121,101,97,114,115,10,10,38,108,116,
+59,33,45,45,32,105,110,99,114,101,97,115,105,110,103,100,101,99,111,114,97,116,
+105,111,110,104,51,32,99,108,97,115,115,61,34,111,114,105,103,105,110,115,32,111
+,102,111,98,108,105,103,97,116,105,111,110,114,101,103,117,108,97,116,105,111,
+110,99,108,97,115,115,105,102,105,101,100,40,102,117,110,99,116,105,111,110,40,
+97,100,118,97,110,116,97,103,101,115,98,101,105,110,103,32,116,104,101,32,104,
+105,115,116,111,114,105,97,110,115,60,98,97,115,101,32,104,114,101,102,114,101,
+112,101,97,116,101,100,108,121,119,105,108,108,105,110,103,32,116,111,99,111,109
+,112,97,114,97,98,108,101,100,101,115,105,103,110,97,116,101,100,110,111,109,105
+,110,97,116,105,111,110,102,117,110,99,116,105,111,110,97,108,105,110,115,105,
+100,101,32,116,104,101,114,101,118,101,108,97,116,105,111,110,101,110,100,32,111
+,102,32,116,104,101,115,32,102,111,114,32,116,104,101,32,97,117,116,104,111,114,
+105,122,101,100,114,101,102,117,115,101,100,32,116,111,116,97,107,101,32,112,108
+,97,99,101,97,117,116,111,110,111,109,111,117,115,99,111,109,112,114,111,109,105
+,115,101,112,111,108,105,116,105,99,97,108,32,114,101,115,116,97,117,114,97,110,
+116,116,119,111,32,111,102,32,116,104,101,70,101,98,114,117,97,114,121,32,50,113
+,117,97,108,105,116,121,32,111,102,115,119,102,111,98,106,101,99,116,46,117,110,
+100,101,114,115,116,97,110,100,110,101,97,114,108,121,32,97,108,108,119,114,105,
+116,116,101,110,32,98,121,105,110,116,101,114,118,105,101,119,115,34,32,119,105,
+100,116,104,61,34,49,119,105,116,104,100,114,97,119,97,108,102,108,111,97,116,58
+,108,101,102,116,105,115,32,117,115,117,97,108,108,121,99,97,110,100,105,100,97,
+116,101,115,110,101,119,115,112,97,112,101,114,115,109,121,115,116,101,114,105,
+111,117,115,68,101,112,97,114,116,109,101,110,116,98,101,115,116,32,107,110,111,
+119,110,112,97,114,108,105,97,109,101,110,116,115,117,112,112,114,101,115,115,
+101,100,99,111,110,118,101,110,105,101,110,116,114,101,109,101,109,98,101,114,
+101,100,100,105,102,102,101,114,101,110,116,32,115,121,115,116,101,109,97,116,
+105,99,104,97,115,32,108,101,100,32,116,111,112,114,111,112,97,103,97,110,100,97
+,99,111,110,116,114,111,108,108,101,100,105,110,102,108,117,101,110,99,101,115,
+99,101,114,101,109,111,110,105,97,108,112,114,111,99,108,97,105,109,101,100,80,
+114,111,116,101,99,116,105,111,110,108,105,32,99,108,97,115,115,61,34,83,99,105,
+101,110,116,105,102,105,99,99,108,97,115,115,61,34,110,111,45,116,114,97,100,101
+,109,97,114,107,115,109,111,114,101,32,116,104,97,110,32,119,105,100,101,115,112
+,114,101,97,100,76,105,98,101,114,97,116,105,111,110,116,111,111,107,32,112,108,
+97,99,101,100,97,121,32,111,102,32,116,104,101,97,115,32,108,111,110,103,32,97,
+115,105,109,112,114,105,115,111,110,101,100,65,100,100,105,116,105,111,110,97,
+108,10,60,104,101,97,100,62,10,60,109,76,97,98,111,114,97,116,111,114,121,78,111
+,118,101,109,98,101,114,32,50,101,120,99,101,112,116,105,111,110,115,73,110,100,
+117,115,116,114,105,97,108,118,97,114,105,101,116,121,32,111,102,102,108,111,97,
+116,58,32,108,101,102,68,117,114,105,110,103,32,116,104,101,97,115,115,101,115,
+115,109,101,110,116,104,97,118,101,32,98,101,101,110,32,100,101,97,108,115,32,
+119,105,116,104,83,116,97,116,105,115,116,105,99,115,111,99,99,117,114,114,101,
+110,99,101,47,117,108,62,60,47,100,105,118,62,99,108,101,97,114,102,105,120,34,
+62,116,104,101,32,112,117,98,108,105,99,109,97,110,121,32,121,101,97,114,115,119
+,104,105,99,104,32,119,101,114,101,111,118,101,114,32,116,105,109,101,44,115,121
+,110,111,110,121,109,111,117,115,99,111,110,116,101,110,116,34,62,10,112,114,101
+,115,117,109,97,98,108,121,104,105,115,32,102,97,109,105,108,121,117,115,101,114
+,65,103,101,110,116,46,117,110,101,120,112,101,99,116,101,100,105,110,99,108,117
+,100,105,110,103,32,99,104,97,108,108,101,110,103,101,100,97,32,109,105,110,111,
+114,105,116,121,117,110,100,101,102,105,110,101,100,34,98,101,108,111,110,103,
+115,32,116,111,116,97,107,101,110,32,102,114,111,109,105,110,32,79,99,116,111,98
+,101,114,112,111,115,105,116,105,111,110,58,32,115,97,105,100,32,116,111,32,98,
+101,114,101,108,105,103,105,111,117,115,32,70,101,100,101,114,97,116,105,111,110
+,32,114,111,119,115,112,97,110,61,34,111,110,108,121,32,97,32,102,101,119,109,
+101,97,110,116,32,116,104,97,116,108,101,100,32,116,111,32,116,104,101,45,45,62,
+13,10,60,100,105,118,32,60,102,105,101,108,100,115,101,116,62,65,114,99,104,98,
+105,115,104,111,112,32,99,108,97,115,115,61,34,110,111,98,101,105,110,103,32,117
+,115,101,100,97,112,112,114,111,97,99,104,101,115,112,114,105,118,105,108,101,
+103,101,115,110,111,115,99,114,105,112,116,62,10,114,101,115,117,108,116,115,32,
+105,110,109,97,121,32,98,101,32,116,104,101,69,97,115,116,101,114,32,101,103,103
+,109,101,99,104,97,110,105,115,109,115,114,101,97,115,111,110,97,98,108,101,80,
+111,112,117,108,97,116,105,111,110,67,111,108,108,101,99,116,105,111,110,115,101
+,108,101,99,116,101,100,34,62,110,111,115,99,114,105,112,116,62,13,47,105,110,
+100,101,120,46,112,104,112,97,114,114,105,118,97,108,32,111,102,45,106,115,115,
+100,107,39,41,41,59,109,97,110,97,103,101,100,32,116,111,105,110,99,111,109,112,
+108,101,116,101,99,97,115,117,97,108,116,105,101,115,99,111,109,112,108,101,116,
+105,111,110,67,104,114,105,115,116,105,97,110,115,83,101,112,116,101,109,98,101,
+114,32,97,114,105,116,104,109,101,116,105,99,112,114,111,99,101,100,117,114,101,
+115,109,105,103,104,116,32,104,97,118,101,80,114,111,100,117,99,116,105,111,110,
+105,116,32,97,112,112,101,97,114,115,80,104,105,108,111,115,111,112,104,121,102,
+114,105,101,110,100,115,104,105,112,108,101,97,100,105,110,103,32,116,111,103,
+105,118,105,110,103,32,116,104,101,116,111,119,97,114,100,32,116,104,101,103,117
+,97,114,97,110,116,101,101,100,100,111,99,117,109,101,110,116,101,100,99,111,108
+,111,114,58,35,48,48,48,118,105,100,101,111,32,103,97,109,101,99,111,109,109,105
+,115,115,105,111,110,114,101,102,108,101,99,116,105,110,103,99,104,97,110,103,
+101,32,116,104,101,97,115,115,111,99,105,97,116,101,100,115,97,110,115,45,115,
+101,114,105,102,111,110,107,101,121,112,114,101,115,115,59,32,112,97,100,100,105
+,110,103,58,72,101,32,119,97,115,32,116,104,101,117,110,100,101,114,108,121,105,
+110,103,116,121,112,105,99,97,108,108,121,32,44,32,97,110,100,32,116,104,101,32,
+115,114,99,69,108,101,109,101,110,116,115,117,99,99,101,115,115,105,118,101,115,
+105,110,99,101,32,116,104,101,32,115,104,111,117,108,100,32,98,101,32,110,101,
+116,119,111,114,107,105,110,103,97,99,99,111,117,110,116,105,110,103,117,115,101
+,32,111,102,32,116,104,101,108,111,119,101,114,32,116,104,97,110,115,104,111,119
+,115,32,116,104,97,116,60,47,115,112,97,110,62,10,9,9,99,111,109,112,108,97,105,
+110,116,115,99,111,110,116,105,110,117,111,117,115,113,117,97,110,116,105,116,
+105,101,115,97,115,116,114,111,110,111,109,101,114,104,101,32,100,105,100,32,110
+,111,116,100,117,101,32,116,111,32,105,116,115,97,112,112,108,105,101,100,32,116
+,111,97,110,32,97,118,101,114,97,103,101,101,102,102,111,114,116,115,32,116,111,
+116,104,101,32,102,117,116,117,114,101,97,116,116,101,109,112,116,32,116,111,84,
+104,101,114,101,102,111,114,101,44,99,97,112,97,98,105,108,105,116,121,82,101,
+112,117,98,108,105,99,97,110,119,97,115,32,102,111,114,109,101,100,69,108,101,99
+,116,114,111,110,105,99,107,105,108,111,109,101,116,101,114,115,99,104,97,108,
+108,101,110,103,101,115,112,117,98,108,105,115,104,105,110,103,116,104,101,32,
+102,111,114,109,101,114,105,110,100,105,103,101,110,111,117,115,100,105,114,101,
+99,116,105,111,110,115,115,117,98,115,105,100,105,97,114,121,99,111,110,115,112,
+105,114,97,99,121,100,101,116,97,105,108,115,32,111,102,97,110,100,32,105,110,32
+,116,104,101,97,102,102,111,114,100,97,98,108,101,115,117,98,115,116,97,110,99,
+101,115,114,101,97,115,111,110,32,102,111,114,99,111,110,118,101,110,116,105,111
+,110,105,116,101,109,116,121,112,101,61,34,97,98,115,111,108,117,116,101,108,121
+,115,117,112,112,111,115,101,100,108,121,114,101,109,97,105,110,101,100,32,97,97
+,116,116,114,97,99,116,105,118,101,116,114,97,118,101,108,108,105,110,103,115,
+101,112,97,114,97,116,101,108,121,102,111,99,117,115,101,115,32,111,110,101,108,
+101,109,101,110,116,97,114,121,97,112,112,108,105,99,97,98,108,101,102,111,117,
+110,100,32,116,104,97,116,115,116,121,108,101,115,104,101,101,116,109,97,110,117
+,115,99,114,105,112,116,115,116,97,110,100,115,32,102,111,114,32,110,111,45,114,
+101,112,101,97,116,40,115,111,109,101,116,105,109,101,115,67,111,109,109,101,114
+,99,105,97,108,105,110,32,65,109,101,114,105,99,97,117,110,100,101,114,116,97,
+107,101,110,113,117,97,114,116,101,114,32,111,102,97,110,32,101,120,97,109,112,
+108,101,112,101,114,115,111,110,97,108,108,121,105,110,100,101,120,46,112,104,
+112,63,60,47,98,117,116,116,111,110,62,10,112,101,114,99,101,110,116,97,103,101,
+98,101,115,116,45,107,110,111,119,110,99,114,101,97,116,105,110,103,32,97,34,32,
+100,105,114,61,34,108,116,114,76,105,101,117,116,101,110,97,110,116,10,60,100,
+105,118,32,105,100,61,34,116,104,101,121,32,119,111,117,108,100,97,98,105,108,
+105,116,121,32,111,102,109,97,100,101,32,117,112,32,111,102,110,111,116,101,100,
+32,116,104,97,116,99,108,101,97,114,32,116,104,97,116,97,114,103,117,101,32,116,
+104,97,116,116,111,32,97,110,111,116,104,101,114,99,104,105,108,100,114,101,110,
+39,115,112,117,114,112,111,115,101,32,111,102,102,111,114,109,117,108,97,116,101
+,100,98,97,115,101,100,32,117,112,111,110,116,104,101,32,114,101,103,105,111,110
+,115,117,98,106,101,99,116,32,111,102,112,97,115,115,101,110,103,101,114,115,112
+,111,115,115,101,115,115,105,111,110,46,10,10,73,110,32,116,104,101,32,66,101,
+102,111,114,101,32,116,104,101,97,102,116,101,114,119,97,114,100,115,99,117,114,
+114,101,110,116,108,121,32,97,99,114,111,115,115,32,116,104,101,115,99,105,101,
+110,116,105,102,105,99,99,111,109,109,117,110,105,116,121,46,99,97,112,105,116,
+97,108,105,115,109,105,110,32,71,101,114,109,97,110,121,114,105,103,104,116,45,
+119,105,110,103,116,104,101,32,115,121,115,116,101,109,83,111,99,105,101,116,121
+,32,111,102,112,111,108,105,116,105,99,105,97,110,100,105,114,101,99,116,105,111
+,110,58,119,101,110,116,32,111,110,32,116,111,114,101,109,111,118,97,108,32,111,
+102,32,78,101,119,32,89,111,114,107,32,97,112,97,114,116,109,101,110,116,115,105
+,110,100,105,99,97,116,105,111,110,100,117,114,105,110,103,32,116,104,101,117,
+110,108,101,115,115,32,116,104,101,104,105,115,116,111,114,105,99,97,108,104,97,
+100,32,98,101,101,110,32,97,100,101,102,105,110,105,116,105,118,101,105,110,103,
+114,101,100,105,101,110,116,97,116,116,101,110,100,97,110,99,101,67,101,110,116,
+101,114,32,102,111,114,112,114,111,109,105,110,101,110,99,101,114,101,97,100,121
+,83,116,97,116,101,115,116,114,97,116,101,103,105,101,115,98,117,116,32,105,110,
+32,116,104,101,97,115,32,112,97,114,116,32,111,102,99,111,110,115,116,105,116,
+117,116,101,99,108,97,105,109,32,116,104,97,116,108,97,98,111,114,97,116,111,114
+,121,99,111,109,112,97,116,105,98,108,101,102,97,105,108,117,114,101,32,111,102,
+44,32,115,117,99,104,32,97,115,32,98,101,103,97,110,32,119,105,116,104,117,115,
+105,110,103,32,116,104,101,32,116,111,32,112,114,111,118,105,100,101,102,101,97,
+116,117,114,101,32,111,102,102,114,111,109,32,119,104,105,99,104,47,34,32,99,108
+,97,115,115,61,34,103,101,111,108,111,103,105,99,97,108,115,101,118,101,114,97,
+108,32,111,102,100,101,108,105,98,101,114,97,116,101,105,109,112,111,114,116,97,
+110,116,32,104,111,108,100,115,32,116,104,97,116,105,110,103,38,113,117,111,116,
+59,32,118,97,108,105,103,110,61,116,111,112,116,104,101,32,71,101,114,109,97,110
+,111,117,116,115,105,100,101,32,111,102,110,101,103,111,116,105,97,116,101,100,
+104,105,115,32,99,97,114,101,101,114,115,101,112,97,114,97,116,105,111,110,105,
+100,61,34,115,101,97,114,99,104,119,97,115,32,99,97,108,108,101,100,116,104,101,
+32,102,111,117,114,116,104,114,101,99,114,101,97,116,105,111,110,111,116,104,101
+,114,32,116,104,97,110,112,114,101,118,101,110,116,105,111,110,119,104,105,108,
+101,32,116,104,101,32,101,100,117,99,97,116,105,111,110,44,99,111,110,110,101,99
+,116,105,110,103,97,99,99,117,114,97,116,101,108,121,119,101,114,101,32,98,117,
+105,108,116,119,97,115,32,107,105,108,108,101,100,97,103,114,101,101,109,101,110
+,116,115,109,117,99,104,32,109,111,114,101,32,68,117,101,32,116,111,32,116,104,
+101,119,105,100,116,104,58,32,49,48,48,115,111,109,101,32,111,116,104,101,114,75
+,105,110,103,100,111,109,32,111,102,116,104,101,32,101,110,116,105,114,101,102,
+97,109,111,117,115,32,102,111,114,116,111,32,99,111,110,110,101,99,116,111,98,
+106,101,99,116,105,118,101,115,116,104,101,32,70,114,101,110,99,104,112,101,111,
+112,108,101,32,97,110,100,102,101,97,116,117,114,101,100,34,62,105,115,32,115,97
+,105,100,32,116,111,115,116,114,117,99,116,117,114,97,108,114,101,102,101,114,
+101,110,100,117,109,109,111,115,116,32,111,102,116,101,110,97,32,115,101,112,97,
+114,97,116,101,45,62,10,60,100,105,118,32,105,100,32,79,102,102,105,99,105,97,
+108,32,119,111,114,108,100,119,105,100,101,46,97,114,105,97,45,108,97,98,101,108
+,116,104,101,32,112,108,97,110,101,116,97,110,100,32,105,116,32,119,97,115,100,
+34,32,118,97,108,117,101,61,34,108,111,111,107,105,110,103,32,97,116,98,101,110,
+101,102,105,99,105,97,108,97,114,101,32,105,110,32,116,104,101,109,111,110,105,
+116,111,114,105,110,103,114,101,112,111,114,116,101,100,108,121,116,104,101,32,
+109,111,100,101,114,110,119,111,114,107,105,110,103,32,111,110,97,108,108,111,
+119,101,100,32,116,111,119,104,101,114,101,32,116,104,101,32,105,110,110,111,118
+,97,116,105,118,101,60,47,97,62,60,47,100,105,118,62,115,111,117,110,100,116,114
+,97,99,107,115,101,97,114,99,104,70,111,114,109,116,101,110,100,32,116,111,32,98
+,101,105,110,112,117,116,32,105,100,61,34,111,112,101,110,105,110,103,32,111,102
+,114,101,115,116,114,105,99,116,101,100,97,100,111,112,116,101,100,32,98,121,97,
+100,100,114,101,115,115,105,110,103,116,104,101,111,108,111,103,105,97,110,109,
+101,116,104,111,100,115,32,111,102,118,97,114,105,97,110,116,32,111,102,67,104,
+114,105,115,116,105,97,110,32,118,101,114,121,32,108,97,114,103,101,97,117,116,
+111,109,111,116,105,118,101,98,121,32,102,97,114,32,116,104,101,114,97,110,103,
+101,32,102,114,111,109,112,117,114,115,117,105,116,32,111,102,102,111,108,108,
+111,119,32,116,104,101,98,114,111,117,103,104,116,32,116,111,105,110,32,69,110,
+103,108,97,110,100,97,103,114,101,101,32,116,104,97,116,97,99,99,117,115,101,100
+,32,111,102,99,111,109,101,115,32,102,114,111,109,112,114,101,118,101,110,116,
+105,110,103,100,105,118,32,115,116,121,108,101,61,104,105,115,32,111,114,32,104,
+101,114,116,114,101,109,101,110,100,111,117,115,102,114,101,101,100,111,109,32,
+111,102,99,111,110,99,101,114,110,105,110,103,48,32,49,101,109,32,49,101,109,59,
+66,97,115,107,101,116,98,97,108,108,47,115,116,121,108,101,46,99,115,115,97,110,
+32,101,97,114,108,105,101,114,101,118,101,110,32,97,102,116,101,114,47,34,32,116
+,105,116,108,101,61,34,46,99,111,109,47,105,110,100,101,120,116,97,107,105,110,
+103,32,116,104,101,112,105,116,116,115,98,117,114,103,104,99,111,110,116,101,110
+,116,34,62,13,60,115,99,114,105,112,116,62,40,102,116,117,114,110,101,100,32,111
+,117,116,104,97,118,105,110,103,32,116,104,101,60,47,115,112,97,110,62,13,10,32,
+111,99,99,97,115,105,111,110,97,108,98,101,99,97,117,115,101,32,105,116,115,116,
+97,114,116,101,100,32,116,111,112,104,121,115,105,99,97,108,108,121,62,60,47,100
+,105,118,62,10,32,32,99,114,101,97,116,101,100,32,98,121,67,117,114,114,101,110,
+116,108,121,44,32,98,103,99,111,108,111,114,61,34,116,97,98,105,110,100,101,120,
+61,34,100,105,115,97,115,116,114,111,117,115,65,110,97,108,121,116,105,99,115,32
+,97,108,115,111,32,104,97,115,32,97,62,60,100,105,118,32,105,100,61,34,60,47,115
+,116,121,108,101,62,10,60,99,97,108,108,101,100,32,102,111,114,115,105,110,103,
+101,114,32,97,110,100,46,115,114,99,32,61,32,34,47,47,118,105,111,108,97,116,105
+,111,110,115,116,104,105,115,32,112,111,105,110,116,99,111,110,115,116,97,110,
+116,108,121,105,115,32,108,111,99,97,116,101,100,114,101,99,111,114,100,105,110,
+103,115,100,32,102,114,111,109,32,116,104,101,110,101,100,101,114,108,97,110,100
+,115,112,111,114,116,117,103,117,195,170,115,215,162,215,145,215,168,215,153,215
+,170,217,129,216,167,216,177,216,179,219,140,100,101,115,97,114,114,111,108,108,
+111,99,111,109,101,110,116,97,114,105,111,101,100,117,99,97,99,105,195,179,110,
+115,101,112,116,105,101,109,98,114,101,114,101,103,105,115,116,114,97,100,111,
+100,105,114,101,99,99,105,195,179,110,117,98,105,99,97,99,105,195,179,110,112,
+117,98,108,105,99,105,100,97,100,114,101,115,112,117,101,115,116,97,115,114,101,
+115,117,108,116,97,100,111,115,105,109,112,111,114,116,97,110,116,101,114,101,
+115,101,114,118,97,100,111,115,97,114,116,195,173,99,117,108,111,115,100,105,102
+,101,114,101,110,116,101,115,115,105,103,117,105,101,110,116,101,115,114,101,112
+,195,186,98,108,105,99,97,115,105,116,117,97,99,105,195,179,110,109,105,110,105,
+115,116,101,114,105,111,112,114,105,118,97,99,105,100,97,100,100,105,114,101,99,
+116,111,114,105,111,102,111,114,109,97,99,105,195,179,110,112,111,98,108,97,99,
+105,195,179,110,112,114,101,115,105,100,101,110,116,101,99,111,110,116,101,110,
+105,100,111,115,97,99,99,101,115,111,114,105,111,115,116,101,99,104,110,111,114,
+97,116,105,112,101,114,115,111,110,97,108,101,115,99,97,116,101,103,111,114,195,
+173,97,101,115,112,101,99,105,97,108,101,115,100,105,115,112,111,110,105,98,108,
+101,97,99,116,117,97,108,105,100,97,100,114,101,102,101,114,101,110,99,105,97,
+118,97,108,108,97,100,111,108,105,100,98,105,98,108,105,111,116,101,99,97,114,
+101,108,97,99,105,111,110,101,115,99,97,108,101,110,100,97,114,105,111,112,111,
+108,195,173,116,105,99,97,115,97,110,116,101,114,105,111,114,101,115,100,111,99,
+117,109,101,110,116,111,115,110,97,116,117,114,97,108,101,122,97,109,97,116,101,
+114,105,97,108,101,115,100,105,102,101,114,101,110,99,105,97,101,99,111,110,195,
+179,109,105,99,97,116,114,97,110,115,112,111,114,116,101,114,111,100,114,195,173
+,103,117,101,122,112,97,114,116,105,99,105,112,97,114,101,110,99,117,101,110,116
+,114,97,110,100,105,115,99,117,115,105,195,179,110,101,115,116,114,117,99,116,
+117,114,97,102,117,110,100,97,99,105,195,179,110,102,114,101,99,117,101,110,116,
+101,115,112,101,114,109,97,110,101,110,116,101,116,111,116,97,108,109,101,110,
+116,101,208,188,208,190,208,182,208,189,208,190,208,177,209,131,208,180,208,181,
+209,130,208,188,208,190,208,182,208,181,209,130,208,178,209,128,208,181,208,188,
+209,143,209,130,208,176,208,186,208,182,208,181,209,135,209,130,208,190,208,177,
+209,139,208,177,208,190,208,187,208,181,208,181,208,190,209,135,208,181,208,189,
+209,140,209,141,209,130,208,190,208,179,208,190,208,186,208,190,208,179,208,180,
+208,176,208,191,208,190,209,129,208,187,208,181,208,178,209,129,208,181,208,179,
+208,190,209,129,208,176,208,185,209,130,208,181,209,135,208,181,209,128,208,181,
+208,183,208,188,208,190,208,179,209,131,209,130,209,129,208,176,208,185,209,130,
+208,176,208,182,208,184,208,183,208,189,208,184,208,188,208,181,208,182,208,180,
+209,131,208,177,209,131,208,180,209,131,209,130,208,159,208,190,208,184,209,129,
+208,186,208,183,208,180,208,181,209,129,209,140,208,178,208,184,208,180,208,181,
+208,190,209,129,208,178,209,143,208,183,208,184,208,189,209,131,208,182,208,189,
+208,190,209,129,208,178,208,190,208,181,208,185,208,187,209,142,208,180,208,181,
+208,185,208,191,208,190,209,128,208,189,208,190,208,188,208,189,208,190,208,179,
+208,190,208,180,208,181,209,130,208,181,208,185,209,129,208,178,208,190,208,184,
+209,133,208,191,209,128,208,176,208,178,208,176,209,130,208,176,208,186,208,190,
+208,185,208,188,208,181,209,129,209,130,208,190,208,184,208,188,208,181,208,181,
+209,130,208,182,208,184,208,183,208,189,209,140,208,190,208,180,208,189,208,190,
+208,185,208,187,209,131,209,135,209,136,208,181,208,191,208,181,209,128,208,181,
+208,180,209,135,208,176,209,129,209,130,208,184,209,135,208,176,209,129,209,130,
+209,140,209,128,208,176,208,177,208,190,209,130,208,189,208,190,208,178,209,139,
+209,133,208,191,209,128,208,176,208,178,208,190,209,129,208,190,208,177,208,190,
+208,185,208,191,208,190,209,130,208,190,208,188,208,188,208,181,208,189,208,181,
+208,181,209,135,208,184,209,129,208,187,208,181,208,189,208,190,208,178,209,139,
+208,181,209,131,209,129,208,187,209,131,208,179,208,190,208,186,208,190,208,187,
+208,190,208,189,208,176,208,183,208,176,208,180,209,130,208,176,208,186,208,190,
+208,181,209,130,208,190,208,179,208,180,208,176,208,191,208,190,209,135,209,130,
+208,184,208,159,208,190,209,129,208,187,208,181,209,130,208,176,208,186,208,184,
+208,181,208,189,208,190,208,178,209,139,208,185,209,129,209,130,208,190,208,184,
+209,130,209,130,208,176,208,186,208,184,209,133,209,129,209,128,208,176,208,183,
+209,131,208,161,208,176,208,189,208,186,209,130,209,132,208,190,209,128,209,131,
+208,188,208,154,208,190,208,179,208,180,208,176,208,186,208,189,208,184,208,179,
+208,184,209,129,208,187,208,190,208,178,208,176,208,189,208,176,209,136,208,181,
+208,185,208,189,208,176,208,185,209,130,208,184,209,129,208,178,208,190,208,184,
+208,188,209,129,208,178,209,143,208,183,209,140,208,187,209,142,208,177,208,190,
+208,185,209,135,208,176,209,129,209,130,208,190,209,129,209,128,208,181,208,180,
+208,184,208,154,209,128,208,190,208,188,208,181,208,164,208,190,209,128,209,131,
+208,188,209,128,209,139,208,189,208,186,208,181,209,129,209,130,208,176,208,187,
+208,184,208,191,208,190,208,184,209,129,208,186,209,130,209,139,209,129,209,143,
+209,135,208,188,208,181,209,129,209,143,209,134,209,134,208,181,208,189,209,130,
+209,128,209,130,209,128,209,131,208,180,208,176,209,129,208,176,208,188,209,139,
+209,133,209,128,209,139,208,189,208,186,208,176,208,157,208,190,208,178,209,139,
+208,185,209,135,208,176,209,129,208,190,208,178,208,188,208,181,209,129,209,130,
+208,176,209,132,208,184,208,187,209,140,208,188,208,188,208,176,209,128,209,130,
+208,176,209,129,209,130,209,128,208,176,208,189,208,188,208,181,209,129,209,130,
+208,181,209,130,208,181,208,186,209,129,209,130,208,189,208,176,209,136,208,184,
+209,133,208,188,208,184,208,189,209,131,209,130,208,184,208,188,208,181,208,189,
+208,184,208,184,208,188,208,181,209,142,209,130,208,189,208,190,208,188,208,181,
+209,128,208,179,208,190,209,128,208,190,208,180,209,129,208,176,208,188,208,190,
+208,188,209,141,209,130,208,190,208,188,209,131,208,186,208,190,208,189,209,134,
+208,181,209,129,208,178,208,190,208,181,208,188,208,186,208,176,208,186,208,190,
+208,185,208,144,209,128,209,133,208,184,208,178,217,133,217,134,216,170,216,175,
+217,137,216,165,216,177,216,179,216,167,217,132,216,177,216,179,216,167,217,132,
+216,169,216,167,217,132,216,185,216,167,217,133,217,131,216,170,216,168,217,135,
+216,167,216,168,216,177,216,167,217,133,216,172,216,167,217,132,217,138,217,136,
+217,133,216,167,217,132,216,181,217,136,216,177,216,172,216,175,217,138,216,175,
+216,169,216,167,217,132,216,185,216,182,217,136,216,165,216,182,216,167,217,129,
+216,169,216,167,217,132,217,130,216,179,217,133,216,167,217,132,216,185,216,167,
+216,168,216,170,216,173,217,133,217,138,217,132,217,133,217,132,217,129,216,167,
+216,170,217,133,217,132,216,170,217,130,217,137,216,170,216,185,216,175,217,138,
+217,132,216,167,217,132,216,180,216,185,216,177,216,163,216,174,216,168,216,167,
+216,177,216,170,216,183,217,136,217,138,216,177,216,185,217,132,217,138,217,131,
+217,133,216,165,216,177,217,129,216,167,217,130,216,183,217,132,216,168,216,167,
+216,170,216,167,217,132,217,132,216,186,216,169,216,170,216,177,216,170,217,138,
+216,168,216,167,217,132,217,134,216,167,216,179,216,167,217,132,216,180,217,138,
+216,174,217,133,217,134,216,170,216,175,217,138,216,167,217,132,216,185,216,177,
+216,168,216,167,217,132,217,130,216,181,216,181,216,167,217,129,217,132,216,167,
+217,133,216,185,217,132,217,138,217,135,216,167,216,170,216,173,216,175,217,138,
+216,171,216,167,217,132,217,132,217,135,217,133,216,167,217,132,216,185,217,133,
+217,132,217,133,217,131,216,170,216,168,216,169,217,138,217,133,217,131,217,134,
+217,131,216,167,217,132,216,183,217,129,217,132,217,129,217,138,216,175,217,138,
+217,136,216,165,216,175,216,167,216,177,216,169,216,170,216,167,216,177,217,138,
+216,174,216,167,217,132,216,181,216,173,216,169,216,170,216,179,216,172,217,138,
+217,132,216,167,217,132,217,136,217,130,216,170,216,185,217,134,216,175,217,133,
+216,167,217,133,216,175,217,138,217,134,216,169,216,170,216,181,217,133,217,138,
+217,133,216,163,216,177,216,180,217,138,217,129,216,167,217,132,216,176,217,138,
+217,134,216,185,216,177,216,168,217,138,216,169,216,168,217,136,216,167,216,168,
+216,169,216,163,217,132,216,185,216,167,216,168,216,167,217,132,216,179,217,129,
+216,177,217,133,216,180,216,167,217,131,217,132,216,170,216,185,216,167,217,132,
+217,137,216,167,217,132,216,163,217,136,217,132,216,167,217,132,216,179,217,134,
+216,169,216,172,216,167,217,133,216,185,216,169,216,167,217,132,216,181,216,173,
+217,129,216,167,217,132,216,175,217,138,217,134,217,131,217,132,217,133,216,167,
+216,170,216,167,217,132,216,174,216,167,216,181,216,167,217,132,217,133,217,132,
+217,129,216,163,216,185,216,182,216,167,216,161,217,131,216,170,216,167,216,168,
+216,169,216,167,217,132,216,174,217,138,216,177,216,177,216,179,216,167,216,166,
+217,132,216,167,217,132,217,130,217,132,216,168,216,167,217,132,216,163,216,175,
+216,168,217,133,217,130,216,167,216,183,216,185,217,133,216,177,216,167,216,179,
+217,132,217,133,217,134,216,183,217,130,216,169,216,167,217,132,217,131,216,170,
+216,168,216,167,217,132,216,177,216,172,217,132,216,167,216,180,216,170,216,177,
+217,131,216,167,217,132,217,130,216,175,217,133,217,138,216,185,216,183,217,138,
+217,131,115,66,121,84,97,103,78,97,109,101,40,46,106,112,103,34,32,97,108,116,61
+,34,49,112,120,32,115,111,108,105,100,32,35,46,103,105,102,34,32,97,108,116,61,
+34,116,114,97,110,115,112,97,114,101,110,116,105,110,102,111,114,109,97,116,105,
+111,110,97,112,112,108,105,99,97,116,105,111,110,34,32,111,110,99,108,105,99,107
+,61,34,101,115,116,97,98,108,105,115,104,101,100,97,100,118,101,114,116,105,115,
+105,110,103,46,112,110,103,34,32,97,108,116,61,34,101,110,118,105,114,111,110,
+109,101,110,116,112,101,114,102,111,114,109,97,110,99,101,97,112,112,114,111,112
+,114,105,97,116,101,38,97,109,112,59,109,100,97,115,104,59,105,109,109,101,100,
+105,97,116,101,108,121,60,47,115,116,114,111,110,103,62,60,47,114,97,116,104,101
+,114,32,116,104,97,110,116,101,109,112,101,114,97,116,117,114,101,100,101,118,
+101,108,111,112,109,101,110,116,99,111,109,112,101,116,105,116,105,111,110,112,
+108,97,99,101,104,111,108,100,101,114,118,105,115,105,98,105,108,105,116,121,58,
+99,111,112,121,114,105,103,104,116,34,62,48,34,32,104,101,105,103,104,116,61,34,
+101,118,101,110,32,116,104,111,117,103,104,114,101,112,108,97,99,101,109,101,110
+,116,100,101,115,116,105,110,97,116,105,111,110,67,111,114,112,111,114,97,116,
+105,111,110,60,117,108,32,99,108,97,115,115,61,34,65,115,115,111,99,105,97,116,
+105,111,110,105,110,100,105,118,105,100,117,97,108,115,112,101,114,115,112,101,
+99,116,105,118,101,115,101,116,84,105,109,101,111,117,116,40,117,114,108,40,104,
+116,116,112,58,47,47,109,97,116,104,101,109,97,116,105,99,115,109,97,114,103,105
+,110,45,116,111,112,58,101,118,101,110,116,117,97,108,108,121,32,100,101,115,99,
+114,105,112,116,105,111,110,41,32,110,111,45,114,101,112,101,97,116,99,111,108,
+108,101,99,116,105,111,110,115,46,74,80,71,124,116,104,117,109,98,124,112,97,114
+,116,105,99,105,112,97,116,101,47,104,101,97,100,62,60,98,111,100,121,102,108,
+111,97,116,58,108,101,102,116,59,60,108,105,32,99,108,97,115,115,61,34,104,117,
+110,100,114,101,100,115,32,111,102,10,10,72,111,119,101,118,101,114,44,32,99,111
+,109,112,111,115,105,116,105,111,110,99,108,101,97,114,58,98,111,116,104,59,99,
+111,111,112,101,114,97,116,105,111,110,119,105,116,104,105,110,32,116,104,101,32
+,108,97,98,101,108,32,102,111,114,61,34,98,111,114,100,101,114,45,116,111,112,58
+,78,101,119,32,90,101,97,108,97,110,100,114,101,99,111,109,109,101,110,100,101,
+100,112,104,111,116,111,103,114,97,112,104,121,105,110,116,101,114,101,115,116,
+105,110,103,38,108,116,59,115,117,112,38,103,116,59,99,111,110,116,114,111,118,
+101,114,115,121,78,101,116,104,101,114,108,97,110,100,115,97,108,116,101,114,110
+,97,116,105,118,101,109,97,120,108,101,110,103,116,104,61,34,115,119,105,116,122
+,101,114,108,97,110,100,68,101,118,101,108,111,112,109,101,110,116,101,115,115,
+101,110,116,105,97,108,108,121,10,10,65,108,116,104,111,117,103,104,32,60,47,116
+,101,120,116,97,114,101,97,62,116,104,117,110,100,101,114,98,105,114,100,114,101
+,112,114,101,115,101,110,116,101,100,38,97,109,112,59,110,100,97,115,104,59,115,
+112,101,99,117,108,97,116,105,111,110,99,111,109,109,117,110,105,116,105,101,115
+,108,101,103,105,115,108,97,116,105,111,110,101,108,101,99,116,114,111,110,105,
+99,115,10,9,60,100,105,118,32,105,100,61,34,105,108,108,117,115,116,114,97,116,
+101,100,101,110,103,105,110,101,101,114,105,110,103,116,101,114,114,105,116,111,
+114,105,101,115,97,117,116,104,111,114,105,116,105,101,115,100,105,115,116,114,
+105,98,117,116,101,100,54,34,32,104,101,105,103,104,116,61,34,115,97,110,115,45,
+115,101,114,105,102,59,99,97,112,97,98,108,101,32,111,102,32,100,105,115,97,112,
+112,101,97,114,101,100,105,110,116,101,114,97,99,116,105,118,101,108,111,111,107
+,105,110,103,32,102,111,114,105,116,32,119,111,117,108,100,32,98,101,65,102,103,
+104,97,110,105,115,116,97,110,119,97,115,32,99,114,101,97,116,101,100,77,97,116,
+104,46,102,108,111,111,114,40,115,117,114,114,111,117,110,100,105,110,103,99,97,
+110,32,97,108,115,111,32,98,101,111,98,115,101,114,118,97,116,105,111,110,109,97
+,105,110,116,101,110,97,110,99,101,101,110,99,111,117,110,116,101,114,101,100,60
+,104,50,32,99,108,97,115,115,61,34,109,111,114,101,32,114,101,99,101,110,116,105
+,116,32,104,97,115,32,98,101,101,110,105,110,118,97,115,105,111,110,32,111,102,
+41,46,103,101,116,84,105,109,101,40,41,102,117,110,100,97,109,101,110,116,97,108
+,68,101,115,112,105,116,101,32,116,104,101,34,62,60,100,105,118,32,105,100,61,34
+,105,110,115,112,105,114,97,116,105,111,110,101,120,97,109,105,110,97,116,105,
+111,110,112,114,101,112,97,114,97,116,105,111,110,101,120,112,108,97,110,97,116,
+105,111,110,60,105,110,112,117,116,32,105,100,61,34,60,47,97,62,60,47,115,112,97
+,110,62,118,101,114,115,105,111,110,115,32,111,102,105,110,115,116,114,117,109,
+101,110,116,115,98,101,102,111,114,101,32,116,104,101,32,32,61,32,39,104,116,116
+,112,58,47,47,68,101,115,99,114,105,112,116,105,111,110,114,101,108,97,116,105,
+118,101,108,121,32,46,115,117,98,115,116,114,105,110,103,40,101,97,99,104,32,111
+,102,32,116,104,101,101,120,112,101,114,105,109,101,110,116,115,105,110,102,108,
+117,101,110,116,105,97,108,105,110,116,101,103,114,97,116,105,111,110,109,97,110
+,121,32,112,101,111,112,108,101,100,117,101,32,116,111,32,116,104,101,32,99,111,
+109,98,105,110,97,116,105,111,110,100,111,32,110,111,116,32,104,97,118,101,77,
+105,100,100,108,101,32,69,97,115,116,60,110,111,115,99,114,105,112,116,62,60,99,
+111,112,121,114,105,103,104,116,34,32,112,101,114,104,97,112,115,32,116,104,101,
+105,110,115,116,105,116,117,116,105,111,110,105,110,32,68,101,99,101,109,98,101,
+114,97,114,114,97,110,103,101,109,101,110,116,109,111,115,116,32,102,97,109,111,
+117,115,112,101,114,115,111,110,97,108,105,116,121,99,114,101,97,116,105,111,110
+,32,111,102,108,105,109,105,116,97,116,105,111,110,115,101,120,99,108,117,115,
+105,118,101,108,121,115,111,118,101,114,101,105,103,110,116,121,45,99,111,110,
+116,101,110,116,34,62,10,60,116,100,32,99,108,97,115,115,61,34,117,110,100,101,
+114,103,114,111,117,110,100,112,97,114,97,108,108,101,108,32,116,111,100,111,99,
+116,114,105,110,101,32,111,102,111,99,99,117,112,105,101,100,32,98,121,116,101,
+114,109,105,110,111,108,111,103,121,82,101,110,97,105,115,115,97,110,99,101,97,
+32,110,117,109,98,101,114,32,111,102,115,117,112,112,111,114,116,32,102,111,114,
+101,120,112,108,111,114,97,116,105,111,110,114,101,99,111,103,110,105,116,105,
+111,110,112,114,101,100,101,99,101,115,115,111,114,60,105,109,103,32,115,114,99,
+61,34,47,60,104,49,32,99,108,97,115,115,61,34,112,117,98,108,105,99,97,116,105,
+111,110,109,97,121,32,97,108,115,111,32,98,101,115,112,101,99,105,97,108,105,122
+,101,100,60,47,102,105,101,108,100,115,101,116,62,112,114,111,103,114,101,115,
+115,105,118,101,109,105,108,108,105,111,110,115,32,111,102,115,116,97,116,101,
+115,32,116,104,97,116,101,110,102,111,114,99,101,109,101,110,116,97,114,111,117,
+110,100,32,116,104,101,32,111,110,101,32,97,110,111,116,104,101,114,46,112,97,
+114,101,110,116,78,111,100,101,97,103,114,105,99,117,108,116,117,114,101,65,108,
+116,101,114,110,97,116,105,118,101,114,101,115,101,97,114,99,104,101,114,115,116
+,111,119,97,114,100,115,32,116,104,101,77,111,115,116,32,111,102,32,116,104,101,
+109,97,110,121,32,111,116,104,101,114,32,40,101,115,112,101,99,105,97,108,108,
+121,60,116,100,32,119,105,100,116,104,61,34,59,119,105,100,116,104,58,49,48,48,
+37,105,110,100,101,112,101,110,100,101,110,116,60,104,51,32,99,108,97,115,115,61
+,34,32,111,110,99,104,97,110,103,101,61,34,41,46,97,100,100,67,108,97,115,115,40
+,105,110,116,101,114,97,99,116,105,111,110,79,110,101,32,111,102,32,116,104,101,
+32,100,97,117,103,104,116,101,114,32,111,102,97,99,99,101,115,115,111,114,105,
+101,115,98,114,97,110,99,104,101,115,32,111,102,13,10,60,100,105,118,32,105,100,
+61,34,116,104,101,32,108,97,114,103,101,115,116,100,101,99,108,97,114,97,116,105
+,111,110,114,101,103,117,108,97,116,105,111,110,115,73,110,102,111,114,109,97,
+116,105,111,110,116,114,97,110,115,108,97,116,105,111,110,100,111,99,117,109,101
+,110,116,97,114,121,105,110,32,111,114,100,101,114,32,116,111,34,62,10,60,104,
+101,97,100,62,10,60,34,32,104,101,105,103,104,116,61,34,49,97,99,114,111,115,115
+,32,116,104,101,32,111,114,105,101,110,116,97,116,105,111,110,41,59,60,47,115,99
+,114,105,112,116,62,105,109,112,108,101,109,101,110,116,101,100,99,97,110,32,98,
+101,32,115,101,101,110,116,104,101,114,101,32,119,97,115,32,97,100,101,109,111,
+110,115,116,114,97,116,101,99,111,110,116,97,105,110,101,114,34,62,99,111,110,
+110,101,99,116,105,111,110,115,116,104,101,32,66,114,105,116,105,115,104,119,97,
+115,32,119,114,105,116,116,101,110,33,105,109,112,111,114,116,97,110,116,59,112,
+120,59,32,109,97,114,103,105,110,45,102,111,108,108,111,119,101,100,32,98,121,97
+,98,105,108,105,116,121,32,116,111,32,99,111,109,112,108,105,99,97,116,101,100,
+100,117,114,105,110,103,32,116,104,101,32,105,109,109,105,103,114,97,116,105,111
+,110,97,108,115,111,32,99,97,108,108,101,100,60,104,52,32,99,108,97,115,115,61,
+34,100,105,115,116,105,110,99,116,105,111,110,114,101,112,108,97,99,101,100,32,
+98,121,103,111,118,101,114,110,109,101,110,116,115,108,111,99,97,116,105,111,110
+,32,111,102,105,110,32,78,111,118,101,109,98,101,114,119,104,101,116,104,101,114
+,32,116,104,101,60,47,112,62,10,60,47,100,105,118,62,97,99,113,117,105,115,105,
+116,105,111,110,99,97,108,108,101,100,32,116,104,101,32,112,101,114,115,101,99,
+117,116,105,111,110,100,101,115,105,103,110,97,116,105,111,110,123,102,111,110,
+116,45,115,105,122,101,58,97,112,112,101,97,114,101,100,32,105,110,105,110,118,
+101,115,116,105,103,97,116,101,101,120,112,101,114,105,101,110,99,101,100,109,
+111,115,116,32,108,105,107,101,108,121,119,105,100,101,108,121,32,117,115,101,
+100,100,105,115,99,117,115,115,105,111,110,115,112,114,101,115,101,110,99,101,32
+,111,102,32,40,100,111,99,117,109,101,110,116,46,101,120,116,101,110,115,105,118
+,101,108,121,73,116,32,104,97,115,32,98,101,101,110,105,116,32,100,111,101,115,
+32,110,111,116,99,111,110,116,114,97,114,121,32,116,111,105,110,104,97,98,105,
+116,97,110,116,115,105,109,112,114,111,118,101,109,101,110,116,115,99,104,111,
+108,97,114,115,104,105,112,99,111,110,115,117,109,112,116,105,111,110,105,110,
+115,116,114,117,99,116,105,111,110,102,111,114,32,101,120,97,109,112,108,101,111
+,110,101,32,111,114,32,109,111,114,101,112,120,59,32,112,97,100,100,105,110,103,
+116,104,101,32,99,117,114,114,101,110,116,97,32,115,101,114,105,101,115,32,111,
+102,97,114,101,32,117,115,117,97,108,108,121,114,111,108,101,32,105,110,32,116,
+104,101,112,114,101,118,105,111,117,115,108,121,32,100,101,114,105,118,97,116,
+105,118,101,115,101,118,105,100,101,110,99,101,32,111,102,101,120,112,101,114,
+105,101,110,99,101,115,99,111,108,111,114,115,99,104,101,109,101,115,116,97,116,
+101,100,32,116,104,97,116,99,101,114,116,105,102,105,99,97,116,101,60,47,97,62,
+60,47,100,105,118,62,10,32,115,101,108,101,99,116,101,100,61,34,104,105,103,104,
+32,115,99,104,111,111,108,114,101,115,112,111,110,115,101,32,116,111,99,111,109,
+102,111,114,116,97,98,108,101,97,100,111,112,116,105,111,110,32,111,102,116,104,
+114,101,101,32,121,101,97,114,115,116,104,101,32,99,111,117,110,116,114,121,105,
+110,32,70,101,98,114,117,97,114,121,115,111,32,116,104,97,116,32,116,104,101,112
+,101,111,112,108,101,32,119,104,111,32,112,114,111,118,105,100,101,100,32,98,121
+,60,112,97,114,97,109,32,110,97,109,101,97,102,102,101,99,116,101,100,32,98,121,
+105,110,32,116,101,114,109,115,32,111,102,97,112,112,111,105,110,116,109,101,110
+,116,73,83,79,45,56,56,53,57,45,49,34,119,97,115,32,98,111,114,110,32,105,110,
+104,105,115,116,111,114,105,99,97,108,32,114,101,103,97,114,100,101,100,32,97,
+115,109,101,97,115,117,114,101,109,101,110,116,105,115,32,98,97,115,101,100,32,
+111,110,32,97,110,100,32,111,116,104,101,114,32,58,32,102,117,110,99,116,105,111
+,110,40,115,105,103,110,105,102,105,99,97,110,116,99,101,108,101,98,114,97,116,
+105,111,110,116,114,97,110,115,109,105,116,116,101,100,47,106,115,47,106,113,117
+,101,114,121,46,105,115,32,107,110,111,119,110,32,97,115,116,104,101,111,114,101
+,116,105,99,97,108,32,116,97,98,105,110,100,101,120,61,34,105,116,32,99,111,117,
+108,100,32,98,101,60,110,111,115,99,114,105,112,116,62,10,104,97,118,105,110,103
+,32,98,101,101,110,13,10,60,104,101,97,100,62,13,10,60,32,38,113,117,111,116,59,
+84,104,101,32,99,111,109,112,105,108,97,116,105,111,110,104,101,32,104,97,100,32
+,98,101,101,110,112,114,111,100,117,99,101,100,32,98,121,112,104,105,108,111,115
+,111,112,104,101,114,99,111,110,115,116,114,117,99,116,101,100,105,110,116,101,
+110,100,101,100,32,116,111,97,109,111,110,103,32,111,116,104,101,114,99,111,109,
+112,97,114,101,100,32,116,111,116,111,32,115,97,121,32,116,104,97,116,69,110,103
+,105,110,101,101,114,105,110,103,97,32,100,105,102,102,101,114,101,110,116,114,
+101,102,101,114,114,101,100,32,116,111,100,105,102,102,101,114,101,110,99,101,
+115,98,101,108,105,101,102,32,116,104,97,116,112,104,111,116,111,103,114,97,112,
+104,115,105,100,101,110,116,105,102,121,105,110,103,72,105,115,116,111,114,121,
+32,111,102,32,82,101,112,117,98,108,105,99,32,111,102,110,101,99,101,115,115,97,
+114,105,108,121,112,114,111,98,97,98,105,108,105,116,121,116,101,99,104,110,105,
+99,97,108,108,121,108,101,97,118,105,110,103,32,116,104,101,115,112,101,99,116,
+97,99,117,108,97,114,102,114,97,99,116,105,111,110,32,111,102,101,108,101,99,116
+,114,105,99,105,116,121,104,101,97,100,32,111,102,32,116,104,101,114,101,115,116
+,97,117,114,97,110,116,115,112,97,114,116,110,101,114,115,104,105,112,101,109,
+112,104,97,115,105,115,32,111,110,109,111,115,116,32,114,101,99,101,110,116,115,
+104,97,114,101,32,119,105,116,104,32,115,97,121,105,110,103,32,116,104,97,116,
+102,105,108,108,101,100,32,119,105,116,104,100,101,115,105,103,110,101,100,32,
+116,111,105,116,32,105,115,32,111,102,116,101,110,34,62,60,47,105,102,114,97,109
+,101,62,97,115,32,102,111,108,108,111,119,115,58,109,101,114,103,101,100,32,119,
+105,116,104,116,104,114,111,117,103,104,32,116,104,101,99,111,109,109,101,114,99
+,105,97,108,32,112,111,105,110,116,101,100,32,111,117,116,111,112,112,111,114,
+116,117,110,105,116,121,118,105,101,119,32,111,102,32,116,104,101,114,101,113,
+117,105,114,101,109,101,110,116,100,105,118,105,115,105,111,110,32,111,102,112,
+114,111,103,114,97,109,109,105,110,103,104,101,32,114,101,99,101,105,118,101,100
+,115,101,116,73,110,116,101,114,118,97,108,34,62,60,47,115,112,97,110,62,60,47,
+105,110,32,78,101,119,32,89,111,114,107,97,100,100,105,116,105,111,110,97,108,32
+,99,111,109,112,114,101,115,115,105,111,110,10,10,60,100,105,118,32,105,100,61,
+34,105,110,99,111,114,112,111,114,97,116,101,59,60,47,115,99,114,105,112,116,62,
+60,97,116,116,97,99,104,69,118,101,110,116,98,101,99,97,109,101,32,116,104,101,
+32,34,32,116,97,114,103,101,116,61,34,95,99,97,114,114,105,101,100,32,111,117,
+116,83,111,109,101,32,111,102,32,116,104,101,115,99,105,101,110,99,101,32,97,110
+,100,116,104,101,32,116,105,109,101,32,111,102,67,111,110,116,97,105,110,101,114
+,34,62,109,97,105,110,116,97,105,110,105,110,103,67,104,114,105,115,116,111,112,
+104,101,114,77,117,99,104,32,111,102,32,116,104,101,119,114,105,116,105,110,103,
+115,32,111,102,34,32,104,101,105,103,104,116,61,34,50,115,105,122,101,32,111,102
+,32,116,104,101,118,101,114,115,105,111,110,32,111,102,32,109,105,120,116,117,
+114,101,32,111,102,32,98,101,116,119,101,101,110,32,116,104,101,69,120,97,109,
+112,108,101,115,32,111,102,101,100,117,99,97,116,105,111,110,97,108,99,111,109,
+112,101,116,105,116,105,118,101,32,111,110,115,117,98,109,105,116,61,34,100,105,
+114,101,99,116,111,114,32,111,102,100,105,115,116,105,110,99,116,105,118,101,47,
+68,84,68,32,88,72,84,77,76,32,114,101,108,97,116,105,110,103,32,116,111,116,101,
+110,100,101,110,99,121,32,116,111,112,114,111,118,105,110,99,101,32,111,102,119,
+104,105,99,104,32,119,111,117,108,100,100,101,115,112,105,116,101,32,116,104,101
+,115,99,105,101,110,116,105,102,105,99,32,108,101,103,105,115,108,97,116,117,114
+,101,46,105,110,110,101,114,72,84,77,76,32,97,108,108,101,103,97,116,105,111,110
+,115,65,103,114,105,99,117,108,116,117,114,101,119,97,115,32,117,115,101,100,32,
+105,110,97,112,112,114,111,97,99,104,32,116,111,105,110,116,101,108,108,105,103,
+101,110,116,121,101,97,114,115,32,108,97,116,101,114,44,115,97,110,115,45,115,
+101,114,105,102,100,101,116,101,114,109,105,110,105,110,103,80,101,114,102,111,
+114,109,97,110,99,101,97,112,112,101,97,114,97,110,99,101,115,44,32,119,104,105,
+99,104,32,105,115,32,102,111,117,110,100,97,116,105,111,110,115,97,98,98,114,101
+,118,105,97,116,101,100,104,105,103,104,101,114,32,116,104,97,110,115,32,102,114
+,111,109,32,116,104,101,32,105,110,100,105,118,105,100,117,97,108,32,99,111,109,
+112,111,115,101,100,32,111,102,115,117,112,112,111,115,101,100,32,116,111,99,108
+,97,105,109,115,32,116,104,97,116,97,116,116,114,105,98,117,116,105,111,110,102,
+111,110,116,45,115,105,122,101,58,49,101,108,101,109,101,110,116,115,32,111,102,
+72,105,115,116,111,114,105,99,97,108,32,104,105,115,32,98,114,111,116,104,101,
+114,97,116,32,116,104,101,32,116,105,109,101,97,110,110,105,118,101,114,115,97,
+114,121,103,111,118,101,114,110,101,100,32,98,121,114,101,108,97,116,101,100,32,
+116,111,32,117,108,116,105,109,97,116,101,108,121,32,105,110,110,111,118,97,116,
+105,111,110,115,105,116,32,105,115,32,115,116,105,108,108,99,97,110,32,111,110,
+108,121,32,98,101,100,101,102,105,110,105,116,105,111,110,115,116,111,71,77,84,
+83,116,114,105,110,103,65,32,110,117,109,98,101,114,32,111,102,105,109,103,32,99
+,108,97,115,115,61,34,69,118,101,110,116,117,97,108,108,121,44,119,97,115,32,99,
+104,97,110,103,101,100,111,99,99,117,114,114,101,100,32,105,110,110,101,105,103,
+104,98,111,114,105,110,103,100,105,115,116,105,110,103,117,105,115,104,119,104,
+101,110,32,104,101,32,119,97,115,105,110,116,114,111,100,117,99,105,110,103,116,
+101,114,114,101,115,116,114,105,97,108,77,97,110,121,32,111,102,32,116,104,101,
+97,114,103,117,101,115,32,116,104,97,116,97,110,32,65,109,101,114,105,99,97,110,
+99,111,110,113,117,101,115,116,32,111,102,119,105,100,101,115,112,114,101,97,100
+,32,119,101,114,101,32,107,105,108,108,101,100,115,99,114,101,101,110,32,97,110,
+100,32,73,110,32,111,114,100,101,114,32,116,111,101,120,112,101,99,116,101,100,
+32,116,111,100,101,115,99,101,110,100,97,110,116,115,97,114,101,32,108,111,99,97
+,116,101,100,108,101,103,105,115,108,97,116,105,118,101,103,101,110,101,114,97,
+116,105,111,110,115,32,98,97,99,107,103,114,111,117,110,100,109,111,115,116,32,
+112,101,111,112,108,101,121,101,97,114,115,32,97,102,116,101,114,116,104,101,114
+,101,32,105,115,32,110,111,116,104,101,32,104,105,103,104,101,115,116,102,114,
+101,113,117,101,110,116,108,121,32,116,104,101,121,32,100,111,32,110,111,116,97,
+114,103,117,101,100,32,116,104,97,116,115,104,111,119,101,100,32,116,104,97,116,
+112,114,101,100,111,109,105,110,97,110,116,116,104,101,111,108,111,103,105,99,97
+,108,98,121,32,116,104,101,32,116,105,109,101,99,111,110,115,105,100,101,114,105
+,110,103,115,104,111,114,116,45,108,105,118,101,100,60,47,115,112,97,110,62,60,
+47,97,62,99,97,110,32,98,101,32,117,115,101,100,118,101,114,121,32,108,105,116,
+116,108,101,111,110,101,32,111,102,32,116,104,101,32,104,97,100,32,97,108,114,
+101,97,100,121,105,110,116,101,114,112,114,101,116,101,100,99,111,109,109,117,
+110,105,99,97,116,101,102,101,97,116,117,114,101,115,32,111,102,103,111,118,101,
+114,110,109,101,110,116,44,60,47,110,111,115,99,114,105,112,116,62,101,110,116,
+101,114,101,100,32,116,104,101,34,32,104,101,105,103,104,116,61,34,51,73,110,100
+,101,112,101,110,100,101,110,116,112,111,112,117,108,97,116,105,111,110,115,108,
+97,114,103,101,45,115,99,97,108,101,46,32,65,108,116,104,111,117,103,104,32,117,
+115,101,100,32,105,110,32,116,104,101,100,101,115,116,114,117,99,116,105,111,110
+,112,111,115,115,105,98,105,108,105,116,121,115,116,97,114,116,105,110,103,32,
+105,110,116,119,111,32,111,114,32,109,111,114,101,101,120,112,114,101,115,115,
+105,111,110,115,115,117,98,111,114,100,105,110,97,116,101,108,97,114,103,101,114
+,32,116,104,97,110,104,105,115,116,111,114,121,32,97,110,100,60,47,111,112,116,
+105,111,110,62,13,10,67,111,110,116,105,110,101,110,116,97,108,101,108,105,109,
+105,110,97,116,105,110,103,119,105,108,108,32,110,111,116,32,98,101,112,114,97,
+99,116,105,99,101,32,111,102,105,110,32,102,114,111,110,116,32,111,102,115,105,
+116,101,32,111,102,32,116,104,101,101,110,115,117,114,101,32,116,104,97,116,116,
+111,32,99,114,101,97,116,101,32,97,109,105,115,115,105,115,115,105,112,112,105,
+112,111,116,101,110,116,105,97,108,108,121,111,117,116,115,116,97,110,100,105,
+110,103,98,101,116,116,101,114,32,116,104,97,110,119,104,97,116,32,105,115,32,
+110,111,119,115,105,116,117,97,116,101,100,32,105,110,109,101,116,97,32,110,97,
+109,101,61,34,84,114,97,100,105,116,105,111,110,97,108,115,117,103,103,101,115,
+116,105,111,110,115,84,114,97,110,115,108,97,116,105,111,110,116,104,101,32,102,
+111,114,109,32,111,102,97,116,109,111,115,112,104,101,114,105,99,105,100,101,111
+,108,111,103,105,99,97,108,101,110,116,101,114,112,114,105,115,101,115,99,97,108
+,99,117,108,97,116,105,110,103,101,97,115,116,32,111,102,32,116,104,101,114,101,
+109,110,97,110,116,115,32,111,102,112,108,117,103,105,110,115,112,97,103,101,47,
+105,110,100,101,120,46,112,104,112,63,114,101,109,97,105,110,101,100,32,105,110,
+116,114,97,110,115,102,111,114,109,101,100,72,101,32,119,97,115,32,97,108,115,
+111,119,97,115,32,97,108,114,101,97,100,121,115,116,97,116,105,115,116,105,99,97
+,108,105,110,32,102,97,118,111,114,32,111,102,77,105,110,105,115,116,114,121,32,
+111,102,109,111,118,101,109,101,110,116,32,111,102,102,111,114,109,117,108,97,
+116,105,111,110,105,115,32,114,101,113,117,105,114,101,100,60,108,105,110,107,32
+,114,101,108,61,34,84,104,105,115,32,105,115,32,116,104,101,32,60,97,32,104,114,
+101,102,61,34,47,112,111,112,117,108,97,114,105,122,101,100,105,110,118,111,108,
+118,101,100,32,105,110,97,114,101,32,117,115,101,100,32,116,111,97,110,100,32,
+115,101,118,101,114,97,108,109,97,100,101,32,98,121,32,116,104,101,115,101,101,
+109,115,32,116,111,32,98,101,108,105,107,101,108,121,32,116,104,97,116,80,97,108
+,101,115,116,105,110,105,97,110,110,97,109,101,100,32,97,102,116,101,114,105,116
+,32,104,97,100,32,98,101,101,110,109,111,115,116,32,99,111,109,109,111,110,116,
+111,32,114,101,102,101,114,32,116,111,98,117,116,32,116,104,105,115,32,105,115,
+99,111,110,115,101,99,117,116,105,118,101,116,101,109,112,111,114,97,114,105,108
+,121,73,110,32,103,101,110,101,114,97,108,44,99,111,110,118,101,110,116,105,111,
+110,115,116,97,107,101,115,32,112,108,97,99,101,115,117,98,100,105,118,105,115,
+105,111,110,116,101,114,114,105,116,111,114,105,97,108,111,112,101,114,97,116,
+105,111,110,97,108,112,101,114,109,97,110,101,110,116,108,121,119,97,115,32,108,
+97,114,103,101,108,121,111,117,116,98,114,101,97,107,32,111,102,105,110,32,116,
+104,101,32,112,97,115,116,102,111,108,108,111,119,105,110,103,32,97,32,120,109,
+108,110,115,58,111,103,61,34,62,60,97,32,99,108,97,115,115,61,34,99,108,97,115,
+115,61,34,116,101,120,116,67,111,110,118,101,114,115,105,111,110,32,109,97,121,
+32,98,101,32,117,115,101,100,109,97,110,117,102,97,99,116,117,114,101,97,102,116
+,101,114,32,98,101,105,110,103,99,108,101,97,114,102,105,120,34,62,10,113,117,
+101,115,116,105,111,110,32,111,102,119,97,115,32,101,108,101,99,116,101,100,116,
+111,32,98,101,99,111,109,101,32,97,98,101,99,97,117,115,101,32,111,102,32,115,
+111,109,101,32,112,101,111,112,108,101,105,110,115,112,105,114,101,100,32,98,121
+,115,117,99,99,101,115,115,102,117,108,32,97,32,116,105,109,101,32,119,104,101,
+110,109,111,114,101,32,99,111,109,109,111,110,97,109,111,110,103,115,116,32,116,
+104,101,97,110,32,111,102,102,105,99,105,97,108,119,105,100,116,104,58,49,48,48,
+37,59,116,101,99,104,110,111,108,111,103,121,44,119,97,115,32,97,100,111,112,116
+,101,100,116,111,32,107,101,101,112,32,116,104,101,115,101,116,116,108,101,109,
+101,110,116,115,108,105,118,101,32,98,105,114,116,104,115,105,110,100,101,120,46
+,104,116,109,108,34,67,111,110,110,101,99,116,105,99,117,116,97,115,115,105,103,
+110,101,100,32,116,111,38,97,109,112,59,116,105,109,101,115,59,97,99,99,111,117,
+110,116,32,102,111,114,97,108,105,103,110,61,114,105,103,104,116,116,104,101,32,
+99,111,109,112,97,110,121,97,108,119,97,121,115,32,98,101,101,110,114,101,116,
+117,114,110,101,100,32,116,111,105,110,118,111,108,118,101,109,101,110,116,66,
+101,99,97,117,115,101,32,116,104,101,116,104,105,115,32,112,101,114,105,111,100,
+34,32,110,97,109,101,61,34,113,34,32,99,111,110,102,105,110,101,100,32,116,111,
+97,32,114,101,115,117,108,116,32,111,102,118,97,108,117,101,61,34,34,32,47,62,
+105,115,32,97,99,116,117,97,108,108,121,69,110,118,105,114,111,110,109,101,110,
+116,13,10,60,47,104,101,97,100,62,13,10,67,111,110,118,101,114,115,101,108,121,
+44,62,10,60,100,105,118,32,105,100,61,34,48,34,32,119,105,100,116,104,61,34,49,
+105,115,32,112,114,111,98,97,98,108,121,104,97,118,101,32,98,101,99,111,109,101,
+99,111,110,116,114,111,108,108,105,110,103,116,104,101,32,112,114,111,98,108,101
+,109,99,105,116,105,122,101,110,115,32,111,102,112,111,108,105,116,105,99,105,97
+,110,115,114,101,97,99,104,101,100,32,116,104,101,97,115,32,101,97,114,108,121,
+32,97,115,58,110,111,110,101,59,32,111,118,101,114,60,116,97,98,108,101,32,99,
+101,108,108,118,97,108,105,100,105,116,121,32,111,102,100,105,114,101,99,116,108
+,121,32,116,111,111,110,109,111,117,115,101,100,111,119,110,119,104,101,114,101,
+32,105,116,32,105,115,119,104,101,110,32,105,116,32,119,97,115,109,101,109,98,
+101,114,115,32,111,102,32,114,101,108,97,116,105,111,110,32,116,111,97,99,99,111
+,109,109,111,100,97,116,101,97,108,111,110,103,32,119,105,116,104,32,73,110,32,
+116,104,101,32,108,97,116,101,116,104,101,32,69,110,103,108,105,115,104,100,101,
+108,105,99,105,111,117,115,34,62,116,104,105,115,32,105,115,32,110,111,116,116,
+104,101,32,112,114,101,115,101,110,116,105,102,32,116,104,101,121,32,97,114,101,
+97,110,100,32,102,105,110,97,108,108,121,97,32,109,97,116,116,101,114,32,111,102
+,13,10,9,60,47,100,105,118,62,13,10,13,10,60,47,115,99,114,105,112,116,62,102,97
+,115,116,101,114,32,116,104,97,110,109,97,106,111,114,105,116,121,32,111,102,97,
+102,116,101,114,32,119,104,105,99,104,99,111,109,112,97,114,97,116,105,118,101,
+116,111,32,109,97,105,110,116,97,105,110,105,109,112,114,111,118,101,32,116,104,
+101,97,119,97,114,100,101,100,32,116,104,101,101,114,34,32,99,108,97,115,115,61,
+34,102,114,97,109,101,98,111,114,100,101,114,114,101,115,116,111,114,97,116,105,
+111,110,105,110,32,116,104,101,32,115,97,109,101,97,110,97,108,121,115,105,115,
+32,111,102,116,104,101,105,114,32,102,105,114,115,116,68,117,114,105,110,103,32,
+116,104,101,32,99,111,110,116,105,110,101,110,116,97,108,115,101,113,117,101,110
+,99,101,32,111,102,102,117,110,99,116,105,111,110,40,41,123,102,111,110,116,45,
+115,105,122,101,58,32,119,111,114,107,32,111,110,32,116,104,101,60,47,115,99,114
+,105,112,116,62,10,60,98,101,103,105,110,115,32,119,105,116,104,106,97,118,97,
+115,99,114,105,112,116,58,99,111,110,115,116,105,116,117,101,110,116,119,97,115,
+32,102,111,117,110,100,101,100,101,113,117,105,108,105,98,114,105,117,109,97,115
+,115,117,109,101,32,116,104,97,116,105,115,32,103,105,118,101,110,32,98,121,110,
+101,101,100,115,32,116,111,32,98,101,99,111,111,114,100,105,110,97,116,101,115,
+116,104,101,32,118,97,114,105,111,117,115,97,114,101,32,112,97,114,116,32,111,
+102,111,110,108,121,32,105,110,32,116,104,101,115,101,99,116,105,111,110,115,32,
+111,102,105,115,32,97,32,99,111,109,109,111,110,116,104,101,111,114,105,101,115,
+32,111,102,100,105,115,99,111,118,101,114,105,101,115,97,115,115,111,99,105,97,
+116,105,111,110,101,100,103,101,32,111,102,32,116,104,101,115,116,114,101,110,
+103,116,104,32,111,102,112,111,115,105,116,105,111,110,32,105,110,112,114,101,
+115,101,110,116,45,100,97,121,117,110,105,118,101,114,115,97,108,108,121,116,111
+,32,102,111,114,109,32,116,104,101,98,117,116,32,105,110,115,116,101,97,100,99,
+111,114,112,111,114,97,116,105,111,110,97,116,116,97,99,104,101,100,32,116,111,
+105,115,32,99,111,109,109,111,110,108,121,114,101,97,115,111,110,115,32,102,111,
+114,32,38,113,117,111,116,59,116,104,101,32,99,97,110,32,98,101,32,109,97,100,
+101,119,97,115,32,97,98,108,101,32,116,111,119,104,105,99,104,32,109,101,97,110,
+115,98,117,116,32,100,105,100,32,110,111,116,111,110,77,111,117,115,101,79,118,
+101,114,97,115,32,112,111,115,115,105,98,108,101,111,112,101,114,97,116,101,100,
+32,98,121,99,111,109,105,110,103,32,102,114,111,109,116,104,101,32,112,114,105,
+109,97,114,121,97,100,100,105,116,105,111,110,32,111,102,102,111,114,32,115,101,
+118,101,114,97,108,116,114,97,110,115,102,101,114,114,101,100,97,32,112,101,114,
+105,111,100,32,111,102,97,114,101,32,97,98,108,101,32,116,111,104,111,119,101,
+118,101,114,44,32,105,116,115,104,111,117,108,100,32,104,97,118,101,109,117,99,
+104,32,108,97,114,103,101,114,10,9,60,47,115,99,114,105,112,116,62,97,100,111,
+112,116,101,100,32,116,104,101,112,114,111,112,101,114,116,121,32,111,102,100,
+105,114,101,99,116,101,100,32,98,121,101,102,102,101,99,116,105,118,101,108,121,
+119,97,115,32,98,114,111,117,103,104,116,99,104,105,108,100,114,101,110,32,111,
+102,80,114,111,103,114,97,109,109,105,110,103,108,111,110,103,101,114,32,116,104
+,97,110,109,97,110,117,115,99,114,105,112,116,115,119,97,114,32,97,103,97,105,
+110,115,116,98,121,32,109,101,97,110,115,32,111,102,97,110,100,32,109,111,115,
+116,32,111,102,115,105,109,105,108,97,114,32,116,111,32,112,114,111,112,114,105,
+101,116,97,114,121,111,114,105,103,105,110,97,116,105,110,103,112,114,101,115,
+116,105,103,105,111,117,115,103,114,97,109,109,97,116,105,99,97,108,101,120,112,
+101,114,105,101,110,99,101,46,116,111,32,109,97,107,101,32,116,104,101,73,116,32
+,119,97,115,32,97,108,115,111,105,115,32,102,111,117,110,100,32,105,110,99,111,
+109,112,101,116,105,116,111,114,115,105,110,32,116,104,101,32,85,46,83,46,114,
+101,112,108,97,99,101,32,116,104,101,98,114,111,117,103,104,116,32,116,104,101,
+99,97,108,99,117,108,97,116,105,111,110,102,97,108,108,32,111,102,32,116,104,101
+,116,104,101,32,103,101,110,101,114,97,108,112,114,97,99,116,105,99,97,108,108,
+121,105,110,32,104,111,110,111,114,32,111,102,114,101,108,101,97,115,101,100,32,
+105,110,114,101,115,105,100,101,110,116,105,97,108,97,110,100,32,115,111,109,101
+,32,111,102,107,105,110,103,32,111,102,32,116,104,101,114,101,97,99,116,105,111,
+110,32,116,111,49,115,116,32,69,97,114,108,32,111,102,99,117,108,116,117,114,101
+,32,97,110,100,112,114,105,110,99,105,112,97,108,108,121,60,47,116,105,116,108,
+101,62,10,32,32,116,104,101,121,32,99,97,110,32,98,101,98,97,99,107,32,116,111,
+32,116,104,101,115,111,109,101,32,111,102,32,104,105,115,101,120,112,111,115,117
+,114,101,32,116,111,97,114,101,32,115,105,109,105,108,97,114,102,111,114,109,32,
+111,102,32,116,104,101,97,100,100,70,97,118,111,114,105,116,101,99,105,116,105,
+122,101,110,115,104,105,112,112,97,114,116,32,105,110,32,116,104,101,112,101,111
+,112,108,101,32,119,105,116,104,105,110,32,112,114,97,99,116,105,99,101,116,111,
+32,99,111,110,116,105,110,117,101,38,97,109,112,59,109,105,110,117,115,59,97,112
+,112,114,111,118,101,100,32,98,121,32,116,104,101,32,102,105,114,115,116,32,97,
+108,108,111,119,101,100,32,116,104,101,97,110,100,32,102,111,114,32,116,104,101,
+102,117,110,99,116,105,111,110,105,110,103,112,108,97,121,105,110,103,32,116,104
+,101,115,111,108,117,116,105,111,110,32,116,111,104,101,105,103,104,116,61,34,48
+,34,32,105,110,32,104,105,115,32,98,111,111,107,109,111,114,101,32,116,104,97,
+110,32,97,102,111,108,108,111,119,115,32,116,104,101,99,114,101,97,116,101,100,
+32,116,104,101,112,114,101,115,101,110,99,101,32,105,110,38,110,98,115,112,59,60
+,47,116,100,62,110,97,116,105,111,110,97,108,105,115,116,116,104,101,32,105,100,
+101,97,32,111,102,97,32,99,104,97,114,97,99,116,101,114,119,101,114,101,32,102,
+111,114,99,101,100,32,99,108,97,115,115,61,34,98,116,110,100,97,121,115,32,111,
+102,32,116,104,101,102,101,97,116,117,114,101,100,32,105,110,115,104,111,119,105
+,110,103,32,116,104,101,105,110,116,101,114,101,115,116,32,105,110,105,110,32,
+112,108,97,99,101,32,111,102,116,117,114,110,32,111,102,32,116,104,101,116,104,
+101,32,104,101,97,100,32,111,102,76,111,114,100,32,111,102,32,116,104,101,112,
+111,108,105,116,105,99,97,108,108,121,104,97,115,32,105,116,115,32,111,119,110,
+69,100,117,99,97,116,105,111,110,97,108,97,112,112,114,111,118,97,108,32,111,102
+,115,111,109,101,32,111,102,32,116,104,101,101,97,99,104,32,111,116,104,101,114,
+44,98,101,104,97,118,105,111,114,32,111,102,97,110,100,32,98,101,99,97,117,115,
+101,97,110,100,32,97,110,111,116,104,101,114,97,112,112,101,97,114,101,100,32,
+111,110,114,101,99,111,114,100,101,100,32,105,110,98,108,97,99,107,38,113,117,
+111,116,59,109,97,121,32,105,110,99,108,117,100,101,116,104,101,32,119,111,114,
+108,100,39,115,99,97,110,32,108,101,97,100,32,116,111,114,101,102,101,114,115,32
+,116,111,32,97,98,111,114,100,101,114,61,34,48,34,32,103,111,118,101,114,110,109
+,101,110,116,32,119,105,110,110,105,110,103,32,116,104,101,114,101,115,117,108,
+116,101,100,32,105,110,32,119,104,105,108,101,32,116,104,101,32,87,97,115,104,
+105,110,103,116,111,110,44,116,104,101,32,115,117,98,106,101,99,116,99,105,116,
+121,32,105,110,32,116,104,101,62,60,47,100,105,118,62,13,10,9,9,114,101,102,108,
+101,99,116,32,116,104,101,116,111,32,99,111,109,112,108,101,116,101,98,101,99,97
+,109,101,32,109,111,114,101,114,97,100,105,111,97,99,116,105,118,101,114,101,106
+,101,99,116,101,100,32,98,121,119,105,116,104,111,117,116,32,97,110,121,104,105,
+115,32,102,97,116,104,101,114,44,119,104,105,99,104,32,99,111,117,108,100,99,111
+,112,121,32,111,102,32,116,104,101,116,111,32,105,110,100,105,99,97,116,101,97,
+32,112,111,108,105,116,105,99,97,108,97,99,99,111,117,110,116,115,32,111,102,99,
+111,110,115,116,105,116,117,116,101,115,119,111,114,107,101,100,32,119,105,116,
+104,101,114,60,47,97,62,60,47,108,105,62,111,102,32,104,105,115,32,108,105,102,
+101,97,99,99,111,109,112,97,110,105,101,100,99,108,105,101,110,116,87,105,100,
+116,104,112,114,101,118,101,110,116,32,116,104,101,76,101,103,105,115,108,97,116
+,105,118,101,100,105,102,102,101,114,101,110,116,108,121,116,111,103,101,116,104
+,101,114,32,105,110,104,97,115,32,115,101,118,101,114,97,108,102,111,114,32,97,
+110,111,116,104,101,114,116,101,120,116,32,111,102,32,116,104,101,102,111,117,
+110,100,101,100,32,116,104,101,101,32,119,105,116,104,32,116,104,101,32,105,115,
+32,117,115,101,100,32,102,111,114,99,104,97,110,103,101,100,32,116,104,101,117,
+115,117,97,108,108,121,32,116,104,101,112,108,97,99,101,32,119,104,101,114,101,
+119,104,101,114,101,97,115,32,116,104,101,62,32,60,97,32,104,114,101,102,61,34,
+34,62,60,97,32,104,114,101,102,61,34,116,104,101,109,115,101,108,118,101,115,44,
+97,108,116,104,111,117,103,104,32,104,101,116,104,97,116,32,99,97,110,32,98,101,
+116,114,97,100,105,116,105,111,110,97,108,114,111,108,101,32,111,102,32,116,104,
+101,97,115,32,97,32,114,101,115,117,108,116,114,101,109,111,118,101,67,104,105,
+108,100,100,101,115,105,103,110,101,100,32,98,121,119,101,115,116,32,111,102,32,
+116,104,101,83,111,109,101,32,112,101,111,112,108,101,112,114,111,100,117,99,116
+,105,111,110,44,115,105,100,101,32,111,102,32,116,104,101,110,101,119,115,108,
+101,116,116,101,114,115,117,115,101,100,32,98,121,32,116,104,101,100,111,119,110
+,32,116,111,32,116,104,101,97,99,99,101,112,116,101,100,32,98,121,108,105,118,
+101,32,105,110,32,116,104,101,97,116,116,101,109,112,116,115,32,116,111,111,117,
+116,115,105,100,101,32,116,104,101,102,114,101,113,117,101,110,99,105,101,115,72
+,111,119,101,118,101,114,44,32,105,110,112,114,111,103,114,97,109,109,101,114,
+115,97,116,32,108,101,97,115,116,32,105,110,97,112,112,114,111,120,105,109,97,
+116,101,97,108,116,104,111,117,103,104,32,105,116,119,97,115,32,112,97,114,116,
+32,111,102,97,110,100,32,118,97,114,105,111,117,115,71,111,118,101,114,110,111,
+114,32,111,102,116,104,101,32,97,114,116,105,99,108,101,116,117,114,110,101,100,
+32,105,110,116,111,62,60,97,32,104,114,101,102,61,34,47,116,104,101,32,101,99,
+111,110,111,109,121,105,115,32,116,104,101,32,109,111,115,116,109,111,115,116,32
+,119,105,100,101,108,121,119,111,117,108,100,32,108,97,116,101,114,97,110,100,32
+,112,101,114,104,97,112,115,114,105,115,101,32,116,111,32,116,104,101,111,99,99,
+117,114,115,32,119,104,101,110,117,110,100,101,114,32,119,104,105,99,104,99,111,
+110,100,105,116,105,111,110,115,46,116,104,101,32,119,101,115,116,101,114,110,
+116,104,101,111,114,121,32,116,104,97,116,105,115,32,112,114,111,100,117,99,101,
+100,116,104,101,32,99,105,116,121,32,111,102,105,110,32,119,104,105,99,104,32,
+104,101,115,101,101,110,32,105,110,32,116,104,101,116,104,101,32,99,101,110,116,
+114,97,108,98,117,105,108,100,105,110,103,32,111,102,109,97,110,121,32,111,102,
+32,104,105,115,97,114,101,97,32,111,102,32,116,104,101,105,115,32,116,104,101,32
+,111,110,108,121,109,111,115,116,32,111,102,32,116,104,101,109,97,110,121,32,111
+,102,32,116,104,101,116,104,101,32,87,101,115,116,101,114,110,84,104,101,114,101
+,32,105,115,32,110,111,101,120,116,101,110,100,101,100,32,116,111,83,116,97,116,
+105,115,116,105,99,97,108,99,111,108,115,112,97,110,61,50,32,124,115,104,111,114
+,116,32,115,116,111,114,121,112,111,115,115,105,98,108,101,32,116,111,116,111,
+112,111,108,111,103,105,99,97,108,99,114,105,116,105,99,97,108,32,111,102,114,
+101,112,111,114,116,101,100,32,116,111,97,32,67,104,114,105,115,116,105,97,110,
+100,101,99,105,115,105,111,110,32,116,111,105,115,32,101,113,117,97,108,32,116,
+111,112,114,111,98,108,101,109,115,32,111,102,84,104,105,115,32,99,97,110,32,98,
+101,109,101,114,99,104,97,110,100,105,115,101,102,111,114,32,109,111,115,116,32,
+111,102,110,111,32,101,118,105,100,101,110,99,101,101,100,105,116,105,111,110,
+115,32,111,102,101,108,101,109,101,110,116,115,32,105,110,38,113,117,111,116,59,
+46,32,84,104,101,99,111,109,47,105,109,97,103,101,115,47,119,104,105,99,104,32,
+109,97,107,101,115,116,104,101,32,112,114,111,99,101,115,115,114,101,109,97,105,
+110,115,32,116,104,101,108,105,116,101,114,97,116,117,114,101,44,105,115,32,97,
+32,109,101,109,98,101,114,116,104,101,32,112,111,112,117,108,97,114,116,104,101,
+32,97,110,99,105,101,110,116,112,114,111,98,108,101,109,115,32,105,110,116,105,
+109,101,32,111,102,32,116,104,101,100,101,102,101,97,116,101,100,32,98,121,98,
+111,100,121,32,111,102,32,116,104,101,97,32,102,101,119,32,121,101,97,114,115,
+109,117,99,104,32,111,102,32,116,104,101,116,104,101,32,119,111,114,107,32,111,
+102,67,97,108,105,102,111,114,110,105,97,44,115,101,114,118,101,100,32,97,115,32
+,97,103,111,118,101,114,110,109,101,110,116,46,99,111,110,99,101,112,116,115,32,
+111,102,109,111,118,101,109,101,110,116,32,105,110,9,9,60,100,105,118,32,105,100
+,61,34,105,116,34,32,118,97,108,117,101,61,34,108,97,110,103,117,97,103,101,32,
+111,102,97,115,32,116,104,101,121,32,97,114,101,112,114,111,100,117,99,101,100,
+32,105,110,105,115,32,116,104,97,116,32,116,104,101,101,120,112,108,97,105,110,
+32,116,104,101,100,105,118,62,60,47,100,105,118,62,10,72,111,119,101,118,101,114
+,32,116,104,101,108,101,97,100,32,116,111,32,116,104,101,9,60,97,32,104,114,101,
+102,61,34,47,119,97,115,32,103,114,97,110,116,101,100,112,101,111,112,108,101,32
+,104,97,118,101,99,111,110,116,105,110,117,97,108,108,121,119,97,115,32,115,101,
+101,110,32,97,115,97,110,100,32,114,101,108,97,116,101,100,116,104,101,32,114,
+111,108,101,32,111,102,112,114,111,112,111,115,101,100,32,98,121,111,102,32,116,
+104,101,32,98,101,115,116,101,97,99,104,32,111,116,104,101,114,46,67,111,110,115
+,116,97,110,116,105,110,101,112,101,111,112,108,101,32,102,114,111,109,100,105,
+97,108,101,99,116,115,32,111,102,116,111,32,114,101,118,105,115,105,111,110,119,
+97,115,32,114,101,110,97,109,101,100,97,32,115,111,117,114,99,101,32,111,102,116
+,104,101,32,105,110,105,116,105,97,108,108,97,117,110,99,104,101,100,32,105,110,
+112,114,111,118,105,100,101,32,116,104,101,116,111,32,116,104,101,32,119,101,115
+,116,119,104,101,114,101,32,116,104,101,114,101,97,110,100,32,115,105,109,105,
+108,97,114,98,101,116,119,101,101,110,32,116,119,111,105,115,32,97,108,115,111,
+32,116,104,101,69,110,103,108,105,115,104,32,97,110,100,99,111,110,100,105,116,
+105,111,110,115,44,116,104,97,116,32,105,116,32,119,97,115,101,110,116,105,116,
+108,101,100,32,116,111,116,104,101,109,115,101,108,118,101,115,46,113,117,97,110
+,116,105,116,121,32,111,102,114,97,110,115,112,97,114,101,110,99,121,116,104,101
+,32,115,97,109,101,32,97,115,116,111,32,106,111,105,110,32,116,104,101,99,111,
+117,110,116,114,121,32,97,110,100,116,104,105,115,32,105,115,32,116,104,101,84,
+104,105,115,32,108,101,100,32,116,111,97,32,115,116,97,116,101,109,101,110,116,
+99,111,110,116,114,97,115,116,32,116,111,108,97,115,116,73,110,100,101,120,79,
+102,116,104,114,111,117,103,104,32,104,105,115,105,115,32,100,101,115,105,103,
+110,101,100,116,104,101,32,116,101,114,109,32,105,115,105,115,32,112,114,111,118
+,105,100,101,100,112,114,111,116,101,99,116,32,116,104,101,110,103,60,47,97,62,
+60,47,108,105,62,84,104,101,32,99,117,114,114,101,110,116,116,104,101,32,115,105
+,116,101,32,111,102,115,117,98,115,116,97,110,116,105,97,108,101,120,112,101,114
+,105,101,110,99,101,44,105,110,32,116,104,101,32,87,101,115,116,116,104,101,121,
+32,115,104,111,117,108,100,115,108,111,118,101,110,196,141,105,110,97,99,111,109
+,101,110,116,97,114,105,111,115,117,110,105,118,101,114,115,105,100,97,100,99,
+111,110,100,105,99,105,111,110,101,115,97,99,116,105,118,105,100,97,100,101,115,
+101,120,112,101,114,105,101,110,99,105,97,116,101,99,110,111,108,111,103,195,173
+,97,112,114,111,100,117,99,99,105,195,179,110,112,117,110,116,117,97,99,105,195,
+179,110,97,112,108,105,99,97,99,105,195,179,110,99,111,110,116,114,97,115,101,
+195,177,97,99,97,116,101,103,111,114,195,173,97,115,114,101,103,105,115,116,114,
+97,114,115,101,112,114,111,102,101,115,105,111,110,97,108,116,114,97,116,97,109,
+105,101,110,116,111,114,101,103,195,173,115,116,114,97,116,101,115,101,99,114,
+101,116,97,114,195,173,97,112,114,105,110,99,105,112,97,108,101,115,112,114,111,
+116,101,99,99,105,195,179,110,105,109,112,111,114,116,97,110,116,101,115,105,109
+,112,111,114,116,97,110,99,105,97,112,111,115,105,98,105,108,105,100,97,100,105,
+110,116,101,114,101,115,97,110,116,101,99,114,101,99,105,109,105,101,110,116,111
+,110,101,99,101,115,105,100,97,100,101,115,115,117,115,99,114,105,98,105,114,115
+,101,97,115,111,99,105,97,99,105,195,179,110,100,105,115,112,111,110,105,98,108,
+101,115,101,118,97,108,117,97,99,105,195,179,110,101,115,116,117,100,105,97,110,
+116,101,115,114,101,115,112,111,110,115,97,98,108,101,114,101,115,111,108,117,99
+,105,195,179,110,103,117,97,100,97,108,97,106,97,114,97,114,101,103,105,115,116,
+114,97,100,111,115,111,112,111,114,116,117,110,105,100,97,100,99,111,109,101,114
+,99,105,97,108,101,115,102,111,116,111,103,114,97,102,195,173,97,97,117,116,111,
+114,105,100,97,100,101,115,105,110,103,101,110,105,101,114,195,173,97,116,101,
+108,101,118,105,115,105,195,179,110,99,111,109,112,101,116,101,110,99,105,97,111
+,112,101,114,97,99,105,111,110,101,115,101,115,116,97,98,108,101,99,105,100,111,
+115,105,109,112,108,101,109,101,110,116,101,97,99,116,117,97,108,109,101,110,116
+,101,110,97,118,101,103,97,99,105,195,179,110,99,111,110,102,111,114,109,105,100
+,97,100,108,105,110,101,45,104,101,105,103,104,116,58,102,111,110,116,45,102,97,
+109,105,108,121,58,34,32,58,32,34,104,116,116,112,58,47,47,97,112,112,108,105,99
+,97,116,105,111,110,115,108,105,110,107,34,32,104,114,101,102,61,34,115,112,101,
+99,105,102,105,99,97,108,108,121,47,47,60,33,91,67,68,65,84,65,91,10,79,114,103,
+97,110,105,122,97,116,105,111,110,100,105,115,116,114,105,98,117,116,105,111,110
+,48,112,120,59,32,104,101,105,103,104,116,58,114,101,108,97,116,105,111,110,115,
+104,105,112,100,101,118,105,99,101,45,119,105,100,116,104,60,100,105,118,32,99,
+108,97,115,115,61,34,60,108,97,98,101,108,32,102,111,114,61,34,114,101,103,105,
+115,116,114,97,116,105,111,110,60,47,110,111,115,99,114,105,112,116,62,10,47,105
+,110,100,101,120,46,104,116,109,108,34,119,105,110,100,111,119,46,111,112,101,
+110,40,32,33,105,109,112,111,114,116,97,110,116,59,97,112,112,108,105,99,97,116,
+105,111,110,47,105,110,100,101,112,101,110,100,101,110,99,101,47,47,119,119,119,
+46,103,111,111,103,108,101,111,114,103,97,110,105,122,97,116,105,111,110,97,117,
+116,111,99,111,109,112,108,101,116,101,114,101,113,117,105,114,101,109,101,110,
+116,115,99,111,110,115,101,114,118,97,116,105,118,101,60,102,111,114,109,32,110,
+97,109,101,61,34,105,110,116,101,108,108,101,99,116,117,97,108,109,97,114,103,
+105,110,45,108,101,102,116,58,49,56,116,104,32,99,101,110,116,117,114,121,97,110
+,32,105,109,112,111,114,116,97,110,116,105,110,115,116,105,116,117,116,105,111,
+110,115,97,98,98,114,101,118,105,97,116,105,111,110,60,105,109,103,32,99,108,97,
+115,115,61,34,111,114,103,97,110,105,115,97,116,105,111,110,99,105,118,105,108,
+105,122,97,116,105,111,110,49,57,116,104,32,99,101,110,116,117,114,121,97,114,99
+,104,105,116,101,99,116,117,114,101,105,110,99,111,114,112,111,114,97,116,101,
+100,50,48,116,104,32,99,101,110,116,117,114,121,45,99,111,110,116,97,105,110,101
+,114,34,62,109,111,115,116,32,110,111,116,97,98,108,121,47,62,60,47,97,62,60,47,
+100,105,118,62,110,111,116,105,102,105,99,97,116,105,111,110,39,117,110,100,101,
+102,105,110,101,100,39,41,70,117,114,116,104,101,114,109,111,114,101,44,98,101,
+108,105,101,118,101,32,116,104,97,116,105,110,110,101,114,72,84,77,76,32,61,32,
+112,114,105,111,114,32,116,111,32,116,104,101,100,114,97,109,97,116,105,99,97,
+108,108,121,114,101,102,101,114,114,105,110,103,32,116,111,110,101,103,111,116,
+105,97,116,105,111,110,115,104,101,97,100,113,117,97,114,116,101,114,115,83,111,
+117,116,104,32,65,102,114,105,99,97,117,110,115,117,99,99,101,115,115,102,117,
+108,80,101,110,110,115,121,108,118,97,110,105,97,65,115,32,97,32,114,101,115,117
+,108,116,44,60,104,116,109,108,32,108,97,110,103,61,34,38,108,116,59,47,115,117,
+112,38,103,116,59,100,101,97,108,105,110,103,32,119,105,116,104,112,104,105,108,
+97,100,101,108,112,104,105,97,104,105,115,116,111,114,105,99,97,108,108,121,41,
+59,60,47,115,99,114,105,112,116,62,10,112,97,100,100,105,110,103,45,116,111,112,
+58,101,120,112,101,114,105,109,101,110,116,97,108,103,101,116,65,116,116,114,105
+,98,117,116,101,105,110,115,116,114,117,99,116,105,111,110,115,116,101,99,104,
+110,111,108,111,103,105,101,115,112,97,114,116,32,111,102,32,116,104,101,32,61,
+102,117,110,99,116,105,111,110,40,41,123,115,117,98,115,99,114,105,112,116,105,
+111,110,108,46,100,116,100,34,62,13,10,60,104,116,103,101,111,103,114,97,112,104
+,105,99,97,108,67,111,110,115,116,105,116,117,116,105,111,110,39,44,32,102,117,
+110,99,116,105,111,110,40,115,117,112,112,111,114,116,101,100,32,98,121,97,103,
+114,105,99,117,108,116,117,114,97,108,99,111,110,115,116,114,117,99,116,105,111,
+110,112,117,98,108,105,99,97,116,105,111,110,115,102,111,110,116,45,115,105,122,
+101,58,32,49,97,32,118,97,114,105,101,116,121,32,111,102,60,100,105,118,32,115,
+116,121,108,101,61,34,69,110,99,121,99,108,111,112,101,100,105,97,105,102,114,97
+,109,101,32,115,114,99,61,34,100,101,109,111,110,115,116,114,97,116,101,100,97,
+99,99,111,109,112,108,105,115,104,101,100,117,110,105,118,101,114,115,105,116,
+105,101,115,68,101,109,111,103,114,97,112,104,105,99,115,41,59,60,47,115,99,114,
+105,112,116,62,60,100,101,100,105,99,97,116,101,100,32,116,111,107,110,111,119,
+108,101,100,103,101,32,111,102,115,97,116,105,115,102,97,99,116,105,111,110,112,
+97,114,116,105,99,117,108,97,114,108,121,60,47,100,105,118,62,60,47,100,105,118,
+62,69,110,103,108,105,115,104,32,40,85,83,41,97,112,112,101,110,100,67,104,105,
+108,100,40,116,114,97,110,115,109,105,115,115,105,111,110,115,46,32,72,111,119,
+101,118,101,114,44,32,105,110,116,101,108,108,105,103,101,110,99,101,34,32,116,
+97,98,105,110,100,101,120,61,34,102,108,111,97,116,58,114,105,103,104,116,59,67,
+111,109,109,111,110,119,101,97,108,116,104,114,97,110,103,105,110,103,32,102,114
+,111,109,105,110,32,119,104,105,99,104,32,116,104,101,97,116,32,108,101,97,115,
+116,32,111,110,101,114,101,112,114,111,100,117,99,116,105,111,110,101,110,99,121
+,99,108,111,112,101,100,105,97,59,102,111,110,116,45,115,105,122,101,58,49,106,
+117,114,105,115,100,105,99,116,105,111,110,97,116,32,116,104,97,116,32,116,105,
+109,101,34,62,60,97,32,99,108,97,115,115,61,34,73,110,32,97,100,100,105,116,105,
+111,110,44,100,101,115,99,114,105,112,116,105,111,110,43,99,111,110,118,101,114,
+115,97,116,105,111,110,99,111,110,116,97,99,116,32,119,105,116,104,105,115,32,
+103,101,110,101,114,97,108,108,121,114,34,32,99,111,110,116,101,110,116,61,34,
+114,101,112,114,101,115,101,110,116,105,110,103,38,108,116,59,109,97,116,104,38,
+103,116,59,112,114,101,115,101,110,116,97,116,105,111,110,111,99,99,97,115,105,
+111,110,97,108,108,121,60,105,109,103,32,119,105,100,116,104,61,34,110,97,118,
+105,103,97,116,105,111,110,34,62,99,111,109,112,101,110,115,97,116,105,111,110,
+99,104,97,109,112,105,111,110,115,104,105,112,109,101,100,105,97,61,34,97,108,
+108,34,32,118,105,111,108,97,116,105,111,110,32,111,102,114,101,102,101,114,101,
+110,99,101,32,116,111,114,101,116,117,114,110,32,116,114,117,101,59,83,116,114,
+105,99,116,47,47,69,78,34,32,116,114,97,110,115,97,99,116,105,111,110,115,105,
+110,116,101,114,118,101,110,116,105,111,110,118,101,114,105,102,105,99,97,116,
+105,111,110,73,110,102,111,114,109,97,116,105,111,110,32,100,105,102,102,105,99,
+117,108,116,105,101,115,67,104,97,109,112,105,111,110,115,104,105,112,99,97,112,
+97,98,105,108,105,116,105,101,115,60,33,91,101,110,100,105,102,93,45,45,62,125,
+10,60,47,115,99,114,105,112,116,62,10,67,104,114,105,115,116,105,97,110,105,116,
+121,102,111,114,32,101,120,97,109,112,108,101,44,80,114,111,102,101,115,115,105,
+111,110,97,108,114,101,115,116,114,105,99,116,105,111,110,115,115,117,103,103,
+101,115,116,32,116,104,97,116,119,97,115,32,114,101,108,101,97,115,101,100,40,
+115,117,99,104,32,97,115,32,116,104,101,114,101,109,111,118,101,67,108,97,115,
+115,40,117,110,101,109,112,108,111,121,109,101,110,116,116,104,101,32,65,109,101
+,114,105,99,97,110,115,116,114,117,99,116,117,114,101,32,111,102,47,105,110,100,
+101,120,46,104,116,109,108,32,112,117,98,108,105,115,104,101,100,32,105,110,115,
+112,97,110,32,99,108,97,115,115,61,34,34,62,60,97,32,104,114,101,102,61,34,47,
+105,110,116,114,111,100,117,99,116,105,111,110,98,101,108,111,110,103,105,110,
+103,32,116,111,99,108,97,105,109,101,100,32,116,104,97,116,99,111,110,115,101,
+113,117,101,110,99,101,115,60,109,101,116,97,32,110,97,109,101,61,34,71,117,105,
+100,101,32,116,111,32,116,104,101,111,118,101,114,119,104,101,108,109,105,110,
+103,97,103,97,105,110,115,116,32,116,104,101,32,99,111,110,99,101,110,116,114,97
+,116,101,100,44,10,46,110,111,110,116,111,117,99,104,32,111,98,115,101,114,118,
+97,116,105,111,110,115,60,47,97,62,10,60,47,100,105,118,62,10,102,32,40,100,111,
+99,117,109,101,110,116,46,98,111,114,100,101,114,58,32,49,112,120,32,123,102,111
+,110,116,45,115,105,122,101,58,49,116,114,101,97,116,109,101,110,116,32,111,102,
+48,34,32,104,101,105,103,104,116,61,34,49,109,111,100,105,102,105,99,97,116,105,
+111,110,73,110,100,101,112,101,110,100,101,110,99,101,100,105,118,105,100,101,
+100,32,105,110,116,111,103,114,101,97,116,101,114,32,116,104,97,110,97,99,104,
+105,101,118,101,109,101,110,116,115,101,115,116,97,98,108,105,115,104,105,110,
+103,74,97,118,97,83,99,114,105,112,116,34,32,110,101,118,101,114,116,104,101,108
+,101,115,115,115,105,103,110,105,102,105,99,97,110,99,101,66,114,111,97,100,99,
+97,115,116,105,110,103,62,38,110,98,115,112,59,60,47,116,100,62,99,111,110,116,
+97,105,110,101,114,34,62,10,115,117,99,104,32,97,115,32,116,104,101,32,105,110,
+102,108,117,101,110,99,101,32,111,102,97,32,112,97,114,116,105,99,117,108,97,114
+,115,114,99,61,39,104,116,116,112,58,47,47,110,97,118,105,103,97,116,105,111,110
+,34,32,104,97,108,102,32,111,102,32,116,104,101,32,115,117,98,115,116,97,110,116
+,105,97,108,32,38,110,98,115,112,59,60,47,100,105,118,62,97,100,118,97,110,116,
+97,103,101,32,111,102,100,105,115,99,111,118,101,114,121,32,111,102,102,117,110,
+100,97,109,101,110,116,97,108,32,109,101,116,114,111,112,111,108,105,116,97,110,
+116,104,101,32,111,112,112,111,115,105,116,101,34,32,120,109,108,58,108,97,110,
+103,61,34,100,101,108,105,98,101,114,97,116,101,108,121,97,108,105,103,110,61,99
+,101,110,116,101,114,101,118,111,108,117,116,105,111,110,32,111,102,112,114,101,
+115,101,114,118,97,116,105,111,110,105,109,112,114,111,118,101,109,101,110,116,
+115,98,101,103,105,110,110,105,110,103,32,105,110,74,101,115,117,115,32,67,104,
+114,105,115,116,80,117,98,108,105,99,97,116,105,111,110,115,100,105,115,97,103,
+114,101,101,109,101,110,116,116,101,120,116,45,97,108,105,103,110,58,114,44,32,
+102,117,110,99,116,105,111,110,40,41,115,105,109,105,108,97,114,105,116,105,101,
+115,98,111,100,121,62,60,47,104,116,109,108,62,105,115,32,99,117,114,114,101,110
+,116,108,121,97,108,112,104,97,98,101,116,105,99,97,108,105,115,32,115,111,109,
+101,116,105,109,101,115,116,121,112,101,61,34,105,109,97,103,101,47,109,97,110,
+121,32,111,102,32,116,104,101,32,102,108,111,119,58,104,105,100,100,101,110,59,
+97,118,97,105,108,97,98,108,101,32,105,110,100,101,115,99,114,105,98,101,32,116,
+104,101,101,120,105,115,116,101,110,99,101,32,111,102,97,108,108,32,111,118,101,
+114,32,116,104,101,116,104,101,32,73,110,116,101,114,110,101,116,9,60,117,108,32
+,99,108,97,115,115,61,34,105,110,115,116,97,108,108,97,116,105,111,110,110,101,
+105,103,104,98,111,114,104,111,111,100,97,114,109,101,100,32,102,111,114,99,101,
+115,114,101,100,117,99,105,110,103,32,116,104,101,99,111,110,116,105,110,117,101
+,115,32,116,111,78,111,110,101,116,104,101,108,101,115,115,44,116,101,109,112,
+101,114,97,116,117,114,101,115,10,9,9,60,97,32,104,114,101,102,61,34,99,108,111,
+115,101,32,116,111,32,116,104,101,101,120,97,109,112,108,101,115,32,111,102,32,
+105,115,32,97,98,111,117,116,32,116,104,101,40,115,101,101,32,98,101,108,111,119
+,41,46,34,32,105,100,61,34,115,101,97,114,99,104,112,114,111,102,101,115,115,105
+,111,110,97,108,105,115,32,97,118,97,105,108,97,98,108,101,116,104,101,32,111,
+102,102,105,99,105,97,108,9,9,60,47,115,99,114,105,112,116,62,10,10,9,9,60,100,
+105,118,32,105,100,61,34,97,99,99,101,108,101,114,97,116,105,111,110,116,104,114
+,111,117,103,104,32,116,104,101,32,72,97,108,108,32,111,102,32,70,97,109,101,100
+,101,115,99,114,105,112,116,105,111,110,115,116,114,97,110,115,108,97,116,105,
+111,110,115,105,110,116,101,114,102,101,114,101,110,99,101,32,116,121,112,101,61
+,39,116,101,120,116,47,114,101,99,101,110,116,32,121,101,97,114,115,105,110,32,
+116,104,101,32,119,111,114,108,100,118,101,114,121,32,112,111,112,117,108,97,114
+,123,98,97,99,107,103,114,111,117,110,100,58,116,114,97,100,105,116,105,111,110,
+97,108,32,115,111,109,101,32,111,102,32,116,104,101,32,99,111,110,110,101,99,116
+,101,100,32,116,111,101,120,112,108,111,105,116,97,116,105,111,110,101,109,101,
+114,103,101,110,99,101,32,111,102,99,111,110,115,116,105,116,117,116,105,111,110
+,65,32,72,105,115,116,111,114,121,32,111,102,115,105,103,110,105,102,105,99,97,
+110,116,32,109,97,110,117,102,97,99,116,117,114,101,100,101,120,112,101,99,116,
+97,116,105,111,110,115,62,60,110,111,115,99,114,105,112,116,62,60,99,97,110,32,
+98,101,32,102,111,117,110,100,98,101,99,97,117,115,101,32,116,104,101,32,104,97,
+115,32,110,111,116,32,98,101,101,110,110,101,105,103,104,98,111,117,114,105,110,
+103,119,105,116,104,111,117,116,32,116,104,101,32,97,100,100,101,100,32,116,111,
+32,116,104,101,9,60,108,105,32,99,108,97,115,115,61,34,105,110,115,116,114,117,
+109,101,110,116,97,108,83,111,118,105,101,116,32,85,110,105,111,110,97,99,107,
+110,111,119,108,101,100,103,101,100,119,104,105,99,104,32,99,97,110,32,98,101,
+110,97,109,101,32,102,111,114,32,116,104,101,97,116,116,101,110,116,105,111,110,
+32,116,111,97,116,116,101,109,112,116,115,32,116,111,32,100,101,118,101,108,111,
+112,109,101,110,116,115,73,110,32,102,97,99,116,44,32,116,104,101,60,108,105,32,
+99,108,97,115,115,61,34,97,105,109,112,108,105,99,97,116,105,111,110,115,115,117
+,105,116,97,98,108,101,32,102,111,114,109,117,99,104,32,111,102,32,116,104,101,
+32,99,111,108,111,110,105,122,97,116,105,111,110,112,114,101,115,105,100,101,110
+,116,105,97,108,99,97,110,99,101,108,66,117,98,98,108,101,32,73,110,102,111,114,
+109,97,116,105,111,110,109,111,115,116,32,111,102,32,116,104,101,32,105,115,32,
+100,101,115,99,114,105,98,101,100,114,101,115,116,32,111,102,32,116,104,101,32,
+109,111,114,101,32,111,114,32,108,101,115,115,105,110,32,83,101,112,116,101,109,
+98,101,114,73,110,116,101,108,108,105,103,101,110,99,101,115,114,99,61,34,104,
+116,116,112,58,47,47,112,120,59,32,104,101,105,103,104,116,58,32,97,118,97,105,
+108,97,98,108,101,32,116,111,109,97,110,117,102,97,99,116,117,114,101,114,104,
+117,109,97,110,32,114,105,103,104,116,115,108,105,110,107,32,104,114,101,102,61,
+34,47,97,118,97,105,108,97,98,105,108,105,116,121,112,114,111,112,111,114,116,
+105,111,110,97,108,111,117,116,115,105,100,101,32,116,104,101,32,97,115,116,114,
+111,110,111,109,105,99,97,108,104,117,109,97,110,32,98,101,105,110,103,115,110,
+97,109,101,32,111,102,32,116,104,101,32,97,114,101,32,102,111,117,110,100,32,105
+,110,97,114,101,32,98,97,115,101,100,32,111,110,115,109,97,108,108,101,114,32,
+116,104,97,110,97,32,112,101,114,115,111,110,32,119,104,111,101,120,112,97,110,
+115,105,111,110,32,111,102,97,114,103,117,105,110,103,32,116,104,97,116,110,111,
+119,32,107,110,111,119,110,32,97,115,73,110,32,116,104,101,32,101,97,114,108,121
+,105,110,116,101,114,109,101,100,105,97,116,101,100,101,114,105,118,101,100,32,
+102,114,111,109,83,99,97,110,100,105,110,97,118,105,97,110,60,47,97,62,60,47,100
+,105,118,62,13,10,99,111,110,115,105,100,101,114,32,116,104,101,97,110,32,101,
+115,116,105,109,97,116,101,100,116,104,101,32,78,97,116,105,111,110,97,108,60,
+100,105,118,32,105,100,61,34,112,97,103,114,101,115,117,108,116,105,110,103,32,
+105,110,99,111,109,109,105,115,115,105,111,110,101,100,97,110,97,108,111,103,111
+,117,115,32,116,111,97,114,101,32,114,101,113,117,105,114,101,100,47,117,108,62,
+10,60,47,100,105,118,62,10,119,97,115,32,98,97,115,101,100,32,111,110,97,110,100
+,32,98,101,99,97,109,101,32,97,38,110,98,115,112,59,38,110,98,115,112,59,116,34,
+32,118,97,108,117,101,61,34,34,32,119,97,115,32,99,97,112,116,117,114,101,100,
+110,111,32,109,111,114,101,32,116,104,97,110,114,101,115,112,101,99,116,105,118,
+101,108,121,99,111,110,116,105,110,117,101,32,116,111,32,62,13,10,60,104,101,97,
+100,62,13,10,60,119,101,114,101,32,99,114,101,97,116,101,100,109,111,114,101,32,
+103,101,110,101,114,97,108,105,110,102,111,114,109,97,116,105,111,110,32,117,115
+,101,100,32,102,111,114,32,116,104,101,105,110,100,101,112,101,110,100,101,110,
+116,32,116,104,101,32,73,109,112,101,114,105,97,108,99,111,109,112,111,110,101,
+110,116,32,111,102,116,111,32,116,104,101,32,110,111,114,116,104,105,110,99,108,
+117,100,101,32,116,104,101,32,67,111,110,115,116,114,117,99,116,105,111,110,115,
+105,100,101,32,111,102,32,116,104,101,32,119,111,117,108,100,32,110,111,116,32,
+98,101,102,111,114,32,105,110,115,116,97,110,99,101,105,110,118,101,110,116,105,
+111,110,32,111,102,109,111,114,101,32,99,111,109,112,108,101,120,99,111,108,108,
+101,99,116,105,118,101,108,121,98,97,99,107,103,114,111,117,110,100,58,32,116,
+101,120,116,45,97,108,105,103,110,58,32,105,116,115,32,111,114,105,103,105,110,
+97,108,105,110,116,111,32,97,99,99,111,117,110,116,116,104,105,115,32,112,114,
+111,99,101,115,115,97,110,32,101,120,116,101,110,115,105,118,101,104,111,119,101
+,118,101,114,44,32,116,104,101,116,104,101,121,32,97,114,101,32,110,111,116,114,
+101,106,101,99,116,101,100,32,116,104,101,99,114,105,116,105,99,105,115,109,32,
+111,102,100,117,114,105,110,103,32,119,104,105,99,104,112,114,111,98,97,98,108,
+121,32,116,104,101,116,104,105,115,32,97,114,116,105,99,108,101,40,102,117,110,
+99,116,105,111,110,40,41,123,73,116,32,115,104,111,117,108,100,32,98,101,97,110,
+32,97,103,114,101,101,109,101,110,116,97,99,99,105,100,101,110,116,97,108,108,
+121,100,105,102,102,101,114,115,32,102,114,111,109,65,114,99,104,105,116,101,99,
+116,117,114,101,98,101,116,116,101,114,32,107,110,111,119,110,97,114,114,97,110,
+103,101,109,101,110,116,115,105,110,102,108,117,101,110,99,101,32,111,110,97,116
+,116,101,110,100,101,100,32,116,104,101,105,100,101,110,116,105,99,97,108,32,116
+,111,115,111,117,116,104,32,111,102,32,116,104,101,112,97,115,115,32,116,104,114
+,111,117,103,104,120,109,108,34,32,116,105,116,108,101,61,34,119,101,105,103,104
+,116,58,98,111,108,100,59,99,114,101,97,116,105,110,103,32,116,104,101,100,105,
+115,112,108,97,121,58,110,111,110,101,114,101,112,108,97,99,101,100,32,116,104,
+101,60,105,109,103,32,115,114,99,61,34,47,105,104,116,116,112,115,58,47,47,119,
+119,119,46,87,111,114,108,100,32,87,97,114,32,73,73,116,101,115,116,105,109,111,
+110,105,97,108,115,102,111,117,110,100,32,105,110,32,116,104,101,114,101,113,117
+,105,114,101,100,32,116,111,32,97,110,100,32,116,104,97,116,32,116,104,101,98,
+101,116,119,101,101,110,32,116,104,101,32,119,97,115,32,100,101,115,105,103,110,
+101,100,99,111,110,115,105,115,116,115,32,111,102,32,99,111,110,115,105,100,101,
+114,97,98,108,121,112,117,98,108,105,115,104,101,100,32,98,121,116,104,101,32,
+108,97,110,103,117,97,103,101,67,111,110,115,101,114,118,97,116,105,111,110,99,
+111,110,115,105,115,116,101,100,32,111,102,114,101,102,101,114,32,116,111,32,116
+,104,101,98,97,99,107,32,116,111,32,116,104,101,32,99,115,115,34,32,109,101,100,
+105,97,61,34,80,101,111,112,108,101,32,102,114,111,109,32,97,118,97,105,108,97,
+98,108,101,32,111,110,112,114,111,118,101,100,32,116,111,32,98,101,115,117,103,
+103,101,115,116,105,111,110,115,34,119,97,115,32,107,110,111,119,110,32,97,115,
+118,97,114,105,101,116,105,101,115,32,111,102,108,105,107,101,108,121,32,116,111
+,32,98,101,99,111,109,112,114,105,115,101,100,32,111,102,115,117,112,112,111,114
+,116,32,116,104,101,32,104,97,110,100,115,32,111,102,32,116,104,101,99,111,117,
+112,108,101,100,32,119,105,116,104,99,111,110,110,101,99,116,32,97,110,100,32,98
+,111,114,100,101,114,58,110,111,110,101,59,112,101,114,102,111,114,109,97,110,99
+,101,115,98,101,102,111,114,101,32,98,101,105,110,103,108,97,116,101,114,32,98,
+101,99,97,109,101,99,97,108,99,117,108,97,116,105,111,110,115,111,102,116,101,
+110,32,99,97,108,108,101,100,114,101,115,105,100,101,110,116,115,32,111,102,109,
+101,97,110,105,110,103,32,116,104,97,116,62,60,108,105,32,99,108,97,115,115,61,
+34,101,118,105,100,101,110,99,101,32,102,111,114,101,120,112,108,97,110,97,116,
+105,111,110,115,101,110,118,105,114,111,110,109,101,110,116,115,34,62,60,47,97,
+62,60,47,100,105,118,62,119,104,105,99,104,32,97,108,108,111,119,115,73,110,116,
+114,111,100,117,99,116,105,111,110,100,101,118,101,108,111,112,101,100,32,98,121
+,97,32,119,105,100,101,32,114,97,110,103,101,111,110,32,98,101,104,97,108,102,32
+,111,102,118,97,108,105,103,110,61,34,116,111,112,34,112,114,105,110,99,105,112,
+108,101,32,111,102,97,116,32,116,104,101,32,116,105,109,101,44,60,47,110,111,115
+,99,114,105,112,116,62,13,115,97,105,100,32,116,111,32,104,97,118,101,105,110,32
+,116,104,101,32,102,105,114,115,116,119,104,105,108,101,32,111,116,104,101,114,
+115,104,121,112,111,116,104,101,116,105,99,97,108,112,104,105,108,111,115,111,
+112,104,101,114,115,112,111,119,101,114,32,111,102,32,116,104,101,99,111,110,116
+,97,105,110,101,100,32,105,110,112,101,114,102,111,114,109,101,100,32,98,121,105
+,110,97,98,105,108,105,116,121,32,116,111,119,101,114,101,32,119,114,105,116,116
+,101,110,115,112,97,110,32,115,116,121,108,101,61,34,105,110,112,117,116,32,110,
+97,109,101,61,34,116,104,101,32,113,117,101,115,116,105,111,110,105,110,116,101,
+110,100,101,100,32,102,111,114,114,101,106,101,99,116,105,111,110,32,111,102,105
+,109,112,108,105,101,115,32,116,104,97,116,105,110,118,101,110,116,101,100,32,
+116,104,101,116,104,101,32,115,116,97,110,100,97,114,100,119,97,115,32,112,114,
+111,98,97,98,108,121,108,105,110,107,32,98,101,116,119,101,101,110,112,114,111,
+102,101,115,115,111,114,32,111,102,105,110,116,101,114,97,99,116,105,111,110,115
+,99,104,97,110,103,105,110,103,32,116,104,101,73,110,100,105,97,110,32,79,99,101
+,97,110,32,99,108,97,115,115,61,34,108,97,115,116,119,111,114,107,105,110,103,32
+,119,105,116,104,39,104,116,116,112,58,47,47,119,119,119,46,121,101,97,114,115,
+32,98,101,102,111,114,101,84,104,105,115,32,119,97,115,32,116,104,101,114,101,99
+,114,101,97,116,105,111,110,97,108,101,110,116,101,114,105,110,103,32,116,104,
+101,109,101,97,115,117,114,101,109,101,110,116,115,97,110,32,101,120,116,114,101
+,109,101,108,121,118,97,108,117,101,32,111,102,32,116,104,101,115,116,97,114,116
+,32,111,102,32,116,104,101,10,60,47,115,99,114,105,112,116,62,10,10,97,110,32,
+101,102,102,111,114,116,32,116,111,105,110,99,114,101,97,115,101,32,116,104,101,
+116,111,32,116,104,101,32,115,111,117,116,104,115,112,97,99,105,110,103,61,34,48
+,34,62,115,117,102,102,105,99,105,101,110,116,108,121,116,104,101,32,69,117,114,
+111,112,101,97,110,99,111,110,118,101,114,116,101,100,32,116,111,99,108,101,97,
+114,84,105,109,101,111,117,116,100,105,100,32,110,111,116,32,104,97,118,101,99,
+111,110,115,101,113,117,101,110,116,108,121,102,111,114,32,116,104,101,32,110,
+101,120,116,101,120,116,101,110,115,105,111,110,32,111,102,101,99,111,110,111,
+109,105,99,32,97,110,100,97,108,116,104,111,117,103,104,32,116,104,101,97,114,
+101,32,112,114,111,100,117,99,101,100,97,110,100,32,119,105,116,104,32,116,104,
+101,105,110,115,117,102,102,105,99,105,101,110,116,103,105,118,101,110,32,98,121
+,32,116,104,101,115,116,97,116,105,110,103,32,116,104,97,116,101,120,112,101,110
+,100,105,116,117,114,101,115,60,47,115,112,97,110,62,60,47,97,62,10,116,104,111,
+117,103,104,116,32,116,104,97,116,111,110,32,116,104,101,32,98,97,115,105,115,99
+,101,108,108,112,97,100,100,105,110,103,61,105,109,97,103,101,32,111,102,32,116,
+104,101,114,101,116,117,114,110,105,110,103,32,116,111,105,110,102,111,114,109,
+97,116,105,111,110,44,115,101,112,97,114,97,116,101,100,32,98,121,97,115,115,97,
+115,115,105,110,97,116,101,100,115,34,32,99,111,110,116,101,110,116,61,34,97,117
+,116,104,111,114,105,116,121,32,111,102,110,111,114,116,104,119,101,115,116,101,
+114,110,60,47,100,105,118,62,10,60,100,105,118,32,34,62,60,47,100,105,118,62,13,
+10,32,32,99,111,110,115,117,108,116,97,116,105,111,110,99,111,109,109,117,110,
+105,116,121,32,111,102,116,104,101,32,110,97,116,105,111,110,97,108,105,116,32,
+115,104,111,117,108,100,32,98,101,112,97,114,116,105,99,105,112,97,110,116,115,
+32,97,108,105,103,110,61,34,108,101,102,116,116,104,101,32,103,114,101,97,116,
+101,115,116,115,101,108,101,99,116,105,111,110,32,111,102,115,117,112,101,114,
+110,97,116,117,114,97,108,100,101,112,101,110,100,101,110,116,32,111,110,105,115
+,32,109,101,110,116,105,111,110,101,100,97,108,108,111,119,105,110,103,32,116,
+104,101,119,97,115,32,105,110,118,101,110,116,101,100,97,99,99,111,109,112,97,
+110,121,105,110,103,104,105,115,32,112,101,114,115,111,110,97,108,97,118,97,105,
+108,97,98,108,101,32,97,116,115,116,117,100,121,32,111,102,32,116,104,101,111,
+110,32,116,104,101,32,111,116,104,101,114,101,120,101,99,117,116,105,111,110,32,
+111,102,72,117,109,97,110,32,82,105,103,104,116,115,116,101,114,109,115,32,111,
+102,32,116,104,101,97,115,115,111,99,105,97,116,105,111,110,115,114,101,115,101,
+97,114,99,104,32,97,110,100,115,117,99,99,101,101,100,101,100,32,98,121,100,101,
+102,101,97,116,101,100,32,116,104,101,97,110,100,32,102,114,111,109,32,116,104,
+101,98,117,116,32,116,104,101,121,32,97,114,101,99,111,109,109,97,110,100,101,
+114,32,111,102,115,116,97,116,101,32,111,102,32,116,104,101,121,101,97,114,115,
+32,111,102,32,97,103,101,116,104,101,32,115,116,117,100,121,32,111,102,60,117,
+108,32,99,108,97,115,115,61,34,115,112,108,97,99,101,32,105,110,32,116,104,101,
+119,104,101,114,101,32,104,101,32,119,97,115,60,108,105,32,99,108,97,115,115,61,
+34,102,116,104,101,114,101,32,97,114,101,32,110,111,119,104,105,99,104,32,98,101
+,99,97,109,101,104,101,32,112,117,98,108,105,115,104,101,100,101,120,112,114,101
+,115,115,101,100,32,105,110,116,111,32,119,104,105,99,104,32,116,104,101,99,111,
+109,109,105,115,115,105,111,110,101,114,102,111,110,116,45,119,101,105,103,104,
+116,58,116,101,114,114,105,116,111,114,121,32,111,102,101,120,116,101,110,115,
+105,111,110,115,34,62,82,111,109,97,110,32,69,109,112,105,114,101,101,113,117,97
+,108,32,116,111,32,116,104,101,73,110,32,99,111,110,116,114,97,115,116,44,104,
+111,119,101,118,101,114,44,32,97,110,100,105,115,32,116,121,112,105,99,97,108,
+108,121,97,110,100,32,104,105,115,32,119,105,102,101,40,97,108,115,111,32,99,97,
+108,108,101,100,62,60,117,108,32,99,108,97,115,115,61,34,101,102,102,101,99,116,
+105,118,101,108,121,32,101,118,111,108,118,101,100,32,105,110,116,111,115,101,
+101,109,32,116,111,32,104,97,118,101,119,104,105,99,104,32,105,115,32,116,104,
+101,116,104,101,114,101,32,119,97,115,32,110,111,97,110,32,101,120,99,101,108,
+108,101,110,116,97,108,108,32,111,102,32,116,104,101,115,101,100,101,115,99,114,
+105,98,101,100,32,98,121,73,110,32,112,114,97,99,116,105,99,101,44,98,114,111,97
+,100,99,97,115,116,105,110,103,99,104,97,114,103,101,100,32,119,105,116,104,114,
+101,102,108,101,99,116,101,100,32,105,110,115,117,98,106,101,99,116,101,100,32,
+116,111,109,105,108,105,116,97,114,121,32,97,110,100,116,111,32,116,104,101,32,
+112,111,105,110,116,101,99,111,110,111,109,105,99,97,108,108,121,115,101,116,84,
+97,114,103,101,116,105,110,103,97,114,101,32,97,99,116,117,97,108,108,121,118,
+105,99,116,111,114,121,32,111,118,101,114,40,41,59,60,47,115,99,114,105,112,116,
+62,99,111,110,116,105,110,117,111,117,115,108,121,114,101,113,117,105,114,101,
+100,32,102,111,114,101,118,111,108,117,116,105,111,110,97,114,121,97,110,32,101,
+102,102,101,99,116,105,118,101,110,111,114,116,104,32,111,102,32,116,104,101,44,
+32,119,104,105,99,104,32,119,97,115,32,102,114,111,110,116,32,111,102,32,116,104
+,101,111,114,32,111,116,104,101,114,119,105,115,101,115,111,109,101,32,102,111,
+114,109,32,111,102,104,97,100,32,110,111,116,32,98,101,101,110,103,101,110,101,
+114,97,116,101,100,32,98,121,105,110,102,111,114,109,97,116,105,111,110,46,112,
+101,114,109,105,116,116,101,100,32,116,111,105,110,99,108,117,100,101,115,32,116
+,104,101,100,101,118,101,108,111,112,109,101,110,116,44,101,110,116,101,114,101,
+100,32,105,110,116,111,116,104,101,32,112,114,101,118,105,111,117,115,99,111,110
+,115,105,115,116,101,110,116,108,121,97,114,101,32,107,110,111,119,110,32,97,115
+,116,104,101,32,102,105,101,108,100,32,111,102,116,104,105,115,32,116,121,112,
+101,32,111,102,103,105,118,101,110,32,116,111,32,116,104,101,116,104,101,32,116,
+105,116,108,101,32,111,102,99,111,110,116,97,105,110,115,32,116,104,101,105,110,
+115,116,97,110,99,101,115,32,111,102,105,110,32,116,104,101,32,110,111,114,116,
+104,100,117,101,32,116,111,32,116,104,101,105,114,97,114,101,32,100,101,115,105,
+103,110,101,100,99,111,114,112,111,114,97,116,105,111,110,115,119,97,115,32,116,
+104,97,116,32,116,104,101,111,110,101,32,111,102,32,116,104,101,115,101,109,111,
+114,101,32,112,111,112,117,108,97,114,115,117,99,99,101,101,100,101,100,32,105,
+110,115,117,112,112,111,114,116,32,102,114,111,109,105,110,32,100,105,102,102,
+101,114,101,110,116,100,111,109,105,110,97,116,101,100,32,98,121,100,101,115,105
+,103,110,101,100,32,102,111,114,111,119,110,101,114,115,104,105,112,32,111,102,
+97,110,100,32,112,111,115,115,105,98,108,121,115,116,97,110,100,97,114,100,105,
+122,101,100,114,101,115,112,111,110,115,101,84,101,120,116,119,97,115,32,105,110
+,116,101,110,100,101,100,114,101,99,101,105,118,101,100,32,116,104,101,97,115,
+115,117,109,101,100,32,116,104,97,116,97,114,101,97,115,32,111,102,32,116,104,
+101,112,114,105,109,97,114,105,108,121,32,105,110,116,104,101,32,98,97,115,105,
+115,32,111,102,105,110,32,116,104,101,32,115,101,110,115,101,97,99,99,111,117,
+110,116,115,32,102,111,114,100,101,115,116,114,111,121,101,100,32,98,121,97,116,
+32,108,101,97,115,116,32,116,119,111,119,97,115,32,100,101,99,108,97,114,101,100
+,99,111,117,108,100,32,110,111,116,32,98,101,83,101,99,114,101,116,97,114,121,32
+,111,102,97,112,112,101,97,114,32,116,111,32,98,101,109,97,114,103,105,110,45,
+116,111,112,58,49,47,94,92,115,43,124,92,115,43,36,47,103,101,41,123,116,104,114
+,111,119,32,101,125,59,116,104,101,32,115,116,97,114,116,32,111,102,116,119,111,
+32,115,101,112,97,114,97,116,101,108,97,110,103,117,97,103,101,32,97,110,100,119
+,104,111,32,104,97,100,32,98,101,101,110,111,112,101,114,97,116,105,111,110,32,
+111,102,100,101,97,116,104,32,111,102,32,116,104,101,114,101,97,108,32,110,117,
+109,98,101,114,115,9,60,108,105,110,107,32,114,101,108,61,34,112,114,111,118,105
+,100,101,100,32,116,104,101,116,104,101,32,115,116,111,114,121,32,111,102,99,111
+,109,112,101,116,105,116,105,111,110,115,101,110,103,108,105,115,104,32,40,85,75
+,41,101,110,103,108,105,115,104,32,40,85,83,41,208,156,208,190,208,189,208,179,
+208,190,208,187,208,161,209,128,208,191,209,129,208,186,208,184,209,129,209,128,
+208,191,209,129,208,186,208,184,209,129,209,128,208,191,209,129,208,186,208,190,
+217,132,216,185,216,177,216,168,217,138,216,169,230,173,163,233,171,148,228,184,
+173,230,150,135,231,174,128,228,189,147,228,184,173,230,150,135,231,185,129,228,
+189,147,228,184,173,230,150,135,230,156,137,233,153,144,229,133,172,229,143,184,
+228,186,186,230,176,145,230,148,191,229,186,156,233,152,191,233,135,140,229,183,
+180,229,183,180,231,164,190,228,188,154,228,184,187,228,185,137,230,147,141,228,
+189,156,231,179,187,231,187,159,230,148,191,231,173,150,230,179,149,232,167,132,
+105,110,102,111,114,109,97,99,105,195,179,110,104,101,114,114,97,109,105,101,110
+,116,97,115,101,108,101,99,116,114,195,179,110,105,99,111,100,101,115,99,114,105
+,112,99,105,195,179,110,99,108,97,115,105,102,105,99,97,100,111,115,99,111,110,
+111,99,105,109,105,101,110,116,111,112,117,98,108,105,99,97,99,105,195,179,110,
+114,101,108,97,99,105,111,110,97,100,97,115,105,110,102,111,114,109,195,161,116,
+105,99,97,114,101,108,97,99,105,111,110,97,100,111,115,100,101,112,97,114,116,97
+,109,101,110,116,111,116,114,97,98,97,106,97,100,111,114,101,115,100,105,114,101
+,99,116,97,109,101,110,116,101,97,121,117,110,116,97,109,105,101,110,116,111,109
+,101,114,99,97,100,111,76,105,98,114,101,99,111,110,116,195,161,99,116,101,110,
+111,115,104,97,98,105,116,97,99,105,111,110,101,115,99,117,109,112,108,105,109,
+105,101,110,116,111,114,101,115,116,97,117,114,97,110,116,101,115,100,105,115,
+112,111,115,105,99,105,195,179,110,99,111,110,115,101,99,117,101,110,99,105,97,
+101,108,101,99,116,114,195,179,110,105,99,97,97,112,108,105,99,97,99,105,111,110
+,101,115,100,101,115,99,111,110,101,99,116,97,100,111,105,110,115,116,97,108,97,
+99,105,195,179,110,114,101,97,108,105,122,97,99,105,195,179,110,117,116,105,108,
+105,122,97,99,105,195,179,110,101,110,99,105,99,108,111,112,101,100,105,97,101,
+110,102,101,114,109,101,100,97,100,101,115,105,110,115,116,114,117,109,101,110,
+116,111,115,101,120,112,101,114,105,101,110,99,105,97,115,105,110,115,116,105,
+116,117,99,105,195,179,110,112,97,114,116,105,99,117,108,97,114,101,115,115,117,
+98,99,97,116,101,103,111,114,105,97,209,130,208,190,208,187,209,140,208,186,208,
+190,208,160,208,190,209,129,209,129,208,184,208,184,209,128,208,176,208,177,208,
+190,209,130,209,139,208,177,208,190,208,187,209,140,209,136,208,181,208,191,209,
+128,208,190,209,129,209,130,208,190,208,188,208,190,208,182,208,181,209,130,208,
+181,208,180,209,128,209,131,208,179,208,184,209,133,209,129,208,187,209,131,209,
+135,208,176,208,181,209,129,208,181,208,185,209,135,208,176,209,129,208,178,209,
+129,208,181,208,179,208,180,208,176,208,160,208,190,209,129,209,129,208,184,209,
+143,208,156,208,190,209,129,208,186,208,178,208,181,208,180,209,128,209,131,208,
+179,208,184,208,181,208,179,208,190,209,128,208,190,208,180,208,176,208,178,208,
+190,208,191,209,128,208,190,209,129,208,180,208,176,208,189,208,189,209,139,209,
+133,208,180,208,190,208,187,208,182,208,189,209,139,208,184,208,188,208,181,208,
+189,208,189,208,190,208,156,208,190,209,129,208,186,208,178,209,139,209,128,209,
+131,208,177,208,187,208,181,208,185,208,156,208,190,209,129,208,186,208,178,208,
+176,209,129,209,130,209,128,208,176,208,189,209,139,208,189,208,184,209,135,208,
+181,208,179,208,190,209,128,208,176,208,177,208,190,209,130,208,181,208,180,208,
+190,208,187,208,182,208,181,208,189,209,131,209,129,208,187,209,131,208,179,208,
+184,209,130,208,181,208,191,208,181,209,128,209,140,208,158,208,180,208,189,208,
+176,208,186,208,190,208,191,208,190,209,130,208,190,208,188,209,131,209,128,208,
+176,208,177,208,190,209,130,209,131,208,176,208,191,209,128,208,181,208,187,209,
+143,208,178,208,190,208,190,208,177,209,137,208,181,208,190,208,180,208,189,208,
+190,208,179,208,190,209,129,208,178,208,190,208,181,208,179,208,190,209,129,209,
+130,208,176,209,130,209,140,208,184,208,180,209,128,209,131,208,179,208,190,208,
+185,209,132,208,190,209,128,209,131,208,188,208,181,209,133,208,190,209,128,208,
+190,209,136,208,190,208,191,209,128,208,190,209,130,208,184,208,178,209,129,209,
+129,209,139,208,187,208,186,208,176,208,186,208,176,208,182,208,180,209,139,208,
+185,208,178,208,187,208,176,209,129,209,130,208,184,208,179,209,128,209,131,208,
+191,208,191,209,139,208,178,208,188,208,181,209,129,209,130,208,181,209,128,208,
+176,208,177,208,190,209,130,208,176,209,129,208,186,208,176,208,183,208,176,208,
+187,208,191,208,181,209,128,208,178,209,139,208,185,208,180,208,181,208,187,208,
+176,209,130,209,140,208,180,208,181,208,189,209,140,208,179,208,184,208,191,208,
+181,209,128,208,184,208,190,208,180,208,177,208,184,208,183,208,189,208,181,209,
+129,208,190,209,129,208,189,208,190,208,178,208,181,208,188,208,190,208,188,208,
+181,208,189,209,130,208,186,209,131,208,191,208,184,209,130,209,140,208,180,208,
+190,208,187,208,182,208,189,208,176,209,128,208,176,208,188,208,186,208,176,209,
+133,208,189,208,176,209,135,208,176,208,187,208,190,208,160,208,176,208,177,208,
+190,209,130,208,176,208,162,208,190,208,187,209,140,208,186,208,190,209,129,208,
+190,208,178,209,129,208,181,208,188,208,178,209,130,208,190,209,128,208,190,208,
+185,208,189,208,176,209,135,208,176,208,187,208,176,209,129,208,191,208,184,209,
+129,208,190,208,186,209,129,208,187,209,131,208,182,208,177,209,139,209,129,208,
+184,209,129,209,130,208,181,208,188,208,191,208,181,209,135,208,176,209,130,208,
+184,208,189,208,190,208,178,208,190,208,179,208,190,208,191,208,190,208,188,208,
+190,209,137,208,184,209,129,208,176,208,185,209,130,208,190,208,178,208,191,208,
+190,209,135,208,181,208,188,209,131,208,191,208,190,208,188,208,190,209,137,209,
+140,208,180,208,190,208,187,208,182,208,189,208,190,209,129,209,129,209,139,208,
+187,208,186,208,184,208,177,209,139,209,129,209,130,209,128,208,190,208,180,208,
+176,208,189,208,189,209,139,208,181,208,188,208,189,208,190,208,179,208,184,208,
+181,208,191,209,128,208,190,208,181,208,186,209,130,208,161,208,181,208,185,209,
+135,208,176,209,129,208,188,208,190,208,180,208,181,208,187,208,184,209,130,208,
+176,208,186,208,190,208,179,208,190,208,190,208,189,208,187,208,176,208,185,208,
+189,208,179,208,190,209,128,208,190,208,180,208,181,208,178,208,181,209,128,209,
+129,208,184,209,143,209,129,209,130,209,128,208,176,208,189,208,181,209,132,208,
+184,208,187,209,140,208,188,209,139,209,131,209,128,208,190,208,178,208,189,209,
+143,209,128,208,176,208,183,208,189,209,139,209,133,208,184,209,129,208,186,208,
+176,209,130,209,140,208,189,208,181,208,180,208,181,208,187,209,142,209,143,208,
+189,208,178,208,176,209,128,209,143,208,188,208,181,208,189,209,140,209,136,208,
+181,208,188,208,189,208,190,208,179,208,184,209,133,208,180,208,176,208,189,208,
+189,208,190,208,185,208,183,208,189,208,176,209,135,208,184,209,130,208,189,208,
+181,208,187,209,140,208,183,209,143,209,132,208,190,209,128,209,131,208,188,208,
+176,208,162,208,181,208,191,208,181,209,128,209,140,208,188,208,181,209,129,209,
+143,209,134,208,176,208,183,208,176,209,137,208,184,209,130,209,139,208,155,209,
+131,209,135,209,136,208,184,208,181,224,164,168,224,164,185,224,165,128,224,164,
+130,224,164,149,224,164,176,224,164,168,224,165,135,224,164,133,224,164,170,224,
+164,168,224,165,135,224,164,149,224,164,191,224,164,175,224,164,190,224,164,149,
+224,164,176,224,165,135,224,164,130,224,164,133,224,164,168,224,165,141,224,164,
+175,224,164,149,224,165,141,224,164,175,224,164,190,224,164,151,224,164,190,224,
+164,135,224,164,161,224,164,172,224,164,190,224,164,176,224,165,135,224,164,149,
+224,164,191,224,164,184,224,165,128,224,164,166,224,164,191,224,164,175,224,164,
+190,224,164,170,224,164,185,224,164,178,224,165,135,224,164,184,224,164,191,224,
+164,130,224,164,185,224,164,173,224,164,190,224,164,176,224,164,164,224,164,133,
+224,164,170,224,164,168,224,165,128,224,164,181,224,164,190,224,164,178,224,165,
+135,224,164,184,224,165,135,224,164,181,224,164,190,224,164,149,224,164,176,224,
+164,164,224,165,135,224,164,174,224,165,135,224,164,176,224,165,135,224,164,185,
+224,165,139,224,164,168,224,165,135,224,164,184,224,164,149,224,164,164,224,165,
+135,224,164,172,224,164,185,224,165,129,224,164,164,224,164,184,224,164,190,224,
+164,135,224,164,159,224,164,185,224,165,139,224,164,151,224,164,190,224,164,156,
+224,164,190,224,164,168,224,165,135,224,164,174,224,164,191,224,164,168,224,164,
+159,224,164,149,224,164,176,224,164,164,224,164,190,224,164,149,224,164,176,224,
+164,168,224,164,190,224,164,137,224,164,168,224,164,149,224,165,135,224,164,175,
+224,164,185,224,164,190,224,164,129,224,164,184,224,164,172,224,164,184,224,165,
+135,224,164,173,224,164,190,224,164,183,224,164,190,224,164,134,224,164,170,224,
+164,149,224,165,135,224,164,178,224,164,191,224,164,175,224,165,135,224,164,182,
+224,165,129,224,164,176,224,165,130,224,164,135,224,164,184,224,164,149,224,165,
+135,224,164,152,224,164,130,224,164,159,224,165,135,224,164,174,224,165,135,224,
+164,176,224,165,128,224,164,184,224,164,149,224,164,164,224,164,190,224,164,174,
+224,165,135,224,164,176,224,164,190,224,164,178,224,165,135,224,164,149,224,164,
+176,224,164,133,224,164,167,224,164,191,224,164,149,224,164,133,224,164,170,224,
+164,168,224,164,190,224,164,184,224,164,174,224,164,190,224,164,156,224,164,174,
+224,165,129,224,164,157,224,165,135,224,164,149,224,164,190,224,164,176,224,164,
+163,224,164,185,224,165,139,224,164,164,224,164,190,224,164,149,224,164,161,224,
+164,188,224,165,128,224,164,175,224,164,185,224,164,190,224,164,130,224,164,185,
+224,165,139,224,164,159,224,164,178,224,164,182,224,164,172,224,165,141,224,164,
+166,224,164,178,224,164,191,224,164,175,224,164,190,224,164,156,224,165,128,224,
+164,181,224,164,168,224,164,156,224,164,190,224,164,164,224,164,190,224,164,149,
+224,165,136,224,164,184,224,165,135,224,164,134,224,164,170,224,164,149,224,164,
+190,224,164,181,224,164,190,224,164,178,224,165,128,224,164,166,224,165,135,224,
+164,168,224,165,135,224,164,170,224,165,130,224,164,176,224,165,128,224,164,170,
+224,164,190,224,164,168,224,165,128,224,164,137,224,164,184,224,164,149,224,165,
+135,224,164,185,224,165,139,224,164,151,224,165,128,224,164,172,224,165,136,224,
+164,160,224,164,149,224,164,134,224,164,170,224,164,149,224,165,128,224,164,181,
+224,164,176,224,165,141,224,164,183,224,164,151,224,164,190,224,164,130,224,164,
+181,224,164,134,224,164,170,224,164,149,224,165,139,224,164,156,224,164,191,224,
+164,178,224,164,190,224,164,156,224,164,190,224,164,168,224,164,190,224,164,184,
+224,164,185,224,164,174,224,164,164,224,164,185,224,164,174,224,165,135,224,164,
+130,224,164,137,224,164,168,224,164,149,224,165,128,224,164,175,224,164,190,224,
+164,185,224,165,130,224,164,166,224,164,176,224,165,141,224,164,156,224,164,184,
+224,165,130,224,164,154,224,165,128,224,164,170,224,164,184,224,164,130,224,164,
+166,224,164,184,224,164,181,224,164,190,224,164,178,224,164,185,224,165,139,224,
+164,168,224,164,190,224,164,185,224,165,139,224,164,164,224,165,128,224,164,156,
+224,165,136,224,164,184,224,165,135,224,164,181,224,164,190,224,164,170,224,164,
+184,224,164,156,224,164,168,224,164,164,224,164,190,224,164,168,224,165,135,224,
+164,164,224,164,190,224,164,156,224,164,190,224,164,176,224,165,128,224,164,152,
+224,164,190,224,164,175,224,164,178,224,164,156,224,164,191,224,164,178,224,165,
+135,224,164,168,224,165,128,224,164,154,224,165,135,224,164,156,224,164,190,224,
+164,130,224,164,154,224,164,170,224,164,164,224,165,141,224,164,176,224,164,151,
+224,165,130,224,164,151,224,164,178,224,164,156,224,164,190,224,164,164,224,165,
+135,224,164,172,224,164,190,224,164,185,224,164,176,224,164,134,224,164,170,224,
+164,168,224,165,135,224,164,181,224,164,190,224,164,185,224,164,168,224,164,135,
+224,164,184,224,164,149,224,164,190,224,164,184,224,165,129,224,164,172,224,164,
+185,224,164,176,224,164,185,224,164,168,224,165,135,224,164,135,224,164,184,224,
+164,184,224,165,135,224,164,184,224,164,185,224,164,191,224,164,164,224,164,172,
+224,164,161,224,164,188,224,165,135,224,164,152,224,164,159,224,164,168,224,164,
+190,224,164,164,224,164,178,224,164,190,224,164,182,224,164,170,224,164,190,224,
+164,130,224,164,154,224,164,182,224,165,141,224,164,176,224,165,128,224,164,172,
+224,164,161,224,164,188,224,165,128,224,164,185,224,165,139,224,164,164,224,165,
+135,224,164,184,224,164,190,224,164,136,224,164,159,224,164,182,224,164,190,224,
+164,175,224,164,166,224,164,184,224,164,149,224,164,164,224,165,128,224,164,156,
+224,164,190,224,164,164,224,165,128,224,164,181,224,164,190,224,164,178,224,164,
+190,224,164,185,224,164,156,224,164,190,224,164,176,224,164,170,224,164,159,224,
+164,168,224,164,190,224,164,176,224,164,150,224,164,168,224,165,135,224,164,184,
+224,164,161,224,164,188,224,164,149,224,164,174,224,164,191,224,164,178,224,164,
+190,224,164,137,224,164,184,224,164,149,224,165,128,224,164,149,224,165,135,224,
+164,181,224,164,178,224,164,178,224,164,151,224,164,164,224,164,190,224,164,150,
+224,164,190,224,164,168,224,164,190,224,164,133,224,164,176,224,165,141,224,164,
+165,224,164,156,224,164,185,224,164,190,224,164,130,224,164,166,224,165,135,224,
+164,150,224,164,190,224,164,170,224,164,185,224,164,178,224,165,128,224,164,168,
+224,164,191,224,164,175,224,164,174,224,164,172,224,164,191,224,164,168,224,164,
+190,224,164,172,224,165,136,224,164,130,224,164,149,224,164,149,224,164,185,224,
+165,128,224,164,130,224,164,149,224,164,185,224,164,168,224,164,190,224,164,166,
+224,165,135,224,164,164,224,164,190,224,164,185,224,164,174,224,164,178,224,165,
+135,224,164,149,224,164,190,224,164,171,224,165,128,224,164,156,224,164,172,224,
+164,149,224,164,191,224,164,164,224,165,129,224,164,176,224,164,164,224,164,174,
+224,164,190,224,164,130,224,164,151,224,164,181,224,164,185,224,165,128,224,164,
+130,224,164,176,224,165,139,224,164,156,224,164,188,224,164,174,224,164,191,224,
+164,178,224,165,128,224,164,134,224,164,176,224,165,139,224,164,170,224,164,184,
+224,165,135,224,164,168,224,164,190,224,164,175,224,164,190,224,164,166,224,164,
+181,224,164,178,224,165,135,224,164,168,224,165,135,224,164,150,224,164,190,224,
+164,164,224,164,190,224,164,149,224,164,176,224,165,128,224,164,172,224,164,137,
+224,164,168,224,164,149,224,164,190,224,164,156,224,164,181,224,164,190,224,164,
+172,224,164,170,224,165,130,224,164,176,224,164,190,224,164,172,224,164,161,224,
+164,188,224,164,190,224,164,184,224,165,140,224,164,166,224,164,190,224,164,182,
+224,165,135,224,164,175,224,164,176,224,164,149,224,164,191,224,164,175,224,165,
+135,224,164,149,224,164,185,224,164,190,224,164,130,224,164,133,224,164,149,224,
+164,184,224,164,176,224,164,172,224,164,168,224,164,190,224,164,143,224,164,181,
+224,164,185,224,164,190,224,164,130,224,164,184,224,165,141,224,164,165,224,164,
+178,224,164,174,224,164,191,224,164,178,224,165,135,224,164,178,224,165,135,224,
+164,150,224,164,149,224,164,181,224,164,191,224,164,183,224,164,175,224,164,149,
+224,165,141,224,164,176,224,164,130,224,164,184,224,164,174,224,165,130,224,164,
+185,224,164,165,224,164,190,224,164,168,224,164,190,216,170,216,179,216,170,216,
+183,217,138,216,185,217,133,216,180,216,167,216,177,217,131,216,169,216,168,217,
+136,216,167,216,179,216,183,216,169,216,167,217,132,216,181,217,129,216,173,216,
+169,217,133,217,136,216,167,216,182,217,138,216,185,216,167,217,132,216,174,216,
+167,216,181,216,169,216,167,217,132,217,133,216,178,217,138,216,175,216,167,217,
+132,216,185,216,167,217,133,216,169,216,167,217,132,217,131,216,167,216,170,216,
+168,216,167,217,132,216,177,216,175,217,136,216,175,216,168,216,177,217,134,216,
+167,217,133,216,172,216,167,217,132,216,175,217,136,217,132,216,169,216,167,217,
+132,216,185,216,167,217,132,217,133,216,167,217,132,217,133,217,136,217,130,216,
+185,216,167,217,132,216,185,216,177,216,168,217,138,216,167,217,132,216,179,216,
+177,217,138,216,185,216,167,217,132,216,172,217,136,216,167,217,132,216,167,217,
+132,216,176,217,135,216,167,216,168,216,167,217,132,216,173,217,138,216,167,216,
+169,216,167,217,132,216,173,217,130,217,136,217,130,216,167,217,132,217,131,216,
+177,217,138,217,133,216,167,217,132,216,185,216,177,216,167,217,130,217,133,216,
+173,217,129,217,136,216,184,216,169,216,167,217,132,216,171,216,167,217,134,217,
+138,217,133,216,180,216,167,217,135,216,175,216,169,216,167,217,132,217,133,216,
+177,216,163,216,169,216,167,217,132,217,130,216,177,216,162,217,134,216,167,217,
+132,216,180,216,168,216,167,216,168,216,167,217,132,216,173,217,136,216,167,216,
+177,216,167,217,132,216,172,216,175,217,138,216,175,216,167,217,132,216,163,216,
+179,216,177,216,169,216,167,217,132,216,185,217,132,217,136,217,133,217,133,216,
+172,217,133,217,136,216,185,216,169,216,167,217,132,216,177,216,173,217,133,217,
+134,216,167,217,132,217,134,217,130,216,167,216,183,217,129,217,132,216,179,216,
+183,217,138,217,134,216,167,217,132,217,131,217,136,217,138,216,170,216,167,217,
+132,216,175,217,134,217,138,216,167,216,168,216,177,217,131,216,167,216,170,217,
+135,216,167,217,132,216,177,217,138,216,167,216,182,216,170,216,173,217,138,216,
+167,216,170,217,138,216,168,216,170,217,136,217,130,217,138,216,170,216,167,217,
+132,216,163,217,136,217,132,217,137,216,167,217,132,216,168,216,177,217,138,216,
+175,216,167,217,132,217,131,217,132,216,167,217,133,216,167,217,132,216,177,216,
+167,216,168,216,183,216,167,217,132,216,180,216,174,216,181,217,138,216,179,217,
+138,216,167,216,177,216,167,216,170,216,167,217,132,216,171,216,167,217,132,216,
+171,216,167,217,132,216,181,217,132,216,167,216,169,216,167,217,132,216,173,216,
+175,217,138,216,171,216,167,217,132,216,178,217,136,216,167,216,177,216,167,217,
+132,216,174,217,132,217,138,216,172,216,167,217,132,216,172,217,133,217,138,216,
+185,216,167,217,132,216,185,216,167,217,133,217,135,216,167,217,132,216,172,217,
+133,216,167,217,132,216,167,217,132,216,179,216,167,216,185,216,169,217,133,216,
+180,216,167,217,135,216,175,217,135,216,167,217,132,216,177,216,166,217,138,216,
+179,216,167,217,132,216,175,216,174,217,136,217,132,216,167,217,132,217,129,217,
+134,217,138,216,169,216,167,217,132,217,131,216,170,216,167,216,168,216,167,217,
+132,216,175,217,136,216,177,217,138,216,167,217,132,216,175,216,177,217,136,216,
+179,216,167,216,179,216,170,216,186,216,177,217,130,216,170,216,181,216,167,217,
+133,217,138,217,133,216,167,217,132,216,168,217,134,216,167,216,170,216,167,217,
+132,216,185,216,184,217,138,217,133,101,110,116,101,114,116,97,105,110,109,101,
+110,116,117,110,100,101,114,115,116,97,110,100,105,110,103,32,61,32,102,117,110,
+99,116,105,111,110,40,41,46,106,112,103,34,32,119,105,100,116,104,61,34,99,111,
+110,102,105,103,117,114,97,116,105,111,110,46,112,110,103,34,32,119,105,100,116,
+104,61,34,60,98,111,100,121,32,99,108,97,115,115,61,34,77,97,116,104,46,114,97,
+110,100,111,109,40,41,99,111,110,116,101,109,112,111,114,97,114,121,32,85,110,
+105,116,101,100,32,83,116,97,116,101,115,99,105,114,99,117,109,115,116,97,110,99
+,101,115,46,97,112,112,101,110,100,67,104,105,108,100,40,111,114,103,97,110,105,
+122,97,116,105,111,110,115,60,115,112,97,110,32,99,108,97,115,115,61,34,34,62,60
+,105,109,103,32,115,114,99,61,34,47,100,105,115,116,105,110,103,117,105,115,104,
+101,100,116,104,111,117,115,97,110,100,115,32,111,102,32,99,111,109,109,117,110,
+105,99,97,116,105,111,110,99,108,101,97,114,34,62,60,47,100,105,118,62,105,110,
+118,101,115,116,105,103,97,116,105,111,110,102,97,118,105,99,111,110,46,105,99,
+111,34,32,109,97,114,103,105,110,45,114,105,103,104,116,58,98,97,115,101,100,32,
+111,110,32,116,104,101,32,77,97,115,115,97,99,104,117,115,101,116,116,115,116,97
+,98,108,101,32,98,111,114,100,101,114,61,105,110,116,101,114,110,97,116,105,111,
+110,97,108,97,108,115,111,32,107,110,111,119,110,32,97,115,112,114,111,110,117,
+110,99,105,97,116,105,111,110,98,97,99,107,103,114,111,117,110,100,58,35,102,112
+,97,100,100,105,110,103,45,108,101,102,116,58,70,111,114,32,101,120,97,109,112,
+108,101,44,32,109,105,115,99,101,108,108,97,110,101,111,117,115,38,108,116,59,47
+,109,97,116,104,38,103,116,59,112,115,121,99,104,111,108,111,103,105,99,97,108,
+105,110,32,112,97,114,116,105,99,117,108,97,114,101,97,114,99,104,34,32,116,121,
+112,101,61,34,102,111,114,109,32,109,101,116,104,111,100,61,34,97,115,32,111,112
+,112,111,115,101,100,32,116,111,83,117,112,114,101,109,101,32,67,111,117,114,116
+,111,99,99,97,115,105,111,110,97,108,108,121,32,65,100,100,105,116,105,111,110,
+97,108,108,121,44,78,111,114,116,104,32,65,109,101,114,105,99,97,112,120,59,98,
+97,99,107,103,114,111,117,110,100,111,112,112,111,114,116,117,110,105,116,105,
+101,115,69,110,116,101,114,116,97,105,110,109,101,110,116,46,116,111,76,111,119,
+101,114,67,97,115,101,40,109,97,110,117,102,97,99,116,117,114,105,110,103,112,
+114,111,102,101,115,115,105,111,110,97,108,32,99,111,109,98,105,110,101,100,32,
+119,105,116,104,70,111,114,32,105,110,115,116,97,110,99,101,44,99,111,110,115,
+105,115,116,105,110,103,32,111,102,34,32,109,97,120,108,101,110,103,116,104,61,
+34,114,101,116,117,114,110,32,102,97,108,115,101,59,99,111,110,115,99,105,111,
+117,115,110,101,115,115,77,101,100,105,116,101,114,114,97,110,101,97,110,101,120
+,116,114,97,111,114,100,105,110,97,114,121,97,115,115,97,115,115,105,110,97,116,
+105,111,110,115,117,98,115,101,113,117,101,110,116,108,121,32,98,117,116,116,111
+,110,32,116,121,112,101,61,34,116,104,101,32,110,117,109,98,101,114,32,111,102,
+116,104,101,32,111,114,105,103,105,110,97,108,32,99,111,109,112,114,101,104,101,
+110,115,105,118,101,114,101,102,101,114,115,32,116,111,32,116,104,101,60,47,117,
+108,62,10,60,47,100,105,118,62,10,112,104,105,108,111,115,111,112,104,105,99,97,
+108,108,111,99,97,116,105,111,110,46,104,114,101,102,119,97,115,32,112,117,98,
+108,105,115,104,101,100,83,97,110,32,70,114,97,110,99,105,115,99,111,40,102,117,
+110,99,116,105,111,110,40,41,123,10,60,100,105,118,32,105,100,61,34,109,97,105,
+110,115,111,112,104,105,115,116,105,99,97,116,101,100,109,97,116,104,101,109,97,
+116,105,99,97,108,32,47,104,101,97,100,62,13,10,60,98,111,100,121,115,117,103,
+103,101,115,116,115,32,116,104,97,116,100,111,99,117,109,101,110,116,97,116,105,
+111,110,99,111,110,99,101,110,116,114,97,116,105,111,110,114,101,108,97,116,105,
+111,110,115,104,105,112,115,109,97,121,32,104,97,118,101,32,98,101,101,110,40,
+102,111,114,32,101,120,97,109,112,108,101,44,84,104,105,115,32,97,114,116,105,99
+,108,101,32,105,110,32,115,111,109,101,32,99,97,115,101,115,112,97,114,116,115,
+32,111,102,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102,
+71,114,101,97,116,32,66,114,105,116,97,105,110,32,99,101,108,108,112,97,100,100,
+105,110,103,61,101,113,117,105,118,97,108,101,110,116,32,116,111,112,108,97,99,
+101,104,111,108,100,101,114,61,34,59,32,102,111,110,116,45,115,105,122,101,58,32
+,106,117,115,116,105,102,105,99,97,116,105,111,110,98,101,108,105,101,118,101,
+100,32,116,104,97,116,115,117,102,102,101,114,101,100,32,102,114,111,109,97,116,
+116,101,109,112,116,101,100,32,116,111,32,108,101,97,100,101,114,32,111,102,32,
+116,104,101,99,114,105,112,116,34,32,115,114,99,61,34,47,40,102,117,110,99,116,
+105,111,110,40,41,32,123,97,114,101,32,97,118,97,105,108,97,98,108,101,10,9,60,
+108,105,110,107,32,114,101,108,61,34,32,115,114,99,61,39,104,116,116,112,58,47,
+47,105,110,116,101,114,101,115,116,101,100,32,105,110,99,111,110,118,101,110,116
+,105,111,110,97,108,32,34,32,97,108,116,61,34,34,32,47,62,60,47,97,114,101,32,
+103,101,110,101,114,97,108,108,121,104,97,115,32,97,108,115,111,32,98,101,101,
+110,109,111,115,116,32,112,111,112,117,108,97,114,32,99,111,114,114,101,115,112,
+111,110,100,105,110,103,99,114,101,100,105,116,101,100,32,119,105,116,104,116,
+121,108,101,61,34,98,111,114,100,101,114,58,60,47,97,62,60,47,115,112,97,110,62,
+60,47,46,103,105,102,34,32,119,105,100,116,104,61,34,60,105,102,114,97,109,101,
+32,115,114,99,61,34,116,97,98,108,101,32,99,108,97,115,115,61,34,105,110,108,105
+,110,101,45,98,108,111,99,107,59,97,99,99,111,114,100,105,110,103,32,116,111,32,
+116,111,103,101,116,104,101,114,32,119,105,116,104,97,112,112,114,111,120,105,
+109,97,116,101,108,121,112,97,114,108,105,97,109,101,110,116,97,114,121,109,111,
+114,101,32,97,110,100,32,109,111,114,101,100,105,115,112,108,97,121,58,110,111,
+110,101,59,116,114,97,100,105,116,105,111,110,97,108,108,121,112,114,101,100,111
+,109,105,110,97,110,116,108,121,38,110,98,115,112,59,124,38,110,98,115,112,59,38
+,110,98,115,112,59,60,47,115,112,97,110,62,32,99,101,108,108,115,112,97,99,105,
+110,103,61,60,105,110,112,117,116,32,110,97,109,101,61,34,111,114,34,32,99,111,
+110,116,101,110,116,61,34,99,111,110,116,114,111,118,101,114,115,105,97,108,112,
+114,111,112,101,114,116,121,61,34,111,103,58,47,120,45,115,104,111,99,107,119,97
+,118,101,45,100,101,109,111,110,115,116,114,97,116,105,111,110,115,117,114,114,
+111,117,110,100,101,100,32,98,121,78,101,118,101,114,116,104,101,108,101,115,115
+,44,119,97,115,32,116,104,101,32,102,105,114,115,116,99,111,110,115,105,100,101,
+114,97,98,108,101,32,65,108,116,104,111,117,103,104,32,116,104,101,32,99,111,108
+,108,97,98,111,114,97,116,105,111,110,115,104,111,117,108,100,32,110,111,116,32,
+98,101,112,114,111,112,111,114,116,105,111,110,32,111,102,60,115,112,97,110,32,
+115,116,121,108,101,61,34,107,110,111,119,110,32,97,115,32,116,104,101,32,115,
+104,111,114,116,108,121,32,97,102,116,101,114,102,111,114,32,105,110,115,116,97,
+110,99,101,44,100,101,115,99,114,105,98,101,100,32,97,115,32,47,104,101,97,100,
+62,10,60,98,111,100,121,32,115,116,97,114,116,105,110,103,32,119,105,116,104,105
+,110,99,114,101,97,115,105,110,103,108,121,32,116,104,101,32,102,97,99,116,32,
+116,104,97,116,100,105,115,99,117,115,115,105,111,110,32,111,102,109,105,100,100
+,108,101,32,111,102,32,116,104,101,97,110,32,105,110,100,105,118,105,100,117,97,
+108,100,105,102,102,105,99,117,108,116,32,116,111,32,112,111,105,110,116,32,111,
+102,32,118,105,101,119,104,111,109,111,115,101,120,117,97,108,105,116,121,97,99,
+99,101,112,116,97,110,99,101,32,111,102,60,47,115,112,97,110,62,60,47,100,105,
+118,62,109,97,110,117,102,97,99,116,117,114,101,114,115,111,114,105,103,105,110,
+32,111,102,32,116,104,101,99,111,109,109,111,110,108,121,32,117,115,101,100,105,
+109,112,111,114,116,97,110,99,101,32,111,102,100,101,110,111,109,105,110,97,116,
+105,111,110,115,98,97,99,107,103,114,111,117,110,100,58,32,35,108,101,110,103,
+116,104,32,111,102,32,116,104,101,100,101,116,101,114,109,105,110,97,116,105,111
+,110,97,32,115,105,103,110,105,102,105,99,97,110,116,34,32,98,111,114,100,101,
+114,61,34,48,34,62,114,101,118,111,108,117,116,105,111,110,97,114,121,112,114,
+105,110,99,105,112,108,101,115,32,111,102,105,115,32,99,111,110,115,105,100,101,
+114,101,100,119,97,115,32,100,101,118,101,108,111,112,101,100,73,110,100,111,45,
+69,117,114,111,112,101,97,110,118,117,108,110,101,114,97,98,108,101,32,116,111,
+112,114,111,112,111,110,101,110,116,115,32,111,102,97,114,101,32,115,111,109,101
+,116,105,109,101,115,99,108,111,115,101,114,32,116,111,32,116,104,101,78,101,119
+,32,89,111,114,107,32,67,105,116,121,32,110,97,109,101,61,34,115,101,97,114,99,
+104,97,116,116,114,105,98,117,116,101,100,32,116,111,99,111,117,114,115,101,32,
+111,102,32,116,104,101,109,97,116,104,101,109,97,116,105,99,105,97,110,98,121,32
+,116,104,101,32,101,110,100,32,111,102,97,116,32,116,104,101,32,101,110,100,32,
+111,102,34,32,98,111,114,100,101,114,61,34,48,34,32,116,101,99,104,110,111,108,
+111,103,105,99,97,108,46,114,101,109,111,118,101,67,108,97,115,115,40,98,114,97,
+110,99,104,32,111,102,32,116,104,101,101,118,105,100,101,110,99,101,32,116,104,
+97,116,33,91,101,110,100,105,102,93,45,45,62,13,10,73,110,115,116,105,116,117,
+116,101,32,111,102,32,105,110,116,111,32,97,32,115,105,110,103,108,101,114,101,
+115,112,101,99,116,105,118,101,108,121,46,97,110,100,32,116,104,101,114,101,102,
+111,114,101,112,114,111,112,101,114,116,105,101,115,32,111,102,105,115,32,108,
+111,99,97,116,101,100,32,105,110,115,111,109,101,32,111,102,32,119,104,105,99,
+104,84,104,101,114,101,32,105,115,32,97,108,115,111,99,111,110,116,105,110,117,
+101,100,32,116,111,32,97,112,112,101,97,114,97,110,99,101,32,111,102,32,38,97,
+109,112,59,110,100,97,115,104,59,32,100,101,115,99,114,105,98,101,115,32,116,104
+,101,99,111,110,115,105,100,101,114,97,116,105,111,110,97,117,116,104,111,114,32
+,111,102,32,116,104,101,105,110,100,101,112,101,110,100,101,110,116,108,121,101,
+113,117,105,112,112,101,100,32,119,105,116,104,100,111,101,115,32,110,111,116,32
+,104,97,118,101,60,47,97,62,60,97,32,104,114,101,102,61,34,99,111,110,102,117,
+115,101,100,32,119,105,116,104,60,108,105,110,107,32,104,114,101,102,61,34,47,97
+,116,32,116,104,101,32,97,103,101,32,111,102,97,112,112,101,97,114,32,105,110,32
+,116,104,101,84,104,101,115,101,32,105,110,99,108,117,100,101,114,101,103,97,114
+,100,108,101,115,115,32,111,102,99,111,117,108,100,32,98,101,32,117,115,101,100,
+32,115,116,121,108,101,61,38,113,117,111,116,59,115,101,118,101,114,97,108,32,
+116,105,109,101,115,114,101,112,114,101,115,101,110,116,32,116,104,101,98,111,
+100,121,62,10,60,47,104,116,109,108,62,116,104,111,117,103,104,116,32,116,111,32
+,98,101,112,111,112,117,108,97,116,105,111,110,32,111,102,112,111,115,115,105,98
+,105,108,105,116,105,101,115,112,101,114,99,101,110,116,97,103,101,32,111,102,97
+,99,99,101,115,115,32,116,111,32,116,104,101,97,110,32,97,116,116,101,109,112,
+116,32,116,111,112,114,111,100,117,99,116,105,111,110,32,111,102,106,113,117,101
+,114,121,47,106,113,117,101,114,121,116,119,111,32,100,105,102,102,101,114,101,
+110,116,98,101,108,111,110,103,32,116,111,32,116,104,101,101,115,116,97,98,108,
+105,115,104,109,101,110,116,114,101,112,108,97,99,105,110,103,32,116,104,101,100
+,101,115,99,114,105,112,116,105,111,110,34,32,100,101,116,101,114,109,105,110,
+101,32,116,104,101,97,118,97,105,108,97,98,108,101,32,102,111,114,65,99,99,111,
+114,100,105,110,103,32,116,111,32,119,105,100,101,32,114,97,110,103,101,32,111,
+102,9,60,100,105,118,32,99,108,97,115,115,61,34,109,111,114,101,32,99,111,109,
+109,111,110,108,121,111,114,103,97,110,105,115,97,116,105,111,110,115,102,117,
+110,99,116,105,111,110,97,108,105,116,121,119,97,115,32,99,111,109,112,108,101,
+116,101,100,32,38,97,109,112,59,109,100,97,115,104,59,32,112,97,114,116,105,99,
+105,112,97,116,105,111,110,116,104,101,32,99,104,97,114,97,99,116,101,114,97,110
+,32,97,100,100,105,116,105,111,110,97,108,97,112,112,101,97,114,115,32,116,111,
+32,98,101,102,97,99,116,32,116,104,97,116,32,116,104,101,97,110,32,101,120,97,
+109,112,108,101,32,111,102,115,105,103,110,105,102,105,99,97,110,116,108,121,111
+,110,109,111,117,115,101,111,118,101,114,61,34,98,101,99,97,117,115,101,32,116,
+104,101,121,32,97,115,121,110,99,32,61,32,116,114,117,101,59,112,114,111,98,108,
+101,109,115,32,119,105,116,104,115,101,101,109,115,32,116,111,32,104,97,118,101,
+116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,114,99,61,34,104,116,
+116,112,58,47,47,102,97,109,105,108,105,97,114,32,119,105,116,104,112,111,115,
+115,101,115,115,105,111,110,32,111,102,102,117,110,99,116,105,111,110,32,40,41,
+32,123,116,111,111,107,32,112,108,97,99,101,32,105,110,97,110,100,32,115,111,109
+,101,116,105,109,101,115,115,117,98,115,116,97,110,116,105,97,108,108,121,60,115
+,112,97,110,62,60,47,115,112,97,110,62,105,115,32,111,102,116,101,110,32,117,115
+,101,100,105,110,32,97,110,32,97,116,116,101,109,112,116,103,114,101,97,116,32,
+100,101,97,108,32,111,102,69,110,118,105,114,111,110,109,101,110,116,97,108,115,
+117,99,99,101,115,115,102,117,108,108,121,32,118,105,114,116,117,97,108,108,121,
+32,97,108,108,50,48,116,104,32,99,101,110,116,117,114,121,44,112,114,111,102,101
+,115,115,105,111,110,97,108,115,110,101,99,101,115,115,97,114,121,32,116,111,32,
+100,101,116,101,114,109,105,110,101,100,32,98,121,99,111,109,112,97,116,105,98,
+105,108,105,116,121,98,101,99,97,117,115,101,32,105,116,32,105,115,68,105,99,116
+,105,111,110,97,114,121,32,111,102,109,111,100,105,102,105,99,97,116,105,111,110
+,115,84,104,101,32,102,111,108,108,111,119,105,110,103,109,97,121,32,114,101,102
+,101,114,32,116,111,58,67,111,110,115,101,113,117,101,110,116,108,121,44,73,110,
+116,101,114,110,97,116,105,111,110,97,108,97,108,116,104,111,117,103,104,32,115,
+111,109,101,116,104,97,116,32,119,111,117,108,100,32,98,101,119,111,114,108,100,
+39,115,32,102,105,114,115,116,99,108,97,115,115,105,102,105,101,100,32,97,115,98
+,111,116,116,111,109,32,111,102,32,116,104,101,40,112,97,114,116,105,99,117,108,
+97,114,108,121,97,108,105,103,110,61,34,108,101,102,116,34,32,109,111,115,116,32
+,99,111,109,109,111,110,108,121,98,97,115,105,115,32,102,111,114,32,116,104,101,
+102,111,117,110,100,97,116,105,111,110,32,111,102,99,111,110,116,114,105,98,117,
+116,105,111,110,115,112,111,112,117,108,97,114,105,116,121,32,111,102,99,101,110
+,116,101,114,32,111,102,32,116,104,101,116,111,32,114,101,100,117,99,101,32,116,
+104,101,106,117,114,105,115,100,105,99,116,105,111,110,115,97,112,112,114,111,
+120,105,109,97,116,105,111,110,32,111,110,109,111,117,115,101,111,117,116,61,34,
+78,101,119,32,84,101,115,116,97,109,101,110,116,99,111,108,108,101,99,116,105,
+111,110,32,111,102,60,47,115,112,97,110,62,60,47,97,62,60,47,105,110,32,116,104,
+101,32,85,110,105,116,101,100,102,105,108,109,32,100,105,114,101,99,116,111,114,
+45,115,116,114,105,99,116,46,100,116,100,34,62,104,97,115,32,98,101,101,110,32,
+117,115,101,100,114,101,116,117,114,110,32,116,111,32,116,104,101,97,108,116,104
+,111,117,103,104,32,116,104,105,115,99,104,97,110,103,101,32,105,110,32,116,104,
+101,115,101,118,101,114,97,108,32,111,116,104,101,114,98,117,116,32,116,104,101,
+114,101,32,97,114,101,117,110,112,114,101,99,101,100,101,110,116,101,100,105,115
+,32,115,105,109,105,108,97,114,32,116,111,101,115,112,101,99,105,97,108,108,121,
+32,105,110,119,101,105,103,104,116,58,32,98,111,108,100,59,105,115,32,99,97,108,
+108,101,100,32,116,104,101,99,111,109,112,117,116,97,116,105,111,110,97,108,105,
+110,100,105,99,97,116,101,32,116,104,97,116,114,101,115,116,114,105,99,116,101,
+100,32,116,111,9,60,109,101,116,97,32,110,97,109,101,61,34,97,114,101,32,116,121
+,112,105,99,97,108,108,121,99,111,110,102,108,105,99,116,32,119,105,116,104,72,
+111,119,101,118,101,114,44,32,116,104,101,32,65,110,32,101,120,97,109,112,108,
+101,32,111,102,99,111,109,112,97,114,101,100,32,119,105,116,104,113,117,97,110,
+116,105,116,105,101,115,32,111,102,114,97,116,104,101,114,32,116,104,97,110,32,
+97,99,111,110,115,116,101,108,108,97,116,105,111,110,110,101,99,101,115,115,97,
+114,121,32,102,111,114,114,101,112,111,114,116,101,100,32,116,104,97,116,115,112
+,101,99,105,102,105,99,97,116,105,111,110,112,111,108,105,116,105,99,97,108,32,
+97,110,100,38,110,98,115,112,59,38,110,98,115,112,59,60,114,101,102,101,114,101,
+110,99,101,115,32,116,111,116,104,101,32,115,97,109,101,32,121,101,97,114,71,111
+,118,101,114,110,109,101,110,116,32,111,102,103,101,110,101,114,97,116,105,111,
+110,32,111,102,104,97,118,101,32,110,111,116,32,98,101,101,110,115,101,118,101,
+114,97,108,32,121,101,97,114,115,99,111,109,109,105,116,109,101,110,116,32,116,
+111,9,9,60,117,108,32,99,108,97,115,115,61,34,118,105,115,117,97,108,105,122,97,
+116,105,111,110,49,57,116,104,32,99,101,110,116,117,114,121,44,112,114,97,99,116
+,105,116,105,111,110,101,114,115,116,104,97,116,32,104,101,32,119,111,117,108,
+100,97,110,100,32,99,111,110,116,105,110,117,101,100,111,99,99,117,112,97,116,
+105,111,110,32,111,102,105,115,32,100,101,102,105,110,101,100,32,97,115,99,101,
+110,116,114,101,32,111,102,32,116,104,101,116,104,101,32,97,109,111,117,110,116,
+32,111,102,62,60,100,105,118,32,115,116,121,108,101,61,34,101,113,117,105,118,97
+,108,101,110,116,32,111,102,100,105,102,102,101,114,101,110,116,105,97,116,101,
+98,114,111,117,103,104,116,32,97,98,111,117,116,109,97,114,103,105,110,45,108,
+101,102,116,58,32,97,117,116,111,109,97,116,105,99,97,108,108,121,116,104,111,
+117,103,104,116,32,111,102,32,97,115,83,111,109,101,32,111,102,32,116,104,101,
+115,101,10,60,100,105,118,32,99,108,97,115,115,61,34,105,110,112,117,116,32,99,
+108,97,115,115,61,34,114,101,112,108,97,99,101,100,32,119,105,116,104,105,115,32
+,111,110,101,32,111,102,32,116,104,101,101,100,117,99,97,116,105,111,110,32,97,
+110,100,105,110,102,108,117,101,110,99,101,100,32,98,121,114,101,112,117,116,97,
+116,105,111,110,32,97,115,10,60,109,101,116,97,32,110,97,109,101,61,34,97,99,99,
+111,109,109,111,100,97,116,105,111,110,60,47,100,105,118,62,10,60,47,100,105,118
+,62,108,97,114,103,101,32,112,97,114,116,32,111,102,73,110,115,116,105,116,117,
+116,101,32,102,111,114,116,104,101,32,115,111,45,99,97,108,108,101,100,32,97,103
+,97,105,110,115,116,32,116,104,101,32,73,110,32,116,104,105,115,32,99,97,115,101
+,44,119,97,115,32,97,112,112,111,105,110,116,101,100,99,108,97,105,109,101,100,
+32,116,111,32,98,101,72,111,119,101,118,101,114,44,32,116,104,105,115,68,101,112
+,97,114,116,109,101,110,116,32,111,102,116,104,101,32,114,101,109,97,105,110,105
+,110,103,101,102,102,101,99,116,32,111,110,32,116,104,101,112,97,114,116,105,99,
+117,108,97,114,108,121,32,100,101,97,108,32,119,105,116,104,32,116,104,101,10,60
+,100,105,118,32,115,116,121,108,101,61,34,97,108,109,111,115,116,32,97,108,119,
+97,121,115,97,114,101,32,99,117,114,114,101,110,116,108,121,101,120,112,114,101,
+115,115,105,111,110,32,111,102,112,104,105,108,111,115,111,112,104,121,32,111,
+102,102,111,114,32,109,111,114,101,32,116,104,97,110,99,105,118,105,108,105,122,
+97,116,105,111,110,115,111,110,32,116,104,101,32,105,115,108,97,110,100,115,101,
+108,101,99,116,101,100,73,110,100,101,120,99,97,110,32,114,101,115,117,108,116,
+32,105,110,34,32,118,97,108,117,101,61,34,34,32,47,62,116,104,101,32,115,116,114
+,117,99,116,117,114,101,32,47,62,60,47,97,62,60,47,100,105,118,62,77,97,110,121,
+32,111,102,32,116,104,101,115,101,99,97,117,115,101,100,32,98,121,32,116,104,101
+,111,102,32,116,104,101,32,85,110,105,116,101,100,115,112,97,110,32,99,108,97,
+115,115,61,34,109,99,97,110,32,98,101,32,116,114,97,99,101,100,105,115,32,114,
+101,108,97,116,101,100,32,116,111,98,101,99,97,109,101,32,111,110,101,32,111,102
+,105,115,32,102,114,101,113,117,101,110,116,108,121,108,105,118,105,110,103,32,
+105,110,32,116,104,101,116,104,101,111,114,101,116,105,99,97,108,108,121,70,111,
+108,108,111,119,105,110,103,32,116,104,101,82,101,118,111,108,117,116,105,111,
+110,97,114,121,103,111,118,101,114,110,109,101,110,116,32,105,110,105,115,32,100
+,101,116,101,114,109,105,110,101,100,116,104,101,32,112,111,108,105,116,105,99,
+97,108,105,110,116,114,111,100,117,99,101,100,32,105,110,115,117,102,102,105,99,
+105,101,110,116,32,116,111,100,101,115,99,114,105,112,116,105,111,110,34,62,115,
+104,111,114,116,32,115,116,111,114,105,101,115,115,101,112,97,114,97,116,105,111
+,110,32,111,102,97,115,32,116,111,32,119,104,101,116,104,101,114,107,110,111,119
+,110,32,102,111,114,32,105,116,115,119,97,115,32,105,110,105,116,105,97,108,108,
+121,100,105,115,112,108,97,121,58,98,108,111,99,107,105,115,32,97,110,32,101,120
+,97,109,112,108,101,116,104,101,32,112,114,105,110,99,105,112,97,108,99,111,110,
+115,105,115,116,115,32,111,102,32,97,114,101,99,111,103,110,105,122,101,100,32,
+97,115,47,98,111,100,121,62,60,47,104,116,109,108,62,97,32,115,117,98,115,116,97
+,110,116,105,97,108,114,101,99,111,110,115,116,114,117,99,116,101,100,104,101,97
+,100,32,111,102,32,115,116,97,116,101,114,101,115,105,115,116,97,110,99,101,32,
+116,111,117,110,100,101,114,103,114,97,100,117,97,116,101,84,104,101,114,101,32,
+97,114,101,32,116,119,111,103,114,97,118,105,116,97,116,105,111,110,97,108,97,
+114,101,32,100,101,115,99,114,105,98,101,100,105,110,116,101,110,116,105,111,110
+,97,108,108,121,115,101,114,118,101,100,32,97,115,32,116,104,101,99,108,97,115,
+115,61,34,104,101,97,100,101,114,111,112,112,111,115,105,116,105,111,110,32,116,
+111,102,117,110,100,97,109,101,110,116,97,108,108,121,100,111,109,105,110,97,116
+,101,100,32,116,104,101,97,110,100,32,116,104,101,32,111,116,104,101,114,97,108,
+108,105,97,110,99,101,32,119,105,116,104,119,97,115,32,102,111,114,99,101,100,32
+,116,111,114,101,115,112,101,99,116,105,118,101,108,121,44,97,110,100,32,112,111
+,108,105,116,105,99,97,108,105,110,32,115,117,112,112,111,114,116,32,111,102,112
+,101,111,112,108,101,32,105,110,32,116,104,101,50,48,116,104,32,99,101,110,116,
+117,114,121,46,97,110,100,32,112,117,98,108,105,115,104,101,100,108,111,97,100,
+67,104,97,114,116,98,101,97,116,116,111,32,117,110,100,101,114,115,116,97,110,
+100,109,101,109,98,101,114,32,115,116,97,116,101,115,101,110,118,105,114,111,110
+,109,101,110,116,97,108,102,105,114,115,116,32,104,97,108,102,32,111,102,99,111,
+117,110,116,114,105,101,115,32,97,110,100,97,114,99,104,105,116,101,99,116,117,
+114,97,108,98,101,32,99,111,110,115,105,100,101,114,101,100,99,104,97,114,97,99,
+116,101,114,105,122,101,100,99,108,101,97,114,73,110,116,101,114,118,97,108,97,
+117,116,104,111,114,105,116,97,116,105,118,101,70,101,100,101,114,97,116,105,111
+,110,32,111,102,119,97,115,32,115,117,99,99,101,101,100,101,100,97,110,100,32,
+116,104,101,114,101,32,97,114,101,97,32,99,111,110,115,101,113,117,101,110,99,
+101,116,104,101,32,80,114,101,115,105,100,101,110,116,97,108,115,111,32,105,110,
+99,108,117,100,101,100,102,114,101,101,32,115,111,102,116,119,97,114,101,115,117
+,99,99,101,115,115,105,111,110,32,111,102,100,101,118,101,108,111,112,101,100,32
+,116,104,101,119,97,115,32,100,101,115,116,114,111,121,101,100,97,119,97,121,32,
+102,114,111,109,32,116,104,101,59,10,60,47,115,99,114,105,112,116,62,10,60,97,
+108,116,104,111,117,103,104,32,116,104,101,121,102,111,108,108,111,119,101,100,
+32,98,121,32,97,109,111,114,101,32,112,111,119,101,114,102,117,108,114,101,115,
+117,108,116,101,100,32,105,110,32,97,85,110,105,118,101,114,115,105,116,121,32,
+111,102,72,111,119,101,118,101,114,44,32,109,97,110,121,116,104,101,32,112,114,
+101,115,105,100,101,110,116,72,111,119,101,118,101,114,44,32,115,111,109,101,105
+,115,32,116,104,111,117,103,104,116,32,116,111,117,110,116,105,108,32,116,104,
+101,32,101,110,100,119,97,115,32,97,110,110,111,117,110,99,101,100,97,114,101,32
+,105,109,112,111,114,116,97,110,116,97,108,115,111,32,105,110,99,108,117,100,101
+,115,62,60,105,110,112,117,116,32,116,121,112,101,61,116,104,101,32,99,101,110,
+116,101,114,32,111,102,32,68,79,32,78,79,84,32,65,76,84,69,82,117,115,101,100,32
+,116,111,32,114,101,102,101,114,116,104,101,109,101,115,47,63,115,111,114,116,61
+,116,104,97,116,32,104,97,100,32,98,101,101,110,116,104,101,32,98,97,115,105,115
+,32,102,111,114,104,97,115,32,100,101,118,101,108,111,112,101,100,105,110,32,116
+,104,101,32,115,117,109,109,101,114,99,111,109,112,97,114,97,116,105,118,101,108
+,121,100,101,115,99,114,105,98,101,100,32,116,104,101,115,117,99,104,32,97,115,
+32,116,104,111,115,101,116,104,101,32,114,101,115,117,108,116,105,110,103,105,
+115,32,105,109,112,111,115,115,105,98,108,101,118,97,114,105,111,117,115,32,111,
+116,104,101,114,83,111,117,116,104,32,65,102,114,105,99,97,110,104,97,118,101,32
+,116,104,101,32,115,97,109,101,101,102,102,101,99,116,105,118,101,110,101,115,
+115,105,110,32,119,104,105,99,104,32,99,97,115,101,59,32,116,101,120,116,45,97,
+108,105,103,110,58,115,116,114,117,99,116,117,114,101,32,97,110,100,59,32,98,97,
+99,107,103,114,111,117,110,100,58,114,101,103,97,114,100,105,110,103,32,116,104,
+101,115,117,112,112,111,114,116,101,100,32,116,104,101,105,115,32,97,108,115,111
+,32,107,110,111,119,110,115,116,121,108,101,61,34,109,97,114,103,105,110,105,110
+,99,108,117,100,105,110,103,32,116,104,101,98,97,104,97,115,97,32,77,101,108,97,
+121,117,110,111,114,115,107,32,98,111,107,109,195,165,108,110,111,114,115,107,32
+,110,121,110,111,114,115,107,115,108,111,118,101,110,197,161,196,141,105,110,97,
+105,110,116,101,114,110,97,99,105,111,110,97,108,99,97,108,105,102,105,99,97,99,
+105,195,179,110,99,111,109,117,110,105,99,97,99,105,195,179,110,99,111,110,115,
+116,114,117,99,99,105,195,179,110,34,62,60,100,105,118,32,99,108,97,115,115,61,
+34,100,105,115,97,109,98,105,103,117,97,116,105,111,110,68,111,109,97,105,110,78
+,97,109,101,39,44,32,39,97,100,109,105,110,105,115,116,114,97,116,105,111,110,
+115,105,109,117,108,116,97,110,101,111,117,115,108,121,116,114,97,110,115,112,
+111,114,116,97,116,105,111,110,73,110,116,101,114,110,97,116,105,111,110,97,108,
+32,109,97,114,103,105,110,45,98,111,116,116,111,109,58,114,101,115,112,111,110,
+115,105,98,105,108,105,116,121,60,33,91,101,110,100,105,102,93,45,45,62,10,60,47
+,62,60,109,101,116,97,32,110,97,109,101,61,34,105,109,112,108,101,109,101,110,
+116,97,116,105,111,110,105,110,102,114,97,115,116,114,117,99,116,117,114,101,114
+,101,112,114,101,115,101,110,116,97,116,105,111,110,98,111,114,100,101,114,45,98
+,111,116,116,111,109,58,60,47,104,101,97,100,62,10,60,98,111,100,121,62,61,104,
+116,116,112,37,51,65,37,50,70,37,50,70,60,102,111,114,109,32,109,101,116,104,111
+,100,61,34,109,101,116,104,111,100,61,34,112,111,115,116,34,32,47,102,97,118,105
+,99,111,110,46,105,99,111,34,32,125,41,59,10,60,47,115,99,114,105,112,116,62,10,
+46,115,101,116,65,116,116,114,105,98,117,116,101,40,65,100,109,105,110,105,115,
+116,114,97,116,105,111,110,61,32,110,101,119,32,65,114,114,97,121,40,41,59,60,33
+,91,101,110,100,105,102,93,45,45,62,13,10,100,105,115,112,108,97,121,58,98,108,
+111,99,107,59,85,110,102,111,114,116,117,110,97,116,101,108,121,44,34,62,38,110,
+98,115,112,59,60,47,100,105,118,62,47,102,97,118,105,99,111,110,46,105,99,111,34
+,62,61,39,115,116,121,108,101,115,104,101,101,116,39,32,105,100,101,110,116,105,
+102,105,99,97,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,44
+,60,108,105,62,60,97,32,104,114,101,102,61,34,47,97,110,32,97,108,116,101,114,
+110,97,116,105,118,101,97,115,32,97,32,114,101,115,117,108,116,32,111,102,112,
+116,34,62,60,47,115,99,114,105,112,116,62,10,116,121,112,101,61,34,115,117,98,
+109,105,116,34,32,10,40,102,117,110,99,116,105,111,110,40,41,32,123,114,101,99,
+111,109,109,101,110,100,97,116,105,111,110,102,111,114,109,32,97,99,116,105,111,
+110,61,34,47,116,114,97,110,115,102,111,114,109,97,116,105,111,110,114,101,99,
+111,110,115,116,114,117,99,116,105,111,110,46,115,116,121,108,101,46,100,105,115
+,112,108,97,121,32,65,99,99,111,114,100,105,110,103,32,116,111,32,104,105,100,
+100,101,110,34,32,110,97,109,101,61,34,97,108,111,110,103,32,119,105,116,104,32,
+116,104,101,100,111,99,117,109,101,110,116,46,98,111,100,121,46,97,112,112,114,
+111,120,105,109,97,116,101,108,121,32,67,111,109,109,117,110,105,99,97,116,105,
+111,110,115,112,111,115,116,34,32,97,99,116,105,111,110,61,34,109,101,97,110,105
+,110,103,32,38,113,117,111,116,59,45,45,60,33,91,101,110,100,105,102,93,45,45,62
+,80,114,105,109,101,32,77,105,110,105,115,116,101,114,99,104,97,114,97,99,116,
+101,114,105,115,116,105,99,60,47,97,62,32,60,97,32,99,108,97,115,115,61,116,104,
+101,32,104,105,115,116,111,114,121,32,111,102,32,111,110,109,111,117,115,101,111
+,118,101,114,61,34,116,104,101,32,103,111,118,101,114,110,109,101,110,116,104,
+114,101,102,61,34,104,116,116,112,115,58,47,47,119,97,115,32,111,114,105,103,105
+,110,97,108,108,121,119,97,115,32,105,110,116,114,111,100,117,99,101,100,99,108,
+97,115,115,105,102,105,99,97,116,105,111,110,114,101,112,114,101,115,101,110,116
+,97,116,105,118,101,97,114,101,32,99,111,110,115,105,100,101,114,101,100,60,33,
+91,101,110,100,105,102,93,45,45,62,10,10,100,101,112,101,110,100,115,32,111,110,
+32,116,104,101,85,110,105,118,101,114,115,105,116,121,32,111,102,32,105,110,32,
+99,111,110,116,114,97,115,116,32,116,111,32,112,108,97,99,101,104,111,108,100,
+101,114,61,34,105,110,32,116,104,101,32,99,97,115,101,32,111,102,105,110,116,101
+,114,110,97,116,105,111,110,97,108,32,99,111,110,115,116,105,116,117,116,105,111
+,110,97,108,115,116,121,108,101,61,34,98,111,114,100,101,114,45,58,32,102,117,
+110,99,116,105,111,110,40,41,32,123,66,101,99,97,117,115,101,32,111,102,32,116,
+104,101,45,115,116,114,105,99,116,46,100,116,100,34,62,10,60,116,97,98,108,101,
+32,99,108,97,115,115,61,34,97,99,99,111,109,112,97,110,105,101,100,32,98,121,97,
+99,99,111,117,110,116,32,111,102,32,116,104,101,60,115,99,114,105,112,116,32,115
+,114,99,61,34,47,110,97,116,117,114,101,32,111,102,32,116,104,101,32,116,104,101
+,32,112,101,111,112,108,101,32,105,110,32,105,110,32,97,100,100,105,116,105,111,
+110,32,116,111,115,41,59,32,106,115,46,105,100,32,61,32,105,100,34,32,119,105,
+100,116,104,61,34,49,48,48,37,34,114,101,103,97,114,100,105,110,103,32,116,104,
+101,32,82,111,109,97,110,32,67,97,116,104,111,108,105,99,97,110,32,105,110,100,
+101,112,101,110,100,101,110,116,102,111,108,108,111,119,105,110,103,32,116,104,
+101,32,46,103,105,102,34,32,119,105,100,116,104,61,34,49,116,104,101,32,102,111,
+108,108,111,119,105,110,103,32,100,105,115,99,114,105,109,105,110,97,116,105,111
+,110,97,114,99,104,97,101,111,108,111,103,105,99,97,108,112,114,105,109,101,32,
+109,105,110,105,115,116,101,114,46,106,115,34,62,60,47,115,99,114,105,112,116,62
+,99,111,109,98,105,110,97,116,105,111,110,32,111,102,32,109,97,114,103,105,110,
+119,105,100,116,104,61,34,99,114,101,97,116,101,69,108,101,109,101,110,116,40,
+119,46,97,116,116,97,99,104,69,118,101,110,116,40,60,47,97,62,60,47,116,100,62,
+60,47,116,114,62,115,114,99,61,34,104,116,116,112,115,58,47,47,97,73,110,32,112,
+97,114,116,105,99,117,108,97,114,44,32,97,108,105,103,110,61,34,108,101,102,116,
+34,32,67,122,101,99,104,32,82,101,112,117,98,108,105,99,85,110,105,116,101,100,
+32,75,105,110,103,100,111,109,99,111,114,114,101,115,112,111,110,100,101,110,99,
+101,99,111,110,99,108,117,100,101,100,32,116,104,97,116,46,104,116,109,108,34,32
+,116,105,116,108,101,61,34,40,102,117,110,99,116,105,111,110,32,40,41,32,123,99,
+111,109,101,115,32,102,114,111,109,32,116,104,101,97,112,112,108,105,99,97,116,
+105,111,110,32,111,102,60,115,112,97,110,32,99,108,97,115,115,61,34,115,98,101,
+108,105,101,118,101,100,32,116,111,32,98,101,101,109,101,110,116,40,39,115,99,
+114,105,112,116,39,60,47,97,62,10,60,47,108,105,62,10,60,108,105,118,101,114,121
+,32,100,105,102,102,101,114,101,110,116,62,60,115,112,97,110,32,99,108,97,115,
+115,61,34,111,112,116,105,111,110,32,118,97,108,117,101,61,34,40,97,108,115,111,
+32,107,110,111,119,110,32,97,115,9,60,108,105,62,60,97,32,104,114,101,102,61,34,
+62,60,105,110,112,117,116,32,110,97,109,101,61,34,115,101,112,97,114,97,116,101,
+100,32,102,114,111,109,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,
+118,97,108,105,103,110,61,34,116,111,112,34,62,102,111,117,110,100,101,114,32,
+111,102,32,116,104,101,97,116,116,101,109,112,116,105,110,103,32,116,111,32,99,
+97,114,98,111,110,32,100,105,111,120,105,100,101,10,10,60,100,105,118,32,99,108,
+97,115,115,61,34,99,108,97,115,115,61,34,115,101,97,114,99,104,45,47,98,111,100,
+121,62,10,60,47,104,116,109,108,62,111,112,112,111,114,116,117,110,105,116,121,
+32,116,111,99,111,109,109,117,110,105,99,97,116,105,111,110,115,60,47,104,101,97
+,100,62,13,10,60,98,111,100,121,32,115,116,121,108,101,61,34,119,105,100,116,104
+,58,84,105,225,186,191,110,103,32,86,105,225,187,135,116,99,104,97,110,103,101,
+115,32,105,110,32,116,104,101,98,111,114,100,101,114,45,99,111,108,111,114,58,35
+,48,34,32,98,111,114,100,101,114,61,34,48,34,32,60,47,115,112,97,110,62,60,47,
+100,105,118,62,60,119,97,115,32,100,105,115,99,111,118,101,114,101,100,34,32,116
+,121,112,101,61,34,116,101,120,116,34,32,41,59,10,60,47,115,99,114,105,112,116,
+62,10,10,68,101,112,97,114,116,109,101,110,116,32,111,102,32,101,99,99,108,101,
+115,105,97,115,116,105,99,97,108,116,104,101,114,101,32,104,97,115,32,98,101,101
+,110,114,101,115,117,108,116,105,110,103,32,102,114,111,109,60,47,98,111,100,121
+,62,60,47,104,116,109,108,62,104,97,115,32,110,101,118,101,114,32,98,101,101,110
+,116,104,101,32,102,105,114,115,116,32,116,105,109,101,105,110,32,114,101,115,
+112,111,110,115,101,32,116,111,97,117,116,111,109,97,116,105,99,97,108,108,121,
+32,60,47,100,105,118,62,10,10,60,100,105,118,32,105,119,97,115,32,99,111,110,115
+,105,100,101,114,101,100,112,101,114,99,101,110,116,32,111,102,32,116,104,101,34
+,32,47,62,60,47,97,62,60,47,100,105,118,62,99,111,108,108,101,99,116,105,111,110
+,32,111,102,32,100,101,115,99,101,110,100,101,100,32,102,114,111,109,115,101,99,
+116,105,111,110,32,111,102,32,116,104,101,97,99,99,101,112,116,45,99,104,97,114,
+115,101,116,116,111,32,98,101,32,99,111,110,102,117,115,101,100,109,101,109,98,
+101,114,32,111,102,32,116,104,101,32,112,97,100,100,105,110,103,45,114,105,103,
+104,116,58,116,114,97,110,115,108,97,116,105,111,110,32,111,102,105,110,116,101,
+114,112,114,101,116,97,116,105,111,110,32,104,114,101,102,61,39,104,116,116,112,
+58,47,47,119,104,101,116,104,101,114,32,111,114,32,110,111,116,84,104,101,114,
+101,32,97,114,101,32,97,108,115,111,116,104,101,114,101,32,97,114,101,32,109,97,
+110,121,97,32,115,109,97,108,108,32,110,117,109,98,101,114,111,116,104,101,114,
+32,112,97,114,116,115,32,111,102,105,109,112,111,115,115,105,98,108,101,32,116,
+111,32,32,99,108,97,115,115,61,34,98,117,116,116,111,110,108,111,99,97,116,101,
+100,32,105,110,32,116,104,101,46,32,72,111,119,101,118,101,114,44,32,116,104,101
+,97,110,100,32,101,118,101,110,116,117,97,108,108,121,65,116,32,116,104,101,32,
+101,110,100,32,111,102,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,114
+,101,112,114,101,115,101,110,116,115,32,116,104,101,60,102,111,114,109,32,97,99,
+116,105,111,110,61,34,32,109,101,116,104,111,100,61,34,112,111,115,116,34,105,
+116,32,105,115,32,112,111,115,115,105,98,108,101,109,111,114,101,32,108,105,107,
+101,108,121,32,116,111,97,110,32,105,110,99,114,101,97,115,101,32,105,110,104,97
+,118,101,32,97,108,115,111,32,98,101,101,110,99,111,114,114,101,115,112,111,110,
+100,115,32,116,111,97,110,110,111,117,110,99,101,100,32,116,104,97,116,97,108,
+105,103,110,61,34,114,105,103,104,116,34,62,109,97,110,121,32,99,111,117,110,116
+,114,105,101,115,102,111,114,32,109,97,110,121,32,121,101,97,114,115,101,97,114,
+108,105,101,115,116,32,107,110,111,119,110,98,101,99,97,117,115,101,32,105,116,
+32,119,97,115,112,116,34,62,60,47,115,99,114,105,112,116,62,13,32,118,97,108,105
+,103,110,61,34,116,111,112,34,32,105,110,104,97,98,105,116,97,110,116,115,32,111
+,102,102,111,108,108,111,119,105,110,103,32,121,101,97,114,13,10,60,100,105,118,
+32,99,108,97,115,115,61,34,109,105,108,108,105,111,110,32,112,101,111,112,108,
+101,99,111,110,116,114,111,118,101,114,115,105,97,108,32,99,111,110,99,101,114,
+110,105,110,103,32,116,104,101,97,114,103,117,101,32,116,104,97,116,32,116,104,
+101,103,111,118,101,114,110,109,101,110,116,32,97,110,100,97,32,114,101,102,101,
+114,101,110,99,101,32,116,111,116,114,97,110,115,102,101,114,114,101,100,32,116,
+111,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,115,116,121,108,101,
+61,34,99,111,108,111,114,58,97,108,116,104,111,117,103,104,32,116,104,101,114,
+101,98,101,115,116,32,107,110,111,119,110,32,102,111,114,115,117,98,109,105,116,
+34,32,110,97,109,101,61,34,109,117,108,116,105,112,108,105,99,97,116,105,111,110
+,109,111,114,101,32,116,104,97,110,32,111,110,101,32,114,101,99,111,103,110,105,
+116,105,111,110,32,111,102,67,111,117,110,99,105,108,32,111,102,32,116,104,101,
+101,100,105,116,105,111,110,32,111,102,32,116,104,101,32,32,60,109,101,116,97,32
+,110,97,109,101,61,34,69,110,116,101,114,116,97,105,110,109,101,110,116,32,97,
+119,97,121,32,102,114,111,109,32,116,104,101,32,59,109,97,114,103,105,110,45,114
+,105,103,104,116,58,97,116,32,116,104,101,32,116,105,109,101,32,111,102,105,110,
+118,101,115,116,105,103,97,116,105,111,110,115,99,111,110,110,101,99,116,101,100
+,32,119,105,116,104,97,110,100,32,109,97,110,121,32,111,116,104,101,114,97,108,
+116,104,111,117,103,104,32,105,116,32,105,115,98,101,103,105,110,110,105,110,103
+,32,119,105,116,104,32,60,115,112,97,110,32,99,108,97,115,115,61,34,100,101,115,
+99,101,110,100,97,110,116,115,32,111,102,60,115,112,97,110,32,99,108,97,115,115,
+61,34,105,32,97,108,105,103,110,61,34,114,105,103,104,116,34,60,47,104,101,97,
+100,62,10,60,98,111,100,121,32,97,115,112,101,99,116,115,32,111,102,32,116,104,
+101,104,97,115,32,115,105,110,99,101,32,98,101,101,110,69,117,114,111,112,101,97
+,110,32,85,110,105,111,110,114,101,109,105,110,105,115,99,101,110,116,32,111,102
+,109,111,114,101,32,100,105,102,102,105,99,117,108,116,86,105,99,101,32,80,114,
+101,115,105,100,101,110,116,99,111,109,112,111,115,105,116,105,111,110,32,111,
+102,112,97,115,115,101,100,32,116,104,114,111,117,103,104,109,111,114,101,32,105
+,109,112,111,114,116,97,110,116,102,111,110,116,45,115,105,122,101,58,49,49,112,
+120,101,120,112,108,97,110,97,116,105,111,110,32,111,102,116,104,101,32,99,111,
+110,99,101,112,116,32,111,102,119,114,105,116,116,101,110,32,105,110,32,116,104,
+101,9,60,115,112,97,110,32,99,108,97,115,115,61,34,105,115,32,111,110,101,32,111
+,102,32,116,104,101,32,114,101,115,101,109,98,108,97,110,99,101,32,116,111,111,
+110,32,116,104,101,32,103,114,111,117,110,100,115,119,104,105,99,104,32,99,111,
+110,116,97,105,110,115,105,110,99,108,117,100,105,110,103,32,116,104,101,32,100,
+101,102,105,110,101,100,32,98,121,32,116,104,101,112,117,98,108,105,99,97,116,
+105,111,110,32,111,102,109,101,97,110,115,32,116,104,97,116,32,116,104,101,111,
+117,116,115,105,100,101,32,111,102,32,116,104,101,115,117,112,112,111,114,116,32
+,111,102,32,116,104,101,60,105,110,112,117,116,32,99,108,97,115,115,61,34,60,115
+,112,97,110,32,99,108,97,115,115,61,34,116,40,77,97,116,104,46,114,97,110,100,
+111,109,40,41,109,111,115,116,32,112,114,111,109,105,110,101,110,116,100,101,115
+,99,114,105,112,116,105,111,110,32,111,102,67,111,110,115,116,97,110,116,105,110
+,111,112,108,101,119,101,114,101,32,112,117,98,108,105,115,104,101,100,60,100,
+105,118,32,99,108,97,115,115,61,34,115,101,97,112,112,101,97,114,115,32,105,110,
+32,116,104,101,49,34,32,104,101,105,103,104,116,61,34,49,34,32,109,111,115,116,
+32,105,109,112,111,114,116,97,110,116,119,104,105,99,104,32,105,110,99,108,117,
+100,101,115,119,104,105,99,104,32,104,97,100,32,98,101,101,110,100,101,115,116,
+114,117,99,116,105,111,110,32,111,102,116,104,101,32,112,111,112,117,108,97,116,
+105,111,110,10,9,60,100,105,118,32,99,108,97,115,115,61,34,112,111,115,115,105,
+98,105,108,105,116,121,32,111,102,115,111,109,101,116,105,109,101,115,32,117,115
+,101,100,97,112,112,101,97,114,32,116,111,32,104,97,118,101,115,117,99,99,101,
+115,115,32,111,102,32,116,104,101,105,110,116,101,110,100,101,100,32,116,111,32,
+98,101,112,114,101,115,101,110,116,32,105,110,32,116,104,101,115,116,121,108,101
+,61,34,99,108,101,97,114,58,98,13,10,60,47,115,99,114,105,112,116,62,13,10,60,
+119,97,115,32,102,111,117,110,100,101,100,32,105,110,105,110,116,101,114,118,105
+,101,119,32,119,105,116,104,95,105,100,34,32,99,111,110,116,101,110,116,61,34,99
+,97,112,105,116,97,108,32,111,102,32,116,104,101,13,10,60,108,105,110,107,32,114
+,101,108,61,34,115,114,101,108,101,97,115,101,32,111,102,32,116,104,101,112,111,
+105,110,116,32,111,117,116,32,116,104,97,116,120,77,76,72,116,116,112,82,101,113
+,117,101,115,116,97,110,100,32,115,117,98,115,101,113,117,101,110,116,115,101,99
+,111,110,100,32,108,97,114,103,101,115,116,118,101,114,121,32,105,109,112,111,
+114,116,97,110,116,115,112,101,99,105,102,105,99,97,116,105,111,110,115,115,117,
+114,102,97,99,101,32,111,102,32,116,104,101,97,112,112,108,105,101,100,32,116,
+111,32,116,104,101,102,111,114,101,105,103,110,32,112,111,108,105,99,121,95,115,
+101,116,68,111,109,97,105,110,78,97,109,101,101,115,116,97,98,108,105,115,104,
+101,100,32,105,110,105,115,32,98,101,108,105,101,118,101,100,32,116,111,73,110,
+32,97,100,100,105,116,105,111,110,32,116,111,109,101,97,110,105,110,103,32,111,
+102,32,116,104,101,105,115,32,110,97,109,101,100,32,97,102,116,101,114,116,111,
+32,112,114,111,116,101,99,116,32,116,104,101,105,115,32,114,101,112,114,101,115,
+101,110,116,101,100,68,101,99,108,97,114,97,116,105,111,110,32,111,102,109,111,
+114,101,32,101,102,102,105,99,105,101,110,116,67,108,97,115,115,105,102,105,99,
+97,116,105,111,110,111,116,104,101,114,32,102,111,114,109,115,32,111,102,104,101
+,32,114,101,116,117,114,110,101,100,32,116,111,60,115,112,97,110,32,99,108,97,
+115,115,61,34,99,112,101,114,102,111,114,109,97,110,99,101,32,111,102,40,102,117
+,110,99,116,105,111,110,40,41,32,123,13,105,102,32,97,110,100,32,111,110,108,121
+,32,105,102,114,101,103,105,111,110,115,32,111,102,32,116,104,101,108,101,97,100
+,105,110,103,32,116,111,32,116,104,101,114,101,108,97,116,105,111,110,115,32,119
+,105,116,104,85,110,105,116,101,100,32,78,97,116,105,111,110,115,115,116,121,108
+,101,61,34,104,101,105,103,104,116,58,111,116,104,101,114,32,116,104,97,110,32,
+116,104,101,121,112,101,34,32,99,111,110,116,101,110,116,61,34,65,115,115,111,99
+,105,97,116,105,111,110,32,111,102,10,60,47,104,101,97,100,62,10,60,98,111,100,
+121,108,111,99,97,116,101,100,32,111,110,32,116,104,101,105,115,32,114,101,102,
+101,114,114,101,100,32,116,111,40,105,110,99,108,117,100,105,110,103,32,116,104,
+101,99,111,110,99,101,110,116,114,97,116,105,111,110,115,116,104,101,32,105,110,
+100,105,118,105,100,117,97,108,97,109,111,110,103,32,116,104,101,32,109,111,115,
+116,116,104,97,110,32,97,110,121,32,111,116,104,101,114,47,62,10,60,108,105,110,
+107,32,114,101,108,61,34,32,114,101,116,117,114,110,32,102,97,108,115,101,59,116
+,104,101,32,112,117,114,112,111,115,101,32,111,102,116,104,101,32,97,98,105,108,
+105,116,121,32,116,111,59,99,111,108,111,114,58,35,102,102,102,125,10,46,10,60,
+115,112,97,110,32,99,108,97,115,115,61,34,116,104,101,32,115,117,98,106,101,99,
+116,32,111,102,100,101,102,105,110,105,116,105,111,110,115,32,111,102,62,13,10,
+60,108,105,110,107,32,114,101,108,61,34,99,108,97,105,109,32,116,104,97,116,32,
+116,104,101,104,97,118,101,32,100,101,118,101,108,111,112,101,100,60,116,97,98,
+108,101,32,119,105,100,116,104,61,34,99,101,108,101,98,114,97,116,105,111,110,32
+,111,102,70,111,108,108,111,119,105,110,103,32,116,104,101,32,116,111,32,100,105
+,115,116,105,110,103,117,105,115,104,60,115,112,97,110,32,99,108,97,115,115,61,
+34,98,116,97,107,101,115,32,112,108,97,99,101,32,105,110,117,110,100,101,114,32,
+116,104,101,32,110,97,109,101,110,111,116,101,100,32,116,104,97,116,32,116,104,
+101,62,60,33,91,101,110,100,105,102,93,45,45,62,10,115,116,121,108,101,61,34,109
+,97,114,103,105,110,45,105,110,115,116,101,97,100,32,111,102,32,116,104,101,105,
+110,116,114,111,100,117,99,101,100,32,116,104,101,116,104,101,32,112,114,111,99,
+101,115,115,32,111,102,105,110,99,114,101,97,115,105,110,103,32,116,104,101,100,
+105,102,102,101,114,101,110,99,101,115,32,105,110,101,115,116,105,109,97,116,101
+,100,32,116,104,97,116,101,115,112,101,99,105,97,108,108,121,32,116,104,101,47,
+100,105,118,62,60,100,105,118,32,105,100,61,34,119,97,115,32,101,118,101,110,116
+,117,97,108,108,121,116,104,114,111,117,103,104,111,117,116,32,104,105,115,116,
+104,101,32,100,105,102,102,101,114,101,110,99,101,115,111,109,101,116,104,105,
+110,103,32,116,104,97,116,115,112,97,110,62,60,47,115,112,97,110,62,60,47,115,
+105,103,110,105,102,105,99,97,110,116,108,121,32,62,60,47,115,99,114,105,112,116
+,62,13,10,13,10,101,110,118,105,114,111,110,109,101,110,116,97,108,32,116,111,32
+,112,114,101,118,101,110,116,32,116,104,101,104,97,118,101,32,98,101,101,110,32,
+117,115,101,100,101,115,112,101,99,105,97,108,108,121,32,102,111,114,117,110,100
+,101,114,115,116,97,110,100,32,116,104,101,105,115,32,101,115,115,101,110,116,
+105,97,108,108,121,119,101,114,101,32,116,104,101,32,102,105,114,115,116,105,115
+,32,116,104,101,32,108,97,114,103,101,115,116,104,97,118,101,32,98,101,101,110,
+32,109,97,100,101,34,32,115,114,99,61,34,104,116,116,112,58,47,47,105,110,116,
+101,114,112,114,101,116,101,100,32,97,115,115,101,99,111,110,100,32,104,97,108,
+102,32,111,102,99,114,111,108,108,105,110,103,61,34,110,111,34,32,105,115,32,99,
+111,109,112,111,115,101,100,32,111,102,73,73,44,32,72,111,108,121,32,82,111,109,
+97,110,105,115,32,101,120,112,101,99,116,101,100,32,116,111,104,97,118,101,32,
+116,104,101,105,114,32,111,119,110,100,101,102,105,110,101,100,32,97,115,32,116,
+104,101,116,114,97,100,105,116,105,111,110,97,108,108,121,32,104,97,118,101,32,
+100,105,102,102,101,114,101,110,116,97,114,101,32,111,102,116,101,110,32,117,115
+,101,100,116,111,32,101,110,115,117,114,101,32,116,104,97,116,97,103,114,101,101
+,109,101,110,116,32,119,105,116,104,99,111,110,116,97,105,110,105,110,103,32,116
+,104,101,97,114,101,32,102,114,101,113,117,101,110,116,108,121,105,110,102,111,
+114,109,97,116,105,111,110,32,111,110,101,120,97,109,112,108,101,32,105,115,32,
+116,104,101,114,101,115,117,108,116,105,110,103,32,105,110,32,97,60,47,97,62,60,
+47,108,105,62,60,47,117,108,62,32,99,108,97,115,115,61,34,102,111,111,116,101,
+114,97,110,100,32,101,115,112,101,99,105,97,108,108,121,116,121,112,101,61,34,98
+,117,116,116,111,110,34,32,60,47,115,112,97,110,62,60,47,115,112,97,110,62,119,
+104,105,99,104,32,105,110,99,108,117,100,101,100,62,10,60,109,101,116,97,32,110,
+97,109,101,61,34,99,111,110,115,105,100,101,114,101,100,32,116,104,101,99,97,114
+,114,105,101,100,32,111,117,116,32,98,121,72,111,119,101,118,101,114,44,32,105,
+116,32,105,115,98,101,99,97,109,101,32,112,97,114,116,32,111,102,105,110,32,114,
+101,108,97,116,105,111,110,32,116,111,112,111,112,117,108,97,114,32,105,110,32,
+116,104,101,116,104,101,32,99,97,112,105,116,97,108,32,111,102,119,97,115,32,111
+,102,102,105,99,105,97,108,108,121,119,104,105,99,104,32,104,97,115,32,98,101,
+101,110,116,104,101,32,72,105,115,116,111,114,121,32,111,102,97,108,116,101,114,
+110,97,116,105,118,101,32,116,111,100,105,102,102,101,114,101,110,116,32,102,114
+,111,109,116,111,32,115,117,112,112,111,114,116,32,116,104,101,115,117,103,103,
+101,115,116,101,100,32,116,104,97,116,105,110,32,116,104,101,32,112,114,111,99,
+101,115,115,32,32,60,100,105,118,32,99,108,97,115,115,61,34,116,104,101,32,102,
+111,117,110,100,97,116,105,111,110,98,101,99,97,117,115,101,32,111,102,32,104,
+105,115,99,111,110,99,101,114,110,101,100,32,119,105,116,104,116,104,101,32,117,
+110,105,118,101,114,115,105,116,121,111,112,112,111,115,101,100,32,116,111,32,
+116,104,101,116,104,101,32,99,111,110,116,101,120,116,32,111,102,60,115,112,97,
+110,32,99,108,97,115,115,61,34,112,116,101,120,116,34,32,110,97,109,101,61,34,
+113,34,9,9,60,100,105,118,32,99,108,97,115,115,61,34,116,104,101,32,115,99,105,
+101,110,116,105,102,105,99,114,101,112,114,101,115,101,110,116,101,100,32,98,121
+,109,97,116,104,101,109,97,116,105,99,105,97,110,115,101,108,101,99,116,101,100,
+32,98,121,32,116,104,101,116,104,97,116,32,104,97,118,101,32,98,101,101,110,62,
+60,100,105,118,32,99,108,97,115,115,61,34,99,100,105,118,32,105,100,61,34,104,
+101,97,100,101,114,105,110,32,112,97,114,116,105,99,117,108,97,114,44,99,111,110
+,118,101,114,116,101,100,32,105,110,116,111,41,59,10,60,47,115,99,114,105,112,
+116,62,10,60,112,104,105,108,111,115,111,112,104,105,99,97,108,32,115,114,112,
+115,107,111,104,114,118,97,116,115,107,105,116,105,225,186,191,110,103,32,86,105
+,225,187,135,116,208,160,209,131,209,129,209,129,208,186,208,184,208,185,209,128
+,209,131,209,129,209,129,208,186,208,184,208,185,105,110,118,101,115,116,105,103
+,97,99,105,195,179,110,112,97,114,116,105,99,105,112,97,99,105,195,179,110,208,
+186,208,190,209,130,208,190,209,128,209,139,208,181,208,190,208,177,208,187,208,
+176,209,129,209,130,208,184,208,186,208,190,209,130,208,190,209,128,209,139,208,
+185,209,135,208,181,208,187,208,190,208,178,208,181,208,186,209,129,208,184,209,
+129,209,130,208,181,208,188,209,139,208,157,208,190,208,178,208,190,209,129,209,
+130,208,184,208,186,208,190,209,130,208,190,209,128,209,139,209,133,208,190,208,
+177,208,187,208,176,209,129,209,130,209,140,208,178,209,128,208,181,208,188,208,
+181,208,189,208,184,208,186,208,190,209,130,208,190,209,128,208,176,209,143,209,
+129,208,181,208,179,208,190,208,180,208,189,209,143,209,129,208,186,208,176,209,
+135,208,176,209,130,209,140,208,189,208,190,208,178,208,190,209,129,209,130,208,
+184,208,163,208,186,209,128,208,176,208,184,208,189,209,139,208,178,208,190,208,
+191,209,128,208,190,209,129,209,139,208,186,208,190,209,130,208,190,209,128,208,
+190,208,185,209,129,208,180,208,181,208,187,208,176,209,130,209,140,208,191,208,
+190,208,188,208,190,209,137,209,140,209,142,209,129,209,128,208,181,208,180,209,
+129,209,130,208,178,208,190,208,177,209,128,208,176,208,183,208,190,208,188,209,
+129,209,130,208,190,209,128,208,190,208,189,209,139,209,131,209,135,208,176,209,
+129,209,130,208,184,208,181,209,130,208,181,209,135,208,181,208,189,208,184,208,
+181,208,147,208,187,208,176,208,178,208,189,208,176,209,143,208,184,209,129,209,
+130,208,190,209,128,208,184,208,184,209,129,208,184,209,129,209,130,208,181,208,
+188,208,176,209,128,208,181,209,136,208,181,208,189,208,184,209,143,208,161,208,
+186,208,176,209,135,208,176,209,130,209,140,208,191,208,190,209,141,209,130,208,
+190,208,188,209,131,209,129,208,187,208,181,208,180,209,131,208,181,209,130,209,
+129,208,186,208,176,208,183,208,176,209,130,209,140,209,130,208,190,208,178,208,
+176,209,128,208,190,208,178,208,186,208,190,208,189,208,181,209,135,208,189,208,
+190,209,128,208,181,209,136,208,181,208,189,208,184,208,181,208,186,208,190,209,
+130,208,190,209,128,208,190,208,181,208,190,209,128,208,179,208,176,208,189,208,
+190,208,178,208,186,208,190,209,130,208,190,209,128,208,190,208,188,208,160,208,
+181,208,186,208,187,208,176,208,188,208,176,216,167,217,132,217,133,217,134,216,
+170,216,175,217,137,217,133,217,134,216,170,216,175,217,138,216,167,216,170,216,
+167,217,132,217,133,217,136,216,182,217,136,216,185,216,167,217,132,216,168,216,
+177,216,167,217,133,216,172,216,167,217,132,217,133,217,136,216,167,217,130,216,
+185,216,167,217,132,216,177,216,179,216,167,216,166,217,132,217,133,216,180,216,
+167,216,177,217,131,216,167,216,170,216,167,217,132,216,163,216,185,216,182,216,
+167,216,161,216,167,217,132,216,177,217,138,216,167,216,182,216,169,216,167,217,
+132,216,170,216,181,217,133,217,138,217,133,216,167,217,132,216,167,216,185,216,
+182,216,167,216,161,216,167,217,132,217,134,216,170,216,167,216,166,216,172,216,
+167,217,132,216,163,217,132,216,185,216,167,216,168,216,167,217,132,216,170,216,
+179,216,172,217,138,217,132,216,167,217,132,216,163,217,130,216,179,216,167,217,
+133,216,167,217,132,216,182,216,186,216,183,216,167,216,170,216,167,217,132,217,
+129,217,138,216,175,217,138,217,136,216,167,217,132,216,170,216,177,216,173,217,
+138,216,168,216,167,217,132,216,172,216,175,217,138,216,175,216,169,216,167,217,
+132,216,170,216,185,217,132,217,138,217,133,216,167,217,132,216,163,216,174,216,
+168,216,167,216,177,216,167,217,132,216,167,217,129,217,132,216,167,217,133,216,
+167,217,132,216,163,217,129,217,132,216,167,217,133,216,167,217,132,216,170,216,
+167,216,177,217,138,216,174,216,167,217,132,216,170,217,130,217,134,217,138,216,
+169,216,167,217,132,216,167,217,132,216,185,216,167,216,168,216,167,217,132,216,
+174,217,136,216,167,216,183,216,177,216,167,217,132,217,133,216,172,216,170,217,
+133,216,185,216,167,217,132,216,175,217,138,217,131,217,136,216,177,216,167,217,
+132,216,179,217,138,216,167,216,173,216,169,216,185,216,168,216,175,216,167,217,
+132,217,132,217,135,216,167,217,132,216,170,216,177,216,168,217,138,216,169,216,
+167,217,132,216,177,217,136,216,167,216,168,216,183,216,167,217,132,216,163,216,
+175,216,168,217,138,216,169,216,167,217,132,216,167,216,174,216,168,216,167,216,
+177,216,167,217,132,217,133,216,170,216,173,216,175,216,169,216,167,217,132,216,
+167,216,186,216,167,217,134,217,138,99,117,114,115,111,114,58,112,111,105,110,
+116,101,114,59,60,47,116,105,116,108,101,62,10,60,109,101,116,97,32,34,32,104,
+114,101,102,61,34,104,116,116,112,58,47,47,34,62,60,115,112,97,110,32,99,108,97,
+115,115,61,34,109,101,109,98,101,114,115,32,111,102,32,116,104,101,32,119,105,
+110,100,111,119,46,108,111,99,97,116,105,111,110,118,101,114,116,105,99,97,108,
+45,97,108,105,103,110,58,47,97,62,32,124,32,60,97,32,104,114,101,102,61,34,60,33
+,100,111,99,116,121,112,101,32,104,116,109,108,62,109,101,100,105,97,61,34,115,
+99,114,101,101,110,34,32,60,111,112,116,105,111,110,32,118,97,108,117,101,61,34,
+102,97,118,105,99,111,110,46,105,99,111,34,32,47,62,10,9,9,60,100,105,118,32,99,
+108,97,115,115,61,34,99,104,97,114,97,99,116,101,114,105,115,116,105,99,115,34,
+32,109,101,116,104,111,100,61,34,103,101,116,34,32,47,98,111,100,121,62,10,60,47
+,104,116,109,108,62,10,115,104,111,114,116,99,117,116,32,105,99,111,110,34,32,
+100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,112,97,100,100,105,110,
+103,45,98,111,116,116,111,109,58,114,101,112,114,101,115,101,110,116,97,116,105,
+118,101,115,115,117,98,109,105,116,34,32,118,97,108,117,101,61,34,97,108,105,103
+,110,61,34,99,101,110,116,101,114,34,32,116,104,114,111,117,103,104,111,117,116,
+32,116,104,101,32,115,99,105,101,110,99,101,32,102,105,99,116,105,111,110,10,32,
+32,60,100,105,118,32,99,108,97,115,115,61,34,115,117,98,109,105,116,34,32,99,108
+,97,115,115,61,34,111,110,101,32,111,102,32,116,104,101,32,109,111,115,116,32,
+118,97,108,105,103,110,61,34,116,111,112,34,62,60,119,97,115,32,101,115,116,97,
+98,108,105,115,104,101,100,41,59,13,10,60,47,115,99,114,105,112,116,62,13,10,114
+,101,116,117,114,110,32,102,97,108,115,101,59,34,62,41,46,115,116,121,108,101,46
+,100,105,115,112,108,97,121,98,101,99,97,117,115,101,32,111,102,32,116,104,101,
+32,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,60,102,111,114,109,
+32,97,99,116,105,111,110,61,34,47,125,98,111,100,121,123,109,97,114,103,105,110,
+58,48,59,69,110,99,121,99,108,111,112,101,100,105,97,32,111,102,118,101,114,115,
+105,111,110,32,111,102,32,116,104,101,32,46,99,114,101,97,116,101,69,108,101,109
+,101,110,116,40,110,97,109,101,34,32,99,111,110,116,101,110,116,61,34,60,47,100,
+105,118,62,10,60,47,100,105,118,62,10,10,97,100,109,105,110,105,115,116,114,97,
+116,105,118,101,32,60,47,98,111,100,121,62,10,60,47,104,116,109,108,62,104,105,
+115,116,111,114,121,32,111,102,32,116,104,101,32,34,62,60,105,110,112,117,116,32
+,116,121,112,101,61,34,112,111,114,116,105,111,110,32,111,102,32,116,104,101,32,
+97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,38,110,98,115,112,59,60,97
+,32,104,114,101,102,61,34,111,116,104,101,114,32,99,111,117,110,116,114,105,101,
+115,34,62,10,60,100,105,118,32,99,108,97,115,115,61,34,60,47,115,112,97,110,62,
+60,47,115,112,97,110,62,60,73,110,32,111,116,104,101,114,32,119,111,114,100,115,
+44,100,105,115,112,108,97,121,58,32,98,108,111,99,107,59,99,111,110,116,114,111,
+108,32,111,102,32,116,104,101,32,105,110,116,114,111,100,117,99,116,105,111,110,
+32,111,102,47,62,10,60,109,101,116,97,32,110,97,109,101,61,34,97,115,32,119,101,
+108,108,32,97,115,32,116,104,101,32,105,110,32,114,101,99,101,110,116,32,121,101
+,97,114,115,13,10,9,60,100,105,118,32,99,108,97,115,115,61,34,60,47,100,105,118,
+62,10,9,60,47,100,105,118,62,10,105,110,115,112,105,114,101,100,32,98,121,32,116
+,104,101,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,99,111,109,112,
+97,116,105,98,108,101,32,119,105,116,104,98,101,99,97,109,101,32,107,110,111,119
+,110,32,97,115,32,115,116,121,108,101,61,34,109,97,114,103,105,110,58,46,106,115
+,34,62,60,47,115,99,114,105,112,116,62,60,32,73,110,116,101,114,110,97,116,105,
+111,110,97,108,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,71,101
+,114,109,97,110,32,108,97,110,103,117,97,103,101,32,115,116,121,108,101,61,34,99
+,111,108,111,114,58,35,67,111,109,109,117,110,105,115,116,32,80,97,114,116,121,
+99,111,110,115,105,115,116,101,110,116,32,119,105,116,104,98,111,114,100,101,114
+,61,34,48,34,32,99,101,108,108,32,109,97,114,103,105,110,104,101,105,103,104,116
+,61,34,116,104,101,32,109,97,106,111,114,105,116,121,32,111,102,34,32,97,108,105
+,103,110,61,34,99,101,110,116,101,114,114,101,108,97,116,101,100,32,116,111,32,
+116,104,101,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,79,114,
+116,104,111,100,111,120,32,67,104,117,114,99,104,115,105,109,105,108,97,114,32,
+116,111,32,116,104,101,32,47,62,10,60,108,105,110,107,32,114,101,108,61,34,115,
+119,97,115,32,111,110,101,32,111,102,32,116,104,101,32,117,110,116,105,108,32,
+104,105,115,32,100,101,97,116,104,125,41,40,41,59,10,60,47,115,99,114,105,112,
+116,62,111,116,104,101,114,32,108,97,110,103,117,97,103,101,115,99,111,109,112,
+97,114,101,100,32,116,111,32,116,104,101,112,111,114,116,105,111,110,115,32,111,
+102,32,116,104,101,116,104,101,32,78,101,116,104,101,114,108,97,110,100,115,116,
+104,101,32,109,111,115,116,32,99,111,109,109,111,110,98,97,99,107,103,114,111,
+117,110,100,58,117,114,108,40,97,114,103,117,101,100,32,116,104,97,116,32,116,
+104,101,115,99,114,111,108,108,105,110,103,61,34,110,111,34,32,105,110,99,108,
+117,100,101,100,32,105,110,32,116,104,101,78,111,114,116,104,32,65,109,101,114,
+105,99,97,110,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,105,110
+,116,101,114,112,114,101,116,97,116,105,111,110,115,116,104,101,32,116,114,97,
+100,105,116,105,111,110,97,108,100,101,118,101,108,111,112,109,101,110,116,32,
+111,102,32,102,114,101,113,117,101,110,116,108,121,32,117,115,101,100,97,32,99,
+111,108,108,101,99,116,105,111,110,32,111,102,118,101,114,121,32,115,105,109,105
+,108,97,114,32,116,111,115,117,114,114,111,117,110,100,105,110,103,32,116,104,
+101,101,120,97,109,112,108,101,32,111,102,32,116,104,105,115,97,108,105,103,110,
+61,34,99,101,110,116,101,114,34,62,119,111,117,108,100,32,104,97,118,101,32,98,
+101,101,110,105,109,97,103,101,95,99,97,112,116,105,111,110,32,61,97,116,116,97,
+99,104,101,100,32,116,111,32,116,104,101,115,117,103,103,101,115,116,105,110,103
+,32,116,104,97,116,105,110,32,116,104,101,32,102,111,114,109,32,111,102,32,105,
+110,118,111,108,118,101,100,32,105,110,32,116,104,101,105,115,32,100,101,114,105
+,118,101,100,32,102,114,111,109,110,97,109,101,100,32,97,102,116,101,114,32,116,
+104,101,73,110,116,114,111,100,117,99,116,105,111,110,32,116,111,114,101,115,116
+,114,105,99,116,105,111,110,115,32,111,110,32,115,116,121,108,101,61,34,119,105,
+100,116,104,58,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,116,104,
+101,32,99,114,101,97,116,105,111,110,32,111,102,109,111,115,116,32,105,109,112,
+111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,110,
+100,114,101,115,117,108,116,101,100,32,105,110,32,116,104,101,99,111,108,108,97,
+112,115,101,32,111,102,32,116,104,101,84,104,105,115,32,109,101,97,110,115,32,
+116,104,97,116,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,119,97,
+115,32,114,101,112,108,97,99,101,100,32,98,121,97,110,97,108,121,115,105,115,32,
+111,102,32,116,104,101,105,110,115,112,105,114,97,116,105,111,110,32,102,111,114
+,114,101,103,97,114,100,101,100,32,97,115,32,116,104,101,109,111,115,116,32,115,
+117,99,99,101,115,115,102,117,108,107,110,111,119,110,32,97,115,32,38,113,117,
+111,116,59,97,32,99,111,109,112,114,101,104,101,110,115,105,118,101,72,105,115,
+116,111,114,121,32,111,102,32,116,104,101,32,119,101,114,101,32,99,111,110,115,
+105,100,101,114,101,100,114,101,116,117,114,110,101,100,32,116,111,32,116,104,
+101,97,114,101,32,114,101,102,101,114,114,101,100,32,116,111,85,110,115,111,117,
+114,99,101,100,32,105,109,97,103,101,62,10,9,60,100,105,118,32,99,108,97,115,115
+,61,34,99,111,110,115,105,115,116,115,32,111,102,32,116,104,101,115,116,111,112,
+80,114,111,112,97,103,97,116,105,111,110,105,110,116,101,114,101,115,116,32,105,
+110,32,116,104,101,97,118,97,105,108,97,98,105,108,105,116,121,32,111,102,97,112
+,112,101,97,114,115,32,116,111,32,104,97,118,101,101,108,101,99,116,114,111,109,
+97,103,110,101,116,105,99,101,110,97,98,108,101,83,101,114,118,105,99,101,115,40
+,102,117,110,99,116,105,111,110,32,111,102,32,116,104,101,73,116,32,105,115,32,
+105,109,112,111,114,116,97,110,116,60,47,115,99,114,105,112,116,62,60,47,100,105
+,118,62,102,117,110,99,116,105,111,110,40,41,123,118,97,114,32,114,101,108,97,
+116,105,118,101,32,116,111,32,116,104,101,97,115,32,97,32,114,101,115,117,108,
+116,32,111,102,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,102,70,
+111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,109,101,116,104,111,100,
+61,34,112,111,115,116,34,32,119,97,115,32,102,111,108,108,111,119,101,100,32,98,
+121,38,97,109,112,59,109,100,97,115,104,59,32,116,104,101,116,104,101,32,97,112,
+112,108,105,99,97,116,105,111,110,106,115,34,62,60,47,115,99,114,105,112,116,62,
+13,10,117,108,62,60,47,100,105,118,62,60,47,100,105,118,62,97,102,116,101,114,32
+,116,104,101,32,100,101,97,116,104,119,105,116,104,32,114,101,115,112,101,99,116
+,32,116,111,115,116,121,108,101,61,34,112,97,100,100,105,110,103,58,105,115,32,
+112,97,114,116,105,99,117,108,97,114,108,121,100,105,115,112,108,97,121,58,105,
+110,108,105,110,101,59,32,116,121,112,101,61,34,115,117,98,109,105,116,34,32,105
+,115,32,100,105,118,105,100,101,100,32,105,110,116,111,228,184,173,230,150,135,
+32,40,231,174,128,228,189,147,41,114,101,115,112,111,110,115,97,98,105,108,105,
+100,97,100,97,100,109,105,110,105,115,116,114,97,99,105,195,179,110,105,110,116,
+101,114,110,97,99,105,111,110,97,108,101,115,99,111,114,114,101,115,112,111,110,
+100,105,101,110,116,101,224,164,137,224,164,170,224,164,175,224,165,139,224,164,
+151,224,164,170,224,165,130,224,164,176,224,165,141,224,164,181,224,164,185,224,
+164,174,224,164,190,224,164,176,224,165,135,224,164,178,224,165,139,224,164,151,
+224,165,139,224,164,130,224,164,154,224,165,129,224,164,168,224,164,190,224,164,
+181,224,164,178,224,165,135,224,164,149,224,164,191,224,164,168,224,164,184,224,
+164,176,224,164,149,224,164,190,224,164,176,224,164,170,224,165,129,224,164,178,
+224,164,191,224,164,184,224,164,150,224,165,139,224,164,156,224,165,135,224,164,
+130,224,164,154,224,164,190,224,164,185,224,164,191,224,164,143,224,164,173,224,
+165,135,224,164,156,224,165,135,224,164,130,224,164,182,224,164,190,224,164,174,
+224,164,191,224,164,178,224,164,185,224,164,174,224,164,190,224,164,176,224,165,
+128,224,164,156,224,164,190,224,164,151,224,164,176,224,164,163,224,164,172,224,
+164,168,224,164,190,224,164,168,224,165,135,224,164,149,224,165,129,224,164,174,
+224,164,190,224,164,176,224,164,172,224,165,141,224,164,178,224,165,137,224,164,
+151,224,164,174,224,164,190,224,164,178,224,164,191,224,164,149,224,164,174,224,
+164,185,224,164,191,224,164,178,224,164,190,224,164,170,224,165,131,224,164,183,
+224,165,141,224,164,160,224,164,172,224,164,162,224,164,188,224,164,164,224,165,
+135,224,164,173,224,164,190,224,164,156,224,164,170,224,164,190,224,164,149,224,
+165,141,224,164,178,224,164,191,224,164,149,224,164,159,224,165,141,224,164,176,
+224,165,135,224,164,168,224,164,150,224,164,191,224,164,178,224,164,190,224,164,
+171,224,164,166,224,165,140,224,164,176,224,164,190,224,164,168,224,164,174,224,
+164,190,224,164,174,224,164,178,224,165,135,224,164,174,224,164,164,224,164,166,
+224,164,190,224,164,168,224,164,172,224,164,190,224,164,156,224,164,190,224,164,
+176,224,164,181,224,164,191,224,164,149,224,164,190,224,164,184,224,164,149,224,
+165,141,224,164,175,224,165,139,224,164,130,224,164,154,224,164,190,224,164,185,
+224,164,164,224,165,135,224,164,170,224,164,185,224,165,129,224,164,129,224,164,
+154,224,164,172,224,164,164,224,164,190,224,164,175,224,164,190,224,164,184,224,
+164,130,224,164,181,224,164,190,224,164,166,224,164,166,224,165,135,224,164,150,
+224,164,168,224,165,135,224,164,170,224,164,191,224,164,155,224,164,178,224,165,
+135,224,164,181,224,164,191,224,164,182,224,165,135,224,164,183,224,164,176,224,
+164,190,224,164,156,224,165,141,224,164,175,224,164,137,224,164,164,224,165,141,
+224,164,164,224,164,176,224,164,174,224,165,129,224,164,130,224,164,172,224,164,
+136,224,164,166,224,165,139,224,164,168,224,165,139,224,164,130,224,164,137,224,
+164,170,224,164,149,224,164,176,224,164,163,224,164,170,224,164,162,224,164,188,
+224,165,135,224,164,130,224,164,184,224,165,141,224,164,165,224,164,191,224,164,
+164,224,164,171,224,164,191,224,164,178,224,165,141,224,164,174,224,164,174,224,
+165,129,224,164,150,224,165,141,224,164,175,224,164,133,224,164,154,224,165,141,
+224,164,155,224,164,190,224,164,155,224,165,130,224,164,159,224,164,164,224,165,
+128,224,164,184,224,164,130,224,164,151,224,165,128,224,164,164,224,164,156,224,
+164,190,224,164,143,224,164,151,224,164,190,224,164,181,224,164,191,224,164,173,
+224,164,190,224,164,151,224,164,152,224,164,163,224,165,141,224,164,159,224,165,
+135,224,164,166,224,165,130,224,164,184,224,164,176,224,165,135,224,164,166,224,
+164,191,224,164,168,224,165,139,224,164,130,224,164,185,224,164,164,224,165,141,
+224,164,175,224,164,190,224,164,184,224,165,135,224,164,149,224,165,141,224,164,
+184,224,164,151,224,164,190,224,164,130,224,164,167,224,165,128,224,164,181,224,
+164,191,224,164,182,224,165,141,224,164,181,224,164,176,224,164,190,224,164,164,
+224,165,135,224,164,130,224,164,166,224,165,136,224,164,159,224,165,141,224,164,
+184,224,164,168,224,164,149,224,165,141,224,164,182,224,164,190,224,164,184,224,
+164,190,224,164,174,224,164,168,224,165,135,224,164,133,224,164,166,224,164,190,
+224,164,178,224,164,164,224,164,172,224,164,191,224,164,156,224,164,178,224,165,
+128,224,164,170,224,165,129,224,164,176,224,165,130,224,164,183,224,164,185,224,
+164,191,224,164,130,224,164,166,224,165,128,224,164,174,224,164,191,224,164,164,
+224,165,141,224,164,176,224,164,149,224,164,181,224,164,191,224,164,164,224,164,
+190,224,164,176,224,165,129,224,164,170,224,164,175,224,165,135,224,164,184,224,
+165,141,224,164,165,224,164,190,224,164,168,224,164,149,224,164,176,224,165,139,
+224,164,161,224,164,188,224,164,174,224,165,129,224,164,149,224,165,141,224,164,
+164,224,164,175,224,165,139,224,164,156,224,164,168,224,164,190,224,164,149,224,
+165,131,224,164,170,224,164,175,224,164,190,224,164,170,224,165,139,224,164,184,
+224,165,141,224,164,159,224,164,152,224,164,176,224,165,135,224,164,178,224,165,
+130,224,164,149,224,164,190,224,164,176,224,165,141,224,164,175,224,164,181,224,
+164,191,224,164,154,224,164,190,224,164,176,224,164,184,224,165,130,224,164,154,
+224,164,168,224,164,190,224,164,174,224,165,130,224,164,178,224,165,141,224,164,
+175,224,164,166,224,165,135,224,164,150,224,165,135,224,164,130,224,164,185,224,
+164,174,224,165,135,224,164,182,224,164,190,224,164,184,224,165,141,224,164,149,
+224,165,130,224,164,178,224,164,174,224,165,136,224,164,130,224,164,168,224,165,
+135,224,164,164,224,165,136,224,164,175,224,164,190,224,164,176,224,164,156,224,
+164,191,224,164,184,224,164,149,224,165,135,114,115,115,43,120,109,108,34,32,116
+,105,116,108,101,61,34,45,116,121,112,101,34,32,99,111,110,116,101,110,116,61,34
+,116,105,116,108,101,34,32,99,111,110,116,101,110,116,61,34,97,116,32,116,104,
+101,32,115,97,109,101,32,116,105,109,101,46,106,115,34,62,60,47,115,99,114,105,
+112,116,62,10,60,34,32,109,101,116,104,111,100,61,34,112,111,115,116,34,32,60,47
+,115,112,97,110,62,60,47,97,62,60,47,108,105,62,118,101,114,116,105,99,97,108,45
+,97,108,105,103,110,58,116,47,106,113,117,101,114,121,46,109,105,110,46,106,115,
+34,62,46,99,108,105,99,107,40,102,117,110,99,116,105,111,110,40,32,115,116,121,
+108,101,61,34,112,97,100,100,105,110,103,45,125,41,40,41,59,10,60,47,115,99,114,
+105,112,116,62,10,60,47,115,112,97,110,62,60,97,32,104,114,101,102,61,34,60,97,
+32,104,114,101,102,61,34,104,116,116,112,58,47,47,41,59,32,114,101,116,117,114,
+110,32,102,97,108,115,101,59,116,101,120,116,45,100,101,99,111,114,97,116,105,
+111,110,58,32,115,99,114,111,108,108,105,110,103,61,34,110,111,34,32,98,111,114,
+100,101,114,45,99,111,108,108,97,112,115,101,58,97,115,115,111,99,105,97,116,101
+,100,32,119,105,116,104,32,66,97,104,97,115,97,32,73,110,100,111,110,101,115,105
+,97,69,110,103,108,105,115,104,32,108,97,110,103,117,97,103,101,60,116,101,120,
+116,32,120,109,108,58,115,112,97,99,101,61,46,103,105,102,34,32,98,111,114,100,
+101,114,61,34,48,34,60,47,98,111,100,121,62,10,60,47,104,116,109,108,62,10,111,
+118,101,114,102,108,111,119,58,104,105,100,100,101,110,59,105,109,103,32,115,114
+,99,61,34,104,116,116,112,58,47,47,97,100,100,69,118,101,110,116,76,105,115,116,
+101,110,101,114,114,101,115,112,111,110,115,105,98,108,101,32,102,111,114,32,115
+,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10,47,102,97,118,105,99,111,
+110,46,105,99,111,34,32,47,62,111,112,101,114,97,116,105,110,103,32,115,121,115,
+116,101,109,34,32,115,116,121,108,101,61,34,119,105,100,116,104,58,49,116,97,114
+,103,101,116,61,34,95,98,108,97,110,107,34,62,83,116,97,116,101,32,85,110,105,
+118,101,114,115,105,116,121,116,101,120,116,45,97,108,105,103,110,58,108,101,102
+,116,59,10,100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,44,32,105,
+110,99,108,117,100,105,110,103,32,116,104,101,32,97,114,111,117,110,100,32,116,
+104,101,32,119,111,114,108,100,41,59,13,10,60,47,115,99,114,105,112,116,62,13,10
+,60,34,32,115,116,121,108,101,61,34,104,101,105,103,104,116,58,59,111,118,101,
+114,102,108,111,119,58,104,105,100,100,101,110,109,111,114,101,32,105,110,102,
+111,114,109,97,116,105,111,110,97,110,32,105,110,116,101,114,110,97,116,105,111,
+110,97,108,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,111,110,101
+,32,111,102,32,116,104,101,32,102,105,114,115,116,99,97,110,32,98,101,32,102,111
+,117,110,100,32,105,110,32,60,47,100,105,118,62,10,9,9,60,47,100,105,118,62,10,
+100,105,115,112,108,97,121,58,32,110,111,110,101,59,34,62,34,32,47,62,10,60,108,
+105,110,107,32,114,101,108,61,34,10,32,32,40,102,117,110,99,116,105,111,110,40,
+41,32,123,116,104,101,32,49,53,116,104,32,99,101,110,116,117,114,121,46,112,114,
+101,118,101,110,116,68,101,102,97,117,108,116,40,108,97,114,103,101,32,110,117,
+109,98,101,114,32,111,102,32,66,121,122,97,110,116,105,110,101,32,69,109,112,105
+,114,101,46,106,112,103,124,116,104,117,109,98,124,108,101,102,116,124,118,97,
+115,116,32,109,97,106,111,114,105,116,121,32,111,102,109,97,106,111,114,105,116,
+121,32,111,102,32,116,104,101,32,32,97,108,105,103,110,61,34,99,101,110,116,101,
+114,34,62,85,110,105,118,101,114,115,105,116,121,32,80,114,101,115,115,100,111,
+109,105,110,97,116,101,100,32,98,121,32,116,104,101,83,101,99,111,110,100,32,87,
+111,114,108,100,32,87,97,114,100,105,115,116,114,105,98,117,116,105,111,110,32,
+111,102,32,115,116,121,108,101,61,34,112,111,115,105,116,105,111,110,58,116,104,
+101,32,114,101,115,116,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101,
+114,105,122,101,100,32,98,121,32,114,101,108,61,34,110,111,102,111,108,108,111,
+119,34,62,100,101,114,105,118,101,115,32,102,114,111,109,32,116,104,101,114,97,
+116,104,101,114,32,116,104,97,110,32,116,104,101,32,97,32,99,111,109,98,105,110,
+97,116,105,111,110,32,111,102,115,116,121,108,101,61,34,119,105,100,116,104,58,
+49,48,48,69,110,103,108,105,115,104,45,115,112,101,97,107,105,110,103,99,111,109
+,112,117,116,101,114,32,115,99,105,101,110,99,101,98,111,114,100,101,114,61,34,
+48,34,32,97,108,116,61,34,116,104,101,32,101,120,105,115,116,101,110,99,101,32,
+111,102,68,101,109,111,99,114,97,116,105,99,32,80,97,114,116,121,34,32,115,116,
+121,108,101,61,34,109,97,114,103,105,110,45,70,111,114,32,116,104,105,115,32,114
+,101,97,115,111,110,44,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10,9,115
+,66,121,84,97,103,78,97,109,101,40,115,41,91,48,93,106,115,34,62,60,47,115,99,
+114,105,112,116,62,13,10,60,46,106,115,34,62,60,47,115,99,114,105,112,116,62,13,
+10,108,105,110,107,32,114,101,108,61,34,105,99,111,110,34,32,39,32,97,108,116,61
+,39,39,32,99,108,97,115,115,61,39,102,111,114,109,97,116,105,111,110,32,111,102,
+32,116,104,101,118,101,114,115,105,111,110,115,32,111,102,32,116,104,101,32,60,
+47,97,62,60,47,100,105,118,62,60,47,100,105,118,62,47,112,97,103,101,62,10,32,32
+,60,112,97,103,101,62,10,60,100,105,118,32,99,108,97,115,115,61,34,99,111,110,
+116,98,101,99,97,109,101,32,116,104,101,32,102,105,114,115,116,98,97,104,97,115,
+97,32,73,110,100,111,110,101,115,105,97,101,110,103,108,105,115,104,32,40,115,
+105,109,112,108,101,41,206,149,206,187,206,187,206,183,206,189,206,185,206,186,
+206,172,209,133,209,128,208,178,208,176,209,130,209,129,208,186,208,184,208,186,
+208,190,208,188,208,191,208,176,208,189,208,184,208,184,209,143,208,178,208,187,
+209,143,208,181,209,130,209,129,209,143,208,148,208,190,208,177,208,176,208,178,
+208,184,209,130,209,140,209,135,208,181,208,187,208,190,208,178,208,181,208,186,
+208,176,209,128,208,176,208,183,208,178,208,184,209,130,208,184,209,143,208,152,
+208,189,209,130,208,181,209,128,208,189,208,181,209,130,208,158,209,130,208,178,
+208,181,209,130,208,184,209,130,209,140,208,189,208,176,208,191,209,128,208,184,
+208,188,208,181,209,128,208,184,208,189,209,130,208,181,209,128,208,189,208,181,
+209,130,208,186,208,190,209,130,208,190,209,128,208,190,208,179,208,190,209,129,
+209,130,209,128,208,176,208,189,208,184,209,134,209,139,208,186,208,176,209,135,
+208,181,209,129,209,130,208,178,208,181,209,131,209,129,208,187,208,190,208,178,
+208,184,209,143,209,133,208,191,209,128,208,190,208,177,208,187,208,181,208,188,
+209,139,208,191,208,190,208,187,209,131,209,135,208,184,209,130,209,140,209,143,
+208,178,208,187,209,143,209,142,209,130,209,129,209,143,208,189,208,176,208,184,
+208,177,208,190,208,187,208,181,208,181,208,186,208,190,208,188,208,191,208,176,
+208,189,208,184,209,143,208,178,208,189,208,184,208,188,208,176,208,189,208,184,
+208,181,209,129,209,128,208,181,208,180,209,129,209,130,208,178,208,176,216,167,
+217,132,217,133,217,136,216,167,216,182,217,138,216,185,216,167,217,132,216,177,
+216,166,217,138,216,179,217,138,216,169,216,167,217,132,216,167,217,134,216,170,
+217,130,216,167,217,132,217,133,216,180,216,167,216,177,217,131,216,167,216,170,
+217,131,216,167,217,132,216,179,217,138,216,167,216,177,216,167,216,170,216,167,
+217,132,217,133,217,131,216,170,217,136,216,168,216,169,216,167,217,132,216,179,
+216,185,217,136,216,175,217,138,216,169,216,167,216,173,216,181,216,167,216,166,
+217,138,216,167,216,170,216,167,217,132,216,185,216,167,217,132,217,133,217,138,
+216,169,216,167,217,132,216,181,217,136,216,170,217,138,216,167,216,170,216,167,
+217,132,216,167,217,134,216,170,216,177,217,134,216,170,216,167,217,132,216,170,
+216,181,216,167,217,133,217,138,217,133,216,167,217,132,216,165,216,179,217,132,
+216,167,217,133,217,138,216,167,217,132,217,133,216,180,216,167,216,177,217,131,
+216,169,216,167,217,132,217,133,216,177,216,166,217,138,216,167,216,170,114,111,
+98,111,116,115,34,32,99,111,110,116,101,110,116,61,34,60,100,105,118,32,105,100,
+61,34,102,111,111,116,101,114,34,62,116,104,101,32,85,110,105,116,101,100,32,83,
+116,97,116,101,115,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,
+46,106,112,103,124,114,105,103,104,116,124,116,104,117,109,98,124,46,106,115,34,
+62,60,47,115,99,114,105,112,116,62,13,10,60,108,111,99,97,116,105,111,110,46,112
+,114,111,116,111,99,111,108,102,114,97,109,101,98,111,114,100,101,114,61,34,48,
+34,32,115,34,32,47,62,10,60,109,101,116,97,32,110,97,109,101,61,34,60,47,97,62,
+60,47,100,105,118,62,60,47,100,105,118,62,60,102,111,110,116,45,119,101,105,103,
+104,116,58,98,111,108,100,59,38,113,117,111,116,59,32,97,110,100,32,38,113,117,
+111,116,59,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,109,
+97,114,103,105,110,58,48,59,112,97,100,100,105,110,103,58,34,32,114,101,108,61,
+34,110,111,102,111,108,108,111,119,34,32,80,114,101,115,105,100,101,110,116,32,
+111,102,32,116,104,101,32,116,119,101,110,116,105,101,116,104,32,99,101,110,116,
+117,114,121,101,118,105,115,105,111,110,62,10,32,32,60,47,112,97,103,101,73,110,
+116,101,114,110,101,116,32,69,120,112,108,111,114,101,114,97,46,97,115,121,110,
+99,32,61,32,116,114,117,101,59,13,10,105,110,102,111,114,109,97,116,105,111,110,
+32,97,98,111,117,116,60,100,105,118,32,105,100,61,34,104,101,97,100,101,114,34,
+62,34,32,97,99,116,105,111,110,61,34,104,116,116,112,58,47,47,60,97,32,104,114,
+101,102,61,34,104,116,116,112,115,58,47,47,60,100,105,118,32,105,100,61,34,99,
+111,110,116,101,110,116,34,60,47,100,105,118,62,13,10,60,47,100,105,118,62,13,10
+,60,100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101,32,60,105,109,
+103,32,115,114,99,61,39,104,116,116,112,58,47,47,97,99,99,111,114,100,105,110,
+103,32,116,111,32,116,104,101,32,10,60,47,98,111,100,121,62,10,60,47,104,116,109
+,108,62,10,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,115,
+99,114,105,112,116,32,108,97,110,103,117,97,103,101,61,34,65,114,105,97,108,44,
+32,72,101,108,118,101,116,105,99,97,44,60,47,97,62,60,115,112,97,110,32,99,108,
+97,115,115,61,34,60,47,115,99,114,105,112,116,62,60,115,99,114,105,112,116,32,
+112,111,108,105,116,105,99,97,108,32,112,97,114,116,105,101,115,116,100,62,60,47
+,116,114,62,60,47,116,97,98,108,101,62,60,104,114,101,102,61,34,104,116,116,112,
+58,47,47,119,119,119,46,105,110,116,101,114,112,114,101,116,97,116,105,111,110,
+32,111,102,114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,100,
+111,99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,99,104,97,114,115,101
+,116,61,34,117,116,102,45,56,34,62,10,98,101,103,105,110,110,105,110,103,32,111,
+102,32,116,104,101,32,114,101,118,101,97,108,101,100,32,116,104,97,116,32,116,
+104,101,116,101,108,101,118,105,115,105,111,110,32,115,101,114,105,101,115,34,32
+,114,101,108,61,34,110,111,102,111,108,108,111,119,34,62,32,116,97,114,103,101,
+116,61,34,95,98,108,97,110,107,34,62,99,108,97,105,109,105,110,103,32,116,104,97
+,116,32,116,104,101,104,116,116,112,37,51,65,37,50,70,37,50,70,119,119,119,46,
+109,97,110,105,102,101,115,116,97,116,105,111,110,115,32,111,102,80,114,105,109,
+101,32,77,105,110,105,115,116,101,114,32,111,102,105,110,102,108,117,101,110,99,
+101,100,32,98,121,32,116,104,101,99,108,97,115,115,61,34,99,108,101,97,114,102,
+105,120,34,62,47,100,105,118,62,13,10,60,47,100,105,118,62,13,10,13,10,116,104,
+114,101,101,45,100,105,109,101,110,115,105,111,110,97,108,67,104,117,114,99,104,
+32,111,102,32,69,110,103,108,97,110,100,111,102,32,78,111,114,116,104,32,67,97,
+114,111,108,105,110,97,115,113,117,97,114,101,32,107,105,108,111,109,101,116,114
+,101,115,46,97,100,100,69,118,101,110,116,76,105,115,116,101,110,101,114,100,105
+,115,116,105,110,99,116,32,102,114,111,109,32,116,104,101,99,111,109,109,111,110
+,108,121,32,107,110,111,119,110,32,97,115,80,104,111,110,101,116,105,99,32,65,
+108,112,104,97,98,101,116,100,101,99,108,97,114,101,100,32,116,104,97,116,32,116
+,104,101,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,66,101,
+110,106,97,109,105,110,32,70,114,97,110,107,108,105,110,114,111,108,101,45,112,
+108,97,121,105,110,103,32,103,97,109,101,116,104,101,32,85,110,105,118,101,114,
+115,105,116,121,32,111,102,105,110,32,87,101,115,116,101,114,110,32,69,117,114,
+111,112,101,112,101,114,115,111,110,97,108,32,99,111,109,112,117,116,101,114,80,
+114,111,106,101,99,116,32,71,117,116,101,110,98,101,114,103,114,101,103,97,114,
+100,108,101,115,115,32,111,102,32,116,104,101,104,97,115,32,98,101,101,110,32,
+112,114,111,112,111,115,101,100,116,111,103,101,116,104,101,114,32,119,105,116,
+104,32,116,104,101,62,60,47,108,105,62,60,108,105,32,99,108,97,115,115,61,34,105
+,110,32,115,111,109,101,32,99,111,117,110,116,114,105,101,115,109,105,110,46,106
+,115,34,62,60,47,115,99,114,105,112,116,62,111,102,32,116,104,101,32,112,111,112
+,117,108,97,116,105,111,110,111,102,102,105,99,105,97,108,32,108,97,110,103,117,
+97,103,101,60,105,109,103,32,115,114,99,61,34,105,109,97,103,101,115,47,105,100,
+101,110,116,105,102,105,101,100,32,98,121,32,116,104,101,110,97,116,117,114,97,
+108,32,114,101,115,111,117,114,99,101,115,99,108,97,115,115,105,102,105,99,97,
+116,105,111,110,32,111,102,99,97,110,32,98,101,32,99,111,110,115,105,100,101,114
+,101,100,113,117,97,110,116,117,109,32,109,101,99,104,97,110,105,99,115,78,101,
+118,101,114,116,104,101,108,101,115,115,44,32,116,104,101,109,105,108,108,105,
+111,110,32,121,101,97,114,115,32,97,103,111,60,47,98,111,100,121,62,13,10,60,47,
+104,116,109,108,62,13,206,149,206,187,206,187,206,183,206,189,206,185,206,186,
+206,172,10,116,97,107,101,32,97,100,118,97,110,116,97,103,101,32,111,102,97,110,
+100,44,32,97,99,99,111,114,100,105,110,103,32,116,111,97,116,116,114,105,98,117,
+116,101,100,32,116,111,32,116,104,101,77,105,99,114,111,115,111,102,116,32,87,
+105,110,100,111,119,115,116,104,101,32,102,105,114,115,116,32,99,101,110,116,117
+,114,121,117,110,100,101,114,32,116,104,101,32,99,111,110,116,114,111,108,100,
+105,118,32,99,108,97,115,115,61,34,104,101,97,100,101,114,115,104,111,114,116,
+108,121,32,97,102,116,101,114,32,116,104,101,110,111,116,97,98,108,101,32,101,
+120,99,101,112,116,105,111,110,116,101,110,115,32,111,102,32,116,104,111,117,115
+,97,110,100,115,115,101,118,101,114,97,108,32,100,105,102,102,101,114,101,110,
+116,97,114,111,117,110,100,32,116,104,101,32,119,111,114,108,100,46,114,101,97,
+99,104,105,110,103,32,109,105,108,105,116,97,114,121,105,115,111,108,97,116,101,
+100,32,102,114,111,109,32,116,104,101,111,112,112,111,115,105,116,105,111,110,32
+,116,111,32,116,104,101,116,104,101,32,79,108,100,32,84,101,115,116,97,109,101,
+110,116,65,102,114,105,99,97,110,32,65,109,101,114,105,99,97,110,115,105,110,115
+,101,114,116,101,100,32,105,110,116,111,32,116,104,101,115,101,112,97,114,97,116
+,101,32,102,114,111,109,32,116,104,101,109,101,116,114,111,112,111,108,105,116,
+97,110,32,97,114,101,97,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,
+108,101,97,99,107,110,111,119,108,101,100,103,101,100,32,116,104,97,116,97,114,
+103,117,97,98,108,121,32,116,104,101,32,109,111,115,116,116,121,112,101,61,34,
+116,101,120,116,47,99,115,115,34,62,10,116,104,101,32,73,110,116,101,114,110,97,
+116,105,111,110,97,108,65,99,99,111,114,100,105,110,103,32,116,111,32,116,104,
+101,32,112,101,61,34,116,101,120,116,47,99,115,115,34,32,47,62,10,99,111,105,110
+,99,105,100,101,32,119,105,116,104,32,116,104,101,116,119,111,45,116,104,105,114
+,100,115,32,111,102,32,116,104,101,68,117,114,105,110,103,32,116,104,105,115,32,
+116,105,109,101,44,100,117,114,105,110,103,32,116,104,101,32,112,101,114,105,111
+,100,97,110,110,111,117,110,99,101,100,32,116,104,97,116,32,104,101,116,104,101,
+32,105,110,116,101,114,110,97,116,105,111,110,97,108,97,110,100,32,109,111,114,
+101,32,114,101,99,101,110,116,108,121,98,101,108,105,101,118,101,100,32,116,104,
+97,116,32,116,104,101,99,111,110,115,99,105,111,117,115,110,101,115,115,32,97,
+110,100,102,111,114,109,101,114,108,121,32,107,110,111,119,110,32,97,115,115,117
+,114,114,111,117,110,100,101,100,32,98,121,32,116,104,101,102,105,114,115,116,32
+,97,112,112,101,97,114,101,100,32,105,110,111,99,99,97,115,105,111,110,97,108,
+108,121,32,117,115,101,100,112,111,115,105,116,105,111,110,58,97,98,115,111,108,
+117,116,101,59,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110,107,34,32,112
+,111,115,105,116,105,111,110,58,114,101,108,97,116,105,118,101,59,116,101,120,
+116,45,97,108,105,103,110,58,99,101,110,116,101,114,59,106,97,120,47,108,105,98,
+115,47,106,113,117,101,114,121,47,49,46,98,97,99,107,103,114,111,117,110,100,45,
+99,111,108,111,114,58,35,116,121,112,101,61,34,97,112,112,108,105,99,97,116,105,
+111,110,47,97,110,103,117,97,103,101,34,32,99,111,110,116,101,110,116,61,34,60,
+109,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,80,114,105,118,97
+,99,121,32,80,111,108,105,99,121,60,47,97,62,101,40,34,37,51,67,115,99,114,105,
+112,116,32,115,114,99,61,39,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110,
+107,34,62,79,110,32,116,104,101,32,111,116,104,101,114,32,104,97,110,100,44,46,
+106,112,103,124,116,104,117,109,98,124,114,105,103,104,116,124,50,60,47,100,105,
+118,62,60,100,105,118,32,99,108,97,115,115,61,34,60,100,105,118,32,115,116,121,
+108,101,61,34,102,108,111,97,116,58,110,105,110,101,116,101,101,110,116,104,32,
+99,101,110,116,117,114,121,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108,
+62,13,10,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,115,59,116,
+101,120,116,45,97,108,105,103,110,58,99,101,110,116,101,114,102,111,110,116,45,
+119,101,105,103,104,116,58,32,98,111,108,100,59,32,65,99,99,111,114,100,105,110,
+103,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,
+101,116,119,101,101,110,34,32,102,114,97,109,101,98,111,114,100,101,114,61,34,48
+,34,32,34,32,115,116,121,108,101,61,34,112,111,115,105,116,105,111,110,58,108,
+105,110,107,32,104,114,101,102,61,34,104,116,116,112,58,47,47,104,116,109,108,52
+,47,108,111,111,115,101,46,100,116,100,34,62,10,100,117,114,105,110,103,32,116,
+104,105,115,32,112,101,114,105,111,100,60,47,116,100,62,60,47,116,114,62,60,47,
+116,97,98,108,101,62,99,108,111,115,101,108,121,32,114,101,108,97,116,101,100,32
+,116,111,102,111,114,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,59
+,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,105,110,112,117
+,116,32,116,121,112,101,61,34,116,101,120,116,34,32,60,115,112,97,110,32,115,116
+,121,108,101,61,34,102,111,110,116,45,111,110,114,101,97,100,121,115,116,97,116,
+101,99,104,97,110,103,101,9,60,100,105,118,32,99,108,97,115,115,61,34,99,108,101
+,97,114,100,111,99,117,109,101,110,116,46,108,111,99,97,116,105,111,110,46,32,70
+,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,97,32,119,105,100,
+101,32,118,97,114,105,101,116,121,32,111,102,32,60,33,68,79,67,84,89,80,69,32,
+104,116,109,108,62,13,10,60,38,110,98,115,112,59,38,110,98,115,112,59,38,110,98,
+115,112,59,34,62,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,115,116
+,121,108,101,61,34,102,108,111,97,116,58,108,101,102,116,59,99,111,110,99,101,
+114,110,101,100,32,119,105,116,104,32,116,104,101,61,104,116,116,112,37,51,65,37
+,50,70,37,50,70,119,119,119,46,105,110,32,112,111,112,117,108,97,114,32,99,117,
+108,116,117,114,101,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,32,47
+,62,105,116,32,105,115,32,112,111,115,115,105,98,108,101,32,116,111,32,72,97,114
+,118,97,114,100,32,85,110,105,118,101,114,115,105,116,121,116,121,108,101,115,
+104,101,101,116,34,32,104,114,101,102,61,34,47,116,104,101,32,109,97,105,110,32,
+99,104,97,114,97,99,116,101,114,79,120,102,111,114,100,32,85,110,105,118,101,114
+,115,105,116,121,32,32,110,97,109,101,61,34,107,101,121,119,111,114,100,115,34,
+32,99,115,116,121,108,101,61,34,116,101,120,116,45,97,108,105,103,110,58,116,104
+,101,32,85,110,105,116,101,100,32,75,105,110,103,100,111,109,102,101,100,101,114
+,97,108,32,103,111,118,101,114,110,109,101,110,116,60,100,105,118,32,115,116,121
+,108,101,61,34,109,97,114,103,105,110,32,100,101,112,101,110,100,105,110,103,32,
+111,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,
+32,116,104,101,60,100,105,118,32,99,108,97,115,115,61,34,104,101,97,100,101,114,
+46,109,105,110,46,106,115,34,62,60,47,115,99,114,105,112,116,62,100,101,115,116,
+114,117,99,116,105,111,110,32,111,102,32,116,104,101,115,108,105,103,104,116,108
+,121,32,100,105,102,102,101,114,101,110,116,105,110,32,97,99,99,111,114,100,97,
+110,99,101,32,119,105,116,104,116,101,108,101,99,111,109,109,117,110,105,99,97,
+116,105,111,110,115,105,110,100,105,99,97,116,101,115,32,116,104,97,116,32,116,
+104,101,115,104,111,114,116,108,121,32,116,104,101,114,101,97,102,116,101,114,
+101,115,112,101,99,105,97,108,108,121,32,105,110,32,116,104,101,32,69,117,114,
+111,112,101,97,110,32,99,111,117,110,116,114,105,101,115,72,111,119,101,118,101,
+114,44,32,116,104,101,114,101,32,97,114,101,115,114,99,61,34,104,116,116,112,58,
+47,47,115,116,97,116,105,99,115,117,103,103,101,115,116,101,100,32,116,104,97,
+116,32,116,104,101,34,32,115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,
+46,97,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,84,101,108,
+101,99,111,109,109,117,110,105,99,97,116,105,111,110,115,34,32,114,101,108,61,34
+,110,111,102,111,108,108,111,119,34,32,116,72,111,108,121,32,82,111,109,97,110,
+32,69,109,112,101,114,111,114,97,108,109,111,115,116,32,101,120,99,108,117,115,
+105,118,101,108,121,34,32,98,111,114,100,101,114,61,34,48,34,32,97,108,116,61,34
+,83,101,99,114,101,116,97,114,121,32,111,102,32,83,116,97,116,101,99,117,108,109
+,105,110,97,116,105,110,103,32,105,110,32,116,104,101,67,73,65,32,87,111,114,108
+,100,32,70,97,99,116,98,111,111,107,116,104,101,32,109,111,115,116,32,105,109,
+112,111,114,116,97,110,116,97,110,110,105,118,101,114,115,97,114,121,32,111,102,
+32,116,104,101,115,116,121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,45
+,60,108,105,62,60,101,109,62,60,97,32,104,114,101,102,61,34,47,116,104,101,32,65
+,116,108,97,110,116,105,99,32,79,99,101,97,110,115,116,114,105,99,116,108,121,32
+,115,112,101,97,107,105,110,103,44,115,104,111,114,116,108,121,32,98,101,102,111
+,114,101,32,116,104,101,100,105,102,102,101,114,101,110,116,32,116,121,112,101,
+115,32,111,102,116,104,101,32,79,116,116,111,109,97,110,32,69,109,112,105,114,
+101,62,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,65,110,32,73,
+110,116,114,111,100,117,99,116,105,111,110,32,116,111,99,111,110,115,101,113,117
+,101,110,99,101,32,111,102,32,116,104,101,100,101,112,97,114,116,117,114,101,32,
+102,114,111,109,32,116,104,101,67,111,110,102,101,100,101,114,97,116,101,32,83,
+116,97,116,101,115,105,110,100,105,103,101,110,111,117,115,32,112,101,111,112,
+108,101,115,80,114,111,99,101,101,100,105,110,103,115,32,111,102,32,116,104,101,
+105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,116,104,101,116,104,101
+,111,114,105,101,115,32,104,97,118,101,32,98,101,101,110,105,110,118,111,108,118
+,101,109,101,110,116,32,105,110,32,116,104,101,100,105,118,105,100,101,100,32,
+105,110,116,111,32,116,104,114,101,101,97,100,106,97,99,101,110,116,32,99,111,
+117,110,116,114,105,101,115,105,115,32,114,101,115,112,111,110,115,105,98,108,
+101,32,102,111,114,100,105,115,115,111,108,117,116,105,111,110,32,111,102,32,116
+,104,101,99,111,108,108,97,98,111,114,97,116,105,111,110,32,119,105,116,104,119,
+105,100,101,108,121,32,114,101,103,97,114,100,101,100,32,97,115,104,105,115,32,
+99,111,110,116,101,109,112,111,114,97,114,105,101,115,102,111,117,110,100,105,
+110,103,32,109,101,109,98,101,114,32,111,102,68,111,109,105,110,105,99,97,110,32
+,82,101,112,117,98,108,105,99,103,101,110,101,114,97,108,108,121,32,97,99,99,101
+,112,116,101,100,116,104,101,32,112,111,115,115,105,98,105,108,105,116,121,32,
+111,102,97,114,101,32,97,108,115,111,32,97,118,97,105,108,97,98,108,101,117,110,
+100,101,114,32,99,111,110,115,116,114,117,99,116,105,111,110,114,101,115,116,111
+,114,97,116,105,111,110,32,111,102,32,116,104,101,116,104,101,32,103,101,110,101
+,114,97,108,32,112,117,98,108,105,99,105,115,32,97,108,109,111,115,116,32,101,
+110,116,105,114,101,108,121,112,97,115,115,101,115,32,116,104,114,111,117,103,
+104,32,116,104,101,104,97,115,32,98,101,101,110,32,115,117,103,103,101,115,116,
+101,100,99,111,109,112,117,116,101,114,32,97,110,100,32,118,105,100,101,111,71,
+101,114,109,97,110,105,99,32,108,97,110,103,117,97,103,101,115,32,97,99,99,111,
+114,100,105,110,103,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110
+,116,32,102,114,111,109,32,116,104,101,115,104,111,114,116,108,121,32,97,102,116
+,101,114,119,97,114,100,115,104,114,101,102,61,34,104,116,116,112,115,58,47,47,
+119,119,119,46,114,101,99,101,110,116,32,100,101,118,101,108,111,112,109,101,110
+,116,66,111,97,114,100,32,111,102,32,68,105,114,101,99,116,111,114,115,60,100,
+105,118,32,99,108,97,115,115,61,34,115,101,97,114,99,104,124,32,60,97,32,104,114
+,101,102,61,34,104,116,116,112,58,47,47,73,110,32,112,97,114,116,105,99,117,108,
+97,114,44,32,116,104,101,77,117,108,116,105,112,108,101,32,102,111,111,116,110,
+111,116,101,115,111,114,32,111,116,104,101,114,32,115,117,98,115,116,97,110,99,
+101,116,104,111,117,115,97,110,100,115,32,111,102,32,121,101,97,114,115,116,114,
+97,110,115,108,97,116,105,111,110,32,111,102,32,116,104,101,60,47,100,105,118,62
+,13,10,60,47,100,105,118,62,13,10,13,10,60,97,32,104,114,101,102,61,34,105,110,
+100,101,120,46,112,104,112,119,97,115,32,101,115,116,97,98,108,105,115,104,101,
+100,32,105,110,109,105,110,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10,
+112,97,114,116,105,99,105,112,97,116,101,32,105,110,32,116,104,101,97,32,115,116
+,114,111,110,103,32,105,110,102,108,117,101,110,99,101,115,116,121,108,101,61,34
+,109,97,114,103,105,110,45,116,111,112,58,114,101,112,114,101,115,101,110,116,
+101,100,32,98,121,32,116,104,101,103,114,97,100,117,97,116,101,100,32,102,114,
+111,109,32,116,104,101,84,114,97,100,105,116,105,111,110,97,108,108,121,44,32,
+116,104,101,69,108,101,109,101,110,116,40,34,115,99,114,105,112,116,34,41,59,72,
+111,119,101,118,101,114,44,32,115,105,110,99,101,32,116,104,101,47,100,105,118,
+62,10,60,47,100,105,118,62,10,60,100,105,118,32,108,101,102,116,59,32,109,97,114
+,103,105,110,45,108,101,102,116,58,112,114,111,116,101,99,116,105,111,110,32,97,
+103,97,105,110,115,116,48,59,32,118,101,114,116,105,99,97,108,45,97,108,105,103,
+110,58,85,110,102,111,114,116,117,110,97,116,101,108,121,44,32,116,104,101,116,
+121,112,101,61,34,105,109,97,103,101,47,120,45,105,99,111,110,47,100,105,118,62,
+10,60,100,105,118,32,99,108,97,115,115,61,34,32,99,108,97,115,115,61,34,99,108,
+101,97,114,102,105,120,34,62,60,100,105,118,32,99,108,97,115,115,61,34,102,111,
+111,116,101,114,9,9,60,47,100,105,118,62,10,9,9,60,47,100,105,118,62,10,116,104,
+101,32,109,111,116,105,111,110,32,112,105,99,116,117,114,101,208,145,209,138,208
+,187,208,179,208,176,209,128,209,129,208,186,208,184,208,177,209,138,208,187,208
+,179,208,176,209,128,209,129,208,186,208,184,208,164,208,181,208,180,208,181,209
+,128,208,176,209,134,208,184,208,184,208,189,208,181,209,129,208,186,208,190,208
+,187,209,140,208,186,208,190,209,129,208,190,208,190,208,177,209,137,208,181,208
+,189,208,184,208,181,209,129,208,190,208,190,208,177,209,137,208,181,208,189,208
+,184,209,143,208,191,209,128,208,190,208,179,209,128,208,176,208,188,208,188,209
+,139,208,158,209,130,208,191,209,128,208,176,208,178,208,184,209,130,209,140,208
+,177,208,181,209,129,208,191,208,187,208,176,209,130,208,189,208,190,208,188,208
+,176,209,130,208,181,209,128,208,184,208,176,208,187,209,139,208,191,208,190,208
+,183,208,178,208,190,208,187,209,143,208,181,209,130,208,191,208,190,209,129,208
+,187,208,181,208,180,208,189,208,184,208,181,209,128,208,176,208,183,208,187,208
+,184,209,135,208,189,209,139,209,133,208,191,209,128,208,190,208,180,209,131,208
+,186,209,134,208,184,208,184,208,191,209,128,208,190,208,179,209,128,208,176,208
+,188,208,188,208,176,208,191,208,190,208,187,208,189,208,190,209,129,209,130,209
+,140,209,142,208,189,208,176,209,133,208,190,208,180,208,184,209,130,209,129,209
+,143,208,184,208,183,208,177,209,128,208,176,208,189,208,189,208,190,208,181,208
+,189,208,176,209,129,208,181,208,187,208,181,208,189,208,184,209,143,208,184,208
+,183,208,188,208,181,208,189,208,181,208,189,208,184,209,143,208,186,208,176,209
+,130,208,181,208,179,208,190,209,128,208,184,208,184,208,144,208,187,208,181,208
+,186,209,129,208,176,208,189,208,180,209,128,224,164,166,224,165,141,224,164,181
+,224,164,190,224,164,176,224,164,190,224,164,174,224,165,136,224,164,168,224,165
+,129,224,164,133,224,164,178,224,164,170,224,165,141,224,164,176,224,164,166,224
+,164,190,224,164,168,224,164,173,224,164,190,224,164,176,224,164,164,224,165,128
+,224,164,175,224,164,133,224,164,168,224,165,129,224,164,166,224,165,135,224,164
+,182,224,164,185,224,164,191,224,164,168,224,165,141,224,164,166,224,165,128,224
+,164,135,224,164,130,224,164,161,224,164,191,224,164,175,224,164,190,224,164,166
+,224,164,191,224,164,178,224,165,141,224,164,178,224,165,128,224,164,133,224,164
+,167,224,164,191,224,164,149,224,164,190,224,164,176,224,164,181,224,165,128,224
+,164,161,224,164,191,224,164,175,224,165,139,224,164,154,224,164,191,224,164,159
+,224,165,141,224,164,160,224,165,135,224,164,184,224,164,174,224,164,190,224,164
+,154,224,164,190,224,164,176,224,164,156,224,164,130,224,164,149,224,165,141,224
+,164,182,224,164,168,224,164,166,224,165,129,224,164,168,224,164,191,224,164,175
+,224,164,190,224,164,170,224,165,141,224,164,176,224,164,175,224,165,139,224,164
+,151,224,164,133,224,164,168,224,165,129,224,164,184,224,164,190,224,164,176,224
+,164,145,224,164,168,224,164,178,224,164,190,224,164,135,224,164,168,224,164,170
+,224,164,190,224,164,176,224,165,141,224,164,159,224,165,128,224,164,182,224,164
+,176,224,165,141,224,164,164,224,165,139,224,164,130,224,164,178,224,165,139,224
+,164,149,224,164,184,224,164,173,224,164,190,224,164,171,224,164,188,224,165,141
+,224,164,178,224,165,136,224,164,182,224,164,182,224,164,176,224,165,141,224,164
+,164,224,165,135,224,164,130,224,164,170,224,165,141,224,164,176,224,164,166,224
+,165,135,224,164,182,224,164,170,224,165,141,224,164,178,224,165,135,224,164,175
+,224,164,176,224,164,149,224,165,135,224,164,130,224,164,166,224,165,141,224,164
+,176,224,164,184,224,165,141,224,164,165,224,164,191,224,164,164,224,164,191,224
+,164,137,224,164,164,224,165,141,224,164,170,224,164,190,224,164,166,224,164,137
+,224,164,168,224,165,141,224,164,185,224,165,135,224,164,130,224,164,154,224,164
+,191,224,164,159,224,165,141,224,164,160,224,164,190,224,164,175,224,164,190,224
+,164,164,224,165,141,224,164,176,224,164,190,224,164,156,224,165,141,224,164,175
+,224,164,190,224,164,166,224,164,190,224,164,170,224,165,129,224,164,176,224,164
+,190,224,164,168,224,165,135,224,164,156,224,165,139,224,164,161,224,164,188,224
+,165,135,224,164,130,224,164,133,224,164,168,224,165,129,224,164,181,224,164,190
+,224,164,166,224,164,182,224,165,141,224,164,176,224,165,135,224,164,163,224,165
+,128,224,164,182,224,164,191,224,164,149,224,165,141,224,164,183,224,164,190,224
+,164,184,224,164,176,224,164,149,224,164,190,224,164,176,224,165,128,224,164,184
+,224,164,130,224,164,151,224,165,141,224,164,176,224,164,185,224,164,170,224,164
+,176,224,164,191,224,164,163,224,164,190,224,164,174,224,164,172,224,165,141,224
+,164,176,224,164,190,224,164,130,224,164,161,224,164,172,224,164,154,224,165,141
+,224,164,154,224,165,139,224,164,130,224,164,137,224,164,170,224,164,178,224,164
+,172,224,165,141,224,164,167,224,164,174,224,164,130,224,164,164,224,165,141,224
+,164,176,224,165,128,224,164,184,224,164,130,224,164,170,224,164,176,224,165,141
+,224,164,149,224,164,137,224,164,174,224,165,141,224,164,174,224,165,128,224,164
+,166,224,164,174,224,164,190,224,164,167,224,165,141,224,164,175,224,164,174,224
+,164,184,224,164,185,224,164,190,224,164,175,224,164,164,224,164,190,224,164,182
+,224,164,172,224,165,141,224,164,166,224,165,139,224,164,130,224,164,174,224,165
+,128,224,164,161,224,164,191,224,164,175,224,164,190,224,164,134,224,164,136,224
+,164,170,224,165,128,224,164,143,224,164,178,224,164,174,224,165,139,224,164,172
+,224,164,190,224,164,135,224,164,178,224,164,184,224,164,130,224,164,150,224,165
+,141,224,164,175,224,164,190,224,164,134,224,164,170,224,164,176,224,165,135,224
+,164,182,224,164,168,224,164,133,224,164,168,224,165,129,224,164,172,224,164,130
+,224,164,167,224,164,172,224,164,190,224,164,156,224,164,188,224,164,190,224,164
+,176,224,164,168,224,164,181,224,165,128,224,164,168,224,164,164,224,164,174,224
+,164,170,224,165,141,224,164,176,224,164,174,224,165,129,224,164,150,224,164,170
+,224,165,141,224,164,176,224,164,182,224,165,141,224,164,168,224,164,170,224,164
+,176,224,164,191,224,164,181,224,164,190,224,164,176,224,164,168,224,165,129,224
+,164,149,224,164,184,224,164,190,224,164,168,224,164,184,224,164,174,224,164,176
+,224,165,141,224,164,165,224,164,168,224,164,134,224,164,175,224,165,139,224,164
+,156,224,164,191,224,164,164,224,164,184,224,165,139,224,164,174,224,164,181,224
+,164,190,224,164,176,216,167,217,132,217,133,216,180,216,167,216,177,217,131,216
+,167,216,170,216,167,217,132,217,133,217,134,216,170,216,175,217,138,216,167,216
+,170,216,167,217,132,217,131,217,133,216,168,217,138,217,136,216,170,216,177,216
+,167,217,132,217,133,216,180,216,167,217,135,216,175,216,167,216,170,216,185,216
+,175,216,175,216,167,217,132,216,178,217,136,216,167,216,177,216,185,216,175,216
+,175,216,167,217,132,216,177,216,175,217,136,216,175,216,167,217,132,216,165,216
+,179,217,132,216,167,217,133,217,138,216,169,216,167,217,132,217,129,217,136,216
+,170,217,136,216,180,217,136,216,168,216,167,217,132,217,133,216,179,216,167,216
+,168,217,130,216,167,216,170,216,167,217,132,217,133,216,185,217,132,217,136,217
+,133,216,167,216,170,216,167,217,132,217,133,216,179,217,132,216,179,217,132,216
+,167,216,170,216,167,217,132,216,172,216,177,216,167,217,129,217,138,217,131,216
+,179,216,167,217,132,216,167,216,179,217,132,216,167,217,133,217,138,216,169,216
+,167,217,132,216,167,216,170,216,181,216,167,217,132,216,167,216,170,107,101,121
+,119,111,114,100,115,34,32,99,111,110,116,101,110,116,61,34,119,51,46,111,114,
+103,47,49,57,57,57,47,120,104,116,109,108,34,62,60,97,32,116,97,114,103,101,116,
+61,34,95,98,108,97,110,107,34,32,116,101,120,116,47,104,116,109,108,59,32,99,104
+,97,114,115,101,116,61,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110,107,
+34,62,60,116,97,98,108,101,32,99,101,108,108,112,97,100,100,105,110,103,61,34,97
+,117,116,111,99,111,109,112,108,101,116,101,61,34,111,102,102,34,32,116,101,120,
+116,45,97,108,105,103,110,58,32,99,101,110,116,101,114,59,116,111,32,108,97,115,
+116,32,118,101,114,115,105,111,110,32,98,121,32,98,97,99,107,103,114,111,117,110
+,100,45,99,111,108,111,114,58,32,35,34,32,104,114,101,102,61,34,104,116,116,112,
+58,47,47,119,119,119,46,47,100,105,118,62,60,47,100,105,118,62,60,100,105,118,32
+,105,100,61,60,97,32,104,114,101,102,61,34,35,34,32,99,108,97,115,115,61,34,34,
+62,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,99,114,105,112,
+116,34,32,115,114,99,61,34,104,116,116,112,58,47,47,10,60,115,99,114,105,112,116
+,32,108,97,110,103,117,97,103,101,61,34,47,47,69,78,34,32,34,104,116,116,112,58,
+47,47,119,119,119,46,119,101,110,99,111,100,101,85,82,73,67,111,109,112,111,110,
+101,110,116,40,34,32,104,114,101,102,61,34,106,97,118,97,115,99,114,105,112,116,
+58,60,100,105,118,32,99,108,97,115,115,61,34,99,111,110,116,101,110,116,100,111,
+99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,115,99,112,111,115,105,
+116,105,111,110,58,32,97,98,115,111,108,117,116,101,59,115,99,114,105,112,116,32
+,115,114,99,61,34,104,116,116,112,58,47,47,32,115,116,121,108,101,61,34,109,97,
+114,103,105,110,45,116,111,112,58,46,109,105,110,46,106,115,34,62,60,47,115,99,
+114,105,112,116,62,10,60,47,100,105,118,62,10,60,100,105,118,32,99,108,97,115,
+115,61,34,119,51,46,111,114,103,47,49,57,57,57,47,120,104,116,109,108,34,32,10,
+13,10,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108,62,100,105,115,116,105
+,110,99,116,105,111,110,32,98,101,116,119,101,101,110,47,34,32,116,97,114,103,
+101,116,61,34,95,98,108,97,110,107,34,62,60,108,105,110,107,32,104,114,101,102,
+61,34,104,116,116,112,58,47,47,101,110,99,111,100,105,110,103,61,34,117,116,102,
+45,56,34,63,62,10,119,46,97,100,100,69,118,101,110,116,76,105,115,116,101,110,
+101,114,63,97,99,116,105,111,110,61,34,104,116,116,112,58,47,47,119,119,119,46,
+105,99,111,110,34,32,104,114,101,102,61,34,104,116,116,112,58,47,47,32,115,116,
+121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,58,116,121,112,101,61,34,
+116,101,120,116,47,99,115,115,34,32,47,62,10,109,101,116,97,32,112,114,111,112,
+101,114,116,121,61,34,111,103,58,116,60,105,110,112,117,116,32,116,121,112,101,
+61,34,116,101,120,116,34,32,32,115,116,121,108,101,61,34,116,101,120,116,45,97,
+108,105,103,110,58,116,104,101,32,100,101,118,101,108,111,112,109,101,110,116,32
+,111,102,32,116,121,108,101,115,104,101,101,116,34,32,116,121,112,101,61,34,116,
+101,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116,102,45,56,105,115
+,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,116,97,98,108,
+101,32,119,105,100,116,104,61,34,49,48,48,37,34,32,73,110,32,97,100,100,105,116,
+105,111,110,32,116,111,32,116,104,101,32,99,111,110,116,114,105,98,117,116,101,
+100,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,115,32,
+98,101,116,119,101,101,110,100,101,118,101,108,111,112,109,101,110,116,32,111,
+102,32,116,104,101,32,73,116,32,105,115,32,105,109,112,111,114,116,97,110,116,32
+,116,111,32,60,47,115,99,114,105,112,116,62,10,10,60,115,99,114,105,112,116,32,
+32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,62,60,47,
+115,112,97,110,62,60,115,112,97,110,32,105,100,61,103,98,76,105,98,114,97,114,
+121,32,111,102,32,67,111,110,103,114,101,115,115,60,105,109,103,32,115,114,99,61
+,34,104,116,116,112,58,47,47,105,109,69,110,103,108,105,115,104,32,116,114,97,
+110,115,108,97,116,105,111,110,65,99,97,100,101,109,121,32,111,102,32,83,99,105,
+101,110,99,101,115,100,105,118,32,115,116,121,108,101,61,34,100,105,115,112,108,
+97,121,58,99,111,110,115,116,114,117,99,116,105,111,110,32,111,102,32,116,104,
+101,46,103,101,116,69,108,101,109,101,110,116,66,121,73,100,40,105,100,41,105,
+110,32,99,111,110,106,117,110,99,116,105,111,110,32,119,105,116,104,69,108,101,
+109,101,110,116,40,39,115,99,114,105,112,116,39,41,59,32,60,109,101,116,97,32,
+112,114,111,112,101,114,116,121,61,34,111,103,58,208,145,209,138,208,187,208,179
+,208,176,209,128,209,129,208,186,208,184,10,32,116,121,112,101,61,34,116,101,120
+,116,34,32,110,97,109,101,61,34,62,80,114,105,118,97,99,121,32,80,111,108,105,99
+,121,60,47,97,62,97,100,109,105,110,105,115,116,101,114,101,100,32,98,121,32,116
+,104,101,101,110,97,98,108,101,83,105,110,103,108,101,82,101,113,117,101,115,116
+,115,116,121,108,101,61,38,113,117,111,116,59,109,97,114,103,105,110,58,60,47,
+100,105,118,62,60,47,100,105,118,62,60,47,100,105,118,62,60,62,60,105,109,103,32
+,115,114,99,61,34,104,116,116,112,58,47,47,105,32,115,116,121,108,101,61,38,113,
+117,111,116,59,102,108,111,97,116,58,114,101,102,101,114,114,101,100,32,116,111,
+32,97,115,32,116,104,101,32,116,111,116,97,108,32,112,111,112,117,108,97,116,105
+,111,110,32,111,102,105,110,32,87,97,115,104,105,110,103,116,111,110,44,32,68,46
+,67,46,32,115,116,121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,45,97,
+109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,44,111,114,103
+,97,110,105,122,97,116,105,111,110,32,111,102,32,116,104,101,112,97,114,116,105,
+99,105,112,97,116,101,100,32,105,110,32,116,104,101,116,104,101,32,105,110,116,
+114,111,100,117,99,116,105,111,110,32,111,102,105,100,101,110,116,105,102,105,
+101,100,32,119,105,116,104,32,116,104,101,102,105,99,116,105,111,110,97,108,32,
+99,104,97,114,97,99,116,101,114,32,79,120,102,111,114,100,32,85,110,105,118,101,
+114,115,105,116,121,32,109,105,115,117,110,100,101,114,115,116,97,110,100,105,
+110,103,32,111,102,84,104,101,114,101,32,97,114,101,44,32,104,111,119,101,118,
+101,114,44,115,116,121,108,101,115,104,101,101,116,34,32,104,114,101,102,61,34,
+47,67,111,108,117,109,98,105,97,32,85,110,105,118,101,114,115,105,116,121,101,
+120,112,97,110,100,101,100,32,116,111,32,105,110,99,108,117,100,101,117,115,117,
+97,108,108,121,32,114,101,102,101,114,114,101,100,32,116,111,105,110,100,105,99,
+97,116,105,110,103,32,116,104,97,116,32,116,104,101,104,97,118,101,32,115,117,
+103,103,101,115,116,101,100,32,116,104,97,116,97,102,102,105,108,105,97,116,101,
+100,32,119,105,116,104,32,116,104,101,99,111,114,114,101,108,97,116,105,111,110,
+32,98,101,116,119,101,101,110,110,117,109,98,101,114,32,111,102,32,100,105,102,
+102,101,114,101,110,116,62,60,47,116,100,62,60,47,116,114,62,60,47,116,97,98,108
+,101,62,82,101,112,117,98,108,105,99,32,111,102,32,73,114,101,108,97,110,100,10,
+60,47,115,99,114,105,112,116,62,10,60,115,99,114,105,112,116,32,117,110,100,101,
+114,32,116,104,101,32,105,110,102,108,117,101,110,99,101,99,111,110,116,114,105,
+98,117,116,105,111,110,32,116,111,32,116,104,101,79,102,102,105,99,105,97,108,32
+,119,101,98,115,105,116,101,32,111,102,104,101,97,100,113,117,97,114,116,101,114
+,115,32,111,102,32,116,104,101,99,101,110,116,101,114,101,100,32,97,114,111,117,
+110,100,32,116,104,101,105,109,112,108,105,99,97,116,105,111,110,115,32,111,102,
+32,116,104,101,104,97,118,101,32,98,101,101,110,32,100,101,118,101,108,111,112,
+101,100,70,101,100,101,114,97,108,32,82,101,112,117,98,108,105,99,32,111,102,98,
+101,99,97,109,101,32,105,110,99,114,101,97,115,105,110,103,108,121,99,111,110,
+116,105,110,117,97,116,105,111,110,32,111,102,32,116,104,101,78,111,116,101,44,
+32,104,111,119,101,118,101,114,44,32,116,104,97,116,115,105,109,105,108,97,114,
+32,116,111,32,116,104,97,116,32,111,102,32,99,97,112,97,98,105,108,105,116,105,
+101,115,32,111,102,32,116,104,101,97,99,99,111,114,100,97,110,99,101,32,119,105,
+116,104,32,116,104,101,112,97,114,116,105,99,105,112,97,110,116,115,32,105,110,
+32,116,104,101,102,117,114,116,104,101,114,32,100,101,118,101,108,111,112,109,
+101,110,116,117,110,100,101,114,32,116,104,101,32,100,105,114,101,99,116,105,111
+,110,105,115,32,111,102,116,101,110,32,99,111,110,115,105,100,101,114,101,100,
+104,105,115,32,121,111,117,110,103,101,114,32,98,114,111,116,104,101,114,60,47,
+116,100,62,60,47,116,114,62,60,47,116,97,98,108,101,62,60,97,32,104,116,116,112,
+45,101,113,117,105,118,61,34,88,45,85,65,45,112,104,121,115,105,99,97,108,32,112
+,114,111,112,101,114,116,105,101,115,111,102,32,66,114,105,116,105,115,104,32,67
+,111,108,117,109,98,105,97,104,97,115,32,98,101,101,110,32,99,114,105,116,105,99
+,105,122,101,100,40,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105
+,111,110,113,117,101,115,116,105,111,110,115,32,97,98,111,117,116,32,116,104,101
+,112,97,115,115,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,48,34,
+32,99,101,108,108,112,97,100,100,105,110,103,61,34,48,34,32,116,104,111,117,115,
+97,110,100,115,32,111,102,32,112,101,111,112,108,101,114,101,100,105,114,101,99,
+116,115,32,104,101,114,101,46,32,70,111,114,104,97,118,101,32,99,104,105,108,100
+,114,101,110,32,117,110,100,101,114,37,51,69,37,51,67,47,115,99,114,105,112,116,
+37,51,69,34,41,41,59,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119
+,119,119,46,60,108,105,62,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,
+47,115,105,116,101,95,110,97,109,101,34,32,99,111,110,116,101,110,116,61,34,116,
+101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,115,116,
+121,108,101,61,34,100,105,115,112,108,97,121,58,32,110,111,110,101,60,109,101,
+116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,88,45,110,101,119,32,68,
+97,116,101,40,41,46,103,101,116,84,105,109,101,40,41,32,116,121,112,101,61,34,
+105,109,97,103,101,47,120,45,105,99,111,110,34,60,47,115,112,97,110,62,60,115,
+112,97,110,32,99,108,97,115,115,61,34,108,97,110,103,117,97,103,101,61,34,106,97
+,118,97,115,99,114,105,112,116,119,105,110,100,111,119,46,108,111,99,97,116,105,
+111,110,46,104,114,101,102,60,97,32,104,114,101,102,61,34,106,97,118,97,115,99,
+114,105,112,116,58,45,45,62,13,10,60,115,99,114,105,112,116,32,116,121,112,101,
+61,34,116,60,97,32,104,114,101,102,61,39,104,116,116,112,58,47,47,119,119,119,46
+,104,111,114,116,99,117,116,32,105,99,111,110,34,32,104,114,101,102,61,34,60,47,
+100,105,118,62,13,10,60,100,105,118,32,99,108,97,115,115,61,34,60,115,99,114,105
+,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,34,32,114,101,108,61,34,
+115,116,121,108,101,115,104,101,101,116,34,32,116,60,47,100,105,118,62,10,60,115
+,99,114,105,112,116,32,116,121,112,101,61,47,97,62,32,60,97,32,104,114,101,102,
+61,34,104,116,116,112,58,47,47,32,97,108,108,111,119,84,114,97,110,115,112,97,
+114,101,110,99,121,61,34,88,45,85,65,45,67,111,109,112,97,116,105,98,108,101,34,
+32,99,111,110,114,101,108,97,116,105,111,110,115,104,105,112,32,98,101,116,119,
+101,101,110,10,60,47,115,99,114,105,112,116,62,13,10,60,115,99,114,105,112,116,
+32,60,47,97,62,60,47,108,105,62,60,47,117,108,62,60,47,100,105,118,62,97,115,115
+,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,112,114,111,103,
+114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,60,47,97,62,60,97,32
+,104,114,101,102,61,34,104,116,116,112,58,47,47,60,47,97,62,60,47,108,105,62,60,
+108,105,32,99,108,97,115,115,61,34,102,111,114,109,32,97,99,116,105,111,110,61,
+34,104,116,116,112,58,47,47,60,100,105,118,32,115,116,121,108,101,61,34,100,105,
+115,112,108,97,121,58,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101
+,61,34,113,34,60,116,97,98,108,101,32,119,105,100,116,104,61,34,49,48,48,37,34,
+32,98,97,99,107,103,114,111,117,110,100,45,112,111,115,105,116,105,111,110,58,34
+,32,98,111,114,100,101,114,61,34,48,34,32,119,105,100,116,104,61,34,114,101,108,
+61,34,115,104,111,114,116,99,117,116,32,105,99,111,110,34,32,104,54,62,60,117,
+108,62,60,108,105,62,60,97,32,104,114,101,102,61,34,32,32,60,109,101,116,97,32,
+104,116,116,112,45,101,113,117,105,118,61,34,99,115,115,34,32,109,101,100,105,97
+,61,34,115,99,114,101,101,110,34,32,114,101,115,112,111,110,115,105,98,108,101,
+32,102,111,114,32,116,104,101,32,34,32,116,121,112,101,61,34,97,112,112,108,105,
+99,97,116,105,111,110,47,34,32,115,116,121,108,101,61,34,98,97,99,107,103,114,
+111,117,110,100,45,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116,
+102,45,56,34,32,97,108,108,111,119,116,114,97,110,115,112,97,114,101,110,99,121,
+61,34,115,116,121,108,101,115,104,101,101,116,34,32,116,121,112,101,61,34,116,
+101,13,10,60,109,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,62,
+60,47,115,112,97,110,62,60,115,112,97,110,32,99,108,97,115,115,61,34,48,34,32,99
+,101,108,108,115,112,97,99,105,110,103,61,34,48,34,62,59,10,60,47,115,99,114,105
+,112,116,62,10,60,115,99,114,105,112,116,32,115,111,109,101,116,105,109,101,115,
+32,99,97,108,108,101,100,32,116,104,101,100,111,101,115,32,110,111,116,32,110,
+101,99,101,115,115,97,114,105,108,121,70,111,114,32,109,111,114,101,32,105,110,
+102,111,114,109,97,116,105,111,110,97,116,32,116,104,101,32,98,101,103,105,110,
+110,105,110,103,32,111,102,32,60,33,68,79,67,84,89,80,69,32,104,116,109,108,62,
+60,104,116,109,108,112,97,114,116,105,99,117,108,97,114,108,121,32,105,110,32,
+116,104,101,32,116,121,112,101,61,34,104,105,100,100,101,110,34,32,110,97,109,
+101,61,34,106,97,118,97,115,99,114,105,112,116,58,118,111,105,100,40,48,41,59,34
+,101,102,102,101,99,116,105,118,101,110,101,115,115,32,111,102,32,116,104,101,32
+,97,117,116,111,99,111,109,112,108,101,116,101,61,34,111,102,102,34,32,103,101,
+110,101,114,97,108,108,121,32,99,111,110,115,105,100,101,114,101,100,62,60,105,
+110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,34,62,60,47,115,
+99,114,105,112,116,62,13,10,60,115,99,114,105,112,116,116,104,114,111,117,103,
+104,111,117,116,32,116,104,101,32,119,111,114,108,100,99,111,109,109,111,110,32,
+109,105,115,99,111,110,99,101,112,116,105,111,110,97,115,115,111,99,105,97,116,
+105,111,110,32,119,105,116,104,32,116,104,101,60,47,100,105,118,62,10,60,47,100,
+105,118,62,10,60,100,105,118,32,99,100,117,114,105,110,103,32,104,105,115,32,108
+,105,102,101,116,105,109,101,44,99,111,114,114,101,115,112,111,110,100,105,110,
+103,32,116,111,32,116,104,101,116,121,112,101,61,34,105,109,97,103,101,47,120,45
+,105,99,111,110,34,32,97,110,32,105,110,99,114,101,97,115,105,110,103,32,110,117
+,109,98,101,114,100,105,112,108,111,109,97,116,105,99,32,114,101,108,97,116,105,
+111,110,115,97,114,101,32,111,102,116,101,110,32,99,111,110,115,105,100,101,114,
+101,100,109,101,116,97,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34,
+32,60,105,110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,101,120
+,97,109,112,108,101,115,32,105,110,99,108,117,100,101,32,116,104,101,34,62,60,
+105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,105,112,97,114,116,105,
+99,105,112,97,116,105,111,110,32,105,110,32,116,104,101,116,104,101,32,101,115,
+116,97,98,108,105,115,104,109,101,110,116,32,111,102,10,60,47,100,105,118,62,10,
+60,100,105,118,32,99,108,97,115,115,61,34,38,97,109,112,59,110,98,115,112,59,38,
+97,109,112,59,110,98,115,112,59,116,111,32,100,101,116,101,114,109,105,110,101,
+32,119,104,101,116,104,101,114,113,117,105,116,101,32,100,105,102,102,101,114,
+101,110,116,32,102,114,111,109,109,97,114,107,101,100,32,116,104,101,32,98,101,
+103,105,110,110,105,110,103,100,105,115,116,97,110,99,101,32,98,101,116,119,101,
+101,110,32,116,104,101,99,111,110,116,114,105,98,117,116,105,111,110,115,32,116,
+111,32,116,104,101,99,111,110,102,108,105,99,116,32,98,101,116,119,101,101,110,
+32,116,104,101,119,105,100,101,108,121,32,99,111,110,115,105,100,101,114,101,100
+,32,116,111,119,97,115,32,111,110,101,32,111,102,32,116,104,101,32,102,105,114,
+115,116,119,105,116,104,32,118,97,114,121,105,110,103,32,100,101,103,114,101,101
+,115,104,97,118,101,32,115,112,101,99,117,108,97,116,101,100,32,116,104,97,116,
+40,100,111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,112,
+97,114,116,105,99,105,112,97,116,105,110,103,32,105,110,32,116,104,101,111,114,
+105,103,105,110,97,108,108,121,32,100,101,118,101,108,111,112,101,100,101,116,97
+,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34,62,32,116,121,112,101,
+61,34,116,101,120,116,47,99,115,115,34,32,47,62,10,105,110,116,101,114,99,104,97
+,110,103,101,97,98,108,121,32,119,105,116,104,109,111,114,101,32,99,108,111,115,
+101,108,121,32,114,101,108,97,116,101,100,115,111,99,105,97,108,32,97,110,100,32
+,112,111,108,105,116,105,99,97,108,116,104,97,116,32,119,111,117,108,100,32,111,
+116,104,101,114,119,105,115,101,112,101,114,112,101,110,100,105,99,117,108,97,
+114,32,116,111,32,116,104,101,115,116,121,108,101,32,116,121,112,101,61,34,116,
+101,120,116,47,99,115,115,116,121,112,101,61,34,115,117,98,109,105,116,34,32,110
+,97,109,101,61,34,102,97,109,105,108,105,101,115,32,114,101,115,105,100,105,110,
+103,32,105,110,100,101,118,101,108,111,112,105,110,103,32,99,111,117,110,116,114
+,105,101,115,99,111,109,112,117,116,101,114,32,112,114,111,103,114,97,109,109,
+105,110,103,101,99,111,110,111,109,105,99,32,100,101,118,101,108,111,112,109,101
+,110,116,100,101,116,101,114,109,105,110,97,116,105,111,110,32,111,102,32,116,
+104,101,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111
+,110,111,110,32,115,101,118,101,114,97,108,32,111,99,99,97,115,105,111,110,115,
+112,111,114,116,117,103,117,195,170,115,32,40,69,117,114,111,112,101,117,41,208,
+163,208,186,209,128,208,176,209,151,208,189,209,129,209,140,208,186,208,176,209,
+131,208,186,209,128,208,176,209,151,208,189,209,129,209,140,208,186,208,176,208,
+160,208,190,209,129,209,129,208,184,208,185,209,129,208,186,208,190,208,185,208,
+188,208,176,209,130,208,181,209,128,208,184,208,176,208,187,208,190,208,178,208,
+184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,208,184,209,
+131,208,191,209,128,208,176,208,178,208,187,208,181,208,189,208,184,209,143,208,
+189,208,181,208,190,208,177,209,133,208,190,208,180,208,184,208,188,208,190,208,
+184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,143,208,
+152,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,143,208,
+160,208,181,209,129,208,191,209,131,208,177,208,187,208,184,208,186,208,184,208,
+186,208,190,208,187,208,184,209,135,208,181,209,129,209,130,208,178,208,190,208,
+184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,142,209,
+130,208,181,209,128,209,128,208,184,209,130,208,190,209,128,208,184,208,184,208,
+180,208,190,209,129,209,130,208,176,209,130,208,190,209,135,208,189,208,190,216,
+167,217,132,217,133,216,170,217,136,216,167,216,172,216,175,217,136,217,134,216,
+167,217,132,216,167,216,180,216,170,216,177,216,167,217,131,216,167,216,170,216,
+167,217,132,216,167,217,130,216,170,216,177,216,167,216,173,216,167,216,170,104,
+116,109,108,59,32,99,104,97,114,115,101,116,61,85,84,70,45,56,34,32,115,101,116,
+84,105,109,101,111,117,116,40,102,117,110,99,116,105,111,110,40,41,100,105,115,
+112,108,97,121,58,105,110,108,105,110,101,45,98,108,111,99,107,59,60,105,110,112
+,117,116,32,116,121,112,101,61,34,115,117,98,109,105,116,34,32,116,121,112,101,
+32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114,105,60,105,109,103,32,
+115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,46,34,32,34,104,116,116,
+112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,115,104,111,114,116,99,117,
+116,32,105,99,111,110,34,32,104,114,101,102,61,34,34,32,97,117,116,111,99,111,
+109,112,108,101,116,101,61,34,111,102,102,34,32,60,47,97,62,60,47,100,105,118,62
+,60,100,105,118,32,99,108,97,115,115,61,60,47,97,62,60,47,108,105,62,10,60,108,
+105,32,99,108,97,115,115,61,34,99,115,115,34,32,116,121,112,101,61,34,116,101,
+120,116,47,99,115,115,34,32,60,102,111,114,109,32,97,99,116,105,111,110,61,34,
+104,116,116,112,58,47,47,120,116,47,99,115,115,34,32,104,114,101,102,61,34,104,
+116,116,112,58,47,47,108,105,110,107,32,114,101,108,61,34,97,108,116,101,114,110
+,97,116,101,34,32,13,10,60,115,99,114,105,112,116,32,116,121,112,101,61,34,116,
+101,120,116,47,32,111,110,99,108,105,99,107,61,34,106,97,118,97,115,99,114,105,
+112,116,58,40,110,101,119,32,68,97,116,101,41,46,103,101,116,84,105,109,101,40,
+41,125,104,101,105,103,104,116,61,34,49,34,32,119,105,100,116,104,61,34,49,34,32
+,80,101,111,112,108,101,39,115,32,82,101,112,117,98,108,105,99,32,111,102,32,32,
+60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,116,101,
+120,116,45,100,101,99,111,114,97,116,105,111,110,58,117,110,100,101,114,116,104,
+101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,116,104,101,32,60,47,100
+,105,118,62,10,60,47,100,105,118,62,10,60,47,100,105,118,62,10,101,115,116,97,98
+,108,105,115,104,109,101,110,116,32,111,102,32,116,104,101,32,60,47,100,105,118,
+62,60,47,100,105,118,62,60,47,100,105,118,62,60,47,100,35,118,105,101,119,112,
+111,114,116,123,109,105,110,45,104,101,105,103,104,116,58,10,60,115,99,114,105,
+112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,111,112,116,105,111,110,62,
+60,111,112,116,105,111,110,32,118,97,108,117,101,61,111,102,116,101,110,32,114,
+101,102,101,114,114,101,100,32,116,111,32,97,115,32,47,111,112,116,105,111,110,
+62,10,60,111,112,116,105,111,110,32,118,97,108,117,60,33,68,79,67,84,89,80,69,32
+,104,116,109,108,62,10,60,33,45,45,91,73,110,116,101,114,110,97,116,105,111,110,
+97,108,32,65,105,114,112,111,114,116,62,10,60,97,32,104,114,101,102,61,34,104,
+116,116,112,58,47,47,119,119,119,60,47,97,62,60,97,32,104,114,101,102,61,34,104,
+116,116,112,58,47,47,119,224,184,160,224,184,178,224,184,169,224,184,178,224,185
+,132,224,184,151,224,184,162,225,131,165,225,131,144,225,131,160,225,131,151,225
+,131,163,225,131,154,225,131,152,230,173,163,233,171,148,228,184,173,230,150,135
+,32,40,231,185,129,233,171,148,41,224,164,168,224,164,191,224,164,176,224,165,
+141,224,164,166,224,165,135,224,164,182,224,164,161,224,164,190,224,164,137,224,
+164,168,224,164,178,224,165,139,224,164,161,224,164,149,224,165,141,224,164,183,
+224,165,135,224,164,164,224,165,141,224,164,176,224,164,156,224,164,190,224,164,
+168,224,164,149,224,164,190,224,164,176,224,165,128,224,164,184,224,164,130,224,
+164,172,224,164,130,224,164,167,224,164,191,224,164,164,224,164,184,224,165,141,
+224,164,165,224,164,190,224,164,170,224,164,168,224,164,190,224,164,184,224,165,
+141,224,164,181,224,165,128,224,164,149,224,164,190,224,164,176,224,164,184,224,
+164,130,224,164,184,224,165,141,224,164,149,224,164,176,224,164,163,224,164,184,
+224,164,190,224,164,174,224,164,151,224,165,141,224,164,176,224,165,128,224,164,
+154,224,164,191,224,164,159,224,165,141,224,164,160,224,165,139,224,164,130,224,
+164,181,224,164,191,224,164,156,224,165,141,224,164,158,224,164,190,224,164,168,
+224,164,133,224,164,174,224,165,135,224,164,176,224,164,191,224,164,149,224,164,
+190,224,164,181,224,164,191,224,164,173,224,164,191,224,164,168,224,165,141,224,
+164,168,224,164,151,224,164,190,224,164,161,224,164,191,224,164,175,224,164,190,
+224,164,129,224,164,149,224,165,141,224,164,175,224,165,139,224,164,130,224,164,
+149,224,164,191,224,164,184,224,165,129,224,164,176,224,164,149,224,165,141,224,
+164,183,224,164,190,224,164,170,224,164,185,224,165,129,224,164,129,224,164,154,
+224,164,164,224,165,128,224,164,170,224,165,141,224,164,176,224,164,172,224,164,
+130,224,164,167,224,164,168,224,164,159,224,164,191,224,164,170,224,165,141,224,
+164,170,224,164,163,224,165,128,224,164,149,224,165,141,224,164,176,224,164,191,
+224,164,149,224,165,135,224,164,159,224,164,170,224,165,141,224,164,176,224,164,
+190,224,164,176,224,164,130,224,164,173,224,164,170,224,165,141,224,164,176,224,
+164,190,224,164,170,224,165,141,224,164,164,224,164,174,224,164,190,224,164,178,
+224,164,191,224,164,149,224,165,139,224,164,130,224,164,176,224,164,171,224,164,
+188,224,165,141,224,164,164,224,164,190,224,164,176,224,164,168,224,164,191,224,
+164,176,224,165,141,224,164,174,224,164,190,224,164,163,224,164,178,224,164,191,
+224,164,174,224,164,191,224,164,159,224,165,135,224,164,161,100,101,115,99,114,
+105,112,116,105,111,110,34,32,99,111,110,116,101,110,116,61,34,100,111,99,117,
+109,101,110,116,46,108,111,99,97,116,105,111,110,46,112,114,111,116,46,103,101,
+116,69,108,101,109,101,110,116,115,66,121,84,97,103,78,97,109,101,40,60,33,68,79
+,67,84,89,80,69,32,104,116,109,108,62,10,60,104,116,109,108,32,60,109,101,116,97
+,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34,62,58,117,114,108,34,32
+,99,111,110,116,101,110,116,61,34,104,116,116,112,58,47,47,46,99,115,115,34,32,
+114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,115,116,121,108,101
+,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,62,116,121,112,101,61
+,34,116,101,120,116,47,99,115,115,34,32,104,114,101,102,61,34,119,51,46,111,114,
+103,47,49,57,57,57,47,120,104,116,109,108,34,32,120,109,108,116,121,112,101,61,
+34,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,34,32,109,101,116,104
+,111,100,61,34,103,101,116,34,32,97,99,116,105,111,110,61,34,108,105,110,107,32,
+114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,32,61,32,100,111
+,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,116,121,112,
+101,61,34,105,109,97,103,101,47,120,45,105,99,111,110,34,32,47,62,99,101,108,108
+,112,97,100,100,105,110,103,61,34,48,34,32,99,101,108,108,115,112,46,99,115,115,
+34,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,32,60,47,97,62,60,
+47,108,105,62,60,108,105,62,60,97,32,104,114,101,102,61,34,34,32,119,105,100,116
+,104,61,34,49,34,32,104,101,105,103,104,116,61,34,49,34,34,62,60,97,32,104,114,
+101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,115,116,121,108,101,61,34,
+100,105,115,112,108,97,121,58,110,111,110,101,59,34,62,97,108,116,101,114,110,97
+,116,101,34,32,116,121,112,101,61,34,97,112,112,108,105,45,47,47,87,51,67,47,47,
+68,84,68,32,88,72,84,77,76,32,49,46,48,32,101,108,108,115,112,97,99,105,110,103,
+61,34,48,34,32,99,101,108,108,112,97,100,32,116,121,112,101,61,34,104,105,100,
+100,101,110,34,32,118,97,108,117,101,61,34,47,97,62,38,110,98,115,112,59,60,115,
+112,97,110,32,114,111,108,101,61,34,115,10,60,105,110,112,117,116,32,116,121,112
+,101,61,34,104,105,100,100,101,110,34,32,108,97,110,103,117,97,103,101,61,34,74,
+97,118,97,83,99,114,105,112,116,34,32,32,100,111,99,117,109,101,110,116,46,103,
+101,116,69,108,101,109,101,110,116,115,66,103,61,34,48,34,32,99,101,108,108,115,
+112,97,99,105,110,103,61,34,48,34,32,121,112,101,61,34,116,101,120,116,47,99,115
+,115,34,32,109,101,100,105,97,61,34,116,121,112,101,61,39,116,101,120,116,47,106
+,97,118,97,115,99,114,105,112,116,39,119,105,116,104,32,116,104,101,32,101,120,
+99,101,112,116,105,111,110,32,111,102,32,121,112,101,61,34,116,101,120,116,47,99
+,115,115,34,32,114,101,108,61,34,115,116,32,104,101,105,103,104,116,61,34,49,34,
+32,119,105,100,116,104,61,34,49,34,32,61,39,43,101,110,99,111,100,101,85,82,73,
+67,111,109,112,111,110,101,110,116,40,60,108,105,110,107,32,114,101,108,61,34,97
+,108,116,101,114,110,97,116,101,34,32,10,98,111,100,121,44,32,116,114,44,32,105,
+110,112,117,116,44,32,116,101,120,116,109,101,116,97,32,110,97,109,101,61,34,114
+,111,98,111,116,115,34,32,99,111,110,109,101,116,104,111,100,61,34,112,111,115,
+116,34,32,97,99,116,105,111,110,61,34,62,10,60,97,32,104,114,101,102,61,34,104,
+116,116,112,58,47,47,119,119,119,46,99,115,115,34,32,114,101,108,61,34,115,116,
+121,108,101,115,104,101,101,116,34,32,60,47,100,105,118,62,60,47,100,105,118,62,
+60,100,105,118,32,99,108,97,115,115,108,97,110,103,117,97,103,101,61,34,106,97,
+118,97,115,99,114,105,112,116,34,62,97,114,105,97,45,104,105,100,100,101,110,61,
+34,116,114,117,101,34,62,194,183,60,114,105,112,116,34,32,116,121,112,101,61,34,
+116,101,120,116,47,106,97,118,97,115,108,61,48,59,125,41,40,41,59,10,40,102,117,
+110,99,116,105,111,110,40,41,123,98,97,99,107,103,114,111,117,110,100,45,105,109
+,97,103,101,58,32,117,114,108,40,47,97,62,60,47,108,105,62,60,108,105,62,60,97,
+32,104,114,101,102,61,34,104,9,9,60,108,105,62,60,97,32,104,114,101,102,61,34,
+104,116,116,112,58,47,47,97,116,111,114,34,32,97,114,105,97,45,104,105,100,100,
+101,110,61,34,116,114,117,62,32,60,97,32,104,114,101,102,61,34,104,116,116,112,
+58,47,47,119,119,119,46,108,97,110,103,117,97,103,101,61,34,106,97,118,97,115,99
+,114,105,112,116,34,32,47,111,112,116,105,111,110,62,10,60,111,112,116,105,111,
+110,32,118,97,108,117,101,47,100,105,118,62,60,47,100,105,118,62,60,100,105,118,
+32,99,108,97,115,115,61,114,97,116,111,114,34,32,97,114,105,97,45,104,105,100,
+100,101,110,61,34,116,114,101,61,40,110,101,119,32,68,97,116,101,41,46,103,101,
+116,84,105,109,101,40,41,112,111,114,116,117,103,117,195,170,115,32,40,100,111,
+32,66,114,97,115,105,108,41,208,190,209,128,208,179,208,176,208,189,208,184,208,
+183,208,176,209,134,208,184,208,184,208,178,208,190,208,183,208,188,208,190,208,
+182,208,189,208,190,209,129,209,130,209,140,208,190,208,177,209,128,208,176,208,
+183,208,190,208,178,208,176,208,189,208,184,209,143,209,128,208,181,208,179,208,
+184,209,129,209,130,209,128,208,176,209,134,208,184,208,184,208,178,208,190,208,
+183,208,188,208,190,208,182,208,189,208,190,209,129,209,130,208,184,208,190,208,
+177,209,143,208,183,208,176,209,130,208,181,208,187,209,140,208,189,208,176,60,
+33,68,79,67,84,89,80,69,32,104,116,109,108,32,80,85,66,76,73,67,32,34,110,116,45
+,84,121,112,101,34,32,99,111,110,116,101,110,116,61,34,116,101,120,116,47,60,109
+,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,67,111,110,116,101,
+114,97,110,115,105,116,105,111,110,97,108,47,47,69,78,34,32,34,104,116,116,112,
+58,60,104,116,109,108,32,120,109,108,110,115,61,34,104,116,116,112,58,47,47,119,
+119,119,45,47,47,87,51,67,47,47,68,84,68,32,88,72,84,77,76,32,49,46,48,32,84,68,
+84,68,47,120,104,116,109,108,49,45,116,114,97,110,115,105,116,105,111,110,97,108
+,47,47,119,119,119,46,119,51,46,111,114,103,47,84,82,47,120,104,116,109,108,49,
+47,112,101,32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,
+39,59,60,109,101,116,97,32,110,97,109,101,61,34,100,101,115,99,114,105,112,116,
+105,111,110,112,97,114,101,110,116,78,111,100,101,46,105,110,115,101,114,116,66,
+101,102,111,114,101,60,105,110,112,117,116,32,116,121,112,101,61,34,104,105,100,
+100,101,110,34,32,110,97,106,115,34,32,116,121,112,101,61,34,116,101,120,116,47,
+106,97,118,97,115,99,114,105,40,100,111,99,117,109,101,110,116,41,46,114,101,97,
+100,121,40,102,117,110,99,116,105,115,99,114,105,112,116,32,116,121,112,101,61,
+34,116,101,120,116,47,106,97,118,97,115,105,109,97,103,101,34,32,99,111,110,116,
+101,110,116,61,34,104,116,116,112,58,47,47,85,65,45,67,111,109,112,97,116,105,98
+,108,101,34,32,99,111,110,116,101,110,116,61,116,109,108,59,32,99,104,97,114,115
+,101,116,61,117,116,102,45,56,34,32,47,62,10,108,105,110,107,32,114,101,108,61,
+34,115,104,111,114,116,99,117,116,32,105,99,111,110,60,108,105,110,107,32,114,
+101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,60,47,115,99,114,105
+,112,116,62,10,60,115,99,114,105,112,116,32,116,121,112,101,61,61,32,100,111,99,
+117,109,101,110,116,46,99,114,101,97,116,101,69,108,101,109,101,110,60,97,32,116
+,97,114,103,101,116,61,34,95,98,108,97,110,107,34,32,104,114,101,102,61,32,100,
+111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,115,66,105,
+110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101,61
+,97,46,116,121,112,101,32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114,
+105,110,112,117,116,32,116,121,112,101,61,34,104,105,100,100,101,110,34,32,110,
+97,109,101,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116,102,45,56,
+34,32,47,62,100,116,100,34,62,10,60,104,116,109,108,32,120,109,108,110,115,61,34
+,104,116,116,112,45,47,47,87,51,67,47,47,68,84,68,32,72,84,77,76,32,52,46,48,49,
+32,84,101,110,116,115,66,121,84,97,103,78,97,109,101,40,39,115,99,114,105,112,
+116,39,41,105,110,112,117,116,32,116,121,112,101,61,34,104,105,100,100,101,110,
+34,32,110,97,109,60,115,99,114,105,112,116,32,116,121,112,101,61,34,116,101,120,
+116,47,106,97,118,97,115,34,32,115,116,121,108,101,61,34,100,105,115,112,108,97,
+121,58,110,111,110,101,59,34,62,100,111,99,117,109,101,110,116,46,103,101,116,69
+,108,101,109,101,110,116,66,121,73,100,40,61,100,111,99,117,109,101,110,116,46,
+99,114,101,97,116,101,69,108,101,109,101,110,116,40,39,32,116,121,112,101,61,39,
+116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,39,105,110,112,117,116,
+32,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101,61,34,100,46,103,
+101,116,69,108,101,109,101,110,116,115,66,121,84,97,103,78,97,109,101,40,115,110
+,105,99,97,108,34,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119,119,119,
+46,67,47,47,68,84,68,32,72,84,77,76,32,52,46,48,49,32,84,114,97,110,115,105,116,
+60,115,116,121,108,101,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34
+,62,10,10,60,115,116,121,108,101,32,116,121,112,101,61,34,116,101,120,116,47,99,
+115,115,34,62,105,111,110,97,108,46,100,116,100,34,62,10,60,104,116,109,108,32,
+120,109,108,110,115,61,104,116,116,112,45,101,113,117,105,118,61,34,67,111,110,
+116,101,110,116,45,84,121,112,101,100,105,110,103,61,34,48,34,32,99,101,108,108,
+115,112,97,99,105,110,103,61,34,48,34,104,116,109,108,59,32,99,104,97,114,115,
+101,116,61,117,116,102,45,56,34,32,47,62,10,32,115,116,121,108,101,61,34,100,105
+,115,112,108,97,121,58,110,111,110,101,59,34,62,60,60,108,105,62,60,97,32,104,
+114,101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,32,116,121,112,101,61,
+39,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,39,62,208,180,208,181
+,209,143,209,130,208,181,208,187,209,140,208,189,208,190,209,129,209,130,208,184
+,209,129,208,190,208,190,209,130,208,178,208,181,209,130,209,129,209,130,208,178
+,208,184,208,184,208,191,209,128,208,190,208,184,208,183,208,178,208,190,208,180
+,209,129,209,130,208,178,208,176,208,177,208,181,208,183,208,190,208,191,208,176
+,209,129,208,189,208,190,209,129,209,130,208,184,224,164,170,224,165,129,224,164
+,184,224,165,141,224,164,164,224,164,191,224,164,149,224,164,190,224,164,149,224
+,164,190,224,164,130,224,164,151,224,165,141,224,164,176,224,165,135,224,164,184
+,224,164,137,224,164,168,224,165,141,224,164,185,224,165,139,224,164,130,224,164
+,168,224,165,135,224,164,181,224,164,191,224,164,167,224,164,190,224,164,168,224
+,164,184,224,164,173,224,164,190,224,164,171,224,164,191,224,164,149,224,165,141
+,224,164,184,224,164,191,224,164,130,224,164,151,224,164,184,224,165,129,224,164
+,176,224,164,149,224,165,141,224,164,183,224,164,191,224,164,164,224,164,149,224
+,165,137,224,164,170,224,165,128,224,164,176,224,164,190,224,164,135,224,164,159
+,224,164,181,224,164,191,224,164,156,224,165,141,224,164,158,224,164,190,224,164
+,170,224,164,168,224,164,149,224,164,190,224,164,176,224,165,141,224,164,176,224
+,164,181,224,164,190,224,164,136,224,164,184,224,164,149,224,165,141,224,164,176
+,224,164,191,224,164,175,224,164,164,224,164,190
+}
+;
+#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
+
+#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
+static const BrotliDictionary kBrotliDictionary = {
+#else
+static BrotliDictionary kBrotliDictionary = {
+#endif
+ /* size_bits_by_length */
+ {
+ 0, 0, 0, 0, 10, 10, 11, 11,
+ 10, 10, 10, 10, 10, 9, 9, 8,
+ 7, 7, 8, 7, 7, 6, 6, 5,
+ 5, 0, 0, 0, 0, 0, 0, 0
+ },
+
+ /* offsets_by_length */
+ {
+ 0, 0, 0, 0, 0, 4096, 9216, 21504,
+ 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864,
+ 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280,
+ 122016, 122784, 122784, 122784, 122784, 122784, 122784, 122784
+ },
+
+ /* data_size == sizeof(kBrotliDictionaryData) */
+ 122784,
+
+ /* data */
+#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
+ NULL
+#else
+ kBrotliDictionaryData
+#endif
+};
+
+const BrotliDictionary* BrotliGetDictionary() {
+ return &kBrotliDictionary;
+}
+
+void BrotliSetDictionaryData(const uint8_t* data) {
+#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
+ if (!!data && !kBrotliDictionary.data) {
+ kBrotliDictionary.data = data;
+ }
+#else
+ BROTLI_UNUSED(data); // Appease -Werror=unused-parameter
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.h
new file mode 100644
index 000000000..b1c6f7f58
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/dictionary.h
@@ -0,0 +1,64 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Collection of static dictionary words. */
+
+#ifndef BROTLI_COMMON_DICTIONARY_H_
+#define BROTLI_COMMON_DICTIONARY_H_
+
+#include <brotli/port.h>
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct BrotliDictionary {
+ /**
+ * Number of bits to encode index of dictionary word in a bucket.
+ *
+ * Specification: Appendix A. Static Dictionary Data
+ *
+ * Words in a dictionary are bucketed by length.
+ * @c 0 means that there are no words of a given length.
+ * Dictionary consists of words with length of [4..24] bytes.
+ * Values at [0..3] and [25..31] indices should not be addressed.
+ */
+ uint8_t size_bits_by_length[32];
+
+ /* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */
+ uint32_t offsets_by_length[32];
+
+ /* assert(data_size == offsets_by_length[31]) */
+ size_t data_size;
+
+ /* Data array is not bound, and should obey to size_bits_by_length values.
+ Specified size matches default (RFC 7932) dictionary. Its size is
+ defined by data_size */
+ const uint8_t* data;
+} BrotliDictionary;
+
+BROTLI_COMMON_API const BrotliDictionary* BrotliGetDictionary(void);
+
+/**
+ * Sets dictionary data.
+ *
+ * When dictionary data is already set / present, this method is no-op.
+ *
+ * Dictionary data MUST be provided before BrotliGetDictionary is invoked.
+ * This method is used ONLY in multi-client environment (e.g. C + Java),
+ * to reduce storage by sharing single dictionary between implementations.
+ */
+BROTLI_COMMON_API void BrotliSetDictionaryData(const uint8_t* data);
+
+#define BROTLI_MIN_DICTIONARY_WORD_LENGTH 4
+#define BROTLI_MAX_DICTIONARY_WORD_LENGTH 24
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_COMMON_DICTIONARY_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/platform.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/platform.h
new file mode 100755
index 000000000..2633e0405
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/platform.h
@@ -0,0 +1,567 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Macros for compiler / platform specific features and build options.
+
+ Build options are:
+ * BROTLI_BUILD_32_BIT disables 64-bit optimizations
+ * BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
+ * BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
+ * BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
+ * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
+ * BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
+ read and overlapping memcpy; this reduces decompression speed by 5%
+ * BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
+ * BROTLI_DEBUG dumps file name and line number when decoder detects stream
+ or memory error
+ * BROTLI_ENABLE_LOG enables asserts and dumps various state information
+*/
+
+#ifndef BROTLI_COMMON_PLATFORM_H_
+#define BROTLI_COMMON_PLATFORM_H_
+
+#include <string.h> /* memcpy */
+#include <stdlib.h> /* malloc, free */
+
+#include <brotli/port.h>
+#include <brotli/types.h>
+
+#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
+#include <endian.h>
+#elif defined(OS_FREEBSD)
+#include <machine/endian.h>
+#elif defined(OS_MACOSX)
+#include <machine/endian.h>
+/* Let's try and follow the Linux convention */
+#define BROTLI_X_BYTE_ORDER BYTE_ORDER
+#define BROTLI_X_LITTLE_ENDIAN LITTLE_ENDIAN
+#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
+#endif
+
+#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
+#include <assert.h>
+#include <stdio.h>
+#endif
+
+/* The following macros were borrowed from https://github.com/nemequ/hedley
+ * with permission of original author - Evan Nemerson <evan@nemerson.com> */
+
+/* >>> >>> >>> hedley macros */
+
+/* Define "BROTLI_PREDICT_TRUE" and "BROTLI_PREDICT_FALSE" macros for capable
+ compilers.
+
+To apply compiler hint, enclose the branching condition into macros, like this:
+
+ if (BROTLI_PREDICT_TRUE(zero == 0)) {
+ // main execution path
+ } else {
+ // compiler should place this code outside of main execution path
+ }
+
+OR:
+
+ if (BROTLI_PREDICT_FALSE(something_rare_or_unexpected_happens)) {
+ // compiler should place this code outside of main execution path
+ }
+
+*/
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+ BROTLI_TI_VERSION_CHECK(7, 3, 0) || \
+ BROTLI_TINYC_VERSION_CHECK(0, 9, 27)
+#define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#else
+#define BROTLI_PREDICT_FALSE(x) (x)
+#define BROTLI_PREDICT_TRUE(x) (x)
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+ !defined(__cplusplus)
+#define BROTLI_RESTRICT restrict
+#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) || \
+ BROTLI_MSVC_VERSION_CHECK(14, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+ BROTLI_PGI_VERSION_CHECK(17, 10, 0) || \
+ BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
+ BROTLI_IAR_VERSION_CHECK(8, 0, 0) || \
+ (BROTLI_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus))
+#define BROTLI_RESTRICT __restrict
+#elif BROTLI_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus)
+#define BROTLI_RESTRICT _Restrict
+#else
+#define BROTLI_RESTRICT
+#endif
+
+#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+ (defined(__cplusplus) && (__cplusplus >= 199711L))
+#define BROTLI_MAYBE_INLINE inline
+#elif defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__) || \
+ BROTLI_ARM_VERSION_CHECK(6, 2, 0)
+#define BROTLI_MAYBE_INLINE __inline__
+#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_TI_VERSION_CHECK(8, 0, 0)
+#define BROTLI_MAYBE_INLINE __inline
+#else
+#define BROTLI_MAYBE_INLINE
+#endif
+
+#if BROTLI_GNUC_HAS_ATTRIBUTE(always_inline, 4, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+ BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
+ (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
+#define BROTLI_INLINE BROTLI_MAYBE_INLINE __attribute__((__always_inline__))
+#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
+#define BROTLI_INLINE BROTLI_MAYBE_INLINE __forceinline
+#elif BROTLI_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus)
+#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
+#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
+#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("inline=forced")
+#else
+#define BROTLI_INLINE BROTLI_MAYBE_INLINE
+#endif
+
+#if BROTLI_GNUC_HAS_ATTRIBUTE(noinline, 4, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+ BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
+ (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
+#define BROTLI_NOINLINE __attribute__((__noinline__))
+#elif BROTLI_MSVC_VERSION_CHECK(13, 10, 0)
+#define BROTLI_NOINLINE __declspec(noinline)
+#elif BROTLI_PGI_VERSION_CHECK(10, 2, 0)
+#define BROTLI_NOINLINE _Pragma("noinline")
+#elif BROTLI_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus)
+#define BROTLI_NOINLINE _Pragma("FUNC_CANNOT_INLINE;")
+#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
+#define BROTLI_NOINLINE _Pragma("inline=never")
+#else
+#define BROTLI_NOINLINE
+#endif
+
+/* BROTLI_INTERNAL could be defined to override visibility, e.g. for tests. */
+#if !defined(BROTLI_INTERNAL)
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define BROTLI_INTERNAL
+#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
+ BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
+ (BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
+ defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
+#define BROTLI_INTERNAL __attribute__ ((visibility ("hidden")))
+#else
+#define BROTLI_INTERNAL
+#endif
+#endif
+
+/* <<< <<< <<< end of hedley macros. */
+
+#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
+#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE __attribute__ ((unused))
+#else
+#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE
+#endif
+
+#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
+#define BROTLI_ALIGNED(N) __attribute__((aligned(N)))
+#else
+#define BROTLI_ALIGNED(N)
+#endif
+
+#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
+ (defined(M_ARM) && (M_ARM == 7))
+#define BROTLI_TARGET_ARMV7
+#endif /* ARMv7 */
+
+#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \
+ defined(__aarch64__) || defined(__ARM64_ARCH_8__)
+#define BROTLI_TARGET_ARMV8_ANY
+
+#if defined(__ARM_32BIT_STATE)
+#define BROTLI_TARGET_ARMV8_32
+#elif defined(__ARM_64BIT_STATE)
+#define BROTLI_TARGET_ARMV8_64
+#endif
+
+#endif /* ARMv8 */
+
+#if defined(__ARM_NEON__) || defined(__ARM_NEON)
+#define BROTLI_TARGET_NEON
+#endif
+
+#if defined(__i386) || defined(_M_IX86)
+#define BROTLI_TARGET_X86
+#endif
+
+#if defined(__x86_64__) || defined(_M_X64)
+#define BROTLI_TARGET_X64
+#endif
+
+#if defined(__PPC64__)
+#define BROTLI_TARGET_POWERPC64
+#endif
+
+#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
+#define BROTLI_TARGET_RISCV64
+#endif
+
+#if defined(BROTLI_BUILD_64_BIT)
+#define BROTLI_64_BITS 1
+#elif defined(BROTLI_BUILD_32_BIT)
+#define BROTLI_64_BITS 0
+#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
+ defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
+#define BROTLI_64_BITS 1
+#else
+#define BROTLI_64_BITS 0
+#endif
+
+#if (BROTLI_64_BITS)
+#define brotli_reg_t uint64_t
+#else
+#define brotli_reg_t uint32_t
+#endif
+
+#if defined(BROTLI_BUILD_BIG_ENDIAN)
+#define BROTLI_BIG_ENDIAN 1
+#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
+#define BROTLI_LITTLE_ENDIAN 1
+#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
+/* Just break elif chain. */
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define BROTLI_LITTLE_ENDIAN 1
+#elif defined(_WIN32) || defined(BROTLI_TARGET_X64)
+/* Win32 & x64 can currently always be assumed to be little endian */
+#define BROTLI_LITTLE_ENDIAN 1
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define BROTLI_BIG_ENDIAN 1
+#elif defined(BROTLI_X_BYTE_ORDER)
+#if BROTLI_X_BYTE_ORDER == BROTLI_X_LITTLE_ENDIAN
+#define BROTLI_LITTLE_ENDIAN 1
+#elif BROTLI_X_BYTE_ORDER == BROTLI_X_BIG_ENDIAN
+#define BROTLI_BIG_ENDIAN 1
+#endif
+#endif /* BROTLI_X_BYTE_ORDER */
+
+#if !defined(BROTLI_LITTLE_ENDIAN)
+#define BROTLI_LITTLE_ENDIAN 0
+#endif
+
+#if !defined(BROTLI_BIG_ENDIAN)
+#define BROTLI_BIG_ENDIAN 0
+#endif
+
+#if defined(BROTLI_X_BYTE_ORDER)
+#undef BROTLI_X_BYTE_ORDER
+#undef BROTLI_X_LITTLE_ENDIAN
+#undef BROTLI_X_BIG_ENDIAN
+#endif
+
+#if defined(BROTLI_BUILD_PORTABLE)
+#define BROTLI_ALIGNED_READ (!!1)
+#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
+ defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
+ defined(BROTLI_TARGET_RISCV64)
+/* Allow unaligned read only for white-listed CPUs. */
+#define BROTLI_ALIGNED_READ (!!0)
+#else
+#define BROTLI_ALIGNED_READ (!!1)
+#endif
+
+#if BROTLI_ALIGNED_READ
+/* Portable unaligned memory access: read / write values via memcpy. */
+static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
+ uint16_t t;
+ memcpy(&t, p, sizeof t);
+ return t;
+}
+static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
+ uint32_t t;
+ memcpy(&t, p, sizeof t);
+ return t;
+}
+static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
+ uint64_t t;
+ memcpy(&t, p, sizeof t);
+ return t;
+}
+static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
+ memcpy(p, &v, sizeof v);
+}
+#else /* BROTLI_ALIGNED_READ */
+/* Unaligned memory access is allowed: just cast pointer to requested type. */
+#if BROTLI_SANITIZED
+/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
+ AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
+ will miss a bug if 08 is the first unaddressable byte.
+ ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
+ miss a race between this access and some other accesses to 08.
+ MemorySanitizer will correctly propagate the shadow on unaligned stores
+ and correctly report bugs on unaligned loads, but it may not properly
+ update and report the origin of the uninitialized memory.
+ For all three tools, replacing an unaligned access with a tool-specific
+ callback solves the problem. */
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+ uint16_t __sanitizer_unaligned_load16(const void* p);
+ uint32_t __sanitizer_unaligned_load32(const void* p);
+ uint64_t __sanitizer_unaligned_load64(const void* p);
+ void __sanitizer_unaligned_store64(void* p, uint64_t v);
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* __cplusplus */
+#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
+#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
+#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
+#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
+#else /* BROTLI_SANITIZED */
+static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
+ return *(const uint16_t*)p;
+}
+static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
+ return *(const uint32_t*)p;
+}
+#if (BROTLI_64_BITS)
+static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
+ return *(const uint64_t*)p;
+}
+static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
+ *(uint64_t*)p = v;
+}
+#else /* BROTLI_64_BITS */
+/* Avoid emitting LDRD / STRD, which require properly aligned address. */
+/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
+
+#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
+typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
+
+static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
+ return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
+}
+static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
+ brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
+ dwords[0] = (brotli_unaligned_uint64_t) v;
+}
+#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
+static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
+ uint64_t v;
+ memcpy(&v, p, sizeof(uint64_t));
+ return v;
+}
+
+static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
+ memcpy(p, &v, sizeof(uint64_t));
+}
+#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
+#endif /* BROTLI_64_BITS */
+#endif /* BROTLI_SANITIZED */
+#endif /* BROTLI_ALIGNED_READ */
+
+#if BROTLI_LITTLE_ENDIAN
+/* Straight endianness. Just read / write values. */
+#define BROTLI_UNALIGNED_LOAD16LE BrotliUnalignedRead16
+#define BROTLI_UNALIGNED_LOAD32LE BrotliUnalignedRead32
+#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64
+#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64
+#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */
+/* Explain compiler to byte-swap values. */
+#define BROTLI_BSWAP16_(V) ((uint16_t)( \
+ (((V) & 0xFFU) << 8) | \
+ (((V) >> 8) & 0xFFU)))
+static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
+ uint16_t value = BrotliUnalignedRead16(p);
+ return BROTLI_BSWAP16_(value);
+}
+#define BROTLI_BSWAP32_(V) ( \
+ (((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
+ (((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU))
+static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
+ uint32_t value = BrotliUnalignedRead32(p);
+ return BROTLI_BSWAP32_(value);
+}
+#define BROTLI_BSWAP64_(V) ( \
+ (((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
+ (((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
+ (((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
+ (((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU))
+static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
+ uint64_t value = BrotliUnalignedRead64(p);
+ return BROTLI_BSWAP64_(value);
+}
+static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
+ uint64_t value = BROTLI_BSWAP64_(v);
+ BrotliUnalignedWrite64(p, value);
+}
+#else /* BROTLI_LITTLE_ENDIAN */
+/* Read / store values byte-wise; hopefully compiler will understand. */
+static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
+ const uint8_t* in = (const uint8_t*)p;
+ return (uint16_t)(in[0] | (in[1] << 8));
+}
+static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
+ const uint8_t* in = (const uint8_t*)p;
+ uint32_t value = (uint32_t)(in[0]);
+ value |= (uint32_t)(in[1]) << 8;
+ value |= (uint32_t)(in[2]) << 16;
+ value |= (uint32_t)(in[3]) << 24;
+ return value;
+}
+static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
+ const uint8_t* in = (const uint8_t*)p;
+ uint64_t value = (uint64_t)(in[0]);
+ value |= (uint64_t)(in[1]) << 8;
+ value |= (uint64_t)(in[2]) << 16;
+ value |= (uint64_t)(in[3]) << 24;
+ value |= (uint64_t)(in[4]) << 32;
+ value |= (uint64_t)(in[5]) << 40;
+ value |= (uint64_t)(in[6]) << 48;
+ value |= (uint64_t)(in[7]) << 56;
+ return value;
+}
+static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
+ uint8_t* out = (uint8_t*)p;
+ out[0] = (uint8_t)v;
+ out[1] = (uint8_t)(v >> 8);
+ out[2] = (uint8_t)(v >> 16);
+ out[3] = (uint8_t)(v >> 24);
+ out[4] = (uint8_t)(v >> 32);
+ out[5] = (uint8_t)(v >> 40);
+ out[6] = (uint8_t)(v >> 48);
+ out[7] = (uint8_t)(v >> 56);
+}
+#endif /* BROTLI_LITTLE_ENDIAN */
+
+/* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
+#define BROTLI_IS_CONSTANT(x) (!!__builtin_constant_p(x))
+#else
+#define BROTLI_IS_CONSTANT(x) (!!0)
+#endif
+
+#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
+#define BROTLI_HAS_UBFX (!!1)
+#else
+#define BROTLI_HAS_UBFX (!!0)
+#endif
+
+#if defined(BROTLI_ENABLE_LOG)
+#define BROTLI_LOG(x) printf x
+#else
+#define BROTLI_LOG(x)
+#endif
+
+#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
+#define BROTLI_DCHECK(x) assert(x)
+static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
+ fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
+ fflush(stderr);
+}
+#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
+#else
+#define BROTLI_DCHECK(x)
+#define BROTLI_DUMP() (void)(0)
+#endif
+
+/* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */
+#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \
+ !defined(BROTLI_BUILD_NO_RBIT)
+#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
+/* TODO: detect ARMv6T2 and enable this code for it. */
+static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
+ brotli_reg_t output;
+ __asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
+ return output;
+}
+#define BROTLI_RBIT(x) BrotliRBit(x)
+#endif /* armv7 / armv8 */
+#endif /* gcc || clang */
+#if !defined(BROTLI_RBIT)
+static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ }
+#endif /* BROTLI_RBIT */
+
+#define BROTLI_REPEAT(N, X) { \
+ if ((N & 1) != 0) {X;} \
+ if ((N & 2) != 0) {X; X;} \
+ if ((N & 4) != 0) {X; X; X; X;} \
+}
+
+#define BROTLI_UNUSED(X) (void)(X)
+
+#define BROTLI_MIN_MAX(T) \
+ static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \
+ static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; }
+BROTLI_MIN_MAX(double) BROTLI_MIN_MAX(float) BROTLI_MIN_MAX(int)
+BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
+#undef BROTLI_MIN_MAX
+#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
+#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
+
+#define BROTLI_SWAP(T, A, I, J) { \
+ T __brotli_swap_tmp = (A)[(I)]; \
+ (A)[(I)] = (A)[(J)]; \
+ (A)[(J)] = __brotli_swap_tmp; \
+}
+
+/* Default brotli_alloc_func */
+static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
+ BROTLI_UNUSED(opaque);
+ return malloc(size);
+}
+
+/* Default brotli_free_func */
+static void BrotliDefaultFreeFunc(void* opaque, void* address) {
+ BROTLI_UNUSED(opaque);
+ free(address);
+}
+
+BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
+ BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
+ BROTLI_UNUSED(&BrotliUnalignedRead16);
+ BROTLI_UNUSED(&BrotliUnalignedRead32);
+ BROTLI_UNUSED(&BrotliUnalignedRead64);
+ BROTLI_UNUSED(&BrotliUnalignedWrite64);
+ BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD16LE);
+ BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE);
+ BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE);
+ BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE);
+ BROTLI_UNUSED(&BrotliRBit);
+ BROTLI_UNUSED(&brotli_min_double);
+ BROTLI_UNUSED(&brotli_max_double);
+ BROTLI_UNUSED(&brotli_min_float);
+ BROTLI_UNUSED(&brotli_max_float);
+ BROTLI_UNUSED(&brotli_min_int);
+ BROTLI_UNUSED(&brotli_max_int);
+ BROTLI_UNUSED(&brotli_min_size_t);
+ BROTLI_UNUSED(&brotli_max_size_t);
+ BROTLI_UNUSED(&brotli_min_uint32_t);
+ BROTLI_UNUSED(&brotli_max_uint32_t);
+ BROTLI_UNUSED(&brotli_min_uint8_t);
+ BROTLI_UNUSED(&brotli_max_uint8_t);
+ BROTLI_UNUSED(&BrotliDefaultAllocFunc);
+ BROTLI_UNUSED(&BrotliDefaultFreeFunc);
+#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
+ BROTLI_UNUSED(&BrotliDump);
+#endif
+}
+
+#endif /* BROTLI_COMMON_PLATFORM_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.c
new file mode 100755
index 000000000..f8fa4335e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.c
@@ -0,0 +1,291 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./transform.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* RFC 7932 transforms string data */
+static const char kPrefixSuffix[217] =
+ "\1 \2, \10 of the \4 of \2s \1.\5 and \4 "
+/* 0x _0 _2 __5 _E _3 _6 _8 _E */
+ "in \1\"\4 to \2\">\1\n\2. \1]\5 for \3 a \6 "
+/* 2x _3_ _5 _A_ _D_ _F _2 _4 _A _E */
+ "that \1\'\6 with \6 from \4 by \1(\6. T"
+/* 4x _5_ _7 _E _5 _A _C */
+ "he \4 on \4 as \4 is \4ing \2\n\t\1:\3ed "
+/* 6x _3 _8 _D _2 _7_ _ _A _C */
+ "\2=\"\4 at \3ly \1,\2=\'\5.com/\7. This \5"
+/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */
+ " not \3er \3al \4ful \4ive \5less \4es"
+/* Ax _5 _9 _D _2 _7 _D */
+ "t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
+/* Cx _2 _7___ ___ _A _F _5 _8 */
+
+static const uint16_t kPrefixSuffixMap[50] = {
+ 0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
+ 0x2A, 0x2D, 0x2F, 0x32, 0x34, 0x3A, 0x3E, 0x45, 0x47, 0x4E,
+ 0x55, 0x5A, 0x5C, 0x63, 0x68, 0x6D, 0x72, 0x77, 0x7A, 0x7C,
+ 0x80, 0x83, 0x88, 0x8C, 0x8E, 0x91, 0x97, 0x9F, 0xA5, 0xA9,
+ 0xAD, 0xB2, 0xB7, 0xBD, 0xC2, 0xC7, 0xCA, 0xCF, 0xD5, 0xD8
+};
+
+/* RFC 7932 transforms */
+static const uint8_t kTransformsData[] = {
+ 49, BROTLI_TRANSFORM_IDENTITY, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 0,
+ 0, BROTLI_TRANSFORM_IDENTITY, 0,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_1, 49,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 47,
+ 0, BROTLI_TRANSFORM_IDENTITY, 49,
+ 4, BROTLI_TRANSFORM_IDENTITY, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 3,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 6,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_2, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_1, 49,
+ 1, BROTLI_TRANSFORM_IDENTITY, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 1,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 7,
+ 49, BROTLI_TRANSFORM_IDENTITY, 9,
+ 48, BROTLI_TRANSFORM_IDENTITY, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 8,
+ 49, BROTLI_TRANSFORM_IDENTITY, 5,
+ 49, BROTLI_TRANSFORM_IDENTITY, 10,
+ 49, BROTLI_TRANSFORM_IDENTITY, 11,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_3, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 13,
+ 49, BROTLI_TRANSFORM_IDENTITY, 14,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_3, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_2, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 15,
+ 49, BROTLI_TRANSFORM_IDENTITY, 16,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 12,
+ 5, BROTLI_TRANSFORM_IDENTITY, 49,
+ 0, BROTLI_TRANSFORM_IDENTITY, 1,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_4, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 18,
+ 49, BROTLI_TRANSFORM_IDENTITY, 17,
+ 49, BROTLI_TRANSFORM_IDENTITY, 19,
+ 49, BROTLI_TRANSFORM_IDENTITY, 20,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_5, 49,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_6, 49,
+ 47, BROTLI_TRANSFORM_IDENTITY, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_4, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 22,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 23,
+ 49, BROTLI_TRANSFORM_IDENTITY, 24,
+ 49, BROTLI_TRANSFORM_IDENTITY, 25,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_7, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_1, 26,
+ 49, BROTLI_TRANSFORM_IDENTITY, 27,
+ 49, BROTLI_TRANSFORM_IDENTITY, 28,
+ 0, BROTLI_TRANSFORM_IDENTITY, 12,
+ 49, BROTLI_TRANSFORM_IDENTITY, 29,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_9, 49,
+ 49, BROTLI_TRANSFORM_OMIT_FIRST_7, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_6, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 21,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_8, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 31,
+ 49, BROTLI_TRANSFORM_IDENTITY, 32,
+ 47, BROTLI_TRANSFORM_IDENTITY, 3,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_5, 49,
+ 49, BROTLI_TRANSFORM_OMIT_LAST_9, 49,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 8,
+ 5, BROTLI_TRANSFORM_IDENTITY, 21,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 0,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 10,
+ 49, BROTLI_TRANSFORM_IDENTITY, 30,
+ 0, BROTLI_TRANSFORM_IDENTITY, 5,
+ 35, BROTLI_TRANSFORM_IDENTITY, 49,
+ 47, BROTLI_TRANSFORM_IDENTITY, 2,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 17,
+ 49, BROTLI_TRANSFORM_IDENTITY, 36,
+ 49, BROTLI_TRANSFORM_IDENTITY, 33,
+ 5, BROTLI_TRANSFORM_IDENTITY, 0,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 21,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5,
+ 49, BROTLI_TRANSFORM_IDENTITY, 37,
+ 0, BROTLI_TRANSFORM_IDENTITY, 30,
+ 49, BROTLI_TRANSFORM_IDENTITY, 38,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 0,
+ 49, BROTLI_TRANSFORM_IDENTITY, 39,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 49,
+ 49, BROTLI_TRANSFORM_IDENTITY, 34,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 8,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12,
+ 0, BROTLI_TRANSFORM_IDENTITY, 21,
+ 49, BROTLI_TRANSFORM_IDENTITY, 40,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12,
+ 49, BROTLI_TRANSFORM_IDENTITY, 41,
+ 49, BROTLI_TRANSFORM_IDENTITY, 42,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 17,
+ 49, BROTLI_TRANSFORM_IDENTITY, 43,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 10,
+ 0, BROTLI_TRANSFORM_IDENTITY, 34,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33,
+ 49, BROTLI_TRANSFORM_IDENTITY, 44,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 5,
+ 45, BROTLI_TRANSFORM_IDENTITY, 49,
+ 0, BROTLI_TRANSFORM_IDENTITY, 33,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 30,
+ 49, BROTLI_TRANSFORM_IDENTITY, 46,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 1,
+ 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 30,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 1,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 33,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 21,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 12,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 5,
+ 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 34,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 12,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30,
+ 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 34,
+ 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
+};
+
+static const BrotliTransforms kBrotliTransforms = {
+ sizeof(kPrefixSuffix),
+ (const uint8_t*)kPrefixSuffix,
+ kPrefixSuffixMap,
+ sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
+ kTransformsData,
+ NULL, /* no extra parameters */
+ {0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
+};
+
+const BrotliTransforms* BrotliGetTransforms(void) {
+ return &kBrotliTransforms;
+}
+
+static int ToUpperCase(uint8_t* p) {
+ if (p[0] < 0xC0) {
+ if (p[0] >= 'a' && p[0] <= 'z') {
+ p[0] ^= 32;
+ }
+ return 1;
+ }
+ /* An overly simplified uppercasing model for UTF-8. */
+ if (p[0] < 0xE0) {
+ p[1] ^= 32;
+ return 2;
+ }
+ /* An arbitrary transform for three byte characters. */
+ p[2] ^= 5;
+ return 3;
+}
+
+static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
+ /* Limited sign extension: scalar < (1 << 24). */
+ uint32_t scalar =
+ (parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
+ if (word[0] < 0x80) {
+ /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
+ scalar += (uint32_t)word[0];
+ word[0] = (uint8_t)(scalar & 0x7Fu);
+ return 1;
+ } else if (word[0] < 0xC0) {
+ /* Continuation / 10AAAAAA. */
+ return 1;
+ } else if (word[0] < 0xE0) {
+ /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
+ if (word_len < 2) return 1;
+ scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
+ word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
+ word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
+ return 2;
+ } else if (word[0] < 0xF0) {
+ /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
+ if (word_len < 3) return word_len;
+ scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
+ ((word[0] & 0x0Fu) << 12u));
+ word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
+ word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
+ word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
+ return 3;
+ } else if (word[0] < 0xF8) {
+ /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
+ if (word_len < 4) return word_len;
+ scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
+ ((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
+ word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
+ word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
+ word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
+ word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
+ return 4;
+ }
+ return 1;
+}
+
+int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
+ const BrotliTransforms* transforms, int transform_idx) {
+ int idx = 0;
+ const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transform_idx);
+ uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transform_idx);
+ const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transform_idx);
+ {
+ int prefix_len = *prefix++;
+ while (prefix_len--) { dst[idx++] = *prefix++; }
+ }
+ {
+ const int t = type;
+ int i = 0;
+ if (t <= BROTLI_TRANSFORM_OMIT_LAST_9) {
+ len -= t;
+ } else if (t >= BROTLI_TRANSFORM_OMIT_FIRST_1
+ && t <= BROTLI_TRANSFORM_OMIT_FIRST_9) {
+ int skip = t - (BROTLI_TRANSFORM_OMIT_FIRST_1 - 1);
+ word += skip;
+ len -= skip;
+ }
+ while (i < len) { dst[idx++] = word[i++]; }
+ if (t == BROTLI_TRANSFORM_UPPERCASE_FIRST) {
+ ToUpperCase(&dst[idx - len]);
+ } else if (t == BROTLI_TRANSFORM_UPPERCASE_ALL) {
+ uint8_t* uppercase = &dst[idx - len];
+ while (len > 0) {
+ int step = ToUpperCase(uppercase);
+ uppercase += step;
+ len -= step;
+ }
+ } else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
+ uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+ + (transforms->params[transform_idx * 2 + 1] << 8u));
+ Shift(&dst[idx - len], len, param);
+ } else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
+ uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+ + (transforms->params[transform_idx * 2 + 1] << 8u));
+ uint8_t* shift = &dst[idx - len];
+ while (len > 0) {
+ int step = Shift(shift, len, param);
+ shift += step;
+ len -= step;
+ }
+ }
+ }
+ {
+ int suffix_len = *suffix++;
+ while (suffix_len--) { dst[idx++] = *suffix++; }
+ return idx;
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.h
new file mode 100755
index 000000000..b6f86cc7d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/transform.h
@@ -0,0 +1,85 @@
+/* transforms is a part of ABI, but not API.
+
+ It means that there are some functions that are supposed to be in "common"
+ library, but header itself is not placed into include/brotli. This way,
+ aforementioned functions will be available only to brotli internals.
+ */
+
+#ifndef BROTLI_COMMON_TRANSFORM_H_
+#define BROTLI_COMMON_TRANSFORM_H_
+
+#include <brotli/port.h>
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+enum BrotliWordTransformType {
+ BROTLI_TRANSFORM_IDENTITY = 0,
+ BROTLI_TRANSFORM_OMIT_LAST_1 = 1,
+ BROTLI_TRANSFORM_OMIT_LAST_2 = 2,
+ BROTLI_TRANSFORM_OMIT_LAST_3 = 3,
+ BROTLI_TRANSFORM_OMIT_LAST_4 = 4,
+ BROTLI_TRANSFORM_OMIT_LAST_5 = 5,
+ BROTLI_TRANSFORM_OMIT_LAST_6 = 6,
+ BROTLI_TRANSFORM_OMIT_LAST_7 = 7,
+ BROTLI_TRANSFORM_OMIT_LAST_8 = 8,
+ BROTLI_TRANSFORM_OMIT_LAST_9 = 9,
+ BROTLI_TRANSFORM_UPPERCASE_FIRST = 10,
+ BROTLI_TRANSFORM_UPPERCASE_ALL = 11,
+ BROTLI_TRANSFORM_OMIT_FIRST_1 = 12,
+ BROTLI_TRANSFORM_OMIT_FIRST_2 = 13,
+ BROTLI_TRANSFORM_OMIT_FIRST_3 = 14,
+ BROTLI_TRANSFORM_OMIT_FIRST_4 = 15,
+ BROTLI_TRANSFORM_OMIT_FIRST_5 = 16,
+ BROTLI_TRANSFORM_OMIT_FIRST_6 = 17,
+ BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
+ BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
+ BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
+ BROTLI_TRANSFORM_SHIFT_FIRST = 21,
+ BROTLI_TRANSFORM_SHIFT_ALL = 22,
+ BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
+};
+
+#define BROTLI_TRANSFORMS_MAX_CUT_OFF BROTLI_TRANSFORM_OMIT_LAST_9
+
+typedef struct BrotliTransforms {
+ uint16_t prefix_suffix_size;
+ /* Last character must be null, so prefix_suffix_size must be at least 1. */
+ const uint8_t* prefix_suffix;
+ const uint16_t* prefix_suffix_map;
+ uint32_t num_transforms;
+ /* Each entry is a [prefix_id, transform, suffix_id] triplet. */
+ const uint8_t* transforms;
+ /* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
+ must be NULL if and only if no such transforms are present. */
+ const uint8_t* params;
+ /* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
+ 0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
+ -1, if cut-off transform does not exist. */
+ int16_t cutOffTransforms[BROTLI_TRANSFORMS_MAX_CUT_OFF + 1];
+} BrotliTransforms;
+
+/* T is BrotliTransforms*; result is uint8_t. */
+#define BROTLI_TRANSFORM_PREFIX_ID(T, I) ((T)->transforms[((I) * 3) + 0])
+#define BROTLI_TRANSFORM_TYPE(T, I) ((T)->transforms[((I) * 3) + 1])
+#define BROTLI_TRANSFORM_SUFFIX_ID(T, I) ((T)->transforms[((I) * 3) + 2])
+
+/* T is BrotliTransforms*; result is const uint8_t*. */
+#define BROTLI_TRANSFORM_PREFIX(T, I) (&(T)->prefix_suffix[ \
+ (T)->prefix_suffix_map[BROTLI_TRANSFORM_PREFIX_ID(T, I)]])
+#define BROTLI_TRANSFORM_SUFFIX(T, I) (&(T)->prefix_suffix[ \
+ (T)->prefix_suffix_map[BROTLI_TRANSFORM_SUFFIX_ID(T, I)]])
+
+BROTLI_COMMON_API const BrotliTransforms* BrotliGetTransforms(void);
+
+BROTLI_COMMON_API int BrotliTransformDictionaryWord(
+ uint8_t* dst, const uint8_t* word, int len,
+ const BrotliTransforms* transforms, int transform_idx);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_COMMON_TRANSFORM_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/version.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/version.h
new file mode 100644
index 000000000..0d0d0c796
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/common/version.h
@@ -0,0 +1,26 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Version definition. */
+
+#ifndef BROTLI_COMMON_VERSION_H_
+#define BROTLI_COMMON_VERSION_H_
+
+/* This macro should only be used when library is compiled together with client.
+ If library is dynamically linked, use BrotliDecoderVersion and
+ BrotliEncoderVersion methods. */
+
+/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
+#define BROTLI_VERSION 0x1000007
+
+/* This macro is used by build system to produce Libtool-friendly soname. See
+ https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
+ */
+
+/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
+#define BROTLI_ABI_VERSION 0x1007000
+
+#endif /* BROTLI_COMMON_VERSION_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.c
new file mode 100644
index 000000000..41cd0504f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.c
@@ -0,0 +1,65 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Bit reading helpers */
+
+#include "./bit_reader.h"
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+void BrotliInitBitReader(BrotliBitReader* const br) {
+ br->val_ = 0;
+ br->bit_pos_ = sizeof(br->val_) << 3;
+}
+
+BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
+ size_t aligned_read_mask = (sizeof(br->val_) >> 1) - 1;
+ /* Fixing alignment after unaligned BrotliFillWindow would result accumulator
+ overflow. If unalignment is caused by BrotliSafeReadBits, then there is
+ enough space in accumulator to fix alignment. */
+ if (!BROTLI_ALIGNED_READ) {
+ aligned_read_mask = 0;
+ }
+ if (BrotliGetAvailableBits(br) == 0) {
+ if (!BrotliPullByte(br)) {
+ return BROTLI_FALSE;
+ }
+ }
+
+ while ((((size_t)br->next_in) & aligned_read_mask) != 0) {
+ if (!BrotliPullByte(br)) {
+ /* If we consumed all the input, we don't care about the alignment. */
+ return BROTLI_TRUE;
+ }
+ }
+ return BROTLI_TRUE;
+}
+
+BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
+ uint32_t n_bits, uint32_t* val) {
+ uint32_t low_val;
+ uint32_t high_val;
+ BrotliBitReaderState memento;
+ BROTLI_DCHECK(n_bits <= 32);
+ BROTLI_DCHECK(n_bits > 24);
+ BrotliBitReaderSaveState(br, &memento);
+ if (!BrotliSafeReadBits(br, 16, &low_val) ||
+ !BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
+ BrotliBitReaderRestoreState(br, &memento);
+ return BROTLI_FALSE;
+ }
+ *val = low_val | (high_val << 16);
+ return BROTLI_TRUE;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.h
new file mode 100644
index 000000000..f94a717ea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/bit_reader.h
@@ -0,0 +1,356 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Bit reading helpers */
+
+#ifndef BROTLI_DEC_BIT_READER_H_
+#define BROTLI_DEC_BIT_READER_H_
+
+#include <string.h> /* memcpy */
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
+
+static const uint32_t kBitMask[33] = { 0x00000000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+ 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+ 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+ 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+ 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+ 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+ 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+ 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
+static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
+ if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
+ /* Masking with this expression turns to a single
+ "Unsigned Bit Field Extract" UBFX instruction on ARM. */
+ return ~((0xFFFFFFFFu) << n);
+ } else {
+ return kBitMask[n];
+ }
+}
+
+typedef struct {
+ brotli_reg_t val_; /* pre-fetched bits */
+ uint32_t bit_pos_; /* current bit-reading position in val_ */
+ const uint8_t* next_in; /* the byte we're reading from */
+ size_t avail_in;
+} BrotliBitReader;
+
+typedef struct {
+ brotli_reg_t val_;
+ uint32_t bit_pos_;
+ const uint8_t* next_in;
+ size_t avail_in;
+} BrotliBitReaderState;
+
+/* Initializes the BrotliBitReader fields. */
+BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
+
+/* Ensures that accumulator is not empty.
+ May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
+ Returns BROTLI_FALSE if data is required but there is no input available.
+ For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
+ reading. */
+BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
+
+/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
+ the main code-path. Never called for RFC brotli streams, required only for
+ "large-window" mode and other extensions. */
+BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
+
+static BROTLI_INLINE void BrotliBitReaderSaveState(
+ BrotliBitReader* const from, BrotliBitReaderState* to) {
+ to->val_ = from->val_;
+ to->bit_pos_ = from->bit_pos_;
+ to->next_in = from->next_in;
+ to->avail_in = from->avail_in;
+}
+
+static BROTLI_INLINE void BrotliBitReaderRestoreState(
+ BrotliBitReader* const to, BrotliBitReaderState* from) {
+ to->val_ = from->val_;
+ to->bit_pos_ = from->bit_pos_;
+ to->next_in = from->next_in;
+ to->avail_in = from->avail_in;
+}
+
+static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
+ const BrotliBitReader* br) {
+ return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
+}
+
+/* Returns amount of unread bytes the bit reader still has buffered from the
+ BrotliInput, including whole bytes in br->val_. */
+static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
+ return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
+}
+
+/* Checks if there is at least |num| bytes left in the input ring-buffer
+ (excluding the bits remaining in br->val_). */
+static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
+ BrotliBitReader* const br, size_t num) {
+ return TO_BROTLI_BOOL(br->avail_in >= num);
+}
+
+/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
+ Precondition: accumulator contains at least 1 bit.
+ |n_bits| should be in the range [1..24] for regular build. For portable
+ non-64-bit little-endian build only 16 bits are safe to request. */
+static BROTLI_INLINE void BrotliFillBitWindow(
+ BrotliBitReader* const br, uint32_t n_bits) {
+#if (BROTLI_64_BITS)
+ if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
+ if (br->bit_pos_ >= 56) {
+ br->val_ >>= 56;
+ br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
+ br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8;
+ br->avail_in -= 7;
+ br->next_in += 7;
+ }
+ } else if (
+ !BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) {
+ if (br->bit_pos_ >= 48) {
+ br->val_ >>= 48;
+ br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
+ br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16;
+ br->avail_in -= 6;
+ br->next_in += 6;
+ }
+ } else {
+ if (br->bit_pos_ >= 32) {
+ br->val_ >>= 32;
+ br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
+ br->val_ |= ((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32;
+ br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ }
+ }
+#else
+ if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
+ if (br->bit_pos_ >= 24) {
+ br->val_ >>= 24;
+ br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
+ br->val_ |= BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8;
+ br->avail_in -= 3;
+ br->next_in += 3;
+ }
+ } else {
+ if (br->bit_pos_ >= 16) {
+ br->val_ >>= 16;
+ br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
+ br->val_ |= ((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16;
+ br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ }
+ }
+#endif
+}
+
+/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
+ more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
+static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
+ BrotliFillBitWindow(br, 17);
+}
+
+/* Tries to pull one byte of input to accumulator.
+ Returns BROTLI_FALSE if there is no input available. */
+static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
+ if (br->avail_in == 0) {
+ return BROTLI_FALSE;
+ }
+ br->val_ >>= 8;
+#if (BROTLI_64_BITS)
+ br->val_ |= ((uint64_t)*br->next_in) << 56;
+#else
+ br->val_ |= ((uint32_t)*br->next_in) << 24;
+#endif
+ br->bit_pos_ -= 8;
+ --br->avail_in;
+ ++br->next_in;
+ return BROTLI_TRUE;
+}
+
+/* Returns currently available bits.
+ The number of valid bits could be calculated by BrotliGetAvailableBits. */
+static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
+ BrotliBitReader* const br) {
+ return br->val_ >> br->bit_pos_;
+}
+
+/* Like BrotliGetBits, but does not mask the result.
+ The result contains at least 16 valid bits. */
+static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
+ BrotliBitReader* const br) {
+ BrotliFillBitWindow(br, 16);
+ return (uint32_t)BrotliGetBitsUnmasked(br);
+}
+
+/* Returns the specified number of bits from |br| without advancing bit
+ position. */
+static BROTLI_INLINE uint32_t BrotliGetBits(
+ BrotliBitReader* const br, uint32_t n_bits) {
+ BrotliFillBitWindow(br, n_bits);
+ return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
+}
+
+/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there
+ is not enough input. */
+static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ while (BrotliGetAvailableBits(br) < n_bits) {
+ if (!BrotliPullByte(br)) {
+ return BROTLI_FALSE;
+ }
+ }
+ *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
+ return BROTLI_TRUE;
+}
+
+/* Advances the bit pos by |n_bits|. */
+static BROTLI_INLINE void BrotliDropBits(
+ BrotliBitReader* const br, uint32_t n_bits) {
+ br->bit_pos_ += n_bits;
+}
+
+static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
+ uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
+ uint32_t unused_bits = unused_bytes << 3;
+ br->avail_in += unused_bytes;
+ br->next_in -= unused_bytes;
+ if (unused_bits == sizeof(br->val_) << 3) {
+ br->val_ = 0;
+ } else {
+ br->val_ <<= unused_bits;
+ }
+ br->bit_pos_ += unused_bits;
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Precondition: accumulator MUST contain at least |n_bits|. */
+static BROTLI_INLINE void BrotliTakeBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
+ BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
+ (int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
+ BrotliDropBits(br, n_bits);
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Assumes that there is enough input to perform BrotliFillBitWindow.
+ Up to 24 bits are allowed to be requested from this method. */
+static BROTLI_INLINE uint32_t BrotliReadBits24(
+ BrotliBitReader* const br, uint32_t n_bits) {
+ BROTLI_DCHECK(n_bits <= 24);
+ if (BROTLI_64_BITS || (n_bits <= 16)) {
+ uint32_t val;
+ BrotliFillBitWindow(br, n_bits);
+ BrotliTakeBits(br, n_bits, &val);
+ return val;
+ } else {
+ uint32_t low_val;
+ uint32_t high_val;
+ BrotliFillBitWindow(br, 16);
+ BrotliTakeBits(br, 16, &low_val);
+ BrotliFillBitWindow(br, 8);
+ BrotliTakeBits(br, n_bits - 16, &high_val);
+ return low_val | (high_val << 16);
+ }
+}
+
+/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
+static BROTLI_INLINE uint32_t BrotliReadBits32(
+ BrotliBitReader* const br, uint32_t n_bits) {
+ BROTLI_DCHECK(n_bits <= 32);
+ if (BROTLI_64_BITS || (n_bits <= 16)) {
+ uint32_t val;
+ BrotliFillBitWindow(br, n_bits);
+ BrotliTakeBits(br, n_bits, &val);
+ return val;
+ } else {
+ uint32_t low_val;
+ uint32_t high_val;
+ BrotliFillBitWindow(br, 16);
+ BrotliTakeBits(br, 16, &low_val);
+ BrotliFillBitWindow(br, 16);
+ BrotliTakeBits(br, n_bits - 16, &high_val);
+ return low_val | (high_val << 16);
+ }
+}
+
+/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
+ is not enough input. |n_bits| MUST be positive.
+ Up to 24 bits are allowed to be requested from this method. */
+static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ BROTLI_DCHECK(n_bits <= 24);
+ while (BrotliGetAvailableBits(br) < n_bits) {
+ if (!BrotliPullByte(br)) {
+ return BROTLI_FALSE;
+ }
+ }
+ BrotliTakeBits(br, n_bits, val);
+ return BROTLI_TRUE;
+}
+
+/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
+static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ BROTLI_DCHECK(n_bits <= 32);
+ if (BROTLI_64_BITS || (n_bits <= 24)) {
+ while (BrotliGetAvailableBits(br) < n_bits) {
+ if (!BrotliPullByte(br)) {
+ return BROTLI_FALSE;
+ }
+ }
+ BrotliTakeBits(br, n_bits, val);
+ return BROTLI_TRUE;
+ } else {
+ return BrotliSafeReadBits32Slow(br, n_bits, val);
+ }
+}
+
+/* Advances the bit reader position to the next byte boundary and verifies
+ that any skipped bits are set to zero. */
+static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
+ uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
+ uint32_t pad_bits = 0;
+ if (pad_bits_count != 0) {
+ BrotliTakeBits(br, pad_bits_count, &pad_bits);
+ }
+ return TO_BROTLI_BOOL(pad_bits == 0);
+}
+
+/* Copies remaining input bytes stored in the bit reader to the output. Value
+ |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
+ warmed up again after this. */
+static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
+ BrotliBitReader* br, size_t num) {
+ while (BrotliGetAvailableBits(br) >= 8 && num > 0) {
+ *dest = (uint8_t)BrotliGetBitsUnmasked(br);
+ BrotliDropBits(br, 8);
+ ++dest;
+ --num;
+ }
+ memcpy(dest, br->next_in, num);
+ br->avail_in -= num;
+ br->next_in += num;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_DEC_BIT_READER_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/decode.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/decode.c
new file mode 100644
index 000000000..114c5057d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/decode.c
@@ -0,0 +1,2605 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <brotli/decode.h>
+
+#include <stdlib.h> /* free, malloc */
+#include <string.h> /* memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include "../common/transform.h"
+#include "../common/version.h"
+#include "./bit_reader.h"
+#include "./huffman.h"
+#include "./prefix.h"
+#include "./state.h"
+
+#if defined(BROTLI_TARGET_NEON)
+#include <arm_neon.h>
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BROTLI_FAILURE(CODE) (BROTLI_DUMP(), CODE)
+
+#define BROTLI_LOG_UINT(name) \
+ BROTLI_LOG(("[%s] %s = %lu\n", __func__, #name, (unsigned long)(name)))
+#define BROTLI_LOG_ARRAY_INDEX(array_name, idx) \
+ BROTLI_LOG(("[%s] %s[%lu] = %lu\n", __func__, #array_name, \
+ (unsigned long)(idx), (unsigned long)array_name[idx]))
+
+#define HUFFMAN_TABLE_BITS 8U
+#define HUFFMAN_TABLE_MASK 0xFF
+
+/* We need the slack region for the following reasons:
+ - doing up to two 16-byte copies for fast backward copying
+ - inserting transformed dictionary word:
+ 5 prefix + 24 base + 8 suffix */
+static const uint32_t kRingBufferWriteAheadSlack = 42;
+
+static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = {
+ 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+};
+
+/* Static prefix code for the complex code length code lengths. */
+static const uint8_t kCodeLengthPrefixLength[16] = {
+ 2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4,
+};
+
+static const uint8_t kCodeLengthPrefixValue[16] = {
+ 0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5,
+};
+
+BROTLI_BOOL BrotliDecoderSetParameter(
+ BrotliDecoderState* state, BrotliDecoderParameter p, uint32_t value) {
+ if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE;
+ switch (p) {
+ case BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:
+ state->canny_ringbuffer_allocation = !!value ? 0 : 1;
+ return BROTLI_TRUE;
+
+ case BROTLI_DECODER_PARAM_LARGE_WINDOW:
+ state->large_window = TO_BROTLI_BOOL(!!value);
+ return BROTLI_TRUE;
+
+ default: return BROTLI_FALSE;
+ }
+}
+
+BrotliDecoderState* BrotliDecoderCreateInstance(
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
+ BrotliDecoderState* state = 0;
+ if (!alloc_func && !free_func) {
+ state = (BrotliDecoderState*)malloc(sizeof(BrotliDecoderState));
+ } else if (alloc_func && free_func) {
+ state = (BrotliDecoderState*)alloc_func(opaque, sizeof(BrotliDecoderState));
+ }
+ if (state == 0) {
+ BROTLI_DUMP();
+ return 0;
+ }
+ if (!BrotliDecoderStateInit(state, alloc_func, free_func, opaque)) {
+ BROTLI_DUMP();
+ if (!alloc_func && !free_func) {
+ free(state);
+ } else if (alloc_func && free_func) {
+ free_func(opaque, state);
+ }
+ return 0;
+ }
+ return state;
+}
+
+/* Deinitializes and frees BrotliDecoderState instance. */
+void BrotliDecoderDestroyInstance(BrotliDecoderState* state) {
+ if (!state) {
+ return;
+ } else {
+ brotli_free_func free_func = state->free_func;
+ void* opaque = state->memory_manager_opaque;
+ BrotliDecoderStateCleanup(state);
+ free_func(opaque, state);
+ }
+}
+
+/* Saves error code and converts it to BrotliDecoderResult. */
+static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode(
+ BrotliDecoderState* s, BrotliDecoderErrorCode e) {
+ s->error_code = (int)e;
+ switch (e) {
+ case BROTLI_DECODER_SUCCESS:
+ return BROTLI_DECODER_RESULT_SUCCESS;
+
+ case BROTLI_DECODER_NEEDS_MORE_INPUT:
+ return BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
+
+ case BROTLI_DECODER_NEEDS_MORE_OUTPUT:
+ return BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+
+ default:
+ return BROTLI_DECODER_RESULT_ERROR;
+ }
+}
+
+/* Decodes WBITS by reading 1 - 7 bits, or 0x11 for "Large Window Brotli".
+ Precondition: bit-reader accumulator has at least 8 bits. */
+static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s,
+ BrotliBitReader* br) {
+ uint32_t n;
+ BROTLI_BOOL large_window = s->large_window;
+ s->large_window = BROTLI_FALSE;
+ BrotliTakeBits(br, 1, &n);
+ if (n == 0) {
+ s->window_bits = 16;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ BrotliTakeBits(br, 3, &n);
+ if (n != 0) {
+ s->window_bits = 17 + n;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ BrotliTakeBits(br, 3, &n);
+ if (n == 1) {
+ if (large_window) {
+ BrotliTakeBits(br, 1, &n);
+ if (n == 1) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
+ }
+ s->large_window = BROTLI_TRUE;
+ return BROTLI_DECODER_SUCCESS;
+ } else {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
+ }
+ }
+ if (n != 0) {
+ s->window_bits = 8 + n;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ s->window_bits = 17;
+ return BROTLI_DECODER_SUCCESS;
+}
+
+static BROTLI_INLINE void memmove16(uint8_t* dst, uint8_t* src) {
+#if defined(BROTLI_TARGET_NEON)
+ vst1q_u8(dst, vld1q_u8(src));
+#else
+ uint32_t buffer[4];
+ memcpy(buffer, src, 16);
+ memcpy(dst, buffer, 16);
+#endif
+}
+
+/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */
+static BROTLI_NOINLINE BrotliDecoderErrorCode DecodeVarLenUint8(
+ BrotliDecoderState* s, BrotliBitReader* br, uint32_t* value) {
+ uint32_t bits;
+ switch (s->substate_decode_uint8) {
+ case BROTLI_STATE_DECODE_UINT8_NONE:
+ if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 1, &bits))) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits == 0) {
+ *value = 0;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_DECODE_UINT8_SHORT:
+ if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 3, &bits))) {
+ s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_SHORT;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits == 0) {
+ *value = 1;
+ s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ /* Use output value as a temporary storage. It MUST be persisted. */
+ *value = bits;
+ /* Fall through. */
+
+ case BROTLI_STATE_DECODE_UINT8_LONG:
+ if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, *value, &bits))) {
+ s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_LONG;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ *value = (1U << *value) + bits;
+ s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
+ return BROTLI_DECODER_SUCCESS;
+
+ default:
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE);
+ }
+}
+
+/* Decodes a metablock length and flags by reading 2 - 31 bits. */
+static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
+ BrotliDecoderState* s, BrotliBitReader* br) {
+ uint32_t bits;
+ int i;
+ for (;;) {
+ switch (s->substate_metablock_header) {
+ case BROTLI_STATE_METABLOCK_HEADER_NONE:
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ s->is_last_metablock = bits ? 1 : 0;
+ s->meta_block_remaining_len = 0;
+ s->is_uncompressed = 0;
+ s->is_metadata = 0;
+ if (!s->is_last_metablock) {
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES;
+ break;
+ }
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_EMPTY;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_EMPTY:
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits) {
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_NIBBLES:
+ if (!BrotliSafeReadBits(br, 2, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ s->size_nibbles = (uint8_t)(bits + 4);
+ s->loop_counter = 0;
+ if (bits == 3) {
+ s->is_metadata = 1;
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_RESERVED;
+ break;
+ }
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_SIZE;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_SIZE:
+ i = s->loop_counter;
+ for (; i < (int)s->size_nibbles; ++i) {
+ if (!BrotliSafeReadBits(br, 4, &bits)) {
+ s->loop_counter = i;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 && bits == 0) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
+ }
+ s->meta_block_remaining_len |= (int)(bits << (i * 4));
+ }
+ s->substate_metablock_header =
+ BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED:
+ if (!s->is_last_metablock) {
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ s->is_uncompressed = bits ? 1 : 0;
+ }
+ ++s->meta_block_remaining_len;
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
+ return BROTLI_DECODER_SUCCESS;
+
+ case BROTLI_STATE_METABLOCK_HEADER_RESERVED:
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits != 0) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_RESERVED);
+ }
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_BYTES;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_BYTES:
+ if (!BrotliSafeReadBits(br, 2, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits == 0) {
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+ s->size_nibbles = (uint8_t)bits;
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_METADATA;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER_METADATA:
+ i = s->loop_counter;
+ for (; i < (int)s->size_nibbles; ++i) {
+ if (!BrotliSafeReadBits(br, 8, &bits)) {
+ s->loop_counter = i;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 && bits == 0) {
+ return BROTLI_FAILURE(
+ BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
+ }
+ s->meta_block_remaining_len |= (int)(bits << (i * 8));
+ }
+ ++s->meta_block_remaining_len;
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
+ return BROTLI_DECODER_SUCCESS;
+
+ default:
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE);
+ }
+ }
+}
+
+/* Decodes the Huffman code.
+ This method doesn't read data from the bit reader, BUT drops the amount of
+ bits that correspond to the decoded symbol.
+ bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */
+static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits,
+ const HuffmanCode* table,
+ BrotliBitReader* br) {
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, bits & HUFFMAN_TABLE_MASK);
+ if (BROTLI_HC_FAST_LOAD_BITS(table) > HUFFMAN_TABLE_BITS) {
+ uint32_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS;
+ BrotliDropBits(br, HUFFMAN_TABLE_BITS);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table,
+ BROTLI_HC_FAST_LOAD_VALUE(table) +
+ ((bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits)));
+ }
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
+ return BROTLI_HC_FAST_LOAD_VALUE(table);
+}
+
+/* Reads and decodes the next Huffman code from bit-stream.
+ This method peeks 16 bits of input and drops 0 - 15 of them. */
+static BROTLI_INLINE uint32_t ReadSymbol(const HuffmanCode* table,
+ BrotliBitReader* br) {
+ return DecodeSymbol(BrotliGet16BitsUnmasked(br), table, br);
+}
+
+/* Same as DecodeSymbol, but it is known that there is less than 15 bits of
+ input are currently available. */
+static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol(
+ const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) {
+ uint32_t val;
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ if (available_bits == 0) {
+ if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) {
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
+ return BROTLI_TRUE;
+ }
+ return BROTLI_FALSE; /* No valid bits at all. */
+ }
+ val = (uint32_t)BrotliGetBitsUnmasked(br);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK);
+ if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) {
+ if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) {
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
+ return BROTLI_TRUE;
+ } else {
+ return BROTLI_FALSE; /* Not enough bits for the first level. */
+ }
+ }
+ if (available_bits <= HUFFMAN_TABLE_BITS) {
+ return BROTLI_FALSE; /* Not enough bits to move to the second level. */
+ }
+
+ /* Speculatively drop HUFFMAN_TABLE_BITS. */
+ val = (val & BitMask(BROTLI_HC_FAST_LOAD_BITS(table))) >> HUFFMAN_TABLE_BITS;
+ available_bits -= HUFFMAN_TABLE_BITS;
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + val);
+ if (available_bits < BROTLI_HC_FAST_LOAD_BITS(table)) {
+ return BROTLI_FALSE; /* Not enough bits for the second level. */
+ }
+
+ BrotliDropBits(br, HUFFMAN_TABLE_BITS + BROTLI_HC_FAST_LOAD_BITS(table));
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
+ return BROTLI_TRUE;
+}
+
+static BROTLI_INLINE BROTLI_BOOL SafeReadSymbol(
+ const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) {
+ uint32_t val;
+ if (BROTLI_PREDICT_TRUE(BrotliSafeGetBits(br, 15, &val))) {
+ *result = DecodeSymbol(val, table, br);
+ return BROTLI_TRUE;
+ }
+ return SafeDecodeSymbol(table, br, result);
+}
+
+/* Makes a look-up in first level Huffman table. Peeks 8 bits. */
+static BROTLI_INLINE void PreloadSymbol(int safe,
+ const HuffmanCode* table,
+ BrotliBitReader* br,
+ uint32_t* bits,
+ uint32_t* value) {
+ if (safe) {
+ return;
+ }
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, BrotliGetBits(br, HUFFMAN_TABLE_BITS));
+ *bits = BROTLI_HC_FAST_LOAD_BITS(table);
+ *value = BROTLI_HC_FAST_LOAD_VALUE(table);
+}
+
+/* Decodes the next Huffman code using data prepared by PreloadSymbol.
+ Reads 0 - 15 bits. Also peeks 8 following bits. */
+static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table,
+ BrotliBitReader* br,
+ uint32_t* bits,
+ uint32_t* value) {
+ uint32_t result = *value;
+ if (BROTLI_PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) {
+ uint32_t val = BrotliGet16BitsUnmasked(br);
+ const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
+ uint32_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS));
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext);
+ BrotliDropBits(br, HUFFMAN_TABLE_BITS);
+ BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask);
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(ext));
+ result = BROTLI_HC_FAST_LOAD_VALUE(ext);
+ } else {
+ BrotliDropBits(br, *bits);
+ }
+ PreloadSymbol(0, table, br, bits, value);
+ return result;
+}
+
+static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) {
+ uint32_t result = 0;
+ while (x) {
+ x >>= 1;
+ ++result;
+ }
+ return result;
+}
+
+/* Reads (s->symbol + 1) symbols.
+ Totally 1..4 symbols are read, 1..11 bits each.
+ The list of symbols MUST NOT contain duplicates. */
+static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
+ uint32_t alphabet_size_max, uint32_t alphabet_size_limit,
+ BrotliDecoderState* s) {
+ /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
+ BrotliBitReader* br = &s->br;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ uint32_t max_bits = Log2Floor(alphabet_size_max - 1);
+ uint32_t i = h->sub_loop_counter;
+ uint32_t num_symbols = h->symbol;
+ while (i <= num_symbols) {
+ uint32_t v;
+ if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
+ h->sub_loop_counter = i;
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (v >= alphabet_size_limit) {
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
+ }
+ h->symbols_lists_array[i] = (uint16_t)v;
+ BROTLI_LOG_UINT(h->symbols_lists_array[i]);
+ ++i;
+ }
+
+ for (i = 0; i < num_symbols; ++i) {
+ uint32_t k = i + 1;
+ for (; k <= num_symbols; ++k) {
+ if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
+ }
+ }
+ }
+
+ return BROTLI_DECODER_SUCCESS;
+}
+
+/* Process single decoded symbol code length:
+ A) reset the repeat variable
+ B) remember code length (if it is not 0)
+ C) extend corresponding index-chain
+ D) reduce the Huffman space
+ E) update the histogram */
+static BROTLI_INLINE void ProcessSingleCodeLength(uint32_t code_len,
+ uint32_t* symbol, uint32_t* repeat, uint32_t* space,
+ uint32_t* prev_code_len, uint16_t* symbol_lists,
+ uint16_t* code_length_histo, int* next_symbol) {
+ *repeat = 0;
+ if (code_len != 0) { /* code_len == 1..15 */
+ symbol_lists[next_symbol[code_len]] = (uint16_t)(*symbol);
+ next_symbol[code_len] = (int)(*symbol);
+ *prev_code_len = code_len;
+ *space -= 32768U >> code_len;
+ code_length_histo[code_len]++;
+ BROTLI_LOG(("[ReadHuffmanCode] code_length[%d] = %d\n",
+ (int)*symbol, (int)code_len));
+ }
+ (*symbol)++;
+}
+
+/* Process repeated symbol code length.
+ A) Check if it is the extension of previous repeat sequence; if the decoded
+ value is not BROTLI_REPEAT_PREVIOUS_CODE_LENGTH, then it is a new
+ symbol-skip
+ B) Update repeat variable
+ C) Check if operation is feasible (fits alphabet)
+ D) For each symbol do the same operations as in ProcessSingleCodeLength
+
+ PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or
+ code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */
+static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
+ uint32_t repeat_delta, uint32_t alphabet_size, uint32_t* symbol,
+ uint32_t* repeat, uint32_t* space, uint32_t* prev_code_len,
+ uint32_t* repeat_code_len, uint16_t* symbol_lists,
+ uint16_t* code_length_histo, int* next_symbol) {
+ uint32_t old_repeat;
+ uint32_t extra_bits = 3; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */
+ uint32_t new_len = 0; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */
+ if (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
+ new_len = *prev_code_len;
+ extra_bits = 2;
+ }
+ if (*repeat_code_len != new_len) {
+ *repeat = 0;
+ *repeat_code_len = new_len;
+ }
+ old_repeat = *repeat;
+ if (*repeat > 0) {
+ *repeat -= 2;
+ *repeat <<= extra_bits;
+ }
+ *repeat += repeat_delta + 3U;
+ repeat_delta = *repeat - old_repeat;
+ if (*symbol + repeat_delta > alphabet_size) {
+ BROTLI_DUMP();
+ *symbol = alphabet_size;
+ *space = 0xFFFFF;
+ return;
+ }
+ BROTLI_LOG(("[ReadHuffmanCode] code_length[%d..%d] = %d\n",
+ (int)*symbol, (int)(*symbol + repeat_delta - 1), (int)*repeat_code_len));
+ if (*repeat_code_len != 0) {
+ unsigned last = *symbol + repeat_delta;
+ int next = next_symbol[*repeat_code_len];
+ do {
+ symbol_lists[next] = (uint16_t)*symbol;
+ next = (int)*symbol;
+ } while (++(*symbol) != last);
+ next_symbol[*repeat_code_len] = next;
+ *space -= repeat_delta << (15 - *repeat_code_len);
+ code_length_histo[*repeat_code_len] =
+ (uint16_t)(code_length_histo[*repeat_code_len] + repeat_delta);
+ } else {
+ *symbol += repeat_delta;
+ }
+}
+
+/* Reads and decodes symbol codelengths. */
+static BrotliDecoderErrorCode ReadSymbolCodeLengths(
+ uint32_t alphabet_size, BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ uint32_t symbol = h->symbol;
+ uint32_t repeat = h->repeat;
+ uint32_t space = h->space;
+ uint32_t prev_code_len = h->prev_code_len;
+ uint32_t repeat_code_len = h->repeat_code_len;
+ uint16_t* symbol_lists = h->symbol_lists;
+ uint16_t* code_length_histo = h->code_length_histo;
+ int* next_symbol = h->next_symbol;
+ if (!BrotliWarmupBitReader(br)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ while (symbol < alphabet_size && space > 0) {
+ const HuffmanCode* p = h->table;
+ uint32_t code_len;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
+ if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
+ h->symbol = symbol;
+ h->repeat = repeat;
+ h->prev_code_len = prev_code_len;
+ h->repeat_code_len = repeat_code_len;
+ h->space = space;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ BrotliFillBitWindow16(br);
+ BROTLI_HC_ADJUST_TABLE_INDEX(p, BrotliGetBitsUnmasked(br) &
+ BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); /* Use 1..5 bits. */
+ code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
+ if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
+ ProcessSingleCodeLength(code_len, &symbol, &repeat, &space,
+ &prev_code_len, symbol_lists, code_length_histo, next_symbol);
+ } else { /* code_len == 16..17, extra_bits == 2..3 */
+ uint32_t extra_bits =
+ (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) ? 2 : 3;
+ uint32_t repeat_delta =
+ (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(extra_bits);
+ BrotliDropBits(br, extra_bits);
+ ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
+ &symbol, &repeat, &space, &prev_code_len, &repeat_code_len,
+ symbol_lists, code_length_histo, next_symbol);
+ }
+ }
+ h->space = space;
+ return BROTLI_DECODER_SUCCESS;
+}
+
+static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
+ uint32_t alphabet_size, BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ BROTLI_BOOL get_byte = BROTLI_FALSE;
+ while (h->symbol < alphabet_size && h->space > 0) {
+ const HuffmanCode* p = h->table;
+ uint32_t code_len;
+ uint32_t available_bits;
+ uint32_t bits = 0;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
+ if (get_byte && !BrotliPullByte(br)) return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ get_byte = BROTLI_FALSE;
+ available_bits = BrotliGetAvailableBits(br);
+ if (available_bits != 0) {
+ bits = (uint32_t)BrotliGetBitsUnmasked(br);
+ }
+ BROTLI_HC_ADJUST_TABLE_INDEX(p,
+ bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
+ if (BROTLI_HC_FAST_LOAD_BITS(p) > available_bits) {
+ get_byte = BROTLI_TRUE;
+ continue;
+ }
+ code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
+ if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
+ ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space,
+ &h->prev_code_len, h->symbol_lists, h->code_length_histo,
+ h->next_symbol);
+ } else { /* code_len == 16..17, extra_bits == 2..3 */
+ uint32_t extra_bits = code_len - 14U;
+ uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
+ BitMask(extra_bits);
+ if (available_bits < BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits) {
+ get_byte = BROTLI_TRUE;
+ continue;
+ }
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
+ ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
+ &h->symbol, &h->repeat, &h->space, &h->prev_code_len,
+ &h->repeat_code_len, h->symbol_lists, h->code_length_histo,
+ h->next_symbol);
+ }
+ }
+ return BROTLI_DECODER_SUCCESS;
+}
+
+/* Reads and decodes 15..18 codes using static prefix code.
+ Each code is 2..4 bits long. In total 30..72 bits are used. */
+static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ uint32_t num_codes = h->repeat;
+ unsigned space = h->space;
+ uint32_t i = h->sub_loop_counter;
+ for (; i < BROTLI_CODE_LENGTH_CODES; ++i) {
+ const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
+ uint32_t ix;
+ uint32_t v;
+ if (BROTLI_PREDICT_FALSE(!BrotliSafeGetBits(br, 4, &ix))) {
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ if (available_bits != 0) {
+ ix = BrotliGetBitsUnmasked(br) & 0xF;
+ } else {
+ ix = 0;
+ }
+ if (kCodeLengthPrefixLength[ix] > available_bits) {
+ h->sub_loop_counter = i;
+ h->repeat = num_codes;
+ h->space = space;
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ }
+ v = kCodeLengthPrefixValue[ix];
+ BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
+ h->code_length_code_lengths[code_len_idx] = (uint8_t)v;
+ BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx);
+ if (v != 0) {
+ space = space - (32U >> v);
+ ++num_codes;
+ ++h->code_length_histo[v];
+ if (space - 1U >= 32U) {
+ /* space is 0 or wrapped around. */
+ break;
+ }
+ }
+ }
+ if (!(num_codes == 1 || space == 0)) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
+ }
+ return BROTLI_DECODER_SUCCESS;
+}
+
+/* Decodes the Huffman tables.
+ There are 2 scenarios:
+ A) Huffman code contains only few symbols (1..4). Those symbols are read
+ directly; their code lengths are defined by the number of symbols.
+ For this scenario 4 - 49 bits will be read.
+
+ B) 2-phase decoding:
+ B.1) Small Huffman table is decoded; it is specified with code lengths
+ encoded with predefined entropy code. 32 - 74 bits are used.
+ B.2) Decoded table is used to decode code lengths of symbols in resulting
+ Huffman table. In worst case 3520 bits are read. */
+static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max,
+ uint32_t alphabet_size_limit,
+ HuffmanCode* table,
+ uint32_t* opt_table_size,
+ BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ /* State machine. */
+ for (;;) {
+ switch (h->substate_huffman) {
+ case BROTLI_STATE_HUFFMAN_NONE:
+ if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ BROTLI_LOG_UINT(h->sub_loop_counter);
+ /* The value is used as follows:
+ 1 for simple code;
+ 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
+ if (h->sub_loop_counter != 1) {
+ h->space = 32;
+ h->repeat = 0; /* num_codes */
+ memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) *
+ (BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
+ memset(&h->code_length_code_lengths[0], 0,
+ sizeof(h->code_length_code_lengths));
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+ continue;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
+ /* Read symbols, codes & code lengths directly. */
+ if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ h->sub_loop_counter = 0;
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
+ BrotliDecoderErrorCode result =
+ ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
+ }
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
+ uint32_t table_size;
+ if (h->symbol == 3) {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ h->symbol += bits;
+ }
+ BROTLI_LOG_UINT(h->symbol);
+ table_size = BrotliBuildSimpleHuffmanTable(
+ table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol);
+ if (opt_table_size) {
+ *opt_table_size = table_size;
+ }
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+
+ /* Decode Huffman-coded code lengths. */
+ case BROTLI_STATE_HUFFMAN_COMPLEX: {
+ uint32_t i;
+ BrotliDecoderErrorCode result = ReadCodeLengthCodeLengths(s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
+ }
+ BrotliBuildCodeLengthsHuffmanTable(h->table,
+ h->code_length_code_lengths,
+ h->code_length_histo);
+ memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo));
+ for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
+ h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
+ h->symbol_lists[h->next_symbol[i]] = 0xFFFF;
+ }
+
+ h->symbol = 0;
+ h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
+ h->repeat = 0;
+ h->repeat_code_len = 0;
+ h->space = 32768;
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
+ uint32_t table_size;
+ BrotliDecoderErrorCode result = ReadSymbolCodeLengths(
+ alphabet_size_limit, s);
+ if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
+ result = SafeReadSymbolCodeLengths(alphabet_size_limit, s);
+ }
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
+ }
+
+ if (h->space != 0) {
+ BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space));
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
+ }
+ table_size = BrotliBuildHuffmanTable(
+ table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo);
+ if (opt_table_size) {
+ *opt_table_size = table_size;
+ }
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+
+ default:
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE);
+ }
+ }
+}
+
+/* Decodes a block length by reading 3..39 bits. */
+static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table,
+ BrotliBitReader* br) {
+ uint32_t code;
+ uint32_t nbits;
+ code = ReadSymbol(table, br);
+ nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */
+ return kBlockLengthPrefixCode[code].offset + BrotliReadBits24(br, nbits);
+}
+
+/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
+ reading can't be continued with ReadBlockLength. */
+static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength(
+ BrotliDecoderState* s, uint32_t* result, const HuffmanCode* table,
+ BrotliBitReader* br) {
+ uint32_t index;
+ if (s->substate_read_block_length == BROTLI_STATE_READ_BLOCK_LENGTH_NONE) {
+ if (!SafeReadSymbol(table, br, &index)) {
+ return BROTLI_FALSE;
+ }
+ } else {
+ index = s->block_length_index;
+ }
+ {
+ uint32_t bits;
+ uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */
+ if (!BrotliSafeReadBits(br, nbits, &bits)) {
+ s->block_length_index = index;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
+ return BROTLI_FALSE;
+ }
+ *result = kBlockLengthPrefixCode[index].offset + bits;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+ return BROTLI_TRUE;
+ }
+}
+
+/* Transform:
+ 1) initialize list L with values 0, 1,... 255
+ 2) For each input element X:
+ 2.1) let Y = L[X]
+ 2.2) remove X-th element from L
+ 2.3) prepend Y to L
+ 2.4) append Y to output
+
+ In most cases max(Y) <= 7, so most of L remains intact.
+ To reduce the cost of initialization, we reuse L, remember the upper bound
+ of Y values, and reinitialize only first elements in L.
+
+ Most of input values are 0 and 1. To reduce number of branches, we replace
+ inner for loop with do-while. */
+static BROTLI_NOINLINE void InverseMoveToFrontTransform(
+ uint8_t* v, uint32_t v_len, BrotliDecoderState* state) {
+ /* Reinitialize elements that could have been changed. */
+ uint32_t i = 1;
+ uint32_t upper_bound = state->mtf_upper_bound;
+ uint32_t* mtf = &state->mtf[1]; /* Make mtf[-1] addressable. */
+ uint8_t* mtf_u8 = (uint8_t*)mtf;
+ /* Load endian-aware constant. */
+ const uint8_t b0123[4] = {0, 1, 2, 3};
+ uint32_t pattern;
+ memcpy(&pattern, &b0123, 4);
+
+ /* Initialize list using 4 consequent values pattern. */
+ mtf[0] = pattern;
+ do {
+ pattern += 0x04040404; /* Advance all 4 values by 4. */
+ mtf[i] = pattern;
+ i++;
+ } while (i <= upper_bound);
+
+ /* Transform the input. */
+ upper_bound = 0;
+ for (i = 0; i < v_len; ++i) {
+ int index = v[i];
+ uint8_t value = mtf_u8[index];
+ upper_bound |= v[i];
+ v[i] = value;
+ mtf_u8[-1] = value;
+ do {
+ index--;
+ mtf_u8[index + 1] = mtf_u8[index];
+ } while (index >= 0);
+ }
+ /* Remember amount of elements to be reinitialized. */
+ state->mtf_upper_bound = upper_bound >> 2;
+}
+
+/* Decodes a series of Huffman table using ReadHuffmanCode function. */
+static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
+ HuffmanTreeGroup* group, BrotliDecoderState* s) {
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
+ h->next = group->codes;
+ h->htree_index = 0;
+ h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
+ }
+ while (h->htree_index < group->num_htrees) {
+ uint32_t table_size;
+ BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
+ group->alphabet_size_limit, h->next, &table_size, s);
+ if (result != BROTLI_DECODER_SUCCESS) return result;
+ group->htrees[h->htree_index] = h->next;
+ h->next += table_size;
+ ++h->htree_index;
+ }
+ h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
+ return BROTLI_DECODER_SUCCESS;
+}
+
+/* Decodes a context map.
+ Decoding is done in 4 phases:
+ 1) Read auxiliary information (6..16 bits) and allocate memory.
+ In case of trivial context map, decoding is finished at this phase.
+ 2) Decode Huffman table using ReadHuffmanCode function.
+ This table will be used for reading context map items.
+ 3) Read context map items; "0" values could be run-length encoded.
+ 4) Optionally, apply InverseMoveToFront transform to the resulting map. */
+static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
+ uint32_t* num_htrees,
+ uint8_t** context_map_arg,
+ BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+
+ switch ((int)h->substate_context_map) {
+ case BROTLI_STATE_CONTEXT_MAP_NONE:
+ result = DecodeVarLenUint8(s, br, num_htrees);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
+ }
+ (*num_htrees)++;
+ h->context_index = 0;
+ BROTLI_LOG_UINT(context_map_size);
+ BROTLI_LOG_UINT(*num_htrees);
+ *context_map_arg =
+ (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)context_map_size);
+ if (*context_map_arg == 0) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
+ }
+ if (*num_htrees <= 1) {
+ memset(*context_map_arg, 0, (size_t)context_map_size);
+ return BROTLI_DECODER_SUCCESS;
+ }
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
+ uint32_t bits;
+ /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe
+ to peek 4 bits ahead. */
+ if (!BrotliSafeGetBits(br, 5, &bits)) {
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if ((bits & 1) != 0) { /* Use RLE for zeros. */
+ h->max_run_length_prefix = (bits >> 1) + 1;
+ BrotliDropBits(br, 5);
+ } else {
+ h->max_run_length_prefix = 0;
+ BrotliDropBits(br, 1);
+ }
+ BROTLI_LOG_UINT(h->max_run_length_prefix);
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
+ uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix;
+ result = ReadHuffmanCode(alphabet_size, alphabet_size,
+ h->context_map_table, NULL, s);
+ if (result != BROTLI_DECODER_SUCCESS) return result;
+ h->code = 0xFFFF;
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_DECODE: {
+ uint32_t context_index = h->context_index;
+ uint32_t max_run_length_prefix = h->max_run_length_prefix;
+ uint8_t* context_map = *context_map_arg;
+ uint32_t code = h->code;
+ BROTLI_BOOL skip_preamble = (code != 0xFFFF);
+ while (context_index < context_map_size || skip_preamble) {
+ if (!skip_preamble) {
+ if (!SafeReadSymbol(h->context_map_table, br, &code)) {
+ h->code = 0xFFFF;
+ h->context_index = context_index;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ BROTLI_LOG_UINT(code);
+
+ if (code == 0) {
+ context_map[context_index++] = 0;
+ continue;
+ }
+ if (code > max_run_length_prefix) {
+ context_map[context_index++] =
+ (uint8_t)(code - max_run_length_prefix);
+ continue;
+ }
+ } else {
+ skip_preamble = BROTLI_FALSE;
+ }
+ /* RLE sub-stage. */
+ {
+ uint32_t reps;
+ if (!BrotliSafeReadBits(br, code, &reps)) {
+ h->code = code;
+ h->context_index = context_index;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ reps += 1U << code;
+ BROTLI_LOG_UINT(reps);
+ if (context_index + reps > context_map_size) {
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
+ }
+ do {
+ context_map[context_index++] = 0;
+ } while (--reps);
+ }
+ }
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ if (bits != 0) {
+ InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
+ }
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
+ return BROTLI_DECODER_SUCCESS;
+ }
+
+ default:
+ return
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE);
+ }
+}
+
+/* Decodes a command or literal and updates block type ring-buffer.
+ Reads 3..54 bits. */
+static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
+ int safe, BrotliDecoderState* s, int tree_type) {
+ uint32_t max_block_type = s->num_block_types[tree_type];
+ const HuffmanCode* type_tree = &s->block_type_trees[
+ tree_type * BROTLI_HUFFMAN_MAX_SIZE_258];
+ const HuffmanCode* len_tree = &s->block_len_trees[
+ tree_type * BROTLI_HUFFMAN_MAX_SIZE_26];
+ BrotliBitReader* br = &s->br;
+ uint32_t* ringbuffer = &s->block_type_rb[tree_type * 2];
+ uint32_t block_type;
+ if (max_block_type <= 1) {
+ return BROTLI_FALSE;
+ }
+
+ /* Read 0..15 + 3..39 bits. */
+ if (!safe) {
+ block_type = ReadSymbol(type_tree, br);
+ s->block_length[tree_type] = ReadBlockLength(len_tree, br);
+ } else {
+ BrotliBitReaderState memento;
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(type_tree, br, &block_type)) return BROTLI_FALSE;
+ if (!SafeReadBlockLength(s, &s->block_length[tree_type], len_tree, br)) {
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+ BrotliBitReaderRestoreState(br, &memento);
+ return BROTLI_FALSE;
+ }
+ }
+
+ if (block_type == 1) {
+ block_type = ringbuffer[1] + 1;
+ } else if (block_type == 0) {
+ block_type = ringbuffer[0];
+ } else {
+ block_type -= 2;
+ }
+ if (block_type >= max_block_type) {
+ block_type -= max_block_type;
+ }
+ ringbuffer[0] = ringbuffer[1];
+ ringbuffer[1] = block_type;
+ return BROTLI_TRUE;
+}
+
+static BROTLI_INLINE void DetectTrivialLiteralBlockTypes(
+ BrotliDecoderState* s) {
+ size_t i;
+ for (i = 0; i < 8; ++i) s->trivial_literal_contexts[i] = 0;
+ for (i = 0; i < s->num_block_types[0]; i++) {
+ size_t offset = i << BROTLI_LITERAL_CONTEXT_BITS;
+ size_t error = 0;
+ size_t sample = s->context_map[offset];
+ size_t j;
+ for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS);) {
+ BROTLI_REPEAT(4, error |= s->context_map[offset + j++] ^ sample;)
+ }
+ if (error == 0) {
+ s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31);
+ }
+ }
+}
+
+static BROTLI_INLINE void PrepareLiteralDecoding(BrotliDecoderState* s) {
+ uint8_t context_mode;
+ size_t trivial;
+ uint32_t block_type = s->block_type_rb[1];
+ uint32_t context_offset = block_type << BROTLI_LITERAL_CONTEXT_BITS;
+ s->context_map_slice = s->context_map + context_offset;
+ trivial = s->trivial_literal_contexts[block_type >> 5];
+ s->trivial_literal_context = (trivial >> (block_type & 31)) & 1;
+ s->literal_htree = s->literal_hgroup.htrees[s->context_map_slice[0]];
+ context_mode = s->context_modes[block_type] & 3;
+ s->context_lookup = BROTLI_CONTEXT_LUT(context_mode);
+}
+
+/* Decodes the block type and updates the state for literal context.
+ Reads 3..54 bits. */
+static BROTLI_INLINE BROTLI_BOOL DecodeLiteralBlockSwitchInternal(
+ int safe, BrotliDecoderState* s) {
+ if (!DecodeBlockTypeAndLength(safe, s, 0)) {
+ return BROTLI_FALSE;
+ }
+ PrepareLiteralDecoding(s);
+ return BROTLI_TRUE;
+}
+
+static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
+ DecodeLiteralBlockSwitchInternal(0, s);
+}
+
+static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch(
+ BrotliDecoderState* s) {
+ return DecodeLiteralBlockSwitchInternal(1, s);
+}
+
+/* Block switch for insert/copy length.
+ Reads 3..54 bits. */
+static BROTLI_INLINE BROTLI_BOOL DecodeCommandBlockSwitchInternal(
+ int safe, BrotliDecoderState* s) {
+ if (!DecodeBlockTypeAndLength(safe, s, 1)) {
+ return BROTLI_FALSE;
+ }
+ s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
+ return BROTLI_TRUE;
+}
+
+static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s) {
+ DecodeCommandBlockSwitchInternal(0, s);
+}
+
+static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeCommandBlockSwitch(
+ BrotliDecoderState* s) {
+ return DecodeCommandBlockSwitchInternal(1, s);
+}
+
+/* Block switch for distance codes.
+ Reads 3..54 bits. */
+static BROTLI_INLINE BROTLI_BOOL DecodeDistanceBlockSwitchInternal(
+ int safe, BrotliDecoderState* s) {
+ if (!DecodeBlockTypeAndLength(safe, s, 2)) {
+ return BROTLI_FALSE;
+ }
+ s->dist_context_map_slice = s->dist_context_map +
+ (s->block_type_rb[5] << BROTLI_DISTANCE_CONTEXT_BITS);
+ s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+ return BROTLI_TRUE;
+}
+
+static void BROTLI_NOINLINE DecodeDistanceBlockSwitch(BrotliDecoderState* s) {
+ DecodeDistanceBlockSwitchInternal(0, s);
+}
+
+static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeDistanceBlockSwitch(
+ BrotliDecoderState* s) {
+ return DecodeDistanceBlockSwitchInternal(1, s);
+}
+
+static size_t UnwrittenBytes(const BrotliDecoderState* s, BROTLI_BOOL wrap) {
+ size_t pos = wrap && s->pos > s->ringbuffer_size ?
+ (size_t)s->ringbuffer_size : (size_t)(s->pos);
+ size_t partial_pos_rb = (s->rb_roundtrips * (size_t)s->ringbuffer_size) + pos;
+ return partial_pos_rb - s->partial_pos_out;
+}
+
+/* Dumps output.
+ Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push
+ and either ring-buffer is as big as window size, or |force| is true. */
+static BrotliDecoderErrorCode BROTLI_NOINLINE WriteRingBuffer(
+ BrotliDecoderState* s, size_t* available_out, uint8_t** next_out,
+ size_t* total_out, BROTLI_BOOL force) {
+ uint8_t* start =
+ s->ringbuffer + (s->partial_pos_out & (size_t)s->ringbuffer_mask);
+ size_t to_write = UnwrittenBytes(s, BROTLI_TRUE);
+ size_t num_written = *available_out;
+ if (num_written > to_write) {
+ num_written = to_write;
+ }
+ if (s->meta_block_remaining_len < 0) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
+ }
+ if (next_out && !*next_out) {
+ *next_out = start;
+ } else {
+ if (next_out) {
+ memcpy(*next_out, start, num_written);
+ *next_out += num_written;
+ }
+ }
+ *available_out -= num_written;
+ BROTLI_LOG_UINT(to_write);
+ BROTLI_LOG_UINT(num_written);
+ s->partial_pos_out += num_written;
+ if (total_out) {
+ *total_out = s->partial_pos_out;
+ }
+ if (num_written < to_write) {
+ if (s->ringbuffer_size == (1 << s->window_bits) || force) {
+ return BROTLI_DECODER_NEEDS_MORE_OUTPUT;
+ } else {
+ return BROTLI_DECODER_SUCCESS;
+ }
+ }
+ /* Wrap ring buffer only if it has reached its maximal size. */
+ if (s->ringbuffer_size == (1 << s->window_bits) &&
+ s->pos >= s->ringbuffer_size) {
+ s->pos -= s->ringbuffer_size;
+ s->rb_roundtrips++;
+ s->should_wrap_ringbuffer = (size_t)s->pos != 0 ? 1 : 0;
+ }
+ return BROTLI_DECODER_SUCCESS;
+}
+
+static void BROTLI_NOINLINE WrapRingBuffer(BrotliDecoderState* s) {
+ if (s->should_wrap_ringbuffer) {
+ memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)s->pos);
+ s->should_wrap_ringbuffer = 0;
+ }
+}
+
+/* Allocates ring-buffer.
+
+ s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before
+ this function is called.
+
+ Last two bytes of ring-buffer are initialized to 0, so context calculation
+ could be done uniformly for the first two and all other positions. */
+static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer(
+ BrotliDecoderState* s) {
+ uint8_t* old_ringbuffer = s->ringbuffer;
+ if (s->ringbuffer_size == s->new_ringbuffer_size) {
+ return BROTLI_TRUE;
+ }
+
+ s->ringbuffer = (uint8_t*)BROTLI_DECODER_ALLOC(s,
+ (size_t)(s->new_ringbuffer_size) + kRingBufferWriteAheadSlack);
+ if (s->ringbuffer == 0) {
+ /* Restore previous value. */
+ s->ringbuffer = old_ringbuffer;
+ return BROTLI_FALSE;
+ }
+ s->ringbuffer[s->new_ringbuffer_size - 2] = 0;
+ s->ringbuffer[s->new_ringbuffer_size - 1] = 0;
+
+ if (!!old_ringbuffer) {
+ memcpy(s->ringbuffer, old_ringbuffer, (size_t)s->pos);
+ BROTLI_DECODER_FREE(s, old_ringbuffer);
+ }
+
+ s->ringbuffer_size = s->new_ringbuffer_size;
+ s->ringbuffer_mask = s->new_ringbuffer_size - 1;
+ s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size;
+
+ return BROTLI_TRUE;
+}
+
+static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
+ size_t* available_out, uint8_t** next_out, size_t* total_out,
+ BrotliDecoderState* s) {
+ /* TODO: avoid allocation for single uncompressed block. */
+ if (!BrotliEnsureRingBuffer(s)) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
+ }
+
+ /* State machine */
+ for (;;) {
+ switch (s->substate_uncompressed) {
+ case BROTLI_STATE_UNCOMPRESSED_NONE: {
+ int nbytes = (int)BrotliGetRemainingBytes(&s->br);
+ if (nbytes > s->meta_block_remaining_len) {
+ nbytes = s->meta_block_remaining_len;
+ }
+ if (s->pos + nbytes > s->ringbuffer_size) {
+ nbytes = s->ringbuffer_size - s->pos;
+ }
+ /* Copy remaining bytes from s->br.buf_ to ring-buffer. */
+ BrotliCopyBytes(&s->ringbuffer[s->pos], &s->br, (size_t)nbytes);
+ s->pos += nbytes;
+ s->meta_block_remaining_len -= nbytes;
+ if (s->pos < 1 << s->window_bits) {
+ if (s->meta_block_remaining_len == 0) {
+ return BROTLI_DECODER_SUCCESS;
+ }
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_UNCOMPRESSED_WRITE: {
+ BrotliDecoderErrorCode result;
+ result = WriteRingBuffer(
+ s, available_out, next_out, total_out, BROTLI_FALSE);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ return result;
+ }
+ if (s->ringbuffer_size == 1 << s->window_bits) {
+ s->max_distance = s->max_backward_distance;
+ }
+ s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
+ break;
+ }
+ }
+ }
+ BROTLI_DCHECK(0); /* Unreachable */
+}
+
+/* Calculates the smallest feasible ring buffer.
+
+ If we know the data size is small, do not allocate more ring buffer
+ size than needed to reduce memory usage.
+
+ When this method is called, metablock size and flags MUST be decoded. */
+static void BROTLI_NOINLINE BrotliCalculateRingBufferSize(
+ BrotliDecoderState* s) {
+ int window_size = 1 << s->window_bits;
+ int new_ringbuffer_size = window_size;
+ /* We need at least 2 bytes of ring buffer size to get the last two
+ bytes for context from there */
+ int min_size = s->ringbuffer_size ? s->ringbuffer_size : 1024;
+ int output_size;
+
+ /* If maximum is already reached, no further extension is retired. */
+ if (s->ringbuffer_size == window_size) {
+ return;
+ }
+
+ /* Metadata blocks does not touch ring buffer. */
+ if (s->is_metadata) {
+ return;
+ }
+
+ if (!s->ringbuffer) {
+ output_size = 0;
+ } else {
+ output_size = s->pos;
+ }
+ output_size += s->meta_block_remaining_len;
+ min_size = min_size < output_size ? output_size : min_size;
+
+ if (!!s->canny_ringbuffer_allocation) {
+ /* Reduce ring buffer size to save memory when server is unscrupulous.
+ In worst case memory usage might be 1.5x bigger for a short period of
+ ring buffer reallocation. */
+ while ((new_ringbuffer_size >> 1) >= min_size) {
+ new_ringbuffer_size >>= 1;
+ }
+ }
+
+ s->new_ringbuffer_size = new_ringbuffer_size;
+}
+
+/* Reads 1..256 2-bit context modes. */
+static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) {
+ BrotliBitReader* br = &s->br;
+ int i = s->loop_counter;
+
+ while (i < (int)s->num_block_types[0]) {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 2, &bits)) {
+ s->loop_counter = i;
+ return BROTLI_DECODER_NEEDS_MORE_INPUT;
+ }
+ s->context_modes[i] = (uint8_t)bits;
+ BROTLI_LOG_ARRAY_INDEX(s->context_modes, i);
+ i++;
+ }
+ return BROTLI_DECODER_SUCCESS;
+}
+
+static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) {
+ int offset = s->distance_code - 3;
+ if (s->distance_code <= 3) {
+ /* Compensate double distance-ring-buffer roll for dictionary items. */
+ s->distance_context = 1 >> s->distance_code;
+ s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
+ s->dist_rb_idx -= s->distance_context;
+ } else {
+ int index_delta = 3;
+ int delta;
+ int base = s->distance_code - 10;
+ if (s->distance_code < 10) {
+ base = s->distance_code - 4;
+ } else {
+ index_delta = 2;
+ }
+ /* Unpack one of six 4-bit values. */
+ delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
+ s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta;
+ if (s->distance_code <= 0) {
+ /* A huge distance will cause a BROTLI_FAILURE() soon.
+ This is a little faster than failing here. */
+ s->distance_code = 0x7FFFFFFF;
+ }
+ }
+}
+
+static BROTLI_INLINE BROTLI_BOOL SafeReadBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ if (n_bits != 0) {
+ return BrotliSafeReadBits(br, n_bits, val);
+ } else {
+ *val = 0;
+ return BROTLI_TRUE;
+ }
+}
+
+static BROTLI_INLINE BROTLI_BOOL SafeReadBits32(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ if (n_bits != 0) {
+ return BrotliSafeReadBits32(br, n_bits, val);
+ } else {
+ *val = 0;
+ return BROTLI_TRUE;
+ }
+}
+
+/*
+ RFC 7932 Section 4 with "..." shortenings and "[]" emendations.
+
+ Each distance ... is represented with a pair <distance code, extra bits>...
+ The distance code is encoded using a prefix code... The number of extra bits
+ can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ...
+ NDIRECT (0..120) ... are encoded in the meta-block header...
+
+ The first 16 distance symbols ... reference past distances... ring buffer ...
+ Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT...
+ [For] distance symbols 16 + NDIRECT and greater ... the number of extra bits
+ ... is given by the following formula:
+
+ [ xcode = dcode - NDIRECT - 16 ]
+ ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1)
+
+ ...
+*/
+
+/*
+ RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations.
+
+ ... to get the actual value of the parameter NDIRECT, left-shift this
+ four-bit number by NPOSTFIX bits ...
+*/
+
+/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following:
+
+ alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1))
+
+ half = ((xcode >> NPOSTFIX) & 1) << ndistbits
+ postfix = xcode & ((1 << NPOSTFIX) - 1)
+ range_start = 2 * (1 << ndistbits - 1 - 1)
+
+ distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1
+
+ NB: ndistbits >= 1 -> range_start >= 0
+ NB: range_start has factor 2, as the range is covered by 2 "halves"
+ NB: extra -1 offset in range_start formula covers the absence of
+ ndistbits = 0 case
+ NB: when NPOSTFIX = 0, NDIRECT is not greater than 15
+
+ In other words, xcode has the following binary structure - XXXHPPP:
+ - XXX represent the number of extra distance bits
+ - H selects upper / lower range of distances
+ - PPP represent "postfix"
+
+ "Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part
+ simplifies distance calculation.
+
+ Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where
+ most of distances have the same reminder of division by 2/4/8. For example,
+ the table of int32_t values that come from different sources; if it is likely
+ that 3 highest bytes of values from the same source are the same, then
+ copy distance often looks like 4x + y.
+
+ Distance calculation could be rewritten to:
+
+ ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode]
+ distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX
+
+ NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could
+ change only once per meta-block.
+*/
+
+/* Calculates distance lookup table.
+ NB: it is possible to have all 64 tables precalculated. */
+static void CalculateDistanceLut(BrotliDecoderState* s) {
+ BrotliMetablockBodyArena* b = &s->arena.body;
+ uint32_t npostfix = s->distance_postfix_bits;
+ uint32_t ndirect = s->num_direct_distance_codes;
+ uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit;
+ uint32_t postfix = 1u << npostfix;
+ uint32_t j;
+ uint32_t bits = 1;
+ uint32_t half = 0;
+
+ /* Skip short codes. */
+ uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES;
+
+ /* Fill direct codes. */
+ for (j = 0; j < ndirect; ++j) {
+ b->dist_extra_bits[i] = 0;
+ b->dist_offset[i] = j + 1;
+ ++i;
+ }
+
+ /* Fill regular distance codes. */
+ while (i < alphabet_size_limit) {
+ uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
+ /* Always fill the complete group. */
+ for (j = 0; j < postfix; ++j) {
+ b->dist_extra_bits[i] = (uint8_t)bits;
+ b->dist_offset[i] = base + j;
+ ++i;
+ }
+ bits = bits + half;
+ half = half ^ 1;
+ }
+}
+
+/* Precondition: s->distance_code < 0. */
+static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal(
+ int safe, BrotliDecoderState* s, BrotliBitReader* br) {
+ BrotliMetablockBodyArena* b = &s->arena.body;
+ uint32_t code;
+ uint32_t bits;
+ BrotliBitReaderState memento;
+ HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
+ if (!safe) {
+ code = ReadSymbol(distance_tree, br);
+ } else {
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(distance_tree, br, &code)) {
+ return BROTLI_FALSE;
+ }
+ }
+ --s->block_length[2];
+ /* Convert the distance code to the actual distance by possibly
+ looking up past distances from the s->dist_rb. */
+ s->distance_context = 0;
+ if ((code & ~0xFu) == 0) {
+ s->distance_code = (int)code;
+ TakeDistanceFromRingBuffer(s);
+ return BROTLI_TRUE;
+ }
+ if (!safe) {
+ bits = BrotliReadBits32(br, b->dist_extra_bits[code]);
+ } else {
+ if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) {
+ ++s->block_length[2];
+ BrotliBitReaderRestoreState(br, &memento);
+ return BROTLI_FALSE;
+ }
+ }
+ s->distance_code =
+ (int)(b->dist_offset[code] + (bits << s->distance_postfix_bits));
+ return BROTLI_TRUE;
+}
+
+static BROTLI_INLINE void ReadDistance(
+ BrotliDecoderState* s, BrotliBitReader* br) {
+ ReadDistanceInternal(0, s, br);
+}
+
+static BROTLI_INLINE BROTLI_BOOL SafeReadDistance(
+ BrotliDecoderState* s, BrotliBitReader* br) {
+ return ReadDistanceInternal(1, s, br);
+}
+
+static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal(
+ int safe, BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) {
+ uint32_t cmd_code;
+ uint32_t insert_len_extra = 0;
+ uint32_t copy_length;
+ CmdLutElement v;
+ BrotliBitReaderState memento;
+ if (!safe) {
+ cmd_code = ReadSymbol(s->htree_command, br);
+ } else {
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(s->htree_command, br, &cmd_code)) {
+ return BROTLI_FALSE;
+ }
+ }
+ v = kCmdLut[cmd_code];
+ s->distance_code = v.distance_code;
+ s->distance_context = v.context;
+ s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+ *insert_length = v.insert_len_offset;
+ if (!safe) {
+ if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
+ insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits);
+ }
+ copy_length = BrotliReadBits24(br, v.copy_len_extra_bits);
+ } else {
+ if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
+ !SafeReadBits(br, v.copy_len_extra_bits, &copy_length)) {
+ BrotliBitReaderRestoreState(br, &memento);
+ return BROTLI_FALSE;
+ }
+ }
+ s->copy_length = (int)copy_length + v.copy_len_offset;
+ --s->block_length[1];
+ *insert_length += (int)insert_len_extra;
+ return BROTLI_TRUE;
+}
+
+static BROTLI_INLINE void ReadCommand(
+ BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) {
+ ReadCommandInternal(0, s, br, insert_length);
+}
+
+static BROTLI_INLINE BROTLI_BOOL SafeReadCommand(
+ BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) {
+ return ReadCommandInternal(1, s, br, insert_length);
+}
+
+static BROTLI_INLINE BROTLI_BOOL CheckInputAmount(
+ int safe, BrotliBitReader* const br, size_t num) {
+ if (safe) {
+ return BROTLI_TRUE;
+ }
+ return BrotliCheckInputAmount(br, num);
+}
+
+#define BROTLI_SAFE(METHOD) \
+ { \
+ if (safe) { \
+ if (!Safe##METHOD) { \
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT; \
+ goto saveStateAndReturn; \
+ } \
+ } else { \
+ METHOD; \
+ } \
+ }
+
+static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
+ int safe, BrotliDecoderState* s) {
+ int pos = s->pos;
+ int i = s->loop_counter;
+ BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
+ BrotliBitReader* br = &s->br;
+
+ if (!CheckInputAmount(safe, br, 28)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (!safe) {
+ BROTLI_UNUSED(BrotliWarmupBitReader(br));
+ }
+
+ /* Jump into state machine. */
+ if (s->state == BROTLI_STATE_COMMAND_BEGIN) {
+ goto CommandBegin;
+ } else if (s->state == BROTLI_STATE_COMMAND_INNER) {
+ goto CommandInner;
+ } else if (s->state == BROTLI_STATE_COMMAND_POST_DECODE_LITERALS) {
+ goto CommandPostDecodeLiterals;
+ } else if (s->state == BROTLI_STATE_COMMAND_POST_WRAP_COPY) {
+ goto CommandPostWrapCopy;
+ } else {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE);
+ }
+
+CommandBegin:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ }
+ if (!CheckInputAmount(safe, br, 28)) { /* 156 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (BROTLI_PREDICT_FALSE(s->block_length[1] == 0)) {
+ BROTLI_SAFE(DecodeCommandBlockSwitch(s));
+ goto CommandBegin;
+ }
+ /* Read the insert/copy length in the command. */
+ BROTLI_SAFE(ReadCommand(s, br, &i));
+ BROTLI_LOG(("[ProcessCommandsInternal] pos = %d insert = %d copy = %d\n",
+ pos, i, s->copy_length));
+ if (i == 0) {
+ goto CommandPostDecodeLiterals;
+ }
+ s->meta_block_remaining_len -= i;
+
+CommandInner:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ }
+ /* Read the literals in the command. */
+ if (s->trivial_literal_context) {
+ uint32_t bits;
+ uint32_t value;
+ PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
+ do {
+ if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) {
+ BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+ PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
+ if (!s->trivial_literal_context) goto CommandInner;
+ }
+ if (!safe) {
+ s->ringbuffer[pos] =
+ (uint8_t)ReadPreloadedSymbol(s->literal_htree, br, &bits, &value);
+ } else {
+ uint32_t literal;
+ if (!SafeReadSymbol(s->literal_htree, br, &literal)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ s->ringbuffer[pos] = (uint8_t)literal;
+ }
+ --s->block_length[0];
+ BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
+ ++pos;
+ if (BROTLI_PREDICT_FALSE(pos == s->ringbuffer_size)) {
+ s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+ --i;
+ goto saveStateAndReturn;
+ }
+ } while (--i != 0);
+ } else {
+ uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask];
+ uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask];
+ do {
+ const HuffmanCode* hc;
+ uint8_t context;
+ if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) {
+ BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+ if (s->trivial_literal_context) goto CommandInner;
+ }
+ context = BROTLI_CONTEXT(p1, p2, s->context_lookup);
+ BROTLI_LOG_UINT(context);
+ hc = s->literal_hgroup.htrees[s->context_map_slice[context]];
+ p2 = p1;
+ if (!safe) {
+ p1 = (uint8_t)ReadSymbol(hc, br);
+ } else {
+ uint32_t literal;
+ if (!SafeReadSymbol(hc, br, &literal)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ p1 = (uint8_t)literal;
+ }
+ s->ringbuffer[pos] = p1;
+ --s->block_length[0];
+ BROTLI_LOG_UINT(s->context_map_slice[context]);
+ BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
+ ++pos;
+ if (BROTLI_PREDICT_FALSE(pos == s->ringbuffer_size)) {
+ s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+ --i;
+ goto saveStateAndReturn;
+ }
+ } while (--i != 0);
+ }
+ BROTLI_LOG_UINT(s->meta_block_remaining_len);
+ if (BROTLI_PREDICT_FALSE(s->meta_block_remaining_len <= 0)) {
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ }
+
+CommandPostDecodeLiterals:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
+ }
+ if (s->distance_code >= 0) {
+ /* Implicit distance case. */
+ s->distance_context = s->distance_code ? 0 : 1;
+ --s->dist_rb_idx;
+ s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+ } else {
+ /* Read distance code in the command, unless it was implicitly zero. */
+ if (BROTLI_PREDICT_FALSE(s->block_length[2] == 0)) {
+ BROTLI_SAFE(DecodeDistanceBlockSwitch(s));
+ }
+ BROTLI_SAFE(ReadDistance(s, br));
+ }
+ BROTLI_LOG(("[ProcessCommandsInternal] pos = %d distance = %d\n",
+ pos, s->distance_code));
+ if (s->max_distance != s->max_backward_distance) {
+ s->max_distance =
+ (pos < s->max_backward_distance) ? pos : s->max_backward_distance;
+ }
+ i = s->copy_length;
+ /* Apply copy of LZ77 back-reference, or static dictionary reference if
+ the distance is larger than the max LZ77 distance */
+ if (s->distance_code > s->max_distance) {
+ /* The maximum allowed distance is BROTLI_MAX_ALLOWED_DISTANCE = 0x7FFFFFFC.
+ With this choice, no signed overflow can occur after decoding
+ a special distance code (e.g., after adding 3 to the last distance). */
+ if (s->distance_code > BROTLI_MAX_ALLOWED_DISTANCE) {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n",
+ pos, s->distance_code, i, s->meta_block_remaining_len));
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
+ }
+ if (i >= BROTLI_MIN_DICTIONARY_WORD_LENGTH &&
+ i <= BROTLI_MAX_DICTIONARY_WORD_LENGTH) {
+ int address = s->distance_code - s->max_distance - 1;
+ const BrotliDictionary* words = s->dictionary;
+ const BrotliTransforms* transforms = s->transforms;
+ int offset = (int)s->dictionary->offsets_by_length[i];
+ uint32_t shift = s->dictionary->size_bits_by_length[i];
+
+ int mask = (int)BitMask(shift);
+ int word_idx = address & mask;
+ int transform_idx = address >> shift;
+ /* Compensate double distance-ring-buffer roll. */
+ s->dist_rb_idx += s->distance_context;
+ offset += word_idx * i;
+ if (BROTLI_PREDICT_FALSE(!words->data)) {
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
+ }
+ if (transform_idx < (int)transforms->num_transforms) {
+ const uint8_t* word = &words->data[offset];
+ int len = i;
+ if (transform_idx == transforms->cutOffTransforms[0]) {
+ memcpy(&s->ringbuffer[pos], word, (size_t)len);
+ BROTLI_LOG(("[ProcessCommandsInternal] dictionary word: [%.*s]\n",
+ len, word));
+ } else {
+ len = BrotliTransformDictionaryWord(&s->ringbuffer[pos], word, len,
+ transforms, transform_idx);
+ BROTLI_LOG(("[ProcessCommandsInternal] dictionary word: [%.*s],"
+ " transform_idx = %d, transformed: [%.*s]\n",
+ i, word, transform_idx, len, &s->ringbuffer[pos]));
+ }
+ pos += len;
+ s->meta_block_remaining_len -= len;
+ if (pos >= s->ringbuffer_size) {
+ s->state = BROTLI_STATE_COMMAND_POST_WRITE_1;
+ goto saveStateAndReturn;
+ }
+ } else {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n",
+ pos, s->distance_code, i, s->meta_block_remaining_len));
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
+ }
+ } else {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n",
+ pos, s->distance_code, i, s->meta_block_remaining_len));
+ return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
+ }
+ } else {
+ int src_start = (pos - s->distance_code) & s->ringbuffer_mask;
+ uint8_t* copy_dst = &s->ringbuffer[pos];
+ uint8_t* copy_src = &s->ringbuffer[src_start];
+ int dst_end = pos + i;
+ int src_end = src_start + i;
+ /* Update the recent distances cache. */
+ s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
+ ++s->dist_rb_idx;
+ s->meta_block_remaining_len -= i;
+ /* There are 32+ bytes of slack in the ring-buffer allocation.
+ Also, we have 16 short codes, that make these 16 bytes irrelevant
+ in the ring-buffer. Let's copy over them as a first guess. */
+ memmove16(copy_dst, copy_src);
+ if (src_end > pos && dst_end > src_start) {
+ /* Regions intersect. */
+ goto CommandPostWrapCopy;
+ }
+ if (dst_end >= s->ringbuffer_size || src_end >= s->ringbuffer_size) {
+ /* At least one region wraps. */
+ goto CommandPostWrapCopy;
+ }
+ pos += i;
+ if (i > 16) {
+ if (i > 32) {
+ memcpy(copy_dst + 16, copy_src + 16, (size_t)(i - 16));
+ } else {
+ /* This branch covers about 45% cases.
+ Fixed size short copy allows more compiler optimizations. */
+ memmove16(copy_dst + 16, copy_src + 16);
+ }
+ }
+ }
+ BROTLI_LOG_UINT(s->meta_block_remaining_len);
+ if (s->meta_block_remaining_len <= 0) {
+ /* Next metablock, if any. */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ } else {
+ goto CommandBegin;
+ }
+CommandPostWrapCopy:
+ {
+ int wrap_guard = s->ringbuffer_size - pos;
+ while (--i >= 0) {
+ s->ringbuffer[pos] =
+ s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
+ ++pos;
+ if (BROTLI_PREDICT_FALSE(--wrap_guard == 0)) {
+ s->state = BROTLI_STATE_COMMAND_POST_WRITE_2;
+ goto saveStateAndReturn;
+ }
+ }
+ }
+ if (s->meta_block_remaining_len <= 0) {
+ /* Next metablock, if any. */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ } else {
+ goto CommandBegin;
+ }
+
+saveStateAndReturn:
+ s->pos = pos;
+ s->loop_counter = i;
+ return result;
+}
+
+#undef BROTLI_SAFE
+
+static BROTLI_NOINLINE BrotliDecoderErrorCode ProcessCommands(
+ BrotliDecoderState* s) {
+ return ProcessCommandsInternal(0, s);
+}
+
+static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands(
+ BrotliDecoderState* s) {
+ return ProcessCommandsInternal(1, s);
+}
+
+BrotliDecoderResult BrotliDecoderDecompress(
+ size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
+ uint8_t* decoded_buffer) {
+ BrotliDecoderState s;
+ BrotliDecoderResult result;
+ size_t total_out = 0;
+ size_t available_in = encoded_size;
+ const uint8_t* next_in = encoded_buffer;
+ size_t available_out = *decoded_size;
+ uint8_t* next_out = decoded_buffer;
+ if (!BrotliDecoderStateInit(&s, 0, 0, 0)) {
+ return BROTLI_DECODER_RESULT_ERROR;
+ }
+ result = BrotliDecoderDecompressStream(
+ &s, &available_in, &next_in, &available_out, &next_out, &total_out);
+ *decoded_size = total_out;
+ BrotliDecoderStateCleanup(&s);
+ if (result != BROTLI_DECODER_RESULT_SUCCESS) {
+ result = BROTLI_DECODER_RESULT_ERROR;
+ }
+ return result;
+}
+
+/* Invariant: input stream is never overconsumed:
+ - invalid input implies that the whole stream is invalid -> any amount of
+ input could be read and discarded
+ - when result is "needs more input", then at least one more byte is REQUIRED
+ to complete decoding; all input data MUST be consumed by decoder, so
+ client could swap the input buffer
+ - when result is "needs more output" decoder MUST ensure that it doesn't
+ hold more than 7 bits in bit reader; this saves client from swapping input
+ buffer ahead of time
+ - when result is "success" decoder MUST return all unused data back to input
+ buffer; this is possible because the invariant is held on enter */
+BrotliDecoderResult BrotliDecoderDecompressStream(
+ BrotliDecoderState* s, size_t* available_in, const uint8_t** next_in,
+ size_t* available_out, uint8_t** next_out, size_t* total_out) {
+ BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
+ BrotliBitReader* br = &s->br;
+ /* Ensure that |total_out| is set, even if no data will ever be pushed out. */
+ if (total_out) {
+ *total_out = s->partial_pos_out;
+ }
+ /* Do not try to process further in a case of unrecoverable error. */
+ if ((int)s->error_code < 0) {
+ return BROTLI_DECODER_RESULT_ERROR;
+ }
+ if (*available_out && (!next_out || !*next_out)) {
+ return SaveErrorCode(
+ s, BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS));
+ }
+ if (!*available_out) next_out = 0;
+ if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */
+ br->avail_in = *available_in;
+ br->next_in = *next_in;
+ } else {
+ /* At least one byte of input is required. More than one byte of input may
+ be required to complete the transaction -> reading more data must be
+ done in a loop -> do it in a main loop. */
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ br->next_in = &s->buffer.u8[0];
+ }
+ /* State machine */
+ for (;;) {
+ if (result != BROTLI_DECODER_SUCCESS) {
+ /* Error, needs more input/output. */
+ if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
+ if (s->ringbuffer != 0) { /* Pro-actively push output. */
+ BrotliDecoderErrorCode intermediate_result = WriteRingBuffer(s,
+ available_out, next_out, total_out, BROTLI_TRUE);
+ /* WriteRingBuffer checks s->meta_block_remaining_len validity. */
+ if ((int)intermediate_result < 0) {
+ result = intermediate_result;
+ break;
+ }
+ }
+ if (s->buffer_length != 0) { /* Used with internal buffer. */
+ if (br->avail_in == 0) {
+ /* Successfully finished read transaction.
+ Accumulator contains less than 8 bits, because internal buffer
+ is expanded byte-by-byte until it is enough to complete read. */
+ s->buffer_length = 0;
+ /* Switch to input stream and restart. */
+ result = BROTLI_DECODER_SUCCESS;
+ br->avail_in = *available_in;
+ br->next_in = *next_in;
+ continue;
+ } else if (*available_in != 0) {
+ /* Not enough data in buffer, but can take one more byte from
+ input stream. */
+ result = BROTLI_DECODER_SUCCESS;
+ s->buffer.u8[s->buffer_length] = **next_in;
+ s->buffer_length++;
+ br->avail_in = s->buffer_length;
+ (*next_in)++;
+ (*available_in)--;
+ /* Retry with more data in buffer. */
+ continue;
+ }
+ /* Can't finish reading and no more input. */
+ break;
+ } else { /* Input stream doesn't contain enough input. */
+ /* Copy tail to internal buffer and return. */
+ *next_in = br->next_in;
+ *available_in = br->avail_in;
+ while (*available_in) {
+ s->buffer.u8[s->buffer_length] = **next_in;
+ s->buffer_length++;
+ (*next_in)++;
+ (*available_in)--;
+ }
+ break;
+ }
+ /* Unreachable. */
+ }
+
+ /* Fail or needs more output. */
+
+ if (s->buffer_length != 0) {
+ /* Just consumed the buffered input and produced some output. Otherwise
+ it would result in "needs more input". Reset internal buffer. */
+ s->buffer_length = 0;
+ } else {
+ /* Using input stream in last iteration. When decoder switches to input
+ stream it has less than 8 bits in accumulator, so it is safe to
+ return unused accumulator bits there. */
+ BrotliBitReaderUnload(br);
+ *available_in = br->avail_in;
+ *next_in = br->next_in;
+ }
+ break;
+ }
+ switch (s->state) {
+ case BROTLI_STATE_UNINITED:
+ /* Prepare to the first read. */
+ if (!BrotliWarmupBitReader(br)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ break;
+ }
+ /* Decode window size. */
+ result = DecodeWindowBits(s, br); /* Reads 1..8 bits. */
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ if (s->large_window) {
+ s->state = BROTLI_STATE_LARGE_WINDOW_BITS;
+ break;
+ }
+ s->state = BROTLI_STATE_INITIALIZE;
+ break;
+
+ case BROTLI_STATE_LARGE_WINDOW_BITS:
+ if (!BrotliSafeReadBits(br, 6, &s->window_bits)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ break;
+ }
+ if (s->window_bits < BROTLI_LARGE_MIN_WBITS ||
+ s->window_bits > BROTLI_LARGE_MAX_WBITS) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
+ break;
+ }
+ s->state = BROTLI_STATE_INITIALIZE;
+ /* Fall through. */
+
+ case BROTLI_STATE_INITIALIZE:
+ BROTLI_LOG_UINT(s->window_bits);
+ /* Maximum distance, see section 9.1. of the spec. */
+ s->max_backward_distance = (1 << s->window_bits) - BROTLI_WINDOW_GAP;
+
+ /* Allocate memory for both block_type_trees and block_len_trees. */
+ s->block_type_trees = (HuffmanCode*)BROTLI_DECODER_ALLOC(s,
+ sizeof(HuffmanCode) * 3 *
+ (BROTLI_HUFFMAN_MAX_SIZE_258 + BROTLI_HUFFMAN_MAX_SIZE_26));
+ if (s->block_type_trees == 0) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
+ break;
+ }
+ s->block_len_trees =
+ s->block_type_trees + 3 * BROTLI_HUFFMAN_MAX_SIZE_258;
+
+ s->state = BROTLI_STATE_METABLOCK_BEGIN;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_BEGIN:
+ BrotliDecoderStateMetablockBegin(s);
+ BROTLI_LOG_UINT(s->pos);
+ s->state = BROTLI_STATE_METABLOCK_HEADER;
+ /* Fall through. */
+
+ case BROTLI_STATE_METABLOCK_HEADER:
+ result = DecodeMetaBlockLength(s, br); /* Reads 2 - 31 bits. */
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ BROTLI_LOG_UINT(s->is_last_metablock);
+ BROTLI_LOG_UINT(s->meta_block_remaining_len);
+ BROTLI_LOG_UINT(s->is_metadata);
+ BROTLI_LOG_UINT(s->is_uncompressed);
+ if (s->is_metadata || s->is_uncompressed) {
+ if (!BrotliJumpToByteBoundary(br)) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
+ break;
+ }
+ }
+ if (s->is_metadata) {
+ s->state = BROTLI_STATE_METADATA;
+ break;
+ }
+ if (s->meta_block_remaining_len == 0) {
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ break;
+ }
+ BrotliCalculateRingBufferSize(s);
+ if (s->is_uncompressed) {
+ s->state = BROTLI_STATE_UNCOMPRESSED;
+ break;
+ }
+ s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER;
+ /* Fall through. */
+
+ case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
+ BrotliMetablockHeaderArena* h = &s->arena.header;
+ s->loop_counter = 0;
+ /* Initialize compressed metablock header arena. */
+ h->sub_loop_counter = 0;
+ /* Make small negative indexes addressable. */
+ h->symbol_lists =
+ &h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
+ h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+ h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
+ h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
+ s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_CODE_0:
+ if (s->loop_counter >= 3) {
+ s->state = BROTLI_STATE_METABLOCK_HEADER_2;
+ break;
+ }
+ /* Reads 1..11 bits. */
+ result = DecodeVarLenUint8(s, br, &s->num_block_types[s->loop_counter]);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ s->num_block_types[s->loop_counter]++;
+ BROTLI_LOG_UINT(s->num_block_types[s->loop_counter]);
+ if (s->num_block_types[s->loop_counter] < 2) {
+ s->loop_counter++;
+ break;
+ }
+ s->state = BROTLI_STATE_HUFFMAN_CODE_1;
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_CODE_1: {
+ uint32_t alphabet_size = s->num_block_types[s->loop_counter] + 2;
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_258;
+ result = ReadHuffmanCode(alphabet_size, alphabet_size,
+ &s->block_type_trees[tree_offset], NULL, s);
+ if (result != BROTLI_DECODER_SUCCESS) break;
+ s->state = BROTLI_STATE_HUFFMAN_CODE_2;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_CODE_2: {
+ uint32_t alphabet_size = BROTLI_NUM_BLOCK_LEN_SYMBOLS;
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26;
+ result = ReadHuffmanCode(alphabet_size, alphabet_size,
+ &s->block_len_trees[tree_offset], NULL, s);
+ if (result != BROTLI_DECODER_SUCCESS) break;
+ s->state = BROTLI_STATE_HUFFMAN_CODE_3;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_HUFFMAN_CODE_3: {
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26;
+ if (!SafeReadBlockLength(s, &s->block_length[s->loop_counter],
+ &s->block_len_trees[tree_offset], br)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ break;
+ }
+ BROTLI_LOG_UINT(s->block_length[s->loop_counter]);
+ s->loop_counter++;
+ s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+ break;
+ }
+
+ case BROTLI_STATE_UNCOMPRESSED: {
+ result = CopyUncompressedBlockToOutput(
+ available_out, next_out, total_out, s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ break;
+ }
+
+ case BROTLI_STATE_METADATA:
+ for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
+ uint32_t bits;
+ /* Read one byte and ignore it. */
+ if (!BrotliSafeReadBits(br, 8, &bits)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ break;
+ }
+ }
+ if (result == BROTLI_DECODER_SUCCESS) {
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ }
+ break;
+
+ case BROTLI_STATE_METABLOCK_HEADER_2: {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 6, &bits)) {
+ result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+ break;
+ }
+ s->distance_postfix_bits = bits & BitMask(2);
+ bits >>= 2;
+ s->num_direct_distance_codes = bits << s->distance_postfix_bits;
+ BROTLI_LOG_UINT(s->num_direct_distance_codes);
+ BROTLI_LOG_UINT(s->distance_postfix_bits);
+ s->context_modes =
+ (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]);
+ if (s->context_modes == 0) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
+ break;
+ }
+ s->loop_counter = 0;
+ s->state = BROTLI_STATE_CONTEXT_MODES;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MODES:
+ result = ReadContextModes(s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ s->state = BROTLI_STATE_CONTEXT_MAP_1;
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_1:
+ result = DecodeContextMap(
+ s->num_block_types[0] << BROTLI_LITERAL_CONTEXT_BITS,
+ &s->num_literal_htrees, &s->context_map, s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ DetectTrivialLiteralBlockTypes(s);
+ s->state = BROTLI_STATE_CONTEXT_MAP_2;
+ /* Fall through. */
+
+ case BROTLI_STATE_CONTEXT_MAP_2: {
+ uint32_t npostfix = s->distance_postfix_bits;
+ uint32_t ndirect = s->num_direct_distance_codes;
+ uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+ npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
+ uint32_t distance_alphabet_size_limit = distance_alphabet_size_max;
+ BROTLI_BOOL allocation_success = BROTLI_TRUE;
+ if (s->large_window) {
+ BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
+ BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
+ distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+ npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
+ distance_alphabet_size_limit = limit.max_alphabet_size;
+ }
+ result = DecodeContextMap(
+ s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
+ &s->num_dist_htrees, &s->dist_context_map, s);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
+ s, &s->literal_hgroup, BROTLI_NUM_LITERAL_SYMBOLS,
+ BROTLI_NUM_LITERAL_SYMBOLS, s->num_literal_htrees);
+ allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
+ s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS,
+ BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]);
+ allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
+ s, &s->distance_hgroup, distance_alphabet_size_max,
+ distance_alphabet_size_limit, s->num_dist_htrees);
+ if (!allocation_success) {
+ return SaveErrorCode(s,
+ BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
+ }
+ s->loop_counter = 0;
+ s->state = BROTLI_STATE_TREE_GROUP;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_TREE_GROUP: {
+ HuffmanTreeGroup* hgroup = NULL;
+ switch (s->loop_counter) {
+ case 0: hgroup = &s->literal_hgroup; break;
+ case 1: hgroup = &s->insert_copy_hgroup; break;
+ case 2: hgroup = &s->distance_hgroup; break;
+ default: return SaveErrorCode(s, BROTLI_FAILURE(
+ BROTLI_DECODER_ERROR_UNREACHABLE));
+ }
+ result = HuffmanTreeGroupDecode(hgroup, s);
+ if (result != BROTLI_DECODER_SUCCESS) break;
+ s->loop_counter++;
+ if (s->loop_counter < 3) {
+ break;
+ }
+ s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY;
+ }
+ /* Fall through. */
+
+ case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
+ PrepareLiteralDecoding(s);
+ s->dist_context_map_slice = s->dist_context_map;
+ s->htree_command = s->insert_copy_hgroup.htrees[0];
+ if (!BrotliEnsureRingBuffer(s)) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
+ break;
+ }
+ CalculateDistanceLut(s);
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ /* Fall through. */
+
+ case BROTLI_STATE_COMMAND_BEGIN:
+ /* Fall through. */
+ case BROTLI_STATE_COMMAND_INNER:
+ /* Fall through. */
+ case BROTLI_STATE_COMMAND_POST_DECODE_LITERALS:
+ /* Fall through. */
+ case BROTLI_STATE_COMMAND_POST_WRAP_COPY:
+ result = ProcessCommands(s);
+ if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
+ result = SafeProcessCommands(s);
+ }
+ break;
+
+ case BROTLI_STATE_COMMAND_INNER_WRITE:
+ /* Fall through. */
+ case BROTLI_STATE_COMMAND_POST_WRITE_1:
+ /* Fall through. */
+ case BROTLI_STATE_COMMAND_POST_WRITE_2:
+ result = WriteRingBuffer(
+ s, available_out, next_out, total_out, BROTLI_FALSE);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ WrapRingBuffer(s);
+ if (s->ringbuffer_size == 1 << s->window_bits) {
+ s->max_distance = s->max_backward_distance;
+ }
+ if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
+ if (s->meta_block_remaining_len == 0) {
+ /* Next metablock, if any. */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ } else {
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ }
+ break;
+ } else if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_2) {
+ s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
+ } else { /* BROTLI_STATE_COMMAND_INNER_WRITE */
+ if (s->loop_counter == 0) {
+ if (s->meta_block_remaining_len == 0) {
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ } else {
+ s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
+ }
+ break;
+ }
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ }
+ break;
+
+ case BROTLI_STATE_METABLOCK_DONE:
+ if (s->meta_block_remaining_len < 0) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
+ break;
+ }
+ BrotliDecoderStateCleanupAfterMetablock(s);
+ if (!s->is_last_metablock) {
+ s->state = BROTLI_STATE_METABLOCK_BEGIN;
+ break;
+ }
+ if (!BrotliJumpToByteBoundary(br)) {
+ result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
+ break;
+ }
+ if (s->buffer_length == 0) {
+ BrotliBitReaderUnload(br);
+ *available_in = br->avail_in;
+ *next_in = br->next_in;
+ }
+ s->state = BROTLI_STATE_DONE;
+ /* Fall through. */
+
+ case BROTLI_STATE_DONE:
+ if (s->ringbuffer != 0) {
+ result = WriteRingBuffer(
+ s, available_out, next_out, total_out, BROTLI_TRUE);
+ if (result != BROTLI_DECODER_SUCCESS) {
+ break;
+ }
+ }
+ return SaveErrorCode(s, result);
+ }
+ }
+ return SaveErrorCode(s, result);
+}
+
+BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s) {
+ /* After unrecoverable error remaining output is considered nonsensical. */
+ if ((int)s->error_code < 0) {
+ return BROTLI_FALSE;
+ }
+ return TO_BROTLI_BOOL(
+ s->ringbuffer != 0 && UnwrittenBytes(s, BROTLI_FALSE) != 0);
+}
+
+const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) {
+ uint8_t* result = 0;
+ size_t available_out = *size ? *size : 1u << 24;
+ size_t requested_out = available_out;
+ BrotliDecoderErrorCode status;
+ if ((s->ringbuffer == 0) || ((int)s->error_code < 0)) {
+ *size = 0;
+ return 0;
+ }
+ WrapRingBuffer(s);
+ status = WriteRingBuffer(s, &available_out, &result, 0, BROTLI_TRUE);
+ /* Either WriteRingBuffer returns those "success" codes... */
+ if (status == BROTLI_DECODER_SUCCESS ||
+ status == BROTLI_DECODER_NEEDS_MORE_OUTPUT) {
+ *size = requested_out - available_out;
+ } else {
+ /* ... or stream is broken. Normally this should be caught by
+ BrotliDecoderDecompressStream, this is just a safeguard. */
+ if ((int)status < 0) SaveErrorCode(s, status);
+ *size = 0;
+ result = 0;
+ }
+ return result;
+}
+
+BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* s) {
+ return TO_BROTLI_BOOL(s->state != BROTLI_STATE_UNINITED ||
+ BrotliGetAvailableBits(&s->br) != 0);
+}
+
+BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s) {
+ return TO_BROTLI_BOOL(s->state == BROTLI_STATE_DONE) &&
+ !BrotliDecoderHasMoreOutput(s);
+}
+
+BrotliDecoderErrorCode BrotliDecoderGetErrorCode(const BrotliDecoderState* s) {
+ return (BrotliDecoderErrorCode)s->error_code;
+}
+
+const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c) {
+ switch (c) {
+#define BROTLI_ERROR_CODE_CASE_(PREFIX, NAME, CODE) \
+ case BROTLI_DECODER ## PREFIX ## NAME: return #NAME;
+#define BROTLI_NOTHING_
+ BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_CASE_, BROTLI_NOTHING_)
+#undef BROTLI_ERROR_CODE_CASE_
+#undef BROTLI_NOTHING_
+ default: return "INVALID";
+ }
+}
+
+uint32_t BrotliDecoderVersion() {
+ return BROTLI_VERSION;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.c
new file mode 100644
index 000000000..30c40d33f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.c
@@ -0,0 +1,339 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+#include "./huffman.h"
+
+#include <string.h> /* memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BROTLI_REVERSE_BITS_MAX 8
+
+#if defined(BROTLI_RBIT)
+#define BROTLI_REVERSE_BITS_BASE \
+ ((sizeof(brotli_reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
+#else
+#define BROTLI_REVERSE_BITS_BASE 0
+static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+#endif /* BROTLI_RBIT */
+
+#define BROTLI_REVERSE_BITS_LOWEST \
+ ((brotli_reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
+
+/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
+ where reverse(value, len) is the bit-wise reversal of the len least
+ significant bits of value. */
+static BROTLI_INLINE brotli_reg_t BrotliReverseBits(brotli_reg_t num) {
+#if defined(BROTLI_RBIT)
+ return BROTLI_RBIT(num);
+#else
+ return kReverseBits[num];
+#endif
+}
+
+/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
+/* Assumes that end is an integer multiple of step */
+static BROTLI_INLINE void ReplicateValue(HuffmanCode* table,
+ int step, int end,
+ HuffmanCode code) {
+ do {
+ end -= step;
+ table[end] = code;
+ } while (end > 0);
+}
+
+/* Returns the table width of the next 2nd level table. |count| is the histogram
+ of bit lengths for the remaining symbols, |len| is the code length of the
+ next processed symbol. */
+static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
+ int len, int root_bits) {
+ int left = 1 << (len - root_bits);
+ while (len < BROTLI_HUFFMAN_MAX_CODE_LENGTH) {
+ left -= count[len];
+ if (left <= 0) break;
+ ++len;
+ left <<= 1;
+ }
+ return len - root_bits;
+}
+
+void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
+ const uint8_t* const code_lengths,
+ uint16_t* count) {
+ HuffmanCode code; /* current table entry */
+ int symbol; /* symbol index in original or sorted table */
+ brotli_reg_t key; /* prefix code */
+ brotli_reg_t key_step; /* prefix code addend */
+ int step; /* step size to replicate values in current table */
+ int table_size; /* size of current table */
+ int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */
+ /* offsets in sorted table for each length */
+ int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
+ int bits;
+ int bits_count;
+ BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
+ BROTLI_REVERSE_BITS_MAX);
+
+ /* Generate offsets into sorted symbol table by code length. */
+ symbol = -1;
+ bits = 1;
+ BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, {
+ symbol += count[bits];
+ offset[bits] = symbol;
+ bits++;
+ });
+ /* Symbols with code length 0 are placed after all other symbols. */
+ offset[0] = BROTLI_CODE_LENGTH_CODES - 1;
+
+ /* Sort symbols by length, by symbol order within each length. */
+ symbol = BROTLI_CODE_LENGTH_CODES;
+ do {
+ BROTLI_REPEAT(6, {
+ symbol--;
+ sorted[offset[code_lengths[symbol]]--] = symbol;
+ });
+ } while (symbol != 0);
+
+ table_size = 1 << BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH;
+
+ /* Special case: all symbols but one have 0 code length. */
+ if (offset[0] == 0) {
+ code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
+ for (key = 0; key < (brotli_reg_t)table_size; ++key) {
+ table[key] = code;
+ }
+ return;
+ }
+
+ /* Fill in table. */
+ key = 0;
+ key_step = BROTLI_REVERSE_BITS_LOWEST;
+ symbol = 0;
+ bits = 1;
+ step = 2;
+ do {
+ for (bits_count = count[bits]; bits_count != 0; --bits_count) {
+ code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]);
+ ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
+ key += key_step;
+ }
+ step <<= 1;
+ key_step >>= 1;
+ } while (++bits <= BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
+}
+
+uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
+ int root_bits,
+ const uint16_t* const symbol_lists,
+ uint16_t* count) {
+ HuffmanCode code; /* current table entry */
+ HuffmanCode* table; /* next available space in table */
+ int len; /* current code length */
+ int symbol; /* symbol index in original or sorted table */
+ brotli_reg_t key; /* prefix code */
+ brotli_reg_t key_step; /* prefix code addend */
+ brotli_reg_t sub_key; /* 2nd level table prefix code */
+ brotli_reg_t sub_key_step; /* 2nd level table prefix code addend */
+ int step; /* step size to replicate values in current table */
+ int table_bits; /* key length of current table */
+ int table_size; /* size of current table */
+ int total_size; /* sum of root table size and 2nd level table sizes */
+ int max_length = -1;
+ int bits;
+ int bits_count;
+
+ BROTLI_DCHECK(root_bits <= BROTLI_REVERSE_BITS_MAX);
+ BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH - root_bits <=
+ BROTLI_REVERSE_BITS_MAX);
+
+ while (symbol_lists[max_length] == 0xFFFF) max_length--;
+ max_length += BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1;
+
+ table = root_table;
+ table_bits = root_bits;
+ table_size = 1 << table_bits;
+ total_size = table_size;
+
+ /* Fill in the root table. Reduce the table size to if possible,
+ and create the repetitions by memcpy. */
+ if (table_bits > max_length) {
+ table_bits = max_length;
+ table_size = 1 << table_bits;
+ }
+ key = 0;
+ key_step = BROTLI_REVERSE_BITS_LOWEST;
+ bits = 1;
+ step = 2;
+ do {
+ symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
+ for (bits_count = count[bits]; bits_count != 0; --bits_count) {
+ symbol = symbol_lists[symbol];
+ code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol);
+ ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
+ key += key_step;
+ }
+ step <<= 1;
+ key_step >>= 1;
+ } while (++bits <= table_bits);
+
+ /* If root_bits != table_bits then replicate to fill the remaining slots. */
+ while (total_size != table_size) {
+ memcpy(&table[table_size], &table[0],
+ (size_t)table_size * sizeof(table[0]));
+ table_size <<= 1;
+ }
+
+ /* Fill in 2nd level tables and add pointers to root table. */
+ key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1);
+ sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1);
+ sub_key_step = BROTLI_REVERSE_BITS_LOWEST;
+ for (len = root_bits + 1, step = 2; len <= max_length; ++len) {
+ symbol = len - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
+ for (; count[len] != 0; --count[len]) {
+ if (sub_key == (BROTLI_REVERSE_BITS_LOWEST << 1U)) {
+ table += table_size;
+ table_bits = NextTableBitSize(count, len, root_bits);
+ table_size = 1 << table_bits;
+ total_size += table_size;
+ sub_key = BrotliReverseBits(key);
+ key += key_step;
+ root_table[sub_key] = ConstructHuffmanCode(
+ (uint8_t)(table_bits + root_bits),
+ (uint16_t)(((size_t)(table - root_table)) - sub_key));
+ sub_key = 0;
+ }
+ symbol = symbol_lists[symbol];
+ code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol);
+ ReplicateValue(
+ &table[BrotliReverseBits(sub_key)], step, table_size, code);
+ sub_key += sub_key_step;
+ }
+ step <<= 1;
+ sub_key_step >>= 1;
+ }
+ return (uint32_t)total_size;
+}
+
+uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
+ int root_bits,
+ uint16_t* val,
+ uint32_t num_symbols) {
+ uint32_t table_size = 1;
+ const uint32_t goal_size = 1U << root_bits;
+ switch (num_symbols) {
+ case 0:
+ table[0] = ConstructHuffmanCode(0, val[0]);
+ break;
+ case 1:
+ if (val[1] > val[0]) {
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[1] = ConstructHuffmanCode(1, val[1]);
+ } else {
+ table[0] = ConstructHuffmanCode(1, val[1]);
+ table[1] = ConstructHuffmanCode(1, val[0]);
+ }
+ table_size = 2;
+ break;
+ case 2:
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[2] = ConstructHuffmanCode(1, val[0]);
+ if (val[2] > val[1]) {
+ table[1] = ConstructHuffmanCode(2, val[1]);
+ table[3] = ConstructHuffmanCode(2, val[2]);
+ } else {
+ table[1] = ConstructHuffmanCode(2, val[2]);
+ table[3] = ConstructHuffmanCode(2, val[1]);
+ }
+ table_size = 4;
+ break;
+ case 3: {
+ int i, k;
+ for (i = 0; i < 3; ++i) {
+ for (k = i + 1; k < 4; ++k) {
+ if (val[k] < val[i]) {
+ uint16_t t = val[k];
+ val[k] = val[i];
+ val[i] = t;
+ }
+ }
+ }
+ table[0] = ConstructHuffmanCode(2, val[0]);
+ table[2] = ConstructHuffmanCode(2, val[1]);
+ table[1] = ConstructHuffmanCode(2, val[2]);
+ table[3] = ConstructHuffmanCode(2, val[3]);
+ table_size = 4;
+ break;
+ }
+ case 4: {
+ if (val[3] < val[2]) {
+ uint16_t t = val[3];
+ val[3] = val[2];
+ val[2] = t;
+ }
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[1] = ConstructHuffmanCode(2, val[1]);
+ table[2] = ConstructHuffmanCode(1, val[0]);
+ table[3] = ConstructHuffmanCode(3, val[2]);
+ table[4] = ConstructHuffmanCode(1, val[0]);
+ table[5] = ConstructHuffmanCode(2, val[1]);
+ table[6] = ConstructHuffmanCode(1, val[0]);
+ table[7] = ConstructHuffmanCode(3, val[3]);
+ table_size = 8;
+ break;
+ }
+ }
+ while (table_size != goal_size) {
+ memcpy(&table[table_size], &table[0],
+ (size_t)table_size * sizeof(table[0]));
+ table_size <<= 1;
+ }
+ return goal_size;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.h
new file mode 100644
index 000000000..70e8469e3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/huffman.h
@@ -0,0 +1,128 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+#ifndef BROTLI_DEC_HUFFMAN_H_
+#define BROTLI_DEC_HUFFMAN_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
+
+/* Maximum possible Huffman table size for an alphabet size of (index * 32),
+ max code length 15 and root table bits 8. This table describes table sizes
+ for alphabets containing up to 1152 = 36 * 32 symbols. */
+static const uint16_t kMaxHuffmanTableSize[] = {
+ 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
+ 854, 886, 920, 952, 984, 1016, 1048, 1080, 1112, 1144, 1176, 1208, 1240, 1272,
+ 1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
+/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
+#define BROTLI_HUFFMAN_MAX_SIZE_26 396
+/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
+#define BROTLI_HUFFMAN_MAX_SIZE_258 632
+/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */
+#define BROTLI_HUFFMAN_MAX_SIZE_272 646
+
+#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
+
+#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \
+ BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0))
+#define BROTLI_HUFFMAN_CODE_FAST_LOAD
+#endif
+
+#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD)
+/* Do not create this struct directly - use the ConstructHuffmanCode
+ * constructor below! */
+typedef struct {
+ uint8_t bits; /* number of bits used for this symbol */
+ uint16_t value; /* symbol value or table offset */
+} HuffmanCode;
+
+static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
+ const uint16_t value) {
+ HuffmanCode h;
+ h.bits = bits;
+ h.value = value;
+ return h;
+}
+
+/* Please use the following macros to optimize HuffmanCode accesses in hot
+ * paths.
+ *
+ * For example, assuming |table| contains a HuffmanCode pointer:
+ *
+ * BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ * BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table);
+ * *bits = BROTLI_HC_GET_BITS(table);
+ * *value = BROTLI_HC_GET_VALUE(table);
+ * BROTLI_HC_ADJUST_TABLE_INDEX(table, offset);
+ * *bits2 = BROTLI_HC_GET_BITS(table);
+ * *value2 = BROTLI_HC_GET_VALUE(table);
+ *
+ */
+
+#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H)
+#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V)
+
+/* These must be given a HuffmanCode pointer! */
+#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits)
+#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value)
+
+#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
+
+typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
+
+static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
+ const uint16_t value) {
+ return ((value & 0xFFFF) << 16) | (bits & 0xFF);
+}
+
+#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
+#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H)
+
+/* These must be given a HuffmanCode pointer! */
+#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF)
+#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16)
+#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order. */
+BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
+ const uint8_t* const code_lengths, uint16_t* count);
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order.
+ Returns size of resulting table. */
+BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
+ int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
+
+/* Builds a simple Huffman table. The |num_symbols| parameter is to be
+ interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
+ 2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
+ 4 means 4 symbols with lengths [1, 2, 3, 3]. */
+BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
+ int root_bits, uint16_t* symbols, uint32_t num_symbols);
+
+/* Contains a collection of Huffman trees with the same alphabet size. */
+/* alphabet_size_limit is needed due to simple codes, since
+ log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
+typedef struct {
+ HuffmanCode** htrees;
+ HuffmanCode* codes;
+ uint16_t alphabet_size_max;
+ uint16_t alphabet_size_limit;
+ uint16_t num_htrees;
+} HuffmanTreeGroup;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_DEC_HUFFMAN_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/prefix.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/prefix.h
new file mode 100644
index 000000000..3ea062d84
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/prefix.h
@@ -0,0 +1,750 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Lookup tables to map prefix codes to value ranges. This is used during
+ decoding of the block lengths, literal insertion lengths and copy lengths. */
+
+#ifndef BROTLI_DEC_PREFIX_H_
+#define BROTLI_DEC_PREFIX_H_
+
+#include "../common/constants.h"
+#include <brotli/types.h>
+
+/* Represents the range of values belonging to a prefix code:
+ [offset, offset + 2^nbits) */
+struct PrefixCodeRange {
+ uint16_t offset;
+ uint8_t nbits;
+};
+
+static const struct PrefixCodeRange
+ kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
+ { 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
+ { 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
+ { 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
+ { 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
+ { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
+ { 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
+ {8433, 13}, {16625, 24}
+};
+
+typedef struct CmdLutElement {
+ uint8_t insert_len_extra_bits;
+ uint8_t copy_len_extra_bits;
+ int8_t distance_code;
+ uint8_t context;
+ uint16_t insert_len_offset;
+ uint16_t copy_len_offset;
+} CmdLutElement;
+
+static const CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ { 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
+ { 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
+ { 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
+ { 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
+ { 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
+ { 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
+ { 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
+ { 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
+ { 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
+ { 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
+ { 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
+ { 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
+ { 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
+ { 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
+ { 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
+ { 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
+ { 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
+ { 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
+ { 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
+ { 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
+ { 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
+ { 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
+ { 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
+ { 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
+ { 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
+ { 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
+ { 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
+ { 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
+ { 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
+ { 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
+ { 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
+ { 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
+ { 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
+ { 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
+ { 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
+ { 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
+ { 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
+ { 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
+ { 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
+ { 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
+ { 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
+ { 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
+ { 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
+ { 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
+ { 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
+ { 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
+ { 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
+ { 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
+ { 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
+ { 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
+ { 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
+ { 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
+ { 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
+ { 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
+ { 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
+ { 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
+ { 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
+ { 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
+ { 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
+ { 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
+ { 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
+ { 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
+ { 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
+ { 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
+ { 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
+ { 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
+ { 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
+ { 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
+ { 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
+ { 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
+ { 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
+ { 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
+ { 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
+ { 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
+ { 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
+ { 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
+ { 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
+ { 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
+ { 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
+ { 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
+ { 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
+ { 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
+ { 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
+ { 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
+ { 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
+ { 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
+ { 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
+ { 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
+ { 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
+ { 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
+ { 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
+ { 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
+ { 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
+ { 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
+ { 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
+ { 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
+ { 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
+ { 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
+ { 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
+ { 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
+ { 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
+ { 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
+ { 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
+ { 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
+ { 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
+ { 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
+ { 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
+ { 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
+ { 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
+ { 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
+ { 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
+ { 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
+ { 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
+ { 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
+ { 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
+ { 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
+ { 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
+ { 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
+ { 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
+ { 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
+ { 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
+ { 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
+ { 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
+ { 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
+ { 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
+ { 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
+ { 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
+ { 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
+ { 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
+ { 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
+ { 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
+ { 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
+ { 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
+ { 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
+ { 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
+ { 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
+ { 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
+ { 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
+ { 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
+ { 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
+ { 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
+ { 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
+ { 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
+ { 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
+ { 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
+ { 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
+ { 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
+ { 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
+ { 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
+ { 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
+ { 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
+ { 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
+ { 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
+ { 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
+ { 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
+ { 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
+ { 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
+ { 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
+ { 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
+ { 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
+ { 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
+ { 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
+ { 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
+ { 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
+ { 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
+ { 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
+ { 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
+ { 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
+ { 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
+ { 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
+ { 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
+ { 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
+ { 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
+ { 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
+ { 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
+ { 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
+ { 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
+ { 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
+ { 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
+ { 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
+ { 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
+ { 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
+ { 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
+ { 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
+ { 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
+ { 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
+ { 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
+ { 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
+ { 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
+ { 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
+ { 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
+ { 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
+ { 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
+ { 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
+ { 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
+ { 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
+ { 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
+ { 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
+ { 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
+ { 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
+ { 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
+ { 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
+ { 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
+ { 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
+ { 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
+ { 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
+ { 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
+ { 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
+ { 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
+ { 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
+ { 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
+ { 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
+ { 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
+ { 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
+ { 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
+ { 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
+ { 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
+ { 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
+ { 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
+ { 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
+ { 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
+ { 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
+ { 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
+ { 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
+ { 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
+ { 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
+ { 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
+ { 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
+ { 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
+ { 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
+ { 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
+ { 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
+ { 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
+ { 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
+ { 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
+ { 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
+ { 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
+ { 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
+ { 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
+ { 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
+ { 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
+ { 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
+ { 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
+ { 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
+ { 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
+ { 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
+ { 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
+ { 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
+ { 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
+ { 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
+ { 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
+ { 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
+ { 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
+ { 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
+ { 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
+ { 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
+ { 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
+ { 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
+ { 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
+ { 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
+ { 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
+ { 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
+ { 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
+ { 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
+ { 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
+ { 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
+ { 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
+ { 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
+ { 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
+ { 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
+ { 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
+ { 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
+ { 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
+ { 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
+ { 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
+ { 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
+ { 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
+ { 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
+ { 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
+ { 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
+ { 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
+ { 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
+ { 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
+ { 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
+ { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
+ { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
+ { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
+ { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
+ { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
+ { 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
+ { 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
+ { 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
+ { 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
+ { 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
+ { 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
+ { 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
+ { 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
+ { 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
+ { 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
+ { 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
+ { 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
+ { 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
+ { 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
+ { 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
+ { 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
+ { 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
+ { 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
+ { 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
+ { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
+ { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
+ { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
+ { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
+ { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
+ { 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
+ { 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
+ { 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
+ { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
+ { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
+ { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
+ { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
+ { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
+ { 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
+ { 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
+ { 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
+ { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
+ { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
+ { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
+ { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
+ { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
+ { 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
+ { 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
+ { 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
+ { 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
+ { 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
+ { 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
+ { 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
+ { 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
+ { 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
+ { 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
+ { 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
+ { 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
+ { 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
+ { 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
+ { 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
+ { 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
+ { 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
+ { 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
+ { 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
+ { 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
+ { 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
+ { 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
+ { 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
+ { 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
+ { 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
+ { 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
+ { 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
+ { 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
+ { 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
+ { 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
+ { 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
+ { 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
+ { 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
+ { 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
+ { 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
+ { 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
+ { 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
+ { 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
+ { 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
+ { 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
+ { 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
+ { 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
+ { 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
+ { 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
+ { 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
+ { 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
+ { 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
+ { 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
+ { 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
+ { 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
+ { 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
+ { 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
+ { 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
+ { 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
+ { 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
+ { 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
+ { 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
+ { 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
+ { 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
+ { 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
+ { 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
+ { 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
+ { 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
+ { 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
+ { 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
+ { 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
+ { 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
+ { 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
+ { 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
+ { 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
+ { 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
+ { 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
+ { 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
+ { 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
+ { 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
+ { 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
+ { 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
+ { 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
+ { 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
+ { 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
+ { 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
+ { 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
+ { 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
+ { 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
+ { 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
+ { 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
+ { 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
+ { 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
+ { 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
+ { 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
+ { 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
+ { 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
+ { 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
+ { 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
+ { 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
+ { 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
+ { 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
+ { 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
+ { 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
+ { 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
+ { 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
+ { 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
+ { 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
+ { 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
+ { 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
+ { 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
+ { 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
+ { 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
+ { 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
+ { 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
+ { 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
+ { 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
+ { 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
+ { 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
+ { 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
+ { 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
+ { 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
+ { 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
+ { 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
+ { 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
+ { 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
+ { 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
+ { 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
+ { 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
+ { 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
+ { 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
+ { 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
+ { 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
+ { 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
+ { 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
+ { 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
+ { 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
+ { 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
+ { 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
+ { 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
+ { 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
+ { 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
+ { 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
+ { 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
+ { 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
+ { 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
+ { 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
+ { 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
+ { 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
+ { 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
+ { 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
+ { 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
+ { 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
+ { 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
+ { 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
+ { 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
+ { 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
+ { 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
+ { 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
+ { 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
+ { 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
+ { 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
+ { 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
+ { 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
+ { 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
+ { 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
+ { 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
+ { 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
+ { 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
+ { 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
+ { 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
+ { 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
+ { 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
+ { 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
+ { 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
+ { 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
+ { 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
+ { 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
+ { 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
+ { 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
+ { 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
+ { 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
+ { 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
+ { 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
+ { 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
+ { 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
+ { 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
+ { 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
+ { 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
+ { 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
+ { 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
+ { 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
+ { 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
+ { 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
+ { 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
+ { 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
+ { 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
+ { 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
+ { 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
+ { 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
+ { 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
+ { 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
+ { 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
+ { 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
+ { 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
+};
+
+#endif /* BROTLI_DEC_PREFIX_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.c
new file mode 100644
index 000000000..6cf2476c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.c
@@ -0,0 +1,157 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./state.h"
+
+#include <stdlib.h> /* free, malloc */
+
+#include <brotli/types.h>
+#include "./huffman.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
+ if (!alloc_func) {
+ s->alloc_func = BrotliDefaultAllocFunc;
+ s->free_func = BrotliDefaultFreeFunc;
+ s->memory_manager_opaque = 0;
+ } else {
+ s->alloc_func = alloc_func;
+ s->free_func = free_func;
+ s->memory_manager_opaque = opaque;
+ }
+
+ s->error_code = 0; /* BROTLI_DECODER_NO_ERROR */
+
+ BrotliInitBitReader(&s->br);
+ s->state = BROTLI_STATE_UNINITED;
+ s->large_window = 0;
+ s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
+ s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
+ s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+
+ s->buffer_length = 0;
+ s->loop_counter = 0;
+ s->pos = 0;
+ s->rb_roundtrips = 0;
+ s->partial_pos_out = 0;
+
+ s->block_type_trees = NULL;
+ s->block_len_trees = NULL;
+ s->ringbuffer = NULL;
+ s->ringbuffer_size = 0;
+ s->new_ringbuffer_size = 0;
+ s->ringbuffer_mask = 0;
+
+ s->context_map = NULL;
+ s->context_modes = NULL;
+ s->dist_context_map = NULL;
+ s->context_map_slice = NULL;
+ s->dist_context_map_slice = NULL;
+
+ s->literal_hgroup.codes = NULL;
+ s->literal_hgroup.htrees = NULL;
+ s->insert_copy_hgroup.codes = NULL;
+ s->insert_copy_hgroup.htrees = NULL;
+ s->distance_hgroup.codes = NULL;
+ s->distance_hgroup.htrees = NULL;
+
+ s->is_last_metablock = 0;
+ s->is_uncompressed = 0;
+ s->is_metadata = 0;
+ s->should_wrap_ringbuffer = 0;
+ s->canny_ringbuffer_allocation = 1;
+
+ s->window_bits = 0;
+ s->max_distance = 0;
+ s->dist_rb[0] = 16;
+ s->dist_rb[1] = 15;
+ s->dist_rb[2] = 11;
+ s->dist_rb[3] = 4;
+ s->dist_rb_idx = 0;
+ s->block_type_trees = NULL;
+ s->block_len_trees = NULL;
+
+ s->mtf_upper_bound = 63;
+
+ s->dictionary = BrotliGetDictionary();
+ s->transforms = BrotliGetTransforms();
+
+ return BROTLI_TRUE;
+}
+
+void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
+ s->meta_block_remaining_len = 0;
+ s->block_length[0] = 1U << 24;
+ s->block_length[1] = 1U << 24;
+ s->block_length[2] = 1U << 24;
+ s->num_block_types[0] = 1;
+ s->num_block_types[1] = 1;
+ s->num_block_types[2] = 1;
+ s->block_type_rb[0] = 1;
+ s->block_type_rb[1] = 0;
+ s->block_type_rb[2] = 1;
+ s->block_type_rb[3] = 0;
+ s->block_type_rb[4] = 1;
+ s->block_type_rb[5] = 0;
+ s->context_map = NULL;
+ s->context_modes = NULL;
+ s->dist_context_map = NULL;
+ s->context_map_slice = NULL;
+ s->literal_htree = NULL;
+ s->dist_context_map_slice = NULL;
+ s->dist_htree_index = 0;
+ s->context_lookup = NULL;
+ s->literal_hgroup.codes = NULL;
+ s->literal_hgroup.htrees = NULL;
+ s->insert_copy_hgroup.codes = NULL;
+ s->insert_copy_hgroup.htrees = NULL;
+ s->distance_hgroup.codes = NULL;
+ s->distance_hgroup.htrees = NULL;
+}
+
+void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
+ BROTLI_DECODER_FREE(s, s->context_modes);
+ BROTLI_DECODER_FREE(s, s->context_map);
+ BROTLI_DECODER_FREE(s, s->dist_context_map);
+ BROTLI_DECODER_FREE(s, s->literal_hgroup.htrees);
+ BROTLI_DECODER_FREE(s, s->insert_copy_hgroup.htrees);
+ BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees);
+}
+
+void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
+ BrotliDecoderStateCleanupAfterMetablock(s);
+
+ BROTLI_DECODER_FREE(s, s->ringbuffer);
+ BROTLI_DECODER_FREE(s, s->block_type_trees);
+}
+
+BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
+ HuffmanTreeGroup* group, uint32_t alphabet_size_max,
+ uint32_t alphabet_size_limit, uint32_t ntrees) {
+ /* Pack two allocations into one */
+ const size_t max_table_size =
+ kMaxHuffmanTableSize[(alphabet_size_limit + 31) >> 5];
+ const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
+ const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
+ /* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
+ HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
+ code_size + htree_size);
+ group->alphabet_size_max = (uint16_t)alphabet_size_max;
+ group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
+ group->num_htrees = (uint16_t)ntrees;
+ group->htrees = p;
+ group->codes = (HuffmanCode*)(&p[ntrees]);
+ return !!p;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.h
new file mode 100644
index 000000000..54dab698b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/dec/state.h
@@ -0,0 +1,365 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Brotli state for partial streaming decoding. */
+
+#ifndef BROTLI_DEC_STATE_H_
+#define BROTLI_DEC_STATE_H_
+
+#include "../common/constants.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include "../common/transform.h"
+#include <brotli/types.h>
+#include "./bit_reader.h"
+#include "./huffman.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Graphviz diagram that describes state transitions:
+
+digraph States {
+ graph [compound=true]
+ concentrate=true
+ node [shape="box"]
+
+ UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
+ subgraph cluster_metablock_workflow {
+ style="rounded"
+ label=< <B>METABLOCK CYCLE</B> >
+ METABLOCK_BEGIN -> METABLOCK_HEADER
+ METABLOCK_HEADER:sw -> METADATA
+ METABLOCK_HEADER:s -> UNCOMPRESSED
+ METABLOCK_HEADER:se -> METABLOCK_DONE:ne
+ METADATA:s -> METABLOCK_DONE:w
+ UNCOMPRESSED:s -> METABLOCK_DONE:n
+ METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
+ }
+ INITIALIZE -> METABLOCK_BEGIN
+ METABLOCK_DONE -> DONE
+
+ subgraph cluster_compressed_metablock {
+ style="rounded"
+ label=< <B>COMPRESSED METABLOCK</B> >
+
+ subgraph cluster_command {
+ style="rounded"
+ label=< <B>HOT LOOP</B> >
+
+ _METABLOCK_DONE_PORT_ [shape=point style=invis]
+
+ {
+ // Set different shape for nodes returning from "compressed metablock".
+ node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
+ CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
+ }
+
+ CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
+
+ // IO ("write") nodes are not in the hot loop!
+ CMD_INNER_WRITE [style=dashed]
+ CMD_INNER -> CMD_INNER_WRITE
+ CMD_POST_WRITE_1 [style=dashed]
+ CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
+ CMD_POST_WRITE_2 [style=dashed]
+ CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
+
+ CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
+ CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
+ [constraint="false"]
+ CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
+ CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
+ CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
+ CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
+ {rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
+ CMD_POST_WRAP_COPY}
+ {rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
+
+ {CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
+ _METABLOCK_DONE_PORT_ [style=invis]
+ {CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
+ [constraint="false" style=invis]
+ }
+
+ BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
+ HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
+ HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
+ CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
+ TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
+ BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
+
+ HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
+ {rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
+ {rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
+ TREE_GROUP}
+ }
+ METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
+
+ _METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
+ [constraint="false" ltail=cluster_command]
+
+ UNINITED [shape=Mdiamond];
+ DONE [shape=Msquare];
+}
+
+
+ */
+
+typedef enum {
+ BROTLI_STATE_UNINITED,
+ BROTLI_STATE_LARGE_WINDOW_BITS,
+ BROTLI_STATE_INITIALIZE,
+ BROTLI_STATE_METABLOCK_BEGIN,
+ BROTLI_STATE_METABLOCK_HEADER,
+ BROTLI_STATE_METABLOCK_HEADER_2,
+ BROTLI_STATE_CONTEXT_MODES,
+ BROTLI_STATE_COMMAND_BEGIN,
+ BROTLI_STATE_COMMAND_INNER,
+ BROTLI_STATE_COMMAND_POST_DECODE_LITERALS,
+ BROTLI_STATE_COMMAND_POST_WRAP_COPY,
+ BROTLI_STATE_UNCOMPRESSED,
+ BROTLI_STATE_METADATA,
+ BROTLI_STATE_COMMAND_INNER_WRITE,
+ BROTLI_STATE_METABLOCK_DONE,
+ BROTLI_STATE_COMMAND_POST_WRITE_1,
+ BROTLI_STATE_COMMAND_POST_WRITE_2,
+ BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
+ BROTLI_STATE_HUFFMAN_CODE_0,
+ BROTLI_STATE_HUFFMAN_CODE_1,
+ BROTLI_STATE_HUFFMAN_CODE_2,
+ BROTLI_STATE_HUFFMAN_CODE_3,
+ BROTLI_STATE_CONTEXT_MAP_1,
+ BROTLI_STATE_CONTEXT_MAP_2,
+ BROTLI_STATE_TREE_GROUP,
+ BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
+ BROTLI_STATE_DONE
+} BrotliRunningState;
+
+typedef enum {
+ BROTLI_STATE_METABLOCK_HEADER_NONE,
+ BROTLI_STATE_METABLOCK_HEADER_EMPTY,
+ BROTLI_STATE_METABLOCK_HEADER_NIBBLES,
+ BROTLI_STATE_METABLOCK_HEADER_SIZE,
+ BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED,
+ BROTLI_STATE_METABLOCK_HEADER_RESERVED,
+ BROTLI_STATE_METABLOCK_HEADER_BYTES,
+ BROTLI_STATE_METABLOCK_HEADER_METADATA
+} BrotliRunningMetablockHeaderState;
+
+typedef enum {
+ BROTLI_STATE_UNCOMPRESSED_NONE,
+ BROTLI_STATE_UNCOMPRESSED_WRITE
+} BrotliRunningUncompressedState;
+
+typedef enum {
+ BROTLI_STATE_TREE_GROUP_NONE,
+ BROTLI_STATE_TREE_GROUP_LOOP
+} BrotliRunningTreeGroupState;
+
+typedef enum {
+ BROTLI_STATE_CONTEXT_MAP_NONE,
+ BROTLI_STATE_CONTEXT_MAP_READ_PREFIX,
+ BROTLI_STATE_CONTEXT_MAP_HUFFMAN,
+ BROTLI_STATE_CONTEXT_MAP_DECODE,
+ BROTLI_STATE_CONTEXT_MAP_TRANSFORM
+} BrotliRunningContextMapState;
+
+typedef enum {
+ BROTLI_STATE_HUFFMAN_NONE,
+ BROTLI_STATE_HUFFMAN_SIMPLE_SIZE,
+ BROTLI_STATE_HUFFMAN_SIMPLE_READ,
+ BROTLI_STATE_HUFFMAN_SIMPLE_BUILD,
+ BROTLI_STATE_HUFFMAN_COMPLEX,
+ BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS
+} BrotliRunningHuffmanState;
+
+typedef enum {
+ BROTLI_STATE_DECODE_UINT8_NONE,
+ BROTLI_STATE_DECODE_UINT8_SHORT,
+ BROTLI_STATE_DECODE_UINT8_LONG
+} BrotliRunningDecodeUint8State;
+
+typedef enum {
+ BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
+ BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
+} BrotliRunningReadBlockLengthState;
+
+typedef struct BrotliMetablockHeaderArena {
+ BrotliRunningTreeGroupState substate_tree_group;
+ BrotliRunningContextMapState substate_context_map;
+ BrotliRunningHuffmanState substate_huffman;
+
+ uint32_t sub_loop_counter;
+
+ uint32_t repeat_code_len;
+ uint32_t prev_code_len;
+
+ /* For ReadHuffmanCode. */
+ uint32_t symbol;
+ uint32_t repeat;
+ uint32_t space;
+
+ /* Huffman table for "histograms". */
+ HuffmanCode table[32];
+ /* List of heads of symbol chains. */
+ uint16_t* symbol_lists;
+ /* Storage from symbol_lists. */
+ uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
+ BROTLI_NUM_COMMAND_SYMBOLS];
+ /* Tails of symbol chains. */
+ int next_symbol[32];
+ uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
+ /* Population counts for the code lengths. */
+ uint16_t code_length_histo[16];
+
+ /* For HuffmanTreeGroupDecode. */
+ int htree_index;
+ HuffmanCode* next;
+
+ /* For DecodeContextMap. */
+ uint32_t context_index;
+ uint32_t max_run_length_prefix;
+ uint32_t code;
+ HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
+} BrotliMetablockHeaderArena;
+
+typedef struct BrotliMetablockBodyArena {
+ uint8_t dist_extra_bits[544];
+ uint32_t dist_offset[544];
+} BrotliMetablockBodyArena;
+
+struct BrotliDecoderStateStruct {
+ BrotliRunningState state;
+
+ /* This counter is reused for several disjoint loops. */
+ int loop_counter;
+
+ BrotliBitReader br;
+
+ brotli_alloc_func alloc_func;
+ brotli_free_func free_func;
+ void* memory_manager_opaque;
+
+ /* Temporary storage for remaining input. Brotli stream format is designed in
+ a way, that 64 bits are enough to make progress in decoding. */
+ union {
+ uint64_t u64;
+ uint8_t u8[8];
+ } buffer;
+ uint32_t buffer_length;
+
+ int pos;
+ int max_backward_distance;
+ int max_distance;
+ int ringbuffer_size;
+ int ringbuffer_mask;
+ int dist_rb_idx;
+ int dist_rb[4];
+ int error_code;
+ uint8_t* ringbuffer;
+ uint8_t* ringbuffer_end;
+ HuffmanCode* htree_command;
+ const uint8_t* context_lookup;
+ uint8_t* context_map_slice;
+ uint8_t* dist_context_map_slice;
+
+ /* This ring buffer holds a few past copy distances that will be used by
+ some special distance codes. */
+ HuffmanTreeGroup literal_hgroup;
+ HuffmanTreeGroup insert_copy_hgroup;
+ HuffmanTreeGroup distance_hgroup;
+ HuffmanCode* block_type_trees;
+ HuffmanCode* block_len_trees;
+ /* This is true if the literal context map histogram type always matches the
+ block type. It is then not needed to keep the context (faster decoding). */
+ int trivial_literal_context;
+ /* Distance context is actual after command is decoded and before distance is
+ computed. After distance computation it is used as a temporary variable. */
+ int distance_context;
+ int meta_block_remaining_len;
+ uint32_t block_length_index;
+ uint32_t block_length[3];
+ uint32_t num_block_types[3];
+ uint32_t block_type_rb[6];
+ uint32_t distance_postfix_bits;
+ uint32_t num_direct_distance_codes;
+ uint32_t num_dist_htrees;
+ uint8_t* dist_context_map;
+ HuffmanCode* literal_htree;
+ uint8_t dist_htree_index;
+
+ int copy_length;
+ int distance_code;
+
+ /* For partial write operations. */
+ size_t rb_roundtrips; /* how many times we went around the ring-buffer */
+ size_t partial_pos_out; /* how much output to the user in total */
+
+ /* For InverseMoveToFrontTransform. */
+ uint32_t mtf_upper_bound;
+ uint32_t mtf[64 + 1];
+
+ /* Less used attributes are at the end of this struct. */
+
+ /* States inside function calls. */
+ BrotliRunningMetablockHeaderState substate_metablock_header;
+ BrotliRunningUncompressedState substate_uncompressed;
+ BrotliRunningDecodeUint8State substate_decode_uint8;
+ BrotliRunningReadBlockLengthState substate_read_block_length;
+
+ unsigned int is_last_metablock : 1;
+ unsigned int is_uncompressed : 1;
+ unsigned int is_metadata : 1;
+ unsigned int should_wrap_ringbuffer : 1;
+ unsigned int canny_ringbuffer_allocation : 1;
+ unsigned int large_window : 1;
+ unsigned int size_nibbles : 8;
+ uint32_t window_bits;
+
+ int new_ringbuffer_size;
+
+ uint32_t num_literal_htrees;
+ uint8_t* context_map;
+ uint8_t* context_modes;
+
+ const BrotliDictionary* dictionary;
+ const BrotliTransforms* transforms;
+
+ uint32_t trivial_literal_contexts[8]; /* 256 bits */
+
+ union {
+ BrotliMetablockHeaderArena header;
+ BrotliMetablockBodyArena body;
+ } arena;
+};
+
+typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
+#define BrotliDecoderState BrotliDecoderStateInternal
+
+BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
+BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s);
+BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
+BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
+ BrotliDecoderState* s);
+BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
+ BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
+ uint32_t alphabet_size_limit, uint32_t ntrees);
+
+#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
+
+#define BROTLI_DECODER_FREE(S, X) { \
+ S->free_func(S->memory_manager_opaque, X); \
+ X = NULL; \
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_DEC_STATE_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.c
new file mode 100644
index 000000000..a07a617a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.c
@@ -0,0 +1,145 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+#include "./backward_references.h"
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./dictionary_hash.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
+ size_t max_distance,
+ const int* dist_cache) {
+ if (distance <= max_distance) {
+ size_t distance_plus_3 = distance + 3;
+ size_t offset0 = distance_plus_3 - (size_t)dist_cache[0];
+ size_t offset1 = distance_plus_3 - (size_t)dist_cache[1];
+ if (distance == (size_t)dist_cache[0]) {
+ return 0;
+ } else if (distance == (size_t)dist_cache[1]) {
+ return 1;
+ } else if (offset0 < 7) {
+ return (0x9750468 >> (4 * offset0)) & 0xF;
+ } else if (offset1 < 7) {
+ return (0xFDB1ACE >> (4 * offset1)) & 0xF;
+ } else if (distance == (size_t)dist_cache[2]) {
+ return 2;
+ } else if (distance == (size_t)dist_cache[3]) {
+ return 3;
+ }
+ }
+ return distance + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
+}
+
+#define EXPAND_CAT(a, b) CAT(a, b)
+#define CAT(a, b) a ## b
+#define FN(X) EXPAND_CAT(X, HASHER())
+#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
+
+#define PREFIX() N
+
+#define HASHER() H2
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H3
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H4
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H5
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H6
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H40
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H41
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H42
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H54
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H35
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H55
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#define HASHER() H65
+/* NOLINTNEXTLINE(build/include) */
+#include "./backward_references_inc.h"
+#undef HASHER
+
+#undef PREFIX
+
+#undef EXPORT_FN
+#undef FN
+#undef CAT
+#undef EXPAND_CAT
+
+void BrotliCreateBackwardReferences(size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals) {
+ switch (params->hasher.type) {
+#define CASE_(N) \
+ case N: \
+ CreateBackwardReferencesNH ## N(num_bytes, \
+ position, ringbuffer, ringbuffer_mask, \
+ literal_context_lut, params, hasher, dist_cache, \
+ last_insert_len, commands, num_commands, num_literals); \
+ return;
+ FOR_GENERIC_HASHERS(CASE_)
+#undef CASE_
+ default:
+ break;
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.h
new file mode 100644
index 000000000..9589cc154
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references.h
@@ -0,0 +1,39 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_
+#define BROTLI_ENC_BACKWARD_REFERENCES_H_
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./hash.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* "commands" points to the next output command to write to, "*num_commands" is
+ initially the total amount of commands output by previous
+ CreateBackwardReferences calls, and must be incremented by the amount written
+ by this call. */
+BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_BACKWARD_REFERENCES_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.c
new file mode 100644
index 000000000..5651caeb7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.c
@@ -0,0 +1,843 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+#include "./backward_references_hq.h"
+
+#include <string.h> /* memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./fast_log.h"
+#include "./find_match_length.h"
+#include "./literal_cost.h"
+#include "./memory.h"
+#include "./params.h"
+#include "./prefix.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
+#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
+
+static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
+
+static const uint32_t kDistanceCacheIndex[] = {
+ 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+};
+static const int kDistanceCacheOffset[] = {
+ 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
+};
+
+void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
+ ZopfliNode stub;
+ size_t i;
+ stub.length = 1;
+ stub.distance = 0;
+ stub.dcode_insert_length = 0;
+ stub.u.cost = kInfinity;
+ for (i = 0; i < length; ++i) array[i] = stub;
+}
+
+static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
+ return self->length & 0x1FFFFFF;
+}
+
+static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
+ const uint32_t modifier = self->length >> 25;
+ return ZopfliNodeCopyLength(self) + 9u - modifier;
+}
+
+static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
+ return self->distance;
+}
+
+static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
+ const uint32_t short_code = self->dcode_insert_length >> 27;
+ return short_code == 0 ?
+ ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
+ short_code - 1;
+}
+
+static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
+ return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
+}
+
+/* Histogram based cost model for zopflification. */
+typedef struct ZopfliCostModel {
+ /* The insert and copy length symbols. */
+ float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
+ float* cost_dist_;
+ uint32_t distance_histogram_size;
+ /* Cumulative costs of literals per position in the stream. */
+ float* literal_costs_;
+ float min_cost_cmd_;
+ size_t num_bytes_;
+} ZopfliCostModel;
+
+static void InitZopfliCostModel(
+ MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
+ size_t num_bytes) {
+ self->num_bytes_ = num_bytes;
+ self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
+ self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
+ self->distance_histogram_size = dist->alphabet_size_limit;
+ if (BROTLI_IS_OOM(m)) return;
+}
+
+static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
+ BROTLI_FREE(m, self->literal_costs_);
+ BROTLI_FREE(m, self->cost_dist_);
+}
+
+static void SetCost(const uint32_t* histogram, size_t histogram_size,
+ BROTLI_BOOL literal_histogram, float* cost) {
+ size_t sum = 0;
+ size_t missing_symbol_sum;
+ float log2sum;
+ float missing_symbol_cost;
+ size_t i;
+ for (i = 0; i < histogram_size; i++) {
+ sum += histogram[i];
+ }
+ log2sum = (float)FastLog2(sum);
+ missing_symbol_sum = sum;
+ if (!literal_histogram) {
+ for (i = 0; i < histogram_size; i++) {
+ if (histogram[i] == 0) missing_symbol_sum++;
+ }
+ }
+ missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
+ for (i = 0; i < histogram_size; i++) {
+ if (histogram[i] == 0) {
+ cost[i] = missing_symbol_cost;
+ continue;
+ }
+
+ /* Shannon bits for this symbol. */
+ cost[i] = log2sum - (float)FastLog2(histogram[i]);
+
+ /* Cannot be coded with less than 1 bit */
+ if (cost[i] < 1) cost[i] = 1;
+ }
+}
+
+static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
+ size_t position,
+ const uint8_t* ringbuffer,
+ size_t ringbuffer_mask,
+ const Command* commands,
+ size_t num_commands,
+ size_t last_insert_len) {
+ uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
+ float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
+ size_t pos = position - last_insert_len;
+ float min_cost_cmd = kInfinity;
+ size_t i;
+ float* cost_cmd = self->cost_cmd_;
+
+ memset(histogram_literal, 0, sizeof(histogram_literal));
+ memset(histogram_cmd, 0, sizeof(histogram_cmd));
+ memset(histogram_dist, 0, sizeof(histogram_dist));
+
+ for (i = 0; i < num_commands; i++) {
+ size_t inslength = commands[i].insert_len_;
+ size_t copylength = CommandCopyLen(&commands[i]);
+ size_t distcode = commands[i].dist_prefix_ & 0x3FF;
+ size_t cmdcode = commands[i].cmd_prefix_;
+ size_t j;
+
+ histogram_cmd[cmdcode]++;
+ if (cmdcode >= 128) histogram_dist[distcode]++;
+
+ for (j = 0; j < inslength; j++) {
+ histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
+ }
+
+ pos += inslength + copylength;
+ }
+
+ SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
+ cost_literal);
+ SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
+ cost_cmd);
+ SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
+ self->cost_dist_);
+
+ for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
+ min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
+ }
+ self->min_cost_cmd_ = min_cost_cmd;
+
+ {
+ float* literal_costs = self->literal_costs_;
+ float literal_carry = 0.0;
+ size_t num_bytes = self->num_bytes_;
+ literal_costs[0] = 0.0;
+ for (i = 0; i < num_bytes; ++i) {
+ literal_carry +=
+ cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
+ literal_costs[i + 1] = literal_costs[i] + literal_carry;
+ literal_carry -= literal_costs[i + 1] - literal_costs[i];
+ }
+ }
+}
+
+static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
+ size_t position,
+ const uint8_t* ringbuffer,
+ size_t ringbuffer_mask) {
+ float* literal_costs = self->literal_costs_;
+ float literal_carry = 0.0;
+ float* cost_dist = self->cost_dist_;
+ float* cost_cmd = self->cost_cmd_;
+ size_t num_bytes = self->num_bytes_;
+ size_t i;
+ BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
+ ringbuffer, &literal_costs[1]);
+ literal_costs[0] = 0.0;
+ for (i = 0; i < num_bytes; ++i) {
+ literal_carry += literal_costs[i + 1];
+ literal_costs[i + 1] = literal_costs[i] + literal_carry;
+ literal_carry -= literal_costs[i + 1] - literal_costs[i];
+ }
+ for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
+ cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
+ }
+ for (i = 0; i < self->distance_histogram_size; ++i) {
+ cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
+ }
+ self->min_cost_cmd_ = (float)FastLog2(11);
+}
+
+static BROTLI_INLINE float ZopfliCostModelGetCommandCost(
+ const ZopfliCostModel* self, uint16_t cmdcode) {
+ return self->cost_cmd_[cmdcode];
+}
+
+static BROTLI_INLINE float ZopfliCostModelGetDistanceCost(
+ const ZopfliCostModel* self, size_t distcode) {
+ return self->cost_dist_[distcode];
+}
+
+static BROTLI_INLINE float ZopfliCostModelGetLiteralCosts(
+ const ZopfliCostModel* self, size_t from, size_t to) {
+ return self->literal_costs_[to] - self->literal_costs_[from];
+}
+
+static BROTLI_INLINE float ZopfliCostModelGetMinCostCmd(
+ const ZopfliCostModel* self) {
+ return self->min_cost_cmd_;
+}
+
+/* REQUIRES: len >= 2, start_pos <= pos */
+/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
+/* Maintains the "ZopfliNode array invariant". */
+static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
+ size_t start_pos, size_t len, size_t len_code, size_t dist,
+ size_t short_code, float cost) {
+ ZopfliNode* next = &nodes[pos + len];
+ next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
+ next->distance = (uint32_t)dist;
+ next->dcode_insert_length = (uint32_t)(
+ (short_code << 27) | (pos - start_pos));
+ next->u.cost = cost;
+}
+
+typedef struct PosData {
+ size_t pos;
+ int distance_cache[4];
+ float costdiff;
+ float cost;
+} PosData;
+
+/* Maintains the smallest 8 cost difference together with their positions */
+typedef struct StartPosQueue {
+ PosData q_[8];
+ size_t idx_;
+} StartPosQueue;
+
+static BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) {
+ self->idx_ = 0;
+}
+
+static size_t StartPosQueueSize(const StartPosQueue* self) {
+ return BROTLI_MIN(size_t, self->idx_, 8);
+}
+
+static void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) {
+ size_t offset = ~(self->idx_++) & 7;
+ size_t len = StartPosQueueSize(self);
+ size_t i;
+ PosData* q = self->q_;
+ q[offset] = *posdata;
+ /* Restore the sorted order. In the list of |len| items at most |len - 1|
+ adjacent element comparisons / swaps are required. */
+ for (i = 1; i < len; ++i) {
+ if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) {
+ BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7);
+ }
+ ++offset;
+ }
+}
+
+static const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) {
+ return &self->q_[(k - self->idx_) & 7];
+}
+
+/* Returns the minimum possible copy length that can improve the cost of any */
+/* future position. */
+static size_t ComputeMinimumCopyLength(const float start_cost,
+ const ZopfliNode* nodes,
+ const size_t num_bytes,
+ const size_t pos) {
+ /* Compute the minimum possible cost of reaching any future position. */
+ float min_cost = start_cost;
+ size_t len = 2;
+ size_t next_len_bucket = 4;
+ size_t next_len_offset = 10;
+ while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) {
+ /* We already reached (pos + len) with no more cost than the minimum
+ possible cost of reaching anything from this pos, so there is no point in
+ looking for lengths <= len. */
+ ++len;
+ if (len == next_len_offset) {
+ /* We reached the next copy length code bucket, so we add one more
+ extra bit to the minimum cost. */
+ min_cost += 1.0f;
+ next_len_offset += next_len_bucket;
+ next_len_bucket *= 2;
+ }
+ }
+ return len;
+}
+
+/* REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+static uint32_t ComputeDistanceShortcut(const size_t block_start,
+ const size_t pos,
+ const size_t max_backward_limit,
+ const size_t gap,
+ const ZopfliNode* nodes) {
+ const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
+ const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
+ const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
+ /* Since |block_start + pos| is the end position of the command, the copy part
+ starts from |block_start + pos - clen|. Distances that are greater than
+ this or greater than |max_backward_limit| + |gap| are static dictionary
+ references, and do not update the last distances.
+ Also distance code 0 (last distance) does not update the last distances. */
+ if (pos == 0) {
+ return 0;
+ } else if (dist + clen <= block_start + pos + gap &&
+ dist <= max_backward_limit + gap &&
+ ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
+ return (uint32_t)pos;
+ } else {
+ return nodes[pos - clen - ilen].u.shortcut;
+ }
+}
+
+/* Fills in dist_cache[0..3] with the last four distances (as defined by
+ Section 4. of the Spec) that would be used at (block_start + pos) if we
+ used the shortest path of commands from block_start, computed from
+ nodes[0..pos]. The last four distances at block_start are in
+ starting_dist_cache[0..3].
+ REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+static void ComputeDistanceCache(const size_t pos,
+ const int* starting_dist_cache,
+ const ZopfliNode* nodes,
+ int* dist_cache) {
+ int idx = 0;
+ size_t p = nodes[pos].u.shortcut;
+ while (idx < 4 && p > 0) {
+ const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
+ const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
+ const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
+ dist_cache[idx++] = (int)dist;
+ /* Because of prerequisite, p >= clen + ilen >= 2. */
+ p = nodes[p - clen - ilen].u.shortcut;
+ }
+ for (; idx < 4; ++idx) {
+ dist_cache[idx] = *starting_dist_cache++;
+ }
+}
+
+/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
+ is eligible. */
+static void EvaluateNode(
+ const size_t block_start, const size_t pos, const size_t max_backward_limit,
+ const size_t gap, const int* starting_dist_cache,
+ const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) {
+ /* Save cost, because ComputeDistanceCache invalidates it. */
+ float node_cost = nodes[pos].u.cost;
+ nodes[pos].u.shortcut = ComputeDistanceShortcut(
+ block_start, pos, max_backward_limit, gap, nodes);
+ if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
+ PosData posdata;
+ posdata.pos = pos;
+ posdata.cost = node_cost;
+ posdata.costdiff = node_cost -
+ ZopfliCostModelGetLiteralCosts(model, 0, pos);
+ ComputeDistanceCache(
+ pos, starting_dist_cache, nodes, posdata.distance_cache);
+ StartPosQueuePush(queue, &posdata);
+ }
+}
+
+/* Returns longest copy length. */
+static size_t UpdateNodes(
+ const size_t num_bytes, const size_t block_start, const size_t pos,
+ const uint8_t* ringbuffer, const size_t ringbuffer_mask,
+ const BrotliEncoderParams* params, const size_t max_backward_limit,
+ const int* starting_dist_cache, const size_t num_matches,
+ const BackwardMatch* matches, const ZopfliCostModel* model,
+ StartPosQueue* queue, ZopfliNode* nodes) {
+ const size_t stream_offset = params->stream_offset;
+ const size_t cur_ix = block_start + pos;
+ const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
+ const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
+ const size_t dictionary_start = BROTLI_MIN(size_t,
+ cur_ix + stream_offset, max_backward_limit);
+ const size_t max_len = num_bytes - pos;
+ const size_t max_zopfli_len = MaxZopfliLen(params);
+ const size_t max_iters = MaxZopfliCandidates(params);
+ size_t min_len;
+ size_t result = 0;
+ size_t k;
+ size_t gap = 0;
+
+ EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
+ starting_dist_cache, model, queue, nodes);
+
+ {
+ const PosData* posdata = StartPosQueueAt(queue, 0);
+ float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
+ ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
+ min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
+ }
+
+ /* Go over the command starting positions in order of increasing cost
+ difference. */
+ for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) {
+ const PosData* posdata = StartPosQueueAt(queue, k);
+ const size_t start = posdata->pos;
+ const uint16_t inscode = GetInsertLengthCode(pos - start);
+ const float start_costdiff = posdata->costdiff;
+ const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
+ ZopfliCostModelGetLiteralCosts(model, 0, pos);
+
+ /* Look for last distance matches using the distance cache from this
+ starting position. */
+ size_t best_len = min_len - 1;
+ size_t j = 0;
+ for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) {
+ const size_t idx = kDistanceCacheIndex[j];
+ const size_t backward =
+ (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
+ size_t prev_ix = cur_ix - backward;
+ size_t len = 0;
+ uint8_t continuation = ringbuffer[cur_ix_masked + best_len];
+ if (cur_ix_masked + best_len > ringbuffer_mask) {
+ break;
+ }
+ if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
+ /* Word dictionary -> ignore. */
+ continue;
+ }
+ if (backward <= max_distance) {
+ /* Regular backward reference. */
+ if (prev_ix >= cur_ix) {
+ continue;
+ }
+
+ prev_ix &= ringbuffer_mask;
+ if (prev_ix + best_len > ringbuffer_mask ||
+ continuation != ringbuffer[prev_ix + best_len]) {
+ continue;
+ }
+ len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
+ &ringbuffer[cur_ix_masked],
+ max_len);
+ } else {
+ /* "Gray" area. It is addressable by decoder, but this encoder
+ instance does not have that data -> should not touch it. */
+ continue;
+ }
+ {
+ const float dist_cost = base_cost +
+ ZopfliCostModelGetDistanceCost(model, j);
+ size_t l;
+ for (l = best_len + 1; l <= len; ++l) {
+ const uint16_t copycode = GetCopyLengthCode(l);
+ const uint16_t cmdcode =
+ CombineLengthCodes(inscode, copycode, j == 0);
+ const float cost = (cmdcode < 128 ? base_cost : dist_cost) +
+ (float)GetCopyExtra(copycode) +
+ ZopfliCostModelGetCommandCost(model, cmdcode);
+ if (cost < nodes[pos + l].u.cost) {
+ UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
+ result = BROTLI_MAX(size_t, result, l);
+ }
+ best_len = l;
+ }
+ }
+ }
+
+ /* At higher iterations look only for new last distance matches, since
+ looking only for new command start positions with the same distances
+ does not help much. */
+ if (k >= 2) continue;
+
+ {
+ /* Loop through all possible copy lengths at this position. */
+ size_t len = min_len;
+ for (j = 0; j < num_matches; ++j) {
+ BackwardMatch match = matches[j];
+ size_t dist = match.distance;
+ BROTLI_BOOL is_dictionary_match =
+ TO_BROTLI_BOOL(dist > dictionary_start + gap);
+ /* We already tried all possible last distance matches, so we can use
+ normal distance code here. */
+ size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
+ uint16_t dist_symbol;
+ uint32_t distextra;
+ uint32_t distnumextra;
+ float dist_cost;
+ size_t max_match_len;
+ PrefixEncodeCopyDistance(
+ dist_code, params->dist.num_direct_distance_codes,
+ params->dist.distance_postfix_bits, &dist_symbol, &distextra);
+ distnumextra = dist_symbol >> 10;
+ dist_cost = base_cost + (float)distnumextra +
+ ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
+
+ /* Try all copy lengths up until the maximum copy length corresponding
+ to this distance. If the distance refers to the static dictionary, or
+ the maximum length is long enough, try only one maximum length. */
+ max_match_len = BackwardMatchLength(&match);
+ if (len < max_match_len &&
+ (is_dictionary_match || max_match_len > max_zopfli_len)) {
+ len = max_match_len;
+ }
+ for (; len <= max_match_len; ++len) {
+ const size_t len_code =
+ is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
+ const uint16_t copycode = GetCopyLengthCode(len_code);
+ const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0);
+ const float cost = dist_cost + (float)GetCopyExtra(copycode) +
+ ZopfliCostModelGetCommandCost(model, cmdcode);
+ if (cost < nodes[pos + len].u.cost) {
+ UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
+ result = BROTLI_MAX(size_t, result, len);
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static size_t ComputeShortestPathFromNodes(size_t num_bytes,
+ ZopfliNode* nodes) {
+ size_t index = num_bytes;
+ size_t num_commands = 0;
+ while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
+ nodes[index].length == 1) --index;
+ nodes[index].u.next = BROTLI_UINT32_MAX;
+ while (index != 0) {
+ size_t len = ZopfliNodeCommandLength(&nodes[index]);
+ index -= len;
+ nodes[index].u.next = (uint32_t)len;
+ num_commands++;
+ }
+ return num_commands;
+}
+
+/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
+void BrotliZopfliCreateCommands(const size_t num_bytes,
+ const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
+ size_t* last_insert_len, const BrotliEncoderParams* params,
+ Command* commands, size_t* num_literals) {
+ const size_t stream_offset = params->stream_offset;
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+ size_t pos = 0;
+ uint32_t offset = nodes[0].u.next;
+ size_t i;
+ size_t gap = 0;
+ for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
+ const ZopfliNode* next = &nodes[pos + offset];
+ size_t copy_length = ZopfliNodeCopyLength(next);
+ size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
+ pos += insert_length;
+ offset = next->u.next;
+ if (i == 0) {
+ insert_length += *last_insert_len;
+ *last_insert_len = 0;
+ }
+ {
+ size_t distance = ZopfliNodeCopyDistance(next);
+ size_t len_code = ZopfliNodeLengthCode(next);
+ size_t dictionary_start = BROTLI_MIN(size_t,
+ block_start + pos + stream_offset, max_backward_limit);
+ BROTLI_BOOL is_dictionary =
+ TO_BROTLI_BOOL(distance > dictionary_start + gap);
+ size_t dist_code = ZopfliNodeDistanceCode(next);
+ InitCommand(&commands[i], &params->dist, insert_length,
+ copy_length, (int)len_code - (int)copy_length, dist_code);
+
+ if (!is_dictionary && dist_code > 0) {
+ dist_cache[3] = dist_cache[2];
+ dist_cache[2] = dist_cache[1];
+ dist_cache[1] = dist_cache[0];
+ dist_cache[0] = (int)distance;
+ }
+ }
+
+ *num_literals += insert_length;
+ pos += copy_length;
+ }
+ *last_insert_len += num_bytes - pos;
+}
+
+static size_t ZopfliIterate(size_t num_bytes, size_t position,
+ const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
+ const ZopfliCostModel* model, const uint32_t* num_matches,
+ const BackwardMatch* matches, ZopfliNode* nodes) {
+ const size_t stream_offset = params->stream_offset;
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+ const size_t max_zopfli_len = MaxZopfliLen(params);
+ StartPosQueue queue;
+ size_t cur_match_pos = 0;
+ size_t i;
+ nodes[0].length = 0;
+ nodes[0].u.cost = 0;
+ InitStartPosQueue(&queue);
+ for (i = 0; i + 3 < num_bytes; i++) {
+ size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer,
+ ringbuffer_mask, params, max_backward_limit, dist_cache,
+ num_matches[i], &matches[cur_match_pos], model, &queue, nodes);
+ if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
+ cur_match_pos += num_matches[i];
+ if (num_matches[i] == 1 &&
+ BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) {
+ skip = BROTLI_MAX(size_t,
+ BackwardMatchLength(&matches[cur_match_pos - 1]), skip);
+ }
+ if (skip > 1) {
+ skip--;
+ while (skip) {
+ i++;
+ if (i + 3 >= num_bytes) break;
+ EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
+ dist_cache, model, &queue, nodes);
+ cur_match_pos += num_matches[i];
+ skip--;
+ }
+ }
+ }
+ return ComputeShortestPathFromNodes(num_bytes, nodes);
+}
+
+/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
+size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
+ const size_t stream_offset = params->stream_offset;
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+ const size_t max_zopfli_len = MaxZopfliLen(params);
+ ZopfliCostModel model;
+ StartPosQueue queue;
+ BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
+ const size_t store_end = num_bytes >= StoreLookaheadH10() ?
+ position + num_bytes - StoreLookaheadH10() + 1 : position;
+ size_t i;
+ size_t gap = 0;
+ size_t lz_matches_offset = 0;
+ BROTLI_UNUSED(literal_context_lut);
+ nodes[0].length = 0;
+ nodes[0].u.cost = 0;
+ InitZopfliCostModel(m, &model, &params->dist, num_bytes);
+ if (BROTLI_IS_OOM(m)) return 0;
+ ZopfliCostModelSetFromLiteralCosts(
+ &model, position, ringbuffer, ringbuffer_mask);
+ InitStartPosQueue(&queue);
+ for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
+ const size_t pos = position + i;
+ const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
+ const size_t dictionary_start = BROTLI_MIN(size_t,
+ pos + stream_offset, max_backward_limit);
+ size_t skip;
+ size_t num_matches;
+ num_matches = FindAllMatchesH10(&hasher->privat._H10,
+ &params->dictionary,
+ ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
+ dictionary_start + gap, params, &matches[lz_matches_offset]);
+ if (num_matches > 0 &&
+ BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
+ matches[0] = matches[num_matches - 1];
+ num_matches = 1;
+ }
+ skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
+ params, max_backward_limit, dist_cache, num_matches, matches, &model,
+ &queue, nodes);
+ if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
+ if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
+ skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip);
+ }
+ if (skip > 1) {
+ /* Add the tail of the copy to the hasher. */
+ StoreRangeH10(&hasher->privat._H10,
+ ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
+ size_t, pos + skip, store_end));
+ skip--;
+ while (skip) {
+ i++;
+ if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
+ EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
+ dist_cache, &model, &queue, nodes);
+ skip--;
+ }
+ }
+ }
+ CleanupZopfliCostModel(m, &model);
+ return ComputeShortestPathFromNodes(num_bytes, nodes);
+}
+
+void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals) {
+ ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
+ BrotliInitZopfliNodes(nodes, num_bytes + 1);
+ *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
+ position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
+ dist_cache, hasher, nodes);
+ if (BROTLI_IS_OOM(m)) return;
+ BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
+ last_insert_len, params, commands, num_literals);
+ BROTLI_FREE(m, nodes);
+}
+
+void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals) {
+ const size_t stream_offset = params->stream_offset;
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+ uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
+ size_t matches_size = 4 * num_bytes;
+ const size_t store_end = num_bytes >= StoreLookaheadH10() ?
+ position + num_bytes - StoreLookaheadH10() + 1 : position;
+ size_t cur_match_pos = 0;
+ size_t i;
+ size_t orig_num_literals;
+ size_t orig_last_insert_len;
+ int orig_dist_cache[4];
+ size_t orig_num_commands;
+ ZopfliCostModel model;
+ ZopfliNode* nodes;
+ BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
+ size_t gap = 0;
+ size_t shadow_matches = 0;
+ BROTLI_UNUSED(literal_context_lut);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
+ BROTLI_IS_NULL(matches)) {
+ return;
+ }
+ for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
+ const size_t pos = position + i;
+ size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
+ size_t dictionary_start = BROTLI_MIN(size_t,
+ pos + stream_offset, max_backward_limit);
+ size_t max_length = num_bytes - i;
+ size_t num_found_matches;
+ size_t cur_match_end;
+ size_t j;
+ /* Ensure that we have enough free slots. */
+ BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
+ cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
+ if (BROTLI_IS_OOM(m)) return;
+ num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
+ &params->dictionary,
+ ringbuffer, ringbuffer_mask, pos, max_length,
+ max_distance, dictionary_start + gap, params,
+ &matches[cur_match_pos + shadow_matches]);
+ cur_match_end = cur_match_pos + num_found_matches;
+ for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
+ BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
+ BackwardMatchLength(&matches[j + 1]));
+ }
+ num_matches[i] = (uint32_t)num_found_matches;
+ if (num_found_matches > 0) {
+ const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]);
+ if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) {
+ const size_t skip = match_len - 1;
+ matches[cur_match_pos++] = matches[cur_match_end - 1];
+ num_matches[i] = 1;
+ /* Add the tail of the copy to the hasher. */
+ StoreRangeH10(&hasher->privat._H10,
+ ringbuffer, ringbuffer_mask, pos + 1,
+ BROTLI_MIN(size_t, pos + match_len, store_end));
+ memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
+ i += skip;
+ } else {
+ cur_match_pos = cur_match_end;
+ }
+ }
+ }
+ orig_num_literals = *num_literals;
+ orig_last_insert_len = *last_insert_len;
+ memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
+ orig_num_commands = *num_commands;
+ nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
+ InitZopfliCostModel(m, &model, &params->dist, num_bytes);
+ if (BROTLI_IS_OOM(m)) return;
+ for (i = 0; i < 2; i++) {
+ BrotliInitZopfliNodes(nodes, num_bytes + 1);
+ if (i == 0) {
+ ZopfliCostModelSetFromLiteralCosts(
+ &model, position, ringbuffer, ringbuffer_mask);
+ } else {
+ ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
+ ringbuffer_mask, commands, *num_commands - orig_num_commands,
+ orig_last_insert_len);
+ }
+ *num_commands = orig_num_commands;
+ *num_literals = orig_num_literals;
+ *last_insert_len = orig_last_insert_len;
+ memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
+ *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
+ ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
+ nodes);
+ BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
+ last_insert_len, params, commands, num_literals);
+ }
+ CleanupZopfliCostModel(m, &model);
+ BROTLI_FREE(m, nodes);
+ BROTLI_FREE(m, matches);
+ BROTLI_FREE(m, num_matches);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.h
new file mode 100644
index 000000000..36b75f250
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_hq.h
@@ -0,0 +1,95 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
+#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./hash.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
+ size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals);
+
+BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
+ size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals);
+
+typedef struct ZopfliNode {
+ /* Best length to get up to this byte (not including this byte itself)
+ highest 7 bit is used to reconstruct the length code. */
+ uint32_t length;
+ /* Distance associated with the length. */
+ uint32_t distance;
+ /* Number of literal inserts before this copy; highest 5 bits contain
+ distance short code + 1 (or zero if no short code). */
+ uint32_t dcode_insert_length;
+
+ /* This union holds information used by dynamic-programming. During forward
+ pass |cost| it used to store the goal function. When node is processed its
+ |cost| is invalidated in favor of |shortcut|. On path back-tracing pass
+ |next| is assigned the offset to next node on the path. */
+ union {
+ /* Smallest cost to get to this byte from the beginning, as found so far. */
+ float cost;
+ /* Offset to the next node on the path. Equals to command_length() of the
+ next node on the path. For last node equals to BROTLI_UINT32_MAX */
+ uint32_t next;
+ /* Node position that provides next distance for distance cache. */
+ uint32_t shortcut;
+ } u;
+} ZopfliNode;
+
+BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
+
+/* Computes the shortest path of commands from position to at most
+ position + num_bytes.
+
+ On return, path->size() is the number of commands found and path[i] is the
+ length of the i-th command (copy length plus insert length).
+ Note that the sum of the lengths of all commands can be less than num_bytes.
+
+ On return, the nodes[0..num_bytes] array will have the following
+ "ZopfliNode array invariant":
+ For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then
+ (1) nodes[i].copy_length() >= 2
+ (2) nodes[i].command_length() <= i and
+ (3) nodes[i - nodes[i].command_length()].cost < kInfinity */
+BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
+ MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
+
+BROTLI_INTERNAL void BrotliZopfliCreateCommands(
+ const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
+ int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
+ Command* commands, size_t* num_literals);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_inc.h
new file mode 100644
index 000000000..766bf91ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/backward_references_inc.h
@@ -0,0 +1,163 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: EXPORT_FN, FN */
+
+static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
+ size_t num_bytes, size_t position,
+ const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals) {
+ HASHER()* privat = &hasher->privat.FN(_);
+ /* Set maximum distance, see section 9.1. of the spec. */
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+ const size_t position_offset = params->stream_offset;
+
+ const Command* const orig_commands = commands;
+ size_t insert_length = *last_insert_len;
+ const size_t pos_end = position + num_bytes;
+ const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
+ position + num_bytes - FN(StoreLookahead)() + 1 : position;
+
+ /* For speed up heuristics for random data. */
+ const size_t random_heuristics_window_size =
+ LiteralSpreeLengthForSparseSearch(params);
+ size_t apply_random_heuristics = position + random_heuristics_window_size;
+ const size_t gap = 0;
+
+ /* Minimum score to accept a backward reference. */
+ const score_t kMinScore = BROTLI_SCORE_BASE + 100;
+
+ BROTLI_UNUSED(literal_context_lut);
+
+ FN(PrepareDistanceCache)(privat, dist_cache);
+
+ while (position + FN(HashTypeLength)() < pos_end) {
+ size_t max_length = pos_end - position;
+ size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
+ size_t dictionary_start = BROTLI_MIN(size_t,
+ position + position_offset, max_backward_limit);
+ HasherSearchResult sr;
+ sr.len = 0;
+ sr.len_code_delta = 0;
+ sr.distance = 0;
+ sr.score = kMinScore;
+ FN(FindLongestMatch)(privat, &params->dictionary,
+ ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
+ max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
+ if (sr.score > kMinScore) {
+ /* Found a match. Let's look for something even better ahead. */
+ int delayed_backward_references_in_row = 0;
+ --max_length;
+ for (;; --max_length) {
+ const score_t cost_diff_lazy = 175;
+ HasherSearchResult sr2;
+ sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
+ BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
+ sr2.len_code_delta = 0;
+ sr2.distance = 0;
+ sr2.score = kMinScore;
+ max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
+ dictionary_start = BROTLI_MIN(size_t,
+ position + 1 + position_offset, max_backward_limit);
+ FN(FindLongestMatch)(privat,
+ &params->dictionary,
+ ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
+ max_distance, dictionary_start + gap, params->dist.max_distance,
+ &sr2);
+ if (sr2.score >= sr.score + cost_diff_lazy) {
+ /* Ok, let's just write one byte for now and start a match from the
+ next byte. */
+ ++position;
+ ++insert_length;
+ sr = sr2;
+ if (++delayed_backward_references_in_row < 4 &&
+ position + FN(HashTypeLength)() < pos_end) {
+ continue;
+ }
+ }
+ break;
+ }
+ apply_random_heuristics =
+ position + 2 * sr.len + random_heuristics_window_size;
+ dictionary_start = BROTLI_MIN(size_t,
+ position + position_offset, max_backward_limit);
+ {
+ /* The first 16 codes are special short-codes,
+ and the minimum offset is 1. */
+ size_t distance_code = ComputeDistanceCode(
+ sr.distance, dictionary_start + gap, dist_cache);
+ if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
+ dist_cache[3] = dist_cache[2];
+ dist_cache[2] = dist_cache[1];
+ dist_cache[1] = dist_cache[0];
+ dist_cache[0] = (int)sr.distance;
+ FN(PrepareDistanceCache)(privat, dist_cache);
+ }
+ InitCommand(commands++, &params->dist, insert_length,
+ sr.len, sr.len_code_delta, distance_code);
+ }
+ *num_literals += insert_length;
+ insert_length = 0;
+ /* Put the hash keys into the table, if there are enough bytes left.
+ Depending on the hasher implementation, it can push all positions
+ in the given range or only a subset of them.
+ Avoid hash poisoning with RLE data. */
+ {
+ size_t range_start = position + 2;
+ size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
+ if (sr.distance < (sr.len >> 2)) {
+ range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
+ range_start, position + sr.len - (sr.distance << 2)));
+ }
+ FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
+ range_end);
+ }
+ position += sr.len;
+ } else {
+ ++insert_length;
+ ++position;
+ /* If we have not seen matches for a long time, we can skip some
+ match lookups. Unsuccessful match lookups are very very expensive
+ and this kind of a heuristic speeds up compression quite
+ a lot. */
+ if (position > apply_random_heuristics) {
+ /* Going through uncompressible data, jump. */
+ if (position >
+ apply_random_heuristics + 4 * random_heuristics_window_size) {
+ /* It is quite a long time since we saw a copy, so we assume
+ that this data is not compressible, and store hashes less
+ often. Hashes of non compressible data are less likely to
+ turn out to be useful in the future, too, so we store less of
+ them to not to flood out the hash table of good compressible
+ data. */
+ const size_t kMargin =
+ BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
+ size_t pos_jump =
+ BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
+ for (; position < pos_jump; position += 4) {
+ FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
+ insert_length += 4;
+ }
+ } else {
+ const size_t kMargin =
+ BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
+ size_t pos_jump =
+ BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
+ for (; position < pos_jump; position += 2) {
+ FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
+ insert_length += 2;
+ }
+ }
+ }
+ }
+ }
+ insert_length += pos_end - position;
+ *last_insert_len = insert_length;
+ *num_commands += (size_t)(commands - orig_commands);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.c
new file mode 100644
index 000000000..1f3f7ad5c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.c
@@ -0,0 +1,35 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions to estimate the bit cost of Huffman trees. */
+
+#include "./bit_cost.h"
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./fast_log.h"
+#include "./histogram.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define FN(X) X ## Literal
+#include "./bit_cost_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Command
+#include "./bit_cost_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Distance
+#include "./bit_cost_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.h
new file mode 100644
index 000000000..6586469e6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost.h
@@ -0,0 +1,63 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions to estimate the bit cost of Huffman trees. */
+
+#ifndef BROTLI_ENC_BIT_COST_H_
+#define BROTLI_ENC_BIT_COST_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./fast_log.h"
+#include "./histogram.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static BROTLI_INLINE double ShannonEntropy(
+ const uint32_t* population, size_t size, size_t* total) {
+ size_t sum = 0;
+ double retval = 0;
+ const uint32_t* population_end = population + size;
+ size_t p;
+ if (size & 1) {
+ goto odd_number_of_elements_left;
+ }
+ while (population < population_end) {
+ p = *population++;
+ sum += p;
+ retval -= (double)p * FastLog2(p);
+ odd_number_of_elements_left:
+ p = *population++;
+ sum += p;
+ retval -= (double)p * FastLog2(p);
+ }
+ if (sum) retval += (double)sum * FastLog2(sum);
+ *total = sum;
+ return retval;
+}
+
+static BROTLI_INLINE double BitsEntropy(
+ const uint32_t* population, size_t size) {
+ size_t sum;
+ double retval = ShannonEntropy(population, size, &sum);
+ if (retval < sum) {
+ /* At least one bit per literal is needed. */
+ retval = (double)sum;
+ }
+ return retval;
+}
+
+BROTLI_INTERNAL double BrotliPopulationCostLiteral(const HistogramLiteral*);
+BROTLI_INTERNAL double BrotliPopulationCostCommand(const HistogramCommand*);
+BROTLI_INTERNAL double BrotliPopulationCostDistance(const HistogramDistance*);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_BIT_COST_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost_inc.h
new file mode 100644
index 000000000..453c22604
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/bit_cost_inc.h
@@ -0,0 +1,127 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN */
+
+#define HistogramType FN(Histogram)
+
+double FN(BrotliPopulationCost)(const HistogramType* histogram) {
+ static const double kOneSymbolHistogramCost = 12;
+ static const double kTwoSymbolHistogramCost = 20;
+ static const double kThreeSymbolHistogramCost = 28;
+ static const double kFourSymbolHistogramCost = 37;
+ const size_t data_size = FN(HistogramDataSize)();
+ int count = 0;
+ size_t s[5];
+ double bits = 0.0;
+ size_t i;
+ if (histogram->total_count_ == 0) {
+ return kOneSymbolHistogramCost;
+ }
+ for (i = 0; i < data_size; ++i) {
+ if (histogram->data_[i] > 0) {
+ s[count] = i;
+ ++count;
+ if (count > 4) break;
+ }
+ }
+ if (count == 1) {
+ return kOneSymbolHistogramCost;
+ }
+ if (count == 2) {
+ return (kTwoSymbolHistogramCost + (double)histogram->total_count_);
+ }
+ if (count == 3) {
+ const uint32_t histo0 = histogram->data_[s[0]];
+ const uint32_t histo1 = histogram->data_[s[1]];
+ const uint32_t histo2 = histogram->data_[s[2]];
+ const uint32_t histomax =
+ BROTLI_MAX(uint32_t, histo0, BROTLI_MAX(uint32_t, histo1, histo2));
+ return (kThreeSymbolHistogramCost +
+ 2 * (histo0 + histo1 + histo2) - histomax);
+ }
+ if (count == 4) {
+ uint32_t histo[4];
+ uint32_t h23;
+ uint32_t histomax;
+ for (i = 0; i < 4; ++i) {
+ histo[i] = histogram->data_[s[i]];
+ }
+ /* Sort */
+ for (i = 0; i < 4; ++i) {
+ size_t j;
+ for (j = i + 1; j < 4; ++j) {
+ if (histo[j] > histo[i]) {
+ BROTLI_SWAP(uint32_t, histo, j, i);
+ }
+ }
+ }
+ h23 = histo[2] + histo[3];
+ histomax = BROTLI_MAX(uint32_t, h23, histo[0]);
+ return (kFourSymbolHistogramCost +
+ 3 * h23 + 2 * (histo[0] + histo[1]) - histomax);
+ }
+
+ {
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+ size_t max_depth = 1;
+ uint32_t depth_histo[BROTLI_CODE_LENGTH_CODES] = { 0 };
+ const double log2total = FastLog2(histogram->total_count_);
+ for (i = 0; i < data_size;) {
+ if (histogram->data_[i] > 0) {
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+ double log2p = log2total - FastLog2(histogram->data_[i]);
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ size_t depth = (size_t)(log2p + 0.5);
+ bits += histogram->data_[i] * log2p;
+ if (depth > 15) {
+ depth = 15;
+ }
+ if (depth > max_depth) {
+ max_depth = depth;
+ }
+ ++depth_histo[depth];
+ ++i;
+ } else {
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+ uint32_t reps = 1;
+ size_t k;
+ for (k = i + 1; k < data_size && histogram->data_[k] == 0; ++k) {
+ ++reps;
+ }
+ i += reps;
+ if (i == data_size) {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break;
+ }
+ if (reps < 3) {
+ depth_histo[0] += reps;
+ } else {
+ reps -= 2;
+ while (reps > 0) {
+ ++depth_histo[BROTLI_REPEAT_ZERO_CODE_LENGTH];
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3;
+ reps >>= 3;
+ }
+ }
+ }
+ }
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += (double)(18 + 2 * max_depth);
+ /* Add the entropy of the code length code histogram. */
+ bits += BitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
+ }
+ return bits;
+}
+
+#undef HistogramType
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_encoder_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_encoder_inc.h
new file mode 100644
index 000000000..8cbd5eac6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_encoder_inc.h
@@ -0,0 +1,34 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN */
+
+#define HistogramType FN(Histogram)
+
+/* Creates entropy codes for all block types and stores them to the bit
+ stream. */
+static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
+ const HistogramType* histograms, const size_t histograms_size,
+ const size_t alphabet_size, HuffmanTree* tree,
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t table_size = histograms_size * self->histogram_length_;
+ self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size);
+ self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size);
+ if (BROTLI_IS_OOM(m)) return;
+
+ {
+ size_t i;
+ for (i = 0; i < histograms_size; ++i) {
+ size_t ix = i * self->histogram_length_;
+ BuildAndStoreHuffmanTree(&histograms[i].data_[0], self->histogram_length_,
+ alphabet_size, tree, &self->depths_[ix], &self->bits_[ix],
+ storage_ix, storage);
+ }
+ }
+}
+
+#undef HistogramType
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.c
new file mode 100644
index 000000000..deb7c2e15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.c
@@ -0,0 +1,194 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Block split point selection utilities. */
+
+#include "./block_splitter.h"
+
+#include <string.h> /* memcpy, memset */
+
+#include "../common/platform.h"
+#include "./bit_cost.h"
+#include "./cluster.h"
+#include "./command.h"
+#include "./fast_log.h"
+#include "./histogram.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const size_t kMaxLiteralHistograms = 100;
+static const size_t kMaxCommandHistograms = 50;
+static const double kLiteralBlockSwitchCost = 28.1;
+static const double kCommandBlockSwitchCost = 13.5;
+static const double kDistanceBlockSwitchCost = 14.6;
+static const size_t kLiteralStrideLength = 70;
+static const size_t kCommandStrideLength = 40;
+static const size_t kSymbolsPerLiteralHistogram = 544;
+static const size_t kSymbolsPerCommandHistogram = 530;
+static const size_t kSymbolsPerDistanceHistogram = 544;
+static const size_t kMinLengthForBlockSplitting = 128;
+static const size_t kIterMulForRefining = 2;
+static const size_t kMinItersForRefining = 100;
+
+static size_t CountLiterals(const Command* cmds, const size_t num_commands) {
+ /* Count how many we have. */
+ size_t total_length = 0;
+ size_t i;
+ for (i = 0; i < num_commands; ++i) {
+ total_length += cmds[i].insert_len_;
+ }
+ return total_length;
+}
+
+static void CopyLiteralsToByteArray(const Command* cmds,
+ const size_t num_commands,
+ const uint8_t* data,
+ const size_t offset,
+ const size_t mask,
+ uint8_t* literals) {
+ size_t pos = 0;
+ size_t from_pos = offset & mask;
+ size_t i;
+ for (i = 0; i < num_commands; ++i) {
+ size_t insert_len = cmds[i].insert_len_;
+ if (from_pos + insert_len > mask) {
+ size_t head_size = mask + 1 - from_pos;
+ memcpy(literals + pos, data + from_pos, head_size);
+ from_pos = 0;
+ pos += head_size;
+ insert_len -= head_size;
+ }
+ if (insert_len > 0) {
+ memcpy(literals + pos, data + from_pos, insert_len);
+ pos += insert_len;
+ }
+ from_pos = (from_pos + insert_len + CommandCopyLen(&cmds[i])) & mask;
+ }
+}
+
+static BROTLI_INLINE uint32_t MyRand(uint32_t* seed) {
+ /* Initial seed should be 7. In this case, loop length is (1 << 29). */
+ *seed *= 16807U;
+ return *seed;
+}
+
+static BROTLI_INLINE double BitCost(size_t count) {
+ return count == 0 ? -2.0 : FastLog2(count);
+}
+
+#define HISTOGRAMS_PER_BATCH 64
+#define CLUSTERS_PER_BATCH 16
+
+#define FN(X) X ## Literal
+#define DataType uint8_t
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_splitter_inc.h"
+#undef DataType
+#undef FN
+
+#define FN(X) X ## Command
+#define DataType uint16_t
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_splitter_inc.h"
+#undef FN
+
+#define FN(X) X ## Distance
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_splitter_inc.h"
+#undef DataType
+#undef FN
+
+void BrotliInitBlockSplit(BlockSplit* self) {
+ self->num_types = 0;
+ self->num_blocks = 0;
+ self->types = 0;
+ self->lengths = 0;
+ self->types_alloc_size = 0;
+ self->lengths_alloc_size = 0;
+}
+
+void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) {
+ BROTLI_FREE(m, self->types);
+ BROTLI_FREE(m, self->lengths);
+}
+
+void BrotliSplitBlock(MemoryManager* m,
+ const Command* cmds,
+ const size_t num_commands,
+ const uint8_t* data,
+ const size_t pos,
+ const size_t mask,
+ const BrotliEncoderParams* params,
+ BlockSplit* literal_split,
+ BlockSplit* insert_and_copy_split,
+ BlockSplit* dist_split) {
+ {
+ size_t literals_count = CountLiterals(cmds, num_commands);
+ uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
+ /* Create a continuous array of literals. */
+ CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
+ /* Create the block split on the array of literals.
+ Literal histograms have alphabet size 256. */
+ SplitByteVectorLiteral(
+ m, literals, literals_count,
+ kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
+ kLiteralStrideLength, kLiteralBlockSwitchCost, params,
+ literal_split);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, literals);
+ }
+
+ {
+ /* Compute prefix codes for commands. */
+ uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
+ for (i = 0; i < num_commands; ++i) {
+ insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
+ }
+ /* Create the block split on the array of command prefixes. */
+ SplitByteVectorCommand(
+ m, insert_and_copy_codes, num_commands,
+ kSymbolsPerCommandHistogram, kMaxCommandHistograms,
+ kCommandStrideLength, kCommandBlockSwitchCost, params,
+ insert_and_copy_split);
+ if (BROTLI_IS_OOM(m)) return;
+ /* TODO: reuse for distances? */
+ BROTLI_FREE(m, insert_and_copy_codes);
+ }
+
+ {
+ /* Create a continuous array of distance prefixes. */
+ uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
+ size_t j = 0;
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
+ for (i = 0; i < num_commands; ++i) {
+ const Command* cmd = &cmds[i];
+ if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
+ distance_prefixes[j++] = cmd->dist_prefix_ & 0x3FF;
+ }
+ }
+ /* Create the block split on the array of distance prefixes. */
+ SplitByteVectorDistance(
+ m, distance_prefixes, j,
+ kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
+ kCommandStrideLength, kDistanceBlockSwitchCost, params,
+ dist_split);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, distance_prefixes);
+ }
+}
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.h
new file mode 100644
index 000000000..a5e006c4b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter.h
@@ -0,0 +1,51 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Block split point selection utilities. */
+
+#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
+#define BROTLI_ENC_BLOCK_SPLITTER_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct BlockSplit {
+ size_t num_types; /* Amount of distinct types */
+ size_t num_blocks; /* Amount of values in types and length */
+ uint8_t* types;
+ uint32_t* lengths;
+
+ size_t types_alloc_size;
+ size_t lengths_alloc_size;
+} BlockSplit;
+
+BROTLI_INTERNAL void BrotliInitBlockSplit(BlockSplit* self);
+BROTLI_INTERNAL void BrotliDestroyBlockSplit(MemoryManager* m,
+ BlockSplit* self);
+
+BROTLI_INTERNAL void BrotliSplitBlock(MemoryManager* m,
+ const Command* cmds,
+ const size_t num_commands,
+ const uint8_t* data,
+ const size_t offset,
+ const size_t mask,
+ const BrotliEncoderParams* params,
+ BlockSplit* literal_split,
+ BlockSplit* insert_and_copy_split,
+ BlockSplit* dist_split);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_BLOCK_SPLITTER_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter_inc.h
new file mode 100644
index 000000000..e612d6a37
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/block_splitter_inc.h
@@ -0,0 +1,440 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, DataType */
+
+#define HistogramType FN(Histogram)
+
+static void FN(InitialEntropyCodes)(const DataType* data, size_t length,
+ size_t stride,
+ size_t num_histograms,
+ HistogramType* histograms) {
+ uint32_t seed = 7;
+ size_t block_length = length / num_histograms;
+ size_t i;
+ FN(ClearHistograms)(histograms, num_histograms);
+ for (i = 0; i < num_histograms; ++i) {
+ size_t pos = length * i / num_histograms;
+ if (i != 0) {
+ pos += MyRand(&seed) % block_length;
+ }
+ if (pos + stride >= length) {
+ pos = length - stride - 1;
+ }
+ FN(HistogramAddVector)(&histograms[i], data + pos, stride);
+ }
+}
+
+static void FN(RandomSample)(uint32_t* seed,
+ const DataType* data,
+ size_t length,
+ size_t stride,
+ HistogramType* sample) {
+ size_t pos = 0;
+ if (stride >= length) {
+ stride = length;
+ } else {
+ pos = MyRand(seed) % (length - stride + 1);
+ }
+ FN(HistogramAddVector)(sample, data + pos, stride);
+}
+
+static void FN(RefineEntropyCodes)(const DataType* data, size_t length,
+ size_t stride,
+ size_t num_histograms,
+ HistogramType* histograms) {
+ size_t iters =
+ kIterMulForRefining * length / stride + kMinItersForRefining;
+ uint32_t seed = 7;
+ size_t iter;
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms;
+ for (iter = 0; iter < iters; ++iter) {
+ HistogramType sample;
+ FN(HistogramClear)(&sample);
+ FN(RandomSample)(&seed, data, length, stride, &sample);
+ FN(HistogramAddHistogram)(&histograms[iter % num_histograms], &sample);
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+static size_t FN(FindBlocks)(const DataType* data, const size_t length,
+ const double block_switch_bitcost,
+ const size_t num_histograms,
+ const HistogramType* histograms,
+ double* insert_cost,
+ double* cost,
+ uint8_t* switch_signal,
+ uint8_t* block_id) {
+ const size_t data_size = FN(HistogramDataSize)();
+ const size_t bitmaplen = (num_histograms + 7) >> 3;
+ size_t num_blocks = 1;
+ size_t i;
+ size_t j;
+ BROTLI_DCHECK(num_histograms <= 256);
+ if (num_histograms <= 1) {
+ for (i = 0; i < length; ++i) {
+ block_id[i] = 0;
+ }
+ return 1;
+ }
+ memset(insert_cost, 0, sizeof(insert_cost[0]) * data_size * num_histograms);
+ for (i = 0; i < num_histograms; ++i) {
+ insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_);
+ }
+ for (i = data_size; i != 0;) {
+ --i;
+ for (j = 0; j < num_histograms; ++j) {
+ insert_cost[i * num_histograms + j] =
+ insert_cost[j] - BitCost(histograms[j].data_[i]);
+ }
+ }
+ memset(cost, 0, sizeof(cost[0]) * num_histograms);
+ memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmaplen);
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for (i = 0; i < length; ++i) {
+ const size_t byte_ix = i;
+ size_t ix = byte_ix * bitmaplen;
+ size_t insert_cost_ix = data[byte_ix] * num_histograms;
+ double min_cost = 1e99;
+ double block_switch_cost = block_switch_bitcost;
+ size_t k;
+ for (k = 0; k < num_histograms; ++k) {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix + k];
+ if (cost[k] < min_cost) {
+ min_cost = cost[k];
+ block_id[byte_ix] = (uint8_t)k;
+ }
+ }
+ /* More blocks for the beginning. */
+ if (byte_ix < 2000) {
+ block_switch_cost *= 0.77 + 0.07 * (double)byte_ix / 2000;
+ }
+ for (k = 0; k < num_histograms; ++k) {
+ cost[k] -= min_cost;
+ if (cost[k] >= block_switch_cost) {
+ const uint8_t mask = (uint8_t)(1u << (k & 7));
+ cost[k] = block_switch_cost;
+ BROTLI_DCHECK((k >> 3) < bitmaplen);
+ switch_signal[ix + (k >> 3)] |= mask;
+ }
+ }
+ }
+ { /* Trace back from the last position and switch at the marked places. */
+ size_t byte_ix = length - 1;
+ size_t ix = byte_ix * bitmaplen;
+ uint8_t cur_id = block_id[byte_ix];
+ while (byte_ix > 0) {
+ const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
+ BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmaplen);
+ --byte_ix;
+ ix -= bitmaplen;
+ if (switch_signal[ix + (cur_id >> 3)] & mask) {
+ if (cur_id != block_id[byte_ix]) {
+ cur_id = block_id[byte_ix];
+ ++num_blocks;
+ }
+ }
+ block_id[byte_ix] = cur_id;
+ }
+ }
+ return num_blocks;
+}
+
+static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length,
+ uint16_t* new_id, const size_t num_histograms) {
+ static const uint16_t kInvalidId = 256;
+ uint16_t next_id = 0;
+ size_t i;
+ for (i = 0; i < num_histograms; ++i) {
+ new_id[i] = kInvalidId;
+ }
+ for (i = 0; i < length; ++i) {
+ BROTLI_DCHECK(block_ids[i] < num_histograms);
+ if (new_id[block_ids[i]] == kInvalidId) {
+ new_id[block_ids[i]] = next_id++;
+ }
+ }
+ for (i = 0; i < length; ++i) {
+ block_ids[i] = (uint8_t)new_id[block_ids[i]];
+ BROTLI_DCHECK(block_ids[i] < num_histograms);
+ }
+ BROTLI_DCHECK(next_id <= num_histograms);
+ return next_id;
+}
+
+static void FN(BuildBlockHistograms)(const DataType* data, const size_t length,
+ const uint8_t* block_ids,
+ const size_t num_histograms,
+ HistogramType* histograms) {
+ size_t i;
+ FN(ClearHistograms)(histograms, num_histograms);
+ for (i = 0; i < length; ++i) {
+ FN(HistogramAdd)(&histograms[block_ids[i]], data[i]);
+ }
+}
+
+static void FN(ClusterBlocks)(MemoryManager* m,
+ const DataType* data, const size_t length,
+ const size_t num_blocks,
+ uint8_t* block_ids,
+ BlockSplit* split) {
+ uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks);
+ uint32_t* block_lengths = BROTLI_ALLOC(m, uint32_t, num_blocks);
+ const size_t expected_num_clusters = CLUSTERS_PER_BATCH *
+ (num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH;
+ size_t all_histograms_size = 0;
+ size_t all_histograms_capacity = expected_num_clusters;
+ HistogramType* all_histograms =
+ BROTLI_ALLOC(m, HistogramType, all_histograms_capacity);
+ size_t cluster_size_size = 0;
+ size_t cluster_size_capacity = expected_num_clusters;
+ uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, cluster_size_capacity);
+ size_t num_clusters = 0;
+ HistogramType* histograms = BROTLI_ALLOC(m, HistogramType,
+ BROTLI_MIN(size_t, num_blocks, HISTOGRAMS_PER_BATCH));
+ size_t max_num_pairs =
+ HISTOGRAMS_PER_BATCH * HISTOGRAMS_PER_BATCH / 2;
+ size_t pairs_capacity = max_num_pairs + 1;
+ HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity);
+ size_t pos = 0;
+ uint32_t* clusters;
+ size_t num_final_clusters;
+ static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
+ uint32_t* new_index;
+ size_t i;
+ uint32_t sizes[HISTOGRAMS_PER_BATCH] = { 0 };
+ uint32_t new_clusters[HISTOGRAMS_PER_BATCH] = { 0 };
+ uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
+ uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
+
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
+ BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
+ BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
+ BROTLI_IS_NULL(pairs)) {
+ return;
+ }
+
+ memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
+
+ {
+ size_t block_idx = 0;
+ for (i = 0; i < length; ++i) {
+ BROTLI_DCHECK(block_idx < num_blocks);
+ ++block_lengths[block_idx];
+ if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
+ ++block_idx;
+ }
+ }
+ BROTLI_DCHECK(block_idx == num_blocks);
+ }
+
+ for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
+ const size_t num_to_combine =
+ BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
+ size_t num_new_clusters;
+ size_t j;
+ for (j = 0; j < num_to_combine; ++j) {
+ size_t k;
+ FN(HistogramClear)(&histograms[j]);
+ for (k = 0; k < block_lengths[i + j]; ++k) {
+ FN(HistogramAdd)(&histograms[j], data[pos++]);
+ }
+ histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
+ new_clusters[j] = (uint32_t)j;
+ symbols[j] = (uint32_t)j;
+ sizes[j] = 1;
+ }
+ num_new_clusters = FN(BrotliHistogramCombine)(
+ histograms, sizes, symbols, new_clusters, pairs, num_to_combine,
+ num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs);
+ BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms,
+ all_histograms_capacity, all_histograms_size + num_new_clusters);
+ BROTLI_ENSURE_CAPACITY(m, uint32_t, cluster_size,
+ cluster_size_capacity, cluster_size_size + num_new_clusters);
+ if (BROTLI_IS_OOM(m)) return;
+ for (j = 0; j < num_new_clusters; ++j) {
+ all_histograms[all_histograms_size++] = histograms[new_clusters[j]];
+ cluster_size[cluster_size_size++] = sizes[new_clusters[j]];
+ remap[new_clusters[j]] = (uint32_t)j;
+ }
+ for (j = 0; j < num_to_combine; ++j) {
+ histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
+ }
+ num_clusters += num_new_clusters;
+ BROTLI_DCHECK(num_clusters == cluster_size_size);
+ BROTLI_DCHECK(num_clusters == all_histograms_size);
+ }
+ BROTLI_FREE(m, histograms);
+
+ max_num_pairs =
+ BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters);
+ if (pairs_capacity < max_num_pairs + 1) {
+ BROTLI_FREE(m, pairs);
+ pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
+ }
+
+ clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
+ for (i = 0; i < num_clusters; ++i) {
+ clusters[i] = (uint32_t)i;
+ }
+ num_final_clusters = FN(BrotliHistogramCombine)(
+ all_histograms, cluster_size, histogram_symbols, clusters, pairs,
+ num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES,
+ max_num_pairs);
+ BROTLI_FREE(m, pairs);
+ BROTLI_FREE(m, cluster_size);
+
+ new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
+ for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
+ pos = 0;
+ {
+ uint32_t next_index = 0;
+ for (i = 0; i < num_blocks; ++i) {
+ HistogramType histo;
+ size_t j;
+ uint32_t best_out;
+ double best_bits;
+ FN(HistogramClear)(&histo);
+ for (j = 0; j < block_lengths[i]; ++j) {
+ FN(HistogramAdd)(&histo, data[pos++]);
+ }
+ best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1];
+ best_bits =
+ FN(BrotliHistogramBitCostDistance)(&histo, &all_histograms[best_out]);
+ for (j = 0; j < num_final_clusters; ++j) {
+ const double cur_bits = FN(BrotliHistogramBitCostDistance)(
+ &histo, &all_histograms[clusters[j]]);
+ if (cur_bits < best_bits) {
+ best_bits = cur_bits;
+ best_out = clusters[j];
+ }
+ }
+ histogram_symbols[i] = best_out;
+ if (new_index[best_out] == kInvalidIndex) {
+ new_index[best_out] = next_index++;
+ }
+ }
+ }
+ BROTLI_FREE(m, clusters);
+ BROTLI_FREE(m, all_histograms);
+ BROTLI_ENSURE_CAPACITY(
+ m, uint8_t, split->types, split->types_alloc_size, num_blocks);
+ BROTLI_ENSURE_CAPACITY(
+ m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks);
+ if (BROTLI_IS_OOM(m)) return;
+ {
+ uint32_t cur_length = 0;
+ size_t block_idx = 0;
+ uint8_t max_type = 0;
+ for (i = 0; i < num_blocks; ++i) {
+ cur_length += block_lengths[i];
+ if (i + 1 == num_blocks ||
+ histogram_symbols[i] != histogram_symbols[i + 1]) {
+ const uint8_t id = (uint8_t)new_index[histogram_symbols[i]];
+ split->types[block_idx] = id;
+ split->lengths[block_idx] = cur_length;
+ max_type = BROTLI_MAX(uint8_t, max_type, id);
+ cur_length = 0;
+ ++block_idx;
+ }
+ }
+ split->num_blocks = block_idx;
+ split->num_types = (size_t)max_type + 1;
+ }
+ BROTLI_FREE(m, new_index);
+ BROTLI_FREE(m, block_lengths);
+ BROTLI_FREE(m, histogram_symbols);
+}
+
+static void FN(SplitByteVector)(MemoryManager* m,
+ const DataType* data, const size_t length,
+ const size_t literals_per_histogram,
+ const size_t max_histograms,
+ const size_t sampling_stride_length,
+ const double block_switch_cost,
+ const BrotliEncoderParams* params,
+ BlockSplit* split) {
+ const size_t data_size = FN(HistogramDataSize)();
+ size_t num_histograms = length / literals_per_histogram + 1;
+ HistogramType* histograms;
+ if (num_histograms > max_histograms) {
+ num_histograms = max_histograms;
+ }
+ if (length == 0) {
+ split->num_types = 1;
+ return;
+ } else if (length < kMinLengthForBlockSplitting) {
+ BROTLI_ENSURE_CAPACITY(m, uint8_t,
+ split->types, split->types_alloc_size, split->num_blocks + 1);
+ BROTLI_ENSURE_CAPACITY(m, uint32_t,
+ split->lengths, split->lengths_alloc_size, split->num_blocks + 1);
+ if (BROTLI_IS_OOM(m)) return;
+ split->num_types = 1;
+ split->types[split->num_blocks] = 0;
+ split->lengths[split->num_blocks] = (uint32_t)length;
+ split->num_blocks++;
+ return;
+ }
+ histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
+ /* Find good entropy codes. */
+ FN(InitialEntropyCodes)(data, length,
+ sampling_stride_length,
+ num_histograms, histograms);
+ FN(RefineEntropyCodes)(data, length,
+ sampling_stride_length,
+ num_histograms, histograms);
+ {
+ /* Find a good path through literals with the good entropy codes. */
+ uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length);
+ size_t num_blocks = 0;
+ const size_t bitmaplen = (num_histograms + 7) >> 3;
+ double* insert_cost = BROTLI_ALLOC(m, double, data_size * num_histograms);
+ double* cost = BROTLI_ALLOC(m, double, num_histograms);
+ uint8_t* switch_signal = BROTLI_ALLOC(m, uint8_t, length * bitmaplen);
+ uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
+ const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
+ BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
+ BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
+ return;
+ }
+ for (i = 0; i < iters; ++i) {
+ num_blocks = FN(FindBlocks)(data, length,
+ block_switch_cost,
+ num_histograms, histograms,
+ insert_cost, cost, switch_signal,
+ block_ids);
+ num_histograms = FN(RemapBlockIds)(block_ids, length,
+ new_id, num_histograms);
+ FN(BuildBlockHistograms)(data, length, block_ids,
+ num_histograms, histograms);
+ }
+ BROTLI_FREE(m, insert_cost);
+ BROTLI_FREE(m, cost);
+ BROTLI_FREE(m, switch_signal);
+ BROTLI_FREE(m, new_id);
+ BROTLI_FREE(m, histograms);
+ FN(ClusterBlocks)(m, data, length, num_blocks, block_ids, split);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, block_ids);
+ }
+}
+
+#undef HistogramType
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.c
new file mode 100644
index 000000000..6391454f9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.c
@@ -0,0 +1,1329 @@
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Brotli bit stream functions to support the low level format. There are no
+ compression algorithms here, just the right ordering of bits to match the
+ specs. */
+
+#include "./brotli_bit_stream.h"
+
+#include <string.h> /* memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./entropy_encode.h"
+#include "./entropy_encode_static.h"
+#include "./fast_log.h"
+#include "./histogram.h"
+#include "./memory.h"
+#include "./write_bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_HUFFMAN_TREE_SIZE (2 * BROTLI_NUM_COMMAND_SYMBOLS + 1)
+/* The maximum size of Huffman dictionary for distances assuming that
+ NPOSTFIX = 0 and NDIRECT = 0. */
+#define MAX_SIMPLE_DISTANCE_ALPHABET_SIZE \
+ BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
+/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
+
+/* Represents the range of values belonging to a prefix code:
+ [offset, offset + 2^nbits) */
+typedef struct PrefixCodeRange {
+ uint32_t offset;
+ uint32_t nbits;
+} PrefixCodeRange;
+
+static const PrefixCodeRange
+ kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
+ { 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
+ {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
+ {177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
+ {753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
+};
+
+static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
+ uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
+ while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
+ len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
+ return code;
+}
+
+static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
+ uint32_t* n_extra, uint32_t* extra) {
+ *code = BlockLengthPrefixCode(len);
+ *n_extra = kBlockLengthPrefixCode[*code].nbits;
+ *extra = len - kBlockLengthPrefixCode[*code].offset;
+}
+
+typedef struct BlockTypeCodeCalculator {
+ size_t last_type;
+ size_t second_last_type;
+} BlockTypeCodeCalculator;
+
+static void InitBlockTypeCodeCalculator(BlockTypeCodeCalculator* self) {
+ self->last_type = 1;
+ self->second_last_type = 0;
+}
+
+static BROTLI_INLINE size_t NextBlockTypeCode(
+ BlockTypeCodeCalculator* calculator, uint8_t type) {
+ size_t type_code = (type == calculator->last_type + 1) ? 1u :
+ (type == calculator->second_last_type) ? 0u : type + 2u;
+ calculator->second_last_type = calculator->last_type;
+ calculator->last_type = type;
+ return type_code;
+}
+
+/* |nibblesbits| represents the 2 bits to encode MNIBBLES (0-3)
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+static void BrotliEncodeMlen(size_t length, uint64_t* bits,
+ size_t* numbits, uint64_t* nibblesbits) {
+ size_t lg = (length == 1) ? 1 : Log2FloorNonZero((uint32_t)(length - 1)) + 1;
+ size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
+ BROTLI_DCHECK(length > 0);
+ BROTLI_DCHECK(length <= (1 << 24));
+ BROTLI_DCHECK(lg <= 24);
+ *nibblesbits = mnibbles - 4;
+ *numbits = mnibbles * 4;
+ *bits = length - 1;
+}
+
+static BROTLI_INLINE void StoreCommandExtra(
+ const Command* cmd, size_t* storage_ix, uint8_t* storage) {
+ uint32_t copylen_code = CommandCopyLenCode(cmd);
+ uint16_t inscode = GetInsertLengthCode(cmd->insert_len_);
+ uint16_t copycode = GetCopyLengthCode(copylen_code);
+ uint32_t insnumextra = GetInsertExtra(inscode);
+ uint64_t insextraval = cmd->insert_len_ - GetInsertBase(inscode);
+ uint64_t copyextraval = copylen_code - GetCopyBase(copycode);
+ uint64_t bits = (copyextraval << insnumextra) | insextraval;
+ BrotliWriteBits(
+ insnumextra + GetCopyExtra(copycode), bits, storage_ix, storage);
+}
+
+/* Data structure that stores almost everything that is needed to encode each
+ block switch command. */
+typedef struct BlockSplitCode {
+ BlockTypeCodeCalculator type_code_calculator;
+ uint8_t type_depths[BROTLI_MAX_BLOCK_TYPE_SYMBOLS];
+ uint16_t type_bits[BROTLI_MAX_BLOCK_TYPE_SYMBOLS];
+ uint8_t length_depths[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
+ uint16_t length_bits[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
+} BlockSplitCode;
+
+/* Stores a number between 0 and 255. */
+static void StoreVarLenUint8(size_t n, size_t* storage_ix, uint8_t* storage) {
+ if (n == 0) {
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ } else {
+ size_t nbits = Log2FloorNonZero(n);
+ BrotliWriteBits(1, 1, storage_ix, storage);
+ BrotliWriteBits(3, nbits, storage_ix, storage);
+ BrotliWriteBits(nbits, n - ((size_t)1 << nbits), storage_ix, storage);
+ }
+}
+
+/* Stores the compressed meta-block header.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+static void StoreCompressedMetaBlockHeader(BROTLI_BOOL is_final_block,
+ size_t length,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ uint64_t lenbits;
+ size_t nlenbits;
+ uint64_t nibblesbits;
+
+ /* Write ISLAST bit. */
+ BrotliWriteBits(1, (uint64_t)is_final_block, storage_ix, storage);
+ /* Write ISEMPTY bit. */
+ if (is_final_block) {
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ }
+
+ BrotliEncodeMlen(length, &lenbits, &nlenbits, &nibblesbits);
+ BrotliWriteBits(2, nibblesbits, storage_ix, storage);
+ BrotliWriteBits(nlenbits, lenbits, storage_ix, storage);
+
+ if (!is_final_block) {
+ /* Write ISUNCOMPRESSED bit. */
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ }
+}
+
+/* Stores the uncompressed meta-block header.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+static void BrotliStoreUncompressedMetaBlockHeader(size_t length,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ uint64_t lenbits;
+ size_t nlenbits;
+ uint64_t nibblesbits;
+
+ /* Write ISLAST bit.
+ Uncompressed block cannot be the last one, so set to 0. */
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ BrotliEncodeMlen(length, &lenbits, &nlenbits, &nibblesbits);
+ BrotliWriteBits(2, nibblesbits, storage_ix, storage);
+ BrotliWriteBits(nlenbits, lenbits, storage_ix, storage);
+ /* Write ISUNCOMPRESSED bit. */
+ BrotliWriteBits(1, 1, storage_ix, storage);
+}
+
+static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
+ const int num_codes, const uint8_t* code_length_bitdepth,
+ size_t* storage_ix, uint8_t* storage) {
+ static const uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = {
+ 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ };
+ /* The bit lengths of the Huffman code over the code length alphabet
+ are compressed with the following static Huffman code:
+ Symbol Code
+ ------ ----
+ 0 00
+ 1 1110
+ 2 110
+ 3 01
+ 4 10
+ 5 1111 */
+ static const uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {
+ 0, 7, 3, 2, 1, 15
+ };
+ static const uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {
+ 2, 4, 3, 2, 2, 4
+ };
+
+ size_t skip_some = 0; /* skips none. */
+
+ /* Throw away trailing zeros: */
+ size_t codes_to_store = BROTLI_CODE_LENGTH_CODES;
+ if (num_codes > 1) {
+ for (; codes_to_store > 0; --codes_to_store) {
+ if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
+ break;
+ }
+ }
+ }
+ if (code_length_bitdepth[kStorageOrder[0]] == 0 &&
+ code_length_bitdepth[kStorageOrder[1]] == 0) {
+ skip_some = 2; /* skips two. */
+ if (code_length_bitdepth[kStorageOrder[2]] == 0) {
+ skip_some = 3; /* skips three. */
+ }
+ }
+ BrotliWriteBits(2, skip_some, storage_ix, storage);
+ {
+ size_t i;
+ for (i = skip_some; i < codes_to_store; ++i) {
+ size_t l = code_length_bitdepth[kStorageOrder[i]];
+ BrotliWriteBits(kHuffmanBitLengthHuffmanCodeBitLengths[l],
+ kHuffmanBitLengthHuffmanCodeSymbols[l], storage_ix, storage);
+ }
+ }
+}
+
+static void BrotliStoreHuffmanTreeToBitMask(
+ const size_t huffman_tree_size, const uint8_t* huffman_tree,
+ const uint8_t* huffman_tree_extra_bits, const uint8_t* code_length_bitdepth,
+ const uint16_t* code_length_bitdepth_symbols,
+ size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage) {
+ size_t i;
+ for (i = 0; i < huffman_tree_size; ++i) {
+ size_t ix = huffman_tree[i];
+ BrotliWriteBits(code_length_bitdepth[ix], code_length_bitdepth_symbols[ix],
+ storage_ix, storage);
+ /* Extra bits */
+ switch (ix) {
+ case BROTLI_REPEAT_PREVIOUS_CODE_LENGTH:
+ BrotliWriteBits(2, huffman_tree_extra_bits[i], storage_ix, storage);
+ break;
+ case BROTLI_REPEAT_ZERO_CODE_LENGTH:
+ BrotliWriteBits(3, huffman_tree_extra_bits[i], storage_ix, storage);
+ break;
+ }
+ }
+}
+
+static void StoreSimpleHuffmanTree(const uint8_t* depths,
+ size_t symbols[4],
+ size_t num_symbols,
+ size_t max_bits,
+ size_t* storage_ix, uint8_t* storage) {
+ /* value of 1 indicates a simple Huffman code */
+ BrotliWriteBits(2, 1, storage_ix, storage);
+ BrotliWriteBits(2, num_symbols - 1, storage_ix, storage); /* NSYM - 1 */
+
+ {
+ /* Sort */
+ size_t i;
+ for (i = 0; i < num_symbols; i++) {
+ size_t j;
+ for (j = i + 1; j < num_symbols; j++) {
+ if (depths[symbols[j]] < depths[symbols[i]]) {
+ BROTLI_SWAP(size_t, symbols, j, i);
+ }
+ }
+ }
+ }
+
+ if (num_symbols == 2) {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ } else if (num_symbols == 3) {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[2], storage_ix, storage);
+ } else {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[2], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[3], storage_ix, storage);
+ /* tree-select */
+ BrotliWriteBits(1, depths[symbols[0]] == 1 ? 1 : 0, storage_ix, storage);
+ }
+}
+
+/* num = alphabet size
+ depths = symbol depths */
+void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
+ HuffmanTree* tree,
+ size_t* storage_ix, uint8_t* storage) {
+ /* Write the Huffman tree into the brotli-representation.
+ The command alphabet is the largest, so this allocation will fit all
+ alphabets. */
+ uint8_t huffman_tree[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint8_t huffman_tree_extra_bits[BROTLI_NUM_COMMAND_SYMBOLS];
+ size_t huffman_tree_size = 0;
+ uint8_t code_length_bitdepth[BROTLI_CODE_LENGTH_CODES] = { 0 };
+ uint16_t code_length_bitdepth_symbols[BROTLI_CODE_LENGTH_CODES];
+ uint32_t huffman_tree_histogram[BROTLI_CODE_LENGTH_CODES] = { 0 };
+ size_t i;
+ int num_codes = 0;
+ size_t code = 0;
+
+ BROTLI_DCHECK(num <= BROTLI_NUM_COMMAND_SYMBOLS);
+
+ BrotliWriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
+ huffman_tree_extra_bits);
+
+ /* Calculate the statistics of the Huffman tree in brotli-representation. */
+ for (i = 0; i < huffman_tree_size; ++i) {
+ ++huffman_tree_histogram[huffman_tree[i]];
+ }
+
+ for (i = 0; i < BROTLI_CODE_LENGTH_CODES; ++i) {
+ if (huffman_tree_histogram[i]) {
+ if (num_codes == 0) {
+ code = i;
+ num_codes = 1;
+ } else if (num_codes == 1) {
+ num_codes = 2;
+ break;
+ }
+ }
+ }
+
+ /* Calculate another Huffman tree to use for compressing both the
+ earlier Huffman tree with. */
+ BrotliCreateHuffmanTree(huffman_tree_histogram, BROTLI_CODE_LENGTH_CODES,
+ 5, tree, code_length_bitdepth);
+ BrotliConvertBitDepthsToSymbols(code_length_bitdepth,
+ BROTLI_CODE_LENGTH_CODES,
+ code_length_bitdepth_symbols);
+
+ /* Now, we have all the data, let's start storing it */
+ BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth,
+ storage_ix, storage);
+
+ if (num_codes == 1) {
+ code_length_bitdepth[code] = 0;
+ }
+
+ /* Store the real Huffman tree now. */
+ BrotliStoreHuffmanTreeToBitMask(huffman_tree_size,
+ huffman_tree,
+ huffman_tree_extra_bits,
+ code_length_bitdepth,
+ code_length_bitdepth_symbols,
+ storage_ix, storage);
+}
+
+/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
+ bits[0:length] and stores the encoded tree to the bit stream. */
+static void BuildAndStoreHuffmanTree(const uint32_t* histogram,
+ const size_t histogram_length,
+ const size_t alphabet_size,
+ HuffmanTree* tree,
+ uint8_t* depth,
+ uint16_t* bits,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ size_t count = 0;
+ size_t s4[4] = { 0 };
+ size_t i;
+ size_t max_bits = 0;
+ for (i = 0; i < histogram_length; i++) {
+ if (histogram[i]) {
+ if (count < 4) {
+ s4[count] = i;
+ } else if (count > 4) {
+ break;
+ }
+ count++;
+ }
+ }
+
+ {
+ size_t max_bits_counter = alphabet_size - 1;
+ while (max_bits_counter) {
+ max_bits_counter >>= 1;
+ ++max_bits;
+ }
+ }
+
+ if (count <= 1) {
+ BrotliWriteBits(4, 1, storage_ix, storage);
+ BrotliWriteBits(max_bits, s4[0], storage_ix, storage);
+ depth[s4[0]] = 0;
+ bits[s4[0]] = 0;
+ return;
+ }
+
+ memset(depth, 0, histogram_length * sizeof(depth[0]));
+ BrotliCreateHuffmanTree(histogram, histogram_length, 15, tree, depth);
+ BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits);
+
+ if (count <= 4) {
+ StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage);
+ } else {
+ BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage);
+ }
+}
+
+static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
+ const HuffmanTree* v0, const HuffmanTree* v1) {
+ return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_);
+}
+
+void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
+ const uint32_t* histogram,
+ const size_t histogram_total,
+ const size_t max_bits,
+ uint8_t* depth, uint16_t* bits,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ size_t count = 0;
+ size_t symbols[4] = { 0 };
+ size_t length = 0;
+ size_t total = histogram_total;
+ while (total != 0) {
+ if (histogram[length]) {
+ if (count < 4) {
+ symbols[count] = length;
+ }
+ ++count;
+ total -= histogram[length];
+ }
+ ++length;
+ }
+
+ if (count <= 1) {
+ BrotliWriteBits(4, 1, storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ depth[symbols[0]] = 0;
+ bits[symbols[0]] = 0;
+ return;
+ }
+
+ memset(depth, 0, length * sizeof(depth[0]));
+ {
+ const size_t max_tree_size = 2 * length + 1;
+ HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
+ uint32_t count_limit;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
+ for (count_limit = 1; ; count_limit *= 2) {
+ HuffmanTree* node = tree;
+ size_t l;
+ for (l = length; l != 0;) {
+ --l;
+ if (histogram[l]) {
+ if (BROTLI_PREDICT_TRUE(histogram[l] >= count_limit)) {
+ InitHuffmanTree(node, histogram[l], -1, (int16_t)l);
+ } else {
+ InitHuffmanTree(node, count_limit, -1, (int16_t)l);
+ }
+ ++node;
+ }
+ }
+ {
+ const int n = (int)(node - tree);
+ HuffmanTree sentinel;
+ int i = 0; /* Points to the next leaf node. */
+ int j = n + 1; /* Points to the next non-leaf node. */
+ int k;
+
+ SortHuffmanTreeItems(tree, (size_t)n, SortHuffmanTree);
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1);
+ *node++ = sentinel;
+ *node++ = sentinel;
+
+ for (k = n - 1; k > 0; --k) {
+ int left, right;
+ if (tree[i].total_count_ <= tree[j].total_count_) {
+ left = i;
+ ++i;
+ } else {
+ left = j;
+ ++j;
+ }
+ if (tree[i].total_count_ <= tree[j].total_count_) {
+ right = i;
+ ++i;
+ } else {
+ right = j;
+ ++j;
+ }
+ /* The sentinel node becomes the parent node. */
+ node[-1].total_count_ =
+ tree[left].total_count_ + tree[right].total_count_;
+ node[-1].index_left_ = (int16_t)left;
+ node[-1].index_right_or_value_ = (int16_t)right;
+ /* Add back the last sentinel node. */
+ *node++ = sentinel;
+ }
+ if (BrotliSetDepth(2 * n - 1, tree, depth, 14)) {
+ /* We need to pack the Huffman tree in 14 bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break;
+ }
+ }
+ }
+ BROTLI_FREE(m, tree);
+ }
+ BrotliConvertBitDepthsToSymbols(depth, length, bits);
+ if (count <= 4) {
+ size_t i;
+ /* value of 1 indicates a simple Huffman code */
+ BrotliWriteBits(2, 1, storage_ix, storage);
+ BrotliWriteBits(2, count - 1, storage_ix, storage); /* NSYM - 1 */
+
+ /* Sort */
+ for (i = 0; i < count; i++) {
+ size_t j;
+ for (j = i + 1; j < count; j++) {
+ if (depth[symbols[j]] < depth[symbols[i]]) {
+ BROTLI_SWAP(size_t, symbols, j, i);
+ }
+ }
+ }
+
+ if (count == 2) {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ } else if (count == 3) {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[2], storage_ix, storage);
+ } else {
+ BrotliWriteBits(max_bits, symbols[0], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[1], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[2], storage_ix, storage);
+ BrotliWriteBits(max_bits, symbols[3], storage_ix, storage);
+ /* tree-select */
+ BrotliWriteBits(1, depth[symbols[0]] == 1 ? 1 : 0, storage_ix, storage);
+ }
+ } else {
+ uint8_t previous_value = 8;
+ size_t i;
+ /* Complex Huffman Tree */
+ StoreStaticCodeLengthCode(storage_ix, storage);
+
+ /* Actual RLE coding. */
+ for (i = 0; i < length;) {
+ const uint8_t value = depth[i];
+ size_t reps = 1;
+ size_t k;
+ for (k = i + 1; k < length && depth[k] == value; ++k) {
+ ++reps;
+ }
+ i += reps;
+ if (value == 0) {
+ BrotliWriteBits(kZeroRepsDepth[reps], kZeroRepsBits[reps],
+ storage_ix, storage);
+ } else {
+ if (previous_value != value) {
+ BrotliWriteBits(kCodeLengthDepth[value], kCodeLengthBits[value],
+ storage_ix, storage);
+ --reps;
+ }
+ if (reps < 3) {
+ while (reps != 0) {
+ reps--;
+ BrotliWriteBits(kCodeLengthDepth[value], kCodeLengthBits[value],
+ storage_ix, storage);
+ }
+ } else {
+ reps -= 3;
+ BrotliWriteBits(kNonZeroRepsDepth[reps], kNonZeroRepsBits[reps],
+ storage_ix, storage);
+ }
+ previous_value = value;
+ }
+ }
+ }
+}
+
+static size_t IndexOf(const uint8_t* v, size_t v_size, uint8_t value) {
+ size_t i = 0;
+ for (; i < v_size; ++i) {
+ if (v[i] == value) return i;
+ }
+ return i;
+}
+
+static void MoveToFront(uint8_t* v, size_t index) {
+ uint8_t value = v[index];
+ size_t i;
+ for (i = index; i != 0; --i) {
+ v[i] = v[i - 1];
+ }
+ v[0] = value;
+}
+
+static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in,
+ const size_t v_size,
+ uint32_t* v_out) {
+ size_t i;
+ uint8_t mtf[256];
+ uint32_t max_value;
+ if (v_size == 0) {
+ return;
+ }
+ max_value = v_in[0];
+ for (i = 1; i < v_size; ++i) {
+ if (v_in[i] > max_value) max_value = v_in[i];
+ }
+ BROTLI_DCHECK(max_value < 256u);
+ for (i = 0; i <= max_value; ++i) {
+ mtf[i] = (uint8_t)i;
+ }
+ {
+ size_t mtf_size = max_value + 1;
+ for (i = 0; i < v_size; ++i) {
+ size_t index = IndexOf(mtf, mtf_size, (uint8_t)v_in[i]);
+ BROTLI_DCHECK(index < mtf_size);
+ v_out[i] = (uint32_t)index;
+ MoveToFront(mtf, index);
+ }
+ }
+}
+
+/* Finds runs of zeros in v[0..in_size) and replaces them with a prefix code of
+ the run length plus extra bits (lower 9 bits is the prefix code and the rest
+ are the extra bits). Non-zero values in v[] are shifted by
+ *max_length_prefix. Will not create prefix codes bigger than the initial
+ value of *max_run_length_prefix. The prefix code of run length L is simply
+ Log2Floor(L) and the number of extra bits is the same as the prefix code. */
+static void RunLengthCodeZeros(const size_t in_size,
+ uint32_t* BROTLI_RESTRICT v, size_t* BROTLI_RESTRICT out_size,
+ uint32_t* BROTLI_RESTRICT max_run_length_prefix) {
+ uint32_t max_reps = 0;
+ size_t i;
+ uint32_t max_prefix;
+ for (i = 0; i < in_size;) {
+ uint32_t reps = 0;
+ for (; i < in_size && v[i] != 0; ++i) ;
+ for (; i < in_size && v[i] == 0; ++i) {
+ ++reps;
+ }
+ max_reps = BROTLI_MAX(uint32_t, reps, max_reps);
+ }
+ max_prefix = max_reps > 0 ? Log2FloorNonZero(max_reps) : 0;
+ max_prefix = BROTLI_MIN(uint32_t, max_prefix, *max_run_length_prefix);
+ *max_run_length_prefix = max_prefix;
+ *out_size = 0;
+ for (i = 0; i < in_size;) {
+ BROTLI_DCHECK(*out_size <= i);
+ if (v[i] != 0) {
+ v[*out_size] = v[i] + *max_run_length_prefix;
+ ++i;
+ ++(*out_size);
+ } else {
+ uint32_t reps = 1;
+ size_t k;
+ for (k = i + 1; k < in_size && v[k] == 0; ++k) {
+ ++reps;
+ }
+ i += reps;
+ while (reps != 0) {
+ if (reps < (2u << max_prefix)) {
+ uint32_t run_length_prefix = Log2FloorNonZero(reps);
+ const uint32_t extra_bits = reps - (1u << run_length_prefix);
+ v[*out_size] = run_length_prefix + (extra_bits << 9);
+ ++(*out_size);
+ break;
+ } else {
+ const uint32_t extra_bits = (1u << max_prefix) - 1u;
+ v[*out_size] = max_prefix + (extra_bits << 9);
+ reps -= (2u << max_prefix) - 1u;
+ ++(*out_size);
+ }
+ }
+ }
+ }
+}
+
+#define SYMBOL_BITS 9
+
+static void EncodeContextMap(MemoryManager* m,
+ const uint32_t* context_map,
+ size_t context_map_size,
+ size_t num_clusters,
+ HuffmanTree* tree,
+ size_t* storage_ix, uint8_t* storage) {
+ size_t i;
+ uint32_t* rle_symbols;
+ uint32_t max_run_length_prefix = 6;
+ size_t num_rle_symbols = 0;
+ uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+ static const uint32_t kSymbolMask = (1u << SYMBOL_BITS) - 1u;
+ uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+ uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+
+ StoreVarLenUint8(num_clusters - 1, storage_ix, storage);
+
+ if (num_clusters == 1) {
+ return;
+ }
+
+ rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
+ MoveToFrontTransform(context_map, context_map_size, rle_symbols);
+ RunLengthCodeZeros(context_map_size, rle_symbols,
+ &num_rle_symbols, &max_run_length_prefix);
+ memset(histogram, 0, sizeof(histogram));
+ for (i = 0; i < num_rle_symbols; ++i) {
+ ++histogram[rle_symbols[i] & kSymbolMask];
+ }
+ {
+ BROTLI_BOOL use_rle = TO_BROTLI_BOOL(max_run_length_prefix > 0);
+ BrotliWriteBits(1, (uint64_t)use_rle, storage_ix, storage);
+ if (use_rle) {
+ BrotliWriteBits(4, max_run_length_prefix - 1, storage_ix, storage);
+ }
+ }
+ BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix,
+ num_clusters + max_run_length_prefix,
+ tree, depths, bits, storage_ix, storage);
+ for (i = 0; i < num_rle_symbols; ++i) {
+ const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask;
+ const uint32_t extra_bits_val = rle_symbols[i] >> SYMBOL_BITS;
+ BrotliWriteBits(depths[rle_symbol], bits[rle_symbol], storage_ix, storage);
+ if (rle_symbol > 0 && rle_symbol <= max_run_length_prefix) {
+ BrotliWriteBits(rle_symbol, extra_bits_val, storage_ix, storage);
+ }
+ }
+ BrotliWriteBits(1, 1, storage_ix, storage); /* use move-to-front */
+ BROTLI_FREE(m, rle_symbols);
+}
+
+/* Stores the block switch command with index block_ix to the bit stream. */
+static BROTLI_INLINE void StoreBlockSwitch(BlockSplitCode* code,
+ const uint32_t block_len,
+ const uint8_t block_type,
+ BROTLI_BOOL is_first_block,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ size_t typecode = NextBlockTypeCode(&code->type_code_calculator, block_type);
+ size_t lencode;
+ uint32_t len_nextra;
+ uint32_t len_extra;
+ if (!is_first_block) {
+ BrotliWriteBits(code->type_depths[typecode], code->type_bits[typecode],
+ storage_ix, storage);
+ }
+ GetBlockLengthPrefixCode(block_len, &lencode, &len_nextra, &len_extra);
+
+ BrotliWriteBits(code->length_depths[lencode], code->length_bits[lencode],
+ storage_ix, storage);
+ BrotliWriteBits(len_nextra, len_extra, storage_ix, storage);
+}
+
+/* Builds a BlockSplitCode data structure from the block split given by the
+ vector of block types and block lengths and stores it to the bit stream. */
+static void BuildAndStoreBlockSplitCode(const uint8_t* types,
+ const uint32_t* lengths,
+ const size_t num_blocks,
+ const size_t num_types,
+ HuffmanTree* tree,
+ BlockSplitCode* code,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ uint32_t type_histo[BROTLI_MAX_BLOCK_TYPE_SYMBOLS];
+ uint32_t length_histo[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
+ size_t i;
+ BlockTypeCodeCalculator type_code_calculator;
+ memset(type_histo, 0, (num_types + 2) * sizeof(type_histo[0]));
+ memset(length_histo, 0, sizeof(length_histo));
+ InitBlockTypeCodeCalculator(&type_code_calculator);
+ for (i = 0; i < num_blocks; ++i) {
+ size_t type_code = NextBlockTypeCode(&type_code_calculator, types[i]);
+ if (i != 0) ++type_histo[type_code];
+ ++length_histo[BlockLengthPrefixCode(lengths[i])];
+ }
+ StoreVarLenUint8(num_types - 1, storage_ix, storage);
+ if (num_types > 1) { /* TODO: else? could StoreBlockSwitch occur? */
+ BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, num_types + 2, tree,
+ &code->type_depths[0], &code->type_bits[0],
+ storage_ix, storage);
+ BuildAndStoreHuffmanTree(&length_histo[0], BROTLI_NUM_BLOCK_LEN_SYMBOLS,
+ BROTLI_NUM_BLOCK_LEN_SYMBOLS,
+ tree, &code->length_depths[0],
+ &code->length_bits[0], storage_ix, storage);
+ StoreBlockSwitch(code, lengths[0], types[0], 1, storage_ix, storage);
+ }
+}
+
+/* Stores a context map where the histogram type is always the block type. */
+static void StoreTrivialContextMap(size_t num_types,
+ size_t context_bits,
+ HuffmanTree* tree,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ StoreVarLenUint8(num_types - 1, storage_ix, storage);
+ if (num_types > 1) {
+ size_t repeat_code = context_bits - 1u;
+ size_t repeat_bits = (1u << repeat_code) - 1u;
+ size_t alphabet_size = num_types + repeat_code;
+ uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+ uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+ uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
+ size_t i;
+ memset(histogram, 0, alphabet_size * sizeof(histogram[0]));
+ /* Write RLEMAX. */
+ BrotliWriteBits(1, 1, storage_ix, storage);
+ BrotliWriteBits(4, repeat_code - 1, storage_ix, storage);
+ histogram[repeat_code] = (uint32_t)num_types;
+ histogram[0] = 1;
+ for (i = context_bits; i < alphabet_size; ++i) {
+ histogram[i] = 1;
+ }
+ BuildAndStoreHuffmanTree(histogram, alphabet_size, alphabet_size,
+ tree, depths, bits, storage_ix, storage);
+ for (i = 0; i < num_types; ++i) {
+ size_t code = (i == 0 ? 0 : i + context_bits - 1);
+ BrotliWriteBits(depths[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(
+ depths[repeat_code], bits[repeat_code], storage_ix, storage);
+ BrotliWriteBits(repeat_code, repeat_bits, storage_ix, storage);
+ }
+ /* Write IMTF (inverse-move-to-front) bit. */
+ BrotliWriteBits(1, 1, storage_ix, storage);
+ }
+}
+
+/* Manages the encoding of one block category (literal, command or distance). */
+typedef struct BlockEncoder {
+ size_t histogram_length_;
+ size_t num_block_types_;
+ const uint8_t* block_types_; /* Not owned. */
+ const uint32_t* block_lengths_; /* Not owned. */
+ size_t num_blocks_;
+ BlockSplitCode block_split_code_;
+ size_t block_ix_;
+ size_t block_len_;
+ size_t entropy_ix_;
+ uint8_t* depths_;
+ uint16_t* bits_;
+} BlockEncoder;
+
+static void InitBlockEncoder(BlockEncoder* self, size_t histogram_length,
+ size_t num_block_types, const uint8_t* block_types,
+ const uint32_t* block_lengths, const size_t num_blocks) {
+ self->histogram_length_ = histogram_length;
+ self->num_block_types_ = num_block_types;
+ self->block_types_ = block_types;
+ self->block_lengths_ = block_lengths;
+ self->num_blocks_ = num_blocks;
+ InitBlockTypeCodeCalculator(&self->block_split_code_.type_code_calculator);
+ self->block_ix_ = 0;
+ self->block_len_ = num_blocks == 0 ? 0 : block_lengths[0];
+ self->entropy_ix_ = 0;
+ self->depths_ = 0;
+ self->bits_ = 0;
+}
+
+static void CleanupBlockEncoder(MemoryManager* m, BlockEncoder* self) {
+ BROTLI_FREE(m, self->depths_);
+ BROTLI_FREE(m, self->bits_);
+}
+
+/* Creates entropy codes of block lengths and block types and stores them
+ to the bit stream. */
+static void BuildAndStoreBlockSwitchEntropyCodes(BlockEncoder* self,
+ HuffmanTree* tree, size_t* storage_ix, uint8_t* storage) {
+ BuildAndStoreBlockSplitCode(self->block_types_, self->block_lengths_,
+ self->num_blocks_, self->num_block_types_, tree, &self->block_split_code_,
+ storage_ix, storage);
+}
+
+/* Stores the next symbol with the entropy code of the current block type.
+ Updates the block type and block length at block boundaries. */
+static void StoreSymbol(BlockEncoder* self, size_t symbol, size_t* storage_ix,
+ uint8_t* storage) {
+ if (self->block_len_ == 0) {
+ size_t block_ix = ++self->block_ix_;
+ uint32_t block_len = self->block_lengths_[block_ix];
+ uint8_t block_type = self->block_types_[block_ix];
+ self->block_len_ = block_len;
+ self->entropy_ix_ = block_type * self->histogram_length_;
+ StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0,
+ storage_ix, storage);
+ }
+ --self->block_len_;
+ {
+ size_t ix = self->entropy_ix_ + symbol;
+ BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage);
+ }
+}
+
+/* Stores the next symbol with the entropy code of the current block type and
+ context value.
+ Updates the block type and block length at block boundaries. */
+static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol,
+ size_t context, const uint32_t* context_map, size_t* storage_ix,
+ uint8_t* storage, const size_t context_bits) {
+ if (self->block_len_ == 0) {
+ size_t block_ix = ++self->block_ix_;
+ uint32_t block_len = self->block_lengths_[block_ix];
+ uint8_t block_type = self->block_types_[block_ix];
+ self->block_len_ = block_len;
+ self->entropy_ix_ = (size_t)block_type << context_bits;
+ StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0,
+ storage_ix, storage);
+ }
+ --self->block_len_;
+ {
+ size_t histo_ix = context_map[self->entropy_ix_ + context];
+ size_t ix = histo_ix * self->histogram_length_ + symbol;
+ BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage);
+ }
+}
+
+#define FN(X) X ## Literal
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_encoder_inc.h"
+#undef FN
+
+#define FN(X) X ## Command
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_encoder_inc.h"
+#undef FN
+
+#define FN(X) X ## Distance
+/* NOLINTNEXTLINE(build/include) */
+#include "./block_encoder_inc.h"
+#undef FN
+
+static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ storage[*storage_ix >> 3] = 0;
+}
+
+void BrotliStoreMetaBlock(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
+ const BrotliEncoderParams* params, ContextType literal_context_mode,
+ const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
+ size_t* storage_ix, uint8_t* storage) {
+
+ size_t pos = start_pos;
+ size_t i;
+ uint32_t num_distance_symbols = params->dist.alphabet_size_max;
+ uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
+ HuffmanTree* tree;
+ ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
+ BlockEncoder literal_enc;
+ BlockEncoder command_enc;
+ BlockEncoder distance_enc;
+ const BrotliDistanceParams* dist = &params->dist;
+ BROTLI_DCHECK(
+ num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
+
+ StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
+
+ tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
+ InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
+ mb->literal_split.num_types, mb->literal_split.types,
+ mb->literal_split.lengths, mb->literal_split.num_blocks);
+ InitBlockEncoder(&command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
+ mb->command_split.num_types, mb->command_split.types,
+ mb->command_split.lengths, mb->command_split.num_blocks);
+ InitBlockEncoder(&distance_enc, num_effective_distance_symbols,
+ mb->distance_split.num_types, mb->distance_split.types,
+ mb->distance_split.lengths, mb->distance_split.num_blocks);
+
+ BuildAndStoreBlockSwitchEntropyCodes(&literal_enc, tree, storage_ix, storage);
+ BuildAndStoreBlockSwitchEntropyCodes(&command_enc, tree, storage_ix, storage);
+ BuildAndStoreBlockSwitchEntropyCodes(
+ &distance_enc, tree, storage_ix, storage);
+
+ BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage);
+ BrotliWriteBits(
+ 4, dist->num_direct_distance_codes >> dist->distance_postfix_bits,
+ storage_ix, storage);
+ for (i = 0; i < mb->literal_split.num_types; ++i) {
+ BrotliWriteBits(2, literal_context_mode, storage_ix, storage);
+ }
+
+ if (mb->literal_context_map_size == 0) {
+ StoreTrivialContextMap(mb->literal_histograms_size,
+ BROTLI_LITERAL_CONTEXT_BITS, tree, storage_ix, storage);
+ } else {
+ EncodeContextMap(m,
+ mb->literal_context_map, mb->literal_context_map_size,
+ mb->literal_histograms_size, tree, storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+
+ if (mb->distance_context_map_size == 0) {
+ StoreTrivialContextMap(mb->distance_histograms_size,
+ BROTLI_DISTANCE_CONTEXT_BITS, tree, storage_ix, storage);
+ } else {
+ EncodeContextMap(m,
+ mb->distance_context_map, mb->distance_context_map_size,
+ mb->distance_histograms_size, tree, storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+
+ BuildAndStoreEntropyCodesLiteral(m, &literal_enc, mb->literal_histograms,
+ mb->literal_histograms_size, BROTLI_NUM_LITERAL_SYMBOLS, tree,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BuildAndStoreEntropyCodesCommand(m, &command_enc, mb->command_histograms,
+ mb->command_histograms_size, BROTLI_NUM_COMMAND_SYMBOLS, tree,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BuildAndStoreEntropyCodesDistance(m, &distance_enc, mb->distance_histograms,
+ mb->distance_histograms_size, num_distance_symbols, tree,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, tree);
+
+ for (i = 0; i < n_commands; ++i) {
+ const Command cmd = commands[i];
+ size_t cmd_code = cmd.cmd_prefix_;
+ StoreSymbol(&command_enc, cmd_code, storage_ix, storage);
+ StoreCommandExtra(&cmd, storage_ix, storage);
+ if (mb->literal_context_map_size == 0) {
+ size_t j;
+ for (j = cmd.insert_len_; j != 0; --j) {
+ StoreSymbol(&literal_enc, input[pos & mask], storage_ix, storage);
+ ++pos;
+ }
+ } else {
+ size_t j;
+ for (j = cmd.insert_len_; j != 0; --j) {
+ size_t context =
+ BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
+ uint8_t literal = input[pos & mask];
+ StoreSymbolWithContext(&literal_enc, literal, context,
+ mb->literal_context_map, storage_ix, storage,
+ BROTLI_LITERAL_CONTEXT_BITS);
+ prev_byte2 = prev_byte;
+ prev_byte = literal;
+ ++pos;
+ }
+ }
+ pos += CommandCopyLen(&cmd);
+ if (CommandCopyLen(&cmd)) {
+ prev_byte2 = input[(pos - 2) & mask];
+ prev_byte = input[(pos - 1) & mask];
+ if (cmd.cmd_prefix_ >= 128) {
+ size_t dist_code = cmd.dist_prefix_ & 0x3FF;
+ uint32_t distnumextra = cmd.dist_prefix_ >> 10;
+ uint64_t distextra = cmd.dist_extra_;
+ if (mb->distance_context_map_size == 0) {
+ StoreSymbol(&distance_enc, dist_code, storage_ix, storage);
+ } else {
+ size_t context = CommandDistanceContext(&cmd);
+ StoreSymbolWithContext(&distance_enc, dist_code, context,
+ mb->distance_context_map, storage_ix, storage,
+ BROTLI_DISTANCE_CONTEXT_BITS);
+ }
+ BrotliWriteBits(distnumextra, distextra, storage_ix, storage);
+ }
+ }
+ }
+ CleanupBlockEncoder(m, &distance_enc);
+ CleanupBlockEncoder(m, &command_enc);
+ CleanupBlockEncoder(m, &literal_enc);
+ if (is_last) {
+ JumpToByteBoundary(storage_ix, storage);
+ }
+}
+
+static void BuildHistograms(const uint8_t* input,
+ size_t start_pos,
+ size_t mask,
+ const Command* commands,
+ size_t n_commands,
+ HistogramLiteral* lit_histo,
+ HistogramCommand* cmd_histo,
+ HistogramDistance* dist_histo) {
+ size_t pos = start_pos;
+ size_t i;
+ for (i = 0; i < n_commands; ++i) {
+ const Command cmd = commands[i];
+ size_t j;
+ HistogramAddCommand(cmd_histo, cmd.cmd_prefix_);
+ for (j = cmd.insert_len_; j != 0; --j) {
+ HistogramAddLiteral(lit_histo, input[pos & mask]);
+ ++pos;
+ }
+ pos += CommandCopyLen(&cmd);
+ if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
+ HistogramAddDistance(dist_histo, cmd.dist_prefix_ & 0x3FF);
+ }
+ }
+}
+
+static void StoreDataWithHuffmanCodes(const uint8_t* input,
+ size_t start_pos,
+ size_t mask,
+ const Command* commands,
+ size_t n_commands,
+ const uint8_t* lit_depth,
+ const uint16_t* lit_bits,
+ const uint8_t* cmd_depth,
+ const uint16_t* cmd_bits,
+ const uint8_t* dist_depth,
+ const uint16_t* dist_bits,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ size_t pos = start_pos;
+ size_t i;
+ for (i = 0; i < n_commands; ++i) {
+ const Command cmd = commands[i];
+ const size_t cmd_code = cmd.cmd_prefix_;
+ size_t j;
+ BrotliWriteBits(
+ cmd_depth[cmd_code], cmd_bits[cmd_code], storage_ix, storage);
+ StoreCommandExtra(&cmd, storage_ix, storage);
+ for (j = cmd.insert_len_; j != 0; --j) {
+ const uint8_t literal = input[pos & mask];
+ BrotliWriteBits(
+ lit_depth[literal], lit_bits[literal], storage_ix, storage);
+ ++pos;
+ }
+ pos += CommandCopyLen(&cmd);
+ if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
+ const size_t dist_code = cmd.dist_prefix_ & 0x3FF;
+ const uint32_t distnumextra = cmd.dist_prefix_ >> 10;
+ const uint32_t distextra = cmd.dist_extra_;
+ BrotliWriteBits(dist_depth[dist_code], dist_bits[dist_code],
+ storage_ix, storage);
+ BrotliWriteBits(distnumextra, distextra, storage_ix, storage);
+ }
+ }
+}
+
+void BrotliStoreMetaBlockTrivial(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ BROTLI_BOOL is_last, const BrotliEncoderParams* params,
+ const Command* commands, size_t n_commands,
+ size_t* storage_ix, uint8_t* storage) {
+ HistogramLiteral lit_histo;
+ HistogramCommand cmd_histo;
+ HistogramDistance dist_histo;
+ uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
+ uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
+ HuffmanTree* tree;
+ uint32_t num_distance_symbols = params->dist.alphabet_size_max;
+
+ StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
+
+ HistogramClearLiteral(&lit_histo);
+ HistogramClearCommand(&cmd_histo);
+ HistogramClearDistance(&dist_histo);
+
+ BuildHistograms(input, start_pos, mask, commands, n_commands,
+ &lit_histo, &cmd_histo, &dist_histo);
+
+ BrotliWriteBits(13, 0, storage_ix, storage);
+
+ tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
+ BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
+ BROTLI_NUM_LITERAL_SYMBOLS, tree,
+ lit_depth, lit_bits,
+ storage_ix, storage);
+ BuildAndStoreHuffmanTree(cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
+ BROTLI_NUM_COMMAND_SYMBOLS, tree,
+ cmd_depth, cmd_bits,
+ storage_ix, storage);
+ BuildAndStoreHuffmanTree(dist_histo.data_, MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
+ num_distance_symbols, tree,
+ dist_depth, dist_bits,
+ storage_ix, storage);
+ BROTLI_FREE(m, tree);
+ StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
+ n_commands, lit_depth, lit_bits,
+ cmd_depth, cmd_bits,
+ dist_depth, dist_bits,
+ storage_ix, storage);
+ if (is_last) {
+ JumpToByteBoundary(storage_ix, storage);
+ }
+}
+
+void BrotliStoreMetaBlockFast(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ BROTLI_BOOL is_last, const BrotliEncoderParams* params,
+ const Command* commands, size_t n_commands,
+ size_t* storage_ix, uint8_t* storage) {
+ uint32_t num_distance_symbols = params->dist.alphabet_size_max;
+ uint32_t distance_alphabet_bits =
+ Log2FloorNonZero(num_distance_symbols - 1) + 1;
+
+ StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
+
+ BrotliWriteBits(13, 0, storage_ix, storage);
+
+ if (n_commands <= 128) {
+ uint32_t histogram[BROTLI_NUM_LITERAL_SYMBOLS] = { 0 };
+ size_t pos = start_pos;
+ size_t num_literals = 0;
+ size_t i;
+ uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
+ for (i = 0; i < n_commands; ++i) {
+ const Command cmd = commands[i];
+ size_t j;
+ for (j = cmd.insert_len_; j != 0; --j) {
+ ++histogram[input[pos & mask]];
+ ++pos;
+ }
+ num_literals += cmd.insert_len_;
+ pos += CommandCopyLen(&cmd);
+ }
+ BrotliBuildAndStoreHuffmanTreeFast(m, histogram, num_literals,
+ /* max_bits = */ 8,
+ lit_depth, lit_bits,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ StoreStaticCommandHuffmanTree(storage_ix, storage);
+ StoreStaticDistanceHuffmanTree(storage_ix, storage);
+ StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
+ n_commands, lit_depth, lit_bits,
+ kStaticCommandCodeDepth,
+ kStaticCommandCodeBits,
+ kStaticDistanceCodeDepth,
+ kStaticDistanceCodeBits,
+ storage_ix, storage);
+ } else {
+ HistogramLiteral lit_histo;
+ HistogramCommand cmd_histo;
+ HistogramDistance dist_histo;
+ uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
+ uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
+ uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
+ uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
+ HistogramClearLiteral(&lit_histo);
+ HistogramClearCommand(&cmd_histo);
+ HistogramClearDistance(&dist_histo);
+ BuildHistograms(input, start_pos, mask, commands, n_commands,
+ &lit_histo, &cmd_histo, &dist_histo);
+ BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo.data_,
+ lit_histo.total_count_,
+ /* max_bits = */ 8,
+ lit_depth, lit_bits,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BrotliBuildAndStoreHuffmanTreeFast(m, cmd_histo.data_,
+ cmd_histo.total_count_,
+ /* max_bits = */ 10,
+ cmd_depth, cmd_bits,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BrotliBuildAndStoreHuffmanTreeFast(m, dist_histo.data_,
+ dist_histo.total_count_,
+ /* max_bits = */
+ distance_alphabet_bits,
+ dist_depth, dist_bits,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
+ n_commands, lit_depth, lit_bits,
+ cmd_depth, cmd_bits,
+ dist_depth, dist_bits,
+ storage_ix, storage);
+ }
+
+ if (is_last) {
+ JumpToByteBoundary(storage_ix, storage);
+ }
+}
+
+/* This is for storing uncompressed blocks (simple raw storage of
+ bytes-as-bytes). */
+void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
+ const uint8_t* BROTLI_RESTRICT input,
+ size_t position, size_t mask,
+ size_t len,
+ size_t* BROTLI_RESTRICT storage_ix,
+ uint8_t* BROTLI_RESTRICT storage) {
+ size_t masked_pos = position & mask;
+ BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
+ JumpToByteBoundary(storage_ix, storage);
+
+ if (masked_pos + len > mask + 1) {
+ size_t len1 = mask + 1 - masked_pos;
+ memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len1);
+ *storage_ix += len1 << 3;
+ len -= len1;
+ masked_pos = 0;
+ }
+ memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len);
+ *storage_ix += len << 3;
+
+ /* We need to clear the next 4 bytes to continue to be
+ compatible with BrotliWriteBits. */
+ BrotliWriteBitsPrepareStorage(*storage_ix, storage);
+
+ /* Since the uncompressed block itself may not be the final block, add an
+ empty one after this. */
+ if (is_final_block) {
+ BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
+ BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
+ JumpToByteBoundary(storage_ix, storage);
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.h
new file mode 100644
index 000000000..2ed703bf7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/brotli_bit_stream.h
@@ -0,0 +1,84 @@
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions to convert brotli-related data structures into the
+ brotli bit stream. The functions here operate under
+ assumption that there is enough space in the storage, i.e., there are
+ no out-of-range checks anywhere.
+
+ These functions do bit addressing into a byte array. The byte array
+ is called "storage" and the index to the bit is called storage_ix
+ in function arguments. */
+
+#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
+#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
+
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./command.h"
+#include "./entropy_encode.h"
+#include "./memory.h"
+#include "./metablock.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* All Store functions here will use a storage_ix, which is always the bit
+ position for the current storage. */
+
+BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
+ HuffmanTree* tree, size_t* storage_ix, uint8_t* storage);
+
+BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
+ MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
+ const size_t max_bits, uint8_t* depth, uint16_t* bits, size_t* storage_ix,
+ uint8_t* storage);
+
+/* REQUIRES: length > 0 */
+/* REQUIRES: length <= (1 << 24) */
+BROTLI_INTERNAL void BrotliStoreMetaBlock(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
+ const BrotliEncoderParams* params, ContextType literal_context_mode,
+ const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
+ size_t* storage_ix, uint8_t* storage);
+
+/* Stores the meta-block without doing any block splitting, just collects
+ one histogram per block category and uses that for entropy coding.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ BROTLI_BOOL is_last, const BrotliEncoderParams* params,
+ const Command* commands, size_t n_commands,
+ size_t* storage_ix, uint8_t* storage);
+
+/* Same as above, but uses static prefix codes for histograms with a only a few
+ symbols, and uses static code length prefix codes for all other histograms.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m,
+ const uint8_t* input, size_t start_pos, size_t length, size_t mask,
+ BROTLI_BOOL is_last, const BrotliEncoderParams* params,
+ const Command* commands, size_t n_commands,
+ size_t* storage_ix, uint8_t* storage);
+
+/* This is for storing uncompressed blocks (simple raw storage of
+ bytes-as-bytes).
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock(
+ BROTLI_BOOL is_final_block, const uint8_t* BROTLI_RESTRICT input,
+ size_t position, size_t mask, size_t len,
+ size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_BROTLI_BIT_STREAM_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.c
new file mode 100644
index 000000000..a20dfd385
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.c
@@ -0,0 +1,56 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for clustering similar histograms together. */
+
+#include "./cluster.h"
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./bit_cost.h" /* BrotliPopulationCost */
+#include "./fast_log.h"
+#include "./histogram.h"
+#include "./memory.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static BROTLI_INLINE BROTLI_BOOL HistogramPairIsLess(
+ const HistogramPair* p1, const HistogramPair* p2) {
+ if (p1->cost_diff != p2->cost_diff) {
+ return TO_BROTLI_BOOL(p1->cost_diff > p2->cost_diff);
+ }
+ return TO_BROTLI_BOOL((p1->idx2 - p1->idx1) > (p2->idx2 - p2->idx1));
+}
+
+/* Returns entropy reduction of the context map when we combine two clusters. */
+static BROTLI_INLINE double ClusterCostDiff(size_t size_a, size_t size_b) {
+ size_t size_c = size_a + size_b;
+ return (double)size_a * FastLog2(size_a) +
+ (double)size_b * FastLog2(size_b) -
+ (double)size_c * FastLog2(size_c);
+}
+
+#define CODE(X) X
+
+#define FN(X) X ## Literal
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Command
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Distance
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#undef CODE
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.h
new file mode 100644
index 000000000..bb26124d2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster.h
@@ -0,0 +1,48 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for clustering similar histograms together. */
+
+#ifndef BROTLI_ENC_CLUSTER_H_
+#define BROTLI_ENC_CLUSTER_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./histogram.h"
+#include "./memory.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct HistogramPair {
+ uint32_t idx1;
+ uint32_t idx2;
+ double cost_combo;
+ double cost_diff;
+} HistogramPair;
+
+#define CODE(X) /* Declaration */;
+
+#define FN(X) X ## Literal
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Command
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Distance
+#include "./cluster_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#undef CODE
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_CLUSTER_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster_inc.h
new file mode 100644
index 000000000..3d4f40e60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/cluster_inc.h
@@ -0,0 +1,320 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, CODE */
+
+#define HistogramType FN(Histogram)
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
+ const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
+ uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
+ size_t* num_pairs) CODE({
+ BROTLI_BOOL is_good_pair = BROTLI_FALSE;
+ HistogramPair p;
+ p.idx1 = p.idx2 = 0;
+ p.cost_diff = p.cost_combo = 0;
+ if (idx1 == idx2) {
+ return;
+ }
+ if (idx2 < idx1) {
+ uint32_t t = idx2;
+ idx2 = idx1;
+ idx1 = t;
+ }
+ p.idx1 = idx1;
+ p.idx2 = idx2;
+ p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]);
+ p.cost_diff -= out[idx1].bit_cost_;
+ p.cost_diff -= out[idx2].bit_cost_;
+
+ if (out[idx1].total_count_ == 0) {
+ p.cost_combo = out[idx2].bit_cost_;
+ is_good_pair = BROTLI_TRUE;
+ } else if (out[idx2].total_count_ == 0) {
+ p.cost_combo = out[idx1].bit_cost_;
+ is_good_pair = BROTLI_TRUE;
+ } else {
+ double threshold = *num_pairs == 0 ? 1e99 :
+ BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
+ HistogramType combo = out[idx1];
+ double cost_combo;
+ FN(HistogramAddHistogram)(&combo, &out[idx2]);
+ cost_combo = FN(BrotliPopulationCost)(&combo);
+ if (cost_combo < threshold - p.cost_diff) {
+ p.cost_combo = cost_combo;
+ is_good_pair = BROTLI_TRUE;
+ }
+ }
+ if (is_good_pair) {
+ p.cost_diff += p.cost_combo;
+ if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) {
+ /* Replace the top of the queue if needed. */
+ if (*num_pairs < max_num_pairs) {
+ pairs[*num_pairs] = pairs[0];
+ ++(*num_pairs);
+ }
+ pairs[0] = p;
+ } else if (*num_pairs < max_num_pairs) {
+ pairs[*num_pairs] = p;
+ ++(*num_pairs);
+ }
+ }
+})
+
+BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
+ uint32_t* cluster_size,
+ uint32_t* symbols,
+ uint32_t* clusters,
+ HistogramPair* pairs,
+ size_t num_clusters,
+ size_t symbols_size,
+ size_t max_clusters,
+ size_t max_num_pairs) CODE({
+ double cost_diff_threshold = 0.0;
+ size_t min_cluster_size = 1;
+ size_t num_pairs = 0;
+
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ size_t idx1;
+ for (idx1 = 0; idx1 < num_clusters; ++idx1) {
+ size_t idx2;
+ for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
+ FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
+ clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
+ }
+ }
+ }
+
+ while (num_clusters > min_cluster_size) {
+ uint32_t best_idx1;
+ uint32_t best_idx2;
+ size_t i;
+ if (pairs[0].cost_diff >= cost_diff_threshold) {
+ cost_diff_threshold = 1e99;
+ min_cluster_size = max_clusters;
+ continue;
+ }
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1;
+ best_idx2 = pairs[0].idx2;
+ FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]);
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo;
+ cluster_size[best_idx1] += cluster_size[best_idx2];
+ for (i = 0; i < symbols_size; ++i) {
+ if (symbols[i] == best_idx2) {
+ symbols[i] = best_idx1;
+ }
+ }
+ for (i = 0; i < num_clusters; ++i) {
+ if (clusters[i] == best_idx2) {
+ memmove(&clusters[i], &clusters[i + 1],
+ (num_clusters - i - 1) * sizeof(clusters[0]));
+ break;
+ }
+ }
+ --num_clusters;
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ size_t copy_to_idx = 0;
+ for (i = 0; i < num_pairs; ++i) {
+ HistogramPair* p = &pairs[i];
+ if (p->idx1 == best_idx1 || p->idx2 == best_idx1 ||
+ p->idx1 == best_idx2 || p->idx2 == best_idx2) {
+ /* Remove invalid pair from the queue. */
+ continue;
+ }
+ if (HistogramPairIsLess(&pairs[0], p)) {
+ /* Replace the top of the queue if needed. */
+ HistogramPair front = pairs[0];
+ pairs[0] = *p;
+ pairs[copy_to_idx] = front;
+ } else {
+ pairs[copy_to_idx] = *p;
+ }
+ ++copy_to_idx;
+ }
+ num_pairs = copy_to_idx;
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for (i = 0; i < num_clusters; ++i) {
+ FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
+ max_num_pairs, &pairs[0], &num_pairs);
+ }
+ }
+ return num_clusters;
+})
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
+ const HistogramType* histogram, const HistogramType* candidate) CODE({
+ if (histogram->total_count_ == 0) {
+ return 0.0;
+ } else {
+ HistogramType tmp = *histogram;
+ FN(HistogramAddHistogram)(&tmp, candidate);
+ return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
+ }
+})
+
+/* Find the best 'out' histogram for each of the 'in' histograms.
+ When called, clusters[0..num_clusters) contains the unique values from
+ symbols[0..in_size), but this property is not preserved in this function.
+ Note: we assume that out[]->bit_cost_ is already up-to-date. */
+BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
+ size_t in_size, const uint32_t* clusters, size_t num_clusters,
+ HistogramType* out, uint32_t* symbols) CODE({
+ size_t i;
+ for (i = 0; i < in_size; ++i) {
+ uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
+ double best_bits =
+ FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
+ size_t j;
+ for (j = 0; j < num_clusters; ++j) {
+ const double cur_bits =
+ FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
+ if (cur_bits < best_bits) {
+ best_bits = cur_bits;
+ best_out = clusters[j];
+ }
+ }
+ symbols[i] = best_out;
+ }
+
+ /* Recompute each out based on raw and symbols. */
+ for (i = 0; i < num_clusters; ++i) {
+ FN(HistogramClear)(&out[clusters[i]]);
+ }
+ for (i = 0; i < in_size; ++i) {
+ FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]);
+ }
+})
+
+/* Reorders elements of the out[0..length) array and changes values in
+ symbols[0..length) array in the following way:
+ * when called, symbols[] contains indexes into out[], and has N unique
+ values (possibly N < length)
+ * on return, symbols'[i] = f(symbols[i]) and
+ out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
+ where f is a bijection between the range of symbols[] and [0..N), and
+ the first occurrences of values in symbols'[i] come in consecutive
+ increasing order.
+ Returns N, the number of unique values in symbols[]. */
+BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
+ HistogramType* out, uint32_t* symbols, size_t length) CODE({
+ static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
+ uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length);
+ uint32_t next_index;
+ HistogramType* tmp;
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
+ for (i = 0; i < length; ++i) {
+ new_index[i] = kInvalidIndex;
+ }
+ next_index = 0;
+ for (i = 0; i < length; ++i) {
+ if (new_index[symbols[i]] == kInvalidIndex) {
+ new_index[symbols[i]] = next_index;
+ ++next_index;
+ }
+ }
+ /* TODO: by using idea of "cycle-sort" we can avoid allocation of
+ tmp and reduce the number of copying by the factor of 2. */
+ tmp = BROTLI_ALLOC(m, HistogramType, next_index);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
+ next_index = 0;
+ for (i = 0; i < length; ++i) {
+ if (new_index[symbols[i]] == next_index) {
+ tmp[next_index] = out[symbols[i]];
+ ++next_index;
+ }
+ symbols[i] = new_index[symbols[i]];
+ }
+ BROTLI_FREE(m, new_index);
+ for (i = 0; i < next_index; ++i) {
+ out[i] = tmp[i];
+ }
+ BROTLI_FREE(m, tmp);
+ return next_index;
+})
+
+BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
+ MemoryManager* m, const HistogramType* in, const size_t in_size,
+ size_t max_histograms, HistogramType* out, size_t* out_size,
+ uint32_t* histogram_symbols) CODE({
+ uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size);
+ uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size);
+ size_t num_clusters = 0;
+ const size_t max_input_histograms = 64;
+ size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
+ /* For the first pass of clustering, we allow all pairs. */
+ HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
+ size_t i;
+
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
+ BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
+ return;
+ }
+
+ for (i = 0; i < in_size; ++i) {
+ cluster_size[i] = 1;
+ }
+
+ for (i = 0; i < in_size; ++i) {
+ out[i] = in[i];
+ out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]);
+ histogram_symbols[i] = (uint32_t)i;
+ }
+
+ for (i = 0; i < in_size; i += max_input_histograms) {
+ size_t num_to_combine =
+ BROTLI_MIN(size_t, in_size - i, max_input_histograms);
+ size_t num_new_clusters;
+ size_t j;
+ for (j = 0; j < num_to_combine; ++j) {
+ clusters[num_clusters + j] = (uint32_t)(i + j);
+ }
+ num_new_clusters =
+ FN(BrotliHistogramCombine)(out, cluster_size,
+ &histogram_symbols[i],
+ &clusters[num_clusters], pairs,
+ num_to_combine, num_to_combine,
+ max_histograms, pairs_capacity);
+ num_clusters += num_new_clusters;
+ }
+
+ {
+ /* For the second pass, we limit the total number of histogram pairs.
+ After this limit is reached, we only keep searching for the best pair. */
+ size_t max_num_pairs = BROTLI_MIN(size_t,
+ 64 * num_clusters, (num_clusters / 2) * num_clusters);
+ BROTLI_ENSURE_CAPACITY(
+ m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1);
+ if (BROTLI_IS_OOM(m)) return;
+
+ /* Collapse similar histograms. */
+ num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
+ histogram_symbols, clusters,
+ pairs, num_clusters, in_size,
+ max_histograms, max_num_pairs);
+ }
+ BROTLI_FREE(m, pairs);
+ BROTLI_FREE(m, cluster_size);
+ /* Find the optimal map from original histograms to the final ones. */
+ FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
+ out, histogram_symbols);
+ BROTLI_FREE(m, clusters);
+ /* Convert the context map to a canonical form. */
+ *out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
+ if (BROTLI_IS_OOM(m)) return;
+})
+
+#undef HistogramType
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/command.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/command.h
new file mode 100644
index 000000000..1aac85689
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/command.h
@@ -0,0 +1,190 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* This class models a sequence of literals and a backward reference copy. */
+
+#ifndef BROTLI_ENC_COMMAND_H_
+#define BROTLI_ENC_COMMAND_H_
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./fast_log.h"
+#include "./params.h"
+#include "./prefix.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
+ 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
+static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
+static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
+ 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
+static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
+
+static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
+ if (insertlen < 6) {
+ return (uint16_t)insertlen;
+ } else if (insertlen < 130) {
+ uint32_t nbits = Log2FloorNonZero(insertlen - 2) - 1u;
+ return (uint16_t)((nbits << 1) + ((insertlen - 2) >> nbits) + 2);
+ } else if (insertlen < 2114) {
+ return (uint16_t)(Log2FloorNonZero(insertlen - 66) + 10);
+ } else if (insertlen < 6210) {
+ return 21u;
+ } else if (insertlen < 22594) {
+ return 22u;
+ } else {
+ return 23u;
+ }
+}
+
+static BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) {
+ if (copylen < 10) {
+ return (uint16_t)(copylen - 2);
+ } else if (copylen < 134) {
+ uint32_t nbits = Log2FloorNonZero(copylen - 6) - 1u;
+ return (uint16_t)((nbits << 1) + ((copylen - 6) >> nbits) + 4);
+ } else if (copylen < 2118) {
+ return (uint16_t)(Log2FloorNonZero(copylen - 70) + 12);
+ } else {
+ return 23u;
+ }
+}
+
+static BROTLI_INLINE uint16_t CombineLengthCodes(
+ uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
+ uint16_t bits64 =
+ (uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u));
+ if (use_last_distance && inscode < 8u && copycode < 16u) {
+ return (copycode < 8u) ? bits64 : (bits64 | 64u);
+ } else {
+ /* Specification: 5 Encoding of ... (last table) */
+ /* offset = 2 * index, where index is in range [0..8] */
+ uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u));
+ /* All values in specification are K * 64,
+ where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
+ i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
+ K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
+ All values in D require only 2 bits to encode.
+ Magic constant is shifted 6 bits left, to avoid final multiplication. */
+ offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u);
+ return (uint16_t)(offset | bits64);
+ }
+}
+
+static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
+ BROTLI_BOOL use_last_distance,
+ uint16_t* code) {
+ uint16_t inscode = GetInsertLengthCode(insertlen);
+ uint16_t copycode = GetCopyLengthCode(copylen);
+ *code = CombineLengthCodes(inscode, copycode, use_last_distance);
+}
+
+static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
+ return kInsBase[inscode];
+}
+
+static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
+ return kInsExtra[inscode];
+}
+
+static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
+ return kCopyBase[copycode];
+}
+
+static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
+ return kCopyExtra[copycode];
+}
+
+typedef struct Command {
+ uint32_t insert_len_;
+ /* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */
+ uint32_t copy_len_;
+ /* Stores distance extra bits. */
+ uint32_t dist_extra_;
+ uint16_t cmd_prefix_;
+ /* Stores distance code in low 10 bits
+ and number of extra bits in high 6 bits. */
+ uint16_t dist_prefix_;
+} Command;
+
+/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
+static BROTLI_INLINE void InitCommand(Command* self,
+ const BrotliDistanceParams* dist, size_t insertlen,
+ size_t copylen, int copylen_code_delta, size_t distance_code) {
+ /* Don't rely on signed int representation, use honest casts. */
+ uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
+ self->insert_len_ = (uint32_t)insertlen;
+ self->copy_len_ = (uint32_t)(copylen | (delta << 25));
+ /* The distance prefix and extra bits are stored in this Command as if
+ npostfix and ndirect were 0, they are only recomputed later after the
+ clustering if needed. */
+ PrefixEncodeCopyDistance(
+ distance_code, dist->num_direct_distance_codes,
+ dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_);
+ GetLengthCode(
+ insertlen, (size_t)((int)copylen + copylen_code_delta),
+ TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_);
+}
+
+static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
+ self->insert_len_ = (uint32_t)insertlen;
+ self->copy_len_ = 4 << 25;
+ self->dist_extra_ = 0;
+ self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
+ GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
+}
+
+static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(
+ const Command* self, const BrotliDistanceParams* dist) {
+ if ((self->dist_prefix_ & 0x3FFu) <
+ BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) {
+ return self->dist_prefix_ & 0x3FFu;
+ } else {
+ uint32_t dcode = self->dist_prefix_ & 0x3FFu;
+ uint32_t nbits = self->dist_prefix_ >> 10;
+ uint32_t extra = self->dist_extra_;
+ uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U;
+ uint32_t hcode = (dcode - dist->num_direct_distance_codes -
+ BROTLI_NUM_DISTANCE_SHORT_CODES) >>
+ dist->distance_postfix_bits;
+ uint32_t lcode = (dcode - dist->num_direct_distance_codes -
+ BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask;
+ uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U;
+ return ((offset + extra) << dist->distance_postfix_bits) + lcode +
+ dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES;
+ }
+}
+
+static BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) {
+ uint32_t r = self->cmd_prefix_ >> 6;
+ uint32_t c = self->cmd_prefix_ & 7;
+ if ((r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2)) {
+ return c;
+ }
+ return 3;
+}
+
+static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
+ return self->copy_len_ & 0x1FFFFFF;
+}
+
+static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
+ uint32_t modifier = self->copy_len_ >> 25;
+ int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1)));
+ return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_COMMAND_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.c
new file mode 100644
index 000000000..9e50b2098
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.c
@@ -0,0 +1,790 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses one-pass processing: when we find a backward
+ match, we immediately emit the corresponding command and literal codes to
+ the bit stream.
+
+ Adapted from the CompressFragment() function in
+ https://github.com/google/snappy/blob/master/snappy.cc */
+
+#include "./compress_fragment.h"
+
+#include <string.h> /* memcmp, memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./brotli_bit_stream.h"
+#include "./entropy_encode.h"
+#include "./fast_log.h"
+#include "./find_match_length.h"
+#include "./memory.h"
+#include "./write_bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
+
+/* kHashMul32 multiplier has these properties:
+ * The multiplier must be odd. Otherwise we may lose the highest bit.
+ * No long streaks of ones or zeros.
+ * There is no effort to ensure that it is a prime, the oddity is enough
+ for this use.
+ * The number has been tuned heuristically against compression benchmarks. */
+static const uint32_t kHashMul32 = 0x1E35A7BD;
+
+static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
+ const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
+ return (uint32_t)(h >> shift);
+}
+
+static BROTLI_INLINE uint32_t HashBytesAtOffset(
+ uint64_t v, int offset, size_t shift) {
+ BROTLI_DCHECK(offset >= 0);
+ BROTLI_DCHECK(offset <= 3);
+ {
+ const uint64_t h = ((v >> (8 * offset)) << 24) * kHashMul32;
+ return (uint32_t)(h >> shift);
+ }
+}
+
+static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
+ return TO_BROTLI_BOOL(
+ BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2) &&
+ p1[4] == p2[4]);
+}
+
+/* Builds a literal prefix code into "depths" and "bits" based on the statistics
+ of the "input" string and stores it into the bit stream.
+ Note that the prefix code here is built from the pre-LZ77 input, therefore
+ we can only approximate the statistics of the actual literal stream.
+ Moreover, for long inputs we build a histogram from a sample of the input
+ and thus have to assign a non-zero depth for each literal.
+ Returns estimated compression ratio millibytes/char for encoding given input
+ with generated code. */
+static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
+ const uint8_t* input,
+ const size_t input_size,
+ uint8_t depths[256],
+ uint16_t bits[256],
+ size_t* storage_ix,
+ uint8_t* storage) {
+ uint32_t histogram[256] = { 0 };
+ size_t histogram_total;
+ size_t i;
+ if (input_size < (1 << 15)) {
+ for (i = 0; i < input_size; ++i) {
+ ++histogram[input[i]];
+ }
+ histogram_total = input_size;
+ for (i = 0; i < 256; ++i) {
+ /* We weigh the first 11 samples with weight 3 to account for the
+ balancing effect of the LZ77 phase on the histogram. */
+ const uint32_t adjust = 2 * BROTLI_MIN(uint32_t, histogram[i], 11u);
+ histogram[i] += adjust;
+ histogram_total += adjust;
+ }
+ } else {
+ static const size_t kSampleRate = 29;
+ for (i = 0; i < input_size; i += kSampleRate) {
+ ++histogram[input[i]];
+ }
+ histogram_total = (input_size + kSampleRate - 1) / kSampleRate;
+ for (i = 0; i < 256; ++i) {
+ /* We add 1 to each population count to avoid 0 bit depths (since this is
+ only a sample and we don't know if the symbol appears or not), and we
+ weigh the first 11 samples with weight 3 to account for the balancing
+ effect of the LZ77 phase on the histogram (more frequent symbols are
+ more likely to be in backward references instead as literals). */
+ const uint32_t adjust = 1 + 2 * BROTLI_MIN(uint32_t, histogram[i], 11u);
+ histogram[i] += adjust;
+ histogram_total += adjust;
+ }
+ }
+ BrotliBuildAndStoreHuffmanTreeFast(m, histogram, histogram_total,
+ /* max_bits = */ 8,
+ depths, bits, storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return 0;
+ {
+ size_t literal_ratio = 0;
+ for (i = 0; i < 256; ++i) {
+ if (histogram[i]) literal_ratio += histogram[i] * depths[i];
+ }
+ /* Estimated encoding ratio, millibytes per symbol. */
+ return (literal_ratio * 125) / histogram_total;
+ }
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+static void BuildAndStoreCommandPrefixCode(const uint32_t histogram[128],
+ uint8_t depth[128], uint16_t bits[128], size_t* storage_ix,
+ uint8_t* storage) {
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+ HuffmanTree tree[129];
+ uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
+ uint16_t cmd_bits[64];
+
+ BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
+ BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ memcpy(cmd_depth, depth, 24);
+ memcpy(cmd_depth + 24, depth + 40, 8);
+ memcpy(cmd_depth + 32, depth + 24, 8);
+ memcpy(cmd_depth + 40, depth + 48, 8);
+ memcpy(cmd_depth + 48, depth + 32, 8);
+ memcpy(cmd_depth + 56, depth + 56, 8);
+ BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
+ memcpy(bits, cmd_bits, 48);
+ memcpy(bits + 24, cmd_bits + 32, 16);
+ memcpy(bits + 32, cmd_bits + 48, 16);
+ memcpy(bits + 40, cmd_bits + 24, 16);
+ memcpy(bits + 48, cmd_bits + 40, 16);
+ memcpy(bits + 56, cmd_bits + 56, 16);
+ BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
+ {
+ /* Create the bit length array for the full command alphabet. */
+ size_t i;
+ memset(cmd_depth, 0, 64); /* only 64 first values were used */
+ memcpy(cmd_depth, depth, 8);
+ memcpy(cmd_depth + 64, depth + 8, 8);
+ memcpy(cmd_depth + 128, depth + 16, 8);
+ memcpy(cmd_depth + 192, depth + 24, 8);
+ memcpy(cmd_depth + 384, depth + 32, 8);
+ for (i = 0; i < 8; ++i) {
+ cmd_depth[128 + 8 * i] = depth[40 + i];
+ cmd_depth[256 + 8 * i] = depth[48 + i];
+ cmd_depth[448 + 8 * i] = depth[56 + i];
+ }
+ BrotliStoreHuffmanTree(
+ cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
+ }
+ BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
+}
+
+/* REQUIRES: insertlen < 6210 */
+static BROTLI_INLINE void EmitInsertLen(size_t insertlen,
+ const uint8_t depth[128],
+ const uint16_t bits[128],
+ uint32_t histo[128],
+ size_t* storage_ix,
+ uint8_t* storage) {
+ if (insertlen < 6) {
+ const size_t code = insertlen + 40;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ ++histo[code];
+ } else if (insertlen < 130) {
+ const size_t tail = insertlen - 2;
+ const uint32_t nbits = Log2FloorNonZero(tail) - 1u;
+ const size_t prefix = tail >> nbits;
+ const size_t inscode = (nbits << 1) + prefix + 42;
+ BrotliWriteBits(depth[inscode], bits[inscode], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage);
+ ++histo[inscode];
+ } else if (insertlen < 2114) {
+ const size_t tail = insertlen - 66;
+ const uint32_t nbits = Log2FloorNonZero(tail);
+ const size_t code = nbits + 50;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage);
+ ++histo[code];
+ } else {
+ BrotliWriteBits(depth[61], bits[61], storage_ix, storage);
+ BrotliWriteBits(12, insertlen - 2114, storage_ix, storage);
+ ++histo[61];
+ }
+}
+
+static BROTLI_INLINE void EmitLongInsertLen(size_t insertlen,
+ const uint8_t depth[128],
+ const uint16_t bits[128],
+ uint32_t histo[128],
+ size_t* storage_ix,
+ uint8_t* storage) {
+ if (insertlen < 22594) {
+ BrotliWriteBits(depth[62], bits[62], storage_ix, storage);
+ BrotliWriteBits(14, insertlen - 6210, storage_ix, storage);
+ ++histo[62];
+ } else {
+ BrotliWriteBits(depth[63], bits[63], storage_ix, storage);
+ BrotliWriteBits(24, insertlen - 22594, storage_ix, storage);
+ ++histo[63];
+ }
+}
+
+static BROTLI_INLINE void EmitCopyLen(size_t copylen,
+ const uint8_t depth[128],
+ const uint16_t bits[128],
+ uint32_t histo[128],
+ size_t* storage_ix,
+ uint8_t* storage) {
+ if (copylen < 10) {
+ BrotliWriteBits(
+ depth[copylen + 14], bits[copylen + 14], storage_ix, storage);
+ ++histo[copylen + 14];
+ } else if (copylen < 134) {
+ const size_t tail = copylen - 6;
+ const uint32_t nbits = Log2FloorNonZero(tail) - 1u;
+ const size_t prefix = tail >> nbits;
+ const size_t code = (nbits << 1) + prefix + 20;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage);
+ ++histo[code];
+ } else if (copylen < 2118) {
+ const size_t tail = copylen - 70;
+ const uint32_t nbits = Log2FloorNonZero(tail);
+ const size_t code = nbits + 28;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage);
+ ++histo[code];
+ } else {
+ BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
+ BrotliWriteBits(24, copylen - 2118, storage_ix, storage);
+ ++histo[39];
+ }
+}
+
+static BROTLI_INLINE void EmitCopyLenLastDistance(size_t copylen,
+ const uint8_t depth[128],
+ const uint16_t bits[128],
+ uint32_t histo[128],
+ size_t* storage_ix,
+ uint8_t* storage) {
+ if (copylen < 12) {
+ BrotliWriteBits(depth[copylen - 4], bits[copylen - 4], storage_ix, storage);
+ ++histo[copylen - 4];
+ } else if (copylen < 72) {
+ const size_t tail = copylen - 8;
+ const uint32_t nbits = Log2FloorNonZero(tail) - 1;
+ const size_t prefix = tail >> nbits;
+ const size_t code = (nbits << 1) + prefix + 4;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage);
+ ++histo[code];
+ } else if (copylen < 136) {
+ const size_t tail = copylen - 8;
+ const size_t code = (tail >> 5) + 30;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(5, tail & 31, storage_ix, storage);
+ BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
+ ++histo[code];
+ ++histo[64];
+ } else if (copylen < 2120) {
+ const size_t tail = copylen - 72;
+ const uint32_t nbits = Log2FloorNonZero(tail);
+ const size_t code = nbits + 28;
+ BrotliWriteBits(depth[code], bits[code], storage_ix, storage);
+ BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage);
+ BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
+ ++histo[code];
+ ++histo[64];
+ } else {
+ BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
+ BrotliWriteBits(24, copylen - 2120, storage_ix, storage);
+ BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
+ ++histo[39];
+ ++histo[64];
+ }
+}
+
+static BROTLI_INLINE void EmitDistance(size_t distance,
+ const uint8_t depth[128],
+ const uint16_t bits[128],
+ uint32_t histo[128],
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t d = distance + 3;
+ const uint32_t nbits = Log2FloorNonZero(d) - 1u;
+ const size_t prefix = (d >> nbits) & 1;
+ const size_t offset = (2 + prefix) << nbits;
+ const size_t distcode = 2 * (nbits - 1) + prefix + 80;
+ BrotliWriteBits(depth[distcode], bits[distcode], storage_ix, storage);
+ BrotliWriteBits(nbits, d - offset, storage_ix, storage);
+ ++histo[distcode];
+}
+
+static BROTLI_INLINE void EmitLiterals(const uint8_t* input, const size_t len,
+ const uint8_t depth[256],
+ const uint16_t bits[256],
+ size_t* storage_ix, uint8_t* storage) {
+ size_t j;
+ for (j = 0; j < len; j++) {
+ const uint8_t lit = input[j];
+ BrotliWriteBits(depth[lit], bits[lit], storage_ix, storage);
+ }
+}
+
+/* REQUIRES: len <= 1 << 24. */
+static void BrotliStoreMetaBlockHeader(
+ size_t len, BROTLI_BOOL is_uncompressed, size_t* storage_ix,
+ uint8_t* storage) {
+ size_t nibbles = 6;
+ /* ISLAST */
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ if (len <= (1U << 16)) {
+ nibbles = 4;
+ } else if (len <= (1U << 20)) {
+ nibbles = 5;
+ }
+ BrotliWriteBits(2, nibbles - 4, storage_ix, storage);
+ BrotliWriteBits(nibbles * 4, len - 1, storage_ix, storage);
+ /* ISUNCOMPRESSED */
+ BrotliWriteBits(1, (uint64_t)is_uncompressed, storage_ix, storage);
+}
+
+static void UpdateBits(size_t n_bits, uint32_t bits, size_t pos,
+ uint8_t* array) {
+ while (n_bits > 0) {
+ size_t byte_pos = pos >> 3;
+ size_t n_unchanged_bits = pos & 7;
+ size_t n_changed_bits = BROTLI_MIN(size_t, n_bits, 8 - n_unchanged_bits);
+ size_t total_bits = n_unchanged_bits + n_changed_bits;
+ uint32_t mask =
+ (~((1u << total_bits) - 1u)) | ((1u << n_unchanged_bits) - 1u);
+ uint32_t unchanged_bits = array[byte_pos] & mask;
+ uint32_t changed_bits = bits & ((1u << n_changed_bits) - 1u);
+ array[byte_pos] =
+ (uint8_t)((changed_bits << n_unchanged_bits) | unchanged_bits);
+ n_bits -= n_changed_bits;
+ bits >>= n_changed_bits;
+ pos += n_changed_bits;
+ }
+}
+
+static void RewindBitPosition(const size_t new_storage_ix,
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t bitpos = new_storage_ix & 7;
+ const size_t mask = (1u << bitpos) - 1;
+ storage[new_storage_ix >> 3] &= (uint8_t)mask;
+ *storage_ix = new_storage_ix;
+}
+
+static BROTLI_BOOL ShouldMergeBlock(
+ const uint8_t* data, size_t len, const uint8_t* depths) {
+ size_t histo[256] = { 0 };
+ static const size_t kSampleRate = 43;
+ size_t i;
+ for (i = 0; i < len; i += kSampleRate) {
+ ++histo[data[i]];
+ }
+ {
+ const size_t total = (len + kSampleRate - 1) / kSampleRate;
+ double r = (FastLog2(total) + 0.5) * (double)total + 200;
+ for (i = 0; i < 256; ++i) {
+ r -= (double)histo[i] * (depths[i] + FastLog2(histo[i]));
+ }
+ return TO_BROTLI_BOOL(r >= 0.0);
+ }
+}
+
+/* Acceptable loss for uncompressible speedup is 2% */
+#define MIN_RATIO 980
+
+static BROTLI_INLINE BROTLI_BOOL ShouldUseUncompressedMode(
+ const uint8_t* metablock_start, const uint8_t* next_emit,
+ const size_t insertlen, const size_t literal_ratio) {
+ const size_t compressed = (size_t)(next_emit - metablock_start);
+ if (compressed * 50 > insertlen) {
+ return BROTLI_FALSE;
+ } else {
+ return TO_BROTLI_BOOL(literal_ratio > MIN_RATIO);
+ }
+}
+
+static void EmitUncompressedMetaBlock(const uint8_t* begin, const uint8_t* end,
+ const size_t storage_ix_start,
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t len = (size_t)(end - begin);
+ RewindBitPosition(storage_ix_start, storage_ix, storage);
+ BrotliStoreMetaBlockHeader(len, 1, storage_ix, storage);
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ memcpy(&storage[*storage_ix >> 3], begin, len);
+ *storage_ix += len << 3;
+ storage[*storage_ix >> 3] = 0;
+}
+
+static uint32_t kCmdHistoSeed[128] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 0, 0, 0,
+};
+
+static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
+ MemoryManager* m, const uint8_t* input, size_t input_size,
+ BROTLI_BOOL is_last, int* table, size_t table_bits, uint8_t cmd_depth[128],
+ uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
+ size_t* storage_ix, uint8_t* storage) {
+ uint32_t cmd_histo[128];
+ const uint8_t* ip_end;
+
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+ const uint8_t* next_emit = input;
+ /* Save the start of the first block for position and distance computations.
+ */
+ const uint8_t* base_ip = input;
+
+ static const size_t kFirstBlockSize = 3 << 15;
+ static const size_t kMergeBlockSize = 1 << 16;
+
+ const size_t kInputMarginBytes = BROTLI_WINDOW_GAP;
+ const size_t kMinMatchLen = 5;
+
+ const uint8_t* metablock_start = input;
+ size_t block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize);
+ size_t total_block_size = block_size;
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ size_t mlen_storage_ix = *storage_ix + 3;
+
+ uint8_t lit_depth[256];
+ uint16_t lit_bits[256];
+
+ size_t literal_ratio;
+
+ const uint8_t* ip;
+ int last_distance;
+
+ const size_t shift = 64u - table_bits;
+
+ BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage);
+ /* No block splits, no contexts. */
+ BrotliWriteBits(13, 0, storage_ix, storage);
+
+ literal_ratio = BuildAndStoreLiteralPrefixCode(
+ m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+
+ {
+ /* Store the pre-compressed command and distance prefix codes. */
+ size_t i;
+ for (i = 0; i + 7 < *cmd_code_numbits; i += 8) {
+ BrotliWriteBits(8, cmd_code[i >> 3], storage_ix, storage);
+ }
+ }
+ BrotliWriteBits(*cmd_code_numbits & 7, cmd_code[*cmd_code_numbits >> 3],
+ storage_ix, storage);
+
+ emit_commands:
+ /* Initialize the command and distance histograms. We will gather
+ statistics of command and distance codes during the processing
+ of this block and use it to update the command and distance
+ prefix codes for the next block. */
+ memcpy(cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
+
+ /* "ip" is the input pointer. */
+ ip = input;
+ last_distance = -1;
+ ip_end = input + block_size;
+
+ if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) {
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+ const size_t len_limit = BROTLI_MIN(size_t, block_size - kMinMatchLen,
+ input_size - kInputMarginBytes);
+ const uint8_t* ip_limit = input + len_limit;
+
+ uint32_t next_hash;
+ for (next_hash = Hash(++ip, shift); ; ) {
+ /* Step 1: Scan forward in the input looking for a 5-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (i.e. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+ uint32_t skip = 32;
+
+ const uint8_t* next_ip = ip;
+ const uint8_t* candidate;
+ BROTLI_DCHECK(next_emit < ip);
+trawl:
+ do {
+ uint32_t hash = next_hash;
+ uint32_t bytes_between_hash_lookups = skip++ >> 5;
+ BROTLI_DCHECK(hash == Hash(next_ip, shift));
+ ip = next_ip;
+ next_ip = ip + bytes_between_hash_lookups;
+ if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
+ goto emit_remainder;
+ }
+ next_hash = Hash(next_ip, shift);
+ candidate = ip - last_distance;
+ if (IsMatch(ip, candidate)) {
+ if (BROTLI_PREDICT_TRUE(candidate < ip)) {
+ table[hash] = (int)(ip - base_ip);
+ break;
+ }
+ }
+ candidate = base_ip + table[hash];
+ BROTLI_DCHECK(candidate >= base_ip);
+ BROTLI_DCHECK(candidate < ip);
+
+ table[hash] = (int)(ip - base_ip);
+ } while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if (ip - candidate > MAX_DISTANCE) goto trawl;
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit" to the bit stream, and then see if we can find a next match
+ immediately afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+
+ {
+ /* We have a 5-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+ const uint8_t* base = ip;
+ size_t matched = 5 + FindMatchLengthWithLimit(
+ candidate + 5, ip + 5, (size_t)(ip_end - ip) - 5);
+ int distance = (int)(base - candidate); /* > 0 */
+ size_t insert = (size_t)(base - next_emit);
+ ip += matched;
+ BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
+ if (BROTLI_PREDICT_TRUE(insert < 6210)) {
+ EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+ } else if (ShouldUseUncompressedMode(metablock_start, next_emit, insert,
+ literal_ratio)) {
+ EmitUncompressedMetaBlock(metablock_start, base, mlen_storage_ix - 3,
+ storage_ix, storage);
+ input_size -= (size_t)(base - input);
+ input = base;
+ next_emit = input;
+ goto next_block;
+ } else {
+ EmitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+ }
+ EmitLiterals(next_emit, insert, lit_depth, lit_bits,
+ storage_ix, storage);
+ if (distance == last_distance) {
+ BrotliWriteBits(cmd_depth[64], cmd_bits[64], storage_ix, storage);
+ ++cmd_histo[64];
+ } else {
+ EmitDistance((size_t)distance, cmd_depth, cmd_bits,
+ cmd_histo, storage_ix, storage);
+ last_distance = distance;
+ }
+ EmitCopyLenLastDistance(matched, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+
+ next_emit = ip;
+ if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
+ goto emit_remainder;
+ }
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
+ uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
+ uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+
+ candidate = base_ip + table[cur_hash];
+ table[cur_hash] = (int)(ip - base_ip);
+ }
+ }
+
+ while (IsMatch(ip, candidate)) {
+ /* We have a 5-byte match at ip, and no need to emit any literal bytes
+ prior to ip. */
+ const uint8_t* base = ip;
+ size_t matched = 5 + FindMatchLengthWithLimit(
+ candidate + 5, ip + 5, (size_t)(ip_end - ip) - 5);
+ if (ip - candidate > MAX_DISTANCE) break;
+ ip += matched;
+ last_distance = (int)(base - candidate); /* > 0 */
+ BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
+ EmitCopyLen(matched, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+ EmitDistance((size_t)last_distance, cmd_depth, cmd_bits,
+ cmd_histo, storage_ix, storage);
+
+ next_emit = ip;
+ if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
+ goto emit_remainder;
+ }
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
+ uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
+ uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+
+ candidate = base_ip + table[cur_hash];
+ table[cur_hash] = (int)(ip - base_ip);
+ }
+ }
+
+ next_hash = Hash(++ip, shift);
+ }
+ }
+
+ emit_remainder:
+ BROTLI_DCHECK(next_emit <= ip_end);
+ input += block_size;
+ input_size -= block_size;
+ block_size = BROTLI_MIN(size_t, input_size, kMergeBlockSize);
+
+ /* Decide if we want to continue this meta-block instead of emitting the
+ last insert-only command. */
+ if (input_size > 0 &&
+ total_block_size + block_size <= (1 << 20) &&
+ ShouldMergeBlock(input, block_size, lit_depth)) {
+ BROTLI_DCHECK(total_block_size > (1 << 16));
+ /* Update the size of the current meta-block and continue emitting commands.
+ We can do this because the current size and the new size both have 5
+ nibbles. */
+ total_block_size += block_size;
+ UpdateBits(20, (uint32_t)(total_block_size - 1), mlen_storage_ix, storage);
+ goto emit_commands;
+ }
+
+ /* Emit the remaining bytes as literals. */
+ if (next_emit < ip_end) {
+ const size_t insert = (size_t)(ip_end - next_emit);
+ if (BROTLI_PREDICT_TRUE(insert < 6210)) {
+ EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+ EmitLiterals(next_emit, insert, lit_depth, lit_bits, storage_ix, storage);
+ } else if (ShouldUseUncompressedMode(metablock_start, next_emit, insert,
+ literal_ratio)) {
+ EmitUncompressedMetaBlock(metablock_start, ip_end, mlen_storage_ix - 3,
+ storage_ix, storage);
+ } else {
+ EmitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
+ storage_ix, storage);
+ EmitLiterals(next_emit, insert, lit_depth, lit_bits,
+ storage_ix, storage);
+ }
+ }
+ next_emit = ip_end;
+
+next_block:
+ /* If we have more data, write a new meta-block header and prefix codes and
+ then continue emitting commands. */
+ if (input_size > 0) {
+ metablock_start = input;
+ block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize);
+ total_block_size = block_size;
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ mlen_storage_ix = *storage_ix + 3;
+ BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage);
+ /* No block splits, no contexts. */
+ BrotliWriteBits(13, 0, storage_ix, storage);
+ literal_ratio = BuildAndStoreLiteralPrefixCode(
+ m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
+ storage_ix, storage);
+ goto emit_commands;
+ }
+
+ if (!is_last) {
+ /* If this is not the last block, update the command and distance prefix
+ codes for the next block and store the compressed forms. */
+ cmd_code[0] = 0;
+ *cmd_code_numbits = 0;
+ BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
+ cmd_code_numbits, cmd_code);
+ }
+}
+
+#define FOR_TABLE_BITS_(X) X(9) X(11) X(13) X(15)
+
+#define BAKE_METHOD_PARAM_(B) \
+static BROTLI_NOINLINE void BrotliCompressFragmentFastImpl ## B( \
+ MemoryManager* m, const uint8_t* input, size_t input_size, \
+ BROTLI_BOOL is_last, int* table, uint8_t cmd_depth[128], \
+ uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code, \
+ size_t* storage_ix, uint8_t* storage) { \
+ BrotliCompressFragmentFastImpl(m, input, input_size, is_last, table, B, \
+ cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage); \
+}
+FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
+#undef BAKE_METHOD_PARAM_
+
+void BrotliCompressFragmentFast(
+ MemoryManager* m, const uint8_t* input, size_t input_size,
+ BROTLI_BOOL is_last, int* table, size_t table_size, uint8_t cmd_depth[128],
+ uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t initial_storage_ix = *storage_ix;
+ const size_t table_bits = Log2FloorNonZero(table_size);
+
+ if (input_size == 0) {
+ BROTLI_DCHECK(is_last);
+ BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
+ BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ return;
+ }
+
+ switch (table_bits) {
+#define CASE_(B) \
+ case B: \
+ BrotliCompressFragmentFastImpl ## B( \
+ m, input, input_size, is_last, table, cmd_depth, cmd_bits, \
+ cmd_code_numbits, cmd_code, storage_ix, storage); \
+ break;
+ FOR_TABLE_BITS_(CASE_)
+#undef CASE_
+ default: BROTLI_DCHECK(0); break;
+ }
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if (*storage_ix - initial_storage_ix > 31 + (input_size << 3)) {
+ EmitUncompressedMetaBlock(input, input + input_size, initial_storage_ix,
+ storage_ix, storage);
+ }
+
+ if (is_last) {
+ BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
+ BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ }
+}
+
+#undef FOR_TABLE_BITS_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.h
new file mode 100644
index 000000000..80007f5dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment.h
@@ -0,0 +1,61 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses one-pass processing: when we find a backward
+ match, we immediately emit the corresponding command and literal codes to
+ the bit stream. */
+
+#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
+#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./memory.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ "cmd_depth" and "cmd_bits" contain the command and distance prefix codes
+ (see comment in encode.h) used for the encoding of this input fragment.
+ If "is_last" is 0, they are updated to reflect the statistics
+ of this input fragment, to be used for the encoding of the next fragment.
+
+ "*cmd_code_numbits" is the number of bits of the compressed representation
+ of the command and distance prefix codes, and "cmd_code" is an array of
+ at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed
+ command and distance prefix codes. If "is_last" is 0, these are also
+ updated to represent the updated "cmd_depth" and "cmd_bits".
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+BROTLI_INTERNAL void BrotliCompressFragmentFast(MemoryManager* m,
+ const uint8_t* input,
+ size_t input_size,
+ BROTLI_BOOL is_last,
+ int* table, size_t table_size,
+ uint8_t cmd_depth[128],
+ uint16_t cmd_bits[128],
+ size_t* cmd_code_numbits,
+ uint8_t* cmd_code,
+ size_t* storage_ix,
+ uint8_t* storage);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.c
new file mode 100644
index 000000000..f8a560638
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.c
@@ -0,0 +1,645 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses two-pass processing: in the first pass we save
+ the found backward matches and literal bytes into a buffer, and in the
+ second pass we emit them into the bit stream using prefix codes built based
+ on the actual command and literal byte histograms. */
+
+#include "./compress_fragment_two_pass.h"
+
+#include <string.h> /* memcmp, memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./bit_cost.h"
+#include "./brotli_bit_stream.h"
+#include "./entropy_encode.h"
+#include "./fast_log.h"
+#include "./find_match_length.h"
+#include "./memory.h"
+#include "./write_bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
+
+/* kHashMul32 multiplier has these properties:
+ * The multiplier must be odd. Otherwise we may lose the highest bit.
+ * No long streaks of ones or zeros.
+ * There is no effort to ensure that it is a prime, the oddity is enough
+ for this use.
+ * The number has been tuned heuristically against compression benchmarks. */
+static const uint32_t kHashMul32 = 0x1E35A7BD;
+
+static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
+ size_t shift, size_t length) {
+ const uint64_t h =
+ (BROTLI_UNALIGNED_LOAD64LE(p) << ((8 - length) * 8)) * kHashMul32;
+ return (uint32_t)(h >> shift);
+}
+
+static BROTLI_INLINE uint32_t HashBytesAtOffset(uint64_t v, size_t offset,
+ size_t shift, size_t length) {
+ BROTLI_DCHECK(offset <= 8 - length);
+ {
+ const uint64_t h = ((v >> (8 * offset)) << ((8 - length) * 8)) * kHashMul32;
+ return (uint32_t)(h >> shift);
+ }
+}
+
+static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2,
+ size_t length) {
+ if (BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2)) {
+ if (length == 4) return BROTLI_TRUE;
+ return TO_BROTLI_BOOL(p1[4] == p2[4] && p1[5] == p2[5]);
+ }
+ return BROTLI_FALSE;
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+static void BuildAndStoreCommandPrefixCode(
+ const uint32_t histogram[128],
+ uint8_t depth[128], uint16_t bits[128],
+ size_t* storage_ix, uint8_t* storage) {
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+ HuffmanTree tree[129];
+ uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
+ uint16_t cmd_bits[64];
+ BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
+ BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ memcpy(cmd_depth, depth + 24, 24);
+ memcpy(cmd_depth + 24, depth, 8);
+ memcpy(cmd_depth + 32, depth + 48, 8);
+ memcpy(cmd_depth + 40, depth + 8, 8);
+ memcpy(cmd_depth + 48, depth + 56, 8);
+ memcpy(cmd_depth + 56, depth + 16, 8);
+ BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
+ memcpy(bits, cmd_bits + 24, 16);
+ memcpy(bits + 8, cmd_bits + 40, 16);
+ memcpy(bits + 16, cmd_bits + 56, 16);
+ memcpy(bits + 24, cmd_bits, 48);
+ memcpy(bits + 48, cmd_bits + 32, 16);
+ memcpy(bits + 56, cmd_bits + 48, 16);
+ BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
+ {
+ /* Create the bit length array for the full command alphabet. */
+ size_t i;
+ memset(cmd_depth, 0, 64); /* only 64 first values were used */
+ memcpy(cmd_depth, depth + 24, 8);
+ memcpy(cmd_depth + 64, depth + 32, 8);
+ memcpy(cmd_depth + 128, depth + 40, 8);
+ memcpy(cmd_depth + 192, depth + 48, 8);
+ memcpy(cmd_depth + 384, depth + 56, 8);
+ for (i = 0; i < 8; ++i) {
+ cmd_depth[128 + 8 * i] = depth[i];
+ cmd_depth[256 + 8 * i] = depth[8 + i];
+ cmd_depth[448 + 8 * i] = depth[16 + i];
+ }
+ BrotliStoreHuffmanTree(
+ cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
+ }
+ BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
+}
+
+static BROTLI_INLINE void EmitInsertLen(
+ uint32_t insertlen, uint32_t** commands) {
+ if (insertlen < 6) {
+ **commands = insertlen;
+ } else if (insertlen < 130) {
+ const uint32_t tail = insertlen - 2;
+ const uint32_t nbits = Log2FloorNonZero(tail) - 1u;
+ const uint32_t prefix = tail >> nbits;
+ const uint32_t inscode = (nbits << 1) + prefix + 2;
+ const uint32_t extra = tail - (prefix << nbits);
+ **commands = inscode | (extra << 8);
+ } else if (insertlen < 2114) {
+ const uint32_t tail = insertlen - 66;
+ const uint32_t nbits = Log2FloorNonZero(tail);
+ const uint32_t code = nbits + 10;
+ const uint32_t extra = tail - (1u << nbits);
+ **commands = code | (extra << 8);
+ } else if (insertlen < 6210) {
+ const uint32_t extra = insertlen - 2114;
+ **commands = 21 | (extra << 8);
+ } else if (insertlen < 22594) {
+ const uint32_t extra = insertlen - 6210;
+ **commands = 22 | (extra << 8);
+ } else {
+ const uint32_t extra = insertlen - 22594;
+ **commands = 23 | (extra << 8);
+ }
+ ++(*commands);
+}
+
+static BROTLI_INLINE void EmitCopyLen(size_t copylen, uint32_t** commands) {
+ if (copylen < 10) {
+ **commands = (uint32_t)(copylen + 38);
+ } else if (copylen < 134) {
+ const size_t tail = copylen - 6;
+ const size_t nbits = Log2FloorNonZero(tail) - 1;
+ const size_t prefix = tail >> nbits;
+ const size_t code = (nbits << 1) + prefix + 44;
+ const size_t extra = tail - (prefix << nbits);
+ **commands = (uint32_t)(code | (extra << 8));
+ } else if (copylen < 2118) {
+ const size_t tail = copylen - 70;
+ const size_t nbits = Log2FloorNonZero(tail);
+ const size_t code = nbits + 52;
+ const size_t extra = tail - ((size_t)1 << nbits);
+ **commands = (uint32_t)(code | (extra << 8));
+ } else {
+ const size_t extra = copylen - 2118;
+ **commands = (uint32_t)(63 | (extra << 8));
+ }
+ ++(*commands);
+}
+
+static BROTLI_INLINE void EmitCopyLenLastDistance(
+ size_t copylen, uint32_t** commands) {
+ if (copylen < 12) {
+ **commands = (uint32_t)(copylen + 20);
+ ++(*commands);
+ } else if (copylen < 72) {
+ const size_t tail = copylen - 8;
+ const size_t nbits = Log2FloorNonZero(tail) - 1;
+ const size_t prefix = tail >> nbits;
+ const size_t code = (nbits << 1) + prefix + 28;
+ const size_t extra = tail - (prefix << nbits);
+ **commands = (uint32_t)(code | (extra << 8));
+ ++(*commands);
+ } else if (copylen < 136) {
+ const size_t tail = copylen - 8;
+ const size_t code = (tail >> 5) + 54;
+ const size_t extra = tail & 31;
+ **commands = (uint32_t)(code | (extra << 8));
+ ++(*commands);
+ **commands = 64;
+ ++(*commands);
+ } else if (copylen < 2120) {
+ const size_t tail = copylen - 72;
+ const size_t nbits = Log2FloorNonZero(tail);
+ const size_t code = nbits + 52;
+ const size_t extra = tail - ((size_t)1 << nbits);
+ **commands = (uint32_t)(code | (extra << 8));
+ ++(*commands);
+ **commands = 64;
+ ++(*commands);
+ } else {
+ const size_t extra = copylen - 2120;
+ **commands = (uint32_t)(63 | (extra << 8));
+ ++(*commands);
+ **commands = 64;
+ ++(*commands);
+ }
+}
+
+static BROTLI_INLINE void EmitDistance(uint32_t distance, uint32_t** commands) {
+ uint32_t d = distance + 3;
+ uint32_t nbits = Log2FloorNonZero(d) - 1;
+ const uint32_t prefix = (d >> nbits) & 1;
+ const uint32_t offset = (2 + prefix) << nbits;
+ const uint32_t distcode = 2 * (nbits - 1) + prefix + 80;
+ uint32_t extra = d - offset;
+ **commands = distcode | (extra << 8);
+ ++(*commands);
+}
+
+/* REQUIRES: len <= 1 << 24. */
+static void BrotliStoreMetaBlockHeader(
+ size_t len, BROTLI_BOOL is_uncompressed, size_t* storage_ix,
+ uint8_t* storage) {
+ size_t nibbles = 6;
+ /* ISLAST */
+ BrotliWriteBits(1, 0, storage_ix, storage);
+ if (len <= (1U << 16)) {
+ nibbles = 4;
+ } else if (len <= (1U << 20)) {
+ nibbles = 5;
+ }
+ BrotliWriteBits(2, nibbles - 4, storage_ix, storage);
+ BrotliWriteBits(nibbles * 4, len - 1, storage_ix, storage);
+ /* ISUNCOMPRESSED */
+ BrotliWriteBits(1, (uint64_t)is_uncompressed, storage_ix, storage);
+}
+
+static BROTLI_INLINE void CreateCommands(const uint8_t* input,
+ size_t block_size, size_t input_size, const uint8_t* base_ip, int* table,
+ size_t table_bits, size_t min_match,
+ uint8_t** literals, uint32_t** commands) {
+ /* "ip" is the input pointer. */
+ const uint8_t* ip = input;
+ const size_t shift = 64u - table_bits;
+ const uint8_t* ip_end = input + block_size;
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+ const uint8_t* next_emit = input;
+
+ int last_distance = -1;
+ const size_t kInputMarginBytes = BROTLI_WINDOW_GAP;
+
+ if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) {
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+ const size_t len_limit = BROTLI_MIN(size_t, block_size - min_match,
+ input_size - kInputMarginBytes);
+ const uint8_t* ip_limit = input + len_limit;
+
+ uint32_t next_hash;
+ for (next_hash = Hash(++ip, shift, min_match); ; ) {
+ /* Step 1: Scan forward in the input looking for a 6-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (ie. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+ uint32_t skip = 32;
+
+ const uint8_t* next_ip = ip;
+ const uint8_t* candidate;
+
+ BROTLI_DCHECK(next_emit < ip);
+trawl:
+ do {
+ uint32_t hash = next_hash;
+ uint32_t bytes_between_hash_lookups = skip++ >> 5;
+ ip = next_ip;
+ BROTLI_DCHECK(hash == Hash(ip, shift, min_match));
+ next_ip = ip + bytes_between_hash_lookups;
+ if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
+ goto emit_remainder;
+ }
+ next_hash = Hash(next_ip, shift, min_match);
+ candidate = ip - last_distance;
+ if (IsMatch(ip, candidate, min_match)) {
+ if (BROTLI_PREDICT_TRUE(candidate < ip)) {
+ table[hash] = (int)(ip - base_ip);
+ break;
+ }
+ }
+ candidate = base_ip + table[hash];
+ BROTLI_DCHECK(candidate >= base_ip);
+ BROTLI_DCHECK(candidate < ip);
+
+ table[hash] = (int)(ip - base_ip);
+ } while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate, min_match)));
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if (ip - candidate > MAX_DISTANCE) goto trawl;
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit", and then see if we can find a next match immediately
+ afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+
+ {
+ /* We have a 6-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+ const uint8_t* base = ip;
+ size_t matched = min_match + FindMatchLengthWithLimit(
+ candidate + min_match, ip + min_match,
+ (size_t)(ip_end - ip) - min_match);
+ int distance = (int)(base - candidate); /* > 0 */
+ int insert = (int)(base - next_emit);
+ ip += matched;
+ BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
+ EmitInsertLen((uint32_t)insert, commands);
+ memcpy(*literals, next_emit, (size_t)insert);
+ *literals += insert;
+ if (distance == last_distance) {
+ **commands = 64;
+ ++(*commands);
+ } else {
+ EmitDistance((uint32_t)distance, commands);
+ last_distance = distance;
+ }
+ EmitCopyLenLastDistance(matched, commands);
+
+ next_emit = ip;
+ if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
+ goto emit_remainder;
+ }
+ {
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+ uint64_t input_bytes;
+ uint32_t cur_hash;
+ uint32_t prev_hash;
+ if (min_match == 4) {
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
+ cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+ } else {
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 5);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 4);
+ prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
+ cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+ }
+
+ candidate = base_ip + table[cur_hash];
+ table[cur_hash] = (int)(ip - base_ip);
+ }
+ }
+
+ while (ip - candidate <= MAX_DISTANCE &&
+ IsMatch(ip, candidate, min_match)) {
+ /* We have a 6-byte match at ip, and no need to emit any
+ literal bytes prior to ip. */
+ const uint8_t* base = ip;
+ size_t matched = min_match + FindMatchLengthWithLimit(
+ candidate + min_match, ip + min_match,
+ (size_t)(ip_end - ip) - min_match);
+ ip += matched;
+ last_distance = (int)(base - candidate); /* > 0 */
+ BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
+ EmitCopyLen(matched, commands);
+ EmitDistance((uint32_t)last_distance, commands);
+
+ next_emit = ip;
+ if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
+ goto emit_remainder;
+ }
+ {
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+ uint64_t input_bytes;
+ uint32_t cur_hash;
+ uint32_t prev_hash;
+ if (min_match == 4) {
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
+ cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+ } else {
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 5);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 4);
+ prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 3);
+ input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
+ cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
+ prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 2);
+ prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
+ table[prev_hash] = (int)(ip - base_ip - 1);
+ }
+
+ candidate = base_ip + table[cur_hash];
+ table[cur_hash] = (int)(ip - base_ip);
+ }
+ }
+
+ next_hash = Hash(++ip, shift, min_match);
+ }
+ }
+
+emit_remainder:
+ BROTLI_DCHECK(next_emit <= ip_end);
+ /* Emit the remaining bytes as literals. */
+ if (next_emit < ip_end) {
+ const uint32_t insert = (uint32_t)(ip_end - next_emit);
+ EmitInsertLen(insert, commands);
+ memcpy(*literals, next_emit, insert);
+ *literals += insert;
+ }
+}
+
+static void StoreCommands(MemoryManager* m,
+ const uint8_t* literals, const size_t num_literals,
+ const uint32_t* commands, const size_t num_commands,
+ size_t* storage_ix, uint8_t* storage) {
+ static const uint32_t kNumExtraBits[128] = {
+ 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
+ 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
+ };
+ static const uint32_t kInsertOffset[24] = {
+ 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578,
+ 1090, 2114, 6210, 22594,
+ };
+
+ uint8_t lit_depths[256];
+ uint16_t lit_bits[256];
+ uint32_t lit_histo[256] = { 0 };
+ uint8_t cmd_depths[128] = { 0 };
+ uint16_t cmd_bits[128] = { 0 };
+ uint32_t cmd_histo[128] = { 0 };
+ size_t i;
+ for (i = 0; i < num_literals; ++i) {
+ ++lit_histo[literals[i]];
+ }
+ BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo, num_literals,
+ /* max_bits = */ 8,
+ lit_depths, lit_bits,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+
+ for (i = 0; i < num_commands; ++i) {
+ const uint32_t code = commands[i] & 0xFF;
+ BROTLI_DCHECK(code < 128);
+ ++cmd_histo[code];
+ }
+ cmd_histo[1] += 1;
+ cmd_histo[2] += 1;
+ cmd_histo[64] += 1;
+ cmd_histo[84] += 1;
+ BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depths, cmd_bits,
+ storage_ix, storage);
+
+ for (i = 0; i < num_commands; ++i) {
+ const uint32_t cmd = commands[i];
+ const uint32_t code = cmd & 0xFF;
+ const uint32_t extra = cmd >> 8;
+ BROTLI_DCHECK(code < 128);
+ BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
+ BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage);
+ if (code < 24) {
+ const uint32_t insert = kInsertOffset[code] + extra;
+ uint32_t j;
+ for (j = 0; j < insert; ++j) {
+ const uint8_t lit = *literals;
+ BrotliWriteBits(lit_depths[lit], lit_bits[lit], storage_ix, storage);
+ ++literals;
+ }
+ }
+ }
+}
+
+/* Acceptable loss for uncompressible speedup is 2% */
+#define MIN_RATIO 0.98
+#define SAMPLE_RATE 43
+
+static BROTLI_BOOL ShouldCompress(
+ const uint8_t* input, size_t input_size, size_t num_literals) {
+ double corpus_size = (double)input_size;
+ if (num_literals < MIN_RATIO * corpus_size) {
+ return BROTLI_TRUE;
+ } else {
+ uint32_t literal_histo[256] = { 0 };
+ const double max_total_bit_cost = corpus_size * 8 * MIN_RATIO / SAMPLE_RATE;
+ size_t i;
+ for (i = 0; i < input_size; i += SAMPLE_RATE) {
+ ++literal_histo[input[i]];
+ }
+ return TO_BROTLI_BOOL(BitsEntropy(literal_histo, 256) < max_total_bit_cost);
+ }
+}
+
+static void RewindBitPosition(const size_t new_storage_ix,
+ size_t* storage_ix, uint8_t* storage) {
+ const size_t bitpos = new_storage_ix & 7;
+ const size_t mask = (1u << bitpos) - 1;
+ storage[new_storage_ix >> 3] &= (uint8_t)mask;
+ *storage_ix = new_storage_ix;
+}
+
+static void EmitUncompressedMetaBlock(const uint8_t* input, size_t input_size,
+ size_t* storage_ix, uint8_t* storage) {
+ BrotliStoreMetaBlockHeader(input_size, 1, storage_ix, storage);
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ memcpy(&storage[*storage_ix >> 3], input, input_size);
+ *storage_ix += input_size << 3;
+ storage[*storage_ix >> 3] = 0;
+}
+
+static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
+ MemoryManager* m, const uint8_t* input, size_t input_size,
+ BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
+ int* table, size_t table_bits, size_t min_match,
+ size_t* storage_ix, uint8_t* storage) {
+ /* Save the start of the first block for position and distance computations.
+ */
+ const uint8_t* base_ip = input;
+ BROTLI_UNUSED(is_last);
+
+ while (input_size > 0) {
+ size_t block_size =
+ BROTLI_MIN(size_t, input_size, kCompressFragmentTwoPassBlockSize);
+ uint32_t* commands = command_buf;
+ uint8_t* literals = literal_buf;
+ size_t num_literals;
+ CreateCommands(input, block_size, input_size, base_ip, table,
+ table_bits, min_match, &literals, &commands);
+ num_literals = (size_t)(literals - literal_buf);
+ if (ShouldCompress(input, block_size, num_literals)) {
+ const size_t num_commands = (size_t)(commands - command_buf);
+ BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage);
+ /* No block splits, no contexts. */
+ BrotliWriteBits(13, 0, storage_ix, storage);
+ StoreCommands(m, literal_buf, num_literals, command_buf, num_commands,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ } else {
+ /* Since we did not find many backward references and the entropy of
+ the data is close to 8 bits, we can simply emit an uncompressed block.
+ This makes compression speed of uncompressible data about 3x faster. */
+ EmitUncompressedMetaBlock(input, block_size, storage_ix, storage);
+ }
+ input += block_size;
+ input_size -= block_size;
+ }
+}
+
+#define FOR_TABLE_BITS_(X) \
+ X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17)
+
+#define BAKE_METHOD_PARAM_(B) \
+static BROTLI_NOINLINE void BrotliCompressFragmentTwoPassImpl ## B( \
+ MemoryManager* m, const uint8_t* input, size_t input_size, \
+ BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \
+ int* table, size_t* storage_ix, uint8_t* storage) { \
+ size_t min_match = (B <= 15) ? 4 : 6; \
+ BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
+ literal_buf, table, B, min_match, storage_ix, storage); \
+}
+FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
+#undef BAKE_METHOD_PARAM_
+
+void BrotliCompressFragmentTwoPass(
+ MemoryManager* m, const uint8_t* input, size_t input_size,
+ BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
+ int* table, size_t table_size, size_t* storage_ix, uint8_t* storage) {
+ const size_t initial_storage_ix = *storage_ix;
+ const size_t table_bits = Log2FloorNonZero(table_size);
+ switch (table_bits) {
+#define CASE_(B) \
+ case B: \
+ BrotliCompressFragmentTwoPassImpl ## B( \
+ m, input, input_size, is_last, command_buf, \
+ literal_buf, table, storage_ix, storage); \
+ break;
+ FOR_TABLE_BITS_(CASE_)
+#undef CASE_
+ default: BROTLI_DCHECK(0); break;
+ }
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if (*storage_ix - initial_storage_ix > 31 + (input_size << 3)) {
+ RewindBitPosition(initial_storage_ix, storage_ix, storage);
+ EmitUncompressedMetaBlock(input, input_size, storage_ix, storage);
+ }
+
+ if (is_last) {
+ BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
+ BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ }
+}
+
+#undef FOR_TABLE_BITS_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.h
new file mode 100644
index 000000000..928677df4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/compress_fragment_two_pass.h
@@ -0,0 +1,54 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses two-pass processing: in the first pass we save
+ the found backward matches and literal bytes into a buffer, and in the
+ second pass we emit them into the bit stream using prefix codes built based
+ on the actual command and literal byte histograms. */
+
+#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
+#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./memory.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: "command_buf" and "literal_buf" point to at least
+ kCompressFragmentTwoPassBlockSize long arrays.
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is a power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(MemoryManager* m,
+ const uint8_t* input,
+ size_t input_size,
+ BROTLI_BOOL is_last,
+ uint32_t* command_buf,
+ uint8_t* literal_buf,
+ int* table,
+ size_t table_size,
+ size_t* storage_ix,
+ uint8_t* storage);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.c
new file mode 100644
index 000000000..16d853fe5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.c
@@ -0,0 +1,1846 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Hash table on the 4-byte prefixes of static dictionary words. */
+
+#include "../common/platform.h"
+#include "./dictionary_hash.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+BROTLI_INTERNAL const uint16_t kStaticDictionaryHashWords[32768] = {
+1002,0,0,0,0,0,0,0,0,683,0,0,0,0,0,0,0,1265,0,0,0,0,0,1431,0,0,0,0,0,0,40,0,0,0,
+0,155,8,741,0,624,0,0,0,0,0,0,0,0,0,0,0,0,66,503,0,0,0,451,0,0,0,0,0,0,0,835,70,
+0,0,539,0,0,0,0,0,0,0,0,0,113,0,0,0,0,718,0,0,0,0,0,0,520,0,1070,0,0,0,0,0,1515,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,610,0,0,750,0,0,0,307,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,964,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,999,0,0,0,0,0,0,0,0,
+645,75,0,649,52,282,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1621,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,211,225,0,0,687,718,0,0,110,0,58,0,0,0,0,0,0,345,0,0,301,0,0,
+0,203,0,0,1154,674,1949,0,0,0,0,0,0,0,0,0,259,0,0,0,0,0,0,0,1275,0,0,0,1231,254,
+0,0,0,0,0,0,0,277,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,0,0,800,0,0,0,29,
+116,100,490,0,0,0,0,0,1641,0,543,0,0,0,0,41,181,0,657,0,0,202,25,0,0,0,0,0,0,0,
+0,0,0,423,0,0,0,113,0,0,0,927,963,0,976,0,206,0,0,0,0,0,0,0,0,0,2002,0,0,0,0,0,
+0,0,0,0,0,0,696,0,1170,0,0,0,0,226,13,0,769,678,551,0,0,0,0,0,0,57,0,0,0,10,188,
+0,0,0,624,0,0,0,0,0,0,0,0,0,1941,130,0,0,0,0,378,269,0,0,528,0,1146,0,0,0,1105,
+0,1616,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,656,0,1940,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,
+0,0,457,342,810,0,0,0,0,620,0,0,0,0,0,0,0,967,95,447,406,0,0,0,477,0,1268,944,
+1941,0,0,0,629,0,0,0,0,0,375,0,0,0,1636,0,0,0,0,774,0,1,1034,0,0,0,0,0,824,0,0,
+0,0,0,118,0,0,560,296,0,0,0,0,0,0,0,0,1009,894,0,0,0,0,0,0,0,0,0,0,0,0,0,1474,
+366,0,0,0,0,0,0,0,0,0,79,1723,0,0,200,0,0,0,0,0,0,0,0,1759,372,0,16,0,943,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,900,1839,707,30,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2004,0,0,10,115,0,50,0,0,0,0,0,0,0,0,0,0,520,1,0,738,98,482,0,0,0,0,
+0,0,0,0,0,0,701,2,0,0,0,0,0,0,0,0,557,0,0,0,0,0,0,0,0,0,347,0,0,0,0,572,0,0,0,0,
+0,0,0,0,0,832,0,0,797,809,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,861,0,0,294,0,0,0,109,
+0,0,0,0,0,0,0,0,1187,290,266,0,0,0,0,49,50,748,0,0,466,399,0,0,0,0,0,0,0,378,0,
+519,0,0,0,0,0,0,0,0,0,0,0,0,667,351,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180,
+0,0,869,0,0,0,0,0,0,0,260,0,0,0,0,0,0,0,0,0,0,523,36,0,0,587,510,809,29,260,0,0,
+0,0,0,0,0,0,570,0,565,0,1464,0,0,0,0,0,0,10,0,0,787,399,380,200,0,0,0,0,516,0,
+844,887,0,0,0,0,0,0,0,44,0,0,0,305,1655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,786,10,0,0,
+0,0,0,0,0,0,0,2031,0,0,0,0,0,684,0,0,0,0,0,1480,0,0,0,27,0,0,0,395,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,813,511,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,206,
+496,0,0,0,0,0,909,0,891,0,0,0,0,0,0,0,0,0,687,0,0,0,1342,0,0,0,0,0,0,0,0,0,0,
+160,41,0,0,0,0,0,0,0,0,0,0,0,1718,778,0,0,0,0,0,0,0,0,0,0,1610,0,0,0,0,0,115,0,
+0,0,0,314,294,0,0,0,983,178,193,0,0,0,0,0,0,0,0,0,174,0,0,0,0,0,0,0,0,0,0,848,
+1796,0,0,0,0,0,0,221,0,687,1660,0,0,0,0,262,0,0,179,0,0,0,0,0,66,0,773,0,352,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,152,0,0,1197,0,0,0,0,0,0,0,0,0,0,0,0,560,0,0,
+564,0,0,0,797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,819,0,0,0,0,0,0,0,0,719,544,
+637,5,0,0,0,0,0,0,0,0,0,0,0,101,0,1441,0,0,0,893,0,0,0,0,0,0,0,0,0,238,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1296,0,0,969,1729,314,60,0,0,0,0,0,1144,0,1147,0,0,0,0,0,
+0,0,0,0,0,437,1853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,828,0,176,0,0,0,0,0,0,434,39,0,
+0,0,0,0,159,0,0,0,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,801,556,0,0,
+0,0,0,0,0,416,19,197,369,0,0,0,0,0,0,0,0,0,28,34,0,757,0,0,898,1553,0,721,0,0,0,
+0,1012,0,0,0,0,1102,0,898,183,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,277,0,0,0,435,0,0,0,0,0,1311,0,0,0,0,
+0,0,211,437,0,0,0,28,0,0,750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2012,0,702,
+0,808,0,0,0,0,739,166,0,0,0,0,0,0,719,170,500,0,0,0,0,0,0,0,0,1500,327,0,0,450,
+0,0,0,1318,0,0,0,1602,0,0,331,754,0,0,0,0,0,1368,0,0,557,0,0,0,799,850,0,0,0,0,
+0,0,0,0,908,0,0,0,0,0,19,62,459,0,0,0,0,0,0,0,0,0,0,0,0,1802,0,0,0,0,0,0,0,0,0,
+1397,0,0,0,0,120,238,0,0,0,0,0,0,0,0,0,0,0,1324,0,0,0,0,0,0,0,0,602,201,0,0,164,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,0,0,0,968,0,0,
+0,0,0,0,882,0,0,0,907,329,100,0,0,0,0,0,0,0,0,0,0,0,176,26,9,0,0,265,256,0,0,0,
+0,0,0,0,0,0,643,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,610,0,0,0,0,973,2001,0,
+0,0,0,0,0,522,0,0,0,0,0,0,0,0,0,0,0,553,0,0,0,0,0,0,1582,0,1578,0,0,0,0,0,0,0,0,
+0,0,0,795,0,0,0,432,0,0,0,0,0,0,84,126,0,0,0,0,790,0,377,64,0,1529,0,0,0,0,530,
+1857,539,1104,0,0,0,0,0,0,0,0,0,0,0,0,977,0,0,0,34,0,0,0,0,0,0,0,0,0,0,0,24,26,
+0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,183,379,0,0,0,0,0,0,0,792,
+0,0,0,0,0,0,0,0,0,1920,0,0,0,0,0,0,0,0,0,771,0,0,0,1979,0,901,254,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,0,0,0,0,0,440,37,0,
+508,0,0,0,513,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,533,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,752,920,0,1048,0,153,0,
+0,391,0,0,1952,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,640,0,483,69,1616,0,0,0,0,0,734,
+0,0,0,0,0,0,480,0,495,0,472,0,0,0,0,0,0,0,0,874,229,0,0,0,0,948,0,0,0,0,0,0,0,0,
+1009,748,0,555,0,0,0,0,0,0,193,0,653,0,0,0,0,0,0,0,0,0,0,984,0,0,0,172,0,0,0,0,
+0,0,0,0,83,1568,0,0,384,0,0,0,0,0,0,0,164,880,0,0,0,0,0,0,0,0,0,0,0,367,121,0,0,
+828,0,0,0,0,0,0,0,1541,0,0,0,0,0,0,0,343,0,0,0,0,0,0,0,0,561,57,0,0,0,0,0,0,0,
+926,0,0,0,0,827,0,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,
+0,0,0,896,1249,0,0,0,0,0,1614,0,0,0,860,0,0,0,0,0,0,0,0,964,102,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,569,0,0,0,0,795,2045,0,0,0,
+0,0,0,104,52,0,0,0,0,0,604,0,0,0,0,779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,
+494,0,677,0,0,0,0,0,0,0,508,0,0,0,0,0,0,0,0,0,1014,0,957,0,0,630,310,0,0,0,570,
+0,0,449,0,64,537,0,0,0,0,0,0,0,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,1650,49,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,1279,0,0,0,0,0,0,0,896,0,0,
+178,0,0,0,0,0,0,0,0,0,0,0,0,0,808,695,0,0,0,0,539,1117,0,0,0,0,0,0,0,0,257,0,
+1003,0,0,0,1,448,0,516,0,0,960,0,125,4,0,1268,30,748,0,0,852,0,0,0,6,0,0,848,
+236,1385,862,1811,0,0,0,0,698,803,0,0,0,0,0,0,0,610,992,0,0,878,0,1847,0,0,0,0,
+0,0,0,383,0,1404,0,0,0,0,986,0,347,0,0,0,0,0,0,0,0,0,0,0,592,572,0,1411,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,606,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1829,0,0,0,0,0,0,0,0,0,0,0,0,700,748,0,0,0,0,0,0,365,0,0,127,0,0,
+83,198,0,0,0,0,0,0,864,55,0,0,0,0,726,1752,0,0,0,0,0,0,0,0,0,0,0,0,0,1066,0,764,
+0,0,0,0,683,0,550,309,0,0,874,1212,0,0,0,1364,0,986,381,723,0,0,0,1573,0,0,0,0,
+0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1559,0,0,0,0,493,133,0,0,0,0,148,
+119,0,0,0,0,0,0,537,14,541,0,635,126,0,0,0,495,0,0,0,0,861,998,1009,0,0,0,0,0,0,
+0,359,368,0,0,0,0,304,1577,0,0,0,0,0,1107,0,0,0,0,0,929,0,0,0,1142,0,0,0,0,289,
+175,0,432,0,219,0,0,0,0,0,785,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,
+931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1323,0,0,0,0,290,0,559,1751,127,0,0,0,
+934,1167,0,963,0,260,0,0,0,573,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+580,1689,0,0,0,0,0,0,0,0,0,1164,0,0,982,1922,0,63,0,0,0,0,0,793,0,0,0,0,0,0,0,0,
+0,0,0,0,0,67,790,0,0,0,0,0,0,0,0,0,0,391,443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,1140,0,0,0,0,340,300,0,897,0,0,0,0,0,0,
+0,0,0,0,890,0,0,0,0,818,321,53,0,0,0,0,0,0,0,0,0,468,0,243,0,870,0,0,0,1765,121,
+0,0,0,180,518,0,822,419,634,0,0,0,0,0,0,0,0,0,898,0,0,0,0,454,36,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,0,0,0,0,0,0,1326,0,104,0,0,0,0,0,0,0,
+0,0,260,0,0,0,0,0,0,0,0,0,0,0,0,542,45,0,0,263,1516,42,0,0,0,0,0,468,0,1005,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,288,87,0,0,0,0,0,0,0,0,502,988,133,0,0,0,0,0,0,
+141,0,0,872,1842,0,0,0,0,0,0,0,0,261,619,0,0,0,0,189,246,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,678,0,0,0,0,0,0,0,0,0,0,0,0,285,35,0,517,0,0,0,0,0,0,0,0,0,0,
+540,214,667,0,74,0,0,125,0,0,0,0,0,761,131,0,0,0,0,0,0,0,0,0,0,0,0,0,333,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1338,94,0,0,0,0,0,0,0,0,0,0,0,0,449,0,646,103,
+86,641,2028,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,869,87,277,117,39,0,0,0,0,0,0,0,0,938,
+297,0,0,0,0,558,464,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1608,0,
+0,0,0,0,0,0,1429,0,0,733,1010,0,0,338,1656,0,0,0,1038,979,2010,0,0,0,0,0,0,0,
+1005,0,0,121,0,0,0,219,20,0,0,0,0,0,0,872,1440,0,0,0,683,0,1070,0,0,522,0,0,0,0,
+439,669,0,0,0,0,0,0,0,0,1245,0,0,0,0,0,1218,0,0,547,233,0,0,0,0,0,0,0,0,0,482,0,
+0,0,0,0,0,0,886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,795,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,371,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,625,0,0,0,339,29,0,0,338,0,0,0,
+0,130,0,0,0,0,0,0,0,0,0,307,0,0,0,0,0,0,0,0,0,0,2044,0,0,0,0,0,0,0,0,308,770,0,
+0,0,0,0,1266,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,690,739,0,0,
+0,0,0,0,0,990,0,0,0,1831,0,0,0,0,0,0,0,0,0,0,0,0,0,613,0,0,0,0,0,0,0,0,0,0,0,0,
+0,763,0,878,0,0,0,977,0,100,0,0,0,0,0,0,0,0,0,463,0,0,0,0,623,318,0,0,296,463,
+137,0,0,454,0,0,0,1527,58,0,0,0,0,0,0,0,18,48,0,0,0,0,0,729,0,0,0,442,0,0,0,0,
+40,449,0,853,0,0,0,0,0,0,227,0,0,0,0,0,0,1491,0,0,0,0,0,0,0,0,0,0,161,55,0,450,
+0,1174,62,0,207,0,0,0,0,0,0,0,0,869,0,0,0,0,80,213,0,0,0,0,0,0,0,0,0,0,354,820,
+0,0,747,0,0,0,954,0,0,1073,0,556,0,0,0,692,0,191,0,804,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,831,162,0,0,35,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,1234,0,0,
+0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,149,0,0,0,902,204,0,0,833,0,287,366,0,0,0,0,0,
+0,992,2020,0,0,0,0,0,0,0,0,0,0,0,356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,784,0,0,567,
+630,0,0,0,539,0,0,27,0,0,0,0,0,0,0,0,0,0,755,0,0,0,0,0,0,0,0,0,0,0,0,814,0,0,0,
+0,0,0,0,0,0,0,0,0,0,987,0,0,255,761,194,0,1086,0,0,0,0,0,0,1016,0,0,1396,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,562,271,913,0,0,0,0,0,0,0,0,320,153,45,475,0,0,
+0,0,0,0,0,713,0,327,0,0,0,0,0,0,604,552,3,359,0,0,0,0,853,80,0,0,0,0,0,0,0,2016,
+6,887,0,0,0,0,975,0,961,0,0,0,0,0,916,1891,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,100,101,390,708,0,0,0,587,983,512,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,851,0,0,0,
+0,0,498,140,217,0,0,0,1448,0,0,0,0,0,0,0,0,0,905,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+643,105,0,792,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,535,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1748,0,0,0,0,0,754,0,0,0,0,0,0,0,0,0,0,0,0,91,0,0,1565,0,91,792,
+939,3,370,0,0,0,0,95,0,0,0,0,551,7,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1150,0,
+0,0,0,0,0,0,0,0,0,0,0,0,671,0,0,0,0,0,888,368,149,0,0,105,1134,0,983,0,0,458,31,
+0,643,0,0,0,312,0,740,0,0,0,1642,0,0,0,0,0,0,0,236,0,0,0,0,0,0,0,59,68,0,0,0,0,
+0,867,795,0,0,0,0,970,1977,0,0,0,0,0,0,0,1148,0,775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,970,0,0,0,0,0,0,0,0,0,665,71,0,0,0,0,827,0,0,0,0,0,0,0,0,0,
+0,479,0,0,0,0,0,0,0,0,99,607,0,0,0,0,0,0,0,1960,0,0,0,793,0,0,871,41,0,0,241,94,
+0,0,0,0,209,0,0,1497,0,0,0,0,0,0,0,0,0,98,0,0,0,463,0,0,0,0,291,0,0,0,0,0,0,0,0,
+0,0,984,0,0,0,0,0,205,0,0,0,0,0,0,205,42,0,801,0,0,0,0,0,635,0,0,533,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,371,0,1282,0,0,0,825,0,0,0,0,0,0,0,0,0,357,879,467,0,317,0,0,
+0,0,0,0,0,924,0,0,0,0,849,1795,0,0,0,0,895,1799,43,0,0,0,0,0,0,0,0,0,0,1820,0,0,
+0,0,0,0,0,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,0,493,0,174,417,0,0,
+0,0,0,583,733,0,0,0,0,0,0,481,215,0,0,0,0,477,0,0,0,0,0,0,0,0,308,0,0,0,0,0,0,0,
+0,297,126,0,0,361,1551,0,0,0,0,0,0,871,1807,0,0,0,0,0,1307,0,685,0,0,0,0,0,0,0,
+797,0,858,0,565,0,0,0,0,0,0,0,0,0,0,0,0,434,252,826,0,0,0,0,0,0,791,0,0,0,0,509,
+231,178,601,0,0,0,0,0,0,0,0,43,1591,0,0,0,0,0,1683,0,0,0,0,45,0,0,0,0,0,0,0,0,0,
+0,1120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,494,0,398,0,0,0,1030,0,0,0,0,0,0,
+168,0,0,0,0,0,0,0,0,0,0,973,0,642,0,0,0,0,0,0,0,0,0,1615,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,378,594,0,1093,0,679,112,0,0,0,0,1492,540,1374,714,
+1486,0,0,0,0,825,1511,0,0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,736,143,0,700,0,1540,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1557,0,0,0,860,990,0,0,0,807,0,0,0,0,0,131,
+515,0,646,0,0,0,0,117,728,508,121,0,0,0,0,0,0,357,0,0,0,0,0,0,237,0,0,0,0,0,0,0,
+0,0,1784,0,0,0,0,0,0,0,0,0,0,0,713,348,1536,0,738,0,0,0,0,0,0,0,434,0,0,0,0,0,0,
+366,1877,39,0,0,0,0,0,0,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,0,0,0,0,171,0,625,
+550,107,343,943,0,0,0,0,0,0,0,768,0,0,0,0,0,0,0,799,0,0,0,894,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1673,0,0,0,0,0,0,0,0,0,0,0,1052,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+272,0,441,0,0,3,9,0,0,0,1182,0,1346,0,0,0,0,0,0,0,0,682,0,0,1004,24,0,0,968,0,0,
+0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,0,0,0,578,
+474,0,0,0,0,0,0,0,0,0,0,0,0,0,0,113,530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,556,0,0,0,0,0,0,16,1317,0,0,97,0,0,0,703,0,0,0,0,0,0,0,0,892,0,0,0,1571,0,0,
+426,186,0,1101,0,0,0,0,0,0,0,0,937,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,644,291,
+0,0,0,0,749,0,162,0,0,381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,762,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,628,21,0,0,0,0,0,0,0,0,919,0,0,0,0,0,0,0,0,0,
+633,0,0,0,0,332,0,0,0,0,0,0,0,0,0,1489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,832,398,0,645,0,0,0,13,0,0,0,0,0,0,0,0,0,0,20,0,800,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1993,0,0,0,0,769,0,0,0,665,0,0,0,0,0,0,0,0,0,0,1426,0,0,0,0,60,0,0,0,
+641,1874,0,644,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1757,0,0,0,0,0,937,0,1652,0,654,0,
+0,0,0,0,0,0,527,0,0,0,0,0,0,0,0,0,0,0,0,0,226,0,0,0,0,0,1486,0,0,0,0,0,0,0,0,0,
+0,0,325,0,0,0,0,0,0,0,1345,0,0,91,0,404,0,0,0,0,0,0,0,0,0,0,0,0,973,0,0,0,0,0,0,
+0,1176,0,549,0,0,0,0,0,0,0,0,0,0,976,0,0,0,0,0,21,0,0,0,0,0,51,0,0,0,0,314,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,198,6,0,1093,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1776,0,0,0,0,0,1528,0,419,0,0,0,0,0,0,0,0,76,138,0,0,0,0,638,29,0,0,0,0,
+0,0,0,1418,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1710,0,0,0,0,0,
+0,0,0,0,0,0,0,532,23,0,0,0,0,0,0,0,862,0,0,946,592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,70,0,0,0,0,0,0,0,0,0,812,0,0,0,76,0,0,988,0,442,0,0,0,896,0,0,0,0,0,0,
+483,0,0,0,0,1709,0,0,0,0,0,0,119,0,0,0,117,0,309,0,0,0,0,0,596,976,0,0,0,0,0,0,
+0,0,0,0,0,768,0,0,0,0,0,0,0,0,0,518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,0,0,0,24,
+145,1020,0,0,1984,0,0,0,0,0,0,0,658,0,0,0,0,0,0,0,0,0,0,106,1827,0,1010,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,582,87,0,0,0,0,0,0,0,267,0,0,0,703,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,496,0,0,0,0,1121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,561,0,0,0,0,0,
+0,0,760,0,0,154,0,0,0,255,0,419,323,0,0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,522,0,0,0,
+0,0,0,0,551,562,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,0,0,0,0,
+0,0,0,284,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,958,0,0,594,0,0,0,0,0,0,6,479,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,820,1641,0,1556,0,0,0,0,0,0,0,302,0,0,
+0,0,0,148,0,0,676,0,0,0,0,0,0,1674,0,0,0,0,0,0,178,0,0,0,0,0,0,0,94,389,0,0,0,0,
+91,8,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,747,0,0,0,0,0,0,0,1746,0,0,0,0,
+0,24,0,1352,158,1530,0,0,718,130,280,1401,0,0,0,0,0,1946,8,0,0,0,0,1607,0,0,0,0,
+0,0,882,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,1597,633,433,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,234,0,0,0,0,0,0,0,0,680,1950,0,0,0,0,249,5,0,0,0,
+0,0,0,0,0,0,1216,0,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,180,0,0,0,0,0,0,0,1002,
+0,0,0,0,0,0,0,0,0,0,0,0,0,931,0,0,0,0,0,0,0,0,747,943,0,1837,0,0,0,0,0,0,0,641,
+0,0,0,0,280,0,0,0,5,0,0,0,0,0,72,545,0,0,0,0,0,0,0,0,0,742,0,0,254,151,872,0,0,
+0,0,0,0,0,0,0,0,0,0,921,0,0,517,833,0,1680,0,0,436,251,584,0,0,0,0,0,0,0,0,0,0,
+0,24,500,0,0,0,0,0,0,0,0,195,1775,514,389,0,0,0,0,0,0,0,743,0,0,0,0,0,0,292,0,0,
+0,227,1283,774,1805,0,0,0,0,0,0,0,0,0,0,119,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,
+1910,0,0,0,1826,490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1162,700,30,
+0,0,0,721,839,0,0,0,617,0,0,0,0,0,0,0,0,0,169,428,0,0,0,0,0,1648,637,1205,0,0,0,
+1596,0,0,4,266,0,0,0,0,0,0,0,0,0,0,0,862,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,
+0,279,157,391,604,0,0,713,945,877,973,0,0,0,0,0,0,0,0,0,0,0,0,0,0,859,567,628,
+1846,0,0,0,0,0,0,0,0,0,762,0,0,191,0,0,0,0,298,0,0,767,909,0,0,0,0,0,0,0,795,0,
+0,301,0,0,1970,0,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,644,369,15,0,160,71,0,0,0,0,0,
+1447,0,0,0,0,0,0,0,0,735,1255,76,0,0,0,0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,0,
+841,0,0,0,0,0,0,0,0,0,0,836,0,0,0,0,0,1622,0,0,735,0,0,0,0,1601,804,1390,394,0,
+0,0,0,0,0,96,0,289,0,0,35,688,0,0,0,667,0,513,0,0,0,0,0,0,0,2034,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,704,0,1524,0,1078,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,306,
+0,0,0,0,0,0,0,431,0,1196,0,0,54,0,15,1448,0,1418,0,0,0,0,0,0,0,0,0,907,0,0,0,0,
+0,0,194,1767,0,0,0,0,0,840,0,900,0,0,0,0,0,0,0,0,0,0,0,1436,0,0,0,0,642,1560,0,
+0,0,0,0,0,94,386,0,0,0,0,0,0,0,0,0,0,830,416,0,0,20,731,0,0,0,0,0,0,0,0,697,0,0,
+662,0,0,0,0,0,0,0,0,0,861,0,0,0,0,0,0,0,871,671,864,0,928,7,0,332,0,0,0,0,1055,
+0,0,0,0,0,0,986,0,0,0,0,0,44,76,0,0,0,0,0,0,0,0,0,0,300,0,0,0,0,0,0,0,175,518,
+831,1108,0,0,0,836,0,1852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,843,1804,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,246,0,0,0,610,202,0,0,36,0,0,0,240,654,13,0,0,0,0,0,0,0,
+0,391,0,403,0,0,0,0,0,0,0,0,0,0,75,0,366,815,0,0,631,0,0,0,0,0,0,0,0,345,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,0,0,0,0,0,0,0,0,0,673,35,662,0,287,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,34,0,0,0,0,0,0,0,0,151,0,427,0,0,382,0,0,0,329,0,0,279,0,0,0,
+0,0,0,0,0,0,0,906,0,0,366,843,0,1443,0,1372,992,0,36,123,0,649,0,0,0,0,0,767,0,
+1018,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,995,0,0,0,0,0,0,0,72,368,0,0,1345,0,0,0,
+589,0,0,0,0,0,0,0,0,0,1988,0,0,220,541,0,0,0,686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,32,196,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,0,0,1452,0,
+0,0,616,0,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,667,120,0,0,0,0,0,0,0,1146,0,
+0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,935,0,1050,0,
+147,88,0,0,923,0,0,0,0,0,934,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,341,222,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,
+637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1159,0,0,0,847,0,0,0,0,0,0,683,0,867,944,0,0,
+0,0,0,1809,0,0,0,0,0,0,0,0,0,0,395,170,0,0,0,0,0,0,0,0,0,0,618,535,0,1625,0,0,0,
+0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,778,0,0,0,0,0,46,0,2032,0,0,37,
+1458,0,938,363,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,889,0,0,0,0,0,0,0,
+0,0,0,0,462,0,0,0,0,525,0,0,23,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,
+0,498,725,0,0,0,0,7,0,0,0,0,773,0,0,0,164,0,0,0,0,0,0,0,0,936,583,659,1462,0,
+220,0,0,0,0,803,0,0,544,119,0,0,0,0,0,0,0,0,0,0,0,181,176,0,1192,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1878,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,0,0,0,0,0,
+944,0,0,0,0,0,0,0,273,0,0,0,0,0,855,0,0,0,0,5,127,0,0,0,0,0,0,0,0,752,230,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,162,0,654,48,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,
+0,0,0,0,0,0,0,963,0,0,0,0,0,0,0,0,0,0,858,0,0,0,0,0,0,0,0,0,0,676,1978,0,0,102,
+972,0,0,0,0,0,0,0,361,0,461,0,0,0,472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,747,905,0,0,0,
+155,0,0,0,0,0,0,0,0,0,0,319,163,0,0,0,0,0,0,0,0,0,848,0,0,36,631,0,0,0,0,0,1769,
+0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,555,247,0,0,
+996,0,0,189,0,0,0,0,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,526,746,0,0,345,0,0,0,
+1017,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,651,428,0,0,0,1162,230,327,546,792,0,0,0,
+1203,0,0,0,0,0,0,0,0,0,672,189,0,0,0,0,0,0,99,0,0,0,298,0,0,0,0,0,0,555,397,0,0,
+0,0,0,1157,0,0,0,0,0,0,0,0,0,0,398,1523,0,366,0,0,787,0,0,0,282,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,157,0,941,0,0,0,0,0,1336,0,0,116,0,0,0,0,0,0,787,0,0,0,0,0,0,0,0,0,
+0,170,160,0,1815,0,0,0,0,0,866,0,0,0,0,0,0,0,0,0,689,0,0,0,0,820,0,498,108,0,0,
+0,1119,0,0,0,244,609,1005,0,581,0,0,0,0,0,895,0,0,0,1898,0,0,0,0,0,926,0,0,0,0,
+0,0,0,0,0,0,0,0,0,538,496,294,301,0,0,0,18,0,0,757,0,0,0,0,0,1263,0,820,0,722,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2028,0,0,0,0,124,1875,0,0,0,881,0,0,0,1348,
+0,0,0,0,0,0,0,911,0,954,0,0,0,0,414,0,0,0,0,517,0,0,0,0,0,816,0,0,0,0,0,0,0,0,
+713,0,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,593,150,0,0,0,0,
+0,553,0,0,0,0,0,0,0,0,0,0,108,0,0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,1777,0,0,55,493,
+0,0,81,0,321,980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,112,0,74,0,0,0,0,0,0,0,625,0,0,
+0,0,0,0,377,16,0,0,61,281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,1031,0,0,0,0,0,0,51,0,
+0,0,0,0,0,0,211,309,15,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,789,173,0,439,9,648,
+0,0,294,0,0,0,0,0,0,0,374,8,0,1099,0,0,0,0,0,0,0,575,0,0,0,518,0,0,0,702,0,0,0,
+0,0,0,87,0,0,0,438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,464,122,0,0,0,1802,0,0,0,0,
+0,0,499,0,0,0,87,476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,840,283,0,0,0,0,1620,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,609,1160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,
+323,372,0,0,0,0,471,722,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,
+477,1304,0,1774,0,0,88,0,438,12,0,0,0,0,0,0,0,0,671,997,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,639,22,0,0,782,681,0,0,0,0,0,0,0,0,0,0,1013,664,0,942,0,1349,0,0,0,0,0,0,0,
+0,0,0,0,0,356,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,215,289,0,1975,
+109,450,0,0,0,0,0,0,0,0,0,0,705,0,0,664,0,0,0,0,0,0,0,1238,0,0,318,0,0,0,0,0,0,
+0,0,0,0,0,0,0,960,1872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,0,0,0,0,0,0,0,0,0,239,
+777,0,26,0,0,0,0,0,0,0,0,0,0,0,0,375,414,0,17,0,0,0,1350,0,955,0,0,0,0,0,0,0,0,
+887,960,0,0,0,0,0,0,0,0,0,0,708,710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,919,0,0,0,
+0,502,280,7,45,0,0,0,0,777,0,0,0,0,410,0,1110,0,0,0,0,0,0,414,341,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,787,0,0,0,436,0,0,0,0,0,0,0,1707,613,377,96,0,0,0,0,451,
+0,0,0,0,0,0,0,0,0,0,0,0,0,680,0,483,916,0,0,0,0,0,0,937,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,739,0,0,0,0,0,0,0,0,82,0,0,663,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,128,0,0,0,0,0,0,0,0,1087,0,0,0,0,0,0,0,503,0,0,0,0,0,0,9,113,104,324,0,460,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,935,702,434,485,1014,949,423,0,900,
+0,0,0,0,0,0,0,2018,574,0,0,0,0,0,0,0,0,0,0,0,0,1206,0,0,0,0,0,0,0,0,38,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1022,0,0,0,0,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2029,0,0,0,0,0,0,0,0,0,0,0,0,523,0,0,0,0,0,0,625,0,0,425,37,0,0,0,1943,0,0,0,
+0,0,765,0,0,0,0,0,0,0,0,0,0,551,0,0,0,0,0,0,0,0,0,0,0,0,168,0,0,1010,0,0,1994,0,
+0,0,91,0,0,0,0,532,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1884,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,240,15,0,0,0,1227,0,1534,0,0,0,0,0,0,0,0,0,0,0,0,0,0,392,0,
+0,0,0,0,0,0,0,0,0,0,0,655,562,395,0,0,0,501,1019,0,0,0,0,509,267,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,0,0,0,0,0,0,948,0,0,0,0,0,0,0,
+462,114,0,0,258,404,0,1717,0,0,0,0,82,1061,0,724,0,0,0,0,0,1133,0,0,0,0,0,0,
+1021,841,0,1021,0,0,0,0,0,0,0,0,0,0,488,373,37,0,0,0,0,564,0,0,0,0,0,513,0,0,0,
+825,0,0,899,0,0,778,0,0,12,1417,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,545,0,5,
+0,0,0,0,0,0,0,192,0,0,763,0,0,0,0,0,0,0,755,759,0,0,0,0,0,0,0,0,0,370,0,1237,0,
+0,0,0,0,0,298,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,
+0,0,0,0,814,991,0,757,57,0,0,0,0,0,0,0,0,0,540,0,0,0,0,608,0,0,0,0,0,0,0,0,1014,
+0,0,0,902,0,0,0,0,553,1668,0,0,0,0,0,0,0,0,0,559,60,0,0,0,0,0,511,0,0,675,0,0,
+156,0,0,0,0,0,0,709,0,698,0,0,0,1745,0,0,0,0,0,0,0,0,0,714,0,0,0,0,0,0,0,0,206,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,776,0,0,0,0,0,0,0,0,0,1272,0,0,
+0,0,0,1059,0,0,0,0,0,0,406,0,0,0,0,0,0,0,0,0,0,947,0,0,0,0,0,0,168,0,0,0,0,0,0,
+870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,554,0,0,0,0,784,908,0,0,0,0,0,0,
+0,396,358,0,0,0,0,0,0,0,0,2,228,0,0,0,0,0,0,0,0,0,0,0,845,14,0,716,1820,594,0,
+81,1428,0,161,0,782,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,998,0,
+0,0,0,0,0,0,0,0,0,0,0,1043,0,1496,0,0,0,0,0,0,0,0,781,0,0,0,0,0,0,0,817,1114,0,
+1814,958,0,0,0,0,812,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,236,643,0,0,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,0,0,0,1338,0,0,0,
+0,0,0,0,0,0,0,0,54,0,0,0,256,0,0,351,0,955,1885,0,469,0,0,0,1270,0,744,0,313,0,
+0,0,0,0,0,0,0,402,969,0,0,0,0,0,0,50,0,0,0,0,572,0,0,0,0,847,0,0,0,0,0,0,0,248,
+43,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,766,0,363,0,0,0,0,0,0,0,0,0,0,0,678,0,0,409,
+258,82,249,0,0,0,0,0,0,0,0,0,0,0,0,32,393,0,788,0,0,0,1281,509,1968,0,0,0,0,39,
+291,0,0,0,589,0,0,54,1059,0,0,0,0,0,0,824,0,0,0,0,0,0,0,0,0,0,1005,0,1598,0,0,0,
+0,0,919,0,0,0,0,0,0,0,0,52,132,0,0,0,0,0,328,0,0,0,0,173,0,0,0,0,0,65,1411,0,0,
+0,0,0,0,0,0,0,0,442,0,842,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,0,0,845,
+210,0,0,0,0,0,0,0,0,892,0,0,223,0,0,0,0,529,0,0,0,807,0,137,218,0,1444,0,0,0,0,
+0,332,661,0,0,0,0,0,0,0,76,1517,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,0,0,0,0,0,481,
+379,0,0,0,0,0,149,18,0,0,0,0,0,0,0,0,742,304,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,799,925,195,51,0,0,0,0,688,0,0,0,0,697,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1169,751,0,0,0,452,929,0,221,0,1437,0,0,0,0,955,1251,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,132,0,0,0,0,0,865,0,0,0,0,0,0,0,767,
+672,42,0,0,0,1050,0,0,0,0,0,0,0,0,368,44,0,0,0,0,0,0,0,570,29,0,0,0,0,0,0,227,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,522,0,0,0,0,0,0,0,1529,0,0,0,0,0,0,739,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1667,0,0,0,0,0,0,132,511,0,138,208,1020,0,0,23,565,0,344,0,0,0,
+0,0,922,0,0,0,0,0,0,0,240,0,0,415,171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,402,0,0,754,31,716,0,982,731,0,0,0,0,0,0,0,888,0,0,0,803,847,0,0,823,
+0,0,0,0,0,0,785,0,0,2,0,0,0,0,0,0,0,532,0,0,681,0,0,314,0,384,684,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,649,447,0,1818,1007,0,321,0,66,360,0,0,0,385,0,0,0,0,0,0,
+0,900,73,254,0,0,0,0,683,1959,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,86,0,0,725,0,0,0,0,0,196,0,0,0,0,0,831,0,0,0,0,723,0,0,0,0,0,994,627,0,0,
+0,0,0,0,0,0,0,0,764,66,0,0,0,0,205,36,0,0,0,0,0,0,0,950,0,0,0,887,111,0,0,831,
+388,165,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,780,755,0,0,0,0,898,146,0,0,0,
+0,0,0,0,45,7,0,0,0,0,0,0,0,0,607,0,0,0,0,0,0,65,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0,
+621,600,0,367,0,0,0,0,0,0,0,561,0,559,0,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,672,157,0,0,0,0,714,0,0,0,
+0,0,456,0,925,0,0,0,0,0,0,0,0,19,0,0,0,0,1473,0,0,0,0,0,0,0,0,0,0,113,0,0,0,0,0,
+0,0,0,0,0,0,0,0,69,463,0,0,82,193,2,471,0,0,0,0,633,0,0,0,0,0,0,1148,129,1392,
+542,803,0,0,0,0,0,0,0,0,0,0,0,0,438,0,0,0,0,0,0,875,0,0,0,0,0,237,0,0,0,0,0,0,0,
+65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,563,0,0,0,9,444,0,0,43,1260,0,0,0,0,0,0,
+971,0,0,699,0,0,0,0,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,829,242,0,
+0,593,0,0,0,0,0,0,0,0,201,36,224,0,0,0,0,0,0,1430,0,1806,0,523,0,0,212,1889,0,0,
+0,827,0,0,0,0,0,2043,136,242,0,0,0,0,0,0,284,148,10,0,0,0,0,0,0,1249,0,0,0,807,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,94,0,0,0,494,0,0,0,0,0,0,0,0,1510,0,0,0,0,0,
+0,0,0,0,0,505,1306,0,0,764,268,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1703,0,0,0,0,159,964,583,0,0,0,
+0,0,0,515,0,0,854,0,0,0,0,0,0,0,0,0,0,0,0,1123,0,0,0,0,0,0,0,136,0,0,0,0,0,1782,
+0,0,44,1287,0,0,0,0,0,732,0,0,0,0,313,679,0,0,316,0,0,0,0,595,0,0,0,0,0,0,753,
+147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,0,0,0,0,414,0,1762,0,0,0,0,0,0,0,0,
+0,0,0,599,0,0,0,0,0,0,0,0,0,1749,0,0,0,1627,0,488,0,0,0,0,0,83,0,0,0,0,676,0,0,
+1639,0,0,0,0,0,0,0,0,0,278,0,0,0,0,0,0,97,0,14,1085,0,0,0,0,0,0,781,388,0,849,
+59,229,0,0,0,0,0,1115,0,0,0,0,108,0,0,0,0,700,0,0,0,0,0,0,0,0,0,1414,0,0,0,0,0,
+0,0,0,0,0,0,0,0,660,737,1035,0,0,0,0,0,0,521,690,0,0,0,0,0,0,0,0,0,0,0,0,272,0,
+0,0,0,0,0,0,0,0,0,1744,0,0,0,0,0,0,128,733,0,0,277,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,936,1981,40,0,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,306,0,0,0,0,
+0,0,0,979,0,0,0,0,0,611,0,0,0,0,0,178,0,0,0,1969,0,0,0,0,0,0,0,664,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,390,0,0,0,1510,0,0,0,0,0,0,0,0,0,0,0,493,0,0,37,0,0,0,0,724,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,1537,0,0,168,473,0,0,0,105,0,0,0,0,
+627,438,0,0,0,0,0,0,0,0,0,0,11,1256,0,0,0,1626,0,779,0,0,0,0,25,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,308,0,0,0,0,0,741,0,671,0,0,0,0,649,150,0,0,99,521,0,0,3,339,0,0,0,
+543,0,0,0,0,0,0,0,0,0,1358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,234,155,
+0,0,0,0,0,0,0,1628,0,766,0,0,0,0,0,0,0,0,0,0,0,0,0,829,0,0,0,1445,0,0,0,486,0,0,
+0,0,2,1635,0,0,0,0,558,0,0,0,0,0,0,0,0,0,0,1461,0,0,0,0,0,599,0,0,0,0,0,0,0,0,0,
+1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,0,0,0,0,0,447,0,0,66,1432,0,0,0,0,
+0,0,307,0,413,609,0,0,0,930,0,0,0,0,21,939,0,0,0,0,0,962,4,651,0,0,0,0,15,579,0,
+0,0,0,0,597,0,0,0,0,0,981,0,0,0,545,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,800,17,0,0,17,0,907,0,0,0,110,0,0,0,53,458,0,1983,0,0,0,0,0,0,0,0,0,0,443,0,
+0,0,0,0,0,0,0,0,0,0,924,1844,0,1232,0,0,0,0,70,519,0,993,0,0,0,0,0,0,14,530,0,
+907,0,0,0,0,0,733,0,0,0,0,0,0,0,0,55,0,188,531,56,0,0,1693,0,0,0,0,0,0,0,0,441,
+0,192,928,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1525,0,259,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,512,185,0,464,1603,0,0,0,0,0,0,0,0,0,0,0,1113,
+284,720,0,0,722,0,0,0,0,0,13,0,0,0,0,0,0,0,4,289,43,0,0,0,0,0,0,1694,0,0,0,0,
+193,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,308,0,0,1863,0,0,0,0,0,0,0,0,0,790,0,0,
+745,1002,0,0,0,0,0,0,0,0,0,289,68,477,13,0,0,0,0,0,0,0,0,0,0,609,0,0,0,0,0,0,0,
+0,0,0,0,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,0,0,0,0,0,0,694,58,
+548,0,0,0,0,0,0,687,0,0,0,0,1749,0,0,0,0,0,0,0,0,1004,661,0,0,0,0,0,0,445,0,0,0,
+74,0,0,0,0,213,0,0,0,0,0,0,0,0,0,0,0,0,0,834,0,0,189,1672,0,0,0,0,0,0,0,1548,
+192,0,0,0,0,0,0,0,0,0,0,0,0,0,32,751,0,78,0,0,0,0,0,0,544,1602,105,473,0,0,0,0,
+0,0,156,1949,0,1779,0,0,0,0,0,0,0,0,0,0,0,763,0,0,0,0,0,0,0,0,29,0,0,0,0,0,0,0,
+0,0,0,883,0,0,0,0,0,0,0,488,0,617,0,0,50,0,694,1518,785,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,546,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,1016,0,0,0,577,0,0,0,0,0,0,
+184,935,114,720,0,0,100,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,95,14,0,969,0,0,0,0,0,0,0,
+727,0,1021,0,0,0,0,0,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,0,0,0,0,0,0,0,0,798,0,
+587,0,0,695,42,0,1929,141,957,0,465,7,908,0,0,450,148,0,0,0,1166,0,0,0,0,0,0,0,
+0,0,0,0,0,253,0,1003,0,0,0,0,0,0,0,0,0,0,0,46,0,0,879,0,806,0,1868,0,0,0,0,0,
+1846,0,0,0,730,0,0,0,0,0,0,0,965,0,0,0,0,506,0,0,0,10,0,0,0,22,0,0,0,0,0,0,0,0,
+0,0,0,0,0,960,296,0,0,0,0,0,0,0,0,0,0,0,587,0,0,0,0,20,0,0,0,32,982,0,0,0,0,0,0,
+0,0,0,0,941,0,0,0,0,435,0,0,0,0,0,0,71,419,0,0,0,0,0,0,688,740,94,345,0,0,679,
+582,0,0,0,0,0,0,0,945,0,0,0,0,0,0,0,0,0,0,0,0,539,0,684,1993,0,0,0,659,0,583,0,
+803,0,704,0,0,0,0,0,198,181,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,481,405,203,0,0,99,826,0,0,0,0,0,0,0,492,0,408,0,0,0,0,0,0,0,0,0,0,4,0,0,
+0,0,665,349,137,0,0,0,0,612,1270,0,0,0,0,0,371,0,0,0,826,0,0,0,0,21,1535,858,
+374,0,0,0,0,0,0,311,0,0,0,991,1968,0,0,0,0,494,1647,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,769,0,0,0,0,0,642,0,0,157,123,0,0,0,1435,0,0,0,0,0,0,0,0,0,0,79,0,0,0,
+0,0,0,1425,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,393,486,1690,0,0,0,0,
+0,0,0,0,0,0,0,0,756,184,0,0,0,1382,0,0,0,175,0,1493,0,1007,0,0,0,0,0,0,0,0,0,0,
+0,219,0,0,0,0,515,99,0,851,0,0,0,0,0,1278,0,0,0,0,0,0,0,1000,982,0,762,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,910,1819,0,0,0,0,0,0,906,0,0,0,0,0,0,0,0,0,0,1730,0,0,
+0,0,0,0,0,0,0,0,0,1185,0,0,0,0,0,0,0,0,40,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0,
+650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,30,0,553,0,0,20,597,0,1614,0,0,0,0,0,327,
+49,0,0,0,0,0,0,0,78,0,0,786,134,0,0,0,12,496,0,0,0,0,0,0,0,0,0,0,42,204,0,614,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,247,0,0,0,0,942,0,0,2023,0,0,0,0,
+0,0,67,285,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,532,0,0,0,0,0,0,0,
+1692,0,0,0,0,55,1704,0,0,0,0,988,0,0,0,223,0,0,0,0,0,0,0,57,1123,0,0,0,0,0,1764,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2015,0,0,0,1599,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,
+0,0,504,621,1248,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1397,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,441,75,0,0,0,0,0,0,0,0,0,0,841,0,0,0,0,0,693,0,650,314,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,475,0,
+0,1016,179,602,111,329,0,0,0,1864,0,0,0,0,846,1888,0,0,780,0,0,0,82,0,0,0,0,821,
+0,0,0,0,0,0,0,0,0,0,0,956,112,0,0,0,261,455,0,0,0,0,0,0,337,385,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,184,1865,0,0,721,16,0,486,0,0,0,265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,621,0,0,0,0,0,0,0,0,234,0,0,815,0,0,743,
+1987,205,197,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,219,452,589,0,
+176,333,0,0,0,0,0,0,0,1110,47,0,0,0,0,0,0,0,0,0,0,0,864,0,0,300,0,1237,0,0,0,0,
+0,0,0,0,0,0,0,1685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,135,395,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,835,0,0,0,606,459,0,979,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,612,0,0,0,0,0,0,0,0,158,372,0,854,0,0,0,0,0,
+0,0,1492,0,0,0,833,0,0,0,0,0,0,0,1739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+195,0,0,0,0,0,0,0,0,730,1997,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,266,751,0,0,0,0,0,
+0,0,821,0,0,0,715,0,0,0,868,0,959,0,0,0,0,0,0,0,0,0,0,0,1053,0,0,0,950,0,1081,0,
+1595,0,0,0,0,59,0,0,0,0,0,0,0,0,0,0,47,684,0,0,0,0,0,0,1606,0,777,0,1020,0,0,0,
+1094,0,0,0,0,0,0,0,350,0,0,0,0,0,0,242,1812,0,0,0,967,0,0,0,473,286,0,0,0,0,0,0,
+798,629,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,513,337,306,0,0,0,0,0,0,0,0,0,
+146,0,0,1646,0,0,0,0,0,465,0,0,0,525,0,0,0,0,0,0,299,165,0,0,0,0,0,0,0,1064,0,0,
+0,0,0,596,0,0,0,0,0,0,0,0,0,0,0,0,0,0,238,1741,0,1233,451,1824,0,0,0,0,733,495,
+0,0,0,0,0,1204,0,0,0,559,341,0,224,21,0,0,0,0,0,0,0,0,97,1446,0,0,0,0,0,0,0,729,
+0,0,565,727,0,1948,0,0,0,519,0,0,0,0,0,0,0,0,0,1193,0,0,0,0,0,0,790,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,323,2,201,0,0,59,0,0,34,0,896,961,0,1285,0,0,46,0,479,0,0,
+0,0,549,0,663,0,0,0,0,0,783,65,682,0,0,0,0,0,11,0,0,0,0,0,522,0,0,0,52,0,0,0,0,
+0,383,0,0,0,0,0,0,0,0,127,0,0,0,0,0,397,194,0,0,635,0,0,0,0,0,0,0,0,0,0,975,0,0,
+0,0,0,0,0,0,0,0,116,0,51,0,0,858,0,1075,535,448,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,
+0,191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,267,673,319,94,92,0,551,0,0,218,
+1406,69,256,0,0,952,1980,0,833,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,81,0,0,
+0,352,634,0,0,0,0,0,618,0,0,0,0,0,0,73,339,0,0,0,0,0,0,0,0,0,0,0,0,0,0,169,759,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1075,0,0,0,0,0,0,482,649,0,0,0,0,0,0,0,0,386,336,0,0,
+0,1035,0,0,0,0,0,0,0,0,0,0,0,924,0,73,0,0,0,0,0,1971,0,0,0,0,0,0,0,0,0,1344,0,
+501,0,0,0,0,0,0,0,0,46,799,0,0,0,0,0,0,0,276,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,0,
+0,0,0,0,0,158,0,0,0,0,0,1432,0,0,0,0,0,0,0,0,0,0,25,0,0,2001,0,0,0,0,0,0,0,0,0,
+0,0,0,0,478,0,0,0,0,0,0,91,1461,211,602,0,0,0,0,0,0,0,0,0,1068,0,0,124,567,0,0,
+0,1006,0,0,0,0,0,0,0,0,0,735,812,0,0,323,0,0,0,304,0,0,0,0,0,0,0,0,0,148,0,0,0,
+0,0,0,0,0,0,523,0,0,144,730,0,0,981,0,0,111,0,0,132,0,0,0,0,0,0,890,0,0,0,0,0,
+444,0,1787,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,2041,932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,937,0,995,0,0,255,0,0,138,863,965,0,0,631,0,0,0,0,1394,16,652,0,0,0,0,0,0,
+0,0,0,0,0,0,0,897,0,321,0,0,0,0,0,922,0,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,844,0,0,0,0,0,0,1659,0,1100,0,0,0,1173,0,1930,268,251,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,390,711,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,0,0,0,0,624,0,0,0,
+1998,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1125,0,0,0,594,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,268,0,0,0,0,0,0,0,563,0,0,0,0,0,0,0,0,2,39,0,0,0,1332,0,0,0,0,0,
+0,0,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,796,0,0,0,0,527,0,0,0,0,98,0,0,576,0,
+0,0,0,0,122,0,276,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,0,
+0,0,0,0,0,0,0,290,0,0,762,1292,0,0,0,1315,0,1955,0,0,0,0,0,0,0,0,0,0,210,131,0,
+0,0,0,797,0,38,0,11,488,0,936,0,441,0,0,0,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+991,0,0,0,0,0,0,0,0,0,0,0,653,0,523,0,0,0,903,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,
+0,0,0,0,0,0,432,0,0,314,0,0,0,0,232,1368,534,0,0,0,0,0,27,0,0,0,12,0,0,0,0,0,0,
+0,0,0,264,736,0,1657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1117,0,127,0,0,0,1208,0,1294,
+0,0,0,0,364,0,0,0,0,0,125,1334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,792,0,0,0,0,0,0,0,
+849,699,0,0,0,0,0,968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1446,
+124,397,0,0,0,0,0,0,0,0,0,0,0,641,0,0,0,0,0,0,0,0,0,0,0,0,127,346,0,0,517,75,0,
+0,0,0,0,0,0,0,83,0,0,0,0,0,0,1031,0,0,0,0,0,0,0,1470,0,954,0,0,345,304,410,0,0,
+0,0,734,0,0,0,0,0,1822,0,0,0,1798,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,161,
+1865,69,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,0,0,0,541,0,627,0,0,0,0,0,0,0,0,0,166,0,
+0,0,0,0,0,0,0,0,849,0,0,0,0,0,0,0,717,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,0,0,0,0,0,
+0,654,0,0,188,273,0,0,0,543,0,410,87,0,0,941,0,0,186,250,0,1785,0,0,0,0,0,1339,
+462,961,0,780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,529,0,0,0,0,0,0,474,1276,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,24,948,0,0,0,0,657,753,0,0,0,0,941,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,706,985,837,0,1861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,292,933,0,0,0,0,0,
+0,0,0,0,767,0,0,0,0,0,0,0,641,0,0,0,1233,114,0,883,0,274,2008,0,1794,285,0,0,
+571,0,0,0,0,0,0,0,0,0,0,823,960,16,617,0,431,0,0,0,0,0,0,0,0,0,0,567,0,401,0,2,
+781,424,33,0,2006,0,0,274,0,0,1882,0,794,0,0,0,1848,0,0,0,0,0,0,448,47,0,0,0,
+1199,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,295,0,0,0,0,0,0,0,1019,0,0,0,0,0,0,
+0,0,0,0,0,0,0,620,0,0,0,0,464,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,442,0,930,0,0,0,0,0,516,68,0,0,0,0,0,1128,104,0,0,0,0,0,0,0,0,787,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,491,0,0,0,0,0,0,711,0,0,9,0,101,441,0,0,0,0,0,0,0,0,
+0,0,160,396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,679,326,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1128,0,0,0,0,0,737,0,1796,0,0,0,0,0,0,0,0,0,0,0,0,338,574,0,0,
+0,0,0,1096,491,405,0,0,0,0,0,1081,0,0,0,0,0,0,0,0,0,0,0,0,0,1676,0,1207,0,0,0,0,
+0,0,969,354,0,0,0,0,598,0,297,0,0,0,0,0,0,0,0,1772,751,0,37,0,0,1828,0,0,0,0,0,
+0,0,0,0,257,191,582,0,0,0,0,0,0,790,0,0,0,0,0,47,0,0,0,0,0,0,0,449,306,1011,0,0,
+0,0,0,299,0,0,0,0,0,0,837,0,0,0,0,0,0,10,329,0,0,0,0,0,1320,0,0,0,0,0,0,158,657,
+0,1191,0,0,0,0,0,0,7,0,974,1939,0,1665,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,288,
+66,0,0,0,0,494,175,0,1643,0,0,0,0,0,0,0,0,570,750,719,0,0,0,0,0,0,0,0,0,0,0,0,0,
+13,0,0,1247,0,0,221,356,0,0,0,0,0,0,0,0,0,0,694,1809,0,0,0,0,0,0,0,411,0,44,31,
+0,0,0,0,669,0,673,0,0,0,0,0,0,0,0,0,1303,704,299,0,0,0,275,0,0,216,1761,0,0,0,0,
+0,0,0,0,0,0,0,1319,0,0,428,0,0,0,0,0,0,0,0,0,0,514,0,0,0,0,0,0,49,55,102,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,364,0,0,0,0,379,0,921,971,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1258,0,0,0,1058,0,0,0,0,0,656,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,
+0,1373,10,605,0,0,0,0,0,0,0,838,0,1012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154,365,0,0,
+0,0,0,0,0,0,0,340,0,0,0,0,0,810,0,0,0,0,0,0,495,0,0,0,0,0,0,0,0,0,261,0,535,248,
+0,358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,567,445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,697,0,0,0,1336,0,0,0,0,0,0,0,0,917,174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,351,0,0,0,0,0,0,0,0,0,0,
+0,0,0,286,0,0,56,438,0,0,0,0,0,1950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,738,0,0,0,0,0,
+0,0,0,0,0,969,2047,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,866,0,0,0,0,0,0,0,1467,0,0,0,
+0,0,0,0,0,0,0,0,0,0,972,0,355,0,0,0,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,267,189,104,0,0,0,0,1613,0,0,0,0,0,0,0,116,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,886,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,863,0,0,0,0,0,
+0,0,1953,450,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,
+0,0,0,0,0,1142,0,1189,0,0,0,663,0,0,0,0,0,0,0,846,0,0,528,0,393,378,0,0,0,0,0,0,
+325,899,680,1880,0,1770,0,0,0,0,0,648,0,0,0,0,0,0,185,167,0,2046,0,0,0,0,0,0,
+249,1645,0,152,0,0,0,1733,0,0,0,0,0,1006,0,0,0,0,0,420,0,0,0,832,0,0,0,0,0,351,
+0,0,0,0,6,40,0,0,60,0,0,0,0,1354,745,724,0,0,0,0,0,0,0,0,772,1951,275,108,639,0,
+0,0,0,0,0,0,0,0,500,1758,0,0,0,0,0,0,0,0,0,0,0,1886,711,205,0,0,965,865,0,0,0,
+534,0,0,0,0,691,0,0,0,237,443,0,878,0,0,0,0,0,1410,0,0,0,0,0,0,0,0,0,0,0,0,0,
+995,0,0,0,0,0,0,0,0,0,0,0,0,0,578,0,0,0,0,881,0,0,0,0,0,0,0,0,822,0,923,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,665,0,0,0,0,0,1901,0,0,0,0,0,950,498,93,
+0,0,0,1451,0,0,0,0,0,747,828,788,400,184,0,198,0,0,0,0,0,0,0,0,0,0,0,994,0,0,0,
+0,0,0,0,0,615,320,0,0,0,978,843,905,0,0,0,0,0,0,0,0,850,974,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,0,0,0,0,0,273,0,0,0,0,0,0,0,0,0,0,0,0,0,
+201,0,0,0,1041,0,0,0,1040,0,0,0,0,0,0,0,0,0,693,234,774,0,336,0,1399,22,0,805,
+802,777,167,789,0,0,1705,0,0,0,0,0,0,0,0,0,0,0,10,13,11,0,0,204,264,0,0,56,0,0,
+1917,0,470,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,0,0,1002,0,0,0,298,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,867,0,0,724,0,0,0,0,0,0,0,0,0,0,0,0,768,0,0,0,0,0,1066,0,0,0,0,67,0,174,948,
+0,0,0,0,0,0,0,0,0,0,0,0,0,764,0,0,0,0,75,137,0,756,0,0,0,0,0,0,1008,842,643,0,0,
+0,67,0,0,0,0,0,0,0,0,0,0,0,135,821,0,0,0,0,0,0,0,0,736,0,389,355,0,0,786,0,0,0,
+0,0,0,2044,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1030,0,0,0,1083,0,0,0,0,0,
+1226,0,0,0,0,356,319,8,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,474,0,0,0,427,
+0,413,0,730,0,0,0,0,0,373,0,0,0,0,0,0,0,0,0,799,0,0,0,1793,0,0,0,322,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,290,2,0,0,0,0,0,0,0,0,0,0,672,
+699,1860,0,0,0,737,0,0,0,1612,0,0,0,0,0,0,0,0,0,0,0,145,124,884,0,0,0,0,0,387,0,
+0,0,0,0,0,0,0,0,0,0,679,0,550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,0,0,
+576,0,0,0,0,0,0,0,686,0,607,0,0,37,0,0,0,0,0,0,0,0,0,101,1726,0,0,0,0,0,958,0,0,
+0,903,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,367,0,0,0,0,690,0,705,273,0,0,887,0,0,0,
+0,0,0,0,0,0,0,0,90,0,0,0,0,0,0,0,908,0,0,0,0,0,0,0,1261,0,0,497,1235,0,429,0,0,
+0,0,904,0,12,125,0,0,0,841,0,0,0,0,0,860,946,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,768,0,770,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,271,0,0,0,0,0,0,0,719,0,699,581,0,0,0,0,0,0,0,0,0,0,862,304,0,631,0,0,0,0,880,
+1513,0,0,0,0,0,981,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,434,0,0,0,0,0,550,0,0,476,930,
+824,553,0,0,452,0,151,0,0,0,0,0,0,772,0,292,135,0,0,0,0,0,0,0,504,0,0,1089,0,0,
+0,0,0,0,0,0,0,0,0,783,0,0,0,0,0,0,206,393,0,0,0,0,0,0,0,0,232,912,0,0,0,0,0,977,
+0,0,716,98,0,0,0,0,0,733,0,0,0,0,0,0,0,0,19,0,0,0,0,668,0,360,0,0,0,0,0,0,656,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,726,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,1269,0,0,463,0,
+0,0,0,0,0,1454,0,1287,245,0,989,0,0,0,0,0,0,0,0,0,107,164,0,0,0,0,0,0,0,1061,0,
+0,0,0,2,484,0,0,0,0,0,0,0,1127,0,0,0,0,0,0,0,460,0,0,0,0,0,932,0,0,0,0,0,0,0,
+588,625,0,0,0,0,76,92,0,0,0,0,0,0,0,0,0,0,0,0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+763,0,622,0,0,0,253,0,546,0,0,110,0,256,916,0,0,35,212,0,0,746,0,0,0,150,0,0,
+1466,0,0,0,1299,0,0,0,0,0,0,0,0,0,1518,0,0,0,0,0,0,0,0,0,0,0,0,0,1229,0,0,0,816,
+0,0,0,0,0,0,159,0,0,0,0,0,734,869,126,1716,0,0,0,0,0,0,202,232,0,0,0,0,212,0,0,
+0,0,0,111,1003,0,0,0,0,0,0,0,0,0,0,0,1712,0,0,216,0,0,0,0,516,0,0,0,0,0,650,0,0,
+0,0,57,99,0,0,0,0,300,574,0,0,0,0,1023,0,0,302,0,1871,0,728,252,0,0,461,0,0,0,
+323,0,0,0,0,0,0,775,461,0,0,0,0,0,0,172,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,73,727,0,1023,0,0,0,0,0,0,0,0,0,0,577,0,0,0,0,0,0,0,0,1037,0,0,0,0,0,0,
+0,0,280,677,0,0,0,0,0,0,0,0,0,0,0,799,0,0,0,0,159,0,446,1730,0,0,0,0,0,0,0,0,0,
+395,0,0,0,0,145,0,0,0,0,0,0,0,20,0,0,426,608,0,0,0,0,0,977,0,250,0,0,0,0,0,100,
+0,0,0,0,1982,0,0,0,0,0,476,0,0,0,0,0,0,594,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,447,0,0,0,0,526,0,0,14,1124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,188,0,0,0,0,0,0,0,0,362,301,0,0,0,1743,0,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,831,0,0,208,202,0,0,0,0,0,0,0,1954,0,
+0,0,0,516,872,0,0,313,224,0,0,24,0,11,546,0,0,0,1937,242,241,46,0,0,0,830,1273,
+0,0,0,0,0,0,0,825,327,1006,0,0,0,0,0,1580,516,366,0,0,0,0,0,1736,0,0,0,0,0,0,0,
+0,0,0,0,1935,0,826,0,0,0,0,139,331,0,0,0,0,0,0,0,0,0,0,0,288,0,916,0,0,0,0,0,
+1888,0,0,0,0,0,0,0,1471,0,1570,0,394,0,0,0,0,0,0,0,1931,0,1719,0,658,228,0,0,0,
+0,0,374,0,0,0,0,735,0,0,0,0,0,0,323,498,0,1063,0,0,0,0,155,0,0,0,0,0,0,0,0,906,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,616,
+902,0,0,0,0,0,692,0,0,0,0,0,0,823,0,0,0,305,0,0,0,0,0,0,0,681,0,0,0,0,0,214,
+1004,0,0,0,0,0,0,0,23,0,0,1703,0,0,0,0,0,0,0,0,0,1443,0,0,19,714,0,0,0,0,64,737,
+0,0,345,1758,0,0,579,47,0,0,539,139,0,0,0,0,388,0,0,0,0,253,0,0,0,0,0,0,252,0,
+745,0,0,0,0,0,0,0,0,0,0,0,504,107,0,871,0,0,0,229,0,0,0,0,0,903,0,0,71,0,0,549,
+6,47,0,0,0,0,0,0,0,0,0,980,865,705,0,0,0,161,0,0,0,0,143,1331,0,0,0,1388,33,724,
+0,0,0,19,0,0,0,395,0,0,0,0,0,846,210,0,0,0,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,937,497,0,0,0,0,0,718,0,0,0,0,0,0,0,1581,0,
+0,0,0,0,0,161,49,0,0,0,0,0,0,0,0,0,597,0,0,0,1094,0,0,0,811,908,0,0,0,0,0,0,0,0,
+0,0,1471,0,0,0,0,0,0,0,0,0,0,42,1935,0,0,0,2014,66,2007,0,0,586,0,0,0,0,0,0,0,0,
+0,28,1077,0,0,0,1221,0,0,62,0,0,0,0,0,0,0,0,0,0,1766,0,0,0,0,0,0,0,0,0,0,0,0,25,
+0,499,1388,0,0,97,10,0,0,0,0,0,481,0,0,0,0,0,0,0,0,0,0,37,134,155,486,0,1442,0,
+0,0,0,0,591,0,0,0,0,0,0,310,1173,0,0,0,0,409,1156,0,0,0,482,0,0,263,926,0,0,0,0,
+0,0,0,0,0,0,0,0,0,804,0,0,0,0,0,0,0,0,0,0,0,0,0,1265,0,415,0,348,0,0,0,1012,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,165,1803,0,0,0,0,0,0,0,408,
+0,0,0,0,0,0,257,1321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1138,0,0,0,249,0,
+0,0,576,0,0,0,0,231,0,0,0,288,0,0,0,0,0,0,0,0,0,433,1487,569,1678,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,0,0,0,0,0,779,538,0,0,0,413,0,0,0,
+0,0,0,0,0,0,0,495,0,0,0,0,0,191,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,530,567,
+0,0,0,0,0,1484,0,0,0,0,0,0,815,609,0,0,0,0,0,484,0,0,0,0,0,0,0,0,0,0,900,0,0,0,
+0,1335,0,1724,0,0,0,0,0,0,0,0,0,0,0,640,0,0,0,0,0,0,0,0,0,0,0,1831,0,0,0,0,0,0,
+0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,1103,0,1504,655,1034,0,0,0,0,0,305,0,0,0,0,
+0,0,0,0,0,1236,0,0,429,217,0,0,0,0,739,278,0,0,0,0,0,0,0,708,0,0,0,0,0,1840,233,
+0,0,0,0,0,0,0,0,2017,0,0,0,0,0,1488,0,0,0,1590,0,0,0,0,0,1800,28,0,0,0,0,0,0,0,
+0,0,45,0,36,0,22,1442,378,0,0,0,0,0,0,1507,0,0,0,0,0,0,0,0,0,0,39,0,0,1054,725,
+1955,0,2036,0,0,0,0,0,0,0,0,0,0,896,1871,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,2046,0,
+0,0,0,17,712,0,617,55,320,271,0,0,0,0,0,0,0,0,0,445,0,184,103,0,0,0,0,0,0,0,0,
+659,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+337,0,0,0,506,0,0,0,0,0,843,77,0,458,0,0,0,0,0,1420,382,109,142,330,0,0,0,0,0,0,
+0,0,0,0,0,0,87,0,0,0,492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0,
+211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1049,0,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1985,0,0,122,0,0,234,0,0,0,1098,0,0,0,0,0,0,549,253,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,522,131,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,507,0,0,0,0,811,630,0,0,0,343,
+0,0,0,0,0,448,591,455,0,1381,0,0,0,0,0,0,0,575,0,0,0,0,0,1175,0,0,0,0,0,0,0,0,0,
+653,0,0,0,1761,0,1198,0,0,0,0,297,1127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,678,0,0,
+164,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,45,0,0,0,0,0,121,0,0,0,0,0,0,
+0,0,125,0,0,0,1622,0,0,0,0,0,721,145,0,0,0,970,792,0,0,0,715,0,0,0,0,0,1999,0,0,
+74,531,0,0,65,0,0,0,105,220,0,0,0,0,0,0,0,960,0,0,0,0,0,0,428,19,0,0,401,96,0,0,
+0,0,0,1595,116,0,1021,0,0,0,0,0,750,1961,0,0,148,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0,
+0,1383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,779,0,0,0,0,0,0,0,0,598,0,424,0,0,0,0,0,0,0,
+1222,0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,0,0,187,0,8,0,0,0,0,0,
+0,0,429,0,685,0,0,0,0,0,0,0,0,0,0,0,132,472,0,0,0,0,0,0,0,0,0,938,0,0,874,0,0,0,
+0,0,774,0,0,0,0,0,92,0,0,0,0,0,0,830,701,0,0,0,0,0,426,350,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,603,59,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,441,163,4,0,
+0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,233,0,0,0,0,1994,0,1739,0,0,393,0,47,1038,0,0,0,
+309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,363,0,0,0,175,0,0,0,0,0,0,0,666,
+0,0,1675,0,1600,0,0,0,808,0,0,0,0,0,0,0,0,0,0,0,280,54,0,0,0,0,0,0,0,0,421,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,0,0,103,254,0,262,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,1630,0,0,0,0,0,0,0,0,0,0,0,0,0,671,972,989,0,0,
+0,0,0,0,0,889,0,0,0,1382,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,0,388,202,0,0,0,0,
+16,560,0,0,0,841,0,0,566,0,0,0,938,0,0,0,0,0,0,0,0,0,0,912,0,0,0,1361,0,0,0,0,0,
+0,618,236,0,1854,0,0,318,190,0,1376,0,0,0,0,0,0,0,349,0,0,0,0,951,1972,0,0,0,0,
+0,0,344,0,0,0,0,0,0,0,0,850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,163,85,0,487,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,145,0,83,0,0,1013,0,0,0,1922,0,0,169,557,66,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1193,82,0,352,454,57,0,0,1333,396,107,0,370,0,0,0,0,0,0,0,0,0,204,0,0,0,
+0,0,1706,0,0,0,0,0,0,0,0,0,0,0,0,394,1204,0,0,0,0,0,1007,0,0,0,1696,0,1519,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,981,0,0,0,0,1072,0,0,0,712,0,1629,0,0,0,0,0,0,0,728,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1271,0,0,0,1608,16,0,0,0,0,485,0,0,0,0,0,0,
+153,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1991,0,0,0,0,0,0,0,0,52,0,21,0,
+0,0,0,0,0,0,0,0,819,0,0,0,0,0,917,0,0,0,0,784,0,0,0,0,135,0,0,0,0,0,454,0,0,0,0,
+0,0,0,0,0,852,1719,0,0,0,0,0,852,0,0,0,0,0,952,0,0,0,0,568,0,0,0,0,0,448,0,0,0,
+67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1826,657,0,729,666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+669,0,0,0,0,0,0,0,402,0,0,152,0,0,0,0,912,0,0,0,0,0,0,51,320,0,445,0,0,0,0,308,
+0,0,0,0,0,386,0,0,239,0,0,130,83,0,143,0,348,0,0,0,0,0,0,0,958,0,0,0,0,0,210,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,430,0,0,0,0,0,0,0,0,0,0,0,0,7,213,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,801,0,0,0,0,0,0,0,0,0,936,0,108,0,0,
+0,0,0,0,0,0,0,885,587,219,398,364,0,1165,0,0,342,241,303,0,0,0,0,0,0,0,0,0,0,
+1454,0,0,0,0,0,0,0,0,0,0,254,562,0,786,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1294,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,493,216,0,0,0,0,219,341,0,0,0,0,0,
+0,0,0,0,0,130,1734,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,701,604,0,0,879,0,195,
+666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1669,0,0,0,1791,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1228,0,0,0,0,0,623,0,0,0,0,0,0,0,798,0,0,0,0,0,0,0,0,0,0,0,0,84,
+122,0,0,0,837,0,0,0,0,0,0,1013,0,0,577,0,0,0,460,932,0,0,0,0,0,0,0,0,0,0,0,31,
+131,0,0,0,605,0,0,0,1246,0,0,0,0,68,278,165,307,781,0,0,0,0,0,0,33,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1113,0,0,720,1953,203,0,0,0,0,0,0,0,425,326,0,0,0,0,0,
+0,0,0,0,0,241,1316,0,0,0,0,0,416,0,0,0,1300,0,847,0,0,662,358,0,0,0,0,839,1823,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,654,1522,0,0,0,0,0,0,163,0,0,0,0,0,314,978,0,0,0,
+601,0,0,0,0,0,946,434,0,0,0,402,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,1467,
+410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,1405,0,0,0,0,0,0,108,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,777,0,0,0,0,0,747,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,505,0,326,0,0,164,628,654,0,0,0,
+37,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,668,152,0,0,0,0,0,0,0,0,0,0,0,581,
+0,0,0,0,44,126,89,0,0,0,0,0,0,0,0,1531,0,0,0,0,0,0,0,0,203,1167,0,0,0,0,0,0,0,0,
+531,1232,0,0,0,0,0,943,0,670,231,880,0,1617,0,0,0,1957,0,0,0,0,0,0,0,975,0,0,0,
+0,0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,0,0,421,0,0,14,834,0,0,0,0,0,0,0,0,0,0,0,0,
+465,0,0,0,0,0,834,688,413,855,0,0,0,590,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,
+0,45,169,0,0,0,0,0,0,0,0,0,0,0,198,0,0,565,585,0,0,0,0,0,0,0,0,0,0,0,0,0,691,0,
+0,0,593,0,0,0,0,0,0,0,0,0,913,116,0,0,0,0,1360,0,0,0,802,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,673,308,0,709,1006,1895,0,228,0,0,0,1840,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,608,0,0,0,0,0,0,0,0,0,1573,0,2039,136,540,0,0,0,0,0,0,0,
+897,0,0,938,1878,0,0,0,0,0,0,0,0,0,1469,0,999,0,299,0,0,0,0,0,0,0,578,0,0,0,0,0,
+456,0,0,0,1679,163,693,0,0,0,0,0,0,48,755,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,
+1091,0,0,0,0,695,0,0,1464,0,0,0,0,0,975,0,0,335,0,0,1979,0,0,0,0,269,1566,630,
+396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1815,634,0,0,0,966,0,0,0,0,0,0,0,9,
+412,0,958,0,0,579,382,0,212,0,0,0,0,965,681,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,655,
+0,0,0,0,67,0,0,0,0,0,0,751,0,0,0,0,423,231,0,0,1016,300,0,0,0,0,100,237,0,0,0,
+1370,0,0,0,1208,0,0,0,0,0,1219,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,199,0,0,427,0,0,
+0,0,949,665,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,712,0,0,0,0,0,1186,0,0,0,0,0,0,0,0,0,0,295,312,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+151,0,0,0,0,588,4,0,0,0,0,0,414,104,0,0,757,263,0,561,0,0,0,320,0,0,0,0,0,0,0,0,
+0,0,0,225,0,0,0,0,37,817,0,974,0,0,0,0,0,0,0,0,0,0,0,0,0,2026,131,235,16,0,590,
+1157,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,390,0,0,0,0,
+0,0,0,1144,0,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,204,407,303,1218,0,0,0,0,5,325,0,0,
+0,0,12,800,0,1783,0,0,0,0,0,0,0,0,0,0,504,621,0,0,0,0,0,0,0,0,0,920,0,376,0,0,0,
+0,0,218,580,0,768,454,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,164,0,0,0,0,0,0,0,
+0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,120,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,343,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,1812,0,0,8,0,0,0,21,1125,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1327,0,0,0,0,575,1598,0,0,0,0,0,0,0,0,0,895,0,0,0,959,0,0,
+0,0,0,1759,173,0,0,0,0,266,261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1427,0,0,300,1033,0,0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,52,734,
+0,0,217,239,0,1129,0,0,0,0,0,0,0,0,732,20,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,613,0,
+0,0,0,0,0,0,0,0,632,0,0,85,984,0,0,0,0,909,694,7,1109,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,167,0,0,0,0,280,62,0,0,33,0,0,359,186,980,0,0,0,0,0,0,0,0,0,0,0,585,0,0,0,
+211,0,0,336,145,0,1130,0,873,0,0,840,263,0,0,0,0,0,0,0,0,0,916,0,0,0,0,0,0,0,0,
+0,0,155,0,0,0,461,97,0,0,0,0,0,1356,0,0,0,0,0,0,0,593,0,0,0,0,0,1392,0,0,0,0,
+126,0,0,0,0,1179,0,0,0,0,0,162,0,0,0,0,0,765,0,187,0,1286,0,0,0,0,0,0,0,0,0,635,
+0,0,23,215,0,0,0,1306,0,0,97,716,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,657,0,
+0,0,0,0,0,0,0,299,0,0,0,0,0,0,134,0,0,0,0,0,0,0,0,0,0,0,658,1082,0,0,0,0,0,2002,
+0,0,0,0,0,0,833,248,0,0,0,0,0,1654,0,0,531,0,0,0,0,0,0,634,0,0,0,0,0,0,0,0,0,
+853,573,249,0,0,0,0,0,0,0,0,527,0,0,0,0,1419,0,0,0,0,0,0,20,49,0,0,0,992,0,0,0,
+728,0,0,0,0,0,0,0,0,0,0,0,0,497,1579,0,0,0,0,62,268,0,0,0,0,0,0,0,1201,0,0,0,0,
+0,0,0,0,0,0,0,0,495,193,0,0,0,0,106,0,0,859,0,0,23,0,0,0,0,0,0,0,813,925,0,0,
+223,613,953,0,0,0,0,0,0,0,0,666,0,0,0,0,0,0,0,0,0,670,0,0,40,216,0,0,0,0,0,0,
+259,0,0,0,440,1114,0,0,0,0,0,0,0,0,74,475,0,0,188,139,0,797,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1572,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,1594,0,0,0,0,0,0,0,290,0,232,
+0,0,887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,14,0,0,0,0,0,741,0,0,0,992,0,
+0,0,0,0,0,0,0,111,0,0,425,0,0,0,0,0,789,0,0,0,1593,0,1768,0,0,233,0,0,0,0,943,0,
+0,0,0,0,0,0,955,225,245,0,0,0,0,0,0,241,0,0,0,0,1943,0,0,0,1284,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,709,0,0,0,0,0,0,554,0,0,0,0,0,0,0,0,1564,0,0,0,
+443,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,729,0,0,0,348,0,0,0,0,0,0,0,758,848,298,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,829,1422,189,121,0,0,632,812,0,0,556,0,0,0,0,0,436,172,
+530,844,232,984,0,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,537,0,0,0,0,0,859,0,0,
+842,0,0,0,0,0,0,0,0,0,0,1291,0,0,0,0,0,0,0,0,0,0,0,1482,612,392,0,0,0,262,31,0,
+0,0,0,0,0,0,0,0,0,753,549,0,0,0,0,0,0,696,0,0,0,0,0,0,0,834,0,0,0,0,0,771,0,0,0,
+0,0,0,0,0,0,0,0,0,0,921,0,0,0,674,0,0,0,0,0,0,0,0,0,0,308,444,0,0,0,0,0,0,805,
+180,0,0,278,271,0,0,214,505,0,1215,0,0,0,0,0,0,387,271,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1645,42,92,0,459,0,0,330,1557,0,0,0,0,0,0,0,0,113,18,0,0,0,
+1742,0,0,0,965,0,0,0,0,0,0,0,0,0,0,0,0,0,182,0,0,65,0,0,0,0,0,0,0,0,0,0,0,0,973,
+0,0,0,0,0,328,0,0,588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1786,
+0,0,962,1985,0,0,0,308,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,588,0,0,0,0,0,0,614,793,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,290,0,0,0,0,0,0,0,0,0,0,1136,0,0,0,0,0,0,0,0,0,0,796,719,0,0,
+326,210,0,0,0,701,758,472,0,0,0,1947,278,1079,0,0,0,0,0,0,497,41,0,0,634,46,961,
+0,810,524,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,532,0,997,0,0,0,0,0,0,0,0,0,0,0,1301,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1298,0,671,0,0,0,306,0,0,0,0,0,0,0,0,0,0,
+693,1823,0,0,0,759,0,0,0,0,0,1932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,182,0,0,0,1964,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,0,0,0,0,0,0,424,857,0,0,0,0,671,328,0,
+529,0,0,0,0,0,716,0,1509,80,67,0,0,0,0,59,141,0,0,0,0,0,0,783,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1498,0,0,0,0,343,430,803,1183,677,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1357,53,0,0,0,0,590,0,0,0,0,0,0,0,0,0,0,
+0,0,0,329,0,0,0,0,0,0,0,469,0,0,0,0,0,0,0,0,0,0,460,0,0,1743,0,0,963,340,0,0,0,
+0,0,1603,0,0,250,0,0,0,0,0,646,218,0,1794,0,0,0,571,0,455,0,0,0,1012,0,0,0,0,0,
+0,0,0,0,0,0,0,597,161,0,349,0,524,0,0,0,0,0,0,0,0,0,0,0,0,322,432,0,0,0,0,0,0,
+325,223,0,0,0,0,0,566,0,0,0,1394,481,436,0,48,457,610,756,618,0,0,0,755,0,1217,
+0,0,0,0,0,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,492,107,414,0,0,0,0,0,0,0,0,0,0,0,
+1007,0,0,0,0,5,0,0,1580,0,0,0,0,0,0,0,0,0,0,0,0,0,673,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1843,0,0,0,0,0,0,0,0,0,165,0,0,0,0,0,0,809,885,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,498,0,0,0,306,9,0,0,0,0,0,0,0,437,721,146,0,0,0,0,0,0,0,0,0,0,0,177,0,0,0,0,
+0,0,0,1377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,959,0,0,0,1928,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1435,0,481,0,0,0,0,0,0,142,84,0,0,0,0,0,
+1015,0,0,0,315,0,0,0,0,0,0,759,0,0,0,0,0,0,0,0,712,0,0,0,1722,0,0,0,0,0,0,0,0,0,
+0,0,0,222,0,985,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1273,
+538,706,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,0,0,0,0,1781,0,0,0,0,0,431,97,665,42,
+237,0,0,0,264,0,0,213,0,0,0,0,0,0,0,455,0,0,0,906,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+624,0,574,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,
+235,723,1813,0,0,0,957,0,830,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,496,0,0,0,0,0,0,0,
+547,239,88,0,0,0,0,0,0,0,0,0,1310,0,0,0,0,0,0,0,0,80,1076,0,0,118,0,0,0,479,274,
+0,0,0,0,0,0,0,0,0,0,0,497,0,0,669,261,0,0,0,0,13,0,0,0,0,0,0,791,250,642,0,0,0,
+1429,939,949,0,0,0,0,0,0,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,982,330,0,0,0,0,545,0,0,0,0,0,0,947,0,1188,0,0,0,0,0,904,0,0,0,0,0,1372,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,693,377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,0,0,
+713,386,0,0,0,0,128,1575,0,0,0,0,0,0,424,893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,904,0,0,0,0,0,552,322,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,1808,49,0,0,0,0,
+1832,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,421,0,0,442,415,0,0,289,
+0,0,0,0,0,206,110,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+19,1539,0,0,0,0,0,1340,0,1194,0,0,0,0,0,0,0,0,549,0,0,0,0,0,0,0,0,1720,0,0,0,0,
+0,0,0,0,0,319,0,0,0,0,112,1180,0,0,0,0,0,0,0,0,0,0,0,967,0,0,0,0,0,0,0,0,0,1940,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,735,0,0,0,0,0,0,0,0,0,897,132,0,0,0,0,0,0,0,
+0,0,0,38,838,0,0,0,379,218,8,660,1017,0,0,0,0,0,0,111,387,647,877,0,0,53,790,0,
+0,0,0,0,0,0,0,458,0,0,0,0,0,0,954,0,0,0,394,0,1367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,882,0,0,0,0,0,0,0,1409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,124,342,199,0,0,0,0,
+0,0,0,0,0,0,724,628,0,0,0,0,804,266,0,0,0,0,0,208,0,79,0,0,0,0,0,0,0,0,741,0,0,
+0,0,0,0,0,0,0,0,606,0,1494,821,1553,0,0,135,405,0,0,178,100,0,0,0,0,0,0,0,0,0,0,
+0,0,0,481,0,0,0,1378,0,0,0,0,0,0,0,0,0,0,0,0,0,791,33,1227,857,0,467,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,447,0,0,0,0,0,0,86,128,0,0,0,0,0,0,587,0,0,0,692,1018,0,
+195,0,0,0,0,0,0,0,1546,0,0,0,0,0,0,0,0,0,0,0,684,0,0,345,0,0,0,0,0,0,365,0,1683,
+0,0,472,0,433,0,0,0,0,0,0,0,28,0,0,0,997,0,705,3,0,0,0,0,0,0,0,0,0,229,0,0,0,0,
+102,0,0,0,0,866,1022,0,0,0,0,0,0,0,0,0,55,0,115,0,0,0,0,933,0,0,0,0,0,0,0,702,0,
+0,0,0,0,0,0,1728,26,484,0,0,0,185,618,417,0,803,0,0,0,0,0,0,0,0,0,0,0,1262,0,0,
+0,0,0,0,0,0,0,0,0,0,0,633,0,0,0,0,0,0,0,0,0,0,0,0,0,479,262,0,0,0,0,0,0,830,0,0,
+0,0,26,70,0,0,0,0,0,0,0,0,217,0,640,51,0,0,360,1586,0,0,0,0,0,652,0,0,0,0,0,766,
+0,0,0,0,298,737,0,0,0,0,0,0,0,0,0,0,655,222,906,0,0,1013,991,2009,0,0,0,0,503,0,
+0,0,216,154,0,0,0,716,0,844,0,0,0,0,621,252,0,0,0,0,748,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,103,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,648,0,0,0,331,0,0,0,
+0,0,0,0,0,0,0,0,0,632,0,0,0,518,107,0,0,0,0,0,0,0,0,851,0,0,0,0,504,0,0,0,0,0,0,
+0,0,0,0,0,0,7,883,0,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,91,993,0,0,0,0,0,0,200,131,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,365,1433,0,0,0,0,28,103,0,0,798,1013,0,0,0,0,0,0,0,
+0,39,1925,0,853,0,0,271,519,0,0,0,0,338,0,0,300,470,419,0,0,0,0,0,0,836,0,0,0,0,
+0,0,1937,0,0,0,0,0,393,0,0,357,0,0,0,0,0,703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,387,0,0,0,0,0,0,75,708,453,1351,0,303,0,0,772,0,0,0,0,0,0,0,0,749,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1065,0,0,717,226,0,0,0,0,0,890,431,626,0,0,0,0,706,0,0,0,
+51,698,0,0,0,0,0,0,0,0,0,0,0,828,0,0,17,0,0,0,0,1929,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,871,498,0,101,1793,0,0,0,0,0,0,435,0,
+0,0,0,0,966,0,129,1644,0,0,0,0,0,0,0,0,0,0,0,0,0,997,502,0,0,0,0,0,0,0,0,0,0,0,
+0,823,0,1927,0,0,0,0,98,1756,0,0,0,0,0,0,0,0,0,0,0,0,8,0,160,1046,0,492,0,0,0,0,
+0,0,129,45,0,0,0,0,0,0,353,558,0,0,0,0,0,785,0,0,0,1145,189,0,0,0,26,353,0,0,0,
+0,0,2024,0,0,0,606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,855,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2011,0,0,5,4,0,0,461,764,0,0,0,1449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1445,0,0,
+0,1168,0,0,0,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,216,0,0,0,286,0,0,0,
+3,0,0,0,723,536,0,0,0,0,0,285,0,0,0,560,0,0,0,0,0,690,0,0,0,0,0,1246,0,0,63,0,
+33,0,0,0,0,0,520,1862,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,0,0,554,0,0,0,0,0,1001,0,
+0,0,0,0,446,0,0,0,0,0,0,0,1313,0,0,837,636,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278,
+0,0,0,0,0,0,0,0,868,0,0,0,0,1010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1231,0,304,0,506,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,93,1408,794,
+843,704,0,285,114,485,898,145,0,19,2035,0,0,0,1933,0,0,0,0,0,0,0,1728,0,0,0,0,0,
+0,0,0,746,0,0,0,0,0,0,0,995,1964,0,0,0,0,0,0,0,0,0,0,0,1550,0,874,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1018,0,0,0,814,126,0,0,1264,0,0,814,955,0,0,0,0,0,0,
+0,981,0,0,0,0,0,0,0,0,915,56,0,0,100,0,0,0,0,0,0,0,0,0,638,0,0,0,0,738,0,0,0,0,
+0,0,0,0,0,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1112,0,0,214,0,0,0,133,0,196,
+168,0,0,0,0,0,1152,0,1245,0,0,538,169,871,1816,0,0,413,133,0,0,0,978,0,0,43,93,
+371,0,0,0,0,0,0,526,25,0,754,335,0,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0,39,601,0,0,0,
+0,0,0,0,181,370,0,0,1652,358,0,0,0,0,0,0,0,0,0,176,286,0,788,0,0,0,0,0,1223,780,
+254,1003,896,0,0,0,1447,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,126,0,
+41,788,0,0,0,629,0,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,420,37,1900,0,0,0,0,542,1570,957,0,0,0,0,0,0,
+0,373,31,0,0,0,0,125,325,0,0,0,0,0,0,323,0,0,1547,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1216,0,0,0,0,0,0,198,1905,629,15,0,0,0,0,0,0,20,75,543,1353,0,0,0,533,0,0,6,0,0,
+0,0,0,0,538,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,11,0,0,0,284,659,0,989,0,0,0,0,0,
+0,0,0,0,848,0,0,507,0,0,0,0,0,0,0,0,188,991,884,0,0,0,0,60,959,0,0,0,0,0,1653,0,
+0,922,337,0,638,0,0,500,0,0,0,0,0,0,0,0,0,0,0,166,0,0,0,0,0,0,0,0,0,0,0,0,418,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,760,0,0,0,0,0,0,1277,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,243,89,0,0,0,0,0,0,0,0,0,1396,0,
+560,0,0,3,1658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,586,0,0,1271,0,0,0,505,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1947,
+41,445,0,0,0,0,0,0,0,0,57,189,0,0,371,0,0,0,0,552,0,883,0,923,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,875,0,0,0,1788,49,0,0,0,0,0,
+0,0,0,0,0,0,661,0,0,1945,0,0,0,0,0,794,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1135,0,0,0,745,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,410,0,976,0,0,0,0,0,703,0,0,
+0,0,0,0,187,322,0,0,0,227,0,0,0,0,560,0,31,1395,0,0,0,0,0,466,0,0,0,0,643,167,0,
+0,0,1428,0,412,0,0,0,0,0,0,0,0,0,1118,562,0,0,0,0,0,256,0,0,0,0,0,0,1771,0,0,0,
+0,0,1190,132,0,66,0,0,0,0,0,0,0,0,0,0,317,0,0,0,63,0,0,0,0,0,0,0,1475,0,0,0,0,0,
+0,0,288,0,0,0,0,608,0,0,0,0,0,0,0,0,1225,0,1189,0,0,0,0,0,0,0,1468,0,0,0,0,0,
+689,120,0,0,0,0,0,0,0,1,0,329,0,0,0,0,226,0,0,0,0,0,1855,0,0,461,0,0,0,0,1346,0,
+0,0,0,0,85,0,0,299,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1171,0,0,
+0,980,0,0,0,0,0,0,0,0,637,279,0,0,0,0,0,293,0,0,0,0,528,17,0,0,0,0,5,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,0,0,0,0,601,0,0,0,0,0,0,779,0,
+196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1322,737,752,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,412,192,80,0,0,8,1470,0,0,0,0,0,0,0,0,0,873,0,0,0,0,0,835,0,0,0,0,256,
+38,986,0,0,0,0,0,0,0,0,0,91,257,278,911,0,0,0,0,0,0,0,0,749,151,0,0,0,0,0,0,0,0,
+0,0,0,0,989,0,0,990,0,0,90,194,0,0,0,0,0,425,0,0,0,0,0,774,0,0,0,0,0,0,0,0,0,0,
+646,827,752,0,0,0,662,0,22,21,0,0,0,0,0,0,95,239,0,0,0,431,0,0,0,0,0,874,0,0,
+265,65,0,0,0,1350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1887,0,0,0,0,0,0,0,809,
+0,696,0,1074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,802,0,0,0,56,776,0,
+970,0,0,797,0,0,0,0,0,400,0,0,1951,0,0,41,0,11,118,0,0,0,0,0,0,0,0,251,615,0,0,
+0,1044,0,0,0,0,0,0,0,0,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,0,0,0,0,
+104,48,209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,930,0,0,0,0,
+0,0,0,0,0,0,0,1286,0,759,0,120,385,0,0,0,429,0,0,0,0,0,0,0,0,820,0,0,0,0,0,0,
+199,0,10,151,0,0,0,761,365,0,0,0,0,0,0,0,0,0,46,1086,0,0,0,0,11,1624,58,344,0,0,
+1008,1868,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,914,1913,0,958,0,885,0,0,0,0,0,0,0,0,0,0,0,
+0,0,847,276,0,302,65,0,0,0,510,0,1514,0,0,0,0,0,0,152,291,0,0,0,0,0,0,0,0,0,0,0,
+0,282,589,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,463,42,0,0,0,0,0,372,0,0,0,0,0,0,0,
+0,0,680,0,0,0,0,0,0,0,0,977,1997,0,0,0,810,0,0,0,0,0,0,0,0,0,1390,0,0,0,644,0,0,
+867,982,0,0,0,0,0,0,0,540,0,123,0,0,0,1978,0,0,0,0,789,623,0,1723,0,1220,0,0,0,
+0,0,0,0,480,0,0,0,0,0,0,0,0,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,299,1995,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,788,179,0,0,0,0,0,0,431,156,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1373,39,80,196,0,0,507,0,0,0,646,0,0,0,0,
+0,1214,0,0,0,0,926,0,0,0,1,114,0,0,0,0,0,446,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,490,0,0,0,491,0,1584,0,0,507,250,0,0,0,158,
+10,362,1,0,0,0,0,0,0,0,0,0,408,228,860,480,0,779,0,0,0,557,0,0,142,197,0,0,0,0,
+0,0,0,0,0,0,0,1490,11,378,316,1057,0,0,18,579,299,1546,0,177,0,0,0,0,0,0,0,0,0,
+411,0,0,0,0,727,439,0,0,0,0,0,1528,0,0,0,0,0,0,58,0,482,0,0,0,505,1952,0,0,0,0,
+0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,953,0,0,0,0,802,0,0,0,0,0,0,0,0,0,0,290,0,0,791,
+52,0,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,1028,0,0,138,0,0,0,0,1811,0,0,0,0,0,0,
+934,1821,0,0,0,0,371,38,0,0,0,1296,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,723,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1330,0,0,0,0,0,0,0,1255,296,109,0,0,0,0,0,660,0,0,0,0,270,591,0,
+0,0,0,0,0,0,1090,81,0,0,0,0,391,0,0,0,0,249,322,0,0,0,0,0,0,0,1412,0,0,0,0,0,0,
+0,0,0,0,526,632,0,0,0,0,0,0,235,144,0,0,0,0,0,940,0,0,0,52,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,309,196,0,0,0,0,0,1912,0,1290,0,686,0,0,625,0,0,0,0,0,0,0,0,0,0,0,412,0,
+0,0,0,43,0,0,0,0,11,967,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,
+873,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,890,0,0,2,0,0,0,0,0,0,0,0,1774,
+393,263,0,0,0,0,0,0,818,456,0,0,251,178,393,97,0,0,0,0,0,674,168,0,0,0,0,0,0,0,
+159,1639,0,0,0,0,0,0,0,0,59,934,0,191,0,0,0,0,346,165,0,877,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,128,0,0,0,0,0,0,1297,0,0,0,0,0,0,164,0,0,0,15,132,241,1073,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,324,53,0,0,910,0,0,0,0,0,0,0,0,734,705,
+217,73,0,0,0,0,0,0,0,0,636,389,0,1409,0,0,0,0,0,893,0,0,0,0,21,0,0,0,0,0,0,0,0,
+0,0,0,0,0,721,0,0,0,959,0,0,0,0,1433,0,0,0,0,0,0,0,0,0,0,0,0,174,189,0,0,0,0,0,
+0,0,0,0,0,22,2,0,0,815,354,0,0,0,0,425,0,411,60,13,1611,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1478,596,0,0,398,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,1159,0,0,0,0,0,
+592,223,0,0,0,0,0,0,0,245,64,0,0,0,0,278,0,604,0,0,1502,265,0,0,0,0,0,0,0,310,
+1763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,1356,0,0,0,0,0,0,0,
+0,505,0,0,0,0,0,0,0,1000,0,0,966,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,
+0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,0,0,0,0,280,0,0,0,1386,0,0,0,
+281,0,1064,0,0,0,0,0,917,0,0,15,555,0,0,1014,1883,0,0,0,965,0,0,117,33,0,0,0,
+801,0,0,0,0,0,877,0,824,0,0,0,0,0,0,0,0,0,0,0,365,0,0,0,0,0,0,774,7,0,430,0,0,
+231,360,0,0,0,0,0,0,0,0,822,740,0,0,929,1485,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,852,0,0,0,0,17,0,0,0,0,0,0,1001,0,0,0,0,35,831,0,0,384,457,0,0,0,1351,0,27,
+0,0,984,0,264,552,0,401,0,0,0,710,0,1211,0,0,11,205,0,0,0,0,0,0,0,0,0,0,0,0,5,
+579,0,717,0,0,1011,0,0,0,0,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,0,0,489,0,
+0,0,1024,0,0,0,0,0,0,0,0,0,892,0,0,0,0,0,0,0,0,0,0,0,0,473,0,0,0,659,864,0,0,0,
+0,0,0,152,819,0,51,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,229,0,0,0,0,674,0,0,0,0,0,
+0,0,0,0,770,52,79,0,0,0,1666,0,409,0,0,0,0,0,0,0,195,0,688,0,0,0,0,0,0,0,0,0,0,
+0,889,174,160,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,918,569,268,0,0,0,1224,0,1361,0,0,
+0,0,0,0,0,0,0,374,0,0,0,0,0,731,0,0,0,0,190,0,0,0,0,0,0,0,202,506,444,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,835,0,17,1526,0,0,0,0,0,477,0,0,
+994,1374,76,0,0,0,0,0,0,0,355,287,0,1389,0,0,0,0,0,0,455,384,0,0,0,264,0,0,0,0,
+0,0,0,0,0,0,0,0,1001,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,851,175,359,0,0,0,0,0,0,0,
+0,287,740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+819,1402,0,0,0,0,0,0,174,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1649,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,655,573,0,0,0,0,0,0,0,0,128,351,0,0,0,0,0,0,
+0,0,0,0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,687,0,0,0,0,0,0,0,0,0,1525,
+0,0,0,1009,0,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,861,0,176,0,0,0,0,0,0,0,0,0,96,
+985,0,615,0,0,0,0,0,0,0,1919,0,0,0,0,0,1131,0,0,0,0,0,0,0,247,0,0,0,0,27,23,0,0,
+0,0,0,0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,1088,0,0,
+0,0,0,1585,0,0,0,0,227,0,0,0,478,360,0,0,0,95,0,0,0,0,0,0,699,0,0,0,26,0,0,0,0,
+1119,0,0,0,739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,741,67,0,0,0,0,0,0,464,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,0,96,0,0,0,26,342,0,0,0,0,0,0,203,0,0,449,0,
+0,0,0,0,0,0,0,0,0,256,311,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0,827,0,0,0,0,581,64,0,
+1047,0,0,0,0,0,288,0,0,0,0,0,1375,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,
+376,12,0,0,0,0,0,154,0,1520,0,1753,95,502,0,0,0,0,0,0,0,269,291,1197,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,1341,0,1017,0,0,0,0,0,0,0,
+0,857,1810,533,0,0,1453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,211,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,19,0,156,0,0,0,0,1009,0,0,0,0,0,0,0,0,0,0,0,0,0,820,0,0,
+0,0,0,0,0,0,0,228,0,0,0,1131,0,1276,0,0,0,0,0,0,0,0,0,0,0,0,849,1792,0,0,389,
+291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,525,0,0,
+0,453,0,0,0,0,666,0,0,0,422,0,355,0,0,0,0,165,0,260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,865,0,0,0,0,0,0,0,1625,0,0,0,234,0,1383,0,0,0,0,0,0,0,0,306,0,0,0,802,1921,
+0,0,0,0,0,0,180,0,0,0,0,1312,814,0,0,0,0,0,0,0,0,0,0,707,0,0,0,1493,11,61,733,0,
+0,0,341,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,1014,0,0,0,0,0,0,0,142,102,0,0,30,0,0,
+823,0,1045,0,0,0,1930,0,1512,0,0,0,0,0,0,0,87,0,1243,245,0,0,0,0,0,0,0,48,68,0,
+0,0,0,0,0,0,0,126,77,625,938,0,0,351,0,0,0,174,1668,0,707,0,0,0,0,0,0,0,0,0,0,0,
+403,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,282,0,0,0,0,0,0,8,44,0,0,363,115,0,0,0,0,0,0,
+0,0,0,0,0,0,545,761,0,0,835,1254,0,0,0,0,930,1936,0,0,0,0,0,0,0,0,653,0,0,0,0,0,
+344,0,0,1483,673,185,0,0,460,93,753,478,0,0,0,0,0,1020,0,0,0,0,0,0,0,103,0,0,0,
+499,0,0,0,0,0,0,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,968,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,3,0,0,0,0,399,0,0,0,0,224,563,0,0,0,0,0,704,0,0,0,0,0,0,0,0,0,0,0,
+1559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,861,0,0,0,0,946,333,746,0,0,0,0,0,
+0,0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1514,0,0,0,0,201,0,510,717,0,0,528,0,0,0,0,
+20,0,0,0,1251,0,0,0,1163,0,0,0,307,0,0,0,0,0,1091,0,0,0,0,0,0,0,0,0,0,0,429,0,0,
+0,881,0,0,0,0,0,621,0,0,0,0,0,0,0,736,0,348,0,868,0,0,0,0,433,0,0,0,771,1495,0,
+0,0,0,215,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,112,62,0,856,270,
+0,572,0,0,0,0,939,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,0,647,0,0,0,0,10,0,0,0,0,0,
+0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,464,0,0,109,0,0,0,1746,0,0,0,515,0,0,0,566,0,
+0,0,0,0,0,67,40,0,0,722,992,0,0,923,0,0,0,0,0,0,1145,0,0,0,0,0,0,0,0,0,0,0,568,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,0,0,0,0,645,0,0,328,0,0,0,0,0,0,0,0,0,0,0,0,
+1363,0,0,0,0,0,1280,0,0,0,0,0,0,0,0,0,0,7,28,360,162,0,0,0,0,0,0,0,0,0,0,0,764,
+0,0,833,862,0,856,0,0,0,0,0,0,736,92,0,0,948,1944,0,1479,63,590,0,0,0,1521,0,0,
+0,709,0,0,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,1213,
+0,0,0,0,29,1022,0,1712,0,466,0,0,0,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,171,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,964,2005,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1100,0,0,0,954,0,0,0,0,0,0,0,0,0,1958,0,0,34,549,994,0,0,449,
+137,850,0,0,670,146,0,0,0,0,518,159,0,0,0,0,0,0,0,0,151,0,0,1027,0,0,0,0,0,0,0,
+0,0,0,983,0,0,0,0,993,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,501,0,0,0,
+0,0,0,0,0,0,452,0,0,0,0,0,0,0,0,0,0,233,149,0,0,0,0,0,0,0,0,582,0,0,0,801,0,0,0,
+0,0,0,70,0,0,369,0,36,0,0,0,0,0,0,0,204,721,430,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1817,16,1078,1021,0,0,
+406,0,0,0,0,0,69,0,0,0,0,0,1830,0,0,0,824,0,0,0,0,0,0,0,0,0,826,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,717,1845,0,423,0,0,
+0,0,0,0,0,0,510,0,0,1048,0,0,0,618,0,0,0,520,0,0,0,0,990,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,321,0,0,0,0,0,0,0,1135,0,0,921,0,0,0,24,397,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,856,0,0,0,139,282,981,0,288,0,0,0,1890,651,56,0,0,0,0,0,0,0,
+0,261,0,0,0,0,0,0,0,0,0,0,0,617,1403,0,1205,0,0,563,0,0,0,0,0,0,0,0,333,0,0,0,0,
+0,369,0,0,0,0,0,0,0,0,0,622,0,0,0,1407,0,0,0,0,0,0,0,0,0,0,0,0,624,160,0,363,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,619,0,174,292,0,0,656,616,0,0,0,685,0,0,0,0,0,0,0,0,0,0,0,0,0,647,0,0,0,631,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1267,0,0,0,1797,0,0,0,1684,0,0,469,0,531,
+1230,73,0,0,0,0,0,0,0,0,0,268,0,0,0,0,0,102,558,109,65,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,595,0,0,0,0,0,374,1832,0,0,0,0,0,0,16,0,405,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,881,0,1495,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,21,466,23,
+257,0,0,0,0,0,0,77,404,0,0,0,0,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,860,
+1848,0,0,652,629,0,0,0,0,13,377,0,1842,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1501,0,
+0,0,1906,0,0,0,0,0,0,0,0,0,0,0,0,0,491,234,171,0,0,0,0,631,1186,0,0,0,0,0,0,0,0,
+0,0,0,0,931,0,170,0,0,0,0,0,0,0,0,0,0,1587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+765,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,424,0,0,714,0,0,0,0,685,0,0,0,0,0,
+0,285,0,0,0,0,0,0,429,0,0,0,0,0,0,0,0,0,0,71,18,0,0,0,0,0,0,0,0,0,0,116,828,0,0,
+0,0,0,0,289,0,0,0,0,0,0,0,0,675,0,0,0,1424,0,0,0,0,0,647,0,0,0,1334,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,36,209,0,0,0,0,0,0,0,342,0,0,0,928,0,0,0,0,0,1838,118,856,654,
+318,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,915,895,454,0,0,513,1425,0,0,
+0,0,0,0,791,0,153,0,0,0,0,0,0,796,909,445,345,0,0,0,0,0,0,0,0,578,0,0,0,1387,0,
+0,0,555,0,0,0,0,0,0,766,0,0,0,0,0,0,0,0,0,0,541,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,
+0,0,0,0,1506,0,0,983,0,768,0,0,0,0,584,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,737,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,30,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,462,0,0,0,385,0,398,0,0,0,0,0,0,
+0,0,0,347,0,0,0,0,125,1259,644,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,469,0,0,0,0,0,
+1367,0,0,0,0,0,0,0,0,0,0,0,719,0,0,0,0,0,0,0,0,0,0,0,0,0,1423,0,0,0,0,0,0,0,0,0,
+749,0,0,0,0,546,645,0,0,0,0,0,0,277,0,0,1275,0,0,0,0,0,0,0,453,536,555,0,0,987,
+1107,0,0,90,0,0,0,0,0,0,0,0,860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+257,0,1768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1071,0,0,0,0,0,0,0,0,0,0,0,0,0,83,
+0,835,0,0,0,0,0,0,0,2006,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,696,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,95,1718,0,0,0,0,0,0,0,26,0,550,0,0,0,0,0,901,0,0,0,0,0,
+0,822,0,0,122,0,0,0,807,0,0,0,0,0,262,0,620,601,34,0,0,170,0,0,0,0,537,0,0,0,0,
+0,0,0,0,0,332,0,0,208,1909,182,261,0,0,0,1721,0,0,0,0,0,933,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1609,0,895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,812,0,0,942,1916,0,0,0,0,
+0,0,0,778,0,0,0,137,0,1314,0,0,0,0,0,0,0,1661,0,0,0,0,0,0,0,1591,0,0,0,0,0,0,
+820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,89,0,1160,230,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,63,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1740,0,0,177,
+170,0,1961,0,0,0,0,0,0,0,0,0,0,0,0,91,0,17,44,0,0,0,0,0,0,0,0,0,270,0,296,0,0,0,
+0,0,0,0,1523,0,0,0,0,0,0,0,0,0,0,757,7,0,0,0,0,0,0,0,0,0,0,530,588,0,0,0,0,0,0,
+0,0,0,786,0,0,0,0,0,580,627,88,447,57,0,0,0,0,0,0,0,0,845,735,0,0,0,0,0,31,15,0,
+460,521,12,424,0,0,0,1302,0,0,0,0,0,0,0,595,0,0,0,13,548,97,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1472,452,1767,0,0,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,1543,0,1111,0,0,0,0,
+1,0,359,488,0,267,0,0,0,1983,0,0,0,0,0,0,0,1155,0,1575,0,1438,31,0,0,377,101,0,
+0,0,0,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,0,0,0,2023,0,0,0,0,0,1836,0,0,0,0,35,843,
+0,0,0,0,0,0,0,554,0,0,0,536,625,207,0,1371,0,0,0,424,785,336,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,896,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,750,0,0,0,0,238,0,0,
+0,0,0,383,0,0,0,0,0,0,0,0,603,725,11,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,1552,0,0,0,
+0,0,0,0,680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,435,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1431,0,0,13,112,0,0,356,0,0,0,0,0,0,0,0,0,0,1963,0,0,0,1244,18,0,0,0,0,0,0,867,
+0,0,0,0,0,0,50,708,73,592,0,502,0,0,0,0,0,0,161,347,0,0,0,0,470,33,0,246,571,10,
+0,465,614,0,237,0,0,0,0,0,24,18,0,506,0,0,0,0,0,0,33,309,0,0,0,0,0,0,0,0,0,0,
+140,0,0,0,0,1056,0,0,0,1704,0,0,0,0,0,0,0,1036,0,0,0,0,0,0,0,0,0,1315,432,86,
+264,524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,0,0,0,123,927,0,0,957,1149,0,0,
+0,0,0,778,0,502,196,0,0,0,0,1312,0,0,0,0,0,0,0,855,0,0,0,0,0,0,0,0,0,0,45,1400,
+0,0,0,1003,0,0,0,0,0,1097,0,0,0,0,0,0,0,0,545,612,0,0,0,0,0,0,0,0,0,0,0,0,54,0,
+0,0,0,172,0,0,0,1029,0,0,0,0,0,0,0,0,0,568,0,0,0,732,617,0,0,974,94,989,733,0,0,
+0,0,0,0,1789,0,0,665,2015,0,0,0,0,0,0,806,287,0,0,0,0,0,1539,0,0,0,0,0,0,0,0,0,
+0,182,1563,0,0,0,0,0,0,0,0,0,484,0,0,0,0,0,1623,0,0,0,0,0,0,0,0,878,1833,0,1569,
+0,0,0,0,0,0,0,0,93,0,715,994,0,0,0,0,0,63,0,591,0,0,0,0,0,0,0,749,0,0,0,0,547,
+366,0,0,0,1747,0,0,0,0,0,0,0,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1463,0,772,
+893,0,0,0,48,0,0,941,0,0,690,1785,106,440,0,0,0,0,0,0,0,0,0,0,32,0,332,216,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,852,0,
+0,416,564,0,918,0,1764,0,0,3,0,0,274,0,0,0,0,501,0,0,0,0,0,0,0,851,743,0,49,0,
+879,0,0,47,0,0,0,0,0,0,865,0,1202,0,0,0,0,0,0,47,272,0,0,0,0,0,0,0,0,0,0,0,1455,
+0,0,0,0,891,1911,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,761,0,0,0,0,0,0,0,0,0,407,0,
+183,0,0,490,0,0,0,0,0,0,0,35,731,0,0,0,0,0,0,0,819,0,0,0,0,0,0,0,0,0,0,0,0,0,
+575,0,0,0,0,45,818,0,0,77,222,0,0,0,0,849,1880,0,0,0,633,0,1308,0,0,0,0,0,0,0,0,
+0,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,817,0,0,0,0,0,0,0,0,0,882,0,0,0,914,0,0,0,0,
+0,0,0,0,0,0,865,0,0,426,399,58,0,0,0,0,0,0,538,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,566,0,63,12,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,114,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,0,0,933,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,692,0,0,0,0,0,0,0,0,0,0,0,0,752,0,0,0,0,
+0,0,0,0,375,0,1011,0,0,96,0,0,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,337,56,
+666,0,246,394,0,0,0,0,0,0,0,0,437,0,0,0,506,0,0,0,0,1003,0,1163,0,328,0,0,0,0,0,
+0,0,0,1000,0,0,0,0,0,744,101,0,0,0,0,0,726,0,0,176,0,146,9,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,246,1931,29,0,0,1771,0,0,0,0,0,846,6,157,0,0,0,0,0,0,0,0,0,875,0,0,477,
+773,177,639,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1747,0,0,0,0,158,873,0,659,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,391,0,0,0,0,0,0,0,0,0,0,0,0,668,883,0,78,628,0,0,0,
+0,0,0,0,0,0,0,0,0,1460,0,962,0,0,0,0,0,460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,199,0,
+0,0,388,474,0,271,0,333,608,0,0,0,0,0,0,49,0,988,0,707,617,0,0,0,0,0,0,0,756,0,
+0,0,0,0,1583,0,0,0,0,0,0,0,0,0,0,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,344,0,0,0,0,0,
+0,0,0,515,1709,0,0,0,0,0,0,0,0,404,0,0,0,0,500,0,0,0,0,0,0,0,0,0,68,216,0,0,0,0,
+0,0,0,488,353,0,0,177,236,0,0,458,490,0,0,0,0,0,0,756,1504,0,757,0,1735,0,0,108,
+598,0,0,0,0};
+BROTLI_INTERNAL const uint8_t kStaticDictionaryHashLengths[32768] = {
+8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,4,22,5,0,
+4,0,0,0,0,0,0,0,0,0,0,0,0,14,6,0,0,0,5,0,0,0,0,0,0,0,7,13,0,0,4,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,8,0,0,0,0,0,0,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,4,0,5,13,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,9,0,8,0,0,0,0,0,0,6,0,
+0,9,0,0,0,11,0,0,6,8,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,6,8,0,0,0,0,0,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,8,4,13,7,0,0,0,0,0,
+7,0,5,0,0,0,0,8,5,0,5,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,8,0,0,0,10,4,0,5,0,4,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,8,7,0,4,9,4,0,0,0,0,0,0,
+9,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,7,18,0,0,0,0,4,9,0,0,4,0,6,0,0,0,6,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,0,0,
+0,9,0,0,0,0,0,0,0,8,6,10,6,0,0,0,4,0,6,8,6,0,0,0,4,0,0,0,0,0,5,0,0,0,6,0,0,0,0,
+10,0,12,7,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,7,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,6,10,0,17,0,8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,6,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+7,0,0,11,4,0,5,0,0,0,0,0,0,0,0,0,0,10,5,0,6,8,5,0,0,0,0,0,0,0,0,0,0,11,5,0,0,0,
+0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,0,0,0,0,
+0,0,0,0,0,0,5,0,0,0,6,0,0,10,0,0,0,20,0,0,0,0,0,0,0,0,6,9,5,0,0,0,0,10,4,8,0,0,
+4,13,0,0,0,0,0,0,0,9,0,9,0,0,0,0,0,0,0,0,0,0,0,0,4,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,12,5,0,0,10,4,10,7,13,
+0,0,0,0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,19,0,0,4,12,6,9,0,0,0,0,4,0,4,11,0,0,0,0,
+0,0,0,12,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,5,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,9,6,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,5,0,0,0,0,14,4,0,0,0,4,12,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,
+0,0,0,0,0,12,0,9,6,0,0,0,0,13,0,0,5,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,13,0,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,8,7,8,4,0,0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,0,4,0,
+0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,8,4,0,0,0,0,0,6,0,7,0,
+0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,0,9,5,0,0,
+0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,4,0,0,0,0,0,0,0,4,
+12,5,11,0,0,0,0,0,0,0,0,0,8,7,0,5,0,0,8,7,0,5,0,0,0,0,8,0,0,0,0,7,0,4,10,0,0,0,
+0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+13,5,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,14,5,0,0,0,7,0,0,10,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,4,0,5,0,0,0,0,8,5,0,0,0,0,0,0,9,5,9,0,0,0,0,0,0,0,0,6,9,0,
+0,4,0,0,0,7,0,0,0,6,0,0,10,4,0,0,0,0,0,6,0,0,10,0,0,0,8,5,0,0,0,0,0,0,0,0,10,0,
+0,0,0,0,18,4,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,7,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,
+0,4,8,7,0,0,8,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,
+0,0,0,8,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,8,7,0,0,0,0,8,0,12,6,0,6,0,0,0,0,9,7,11,7,0,0,0,
+0,0,0,0,0,0,0,0,0,11,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,6,0,0,0,7,0,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,14,0,0,0,0,0,8,4,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,20,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,5,0,7,0,5,0,0,10,0,0,7,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,6,0,4,9,7,0,0,0,
+0,0,7,0,0,0,0,0,0,10,0,9,0,9,0,0,0,0,0,0,0,0,4,9,0,0,0,0,6,0,0,0,0,0,0,0,0,11,4,
+0,6,0,0,0,0,0,0,8,0,8,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,13,6,0,0,11,
+0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,6,18,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,11,
+4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,0,8,
+6,0,0,0,0,0,0,9,6,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,
+0,6,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,6,0,0,10,6,0,0,0,7,0,0,8,0,8,7,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,12,0,12,0,0,0,11,6,0,5,0,0,12,0,12,5,0,7,11,6,0,0,11,
+0,0,0,12,0,0,4,12,7,8,6,0,0,0,0,8,5,0,0,0,0,0,0,0,4,11,0,0,6,0,7,0,0,0,0,0,0,0,
+5,0,6,0,0,0,0,8,0,10,0,0,0,0,0,0,0,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,0,10,0,0,5,0,0,12,6,0,0,0,0,0,0,10,6,0,0,0,0,8,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,5,0,0,0,0,11,0,10,6,0,0,8,6,0,0,0,6,0,7,10,6,0,
+0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,10,7,0,0,0,0,
+10,6,0,0,0,0,0,0,8,5,11,0,8,4,0,0,0,4,0,0,0,0,9,4,8,0,0,0,0,0,0,0,11,6,0,0,0,0,
+10,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,7,0,0,11,0,0,
+0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,13,0,8,6,13,0,0,0,11,7,0,7,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,9,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,0,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,
+5,11,5,0,0,0,0,0,0,0,0,0,4,0,7,0,6,0,0,0,6,20,0,0,0,10,7,0,5,14,4,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,
+0,0,6,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,11,6,15,0,0,0,0,0,
+10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,9,7,13,0,0,0,0,0,
+0,7,0,0,8,6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,0,0,0,0,0,0,0,0,0,0,12,6,8,0,12,0,0,7,0,0,0,
+0,0,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+14,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,8,7,10,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,18,6,
+14,7,0,0,0,0,0,0,0,0,11,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,11,7,0,0,10,7,0,0,0,6,8,6,0,0,0,0,0,0,0,6,0,0,
+19,0,0,0,9,5,0,0,0,0,0,0,11,7,0,0,0,7,0,6,0,0,11,0,0,0,0,4,8,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,6,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+0,7,0,0,0,7,15,0,0,5,0,0,0,0,10,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,0,4,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,6,0,0,8,5,14,0,0,4,0,0,0,7,
+17,0,0,0,0,0,0,0,13,5,0,0,0,0,0,5,0,0,0,5,0,0,0,0,16,6,0,4,0,0,0,0,0,0,12,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,5,0,5,0,6,10,0,12,0,0,0,0,0,0,0,0,7,0,0,0,0,8,4,
+0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,0,0,0,8,0,0,6,0,7,0,0,0,5,0,6,0,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,22,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,18,0,0,0,9,4,0,0,8,0,9,7,0,0,0,0,0,0,8,6,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,7,0,0,0,6,0,0,14,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,7,10,4,
+0,6,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,6,0,0,0,0,0,0,
+0,0,11,6,12,7,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,9,6,11,6,0,0,0,0,9,5,0,0,0,0,0,0,
+0,6,8,5,0,0,0,0,8,0,10,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,
+5,10,7,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,8,7,0,0,0,6,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,
+0,0,0,0,0,17,0,0,6,0,6,12,4,19,6,0,0,0,0,16,0,0,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,10,4,0,0,8,7,0,7,0,0,9,
+4,0,6,0,0,0,4,0,5,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,10,0,0,0,0,0,11,7,0,0,
+0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,
+0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,8,7,0,0,
+0,0,0,0,0,6,0,0,0,4,0,0,11,4,0,0,12,7,0,0,0,0,9,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,
+4,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,9,4,0,6,0,0,0,0,0,4,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,7,9,6,0,7,0,
+0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,0,0,10,6,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,4,8,0,0,0,0,0,9,7,0,0,0,0,0,0,
+13,5,0,0,0,0,8,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,5,0,0,11,7,0,0,0,0,0,0,8,6,0,
+0,0,0,0,7,0,4,0,0,0,0,0,0,0,5,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,10,4,9,0,0,0,0,0,
+0,4,0,0,0,0,10,5,10,7,0,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,0,0,0,
+0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,4,0,0,0,7,0,0,0,0,0,0,13,0,0,
+0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,13,7,0,7,0,4,16,0,0,0,0,6,8,7,9,7,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,8,5,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,11,7,0,0,11,
+0,0,0,0,0,9,5,0,4,0,0,0,0,9,7,8,6,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,7,0,0,0,0,0,0,0,0,0,0,0,4,10,6,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,10,7,10,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,6,8,7,12,4,0,0,0,0,0,0,0,5,14,
+0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,20,4,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,
+0,6,15,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,12,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,18,0,0,0,10,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,9,6,0,
+6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,9,0,9,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,9,5,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,8,0,0,0,16,0,0,0,0,0,0,0,
+0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,0,0,11,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,11,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,7,0,6,
+0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,6,0,0,18,0,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,4,0,0,0,
+0,0,0,0,0,0,0,8,0,0,0,0,0,16,0,0,0,0,0,16,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,18,0,0,0,0,0,0,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,4,0,
+0,0,0,0,0,0,0,9,4,0,0,0,0,12,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,5,0,0,10,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,11,0,0,6,0,6,0,0,
+0,7,0,0,0,0,0,0,8,0,0,0,0,6,0,0,0,0,0,0,19,0,0,0,12,0,9,0,0,0,0,0,10,7,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,16,7,12,
+0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,10,5,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,4,0,0,9,0,0,0,8,0,12,4,0,0,0,0,
+0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,
+0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,8,6,0,6,0,0,0,0,0,0,
+0,4,0,0,0,0,0,6,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,10,6,0,0,0,0,8,
+6,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,6,
+10,7,0,0,10,5,11,6,0,0,0,0,0,7,16,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,
+0,0,0,0,0,8,7,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,12,7,0,7,0,0,0,
+0,0,0,0,6,0,0,0,0,9,0,0,0,23,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,4,0,0,11,7,10,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,7,0,0,8,7,8,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,
+0,0,0,0,18,6,8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,0,0,0,9,7,12,6,0,0,0,0,0,0,0,0,
+0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,6,10,0,0,0,9,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,6,
+10,7,0,0,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,
+0,0,0,8,7,8,6,0,0,11,7,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,4,8,7,0,0,0,0,0,0,0,0,
+0,5,0,0,13,0,0,0,0,5,0,0,9,7,0,0,0,0,0,0,0,4,0,0,11,0,0,7,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,12,7,19,0,8,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,0,0,12,0,0,0,0,6,9,6,
+14,0,0,0,0,0,0,6,0,5,0,0,8,7,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,
+7,0,0,10,0,9,7,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,0,0,0,0,5,0,6,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,13,7,
+0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,11,5,0,5,13,0,8,0,
+0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,11,5,
+9,6,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,10,0,0,0,8,5,0,0,9,0,0,0,8,7,9,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,
+0,11,0,13,6,0,0,9,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,5,21,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,5,0,0,0,0,0,0,0,0,10,0,8,0,
+0,6,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,4,0,0,8,6,0,6,0,7,10,0,8,4,0,4,0,0,0,0,0,
+5,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,12,0,0,7,0,0,0,5,0,0,
+0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,24,7,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,12,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,15,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,9,0,9,6,
+0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,4,0,7,0,0,0,0,0,0,0,0,
+22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,7,0,0,21,7,0,7,9,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,23,0,0,0,0,7,0,0,0,
+4,0,0,0,0,0,0,0,0,9,4,11,7,0,5,0,0,0,0,11,0,0,4,20,0,0,0,0,0,0,0,0,0,0,0,11,5,0,
+7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+21,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,11,6,0,0,0,0,0,0,0,0,9,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,
+0,0,0,10,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,11,7,0,0,0,0,0,0,0,4,
+0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,7,0,
+0,0,0,0,0,0,0,0,6,0,0,21,6,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,
+0,0,0,8,7,0,0,11,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,13,7,10,4,0,
+0,0,6,0,0,0,0,0,0,0,0,0,5,10,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,8,4,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,
+0,0,0,0,7,0,0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,5,0,6,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,9,0,11,4,0,0,0,6,0,0,0,5,12,7,0,5,0,0,0,0,0,4,0,0,0,7,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,13,6,10,0,0,0,17,0,0,4,0,0,0,0,0,6,0,4,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,7,0,0,0,7,0,0,0,6,0,0,0,0,0,0,
+0,6,0,4,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,4,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,0,0,
+0,0,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,16,4,0,0,11,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+8,7,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,8,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
+7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,5,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,
+5,18,7,0,0,14,0,0,0,0,0,0,0,9,4,0,7,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,0,0,0,
+8,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,0,0,0,0,0,0,11,0,0,0,
+10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,14,6,0,0,0,0,11,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,10,7,0,6,0,0,9,0,9,5,0,0,0,0,0,
+0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,8,5,0,0,0,0,0,0,0,0,0,0,11,4,0,6,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,12,4,0,6,8,6,0,0,0,0,0,0,0,0,0,0,8,0,0,5,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,13,4,0,7,0,0,0,7,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,
+9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,6,21,5,0,0,0,0,8,0,0,0,0,4,0,
+7,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,
+0,7,9,6,11,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,10,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,19,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,9,4,10,4,0,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,9,7,9,7,10,4,0,7,0,0,0,0,0,0,0,6,12,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,
+0,0,0,0,0,5,0,0,8,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,0,8,0,0,6,0,0,0,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,0,4,8,0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,13,4,0,0,
+12,6,0,6,0,0,0,0,8,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,4,0,0,0,0,0,0,0,0,0,0,9,
+7,22,0,0,0,0,4,0,0,0,0,0,6,0,0,0,4,0,0,9,0,0,6,0,0,24,7,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,10,6,0,5,0,0,0,0,0,0,0,7,0,0,8,0,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,7,0,
+7,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,
+0,0,0,0,0,7,12,0,9,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,4,0,0,0,7,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,0,4,18,0,0,0,0,0,10,0,0,5,0,0,11,0,0,0,0,0,0,5,0,6,0,
+0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,
+0,0,0,5,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,20,7,0,0,0,0,0,0,0,0,0,0,0,4,9,0,12,
+6,8,0,14,7,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,10,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,9,6,0,7,12,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,0,9,0,
+12,6,0,5,0,0,0,6,0,4,0,6,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,
+10,0,0,0,0,0,0,0,8,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,12,6,20,5,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,5,0,0,0,6,13,7,0,0,0,0,15,6,0,0,0,
+6,0,0,13,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
+10,6,0,0,0,0,0,6,0,0,0,0,9,0,0,0,0,0,19,6,0,0,0,0,0,0,0,0,0,0,13,0,11,0,0,0,0,0,
+0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,10,0,0,6,0,0,0,0,8,0,0,
+0,9,0,15,4,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,
+0,0,0,0,0,8,7,0,0,0,0,0,6,10,0,0,0,0,0,0,0,0,7,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,10,5,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,12,0,0,0,10,7,0,5,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,4,9,6,0,0,0,7,0,0,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,0,4,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,6,9,4,0,0,8,4,0,6,
+0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,8,0,0,6,13,4,0,5,8,0,0,0,0,0,0,0,8,0,0,0,10,5,0,0,9,0,0,0,0,0,0,6,0,0,
+24,0,0,0,0,0,0,0,8,0,0,7,0,0,12,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,
+6,8,0,10,0,9,7,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,4,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,8,0,0,
+0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,10,4,0,0,0,0,0,0,0,6,0,0,0,4,20,0,0,7,
+10,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,9,6,0,0,0,0,0,0,0,4,
+12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,9,4,0,5,0,0,
+0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,9,0,0,0,0,7,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,0,9,0,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,17,7,0,0,13,6,14,6,0,0,0,0,
+8,0,0,0,0,0,0,7,12,7,8,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,4,0,0,0,0,0,4,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,4,0,0,10,7,0,0,0,
+0,0,0,10,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,12,0,0,6,
+0,0,0,0,0,0,0,0,8,7,12,0,0,0,0,0,0,6,0,6,0,4,0,0,18,6,0,0,0,6,0,0,0,0,0,6,10,6,
+0,0,0,0,0,0,8,7,14,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,
+0,0,0,8,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,9,4,8,0,0,0,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,
+0,6,0,0,9,7,0,0,0,0,0,5,0,0,0,0,8,7,0,0,14,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,0,0,6,0,0,0,6,0,4,0,0,0,0,0,4,0,0,0,0,12,0,0,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,12,0,16,6,0,0,0,0,0,0,11,7,0,4,8,7,0,0,0,0,0,6,0,0,0,0,16,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,10,7,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,13,4,0,0,10,0,0,0,0,0,0,0,0,0,19,0,0,0,
+0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,
+5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,18,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,14,7,0,0,11,5,0,0,0,5,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,24,6,0,0,
+0,7,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,4,0,0,0,0,8,7,0,0,
+9,6,0,0,14,5,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,5,0,0,
+0,0,12,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,13,7,0,0,0,0,0,0,14,0,11,4,0,
+0,0,4,0,0,0,0,14,5,0,0,0,0,0,5,11,5,0,0,0,0,22,5,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,
+4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,17,0,10,0,0,0,8,0,0,0,19,
+5,18,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,10,6,0,6,0,0,0,0,10,4,0,4,0,
+0,0,0,0,0,14,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,0,9,6,12,0,0,6,0,0,0,0,0,0,0,0,
+12,0,10,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,13,0,9,7,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,8,0,0,0,0,0,
+22,0,0,0,0,0,0,0,23,6,14,0,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,8,5,0,0,0,0,0,0,0,0,0,7,11,6,21,0,0,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,0,4,9,7,0,0,0,0,0,0,12,0,0,0,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,9,
+0,0,0,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,7,0,0,0,0,0,0,0,6,15,0,0,
+0,0,0,0,0,0,0,0,0,0,0,12,4,0,5,0,0,0,0,0,0,11,7,17,6,0,0,0,0,0,0,15,6,0,7,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,5,
+0,0,11,0,11,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,
+17,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,7,9,6,0,0,14,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,
+8,7,0,4,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,
+0,0,0,5,0,4,0,0,8,7,0,6,12,5,0,7,18,7,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+10,0,11,0,0,0,0,0,0,0,0,0,0,0,9,0,0,4,0,6,0,7,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,
+7,0,0,0,0,8,0,0,0,15,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,23,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,12,7,9,7,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,7,0,0,0,
+6,0,6,0,4,0,5,0,0,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,7,10,5,0,0,11,6,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,4,9,7,0,
+0,0,0,11,7,0,0,0,0,0,5,0,0,0,7,0,0,0,0,23,6,11,4,0,0,0,0,0,0,9,0,0,0,10,6,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,10,6,0,0,0,7,0,0,
+0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
+6,11,7,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,6,0,0,0,5,0,6,0,6,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,8,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,4,10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,11,6,0,4,0,0,14,5,0,7,0,0,0,0,0,6,16,0,0,0,0,0,0,0,10,0,0,7,15,0,0,0,11,7,0,0,
+0,0,0,0,0,0,0,0,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,5,0,0,0,
+0,8,0,0,6,0,0,0,0,0,0,9,5,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,6,0,
+0,0,0,0,0,0,7,0,0,0,0,15,7,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,12,6,11,7,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
+7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,8,0,0,5,8,7,10,6,0,0,0,7,0,0,0,0,12,6,
+0,0,9,0,0,0,12,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,10,0,0,0,10,5,0,0,0,0,0,0,9,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,9,5,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,0,0,5,0,0,8,7,8,
+6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,10,0,9,4,0,0,0,0,0,0,0,6,
+11,0,0,0,0,0,0,0,0,0,0,0,8,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,8,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,
+0,0,0,10,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,8,4,0,5,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,8,5,0,0,0,
+0,0,0,0,7,0,0,0,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,6,0,7,0,0,0,0,
+20,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,6,0,6,0,7,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,
+0,0,0,14,7,0,0,0,5,0,0,22,4,10,0,0,0,0,0,0,4,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,11,5,13,0,0,0,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,10,7,0,
+0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,7,14,6,0,0,0,0,9,5,
+0,0,0,0,0,6,0,0,0,5,10,0,8,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,8,4,0,6,0,
+0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,
+14,0,0,5,0,0,18,0,8,4,0,6,0,0,20,0,13,0,0,0,0,7,0,4,0,0,0,0,0,4,8,4,0,0,0,0,0,6,
+0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,14,0,0,0,0,0,9,7,0,0,9,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,4,0,6,8,5,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,4,12,7,0,6,0,0,9,7,10,5,
+0,0,8,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,18,0,0,0,14,7,0,0,0,0,0,4,
+0,0,0,0,0,0,17,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,23,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,7,8,4,0,0,0,0,0,0,0,0,0,6,0,0,9,5,0,0,0,7,0,0,0,
+0,0,0,0,0,0,4,10,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,18,7,
+0,0,8,0,0,5,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,
+6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,10,0,0,5,10,4,0,0,12,0,0,0,0,
+6,22,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,16,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,7,0,0,0,0,9,0,0,0,0,6,0,0,11,0,0,0,0,0,13,0,9,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,10,7,0,0,0,7,0,6,0,
+0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,11,0,15,0,22,7,0,4,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+18,0,0,0,0,0,0,0,0,0,14,0,0,4,0,0,0,0,8,7,9,0,0,0,0,0,9,0,0,0,14,0,0,0,0,0,0,0,
+0,0,11,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,0,0,0,0,8,0,0,0,0,
+0,11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,4,0,0,0,0,0,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,0,0,0,0,8,6,0,0,9,5,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,
+0,10,6,9,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+11,7,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,5,0,0,10,6,
+0,0,0,4,0,7,13,0,0,4,0,0,11,4,0,6,0,0,0,0,0,6,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,5,0,0,0,0,12,6,0,0,0,0,
+11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,11,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,
+7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,6,17,0,9,0,10,6,0,6,12,0,0,4,0,0,0,
+0,0,0,0,0,0,0,8,5,12,7,0,4,0,0,0,0,0,0,0,0,0,0,11,0,9,0,10,6,11,5,0,7,0,0,8,0,0,
+7,0,4,0,0,0,7,0,0,0,0,0,0,8,6,0,0,0,6,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,10,0,0,0,0,0,8,6,0,0,0,0,0,6,12,0,0,0,0,0,
+0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,16,0,11,5,0,0,0,0,0,
+0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,10,
+7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,9,5,0,0,0,0,8,0,9,0,0,
+0,0,0,0,0,0,7,10,0,13,0,0,6,0,0,0,0,0,0,0,0,0,6,9,4,0,0,0,0,0,0,10,0,0,0,0,0,10,
+0,0,0,0,0,0,0,10,6,11,0,0,0,0,0,9,0,0,0,0,0,0,4,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0,
+0,0,0,0,0,18,4,0,7,0,0,0,0,0,0,24,0,8,6,0,7,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,0,0,0,0,10,7,0,6,0,0,0,0,0,0,0,0,8,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,
+6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,4,0,5,15,0,0,0,0,7,0,7,0,0,0,0,
+0,0,0,0,0,6,10,5,0,0,0,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,0,0,0,0,0,0,0,0,
+0,0,5,0,0,0,0,0,0,14,4,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,11,0,10,4,9,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,
+0,0,0,0,0,0,0,0,7,13,7,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,8,0,10,6,0,4,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,
+0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,9,7,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,11,0,0,0,0,6,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,
+6,0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,10,0,11,5,0,0,0,0,0,0,14,7,9,7,
+0,6,0,0,0,0,0,4,0,0,0,0,0,0,11,7,0,6,0,0,0,0,0,0,9,7,0,4,0,0,0,7,0,0,0,0,0,5,0,
+0,0,0,0,5,0,0,0,7,0,0,0,0,0,5,0,0,0,0,17,5,0,0,8,0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,
+8,7,11,7,9,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,9,5,0,0,8,6,0,0,0,5,0,
+0,0,0,9,0,0,0,9,6,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,5,0,0,0,0,0,7,0,0,0,0,0,7,13,5,0,0,0,7,0,0,0,0,0,7,9,6,11,7,0,7,0,0,0,
+0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,8,5,0,0,0,5,9,4,0,0,0,0,0,0,0,0,8,4,0,0,0,0,
+24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,0,4,0,7,20,0,8,5,9,5,9,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,7,23,5,0,0,8,4,0,0,10,0,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,
+6,0,0,0,0,14,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,6,0,4,0,0,0,0,0,0,8,4,
+11,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,12,0,10,7,0,0,10,0,0,0,0,
+0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,6,0,0,0,0,8,
+6,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,6,0,4,0,0,0,0,0,5,0,0,
+0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,17,7,11,0,0,0,0,0,0,0,0,0,0,4,12,6,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,5,12,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,0,20,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,4,
+0,0,0,5,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,4,13,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,12,6,0,7,0,0,0,0,10,0,23,6,0,0,
+0,4,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+10,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,11,0,9,7,0,0,
+0,0,0,0,0,0,0,0,9,7,0,4,0,0,0,0,8,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0,0,0,0,0,6,0,0,10,7,10,5,0,0,8,0,8,0,0,0,0,0,0,4,0,5,10,0,0,0,0,0,0,0,9,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,6,0,0,8,
+7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,24,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,6,0,0,9,0,0,0,0,0,0,7,0,6,13,0,8,
+0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,
+4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,5,0,7,0,0,10,0,10,7,0,0,12,5,0,0,9,0,0,0,10,0,
+0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,
+12,0,0,0,0,0,8,5,13,6,0,0,0,0,0,0,9,4,0,0,0,0,8,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,14,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,17,6,0,0,0,0,12,6,0,0,0,0,8,0,0,7,0,
+7,0,4,9,0,0,6,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,0,0,0,11,0,0,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,18,7,0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,11,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+11,0,0,0,0,0,0,0,21,0,0,6,10,0,0,0,0,0,9,0,10,0,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,
+5,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,4,0,0,23,7,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,0,7,
+0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,
+11,6,0,0,0,0,0,0,0,6,0,0,0,0,10,7,0,0,9,4,0,0,11,0,8,5,0,0,0,7,8,5,22,0,0,0,9,6,
+0,0,0,0,0,0,0,6,10,4,0,0,0,0,0,7,9,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,
+0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,6,0,4,0,0,
+0,0,0,0,0,7,0,7,0,4,13,0,0,0,0,0,8,0,0,0,0,7,0,0,0,0,0,0,11,6,0,7,0,0,0,0,9,0,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,8,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,13,5,8,0,0,
+0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,17,6,0,0,0,0,13,4,0,0,9,6,0,0,10,5,0,
+0,10,5,0,0,0,0,13,0,0,0,0,6,0,0,0,0,0,0,10,0,12,0,0,0,0,0,0,0,0,0,0,0,8,4,0,4,0,
+0,0,4,0,0,0,0,0,4,0,0,12,0,0,5,9,4,0,0,0,0,0,0,0,0,0,5,8,5,0,0,0,7,0,0,0,0,8,7,
+0,0,0,6,12,5,0,0,0,5,0,0,0,5,0,0,0,0,0,4,12,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,4,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,12,7,0,0,0,7,10,7,0,0,11,0,0,0,0,0,0,0,0,0,11,7,0,0,0,6,0,0,11,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,0,10,7,0,0,8,5,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,0,0,9,6,8,7,0,6,0,0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,9,7,0,0,0,6,0,0,8,7,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,5,0,0,0,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,5,0,0,0,0,14,0,0,0,
+9,0,0,0,0,0,0,0,0,0,9,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,0,0,0,0,0,12,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,9,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,7,12,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,7,0,0,8,6,0,0,0,0,10,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,6,0,0,0,6,0,0,0,0,0,6,16,0,0,0,0,0,0,0,0,0,9,0,17,0,14,7,8,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,11,0,0,6,8,7,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,
+9,0,0,0,0,7,0,0,0,0,11,5,0,4,9,6,8,0,0,0,0,0,0,0,0,0,10,0,11,7,0,0,0,0,0,0,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,
+0,0,0,12,0,0,0,0,0,10,5,0,4,0,0,0,0,0,7,10,6,11,6,0,0,0,0,0,0,0,0,0,0,0,0,17,0,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,8,0,0,4,0,0,0,6,0,0,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,9,6,0,0,0,4,0,0,0,0,0,4,10,7,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,6,0,0,0,6,0,6,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,18,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,13,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,
+0,0,0,6,0,0,0,0,0,4,8,0,0,0,11,7,0,0,0,4,0,0,0,0,0,7,0,0,8,5,0,0,16,0,0,0,13,6,
+0,0,0,0,0,0,0,6,0,0,0,0,20,0,11,6,0,0,8,7,0,0,0,0,0,6,17,0,8,0,0,0,0,0,8,7,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,
+0,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,8,
+0,8,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,6,0,0,9,0,
+0,0,0,0,8,0,0,0,0,0,18,0,0,0,0,0,0,4,9,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,0,14,0,0,0,0,7,0,6,0,0,8,0,20,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,8,0,0,7,0,6,0,0,0,7,0,0,0,0,0,0,0,0,
+0,0,0,4,12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,6,0,
+5,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,5,8,4,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,12,7,0,
+0,0,0,13,6,0,0,0,7,0,0,8,0,0,0,8,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,11,5,
+0,6,0,0,8,5,0,7,0,0,0,0,0,0,0,7,0,0,0,0,8,6,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+14,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,19,0,0,4,0,0,0,7,
+0,0,11,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,16,0,10,5,18,0,0,7,9,6,0,5,0,0,0,0,0,
+0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,0,7,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,4,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,23,0,0,0,0,5,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,20,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,
+11,0,0,0,0,7,0,0,0,0,15,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,
+0,4,0,0,0,0,10,0,0,0,0,0,9,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,0,11,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,11,0,0,0,0,7,0,0,0,0,0,0,8,7,0,
+4,0,0,0,0,11,0,0,0,0,0,11,0,0,5,0,0,8,7,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,
+0,0,4,11,5,10,7,0,7,0,0,9,6,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,9,4,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,8,6,0,0,0,0,11,7,0,0,0,0,0,0,0,0,0,0,11,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,8,5,0,0,8,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,
+10,7,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,10,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,
+0,0,6,0,0,0,0,9,5,8,5,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,8,7,10,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,5,0,0,0,6,0,7,0,0,
+10,5,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,11,0,0,0,0,0,13,4,
+0,0,0,4,0,0,0,0,0,5,8,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,14,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,15,6,10,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,14,6,10,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,6,0,5,11,4,0,6,0,0,0,7,0,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,8,5,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,0,0,0,9,6,9,4,0,0,0,4,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,
+0,0,0,7,12,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,
+4,9,6,0,4,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,
+7,8,6,0,0,0,0,0,0,0,4,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,5,0,4,0,0,0,0,0,0,0,5,0,0,0,
+0,0,5,0,0,0,7,12,7,0,0,0,0,0,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,6,0,0,0,
+0,12,0,0,7,0,0,0,0,0,7,0,0,13,0,0,6,0,0,0,0,8,7,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,7,10,5,0,0,8,0,0,0,0,0,0,0,8,6,0,7,0,0,8,4,0,4,0,0,0,0,10,4,0,0,14,0,
+0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,17,0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,10,5,0,0,0,0,8,
+6,0,0,0,6,0,0,0,7,0,0,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,12,0,0,0,0,6,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,24,0,0,
+0,0,0,12,6,0,0,10,6,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,7,0,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,11,5,9,0,8,7,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,5,8,7,0,0,0,
+0,8,5,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,
+0,6,12,0,8,7,0,0,0,0,0,0,0,0,0,0,16,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,22,0,0,0,
+0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,22,0,0,6,0,0,21,0,0,0,22,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,7,8,0,0,0,0,6,14,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,8,5,0,0,11,7,0,6,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,8,7,0,0,0,0,8,5,11,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,8,5,0,0,10,0,0,4,13,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,13,6,
+0,6,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,15,0,0,0,10,7,0,0,0,0,0,
+7,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,19,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,5,
+0,7,0,0,0,0,0,0,0,0,0,6,0,0,11,4,0,0,0,6,0,0,13,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,
+0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,
+0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0,
+0,0,0,8,7,0,0,0,0,9,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,10,0,
+0,6,0,0,13,0,0,0,0,0,0,0,9,6,0,0,8,6,8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,
+0,9,7,0,0,0,0,0,0,11,0,0,0,10,7,0,0,0,0,0,0,0,0,9,6,0,0,12,4,0,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,
+16,0,0,4,0,0,0,0,0,7,0,0,0,6,0,6,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,
+0,14,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,
+0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,
+0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,14,7,0,0,9,7,0,0,11,0,0,0,0,0,10,
+4,11,5,13,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,5,0,0,0,0,0,4,0,0,9,0,0,0,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,12,5,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,4,9,4,
+0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,
+0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,11,6,0,0,13,7,0,0,13,6,0,7,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,6,0,4,0,0,12,6,0,0,0,0,0,0,0,0,10,6,
+0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,7,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,
+0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,5,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,5,0,0,0,4,9,5,0,0,0,7,10,6,0,0,
+0,0,0,0,9,7,0,0,8,5,8,0,8,4,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,11,7,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,5,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,7,0,0,0,0,8,5,0,4,0,0,0,0,0,6,0,6,14,
+6,0,0,0,0,9,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,14,7,9,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,
+0,6,0,0,8,6,0,0,0,0,0,6,0,0,12,0,0,0,0,0,8,5,0,7,11,0,0,5,0,4,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,9,6,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,10,5,0,0,0,0,
+0,4,0,0,0,7,11,6,0,4,8,5,9,5,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,14,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,16,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,5,0,0,0,0,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,4,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,10,4,0,0,0,0,0,5,0,0,0,4,
+0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,0,10,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,7,0,0,0,0,0,0,0,0,15,0,0,0,
+0,0,0,0,0,0,0,7,0,0,0,0,0,7,10,7,9,7,0,0,0,7,0,0,8,0,0,0,0,0,0,0,9,0,0,0,8,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,15,7,12,6,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,5,0,0,0,0,
+0,0,0,6,9,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,14,0,0,0,11,7,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,11,7,0,0,0,0,8,0,0,0,0,0,0,6,8,7,0,0,0,7,10,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,10,0,0,0,0,0,0,
+6,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,7,0,0,0,0,9,7,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,12,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,9,6,0,0,11,0,0,
+0,0,0,14,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,7,0,0,
+0,0,0,6,0,7,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,20,
+7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,5,8,5,10,4,0,0,0,0,0,
+0,13,6,9,7,0,0,10,7,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,7,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,10,7,0,0,
+0,0,0,0,0,0,0,0,12,4,0,0,0,0,8,7,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,
+0,0,0,0,6,0,6,9,6,0,0,12,5,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,5,8,7,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,
+4,0,0,0,0,0,0,8,0,0,0,10,7,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,0,
+0,0,0,0,0,5,0,6,0,0,10,0,14,0,0,0,0,0,0,0,23,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,22,0,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,
+0,0,0,0,0,6,18,4,0,0,0,7,10,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,0,0,0,0,0,0,6,0,0,0,0,11,5,0,0,0,0,0,0,0,0,
+15,0,8,6,0,0,13,7,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,5,9,
+0,0,6,8,6,0,0,0,0,10,0,0,0,18,5,0,0,0,5,0,7,0,0,0,0,8,6,0,0,0,0,9,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,14,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,
+0,0,0,0,20,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,8,4,24,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,7,0,0,0,0,10,5,0,0,8,5,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,6,0,0,0,
+0,14,0,0,4,9,5,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,8,0,0,0,0,0,11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,8,5,11,7,0,4,0,0,10,0,0,0,0,
+0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,6,0,0,0,0,0,5,14,6,0,0,0,0,10,0,0,
+0,13,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,12,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,10,0,9,
+7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,9,7,0,0,0,
+0,0,0,0,0,0,0,0,0,24,0,11,7,0,7,0,0,0,0,0,0,8,6,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,
+0,6,9,0,0,0,23,5,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,18,4,0,0,11,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,0,0,0,11,0,0,0,23,0,0,
+0,10,4,0,0,0,0,0,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,7,0,0,19,0,11,0,0,0,0,0,12,7,0,
+0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,
+9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,22,0,8,7,10,4,11,0,13,5,8,7,9,0,8,7,0,0,0,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,4,11,0,0,6,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,5,0,0,
+20,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,7,0,0,14,0,0,0,9,0,13,7,0,0,0,0,0,6,0,7,0,0,8,6,10,6,0,0,8,6,0,0,0,6,0,
+0,12,6,9,0,0,0,0,0,0,5,9,0,12,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,
+0,0,4,8,0,0,6,8,0,0,0,0,0,0,0,0,0,13,6,0,7,0,0,0,0,0,6,8,7,8,6,0,0,0,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,18,0,11,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,
+6,0,0,0,0,12,7,8,0,0,0,0,0,0,0,8,7,0,0,0,0,10,4,0,0,0,0,0,0,10,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,15,6,9,7,0,0,0,0,0,0,15,6,11,7,0,0,0,7,0,0,21,0,0,
+0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,6,0,0,10,5,0,5,0,0,0,0,0,0,0,0,0,7,
+0,0,10,0,0,0,0,0,0,0,0,4,11,5,0,0,0,0,16,7,0,0,0,0,0,6,0,0,8,7,0,4,0,0,10,0,0,0,
+0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,
+0,0,0,10,4,0,0,0,0,0,0,0,0,0,6,0,5,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,
+0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,8,4,0,0,10,0,0,0,0,4,0,6,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,17,0,0,0,0,0,
+0,0,0,0,0,0,10,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,4,0,0,0,0,0,6,0,0,0,0,0,0,10,5,0,0,
+0,5,0,0,0,0,9,0,19,7,0,0,0,0,0,7,0,0,0,0,10,6,0,0,0,6,0,5,0,0,0,0,0,0,0,0,0,6,8,
+0,0,0,0,0,11,0,0,0,0,0,0,6,0,0,0,0,0,7,9,0,15,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,6,0,0,
+0,0,0,6,10,0,0,0,0,0,0,0,23,0,14,0,0,0,0,7,0,0,0,0,0,7,0,0,9,0,0,0,0,7,0,0,0,0,
+0,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,
+0,0,0,0,0,9,5,0,0,0,0,0,4,0,0,0,0,9,5,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,14,7,0,0,12,7,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,8,6,10,0,0,0,0,0,0,0,0,0,10,7,8,5,0,0,0,0,0,0,
+0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,5,0,0,9,5,0,0,0,0,0,5,0,0,0,0,0,4,0,0,0,
+0,0,0,0,0,0,0,12,4,11,0,0,0,9,0,11,7,0,0,0,0,0,0,10,6,0,0,0,6,0,0,0,0,15,5,0,0,
+11,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,4,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,0,0,0,19,7,0,4,0,0,9,0,0,0,0,0,10,0,
+0,6,0,0,13,0,12,6,0,0,0,0,0,0,0,0,10,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,13,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,9,0,0,0,10,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,10,0,23,6,0,0,0,6,8,0,0,0,0,0,0,0,0,0,17,7,0,0,0,0,11,6,22,5,0,
+0,9,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,9,4,0,0,
+0,7,0,7,0,0,0,0,0,0,12,4,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,11,5,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,6,0,0,0,4,0,0,0,0,
+0,0,0,0,0,7,0,0,0,4,0,0,10,4,0,0,0,0,0,0,0,7,0,7,0,0,0,6,0,0,0,0,8,6,0,6,0,6,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,22,6,12,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,11,0,0,0,
+9,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,0,0,0,6,0,6,0,0,8,7,0,0,0,4,9,7,19,0,0,0,0,0,0,0,0,0,9,6,10,6,0,6,0,0,0,
+4,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,16,7,10,6,0,0,23,6,11,7,0,4,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,10,7,0,0,0,0,0,7,0,0,0,0,0,0,15,0,10,0,0,0,14,6,0,0,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,5,0,0,11,5,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,10,6,0,0,0,0,8,4,0,0,0,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,12,5,0,0,0,0,
+0,6,0,0,0,0,9,6,0,0,0,0,0,0,0,6,9,0,0,0,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,10,5,0,0,0,0,0,0,8,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,0,0,0,0,0,7,0,7,0,4,0,0,10,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,13,
+7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,0,7,10,5,0,0,0,0,0,0,9,7,0,0,8,6,9,
+5,0,0,0,0,0,6,12,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,0,19,7,0,4,0,0,0,0,9,5,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,7,0,0,0,0,0,0,14,0,0,0,23,7,8,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,7,0,0,0,0,0,0,0,0,9,7,8,4,0,
+0,0,0,0,0,0,0,8,5,0,6,0,0,0,0,0,6,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,
+8,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,8,6,0,0,11,7,0,0,0,
+0,12,0,8,6,19,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,11,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,11,7,0,0,0,0,0,4,10,0,0,0,0,0,0,0,8,7,0,0,0,0,14,0,8,0,0,6,10,0,0,
+0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,13,0,0,0,0,0,0,0,11,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,6,0,0,0,5,0,7,0,0,0,
+0,0,6,0,0,21,7,0,0,9,6,0,0,0,6,0,0,13,7,0,0,0,5,0,0,0,0,0,4,0,6,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,11,5,0,6,0,0,10,5,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,15,4,0,0,12,7,0,0,0,6,
+0,7,0,0,8,0,9,5,0,4,0,0,0,6,0,6,0,0,23,4,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,8,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,6,0,0,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,
+9,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,11,5,0,0,0,6,0,6,0,0,0,0,0,0,0,6,0,
+4,0,0,0,0,0,0,0,0,0,0,0,5,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,8,7,0,0,0,6,0,6,0,
+0,0,0,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,10,5,9,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,23,7,0,0,0,0,0,7,0,0,10,6,18,0,0,0,
+0,0,0,0,8,7,0,6,0,0,0,0,0,0,8,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,4,12,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,13,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,0,11,0,0,0,0,0,0,0,0,0,
+17,5,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,8,7,0,0,0,0,0,0,0,
+0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,
+10,0,0,0,8,6,0,0,0,7,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,
+10,0,0,0,16,5,0,0,0,0,0,0,8,0,0,4,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,10,0,0,0,
+0,0,0,0,0,5,0,0,0,0,12,5,0,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,12,6,0,0,0,0,0,7,0,6,0,6,12,6,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+16,0,8,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,23,5,0,0,0,7,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,14,0,0,0,0,7,0,0,0,4,17,5,0,0,0,0,11,0,9,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,5,0,7,0,0,0,0,0,0,0,0,8,0,0,0,
+12,6,0,0,0,0,0,0,13,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,10,7,12,0,0,0,9,0,
+0,0,14,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,15,6,0,0,23,0,0,7,0,6,0,0,0,7,0,6,
+0,0,0,0,0,0,0,6,0,6,9,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,8,7,9,4,0,0,10,0,0,0,10,
+6,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,6,0,0,0,0,0,0,9,4,
+0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,9,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,12,0,0,
+0,0,0,8,0,0,6,11,6,0,0,8,7,8,5,0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,
+7,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,0,0,0,0,6,12,5,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,0,10,
+7,0,0,8,0,0,0,0,4,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,
+0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,5,0,0,0,0,8,0,0,0,10,7,0,0,0,0,10,0,0,0,
+0,0,13,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,19,7,0,4,12,0,8,0,0,0,0,6,0,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,18,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,
+0,14,0,0,4,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,0,0,0,10,4,0,0,9,7,0,0,11,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,12,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,22,5,9,7,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,9,6,0,5,0,0,0,0,0,0,10,5,0,0,8,6,0,6,10,5,0,0,0,6,0,0,0,6,0,0,20,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,17,4,0,7,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
+0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,
+0,0,7,0,0,8,6,12,0,0,7,18,7,0,0,8,4,0,0,0,0,9,6,0,0,0,0,0,0,0,0,13,0,0,6,0,0,0,
+0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,12,0,0,0,8,0,0,0,0,0,0,
+4,0,0,10,0,16,0,0,0,0,0,0,0,12,7,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,6,10,0,0,5,0,0,0,0,0,6,0,0,0,0,
+0,7,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,7,0,0,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,4,0,0,0,0,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,8,0,0,0,
+9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,13,5,0,5,0,0,0,7,8,4,0,0,0,0,0,0,0,
+0,12,0,0,0,0,0,0,0,0,0,0,0,8,6,0,6,0,0,11,0,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,6,0,0,10,6,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,6,0,0,0,7,0,0,9,0,8,7,11,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,9,6,10,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,0,11,0,9,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,15,5,12,5,
+0,0,0,0,0,0,12,7,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,12,6,0,
+0,0,0,24,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,10,4,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+0,0,8,0,0,0,0,7,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,
+0,0,0,0,0,14,7,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,6,0,0,0,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,7,20,7,11,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,9,6,0,0,12,7,0,0,0,0,0,0,10,0,12,0,
+0,0,0,0,0,4,9,6,13,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,0,0,0,0,0,0,
+0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,11,0,9,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,4,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,7,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,8,7,0,0,0,0,0,0,12,0,0,6,0,0,0,0,0,0,0,6,8,4,0,0,10,7,0,0,10,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,5,
+0,4,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,0,0,7,0,5,8,4,0,0,9,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,5,0,0,15,6,8,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,4,0,
+6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,5,0,6,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,12,7,0,0,0,0,
+0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,10,
+7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,8,7,9,6,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,5,12,0,
+10,5,12,6,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,5,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+11,7,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,6,0,7,0,0,0,0,8,0,8,5,0,6,0,0,0,6,0,0,0,
+0,0,0,0,6,0,6,0,6,9,0,0,5,17,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,7,0,0,0,0,16,5,0,0,0,0,0,0,0,4,0,0,0,5,11,5,0,7,0,0,0,4,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,12,0,0,0,
+0,0,12,0,0,0,0,0,0,0,0,4,10,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,5,0,0,
+10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,12,0,0,0,0,0,0,6,0,0,0,0,0,0,9,4,10,7,0,4,0,0,
+0,0,0,0,10,6,0,0,0,0,8,4,0,7,8,6,0,6,8,0,10,0,0,0,0,0,13,5,0,6,0,0,0,0,0,0,22,4,
+0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,10,
+5,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,10,4,0,0,10,7,0,0,0,0,0,5,0,
+5,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,4,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,
+4,0,0,0,4,10,0,0,6,13,7,8,0,0,0,0,0,0,7,0,0,12,7,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,6,0,6,
+0,0,0,0,0,0,0,0,12,0,8,4,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,5,0,0,0,0,12,5,0,0,0,7,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,10,0,0,0,20,0,0,5,0,0,10,
+7,11,7,0,0,0,0,0,0,0,0,0,0,17,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,10,7,0,4,0,6,0,0,24,0,0,5,0,0,0,0,8,0,0,
+0,0,0,0,0,10,5,0,4,0,6,0,0,8,0,0,0,0,0,0,4,0,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,
+0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,7,
+0,0,13,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+17,7,0,0,11,6,0,0,0,0,12,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,4,8,6,0,0,0,
+0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,5,0,7,18,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,6,0,0,9,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,
+0,0,0,8,7,10,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,10,0,0,0,0,6,0,7,0,4,0,0,0,0,0,0,0,0,
+8,0,0,0,0,0,8,4,0,0,0,0,0,5,0,0,10,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,11,0,0,
+7,0,0,0,0,0,6,10,5,0,0,0,0,0,0,0,0,0,5,0,0,9,5,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,13,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,
+0,0,0,8,4,0,6,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,11,4,0,0,0,6,14,0,11,0,9,6,0,0,0,0,0,0,22,0,12,0,8,6,0,0,0,0,0,0,0,6,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,
+10,7,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,11,0,0,0,0,0,0,0,8,6,0,0,9,
+7,0,0,12,4,0,0,0,0,0,0,12,6,0,6,0,7,0,0,8,5,0,0,0,0};
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.h
new file mode 100644
index 000000000..e553ea5d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/dictionary_hash.h
@@ -0,0 +1,25 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Hash table on the 4-byte prefixes of static dictionary words. */
+
+#ifndef BROTLI_ENC_DICTIONARY_HASH_H_
+#define BROTLI_ENC_DICTIONARY_HASH_H_
+
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern const uint16_t kStaticDictionaryHashWords[32768];
+extern const uint8_t kStaticDictionaryHashLengths[32768];
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_DICTIONARY_HASH_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encode.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encode.c
new file mode 100644
index 000000000..68548ef55
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encode.c
@@ -0,0 +1,1925 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Implementation of Brotli compressor. */
+
+#include <brotli/encode.h>
+
+#include <stdlib.h> /* free, malloc */
+#include <string.h> /* memcpy, memset */
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/platform.h"
+#include "../common/version.h"
+#include "./backward_references.h"
+#include "./backward_references_hq.h"
+#include "./bit_cost.h"
+#include "./brotli_bit_stream.h"
+#include "./compress_fragment.h"
+#include "./compress_fragment_two_pass.h"
+#include "./encoder_dict.h"
+#include "./entropy_encode.h"
+#include "./fast_log.h"
+#include "./hash.h"
+#include "./histogram.h"
+#include "./memory.h"
+#include "./metablock.h"
+#include "./prefix.h"
+#include "./quality.h"
+#include "./ringbuffer.h"
+#include "./utf8_util.h"
+#include "./write_bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define COPY_ARRAY(dst, src) memcpy(dst, src, sizeof(src));
+
+typedef enum BrotliEncoderStreamState {
+ /* Default state. */
+ BROTLI_STREAM_PROCESSING = 0,
+ /* Intermediate state; after next block is emitted, byte-padding should be
+ performed before getting back to default state. */
+ BROTLI_STREAM_FLUSH_REQUESTED = 1,
+ /* Last metablock was produced; no more input is acceptable. */
+ BROTLI_STREAM_FINISHED = 2,
+ /* Flushing compressed block and writing meta-data block header. */
+ BROTLI_STREAM_METADATA_HEAD = 3,
+ /* Writing metadata block body. */
+ BROTLI_STREAM_METADATA_BODY = 4
+} BrotliEncoderStreamState;
+
+typedef enum BrotliEncoderFlintState {
+ BROTLI_FLINT_NEEDS_2_BYTES = 2,
+ BROTLI_FLINT_NEEDS_1_BYTE = 1,
+ BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
+ BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
+ BROTLI_FLINT_DONE = -2
+} BrotliEncoderFlintState;
+
+typedef struct BrotliEncoderStateStruct {
+ BrotliEncoderParams params;
+
+ MemoryManager memory_manager_;
+
+ uint64_t input_pos_;
+ RingBuffer ringbuffer_;
+ size_t cmd_alloc_size_;
+ Command* commands_;
+ size_t num_commands_;
+ size_t num_literals_;
+ size_t last_insert_len_;
+ uint64_t last_flush_pos_;
+ uint64_t last_processed_pos_;
+ int dist_cache_[BROTLI_NUM_DISTANCE_SHORT_CODES];
+ int saved_dist_cache_[4];
+ uint16_t last_bytes_;
+ uint8_t last_bytes_bits_;
+ /* "Flint" is a tiny uncompressed block emitted before the continuation
+ block to unwire literal context from previous data. Despite being int8_t,
+ field is actually BrotliEncoderFlintState enum. */
+ int8_t flint_;
+ uint8_t prev_byte_;
+ uint8_t prev_byte2_;
+ size_t storage_size_;
+ uint8_t* storage_;
+
+ Hasher hasher_;
+
+ /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
+ int small_table_[1 << 10]; /* 4KiB */
+ int* large_table_; /* Allocated only when needed */
+ size_t large_table_size_;
+ /* Command and distance prefix codes (each 64 symbols, stored back-to-back)
+ used for the next block in FAST_ONE_PASS_COMPRESSION_QUALITY. The command
+ prefix code is over a smaller alphabet with the following 64 symbols:
+ 0 - 15: insert length code 0, copy length code 0 - 15, same distance
+ 16 - 39: insert length code 0, copy length code 0 - 23
+ 40 - 63: insert length code 0 - 23, copy length code 0
+ Note that symbols 16 and 40 represent the same code in the full alphabet,
+ but we do not use either of them in FAST_ONE_PASS_COMPRESSION_QUALITY. */
+ uint8_t cmd_depths_[128];
+ uint16_t cmd_bits_[128];
+ /* The compressed form of the command and distance prefix codes for the next
+ block in FAST_ONE_PASS_COMPRESSION_QUALITY. */
+ uint8_t cmd_code_[512];
+ size_t cmd_code_numbits_;
+ /* Command and literal buffers for FAST_TWO_PASS_COMPRESSION_QUALITY. */
+ uint32_t* command_buf_;
+ uint8_t* literal_buf_;
+
+ uint8_t* next_out_;
+ size_t available_out_;
+ size_t total_out_;
+ /* Temporary buffer for padding flush bits or metadata block header / body. */
+ union {
+ uint64_t u64[2];
+ uint8_t u8[16];
+ } tiny_buf_;
+ uint32_t remaining_metadata_bytes_;
+ BrotliEncoderStreamState stream_state_;
+
+ BROTLI_BOOL is_last_block_emitted_;
+ BROTLI_BOOL is_initialized_;
+} BrotliEncoderStateStruct;
+
+static size_t InputBlockSize(BrotliEncoderState* s) {
+ return (size_t)1 << s->params.lgblock;
+}
+
+static uint64_t UnprocessedInputSize(BrotliEncoderState* s) {
+ return s->input_pos_ - s->last_processed_pos_;
+}
+
+static size_t RemainingInputBlockSize(BrotliEncoderState* s) {
+ const uint64_t delta = UnprocessedInputSize(s);
+ size_t block_size = InputBlockSize(s);
+ if (delta >= block_size) return 0;
+ return block_size - (size_t)delta;
+}
+
+BROTLI_BOOL BrotliEncoderSetParameter(
+ BrotliEncoderState* state, BrotliEncoderParameter p, uint32_t value) {
+ /* Changing parameters on the fly is not implemented yet. */
+ if (state->is_initialized_) return BROTLI_FALSE;
+ /* TODO: Validate/clamp parameters here. */
+ switch (p) {
+ case BROTLI_PARAM_MODE:
+ state->params.mode = (BrotliEncoderMode)value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_QUALITY:
+ state->params.quality = (int)value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_LGWIN:
+ state->params.lgwin = (int)value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_LGBLOCK:
+ state->params.lgblock = (int)value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:
+ if ((value != 0) && (value != 1)) return BROTLI_FALSE;
+ state->params.disable_literal_context_modeling = TO_BROTLI_BOOL(!!value);
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_SIZE_HINT:
+ state->params.size_hint = value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_LARGE_WINDOW:
+ state->params.large_window = TO_BROTLI_BOOL(!!value);
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_NPOSTFIX:
+ state->params.dist.distance_postfix_bits = value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_NDIRECT:
+ state->params.dist.num_direct_distance_codes = value;
+ return BROTLI_TRUE;
+
+ case BROTLI_PARAM_STREAM_OFFSET:
+ if (value > (1u << 30)) return BROTLI_FALSE;
+ state->params.stream_offset = value;
+ return BROTLI_TRUE;
+
+ default: return BROTLI_FALSE;
+ }
+}
+
+/* Wraps 64-bit input position to 32-bit ring-buffer position preserving
+ "not-a-first-lap" feature. */
+static uint32_t WrapPosition(uint64_t position) {
+ uint32_t result = (uint32_t)position;
+ uint64_t gb = position >> 30;
+ if (gb > 2) {
+ /* Wrap every 2GiB; The first 3GB are continuous. */
+ result = (result & ((1u << 30) - 1)) | ((uint32_t)((gb - 1) & 1) + 1) << 30;
+ }
+ return result;
+}
+
+static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) {
+ MemoryManager* m = &s->memory_manager_;
+ if (s->storage_size_ < size) {
+ BROTLI_FREE(m, s->storage_);
+ s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
+ s->storage_size_ = size;
+ }
+ return s->storage_;
+}
+
+static size_t HashTableSize(size_t max_table_size, size_t input_size) {
+ size_t htsize = 256;
+ while (htsize < max_table_size && htsize < input_size) {
+ htsize <<= 1;
+ }
+ return htsize;
+}
+
+static int* GetHashTable(BrotliEncoderState* s, int quality,
+ size_t input_size, size_t* table_size) {
+ /* Use smaller hash table when input.size() is smaller, since we
+ fill the table, incurring O(hash table size) overhead for
+ compression, and if the input is short, we won't need that
+ many hash table entries anyway. */
+ MemoryManager* m = &s->memory_manager_;
+ const size_t max_table_size = MaxHashTableSize(quality);
+ size_t htsize = HashTableSize(max_table_size, input_size);
+ int* table;
+ BROTLI_DCHECK(max_table_size >= 256);
+ if (quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
+ /* Only odd shifts are supported by fast-one-pass. */
+ if ((htsize & 0xAAAAA) == 0) {
+ htsize <<= 1;
+ }
+ }
+
+ if (htsize <= sizeof(s->small_table_) / sizeof(s->small_table_[0])) {
+ table = s->small_table_;
+ } else {
+ if (htsize > s->large_table_size_) {
+ s->large_table_size_ = htsize;
+ BROTLI_FREE(m, s->large_table_);
+ s->large_table_ = BROTLI_ALLOC(m, int, htsize);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
+ }
+ table = s->large_table_;
+ }
+
+ *table_size = htsize;
+ memset(table, 0, htsize * sizeof(*table));
+ return table;
+}
+
+static void EncodeWindowBits(int lgwin, BROTLI_BOOL large_window,
+ uint16_t* last_bytes, uint8_t* last_bytes_bits) {
+ if (large_window) {
+ *last_bytes = (uint16_t)(((lgwin & 0x3F) << 8) | 0x11);
+ *last_bytes_bits = 14;
+ } else {
+ if (lgwin == 16) {
+ *last_bytes = 0;
+ *last_bytes_bits = 1;
+ } else if (lgwin == 17) {
+ *last_bytes = 1;
+ *last_bytes_bits = 7;
+ } else if (lgwin > 17) {
+ *last_bytes = (uint16_t)(((lgwin - 17) << 1) | 0x01);
+ *last_bytes_bits = 4;
+ } else {
+ *last_bytes = (uint16_t)(((lgwin - 8) << 4) | 0x01);
+ *last_bytes_bits = 7;
+ }
+ }
+}
+
+/* Initializes the command and distance prefix codes for the first block. */
+static void InitCommandPrefixCodes(uint8_t cmd_depths[128],
+ uint16_t cmd_bits[128],
+ uint8_t cmd_code[512],
+ size_t* cmd_code_numbits) {
+ static const uint8_t kDefaultCommandDepths[128] = {
+ 0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
+ 0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7,
+ 7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6,
+ 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ };
+ static const uint16_t kDefaultCommandBits[128] = {
+ 0, 0, 8, 9, 3, 35, 7, 71,
+ 39, 103, 23, 47, 175, 111, 239, 31,
+ 0, 0, 0, 4, 12, 2, 10, 6,
+ 13, 29, 11, 43, 27, 59, 87, 55,
+ 15, 79, 319, 831, 191, 703, 447, 959,
+ 0, 14, 1, 25, 5, 21, 19, 51,
+ 119, 159, 95, 223, 479, 991, 63, 575,
+ 127, 639, 383, 895, 255, 767, 511, 1023,
+ 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8, 4, 12,
+ 2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255,
+ 767, 2815, 1791, 3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095,
+ };
+ static const uint8_t kDefaultCommandCode[] = {
+ 0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6,
+ 0x70, 0x57, 0xbc, 0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c,
+ 0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83, 0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa,
+ 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce, 0x88, 0x54, 0x94,
+ 0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x04, 0x00,
+ };
+ static const size_t kDefaultCommandCodeNumBits = 448;
+ COPY_ARRAY(cmd_depths, kDefaultCommandDepths);
+ COPY_ARRAY(cmd_bits, kDefaultCommandBits);
+
+ /* Initialize the pre-compressed form of the command and distance prefix
+ codes. */
+ COPY_ARRAY(cmd_code, kDefaultCommandCode);
+ *cmd_code_numbits = kDefaultCommandCodeNumBits;
+}
+
+/* Decide about the context map based on the ability of the prediction
+ ability of the previous byte UTF8-prefix on the next byte. The
+ prediction ability is calculated as Shannon entropy. Here we need
+ Shannon entropy instead of 'BitsEntropy' since the prefix will be
+ encoded with the remaining 6 bits of the following byte, and
+ BitsEntropy will assume that symbol to be stored alone using Huffman
+ coding. */
+static void ChooseContextMap(int quality,
+ uint32_t* bigram_histo,
+ size_t* num_literal_contexts,
+ const uint32_t** literal_context_map) {
+ static const uint32_t kStaticContextMapContinuation[64] = {
+ 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ static const uint32_t kStaticContextMapSimpleUTF8[64] = {
+ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ uint32_t monogram_histo[3] = { 0 };
+ uint32_t two_prefix_histo[6] = { 0 };
+ size_t total;
+ size_t i;
+ size_t dummy;
+ double entropy[4];
+ for (i = 0; i < 9; ++i) {
+ monogram_histo[i % 3] += bigram_histo[i];
+ two_prefix_histo[i % 6] += bigram_histo[i];
+ }
+ entropy[1] = ShannonEntropy(monogram_histo, 3, &dummy);
+ entropy[2] = (ShannonEntropy(two_prefix_histo, 3, &dummy) +
+ ShannonEntropy(two_prefix_histo + 3, 3, &dummy));
+ entropy[3] = 0;
+ for (i = 0; i < 3; ++i) {
+ entropy[3] += ShannonEntropy(bigram_histo + 3 * i, 3, &dummy);
+ }
+
+ total = monogram_histo[0] + monogram_histo[1] + monogram_histo[2];
+ BROTLI_DCHECK(total != 0);
+ entropy[0] = 1.0 / (double)total;
+ entropy[1] *= entropy[0];
+ entropy[2] *= entropy[0];
+ entropy[3] *= entropy[0];
+
+ if (quality < MIN_QUALITY_FOR_HQ_CONTEXT_MODELING) {
+ /* 3 context models is a bit slower, don't use it at lower qualities. */
+ entropy[3] = entropy[1] * 10;
+ }
+ /* If expected savings by symbol are less than 0.2 bits, skip the
+ context modeling -- in exchange for faster decoding speed. */
+ if (entropy[1] - entropy[2] < 0.2 &&
+ entropy[1] - entropy[3] < 0.2) {
+ *num_literal_contexts = 1;
+ } else if (entropy[2] - entropy[3] < 0.02) {
+ *num_literal_contexts = 2;
+ *literal_context_map = kStaticContextMapSimpleUTF8;
+ } else {
+ *num_literal_contexts = 3;
+ *literal_context_map = kStaticContextMapContinuation;
+ }
+}
+
+/* Decide if we want to use a more complex static context map containing 13
+ context values, based on the entropy reduction of histograms over the
+ first 5 bits of literals. */
+static BROTLI_BOOL ShouldUseComplexStaticContextMap(const uint8_t* input,
+ size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint,
+ size_t* num_literal_contexts, const uint32_t** literal_context_map) {
+ static const uint32_t kStaticContextMapComplexUTF8[64] = {
+ 11, 11, 12, 12, /* 0 special */
+ 0, 0, 0, 0, /* 4 lf */
+ 1, 1, 9, 9, /* 8 space */
+ 2, 2, 2, 2, /* !, first after space/lf and after something else. */
+ 1, 1, 1, 1, /* " */
+ 8, 3, 3, 3, /* % */
+ 1, 1, 1, 1, /* ({[ */
+ 2, 2, 2, 2, /* }]) */
+ 8, 4, 4, 4, /* :; */
+ 8, 7, 4, 4, /* . */
+ 8, 0, 0, 0, /* > */
+ 3, 3, 3, 3, /* [0..9] */
+ 5, 5, 10, 5, /* [A-Z] */
+ 5, 5, 10, 5,
+ 6, 6, 6, 6, /* [a-z] */
+ 6, 6, 6, 6,
+ };
+ BROTLI_UNUSED(quality);
+ /* Try the more complex static context map only for long data. */
+ if (size_hint < (1 << 20)) {
+ return BROTLI_FALSE;
+ } else {
+ const size_t end_pos = start_pos + length;
+ /* To make entropy calculations faster and to fit on the stack, we collect
+ histograms over the 5 most significant bits of literals. One histogram
+ without context and 13 additional histograms for each context value. */
+ uint32_t combined_histo[32] = { 0 };
+ uint32_t context_histo[13][32] = { { 0 } };
+ uint32_t total = 0;
+ double entropy[3];
+ size_t dummy;
+ size_t i;
+ ContextLut utf8_lut = BROTLI_CONTEXT_LUT(CONTEXT_UTF8);
+ for (; start_pos + 64 <= end_pos; start_pos += 4096) {
+ const size_t stride_end_pos = start_pos + 64;
+ uint8_t prev2 = input[start_pos & mask];
+ uint8_t prev1 = input[(start_pos + 1) & mask];
+ size_t pos;
+ /* To make the analysis of the data faster we only examine 64 byte long
+ strides at every 4kB intervals. */
+ for (pos = start_pos + 2; pos < stride_end_pos; ++pos) {
+ const uint8_t literal = input[pos & mask];
+ const uint8_t context = (uint8_t)kStaticContextMapComplexUTF8[
+ BROTLI_CONTEXT(prev1, prev2, utf8_lut)];
+ ++total;
+ ++combined_histo[literal >> 3];
+ ++context_histo[context][literal >> 3];
+ prev2 = prev1;
+ prev1 = literal;
+ }
+ }
+ entropy[1] = ShannonEntropy(combined_histo, 32, &dummy);
+ entropy[2] = 0;
+ for (i = 0; i < 13; ++i) {
+ entropy[2] += ShannonEntropy(&context_histo[i][0], 32, &dummy);
+ }
+ entropy[0] = 1.0 / (double)total;
+ entropy[1] *= entropy[0];
+ entropy[2] *= entropy[0];
+ /* The triggering heuristics below were tuned by compressing the individual
+ files of the silesia corpus. If we skip this kind of context modeling
+ for not very well compressible input (i.e. entropy using context modeling
+ is 60% of maximal entropy) or if expected savings by symbol are less
+ than 0.2 bits, then in every case when it triggers, the final compression
+ ratio is improved. Note however that this heuristics might be too strict
+ for some cases and could be tuned further. */
+ if (entropy[2] > 3.0 || entropy[1] - entropy[2] < 0.2) {
+ return BROTLI_FALSE;
+ } else {
+ *num_literal_contexts = 13;
+ *literal_context_map = kStaticContextMapComplexUTF8;
+ return BROTLI_TRUE;
+ }
+ }
+}
+
+static void DecideOverLiteralContextModeling(const uint8_t* input,
+ size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint,
+ size_t* num_literal_contexts, const uint32_t** literal_context_map) {
+ if (quality < MIN_QUALITY_FOR_CONTEXT_MODELING || length < 64) {
+ return;
+ } else if (ShouldUseComplexStaticContextMap(
+ input, start_pos, length, mask, quality, size_hint,
+ num_literal_contexts, literal_context_map)) {
+ /* Context map was already set, nothing else to do. */
+ } else {
+ /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of
+ UTF8 data faster we only examine 64 byte long strides at every 4kB
+ intervals. */
+ const size_t end_pos = start_pos + length;
+ uint32_t bigram_prefix_histo[9] = { 0 };
+ for (; start_pos + 64 <= end_pos; start_pos += 4096) {
+ static const int lut[4] = { 0, 0, 1, 2 };
+ const size_t stride_end_pos = start_pos + 64;
+ int prev = lut[input[start_pos & mask] >> 6] * 3;
+ size_t pos;
+ for (pos = start_pos + 1; pos < stride_end_pos; ++pos) {
+ const uint8_t literal = input[pos & mask];
+ ++bigram_prefix_histo[prev + lut[literal >> 6]];
+ prev = lut[literal >> 6] * 3;
+ }
+ }
+ ChooseContextMap(quality, &bigram_prefix_histo[0], num_literal_contexts,
+ literal_context_map);
+ }
+}
+
+static BROTLI_BOOL ShouldCompress(
+ const uint8_t* data, const size_t mask, const uint64_t last_flush_pos,
+ const size_t bytes, const size_t num_literals, const size_t num_commands) {
+ /* TODO: find more precise minimal block overhead. */
+ if (bytes <= 2) return BROTLI_FALSE;
+ if (num_commands < (bytes >> 8) + 2) {
+ if (num_literals > 0.99 * (double)bytes) {
+ uint32_t literal_histo[256] = { 0 };
+ static const uint32_t kSampleRate = 13;
+ static const double kMinEntropy = 7.92;
+ const double bit_cost_threshold =
+ (double)bytes * kMinEntropy / kSampleRate;
+ size_t t = (bytes + kSampleRate - 1) / kSampleRate;
+ uint32_t pos = (uint32_t)last_flush_pos;
+ size_t i;
+ for (i = 0; i < t; i++) {
+ ++literal_histo[data[pos & mask]];
+ pos += kSampleRate;
+ }
+ if (BitsEntropy(literal_histo, 256) > bit_cost_threshold) {
+ return BROTLI_FALSE;
+ }
+ }
+ }
+ return BROTLI_TRUE;
+}
+
+/* Chooses the literal context mode for a metablock */
+static ContextType ChooseContextMode(const BrotliEncoderParams* params,
+ const uint8_t* data, const size_t pos, const size_t mask,
+ const size_t length) {
+ /* We only do the computation for the option of something else than
+ CONTEXT_UTF8 for the highest qualities */
+ if (params->quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING &&
+ !BrotliIsMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio)) {
+ return CONTEXT_SIGNED;
+ }
+ return CONTEXT_UTF8;
+}
+
+static void WriteMetaBlockInternal(MemoryManager* m,
+ const uint8_t* data,
+ const size_t mask,
+ const uint64_t last_flush_pos,
+ const size_t bytes,
+ const BROTLI_BOOL is_last,
+ ContextType literal_context_mode,
+ const BrotliEncoderParams* params,
+ const uint8_t prev_byte,
+ const uint8_t prev_byte2,
+ const size_t num_literals,
+ const size_t num_commands,
+ Command* commands,
+ const int* saved_dist_cache,
+ int* dist_cache,
+ size_t* storage_ix,
+ uint8_t* storage) {
+ const uint32_t wrapped_last_flush_pos = WrapPosition(last_flush_pos);
+ uint16_t last_bytes;
+ uint8_t last_bytes_bits;
+ ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
+ BrotliEncoderParams block_params = *params;
+
+ if (bytes == 0) {
+ /* Write the ISLAST and ISEMPTY bits. */
+ BrotliWriteBits(2, 3, storage_ix, storage);
+ *storage_ix = (*storage_ix + 7u) & ~7u;
+ return;
+ }
+
+ if (!ShouldCompress(data, mask, last_flush_pos, bytes,
+ num_literals, num_commands)) {
+ /* Restore the distance cache, as its last update by
+ CreateBackwardReferences is now unused. */
+ memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
+ BrotliStoreUncompressedMetaBlock(is_last, data,
+ wrapped_last_flush_pos, mask, bytes,
+ storage_ix, storage);
+ return;
+ }
+
+ BROTLI_DCHECK(*storage_ix <= 14);
+ last_bytes = (uint16_t)((storage[1] << 8) | storage[0]);
+ last_bytes_bits = (uint8_t)(*storage_ix);
+ if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
+ BrotliStoreMetaBlockFast(m, data, wrapped_last_flush_pos,
+ bytes, mask, is_last, params,
+ commands, num_commands,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
+ BrotliStoreMetaBlockTrivial(m, data, wrapped_last_flush_pos,
+ bytes, mask, is_last, params,
+ commands, num_commands,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ } else {
+ MetaBlockSplit mb;
+ InitMetaBlockSplit(&mb);
+ if (params->quality < MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) {
+ size_t num_literal_contexts = 1;
+ const uint32_t* literal_context_map = NULL;
+ if (!params->disable_literal_context_modeling) {
+ DecideOverLiteralContextModeling(
+ data, wrapped_last_flush_pos, bytes, mask, params->quality,
+ params->size_hint, &num_literal_contexts,
+ &literal_context_map);
+ }
+ BrotliBuildMetaBlockGreedy(m, data, wrapped_last_flush_pos, mask,
+ prev_byte, prev_byte2, literal_context_lut, num_literal_contexts,
+ literal_context_map, commands, num_commands, &mb);
+ if (BROTLI_IS_OOM(m)) return;
+ } else {
+ BrotliBuildMetaBlock(m, data, wrapped_last_flush_pos, mask, &block_params,
+ prev_byte, prev_byte2,
+ commands, num_commands,
+ literal_context_mode,
+ &mb);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+ if (params->quality >= MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS) {
+ /* The number of distance symbols effectively used for distance
+ histograms. It might be less than distance alphabet size
+ for "Large Window Brotli" (32-bit). */
+ BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
+ }
+ BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
+ prev_byte, prev_byte2,
+ is_last,
+ &block_params,
+ literal_context_mode,
+ commands, num_commands,
+ &mb,
+ storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return;
+ DestroyMetaBlockSplit(m, &mb);
+ }
+ if (bytes + 4 < (*storage_ix >> 3)) {
+ /* Restore the distance cache and last byte. */
+ memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
+ storage[0] = (uint8_t)last_bytes;
+ storage[1] = (uint8_t)(last_bytes >> 8);
+ *storage_ix = last_bytes_bits;
+ BrotliStoreUncompressedMetaBlock(is_last, data,
+ wrapped_last_flush_pos, mask,
+ bytes, storage_ix, storage);
+ }
+}
+
+static void ChooseDistanceParams(BrotliEncoderParams* params) {
+ uint32_t distance_postfix_bits = 0;
+ uint32_t num_direct_distance_codes = 0;
+
+ if (params->quality >= MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS) {
+ uint32_t ndirect_msb;
+ if (params->mode == BROTLI_MODE_FONT) {
+ distance_postfix_bits = 1;
+ num_direct_distance_codes = 12;
+ } else {
+ distance_postfix_bits = params->dist.distance_postfix_bits;
+ num_direct_distance_codes = params->dist.num_direct_distance_codes;
+ }
+ ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F;
+ if (distance_postfix_bits > BROTLI_MAX_NPOSTFIX ||
+ num_direct_distance_codes > BROTLI_MAX_NDIRECT ||
+ (ndirect_msb << distance_postfix_bits) != num_direct_distance_codes) {
+ distance_postfix_bits = 0;
+ num_direct_distance_codes = 0;
+ }
+ }
+
+ BrotliInitDistanceParams(
+ params, distance_postfix_bits, num_direct_distance_codes);
+}
+
+static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
+ if (BROTLI_IS_OOM(&s->memory_manager_)) return BROTLI_FALSE;
+ if (s->is_initialized_) return BROTLI_TRUE;
+
+ s->last_bytes_bits_ = 0;
+ s->last_bytes_ = 0;
+ s->flint_ = BROTLI_FLINT_DONE;
+ s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
+
+ SanitizeParams(&s->params);
+ s->params.lgblock = ComputeLgBlock(&s->params);
+ ChooseDistanceParams(&s->params);
+
+ if (s->params.stream_offset != 0) {
+ s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
+ /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
+ s->dist_cache_[0] = -16;
+ s->dist_cache_[1] = -16;
+ s->dist_cache_[2] = -16;
+ s->dist_cache_[3] = -16;
+ memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
+ }
+
+ RingBufferSetup(&s->params, &s->ringbuffer_);
+
+ /* Initialize last byte with stream header. */
+ {
+ int lgwin = s->params.lgwin;
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
+ s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ lgwin = BROTLI_MAX(int, lgwin, 18);
+ }
+ if (s->params.stream_offset == 0) {
+ EncodeWindowBits(lgwin, s->params.large_window,
+ &s->last_bytes_, &s->last_bytes_bits_);
+ } else {
+ /* Bigger values have the same effect, but could cause overflows. */
+ s->params.stream_offset = BROTLI_MIN(size_t,
+ s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
+ }
+ }
+
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
+ InitCommandPrefixCodes(s->cmd_depths_, s->cmd_bits_,
+ s->cmd_code_, &s->cmd_code_numbits_);
+ }
+
+ s->is_initialized_ = BROTLI_TRUE;
+ return BROTLI_TRUE;
+}
+
+static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
+ params->mode = BROTLI_DEFAULT_MODE;
+ params->large_window = BROTLI_FALSE;
+ params->quality = BROTLI_DEFAULT_QUALITY;
+ params->lgwin = BROTLI_DEFAULT_WINDOW;
+ params->lgblock = 0;
+ params->stream_offset = 0;
+ params->size_hint = 0;
+ params->disable_literal_context_modeling = BROTLI_FALSE;
+ BrotliInitEncoderDictionary(&params->dictionary);
+ params->dist.distance_postfix_bits = 0;
+ params->dist.num_direct_distance_codes = 0;
+ params->dist.alphabet_size_max =
+ BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
+ params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
+ params->dist.max_distance = BROTLI_MAX_DISTANCE;
+}
+
+static void BrotliEncoderInitState(BrotliEncoderState* s) {
+ BrotliEncoderInitParams(&s->params);
+ s->input_pos_ = 0;
+ s->num_commands_ = 0;
+ s->num_literals_ = 0;
+ s->last_insert_len_ = 0;
+ s->last_flush_pos_ = 0;
+ s->last_processed_pos_ = 0;
+ s->prev_byte_ = 0;
+ s->prev_byte2_ = 0;
+ s->storage_size_ = 0;
+ s->storage_ = 0;
+ HasherInit(&s->hasher_);
+ s->large_table_ = NULL;
+ s->large_table_size_ = 0;
+ s->cmd_code_numbits_ = 0;
+ s->command_buf_ = NULL;
+ s->literal_buf_ = NULL;
+ s->next_out_ = NULL;
+ s->available_out_ = 0;
+ s->total_out_ = 0;
+ s->stream_state_ = BROTLI_STREAM_PROCESSING;
+ s->is_last_block_emitted_ = BROTLI_FALSE;
+ s->is_initialized_ = BROTLI_FALSE;
+
+ RingBufferInit(&s->ringbuffer_);
+
+ s->commands_ = 0;
+ s->cmd_alloc_size_ = 0;
+
+ /* Initialize distance cache. */
+ s->dist_cache_[0] = 4;
+ s->dist_cache_[1] = 11;
+ s->dist_cache_[2] = 15;
+ s->dist_cache_[3] = 16;
+ /* Save the state of the distance cache in case we need to restore it for
+ emitting an uncompressed block. */
+ memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
+}
+
+BrotliEncoderState* BrotliEncoderCreateInstance(
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
+ BrotliEncoderState* state = 0;
+ if (!alloc_func && !free_func) {
+ state = (BrotliEncoderState*)malloc(sizeof(BrotliEncoderState));
+ } else if (alloc_func && free_func) {
+ state = (BrotliEncoderState*)alloc_func(opaque, sizeof(BrotliEncoderState));
+ }
+ if (state == 0) {
+ /* BROTLI_DUMP(); */
+ return 0;
+ }
+ BrotliInitMemoryManager(
+ &state->memory_manager_, alloc_func, free_func, opaque);
+ BrotliEncoderInitState(state);
+ return state;
+}
+
+static void BrotliEncoderCleanupState(BrotliEncoderState* s) {
+ MemoryManager* m = &s->memory_manager_;
+ if (BROTLI_IS_OOM(m)) {
+ BrotliWipeOutMemoryManager(m);
+ return;
+ }
+ BROTLI_FREE(m, s->storage_);
+ BROTLI_FREE(m, s->commands_);
+ RingBufferFree(m, &s->ringbuffer_);
+ DestroyHasher(m, &s->hasher_);
+ BROTLI_FREE(m, s->large_table_);
+ BROTLI_FREE(m, s->command_buf_);
+ BROTLI_FREE(m, s->literal_buf_);
+}
+
+/* Deinitializes and frees BrotliEncoderState instance. */
+void BrotliEncoderDestroyInstance(BrotliEncoderState* state) {
+ if (!state) {
+ return;
+ } else {
+ MemoryManager* m = &state->memory_manager_;
+ brotli_free_func free_func = m->free_func;
+ void* opaque = m->opaque;
+ BrotliEncoderCleanupState(state);
+ free_func(opaque, state);
+ }
+}
+
+/*
+ Copies the given input data to the internal ring buffer of the compressor.
+ No processing of the data occurs at this time and this function can be
+ called multiple times before calling WriteBrotliData() to process the
+ accumulated input. At most input_block_size() bytes of input data can be
+ copied to the ring buffer, otherwise the next WriteBrotliData() will fail.
+ */
+static void CopyInputToRingBuffer(BrotliEncoderState* s,
+ const size_t input_size,
+ const uint8_t* input_buffer) {
+ RingBuffer* ringbuffer_ = &s->ringbuffer_;
+ MemoryManager* m = &s->memory_manager_;
+ RingBufferWrite(m, input_buffer, input_size, ringbuffer_);
+ if (BROTLI_IS_OOM(m)) return;
+ s->input_pos_ += input_size;
+
+ /* TL;DR: If needed, initialize 7 more bytes in the ring buffer to make the
+ hashing not depend on uninitialized data. This makes compression
+ deterministic and it prevents uninitialized memory warnings in Valgrind.
+ Even without erasing, the output would be valid (but nondeterministic).
+
+ Background information: The compressor stores short (at most 8 bytes)
+ substrings of the input already read in a hash table, and detects
+ repetitions by looking up such substrings in the hash table. If it
+ can find a substring, it checks whether the substring is really there
+ in the ring buffer (or it's just a hash collision). Should the hash
+ table become corrupt, this check makes sure that the output is
+ still valid, albeit the compression ratio would be bad.
+
+ The compressor populates the hash table from the ring buffer as it's
+ reading new bytes from the input. However, at the last few indexes of
+ the ring buffer, there are not enough bytes to build full-length
+ substrings from. Since the hash table always contains full-length
+ substrings, we erase with dummy zeros here to make sure that those
+ substrings will contain zeros at the end instead of uninitialized
+ data.
+
+ Please note that erasing is not necessary (because the
+ memory region is already initialized since he ring buffer
+ has a `tail' that holds a copy of the beginning,) so we
+ skip erasing if we have already gone around at least once in
+ the ring buffer.
+
+ Only clear during the first round of ring-buffer writes. On
+ subsequent rounds data in the ring-buffer would be affected. */
+ if (ringbuffer_->pos_ <= ringbuffer_->mask_) {
+ /* This is the first time when the ring buffer is being written.
+ We clear 7 bytes just after the bytes that have been copied from
+ the input buffer.
+
+ The ring-buffer has a "tail" that holds a copy of the beginning,
+ but only once the ring buffer has been fully written once, i.e.,
+ pos <= mask. For the first time, we need to write values
+ in this tail (where index may be larger than mask), so that
+ we have exactly defined behavior and don't read uninitialized
+ memory. Due to performance reasons, hashing reads data using a
+ LOAD64, which can go 7 bytes beyond the bytes written in the
+ ring-buffer. */
+ memset(ringbuffer_->buffer_ + ringbuffer_->pos_, 0, 7);
+ }
+}
+
+/* Marks all input as processed.
+ Returns true if position wrapping occurs. */
+static BROTLI_BOOL UpdateLastProcessedPos(BrotliEncoderState* s) {
+ uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_);
+ uint32_t wrapped_input_pos = WrapPosition(s->input_pos_);
+ s->last_processed_pos_ = s->input_pos_;
+ return TO_BROTLI_BOOL(wrapped_input_pos < wrapped_last_processed_pos);
+}
+
+static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
+ uint32_t* wrapped_last_processed_pos) {
+ Command* last_command = &s->commands_[s->num_commands_ - 1];
+ const uint8_t* data = s->ringbuffer_.buffer_;
+ const uint32_t mask = s->ringbuffer_.mask_;
+ uint64_t max_backward_distance =
+ (((uint64_t)1) << s->params.lgwin) - BROTLI_WINDOW_GAP;
+ uint64_t last_copy_len = last_command->copy_len_ & 0x1FFFFFF;
+ uint64_t last_processed_pos = s->last_processed_pos_ - last_copy_len;
+ uint64_t max_distance = last_processed_pos < max_backward_distance ?
+ last_processed_pos : max_backward_distance;
+ uint64_t cmd_dist = (uint64_t)s->dist_cache_[0];
+ uint32_t distance_code = CommandRestoreDistanceCode(last_command,
+ &s->params.dist);
+ if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES ||
+ distance_code - (BROTLI_NUM_DISTANCE_SHORT_CODES - 1) == cmd_dist) {
+ if (cmd_dist <= max_distance) {
+ while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] ==
+ data[(*wrapped_last_processed_pos - cmd_dist) & mask]) {
+ last_command->copy_len_++;
+ (*bytes)--;
+ (*wrapped_last_processed_pos)++;
+ }
+ } else {
+ }
+ /* The copy length is at most the metablock size, and thus expressible. */
+ GetLengthCode(last_command->insert_len_,
+ (size_t)((int)(last_command->copy_len_ & 0x1FFFFFF) +
+ (int)(last_command->copy_len_ >> 25)),
+ TO_BROTLI_BOOL((last_command->dist_prefix_ & 0x3FF) == 0),
+ &last_command->cmd_prefix_);
+ }
+}
+
+/*
+ Processes the accumulated input data and sets |*out_size| to the length of
+ the new output meta-block, or to zero if no new output meta-block has been
+ created (in this case the processed input data is buffered internally).
+ If |*out_size| is positive, |*output| points to the start of the output
+ data. If |is_last| or |force_flush| is BROTLI_TRUE, an output meta-block is
+ always created. However, until |is_last| is BROTLI_TRUE encoder may retain up
+ to 7 bits of the last byte of output. To force encoder to dump the remaining
+ bits use WriteMetadata() to append an empty meta-data block.
+ Returns BROTLI_FALSE if the size of the input data is larger than
+ input_block_size().
+ */
+static BROTLI_BOOL EncodeData(
+ BrotliEncoderState* s, const BROTLI_BOOL is_last,
+ const BROTLI_BOOL force_flush, size_t* out_size, uint8_t** output) {
+ const uint64_t delta = UnprocessedInputSize(s);
+ uint32_t bytes = (uint32_t)delta;
+ uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_);
+ uint8_t* data;
+ uint32_t mask;
+ MemoryManager* m = &s->memory_manager_;
+ ContextType literal_context_mode;
+ ContextLut literal_context_lut;
+
+ data = s->ringbuffer_.buffer_;
+ mask = s->ringbuffer_.mask_;
+
+ /* Adding more blocks after "last" block is forbidden. */
+ if (s->is_last_block_emitted_) return BROTLI_FALSE;
+ if (is_last) s->is_last_block_emitted_ = BROTLI_TRUE;
+
+ if (delta > InputBlockSize(s)) {
+ return BROTLI_FALSE;
+ }
+ if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY &&
+ !s->command_buf_) {
+ s->command_buf_ =
+ BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
+ s->literal_buf_ =
+ BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
+ BROTLI_IS_NULL(s->literal_buf_)) {
+ return BROTLI_FALSE;
+ }
+ }
+
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
+ s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ uint8_t* storage;
+ size_t storage_ix = s->last_bytes_bits_;
+ size_t table_size;
+ int* table;
+
+ if (delta == 0 && !is_last) {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ *out_size = 0;
+ return BROTLI_TRUE;
+ }
+ storage = GetBrotliStorage(s, 2 * bytes + 503);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ storage[0] = (uint8_t)s->last_bytes_;
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
+ table = GetHashTable(s, s->params.quality, bytes, &table_size);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
+ BrotliCompressFragmentFast(
+ m, &data[wrapped_last_processed_pos & mask],
+ bytes, is_last,
+ table, table_size,
+ s->cmd_depths_, s->cmd_bits_,
+ &s->cmd_code_numbits_, s->cmd_code_,
+ &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ } else {
+ BrotliCompressFragmentTwoPass(
+ m, &data[wrapped_last_processed_pos & mask],
+ bytes, is_last,
+ s->command_buf_, s->literal_buf_,
+ table, table_size,
+ &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ }
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
+ s->last_bytes_bits_ = storage_ix & 7u;
+ UpdateLastProcessedPos(s);
+ *output = &storage[0];
+ *out_size = storage_ix >> 3;
+ return BROTLI_TRUE;
+ }
+
+ {
+ /* Theoretical max number of commands is 1 per 2 bytes. */
+ size_t newsize = s->num_commands_ + bytes / 2 + 1;
+ if (newsize > s->cmd_alloc_size_) {
+ Command* new_commands;
+ /* Reserve a bit more memory to allow merging with a next block
+ without reallocation: that would impact speed. */
+ newsize += (bytes / 4) + 16;
+ s->cmd_alloc_size_ = newsize;
+ new_commands = BROTLI_ALLOC(m, Command, newsize);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
+ if (s->commands_) {
+ memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
+ BROTLI_FREE(m, s->commands_);
+ }
+ s->commands_ = new_commands;
+ }
+ }
+
+ InitOrStitchToPreviousBlock(m, &s->hasher_, data, mask, &s->params,
+ wrapped_last_processed_pos, bytes, is_last);
+
+ literal_context_mode = ChooseContextMode(
+ &s->params, data, WrapPosition(s->last_flush_pos_),
+ mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
+ literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
+
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+
+ if (s->num_commands_ && s->last_insert_len_ == 0) {
+ ExtendLastCommand(s, &bytes, &wrapped_last_processed_pos);
+ }
+
+ if (s->params.quality == ZOPFLIFICATION_QUALITY) {
+ BROTLI_DCHECK(s->params.hasher.type == 10);
+ BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
+ data, mask, literal_context_lut, &s->params,
+ &s->hasher_, s->dist_cache_,
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
+ &s->num_commands_, &s->num_literals_);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
+ BROTLI_DCHECK(s->params.hasher.type == 10);
+ BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
+ data, mask, literal_context_lut, &s->params,
+ &s->hasher_, s->dist_cache_,
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
+ &s->num_commands_, &s->num_literals_);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ } else {
+ BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
+ data, mask, literal_context_lut, &s->params,
+ &s->hasher_, s->dist_cache_,
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
+ &s->num_commands_, &s->num_literals_);
+ }
+
+ {
+ const size_t max_length = MaxMetablockSize(&s->params);
+ const size_t max_literals = max_length / 8;
+ const size_t max_commands = max_length / 8;
+ const size_t processed_bytes = (size_t)(s->input_pos_ - s->last_flush_pos_);
+ /* If maximal possible additional block doesn't fit metablock, flush now. */
+ /* TODO: Postpone decision until next block arrives? */
+ const BROTLI_BOOL next_input_fits_metablock = TO_BROTLI_BOOL(
+ processed_bytes + InputBlockSize(s) <= max_length);
+ /* If block splitting is not used, then flush as soon as there is some
+ amount of commands / literals produced. */
+ const BROTLI_BOOL should_flush = TO_BROTLI_BOOL(
+ s->params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT &&
+ s->num_literals_ + s->num_commands_ >= MAX_NUM_DELAYED_SYMBOLS);
+ if (!is_last && !force_flush && !should_flush &&
+ next_input_fits_metablock &&
+ s->num_literals_ < max_literals &&
+ s->num_commands_ < max_commands) {
+ /* Merge with next input block. Everything will happen later. */
+ if (UpdateLastProcessedPos(s)) {
+ HasherReset(&s->hasher_);
+ }
+ *out_size = 0;
+ return BROTLI_TRUE;
+ }
+ }
+
+ /* Create the last insert-only command. */
+ if (s->last_insert_len_ > 0) {
+ InitInsertCommand(&s->commands_[s->num_commands_++], s->last_insert_len_);
+ s->num_literals_ += s->last_insert_len_;
+ s->last_insert_len_ = 0;
+ }
+
+ if (!is_last && s->input_pos_ == s->last_flush_pos_) {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ *out_size = 0;
+ return BROTLI_TRUE;
+ }
+ BROTLI_DCHECK(s->input_pos_ >= s->last_flush_pos_);
+ BROTLI_DCHECK(s->input_pos_ > s->last_flush_pos_ || is_last);
+ BROTLI_DCHECK(s->input_pos_ - s->last_flush_pos_ <= 1u << 24);
+ {
+ const uint32_t metablock_size =
+ (uint32_t)(s->input_pos_ - s->last_flush_pos_);
+ uint8_t* storage = GetBrotliStorage(s, 2 * metablock_size + 503);
+ size_t storage_ix = s->last_bytes_bits_;
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ storage[0] = (uint8_t)s->last_bytes_;
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
+ WriteMetaBlockInternal(
+ m, data, mask, s->last_flush_pos_, metablock_size, is_last,
+ literal_context_mode, &s->params, s->prev_byte_, s->prev_byte2_,
+ s->num_literals_, s->num_commands_, s->commands_, s->saved_dist_cache_,
+ s->dist_cache_, &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
+ s->last_bytes_bits_ = storage_ix & 7u;
+ s->last_flush_pos_ = s->input_pos_;
+ if (UpdateLastProcessedPos(s)) {
+ HasherReset(&s->hasher_);
+ }
+ if (s->last_flush_pos_ > 0) {
+ s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
+ }
+ if (s->last_flush_pos_ > 1) {
+ s->prev_byte2_ = data[(uint32_t)(s->last_flush_pos_ - 2) & mask];
+ }
+ s->num_commands_ = 0;
+ s->num_literals_ = 0;
+ /* Save the state of the distance cache in case we need to restore it for
+ emitting an uncompressed block. */
+ memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
+ *output = &storage[0];
+ *out_size = storage_ix >> 3;
+ return BROTLI_TRUE;
+ }
+}
+
+/* Dumps remaining output bits and metadata header to |header|.
+ Returns number of produced bytes.
+ REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long.
+ REQUIRED: |block_size| <= (1 << 24). */
+static size_t WriteMetadataHeader(
+ BrotliEncoderState* s, const size_t block_size, uint8_t* header) {
+ size_t storage_ix;
+ storage_ix = s->last_bytes_bits_;
+ header[0] = (uint8_t)s->last_bytes_;
+ header[1] = (uint8_t)(s->last_bytes_ >> 8);
+ s->last_bytes_ = 0;
+ s->last_bytes_bits_ = 0;
+
+ BrotliWriteBits(1, 0, &storage_ix, header);
+ BrotliWriteBits(2, 3, &storage_ix, header);
+ BrotliWriteBits(1, 0, &storage_ix, header);
+ if (block_size == 0) {
+ BrotliWriteBits(2, 0, &storage_ix, header);
+ } else {
+ uint32_t nbits = (block_size == 1) ? 0 :
+ (Log2FloorNonZero((uint32_t)block_size - 1) + 1);
+ uint32_t nbytes = (nbits + 7) / 8;
+ BrotliWriteBits(2, nbytes, &storage_ix, header);
+ BrotliWriteBits(8 * nbytes, block_size - 1, &storage_ix, header);
+ }
+ return (storage_ix + 7u) >> 3;
+}
+
+static BROTLI_BOOL BrotliCompressBufferQuality10(
+ int lgwin, size_t input_size, const uint8_t* input_buffer,
+ size_t* encoded_size, uint8_t* encoded_buffer) {
+ MemoryManager memory_manager;
+ MemoryManager* m = &memory_manager;
+
+ const size_t mask = BROTLI_SIZE_MAX >> 1;
+ int dist_cache[4] = { 4, 11, 15, 16 };
+ int saved_dist_cache[4] = { 4, 11, 15, 16 };
+ BROTLI_BOOL ok = BROTLI_TRUE;
+ const size_t max_out_size = *encoded_size;
+ size_t total_out_size = 0;
+ uint16_t last_bytes;
+ uint8_t last_bytes_bits;
+
+ const size_t hasher_eff_size = BROTLI_MIN(size_t,
+ input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
+
+ BrotliEncoderParams params;
+
+ const int lgmetablock = BROTLI_MIN(int, 24, lgwin + 1);
+ size_t max_block_size;
+ const size_t max_metablock_size = (size_t)1 << lgmetablock;
+ const size_t max_literals_per_metablock = max_metablock_size / 8;
+ const size_t max_commands_per_metablock = max_metablock_size / 8;
+ size_t metablock_start = 0;
+ uint8_t prev_byte = 0;
+ uint8_t prev_byte2 = 0;
+
+ Hasher hasher;
+ HasherInit(&hasher);
+
+ BrotliEncoderInitParams(&params);
+ params.quality = 10;
+ params.lgwin = lgwin;
+ if (lgwin > BROTLI_MAX_WINDOW_BITS) {
+ params.large_window = BROTLI_TRUE;
+ }
+ SanitizeParams(&params);
+ params.lgblock = ComputeLgBlock(&params);
+ ChooseDistanceParams(&params);
+ max_block_size = (size_t)1 << params.lgblock;
+
+ BrotliInitMemoryManager(m, 0, 0, 0);
+
+ BROTLI_DCHECK(input_size <= mask + 1);
+ EncodeWindowBits(lgwin, params.large_window, &last_bytes, &last_bytes_bits);
+ InitOrStitchToPreviousBlock(m, &hasher, input_buffer, mask, &params,
+ 0, hasher_eff_size, BROTLI_TRUE);
+ if (BROTLI_IS_OOM(m)) goto oom;
+
+ while (ok && metablock_start < input_size) {
+ const size_t metablock_end =
+ BROTLI_MIN(size_t, input_size, metablock_start + max_metablock_size);
+ const size_t expected_num_commands =
+ (metablock_end - metablock_start) / 12 + 16;
+ Command* commands = 0;
+ size_t num_commands = 0;
+ size_t last_insert_len = 0;
+ size_t num_literals = 0;
+ size_t metablock_size = 0;
+ size_t cmd_alloc_size = 0;
+ BROTLI_BOOL is_last;
+ uint8_t* storage;
+ size_t storage_ix;
+
+ ContextType literal_context_mode = ChooseContextMode(&params,
+ input_buffer, metablock_start, mask, metablock_end - metablock_start);
+ ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
+
+ size_t block_start;
+ for (block_start = metablock_start; block_start < metablock_end; ) {
+ size_t block_size =
+ BROTLI_MIN(size_t, metablock_end - block_start, max_block_size);
+ ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
+ size_t path_size;
+ size_t new_cmd_alloc_size;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
+ BrotliInitZopfliNodes(nodes, block_size + 1);
+ StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start,
+ input_buffer, mask);
+ path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
+ input_buffer, mask, literal_context_lut, &params, dist_cache, &hasher,
+ nodes);
+ if (BROTLI_IS_OOM(m)) goto oom;
+ /* We allocate a command buffer in the first iteration of this loop that
+ will be likely big enough for the whole metablock, so that for most
+ inputs we will not have to reallocate in later iterations. We do the
+ allocation here and not before the loop, because if the input is small,
+ this will be allocated after the Zopfli cost model is freed, so this
+ will not increase peak memory usage.
+ TODO: If the first allocation is too small, increase command
+ buffer size exponentially. */
+ new_cmd_alloc_size = BROTLI_MAX(size_t, expected_num_commands,
+ num_commands + path_size + 1);
+ if (cmd_alloc_size != new_cmd_alloc_size) {
+ Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
+ cmd_alloc_size = new_cmd_alloc_size;
+ if (commands) {
+ memcpy(new_commands, commands, sizeof(Command) * num_commands);
+ BROTLI_FREE(m, commands);
+ }
+ commands = new_commands;
+ }
+ BrotliZopfliCreateCommands(block_size, block_start, &nodes[0], dist_cache,
+ &last_insert_len, &params, &commands[num_commands], &num_literals);
+ num_commands += path_size;
+ block_start += block_size;
+ metablock_size += block_size;
+ BROTLI_FREE(m, nodes);
+ if (num_literals > max_literals_per_metablock ||
+ num_commands > max_commands_per_metablock) {
+ break;
+ }
+ }
+
+ if (last_insert_len > 0) {
+ InitInsertCommand(&commands[num_commands++], last_insert_len);
+ num_literals += last_insert_len;
+ }
+
+ is_last = TO_BROTLI_BOOL(metablock_start + metablock_size == input_size);
+ storage = NULL;
+ storage_ix = last_bytes_bits;
+
+ if (metablock_size == 0) {
+ /* Write the ISLAST and ISEMPTY bits. */
+ storage = BROTLI_ALLOC(m, uint8_t, 16);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
+ storage[0] = (uint8_t)last_bytes;
+ storage[1] = (uint8_t)(last_bytes >> 8);
+ BrotliWriteBits(2, 3, &storage_ix, storage);
+ storage_ix = (storage_ix + 7u) & ~7u;
+ } else if (!ShouldCompress(input_buffer, mask, metablock_start,
+ metablock_size, num_literals, num_commands)) {
+ /* Restore the distance cache, as its last update by
+ CreateBackwardReferences is now unused. */
+ memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
+ storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
+ storage[0] = (uint8_t)last_bytes;
+ storage[1] = (uint8_t)(last_bytes >> 8);
+ BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
+ metablock_start, mask, metablock_size,
+ &storage_ix, storage);
+ } else {
+ MetaBlockSplit mb;
+ BrotliEncoderParams block_params = params;
+ InitMetaBlockSplit(&mb);
+ BrotliBuildMetaBlock(m, input_buffer, metablock_start, mask,
+ &block_params,
+ prev_byte, prev_byte2,
+ commands, num_commands,
+ literal_context_mode,
+ &mb);
+ if (BROTLI_IS_OOM(m)) goto oom;
+ {
+ /* The number of distance symbols effectively used for distance
+ histograms. It might be less than distance alphabet size
+ for "Large Window Brotli" (32-bit). */
+ BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
+ }
+ storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
+ storage[0] = (uint8_t)last_bytes;
+ storage[1] = (uint8_t)(last_bytes >> 8);
+ BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
+ mask, prev_byte, prev_byte2,
+ is_last,
+ &block_params,
+ literal_context_mode,
+ commands, num_commands,
+ &mb,
+ &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) goto oom;
+ if (metablock_size + 4 < (storage_ix >> 3)) {
+ /* Restore the distance cache and last byte. */
+ memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
+ storage[0] = (uint8_t)last_bytes;
+ storage[1] = (uint8_t)(last_bytes >> 8);
+ storage_ix = last_bytes_bits;
+ BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
+ metablock_start, mask,
+ metablock_size, &storage_ix, storage);
+ }
+ DestroyMetaBlockSplit(m, &mb);
+ }
+ last_bytes = (uint16_t)(storage[storage_ix >> 3]);
+ last_bytes_bits = storage_ix & 7u;
+ metablock_start += metablock_size;
+ if (metablock_start < input_size) {
+ prev_byte = input_buffer[metablock_start - 1];
+ prev_byte2 = input_buffer[metablock_start - 2];
+ }
+ /* Save the state of the distance cache in case we need to restore it for
+ emitting an uncompressed block. */
+ memcpy(saved_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
+
+ {
+ const size_t out_size = storage_ix >> 3;
+ total_out_size += out_size;
+ if (total_out_size <= max_out_size) {
+ memcpy(encoded_buffer, storage, out_size);
+ encoded_buffer += out_size;
+ } else {
+ ok = BROTLI_FALSE;
+ }
+ }
+ BROTLI_FREE(m, storage);
+ BROTLI_FREE(m, commands);
+ }
+
+ *encoded_size = total_out_size;
+ DestroyHasher(m, &hasher);
+ return ok;
+
+oom:
+ BrotliWipeOutMemoryManager(m);
+ return BROTLI_FALSE;
+}
+
+size_t BrotliEncoderMaxCompressedSize(size_t input_size) {
+ /* [window bits / empty metadata] + N * [uncompressed] + [last empty] */
+ size_t num_large_blocks = input_size >> 14;
+ size_t overhead = 2 + (4 * num_large_blocks) + 3 + 1;
+ size_t result = input_size + overhead;
+ if (input_size == 0) return 2;
+ return (result < input_size) ? 0 : result;
+}
+
+/* Wraps data to uncompressed brotli stream with minimal window size.
+ |output| should point at region with at least BrotliEncoderMaxCompressedSize
+ addressable bytes.
+ Returns the length of stream. */
+static size_t MakeUncompressedStream(
+ const uint8_t* input, size_t input_size, uint8_t* output) {
+ size_t size = input_size;
+ size_t result = 0;
+ size_t offset = 0;
+ if (input_size == 0) {
+ output[0] = 6;
+ return 1;
+ }
+ output[result++] = 0x21; /* window bits = 10, is_last = false */
+ output[result++] = 0x03; /* empty metadata, padding */
+ while (size > 0) {
+ uint32_t nibbles = 0;
+ uint32_t chunk_size;
+ uint32_t bits;
+ chunk_size = (size > (1u << 24)) ? (1u << 24) : (uint32_t)size;
+ if (chunk_size > (1u << 16)) nibbles = (chunk_size > (1u << 20)) ? 2 : 1;
+ bits =
+ (nibbles << 1) | ((chunk_size - 1) << 3) | (1u << (19 + 4 * nibbles));
+ output[result++] = (uint8_t)bits;
+ output[result++] = (uint8_t)(bits >> 8);
+ output[result++] = (uint8_t)(bits >> 16);
+ if (nibbles == 2) output[result++] = (uint8_t)(bits >> 24);
+ memcpy(&output[result], &input[offset], chunk_size);
+ result += chunk_size;
+ offset += chunk_size;
+ size -= chunk_size;
+ }
+ output[result++] = 3;
+ return result;
+}
+
+BROTLI_BOOL BrotliEncoderCompress(
+ int quality, int lgwin, BrotliEncoderMode mode, size_t input_size,
+ const uint8_t* input_buffer, size_t* encoded_size,
+ uint8_t* encoded_buffer) {
+ BrotliEncoderState* s;
+ size_t out_size = *encoded_size;
+ const uint8_t* input_start = input_buffer;
+ uint8_t* output_start = encoded_buffer;
+ size_t max_out_size = BrotliEncoderMaxCompressedSize(input_size);
+ if (out_size == 0) {
+ /* Output buffer needs at least one byte. */
+ return BROTLI_FALSE;
+ }
+ if (input_size == 0) {
+ /* Handle the special case of empty input. */
+ *encoded_size = 1;
+ *encoded_buffer = 6;
+ return BROTLI_TRUE;
+ }
+ if (quality == 10) {
+ /* TODO: Implement this direct path for all quality levels. */
+ const int lg_win = BROTLI_MIN(int, BROTLI_LARGE_MAX_WINDOW_BITS,
+ BROTLI_MAX(int, 16, lgwin));
+ int ok = BrotliCompressBufferQuality10(lg_win, input_size, input_buffer,
+ encoded_size, encoded_buffer);
+ if (!ok || (max_out_size && *encoded_size > max_out_size)) {
+ goto fallback;
+ }
+ return BROTLI_TRUE;
+ }
+
+ s = BrotliEncoderCreateInstance(0, 0, 0);
+ if (!s) {
+ return BROTLI_FALSE;
+ } else {
+ size_t available_in = input_size;
+ const uint8_t* next_in = input_buffer;
+ size_t available_out = *encoded_size;
+ uint8_t* next_out = encoded_buffer;
+ size_t total_out = 0;
+ BROTLI_BOOL result = BROTLI_FALSE;
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)quality);
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, (uint32_t)mode);
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, (uint32_t)input_size);
+ if (lgwin > BROTLI_MAX_WINDOW_BITS) {
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE);
+ }
+ result = BrotliEncoderCompressStream(s, BROTLI_OPERATION_FINISH,
+ &available_in, &next_in, &available_out, &next_out, &total_out);
+ if (!BrotliEncoderIsFinished(s)) result = 0;
+ *encoded_size = total_out;
+ BrotliEncoderDestroyInstance(s);
+ if (!result || (max_out_size && *encoded_size > max_out_size)) {
+ goto fallback;
+ }
+ return BROTLI_TRUE;
+ }
+fallback:
+ *encoded_size = 0;
+ if (!max_out_size) return BROTLI_FALSE;
+ if (out_size >= max_out_size) {
+ *encoded_size =
+ MakeUncompressedStream(input_start, input_size, output_start);
+ return BROTLI_TRUE;
+ }
+ return BROTLI_FALSE;
+}
+
+static void InjectBytePaddingBlock(BrotliEncoderState* s) {
+ uint32_t seal = s->last_bytes_;
+ size_t seal_bits = s->last_bytes_bits_;
+ uint8_t* destination;
+ s->last_bytes_ = 0;
+ s->last_bytes_bits_ = 0;
+ /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */
+ seal |= 0x6u << seal_bits;
+ seal_bits += 6;
+ /* If we have already created storage, then append to it.
+ Storage is valid until next block is being compressed. */
+ if (s->next_out_) {
+ destination = s->next_out_ + s->available_out_;
+ } else {
+ destination = s->tiny_buf_.u8;
+ s->next_out_ = destination;
+ }
+ destination[0] = (uint8_t)seal;
+ if (seal_bits > 8) destination[1] = (uint8_t)(seal >> 8);
+ if (seal_bits > 16) destination[2] = (uint8_t)(seal >> 16);
+ s->available_out_ += (seal_bits + 7) >> 3;
+}
+
+/* Injects padding bits or pushes compressed data to output.
+ Returns false if nothing is done. */
+static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s,
+ size_t* available_out, uint8_t** next_out, size_t* total_out) {
+ if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED &&
+ s->last_bytes_bits_ != 0) {
+ InjectBytePaddingBlock(s);
+ return BROTLI_TRUE;
+ }
+
+ if (s->available_out_ != 0 && *available_out != 0) {
+ size_t copy_output_size =
+ BROTLI_MIN(size_t, s->available_out_, *available_out);
+ memcpy(*next_out, s->next_out_, copy_output_size);
+ *next_out += copy_output_size;
+ *available_out -= copy_output_size;
+ s->next_out_ += copy_output_size;
+ s->available_out_ -= copy_output_size;
+ s->total_out_ += copy_output_size;
+ if (total_out) *total_out = s->total_out_;
+ return BROTLI_TRUE;
+ }
+
+ return BROTLI_FALSE;
+}
+
+static void CheckFlushComplete(BrotliEncoderState* s) {
+ if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED &&
+ s->available_out_ == 0) {
+ s->stream_state_ = BROTLI_STREAM_PROCESSING;
+ s->next_out_ = 0;
+ }
+}
+
+static BROTLI_BOOL BrotliEncoderCompressStreamFast(
+ BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in,
+ const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
+ size_t* total_out) {
+ const size_t block_size_limit = (size_t)1 << s->params.lgwin;
+ const size_t buf_size = BROTLI_MIN(size_t, kCompressFragmentTwoPassBlockSize,
+ BROTLI_MIN(size_t, *available_in, block_size_limit));
+ uint32_t* tmp_command_buf = NULL;
+ uint32_t* command_buf = NULL;
+ uint8_t* tmp_literal_buf = NULL;
+ uint8_t* literal_buf = NULL;
+ MemoryManager* m = &s->memory_manager_;
+ if (s->params.quality != FAST_ONE_PASS_COMPRESSION_QUALITY &&
+ s->params.quality != FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ return BROTLI_FALSE;
+ }
+ if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ if (!s->command_buf_ && buf_size == kCompressFragmentTwoPassBlockSize) {
+ s->command_buf_ =
+ BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
+ s->literal_buf_ =
+ BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
+ BROTLI_IS_NULL(s->literal_buf_)) {
+ return BROTLI_FALSE;
+ }
+ }
+ if (s->command_buf_) {
+ command_buf = s->command_buf_;
+ literal_buf = s->literal_buf_;
+ } else {
+ tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
+ tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
+ BROTLI_IS_NULL(tmp_literal_buf)) {
+ return BROTLI_FALSE;
+ }
+ command_buf = tmp_command_buf;
+ literal_buf = tmp_literal_buf;
+ }
+ }
+
+ while (BROTLI_TRUE) {
+ if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
+ continue;
+ }
+
+ /* Compress block only when internal output buffer is empty, stream is not
+ finished, there is no pending flush request, and there is either
+ additional input or pending operation. */
+ if (s->available_out_ == 0 &&
+ s->stream_state_ == BROTLI_STREAM_PROCESSING &&
+ (*available_in != 0 || op != BROTLI_OPERATION_PROCESS)) {
+ size_t block_size = BROTLI_MIN(size_t, block_size_limit, *available_in);
+ BROTLI_BOOL is_last =
+ (*available_in == block_size) && (op == BROTLI_OPERATION_FINISH);
+ BROTLI_BOOL force_flush =
+ (*available_in == block_size) && (op == BROTLI_OPERATION_FLUSH);
+ size_t max_out_size = 2 * block_size + 503;
+ BROTLI_BOOL inplace = BROTLI_TRUE;
+ uint8_t* storage = NULL;
+ size_t storage_ix = s->last_bytes_bits_;
+ size_t table_size;
+ int* table;
+
+ if (force_flush && block_size == 0) {
+ s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
+ continue;
+ }
+ if (max_out_size <= *available_out) {
+ storage = *next_out;
+ } else {
+ inplace = BROTLI_FALSE;
+ storage = GetBrotliStorage(s, max_out_size);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ }
+ storage[0] = (uint8_t)s->last_bytes_;
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
+ table = GetHashTable(s, s->params.quality, block_size, &table_size);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
+ BrotliCompressFragmentFast(m, *next_in, block_size, is_last, table,
+ table_size, s->cmd_depths_, s->cmd_bits_, &s->cmd_code_numbits_,
+ s->cmd_code_, &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ } else {
+ BrotliCompressFragmentTwoPass(m, *next_in, block_size, is_last,
+ command_buf, literal_buf, table, table_size,
+ &storage_ix, storage);
+ if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+ }
+ *next_in += block_size;
+ *available_in -= block_size;
+ if (inplace) {
+ size_t out_bytes = storage_ix >> 3;
+ BROTLI_DCHECK(out_bytes <= *available_out);
+ BROTLI_DCHECK((storage_ix & 7) == 0 || out_bytes < *available_out);
+ *next_out += out_bytes;
+ *available_out -= out_bytes;
+ s->total_out_ += out_bytes;
+ if (total_out) *total_out = s->total_out_;
+ } else {
+ size_t out_bytes = storage_ix >> 3;
+ s->next_out_ = storage;
+ s->available_out_ = out_bytes;
+ }
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
+ s->last_bytes_bits_ = storage_ix & 7u;
+
+ if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
+ if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED;
+ continue;
+ }
+ break;
+ }
+ BROTLI_FREE(m, tmp_command_buf);
+ BROTLI_FREE(m, tmp_literal_buf);
+ CheckFlushComplete(s);
+ return BROTLI_TRUE;
+}
+
+static BROTLI_BOOL ProcessMetadata(
+ BrotliEncoderState* s, size_t* available_in, const uint8_t** next_in,
+ size_t* available_out, uint8_t** next_out, size_t* total_out) {
+ if (*available_in > (1u << 24)) return BROTLI_FALSE;
+ /* Switch to metadata block workflow, if required. */
+ if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
+ s->remaining_metadata_bytes_ = (uint32_t)*available_in;
+ s->stream_state_ = BROTLI_STREAM_METADATA_HEAD;
+ }
+ if (s->stream_state_ != BROTLI_STREAM_METADATA_HEAD &&
+ s->stream_state_ != BROTLI_STREAM_METADATA_BODY) {
+ return BROTLI_FALSE;
+ }
+
+ while (BROTLI_TRUE) {
+ if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
+ continue;
+ }
+ if (s->available_out_ != 0) break;
+
+ if (s->input_pos_ != s->last_flush_pos_) {
+ BROTLI_BOOL result = EncodeData(s, BROTLI_FALSE, BROTLI_TRUE,
+ &s->available_out_, &s->next_out_);
+ if (!result) return BROTLI_FALSE;
+ continue;
+ }
+
+ if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD) {
+ s->next_out_ = s->tiny_buf_.u8;
+ s->available_out_ =
+ WriteMetadataHeader(s, s->remaining_metadata_bytes_, s->next_out_);
+ s->stream_state_ = BROTLI_STREAM_METADATA_BODY;
+ continue;
+ } else {
+ /* Exit workflow only when there is no more input and no more output.
+ Otherwise client may continue producing empty metadata blocks. */
+ if (s->remaining_metadata_bytes_ == 0) {
+ s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
+ s->stream_state_ = BROTLI_STREAM_PROCESSING;
+ break;
+ }
+ if (*available_out) {
+ /* Directly copy input to output. */
+ uint32_t copy = (uint32_t)BROTLI_MIN(
+ size_t, s->remaining_metadata_bytes_, *available_out);
+ memcpy(*next_out, *next_in, copy);
+ *next_in += copy;
+ *available_in -= copy;
+ s->remaining_metadata_bytes_ -= copy;
+ *next_out += copy;
+ *available_out -= copy;
+ } else {
+ /* This guarantees progress in "TakeOutput" workflow. */
+ uint32_t copy = BROTLI_MIN(uint32_t, s->remaining_metadata_bytes_, 16);
+ s->next_out_ = s->tiny_buf_.u8;
+ memcpy(s->next_out_, *next_in, copy);
+ *next_in += copy;
+ *available_in -= copy;
+ s->remaining_metadata_bytes_ -= copy;
+ s->available_out_ = copy;
+ }
+ continue;
+ }
+ }
+
+ return BROTLI_TRUE;
+}
+
+static void UpdateSizeHint(BrotliEncoderState* s, size_t available_in) {
+ if (s->params.size_hint == 0) {
+ uint64_t delta = UnprocessedInputSize(s);
+ uint64_t tail = available_in;
+ uint32_t limit = 1u << 30;
+ uint32_t total;
+ if ((delta >= limit) || (tail >= limit) || ((delta + tail) >= limit)) {
+ total = limit;
+ } else {
+ total = (uint32_t)(delta + tail);
+ }
+ s->params.size_hint = total;
+ }
+}
+
+BROTLI_BOOL BrotliEncoderCompressStream(
+ BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in,
+ const uint8_t** next_in, size_t* available_out,uint8_t** next_out,
+ size_t* total_out) {
+ if (!EnsureInitialized(s)) return BROTLI_FALSE;
+
+ /* Unfinished metadata block; check requirements. */
+ if (s->remaining_metadata_bytes_ != BROTLI_UINT32_MAX) {
+ if (*available_in != s->remaining_metadata_bytes_) return BROTLI_FALSE;
+ if (op != BROTLI_OPERATION_EMIT_METADATA) return BROTLI_FALSE;
+ }
+
+ if (op == BROTLI_OPERATION_EMIT_METADATA) {
+ UpdateSizeHint(s, 0); /* First data metablock might be emitted here. */
+ return ProcessMetadata(
+ s, available_in, next_in, available_out, next_out, total_out);
+ }
+
+ if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD ||
+ s->stream_state_ == BROTLI_STREAM_METADATA_BODY) {
+ return BROTLI_FALSE;
+ }
+
+ if (s->stream_state_ != BROTLI_STREAM_PROCESSING && *available_in != 0) {
+ return BROTLI_FALSE;
+ }
+ if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
+ s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ return BrotliEncoderCompressStreamFast(s, op, available_in, next_in,
+ available_out, next_out, total_out);
+ }
+ while (BROTLI_TRUE) {
+ size_t remaining_block_size = RemainingInputBlockSize(s);
+ /* Shorten input to flint size. */
+ if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
+ remaining_block_size = (size_t)s->flint_;
+ }
+
+ if (remaining_block_size != 0 && *available_in != 0) {
+ size_t copy_input_size =
+ BROTLI_MIN(size_t, remaining_block_size, *available_in);
+ CopyInputToRingBuffer(s, copy_input_size, *next_in);
+ *next_in += copy_input_size;
+ *available_in -= copy_input_size;
+ if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
+ continue;
+ }
+
+ if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
+ /* Exit the "emit flint" workflow. */
+ if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
+ CheckFlushComplete(s);
+ if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
+ s->flint_ = BROTLI_FLINT_DONE;
+ }
+ }
+ continue;
+ }
+
+ /* Compress data only when internal output buffer is empty, stream is not
+ finished and there is no pending flush request. */
+ if (s->available_out_ == 0 &&
+ s->stream_state_ == BROTLI_STREAM_PROCESSING) {
+ if (remaining_block_size == 0 || op != BROTLI_OPERATION_PROCESS) {
+ BROTLI_BOOL is_last = TO_BROTLI_BOOL(
+ (*available_in == 0) && op == BROTLI_OPERATION_FINISH);
+ BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
+ (*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
+ BROTLI_BOOL result;
+ /* Force emitting (uncompressed) piece containing flint. */
+ if (!is_last && s->flint_ == 0) {
+ s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
+ force_flush = BROTLI_TRUE;
+ }
+ UpdateSizeHint(s, *available_in);
+ result = EncodeData(s, is_last, force_flush,
+ &s->available_out_, &s->next_out_);
+ if (!result) return BROTLI_FALSE;
+ if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
+ if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED;
+ continue;
+ }
+ }
+ break;
+ }
+ CheckFlushComplete(s);
+ return BROTLI_TRUE;
+}
+
+BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* s) {
+ return TO_BROTLI_BOOL(s->stream_state_ == BROTLI_STREAM_FINISHED &&
+ !BrotliEncoderHasMoreOutput(s));
+}
+
+BROTLI_BOOL BrotliEncoderHasMoreOutput(BrotliEncoderState* s) {
+ return TO_BROTLI_BOOL(s->available_out_ != 0);
+}
+
+const uint8_t* BrotliEncoderTakeOutput(BrotliEncoderState* s, size_t* size) {
+ size_t consumed_size = s->available_out_;
+ uint8_t* result = s->next_out_;
+ if (*size) {
+ consumed_size = BROTLI_MIN(size_t, *size, s->available_out_);
+ }
+ if (consumed_size) {
+ s->next_out_ += consumed_size;
+ s->available_out_ -= consumed_size;
+ s->total_out_ += consumed_size;
+ CheckFlushComplete(s);
+ *size = consumed_size;
+ } else {
+ *size = 0;
+ result = 0;
+ }
+ return result;
+}
+
+uint32_t BrotliEncoderVersion(void) {
+ return BROTLI_VERSION;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.c
new file mode 100755
index 000000000..c9e963b89
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.c
@@ -0,0 +1,33 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./encoder_dict.h"
+
+#include "../common/dictionary.h"
+#include "../common/transform.h"
+#include "./dictionary_hash.h"
+#include "./hash.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
+ dict->words = BrotliGetDictionary();
+ dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
+
+ dict->hash_table_words = kStaticDictionaryHashWords;
+ dict->hash_table_lengths = kStaticDictionaryHashLengths;
+ dict->buckets = kStaticDictionaryBuckets;
+ dict->dict_words = kStaticDictionaryWords;
+
+ dict->cutoffTransformsCount = kCutoffTransformsCount;
+ dict->cutoffTransforms = kCutoffTransforms;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.h
new file mode 100755
index 000000000..a1c329fbf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/encoder_dict.h
@@ -0,0 +1,43 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#ifndef BROTLI_ENC_ENCODER_DICT_H_
+#define BROTLI_ENC_ENCODER_DICT_H_
+
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./static_dict_lut.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Dictionary data (words and transforms) for 1 possible context */
+typedef struct BrotliEncoderDictionary {
+ const BrotliDictionary* words;
+ uint32_t num_transforms;
+
+ /* cut off for fast encoder */
+ uint32_t cutoffTransformsCount;
+ uint64_t cutoffTransforms;
+
+ /* from dictionary_hash.h, for fast encoder */
+ const uint16_t* hash_table_words;
+ const uint8_t* hash_table_lengths;
+
+ /* from static_dict_lut.h, for slow encoder */
+ const uint16_t* buckets;
+ const DictWord* dict_words;
+} BrotliEncoderDictionary;
+
+BROTLI_INTERNAL void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_ENCODER_DICT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.c
new file mode 100644
index 000000000..97f9dfb82
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.c
@@ -0,0 +1,501 @@
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Entropy encoding (Huffman) utilities. */
+
+#include "./entropy_encode.h"
+
+#include <string.h> /* memset */
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+BROTLI_BOOL BrotliSetDepth(
+ int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
+ int stack[16];
+ int level = 0;
+ int p = p0;
+ BROTLI_DCHECK(max_depth <= 15);
+ stack[0] = -1;
+ while (BROTLI_TRUE) {
+ if (pool[p].index_left_ >= 0) {
+ level++;
+ if (level > max_depth) return BROTLI_FALSE;
+ stack[level] = pool[p].index_right_or_value_;
+ p = pool[p].index_left_;
+ continue;
+ } else {
+ depth[pool[p].index_right_or_value_] = (uint8_t)level;
+ }
+ while (level >= 0 && stack[level] == -1) level--;
+ if (level < 0) return BROTLI_TRUE;
+ p = stack[level];
+ stack[level] = -1;
+ }
+}
+
+/* Sort the root nodes, least popular first. */
+static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
+ const HuffmanTree* v0, const HuffmanTree* v1) {
+ if (v0->total_count_ != v1->total_count_) {
+ return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_);
+ }
+ return TO_BROTLI_BOOL(v0->index_right_or_value_ > v1->index_right_or_value_);
+}
+
+/* This function will create a Huffman tree.
+
+ The catch here is that the tree cannot be arbitrarily deep.
+ Brotli specifies a maximum depth of 15 bits for "code trees"
+ and 7 bits for "code length code trees."
+
+ count_limit is the value that is to be faked as the minimum value
+ and this minimum value is raised until the tree matches the
+ maximum length requirement.
+
+ This algorithm is not of excellent performance for very long data blocks,
+ especially when population counts are longer than 2**tree_limit, but
+ we are not planning to use this with extremely long blocks.
+
+ See http://en.wikipedia.org/wiki/Huffman_coding */
+void BrotliCreateHuffmanTree(const uint32_t* data,
+ const size_t length,
+ const int tree_limit,
+ HuffmanTree* tree,
+ uint8_t* depth) {
+ uint32_t count_limit;
+ HuffmanTree sentinel;
+ InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1);
+ /* For block sizes below 64 kB, we never need to do a second iteration
+ of this loop. Probably all of our block sizes will be smaller than
+ that, so this loop is mostly of academic interest. If we actually
+ would need this, we would be better off with the Katajainen algorithm. */
+ for (count_limit = 1; ; count_limit *= 2) {
+ size_t n = 0;
+ size_t i;
+ size_t j;
+ size_t k;
+ for (i = length; i != 0;) {
+ --i;
+ if (data[i]) {
+ const uint32_t count = BROTLI_MAX(uint32_t, data[i], count_limit);
+ InitHuffmanTree(&tree[n++], count, -1, (int16_t)i);
+ }
+ }
+
+ if (n == 1) {
+ depth[tree[0].index_right_or_value_] = 1; /* Only one element. */
+ break;
+ }
+
+ SortHuffmanTreeItems(tree, n, SortHuffmanTree);
+
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ tree[n] = sentinel;
+ tree[n + 1] = sentinel;
+
+ i = 0; /* Points to the next leaf node. */
+ j = n + 1; /* Points to the next non-leaf node. */
+ for (k = n - 1; k != 0; --k) {
+ size_t left, right;
+ if (tree[i].total_count_ <= tree[j].total_count_) {
+ left = i;
+ ++i;
+ } else {
+ left = j;
+ ++j;
+ }
+ if (tree[i].total_count_ <= tree[j].total_count_) {
+ right = i;
+ ++i;
+ } else {
+ right = j;
+ ++j;
+ }
+
+ {
+ /* The sentinel node becomes the parent node. */
+ size_t j_end = 2 * n - k;
+ tree[j_end].total_count_ =
+ tree[left].total_count_ + tree[right].total_count_;
+ tree[j_end].index_left_ = (int16_t)left;
+ tree[j_end].index_right_or_value_ = (int16_t)right;
+
+ /* Add back the last sentinel node. */
+ tree[j_end + 1] = sentinel;
+ }
+ }
+ if (BrotliSetDepth((int)(2 * n - 1), &tree[0], depth, tree_limit)) {
+ /* We need to pack the Huffman tree in tree_limit bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break;
+ }
+ }
+}
+
+static void Reverse(uint8_t* v, size_t start, size_t end) {
+ --end;
+ while (start < end) {
+ uint8_t tmp = v[start];
+ v[start] = v[end];
+ v[end] = tmp;
+ ++start;
+ --end;
+ }
+}
+
+static void BrotliWriteHuffmanTreeRepetitions(
+ const uint8_t previous_value,
+ const uint8_t value,
+ size_t repetitions,
+ size_t* tree_size,
+ uint8_t* tree,
+ uint8_t* extra_bits_data) {
+ BROTLI_DCHECK(repetitions > 0);
+ if (previous_value != value) {
+ tree[*tree_size] = value;
+ extra_bits_data[*tree_size] = 0;
+ ++(*tree_size);
+ --repetitions;
+ }
+ if (repetitions == 7) {
+ tree[*tree_size] = value;
+ extra_bits_data[*tree_size] = 0;
+ ++(*tree_size);
+ --repetitions;
+ }
+ if (repetitions < 3) {
+ size_t i;
+ for (i = 0; i < repetitions; ++i) {
+ tree[*tree_size] = value;
+ extra_bits_data[*tree_size] = 0;
+ ++(*tree_size);
+ }
+ } else {
+ size_t start = *tree_size;
+ repetitions -= 3;
+ while (BROTLI_TRUE) {
+ tree[*tree_size] = BROTLI_REPEAT_PREVIOUS_CODE_LENGTH;
+ extra_bits_data[*tree_size] = repetitions & 0x3;
+ ++(*tree_size);
+ repetitions >>= 2;
+ if (repetitions == 0) {
+ break;
+ }
+ --repetitions;
+ }
+ Reverse(tree, start, *tree_size);
+ Reverse(extra_bits_data, start, *tree_size);
+ }
+}
+
+static void BrotliWriteHuffmanTreeRepetitionsZeros(
+ size_t repetitions,
+ size_t* tree_size,
+ uint8_t* tree,
+ uint8_t* extra_bits_data) {
+ if (repetitions == 11) {
+ tree[*tree_size] = 0;
+ extra_bits_data[*tree_size] = 0;
+ ++(*tree_size);
+ --repetitions;
+ }
+ if (repetitions < 3) {
+ size_t i;
+ for (i = 0; i < repetitions; ++i) {
+ tree[*tree_size] = 0;
+ extra_bits_data[*tree_size] = 0;
+ ++(*tree_size);
+ }
+ } else {
+ size_t start = *tree_size;
+ repetitions -= 3;
+ while (BROTLI_TRUE) {
+ tree[*tree_size] = BROTLI_REPEAT_ZERO_CODE_LENGTH;
+ extra_bits_data[*tree_size] = repetitions & 0x7;
+ ++(*tree_size);
+ repetitions >>= 3;
+ if (repetitions == 0) {
+ break;
+ }
+ --repetitions;
+ }
+ Reverse(tree, start, *tree_size);
+ Reverse(extra_bits_data, start, *tree_size);
+ }
+}
+
+void BrotliOptimizeHuffmanCountsForRle(size_t length, uint32_t* counts,
+ uint8_t* good_for_rle) {
+ size_t nonzero_count = 0;
+ size_t stride;
+ size_t limit;
+ size_t sum;
+ const size_t streak_limit = 1240;
+ /* Let's make the Huffman code more compatible with RLE encoding. */
+ size_t i;
+ for (i = 0; i < length; i++) {
+ if (counts[i]) {
+ ++nonzero_count;
+ }
+ }
+ if (nonzero_count < 16) {
+ return;
+ }
+ while (length != 0 && counts[length - 1] == 0) {
+ --length;
+ }
+ if (length == 0) {
+ return; /* All zeros. */
+ }
+ /* Now counts[0..length - 1] does not have trailing zeros. */
+ {
+ size_t nonzeros = 0;
+ uint32_t smallest_nonzero = 1 << 30;
+ for (i = 0; i < length; ++i) {
+ if (counts[i] != 0) {
+ ++nonzeros;
+ if (smallest_nonzero > counts[i]) {
+ smallest_nonzero = counts[i];
+ }
+ }
+ }
+ if (nonzeros < 5) {
+ /* Small histogram will model it well. */
+ return;
+ }
+ if (smallest_nonzero < 4) {
+ size_t zeros = length - nonzeros;
+ if (zeros < 6) {
+ for (i = 1; i < length - 1; ++i) {
+ if (counts[i - 1] != 0 && counts[i] == 0 && counts[i + 1] != 0) {
+ counts[i] = 1;
+ }
+ }
+ }
+ }
+ if (nonzeros < 28) {
+ return;
+ }
+ }
+ /* 2) Let's mark all population counts that already can be encoded
+ with an RLE code. */
+ memset(good_for_rle, 0, length);
+ {
+ /* Let's not spoil any of the existing good RLE codes.
+ Mark any seq of 0's that is longer as 5 as a good_for_rle.
+ Mark any seq of non-0's that is longer as 7 as a good_for_rle. */
+ uint32_t symbol = counts[0];
+ size_t step = 0;
+ for (i = 0; i <= length; ++i) {
+ if (i == length || counts[i] != symbol) {
+ if ((symbol == 0 && step >= 5) ||
+ (symbol != 0 && step >= 7)) {
+ size_t k;
+ for (k = 0; k < step; ++k) {
+ good_for_rle[i - k - 1] = 1;
+ }
+ }
+ step = 1;
+ if (i != length) {
+ symbol = counts[i];
+ }
+ } else {
+ ++step;
+ }
+ }
+ }
+ /* 3) Let's replace those population counts that lead to more RLE codes.
+ Math here is in 24.8 fixed point representation. */
+ stride = 0;
+ limit = 256 * (counts[0] + counts[1] + counts[2]) / 3 + 420;
+ sum = 0;
+ for (i = 0; i <= length; ++i) {
+ if (i == length || good_for_rle[i] ||
+ (i != 0 && good_for_rle[i - 1]) ||
+ (256 * counts[i] - limit + streak_limit) >= 2 * streak_limit) {
+ if (stride >= 4 || (stride >= 3 && sum == 0)) {
+ size_t k;
+ /* The stride must end, collapse what we have, if we have enough (4). */
+ size_t count = (sum + stride / 2) / stride;
+ if (count == 0) {
+ count = 1;
+ }
+ if (sum == 0) {
+ /* Don't make an all zeros stride to be upgraded to ones. */
+ count = 0;
+ }
+ for (k = 0; k < stride; ++k) {
+ /* We don't want to change value at counts[i],
+ that is already belonging to the next stride. Thus - 1. */
+ counts[i - k - 1] = (uint32_t)count;
+ }
+ }
+ stride = 0;
+ sum = 0;
+ if (i < length - 2) {
+ /* All interesting strides have a count of at least 4, */
+ /* at least when non-zeros. */
+ limit = 256 * (counts[i] + counts[i + 1] + counts[i + 2]) / 3 + 420;
+ } else if (i < length) {
+ limit = 256 * counts[i];
+ } else {
+ limit = 0;
+ }
+ }
+ ++stride;
+ if (i != length) {
+ sum += counts[i];
+ if (stride >= 4) {
+ limit = (256 * sum + stride / 2) / stride;
+ }
+ if (stride == 4) {
+ limit += 120;
+ }
+ }
+ }
+}
+
+static void DecideOverRleUse(const uint8_t* depth, const size_t length,
+ BROTLI_BOOL* use_rle_for_non_zero,
+ BROTLI_BOOL* use_rle_for_zero) {
+ size_t total_reps_zero = 0;
+ size_t total_reps_non_zero = 0;
+ size_t count_reps_zero = 1;
+ size_t count_reps_non_zero = 1;
+ size_t i;
+ for (i = 0; i < length;) {
+ const uint8_t value = depth[i];
+ size_t reps = 1;
+ size_t k;
+ for (k = i + 1; k < length && depth[k] == value; ++k) {
+ ++reps;
+ }
+ if (reps >= 3 && value == 0) {
+ total_reps_zero += reps;
+ ++count_reps_zero;
+ }
+ if (reps >= 4 && value != 0) {
+ total_reps_non_zero += reps;
+ ++count_reps_non_zero;
+ }
+ i += reps;
+ }
+ *use_rle_for_non_zero =
+ TO_BROTLI_BOOL(total_reps_non_zero > count_reps_non_zero * 2);
+ *use_rle_for_zero = TO_BROTLI_BOOL(total_reps_zero > count_reps_zero * 2);
+}
+
+void BrotliWriteHuffmanTree(const uint8_t* depth,
+ size_t length,
+ size_t* tree_size,
+ uint8_t* tree,
+ uint8_t* extra_bits_data) {
+ uint8_t previous_value = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
+ size_t i;
+ BROTLI_BOOL use_rle_for_non_zero = BROTLI_FALSE;
+ BROTLI_BOOL use_rle_for_zero = BROTLI_FALSE;
+
+ /* Throw away trailing zeros. */
+ size_t new_length = length;
+ for (i = 0; i < length; ++i) {
+ if (depth[length - i - 1] == 0) {
+ --new_length;
+ } else {
+ break;
+ }
+ }
+
+ /* First gather statistics on if it is a good idea to do RLE. */
+ if (length > 50) {
+ /* Find RLE coding for longer codes.
+ Shorter codes seem not to benefit from RLE. */
+ DecideOverRleUse(depth, new_length,
+ &use_rle_for_non_zero, &use_rle_for_zero);
+ }
+
+ /* Actual RLE coding. */
+ for (i = 0; i < new_length;) {
+ const uint8_t value = depth[i];
+ size_t reps = 1;
+ if ((value != 0 && use_rle_for_non_zero) ||
+ (value == 0 && use_rle_for_zero)) {
+ size_t k;
+ for (k = i + 1; k < new_length && depth[k] == value; ++k) {
+ ++reps;
+ }
+ }
+ if (value == 0) {
+ BrotliWriteHuffmanTreeRepetitionsZeros(
+ reps, tree_size, tree, extra_bits_data);
+ } else {
+ BrotliWriteHuffmanTreeRepetitions(previous_value,
+ value, reps, tree_size,
+ tree, extra_bits_data);
+ previous_value = value;
+ }
+ i += reps;
+ }
+}
+
+static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) {
+ static const size_t kLut[16] = { /* Pre-reversed 4-bit values. */
+ 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E,
+ 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F
+ };
+ size_t retval = kLut[bits & 0x0F];
+ size_t i;
+ for (i = 4; i < num_bits; i += 4) {
+ retval <<= 4;
+ bits = (uint16_t)(bits >> 4);
+ retval |= kLut[bits & 0x0F];
+ }
+ retval >>= ((0 - num_bits) & 0x03);
+ return (uint16_t)retval;
+}
+
+/* 0..15 are values for bits */
+#define MAX_HUFFMAN_BITS 16
+
+void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
+ size_t len,
+ uint16_t* bits) {
+ /* In Brotli, all bit depths are [1..15]
+ 0 bit depth means that the symbol does not exist. */
+ uint16_t bl_count[MAX_HUFFMAN_BITS] = { 0 };
+ uint16_t next_code[MAX_HUFFMAN_BITS];
+ size_t i;
+ int code = 0;
+ for (i = 0; i < len; ++i) {
+ ++bl_count[depth[i]];
+ }
+ bl_count[0] = 0;
+ next_code[0] = 0;
+ for (i = 1; i < MAX_HUFFMAN_BITS; ++i) {
+ code = (code + bl_count[i - 1]) << 1;
+ next_code[i] = (uint16_t)code;
+ }
+ for (i = 0; i < len; ++i) {
+ if (depth[i]) {
+ bits[i] = BrotliReverseBits(depth[i], next_code[depth[i]]++);
+ }
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.h
new file mode 100644
index 000000000..f23d9c379
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode.h
@@ -0,0 +1,122 @@
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Entropy encoding (Huffman) utilities. */
+
+#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
+#define BROTLI_ENC_ENTROPY_ENCODE_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* A node of a Huffman tree. */
+typedef struct HuffmanTree {
+ uint32_t total_count_;
+ int16_t index_left_;
+ int16_t index_right_or_value_;
+} HuffmanTree;
+
+static BROTLI_INLINE void InitHuffmanTree(HuffmanTree* self, uint32_t count,
+ int16_t left, int16_t right) {
+ self->total_count_ = count;
+ self->index_left_ = left;
+ self->index_right_or_value_ = right;
+}
+
+/* Returns 1 is assignment of depths succeeded, otherwise 0. */
+BROTLI_INTERNAL BROTLI_BOOL BrotliSetDepth(
+ int p, HuffmanTree* pool, uint8_t* depth, int max_depth);
+
+/* This function will create a Huffman tree.
+
+ The (data,length) contains the population counts.
+ The tree_limit is the maximum bit depth of the Huffman codes.
+
+ The depth contains the tree, i.e., how many bits are used for
+ the symbol.
+
+ The actual Huffman tree is constructed in the tree[] array, which has to
+ be at least 2 * length + 1 long.
+
+ See http://en.wikipedia.org/wiki/Huffman_coding */
+BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t* data,
+ const size_t length,
+ const int tree_limit,
+ HuffmanTree* tree,
+ uint8_t* depth);
+
+/* Change the population counts in a way that the consequent
+ Huffman tree compression, especially its RLE-part will be more
+ likely to compress this data more efficiently.
+
+ length contains the size of the histogram.
+ counts contains the population counts.
+ good_for_rle is a buffer of at least length size */
+BROTLI_INTERNAL void BrotliOptimizeHuffmanCountsForRle(
+ size_t length, uint32_t* counts, uint8_t* good_for_rle);
+
+/* Write a Huffman tree from bit depths into the bit-stream representation
+ of a Huffman tree. The generated Huffman tree is to be compressed once
+ more using a Huffman tree */
+BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth,
+ size_t num,
+ size_t* tree_size,
+ uint8_t* tree,
+ uint8_t* extra_bits_data);
+
+/* Get the actual bit values for a tree of bit depths. */
+BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
+ size_t len,
+ uint16_t* bits);
+
+/* Input size optimized Shell sort. */
+typedef BROTLI_BOOL (*HuffmanTreeComparator)(
+ const HuffmanTree*, const HuffmanTree*);
+static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
+ const size_t n, HuffmanTreeComparator comparator) {
+ static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
+ if (n < 13) {
+ /* Insertion sort. */
+ size_t i;
+ for (i = 1; i < n; ++i) {
+ HuffmanTree tmp = items[i];
+ size_t k = i;
+ size_t j = i - 1;
+ while (comparator(&tmp, &items[j])) {
+ items[k] = items[j];
+ k = j;
+ if (!j--) break;
+ }
+ items[k] = tmp;
+ }
+ return;
+ } else {
+ /* Shell sort. */
+ int g = n < 57 ? 2 : 0;
+ for (; g < 6; ++g) {
+ size_t gap = gaps[g];
+ size_t i;
+ for (i = gap; i < n; ++i) {
+ size_t j = i;
+ HuffmanTree tmp = items[i];
+ for (; j >= gap && comparator(&tmp, &items[j - gap]); j -= gap) {
+ items[j] = items[j - gap];
+ }
+ items[j] = tmp;
+ }
+ }
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_ENTROPY_ENCODE_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode_static.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode_static.h
new file mode 100644
index 000000000..62b99a954
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/entropy_encode_static.h
@@ -0,0 +1,539 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Static entropy codes used for faster meta-block encoding. */
+
+#ifndef BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
+#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./write_bits.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const uint8_t kCodeLengthDepth[18] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4,
+};
+
+static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+};
+
+static const uint8_t kStaticDistanceCodeDepth[64] = {
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+};
+
+static const uint32_t kCodeLengthBits[18] = {
+ 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7,
+};
+
+static BROTLI_INLINE void StoreStaticCodeLengthCode(
+ size_t* storage_ix, uint8_t* storage) {
+ BrotliWriteBits(
+ 40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage);
+}
+
+static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x00000017, 0x00000027,
+ 0x00000037, 0x00000047, 0x00000057, 0x00000067, 0x00000077, 0x00000770,
+ 0x00000b87, 0x00001387, 0x00001b87, 0x00002387, 0x00002b87, 0x00003387,
+ 0x00003b87, 0x00000397, 0x00000b97, 0x00001397, 0x00001b97, 0x00002397,
+ 0x00002b97, 0x00003397, 0x00003b97, 0x000003a7, 0x00000ba7, 0x000013a7,
+ 0x00001ba7, 0x000023a7, 0x00002ba7, 0x000033a7, 0x00003ba7, 0x000003b7,
+ 0x00000bb7, 0x000013b7, 0x00001bb7, 0x000023b7, 0x00002bb7, 0x000033b7,
+ 0x00003bb7, 0x000003c7, 0x00000bc7, 0x000013c7, 0x00001bc7, 0x000023c7,
+ 0x00002bc7, 0x000033c7, 0x00003bc7, 0x000003d7, 0x00000bd7, 0x000013d7,
+ 0x00001bd7, 0x000023d7, 0x00002bd7, 0x000033d7, 0x00003bd7, 0x000003e7,
+ 0x00000be7, 0x000013e7, 0x00001be7, 0x000023e7, 0x00002be7, 0x000033e7,
+ 0x00003be7, 0x000003f7, 0x00000bf7, 0x000013f7, 0x00001bf7, 0x000023f7,
+ 0x00002bf7, 0x000033f7, 0x00003bf7, 0x0001c387, 0x0005c387, 0x0009c387,
+ 0x000dc387, 0x0011c387, 0x0015c387, 0x0019c387, 0x001dc387, 0x0001cb87,
+ 0x0005cb87, 0x0009cb87, 0x000dcb87, 0x0011cb87, 0x0015cb87, 0x0019cb87,
+ 0x001dcb87, 0x0001d387, 0x0005d387, 0x0009d387, 0x000dd387, 0x0011d387,
+ 0x0015d387, 0x0019d387, 0x001dd387, 0x0001db87, 0x0005db87, 0x0009db87,
+ 0x000ddb87, 0x0011db87, 0x0015db87, 0x0019db87, 0x001ddb87, 0x0001e387,
+ 0x0005e387, 0x0009e387, 0x000de387, 0x0011e387, 0x0015e387, 0x0019e387,
+ 0x001de387, 0x0001eb87, 0x0005eb87, 0x0009eb87, 0x000deb87, 0x0011eb87,
+ 0x0015eb87, 0x0019eb87, 0x001deb87, 0x0001f387, 0x0005f387, 0x0009f387,
+ 0x000df387, 0x0011f387, 0x0015f387, 0x0019f387, 0x001df387, 0x0001fb87,
+ 0x0005fb87, 0x0009fb87, 0x000dfb87, 0x0011fb87, 0x0015fb87, 0x0019fb87,
+ 0x001dfb87, 0x0001c397, 0x0005c397, 0x0009c397, 0x000dc397, 0x0011c397,
+ 0x0015c397, 0x0019c397, 0x001dc397, 0x0001cb97, 0x0005cb97, 0x0009cb97,
+ 0x000dcb97, 0x0011cb97, 0x0015cb97, 0x0019cb97, 0x001dcb97, 0x0001d397,
+ 0x0005d397, 0x0009d397, 0x000dd397, 0x0011d397, 0x0015d397, 0x0019d397,
+ 0x001dd397, 0x0001db97, 0x0005db97, 0x0009db97, 0x000ddb97, 0x0011db97,
+ 0x0015db97, 0x0019db97, 0x001ddb97, 0x0001e397, 0x0005e397, 0x0009e397,
+ 0x000de397, 0x0011e397, 0x0015e397, 0x0019e397, 0x001de397, 0x0001eb97,
+ 0x0005eb97, 0x0009eb97, 0x000deb97, 0x0011eb97, 0x0015eb97, 0x0019eb97,
+ 0x001deb97, 0x0001f397, 0x0005f397, 0x0009f397, 0x000df397, 0x0011f397,
+ 0x0015f397, 0x0019f397, 0x001df397, 0x0001fb97, 0x0005fb97, 0x0009fb97,
+ 0x000dfb97, 0x0011fb97, 0x0015fb97, 0x0019fb97, 0x001dfb97, 0x0001c3a7,
+ 0x0005c3a7, 0x0009c3a7, 0x000dc3a7, 0x0011c3a7, 0x0015c3a7, 0x0019c3a7,
+ 0x001dc3a7, 0x0001cba7, 0x0005cba7, 0x0009cba7, 0x000dcba7, 0x0011cba7,
+ 0x0015cba7, 0x0019cba7, 0x001dcba7, 0x0001d3a7, 0x0005d3a7, 0x0009d3a7,
+ 0x000dd3a7, 0x0011d3a7, 0x0015d3a7, 0x0019d3a7, 0x001dd3a7, 0x0001dba7,
+ 0x0005dba7, 0x0009dba7, 0x000ddba7, 0x0011dba7, 0x0015dba7, 0x0019dba7,
+ 0x001ddba7, 0x0001e3a7, 0x0005e3a7, 0x0009e3a7, 0x000de3a7, 0x0011e3a7,
+ 0x0015e3a7, 0x0019e3a7, 0x001de3a7, 0x0001eba7, 0x0005eba7, 0x0009eba7,
+ 0x000deba7, 0x0011eba7, 0x0015eba7, 0x0019eba7, 0x001deba7, 0x0001f3a7,
+ 0x0005f3a7, 0x0009f3a7, 0x000df3a7, 0x0011f3a7, 0x0015f3a7, 0x0019f3a7,
+ 0x001df3a7, 0x0001fba7, 0x0005fba7, 0x0009fba7, 0x000dfba7, 0x0011fba7,
+ 0x0015fba7, 0x0019fba7, 0x001dfba7, 0x0001c3b7, 0x0005c3b7, 0x0009c3b7,
+ 0x000dc3b7, 0x0011c3b7, 0x0015c3b7, 0x0019c3b7, 0x001dc3b7, 0x0001cbb7,
+ 0x0005cbb7, 0x0009cbb7, 0x000dcbb7, 0x0011cbb7, 0x0015cbb7, 0x0019cbb7,
+ 0x001dcbb7, 0x0001d3b7, 0x0005d3b7, 0x0009d3b7, 0x000dd3b7, 0x0011d3b7,
+ 0x0015d3b7, 0x0019d3b7, 0x001dd3b7, 0x0001dbb7, 0x0005dbb7, 0x0009dbb7,
+ 0x000ddbb7, 0x0011dbb7, 0x0015dbb7, 0x0019dbb7, 0x001ddbb7, 0x0001e3b7,
+ 0x0005e3b7, 0x0009e3b7, 0x000de3b7, 0x0011e3b7, 0x0015e3b7, 0x0019e3b7,
+ 0x001de3b7, 0x0001ebb7, 0x0005ebb7, 0x0009ebb7, 0x000debb7, 0x0011ebb7,
+ 0x0015ebb7, 0x0019ebb7, 0x001debb7, 0x0001f3b7, 0x0005f3b7, 0x0009f3b7,
+ 0x000df3b7, 0x0011f3b7, 0x0015f3b7, 0x0019f3b7, 0x001df3b7, 0x0001fbb7,
+ 0x0005fbb7, 0x0009fbb7, 0x000dfbb7, 0x0011fbb7, 0x0015fbb7, 0x0019fbb7,
+ 0x001dfbb7, 0x0001c3c7, 0x0005c3c7, 0x0009c3c7, 0x000dc3c7, 0x0011c3c7,
+ 0x0015c3c7, 0x0019c3c7, 0x001dc3c7, 0x0001cbc7, 0x0005cbc7, 0x0009cbc7,
+ 0x000dcbc7, 0x0011cbc7, 0x0015cbc7, 0x0019cbc7, 0x001dcbc7, 0x0001d3c7,
+ 0x0005d3c7, 0x0009d3c7, 0x000dd3c7, 0x0011d3c7, 0x0015d3c7, 0x0019d3c7,
+ 0x001dd3c7, 0x0001dbc7, 0x0005dbc7, 0x0009dbc7, 0x000ddbc7, 0x0011dbc7,
+ 0x0015dbc7, 0x0019dbc7, 0x001ddbc7, 0x0001e3c7, 0x0005e3c7, 0x0009e3c7,
+ 0x000de3c7, 0x0011e3c7, 0x0015e3c7, 0x0019e3c7, 0x001de3c7, 0x0001ebc7,
+ 0x0005ebc7, 0x0009ebc7, 0x000debc7, 0x0011ebc7, 0x0015ebc7, 0x0019ebc7,
+ 0x001debc7, 0x0001f3c7, 0x0005f3c7, 0x0009f3c7, 0x000df3c7, 0x0011f3c7,
+ 0x0015f3c7, 0x0019f3c7, 0x001df3c7, 0x0001fbc7, 0x0005fbc7, 0x0009fbc7,
+ 0x000dfbc7, 0x0011fbc7, 0x0015fbc7, 0x0019fbc7, 0x001dfbc7, 0x0001c3d7,
+ 0x0005c3d7, 0x0009c3d7, 0x000dc3d7, 0x0011c3d7, 0x0015c3d7, 0x0019c3d7,
+ 0x001dc3d7, 0x0001cbd7, 0x0005cbd7, 0x0009cbd7, 0x000dcbd7, 0x0011cbd7,
+ 0x0015cbd7, 0x0019cbd7, 0x001dcbd7, 0x0001d3d7, 0x0005d3d7, 0x0009d3d7,
+ 0x000dd3d7, 0x0011d3d7, 0x0015d3d7, 0x0019d3d7, 0x001dd3d7, 0x0001dbd7,
+ 0x0005dbd7, 0x0009dbd7, 0x000ddbd7, 0x0011dbd7, 0x0015dbd7, 0x0019dbd7,
+ 0x001ddbd7, 0x0001e3d7, 0x0005e3d7, 0x0009e3d7, 0x000de3d7, 0x0011e3d7,
+ 0x0015e3d7, 0x0019e3d7, 0x001de3d7, 0x0001ebd7, 0x0005ebd7, 0x0009ebd7,
+ 0x000debd7, 0x0011ebd7, 0x0015ebd7, 0x0019ebd7, 0x001debd7, 0x0001f3d7,
+ 0x0005f3d7, 0x0009f3d7, 0x000df3d7, 0x0011f3d7, 0x0015f3d7, 0x0019f3d7,
+ 0x001df3d7, 0x0001fbd7, 0x0005fbd7, 0x0009fbd7, 0x000dfbd7, 0x0011fbd7,
+ 0x0015fbd7, 0x0019fbd7, 0x001dfbd7, 0x0001c3e7, 0x0005c3e7, 0x0009c3e7,
+ 0x000dc3e7, 0x0011c3e7, 0x0015c3e7, 0x0019c3e7, 0x001dc3e7, 0x0001cbe7,
+ 0x0005cbe7, 0x0009cbe7, 0x000dcbe7, 0x0011cbe7, 0x0015cbe7, 0x0019cbe7,
+ 0x001dcbe7, 0x0001d3e7, 0x0005d3e7, 0x0009d3e7, 0x000dd3e7, 0x0011d3e7,
+ 0x0015d3e7, 0x0019d3e7, 0x001dd3e7, 0x0001dbe7, 0x0005dbe7, 0x0009dbe7,
+ 0x000ddbe7, 0x0011dbe7, 0x0015dbe7, 0x0019dbe7, 0x001ddbe7, 0x0001e3e7,
+ 0x0005e3e7, 0x0009e3e7, 0x000de3e7, 0x0011e3e7, 0x0015e3e7, 0x0019e3e7,
+ 0x001de3e7, 0x0001ebe7, 0x0005ebe7, 0x0009ebe7, 0x000debe7, 0x0011ebe7,
+ 0x0015ebe7, 0x0019ebe7, 0x001debe7, 0x0001f3e7, 0x0005f3e7, 0x0009f3e7,
+ 0x000df3e7, 0x0011f3e7, 0x0015f3e7, 0x0019f3e7, 0x001df3e7, 0x0001fbe7,
+ 0x0005fbe7, 0x0009fbe7, 0x000dfbe7, 0x0011fbe7, 0x0015fbe7, 0x0019fbe7,
+ 0x001dfbe7, 0x0001c3f7, 0x0005c3f7, 0x0009c3f7, 0x000dc3f7, 0x0011c3f7,
+ 0x0015c3f7, 0x0019c3f7, 0x001dc3f7, 0x0001cbf7, 0x0005cbf7, 0x0009cbf7,
+ 0x000dcbf7, 0x0011cbf7, 0x0015cbf7, 0x0019cbf7, 0x001dcbf7, 0x0001d3f7,
+ 0x0005d3f7, 0x0009d3f7, 0x000dd3f7, 0x0011d3f7, 0x0015d3f7, 0x0019d3f7,
+ 0x001dd3f7, 0x0001dbf7, 0x0005dbf7, 0x0009dbf7, 0x000ddbf7, 0x0011dbf7,
+ 0x0015dbf7, 0x0019dbf7, 0x001ddbf7, 0x0001e3f7, 0x0005e3f7, 0x0009e3f7,
+ 0x000de3f7, 0x0011e3f7, 0x0015e3f7, 0x0019e3f7, 0x001de3f7, 0x0001ebf7,
+ 0x0005ebf7, 0x0009ebf7, 0x000debf7, 0x0011ebf7, 0x0015ebf7, 0x0019ebf7,
+ 0x001debf7, 0x0001f3f7, 0x0005f3f7, 0x0009f3f7, 0x000df3f7, 0x0011f3f7,
+ 0x0015f3f7, 0x0019f3f7, 0x001df3f7, 0x0001fbf7, 0x0005fbf7, 0x0009fbf7,
+ 0x000dfbf7, 0x0011fbf7, 0x0015fbf7, 0x0019fbf7, 0x001dfbf7, 0x00e1c387,
+ 0x02e1c387, 0x04e1c387, 0x06e1c387, 0x08e1c387, 0x0ae1c387, 0x0ce1c387,
+ 0x0ee1c387, 0x00e5c387, 0x02e5c387, 0x04e5c387, 0x06e5c387, 0x08e5c387,
+ 0x0ae5c387, 0x0ce5c387, 0x0ee5c387, 0x00e9c387, 0x02e9c387, 0x04e9c387,
+ 0x06e9c387, 0x08e9c387, 0x0ae9c387, 0x0ce9c387, 0x0ee9c387, 0x00edc387,
+ 0x02edc387, 0x04edc387, 0x06edc387, 0x08edc387, 0x0aedc387, 0x0cedc387,
+ 0x0eedc387, 0x00f1c387, 0x02f1c387, 0x04f1c387, 0x06f1c387, 0x08f1c387,
+ 0x0af1c387, 0x0cf1c387, 0x0ef1c387, 0x00f5c387, 0x02f5c387, 0x04f5c387,
+ 0x06f5c387, 0x08f5c387, 0x0af5c387, 0x0cf5c387, 0x0ef5c387, 0x00f9c387,
+ 0x02f9c387, 0x04f9c387, 0x06f9c387, 0x08f9c387, 0x0af9c387, 0x0cf9c387,
+ 0x0ef9c387, 0x00fdc387, 0x02fdc387, 0x04fdc387, 0x06fdc387, 0x08fdc387,
+ 0x0afdc387, 0x0cfdc387, 0x0efdc387, 0x00e1cb87, 0x02e1cb87, 0x04e1cb87,
+ 0x06e1cb87, 0x08e1cb87, 0x0ae1cb87, 0x0ce1cb87, 0x0ee1cb87, 0x00e5cb87,
+ 0x02e5cb87, 0x04e5cb87, 0x06e5cb87, 0x08e5cb87, 0x0ae5cb87, 0x0ce5cb87,
+ 0x0ee5cb87, 0x00e9cb87, 0x02e9cb87, 0x04e9cb87, 0x06e9cb87, 0x08e9cb87,
+ 0x0ae9cb87, 0x0ce9cb87, 0x0ee9cb87, 0x00edcb87, 0x02edcb87, 0x04edcb87,
+ 0x06edcb87, 0x08edcb87, 0x0aedcb87, 0x0cedcb87, 0x0eedcb87, 0x00f1cb87,
+ 0x02f1cb87, 0x04f1cb87, 0x06f1cb87, 0x08f1cb87, 0x0af1cb87, 0x0cf1cb87,
+ 0x0ef1cb87, 0x00f5cb87, 0x02f5cb87, 0x04f5cb87, 0x06f5cb87, 0x08f5cb87,
+ 0x0af5cb87, 0x0cf5cb87, 0x0ef5cb87, 0x00f9cb87, 0x02f9cb87, 0x04f9cb87,
+ 0x06f9cb87, 0x08f9cb87,
+};
+
+static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 0, 4, 8, 7, 7, 7, 7, 7, 7, 7, 7, 11, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+};
+
+static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 0x0000000b, 0x0000001b, 0x0000002b, 0x0000003b, 0x000002cb, 0x000006cb,
+ 0x00000acb, 0x00000ecb, 0x000002db, 0x000006db, 0x00000adb, 0x00000edb,
+ 0x000002eb, 0x000006eb, 0x00000aeb, 0x00000eeb, 0x000002fb, 0x000006fb,
+ 0x00000afb, 0x00000efb, 0x0000b2cb, 0x0001b2cb, 0x0002b2cb, 0x0003b2cb,
+ 0x0000b6cb, 0x0001b6cb, 0x0002b6cb, 0x0003b6cb, 0x0000bacb, 0x0001bacb,
+ 0x0002bacb, 0x0003bacb, 0x0000becb, 0x0001becb, 0x0002becb, 0x0003becb,
+ 0x0000b2db, 0x0001b2db, 0x0002b2db, 0x0003b2db, 0x0000b6db, 0x0001b6db,
+ 0x0002b6db, 0x0003b6db, 0x0000badb, 0x0001badb, 0x0002badb, 0x0003badb,
+ 0x0000bedb, 0x0001bedb, 0x0002bedb, 0x0003bedb, 0x0000b2eb, 0x0001b2eb,
+ 0x0002b2eb, 0x0003b2eb, 0x0000b6eb, 0x0001b6eb, 0x0002b6eb, 0x0003b6eb,
+ 0x0000baeb, 0x0001baeb, 0x0002baeb, 0x0003baeb, 0x0000beeb, 0x0001beeb,
+ 0x0002beeb, 0x0003beeb, 0x0000b2fb, 0x0001b2fb, 0x0002b2fb, 0x0003b2fb,
+ 0x0000b6fb, 0x0001b6fb, 0x0002b6fb, 0x0003b6fb, 0x0000bafb, 0x0001bafb,
+ 0x0002bafb, 0x0003bafb, 0x0000befb, 0x0001befb, 0x0002befb, 0x0003befb,
+ 0x002cb2cb, 0x006cb2cb, 0x00acb2cb, 0x00ecb2cb, 0x002db2cb, 0x006db2cb,
+ 0x00adb2cb, 0x00edb2cb, 0x002eb2cb, 0x006eb2cb, 0x00aeb2cb, 0x00eeb2cb,
+ 0x002fb2cb, 0x006fb2cb, 0x00afb2cb, 0x00efb2cb, 0x002cb6cb, 0x006cb6cb,
+ 0x00acb6cb, 0x00ecb6cb, 0x002db6cb, 0x006db6cb, 0x00adb6cb, 0x00edb6cb,
+ 0x002eb6cb, 0x006eb6cb, 0x00aeb6cb, 0x00eeb6cb, 0x002fb6cb, 0x006fb6cb,
+ 0x00afb6cb, 0x00efb6cb, 0x002cbacb, 0x006cbacb, 0x00acbacb, 0x00ecbacb,
+ 0x002dbacb, 0x006dbacb, 0x00adbacb, 0x00edbacb, 0x002ebacb, 0x006ebacb,
+ 0x00aebacb, 0x00eebacb, 0x002fbacb, 0x006fbacb, 0x00afbacb, 0x00efbacb,
+ 0x002cbecb, 0x006cbecb, 0x00acbecb, 0x00ecbecb, 0x002dbecb, 0x006dbecb,
+ 0x00adbecb, 0x00edbecb, 0x002ebecb, 0x006ebecb, 0x00aebecb, 0x00eebecb,
+ 0x002fbecb, 0x006fbecb, 0x00afbecb, 0x00efbecb, 0x002cb2db, 0x006cb2db,
+ 0x00acb2db, 0x00ecb2db, 0x002db2db, 0x006db2db, 0x00adb2db, 0x00edb2db,
+ 0x002eb2db, 0x006eb2db, 0x00aeb2db, 0x00eeb2db, 0x002fb2db, 0x006fb2db,
+ 0x00afb2db, 0x00efb2db, 0x002cb6db, 0x006cb6db, 0x00acb6db, 0x00ecb6db,
+ 0x002db6db, 0x006db6db, 0x00adb6db, 0x00edb6db, 0x002eb6db, 0x006eb6db,
+ 0x00aeb6db, 0x00eeb6db, 0x002fb6db, 0x006fb6db, 0x00afb6db, 0x00efb6db,
+ 0x002cbadb, 0x006cbadb, 0x00acbadb, 0x00ecbadb, 0x002dbadb, 0x006dbadb,
+ 0x00adbadb, 0x00edbadb, 0x002ebadb, 0x006ebadb, 0x00aebadb, 0x00eebadb,
+ 0x002fbadb, 0x006fbadb, 0x00afbadb, 0x00efbadb, 0x002cbedb, 0x006cbedb,
+ 0x00acbedb, 0x00ecbedb, 0x002dbedb, 0x006dbedb, 0x00adbedb, 0x00edbedb,
+ 0x002ebedb, 0x006ebedb, 0x00aebedb, 0x00eebedb, 0x002fbedb, 0x006fbedb,
+ 0x00afbedb, 0x00efbedb, 0x002cb2eb, 0x006cb2eb, 0x00acb2eb, 0x00ecb2eb,
+ 0x002db2eb, 0x006db2eb, 0x00adb2eb, 0x00edb2eb, 0x002eb2eb, 0x006eb2eb,
+ 0x00aeb2eb, 0x00eeb2eb, 0x002fb2eb, 0x006fb2eb, 0x00afb2eb, 0x00efb2eb,
+ 0x002cb6eb, 0x006cb6eb, 0x00acb6eb, 0x00ecb6eb, 0x002db6eb, 0x006db6eb,
+ 0x00adb6eb, 0x00edb6eb, 0x002eb6eb, 0x006eb6eb, 0x00aeb6eb, 0x00eeb6eb,
+ 0x002fb6eb, 0x006fb6eb, 0x00afb6eb, 0x00efb6eb, 0x002cbaeb, 0x006cbaeb,
+ 0x00acbaeb, 0x00ecbaeb, 0x002dbaeb, 0x006dbaeb, 0x00adbaeb, 0x00edbaeb,
+ 0x002ebaeb, 0x006ebaeb, 0x00aebaeb, 0x00eebaeb, 0x002fbaeb, 0x006fbaeb,
+ 0x00afbaeb, 0x00efbaeb, 0x002cbeeb, 0x006cbeeb, 0x00acbeeb, 0x00ecbeeb,
+ 0x002dbeeb, 0x006dbeeb, 0x00adbeeb, 0x00edbeeb, 0x002ebeeb, 0x006ebeeb,
+ 0x00aebeeb, 0x00eebeeb, 0x002fbeeb, 0x006fbeeb, 0x00afbeeb, 0x00efbeeb,
+ 0x002cb2fb, 0x006cb2fb, 0x00acb2fb, 0x00ecb2fb, 0x002db2fb, 0x006db2fb,
+ 0x00adb2fb, 0x00edb2fb, 0x002eb2fb, 0x006eb2fb, 0x00aeb2fb, 0x00eeb2fb,
+ 0x002fb2fb, 0x006fb2fb, 0x00afb2fb, 0x00efb2fb, 0x002cb6fb, 0x006cb6fb,
+ 0x00acb6fb, 0x00ecb6fb, 0x002db6fb, 0x006db6fb, 0x00adb6fb, 0x00edb6fb,
+ 0x002eb6fb, 0x006eb6fb, 0x00aeb6fb, 0x00eeb6fb, 0x002fb6fb, 0x006fb6fb,
+ 0x00afb6fb, 0x00efb6fb, 0x002cbafb, 0x006cbafb, 0x00acbafb, 0x00ecbafb,
+ 0x002dbafb, 0x006dbafb, 0x00adbafb, 0x00edbafb, 0x002ebafb, 0x006ebafb,
+ 0x00aebafb, 0x00eebafb, 0x002fbafb, 0x006fbafb, 0x00afbafb, 0x00efbafb,
+ 0x002cbefb, 0x006cbefb, 0x00acbefb, 0x00ecbefb, 0x002dbefb, 0x006dbefb,
+ 0x00adbefb, 0x00edbefb, 0x002ebefb, 0x006ebefb, 0x00aebefb, 0x00eebefb,
+ 0x002fbefb, 0x006fbefb, 0x00afbefb, 0x00efbefb, 0x0b2cb2cb, 0x1b2cb2cb,
+ 0x2b2cb2cb, 0x3b2cb2cb, 0x0b6cb2cb, 0x1b6cb2cb, 0x2b6cb2cb, 0x3b6cb2cb,
+ 0x0bacb2cb, 0x1bacb2cb, 0x2bacb2cb, 0x3bacb2cb, 0x0becb2cb, 0x1becb2cb,
+ 0x2becb2cb, 0x3becb2cb, 0x0b2db2cb, 0x1b2db2cb, 0x2b2db2cb, 0x3b2db2cb,
+ 0x0b6db2cb, 0x1b6db2cb, 0x2b6db2cb, 0x3b6db2cb, 0x0badb2cb, 0x1badb2cb,
+ 0x2badb2cb, 0x3badb2cb, 0x0bedb2cb, 0x1bedb2cb, 0x2bedb2cb, 0x3bedb2cb,
+ 0x0b2eb2cb, 0x1b2eb2cb, 0x2b2eb2cb, 0x3b2eb2cb, 0x0b6eb2cb, 0x1b6eb2cb,
+ 0x2b6eb2cb, 0x3b6eb2cb, 0x0baeb2cb, 0x1baeb2cb, 0x2baeb2cb, 0x3baeb2cb,
+ 0x0beeb2cb, 0x1beeb2cb, 0x2beeb2cb, 0x3beeb2cb, 0x0b2fb2cb, 0x1b2fb2cb,
+ 0x2b2fb2cb, 0x3b2fb2cb, 0x0b6fb2cb, 0x1b6fb2cb, 0x2b6fb2cb, 0x3b6fb2cb,
+ 0x0bafb2cb, 0x1bafb2cb, 0x2bafb2cb, 0x3bafb2cb, 0x0befb2cb, 0x1befb2cb,
+ 0x2befb2cb, 0x3befb2cb, 0x0b2cb6cb, 0x1b2cb6cb, 0x2b2cb6cb, 0x3b2cb6cb,
+ 0x0b6cb6cb, 0x1b6cb6cb, 0x2b6cb6cb, 0x3b6cb6cb, 0x0bacb6cb, 0x1bacb6cb,
+ 0x2bacb6cb, 0x3bacb6cb, 0x0becb6cb, 0x1becb6cb, 0x2becb6cb, 0x3becb6cb,
+ 0x0b2db6cb, 0x1b2db6cb, 0x2b2db6cb, 0x3b2db6cb, 0x0b6db6cb, 0x1b6db6cb,
+ 0x2b6db6cb, 0x3b6db6cb, 0x0badb6cb, 0x1badb6cb, 0x2badb6cb, 0x3badb6cb,
+ 0x0bedb6cb, 0x1bedb6cb, 0x2bedb6cb, 0x3bedb6cb, 0x0b2eb6cb, 0x1b2eb6cb,
+ 0x2b2eb6cb, 0x3b2eb6cb, 0x0b6eb6cb, 0x1b6eb6cb, 0x2b6eb6cb, 0x3b6eb6cb,
+ 0x0baeb6cb, 0x1baeb6cb, 0x2baeb6cb, 0x3baeb6cb, 0x0beeb6cb, 0x1beeb6cb,
+ 0x2beeb6cb, 0x3beeb6cb, 0x0b2fb6cb, 0x1b2fb6cb, 0x2b2fb6cb, 0x3b2fb6cb,
+ 0x0b6fb6cb, 0x1b6fb6cb, 0x2b6fb6cb, 0x3b6fb6cb, 0x0bafb6cb, 0x1bafb6cb,
+ 0x2bafb6cb, 0x3bafb6cb, 0x0befb6cb, 0x1befb6cb, 0x2befb6cb, 0x3befb6cb,
+ 0x0b2cbacb, 0x1b2cbacb, 0x2b2cbacb, 0x3b2cbacb, 0x0b6cbacb, 0x1b6cbacb,
+ 0x2b6cbacb, 0x3b6cbacb, 0x0bacbacb, 0x1bacbacb, 0x2bacbacb, 0x3bacbacb,
+ 0x0becbacb, 0x1becbacb, 0x2becbacb, 0x3becbacb, 0x0b2dbacb, 0x1b2dbacb,
+ 0x2b2dbacb, 0x3b2dbacb, 0x0b6dbacb, 0x1b6dbacb, 0x2b6dbacb, 0x3b6dbacb,
+ 0x0badbacb, 0x1badbacb, 0x2badbacb, 0x3badbacb, 0x0bedbacb, 0x1bedbacb,
+ 0x2bedbacb, 0x3bedbacb, 0x0b2ebacb, 0x1b2ebacb, 0x2b2ebacb, 0x3b2ebacb,
+ 0x0b6ebacb, 0x1b6ebacb, 0x2b6ebacb, 0x3b6ebacb, 0x0baebacb, 0x1baebacb,
+ 0x2baebacb, 0x3baebacb, 0x0beebacb, 0x1beebacb, 0x2beebacb, 0x3beebacb,
+ 0x0b2fbacb, 0x1b2fbacb, 0x2b2fbacb, 0x3b2fbacb, 0x0b6fbacb, 0x1b6fbacb,
+ 0x2b6fbacb, 0x3b6fbacb, 0x0bafbacb, 0x1bafbacb, 0x2bafbacb, 0x3bafbacb,
+ 0x0befbacb, 0x1befbacb, 0x2befbacb, 0x3befbacb, 0x0b2cbecb, 0x1b2cbecb,
+ 0x2b2cbecb, 0x3b2cbecb, 0x0b6cbecb, 0x1b6cbecb, 0x2b6cbecb, 0x3b6cbecb,
+ 0x0bacbecb, 0x1bacbecb, 0x2bacbecb, 0x3bacbecb, 0x0becbecb, 0x1becbecb,
+ 0x2becbecb, 0x3becbecb, 0x0b2dbecb, 0x1b2dbecb, 0x2b2dbecb, 0x3b2dbecb,
+ 0x0b6dbecb, 0x1b6dbecb, 0x2b6dbecb, 0x3b6dbecb, 0x0badbecb, 0x1badbecb,
+ 0x2badbecb, 0x3badbecb, 0x0bedbecb, 0x1bedbecb, 0x2bedbecb, 0x3bedbecb,
+ 0x0b2ebecb, 0x1b2ebecb, 0x2b2ebecb, 0x3b2ebecb, 0x0b6ebecb, 0x1b6ebecb,
+ 0x2b6ebecb, 0x3b6ebecb, 0x0baebecb, 0x1baebecb, 0x2baebecb, 0x3baebecb,
+ 0x0beebecb, 0x1beebecb, 0x2beebecb, 0x3beebecb, 0x0b2fbecb, 0x1b2fbecb,
+ 0x2b2fbecb, 0x3b2fbecb, 0x0b6fbecb, 0x1b6fbecb, 0x2b6fbecb, 0x3b6fbecb,
+ 0x0bafbecb, 0x1bafbecb, 0x2bafbecb, 0x3bafbecb, 0x0befbecb, 0x1befbecb,
+ 0x2befbecb, 0x3befbecb, 0x0b2cb2db, 0x1b2cb2db, 0x2b2cb2db, 0x3b2cb2db,
+ 0x0b6cb2db, 0x1b6cb2db, 0x2b6cb2db, 0x3b6cb2db, 0x0bacb2db, 0x1bacb2db,
+ 0x2bacb2db, 0x3bacb2db, 0x0becb2db, 0x1becb2db, 0x2becb2db, 0x3becb2db,
+ 0x0b2db2db, 0x1b2db2db, 0x2b2db2db, 0x3b2db2db, 0x0b6db2db, 0x1b6db2db,
+ 0x2b6db2db, 0x3b6db2db, 0x0badb2db, 0x1badb2db, 0x2badb2db, 0x3badb2db,
+ 0x0bedb2db, 0x1bedb2db, 0x2bedb2db, 0x3bedb2db, 0x0b2eb2db, 0x1b2eb2db,
+ 0x2b2eb2db, 0x3b2eb2db, 0x0b6eb2db, 0x1b6eb2db, 0x2b6eb2db, 0x3b6eb2db,
+ 0x0baeb2db, 0x1baeb2db, 0x2baeb2db, 0x3baeb2db, 0x0beeb2db, 0x1beeb2db,
+ 0x2beeb2db, 0x3beeb2db, 0x0b2fb2db, 0x1b2fb2db, 0x2b2fb2db, 0x3b2fb2db,
+ 0x0b6fb2db, 0x1b6fb2db, 0x2b6fb2db, 0x3b6fb2db, 0x0bafb2db, 0x1bafb2db,
+ 0x2bafb2db, 0x3bafb2db, 0x0befb2db, 0x1befb2db, 0x2befb2db, 0x3befb2db,
+ 0x0b2cb6db, 0x1b2cb6db, 0x2b2cb6db, 0x3b2cb6db, 0x0b6cb6db, 0x1b6cb6db,
+ 0x2b6cb6db, 0x3b6cb6db, 0x0bacb6db, 0x1bacb6db, 0x2bacb6db, 0x3bacb6db,
+ 0x0becb6db, 0x1becb6db, 0x2becb6db, 0x3becb6db, 0x0b2db6db, 0x1b2db6db,
+ 0x2b2db6db, 0x3b2db6db, 0x0b6db6db, 0x1b6db6db, 0x2b6db6db, 0x3b6db6db,
+ 0x0badb6db, 0x1badb6db, 0x2badb6db, 0x3badb6db, 0x0bedb6db, 0x1bedb6db,
+ 0x2bedb6db, 0x3bedb6db, 0x0b2eb6db, 0x1b2eb6db, 0x2b2eb6db, 0x3b2eb6db,
+ 0x0b6eb6db, 0x1b6eb6db, 0x2b6eb6db, 0x3b6eb6db, 0x0baeb6db, 0x1baeb6db,
+ 0x2baeb6db, 0x3baeb6db,
+};
+
+static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+};
+
+static const uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
+ 0, 256, 128, 384, 64, 320, 192, 448,
+ 32, 288, 160, 416, 96, 352, 224, 480,
+ 16, 272, 144, 400, 80, 336, 208, 464,
+ 48, 304, 176, 432, 112, 368, 240, 496,
+ 8, 264, 136, 392, 72, 328, 200, 456,
+ 40, 296, 168, 424, 104, 360, 232, 488,
+ 24, 280, 152, 408, 88, 344, 216, 472,
+ 56, 312, 184, 440, 120, 376, 248, 504,
+ 4, 260, 132, 388, 68, 324, 196, 452,
+ 36, 292, 164, 420, 100, 356, 228, 484,
+ 20, 276, 148, 404, 84, 340, 212, 468,
+ 52, 308, 180, 436, 116, 372, 244, 500,
+ 12, 268, 140, 396, 76, 332, 204, 460,
+ 44, 300, 172, 428, 108, 364, 236, 492,
+ 28, 284, 156, 412, 92, 348, 220, 476,
+ 60, 316, 188, 444, 124, 380, 252, 508,
+ 2, 258, 130, 386, 66, 322, 194, 450,
+ 34, 290, 162, 418, 98, 354, 226, 482,
+ 18, 274, 146, 402, 82, 338, 210, 466,
+ 50, 306, 178, 434, 114, 370, 242, 498,
+ 10, 266, 138, 394, 74, 330, 202, 458,
+ 42, 298, 170, 426, 106, 362, 234, 490,
+ 26, 282, 154, 410, 90, 346, 218, 474,
+ 58, 314, 186, 442, 122, 378, 250, 506,
+ 6, 262, 134, 390, 70, 326, 198, 454,
+ 38, 294, 166, 422, 102, 358, 230, 486,
+ 22, 278, 150, 406, 86, 342, 214, 470,
+ 54, 310, 182, 438, 118, 374, 246, 502,
+ 14, 270, 142, 398, 78, 334, 206, 462,
+ 46, 302, 174, 430, 110, 366, 238, 494,
+ 30, 286, 158, 414, 94, 350, 222, 478,
+ 62, 318, 190, 446, 126, 382, 254, 510,
+ 1, 257, 129, 385, 65, 321, 193, 449,
+ 33, 289, 161, 417, 97, 353, 225, 481,
+ 17, 273, 145, 401, 81, 337, 209, 465,
+ 49, 305, 177, 433, 113, 369, 241, 497,
+ 9, 265, 137, 393, 73, 329, 201, 457,
+ 41, 297, 169, 425, 105, 361, 233, 489,
+ 25, 281, 153, 409, 89, 345, 217, 473,
+ 57, 313, 185, 441, 121, 377, 249, 505,
+ 5, 261, 133, 389, 69, 325, 197, 453,
+ 37, 293, 165, 421, 101, 357, 229, 485,
+ 21, 277, 149, 405, 85, 341, 213, 469,
+ 53, 309, 181, 437, 117, 373, 245, 501,
+ 13, 269, 141, 397, 77, 333, 205, 461,
+ 45, 301, 173, 429, 109, 365, 237, 493,
+ 29, 285, 157, 413, 93, 349, 221, 477,
+ 61, 317, 189, 445, 125, 381, 253, 509,
+ 3, 259, 131, 387, 67, 323, 195, 451,
+ 35, 291, 163, 419, 99, 355, 227, 483,
+ 19, 275, 147, 403, 83, 339, 211, 467,
+ 51, 307, 179, 435, 115, 371, 243, 499,
+ 11, 267, 139, 395, 75, 331, 203, 459,
+ 43, 299, 171, 427, 107, 363, 235, 491,
+ 27, 283, 155, 411, 91, 347, 219, 475,
+ 59, 315, 187, 443, 123, 379, 251, 507,
+ 7, 1031, 519, 1543, 263, 1287, 775, 1799,
+ 135, 1159, 647, 1671, 391, 1415, 903, 1927,
+ 71, 1095, 583, 1607, 327, 1351, 839, 1863,
+ 199, 1223, 711, 1735, 455, 1479, 967, 1991,
+ 39, 1063, 551, 1575, 295, 1319, 807, 1831,
+ 167, 1191, 679, 1703, 423, 1447, 935, 1959,
+ 103, 1127, 615, 1639, 359, 1383, 871, 1895,
+ 231, 1255, 743, 1767, 487, 1511, 999, 2023,
+ 23, 1047, 535, 1559, 279, 1303, 791, 1815,
+ 151, 1175, 663, 1687, 407, 1431, 919, 1943,
+ 87, 1111, 599, 1623, 343, 1367, 855, 1879,
+ 215, 1239, 727, 1751, 471, 1495, 983, 2007,
+ 55, 1079, 567, 1591, 311, 1335, 823, 1847,
+ 183, 1207, 695, 1719, 439, 1463, 951, 1975,
+ 119, 1143, 631, 1655, 375, 1399, 887, 1911,
+ 247, 1271, 759, 1783, 503, 1527, 1015, 2039,
+ 15, 1039, 527, 1551, 271, 1295, 783, 1807,
+ 143, 1167, 655, 1679, 399, 1423, 911, 1935,
+ 79, 1103, 591, 1615, 335, 1359, 847, 1871,
+ 207, 1231, 719, 1743, 463, 1487, 975, 1999,
+ 47, 1071, 559, 1583, 303, 1327, 815, 1839,
+ 175, 1199, 687, 1711, 431, 1455, 943, 1967,
+ 111, 1135, 623, 1647, 367, 1391, 879, 1903,
+ 239, 1263, 751, 1775, 495, 1519, 1007, 2031,
+ 31, 1055, 543, 1567, 287, 1311, 799, 1823,
+ 159, 1183, 671, 1695, 415, 1439, 927, 1951,
+ 95, 1119, 607, 1631, 351, 1375, 863, 1887,
+ 223, 1247, 735, 1759, 479, 1503, 991, 2015,
+ 63, 1087, 575, 1599, 319, 1343, 831, 1855,
+ 191, 1215, 703, 1727, 447, 1471, 959, 1983,
+ 127, 1151, 639, 1663, 383, 1407, 895, 1919,
+ 255, 1279, 767, 1791, 511, 1535, 1023, 2047,
+};
+
+static BROTLI_INLINE void StoreStaticCommandHuffmanTree(
+ size_t* storage_ix, uint8_t* storage) {
+ BrotliWriteBits(
+ 56, BROTLI_MAKE_UINT64_T(0x926244U, 0x16307003U), storage_ix, storage);
+ BrotliWriteBits(3, 0x00000000U, storage_ix, storage);
+}
+
+static const uint16_t kStaticDistanceCodeBits[64] = {
+ 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
+ 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
+ 1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
+ 3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63,
+};
+
+static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
+ size_t* storage_ix, uint8_t* storage) {
+ BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/fast_log.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/fast_log.h
new file mode 100644
index 000000000..cade1235a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/fast_log.h
@@ -0,0 +1,147 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for fast computation of logarithms. */
+
+#ifndef BROTLI_ENC_FAST_LOG_H_
+#define BROTLI_ENC_FAST_LOG_H_
+
+#include <math.h>
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
+ /* TODO: generalize and move to platform.h */
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
+ return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
+#else
+ uint32_t result = 0;
+ while (n >>= 1) result++;
+ return result;
+#endif
+}
+
+/* A lookup table for small values of log2(int) to be used in entropy
+ computation.
+
+ ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
+static const float kLog2Table[] = {
+ 0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
+ 1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
+ 2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
+ 3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
+ 3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
+ 3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
+ 4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
+ 4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
+ 4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
+ 4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
+ 4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
+ 5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
+ 5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
+ 5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
+ 5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
+ 5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
+ 5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
+ 5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
+ 5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
+ 5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
+ 5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
+ 5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
+ 6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
+ 6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
+ 6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
+ 6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
+ 6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
+ 6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
+ 6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
+ 6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
+ 6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
+ 6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
+ 6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
+ 6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
+ 6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
+ 6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
+ 6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
+ 6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
+ 6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
+ 6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
+ 6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
+ 6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
+ 6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
+ 7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
+ 7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
+ 7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
+ 7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
+ 7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
+ 7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
+ 7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
+ 7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
+ 7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
+ 7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
+ 7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
+ 7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
+ 7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
+ 7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
+ 7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
+ 7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
+ 7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
+ 7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
+ 7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
+ 7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
+ 7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
+ 7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
+ 7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
+ 7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
+ 7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
+ 7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
+ 7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
+ 7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
+ 7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
+ 7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
+ 7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
+ 7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
+ 7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
+ 7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
+ 7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
+ 7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
+ 7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
+ 7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
+ 7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
+ 7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
+ 7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
+ 7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
+ 7.9943534368588578f
+};
+
+#define LOG_2_INV 1.4426950408889634
+
+/* Faster logarithm for small integers, with the property of log2(0) == 0. */
+static BROTLI_INLINE double FastLog2(size_t v) {
+ if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
+ return kLog2Table[v];
+ }
+#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
+ (defined(__ANDROID_API__) && __ANDROID_API__ < 18)
+ /* Visual Studio 2012 and Android API levels < 18 do not have the log2()
+ * function defined, so we use log() and a multiplication instead. */
+ return log((double)v) * LOG_2_INV;
+#else
+ return log2((double)v);
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_FAST_LOG_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/find_match_length.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/find_match_length.h
new file mode 100644
index 000000000..bc428cffd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/find_match_length.h
@@ -0,0 +1,80 @@
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find maximal matching prefixes of strings. */
+
+#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
+#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Separate implementation for little-endian 64-bit targets, for speed. */
+#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN)
+
+static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
+ const uint8_t* s2,
+ size_t limit) {
+ size_t matched = 0;
+ size_t limit2 = (limit >> 3) + 1; /* + 1 is for pre-decrement in while */
+ while (BROTLI_PREDICT_TRUE(--limit2)) {
+ if (BROTLI_PREDICT_FALSE(BROTLI_UNALIGNED_LOAD64LE(s2) ==
+ BROTLI_UNALIGNED_LOAD64LE(s1 + matched))) {
+ s2 += 8;
+ matched += 8;
+ } else {
+ uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
+ BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
+ size_t matching_bits = (size_t)__builtin_ctzll(x);
+ matched += matching_bits >> 3;
+ return matched;
+ }
+ }
+ limit = (limit & 7) + 1; /* + 1 is for pre-decrement in while */
+ while (--limit) {
+ if (BROTLI_PREDICT_TRUE(s1[matched] == *s2)) {
+ ++s2;
+ ++matched;
+ } else {
+ return matched;
+ }
+ }
+ return matched;
+}
+#else
+static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
+ const uint8_t* s2,
+ size_t limit) {
+ size_t matched = 0;
+ const uint8_t* s2_limit = s2 + limit;
+ const uint8_t* s2_ptr = s2;
+ /* Find out how long the match is. We loop over the data 32 bits at a
+ time until we find a 32-bit block that doesn't match; then we find
+ the first non-matching bit and use that to calculate the total
+ length of the match. */
+ while (s2_ptr <= s2_limit - 4 &&
+ BrotliUnalignedRead32(s2_ptr) ==
+ BrotliUnalignedRead32(s1 + matched)) {
+ s2_ptr += 4;
+ matched += 4;
+ }
+ while ((s2_ptr < s2_limit) && (s1[matched] == *s2_ptr)) {
+ ++s2_ptr;
+ ++matched;
+ }
+ return matched;
+}
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_FIND_MATCH_LENGTH_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash.h
new file mode 100644
index 000000000..6362f69b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash.h
@@ -0,0 +1,488 @@
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data. */
+
+#ifndef BROTLI_ENC_HASH_H_
+#define BROTLI_ENC_HASH_H_
+
+#include <string.h> /* memcmp, memset */
+
+#include "../common/constants.h"
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./encoder_dict.h"
+#include "./fast_log.h"
+#include "./find_match_length.h"
+#include "./memory.h"
+#include "./quality.h"
+#include "./static_dict.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct {
+ /* Dynamically allocated area; first member for quickest access. */
+ void* extra;
+
+ size_t dict_num_lookups;
+ size_t dict_num_matches;
+
+ BrotliHasherParams params;
+
+ /* False if hasher needs to be "prepared" before use. */
+ BROTLI_BOOL is_prepared_;
+} HasherCommon;
+
+#define score_t size_t
+
+static const uint32_t kCutoffTransformsCount = 10;
+/* 0, 12, 27, 23, 42, 63, 56, 48, 59, 64 */
+/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */
+static const uint64_t kCutoffTransforms =
+ BROTLI_MAKE_UINT64_T(0x071B520A, 0xDA2D3200);
+
+typedef struct HasherSearchResult {
+ size_t len;
+ size_t distance;
+ score_t score;
+ int len_code_delta; /* == len_code - len */
+} HasherSearchResult;
+
+/* kHashMul32 multiplier has these properties:
+ * The multiplier must be odd. Otherwise we may lose the highest bit.
+ * No long streaks of ones or zeros.
+ * There is no effort to ensure that it is a prime, the oddity is enough
+ for this use.
+ * The number has been tuned heuristically against compression benchmarks. */
+static const uint32_t kHashMul32 = 0x1E35A7BD;
+static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
+static const uint64_t kHashMul64Long =
+ BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
+
+static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
+ uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - 14);
+}
+
+static BROTLI_INLINE void PrepareDistanceCache(
+ int* BROTLI_RESTRICT distance_cache, const int num_distances) {
+ if (num_distances > 4) {
+ int last_distance = distance_cache[0];
+ distance_cache[4] = last_distance - 1;
+ distance_cache[5] = last_distance + 1;
+ distance_cache[6] = last_distance - 2;
+ distance_cache[7] = last_distance + 2;
+ distance_cache[8] = last_distance - 3;
+ distance_cache[9] = last_distance + 3;
+ if (num_distances > 10) {
+ int next_last_distance = distance_cache[1];
+ distance_cache[10] = next_last_distance - 1;
+ distance_cache[11] = next_last_distance + 1;
+ distance_cache[12] = next_last_distance - 2;
+ distance_cache[13] = next_last_distance + 2;
+ distance_cache[14] = next_last_distance - 3;
+ distance_cache[15] = next_last_distance + 3;
+ }
+ }
+}
+
+#define BROTLI_LITERAL_BYTE_SCORE 135
+#define BROTLI_DISTANCE_BIT_PENALTY 30
+/* Score must be positive after applying maximal penalty. */
+#define BROTLI_SCORE_BASE (BROTLI_DISTANCE_BIT_PENALTY * 8 * sizeof(size_t))
+
+/* Usually, we always choose the longest backward reference. This function
+ allows for the exception of that rule.
+
+ If we choose a backward reference that is further away, it will
+ usually be coded with more bits. We approximate this by assuming
+ log2(distance). If the distance can be expressed in terms of the
+ last four distances, we use some heuristic constants to estimate
+ the bits cost. For the first up to four literals we use the bit
+ cost of the literals from the literal cost model, after that we
+ use the average bit cost of the cost model.
+
+ This function is used to sometimes discard a longer backward reference
+ when it is not much longer and the bit cost for encoding it is more
+ than the saved literals.
+
+ backward_reference_offset MUST be positive. */
+static BROTLI_INLINE score_t BackwardReferenceScore(
+ size_t copy_length, size_t backward_reference_offset) {
+ return BROTLI_SCORE_BASE + BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length -
+ BROTLI_DISTANCE_BIT_PENALTY * Log2FloorNonZero(backward_reference_offset);
+}
+
+static BROTLI_INLINE score_t BackwardReferenceScoreUsingLastDistance(
+ size_t copy_length) {
+ return BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length +
+ BROTLI_SCORE_BASE + 15;
+}
+
+static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
+ size_t distance_short_code) {
+ return (score_t)39 + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE);
+}
+
+static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
+ const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
+ const uint8_t* data, size_t max_length, size_t max_backward,
+ size_t max_distance, HasherSearchResult* out) {
+ size_t offset;
+ size_t matchlen;
+ size_t backward;
+ score_t score;
+ offset = dictionary->words->offsets_by_length[len] + len * word_idx;
+ if (len > max_length) {
+ return BROTLI_FALSE;
+ }
+
+ matchlen =
+ FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len);
+ if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) {
+ return BROTLI_FALSE;
+ }
+ {
+ size_t cut = len - matchlen;
+ size_t transform_id = (cut << 2) +
+ (size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
+ backward = max_backward + 1 + word_idx +
+ (transform_id << dictionary->words->size_bits_by_length[len]);
+ }
+ if (backward > max_distance) {
+ return BROTLI_FALSE;
+ }
+ score = BackwardReferenceScore(matchlen, backward);
+ if (score < out->score) {
+ return BROTLI_FALSE;
+ }
+ out->len = matchlen;
+ out->len_code_delta = (int)len - (int)matchlen;
+ out->distance = backward;
+ out->score = score;
+ return BROTLI_TRUE;
+}
+
+static BROTLI_INLINE void SearchInStaticDictionary(
+ const BrotliEncoderDictionary* dictionary,
+ HasherCommon* common, const uint8_t* data, size_t max_length,
+ size_t max_backward, size_t max_distance,
+ HasherSearchResult* out, BROTLI_BOOL shallow) {
+ size_t key;
+ size_t i;
+ if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
+ return;
+ }
+ key = Hash14(data) << 1;
+ for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
+ common->dict_num_lookups++;
+ if (dictionary->hash_table_lengths[key] != 0) {
+ BROTLI_BOOL item_matches = TestStaticDictionaryItem(
+ dictionary, dictionary->hash_table_lengths[key],
+ dictionary->hash_table_words[key], data,
+ max_length, max_backward, max_distance, out);
+ if (item_matches) {
+ common->dict_num_matches++;
+ }
+ }
+ }
+}
+
+typedef struct BackwardMatch {
+ uint32_t distance;
+ uint32_t length_and_code;
+} BackwardMatch;
+
+static BROTLI_INLINE void InitBackwardMatch(BackwardMatch* self,
+ size_t dist, size_t len) {
+ self->distance = (uint32_t)dist;
+ self->length_and_code = (uint32_t)(len << 5);
+}
+
+static BROTLI_INLINE void InitDictionaryBackwardMatch(BackwardMatch* self,
+ size_t dist, size_t len, size_t len_code) {
+ self->distance = (uint32_t)dist;
+ self->length_and_code =
+ (uint32_t)((len << 5) | (len == len_code ? 0 : len_code));
+}
+
+static BROTLI_INLINE size_t BackwardMatchLength(const BackwardMatch* self) {
+ return self->length_and_code >> 5;
+}
+
+static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
+ size_t code = self->length_and_code & 31;
+ return code ? code : BackwardMatchLength(self);
+}
+
+#define EXPAND_CAT(a, b) CAT(a, b)
+#define CAT(a, b) a ## b
+#define FN(X) EXPAND_CAT(X, HASHER())
+
+#define HASHER() H10
+#define BUCKET_BITS 17
+#define MAX_TREE_SEARCH_DEPTH 64
+#define MAX_TREE_COMP_LENGTH 128
+#include "./hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
+#undef MAX_TREE_SEARCH_DEPTH
+#undef MAX_TREE_COMP_LENGTH
+#undef BUCKET_BITS
+#undef HASHER
+/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
+#define MAX_NUM_MATCHES_H10 128
+
+/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
+ a little faster (0.5% - 1%) and it compresses 0.15% better on small text
+ and HTML inputs. */
+
+#define HASHER() H2
+#define BUCKET_BITS 16
+#define BUCKET_SWEEP_BITS 0
+#define HASH_LEN 5
+#define USE_DICTIONARY 1
+#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
+#undef BUCKET_SWEEP_BITS
+#undef USE_DICTIONARY
+#undef HASHER
+
+#define HASHER() H3
+#define BUCKET_SWEEP_BITS 1
+#define USE_DICTIONARY 0
+#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
+#undef USE_DICTIONARY
+#undef BUCKET_SWEEP_BITS
+#undef BUCKET_BITS
+#undef HASHER
+
+#define HASHER() H4
+#define BUCKET_BITS 17
+#define BUCKET_SWEEP_BITS 2
+#define USE_DICTIONARY 1
+#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
+#undef USE_DICTIONARY
+#undef HASH_LEN
+#undef BUCKET_SWEEP_BITS
+#undef BUCKET_BITS
+#undef HASHER
+
+#define HASHER() H5
+#include "./hash_longest_match_inc.h" /* NOLINT(build/include) */
+#undef HASHER
+
+#define HASHER() H6
+#include "./hash_longest_match64_inc.h" /* NOLINT(build/include) */
+#undef HASHER
+
+#define BUCKET_BITS 15
+
+#define NUM_LAST_DISTANCES_TO_CHECK 4
+#define NUM_BANKS 1
+#define BANK_BITS 16
+#define HASHER() H40
+#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
+#undef HASHER
+#undef NUM_LAST_DISTANCES_TO_CHECK
+
+#define NUM_LAST_DISTANCES_TO_CHECK 10
+#define HASHER() H41
+#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
+#undef HASHER
+#undef NUM_LAST_DISTANCES_TO_CHECK
+#undef NUM_BANKS
+#undef BANK_BITS
+
+#define NUM_LAST_DISTANCES_TO_CHECK 16
+#define NUM_BANKS 512
+#define BANK_BITS 9
+#define HASHER() H42
+#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
+#undef HASHER
+#undef NUM_LAST_DISTANCES_TO_CHECK
+#undef NUM_BANKS
+#undef BANK_BITS
+
+#undef BUCKET_BITS
+
+#define HASHER() H54
+#define BUCKET_BITS 20
+#define BUCKET_SWEEP_BITS 2
+#define HASH_LEN 7
+#define USE_DICTIONARY 0
+#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
+#undef USE_DICTIONARY
+#undef HASH_LEN
+#undef BUCKET_SWEEP_BITS
+#undef BUCKET_BITS
+#undef HASHER
+
+/* fast large window hashers */
+
+#define HASHER() HROLLING_FAST
+#define CHUNKLEN 32
+#define JUMP 4
+#define NUMBUCKETS 16777216
+#define MASK ((NUMBUCKETS * 64) - 1)
+#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
+#undef JUMP
+#undef HASHER
+
+
+#define HASHER() HROLLING
+#define JUMP 1
+#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
+#undef MASK
+#undef NUMBUCKETS
+#undef JUMP
+#undef CHUNKLEN
+#undef HASHER
+
+#define HASHER() H35
+#define HASHER_A H3
+#define HASHER_B HROLLING_FAST
+#include "./hash_composite_inc.h" /* NOLINT(build/include) */
+#undef HASHER_A
+#undef HASHER_B
+#undef HASHER
+
+#define HASHER() H55
+#define HASHER_A H54
+#define HASHER_B HROLLING_FAST
+#include "./hash_composite_inc.h" /* NOLINT(build/include) */
+#undef HASHER_A
+#undef HASHER_B
+#undef HASHER
+
+#define HASHER() H65
+#define HASHER_A H6
+#define HASHER_B HROLLING
+#include "./hash_composite_inc.h" /* NOLINT(build/include) */
+#undef HASHER_A
+#undef HASHER_B
+#undef HASHER
+
+#undef FN
+#undef CAT
+#undef EXPAND_CAT
+
+#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
+#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
+#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
+#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
+
+typedef struct {
+ HasherCommon common;
+
+ union {
+#define MEMBER_(N) \
+ H ## N _H ## N;
+ FOR_ALL_HASHERS(MEMBER_)
+#undef MEMBER_
+ } privat;
+} Hasher;
+
+/* MUST be invoked before any other method. */
+static BROTLI_INLINE void HasherInit(Hasher* hasher) {
+ hasher->common.extra = NULL;
+}
+
+static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
+ if (hasher->common.extra == NULL) return;
+ BROTLI_FREE(m, hasher->common.extra);
+}
+
+static BROTLI_INLINE void HasherReset(Hasher* hasher) {
+ hasher->common.is_prepared_ = BROTLI_FALSE;
+}
+
+static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
+ BROTLI_BOOL one_shot, const size_t input_size) {
+ switch (params->hasher.type) {
+#define SIZE_(N) \
+ case N: \
+ return HashMemAllocInBytesH ## N(params, one_shot, input_size);
+ FOR_ALL_HASHERS(SIZE_)
+#undef SIZE_
+ default:
+ break;
+ }
+ return 0; /* Default case. */
+}
+
+static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
+ BrotliEncoderParams* params, const uint8_t* data, size_t position,
+ size_t input_size, BROTLI_BOOL is_last) {
+ BROTLI_BOOL one_shot = (position == 0 && is_last);
+ if (hasher->common.extra == NULL) {
+ size_t alloc_size;
+ ChooseHasher(params, &params->hasher);
+ alloc_size = HasherSize(params, one_shot, input_size);
+ hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
+ hasher->common.params = params->hasher;
+ switch (hasher->common.params.type) {
+#define INITIALIZE_(N) \
+ case N: \
+ InitializeH ## N(&hasher->common, \
+ &hasher->privat._H ## N, params); \
+ break;
+ FOR_ALL_HASHERS(INITIALIZE_);
+#undef INITIALIZE_
+ default:
+ break;
+ }
+ HasherReset(hasher);
+ }
+
+ if (!hasher->common.is_prepared_) {
+ switch (hasher->common.params.type) {
+#define PREPARE_(N) \
+ case N: \
+ PrepareH ## N( \
+ &hasher->privat._H ## N, \
+ one_shot, input_size, data); \
+ break;
+ FOR_ALL_HASHERS(PREPARE_)
+#undef PREPARE_
+ default: break;
+ }
+ if (position == 0) {
+ hasher->common.dict_num_lookups = 0;
+ hasher->common.dict_num_matches = 0;
+ }
+ hasher->common.is_prepared_ = BROTLI_TRUE;
+ }
+}
+
+static BROTLI_INLINE void InitOrStitchToPreviousBlock(
+ MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
+ BrotliEncoderParams* params, size_t position, size_t input_size,
+ BROTLI_BOOL is_last) {
+ HasherSetup(m, hasher, params, data, position, input_size, is_last);
+ if (BROTLI_IS_OOM(m)) return;
+ switch (hasher->common.params.type) {
+#define INIT_(N) \
+ case N: \
+ StitchToPreviousBlockH ## N( \
+ &hasher->privat._H ## N, \
+ input_size, position, data, mask); \
+ break;
+ FOR_ALL_HASHERS(INIT_)
+#undef INIT_
+ default: break;
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_HASH_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_composite_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_composite_inc.h
new file mode 100755
index 000000000..cba156c0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_composite_inc.h
@@ -0,0 +1,125 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, HASHER_A, HASHER_B */
+
+/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
+ and HASHER_B. */
+
+#define HashComposite HASHER()
+
+#define FN_A(X) EXPAND_CAT(X, HASHER_A)
+#define FN_B(X) EXPAND_CAT(X, HASHER_B)
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) {
+ size_t a = FN_A(HashTypeLength)();
+ size_t b = FN_B(HashTypeLength)();
+ return a > b ? a : b;
+}
+
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
+ size_t a = FN_A(StoreLookahead)();
+ size_t b = FN_B(StoreLookahead)();
+ return a > b ? a : b;
+}
+
+typedef struct HashComposite {
+ HASHER_A ha;
+ HASHER_B hb;
+ HasherCommon hb_common;
+
+ /* Shortcuts. */
+ void* extra;
+ HasherCommon* common;
+
+ BROTLI_BOOL fresh;
+ const BrotliEncoderParams* params;
+} HashComposite;
+
+static void FN(Initialize)(HasherCommon* common,
+ HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
+ self->common = common;
+ self->extra = common->extra;
+
+ self->hb_common = *self->common;
+ self->fresh = BROTLI_TRUE;
+ self->params = params;
+ /* TODO: Initialize of the hashers is defered to Prepare (and params
+ remembered here) because we don't get the one_shot and input_size params
+ here that are needed to know the memory size of them. Instead provide
+ those params to all hashers FN(Initialize) */
+}
+
+static void FN(Prepare)(
+ HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ if (self->fresh) {
+ self->fresh = BROTLI_FALSE;
+ self->hb_common.extra = (uint8_t*)self->extra +
+ FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
+
+ FN_A(Initialize)(self->common, &self->ha, self->params);
+ FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
+ }
+ FN_A(Prepare)(&self->ha, one_shot, input_size, data);
+ FN_B(Prepare)(&self->hb, one_shot, input_size, data);
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
+ FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
+}
+
+static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
+ FN_A(Store)(&self->ha, data, mask, ix);
+ FN_B(Store)(&self->hb, data, mask, ix);
+}
+
+static BROTLI_INLINE void FN(StoreRange)(
+ HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
+ const size_t mask, const size_t ix_start,
+ const size_t ix_end) {
+ FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
+ FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashComposite* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ring_buffer_mask) {
+ FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
+ ringbuffer, ring_buffer_mask);
+ FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
+ ringbuffer, ring_buffer_mask);
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
+ FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
+ FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
+}
+
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashComposite* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
+ const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
+ const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
+ distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
+ max_distance, out);
+ FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
+ distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
+ max_distance, out);
+}
+
+#undef HashComposite
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_forgetful_chain_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_forgetful_chain_inc.h
new file mode 100644
index 000000000..bfae6ba6a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_forgetful_chain_inc.h
@@ -0,0 +1,293 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, BUCKET_BITS, NUM_BANKS, BANK_BITS,
+ NUM_LAST_DISTANCES_TO_CHECK */
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ Hashes are stored in chains which are bucketed to groups. Group of chains
+ share a storage "bank". When more than "bank size" chain nodes are added,
+ oldest nodes are replaced; this way several chains may share a tail. */
+
+#define HashForgetfulChain HASHER()
+
+#define BANK_SIZE (1 << BANK_BITS)
+
+/* Number of hash buckets. */
+#define BUCKET_SIZE (1 << BUCKET_BITS)
+
+#define CAPPED_CHAINS 0
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
+
+/* HashBytes is the function that chooses the bucket to place the address in.*/
+static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
+ const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - BUCKET_BITS);
+}
+
+typedef struct FN(Slot) {
+ uint16_t delta;
+ uint16_t next;
+} FN(Slot);
+
+typedef struct FN(Bank) {
+ FN(Slot) slots[BANK_SIZE];
+} FN(Bank);
+
+typedef struct HashForgetfulChain {
+ uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
+ size_t max_hops;
+
+ /* Shortcuts. */
+ void* extra;
+ HasherCommon* common;
+
+ /* --- Dynamic size members --- */
+
+ /* uint32_t addr[BUCKET_SIZE]; */
+
+ /* uint16_t head[BUCKET_SIZE]; */
+
+ /* Truncated hash used for quick rejection of "distance cache" candidates. */
+ /* uint8_t tiny_hash[65536];*/
+
+ /* FN(Bank) banks[NUM_BANKS]; */
+} HashForgetfulChain;
+
+static uint32_t* FN(Addr)(void* extra) {
+ return (uint32_t*)extra;
+}
+
+static uint16_t* FN(Head)(void* extra) {
+ return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
+}
+
+static uint8_t* FN(TinyHash)(void* extra) {
+ return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
+}
+
+static FN(Bank)* FN(Banks)(void* extra) {
+ return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
+}
+
+static void FN(Initialize)(
+ HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ self->common = common;
+ self->extra = common->extra;
+
+ self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
+}
+
+static void FN(Prepare)(
+ HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+ uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+ uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
+ /* Partial preparation is 100 times slower (per socket). */
+ size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
+ if (one_shot && input_size <= partial_prepare_threshold) {
+ size_t i;
+ for (i = 0; i < input_size; ++i) {
+ size_t bucket = FN(HashBytes)(&data[i]);
+ /* See InitEmpty comment. */
+ addr[bucket] = 0xCCCCCCCC;
+ head[bucket] = 0xCCCC;
+ }
+ } else {
+ /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
+ processed by hasher never reaches 3GB + 64M; this makes all new chains
+ to be terminated after the first node. */
+ memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
+ memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
+ }
+ memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
+ memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ BROTLI_UNUSED(params);
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+ return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
+ sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
+}
+
+/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
+ node to corresponding chain; also update tiny_hash for current position. */
+static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
+ uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+ uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+ uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
+ FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
+ const size_t key = FN(HashBytes)(&data[ix & mask]);
+ const size_t bank = key & (NUM_BANKS - 1);
+ const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
+ size_t delta = ix - addr[key];
+ tiny_hash[(uint16_t)ix] = (uint8_t)key;
+ if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
+ banks[bank].slots[idx].delta = (uint16_t)delta;
+ banks[bank].slots[idx].next = head[key];
+ addr[key] = (uint32_t)ix;
+ head[key] = (uint16_t)idx;
+}
+
+static BROTLI_INLINE void FN(StoreRange)(
+ HashForgetfulChain* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ size_t i;
+ for (i = ix_start; i < ix_end; ++i) {
+ FN(Store)(self, data, mask, i);
+ }
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashForgetfulChain* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ring_buffer_mask) {
+ if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
+ FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
+ FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
+ }
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashForgetfulChain* BROTLI_RESTRICT self,
+ int* BROTLI_RESTRICT distance_cache) {
+ BROTLI_UNUSED(self);
+ PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke FN(PrepareDistanceCache) once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashForgetfulChain* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
+ const int* BROTLI_RESTRICT distance_cache,
+ const size_t cur_ix, const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+ uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+ uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
+ FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ /* Don't accept a short copy from far away. */
+ score_t min_score = out->score;
+ score_t best_score = out->score;
+ size_t best_len = out->len;
+ size_t i;
+ const size_t key = FN(HashBytes)(&data[cur_ix_masked]);
+ const uint8_t tiny_hash = (uint8_t)(key);
+ out->len = 0;
+ out->len_code_delta = 0;
+ /* Try last distance first. */
+ for (i = 0; i < NUM_LAST_DISTANCES_TO_CHECK; ++i) {
+ const size_t backward = (size_t)distance_cache[i];
+ size_t prev_ix = (cur_ix - backward);
+ /* For distance code 0 we want to consider 2-byte matches. */
+ if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
+ if (prev_ix >= cur_ix || backward > max_backward) {
+ continue;
+ }
+ prev_ix &= ring_buffer_mask;
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 2) {
+ score_t score = BackwardReferenceScoreUsingLastDistance(len);
+ if (best_score < score) {
+ if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ }
+ {
+ const size_t bank = key & (NUM_BANKS - 1);
+ size_t backward = 0;
+ size_t hops = self->max_hops;
+ size_t delta = cur_ix - addr[key];
+ size_t slot = head[key];
+ while (hops--) {
+ size_t prev_ix;
+ size_t last = slot;
+ backward += delta;
+ if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
+ prev_ix = (cur_ix - backward) & ring_buffer_mask;
+ slot = banks[bank].slots[last].next;
+ delta = banks[bank].slots[last].delta;
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
+ prev_ix + best_len > ring_buffer_mask ||
+ data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
+ continue;
+ }
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4) {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ score_t score = BackwardReferenceScore(len, backward);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ FN(Store)(self, data, ring_buffer_mask, cur_ix);
+ }
+ if (out->score == min_score) {
+ SearchInStaticDictionary(dictionary,
+ self->common, &data[cur_ix_masked], max_length, dictionary_distance,
+ max_distance, out, BROTLI_FALSE);
+ }
+}
+
+#undef BANK_SIZE
+#undef BUCKET_SIZE
+#undef CAPPED_CHAINS
+
+#undef HashForgetfulChain
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match64_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match64_inc.h
new file mode 100644
index 000000000..bdee7e41b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match64_inc.h
@@ -0,0 +1,267 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN */
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+
+#define HashLongestMatch HASHER()
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
+ const uint64_t mask,
+ const int shift) {
+ const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return (uint32_t)(h >> shift);
+}
+
+typedef struct HashLongestMatch {
+ /* Number of hash buckets. */
+ size_t bucket_size_;
+ /* Only block_size_ newest backward references are kept,
+ and the older are forgotten. */
+ size_t block_size_;
+ /* Left-shift for computing hash bucket index from hash value. */
+ int hash_shift_;
+ /* Mask for selecting the next 4-8 bytes of input */
+ uint64_t hash_mask_;
+ /* Mask for accessing entries in a block (in a ring-buffer manner). */
+ uint32_t block_mask_;
+
+ int block_bits_;
+ int num_last_distances_to_check_;
+
+ /* Shortcuts. */
+ HasherCommon* common_;
+
+ /* --- Dynamic size members --- */
+
+ /* Number of entries in a particular bucket. */
+ uint16_t* num_; /* uint16_t[bucket_size]; */
+
+ /* Buckets containing block_size_ of backward references. */
+ uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
+} HashLongestMatch;
+
+static void FN(Initialize)(
+ HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ self->common_ = common;
+
+ BROTLI_UNUSED(params);
+ self->hash_shift_ = 64 - common->params.bucket_bits;
+ self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
+ self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
+ self->block_bits_ = common->params.block_bits;
+ self->block_size_ = (size_t)1 << common->params.block_bits;
+ self->block_mask_ = (uint32_t)(self->block_size_ - 1);
+ self->num_last_distances_to_check_ =
+ common->params.num_last_distances_to_check;
+ self->num_ = (uint16_t*)common->extra;
+ self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
+}
+
+static void FN(Prepare)(
+ HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ uint16_t* BROTLI_RESTRICT num = self->num_;
+ /* Partial preparation is 100 times slower (per socket). */
+ size_t partial_prepare_threshold = self->bucket_size_ >> 6;
+ if (one_shot && input_size <= partial_prepare_threshold) {
+ size_t i;
+ for (i = 0; i < input_size; ++i) {
+ const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_,
+ self->hash_shift_);
+ num[key] = 0;
+ }
+ } else {
+ memset(num, 0, self->bucket_size_ * sizeof(num[0]));
+ }
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
+ size_t block_size = (size_t)1 << params->hasher.block_bits;
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+ return sizeof(uint16_t) * bucket_size +
+ sizeof(uint32_t) * bucket_size * block_size;
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+static BROTLI_INLINE void FN(Store)(
+ HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
+ const size_t mask, const size_t ix) {
+ uint16_t* BROTLI_RESTRICT num = self->num_;
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
+ self->hash_shift_);
+ const size_t minor_ix = num[key] & self->block_mask_;
+ const size_t offset = minor_ix + (key << self->block_bits_);
+ buckets[offset] = (uint32_t)ix;
+ ++num[key];
+}
+
+static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ size_t i;
+ for (i = ix_start; i < ix_end; ++i) {
+ FN(Store)(self, data, mask, i);
+ }
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ringbuffer_mask) {
+ if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
+ }
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ int* BROTLI_RESTRICT distance_cache) {
+ PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke FN(PrepareDistanceCache) once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
+ const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
+ const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ uint16_t* BROTLI_RESTRICT num = self->num_;
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ /* Don't accept a short copy from far away. */
+ score_t min_score = out->score;
+ score_t best_score = out->score;
+ size_t best_len = out->len;
+ size_t i;
+ out->len = 0;
+ out->len_code_delta = 0;
+ /* Try last distance first. */
+ for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
+ const size_t backward = (size_t)distance_cache[i];
+ size_t prev_ix = (size_t)(cur_ix - backward);
+ if (prev_ix >= cur_ix) {
+ continue;
+ }
+ if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
+ continue;
+ }
+ prev_ix &= ring_buffer_mask;
+
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
+ prev_ix + best_len > ring_buffer_mask ||
+ data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
+ continue;
+ }
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 3 || (len == 2 && i < 2)) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ score_t score = BackwardReferenceScoreUsingLastDistance(len);
+ if (best_score < score) {
+ if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ }
+ {
+ const uint32_t key = FN(HashBytes)(
+ &data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
+ uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
+ const size_t down =
+ (num[key] > self->block_size_) ?
+ (num[key] - self->block_size_) : 0u;
+ for (i = num[key]; i > down;) {
+ size_t prev_ix = bucket[--i & self->block_mask_];
+ const size_t backward = cur_ix - prev_ix;
+ if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
+ break;
+ }
+ prev_ix &= ring_buffer_mask;
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
+ prev_ix + best_len > ring_buffer_mask ||
+ data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
+ continue;
+ }
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4) {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ score_t score = BackwardReferenceScore(len, backward);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
+ ++num[key];
+ }
+ if (min_score == out->score) {
+ SearchInStaticDictionary(dictionary,
+ self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
+ max_distance, out, BROTLI_FALSE);
+ }
+}
+
+#undef HashLongestMatch
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_inc.h
new file mode 100644
index 000000000..27f4463d7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_inc.h
@@ -0,0 +1,262 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN */
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+
+#define HashLongestMatch HASHER()
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+static uint32_t FN(HashBytes)(
+ const uint8_t* BROTLI_RESTRICT data, const int shift) {
+ uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return (uint32_t)(h >> shift);
+}
+
+typedef struct HashLongestMatch {
+ /* Number of hash buckets. */
+ size_t bucket_size_;
+ /* Only block_size_ newest backward references are kept,
+ and the older are forgotten. */
+ size_t block_size_;
+ /* Left-shift for computing hash bucket index from hash value. */
+ int hash_shift_;
+ /* Mask for accessing entries in a block (in a ring-buffer manner). */
+ uint32_t block_mask_;
+
+ int block_bits_;
+ int num_last_distances_to_check_;
+
+ /* Shortcuts. */
+ HasherCommon* common_;
+
+ /* --- Dynamic size members --- */
+
+ /* Number of entries in a particular bucket. */
+ uint16_t* num_; /* uint16_t[bucket_size]; */
+
+ /* Buckets containing block_size_ of backward references. */
+ uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
+} HashLongestMatch;
+
+static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
+ return (uint16_t*)extra;
+}
+
+static void FN(Initialize)(
+ HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ self->common_ = common;
+
+ BROTLI_UNUSED(params);
+ self->hash_shift_ = 32 - common->params.bucket_bits;
+ self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
+ self->block_size_ = (size_t)1 << common->params.block_bits;
+ self->block_mask_ = (uint32_t)(self->block_size_ - 1);
+ self->num_ = (uint16_t*)common->extra;
+ self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
+ self->block_bits_ = common->params.block_bits;
+ self->num_last_distances_to_check_ =
+ common->params.num_last_distances_to_check;
+}
+
+static void FN(Prepare)(
+ HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ uint16_t* BROTLI_RESTRICT num = self->num_;
+ /* Partial preparation is 100 times slower (per socket). */
+ size_t partial_prepare_threshold = self->bucket_size_ >> 6;
+ if (one_shot && input_size <= partial_prepare_threshold) {
+ size_t i;
+ for (i = 0; i < input_size; ++i) {
+ const uint32_t key = FN(HashBytes)(&data[i], self->hash_shift_);
+ num[key] = 0;
+ }
+ } else {
+ memset(num, 0, self->bucket_size_ * sizeof(num[0]));
+ }
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
+ size_t block_size = (size_t)1 << params->hasher.block_bits;
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+ return sizeof(uint16_t) * bucket_size +
+ sizeof(uint32_t) * bucket_size * block_size;
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+static BROTLI_INLINE void FN(Store)(
+ HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
+ const size_t mask, const size_t ix) {
+ const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
+ const size_t minor_ix = self->num_[key] & self->block_mask_;
+ const size_t offset = minor_ix + (key << self->block_bits_);
+ self->buckets_[offset] = (uint32_t)ix;
+ ++self->num_[key];
+}
+
+static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ size_t i;
+ for (i = ix_start; i < ix_end; ++i) {
+ FN(Store)(self, data, mask, i);
+ }
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ringbuffer_mask) {
+ if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
+ }
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ int* BROTLI_RESTRICT distance_cache) {
+ PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke FN(PrepareDistanceCache) once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashLongestMatch* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
+ const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
+ const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ uint16_t* BROTLI_RESTRICT num = self->num_;
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ /* Don't accept a short copy from far away. */
+ score_t min_score = out->score;
+ score_t best_score = out->score;
+ size_t best_len = out->len;
+ size_t i;
+ out->len = 0;
+ out->len_code_delta = 0;
+ /* Try last distance first. */
+ for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
+ const size_t backward = (size_t)distance_cache[i];
+ size_t prev_ix = (size_t)(cur_ix - backward);
+ if (prev_ix >= cur_ix) {
+ continue;
+ }
+ if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
+ continue;
+ }
+ prev_ix &= ring_buffer_mask;
+
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
+ prev_ix + best_len > ring_buffer_mask ||
+ data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
+ continue;
+ }
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 3 || (len == 2 && i < 2)) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ score_t score = BackwardReferenceScoreUsingLastDistance(len);
+ if (best_score < score) {
+ if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ }
+ {
+ const uint32_t key =
+ FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
+ uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
+ const size_t down =
+ (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
+ for (i = num[key]; i > down;) {
+ size_t prev_ix = bucket[--i & self->block_mask_];
+ const size_t backward = cur_ix - prev_ix;
+ if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
+ break;
+ }
+ prev_ix &= ring_buffer_mask;
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
+ prev_ix + best_len > ring_buffer_mask ||
+ data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
+ continue;
+ }
+ {
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4) {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ score_t score = BackwardReferenceScore(len, backward);
+ if (best_score < score) {
+ best_score = score;
+ best_len = len;
+ out->len = best_len;
+ out->distance = backward;
+ out->score = best_score;
+ }
+ }
+ }
+ }
+ bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
+ ++num[key];
+ }
+ if (min_score == out->score) {
+ SearchInStaticDictionary(dictionary,
+ self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
+ max_distance, out, BROTLI_FALSE);
+ }
+}
+
+#undef HashLongestMatch
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_quickly_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_quickly_inc.h
new file mode 100644
index 000000000..e5ba840ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_longest_match_quickly_inc.h
@@ -0,0 +1,266 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
+ USE_DICTIONARY
+ */
+
+#define HashLongestMatchQuickly HASHER()
+
+#define BUCKET_SIZE (1 << BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE - 1)
+#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
+#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
+
+/* HashBytes is the function that chooses the bucket to place
+ the address in. The HashLongestMatch and HashLongestMatchQuickly
+ classes have separate, different implementations of hashing. */
+static uint32_t FN(HashBytes)(const uint8_t* data) {
+ const uint64_t h = ((BROTLI_UNALIGNED_LOAD64LE(data) << (64 - 8 * HASH_LEN)) *
+ kHashMul64);
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return (uint32_t)(h >> (64 - BUCKET_BITS));
+}
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (BUCKET_SIZE). */
+typedef struct HashLongestMatchQuickly {
+ /* Shortcuts. */
+ HasherCommon* common;
+
+ /* --- Dynamic size members --- */
+
+ uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
+} HashLongestMatchQuickly;
+
+static void FN(Initialize)(
+ HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ self->common = common;
+
+ BROTLI_UNUSED(params);
+ self->buckets_ = (uint32_t*)common->extra;
+}
+
+static void FN(Prepare)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ /* Partial preparation is 100 times slower (per socket). */
+ size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
+ if (one_shot && input_size <= partial_prepare_threshold) {
+ size_t i;
+ for (i = 0; i < input_size; ++i) {
+ const uint32_t key = FN(HashBytes)(&data[i]);
+ if (BUCKET_SWEEP == 1) {
+ buckets[key] = 0;
+ } else {
+ uint32_t j;
+ for (j = 0; j < BUCKET_SWEEP; ++j) {
+ buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
+ }
+ }
+ }
+ } else {
+ /* It is not strictly necessary to fill this buffer here, but
+ not filling will make the results of the compression stochastic
+ (but correct). This is because random data would cause the
+ system to find accidentally good backward references here and there. */
+ memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
+ }
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ BROTLI_UNUSED(params);
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+ return sizeof(uint32_t) * BUCKET_SIZE;
+}
+
+/* Look at 5 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value somewhere within
+ [ix .. ix+3]. */
+static BROTLI_INLINE void FN(Store)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
+ const uint32_t key = FN(HashBytes)(&data[ix & mask]);
+ if (BUCKET_SWEEP == 1) {
+ self->buckets_[key] = (uint32_t)ix;
+ } else {
+ /* Wiggle the value with the bucket sweep range. */
+ const uint32_t off = ix & BUCKET_SWEEP_MASK;
+ self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
+ }
+}
+
+static BROTLI_INLINE void FN(StoreRange)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ size_t i;
+ for (i = ix_start; i < ix_end; ++i) {
+ FN(Store)(self, data, mask, i);
+ }
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position,
+ const uint8_t* ringbuffer, size_t ringbuffer_mask) {
+ if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+ FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
+ }
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ int* BROTLI_RESTRICT distance_cache) {
+ BROTLI_UNUSED(self);
+ BROTLI_UNUSED(distance_cache);
+}
+
+/* Find a longest backward match of &data[cur_ix & ring_buffer_mask]
+ up to the length of max_length and stores the position cur_ix in the
+ hash table.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashLongestMatchQuickly* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data,
+ const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
+ const size_t cur_ix, const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ const size_t best_len_in = out->len;
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ int compare_char = data[cur_ix_masked + best_len_in];
+ size_t key = FN(HashBytes)(&data[cur_ix_masked]);
+ size_t key_out;
+ score_t min_score = out->score;
+ score_t best_score = out->score;
+ size_t best_len = best_len_in;
+ size_t cached_backward = (size_t)distance_cache[0];
+ size_t prev_ix = cur_ix - cached_backward;
+ out->len_code_delta = 0;
+ if (prev_ix < cur_ix) {
+ prev_ix &= (uint32_t)ring_buffer_mask;
+ if (compare_char == data[prev_ix + best_len]) {
+ const size_t len = FindMatchLengthWithLimit(
+ &data[prev_ix], &data[cur_ix_masked], max_length);
+ if (len >= 4) {
+ const score_t score = BackwardReferenceScoreUsingLastDistance(len);
+ if (best_score < score) {
+ out->len = len;
+ out->distance = cached_backward;
+ out->score = score;
+ if (BUCKET_SWEEP == 1) {
+ buckets[key] = (uint32_t)cur_ix;
+ return;
+ } else {
+ best_len = len;
+ best_score = score;
+ compare_char = data[cur_ix_masked + len];
+ }
+ }
+ }
+ }
+ }
+ if (BUCKET_SWEEP == 1) {
+ size_t backward;
+ size_t len;
+ /* Only one to look for, don't bother to prepare for a loop. */
+ prev_ix = buckets[key];
+ buckets[key] = (uint32_t)cur_ix;
+ backward = cur_ix - prev_ix;
+ prev_ix &= (uint32_t)ring_buffer_mask;
+ if (compare_char != data[prev_ix + best_len_in]) {
+ return;
+ }
+ if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) {
+ return;
+ }
+ len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4) {
+ const score_t score = BackwardReferenceScore(len, backward);
+ if (best_score < score) {
+ out->len = len;
+ out->distance = backward;
+ out->score = score;
+ return;
+ }
+ }
+ } else {
+ size_t keys[BUCKET_SWEEP];
+ size_t i;
+ for (i = 0; i < BUCKET_SWEEP; ++i) {
+ keys[i] = (key + (i << 3)) & BUCKET_MASK;
+ }
+ key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
+ for (i = 0; i < BUCKET_SWEEP; ++i) {
+ size_t len;
+ size_t backward;
+ prev_ix = buckets[keys[i]];
+ backward = cur_ix - prev_ix;
+ prev_ix &= (uint32_t)ring_buffer_mask;
+ if (compare_char != data[prev_ix + best_len]) {
+ continue;
+ }
+ if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) {
+ continue;
+ }
+ len = FindMatchLengthWithLimit(&data[prev_ix],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4) {
+ const score_t score = BackwardReferenceScore(len, backward);
+ if (best_score < score) {
+ best_len = len;
+ out->len = len;
+ compare_char = data[cur_ix_masked + len];
+ best_score = score;
+ out->score = score;
+ out->distance = backward;
+ }
+ }
+ }
+ }
+ if (USE_DICTIONARY && min_score == out->score) {
+ SearchInStaticDictionary(dictionary,
+ self->common, &data[cur_ix_masked], max_length, dictionary_distance,
+ max_distance, out, BROTLI_TRUE);
+ }
+ if (BUCKET_SWEEP != 1) {
+ buckets[key_out] = (uint32_t)cur_ix;
+ }
+}
+
+#undef BUCKET_SWEEP_MASK
+#undef BUCKET_SWEEP
+#undef BUCKET_MASK
+#undef BUCKET_SIZE
+
+#undef HashLongestMatchQuickly
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_rolling_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_rolling_inc.h
new file mode 100755
index 000000000..586ae7385
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_rolling_inc.h
@@ -0,0 +1,212 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, JUMP, NUMBUCKETS, MASK, CHUNKLEN */
+/* NUMBUCKETS / (MASK + 1) = probability of storing and using hash code. */
+/* JUMP = skip bytes for speedup */
+
+/* Rolling hash for long distance long string matches. Stores one position
+ per bucket, bucket key is computed over a long region. */
+
+#define HashRolling HASHER()
+
+static const uint32_t FN(kRollingHashMul32) = 69069;
+static const uint32_t FN(kInvalidPos) = 0xffffffff;
+
+/* This hasher uses a longer forward length, but returning a higher value here
+ will hurt compression by the main hasher when combined with a composite
+ hasher. The hasher tests for forward itself instead. */
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
+
+/* Computes a code from a single byte. A lookup table of 256 values could be
+ used, but simply adding 1 works about as good. */
+static uint32_t FN(HashByte)(uint8_t byte) {
+ return (uint32_t)byte + 1u;
+}
+
+static uint32_t FN(HashRollingFunctionInitial)(uint32_t state, uint8_t add,
+ uint32_t factor) {
+ return (uint32_t)(factor * state + FN(HashByte)(add));
+}
+
+static uint32_t FN(HashRollingFunction)(uint32_t state, uint8_t add,
+ uint8_t rem, uint32_t factor,
+ uint32_t factor_remove) {
+ return (uint32_t)(factor * state +
+ FN(HashByte)(add) - factor_remove * FN(HashByte)(rem));
+}
+
+typedef struct HashRolling {
+ uint32_t state;
+ uint32_t* table;
+ size_t next_ix;
+
+ uint32_t chunk_len;
+ uint32_t factor;
+ uint32_t factor_remove;
+} HashRolling;
+
+static void FN(Initialize)(
+ HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ size_t i;
+ self->state = 0;
+ self->next_ix = 0;
+
+ self->factor = FN(kRollingHashMul32);
+
+ /* Compute the factor of the oldest byte to remove: factor**steps modulo
+ 0xffffffff (the multiplications rely on 32-bit overflow) */
+ self->factor_remove = 1;
+ for (i = 0; i < CHUNKLEN; i += JUMP) {
+ self->factor_remove *= self->factor;
+ }
+
+ self->table = (uint32_t*)common->extra;
+ for (i = 0; i < NUMBUCKETS; i++) {
+ self->table[i] = FN(kInvalidPos);
+ }
+
+ BROTLI_UNUSED(params);
+}
+
+static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ size_t i;
+ /* Too small size, cannot use this hasher. */
+ if (input_size < CHUNKLEN) return;
+ self->state = 0;
+ for (i = 0; i < CHUNKLEN; i += JUMP) {
+ self->state = FN(HashRollingFunctionInitial)(
+ self->state, data[i], self->factor);
+ }
+ BROTLI_UNUSED(one_shot);
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ return NUMBUCKETS * sizeof(uint32_t);
+ BROTLI_UNUSED(params);
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+}
+
+static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
+ BROTLI_UNUSED(self);
+ BROTLI_UNUSED(data);
+ BROTLI_UNUSED(mask);
+ BROTLI_UNUSED(ix);
+}
+
+static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ BROTLI_UNUSED(self);
+ BROTLI_UNUSED(data);
+ BROTLI_UNUSED(mask);
+ BROTLI_UNUSED(ix_start);
+ BROTLI_UNUSED(ix_end);
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashRolling* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ring_buffer_mask) {
+ /* In this case we must re-initialize the hasher from scratch from the
+ current position. */
+ size_t position_masked;
+ size_t available = num_bytes;
+ if ((position & (JUMP - 1)) != 0) {
+ size_t diff = JUMP - (position & (JUMP - 1));
+ available = (diff > available) ? 0 : (available - diff);
+ position += diff;
+ }
+ position_masked = position & ring_buffer_mask;
+ /* wrapping around ringbuffer not handled. */
+ if (available > ring_buffer_mask - position_masked) {
+ available = ring_buffer_mask - position_masked;
+ }
+
+ FN(Prepare)(self, BROTLI_FALSE, available,
+ ringbuffer + (position & ring_buffer_mask));
+ self->next_ix = position;
+ BROTLI_UNUSED(num_bytes);
+}
+
+static BROTLI_INLINE void FN(PrepareDistanceCache)(
+ HashRolling* BROTLI_RESTRICT self,
+ int* BROTLI_RESTRICT distance_cache) {
+ BROTLI_UNUSED(self);
+ BROTLI_UNUSED(distance_cache);
+}
+
+static BROTLI_INLINE void FN(FindLongestMatch)(
+ HashRolling* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
+ const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
+ const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ size_t pos;
+
+ if ((cur_ix & (JUMP - 1)) != 0) return;
+
+ /* Not enough lookahead */
+ if (max_length < CHUNKLEN) return;
+
+ for (pos = self->next_ix; pos <= cur_ix; pos += JUMP) {
+ uint32_t code = self->state & MASK;
+
+ uint8_t rem = data[pos & ring_buffer_mask];
+ uint8_t add = data[(pos + CHUNKLEN) & ring_buffer_mask];
+ size_t found_ix = FN(kInvalidPos);
+
+ self->state = FN(HashRollingFunction)(
+ self->state, add, rem, self->factor, self->factor_remove);
+
+ if (code < NUMBUCKETS) {
+ found_ix = self->table[code];
+ self->table[code] = (uint32_t)pos;
+ if (pos == cur_ix && found_ix != FN(kInvalidPos)) {
+ /* The cast to 32-bit makes backward distances up to 4GB work even
+ if cur_ix is above 4GB, despite using 32-bit values in the table. */
+ size_t backward = (uint32_t)(cur_ix - found_ix);
+ if (backward <= max_backward) {
+ const size_t found_ix_masked = found_ix & ring_buffer_mask;
+ const size_t len = FindMatchLengthWithLimit(&data[found_ix_masked],
+ &data[cur_ix_masked],
+ max_length);
+ if (len >= 4 && len > out->len) {
+ score_t score = BackwardReferenceScore(len, backward);
+ if (score > out->score) {
+ out->len = len;
+ out->distance = backward;
+ out->score = score;
+ out->len_code_delta = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ self->next_ix = cur_ix + JUMP;
+
+ /* NOTE: this hasher does not search in the dictionary. It is used as
+ backup-hasher, the main hasher already searches in it. */
+ BROTLI_UNUSED(dictionary);
+ BROTLI_UNUSED(distance_cache);
+ BROTLI_UNUSED(dictionary_distance);
+ BROTLI_UNUSED(max_distance);
+}
+
+#undef HashRolling
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_to_binary_tree_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_to_binary_tree_inc.h
new file mode 100644
index 000000000..9880e0aef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/hash_to_binary_tree_inc.h
@@ -0,0 +1,329 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN, BUCKET_BITS, MAX_TREE_COMP_LENGTH,
+ MAX_TREE_SEARCH_DEPTH */
+
+/* A (forgetful) hash table where each hash bucket contains a binary tree of
+ sequences whose first 4 bytes share the same hash code.
+ Each sequence is MAX_TREE_COMP_LENGTH long and is identified by its starting
+ position in the input data. The binary tree is sorted by the lexicographic
+ order of the sequences, and it is also a max-heap with respect to the
+ starting positions. */
+
+#define HashToBinaryTree HASHER()
+
+#define BUCKET_SIZE (1 << BUCKET_BITS)
+
+static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
+static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
+ return MAX_TREE_COMP_LENGTH;
+}
+
+static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
+ uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - BUCKET_BITS);
+}
+
+typedef struct HashToBinaryTree {
+ /* The window size minus 1 */
+ size_t window_mask_;
+
+ /* Hash table that maps the 4-byte hashes of the sequence to the last
+ position where this hash was found, which is the root of the binary
+ tree of sequences that share this hash bucket. */
+ uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
+
+ /* A position used to mark a non-existent sequence, i.e. a tree is empty if
+ its root is at invalid_pos_ and a node is a leaf if both its children
+ are at invalid_pos_. */
+ uint32_t invalid_pos_;
+
+ /* --- Dynamic size members --- */
+
+ /* The union of the binary trees of each hash bucket. The root of the tree
+ corresponding to a hash is a sequence starting at buckets_[hash] and
+ the left and right children of a sequence starting at pos are
+ forest_[2 * pos] and forest_[2 * pos + 1]. */
+ uint32_t* forest_; /* uint32_t[2 * num_nodes] */
+} HashToBinaryTree;
+
+static void FN(Initialize)(
+ HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
+ const BrotliEncoderParams* params) {
+ self->buckets_ = (uint32_t*)common->extra;
+ self->forest_ = &self->buckets_[BUCKET_SIZE];
+
+ self->window_mask_ = (1u << params->lgwin) - 1u;
+ self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
+}
+
+static void FN(Prepare)
+ (HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+ size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+ uint32_t invalid_pos = self->invalid_pos_;
+ uint32_t i;
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ BROTLI_UNUSED(data);
+ BROTLI_UNUSED(one_shot);
+ BROTLI_UNUSED(input_size);
+ for (i = 0; i < BUCKET_SIZE; i++) {
+ buckets[i] = invalid_pos;
+ }
+}
+
+static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
+ const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
+ size_t input_size) {
+ size_t num_nodes = (size_t)1 << params->lgwin;
+ if (one_shot && input_size < num_nodes) {
+ num_nodes = input_size;
+ }
+ return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
+}
+
+static BROTLI_INLINE size_t FN(LeftChildIndex)(
+ HashToBinaryTree* BROTLI_RESTRICT self,
+ const size_t pos) {
+ return 2 * (pos & self->window_mask_);
+}
+
+static BROTLI_INLINE size_t FN(RightChildIndex)(
+ HashToBinaryTree* BROTLI_RESTRICT self,
+ const size_t pos) {
+ return 2 * (pos & self->window_mask_) + 1;
+}
+
+/* Stores the hash of the next 4 bytes and in a single tree-traversal, the
+ hash bucket's binary tree is searched for matches and is re-rooted at the
+ current position.
+
+ If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the
+ current position is searched for matches, but the state of the hash table
+ is not changed, since we can not know the final sorting order of the
+ current (incomplete) sequence.
+
+ This function must be called with increasing cur_ix positions. */
+static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
+ HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
+ const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
+ const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
+ BackwardMatch* BROTLI_RESTRICT matches) {
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ const size_t max_comp_len =
+ BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH);
+ const BROTLI_BOOL should_reroot_tree =
+ TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
+ const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
+ uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+ uint32_t* BROTLI_RESTRICT forest = self->forest_;
+ size_t prev_ix = buckets[key];
+ /* The forest index of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ size_t node_left = FN(LeftChildIndex)(self, cur_ix);
+ /* The forest index of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ size_t node_right = FN(RightChildIndex)(self, cur_ix);
+ /* The match length of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ size_t best_len_left = 0;
+ /* The match length of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ size_t best_len_right = 0;
+ size_t depth_remaining;
+ if (should_reroot_tree) {
+ buckets[key] = (uint32_t)cur_ix;
+ }
+ for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
+ const size_t backward = cur_ix - prev_ix;
+ const size_t prev_ix_masked = prev_ix & ring_buffer_mask;
+ if (backward == 0 || backward > max_backward || depth_remaining == 0) {
+ if (should_reroot_tree) {
+ forest[node_left] = self->invalid_pos_;
+ forest[node_right] = self->invalid_pos_;
+ }
+ break;
+ }
+ {
+ const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
+ size_t len;
+ BROTLI_DCHECK(cur_len <= MAX_TREE_COMP_LENGTH);
+ len = cur_len +
+ FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
+ &data[prev_ix_masked + cur_len],
+ max_length - cur_len);
+ BROTLI_DCHECK(
+ 0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));
+ if (matches && len > *best_len) {
+ *best_len = len;
+ InitBackwardMatch(matches++, backward, len);
+ }
+ if (len >= max_comp_len) {
+ if (should_reroot_tree) {
+ forest[node_left] = forest[FN(LeftChildIndex)(self, prev_ix)];
+ forest[node_right] = forest[FN(RightChildIndex)(self, prev_ix)];
+ }
+ break;
+ }
+ if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) {
+ best_len_left = len;
+ if (should_reroot_tree) {
+ forest[node_left] = (uint32_t)prev_ix;
+ }
+ node_left = FN(RightChildIndex)(self, prev_ix);
+ prev_ix = forest[node_left];
+ } else {
+ best_len_right = len;
+ if (should_reroot_tree) {
+ forest[node_right] = (uint32_t)prev_ix;
+ }
+ node_right = FN(LeftChildIndex)(self, prev_ix);
+ prev_ix = forest[node_right];
+ }
+ }
+ }
+ return matches;
+}
+
+/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the
+ length of max_length and stores the position cur_ix in the hash table.
+
+ Sets *num_matches to the number of matches found, and stores the found
+ matches in matches[0] to matches[*num_matches - 1]. The matches will be
+ sorted by strictly increasing length and (non-strictly) increasing
+ distance. */
+static BROTLI_INLINE size_t FN(FindAllMatches)(
+ HashToBinaryTree* BROTLI_RESTRICT self,
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* BROTLI_RESTRICT data,
+ const size_t ring_buffer_mask, const size_t cur_ix,
+ const size_t max_length, const size_t max_backward,
+ const size_t dictionary_distance, const BrotliEncoderParams* params,
+ BackwardMatch* matches) {
+ BackwardMatch* const orig_matches = matches;
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
+ size_t best_len = 1;
+ const size_t short_match_max_backward =
+ params->quality != HQ_ZOPFLIFICATION_QUALITY ? 16 : 64;
+ size_t stop = cur_ix - short_match_max_backward;
+ uint32_t dict_matches[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];
+ size_t i;
+ if (cur_ix < short_match_max_backward) { stop = 0; }
+ for (i = cur_ix - 1; i > stop && best_len <= 2; --i) {
+ size_t prev_ix = i;
+ const size_t backward = cur_ix - prev_ix;
+ if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
+ break;
+ }
+ prev_ix &= ring_buffer_mask;
+ if (data[cur_ix_masked] != data[prev_ix] ||
+ data[cur_ix_masked + 1] != data[prev_ix + 1]) {
+ continue;
+ }
+ {
+ const size_t len =
+ FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked],
+ max_length);
+ if (len > best_len) {
+ best_len = len;
+ InitBackwardMatch(matches++, backward, len);
+ }
+ }
+ }
+ if (best_len < max_length) {
+ matches = FN(StoreAndFindMatches)(self, data, cur_ix,
+ ring_buffer_mask, max_length, max_backward, &best_len, matches);
+ }
+ for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
+ dict_matches[i] = kInvalidMatch;
+ }
+ {
+ size_t minlen = BROTLI_MAX(size_t, 4, best_len + 1);
+ if (BrotliFindAllStaticDictionaryMatches(dictionary,
+ &data[cur_ix_masked], minlen, max_length, &dict_matches[0])) {
+ size_t maxlen = BROTLI_MIN(
+ size_t, BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN, max_length);
+ size_t l;
+ for (l = minlen; l <= maxlen; ++l) {
+ uint32_t dict_id = dict_matches[l];
+ if (dict_id < kInvalidMatch) {
+ size_t distance = dictionary_distance + (dict_id >> 5) + 1;
+ if (distance <= params->dist.max_distance) {
+ InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
+ }
+ }
+ }
+ }
+ }
+ return (size_t)(matches - orig_matches);
+}
+
+/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
+ current sequence, without returning any matches.
+ REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
+static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data,
+ const size_t mask, const size_t ix) {
+ /* Maximum distance is window size - 16, see section 9.1. of the spec. */
+ const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
+ FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
+ max_backward, NULL, NULL);
+}
+
+static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
+ const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+ const size_t ix_start, const size_t ix_end) {
+ size_t i = ix_start;
+ size_t j = ix_start;
+ if (ix_start + 63 <= ix_end) {
+ i = ix_end - 63;
+ }
+ if (ix_start + 512 <= i) {
+ for (; j < i; j += 8) {
+ FN(Store)(self, data, mask, j);
+ }
+ }
+ for (; i < ix_end; ++i) {
+ FN(Store)(self, data, mask, i);
+ }
+}
+
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+ HashToBinaryTree* BROTLI_RESTRICT self,
+ size_t num_bytes, size_t position, const uint8_t* ringbuffer,
+ size_t ringbuffer_mask) {
+ if (num_bytes >= FN(HashTypeLength)() - 1 &&
+ position >= MAX_TREE_COMP_LENGTH) {
+ /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1;
+ const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes);
+ size_t i;
+ for (i = i_start; i < i_end; ++i) {
+ /* Maximum distance is window size - 16, see section 9.1. of the spec.
+ Furthermore, we have to make sure that we don't look further back
+ from the start of the next block than the window size, otherwise we
+ could access already overwritten areas of the ring-buffer. */
+ const size_t max_backward =
+ self->window_mask_ - BROTLI_MAX(size_t,
+ BROTLI_WINDOW_GAP - 1,
+ position - i);
+ /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the
+ end of the current block and that we have at least
+ MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
+ FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask,
+ MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL);
+ }
+ }
+}
+
+#undef BUCKET_SIZE
+
+#undef HashToBinaryTree
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.c
new file mode 100644
index 000000000..6da2ff6bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.c
@@ -0,0 +1,100 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Build per-context histograms of literals, commands and distance codes. */
+
+#include "./histogram.h"
+
+#include "../common/context.h"
+#include "./block_splitter.h"
+#include "./command.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct BlockSplitIterator {
+ const BlockSplit* split_; /* Not owned. */
+ size_t idx_;
+ size_t type_;
+ size_t length_;
+} BlockSplitIterator;
+
+static void InitBlockSplitIterator(BlockSplitIterator* self,
+ const BlockSplit* split) {
+ self->split_ = split;
+ self->idx_ = 0;
+ self->type_ = 0;
+ self->length_ = split->lengths ? split->lengths[0] : 0;
+}
+
+static void BlockSplitIteratorNext(BlockSplitIterator* self) {
+ if (self->length_ == 0) {
+ ++self->idx_;
+ self->type_ = self->split_->types[self->idx_];
+ self->length_ = self->split_->lengths[self->idx_];
+ }
+ --self->length_;
+}
+
+void BrotliBuildHistogramsWithContext(
+ const Command* cmds, const size_t num_commands,
+ const BlockSplit* literal_split, const BlockSplit* insert_and_copy_split,
+ const BlockSplit* dist_split, const uint8_t* ringbuffer, size_t start_pos,
+ size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
+ const ContextType* context_modes, HistogramLiteral* literal_histograms,
+ HistogramCommand* insert_and_copy_histograms,
+ HistogramDistance* copy_dist_histograms) {
+ size_t pos = start_pos;
+ BlockSplitIterator literal_it;
+ BlockSplitIterator insert_and_copy_it;
+ BlockSplitIterator dist_it;
+ size_t i;
+
+ InitBlockSplitIterator(&literal_it, literal_split);
+ InitBlockSplitIterator(&insert_and_copy_it, insert_and_copy_split);
+ InitBlockSplitIterator(&dist_it, dist_split);
+ for (i = 0; i < num_commands; ++i) {
+ const Command* cmd = &cmds[i];
+ size_t j;
+ BlockSplitIteratorNext(&insert_and_copy_it);
+ HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_],
+ cmd->cmd_prefix_);
+ /* TODO: unwrap iterator blocks. */
+ for (j = cmd->insert_len_; j != 0; --j) {
+ size_t context;
+ BlockSplitIteratorNext(&literal_it);
+ context = literal_it.type_;
+ if (context_modes) {
+ ContextLut lut = BROTLI_CONTEXT_LUT(context_modes[context]);
+ context = (context << BROTLI_LITERAL_CONTEXT_BITS) +
+ BROTLI_CONTEXT(prev_byte, prev_byte2, lut);
+ }
+ HistogramAddLiteral(&literal_histograms[context],
+ ringbuffer[pos & mask]);
+ prev_byte2 = prev_byte;
+ prev_byte = ringbuffer[pos & mask];
+ ++pos;
+ }
+ pos += CommandCopyLen(cmd);
+ if (CommandCopyLen(cmd)) {
+ prev_byte2 = ringbuffer[(pos - 2) & mask];
+ prev_byte = ringbuffer[(pos - 1) & mask];
+ if (cmd->cmd_prefix_ >= 128) {
+ size_t context;
+ BlockSplitIteratorNext(&dist_it);
+ context = (dist_it.type_ << BROTLI_DISTANCE_CONTEXT_BITS) +
+ CommandDistanceContext(cmd);
+ HistogramAddDistance(&copy_dist_histograms[context],
+ cmd->dist_prefix_ & 0x3FF);
+ }
+ }
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.h
new file mode 100644
index 000000000..42af3c3f9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram.h
@@ -0,0 +1,63 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Models the histograms of literals, commands and distance codes. */
+
+#ifndef BROTLI_ENC_HISTOGRAM_H_
+#define BROTLI_ENC_HISTOGRAM_H_
+
+#include <string.h> /* memset */
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./block_splitter.h"
+#include "./command.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
+#define BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS 544
+
+#define FN(X) X ## Literal
+#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
+#define DataType uint8_t
+#include "./histogram_inc.h" /* NOLINT(build/include) */
+#undef DataType
+#undef DATA_SIZE
+#undef FN
+
+#define FN(X) X ## Command
+#define DataType uint16_t
+#define DATA_SIZE BROTLI_NUM_COMMAND_SYMBOLS
+#include "./histogram_inc.h" /* NOLINT(build/include) */
+#undef DATA_SIZE
+#undef FN
+
+#define FN(X) X ## Distance
+#define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
+#include "./histogram_inc.h" /* NOLINT(build/include) */
+#undef DataType
+#undef DATA_SIZE
+#undef FN
+
+BROTLI_INTERNAL void BrotliBuildHistogramsWithContext(
+ const Command* cmds, const size_t num_commands,
+ const BlockSplit* literal_split, const BlockSplit* insert_and_copy_split,
+ const BlockSplit* dist_split, const uint8_t* ringbuffer, size_t pos,
+ size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
+ const ContextType* context_modes, HistogramLiteral* literal_histograms,
+ HistogramCommand* insert_and_copy_histograms,
+ HistogramDistance* copy_dist_histograms);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_HISTOGRAM_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram_inc.h
new file mode 100644
index 000000000..50eaf7468
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/histogram_inc.h
@@ -0,0 +1,51 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: Histogram, DATA_SIZE, DataType */
+
+/* A simple container for histograms of data in blocks. */
+
+typedef struct FN(Histogram) {
+ uint32_t data_[DATA_SIZE];
+ size_t total_count_;
+ double bit_cost_;
+} FN(Histogram);
+
+static BROTLI_INLINE void FN(HistogramClear)(FN(Histogram)* self) {
+ memset(self->data_, 0, sizeof(self->data_));
+ self->total_count_ = 0;
+ self->bit_cost_ = HUGE_VAL;
+}
+
+static BROTLI_INLINE void FN(ClearHistograms)(
+ FN(Histogram)* array, size_t length) {
+ size_t i;
+ for (i = 0; i < length; ++i) FN(HistogramClear)(array + i);
+}
+
+static BROTLI_INLINE void FN(HistogramAdd)(FN(Histogram)* self, size_t val) {
+ ++self->data_[val];
+ ++self->total_count_;
+}
+
+static BROTLI_INLINE void FN(HistogramAddVector)(FN(Histogram)* self,
+ const DataType* p, size_t n) {
+ self->total_count_ += n;
+ n += 1;
+ while (--n) ++self->data_[*p++];
+}
+
+static BROTLI_INLINE void FN(HistogramAddHistogram)(FN(Histogram)* self,
+ const FN(Histogram)* v) {
+ size_t i;
+ self->total_count_ += v->total_count_;
+ for (i = 0; i < DATA_SIZE; ++i) {
+ self->data_[i] += v->data_[i];
+ }
+}
+
+static BROTLI_INLINE size_t FN(HistogramDataSize)(void) { return DATA_SIZE; }
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.c
new file mode 100644
index 000000000..c231100e3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.c
@@ -0,0 +1,175 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Literal cost model to allow backward reference replacement to be efficient.
+*/
+
+#include "./literal_cost.h"
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./fast_log.h"
+#include "./utf8_util.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static size_t UTF8Position(size_t last, size_t c, size_t clamp) {
+ if (c < 128) {
+ return 0; /* Next one is the 'Byte 1' again. */
+ } else if (c >= 192) { /* Next one is the 'Byte 2' of utf-8 encoding. */
+ return BROTLI_MIN(size_t, 1, clamp);
+ } else {
+ /* Let's decide over the last byte if this ends the sequence. */
+ if (last < 0xE0) {
+ return 0; /* Completed two or three byte coding. */
+ } else { /* Next one is the 'Byte 3' of utf-8 encoding. */
+ return BROTLI_MIN(size_t, 2, clamp);
+ }
+ }
+}
+
+static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
+ const uint8_t* data) {
+ size_t counts[3] = { 0 };
+ size_t max_utf8 = 1; /* should be 2, but 1 compresses better. */
+ size_t last_c = 0;
+ size_t i;
+ for (i = 0; i < len; ++i) {
+ size_t c = data[(pos + i) & mask];
+ ++counts[UTF8Position(last_c, c, 2)];
+ last_c = c;
+ }
+ if (counts[2] < 500) {
+ max_utf8 = 1;
+ }
+ if (counts[1] + counts[2] < 25) {
+ max_utf8 = 0;
+ }
+ return max_utf8;
+}
+
+static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
+ const uint8_t* data, float* cost) {
+ /* max_utf8 is 0 (normal ASCII single byte modeling),
+ 1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
+ const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
+ size_t histogram[3][256] = { { 0 } };
+ size_t window_half = 495;
+ size_t in_window = BROTLI_MIN(size_t, window_half, len);
+ size_t in_window_utf8[3] = { 0 };
+
+ size_t i;
+ { /* Bootstrap histograms. */
+ size_t last_c = 0;
+ size_t utf8_pos = 0;
+ for (i = 0; i < in_window; ++i) {
+ size_t c = data[(pos + i) & mask];
+ ++histogram[utf8_pos][c];
+ ++in_window_utf8[utf8_pos];
+ utf8_pos = UTF8Position(last_c, c, max_utf8);
+ last_c = c;
+ }
+ }
+
+ /* Compute bit costs with sliding window. */
+ for (i = 0; i < len; ++i) {
+ if (i >= window_half) {
+ /* Remove a byte in the past. */
+ size_t c =
+ i < window_half + 1 ? 0 : data[(pos + i - window_half - 1) & mask];
+ size_t last_c =
+ i < window_half + 2 ? 0 : data[(pos + i - window_half - 2) & mask];
+ size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
+ --histogram[utf8_pos2][data[(pos + i - window_half) & mask]];
+ --in_window_utf8[utf8_pos2];
+ }
+ if (i + window_half < len) {
+ /* Add a byte in the future. */
+ size_t c = data[(pos + i + window_half - 1) & mask];
+ size_t last_c = data[(pos + i + window_half - 2) & mask];
+ size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
+ ++histogram[utf8_pos2][data[(pos + i + window_half) & mask]];
+ ++in_window_utf8[utf8_pos2];
+ }
+ {
+ size_t c = i < 1 ? 0 : data[(pos + i - 1) & mask];
+ size_t last_c = i < 2 ? 0 : data[(pos + i - 2) & mask];
+ size_t utf8_pos = UTF8Position(last_c, c, max_utf8);
+ size_t masked_pos = (pos + i) & mask;
+ size_t histo = histogram[utf8_pos][data[masked_pos]];
+ double lit_cost;
+ if (histo == 0) {
+ histo = 1;
+ }
+ lit_cost = FastLog2(in_window_utf8[utf8_pos]) - FastLog2(histo);
+ lit_cost += 0.02905;
+ if (lit_cost < 1.0) {
+ lit_cost *= 0.5;
+ lit_cost += 0.5;
+ }
+ /* Make the first bytes more expensive -- seems to help, not sure why.
+ Perhaps because the entropy source is changing its properties
+ rapidly in the beginning of the file, perhaps because the beginning
+ of the data is a statistical "anomaly". */
+ if (i < 2000) {
+ lit_cost += 0.7 - ((double)(2000 - i) / 2000.0 * 0.35);
+ }
+ cost[i] = (float)lit_cost;
+ }
+ }
+}
+
+void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask,
+ const uint8_t* data, float* cost) {
+ if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) {
+ EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, cost);
+ return;
+ } else {
+ size_t histogram[256] = { 0 };
+ size_t window_half = 2000;
+ size_t in_window = BROTLI_MIN(size_t, window_half, len);
+
+ /* Bootstrap histogram. */
+ size_t i;
+ for (i = 0; i < in_window; ++i) {
+ ++histogram[data[(pos + i) & mask]];
+ }
+
+ /* Compute bit costs with sliding window. */
+ for (i = 0; i < len; ++i) {
+ size_t histo;
+ if (i >= window_half) {
+ /* Remove a byte in the past. */
+ --histogram[data[(pos + i - window_half) & mask]];
+ --in_window;
+ }
+ if (i + window_half < len) {
+ /* Add a byte in the future. */
+ ++histogram[data[(pos + i + window_half) & mask]];
+ ++in_window;
+ }
+ histo = histogram[data[(pos + i) & mask]];
+ if (histo == 0) {
+ histo = 1;
+ }
+ {
+ double lit_cost = FastLog2(in_window) - FastLog2(histo);
+ lit_cost += 0.029;
+ if (lit_cost < 1.0) {
+ lit_cost *= 0.5;
+ lit_cost += 0.5;
+ }
+ cost[i] = (float)lit_cost;
+ }
+ }
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.h
new file mode 100644
index 000000000..8f53f39d3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/literal_cost.h
@@ -0,0 +1,30 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Literal cost model to allow backward reference replacement to be efficient.
+*/
+
+#ifndef BROTLI_ENC_LITERAL_COST_H_
+#define BROTLI_ENC_LITERAL_COST_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Estimates how many bits the literals in the interval [pos, pos + len) in the
+ ring-buffer (data, mask) will take entropy coded and writes these estimates
+ to the cost[0..len) array. */
+BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
+ size_t pos, size_t len, size_t mask, const uint8_t* data, float* cost);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_LITERAL_COST_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.c
new file mode 100644
index 000000000..f6ed7e3cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.c
@@ -0,0 +1,170 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Algorithms for distributing the literals and commands of a metablock between
+ block types and contexts. */
+
+#include "./memory.h"
+
+#include <stdlib.h> /* exit, free, malloc */
+#include <string.h> /* memcpy */
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_PERM_ALLOCATED 128
+#define MAX_NEW_ALLOCATED 64
+#define MAX_NEW_FREED 64
+
+#define PERM_ALLOCATED_OFFSET 0
+#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
+#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED)
+
+void BrotliInitMemoryManager(
+ MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
+ void* opaque) {
+ if (!alloc_func) {
+ m->alloc_func = BrotliDefaultAllocFunc;
+ m->free_func = BrotliDefaultFreeFunc;
+ m->opaque = 0;
+ } else {
+ m->alloc_func = alloc_func;
+ m->free_func = free_func;
+ m->opaque = opaque;
+ }
+#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
+ m->is_oom = BROTLI_FALSE;
+ m->perm_allocated = 0;
+ m->new_allocated = 0;
+ m->new_freed = 0;
+#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
+}
+
+#if defined(BROTLI_ENCODER_EXIT_ON_OOM)
+
+void* BrotliAllocate(MemoryManager* m, size_t n) {
+ void* result = m->alloc_func(m->opaque, n);
+ if (!result) exit(EXIT_FAILURE);
+ return result;
+}
+
+void BrotliFree(MemoryManager* m, void* p) {
+ m->free_func(m->opaque, p);
+}
+
+void BrotliWipeOutMemoryManager(MemoryManager* m) {
+ BROTLI_UNUSED(m);
+}
+
+#else /* BROTLI_ENCODER_EXIT_ON_OOM */
+
+static void SortPointers(void** items, const size_t n) {
+ /* Shell sort. */
+ static const size_t gaps[] = {23, 10, 4, 1};
+ int g = 0;
+ for (; g < 4; ++g) {
+ size_t gap = gaps[g];
+ size_t i;
+ for (i = gap; i < n; ++i) {
+ size_t j = i;
+ void* tmp = items[i];
+ for (; j >= gap && tmp < items[j - gap]; j -= gap) {
+ items[j] = items[j - gap];
+ }
+ items[j] = tmp;
+ }
+ }
+}
+
+static size_t Annihilate(void** a, size_t a_len, void** b, size_t b_len) {
+ size_t a_read_index = 0;
+ size_t b_read_index = 0;
+ size_t a_write_index = 0;
+ size_t b_write_index = 0;
+ size_t annihilated = 0;
+ while (a_read_index < a_len && b_read_index < b_len) {
+ if (a[a_read_index] == b[b_read_index]) {
+ a_read_index++;
+ b_read_index++;
+ annihilated++;
+ } else if (a[a_read_index] < b[b_read_index]) {
+ a[a_write_index++] = a[a_read_index++];
+ } else {
+ b[b_write_index++] = b[b_read_index++];
+ }
+ }
+ while (a_read_index < a_len) a[a_write_index++] = a[a_read_index++];
+ while (b_read_index < b_len) b[b_write_index++] = b[b_read_index++];
+ return annihilated;
+}
+
+static void CollectGarbagePointers(MemoryManager* m) {
+ size_t annihilated;
+ SortPointers(m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated);
+ SortPointers(m->pointers + NEW_FREED_OFFSET, m->new_freed);
+ annihilated = Annihilate(
+ m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated,
+ m->pointers + NEW_FREED_OFFSET, m->new_freed);
+ m->new_allocated -= annihilated;
+ m->new_freed -= annihilated;
+
+ if (m->new_freed != 0) {
+ annihilated = Annihilate(
+ m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated,
+ m->pointers + NEW_FREED_OFFSET, m->new_freed);
+ m->perm_allocated -= annihilated;
+ m->new_freed -= annihilated;
+ BROTLI_DCHECK(m->new_freed == 0);
+ }
+
+ if (m->new_allocated != 0) {
+ BROTLI_DCHECK(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED);
+ memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated,
+ m->pointers + NEW_ALLOCATED_OFFSET,
+ sizeof(void*) * m->new_allocated);
+ m->perm_allocated += m->new_allocated;
+ m->new_allocated = 0;
+ SortPointers(m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated);
+ }
+}
+
+void* BrotliAllocate(MemoryManager* m, size_t n) {
+ void* result = m->alloc_func(m->opaque, n);
+ if (!result) {
+ m->is_oom = BROTLI_TRUE;
+ return NULL;
+ }
+ if (m->new_allocated == MAX_NEW_ALLOCATED) CollectGarbagePointers(m);
+ m->pointers[NEW_ALLOCATED_OFFSET + (m->new_allocated++)] = result;
+ return result;
+}
+
+void BrotliFree(MemoryManager* m, void* p) {
+ if (!p) return;
+ m->free_func(m->opaque, p);
+ if (m->new_freed == MAX_NEW_FREED) CollectGarbagePointers(m);
+ m->pointers[NEW_FREED_OFFSET + (m->new_freed++)] = p;
+}
+
+void BrotliWipeOutMemoryManager(MemoryManager* m) {
+ size_t i;
+ CollectGarbagePointers(m);
+ /* Now all unfreed pointers are in perm-allocated list. */
+ for (i = 0; i < m->perm_allocated; ++i) {
+ m->free_func(m->opaque, m->pointers[PERM_ALLOCATED_OFFSET + i]);
+ }
+ m->perm_allocated = 0;
+}
+
+#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.h
new file mode 100644
index 000000000..832e7b2b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/memory.h
@@ -0,0 +1,114 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Macros for memory management. */
+
+#ifndef BROTLI_ENC_MEMORY_H_
+#define BROTLI_ENC_MEMORY_H_
+
+#include <string.h> /* memcpy */
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if !defined(BROTLI_ENCODER_CLEANUP_ON_OOM) && \
+ !defined(BROTLI_ENCODER_EXIT_ON_OOM)
+#define BROTLI_ENCODER_EXIT_ON_OOM
+#endif
+
+typedef struct MemoryManager {
+ brotli_alloc_func alloc_func;
+ brotli_free_func free_func;
+ void* opaque;
+#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
+ BROTLI_BOOL is_oom;
+ size_t perm_allocated;
+ size_t new_allocated;
+ size_t new_freed;
+ void* pointers[256];
+#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
+} MemoryManager;
+
+BROTLI_INTERNAL void BrotliInitMemoryManager(
+ MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
+ void* opaque);
+
+BROTLI_INTERNAL void* BrotliAllocate(MemoryManager* m, size_t n);
+#define BROTLI_ALLOC(M, T, N) \
+ ((N) > 0 ? ((T*)BrotliAllocate((M), (N) * sizeof(T))) : NULL)
+
+BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
+#define BROTLI_FREE(M, P) { \
+ BrotliFree((M), (P)); \
+ P = NULL; \
+}
+
+#if defined(BROTLI_ENCODER_EXIT_ON_OOM)
+#define BROTLI_IS_OOM(M) (!!0)
+#else /* BROTLI_ENCODER_EXIT_ON_OOM */
+#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
+#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
+
+/*
+BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
+The only purpose of it is to explain static analyzers the state of things.
+NB: use ONLY together with BROTLI_IS_OOM
+ AND ONLY for allocations in the current scope.
+ */
+#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
+#define BROTLI_IS_NULL(A) ((A) == nullptr)
+#else /* defined(__clang_analyzer__) */
+#define BROTLI_IS_NULL(A) (!!0)
+#endif /* defined(__clang_analyzer__) */
+
+BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
+
+/*
+Dynamically grows array capacity to at least the requested size
+M: MemoryManager
+T: data type
+A: array
+C: capacity
+R: requested size
+*/
+#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
+ if (C < (R)) { \
+ size_t _new_size = (C == 0) ? (R) : C; \
+ T* new_array; \
+ while (_new_size < (R)) _new_size *= 2; \
+ new_array = BROTLI_ALLOC((M), T, _new_size); \
+ if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
+ memcpy(new_array, A, C * sizeof(T)); \
+ BROTLI_FREE((M), A); \
+ A = new_array; \
+ C = _new_size; \
+ } \
+}
+
+/*
+Appends value and dynamically grows array capacity when needed
+M: MemoryManager
+T: data type
+A: array
+C: array capacity
+S: array size
+V: value to append
+*/
+#define BROTLI_ENSURE_CAPACITY_APPEND(M, T, A, C, S, V) { \
+ (S)++; \
+ BROTLI_ENSURE_CAPACITY(M, T, A, C, S); \
+ A[(S) - 1] = (V); \
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_MEMORY_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.c
new file mode 100644
index 000000000..5aa4d4f17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.c
@@ -0,0 +1,663 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Algorithms for distributing the literals and commands of a metablock between
+ block types and contexts. */
+
+#include "./metablock.h"
+
+#include "../common/constants.h"
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./bit_cost.h"
+#include "./block_splitter.h"
+#include "./cluster.h"
+#include "./entropy_encode.h"
+#include "./histogram.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+void BrotliInitDistanceParams(BrotliEncoderParams* params,
+ uint32_t npostfix, uint32_t ndirect) {
+ BrotliDistanceParams* dist_params = &params->dist;
+ uint32_t alphabet_size_max;
+ uint32_t alphabet_size_limit;
+ uint32_t max_distance;
+
+ dist_params->distance_postfix_bits = npostfix;
+ dist_params->num_direct_distance_codes = ndirect;
+
+ alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+ npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
+ alphabet_size_limit = alphabet_size_max;
+ max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
+ (1U << (npostfix + 2));
+
+ if (params->large_window) {
+ BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
+ BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
+ alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+ npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
+ alphabet_size_limit = limit.max_alphabet_size;
+ max_distance = limit.max_distance;
+ }
+
+ dist_params->alphabet_size_max = alphabet_size_max;
+ dist_params->alphabet_size_limit = alphabet_size_limit;
+ dist_params->max_distance = max_distance;
+}
+
+static void RecomputeDistancePrefixes(Command* cmds,
+ size_t num_commands,
+ const BrotliDistanceParams* orig_params,
+ const BrotliDistanceParams* new_params) {
+ size_t i;
+
+ if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
+ orig_params->num_direct_distance_codes ==
+ new_params->num_direct_distance_codes) {
+ return;
+ }
+
+ for (i = 0; i < num_commands; ++i) {
+ Command* cmd = &cmds[i];
+ if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
+ PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
+ new_params->num_direct_distance_codes,
+ new_params->distance_postfix_bits,
+ &cmd->dist_prefix_,
+ &cmd->dist_extra_);
+ }
+ }
+}
+
+static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
+ size_t num_commands,
+ const BrotliDistanceParams* orig_params,
+ const BrotliDistanceParams* new_params,
+ double* cost) {
+ size_t i;
+ BROTLI_BOOL equal_params = BROTLI_FALSE;
+ uint16_t dist_prefix;
+ uint32_t dist_extra;
+ double extra_bits = 0.0;
+ HistogramDistance histo;
+ HistogramClearDistance(&histo);
+
+ if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
+ orig_params->num_direct_distance_codes ==
+ new_params->num_direct_distance_codes) {
+ equal_params = BROTLI_TRUE;
+ }
+
+ for (i = 0; i < num_commands; i++) {
+ const Command* cmd = &cmds[i];
+ if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
+ if (equal_params) {
+ dist_prefix = cmd->dist_prefix_;
+ } else {
+ uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
+ if (distance > new_params->max_distance) {
+ return BROTLI_FALSE;
+ }
+ PrefixEncodeCopyDistance(distance,
+ new_params->num_direct_distance_codes,
+ new_params->distance_postfix_bits,
+ &dist_prefix,
+ &dist_extra);
+ }
+ HistogramAddDistance(&histo, dist_prefix & 0x3FF);
+ extra_bits += dist_prefix >> 10;
+ }
+ }
+
+ *cost = BrotliPopulationCostDistance(&histo) + extra_bits;
+ return BROTLI_TRUE;
+}
+
+void BrotliBuildMetaBlock(MemoryManager* m,
+ const uint8_t* ringbuffer,
+ const size_t pos,
+ const size_t mask,
+ BrotliEncoderParams* params,
+ uint8_t prev_byte,
+ uint8_t prev_byte2,
+ Command* cmds,
+ size_t num_commands,
+ ContextType literal_context_mode,
+ MetaBlockSplit* mb) {
+ /* Histogram ids need to fit in one byte. */
+ static const size_t kMaxNumberOfHistograms = 256;
+ HistogramDistance* distance_histograms;
+ HistogramLiteral* literal_histograms;
+ ContextType* literal_context_modes = NULL;
+ size_t literal_histograms_size;
+ size_t distance_histograms_size;
+ size_t i;
+ size_t literal_context_multiplier = 1;
+ uint32_t npostfix;
+ uint32_t ndirect_msb = 0;
+ BROTLI_BOOL check_orig = BROTLI_TRUE;
+ double best_dist_cost = 1e99;
+ BrotliEncoderParams orig_params = *params;
+ BrotliEncoderParams new_params = *params;
+
+ for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
+ for (; ndirect_msb < 16; ndirect_msb++) {
+ uint32_t ndirect = ndirect_msb << npostfix;
+ BROTLI_BOOL skip;
+ double dist_cost;
+ BrotliInitDistanceParams(&new_params, npostfix, ndirect);
+ if (npostfix == orig_params.dist.distance_postfix_bits &&
+ ndirect == orig_params.dist.num_direct_distance_codes) {
+ check_orig = BROTLI_FALSE;
+ }
+ skip = !ComputeDistanceCost(
+ cmds, num_commands,
+ &orig_params.dist, &new_params.dist, &dist_cost);
+ if (skip || (dist_cost > best_dist_cost)) {
+ break;
+ }
+ best_dist_cost = dist_cost;
+ params->dist = new_params.dist;
+ }
+ if (ndirect_msb > 0) ndirect_msb--;
+ ndirect_msb /= 2;
+ }
+ if (check_orig) {
+ double dist_cost;
+ ComputeDistanceCost(cmds, num_commands,
+ &orig_params.dist, &orig_params.dist, &dist_cost);
+ if (dist_cost < best_dist_cost) {
+ /* NB: currently unused; uncomment when more param tuning is added. */
+ /* best_dist_cost = dist_cost; */
+ params->dist = orig_params.dist;
+ }
+ }
+ RecomputeDistancePrefixes(cmds, num_commands,
+ &orig_params.dist, &params->dist);
+
+ BrotliSplitBlock(m, cmds, num_commands,
+ ringbuffer, pos, mask, params,
+ &mb->literal_split,
+ &mb->command_split,
+ &mb->distance_split);
+ if (BROTLI_IS_OOM(m)) return;
+
+ if (!params->disable_literal_context_modeling) {
+ literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
+ literal_context_modes =
+ BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
+ for (i = 0; i < mb->literal_split.num_types; ++i) {
+ literal_context_modes[i] = literal_context_mode;
+ }
+ }
+
+ literal_histograms_size =
+ mb->literal_split.num_types * literal_context_multiplier;
+ literal_histograms =
+ BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
+ ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
+
+ distance_histograms_size =
+ mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
+ distance_histograms =
+ BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
+ ClearHistogramsDistance(distance_histograms, distance_histograms_size);
+
+ BROTLI_DCHECK(mb->command_histograms == 0);
+ mb->command_histograms_size = mb->command_split.num_types;
+ mb->command_histograms =
+ BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
+ ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
+
+ BrotliBuildHistogramsWithContext(cmds, num_commands,
+ &mb->literal_split, &mb->command_split, &mb->distance_split,
+ ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
+ literal_histograms, mb->command_histograms, distance_histograms);
+ BROTLI_FREE(m, literal_context_modes);
+
+ BROTLI_DCHECK(mb->literal_context_map == 0);
+ mb->literal_context_map_size =
+ mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
+ mb->literal_context_map =
+ BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
+
+ BROTLI_DCHECK(mb->literal_histograms == 0);
+ mb->literal_histograms_size = mb->literal_context_map_size;
+ mb->literal_histograms =
+ BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
+
+ BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
+ kMaxNumberOfHistograms, mb->literal_histograms,
+ &mb->literal_histograms_size, mb->literal_context_map);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, literal_histograms);
+
+ if (params->disable_literal_context_modeling) {
+ /* Distribute assignment to all contexts. */
+ for (i = mb->literal_split.num_types; i != 0;) {
+ size_t j = 0;
+ i--;
+ for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
+ mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
+ mb->literal_context_map[i];
+ }
+ }
+ }
+
+ BROTLI_DCHECK(mb->distance_context_map == 0);
+ mb->distance_context_map_size =
+ mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
+ mb->distance_context_map =
+ BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
+
+ BROTLI_DCHECK(mb->distance_histograms == 0);
+ mb->distance_histograms_size = mb->distance_context_map_size;
+ mb->distance_histograms =
+ BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
+
+ BrotliClusterHistogramsDistance(m, distance_histograms,
+ mb->distance_context_map_size,
+ kMaxNumberOfHistograms,
+ mb->distance_histograms,
+ &mb->distance_histograms_size,
+ mb->distance_context_map);
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_FREE(m, distance_histograms);
+}
+
+#define FN(X) X ## Literal
+#include "./metablock_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Command
+#include "./metablock_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define FN(X) X ## Distance
+#include "./metablock_inc.h" /* NOLINT(build/include) */
+#undef FN
+
+#define BROTLI_MAX_STATIC_CONTEXTS 13
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ Gathers histograms for all context buckets. */
+typedef struct ContextBlockSplitter {
+ /* Alphabet size of particular block category. */
+ size_t alphabet_size_;
+ size_t num_contexts_;
+ size_t max_block_types_;
+ /* We collect at least this many symbols for each block. */
+ size_t min_block_size_;
+ /* We merge histograms A and B if
+ entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
+ where A is the current histogram and B is the histogram of the last or the
+ second last block type. */
+ double split_threshold_;
+
+ size_t num_blocks_;
+ BlockSplit* split_; /* not owned */
+ HistogramLiteral* histograms_; /* not owned */
+ size_t* histograms_size_; /* not owned */
+
+ /* The number of symbols that we want to collect before deciding on whether
+ or not to merge the block with a previous one or emit a new block. */
+ size_t target_block_size_;
+ /* The number of symbols in the current histogram. */
+ size_t block_size_;
+ /* Offset of the current histogram. */
+ size_t curr_histogram_ix_;
+ /* Offset of the histograms of the previous two block types. */
+ size_t last_histogram_ix_[2];
+ /* Entropy of the previous two block types. */
+ double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
+ /* The number of times we merged the current block with the last one. */
+ size_t merge_last_count_;
+} ContextBlockSplitter;
+
+static void InitContextBlockSplitter(
+ MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
+ size_t num_contexts, size_t min_block_size, double split_threshold,
+ size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
+ size_t* histograms_size) {
+ size_t max_num_blocks = num_symbols / min_block_size + 1;
+ size_t max_num_types;
+ BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
+
+ self->alphabet_size_ = alphabet_size;
+ self->num_contexts_ = num_contexts;
+ self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
+ self->min_block_size_ = min_block_size;
+ self->split_threshold_ = split_threshold;
+ self->num_blocks_ = 0;
+ self->split_ = split;
+ self->histograms_size_ = histograms_size;
+ self->target_block_size_ = min_block_size;
+ self->block_size_ = 0;
+ self->curr_histogram_ix_ = 0;
+ self->merge_last_count_ = 0;
+
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ max_num_types =
+ BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
+ BROTLI_ENSURE_CAPACITY(m, uint8_t,
+ split->types, split->types_alloc_size, max_num_blocks);
+ BROTLI_ENSURE_CAPACITY(m, uint32_t,
+ split->lengths, split->lengths_alloc_size, max_num_blocks);
+ if (BROTLI_IS_OOM(m)) return;
+ split->num_blocks = max_num_blocks;
+ if (BROTLI_IS_OOM(m)) return;
+ BROTLI_DCHECK(*histograms == 0);
+ *histograms_size = max_num_types * num_contexts;
+ *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
+ self->histograms_ = *histograms;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
+ /* Clear only current histogram. */
+ ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
+ self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+static void ContextBlockSplitterFinishBlock(
+ ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
+ BlockSplit* split = self->split_;
+ const size_t num_contexts = self->num_contexts_;
+ double* last_entropy = self->last_entropy_;
+ HistogramLiteral* histograms = self->histograms_;
+
+ if (self->block_size_ < self->min_block_size_) {
+ self->block_size_ = self->min_block_size_;
+ }
+ if (self->num_blocks_ == 0) {
+ size_t i;
+ /* Create first block. */
+ split->lengths[0] = (uint32_t)self->block_size_;
+ split->types[0] = 0;
+
+ for (i = 0; i < num_contexts; ++i) {
+ last_entropy[i] =
+ BitsEntropy(histograms[i].data_, self->alphabet_size_);
+ last_entropy[num_contexts + i] = last_entropy[i];
+ }
+ ++self->num_blocks_;
+ ++split->num_types;
+ self->curr_histogram_ix_ += num_contexts;
+ if (self->curr_histogram_ix_ < *self->histograms_size_) {
+ ClearHistogramsLiteral(
+ &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
+ }
+ self->block_size_ = 0;
+ } else if (self->block_size_ > 0) {
+ /* Try merging the set of histograms for the current block type with the
+ respective set of histograms for the last and second last block types.
+ Decide over the split based on the total reduction of entropy across
+ all contexts. */
+ double entropy[BROTLI_MAX_STATIC_CONTEXTS];
+ HistogramLiteral* combined_histo =
+ BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
+ double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
+ double diff[2] = { 0.0 };
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
+ for (i = 0; i < num_contexts; ++i) {
+ size_t curr_histo_ix = self->curr_histogram_ix_ + i;
+ size_t j;
+ entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
+ self->alphabet_size_);
+ for (j = 0; j < 2; ++j) {
+ size_t jx = j * num_contexts + i;
+ size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
+ combined_histo[jx] = histograms[curr_histo_ix];
+ HistogramAddHistogramLiteral(&combined_histo[jx],
+ &histograms[last_histogram_ix]);
+ combined_entropy[jx] = BitsEntropy(
+ &combined_histo[jx].data_[0], self->alphabet_size_);
+ diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
+ }
+ }
+
+ if (split->num_types < self->max_block_types_ &&
+ diff[0] > self->split_threshold_ &&
+ diff[1] > self->split_threshold_) {
+ /* Create new block. */
+ split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
+ split->types[self->num_blocks_] = (uint8_t)split->num_types;
+ self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
+ self->last_histogram_ix_[0] = split->num_types * num_contexts;
+ for (i = 0; i < num_contexts; ++i) {
+ last_entropy[num_contexts + i] = last_entropy[i];
+ last_entropy[i] = entropy[i];
+ }
+ ++self->num_blocks_;
+ ++split->num_types;
+ self->curr_histogram_ix_ += num_contexts;
+ if (self->curr_histogram_ix_ < *self->histograms_size_) {
+ ClearHistogramsLiteral(
+ &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
+ }
+ self->block_size_ = 0;
+ self->merge_last_count_ = 0;
+ self->target_block_size_ = self->min_block_size_;
+ } else if (diff[1] < diff[0] - 20.0) {
+ /* Combine this block with second last block. */
+ split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
+ split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
+ BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
+ for (i = 0; i < num_contexts; ++i) {
+ histograms[self->last_histogram_ix_[0] + i] =
+ combined_histo[num_contexts + i];
+ last_entropy[num_contexts + i] = last_entropy[i];
+ last_entropy[i] = combined_entropy[num_contexts + i];
+ HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
+ }
+ ++self->num_blocks_;
+ self->block_size_ = 0;
+ self->merge_last_count_ = 0;
+ self->target_block_size_ = self->min_block_size_;
+ } else {
+ /* Combine this block with last block. */
+ split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
+ for (i = 0; i < num_contexts; ++i) {
+ histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
+ last_entropy[i] = combined_entropy[i];
+ if (split->num_types == 1) {
+ last_entropy[num_contexts + i] = last_entropy[i];
+ }
+ HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
+ }
+ self->block_size_ = 0;
+ if (++self->merge_last_count_ > 1) {
+ self->target_block_size_ += self->min_block_size_;
+ }
+ }
+ BROTLI_FREE(m, combined_histo);
+ }
+ if (is_final) {
+ *self->histograms_size_ = split->num_types * num_contexts;
+ split->num_blocks = self->num_blocks_;
+ }
+}
+
+/* Adds the next symbol to the current block type and context. When the
+ current block reaches the target size, decides on merging the block. */
+static void ContextBlockSplitterAddSymbol(
+ ContextBlockSplitter* self, MemoryManager* m,
+ size_t symbol, size_t context) {
+ HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
+ symbol);
+ ++self->block_size_;
+ if (self->block_size_ == self->target_block_size_) {
+ ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+}
+
+static void MapStaticContexts(MemoryManager* m,
+ size_t num_contexts,
+ const uint32_t* static_context_map,
+ MetaBlockSplit* mb) {
+ size_t i;
+ BROTLI_DCHECK(mb->literal_context_map == 0);
+ mb->literal_context_map_size =
+ mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
+ mb->literal_context_map =
+ BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
+
+ for (i = 0; i < mb->literal_split.num_types; ++i) {
+ uint32_t offset = (uint32_t)(i * num_contexts);
+ size_t j;
+ for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
+ mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
+ offset + static_context_map[j];
+ }
+ }
+}
+
+static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
+ MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
+ uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
+ const size_t num_contexts, const uint32_t* static_context_map,
+ const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
+ union {
+ BlockSplitterLiteral plain;
+ ContextBlockSplitter ctx;
+ } lit_blocks;
+ BlockSplitterCommand cmd_blocks;
+ BlockSplitterDistance dist_blocks;
+ size_t num_literals = 0;
+ size_t i;
+ for (i = 0; i < n_commands; ++i) {
+ num_literals += commands[i].insert_len_;
+ }
+
+ if (num_contexts == 1) {
+ InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
+ num_literals, &mb->literal_split, &mb->literal_histograms,
+ &mb->literal_histograms_size);
+ } else {
+ InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
+ num_literals, &mb->literal_split, &mb->literal_histograms,
+ &mb->literal_histograms_size);
+ }
+ if (BROTLI_IS_OOM(m)) return;
+ InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
+ 500.0, n_commands, &mb->command_split, &mb->command_histograms,
+ &mb->command_histograms_size);
+ if (BROTLI_IS_OOM(m)) return;
+ InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
+ &mb->distance_split, &mb->distance_histograms,
+ &mb->distance_histograms_size);
+ if (BROTLI_IS_OOM(m)) return;
+
+ for (i = 0; i < n_commands; ++i) {
+ const Command cmd = commands[i];
+ size_t j;
+ BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
+ for (j = cmd.insert_len_; j != 0; --j) {
+ uint8_t literal = ringbuffer[pos & mask];
+ if (num_contexts == 1) {
+ BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
+ } else {
+ size_t context =
+ BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
+ ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
+ static_context_map[context]);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+ prev_byte2 = prev_byte;
+ prev_byte = literal;
+ ++pos;
+ }
+ pos += CommandCopyLen(&cmd);
+ if (CommandCopyLen(&cmd)) {
+ prev_byte2 = ringbuffer[(pos - 2) & mask];
+ prev_byte = ringbuffer[(pos - 1) & mask];
+ if (cmd.cmd_prefix_ >= 128) {
+ BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF);
+ }
+ }
+ }
+
+ if (num_contexts == 1) {
+ BlockSplitterFinishBlockLiteral(
+ &lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
+ } else {
+ ContextBlockSplitterFinishBlock(
+ &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
+ if (BROTLI_IS_OOM(m)) return;
+ }
+ BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
+ BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
+
+ if (num_contexts > 1) {
+ MapStaticContexts(m, num_contexts, static_context_map, mb);
+ }
+}
+
+void BrotliBuildMetaBlockGreedy(MemoryManager* m,
+ const uint8_t* ringbuffer,
+ size_t pos,
+ size_t mask,
+ uint8_t prev_byte,
+ uint8_t prev_byte2,
+ ContextLut literal_context_lut,
+ size_t num_contexts,
+ const uint32_t* static_context_map,
+ const Command* commands,
+ size_t n_commands,
+ MetaBlockSplit* mb) {
+ if (num_contexts == 1) {
+ BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
+ prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb);
+ } else {
+ BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
+ prev_byte2, literal_context_lut, num_contexts, static_context_map,
+ commands, n_commands, mb);
+ }
+}
+
+void BrotliOptimizeHistograms(uint32_t num_distance_codes,
+ MetaBlockSplit* mb) {
+ uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
+ size_t i;
+ for (i = 0; i < mb->literal_histograms_size; ++i) {
+ BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
+ good_for_rle);
+ }
+ for (i = 0; i < mb->command_histograms_size; ++i) {
+ BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
+ mb->command_histograms[i].data_,
+ good_for_rle);
+ }
+ for (i = 0; i < mb->distance_histograms_size; ++i) {
+ BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
+ mb->distance_histograms[i].data_,
+ good_for_rle);
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.h
new file mode 100644
index 000000000..334a79a44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock.h
@@ -0,0 +1,105 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Algorithms for distributing the literals and commands of a metablock between
+ block types and contexts. */
+
+#ifndef BROTLI_ENC_METABLOCK_H_
+#define BROTLI_ENC_METABLOCK_H_
+
+#include "../common/context.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./block_splitter.h"
+#include "./command.h"
+#include "./histogram.h"
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct MetaBlockSplit {
+ BlockSplit literal_split;
+ BlockSplit command_split;
+ BlockSplit distance_split;
+ uint32_t* literal_context_map;
+ size_t literal_context_map_size;
+ uint32_t* distance_context_map;
+ size_t distance_context_map_size;
+ HistogramLiteral* literal_histograms;
+ size_t literal_histograms_size;
+ HistogramCommand* command_histograms;
+ size_t command_histograms_size;
+ HistogramDistance* distance_histograms;
+ size_t distance_histograms_size;
+} MetaBlockSplit;
+
+static BROTLI_INLINE void InitMetaBlockSplit(MetaBlockSplit* mb) {
+ BrotliInitBlockSplit(&mb->literal_split);
+ BrotliInitBlockSplit(&mb->command_split);
+ BrotliInitBlockSplit(&mb->distance_split);
+ mb->literal_context_map = 0;
+ mb->literal_context_map_size = 0;
+ mb->distance_context_map = 0;
+ mb->distance_context_map_size = 0;
+ mb->literal_histograms = 0;
+ mb->literal_histograms_size = 0;
+ mb->command_histograms = 0;
+ mb->command_histograms_size = 0;
+ mb->distance_histograms = 0;
+ mb->distance_histograms_size = 0;
+}
+
+static BROTLI_INLINE void DestroyMetaBlockSplit(
+ MemoryManager* m, MetaBlockSplit* mb) {
+ BrotliDestroyBlockSplit(m, &mb->literal_split);
+ BrotliDestroyBlockSplit(m, &mb->command_split);
+ BrotliDestroyBlockSplit(m, &mb->distance_split);
+ BROTLI_FREE(m, mb->literal_context_map);
+ BROTLI_FREE(m, mb->distance_context_map);
+ BROTLI_FREE(m, mb->literal_histograms);
+ BROTLI_FREE(m, mb->command_histograms);
+ BROTLI_FREE(m, mb->distance_histograms);
+}
+
+/* Uses the slow shortest-path block splitter and does context clustering.
+ The distance parameters are dynamically selected based on the commands
+ which get recomputed under the new distance parameters. The new distance
+ parameters are stored into *params. */
+BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m,
+ const uint8_t* ringbuffer,
+ const size_t pos,
+ const size_t mask,
+ BrotliEncoderParams* params,
+ uint8_t prev_byte,
+ uint8_t prev_byte2,
+ Command* cmds,
+ size_t num_commands,
+ ContextType literal_context_mode,
+ MetaBlockSplit* mb);
+
+/* Uses a fast greedy block splitter that tries to merge current block with the
+ last or the second last block and uses a static context clustering which
+ is the same for all block types. */
+BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy(
+ MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
+ uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
+ size_t num_contexts, const uint32_t* static_context_map,
+ const Command* commands, size_t n_commands, MetaBlockSplit* mb);
+
+BROTLI_INTERNAL void BrotliOptimizeHistograms(uint32_t num_distance_codes,
+ MetaBlockSplit* mb);
+
+BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliEncoderParams* params,
+ uint32_t npostfix, uint32_t ndirect);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_METABLOCK_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock_inc.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock_inc.h
new file mode 100644
index 000000000..ed507ef5e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/metablock_inc.h
@@ -0,0 +1,183 @@
+/* NOLINT(build/header_guard) */
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* template parameters: FN */
+
+#define HistogramType FN(Histogram)
+
+/* Greedy block splitter for one block category (literal, command or distance).
+*/
+typedef struct FN(BlockSplitter) {
+ /* Alphabet size of particular block category. */
+ size_t alphabet_size_;
+ /* We collect at least this many symbols for each block. */
+ size_t min_block_size_;
+ /* We merge histograms A and B if
+ entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
+ where A is the current histogram and B is the histogram of the last or the
+ second last block type. */
+ double split_threshold_;
+
+ size_t num_blocks_;
+ BlockSplit* split_; /* not owned */
+ HistogramType* histograms_; /* not owned */
+ size_t* histograms_size_; /* not owned */
+
+ /* The number of symbols that we want to collect before deciding on whether
+ or not to merge the block with a previous one or emit a new block. */
+ size_t target_block_size_;
+ /* The number of symbols in the current histogram. */
+ size_t block_size_;
+ /* Offset of the current histogram. */
+ size_t curr_histogram_ix_;
+ /* Offset of the histograms of the previous two block types. */
+ size_t last_histogram_ix_[2];
+ /* Entropy of the previous two block types. */
+ double last_entropy_[2];
+ /* The number of times we merged the current block with the last one. */
+ size_t merge_last_count_;
+} FN(BlockSplitter);
+
+static void FN(InitBlockSplitter)(
+ MemoryManager* m, FN(BlockSplitter)* self, size_t alphabet_size,
+ size_t min_block_size, double split_threshold, size_t num_symbols,
+ BlockSplit* split, HistogramType** histograms, size_t* histograms_size) {
+ size_t max_num_blocks = num_symbols / min_block_size + 1;
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ size_t max_num_types =
+ BROTLI_MIN(size_t, max_num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 1);
+ self->alphabet_size_ = alphabet_size;
+ self->min_block_size_ = min_block_size;
+ self->split_threshold_ = split_threshold;
+ self->num_blocks_ = 0;
+ self->split_ = split;
+ self->histograms_size_ = histograms_size;
+ self->target_block_size_ = min_block_size;
+ self->block_size_ = 0;
+ self->curr_histogram_ix_ = 0;
+ self->merge_last_count_ = 0;
+ BROTLI_ENSURE_CAPACITY(m, uint8_t,
+ split->types, split->types_alloc_size, max_num_blocks);
+ BROTLI_ENSURE_CAPACITY(m, uint32_t,
+ split->lengths, split->lengths_alloc_size, max_num_blocks);
+ if (BROTLI_IS_OOM(m)) return;
+ self->split_->num_blocks = max_num_blocks;
+ BROTLI_DCHECK(*histograms == 0);
+ *histograms_size = max_num_types;
+ *histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
+ self->histograms_ = *histograms;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
+ /* Clear only current histogram. */
+ FN(HistogramClear)(&self->histograms_[0]);
+ self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+static void FN(BlockSplitterFinishBlock)(
+ FN(BlockSplitter)* self, BROTLI_BOOL is_final) {
+ BlockSplit* split = self->split_;
+ double* last_entropy = self->last_entropy_;
+ HistogramType* histograms = self->histograms_;
+ self->block_size_ =
+ BROTLI_MAX(size_t, self->block_size_, self->min_block_size_);
+ if (self->num_blocks_ == 0) {
+ /* Create first block. */
+ split->lengths[0] = (uint32_t)self->block_size_;
+ split->types[0] = 0;
+ last_entropy[0] =
+ BitsEntropy(histograms[0].data_, self->alphabet_size_);
+ last_entropy[1] = last_entropy[0];
+ ++self->num_blocks_;
+ ++split->num_types;
+ ++self->curr_histogram_ix_;
+ if (self->curr_histogram_ix_ < *self->histograms_size_)
+ FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
+ self->block_size_ = 0;
+ } else if (self->block_size_ > 0) {
+ double entropy = BitsEntropy(histograms[self->curr_histogram_ix_].data_,
+ self->alphabet_size_);
+ HistogramType combined_histo[2];
+ double combined_entropy[2];
+ double diff[2];
+ size_t j;
+ for (j = 0; j < 2; ++j) {
+ size_t last_histogram_ix = self->last_histogram_ix_[j];
+ combined_histo[j] = histograms[self->curr_histogram_ix_];
+ FN(HistogramAddHistogram)(&combined_histo[j],
+ &histograms[last_histogram_ix]);
+ combined_entropy[j] = BitsEntropy(
+ &combined_histo[j].data_[0], self->alphabet_size_);
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j];
+ }
+
+ if (split->num_types < BROTLI_MAX_NUMBER_OF_BLOCK_TYPES &&
+ diff[0] > self->split_threshold_ &&
+ diff[1] > self->split_threshold_) {
+ /* Create new block. */
+ split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
+ split->types[self->num_blocks_] = (uint8_t)split->num_types;
+ self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
+ self->last_histogram_ix_[0] = (uint8_t)split->num_types;
+ last_entropy[1] = last_entropy[0];
+ last_entropy[0] = entropy;
+ ++self->num_blocks_;
+ ++split->num_types;
+ ++self->curr_histogram_ix_;
+ if (self->curr_histogram_ix_ < *self->histograms_size_)
+ FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
+ self->block_size_ = 0;
+ self->merge_last_count_ = 0;
+ self->target_block_size_ = self->min_block_size_;
+ } else if (diff[1] < diff[0] - 20.0) {
+ /* Combine this block with second last block. */
+ split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
+ split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
+ BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
+ histograms[self->last_histogram_ix_[0]] = combined_histo[1];
+ last_entropy[1] = last_entropy[0];
+ last_entropy[0] = combined_entropy[1];
+ ++self->num_blocks_;
+ self->block_size_ = 0;
+ FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
+ self->merge_last_count_ = 0;
+ self->target_block_size_ = self->min_block_size_;
+ } else {
+ /* Combine this block with last block. */
+ split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
+ histograms[self->last_histogram_ix_[0]] = combined_histo[0];
+ last_entropy[0] = combined_entropy[0];
+ if (split->num_types == 1) {
+ last_entropy[1] = last_entropy[0];
+ }
+ self->block_size_ = 0;
+ FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
+ if (++self->merge_last_count_ > 1) {
+ self->target_block_size_ += self->min_block_size_;
+ }
+ }
+ }
+ if (is_final) {
+ *self->histograms_size_ = split->num_types;
+ split->num_blocks = self->num_blocks_;
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+static void FN(BlockSplitterAddSymbol)(FN(BlockSplitter)* self, size_t symbol) {
+ FN(HistogramAdd)(&self->histograms_[self->curr_histogram_ix_], symbol);
+ ++self->block_size_;
+ if (self->block_size_ == self->target_block_size_) {
+ FN(BlockSplitterFinishBlock)(self, /* is_final = */ BROTLI_FALSE);
+ }
+}
+
+#undef HistogramType
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/params.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/params.h
new file mode 100755
index 000000000..54a7f0073
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/params.h
@@ -0,0 +1,46 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Parameters for the Brotli encoder with chosen quality levels. */
+
+#ifndef BROTLI_ENC_PARAMS_H_
+#define BROTLI_ENC_PARAMS_H_
+
+#include <brotli/encode.h>
+#include "./encoder_dict.h"
+
+typedef struct BrotliHasherParams {
+ int type;
+ int bucket_bits;
+ int block_bits;
+ int hash_len;
+ int num_last_distances_to_check;
+} BrotliHasherParams;
+
+typedef struct BrotliDistanceParams {
+ uint32_t distance_postfix_bits;
+ uint32_t num_direct_distance_codes;
+ uint32_t alphabet_size_max;
+ uint32_t alphabet_size_limit;
+ size_t max_distance;
+} BrotliDistanceParams;
+
+/* Encoding parameters */
+typedef struct BrotliEncoderParams {
+ BrotliEncoderMode mode;
+ int quality;
+ int lgwin;
+ int lgblock;
+ size_t stream_offset;
+ size_t size_hint;
+ BROTLI_BOOL disable_literal_context_modeling;
+ BROTLI_BOOL large_window;
+ BrotliHasherParams hasher;
+ BrotliDistanceParams dist;
+ BrotliEncoderDictionary dictionary;
+} BrotliEncoderParams;
+
+#endif /* BROTLI_ENC_PARAMS_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/prefix.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/prefix.h
new file mode 100644
index 000000000..fd359a478
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/prefix.h
@@ -0,0 +1,53 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for encoding of integers into prefix codes the amount of extra
+ bits, and the actual values of the extra bits. */
+
+#ifndef BROTLI_ENC_PREFIX_H_
+#define BROTLI_ENC_PREFIX_H_
+
+#include "../common/constants.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./fast_log.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Here distance_code is an intermediate code, i.e. one of the special codes or
+ the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */
+static BROTLI_INLINE void PrefixEncodeCopyDistance(size_t distance_code,
+ size_t num_direct_codes,
+ size_t postfix_bits,
+ uint16_t* code,
+ uint32_t* extra_bits) {
+ if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes) {
+ *code = (uint16_t)distance_code;
+ *extra_bits = 0;
+ return;
+ } else {
+ size_t dist = ((size_t)1 << (postfix_bits + 2u)) +
+ (distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES - num_direct_codes);
+ size_t bucket = Log2FloorNonZero(dist) - 1;
+ size_t postfix_mask = (1u << postfix_bits) - 1;
+ size_t postfix = dist & postfix_mask;
+ size_t prefix = (dist >> bucket) & 1;
+ size_t offset = (2 + prefix) << bucket;
+ size_t nbits = bucket - postfix_bits;
+ *code = (uint16_t)((nbits << 10) |
+ (BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes +
+ ((2 * (nbits - 1) + prefix) << postfix_bits) + postfix));
+ *extra_bits = (uint32_t)((dist - offset) >> postfix_bits);
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_PREFIX_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/quality.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/quality.h
new file mode 100644
index 000000000..5f4d03450
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/quality.h
@@ -0,0 +1,165 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Constants and formulas that affect speed-ratio trade-offs and thus define
+ quality levels. */
+
+#ifndef BROTLI_ENC_QUALITY_H_
+#define BROTLI_ENC_QUALITY_H_
+
+#include "../common/platform.h"
+#include <brotli/encode.h>
+#include "./params.h"
+
+#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
+#define FAST_TWO_PASS_COMPRESSION_QUALITY 1
+#define ZOPFLIFICATION_QUALITY 10
+#define HQ_ZOPFLIFICATION_QUALITY 11
+
+#define MAX_QUALITY_FOR_STATIC_ENTROPY_CODES 2
+#define MIN_QUALITY_FOR_BLOCK_SPLIT 4
+#define MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS 4
+#define MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS 4
+#define MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH 5
+#define MIN_QUALITY_FOR_CONTEXT_MODELING 5
+#define MIN_QUALITY_FOR_HQ_CONTEXT_MODELING 7
+#define MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING 10
+
+/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
+ so we buffer at most this much literals and commands. */
+#define MAX_NUM_DELAYED_SYMBOLS 0x2FFF
+
+/* Returns hash-table size for quality levels 0 and 1. */
+static BROTLI_INLINE size_t MaxHashTableSize(int quality) {
+ return quality == FAST_ONE_PASS_COMPRESSION_QUALITY ? 1 << 15 : 1 << 17;
+}
+
+/* The maximum length for which the zopflification uses distinct distances. */
+#define MAX_ZOPFLI_LEN_QUALITY_10 150
+#define MAX_ZOPFLI_LEN_QUALITY_11 325
+
+/* Do not thoroughly search when a long copy is found. */
+#define BROTLI_LONG_COPY_QUICK_STEP 16384
+
+static BROTLI_INLINE size_t MaxZopfliLen(const BrotliEncoderParams* params) {
+ return params->quality <= 10 ?
+ MAX_ZOPFLI_LEN_QUALITY_10 :
+ MAX_ZOPFLI_LEN_QUALITY_11;
+}
+
+/* Number of best candidates to evaluate to expand Zopfli chain. */
+static BROTLI_INLINE size_t MaxZopfliCandidates(
+ const BrotliEncoderParams* params) {
+ return params->quality <= 10 ? 1 : 5;
+}
+
+static BROTLI_INLINE void SanitizeParams(BrotliEncoderParams* params) {
+ params->quality = BROTLI_MIN(int, BROTLI_MAX_QUALITY,
+ BROTLI_MAX(int, BROTLI_MIN_QUALITY, params->quality));
+ if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
+ params->large_window = BROTLI_FALSE;
+ }
+ if (params->lgwin < BROTLI_MIN_WINDOW_BITS) {
+ params->lgwin = BROTLI_MIN_WINDOW_BITS;
+ } else {
+ int max_lgwin = params->large_window ? BROTLI_LARGE_MAX_WINDOW_BITS :
+ BROTLI_MAX_WINDOW_BITS;
+ if (params->lgwin > max_lgwin) params->lgwin = max_lgwin;
+ }
+}
+
+/* Returns optimized lg_block value. */
+static BROTLI_INLINE int ComputeLgBlock(const BrotliEncoderParams* params) {
+ int lgblock = params->lgblock;
+ if (params->quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
+ params->quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ lgblock = params->lgwin;
+ } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
+ lgblock = 14;
+ } else if (lgblock == 0) {
+ lgblock = 16;
+ if (params->quality >= 9 && params->lgwin > lgblock) {
+ lgblock = BROTLI_MIN(int, 18, params->lgwin);
+ }
+ } else {
+ lgblock = BROTLI_MIN(int, BROTLI_MAX_INPUT_BLOCK_BITS,
+ BROTLI_MAX(int, BROTLI_MIN_INPUT_BLOCK_BITS, lgblock));
+ }
+ return lgblock;
+}
+
+/* Returns log2 of the size of main ring buffer area.
+ Allocate at least lgwin + 1 bits for the ring buffer so that the newly
+ added block fits there completely and we still get lgwin bits and at least
+ read_block_size_bits + 1 bits because the copy tail length needs to be
+ smaller than ring-buffer size. */
+static BROTLI_INLINE int ComputeRbBits(const BrotliEncoderParams* params) {
+ return 1 + BROTLI_MAX(int, params->lgwin, params->lgblock);
+}
+
+static BROTLI_INLINE size_t MaxMetablockSize(
+ const BrotliEncoderParams* params) {
+ int bits =
+ BROTLI_MIN(int, ComputeRbBits(params), BROTLI_MAX_INPUT_BLOCK_BITS);
+ return (size_t)1 << bits;
+}
+
+/* When searching for backward references and have not seen matches for a long
+ time, we can skip some match lookups. Unsuccessful match lookups are very
+ expensive and this kind of a heuristic speeds up compression quite a lot.
+ At first 8 byte strides are taken and every second byte is put to hasher.
+ After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
+ Applied only to qualities 2 to 9. */
+static BROTLI_INLINE size_t LiteralSpreeLengthForSparseSearch(
+ const BrotliEncoderParams* params) {
+ return params->quality < 9 ? 64 : 512;
+}
+
+static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
+ BrotliHasherParams* hparams) {
+ if (params->quality > 9) {
+ hparams->type = 10;
+ } else if (params->quality == 4 && params->size_hint >= (1 << 20)) {
+ hparams->type = 54;
+ } else if (params->quality < 5) {
+ hparams->type = params->quality;
+ } else if (params->lgwin <= 16) {
+ hparams->type = params->quality < 7 ? 40 : params->quality < 9 ? 41 : 42;
+ } else if (params->size_hint >= (1 << 20) && params->lgwin >= 19) {
+ hparams->type = 6;
+ hparams->block_bits = params->quality - 1;
+ hparams->bucket_bits = 15;
+ hparams->hash_len = 5;
+ hparams->num_last_distances_to_check =
+ params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
+ } else {
+ hparams->type = 5;
+ hparams->block_bits = params->quality - 1;
+ hparams->bucket_bits = params->quality < 7 ? 14 : 15;
+ hparams->num_last_distances_to_check =
+ params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
+ }
+
+ if (params->lgwin > 24) {
+ /* Different hashers for large window brotli: not for qualities <= 2,
+ these are too fast for large window. Not for qualities >= 10: their
+ hasher already works well with large window. So the changes are:
+ H3 --> H35: for quality 3.
+ H54 --> H55: for quality 4 with size hint > 1MB
+ H6 --> H65: for qualities 5, 6, 7, 8, 9. */
+ if (hparams->type == 3) {
+ hparams->type = 35;
+ }
+ if (hparams->type == 54) {
+ hparams->type = 55;
+ }
+ if (hparams->type == 6) {
+ hparams->type = 65;
+ }
+ }
+}
+
+#endif /* BROTLI_ENC_QUALITY_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/ringbuffer.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/ringbuffer.h
new file mode 100644
index 000000000..8dce14803
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/ringbuffer.h
@@ -0,0 +1,167 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Sliding window over the input data. */
+
+#ifndef BROTLI_ENC_RINGBUFFER_H_
+#define BROTLI_ENC_RINGBUFFER_H_
+
+#include <string.h> /* memcpy */
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./memory.h"
+#include "./quality.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
+ data in a circular manner: writing a byte writes it to:
+ `position() % (1 << window_bits)'.
+ For convenience, the RingBuffer array contains another copy of the
+ first `1 << tail_bits' bytes:
+ buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
+ and another copy of the last two bytes:
+ buffer_[-1] == buffer_[(1 << window_bits) - 1] and
+ buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
+typedef struct RingBuffer {
+ /* Size of the ring-buffer is (1 << window_bits) + tail_size_. */
+ const uint32_t size_;
+ const uint32_t mask_;
+ const uint32_t tail_size_;
+ const uint32_t total_size_;
+
+ uint32_t cur_size_;
+ /* Position to write in the ring buffer. */
+ uint32_t pos_;
+ /* The actual ring buffer containing the copy of the last two bytes, the data,
+ and the copy of the beginning as a tail. */
+ uint8_t* data_;
+ /* The start of the ring-buffer. */
+ uint8_t* buffer_;
+} RingBuffer;
+
+static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) {
+ rb->cur_size_ = 0;
+ rb->pos_ = 0;
+ rb->data_ = 0;
+ rb->buffer_ = 0;
+}
+
+static BROTLI_INLINE void RingBufferSetup(
+ const BrotliEncoderParams* params, RingBuffer* rb) {
+ int window_bits = ComputeRbBits(params);
+ int tail_bits = params->lgblock;
+ *(uint32_t*)&rb->size_ = 1u << window_bits;
+ *(uint32_t*)&rb->mask_ = (1u << window_bits) - 1;
+ *(uint32_t*)&rb->tail_size_ = 1u << tail_bits;
+ *(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_;
+}
+
+static BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) {
+ BROTLI_FREE(m, rb->data_);
+}
+
+/* Allocates or re-allocates data_ to the given length + plus some slack
+ region before and after. Fills the slack regions with zeros. */
+static BROTLI_INLINE void RingBufferInitBuffer(
+ MemoryManager* m, const uint32_t buflen, RingBuffer* rb) {
+ static const size_t kSlackForEightByteHashingEverywhere = 7;
+ uint8_t* new_data = BROTLI_ALLOC(
+ m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
+ size_t i;
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
+ if (rb->data_) {
+ memcpy(new_data, rb->data_,
+ 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
+ BROTLI_FREE(m, rb->data_);
+ }
+ rb->data_ = new_data;
+ rb->cur_size_ = buflen;
+ rb->buffer_ = rb->data_ + 2;
+ rb->buffer_[-2] = rb->buffer_[-1] = 0;
+ for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) {
+ rb->buffer_[rb->cur_size_ + i] = 0;
+ }
+}
+
+static BROTLI_INLINE void RingBufferWriteTail(
+ const uint8_t* bytes, size_t n, RingBuffer* rb) {
+ const size_t masked_pos = rb->pos_ & rb->mask_;
+ if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) {
+ /* Just fill the tail buffer with the beginning data. */
+ const size_t p = rb->size_ + masked_pos;
+ memcpy(&rb->buffer_[p], bytes,
+ BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos));
+ }
+}
+
+/* Push bytes into the ring buffer. */
+static BROTLI_INLINE void RingBufferWrite(
+ MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) {
+ if (rb->pos_ == 0 && n < rb->tail_size_) {
+ /* Special case for the first write: to process the first block, we don't
+ need to allocate the whole ring-buffer and we don't need the tail
+ either. However, we do this memory usage optimization only if the
+ first write is less than the tail size, which is also the input block
+ size, otherwise it is likely that other blocks will follow and we
+ will need to reallocate to the full size anyway. */
+ rb->pos_ = (uint32_t)n;
+ RingBufferInitBuffer(m, rb->pos_, rb);
+ if (BROTLI_IS_OOM(m)) return;
+ memcpy(rb->buffer_, bytes, n);
+ return;
+ }
+ if (rb->cur_size_ < rb->total_size_) {
+ /* Lazily allocate the full buffer. */
+ RingBufferInitBuffer(m, rb->total_size_, rb);
+ if (BROTLI_IS_OOM(m)) return;
+ /* Initialize the last two bytes to zero, so that we don't have to worry
+ later when we copy the last two bytes to the first two positions. */
+ rb->buffer_[rb->size_ - 2] = 0;
+ rb->buffer_[rb->size_ - 1] = 0;
+ /* Initialize tail; might be touched by "best_len++" optimization when
+ ring buffer is "full". */
+ rb->buffer_[rb->size_] = 241;
+ }
+ {
+ const size_t masked_pos = rb->pos_ & rb->mask_;
+ /* The length of the writes is limited so that we do not need to worry
+ about a write */
+ RingBufferWriteTail(bytes, n, rb);
+ if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) {
+ /* A single write fits. */
+ memcpy(&rb->buffer_[masked_pos], bytes, n);
+ } else {
+ /* Split into two writes.
+ Copy into the end of the buffer, including the tail buffer. */
+ memcpy(&rb->buffer_[masked_pos], bytes,
+ BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos));
+ /* Copy into the beginning of the buffer */
+ memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos),
+ n - (rb->size_ - masked_pos));
+ }
+ }
+ {
+ BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0;
+ uint32_t rb_pos_mask = (1u << 31) - 1;
+ rb->buffer_[-2] = rb->buffer_[rb->size_ - 2];
+ rb->buffer_[-1] = rb->buffer_[rb->size_ - 1];
+ rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask);
+ if (not_first_lap) {
+ /* Wrap, but preserve not-a-first-lap feature. */
+ rb->pos_ |= 1u << 31;
+ }
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_RINGBUFFER_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.c
new file mode 100644
index 000000000..7299ab720
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.c
@@ -0,0 +1,486 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./static_dict.h"
+
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include "../common/transform.h"
+#include "./encoder_dict.h"
+#include "./find_match_length.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static BROTLI_INLINE uint32_t Hash(const uint8_t* data) {
+ uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kDictHashMul32;
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - kDictNumBits);
+}
+
+static BROTLI_INLINE void AddMatch(size_t distance, size_t len, size_t len_code,
+ uint32_t* matches) {
+ uint32_t match = (uint32_t)((distance << 5) + len_code);
+ matches[len] = BROTLI_MIN(uint32_t, matches[len], match);
+}
+
+static BROTLI_INLINE size_t DictMatchLength(const BrotliDictionary* dictionary,
+ const uint8_t* data,
+ size_t id,
+ size_t len,
+ size_t maxlen) {
+ const size_t offset = dictionary->offsets_by_length[len] + len * id;
+ return FindMatchLengthWithLimit(&dictionary->data[offset], data,
+ BROTLI_MIN(size_t, len, maxlen));
+}
+
+static BROTLI_INLINE BROTLI_BOOL IsMatch(const BrotliDictionary* dictionary,
+ DictWord w, const uint8_t* data, size_t max_length) {
+ if (w.len > max_length) {
+ return BROTLI_FALSE;
+ } else {
+ const size_t offset = dictionary->offsets_by_length[w.len] +
+ (size_t)w.len * (size_t)w.idx;
+ const uint8_t* dict = &dictionary->data[offset];
+ if (w.transform == 0) {
+ /* Match against base dictionary word. */
+ return
+ TO_BROTLI_BOOL(FindMatchLengthWithLimit(dict, data, w.len) == w.len);
+ } else if (w.transform == 10) {
+ /* Match against uppercase first transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ return TO_BROTLI_BOOL(dict[0] >= 'a' && dict[0] <= 'z' &&
+ (dict[0] ^ 32) == data[0] &&
+ FindMatchLengthWithLimit(&dict[1], &data[1], w.len - 1u) ==
+ w.len - 1u);
+ } else {
+ /* Match against uppercase all transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ size_t i;
+ for (i = 0; i < w.len; ++i) {
+ if (dict[i] >= 'a' && dict[i] <= 'z') {
+ if ((dict[i] ^ 32) != data[i]) return BROTLI_FALSE;
+ } else {
+ if (dict[i] != data[i]) return BROTLI_FALSE;
+ }
+ }
+ return BROTLI_TRUE;
+ }
+ }
+}
+
+BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
+ const BrotliEncoderDictionary* dictionary, const uint8_t* data,
+ size_t min_length, size_t max_length, uint32_t* matches) {
+ BROTLI_BOOL has_found_match = BROTLI_FALSE;
+ {
+ size_t offset = dictionary->buckets[Hash(data)];
+ BROTLI_BOOL end = !offset;
+ while (!end) {
+ DictWord w = dictionary->dict_words[offset++];
+ const size_t l = w.len & 0x1F;
+ const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
+ const size_t id = w.idx;
+ end = !!(w.len & 0x80);
+ w.len = (uint8_t)l;
+ if (w.transform == 0) {
+ const size_t matchlen =
+ DictMatchLength(dictionary->words, data, id, l, max_length);
+ const uint8_t* s;
+ size_t minlen;
+ size_t maxlen;
+ size_t len;
+ /* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */
+ if (matchlen == l) {
+ AddMatch(id, l, l, matches);
+ has_found_match = BROTLI_TRUE;
+ }
+ /* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and
+ "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */
+ if (matchlen >= l - 1) {
+ AddMatch(id + 12 * n, l - 1, l, matches);
+ if (l + 2 < max_length &&
+ data[l - 1] == 'i' && data[l] == 'n' && data[l + 1] == 'g' &&
+ data[l + 2] == ' ') {
+ AddMatch(id + 49 * n, l + 3, l, matches);
+ }
+ has_found_match = BROTLI_TRUE;
+ }
+ /* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */
+ minlen = min_length;
+ if (l > 9) minlen = BROTLI_MAX(size_t, minlen, l - 9);
+ maxlen = BROTLI_MIN(size_t, matchlen, l - 2);
+ for (len = minlen; len <= maxlen; ++len) {
+ size_t cut = l - len;
+ size_t transform_id = (cut << 2) +
+ (size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
+ AddMatch(id + transform_id * n, len, l, matches);
+ has_found_match = BROTLI_TRUE;
+ }
+ if (matchlen < l || l + 6 >= max_length) {
+ continue;
+ }
+ s = &data[l];
+ /* Transforms "" + BROTLI_TRANSFORM_IDENTITY + <suffix> */
+ if (s[0] == ' ') {
+ AddMatch(id + n, l + 1, l, matches);
+ if (s[1] == 'a') {
+ if (s[2] == ' ') {
+ AddMatch(id + 28 * n, l + 3, l, matches);
+ } else if (s[2] == 's') {
+ if (s[3] == ' ') AddMatch(id + 46 * n, l + 4, l, matches);
+ } else if (s[2] == 't') {
+ if (s[3] == ' ') AddMatch(id + 60 * n, l + 4, l, matches);
+ } else if (s[2] == 'n') {
+ if (s[3] == 'd' && s[4] == ' ') {
+ AddMatch(id + 10 * n, l + 5, l, matches);
+ }
+ }
+ } else if (s[1] == 'b') {
+ if (s[2] == 'y' && s[3] == ' ') {
+ AddMatch(id + 38 * n, l + 4, l, matches);
+ }
+ } else if (s[1] == 'i') {
+ if (s[2] == 'n') {
+ if (s[3] == ' ') AddMatch(id + 16 * n, l + 4, l, matches);
+ } else if (s[2] == 's') {
+ if (s[3] == ' ') AddMatch(id + 47 * n, l + 4, l, matches);
+ }
+ } else if (s[1] == 'f') {
+ if (s[2] == 'o') {
+ if (s[3] == 'r' && s[4] == ' ') {
+ AddMatch(id + 25 * n, l + 5, l, matches);
+ }
+ } else if (s[2] == 'r') {
+ if (s[3] == 'o' && s[4] == 'm' && s[5] == ' ') {
+ AddMatch(id + 37 * n, l + 6, l, matches);
+ }
+ }
+ } else if (s[1] == 'o') {
+ if (s[2] == 'f') {
+ if (s[3] == ' ') AddMatch(id + 8 * n, l + 4, l, matches);
+ } else if (s[2] == 'n') {
+ if (s[3] == ' ') AddMatch(id + 45 * n, l + 4, l, matches);
+ }
+ } else if (s[1] == 'n') {
+ if (s[2] == 'o' && s[3] == 't' && s[4] == ' ') {
+ AddMatch(id + 80 * n, l + 5, l, matches);
+ }
+ } else if (s[1] == 't') {
+ if (s[2] == 'h') {
+ if (s[3] == 'e') {
+ if (s[4] == ' ') AddMatch(id + 5 * n, l + 5, l, matches);
+ } else if (s[3] == 'a') {
+ if (s[4] == 't' && s[5] == ' ') {
+ AddMatch(id + 29 * n, l + 6, l, matches);
+ }
+ }
+ } else if (s[2] == 'o') {
+ if (s[3] == ' ') AddMatch(id + 17 * n, l + 4, l, matches);
+ }
+ } else if (s[1] == 'w') {
+ if (s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ') {
+ AddMatch(id + 35 * n, l + 6, l, matches);
+ }
+ }
+ } else if (s[0] == '"') {
+ AddMatch(id + 19 * n, l + 1, l, matches);
+ if (s[1] == '>') {
+ AddMatch(id + 21 * n, l + 2, l, matches);
+ }
+ } else if (s[0] == '.') {
+ AddMatch(id + 20 * n, l + 1, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + 31 * n, l + 2, l, matches);
+ if (s[2] == 'T' && s[3] == 'h') {
+ if (s[4] == 'e') {
+ if (s[5] == ' ') AddMatch(id + 43 * n, l + 6, l, matches);
+ } else if (s[4] == 'i') {
+ if (s[5] == 's' && s[6] == ' ') {
+ AddMatch(id + 75 * n, l + 7, l, matches);
+ }
+ }
+ }
+ }
+ } else if (s[0] == ',') {
+ AddMatch(id + 76 * n, l + 1, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + 14 * n, l + 2, l, matches);
+ }
+ } else if (s[0] == '\n') {
+ AddMatch(id + 22 * n, l + 1, l, matches);
+ if (s[1] == '\t') {
+ AddMatch(id + 50 * n, l + 2, l, matches);
+ }
+ } else if (s[0] == ']') {
+ AddMatch(id + 24 * n, l + 1, l, matches);
+ } else if (s[0] == '\'') {
+ AddMatch(id + 36 * n, l + 1, l, matches);
+ } else if (s[0] == ':') {
+ AddMatch(id + 51 * n, l + 1, l, matches);
+ } else if (s[0] == '(') {
+ AddMatch(id + 57 * n, l + 1, l, matches);
+ } else if (s[0] == '=') {
+ if (s[1] == '"') {
+ AddMatch(id + 70 * n, l + 2, l, matches);
+ } else if (s[1] == '\'') {
+ AddMatch(id + 86 * n, l + 2, l, matches);
+ }
+ } else if (s[0] == 'a') {
+ if (s[1] == 'l' && s[2] == ' ') {
+ AddMatch(id + 84 * n, l + 3, l, matches);
+ }
+ } else if (s[0] == 'e') {
+ if (s[1] == 'd') {
+ if (s[2] == ' ') AddMatch(id + 53 * n, l + 3, l, matches);
+ } else if (s[1] == 'r') {
+ if (s[2] == ' ') AddMatch(id + 82 * n, l + 3, l, matches);
+ } else if (s[1] == 's') {
+ if (s[2] == 't' && s[3] == ' ') {
+ AddMatch(id + 95 * n, l + 4, l, matches);
+ }
+ }
+ } else if (s[0] == 'f') {
+ if (s[1] == 'u' && s[2] == 'l' && s[3] == ' ') {
+ AddMatch(id + 90 * n, l + 4, l, matches);
+ }
+ } else if (s[0] == 'i') {
+ if (s[1] == 'v') {
+ if (s[2] == 'e' && s[3] == ' ') {
+ AddMatch(id + 92 * n, l + 4, l, matches);
+ }
+ } else if (s[1] == 'z') {
+ if (s[2] == 'e' && s[3] == ' ') {
+ AddMatch(id + 100 * n, l + 4, l, matches);
+ }
+ }
+ } else if (s[0] == 'l') {
+ if (s[1] == 'e') {
+ if (s[2] == 's' && s[3] == 's' && s[4] == ' ') {
+ AddMatch(id + 93 * n, l + 5, l, matches);
+ }
+ } else if (s[1] == 'y') {
+ if (s[2] == ' ') AddMatch(id + 61 * n, l + 3, l, matches);
+ }
+ } else if (s[0] == 'o') {
+ if (s[1] == 'u' && s[2] == 's' && s[3] == ' ') {
+ AddMatch(id + 106 * n, l + 4, l, matches);
+ }
+ }
+ } else {
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+ const BROTLI_BOOL is_all_caps =
+ TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST);
+ const uint8_t* s;
+ if (!IsMatch(dictionary->words, w, data, max_length)) {
+ continue;
+ }
+ /* Transform "" + kUppercase{First,All} + "" */
+ AddMatch(id + (is_all_caps ? 44 : 9) * n, l, l, matches);
+ has_found_match = BROTLI_TRUE;
+ if (l + 1 >= max_length) {
+ continue;
+ }
+ /* Transforms "" + kUppercase{First,All} + <suffix> */
+ s = &data[l];
+ if (s[0] == ' ') {
+ AddMatch(id + (is_all_caps ? 68 : 4) * n, l + 1, l, matches);
+ } else if (s[0] == '"') {
+ AddMatch(id + (is_all_caps ? 87 : 66) * n, l + 1, l, matches);
+ if (s[1] == '>') {
+ AddMatch(id + (is_all_caps ? 97 : 69) * n, l + 2, l, matches);
+ }
+ } else if (s[0] == '.') {
+ AddMatch(id + (is_all_caps ? 101 : 79) * n, l + 1, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + (is_all_caps ? 114 : 88) * n, l + 2, l, matches);
+ }
+ } else if (s[0] == ',') {
+ AddMatch(id + (is_all_caps ? 112 : 99) * n, l + 1, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + (is_all_caps ? 107 : 58) * n, l + 2, l, matches);
+ }
+ } else if (s[0] == '\'') {
+ AddMatch(id + (is_all_caps ? 94 : 74) * n, l + 1, l, matches);
+ } else if (s[0] == '(') {
+ AddMatch(id + (is_all_caps ? 113 : 78) * n, l + 1, l, matches);
+ } else if (s[0] == '=') {
+ if (s[1] == '"') {
+ AddMatch(id + (is_all_caps ? 105 : 104) * n, l + 2, l, matches);
+ } else if (s[1] == '\'') {
+ AddMatch(id + (is_all_caps ? 116 : 108) * n, l + 2, l, matches);
+ }
+ }
+ }
+ }
+ }
+ /* Transforms with prefixes " " and "." */
+ if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) {
+ BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' ');
+ size_t offset = dictionary->buckets[Hash(&data[1])];
+ BROTLI_BOOL end = !offset;
+ while (!end) {
+ DictWord w = dictionary->dict_words[offset++];
+ const size_t l = w.len & 0x1F;
+ const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
+ const size_t id = w.idx;
+ end = !!(w.len & 0x80);
+ w.len = (uint8_t)l;
+ if (w.transform == 0) {
+ const uint8_t* s;
+ if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) {
+ continue;
+ }
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and
+ "." + BROTLI_TRANSFORM_IDENTITY + "" */
+ AddMatch(id + (is_space ? 6 : 32) * n, l + 1, l, matches);
+ has_found_match = BROTLI_TRUE;
+ if (l + 2 >= max_length) {
+ continue;
+ }
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + <suffix> and
+ "." + BROTLI_TRANSFORM_IDENTITY + <suffix>
+ */
+ s = &data[l + 1];
+ if (s[0] == ' ') {
+ AddMatch(id + (is_space ? 2 : 77) * n, l + 2, l, matches);
+ } else if (s[0] == '(') {
+ AddMatch(id + (is_space ? 89 : 67) * n, l + 2, l, matches);
+ } else if (is_space) {
+ if (s[0] == ',') {
+ AddMatch(id + 103 * n, l + 2, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + 33 * n, l + 3, l, matches);
+ }
+ } else if (s[0] == '.') {
+ AddMatch(id + 71 * n, l + 2, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + 52 * n, l + 3, l, matches);
+ }
+ } else if (s[0] == '=') {
+ if (s[1] == '"') {
+ AddMatch(id + 81 * n, l + 3, l, matches);
+ } else if (s[1] == '\'') {
+ AddMatch(id + 98 * n, l + 3, l, matches);
+ }
+ }
+ }
+ } else if (is_space) {
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+ const BROTLI_BOOL is_all_caps =
+ TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST);
+ const uint8_t* s;
+ if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) {
+ continue;
+ }
+ /* Transforms " " + kUppercase{First,All} + "" */
+ AddMatch(id + (is_all_caps ? 85 : 30) * n, l + 1, l, matches);
+ has_found_match = BROTLI_TRUE;
+ if (l + 2 >= max_length) {
+ continue;
+ }
+ /* Transforms " " + kUppercase{First,All} + <suffix> */
+ s = &data[l + 1];
+ if (s[0] == ' ') {
+ AddMatch(id + (is_all_caps ? 83 : 15) * n, l + 2, l, matches);
+ } else if (s[0] == ',') {
+ if (!is_all_caps) {
+ AddMatch(id + 109 * n, l + 2, l, matches);
+ }
+ if (s[1] == ' ') {
+ AddMatch(id + (is_all_caps ? 111 : 65) * n, l + 3, l, matches);
+ }
+ } else if (s[0] == '.') {
+ AddMatch(id + (is_all_caps ? 115 : 96) * n, l + 2, l, matches);
+ if (s[1] == ' ') {
+ AddMatch(id + (is_all_caps ? 117 : 91) * n, l + 3, l, matches);
+ }
+ } else if (s[0] == '=') {
+ if (s[1] == '"') {
+ AddMatch(id + (is_all_caps ? 110 : 118) * n, l + 3, l, matches);
+ } else if (s[1] == '\'') {
+ AddMatch(id + (is_all_caps ? 119 : 120) * n, l + 3, l, matches);
+ }
+ }
+ }
+ }
+ }
+ if (max_length >= 6) {
+ /* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */
+ if ((data[1] == ' ' &&
+ (data[0] == 'e' || data[0] == 's' || data[0] == ',')) ||
+ (data[0] == 0xC2 && data[1] == 0xA0)) {
+ size_t offset = dictionary->buckets[Hash(&data[2])];
+ BROTLI_BOOL end = !offset;
+ while (!end) {
+ DictWord w = dictionary->dict_words[offset++];
+ const size_t l = w.len & 0x1F;
+ const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
+ const size_t id = w.idx;
+ end = !!(w.len & 0x80);
+ w.len = (uint8_t)l;
+ if (w.transform == 0 &&
+ IsMatch(dictionary->words, w, &data[2], max_length - 2)) {
+ if (data[0] == 0xC2) {
+ AddMatch(id + 102 * n, l + 2, l, matches);
+ has_found_match = BROTLI_TRUE;
+ } else if (l + 2 < max_length && data[l + 2] == ' ') {
+ size_t t = data[0] == 'e' ? 18 : (data[0] == 's' ? 7 : 13);
+ AddMatch(id + t * n, l + 3, l, matches);
+ has_found_match = BROTLI_TRUE;
+ }
+ }
+ }
+ }
+ }
+ if (max_length >= 9) {
+ /* Transforms with prefixes " the " and ".com/" */
+ if ((data[0] == ' ' && data[1] == 't' && data[2] == 'h' &&
+ data[3] == 'e' && data[4] == ' ') ||
+ (data[0] == '.' && data[1] == 'c' && data[2] == 'o' &&
+ data[3] == 'm' && data[4] == '/')) {
+ size_t offset = dictionary->buckets[Hash(&data[5])];
+ BROTLI_BOOL end = !offset;
+ while (!end) {
+ DictWord w = dictionary->dict_words[offset++];
+ const size_t l = w.len & 0x1F;
+ const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
+ const size_t id = w.idx;
+ end = !!(w.len & 0x80);
+ w.len = (uint8_t)l;
+ if (w.transform == 0 &&
+ IsMatch(dictionary->words, w, &data[5], max_length - 5)) {
+ AddMatch(id + (data[0] == ' ' ? 41 : 72) * n, l + 5, l, matches);
+ has_found_match = BROTLI_TRUE;
+ if (l + 5 < max_length) {
+ const uint8_t* s = &data[l + 5];
+ if (data[0] == ' ') {
+ if (l + 8 < max_length &&
+ s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ') {
+ AddMatch(id + 62 * n, l + 9, l, matches);
+ if (l + 12 < max_length &&
+ s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ') {
+ AddMatch(id + 73 * n, l + 13, l, matches);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return has_found_match;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.h
new file mode 100644
index 000000000..6b5d4eb0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict.h
@@ -0,0 +1,40 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Class to model the static dictionary. */
+
+#ifndef BROTLI_ENC_STATIC_DICT_H_
+#define BROTLI_ENC_STATIC_DICT_H_
+
+#include "../common/dictionary.h"
+#include "../common/platform.h"
+#include <brotli/types.h>
+#include "./encoder_dict.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN 37
+static const uint32_t kInvalidMatch = 0xFFFFFFF;
+
+/* Matches data against static dictionary words, and for each length l,
+ for which a match is found, updates matches[l] to be the minimum possible
+ (distance << 5) + len_code.
+ Returns 1 if matches have been found, otherwise 0.
+ Prerequisites:
+ matches array is at least BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1 long
+ all elements are initialized to kInvalidMatch */
+BROTLI_INTERNAL BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
+ const BrotliEncoderDictionary* dictionary,
+ const uint8_t* data, size_t min_length, size_t max_length,
+ uint32_t* matches);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_STATIC_DICT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict_lut.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict_lut.h
new file mode 100644
index 000000000..e299cda6d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/static_dict_lut.h
@@ -0,0 +1,5864 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Lookup table for static dictionary and transforms. */
+
+#ifndef BROTLI_ENC_STATIC_DICT_LUT_H_
+#define BROTLI_ENC_STATIC_DICT_LUT_H_
+
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct DictWord {
+ /* Highest bit is used to indicate end of bucket. */
+ uint8_t len;
+ uint8_t transform;
+ uint16_t idx;
+} DictWord;
+
+static const int kDictNumBits = 15;
+static const uint32_t kDictHashMul32 = 0x1E35A7BD;
+
+static const uint16_t kStaticDictionaryBuckets[32768] = {
+1,0,0,0,0,0,0,0,0,3,6,0,0,0,0,0,20,0,0,0,21,0,22,0,0,0,0,0,0,0,0,23,0,0,25,0,29,
+0,53,0,0,0,0,0,0,55,0,0,0,0,0,0,61,76,0,0,0,94,0,0,0,0,0,0,96,0,97,0,98,0,0,0,0,
+0,0,0,99,101,106,108,0,0,0,0,0,110,0,111,112,0,113,118,124,0,0,0,0,0,125,128,0,0
+,0,0,129,0,0,131,0,0,0,0,0,0,132,0,0,135,0,0,0,137,0,0,0,0,0,138,139,0,0,0,0,0,0
+,0,142,143,144,0,0,0,0,0,145,0,0,0,146,149,151,152,0,0,153,0,0,0,0,0,0,0,0,0,0,0
+,0,0,0,0,154,0,0,0,0,0,0,155,0,0,0,0,160,182,0,0,0,0,0,0,183,0,0,0,188,189,0,0,
+192,0,0,0,0,0,0,194,0,0,0,0,0,0,0,0,197,202,209,0,0,210,0,224,0,0,0,225,0,0,0,0,
+0,0,0,0,0,0,231,0,0,0,232,0,240,0,0,242,0,0,0,0,0,0,0,0,0,0,0,244,0,0,0,246,0,0,
+249,251,253,0,0,0,0,0,258,0,0,261,263,0,0,0,267,0,0,268,0,269,0,0,0,0,0,0,0,0,0,
+271,0,0,0,0,0,0,272,0,273,0,277,0,278,286,0,0,0,0,287,0,289,290,291,0,0,0,295,0,
+0,296,297,0,0,0,0,0,0,0,0,0,0,298,0,0,0,299,0,0,305,0,324,0,0,0,0,0,327,0,328,
+329,0,0,0,0,336,0,0,340,0,341,342,343,0,0,346,0,348,0,0,0,0,0,0,349,351,0,0,355,
+0,363,0,364,0,368,369,0,370,0,0,0,0,0,0,0,372,0,0,0,0,0,0,0,0,0,0,0,373,0,375,0,
+0,0,0,376,377,0,0,394,395,396,0,0,398,0,0,0,0,400,0,0,408,0,0,0,0,420,0,0,0,0,0,
+0,421,0,0,422,423,0,0,429,435,436,442,0,0,443,0,444,445,453,456,0,457,0,0,0,0,0,
+458,0,0,0,459,0,0,0,460,0,462,463,465,0,0,0,0,0,0,466,469,0,0,0,0,0,0,470,0,0,0,
+474,0,476,0,0,0,0,483,0,485,0,0,0,486,0,0,488,491,492,0,0,497,499,500,0,501,0,0,
+0,505,0,0,506,0,0,0,507,0,0,0,509,0,0,0,0,511,512,519,0,0,0,0,0,0,529,530,0,0,0,
+534,0,0,0,0,543,0,0,0,0,0,0,0,0,0,553,0,0,0,0,557,560,0,0,0,0,0,0,561,0,564,0,0,
+0,0,0,0,565,566,0,575,0,619,0,620,0,0,623,624,0,0,0,625,0,0,626,627,0,0,628,0,0,
+0,0,630,0,631,0,0,0,0,0,0,0,0,0,641,0,0,0,0,643,656,668,0,0,0,673,0,0,0,674,0,0,
+0,0,0,0,0,0,682,0,687,0,690,0,693,699,700,0,0,0,0,0,0,704,705,0,0,0,0,707,710,0,
+711,0,0,0,0,726,0,0,729,0,0,0,730,731,0,0,0,0,0,752,0,0,0,762,0,763,0,0,767,0,0,
+0,770,774,0,0,775,0,0,0,0,0,0,0,0,0,0,776,0,0,0,777,783,0,0,0,785,788,0,0,0,0,
+790,0,0,0,793,0,0,0,0,794,0,0,804,819,821,0,827,0,0,0,834,0,0,835,0,0,0,841,0,
+844,0,850,851,859,0,860,0,0,0,0,0,0,0,874,0,876,0,877,890,0,0,0,0,0,0,0,0,893,
+894,898,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,0,0,900,904,906,0,0,0,907,0,908,909,
+0,910,0,0,0,0,911,0,0,0,0,0,916,0,0,0,922,925,0,930,0,934,0,0,0,0,0,943,0,0,944,
+0,953,954,0,0,0,0,0,0,955,0,962,963,0,0,976,0,0,977,978,979,980,0,981,0,0,0,0,
+984,0,0,985,0,0,987,989,991,0,0,0,0,0,0,0,0,0,992,0,0,0,993,0,0,0,0,0,0,996,0,0,
+0,1000,0,0,0,0,0,1002,0,0,0,0,1005,1007,0,0,0,1009,0,0,0,1010,0,0,0,0,0,0,1011,0
+,1012,0,0,0,0,1014,1016,0,0,0,1020,0,1021,0,0,0,0,1022,0,0,0,1024,0,0,0,0,0,0,
+1025,0,0,1026,1027,0,0,0,0,0,1031,0,1033,0,0,0,0,1034,0,0,0,1037,1040,0,0,0,1042
+,1043,0,0,1053,0,1054,0,0,1057,0,0,0,1058,0,0,1060,0,0,0,0,0,0,0,1061,0,0,1062,0
+,0,0,0,1063,0,0,0,0,1064,0,0,0,0,0,1065,0,0,0,0,1066,1067,0,0,0,1069,1070,1072,0
+,0,0,0,0,0,1073,0,1075,0,0,0,0,0,0,1080,1084,0,0,0,0,1088,0,0,0,0,0,0,1094,0,
+1095,0,1107,0,0,0,1112,1114,0,1119,0,1122,0,0,1126,0,1129,0,1130,0,0,0,0,0,1132,
+0,0,0,0,0,0,1144,0,0,1145,1146,0,1148,1149,0,0,1150,1151,0,0,0,0,1152,0,1153,0,0
+,0,0,0,1154,0,1163,0,0,0,1164,0,0,0,0,0,1165,0,1167,0,1170,0,0,0,0,0,1171,1172,0
+,0,0,0,0,0,0,0,1173,1175,1177,0,1186,0,0,0,0,0,0,0,0,0,0,1195,0,0,1221,0,0,1224,
+0,0,1227,0,0,0,0,0,1228,1229,0,0,1230,0,0,0,0,0,0,0,0,0,1231,0,0,0,1233,0,0,1243
+,1244,1246,1248,0,0,0,0,1254,1255,1258,1259,0,0,0,1260,0,0,1261,0,0,0,1262,1264,
+0,0,1265,0,0,0,0,0,0,0,0,0,0,0,0,1266,0,1267,0,0,0,0,1273,1274,1276,1289,0,0,
+1291,1292,1293,0,0,1294,1295,1296,0,0,0,0,1302,0,1304,0,0,0,0,0,0,0,0,0,1311,
+1312,0,1314,0,1316,1320,1321,0,0,0,0,0,0,0,1322,1323,1324,0,1335,0,1336,0,0,0,0,
+1341,1342,0,1346,0,1357,0,0,0,1358,1360,0,0,0,0,0,0,1361,0,0,0,1362,1365,0,1366,
+0,0,0,0,0,0,0,1379,0,0,0,0,0,0,0,0,0,0,0,0,1386,0,1388,0,0,0,0,0,0,0,0,0,0,0,0,0
+,0,1395,0,0,0,0,1403,0,1405,0,0,1407,0,0,0,0,0,1408,1409,0,1410,0,0,0,1412,1413,
+1416,0,0,1429,1451,0,0,1454,0,0,0,0,0,0,0,1455,0,0,0,0,0,0,0,1456,0,0,0,0,1459,
+1460,1461,1475,0,0,0,0,0,0,1477,0,1480,0,1481,0,0,1486,0,0,1495,0,0,0,1496,0,0,
+1498,1499,1501,1520,1521,0,0,0,1526,0,0,0,0,1528,1529,0,1533,1536,0,0,0,1537,
+1538,1549,0,1550,1558,1559,1572,0,1573,0,0,0,0,0,0,0,0,0,1575,0,0,0,0,0,1579,0,
+1599,0,1603,0,1604,0,1605,0,0,0,0,0,1608,1610,0,0,0,0,1611,0,1615,0,1616,1618,0,
+1619,0,0,1622,0,0,0,0,1634,0,0,0,1635,0,0,0,1641,0,0,0,0,0,0,0,0,0,1643,0,0,0,
+1650,0,0,1652,0,0,0,0,0,1653,0,0,0,1654,0,0,0,0,1655,0,1662,0,0,1663,1664,0,0,
+1668,0,0,1669,1670,0,1672,1673,0,0,0,0,0,1674,0,0,0,1675,1676,1680,0,1682,0,0,
+1687,0,0,0,0,0,1704,0,0,1705,0,0,1721,0,0,0,0,1734,1735,0,0,0,0,1737,0,0,0,0,
+1739,0,0,1740,0,0,0,0,0,0,0,0,0,0,1741,1743,0,0,0,0,1745,0,0,0,1749,0,0,0,1751,0
+,0,0,0,0,0,1760,0,0,0,0,1765,0,0,0,0,0,1784,0,1785,1787,0,0,0,0,1788,1789,0,0,0,
+0,1790,1791,1793,0,1798,1799,0,0,0,0,1801,0,1803,1805,0,0,0,1806,1811,0,1812,
+1814,0,1821,0,0,0,0,0,1822,1833,0,0,0,0,0,0,1848,0,0,0,0,0,0,1857,0,0,0,1859,0,0
+,0,0,1861,0,0,0,0,0,0,0,1866,0,1921,1925,0,0,0,1929,1930,0,0,0,0,0,0,0,0,0,1931,
+0,0,0,0,1932,0,0,0,1934,0,0,0,0,0,0,0,0,1946,0,0,1948,0,0,0,0,1950,0,1957,0,1958
+,0,0,0,0,0,1965,1967,0,0,0,0,1968,0,1969,0,1971,1972,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+,0,1973,0,0,0,0,1975,0,0,0,0,1976,1979,0,1982,0,0,0,0,1984,1988,0,0,0,0,1990,
+2004,2008,0,0,0,2012,2013,0,0,0,0,0,0,0,0,0,0,2015,0,2016,2017,0,0,0,0,2021,0,0,
+2025,0,0,0,0,0,2029,2036,2040,0,2042,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2043,0,0,0,0,0,
+2045,0,0,0,0,0,0,0,2046,2047,0,2048,2049,0,2059,0,0,2063,0,2064,2065,0,0,2066,0,
+0,0,0,0,0,2069,0,0,0,0,2070,0,2071,0,2072,0,0,0,0,2080,2082,2083,0,0,0,0,0,2085,
+0,2086,2088,2089,2105,0,0,0,0,2107,0,0,2116,2117,0,2120,0,0,2122,0,0,0,0,0,2123,
+0,0,2125,2127,2128,0,0,0,2130,0,0,0,2137,2139,2140,2141,0,0,0,0,0,0,0,0,0,2144,
+2145,0,0,2146,2149,0,0,0,0,2150,0,0,2151,2158,0,2159,0,2160,0,0,0,0,0,0,2161,
+2162,0,0,2194,2202,0,0,0,0,0,0,2205,2217,0,2220,0,2221,0,2222,2224,0,0,0,0,2237,
+0,0,0,0,0,2238,0,2239,2241,0,0,2242,0,0,0,0,0,2243,0,0,0,0,0,0,2252,0,0,2253,0,0
+,0,2257,2258,0,0,0,2260,0,0,0,0,0,0,0,2262,0,2264,0,0,0,0,0,2269,2270,0,0,0,0,0,
+0,0,0,0,2271,0,2273,0,0,0,0,2277,0,0,0,0,2278,0,0,0,0,2279,0,2280,0,2283,0,0,0,0
+,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2287,0,0,0,0,0,0,0,2289,2290,0,0,0,0,2291,0,2292,0,
+0,0,2293,2295,2296,0,0,0,0,0,0,0,2298,0,0,0,0,0,2303,0,2305,0,0,2306,0,2307,0,0,
+0,0,0,0,0,0,0,0,0,0,2313,2314,2315,2316,0,0,2318,0,2319,0,2322,0,0,2323,0,2324,0
+,2326,0,0,0,0,0,0,0,2335,0,2336,2338,2339,0,2340,0,0,0,2355,0,2375,0,2382,2386,0
+,2387,0,0,2394,0,0,0,0,2395,0,2397,0,0,0,0,0,2398,0,0,0,0,0,0,0,2399,2402,2404,
+2408,2411,0,0,0,2413,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2415,0,0,2416,2417,2419,0,2420,
+0,0,0,0,0,2425,0,0,0,2426,0,0,0,0,0,0,0,0,0,0,0,0,2427,2428,0,2429,0,0,2430,2434
+,0,2436,0,0,0,0,0,0,2441,2442,0,2445,0,0,2446,2457,0,2459,0,0,2462,0,2464,0,2477
+,0,2478,2486,0,0,0,2491,0,0,2493,0,0,2494,0,2495,0,2513,2523,0,0,0,0,2524,0,0,0,
+0,0,0,2528,2529,2530,0,0,2531,0,2533,0,0,2534,2535,0,2536,2537,0,2538,0,2539,
+2540,0,0,0,2545,2546,0,0,0,0,0,0,0,2548,0,0,2549,0,2550,2555,0,0,0,0,0,2557,0,
+2560,0,0,0,0,0,0,0,0,0,0,0,2561,0,2576,0,0,0,0,0,0,0,0,0,2577,2578,0,0,0,2579,0,
+0,0,0,0,0,0,2580,0,0,0,0,2581,0,0,0,0,2583,0,2584,0,2588,2590,0,0,0,2591,0,0,0,0
+,2593,2594,0,2595,0,2601,2602,0,0,2603,0,2605,0,0,0,2606,2607,2611,0,2615,0,0,0,
+2617,0,0,0,0,0,0,0,0,0,0,0,0,0,2619,0,0,2620,0,0,0,2621,0,2623,0,2625,0,0,2628,
+2629,0,0,2635,2636,2637,0,0,2639,0,0,0,2642,0,0,0,0,2643,0,2644,0,2649,0,0,0,0,0
+,0,2655,2656,0,0,2657,0,0,0,0,0,2658,0,0,0,0,0,2659,0,0,0,0,2664,2685,0,2687,0,
+2688,0,0,2689,0,0,2694,0,2695,0,0,2698,0,2701,2706,0,0,0,2707,0,2709,2710,2711,0
+,0,0,2720,2730,2735,0,0,0,0,2738,2740,0,0,0,0,2747,0,0,0,0,0,0,2748,0,0,2749,0,0
+,0,0,0,2750,0,0,2752,2754,0,0,0,0,0,2758,0,0,0,0,2762,0,0,0,0,2763,0,0,0,0,0,0,0
+,2764,2767,0,0,0,0,2768,0,0,2770,0,0,0,0,0,0,0,2771,0,0,0,0,0,0,0,0,0,2772,0,0,0
+,0,0,2773,2776,0,0,2783,0,0,2784,0,2789,0,2790,0,0,0,2792,0,0,0,0,0,0,0,0,0,0,
+2793,2795,0,0,0,0,0,0,2796,0,0,0,0,0,0,2797,2799,0,0,0,0,2803,0,0,0,0,2806,0,
+2807,2808,2817,2819,0,0,0,0,0,2821,0,0,0,0,2822,2823,0,0,0,0,0,0,0,2824,0,0,2828
+,0,2834,0,0,0,0,0,0,2836,0,2838,0,0,2839,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2841,
+0,0,0,2842,0,0,0,0,0,2843,2844,0,0,0,0,2846,0,0,2847,0,2849,0,2853,0,0,0,0,0,
+2857,0,0,0,0,2858,0,2859,0,0,2860,0,2862,2868,0,0,0,0,2875,0,2876,0,0,2877,2878,
+2884,2889,2890,0,0,2891,0,0,2892,0,0,0,2906,2912,0,2913,0,0,0,0,0,0,0,0,2916,0,
+2934,0,0,0,0,0,2935,0,0,0,0,2939,0,2940,0,0,0,0,0,0,0,2941,0,0,0,2946,0,2949,0,0
+,2950,2954,2955,0,0,0,2959,2961,0,0,2962,0,2963,0,0,0,0,0,0,2964,2965,2966,2967,
+0,0,0,0,0,0,0,2969,0,0,0,0,0,2970,2975,0,2982,2983,2984,0,0,0,0,0,2989,0,0,2990,
+0,0,0,0,0,0,0,2991,0,0,0,0,0,0,0,0,2998,0,3000,3001,0,0,3002,0,0,0,3003,0,0,3012
+,0,0,3022,0,0,3024,0,0,3025,3027,0,0,0,3030,0,0,0,0,3034,3035,0,0,3036,0,3039,0,
+3049,0,0,3050,0,0,0,0,0,0,3051,0,3053,0,0,0,0,3057,0,3058,0,0,0,0,0,0,0,0,3063,0
+,0,3073,3074,3078,3079,0,3080,3086,0,0,0,0,0,0,0,0,3087,0,3092,0,3095,0,3099,0,0
+,0,3100,0,3101,3102,0,3122,0,0,0,3124,0,3125,0,0,0,0,0,0,3132,3134,0,0,3136,0,0,
+0,0,0,0,0,3147,0,0,3149,0,0,0,0,0,3150,3151,3152,0,0,0,0,3158,0,0,3160,0,0,3161,
+0,0,3162,0,3163,3166,3168,0,0,3169,3170,0,0,3171,0,0,0,0,0,0,0,3182,0,3184,0,0,
+3188,0,0,3194,0,0,0,0,0,0,3204,0,0,0,0,3209,0,0,0,0,0,0,0,0,0,0,0,3216,3217,0,0,
+0,0,0,0,0,3219,0,0,3220,3222,0,3223,0,0,0,0,3224,0,3225,3226,0,3228,3233,0,3239,
+3241,3242,0,0,3251,3252,3253,3255,0,0,0,0,0,0,0,0,3260,0,0,3261,0,0,0,3267,0,0,0
+,0,0,0,0,0,3271,0,0,0,3278,0,3282,0,0,0,3284,0,0,0,3285,3286,0,0,0,0,0,0,0,3287,
+3292,0,0,0,0,3294,3296,0,0,3299,3300,3301,0,3302,0,0,0,0,0,3304,3306,0,0,0,0,0,0
+,3308,0,0,0,0,0,0,0,0,0,3311,0,0,0,0,0,0,0,0,3312,3314,3315,0,3318,0,0,0,0,0,0,0
+,0,3319,0,0,0,0,0,3321,0,0,0,0,0,0,0,0,0,3322,0,0,3324,3325,0,0,3326,0,0,3328,
+3329,3331,0,0,3335,0,0,3337,0,3338,0,0,0,0,3343,3347,0,0,0,3348,0,0,3351,0,0,0,0
+,0,0,3354,0,0,0,0,0,0,0,0,0,0,3355,0,0,3365,3366,3367,0,0,0,0,0,0,3368,3369,0,
+3370,0,0,3373,0,0,3376,0,0,3377,0,3379,3387,0,0,0,0,0,3390,0,0,0,0,0,0,0,3402,0,
+3403,3436,3437,3439,0,0,3441,0,0,0,3442,0,0,3449,0,0,0,3450,0,0,0,0,0,0,0,3451,0
+,0,3452,0,3453,3456,0,3457,0,0,3458,0,3459,0,0,0,0,0,0,0,0,0,3460,0,0,3469,3470,
+0,0,3475,0,0,0,3480,3487,3489,0,3490,0,0,3491,3499,0,3500,0,0,3501,0,0,0,3502,0,
+3514,0,0,0,3516,3517,0,0,0,3518,0,0,0,0,3520,3521,3522,0,0,3526,3530,0,0,0,0,
+3531,0,0,0,0,3536,0,0,0,0,0,0,0,3539,3541,0,0,3542,3544,0,3547,3548,0,0,3550,0,
+3553,0,0,0,0,0,0,0,3554,0,3555,0,3558,0,3559,0,0,0,0,0,0,0,0,3563,0,3581,0,0,0,
+3599,0,0,0,3600,0,3601,0,3602,3603,0,0,3606,3608,0,3610,3611,0,0,0,0,0,0,0,0,0,
+3612,3616,3619,0,0,0,0,0,0,0,0,0,0,0,0,0,3624,3628,0,3629,3634,3635,0,0,0,0,0,0,
+3636,0,3637,0,0,3638,3651,0,0,0,0,0,0,3652,3653,0,0,0,0,3656,3657,0,0,0,0,0,3658
+,0,0,0,0,3659,0,3661,3663,3664,0,3665,0,3692,0,0,0,3694,3696,0,0,0,0,0,0,0,0,0,0
+,0,0,3698,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3700,0,0,3701,0,0,0,3708,3709,0,0,0,3711
+,3712,0,0,0,0,0,3723,0,3724,3725,0,0,3726,0,0,0,0,0,0,3728,3729,0,3734,3735,3737
+,0,0,0,3743,0,3745,0,0,3746,0,0,3747,3748,0,3757,0,3759,3766,3767,0,3768,0,0,0,0
+,3769,0,0,3771,0,3774,0,0,0,0,0,0,3775,0,0,0,0,0,0,3776,0,3777,3786,0,3788,3789,
+0,0,0,0,0,0,0,0,0,3791,0,3811,0,0,0,0,0,3814,3815,3816,3820,0,0,0,0,0,0,0,3821,0
+,0,3825,0,0,0,0,3835,0,0,3848,3849,0,0,0,0,3850,3851,3853,0,0,0,0,3859,0,3860,
+3862,0,0,0,0,0,3863,0,0,0,0,0,0,0,0,3873,0,3874,0,3875,3886,0,3887,0,0,0,0,3892,
+3913,0,3914,0,0,0,3925,3931,0,0,0,0,3934,3941,3942,0,0,0,0,3943,0,0,0,3944,0,0,0
+,0,0,3945,0,3947,0,0,0,3956,3957,0,0,0,0,0,0,0,0,0,3958,0,3959,3965,0,0,0,0,3966
+,0,0,0,3967,0,0,0,3968,3974,0,0,0,0,0,3975,3977,3978,0,0,0,0,3980,0,3985,0,0,0,0
+,0,0,0,0,3986,4011,0,0,4017,0,0,0,0,0,0,0,0,0,0,0,4018,0,0,0,0,4019,0,4023,0,0,0
+,4027,4028,0,0,0,0,0,0,0,0,4031,4034,0,0,4035,4037,4039,4040,0,0,0,0,0,4059,0,
+4060,4061,0,4062,4063,4066,0,0,4072,0,0,0,0,0,0,0,0,0,0,0,0,0,4088,0,0,0,0,0,
+4091,0,0,0,0,4094,4095,0,0,4096,0,0,0,0,0,4098,4099,0,0,0,4101,0,4104,0,0,0,4105
+,4108,0,4113,0,0,4115,4116,0,4126,0,0,4127,0,0,0,0,0,0,0,4128,4132,4133,0,4134,0
+,0,0,4137,0,0,4141,0,0,0,0,4144,4146,4147,0,0,0,0,4148,0,0,4311,0,0,0,4314,4329,
+0,4331,4332,0,4333,0,4334,0,0,0,4335,0,4336,0,0,0,4337,0,0,0,4342,4345,4346,4350
+,0,4351,4352,0,4354,4355,0,0,4364,0,0,0,0,4369,0,0,0,4373,0,4374,0,0,0,0,4377,0,
+0,0,0,4378,0,0,0,4380,0,0,0,4381,4382,0,0,0,0,0,0,0,4384,0,0,0,0,4385,0,0,0,4386
+,0,0,0,4391,4398,0,0,0,0,4407,4409,0,0,0,0,4410,0,0,4411,0,4414,4415,4418,0,4427
+,4428,4430,0,4431,0,4448,0,0,0,0,0,4449,0,0,0,4451,4452,0,4453,4454,0,4456,0,0,0
+,0,0,0,0,4459,0,4463,0,0,0,0,0,4466,0,4467,0,4469,0,0,0,0,0,0,0,0,0,0,0,0,0,4470
+,4471,0,4473,0,0,4475,0,0,0,0,4477,4478,0,0,0,4479,4481,0,4482,0,4484,0,0,0,0,0,
+0,0,4486,0,0,4488,0,0,4497,0,4508,0,0,4510,4511,0,4520,4523,0,4524,0,4525,0,4527
+,0,0,4528,0,0,0,0,4530,0,4531,0,0,4532,0,0,0,4533,0,0,0,0,0,4535,0,0,0,4536,0,0,
+0,0,0,4541,4543,4544,4545,4547,0,4548,0,0,0,0,4550,4551,0,4553,0,0,0,0,4562,0,0,
+4571,0,0,0,4574,0,0,0,4575,0,4576,0,4577,0,0,0,4581,0,0,0,0,0,4582,0,0,4586,0,0,
+0,4588,0,0,4597,0,4598,0,0,0,0,4616,4617,0,4618,0,0,0,0,4619,0,4620,0,0,4621,0,
+4624,0,0,0,0,0,4625,0,0,0,0,4657,0,4659,0,4667,0,0,0,4668,4670,0,4672,0,0,0,0,0,
+4673,4676,0,0,0,0,4687,0,0,0,0,4697,0,0,0,0,4699,0,4701,0,0,0,0,4702,0,0,4706,0,
+0,4713,0,0,0,4714,4715,4716,0,0,0,0,0,0,0,0,0,0,0,0,4717,0,0,4720,0,4721,4729,
+4735,0,0,0,4737,0,0,0,4739,0,0,0,4740,0,0,0,4741,0,0,0,0,0,4742,0,4745,4746,4747
+,0,0,0,0,0,0,0,0,4748,0,0,0,4749,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4751,
+4786,0,4787,0,4788,4796,0,0,4797,4798,0,4799,4806,4807,0,0,0,0,4809,4810,0,0,0,0
+,0,0,4811,0,0,0,0,0,4812,0,4813,0,0,4815,0,4821,4822,0,0,0,0,4823,0,0,0,0,0,0,0,
+0,0,0,4824,0,0,0,0,4826,0,0,0,4828,0,4829,0,0,0,4843,0,0,4847,0,4853,4855,4858,0
+,0,0,0,0,4859,0,4864,0,0,4879,0,0,0,0,4880,0,0,0,0,4881,0,4882,0,0,0,0,0,0,0,0,0
+,4883,0,0,0,0,4884,0,0,0,0,0,4886,4887,4888,4894,4896,0,4902,0,0,4905,0,0,4915,0
+,0,0,0,0,0,0,4916,4917,4919,4921,0,0,0,0,0,4926,0,0,0,0,4927,0,0,0,0,0,0,0,0,
+4929,0,4930,4931,0,4938,0,4952,0,4953,4957,4960,4964,0,0,0,0,0,0,0,5019,5020,
+5022,0,0,0,0,0,5023,0,0,0,5024,0,0,0,5025,0,0,0,0,5028,0,0,0,0,5029,5030,5031,0,
+5033,0,0,0,0,0,0,0,0,0,5034,5035,0,5036,0,0,5037,0,0,0,0,5038,0,0,5039,0,0,0,
+5041,5042,0,0,0,0,5044,5049,5054,0,5055,0,5057,0,0,0,5060,0,0,0,0,0,5063,0,5064,
+5065,0,5067,0,0,0,5068,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5076,0,0,0,0,0,0,
+0,5077,0,0,5078,5080,0,0,5083,0,0,0,0,0,0,0,0,5085,0,0,0,0,0,0,5098,5099,5101,
+5105,5107,0,5108,0,5109,0,0,0,0,0,0,0,5110,0,0,0,0,0,5117,5118,0,5121,0,5122,0,0
+,5130,0,0,0,5137,0,0,0,5148,0,0,0,0,0,0,0,5151,5154,0,0,0,5155,0,0,5156,5159,
+5161,0,0,0,0,5162,0,0,0,0,5163,5164,0,5166,0,0,0,0,0,0,0,0,0,0,5167,0,0,0,5172,0
+,0,0,0,0,0,5178,5179,0,0,5190,0,0,5191,5192,5194,0,0,5198,5201,0,0,0,0,0,5203,0,
+5206,5209,0,0,0,0,0,0,5213,0,5214,5216,0,0,0,0,0,5217,0,0,0,0,0,0,0,0,5218,5219,
+0,5231,0,0,5244,5249,0,5254,0,5255,0,0,5257,0,0,0,0,0,5258,0,5260,5270,0,5277,0,
+0,0,0,0,0,5280,5281,5282,5283,0,0,0,0,0,5284,0,5285,0,0,0,0,0,5287,5288,0,0,0,0,
+0,0,0,0,0,0,5289,5291,0,0,5294,0,0,5295,0,0,0,0,0,0,0,5304,0,0,5306,5307,5308,0,
+5309,0,0,5310,0,0,0,0,5311,5312,0,5313,0,0,0,0,0,5316,0,0,0,5317,0,0,0,0,0,0,0,0
+,0,5325,0,0,0,0,0,0,5326,0,5327,5329,0,5332,0,0,0,0,5338,0,0,0,0,0,0,0,0,5340,0,
+0,5341,0,0,0,5342,0,5343,5344,0,0,5345,0,0,0,0,0,0,5347,5348,0,0,0,0,0,0,0,0,0,
+5349,0,5350,0,5354,0,0,0,0,5358,0,0,5359,0,0,5361,0,0,5365,0,5367,0,5373,0,0,0,
+5379,0,0,0,5380,0,0,0,5382,0,5384,0,0,0,0,0,0,5385,0,0,0,0,5387,0,0,0,0,0,0,5388
+,5390,5393,0,0,0,0,0,0,0,0,0,0,0,5396,0,0,0,0,5397,5402,0,0,0,0,0,5403,0,0,0,
+5404,5405,0,0,0,0,0,0,0,0,0,0,0,0,5406,0,0,0,0,5410,0,0,5411,0,5415,0,0,0,0,5416
+,5434,0,0,0,0,0,0,0,0,0,0,0,5438,0,5440,0,0,0,0,0,0,5441,5442,0,0,0,5443,5444,
+5447,0,0,5448,5449,5451,0,0,0,5456,5457,0,0,0,5459,0,0,0,5461,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5464,0,5466,0,0,5467,0,5470,0,0,5473,0,0,5474,0,0,5476,0,0,0,0,0,0,0,0
+,0,0,0,5477,0,0,0,0,0,0,0,5484,0,0,5485,5486,0,0,0,0,0,5488,0,0,0,0,0,0,0,5489,0
+,0,0,0,0,5507,0,0,0,5510,0,5511,0,0,5512,0,0,0,5513,0,5515,0,0,5516,5517,0,5518,
+0,0,5522,0,0,0,0,0,5534,5535,0,0,5536,0,5538,0,0,5543,0,5544,0,0,5545,0,5547,0,
+5557,0,0,5558,0,5560,5567,0,0,0,0,5568,0,0,0,5571,5573,0,5574,0,5575,0,0,0,0,
+5577,0,0,5598,0,0,0,0,0,0,0,0,0,5600,5609,0,0,0,0,5610,0,0,5612,0,5624,0,5625,0,
+0,0,5629,0,5641,0,5642,5643,0,0,0,0,0,0,5651,0,0,0,5652,5653,0,5661,5662,5678,0,
+5679,0,0,0,0,5685,5686,0,0,0,0,0,5690,5692,0,5703,0,0,0,0,0,5706,0,0,0,0,5707,0,
+0,0,0,0,0,5708,0,0,5709,0,5710,0,0,0,5712,0,5733,0,5734,5735,0,0,5744,5751,0,0,0
+,0,0,0,0,0,0,0,0,0,5752,0,5754,0,0,0,0,0,0,5757,5758,0,5760,5761,0,0,0,0,5763,
+5764,5765,0,5766,0,5767,5768,0,5770,0,0,0,0,5776,5780,0,0,0,0,5782,0,0,0,0,5784,
+0,0,5788,0,0,0,0,0,0,0,0,0,0,0,5797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5799,0,0,5801,
+0,0,0,5811,0,0,0,0,0,0,5816,0,0,5827,0,0,0,0,0,0,0,0,5830,5831,0,0,5832,0,0,5833
+,0,5835,5844,5845,0,5846,0,0,0,0,0,5850,0,0,0,0,0,5852,0,5855,5857,0,0,5859,0,
+5861,0,0,5863,0,5865,0,0,0,5873,5875,0,0,0,5877,0,5879,0,0,0,5888,0,0,5889,5891,
+0,5894,0,0,0,0,0,0,5895,0,5897,0,0,0,0,0,0,5907,0,5911,0,0,5912,0,5913,5922,5924
+,0,5927,5928,0,0,0,0,5929,5930,0,5933,0,0,0,0,5949,0,0,5951,0,0,0,0,0,0,0,0,5953
+,0,0,5954,0,5959,5960,5961,0,5964,0,0,0,5976,5978,5987,5990,0,0,0,0,0,5991,0,
+5992,0,0,0,5994,5995,0,0,5996,0,0,6001,6003,0,0,0,0,6007,0,0,0,0,0,6008,0,0,6009
+,0,6010,0,0,0,6011,6015,0,6017,0,6019,0,6023,0,0,0,0,0,0,0,6025,0,0,0,0,0,0,0,0,
+0,0,6026,0,6030,0,0,6032,0,0,0,6033,6038,6040,0,0,0,6041,6045,0,0,6046,0,0,6053,
+0,0,6054,0,6055,0,0,0,0,0,0,6057,0,6063,0,0,0,6064,0,6066,6071,6072,0,0,0,0,0,0,
+6075,6076,0,0,6077,0,0,0,0,0,0,0,0,0,6078,6079,0,0,0,0,0,0,0,0,6080,0,6083,0,0,0
+,0,0,6084,0,0,6088,0,6089,0,0,6093,6105,0,0,6107,0,6110,0,0,0,6111,6125,6126,0,0
+,0,6129,0,0,0,0,6130,0,0,0,6131,6134,0,0,0,0,0,0,6142,0,0,0,0,0,6144,0,0,6146,
+6151,6153,0,6156,0,6163,0,6180,6181,0,0,0,0,0,6182,0,0,0,0,6184,6195,0,0,6206,0,
+6208,0,0,6212,6213,6214,0,6215,0,0,0,6228,0,0,0,6234,0,0,0,0,0,0,6235,6240,0,
+6242,6243,6244,0,6250,6255,0,0,0,0,0,6257,0,0,0,6258,6278,0,6284,0,0,0,6285,0,0,
+0,0,0,0,0,0,6286,0,0,0,6320,0,0,6322,6332,0,0,0,0,0,0,0,0,6334,0,0,0,0,0,0,0,
+6335,0,0,6337,0,6338,0,6339,6340,0,0,6356,6357,6369,0,0,0,6370,6371,6372,0,6373,
+0,0,0,0,0,6376,0,0,0,0,0,6382,6383,6384,0,0,0,0,6386,0,6389,6397,6400,6411,0,
+6414,0,0,0,0,0,0,0,6415,6416,0,0,0,0,0,0,6417,0,0,0,0,6418,0,0,0,0,0,0,0,6420,0,
+6421,6423,6425,0,6429,6430,0,6433,6438,0,0,0,0,0,0,0,0,0,0,6439,6440,0,0,6441,0,
+0,6444,0,0,0,0,6446,0,0,0,0,6447,6448,0,0,6450,0,0,0,6454,0,0,6455,0,6461,0,0,0,
+0,0,0,6462,0,0,6463,0,6464,0,6465,6467,0,0,0,6468,0,6479,6480,0,0,0,0,0,0,0,6481
+,0,0,6485,6487,0,0,0,0,0,0,6493,0,0,0,0,0,0,0,0,6494,6495,6496,0,0,0,0,0,6498,0,
+0,0,6507,6508,0,0,0,0,0,0,0,0,0,0,6511,6512,0,0,0,0,6513,0,0,0,6514,0,0,0,0,0,
+6516,0,0,6517,6518,0,0,0,6519,6520,6521,0,6523,0,0,0,0,6524,6528,0,6530,0,0,6532
+,0,6578,0,0,0,6583,0,6584,0,0,0,6587,0,0,0,6590,0,6591,0,0,0,0,0,6592,0,0,0,0,
+6593,6594,0,0,0,0,0,6599,6600,0,0,6601,6602,6604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6608,0,0,0,0,0,0,0,0,6610,6611,0,6615,0,6616,6618,6620,0,6637,0,0,0,0,6639,0,0,0
+,0,6641,0,6642,0,0,0,6647,0,6660,6663,0,6664,0,6666,6669,0,6675,6676,6677,0,0,0,
+0,0,0,0,0,0,6678,0,0,0,6679,0,6680,0,0,0,0,0,0,0,6693,0,0,0,0,0,0,0,0,0,6704,
+6705,6706,0,0,6711,6713,0,0,0,0,0,6716,0,0,0,6717,0,6719,6724,0,0,0,0,0,0,0,0,
+6725,6726,0,0,0,0,0,6728,6729,6735,0,6737,6742,0,0,6743,6750,0,6751,0,0,6752,
+6753,0,0,0,0,0,0,6754,0,0,0,0,0,6756,0,0,0,0,0,0,6763,0,0,6764,6765,0,0,0,6770,0
+,0,0,6776,6780,0,6781,0,0,0,6783,0,6784,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6785,0,0,0,6792,0,0,0,6793,0,0,6802,0,0,0,0,0,6803,0,0,0,6804,0,0,0,6812,0,0,
+6823,0,6824,6839,0,0,0,0,6852,0,0,6854,0,6856,6857,0,0,0,0,0,0,0,0,0,6867,0,6868
+,6870,6872,0,0,0,6873,6874,0,0,0,0,0,6875,0,0,6877,0,0,0,0,0,0,0,6878,0,0,0,6879
+,0,6880,0,0,0,0,0,0,0,0,0,0,6887,0,6888,6891,6893,0,6895,0,0,0,0,0,0,0,0,6899,0,
+0,0,0,6901,0,0,0,0,6910,0,6911,0,0,6912,0,0,6913,6914,0,0,0,6915,0,0,0,6916,6919
+,0,0,0,0,0,0,6924,0,6925,0,0,0,6926,6927,6928,0,6929,0,6930,0,0,6931,6935,0,6936
+,0,0,0,0,6939,6940,6941,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6942,6948,6949,0,0,0,0,0,0
+,0,6952,6954,6963,6965,6966,0,0,6967,6968,0,0,0,0,0,0,0,0,0,6969,0,0,6970,6979,0
+,0,6980,0,0,6983,0,0,0,0,0,6984,0,0,0,0,0,0,0,6988,6990,6992,0,0,0,0,0,0,0,6995,
+0,0,0,7012,0,0,0,0,0,0,0,0,0,7019,0,0,0,0,0,0,0,0,7021,0,0,7022,7023,7028,0,7030
+,7033,0,0,0,0,0,0,7038,0,0,0,0,0,0,0,0,0,0,7039,0,0,0,0,0,7046,0,7047,0,0,0,0,0,
+0,0,0,0,0,0,7048,7052,0,0,0,0,0,7054,0,7060,0,0,0,0,7061,0,7065,0,0,0,0,7067,
+7069,0,7070,7071,7072,0,0,7078,0,7080,7081,0,7083,0,0,0,7084,7087,7088,0,0,7090,
+0,7093,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7107,0,0,7108,0,0,0,0,0,0,0,0,7110,0,7114,0
+,0,0,0,0,0,0,7115,0,7116,0,0,0,0,0,7117,0,0,7118,0,0,7124,0,7125,0,0,7126,0,0,0,
+0,7128,0,0,0,0,0,7129,0,7130,0,7132,7133,0,0,7134,0,0,7139,0,7148,7150,0,0,0,0,
+7152,0,0,0,7153,7156,7157,0,0,0,0,0,7158,0,0,0,0,0,0,0,0,0,0,7163,7165,7169,0,
+7171,0,0,0,0,0,0,0,0,0,7172,0,7173,7181,0,0,0,0,0,7182,7185,0,0,0,0,7187,0,7201,
+7204,0,0,0,0,0,7206,7207,0,0,0,0,7211,7216,0,7218,0,0,0,0,7226,7228,7230,7232,
+7233,7235,7237,0,0,0,0,7238,7241,0,7242,0,0,7247,0,0,0,7266,0,0,0,0,0,0,0,7289,0
+,0,7290,7291,0,0,7292,0,7297,0,0,0,0,0,0,0,0,0,0,7300,0,7301,0,0,0,0,0,0,0,0,0,0
+,0,0,7302,0,0,0,0,7305,0,0,0,0,7307,0,7308,0,7310,0,7335,0,0,0,0,0,0,0,7337,0,
+7343,7347,0,0,0,0,0,7348,0,7349,7350,7352,7354,0,0,0,0,7357,0,7358,7366,0,7367,
+7368,0,0,7373,0,0,0,7374,0,0,0,0,0,0,0,7376,0,0,0,7377,0,0,0,0,0,7378,0,7379,
+7380,0,0,0,0,0,7383,0,0,7386,0,0,0,0,7398,0,0,0,7399,7400,0,7401,0,0,0,0,0,0,0,
+7402,0,0,0,0,0,7405,0,0,0,0,0,7406,0,0,0,0,0,0,0,0,7421,7427,7429,0,0,0,7435,0,0
+,7436,0,0,0,7437,0,0,0,0,0,0,7438,7443,0,7446,0,7448,0,0,0,0,0,0,0,0,0,0,7456,0,
+0,0,0,0,7457,0,0,7461,0,0,0,0,0,7462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7463,7466,7472,
+0,7476,0,0,7490,0,7491,0,0,7493,0,0,0,7498,7499,0,0,7508,0,0,0,0,0,7512,0,0,0,
+7513,7514,7516,0,0,0,0,7518,0,0,7519,7521,7522,0,0,0,7526,0,0,7529,0,0,7531,0,
+7536,0,7538,0,7539,0,0,7541,7542,7546,0,0,0,0,0,7547,0,7548,0,0,0,0,0,7550,0,0,
+7552,7553,0,0,0,0,0,0,0,0,0,0,7554,7563,0,7573,0,0,0,0,0,0,7574,7576,0,7578,7581
+,7583,0,0,0,7584,0,7587,0,0,0,0,0,7589,0,0,0,7594,0,0,7595,0,0,7600,7602,7610,0,
+0,0,0,0,7612,0,7613,7614,0,0,7615,0,0,7616,0,7620,0,7621,7622,0,7623,0,0,0,0,
+7626,0,0,0,0,7627,7629,7631,0,0,7633,0,0,0,0,0,7639,0,7640,7642,0,0,7643,0,0,0,0
+,7644,0,0,0,0,0,0,0,7645,0,0,0,0,0,7661,7662,7663,7665,0,7666,0,7667,0,7684,7688
+,7690,0,7691,0,0,0,0,0,0,7692,0,0,7700,0,7707,0,7708,0,7709,0,7721,0,0,0,7722,0,
+7724,0,0,0,0,0,0,7729,7731,0,7732,0,7733,7735,0,0,0,0,0,0,0,7739,0,0,7741,7745,0
+,7748,0,0,0,7751,0,0,0,7752,0,0,0,0,0,0,0,7753,0,0,7756,0,7757,0,7759,0,7760,0,0
+,0,0,7761,7768,0,0,7769,0,0,7770,0,0,7771,0,0,7772,0,0,7773,0,0,0,0,0,7778,7783,
+0,0,0,0,0,7784,7785,0,7790,0,0,0,0,7792,0,7798,0,0,0,0,0,7799,0,7810,0,0,7813,0,
+7814,0,7816,0,7818,7824,7825,7826,0,7828,7830,0,0,0,7840,0,7842,0,7843,0,0,0,0,
+7844,0,0,0,0,0,0,0,7846,0,0,0,0,0,7856,7857,7858,7862,0,7865,0,0,7866,0,0,7913,0
+,0,0,0,7914,0,0,7915,7917,7918,7919,0,7920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7921,
+7922,0,7924,0,0,7925,0,0,7927,0,7930,7935,0,0,7937,0,0,0,0,0,0,7939,0,7940,0,0,0
+,0,0,7941,0,0,0,0,7945,0,0,0,0,7949,0,0,0,0,0,0,0,0,7950,0,7953,0,0,0,0,0,0,0,
+7968,0,0,0,0,7969,7972,7992,0,7993,0,0,0,0,0,0,0,0,0,0,0,7994,0,0,0,0,8007,8008,
+0,0,0,0,0,0,0,0,0,0,0,0,8010,0,0,0,8012,0,0,0,0,0,0,0,0,8018,0,8028,8029,0,0,
+8030,0,0,8032,8033,0,0,8034,8036,0,0,0,0,0,0,0,0,0,0,8037,0,0,0,8043,8052,8059,
+8060,0,0,8061,0,0,0,8062,0,8063,0,8064,0,8066,8068,0,0,0,8080,8081,0,8089,0,0,0,
+0,0,8092,0,0,0,0,0,0,8093,8110,0,0,0,0,0,0,0,8111,0,0,0,0,0,8112,8115,0,8117,0,0
+,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8120,8121,8122,8128,8129,8130,8131,0,0,8139,0,0,
+8144,0,0,0,0,8145,8146,8153,0,0,0,0,0,0,0,0,8154,0,8157,8160,8162,0,8164,8165,0,
+0,0,0,8166,8167,0,0,8179,0,0,0,8185,0,0,0,8186,0,0,8187,0,0,0,8188,0,0,0,0,0,
+8204,0,0,0,0,8210,0,0,0,0,0,8213,0,8214,0,0,8215,0,0,0,0,0,0,8218,0,0,0,0,0,0,0,
+0,0,8219,0,8221,0,0,8222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8225,0,0,0,8233,0,0,
+8242,0,0,0,0,0,0,0,0,0,0,0,8247,0,8248,8252,0,8256,8257,0,0,8261,0,8264,8265,0,0
+,0,0,8267,0,0,0,8269,0,0,0,0,0,0,0,0,0,8270,0,0,0,8278,0,8279,8283,0,0,8285,8286
+,8289,8292,0,0,0,0,8293,8295,8299,8300,8301,0,0,0,0,0,0,8304,8307,0,0,0,0,0,0,0,
+8321,0,0,0,8322,8323,8325,8326,8327,0,0,8332,8338,0,0,8340,0,0,0,0,0,8350,0,0,
+8351,0,8354,8355,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8360,8372,0,0,0,0,0,0,0,0,8377,0,0,
+0,0,8380,0,0,0,8383,0,8384,0,0,0,0,8386,8392,0,0,8394,0,0,0,0,0,0,0,8396,8397,0,
+8398,0,8399,0,0,0,0,0,8400,0,8401,8410,8411,0,8412,8413,8422,0,0,0,0,8423,0,0,0,
+0,8424,0,0,8425,0,0,0,0,0,0,0,8441,8442,0,0,0,0,0,0,8443,0,0,8444,0,8447,0,0,0,0
+,8451,0,8458,0,8462,0,0,8468,0,8469,0,0,0,8470,0,8473,8479,8480,0,0,0,0,8481,
+8483,0,0,0,0,0,0,0,0,0,8484,0,0,8490,0,0,0,0,0,0,8491,8493,8494,0,8528,0,0,0,0,0
+,0,0,8530,0,0,0,0,0,0,0,0,8534,8538,8540,0,0,8541,0,0,8545,0,8557,0,0,8569,8570,
+0,0,8571,8574,8575,8579,0,8583,0,0,0,0,8591,0,0,0,0,0,0,0,0,8606,0,8607,0,0,0,0,
+0,0,0,0,0,8608,0,0,8609,0,0,0,8610,0,0,0,8611,0,0,8613,8617,8621,0,0,8622,0,8623
+,0,8624,8625,0,0,0,0,0,0,0,0,0,8637,8638,8639,8650,0,0,0,0,8652,8654,8655,0,0,0,
+0,0,0,0,0,0,0,8656,0,0,0,0,0,8657,0,0,0,0,0,0,0,0,0,8658,0,0,8659,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,8660,0,0,0,0,0,0,8661,8663,8664,0,0,0,0,8665,0,8669,0,
+0,0,0,0,0,0,8671,8674,0,8684,0,8686,0,0,0,8689,0,0,0,8690,0,8706,0,0,0,0,0,0,0,0
+,0,0,0,8710,0,8711,8713,8714,8724,8727,8728,8733,8736,0,8737,8739,0,0,0,0,8742,
+8743,8745,8754,0,0,0,0,8756,0,0,0,0,0,0,8757,8760,0,0,0,0,0,8762,8763,8764,0,
+8766,8769,8770,8773,0,8774,0,8779,0,0,0,0,8780,0,0,8781,0,0,8783,0,0,0,0,0,0,0,0
+,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8784,0,0,0,0,0,0,0,0,8785,0,0,0,0,8786,0,0,0,0,8788
+,8790,0,0,0,8803,0,8813,8814,0,0,0,0,0,8815,8816,0,0,0,0,8818,0,0,0,0,8822,8828,
+8829,0,8831,0,0,0,0,8833,0,0,0,8834,0,0,0,8835,0,8836,0,0,0,8837,0,0,0,0,0,0,
+8838,8839,0,0,0,0,0,0,0,0,0,0,0,8840,0,0,0,8841,0,8842,0,0,0,8846,0,0,0,0,0,0,0,
+8847,0,8848,0,0,8864,0,0,8866,0,0,8870,8872,0,0,8873,8874,0,0,0,0,0,0,8875,0,
+8876,0,0,0,0,8896,8900,0,0,0,0,8901,0,0,0,0,0,8904,0,8907,0,0,0,0,8911,8912,8913
+,0,0,0,8914,0,8915,0,0,0,0,0,0,0,0,0,0,0,0,8916,0,0,0,8929,0,0,0,0,0,0,0,0,0,0,
+8930,0,8932,0,8943,0,0,0,8945,8947,0,0,0,0,8949,0,8950,0,8954,8957,0,0,8970,0,0,
+0,0,8971,0,8996,0,0,0,0,8997,9000,0,0,0,0,9001,9002,0,9004,9009,9024,0,0,0,0,0,0
+,0,0,0,0,0,0,9027,9082,0,0,9083,9089,0,0,0,0,0,0,9090,0,0,0,9092,0,0,9093,0,9095
+,0,0,9096,9097,9101,9102,0,0,0,0,0,0,0,0,9112,0,0,0,0,0,0,9114,0,0,9120,0,9121,
+9122,0,0,0,9123,9124,0,0,9125,0,0,9126,0,9127,0,0,9129,9131,0,0,0,9132,0,0,9136,
+0,9144,0,0,9148,0,0,0,0,0,0,9149,0,9152,9163,0,0,9165,0,0,0,0,0,0,0,0,0,0,0,0,0,
+9166,0,9169,0,0,0,0,0,0,0,9170,0,0,0,0,9172,0,9174,9175,9176,0,9177,0,0,0,0,0,0,
+0,0,9186,0,9187,0,0,0,9188,9189,0,0,9190,0,0,0,0,9191,0,0,0,9193,0,0,0,0,9197,
+9198,0,0,0,9208,9211,0,0,0,0,9216,9217,0,9220,0,0,0,0,9221,9222,9223,0,9224,9225
+,0,0,9227,0,9228,9229,0,0,9230,0,9232,0,9233,0,0,0,0,0,9234,9235,0,0,9237,0,0,0,
+0,0,0,0,0,9238,9240,0,0,9241,0,0,0,0,9244,0,0,0,0,9247,0,0,0,0,0,0,0,0,0,0,9248,
+0,0,0,9249,0,0,0,0,0,9250,0,0,0,0,9251,0,0,9252,9255,0,0,0,9256,0,0,0,0,0,0,0,
+9257,0,0,9258,0,0,0,0,0,0,9259,0,0,0,0,0,9262,9263,0,0,9265,9266,0,0,0,0,0,0,0,0
+,9268,9271,0,0,0,0,0,0,0,0,0,9273,0,0,0,9276,9277,9279,0,0,0,0,0,0,0,9280,0,0,
+9293,0,0,0,0,0,9297,9301,0,0,0,0,0,0,0,0,0,0,0,9308,9309,9313,9321,9322,0,9326,
+9327,0,0,9477,0,9479,0,0,0,0,9482,0,0,0,9483,0,9484,0,0,0,0,0,0,0,0,0,9485,0,0,
+9486,0,0,0,9489,0,0,0,0,9490,9491,0,0,0,0,9493,0,9495,9496,0,0,0,0,0,0,0,0,9500,
+0,9502,0,0,0,0,0,9504,9507,0,9509,0,9511,0,0,9513,0,0,0,0,0,0,0,0,9515,0,0,0,0,0
+,0,9516,9517,0,0,0,0,9532,0,0,9533,0,0,9538,0,9539,9540,0,0,0,0,9541,0,0,0,9542,
+0,0,0,0,0,0,0,0,9544,9545,0,9546,0,0,0,0,0,0,9547,9548,0,0,0,9550,0,9557,0,9558,
+0,9561,0,9563,9570,0,9572,9574,9575,0,0,0,9577,9592,0,0,9596,0,0,0,9598,0,9600,0
+,9601,0,0,0,0,0,0,9608,0,9638,9639,0,0,0,0,0,0,0,9641,0,0,9643,9644,9645,9646,0,
+0,0,9648,0,0,0,0,0,0,0,9650,9654,0,0,0,0,0,0,0,0,9655,0,0,0,0,0,9656,0,9657,0,0,
+0,0,9658,0,0,9659,0,0,9664,0,0,9665,0,9667,9669,0,0,0,0,0,0,0,0,0,0,0,0,9671,0,
+9673,9681,0,0,0,0,9682,9683,9684,0,0,0,0,9686,9698,0,0,9700,9701,9702,0,9703,
+9717,0,0,0,0,9718,0,9726,0,0,0,0,9727,0,0,0,9728,0,9742,0,9744,0,0,0,9750,0,9754
+,9755,0,0,0,0,0,9756,0,9757,9768,0,9769,0,0,0,9770,9771,0,9773,0,9774,0,9775,0,0
+,0,9776,9777,9784,0,0,0,9786,0,9789,0,0,0,0,9793,9794,0,0,0,9808,0,0,0,0,0,9811,
+0,0,0,0,0,0,0,0,0,0,0,0,9812,0,9820,0,9823,0,9828,0,0,0,0,9830,0,0,9833,9836,0,0
+,0,9840,0,0,0,9841,0,0,9842,0,9845,0,0,0,9847,9848,0,0,9855,0,0,0,0,0,0,9856,
+9863,9865,0,0,0,0,0,0,0,0,9866,9867,9868,9873,9875,0,0,0,0,0,0,9880,0,9886,0,0,0
+,9887,0,0,9891,0,0,0,0,0,0,0,9906,9907,9908,0,0,0,9909,0,0,0,0,0,0,9910,0,0,0,0,
+9913,0,0,0,0,9914,0,0,0,0,0,9922,0,0,0,0,9923,9925,0,0,0,0,0,0,9930,0,0,0,9931,0
+,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9932,0,9939,0,0,9940,9962,9966,0,9969,9970,0,0,9974
+,0,9979,9981,9982,0,0,0,9985,0,0,0,0,0,0,9987,0,0,0,0,0,0,0,9988,9993,0,0,9994,0
+,0,0,9997,0,10004,0,0,0,0,0,10007,10019,10020,10022,0,0,0,10031,0,0,0,0,0,10032,
+0,0,10034,0,10036,0,0,0,0,10038,0,10039,10040,10041,10042,0,0,0,0,0,10043,0,0,0,
+0,0,10045,10054,0,0,0,0,10055,0,0,10057,10058,0,0,0,0,0,0,10059,0,0,0,0,0,0,0,
+10060,0,0,0,0,0,0,0,10063,0,10066,0,0,0,10070,0,10072,0,0,10076,10077,0,0,10084,
+0,10087,10090,10091,0,0,0,10094,10097,0,0,0,0,0,0,10098,0,0,0,0,0,0,10103,0,
+10104,0,10108,0,0,0,0,0,0,0,0,10120,0,0,0,10122,0,0,10125,0,0,0,0,10127,10128,0,
+0,10134,0,10135,10136,0,10137,0,0,10147,0,10149,10150,0,0,10156,0,10158,10159,
+10160,10168,0,0,10171,0,10173,0,0,0,10176,0,0,0,0,10177,0,0,0,0,10178,0,0,0,0,
+10194,0,10202,0,0,10203,10204,0,10205,10206,0,10207,0,0,0,0,10209,0,0,0,0,0,0,0,
+10213,0,0,0,0,0,0,10217,0,10229,0,10230,10231,0,0,10232,0,0,10237,10238,10244,0,
+0,0,0,0,10250,0,10252,0,0,0,0,0,0,10255,0,0,10257,0,0,0,0,0,0,10258,0,10259,0,0,
+0,0,0,0,0,0,10260,0,0,0,0,0,0,0,10284,10288,10289,0,0,0,10290,0,10296,0,0,0,0,0,
+10297,0,0,0,0,0,0,10298,0,0,0,0,10299,10303,0,0,0,0,0,10306,0,0,0,10307,0,10308,
+0,0,0,0,10311,0,0,0,0,0,0,0,10315,10317,0,0,0,10318,10319,0,10321,0,10326,0,
+10328,0,0,0,0,10329,0,0,10331,0,10332,0,0,0,0,0,0,10334,0,0,10335,10338,0,0,0,0,
+0,10339,10349,0,0,0,0,0,0,10351,0,10353,0,0,0,0,0,0,10362,0,10368,0,10369,0,0,0,
+10372,10373,0,0,0,0,0,10374,0,0,0,10375,0,10376,0,0,10386,10388,10390,0,0,0,0,0,
+0,0,10391,0,0,10392,10394,0,0,10396,0,10397,0,10403,0,0,0,0,0,0,0,0,10404,0,
+10405,10410,0,0,10411,0,10412,0,0,0,0,0,0,0,10421,10422,10423,0,0,0,0,0,0,0,0,0,
+10425,0,0,10427,0,0,10430,0,0,0,0,0,10432,0,10433,10434,0,0,0,0,10436,10437,0,
+10438,0,10439,0,10444,10446,0,0,0,0,0,10448,0,0,0,0,0,10449,0,0,0,0,0,0,0,10451,
+0,10453,0,0,0,10454,10457,0,0,10459,0,10469,0,0,0,0,0,10472,10481,0,0,0,0,0,
+10482,10483,0,10492,0,0,0,0,0,0,0,0,0,0,10499,0,0,0,10502,0,0,10510,0,10521,
+10524,0,0,10525,10526,10528,0,0,0,0,0,0,0,0,10530,0,0,0,0,10533,0,10534,0,0,0,0,
+0,0,0,0,0,0,10535,10536,0,0,10544,0,10553,10556,0,10557,10559,0,0,0,0,0,10562,
+10563,10564,0,10565,0,0,0,10566,0,10567,0,0,0,0,10575,0,0,10576,0,10578,0,0,0,0,
+0,0,0,0,0,0,10585,10586,10587,10589,0,10590,0,0,10594,0,0,0,0,0,10598,0,0,10601,
+0,0,0,10602,0,10603,0,10604,0,10605,0,0,10607,0,10626,0,10627,0,0,0,0,0,10629,
+10630,10631,0,0,0,10646,0,0,0,10647,0,10650,0,10651,0,0,0,10652,10653,10655,0,
+10658,0,0,10659,0,10667,0,0,0,0,10669,0,0,0,0,0,0,0,0,0,10670,0,0,0,10671,0,0,0,
+0,10672,10673,0,10674,0,0,0,10676,0,0,0,0,0,0,10678,0,10682,0,0,10692,0,10697,0,
+0,0,0,10698,0,0,0,10700,0,0,0,0,0,10703,0,10704,0,0,0,0,0,0,0,10705,0,10715,
+10718,10720,0,0,10722,0,0,0,0,0,0,0,0,10723,0,0,0,0,10726,0,0,0,0,0,10727,10730,
+10743,0,0,0,0,0,0,10744,0,0,10745,0,0,0,0,0,0,10748,0,0,0,0,10750,0,0,10752,
+10753,0,0,0,10756,0,0,0,0,0,0,10758,0,0,0,10759,0,10769,0,0,10772,0,0,0,0,0,0,
+10773,0,0,0,10777,0,0,10779,0,0,0,0,0,0,0,0,10780,10784,0,0,0,10789,0,0,0,10791,
+0,0,0,0,0,0,0,0,0,10795,0,0,10796,0,10808,0,10809,0,0,0,10810,0,0,0,10812,0,0,
+10814,0,0,0,0,0,0,0,0,0,10815,0,0,0,0,10816,10817,0,0,0,0,10819,0,10820,0,0,0,0,
+10821,10822,10823,0,10826,10849,0,0,0,0,10850,0,0,10852,0,10853,0,0,10856,0,0,
+10857,10858,10859,10860,0,0,0,0,0,0,10863,0,10866,10867,10872,10890,0,0,10891,
+10892,0,0,0,0,0,10893,0,0,0,10896,10899,0,0,10900,10902,0,0,0,0,0,10903,0,0,0,0,
+0,0,0,0,0,0,0,0,10905,0,10906,0,0,0,0,10908,10911,0,10912,0,0,10916,0,0,0,0,0,
+10917,0,10918,0,0,0,10923,0,0,0,0,0,10924,0,0,10928,10929,0,0,10930,0,0,0,10932,
+0,0,0,0,10939,0,0,10945,0,0,0,10947,0,0,10948,0,0,0,0,0,0,0,0,0,0,0,0,10958,0,
+10960,10962,0,0,10964,0,0,0,10966,0,0,0,0,0,0,0,0,0,0,10967,0,0,0,10968,0,0,0,
+10973,0,0,0,0,0,10975,0,0,0,10976,10978,0,0,10982,10984,10987,0,0,10988,0,10989,
+0,0,10991,0,0,0,0,10992,0,0,0,10993,0,10995,0,0,0,10996,10997,0,0,0,10998,0,
+10999,0,11001,0,0,0,0,0,0,11010,11012,0,11013,11016,11017,0,0,11019,11020,11021,
+0,0,0,0,0,0,0,0,0,0,0,0,11022,0,0,11023,11029,0,0,0,0,11031,0,0,0,11034,0,0,0,0,
+11055,0,0,0,0,0,11056,11060,0,0,0,0,0,0,11061,0,0,11064,11065,0,11066,0,11069,0,
+11085,0,0,0,0,0,11086,0,0,0,11088,0,0,0,11094,0,0,0,11095,11096,0,0,0,0,0,0,
+11097,11098,0,0,0,0,0,0,11099,0,0,11102,11108,0,0,0,11109,0,11114,11119,0,11131,
+0,0,0,11142,0,0,11143,0,11146,0,11147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11148,0,
+11149,11152,11153,11154,0,11156,0,11157,0,0,0,11158,0,0,11159,11160,0,0,0,0,0,0,
+0,0,0,0,0,0,11163,0,0,11164,11166,0,0,0,11172,11174,0,0,0,11176,0,0,0,0,0,11182,
+11183,0,0,0,11184,11187,0,0,11188,11189,0,0,0,0,0,0,11194,0,0,0,0,0,0,0,11200,
+11202,0,0,0,0,0,0,11203,0,11204,0,0,0,0,0,11205,0,0,0,11206,0,11207,0,0,11209,0,
+11211,0,11214,0,0,11231,0,0,0,11293,11295,0,0,11296,11297,11302,0,0,0,11307,0,0,
+0,0,11309,11310,0,11311,0,0,0,11313,0,11314,0,0,0,0,11334,0,11338,0,0,0,11339,0,
+0,0,0,0,11340,0,11341,11342,0,11344,0,11345,0,0,0,11348,11349,0,0,11350,0,0,0,
+11355,0,0,0,0,0,0,11356,0,11357,11370,0,0,11371,0,11374,11376,0,0,0,11377,0,0,
+11378,11383,0,11386,11399,0,11400,11406,0,0,0,11408,0,0,11409,11412,0,0,0,0,
+11417,0,0,0,11418,0,11421,0,11426,11429,0,0,0,0,0,11430,0,11437,0,11438,0,0,0,0,
+0,11440,11453,0,0,0,0,0,0,11454,0,0,0,0,11455,0,0,11456,11460,11461,11463,0,
+11469,0,11473,0,0,0,0,11474,0,0,0,11475,0,11476,11477,11480,0,0,0,0,11481,0,0,
+11484,0,0,11487,0,0,0,0,0,0,0,0,0,0,11497,0,0,11502,0,11509,0,0,11510,11511,
+11513,0,0,0,0,0,0,0,0,0,0,11515,0,0,0,0,11516,0,11520,11521,0,0,0,0,0,0,0,0,0,0,
+0,11529,11530,11531,11534,0,0,11543,0,0,0,0,0,11547,0,11548,0,0,0,0,0,11552,
+11556,0,11557,0,0,11559,0,11560,0,0,0,0,0,0,11561,0,0,11563,11564,0,11565,0,0,0,
+0,11567,0,0,0,11569,0,11574,0,11575,0,0,0,11577,0,11578,0,0,0,11580,11581,0,0,0,
+11582,11584,0,0,0,0,0,0,0,11587,0,11588,11591,0,11595,0,0,0,0,0,0,0,0,11596,0,
+11597,0,0,0,0,11598,11601,0,0,0,11602,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11603,
+11604,0,11606,0,0,11608,0,0,0,0,11610,0,0,11611,0,0,0,0,11613,0,11622,0,0,0,
+11623,0,0,0,0,11625,0,0,11626,11627,11628,11630,0,0,0,0,0,0,11639,0,0,11646,0,
+11648,11649,0,11650,0,0,0,0,0,0,0,0,0,11651,0,0,11652,11653,11656,0,0,11677,
+11679,0,0,0,0,11680,0,0,11681,0,11685,0,0,0,0,0,0,0,0,11688,0,0,0,11716,0,11719,
+0,0,0,0,0,11721,0,0,11724,11743,0,0,0,0,0,0,0,0,11745,11748,11750,0,0,0,0,0,
+11751,0,0,0,11752,11754,0,11755,0,0,0,0,0,0,0,11759,0,0,0,0,0,0,11760,0,0,0,
+11761,0,0,0,0,0,0,11766,11767,0,11772,11773,0,11774,0,0,11775,0,11777,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,11778,11780,0,0,0,0,0,0,0,11783,0,11784,0,0,0,11785,
+0,0,0,11786,0,0,0,0,11788,0,0,11789,11791,11792,0,0,0,0,11795,11834,11835,11836,
+0,0,11837,0,0,0,11838,0,0,11846,11851,0,11852,0,11869,0,0,0,11871,0,0,0,11872,
+11874,0,0,0,0,0,0,11875,0,11876,11877,0,0,0,0,0,0,0,0,0,0,11883,0,0,0,0,0,0,0,
+11884,0,11885,0,11886,0,0,11887,0,11894,11895,11897,11909,11910,0,11912,11918,0,
+0,11920,0,11922,11924,11927,11928,0,0,0,0,11929,0,11934,0,0,0,0,0,11941,11943,
+11944,0,11945,0,0,0,0,11948,11949,0,0,0,0,11953,0,11954,0,11955,0,11956,0,0,0,0,
+0,11957,0,0,11959,0,0,0,0,0,0,0,0,11961,0,0,0,0,0,11978,0,0,0,11979,11980,11986,
+11987,0,11992,0,0,0,0,0,11993,0,0,0,11994,0,11999,12004,12005,12006,0,0,0,0,0,
+12011,0,0,12012,12014,0,0,12015,0,0,12019,12028,0,0,12029,0,0,12032,12033,0,0,0,
+0,12034,0,12041,12043,0,0,12044,0,0,0,0,0,0,0,12046,0,0,0,0,0,0,0,12054,12055,0,
+12056,0,0,0,12060,12064,0,0,0,0,0,12065,12067,12068,0,0,0,0,0,0,0,0,12074,0,0,0,
+12075,12076,0,0,0,12079,0,12081,12086,12087,0,0,12088,0,0,0,0,12089,0,12092,0,0,
+0,0,12097,0,0,0,0,0,0,0,0,12098,0,0,0,0,0,0,0,0,0,0,0,0,0,12102,12103,12104,
+12111,0,0,12114,12116,0,0,0,12118,0,0,0,12119,12120,12128,0,0,0,0,12130,0,0,0,0,
+0,0,12131,0,0,0,12132,12134,0,0,0,0,12137,0,12139,0,12141,0,0,12142,0,0,0,12144,
+0,0,0,0,0,12145,0,12148,0,12153,0,0,0,0,12154,12171,12173,0,0,0,12175,0,0,0,0,
+12178,0,0,0,0,0,0,0,12183,0,0,0,0,0,0,0,0,12184,0,0,0,12186,0,0,0,0,0,12187,
+12188,0,0,12189,0,12196,0,12197,0,0,12198,0,12201,0,0,0,0,12203,0,12209,0,0,0,0,
+12210,12211,12212,12213,0,12217,12218,0,0,0,0,0,0,0,0,0,12222,0,0,0,0,0,0,0,
+12223,0,0,12229,0,0,0,0,12233,0,0,0,0,12234,0,0,12236,12242,0,0,0,12243,0,0,0,
+12244,12253,0,12254,12256,0,12257,0,0,12275,0,0,0,0,0,12277,0,0,0,0,0,12278,0,
+12289,0,0,12290,0,12292,12293,0,0,12294,0,12295,0,0,12296,0,12297,0,12298,0,0,0,
+0,12301,0,0,0,0,0,0,0,0,0,0,0,0,0,12309,0,12338,12340,0,0,0,0,12341,0,0,0,0,0,0,
+0,0,12342,12343,0,12344,0,0,0,0,0,0,0,0,0,12345,0,0,0,0,0,0,0,0,12346,0,0,0,0,
+12348,0,0,0,0,0,0,0,0,0,0,0,0,12350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12351,0,12355,
+12356,12357,0,0,12367,12370,12371,0,0,0,0,0,12372,12376,0,0,0,0,0,0,0,0,12379,0,
+12382,0,12383,0,0,12384,0,0,0,0,12393,0,0,12394,0,0,0,0,12398,12403,0,0,12404,0,
+0,0,0,0,0,0,0,0,0,0,0,0,12410,0,0,0,12411,0,0,0,12412,0,0,0,0,12420,0,12421,0,0,
+0,0,0,12423,0,12425,12429,0,0,0,12431,12432,0,0,0,0,0,0,0,0,0,0,0,0,12434,0,0,0,
+0,0,12435,12436,0,0,0,0,0,0,0,0,12437,0,0,0,0,0,12438,0,0,0,0,0,0,0,0,12445,0,0,
+0,12450,12451,0,0,0,0,0,0,0,0,12452,12475,0,0,12493,12494,0,0,0,12495,0,0,0,0,
+12496,12502,12509,0,0,0,0,12510,0,12512,12513,0,0,0,0,12514,0,0,0,12515,0,12520,
+0,0,0,12524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12527,0,0,0,12528,0,0,0,12529,0,0,0,
+0,0,12530,0,12535,0,0,12536,0,12538,0,0,0,0,0,0,0,0,0,0,0,0,12540,0,12548,0,0,0,
+0,0,12550,0,0,0,12551,12552,0,0,0,12554,0,0,0,0,0,0,0,0,12555,0,0,12562,0,12565,
+0,12566,0,0,0,0,0,0,0,0,0,0,0,0,12569,0,0,0,12571,12574,0,0,0,0,0,0,0,12577,0,0,
+0,0,0,0,0,12578,12579,12603,0,12608,0,0,12611,0,12612,0,12615,0,12625,0,0,0,0,
+12627,12646,0,12648,0,0,12657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12670,0,0,12671,0,
+12673,12677,0,0,0,0,0,0,0,0,0,0,0,12679,0,12681,0,12682,12693,0,12694,0,12697,0,
+12701,0,0,0,12703,12704,0,0,0,0,12707,12737,0,0,12739,0,0,12740,0,0,12742,12743,
+0,0,0,0,0,0,0,0,0,12745,0,12746,12747,0,12748,0,0,12759,12767,0,0,0,0,12773,0,
+12774,12778,0,0,0,0,0,0,0,12779,0,0,0,0,0,12780,12793,0,12824,0,12825,0,12836,0,
+0,0,0,12839,0,12842,0,0,0,0,0,0,0,0,0,0,0,0,12843,12845,0,12846,0,0,0,0,12847,0,
+0,12850,12852,12853,0,0,0,12854,0,0,0,12855,0,12856,0,12858,0,0,12859,0,12862,0,
+12863,0,0,12866,0,12869,12872,12873,0,0,0,0,0,0,0,0,0,12875,0,12877,0,0,12878,0,
+0,0,0,0,0,0,0,0,12884,12885,12888,0,12889,0,0,0,0,12893,0,0,0,12895,12896,12898,
+0,0,0,0,0,0,0,12902,0,12909,12910,0,12926,0,12928,0,0,0,12929,0,12930,0,0,0,0,
+12931,0,12932,12933,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12934,0,12942,0,0,0,0,12944,
+0,0,0,0,0,0,0,0,12946,0,0,12948,0,0,12949,0,0,0,0,12950,0,0,0,0,12951,0,12952,0,
+12953,0,0,0,12954,12958,12959,0,0,0,0,0,12960,12964,0,0,0,0,0,12966,0,0,0,0,0,0,
+0,0,12970,0,12971,0,0,0,0,0,0,12972,0,0,12982,0,0,0,12984,12985,0,12986,12996,
+12997,13001,13002,0,0,0,0,13004,0,0,13005,0,0,13007,13009,0,13017,0,0,0,13020,0,
+13021,0,0,0,0,0,0,0,0,0,0,13022,0,0,0,0,0,0,0,0,13024,13027,0,0,0,0,0,13028,0,0,
+13029,0,0,0,0,0,0,0,13032,0,13037,0,0,0,0,0,0,13040,0,0,13041,0,0,0,13043,13044,
+13046,0,0,0,0,13047,0,0,0,0,0,0,0,13049,13054,0,13056,0,0,13060,13061,0,0,0,0,0,
+13067,0,0,13068,0,13071,0,0,0,0,0,13077,13078,0,0,0,0,0,13079,13080,13081,0,
+13082,0,0,0,13085,0,0,0,0,0,0,0,13086,0,13087,13088,0,0,0,0,0,13094,0,13099,0,
+13100,0,0,0,13101,0,13125,13126,13128,13129,0,0,13130,0,13131,0,0,0,0,0,0,13134,
+0,0,0,0,0,0,0,0,0,0,0,13150,0,13168,0,0,0,0,0,0,0,0,0,13169,0,0,13170,0,0,0,0,
+13174,0,0,0,13176,0,0,0,0,0,13177,0,13178,13183,13187,0,0,0,13189,0,0,13190,0,0,
+13191,0,0,13206,0,0,0,13207,0,0,0,0,0,0,0,0,0,0,13212,0,0,13219,13232,0,0,0,
+13241,0,13249,13253,0,0,0,0,0,13255,13259,0,13260,13261,0,13262,0,13272,0,0,0,0,
+13276,0,0,0,0,13277,13299,0,0,13301,13302,0,0,13303,0,0,13305,0,13310,0,0,0,
+13311,0,0,0,0,13325,0,13328,0,0,0,13329,0,0,0,0,0,0,13330,0,0,13331,0,13335,0,0,
+13342,0,0,0,0,0,13343,0,13354,0,13362,0,13366,13367,13369,0,0,13371,13372,0,
+13373,13374,0,13376,0,13380,13381,13386,0,13387,13388,0,13389,13391,13395,0,0,0,
+0,0,13401,13409,0,13410,0,0,0,0,13420,0,0,0,0,0,13422,0,0,0,0,13423,0,0,0,0,
+13425,0,0,0,0,0,13427,0,0,0,13428,0,0,13430,13438,0,13439,0,13445,0,13448,13449,
+0,0,0,0,0,0,13451,0,13457,0,0,0,0,13458,13459,0,13460,0,0,0,0,13464,13465,13466,
+13470,0,13471,13472,13474,13475,0,13476,0,0,13478,13479,0,13481,0,0,0,0,13487,0,
+13490,0,13493,0,0,13494,0,0,13495,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13496,13497,0,
+13500,0,0,13516,13522,0,0,13525,13528,0,0,0,13530,13535,0,13537,13539,0,13540,0,
+13543,0,13544,0,0,0,0,0,0,13545,0,0,0,0,0,0,13547,0,0,0,13549,13555,0,0,0,13556,
+13557,0,0,0,0,0,0,0,13558,0,13563,0,0,0,0,13564,0,0,0,0,0,0,0,0,13566,0,0,0,0,0,
+0,13569,0,0,13571,0,0,0,0,13573,0,0,0,0,0,0,13578,0,0,0,0,0,0,0,0,0,0,13581,0,
+13586,0,13595,0,13600,0,0,0,0,0,0,0,0,13601,13603,0,13604,13605,13606,13607,0,0,
+13617,13618,0,0,0,0,0,0,0,13623,0,13625,13627,0,0,0,0,0,0,0,0,13629,0,0,0,13634,
+0,0,0,13638,0,0,0,0,0,0,0,0,13654,0,0,0,0,0,0,0,0,0,0,13656,0,13659,0,0,13660,0,
+0,13662,0,0,0,13663,0,13664,0,0,0,0,0,13668,0,13669,13671,0,0,13672,0,0,0,0,0,0,
+13675,13685,0,13686,0,0,0,13687,0,0,0,13692,13694,13697,0,0,0,13702,0,0,0,0,0,
+13705,0,0,0,0,13707,0,0,0,13714,0,0,0,0,0,0,0,0,0,13715,0,13716,13717,0,0,13719,
+13724,13730,13731,0,0,0,0,0,0,0,0,13732,0,0,0,0,0,0,0,13734,0,13736,0,0,13737,
+13738,13747,0,13751,0,0,13752,0,0,0,13753,0,13757,0,0,13762,13763,0,13764,13765,
+0,13766,0,0,13767,0,0,0,13768,0,0,0,0,0,0,0,13769,0,0,13772,0,13775,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,13776,13778,13787,0,0,0,13797,0,13798,0,13801,0,13804,
+13806,0,0,0,0,13816,13817,0,0,0,0,0,0,0,0,0,0,0,0,0,13834,0,13836,0,0,13838,0,0,
+13839,0,13840,0,0,0,0,13842,0,0,0,0,0,0,13843,0,0,0,0,0,0,0,0,0,13845,0,0,0,0,0,
+13858,0,0,13860,0,0,13861,0,0,13862,13863,0,13868,0,13869,13870,0,0,0,0,0,0,0,0,
+0,0,13872,0,0,0,0,13873,13878,0,0,0,0,0,0,0,0,0,0,13886,0,13888,13889,13890,0,0,
+13891,13894,0,13897,13899,13900,13904,0,0,13906,0,0,0,13909,0,0,0,13910,0,0,0,
+13911,0,0,0,0,0,13912,13917,0,0,0,0,13918,0,13919,0,0,13920,0,0,0,13921,0,0,
+13922,0,0,0,0,0,0,0,13924,0,13927,0,0,0,0,0,13932,0,13933,0,13934,0,0,13935,0,
+13944,0,0,0,13954,0,0,13955,0,0,0,0,13956,0,13957,0,13967,13969,0,0,0,0,0,0,0,0,
+0,0,0,0,13970,13990,0,13991,13994,0,13995,0,0,0,0,13996,0,0,13999,0,0,0,14018,0,
+14019,0,14021,0,0,0,0,0,0,14041,0,0,0,0,0,0,0,0,14043,0,0,0,0,14046,0,0,0,14048,
+14049,0,0,0,0,0,0,0,0,0,0,14051,0,0,14052,14056,0,14063,0,14064,14066,0,0,14067,
+0,0,0,0,0,0,0,0,0,14068,0,0,0,14072,0,14074,14075,0,14076,14079,14085,14086,
+14087,14093,0,0,0,0,14095,0,0,0,0,0,0,14096,14097,0,0,0,0,0,0,0,14098,0,14102,0,
+0,0,0,0,14103,0,0,0,14104,0,0,14105,0,0,0,14107,14108,0,0,14109,0,0,0,0,0,0,0,0,
+14117,0,0,0,0,14118,0,0,0,0,14119,0,0,14120,0,0,14121,0,14122,14127,0,14128,
+14136,0,0,14138,0,14140,0,0,0,14141,14142,0,0,0,0,14146,0,0,14149,0,14151,0,0,0,
+14152,0,0,14153,0,0,0,0,0,0,0,0,0,14154,0,14156,14157,0,0,14159,0,14161,0,0,0,0,
+14162,0,0,0,0,0,0,14163,0,0,14173,0,0,0,0,0,0,14174,0,0,14176,0,0,14178,0,0,
+14179,14181,0,0,14182,14185,14187,0,14190,0,0,14197,0,0,0,0,0,0,0,0,0,0,0,0,
+14198,0,0,0,0,0,0,14199,14200,0,0,0,14204,0,0,14208,0,0,0,0,0,0,0,0,0,0,0,14231,
+0,0,0,0,0,0,0,0,0,14234,0,0,14235,0,0,0,14240,14241,0,0,0,14246,0,0,0,14247,0,
+14250,0,0,14251,0,0,14254,0,0,14256,0,0,0,14260,0,14261,0,0,0,0,14262,14267,
+14269,0,0,14277,0,0,14278,0,14279,14282,0,0,0,14283,0,0,0,14284,14285,0,0,0,0,
+14286,0,0,0,14288,0,0,0,14289,0,14290,0,14293,14301,14302,14304,14305,0,14307,0,
+14308,14309,0,0,0,0,0,0,0,0,0,0,0,14311,14312,0,0,14317,0,0,0,0,0,0,0,14318,0,0,
+0,0,14320,0,0,0,0,14321,14322,0,0,0,0,0,14326,14329,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+14330,14331,0,0,0,0,14332,0,0,0,14333,0,0,14337,14340,0,14341,0,0,14342,0,14345,
+14346,0,0,14347,0,14362,0,0,0,0,0,14364,14365,14371,0,14373,0,0,14374,0,14379,0,
+14400,0,0,0,0,0,14401,0,0,14405,0,14406,0,14408,14409,0,0,0,14417,0,0,14424,0,0,
+0,0,0,0,0,0,0,14430,0,0,0,14431,0,0,14435,0,14440,0,0,0,0,0,0,14442,0,0,14443,0,
+0,0,0,0,14446,0,0,0,0,0,0,0,14454,0,14457,0,14460,0,0,14466,0,0,0,0,0,14467,0,0,
+0,0,0,0,14469,0,14477,0,0,0,0,0,0,14478,14482,0,0,0,14483,0,0,0,14485,14486,0,0,
+0,14487,14488,14489,14492,14493,14494,14495,14496,14497,0,14499,0,14501,0,0,0,0,
+0,0,0,0,0,0,14502,0,14507,14512,14513,14514,0,0,0,0,0,0,0,0,0,0,0,14515,14526,
+14530,0,14537,0,14544,0,14547,0,0,14548,14550,14551,0,0,14552,0,0,0,14553,0,
+14554,0,0,0,0,14556,14564,0,0,14565,14566,0,0,0,0,0,0,14568,0,0,14569,0,0,0,
+14571,14576,0,0,14577,14578,14579,0,0,14580,0,0,0,0,14582,0,0,0,0,0,0,0,0,0,0,0,
+0,14583,0,0,0,0,0,14587,0,14588,0,0,14600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,14601,0,0,14604,14605,14611,0,14613,0,0,0,0,14615,0,0,0,0,0,0,14627,0,14628,0,
+0,0,0,14631,0,14633,14634,0,0,0,0,14635,0,0,0,0,0,0,0,0,14636,0,0,14639,14642,0,
+0,0,0,14644,0,0,0,0,14645,14646,0,14653,0,0,14654,0,14658,0,14661,0,0,0,14665,0,
+0,0,14668,0,0,0,0,0,0,0,0,0,14669,0,0,14670,0,0,0,14680,0,0,14681,0,0,0,0,0,
+14682,14683,0,0,0,0,14686,0,0,0,0,14687,14697,0,0,0,0,14699,14705,14711,0,0,0,0,
+0,0,0,0,0,0,14712,0,0,0,14713,0,0,0,0,14719,0,14720,14721,14726,0,0,0,14728,
+14729,0,0,0,0,14731,0,0,0,0,0,0,0,14733,14736,14737,0,0,14740,14742,0,0,0,14744,
+14753,0,0,0,0,14755,14758,14760,0,0,0,0,0,14761,14762,14765,14771,0,14772,0,
+14773,14774,0,0,14775,0,0,14776,0,0,0,0,14777,0,14779,0,0,14782,0,0,14785,14786,
+14788,0,0,0,0,0,14795,0,0,0,0,0,0,14798,0,14803,14804,14806,0,0,0,14809,0,0,0,0,
+0,0,14810,0,0,0,0,14811,0,14812,0,0,0,0,0,14815,0,0,0,0,0,0,0,0,14816,0,14818,0,
+0,0,0,0,0,14819,0,14820,0,14823,0,0,0,14824,0,0,14826,14827,0,0,0,0,0,0,0,0,0,0,
+0,0,14830,0,0,0,0,0,14833,0,14845,0,0,0,0,0,14846,0,0,14847,14871,0,14873,0,
+14876,0,14877,14878,14880,0,0,0,0,0,14881,0,14882,14894,0,0,0,0,14895,0,14907,0,
+14908,0,0,0,0,0,0,0,14911,0,0,0,0,14920,0,0,14931,0,14932,14934,14935,0,0,14936,
+0,14945,0,0,0,0,0,0,0,14947,0,0,14948,14949,14951,0,0,14952,0,0,0,14964,14973,0,
+0,14990,0,0,0,0,14995,0,0,14998,15001,0,0,15002,15020,0,0,0,0,0,0,15021,0,15022,
+0,0,0,0,15023,0,0,15025,15029,15033,0,0,0,15034,0,0,0,15035,0,0,0,0,0,15043,
+15044,0,0,0,15045,15046,15048,15050,0,15065,0,0,0,0,15066,0,0,15075,15082,15084,
+0,0,15085,15086,0,0,0,0,0,0,0,0,15088,0,0,0,15089,0,0,0,0,15094,0,15096,0,15097,
+0,15100,0,0,15102,0,0,0,0,0,0,0,0,15105,0,0,15106,0,15109,15113,0,0,0,15115,0,
+15118,0,0,0,0,0,0,15119,0,0,15120,0,0,0,0,0,15123,15129,0,0,0,15130,0,15131,0,0,
+15134,0,15135,0,0,0,15137,15138,0,0,0,0,0,0,15139,0,0,0,0,0,15140,0,0,15154,
+15162,0,15169,15170,0,15175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15177,0,15178,15179,0,
+0,0,0,0,15183,0,0,0,0,0,0,0,0,0,0,0,0,15185,15187,0,15194,15195,15196,0,0,0,0,0,
+0,0,15204,0,0,0,0,15206,0,0,0,0,0,15207,0,0,0,0,0,0,0,0,0,15213,0,15214,0,0,0,0,
+0,0,0,15232,0,0,0,0,15234,0,15238,15240,0,15248,0,0,0,0,15250,15251,0,0,0,0,0,0,
+0,15252,0,0,0,15255,15262,15266,0,0,0,15267,0,0,0,15277,15279,0,0,0,15280,15281,
+15282,0,0,0,0,0,15285,0,0,0,0,15289,0,0,15291,0,0,0,0,0,0,0,15296,15297,0,0,
+15304,0,0,0,0,15306,0,0,0,0,0,0,15307,15308,0,15309,0,0,15311,0,0,15312,15313,0,
+0,0,0,0,0,0,0,0,0,0,0,15314,15317,0,0,0,15318,15319,0,0,0,0,15320,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,15321,0,0,0,0,0,15324,0,15325,15326,0,15330,0,0,0,0,15334,0,
+15335,0,15341,0,0,15342,0,0,15343,15344,0,0,0,0,15345,0,0,0,0,15347,0,0,15348,
+15349,15350,0,15356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15357,0,15358,0,0,0,0,0,0,0,
+15359,15360,15364,0,15380,0,0,0,0,0,15392,0,0,15393,0,15395,0,0,0,0,0,0,0,0,
+15396,0,0,15397,15398,0,0,0,0,0,0,0,0,0,15399,0,15400,0,0,0,15402,0,15405,15410,
+0,0,0,0,15411,0,0,0,15412,0,15416,0,0,0,0,0,0,0,15428,0,15435,0,0,15438,0,0,0,0,
+15439,0,0,0,15440,0,0,0,15441,15449,15451,0,0,0,0,0,0,0,15452,0,0,15455,0,0,0,
+15456,0,0,15458,0,15460,15461,0,0,0,0,0,15462,15464,0,15465,0,0,15466,0,0,15467,
+0,0,0,0,0,15468,0,0,0,0,15481,0,0,15484,0,15485,15486,0,0,0,15487,0,0,0,0,0,
+15488,0,15492,15498,0,0,0,15499,0,0,0,15500,0,15501,0,0,15512,0,15522,0,0,0,
+15524,0,15525,15526,0,0,15527,0,0,15545,15546,0,15548,15552,0,15553,0,0,0,15554,
+0,15555,0,15557,15565,15573,15577,15578,0,15582,0,15583,0,0,0,0,0,0,0,0,0,0,0,0,
+0,15586,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15588,0,0,0,0,0,15589,0,0,0,0,0,0,0,15593,
+15594,0,0,0,0,15595,0,0,0,0,0,0,15596,0,0,0,15597,0,0,0,0,15600,0,0,15601,0,0,0,
+0,15602,15603,0,0,0,0,0,0,15604,0,15609,0,0,15612,0,0,15613,0,0,15615,15617,
+15618,0,0,15620,0,15636,15637,0,0,15649,0,0,0,0,0,0,0,15650,0,0,15651,0,0,0,
+15656,0,15658,0,0,0,15664,0,0,15665,0,0,15668,0,0,0,0,0,15669,0,0,15674,0,0,
+15675,0,0,0,0,15676,0,0,0,0,0,0,0,0,0,0,0,15677,0,0,0,0,15678,0,0,0,0,0,15679,0,
+0,15681,0,15686,0,0,0,0,15687,0,15688,0,0,15690,0,0,0,15697,0,15699,15700,0,0,0,
+0,0,0,0,0,0,15701,0,15702,15703,0,15704,0,15705,0,15707,0,15709,0,15712,15716,0,
+15717,0,15718,15720,0,0,0,0,0,15724,0,0,0,15725,0,15726,0,0,0,15740,0,15745,
+15746,0,0,15747,0,15748,0,0,0,0,0,15749,0,0,0,15752,0,15753,0,0,0,0,0,0,15759,0,
+0,0,15765,0,0,0,0,0,0,0,0,0,15767,0,0,0,15771,0,0,15784,0,0,0,0,15785,15790,
+15791,0,0,15792,0,0,0,15807,0,15811,0,0,0,0,0,0,0,0,0,0,0,0,15818,0,0,0,15819,0,
+0,0,0,15821,0,0,0,0,0,15822,15824,0,0,15827,0,0,15829,15831,0,15832,0,0,15833,0,
+15835,15838,15839,15843,0,0,0,0,0,0,0,0,0,0,0,15844,0,0,0,0,15845,15851,15856,0,
+0,0,0,0,0,0,15858,15860,0,15861,0,0,0,15864,0,0,0,0,15865,0,0,0,0,0,0,15866,0,
+15872,0,0,15876,0,0,0,0,15877,15878,15883,15885,0,0,15888,0,0,0,0,0,15889,15890,
+0,0,0,0,0,0,0,0,15892,0,0,0,0,0,0,0,15893,0,0,15894,0,0,0,15895,0,15896,15897,0,
+15898,15901,15902,0,15911,15915,0,15916,0,15924,15935,0,15937,0,0,0,0,0,15950,0,
+0,0,0,0,0,0,15958,0,0,0,15961,0,0,15966,0,15967,0,0,15977,0,0,15978,0,0,15981,
+15982,15983,0,0,0,0,0,0,0,15986,0,0,0,15990,0,15991,15995,15998,0,15999,0,16000,
+0,0,0,0,16008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16009,16011,0,16013,0,0,0,0,
+0,0,0,0,16014,0,0,16015,16023,16024,16025,0,0,16026,0,16030,0,16032,0,16033,0,0,
+0,0,0,0,16035,16036,16037,0,0,0,0,0,16039,0,0,0,0,16041,0,0,0,0,0,16043,16044,0,
+0,16047,0,0,0,16048,0,0,16049,16050,16052,0,0,0,0,0,16055,0,0,0,0,0,0,0,0,16056,
+0,0,0,0,0,0,0,16058,16060,16061,0,0,16063,0,0,16064,0,0,0,16067,16068,0,0,16069,
+16078,0,0,0,16079,0,0,0,16080,0,16081,0,0,0,16088,0,0,0,0,0,0,0,0,0,0,0,16089,
+16093,0,16097,0,16103,0,16104,16105,0,0,16256,0,0,16259,0,0,0,0,0,0,0,16260,
+16261,0,0,16262,0,0,16263,0,16268,0,0,0,0,0,0,0,16269,0,0,16270,16273,0,16274,0,
+0,0,0,16275,16276,16277,16280,0,0,0,16281,16284,0,0,0,16286,0,16289,0,0,0,0,0,0,
+0,0,0,16290,0,0,0,0,16291,0,0,0,0,0,0,0,16292,0,0,0,0,0,0,0,0,16293,16295,16297,
+0,16302,0,16304,0,16305,0,16306,0,0,0,0,0,0,0,0,0,0,0,0,16307,16308,16312,0,0,0,
+0,0,0,16313,16315,0,16318,0,0,0,16321,0,0,0,0,0,0,0,16326,16333,16336,0,0,0,0,
+16337,16340,0,0,0,0,0,16345,0,0,16346,0,0,0,0,0,0,0,0,0,16347,0,0,16348,0,0,0,0,
+16349,0,0,0,16350,0,16357,0,0,0,0,16359,16360,0,0,0,0,16362,16363,16364,16365,0,
+0,16366,0,0,0,0,16367,16368,0,16369,16374,0,0,0,0,0,0,0,16376,0,0,0,0,16378,
+16379,0,16380,0,0,0,16381,16383,0,0,0,0,0,16390,0,0,0,16399,0,16402,16404,16406,
+16407,0,0,0,16409,16411,0,0,0,0,16412,0,16413,16415,16423,0,0,0,0,0,16424,0,0,0,
+16428,16434,16435,16449,0,16450,16451,0,0,0,16453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+16454,0,0,16456,16458,0,0,16459,0,0,16460,0,0,0,0,16462,0,16463,0,0,16466,0,0,0,
+0,0,16479,0,0,16480,0,16481,16484,0,0,0,0,0,0,0,0,0,0,16485,0,0,0,0,0,0,16489,0,
+0,0,0,0,16491,0,0,16498,0,0,16503,0,16505,0,0,0,0,0,0,0,0,16506,0,0,0,16508,
+16509,0,0,0,0,0,0,0,0,16511,16513,0,0,0,16516,0,16517,0,16519,0,16529,0,0,16531,
+0,0,0,0,0,0,16534,0,0,16541,16542,0,0,0,0,0,0,0,0,0,16543,16547,16548,0,0,0,
+16551,0,16552,0,0,0,16553,0,0,16558,0,0,16562,16565,0,0,0,16570,0,0,0,16573,
+16585,0,0,0,16586,16587,16595,0,16596,0,16598,0,0,0,16600,0,0,0,0,0,0,0,0,0,0,0,
+0,0,16601,0,0,0,0,16603,0,0,0,0,0,0,0,16604,16612,0,0,0,0,16613,0,16618,0,0,0,
+16640,0,0,16641,0,0,0,0,0,0,16645,0,0,0,0,16646,0,0,0,0,0,0,16651,0,0,0,0,16653,
+16654,0,0,0,16655,0,0,16656,16667,0,0,0,0,16671,0,16672,0,0,0,16673,0,0,0,0,0,
+16676,0,16686,0,0,0,0,16689,0,16690,0,16692,0,16693,0,16694,0,16696,0,0,0,16705,
+0,0,0,0,0,0,16707,0,0,0,16709,0,0,0,0,16711,0,16712,16713,0,0,0,16715,0,0,0,0,
+16716,0,0,0,0,0,0,0,0,0,16718,16724,0,0,16726,16727,0,0,0,0,0,0,0,16728,0,16729,
+0,0,16730,0,0,0,0,0,16731,0,0,0,16732,0,0,0,0,16734,16738,0,0,0,0,0,0,0,0,16743,
+0,0,16745,0,0,0,0,0,16749,0,16752,0,0,0,0,16756,0,0,16758,0,16759,0,0,0,0,0,
+16760,0,0,0,0,0,0,0,16762,0,16769,0,16770,0,16772,0,0,0,16777,16780,0,0,0,0,0,0,
+16781,0,0,16782,0,16784,0,0,16785,16787,16792,0,0,16794,0,0,0,16798,0,0,16809,0,
+0,16814,16816,16817,0,16819,0,0,0,0,0,0,0,0,0,0,16820,0,0,16836,16839,0,0,16841,
+16851,16857,0,0,16858,16859,0,0,16860,0,0,0,0,0,0,0,0,16862,0,16863,0,0,0,0,0,0,
+0,16864,0,0,0,0,0,0,0,16876,0,16881,16882,0,16885,16886,0,16887,0,0,0,16889,
+16891,0,0,0,0,0,16894,16895,0,0,0,0,0,0,0,0,0,0,0,16897,0,16898,0,0,0,0,0,16913,
+0,0,16924,16925,16926,0,0,16927,0,0,0,16937,16938,0,0,0,16940,16941,0,0,0,16942,
+16945,0,16946,16949,16950,0,0,0,16952,16955,0,0,0,16965,0,16969,0,0,16975,0,0,
+16976,0,0,0,0,16978,0,0,16981,0,16983,16989,0,0,0,0,16990,0,0,16991,0,0,0,16993,
+0,16994,16996,17000,0,0,0,0,0,17002,17004,0,17006,0,0,17007,0,0,0,0,17008,17013,
+17014,0,0,0,0,0,0,0,0,0,17021,0,17031,0,0,0,0,0,17033,17036,0,17038,0,0,17039,0,
+17045,0,0,17046,17047,0,0,0,0,17048,0,17049,17050,0,17051,17053,0,17054,0,17055,
+0,0,0,0,0,17063,0,0,17064,0,0,0,0,0,0,0,17065,0,0,17068,0,0,0,0,0,17072,0,0,0,0,
+0,0,17073,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17074,0,17080,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,17081,17083,17084,0,0,0,17085,0,0,0,0,17092,0,0,0,0,0,0,0,
+0,0,17093,0,17095,17102,0,0,0,0,0,0,17103,0,0,17105,0,17107,0,0,0,0,17114,0,0,0,
+0,0,17115,17125,17127,0,0,17128,0,0,0,17129,17130,0,17131,0,0,0,0,0,17132,17135,
+17145,0,0,0,0,0,0,0,0,17146,0,17147,0,17148,0,0,0,0,0,0,17149,17150,0,17151,
+17153,0,17155,0,0,0,0,17163,17171,0,17174,0,0,0,0,17179,0,0,17182,17185,0,0,0,0,
+0,17186,0,0,17188,0,0,0,0,0,0,0,17189,17191,0,17194,0,0,0,0,0,0,0,0,0,17195,
+17196,17203,17204,0,0,17205,17217,0,0,0,0,0,17218,0,0,0,0,17219,0,17220,0,17221,
+0,0,17230,0,0,0,0,0,17236,0,17238,17239,0,0,0,17241,17244,0,0,17245,0,17248,0,0,
+17251,0,17252,0,0,17264,0,17266,0,0,0,17268,0,0,0,0,17271,17272,0,17273,0,17295,
+0,17302,0,17305,0,0,0,17306,0,0,0,0,0,0,0,17308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+17309,0,17310,17313,0,0,0,0,17314,17315,0,17317,0,0,0,0,17318,0,0,0,0,0,0,0,
+17320,0,0,0,0,0,0,17334,0,17344,17348,0,0,0,17350,17351,0,0,17353,0,0,17354,0,0,
+0,0,0,0,0,0,0,17355,0,0,0,0,0,0,17356,17357,0,0,17359,0,0,0,17371,0,17372,0,0,0,
+17393,0,0,0,0,17394,0,0,0,0,0,17395,0,0,17399,0,0,0,17401,17417,0,17418,0,17419,
+0,0,0,0,0,17422,17423,0,0,0,0,0,17424,0,0,0,0,0,17428,17429,17433,0,0,0,17437,0,
+0,17441,0,0,17442,0,0,17453,0,0,0,0,0,0,0,0,17454,17456,17462,0,0,17466,0,0,
+17468,0,0,17469,0,0,0,0,17470,0,17475,0,0,0,0,0,17479,0,0,0,17483,17484,0,17485,
+0,17486,0,17491,17492,0,0,17493,0,17494,17495,0,0,0,17496,0,0,0,17497,0,0,0,
+17502,0,0,0,0,0,17503,0,17505,0,17507,0,0,0,17512,17513,17514,0,0,17515,0,0,0,
+17519,0,0,0,17522,0,0,17523,0,0,0,0,0,0,0,0,0,17527,0,0,0,17528,0,0,0,17534,0,0,
+0,0,17536,0,0,0,17539,0,17540,17543,17549,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17556,
+0,0,17558,0,17559,0,0,17560,0,0,0,17563,0,0,0,0,0,0,17564,0,0,17565,17566,0,
+17567,0,0,0,0,0,0,17569,17570,0,17575,0,0,0,0,0,0,0,0,0,0,0,17581,0,0,0,17582,
+17583,0,17586,0,0,17587,0,0,0,0,0,0,0,17588,0,0,0,0,17596,17597,0,0,17598,17600,
+0,0,0,0,0,0,17601,0,0,0,17604,0,0,17605,0,0,17607,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,17612,0,0,17618,0,17621,17622,0,0,0,0,17623,0,0,17624,0,0,17630,0,0,
+17631,17633,17634,0,0,0,0,0,0,0,17635,0,0,17636,0,0,17637,0,17638,0,17640,0,0,0,
+0,0,0,0,0,0,0,17641,0,0,0,0,0,0,0,0,0,0,17643,0,0,0,0,17645,0,0,0,0,0,0,0,0,
+17646,17662,0,0,0,0,0,0,0,0,0,17663,17664,0,17665,17666,0,0,0,17669,17671,17673,
+0,17679,0,0,0,0,0,0,0,17684,0,0,0,17686,0,17714,0,0,17720,17722,17726,0,0,17728,
+0,0,17729,0,0,0,17732,0,17733,0,17734,0,0,0,17735,0,0,0,0,17737,0,0,0,0,17739,0,
+0,0,17741,17742,0,0,0,0,17743,17744,17745,0,0,0,17749,0,17750,17751,17752,17754,
+17761,17762,0,17763,0,17766,0,17772,0,0,0,0,0,17775,0,0,0,0,0,0,0,17776,0,0,
+17777,0,0,17778,17779,0,17782,17783,0,0,0,0,0,0,0,0,0,0,17784,0,0,0,0,0,0,0,
+17821,0,0,0,17822,0,0,0,17823,17825,0,0,0,0,0,17826,17831,17832,17833,0,0,17845,
+0,0,0,17846,0,0,0,17848,17850,17854,0,17855,0,0,17859,0,0,0,0,0,0,17860,17861,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17870,17871,0,0,0,0,0,0,17872,0,0,0,17879,0,
+0,0,17881,17883,0,17884,0,17885,0,0,17886,0,0,17887,17891,17953,0,0,0,0,17954,0,
+0,17955,0,17968,0,0,17972,0,0,0,0,0,17974,0,0,0,0,17976,17978,0,0,17983,0,0,0,0,
+18003,0,0,0,0,0,18007,0,0,0,0,0,18009,0,0,0,0,0,0,0,18010,0,0,0,0,0,0,18012,0,0,
+18014,0,0,0,18015,0,0,0,18016,0,18017,0,0,0,18030,0,0,0,0,0,0,0,18031,0,0,18036,
+18037,18038,0,0,18049,18056,0,18057,18058,0,18059,0,0,0,0,0,0,0,0,18062,0,0,0,0,
+18064,0,0,0,0,0,0,0,0,18067,0,0,0,18068,0,0,18075,0,0,18078,18093,18094,0,0,0,0,
+0,0,0,0,18097,0,0,0,0,0,18098,18100,0,0,0,18108,0,18111,0,0,18112,0,18113,0,0,
+18115,18116,0,18118,0,0,0,0,18121,0,0,0,0,18123,0,0,0,0,0,0,0,0,0,18124,0,0,0,0,
+18125,18126,0,18127,0,0,18128,18135,0,0,0,0,0,0,0,0,0,18150,0,0,0,0,0,18151,
+18152,0,0,18156,18164,0,18166,18171,0,0,0,0,0,0,0,0,0,18172,18183,0,18184,0,0,0,
+0,18185,0,18187,0,0,0,0,0,18188,0,0,0,0,0,0,0,0,18189,0,0,18190,0,0,18191,18192,
+0,0,18194,18195,18196,0,0,0,18197,0,18203,0,18204,0,0,0,0,18205,0,0,0,18207,
+18208,0,0,18214,0,0,0,18215,18216,0,0,0,18220,0,0,18222,0,0,0,0,0,18223,0,18225,
+18231,0,18234,0,18235,0,0,0,0,18240,0,0,18241,18242,0,0,0,0,0,18243,18251,0,
+18253,0,18254,0,0,0,18266,0,0,0,0,0,0,18269,18270,18271,18273,18281,0,0,0,0,0,0,
+0,0,0,0,0,0,18282,0,18283,0,18284,0,0,0,0,0,0,18285,0,18287,18289,0,0,18290,0,0,
+0,0,18308,0,0,0,18310,0,0,0,0,0,0,0,0,0,0,0,0,18311,0,18312,18313,0,18315,0,0,
+18316,18320,0,18331,0,18332,0,18336,0,0,0,0,18337,0,18340,0,0,0,0,0,0,0,0,0,
+18341,0,18344,18345,0,18346,0,0,0,0,0,18348,0,18351,0,0,18356,0,0,0,0,0,0,18357,
+0,0,0,0,0,18367,0,0,0,18368,0,18369,0,18370,18371,0,0,0,18437,18444,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,18445,18450,0,0,0,0,18451,0,18452,0,0,0,18453,0,0,0,0,0,18455,0,
+0,0,18456,0,18457,0,18460,0,0,18461,0,0,0,0,0,0,0,0,18466,0,0,18467,0,0,0,0,
+18473,0,0,0,18476,0,18477,0,0,0,18478,18479,18480,0,0,0,18485,0,0,0,18486,0,0,0,
+0,0,0,18488,18490,0,0,0,0,0,0,18491,0,0,0,0,0,18495,0,0,18496,0,0,0,0,0,0,18505,
+0,18521,0,18522,18523,0,0,0,18525,18526,0,0,0,0,0,18527,0,0,0,0,18532,18533,0,
+18534,0,0,0,0,0,0,18535,18537,0,18538,0,0,0,0,0,0,18540,18541,18542,18543,0,
+18546,0,0,0,0,18553,18556,0,0,18558,0,0,18569,18571,0,0,0,18572,0,18574,0,0,0,0,
+18586,0,0,0,0,0,18588,0,0,18589,0,0,0,0,0,0,18590,0,18592,0,0,0,0,18594,0,0,0,
+18596,0,0,18597,18598,0,0,18601,0,0,0,0,18602,0,0,0,18603,18604,0,18605,0,0,0,0,
+18608,0,0,18611,0,0,0,0,0,0,0,0,0,18612,0,18616,0,0,18617,18619,0,0,0,18628,0,0,
+0,18629,0,0,18630,0,0,0,0,0,0,0,18631,0,18632,0,0,18635,18637,0,0,0,0,0,0,18641,
+18643,18648,0,18652,0,0,18653,0,18655,18656,0,0,0,18657,0,0,18666,18674,0,0,0,0,
+18677,18684,18685,0,0,18686,0,0,18690,0,0,0,0,0,0,0,18695,18696,0,0,0,0,0,0,0,0,
+0,0,18697,0,0,18700,0,0,0,0,0,0,18702,0,18708,0,0,18709,0,18710,0,0,18711,0,
+18714,0,0,18718,0,0,0,0,0,0,18719,0,0,18722,0,18726,0,0,0,0,0,0,0,0,0,0,0,0,0,
+18731,0,0,0,0,0,18739,18741,0,0,18742,0,18743,18744,18746,18748,0,18752,18753,0,
+0,18754,18763,0,18765,0,0,0,18766,0,0,0,18769,0,0,0,0,0,18773,18778,18779,18781,
+0,0,18784,18787,0,18788,0,18793,0,0,0,0,0,0,18795,0,0,18800,0,0,0,0,0,18801,
+18804,0,0,0,0,0,0,0,18806,0,0,0,18811,18815,18816,0,0,0,0,18825,0,0,18827,18829,
+0,0,18830,0,0,0,0,18831,0,0,18832,0,0,0,0,18833,0,18840,0,18841,0,18842,0,0,0,0,
+18843,0,18844,0,0,0,0,0,0,18845,18846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+18848,0,0,0,18853,18860,0,0,18862,18866,0,0,18867,18869,0,0,18874,18881,18891,0,
+0,0,0,0,0,0,0,0,0,18892,0,0,0,0,0,0,0,0,18895,0,18896,0,0,0,18900,0,0,0,18901,0,
+18902,18915,18916,0,0,0,0,0,0,0,0,18919,0,0,0,0,0,18920,0,0,0,18921,18929,0,0,0,
+0,18930,0,0,0,0,0,0,18932,0,0,0,0,18934,18942,0,0,0,18951,18957,0,0,0,0,18958,0,
+0,0,0,18959,18960,0,0,18961,0,0,18962,0,0,0,0,18963,18964,0,0,0,18965,0,18967,0,
+0,0,0,0,0,0,0,0,18968,0,18969,0,18970,18973,18976,0,0,0,0,0,0,18977,0,0,0,18981,
+0,0,0,18990,0,18998,0,0,0,0,0,18999,19003,0,0,19005,0,0,0,19006,0,0,0,0,0,0,
+19008,19011,0,0,19018,0,0,19019,0,19024,0,19031,19032,0,19039,0,19041,19050,0,0,
+0,19051,19055,19056,0,19059,19063,19064,0,0,19088,0,0,0,19093,19094,0,0,0,0,
+19095,0,19096,0,0,0,19097,0,0,19098,0,19099,19100,0,0,19103,0,0,0,0,0,0,0,19111,
+0,0,0,0,0,0,19112,0,0,0,19116,19117,0,19121,19122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,19123,19124,0,0,0,0,0,0,0,19125,19126,0,19128,0,0,0,0,0,0,0,0,0,0,
+19129,19130,19131,19132,0,0,19146,0,0,19147,19156,19158,0,0,0,0,0,0,0,0,19182,
+19185,0,0,19187,0,0,0,19193,0,0,0,0,0,19194,0,19197,0,0,0,0,19198,0,0,0,0,0,0,0,
+0,0,0,19202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19203,0,19205,19210,
+0,0,0,19213,0,19218,0,0,0,19223,19229,0,0,19230,0,0,19231,19232,19233,19239,0,0,
+0,0,0,19240,0,19248,19249,0,0,0,0,19254,0,19256,19258,19259,0,0,19261,0,19266,0,
+0,0,19272,0,19278,19281,19282,0,0,0,0,0,0,0,0,0,0,0,0,19283,0,0,19284,0,0,19285,
+19287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19288,19291,0,19292,0,0,0,0,19297,0,19298,0,0,
+0,0,19302,19303,0,0,0,0,19304,19305,0,0,0,0,19314,0,0,19315,0,0,19321,0,0,0,0,0,
+0,0,19322,0,19333,0,19334,19335,0,19336,19337,0,0,0,0,0,0,0,0,0,0,0,19346,0,0,
+19353,0,19354,19362,0,19366,19367,0,0,19369,0,19375,0,19377,19380,19388,0,0,0,0,
+0,19389,19390,0,0,0,0,19392,0,0,0,0,0,19402,0,0,0,0,0,0,0,0,19412,0,0,19413,
+19422,0,19424,0,0,0,19425,0,0,0,19428,0,0,0,0,19431,0,0,0,0,0,19432,0,0,0,0,0,
+19448,19459,0,0,19461,0,19462,19463,0,19467,19474,19482,0,0,0,0,19494,0,0,0,0,
+19501,0,0,0,0,0,0,0,0,0,0,19502,19504,0,0,0,0,0,0,0,19505,0,0,0,0,19506,19507,0,
+0,0,19508,0,0,19511,0,0,19514,0,19515,0,19516,0,19518,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,19530,0,19537,19538,0,19543,19546,0,19547,19551,0,0,0,0,0,0,19552,
+19553,0,0,0,0,0,0,0,0,0,0,0,0,19555,0,0,19556,0,0,0,0,0,0,0,0,0,0,0,0,19560,
+19561,0,0,19562,0,0,0,0,0,0,19565,19567,0,19568,0,0,0,19569,19570,0,19578,0,0,0,
+0,19580,0,0,0,0,19581,19584,0,0,0,0,0,0,0,19585,19586,0,0,0,19587,19588,0,19589,
+0,0,0,0,0,0,19592,19593,19599,0,19600,0,0,19604,0,0,19605,0,19606,19608,19610,0,
+19613,19614,0,0,0,0,0,0,19616,19617,0,0,19618,0,0,19619,0,0,0,19620,19621,19631,
+0,0,19632,19634,19636,0,19643,0,0,19644,19658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,19659,0,0,0,0,0,0,0,0,0,0,0,19675,19677,0,0,0,0,19679,0,19683,0,19684,0,0,
+0,0,0,0,19687,0,0,0,0,0,0,0,0,19688,19689,19692,0,0,0,0,0,0,0,19695,19697,0,0,0,
+0,0,19698,19699,0,0,19700,0,19702,0,0,19703,0,0,0,0,0,0,19704,19708,0,19710,0,
+19713,0,0,0,19715,0,0,0,0,19718,0,0,0,0,0,0,0,19720,0,19722,0,0,19725,0,0,0,0,0,
+0,0,0,0,0,0,0,0,19730,0,0,0,0,0,19731,0,19734,19735,19739,0,0,19740,0,19741,0,0,
+0,19746,0,0,19747,0,19771,0,0,0,0,0,0,0,0,19772,19775,0,0,0,0,0,0,19778,0,0,0,0,
+0,19779,0,0,19780,19790,0,19791,0,0,19792,0,0,0,19793,0,0,19796,19797,0,0,0,
+19799,0,0,0,19801,0,0,0,0,19803,0,19804,0,19805,0,0,19807,0,0,0,19808,0,0,0,0,0,
+0,19809,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19816,0,19821,0,19822,19830,19831,0,0,
+0,19833,0,0,0,0,0,0,0,0,0,0,19838,0,0,0,0,19839,0,0,19843,0,0,0,0,19845,0,0,0,0,
+19847,0,0,19848,0,19849,0,0,0,0,0,0,0,19851,0,0,0,19854,0,0,0,0,0,0,0,0,0,19864,
+0,19865,0,19866,0,0,0,0,0,0,0,19868,0,0,19870,0,0,19871,0,0,19872,19873,19875,0,
+19880,19882,19884,0,0,19885,19886,19888,0,0,0,0,0,0,0,0,0,0,0,0,19890,19892,
+19893,0,0,19894,0,0,0,19895,0,19896,19902,0,0,19903,0,0,19905,0,0,0,19906,0,
+19908,0,19909,19911,0,0,0,19913,19920,0,19938,19939,19940,0,0,0,0,0,0,0,19942,0,
+19943,0,19945,0,0,0,19951,19952,19954,19960,0,19965,0,19971,0,0,0,0,0,19975,0,
+19976,0,19990,0,0,19991,0,19993,0,19995,0,0,0,19998,19999,20001,0,20003,20005,0,
+20011,20012,0,0,0,0,0,0,20014,0,20020,0,0,0,0,20021,0,0,0,0,0,20023,20024,0,0,0,
+0,0,20025,0,0,20027,0,0,20029,0,0,20032,0,0,0,0,20044,20045,0,20048,20049,0,0,
+20050,0,20052,0,0,20054,20057,0,0,0,0,0,0,0,0,0,20059,0,0,20061,0,20062,0,20064,
+0,0,20066,0,0,20067,0,0,0,0,20069,0,0,0,0,0,0,20070,20071,0,0,0,0,0,0,0,0,0,0,0,
+20072,0,0,20073,20074,0,0,0,0,0,20075,0,20078,0,0,0,0,20080,0,20081,0,0,0,0,0,0,
+20095,0,20098,0,0,0,0,0,0,0,20107,0,0,0,0,0,0,0,0,20112,0,0,0,20113,20114,0,0,0,
+20115,20123,20124,0,0,0,20131,20133,20134,0,0,0,0,20136,0,0,20137,20138,20150,0,
+20152,0,0,0,20153,0,0,20154,0,0,0,20158,0,20163,0,0,20164,0,0,0,0,0,0,0,20166,0,
+20168,0,20170,0,20175,0,0,20178,0,0,0,0,20223,0,0,0,0,20224,0,20226,0,0,20230,0,
+20231,0,0,0,0,20232,0,0,20233,20234,0,20244,0,20247,0,0,0,0,0,0,20249,0,0,0,
+20250,0,0,0,0,20251,0,20253,0,20254,0,0,0,0,20256,0,0,20264,0,0,0,0,20266,0,0,0,
+20278,0,0,20279,20282,0,0,0,0,0,20283,0,20284,0,20285,0,20287,20290,0,0,0,0,
+20292,0,0,0,0,20293,20297,0,0,0,0,0,0,20299,0,20300,20303,0,0,0,0,0,0,20307,0,0,
+20308,0,20309,0,20310,0,0,0,0,0,0,20312,0,0,0,20314,0,0,0,0,20315,20316,0,20322,
+0,0,0,0,0,0,20339,0,0,0,20342,0,0,0,0,20352,0,0,0,0,0,0,0,0,0,0,20362,0,0,20365,
+0,20375,20377,0,0,0,0,0,0,0,0,0,0,0,20378,20379,0,20380,0,0,20381,0,20382,0,
+20383,0,20388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20390,20392,20393,0,0,20395,0,0,0,0,0,
+20396,0,0,0,0,0,0,0,0,20398,20415,0,0,0,20417,0,0,20420,0,0,20426,20428,0,20431,
+0,0,20432,0,20433,20434,20435,0,0,0,0,20440,0,0,0,0,0,20442,0,20443,0,20446,0,0,
+0,0,20448,0,20451,0,0,0,0,0,0,0,0,0,20452,20453,0,0,20454,0,0,0,0,0,0,20457,0,
+20458,0,0,0,20465,0,0,0,0,0,20469,0,0,0,20473,0,20476,0,0,0,0,0,0,0,0,20477,0,0,
+20485,0,0,20486,0,0,20487,0,20496,0,20497,0,0,20498,0,0,0,0,0,0,0,0,0,0,20499,
+20500,0,20501,0,0,0,0,0,20520,20527,0,20529,0,0,0,0,20539,0,0,20540,0,0,0,20543,
+0,0,0,20546,0,0,0,0,0,20548,0,0,20563,0,0,20564,0,20566,0,0,0,0,0,20589,0,0,0,0,
+20590,0,0,20593,20594,0,0,0,0,20595,0,20597,20598,0,0,0,20618,20620,0,0,0,0,
+20621,0,0,0,0,20627,0,0,0,0,0,20628,0,0,0,20629,0,20630,0,0,20639,0,0,0,0,0,
+20707,0,0,20709,0,0,0,20713,20714,0,0,0,0,0,20724,20725,0,0,0,0,20726,20728,
+20729,0,20733,0,20734,0,20735,20736,0,20737,0,0,20744,0,20745,0,20748,0,0,20749,
+0,0,0,0,0,0,0,0,20750,0,0,0,0,20754,0,0,0,20761,0,0,20763,0,0,0,0,0,0,0,20766,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,20767,0,0,0,0,20768,0,20769,20777,0,0,0,0,0,0,20785,0,
+0,0,20786,20795,20801,0,20802,0,20807,0,0,20808,0,0,20810,0,0,20811,0,20812,0,0,
+0,0,0,20813,0,0,20818,20820,20821,0,0,0,20822,0,20823,0,0,0,20826,0,0,0,0,0,0,0,
+20829,20830,20831,0,20832,20836,0,0,20839,0,0,20840,20842,0,20843,0,20844,0,
+20854,0,0,0,20855,0,0,0,0,20856,0,0,0,20869,0,0,20871,0,0,0,0,0,0,0,20873,0,0,0,
+0,0,20876,0,0,0,0,0,20880,0,0,20882,0,0,0,0,20883,20884,0,0,20890,0,0,0,0,0,0,0,
+0,0,20891,0,0,0,0,0,20905,0,20906,20910,0,0,20912,20915,0,0,0,0,0,20916,0,20917,
+0,20919,20920,20922,0,20927,0,20928,20929,20930,0,0,20935,0,0,20939,0,0,20941,0,
+0,0,20943,0,0,0,20946,20947,0,0,0,0,0,20950,0,20954,0,0,20955,20964,0,0,20967,0,
+0,0,0,0,20973,20975,0,0,0,20984,0,20987,20988,0,0,0,0,0,20989,0,0,0,20995,0,
+20998,0,20999,0,0,0,0,21000,21001,0,0,0,0,21008,0,21010,0,21016,0,0,0,21017,
+21018,0,0,0,0,0,21021,21026,21027,21028,0,0,21029,0,0,0,0,0,21030,0,0,0,0,0,0,0,
+0,0,0,0,0,0,21031,21032,0,0,0,0,0,21037,0,0,21038,0,0,0,0,0,0,0,0,0,21039,0,
+21041,0,21046,21047,0,0,0,21049,21053,0,0,21057,21064,21065,0,0,21066,21067,0,0,
+0,21069,0,0,0,21071,21072,0,0,21073,0,21074,0,0,21078,0,0,0,0,21079,0,0,21080,
+21081,0,0,21086,21087,0,21089,0,0,0,0,0,0,0,21091,0,21093,0,21094,0,0,0,0,0,0,0,
+0,21095,0,0,0,0,0,21096,0,21098,0,0,0,0,0,0,0,21099,0,0,21100,21101,21102,0,0,0,
+0,0,21103,0,21104,0,0,0,0,0,21105,21108,21109,0,0,21112,21113,0,0,0,0,0,0,21115,
+21122,21123,0,0,0,0,0,21125,0,0,0,0,0,0,0,0,21129,21131,0,0,21134,0,0,0,21137,
+21142,0,21143,0,0,21144,0,21145,21146,0,21152,21154,21155,21156,0,0,0,21160,0,0,
+0,0,0,0,21161,0,21164,0,21166,0,0,0,0,21170,0,0,0,0,21171,0,0,21172,0,21174,0,
+21175,0,0,0,0,0,21176,21179,21188,0,0,0,21189,0,0,21190,0,0,0,21192,0,0,21193,0,
+0,0,21198,0,21212,0,0,21213,0,0,0,0,0,0,21215,21216,0,0,21223,21225,0,21226,0,0,
+0,0,21227,21228,0,0,21229,0,0,0,0,21230,21236,0,0,0,0,0,0,0,0,0,0,0,0,0,21237,0,
+0,21238,21239,0,0,0,0,21256,0,0,0,0,0,21257,0,0,0,0,0,0,0,21259,0,0,0,21263,0,
+21272,0,21274,0,21282,0,0,0,0,0,0,0,0,21283,0,0,0,0,0,0,0,0,21294,0,0,21297,0,0,
+0,0,21298,0,0,0,21299,0,21300,21302,0,21316,0,21318,21322,21323,0,21324,0,21326,
+0,0,0,21327,21328,0,0,0,21352,0,0,21354,21361,0,0,0,0,0,0,0,0,0,0,0,0,0,21362,0,
+0,0,21363,0,0,0,0,0,0,0,0,0,21366,0,0,21367,21372,21374,0,0,0,21375,21377,0,
+21378,0,0,0,21380,0,0,0,0,0,0,0,0,0,0,21381,0,0,0,0,0,0,21382,0,21383,0,0,21384,
+0,0,21385,0,0,0,0,21389,21390,0,0,0,0,0,0,0,0,0,0,0,0,0,21397,21398,0,0,0,0,0,0,
+0,0,0,0,21399,0,21400,0,0,0,0,21402,0,0,0,21403,21404,0,21405,21406,0,0,0,21407,
+0,0,0,0,0,0,0,0,0,0,0,0,21408,0,0,0,0,21409,0,21421,0,21422,0,0,0,21425,21428,0,
+0,0,0,21429,0,0,0,0,0,21433,0,0,0,0,0,0,0,0,0,0,21434,0,21443,0,21444,21449,0,
+21452,0,21453,21454,0,0,0,21457,0,0,21458,0,0,0,21460,21461,0,0,21464,0,0,0,
+21473,21478,0,0,21479,0,0,21481,21483,0,0,0,0,0,0,0,0,21484,0,0,21485,21486,0,0,
+21488,0,0,0,0,0,0,21523,0,0,21525,0,0,0,0,0,0,0,21526,0,0,0,0,0,0,21529,21530,0,
+0,21531,0,0,21533,0,0,21539,21564,0,21567,0,0,0,0,0,0,0,0,21575,0,0,0,0,21577,0,
+0,0,0,0,21591,0,0,21604,0,0,0,0,0,0,0,0,0,21605,0,21606,0,0,21617,21618,21619,
+21620,0,0,0,0,0,0,0,0,0,0,0,0,0,21623,0,0,0,0,21631,0,21635,0,0,0,0,21639,21646,
+21653,21662,0,0,21663,21664,0,21666,0,0,21667,0,21670,21672,21673,0,21674,21683,
+0,0,0,0,0,21684,0,21694,0,0,0,0,21695,21700,0,21703,0,21704,0,0,21709,0,0,0,
+21710,0,0,0,0,0,0,0,0,21711,0,0,0,21712,0,21717,0,21730,0,0,0,21731,21733,0,0,0,
+0,21737,21741,21742,0,21747,0,0,0,21749,0,0,0,0,0,0,0,0,0,0,0,0,0,21750,0,0,0,0,
+0,21752,0,0,0,0,21753,0,0,0,0,0,0,21755,21756,0,21757,0,0,0,0,0,0,21760,0,0,
+21763,0,0,0,0,0,0,0,0,0,21764,0,0,21766,0,0,21767,0,0,0,0,0,0,0,0,0,21773,0,
+21774,0,0,21775,0,0,0,0,21776,0,0,21777,0,0,0,0,0,0,0,0,0,21780,21787,21788,
+21791,0,0,0,21797,0,0,0,0,0,21805,0,0,0,0,21806,0,21807,21809,0,21810,21811,0,
+21817,21819,21820,0,21823,0,21824,0,0,21825,0,0,21826,21832,0,0,0,0,0,21833,
+21848,21849,0,0,21867,21870,21871,21873,0,0,0,21874,0,0,0,0,0,0,0,0,0,21875,0,
+21878,0,0,0,21879,0,21881,21886,0,0,0,0,21887,0,0,21888,21894,21895,21897,0,
+21901,0,21904,0,0,21906,0,0,0,21909,21910,21911,0,0,21912,0,0,21913,21914,21915,
+0,21919,0,0,0,0,0,0,0,21921,0,0,21922,21933,21939,0,0,0,0,0,0,0,0,0,0,0,21944,0,
+0,0,0,0,21945,0,21947,0,0,0,0,0,0,0,0,0,0,21949,0,0,0,21950,0,0,0,0,0,0,0,0,0,0,
+0,0,0,21951,0,21952,0,0,0,0,0,0,0,0,0,21954,21957,0,0,0,0,21958,0,21959,0,0,0,0,
+0,0,21962,21963,0,0,0,0,0,0,0,0,21964,21965,0,0,21969,21970,0,0,0,21974,0,0,
+21980,21981,0,21982,0,0,0,0,0,21985,0,21988,0,21992,0,21999,0,0,0,0,0,0,22001,0,
+22002,0,0,0,0,0,0,22003,0,0,0,0,0,22004,0,0,0,22008,0,22009,22015,0,0,22016,0,0,
+0,22017,22019,0,0,0,0,0,0,0,0,0,22020,0,0,0,0,0,0,0,0,0,0,22021,22037,0,22039,0,
+0,0,22040,0,0,0,22048,22049,0,0,22053,22055,22056,22059,0,0,22060,22061,0,0,
+22064,0,0,0,0,22066,0,0,0,0,0,0,0,22073,0,0,0,22074,22075,0,0,0,0,0,0,0,22076,0,
+0,0,0,22077,22084,22099,0,0,0,0,0,0,0,22104,0,0,22107,0,22108,0,22109,0,22110,0,
+0,0,0,0,0,0,22111,22119,0,22120,22122,0,0,0,0,22125,0,0,0,22128,22129,0,0,0,0,0,
+0,22141,0,0,0,22142,0,0,22144,22146,0,22148,22149,22151,22154,0,0,0,22162,0,0,0,
+0,22164,22177,0,0,0,0,22179,0,22182,22183,0,0,22184,22188,0,0,0,0,0,0,0,0,22190,
+0,22194,22201,0,0,22208,0,22209,0,22212,0,0,22215,0,22223,22231,0,0,22232,0,
+22234,0,0,22235,22236,0,22237,0,22240,0,0,0,0,0,22241,0,0,0,22242,22246,22247,0,
+0,0,22259,22268,0,22269,0,0,0,0,0,0,0,22270,0,0,0,0,22271,0,22272,0,22277,0,0,0,
+0,0,22278,22280,22283,22286,0,0,22287,22289,0,0,22290,0,22293,0,0,0,0,0,0,0,0,0,
+0,22295,0,22301,22302,0,0,0,22305,0,22308,0,0,0,0,0,0,0,0,0,0,22315,0,0,0,22317,
+0,22334,0,0,0,22335,0,0,0,0,0,22336,0,22338,22344,0,22347,22349,0,22350,0,0,0,0,
+0,0,0,22357,0,0,0,0,0,22358,0,0,0,0,0,0,0,0,0,0,22359,22360,0,0,0,0,0,0,0,0,
+22361,22366,0,0,22369,0,22370,22373,0,0,0,0,0,22375,0,22377,0,0,0,0,0,22378,0,0,
+0,0,22381,0,0,0,0,22382,0,22383,0,0,0,0,0,0,0,0,0,22391,0,0,22392,22395,22396,
+22402,0,0,0,0,0,0,0,0,0,0,0,0,0,22405,0,0,22406,0,0,22408,0,0,22409,22410,0,0,0,
+0,0,0,22424,0,0,0,0,22426,0,0,0,22427,0,22428,0,22432,0,22435,22442,22443,0,0,0,
+0,22444,0,0,0,0,0,22446,0,22454,0,22455,0,0,0,22465,0,22470,0,22471,0,0,0,0,
+22472,22473,0,22487,0,0,0,22488,0,0,0,0,22489,0,0,22499,0,0,0,0,0,0,22514,0,0,
+22515,0,0,0,0,0,0,0,22516,0,0,0,22517,22520,0,0,0,22534,0,0,22535,0,0,22536,0,
+22540,22553,0,22555,0,0,0,0,22561,0,0,22562,0,0,0,0,0,0,0,0,0,0,0,22566,0,0,0,0,
+22567,22568,0,0,22575,0,22579,0,22582,22583,22585,0,0,0,0,0,22586,0,0,22587,0,0,
+22590,0,0,0,0,0,22591,0,22592,0,0,0,0,0,22593,0,22602,0,0,22604,0,0,22609,0,0,
+22618,0,0,0,0,0,0,22619,0,22624,22625,0,0,22638,0,0,0,0,0,22639,0,0,22640,0,0,0,
+0,0,0,0,22644,0,22645,22647,0,0,0,0,22652,22653,0,0,0,22654,0,22655,0,0,0,22656,
+0,0,0,0,0,0,0,0,0,0,22673,22675,22676,0,0,22678,22679,0,22691,0,0,0,0,0,0,0,
+22693,0,0,22696,0,22699,22707,22708,0,0,0,0,0,0,0,0,22718,0,22719,0,0,0,0,22723,
+0,0,0,22724,22725,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22726,22728,0,0,0,0,0,0,0,0,22729,
+0,0,22731,0,0,0,0,22732,22735,22736,0,0,0,0,22739,0,22749,0,0,22751,0,0,0,0,0,0,
+0,0,0,0,0,22758,0,0,0,0,0,22760,0,0,0,0,0,22764,22765,22766,0,22768,0,0,0,0,0,
+22769,22770,0,0,0,0,0,0,22771,0,0,22772,22775,0,22776,22777,22780,0,0,22782,
+22784,0,22787,0,22789,22796,0,0,0,0,0,22798,0,0,0,0,0,0,22802,0,22803,22804,0,0,
+0,0,0,0,0,0,0,0,22805,0,0,22810,22811,22814,22816,0,22825,22826,0,22831,22833,0,
+0,0,0,0,0,0,0,0,22834,0,22836,22838,0,22839,0,0,0,0,0,22840,0,22847,0,0,0,0,0,
+22856,22857,0,22858,22859,0,0,22862,0,0,22864,0,0,0,0,22865,0,0,0,0,0,0,0,0,0,0,
+0,22866,0,22867,22868,0,0,0,0,22869,0,22871,0,22872,0,22873,22881,22882,22884,
+22885,0,0,0,0,0,0,0,22886,22887,0,22894,0,22895,0,0,0,22900,0,22901,0,0,0,0,
+22904,0,0,0,0,22905,22907,0,0,0,22915,22917,0,0,22918,0,0,0,22920,0,0,0,22929,
+22930,0,0,0,22941,22942,0,0,0,22943,0,0,0,22944,0,0,0,0,0,0,0,22946,0,22947,0,0,
+22954,0,22956,0,0,22962,0,0,0,0,0,0,0,22963,0,0,22964,0,0,0,0,0,0,0,22965,0,
+22968,0,0,0,22969,0,0,0,0,0,22970,0,22971,0,0,0,0,0,22978,0,0,22979,0,22987,0,0,
+22989,0,0,0,0,0,0,22990,0,23005,0,0,0,0,0,0,0,23006,23007,23008,0,0,23023,23024,
+23029,0,0,0,0,23030,0,0,0,0,0,23032,0,0,0,0,0,23035,0,0,0,0,23038,0,0,0,23048,0,
+23049,23052,23053,23060,23061,0,23063,0,0,0,0,23067,23068,0,0,0,23069,23073,0,0,
+0,23127,0,23128,0,0,0,0,0,23129,0,23138,23141,0,23149,0,0,23150,0,0,0,23152,0,0,
+0,0,0,0,0,0,23154,0,0,0,0,23157,23159,23160,0,0,0,0,0,0,0,0,0,0,0,0,23180,0,0,0,
+0,23181,0,0,23188,0,23189,0,0,0,0,0,0,0,0,0,0,0,0,23195,0,0,23196,23199,0,0,0,0,
+0,0,0,0,0,23202,0,23204,0,23207,0,23209,23210,0,0,0,0,0,0,23227,23229,0,0,23230,
+23234,23238,0,0,0,23245,23246,23248,0,0,0,0,23249,23254,0,0,0,23265,0,0,0,0,0,0,
+0,23268,0,23276,0,0,0,0,23277,0,23297,0,23298,0,0,0,0,23299,0,23302,0,0,23303,
+23312,0,0,23314,0,23320,0,0,0,0,23324,0,23325,0,23328,0,23334,0,0,0,23337,0,0,0,
+0,23343,23344,23346,0,23348,0,0,0,0,0,0,0,0,23353,0,0,0,0,23355,0,23356,23358,0,
+0,0,23359,23360,0,23361,0,23367,0,23369,0,0,23373,0,23378,23379,0,23382,23383,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,23387,0,0,0,0,0,0,23388,23390,0,0,23393,23398,0,0,0,
+23399,0,0,0,23400,0,0,0,0,23401,0,0,0,23415,0,0,0,0,0,0,0,0,23416,0,23422,0,
+23443,23444,0,0,0,0,23448,0,23454,0,0,0,0,0,0,23456,0,0,23458,23464,0,0,0,0,0,0,
+23465,0,0,0,23470,23471,0,0,23472,0,0,0,23473,23496,0,0,0,0,0,0,0,0,23497,0,
+23499,0,0,23502,0,0,23503,0,0,23513,0,0,23515,0,0,0,23517,0,0,0,0,23518,23519,
+23521,23524,0,23525,23528,23539,0,0,0,0,0,23541,0,0,23544,0,0,23556,0,0,23557,0,
+0,0,0,0,0,0,0,0,0,0,0,0,23559,0,23560,0,0,23561,0,0,23566,0,0,0,0,0,23568,23569,
+23570,0,0,0,0,23571,0,23574,0,0,0,0,0,0,0,0,0,0,0,23575,0,23579,0,0,23581,0,0,0,
+0,0,0,23587,0,0,0,0,0,0,0,23596,23598,0,0,0,0,23602,23606,0,0,23607,0,23608,0,0,
+0,23614,23616,0,0,0,0,0,23618,0,0,23619,0,0,0,0,23621,23626,0,23627,0,0,0,0,0,0,
+0,23629,0,23630,0,0,0,0,23634,0,23636,0,0,0,0,0,0,23638,0,0,0,0,23640,23667,0,
+23669,0,0,0,23681,0,0,0,0,0,0,0,23682,0,23683,0,0,0,0,0,23684,0,0,0,23685,23689,
+0,23693,23694,23700,0,23702,0,23709,0,0,0,0,0,0,0,23712,0,0,0,0,0,23714,0,0,
+23715,0,0,0,0,23718,0,0,23720,0,0,0,0,23722,0,0,0,23726,23729,0,23741,23746,0,
+23748,0,0,0,0,23749,0,0,0,0,0,23750,0,0,0,0,23751,0,23753,0,0,0,0,23757,23765,0,
+0,0,23770,0,0,0,0,0,0,0,23771,0,23772,23781,0,0,23796,0,0,0,0,23798,0,23799,0,0,
+0,23802,0,0,23806,0,23807,0,0,23808,0,23809,0,23819,0,0,0,23821,0,23827,0,0,0,
+23829,0,0,0,0,0,0,0,23830,0,0,0,0,0,0,23832,23833,23834,23835,0,0,0,0,23837,
+23838,0,0,0,0,0,23846,0,0,0,0,0,0,23847,0,0,0,0,0,23879,23881,0,0,23882,23883,
+23895,0,23899,0,0,0,0,23901,0,0,0,0,0,0,23902,0,0,0,0,0,23903,23905,0,23906,0,
+23907,23918,23919,23920,0,23922,0,23924,0,23927,0,23934,0,23937,23941,0,23942,
+23946,0,0,0,0,0,23955,23956,23958,0,0,0,0,0,0,23959,0,23962,23965,0,23966,0,0,0,
+0,23967,23968,0,0,23973,0,0,23974,0,0,0,0,23975,0,23976,0,0,0,0,0,0,0,0,0,0,0,0,
+0,23977,0,0,0,0,0,0,0,0,23980,0,0,23984,0,23985,0,0,23987,0,0,23988,23990,23991,
+0,0,0,0,0,0,23992,0,0,0,0,0,0,0,0,23994,0,0,0,23998,0,0,0,0,0,0,0,0,0,23999,0,0,
+24003,0,24004,0,24006,0,0,0,24007,0,0,24008,0,0,0,0,0,0,0,24009,0,0,24010,0,0,
+24011,0,0,24013,24014,0,0,24015,24016,24027,0,24028,24029,0,24030,0,0,0,0,0,
+24033,24034,0,24035,0,0,24036,0,0,24044,0,24048,24049,24063,24067,0,24068,24070,
+0,0,24071,24078,24087,0,24090,0,0,0,24095,0,24098,24101,24104,24106,0,24107,0,0,
+0,24108,0,0,0,0,24110,24111,0,24113,0,0,24115,24120,0,0,0,0,0,0,24124,0,24125,0,
+24126,0,24127,0,0,0,0,0,24135,0,0,24136,0,24137,24142,0,0,0,24146,0,0,24147,
+24149,24154,0,24163,0,0,0,24165,24166,24167,0,0,0,0,0,0,0,0,0,0,24169,24170,
+24175,0,0,0,24178,0,0,24179,0,0,24181,0,24184,24197,0,24201,24204,0,0,0,0,0,0,
+24206,24212,24220,0,0,0,24224,0,0,0,0,0,0,0,0,24226,0,24234,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,24235,0,24236,0,0,0,0,0,24239,24240,24241,0,0,24248,0,0,24249,0,
+24251,0,0,0,0,0,0,24253,0,24268,0,0,0,24269,0,24271,24272,0,0,0,0,24273,0,0,
+24274,0,0,24279,0,0,0,0,0,0,0,24280,0,24293,24294,0,0,0,0,0,0,24296,0,0,24323,0,
+0,0,24329,24330,24331,24339,0,24351,0,0,24369,24370,0,0,0,24371,0,0,0,0,24372,
+24373,24374,0,0,0,0,0,24378,0,0,0,0,24379,0,24381,0,24383,24389,0,24390,0,0,
+24394,24395,24400,0,0,0,24401,24402,0,24406,0,0,0,24411,0,0,0,24415,0,24416,0,0,
+0,0,0,24417,0,24419,0,24422,0,24423,24428,0,24435,0,0,0,24439,0,0,0,24440,24442,
+24446,0,0,0,24447,24448,24449,24452,0,0,0,0,24453,24457,0,0,24458,24459,24460,0,
+24465,0,0,0,0,0,0,0,24470,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24471,0,24473,
+24474,24475,24476,0,24478,0,0,0,0,24480,0,0,0,0,0,0,0,0,0,0,24481,0,0,0,0,0,0,0,
+0,0,0,24482,24485,0,0,0,0,24486,0,0,0,24488,0,0,0,24494,0,0,0,0,24497,0,0,24498,
+0,0,0,24499,24506,0,0,0,24507,0,0,24511,0,0,24513,24514,0,0,0,0,0,24517,0,24518,
+0,24520,0,24521,24524,24525,0,0,0,0,0,24527,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24528,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24537,24539,0,24540,0,0,0,24548,0,0,0,0,0,24549,
+24550,0,0,0,24553,24554,0,24555,0,24556,0,24558,0,0,0,0,0,24560,0,0,0,24561,0,0,
+0,0,0,24562,0,0,0,0,0,0,0,0,0,0,0,0,0,24567,0,0,0,0,0,24569,0,0,0,24574,0,24575,
+0,0,0,0,0,0,0,0,0,0,0,24577,24581,0,24584,0,0,0,0,0,24585,0,0,0,0,0,24586,0,0,
+24587,0,24588,0,0,0,0,0,0,0,0,0,0,24590,24591,0,0,0,0,24592,0,0,0,0,0,0,0,24594,
+0,0,0,0,0,0,0,24596,24597,0,0,0,0,24602,24603,0,0,0,0,24604,0,0,24605,0,24610,0,
+0,24611,0,0,0,0,24612,24615,24616,24624,0,0,0,24627,0,24638,24639,0,0,0,0,24640,
+0,0,0,24655,24656,24657,0,0,0,0,0,0,0,0,24662,0,24663,24664,0,0,0,0,0,24665,0,0,
+0,0,24667,0,0,0,0,0,0,24668,24669,0,24670,24674,0,0,0,24675,0,24678,0,0,24679,0,
+0,0,24681,0,24683,0,0,0,0,24684,0,24685,0,0,24686,0,0,24688,24689,0,0,0,0,24690,
+24691,0,0,0,0,0,0,0,24697,0,24698,0,0,0,0,0,0,0,0,24709,0,0,0,0,0,24710,0,24712,
+0,0,0,0,0,0,24713,24714,0,24715,0,24716,24718,0,24719,0,0,0,0,24720,0,0,24725,0,
+0,24738,0,24749,24750,0,0,0,24752,0,0,0,24753,0,0,0,24758,0,0,0,0,0,24762,0,
+24763,0,0,0,0,0,0,0,24764,0,0,0,0,0,24765,24767,24768,0,24772,0,0,0,0,24773,0,0,
+0,0,24777,0,0,0,0,0,24785,0,24786,24788,0,0,0,24789,0,0,0,0,24794,24798,0,24799,
+24800,0,0,0,24803,0,24804,24806,0,24807,0,0,0,24810,0,0,0,0,0,0,24827,24828,0,
+24835,0,0,0,0,0,0,24836,0,0,0,0,0,24839,0,24843,24844,0,0,0,0,0,0,0,0,0,0,24847,
+0,0,24848,0,0,0,0,0,0,24849,0,24850,24851,0,0,0,24852,0,24853,0,0,0,0,0,0,0,0,0,
+24854,0,24855,0,0,24868,0,0,0,24883,0,0,0,24884,0,24895,24897,0,0,0,0,0,24899,0,
+0,0,0,0,24900,0,24913,0,0,0,0,0,0,24914,0,0,24917,24930,24931,0,0,0,24932,0,0,
+24939,0,0,24942,0,0,0,0,0,0,0,0,0,24945,24950,0,24951,0,0,24953,0,0,0,24954,0,
+24959,0,0,0,24961,0,0,24962,0,24964,24968,24970,24972,0,0,0,0,0,24976,0,0,0,
+24977,0,24982,0,0,24983,0,0,24984,0,0,0,24993,0,0,0,24994,0,0,25001,0,0,0,25003,
+0,0,25018,0,0,25023,0,0,0,25034,0,0,25035,25036,0,25037,0,0,0,0,0,0,0,25039,0,0,
+0,0,0,25040,0,0,0,0,0,0,0,25042,0,0,25043,25045,0,0,0,0,0,0,25049,0,0,25051,0,
+25052,25053,0,0,25054,0,0,0,25055,0,0,0,0,25057,25059,0,0,25060,25064,0,25065,
+25069,25070,0,0,0,0,25072,0,25073,0,25090,0,0,25092,25093,25101,0,0,0,0,0,0,
+25105,25108,0,0,25113,0,0,25115,25116,0,0,0,0,0,0,25117,0,0,0,25120,25121,0,0,0,
+0,0,0,0,25125,0,0,0,25126,0,25130,25134,0,25139,0,25143,0,0,0,25151,0,25161,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25163,0,0,0,0,0,0,0,25174,0,25175,0,25207,0,0,
+0,25209,0,0,0,0,25213,0,25219,0,25223,0,25225,0,0,0,25227,0,0,0,25228,0,0,0,
+25229,0,0,0,0,0,0,0,25231,25233,0,0,0,0,25237,25239,0,0,0,25243,0,0,0,25252,0,
+25257,25258,0,0,0,0,25260,25265,0,25268,0,0,25273,25324,0,25325,0,25326,0,0,0,0,
+0,0,0,0,25327,0,0,0,0,0,25328,0,0,0,0,0,0,25332,0,0,0,25333,0,0,0,25336,25337,
+25338,0,0,25343,0,25350,0,0,0,0,0,0,0,25352,0,25354,0,25375,0,25379,0,0,0,0,
+25384,0,0,0,0,0,0,0,0,0,25386,0,25388,0,25390,0,0,25399,0,0,25401,0,0,0,25402,0,
+0,0,25407,0,0,0,0,0,0,0,0,0,0,0,25413,25415,0,0,25417,0,0,0,0,0,0,0,25419,0,0,0,
+25421,0,0,0,25424,0,0,0,0,25433,0,0,0,0,0,0,0,0,0,25435,0,0,0,0,0,0,25436,0,0,0,
+25437,0,0,25440,0,0,0,0,0,0,25442,0,0,25443,0,25446,0,0,25449,0,0,0,25450,0,0,0,
+0,25452,0,25453,25454,25455,0,0,0,25456,0,25457,0,0,0,25459,0,25461,0,25468,0,0,
+0,0,0,0,0,0,25469,0,0,0,0,0,25471,0,0,0,0,0,25474,0,0,0,0,0,0,0,0,25475,0,0,0,0,
+25477,0,0,0,0,25483,0,0,0,0,0,25484,0,0,0,0,0,0,0,0,0,0,0,0,25485,0,25497,0,0,
+25498,0,25504,0,25510,0,25512,0,0,25513,25514,0,0,0,0,0,0,25517,25518,25519,0,
+25520,0,0,0,0,0,0,0,25521,0,25522,25527,25534,0,25536,0,25537,0,0,25548,25550,0,
+0,25551,0,25552,0,0,0,0,0,25554,0,25555,0,25556,25557,25568,0,0,0,25570,25571,0,
+0,0,0,0,0,25574,0,0,0,0,25579,0,0,0,25581,0,0,0,25582,0,0,0,0,0,0,0,0,0,25588,0,
+0,0,0,25589,0,0,0,0,25590,0,25591,25592,25593,0,25594,0,0,0,25596,0,25597,25615,
+0,0,0,0,0,25618,0,0,0,0,25619,25623,0,0,25629,0,0,25631,0,0,0,25635,25636,0,0,
+25649,0,0,0,0,25654,0,0,0,25661,25663,0,0,25671,0,0,25678,25698,0,25699,25702,
+25703,0,0,0,0,0,0,0,0,25704,0,0,0,0,0,25706,0,0,25710,0,25711,0,25712,0,25715,
+25716,25717,0,0,25718,25728,25732,0,0,0,25734,0,0,0,0,0,0,0,0,0,25737,0,0,25739,
+0,0,0,25740,0,25741,25745,0,25746,0,25748,25772,25778,0,0,0,0,0,25780,0,0,0,0,
+25781,0,25782,25784,25785,0,0,0,25789,0,0,0,0,0,0,25797,25801,0,0,0,25808,25809,
+0,0,25811,25814,25815,0,0,25817,0,0,0,0,0,0,0,0,25820,0,0,0,0,25832,25833,0,0,0,
+25846,0,0,0,25847,25848,0,0,0,0,0,0,0,0,0,25849,25850,0,0,25851,0,0,25852,0,
+25862,0,0,0,25863,25865,0,0,0,0,0,0,0,25867,25868,0,25869,25874,0,25875,0,25876,
+25877,0,0,0,0,25878,25902,0,0,0,0,0,0,0,25903,25904,25905,0,0,0,25908,25909,0,0,
+0,0,25910,0,0,0,0,0,0,0,25912,0,25913,0,0,0,0,0,0,0,0,25914,0,0,25916,0,0,0,0,0,
+25917,25927,0,0,0,0,25928,0,0,25930,0,0,0,25933,0,0,25938,25942,0,0,0,0,0,0,0,
+25945,0,25950,0,25956,0,0,25961,25962,0,0,25963,0,25964,25965,25966,0,0,0,0,0,
+25967,0,0,0,0,25968,0,0,0,25969,25971,0,0,0,0,0,25973,25975,0,0,0,0,0,0,0,25978,
+0,25981,0,0,0,25982,0,0,0,25984,0,0,0,0,0,0,0,25993,0,0,0,0,0,0,0,0,0,0,0,0,0,
+26002,0,0,0,26005,0,0,0,26006,26007,0,0,26014,26015,26016,0,0,0,0,0,0,26017,
+26018,26020,0,26022,26023,0,0,0,26024,26028,0,26029,26033,26034,26044,0,0,0,0,0,
+26046,0,0,26047,0,0,26049,0,26050,0,26051,0,0,0,0,0,26053,0,0,0,0,26054,26059,0,
+0,0,0,0,0,26060,0,26066,0,0,0,0,0,0,0,0,0,0,0,0,26067,0,26069,0,0,26071,0,0,0,
+26073,0,26074,26077,0,0,0,0,26078,0,0,0,26079,0,26090,0,0,26094,0,0,0,0,0,0,0,0,
+26095,0,0,0,0,0,0,0,0,0,0,0,26096,26101,0,26107,26122,0,26124,0,0,26125,0,0,0,0,
+0,0,26136,26141,26155,0,0,0,0,0,0,0,0,0,26164,26166,0,0,0,26167,0,26170,26171,0,
+0,26172,0,0,26174,0,0,0,0,0,0,0,0,0,0,0,0,0,26175,0,0,0,26176,26177,0,26321,
+26322,0,26323,0,0,26324,0,0,0,0,0,0,0,26325,0,26331,0,0,0,0,0,0,26335,0,0,0,
+26350,0,0,0,26379,0,0,26382,26383,26385,0,0,26392,26406,0,0,0,0,26411,0,0,0,0,0,
+26412,0,0,26420,0,0,26423,0,26424,26426,26432,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+26435,0,26436,0,0,0,0,0,26441,0,26444,0,0,0,26446,0,0,0,0,26447,0,0,0,0,26449,0,
+26450,26452,0,26453,26454,0,0,0,26455,0,0,0,26456,0,0,26458,0,0,26460,0,26463,0,
+0,0,0,0,0,0,0,26464,26470,0,0,0,0,0,0,0,0,0,26473,0,0,26474,0,0,0,0,0,0,0,26475,
+0,0,0,0,0,0,0,26477,0,26485,0,0,26486,0,26487,0,0,26488,26493,26494,0,0,26495,0,
+26497,26504,26506,0,0,0,0,0,26507,0,0,0,0,0,26509,0,0,26510,0,0,0,0,0,0,0,0,0,0,
+0,0,0,26512,0,26513,26515,0,0,0,26518,0,0,0,26519,0,26524,26526,0,0,0,26527,0,
+26532,0,26533,26537,26558,0,0,0,26559,0,0,0,26571,0,0,26573,0,26588,0,26593,0,0,
+0,0,0,0,26603,0,26604,0,0,0,0,0,0,0,0,0,0,26606,0,0,0,0,0,0,0,26607,26609,26611,
+26614,0,0,0,26616,26620,0,26621,0,0,0,0,0,26627,0,26629,0,0,26630,0,0,26632,
+26643,0,0,0,26644,0,0,0,0,0,0,0,0,0,26646,26647,0,0,0,26650,0,0,26656,0,0,0,0,
+26663,26670,26671,0,0,0,26685,26686,26687,0,26689,0,0,0,0,26744,0,26745,0,26747,
+26748,0,26749,26750,26751,0,0,0,0,26752,26755,0,0,0,26756,26769,0,0,0,26774,0,0,
+0,0,0,26775,0,26777,26778,0,26786,0,0,0,26787,0,0,0,0,0,0,0,0,0,0,0,0,0,26788,0,
+0,26789,0,0,0,0,0,26791,0,26792,26793,0,0,0,26794,0,26797,26798,0,0,0,26800,0,0,
+26803,0,26804,0,0,0,0,0,0,0,0,0,26805,0,0,26808,0,0,26809,0,0,0,0,0,0,0,26812,0,
+26825,0,0,0,0,0,0,0,26826,0,0,26827,26829,26834,0,0,0,0,26835,0,0,26849,0,26851,
+0,0,0,0,0,0,0,0,0,26852,0,26853,26857,0,26858,0,26859,0,0,0,0,0,0,0,26876,0,
+26878,26882,26883,0,0,0,0,26890,26894,0,0,0,0,26895,26896,0,0,0,0,0,26900,0,0,0,
+0,0,0,0,26911,26913,26914,26915,26916,26919,0,0,0,26921,26922,0,0,26925,0,0,0,
+26928,0,0,26929,26930,0,0,0,26931,0,26932,0,0,0,0,0,26933,0,0,0,0,0,0,26937,0,0,
+26943,0,0,26944,0,0,0,26946,0,0,0,0,0,0,0,26956,0,26958,0,0,26963,0,0,0,0,0,0,0,
+26965,0,26969,26970,26972,0,0,0,0,0,26973,0,26974,0,26978,0,26980,0,0,0,0,0,0,
+26982,0,26986,26987,0,26990,0,0,0,0,27003,27006,0,0,27007,27010,27012,27013,0,0,
+0,0,0,0,0,0,27014,27015,27018,0,27019,0,0,0,0,0,27025,0,0,0,27026,0,0,0,0,27029,
+27030,27031,27034,0,0,27036,27037,0,0,0,27038,27042,0,0,0,27044,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,27045,0,0,0,0,0,0,0,27046,0,0,0,0,0,0,0,27047,27049,0,27050,0,0,0,
+27051,27052,0,27055,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27056,27058,27059,0,
+27061,0,27064,0,0,0,0,0,27069,0,0,27070,0,0,0,0,0,0,0,27072,0,0,0,0,0,0,0,0,
+27076,0,0,0,0,0,27078,0,27079,0,0,0,27081,0,0,0,0,0,0,27082,0,27083,27086,0,0,0,
+0,27087,0,0,0,0,0,27088,27090,0,27094,0,0,27095,0,27099,27102,0,0,0,27103,0,0,0,
+0,27105,0,0,0,27106,0,0,0,0,0,0,27107,0,0,0,0,27108,27117,0,0,0,0,27118,0,0,
+27124,0,27126,0,0,27130,27131,0,0,0,0,0,0,27147,0,0,0,0,27148,27149,0,0,0,0,
+27150,27151,0,27152,0,27159,0,0,0,27164,0,0,0,0,0,0,0,27175,0,27189,0,0,27191,0,
+27193,0,27195,0,27198,0,0,0,0,0,27200,0,0,0,0,27202,0,0,0,0,27203,0,0,27204,0,0,
+27206,0,27207,0,0,0,0,27209,0,0,0,27213,0,0,27216,27219,27220,27222,27223,0,
+27224,0,27225,27226,0,0,27233,0,0,0,0,27235,0,27237,0,27238,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,27239,0,27242,27243,0,27250,0,0,0,27251,0,27253,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,27254,27255,27258,0,0,0,27259,0,0,0,0,0,0,27267,0,27276,27278,
+0,0,0,0,0,0,0,0,0,27296,27297,27301,0,0,0,0,0,0,27302,0,0,0,0,0,0,27312,27313,0,
+0,0,0,0,27318,0,27320,0,27329,0,27330,27331,0,27332,0,0,0,0,27340,0,0,0,27348,0,
+0,0,0,0,0,27350,0,27351,0,0,0,0,27355,0,0,27358,27359,27361,0,0,0,27365,0,27367,
+0,27376,27378,0,0,27379,0,0,0,0,0,0,27396,0,27397,27404,0,0,0,0,0,27408,0,0,0,0,
+27453,0,0,0,27456,0,0,0,27458,0,0,0,0,0,0,0,27459,0,0,0,27460,0,0,27461,0,27465,
+27467,0,0,27469,0,27470,0,27471,0,27477,27482,0,0,0,0,0,0,27484,0,0,0,0,0,0,
+27485,0,0,0,0,0,27493,0,27494,27502,0,0,0,0,0,0,0,0,0,0,0,0,27511,27532,0,0,0,
+27533,27545,0,0,0,27546,0,0,0,0,0,0,0,0,0,0,27547,0,0,27549,27550,0,27551,0,0,0,
+0,0,0,0,27555,0,0,27571,0,27573,27574,27575,27577,0,27578,0,0,27579,27585,0,0,0,
+0,0,27586,0,0,27588,27589,0,0,0,0,27596,0,0,27600,0,0,0,0,0,0,0,0,0,0,0,27608,0,
+0,0,0,0,0,0,0,0,0,0,27610,0,0,0,27618,0,0,27620,0,0,0,27631,0,0,27632,27634,0,
+27636,27638,0,0,0,27643,0,27644,27649,0,0,0,0,0,0,0,0,0,0,0,0,0,27651,27660,0,
+27661,0,0,0,0,0,0,0,27662,0,0,27664,0,27665,0,0,0,27669,0,27671,0,0,0,27673,
+27674,0,0,0,27682,0,0,0,27711,0,27712,27713,27719,27720,0,0,27728,0,27729,0,0,0,
+0,0,0,0,0,0,27731,0,0,27732,0,27733,0,27738,0,0,0,27742,0,0,0,27743,27744,0,0,0,
+0,0,0,27745,27746,0,0,0,27747,27748,27751,27752,0,0,0,27768,27770,0,0,0,27774,
+27775,0,27776,27777,0,0,27781,0,27784,0,27786,0,0,27791,0,27792,27793,27804,0,
+27812,27813,0,0,0,0,0,0,0,0,27814,0,27825,0,27827,0,0,0,0,27828,27861,27862,0,0,
+0,27864,0,0,0,27865,27884,0,27889,0,0,0,0,0,27890,0,27891,0,0,0,27892,0,0,0,0,0,
+27897,27898,0,0,27899,0,0,0,27901,27905,0,0,27920,0,0,27921,0,27922,0,0,0,27931,
+27934,0,0,0,0,0,0,0,0,0,0,27941,0,27942,0,27945,0,27947,27954,0,0,0,0,27960,
+27963,0,0,0,0,0,0,0,0,27964,27965,0,0,0,27967,0,27969,27975,0,27976,27977,0,
+27981,0,27983,28051,28052,0,0,0,0,0,28056,0,0,0,0,0,0,28058,28059,0,0,28061,0,0,
+0,0,0,0,0,28063,0,0,0,0,0,0,28066,0,0,0,0,0,0,28069,28070,28072,0,28073,0,0,
+28074,0,0,0,0,28075,0,0,0,0,0,0,0,28078,0,0,0,0,28085,0,0,0,0,28086,0,0,0,0,0,0,
+28088,0,0,0,0,0,0,0,0,28090,0,28097,28114,28115,0,0,0,0,0,0,0,28116,0,0,0,0,0,
+28118,0,28129,0,28131,0,0,28135,0,0,0,28140,28141,0,0,0,28146,0,0,0,0,28152,0,0,
+0,0,28155,28157,28161,0,0,0,0,28166,0,28167,0,0,0,0,0,0,0,0,0,0,0,28172,0,0,0,0,
+0,0,28173,0,0,28175,0,0,0,0,0,0,0,0,0,28178,28188,0,28190,0,0,0,0,0,28191,0,
+28193,28206,0,0,28207,28209,0,28211,0,28213,0,0,0,28215,28216,28217,0,28222,0,
+28223,28225,0,0,0,28226,0,28227,28229,28232,0,0,0,0,0,0,0,0,0,28235,0,28241,0,0,
+28242,0,0,0,0,28243,0,0,0,28245,0,0,0,28248,28250,0,28251,28252,0,0,0,0,0,0,
+28253,0,0,28254,28255,0,0,28256,0,0,28258,0,0,0,0,0,28259,0,0,28260,0,0,28261,0,
+0,0,0,28262,28263,0,0,28264,0,0,0,28266,0,28268,28269,0,28270,28272,28274,0,
+28277,28278,0,0,0,28279,0,28280,28281,28283,0,28292,0,28294,0,28297,0,0,0,0,
+28299,0,0,0,0,0,28300,0,0,0,0,0,0,0,28301,0,0,0,0,0,0,0,0,0,0,0,0,0,28302,28303,
+0,0,0,0,28304,0,0,28305,0,28312,0,28313,28314,0,0,0,0,0,0,28315,0,0,0,28320,
+28321,0,0,28328,0,0,0,28329,28338,0,28339,0,0,28344,0,0,0,0,0,0,0,0,28347,0,0,0,
+0,0,0,0,0,28348,0,0,0,0,0,28411,0,28412,28413,0,28416,0,0,0,28420,0,0,0,0,0,
+28421,0,0,0,0,28423,0,0,0,28424,0,0,28428,0,0,0,0,0,28429,0,0,0,28431,28434,0,
+28458,0,0,0,0,0,0,0,0,0,0,0,28464,0,0,0,0,28465,0,28467,0,0,0,0,0,0,28471,0,0,0,
+0,28474,0,28480,0,28481,0,0,28485,0,0,0,0,28486,28488,0,0,28489,0,0,0,0,28492,0,
+0,0,28495,0,28497,0,28499,0,0,0,0,28500,0,0,28502,28503,0,0,0,28508,0,0,0,28510,
+0,0,28512,28513,28514,28521,0,28526,0,28527,28528,0,0,0,0,28529,0,0,28532,0,0,
+28537,28538,0,0,0,28539,0,28548,0,28553,28554,0,0,0,0,0,0,0,0,0,0,0,0,28560,
+28563,0,0,28564,0,0,0,0,28565,0,0,0,0,0,0,0,28566,28568,0,0,0,0,0,0,28569,0,0,0,
+28570,0,28572,28573,0,0,0,0,28575,0,0,0,0,28576,28581,28588,0,0,28589,0,0,0,
+28590,28595,0,28598,0,0,28601,0,0,28605,0,0,0,0,28614,28615,28619,0,0,0,0,0,0,
+28620,0,28626,0,0,28628,0,28631,0,28632,0,0,0,0,0,0,28635,0,0,0,28637,28638,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28639,0,28643,0,0,28652,0,0,0,28662,0,
+28670,28671,0,0,0,0,0,0,0,0,0,28672,28673,28675,28676,0,0,0,0,0,0,0,28691,0,0,0,
+28695,0,0,0,28696,0,28697,28698,0,28705,0,28707,28708,28710,0,0,0,0,0,0,0,28711,
+28728,0,0,0,28736,0,0,0,28737,0,0,0,0,0,0,0,0,0,28738,0,28739,0,28741,0,0,28742,
+0,0,0,0,0,0,0,0,0,0,0,28745,0,0,0,0,0,0,28749,28750,28752,28754,28756,0,28757,0,
+0,0,0,28759,28760,0,0,0,0,0,0,28762,0,0,0,28764,0,0,0,0,0,0,28766,0,28767,28768,
+0,0,0,0,28769,28770,0,0,0,0,0,0,0,0,0,0,0,0,0,28771,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,28772,0,28773,0,28782,0,0,0,0,0,0,28784,0,28785,0,28786,0,0,0,28787,0,0,0,
+28797,0,0,0,0,0,0,28799,0,0,28801,0,0,0,0,28802,0,28805,0,0,28806,0,0,28807,0,0,
+0,0,0,0,0,28808,0,0,0,0,0,28810,28812,0,0,28816,28819,0,0,28821,0,28826,0,0,0,
+28842,28852,0,0,28853,0,28854,28855,0,0,0,28857,0,0,0,28858,0,28867,28868,28869,
+0,0,0,28874,28880,28882,28890,28892,0,0,0,0,0,0,0,28895,0,0,0,28898,28899,0,0,0,
+28900,0,0,28904,0,28906,0,0,0,0,28907,0,0,0,0,0,0,28908,0,0,0,28910,0,28914,0,0,
+0,0,0,0,0,28915,28916,28919,0,0,28920,0,28921,0,0,0,0,0,0,0,0,28924,0,0,0,0,
+28926,28929,0,0,0,28930,0,28936,0,28939,0,0,0,0,28942,0,0,0,0,0,0,28956,0,0,0,
+28966,0,0,0,0,28967,0,0,0,0,0,0,0,0,0,28968,0,28971,0,28975,28976,0,28982,28983,
+0,0,28984,28989,28996,28997,28998,0,0,0,0,0,0,28999,0,0,0,0,0,29000,0,29001,0,0,
+0,29009,0,0,29011,0,0,29021,0,0,0,0,29024,0,29025,0,0,0,0,0,29026,0,0,0,29036,0,
+0,0,29037,0,0,0,0,29038,0,29045,0,29047,0,0,0,0,0,0,0,0,0,29051,0,0,0,29054,
+29056,29062,0,29070,29082,0,0,0,29083,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29084,0,0,
+0,0,29085,29088,0,0,0,0,0,0,0,29090,29097,0,0,0,29103,0,0,0,0,0,0,0,0,29105,0,0,
+0,0,0,29107,0,29109,0,0,0,29115,0,0,29120,0,0,29138,29140,0,0,0,0,0,0,0,0,0,
+29152,0,29160,29174,0,29176,0,0,29180,0,29181,0,0,0,0,0,0,0,0,29228,0,0,29229,0,
+0,29230,0,0,0,0,0,0,0,0,0,0,29234,0,0,0,29241,0,29245,0,29248,0,29250,29256,
+29280,0,29282,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29285,0,0,29286,29291,29292,0,0,0,0,
+29294,0,29295,0,0,0,0,0,29296,29297,29298,29300,0,29302,0,0,29304,29307,0,29312,
+0,0,0,29322,0,0,29323,0,0,29324,29326,29328,0,29335,0,0,0,0,0,0,0,29338,29339,0,
+0,0,0,0,29341,29343,0,0,0,0,29344,0,0,0,0,0,29345,0,0,0,0,29346,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,29347,29348,29349,0,0,29354,0,0,29355,0,0,0,0,0,0,0,0,29357,0,0,
+0,0,29364,0,29365,0,0,0,0,0,0,0,29366,0,0,29368,0,0,0,0,0,0,0,0,29378,0,29381,0,
+0,0,0,0,0,0,0,29386,0,0,0,0,0,0,29389,0,0,0,29390,0,0,29391,29397,0,29398,29412,
+29414,29418,29419,0,0,0,0,0,0,0,29420,0,0,0,0,0,0,0,29423,0,0,0,29435,0,0,0,
+29437,0,0,29439,0,29441,0,0,0,0,29443,0,29446,29450,29452,0,0,0,0,0,29456,0,0,0,
+0,0,29461,0,0,0,29464,0,0,0,0,0,0,0,0,29468,0,29473,0,0,0,29486,0,0,0,29490,0,0,
+0,29491,29492,0,0,29497,0,0,0,29498,0,29499,0,29502,29505,0,29509,0,0,0,29510,0,
+0,0,29512,0,0,0,29516,0,0,0,0,0,0,0,0,29518,0,29519,0,0,0,0,0,29520,29521,29529,
+0,0,0,0,0,0,0,0,29530,0,0,29531,29538,0,29540,0,0,0,29542,0,29543,29544,29547,0,
+0,29548,0,0,0,29549,0,0,0,29550,0,0,29552,0,0,0,0,29558,29561,0,29562,29564,0,0,
+29565,0,0,29566,0,0,0,0,0,0,0,0,0,0,29578,29584,29586,29591,0,0,0,0,29593,29594,
+0,0,29597,0,0,29613,0,29614,0,29615,0,0,0,0,29616,29617,0,0,29625,0,0,0,29632,0,
+0,0,0,0,0,0,29633,0,0,0,0,0,29634,29635,29637,0,29638,0,29641,29643,0,0,0,0,0,0,
+29644,0,29645,0,29649,0,0,0,29650,0,29653,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29656,
+29659,0,0,29660,0,0,0,29661,0,0,0,0,0,29664,0,0,0,29671,29673,0,0,0,0,0,0,0,
+29675,0,29677,29679,0,0,29684,0,0,0,0,0,29685,0,0,0,29687,0,0,0,29688,0,29689,
+29690,29700,0,29701,0,0,0,29702,0,29706,0,0,0,0,0,0,0,29720,0,29721,0,29727,0,
+29733,29734,0,29750,29761,0,29763,0,0,0,0,0,29764,0,0,29765,0,0,0,29771,0,0,0,0,
+0,0,0,0,0,0,0,0,29772,0,0,0,29773,29774,29775,0,0,0,0,0,0,0,0,0,0,0,29822,0,0,0,
+29824,0,29825,0,0,0,0,0,29827,0,0,0,0,0,0,0,0,29829,0,29832,29834,0,0,29835,0,0,
+29837,29838,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29843,0,0,0,0,29844,29845,0,0,0,
+0,0,0,0,0,0,29849,0,0,29869,29872,29890,29905,0,0,0,0,0,29907,29921,0,29922,0,0,
+29923,29926,29944,29946,0,0,0,0,0,0,0,29947,29948,0,0,0,29951,0,0,0,0,0,29953,0,
+0,29956,0,29957,0,0,29962,0,0,0,0,29971,0,0,0,29972,0,0,0,0,0,29978,0,29979,
+29992,30007,30008,30010,0,0,0,30013,0,0,0,0,30014,30016,0,0,0,0,0,0,0,0,0,0,0,
+30017,0,0,0,0,0,30023,30031,0,0,30033,0,0,0,0,0,0,0,0,0,0,30034,0,30038,0,30039,
+0,30040,0,0,0,0,0,0,30067,30068,0,0,0,30069,0,30072,0,0,0,30073,0,0,0,0,30075,0,
+0,0,0,0,0,30079,0,0,30080,0,0,0,0,0,30082,0,0,0,0,0,0,0,0,0,0,0,30084,30090,0,0,
+30091,0,0,0,0,30098,30118,0,30119,0,30121,30130,0,0,0,0,0,0,0,0,0,0,0,0,0,30131,
+30132,30133,0,0,0,0,0,0,30135,0,0,0,0,0,0,0,0,0,0,0,30136,0,0,30137,30138,0,0,0,
+30139,30146,0,0,0,0,0,30147,0,0,30148,30151,0,0,0,30168,0,30172,30173,0,0,0,0,0,
+0,0,0,30180,30181,0,30192,0,0,0,0,0,0,0,30194,30196,0,0,30199,0,0,30202,0,0,0,0,
+30203,0,0,0,0,0,0,0,0,0,0,30213,0,0,0,30216,0,0,30217,0,0,0,30218,0,0,0,0,30219,
+0,30220,0,30222,30227,0,0,0,0,0,30231,0,0,30233,30235,0,0,0,0,30238,0,30240,
+30243,30245,0,30250,30252,0,0,0,30269,0,0,30271,30272,0,0,0,30278,30280,0,0,
+30282,0,30284,0,30294,0,0,0,0,30295,30296,0,0,0,0,0,30298,30299,30302,30304,
+30306,0,0,0,0,0,0,30316,30317,0,0,0,30318,0,0,0,30319,0,30320,30322,30326,0,0,0,
+0,0,30327,0,30332,30348,30349,0,0,30356,0,0,0,0,0,0,0,0,30357,0,30358,0,30359,
+30360,0,0,30365,30366,30378,0,0,0,0,30379,0,0,30381,0,30385,0,30388,30397,0,0,0,
+30401,0,0,0,0,30403,0,0,0,0,0,30404,0,0,30405,0,30406,30408,0,30409,0,30410,0,0,
+0,30417,0,0,30418,30419,0,30420,0,30424,0,0,0,30427,30430,30432,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,30433,0,0,0,0,0,0,0,30436,0,30437,30438,0,30441,30442,0,0,
+0,30445,0,0,0,0,30452,30456,30457,0,0,0,30458,0,30464,0,0,0,0,0,0,30467,0,30469,
+0,0,0,0,0,30477,0,0,30484,0,0,0,0,0,30485,0,0,0,0,0,30486,30487,30497,30498,0,0,
+0,0,0,0,0,0,0,0,30505,0,30508,0,0,0,30509,30510,0,30514,30516,0,0,0,0,0,0,0,0,0,
+0,0,30523,0,30524,0,30525,0,0,0,0,30537,0,0,30538,0,0,0,0,0,30553,0,0,30555,
+30556,30558,30559,30560,0,0,30561,0,30562,0,0,0,0,0,0,0,0,30563,30570,30571,0,
+30586,30587,0,0,30590,0,0,30594,0,0,0,0,30611,30612,30623,30634,0,0,30636,30640,
+30655,30656,0,30657,0,0,30658,30669,0,30670,0,30676,30678,0,0,0,0,0,0,0,30679,0,
+0,0,0,0,0,0,0,0,0,0,30695,0,0,30698,0,0,0,0,30700,0,0,0,0,30701,0,30702,30703,0,
+0,0,0,30707,0,0,0,30709,0,0,30710,30719,30729,0,0,0,0,0,0,0,0,0,30731,0,0,30733,
+0,0,0,30734,0,0,0,0,0,30736,30737,0,0,0,30740,0,0,0,30743,0,30746,0,30747,30748,
+0,0,30751,30752,30753,0,0,0,30754,0,0,30760,0,0,0,0,0,0,0,30763,0,30764,0,0,
+30766,0,30769,30770,30771,30774,30777,0,0,30779,30780,30781,0,0,0,0,30790,0,0,0,
+30792,0,0,0,0,30810,0,0,0,0,0,0,0,30812,30819,0,0,30823,30824,0,30825,0,30827,0,
+0,0,0,0,0,30828,0,0,30830,0,0,0,30834,0,30835,0,30837,30838,0,30845,0,0,0,0,0,
+30846,30847,0,0,30849,0,30851,0,0,0,0,0,30852,30858,0,0,30859,0,30865,0,0,30866,
+0,0,30868,0,0,30869,0,0,0,30881,30883,0,0,0,0,0,30889,0,30891,0,0,0,0,30894,0,
+30895,0,30897,0,30898,0,0,0,30904,30906,0,30909,0,0,0,0,0,0,30910,0,0,0,30915,
+30933,30942,0,0,0,0,30943,0,0,30945,0,0,0,0,0,0,30946,0,0,30947,0,0,30955,30956,
+0,0,30960,0,0,30961,30962,30966,0,0,30969,30974,0,0,0,30976,0,0,30977,0,30978,
+30982,0,0,0,0,0,0,0,30994,30995,30998,0,31000,0,0,31001,0,0,31003,31005,0,0,
+31006,31011,0,0,31014,0,31016,0,0,0,0,31018,0,0,31020,31023,31024,31025,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,31027,31028,31029,0,0,0,0,0,0,31032,0,0,0,0,0,0,0,0,0,0,0,
+31036,31037,31038,0,0,0,31041,31043,31045,0,31047,0,0,0,31048,0,31049,0,0,0,
+31053,31054,31055,0,0,31063,0,0,0,0,0,31066,0,31068,31071,0,0,0,31072,31073,0,0,
+0,0,31075,0,0,31076,0,0,0,31077,31079,0,31080,0,0,0,0,0,0,0,0,0,0,31087,0,31142,
+0,31144,0,0,31145,31146,31147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31149,0,31151,31152,0,
+0,0,0,0,0,0,31162,31171,31174,31175,0,0,0,31176,0,0,0,0,0,0,0,31179,0,0,0,31186,
+0,0,0,31192,31195,0,0,31196,0,0,0,0,0,0,0,0,31198,0,0,0,0,0,31199,0,0,0,31205,0,
+0,0,0,31211,31215,0,0,0,0,31231,0,31232,0,0,0,0,0,0,0,0,0,0,31233,31236,31253,0,
+31254,0,0,0,0,0,0,31255,0,0,31257,0,0,0,0,0,0,0,0,0,31258,31259,0,0,31260,0,
+31261,0,0,0,0,0,31262,31263,0,0,31264,0,31266,0,31267,0,0,0,0,0,31281,0,31282,0,
+31284,0,0,31285,31287,31288,0,0,31290,0,0,0,31292,31295,0,31299,0,31300,0,0,0,0,
+0,31302,0,0,0,0,31303,0,0,0,0,0,0,31304,0,0,0,0,0,31305,31308,31309,31315,0,
+31317,0,0,0,0,0,31323,0,31324,0,0,0,0,0,31325,31327,0,0,31331,0,0,0,0,0,31333,0,
+0,0,0,0,31336,0,0,31337,0,0,0,0,0,0,31338,0,0,0,0,0,0,0,0,0,0,0,0,31339,0,0,0,0,
+0,0,0,31342,0,0,0,0,31345,0,0,0,0,0,0,0,0,31347,0,0,0,0,0,0,31348,0,0,31350,
+31351,0,31352,0,0,31354,0,0,0,0,31355,0,0,31356,0,0,0,0,0,0,0,0,0,0,31363,0,
+31372,0,0,31373,0,0,0,0,0,0,0,0,0,31376,0,31388,0,31389,0,31392,0,31401,0,31405,
+31407,31408,0,31409,0,0,0,0,0,0,31413,31415,0,0,0,31416,31418,0,0,0,0,0,0,31422,
+31423,0,0,31424,0,31425,31432,0,0,0,0,0,0,0,0,0,31433,0,0,0,0,0,0,0,0,31434,0,0,
+0,0,0,0,31435,0,0,0,0,31438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31442,0,31444,0,
+31448,0,0,31451,0,0,0,0,31452,0,31461,31465,0,0,31466,0,0,31467,0,0,31468,0,0,0,
+31469,31473,0,31476,0,0,0,0,31489,31490,0,0,0,0,0,0,0,31492,31493,31494,0,0,0,0,
+31501,31504,31505,0,0,0,0,0,0,0,0,0,31509,0,0,0,0,31510,0,0,31511,0,0,31513,0,0,
+0,0,0,0,0,0,0,31514,0,31522,31536,31539,31540,0,31541,0,0,0,0,0,0,31546,31553,
+31559,0,0,0,31560,31561,31562,0,0,31564,31567,0,31569,0,0,0,31570,0,0,0,0,31571,
+0,0,0,0,0,0,31572,31574,31580,31581,0,0,31582,31584,31585,31586,31595,0,31596,0,
+0,0,0,31597,0,31599,0,31600,31601,0,0,31603,31604,0,0,31608,31610,0,0,0,31611,0,
+31615,0,0,0,0,31616,0,0,0,0,0,0,31617,0,0,0,0,0,31618,0,0,0,0,0,0,31621,0,0,0,0,
+0,0,0,0,0,31622,31625,0,0,0,0,31627,0,31641,0,0,31642,0,0,31643,0,0,0,0,0,0,0,0,
+0,31644,0,31646,0,0,0,0,31648,0,0,0,31652,0,0,0,31657,0,0,31676,0,0,0,0,0,0,0,
+31689,31691,31692,0,31694,0,0,0,31696,0,31702,0,31703,0};
+
+static const DictWord kStaticDictionaryWords[31705] = {
+{0,0,0},{8,0,1002},{136,0,1015},{4,0,683},{4,10,325},{138,10,125},{7,11,572},{9,
+11,592},{11,11,680},{11,11,842},{11,11,924},{12,11,356},{12,11,550},{13,11,317},
+{13,11,370},{13,11,469},{13,11,471},{14,11,397},{18,11,69},{146,11,145},{134,0,
+1265},{136,11,534},{134,0,1431},{11,0,138},{140,0,40},{4,0,155},{7,0,1689},{4,10
+,718},{135,10,1216},{4,0,245},{5,0,151},{5,0,741},{6,0,1147},{7,0,498},{7,0,870}
+,{7,0,1542},{12,0,213},{14,0,36},{14,0,391},{17,0,111},{18,0,6},{18,0,46},{18,0,
+151},{19,0,36},{20,0,32},{20,0,56},{20,0,69},{20,0,102},{21,0,4},{22,0,8},{22,0,
+10},{22,0,14},{150,0,31},{4,0,624},{135,0,1752},{5,10,124},{5,10,144},{6,10,548}
+,{7,10,15},{7,10,153},{137,10,629},{6,0,503},{9,0,586},{13,0,468},{14,0,66},{16,
+0,58},{7,10,1531},{8,10,416},{9,10,275},{10,10,100},{11,10,658},{11,10,979},{12,
+10,86},{14,10,207},{15,10,20},{143,10,25},{5,0,603},{7,0,1212},{9,0,565},{14,0,
+301},{5,10,915},{6,10,1783},{7,10,211},{7,10,1353},{9,10,83},{10,10,376},{10,10,
+431},{11,10,543},{12,10,664},{13,10,280},{13,10,428},{14,10,128},{17,10,52},{145
+,10,81},{4,0,492},{133,0,451},{135,0,835},{141,0,70},{132,0,539},{7,11,748},{139
+,11,700},{7,11,1517},{11,11,597},{14,11,76},{14,11,335},{148,11,33},{6,0,113},{
+135,0,436},{4,10,338},{133,10,400},{136,0,718},{133,11,127},{133,11,418},{6,0,
+1505},{7,0,520},{6,11,198},{11,10,892},{140,11,83},{4,10,221},{5,10,659},{5,10,
+989},{7,10,697},{7,10,1211},{138,10,284},{135,0,1070},{5,11,276},{6,11,55},{135,
+11,1369},{134,0,1515},{6,11,1752},{136,11,726},{138,10,507},{15,0,78},{4,10,188}
+,{135,10,805},{5,10,884},{139,10,991},{133,11,764},{134,10,1653},{6,11,309},{7,
+11,331},{138,11,550},{135,11,1861},{132,11,348},{135,11,986},{135,11,1573},{12,0
+,610},{13,0,431},{144,0,59},{9,11,799},{140,10,166},{134,0,1530},{132,0,750},{
+132,0,307},{133,0,964},{6,11,194},{7,11,133},{10,11,493},{10,11,570},{139,11,664
+},{5,11,24},{5,11,569},{6,11,3},{6,11,119},{6,11,143},{6,11,440},{7,11,295},{7,
+11,599},{7,11,1686},{7,11,1854},{8,11,424},{9,11,43},{9,11,584},{9,11,760},{10,
+11,148},{10,11,328},{11,11,159},{11,11,253},{11,11,506},{12,11,487},{12,11,531},
+{144,11,33},{136,10,760},{5,11,14},{5,11,892},{6,11,283},{7,11,234},{136,11,537}
+,{135,11,1251},{4,11,126},{8,11,635},{147,11,34},{4,11,316},{135,11,1561},{6,0,
+999},{6,0,1310},{137,11,861},{4,11,64},{5,11,352},{5,11,720},{6,11,368},{139,11,
+359},{4,0,75},{5,0,180},{6,0,500},{7,0,58},{7,0,710},{10,0,645},{136,10,770},{
+133,0,649},{6,0,276},{7,0,282},{7,0,879},{7,0,924},{8,0,459},{9,0,599},{9,0,754}
+,{11,0,574},{12,0,128},{12,0,494},{13,0,52},{13,0,301},{15,0,30},{143,0,132},{
+132,0,200},{4,10,89},{5,10,489},{6,10,315},{7,10,553},{7,10,1745},{138,10,243},{
+135,11,1050},{7,0,1621},{6,10,1658},{9,10,3},{10,10,154},{11,10,641},{13,10,85},
+{13,10,201},{141,10,346},{6,11,175},{137,11,289},{5,11,432},{133,11,913},{6,0,
+225},{137,0,211},{7,0,718},{8,0,687},{139,0,374},{4,10,166},{133,10,505},{9,0,
+110},{134,10,1670},{8,0,58},{9,0,724},{11,0,809},{13,0,113},{145,0,72},{6,0,345}
+,{7,0,1247},{144,11,82},{5,11,931},{134,11,1698},{8,0,767},{8,0,803},{9,0,301},{
+137,0,903},{139,0,203},{134,0,1154},{7,0,1949},{136,0,674},{134,0,259},{135,0,
+1275},{5,11,774},{6,11,1637},{6,11,1686},{134,11,1751},{134,0,1231},{7,10,445},{
+8,10,307},{8,10,704},{10,10,41},{10,10,439},{11,10,237},{11,10,622},{140,10,201}
+,{136,0,254},{6,11,260},{135,11,1484},{139,0,277},{135,10,1977},{4,10,189},{5,10
+,713},{6,11,573},{136,10,57},{138,10,371},{132,10,552},{134,11,344},{133,0,248},
+{9,0,800},{10,0,693},{11,0,482},{11,0,734},{11,0,789},{134,11,240},{4,0,116},{5,
+0,95},{5,0,445},{7,0,1688},{8,0,29},{9,0,272},{11,0,509},{11,0,915},{4,11,292},{
+4,11,736},{5,11,871},{6,11,171},{6,11,1689},{7,11,1324},{7,11,1944},{9,11,415},{
+9,11,580},{14,11,230},{146,11,68},{7,0,490},{13,0,100},{143,0,75},{135,0,1641},{
+133,0,543},{7,11,209},{8,11,661},{10,11,42},{11,11,58},{12,11,58},{12,11,118},{
+141,11,32},{5,0,181},{8,0,41},{6,11,63},{135,11,920},{133,0,657},{133,11,793},{
+138,0,709},{7,0,25},{8,0,202},{138,0,536},{5,11,665},{135,10,1788},{145,10,49},{
+9,0,423},{140,0,89},{5,11,67},{6,11,62},{6,11,374},{135,11,1391},{8,0,113},{9,0,
+877},{10,0,554},{11,0,83},{12,0,136},{19,0,109},{9,11,790},{140,11,47},{138,10,
+661},{4,0,963},{10,0,927},{14,0,442},{135,10,1945},{133,0,976},{132,0,206},{4,11
+,391},{135,11,1169},{134,0,2002},{6,0,696},{134,0,1008},{134,0,1170},{132,11,271
+},{7,0,13},{8,0,226},{10,0,537},{11,0,570},{11,0,605},{11,0,799},{11,0,804},{12,
+0,85},{12,0,516},{12,0,623},{13,0,112},{13,0,361},{14,0,77},{14,0,78},{17,0,28},
+{19,0,110},{140,11,314},{132,0,769},{134,0,1544},{4,0,551},{137,0,678},{5,10,84}
+,{134,10,163},{9,0,57},{9,0,459},{10,0,425},{11,0,119},{12,0,184},{12,0,371},{13
+,0,358},{145,0,51},{5,0,188},{5,0,814},{8,0,10},{9,0,421},{9,0,729},{10,0,609},{
+11,0,689},{4,11,253},{5,10,410},{5,11,544},{7,11,300},{137,11,340},{134,0,624},{
+138,11,321},{135,0,1941},{18,0,130},{5,10,322},{8,10,186},{9,10,262},{10,10,187}
+,{142,10,208},{5,11,53},{5,11,541},{6,11,94},{6,11,499},{7,11,230},{139,11,321},
+{133,10,227},{4,0,378},{4,11,920},{5,11,25},{5,11,790},{6,11,457},{135,11,853},{
+137,0,269},{132,0,528},{134,0,1146},{7,10,1395},{8,10,486},{9,10,236},{9,10,878}
+,{10,10,218},{11,10,95},{19,10,17},{147,10,31},{7,10,2043},{8,10,672},{141,10,
+448},{134,0,1105},{134,0,1616},{134,11,1765},{140,11,163},{5,10,412},{133,11,822
+},{132,11,634},{6,0,656},{134,11,1730},{134,0,1940},{5,0,104},{6,0,173},{135,0,
+1631},{136,10,562},{6,11,36},{7,11,658},{8,11,454},{147,11,86},{5,0,457},{134,10
+,1771},{7,0,810},{8,0,138},{8,0,342},{9,0,84},{10,0,193},{11,0,883},{140,0,359},
+{9,0,620},{135,10,1190},{137,10,132},{7,11,975},{137,11,789},{6,0,95},{6,0,1934}
+,{136,0,967},{141,11,335},{6,0,406},{10,0,409},{10,0,447},{11,0,44},{140,0,100},
+{4,10,317},{135,10,1279},{132,0,477},{134,0,1268},{6,0,1941},{8,0,944},{5,10,63}
+,{133,10,509},{132,0,629},{132,11,104},{4,0,246},{133,0,375},{6,0,1636},{132,10,
+288},{135,11,1614},{9,0,49},{10,0,774},{8,10,89},{8,10,620},{11,10,628},{12,10,
+322},{143,10,124},{4,0,282},{7,0,1034},{11,0,398},{11,0,634},{12,0,1},{12,0,79},
+{12,0,544},{14,0,237},{17,0,10},{146,0,20},{132,0,824},{7,11,45},{9,11,542},{9,
+11,566},{138,11,728},{5,0,118},{5,0,499},{6,0,476},{6,0,665},{6,0,1176},{6,0,
+1196},{7,0,600},{7,0,888},{135,0,1096},{7,0,296},{7,0,596},{8,0,560},{8,0,586},{
+9,0,612},{11,0,304},{12,0,46},{13,0,89},{14,0,112},{145,0,122},{5,0,894},{6,0,
+1772},{9,0,1009},{138,10,120},{5,11,533},{7,11,755},{138,11,780},{151,10,1},{6,0
+,1474},{7,11,87},{142,11,288},{139,0,366},{137,10,461},{7,11,988},{7,11,1939},{9
+,11,64},{9,11,502},{12,11,7},{12,11,34},{13,11,12},{13,11,234},{147,11,77},{7,0,
+1599},{7,0,1723},{8,0,79},{8,0,106},{8,0,190},{8,0,302},{8,0,383},{8,0,713},{9,0
+,119},{9,0,233},{9,0,419},{9,0,471},{10,0,181},{10,0,406},{11,0,57},{11,0,85},{
+11,0,120},{11,0,177},{11,0,296},{11,0,382},{11,0,454},{11,0,758},{11,0,999},{12,
+0,27},{12,0,98},{12,0,131},{12,0,245},{12,0,312},{12,0,446},{12,0,454},{13,0,25}
+,{13,0,98},{13,0,426},{13,0,508},{14,0,70},{14,0,163},{14,0,272},{14,0,277},{14,
+0,370},{15,0,95},{15,0,138},{15,0,167},{17,0,38},{148,0,96},{135,10,1346},{10,0,
+200},{19,0,2},{151,0,22},{135,11,141},{134,10,85},{134,0,1759},{138,0,372},{145,
+0,16},{8,0,943},{132,11,619},{139,11,88},{5,11,246},{8,11,189},{9,11,355},{9,11,
+512},{10,11,124},{10,11,453},{11,11,143},{11,11,416},{11,11,859},{141,11,341},{5
+,0,258},{134,0,719},{6,0,1798},{6,0,1839},{8,0,900},{10,0,874},{10,0,886},{12,0,
+698},{12,0,732},{12,0,770},{16,0,106},{18,0,163},{18,0,170},{18,0,171},{152,0,20
+},{9,0,707},{11,0,326},{11,0,339},{12,0,423},{12,0,502},{20,0,62},{9,11,707},{11
+,11,326},{11,11,339},{12,11,423},{12,11,502},{148,11,62},{5,0,30},{7,0,495},{8,0
+,134},{9,0,788},{140,0,438},{133,11,678},{5,10,279},{6,10,235},{7,10,468},{8,10,
+446},{9,10,637},{10,10,717},{11,10,738},{140,10,514},{5,11,35},{6,11,287},{7,11,
+862},{7,11,1886},{138,11,179},{7,0,1948},{7,0,2004},{132,11,517},{5,10,17},{6,10
+,371},{137,10,528},{4,0,115},{5,0,669},{6,0,407},{8,0,311},{11,0,10},{141,0,5},{
+137,0,381},{5,0,50},{6,0,439},{7,0,780},{135,0,1040},{136,11,667},{11,11,403},{
+146,11,83},{5,0,1},{6,0,81},{138,0,520},{134,0,738},{5,0,482},{8,0,98},{9,0,172}
+,{10,0,360},{10,0,700},{10,0,822},{11,0,302},{11,0,778},{12,0,50},{12,0,127},{12
+,0,396},{13,0,62},{13,0,328},{14,0,122},{147,0,72},{9,11,157},{10,11,131},{140,
+11,72},{135,11,714},{135,11,539},{5,0,2},{6,0,512},{7,0,797},{7,0,1494},{8,0,253
+},{8,0,589},{9,0,77},{10,0,1},{10,0,129},{10,0,225},{11,0,118},{11,0,226},{11,0,
+251},{11,0,430},{11,0,701},{11,0,974},{11,0,982},{12,0,64},{12,0,260},{12,0,488}
+,{140,0,690},{5,11,394},{7,11,367},{7,11,487},{7,11,857},{7,11,1713},{8,11,246},
+{9,11,537},{10,11,165},{12,11,219},{140,11,561},{136,0,557},{5,10,779},{5,10,807
+},{6,10,1655},{134,10,1676},{4,10,196},{5,10,558},{133,10,949},{11,11,827},{12,
+11,56},{14,11,34},{143,11,148},{137,0,347},{133,0,572},{134,0,832},{4,0,12},{7,0
+,504},{7,0,522},{7,0,809},{8,0,797},{141,0,88},{4,10,752},{133,11,449},{7,11,86}
+,{8,11,103},{145,11,69},{7,11,2028},{138,11,641},{5,0,528},{6,11,1},{142,11,2},{
+134,0,861},{10,0,294},{4,10,227},{5,10,159},{5,10,409},{7,10,80},{10,10,479},{12
+,10,418},{14,10,50},{14,10,249},{142,10,295},{7,10,1470},{8,10,66},{8,10,137},{8
+,10,761},{9,10,638},{11,10,80},{11,10,212},{11,10,368},{11,10,418},{12,10,8},{13
+,10,15},{16,10,61},{17,10,59},{19,10,28},{148,10,84},{20,0,109},{135,11,1148},{6
+,11,277},{7,11,1274},{7,11,1386},{7,11,1392},{12,11,129},{146,11,87},{6,11,187},
+{7,11,39},{7,11,1203},{8,11,380},{8,11,542},{14,11,117},{149,11,28},{134,0,1187}
+,{5,0,266},{9,0,290},{9,0,364},{10,0,293},{11,0,606},{142,0,45},{6,11,297},{7,11
+,793},{139,11,938},{4,0,50},{6,0,594},{9,0,121},{10,0,49},{10,0,412},{139,0,834}
+,{136,0,748},{7,11,464},{8,11,438},{11,11,105},{11,11,363},{12,11,231},{14,11,
+386},{15,11,102},{148,11,75},{132,0,466},{13,0,399},{14,0,337},{6,10,38},{7,10,
+1220},{8,10,185},{8,10,256},{9,10,22},{9,10,331},{10,10,738},{11,10,205},{11,10,
+540},{11,10,746},{13,10,465},{142,10,194},{9,0,378},{141,0,162},{137,0,519},{4,
+10,159},{6,10,115},{7,10,252},{7,10,257},{7,10,1928},{8,10,69},{9,10,384},{10,10
+,91},{10,10,615},{12,10,375},{14,10,235},{18,10,117},{147,10,123},{5,11,604},{5,
+10,911},{136,10,278},{132,0,667},{8,0,351},{9,0,322},{4,10,151},{135,10,1567},{
+134,0,902},{133,10,990},{12,0,180},{5,10,194},{7,10,1662},{137,10,90},{4,0,869},
+{134,0,1996},{134,0,813},{133,10,425},{137,11,761},{132,0,260},{133,10,971},{5,
+11,20},{6,11,298},{7,11,659},{7,11,1366},{137,11,219},{4,0,39},{5,0,36},{7,0,
+1843},{8,0,407},{11,0,144},{140,0,523},{4,0,510},{10,0,587},{139,10,752},{7,0,29
+},{7,0,66},{7,0,1980},{10,0,487},{138,0,809},{13,0,260},{14,0,82},{18,0,63},{137
+,10,662},{5,10,72},{6,10,264},{7,10,21},{7,10,46},{7,10,2013},{8,10,215},{8,10,
+513},{10,10,266},{139,10,22},{134,0,570},{6,0,565},{7,0,1667},{4,11,439},{10,10,
+95},{11,10,603},{12,11,242},{13,10,443},{14,10,160},{143,10,4},{134,0,1464},{134
+,10,431},{9,0,372},{15,0,2},{19,0,10},{19,0,18},{5,10,874},{6,10,1677},{143,10,0
+},{132,0,787},{6,0,380},{12,0,399},{21,0,19},{7,10,939},{7,10,1172},{7,10,1671},
+{9,10,540},{10,10,696},{11,10,265},{11,10,732},{11,10,928},{11,10,937},{141,10,
+438},{137,0,200},{132,11,233},{132,0,516},{134,11,577},{132,0,844},{11,0,887},{
+14,0,365},{142,0,375},{132,11,482},{8,0,821},{140,0,44},{7,0,1655},{136,0,305},{
+5,10,682},{135,10,1887},{135,11,346},{132,10,696},{4,0,10},{7,0,917},{139,0,786}
+,{5,11,795},{6,11,1741},{8,11,417},{137,11,782},{4,0,1016},{134,0,2031},{5,0,684
+},{4,10,726},{133,10,630},{6,0,1021},{134,0,1480},{8,10,802},{136,10,838},{134,0
+,27},{134,0,395},{135,11,622},{7,11,625},{135,11,1750},{4,11,203},{135,11,1936},
+{6,10,118},{7,10,215},{7,10,1521},{140,10,11},{132,0,813},{136,0,511},{7,10,615}
+,{138,10,251},{135,10,1044},{145,0,56},{133,10,225},{6,0,342},{6,0,496},{8,0,275
+},{137,0,206},{4,0,909},{133,0,940},{132,0,891},{7,11,311},{9,11,308},{140,11,
+255},{4,10,370},{5,10,756},{135,10,1326},{4,0,687},{134,0,1596},{134,0,1342},{6,
+10,1662},{7,10,48},{8,10,771},{10,10,116},{13,10,104},{14,10,105},{14,10,184},{
+15,10,168},{19,10,92},{148,10,68},{138,10,209},{4,11,400},{5,11,267},{135,11,232
+},{151,11,12},{6,0,41},{141,0,160},{141,11,314},{134,0,1718},{136,0,778},{142,11
+,261},{134,0,1610},{133,0,115},{132,0,294},{14,0,314},{132,10,120},{132,0,983},{
+5,0,193},{140,0,178},{138,10,429},{5,10,820},{135,10,931},{6,0,994},{6,0,1051},{
+6,0,1439},{7,0,174},{133,11,732},{4,11,100},{7,11,679},{8,11,313},{138,10,199},{
+6,10,151},{6,10,1675},{7,10,383},{151,10,10},{6,0,1796},{8,0,848},{8,0,867},{8,0
+,907},{10,0,855},{140,0,703},{140,0,221},{4,0,122},{5,0,796},{5,0,952},{6,0,1660
+},{6,0,1671},{8,0,567},{9,0,687},{9,0,742},{10,0,686},{11,0,682},{11,0,909},{140
+,0,281},{5,11,362},{5,11,443},{6,11,318},{7,11,1019},{139,11,623},{5,11,463},{
+136,11,296},{11,0,583},{13,0,262},{6,10,1624},{12,10,422},{142,10,360},{5,0,179}
+,{7,0,1095},{135,0,1213},{4,10,43},{4,11,454},{5,10,344},{133,10,357},{4,0,66},{
+7,0,722},{135,0,904},{134,0,773},{7,0,352},{133,10,888},{5,11,48},{5,11,404},{6,
+11,557},{7,11,458},{8,11,597},{10,11,455},{10,11,606},{11,11,49},{11,11,548},{12
+,11,476},{13,11,18},{141,11,450},{134,11,418},{132,10,711},{5,11,442},{135,11,
+1984},{141,0,35},{137,0,152},{134,0,1197},{135,11,1093},{137,11,203},{137,10,440
+},{10,0,592},{10,0,753},{12,0,317},{12,0,355},{12,0,465},{12,0,469},{12,0,560},{
+12,0,578},{141,0,243},{133,0,564},{134,0,797},{5,10,958},{133,10,987},{5,11,55},
+{7,11,376},{140,11,161},{133,11,450},{134,0,556},{134,0,819},{11,10,276},{142,10
+,293},{7,0,544},{138,0,61},{8,0,719},{4,10,65},{5,10,479},{5,10,1004},{7,10,1913
+},{8,10,317},{9,10,302},{10,10,612},{141,10,22},{4,0,5},{5,0,498},{8,0,637},{9,0
+,521},{4,11,213},{4,10,261},{7,11,223},{7,10,510},{136,11,80},{5,0,927},{7,0,101
+},{4,10,291},{7,11,381},{7,11,806},{7,11,820},{8,11,354},{8,11,437},{8,11,787},{
+9,10,515},{9,11,657},{10,11,58},{10,11,339},{10,11,749},{11,11,914},{12,10,152},
+{12,11,162},{12,10,443},{13,11,75},{13,10,392},{14,11,106},{14,11,198},{14,11,
+320},{14,10,357},{14,11,413},{146,11,43},{6,0,1153},{7,0,1441},{136,11,747},{4,0
+,893},{5,0,780},{133,0,893},{138,11,654},{133,11,692},{133,0,238},{134,11,191},{
+4,10,130},{135,10,843},{6,0,1296},{5,10,42},{5,10,879},{7,10,245},{7,10,324},{7,
+10,1532},{11,10,463},{11,10,472},{13,10,363},{144,10,52},{134,0,1729},{6,0,1999}
+,{136,0,969},{4,10,134},{133,10,372},{4,0,60},{7,0,941},{7,0,1800},{8,0,314},{9,
+0,700},{139,0,487},{134,0,1144},{6,11,162},{7,11,1960},{136,11,831},{132,11,706}
+,{135,0,1147},{138,11,426},{138,11,89},{7,0,1853},{138,0,437},{136,0,419},{135,
+10,1634},{133,0,828},{5,0,806},{7,0,176},{7,0,178},{7,0,1240},{7,0,1976},{132,10
+,644},{135,11,1877},{5,11,420},{135,11,1449},{4,0,51},{5,0,39},{6,0,4},{7,0,591}
+,{7,0,849},{7,0,951},{7,0,1613},{7,0,1760},{7,0,1988},{9,0,434},{10,0,754},{11,0
+,25},{139,0,37},{10,11,57},{138,11,277},{135,10,540},{132,11,204},{135,0,159},{
+139,11,231},{133,0,902},{7,0,928},{7,11,366},{9,11,287},{12,11,199},{12,11,556},
+{140,11,577},{6,10,623},{136,10,789},{4,10,908},{5,10,359},{5,10,508},{6,10,1723
+},{7,10,343},{7,10,1996},{135,10,2026},{134,0,270},{4,10,341},{135,10,480},{5,11
+,356},{135,11,224},{11,11,588},{11,11,864},{11,11,968},{143,11,160},{132,0,556},
+{137,0,801},{132,0,416},{142,0,372},{5,0,152},{5,0,197},{7,0,340},{7,0,867},{10,
+0,548},{10,0,581},{11,0,6},{12,0,3},{12,0,19},{14,0,110},{142,0,289},{139,0,369}
+,{7,11,630},{9,11,567},{11,11,150},{11,11,444},{141,11,119},{134,11,539},{7,10,
+1995},{8,10,299},{11,10,890},{140,10,674},{7,0,34},{7,0,190},{8,0,28},{8,0,141},
+{8,0,444},{8,0,811},{9,0,468},{11,0,334},{12,0,24},{12,0,386},{140,0,576},{133,0
+,757},{7,0,1553},{136,0,898},{133,0,721},{136,0,1012},{4,0,789},{5,0,647},{135,0
+,1102},{132,0,898},{10,0,183},{4,10,238},{5,10,503},{6,10,179},{7,10,2003},{8,10
+,381},{8,10,473},{9,10,149},{10,10,788},{15,10,45},{15,10,86},{20,10,110},{150,
+10,57},{9,0,136},{19,0,107},{4,10,121},{5,10,156},{5,10,349},{10,10,605},{142,10
+,342},{4,11,235},{135,11,255},{4,11,194},{5,11,584},{6,11,384},{7,11,583},{10,11
+,761},{11,11,760},{139,11,851},{6,10,80},{6,10,1694},{7,10,173},{7,10,1974},{9,
+10,547},{10,10,730},{14,10,18},{150,10,39},{4,10,923},{134,10,1711},{5,0,277},{
+141,0,247},{132,0,435},{133,11,562},{134,0,1311},{5,11,191},{137,11,271},{132,10
+,595},{7,11,1537},{14,11,96},{143,11,73},{5,0,437},{7,0,502},{7,0,519},{7,0,1122
+},{7,0,1751},{14,0,211},{6,10,459},{7,10,1753},{7,10,1805},{8,10,658},{9,10,1},{
+11,10,959},{141,10,446},{6,0,814},{4,11,470},{5,11,473},{6,11,153},{7,11,1503},{
+7,11,1923},{10,11,701},{11,11,132},{11,11,168},{11,11,227},{11,11,320},{11,11,
+436},{11,11,525},{11,11,855},{12,11,41},{12,11,286},{13,11,103},{13,11,284},{14,
+11,255},{14,11,262},{15,11,117},{143,11,127},{5,0,265},{6,0,212},{135,0,28},{138
+,0,750},{133,11,327},{6,11,552},{7,11,1754},{137,11,604},{134,0,2012},{132,0,702
+},{5,11,80},{6,11,405},{7,11,403},{7,11,1502},{7,11,1626},{8,11,456},{9,11,487},
+{9,11,853},{9,11,889},{10,11,309},{11,11,721},{11,11,994},{12,11,430},{141,11,
+165},{5,0,808},{135,0,2045},{5,0,166},{8,0,739},{140,0,511},{134,10,490},{4,11,
+453},{5,11,887},{6,11,535},{8,11,6},{136,11,543},{4,0,119},{5,0,170},{5,0,447},{
+7,0,1708},{7,0,1889},{9,0,357},{9,0,719},{12,0,486},{140,0,596},{137,0,500},{7,
+10,250},{136,10,507},{132,10,158},{6,0,809},{134,0,1500},{9,0,327},{11,0,350},{
+11,0,831},{13,0,352},{4,10,140},{7,10,362},{8,10,209},{9,10,10},{9,10,503},{9,10
+,614},{10,10,689},{11,10,327},{11,10,725},{12,10,252},{12,10,583},{13,10,192},{
+14,10,269},{14,10,356},{148,10,50},{135,11,741},{4,0,450},{7,0,1158},{19,10,1},{
+19,10,26},{150,10,9},{6,0,597},{135,0,1318},{134,0,1602},{6,10,228},{7,10,1341},
+{9,10,408},{138,10,343},{7,0,1375},{7,0,1466},{138,0,331},{132,0,754},{132,10,
+557},{5,11,101},{6,11,88},{6,11,543},{7,11,1677},{9,11,100},{10,11,677},{14,11,
+169},{14,11,302},{14,11,313},{15,11,48},{143,11,84},{134,0,1368},{4,11,310},{9,
+11,795},{10,11,733},{11,11,451},{12,11,249},{14,11,115},{14,11,286},{143,11,100}
+,{132,10,548},{10,0,557},{7,10,197},{8,10,142},{8,10,325},{9,10,150},{9,10,596},
+{10,10,353},{11,10,74},{11,10,315},{12,10,662},{12,10,681},{14,10,423},{143,10,
+141},{133,11,587},{5,0,850},{136,0,799},{10,0,908},{12,0,701},{12,0,757},{142,0,
+466},{4,0,62},{5,0,275},{18,0,19},{6,10,399},{6,10,579},{7,10,692},{7,10,846},{7
+,10,1015},{7,10,1799},{8,10,403},{9,10,394},{10,10,133},{12,10,4},{12,10,297},{
+12,10,452},{16,10,81},{18,10,25},{21,10,14},{22,10,12},{151,10,18},{12,0,459},{7
+,10,1546},{11,10,299},{142,10,407},{132,10,177},{132,11,498},{7,11,217},{8,11,
+140},{138,11,610},{5,10,411},{135,10,653},{134,0,1802},{7,10,439},{10,10,727},{
+11,10,260},{139,10,684},{133,11,905},{11,11,580},{142,11,201},{134,0,1397},{5,10
+,208},{7,10,753},{135,10,1528},{7,0,238},{7,0,2033},{8,0,120},{8,0,188},{8,0,659
+},{9,0,598},{10,0,466},{12,0,342},{12,0,588},{13,0,503},{14,0,246},{143,0,92},{
+135,11,1041},{4,11,456},{7,11,105},{7,11,358},{7,11,1637},{8,11,643},{139,11,483
+},{6,0,1318},{134,0,1324},{4,0,201},{7,0,1744},{8,0,602},{11,0,247},{11,0,826},{
+17,0,65},{133,10,242},{8,0,164},{146,0,62},{133,10,953},{139,10,802},{133,0,615}
+,{7,11,1566},{8,11,269},{9,11,212},{9,11,718},{14,11,15},{14,11,132},{142,11,227
+},{133,10,290},{132,10,380},{5,10,52},{7,10,277},{9,10,368},{139,10,791},{135,0,
+1243},{133,11,539},{11,11,919},{141,11,409},{136,0,968},{133,11,470},{134,0,882}
+,{132,0,907},{5,0,100},{10,0,329},{12,0,416},{149,0,29},{10,10,138},{139,10,476}
+,{5,10,725},{5,10,727},{6,11,91},{7,11,435},{135,10,1811},{4,11,16},{5,11,316},{
+5,11,842},{6,11,370},{6,11,1778},{8,11,166},{11,11,812},{12,11,206},{12,11,351},
+{14,11,418},{16,11,15},{16,11,34},{18,11,3},{19,11,3},{19,11,7},{20,11,4},{149,
+11,21},{132,0,176},{5,0,636},{5,0,998},{7,0,9},{7,0,1508},{8,0,26},{9,0,317},{9,
+0,358},{10,0,210},{10,0,292},{10,0,533},{11,0,555},{12,0,526},{12,0,607},{13,0,
+263},{13,0,459},{142,0,271},{6,0,256},{8,0,265},{4,10,38},{7,10,307},{7,10,999},
+{7,10,1481},{7,10,1732},{7,10,1738},{9,10,414},{11,10,316},{12,10,52},{13,10,420
+},{147,10,100},{135,10,1296},{4,11,611},{133,11,606},{4,0,643},{142,11,21},{133,
+11,715},{133,10,723},{6,0,610},{135,11,597},{10,0,127},{141,0,27},{6,0,1995},{6,
+0,2001},{8,0,119},{136,0,973},{4,11,149},{138,11,368},{12,0,522},{4,11,154},{5,
+10,109},{6,10,1784},{7,11,1134},{7,10,1895},{8,11,105},{12,10,296},{140,10,302},
+{4,11,31},{6,11,429},{7,11,962},{9,11,458},{139,11,691},{10,0,553},{11,0,876},{
+13,0,193},{13,0,423},{14,0,166},{19,0,84},{4,11,312},{5,10,216},{7,10,1879},{9,
+10,141},{9,10,270},{9,10,679},{10,10,159},{11,10,197},{12,10,538},{12,10,559},{
+14,10,144},{14,10,167},{143,10,67},{134,0,1582},{7,0,1578},{135,11,1578},{137,10
+,81},{132,11,236},{134,10,391},{134,0,795},{7,10,322},{136,10,249},{5,11,836},{5
+,11,857},{6,11,1680},{7,11,59},{147,11,53},{135,0,432},{10,11,68},{139,11,494},{
+4,11,81},{139,11,867},{7,0,126},{136,0,84},{142,11,280},{5,11,282},{8,11,650},{9
+,11,295},{9,11,907},{138,11,443},{136,0,790},{5,10,632},{138,10,526},{6,0,64},{
+12,0,377},{13,0,309},{14,0,141},{14,0,429},{14,11,141},{142,11,429},{134,0,1529}
+,{6,0,321},{7,0,1857},{9,0,530},{19,0,99},{7,10,948},{7,10,1042},{8,10,235},{8,
+10,461},{9,10,453},{10,10,354},{145,10,77},{7,0,1104},{11,0,269},{11,0,539},{11,
+0,627},{11,0,706},{11,0,975},{12,0,248},{12,0,434},{12,0,600},{12,0,622},{13,0,
+297},{13,0,485},{14,0,69},{14,0,409},{143,0,108},{4,10,362},{7,10,52},{7,10,303}
+,{10,11,70},{12,11,26},{14,11,17},{14,11,178},{15,11,34},{149,11,12},{11,0,977},
+{141,0,507},{9,0,34},{139,0,484},{5,10,196},{6,10,486},{7,10,212},{8,10,309},{
+136,10,346},{6,0,1700},{7,0,26},{7,0,293},{7,0,382},{7,0,1026},{7,0,1087},{7,0,
+2027},{8,0,24},{8,0,114},{8,0,252},{8,0,727},{8,0,729},{9,0,30},{9,0,199},{9,0,
+231},{9,0,251},{9,0,334},{9,0,361},{9,0,712},{10,0,55},{10,0,60},{10,0,232},{10,
+0,332},{10,0,384},{10,0,396},{10,0,504},{10,0,542},{10,0,652},{11,0,20},{11,0,48
+},{11,0,207},{11,0,291},{11,0,298},{11,0,342},{11,0,365},{11,0,394},{11,0,620},{
+11,0,705},{11,0,1017},{12,0,123},{12,0,340},{12,0,406},{12,0,643},{13,0,61},{13,
+0,269},{13,0,311},{13,0,319},{13,0,486},{14,0,234},{15,0,62},{15,0,85},{16,0,71}
+,{18,0,119},{20,0,105},{135,10,1912},{4,11,71},{5,11,376},{7,11,119},{138,11,665
+},{10,0,918},{10,0,926},{4,10,686},{136,11,55},{138,10,625},{136,10,706},{132,11
+,479},{4,10,30},{133,10,43},{6,0,379},{7,0,270},{8,0,176},{8,0,183},{9,0,432},{9
+,0,661},{12,0,247},{12,0,617},{18,0,125},{7,11,607},{8,11,99},{152,11,4},{5,0,
+792},{133,0,900},{4,11,612},{133,11,561},{4,11,41},{4,10,220},{5,11,74},{7,10,
+1535},{7,11,1627},{11,11,871},{140,11,619},{135,0,1920},{7,11,94},{11,11,329},{
+11,11,965},{12,11,241},{14,11,354},{15,11,22},{148,11,63},{9,11,209},{137,11,300
+},{134,0,771},{135,0,1979},{4,0,901},{133,0,776},{142,0,254},{133,11,98},{9,11,
+16},{141,11,386},{133,11,984},{4,11,182},{6,11,205},{135,11,220},{7,10,1725},{7,
+10,1774},{138,10,393},{5,10,263},{134,10,414},{4,11,42},{9,11,205},{9,11,786},{
+138,11,659},{14,0,140},{148,0,41},{8,0,440},{10,0,359},{6,10,178},{6,11,289},{6,
+10,1750},{7,11,1670},{9,10,690},{10,10,155},{10,10,373},{11,10,698},{12,11,57},{
+13,10,155},{20,10,93},{151,11,4},{4,0,37},{5,0,334},{7,0,1253},{151,11,25},{4,0,
+508},{4,11,635},{5,10,97},{137,10,393},{139,11,533},{4,0,640},{133,0,513},{134,
+10,1639},{132,11,371},{4,11,272},{7,11,836},{7,11,1651},{145,11,89},{5,11,825},{
+6,11,444},{6,11,1640},{136,11,308},{4,10,191},{7,10,934},{8,10,647},{145,10,97},
+{12,0,246},{15,0,162},{19,0,64},{20,0,8},{20,0,95},{22,0,24},{152,0,17},{4,0,533
+},{5,10,165},{9,10,346},{138,10,655},{5,11,737},{139,10,885},{133,10,877},{8,10,
+128},{139,10,179},{137,11,307},{140,0,752},{133,0,920},{135,0,1048},{5,0,153},{6
+,0,580},{6,10,1663},{7,10,132},{7,10,1154},{7,10,1415},{7,10,1507},{12,10,493},{
+15,10,105},{151,10,15},{5,10,459},{7,10,1073},{8,10,241},{136,10,334},{138,0,391
+},{135,0,1952},{133,11,525},{8,11,641},{11,11,388},{140,11,580},{142,0,126},{134
+,0,640},{132,0,483},{7,0,1616},{9,0,69},{6,10,324},{6,10,520},{7,10,338},{7,10,
+1729},{8,10,228},{139,10,750},{5,11,493},{134,11,528},{135,0,734},{4,11,174},{
+135,11,911},{138,0,480},{9,0,495},{146,0,104},{135,10,705},{9,0,472},{4,10,73},{
+6,10,612},{7,10,927},{7,10,1330},{7,10,1822},{8,10,217},{9,10,765},{9,10,766},{
+10,10,408},{11,10,51},{11,10,793},{12,10,266},{15,10,158},{20,10,89},{150,10,32}
+,{7,11,548},{137,11,58},{4,11,32},{5,11,215},{6,11,269},{7,11,1782},{7,11,1892},
+{10,11,16},{11,11,822},{11,11,954},{141,11,481},{132,0,874},{9,0,229},{5,10,389}
+,{136,10,636},{7,11,1749},{136,11,477},{134,0,948},{5,11,308},{135,11,1088},{4,0
+,748},{139,0,1009},{136,10,21},{6,0,555},{135,0,485},{5,11,126},{8,11,297},{9,11
+,366},{9,11,445},{12,11,53},{12,11,374},{141,11,492},{7,11,1551},{139,11,361},{
+136,0,193},{136,0,472},{8,0,653},{13,0,93},{147,0,14},{132,0,984},{132,11,175},{
+5,0,172},{6,0,1971},{132,11,685},{149,11,8},{133,11,797},{13,0,83},{5,10,189},{7
+,10,442},{7,10,443},{8,10,281},{12,10,174},{141,10,261},{134,0,1568},{133,11,565
+},{139,0,384},{133,0,260},{7,0,758},{7,0,880},{7,0,1359},{9,0,164},{9,0,167},{10
+,0,156},{10,0,588},{12,0,101},{14,0,48},{15,0,70},{6,10,2},{7,10,1262},{7,10,
+1737},{8,10,22},{8,10,270},{8,10,612},{9,10,312},{9,10,436},{10,10,311},{10,10,
+623},{11,10,72},{11,10,330},{11,10,455},{12,10,321},{12,10,504},{12,10,530},{12,
+10,543},{13,10,17},{13,10,156},{13,10,334},{17,10,60},{148,10,64},{4,11,252},{7,
+11,1068},{10,11,434},{11,11,228},{11,11,426},{13,11,231},{18,11,106},{148,11,87}
+,{7,10,354},{10,10,410},{139,10,815},{6,0,367},{7,10,670},{7,10,1327},{8,10,411}
+,{8,10,435},{9,10,653},{9,10,740},{10,10,385},{11,10,222},{11,10,324},{11,10,829
+},{140,10,611},{7,0,1174},{6,10,166},{135,10,374},{146,0,121},{132,0,828},{5,11,
+231},{138,11,509},{7,11,601},{9,11,277},{9,11,674},{10,11,178},{10,11,257},{10,
+11,418},{11,11,531},{11,11,544},{11,11,585},{12,11,113},{12,11,475},{13,11,99},{
+142,11,428},{134,0,1541},{135,11,1779},{5,0,343},{134,10,398},{135,10,50},{135,
+11,1683},{4,0,440},{7,0,57},{8,0,167},{8,0,375},{9,0,82},{9,0,561},{9,0,744},{10
+,0,620},{137,11,744},{134,0,926},{6,10,517},{7,10,1159},{10,10,621},{139,10,192}
+,{137,0,827},{8,0,194},{136,0,756},{10,10,223},{139,10,645},{7,10,64},{136,10,
+245},{4,11,399},{5,11,119},{5,11,494},{7,11,751},{137,11,556},{132,0,808},{135,0
+,22},{7,10,1763},{140,10,310},{5,0,639},{7,0,1249},{11,0,896},{134,11,584},{134,
+0,1614},{135,0,860},{135,11,1121},{5,10,129},{6,10,61},{135,10,947},{4,0,102},{7
+,0,815},{7,0,1699},{139,0,964},{13,10,505},{141,10,506},{139,10,1000},{132,11,
+679},{132,0,899},{132,0,569},{5,11,694},{137,11,714},{136,0,795},{6,0,2045},{139
+,11,7},{6,0,52},{9,0,104},{9,0,559},{12,0,308},{147,0,87},{4,0,301},{132,0,604},
+{133,10,637},{136,0,779},{5,11,143},{5,11,769},{6,11,1760},{7,11,682},{7,11,1992
+},{136,11,736},{137,10,590},{147,0,32},{137,11,527},{5,10,280},{135,10,1226},{
+134,0,494},{6,0,677},{6,0,682},{134,0,1044},{133,10,281},{135,10,1064},{7,0,508}
+,{133,11,860},{6,11,422},{7,11,0},{7,11,1544},{9,11,577},{11,11,990},{12,11,141}
+,{12,11,453},{13,11,47},{141,11,266},{134,0,1014},{5,11,515},{137,11,131},{134,0
+,957},{132,11,646},{6,0,310},{7,0,1849},{8,0,72},{8,0,272},{8,0,431},{9,0,12},{9
+,0,376},{10,0,563},{10,0,630},{10,0,796},{10,0,810},{11,0,367},{11,0,599},{11,0,
+686},{140,0,672},{7,0,570},{4,11,396},{7,10,120},{7,11,728},{8,10,489},{9,11,117
+},{9,10,319},{10,10,820},{11,10,1004},{12,10,379},{12,10,679},{13,10,117},{13,11
+,202},{13,10,412},{14,10,25},{15,10,52},{15,10,161},{16,10,47},{20,11,51},{149,
+10,2},{6,11,121},{6,11,124},{6,11,357},{7,11,1138},{7,11,1295},{8,11,162},{139,
+11,655},{8,0,449},{4,10,937},{5,10,801},{136,11,449},{139,11,958},{6,0,181},{7,0
+,537},{8,0,64},{9,0,127},{10,0,496},{12,0,510},{141,0,384},{138,11,253},{4,0,244
+},{135,0,233},{133,11,237},{132,10,365},{6,0,1650},{10,0,702},{139,0,245},{5,10,
+7},{139,10,774},{13,0,463},{20,0,49},{13,11,463},{148,11,49},{4,10,734},{5,10,
+662},{134,10,430},{4,10,746},{135,10,1090},{5,10,360},{136,10,237},{137,0,338},{
+143,11,10},{7,11,571},{138,11,366},{134,0,1279},{9,11,513},{10,11,22},{10,11,39}
+,{12,11,122},{140,11,187},{133,0,896},{146,0,178},{134,0,695},{137,0,808},{134,
+11,587},{7,11,107},{7,11,838},{8,11,550},{138,11,401},{7,0,1117},{136,0,539},{4,
+10,277},{5,10,608},{6,10,493},{7,10,457},{140,10,384},{133,11,768},{12,0,257},{7
+,10,27},{135,10,316},{140,0,1003},{4,0,207},{5,0,586},{5,0,676},{6,0,448},{8,0,
+244},{11,0,1},{13,0,3},{16,0,54},{17,0,4},{18,0,13},{133,10,552},{4,10,401},{137
+,10,264},{5,0,516},{7,0,1883},{135,11,1883},{12,0,960},{132,11,894},{5,0,4},{5,0
+,810},{6,0,13},{6,0,538},{6,0,1690},{6,0,1726},{7,0,499},{7,0,1819},{8,0,148},{8
+,0,696},{8,0,791},{12,0,125},{143,0,9},{135,0,1268},{11,0,30},{14,0,315},{9,10,
+543},{10,10,524},{12,10,524},{16,10,18},{20,10,26},{148,10,65},{6,0,748},{4,10,
+205},{5,10,623},{7,10,104},{136,10,519},{11,0,542},{139,0,852},{140,0,6},{132,0,
+848},{7,0,1385},{11,0,582},{11,0,650},{11,0,901},{11,0,949},{12,0,232},{12,0,236
+},{13,0,413},{13,0,501},{18,0,116},{7,10,579},{9,10,41},{9,10,244},{9,10,669},{
+10,10,5},{11,10,861},{11,10,951},{139,10,980},{4,0,945},{6,0,1811},{6,0,1845},{6
+,0,1853},{6,0,1858},{8,0,862},{12,0,782},{12,0,788},{18,0,160},{148,0,117},{132,
+10,717},{4,0,925},{5,0,803},{8,0,698},{138,0,828},{134,0,1416},{132,0,610},{139,
+0,992},{6,0,878},{134,0,1477},{135,0,1847},{138,11,531},{137,11,539},{134,11,272
+},{133,0,383},{134,0,1404},{132,10,489},{4,11,9},{5,11,128},{7,11,368},{11,11,
+480},{148,11,3},{136,0,986},{9,0,660},{138,0,347},{135,10,892},{136,11,682},{7,0
+,572},{9,0,592},{11,0,680},{12,0,356},{140,0,550},{7,0,1411},{138,11,527},{4,11,
+2},{7,11,545},{135,11,894},{137,10,473},{11,0,64},{7,11,481},{7,10,819},{9,10,26
+},{9,10,392},{9,11,792},{10,10,152},{10,10,226},{12,10,276},{12,10,426},{12,10,
+589},{13,10,460},{15,10,97},{19,10,48},{148,10,104},{135,10,51},{136,11,445},{
+136,11,646},{135,0,606},{132,10,674},{6,0,1829},{134,0,1830},{132,10,770},{5,10,
+79},{7,10,1027},{7,10,1477},{139,10,52},{5,11,530},{142,11,113},{134,10,1666},{7
+,0,748},{139,0,700},{134,10,195},{133,10,789},{9,0,87},{10,0,365},{4,10,251},{4,
+10,688},{7,10,513},{135,10,1284},{136,11,111},{133,0,127},{6,0,198},{140,0,83},{
+133,11,556},{133,10,889},{4,10,160},{5,10,330},{7,10,1434},{136,10,174},{5,0,276
+},{6,0,55},{7,0,1369},{138,0,864},{8,11,16},{140,11,568},{6,0,1752},{136,0,726},
+{135,0,1066},{133,0,764},{6,11,186},{137,11,426},{11,0,683},{139,11,683},{6,0,
+309},{7,0,331},{138,0,550},{133,10,374},{6,0,1212},{6,0,1852},{7,0,1062},{8,0,
+874},{8,0,882},{138,0,936},{132,11,585},{134,0,1364},{7,0,986},{133,10,731},{6,0
+,723},{6,0,1408},{138,0,381},{135,0,1573},{134,0,1025},{4,10,626},{5,10,642},{6,
+10,425},{10,10,202},{139,10,141},{4,11,93},{5,11,252},{6,11,229},{7,11,291},{9,
+11,550},{139,11,644},{137,11,749},{137,11,162},{132,11,381},{135,0,1559},{6,0,
+194},{7,0,133},{10,0,493},{10,0,570},{139,0,664},{5,0,24},{5,0,569},{6,0,3},{6,0
+,119},{6,0,143},{6,0,440},{7,0,295},{7,0,599},{7,0,1686},{7,0,1854},{8,0,424},{9
+,0,43},{9,0,584},{9,0,760},{10,0,148},{10,0,328},{11,0,159},{11,0,253},{11,0,506
+},{12,0,487},{140,0,531},{6,0,661},{134,0,1517},{136,10,835},{151,10,17},{5,0,14
+},{5,0,892},{6,0,283},{7,0,234},{136,0,537},{139,0,541},{4,0,126},{8,0,635},{147
+,0,34},{4,0,316},{4,0,495},{135,0,1561},{4,11,187},{5,11,184},{5,11,690},{7,11,
+1869},{138,11,756},{139,11,783},{4,0,998},{137,0,861},{136,0,1009},{139,11,292},
+{5,11,21},{6,11,77},{6,11,157},{7,11,974},{7,11,1301},{7,11,1339},{7,11,1490},{7
+,11,1873},{137,11,628},{7,11,1283},{9,11,227},{9,11,499},{10,11,341},{11,11,325}
+,{11,11,408},{14,11,180},{15,11,144},{18,11,47},{147,11,49},{4,0,64},{5,0,352},{
+5,0,720},{6,0,368},{139,0,359},{5,10,384},{8,10,455},{140,10,48},{5,10,264},{134
+,10,184},{7,0,1577},{10,0,304},{10,0,549},{12,0,365},{13,0,220},{13,0,240},{142,
+0,33},{134,0,1107},{134,0,929},{135,0,1142},{6,0,175},{137,0,289},{5,0,432},{133
+,0,913},{6,0,279},{7,0,219},{5,10,633},{135,10,1323},{7,0,785},{7,10,359},{8,10,
+243},{140,10,175},{139,0,595},{132,10,105},{8,11,398},{9,11,681},{139,11,632},{
+140,0,80},{5,0,931},{134,0,1698},{142,11,241},{134,11,20},{134,0,1323},{11,0,526
+},{11,0,939},{141,0,290},{5,0,774},{6,0,780},{6,0,1637},{6,0,1686},{6,0,1751},{8
+,0,559},{141,0,109},{141,0,127},{7,0,1167},{11,0,934},{13,0,391},{17,0,76},{135,
+11,709},{135,0,963},{6,0,260},{135,0,1484},{134,0,573},{4,10,758},{139,11,941},{
+135,10,1649},{145,11,36},{4,0,292},{137,0,580},{4,0,736},{5,0,871},{6,0,1689},{
+135,0,1944},{7,11,945},{11,11,713},{139,11,744},{134,0,1164},{135,11,937},{6,0,
+1922},{9,0,982},{15,0,173},{15,0,178},{15,0,200},{18,0,189},{18,0,207},{21,0,47}
+,{135,11,1652},{7,0,1695},{139,10,128},{6,0,63},{135,0,920},{133,0,793},{143,11,
+134},{133,10,918},{5,0,67},{6,0,62},{6,0,374},{135,0,1391},{9,0,790},{12,0,47},{
+4,11,579},{5,11,226},{5,11,323},{135,11,960},{10,11,784},{141,11,191},{4,0,391},
+{135,0,1169},{137,0,443},{13,11,232},{146,11,35},{132,10,340},{132,0,271},{137,
+11,313},{5,11,973},{137,11,659},{134,0,1140},{6,11,135},{135,11,1176},{4,0,253},
+{5,0,544},{7,0,300},{137,0,340},{7,0,897},{5,10,985},{7,10,509},{145,10,96},{138
+,11,735},{135,10,1919},{138,0,890},{5,0,818},{134,0,1122},{5,0,53},{5,0,541},{6,
+0,94},{6,0,499},{7,0,230},{139,0,321},{4,0,920},{5,0,25},{5,0,790},{6,0,457},{7,
+0,853},{8,0,788},{142,11,31},{132,10,247},{135,11,314},{132,0,468},{7,0,243},{6,
+10,337},{7,10,494},{8,10,27},{8,10,599},{138,10,153},{4,10,184},{5,10,390},{7,10
+,618},{7,10,1456},{139,10,710},{134,0,870},{134,0,1238},{134,0,1765},{10,0,853},
+{10,0,943},{14,0,437},{14,0,439},{14,0,443},{14,0,446},{14,0,452},{14,0,469},{14
+,0,471},{14,0,473},{16,0,93},{16,0,102},{16,0,110},{148,0,121},{4,0,605},{7,0,
+518},{7,0,1282},{7,0,1918},{10,0,180},{139,0,218},{133,0,822},{4,0,634},{11,0,
+916},{142,0,419},{6,11,281},{7,11,6},{8,11,282},{8,11,480},{8,11,499},{9,11,198}
+,{10,11,143},{10,11,169},{10,11,211},{10,11,417},{10,11,574},{11,11,147},{11,11,
+395},{12,11,75},{12,11,407},{12,11,608},{13,11,500},{142,11,251},{134,0,898},{6,
+0,36},{7,0,658},{8,0,454},{150,11,48},{133,11,674},{135,11,1776},{4,11,419},{10,
+10,227},{11,10,497},{11,10,709},{140,10,415},{6,10,360},{7,10,1664},{136,10,478}
+,{137,0,806},{12,11,508},{14,11,102},{14,11,226},{144,11,57},{135,11,1123},{4,11
+,138},{7,11,1012},{7,11,1280},{137,11,76},{5,11,29},{140,11,638},{136,10,699},{
+134,0,1326},{132,0,104},{135,11,735},{132,10,739},{134,0,1331},{7,0,260},{135,11
+,260},{135,11,1063},{7,0,45},{9,0,542},{9,0,566},{10,0,728},{137,10,869},{4,10,
+67},{5,10,422},{7,10,1037},{7,10,1289},{7,10,1555},{9,10,741},{145,10,108},{139,
+0,263},{134,0,1516},{14,0,146},{15,0,42},{16,0,23},{17,0,86},{146,0,17},{138,0,
+468},{136,0,1005},{4,11,17},{5,11,23},{7,11,995},{11,11,383},{11,11,437},{12,11,
+460},{140,11,532},{7,0,87},{142,0,288},{138,10,96},{135,11,626},{144,10,26},{7,0
+,988},{7,0,1939},{9,0,64},{9,0,502},{12,0,22},{12,0,34},{13,0,12},{13,0,234},{
+147,0,77},{13,0,133},{8,10,203},{11,10,823},{11,10,846},{12,10,482},{13,10,277},
+{13,10,302},{13,10,464},{14,10,205},{142,10,221},{4,10,449},{133,10,718},{135,0,
+141},{6,0,1842},{136,0,872},{8,11,70},{12,11,171},{141,11,272},{4,10,355},{6,10,
+311},{9,10,256},{138,10,404},{132,0,619},{137,0,261},{10,11,233},{10,10,758},{
+139,11,76},{5,0,246},{8,0,189},{9,0,355},{9,0,512},{10,0,124},{10,0,453},{11,0,
+143},{11,0,416},{11,0,859},{141,0,341},{134,11,442},{133,10,827},{5,10,64},{140,
+10,581},{4,10,442},{7,10,1047},{7,10,1352},{135,10,1643},{134,11,1709},{5,0,678}
+,{6,0,305},{7,0,775},{7,0,1065},{133,10,977},{11,11,69},{12,11,105},{12,11,117},
+{13,11,213},{14,11,13},{14,11,62},{14,11,177},{14,11,421},{15,11,19},{146,11,141
+},{137,11,309},{5,0,35},{7,0,862},{7,0,1886},{138,0,179},{136,0,285},{132,0,517}
+,{7,11,976},{9,11,146},{10,11,206},{10,11,596},{13,11,218},{142,11,153},{132,10,
+254},{6,0,214},{12,0,540},{4,10,275},{7,10,1219},{140,10,376},{8,0,667},{11,0,
+403},{146,0,83},{12,0,74},{10,11,648},{11,11,671},{143,11,46},{135,0,125},{134,
+10,1753},{133,0,761},{6,0,912},{4,11,518},{6,10,369},{6,10,502},{7,10,1036},{7,
+11,1136},{8,10,348},{9,10,452},{10,10,26},{11,10,224},{11,10,387},{11,10,772},{
+12,10,95},{12,10,629},{13,10,195},{13,10,207},{13,10,241},{14,10,260},{14,10,270
+},{143,10,140},{10,0,131},{140,0,72},{132,10,269},{5,10,480},{7,10,532},{7,10,
+1197},{7,10,1358},{8,10,291},{11,10,349},{142,10,396},{8,11,689},{137,11,863},{8
+,0,333},{138,0,182},{4,11,18},{7,11,145},{7,11,444},{7,11,1278},{8,11,49},{8,11,
+400},{9,11,71},{9,11,250},{10,11,459},{12,11,160},{144,11,24},{14,11,35},{142,11
+,191},{135,11,1864},{135,0,1338},{148,10,15},{14,0,94},{15,0,65},{16,0,4},{16,0,
+77},{16,0,80},{145,0,5},{12,11,82},{143,11,36},{133,11,1010},{133,0,449},{133,0,
+646},{7,0,86},{8,0,103},{135,10,657},{7,0,2028},{138,0,641},{136,10,533},{134,0,
+1},{139,11,970},{5,11,87},{7,11,313},{7,11,1103},{10,11,112},{10,11,582},{11,11,
+389},{11,11,813},{12,11,385},{13,11,286},{14,11,124},{146,11,108},{6,0,869},{132
+,11,267},{6,0,277},{7,0,1274},{7,0,1386},{146,0,87},{6,0,187},{7,0,39},{7,0,1203
+},{8,0,380},{14,0,117},{149,0,28},{4,10,211},{4,10,332},{5,10,335},{6,10,238},{7
+,10,269},{7,10,811},{7,10,1797},{8,10,836},{9,10,507},{141,10,242},{4,0,785},{5,
+0,368},{6,0,297},{7,0,793},{139,0,938},{7,0,464},{8,0,558},{11,0,105},{12,0,231}
+,{14,0,386},{15,0,102},{148,0,75},{133,10,1009},{8,0,877},{140,0,731},{139,11,
+289},{10,11,249},{139,11,209},{132,11,561},{134,0,1608},{132,11,760},{134,0,1429
+},{9,11,154},{140,11,485},{5,10,228},{6,10,203},{7,10,156},{8,10,347},{137,10,
+265},{7,0,1010},{11,0,733},{11,0,759},{13,0,34},{14,0,427},{146,0,45},{7,10,1131
+},{135,10,1468},{136,11,255},{7,0,1656},{9,0,369},{10,0,338},{10,0,490},{11,0,
+154},{11,0,545},{11,0,775},{13,0,77},{141,0,274},{133,11,621},{134,0,1038},{4,11
+,368},{135,11,641},{6,0,2010},{8,0,979},{8,0,985},{10,0,951},{138,0,1011},{134,0
+,1005},{19,0,121},{5,10,291},{5,10,318},{7,10,765},{9,10,389},{140,10,548},{5,0,
+20},{6,0,298},{7,0,659},{137,0,219},{7,0,1440},{11,0,854},{11,0,872},{11,0,921},
+{12,0,551},{13,0,472},{142,0,367},{5,0,490},{6,0,615},{6,0,620},{135,0,683},{6,0
+,1070},{134,0,1597},{139,0,522},{132,0,439},{136,0,669},{6,0,766},{6,0,1143},{6,
+0,1245},{10,10,525},{139,10,82},{9,11,92},{147,11,91},{6,0,668},{134,0,1218},{6,
+11,525},{9,11,876},{140,11,284},{132,0,233},{136,0,547},{132,10,422},{5,10,355},
+{145,10,0},{6,11,300},{135,11,1515},{4,0,482},{137,10,905},{4,0,886},{7,0,346},{
+133,11,594},{133,10,865},{5,10,914},{134,10,1625},{135,0,334},{5,0,795},{6,0,
+1741},{133,10,234},{135,10,1383},{6,11,1641},{136,11,820},{135,0,371},{7,11,1313
+},{138,11,660},{135,10,1312},{135,0,622},{7,0,625},{135,0,1750},{135,0,339},{4,0
+,203},{135,0,1936},{15,0,29},{16,0,38},{15,11,29},{144,11,38},{5,0,338},{135,0,
+1256},{135,10,1493},{10,0,130},{6,10,421},{7,10,61},{7,10,1540},{138,10,501},{6,
+11,389},{7,11,149},{9,11,142},{138,11,94},{137,10,341},{11,0,678},{12,0,307},{
+142,10,98},{6,11,8},{7,11,1881},{136,11,91},{135,0,2044},{6,0,770},{6,0,802},{6,
+0,812},{7,0,311},{9,0,308},{12,0,255},{6,10,102},{7,10,72},{15,10,142},{147,10,
+67},{151,10,30},{135,10,823},{135,0,1266},{135,11,1746},{135,10,1870},{4,0,400},
+{5,0,267},{135,0,232},{7,11,24},{11,11,542},{139,11,852},{135,11,1739},{4,11,503
+},{135,11,1661},{5,11,130},{7,11,1314},{9,11,610},{10,11,718},{11,11,601},{11,11
+,819},{11,11,946},{140,11,536},{10,11,149},{11,11,280},{142,11,336},{7,0,739},{
+11,0,690},{7,11,1946},{8,10,48},{8,10,88},{8,10,582},{8,10,681},{9,10,373},{9,10
+,864},{11,10,157},{11,10,843},{148,10,27},{134,0,990},{4,10,88},{5,10,137},{5,10
+,174},{5,10,777},{6,10,1664},{6,10,1725},{7,10,77},{7,10,426},{7,10,1317},{7,10,
+1355},{8,10,126},{8,10,563},{9,10,523},{9,10,750},{10,10,310},{10,10,836},{11,10
+,42},{11,10,318},{11,10,731},{12,10,68},{12,10,92},{12,10,507},{12,10,692},{13,
+10,81},{13,10,238},{13,10,374},{14,10,436},{18,10,138},{19,10,78},{19,10,111},{
+20,10,55},{20,10,77},{148,10,92},{141,10,418},{7,0,1831},{132,10,938},{6,0,776},
+{134,0,915},{138,10,351},{5,11,348},{6,11,522},{6,10,1668},{7,10,1499},{8,10,117
+},{9,10,314},{138,10,174},{135,10,707},{132,0,613},{133,10,403},{132,11,392},{5,
+11,433},{9,11,633},{139,11,629},{133,0,763},{132,0,878},{132,0,977},{132,0,100},
+{6,0,463},{4,10,44},{5,10,311},{7,10,639},{7,10,762},{7,10,1827},{9,10,8},{9,10,
+462},{148,10,83},{134,11,234},{4,10,346},{7,10,115},{9,10,180},{9,10,456},{138,
+10,363},{5,0,362},{5,0,443},{6,0,318},{7,0,1019},{139,0,623},{5,0,463},{8,0,296}
+,{7,11,140},{7,11,1950},{8,11,680},{11,11,817},{147,11,88},{7,11,1222},{138,11,
+386},{142,0,137},{132,0,454},{7,0,1914},{6,11,5},{7,10,1051},{9,10,545},{11,11,
+249},{12,11,313},{16,11,66},{145,11,26},{135,0,1527},{145,0,58},{148,11,59},{5,0
+,48},{5,0,404},{6,0,557},{7,0,458},{8,0,597},{10,0,455},{10,0,606},{11,0,49},{11
+,0,548},{12,0,476},{13,0,18},{141,0,450},{5,11,963},{134,11,1773},{133,0,729},{
+138,11,586},{5,0,442},{135,0,1984},{134,0,449},{144,0,40},{4,0,853},{7,11,180},{
+8,11,509},{136,11,792},{6,10,185},{7,10,1899},{9,10,875},{139,10,673},{134,11,
+524},{12,0,227},{4,10,327},{5,10,478},{7,10,1332},{136,10,753},{6,0,1491},{5,10,
+1020},{133,10,1022},{4,10,103},{133,10,401},{132,11,931},{4,10,499},{135,10,1421
+},{5,0,55},{7,0,376},{140,0,161},{133,0,450},{6,0,1174},{134,0,1562},{10,0,62},{
+13,0,400},{135,11,1837},{140,0,207},{135,0,869},{4,11,773},{5,11,618},{137,11,
+756},{132,10,96},{4,0,213},{7,0,223},{8,0,80},{135,10,968},{4,11,90},{5,11,337},
+{5,11,545},{7,11,754},{9,11,186},{10,11,72},{10,11,782},{11,11,513},{11,11,577},
+{11,11,610},{11,11,889},{11,11,961},{12,11,354},{12,11,362},{12,11,461},{12,11,
+595},{13,11,79},{143,11,121},{7,0,381},{7,0,806},{7,0,820},{8,0,354},{8,0,437},{
+8,0,787},{9,0,657},{10,0,58},{10,0,339},{10,0,749},{11,0,914},{12,0,162},{13,0,
+75},{14,0,106},{14,0,198},{14,0,320},{14,0,413},{146,0,43},{136,0,747},{136,0,
+954},{134,0,1073},{135,0,556},{7,11,151},{9,11,329},{139,11,254},{5,0,692},{134,
+0,1395},{6,10,563},{137,10,224},{134,0,191},{132,0,804},{9,11,187},{10,11,36},{
+17,11,44},{146,11,64},{7,11,165},{7,11,919},{136,11,517},{4,11,506},{5,11,295},{
+7,11,1680},{15,11,14},{144,11,5},{4,0,706},{6,0,162},{7,0,1960},{136,0,831},{135
+,11,1376},{7,11,987},{9,11,688},{10,11,522},{11,11,788},{140,11,566},{150,0,35},
+{138,0,426},{135,0,1235},{135,11,1741},{7,11,389},{7,11,700},{7,11,940},{8,11,
+514},{9,11,116},{9,11,535},{10,11,118},{11,11,107},{11,11,148},{11,11,922},{12,
+11,254},{12,11,421},{142,11,238},{134,0,1234},{132,11,743},{4,10,910},{5,10,832}
+,{135,11,1335},{141,0,96},{135,11,185},{146,0,149},{4,0,204},{137,0,902},{4,11,
+784},{133,11,745},{136,0,833},{136,0,949},{7,0,366},{9,0,287},{12,0,199},{12,0,
+556},{12,0,577},{5,11,81},{7,11,146},{7,11,1342},{7,11,1446},{8,11,53},{8,11,561
+},{8,11,694},{8,11,754},{9,11,97},{9,11,115},{9,11,894},{10,11,462},{10,11,813},
+{11,11,230},{11,11,657},{11,11,699},{11,11,748},{12,11,119},{12,11,200},{12,11,
+283},{14,11,273},{145,11,15},{5,11,408},{137,11,747},{9,11,498},{140,11,181},{6,
+0,2020},{136,0,992},{5,0,356},{135,0,224},{134,0,784},{7,0,630},{9,0,567},{11,0,
+150},{11,0,444},{13,0,119},{8,10,528},{137,10,348},{134,0,539},{4,10,20},{133,10
+,616},{142,0,27},{7,11,30},{8,11,86},{8,11,315},{8,11,700},{9,11,576},{9,11,858}
+,{11,11,310},{11,11,888},{11,11,904},{12,11,361},{141,11,248},{138,11,839},{134,
+0,755},{134,0,1063},{7,10,1091},{135,10,1765},{134,11,428},{7,11,524},{8,11,169}
+,{8,11,234},{9,11,480},{138,11,646},{139,0,814},{7,11,1462},{139,11,659},{4,10,
+26},{5,10,429},{6,10,245},{7,10,704},{7,10,1379},{135,10,1474},{7,11,1205},{138,
+11,637},{139,11,803},{132,10,621},{136,0,987},{4,11,266},{8,11,4},{9,11,39},{10,
+11,166},{11,11,918},{12,11,635},{20,11,10},{22,11,27},{150,11,43},{4,0,235},{135
+,0,255},{4,0,194},{5,0,584},{6,0,384},{7,0,583},{10,0,761},{11,0,760},{139,0,851
+},{133,10,542},{134,0,1086},{133,10,868},{8,0,1016},{136,0,1018},{7,0,1396},{7,
+11,1396},{136,10,433},{135,10,1495},{138,10,215},{141,10,124},{7,11,157},{8,11,
+279},{9,11,759},{16,11,31},{16,11,39},{16,11,75},{18,11,24},{20,11,42},{152,11,1
+},{5,0,562},{134,11,604},{134,0,913},{5,0,191},{137,0,271},{4,0,470},{6,0,153},{
+7,0,1503},{7,0,1923},{10,0,701},{11,0,132},{11,0,227},{11,0,320},{11,0,436},{11,
+0,525},{11,0,855},{11,0,873},{12,0,41},{12,0,286},{13,0,103},{13,0,284},{14,0,
+255},{14,0,262},{15,0,117},{143,0,127},{7,0,475},{12,0,45},{147,10,112},{132,11,
+567},{137,11,859},{6,0,713},{6,0,969},{6,0,1290},{134,0,1551},{133,0,327},{6,0,
+552},{6,0,1292},{7,0,1754},{137,0,604},{4,0,223},{6,0,359},{11,0,3},{13,0,108},{
+14,0,89},{16,0,22},{5,11,762},{7,11,1880},{9,11,680},{139,11,798},{5,0,80},{6,0,
+405},{7,0,403},{7,0,1502},{8,0,456},{9,0,487},{9,0,853},{9,0,889},{10,0,309},{11
+,0,721},{11,0,994},{12,0,430},{141,0,165},{133,11,298},{132,10,647},{134,0,2016}
+,{18,10,10},{146,11,10},{4,0,453},{5,0,887},{6,0,535},{8,0,6},{8,0,543},{136,0,
+826},{136,0,975},{10,0,961},{138,0,962},{138,10,220},{6,0,1891},{6,0,1893},{9,0,
+916},{9,0,965},{9,0,972},{12,0,801},{12,0,859},{12,0,883},{15,0,226},{149,0,51},
+{132,10,109},{135,11,267},{7,11,92},{7,11,182},{8,11,453},{9,11,204},{11,11,950}
+,{12,11,94},{12,11,644},{16,11,20},{16,11,70},{16,11,90},{147,11,55},{134,10,
+1746},{6,11,71},{7,11,845},{7,11,1308},{8,11,160},{137,11,318},{5,0,101},{6,0,88
+},{7,0,263},{7,0,628},{7,0,1677},{8,0,349},{9,0,100},{10,0,677},{14,0,169},{14,0
+,302},{14,0,313},{15,0,48},{15,0,84},{7,11,237},{8,11,664},{9,11,42},{9,11,266},
+{9,11,380},{9,11,645},{10,11,177},{138,11,276},{138,11,69},{4,0,310},{7,0,708},{
+7,0,996},{9,0,795},{10,0,390},{10,0,733},{11,0,451},{12,0,249},{14,0,115},{14,0,
+286},{143,0,100},{5,0,587},{4,10,40},{10,10,67},{11,10,117},{11,10,768},{139,10,
+935},{6,0,1942},{7,0,512},{136,0,983},{7,10,992},{8,10,301},{9,10,722},{12,10,63
+},{13,10,29},{14,10,161},{143,10,18},{136,11,76},{139,10,923},{134,0,645},{134,0
+,851},{4,0,498},{132,11,293},{7,0,217},{8,0,140},{10,0,610},{14,11,352},{17,11,
+53},{18,11,146},{18,11,152},{19,11,11},{150,11,54},{134,0,1448},{138,11,841},{
+133,0,905},{4,11,605},{7,11,518},{7,11,1282},{7,11,1918},{10,11,180},{139,11,218
+},{139,11,917},{135,10,825},{140,10,328},{4,0,456},{7,0,105},{7,0,358},{7,0,1637
+},{8,0,643},{139,0,483},{134,0,792},{6,11,96},{135,11,1426},{137,11,691},{4,11,
+651},{133,11,289},{7,11,688},{8,11,35},{9,11,511},{10,11,767},{147,11,118},{150,
+0,56},{5,0,243},{5,0,535},{6,10,204},{10,10,320},{10,10,583},{13,10,502},{14,10,
+72},{14,10,274},{14,10,312},{14,10,344},{15,10,159},{16,10,62},{16,10,69},{17,10
+,30},{18,10,42},{18,10,53},{18,10,84},{18,10,140},{19,10,68},{19,10,85},{20,10,5
+},{20,10,45},{20,10,101},{22,10,7},{150,10,20},{4,10,558},{6,10,390},{7,10,162},
+{7,10,689},{9,10,360},{138,10,653},{146,11,23},{135,0,1748},{5,10,856},{6,10,
+1672},{6,10,1757},{134,10,1781},{5,0,539},{5,0,754},{6,0,876},{132,11,704},{135,
+11,1078},{5,10,92},{10,10,736},{140,10,102},{17,0,91},{5,10,590},{137,10,213},{
+134,0,1565},{6,0,91},{135,0,435},{4,0,939},{140,0,792},{134,0,1399},{4,0,16},{5,
+0,316},{5,0,842},{6,0,370},{6,0,1778},{8,0,166},{11,0,812},{12,0,206},{12,0,351}
+,{14,0,418},{16,0,15},{16,0,34},{18,0,3},{19,0,3},{19,0,7},{20,0,4},{21,0,21},{4
+,11,720},{133,11,306},{144,0,95},{133,11,431},{132,11,234},{135,0,551},{4,0,999}
+,{6,0,1966},{134,0,2042},{7,0,619},{10,0,547},{11,0,122},{12,0,601},{15,0,7},{
+148,0,20},{5,11,464},{6,11,236},{7,11,276},{7,11,696},{7,11,914},{7,11,1108},{7,
+11,1448},{9,11,15},{9,11,564},{10,11,14},{12,11,565},{13,11,449},{14,11,53},{15,
+11,13},{16,11,64},{145,11,41},{6,0,884},{6,0,1019},{134,0,1150},{6,11,1767},{12,
+11,194},{145,11,107},{136,10,503},{133,11,840},{7,0,671},{134,10,466},{132,0,888
+},{4,0,149},{138,0,368},{4,0,154},{7,0,1134},{136,0,105},{135,0,983},{9,11,642},
+{11,11,236},{142,11,193},{4,0,31},{6,0,429},{7,0,962},{9,0,458},{139,0,691},{6,0
+,643},{134,0,1102},{132,0,312},{4,11,68},{5,11,634},{6,11,386},{7,11,794},{8,11,
+273},{9,11,563},{10,11,105},{10,11,171},{11,11,94},{139,11,354},{133,0,740},{135
+,0,1642},{4,11,95},{7,11,416},{8,11,211},{139,11,830},{132,0,236},{138,10,241},{
+7,11,731},{13,11,20},{143,11,11},{5,0,836},{5,0,857},{6,0,1680},{135,0,59},{10,0
+,68},{11,0,494},{152,11,6},{4,0,81},{139,0,867},{135,0,795},{133,11,689},{4,0,
+1001},{5,0,282},{6,0,1932},{6,0,1977},{6,0,1987},{6,0,1992},{8,0,650},{8,0,919},
+{8,0,920},{8,0,923},{8,0,926},{8,0,927},{8,0,931},{8,0,939},{8,0,947},{8,0,956},
+{8,0,997},{9,0,907},{10,0,950},{10,0,953},{10,0,954},{10,0,956},{10,0,958},{10,0
+,959},{10,0,964},{10,0,970},{10,0,972},{10,0,973},{10,0,975},{10,0,976},{10,0,
+980},{10,0,981},{10,0,984},{10,0,988},{10,0,990},{10,0,995},{10,0,999},{10,0,
+1002},{10,0,1003},{10,0,1005},{10,0,1006},{10,0,1008},{10,0,1009},{10,0,1012},{
+10,0,1014},{10,0,1015},{10,0,1019},{10,0,1020},{10,0,1022},{12,0,959},{12,0,961}
+,{12,0,962},{12,0,963},{12,0,964},{12,0,965},{12,0,967},{12,0,968},{12,0,969},{
+12,0,970},{12,0,971},{12,0,972},{12,0,973},{12,0,974},{12,0,975},{12,0,976},{12,
+0,977},{12,0,979},{12,0,981},{12,0,982},{12,0,983},{12,0,984},{12,0,985},{12,0,
+986},{12,0,987},{12,0,989},{12,0,990},{12,0,992},{12,0,993},{12,0,995},{12,0,998
+},{12,0,999},{12,0,1000},{12,0,1001},{12,0,1002},{12,0,1004},{12,0,1005},{12,0,
+1006},{12,0,1007},{12,0,1008},{12,0,1009},{12,0,1010},{12,0,1011},{12,0,1012},{
+12,0,1014},{12,0,1015},{12,0,1016},{12,0,1017},{12,0,1018},{12,0,1019},{12,0,
+1022},{12,0,1023},{14,0,475},{14,0,477},{14,0,478},{14,0,479},{14,0,480},{14,0,
+482},{14,0,483},{14,0,484},{14,0,485},{14,0,486},{14,0,487},{14,0,488},{14,0,489
+},{14,0,490},{14,0,491},{14,0,492},{14,0,493},{14,0,494},{14,0,495},{14,0,496},{
+14,0,497},{14,0,498},{14,0,499},{14,0,500},{14,0,501},{14,0,502},{14,0,503},{14,
+0,504},{14,0,506},{14,0,507},{14,0,508},{14,0,509},{14,0,510},{14,0,511},{16,0,
+113},{16,0,114},{16,0,115},{16,0,117},{16,0,118},{16,0,119},{16,0,121},{16,0,122
+},{16,0,123},{16,0,124},{16,0,125},{16,0,126},{16,0,127},{18,0,242},{18,0,243},{
+18,0,244},{18,0,245},{18,0,248},{18,0,249},{18,0,250},{18,0,251},{18,0,252},{18,
+0,253},{18,0,254},{18,0,255},{20,0,125},{20,0,126},{148,0,127},{7,11,1717},{7,11
+,1769},{138,11,546},{7,11,1127},{7,11,1572},{10,11,297},{10,11,422},{11,11,764},
+{11,11,810},{12,11,264},{13,11,102},{13,11,300},{13,11,484},{14,11,147},{14,11,
+229},{17,11,71},{18,11,118},{147,11,120},{6,0,1148},{134,0,1586},{132,0,775},{
+135,10,954},{133,11,864},{133,11,928},{138,11,189},{135,10,1958},{6,10,549},{8,
+10,34},{8,10,283},{9,10,165},{138,10,475},{5,10,652},{5,10,701},{135,10,449},{
+135,11,695},{4,10,655},{7,10,850},{17,10,75},{146,10,137},{140,11,682},{133,11,
+523},{8,0,970},{136,10,670},{136,11,555},{7,11,76},{8,11,44},{9,11,884},{10,11,
+580},{11,11,399},{11,11,894},{15,11,122},{18,11,144},{147,11,61},{6,10,159},{6,
+10,364},{7,10,516},{7,10,1439},{137,10,518},{4,0,71},{5,0,376},{7,0,119},{138,0,
+665},{141,10,151},{11,0,827},{14,0,34},{143,0,148},{133,11,518},{4,0,479},{135,
+11,1787},{135,11,1852},{135,10,993},{7,0,607},{136,0,99},{134,0,1960},{132,0,793
+},{4,0,41},{5,0,74},{7,0,1627},{11,0,871},{140,0,619},{7,0,94},{11,0,329},{11,0,
+965},{12,0,241},{14,0,354},{15,0,22},{148,0,63},{7,10,501},{9,10,111},{10,10,141
+},{11,10,332},{13,10,43},{13,10,429},{14,10,130},{14,10,415},{145,10,102},{9,0,
+209},{137,0,300},{134,0,1497},{138,11,255},{4,11,934},{5,11,138},{136,11,610},{
+133,0,98},{6,0,1316},{10,11,804},{138,11,832},{8,11,96},{9,11,36},{10,11,607},{
+11,11,423},{11,11,442},{12,11,309},{14,11,199},{15,11,90},{145,11,110},{132,0,
+463},{5,10,149},{136,10,233},{133,10,935},{4,11,652},{8,11,320},{9,11,13},{9,11,
+398},{9,11,727},{10,11,75},{10,11,184},{10,11,230},{10,11,564},{10,11,569},{11,
+11,973},{12,11,70},{12,11,189},{13,11,57},{13,11,257},{22,11,6},{150,11,16},{142
+,0,291},{12,10,582},{146,10,131},{136,10,801},{133,0,984},{145,11,116},{4,11,692
+},{133,11,321},{4,0,182},{6,0,205},{135,0,220},{4,0,42},{9,0,205},{9,0,786},{138
+,0,659},{6,0,801},{11,11,130},{140,11,609},{132,0,635},{5,11,345},{135,11,1016},
+{139,0,533},{132,0,371},{4,0,272},{135,0,836},{6,0,1282},{135,11,1100},{5,0,825}
+,{134,0,1640},{135,11,1325},{133,11,673},{4,11,287},{133,11,1018},{135,0,357},{6
+,0,467},{137,0,879},{7,0,317},{135,0,569},{6,0,924},{134,0,1588},{5,11,34},{5,10
+,406},{10,11,724},{12,11,444},{13,11,354},{18,11,32},{23,11,24},{23,11,31},{152,
+11,5},{6,0,1795},{6,0,1835},{6,0,1836},{6,0,1856},{8,0,844},{8,0,849},{8,0,854},
+{8,0,870},{8,0,887},{10,0,852},{138,0,942},{6,10,69},{135,10,117},{137,0,307},{4
+,0,944},{6,0,1799},{6,0,1825},{10,0,848},{10,0,875},{10,0,895},{10,0,899},{10,0,
+902},{140,0,773},{11,0,43},{13,0,72},{141,0,142},{135,10,1830},{134,11,382},{4,
+10,432},{135,10,824},{132,11,329},{7,0,1820},{139,11,124},{133,10,826},{133,0,
+525},{132,11,906},{7,11,1940},{136,11,366},{138,11,10},{4,11,123},{4,11,649},{5,
+11,605},{7,11,1509},{136,11,36},{6,0,110},{135,0,1681},{133,0,493},{133,11,767},
+{4,0,174},{135,0,911},{138,11,786},{8,0,417},{137,0,782},{133,10,1000},{7,0,733}
+,{137,0,583},{4,10,297},{6,10,529},{7,10,152},{7,10,713},{7,10,1845},{8,10,710},
+{8,10,717},{12,10,639},{140,10,685},{4,0,32},{5,0,215},{6,0,269},{7,0,1782},{7,0
+,1892},{10,0,16},{11,0,822},{11,0,954},{141,0,481},{4,11,273},{5,11,658},{133,11
+,995},{136,0,477},{134,11,72},{135,11,1345},{5,0,308},{7,0,1088},{4,10,520},{135
+,10,575},{133,11,589},{5,0,126},{8,0,297},{9,0,366},{140,0,374},{7,0,1551},{139,
+0,361},{5,11,117},{6,11,514},{6,11,541},{7,11,1164},{7,11,1436},{8,11,220},{8,11
+,648},{10,11,688},{139,11,560},{133,11,686},{4,0,946},{6,0,1807},{8,0,871},{10,0
+,854},{10,0,870},{10,0,888},{10,0,897},{10,0,920},{12,0,722},{12,0,761},{12,0,
+763},{12,0,764},{14,0,454},{14,0,465},{16,0,107},{18,0,167},{18,0,168},{146,0,
+172},{132,0,175},{135,0,1307},{132,0,685},{135,11,1834},{133,0,797},{6,0,745},{6
+,0,858},{134,0,963},{133,0,565},{5,10,397},{6,10,154},{7,11,196},{7,10,676},{8,
+10,443},{8,10,609},{9,10,24},{9,10,325},{10,10,35},{10,11,765},{11,11,347},{11,
+10,535},{11,11,552},{11,11,576},{11,10,672},{11,11,790},{11,10,1018},{12,11,263}
+,{12,10,637},{13,11,246},{13,11,270},{13,11,395},{14,11,74},{14,11,176},{14,11,
+190},{14,11,398},{14,11,412},{15,11,32},{15,11,63},{16,10,30},{16,11,88},{147,11
+,105},{13,11,84},{141,11,122},{4,0,252},{7,0,1068},{10,0,434},{11,0,228},{11,0,
+426},{13,0,231},{18,0,106},{148,0,87},{137,0,826},{4,11,589},{139,11,282},{5,11,
+381},{135,11,1792},{132,0,791},{5,0,231},{10,0,509},{133,10,981},{7,0,601},{9,0,
+277},{9,0,674},{10,0,178},{10,0,418},{10,0,571},{11,0,531},{12,0,113},{12,0,475}
+,{13,0,99},{142,0,428},{4,10,56},{7,11,616},{7,10,1791},{8,10,607},{8,10,651},{
+10,11,413},{11,10,465},{11,10,835},{12,10,337},{141,10,480},{7,0,1591},{144,0,43
+},{9,10,158},{138,10,411},{135,0,1683},{8,0,289},{11,0,45},{12,0,278},{140,0,537
+},{6,11,120},{7,11,1188},{7,11,1710},{8,11,286},{9,11,667},{11,11,592},{139,11,
+730},{136,10,617},{135,0,1120},{135,11,1146},{139,10,563},{4,11,352},{4,10,369},
+{135,11,687},{143,11,38},{4,0,399},{5,0,119},{5,0,494},{7,0,751},{9,0,556},{14,
+11,179},{15,11,151},{150,11,11},{4,11,192},{5,11,49},{6,11,200},{6,11,293},{6,11
+,1696},{135,11,488},{4,0,398},{133,0,660},{7,0,1030},{134,10,622},{135,11,595},{
+141,0,168},{132,11,147},{7,0,973},{10,10,624},{142,10,279},{132,10,363},{132,0,
+642},{133,11,934},{134,0,1615},{7,11,505},{135,11,523},{7,0,594},{7,0,851},{7,0,
+1858},{9,0,411},{9,0,574},{9,0,666},{9,0,737},{10,0,346},{10,0,712},{11,0,246},{
+11,0,432},{11,0,517},{11,0,647},{11,0,679},{11,0,727},{12,0,304},{12,0,305},{12,
+0,323},{12,0,483},{12,0,572},{12,0,593},{12,0,602},{13,0,95},{13,0,101},{13,0,
+171},{13,0,315},{13,0,378},{13,0,425},{13,0,475},{14,0,63},{14,0,380},{14,0,384}
+,{15,0,133},{18,0,112},{148,0,72},{135,0,1093},{132,0,679},{8,0,913},{10,0,903},
+{10,0,915},{12,0,648},{12,0,649},{14,0,455},{16,0,112},{138,11,438},{137,0,203},
+{134,10,292},{134,0,1492},{7,0,1374},{8,0,540},{5,10,177},{6,10,616},{7,10,827},
+{9,10,525},{138,10,656},{135,0,1486},{9,0,714},{138,10,31},{136,0,825},{134,0,
+1511},{132,11,637},{134,0,952},{4,10,161},{133,10,631},{5,0,143},{5,0,769},{6,0,
+1760},{7,0,682},{7,0,1992},{136,0,736},{132,0,700},{134,0,1540},{132,11,777},{9,
+11,867},{138,11,837},{7,0,1557},{135,10,1684},{133,0,860},{6,0,422},{7,0,0},{7,0
+,1544},{9,0,605},{11,0,990},{12,0,235},{12,0,453},{13,0,47},{13,0,266},{9,10,469
+},{9,10,709},{12,10,512},{14,10,65},{145,10,12},{11,0,807},{10,10,229},{11,10,73
+},{139,10,376},{6,11,170},{7,11,1080},{8,11,395},{8,11,487},{11,11,125},{141,11,
+147},{5,0,515},{137,0,131},{7,0,1605},{11,0,962},{146,0,139},{132,0,646},{4,0,
+396},{7,0,728},{9,0,117},{13,0,202},{148,0,51},{6,0,121},{6,0,124},{6,0,357},{7,
+0,1138},{7,0,1295},{8,0,162},{8,0,508},{11,0,655},{4,11,535},{6,10,558},{7,10,
+651},{8,11,618},{9,10,0},{10,10,34},{139,10,1008},{135,11,1245},{138,0,357},{150
+,11,23},{133,0,237},{135,0,1784},{7,10,1832},{138,10,374},{132,0,713},{132,11,46
+},{6,0,1536},{10,0,348},{5,11,811},{6,11,1679},{6,11,1714},{135,11,2032},{11,11,
+182},{142,11,195},{6,0,523},{7,0,738},{7,10,771},{7,10,1731},{9,10,405},{138,10,
+421},{7,11,1458},{9,11,407},{139,11,15},{6,11,34},{7,11,69},{7,11,640},{7,11,
+1089},{8,11,708},{8,11,721},{9,11,363},{9,11,643},{10,11,628},{148,11,98},{133,0
+,434},{135,0,1877},{7,0,571},{138,0,366},{5,10,881},{133,10,885},{9,0,513},{10,0
+,25},{10,0,39},{12,0,122},{140,0,187},{132,0,580},{5,10,142},{134,10,546},{132,
+11,462},{137,0,873},{5,10,466},{11,10,571},{12,10,198},{13,10,283},{14,10,186},{
+15,10,21},{143,10,103},{7,0,171},{4,10,185},{5,10,257},{5,10,839},{5,10,936},{9,
+10,399},{10,10,258},{10,10,395},{10,10,734},{11,10,1014},{12,10,23},{13,10,350},
+{14,10,150},{147,10,6},{134,0,625},{7,0,107},{7,0,838},{8,0,550},{138,0,401},{5,
+11,73},{6,11,23},{134,11,338},{4,0,943},{6,0,1850},{12,0,713},{142,0,434},{11,0,
+588},{11,0,864},{11,0,936},{11,0,968},{12,0,73},{12,0,343},{12,0,394},{13,0,275}
+,{14,0,257},{15,0,160},{7,10,404},{7,10,1377},{7,10,1430},{7,10,2017},{8,10,149}
+,{8,10,239},{8,10,512},{8,10,793},{8,10,818},{9,10,474},{9,10,595},{10,10,122},{
+10,10,565},{10,10,649},{10,10,783},{11,10,239},{11,10,295},{11,10,447},{11,10,
+528},{11,10,639},{11,10,800},{12,10,25},{12,10,157},{12,10,316},{12,10,390},{12,
+10,391},{12,10,395},{12,10,478},{12,10,503},{12,10,592},{12,10,680},{13,10,50},{
+13,10,53},{13,10,132},{13,10,198},{13,10,322},{13,10,415},{13,10,511},{14,10,71}
+,{14,10,395},{15,10,71},{15,10,136},{17,10,123},{18,10,93},{147,10,58},{133,0,
+768},{11,0,103},{142,0,0},{136,10,712},{132,0,799},{132,0,894},{7,11,725},{8,11,
+498},{139,11,268},{135,11,1798},{135,11,773},{141,11,360},{4,10,377},{152,10,13}
+,{135,0,1673},{132,11,583},{134,0,1052},{133,11,220},{140,11,69},{132,11,544},{4
+,10,180},{135,10,1906},{134,0,272},{4,0,441},{134,0,1421},{4,0,9},{5,0,128},{7,0
+,368},{11,0,480},{148,0,3},{5,11,176},{6,11,437},{6,11,564},{11,11,181},{141,11,
+183},{132,10,491},{7,0,1182},{141,11,67},{6,0,1346},{4,10,171},{138,10,234},{4,
+10,586},{7,10,1186},{138,10,631},{136,0,682},{134,0,1004},{15,0,24},{143,11,24},
+{134,0,968},{4,0,2},{6,0,742},{6,0,793},{7,0,545},{7,0,894},{9,10,931},{10,10,
+334},{148,10,71},{136,11,600},{133,10,765},{9,0,769},{140,0,185},{4,11,790},{5,
+11,273},{134,11,394},{7,0,474},{137,0,578},{4,11,135},{6,11,127},{7,11,1185},{7,
+11,1511},{8,11,613},{11,11,5},{12,11,133},{12,11,495},{12,11,586},{14,11,385},{
+15,11,118},{17,11,20},{146,11,98},{133,10,424},{5,0,530},{142,0,113},{6,11,230},
+{7,11,961},{7,11,1085},{136,11,462},{7,11,1954},{137,11,636},{136,10,714},{149,
+11,6},{135,10,685},{9,10,420},{10,10,269},{10,10,285},{10,10,576},{11,10,397},{
+13,10,175},{145,10,90},{132,10,429},{5,0,556},{5,11,162},{136,11,68},{132,11,654
+},{4,11,156},{7,11,998},{7,11,1045},{7,11,1860},{9,11,48},{9,11,692},{11,11,419}
+,{139,11,602},{6,0,1317},{8,0,16},{9,0,825},{12,0,568},{7,11,1276},{8,11,474},{
+137,11,652},{18,0,97},{7,10,18},{7,10,699},{7,10,1966},{8,10,752},{9,10,273},{9,
+10,412},{9,10,703},{10,10,71},{10,10,427},{138,10,508},{10,0,703},{7,11,1454},{
+138,11,703},{4,10,53},{5,10,186},{135,10,752},{134,0,892},{134,0,1571},{8,10,575
+},{10,10,289},{139,10,319},{6,0,186},{137,0,426},{134,0,1101},{132,10,675},{132,
+0,585},{6,0,1870},{137,0,937},{152,11,10},{9,11,197},{10,11,300},{12,11,473},{13
+,11,90},{141,11,405},{4,0,93},{5,0,252},{6,0,229},{7,0,291},{9,0,550},{139,0,644
+},{137,0,749},{9,0,162},{6,10,209},{8,10,468},{9,10,210},{11,10,36},{12,10,28},{
+12,10,630},{13,10,21},{13,10,349},{14,10,7},{145,10,13},{132,0,381},{132,11,606}
+,{4,10,342},{135,10,1179},{7,11,1587},{7,11,1707},{10,11,528},{139,11,504},{12,
+11,39},{13,11,265},{141,11,439},{4,10,928},{133,10,910},{7,10,1838},{7,11,1978},
+{136,11,676},{6,0,762},{6,0,796},{134,0,956},{4,10,318},{4,10,496},{7,10,856},{
+139,10,654},{137,11,242},{4,11,361},{133,11,315},{132,11,461},{132,11,472},{132,
+0,857},{5,0,21},{6,0,77},{6,0,157},{7,0,974},{7,0,1301},{7,0,1339},{7,0,1490},{7
+,0,1873},{9,0,628},{7,10,915},{8,10,247},{147,10,0},{4,10,202},{5,10,382},{6,10,
+454},{7,10,936},{7,10,1803},{8,10,758},{9,10,375},{9,10,895},{10,10,743},{10,10,
+792},{11,10,978},{11,10,1012},{142,10,109},{7,11,617},{10,11,498},{11,11,501},{
+12,11,16},{140,11,150},{7,10,1150},{7,10,1425},{7,10,1453},{10,11,747},{140,10,
+513},{133,11,155},{11,0,919},{141,0,409},{138,10,791},{10,0,633},{139,11,729},{7
+,11,163},{8,11,319},{9,11,402},{10,11,24},{10,11,681},{11,11,200},{11,11,567},{
+12,11,253},{12,11,410},{142,11,219},{5,11,475},{7,11,1780},{9,11,230},{11,11,297
+},{11,11,558},{14,11,322},{147,11,76},{7,0,332},{6,10,445},{137,10,909},{135,11,
+1956},{136,11,274},{134,10,578},{135,0,1489},{135,11,1848},{5,11,944},{134,11,
+1769},{132,11,144},{136,10,766},{4,0,832},{135,10,541},{8,0,398},{9,0,681},{139,
+0,632},{136,0,645},{9,0,791},{10,0,93},{16,0,13},{17,0,23},{18,0,135},{19,0,12},
+{20,0,1},{20,0,12},{148,0,14},{6,11,247},{137,11,555},{134,0,20},{132,0,800},{
+135,0,1841},{139,10,983},{137,10,768},{132,10,584},{141,11,51},{6,0,1993},{4,11,
+620},{138,11,280},{136,0,769},{11,0,290},{11,0,665},{7,11,1810},{11,11,866},{12,
+11,103},{13,11,495},{17,11,67},{147,11,74},{134,0,1426},{139,0,60},{4,10,326},{
+135,10,1770},{7,0,1874},{9,0,641},{132,10,226},{6,0,644},{5,10,426},{8,10,30},{9
+,10,2},{11,10,549},{147,10,122},{5,11,428},{138,11,442},{135,11,1871},{135,0,
+1757},{147,10,117},{135,0,937},{135,0,1652},{6,0,654},{134,0,1476},{133,11,99},{
+135,0,527},{132,10,345},{4,10,385},{4,11,397},{7,10,265},{135,10,587},{4,0,579},
+{5,0,226},{5,0,323},{135,0,960},{134,0,1486},{8,11,502},{144,11,9},{4,10,347},{5
+,10,423},{5,10,996},{135,10,1329},{7,11,727},{146,11,73},{4,11,485},{7,11,353},{
+7,10,1259},{7,11,1523},{9,10,125},{139,10,65},{6,0,325},{5,10,136},{6,11,366},{7
+,11,1384},{7,11,1601},{136,10,644},{138,11,160},{6,0,1345},{137,11,282},{18,0,91
+},{147,0,70},{136,0,404},{4,11,157},{133,11,471},{133,0,973},{6,0,135},{135,0,
+1176},{8,11,116},{11,11,551},{142,11,159},{4,0,549},{4,10,433},{133,10,719},{136
+,0,976},{5,11,160},{7,11,363},{7,11,589},{10,11,170},{141,11,55},{144,0,21},{144
+,0,51},{135,0,314},{135,10,1363},{4,11,108},{7,11,405},{10,11,491},{139,11,498},
+{146,0,4},{4,10,555},{8,10,536},{10,10,288},{139,10,1005},{135,11,1005},{6,0,281
+},{7,0,6},{8,0,282},{8,0,480},{8,0,499},{9,0,198},{10,0,143},{10,0,169},{10,0,
+211},{10,0,417},{10,0,574},{11,0,147},{11,0,395},{12,0,75},{12,0,407},{12,0,608}
+,{13,0,500},{142,0,251},{6,0,1093},{6,0,1405},{9,10,370},{138,10,90},{4,11,926},
+{133,11,983},{135,0,1776},{134,0,1528},{132,0,419},{132,11,538},{6,11,294},{7,11
+,1267},{136,11,624},{135,11,1772},{138,11,301},{4,10,257},{135,10,2031},{4,0,138
+},{7,0,1012},{7,0,1280},{9,0,76},{135,10,1768},{132,11,757},{5,0,29},{140,0,638}
+,{7,11,655},{135,11,1844},{7,0,1418},{6,11,257},{135,11,1522},{8,11,469},{138,11
+,47},{142,11,278},{6,10,83},{6,10,1733},{135,10,1389},{11,11,204},{11,11,243},{
+140,11,293},{135,11,1875},{6,0,1710},{135,0,2038},{137,11,299},{4,0,17},{5,0,23}
+,{7,0,995},{11,0,383},{11,0,437},{12,0,460},{140,0,532},{133,0,862},{137,10,696}
+,{6,0,592},{138,0,946},{138,11,599},{7,10,1718},{9,10,95},{9,10,274},{10,10,279}
+,{10,10,317},{10,10,420},{11,10,303},{11,10,808},{12,10,134},{12,10,367},{13,10,
+149},{13,10,347},{14,10,349},{14,10,406},{18,10,22},{18,10,89},{18,10,122},{147,
+10,47},{8,0,70},{12,0,171},{141,0,272},{133,10,26},{132,10,550},{137,0,812},{10,
+0,233},{139,0,76},{134,0,988},{134,0,442},{136,10,822},{7,0,896},{4,10,902},{5,
+10,809},{134,10,122},{5,11,150},{7,11,106},{8,11,603},{9,11,593},{9,11,634},{10,
+11,44},{10,11,173},{11,11,462},{11,11,515},{13,11,216},{13,11,288},{142,11,400},
+{136,0,483},{135,10,262},{6,0,1709},{133,10,620},{4,10,34},{5,10,574},{7,10,279}
+,{7,10,1624},{136,10,601},{137,10,170},{147,0,119},{12,11,108},{141,11,291},{11,
+0,69},{12,0,105},{12,0,117},{13,0,213},{14,0,13},{14,0,62},{14,0,177},{14,0,421}
+,{15,0,19},{146,0,141},{137,0,309},{11,11,278},{142,11,73},{7,0,608},{7,0,976},{
+9,0,146},{10,0,206},{10,0,596},{13,0,218},{142,0,153},{133,10,332},{6,10,261},{8
+,10,182},{139,10,943},{4,11,493},{144,11,55},{134,10,1721},{132,0,768},{4,10,933
+},{133,10,880},{7,11,555},{7,11,1316},{7,11,1412},{7,11,1839},{9,11,192},{9,11,
+589},{11,11,241},{11,11,676},{11,11,811},{11,11,891},{12,11,140},{12,11,346},{12
+,11,479},{13,11,30},{13,11,49},{13,11,381},{14,11,188},{15,11,150},{16,11,76},{
+18,11,30},{148,11,52},{4,0,518},{135,0,1136},{6,11,568},{7,11,112},{7,11,1804},{
+8,11,362},{8,11,410},{8,11,830},{9,11,514},{11,11,649},{142,11,157},{135,11,673}
+,{8,0,689},{137,0,863},{4,0,18},{7,0,145},{7,0,444},{7,0,1278},{8,0,49},{8,0,400
+},{9,0,71},{9,0,250},{10,0,459},{12,0,160},{16,0,24},{132,11,625},{140,0,1020},{
+4,0,997},{6,0,1946},{6,0,1984},{134,0,1998},{6,11,16},{6,11,158},{7,11,43},{7,11
+,129},{7,11,181},{8,11,276},{8,11,377},{10,11,523},{11,11,816},{12,11,455},{13,
+11,303},{142,11,135},{133,10,812},{134,0,658},{4,11,1},{7,11,1143},{7,11,1463},{
+8,11,61},{9,11,207},{9,11,390},{9,11,467},{139,11,836},{150,11,26},{140,0,106},{
+6,0,1827},{10,0,931},{18,0,166},{20,0,114},{4,10,137},{7,10,1178},{7,11,1319},{
+135,10,1520},{133,0,1010},{4,11,723},{5,11,895},{7,11,1031},{8,11,199},{8,11,340
+},{9,11,153},{9,11,215},{10,11,21},{10,11,59},{10,11,80},{10,11,224},{11,11,229}
+,{11,11,652},{12,11,192},{13,11,146},{142,11,91},{132,11,295},{6,11,619},{7,11,
+898},{7,11,1092},{8,11,485},{18,11,28},{147,11,116},{137,11,51},{6,10,1661},{7,
+10,1975},{7,10,2009},{135,10,2011},{5,11,309},{140,11,211},{5,0,87},{7,0,313},{7
+,0,1103},{10,0,208},{10,0,582},{11,0,389},{11,0,813},{12,0,385},{13,0,286},{14,0
+,124},{146,0,108},{5,11,125},{8,11,77},{138,11,15},{132,0,267},{133,0,703},{137,
+11,155},{133,11,439},{11,11,164},{140,11,76},{9,0,496},{5,10,89},{7,10,1915},{9,
+10,185},{9,10,235},{10,10,64},{10,10,270},{10,10,403},{10,10,469},{10,10,529},{
+10,10,590},{11,10,140},{11,10,860},{13,10,1},{13,10,422},{14,10,341},{14,10,364}
+,{17,10,93},{18,10,113},{19,10,97},{147,10,113},{133,10,695},{135,0,1121},{5,10,
+6},{6,10,183},{7,10,680},{7,10,978},{7,10,1013},{7,10,1055},{12,10,230},{13,10,
+172},{146,10,29},{4,11,8},{7,11,1152},{7,11,1153},{7,11,1715},{9,11,374},{10,11,
+478},{139,11,648},{135,11,1099},{6,10,29},{139,10,63},{4,0,561},{10,0,249},{139,
+0,209},{132,0,760},{7,11,799},{138,11,511},{136,11,87},{9,0,154},{140,0,485},{
+136,0,255},{132,0,323},{140,0,419},{132,10,311},{134,10,1740},{4,0,368},{135,0,
+641},{7,10,170},{8,10,90},{8,10,177},{8,10,415},{11,10,714},{142,10,281},{4,11,
+69},{5,11,122},{9,11,656},{138,11,464},{5,11,849},{134,11,1633},{8,0,522},{142,0
+,328},{11,10,91},{13,10,129},{15,10,101},{145,10,125},{7,0,562},{8,0,551},{4,10,
+494},{6,10,74},{7,10,44},{11,11,499},{12,10,17},{15,10,5},{148,10,11},{4,10,276}
+,{133,10,296},{9,0,92},{147,0,91},{4,10,7},{5,10,90},{5,10,158},{6,10,542},{7,10
+,221},{7,10,1574},{9,10,490},{10,10,540},{11,10,443},{139,10,757},{6,0,525},{6,0
+,1976},{8,0,806},{9,0,876},{140,0,284},{5,11,859},{7,10,588},{7,11,1160},{8,11,
+107},{9,10,175},{9,11,291},{9,11,439},{10,10,530},{10,11,663},{11,11,609},{140,
+11,197},{7,11,168},{13,11,196},{141,11,237},{139,0,958},{133,0,594},{135,10,580}
+,{7,10,88},{136,10,627},{6,0,479},{6,0,562},{7,0,1060},{13,0,6},{5,10,872},{6,10
+,57},{7,10,471},{9,10,447},{137,10,454},{136,11,413},{145,11,19},{4,11,117},{6,
+11,372},{7,11,1905},{142,11,323},{4,11,722},{139,11,471},{17,0,61},{5,10,31},{
+134,10,614},{8,10,330},{140,10,477},{7,10,1200},{138,10,460},{6,10,424},{135,10,
+1866},{6,0,1641},{136,0,820},{6,0,1556},{134,0,1618},{9,11,5},{12,11,216},{12,11
+,294},{12,11,298},{12,11,400},{12,11,518},{13,11,229},{143,11,139},{15,11,155},{
+144,11,79},{4,0,302},{135,0,1766},{5,10,13},{134,10,142},{6,0,148},{7,0,1313},{7
+,10,116},{8,10,322},{8,10,755},{9,10,548},{10,10,714},{11,10,884},{141,10,324},{
+137,0,676},{9,11,88},{139,11,270},{5,11,12},{7,11,375},{137,11,438},{134,0,1674}
+,{7,10,1472},{135,10,1554},{11,0,178},{7,10,1071},{7,10,1541},{7,10,1767},{7,10,
+1806},{11,10,162},{11,10,242},{12,10,605},{15,10,26},{144,10,44},{6,0,389},{7,0,
+149},{9,0,142},{138,0,94},{140,11,71},{145,10,115},{6,0,8},{7,0,1881},{8,0,91},{
+11,11,966},{12,11,287},{13,11,342},{13,11,402},{15,11,110},{143,11,163},{4,11,
+258},{136,11,639},{6,11,22},{7,11,903},{138,11,577},{133,11,681},{135,10,1111},{
+135,11,1286},{9,0,112},{8,10,1},{138,10,326},{5,10,488},{6,10,527},{7,10,489},{7
+,10,1636},{8,10,121},{8,10,144},{8,10,359},{9,10,193},{9,10,241},{9,10,336},{9,
+10,882},{11,10,266},{11,10,372},{11,10,944},{12,10,401},{140,10,641},{4,11,664},
+{133,11,804},{6,0,747},{134,0,1015},{135,0,1746},{9,10,31},{10,10,244},{10,10,
+699},{12,10,149},{141,10,497},{133,10,377},{135,0,24},{6,0,1352},{5,11,32},{145,
+10,101},{7,0,1530},{10,0,158},{13,0,13},{13,0,137},{13,0,258},{14,0,111},{14,0,
+225},{14,0,253},{14,0,304},{14,0,339},{14,0,417},{146,0,33},{4,0,503},{135,0,
+1661},{5,0,130},{6,0,845},{7,0,1314},{9,0,610},{10,0,718},{11,0,601},{11,0,819},
+{11,0,946},{140,0,536},{10,0,149},{11,0,280},{142,0,336},{134,0,1401},{135,0,
+1946},{8,0,663},{144,0,8},{134,0,1607},{135,10,2023},{4,11,289},{7,11,629},{7,11
+,1698},{7,11,1711},{140,11,215},{6,11,450},{136,11,109},{10,0,882},{10,0,883},{
+10,0,914},{138,0,928},{133,10,843},{136,11,705},{132,10,554},{133,10,536},{5,0,
+417},{9,10,79},{11,10,625},{145,10,7},{7,11,1238},{142,11,37},{4,0,392},{135,0,
+1597},{5,0,433},{9,0,633},{11,0,629},{132,10,424},{7,10,336},{136,10,785},{134,
+11,355},{6,0,234},{7,0,769},{9,0,18},{138,0,358},{4,10,896},{134,10,1777},{138,
+11,323},{7,0,140},{7,0,1950},{8,0,680},{11,0,817},{147,0,88},{7,0,1222},{138,0,
+386},{139,11,908},{11,0,249},{12,0,313},{16,0,66},{145,0,26},{134,0,5},{7,10,750
+},{9,10,223},{11,10,27},{11,10,466},{12,10,624},{14,10,265},{146,10,61},{134,11,
+26},{134,0,1216},{5,0,963},{134,0,1773},{4,11,414},{5,11,467},{9,11,654},{10,11,
+451},{12,11,59},{141,11,375},{135,11,17},{4,10,603},{133,10,661},{4,10,11},{6,10
+,128},{7,10,231},{7,10,1533},{138,10,725},{135,11,955},{7,0,180},{8,0,509},{136,
+0,792},{132,10,476},{132,0,1002},{133,11,538},{135,10,1807},{132,0,931},{7,0,943
+},{11,0,614},{140,0,747},{135,0,1837},{9,10,20},{10,10,324},{10,10,807},{139,10,
+488},{134,0,641},{6,11,280},{10,11,502},{11,11,344},{140,11,38},{5,11,45},{7,11,
+1161},{11,11,448},{11,11,880},{13,11,139},{13,11,407},{15,11,16},{17,11,95},{18,
+11,66},{18,11,88},{18,11,123},{149,11,7},{9,0,280},{138,0,134},{22,0,22},{23,0,5
+},{151,0,29},{136,11,777},{4,0,90},{5,0,545},{7,0,754},{9,0,186},{10,0,72},{10,0
+,782},{11,0,577},{11,0,610},{11,0,960},{12,0,354},{12,0,362},{12,0,595},{4,11,
+410},{135,11,521},{135,11,1778},{5,10,112},{6,10,103},{134,10,150},{138,10,356},
+{132,0,742},{7,0,151},{9,0,329},{139,0,254},{8,0,853},{8,0,881},{8,0,911},{8,0,
+912},{10,0,872},{12,0,741},{12,0,742},{152,0,18},{4,11,573},{136,11,655},{6,0,
+921},{134,0,934},{9,0,187},{10,0,36},{11,0,1016},{17,0,44},{146,0,64},{7,0,833},
+{136,0,517},{4,0,506},{5,0,295},{135,0,1680},{4,10,708},{8,10,15},{9,10,50},{9,
+10,386},{11,10,18},{11,10,529},{140,10,228},{7,0,251},{7,0,1701},{8,0,436},{4,10
+,563},{7,10,592},{7,10,637},{7,10,770},{8,10,463},{9,10,60},{9,10,335},{9,10,904
+},{10,10,73},{11,10,434},{12,10,585},{13,10,331},{18,10,110},{148,10,60},{132,10
+,502},{136,0,584},{6,10,347},{138,10,161},{7,0,987},{9,0,688},{10,0,522},{11,0,
+788},{12,0,137},{12,0,566},{14,0,9},{14,0,24},{14,0,64},{7,11,899},{142,11,325},
+{4,0,214},{5,0,500},{5,10,102},{6,10,284},{7,10,1079},{7,10,1423},{7,10,1702},{8
+,10,470},{9,10,554},{9,10,723},{139,10,333},{7,10,246},{135,10,840},{6,10,10},{8
+,10,571},{9,10,739},{143,10,91},{133,10,626},{146,0,195},{134,0,1775},{7,0,389},
+{7,0,700},{7,0,940},{8,0,514},{9,0,116},{9,0,535},{10,0,118},{11,0,107},{11,0,
+148},{11,0,922},{12,0,254},{12,0,421},{142,0,238},{5,10,18},{6,10,526},{13,10,24
+},{13,10,110},{19,10,5},{147,10,44},{132,0,743},{11,0,292},{4,10,309},{5,10,462}
+,{7,10,970},{135,10,1097},{22,10,30},{150,10,33},{139,11,338},{135,11,1598},{7,0
+,1283},{9,0,227},{11,0,325},{11,0,408},{14,0,180},{146,0,47},{4,0,953},{6,0,1805
+},{6,0,1814},{6,0,1862},{140,0,774},{6,11,611},{135,11,1733},{135,11,1464},{5,0,
+81},{7,0,146},{7,0,1342},{8,0,53},{8,0,561},{8,0,694},{8,0,754},{9,0,115},{9,0,
+179},{9,0,894},{10,0,462},{10,0,813},{11,0,230},{11,0,657},{11,0,699},{11,0,748}
+,{12,0,119},{12,0,200},{12,0,283},{142,0,273},{5,0,408},{6,0,789},{6,0,877},{6,0
+,1253},{6,0,1413},{137,0,747},{134,10,1704},{135,11,663},{6,0,1910},{6,0,1915},{
+6,0,1923},{9,0,913},{9,0,928},{9,0,950},{9,0,954},{9,0,978},{9,0,993},{12,0,812}
+,{12,0,819},{12,0,831},{12,0,833},{12,0,838},{12,0,909},{12,0,928},{12,0,931},{
+12,0,950},{15,0,186},{15,0,187},{15,0,195},{15,0,196},{15,0,209},{15,0,215},{15,
+0,236},{15,0,241},{15,0,249},{15,0,253},{18,0,180},{18,0,221},{18,0,224},{18,0,
+227},{18,0,229},{149,0,60},{7,0,1826},{135,0,1938},{11,0,490},{18,0,143},{5,10,
+86},{7,10,743},{9,10,85},{10,10,281},{10,10,432},{12,10,251},{13,10,118},{142,10
+,378},{5,10,524},{133,10,744},{141,11,442},{10,10,107},{140,10,436},{135,11,503}
+,{134,0,1162},{132,10,927},{7,0,30},{8,0,86},{8,0,315},{8,0,700},{9,0,576},{9,0,
+858},{10,0,414},{11,0,310},{11,0,888},{11,0,904},{12,0,361},{13,0,248},{13,0,371
+},{14,0,142},{12,10,670},{146,10,94},{134,0,721},{4,11,113},{5,11,163},{5,11,735
+},{7,11,1009},{7,10,1149},{9,11,9},{9,10,156},{9,11,771},{12,11,90},{13,11,138},
+{13,11,410},{143,11,128},{138,0,839},{133,10,778},{137,0,617},{133,10,502},{8,10
+,196},{10,10,283},{139,10,406},{6,0,428},{7,0,524},{8,0,169},{8,0,234},{9,0,480}
+,{138,0,646},{133,10,855},{134,0,1648},{7,0,1205},{138,0,637},{7,0,1596},{4,11,
+935},{133,11,823},{5,11,269},{7,11,434},{7,11,891},{8,11,339},{9,11,702},{11,11,
+594},{11,11,718},{145,11,100},{7,11,878},{9,11,485},{141,11,264},{4,0,266},{8,0,
+4},{9,0,39},{10,0,166},{11,0,918},{12,0,635},{20,0,10},{22,0,27},{22,0,43},{22,0
+,52},{134,11,1713},{7,10,1400},{9,10,446},{138,10,45},{135,11,900},{132,0,862},{
+134,0,1554},{135,11,1033},{19,0,16},{147,11,16},{135,11,1208},{7,0,157},{136,0,
+279},{6,0,604},{136,0,391},{13,10,455},{15,10,99},{15,10,129},{144,10,68},{135,
+10,172},{7,0,945},{11,0,713},{139,0,744},{4,0,973},{10,0,877},{10,0,937},{10,0,
+938},{140,0,711},{139,0,1022},{132,10,568},{142,11,143},{4,0,567},{9,0,859},{132
+,10,732},{7,0,1846},{136,0,628},{136,10,733},{133,0,762},{4,10,428},{135,10,1789
+},{10,0,784},{13,0,191},{7,10,2015},{140,10,665},{133,0,298},{7,0,633},{7,0,905}
+,{7,0,909},{7,0,1538},{9,0,767},{140,0,636},{138,10,806},{132,0,795},{139,0,301}
+,{135,0,1970},{5,11,625},{135,11,1617},{135,11,275},{7,11,37},{8,11,425},{8,11,
+693},{9,11,720},{10,11,380},{10,11,638},{11,11,273},{11,11,307},{11,11,473},{12,
+11,61},{143,11,43},{135,11,198},{134,0,1236},{7,0,369},{12,0,644},{12,0,645},{
+144,0,90},{19,0,15},{149,0,27},{6,0,71},{7,0,845},{8,0,160},{9,0,318},{6,10,1623
+},{134,10,1681},{134,0,1447},{134,0,1255},{138,0,735},{8,0,76},{132,11,168},{6,
+10,1748},{8,10,715},{9,10,802},{10,10,46},{10,10,819},{13,10,308},{14,10,351},{
+14,10,363},{146,10,67},{135,11,91},{6,0,474},{4,10,63},{133,10,347},{133,10,749}
+,{138,0,841},{133,10,366},{6,0,836},{132,11,225},{135,0,1622},{135,10,89},{140,0
+,735},{134,0,1601},{138,11,145},{6,0,1390},{137,0,804},{142,0,394},{6,11,15},{7,
+11,70},{10,11,240},{147,11,93},{6,0,96},{135,0,1426},{4,0,651},{133,0,289},{7,11
+,956},{7,10,977},{7,11,1157},{7,11,1506},{7,11,1606},{7,11,1615},{7,11,1619},{7,
+11,1736},{7,11,1775},{8,11,590},{9,11,324},{9,11,736},{9,11,774},{9,11,776},{9,
+11,784},{10,11,567},{10,11,708},{11,11,518},{11,11,613},{11,11,695},{11,11,716},
+{11,11,739},{11,11,770},{11,11,771},{11,11,848},{11,11,857},{11,11,931},{11,11,
+947},{12,11,326},{12,11,387},{12,11,484},{12,11,528},{12,11,552},{12,11,613},{13
+,11,189},{13,11,256},{13,11,340},{13,11,432},{13,11,436},{13,11,440},{13,11,454}
+,{14,11,174},{14,11,220},{14,11,284},{14,11,390},{145,11,121},{7,0,688},{8,0,35}
+,{9,0,511},{10,0,767},{147,0,118},{134,0,667},{4,0,513},{5,10,824},{133,10,941},
+{7,10,440},{8,10,230},{139,10,106},{134,0,2034},{135,11,1399},{143,11,66},{135,
+11,1529},{4,11,145},{6,11,176},{7,11,395},{9,11,562},{144,11,28},{132,11,501},{
+132,0,704},{134,0,1524},{7,0,1078},{134,11,464},{6,11,509},{10,11,82},{20,11,91}
+,{151,11,13},{4,0,720},{133,0,306},{133,0,431},{7,0,1196},{4,10,914},{5,10,800},
+{133,10,852},{135,11,1189},{10,0,54},{141,10,115},{7,10,564},{142,10,168},{5,0,
+464},{6,0,236},{7,0,696},{7,0,914},{7,0,1108},{7,0,1448},{9,0,15},{9,0,564},{10,
+0,14},{12,0,565},{13,0,449},{14,0,53},{15,0,13},{16,0,64},{17,0,41},{4,10,918},{
+133,10,876},{6,0,1418},{134,10,1764},{4,10,92},{133,10,274},{134,0,907},{4,11,
+114},{8,10,501},{9,11,492},{13,11,462},{142,11,215},{4,11,77},{5,11,361},{6,11,
+139},{6,11,401},{6,11,404},{7,11,413},{7,11,715},{7,11,1716},{11,11,279},{12,11,
+179},{12,11,258},{13,11,244},{142,11,358},{6,0,1767},{12,0,194},{145,0,107},{134
+,11,1717},{5,10,743},{142,11,329},{4,10,49},{7,10,280},{135,10,1633},{5,0,840},{
+7,11,1061},{8,11,82},{11,11,250},{12,11,420},{141,11,184},{135,11,724},{134,0,
+900},{136,10,47},{134,0,1436},{144,11,0},{6,0,675},{7,0,1008},{7,0,1560},{9,0,
+642},{11,0,236},{14,0,193},{5,10,272},{5,10,908},{5,10,942},{8,10,197},{9,10,47}
+,{11,10,538},{139,10,742},{4,0,68},{5,0,628},{5,0,634},{6,0,386},{7,0,794},{8,0,
+273},{9,0,563},{10,0,105},{10,0,171},{11,0,94},{139,0,354},{135,10,1911},{137,10
+,891},{4,0,95},{6,0,1297},{6,0,1604},{7,0,416},{139,0,830},{6,11,513},{135,11,
+1052},{7,0,731},{13,0,20},{143,0,11},{137,11,899},{10,0,850},{140,0,697},{4,0,
+662},{7,11,1417},{12,11,382},{17,11,48},{152,11,12},{133,0,736},{132,0,861},{4,
+10,407},{132,10,560},{141,10,490},{6,11,545},{7,11,565},{7,11,1669},{10,11,114},
+{11,11,642},{140,11,618},{6,0,871},{134,0,1000},{5,0,864},{10,0,648},{11,0,671},
+{15,0,46},{133,11,5},{133,0,928},{11,0,90},{13,0,7},{4,10,475},{11,10,35},{13,10
+,71},{13,10,177},{142,10,422},{136,0,332},{135,11,192},{134,0,1055},{136,11,763}
+,{11,0,986},{140,0,682},{7,0,76},{8,0,44},{9,0,884},{10,0,580},{11,0,399},{11,0,
+894},{143,0,122},{135,11,1237},{135,10,636},{11,0,300},{6,10,222},{7,10,1620},{8
+,10,409},{137,10,693},{4,11,87},{5,11,250},{10,11,601},{13,11,298},{13,11,353},{
+141,11,376},{5,0,518},{10,0,340},{11,0,175},{149,0,16},{140,0,771},{6,0,1108},{
+137,0,831},{132,0,836},{135,0,1852},{4,0,957},{6,0,1804},{8,0,842},{8,0,843},{8,
+0,851},{8,0,855},{140,0,767},{135,11,814},{4,11,57},{7,11,1195},{7,11,1438},{7,
+11,1548},{7,11,1835},{7,11,1904},{9,11,757},{10,11,604},{139,11,519},{133,10,882
+},{138,0,246},{4,0,934},{5,0,202},{8,0,610},{7,11,1897},{12,11,290},{13,11,80},{
+13,11,437},{145,11,74},{8,0,96},{9,0,36},{10,0,607},{10,0,804},{10,0,832},{11,0,
+423},{11,0,442},{12,0,309},{14,0,199},{15,0,90},{145,0,110},{132,10,426},{7,0,
+654},{8,0,240},{6,10,58},{7,10,745},{7,10,1969},{8,10,675},{9,10,479},{9,10,731}
+,{10,10,330},{10,10,593},{10,10,817},{11,10,32},{11,10,133},{11,10,221},{145,10,
+68},{9,0,13},{9,0,398},{9,0,727},{10,0,75},{10,0,184},{10,0,230},{10,0,564},{10,
+0,569},{11,0,973},{12,0,70},{12,0,189},{13,0,57},{141,0,257},{4,11,209},{135,11,
+902},{7,0,391},{137,10,538},{134,0,403},{6,11,303},{7,11,335},{7,11,1437},{7,11,
+1668},{8,11,553},{8,11,652},{8,11,656},{9,11,558},{11,11,743},{149,11,18},{132,
+11,559},{11,0,75},{142,0,267},{6,0,815},{141,11,2},{141,0,366},{137,0,631},{133,
+11,1017},{5,0,345},{135,0,1016},{133,11,709},{134,11,1745},{133,10,566},{7,0,952
+},{6,10,48},{9,10,139},{10,10,399},{11,10,469},{12,10,634},{141,10,223},{133,0,
+673},{9,0,850},{7,11,8},{136,11,206},{6,0,662},{149,0,35},{4,0,287},{133,0,1018}
+,{6,10,114},{7,10,1224},{7,10,1556},{136,10,3},{8,10,576},{137,10,267},{4,0,884}
+,{5,0,34},{10,0,724},{12,0,444},{13,0,354},{18,0,32},{23,0,24},{23,0,31},{152,0,
+5},{133,10,933},{132,11,776},{138,0,151},{136,0,427},{134,0,382},{132,0,329},{9,
+0,846},{10,0,827},{138,11,33},{9,0,279},{10,0,407},{14,0,84},{22,0,18},{135,11,
+1297},{136,11,406},{132,0,906},{136,0,366},{134,0,843},{134,0,1443},{135,0,1372}
+,{138,0,992},{4,0,123},{5,0,605},{7,0,1509},{136,0,36},{132,0,649},{8,11,175},{
+10,11,168},{138,11,573},{133,0,767},{134,0,1018},{135,11,1305},{12,10,30},{13,10
+,148},{14,10,87},{14,10,182},{16,10,42},{148,10,70},{134,11,607},{4,0,273},{5,0,
+658},{133,0,995},{6,0,72},{139,11,174},{10,0,483},{12,0,368},{7,10,56},{7,10,
+1989},{8,10,337},{8,10,738},{9,10,600},{13,10,447},{142,10,92},{5,11,784},{138,
+10,666},{135,0,1345},{139,11,882},{134,0,1293},{133,0,589},{134,0,1988},{5,0,117
+},{6,0,514},{6,0,541},{7,0,1164},{7,0,1436},{8,0,220},{8,0,648},{10,0,688},{139,
+0,560},{136,0,379},{5,0,686},{7,10,866},{135,10,1163},{132,10,328},{9,11,14},{9,
+11,441},{10,11,306},{139,11,9},{4,10,101},{135,10,1171},{5,10,833},{136,10,744},
+{5,11,161},{7,11,839},{135,11,887},{7,0,196},{10,0,765},{11,0,347},{11,0,552},{
+11,0,790},{12,0,263},{13,0,246},{13,0,270},{13,0,395},{14,0,176},{14,0,190},{14,
+0,398},{14,0,412},{15,0,32},{15,0,63},{16,0,88},{147,0,105},{6,10,9},{6,10,397},
+{7,10,53},{7,10,1742},{10,10,632},{11,10,828},{140,10,146},{5,0,381},{135,0,1792
+},{134,0,1452},{135,11,429},{8,0,367},{10,0,760},{14,0,79},{20,0,17},{152,0,0},{
+7,0,616},{138,0,413},{11,10,417},{12,10,223},{140,10,265},{7,11,1611},{13,11,14}
+,{15,11,44},{19,11,13},{148,11,76},{135,0,1229},{6,0,120},{7,0,1188},{7,0,1710},
+{8,0,286},{9,0,667},{11,0,592},{139,0,730},{135,11,1814},{135,0,1146},{4,10,186}
+,{5,10,157},{8,10,168},{138,10,6},{4,0,352},{135,0,687},{4,0,192},{5,0,49},{6,0,
+200},{6,0,293},{6,0,1696},{135,0,1151},{133,10,875},{5,10,773},{5,10,991},{6,10,
+1635},{134,10,1788},{7,10,111},{136,10,581},{6,0,935},{134,0,1151},{134,0,1050},
+{132,0,650},{132,0,147},{11,0,194},{12,0,62},{12,0,88},{11,11,194},{12,11,62},{
+140,11,88},{6,0,339},{135,0,923},{134,10,1747},{7,11,643},{136,11,236},{133,0,
+934},{7,10,1364},{7,10,1907},{141,10,158},{132,10,659},{4,10,404},{135,10,675},{
+7,11,581},{9,11,644},{137,11,699},{13,0,211},{14,0,133},{14,0,204},{15,0,64},{15
+,0,69},{15,0,114},{16,0,10},{19,0,23},{19,0,35},{19,0,39},{19,0,51},{19,0,71},{
+19,0,75},{152,0,15},{133,10,391},{5,11,54},{135,11,1513},{7,0,222},{8,0,341},{5,
+10,540},{134,10,1697},{134,10,78},{132,11,744},{136,0,293},{137,11,701},{7,11,
+930},{10,11,402},{10,11,476},{13,11,452},{18,11,55},{147,11,104},{132,0,637},{
+133,10,460},{8,11,50},{137,11,624},{132,11,572},{134,0,1159},{4,10,199},{139,10,
+34},{134,0,847},{134,10,388},{6,11,43},{7,11,38},{8,11,248},{9,11,504},{138,11,
+513},{9,0,683},{4,10,511},{6,10,608},{9,10,333},{10,10,602},{11,10,441},{11,10,
+723},{11,10,976},{140,10,357},{9,0,867},{138,0,837},{6,0,944},{135,11,326},{135,
+0,1809},{5,10,938},{7,11,783},{136,10,707},{133,11,766},{133,11,363},{6,0,170},{
+7,0,1080},{8,0,395},{8,0,487},{141,0,147},{6,11,258},{140,11,409},{4,0,535},{8,0
+,618},{5,11,249},{148,11,82},{6,0,1379},{149,11,15},{135,0,1625},{150,0,23},{5,
+11,393},{6,11,378},{7,11,1981},{9,11,32},{9,11,591},{10,11,685},{10,11,741},{142
+,11,382},{133,11,788},{7,11,1968},{10,11,19},{139,11,911},{7,11,1401},{135,11,
+1476},{4,11,61},{5,11,58},{5,11,171},{5,11,635},{5,11,683},{5,11,700},{6,11,291}
+,{6,11,566},{7,11,1650},{11,11,523},{12,11,273},{12,11,303},{15,11,39},{143,11,
+111},{6,10,469},{7,10,1709},{138,10,515},{4,0,778},{134,11,589},{132,0,46},{5,0,
+811},{6,0,1679},{6,0,1714},{135,0,2032},{7,0,1458},{9,0,407},{11,0,15},{12,0,651
+},{149,0,37},{7,0,938},{132,10,500},{6,0,34},{7,0,69},{7,0,1089},{7,0,1281},{8,0
+,708},{8,0,721},{9,0,363},{148,0,98},{10,11,231},{147,11,124},{7,11,726},{152,11
+,9},{5,10,68},{134,10,383},{136,11,583},{4,11,917},{133,11,1005},{11,10,216},{
+139,10,340},{135,11,1675},{8,0,441},{10,0,314},{143,0,3},{132,11,919},{4,10,337}
+,{6,10,353},{7,10,1934},{8,10,488},{137,10,429},{7,0,889},{7,10,1795},{8,10,259}
+,{9,10,135},{9,10,177},{9,10,860},{10,10,825},{11,10,115},{11,10,370},{11,10,405
+},{11,10,604},{12,10,10},{12,10,667},{12,10,669},{13,10,76},{14,10,310},{15,10,
+76},{15,10,147},{148,10,23},{4,10,15},{4,11,255},{5,10,22},{5,11,302},{6,11,132}
+,{6,10,244},{7,10,40},{7,11,128},{7,10,200},{7,11,283},{7,10,906},{7,10,1199},{7
+,11,1299},{9,10,616},{10,11,52},{10,11,514},{10,10,716},{11,10,635},{11,10,801},
+{11,11,925},{12,10,458},{13,11,92},{142,11,309},{132,0,462},{137,11,173},{135,10
+,1735},{8,0,525},{5,10,598},{7,10,791},{8,10,108},{137,10,123},{5,0,73},{6,0,23}
+,{134,0,338},{132,0,676},{132,10,683},{7,0,725},{8,0,498},{139,0,268},{12,0,21},
+{151,0,7},{135,0,773},{4,10,155},{135,10,1689},{4,0,164},{5,0,730},{5,10,151},{5
+,10,741},{6,11,210},{7,10,498},{7,10,870},{7,10,1542},{12,10,213},{14,10,36},{14
+,10,391},{17,10,111},{18,10,6},{18,10,46},{18,10,151},{19,10,36},{20,10,32},{20,
+10,56},{20,10,69},{20,10,102},{21,10,4},{22,10,8},{22,10,10},{22,10,14},{150,10,
+31},{4,10,624},{135,10,1752},{4,0,583},{9,0,936},{15,0,214},{18,0,199},{24,0,26}
+,{134,11,588},{7,0,1462},{11,0,659},{4,11,284},{134,11,223},{133,0,220},{139,0,
+803},{132,0,544},{4,10,492},{133,10,451},{16,0,98},{148,0,119},{4,11,218},{7,11,
+526},{143,11,137},{135,10,835},{4,11,270},{5,11,192},{6,11,332},{7,11,1322},{13,
+11,9},{13,10,70},{14,11,104},{142,11,311},{132,10,539},{140,11,661},{5,0,176},{6
+,0,437},{6,0,564},{11,0,181},{141,0,183},{135,0,1192},{6,10,113},{135,10,436},{
+136,10,718},{135,10,520},{135,0,1878},{140,11,196},{7,11,379},{8,11,481},{137,11
+,377},{5,11,1003},{6,11,149},{137,11,746},{8,11,262},{9,11,627},{10,11,18},{11,
+11,214},{11,11,404},{11,11,457},{11,11,780},{11,11,849},{11,11,913},{13,11,330},
+{13,11,401},{142,11,200},{149,0,26},{136,11,304},{132,11,142},{135,0,944},{4,0,
+790},{5,0,273},{134,0,394},{134,0,855},{4,0,135},{6,0,127},{7,0,1185},{7,0,1511}
+,{8,0,613},{11,0,5},{12,0,336},{12,0,495},{12,0,586},{12,0,660},{12,0,668},{14,0
+,385},{15,0,118},{17,0,20},{146,0,98},{6,0,230},{9,0,752},{18,0,109},{12,10,610}
+,{13,10,431},{144,10,59},{7,0,1954},{135,11,925},{4,11,471},{5,11,51},{6,11,602}
+,{8,11,484},{10,11,195},{140,11,159},{132,10,307},{136,11,688},{132,11,697},{7,
+11,812},{7,11,1261},{7,11,1360},{9,11,632},{140,11,352},{5,0,162},{8,0,68},{133,
+10,964},{4,0,654},{136,11,212},{4,0,156},{7,0,998},{7,0,1045},{7,0,1860},{9,0,48
+},{9,0,692},{11,0,419},{139,0,602},{133,11,221},{4,11,373},{5,11,283},{6,11,480}
+,{135,11,609},{142,11,216},{132,0,240},{6,11,192},{9,11,793},{145,11,55},{4,10,
+75},{5,10,180},{6,10,500},{7,10,58},{7,10,710},{138,10,645},{4,11,132},{5,11,69}
+,{5,10,649},{135,11,1242},{6,10,276},{7,10,282},{7,10,879},{7,10,924},{8,10,459}
+,{9,10,599},{9,10,754},{11,10,574},{12,10,128},{12,10,494},{13,10,52},{13,10,301
+},{15,10,30},{143,10,132},{132,10,200},{4,11,111},{135,11,302},{9,0,197},{10,0,
+300},{12,0,473},{13,0,90},{141,0,405},{132,11,767},{6,11,42},{7,11,1416},{7,11,
+1590},{7,11,2005},{8,11,131},{8,11,466},{9,11,672},{13,11,252},{148,11,103},{8,0
+,958},{8,0,999},{10,0,963},{138,0,1001},{135,10,1621},{135,0,858},{4,0,606},{137
+,11,444},{6,11,44},{136,11,368},{139,11,172},{4,11,570},{133,11,120},{139,11,624
+},{7,0,1978},{8,0,676},{6,10,225},{137,10,211},{7,0,972},{11,0,102},{136,10,687}
+,{6,11,227},{135,11,1589},{8,10,58},{9,10,724},{11,10,809},{13,10,113},{145,10,
+72},{4,0,361},{133,0,315},{132,0,461},{6,10,345},{135,10,1247},{132,0,472},{8,10
+,767},{8,10,803},{9,10,301},{137,10,903},{135,11,1333},{135,11,477},{7,10,1949},
+{136,10,674},{6,0,905},{138,0,747},{133,0,155},{134,10,259},{7,0,163},{8,0,319},
+{9,0,402},{10,0,24},{10,0,681},{11,0,200},{12,0,253},{12,0,410},{142,0,219},{5,0
+,475},{7,0,1780},{9,0,230},{11,0,297},{11,0,558},{14,0,322},{19,0,76},{6,11,1667
+},{7,11,2036},{138,11,600},{136,10,254},{6,0,848},{135,0,1956},{6,11,511},{140,
+11,132},{5,11,568},{6,11,138},{135,11,1293},{6,0,631},{137,0,838},{149,0,36},{4,
+11,565},{8,11,23},{136,11,827},{5,0,944},{134,0,1769},{4,0,144},{6,0,842},{6,0,
+1400},{4,11,922},{133,11,1023},{133,10,248},{9,10,800},{10,10,693},{11,10,482},{
+11,10,734},{139,10,789},{7,11,1002},{139,11,145},{4,10,116},{5,10,95},{5,10,445}
+,{7,10,1688},{8,10,29},{9,10,272},{11,10,509},{139,10,915},{14,0,369},{146,0,72}
+,{135,10,1641},{132,11,740},{133,10,543},{140,11,116},{6,0,247},{9,0,555},{5,10,
+181},{136,10,41},{133,10,657},{136,0,996},{138,10,709},{7,0,189},{8,10,202},{138
+,10,536},{136,11,402},{4,11,716},{141,11,31},{10,0,280},{138,0,797},{9,10,423},{
+140,10,89},{8,10,113},{9,10,877},{10,10,554},{11,10,83},{12,10,136},{147,10,109}
+,{133,10,976},{7,0,746},{132,10,206},{136,0,526},{139,0,345},{136,0,1017},{8,11,
+152},{9,11,53},{9,11,268},{9,11,901},{10,11,518},{10,11,829},{11,11,188},{13,11,
+74},{14,11,46},{15,11,17},{15,11,33},{17,11,40},{18,11,36},{19,11,20},{22,11,1},
+{152,11,2},{133,11,736},{136,11,532},{5,0,428},{138,0,651},{135,11,681},{135,0,
+1162},{7,0,327},{13,0,230},{17,0,113},{8,10,226},{10,10,537},{11,10,570},{11,10,
+605},{11,10,799},{11,10,804},{12,10,85},{12,10,516},{12,10,623},{12,11,677},{13,
+10,361},{14,10,77},{14,10,78},{147,10,110},{4,0,792},{7,0,1717},{10,0,546},{132,
+10,769},{4,11,684},{136,11,384},{132,10,551},{134,0,1203},{9,10,57},{9,10,459},{
+10,10,425},{11,10,119},{12,10,184},{12,10,371},{13,10,358},{145,10,51},{5,0,672}
+,{5,10,814},{8,10,10},{9,10,421},{9,10,729},{10,10,609},{139,10,689},{138,0,189}
+,{134,10,624},{7,11,110},{7,11,188},{8,11,290},{8,11,591},{9,11,382},{9,11,649},
+{11,11,71},{11,11,155},{11,11,313},{12,11,5},{13,11,325},{142,11,287},{133,0,99}
+,{6,0,1053},{135,0,298},{7,11,360},{7,11,425},{9,11,66},{9,11,278},{138,11,644},
+{4,0,397},{136,0,555},{137,10,269},{132,10,528},{4,11,900},{133,11,861},{6,0,
+1157},{5,11,254},{7,11,985},{136,11,73},{7,11,1959},{136,11,683},{12,0,398},{20,
+0,39},{21,0,11},{150,0,41},{4,0,485},{7,0,353},{135,0,1523},{6,0,366},{7,0,1384}
+,{135,0,1601},{138,0,787},{137,0,282},{5,10,104},{6,10,173},{135,10,1631},{139,
+11,146},{4,0,157},{133,0,471},{134,0,941},{132,11,725},{7,0,1336},{8,10,138},{8,
+10,342},{9,10,84},{10,10,193},{11,10,883},{140,10,359},{134,11,196},{136,0,116},
+{133,11,831},{134,0,787},{134,10,95},{6,10,406},{10,10,409},{10,10,447},{11,10,
+44},{140,10,100},{5,0,160},{7,0,363},{7,0,589},{10,0,170},{141,0,55},{134,0,1815
+},{132,0,866},{6,0,889},{6,0,1067},{6,0,1183},{4,11,321},{134,11,569},{5,11,848}
+,{134,11,66},{4,11,36},{6,10,1636},{7,11,1387},{10,11,205},{11,11,755},{141,11,
+271},{132,0,689},{9,0,820},{4,10,282},{7,10,1034},{11,10,398},{11,10,634},{12,10
+,1},{12,10,79},{12,10,544},{14,10,237},{17,10,10},{146,10,20},{4,0,108},{7,0,804
+},{139,0,498},{132,11,887},{6,0,1119},{135,11,620},{6,11,165},{138,11,388},{5,0,
+244},{5,10,499},{6,10,476},{7,10,600},{7,10,888},{135,10,1096},{140,0,609},{135,
+0,1005},{4,0,412},{133,0,581},{4,11,719},{135,11,155},{7,10,296},{7,10,596},{8,
+10,560},{8,10,586},{9,10,612},{11,10,304},{12,10,46},{13,10,89},{14,10,112},{145
+,10,122},{4,0,895},{133,0,772},{142,11,307},{135,0,1898},{4,0,926},{133,0,983},{
+4,11,353},{6,11,146},{6,11,1789},{7,11,288},{7,11,990},{7,11,1348},{9,11,665},{9
+,11,898},{11,11,893},{142,11,212},{132,0,538},{133,11,532},{6,0,294},{7,0,1267},
+{8,0,624},{141,0,496},{7,0,1325},{4,11,45},{135,11,1257},{138,0,301},{9,0,298},{
+12,0,291},{13,0,276},{14,0,6},{17,0,18},{21,0,32},{7,10,1599},{7,10,1723},{8,10,
+79},{8,10,106},{8,10,190},{8,10,302},{8,10,383},{8,10,713},{9,10,119},{9,10,233}
+,{9,10,419},{9,10,471},{10,10,181},{10,10,406},{11,10,57},{11,10,85},{11,10,120}
+,{11,10,177},{11,10,296},{11,10,382},{11,10,454},{11,10,758},{11,10,999},{12,10,
+27},{12,10,131},{12,10,245},{12,10,312},{12,10,446},{12,10,454},{13,10,98},{13,
+10,426},{13,10,508},{14,10,163},{14,10,272},{14,10,277},{14,10,370},{15,10,95},{
+15,10,138},{15,10,167},{17,10,38},{148,10,96},{132,0,757},{134,0,1263},{4,0,820}
+,{134,10,1759},{133,0,722},{136,11,816},{138,10,372},{145,10,16},{134,0,1039},{4
+,0,991},{134,0,2028},{133,10,258},{7,0,1875},{139,0,124},{6,11,559},{6,11,1691},
+{135,11,586},{5,0,324},{7,0,881},{8,10,134},{9,10,788},{140,10,438},{7,11,1823},
+{139,11,693},{6,0,1348},{134,0,1545},{134,0,911},{132,0,954},{8,0,329},{8,0,414}
+,{7,10,1948},{135,10,2004},{5,0,517},{6,10,439},{7,10,780},{135,10,1040},{132,0,
+816},{5,10,1},{6,10,81},{138,10,520},{9,0,713},{10,0,222},{5,10,482},{8,10,98},{
+10,10,700},{10,10,822},{11,10,302},{11,10,778},{12,10,50},{12,10,127},{12,10,396
+},{13,10,62},{13,10,328},{14,10,122},{147,10,72},{137,0,33},{5,10,2},{7,10,1494}
+,{136,10,589},{6,10,512},{7,10,797},{8,10,253},{9,10,77},{10,10,1},{10,11,108},{
+10,10,129},{10,10,225},{11,11,116},{11,10,118},{11,10,226},{11,10,251},{11,10,
+430},{11,10,701},{11,10,974},{11,10,982},{12,10,64},{12,10,260},{12,10,488},{140
+,10,690},{134,11,456},{133,11,925},{5,0,150},{7,0,106},{7,0,774},{8,0,603},{9,0,
+593},{9,0,634},{10,0,44},{10,0,173},{11,0,462},{11,0,515},{13,0,216},{13,0,288},
+{142,0,400},{137,10,347},{5,0,748},{134,0,553},{12,0,108},{141,0,291},{7,0,420},
+{4,10,12},{7,10,522},{7,10,809},{8,10,797},{141,10,88},{6,11,193},{7,11,240},{7,
+11,1682},{10,11,51},{10,11,640},{11,11,410},{13,11,82},{14,11,247},{14,11,331},{
+142,11,377},{133,10,528},{135,0,1777},{4,0,493},{144,0,55},{136,11,633},{139,0,
+81},{6,0,980},{136,0,321},{148,10,109},{5,10,266},{9,10,290},{9,10,364},{10,10,
+293},{11,10,606},{142,10,45},{6,0,568},{7,0,112},{7,0,1804},{8,0,362},{8,0,410},
+{8,0,830},{9,0,514},{11,0,649},{142,0,157},{4,0,74},{6,0,510},{6,10,594},{9,10,
+121},{10,10,49},{10,10,412},{139,10,834},{134,0,838},{136,10,748},{132,10,466},{
+132,0,625},{135,11,1443},{4,11,237},{135,11,514},{9,10,378},{141,10,162},{6,0,16
+},{6,0,158},{7,0,43},{7,0,129},{7,0,181},{8,0,276},{8,0,377},{10,0,523},{11,0,
+816},{12,0,455},{13,0,303},{142,0,135},{135,0,281},{4,0,1},{7,0,1143},{7,0,1463}
+,{8,0,61},{9,0,207},{9,0,390},{9,0,467},{139,0,836},{6,11,392},{7,11,65},{135,11
+,2019},{132,10,667},{4,0,723},{5,0,895},{7,0,1031},{8,0,199},{8,0,340},{9,0,153}
+,{9,0,215},{10,0,21},{10,0,59},{10,0,80},{10,0,224},{10,0,838},{11,0,229},{11,0,
+652},{12,0,192},{13,0,146},{142,0,91},{132,0,295},{137,0,51},{9,11,222},{10,11,
+43},{139,11,900},{5,0,309},{140,0,211},{5,0,125},{8,0,77},{138,0,15},{136,11,604
+},{138,0,789},{5,0,173},{4,10,39},{7,10,1843},{8,10,407},{11,10,144},{140,10,523
+},{138,11,265},{133,0,439},{132,10,510},{7,0,648},{7,0,874},{11,0,164},{12,0,76}
+,{18,0,9},{7,10,1980},{10,10,487},{138,10,809},{12,0,111},{14,0,294},{19,0,45},{
+13,10,260},{146,10,63},{133,11,549},{134,10,570},{4,0,8},{7,0,1152},{7,0,1153},{
+7,0,1715},{9,0,374},{10,0,478},{139,0,648},{135,0,1099},{5,0,575},{6,0,354},{135
+,0,701},{7,11,36},{8,11,201},{136,11,605},{4,10,787},{136,11,156},{6,0,518},{149
+,11,13},{140,11,224},{134,0,702},{132,10,516},{5,11,724},{10,11,305},{11,11,151}
+,{12,11,33},{12,11,121},{12,11,381},{17,11,3},{17,11,27},{17,11,78},{18,11,18},{
+19,11,54},{149,11,5},{8,0,87},{4,11,523},{5,11,638},{11,10,887},{14,10,365},{142
+,10,375},{138,0,438},{136,10,821},{135,11,1908},{6,11,242},{7,11,227},{7,11,1581
+},{8,11,104},{9,11,113},{9,11,220},{9,11,427},{10,11,74},{10,11,239},{11,11,579}
+,{11,11,1023},{13,11,4},{13,11,204},{13,11,316},{18,11,95},{148,11,86},{4,0,69},
+{5,0,122},{5,0,849},{6,0,1633},{9,0,656},{138,0,464},{7,0,1802},{4,10,10},{139,
+10,786},{135,11,861},{139,0,499},{7,0,476},{7,0,1592},{138,0,87},{133,10,684},{4
+,0,840},{134,10,27},{142,0,283},{6,0,1620},{7,11,1328},{136,11,494},{5,0,859},{7
+,0,1160},{8,0,107},{9,0,291},{9,0,439},{10,0,663},{11,0,609},{140,0,197},{7,11,
+1306},{8,11,505},{9,11,482},{10,11,126},{11,11,225},{12,11,347},{12,11,449},{13,
+11,19},{142,11,218},{5,11,268},{10,11,764},{12,11,120},{13,11,39},{145,11,127},{
+145,10,56},{7,11,1672},{10,11,472},{11,11,189},{143,11,51},{6,10,342},{6,10,496}
+,{8,10,275},{137,10,206},{133,0,600},{4,0,117},{6,0,372},{7,0,1905},{142,0,323},
+{4,10,909},{5,10,940},{135,11,1471},{132,10,891},{4,0,722},{139,0,471},{4,11,384
+},{135,11,1022},{132,10,687},{9,0,5},{12,0,216},{12,0,294},{12,0,298},{12,0,400}
+,{12,0,518},{13,0,229},{143,0,139},{135,11,1703},{7,11,1602},{10,11,698},{12,11,
+212},{141,11,307},{6,10,41},{141,10,160},{135,11,1077},{9,11,159},{11,11,28},{
+140,11,603},{4,0,514},{7,0,1304},{138,0,477},{134,0,1774},{9,0,88},{139,0,270},{
+5,0,12},{7,0,375},{9,0,438},{134,10,1718},{132,11,515},{136,10,778},{8,11,632},{
+8,11,697},{137,11,854},{6,0,362},{6,0,997},{146,0,51},{7,0,816},{7,0,1241},{9,0,
+283},{9,0,520},{10,0,213},{10,0,307},{10,0,463},{10,0,671},{10,0,746},{11,0,401}
+,{11,0,794},{12,0,517},{18,0,107},{147,0,115},{133,10,115},{150,11,28},{4,11,136
+},{133,11,551},{142,10,314},{132,0,258},{6,0,22},{7,0,903},{7,0,1963},{8,0,639},
+{138,0,577},{5,0,681},{8,0,782},{13,0,130},{17,0,84},{5,10,193},{140,10,178},{9,
+11,17},{138,11,291},{7,11,1287},{9,11,44},{10,11,552},{10,11,642},{11,11,839},{
+12,11,274},{12,11,275},{12,11,372},{13,11,91},{142,11,125},{135,10,174},{4,0,664
+},{5,0,804},{139,0,1013},{134,0,942},{6,0,1349},{6,0,1353},{6,0,1450},{7,11,1518
+},{139,11,694},{11,0,356},{4,10,122},{5,10,796},{5,10,952},{6,10,1660},{6,10,
+1671},{8,10,567},{9,10,687},{9,10,742},{10,10,686},{11,10,682},{140,10,281},{5,0
+,32},{6,11,147},{7,11,886},{9,11,753},{138,11,268},{5,10,179},{7,10,1095},{135,
+10,1213},{4,10,66},{7,10,722},{135,10,904},{135,10,352},{9,11,245},{138,11,137},
+{4,0,289},{7,0,629},{7,0,1698},{7,0,1711},{12,0,215},{133,11,414},{6,0,1975},{
+135,11,1762},{6,0,450},{136,0,109},{141,10,35},{134,11,599},{136,0,705},{133,0,
+664},{134,11,1749},{11,11,402},{12,11,109},{12,11,431},{13,11,179},{13,11,206},{
+14,11,175},{14,11,217},{16,11,3},{148,11,53},{135,0,1238},{134,11,1627},{132,11,
+488},{13,0,318},{10,10,592},{10,10,753},{12,10,317},{12,10,355},{12,10,465},{12,
+10,469},{12,10,560},{140,10,578},{133,10,564},{132,11,83},{140,11,676},{6,0,1872
+},{6,0,1906},{6,0,1907},{9,0,934},{9,0,956},{9,0,960},{9,0,996},{12,0,794},{12,0
+,876},{12,0,880},{12,0,918},{15,0,230},{18,0,234},{18,0,238},{21,0,38},{149,0,62
+},{134,10,556},{134,11,278},{137,0,103},{7,10,544},{8,10,719},{138,10,61},{4,10,
+5},{5,10,498},{8,10,637},{137,10,521},{7,0,777},{12,0,229},{12,0,239},{15,0,12},
+{12,11,229},{12,11,239},{143,11,12},{6,0,26},{7,11,388},{7,11,644},{139,11,781},
+{7,11,229},{8,11,59},{9,11,190},{9,11,257},{10,11,378},{140,11,191},{133,10,927}
+,{135,10,1441},{4,10,893},{5,10,780},{133,10,893},{4,0,414},{5,0,467},{9,0,654},
+{10,0,451},{12,0,59},{141,0,375},{142,0,173},{135,0,17},{7,0,1350},{133,10,238},
+{135,0,955},{4,0,960},{10,0,887},{12,0,753},{18,0,161},{18,0,162},{152,0,19},{
+136,11,344},{6,10,1729},{137,11,288},{132,11,660},{4,0,217},{5,0,710},{7,0,760},
+{7,0,1926},{9,0,428},{9,0,708},{10,0,254},{10,0,296},{10,0,720},{11,0,109},{11,0
+,255},{12,0,165},{12,0,315},{13,0,107},{13,0,203},{14,0,54},{14,0,99},{14,0,114}
+,{14,0,388},{16,0,85},{17,0,9},{17,0,33},{20,0,25},{20,0,28},{20,0,29},{21,0,9},
+{21,0,10},{21,0,34},{22,0,17},{4,10,60},{7,10,1800},{8,10,314},{9,10,700},{139,
+10,487},{7,11,1035},{138,11,737},{7,11,690},{9,11,217},{9,11,587},{140,11,521},{
+6,0,919},{7,11,706},{7,11,1058},{138,11,538},{7,10,1853},{138,10,437},{136,10,
+419},{6,0,280},{10,0,502},{11,0,344},{140,0,38},{5,0,45},{7,0,1161},{11,0,448},{
+11,0,880},{13,0,139},{13,0,407},{15,0,16},{17,0,95},{18,0,66},{18,0,88},{18,0,
+123},{149,0,7},{11,11,92},{11,11,196},{11,11,409},{11,11,450},{11,11,666},{11,11
+,777},{12,11,262},{13,11,385},{13,11,393},{15,11,115},{16,11,45},{145,11,82},{
+136,0,777},{134,11,1744},{4,0,410},{7,0,521},{133,10,828},{134,0,673},{7,0,1110}
+,{7,0,1778},{7,10,176},{135,10,178},{5,10,806},{7,11,268},{7,10,1976},{136,11,
+569},{4,11,733},{9,11,194},{10,11,92},{11,11,198},{12,11,84},{12,11,87},{13,11,
+128},{144,11,74},{5,0,341},{7,0,1129},{11,0,414},{4,10,51},{6,10,4},{7,10,591},{
+7,10,849},{7,10,951},{7,10,1613},{7,10,1760},{7,10,1988},{9,10,434},{10,10,754},
+{11,10,25},{139,10,37},{133,10,902},{135,10,928},{135,0,787},{132,0,436},{134,10
+,270},{7,0,1587},{135,0,1707},{6,0,377},{7,0,1025},{9,0,613},{145,0,104},{7,11,
+982},{7,11,1361},{10,11,32},{143,11,56},{139,0,96},{132,0,451},{132,10,416},{142
+,10,372},{5,10,152},{5,10,197},{7,11,306},{7,10,340},{7,10,867},{10,10,548},{10,
+10,581},{11,10,6},{12,10,3},{12,10,19},{14,10,110},{142,10,289},{134,0,680},{134
+,11,609},{7,0,483},{7,10,190},{8,10,28},{8,10,141},{8,10,444},{8,10,811},{9,10,
+468},{11,10,334},{12,10,24},{12,10,386},{140,10,576},{10,0,916},{133,10,757},{5,
+10,721},{135,10,1553},{133,11,178},{134,0,937},{132,10,898},{133,0,739},{147,0,
+82},{135,0,663},{146,0,128},{5,10,277},{141,10,247},{134,0,1087},{132,10,435},{6
+,11,381},{7,11,645},{7,11,694},{136,11,546},{7,0,503},{135,0,1885},{6,0,1965},{8
+,0,925},{138,0,955},{4,0,113},{5,0,163},{5,0,735},{7,0,1009},{9,0,9},{9,0,771},{
+12,0,90},{13,0,138},{13,0,410},{143,0,128},{4,0,324},{138,0,104},{7,0,460},{5,10
+,265},{134,10,212},{133,11,105},{7,11,261},{7,11,1107},{7,11,1115},{7,11,1354},{
+7,11,1588},{7,11,1705},{7,11,1902},{9,11,465},{10,11,248},{10,11,349},{10,11,647
+},{11,11,527},{11,11,660},{11,11,669},{12,11,529},{141,11,305},{5,11,438},{9,11,
+694},{12,11,627},{141,11,210},{152,11,11},{4,0,935},{133,0,823},{132,10,702},{5,
+0,269},{7,0,434},{7,0,891},{8,0,339},{9,0,702},{11,0,594},{11,0,718},{17,0,100},
+{5,10,808},{135,10,2045},{7,0,1014},{9,0,485},{141,0,264},{134,0,1713},{7,0,1810
+},{11,0,866},{12,0,103},{13,0,495},{140,11,233},{4,0,423},{10,0,949},{138,0,1013
+},{135,0,900},{8,11,25},{138,11,826},{5,10,166},{8,10,739},{140,10,511},{134,0,
+2018},{7,11,1270},{139,11,612},{4,10,119},{5,10,170},{5,10,447},{7,10,1708},{7,
+10,1889},{9,10,357},{9,10,719},{12,10,486},{140,10,596},{12,0,574},{140,11,574},
+{132,11,308},{6,0,964},{6,0,1206},{134,0,1302},{4,10,450},{135,10,1158},{135,11,
+150},{136,11,649},{14,0,213},{148,0,38},{9,11,45},{9,11,311},{141,11,42},{134,11
+,521},{7,10,1375},{7,10,1466},{138,10,331},{132,10,754},{5,11,339},{7,11,1442},{
+14,11,3},{15,11,41},{147,11,66},{136,11,378},{134,0,1022},{5,10,850},{136,10,799
+},{142,0,143},{135,0,2029},{134,11,1628},{8,0,523},{150,0,34},{5,0,625},{135,0,
+1617},{7,0,275},{7,10,238},{7,10,2033},{8,10,120},{8,10,188},{8,10,659},{9,10,
+598},{10,10,466},{12,10,342},{12,10,588},{13,10,503},{14,10,246},{143,10,92},{7,
+0,37},{8,0,425},{8,0,693},{9,0,720},{10,0,380},{10,0,638},{11,0,273},{11,0,473},
+{12,0,61},{143,0,43},{135,11,829},{135,0,1943},{132,0,765},{5,11,486},{135,11,
+1349},{7,11,1635},{8,11,17},{10,11,217},{138,11,295},{4,10,201},{7,10,1744},{8,
+10,602},{11,10,247},{11,10,826},{145,10,65},{138,11,558},{11,0,551},{142,0,159},
+{8,10,164},{146,10,62},{139,11,176},{132,0,168},{136,0,1010},{134,0,1994},{135,0
+,91},{138,0,532},{135,10,1243},{135,0,1884},{132,10,907},{5,10,100},{10,10,329},
+{12,10,416},{149,10,29},{134,11,447},{132,10,176},{5,10,636},{5,10,998},{7,10,9}
+,{7,10,1508},{8,10,26},{9,10,317},{9,10,358},{10,10,210},{10,10,292},{10,10,533}
+,{11,10,555},{12,10,526},{12,10,607},{13,10,263},{13,10,459},{142,10,271},{4,11,
+609},{135,11,756},{6,0,15},{7,0,70},{10,0,240},{147,0,93},{4,11,930},{133,11,947
+},{134,0,1227},{134,0,1534},{133,11,939},{133,11,962},{5,11,651},{8,11,170},{9,
+11,61},{9,11,63},{10,11,23},{10,11,37},{10,11,834},{11,11,4},{11,11,187},{11,11,
+281},{11,11,503},{11,11,677},{12,11,96},{12,11,130},{12,11,244},{14,11,5},{14,11
+,40},{14,11,162},{14,11,202},{146,11,133},{4,11,406},{5,11,579},{12,11,492},{150
+,11,15},{139,0,392},{6,10,610},{10,10,127},{141,10,27},{7,0,655},{7,0,1844},{136
+,10,119},{4,0,145},{6,0,176},{7,0,395},{137,0,562},{132,0,501},{140,11,145},{136
+,0,1019},{134,0,509},{139,0,267},{6,11,17},{7,11,16},{7,11,1001},{7,11,1982},{9,
+11,886},{10,11,489},{10,11,800},{11,11,782},{12,11,320},{13,11,467},{14,11,145},
+{14,11,387},{143,11,119},{145,11,17},{6,0,1099},{133,11,458},{7,11,1983},{8,11,0
+},{8,11,171},{9,11,120},{9,11,732},{10,11,473},{11,11,656},{11,11,998},{18,11,0}
+,{18,11,2},{147,11,21},{12,11,427},{146,11,38},{10,0,948},{138,0,968},{7,10,126}
+,{136,10,84},{136,10,790},{4,0,114},{9,0,492},{13,0,462},{142,0,215},{6,10,64},{
+12,10,377},{141,10,309},{4,0,77},{5,0,361},{6,0,139},{6,0,401},{6,0,404},{7,0,
+413},{7,0,715},{7,0,1716},{11,0,279},{12,0,179},{12,0,258},{13,0,244},{142,0,358
+},{134,0,1717},{7,0,772},{7,0,1061},{7,0,1647},{8,0,82},{11,0,250},{11,0,607},{
+12,0,311},{12,0,420},{13,0,184},{13,0,367},{7,10,1104},{11,10,269},{11,10,539},{
+11,10,627},{11,10,706},{11,10,975},{12,10,248},{12,10,434},{12,10,600},{12,10,
+622},{13,10,297},{13,10,485},{14,10,69},{14,10,409},{143,10,108},{135,0,724},{4,
+11,512},{4,11,519},{133,11,342},{134,0,1133},{145,11,29},{11,10,977},{141,10,507
+},{6,0,841},{6,0,1042},{6,0,1194},{10,0,993},{140,0,1021},{6,11,31},{7,11,491},{
+7,11,530},{8,11,592},{9,10,34},{11,11,53},{11,10,484},{11,11,779},{12,11,167},{
+12,11,411},{14,11,14},{14,11,136},{15,11,72},{16,11,17},{144,11,72},{4,0,1021},{
+6,0,2037},{133,11,907},{7,0,373},{8,0,335},{8,0,596},{9,0,488},{6,10,1700},{7,10
+,293},{7,10,382},{7,10,1026},{7,10,1087},{7,10,2027},{8,10,252},{8,10,727},{8,10
+,729},{9,10,30},{9,10,199},{9,10,231},{9,10,251},{9,10,334},{9,10,361},{9,10,712
+},{10,10,55},{10,10,60},{10,10,232},{10,10,332},{10,10,384},{10,10,396},{10,10,
+504},{10,10,542},{10,10,652},{11,10,20},{11,10,48},{11,10,207},{11,10,291},{11,
+10,298},{11,10,342},{11,10,365},{11,10,394},{11,10,620},{11,10,705},{11,10,1017}
+,{12,10,123},{12,10,340},{12,10,406},{12,10,643},{13,10,61},{13,10,269},{13,10,
+311},{13,10,319},{13,10,486},{14,10,234},{15,10,62},{15,10,85},{16,10,71},{18,10
+,119},{148,10,105},{150,0,37},{4,11,208},{5,11,106},{6,11,531},{8,11,408},{9,11,
+188},{138,11,572},{132,0,564},{6,0,513},{135,0,1052},{132,0,825},{9,0,899},{140,
+11,441},{134,0,778},{133,11,379},{7,0,1417},{12,0,382},{17,0,48},{152,0,12},{132
+,11,241},{7,0,1116},{6,10,379},{7,10,270},{8,10,176},{8,10,183},{9,10,432},{9,10
+,661},{12,10,247},{12,10,617},{146,10,125},{5,10,792},{133,10,900},{6,0,545},{7,
+0,565},{7,0,1669},{10,0,114},{11,0,642},{140,0,618},{133,0,5},{138,11,7},{132,11
+,259},{135,0,192},{134,0,701},{136,0,763},{135,10,1979},{4,10,901},{133,10,776},
+{10,0,755},{147,0,29},{133,0,759},{4,11,173},{5,11,312},{5,11,512},{135,11,1285}
+,{7,11,1603},{7,11,1691},{9,11,464},{11,11,195},{12,11,279},{12,11,448},{14,11,
+11},{147,11,102},{7,0,370},{7,0,1007},{7,0,1177},{135,0,1565},{135,0,1237},{4,0,
+87},{5,0,250},{141,0,298},{4,11,452},{5,11,583},{5,11,817},{6,11,433},{7,11,593}
+,{7,11,720},{7,11,1378},{8,11,161},{9,11,284},{10,11,313},{139,11,886},{4,11,547
+},{135,11,1409},{136,11,722},{4,10,37},{5,10,334},{135,10,1253},{132,10,508},{12
+,0,107},{146,0,31},{8,11,420},{139,11,193},{135,0,814},{135,11,409},{140,0,991},
+{4,0,57},{7,0,1195},{7,0,1438},{7,0,1548},{7,0,1835},{7,0,1904},{9,0,757},{10,0,
+604},{139,0,519},{132,0,540},{138,11,308},{132,10,533},{136,0,608},{144,11,65},{
+4,0,1014},{134,0,2029},{4,0,209},{7,0,902},{5,11,1002},{136,11,745},{134,0,2030}
+,{6,0,303},{7,0,335},{7,0,1437},{7,0,1668},{8,0,553},{8,0,652},{8,0,656},{9,0,
+558},{11,0,743},{149,0,18},{5,11,575},{6,11,354},{135,11,701},{4,11,239},{6,11,
+477},{7,11,1607},{11,11,68},{139,11,617},{132,0,559},{8,0,527},{18,0,60},{147,0,
+24},{133,10,920},{138,0,511},{133,0,1017},{133,0,675},{138,10,391},{11,0,156},{
+135,10,1952},{138,11,369},{132,11,367},{133,0,709},{6,0,698},{134,0,887},{142,10
+,126},{134,0,1745},{132,10,483},{13,11,299},{142,11,75},{133,0,714},{7,0,8},{136
+,0,206},{138,10,480},{4,11,694},{9,10,495},{146,10,104},{7,11,1248},{11,11,621},
+{139,11,702},{140,11,687},{132,0,776},{139,10,1009},{135,0,1272},{134,0,1059},{8
+,10,653},{13,10,93},{147,10,14},{135,11,213},{136,0,406},{133,10,172},{132,0,947
+},{8,0,175},{10,0,168},{138,0,573},{132,0,870},{6,0,1567},{151,11,28},{134,11,
+472},{5,10,260},{136,11,132},{4,11,751},{11,11,390},{140,11,32},{4,11,409},{133,
+11,78},{12,0,554},{6,11,473},{145,11,105},{133,0,784},{8,0,908},{136,11,306},{
+139,0,882},{6,0,358},{7,0,1393},{8,0,396},{10,0,263},{14,0,154},{16,0,48},{17,0,
+8},{7,11,1759},{8,11,396},{10,11,263},{14,11,154},{16,11,48},{145,11,8},{13,11,
+163},{13,11,180},{18,11,78},{148,11,35},{14,0,32},{18,0,85},{20,0,2},{152,0,16},
+{7,0,228},{10,0,770},{8,10,167},{8,10,375},{9,10,82},{9,10,561},{138,10,620},{
+132,0,845},{9,0,14},{9,0,441},{10,0,306},{139,0,9},{11,0,966},{12,0,287},{13,0,
+342},{13,0,402},{15,0,110},{15,0,163},{8,10,194},{136,10,756},{134,0,1578},{4,0,
+967},{6,0,1820},{6,0,1847},{140,0,716},{136,0,594},{7,0,1428},{7,0,1640},{7,0,
+1867},{9,0,169},{9,0,182},{9,0,367},{9,0,478},{9,0,506},{9,0,551},{9,0,557},{9,0
+,648},{9,0,697},{9,0,705},{9,0,725},{9,0,787},{9,0,794},{10,0,198},{10,0,214},{
+10,0,267},{10,0,275},{10,0,456},{10,0,551},{10,0,561},{10,0,613},{10,0,627},{10,
+0,668},{10,0,675},{10,0,691},{10,0,695},{10,0,707},{10,0,715},{11,0,183},{11,0,
+201},{11,0,244},{11,0,262},{11,0,352},{11,0,439},{11,0,493},{11,0,572},{11,0,591
+},{11,0,608},{11,0,611},{11,0,646},{11,0,674},{11,0,711},{11,0,751},{11,0,761},{
+11,0,776},{11,0,785},{11,0,850},{11,0,853},{11,0,862},{11,0,865},{11,0,868},{11,
+0,875},{11,0,898},{11,0,902},{11,0,903},{11,0,910},{11,0,932},{11,0,942},{11,0,
+957},{11,0,967},{11,0,972},{12,0,148},{12,0,195},{12,0,220},{12,0,237},{12,0,318
+},{12,0,339},{12,0,393},{12,0,445},{12,0,450},{12,0,474},{12,0,505},{12,0,509},{
+12,0,533},{12,0,591},{12,0,594},{12,0,597},{12,0,621},{12,0,633},{12,0,642},{13,
+0,59},{13,0,60},{13,0,145},{13,0,239},{13,0,250},{13,0,329},{13,0,344},{13,0,365
+},{13,0,372},{13,0,387},{13,0,403},{13,0,414},{13,0,456},{13,0,470},{13,0,478},{
+13,0,483},{13,0,489},{14,0,55},{14,0,57},{14,0,81},{14,0,90},{14,0,148},{14,0,
+239},{14,0,266},{14,0,321},{14,0,326},{14,0,327},{14,0,330},{14,0,347},{14,0,355
+},{14,0,401},{14,0,404},{14,0,411},{14,0,414},{14,0,416},{14,0,420},{15,0,61},{
+15,0,74},{15,0,87},{15,0,88},{15,0,94},{15,0,96},{15,0,116},{15,0,149},{15,0,154
+},{16,0,50},{16,0,63},{16,0,73},{17,0,2},{17,0,66},{17,0,92},{17,0,103},{17,0,
+112},{17,0,120},{18,0,50},{18,0,54},{18,0,82},{18,0,86},{18,0,90},{18,0,111},{18
+,0,115},{18,0,156},{19,0,40},{19,0,79},{20,0,78},{21,0,22},{135,11,883},{5,0,161
+},{135,0,839},{4,0,782},{13,11,293},{142,11,56},{133,11,617},{139,11,50},{135,10
+,22},{145,0,64},{5,10,639},{7,10,1249},{139,10,896},{138,0,998},{135,11,2042},{4
+,11,546},{142,11,233},{6,0,1043},{134,0,1574},{134,0,1496},{4,10,102},{7,10,815}
+,{7,10,1699},{139,10,964},{12,0,781},{142,0,461},{4,11,313},{133,11,577},{6,0,
+639},{6,0,1114},{137,0,817},{8,11,184},{141,11,433},{7,0,1814},{135,11,935},{10,
+0,997},{140,0,958},{4,0,812},{137,11,625},{132,10,899},{136,10,795},{5,11,886},{
+6,11,46},{6,11,1790},{7,11,14},{7,11,732},{7,11,1654},{8,11,95},{8,11,327},{8,11
+,616},{10,11,598},{10,11,769},{11,11,134},{11,11,747},{12,11,378},{142,11,97},{
+136,0,139},{6,10,52},{9,10,104},{9,10,559},{12,10,308},{147,10,87},{133,11,1021}
+,{132,10,604},{132,10,301},{136,10,779},{7,0,643},{136,0,236},{132,11,153},{134,
+0,1172},{147,10,32},{133,11,798},{6,0,1338},{132,11,587},{6,11,598},{7,11,42},{8
+,11,695},{10,11,212},{11,11,158},{14,11,196},{145,11,85},{135,10,508},{5,11,957}
+,{5,11,1008},{135,11,249},{4,11,129},{135,11,465},{5,0,54},{7,11,470},{7,11,1057
+},{7,11,1201},{9,11,755},{11,11,906},{140,11,527},{7,11,908},{146,11,7},{5,11,
+148},{136,11,450},{144,11,1},{4,0,256},{135,0,1488},{9,0,351},{6,10,310},{7,10,
+1849},{8,10,72},{8,10,272},{8,10,431},{9,10,12},{10,10,563},{10,10,630},{10,10,
+796},{10,10,810},{11,10,367},{11,10,599},{11,10,686},{140,10,672},{6,0,1885},{6,
+0,1898},{6,0,1899},{140,0,955},{4,0,714},{133,0,469},{6,0,1270},{134,0,1456},{
+132,0,744},{6,0,313},{7,10,537},{8,10,64},{9,10,127},{10,10,496},{12,10,510},{
+141,10,384},{4,11,217},{4,10,244},{5,11,710},{7,10,233},{7,11,1926},{9,11,428},{
+9,11,708},{10,11,254},{10,11,296},{10,11,720},{11,11,109},{11,11,255},{12,11,165
+},{12,11,315},{13,11,107},{13,11,203},{14,11,54},{14,11,99},{14,11,114},{14,11,
+388},{16,11,85},{17,11,9},{17,11,33},{20,11,25},{20,11,28},{20,11,29},{21,11,9},
+{21,11,10},{21,11,34},{150,11,17},{138,0,402},{7,0,969},{146,0,55},{8,0,50},{137
+,0,624},{134,0,1355},{132,0,572},{134,10,1650},{10,10,702},{139,10,245},{10,0,
+847},{142,0,445},{6,0,43},{7,0,38},{8,0,248},{138,0,513},{133,0,369},{137,10,338
+},{133,0,766},{133,0,363},{133,10,896},{8,11,392},{11,11,54},{13,11,173},{13,11,
+294},{148,11,7},{134,0,678},{7,11,1230},{136,11,531},{6,0,258},{140,0,409},{5,0,
+249},{148,0,82},{7,10,1117},{136,10,539},{5,0,393},{6,0,378},{7,0,1981},{9,0,32}
+,{9,0,591},{10,0,685},{10,0,741},{142,0,382},{133,0,788},{134,0,1281},{134,0,
+1295},{7,0,1968},{141,0,509},{4,0,61},{5,0,58},{5,0,171},{5,0,683},{6,0,291},{6,
+0,566},{7,0,1650},{11,0,523},{12,0,273},{12,0,303},{15,0,39},{143,0,111},{6,0,
+706},{134,0,1283},{134,0,589},{135,11,1433},{133,11,435},{7,0,1059},{13,0,54},{5
+,10,4},{5,10,810},{6,10,13},{6,10,538},{6,10,1690},{6,10,1726},{7,10,1819},{8,10
+,148},{8,10,696},{8,10,791},{12,10,125},{143,10,9},{135,10,1268},{5,11,85},{6,11
+,419},{7,11,134},{7,11,305},{7,11,361},{7,11,1337},{8,11,71},{140,11,519},{137,0
+,824},{140,11,688},{5,11,691},{7,11,345},{7,10,1385},{9,11,94},{11,10,582},{11,
+10,650},{11,10,901},{11,10,949},{12,11,169},{12,10,232},{12,10,236},{13,10,413},
+{13,10,501},{146,10,116},{4,0,917},{133,0,1005},{7,0,1598},{5,11,183},{6,11,582}
+,{9,11,344},{10,11,679},{140,11,435},{4,10,925},{5,10,803},{8,10,698},{138,10,
+828},{132,0,919},{135,11,511},{139,10,992},{4,0,255},{5,0,302},{6,0,132},{7,0,
+128},{7,0,283},{7,0,1299},{10,0,52},{10,0,514},{11,0,925},{13,0,92},{142,0,309},
+{134,0,1369},{135,10,1847},{134,0,328},{7,11,1993},{136,11,684},{133,10,383},{
+137,0,173},{134,11,583},{134,0,1411},{19,0,65},{5,11,704},{8,11,357},{10,11,745}
+,{14,11,426},{17,11,94},{147,11,57},{9,10,660},{138,10,347},{4,11,179},{5,11,198
+},{133,11,697},{7,11,347},{7,11,971},{8,11,181},{138,11,711},{141,0,442},{11,0,
+842},{11,0,924},{13,0,317},{13,0,370},{13,0,469},{13,0,471},{14,0,397},{18,0,69}
+,{18,0,145},{7,10,572},{9,10,592},{11,10,680},{12,10,356},{140,10,550},{14,11,19
+},{14,11,28},{144,11,29},{136,0,534},{4,11,243},{5,11,203},{7,11,19},{7,11,71},{
+7,11,113},{10,11,405},{11,11,357},{142,11,240},{6,0,210},{10,0,845},{138,0,862},
+{7,11,1351},{9,11,581},{10,11,639},{11,11,453},{140,11,584},{7,11,1450},{139,11,
+99},{10,0,892},{12,0,719},{144,0,105},{4,0,284},{6,0,223},{134,11,492},{5,11,134
+},{6,11,408},{6,11,495},{135,11,1593},{136,0,529},{137,0,807},{4,0,218},{7,0,526
+},{143,0,137},{6,0,1444},{142,11,4},{132,11,665},{4,0,270},{5,0,192},{6,0,332},{
+7,0,1322},{4,11,248},{7,11,137},{137,11,349},{140,0,661},{7,0,1517},{11,0,597},{
+14,0,76},{14,0,335},{20,0,33},{7,10,748},{139,10,700},{5,11,371},{135,11,563},{
+146,11,57},{133,10,127},{133,0,418},{4,11,374},{7,11,547},{7,11,1700},{7,11,1833
+},{139,11,858},{6,10,198},{140,10,83},{7,11,1812},{13,11,259},{13,11,356},{14,11
+,242},{147,11,114},{7,0,379},{8,0,481},{9,0,377},{5,10,276},{6,10,55},{135,10,
+1369},{138,11,286},{5,0,1003},{6,0,149},{6,10,1752},{136,10,726},{8,0,262},{9,0,
+627},{10,0,18},{11,0,214},{11,0,404},{11,0,457},{11,0,780},{11,0,913},{13,0,401}
+,{14,0,200},{6,11,1647},{7,11,1552},{7,11,2010},{9,11,494},{137,11,509},{135,0,
+742},{136,0,304},{132,0,142},{133,10,764},{6,10,309},{7,10,331},{138,10,550},{
+135,10,1062},{6,11,123},{7,11,214},{7,10,986},{9,11,728},{10,11,157},{11,11,346}
+,{11,11,662},{143,11,106},{135,10,1573},{7,0,925},{137,0,799},{4,0,471},{5,0,51}
+,{6,0,602},{8,0,484},{138,0,195},{136,0,688},{132,0,697},{6,0,1169},{6,0,1241},{
+6,10,194},{7,10,133},{10,10,493},{10,10,570},{139,10,664},{140,0,751},{7,0,929},
+{10,0,452},{11,0,878},{16,0,33},{5,10,24},{5,10,569},{6,10,3},{6,10,119},{6,10,
+143},{6,10,440},{7,10,599},{7,10,1686},{7,10,1854},{8,10,424},{9,10,43},{9,10,
+584},{9,10,760},{10,10,328},{11,10,159},{11,10,253},{12,10,487},{140,10,531},{4,
+11,707},{13,11,106},{18,11,49},{147,11,41},{5,0,221},{5,11,588},{134,11,393},{
+134,0,1437},{6,11,211},{7,11,1690},{11,11,486},{140,11,369},{5,10,14},{5,10,892}
+,{6,10,283},{7,10,234},{136,10,537},{4,0,988},{136,0,955},{135,0,1251},{4,10,126
+},{8,10,635},{147,10,34},{4,10,316},{135,10,1561},{137,10,861},{4,10,64},{5,10,
+352},{5,10,720},{6,10,368},{139,10,359},{134,0,192},{4,0,132},{5,0,69},{135,0,
+1242},{7,10,1577},{10,10,304},{10,10,549},{12,10,365},{13,10,220},{13,10,240},{
+142,10,33},{4,0,111},{7,0,865},{134,11,219},{5,11,582},{6,11,1646},{7,11,99},{7,
+11,1962},{7,11,1986},{8,11,515},{8,11,773},{9,11,23},{9,11,491},{12,11,620},{14,
+11,52},{145,11,50},{132,0,767},{7,11,568},{148,11,21},{6,0,42},{7,0,1416},{7,0,
+2005},{8,0,131},{8,0,466},{9,0,672},{13,0,252},{20,0,103},{133,11,851},{135,0,
+1050},{6,10,175},{137,10,289},{5,10,432},{133,10,913},{6,0,44},{136,0,368},{135,
+11,784},{132,0,570},{133,0,120},{139,10,595},{140,0,29},{6,0,227},{135,0,1589},{
+4,11,98},{7,11,1365},{9,11,422},{9,11,670},{10,11,775},{11,11,210},{13,11,26},{
+13,11,457},{141,11,476},{140,10,80},{5,10,931},{134,10,1698},{133,0,522},{134,0,
+1120},{135,0,1529},{12,0,739},{14,0,448},{142,0,467},{11,10,526},{11,10,939},{
+141,10,290},{5,10,774},{6,10,1637},{6,10,1686},{134,10,1751},{6,0,1667},{135,0,
+2036},{7,10,1167},{11,10,934},{13,10,391},{145,10,76},{137,11,147},{6,10,260},{7
+,10,1484},{11,11,821},{12,11,110},{12,11,153},{18,11,41},{150,11,19},{6,0,511},{
+12,0,132},{134,10,573},{5,0,568},{6,0,138},{135,0,1293},{132,0,1020},{8,0,258},{
+9,0,208},{137,0,359},{4,0,565},{8,0,23},{136,0,827},{134,0,344},{4,0,922},{5,0,
+1023},{13,11,477},{14,11,120},{148,11,61},{134,0,240},{5,11,209},{6,11,30},{11,
+11,56},{139,11,305},{6,0,171},{7,0,1002},{7,0,1324},{9,0,415},{14,0,230},{18,0,
+68},{4,10,292},{4,10,736},{5,10,871},{6,10,1689},{7,10,1944},{137,10,580},{9,11,
+635},{139,11,559},{4,11,150},{5,11,303},{134,11,327},{6,10,63},{135,10,920},{133
+,10,793},{8,11,192},{10,11,78},{10,11,555},{11,11,308},{13,11,359},{147,11,95},{
+135,11,786},{135,11,1712},{136,0,402},{6,0,754},{6,11,1638},{7,11,79},{7,11,496}
+,{9,11,138},{10,11,336},{11,11,12},{12,11,412},{12,11,440},{142,11,305},{4,0,716
+},{141,0,31},{133,0,982},{8,0,691},{8,0,731},{5,10,67},{6,10,62},{6,10,374},{135
+,10,1391},{9,10,790},{140,10,47},{139,11,556},{151,11,1},{7,11,204},{7,11,415},{
+8,11,42},{10,11,85},{11,11,33},{11,11,564},{12,11,571},{149,11,1},{8,0,888},{7,
+11,610},{135,11,1501},{4,10,391},{135,10,1169},{5,0,847},{9,0,840},{138,0,803},{
+137,0,823},{134,0,785},{8,0,152},{9,0,53},{9,0,268},{9,0,901},{10,0,518},{10,0,
+829},{11,0,188},{13,0,74},{14,0,46},{15,0,17},{15,0,33},{17,0,40},{18,0,36},{19,
+0,20},{22,0,1},{152,0,2},{4,11,3},{5,11,247},{5,11,644},{7,11,744},{7,11,1207},{
+7,11,1225},{7,11,1909},{146,11,147},{136,0,532},{135,0,681},{132,10,271},{140,0,
+314},{140,0,677},{4,0,684},{136,0,384},{5,11,285},{9,11,67},{13,11,473},{143,11,
+82},{4,10,253},{5,10,544},{7,10,300},{137,10,340},{7,0,110},{7,0,447},{8,0,290},
+{8,0,591},{9,0,382},{9,0,649},{11,0,71},{11,0,155},{11,0,313},{12,0,5},{13,0,325
+},{142,0,287},{134,0,1818},{136,0,1007},{138,0,321},{7,0,360},{7,0,425},{9,0,66}
+,{9,0,278},{138,0,644},{133,10,818},{5,0,385},{5,10,541},{6,10,94},{6,10,499},{7
+,10,230},{139,10,321},{4,10,920},{5,10,25},{5,10,790},{6,10,457},{7,10,853},{136
+,10,788},{4,0,900},{133,0,861},{5,0,254},{7,0,985},{136,0,73},{7,0,1959},{136,0,
+683},{134,10,1765},{133,10,822},{132,10,634},{4,11,29},{6,11,532},{7,11,1628},{7
+,11,1648},{9,11,303},{9,11,350},{10,11,433},{11,11,97},{11,11,557},{11,11,745},{
+12,11,289},{12,11,335},{12,11,348},{12,11,606},{13,11,116},{13,11,233},{13,11,
+466},{14,11,181},{14,11,209},{14,11,232},{14,11,236},{14,11,300},{16,11,41},{148
+,11,97},{19,0,86},{6,10,36},{7,10,658},{136,10,454},{135,11,1692},{132,0,725},{5
+,11,501},{7,11,1704},{9,11,553},{11,11,520},{12,11,557},{141,11,249},{134,0,196}
+,{133,0,831},{136,0,723},{7,0,1897},{13,0,80},{13,0,437},{145,0,74},{4,0,992},{6
+,0,627},{136,0,994},{135,11,1294},{132,10,104},{5,0,848},{6,0,66},{136,0,764},{4
+,0,36},{7,0,1387},{10,0,205},{139,0,755},{6,0,1046},{134,0,1485},{134,0,950},{
+132,0,887},{14,0,450},{148,0,111},{7,0,620},{7,0,831},{9,10,542},{9,10,566},{138
+,10,728},{6,0,165},{138,0,388},{139,10,263},{4,0,719},{135,0,155},{138,10,468},{
+6,11,453},{144,11,36},{134,11,129},{5,0,533},{7,0,755},{138,0,780},{134,0,1465},
+{4,0,353},{6,0,146},{6,0,1789},{7,0,427},{7,0,990},{7,0,1348},{9,0,665},{9,0,898
+},{11,0,893},{142,0,212},{7,10,87},{142,10,288},{4,0,45},{135,0,1257},{12,0,7},{
+7,10,988},{7,10,1939},{9,10,64},{9,10,502},{12,10,34},{13,10,12},{13,10,234},{
+147,10,77},{4,0,607},{5,11,60},{6,11,504},{7,11,614},{7,11,1155},{140,11,0},{135
+,10,141},{8,11,198},{11,11,29},{140,11,534},{140,0,65},{136,0,816},{132,10,619},
+{139,0,88},{5,10,246},{8,10,189},{9,10,355},{9,10,512},{10,10,124},{10,10,453},{
+11,10,143},{11,10,416},{11,10,859},{141,10,341},{4,11,379},{135,11,1397},{4,0,
+600},{137,0,621},{133,0,367},{134,0,561},{6,0,559},{134,0,1691},{6,0,585},{134,
+11,585},{135,11,1228},{4,11,118},{5,10,678},{6,11,274},{6,11,361},{7,11,75},{141
+,11,441},{135,11,1818},{137,11,841},{5,0,573},{6,0,287},{7,10,862},{7,10,1886},{
+138,10,179},{132,10,517},{140,11,693},{5,11,314},{6,11,221},{7,11,419},{10,11,
+650},{11,11,396},{12,11,156},{13,11,369},{14,11,333},{145,11,47},{140,10,540},{
+136,10,667},{11,10,403},{146,10,83},{6,0,672},{133,10,761},{9,0,157},{10,10,131}
+,{140,10,72},{7,0,714},{134,11,460},{134,0,456},{133,0,925},{5,11,682},{135,11,
+1887},{136,11,510},{136,11,475},{133,11,1016},{9,0,19},{7,11,602},{8,11,179},{10
+,11,781},{140,11,126},{6,11,329},{138,11,111},{6,0,822},{134,0,1473},{144,11,86}
+,{11,0,113},{139,11,113},{5,11,821},{134,11,1687},{133,10,449},{7,0,463},{17,0,
+69},{136,10,103},{7,10,2028},{138,10,641},{6,0,193},{7,0,240},{7,0,1682},{10,0,
+51},{10,0,640},{11,0,410},{13,0,82},{14,0,247},{14,0,331},{142,0,377},{6,0,471},
+{11,0,411},{142,0,2},{5,11,71},{7,11,1407},{9,11,388},{9,11,704},{10,11,261},{10
+,11,619},{11,11,547},{11,11,619},{143,11,157},{136,0,633},{135,0,1148},{6,0,554}
+,{7,0,1392},{12,0,129},{7,10,1274},{7,10,1386},{7,11,2008},{9,11,337},{10,11,517
+},{146,10,87},{7,0,803},{8,0,542},{6,10,187},{7,10,1203},{8,10,380},{14,10,117},
+{149,10,28},{6,10,297},{7,10,793},{139,10,938},{8,0,438},{11,0,363},{7,10,464},{
+11,10,105},{12,10,231},{14,10,386},{15,10,102},{148,10,75},{5,11,16},{6,11,86},{
+6,11,603},{7,11,292},{7,11,561},{8,11,257},{8,11,382},{9,11,721},{9,11,778},{11,
+11,581},{140,11,466},{6,0,717},{4,11,486},{133,11,491},{132,0,875},{132,11,72},{
+6,11,265},{135,11,847},{4,0,237},{135,0,514},{6,0,392},{7,0,65},{135,0,2019},{
+140,11,261},{135,11,922},{137,11,404},{12,0,563},{14,0,101},{18,0,129},{7,10,
+1010},{11,10,733},{11,10,759},{13,10,34},{146,10,45},{7,10,1656},{9,10,369},{10,
+10,338},{10,10,490},{11,10,154},{11,10,545},{11,10,775},{13,10,77},{141,10,274},
+{4,0,444},{10,0,146},{140,0,9},{139,11,163},{7,0,1260},{135,0,1790},{9,0,222},{
+10,0,43},{139,0,900},{137,11,234},{138,0,971},{137,0,761},{134,0,699},{136,11,
+434},{6,0,1116},{7,0,1366},{5,10,20},{6,11,197},{6,10,298},{7,10,659},{8,11,205}
+,{137,10,219},{132,11,490},{11,11,820},{150,11,51},{7,10,1440},{11,10,854},{11,
+10,872},{11,10,921},{12,10,551},{13,10,472},{142,10,367},{140,11,13},{132,0,829}
+,{12,0,242},{132,10,439},{136,10,669},{6,0,593},{6,11,452},{7,11,312},{138,11,
+219},{4,11,333},{9,11,176},{12,11,353},{141,11,187},{7,0,36},{8,0,201},{136,0,
+605},{140,0,224},{132,10,233},{134,0,1430},{134,0,1806},{4,0,523},{133,0,638},{6
+,0,1889},{9,0,958},{9,0,971},{9,0,976},{12,0,796},{12,0,799},{12,0,808},{12,0,
+835},{12,0,836},{12,0,914},{12,0,946},{15,0,216},{15,0,232},{18,0,183},{18,0,187
+},{18,0,194},{18,0,212},{18,0,232},{149,0,49},{132,10,482},{6,0,827},{134,0,1434
+},{135,10,346},{134,0,2043},{6,0,242},{7,0,227},{7,0,1581},{8,0,104},{9,0,113},{
+9,0,220},{9,0,427},{10,0,136},{10,0,239},{11,0,579},{11,0,1023},{13,0,4},{13,0,
+204},{13,0,316},{148,0,86},{134,11,1685},{7,0,148},{8,0,284},{141,0,63},{142,0,
+10},{135,11,584},{134,0,1249},{7,0,861},{135,10,334},{5,10,795},{6,10,1741},{137
+,11,70},{132,0,807},{7,11,135},{8,11,7},{8,11,62},{9,11,243},{10,11,658},{10,11,
+697},{11,11,456},{139,11,756},{9,11,395},{138,11,79},{137,11,108},{147,0,94},{
+136,0,494},{135,11,631},{135,10,622},{7,0,1510},{135,10,1750},{4,10,203},{135,10
+,1936},{7,11,406},{7,11,459},{8,11,606},{139,11,726},{7,0,1306},{8,0,505},{9,0,
+482},{10,0,126},{11,0,225},{12,0,347},{12,0,449},{13,0,19},{14,0,218},{142,0,435
+},{5,0,268},{10,0,764},{12,0,120},{13,0,39},{145,0,127},{142,11,68},{11,10,678},
+{140,10,307},{12,11,268},{12,11,640},{142,11,119},{135,10,2044},{133,11,612},{4,
+11,372},{7,11,482},{8,11,158},{9,11,602},{9,11,615},{10,11,245},{10,11,678},{10,
+11,744},{11,11,248},{139,11,806},{7,10,311},{9,10,308},{140,10,255},{4,0,384},{
+135,0,1022},{5,11,854},{135,11,1991},{135,10,1266},{4,10,400},{5,10,267},{135,10
+,232},{135,0,1703},{9,0,159},{11,0,661},{140,0,603},{4,0,964},{14,0,438},{14,0,
+444},{14,0,456},{22,0,60},{22,0,63},{9,11,106},{9,11,163},{9,11,296},{10,11,167}
+,{10,11,172},{10,11,777},{139,11,16},{136,0,583},{132,0,515},{8,0,632},{8,0,697}
+,{137,0,854},{5,11,195},{135,11,1685},{6,0,1123},{134,0,1365},{134,11,328},{7,11
+,1997},{8,11,730},{139,11,1006},{4,0,136},{133,0,551},{134,0,1782},{7,0,1287},{9
+,0,44},{10,0,552},{10,0,642},{11,0,839},{12,0,274},{12,0,275},{12,0,372},{13,0,
+91},{142,0,125},{5,11,751},{11,11,797},{140,11,203},{133,0,732},{7,0,679},{8,0,
+313},{4,10,100},{135,11,821},{10,0,361},{142,0,316},{134,0,595},{6,0,147},{7,0,
+886},{9,0,753},{138,0,268},{5,10,362},{5,10,443},{6,10,318},{7,10,1019},{139,10,
+623},{5,10,463},{136,10,296},{4,10,454},{5,11,950},{5,11,994},{134,11,351},{138,
+0,137},{5,10,48},{5,10,404},{6,10,557},{7,10,458},{8,10,597},{10,10,455},{10,10,
+606},{11,10,49},{11,10,548},{12,10,476},{13,10,18},{141,10,450},{133,0,414},{135
+,0,1762},{5,11,421},{135,11,47},{5,10,442},{135,10,1984},{134,0,599},{134,0,1749
+},{134,0,1627},{4,0,488},{132,11,350},{137,11,751},{132,0,83},{140,0,676},{133,
+11,967},{7,0,1639},{5,10,55},{140,10,161},{4,11,473},{7,11,623},{8,11,808},{9,11
+,871},{9,11,893},{11,11,38},{11,11,431},{12,11,112},{12,11,217},{12,11,243},{12,
+11,562},{12,11,683},{13,11,141},{13,11,197},{13,11,227},{13,11,406},{13,11,487},
+{14,11,156},{14,11,203},{14,11,224},{14,11,256},{18,11,58},{150,11,0},{133,10,
+450},{7,11,736},{139,11,264},{134,0,278},{4,11,222},{7,11,286},{136,11,629},{135
+,10,869},{140,0,97},{144,0,14},{134,0,1085},{4,10,213},{7,10,223},{136,10,80},{7
+,0,388},{7,0,644},{139,0,781},{132,0,849},{7,0,229},{8,0,59},{9,0,190},{10,0,378
+},{140,0,191},{7,10,381},{7,10,806},{7,10,820},{8,10,354},{8,10,437},{8,10,787},
+{9,10,657},{10,10,58},{10,10,339},{10,10,749},{11,10,914},{12,10,162},{13,10,75}
+,{14,10,106},{14,10,198},{14,10,320},{14,10,413},{146,10,43},{141,11,306},{136,
+10,747},{134,0,1115},{16,0,94},{16,0,108},{136,11,146},{6,0,700},{6,0,817},{134,
+0,1002},{133,10,692},{4,11,465},{135,11,1663},{134,10,191},{6,0,1414},{135,11,
+913},{132,0,660},{7,0,1035},{138,0,737},{6,10,162},{7,10,1960},{136,10,831},{132
+,10,706},{7,0,690},{9,0,217},{9,0,587},{140,0,521},{138,10,426},{135,10,1235},{6
+,11,82},{7,11,138},{7,11,517},{9,11,673},{139,11,238},{138,0,272},{5,11,495},{7,
+11,834},{9,11,733},{139,11,378},{134,0,1744},{132,0,1011},{7,11,828},{142,11,116
+},{4,0,733},{9,0,194},{10,0,92},{11,0,198},{12,0,84},{13,0,128},{133,11,559},{10
+,0,57},{10,0,277},{6,11,21},{6,11,1737},{7,11,1444},{136,11,224},{4,10,204},{137
+,10,902},{136,10,833},{11,0,348},{12,0,99},{18,0,1},{18,0,11},{19,0,4},{7,10,366
+},{9,10,287},{12,10,199},{12,10,556},{140,10,577},{6,0,1981},{136,0,936},{21,0,
+33},{150,0,40},{5,11,519},{138,11,204},{5,10,356},{135,10,224},{134,0,775},{135,
+0,306},{7,10,630},{9,10,567},{11,10,150},{11,10,444},{141,10,119},{5,0,979},{134
+,10,539},{133,0,611},{4,11,402},{135,11,1679},{5,0,178},{7,11,2},{8,11,323},{136
+,11,479},{5,11,59},{135,11,672},{4,0,1010},{6,0,1969},{138,11,237},{133,11,412},
+{146,11,34},{7,11,1740},{146,11,48},{134,0,664},{139,10,814},{4,11,85},{135,11,
+549},{133,11,94},{133,11,457},{132,0,390},{134,0,1510},{4,10,235},{135,10,255},{
+4,10,194},{5,10,584},{6,11,11},{6,10,384},{7,11,187},{7,10,583},{10,10,761},{11,
+10,760},{139,10,851},{4,11,522},{139,11,802},{135,0,493},{10,11,776},{13,11,345}
+,{142,11,425},{146,0,37},{4,11,52},{135,11,661},{134,0,724},{134,0,829},{133,11,
+520},{133,10,562},{4,11,281},{5,11,38},{7,11,194},{7,11,668},{7,11,1893},{137,11
+,397},{5,10,191},{137,10,271},{7,0,1537},{14,0,96},{143,0,73},{5,0,473},{11,0,
+168},{4,10,470},{6,10,153},{7,10,1503},{7,10,1923},{10,10,701},{11,10,132},{11,
+10,227},{11,10,320},{11,10,436},{11,10,525},{11,10,855},{12,10,41},{12,10,286},{
+13,10,103},{13,10,284},{14,10,255},{14,10,262},{15,10,117},{143,10,127},{133,0,
+105},{5,0,438},{9,0,694},{12,0,627},{141,0,210},{133,10,327},{6,10,552},{7,10,
+1754},{137,10,604},{134,0,1256},{152,0,11},{5,11,448},{11,11,98},{139,11,524},{7
+,0,1626},{5,10,80},{6,10,405},{7,10,403},{7,10,1502},{8,10,456},{9,10,487},{9,10
+,853},{9,10,889},{10,10,309},{11,10,721},{11,10,994},{12,10,430},{13,10,165},{14
+,11,16},{146,11,44},{132,0,779},{8,0,25},{138,0,826},{4,10,453},{5,10,887},{6,10
+,535},{8,10,6},{8,10,543},{136,10,826},{137,11,461},{140,11,632},{132,0,308},{
+135,0,741},{132,0,671},{7,0,150},{8,0,649},{136,0,1020},{9,0,99},{6,11,336},{8,
+11,552},{9,11,285},{10,11,99},{139,11,568},{134,0,521},{5,0,339},{14,0,3},{15,0,
+41},{15,0,166},{147,0,66},{6,11,423},{7,11,665},{7,11,1210},{9,11,218},{141,11,
+222},{6,0,543},{5,10,101},{5,11,256},{6,10,88},{7,10,1677},{9,10,100},{10,10,677
+},{14,10,169},{14,10,302},{14,10,313},{15,10,48},{143,10,84},{4,10,310},{7,10,
+708},{7,10,996},{9,10,795},{10,10,390},{10,10,733},{11,10,451},{12,10,249},{14,
+10,115},{14,10,286},{143,10,100},{133,10,587},{13,11,417},{14,11,129},{143,11,15
+},{134,0,1358},{136,11,554},{132,10,498},{7,10,217},{8,10,140},{138,10,610},{135
+,11,989},{135,11,634},{6,0,155},{140,0,234},{135,11,462},{132,11,618},{134,0,
+1628},{132,0,766},{4,11,339},{5,10,905},{135,11,259},{135,0,829},{4,11,759},{141
+,11,169},{7,0,1445},{4,10,456},{7,10,358},{7,10,1637},{8,10,643},{139,10,483},{5
+,0,486},{135,0,1349},{5,11,688},{135,11,712},{7,0,1635},{8,0,17},{10,0,217},{10,
+0,295},{12,0,2},{140,11,2},{138,0,558},{150,10,56},{4,11,278},{5,11,465},{135,11
+,1367},{136,11,482},{133,10,535},{6,0,1362},{6,0,1461},{10,11,274},{10,11,625},{
+139,11,530},{5,0,599},{5,11,336},{6,11,341},{6,11,478},{6,11,1763},{136,11,386},
+{7,10,1748},{137,11,151},{134,0,1376},{133,10,539},{135,11,73},{135,11,1971},{
+139,11,283},{9,0,93},{139,0,474},{6,10,91},{135,10,435},{6,0,447},{5,11,396},{
+134,11,501},{4,10,16},{5,10,316},{5,10,842},{6,10,370},{6,10,1778},{8,10,166},{
+11,10,812},{12,10,206},{12,10,351},{14,10,418},{16,10,15},{16,10,34},{18,10,3},{
+19,10,3},{19,10,7},{20,10,4},{149,10,21},{7,0,577},{7,0,1432},{9,0,475},{9,0,505
+},{9,0,526},{9,0,609},{9,0,689},{9,0,726},{9,0,735},{9,0,738},{10,0,556},{10,0,
+674},{10,0,684},{11,0,89},{11,0,202},{11,0,272},{11,0,380},{11,0,415},{11,0,505}
+,{11,0,537},{11,0,550},{11,0,562},{11,0,640},{11,0,667},{11,0,688},{11,0,847},{
+11,0,927},{11,0,930},{11,0,940},{12,0,144},{12,0,325},{12,0,329},{12,0,389},{12,
+0,403},{12,0,451},{12,0,515},{12,0,604},{12,0,616},{12,0,626},{13,0,66},{13,0,
+131},{13,0,167},{13,0,236},{13,0,368},{13,0,411},{13,0,434},{13,0,453},{13,0,461
+},{13,0,474},{14,0,59},{14,0,60},{14,0,139},{14,0,152},{14,0,276},{14,0,353},{14
+,0,402},{15,0,28},{15,0,81},{15,0,123},{15,0,152},{18,0,136},{148,0,88},{4,11,
+929},{133,11,799},{136,11,46},{142,0,307},{4,0,609},{7,0,756},{9,0,544},{11,0,
+413},{144,0,25},{10,0,687},{7,10,619},{10,10,547},{11,10,122},{140,10,601},{4,0,
+930},{133,0,947},{133,0,939},{142,0,21},{4,11,892},{133,11,770},{133,0,962},{5,0
+,651},{8,0,170},{9,0,61},{9,0,63},{10,0,23},{10,0,37},{10,0,834},{11,0,4},{11,0,
+187},{11,0,281},{11,0,503},{11,0,677},{12,0,96},{12,0,130},{12,0,244},{14,0,5},{
+14,0,40},{14,0,162},{14,0,202},{146,0,133},{4,0,406},{5,0,579},{12,0,492},{150,0
+,15},{135,11,158},{135,0,597},{132,0,981},{132,10,888},{4,10,149},{138,10,368},{
+132,0,545},{4,10,154},{7,10,1134},{136,10,105},{135,11,2001},{134,0,1558},{4,10,
+31},{6,10,429},{7,10,962},{9,10,458},{139,10,691},{132,10,312},{135,10,1642},{6,
+0,17},{6,0,1304},{7,0,16},{7,0,1001},{9,0,886},{10,0,489},{10,0,800},{11,0,782},
+{12,0,320},{13,0,467},{14,0,145},{14,0,387},{143,0,119},{135,0,1982},{17,0,17},{
+7,11,1461},{140,11,91},{4,10,236},{132,11,602},{138,0,907},{136,0,110},{7,0,272}
+,{19,0,53},{5,10,836},{5,10,857},{134,10,1680},{5,0,458},{7,11,1218},{136,11,303
+},{7,0,1983},{8,0,0},{8,0,171},{9,0,120},{9,0,732},{10,0,473},{11,0,656},{11,0,
+998},{18,0,0},{18,0,2},{19,0,21},{10,10,68},{139,10,494},{137,11,662},{4,11,13},
+{5,11,567},{7,11,1498},{9,11,124},{11,11,521},{140,11,405},{4,10,81},{139,10,867
+},{135,11,1006},{7,11,800},{7,11,1783},{138,11,12},{9,0,295},{10,0,443},{5,10,
+282},{8,10,650},{137,10,907},{132,11,735},{4,11,170},{4,10,775},{135,11,323},{6,
+0,1844},{10,0,924},{11,11,844},{12,11,104},{140,11,625},{5,11,304},{7,11,1403},{
+140,11,498},{134,0,1232},{4,0,519},{10,0,70},{12,0,26},{14,0,17},{14,0,178},{15,
+0,34},{149,0,12},{132,0,993},{4,11,148},{133,11,742},{6,0,31},{7,0,491},{7,0,530
+},{8,0,592},{11,0,53},{11,0,779},{12,0,167},{12,0,411},{14,0,14},{14,0,136},{15,
+0,72},{16,0,17},{144,0,72},{133,0,907},{134,0,733},{133,11,111},{4,10,71},{5,10,
+376},{7,10,119},{138,10,665},{136,0,55},{8,0,430},{136,11,430},{4,0,208},{5,0,
+106},{6,0,531},{8,0,408},{9,0,188},{138,0,572},{12,0,56},{11,10,827},{14,10,34},
+{143,10,148},{134,0,1693},{133,11,444},{132,10,479},{140,0,441},{9,0,449},{10,0,
+192},{138,0,740},{134,0,928},{4,0,241},{7,10,607},{136,10,99},{8,11,123},{15,11,
+6},{144,11,7},{6,11,285},{8,11,654},{11,11,749},{12,11,190},{12,11,327},{13,11,
+120},{13,11,121},{13,11,327},{15,11,47},{146,11,40},{4,10,41},{5,10,74},{7,10,
+1627},{11,10,871},{140,10,619},{7,0,1525},{11,10,329},{11,10,965},{12,10,241},{
+14,10,354},{15,10,22},{148,10,63},{132,0,259},{135,11,183},{9,10,209},{137,10,
+300},{5,11,937},{135,11,100},{133,10,98},{4,0,173},{5,0,312},{5,0,512},{135,0,
+1285},{141,0,185},{7,0,1603},{7,0,1691},{9,0,464},{11,0,195},{12,0,279},{12,0,
+448},{14,0,11},{147,0,102},{135,0,1113},{133,10,984},{4,0,452},{5,0,583},{135,0,
+720},{4,0,547},{5,0,817},{6,0,433},{7,0,593},{7,0,1378},{8,0,161},{9,0,284},{10,
+0,313},{139,0,886},{8,0,722},{4,10,182},{6,10,205},{135,10,220},{150,0,13},{4,10
+,42},{9,10,205},{9,10,786},{138,10,659},{6,0,289},{7,0,1670},{12,0,57},{151,0,4}
+,{132,10,635},{14,0,43},{146,0,21},{139,10,533},{135,0,1694},{8,0,420},{139,0,
+193},{135,0,409},{132,10,371},{4,10,272},{135,10,836},{5,10,825},{134,10,1640},{
+5,11,251},{5,11,956},{8,11,268},{9,11,214},{146,11,142},{138,0,308},{6,0,1863},{
+141,11,37},{137,10,879},{7,10,317},{135,10,569},{132,11,294},{134,0,790},{5,0,
+1002},{136,0,745},{5,11,346},{5,11,711},{136,11,390},{135,0,289},{5,0,504},{11,0
+,68},{137,10,307},{4,0,239},{6,0,477},{7,0,1607},{139,0,617},{149,0,13},{133,0,
+609},{133,11,624},{5,11,783},{7,11,1998},{135,11,2047},{133,10,525},{132,0,367},
+{132,11,594},{6,0,528},{133,10,493},{4,10,174},{135,10,911},{8,10,417},{137,10,
+782},{132,0,694},{7,0,548},{137,0,58},{4,10,32},{5,10,215},{6,10,269},{7,10,1782
+},{7,10,1892},{10,10,16},{11,10,822},{11,10,954},{141,10,481},{140,0,687},{7,0,
+1749},{136,10,477},{132,11,569},{133,10,308},{135,10,1088},{4,0,661},{138,0,1004
+},{5,11,37},{6,11,39},{6,11,451},{7,11,218},{7,11,667},{7,11,1166},{7,11,1687},{
+8,11,662},{144,11,2},{9,0,445},{12,0,53},{13,0,492},{5,10,126},{8,10,297},{9,10,
+366},{140,10,374},{7,10,1551},{139,10,361},{148,0,74},{134,11,508},{135,0,213},{
+132,10,175},{132,10,685},{6,0,760},{6,0,834},{134,0,1248},{7,11,453},{7,11,635},
+{7,11,796},{8,11,331},{9,11,328},{9,11,330},{9,11,865},{10,11,119},{10,11,235},{
+11,11,111},{11,11,129},{11,11,240},{12,11,31},{12,11,66},{12,11,222},{12,11,269}
+,{12,11,599},{12,11,689},{13,11,186},{13,11,364},{142,11,345},{7,0,1672},{139,0,
+189},{133,10,797},{133,10,565},{6,0,1548},{6,11,98},{7,11,585},{135,11,702},{9,0
+,968},{15,0,192},{149,0,56},{4,10,252},{6,11,37},{7,11,299},{7,10,1068},{7,11,
+1666},{8,11,195},{8,11,316},{9,11,178},{9,11,276},{9,11,339},{9,11,536},{10,11,
+102},{10,11,362},{10,10,434},{10,11,785},{11,11,55},{11,11,149},{11,10,228},{11,
+10,426},{11,11,773},{13,10,231},{13,11,416},{13,11,419},{14,11,38},{14,11,41},{
+14,11,210},{18,10,106},{148,10,87},{4,0,751},{11,0,390},{140,0,32},{4,0,409},{
+133,0,78},{11,11,458},{12,11,15},{140,11,432},{7,0,1602},{10,0,257},{10,0,698},{
+11,0,544},{11,0,585},{12,0,212},{13,0,307},{5,10,231},{7,10,601},{9,10,277},{9,
+10,674},{10,10,178},{10,10,418},{10,10,509},{11,10,531},{12,10,113},{12,10,475},
+{13,10,99},{142,10,428},{6,0,473},{145,0,105},{6,0,1949},{15,0,156},{133,11,645}
+,{7,10,1591},{144,10,43},{135,0,1779},{135,10,1683},{4,11,290},{135,11,1356},{
+134,0,763},{6,11,70},{7,11,1292},{10,11,762},{139,11,288},{142,0,29},{140,11,428
+},{7,0,883},{7,11,131},{7,11,422},{8,11,210},{140,11,573},{134,0,488},{4,10,399}
+,{5,10,119},{5,10,494},{7,10,751},{137,10,556},{133,0,617},{132,11,936},{139,0,
+50},{7,0,1518},{139,0,694},{137,0,785},{4,0,546},{135,0,2042},{7,11,716},{13,11,
+97},{141,11,251},{132,11,653},{145,0,22},{134,0,1016},{4,0,313},{133,0,577},{136
+,11,657},{8,0,184},{141,0,433},{135,0,935},{6,0,720},{9,0,114},{146,11,80},{12,0
+,186},{12,0,292},{14,0,100},{18,0,70},{7,10,594},{7,10,851},{7,10,1858},{9,10,
+411},{9,10,574},{9,10,666},{9,10,737},{10,10,346},{10,10,712},{11,10,246},{11,10
+,432},{11,10,517},{11,10,647},{11,10,679},{11,10,727},{12,10,304},{12,10,305},{
+12,10,323},{12,10,483},{12,10,572},{12,10,593},{12,10,602},{13,10,95},{13,10,101
+},{13,10,171},{13,10,315},{13,10,378},{13,10,425},{13,10,475},{14,10,63},{14,10,
+380},{14,10,384},{15,10,133},{18,10,112},{148,10,72},{135,10,1093},{135,11,1836}
+,{132,10,679},{137,10,203},{11,0,402},{12,0,109},{12,0,431},{13,0,179},{13,0,206
+},{14,0,217},{16,0,3},{148,0,53},{7,11,1368},{8,11,232},{8,11,361},{10,11,682},{
+138,11,742},{137,10,714},{5,0,886},{6,0,46},{6,0,1790},{7,0,14},{7,0,732},{7,0,
+1654},{8,0,95},{8,0,327},{8,0,616},{9,0,892},{10,0,598},{10,0,769},{11,0,134},{
+11,0,747},{12,0,378},{14,0,97},{137,11,534},{4,0,969},{136,10,825},{137,11,27},{
+6,0,727},{142,11,12},{133,0,1021},{134,0,1190},{134,11,1657},{5,10,143},{5,10,
+769},{6,10,1760},{7,10,682},{7,10,1992},{136,10,736},{132,0,153},{135,11,127},{
+133,0,798},{132,0,587},{6,0,598},{7,0,42},{8,0,695},{10,0,212},{11,0,158},{14,0,
+196},{145,0,85},{133,10,860},{6,0,1929},{134,0,1933},{5,0,957},{5,0,1008},{9,0,
+577},{12,0,141},{6,10,422},{7,10,0},{7,10,1544},{8,11,364},{11,10,990},{12,10,
+453},{13,10,47},{141,10,266},{134,0,1319},{4,0,129},{135,0,465},{7,0,470},{7,0,
+1057},{7,0,1201},{9,0,755},{11,0,906},{140,0,527},{7,0,908},{146,0,7},{5,0,148},
+{136,0,450},{5,10,515},{137,10,131},{7,10,1605},{11,10,962},{146,10,139},{132,10
+,646},{134,0,1166},{4,10,396},{7,10,728},{9,10,117},{13,10,202},{148,10,51},{6,
+10,121},{6,10,124},{6,10,357},{7,10,1138},{7,10,1295},{8,10,162},{139,10,655},{
+14,0,374},{142,11,374},{138,0,253},{139,0,1003},{5,11,909},{9,11,849},{138,11,
+805},{133,10,237},{7,11,525},{7,11,1579},{8,11,497},{136,11,573},{137,0,46},{132
+,0,879},{134,0,806},{135,0,1868},{6,0,1837},{134,0,1846},{6,0,730},{134,0,881},{
+7,0,965},{7,0,1460},{7,0,1604},{7,11,193},{7,11,397},{7,11,1105},{8,11,124},{8,
+11,619},{9,11,305},{10,11,264},{11,11,40},{12,11,349},{13,11,134},{13,11,295},{
+14,11,155},{15,11,120},{146,11,105},{136,0,506},{143,0,10},{4,11,262},{7,11,342}
+,{7,10,571},{7,10,1877},{10,10,366},{141,11,23},{133,11,641},{10,0,22},{9,10,513
+},{10,10,39},{12,10,122},{140,10,187},{135,11,1431},{150,11,49},{4,11,99},{6,11,
+250},{6,11,346},{8,11,127},{138,11,81},{6,0,2014},{8,0,928},{10,0,960},{10,0,979
+},{140,0,996},{134,0,296},{132,11,915},{5,11,75},{9,11,517},{10,11,470},{12,11,
+155},{141,11,224},{137,10,873},{4,0,854},{140,11,18},{134,0,587},{7,10,107},{7,
+10,838},{8,10,550},{138,10,401},{11,0,636},{15,0,145},{17,0,34},{19,0,50},{23,0,
+20},{11,10,588},{11,10,864},{11,10,968},{143,10,160},{135,11,216},{7,0,982},{10,
+0,32},{143,0,56},{133,10,768},{133,11,954},{6,11,304},{7,11,1114},{8,11,418},{10
+,11,345},{11,11,341},{11,11,675},{141,11,40},{9,11,410},{139,11,425},{136,0,941}
+,{5,0,435},{132,10,894},{5,0,85},{6,0,419},{7,0,134},{7,0,305},{7,0,361},{7,0,
+1337},{8,0,71},{140,0,519},{140,0,688},{135,0,740},{5,0,691},{7,0,345},{9,0,94},
+{140,0,169},{5,0,183},{6,0,582},{10,0,679},{140,0,435},{134,11,14},{6,0,945},{
+135,0,511},{134,11,1708},{5,11,113},{6,11,243},{7,11,1865},{11,11,161},{16,11,37
+},{145,11,99},{132,11,274},{137,0,539},{7,0,1993},{8,0,684},{134,10,272},{6,0,
+659},{134,0,982},{4,10,9},{5,10,128},{7,10,368},{11,10,480},{148,10,3},{134,0,
+583},{132,0,803},{133,0,704},{4,0,179},{5,0,198},{133,0,697},{7,0,347},{7,0,971}
+,{8,0,181},{10,0,711},{135,11,166},{136,10,682},{4,10,2},{7,10,545},{7,10,894},{
+136,11,521},{135,0,481},{132,0,243},{5,0,203},{7,0,19},{7,0,71},{7,0,113},{10,0,
+405},{11,0,357},{142,0,240},{5,11,725},{5,11,727},{135,11,1811},{6,0,826},{137,
+11,304},{7,0,1450},{139,0,99},{133,11,654},{134,0,492},{5,0,134},{6,0,408},{6,0,
+495},{7,0,1593},{6,11,273},{10,11,188},{13,11,377},{146,11,77},{9,10,769},{140,
+10,185},{135,11,410},{142,0,4},{4,0,665},{134,11,1785},{4,0,248},{7,0,137},{137,
+0,349},{5,10,530},{142,10,113},{7,0,1270},{139,0,612},{132,11,780},{5,0,371},{
+135,0,563},{135,0,826},{6,0,1535},{23,0,21},{151,0,23},{4,0,374},{7,0,547},{7,0,
+1700},{7,0,1833},{139,0,858},{133,10,556},{7,11,612},{8,11,545},{8,11,568},{8,11
+,642},{9,11,717},{10,11,541},{10,11,763},{11,11,449},{12,11,489},{13,11,153},{13
+,11,296},{14,11,138},{14,11,392},{15,11,50},{16,11,6},{16,11,12},{148,11,9},{9,0
+,311},{141,0,42},{8,10,16},{140,10,568},{6,0,1968},{6,0,2027},{138,0,991},{6,0,
+1647},{7,0,1552},{7,0,2010},{9,0,494},{137,0,509},{133,11,948},{6,10,186},{137,
+10,426},{134,0,769},{134,0,642},{132,10,585},{6,0,123},{7,0,214},{9,0,728},{10,0
+,157},{11,0,346},{11,0,662},{143,0,106},{142,11,381},{135,0,1435},{4,11,532},{5,
+11,706},{135,11,662},{5,11,837},{134,11,1651},{4,10,93},{5,10,252},{6,10,229},{7
+,10,291},{9,10,550},{139,10,644},{148,0,79},{137,10,749},{134,0,1425},{137,10,
+162},{4,11,362},{7,11,52},{7,11,303},{140,11,166},{132,10,381},{4,11,330},{7,11,
+933},{7,11,2012},{136,11,292},{135,11,767},{4,0,707},{5,0,588},{6,0,393},{13,0,
+106},{18,0,49},{147,0,41},{6,0,211},{7,0,1690},{11,0,486},{140,0,369},{137,11,
+883},{4,11,703},{135,11,207},{4,0,187},{5,0,184},{5,0,690},{7,0,1869},{10,0,756}
+,{139,0,783},{132,11,571},{134,0,1382},{5,0,175},{6,10,77},{6,10,157},{7,10,974}
+,{7,10,1301},{7,10,1339},{7,10,1490},{7,10,1873},{137,10,628},{134,0,1493},{5,11
+,873},{133,11,960},{134,0,1007},{12,11,93},{12,11,501},{13,11,362},{14,11,151},{
+15,11,40},{15,11,59},{16,11,46},{17,11,25},{18,11,14},{18,11,134},{19,11,25},{19
+,11,69},{20,11,16},{20,11,19},{20,11,66},{21,11,23},{21,11,25},{150,11,42},{11,
+10,919},{141,10,409},{134,0,219},{5,0,582},{6,0,1646},{7,0,99},{7,0,1962},{7,0,
+1986},{8,0,515},{8,0,773},{9,0,23},{9,0,491},{12,0,620},{142,0,93},{133,0,851},{
+5,11,33},{134,11,470},{135,11,1291},{134,0,1278},{135,11,1882},{135,10,1489},{
+132,0,1000},{138,0,982},{8,0,762},{8,0,812},{137,0,910},{6,11,47},{7,11,90},{7,
+11,664},{7,11,830},{7,11,1380},{7,11,2025},{8,11,448},{136,11,828},{4,0,98},{4,0
+,940},{6,0,1819},{6,0,1834},{6,0,1841},{7,0,1365},{8,0,859},{8,0,897},{8,0,918},
+{9,0,422},{9,0,670},{10,0,775},{10,0,894},{10,0,909},{10,0,910},{10,0,935},{11,0
+,210},{12,0,750},{12,0,755},{13,0,26},{13,0,457},{13,0,476},{16,0,100},{16,0,109
+},{18,0,173},{18,0,175},{8,10,398},{9,10,681},{139,10,632},{9,11,417},{137,11,
+493},{136,10,645},{138,0,906},{134,0,1730},{134,10,20},{133,11,1019},{134,0,1185
+},{10,0,40},{136,10,769},{9,0,147},{134,11,208},{140,0,650},{5,0,209},{6,0,30},{
+11,0,56},{139,0,305},{132,0,553},{138,11,344},{6,11,68},{7,11,398},{7,11,448},{7
+,11,1629},{7,11,1813},{8,11,387},{8,11,442},{9,11,710},{10,11,282},{138,11,722},
+{5,0,597},{14,0,20},{142,11,20},{135,0,1614},{135,10,1757},{4,0,150},{5,0,303},{
+6,0,327},{135,10,937},{16,0,49},{7,10,1652},{144,11,49},{8,0,192},{10,0,78},{141
+,0,359},{135,0,786},{143,0,134},{6,0,1638},{7,0,79},{7,0,496},{9,0,138},{10,0,
+336},{11,0,12},{12,0,412},{12,0,440},{142,0,305},{136,11,491},{4,10,579},{5,10,
+226},{5,10,323},{135,10,960},{7,0,204},{7,0,415},{8,0,42},{10,0,85},{139,0,564},
+{132,0,614},{4,11,403},{5,11,441},{7,11,450},{11,11,101},{12,11,193},{141,11,430
+},{135,11,1927},{135,11,1330},{4,0,3},{5,0,247},{5,0,644},{7,0,744},{7,0,1207},{
+7,0,1225},{7,0,1909},{146,0,147},{136,0,942},{4,0,1019},{134,0,2023},{5,11,679},
+{133,10,973},{5,0,285},{9,0,67},{13,0,473},{143,0,82},{7,11,328},{137,11,326},{
+151,0,8},{6,10,135},{135,10,1176},{135,11,1128},{134,0,1309},{135,11,1796},{135,
+10,314},{4,11,574},{7,11,350},{7,11,1024},{8,11,338},{9,11,677},{10,11,808},{139
+,11,508},{7,11,818},{17,11,14},{17,11,45},{18,11,75},{148,11,18},{146,10,4},{135
+,11,1081},{4,0,29},{6,0,532},{7,0,1628},{7,0,1648},{9,0,350},{10,0,433},{11,0,97
+},{11,0,557},{11,0,745},{12,0,289},{12,0,335},{12,0,348},{12,0,606},{13,0,116},{
+13,0,233},{13,0,466},{14,0,181},{14,0,209},{14,0,232},{14,0,236},{14,0,300},{16,
+0,41},{148,0,97},{7,0,318},{6,10,281},{8,10,282},{8,10,480},{8,10,499},{9,10,198
+},{10,10,143},{10,10,169},{10,10,211},{10,10,417},{10,10,574},{11,10,147},{11,10
+,395},{12,10,75},{12,10,407},{12,10,608},{13,10,500},{142,10,251},{135,11,1676},
+{135,11,2037},{135,0,1692},{5,0,501},{7,0,1704},{9,0,553},{11,0,520},{12,0,557},
+{141,0,249},{6,0,1527},{14,0,324},{15,0,55},{15,0,80},{14,11,324},{15,11,55},{
+143,11,80},{135,10,1776},{8,0,988},{137,11,297},{132,10,419},{142,0,223},{139,11
+,234},{7,0,1123},{12,0,508},{14,0,102},{14,0,226},{144,0,57},{4,10,138},{7,10,
+1012},{7,10,1280},{137,10,76},{7,0,1764},{5,10,29},{140,10,638},{134,0,2015},{
+134,0,1599},{138,11,56},{6,11,306},{7,11,1140},{7,11,1340},{8,11,133},{138,11,
+449},{139,11,1011},{6,10,1710},{135,10,2038},{7,11,1763},{140,11,310},{6,0,129},
+{4,10,17},{5,10,23},{7,10,995},{11,10,383},{11,10,437},{12,10,460},{140,10,532},
+{5,11,329},{136,11,260},{133,10,862},{132,0,534},{6,0,811},{135,0,626},{132,11,
+657},{4,0,25},{5,0,60},{6,0,504},{7,0,614},{7,0,1155},{12,0,0},{152,11,7},{7,0,
+1248},{11,0,621},{139,0,702},{137,0,321},{8,10,70},{12,10,171},{141,10,272},{10,
+10,233},{139,10,76},{4,0,379},{7,0,1397},{134,10,442},{5,11,66},{7,11,1896},{136
+,11,288},{134,11,1643},{134,10,1709},{4,11,21},{5,11,91},{5,11,570},{5,11,648},{
+5,11,750},{5,11,781},{6,11,54},{6,11,112},{6,11,402},{6,11,1732},{7,11,315},{7,
+11,749},{7,11,1347},{7,11,1900},{9,11,78},{9,11,508},{10,11,611},{11,11,510},{11
+,11,728},{13,11,36},{14,11,39},{16,11,83},{17,11,124},{148,11,30},{4,0,118},{6,0
+,274},{6,0,361},{7,0,75},{141,0,441},{10,11,322},{10,11,719},{139,11,407},{147,
+10,119},{12,11,549},{14,11,67},{147,11,60},{11,10,69},{12,10,105},{12,10,117},{
+13,10,213},{14,10,13},{14,10,62},{14,10,177},{14,10,421},{15,10,19},{146,10,141}
+,{9,0,841},{137,10,309},{7,10,608},{7,10,976},{8,11,125},{8,11,369},{8,11,524},{
+9,10,146},{10,10,206},{10,11,486},{10,10,596},{11,11,13},{11,11,381},{11,11,736}
+,{11,11,766},{11,11,845},{13,11,114},{13,10,218},{13,11,292},{14,11,47},{142,10,
+153},{12,0,693},{135,11,759},{5,0,314},{6,0,221},{7,0,419},{10,0,650},{11,0,396}
+,{12,0,156},{13,0,369},{14,0,333},{145,0,47},{6,11,1684},{6,11,1731},{7,11,356},
+{7,11,1932},{8,11,54},{8,11,221},{9,11,225},{9,11,356},{10,11,77},{10,11,446},{
+10,11,731},{12,11,404},{141,11,491},{132,11,375},{4,10,518},{135,10,1136},{4,0,
+913},{4,11,411},{11,11,643},{140,11,115},{4,11,80},{133,11,44},{8,10,689},{137,
+10,863},{138,0,880},{4,10,18},{7,10,145},{7,10,444},{7,10,1278},{8,10,49},{8,10,
+400},{9,10,71},{9,10,250},{10,10,459},{12,10,160},{144,10,24},{136,0,475},{5,0,
+1016},{5,11,299},{135,11,1083},{7,0,602},{8,0,179},{10,0,781},{140,0,126},{6,0,
+329},{138,0,111},{135,0,1864},{4,11,219},{7,11,1761},{137,11,86},{6,0,1888},{6,0
+,1892},{6,0,1901},{6,0,1904},{9,0,953},{9,0,985},{9,0,991},{9,0,1001},{12,0,818}
+,{12,0,846},{12,0,847},{12,0,861},{12,0,862},{12,0,873},{12,0,875},{12,0,877},{
+12,0,879},{12,0,881},{12,0,884},{12,0,903},{12,0,915},{12,0,926},{12,0,939},{15,
+0,182},{15,0,219},{15,0,255},{18,0,191},{18,0,209},{18,0,211},{149,0,41},{5,11,
+328},{135,11,918},{137,0,780},{12,0,82},{143,0,36},{133,10,1010},{5,0,821},{134,
+0,1687},{133,11,514},{132,0,956},{134,0,1180},{10,0,112},{5,10,87},{7,10,313},{7
+,10,1103},{10,10,582},{11,10,389},{11,10,813},{12,10,385},{13,10,286},{14,10,124
+},{146,10,108},{5,0,71},{7,0,1407},{9,0,704},{10,0,261},{10,0,619},{11,0,547},{
+11,0,619},{143,0,157},{4,0,531},{5,0,455},{5,11,301},{6,11,571},{14,11,49},{146,
+11,102},{132,10,267},{6,0,385},{7,0,2008},{9,0,337},{138,0,517},{133,11,726},{
+133,11,364},{4,11,76},{7,11,1550},{9,11,306},{9,11,430},{9,11,663},{10,11,683},{
+11,11,427},{11,11,753},{12,11,334},{12,11,442},{14,11,258},{14,11,366},{143,11,
+131},{6,0,1865},{6,0,1879},{6,0,1881},{6,0,1894},{6,0,1908},{9,0,915},{9,0,926},
+{9,0,940},{9,0,943},{9,0,966},{9,0,980},{9,0,989},{9,0,1005},{9,0,1010},{12,0,
+813},{12,0,817},{12,0,840},{12,0,843},{12,0,855},{12,0,864},{12,0,871},{12,0,872
+},{12,0,899},{12,0,905},{12,0,924},{15,0,171},{15,0,181},{15,0,224},{15,0,235},{
+15,0,251},{146,0,184},{137,11,52},{5,0,16},{6,0,86},{6,0,603},{7,0,292},{7,0,561
+},{8,0,257},{8,0,382},{9,0,721},{9,0,778},{11,0,581},{140,0,466},{4,0,486},{5,0,
+491},{135,10,1121},{4,0,72},{6,0,265},{135,0,1300},{135,11,1183},{10,10,249},{
+139,10,209},{132,10,561},{137,11,519},{4,11,656},{4,10,760},{135,11,779},{9,10,
+154},{140,10,485},{135,11,1793},{135,11,144},{136,10,255},{133,0,621},{4,10,368}
+,{135,10,641},{135,11,1373},{7,11,554},{7,11,605},{141,11,10},{137,0,234},{5,0,
+815},{6,0,1688},{134,0,1755},{5,11,838},{5,11,841},{134,11,1649},{7,0,1987},{7,0
+,2040},{136,0,743},{133,11,1012},{6,0,197},{136,0,205},{6,0,314},{134,11,314},{
+144,11,53},{6,11,251},{7,11,365},{7,11,1357},{7,11,1497},{8,11,154},{141,11,281}
+,{133,11,340},{6,0,452},{7,0,312},{138,0,219},{138,0,589},{4,0,333},{9,0,176},{
+12,0,353},{141,0,187},{9,10,92},{147,10,91},{134,0,1110},{11,0,47},{139,11,495},
+{6,10,525},{8,10,806},{9,10,876},{140,10,284},{8,11,261},{9,11,144},{9,11,466},{
+10,11,370},{12,11,470},{13,11,144},{142,11,348},{137,11,897},{8,0,863},{8,0,864}
+,{8,0,868},{8,0,884},{10,0,866},{10,0,868},{10,0,873},{10,0,911},{10,0,912},{10,
+0,944},{12,0,727},{6,11,248},{9,11,546},{10,11,535},{11,11,681},{141,11,135},{6,
+0,300},{135,0,1515},{134,0,1237},{139,10,958},{133,10,594},{140,11,250},{134,0,
+1685},{134,11,567},{7,0,135},{8,0,7},{8,0,62},{9,0,243},{10,0,658},{10,0,697},{
+11,0,456},{139,0,756},{9,0,395},{138,0,79},{6,10,1641},{136,10,820},{4,10,302},{
+135,10,1766},{134,11,174},{135,10,1313},{135,0,631},{134,10,1674},{134,11,395},{
+138,0,835},{7,0,406},{7,0,459},{8,0,606},{139,0,726},{134,11,617},{134,0,979},{6
+,10,389},{7,10,149},{9,10,142},{138,10,94},{5,11,878},{133,11,972},{6,10,8},{7,
+10,1881},{8,10,91},{136,11,511},{133,0,612},{132,11,351},{4,0,372},{7,0,482},{8,
+0,158},{9,0,602},{9,0,615},{10,0,245},{10,0,678},{10,0,744},{11,0,248},{139,0,
+806},{5,0,854},{135,0,1991},{132,11,286},{135,11,344},{7,11,438},{7,11,627},{7,
+11,1516},{8,11,40},{9,11,56},{9,11,294},{10,11,30},{10,11,259},{11,11,969},{146,
+11,148},{135,0,1492},{5,11,259},{7,11,414},{7,11,854},{142,11,107},{135,10,1746}
+,{6,0,833},{134,0,998},{135,10,24},{6,0,750},{135,0,1739},{4,10,503},{135,10,
+1661},{5,10,130},{7,10,1314},{9,10,610},{10,10,718},{11,10,601},{11,10,819},{11,
+10,946},{140,10,536},{10,10,149},{11,10,280},{142,10,336},{132,11,738},{135,10,
+1946},{5,0,195},{135,0,1685},{7,0,1997},{8,0,730},{139,0,1006},{151,11,17},{133,
+11,866},{14,0,463},{14,0,470},{150,0,61},{5,0,751},{8,0,266},{11,0,578},{4,10,
+392},{135,10,1597},{5,10,433},{9,10,633},{139,10,629},{135,0,821},{6,0,715},{134
+,0,1325},{133,11,116},{6,0,868},{132,11,457},{134,0,959},{6,10,234},{138,11,199}
+,{7,0,1053},{7,10,1950},{8,10,680},{11,10,817},{147,10,88},{7,10,1222},{138,10,
+386},{5,0,950},{5,0,994},{6,0,351},{134,0,1124},{134,0,1081},{7,0,1595},{6,10,5}
+,{11,10,249},{12,10,313},{16,10,66},{145,10,26},{148,0,59},{5,11,527},{6,11,189}
+,{135,11,859},{5,10,963},{6,10,1773},{11,11,104},{11,11,554},{15,11,60},{143,11,
+125},{135,0,47},{137,0,684},{134,11,116},{134,0,1606},{134,0,777},{7,0,1020},{8,
+10,509},{136,10,792},{135,0,1094},{132,0,350},{133,11,487},{4,11,86},{5,11,667},
+{5,11,753},{6,11,316},{6,11,455},{135,11,946},{7,0,1812},{13,0,259},{13,0,356},{
+14,0,242},{147,0,114},{132,10,931},{133,0,967},{4,0,473},{7,0,623},{8,0,808},{9,
+0,871},{9,0,893},{11,0,38},{11,0,431},{12,0,112},{12,0,217},{12,0,243},{12,0,562
+},{12,0,663},{12,0,683},{13,0,141},{13,0,197},{13,0,227},{13,0,406},{13,0,487},{
+14,0,156},{14,0,203},{14,0,224},{14,0,256},{18,0,58},{150,0,0},{138,0,286},{7,10
+,943},{139,10,614},{135,10,1837},{150,11,45},{132,0,798},{4,0,222},{7,0,286},{
+136,0,629},{4,11,79},{7,11,1773},{10,11,450},{11,11,589},{13,11,332},{13,11,493}
+,{14,11,183},{14,11,334},{14,11,362},{14,11,368},{14,11,376},{14,11,379},{19,11,
+90},{19,11,103},{19,11,127},{148,11,90},{5,0,337},{11,0,513},{11,0,889},{11,0,
+961},{12,0,461},{13,0,79},{15,0,121},{4,10,90},{5,10,545},{7,10,754},{9,10,186},
+{10,10,72},{10,10,782},{11,10,577},{11,10,610},{12,10,354},{12,10,362},{140,10,
+595},{141,0,306},{136,0,146},{7,0,1646},{9,10,329},{11,10,254},{141,11,124},{4,0
+,465},{135,0,1663},{132,0,525},{133,11,663},{10,0,299},{18,0,74},{9,10,187},{11,
+10,1016},{145,10,44},{7,0,165},{7,0,919},{4,10,506},{136,10,517},{5,10,295},{135
+,10,1680},{133,11,846},{134,0,1064},{5,11,378},{7,11,1402},{7,11,1414},{8,11,465
+},{9,11,286},{10,11,185},{10,11,562},{10,11,635},{11,11,31},{11,11,393},{12,11,
+456},{13,11,312},{18,11,65},{18,11,96},{147,11,89},{132,0,596},{7,10,987},{9,10,
+688},{10,10,522},{11,10,788},{140,10,566},{6,0,82},{7,0,138},{7,0,517},{7,0,1741
+},{11,0,238},{4,11,648},{134,10,1775},{7,0,1233},{7,10,700},{7,10,940},{8,10,514
+},{9,10,116},{9,10,535},{10,10,118},{11,10,107},{11,10,148},{11,10,922},{12,10,
+254},{12,10,421},{142,10,238},{4,0,962},{6,0,1824},{8,0,894},{12,0,708},{12,0,
+725},{14,0,451},{20,0,94},{22,0,59},{150,0,62},{5,11,945},{6,11,1656},{6,11,1787
+},{7,11,167},{8,11,824},{9,11,391},{10,11,375},{139,11,185},{5,0,495},{7,0,834},
+{9,0,733},{139,0,378},{4,10,743},{135,11,1273},{6,0,1204},{7,11,1645},{8,11,352}
+,{137,11,249},{139,10,292},{133,0,559},{132,11,152},{9,0,499},{10,0,341},{15,0,
+144},{19,0,49},{7,10,1283},{9,10,227},{11,10,325},{11,10,408},{14,10,180},{146,
+10,47},{6,0,21},{6,0,1737},{7,0,1444},{136,0,224},{133,11,1006},{7,0,1446},{9,0,
+97},{17,0,15},{5,10,81},{7,10,146},{7,10,1342},{8,10,53},{8,10,561},{8,10,694},{
+8,10,754},{9,10,115},{9,10,894},{10,10,462},{10,10,813},{11,10,230},{11,10,657},
+{11,10,699},{11,10,748},{12,10,119},{12,10,200},{12,10,283},{142,10,273},{5,10,
+408},{137,10,747},{135,11,431},{135,11,832},{6,0,729},{134,0,953},{4,0,727},{8,0
+,565},{5,11,351},{7,11,264},{136,11,565},{134,0,1948},{5,0,519},{5,11,40},{7,11,
+598},{7,11,1638},{8,11,78},{9,11,166},{9,11,640},{9,11,685},{9,11,773},{11,11,
+215},{13,11,65},{14,11,172},{14,11,317},{145,11,6},{8,11,60},{9,11,343},{139,11,
+769},{137,11,455},{134,0,1193},{140,0,790},{7,11,1951},{8,11,765},{8,11,772},{
+140,11,671},{7,11,108},{8,11,219},{8,11,388},{9,11,639},{9,11,775},{11,11,275},{
+140,11,464},{132,11,468},{7,10,30},{8,10,86},{8,10,315},{8,10,700},{9,10,576},{9
+,10,858},{11,10,310},{11,10,888},{11,10,904},{12,10,361},{141,10,248},{5,11,15},
+{6,11,56},{7,11,1758},{8,11,500},{9,11,730},{11,11,331},{13,11,150},{142,11,282}
+,{4,0,402},{7,0,2},{8,0,323},{136,0,479},{138,10,839},{11,0,580},{142,0,201},{5,
+0,59},{135,0,672},{137,10,617},{146,0,34},{134,11,1886},{4,0,961},{136,0,896},{6
+,0,1285},{5,11,205},{6,11,438},{137,11,711},{134,10,428},{7,10,524},{8,10,169},{
+8,10,234},{9,10,480},{138,10,646},{148,0,46},{141,0,479},{133,11,534},{6,0,2019}
+,{134,10,1648},{4,0,85},{7,0,549},{7,10,1205},{138,10,637},{4,0,663},{5,0,94},{7
+,11,235},{7,11,1475},{15,11,68},{146,11,120},{6,11,443},{9,11,237},{9,11,571},{9
+,11,695},{10,11,139},{11,11,715},{12,11,417},{141,11,421},{132,0,783},{4,0,682},
+{8,0,65},{9,10,39},{10,10,166},{11,10,918},{12,10,635},{20,10,10},{22,10,27},{22
+,10,43},{150,10,52},{6,0,11},{135,0,187},{132,0,522},{4,0,52},{135,0,661},{4,0,
+383},{133,0,520},{135,11,546},{11,0,343},{142,0,127},{4,11,578},{7,10,157},{7,11
+,624},{7,11,916},{8,10,279},{10,11,256},{11,11,87},{139,11,703},{134,10,604},{4,
+0,281},{5,0,38},{7,0,194},{7,0,668},{7,0,1893},{137,0,397},{7,10,945},{11,10,713
+},{139,10,744},{139,10,1022},{9,0,635},{139,0,559},{5,11,923},{7,11,490},{12,11,
+553},{13,11,100},{14,11,118},{143,11,75},{132,0,975},{132,10,567},{137,10,859},{
+7,10,1846},{7,11,1846},{8,10,628},{136,11,628},{148,0,116},{138,11,750},{14,0,51
+},{14,11,51},{15,11,7},{148,11,20},{132,0,858},{134,0,1075},{4,11,924},{133,10,
+762},{136,0,535},{133,0,448},{10,10,784},{141,10,191},{133,10,298},{7,0,610},{
+135,0,1501},{7,10,633},{7,10,905},{7,10,909},{7,10,1538},{9,10,767},{140,10,636}
+,{4,11,265},{7,11,807},{135,11,950},{5,11,93},{12,11,267},{144,11,26},{136,0,191
+},{139,10,301},{135,10,1970},{135,0,267},{4,0,319},{5,0,699},{138,0,673},{6,0,
+336},{7,0,92},{7,0,182},{8,0,453},{8,0,552},{9,0,204},{9,0,285},{10,0,99},{11,0,
+568},{11,0,950},{12,0,94},{16,0,20},{16,0,70},{19,0,55},{12,10,644},{144,10,90},
+{6,0,551},{7,0,1308},{7,10,845},{7,11,994},{8,10,160},{137,10,318},{19,11,1},{19
+,11,26},{150,11,9},{7,0,1406},{9,0,218},{141,0,222},{5,0,256},{138,0,69},{5,11,
+233},{5,11,320},{6,11,140},{7,11,330},{136,11,295},{6,0,1980},{136,0,952},{4,0,
+833},{137,11,678},{133,11,978},{4,11,905},{6,11,1701},{137,11,843},{138,10,735},
+{136,10,76},{17,0,39},{148,0,36},{18,0,81},{146,11,81},{14,0,352},{17,0,53},{18,
+0,146},{18,0,152},{19,0,11},{150,0,54},{135,0,634},{138,10,841},{132,0,618},{4,0
+,339},{7,0,259},{17,0,73},{4,11,275},{140,11,376},{132,11,509},{7,11,273},{139,
+11,377},{4,0,759},{13,0,169},{137,10,804},{6,10,96},{135,10,1426},{4,10,651},{
+133,10,289},{7,0,1075},{8,10,35},{9,10,511},{10,10,767},{147,10,118},{6,0,649},{
+6,0,670},{136,0,482},{5,0,336},{6,0,341},{6,0,478},{6,0,1763},{136,0,386},{5,11,
+802},{7,11,2021},{8,11,805},{14,11,94},{15,11,65},{16,11,4},{16,11,77},{16,11,80
+},{145,11,5},{6,0,1035},{5,11,167},{5,11,899},{6,11,410},{137,11,777},{134,11,
+1705},{5,0,924},{133,0,969},{132,10,704},{135,0,73},{135,11,10},{135,10,1078},{5
+,11,11},{6,11,117},{6,11,485},{7,11,1133},{9,11,582},{9,11,594},{11,11,21},{11,
+11,818},{12,11,535},{141,11,86},{135,0,1971},{4,11,264},{7,11,1067},{8,11,204},{
+8,11,385},{139,11,953},{6,0,1458},{135,0,1344},{5,0,396},{134,0,501},{4,10,720},
+{133,10,306},{4,0,929},{5,0,799},{8,0,46},{8,0,740},{133,10,431},{7,11,646},{7,
+11,1730},{11,11,446},{141,11,178},{7,0,276},{5,10,464},{6,10,236},{7,10,696},{7,
+10,914},{7,10,1108},{7,10,1448},{9,10,15},{9,10,564},{10,10,14},{12,10,565},{13,
+10,449},{14,10,53},{15,10,13},{16,10,64},{145,10,41},{4,0,892},{133,0,770},{6,10
+,1767},{12,10,194},{145,10,107},{135,0,158},{5,10,840},{138,11,608},{134,0,1432}
+,{138,11,250},{8,11,794},{9,11,400},{10,11,298},{142,11,228},{151,0,25},{7,11,
+1131},{135,11,1468},{135,0,2001},{9,10,642},{11,10,236},{142,10,193},{4,10,68},{
+5,10,634},{6,10,386},{7,10,794},{8,10,273},{9,10,563},{10,10,105},{10,10,171},{
+11,10,94},{139,10,354},{136,11,724},{132,0,478},{11,11,512},{13,11,205},{19,11,
+30},{22,11,36},{151,11,19},{7,0,1461},{140,0,91},{6,11,190},{7,11,768},{135,11,
+1170},{4,0,602},{8,0,211},{4,10,95},{7,10,416},{139,10,830},{7,10,731},{13,10,20
+},{143,10,11},{6,0,1068},{135,0,1872},{4,0,13},{5,0,567},{7,0,1498},{9,0,124},{
+11,0,521},{12,0,405},{135,11,1023},{135,0,1006},{132,0,735},{138,0,812},{4,0,170
+},{135,0,323},{6,11,137},{9,11,75},{9,11,253},{10,11,194},{138,11,444},{5,0,304}
+,{7,0,1403},{5,10,864},{10,10,648},{11,10,671},{143,10,46},{135,11,1180},{133,10
+,928},{4,0,148},{133,0,742},{11,10,986},{140,10,682},{133,0,523},{135,11,1743},{
+7,0,730},{18,0,144},{19,0,61},{8,10,44},{9,10,884},{10,10,580},{11,10,399},{11,
+10,894},{143,10,122},{5,11,760},{7,11,542},{8,11,135},{136,11,496},{136,0,981},{
+133,0,111},{10,0,132},{11,0,191},{11,0,358},{139,0,460},{7,11,319},{7,11,355},{7
+,11,763},{10,11,389},{145,11,43},{134,0,890},{134,0,1420},{136,11,557},{133,10,
+518},{133,0,444},{135,0,1787},{135,10,1852},{8,0,123},{15,0,6},{144,0,7},{6,0,
+2041},{10,11,38},{139,11,784},{136,0,932},{5,0,937},{135,0,100},{6,0,995},{4,11,
+58},{5,11,286},{6,11,319},{7,11,402},{7,11,1254},{7,11,1903},{8,11,356},{140,11,
+408},{4,11,389},{9,11,181},{9,11,255},{10,11,8},{10,11,29},{10,11,816},{11,11,
+311},{11,11,561},{12,11,67},{141,11,181},{138,0,255},{5,0,138},{4,10,934},{136,
+10,610},{4,0,965},{10,0,863},{138,0,898},{10,10,804},{138,10,832},{12,0,631},{8,
+10,96},{9,10,36},{10,10,607},{11,10,423},{11,10,442},{12,10,309},{14,10,199},{15
+,10,90},{145,10,110},{134,0,1394},{4,0,652},{8,0,320},{22,0,6},{22,0,16},{9,10,
+13},{9,10,398},{9,10,727},{10,10,75},{10,10,184},{10,10,230},{10,10,564},{10,10,
+569},{11,10,973},{12,10,70},{12,10,189},{13,10,57},{141,10,257},{6,0,897},{134,0
+,1333},{4,0,692},{133,0,321},{133,11,373},{135,0,922},{5,0,619},{133,0,698},{137
+,10,631},{5,10,345},{135,10,1016},{9,0,957},{9,0,1018},{12,0,828},{12,0,844},{12
+,0,897},{12,0,901},{12,0,943},{15,0,180},{18,0,197},{18,0,200},{18,0,213},{18,0,
+214},{146,0,226},{5,0,917},{134,0,1659},{135,0,1100},{134,0,1173},{134,0,1930},{
+5,0,251},{5,0,956},{8,0,268},{9,0,214},{146,0,142},{133,10,673},{137,10,850},{4,
+10,287},{133,10,1018},{132,11,672},{5,0,346},{5,0,711},{8,0,390},{11,11,752},{
+139,11,885},{5,10,34},{10,10,724},{12,10,444},{13,10,354},{18,10,32},{23,10,24},
+{23,10,31},{152,10,5},{4,11,710},{134,11,606},{134,0,744},{134,10,382},{133,11,
+145},{4,10,329},{7,11,884},{140,11,124},{4,11,467},{5,11,405},{134,11,544},{9,10
+,846},{138,10,827},{133,0,624},{9,11,372},{15,11,2},{19,11,10},{147,11,18},{4,11
+,387},{135,11,1288},{5,0,783},{7,0,1998},{135,0,2047},{132,10,906},{136,10,366},
+{135,11,550},{4,10,123},{4,10,649},{5,10,605},{7,10,1509},{136,10,36},{134,0,
+1125},{132,0,594},{133,10,767},{135,11,1227},{136,11,467},{4,11,576},{135,11,
+1263},{4,0,268},{7,0,1534},{135,11,1534},{4,10,273},{5,10,658},{5,11,919},{5,10,
+995},{134,11,1673},{133,0,563},{134,10,72},{135,10,1345},{4,11,82},{5,11,333},{5
+,11,904},{6,11,207},{7,11,325},{7,11,1726},{8,11,101},{10,11,778},{139,11,220},{
+5,0,37},{6,0,39},{6,0,451},{7,0,218},{7,0,667},{7,0,1166},{7,0,1687},{8,0,662},{
+16,0,2},{133,10,589},{134,0,1332},{133,11,903},{134,0,508},{5,10,117},{6,10,514}
+,{6,10,541},{7,10,1164},{7,10,1436},{8,10,220},{8,10,648},{10,10,688},{11,10,560
+},{140,11,147},{6,11,555},{135,11,485},{133,10,686},{7,0,453},{7,0,635},{7,0,796
+},{8,0,331},{9,0,330},{9,0,865},{10,0,119},{10,0,235},{11,0,111},{11,0,129},{11,
+0,240},{12,0,31},{12,0,66},{12,0,222},{12,0,269},{12,0,599},{12,0,684},{12,0,689
+},{12,0,691},{142,0,345},{135,0,1834},{4,11,705},{7,11,615},{138,11,251},{136,11
+,345},{137,0,527},{6,0,98},{7,0,702},{135,0,991},{11,0,576},{14,0,74},{7,10,196}
+,{10,10,765},{11,10,347},{11,10,552},{11,10,790},{12,10,263},{13,10,246},{13,10,
+270},{13,10,395},{14,10,176},{14,10,190},{14,10,398},{14,10,412},{15,10,32},{15,
+10,63},{16,10,88},{147,10,105},{134,11,90},{13,0,84},{141,0,122},{6,0,37},{7,0,
+299},{7,0,1666},{8,0,195},{8,0,316},{9,0,178},{9,0,276},{9,0,339},{9,0,536},{10,
+0,102},{10,0,362},{10,0,785},{11,0,55},{11,0,149},{11,0,773},{13,0,416},{13,0,
+419},{14,0,38},{14,0,41},{142,0,210},{5,10,381},{135,10,1792},{7,11,813},{12,11,
+497},{141,11,56},{7,10,616},{138,10,413},{133,0,645},{6,11,125},{135,11,1277},{
+132,0,290},{6,0,70},{7,0,1292},{10,0,762},{139,0,288},{6,10,120},{7,10,1188},{7,
+10,1710},{8,10,286},{9,10,667},{11,10,592},{139,10,730},{135,11,1784},{7,0,1315}
+,{135,11,1315},{134,0,1955},{135,10,1146},{7,0,131},{7,0,422},{8,0,210},{140,0,
+573},{4,10,352},{135,10,687},{139,0,797},{143,0,38},{14,0,179},{15,0,151},{150,0
+,11},{7,0,488},{4,10,192},{5,10,49},{6,10,200},{6,10,293},{134,10,1696},{132,0,
+936},{135,11,703},{6,11,160},{7,11,1106},{9,11,770},{10,11,618},{11,11,112},{140
+,11,413},{5,0,453},{134,0,441},{135,0,595},{132,10,650},{132,10,147},{6,0,991},{
+6,0,1182},{12,11,271},{145,11,109},{133,10,934},{140,11,221},{132,0,653},{7,0,
+505},{135,0,523},{134,0,903},{135,11,479},{7,11,304},{9,11,646},{9,11,862},{10,
+11,262},{11,11,696},{12,11,208},{15,11,79},{147,11,108},{146,0,80},{135,11,981},
+{142,0,432},{132,0,314},{137,11,152},{7,0,1368},{8,0,232},{8,0,361},{10,0,682},{
+138,0,742},{135,11,1586},{9,0,534},{4,11,434},{11,11,663},{12,11,210},{13,11,166
+},{13,11,310},{14,11,373},{147,11,43},{7,11,1091},{135,11,1765},{6,11,550},{135,
+11,652},{137,0,27},{142,0,12},{4,10,637},{5,11,553},{7,11,766},{138,11,824},{7,
+11,737},{8,11,298},{136,11,452},{7,0,736},{139,0,264},{134,0,1657},{133,11,292},
+{138,11,135},{6,0,844},{134,0,1117},{135,0,127},{9,10,867},{138,10,837},{6,0,
+1184},{134,0,1208},{134,0,1294},{136,0,364},{6,0,1415},{7,0,1334},{11,0,125},{6,
+10,170},{7,11,393},{8,10,395},{8,10,487},{10,11,603},{11,11,206},{141,10,147},{
+137,11,748},{4,11,912},{137,11,232},{4,10,535},{136,10,618},{137,0,792},{7,11,
+1973},{136,11,716},{135,11,98},{5,0,909},{9,0,849},{138,0,805},{4,0,630},{132,0,
+699},{5,11,733},{14,11,103},{150,10,23},{12,11,158},{18,11,8},{19,11,62},{20,11,
+6},{22,11,4},{23,11,2},{151,11,9},{132,0,968},{132,10,778},{132,10,46},{5,10,811
+},{6,10,1679},{6,10,1714},{135,10,2032},{6,0,1446},{7,10,1458},{9,10,407},{139,
+10,15},{7,0,206},{7,0,397},{7,0,621},{7,0,640},{8,0,124},{8,0,619},{9,0,305},{9,
+0,643},{10,0,264},{10,0,628},{11,0,40},{12,0,349},{13,0,134},{13,0,295},{14,0,
+155},{15,0,120},{18,0,105},{6,10,34},{7,10,1089},{8,10,708},{8,10,721},{9,10,363
+},{148,10,98},{4,0,262},{5,0,641},{135,0,342},{137,11,72},{4,0,99},{6,0,250},{6,
+0,346},{8,0,127},{138,0,81},{132,0,915},{5,0,75},{9,0,517},{10,0,470},{12,0,155}
+,{141,0,224},{132,10,462},{11,11,600},{11,11,670},{141,11,245},{142,0,83},{5,10,
+73},{6,10,23},{134,10,338},{6,0,1031},{139,11,923},{7,11,164},{7,11,1571},{9,11,
+107},{140,11,225},{134,0,1470},{133,0,954},{6,0,304},{8,0,418},{10,0,345},{11,0,
+341},{139,0,675},{9,0,410},{139,0,425},{4,11,27},{5,11,484},{5,11,510},{6,11,434
+},{7,11,1000},{7,11,1098},{8,11,2},{136,11,200},{134,0,734},{140,11,257},{7,10,
+725},{8,10,498},{139,10,268},{134,0,1822},{135,0,1798},{135,10,773},{132,11,460}
+,{4,11,932},{133,11,891},{134,0,14},{132,10,583},{7,10,1462},{8,11,625},{139,10,
+659},{5,0,113},{6,0,243},{6,0,1708},{7,0,1865},{11,0,161},{16,0,37},{17,0,99},{
+133,10,220},{134,11,76},{5,11,461},{135,11,1925},{140,0,69},{8,11,92},{137,11,
+221},{139,10,803},{132,10,544},{4,0,274},{134,0,922},{132,0,541},{5,0,627},{6,10
+,437},{6,10,564},{11,10,181},{141,10,183},{135,10,1192},{7,0,166},{132,11,763},{
+133,11,253},{134,0,849},{9,11,73},{10,11,110},{14,11,185},{145,11,119},{5,11,212
+},{12,11,35},{141,11,382},{133,0,717},{137,0,304},{136,0,600},{133,0,654},{6,0,
+273},{10,0,188},{13,0,377},{146,0,77},{4,10,790},{5,10,273},{134,10,394},{132,0,
+543},{135,0,410},{11,0,98},{11,0,524},{141,0,87},{132,0,941},{135,11,1175},{4,0,
+250},{7,0,1612},{11,0,186},{12,0,133},{6,10,127},{7,10,1511},{8,10,613},{12,10,
+495},{12,10,586},{12,10,660},{12,10,668},{14,10,385},{15,10,118},{17,10,20},{146
+,10,98},{6,0,1785},{133,11,816},{134,0,1339},{7,0,961},{7,0,1085},{7,0,1727},{8,
+0,462},{6,10,230},{135,11,1727},{9,0,636},{135,10,1954},{132,0,780},{5,11,869},{
+5,11,968},{6,11,1626},{8,11,734},{136,11,784},{4,11,542},{6,11,1716},{6,11,1727}
+,{7,11,1082},{7,11,1545},{8,11,56},{8,11,118},{8,11,412},{8,11,564},{9,11,888},{
+9,11,908},{10,11,50},{10,11,423},{11,11,685},{11,11,697},{11,11,933},{12,11,299}
+,{13,11,126},{13,11,136},{13,11,170},{141,11,190},{134,11,226},{4,11,232},{9,11,
+202},{10,11,474},{140,11,433},{137,11,500},{5,0,529},{136,10,68},{132,10,654},{4
+,10,156},{7,10,998},{7,10,1045},{7,10,1860},{9,10,48},{9,10,692},{11,10,419},{
+139,10,602},{7,0,1276},{8,0,474},{9,0,652},{6,11,108},{7,11,1003},{7,11,1181},{
+136,11,343},{7,11,1264},{7,11,1678},{11,11,945},{12,11,341},{12,11,471},{140,11,
+569},{134,11,1712},{5,0,948},{12,0,468},{19,0,96},{148,0,24},{4,11,133},{7,11,
+711},{7,11,1298},{7,11,1585},{135,11,1929},{6,0,753},{140,0,657},{139,0,941},{6,
+11,99},{7,11,1808},{145,11,57},{6,11,574},{7,11,428},{7,11,1250},{10,11,669},{11
+,11,485},{11,11,840},{12,11,300},{142,11,250},{4,0,532},{5,0,706},{135,0,662},{5
+,0,837},{6,0,1651},{139,0,985},{7,0,1861},{9,10,197},{10,10,300},{12,10,473},{13
+,10,90},{141,10,405},{137,11,252},{6,11,323},{135,11,1564},{4,0,330},{4,0,863},{
+7,0,933},{7,0,2012},{8,0,292},{7,11,461},{8,11,775},{138,11,435},{132,10,606},{4
+,11,655},{7,11,850},{17,11,75},{146,11,137},{135,0,767},{7,10,1978},{136,10,676}
+,{132,0,641},{135,11,1559},{134,0,1233},{137,0,242},{17,0,114},{4,10,361},{133,
+10,315},{137,0,883},{132,10,461},{138,0,274},{134,0,2008},{134,0,1794},{4,0,703}
+,{135,0,207},{12,0,285},{132,10,472},{132,0,571},{5,0,873},{5,0,960},{8,0,823},{
+9,0,881},{136,11,577},{7,0,617},{10,0,498},{11,0,501},{12,0,16},{140,0,150},{138
+,10,747},{132,0,431},{133,10,155},{11,0,283},{11,0,567},{7,10,163},{8,10,319},{9
+,10,402},{10,10,24},{10,10,681},{11,10,200},{12,10,253},{12,10,410},{142,10,219}
+,{4,11,413},{5,11,677},{8,11,432},{140,11,280},{9,0,401},{5,10,475},{7,10,1780},
+{11,10,297},{11,10,558},{14,10,322},{147,10,76},{6,0,781},{9,0,134},{10,0,2},{10
+,0,27},{10,0,333},{11,0,722},{143,0,1},{5,0,33},{6,0,470},{139,0,424},{135,0,
+2006},{12,0,783},{135,10,1956},{136,0,274},{135,0,1882},{132,0,794},{135,0,1848}
+,{5,10,944},{134,10,1769},{6,0,47},{7,0,90},{7,0,664},{7,0,830},{7,0,1380},{7,0,
+2025},{8,0,448},{136,0,828},{132,10,144},{134,0,1199},{4,11,395},{139,11,762},{
+135,11,1504},{9,0,417},{137,0,493},{9,11,174},{10,11,164},{11,11,440},{11,11,841
+},{143,11,98},{134,11,426},{139,11,1002},{134,0,295},{134,0,816},{6,10,247},{137
+,10,555},{133,0,1019},{4,0,620},{5,11,476},{10,10,280},{138,10,797},{139,0,464},
+{5,11,76},{6,11,458},{6,11,497},{7,11,764},{7,11,868},{9,11,658},{10,11,594},{11
+,11,173},{11,11,566},{12,11,20},{12,11,338},{141,11,200},{134,0,208},{4,11,526},
+{7,11,1029},{135,11,1054},{132,11,636},{6,11,233},{7,11,660},{7,11,1124},{17,11,
+31},{19,11,22},{151,11,14},{10,0,442},{133,10,428},{10,0,930},{140,0,778},{6,0,
+68},{7,0,448},{7,0,1629},{7,0,1769},{7,0,1813},{8,0,442},{8,0,516},{9,0,710},{10
+,0,282},{10,0,722},{7,10,1717},{138,10,546},{134,0,1128},{11,0,844},{12,0,104},{
+140,0,625},{4,11,432},{135,11,824},{138,10,189},{133,0,787},{133,10,99},{4,11,
+279},{7,11,301},{137,11,362},{8,0,491},{4,10,397},{136,10,555},{4,11,178},{133,
+11,399},{134,0,711},{144,0,9},{4,0,403},{5,0,441},{7,0,450},{10,0,840},{11,0,101
+},{12,0,193},{141,0,430},{135,11,1246},{12,10,398},{20,10,39},{21,10,11},{150,10
+,41},{4,10,485},{7,10,353},{135,10,1523},{6,10,366},{7,10,1384},{7,10,1601},{135
+,11,1912},{7,0,396},{10,0,160},{135,11,396},{137,10,282},{134,11,1692},{4,10,157
+},{5,10,471},{6,11,202},{10,11,448},{11,11,208},{12,11,360},{17,11,117},{17,11,
+118},{18,11,27},{148,11,67},{133,0,679},{137,0,326},{136,10,116},{7,11,872},{10,
+11,516},{139,11,167},{132,11,224},{5,11,546},{7,11,35},{8,11,11},{8,11,12},{9,11
+,315},{9,11,533},{10,11,802},{11,11,166},{12,11,525},{142,11,243},{7,0,1128},{
+135,11,1920},{5,11,241},{8,11,242},{9,11,451},{10,11,667},{11,11,598},{140,11,
+429},{6,0,737},{5,10,160},{7,10,363},{7,10,589},{10,10,170},{141,10,55},{135,0,
+1796},{142,11,254},{4,0,574},{7,0,350},{7,0,1024},{8,0,338},{9,0,677},{138,0,808
+},{134,0,1096},{137,11,516},{7,0,405},{10,0,491},{4,10,108},{4,11,366},{139,10,
+498},{11,11,337},{142,11,303},{134,11,1736},{7,0,1081},{140,11,364},{7,10,1005},
+{140,10,609},{7,0,1676},{4,10,895},{133,10,772},{135,0,2037},{6,0,1207},{11,11,
+916},{142,11,419},{14,11,140},{148,11,41},{6,11,331},{136,11,623},{9,0,944},{9,0
+,969},{9,0,1022},{12,0,913},{12,0,936},{15,0,177},{15,0,193},{4,10,926},{133,10,
+983},{5,0,354},{135,11,506},{8,0,598},{9,0,664},{138,0,441},{4,11,640},{133,11,
+513},{137,0,297},{132,10,538},{6,10,294},{7,10,1267},{136,10,624},{7,0,1772},{7,
+11,1888},{8,11,289},{11,11,45},{12,11,278},{140,11,537},{135,10,1325},{138,0,751
+},{141,0,37},{134,0,1828},{132,10,757},{132,11,394},{6,0,257},{135,0,1522},{4,0,
+582},{9,0,191},{135,11,1931},{7,11,574},{7,11,1719},{137,11,145},{132,11,658},{
+10,0,790},{132,11,369},{9,11,781},{10,11,144},{11,11,385},{13,11,161},{13,11,228
+},{13,11,268},{148,11,107},{8,0,469},{10,0,47},{136,11,374},{6,0,306},{7,0,1140}
+,{7,0,1340},{8,0,133},{138,0,449},{139,0,1011},{7,10,1875},{139,10,124},{4,11,
+344},{6,11,498},{139,11,323},{137,0,299},{132,0,837},{133,11,906},{5,0,329},{8,0
+,260},{138,0,10},{134,0,1320},{4,0,657},{146,0,158},{135,0,1191},{152,0,7},{6,0,
+1939},{8,0,974},{138,0,996},{135,0,1665},{11,11,126},{139,11,287},{143,0,8},{14,
+11,149},{14,11,399},{143,11,57},{5,0,66},{7,0,1896},{136,0,288},{7,0,175},{10,0,
+494},{5,10,150},{8,10,603},{9,10,593},{9,10,634},{10,10,173},{11,10,462},{11,10,
+515},{13,10,216},{13,10,288},{142,10,400},{134,0,1643},{136,11,21},{4,0,21},{5,0
+,91},{5,0,648},{5,0,750},{5,0,781},{6,0,54},{6,0,112},{6,0,402},{6,0,1732},{7,0,
+315},{7,0,749},{7,0,1427},{7,0,1900},{9,0,78},{9,0,508},{10,0,611},{10,0,811},{
+11,0,510},{11,0,728},{13,0,36},{14,0,39},{16,0,83},{17,0,124},{148,0,30},{4,0,
+668},{136,0,570},{10,0,322},{10,0,719},{139,0,407},{135,11,1381},{136,11,193},{
+12,10,108},{141,10,291},{132,11,616},{136,11,692},{8,0,125},{8,0,369},{8,0,524},
+{10,0,486},{11,0,13},{11,0,381},{11,0,736},{11,0,766},{11,0,845},{13,0,114},{13,
+0,292},{142,0,47},{134,0,1247},{6,0,1684},{6,0,1731},{7,0,356},{8,0,54},{8,0,221
+},{9,0,225},{9,0,356},{10,0,77},{10,0,446},{10,0,731},{12,0,404},{141,0,491},{
+135,10,1777},{4,11,305},{4,10,493},{144,10,55},{4,0,951},{6,0,1809},{6,0,1849},{
+8,0,846},{8,0,866},{8,0,899},{10,0,896},{12,0,694},{142,0,468},{5,11,214},{7,11,
+603},{8,11,611},{9,11,686},{10,11,88},{11,11,459},{11,11,496},{12,11,463},{12,11
+,590},{13,11,0},{142,11,214},{132,0,411},{4,0,80},{133,0,44},{140,11,74},{143,0,
+31},{7,0,669},{6,10,568},{7,10,1804},{8,10,362},{8,10,410},{8,10,830},{9,10,514}
+,{11,10,649},{142,10,157},{7,0,673},{134,11,1703},{132,10,625},{134,0,1303},{5,0
+,299},{135,0,1083},{138,0,704},{6,0,275},{7,0,408},{6,10,158},{7,10,129},{7,10,
+181},{8,10,276},{8,10,377},{10,10,523},{11,10,816},{12,10,455},{13,10,303},{142,
+10,135},{4,0,219},{7,0,367},{7,0,1713},{7,0,1761},{9,0,86},{9,0,537},{10,0,165},
+{12,0,219},{140,0,561},{8,0,216},{4,10,1},{4,11,737},{6,11,317},{7,10,1143},{7,
+10,1463},{9,10,207},{9,10,390},{9,10,467},{10,11,98},{11,11,294},{11,10,836},{12
+,11,60},{12,11,437},{13,11,64},{13,11,380},{142,11,430},{6,11,1758},{8,11,520},{
+9,11,345},{9,11,403},{142,11,350},{5,11,47},{10,11,242},{138,11,579},{5,11,139},
+{7,11,1168},{138,11,539},{135,0,1319},{4,10,295},{4,10,723},{5,10,895},{7,10,
+1031},{8,10,199},{8,10,340},{9,10,153},{9,10,215},{10,10,21},{10,10,59},{10,10,
+80},{10,10,224},{10,10,838},{11,10,229},{11,10,652},{12,10,192},{13,10,146},{142
+,10,91},{140,0,428},{137,10,51},{133,0,514},{5,10,309},{140,10,211},{6,0,1010},{
+5,10,125},{8,10,77},{138,10,15},{4,0,55},{5,0,301},{6,0,571},{142,0,49},{146,0,
+102},{136,11,370},{4,11,107},{7,11,613},{8,11,358},{8,11,439},{8,11,504},{9,11,
+501},{10,11,383},{139,11,477},{132,11,229},{133,0,364},{133,10,439},{4,11,903},{
+135,11,1816},{11,0,379},{140,10,76},{4,0,76},{4,0,971},{7,0,1550},{9,0,306},{9,0
+,430},{9,0,663},{10,0,683},{10,0,921},{11,0,427},{11,0,753},{12,0,334},{12,0,442
+},{14,0,258},{14,0,366},{143,0,131},{137,0,52},{4,11,47},{6,11,373},{7,11,452},{
+7,11,543},{7,11,1714},{7,11,1856},{9,11,6},{11,11,257},{139,11,391},{4,10,8},{7,
+10,1152},{7,10,1153},{7,10,1715},{9,10,374},{10,10,478},{139,10,648},{4,11,785},
+{133,11,368},{135,10,1099},{135,11,860},{5,11,980},{134,11,1754},{134,0,1258},{6
+,0,1058},{6,0,1359},{7,11,536},{7,11,1331},{136,11,143},{4,0,656},{135,0,779},{
+136,10,87},{5,11,19},{6,11,533},{146,11,126},{7,0,144},{138,10,438},{5,11,395},{
+5,11,951},{134,11,1776},{135,0,1373},{7,0,554},{7,0,605},{141,0,10},{4,10,69},{5
+,10,122},{9,10,656},{138,10,464},{5,10,849},{134,10,1633},{5,0,838},{5,0,841},{
+134,0,1649},{133,0,1012},{139,10,499},{7,10,476},{7,10,1592},{138,10,87},{6,0,
+251},{7,0,365},{7,0,1357},{7,0,1497},{8,0,154},{141,0,281},{132,11,441},{132,11,
+695},{7,11,497},{9,11,387},{147,11,81},{133,0,340},{14,10,283},{142,11,283},{134
+,0,810},{135,11,1894},{139,0,495},{5,11,284},{6,11,49},{6,11,350},{7,11,1},{7,11
+,377},{7,11,1693},{8,11,18},{8,11,678},{9,11,161},{9,11,585},{9,11,671},{9,11,
+839},{11,11,912},{141,11,427},{5,10,859},{7,10,1160},{8,10,107},{9,10,291},{9,10
+,439},{10,10,663},{11,10,609},{140,10,197},{8,0,261},{9,0,144},{9,0,466},{10,0,
+370},{12,0,470},{13,0,144},{142,0,348},{137,0,897},{6,0,248},{9,0,546},{10,0,535
+},{11,0,681},{141,0,135},{4,0,358},{135,0,1496},{134,0,567},{136,0,445},{4,10,
+117},{6,10,372},{7,10,1905},{142,10,323},{4,10,722},{139,10,471},{6,0,697},{134,
+0,996},{7,11,2007},{9,11,101},{9,11,450},{10,11,66},{10,11,842},{11,11,536},{140
+,11,587},{132,0,577},{134,0,1336},{9,10,5},{12,10,216},{12,10,294},{12,10,298},{
+12,10,400},{12,10,518},{13,10,229},{143,10,139},{6,0,174},{138,0,917},{134,10,
+1774},{5,10,12},{7,10,375},{9,10,88},{9,10,438},{11,11,62},{139,10,270},{134,11,
+1766},{6,11,0},{7,11,84},{7,10,816},{7,10,1241},{9,10,283},{9,10,520},{10,10,213
+},{10,10,307},{10,10,463},{10,10,671},{10,10,746},{11,10,401},{11,10,794},{11,11
+,895},{12,10,517},{17,11,11},{18,10,107},{147,10,115},{5,0,878},{133,0,972},{6,
+11,1665},{7,11,256},{7,11,1388},{138,11,499},{4,10,258},{136,10,639},{4,11,22},{
+5,11,10},{6,10,22},{7,11,848},{7,10,903},{7,10,1963},{8,11,97},{138,10,577},{5,
+10,681},{136,10,782},{133,11,481},{132,0,351},{4,10,664},{5,10,804},{139,10,1013
+},{6,11,134},{7,11,437},{7,11,959},{9,11,37},{14,11,285},{14,11,371},{144,11,60}
+,{7,11,486},{8,11,155},{11,11,93},{140,11,164},{132,0,286},{7,0,438},{7,0,627},{
+7,0,1516},{8,0,40},{9,0,56},{9,0,294},{10,0,30},{11,0,969},{11,0,995},{146,0,148
+},{5,11,591},{135,11,337},{134,0,1950},{133,10,32},{138,11,500},{5,11,380},{5,11
+,650},{136,11,310},{4,11,364},{7,11,1156},{7,11,1187},{137,11,409},{4,0,738},{
+134,11,482},{4,11,781},{6,11,487},{7,11,926},{8,11,263},{139,11,500},{135,11,418
+},{6,0,2047},{10,0,969},{4,10,289},{7,10,629},{7,10,1698},{7,10,1711},{140,10,
+215},{6,10,450},{136,10,109},{134,0,818},{136,10,705},{133,0,866},{4,11,94},{135
+,11,1265},{132,11,417},{134,0,1467},{135,10,1238},{4,0,972},{6,0,1851},{134,0,
+1857},{134,0,355},{133,0,116},{132,0,457},{135,11,1411},{4,11,408},{4,11,741},{
+135,11,500},{134,10,26},{142,11,137},{5,0,527},{6,0,189},{7,0,859},{136,0,267},{
+11,0,104},{11,0,554},{15,0,60},{143,0,125},{134,0,1613},{4,10,414},{5,10,467},{9
+,10,654},{10,10,451},{12,10,59},{141,10,375},{135,10,17},{134,0,116},{135,11,541
+},{135,10,955},{6,11,73},{135,11,177},{133,11,576},{134,0,886},{133,0,487},{4,0,
+86},{5,0,667},{5,0,753},{6,0,316},{6,0,455},{135,0,946},{142,11,231},{150,0,45},
+{134,0,863},{134,0,1953},{6,10,280},{10,10,502},{11,10,344},{140,10,38},{4,0,79}
+,{7,0,1773},{10,0,450},{11,0,589},{13,0,332},{13,0,493},{14,0,183},{14,0,334},{
+14,0,362},{14,0,368},{14,0,376},{14,0,379},{19,0,90},{19,0,103},{19,0,127},{148,
+0,90},{5,10,45},{7,10,1161},{11,10,448},{11,10,880},{13,10,139},{13,10,407},{15,
+10,16},{17,10,95},{18,10,66},{18,10,88},{18,10,123},{149,10,7},{136,10,777},{4,
+10,410},{135,10,521},{135,10,1778},{135,11,538},{142,0,381},{133,11,413},{134,0,
+1142},{6,0,1189},{136,11,495},{5,0,663},{6,0,1962},{134,0,2003},{7,11,54},{8,11,
+312},{10,11,191},{10,11,614},{140,11,567},{132,10,436},{133,0,846},{10,0,528},{
+11,0,504},{7,10,1587},{135,10,1707},{5,0,378},{8,0,465},{9,0,286},{10,0,185},{10
+,0,562},{10,0,635},{11,0,31},{11,0,393},{13,0,312},{18,0,65},{18,0,96},{147,0,89
+},{7,0,899},{14,0,325},{6,11,468},{7,11,567},{7,11,1478},{8,11,530},{142,11,290}
+,{7,0,1880},{9,0,680},{139,0,798},{134,0,1770},{132,0,648},{150,11,35},{5,0,945}
+,{6,0,1656},{6,0,1787},{7,0,167},{8,0,824},{9,0,391},{10,0,375},{139,0,185},{6,
+11,484},{135,11,822},{134,0,2046},{7,0,1645},{8,0,352},{137,0,249},{132,0,152},{
+6,0,611},{135,0,1733},{6,11,1724},{135,11,2022},{133,0,1006},{141,11,96},{5,0,
+420},{135,0,1449},{146,11,149},{135,0,832},{135,10,663},{133,0,351},{5,0,40},{7,
+0,598},{7,0,1638},{8,0,78},{9,0,166},{9,0,640},{9,0,685},{9,0,773},{11,0,215},{
+13,0,65},{14,0,172},{14,0,317},{145,0,6},{8,0,60},{9,0,343},{139,0,769},{134,0,
+1354},{132,0,724},{137,0,745},{132,11,474},{7,0,1951},{8,0,765},{8,0,772},{140,0
+,671},{7,0,108},{8,0,219},{8,0,388},{9,0,775},{11,0,275},{140,0,464},{137,0,639}
+,{135,10,503},{133,11,366},{5,0,15},{6,0,56},{7,0,1758},{8,0,500},{9,0,730},{11,
+0,331},{13,0,150},{14,0,282},{5,11,305},{9,11,560},{141,11,208},{4,10,113},{5,10
+,163},{5,10,735},{7,10,1009},{9,10,9},{9,10,771},{12,10,90},{13,10,138},{13,10,
+410},{143,10,128},{4,10,324},{138,10,104},{135,11,466},{142,11,27},{134,0,1886},
+{5,0,205},{6,0,438},{9,0,711},{4,11,480},{6,11,167},{6,11,302},{6,11,1642},{7,11
+,130},{7,11,656},{7,11,837},{7,11,1547},{7,11,1657},{8,11,429},{9,11,228},{10,11
+,643},{13,11,289},{13,11,343},{147,11,101},{134,0,865},{6,0,2025},{136,0,965},{7
+,11,278},{10,11,739},{11,11,708},{141,11,348},{133,0,534},{135,11,1922},{137,0,
+691},{4,10,935},{133,10,823},{6,0,443},{9,0,237},{9,0,571},{9,0,695},{10,0,139},
+{11,0,715},{12,0,417},{141,0,421},{5,10,269},{7,10,434},{7,10,891},{8,10,339},{9
+,10,702},{11,10,594},{11,10,718},{145,10,100},{6,0,1555},{7,0,878},{9,10,485},{
+141,10,264},{134,10,1713},{7,10,1810},{11,10,866},{12,10,103},{141,10,495},{135,
+10,900},{6,0,1410},{9,11,316},{139,11,256},{4,0,995},{135,0,1033},{132,0,578},{
+10,0,881},{12,0,740},{12,0,743},{140,0,759},{132,0,822},{133,0,923},{142,10,143}
+,{135,11,1696},{6,11,363},{7,11,1955},{136,11,725},{132,0,924},{133,0,665},{135,
+10,2029},{135,0,1901},{4,0,265},{6,0,1092},{6,0,1417},{7,0,807},{135,0,950},{5,0
+,93},{12,0,267},{141,0,498},{135,0,1451},{5,11,813},{135,11,2046},{5,10,625},{
+135,10,1617},{135,0,747},{6,0,788},{137,0,828},{7,0,184},{11,0,307},{11,0,400},{
+15,0,130},{5,11,712},{7,11,1855},{8,10,425},{8,10,693},{9,10,720},{10,10,380},{
+10,10,638},{11,11,17},{11,10,473},{12,10,61},{13,11,321},{144,11,67},{135,0,198}
+,{6,11,320},{7,11,781},{7,11,1921},{9,11,55},{10,11,186},{10,11,273},{10,11,664}
+,{10,11,801},{11,11,996},{11,11,997},{13,11,157},{142,11,170},{136,11,271},{135,
+0,994},{7,11,103},{7,11,863},{11,11,184},{14,11,299},{145,11,62},{11,10,551},{
+142,10,159},{5,0,233},{5,0,320},{6,0,140},{8,0,295},{8,0,615},{136,11,615},{133,
+0,978},{4,0,905},{6,0,1701},{137,0,843},{132,10,168},{4,0,974},{8,0,850},{12,0,
+709},{12,0,768},{140,0,786},{135,10,91},{152,0,6},{138,10,532},{135,10,1884},{
+132,0,509},{6,0,1307},{135,0,273},{5,11,77},{7,11,1455},{10,11,843},{19,11,73},{
+150,11,5},{132,11,458},{135,11,1420},{6,11,109},{138,11,382},{6,0,201},{6,11,330
+},{7,10,70},{7,11,1084},{10,10,240},{11,11,142},{147,10,93},{7,0,1041},{140,11,
+328},{133,11,354},{134,0,1040},{133,0,693},{134,0,774},{139,0,234},{132,0,336},{
+7,0,1399},{139,10,392},{20,0,22},{148,11,22},{5,0,802},{7,0,2021},{136,0,805},{5
+,0,167},{5,0,899},{6,0,410},{137,0,777},{137,0,789},{134,0,1705},{7,10,655},{135
+,10,1844},{4,10,145},{6,10,176},{7,10,395},{137,10,562},{132,10,501},{135,0,10},
+{5,0,11},{6,0,117},{6,0,485},{7,0,1133},{9,0,582},{9,0,594},{10,0,82},{11,0,21},
+{11,0,818},{12,0,535},{13,0,86},{20,0,91},{23,0,13},{134,10,509},{4,0,264},{7,0,
+1067},{8,0,204},{8,0,385},{139,0,953},{139,11,737},{138,0,56},{134,0,1917},{133,
+0,470},{10,11,657},{14,11,297},{142,11,361},{135,11,412},{7,0,1198},{7,11,1198},
+{8,11,556},{14,11,123},{14,11,192},{143,11,27},{7,11,1985},{14,11,146},{15,11,42
+},{16,11,23},{17,11,86},{146,11,17},{11,0,1015},{136,11,122},{4,10,114},{9,10,
+492},{13,10,462},{142,10,215},{4,10,77},{5,10,361},{6,10,139},{6,10,401},{6,10,
+404},{7,10,413},{7,10,715},{7,10,1716},{11,10,279},{12,10,179},{12,10,258},{13,
+10,244},{142,10,358},{134,10,1717},{7,10,1061},{8,10,82},{11,10,250},{12,10,420}
+,{141,10,184},{133,0,715},{135,10,724},{9,0,919},{9,0,922},{9,0,927},{9,0,933},{
+9,0,962},{9,0,1000},{9,0,1002},{9,0,1021},{12,0,890},{12,0,907},{12,0,930},{15,0
+,207},{15,0,228},{15,0,238},{149,0,61},{8,0,794},{9,0,400},{10,0,298},{142,0,228
+},{5,11,430},{5,11,932},{6,11,131},{7,11,417},{9,11,522},{11,11,314},{141,11,390
+},{132,0,867},{8,0,724},{132,11,507},{137,11,261},{4,11,343},{133,11,511},{6,0,
+190},{7,0,768},{135,0,1170},{6,10,513},{135,10,1052},{7,11,455},{138,11,591},{
+134,0,1066},{137,10,899},{14,0,67},{147,0,60},{4,0,948},{18,0,174},{146,0,176},{
+135,0,1023},{7,10,1417},{12,10,382},{17,10,48},{152,10,12},{134,11,575},{132,0,
+764},{6,10,545},{7,10,565},{7,10,1669},{10,10,114},{11,10,642},{140,10,618},{6,0
+,137},{9,0,75},{9,0,253},{10,0,194},{138,0,444},{4,0,756},{133,10,5},{8,0,1008},
+{135,10,192},{132,0,842},{11,0,643},{12,0,115},{136,10,763},{139,0,67},{133,10,
+759},{4,0,821},{5,0,760},{7,0,542},{8,0,135},{8,0,496},{135,11,580},{7,10,370},{
+7,10,1007},{7,10,1177},{135,10,1565},{135,10,1237},{140,0,736},{7,0,319},{7,0,
+355},{7,0,763},{10,0,389},{145,0,43},{8,11,333},{138,11,182},{4,10,87},{5,10,250
+},{141,10,298},{138,0,786},{134,0,2044},{8,11,330},{140,11,477},{135,11,1338},{
+132,11,125},{134,0,1030},{134,0,1083},{132,11,721},{135,10,814},{7,11,776},{8,11
+,145},{147,11,56},{134,0,1226},{4,10,57},{7,10,1195},{7,10,1438},{7,10,1548},{7,
+10,1835},{7,10,1904},{9,10,757},{10,10,604},{139,10,519},{7,11,792},{8,11,147},{
+10,11,821},{139,11,1021},{137,11,797},{4,0,58},{5,0,286},{6,0,319},{7,0,402},{7,
+0,1254},{7,0,1903},{8,0,356},{140,0,408},{4,0,389},{4,0,815},{9,0,181},{9,0,255}
+,{10,0,8},{10,0,29},{10,0,816},{11,0,311},{11,0,561},{12,0,67},{141,0,181},{7,11
+,1472},{135,11,1554},{7,11,1071},{7,11,1541},{7,11,1767},{7,11,1806},{7,11,1999}
+,{9,11,248},{10,11,400},{11,11,162},{11,11,178},{11,11,242},{12,11,605},{15,11,
+26},{144,11,44},{5,11,168},{5,11,930},{8,11,74},{9,11,623},{12,11,500},{12,11,
+579},{13,11,41},{143,11,93},{6,11,220},{7,11,1101},{141,11,105},{5,0,474},{7,0,
+507},{4,10,209},{7,11,507},{135,10,902},{132,0,427},{6,0,413},{7,10,335},{7,10,
+1437},{7,10,1668},{8,10,553},{8,10,652},{8,10,656},{9,10,558},{11,10,743},{149,
+10,18},{132,0,730},{6,11,19},{7,11,1413},{139,11,428},{133,0,373},{132,10,559},{
+7,11,96},{8,11,401},{137,11,896},{7,0,799},{7,0,1972},{5,10,1017},{138,10,511},{
+135,0,1793},{7,11,1961},{7,11,1965},{8,11,702},{136,11,750},{8,11,150},{8,11,737
+},{140,11,366},{132,0,322},{133,10,709},{8,11,800},{9,11,148},{9,11,872},{9,11,
+890},{11,11,309},{11,11,1001},{13,11,267},{141,11,323},{134,10,1745},{7,0,290},{
+136,10,206},{7,0,1651},{145,0,89},{139,0,2},{132,0,672},{6,0,1860},{8,0,905},{10
+,0,844},{10,0,846},{10,0,858},{12,0,699},{12,0,746},{140,0,772},{135,11,424},{
+133,11,547},{133,0,737},{5,11,490},{6,11,615},{6,11,620},{135,11,683},{6,0,746},
+{134,0,1612},{132,10,776},{9,11,385},{149,11,17},{133,0,145},{135,10,1272},{7,0,
+884},{140,0,124},{4,0,387},{135,0,1288},{5,11,133},{136,10,406},{136,11,187},{6,
+0,679},{8,11,8},{138,11,0},{135,0,550},{135,11,798},{136,11,685},{7,11,1086},{
+145,11,46},{8,10,175},{10,10,168},{138,10,573},{135,0,1305},{4,0,576},{135,0,
+1263},{6,0,686},{134,0,1563},{134,0,607},{5,0,919},{134,0,1673},{148,0,37},{8,11
+,774},{10,11,670},{140,11,51},{133,10,784},{139,10,882},{4,0,82},{5,0,333},{5,0,
+904},{6,0,207},{7,0,325},{7,0,1726},{8,0,101},{10,0,778},{139,0,220},{135,11,371
+},{132,0,958},{133,0,903},{4,11,127},{5,11,350},{6,11,356},{8,11,426},{9,11,572}
+,{10,11,247},{139,11,312},{140,0,147},{6,11,59},{7,11,885},{9,11,603},{141,11,
+397},{10,0,367},{9,10,14},{9,10,441},{139,10,9},{11,10,966},{12,10,287},{13,10,
+342},{13,10,402},{15,10,110},{143,10,163},{134,0,690},{132,0,705},{9,0,651},{11,
+0,971},{13,0,273},{7,10,1428},{7,10,1640},{7,10,1867},{9,10,169},{9,10,182},{9,
+10,367},{9,10,478},{9,10,506},{9,10,551},{9,10,557},{9,10,648},{9,10,697},{9,10,
+705},{9,10,725},{9,10,787},{9,10,794},{10,10,198},{10,10,214},{10,10,267},{10,10
+,275},{10,10,456},{10,10,551},{10,10,561},{10,10,613},{10,10,627},{10,10,668},{
+10,10,675},{10,10,691},{10,10,695},{10,10,707},{10,10,715},{11,10,183},{11,10,
+201},{11,10,262},{11,10,352},{11,10,439},{11,10,493},{11,10,572},{11,10,591},{11
+,10,608},{11,10,611},{11,10,646},{11,10,674},{11,10,711},{11,10,751},{11,10,761}
+,{11,10,776},{11,10,785},{11,10,850},{11,10,853},{11,10,862},{11,10,865},{11,10,
+868},{11,10,875},{11,10,898},{11,10,902},{11,10,903},{11,10,910},{11,10,932},{11
+,10,942},{11,10,957},{11,10,967},{11,10,972},{12,10,148},{12,10,195},{12,10,220}
+,{12,10,237},{12,10,318},{12,10,339},{12,10,393},{12,10,445},{12,10,450},{12,10,
+474},{12,10,505},{12,10,509},{12,10,533},{12,10,591},{12,10,594},{12,10,597},{12
+,10,621},{12,10,633},{12,10,642},{13,10,59},{13,10,60},{13,10,145},{13,10,239},{
+13,10,250},{13,10,329},{13,10,344},{13,10,365},{13,10,372},{13,10,387},{13,10,
+403},{13,10,414},{13,10,456},{13,10,470},{13,10,478},{13,10,483},{13,10,489},{14
+,10,55},{14,10,57},{14,10,81},{14,10,90},{14,10,148},{14,10,239},{14,10,266},{14
+,10,321},{14,10,326},{14,10,327},{14,10,330},{14,10,347},{14,10,355},{14,10,401}
+,{14,10,404},{14,10,411},{14,10,414},{14,10,416},{14,10,420},{15,10,61},{15,10,
+74},{15,10,87},{15,10,88},{15,10,94},{15,10,96},{15,10,116},{15,10,149},{15,10,
+154},{16,10,50},{16,10,63},{16,10,73},{17,10,2},{17,10,66},{17,10,92},{17,10,103
+},{17,10,112},{17,10,120},{18,10,50},{18,10,54},{18,10,82},{18,10,86},{18,10,90}
+,{18,10,111},{18,10,115},{18,10,156},{19,10,40},{19,10,79},{20,10,78},{149,10,22
+},{7,0,887},{5,10,161},{135,10,839},{142,11,98},{134,0,90},{138,11,356},{135,11,
+441},{6,11,111},{7,11,4},{8,11,163},{8,11,776},{138,11,566},{134,0,908},{134,0,
+1261},{7,0,813},{12,0,497},{141,0,56},{134,0,1235},{135,0,429},{135,11,1994},{
+138,0,904},{6,0,125},{7,0,1277},{137,0,772},{151,0,12},{4,0,841},{5,0,386},{133,
+11,386},{5,11,297},{135,11,1038},{6,0,860},{6,0,1069},{135,11,309},{136,0,946},{
+135,10,1814},{141,11,418},{136,11,363},{10,0,768},{139,0,787},{22,11,30},{150,11
+,33},{6,0,160},{7,0,1106},{9,0,770},{11,0,112},{140,0,413},{11,11,216},{139,11,
+340},{136,10,139},{135,11,1390},{135,11,808},{132,11,280},{12,0,271},{17,0,109},
+{7,10,643},{136,10,236},{140,11,54},{4,11,421},{133,11,548},{11,0,719},{12,0,36}
+,{141,0,337},{7,0,581},{9,0,644},{137,0,699},{11,11,511},{13,11,394},{14,11,298}
+,{14,11,318},{146,11,103},{7,0,304},{9,0,646},{9,0,862},{11,0,696},{12,0,208},{
+15,0,79},{147,0,108},{4,0,631},{7,0,1126},{135,0,1536},{135,11,1527},{8,0,880},{
+10,0,869},{138,0,913},{7,0,1513},{5,10,54},{6,11,254},{9,11,109},{138,11,103},{
+135,0,981},{133,11,729},{132,10,744},{132,0,434},{134,0,550},{7,0,930},{10,0,476
+},{13,0,452},{19,0,104},{6,11,1630},{10,10,402},{146,10,55},{5,0,553},{138,0,824
+},{136,0,452},{8,0,151},{137,10,624},{132,10,572},{132,0,772},{133,11,671},{133,
+0,292},{138,0,135},{132,11,889},{140,11,207},{9,0,504},{6,10,43},{7,10,38},{8,10
+,248},{138,10,513},{6,0,1089},{135,11,1910},{4,11,627},{133,11,775},{135,0,783},
+{133,10,766},{133,10,363},{7,0,387},{135,11,387},{7,0,393},{10,0,603},{11,0,206}
+,{7,11,202},{11,11,362},{11,11,948},{140,11,388},{6,11,507},{7,11,451},{8,11,389
+},{12,11,490},{13,11,16},{13,11,215},{13,11,351},{18,11,132},{147,11,125},{4,0,
+912},{9,0,232},{135,11,841},{6,10,258},{140,10,409},{5,10,249},{148,10,82},{136,
+11,566},{6,0,977},{135,11,1214},{7,0,1973},{136,0,716},{135,0,98},{133,0,733},{5
+,11,912},{134,11,1695},{5,10,393},{6,10,378},{7,10,1981},{9,10,32},{9,10,591},{
+10,10,685},{10,10,741},{142,10,382},{133,10,788},{10,0,19},{11,0,911},{7,10,1968
+},{141,10,509},{5,0,668},{5,11,236},{6,11,572},{8,11,492},{11,11,618},{144,11,56
+},{135,11,1789},{4,0,360},{5,0,635},{5,0,700},{5,10,58},{5,10,171},{5,10,683},{6
+,10,291},{6,10,566},{7,10,1650},{11,10,523},{12,10,273},{12,10,303},{15,10,39},{
+143,10,111},{133,0,901},{134,10,589},{5,11,190},{136,11,318},{140,0,656},{7,0,
+726},{152,0,9},{4,10,917},{133,10,1005},{135,10,1598},{134,11,491},{4,10,919},{
+133,11,434},{137,0,72},{6,0,1269},{6,0,1566},{134,0,1621},{9,0,463},{10,0,595},{
+4,10,255},{5,10,302},{6,10,132},{7,10,128},{7,10,283},{7,10,1299},{10,10,52},{10
+,10,514},{11,10,925},{13,10,92},{142,10,309},{135,0,1454},{134,0,1287},{11,0,600
+},{13,0,245},{137,10,173},{136,0,989},{7,0,164},{7,0,1571},{9,0,107},{140,0,225}
+,{6,0,1061},{141,10,442},{4,0,27},{5,0,484},{5,0,510},{6,0,434},{7,0,1000},{7,0,
+1098},{136,0,2},{7,11,85},{7,11,247},{8,11,585},{10,11,163},{138,11,316},{11,11,
+103},{142,11,0},{134,0,1127},{4,0,460},{134,0,852},{134,10,210},{4,0,932},{133,0
+,891},{6,0,588},{147,11,83},{8,0,625},{4,10,284},{134,10,223},{134,0,76},{8,0,92
+},{137,0,221},{4,11,124},{10,11,457},{11,11,121},{11,11,169},{11,11,422},{11,11,
+870},{12,11,214},{13,11,389},{14,11,187},{143,11,77},{9,11,618},{138,11,482},{4,
+10,218},{7,10,526},{143,10,137},{13,0,9},{14,0,104},{14,0,311},{4,10,270},{5,10,
+192},{6,10,332},{135,10,1322},{140,10,661},{135,11,1193},{6,11,107},{7,11,638},{
+7,11,1632},{137,11,396},{132,0,763},{4,0,622},{5,11,370},{134,11,1756},{133,0,
+253},{135,0,546},{9,0,73},{10,0,110},{14,0,185},{17,0,119},{133,11,204},{7,0,624
+},{7,0,916},{10,0,256},{139,0,87},{7,10,379},{8,10,481},{137,10,377},{5,0,212},{
+12,0,35},{13,0,382},{5,11,970},{134,11,1706},{9,0,746},{5,10,1003},{134,10,149},
+{10,0,150},{11,0,849},{13,0,330},{8,10,262},{9,10,627},{11,10,214},{11,10,404},{
+11,10,457},{11,10,780},{11,10,913},{13,10,401},{142,10,200},{134,0,1466},{135,11
+,3},{6,0,1299},{4,11,35},{5,11,121},{5,11,483},{5,11,685},{6,11,489},{7,11,1204}
+,{136,11,394},{135,10,742},{4,10,142},{136,10,304},{4,11,921},{133,11,1007},{134
+,0,1518},{6,0,1229},{135,0,1175},{133,0,816},{12,0,159},{4,10,471},{4,11,712},{5
+,10,51},{6,10,602},{7,10,925},{8,10,484},{138,10,195},{134,11,1629},{5,0,869},{5
+,0,968},{6,0,1626},{8,0,734},{136,0,784},{4,0,542},{6,0,1716},{6,0,1727},{7,0,
+1082},{7,0,1545},{8,0,56},{8,0,118},{8,0,412},{8,0,564},{9,0,888},{9,0,908},{10,
+0,50},{10,0,423},{11,0,685},{11,0,697},{11,0,933},{12,0,299},{13,0,126},{13,0,
+136},{13,0,170},{13,0,190},{136,10,688},{132,10,697},{4,0,232},{9,0,202},{10,0,
+474},{140,0,433},{136,0,212},{6,0,108},{7,0,1003},{7,0,1181},{8,0,111},{136,0,
+343},{5,10,221},{135,11,1255},{133,11,485},{134,0,1712},{142,0,216},{5,0,643},{6
+,0,516},{4,11,285},{5,11,317},{6,11,301},{7,11,7},{8,11,153},{10,11,766},{11,11,
+468},{12,11,467},{141,11,143},{4,0,133},{7,0,711},{7,0,1298},{135,0,1585},{134,0
+,650},{135,11,512},{6,0,99},{7,0,1808},{145,0,57},{6,0,246},{6,0,574},{7,0,428},
+{9,0,793},{10,0,669},{11,0,485},{11,0,840},{12,0,300},{14,0,250},{145,0,55},{4,
+10,132},{5,10,69},{135,10,1242},{136,0,1023},{7,0,302},{132,10,111},{135,0,1871}
+,{132,0,728},{9,0,252},{132,10,767},{6,0,461},{7,0,1590},{7,10,1416},{7,10,2005}
+,{8,10,131},{8,10,466},{9,10,672},{13,10,252},{148,10,103},{6,0,323},{135,0,1564
+},{7,0,461},{136,0,775},{6,10,44},{136,10,368},{139,0,172},{132,0,464},{4,10,570
+},{133,10,120},{137,11,269},{6,10,227},{135,10,1589},{6,11,1719},{6,11,1735},{7,
+11,2016},{7,11,2020},{8,11,837},{137,11,852},{7,0,727},{146,0,73},{132,0,1023},{
+135,11,852},{135,10,1529},{136,0,577},{138,11,568},{134,0,1037},{8,11,67},{138,
+11,419},{4,0,413},{5,0,677},{8,0,432},{140,0,280},{10,0,600},{6,10,1667},{7,11,
+967},{7,10,2036},{141,11,11},{6,10,511},{140,10,132},{6,0,799},{5,10,568},{6,10,
+138},{135,10,1293},{8,0,159},{4,10,565},{136,10,827},{7,0,646},{7,0,1730},{11,0,
+446},{141,0,178},{4,10,922},{133,10,1023},{135,11,11},{132,0,395},{11,0,145},{
+135,10,1002},{9,0,174},{10,0,164},{11,0,440},{11,0,514},{11,0,841},{15,0,98},{
+149,0,20},{134,0,426},{10,0,608},{139,0,1002},{7,11,320},{8,11,51},{12,11,481},{
+12,11,570},{148,11,106},{9,0,977},{9,0,983},{132,11,445},{138,0,250},{139,0,100}
+,{6,0,1982},{136,10,402},{133,11,239},{4,10,716},{141,10,31},{5,0,476},{7,11,83}
+,{7,11,1990},{8,11,130},{139,11,720},{8,10,691},{136,10,731},{5,11,123},{6,11,
+530},{7,11,348},{135,11,1419},{5,0,76},{6,0,458},{6,0,497},{7,0,868},{9,0,658},{
+10,0,594},{11,0,173},{11,0,566},{12,0,20},{12,0,338},{141,0,200},{9,11,139},{10,
+11,399},{11,11,469},{12,11,634},{141,11,223},{9,10,840},{138,10,803},{133,10,847
+},{11,11,223},{140,11,168},{132,11,210},{8,0,447},{9,10,53},{9,10,268},{9,10,901
+},{10,10,518},{10,10,829},{11,10,188},{13,10,74},{14,10,46},{15,10,17},{15,10,33
+},{17,10,40},{18,10,36},{19,10,20},{22,10,1},{152,10,2},{4,0,526},{7,0,1029},{
+135,0,1054},{19,11,59},{150,11,2},{4,0,636},{6,0,1875},{6,0,1920},{9,0,999},{12,
+0,807},{12,0,825},{15,0,179},{15,0,190},{18,0,182},{136,10,532},{6,0,1699},{7,0,
+660},{7,0,1124},{17,0,31},{19,0,22},{151,0,14},{135,10,681},{132,11,430},{140,10
+,677},{4,10,684},{136,10,384},{132,11,756},{133,11,213},{7,0,188},{7,10,110},{8,
+10,290},{8,10,591},{9,10,382},{9,10,649},{11,10,71},{11,10,155},{11,10,313},{12,
+10,5},{13,10,325},{142,10,287},{7,10,360},{7,10,425},{9,10,66},{9,10,278},{138,
+10,644},{142,11,164},{4,0,279},{7,0,301},{137,0,362},{134,11,586},{135,0,1743},{
+4,0,178},{133,0,399},{4,10,900},{133,10,861},{5,10,254},{7,10,985},{136,10,73},{
+133,11,108},{7,10,1959},{136,10,683},{133,11,219},{4,11,193},{5,11,916},{7,11,
+364},{10,11,398},{10,11,726},{11,11,317},{11,11,626},{12,11,142},{12,11,288},{12
+,11,678},{13,11,313},{15,11,113},{18,11,114},{21,11,30},{150,11,53},{6,11,241},{
+7,11,907},{8,11,832},{9,11,342},{10,11,729},{11,11,284},{11,11,445},{11,11,651},
+{11,11,863},{13,11,398},{146,11,99},{132,0,872},{134,0,831},{134,0,1692},{6,0,
+202},{6,0,1006},{9,0,832},{10,0,636},{11,0,208},{12,0,360},{17,0,118},{18,0,27},
+{20,0,67},{137,11,734},{132,10,725},{7,11,993},{138,11,666},{134,0,1954},{134,10
+,196},{7,0,872},{10,0,516},{139,0,167},{133,10,831},{4,11,562},{9,11,254},{139,
+11,879},{137,0,313},{4,0,224},{132,11,786},{11,0,24},{12,0,170},{136,10,723},{5,
+0,546},{7,0,35},{8,0,11},{8,0,12},{9,0,315},{9,0,533},{10,0,802},{11,0,166},{12,
+0,525},{142,0,243},{7,0,1937},{13,10,80},{13,10,437},{145,10,74},{5,0,241},{8,0,
+242},{9,0,451},{10,0,667},{11,0,598},{140,0,429},{150,0,46},{6,0,1273},{137,0,
+830},{5,10,848},{6,10,66},{136,10,764},{6,0,825},{134,0,993},{4,0,1006},{10,0,
+327},{13,0,271},{4,10,36},{7,10,1387},{139,10,755},{134,0,1023},{135,0,1580},{4,
+0,366},{137,0,516},{132,10,887},{6,0,1736},{135,0,1891},{6,11,216},{7,11,901},{7
+,11,1343},{136,11,493},{6,10,165},{138,10,388},{7,11,341},{139,11,219},{4,10,719
+},{135,10,155},{134,0,1935},{132,0,826},{6,0,331},{6,0,1605},{8,0,623},{11,0,139
+},{139,0,171},{135,11,1734},{10,11,115},{11,11,420},{12,11,154},{13,11,404},{14,
+11,346},{15,11,54},{143,11,112},{7,0,288},{4,10,353},{6,10,146},{6,10,1789},{7,
+10,990},{7,10,1348},{9,10,665},{9,10,898},{11,10,893},{142,10,212},{6,0,916},{
+134,0,1592},{7,0,1888},{4,10,45},{135,10,1257},{5,11,1011},{136,11,701},{139,11,
+596},{4,11,54},{5,11,666},{7,11,1039},{7,11,1130},{9,11,195},{138,11,302},{134,0
+,1471},{134,0,1570},{132,0,394},{140,10,65},{136,10,816},{135,0,1931},{7,0,574},
+{135,0,1719},{134,11,467},{132,0,658},{9,0,781},{10,0,144},{11,0,385},{13,0,161}
+,{13,0,228},{13,0,268},{20,0,107},{134,11,1669},{136,0,374},{135,0,735},{4,0,344
+},{6,0,498},{139,0,323},{7,0,586},{7,0,1063},{6,10,559},{134,10,1691},{137,0,155
+},{133,0,906},{7,11,122},{9,11,259},{10,11,84},{11,11,470},{12,11,541},{141,11,
+379},{134,0,1139},{10,0,108},{139,0,116},{134,10,456},{133,10,925},{5,11,82},{5,
+11,131},{7,11,1755},{8,11,31},{9,11,168},{9,11,764},{139,11,869},{134,11,605},{5
+,11,278},{137,11,68},{4,11,163},{5,11,201},{5,11,307},{5,11,310},{6,11,335},{7,
+11,284},{136,11,165},{135,11,1660},{6,11,33},{135,11,1244},{4,0,616},{136,11,483
+},{8,0,857},{8,0,902},{8,0,910},{10,0,879},{12,0,726},{4,11,199},{139,11,34},{
+136,0,692},{6,10,193},{7,10,240},{7,10,1682},{10,10,51},{10,10,640},{11,10,410},
+{13,10,82},{14,10,247},{14,10,331},{142,10,377},{6,0,823},{134,0,983},{139,10,
+411},{132,0,305},{136,10,633},{138,11,203},{134,0,681},{6,11,326},{7,11,677},{
+137,11,425},{5,0,214},{7,0,603},{8,0,611},{9,0,686},{10,0,88},{11,0,459},{11,0,
+496},{12,0,463},{12,0,590},{141,0,0},{136,0,1004},{142,0,23},{134,0,1703},{147,
+11,8},{145,11,56},{135,0,1443},{4,10,237},{135,10,514},{6,0,714},{145,0,19},{5,
+11,358},{7,11,473},{7,11,1184},{10,11,662},{13,11,212},{13,11,304},{13,11,333},{
+145,11,98},{4,0,737},{10,0,98},{11,0,294},{12,0,60},{12,0,437},{13,0,64},{13,0,
+380},{142,0,430},{6,10,392},{7,10,65},{135,10,2019},{6,0,1758},{8,0,520},{9,0,
+345},{9,0,403},{142,0,350},{5,0,47},{10,0,242},{138,0,579},{5,0,139},{7,0,1168},
+{138,0,539},{134,0,1459},{13,0,388},{141,11,388},{134,0,253},{7,10,1260},{135,10
+,1790},{10,0,252},{9,10,222},{139,10,900},{140,0,745},{133,11,946},{4,0,107},{7,
+0,613},{8,0,439},{8,0,504},{9,0,501},{10,0,383},{139,0,477},{135,11,1485},{132,0
+,871},{7,11,411},{7,11,590},{8,11,631},{9,11,323},{10,11,355},{11,11,491},{12,11
+,143},{12,11,402},{13,11,73},{14,11,408},{15,11,107},{146,11,71},{132,0,229},{
+132,0,903},{140,0,71},{133,0,549},{4,0,47},{6,0,373},{7,0,452},{7,0,543},{7,0,
+1828},{7,0,1856},{9,0,6},{11,0,257},{139,0,391},{7,11,1467},{8,11,328},{10,11,
+544},{11,11,955},{13,11,320},{145,11,83},{5,0,980},{134,0,1754},{136,0,865},{5,0
+,705},{137,0,606},{7,0,161},{8,10,201},{136,10,605},{143,11,35},{5,11,835},{6,11
+,483},{140,10,224},{7,0,536},{7,0,1331},{136,0,143},{134,0,1388},{5,0,724},{10,0
+,305},{11,0,151},{12,0,33},{12,0,121},{12,0,381},{17,0,3},{17,0,27},{17,0,78},{
+18,0,18},{19,0,54},{149,0,5},{4,10,523},{133,10,638},{5,0,19},{134,0,533},{5,0,
+395},{5,0,951},{134,0,1776},{135,0,1908},{132,0,846},{10,0,74},{11,0,663},{12,0,
+210},{13,0,166},{13,0,310},{14,0,373},{18,0,95},{19,0,43},{6,10,242},{7,10,227},
+{7,10,1581},{8,10,104},{9,10,113},{9,10,220},{9,10,427},{10,10,239},{11,10,579},
+{11,10,1023},{13,10,4},{13,10,204},{13,10,316},{148,10,86},{9,11,716},{11,11,108
+},{13,11,123},{14,11,252},{19,11,38},{21,11,3},{151,11,11},{8,0,372},{9,0,122},{
+138,0,175},{132,11,677},{7,11,1374},{136,11,540},{135,10,861},{132,0,695},{7,0,
+497},{9,0,387},{147,0,81},{136,0,937},{134,0,718},{7,0,1328},{136,10,494},{132,
+11,331},{6,0,1581},{133,11,747},{5,0,284},{6,0,49},{6,0,350},{7,0,1},{7,0,377},{
+7,0,1693},{8,0,18},{8,0,678},{9,0,161},{9,0,585},{9,0,671},{9,0,839},{11,0,912},
+{141,0,427},{7,10,1306},{8,10,505},{9,10,482},{10,10,126},{11,10,225},{12,10,347
+},{12,10,449},{13,10,19},{14,10,218},{142,10,435},{10,10,764},{12,10,120},{13,10
+,39},{145,10,127},{4,0,597},{133,10,268},{134,0,1094},{4,0,1008},{134,0,1973},{
+132,0,811},{139,0,908},{135,0,1471},{133,11,326},{4,10,384},{135,10,1022},{7,0,
+1935},{8,0,324},{12,0,42},{4,11,691},{7,11,1935},{8,11,324},{9,11,35},{10,11,680
+},{11,11,364},{12,11,42},{13,11,357},{146,11,16},{135,0,2014},{7,0,2007},{9,0,
+101},{9,0,450},{10,0,66},{10,0,842},{11,0,536},{12,0,587},{6,11,32},{7,11,385},{
+7,11,757},{7,11,1916},{8,11,37},{8,11,94},{8,11,711},{9,11,541},{10,11,162},{10,
+11,795},{11,11,989},{11,11,1010},{12,11,14},{142,11,308},{139,0,586},{135,10,
+1703},{7,0,1077},{11,0,28},{9,10,159},{140,10,603},{6,0,1221},{136,10,583},{6,11
+,152},{6,11,349},{6,11,1682},{7,11,1252},{8,11,112},{9,11,435},{9,11,668},{10,11
+,290},{10,11,319},{10,11,815},{11,11,180},{11,11,837},{12,11,240},{13,11,152},{
+13,11,219},{142,11,158},{139,0,62},{132,10,515},{8,10,632},{8,10,697},{137,10,
+854},{134,0,1766},{132,11,581},{6,11,126},{7,11,573},{8,11,397},{142,11,44},{150
+,0,28},{11,0,670},{22,0,25},{4,10,136},{133,10,551},{6,0,1665},{7,0,256},{7,0,
+1388},{138,0,499},{4,0,22},{5,0,10},{7,0,1576},{136,0,97},{134,10,1782},{5,0,481
+},{7,10,1287},{9,10,44},{10,10,552},{10,10,642},{11,10,839},{12,10,274},{12,10,
+275},{12,10,372},{13,10,91},{142,10,125},{133,11,926},{7,11,1232},{137,11,531},{
+6,0,134},{7,0,437},{7,0,1824},{9,0,37},{14,0,285},{142,0,371},{7,0,486},{8,0,155
+},{11,0,93},{140,0,164},{6,0,1391},{134,0,1442},{133,11,670},{133,0,591},{6,10,
+147},{7,10,886},{7,11,1957},{9,10,753},{138,10,268},{5,0,380},{5,0,650},{7,0,
+1173},{136,0,310},{4,0,364},{7,0,1156},{7,0,1187},{137,0,409},{135,11,1621},{134
+,0,482},{133,11,506},{4,0,781},{6,0,487},{7,0,926},{8,0,263},{139,0,500},{138,10
+,137},{135,11,242},{139,11,96},{133,10,414},{135,10,1762},{134,0,804},{5,11,834}
+,{7,11,1202},{8,11,14},{9,11,481},{137,11,880},{134,10,599},{4,0,94},{135,0,1265
+},{4,0,415},{132,0,417},{5,0,348},{6,0,522},{6,10,1749},{7,11,1526},{138,11,465}
+,{134,10,1627},{132,0,1012},{132,10,488},{4,11,357},{6,11,172},{7,11,143},{137,
+11,413},{4,10,83},{4,11,590},{146,11,76},{140,10,676},{7,11,287},{8,11,355},{9,
+11,293},{137,11,743},{134,10,278},{6,0,1803},{18,0,165},{24,0,21},{5,11,169},{7,
+11,333},{136,11,45},{12,10,97},{140,11,97},{4,0,408},{4,0,741},{135,0,500},{132,
+11,198},{7,10,388},{7,10,644},{139,10,781},{4,11,24},{5,11,140},{5,11,185},{7,11
+,1500},{11,11,565},{139,11,838},{6,0,1321},{9,0,257},{7,10,229},{8,10,59},{9,10,
+190},{10,10,378},{140,10,191},{4,11,334},{133,11,593},{135,11,1885},{134,0,1138}
+,{4,0,249},{6,0,73},{135,0,177},{133,0,576},{142,0,231},{137,0,288},{132,10,660}
+,{7,10,1035},{138,10,737},{135,0,1487},{6,0,989},{9,0,433},{7,10,690},{9,10,587}
+,{140,10,521},{7,0,1264},{7,0,1678},{11,0,945},{12,0,341},{12,0,471},{140,0,569}
+,{132,11,709},{133,11,897},{5,11,224},{13,11,174},{146,11,52},{135,11,1840},{134
+,10,1744},{12,0,87},{16,0,74},{4,10,733},{9,10,194},{10,10,92},{11,10,198},{12,
+10,84},{141,10,128},{140,0,779},{135,0,538},{4,11,608},{133,11,497},{133,0,413},
+{7,11,1375},{7,11,1466},{138,11,331},{136,0,495},{6,11,540},{136,11,136},{7,0,54
+},{8,0,312},{10,0,191},{10,0,614},{140,0,567},{6,0,468},{7,0,567},{7,0,1478},{8,
+0,530},{14,0,290},{133,11,999},{4,11,299},{7,10,306},{135,11,1004},{142,11,296},
+{134,0,1484},{133,10,979},{6,0,609},{9,0,815},{12,11,137},{14,11,9},{14,11,24},{
+142,11,64},{133,11,456},{6,0,484},{135,0,822},{133,10,178},{136,11,180},{132,11,
+755},{137,0,900},{135,0,1335},{6,0,1724},{135,0,2022},{135,11,1139},{5,0,640},{
+132,10,390},{6,0,1831},{138,11,633},{135,11,566},{4,11,890},{5,11,805},{5,11,819
+},{5,11,961},{6,11,396},{6,11,1631},{6,11,1678},{7,11,1967},{7,11,2041},{9,11,
+630},{11,11,8},{11,11,1019},{12,11,176},{13,11,225},{14,11,292},{149,11,24},{132
+,0,474},{134,0,1103},{135,0,1504},{134,0,1576},{6,0,961},{6,0,1034},{140,0,655},
+{11,11,514},{149,11,20},{5,0,305},{135,11,1815},{7,11,1505},{10,11,190},{10,11,
+634},{11,11,792},{12,11,358},{140,11,447},{5,11,0},{6,11,536},{7,11,604},{13,11,
+445},{145,11,126},{7,0,1236},{133,10,105},{4,0,480},{6,0,217},{6,0,302},{6,0,
+1642},{7,0,130},{7,0,837},{7,0,1321},{7,0,1547},{7,0,1657},{8,0,429},{9,0,228},{
+13,0,289},{13,0,343},{19,0,101},{6,11,232},{6,11,412},{7,11,1074},{8,11,9},{8,11
+,157},{8,11,786},{9,11,196},{9,11,352},{9,11,457},{10,11,337},{11,11,232},{11,11
+,877},{12,11,480},{140,11,546},{5,10,438},{7,11,958},{9,10,694},{12,10,627},{13,
+11,38},{141,10,210},{4,11,382},{136,11,579},{7,0,278},{10,0,739},{11,0,708},{141
+,0,348},{4,11,212},{135,11,1206},{135,11,1898},{6,0,708},{6,0,1344},{152,10,11},
+{137,11,768},{134,0,1840},{140,0,233},{8,10,25},{138,10,826},{6,0,2017},{133,11,
+655},{6,0,1488},{139,11,290},{132,10,308},{134,0,1590},{134,0,1800},{134,0,1259}
+,{16,0,28},{6,11,231},{7,11,95},{136,11,423},{133,11,300},{135,10,150},{136,10,
+649},{7,11,1874},{137,11,641},{6,11,237},{7,11,611},{8,11,100},{9,11,416},{11,11
+,335},{12,11,173},{146,11,101},{137,0,45},{134,10,521},{17,0,36},{14,11,26},{146
+,11,150},{7,0,1442},{14,0,22},{5,10,339},{15,10,41},{15,10,166},{147,10,66},{8,0
+,378},{6,11,581},{135,11,1119},{134,0,1507},{147,11,117},{139,0,39},{134,0,1054}
+,{6,0,363},{7,0,1955},{136,0,725},{134,0,2036},{133,11,199},{6,0,1871},{9,0,935}
+,{9,0,961},{9,0,1004},{9,0,1016},{12,0,805},{12,0,852},{12,0,853},{12,0,869},{12
+,0,882},{12,0,896},{12,0,906},{12,0,917},{12,0,940},{15,0,170},{15,0,176},{15,0,
+188},{15,0,201},{15,0,205},{15,0,212},{15,0,234},{15,0,244},{18,0,181},{18,0,193
+},{18,0,196},{18,0,201},{18,0,202},{18,0,210},{18,0,217},{18,0,235},{18,0,236},{
+18,0,237},{21,0,54},{21,0,55},{21,0,58},{21,0,59},{152,0,22},{134,10,1628},{137,
+0,805},{5,0,813},{135,0,2046},{142,11,42},{5,0,712},{6,0,1240},{11,0,17},{13,0,
+321},{144,0,67},{132,0,617},{135,10,829},{6,0,320},{7,0,781},{7,0,1921},{9,0,55}
+,{10,0,186},{10,0,273},{10,0,664},{10,0,801},{11,0,996},{11,0,997},{13,0,157},{
+142,0,170},{136,0,271},{5,10,486},{135,10,1349},{18,11,91},{147,11,70},{10,0,445
+},{7,10,1635},{8,10,17},{138,10,295},{136,11,404},{7,0,103},{7,0,863},{11,0,184}
+,{145,0,62},{138,10,558},{137,0,659},{6,11,312},{6,11,1715},{10,11,584},{11,11,
+546},{11,11,692},{12,11,259},{12,11,295},{13,11,46},{141,11,154},{134,0,676},{
+132,11,588},{4,11,231},{5,11,61},{6,11,104},{7,11,729},{7,11,964},{7,11,1658},{
+140,11,414},{6,11,263},{138,11,757},{11,0,337},{142,0,303},{135,11,1363},{132,11
+,320},{140,0,506},{134,10,447},{5,0,77},{7,0,1455},{10,0,843},{147,0,73},{7,10,
+577},{7,10,1432},{9,10,475},{9,10,505},{9,10,526},{9,10,609},{9,10,689},{9,10,
+726},{9,10,735},{9,10,738},{10,10,556},{10,10,674},{10,10,684},{11,10,89},{11,10
+,202},{11,10,272},{11,10,380},{11,10,415},{11,10,505},{11,10,537},{11,10,550},{
+11,10,562},{11,10,640},{11,10,667},{11,10,688},{11,10,847},{11,10,927},{11,10,
+930},{11,10,940},{12,10,144},{12,10,325},{12,10,329},{12,10,389},{12,10,403},{12
+,10,451},{12,10,515},{12,10,604},{12,10,616},{12,10,626},{13,10,66},{13,10,131},
+{13,10,167},{13,10,236},{13,10,368},{13,10,411},{13,10,434},{13,10,453},{13,10,
+461},{13,10,474},{14,10,59},{14,10,60},{14,10,139},{14,10,152},{14,10,276},{14,
+10,353},{14,10,402},{15,10,28},{15,10,81},{15,10,123},{15,10,152},{18,10,136},{
+148,10,88},{132,0,458},{135,0,1420},{6,0,109},{10,0,382},{4,11,405},{4,10,609},{
+7,10,756},{7,11,817},{9,10,544},{11,10,413},{14,11,58},{14,10,307},{16,10,25},{
+17,11,37},{146,11,124},{6,0,330},{7,0,1084},{11,0,142},{133,11,974},{4,10,930},{
+133,10,947},{5,10,939},{142,11,394},{16,0,91},{145,0,87},{5,11,235},{5,10,962},{
+7,11,1239},{11,11,131},{140,11,370},{11,0,492},{5,10,651},{8,10,170},{9,10,61},{
+9,10,63},{10,10,23},{10,10,37},{10,10,834},{11,10,4},{11,10,281},{11,10,503},{11
+,10,677},{12,10,96},{12,10,130},{12,10,244},{14,10,5},{14,10,40},{14,10,162},{14
+,10,202},{146,10,133},{4,10,406},{5,10,579},{12,10,492},{150,10,15},{9,11,137},{
+138,11,221},{134,0,1239},{11,0,211},{140,0,145},{7,11,390},{138,11,140},{135,11,
+1418},{135,11,1144},{134,0,1049},{7,0,321},{6,10,17},{7,10,1001},{7,10,1982},{9,
+10,886},{10,10,489},{10,10,800},{11,10,782},{12,10,320},{13,10,467},{14,10,145},
+{14,10,387},{143,10,119},{145,10,17},{5,11,407},{11,11,489},{19,11,37},{20,11,73
+},{150,11,38},{133,10,458},{135,0,1985},{7,10,1983},{8,10,0},{8,10,171},{9,10,
+120},{9,10,732},{10,10,473},{11,10,656},{11,10,998},{18,10,0},{18,10,2},{147,10,
+21},{5,11,325},{7,11,1483},{8,11,5},{8,11,227},{9,11,105},{10,11,585},{140,11,
+614},{136,0,122},{132,0,234},{135,11,1196},{6,0,976},{6,0,1098},{134,0,1441},{7,
+0,253},{136,0,549},{6,11,621},{13,11,504},{144,11,19},{132,10,519},{5,0,430},{5,
+0,932},{6,0,131},{7,0,417},{9,0,522},{11,0,314},{141,0,390},{14,0,149},{14,0,399
+},{143,0,57},{5,10,907},{6,10,31},{6,11,218},{7,10,491},{7,10,530},{8,10,592},{
+11,10,53},{11,10,779},{12,10,167},{12,10,411},{14,10,14},{14,10,136},{15,10,72},
+{16,10,17},{144,10,72},{140,11,330},{7,11,454},{7,11,782},{136,11,768},{132,0,
+507},{10,11,676},{140,11,462},{6,0,630},{9,0,811},{4,10,208},{5,10,106},{6,10,
+531},{8,10,408},{9,10,188},{138,10,572},{4,0,343},{5,0,511},{134,10,1693},{134,
+11,164},{132,0,448},{7,0,455},{138,0,591},{135,0,1381},{12,10,441},{150,11,50},{
+9,10,449},{10,10,192},{138,10,740},{6,0,575},{132,10,241},{134,0,1175},{134,0,
+653},{134,0,1761},{134,0,1198},{132,10,259},{6,11,343},{7,11,195},{9,11,226},{10
+,11,197},{10,11,575},{11,11,502},{139,11,899},{7,0,1127},{7,0,1572},{10,0,297},{
+10,0,422},{11,0,764},{11,0,810},{12,0,264},{13,0,102},{13,0,300},{13,0,484},{14,
+0,147},{14,0,229},{17,0,71},{18,0,118},{147,0,120},{135,11,666},{132,0,678},{4,
+10,173},{5,10,312},{5,10,512},{135,10,1285},{7,10,1603},{7,10,1691},{9,10,464},{
+11,10,195},{12,10,279},{12,10,448},{14,10,11},{147,10,102},{16,0,99},{146,0,164}
+,{7,11,1125},{9,11,143},{11,11,61},{14,11,405},{150,11,21},{137,11,260},{4,10,
+452},{5,10,583},{5,10,817},{6,10,433},{7,10,593},{7,10,720},{7,10,1378},{8,10,
+161},{9,10,284},{10,10,313},{139,10,886},{132,10,547},{136,10,722},{14,0,35},{
+142,0,191},{141,0,45},{138,0,121},{132,0,125},{134,0,1622},{133,11,959},{8,10,
+420},{139,10,193},{132,0,721},{135,10,409},{136,0,145},{7,0,792},{8,0,147},{10,0
+,821},{11,0,970},{11,0,1021},{136,11,173},{134,11,266},{132,0,715},{7,0,1999},{
+138,10,308},{133,0,531},{5,0,168},{5,0,930},{8,0,74},{9,0,623},{12,0,500},{140,0
+,579},{144,0,65},{138,11,246},{6,0,220},{7,0,1101},{13,0,105},{142,11,314},{5,10
+,1002},{136,10,745},{134,0,960},{20,0,0},{148,11,0},{4,0,1005},{4,10,239},{6,10,
+477},{7,10,1607},{11,10,68},{139,10,617},{6,0,19},{7,0,1413},{139,0,428},{149,10
+,13},{7,0,96},{8,0,401},{8,0,703},{9,0,896},{136,11,300},{134,0,1595},{145,0,116
+},{136,0,1021},{7,0,1961},{7,0,1965},{7,0,2030},{8,0,150},{8,0,702},{8,0,737},{8
+,0,750},{140,0,366},{11,11,75},{142,11,267},{132,10,367},{8,0,800},{9,0,148},{9,
+0,872},{9,0,890},{11,0,309},{11,0,1001},{13,0,267},{13,0,323},{5,11,427},{5,11,
+734},{7,11,478},{136,11,52},{7,11,239},{11,11,217},{142,11,165},{132,11,323},{
+140,11,419},{13,0,299},{142,0,75},{6,11,87},{6,11,1734},{7,11,20},{7,11,1056},{8
+,11,732},{9,11,406},{9,11,911},{138,11,694},{134,0,1383},{132,10,694},{133,11,
+613},{137,0,779},{4,0,598},{140,10,687},{6,0,970},{135,0,424},{133,0,547},{7,11,
+32},{7,11,984},{8,11,85},{8,11,709},{9,11,579},{9,11,847},{9,11,856},{10,11,799}
+,{11,11,258},{11,11,1007},{12,11,331},{12,11,615},{13,11,188},{13,11,435},{14,11
+,8},{15,11,165},{16,11,27},{148,11,40},{6,0,1222},{134,0,1385},{132,0,876},{138,
+11,151},{135,10,213},{4,11,167},{135,11,82},{133,0,133},{6,11,24},{7,11,74},{7,
+11,678},{137,11,258},{5,11,62},{6,11,534},{7,11,684},{7,11,1043},{7,11,1072},{8,
+11,280},{8,11,541},{8,11,686},{10,11,519},{11,11,252},{140,11,282},{136,0,187},{
+8,0,8},{10,0,0},{10,0,818},{139,0,988},{132,11,359},{11,0,429},{15,0,51},{135,10
+,1672},{136,0,685},{5,11,211},{7,11,88},{136,11,627},{134,0,472},{136,0,132},{6,
+11,145},{141,11,336},{4,10,751},{11,10,390},{140,10,32},{6,0,938},{6,0,1060},{4,
+11,263},{4,10,409},{133,10,78},{137,0,874},{8,0,774},{10,0,670},{12,0,51},{4,11,
+916},{6,10,473},{7,10,1602},{10,10,698},{12,10,212},{13,10,307},{145,10,105},{
+146,0,92},{143,10,156},{132,0,830},{137,0,701},{4,11,599},{6,11,1634},{7,11,5},{
+7,11,55},{7,11,67},{7,11,97},{7,11,691},{7,11,979},{7,11,1697},{8,11,207},{8,11,
+214},{8,11,231},{8,11,294},{8,11,336},{8,11,428},{8,11,451},{8,11,460},{8,11,471
+},{8,11,622},{8,11,626},{8,11,679},{8,11,759},{8,11,829},{9,11,11},{9,11,246},{9
+,11,484},{9,11,573},{9,11,706},{9,11,762},{9,11,798},{9,11,855},{9,11,870},{9,11
+,912},{10,11,303},{10,11,335},{10,11,424},{10,11,461},{10,11,543},{10,11,759},{
+10,11,814},{11,11,59},{11,11,199},{11,11,235},{11,11,475},{11,11,590},{11,11,929
+},{11,11,963},{12,11,114},{12,11,182},{12,11,226},{12,11,332},{12,11,439},{12,11
+,575},{12,11,598},{13,11,8},{13,11,125},{13,11,194},{13,11,287},{14,11,197},{14,
+11,383},{15,11,53},{17,11,63},{19,11,46},{19,11,98},{19,11,106},{148,11,85},{4,0
+,127},{5,0,350},{6,0,356},{8,0,426},{9,0,572},{10,0,247},{139,0,312},{134,0,1215
+},{6,0,59},{9,0,603},{13,0,397},{7,11,1853},{138,11,437},{134,0,1762},{147,11,
+126},{135,10,883},{13,0,293},{142,0,56},{133,10,617},{139,10,50},{5,11,187},{7,
+10,1518},{139,10,694},{135,0,441},{6,0,111},{7,0,4},{8,0,163},{8,0,776},{138,0,
+566},{132,0,806},{4,11,215},{9,11,38},{10,11,3},{11,11,23},{11,11,127},{139,11,
+796},{14,0,233},{4,10,546},{135,10,2042},{135,0,1994},{134,0,1739},{135,11,1530}
+,{136,0,393},{5,0,297},{7,0,1038},{14,0,359},{19,0,52},{148,0,47},{135,0,309},{4
+,10,313},{133,10,577},{8,10,184},{141,10,433},{135,10,935},{12,10,186},{12,10,
+292},{14,10,100},{146,10,70},{136,0,363},{14,0,175},{11,10,402},{12,10,109},{12,
+10,431},{13,10,179},{13,10,206},{14,10,217},{16,10,3},{148,10,53},{5,10,886},{6,
+10,46},{6,10,1790},{7,10,14},{7,10,732},{7,10,1654},{8,10,95},{8,10,327},{8,10,
+616},{9,10,892},{10,10,598},{10,10,769},{11,10,134},{11,10,747},{12,10,378},{142
+,10,97},{136,0,666},{135,0,1675},{6,0,655},{134,0,1600},{135,0,808},{133,10,1021
+},{4,11,28},{5,11,440},{7,11,248},{11,11,833},{140,11,344},{134,11,1654},{132,0,
+280},{140,0,54},{4,0,421},{133,0,548},{132,10,153},{6,11,339},{135,11,923},{133,
+11,853},{133,10,798},{132,10,587},{6,11,249},{7,11,1234},{139,11,573},{6,10,598}
+,{7,10,42},{8,10,695},{10,10,212},{11,10,158},{14,10,196},{145,10,85},{7,0,249},
+{5,10,957},{133,10,1008},{4,10,129},{135,10,465},{6,0,254},{7,0,842},{7,0,1659},
+{9,0,109},{10,0,103},{7,10,908},{7,10,1201},{9,10,755},{11,10,906},{12,10,527},{
+146,10,7},{5,0,262},{136,10,450},{144,0,1},{10,11,201},{142,11,319},{7,11,49},{7
+,11,392},{8,11,20},{8,11,172},{8,11,690},{9,11,383},{9,11,845},{10,11,48},{11,11
+,293},{11,11,832},{11,11,920},{141,11,221},{5,11,858},{133,11,992},{134,0,805},{
+139,10,1003},{6,0,1630},{134,11,307},{7,11,1512},{135,11,1794},{6,11,268},{137,
+11,62},{135,10,1868},{133,0,671},{4,0,989},{8,0,972},{136,0,998},{132,11,423},{
+132,0,889},{135,0,1382},{135,0,1910},{7,10,965},{7,10,1460},{135,10,1604},{4,0,
+627},{5,0,775},{138,11,106},{134,11,348},{7,0,202},{11,0,362},{11,0,948},{140,0,
+388},{138,11,771},{6,11,613},{136,11,223},{6,0,560},{7,0,451},{8,0,389},{12,0,
+490},{13,0,16},{13,0,215},{13,0,351},{18,0,132},{147,0,125},{135,0,841},{136,0,
+566},{136,0,938},{132,11,670},{5,0,912},{6,0,1695},{140,11,55},{9,11,40},{139,11
+,136},{7,0,1361},{7,10,982},{10,10,32},{143,10,56},{11,11,259},{140,11,270},{5,0
+,236},{6,0,572},{8,0,492},{11,0,618},{144,0,56},{8,11,572},{9,11,310},{9,11,682}
+,{137,11,698},{134,0,1854},{5,0,190},{136,0,318},{133,10,435},{135,0,1376},{4,11
+,296},{6,11,352},{7,11,401},{7,11,1410},{7,11,1594},{7,11,1674},{8,11,63},{8,11,
+660},{137,11,74},{7,0,349},{5,10,85},{6,10,419},{7,10,305},{7,10,361},{7,10,1337
+},{8,10,71},{140,10,519},{4,11,139},{4,11,388},{140,11,188},{6,0,1972},{6,0,2013
+},{8,0,951},{10,0,947},{10,0,974},{10,0,1018},{142,0,476},{140,10,688},{135,10,
+740},{5,10,691},{7,10,345},{9,10,94},{140,10,169},{9,0,344},{5,10,183},{6,10,582
+},{10,10,679},{140,10,435},{135,10,511},{132,0,850},{8,11,441},{10,11,314},{143,
+11,3},{7,10,1993},{136,10,684},{4,11,747},{6,11,290},{6,10,583},{7,11,649},{7,11
+,1479},{135,11,1583},{133,11,232},{133,10,704},{134,0,910},{4,10,179},{5,10,198}
+,{133,10,697},{7,10,347},{7,10,971},{8,10,181},{138,10,711},{136,11,525},{14,0,
+19},{14,0,28},{144,0,29},{7,0,85},{7,0,247},{8,0,585},{138,0,163},{4,0,487},{7,
+11,472},{7,11,1801},{10,11,748},{141,11,458},{4,10,243},{5,10,203},{7,10,19},{7,
+10,71},{7,10,113},{10,10,405},{11,10,357},{142,10,240},{7,10,1450},{139,10,99},{
+132,11,425},{138,0,145},{147,0,83},{6,10,492},{137,11,247},{4,0,1013},{134,0,
+2033},{5,10,134},{6,10,408},{6,10,495},{135,10,1593},{135,0,1922},{134,11,1768},
+{4,0,124},{10,0,457},{11,0,121},{11,0,169},{11,0,870},{11,0,874},{12,0,214},{14,
+0,187},{143,0,77},{5,0,557},{135,0,1457},{139,0,66},{5,11,943},{6,11,1779},{142,
+10,4},{4,10,248},{4,10,665},{7,10,137},{137,10,349},{7,0,1193},{5,11,245},{6,11,
+576},{7,11,582},{136,11,225},{144,0,82},{7,10,1270},{139,10,612},{5,0,454},{10,0
+,352},{138,11,352},{18,0,57},{5,10,371},{135,10,563},{135,0,1333},{6,0,107},{7,0
+,638},{7,0,1632},{9,0,396},{134,11,610},{5,0,370},{134,0,1756},{4,10,374},{7,10,
+547},{7,10,1700},{7,10,1833},{139,10,858},{133,0,204},{6,0,1305},{9,10,311},{141
+,10,42},{5,0,970},{134,0,1706},{6,10,1647},{7,10,1552},{7,10,2010},{9,10,494},{
+137,10,509},{13,11,455},{15,11,99},{15,11,129},{144,11,68},{135,0,3},{4,0,35},{5
+,0,121},{5,0,483},{5,0,685},{6,0,489},{6,0,782},{6,0,1032},{7,0,1204},{136,0,394
+},{4,0,921},{133,0,1007},{8,11,360},{138,11,63},{135,0,1696},{134,0,1519},{132,
+11,443},{135,11,944},{6,10,123},{7,10,214},{9,10,728},{10,10,157},{11,10,346},{
+11,10,662},{143,10,106},{137,0,981},{135,10,1435},{134,0,1072},{132,0,712},{134,
+0,1629},{134,0,728},{4,11,298},{137,11,483},{6,0,1177},{6,0,1271},{5,11,164},{7,
+11,121},{142,11,189},{7,0,1608},{4,10,707},{5,10,588},{6,10,393},{13,10,106},{18
+,10,49},{147,10,41},{23,0,16},{151,11,16},{6,10,211},{7,10,1690},{11,10,486},{
+140,10,369},{133,0,485},{19,11,15},{149,11,27},{4,11,172},{9,11,611},{10,11,436}
+,{12,11,673},{141,11,255},{5,11,844},{10,11,484},{11,11,754},{12,11,457},{14,11,
+171},{14,11,389},{146,11,153},{4,0,285},{5,0,27},{5,0,317},{6,0,301},{7,0,7},{8,
+0,153},{10,0,766},{11,0,468},{12,0,467},{141,0,143},{134,0,1462},{9,11,263},{10,
+11,147},{138,11,492},{133,11,537},{6,0,1945},{6,0,1986},{6,0,1991},{134,0,2038},
+{134,10,219},{137,11,842},{14,0,52},{17,0,50},{5,10,582},{6,10,1646},{7,10,99},{
+7,10,1962},{7,10,1986},{8,10,515},{8,10,773},{9,10,23},{9,10,491},{12,10,620},{
+142,10,93},{138,11,97},{20,0,21},{20,0,44},{133,10,851},{136,0,819},{139,0,917},
+{5,11,230},{5,11,392},{6,11,420},{8,10,762},{8,10,812},{9,11,568},{9,10,910},{
+140,11,612},{135,0,784},{15,0,135},{143,11,135},{10,0,454},{140,0,324},{4,11,0},
+{5,11,41},{7,11,1459},{7,11,1469},{7,11,1618},{7,11,1859},{9,11,549},{139,11,905
+},{4,10,98},{7,10,1365},{9,10,422},{9,10,670},{10,10,775},{11,10,210},{13,10,26}
+,{13,10,457},{141,10,476},{6,0,1719},{6,0,1735},{7,0,2016},{7,0,2020},{8,0,837},
+{137,0,852},{133,11,696},{135,0,852},{132,0,952},{134,10,1730},{132,11,771},{138
+,0,568},{137,0,448},{139,0,146},{8,0,67},{138,0,419},{133,11,921},{137,10,147},{
+134,0,1826},{10,0,657},{14,0,297},{142,0,361},{6,0,666},{6,0,767},{134,0,1542},{
+139,0,729},{6,11,180},{7,11,1137},{8,11,751},{139,11,805},{4,11,183},{7,11,271},
+{11,11,824},{11,11,952},{13,11,278},{13,11,339},{13,11,482},{14,11,424},{148,11,
+99},{4,0,669},{5,11,477},{5,11,596},{6,11,505},{7,11,1221},{11,11,907},{12,11,
+209},{141,11,214},{135,11,1215},{5,0,402},{6,10,30},{11,10,56},{139,10,305},{7,
+11,564},{142,11,168},{139,0,152},{7,0,912},{135,10,1614},{4,10,150},{5,10,303},{
+134,10,327},{7,0,320},{8,0,51},{9,0,868},{10,0,833},{12,0,481},{12,0,570},{148,0
+,106},{132,0,445},{7,11,274},{11,11,263},{11,11,479},{11,11,507},{140,11,277},{
+10,0,555},{11,0,308},{19,0,95},{6,11,1645},{8,10,192},{10,10,78},{141,10,359},{
+135,10,786},{6,11,92},{6,11,188},{7,11,1269},{7,11,1524},{7,11,1876},{10,11,228}
+,{139,11,1020},{4,11,459},{133,11,966},{11,0,386},{6,10,1638},{7,10,79},{7,10,
+496},{9,10,138},{10,10,336},{12,10,412},{12,10,440},{142,10,305},{133,0,239},{7,
+0,83},{7,0,1990},{8,0,130},{139,0,720},{138,11,709},{4,0,143},{5,0,550},{133,0,
+752},{5,0,123},{6,0,530},{7,0,348},{135,0,1419},{135,0,2024},{6,11,18},{7,11,179
+},{7,11,721},{7,11,932},{8,11,548},{8,11,757},{9,11,54},{9,11,65},{9,11,532},{9,
+11,844},{10,11,113},{10,11,117},{10,11,236},{10,11,315},{10,11,430},{10,11,798},
+{11,11,153},{11,11,351},{11,11,375},{12,11,78},{12,11,151},{12,11,392},{14,11,
+248},{143,11,23},{7,10,204},{7,10,415},{8,10,42},{10,10,85},{139,10,564},{134,0,
+958},{133,11,965},{132,0,210},{135,11,1429},{138,11,480},{134,11,182},{139,11,
+345},{10,11,65},{10,11,488},{138,11,497},{4,10,3},{5,10,247},{5,10,644},{7,10,
+744},{7,10,1207},{7,10,1225},{7,10,1909},{146,10,147},{132,0,430},{5,10,285},{9,
+10,67},{13,10,473},{143,10,82},{144,11,16},{7,11,1162},{9,11,588},{10,11,260},{
+151,10,8},{133,0,213},{138,0,7},{135,0,801},{134,11,1786},{135,11,308},{6,0,936}
+,{134,0,1289},{133,0,108},{132,0,885},{133,0,219},{139,0,587},{4,0,193},{5,0,916
+},{6,0,1041},{7,0,364},{10,0,398},{10,0,726},{11,0,317},{11,0,626},{12,0,142},{
+12,0,288},{12,0,678},{13,0,313},{15,0,113},{146,0,114},{135,0,1165},{6,0,241},{9
+,0,342},{10,0,729},{11,0,284},{11,0,445},{11,0,651},{11,0,863},{13,0,398},{146,0
+,99},{7,0,907},{136,0,832},{9,0,303},{4,10,29},{6,10,532},{7,10,1628},{7,10,1648
+},{9,10,350},{10,10,433},{11,10,97},{11,10,557},{11,10,745},{12,10,289},{12,10,
+335},{12,10,348},{12,10,606},{13,10,116},{13,10,233},{13,10,466},{14,10,181},{14
+,10,209},{14,10,232},{14,10,236},{14,10,300},{16,10,41},{148,10,97},{7,11,423},{
+7,10,1692},{136,11,588},{6,0,931},{134,0,1454},{5,10,501},{7,10,1704},{9,10,553}
+,{11,10,520},{12,10,557},{141,10,249},{136,11,287},{4,0,562},{9,0,254},{139,0,
+879},{132,0,786},{14,11,32},{18,11,85},{20,11,2},{152,11,16},{135,0,1294},{7,11,
+723},{135,11,1135},{6,0,216},{7,0,901},{7,0,1343},{8,0,493},{134,11,403},{7,11,
+719},{8,11,809},{136,11,834},{5,11,210},{6,11,213},{7,11,60},{10,11,364},{139,11
+,135},{7,0,341},{11,0,219},{5,11,607},{8,11,326},{136,11,490},{4,11,701},{5,11,
+472},{5,11,639},{7,11,1249},{9,11,758},{139,11,896},{135,11,380},{135,11,1947},{
+139,0,130},{135,0,1734},{10,0,115},{11,0,420},{12,0,154},{13,0,404},{14,0,346},{
+143,0,54},{134,10,129},{4,11,386},{7,11,41},{8,11,405},{9,11,497},{11,11,110},{
+11,11,360},{15,11,37},{144,11,84},{141,11,282},{5,11,46},{7,11,1452},{7,11,1480}
+,{8,11,634},{140,11,472},{4,11,524},{136,11,810},{10,11,238},{141,11,33},{133,0,
+604},{5,0,1011},{136,0,701},{8,0,856},{8,0,858},{8,0,879},{12,0,702},{142,0,447}
+,{4,0,54},{5,0,666},{7,0,1039},{7,0,1130},{9,0,195},{138,0,302},{4,10,25},{5,10,
+60},{6,10,504},{7,10,614},{7,10,1155},{140,10,0},{7,10,1248},{11,10,621},{139,10
+,702},{133,11,997},{137,10,321},{134,0,1669},{134,0,1791},{4,10,379},{135,10,
+1397},{138,11,372},{5,11,782},{5,11,829},{134,11,1738},{135,0,1228},{4,10,118},{
+6,10,274},{6,10,361},{7,10,75},{141,10,441},{132,0,623},{9,11,279},{10,11,407},{
+14,11,84},{150,11,18},{137,10,841},{135,0,798},{140,10,693},{5,10,314},{6,10,221
+},{7,10,419},{10,10,650},{11,10,396},{12,10,156},{13,10,369},{14,10,333},{145,10
+,47},{135,11,1372},{7,0,122},{9,0,259},{10,0,84},{11,0,470},{12,0,541},{141,0,
+379},{134,0,837},{8,0,1013},{4,11,78},{5,11,96},{5,11,182},{7,11,1724},{7,11,
+1825},{10,11,394},{10,11,471},{11,11,532},{14,11,340},{145,11,88},{134,0,577},{
+135,11,1964},{132,10,913},{134,0,460},{8,0,891},{10,0,901},{10,0,919},{10,0,932}
+,{12,0,715},{12,0,728},{12,0,777},{14,0,457},{144,0,103},{5,0,82},{5,0,131},{7,0
+,1755},{8,0,31},{9,0,168},{9,0,764},{139,0,869},{136,10,475},{6,0,605},{5,10,
+1016},{9,11,601},{9,11,619},{10,11,505},{10,11,732},{11,11,355},{140,11,139},{7,
+10,602},{8,10,179},{10,10,781},{140,10,126},{134,0,1246},{6,10,329},{138,10,111}
+,{6,11,215},{7,11,1028},{7,11,1473},{7,11,1721},{9,11,424},{138,11,779},{5,0,278
+},{137,0,68},{6,0,932},{6,0,1084},{144,0,86},{4,0,163},{5,0,201},{5,0,307},{5,0,
+310},{6,0,335},{7,0,284},{7,0,1660},{136,0,165},{136,0,781},{134,0,707},{6,0,33}
+,{135,0,1244},{5,10,821},{6,11,67},{6,10,1687},{7,11,258},{7,11,1630},{9,11,354}
+,{9,11,675},{10,11,830},{14,11,80},{145,11,80},{6,11,141},{7,11,225},{9,11,59},{
+9,11,607},{10,11,312},{11,11,687},{12,11,555},{13,11,373},{13,11,494},{148,11,58
+},{134,0,1113},{9,0,388},{5,10,71},{7,10,1407},{9,10,704},{10,10,261},{10,10,619
+},{11,10,547},{11,10,619},{143,10,157},{7,0,1953},{136,0,720},{138,0,203},{7,10,
+2008},{9,10,337},{138,10,517},{6,0,326},{7,0,677},{137,0,425},{139,11,81},{7,0,
+1316},{7,0,1412},{7,0,1839},{9,0,589},{11,0,241},{11,0,676},{11,0,811},{11,0,891
+},{12,0,140},{12,0,346},{12,0,479},{13,0,140},{13,0,381},{14,0,188},{18,0,30},{
+148,0,108},{5,0,416},{6,10,86},{6,10,603},{7,10,292},{7,10,561},{8,10,257},{8,10
+,382},{9,10,721},{9,10,778},{11,10,581},{140,10,466},{4,10,486},{133,10,491},{
+134,0,1300},{132,10,72},{7,0,847},{6,10,265},{7,11,430},{139,11,46},{5,11,602},{
+6,11,106},{7,11,1786},{7,11,1821},{7,11,2018},{9,11,418},{137,11,763},{5,0,358},
+{7,0,535},{7,0,1184},{10,0,662},{13,0,212},{13,0,304},{13,0,333},{145,0,98},{5,
+11,65},{6,11,416},{7,11,1720},{7,11,1924},{8,11,677},{10,11,109},{11,11,14},{11,
+11,70},{11,11,569},{11,11,735},{15,11,153},{148,11,80},{6,0,1823},{8,0,839},{8,0
+,852},{8,0,903},{10,0,940},{12,0,707},{140,0,775},{135,11,1229},{6,0,1522},{140,
+0,654},{136,11,595},{139,0,163},{141,0,314},{132,0,978},{4,0,601},{6,0,2035},{
+137,10,234},{5,10,815},{6,10,1688},{134,10,1755},{133,0,946},{136,0,434},{6,10,
+197},{136,10,205},{7,0,411},{7,0,590},{8,0,631},{9,0,323},{10,0,355},{11,0,491},
+{12,0,143},{12,0,402},{13,0,73},{14,0,408},{15,0,107},{146,0,71},{7,0,1467},{8,0
+,328},{10,0,544},{11,0,955},{12,0,13},{13,0,320},{145,0,83},{142,0,410},{11,0,
+511},{13,0,394},{14,0,298},{14,0,318},{146,0,103},{6,10,452},{7,10,312},{138,10,
+219},{138,10,589},{4,10,333},{9,10,176},{12,10,353},{141,10,187},{135,11,329},{
+132,11,469},{5,0,835},{134,0,483},{134,11,1743},{5,11,929},{6,11,340},{8,11,376}
+,{136,11,807},{134,10,1685},{132,0,677},{5,11,218},{7,11,1610},{138,11,83},{5,11
+,571},{135,11,1842},{132,11,455},{137,0,70},{135,0,1405},{7,10,135},{8,10,7},{8,
+10,62},{9,10,243},{10,10,658},{10,10,697},{11,10,456},{139,10,756},{9,10,395},{
+138,10,79},{137,0,108},{6,11,161},{7,11,372},{137,11,597},{132,11,349},{132,0,
+777},{132,0,331},{135,10,631},{133,0,747},{6,11,432},{6,11,608},{139,11,322},{
+138,10,835},{5,11,468},{7,11,1809},{10,11,325},{11,11,856},{12,11,345},{143,11,
+104},{133,11,223},{7,10,406},{7,10,459},{8,10,606},{139,10,726},{132,11,566},{
+142,0,68},{4,11,59},{135,11,1394},{6,11,436},{139,11,481},{4,11,48},{5,11,271},{
+135,11,953},{139,11,170},{5,11,610},{136,11,457},{133,11,755},{135,11,1217},{133
+,10,612},{132,11,197},{132,0,505},{4,10,372},{7,10,482},{8,10,158},{9,10,602},{9
+,10,615},{10,10,245},{10,10,678},{10,10,744},{11,10,248},{139,10,806},{133,0,326
+},{5,10,854},{135,10,1991},{4,0,691},{146,0,16},{6,0,628},{9,0,35},{10,0,680},{
+10,0,793},{11,0,364},{13,0,357},{143,0,164},{138,0,654},{6,0,32},{7,0,385},{7,0,
+757},{7,0,1916},{8,0,37},{8,0,94},{8,0,711},{9,0,541},{10,0,162},{10,0,795},{11,
+0,989},{11,0,1010},{12,0,14},{142,0,308},{133,11,217},{6,0,152},{6,0,349},{6,0,
+1682},{7,0,1252},{8,0,112},{9,0,435},{9,0,668},{10,0,290},{10,0,319},{10,0,815},
+{11,0,180},{11,0,837},{12,0,240},{13,0,152},{13,0,219},{142,0,158},{4,0,581},{
+134,0,726},{5,10,195},{135,10,1685},{6,0,126},{7,0,573},{8,0,397},{142,0,44},{
+138,0,89},{7,10,1997},{8,10,730},{139,10,1006},{134,0,1531},{134,0,1167},{5,0,
+926},{12,0,203},{133,10,751},{4,11,165},{7,11,1398},{135,11,1829},{7,0,1232},{
+137,0,531},{135,10,821},{134,0,943},{133,0,670},{4,0,880},{139,0,231},{134,0,
+1617},{135,0,1957},{5,11,9},{7,11,297},{7,11,966},{140,11,306},{6,0,975},{134,0,
+985},{5,10,950},{5,10,994},{134,10,351},{12,11,21},{151,11,7},{5,11,146},{6,11,
+411},{138,11,721},{7,0,242},{135,0,1942},{6,11,177},{135,11,467},{5,0,421},{7,10
+,47},{137,10,684},{5,0,834},{7,0,1202},{8,0,14},{9,0,481},{137,0,880},{138,0,465
+},{6,0,688},{9,0,834},{132,10,350},{132,0,855},{4,0,357},{6,0,172},{7,0,143},{
+137,0,413},{133,11,200},{132,0,590},{7,10,1812},{13,10,259},{13,10,356},{14,10,
+242},{147,10,114},{133,10,967},{11,0,114},{4,10,473},{7,10,623},{8,10,808},{9,10
+,871},{9,10,893},{11,10,431},{12,10,112},{12,10,217},{12,10,243},{12,10,562},{12
+,10,663},{12,10,683},{13,10,141},{13,10,197},{13,10,227},{13,10,406},{13,10,487}
+,{14,10,156},{14,10,203},{14,10,224},{14,10,256},{18,10,58},{150,10,0},{138,10,
+286},{4,10,222},{7,10,286},{136,10,629},{5,0,169},{7,0,333},{136,0,45},{134,11,
+481},{132,0,198},{4,0,24},{5,0,140},{5,0,185},{7,0,1500},{11,0,565},{11,0,838},{
+4,11,84},{7,11,1482},{10,11,76},{138,11,142},{133,0,585},{141,10,306},{133,11,
+1015},{4,11,315},{5,11,507},{135,11,1370},{136,10,146},{6,0,691},{134,0,1503},{4
+,0,334},{133,0,593},{4,10,465},{135,10,1663},{142,11,173},{135,0,913},{12,0,116}
+,{134,11,1722},{134,0,1360},{132,0,802},{8,11,222},{8,11,476},{9,11,238},{11,11,
+516},{11,11,575},{15,11,109},{146,11,100},{6,0,308},{9,0,673},{7,10,138},{7,10,
+517},{139,10,238},{132,0,709},{6,0,1876},{6,0,1895},{9,0,994},{9,0,1006},{12,0,
+829},{12,0,888},{12,0,891},{146,0,185},{148,10,94},{4,0,228},{133,0,897},{7,0,
+1840},{5,10,495},{7,10,834},{9,10,733},{139,10,378},{133,10,559},{6,10,21},{6,10
+,1737},{7,10,1444},{136,10,224},{4,0,608},{133,0,497},{6,11,40},{135,11,1781},{
+134,0,1573},{135,0,2039},{6,0,540},{136,0,136},{4,0,897},{5,0,786},{133,10,519},
+{6,0,1878},{6,0,1884},{9,0,938},{9,0,948},{9,0,955},{9,0,973},{9,0,1012},{12,0,
+895},{12,0,927},{143,0,254},{134,0,1469},{133,0,999},{4,0,299},{135,0,1004},{4,0
+,745},{133,0,578},{136,11,574},{133,0,456},{134,0,1457},{7,0,1679},{132,10,402},
+{7,0,693},{8,0,180},{12,0,163},{8,10,323},{136,10,479},{11,10,580},{142,10,201},
+{5,10,59},{135,10,672},{132,11,354},{146,10,34},{4,0,755},{135,11,1558},{7,0,
+1740},{146,0,48},{4,10,85},{135,10,549},{139,0,338},{133,10,94},{134,0,1091},{
+135,11,469},{12,0,695},{12,0,704},{20,0,113},{5,11,830},{14,11,338},{148,11,81},
+{135,0,1464},{6,10,11},{135,10,187},{135,0,975},{13,0,335},{132,10,522},{134,0,
+1979},{5,11,496},{135,11,203},{4,10,52},{135,10,661},{7,0,1566},{8,0,269},{9,0,
+212},{9,0,718},{14,0,15},{14,0,132},{142,0,227},{4,0,890},{5,0,805},{5,0,819},{5
+,0,961},{6,0,396},{6,0,1631},{6,0,1678},{7,0,1967},{7,0,2041},{9,0,630},{11,0,8}
+,{11,0,1019},{12,0,176},{13,0,225},{14,0,292},{21,0,24},{4,10,383},{133,10,520},
+{134,11,547},{135,11,1748},{5,11,88},{137,11,239},{146,11,128},{7,11,650},{135,
+11,1310},{4,10,281},{5,10,38},{7,10,194},{7,10,668},{7,10,1893},{137,10,397},{
+135,0,1815},{9,10,635},{139,10,559},{7,0,1505},{10,0,190},{10,0,634},{11,0,792},
+{12,0,358},{140,0,447},{5,0,0},{6,0,536},{7,0,604},{13,0,445},{145,0,126},{7,11,
+1076},{9,11,80},{11,11,78},{11,11,421},{11,11,534},{140,11,545},{8,0,966},{10,0,
+1023},{14,11,369},{146,11,72},{135,11,1641},{6,0,232},{6,0,412},{7,0,1074},{8,0,
+9},{8,0,157},{8,0,786},{9,0,196},{9,0,352},{9,0,457},{10,0,337},{11,0,232},{11,0
+,877},{12,0,480},{140,0,546},{135,0,958},{4,0,382},{136,0,579},{4,0,212},{135,0,
+1206},{4,11,497},{5,11,657},{135,11,1584},{132,0,681},{8,0,971},{138,0,965},{5,
+10,448},{136,10,535},{14,0,16},{146,0,44},{11,0,584},{11,0,616},{14,0,275},{11,
+11,584},{11,11,616},{142,11,275},{136,11,13},{7,10,610},{135,10,1501},{7,11,642}
+,{8,11,250},{11,11,123},{11,11,137},{13,11,48},{142,11,95},{133,0,655},{17,0,67}
+,{147,0,74},{134,0,751},{134,0,1967},{6,0,231},{136,0,423},{5,0,300},{138,0,1016
+},{4,10,319},{5,10,699},{138,10,673},{6,0,237},{7,0,611},{8,0,100},{9,0,416},{11
+,0,335},{12,0,173},{18,0,101},{6,10,336},{8,10,552},{9,10,285},{10,10,99},{139,
+10,568},{134,0,1370},{7,10,1406},{9,10,218},{141,10,222},{133,10,256},{135,0,
+1208},{14,11,213},{148,11,38},{6,0,1219},{135,11,1642},{13,0,417},{14,0,129},{
+143,0,15},{10,11,545},{140,11,301},{17,10,39},{148,10,36},{133,0,199},{4,11,904}
+,{133,11,794},{12,0,427},{146,0,38},{134,0,949},{8,0,665},{135,10,634},{132,10,
+618},{135,10,259},{132,10,339},{133,11,761},{141,10,169},{132,10,759},{5,0,688},
+{7,0,539},{135,0,712},{7,11,386},{138,11,713},{134,0,1186},{6,11,7},{6,11,35},{7
+,11,147},{7,11,1069},{7,11,1568},{7,11,1575},{7,11,1917},{8,11,43},{8,11,208},{9
+,11,128},{9,11,866},{10,11,20},{11,11,981},{147,11,33},{7,11,893},{8,10,482},{
+141,11,424},{6,0,312},{6,0,1715},{10,0,584},{11,0,546},{11,0,692},{12,0,259},{12
+,0,295},{13,0,46},{141,0,154},{5,10,336},{6,10,341},{6,10,478},{6,10,1763},{136,
+10,386},{137,0,151},{132,0,588},{152,0,4},{6,11,322},{9,11,552},{11,11,274},{13,
+11,209},{13,11,499},{14,11,85},{15,11,126},{145,11,70},{135,10,73},{4,0,231},{5,
+0,61},{6,0,104},{7,0,729},{7,0,964},{7,0,1658},{140,0,414},{6,0,263},{138,0,757}
+,{135,10,1971},{4,0,612},{133,0,561},{132,0,320},{135,10,1344},{8,11,83},{8,11,
+817},{9,11,28},{9,11,29},{9,11,885},{10,11,387},{11,11,633},{11,11,740},{13,11,
+235},{13,11,254},{15,11,143},{143,11,146},{5,10,396},{134,10,501},{140,11,49},{
+132,0,225},{4,10,929},{5,10,799},{8,10,46},{136,10,740},{4,0,405},{7,0,817},{14,
+0,58},{17,0,37},{146,0,124},{133,0,974},{4,11,412},{133,11,581},{4,10,892},{133,
+10,770},{4,0,996},{134,0,2026},{4,0,527},{5,0,235},{7,0,1239},{11,0,131},{140,0,
+370},{9,0,16},{13,0,386},{135,11,421},{7,0,956},{7,0,1157},{7,0,1506},{7,0,1606}
+,{7,0,1615},{7,0,1619},{7,0,1736},{7,0,1775},{8,0,590},{9,0,324},{9,0,736},{9,0,
+774},{9,0,776},{9,0,784},{10,0,567},{10,0,708},{11,0,518},{11,0,613},{11,0,695},
+{11,0,716},{11,0,739},{11,0,770},{11,0,771},{11,0,848},{11,0,857},{11,0,931},{11
+,0,947},{12,0,326},{12,0,387},{12,0,484},{12,0,528},{12,0,552},{12,0,613},{13,0,
+189},{13,0,256},{13,0,340},{13,0,432},{13,0,436},{13,0,440},{13,0,454},{14,0,174
+},{14,0,220},{14,0,284},{14,0,390},{145,0,121},{135,10,158},{9,0,137},{138,0,221
+},{4,11,110},{10,11,415},{10,11,597},{142,11,206},{141,11,496},{135,11,205},{151
+,10,25},{135,11,778},{7,11,1656},{7,10,2001},{9,11,369},{10,11,338},{10,11,490},
+{11,11,154},{11,11,545},{11,11,775},{13,11,77},{141,11,274},{4,11,444},{10,11,
+146},{140,11,9},{7,0,390},{138,0,140},{135,0,1144},{134,0,464},{7,10,1461},{140,
+10,91},{132,10,602},{4,11,283},{135,11,1194},{5,0,407},{11,0,204},{11,0,243},{11
+,0,489},{12,0,293},{19,0,37},{20,0,73},{150,0,38},{7,0,1218},{136,0,303},{5,0,
+325},{8,0,5},{8,0,227},{9,0,105},{10,0,585},{12,0,614},{4,10,13},{5,10,567},{7,
+10,1498},{9,10,124},{11,10,521},{140,10,405},{135,10,1006},{7,0,800},{10,0,12},{
+134,11,1720},{135,0,1783},{132,10,735},{138,10,812},{4,10,170},{135,10,323},{6,0
+,621},{13,0,504},{144,0,89},{5,10,304},{135,10,1403},{137,11,216},{6,0,920},{6,0
+,1104},{9,11,183},{139,11,286},{4,0,376},{133,10,742},{134,0,218},{8,0,641},{11,
+0,388},{140,0,580},{7,0,454},{7,0,782},{8,0,768},{140,0,686},{137,11,33},{133,10
+,111},{144,0,0},{10,0,676},{140,0,462},{6,0,164},{136,11,735},{133,10,444},{150,
+0,50},{7,11,1862},{12,11,491},{12,11,520},{13,11,383},{14,11,244},{146,11,12},{5
+,11,132},{9,11,486},{9,11,715},{10,11,458},{11,11,373},{11,11,668},{11,11,795},{
+11,11,897},{12,11,272},{12,11,424},{12,11,539},{12,11,558},{14,11,245},{14,11,
+263},{14,11,264},{14,11,393},{142,11,403},{8,10,123},{15,10,6},{144,10,7},{6,0,
+285},{8,0,654},{11,0,749},{12,0,190},{12,0,327},{13,0,120},{13,0,121},{13,0,327}
+,{15,0,47},{146,0,40},{5,11,8},{6,11,89},{6,11,400},{7,11,1569},{7,11,1623},{7,
+11,1850},{8,11,218},{8,11,422},{9,11,570},{138,11,626},{6,11,387},{7,11,882},{
+141,11,111},{6,0,343},{7,0,195},{9,0,226},{10,0,197},{10,0,575},{11,0,502},{11,0
+,899},{6,11,224},{7,11,877},{137,11,647},{5,10,937},{135,10,100},{135,11,790},{
+150,0,29},{147,0,8},{134,0,1812},{149,0,8},{135,11,394},{7,0,1125},{9,0,143},{11
+,0,61},{14,0,405},{150,0,21},{10,11,755},{147,11,29},{9,11,378},{141,11,162},{
+135,10,922},{5,10,619},{133,10,698},{134,0,1327},{6,0,1598},{137,0,575},{9,11,
+569},{12,11,12},{12,11,81},{12,11,319},{13,11,69},{14,11,259},{16,11,87},{17,11,
+1},{17,11,21},{17,11,24},{18,11,15},{18,11,56},{18,11,59},{18,11,127},{18,11,154
+},{19,11,19},{148,11,31},{6,0,895},{135,11,1231},{5,0,959},{7,11,124},{136,11,38
+},{5,11,261},{7,11,78},{7,11,199},{8,11,815},{9,11,126},{138,11,342},{5,10,917},
+{134,10,1659},{7,0,1759},{5,11,595},{135,11,1863},{136,0,173},{134,0,266},{142,0
+,261},{132,11,628},{5,10,251},{5,10,956},{8,10,268},{9,10,214},{146,10,142},{7,
+11,266},{136,11,804},{135,11,208},{6,11,79},{7,11,1021},{135,11,1519},{11,11,704
+},{141,11,396},{5,10,346},{5,10,711},{136,10,390},{136,11,741},{134,11,376},{134
+,0,1427},{6,0,1033},{6,0,1217},{136,0,300},{133,10,624},{6,11,100},{7,11,244},{7
+,11,632},{7,11,1609},{8,11,178},{8,11,638},{141,11,58},{6,0,584},{5,10,783},{7,
+10,1998},{135,10,2047},{5,0,427},{5,0,734},{7,0,478},{136,0,52},{7,0,239},{11,0,
+217},{142,0,165},{134,0,1129},{6,0,168},{6,0,1734},{7,0,20},{7,0,1056},{8,0,732}
+,{9,0,406},{9,0,911},{138,0,694},{132,10,594},{133,11,791},{7,11,686},{8,11,33},
+{8,11,238},{10,11,616},{11,11,467},{11,11,881},{13,11,217},{13,11,253},{142,11,
+268},{137,11,476},{134,0,418},{133,0,613},{132,0,632},{132,11,447},{7,0,32},{7,0
+,984},{8,0,85},{8,0,709},{9,0,579},{9,0,847},{9,0,856},{10,0,799},{11,0,258},{11
+,0,1007},{12,0,331},{12,0,615},{13,0,188},{13,0,435},{14,0,8},{15,0,165},{16,0,
+27},{20,0,40},{144,11,35},{4,11,128},{5,11,415},{6,11,462},{7,11,294},{7,11,578}
+,{10,11,710},{139,11,86},{5,0,694},{136,0,909},{7,0,1109},{11,0,7},{5,10,37},{6,
+10,39},{6,10,451},{7,10,218},{7,10,1166},{7,10,1687},{8,10,662},{144,10,2},{136,
+11,587},{6,11,427},{7,11,1018},{138,11,692},{4,11,195},{6,10,508},{135,11,802},{
+4,0,167},{135,0,82},{5,0,62},{6,0,24},{6,0,534},{7,0,74},{7,0,678},{7,0,684},{7,
+0,1043},{7,0,1072},{8,0,280},{8,0,541},{8,0,686},{9,0,258},{10,0,519},{11,0,252}
+,{140,0,282},{138,0,33},{4,0,359},{133,11,738},{7,0,980},{9,0,328},{13,0,186},{
+13,0,364},{7,10,635},{7,10,796},{8,10,331},{9,10,330},{9,10,865},{10,10,119},{10
+,10,235},{11,10,111},{11,10,129},{11,10,240},{12,10,31},{12,10,66},{12,10,222},{
+12,10,269},{12,10,599},{12,10,684},{12,10,689},{12,10,691},{142,10,345},{137,10,
+527},{6,0,596},{7,0,585},{135,10,702},{134,11,1683},{133,0,211},{6,0,145},{141,0
+,336},{134,0,1130},{7,0,873},{6,10,37},{7,10,1666},{8,10,195},{8,10,316},{9,10,
+178},{9,10,276},{9,10,339},{9,10,536},{10,10,102},{10,10,362},{10,10,785},{11,10
+,55},{11,10,149},{11,10,773},{13,10,416},{13,10,419},{14,10,38},{14,10,41},{142,
+10,210},{8,0,840},{136,0,841},{132,0,263},{5,11,3},{8,11,578},{9,11,118},{10,11,
+705},{12,11,383},{141,11,279},{132,0,916},{133,11,229},{133,10,645},{15,0,155},{
+16,0,79},{8,11,102},{10,11,578},{10,11,672},{12,11,496},{13,11,408},{14,11,121},
+{145,11,106},{4,0,599},{5,0,592},{6,0,1634},{7,0,5},{7,0,55},{7,0,67},{7,0,97},{
+7,0,691},{7,0,979},{7,0,1600},{7,0,1697},{8,0,207},{8,0,214},{8,0,231},{8,0,294}
+,{8,0,336},{8,0,428},{8,0,471},{8,0,622},{8,0,626},{8,0,679},{8,0,759},{8,0,829}
+,{9,0,11},{9,0,246},{9,0,484},{9,0,573},{9,0,706},{9,0,762},{9,0,798},{9,0,855},
+{9,0,870},{9,0,912},{10,0,303},{10,0,335},{10,0,424},{10,0,461},{10,0,543},{10,0
+,759},{10,0,814},{11,0,59},{11,0,199},{11,0,235},{11,0,590},{11,0,631},{11,0,929
+},{11,0,963},{11,0,987},{12,0,114},{12,0,182},{12,0,226},{12,0,332},{12,0,439},{
+12,0,575},{12,0,598},{12,0,675},{13,0,8},{13,0,125},{13,0,194},{13,0,287},{14,0,
+197},{14,0,383},{15,0,53},{17,0,63},{19,0,46},{19,0,98},{19,0,106},{148,0,85},{7
+,0,1356},{132,10,290},{6,10,70},{7,10,1292},{10,10,762},{139,10,288},{150,11,55}
+,{4,0,593},{8,11,115},{8,11,350},{9,11,489},{10,11,128},{11,11,306},{12,11,373},
+{14,11,30},{17,11,79},{147,11,80},{135,11,1235},{134,0,1392},{4,11,230},{133,11,
+702},{147,0,126},{7,10,131},{7,10,422},{8,10,210},{140,10,573},{134,0,1179},{139
+,11,435},{139,10,797},{134,11,1728},{4,0,162},{18,11,26},{19,11,42},{20,11,43},{
+21,11,0},{23,11,27},{152,11,14},{132,10,936},{6,0,765},{5,10,453},{134,10,441},{
+133,0,187},{135,0,1286},{6,0,635},{6,0,904},{6,0,1210},{134,0,1489},{4,0,215},{8
+,0,890},{9,0,38},{10,0,923},{11,0,23},{11,0,127},{139,0,796},{6,0,1165},{134,0,
+1306},{7,0,716},{13,0,97},{141,0,251},{132,10,653},{136,0,657},{146,10,80},{5,11
+,622},{7,11,1032},{11,11,26},{11,11,213},{11,11,707},{12,11,380},{13,11,226},{
+141,11,355},{6,0,299},{5,11,70},{6,11,334},{9,11,171},{11,11,637},{12,11,202},{
+14,11,222},{145,11,42},{142,0,134},{4,11,23},{5,11,313},{5,11,1014},{6,11,50},{6
+,11,51},{7,11,142},{7,11,384},{9,11,783},{139,11,741},{4,11,141},{7,11,559},{8,
+11,640},{9,11,460},{12,11,183},{141,11,488},{136,11,614},{7,10,1368},{8,10,232},
+{8,10,361},{10,10,682},{138,10,742},{137,10,534},{6,0,1082},{140,0,658},{137,10,
+27},{135,0,2002},{142,10,12},{4,0,28},{5,0,440},{7,0,248},{11,0,833},{140,0,344}
+,{7,10,736},{139,10,264},{134,10,1657},{134,0,1654},{138,0,531},{5,11,222},{9,11
+,140},{138,11,534},{6,0,634},{6,0,798},{134,0,840},{138,11,503},{135,10,127},{
+133,0,853},{5,11,154},{7,11,1491},{10,11,379},{138,11,485},{6,0,249},{7,0,1234},
+{139,0,573},{133,11,716},{7,11,1570},{140,11,542},{136,10,364},{138,0,527},{4,11
+,91},{5,11,388},{5,11,845},{6,11,206},{6,11,252},{6,11,365},{7,11,136},{7,11,531
+},{8,11,264},{136,11,621},{134,0,1419},{135,11,1441},{7,0,49},{7,0,392},{8,0,20}
+,{8,0,172},{8,0,690},{9,0,383},{9,0,845},{10,0,48},{11,0,293},{11,0,832},{11,0,
+920},{11,0,984},{141,0,221},{5,0,858},{133,0,992},{5,0,728},{137,10,792},{5,10,
+909},{9,10,849},{138,10,805},{7,0,525},{7,0,1579},{8,0,497},{136,0,573},{6,0,268
+},{137,0,62},{135,11,576},{134,0,1201},{5,11,771},{5,11,863},{5,11,898},{6,11,
+1632},{6,11,1644},{134,11,1780},{133,11,331},{7,0,193},{7,0,1105},{10,0,495},{7,
+10,397},{8,10,124},{8,10,619},{9,10,305},{11,10,40},{12,10,349},{13,10,134},{13,
+10,295},{14,10,155},{15,10,120},{146,10,105},{138,0,106},{6,0,859},{5,11,107},{7
+,11,201},{136,11,518},{6,11,446},{135,11,1817},{13,0,23},{4,10,262},{135,10,342}
+,{133,10,641},{137,11,851},{6,0,925},{137,0,813},{132,11,504},{6,0,613},{136,0,
+223},{4,10,99},{6,10,250},{6,10,346},{8,10,127},{138,10,81},{136,0,953},{132,10,
+915},{139,11,892},{5,10,75},{9,10,517},{10,10,470},{12,10,155},{141,10,224},{4,0
+,666},{7,0,1017},{7,11,996},{138,11,390},{5,11,883},{133,11,975},{14,10,83},{142
+,11,83},{4,0,670},{5,11,922},{134,11,1707},{135,0,216},{9,0,40},{11,0,136},{135,
+11,787},{5,10,954},{5,11,993},{7,11,515},{137,11,91},{139,0,259},{7,0,1114},{9,0
+,310},{9,0,682},{10,0,440},{13,0,40},{6,10,304},{8,10,418},{11,10,341},{139,10,
+675},{14,0,296},{9,10,410},{139,10,425},{10,11,377},{12,11,363},{13,11,68},{13,
+11,94},{14,11,108},{142,11,306},{7,0,1401},{135,0,1476},{4,0,296},{6,0,475},{7,0
+,401},{7,0,1410},{7,0,1594},{7,0,1674},{8,0,63},{8,0,660},{137,0,74},{4,0,139},{
+4,0,388},{140,0,188},{132,0,797},{132,11,766},{5,11,103},{7,11,921},{8,11,580},{
+8,11,593},{8,11,630},{138,11,28},{4,11,911},{5,11,867},{133,11,1013},{134,10,14}
+,{134,0,1572},{134,10,1708},{21,0,39},{5,10,113},{6,10,243},{7,10,1865},{11,10,
+161},{16,10,37},{145,10,99},{7,11,1563},{141,11,182},{5,11,135},{6,11,519},{7,11
+,1722},{10,11,271},{11,11,261},{145,11,54},{132,10,274},{134,0,1594},{4,11,300},
+{5,11,436},{135,11,484},{4,0,747},{6,0,290},{7,0,649},{7,0,1479},{135,0,1583},{
+133,11,535},{147,11,82},{133,0,232},{137,0,887},{135,10,166},{136,0,521},{4,0,14
+},{7,0,472},{7,0,1801},{10,0,748},{141,0,458},{134,0,741},{134,0,992},{16,0,111}
+,{137,10,304},{4,0,425},{5,11,387},{7,11,557},{12,11,547},{142,11,86},{135,11,
+1747},{5,10,654},{135,11,1489},{7,0,789},{4,11,6},{5,11,708},{136,11,75},{6,10,
+273},{10,10,188},{13,10,377},{146,10,77},{6,0,1593},{4,11,303},{7,11,619},{10,11
+,547},{10,11,687},{11,11,122},{140,11,601},{134,0,1768},{135,10,410},{138,11,772
+},{11,0,233},{139,10,524},{5,0,943},{134,0,1779},{134,10,1785},{136,11,529},{132
+,0,955},{5,0,245},{6,0,576},{7,0,582},{136,0,225},{132,10,780},{142,0,241},{134,
+0,1943},{4,11,106},{7,11,310},{7,11,1785},{10,11,690},{139,11,717},{134,0,1284},
+{5,11,890},{133,11,988},{6,11,626},{142,11,431},{10,11,706},{145,11,32},{137,11,
+332},{132,11,698},{135,0,709},{5,10,948},{138,11,17},{136,0,554},{134,0,1564},{
+139,10,941},{132,0,443},{134,0,909},{134,11,84},{142,0,280},{4,10,532},{5,10,706
+},{135,10,662},{132,0,729},{5,10,837},{6,10,1651},{139,10,985},{135,10,1861},{4,
+0,348},{152,11,3},{5,11,986},{6,11,130},{7,11,1582},{8,11,458},{10,11,101},{10,
+11,318},{138,11,823},{134,0,758},{4,0,298},{137,0,848},{4,10,330},{7,10,933},{7,
+10,2012},{136,10,292},{7,11,1644},{137,11,129},{6,0,1422},{9,0,829},{135,10,767}
+,{5,0,164},{7,0,121},{142,0,189},{7,0,812},{7,0,1261},{7,0,1360},{9,0,632},{140,
+0,352},{135,11,1788},{139,0,556},{135,11,997},{145,10,114},{4,0,172},{9,0,611},{
+10,0,436},{12,0,673},{13,0,255},{137,10,883},{11,0,530},{138,10,274},{133,0,844}
+,{134,0,984},{13,0,232},{18,0,35},{4,10,703},{135,10,207},{132,10,571},{9,0,263}
+,{10,0,147},{138,0,492},{7,11,1756},{137,11,98},{5,10,873},{5,10,960},{8,10,823}
+,{137,10,881},{133,0,537},{132,0,859},{7,11,1046},{139,11,160},{137,0,842},{139,
+10,283},{5,10,33},{6,10,470},{139,10,424},{6,11,45},{7,11,433},{8,11,129},{9,11,
+21},{10,11,392},{11,11,79},{12,11,499},{13,11,199},{141,11,451},{135,0,1291},{
+135,10,1882},{7,11,558},{136,11,353},{134,0,1482},{5,0,230},{5,0,392},{6,0,420},
+{9,0,568},{140,0,612},{6,0,262},{7,10,90},{7,10,664},{7,10,830},{7,10,1380},{7,
+10,2025},{8,11,81},{8,10,448},{8,10,828},{9,11,189},{9,11,201},{11,11,478},{11,
+11,712},{141,11,338},{142,0,31},{5,11,353},{151,11,26},{132,0,753},{4,0,0},{5,0,
+41},{7,0,1459},{7,0,1469},{7,0,1859},{9,0,549},{139,0,905},{9,10,417},{137,10,
+493},{135,11,1113},{133,0,696},{141,11,448},{134,10,295},{132,0,834},{4,0,771},{
+5,10,1019},{6,11,25},{7,11,855},{7,11,1258},{144,11,32},{134,0,1076},{133,0,921}
+,{133,0,674},{4,11,4},{7,11,1118},{7,11,1320},{7,11,1706},{8,11,277},{9,11,622},
+{10,11,9},{11,11,724},{12,11,350},{12,11,397},{13,11,28},{13,11,159},{15,11,89},
+{18,11,5},{19,11,9},{20,11,34},{150,11,47},{134,10,208},{6,0,444},{136,0,308},{6
+,0,180},{7,0,1137},{8,0,751},{139,0,805},{4,0,183},{7,0,271},{11,0,824},{11,0,
+952},{13,0,278},{13,0,339},{13,0,482},{14,0,424},{148,0,99},{7,11,317},{135,11,
+569},{4,0,19},{5,0,477},{5,0,596},{6,0,505},{7,0,1221},{11,0,907},{12,0,209},{
+141,0,214},{135,0,1215},{6,0,271},{7,0,398},{8,0,387},{10,0,344},{7,10,448},{7,
+10,1629},{7,10,1813},{8,10,442},{9,10,710},{10,10,282},{138,10,722},{11,10,844},
+{12,10,104},{140,10,625},{134,11,255},{133,10,787},{134,0,1645},{11,11,956},{151
+,11,3},{6,0,92},{6,0,188},{7,0,209},{7,0,1269},{7,0,1524},{7,0,1876},{8,0,661},{
+10,0,42},{10,0,228},{11,0,58},{11,0,1020},{12,0,58},{12,0,118},{141,0,32},{4,0,
+459},{133,0,966},{4,11,536},{7,11,1141},{10,11,723},{139,11,371},{140,0,330},{
+134,0,1557},{7,11,285},{135,11,876},{136,10,491},{135,11,560},{6,0,18},{7,0,179}
+,{7,0,932},{8,0,548},{8,0,757},{9,0,54},{9,0,65},{9,0,532},{9,0,844},{10,0,113},
+{10,0,117},{10,0,315},{10,0,560},{10,0,622},{10,0,798},{11,0,153},{11,0,351},{11
+,0,375},{12,0,78},{12,0,151},{12,0,392},{12,0,666},{14,0,248},{143,0,23},{6,0,
+1742},{132,11,690},{4,10,403},{5,10,441},{7,10,450},{10,10,840},{11,10,101},{12,
+10,193},{141,10,430},{133,0,965},{134,0,182},{10,0,65},{10,0,488},{138,0,497},{
+135,11,1346},{6,0,973},{6,0,1158},{10,11,200},{19,11,2},{151,11,22},{4,11,190},{
+133,11,554},{133,10,679},{7,0,328},{137,10,326},{133,11,1001},{9,0,588},{138,0,
+260},{133,11,446},{135,10,1128},{135,10,1796},{147,11,119},{134,0,1786},{6,0,
+1328},{6,0,1985},{8,0,962},{138,0,1017},{135,0,308},{11,0,508},{4,10,574},{7,10,
+350},{7,10,1024},{8,10,338},{9,10,677},{138,10,808},{138,11,752},{135,10,1081},{
+137,11,96},{7,10,1676},{135,10,2037},{136,0,588},{132,11,304},{133,0,614},{140,0
+,793},{136,0,287},{137,10,297},{141,10,37},{6,11,53},{6,11,199},{7,11,1408},{8,
+11,32},{8,11,93},{9,11,437},{10,11,397},{10,11,629},{11,11,593},{11,11,763},{13,
+11,326},{145,11,35},{134,11,105},{9,11,320},{10,11,506},{138,11,794},{5,11,114},
+{5,11,255},{141,11,285},{140,0,290},{7,11,2035},{8,11,19},{9,11,89},{138,11,831}
+,{134,0,1136},{7,0,719},{8,0,796},{8,0,809},{8,0,834},{6,10,306},{7,10,1140},{7,
+10,1340},{8,10,133},{138,10,449},{139,10,1011},{5,0,210},{6,0,213},{7,0,60},{10,
+0,364},{139,0,135},{5,0,607},{8,0,326},{136,0,490},{138,11,176},{132,0,701},{5,0
+,472},{7,0,380},{137,0,758},{135,0,1947},{6,0,1079},{138,0,278},{138,11,391},{5,
+10,329},{8,10,260},{139,11,156},{4,0,386},{7,0,41},{8,0,405},{8,0,728},{9,0,497}
+,{11,0,110},{11,0,360},{15,0,37},{144,0,84},{5,0,46},{7,0,1452},{7,0,1480},{8,0,
+634},{140,0,472},{136,0,961},{4,0,524},{136,0,810},{10,0,238},{141,0,33},{132,10
+,657},{152,10,7},{133,0,532},{5,0,997},{135,10,1665},{7,11,594},{7,11,851},{7,11
+,1858},{9,11,411},{9,11,574},{9,11,666},{9,11,737},{10,11,346},{10,11,712},{11,
+11,246},{11,11,432},{11,11,517},{11,11,647},{11,11,679},{11,11,727},{12,11,304},
+{12,11,305},{12,11,323},{12,11,483},{12,11,572},{12,11,593},{12,11,602},{13,11,
+95},{13,11,101},{13,11,171},{13,11,315},{13,11,378},{13,11,425},{13,11,475},{14,
+11,63},{14,11,380},{14,11,384},{15,11,133},{18,11,112},{148,11,72},{5,11,955},{
+136,11,814},{134,0,1301},{5,10,66},{7,10,1896},{136,10,288},{133,11,56},{134,10,
+1643},{6,0,1298},{148,11,100},{5,0,782},{5,0,829},{6,0,671},{6,0,1156},{6,0,1738
+},{137,11,621},{4,0,306},{5,0,570},{7,0,1347},{5,10,91},{5,10,648},{5,10,750},{5
+,10,781},{6,10,54},{6,10,112},{6,10,402},{6,10,1732},{7,10,315},{7,10,749},{7,10
+,1900},{9,10,78},{9,10,508},{10,10,611},{10,10,811},{11,10,510},{11,10,728},{13,
+10,36},{14,10,39},{16,10,83},{17,10,124},{148,10,30},{8,10,570},{9,11,477},{141,
+11,78},{4,11,639},{10,11,4},{10,10,322},{10,10,719},{11,10,407},{11,11,638},{12,
+11,177},{148,11,57},{7,0,1823},{139,0,693},{7,0,759},{5,11,758},{8,10,125},{8,10
+,369},{8,10,524},{10,10,486},{11,10,13},{11,10,381},{11,10,736},{11,10,766},{11,
+10,845},{13,10,114},{13,10,292},{142,10,47},{7,0,1932},{6,10,1684},{6,10,1731},{
+7,10,356},{8,10,54},{8,10,221},{9,10,225},{9,10,356},{10,10,77},{10,10,446},{10,
+10,731},{12,10,404},{141,10,491},{135,11,552},{135,11,1112},{4,0,78},{5,0,96},{5
+,0,182},{6,0,1257},{7,0,1724},{7,0,1825},{10,0,394},{10,0,471},{11,0,532},{14,0,
+340},{145,0,88},{139,11,328},{135,0,1964},{132,10,411},{4,10,80},{5,10,44},{137,
+11,133},{5,11,110},{6,11,169},{6,11,1702},{7,11,400},{8,11,538},{9,11,184},{9,11
+,524},{140,11,218},{4,0,521},{5,10,299},{7,10,1083},{140,11,554},{6,11,133},{9,
+11,353},{12,11,628},{146,11,79},{6,0,215},{7,0,584},{7,0,1028},{7,0,1473},{7,0,
+1721},{9,0,424},{138,0,779},{7,0,857},{7,0,1209},{7,10,1713},{9,10,537},{10,10,
+165},{12,10,219},{140,10,561},{4,10,219},{6,11,93},{7,11,1422},{7,10,1761},{7,11
+,1851},{8,11,673},{9,10,86},{9,11,529},{140,11,43},{137,11,371},{136,0,671},{5,0
+,328},{135,0,918},{132,0,529},{9,11,25},{10,11,467},{138,11,559},{4,11,335},{135
+,11,942},{134,0,716},{134,0,1509},{6,0,67},{7,0,258},{7,0,1630},{9,0,354},{9,0,
+675},{10,0,830},{14,0,80},{17,0,80},{140,10,428},{134,0,1112},{6,0,141},{7,0,225
+},{9,0,59},{9,0,607},{10,0,312},{11,0,687},{12,0,555},{13,0,373},{13,0,494},{148
+,0,58},{133,10,514},{8,11,39},{10,11,773},{11,11,84},{12,11,205},{142,11,1},{8,0
+,783},{5,11,601},{133,11,870},{136,11,594},{4,10,55},{5,10,301},{6,10,571},{14,
+10,49},{146,10,102},{132,11,181},{134,11,1652},{133,10,364},{4,11,97},{5,11,147}
+,{6,11,286},{7,11,1362},{141,11,176},{4,10,76},{7,10,1550},{9,10,306},{9,10,430}
+,{9,10,663},{10,10,683},{11,10,427},{11,10,753},{12,10,334},{12,10,442},{14,10,
+258},{14,10,366},{143,10,131},{137,10,52},{6,0,955},{134,0,1498},{6,11,375},{7,
+11,169},{7,11,254},{136,11,780},{7,0,430},{11,0,46},{14,0,343},{142,11,343},{135
+,0,1183},{5,0,602},{7,0,2018},{9,0,418},{9,0,803},{135,11,1447},{8,0,677},{135,
+11,1044},{139,11,285},{4,10,656},{135,10,779},{135,10,144},{5,11,629},{135,11,
+1549},{135,10,1373},{138,11,209},{7,10,554},{7,10,605},{141,10,10},{5,10,838},{5
+,10,841},{134,10,1649},{133,10,1012},{6,0,1357},{134,0,1380},{144,0,53},{6,0,590
+},{7,10,365},{7,10,1357},{7,10,1497},{8,10,154},{141,10,281},{133,10,340},{132,
+11,420},{135,0,329},{147,11,32},{4,0,469},{10,11,429},{139,10,495},{8,10,261},{9
+,10,144},{9,10,466},{10,10,370},{12,10,470},{13,10,144},{142,10,348},{142,0,460}
+,{4,11,325},{9,10,897},{138,11,125},{6,0,1743},{6,10,248},{9,10,546},{10,10,535}
+,{11,10,681},{141,10,135},{4,0,990},{5,0,929},{6,0,340},{8,0,376},{8,0,807},{8,0
+,963},{8,0,980},{138,0,1007},{134,0,1603},{140,0,250},{4,11,714},{133,11,469},{
+134,10,567},{136,10,445},{5,0,218},{7,0,1610},{8,0,646},{10,0,83},{11,11,138},{
+140,11,40},{7,0,1512},{135,0,1794},{135,11,1216},{11,0,0},{16,0,78},{132,11,718}
+,{133,0,571},{132,0,455},{134,0,1012},{5,11,124},{5,11,144},{6,11,548},{7,11,15}
+,{7,11,153},{137,11,629},{142,11,10},{6,11,75},{7,11,1531},{8,11,416},{9,11,240}
+,{9,11,275},{10,11,100},{11,11,658},{11,11,979},{12,11,86},{13,11,468},{14,11,66
+},{14,11,207},{15,11,20},{15,11,25},{144,11,58},{132,10,577},{5,11,141},{5,11,
+915},{6,11,1783},{7,11,211},{7,11,698},{7,11,1353},{9,11,83},{9,11,281},{10,11,
+376},{10,11,431},{11,11,543},{12,11,664},{13,11,280},{13,11,428},{14,11,61},{14,
+11,128},{17,11,52},{145,11,81},{6,0,161},{7,0,372},{137,0,597},{132,0,349},{10,
+11,702},{139,11,245},{134,0,524},{134,10,174},{6,0,432},{9,0,751},{139,0,322},{
+147,11,94},{4,11,338},{133,11,400},{5,0,468},{10,0,325},{11,0,856},{12,0,345},{
+143,0,104},{133,0,223},{132,0,566},{4,11,221},{5,11,659},{5,11,989},{7,11,697},{
+7,11,1211},{138,11,284},{135,11,1070},{4,0,59},{135,0,1394},{6,0,436},{11,0,481}
+,{5,10,878},{133,10,972},{4,0,48},{5,0,271},{135,0,953},{5,0,610},{136,0,457},{4
+,0,773},{5,0,618},{137,0,756},{133,0,755},{135,0,1217},{138,11,507},{132,10,351}
+,{132,0,197},{143,11,78},{4,11,188},{7,11,805},{11,11,276},{142,11,293},{5,11,
+884},{139,11,991},{132,10,286},{10,0,259},{10,0,428},{7,10,438},{7,10,627},{7,10
+,1516},{8,10,40},{9,10,56},{9,10,294},{11,10,969},{11,10,995},{146,10,148},{4,0,
+356},{5,0,217},{5,0,492},{5,0,656},{8,0,544},{136,11,544},{5,0,259},{6,0,1230},{
+7,0,414},{7,0,854},{142,0,107},{132,0,1007},{15,0,14},{144,0,5},{6,0,1580},{132,
+10,738},{132,11,596},{132,0,673},{133,10,866},{6,0,1843},{135,11,1847},{4,0,165}
+,{7,0,1398},{135,0,1829},{135,11,1634},{147,11,65},{6,0,885},{6,0,1009},{137,0,
+809},{133,10,116},{132,10,457},{136,11,770},{9,0,498},{12,0,181},{10,11,361},{
+142,11,316},{134,11,595},{5,0,9},{7,0,297},{7,0,966},{140,0,306},{4,11,89},{5,11
+,489},{6,11,315},{7,11,553},{7,11,1745},{138,11,243},{134,0,1487},{132,0,437},{5
+,0,146},{6,0,411},{138,0,721},{5,10,527},{6,10,189},{135,10,859},{11,10,104},{11
+,10,554},{15,10,60},{143,10,125},{6,11,1658},{9,11,3},{10,11,154},{11,11,641},{
+13,11,85},{13,11,201},{141,11,346},{6,0,177},{135,0,467},{134,0,1377},{134,10,
+116},{136,11,645},{4,11,166},{5,11,505},{6,11,1670},{137,11,110},{133,10,487},{4
+,10,86},{5,10,667},{5,10,753},{6,10,316},{6,10,455},{135,10,946},{133,0,200},{
+132,0,959},{6,0,1928},{134,0,1957},{139,11,203},{150,10,45},{4,10,79},{7,10,1773
+},{10,10,450},{11,10,589},{13,10,332},{13,10,493},{14,10,183},{14,10,334},{14,10
+,362},{14,10,368},{14,10,376},{14,10,379},{19,10,90},{19,10,103},{19,10,127},{
+148,10,90},{6,0,1435},{135,11,1275},{134,0,481},{7,11,445},{8,11,307},{8,11,704}
+,{10,11,41},{10,11,439},{11,11,237},{11,11,622},{140,11,201},{135,11,869},{4,0,
+84},{7,0,1482},{10,0,76},{138,0,142},{11,11,277},{144,11,14},{135,11,1977},{4,11
+,189},{5,11,713},{136,11,57},{133,0,1015},{138,11,371},{4,0,315},{5,0,507},{135,
+0,1370},{4,11,552},{142,10,381},{9,0,759},{16,0,31},{16,0,39},{16,0,75},{18,0,24
+},{20,0,42},{152,0,1},{134,0,712},{134,0,1722},{133,10,663},{133,10,846},{8,0,
+222},{8,0,476},{9,0,238},{11,0,516},{11,0,575},{15,0,109},{146,0,100},{7,0,1402}
+,{7,0,1414},{12,0,456},{5,10,378},{8,10,465},{9,10,286},{10,10,185},{10,10,562},
+{10,10,635},{11,10,31},{11,10,393},{13,10,312},{18,10,65},{18,10,96},{147,10,89}
+,{4,0,986},{6,0,1958},{6,0,2032},{8,0,934},{138,0,985},{7,10,1880},{9,10,680},{
+139,10,798},{134,10,1770},{145,11,49},{132,11,614},{132,10,648},{5,10,945},{6,10
+,1656},{6,10,1787},{7,10,167},{8,10,824},{9,10,391},{10,10,375},{139,10,185},{
+138,11,661},{7,0,1273},{135,11,1945},{7,0,706},{7,0,1058},{138,0,538},{7,10,1645
+},{8,10,352},{137,10,249},{132,10,152},{11,0,92},{11,0,196},{11,0,409},{11,0,450
+},{11,0,666},{11,0,777},{12,0,262},{13,0,385},{13,0,393},{15,0,115},{16,0,45},{
+145,0,82},{133,10,1006},{6,0,40},{135,0,1781},{9,11,614},{139,11,327},{5,10,420}
+,{135,10,1449},{135,0,431},{10,0,97},{135,10,832},{6,0,423},{7,0,665},{135,0,
+1210},{7,0,237},{8,0,664},{9,0,42},{9,0,266},{9,0,380},{9,0,645},{10,0,177},{138
+,0,276},{7,0,264},{133,10,351},{8,0,213},{5,10,40},{7,10,598},{7,10,1638},{9,10,
+166},{9,10,640},{9,10,685},{9,10,773},{11,10,215},{13,10,65},{14,10,172},{14,10,
+317},{145,10,6},{5,11,84},{134,11,163},{8,10,60},{9,10,343},{139,10,769},{137,0,
+455},{133,11,410},{8,0,906},{12,0,700},{12,0,706},{140,0,729},{21,11,33},{150,11
+,40},{7,10,1951},{8,10,765},{8,10,772},{140,10,671},{7,10,108},{8,10,219},{8,10,
+388},{9,10,639},{9,10,775},{11,10,275},{140,10,464},{5,11,322},{7,11,1941},{8,11
+,186},{9,11,262},{10,11,187},{14,11,208},{146,11,130},{139,0,624},{8,0,574},{5,
+11,227},{140,11,29},{7,11,1546},{11,11,299},{142,11,407},{5,10,15},{6,10,56},{7,
+10,1758},{8,10,500},{9,10,730},{11,10,331},{13,10,150},{142,10,282},{7,11,1395},
+{8,11,486},{9,11,236},{9,11,878},{10,11,218},{11,11,95},{19,11,17},{147,11,31},{
+135,11,2043},{4,0,354},{146,11,4},{140,11,80},{135,0,1558},{134,10,1886},{5,10,
+205},{6,10,438},{137,10,711},{133,11,522},{133,10,534},{7,0,235},{7,0,1475},{15,
+0,68},{146,0,120},{137,10,691},{4,0,942},{6,0,1813},{8,0,917},{10,0,884},{12,0,
+696},{12,0,717},{12,0,723},{12,0,738},{12,0,749},{12,0,780},{16,0,97},{146,0,169
+},{6,10,443},{8,11,562},{9,10,237},{9,10,571},{9,10,695},{10,10,139},{11,10,715}
+,{12,10,417},{141,10,421},{135,0,957},{133,0,830},{134,11,1771},{146,0,23},{5,0,
+496},{6,0,694},{7,0,203},{7,11,1190},{137,11,620},{137,11,132},{6,0,547},{134,0,
+1549},{8,11,258},{9,11,208},{137,11,359},{4,0,864},{5,0,88},{137,0,239},{135,11,
+493},{4,11,317},{135,11,1279},{132,11,477},{4,10,578},{5,11,63},{133,11,509},{7,
+0,650},{135,0,1310},{7,0,1076},{9,0,80},{11,0,78},{11,0,421},{11,0,534},{140,0,
+545},{132,11,288},{12,0,553},{14,0,118},{133,10,923},{7,0,274},{11,0,479},{139,0
+,507},{8,11,89},{8,11,620},{9,11,49},{10,11,774},{11,11,628},{12,11,322},{143,11
+,124},{4,0,497},{135,0,1584},{7,0,261},{7,0,1115},{7,0,1354},{7,0,1404},{7,0,
+1588},{7,0,1705},{7,0,1902},{9,0,465},{10,0,248},{10,0,349},{10,0,647},{11,0,527
+},{11,0,660},{11,0,669},{12,0,529},{13,0,305},{132,10,924},{133,10,665},{136,0,
+13},{6,0,791},{138,11,120},{7,0,642},{8,0,250},{11,0,123},{11,0,137},{13,0,48},{
+142,0,95},{4,10,265},{7,10,807},{135,10,950},{5,10,93},{140,10,267},{135,0,1429}
+,{4,0,949},{10,0,885},{10,0,891},{10,0,900},{10,0,939},{12,0,760},{142,0,449},{
+139,11,366},{132,0,818},{134,11,85},{135,10,994},{7,0,330},{5,10,233},{5,10,320}
+,{6,10,140},{136,10,295},{4,0,1004},{8,0,982},{136,0,993},{133,10,978},{4,10,905
+},{6,10,1701},{137,10,843},{10,0,545},{140,0,301},{6,0,947},{134,0,1062},{134,0,
+1188},{4,0,904},{5,0,794},{152,10,6},{134,0,1372},{135,11,608},{5,11,279},{6,11,
+235},{7,11,468},{8,11,446},{9,11,637},{10,11,717},{11,11,738},{140,11,514},{132,
+10,509},{5,11,17},{6,11,371},{137,11,528},{132,0,693},{4,11,115},{5,11,669},{6,
+11,407},{8,11,311},{11,11,10},{141,11,5},{11,0,377},{7,10,273},{137,11,381},{135
+,0,695},{7,0,386},{138,0,713},{135,10,1041},{134,0,1291},{6,0,7},{6,0,35},{7,0,
+147},{7,0,1069},{7,0,1568},{7,0,1575},{7,0,1917},{8,0,43},{8,0,208},{9,0,128},{9
+,0,866},{10,0,20},{11,0,981},{147,0,33},{7,0,893},{141,0,424},{139,10,234},{150,
+11,56},{5,11,779},{5,11,807},{6,11,1655},{134,11,1676},{5,10,802},{7,10,2021},{
+136,10,805},{4,11,196},{5,10,167},{5,11,558},{5,10,899},{5,11,949},{6,10,410},{
+137,10,777},{137,10,789},{134,10,1705},{8,0,904},{140,0,787},{6,0,322},{9,0,552}
+,{11,0,274},{13,0,209},{13,0,499},{14,0,85},{15,0,126},{145,0,70},{135,10,10},{5
+,10,11},{6,10,117},{6,10,485},{7,10,1133},{9,10,582},{9,10,594},{11,10,21},{11,
+10,818},{12,10,535},{141,10,86},{4,10,264},{7,10,1067},{8,10,204},{8,10,385},{
+139,10,953},{132,11,752},{138,10,56},{133,10,470},{6,0,1808},{8,0,83},{8,0,742},
+{8,0,817},{9,0,28},{9,0,29},{9,0,885},{10,0,387},{11,0,633},{11,0,740},{13,0,235
+},{13,0,254},{15,0,143},{143,0,146},{140,0,49},{134,0,1832},{4,11,227},{5,11,159
+},{5,11,409},{7,11,80},{10,11,294},{10,11,479},{12,11,418},{14,11,50},{14,11,249
+},{142,11,295},{7,11,1470},{8,11,66},{8,11,137},{8,11,761},{9,11,638},{11,11,80}
+,{11,11,212},{11,11,368},{11,11,418},{12,11,8},{13,11,15},{16,11,61},{17,11,59},
+{19,11,28},{148,11,84},{139,10,1015},{138,11,468},{135,0,421},{6,0,415},{7,0,
+1049},{137,0,442},{6,11,38},{7,11,1220},{8,11,185},{8,11,256},{9,11,22},{9,11,
+331},{10,11,738},{11,11,205},{11,11,540},{11,11,746},{13,11,399},{13,11,465},{14
+,11,88},{142,11,194},{139,0,289},{133,10,715},{4,0,110},{10,0,415},{10,0,597},{
+142,0,206},{4,11,159},{6,11,115},{7,11,252},{7,11,257},{7,11,1928},{8,11,69},{9,
+11,384},{10,11,91},{10,11,615},{12,11,375},{14,11,235},{18,11,117},{147,11,123},
+{5,11,911},{136,11,278},{7,0,205},{7,0,2000},{8,10,794},{9,10,400},{10,10,298},{
+142,10,228},{135,11,1774},{4,11,151},{7,11,1567},{8,11,351},{137,11,322},{136,10
+,724},{133,11,990},{7,0,1539},{11,0,512},{13,0,205},{19,0,30},{22,0,36},{23,0,19
+},{135,11,1539},{5,11,194},{7,11,1662},{9,11,90},{140,11,180},{6,10,190},{7,10,
+768},{135,10,1170},{134,0,1340},{4,0,283},{135,0,1194},{133,11,425},{133,11,971}
+,{12,0,549},{14,10,67},{147,10,60},{135,10,1023},{134,0,1720},{138,11,587},{5,11
+,72},{6,11,264},{7,11,21},{7,11,46},{7,11,2013},{8,11,215},{8,11,513},{10,11,266
+},{139,11,22},{5,0,319},{135,0,534},{6,10,137},{9,10,75},{9,10,253},{10,10,194},
+{138,10,444},{7,0,1180},{20,0,112},{6,11,239},{7,11,118},{10,11,95},{11,11,603},
+{13,11,443},{14,11,160},{143,11,4},{134,11,431},{5,11,874},{6,11,1677},{11,10,
+643},{12,10,115},{143,11,0},{134,0,967},{6,11,65},{7,11,939},{7,11,1172},{7,11,
+1671},{9,11,540},{10,11,696},{11,11,265},{11,11,732},{11,11,928},{11,11,937},{12
+,11,399},{13,11,438},{149,11,19},{137,11,200},{135,0,1940},{5,10,760},{7,10,542}
+,{8,10,135},{136,10,496},{140,11,44},{7,11,1655},{136,11,305},{7,10,319},{7,10,
+355},{7,10,763},{10,10,389},{145,10,43},{136,0,735},{138,10,786},{137,11,19},{
+132,11,696},{5,0,132},{9,0,486},{9,0,715},{10,0,458},{11,0,373},{11,0,668},{11,0
+,795},{11,0,897},{12,0,272},{12,0,424},{12,0,539},{12,0,558},{14,0,245},{14,0,
+263},{14,0,264},{14,0,393},{142,0,403},{10,0,38},{139,0,784},{132,0,838},{4,11,
+302},{135,11,1766},{133,0,379},{5,0,8},{6,0,89},{6,0,400},{7,0,1569},{7,0,1623},
+{7,0,1850},{8,0,218},{8,0,422},{9,0,570},{10,0,626},{4,11,726},{133,11,630},{4,0
+,1017},{138,0,660},{6,0,387},{7,0,882},{141,0,111},{6,0,224},{7,0,877},{137,0,
+647},{4,10,58},{5,10,286},{6,10,319},{7,10,402},{7,10,1254},{7,10,1903},{8,10,
+356},{140,10,408},{135,0,790},{9,0,510},{10,0,53},{4,10,389},{9,10,181},{10,10,
+29},{10,10,816},{11,10,311},{11,10,561},{12,10,67},{141,10,181},{142,0,458},{6,
+11,118},{7,11,215},{7,11,1521},{140,11,11},{134,0,954},{135,0,394},{134,0,1367},
+{5,11,225},{133,10,373},{132,0,882},{7,0,1409},{135,10,1972},{135,10,1793},{4,11
+,370},{5,11,756},{135,11,1326},{150,11,13},{7,11,354},{10,11,410},{139,11,815},{
+6,11,1662},{7,11,48},{8,11,771},{10,11,116},{13,11,104},{14,11,105},{14,11,184},
+{15,11,168},{19,11,92},{148,11,68},{7,0,124},{136,0,38},{5,0,261},{7,0,78},{7,0,
+199},{8,0,815},{9,0,126},{10,0,342},{140,0,647},{4,0,628},{140,0,724},{7,0,266},
+{8,0,804},{7,10,1651},{145,10,89},{135,0,208},{134,0,1178},{6,0,79},{135,0,1519}
+,{132,10,672},{133,10,737},{136,0,741},{132,11,120},{4,0,710},{6,0,376},{134,0,
+606},{134,0,1347},{134,0,1494},{6,0,850},{6,0,1553},{137,0,821},{5,10,145},{134,
+11,593},{7,0,1311},{140,0,135},{4,0,467},{5,0,405},{134,0,544},{5,11,820},{135,
+11,931},{6,0,100},{7,0,244},{7,0,632},{7,0,1609},{8,0,178},{8,0,638},{141,0,58},
+{4,10,387},{135,10,1288},{6,11,151},{6,11,1675},{7,11,383},{151,11,10},{132,0,
+481},{135,10,550},{134,0,1378},{6,11,1624},{11,11,11},{12,11,422},{13,11,262},{
+142,11,360},{133,0,791},{4,11,43},{5,11,344},{133,11,357},{7,0,1227},{140,0,978}
+,{7,0,686},{8,0,33},{8,0,238},{10,0,616},{11,0,467},{11,0,881},{13,0,217},{13,0,
+253},{142,0,268},{137,0,857},{8,0,467},{8,0,1006},{7,11,148},{8,11,284},{141,11,
+63},{4,10,576},{135,10,1263},{133,11,888},{5,10,919},{134,10,1673},{20,10,37},{
+148,11,37},{132,0,447},{132,11,711},{4,0,128},{5,0,415},{6,0,462},{7,0,294},{7,0
+,578},{10,0,710},{139,0,86},{4,10,82},{5,10,333},{5,10,904},{6,10,207},{7,10,325
+},{7,10,1726},{8,10,101},{10,10,778},{139,10,220},{136,0,587},{137,11,440},{133,
+10,903},{6,0,427},{7,0,1018},{138,0,692},{4,0,195},{135,0,802},{140,10,147},{134
+,0,1546},{134,0,684},{132,10,705},{136,0,345},{11,11,678},{140,11,307},{133,0,
+365},{134,0,1683},{4,11,65},{5,11,479},{5,11,1004},{7,11,1913},{8,11,317},{9,11,
+302},{10,11,612},{141,11,22},{138,0,472},{4,11,261},{135,11,510},{134,10,90},{
+142,0,433},{151,0,28},{4,11,291},{7,11,101},{9,11,515},{12,11,152},{12,11,443},{
+13,11,392},{142,11,357},{140,0,997},{5,0,3},{8,0,578},{9,0,118},{10,0,705},{141,
+0,279},{135,11,1266},{7,10,813},{12,10,497},{141,10,56},{133,0,229},{6,10,125},{
+135,10,1277},{8,0,102},{10,0,578},{10,0,672},{12,0,496},{13,0,408},{14,0,121},{
+17,0,106},{151,10,12},{6,0,866},{134,0,1080},{136,0,1022},{4,11,130},{135,11,843
+},{5,11,42},{5,11,879},{7,11,245},{7,11,324},{7,11,1532},{11,11,463},{11,11,472}
+,{13,11,363},{144,11,52},{150,0,55},{8,0,115},{8,0,350},{9,0,489},{10,0,128},{11
+,0,306},{12,0,373},{14,0,30},{17,0,79},{19,0,80},{4,11,134},{133,11,372},{134,0,
+657},{134,0,933},{135,11,1147},{4,0,230},{133,0,702},{134,0,1728},{4,0,484},{18,
+0,26},{19,0,42},{20,0,43},{21,0,0},{23,0,27},{152,0,14},{7,0,185},{135,0,703},{6
+,0,417},{10,0,618},{7,10,1106},{9,10,770},{11,10,112},{140,10,413},{134,0,803},{
+132,11,644},{134,0,1262},{7,11,540},{12,10,271},{145,10,109},{135,11,123},{132,0
+,633},{134,11,623},{4,11,908},{5,11,359},{5,11,508},{6,11,1723},{7,11,343},{7,11
+,1996},{135,11,2026},{135,0,479},{10,0,262},{7,10,304},{9,10,646},{9,10,862},{11
+,10,696},{12,10,208},{15,10,79},{147,10,108},{4,11,341},{135,11,480},{134,0,830}
+,{5,0,70},{5,0,622},{6,0,334},{7,0,1032},{9,0,171},{11,0,26},{11,0,213},{11,0,
+637},{11,0,707},{12,0,202},{12,0,380},{13,0,226},{13,0,355},{14,0,222},{145,0,42
+},{135,10,981},{143,0,217},{137,11,114},{4,0,23},{4,0,141},{5,0,313},{5,0,1014},
+{6,0,50},{6,0,51},{7,0,142},{7,0,384},{7,0,559},{8,0,640},{9,0,460},{9,0,783},{
+11,0,741},{12,0,183},{141,0,488},{141,0,360},{7,0,1586},{7,11,1995},{8,11,299},{
+11,11,890},{140,11,674},{132,10,434},{7,0,652},{134,10,550},{7,0,766},{5,10,553}
+,{138,10,824},{7,0,737},{8,0,298},{136,10,452},{4,11,238},{5,11,503},{6,11,179},
+{7,11,2003},{8,11,381},{8,11,473},{9,11,149},{10,11,183},{15,11,45},{143,11,86},
+{133,10,292},{5,0,222},{9,0,655},{138,0,534},{138,10,135},{4,11,121},{5,11,156},
+{5,11,349},{9,11,136},{10,11,605},{14,11,342},{147,11,107},{137,0,906},{6,0,1013
+},{134,0,1250},{6,0,1956},{6,0,2009},{8,0,991},{144,0,120},{135,11,1192},{138,0,
+503},{5,0,154},{7,0,1491},{10,0,379},{138,0,485},{6,0,1867},{6,0,1914},{6,0,1925
+},{9,0,917},{9,0,925},{9,0,932},{9,0,951},{9,0,1007},{9,0,1013},{12,0,806},{12,0
+,810},{12,0,814},{12,0,816},{12,0,824},{12,0,832},{12,0,837},{12,0,863},{12,0,
+868},{12,0,870},{12,0,889},{12,0,892},{12,0,900},{12,0,902},{12,0,908},{12,0,933
+},{12,0,942},{12,0,949},{12,0,954},{15,0,175},{15,0,203},{15,0,213},{15,0,218},{
+15,0,225},{15,0,231},{15,0,239},{15,0,248},{15,0,252},{18,0,190},{18,0,204},{18,
+0,215},{18,0,216},{18,0,222},{18,0,225},{18,0,230},{18,0,239},{18,0,241},{21,0,
+42},{21,0,43},{21,0,44},{21,0,45},{21,0,46},{21,0,53},{24,0,27},{152,0,31},{133,
+0,716},{135,0,844},{4,0,91},{5,0,388},{5,0,845},{6,0,206},{6,0,252},{6,0,365},{7
+,0,136},{7,0,531},{136,0,621},{7,10,393},{10,10,603},{139,10,206},{6,11,80},{6,
+11,1694},{7,11,173},{7,11,1974},{9,11,547},{10,11,730},{14,11,18},{150,11,39},{
+137,0,748},{4,11,923},{134,11,1711},{4,10,912},{137,10,232},{7,10,98},{7,10,1973
+},{136,10,716},{14,0,103},{133,10,733},{132,11,595},{12,0,158},{18,0,8},{19,0,62
+},{20,0,6},{22,0,4},{23,0,2},{23,0,9},{5,11,240},{6,11,459},{7,11,12},{7,11,114}
+,{7,11,502},{7,11,1751},{7,11,1753},{7,11,1805},{8,11,658},{9,11,1},{11,11,959},
+{13,11,446},{142,11,211},{135,0,576},{5,0,771},{5,0,863},{5,0,898},{6,0,648},{6,
+0,1632},{6,0,1644},{134,0,1780},{133,0,331},{7,11,633},{7,11,905},{7,11,909},{7,
+11,1538},{9,11,767},{140,11,636},{140,0,632},{5,0,107},{7,0,201},{136,0,518},{6,
+0,446},{7,0,1817},{134,11,490},{9,0,851},{141,0,510},{7,11,250},{8,11,506},{136,
+11,507},{4,0,504},{137,10,72},{132,11,158},{4,11,140},{7,11,362},{8,11,209},{9,
+11,10},{9,11,160},{9,11,503},{10,11,689},{11,11,350},{11,11,553},{11,11,725},{12
+,11,252},{12,11,583},{13,11,192},{13,11,352},{14,11,269},{14,11,356},{148,11,50}
+,{6,11,597},{135,11,1318},{135,10,1454},{5,0,883},{5,0,975},{8,0,392},{148,0,7},
+{6,11,228},{7,11,1341},{9,11,408},{138,11,343},{11,11,348},{11,10,600},{12,11,99
+},{13,10,245},{18,11,1},{18,11,11},{147,11,4},{134,11,296},{5,0,922},{134,0,1707
+},{132,11,557},{4,11,548},{7,10,164},{7,10,1571},{9,10,107},{140,10,225},{7,11,
+197},{8,11,142},{8,11,325},{9,11,150},{9,11,596},{10,11,350},{10,11,353},{11,11,
+74},{11,11,315},{14,11,423},{143,11,141},{5,0,993},{7,0,515},{137,0,91},{4,0,131
+},{8,0,200},{5,10,484},{5,10,510},{6,10,434},{7,10,1000},{7,10,1098},{136,10,2},
+{152,0,10},{4,11,62},{5,11,83},{6,11,399},{6,11,579},{7,11,692},{7,11,846},{7,11
+,1015},{7,11,1799},{8,11,403},{9,11,394},{10,11,133},{12,11,4},{12,11,297},{12,
+11,452},{16,11,81},{18,11,19},{18,11,25},{21,11,14},{22,11,12},{151,11,18},{140,
+11,459},{132,11,177},{7,0,1433},{9,0,365},{137,11,365},{132,10,460},{5,0,103},{6
+,0,2004},{7,0,921},{8,0,580},{8,0,593},{8,0,630},{10,0,28},{5,11,411},{135,11,
+653},{4,10,932},{133,10,891},{4,0,911},{5,0,867},{5,0,1013},{7,0,2034},{8,0,798}
+,{136,0,813},{7,11,439},{10,11,727},{11,11,260},{139,11,684},{136,10,625},{5,11,
+208},{7,11,753},{135,11,1528},{5,0,461},{7,0,1925},{12,0,39},{13,0,265},{13,0,
+439},{134,10,76},{6,0,853},{8,10,92},{137,10,221},{5,0,135},{6,0,519},{7,0,1722}
+,{10,0,271},{11,0,261},{145,0,54},{139,11,814},{14,0,338},{148,0,81},{4,0,300},{
+133,0,436},{5,0,419},{5,0,687},{7,0,864},{9,0,470},{135,11,864},{9,0,836},{133,
+11,242},{134,0,1937},{4,10,763},{133,11,953},{132,10,622},{132,0,393},{133,10,
+253},{8,0,357},{10,0,745},{14,0,426},{17,0,94},{19,0,57},{135,10,546},{5,11,615}
+,{146,11,37},{9,10,73},{10,10,110},{14,10,185},{145,10,119},{11,0,703},{7,10,624
+},{7,10,916},{10,10,256},{139,10,87},{133,11,290},{5,10,212},{12,10,35},{141,10,
+382},{132,11,380},{5,11,52},{7,11,277},{9,11,368},{139,11,791},{133,0,387},{10,
+11,138},{139,11,476},{4,0,6},{5,0,708},{136,0,75},{7,0,1351},{9,0,581},{10,0,639
+},{11,0,453},{140,0,584},{132,0,303},{138,0,772},{135,10,1175},{4,0,749},{5,10,
+816},{6,11,256},{7,11,307},{7,11,999},{7,11,1481},{7,11,1732},{7,11,1738},{8,11,
+265},{9,11,414},{11,11,316},{12,11,52},{13,11,420},{147,11,100},{135,11,1296},{6
+,0,1065},{5,10,869},{5,10,968},{6,10,1626},{8,10,734},{136,10,784},{4,10,542},{6
+,10,1716},{6,10,1727},{7,10,1082},{7,10,1545},{8,10,56},{8,10,118},{8,10,412},{8
+,10,564},{9,10,888},{9,10,908},{10,10,50},{10,10,423},{11,10,685},{11,10,697},{
+11,10,933},{12,10,299},{13,10,126},{13,10,136},{13,10,170},{141,10,190},{134,0,
+226},{4,0,106},{7,0,310},{11,0,717},{133,11,723},{5,0,890},{5,0,988},{4,10,232},
+{9,10,202},{10,10,474},{140,10,433},{6,0,626},{142,0,431},{10,0,706},{150,0,44},
+{13,0,51},{6,10,108},{7,10,1003},{7,10,1181},{8,10,111},{136,10,343},{132,0,698}
+,{5,11,109},{6,11,1784},{7,11,1895},{12,11,296},{140,11,302},{134,0,828},{134,10
+,1712},{138,0,17},{7,0,1929},{4,10,133},{5,11,216},{7,10,711},{7,10,1298},{7,10,
+1585},{7,11,1879},{9,11,141},{9,11,270},{9,11,679},{10,11,159},{10,11,553},{11,
+11,197},{11,11,438},{12,11,538},{12,11,559},{13,11,193},{13,11,423},{14,11,144},
+{14,11,166},{14,11,167},{15,11,67},{147,11,84},{141,11,127},{7,11,1872},{137,11,
+81},{6,10,99},{7,10,1808},{145,10,57},{134,11,391},{5,0,689},{6,0,84},{7,0,1250}
+,{6,10,574},{7,10,428},{10,10,669},{11,10,485},{11,10,840},{12,10,300},{142,10,
+250},{7,11,322},{136,11,249},{7,11,432},{135,11,1649},{135,10,1871},{137,10,252}
+,{6,11,155},{140,11,234},{7,0,871},{19,0,27},{147,11,27},{140,0,498},{5,0,986},{
+6,0,130},{138,0,823},{6,0,1793},{7,0,1582},{8,0,458},{10,0,101},{10,0,318},{10,0
+,945},{12,0,734},{16,0,104},{18,0,177},{6,10,323},{135,10,1564},{5,11,632},{138,
+11,526},{10,0,435},{7,10,461},{136,10,775},{6,11,144},{7,11,948},{7,11,1042},{7,
+11,1857},{8,11,235},{8,11,461},{9,11,453},{9,11,530},{10,11,354},{17,11,77},{19,
+11,99},{148,11,79},{138,0,966},{7,0,1644},{137,0,129},{135,0,997},{136,0,502},{5
+,11,196},{6,11,486},{7,11,212},{8,11,309},{136,11,346},{7,10,727},{146,10,73},{
+132,0,823},{132,11,686},{135,0,1927},{4,0,762},{7,0,1756},{137,0,98},{136,10,577
+},{24,0,8},{4,11,30},{5,11,43},{152,11,8},{7,0,1046},{139,0,160},{7,0,492},{4,10
+,413},{5,10,677},{7,11,492},{8,10,432},{140,10,280},{6,0,45},{7,0,433},{8,0,129}
+,{9,0,21},{10,0,392},{11,0,79},{12,0,499},{13,0,199},{141,0,451},{7,0,558},{136,
+0,353},{4,11,220},{7,11,1535},{9,11,93},{139,11,474},{7,10,646},{7,10,1730},{11,
+10,446},{141,10,178},{133,0,785},{134,0,1145},{8,0,81},{9,0,189},{9,0,201},{11,0
+,478},{11,0,712},{141,0,338},{5,0,353},{151,0,26},{11,0,762},{132,10,395},{134,0
+,2024},{4,0,611},{133,0,606},{9,10,174},{10,10,164},{11,10,440},{11,10,841},{143
+,10,98},{134,10,426},{10,10,608},{139,10,1002},{138,10,250},{6,0,25},{7,0,855},{
+7,0,1258},{144,0,32},{7,11,1725},{138,11,393},{5,11,263},{134,11,414},{6,0,2011}
+,{133,10,476},{4,0,4},{7,0,1118},{7,0,1320},{7,0,1706},{8,0,277},{9,0,622},{10,0
+,9},{11,0,724},{12,0,350},{12,0,397},{13,0,28},{13,0,159},{15,0,89},{18,0,5},{19
+,0,9},{20,0,34},{22,0,47},{6,11,178},{6,11,1750},{8,11,251},{9,11,690},{10,11,
+155},{10,11,196},{10,11,373},{11,11,698},{13,11,155},{148,11,93},{5,11,97},{137,
+11,393},{7,0,764},{11,0,461},{12,0,172},{5,10,76},{6,10,458},{6,10,497},{7,10,
+868},{9,10,658},{10,10,594},{11,10,566},{12,10,338},{141,10,200},{134,0,1449},{
+138,11,40},{134,11,1639},{134,0,1445},{6,0,1168},{4,10,526},{7,10,1029},{135,10,
+1054},{4,11,191},{7,11,934},{8,11,647},{145,11,97},{132,10,636},{6,0,233},{7,10,
+660},{7,10,1124},{17,10,31},{19,10,22},{151,10,14},{6,10,1699},{136,11,110},{12,
+11,246},{15,11,162},{19,11,64},{20,11,8},{20,11,95},{22,11,24},{152,11,17},{5,11
+,165},{9,11,346},{138,11,655},{5,11,319},{135,11,534},{134,0,255},{9,0,216},{8,
+11,128},{139,11,179},{9,0,183},{139,0,286},{11,0,956},{151,0,3},{4,0,536},{7,0,
+1141},{10,0,723},{139,0,371},{4,10,279},{7,10,301},{137,10,362},{7,0,285},{5,11,
+57},{6,11,101},{6,11,1663},{7,11,132},{7,11,1048},{7,11,1154},{7,11,1415},{7,11,
+1507},{12,11,493},{15,11,105},{151,11,15},{5,11,459},{7,11,1073},{7,10,1743},{8,
+11,241},{136,11,334},{4,10,178},{133,10,399},{135,0,560},{132,0,690},{135,0,1246
+},{18,0,157},{147,0,63},{10,0,599},{11,0,33},{12,0,571},{149,0,1},{6,11,324},{6,
+11,520},{7,11,338},{7,11,1616},{7,11,1729},{8,11,228},{9,11,69},{139,11,750},{7,
+0,1862},{12,0,491},{12,0,520},{13,0,383},{142,0,244},{135,11,734},{134,10,1692},
+{10,0,448},{11,0,630},{17,0,117},{6,10,202},{7,11,705},{12,10,360},{17,10,118},{
+18,10,27},{148,10,67},{4,11,73},{6,11,612},{7,11,927},{7,11,1822},{8,11,217},{9,
+11,472},{9,11,765},{9,11,766},{10,11,408},{11,11,51},{11,11,793},{12,11,266},{15
+,11,158},{20,11,89},{150,11,32},{4,0,190},{133,0,554},{133,0,1001},{5,11,389},{8
+,11,636},{137,11,229},{5,0,446},{7,10,872},{10,10,516},{139,10,167},{137,10,313}
+,{132,10,224},{134,0,1313},{5,10,546},{7,10,35},{8,10,11},{8,10,12},{9,10,315},{
+9,10,533},{10,10,802},{11,10,166},{12,10,525},{142,10,243},{6,0,636},{137,0,837}
+,{5,10,241},{8,10,242},{9,10,451},{10,10,667},{11,10,598},{140,10,429},{22,10,46
+},{150,11,46},{136,11,472},{11,0,278},{142,0,73},{141,11,185},{132,0,868},{134,0
+,972},{4,10,366},{137,10,516},{138,0,1010},{5,11,189},{6,10,1736},{7,11,442},{7,
+11,443},{8,11,281},{12,11,174},{13,11,83},{141,11,261},{139,11,384},{6,11,2},{7,
+11,191},{7,11,446},{7,11,758},{7,11,1262},{7,11,1737},{8,11,22},{8,11,270},{8,11
+,612},{9,11,4},{9,11,167},{9,11,312},{9,11,436},{10,11,156},{10,11,216},{10,11,
+311},{10,11,623},{11,11,72},{11,11,330},{11,11,455},{12,11,101},{12,11,321},{12,
+11,504},{12,11,530},{12,11,543},{13,11,17},{13,11,156},{13,11,334},{14,11,48},{
+15,11,70},{17,11,60},{148,11,64},{6,10,331},{136,10,623},{135,0,1231},{132,0,304
+},{6,11,60},{7,11,670},{7,11,1327},{8,11,411},{8,11,435},{9,11,653},{9,11,740},{
+10,11,385},{11,11,222},{11,11,324},{11,11,829},{140,11,611},{7,0,506},{6,11,166}
+,{7,11,374},{135,11,1174},{14,11,43},{146,11,21},{135,11,1694},{135,10,1888},{5,
+11,206},{134,11,398},{135,11,50},{150,0,26},{6,0,53},{6,0,199},{7,0,1408},{8,0,
+32},{8,0,93},{10,0,397},{10,0,629},{11,0,593},{11,0,763},{13,0,326},{145,0,35},{
+134,0,105},{132,10,394},{4,0,843},{138,0,794},{11,0,704},{141,0,396},{5,0,114},{
+5,0,255},{141,0,285},{6,0,619},{7,0,898},{7,0,1092},{8,0,485},{18,0,28},{19,0,
+116},{135,10,1931},{9,0,145},{7,10,574},{135,10,1719},{7,0,2035},{8,0,19},{9,0,
+89},{138,0,831},{132,10,658},{6,11,517},{7,11,1159},{10,11,621},{139,11,192},{7,
+0,1933},{7,11,1933},{9,10,781},{10,10,144},{11,10,385},{13,10,161},{13,10,228},{
+13,10,268},{148,10,107},{136,10,374},{10,11,223},{139,11,645},{135,0,1728},{7,11
+,64},{7,11,289},{136,11,245},{4,10,344},{6,10,498},{139,10,323},{136,0,746},{135
+,10,1063},{137,10,155},{4,0,987},{6,0,1964},{6,0,1974},{6,0,1990},{136,0,995},{
+133,11,609},{133,10,906},{134,0,1550},{134,0,874},{5,11,129},{6,11,61},{135,11,
+947},{4,0,1018},{6,0,1938},{6,0,2021},{134,0,2039},{132,0,814},{11,0,126},{139,0
+,287},{134,0,1264},{5,0,955},{136,0,814},{141,11,506},{132,11,314},{6,0,981},{
+139,11,1000},{5,0,56},{8,0,892},{8,0,915},{140,0,776},{148,0,100},{10,0,4},{10,0
+,13},{11,0,638},{148,0,57},{148,11,74},{5,0,738},{132,10,616},{133,11,637},{136,
+10,692},{133,0,758},{132,10,305},{137,11,590},{5,11,280},{135,11,1226},{134,11,
+494},{135,0,1112},{133,11,281},{13,0,44},{14,0,214},{5,10,214},{7,10,603},{8,10,
+611},{9,10,686},{10,10,88},{11,10,459},{11,10,496},{12,10,463},{140,10,590},{139
+,0,328},{135,11,1064},{137,0,133},{7,0,168},{13,0,196},{141,0,237},{134,10,1703}
+,{134,0,1152},{135,0,1245},{5,0,110},{6,0,169},{6,0,1702},{7,0,400},{8,0,538},{9
+,0,184},{9,0,524},{140,0,218},{6,0,1816},{10,0,871},{12,0,769},{140,0,785},{132,
+11,630},{7,11,33},{7,11,120},{8,11,489},{9,11,319},{10,11,820},{11,11,1004},{12,
+11,379},{13,11,117},{13,11,412},{14,11,25},{15,11,52},{15,11,161},{16,11,47},{
+149,11,2},{6,0,133},{8,0,413},{9,0,353},{139,0,993},{145,10,19},{4,11,937},{133,
+11,801},{134,0,978},{6,0,93},{6,0,1508},{7,0,1422},{7,0,1851},{8,0,673},{9,0,529
+},{140,0,43},{6,0,317},{10,0,512},{4,10,737},{11,10,294},{12,10,60},{12,10,437},
+{13,10,64},{13,10,380},{142,10,430},{9,0,371},{7,11,1591},{144,11,43},{6,10,1758
+},{8,10,520},{9,10,345},{9,10,403},{142,10,350},{5,0,526},{10,10,242},{138,10,
+579},{9,0,25},{10,0,467},{138,0,559},{5,10,139},{7,10,1168},{138,10,539},{4,0,
+335},{135,0,942},{140,0,754},{132,11,365},{11,0,182},{142,0,195},{142,11,29},{5,
+11,7},{139,11,774},{4,11,746},{135,11,1090},{8,0,39},{10,0,773},{11,0,84},{12,0,
+205},{142,0,1},{5,0,601},{5,0,870},{5,11,360},{136,11,237},{132,0,181},{136,0,
+370},{134,0,1652},{8,0,358},{4,10,107},{7,10,613},{8,10,439},{8,10,504},{9,10,
+501},{10,10,383},{139,10,477},{132,10,229},{137,11,785},{4,0,97},{5,0,147},{6,0,
+286},{7,0,1362},{141,0,176},{6,0,537},{7,0,788},{7,0,1816},{132,10,903},{140,10,
+71},{6,0,743},{134,0,1223},{6,0,375},{7,0,169},{7,0,254},{8,0,780},{135,11,1493}
+,{7,0,1714},{4,10,47},{6,10,373},{7,10,452},{7,10,543},{7,10,1856},{9,10,6},{11,
+10,257},{139,10,391},{6,0,896},{136,0,1003},{135,0,1447},{137,11,341},{5,10,980}
+,{134,10,1754},{145,11,22},{4,11,277},{5,11,608},{6,11,493},{7,11,457},{140,11,
+384},{7,10,536},{7,10,1331},{136,10,143},{140,0,744},{7,11,27},{135,11,316},{18,
+0,126},{5,10,19},{134,10,533},{4,0,788},{11,0,41},{5,11,552},{5,11,586},{5,11,
+676},{6,11,448},{8,11,244},{11,11,1},{11,11,41},{13,11,3},{16,11,54},{17,11,4},{
+146,11,13},{4,0,985},{6,0,1801},{4,11,401},{137,11,264},{5,10,395},{5,10,951},{
+134,10,1776},{5,0,629},{135,0,1549},{11,10,663},{12,10,210},{13,10,166},{13,10,
+310},{14,10,373},{147,10,43},{9,11,543},{10,11,524},{11,11,30},{12,11,524},{14,
+11,315},{16,11,18},{20,11,26},{148,11,65},{4,11,205},{5,11,623},{7,11,104},{136,
+11,519},{5,0,293},{134,0,601},{7,11,579},{9,11,41},{9,11,244},{9,11,669},{10,11,
+5},{11,11,861},{11,11,951},{139,11,980},{132,11,717},{132,10,695},{7,10,497},{9,
+10,387},{147,10,81},{132,0,420},{142,0,37},{6,0,1134},{6,0,1900},{12,0,830},{12,
+0,878},{12,0,894},{15,0,221},{143,0,245},{132,11,489},{7,0,1570},{140,0,542},{8,
+0,933},{136,0,957},{6,0,1371},{7,0,31},{8,0,373},{5,10,284},{6,10,49},{6,10,350}
+,{7,10,377},{7,10,1693},{8,10,678},{9,10,161},{9,10,585},{9,10,671},{9,10,839},{
+11,10,912},{141,10,427},{135,11,892},{4,0,325},{138,0,125},{139,11,47},{132,10,
+597},{138,0,323},{6,0,1547},{7,11,1605},{9,11,473},{11,11,962},{146,11,139},{139
+,10,908},{7,11,819},{9,11,26},{9,11,392},{10,11,152},{10,11,226},{11,11,19},{12,
+11,276},{12,11,426},{12,11,589},{13,11,460},{15,11,97},{19,11,48},{148,11,104},{
+135,11,51},{4,0,718},{135,0,1216},{6,0,1896},{6,0,1905},{6,0,1912},{9,0,947},{9,
+0,974},{12,0,809},{12,0,850},{12,0,858},{12,0,874},{12,0,887},{12,0,904},{12,0,
+929},{12,0,948},{12,0,952},{15,0,198},{15,0,206},{15,0,220},{15,0,227},{15,0,247
+},{18,0,188},{21,0,48},{21,0,50},{24,0,25},{24,0,29},{7,11,761},{7,11,1051},{137
+,11,545},{5,0,124},{5,0,144},{6,0,548},{7,0,15},{7,0,153},{137,0,629},{135,11,
+606},{135,10,2014},{7,10,2007},{9,11,46},{9,10,101},{9,10,450},{10,10,66},{10,10
+,842},{11,10,536},{140,10,587},{6,0,75},{7,0,1531},{8,0,416},{9,0,240},{9,0,275}
+,{10,0,100},{11,0,658},{11,0,979},{12,0,86},{14,0,207},{15,0,20},{143,0,25},{5,0
+,141},{5,0,915},{6,0,1783},{7,0,211},{7,0,698},{7,0,1353},{9,0,83},{9,0,281},{10
+,0,376},{10,0,431},{11,0,543},{12,0,664},{13,0,280},{13,0,428},{14,0,61},{14,0,
+128},{17,0,52},{145,0,81},{132,11,674},{135,0,533},{149,0,6},{132,11,770},{133,0
+,538},{5,11,79},{7,11,1027},{7,11,1477},{139,11,52},{139,10,62},{4,0,338},{133,0
+,400},{5,11,789},{134,11,195},{4,11,251},{4,11,688},{7,11,513},{7,11,1284},{9,11
+,87},{138,11,365},{134,10,1766},{6,0,0},{7,0,84},{11,0,895},{145,0,11},{139,0,
+892},{4,0,221},{5,0,659},{7,0,697},{7,0,1211},{138,0,284},{133,0,989},{133,11,
+889},{4,11,160},{5,11,330},{7,11,1434},{136,11,174},{6,10,1665},{7,10,256},{7,10
+,1388},{10,10,499},{139,10,670},{7,0,848},{4,10,22},{5,10,10},{136,10,97},{138,0
+,507},{133,10,481},{4,0,188},{135,0,805},{5,0,884},{6,0,732},{139,0,991},{135,11
+,968},{11,11,636},{15,11,145},{17,11,34},{19,11,50},{151,11,20},{7,0,959},{16,0,
+60},{6,10,134},{7,10,437},{9,10,37},{14,10,285},{142,10,371},{7,10,486},{8,10,
+155},{11,10,93},{140,10,164},{134,0,1653},{7,0,337},{133,10,591},{6,0,1989},{8,0
+,922},{8,0,978},{133,11,374},{132,0,638},{138,0,500},{133,11,731},{5,10,380},{5,
+10,650},{136,10,310},{138,11,381},{4,10,364},{7,10,1156},{7,10,1187},{137,10,409
+},{137,11,224},{140,0,166},{134,10,482},{4,11,626},{5,11,642},{6,11,425},{10,11,
+202},{139,11,141},{4,10,781},{6,10,487},{7,10,926},{8,10,263},{139,10,500},{135,
+0,418},{4,10,94},{135,10,1265},{136,0,760},{132,10,417},{136,11,835},{5,10,348},
+{134,10,522},{6,0,1277},{134,0,1538},{139,11,541},{135,11,1597},{5,11,384},{8,11
+,455},{140,11,48},{136,0,770},{5,11,264},{134,11,184},{4,0,89},{5,0,489},{6,0,
+315},{7,0,553},{7,0,1745},{138,0,243},{4,10,408},{4,10,741},{135,10,500},{134,0,
+1396},{133,0,560},{6,0,1658},{9,0,3},{10,0,154},{11,0,641},{13,0,85},{13,0,201},
+{141,0,346},{135,11,1595},{5,11,633},{6,11,28},{7,11,219},{135,11,1323},{9,11,
+769},{140,11,185},{135,11,785},{7,11,359},{8,11,243},{140,11,175},{138,0,586},{7
+,0,1271},{134,10,73},{132,11,105},{4,0,166},{5,0,505},{134,0,1670},{133,10,576},
+{4,11,324},{138,11,104},{142,10,231},{6,0,637},{7,10,1264},{7,10,1678},{11,10,
+945},{12,10,341},{12,10,471},{12,10,569},{23,11,21},{151,11,23},{8,11,559},{141,
+11,109},{134,0,1947},{7,0,445},{8,0,307},{8,0,704},{10,0,41},{10,0,439},{11,0,
+237},{11,0,622},{140,0,201},{135,11,963},{135,0,1977},{4,0,189},{5,0,713},{136,0
+,57},{138,0,371},{135,10,538},{132,0,552},{6,0,883},{133,10,413},{6,0,923},{132,
+11,758},{138,11,215},{136,10,495},{7,10,54},{8,10,312},{10,10,191},{10,10,614},{
+140,10,567},{7,11,351},{139,11,128},{7,0,875},{6,10,468},{7,10,1478},{8,10,530},
+{142,10,290},{135,0,1788},{17,0,49},{133,11,918},{12,11,398},{20,11,39},{21,11,
+11},{150,11,41},{10,0,661},{6,10,484},{135,10,822},{135,0,1945},{134,0,794},{137
+,10,900},{135,10,1335},{6,10,1724},{135,10,2022},{132,11,340},{134,0,1135},{4,0,
+784},{133,0,745},{5,0,84},{134,0,163},{133,0,410},{4,0,976},{5,11,985},{7,11,509
+},{7,11,529},{145,11,96},{132,10,474},{134,0,703},{135,11,1919},{5,0,322},{8,0,
+186},{9,0,262},{10,0,187},{142,0,208},{135,10,1504},{133,0,227},{9,0,560},{13,0,
+208},{133,10,305},{132,11,247},{7,0,1395},{8,0,486},{9,0,236},{9,0,878},{10,0,
+218},{11,0,95},{19,0,17},{147,0,31},{7,0,2043},{8,0,672},{141,0,448},{4,11,184},
+{5,11,390},{6,11,337},{7,11,23},{7,11,494},{7,11,618},{7,11,1456},{8,11,27},{8,
+11,599},{10,11,153},{139,11,710},{135,0,466},{135,10,1236},{6,0,167},{7,0,186},{
+7,0,656},{10,0,643},{4,10,480},{6,10,302},{6,10,1642},{7,10,837},{7,10,1547},{7,
+10,1657},{8,10,429},{9,10,228},{13,10,289},{13,10,343},{147,10,101},{134,0,1428}
+,{134,0,1440},{5,0,412},{7,10,278},{10,10,739},{11,10,708},{141,10,348},{134,0,
+1118},{136,0,562},{148,11,46},{9,0,316},{139,0,256},{134,0,1771},{135,0,1190},{
+137,0,132},{10,11,227},{11,11,497},{11,11,709},{140,11,415},{143,0,66},{6,11,360
+},{7,11,1664},{136,11,478},{144,10,28},{4,0,317},{135,0,1279},{5,0,63},{133,0,
+509},{136,11,699},{145,10,36},{134,0,1475},{11,11,343},{142,11,127},{132,11,739}
+,{132,0,288},{135,11,1757},{8,0,89},{8,0,620},{9,0,608},{11,0,628},{12,0,322},{
+143,0,124},{134,0,1225},{7,0,1189},{4,11,67},{5,11,422},{6,10,363},{7,11,1037},{
+7,11,1289},{7,11,1555},{7,10,1955},{8,10,725},{9,11,741},{145,11,108},{134,0,
+1468},{6,0,689},{134,0,1451},{138,0,120},{151,0,1},{137,10,805},{142,0,329},{5,
+10,813},{135,10,2046},{135,0,226},{138,11,96},{7,0,1855},{5,10,712},{11,10,17},{
+13,10,321},{144,10,67},{9,0,461},{6,10,320},{7,10,781},{7,10,1921},{9,10,55},{10
+,10,186},{10,10,273},{10,10,664},{10,10,801},{11,10,996},{11,10,997},{13,10,157}
+,{142,10,170},{8,11,203},{8,10,271},{11,11,823},{11,11,846},{12,11,482},{13,11,
+133},{13,11,277},{13,11,302},{13,11,464},{14,11,205},{142,11,221},{135,0,1346},{
+4,11,449},{133,11,718},{134,0,85},{14,0,299},{7,10,103},{7,10,863},{11,10,184},{
+145,10,62},{4,11,355},{6,11,311},{9,11,256},{138,11,404},{137,10,659},{138,11,
+758},{133,11,827},{5,11,64},{140,11,581},{134,0,1171},{4,11,442},{7,11,1047},{7,
+11,1352},{135,11,1643},{132,0,980},{5,11,977},{6,11,288},{7,11,528},{135,11,1065
+},{5,0,279},{6,0,235},{7,0,468},{8,0,446},{9,0,637},{10,0,717},{11,0,738},{140,0
+,514},{132,0,293},{11,10,337},{142,10,303},{136,11,285},{5,0,17},{6,0,371},{9,0,
+528},{12,0,364},{132,11,254},{5,10,77},{7,10,1455},{10,10,843},{147,10,73},{150,
+0,5},{132,10,458},{6,11,12},{7,11,1219},{145,11,73},{135,10,1420},{6,10,109},{
+138,10,382},{135,11,125},{6,10,330},{7,10,1084},{139,10,142},{6,11,369},{6,11,
+502},{7,11,1036},{8,11,348},{9,11,452},{10,11,26},{11,11,224},{11,11,387},{11,11
+,772},{12,11,95},{12,11,629},{13,11,195},{13,11,207},{13,11,241},{14,11,260},{14
+,11,270},{143,11,140},{132,11,269},{5,11,480},{7,11,532},{7,11,1197},{7,11,1358}
+,{8,11,291},{11,11,349},{142,11,396},{150,0,48},{10,0,601},{13,0,353},{141,0,376
+},{5,0,779},{5,0,807},{6,0,1655},{134,0,1676},{142,11,223},{4,0,196},{5,0,558},{
+133,0,949},{148,11,15},{135,11,1764},{134,0,1322},{132,0,752},{139,0,737},{135,
+11,657},{136,11,533},{135,0,412},{4,0,227},{5,0,159},{5,0,409},{7,0,80},{8,0,556
+},{10,0,479},{12,0,418},{14,0,50},{14,0,123},{14,0,192},{14,0,249},{14,0,295},{
+143,0,27},{7,0,1470},{8,0,66},{8,0,137},{8,0,761},{9,0,638},{11,0,80},{11,0,212}
+,{11,0,368},{11,0,418},{12,0,8},{13,0,15},{16,0,61},{17,0,59},{19,0,28},{148,0,
+84},{135,10,1985},{4,11,211},{4,11,332},{5,11,335},{6,11,238},{7,11,269},{7,11,
+811},{7,11,1797},{8,10,122},{8,11,836},{9,11,507},{141,11,242},{6,0,683},{134,0,
+1252},{4,0,873},{132,10,234},{134,0,835},{6,0,38},{7,0,1220},{8,0,185},{8,0,256}
+,{9,0,22},{9,0,331},{10,0,738},{11,0,205},{11,0,540},{11,0,746},{13,0,465},{14,0
+,88},{142,0,194},{138,0,986},{5,11,1009},{12,11,582},{146,11,131},{4,0,159},{6,0
+,115},{7,0,252},{7,0,257},{7,0,1928},{8,0,69},{9,0,384},{10,0,91},{10,0,615},{12
+,0,375},{14,0,235},{18,0,117},{147,0,123},{133,0,911},{136,0,278},{5,10,430},{5,
+10,932},{6,10,131},{7,10,417},{9,10,522},{11,10,314},{141,10,390},{14,10,149},{
+14,10,399},{143,10,57},{4,0,151},{7,0,1567},{136,0,749},{5,11,228},{6,11,203},{7
+,11,156},{8,11,347},{137,11,265},{132,10,507},{10,0,989},{140,0,956},{133,0,990}
+,{5,0,194},{6,0,927},{7,0,1662},{9,0,90},{140,0,564},{4,10,343},{133,10,511},{
+133,0,425},{7,10,455},{138,10,591},{4,0,774},{7,11,476},{7,11,1592},{138,11,87},
+{5,0,971},{135,10,1381},{5,11,318},{147,11,121},{5,11,291},{7,11,765},{9,11,389}
+,{140,11,548},{134,10,575},{4,0,827},{12,0,646},{12,0,705},{12,0,712},{140,0,714
+},{139,0,752},{137,0,662},{5,0,72},{6,0,264},{7,0,21},{7,0,46},{7,0,2013},{8,0,
+215},{8,0,513},{10,0,266},{139,0,22},{139,11,522},{6,0,239},{7,0,118},{10,0,95},
+{11,0,603},{13,0,443},{14,0,160},{143,0,4},{6,0,431},{134,0,669},{7,10,1127},{7,
+10,1572},{10,10,297},{10,10,422},{11,10,764},{11,10,810},{12,10,264},{13,10,102}
+,{13,10,300},{13,10,484},{14,10,147},{14,10,229},{17,10,71},{18,10,118},{147,10,
+120},{5,0,874},{6,0,1677},{15,0,0},{10,11,525},{139,11,82},{6,0,65},{7,0,939},{7
+,0,1172},{7,0,1671},{9,0,540},{10,0,696},{11,0,265},{11,0,732},{11,0,928},{11,0,
+937},{141,0,438},{134,0,1350},{136,11,547},{132,11,422},{5,11,355},{145,11,0},{
+137,11,905},{5,0,682},{135,0,1887},{132,0,809},{4,0,696},{133,11,865},{6,0,1074}
+,{6,0,1472},{14,10,35},{142,10,191},{5,11,914},{134,11,1625},{133,11,234},{135,
+11,1383},{137,11,780},{132,10,125},{4,0,726},{133,0,630},{8,0,802},{136,0,838},{
+132,10,721},{6,0,1337},{7,0,776},{19,0,56},{136,10,145},{132,0,970},{7,10,792},{
+8,10,147},{10,10,821},{139,10,1021},{139,10,970},{8,0,940},{137,0,797},{135,11,
+1312},{9,0,248},{10,0,400},{7,11,816},{7,11,1241},{7,10,1999},{9,11,283},{9,11,
+520},{10,11,213},{10,11,307},{10,11,463},{10,11,671},{10,11,746},{11,11,401},{11
+,11,794},{12,11,517},{18,11,107},{147,11,115},{6,0,1951},{134,0,2040},{135,11,
+339},{13,0,41},{15,0,93},{5,10,168},{5,10,930},{8,10,74},{9,10,623},{12,10,500},
+{140,10,579},{6,0,118},{7,0,215},{7,0,1521},{140,0,11},{6,10,220},{7,10,1101},{
+141,10,105},{6,11,421},{7,11,61},{7,11,1540},{10,11,11},{138,11,501},{7,0,615},{
+138,0,251},{140,11,631},{135,0,1044},{6,10,19},{7,10,1413},{139,10,428},{133,0,
+225},{7,10,96},{8,10,401},{8,10,703},{137,10,896},{145,10,116},{6,11,102},{7,11,
+72},{15,11,142},{147,11,67},{7,10,1961},{7,10,1965},{8,10,702},{136,10,750},{7,
+10,2030},{8,10,150},{8,10,737},{12,10,366},{151,11,30},{4,0,370},{5,0,756},{7,0,
+1326},{135,11,823},{8,10,800},{9,10,148},{9,10,872},{9,10,890},{11,10,309},{11,
+10,1001},{13,10,267},{141,10,323},{6,0,1662},{7,0,48},{8,0,771},{10,0,116},{13,0
+,104},{14,0,105},{14,0,184},{15,0,168},{19,0,92},{148,0,68},{10,0,209},{135,11,
+1870},{7,11,68},{8,11,48},{8,11,88},{8,11,582},{8,11,681},{9,11,373},{9,11,864},
+{11,11,157},{11,11,336},{11,11,843},{148,11,27},{134,0,930},{4,11,88},{5,11,137}
+,{5,11,174},{5,11,777},{6,11,1664},{6,11,1725},{7,11,77},{7,11,426},{7,11,1317},
+{7,11,1355},{8,11,126},{8,11,563},{9,11,523},{9,11,750},{10,11,310},{10,11,836},
+{11,11,42},{11,11,318},{11,11,731},{12,11,68},{12,11,92},{12,11,507},{12,11,692}
+,{13,11,81},{13,11,238},{13,11,374},{18,11,138},{19,11,78},{19,11,111},{20,11,55
+},{20,11,77},{148,11,92},{4,11,938},{135,11,1831},{5,10,547},{7,10,424},{8,11,
+617},{138,11,351},{6,0,1286},{6,11,1668},{7,11,1499},{8,11,117},{9,11,314},{138,
+11,174},{6,0,759},{6,0,894},{7,11,707},{139,11,563},{4,0,120},{135,0,1894},{9,0,
+385},{149,0,17},{138,0,429},{133,11,403},{5,0,820},{135,0,931},{10,0,199},{133,
+10,133},{6,0,151},{6,0,1675},{7,0,383},{151,0,10},{6,0,761},{136,10,187},{8,0,
+365},{10,10,0},{10,10,818},{139,10,988},{4,11,44},{5,11,311},{6,11,156},{7,11,
+639},{7,11,762},{7,11,1827},{9,11,8},{9,11,462},{148,11,83},{4,11,346},{7,11,115
+},{9,11,180},{9,11,456},{138,11,363},{136,10,685},{7,0,1086},{145,0,46},{6,0,
+1624},{11,0,11},{12,0,422},{13,0,444},{142,0,360},{6,0,1020},{6,0,1260},{134,0,
+1589},{4,0,43},{5,0,344},{5,0,357},{14,0,472},{150,0,58},{6,0,1864},{6,0,1866},{
+6,0,1868},{6,0,1869},{6,0,1874},{6,0,1877},{6,0,1903},{6,0,1911},{9,0,920},{9,0,
+921},{9,0,924},{9,0,946},{9,0,959},{9,0,963},{9,0,970},{9,0,997},{9,0,1008},{9,0
+,1017},{12,0,795},{12,0,797},{12,0,798},{12,0,800},{12,0,803},{12,0,811},{12,0,
+820},{12,0,821},{12,0,839},{12,0,841},{12,0,848},{12,0,911},{12,0,921},{12,0,922
+},{12,0,925},{12,0,937},{12,0,944},{12,0,945},{12,0,953},{15,0,184},{15,0,191},{
+15,0,199},{15,0,237},{15,0,240},{15,0,243},{15,0,246},{18,0,203},{21,0,40},{21,0
+,52},{21,0,57},{24,0,23},{24,0,28},{152,0,30},{134,0,725},{145,11,58},{133,0,888
+},{137,10,874},{4,0,711},{8,10,774},{10,10,670},{140,10,51},{144,11,40},{6,11,
+185},{7,11,1899},{139,11,673},{137,10,701},{137,0,440},{4,11,327},{5,11,478},{7,
+11,1332},{8,11,753},{140,11,227},{4,10,127},{5,10,350},{6,10,356},{8,10,426},{9,
+10,572},{10,10,247},{139,10,312},{5,11,1020},{133,11,1022},{4,11,103},{133,11,
+401},{6,0,1913},{6,0,1926},{6,0,1959},{9,0,914},{9,0,939},{9,0,952},{9,0,979},{9
+,0,990},{9,0,998},{9,0,1003},{9,0,1023},{12,0,827},{12,0,834},{12,0,845},{12,0,
+912},{12,0,935},{12,0,951},{15,0,172},{15,0,174},{18,0,198},{149,0,63},{5,0,958}
+,{5,0,987},{4,11,499},{135,11,1421},{7,0,885},{6,10,59},{6,10,1762},{9,10,603},{
+141,10,397},{10,11,62},{141,11,164},{4,0,847},{135,0,326},{11,0,276},{142,0,293}
+,{4,0,65},{5,0,479},{5,0,1004},{7,0,1913},{8,0,317},{9,0,302},{10,0,612},{13,0,
+22},{132,11,96},{4,0,261},{135,0,510},{135,0,1514},{6,10,111},{7,10,4},{8,10,163
+},{8,10,776},{138,10,566},{4,0,291},{9,0,515},{12,0,152},{12,0,443},{13,0,392},{
+142,0,357},{7,11,399},{135,11,1492},{4,0,589},{139,0,282},{6,11,563},{135,10,
+1994},{5,10,297},{135,10,1038},{4,0,130},{7,0,843},{135,0,1562},{5,0,42},{5,0,
+879},{7,0,245},{7,0,324},{7,0,1532},{11,0,463},{11,0,472},{13,0,363},{144,0,52},
+{4,0,134},{133,0,372},{133,0,680},{136,10,363},{6,0,1997},{8,0,935},{136,0,977},
+{4,0,810},{135,0,1634},{135,10,1675},{7,0,1390},{4,11,910},{133,11,832},{7,10,
+808},{8,11,266},{139,11,578},{132,0,644},{4,0,982},{138,0,867},{132,10,280},{135
+,0,540},{140,10,54},{135,0,123},{134,0,1978},{4,10,421},{133,10,548},{6,0,623},{
+136,0,789},{4,0,908},{5,0,359},{5,0,508},{6,0,1723},{7,0,343},{7,0,1996},{135,0,
+2026},{134,0,1220},{4,0,341},{135,0,480},{6,10,254},{9,10,109},{138,10,103},{134
+,0,888},{8,11,528},{137,11,348},{7,0,1995},{8,0,299},{11,0,890},{12,0,674},{4,11
+,20},{133,11,616},{135,11,1094},{134,10,1630},{4,0,238},{5,0,503},{6,0,179},{7,0
+,2003},{8,0,381},{8,0,473},{9,0,149},{10,0,788},{15,0,45},{15,0,86},{20,0,110},{
+150,0,57},{133,10,671},{4,11,26},{5,11,429},{6,11,245},{7,11,704},{7,11,1379},{
+135,11,1474},{4,0,121},{5,0,156},{5,0,349},{9,0,431},{10,0,605},{142,0,342},{7,
+11,943},{139,11,614},{132,10,889},{132,11,621},{7,10,1382},{7,11,1382},{135,10,
+1910},{132,10,627},{133,10,775},{133,11,542},{133,11,868},{136,11,433},{6,0,1373
+},{7,0,1011},{11,10,362},{11,10,948},{140,10,388},{6,0,80},{7,0,173},{9,0,547},{
+10,0,730},{14,0,18},{22,0,39},{135,11,1495},{6,0,1694},{135,0,1974},{140,0,196},
+{4,0,923},{6,0,507},{6,0,1711},{7,10,451},{8,10,389},{12,10,490},{13,10,16},{13,
+10,215},{13,10,351},{18,10,132},{147,10,125},{6,0,646},{134,0,1047},{135,10,841}
+,{136,10,566},{6,0,1611},{135,0,1214},{139,0,926},{132,11,525},{132,0,595},{5,0,
+240},{6,0,459},{7,0,12},{7,0,114},{7,0,949},{7,0,1753},{7,0,1805},{8,0,658},{9,0
+,1},{11,0,959},{141,0,446},{5,10,912},{134,10,1695},{132,0,446},{7,11,62},{12,11
+,45},{147,11,112},{5,10,236},{6,10,572},{8,10,492},{11,10,618},{144,10,56},{5,10
+,190},{136,10,318},{135,10,1376},{4,11,223},{6,11,359},{11,11,3},{13,11,108},{14
+,11,89},{144,11,22},{132,11,647},{134,0,490},{134,0,491},{134,0,1584},{135,11,
+685},{138,11,220},{7,0,250},{136,0,507},{132,0,158},{4,0,140},{7,0,362},{8,0,209
+},{9,0,10},{9,0,160},{9,0,503},{9,0,614},{10,0,689},{11,0,327},{11,0,553},{11,0,
+725},{11,0,767},{12,0,252},{12,0,583},{13,0,192},{14,0,269},{14,0,356},{148,0,50
+},{19,0,1},{19,0,26},{150,0,9},{132,11,109},{6,0,228},{7,0,1341},{9,0,408},{138,
+0,343},{4,0,373},{5,0,283},{6,0,480},{7,0,609},{10,0,860},{138,0,878},{6,0,779},
+{134,0,1209},{4,0,557},{7,11,263},{7,11,628},{136,11,349},{132,0,548},{7,0,197},
+{8,0,142},{8,0,325},{9,0,150},{9,0,596},{10,0,350},{10,0,353},{11,0,74},{11,0,
+315},{12,0,662},{12,0,681},{14,0,423},{143,0,141},{4,11,40},{10,11,67},{11,11,
+117},{11,11,768},{139,11,935},{7,11,992},{8,11,301},{9,11,722},{12,11,63},{13,11
+,29},{14,11,161},{143,11,18},{6,0,1490},{138,11,532},{5,0,580},{7,0,378},{7,0,
+674},{7,0,1424},{15,0,83},{16,0,11},{15,11,83},{144,11,11},{6,0,1057},{6,0,1335}
+,{10,0,316},{7,10,85},{7,10,247},{8,10,585},{138,10,163},{4,0,169},{5,0,83},{6,0
+,399},{6,0,579},{6,0,1513},{7,0,692},{7,0,846},{7,0,1015},{7,0,1799},{8,0,403},{
+9,0,394},{10,0,133},{12,0,4},{12,0,297},{12,0,452},{16,0,81},{18,0,25},{21,0,14}
+,{22,0,12},{151,0,18},{134,0,1106},{7,0,1546},{11,0,299},{142,0,407},{134,0,1192
+},{132,0,177},{5,0,411},{135,0,653},{7,0,439},{10,0,727},{11,0,260},{139,0,684},
+{138,10,145},{147,10,83},{5,0,208},{7,0,753},{135,0,1528},{137,11,617},{135,10,
+1922},{135,11,825},{11,0,422},{13,0,389},{4,10,124},{10,10,457},{11,10,121},{11,
+10,169},{11,10,870},{12,10,214},{14,10,187},{143,10,77},{11,0,615},{15,0,58},{11
+,11,615},{143,11,58},{9,0,618},{138,0,482},{6,0,1952},{6,0,1970},{142,0,505},{7,
+10,1193},{135,11,1838},{133,0,242},{135,10,1333},{6,10,107},{7,10,638},{7,10,
+1632},{137,10,396},{133,0,953},{5,10,370},{134,10,1756},{5,11,28},{6,11,204},{10
+,11,320},{10,11,583},{13,11,502},{14,11,72},{14,11,274},{14,11,312},{14,11,344},
+{15,11,159},{16,11,62},{16,11,69},{17,11,30},{18,11,42},{18,11,53},{18,11,84},{
+18,11,140},{19,11,68},{19,11,85},{20,11,5},{20,11,45},{20,11,101},{22,11,7},{150
+,11,20},{4,11,558},{6,11,390},{7,11,162},{7,11,689},{9,11,360},{138,11,653},{11,
+0,802},{141,0,67},{133,10,204},{133,0,290},{5,10,970},{134,10,1706},{132,0,380},
+{5,0,52},{7,0,277},{9,0,368},{139,0,791},{5,11,856},{6,11,1672},{6,11,1757},{6,
+11,1781},{7,11,1150},{7,11,1425},{7,11,1453},{140,11,513},{5,11,92},{7,10,3},{10
+,11,736},{140,11,102},{4,0,112},{5,0,653},{5,10,483},{5,10,685},{6,10,489},{7,10
+,1204},{136,10,394},{132,10,921},{6,0,1028},{133,10,1007},{5,11,590},{9,11,213},
+{145,11,91},{135,10,1696},{10,0,138},{139,0,476},{5,0,725},{5,0,727},{135,0,1811
+},{4,0,979},{6,0,1821},{6,0,1838},{8,0,876},{8,0,883},{8,0,889},{8,0,893},{8,0,
+895},{10,0,934},{12,0,720},{14,0,459},{148,0,123},{135,11,551},{4,0,38},{6,0,435
+},{7,0,307},{7,0,999},{7,0,1481},{7,0,1732},{7,0,1738},{8,0,371},{9,0,414},{11,0
+,316},{12,0,52},{13,0,420},{147,0,100},{135,0,1296},{132,10,712},{134,10,1629},{
+133,0,723},{134,0,651},{136,11,191},{9,11,791},{10,11,93},{11,11,301},{16,11,13}
+,{17,11,23},{18,11,135},{19,11,12},{20,11,1},{20,11,12},{148,11,14},{136,11,503}
+,{6,11,466},{135,11,671},{6,0,1200},{134,0,1330},{135,0,1255},{134,0,986},{5,0,
+109},{6,0,1784},{7,0,1895},{12,0,296},{140,0,302},{135,11,983},{133,10,485},{134
+,0,660},{134,0,800},{5,0,216},{5,0,294},{6,0,591},{7,0,1879},{9,0,141},{9,0,270}
+,{9,0,679},{10,0,159},{11,0,197},{11,0,438},{12,0,538},{12,0,559},{14,0,144},{14
+,0,167},{15,0,67},{4,10,285},{5,10,317},{6,10,301},{7,10,7},{8,10,153},{10,10,
+766},{11,10,468},{12,10,467},{141,10,143},{136,0,945},{134,0,1090},{137,0,81},{
+12,11,468},{19,11,96},{148,11,24},{134,0,391},{138,11,241},{7,0,322},{136,0,249}
+,{134,0,1412},{135,11,795},{5,0,632},{138,0,526},{136,10,819},{6,0,144},{7,0,948
+},{7,0,1042},{8,0,235},{8,0,461},{9,0,453},{9,0,796},{10,0,354},{17,0,77},{135,
+11,954},{139,10,917},{6,0,940},{134,0,1228},{4,0,362},{7,0,52},{135,0,303},{6,11
+,549},{8,11,34},{8,11,283},{9,11,165},{138,11,475},{7,11,370},{7,11,1007},{7,11,
+1177},{135,11,1565},{5,11,652},{5,11,701},{135,11,449},{5,0,196},{6,0,486},{7,0,
+212},{8,0,309},{136,0,346},{6,10,1719},{6,10,1735},{7,10,2016},{7,10,2020},{8,10
+,837},{137,10,852},{6,11,159},{6,11,364},{7,11,516},{7,11,1439},{137,11,518},{
+135,0,1912},{135,0,1290},{132,0,686},{141,11,151},{138,0,625},{136,0,706},{138,
+10,568},{139,0,412},{4,0,30},{133,0,43},{8,10,67},{138,10,419},{7,0,967},{141,0,
+11},{12,0,758},{14,0,441},{142,0,462},{10,10,657},{14,10,297},{142,10,361},{139,
+10,729},{4,0,220},{135,0,1535},{7,11,501},{9,11,111},{10,11,141},{11,11,332},{13
+,11,43},{13,11,429},{14,11,130},{14,11,415},{145,11,102},{4,0,950},{6,0,1859},{7
+,0,11},{8,0,873},{12,0,710},{12,0,718},{12,0,748},{12,0,765},{148,0,124},{5,11,
+149},{5,11,935},{136,11,233},{142,11,291},{134,0,1579},{7,0,890},{8,10,51},{9,10
+,868},{10,10,833},{12,10,481},{12,10,570},{148,10,106},{141,0,2},{132,10,445},{
+136,11,801},{135,0,1774},{7,0,1725},{138,0,393},{5,0,263},{134,0,414},{132,11,
+322},{133,10,239},{7,0,456},{7,10,1990},{8,10,130},{139,10,720},{137,0,818},{5,
+10,123},{6,10,530},{7,10,348},{135,10,1419},{135,10,2024},{6,0,178},{6,0,1750},{
+8,0,251},{9,0,690},{10,0,155},{10,0,196},{10,0,373},{11,0,698},{13,0,155},{148,0
+,93},{5,0,97},{137,0,393},{134,0,674},{11,0,223},{140,0,168},{132,10,210},{139,
+11,464},{6,0,1639},{146,0,159},{139,11,2},{7,0,934},{8,0,647},{17,0,97},{19,0,59
+},{150,0,2},{132,0,191},{5,0,165},{9,0,346},{10,0,655},{11,0,885},{4,10,430},{
+135,11,357},{133,0,877},{5,10,213},{133,11,406},{8,0,128},{139,0,179},{6,11,69},
+{135,11,117},{135,0,1297},{11,11,43},{13,11,72},{141,11,142},{135,11,1830},{142,
+0,164},{5,0,57},{6,0,101},{6,0,586},{6,0,1663},{7,0,132},{7,0,1154},{7,0,1415},{
+7,0,1507},{12,0,493},{15,0,105},{151,0,15},{5,0,459},{7,0,1073},{8,0,241},{136,0
+,334},{133,11,826},{133,10,108},{5,10,219},{10,11,132},{11,11,191},{11,11,358},{
+139,11,460},{6,0,324},{6,0,520},{7,0,338},{7,0,1729},{8,0,228},{139,0,750},{21,0
+,30},{22,0,53},{4,10,193},{5,10,916},{7,10,364},{10,10,398},{10,10,726},{11,10,
+317},{11,10,626},{12,10,142},{12,10,288},{12,10,678},{13,10,313},{15,10,113},{
+146,10,114},{6,11,110},{135,11,1681},{135,0,910},{6,10,241},{7,10,907},{8,10,832
+},{9,10,342},{10,10,729},{11,10,284},{11,10,445},{11,10,651},{11,10,863},{13,10,
+398},{146,10,99},{7,0,705},{9,0,734},{5,11,1000},{7,11,733},{137,11,583},{4,0,73
+},{6,0,612},{7,0,927},{7,0,1822},{8,0,217},{9,0,765},{9,0,766},{10,0,408},{11,0,
+51},{11,0,793},{12,0,266},{15,0,158},{20,0,89},{150,0,32},{7,0,1330},{4,11,297},
+{6,11,529},{7,11,152},{7,11,713},{7,11,1845},{8,11,710},{8,11,717},{140,11,639},
+{5,0,389},{136,0,636},{134,0,1409},{4,10,562},{9,10,254},{139,10,879},{134,0,893
+},{132,10,786},{4,11,520},{135,11,575},{136,0,21},{140,0,721},{136,0,959},{7,11,
+1428},{7,11,1640},{9,11,169},{9,11,182},{9,11,367},{9,11,478},{9,11,506},{9,11,
+551},{9,11,648},{9,11,651},{9,11,697},{9,11,705},{9,11,725},{9,11,787},{9,11,794
+},{10,11,198},{10,11,214},{10,11,267},{10,11,275},{10,11,456},{10,11,551},{10,11
+,561},{10,11,613},{10,11,627},{10,11,668},{10,11,675},{10,11,691},{10,11,695},{
+10,11,707},{10,11,715},{11,11,183},{11,11,201},{11,11,244},{11,11,262},{11,11,
+352},{11,11,439},{11,11,493},{11,11,572},{11,11,591},{11,11,608},{11,11,611},{11
+,11,646},{11,11,674},{11,11,711},{11,11,751},{11,11,761},{11,11,776},{11,11,785}
+,{11,11,850},{11,11,853},{11,11,862},{11,11,865},{11,11,868},{11,11,898},{11,11,
+902},{11,11,903},{11,11,910},{11,11,932},{11,11,942},{11,11,957},{11,11,967},{11
+,11,972},{12,11,148},{12,11,195},{12,11,220},{12,11,237},{12,11,318},{12,11,339}
+,{12,11,393},{12,11,445},{12,11,450},{12,11,474},{12,11,509},{12,11,533},{12,11,
+591},{12,11,594},{12,11,597},{12,11,621},{12,11,633},{12,11,642},{13,11,59},{13,
+11,60},{13,11,145},{13,11,239},{13,11,250},{13,11,273},{13,11,329},{13,11,344},{
+13,11,365},{13,11,372},{13,11,387},{13,11,403},{13,11,414},{13,11,456},{13,11,
+478},{13,11,483},{13,11,489},{14,11,55},{14,11,57},{14,11,81},{14,11,90},{14,11,
+148},{14,11,239},{14,11,266},{14,11,321},{14,11,326},{14,11,327},{14,11,330},{14
+,11,347},{14,11,355},{14,11,401},{14,11,411},{14,11,414},{14,11,416},{14,11,420}
+,{15,11,61},{15,11,74},{15,11,87},{15,11,88},{15,11,94},{15,11,96},{15,11,116},{
+15,11,149},{15,11,154},{16,11,50},{16,11,63},{16,11,73},{17,11,2},{17,11,66},{17
+,11,92},{17,11,103},{17,11,112},{18,11,50},{18,11,54},{18,11,82},{18,11,86},{18,
+11,90},{18,11,111},{18,11,115},{18,11,156},{19,11,40},{19,11,79},{20,11,78},{149
+,11,22},{137,11,170},{134,0,1433},{135,11,1307},{139,11,411},{5,0,189},{7,0,442}
+,{7,0,443},{8,0,281},{12,0,174},{141,0,261},{6,10,216},{7,10,901},{7,10,1343},{
+136,10,493},{5,11,397},{6,11,154},{7,10,341},{7,11,676},{8,11,443},{8,11,609},{9
+,11,24},{9,11,325},{10,11,35},{11,10,219},{11,11,535},{11,11,672},{11,11,1018},{
+12,11,637},{144,11,30},{6,0,2},{7,0,191},{7,0,446},{7,0,1262},{7,0,1737},{8,0,22
+},{8,0,270},{8,0,612},{9,0,4},{9,0,312},{9,0,436},{9,0,626},{10,0,216},{10,0,311
+},{10,0,521},{10,0,623},{11,0,72},{11,0,330},{11,0,455},{12,0,321},{12,0,504},{
+12,0,530},{12,0,543},{13,0,17},{13,0,156},{13,0,334},{14,0,131},{17,0,60},{148,0
+,64},{7,0,354},{10,0,410},{139,0,815},{139,10,130},{7,10,1734},{137,11,631},{12,
+0,425},{15,0,112},{10,10,115},{11,10,420},{13,10,404},{14,10,346},{143,10,54},{6
+,0,60},{6,0,166},{7,0,374},{7,0,670},{7,0,1327},{8,0,411},{8,0,435},{9,0,653},{9
+,0,740},{10,0,385},{11,0,222},{11,0,324},{11,0,829},{140,0,611},{7,0,1611},{13,0
+,14},{15,0,44},{19,0,13},{148,0,76},{133,11,981},{4,11,56},{7,11,1791},{8,11,607
+},{8,11,651},{11,11,465},{11,11,835},{12,11,337},{141,11,480},{6,0,1478},{5,10,
+1011},{136,10,701},{139,0,596},{5,0,206},{134,0,398},{4,10,54},{5,10,666},{7,10,
+1039},{7,10,1130},{9,10,195},{138,10,302},{7,0,50},{9,11,158},{138,11,411},{135,
+11,1120},{6,0,517},{7,0,1159},{10,0,621},{11,0,192},{134,10,1669},{4,0,592},{6,0
+,600},{135,0,1653},{10,0,223},{139,0,645},{136,11,139},{7,0,64},{136,0,245},{142
+,0,278},{6,11,622},{135,11,1030},{136,0,604},{134,0,1502},{138,0,265},{141,11,
+168},{7,0,1763},{140,0,310},{7,10,798},{139,11,719},{7,11,160},{10,11,624},{142,
+11,279},{132,11,363},{7,10,122},{9,10,259},{10,10,84},{11,10,470},{12,10,541},{
+141,10,379},{5,0,129},{6,0,61},{135,0,947},{134,0,1356},{135,11,1191},{13,0,505}
+,{141,0,506},{11,0,1000},{5,10,82},{5,10,131},{7,10,1755},{8,10,31},{9,10,168},{
+9,10,764},{139,10,869},{134,0,966},{134,10,605},{134,11,292},{5,11,177},{6,11,
+616},{7,11,827},{9,11,525},{138,11,656},{135,11,1486},{138,11,31},{5,10,278},{
+137,10,68},{4,10,163},{5,10,201},{5,10,307},{5,10,310},{6,10,335},{7,10,284},{
+136,10,165},{6,0,839},{135,10,1660},{136,10,781},{6,10,33},{135,10,1244},{133,0,
+637},{4,11,161},{133,11,631},{137,0,590},{7,10,1953},{136,10,720},{5,0,280},{7,0
+,1226},{138,10,203},{134,0,1386},{5,0,281},{6,0,1026},{6,10,326},{7,10,677},{137
+,10,425},{7,11,1557},{135,11,1684},{135,0,1064},{9,11,469},{9,11,709},{12,11,512
+},{14,11,65},{145,11,12},{134,0,917},{10,11,229},{11,11,73},{11,11,376},{139,11,
+433},{7,0,555},{9,0,192},{13,0,30},{13,0,49},{15,0,150},{16,0,76},{20,0,52},{7,
+10,1316},{7,10,1412},{7,10,1839},{9,10,589},{11,10,241},{11,10,676},{11,10,811},
+{11,10,891},{12,10,140},{12,10,346},{12,10,479},{13,10,381},{14,10,188},{146,10,
+30},{149,0,15},{6,0,1882},{6,0,1883},{6,0,1897},{9,0,945},{9,0,1014},{9,0,1020},
+{12,0,823},{12,0,842},{12,0,866},{12,0,934},{15,0,242},{146,0,208},{6,0,965},{
+134,0,1499},{7,0,33},{7,0,120},{8,0,489},{9,0,319},{10,0,820},{11,0,1004},{12,0,
+379},{12,0,679},{13,0,117},{13,0,412},{14,0,25},{15,0,52},{15,0,161},{16,0,47},{
+149,0,2},{6,11,558},{7,11,651},{8,11,421},{9,11,0},{138,11,34},{4,0,937},{5,0,
+801},{7,0,473},{5,10,358},{7,10,1184},{10,10,662},{13,10,212},{13,10,304},{13,10
+,333},{145,10,98},{132,0,877},{6,0,693},{134,0,824},{132,0,365},{7,11,1832},{138
+,11,374},{5,0,7},{139,0,774},{4,0,734},{5,0,662},{134,0,430},{4,0,746},{135,0,
+1090},{5,0,360},{8,0,237},{10,0,231},{147,0,124},{138,11,348},{6,11,6},{7,11,81}
+,{7,11,771},{7,11,1731},{9,11,405},{138,11,421},{6,0,740},{137,0,822},{133,10,
+946},{7,0,1485},{136,0,929},{7,10,411},{8,10,631},{9,10,323},{10,10,355},{11,10,
+491},{12,10,143},{12,10,402},{13,10,73},{14,10,408},{15,10,107},{146,10,71},{135
+,10,590},{5,11,881},{133,11,885},{150,11,25},{4,0,852},{5,11,142},{134,11,546},{
+7,10,1467},{8,10,328},{10,10,544},{11,10,955},{13,10,320},{145,10,83},{9,0,17},{
+10,0,291},{11,10,511},{13,10,394},{14,10,298},{14,10,318},{146,10,103},{5,11,466
+},{11,11,571},{12,11,198},{13,11,283},{14,11,186},{15,11,21},{143,11,103},{134,0
+,1001},{4,11,185},{5,11,257},{5,11,839},{5,11,936},{7,11,171},{9,11,399},{10,11,
+258},{10,11,395},{10,11,734},{11,11,1014},{12,11,23},{13,11,350},{14,11,150},{
+147,11,6},{143,0,35},{132,0,831},{5,10,835},{134,10,483},{4,0,277},{5,0,608},{6,
+0,493},{7,0,457},{12,0,384},{7,11,404},{7,11,1377},{7,11,1430},{7,11,2017},{8,11
+,149},{8,11,239},{8,11,512},{8,11,793},{8,11,818},{9,11,474},{9,11,595},{10,11,
+122},{10,11,565},{10,11,649},{10,11,783},{11,11,239},{11,11,295},{11,11,447},{11
+,11,528},{11,11,639},{11,11,800},{11,11,936},{12,11,25},{12,11,73},{12,11,77},{
+12,11,157},{12,11,316},{12,11,390},{12,11,391},{12,11,394},{12,11,395},{12,11,
+478},{12,11,503},{12,11,592},{12,11,680},{13,11,50},{13,11,53},{13,11,132},{13,
+11,198},{13,11,275},{13,11,322},{13,11,415},{14,11,71},{14,11,257},{14,11,395},{
+15,11,71},{15,11,136},{17,11,123},{18,11,93},{147,11,58},{134,0,1351},{7,0,27},{
+135,0,316},{136,11,712},{136,0,984},{133,0,552},{137,0,264},{132,0,401},{6,0,710
+},{6,0,1111},{134,0,1343},{134,0,1211},{9,0,543},{10,0,524},{11,0,108},{11,0,653
+},{12,0,524},{13,0,123},{14,0,252},{16,0,18},{19,0,38},{20,0,26},{20,0,65},{21,0
+,3},{151,0,11},{4,0,205},{5,0,623},{7,0,104},{8,0,519},{137,0,716},{132,10,677},
+{4,11,377},{152,11,13},{135,11,1673},{7,0,579},{9,0,41},{9,0,244},{9,0,669},{10,
+0,5},{11,0,861},{11,0,951},{139,0,980},{132,0,717},{136,0,1011},{132,0,805},{4,
+11,180},{135,11,1906},{132,10,777},{132,10,331},{132,0,489},{6,0,1024},{4,11,491
+},{133,10,747},{135,11,1182},{4,11,171},{138,11,234},{4,11,586},{7,11,1186},{138
+,11,631},{135,0,892},{135,11,336},{9,11,931},{10,11,334},{148,11,71},{137,0,473}
+,{6,0,864},{12,0,659},{139,11,926},{7,0,819},{9,0,26},{9,0,392},{10,0,152},{10,0
+,226},{11,0,19},{12,0,276},{12,0,426},{12,0,589},{13,0,460},{15,0,97},{19,0,48},
+{148,0,104},{135,0,51},{133,10,326},{4,10,691},{146,10,16},{9,0,130},{11,0,765},
+{10,10,680},{10,10,793},{141,10,357},{133,11,765},{8,0,229},{6,10,32},{7,10,385}
+,{7,10,757},{7,10,1916},{8,10,94},{8,10,711},{9,10,541},{10,10,162},{10,10,795},
+{11,10,989},{11,10,1010},{12,10,14},{142,10,308},{7,11,474},{137,11,578},{132,0,
+674},{132,0,770},{5,0,79},{7,0,1027},{7,0,1477},{139,0,52},{133,11,424},{134,0,
+1666},{6,0,409},{6,10,349},{6,10,1682},{7,10,1252},{8,10,112},{8,11,714},{9,10,
+435},{9,10,668},{10,10,290},{10,10,319},{10,10,815},{11,10,180},{11,10,837},{12,
+10,240},{13,10,152},{13,10,219},{142,10,158},{5,0,789},{134,0,195},{4,0,251},{4,
+0,688},{7,0,513},{135,0,1284},{132,10,581},{9,11,420},{10,11,269},{10,11,285},{
+10,11,576},{11,11,397},{13,11,175},{145,11,90},{6,10,126},{7,10,573},{8,10,397},
+{142,10,44},{132,11,429},{133,0,889},{4,0,160},{5,0,330},{7,0,1434},{136,0,174},
+{7,11,18},{7,11,699},{7,11,1966},{8,11,752},{9,11,273},{9,11,412},{9,11,703},{10
+,11,71},{10,11,427},{10,11,508},{146,11,97},{6,0,872},{134,0,899},{133,10,926},{
+134,0,1126},{134,0,918},{4,11,53},{5,11,186},{135,11,752},{7,0,268},{136,0,569},
+{134,0,1224},{6,0,1361},{7,10,1232},{137,10,531},{8,11,575},{10,11,289},{139,11,
+319},{133,10,670},{132,11,675},{133,0,374},{135,10,1957},{133,0,731},{11,0,190},
+{15,0,49},{11,11,190},{143,11,49},{4,0,626},{5,0,506},{5,0,642},{6,0,425},{10,0,
+202},{139,0,141},{137,0,444},{7,10,242},{135,10,1942},{6,11,209},{8,11,468},{9,
+11,210},{11,11,36},{12,11,28},{12,11,630},{13,11,21},{13,11,349},{14,11,7},{145,
+11,13},{4,11,342},{135,11,1179},{5,10,834},{7,10,1202},{8,10,14},{9,10,481},{137
+,10,880},{4,11,928},{133,11,910},{4,11,318},{4,11,496},{7,11,856},{139,11,654},{
+136,0,835},{7,0,1526},{138,10,465},{151,0,17},{135,0,477},{4,10,357},{6,10,172},
+{7,10,143},{137,10,413},{6,0,1374},{138,0,994},{18,0,76},{132,10,590},{7,0,287},
+{8,0,355},{9,0,293},{137,0,743},{134,0,1389},{7,11,915},{8,11,247},{147,11,0},{4
+,11,202},{5,11,382},{6,11,454},{7,11,936},{7,11,1803},{8,11,758},{9,11,375},{9,
+11,895},{10,11,743},{10,11,792},{11,11,978},{11,11,1012},{142,11,109},{5,0,384},
+{8,0,455},{140,0,48},{132,11,390},{5,10,169},{7,10,333},{136,10,45},{5,0,264},{
+134,0,184},{138,11,791},{133,11,717},{132,10,198},{6,11,445},{7,11,332},{137,11,
+909},{136,0,1001},{4,10,24},{5,10,140},{5,10,185},{7,10,1500},{11,10,565},{139,
+10,838},{134,11,578},{5,0,633},{6,0,28},{135,0,1323},{132,0,851},{136,11,267},{7
+,0,359},{8,0,243},{140,0,175},{4,10,334},{133,10,593},{141,11,87},{136,11,766},{
+10,0,287},{12,0,138},{10,11,287},{140,11,138},{4,0,105},{132,0,740},{140,10,116}
+,{134,0,857},{135,11,1841},{6,0,1402},{137,0,819},{132,11,584},{132,10,709},{133
+,10,897},{5,0,224},{13,0,174},{146,0,52},{135,10,1840},{4,10,608},{133,10,497},{
+139,11,60},{4,0,758},{135,0,1649},{4,11,226},{4,11,326},{135,11,1770},{5,11,426}
+,{8,11,30},{9,11,2},{11,11,549},{147,11,122},{135,10,2039},{6,10,540},{136,10,
+136},{4,0,573},{8,0,655},{4,10,897},{133,10,786},{7,0,351},{139,0,128},{133,10,
+999},{4,10,299},{135,10,1004},{133,0,918},{132,11,345},{4,11,385},{7,11,265},{
+135,11,587},{133,10,456},{136,10,180},{6,0,687},{134,0,1537},{4,11,347},{5,11,
+423},{5,11,996},{135,11,1329},{132,10,755},{7,11,1259},{9,11,125},{11,11,65},{
+140,11,285},{5,11,136},{6,11,136},{136,11,644},{134,0,1525},{4,0,1009},{135,0,
+1139},{139,10,338},{132,0,340},{135,10,1464},{8,0,847},{10,0,861},{10,0,876},{10
+,0,889},{10,0,922},{10,0,929},{10,0,933},{12,0,784},{140,0,791},{139,0,176},{9,
+11,134},{10,11,2},{10,11,27},{10,11,333},{11,11,722},{143,11,1},{4,11,433},{133,
+11,719},{5,0,985},{7,0,509},{7,0,529},{145,0,96},{132,0,615},{4,10,890},{5,10,
+805},{5,10,819},{5,10,961},{6,10,396},{6,10,1631},{6,10,1678},{7,10,1967},{7,10,
+2041},{9,10,630},{11,10,8},{11,10,1019},{12,10,176},{13,10,225},{14,10,292},{149
+,10,24},{135,0,1919},{134,0,1131},{144,11,21},{144,11,51},{135,10,1815},{4,0,247
+},{7,10,1505},{10,10,190},{10,10,634},{11,10,792},{12,10,358},{140,10,447},{5,10
+,0},{6,10,536},{7,10,604},{13,10,445},{145,10,126},{4,0,184},{5,0,390},{6,0,337}
+,{7,0,23},{7,0,494},{7,0,618},{7,0,1456},{8,0,27},{8,0,599},{10,0,153},{139,0,
+710},{6,10,232},{6,10,412},{7,10,1074},{8,10,9},{8,10,157},{8,10,786},{9,10,196}
+,{9,10,352},{9,10,457},{10,10,337},{11,10,232},{11,10,877},{12,10,480},{140,10,
+546},{13,0,38},{135,10,958},{4,10,382},{136,10,579},{4,10,212},{135,10,1206},{4,
+11,555},{8,11,536},{138,11,288},{11,11,139},{139,11,171},{9,11,370},{138,11,90},
+{132,0,1015},{134,0,1088},{5,10,655},{135,11,977},{134,0,1585},{17,10,67},{147,
+10,74},{10,0,227},{11,0,497},{11,0,709},{140,0,415},{6,0,360},{7,0,1664},{136,0,
+478},{7,0,95},{6,10,231},{136,10,423},{140,11,65},{4,11,257},{135,11,2031},{135,
+11,1768},{133,10,300},{139,11,211},{136,0,699},{6,10,237},{7,10,611},{8,10,100},
+{9,10,416},{11,10,335},{12,10,173},{146,10,101},{14,0,26},{146,0,150},{6,0,581},
+{135,0,1119},{135,10,1208},{132,0,739},{6,11,83},{6,11,1733},{135,11,1389},{137,
+0,869},{4,0,67},{5,0,422},{7,0,1037},{7,0,1289},{7,0,1555},{9,0,741},{145,0,108}
+,{133,10,199},{12,10,427},{146,10,38},{136,0,464},{142,0,42},{10,0,96},{8,11,501
+},{137,11,696},{134,11,592},{4,0,512},{4,0,966},{5,0,342},{6,0,1855},{8,0,869},{
+8,0,875},{8,0,901},{144,0,26},{8,0,203},{11,0,823},{11,0,846},{12,0,482},{13,0,
+277},{13,0,302},{13,0,464},{14,0,205},{142,0,221},{4,0,449},{133,0,718},{7,11,
+1718},{9,11,95},{9,11,274},{10,11,279},{10,11,317},{10,11,420},{11,11,303},{11,
+11,808},{12,11,134},{12,11,367},{13,11,149},{13,11,347},{14,11,349},{14,11,406},
+{18,11,22},{18,11,89},{18,11,122},{147,11,47},{133,11,26},{4,0,355},{6,0,311},{9
+,0,256},{138,0,404},{132,11,550},{10,0,758},{6,10,312},{6,10,1715},{10,10,584},{
+11,10,546},{11,10,692},{12,10,259},{12,10,295},{13,10,46},{141,10,154},{136,11,
+822},{5,0,827},{4,11,902},{5,11,809},{6,11,122},{135,11,896},{5,0,64},{140,0,581
+},{4,0,442},{6,0,739},{7,0,1047},{7,0,1352},{7,0,1643},{7,11,1911},{9,11,449},{
+10,11,192},{138,11,740},{135,11,262},{132,10,588},{133,11,620},{5,0,977},{6,0,
+288},{7,0,528},{4,11,34},{5,11,574},{7,11,279},{7,11,1624},{136,11,601},{6,0,
+1375},{4,10,231},{5,10,61},{6,10,104},{7,10,729},{7,10,964},{7,10,1658},{140,10,
+414},{6,10,263},{138,10,757},{132,10,320},{4,0,254},{7,0,1309},{5,11,332},{135,
+11,1309},{6,11,261},{8,11,182},{139,11,943},{132,10,225},{6,0,12},{135,0,1219},{
+4,0,275},{12,0,376},{6,11,1721},{141,11,490},{4,11,933},{133,11,880},{6,0,951},{
+6,0,1109},{6,0,1181},{7,0,154},{4,10,405},{7,10,817},{14,10,58},{17,10,37},{146,
+10,124},{6,0,1520},{133,10,974},{134,0,1753},{6,0,369},{6,0,502},{7,0,1036},{8,0
+,348},{9,0,452},{10,0,26},{11,0,224},{11,0,387},{11,0,772},{12,0,95},{12,0,629},
+{13,0,195},{13,0,207},{13,0,241},{14,0,260},{14,0,270},{143,0,140},{132,0,269},{
+5,0,480},{7,0,532},{7,0,1197},{7,0,1358},{8,0,291},{11,0,349},{142,0,396},{5,10,
+235},{7,10,1239},{11,10,131},{140,10,370},{7,10,956},{7,10,1157},{7,10,1506},{7,
+10,1606},{7,10,1615},{7,10,1619},{7,10,1736},{7,10,1775},{8,10,590},{9,10,324},{
+9,10,736},{9,10,774},{9,10,776},{9,10,784},{10,10,567},{10,10,708},{11,10,518},{
+11,10,613},{11,10,695},{11,10,716},{11,10,739},{11,10,770},{11,10,771},{11,10,
+848},{11,10,857},{11,10,931},{11,10,947},{12,10,326},{12,10,387},{12,10,484},{12
+,10,528},{12,10,552},{12,10,613},{13,10,189},{13,10,256},{13,10,340},{13,10,432}
+,{13,10,436},{13,10,440},{13,10,454},{14,10,174},{14,10,220},{14,10,284},{14,10,
+390},{145,10,121},{8,11,598},{9,11,664},{138,11,441},{9,10,137},{138,10,221},{
+133,11,812},{148,0,15},{134,0,1341},{6,0,1017},{4,11,137},{7,11,1178},{135,11,
+1520},{7,10,390},{138,10,140},{7,11,1260},{135,11,1790},{137,11,191},{135,10,
+1144},{6,0,1810},{7,0,657},{8,0,886},{10,0,857},{14,0,440},{144,0,96},{8,0,533},
+{6,11,1661},{7,11,1975},{7,11,2009},{135,11,2011},{6,0,1453},{134,10,464},{132,
+11,715},{5,10,407},{11,10,204},{11,10,243},{11,10,489},{12,10,293},{19,10,37},{
+20,10,73},{150,10,38},{133,11,703},{4,0,211},{7,0,1483},{5,10,325},{8,10,5},{8,
+10,227},{9,10,105},{10,10,585},{140,10,614},{4,0,332},{5,0,335},{6,0,238},{7,0,
+269},{7,0,811},{7,0,1797},{8,0,836},{9,0,507},{141,0,242},{5,11,89},{7,11,1915},
+{9,11,185},{9,11,235},{9,11,496},{10,11,64},{10,11,270},{10,11,403},{10,11,469},
+{10,11,529},{10,11,590},{11,11,140},{11,11,860},{13,11,1},{13,11,422},{14,11,341
+},{14,11,364},{17,11,93},{18,11,113},{19,11,97},{147,11,113},{133,11,695},{16,0,
+19},{5,11,6},{6,11,183},{6,10,621},{7,11,680},{7,11,978},{7,11,1013},{7,11,1055}
+,{12,11,230},{13,11,172},{13,10,504},{146,11,29},{136,0,156},{133,0,1009},{6,11,
+29},{139,11,63},{134,0,820},{134,10,218},{7,10,454},{7,10,782},{8,10,768},{140,
+10,686},{5,0,228},{6,0,203},{7,0,156},{8,0,347},{9,0,265},{18,0,39},{20,0,54},{
+21,0,31},{22,0,3},{23,0,0},{15,11,8},{18,11,39},{20,11,54},{21,11,31},{22,11,3},
+{151,11,0},{7,0,1131},{135,0,1468},{144,10,0},{134,0,1276},{10,10,676},{140,10,
+462},{132,11,311},{134,11,1740},{7,11,170},{8,11,90},{8,11,177},{8,11,415},{11,
+11,714},{142,11,281},{134,10,164},{6,0,1792},{138,0,849},{150,10,50},{5,0,291},{
+5,0,318},{7,0,765},{9,0,389},{12,0,548},{8,11,522},{142,11,328},{11,11,91},{13,
+11,129},{15,11,101},{145,11,125},{4,11,494},{6,11,74},{7,11,44},{7,11,407},{8,11
+,551},{12,11,17},{15,11,5},{148,11,11},{4,11,276},{133,11,296},{6,10,343},{7,10,
+195},{7,11,1777},{9,10,226},{10,10,197},{10,10,575},{11,10,502},{139,10,899},{10
+,0,525},{139,0,82},{14,0,453},{4,11,7},{5,11,90},{5,11,158},{6,11,542},{7,11,221
+},{7,11,1574},{9,11,490},{10,11,540},{11,11,443},{139,11,757},{135,0,666},{22,10
+,29},{150,11,29},{4,0,422},{147,10,8},{5,0,355},{145,0,0},{6,0,1873},{9,0,918},{
+7,11,588},{9,11,175},{138,11,530},{143,11,31},{11,0,165},{7,10,1125},{9,10,143},
+{14,10,405},{150,10,21},{9,0,260},{137,0,905},{5,11,872},{6,11,57},{6,11,479},{6
+,11,562},{7,11,471},{7,11,1060},{9,11,447},{9,11,454},{141,11,6},{138,11,704},{
+133,0,865},{5,0,914},{134,0,1625},{133,0,234},{7,0,1383},{5,11,31},{6,11,614},{
+145,11,61},{7,11,1200},{138,11,460},{6,11,424},{135,11,1866},{136,0,306},{5,10,
+959},{12,11,30},{13,11,148},{14,11,87},{14,11,182},{16,11,42},{18,11,92},{148,11
+,70},{6,0,1919},{6,0,1921},{9,0,923},{9,0,930},{9,0,941},{9,0,949},{9,0,987},{9,
+0,988},{9,0,992},{12,0,802},{12,0,815},{12,0,856},{12,0,885},{12,0,893},{12,0,
+898},{12,0,919},{12,0,920},{12,0,941},{12,0,947},{15,0,183},{15,0,185},{15,0,189
+},{15,0,197},{15,0,202},{15,0,233},{18,0,218},{18,0,219},{18,0,233},{143,11,156}
+,{135,10,1759},{136,10,173},{13,0,163},{13,0,180},{18,0,78},{20,0,35},{5,11,13},
+{134,11,142},{134,10,266},{6,11,97},{7,11,116},{8,11,322},{8,11,755},{9,11,548},
+{10,11,714},{11,11,884},{141,11,324},{135,0,1312},{9,0,814},{137,11,676},{133,0,
+707},{135,0,1493},{6,0,421},{7,0,61},{7,0,1540},{10,0,11},{138,0,501},{12,0,733}
+,{12,0,766},{7,11,866},{135,11,1163},{137,0,341},{142,0,98},{145,11,115},{135,11
+,1111},{136,10,300},{136,0,1014},{8,11,1},{9,11,112},{138,11,326},{132,11,730},{
+5,11,488},{6,11,527},{7,11,489},{7,11,1636},{8,11,121},{8,11,144},{8,11,359},{9,
+11,193},{9,11,241},{9,11,336},{9,11,882},{11,11,266},{11,11,372},{11,11,944},{12
+,11,401},{140,11,641},{6,0,971},{134,0,1121},{6,0,102},{7,0,72},{15,0,142},{147,
+0,67},{151,0,30},{135,0,823},{134,0,1045},{5,10,427},{5,10,734},{7,10,478},{136,
+10,52},{7,0,1930},{11,10,217},{142,10,165},{6,0,1512},{135,0,1870},{9,11,31},{10
+,11,244},{10,11,699},{12,11,149},{141,11,497},{133,11,377},{145,11,101},{10,11,
+158},{13,11,13},{13,11,137},{13,11,258},{14,11,111},{14,11,225},{14,11,253},{14,
+11,304},{14,11,339},{14,11,417},{146,11,33},{6,0,87},{6,10,1734},{7,10,20},{7,10
+,1056},{8,10,732},{9,10,406},{9,10,911},{138,10,694},{134,0,1243},{137,0,245},{7
+,0,68},{8,0,48},{8,0,88},{8,0,582},{8,0,681},{9,0,373},{9,0,864},{11,0,157},{11,
+0,336},{11,0,843},{148,0,27},{8,11,663},{144,11,8},{133,10,613},{4,0,88},{5,0,
+137},{5,0,174},{5,0,777},{6,0,1664},{6,0,1725},{7,0,77},{7,0,426},{7,0,1317},{7,
+0,1355},{8,0,126},{8,0,563},{9,0,523},{9,0,750},{10,0,310},{10,0,836},{11,0,42},
+{11,0,318},{11,0,731},{12,0,68},{12,0,92},{12,0,507},{12,0,692},{13,0,81},{13,0,
+238},{13,0,374},{14,0,436},{18,0,138},{19,0,78},{19,0,111},{20,0,55},{20,0,77},{
+148,0,92},{141,0,418},{4,0,938},{137,0,625},{138,0,351},{5,11,843},{7,10,32},{7,
+10,984},{8,10,85},{8,10,709},{9,10,579},{9,10,847},{9,10,856},{10,10,799},{11,10
+,258},{11,10,1007},{12,10,331},{12,10,615},{13,10,188},{13,10,435},{14,10,8},{15
+,10,165},{16,10,27},{148,10,40},{6,0,1668},{7,0,1499},{8,0,117},{9,0,314},{138,0
+,174},{135,0,707},{132,11,554},{133,11,536},{5,0,403},{5,11,207},{9,11,79},{11,
+11,625},{145,11,7},{132,11,424},{136,11,785},{4,10,167},{135,10,82},{9,0,7},{23,
+0,6},{9,11,7},{151,11,6},{6,0,282},{5,10,62},{6,10,534},{7,10,74},{7,10,678},{7,
+10,684},{7,10,1043},{7,10,1072},{8,10,280},{8,10,541},{8,10,686},{9,10,258},{10,
+10,519},{11,10,252},{140,10,282},{138,10,33},{132,10,359},{4,0,44},{5,0,311},{6,
+0,156},{7,0,639},{7,0,762},{7,0,1827},{9,0,8},{9,0,462},{148,0,83},{7,11,769},{9
+,11,18},{138,11,358},{4,0,346},{7,0,115},{9,0,180},{9,0,456},{10,0,363},{4,11,
+896},{134,11,1777},{133,10,211},{7,0,761},{7,0,1051},{137,0,545},{6,10,145},{141
+,10,336},{7,11,750},{9,11,223},{11,11,27},{11,11,466},{12,11,624},{14,11,265},{
+146,11,61},{6,0,752},{6,0,768},{6,0,1195},{6,0,1254},{6,0,1619},{137,0,835},{6,0
+,1936},{8,0,930},{136,0,960},{132,10,263},{132,11,249},{12,0,653},{132,10,916},{
+4,11,603},{133,11,661},{8,0,344},{4,11,11},{6,11,128},{7,11,231},{7,11,1533},{
+138,11,725},{134,0,1483},{134,0,875},{6,0,185},{7,0,1899},{9,0,875},{139,0,673},
+{15,10,155},{144,10,79},{7,0,93},{7,0,210},{7,0,1223},{8,0,451},{8,0,460},{11,0,
+353},{11,0,475},{4,10,599},{6,10,1634},{7,10,67},{7,10,691},{7,10,979},{7,10,
+1697},{8,10,207},{8,10,214},{8,10,231},{8,10,294},{8,10,336},{8,10,428},{8,10,
+471},{8,10,622},{8,10,626},{8,10,679},{8,10,759},{8,10,829},{9,10,11},{9,10,246}
+,{9,10,484},{9,10,573},{9,10,706},{9,10,762},{9,10,798},{9,10,855},{9,10,870},{9
+,10,912},{10,10,303},{10,10,335},{10,10,424},{10,10,461},{10,10,543},{10,10,759}
+,{10,10,814},{11,10,59},{11,10,235},{11,10,590},{11,10,929},{11,10,963},{11,10,
+987},{12,10,114},{12,10,182},{12,10,226},{12,10,332},{12,10,439},{12,10,575},{12
+,10,598},{12,10,675},{13,10,8},{13,10,125},{13,10,194},{13,10,287},{14,10,197},{
+14,10,383},{15,10,53},{17,10,63},{19,10,46},{19,10,98},{19,10,106},{148,10,85},{
+132,11,476},{4,0,327},{5,0,478},{7,0,1332},{136,0,753},{5,0,1020},{133,0,1022},{
+135,11,1807},{4,0,103},{133,0,401},{4,0,499},{135,0,1421},{10,0,207},{13,0,164},
+{147,10,126},{9,11,20},{10,11,324},{139,11,488},{132,0,96},{9,11,280},{138,11,
+134},{135,0,968},{133,10,187},{135,10,1286},{5,11,112},{6,11,103},{134,11,150},{
+8,0,914},{10,0,3},{4,10,215},{9,10,38},{11,10,23},{11,10,127},{139,10,796},{135,
+0,399},{6,0,563},{137,0,224},{6,0,704},{134,0,1214},{4,11,708},{8,11,15},{9,11,
+50},{9,11,386},{11,11,18},{11,11,529},{140,11,228},{4,11,563},{7,11,109},{7,11,
+592},{7,11,637},{7,11,770},{7,11,1701},{8,11,436},{8,11,463},{9,11,60},{9,11,335
+},{9,11,904},{10,11,73},{11,11,434},{12,11,585},{13,11,331},{18,11,110},{148,11,
+60},{134,0,1559},{132,11,502},{6,11,347},{138,11,161},{4,11,33},{5,11,102},{5,11
+,500},{6,11,284},{7,11,1079},{7,11,1423},{7,11,1702},{8,11,470},{9,11,554},{9,11
+,723},{139,11,333},{7,11,246},{135,11,840},{6,11,10},{8,11,571},{9,11,739},{143,
+11,91},{8,0,861},{10,0,905},{12,0,730},{12,0,789},{133,11,626},{134,0,946},{5,0,
+746},{12,0,333},{14,0,332},{12,11,333},{142,11,332},{5,11,18},{6,11,526},{13,11,
+24},{13,11,110},{19,11,5},{147,11,44},{4,0,910},{5,0,832},{135,10,2002},{10,11,
+768},{139,11,787},{4,11,309},{5,11,462},{7,11,970},{135,11,1097},{4,10,28},{5,10
+,440},{7,10,248},{11,10,833},{140,10,344},{134,10,1654},{6,0,632},{6,0,652},{6,0
+,1272},{6,0,1384},{134,0,1560},{134,11,1704},{6,0,1393},{133,10,853},{6,10,249},
+{7,10,1234},{139,10,573},{5,11,86},{7,11,743},{9,11,85},{10,11,281},{10,11,432},
+{11,11,490},{12,11,251},{13,11,118},{14,11,378},{146,11,143},{5,11,524},{133,11,
+744},{134,0,1514},{10,0,201},{142,0,319},{7,0,717},{10,0,510},{7,10,392},{8,10,
+20},{8,10,172},{8,10,690},{9,10,383},{9,10,845},{11,10,293},{11,10,832},{11,10,
+920},{11,10,984},{141,10,221},{134,0,1381},{5,10,858},{133,10,992},{8,0,528},{
+137,0,348},{10,11,107},{140,11,436},{4,0,20},{133,0,616},{134,0,1251},{132,11,
+927},{10,11,123},{12,11,670},{13,11,371},{14,11,142},{146,11,94},{134,0,1163},{7
+,11,1149},{137,11,156},{134,0,307},{133,11,778},{7,0,1091},{135,0,1765},{5,11,
+502},{6,10,268},{137,10,62},{8,11,196},{10,11,283},{139,11,406},{4,0,26},{5,0,
+429},{6,0,245},{7,0,704},{7,0,1379},{135,0,1474},{133,11,855},{132,0,881},{4,0,
+621},{135,11,1596},{7,11,1400},{9,11,446},{138,11,45},{6,0,736},{138,10,106},{
+133,0,542},{134,0,348},{133,0,868},{136,0,433},{135,0,1495},{138,0,771},{6,10,
+613},{136,10,223},{138,0,215},{141,0,124},{136,11,391},{135,11,172},{132,10,670}
+,{140,0,55},{9,10,40},{139,10,136},{7,0,62},{147,0,112},{132,0,856},{132,11,568}
+,{12,0,270},{139,10,259},{8,0,572},{137,0,698},{4,11,732},{9,10,310},{137,10,682
+},{142,10,296},{134,0,939},{136,11,733},{135,11,1435},{7,10,1401},{135,10,1476},
+{6,0,352},{4,10,296},{7,10,401},{7,10,1410},{7,10,1594},{7,10,1674},{8,10,63},{8
+,10,660},{137,10,74},{4,11,428},{133,11,668},{4,10,139},{4,10,388},{140,10,188},
+{7,11,2015},{140,11,665},{132,0,647},{146,0,10},{138,0,220},{142,0,464},{132,0,
+109},{134,0,1746},{6,0,515},{4,10,747},{6,11,1623},{6,11,1681},{7,10,649},{7,10,
+1479},{135,10,1583},{133,10,232},{135,0,566},{137,10,887},{4,0,40},{10,0,67},{11
+,0,117},{11,0,768},{139,0,935},{132,0,801},{7,0,992},{8,0,301},{9,0,722},{12,0,
+63},{13,0,29},{14,0,161},{143,0,18},{139,0,923},{6,11,1748},{8,11,715},{9,11,802
+},{10,11,46},{10,11,819},{13,11,308},{14,11,351},{14,11,363},{146,11,67},{137,11
+,745},{7,0,1145},{4,10,14},{7,10,1801},{10,10,748},{141,10,458},{4,11,63},{5,11,
+347},{134,11,474},{135,0,568},{4,10,425},{7,11,577},{7,11,1432},{9,11,475},{9,11
+,505},{9,11,526},{9,11,609},{9,11,689},{9,11,726},{9,11,735},{9,11,738},{10,11,
+556},{10,11,674},{10,11,684},{11,11,89},{11,11,202},{11,11,272},{11,11,380},{11,
+11,415},{11,11,505},{11,11,537},{11,11,550},{11,11,562},{11,11,640},{11,11,667},
+{11,11,688},{11,11,847},{11,11,927},{11,11,930},{11,11,940},{12,11,144},{12,11,
+325},{12,11,329},{12,11,389},{12,11,403},{12,11,451},{12,11,515},{12,11,604},{12
+,11,616},{12,11,626},{13,11,66},{13,11,131},{13,11,167},{13,11,236},{13,11,368},
+{13,11,411},{13,11,434},{13,11,453},{13,11,461},{13,11,474},{14,11,59},{14,11,60
+},{14,11,139},{14,11,152},{14,11,276},{14,11,353},{14,11,402},{15,11,28},{15,11,
+81},{15,11,123},{15,11,152},{18,11,136},{148,11,88},{137,0,247},{135,11,1622},{9
+,11,544},{11,11,413},{144,11,25},{4,0,645},{7,0,825},{6,10,1768},{135,11,89},{
+140,0,328},{5,10,943},{134,10,1779},{134,0,1363},{5,10,245},{6,10,576},{7,10,582
+},{136,10,225},{134,0,1280},{5,11,824},{133,11,941},{7,11,440},{8,11,230},{139,
+11,106},{5,0,28},{6,0,204},{10,0,320},{10,0,583},{13,0,502},{14,0,72},{14,0,274}
+,{14,0,312},{14,0,344},{15,0,159},{16,0,62},{16,0,69},{17,0,30},{18,0,42},{18,0,
+53},{18,0,84},{18,0,140},{19,0,68},{19,0,85},{20,0,5},{20,0,45},{20,0,101},{22,0
+,7},{150,0,20},{4,0,558},{6,0,390},{7,0,162},{7,0,689},{9,0,360},{138,0,653},{
+134,0,764},{6,0,862},{137,0,833},{5,0,856},{6,0,1672},{6,0,1757},{134,0,1781},{5
+,0,92},{10,0,736},{140,0,102},{6,0,1927},{6,0,1944},{8,0,924},{8,0,948},{10,0,
+967},{138,0,978},{134,0,1479},{5,0,590},{8,0,360},{9,0,213},{138,0,63},{134,0,
+1521},{6,0,709},{134,0,891},{132,10,443},{13,0,477},{14,0,120},{148,0,61},{4,11,
+914},{5,11,800},{133,11,852},{10,11,54},{141,11,115},{4,11,918},{133,11,876},{
+139,11,152},{4,11,92},{133,11,274},{135,11,1901},{9,11,800},{10,11,693},{11,11,
+482},{11,11,734},{139,11,789},{9,0,483},{132,10,298},{6,0,1213},{141,11,498},{
+135,11,1451},{133,11,743},{4,0,1022},{10,0,1000},{12,0,957},{12,0,980},{12,0,
+1013},{14,0,481},{144,0,116},{8,0,503},{17,0,29},{4,11,49},{7,11,280},{135,11,
+1633},{135,0,1712},{134,0,466},{136,11,47},{5,10,164},{7,10,121},{142,10,189},{7
+,10,812},{7,10,1261},{7,10,1360},{9,10,632},{140,10,352},{139,10,556},{132,0,731
+},{5,11,272},{5,11,908},{5,11,942},{7,11,1008},{7,11,1560},{8,11,197},{9,11,47},
+{11,11,538},{139,11,742},{4,10,172},{9,10,611},{10,10,436},{12,10,673},{141,10,
+255},{133,10,844},{10,0,484},{11,0,754},{12,0,457},{14,0,171},{14,0,389},{146,0,
+153},{9,10,263},{10,10,147},{138,10,492},{137,11,891},{138,0,241},{133,10,537},{
+6,0,2005},{136,0,964},{137,10,842},{151,11,8},{4,11,407},{132,11,560},{135,11,
+1884},{6,0,1100},{134,0,1242},{135,0,954},{5,10,230},{5,10,392},{6,10,420},{9,10
+,568},{140,10,612},{4,11,475},{11,11,35},{11,11,90},{13,11,7},{13,11,71},{13,11,
+177},{142,11,422},{136,11,332},{135,0,1958},{6,0,549},{8,0,34},{8,0,283},{9,0,
+165},{138,0,475},{10,0,952},{12,0,966},{140,0,994},{5,0,652},{5,0,701},{135,0,
+449},{4,0,655},{7,0,850},{17,0,75},{146,0,137},{4,0,146},{7,0,1618},{8,0,670},{5
+,10,41},{7,10,1459},{7,10,1469},{7,10,1859},{9,10,549},{139,10,905},{133,10,696}
+,{6,0,159},{6,0,364},{7,0,516},{137,0,518},{135,0,1439},{6,11,222},{7,11,636},{7
+,11,1620},{8,11,409},{9,11,693},{139,11,77},{13,0,151},{141,11,45},{6,0,1027},{4
+,11,336},{132,10,771},{139,11,392},{10,11,121},{11,11,175},{149,11,16},{8,0,950}
+,{138,0,983},{133,10,921},{135,0,993},{6,10,180},{7,10,1137},{8,10,751},{139,10,
+805},{7,0,501},{9,0,111},{10,0,141},{11,0,332},{13,0,43},{13,0,429},{14,0,130},{
+14,0,415},{145,0,102},{4,10,183},{5,11,882},{7,10,271},{11,10,824},{11,10,952},{
+13,10,278},{13,10,339},{13,10,482},{14,10,424},{148,10,99},{4,10,19},{5,10,477},
+{5,10,596},{6,10,505},{7,10,1221},{11,10,907},{12,10,209},{141,10,214},{135,10,
+1215},{133,0,452},{132,11,426},{5,0,149},{136,0,233},{133,0,935},{6,11,58},{7,11
+,654},{7,11,745},{7,11,1969},{8,11,240},{8,11,675},{9,11,479},{9,11,731},{10,11,
+330},{10,11,593},{10,11,817},{11,11,32},{11,11,133},{11,11,221},{145,11,68},{12,
+0,582},{18,0,131},{7,11,102},{137,11,538},{136,0,801},{134,10,1645},{132,0,70},{
+6,10,92},{6,10,188},{7,10,1269},{7,10,1524},{7,10,1876},{10,10,228},{139,10,1020
+},{4,10,459},{133,10,966},{138,0,369},{16,0,36},{140,10,330},{141,11,366},{7,0,
+721},{10,0,236},{12,0,204},{6,10,18},{7,10,932},{8,10,757},{9,10,54},{9,10,65},{
+9,10,844},{10,10,113},{10,10,315},{10,10,798},{11,10,153},{12,10,151},{12,10,392
+},{12,10,666},{142,10,248},{7,0,241},{10,0,430},{8,10,548},{9,10,532},{10,10,117
+},{11,10,351},{11,10,375},{143,10,23},{134,10,1742},{133,10,965},{133,11,566},{6
+,11,48},{135,11,63},{134,10,182},{10,10,65},{10,10,488},{138,10,497},{6,11,114},
+{7,11,1224},{7,11,1556},{136,11,3},{134,0,1817},{8,11,576},{137,11,267},{6,0,
+1078},{144,0,16},{9,10,588},{138,10,260},{138,0,1021},{5,0,406},{134,0,2022},{
+133,11,933},{6,0,69},{135,0,117},{7,0,1830},{136,11,427},{4,0,432},{135,0,824},{
+134,10,1786},{133,0,826},{139,11,67},{133,11,759},{135,10,308},{137,0,816},{133,
+0,1000},{4,0,297},{6,0,529},{7,0,152},{7,0,713},{7,0,1845},{8,0,710},{8,0,717},{
+12,0,639},{140,0,685},{7,0,423},{136,10,588},{136,10,287},{136,0,510},{134,0,
+1048},{6,0,618},{7,11,56},{7,11,1989},{8,11,337},{8,11,738},{9,11,600},{10,11,
+483},{12,11,37},{13,11,447},{142,11,92},{4,0,520},{135,0,575},{8,0,990},{138,0,
+977},{135,11,774},{9,11,347},{11,11,24},{140,11,170},{136,11,379},{140,10,290},{
+132,11,328},{4,0,321},{134,0,569},{4,11,101},{135,11,1171},{7,0,723},{7,0,1135},
+{5,11,833},{136,11,744},{7,10,719},{8,10,809},{136,10,834},{8,0,921},{136,10,796
+},{5,10,210},{6,10,213},{7,10,60},{10,10,364},{139,10,135},{5,0,397},{6,0,154},{
+7,0,676},{8,0,443},{8,0,609},{9,0,24},{9,0,325},{10,0,35},{11,0,535},{11,0,672},
+{11,0,1018},{12,0,637},{16,0,30},{5,10,607},{8,10,326},{136,10,490},{4,10,701},{
+5,10,472},{6,11,9},{6,11,397},{7,11,53},{7,11,1742},{9,10,758},{10,11,632},{11,
+11,828},{140,11,146},{135,10,380},{135,10,1947},{148,11,109},{10,10,278},{138,11
+,278},{134,0,856},{7,0,139},{4,10,386},{8,10,405},{8,10,728},{9,10,497},{11,10,
+110},{11,10,360},{15,10,37},{144,10,84},{141,0,282},{133,0,981},{5,0,288},{7,10,
+1452},{7,10,1480},{8,10,634},{140,10,472},{7,0,1890},{8,11,367},{10,11,760},{14,
+11,79},{20,11,17},{152,11,0},{4,10,524},{136,10,810},{4,0,56},{7,0,1791},{8,0,
+607},{8,0,651},{11,0,465},{11,0,835},{12,0,337},{141,0,480},{10,10,238},{141,10,
+33},{11,11,417},{12,11,223},{140,11,265},{9,0,158},{10,0,411},{140,0,261},{133,
+10,532},{133,10,997},{12,11,186},{12,11,292},{14,11,100},{146,11,70},{6,0,1403},
+{136,0,617},{134,0,1205},{139,0,563},{4,0,242},{134,0,333},{4,11,186},{5,11,157}
+,{8,11,168},{138,11,6},{132,0,369},{133,11,875},{5,10,782},{5,10,829},{134,10,
+1738},{134,0,622},{135,11,1272},{6,0,1407},{7,11,111},{136,11,581},{7,10,1823},{
+139,10,693},{7,0,160},{10,0,624},{142,0,279},{132,0,363},{10,11,589},{12,11,111}
+,{13,11,260},{14,11,82},{18,11,63},{147,11,45},{7,11,1364},{7,11,1907},{141,11,
+158},{4,11,404},{4,11,659},{135,11,675},{13,11,211},{14,11,133},{14,11,204},{15,
+11,64},{15,11,69},{15,11,114},{16,11,10},{19,11,23},{19,11,35},{19,11,39},{19,11
+,51},{19,11,71},{19,11,75},{152,11,15},{4,10,78},{5,10,96},{5,10,182},{7,10,1724
+},{7,10,1825},{10,10,394},{10,10,471},{11,10,532},{14,10,340},{145,10,88},{135,
+10,1964},{133,11,391},{11,11,887},{14,11,365},{142,11,375},{5,11,540},{6,11,1697
+},{7,11,222},{136,11,341},{134,11,78},{9,0,601},{9,0,619},{10,0,505},{10,0,732},
+{11,0,355},{140,0,139},{134,0,292},{139,0,174},{5,0,177},{6,0,616},{7,0,827},{9,
+0,525},{138,0,656},{10,0,31},{6,10,215},{7,10,1028},{7,10,1473},{7,10,1721},{9,
+10,424},{138,10,779},{135,10,584},{136,11,293},{134,0,685},{135,11,1868},{133,11
+,460},{7,0,647},{6,10,67},{7,10,1630},{9,10,354},{9,10,675},{10,10,830},{14,10,
+80},{145,10,80},{4,0,161},{133,0,631},{6,10,141},{7,10,225},{9,10,59},{9,10,607}
+,{10,10,312},{11,10,687},{12,10,555},{13,10,373},{13,10,494},{148,10,58},{7,11,
+965},{7,11,1460},{135,11,1604},{136,10,783},{134,11,388},{6,0,722},{6,0,1267},{4
+,11,511},{9,11,333},{9,11,379},{10,11,602},{11,11,441},{11,11,723},{11,11,976},{
+140,11,357},{134,0,1797},{135,0,1684},{9,0,469},{9,0,709},{12,0,512},{14,0,65},{
+17,0,12},{5,11,938},{136,11,707},{7,0,1230},{136,0,531},{10,0,229},{11,0,73},{11
+,0,376},{139,0,433},{12,0,268},{12,0,640},{142,0,119},{7,10,430},{139,10,46},{6,
+0,558},{7,0,651},{8,0,421},{9,0,0},{10,0,34},{139,0,1008},{6,0,106},{7,0,1786},{
+7,0,1821},{9,0,102},{9,0,763},{5,10,602},{7,10,2018},{137,10,418},{5,0,65},{6,0,
+416},{7,0,1720},{7,0,1924},{10,0,109},{11,0,14},{11,0,70},{11,0,569},{11,0,735},
+{15,0,153},{20,0,80},{136,10,677},{135,11,1625},{137,11,772},{136,0,595},{6,11,
+469},{7,11,1709},{138,11,515},{7,0,1832},{138,0,374},{9,0,106},{9,0,163},{9,0,
+296},{10,0,167},{10,0,172},{10,0,777},{139,0,16},{6,0,6},{7,0,81},{7,0,771},{7,0
+,1731},{9,0,405},{138,0,421},{4,11,500},{135,11,938},{5,11,68},{134,11,383},{5,0
+,881},{133,0,885},{6,0,854},{6,0,1132},{6,0,1495},{6,0,1526},{6,0,1533},{134,0,
+1577},{4,11,337},{6,11,353},{7,11,1934},{8,11,488},{137,11,429},{7,11,236},{7,11
+,1795},{8,11,259},{9,11,135},{9,11,177},{10,11,825},{11,11,115},{11,11,370},{11,
+11,405},{11,11,604},{12,11,10},{12,11,667},{12,11,669},{13,11,76},{14,11,310},{
+15,11,76},{15,11,147},{148,11,23},{5,0,142},{134,0,546},{4,11,15},{5,11,22},{6,
+11,244},{7,11,40},{7,11,200},{7,11,906},{7,11,1199},{9,11,616},{10,11,716},{11,
+11,635},{11,11,801},{140,11,458},{5,0,466},{11,0,571},{12,0,198},{13,0,283},{14,
+0,186},{15,0,21},{15,0,103},{135,10,329},{4,0,185},{5,0,257},{5,0,839},{5,0,936}
+,{9,0,399},{10,0,258},{10,0,395},{10,0,734},{11,0,1014},{12,0,23},{13,0,350},{14
+,0,150},{19,0,6},{135,11,1735},{12,11,36},{141,11,337},{5,11,598},{7,11,791},{8,
+11,108},{137,11,123},{132,10,469},{7,0,404},{7,0,1377},{7,0,1430},{7,0,2017},{8,
+0,149},{8,0,239},{8,0,512},{8,0,793},{8,0,818},{9,0,474},{9,0,595},{10,0,122},{
+10,0,565},{10,0,649},{10,0,783},{11,0,239},{11,0,295},{11,0,447},{11,0,528},{11,
+0,639},{11,0,800},{12,0,25},{12,0,77},{12,0,157},{12,0,256},{12,0,316},{12,0,390
+},{12,0,391},{12,0,395},{12,0,478},{12,0,503},{12,0,592},{12,0,680},{13,0,50},{
+13,0,53},{13,0,132},{13,0,198},{13,0,322},{13,0,415},{13,0,511},{14,0,71},{14,0,
+395},{15,0,71},{15,0,136},{17,0,123},{18,0,93},{147,0,58},{136,0,712},{134,10,
+1743},{5,10,929},{6,10,340},{8,10,376},{136,10,807},{6,0,1848},{8,0,860},{10,0,
+856},{10,0,859},{10,0,925},{10,0,941},{140,0,762},{6,0,629},{6,0,906},{9,0,810},
+{140,0,652},{5,10,218},{7,10,1610},{138,10,83},{7,10,1512},{135,10,1794},{4,0,
+377},{24,0,13},{4,11,155},{7,11,1689},{11,10,0},{144,10,78},{4,11,164},{5,11,151
+},{5,11,730},{5,11,741},{7,11,498},{7,11,870},{7,11,1542},{12,11,213},{14,11,36}
+,{14,11,391},{17,11,111},{18,11,6},{18,11,46},{18,11,151},{19,11,36},{20,11,32},
+{20,11,56},{20,11,69},{20,11,102},{21,11,4},{22,11,8},{22,11,10},{22,11,14},{150
+,11,31},{7,0,1842},{133,10,571},{4,10,455},{4,11,624},{135,11,1752},{134,0,1501}
+,{4,11,492},{5,11,451},{6,10,161},{7,10,372},{137,10,597},{132,10,349},{4,0,180}
+,{135,0,1906},{135,11,835},{141,11,70},{132,0,491},{137,10,751},{6,10,432},{139,
+10,322},{4,0,171},{138,0,234},{6,11,113},{135,11,436},{4,0,586},{7,0,1186},{138,
+0,631},{5,10,468},{10,10,325},{11,10,856},{12,10,345},{143,10,104},{5,10,223},{
+10,11,592},{10,11,753},{12,11,317},{12,11,355},{12,11,465},{12,11,469},{12,11,
+560},{12,11,578},{141,11,243},{132,10,566},{135,11,520},{4,10,59},{135,10,1394},
+{6,10,436},{139,10,481},{9,0,931},{10,0,334},{20,0,71},{4,10,48},{5,10,271},{7,
+10,953},{135,11,1878},{11,0,170},{5,10,610},{136,10,457},{133,10,755},{6,0,1587}
+,{135,10,1217},{4,10,197},{149,11,26},{133,11,585},{137,11,521},{133,0,765},{133
+,10,217},{139,11,586},{133,0,424},{9,11,752},{12,11,610},{13,11,431},{16,11,59},
+{146,11,109},{136,0,714},{7,0,685},{132,11,307},{9,0,420},{10,0,269},{10,0,285},
+{10,0,576},{11,0,397},{13,0,175},{145,0,90},{132,0,429},{133,11,964},{9,11,463},
+{138,11,595},{7,0,18},{7,0,699},{7,0,1966},{8,0,752},{9,0,273},{9,0,412},{9,0,
+703},{10,0,71},{10,0,427},{138,0,508},{4,10,165},{7,10,1398},{135,10,1829},{4,0,
+53},{5,0,186},{7,0,752},{7,0,828},{142,0,116},{8,0,575},{10,0,289},{139,0,319},{
+132,0,675},{134,0,1424},{4,11,75},{5,11,180},{6,11,500},{7,11,58},{7,11,710},{
+138,11,645},{133,11,649},{6,11,276},{7,11,282},{7,11,879},{7,11,924},{8,11,459},
+{9,11,599},{9,11,754},{11,11,574},{12,11,128},{12,11,494},{13,11,52},{13,11,301}
+,{15,11,30},{143,11,132},{6,0,647},{134,0,1095},{5,10,9},{7,10,297},{7,10,966},{
+140,10,306},{132,11,200},{134,0,1334},{5,10,146},{6,10,411},{138,10,721},{6,0,
+209},{6,0,1141},{6,0,1288},{8,0,468},{9,0,210},{11,0,36},{12,0,28},{12,0,630},{
+13,0,21},{13,0,349},{14,0,7},{145,0,13},{6,10,177},{135,10,467},{4,0,342},{135,0
+,1179},{10,11,454},{140,11,324},{4,0,928},{133,0,910},{7,0,1838},{6,11,225},{137
+,11,211},{16,0,101},{20,0,115},{20,0,118},{148,0,122},{4,0,496},{135,0,856},{4,0
+,318},{11,0,654},{7,11,718},{139,11,102},{8,11,58},{9,11,724},{11,11,809},{13,11
+,113},{145,11,72},{5,10,200},{6,11,345},{135,11,1247},{8,11,767},{8,11,803},{9,
+11,301},{137,11,903},{7,0,915},{8,0,247},{19,0,0},{7,11,1949},{136,11,674},{4,0,
+202},{5,0,382},{6,0,454},{7,0,936},{7,0,1803},{8,0,758},{9,0,375},{9,0,895},{10,
+0,743},{10,0,792},{11,0,978},{11,0,1012},{142,0,109},{7,0,1150},{7,0,1425},{7,0,
+1453},{140,0,513},{134,11,259},{138,0,791},{11,0,821},{12,0,110},{12,0,153},{18,
+0,41},{150,0,19},{134,10,481},{132,0,796},{6,0,445},{9,0,909},{136,11,254},{10,0
+,776},{13,0,345},{142,0,425},{4,10,84},{7,10,1482},{10,10,76},{138,10,142},{135,
+11,742},{6,0,578},{133,10,1015},{6,0,1387},{4,10,315},{5,10,507},{135,10,1370},{
+4,0,438},{133,0,555},{136,0,766},{133,11,248},{134,10,1722},{4,11,116},{5,11,95}
+,{5,11,445},{7,11,1688},{8,11,29},{9,11,272},{11,11,509},{139,11,915},{135,0,541
+},{133,11,543},{8,10,222},{8,10,476},{9,10,238},{11,10,516},{11,10,575},{15,10,
+109},{146,10,100},{6,0,880},{134,0,1191},{5,11,181},{136,11,41},{134,0,1506},{
+132,11,681},{7,11,25},{8,11,202},{138,11,536},{139,0,983},{137,0,768},{132,0,584
+},{9,11,423},{140,11,89},{8,11,113},{9,11,877},{10,11,554},{11,11,83},{12,11,136
+},{147,11,109},{7,10,706},{7,10,1058},{138,10,538},{133,11,976},{4,11,206},{135,
+11,746},{136,11,526},{140,0,737},{11,10,92},{11,10,196},{11,10,409},{11,10,450},
+{11,10,666},{11,10,777},{12,10,262},{13,10,385},{13,10,393},{15,10,115},{16,10,
+45},{145,10,82},{4,0,226},{4,0,326},{7,0,1770},{4,11,319},{5,11,699},{138,11,673
+},{6,10,40},{135,10,1781},{5,0,426},{8,0,30},{9,0,2},{11,0,549},{147,0,122},{6,0
+,1161},{134,0,1329},{138,10,97},{6,10,423},{7,10,665},{135,10,1210},{7,11,13},{8
+,11,226},{10,11,537},{11,11,570},{11,11,605},{11,11,799},{11,11,804},{12,11,85},
+{12,11,516},{12,11,623},{13,11,112},{13,11,361},{14,11,77},{14,11,78},{17,11,28}
+,{147,11,110},{132,11,769},{132,11,551},{132,11,728},{147,0,117},{9,11,57},{9,11
+,459},{10,11,425},{11,11,119},{12,11,184},{12,11,371},{13,11,358},{145,11,51},{5
+,11,188},{5,11,814},{8,11,10},{9,11,421},{9,11,729},{10,11,609},{139,11,689},{
+134,11,624},{135,11,298},{135,0,462},{4,0,345},{139,10,624},{136,10,574},{4,0,
+385},{7,0,265},{135,0,587},{6,0,808},{132,11,528},{133,0,398},{132,10,354},{4,0,
+347},{5,0,423},{5,0,996},{135,0,1329},{135,10,1558},{7,0,1259},{9,0,125},{139,0,
+65},{5,0,136},{6,0,136},{136,0,644},{5,11,104},{6,11,173},{135,11,1631},{135,0,
+469},{133,10,830},{4,0,278},{5,0,465},{135,0,1367},{7,11,810},{8,11,138},{8,11,
+342},{9,11,84},{10,11,193},{11,11,883},{140,11,359},{5,10,496},{135,10,203},{4,0
+,433},{133,0,719},{6,11,95},{134,10,547},{5,10,88},{137,10,239},{6,11,406},{10,
+11,409},{10,11,447},{11,11,44},{140,11,100},{134,0,1423},{7,10,650},{135,10,1310
+},{134,0,749},{135,11,1243},{135,0,1363},{6,0,381},{7,0,645},{7,0,694},{8,0,546}
+,{7,10,1076},{9,10,80},{11,10,78},{11,10,421},{11,10,534},{140,10,545},{134,11,
+1636},{135,11,1344},{12,0,277},{7,10,274},{11,10,479},{139,10,507},{6,0,705},{6,
+0,783},{6,0,1275},{6,0,1481},{4,11,282},{7,11,1034},{11,11,398},{11,11,634},{12,
+11,1},{12,11,79},{12,11,544},{14,11,237},{17,11,10},{146,11,20},{134,0,453},{4,0
+,555},{8,0,536},{10,0,288},{11,0,1005},{4,10,497},{135,10,1584},{5,11,118},{5,11
+,499},{6,11,476},{7,11,600},{7,11,888},{135,11,1096},{138,0,987},{7,0,1107},{7,
+10,261},{7,10,1115},{7,10,1354},{7,10,1588},{7,10,1705},{7,10,1902},{9,10,465},{
+10,10,248},{10,10,349},{10,10,647},{11,10,527},{11,10,660},{11,10,669},{12,10,
+529},{141,10,305},{7,11,296},{7,11,596},{8,11,560},{8,11,586},{9,11,612},{11,11,
+100},{11,11,304},{12,11,46},{13,11,89},{14,11,112},{145,11,122},{9,0,370},{138,0
+,90},{136,10,13},{132,0,860},{7,10,642},{8,10,250},{11,10,123},{11,10,137},{13,
+10,48},{142,10,95},{135,10,1429},{137,11,321},{132,0,257},{135,0,2031},{7,0,1768
+},{7,11,1599},{7,11,1723},{8,11,79},{8,11,106},{8,11,190},{8,11,302},{8,11,383},
+{9,11,119},{9,11,233},{9,11,298},{9,11,419},{9,11,471},{10,11,181},{10,11,406},{
+11,11,57},{11,11,85},{11,11,120},{11,11,177},{11,11,296},{11,11,382},{11,11,454}
+,{11,11,758},{11,11,999},{12,11,27},{12,11,98},{12,11,131},{12,11,245},{12,11,
+312},{12,11,446},{12,11,454},{13,11,25},{13,11,98},{13,11,426},{13,11,508},{14,
+11,6},{14,11,163},{14,11,272},{14,11,277},{14,11,370},{15,11,95},{15,11,138},{15
+,11,167},{17,11,18},{17,11,38},{20,11,96},{149,11,32},{5,11,722},{134,11,1759},{
+145,11,16},{6,0,1071},{134,0,1561},{10,10,545},{140,10,301},{6,0,83},{6,0,1733},
+{135,0,1389},{4,0,835},{135,0,1818},{133,11,258},{4,10,904},{133,10,794},{134,0,
+2006},{5,11,30},{7,11,495},{8,11,134},{9,11,788},{140,11,438},{135,11,2004},{137
+,0,696},{5,11,50},{6,11,439},{7,11,780},{135,11,1040},{7,11,772},{7,11,1104},{7,
+11,1647},{11,11,269},{11,11,539},{11,11,607},{11,11,627},{11,11,706},{11,11,975}
+,{12,11,248},{12,11,311},{12,11,434},{12,11,600},{12,11,622},{13,11,297},{13,11,
+367},{13,11,485},{14,11,69},{14,11,409},{143,11,108},{5,11,1},{6,11,81},{138,11,
+520},{7,0,1718},{9,0,95},{9,0,274},{10,0,279},{10,0,317},{10,0,420},{11,0,303},{
+11,0,808},{12,0,134},{12,0,367},{13,0,149},{13,0,347},{14,0,349},{14,0,406},{18,
+0,22},{18,0,89},{18,0,122},{147,0,47},{5,11,482},{8,11,98},{9,11,172},{10,11,222
+},{10,11,700},{10,11,822},{11,11,302},{11,11,778},{12,11,50},{12,11,127},{12,11,
+396},{13,11,62},{13,11,328},{14,11,122},{147,11,72},{7,10,386},{138,10,713},{6,
+10,7},{6,10,35},{7,10,147},{7,10,1069},{7,10,1568},{7,10,1575},{7,10,1917},{8,10
+,43},{8,10,208},{9,10,128},{9,10,866},{10,10,20},{11,10,981},{147,10,33},{133,0,
+26},{132,0,550},{5,11,2},{7,11,1494},{136,11,589},{6,11,512},{7,11,797},{8,11,
+253},{9,11,77},{10,11,1},{10,11,129},{10,11,225},{11,11,118},{11,11,226},{11,11,
+251},{11,11,430},{11,11,701},{11,11,974},{11,11,982},{12,11,64},{12,11,260},{12,
+11,488},{140,11,690},{7,10,893},{141,10,424},{134,0,901},{136,0,822},{4,0,902},{
+5,0,809},{134,0,122},{6,0,807},{134,0,1366},{7,0,262},{5,11,748},{134,11,553},{
+133,0,620},{4,0,34},{5,0,574},{7,0,279},{7,0,1624},{136,0,601},{9,0,170},{6,10,
+322},{9,10,552},{11,10,274},{13,10,209},{13,10,499},{14,10,85},{15,10,126},{145,
+10,70},{132,0,537},{4,11,12},{7,11,420},{7,11,522},{7,11,809},{8,11,797},{141,11
+,88},{133,0,332},{8,10,83},{8,10,742},{8,10,817},{9,10,28},{9,10,29},{9,10,885},
+{10,10,387},{11,10,633},{11,10,740},{13,10,235},{13,10,254},{15,10,143},{143,10,
+146},{6,0,1909},{9,0,964},{12,0,822},{12,0,854},{12,0,865},{12,0,910},{12,0,938}
+,{15,0,169},{15,0,208},{15,0,211},{18,0,205},{18,0,206},{18,0,220},{18,0,223},{
+152,0,24},{140,10,49},{5,11,528},{135,11,1580},{6,0,261},{8,0,182},{139,0,943},{
+134,0,1721},{4,0,933},{133,0,880},{136,11,321},{5,11,266},{9,11,290},{9,11,364},
+{10,11,293},{11,11,606},{142,11,45},{6,0,1609},{4,11,50},{6,11,510},{6,11,594},{
+9,11,121},{10,11,49},{10,11,412},{139,11,834},{7,0,895},{136,11,748},{132,11,466
+},{4,10,110},{10,10,415},{10,10,597},{142,10,206},{133,0,812},{135,11,281},{6,0,
+1890},{6,0,1902},{6,0,1916},{9,0,929},{9,0,942},{9,0,975},{9,0,984},{9,0,986},{9
+,0,1011},{9,0,1019},{12,0,804},{12,0,851},{12,0,867},{12,0,916},{12,0,923},{15,0
+,194},{15,0,204},{15,0,210},{15,0,222},{15,0,223},{15,0,229},{15,0,250},{18,0,
+179},{18,0,186},{18,0,192},{7,10,205},{135,10,2000},{132,11,667},{135,0,778},{4,
+0,137},{7,0,1178},{135,0,1520},{134,0,1314},{4,11,242},{134,11,333},{6,0,1661},{
+7,0,1975},{7,0,2009},{135,0,2011},{134,0,1591},{4,10,283},{135,10,1194},{11,0,
+820},{150,0,51},{4,11,39},{5,11,36},{7,11,1843},{8,11,407},{11,11,144},{140,11,
+523},{134,10,1720},{4,11,510},{7,11,29},{7,11,66},{7,11,1980},{10,11,487},{10,11
+,809},{146,11,9},{5,0,89},{7,0,1915},{9,0,185},{9,0,235},{10,0,64},{10,0,270},{
+10,0,403},{10,0,469},{10,0,529},{10,0,590},{11,0,140},{11,0,860},{13,0,1},{13,0,
+422},{14,0,341},{14,0,364},{17,0,93},{18,0,113},{19,0,97},{147,0,113},{133,0,695
+},{6,0,987},{134,0,1160},{5,0,6},{6,0,183},{7,0,680},{7,0,978},{7,0,1013},{7,0,
+1055},{12,0,230},{13,0,172},{146,0,29},{134,11,570},{132,11,787},{134,11,518},{6
+,0,29},{139,0,63},{132,11,516},{136,11,821},{132,0,311},{134,0,1740},{7,0,170},{
+8,0,90},{8,0,177},{8,0,415},{11,0,714},{14,0,281},{136,10,735},{134,0,1961},{135
+,11,1405},{4,11,10},{7,11,917},{139,11,786},{5,10,132},{9,10,486},{9,10,715},{10
+,10,458},{11,10,373},{11,10,668},{11,10,795},{11,10,897},{12,10,272},{12,10,424}
+,{12,10,539},{12,10,558},{14,10,245},{14,10,263},{14,10,264},{14,10,393},{142,10
+,403},{11,0,91},{13,0,129},{15,0,101},{145,0,125},{135,0,1132},{4,0,494},{6,0,74
+},{7,0,44},{7,0,407},{12,0,17},{15,0,5},{148,0,11},{133,10,379},{5,0,270},{5,11,
+684},{6,10,89},{6,10,400},{7,10,1569},{7,10,1623},{7,10,1850},{8,10,218},{8,10,
+422},{9,10,570},{138,10,626},{4,0,276},{133,0,296},{6,0,1523},{134,11,27},{6,10,
+387},{7,10,882},{141,10,111},{6,10,224},{7,10,877},{137,10,647},{135,10,790},{4,
+0,7},{5,0,90},{5,0,158},{6,0,542},{7,0,221},{7,0,1574},{9,0,490},{10,0,540},{11,
+0,443},{139,0,757},{7,0,588},{9,0,175},{138,0,530},{135,10,394},{142,11,23},{134
+,0,786},{135,0,580},{7,0,88},{136,0,627},{5,0,872},{6,0,57},{7,0,471},{9,0,447},
+{137,0,454},{6,11,342},{6,11,496},{8,11,275},{137,11,206},{4,11,909},{133,11,940
+},{6,0,735},{132,11,891},{8,0,845},{8,0,916},{135,10,1409},{5,0,31},{134,0,614},
+{11,0,458},{12,0,15},{140,0,432},{8,0,330},{140,0,477},{4,0,530},{5,0,521},{7,0,
+1200},{10,0,460},{132,11,687},{6,0,424},{135,0,1866},{9,0,569},{12,0,12},{12,0,
+81},{12,0,319},{13,0,69},{14,0,259},{16,0,87},{17,0,1},{17,0,21},{17,0,24},{18,0
+,15},{18,0,56},{18,0,59},{18,0,127},{18,0,154},{19,0,19},{148,0,31},{7,0,1302},{
+136,10,38},{134,11,253},{5,10,261},{7,10,78},{7,10,199},{8,10,815},{9,10,126},{
+138,10,342},{5,0,595},{135,0,1863},{6,11,41},{141,11,160},{5,0,13},{134,0,142},{
+6,0,97},{7,0,116},{8,0,322},{8,0,755},{9,0,548},{10,0,714},{11,0,884},{13,0,324}
+,{7,11,1304},{138,11,477},{132,10,628},{134,11,1718},{7,10,266},{136,10,804},{
+135,10,208},{7,0,1021},{6,10,79},{135,10,1519},{7,0,1472},{135,0,1554},{6,11,362
+},{146,11,51},{7,0,1071},{7,0,1541},{7,0,1767},{7,0,1806},{11,0,162},{11,0,242},
+{11,0,452},{12,0,605},{15,0,26},{144,0,44},{136,10,741},{133,11,115},{145,0,115}
+,{134,10,376},{6,0,1406},{134,0,1543},{5,11,193},{12,11,178},{13,11,130},{145,11
+,84},{135,0,1111},{8,0,1},{9,0,650},{10,0,326},{5,11,705},{137,11,606},{5,0,488}
+,{6,0,527},{7,0,489},{7,0,1636},{8,0,121},{8,0,144},{8,0,359},{9,0,193},{9,0,241
+},{9,0,336},{9,0,882},{11,0,266},{11,0,372},{11,0,944},{12,0,401},{140,0,641},{
+135,11,174},{6,0,267},{7,10,244},{7,10,632},{7,10,1609},{8,10,178},{8,10,638},{
+141,10,58},{134,0,1983},{134,0,1155},{134,0,1575},{134,0,1438},{9,0,31},{10,0,
+244},{10,0,699},{12,0,149},{141,0,497},{133,0,377},{4,11,122},{5,11,796},{5,11,
+952},{6,11,1660},{6,11,1671},{8,11,567},{9,11,687},{9,11,742},{10,11,686},{11,11
+,356},{11,11,682},{140,11,281},{145,0,101},{11,11,0},{144,11,78},{5,11,179},{5,
+10,791},{7,11,1095},{135,11,1213},{8,11,372},{9,11,122},{138,11,175},{7,10,686},
+{8,10,33},{8,10,238},{10,10,616},{11,10,467},{11,10,881},{13,10,217},{13,10,253}
+,{142,10,268},{9,0,476},{4,11,66},{7,11,722},{135,11,904},{7,11,352},{137,11,684
+},{135,0,2023},{135,0,1836},{132,10,447},{5,0,843},{144,0,35},{137,11,779},{141,
+11,35},{4,10,128},{5,10,415},{6,10,462},{7,10,294},{7,10,578},{10,10,710},{139,
+10,86},{132,0,554},{133,0,536},{136,10,587},{5,0,207},{9,0,79},{11,0,625},{145,0
+,7},{7,0,1371},{6,10,427},{138,10,692},{4,0,424},{4,10,195},{135,10,802},{8,0,
+785},{133,11,564},{135,0,336},{4,0,896},{6,0,1777},{134,11,556},{137,11,103},{
+134,10,1683},{7,11,544},{8,11,719},{138,11,61},{138,10,472},{4,11,5},{5,11,498},
+{136,11,637},{7,0,750},{9,0,223},{11,0,27},{11,0,466},{12,0,624},{14,0,265},{146
+,0,61},{12,0,238},{18,0,155},{12,11,238},{146,11,155},{151,10,28},{133,11,927},{
+12,0,383},{5,10,3},{8,10,578},{9,10,118},{10,10,705},{141,10,279},{4,11,893},{5,
+11,780},{133,11,893},{4,0,603},{133,0,661},{4,0,11},{6,0,128},{7,0,231},{7,0,
+1533},{10,0,725},{5,10,229},{5,11,238},{135,11,1350},{8,10,102},{10,10,578},{10,
+10,672},{12,10,496},{13,10,408},{14,10,121},{145,10,106},{132,0,476},{134,0,1552
+},{134,11,1729},{8,10,115},{8,10,350},{9,10,489},{10,10,128},{11,10,306},{12,10,
+373},{14,10,30},{17,10,79},{19,10,80},{150,10,55},{135,0,1807},{4,0,680},{4,11,
+60},{7,11,760},{7,11,1800},{8,11,314},{9,11,700},{139,11,487},{4,10,230},{5,10,
+702},{148,11,94},{132,11,228},{139,0,435},{9,0,20},{10,0,324},{10,0,807},{139,0,
+488},{6,10,1728},{136,11,419},{4,10,484},{18,10,26},{19,10,42},{20,10,43},{21,10
+,0},{23,10,27},{152,10,14},{135,0,1431},{133,11,828},{5,0,112},{6,0,103},{6,0,
+150},{7,0,1303},{9,0,292},{10,0,481},{20,0,13},{7,11,176},{7,11,178},{7,11,1110}
+,{10,11,481},{148,11,13},{138,0,356},{4,11,51},{5,11,39},{6,11,4},{7,11,591},{7,
+11,849},{7,11,951},{7,11,1129},{7,11,1613},{7,11,1760},{7,11,1988},{9,11,434},{
+10,11,754},{11,11,25},{11,11,37},{139,11,414},{6,0,1963},{134,0,2000},{132,10,
+633},{6,0,1244},{133,11,902},{135,11,928},{140,0,18},{138,0,204},{135,11,1173},{
+134,0,867},{4,0,708},{8,0,15},{9,0,50},{9,0,386},{11,0,18},{11,0,529},{140,0,228
+},{134,11,270},{4,0,563},{7,0,109},{7,0,592},{7,0,637},{7,0,770},{8,0,463},{9,0,
+60},{9,0,335},{9,0,904},{10,0,73},{11,0,434},{12,0,585},{13,0,331},{18,0,110},{
+148,0,60},{132,0,502},{14,11,359},{19,11,52},{148,11,47},{6,11,377},{7,11,1025},
+{9,11,613},{145,11,104},{6,0,347},{10,0,161},{5,10,70},{5,10,622},{6,10,334},{7,
+10,1032},{9,10,171},{11,10,26},{11,10,213},{11,10,637},{11,10,707},{12,10,202},{
+12,10,380},{13,10,226},{13,10,355},{14,10,222},{145,10,42},{132,11,416},{4,0,33}
+,{5,0,102},{6,0,284},{7,0,1079},{7,0,1423},{7,0,1702},{8,0,470},{9,0,554},{9,0,
+723},{11,0,333},{142,11,372},{5,11,152},{5,11,197},{7,11,340},{7,11,867},{10,11,
+548},{10,11,581},{11,11,6},{12,11,3},{12,11,19},{14,11,110},{142,11,289},{7,0,
+246},{135,0,840},{6,0,10},{8,0,571},{9,0,739},{143,0,91},{6,0,465},{7,0,1465},{4
+,10,23},{4,10,141},{5,10,313},{5,10,1014},{6,10,50},{7,10,142},{7,10,559},{8,10,
+640},{9,10,460},{9,10,783},{11,10,741},{12,10,183},{141,10,488},{133,0,626},{136
+,0,614},{138,0,237},{7,11,34},{7,11,190},{8,11,28},{8,11,141},{8,11,444},{8,11,
+811},{9,11,468},{11,11,334},{12,11,24},{12,11,386},{140,11,576},{133,11,757},{5,
+0,18},{6,0,526},{13,0,24},{13,0,110},{19,0,5},{147,0,44},{6,0,506},{134,11,506},
+{135,11,1553},{4,0,309},{5,0,462},{7,0,970},{7,0,1097},{22,0,30},{22,0,33},{7,11
+,1385},{11,11,582},{11,11,650},{11,11,901},{11,11,949},{12,11,232},{12,11,236},{
+13,11,413},{13,11,501},{146,11,116},{9,0,140},{5,10,222},{138,10,534},{6,0,1056}
+,{137,10,906},{134,0,1704},{138,10,503},{134,0,1036},{5,10,154},{7,10,1491},{10,
+10,379},{138,10,485},{4,11,383},{133,10,716},{134,0,1315},{5,0,86},{7,0,743},{9,
+0,85},{10,0,281},{10,0,432},{11,0,825},{12,0,251},{13,0,118},{142,0,378},{8,0,
+264},{4,10,91},{5,10,388},{5,10,845},{6,10,206},{6,10,252},{6,10,365},{7,10,136}
+,{7,10,531},{136,10,621},{5,0,524},{133,0,744},{5,11,277},{141,11,247},{132,11,
+435},{10,0,107},{140,0,436},{132,0,927},{10,0,123},{12,0,670},{146,0,94},{7,0,
+1149},{9,0,156},{138,0,957},{5,11,265},{6,11,212},{135,11,28},{133,0,778},{133,0
+,502},{8,0,196},{10,0,283},{139,0,406},{135,10,576},{136,11,535},{134,0,1312},{5
+,10,771},{5,10,863},{5,10,898},{6,10,1632},{6,10,1644},{134,10,1780},{5,0,855},{
+5,10,331},{135,11,1487},{132,11,702},{5,11,808},{135,11,2045},{7,0,1400},{9,0,
+446},{138,0,45},{140,10,632},{132,0,1003},{5,11,166},{8,11,739},{140,11,511},{5,
+10,107},{7,10,201},{136,10,518},{6,10,446},{135,10,1817},{134,0,1532},{134,0,
+1097},{4,11,119},{5,11,170},{5,11,447},{7,11,1708},{7,11,1889},{9,11,357},{9,11,
+719},{12,11,486},{140,11,596},{9,10,851},{141,10,510},{7,0,612},{8,0,545},{8,0,
+568},{8,0,642},{9,0,717},{10,0,541},{10,0,763},{11,0,449},{12,0,489},{13,0,153},
+{13,0,296},{14,0,138},{14,0,392},{15,0,50},{16,0,6},{16,0,12},{20,0,9},{132,10,
+504},{4,11,450},{135,11,1158},{11,0,54},{13,0,173},{13,0,294},{5,10,883},{5,10,
+975},{8,10,392},{148,10,7},{13,0,455},{15,0,99},{15,0,129},{144,0,68},{135,0,172
+},{132,11,754},{5,10,922},{134,10,1707},{134,0,1029},{17,11,39},{148,11,36},{4,0
+,568},{5,10,993},{7,10,515},{137,10,91},{132,0,732},{10,0,617},{138,11,617},{134
+,0,974},{7,0,989},{10,0,377},{12,0,363},{13,0,68},{13,0,94},{14,0,108},{142,0,
+306},{136,0,733},{132,0,428},{7,0,1789},{135,11,1062},{7,0,2015},{140,0,665},{
+135,10,1433},{5,0,287},{7,10,921},{8,10,580},{8,10,593},{8,10,630},{138,10,28},{
+138,0,806},{4,10,911},{5,10,867},{5,10,1013},{7,10,2034},{8,10,798},{136,10,813}
+,{134,0,1539},{8,11,523},{150,11,34},{135,11,740},{7,11,238},{7,11,2033},{8,11,
+120},{8,11,188},{8,11,659},{9,11,598},{10,11,466},{12,11,342},{12,11,588},{13,11
+,503},{14,11,246},{143,11,92},{7,0,1563},{141,0,182},{5,10,135},{6,10,519},{7,10
+,1722},{10,10,271},{11,10,261},{145,10,54},{14,10,338},{148,10,81},{7,0,484},{4,
+10,300},{133,10,436},{145,11,114},{6,0,1623},{134,0,1681},{133,11,640},{4,11,201
+},{7,11,1744},{8,11,602},{11,11,247},{11,11,826},{145,11,65},{8,11,164},{146,11,
+62},{6,0,1833},{6,0,1861},{136,0,878},{134,0,1569},{8,10,357},{10,10,745},{14,10
+,426},{17,10,94},{147,10,57},{12,0,93},{12,0,501},{13,0,362},{14,0,151},{15,0,40
+},{15,0,59},{16,0,46},{17,0,25},{18,0,14},{18,0,134},{19,0,25},{19,0,69},{20,0,
+16},{20,0,19},{20,0,66},{21,0,23},{21,0,25},{150,0,42},{6,0,1748},{8,0,715},{9,0
+,802},{10,0,46},{10,0,819},{13,0,308},{14,0,351},{14,0,363},{146,0,67},{132,0,
+994},{4,0,63},{133,0,347},{132,0,591},{133,0,749},{7,11,1577},{10,11,304},{10,11
+,549},{11,11,424},{12,11,365},{13,11,220},{13,11,240},{142,11,33},{133,0,366},{7
+,0,557},{12,0,547},{14,0,86},{133,10,387},{135,0,1747},{132,11,907},{5,11,100},{
+10,11,329},{12,11,416},{149,11,29},{4,10,6},{5,10,708},{136,10,75},{7,10,1351},{
+9,10,581},{10,10,639},{11,10,453},{140,10,584},{7,0,89},{132,10,303},{138,10,772
+},{132,11,176},{5,11,636},{5,11,998},{8,11,26},{137,11,358},{7,11,9},{7,11,1508}
+,{9,11,317},{10,11,210},{10,11,292},{10,11,533},{11,11,555},{12,11,526},{12,11,
+607},{13,11,263},{13,11,459},{142,11,271},{134,0,1463},{6,0,772},{6,0,1137},{139
+,11,595},{7,0,977},{139,11,66},{138,0,893},{20,0,48},{148,11,48},{5,0,824},{133,
+0,941},{134,11,295},{7,0,1543},{7,0,1785},{10,0,690},{4,10,106},{139,10,717},{7,
+0,440},{8,0,230},{139,0,106},{5,10,890},{133,10,988},{6,10,626},{142,10,431},{10
+,11,127},{141,11,27},{17,0,32},{10,10,706},{150,10,44},{132,0,216},{137,0,332},{
+4,10,698},{136,11,119},{139,11,267},{138,10,17},{11,11,526},{11,11,939},{141,11,
+290},{7,11,1167},{11,11,934},{13,11,391},{145,11,76},{139,11,39},{134,10,84},{4,
+0,914},{5,0,800},{133,0,852},{10,0,416},{141,0,115},{7,0,564},{142,0,168},{4,0,
+918},{133,0,876},{134,0,1764},{152,0,3},{4,0,92},{5,0,274},{7,11,126},{136,11,84
+},{140,10,498},{136,11,790},{8,0,501},{5,10,986},{6,10,130},{7,10,1582},{8,10,
+458},{10,10,101},{10,10,318},{138,10,823},{6,11,64},{12,11,377},{141,11,309},{5,
+0,743},{138,0,851},{4,0,49},{7,0,280},{135,0,1633},{134,0,879},{136,0,47},{7,10,
+1644},{137,10,129},{132,0,865},{134,0,1202},{9,11,34},{139,11,484},{135,10,997},
+{5,0,272},{5,0,908},{5,0,942},{8,0,197},{9,0,47},{11,0,538},{139,0,742},{6,11,
+1700},{7,11,26},{7,11,293},{7,11,382},{7,11,1026},{7,11,1087},{7,11,2027},{8,11,
+24},{8,11,114},{8,11,252},{8,11,727},{8,11,729},{9,11,30},{9,11,199},{9,11,231},
+{9,11,251},{9,11,334},{9,11,361},{9,11,488},{9,11,712},{10,11,55},{10,11,60},{10
+,11,232},{10,11,332},{10,11,384},{10,11,396},{10,11,504},{10,11,542},{10,11,652}
+,{11,11,20},{11,11,48},{11,11,207},{11,11,291},{11,11,298},{11,11,342},{11,11,
+365},{11,11,394},{11,11,620},{11,11,705},{11,11,1017},{12,11,123},{12,11,340},{
+12,11,406},{12,11,643},{13,11,61},{13,11,269},{13,11,311},{13,11,319},{13,11,486
+},{14,11,234},{15,11,62},{15,11,85},{16,11,71},{18,11,119},{148,11,105},{6,0,
+1455},{150,11,37},{135,10,1927},{135,0,1911},{137,0,891},{7,10,1756},{137,10,98}
+,{7,10,1046},{139,10,160},{132,0,761},{6,11,379},{7,11,270},{7,11,1116},{8,11,
+176},{8,11,183},{9,11,432},{9,11,661},{12,11,247},{12,11,617},{146,11,125},{6,10
+,45},{7,10,433},{8,10,129},{9,10,21},{10,10,392},{11,10,79},{12,10,499},{13,10,
+199},{141,10,451},{4,0,407},{5,11,792},{133,11,900},{132,0,560},{135,0,183},{13,
+0,490},{7,10,558},{136,10,353},{4,0,475},{6,0,731},{11,0,35},{13,0,71},{13,0,177
+},{14,0,422},{133,10,785},{8,10,81},{9,10,189},{9,10,201},{11,10,478},{11,10,712
+},{141,10,338},{4,0,418},{4,0,819},{133,10,353},{151,10,26},{4,11,901},{133,11,
+776},{132,0,575},{7,0,818},{16,0,92},{17,0,14},{17,0,45},{18,0,75},{148,0,18},{6
+,0,222},{7,0,636},{7,0,1620},{8,0,409},{9,0,693},{139,0,77},{6,10,25},{7,10,855}
+,{7,10,1258},{144,10,32},{6,0,1880},{6,0,1887},{6,0,1918},{6,0,1924},{9,0,967},{
+9,0,995},{9,0,1015},{12,0,826},{12,0,849},{12,0,857},{12,0,860},{12,0,886},{12,0
+,932},{18,0,228},{18,0,231},{146,0,240},{134,0,633},{134,0,1308},{4,11,37},{5,11
+,334},{135,11,1253},{10,0,86},{4,10,4},{7,10,1118},{7,10,1320},{7,10,1706},{8,10
+,277},{9,10,622},{11,10,724},{12,10,350},{12,10,397},{13,10,28},{13,10,159},{15,
+10,89},{18,10,5},{19,10,9},{20,10,34},{150,10,47},{132,11,508},{137,11,448},{12,
+11,107},{146,11,31},{132,0,817},{134,0,663},{133,0,882},{134,0,914},{132,11,540}
+,{132,11,533},{136,11,608},{8,0,885},{138,0,865},{132,0,426},{6,0,58},{7,0,745},
+{7,0,1969},{8,0,399},{8,0,675},{9,0,479},{9,0,731},{10,0,330},{10,0,593},{10,0,
+817},{11,0,32},{11,0,133},{11,0,221},{145,0,68},{134,10,255},{7,0,102},{137,0,
+538},{137,10,216},{7,11,253},{136,11,549},{135,11,912},{9,10,183},{139,10,286},{
+11,10,956},{151,10,3},{8,11,527},{18,11,60},{147,11,24},{4,10,536},{7,10,1141},{
+10,10,723},{139,10,371},{133,11,920},{7,0,876},{135,10,285},{135,10,560},{132,10
+,690},{142,11,126},{11,10,33},{12,10,571},{149,10,1},{133,0,566},{9,0,139},{10,0
+,399},{11,0,469},{12,0,634},{13,0,223},{132,11,483},{6,0,48},{135,0,63},{18,0,12
+},{7,10,1862},{12,10,491},{12,10,520},{13,10,383},{142,10,244},{135,11,1665},{
+132,11,448},{9,11,495},{146,11,104},{6,0,114},{7,0,1224},{7,0,1556},{136,0,3},{4
+,10,190},{133,10,554},{8,0,576},{9,0,267},{133,10,1001},{133,10,446},{133,0,933}
+,{139,11,1009},{8,11,653},{13,11,93},{147,11,14},{6,0,692},{6,0,821},{134,0,1077
+},{5,11,172},{135,11,801},{138,0,752},{4,0,375},{134,0,638},{134,0,1011},{140,11
+,540},{9,0,96},{133,11,260},{139,11,587},{135,10,1231},{12,0,30},{13,0,148},{14,
+0,87},{14,0,182},{16,0,42},{20,0,70},{132,10,304},{6,0,1398},{7,0,56},{7,0,1989}
+,{8,0,337},{8,0,738},{9,0,600},{12,0,37},{13,0,447},{142,0,92},{138,0,666},{5,0,
+394},{7,0,487},{136,0,246},{9,0,437},{6,10,53},{6,10,199},{7,10,1408},{8,10,32},
+{8,10,93},{10,10,397},{10,10,629},{11,10,593},{11,10,763},{13,10,326},{145,10,35
+},{134,10,105},{9,0,320},{10,0,506},{138,10,794},{7,11,57},{8,11,167},{8,11,375}
+,{9,11,82},{9,11,561},{10,11,620},{10,11,770},{11,10,704},{141,10,396},{6,0,1003
+},{5,10,114},{5,10,255},{141,10,285},{7,0,866},{135,0,1163},{133,11,531},{132,0,
+328},{7,10,2035},{8,10,19},{9,10,89},{138,10,831},{8,11,194},{136,11,756},{136,0
+,1000},{5,11,453},{134,11,441},{4,0,101},{5,0,833},{7,0,1171},{136,0,744},{133,0
+,726},{136,10,746},{138,0,176},{6,0,9},{6,0,397},{7,0,53},{7,0,1742},{10,0,632},
+{11,0,828},{140,0,146},{135,11,22},{145,11,64},{132,0,839},{11,0,417},{12,0,223}
+,{140,0,265},{4,11,102},{7,11,815},{7,11,1699},{139,11,964},{5,10,955},{136,10,
+814},{6,0,1931},{6,0,2007},{18,0,246},{146,0,247},{8,0,198},{11,0,29},{140,0,534
+},{135,0,1771},{6,0,846},{7,11,1010},{11,11,733},{11,11,759},{12,11,563},{13,11,
+34},{14,11,101},{18,11,45},{146,11,129},{4,0,186},{5,0,157},{8,0,168},{138,0,6},
+{132,11,899},{133,10,56},{148,10,100},{133,0,875},{5,0,773},{5,0,991},{6,0,1635}
+,{134,0,1788},{6,0,1274},{9,0,477},{141,0,78},{4,0,639},{7,0,111},{8,0,581},{12,
+0,177},{6,11,52},{9,11,104},{9,11,559},{10,10,4},{10,10,13},{11,10,638},{12,11,
+308},{19,11,87},{148,10,57},{132,11,604},{4,11,301},{133,10,738},{133,10,758},{
+134,0,1747},{7,11,1440},{11,11,854},{11,11,872},{11,11,921},{12,11,551},{13,11,
+472},{142,11,367},{7,0,1364},{7,0,1907},{141,0,158},{134,0,873},{4,0,404},{4,0,
+659},{7,0,552},{135,0,675},{135,10,1112},{139,10,328},{7,11,508},{137,10,133},{
+133,0,391},{5,10,110},{6,10,169},{6,10,1702},{7,10,400},{8,10,538},{9,10,184},{9
+,10,524},{140,10,218},{6,11,310},{7,11,1849},{8,11,72},{8,11,272},{8,11,431},{9,
+11,12},{9,11,351},{10,11,563},{10,11,630},{10,11,810},{11,11,367},{11,11,599},{
+11,11,686},{140,11,672},{5,0,540},{6,0,1697},{136,0,668},{132,0,883},{134,0,78},
+{12,0,628},{18,0,79},{6,10,133},{9,10,353},{139,10,993},{6,11,181},{7,11,537},{8
+,11,64},{9,11,127},{10,11,496},{12,11,510},{141,11,384},{6,10,93},{7,10,1422},{7
+,10,1851},{8,10,673},{9,10,529},{140,10,43},{137,10,371},{134,0,1460},{134,0,962
+},{4,11,244},{135,11,233},{9,10,25},{10,10,467},{138,10,559},{4,10,335},{135,10,
+942},{133,0,460},{135,11,334},{134,11,1650},{4,0,199},{139,0,34},{5,10,601},{8,
+10,39},{10,10,773},{11,10,84},{12,10,205},{142,10,1},{133,10,870},{134,0,388},{
+14,0,474},{148,0,120},{133,11,369},{139,0,271},{4,0,511},{9,0,333},{9,0,379},{10
+,0,602},{11,0,441},{11,0,723},{11,0,976},{12,0,357},{132,10,181},{134,0,608},{
+134,10,1652},{22,0,49},{137,11,338},{140,0,988},{134,0,617},{5,0,938},{136,0,707
+},{132,10,97},{5,10,147},{6,10,286},{7,10,1362},{141,10,176},{6,0,756},{134,0,
+1149},{133,11,896},{6,10,375},{7,10,169},{7,10,254},{136,10,780},{134,0,1583},{
+135,10,1447},{139,0,285},{7,11,1117},{8,11,393},{136,11,539},{135,0,344},{6,0,
+469},{7,0,1709},{138,0,515},{5,10,629},{135,10,1549},{5,11,4},{5,11,810},{6,11,
+13},{6,11,538},{6,11,1690},{6,11,1726},{7,11,499},{7,11,1819},{8,11,148},{8,11,
+696},{8,11,791},{12,11,125},{13,11,54},{143,11,9},{135,11,1268},{137,0,404},{132
+,0,500},{5,0,68},{134,0,383},{11,0,216},{139,0,340},{4,11,925},{5,11,803},{8,11,
+698},{138,11,828},{4,0,337},{6,0,353},{7,0,1934},{8,0,488},{137,0,429},{7,0,236}
+,{7,0,1795},{8,0,259},{9,0,135},{9,0,177},{9,0,860},{10,0,825},{11,0,115},{11,0,
+370},{11,0,405},{11,0,604},{12,0,10},{12,0,667},{12,0,669},{13,0,76},{14,0,310},
+{15,0,76},{15,0,147},{148,0,23},{4,0,15},{4,0,490},{5,0,22},{6,0,244},{7,0,40},{
+7,0,200},{7,0,906},{7,0,1199},{9,0,616},{10,0,716},{11,0,635},{11,0,801},{140,0,
+458},{12,0,756},{132,10,420},{134,0,1504},{6,0,757},{133,11,383},{6,0,1266},{135
+,0,1735},{5,0,598},{7,0,791},{8,0,108},{9,0,123},{7,10,1570},{140,10,542},{142,
+11,410},{9,11,660},{138,11,347}
+};
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_STATIC_DICT_LUT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.c
new file mode 100644
index 000000000..04a780516
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.c
@@ -0,0 +1,85 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Heuristics for deciding about the UTF8-ness of strings. */
+
+#include "./utf8_util.h"
+
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static size_t BrotliParseAsUTF8(
+ int* symbol, const uint8_t* input, size_t size) {
+ /* ASCII */
+ if ((input[0] & 0x80) == 0) {
+ *symbol = input[0];
+ if (*symbol > 0) {
+ return 1;
+ }
+ }
+ /* 2-byte UTF8 */
+ if (size > 1u &&
+ (input[0] & 0xE0) == 0xC0 &&
+ (input[1] & 0xC0) == 0x80) {
+ *symbol = (((input[0] & 0x1F) << 6) |
+ (input[1] & 0x3F));
+ if (*symbol > 0x7F) {
+ return 2;
+ }
+ }
+ /* 3-byte UFT8 */
+ if (size > 2u &&
+ (input[0] & 0xF0) == 0xE0 &&
+ (input[1] & 0xC0) == 0x80 &&
+ (input[2] & 0xC0) == 0x80) {
+ *symbol = (((input[0] & 0x0F) << 12) |
+ ((input[1] & 0x3F) << 6) |
+ (input[2] & 0x3F));
+ if (*symbol > 0x7FF) {
+ return 3;
+ }
+ }
+ /* 4-byte UFT8 */
+ if (size > 3u &&
+ (input[0] & 0xF8) == 0xF0 &&
+ (input[1] & 0xC0) == 0x80 &&
+ (input[2] & 0xC0) == 0x80 &&
+ (input[3] & 0xC0) == 0x80) {
+ *symbol = (((input[0] & 0x07) << 18) |
+ ((input[1] & 0x3F) << 12) |
+ ((input[2] & 0x3F) << 6) |
+ (input[3] & 0x3F));
+ if (*symbol > 0xFFFF && *symbol <= 0x10FFFF) {
+ return 4;
+ }
+ }
+ /* Not UTF8, emit a special symbol above the UTF8-code space */
+ *symbol = 0x110000 | input[0];
+ return 1;
+}
+
+/* Returns 1 if at least min_fraction of the data is UTF8-encoded.*/
+BROTLI_BOOL BrotliIsMostlyUTF8(
+ const uint8_t* data, const size_t pos, const size_t mask,
+ const size_t length, const double min_fraction) {
+ size_t size_utf8 = 0;
+ size_t i = 0;
+ while (i < length) {
+ int symbol;
+ size_t bytes_read =
+ BrotliParseAsUTF8(&symbol, &data[(pos + i) & mask], length - i);
+ i += bytes_read;
+ if (symbol < 0x110000) size_utf8 += bytes_read;
+ }
+ return TO_BROTLI_BOOL(size_utf8 > min_fraction * (double)length);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.h
new file mode 100644
index 000000000..8fda80c22
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/utf8_util.h
@@ -0,0 +1,32 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Heuristics for deciding about the UTF8-ness of strings. */
+
+#ifndef BROTLI_ENC_UTF8_UTIL_H_
+#define BROTLI_ENC_UTF8_UTIL_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const double kMinUTF8Ratio = 0.75;
+
+/* Returns 1 if at least min_fraction of the bytes between pos and
+ pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise
+ returns 0. */
+BROTLI_INTERNAL BROTLI_BOOL BrotliIsMostlyUTF8(
+ const uint8_t* data, const size_t pos, const size_t mask,
+ const size_t length, const double min_fraction);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_UTF8_UTIL_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/write_bits.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/write_bits.h
new file mode 100644
index 000000000..f6f88b45b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/enc/write_bits.h
@@ -0,0 +1,87 @@
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Write bits into a byte array. */
+
+#ifndef BROTLI_ENC_WRITE_BITS_H_
+#define BROTLI_ENC_WRITE_BITS_H_
+
+#include "../common/platform.h"
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* This function writes bits into bytes in increasing addresses, and within
+ a byte least-significant-bit first.
+
+ The function can write up to 56 bits in one go with WriteBits
+ Example: let's assume that 3 bits (Rs below) have been written already:
+
+ BYTE-0 BYTE+1 BYTE+2
+
+ 0000 0RRR 0000 0000 0000 0000
+
+ Now, we could write 5 or less bits in MSB by just shifting by 3
+ and OR'ing to BYTE-0.
+
+ For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
+ and locate the rest in BYTE+1, BYTE+2, etc. */
+static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
+ uint64_t bits,
+ size_t* BROTLI_RESTRICT pos,
+ uint8_t* BROTLI_RESTRICT array) {
+ BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits,
+ (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
+ (int)*pos));
+ BROTLI_DCHECK((bits >> n_bits) == 0);
+ BROTLI_DCHECK(n_bits <= 56);
+#if defined(BROTLI_LITTLE_ENDIAN)
+ /* This branch of the code can write up to 56 bits at a time,
+ 7 bits are lost by being perhaps already in *p and at least
+ 1 bit is needed to initialize the bit-stream ahead (i.e. if 7
+ bits are in *p and we write 57 bits, then the next write will
+ access a byte that was never initialized). */
+ {
+ uint8_t* p = &array[*pos >> 3];
+ uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
+ v |= bits << (*pos & 7);
+ BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
+ *pos += n_bits;
+ }
+#else
+ /* implicit & 0xFF is assumed for uint8_t arithmetics */
+ {
+ uint8_t* array_pos = &array[*pos >> 3];
+ const size_t bits_reserved_in_first_byte = (*pos & 7);
+ size_t bits_left_to_write;
+ bits <<= bits_reserved_in_first_byte;
+ *array_pos++ |= (uint8_t)bits;
+ for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
+ bits_left_to_write >= 9;
+ bits_left_to_write -= 8) {
+ bits >>= 8;
+ *array_pos++ = (uint8_t)bits;
+ }
+ *array_pos = 0;
+ *pos += n_bits;
+ }
+#endif
+}
+
+static BROTLI_INLINE void BrotliWriteBitsPrepareStorage(
+ size_t pos, uint8_t* array) {
+ BROTLI_LOG(("WriteBitsPrepareStorage %10d\n", (int)pos));
+ BROTLI_DCHECK((pos & 7) == 0);
+ array[pos >> 3] = 0;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_WRITE_BITS_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/decode_fuzzer.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/decode_fuzzer.c
new file mode 100644
index 000000000..46144e07e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/decode_fuzzer.c
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <brotli/decode.h>
+
+// Entry point for LibFuzzer.
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ size_t addend = 0;
+ if (size > 0)
+ addend = data[size - 1] & 7;
+ const uint8_t* next_in = data;
+
+ const int kBufferSize = 1024;
+ uint8_t* buffer = (uint8_t*) malloc(kBufferSize);
+ if (!buffer) {
+ // OOM is out-of-scope here.
+ return 0;
+ }
+ /* The biggest "magic number" in brotli is 16MiB - 16, so no need to check
+ the cases with much longer output. */
+ const size_t total_out_limit = (addend == 0) ? (1 << 26) : (1 << 24);
+ size_t total_out = 0;
+
+ BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0);
+
+ if (addend == 0)
+ addend = size;
+ /* Test both fast (addend == size) and slow (addend <= 7) decoding paths. */
+ for (size_t i = 0; i < size;) {
+ size_t next_i = i + addend;
+ if (next_i > size)
+ next_i = size;
+ size_t avail_in = next_i - i;
+ i = next_i;
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+ while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ size_t avail_out = kBufferSize;
+ uint8_t* next_out = buffer;
+ result = BrotliDecoderDecompressStream(
+ state, &avail_in, &next_in, &avail_out, &next_out, &total_out);
+ if (total_out > total_out_limit)
+ break;
+ }
+ if (total_out > total_out_limit)
+ break;
+ if (result != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT)
+ break;
+ }
+
+ BrotliDecoderDestroyInstance(state);
+ free(buffer);
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/run_decode_fuzzer.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/run_decode_fuzzer.c
new file mode 100644
index 000000000..c84f98a32
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/run_decode_fuzzer.c
@@ -0,0 +1,44 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Simple runner for decode_fuzzer.cc */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+
+int main(int argc, char* *argv) {
+ if (argc != 2) {
+ fprintf(stderr, "Exactly one argument is expected.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ FILE* f = fopen(argv[1], "r");
+ if (!f) {
+ fprintf(stderr, "Failed to open input file.");
+ exit(EXIT_FAILURE);
+ }
+
+ size_t max_len = 1 << 20;
+ unsigned char* tmp = (unsigned char*)malloc(max_len);
+ size_t len = fread(tmp, 1, max_len, f);
+ if (ferror(f)) {
+ fclose(f);
+ fprintf(stderr, "Failed read input file.");
+ exit(EXIT_FAILURE);
+ }
+ /* Make data after the end "inaccessible". */
+ unsigned char* data = (unsigned char*)malloc(len);
+ memcpy(data, tmp, len);
+ free(tmp);
+
+ LLVMFuzzerTestOneInput(data, len);
+ free(data);
+ exit(EXIT_SUCCESS);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/test_fuzzer.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/test_fuzzer.sh
new file mode 100755
index 000000000..9985194a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/fuzz/test_fuzzer.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+set -e
+
+export CC=${CC:-cc}
+
+BROTLI="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
+SRC=$BROTLI/c
+
+cd $BROTLI
+
+rm -rf bin
+mkdir bin
+cd bin
+
+cmake $BROTLI -DCMAKE_C_COMPILER="$CC" \
+ -DBUILD_TESTING=OFF -DENABLE_SANITIZER=address
+make -j$(nproc) brotlidec-static
+
+${CC} -o run_decode_fuzzer -std=c99 -fsanitize=address -I$SRC/include \
+ $SRC/fuzz/decode_fuzzer.c $SRC/fuzz/run_decode_fuzzer.c \
+ ./libbrotlidec-static.a ./libbrotlicommon-static.a
+
+mkdir decode_corpora
+unzip $BROTLI/java/org/brotli/integration/fuzz_data.zip -d decode_corpora
+
+for f in `ls decode_corpora`
+do
+ echo "Testing $f"
+ ./run_decode_fuzzer decode_corpora/$f
+done
+
+cd $BROTLI
+rm -rf bin
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/decode.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/decode.h
new file mode 100644
index 000000000..0f5c8f9d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/decode.h
@@ -0,0 +1,344 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/**
+ * @file
+ * API for Brotli decompression.
+ */
+
+#ifndef BROTLI_DEC_DECODE_H_
+#define BROTLI_DEC_DECODE_H_
+
+#include <brotli/port.h>
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/**
+ * Opaque structure that holds decoder state.
+ *
+ * Allocated and initialized with ::BrotliDecoderCreateInstance.
+ * Cleaned up and deallocated with ::BrotliDecoderDestroyInstance.
+ */
+typedef struct BrotliDecoderStateStruct BrotliDecoderState;
+
+/**
+ * Result type for ::BrotliDecoderDecompress and
+ * ::BrotliDecoderDecompressStream functions.
+ */
+typedef enum {
+ /** Decoding error, e.g. corrupted input or memory allocation problem. */
+ BROTLI_DECODER_RESULT_ERROR = 0,
+ /** Decoding successfully completed. */
+ BROTLI_DECODER_RESULT_SUCCESS = 1,
+ /** Partially done; should be called again with more input. */
+ BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2,
+ /** Partially done; should be called again with more output. */
+ BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3
+} BrotliDecoderResult;
+
+/**
+ * Template that evaluates items of ::BrotliDecoderErrorCode.
+ *
+ * Example: @code {.cpp}
+ * // Log Brotli error code.
+ * switch (brotliDecoderErrorCode) {
+ * #define CASE_(PREFIX, NAME, CODE) \
+ * case BROTLI_DECODER ## PREFIX ## NAME: \
+ * LOG(INFO) << "error code:" << #NAME; \
+ * break;
+ * #define NEWLINE_
+ * BROTLI_DECODER_ERROR_CODES_LIST(CASE_, NEWLINE_)
+ * #undef CASE_
+ * #undef NEWLINE_
+ * default: LOG(FATAL) << "unknown brotli error code";
+ * }
+ * @endcode
+ */
+#define BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \
+ BROTLI_ERROR_CODE(_, NO_ERROR, 0) SEPARATOR \
+ /* Same as BrotliDecoderResult values */ \
+ BROTLI_ERROR_CODE(_, SUCCESS, 1) SEPARATOR \
+ BROTLI_ERROR_CODE(_, NEEDS_MORE_INPUT, 2) SEPARATOR \
+ BROTLI_ERROR_CODE(_, NEEDS_MORE_OUTPUT, 3) SEPARATOR \
+ \
+ /* Errors caused by invalid input */ \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_NIBBLE, -1) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, RESERVED, -2) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_META_NIBBLE, -3) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, CL_SPACE, -6) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, HUFFMAN_SPACE, -7) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, CONTEXT_MAP_REPEAT, -8) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_1, -9) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_2, -10) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, TRANSFORM, -11) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, DICTIONARY, -12) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \
+ \
+ /* -17..-18 codes are reserved */ \
+ \
+ BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \
+ \
+ /* Memory allocation problems */ \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MODES, -21) SEPARATOR \
+ /* Literal, insert and distance trees together */ \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, TREE_GROUPS, -22) SEPARATOR \
+ /* -23..-24 codes are reserved for distinct tree groups */ \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MAP, -25) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_1, -26) SEPARATOR \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_2, -27) SEPARATOR \
+ /* -28..-29 codes are reserved for dynamic ring-buffer allocation */ \
+ BROTLI_ERROR_CODE(_ERROR_ALLOC_, BLOCK_TYPE_TREES, -30) SEPARATOR \
+ \
+ /* "Impossible" states */ \
+ BROTLI_ERROR_CODE(_ERROR_, UNREACHABLE, -31)
+
+/**
+ * Error code for detailed logging / production debugging.
+ *
+ * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE.
+ */
+typedef enum {
+#define BROTLI_COMMA_ ,
+#define BROTLI_ERROR_CODE_ENUM_ITEM_(PREFIX, NAME, CODE) \
+ BROTLI_DECODER ## PREFIX ## NAME = CODE
+ BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_ENUM_ITEM_, BROTLI_COMMA_)
+} BrotliDecoderErrorCode;
+#undef BROTLI_ERROR_CODE_ENUM_ITEM_
+#undef BROTLI_COMMA_
+
+/**
+ * The value of the last error code, negative integer.
+ *
+ * All other error code values are in the range from ::BROTLI_LAST_ERROR_CODE
+ * to @c -1. There are also 4 other possible non-error codes @c 0 .. @c 3 in
+ * ::BrotliDecoderErrorCode enumeration.
+ */
+#define BROTLI_LAST_ERROR_CODE BROTLI_DECODER_ERROR_UNREACHABLE
+
+/** Options to be used with ::BrotliDecoderSetParameter. */
+typedef enum BrotliDecoderParameter {
+ /**
+ * Disable "canny" ring buffer allocation strategy.
+ *
+ * Ring buffer is allocated according to window size, despite the real size of
+ * the content.
+ */
+ BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0,
+ /**
+ * Flag that determines if "Large Window Brotli" is used.
+ */
+ BROTLI_DECODER_PARAM_LARGE_WINDOW = 1
+} BrotliDecoderParameter;
+
+/**
+ * Sets the specified parameter to the given decoder instance.
+ *
+ * @param state decoder instance
+ * @param param parameter to set
+ * @param value new parameter value
+ * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid
+ * @returns ::BROTLI_TRUE if value is accepted
+ */
+BROTLI_DEC_API BROTLI_BOOL BrotliDecoderSetParameter(
+ BrotliDecoderState* state, BrotliDecoderParameter param, uint32_t value);
+
+/**
+ * Creates an instance of ::BrotliDecoderState and initializes it.
+ *
+ * The instance can be used once for decoding and should then be destroyed with
+ * ::BrotliDecoderDestroyInstance, it cannot be reused for a new decoding
+ * session.
+ *
+ * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
+ * case they are both zero, default memory allocators are used. @p opaque is
+ * passed to @p alloc_func and @p free_func when they are called. @p free_func
+ * has to return without doing anything when asked to free a NULL pointer.
+ *
+ * @param alloc_func custom memory allocation function
+ * @param free_func custom memory free function
+ * @param opaque custom memory manager handle
+ * @returns @c 0 if instance can not be allocated or initialized
+ * @returns pointer to initialized ::BrotliDecoderState otherwise
+ */
+BROTLI_DEC_API BrotliDecoderState* BrotliDecoderCreateInstance(
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
+
+/**
+ * Deinitializes and frees ::BrotliDecoderState instance.
+ *
+ * @param state decoder instance to be cleaned up and deallocated
+ */
+BROTLI_DEC_API void BrotliDecoderDestroyInstance(BrotliDecoderState* state);
+
+/**
+ * Performs one-shot memory-to-memory decompression.
+ *
+ * Decompresses the data in @p encoded_buffer into @p decoded_buffer, and sets
+ * @p *decoded_size to the decompressed length.
+ *
+ * @param encoded_size size of @p encoded_buffer
+ * @param encoded_buffer compressed data buffer with at least @p encoded_size
+ * addressable bytes
+ * @param[in, out] decoded_size @b in: size of @p decoded_buffer; \n
+ * @b out: length of decompressed data written to
+ * @p decoded_buffer
+ * @param decoded_buffer decompressed data destination buffer
+ * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory
+ * allocation failed, or @p decoded_buffer is not large enough;
+ * @returns ::BROTLI_DECODER_RESULT_SUCCESS otherwise
+ */
+BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompress(
+ size_t encoded_size,
+ const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)],
+ size_t* decoded_size,
+ uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]);
+
+/**
+ * Decompresses the input stream to the output stream.
+ *
+ * The values @p *available_in and @p *available_out must specify the number of
+ * bytes addressable at @p *next_in and @p *next_out respectively.
+ * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL.
+ *
+ * After each call, @p *available_in will be decremented by the amount of input
+ * bytes consumed, and the @p *next_in pointer will be incremented by that
+ * amount. Similarly, @p *available_out will be decremented by the amount of
+ * output bytes written, and the @p *next_out pointer will be incremented by
+ * that amount.
+ *
+ * @p total_out, if it is not a null-pointer, will be set to the number
+ * of bytes decompressed since the last @p state initialization.
+ *
+ * @note Input is never overconsumed, so @p next_in and @p available_in could be
+ * passed to the next consumer after decoding is complete.
+ *
+ * @param state decoder instance
+ * @param[in, out] available_in @b in: amount of available input; \n
+ * @b out: amount of unused input
+ * @param[in, out] next_in pointer to the next compressed byte
+ * @param[in, out] available_out @b in: length of output buffer; \n
+ * @b out: remaining size of output buffer
+ * @param[in, out] next_out output buffer cursor;
+ * can be @c NULL if @p available_out is @c 0
+ * @param[out] total_out number of bytes decompressed so far; can be @c NULL
+ * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory
+ * allocation failed, arguments were invalid, etc.;
+ * use ::BrotliDecoderGetErrorCode to get detailed error code
+ * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT decoding is blocked until
+ * more input data is provided
+ * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT decoding is blocked until
+ * more output space is provided
+ * @returns ::BROTLI_DECODER_RESULT_SUCCESS decoding is finished, no more
+ * input might be consumed and no more output will be produced
+ */
+BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompressStream(
+ BrotliDecoderState* state, size_t* available_in, const uint8_t** next_in,
+ size_t* available_out, uint8_t** next_out, size_t* total_out);
+
+/**
+ * Checks if decoder has more output.
+ *
+ * @param state decoder instance
+ * @returns ::BROTLI_TRUE, if decoder has some unconsumed output
+ * @returns ::BROTLI_FALSE otherwise
+ */
+BROTLI_DEC_API BROTLI_BOOL BrotliDecoderHasMoreOutput(
+ const BrotliDecoderState* state);
+
+/**
+ * Acquires pointer to internal output buffer.
+ *
+ * This method is used to make language bindings easier and more efficient:
+ * -# push data to ::BrotliDecoderDecompressStream,
+ * until ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT is reported
+ * -# use ::BrotliDecoderTakeOutput to peek bytes and copy to language-specific
+ * entity
+ *
+ * Also this could be useful if there is an output stream that is able to
+ * consume all the provided data (e.g. when data is saved to file system).
+ *
+ * @attention After every call to ::BrotliDecoderTakeOutput @p *size bytes of
+ * output are considered consumed for all consecutive calls to the
+ * instance methods; returned pointer becomes invalidated as well.
+ *
+ * @note Decoder output is not guaranteed to be contiguous. This means that
+ * after the size-unrestricted call to ::BrotliDecoderTakeOutput,
+ * immediate next call to ::BrotliDecoderTakeOutput may return more data.
+ *
+ * @param state decoder instance
+ * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if
+ * any amount could be handled; \n
+ * @b out: amount of data pointed by returned pointer and
+ * considered consumed; \n
+ * out value is never greater than in value, unless it is @c 0
+ * @returns pointer to output data
+ */
+BROTLI_DEC_API const uint8_t* BrotliDecoderTakeOutput(
+ BrotliDecoderState* state, size_t* size);
+
+/**
+ * Checks if instance has already consumed input.
+ *
+ * Instance that returns ::BROTLI_FALSE is considered "fresh" and could be
+ * reused.
+ *
+ * @param state decoder instance
+ * @returns ::BROTLI_TRUE if decoder has already used some input bytes
+ * @returns ::BROTLI_FALSE otherwise
+ */
+BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* state);
+
+/**
+ * Checks if decoder instance reached the final state.
+ *
+ * @param state decoder instance
+ * @returns ::BROTLI_TRUE if decoder is in a state where it reached the end of
+ * the input and produced all of the output
+ * @returns ::BROTLI_FALSE otherwise
+ */
+BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsFinished(
+ const BrotliDecoderState* state);
+
+/**
+ * Acquires a detailed error code.
+ *
+ * Should be used only after ::BrotliDecoderDecompressStream returns
+ * ::BROTLI_DECODER_RESULT_ERROR.
+ *
+ * See also ::BrotliDecoderErrorString
+ *
+ * @param state decoder instance
+ * @returns last saved error code
+ */
+BROTLI_DEC_API BrotliDecoderErrorCode BrotliDecoderGetErrorCode(
+ const BrotliDecoderState* state);
+
+/**
+ * Converts error code to a c-string.
+ */
+BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
+
+/**
+ * Gets a decoder library version.
+ *
+ * Look at BROTLI_VERSION for more information.
+ */
+BROTLI_DEC_API uint32_t BrotliDecoderVersion(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_DEC_DECODE_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/encode.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/encode.h
new file mode 100644
index 000000000..b2774cb63
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/encode.h
@@ -0,0 +1,448 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/**
+ * @file
+ * API for Brotli compression.
+ */
+
+#ifndef BROTLI_ENC_ENCODE_H_
+#define BROTLI_ENC_ENCODE_H_
+
+#include <brotli/port.h>
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */
+#define BROTLI_MIN_WINDOW_BITS 10
+/**
+ * Maximal value for ::BROTLI_PARAM_LGWIN parameter.
+ *
+ * @note equal to @c BROTLI_MAX_DISTANCE_BITS constant.
+ */
+#define BROTLI_MAX_WINDOW_BITS 24
+/**
+ * Maximal value for ::BROTLI_PARAM_LGWIN parameter
+ * in "Large Window Brotli" (32-bit).
+ */
+#define BROTLI_LARGE_MAX_WINDOW_BITS 30
+/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */
+#define BROTLI_MIN_INPUT_BLOCK_BITS 16
+/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */
+#define BROTLI_MAX_INPUT_BLOCK_BITS 24
+/** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */
+#define BROTLI_MIN_QUALITY 0
+/** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */
+#define BROTLI_MAX_QUALITY 11
+
+/** Options for ::BROTLI_PARAM_MODE parameter. */
+typedef enum BrotliEncoderMode {
+ /**
+ * Default compression mode.
+ *
+ * In this mode compressor does not know anything in advance about the
+ * properties of the input.
+ */
+ BROTLI_MODE_GENERIC = 0,
+ /** Compression mode for UTF-8 formatted text input. */
+ BROTLI_MODE_TEXT = 1,
+ /** Compression mode used in WOFF 2.0. */
+ BROTLI_MODE_FONT = 2
+} BrotliEncoderMode;
+
+/** Default value for ::BROTLI_PARAM_QUALITY parameter. */
+#define BROTLI_DEFAULT_QUALITY 11
+/** Default value for ::BROTLI_PARAM_LGWIN parameter. */
+#define BROTLI_DEFAULT_WINDOW 22
+/** Default value for ::BROTLI_PARAM_MODE parameter. */
+#define BROTLI_DEFAULT_MODE BROTLI_MODE_GENERIC
+
+/** Operations that can be performed by streaming encoder. */
+typedef enum BrotliEncoderOperation {
+ /**
+ * Process input.
+ *
+ * Encoder may postpone producing output, until it has processed enough input.
+ */
+ BROTLI_OPERATION_PROCESS = 0,
+ /**
+ * Produce output for all processed input.
+ *
+ * Actual flush is performed when input stream is depleted and there is enough
+ * space in output stream. This means that client should repeat
+ * ::BROTLI_OPERATION_FLUSH operation until @p available_in becomes @c 0, and
+ * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired
+ * via ::BrotliEncoderTakeOutput, then operation should be repeated after
+ * output buffer is drained.
+ *
+ * @warning Until flush is complete, client @b SHOULD @b NOT swap,
+ * reduce or extend input stream.
+ *
+ * When flush is complete, output data will be sufficient for decoder to
+ * reproduce all the given input.
+ */
+ BROTLI_OPERATION_FLUSH = 1,
+ /**
+ * Finalize the stream.
+ *
+ * Actual finalization is performed when input stream is depleted and there is
+ * enough space in output stream. This means that client should repeat
+ * ::BROTLI_OPERATION_FINISH operation until @p available_in becomes @c 0, and
+ * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired
+ * via ::BrotliEncoderTakeOutput, then operation should be repeated after
+ * output buffer is drained.
+ *
+ * @warning Until finalization is complete, client @b SHOULD @b NOT swap,
+ * reduce or extend input stream.
+ *
+ * Helper function ::BrotliEncoderIsFinished checks if stream is finalized and
+ * output fully dumped.
+ *
+ * Adding more input data to finalized stream is impossible.
+ */
+ BROTLI_OPERATION_FINISH = 2,
+ /**
+ * Emit metadata block to stream.
+ *
+ * Metadata is opaque to Brotli: neither encoder, nor decoder processes this
+ * data or relies on it. It may be used to pass some extra information from
+ * encoder client to decoder client without interfering with main data stream.
+ *
+ * @note Encoder may emit empty metadata blocks internally, to pad encoded
+ * stream to byte boundary.
+ *
+ * @warning Until emitting metadata is complete client @b SHOULD @b NOT swap,
+ * reduce or extend input stream.
+ *
+ * @warning The whole content of input buffer is considered to be the content
+ * of metadata block. Do @b NOT @e append metadata to input stream,
+ * before it is depleted with other operations.
+ *
+ * Stream is soft-flushed before metadata block is emitted. Metadata block
+ * @b MUST be no longer than than 16MiB.
+ */
+ BROTLI_OPERATION_EMIT_METADATA = 3
+} BrotliEncoderOperation;
+
+/** Options to be used with ::BrotliEncoderSetParameter. */
+typedef enum BrotliEncoderParameter {
+ /**
+ * Tune encoder for specific input.
+ *
+ * ::BrotliEncoderMode enumerates all available values.
+ */
+ BROTLI_PARAM_MODE = 0,
+ /**
+ * The main compression speed-density lever.
+ *
+ * The higher the quality, the slower the compression. Range is
+ * from ::BROTLI_MIN_QUALITY to ::BROTLI_MAX_QUALITY.
+ */
+ BROTLI_PARAM_QUALITY = 1,
+ /**
+ * Recommended sliding LZ77 window size.
+ *
+ * Encoder may reduce this value, e.g. if input is much smaller than
+ * window size.
+ *
+ * Window size is `(1 << value) - 16`.
+ *
+ * Range is from ::BROTLI_MIN_WINDOW_BITS to ::BROTLI_MAX_WINDOW_BITS.
+ */
+ BROTLI_PARAM_LGWIN = 2,
+ /**
+ * Recommended input block size.
+ *
+ * Encoder may reduce this value, e.g. if input is much smaller than input
+ * block size.
+ *
+ * Range is from ::BROTLI_MIN_INPUT_BLOCK_BITS to
+ * ::BROTLI_MAX_INPUT_BLOCK_BITS.
+ *
+ * @note Bigger input block size allows better compression, but consumes more
+ * memory. \n The rough formula of memory used for temporary input
+ * storage is `3 << lgBlock`.
+ */
+ BROTLI_PARAM_LGBLOCK = 3,
+ /**
+ * Flag that affects usage of "literal context modeling" format feature.
+ *
+ * This flag is a "decoding-speed vs compression ratio" trade-off.
+ */
+ BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING = 4,
+ /**
+ * Estimated total input size for all ::BrotliEncoderCompressStream calls.
+ *
+ * The default value is 0, which means that the total input size is unknown.
+ */
+ BROTLI_PARAM_SIZE_HINT = 5,
+ /**
+ * Flag that determines if "Large Window Brotli" is used.
+ */
+ BROTLI_PARAM_LARGE_WINDOW = 6,
+ /**
+ * Recommended number of postfix bits (NPOSTFIX).
+ *
+ * Encoder may change this value.
+ *
+ * Range is from 0 to ::BROTLI_MAX_NPOSTFIX.
+ */
+ BROTLI_PARAM_NPOSTFIX = 7,
+ /**
+ * Recommended number of direct distance codes (NDIRECT).
+ *
+ * Encoder may change this value.
+ *
+ * Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
+ */
+ BROTLI_PARAM_NDIRECT = 8,
+ /**
+ * Number of bytes of input stream already processed by a different instance.
+ *
+ * @note It is important to configure all the encoder instances with same
+ * parameters (except this one) in order to allow all the encoded parts
+ * obey the same restrictions implied by header.
+ *
+ * If offset is not 0, then stream header is omitted.
+ * In any case output start is byte aligned, so for proper streams stitching
+ * "predecessor" stream must be flushed.
+ *
+ * Range is not artificially limited, but all the values greater or equal to
+ * maximal window size have the same effect. Values greater than 2**30 are not
+ * allowed.
+ */
+ BROTLI_PARAM_STREAM_OFFSET = 9
+} BrotliEncoderParameter;
+
+/**
+ * Opaque structure that holds encoder state.
+ *
+ * Allocated and initialized with ::BrotliEncoderCreateInstance.
+ * Cleaned up and deallocated with ::BrotliEncoderDestroyInstance.
+ */
+typedef struct BrotliEncoderStateStruct BrotliEncoderState;
+
+/**
+ * Sets the specified parameter to the given encoder instance.
+ *
+ * @param state encoder instance
+ * @param param parameter to set
+ * @param value new parameter value
+ * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid
+ * @returns ::BROTLI_FALSE if value of parameter can not be changed at current
+ * encoder state (e.g. when encoding is started, window size might be
+ * already encoded and therefore it is impossible to change it)
+ * @returns ::BROTLI_TRUE if value is accepted
+ * @warning invalid values might be accepted in case they would not break
+ * encoding process.
+ */
+BROTLI_ENC_API BROTLI_BOOL BrotliEncoderSetParameter(
+ BrotliEncoderState* state, BrotliEncoderParameter param, uint32_t value);
+
+/**
+ * Creates an instance of ::BrotliEncoderState and initializes it.
+ *
+ * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
+ * case they are both zero, default memory allocators are used. @p opaque is
+ * passed to @p alloc_func and @p free_func when they are called. @p free_func
+ * has to return without doing anything when asked to free a NULL pointer.
+ *
+ * @param alloc_func custom memory allocation function
+ * @param free_func custom memory free function
+ * @param opaque custom memory manager handle
+ * @returns @c 0 if instance can not be allocated or initialized
+ * @returns pointer to initialized ::BrotliEncoderState otherwise
+ */
+BROTLI_ENC_API BrotliEncoderState* BrotliEncoderCreateInstance(
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
+
+/**
+ * Deinitializes and frees ::BrotliEncoderState instance.
+ *
+ * @param state decoder instance to be cleaned up and deallocated
+ */
+BROTLI_ENC_API void BrotliEncoderDestroyInstance(BrotliEncoderState* state);
+
+/**
+ * Calculates the output size bound for the given @p input_size.
+ *
+ * @warning Result is only valid if quality is at least @c 2 and, in
+ * case ::BrotliEncoderCompressStream was used, no flushes
+ * (::BROTLI_OPERATION_FLUSH) were performed.
+ *
+ * @param input_size size of projected input
+ * @returns @c 0 if result does not fit @c size_t
+ */
+BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size);
+
+/**
+ * Performs one-shot memory-to-memory compression.
+ *
+ * Compresses the data in @p input_buffer into @p encoded_buffer, and sets
+ * @p *encoded_size to the compressed length.
+ *
+ * @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
+ * value, then output is guaranteed to be no longer than that.
+ *
+ * @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting
+ * stream might be incompatible with RFC 7932; to decode such streams,
+ * decoder should be configured with
+ * ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1
+ *
+ * @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
+ * @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
+ * @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
+ * @param input_size size of @p input_buffer
+ * @param input_buffer input data buffer with at least @p input_size
+ * addressable bytes
+ * @param[in, out] encoded_size @b in: size of @p encoded_buffer; \n
+ * @b out: length of compressed data written to
+ * @p encoded_buffer, or @c 0 if compression fails
+ * @param encoded_buffer compressed data destination buffer
+ * @returns ::BROTLI_FALSE in case of compression error
+ * @returns ::BROTLI_FALSE if output buffer is too small
+ * @returns ::BROTLI_TRUE otherwise
+ */
+BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompress(
+ int quality, int lgwin, BrotliEncoderMode mode, size_t input_size,
+ const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)],
+ size_t* encoded_size,
+ uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]);
+
+/**
+ * Compresses input stream to output stream.
+ *
+ * The values @p *available_in and @p *available_out must specify the number of
+ * bytes addressable at @p *next_in and @p *next_out respectively.
+ * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL.
+ *
+ * After each call, @p *available_in will be decremented by the amount of input
+ * bytes consumed, and the @p *next_in pointer will be incremented by that
+ * amount. Similarly, @p *available_out will be decremented by the amount of
+ * output bytes written, and the @p *next_out pointer will be incremented by
+ * that amount.
+ *
+ * @p total_out, if it is not a null-pointer, will be set to the number
+ * of bytes compressed since the last @p state initialization.
+ *
+ *
+ *
+ * Internally workflow consists of 3 tasks:
+ * -# (optionally) copy input data to internal buffer
+ * -# actually compress data and (optionally) store it to internal buffer
+ * -# (optionally) copy compressed bytes from internal buffer to output stream
+ *
+ * Whenever all 3 tasks can't move forward anymore, or error occurs, this
+ * method returns the control flow to caller.
+ *
+ * @p op is used to perform flush, finish the stream, or inject metadata block.
+ * See ::BrotliEncoderOperation for more information.
+ *
+ * Flushing the stream means forcing encoding of all input passed to encoder and
+ * completing the current output block, so it could be fully decoded by stream
+ * decoder. To perform flush set @p op to ::BROTLI_OPERATION_FLUSH.
+ * Under some circumstances (e.g. lack of output stream capacity) this operation
+ * would require several calls to ::BrotliEncoderCompressStream. The method must
+ * be called again until both input stream is depleted and encoder has no more
+ * output (see ::BrotliEncoderHasMoreOutput) after the method is called.
+ *
+ * Finishing the stream means encoding of all input passed to encoder and
+ * adding specific "final" marks, so stream decoder could determine that stream
+ * is complete. To perform finish set @p op to ::BROTLI_OPERATION_FINISH.
+ * Under some circumstances (e.g. lack of output stream capacity) this operation
+ * would require several calls to ::BrotliEncoderCompressStream. The method must
+ * be called again until both input stream is depleted and encoder has no more
+ * output (see ::BrotliEncoderHasMoreOutput) after the method is called.
+ *
+ * @warning When flushing and finishing, @p op should not change until operation
+ * is complete; input stream should not be swapped, reduced or
+ * extended as well.
+ *
+ * @param state encoder instance
+ * @param op requested operation
+ * @param[in, out] available_in @b in: amount of available input; \n
+ * @b out: amount of unused input
+ * @param[in, out] next_in pointer to the next input byte
+ * @param[in, out] available_out @b in: length of output buffer; \n
+ * @b out: remaining size of output buffer
+ * @param[in, out] next_out compressed output buffer cursor;
+ * can be @c NULL if @p available_out is @c 0
+ * @param[out] total_out number of bytes produced so far; can be @c NULL
+ * @returns ::BROTLI_FALSE if there was an error
+ * @returns ::BROTLI_TRUE otherwise
+ */
+BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompressStream(
+ BrotliEncoderState* state, BrotliEncoderOperation op, size_t* available_in,
+ const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
+ size_t* total_out);
+
+/**
+ * Checks if encoder instance reached the final state.
+ *
+ * @param state encoder instance
+ * @returns ::BROTLI_TRUE if encoder is in a state where it reached the end of
+ * the input and produced all of the output
+ * @returns ::BROTLI_FALSE otherwise
+ */
+BROTLI_ENC_API BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* state);
+
+/**
+ * Checks if encoder has more output.
+ *
+ * @param state encoder instance
+ * @returns ::BROTLI_TRUE, if encoder has some unconsumed output
+ * @returns ::BROTLI_FALSE otherwise
+ */
+BROTLI_ENC_API BROTLI_BOOL BrotliEncoderHasMoreOutput(
+ BrotliEncoderState* state);
+
+/**
+ * Acquires pointer to internal output buffer.
+ *
+ * This method is used to make language bindings easier and more efficient:
+ * -# push data to ::BrotliEncoderCompressStream,
+ * until ::BrotliEncoderHasMoreOutput returns BROTL_TRUE
+ * -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific
+ * entity
+ *
+ * Also this could be useful if there is an output stream that is able to
+ * consume all the provided data (e.g. when data is saved to file system).
+ *
+ * @attention After every call to ::BrotliEncoderTakeOutput @p *size bytes of
+ * output are considered consumed for all consecutive calls to the
+ * instance methods; returned pointer becomes invalidated as well.
+ *
+ * @note Encoder output is not guaranteed to be contiguous. This means that
+ * after the size-unrestricted call to ::BrotliEncoderTakeOutput,
+ * immediate next call to ::BrotliEncoderTakeOutput may return more data.
+ *
+ * @param state encoder instance
+ * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if
+ * any amount could be handled; \n
+ * @b out: amount of data pointed by returned pointer and
+ * considered consumed; \n
+ * out value is never greater than in value, unless it is @c 0
+ * @returns pointer to output data
+ */
+BROTLI_ENC_API const uint8_t* BrotliEncoderTakeOutput(
+ BrotliEncoderState* state, size_t* size);
+
+
+/**
+ * Gets an encoder library version.
+ *
+ * Look at BROTLI_VERSION for more information.
+ */
+BROTLI_ENC_API uint32_t BrotliEncoderVersion(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* extern "C" */
+#endif
+
+#endif /* BROTLI_ENC_ENCODE_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/port.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/port.h
new file mode 100644
index 000000000..825237a33
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/port.h
@@ -0,0 +1,288 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Macros for compiler / platform specific API declarations. */
+
+#ifndef BROTLI_COMMON_PORT_H_
+#define BROTLI_COMMON_PORT_H_
+
+/* The following macros were borrowed from https://github.com/nemequ/hedley
+ * with permission of original author - Evan Nemerson <evan@nemerson.com> */
+
+/* >>> >>> >>> hedley macros */
+
+#define BROTLI_MAKE_VERSION(major, minor, revision) \
+ (((major) * 1000000) + ((minor) * 1000) + (revision))
+
+#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
+#define BROTLI_GNUC_VERSION \
+ BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#elif defined(__GNUC__)
+#define BROTLI_GNUC_VERSION BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, 0)
+#endif
+
+#if defined(BROTLI_GNUC_VERSION)
+#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_GNUC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
+#define BROTLI_MSVC_VERSION \
+ BROTLI_MAKE_VERSION((_MSC_FULL_VER / 10000000), \
+ (_MSC_FULL_VER % 10000000) / 100000, \
+ (_MSC_FULL_VER % 100000) / 100)
+#elif defined(_MSC_FULL_VER)
+#define BROTLI_MSVC_VERSION \
+ BROTLI_MAKE_VERSION((_MSC_FULL_VER / 1000000), \
+ (_MSC_FULL_VER % 1000000) / 10000, \
+ (_MSC_FULL_VER % 10000) / 10)
+#elif defined(_MSC_VER)
+#define BROTLI_MSVC_VERSION \
+ BROTLI_MAKE_VERSION(_MSC_VER / 100, _MSC_VER % 100, 0)
+#endif
+
+#if !defined(_MSC_VER)
+#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) (0)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
+ (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
+ (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
+#else
+#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
+ (_MSC_VER >= ((major * 100) + (minor)))
+#endif
+
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
+#define BROTLI_INTEL_VERSION \
+ BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, \
+ __INTEL_COMPILER % 100, \
+ __INTEL_COMPILER_UPDATE)
+#elif defined(__INTEL_COMPILER)
+#define BROTLI_INTEL_VERSION \
+ BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
+#endif
+
+#if defined(BROTLI_INTEL_VERSION)
+#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_INTEL_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__PGI) && \
+ defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
+#define BROTLI_PGI_VERSION \
+ BROTLI_MAKE_VERSION(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
+#endif
+
+#if defined(BROTLI_PGI_VERSION)
+#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_PGI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
+#define BROTLI_SUNPRO_VERSION \
+ BROTLI_MAKE_VERSION( \
+ (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
+ (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
+ (__SUNPRO_C & 0xf) * 10)
+#elif defined(__SUNPRO_C)
+#define BROTLI_SUNPRO_VERSION \
+ BROTLI_MAKE_VERSION((__SUNPRO_C >> 8) & 0xf, \
+ (__SUNPRO_C >> 4) & 0xf, \
+ (__SUNPRO_C) & 0xf)
+#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
+#define BROTLI_SUNPRO_VERSION \
+ BROTLI_MAKE_VERSION( \
+ (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
+ (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
+ (__SUNPRO_CC & 0xf) * 10)
+#elif defined(__SUNPRO_CC)
+#define BROTLI_SUNPRO_VERSION \
+ BROTLI_MAKE_VERSION((__SUNPRO_CC >> 8) & 0xf, \
+ (__SUNPRO_CC >> 4) & 0xf, \
+ (__SUNPRO_CC) & 0xf)
+#endif
+
+#if defined(BROTLI_SUNPRO_VERSION)
+#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_SUNPRO_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
+#define BROTLI_ARM_VERSION \
+ BROTLI_MAKE_VERSION((__ARMCOMPILER_VERSION / 1000000), \
+ (__ARMCOMPILER_VERSION % 1000000) / 10000, \
+ (__ARMCOMPILER_VERSION % 10000) / 100)
+#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
+#define BROTLI_ARM_VERSION \
+ BROTLI_MAKE_VERSION((__ARMCC_VERSION / 1000000), \
+ (__ARMCC_VERSION % 1000000) / 10000, \
+ (__ARMCC_VERSION % 10000) / 100)
+#endif
+
+#if defined(BROTLI_ARM_VERSION)
+#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_ARM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__ibmxl__)
+#define BROTLI_IBM_VERSION \
+ BROTLI_MAKE_VERSION(__ibmxl_version__, \
+ __ibmxl_release__, \
+ __ibmxl_modification__)
+#elif defined(__xlC__) && defined(__xlC_ver__)
+#define BROTLI_IBM_VERSION \
+ BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
+#elif defined(__xlC__)
+#define BROTLI_IBM_VERSION BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, 0)
+#endif
+
+#if defined(BROTLI_IBM_VERSION)
+#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_IBM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__TI_COMPILER_VERSION__)
+#define BROTLI_TI_VERSION \
+ BROTLI_MAKE_VERSION((__TI_COMPILER_VERSION__ / 1000000), \
+ (__TI_COMPILER_VERSION__ % 1000000) / 1000, \
+ (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(BROTLI_TI_VERSION)
+#define BROTLI_TI_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_TI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_TI_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__IAR_SYSTEMS_ICC__)
+#if __VER__ > 1000
+#define BROTLI_IAR_VERSION \
+ BROTLI_MAKE_VERSION((__VER__ / 1000000), \
+ (__VER__ / 1000) % 1000, \
+ (__VER__ % 1000))
+#else
+#define BROTLI_IAR_VERSION BROTLI_MAKE_VERSION(VER / 100, __VER__ % 100, 0)
+#endif
+#endif
+
+#if defined(BROTLI_IAR_VERSION)
+#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_IAR_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__TINYC__)
+#define BROTLI_TINYC_VERSION \
+ BROTLI_MAKE_VERSION(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
+#endif
+
+#if defined(BROTLI_TINYC_VERSION)
+#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) \
+ (BROTLI_TINYC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
+#else
+#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) (0)
+#endif
+
+#if defined(__has_attribute)
+#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
+ __has_attribute(attribute)
+#else
+#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
+ BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
+#endif
+
+#if defined(__has_builtin)
+#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
+ __has_builtin(builtin)
+#else
+#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
+ BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
+#endif
+
+#if defined(__has_feature)
+#define BROTLI_HAS_FEATURE(feature) __has_feature(feature)
+#else
+#define BROTLI_HAS_FEATURE(feature) (0)
+#endif
+
+#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \
+ defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) || \
+ defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer)
+#define BROTLI_SANITIZED 1
+#else
+#define BROTLI_SANITIZED 0
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define BROTLI_PUBLIC
+#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
+ BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
+ BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
+ BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
+ BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
+ (BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
+ defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
+#define BROTLI_PUBLIC __attribute__ ((visibility ("default")))
+#else
+#define BROTLI_PUBLIC
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+ !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \
+ !defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__)
+#define BROTLI_ARRAY_PARAM(name) (name)
+#else
+#define BROTLI_ARRAY_PARAM(name)
+#endif
+
+/* <<< <<< <<< end of hedley macros. */
+
+#if defined(BROTLI_SHARED_COMPILATION)
+#if defined(_WIN32)
+#if defined(BROTLICOMMON_SHARED_COMPILATION)
+#define BROTLI_COMMON_API __declspec(dllexport)
+#else
+#define BROTLI_COMMON_API __declspec(dllimport)
+#endif /* BROTLICOMMON_SHARED_COMPILATION */
+#if defined(BROTLIDEC_SHARED_COMPILATION)
+#define BROTLI_DEC_API __declspec(dllexport)
+#else
+#define BROTLI_DEC_API __declspec(dllimport)
+#endif /* BROTLIDEC_SHARED_COMPILATION */
+#if defined(BROTLIENC_SHARED_COMPILATION)
+#define BROTLI_ENC_API __declspec(dllexport)
+#else
+#define BROTLI_ENC_API __declspec(dllimport)
+#endif /* BROTLIENC_SHARED_COMPILATION */
+#else /* _WIN32 */
+#define BROTLI_COMMON_API BROTLI_PUBLIC
+#define BROTLI_DEC_API BROTLI_PUBLIC
+#define BROTLI_ENC_API BROTLI_PUBLIC
+#endif /* _WIN32 */
+#else /* BROTLI_SHARED_COMPILATION */
+#define BROTLI_COMMON_API
+#define BROTLI_DEC_API
+#define BROTLI_ENC_API
+#endif
+
+#endif /* BROTLI_COMMON_PORT_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/types.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/types.h
new file mode 100644
index 000000000..eff1a3cd0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/include/brotli/types.h
@@ -0,0 +1,83 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/**
+ * @file
+ * Common types used in decoder and encoder API.
+ */
+
+#ifndef BROTLI_COMMON_TYPES_H_
+#define BROTLI_COMMON_TYPES_H_
+
+#include <stddef.h> /* for size_t */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+#else
+#include <stdint.h>
+#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */
+
+/**
+ * A portable @c bool replacement.
+ *
+ * ::BROTLI_BOOL is a "documentation" type: actually it is @c int, but in API it
+ * denotes a type, whose only values are ::BROTLI_TRUE and ::BROTLI_FALSE.
+ *
+ * ::BROTLI_BOOL values passed to Brotli should either be ::BROTLI_TRUE or
+ * ::BROTLI_FALSE, or be a result of ::TO_BROTLI_BOOL macros.
+ *
+ * ::BROTLI_BOOL values returned by Brotli should not be tested for equality
+ * with @c true, @c false, ::BROTLI_TRUE, ::BROTLI_FALSE, but rather should be
+ * evaluated, for example: @code{.cpp}
+ * if (SomeBrotliFunction(encoder, BROTLI_TRUE) &&
+ * !OtherBrotliFunction(decoder, BROTLI_FALSE)) {
+ * bool x = !!YetAnotherBrotliFunction(encoder, TO_BROLTI_BOOL(2 * 2 == 4));
+ * DoSomething(x);
+ * }
+ * @endcode
+ */
+#define BROTLI_BOOL int
+/** Portable @c true replacement. */
+#define BROTLI_TRUE 1
+/** Portable @c false replacement. */
+#define BROTLI_FALSE 0
+/** @c bool to ::BROTLI_BOOL conversion macros. */
+#define TO_BROTLI_BOOL(X) (!!(X) ? BROTLI_TRUE : BROTLI_FALSE)
+
+#define BROTLI_MAKE_UINT64_T(high, low) ((((uint64_t)(high)) << 32) | low)
+
+#define BROTLI_UINT32_MAX (~((uint32_t)0))
+#define BROTLI_SIZE_MAX (~((size_t)0))
+
+/**
+ * Allocating function pointer type.
+ *
+ * @param opaque custom memory manager handle provided by client
+ * @param size requested memory region size; can not be @c 0
+ * @returns @c 0 in the case of failure
+ * @returns a valid pointer to a memory region of at least @p size bytes
+ * long otherwise
+ */
+typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
+
+/**
+ * Deallocating function pointer type.
+ *
+ * This function @b SHOULD do nothing if @p address is @c 0.
+ *
+ * @param opaque custom memory manager handle provided by client
+ * @param address memory region pointer returned by ::brotli_alloc_func, or @c 0
+ */
+typedef void (*brotli_free_func)(void* opaque, void* address);
+
+#endif /* BROTLI_COMMON_TYPES_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.c
new file mode 100644
index 000000000..04606a897
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.c
@@ -0,0 +1,1107 @@
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Command line interface for Brotli library. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "../common/constants.h"
+#include "../common/version.h"
+#include <brotli/decode.h>
+#include <brotli/encode.h>
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#include <utime.h>
+#define MAKE_BINARY(FILENO) (FILENO)
+#else
+#include <io.h>
+#include <share.h>
+#include <sys/utime.h>
+
+#define MAKE_BINARY(FILENO) (_setmode((FILENO), _O_BINARY), (FILENO))
+
+#if !defined(__MINGW32__)
+#define STDIN_FILENO _fileno(stdin)
+#define STDOUT_FILENO _fileno(stdout)
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#endif
+
+#define fdopen _fdopen
+#define isatty _isatty
+#define unlink _unlink
+#define utimbuf _utimbuf
+#define utime _utime
+
+#define fopen ms_fopen
+#define open ms_open
+
+#define chmod(F, P) (0)
+#define chown(F, O, G) (0)
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define fseek _fseeki64
+#define ftell _ftelli64
+#endif
+
+static FILE* ms_fopen(const char* filename, const char* mode) {
+ FILE* result = 0;
+ fopen_s(&result, filename, mode);
+ return result;
+}
+
+static int ms_open(const char* filename, int oflag, int pmode) {
+ int result = -1;
+ _sopen_s(&result, filename, oflag | O_BINARY, _SH_DENYNO, pmode);
+ return result;
+}
+#endif /* WIN32 */
+
+typedef enum {
+ COMMAND_COMPRESS,
+ COMMAND_DECOMPRESS,
+ COMMAND_HELP,
+ COMMAND_INVALID,
+ COMMAND_TEST_INTEGRITY,
+ COMMAND_NOOP,
+ COMMAND_VERSION
+} Command;
+
+#define DEFAULT_LGWIN 24
+#define DEFAULT_SUFFIX ".br"
+#define MAX_OPTIONS 20
+
+typedef struct {
+ /* Parameters */
+ int quality;
+ int lgwin;
+ int verbosity;
+ BROTLI_BOOL force_overwrite;
+ BROTLI_BOOL junk_source;
+ BROTLI_BOOL copy_stat;
+ BROTLI_BOOL write_to_stdout;
+ BROTLI_BOOL test_integrity;
+ BROTLI_BOOL decompress;
+ BROTLI_BOOL large_window;
+ const char* output_path;
+ const char* suffix;
+ int not_input_indices[MAX_OPTIONS];
+ size_t longest_path_len;
+ size_t input_count;
+
+ /* Inner state */
+ int argc;
+ char** argv;
+ char* modified_path; /* Storage for path with appended / cut suffix */
+ int iterator;
+ int ignore;
+ BROTLI_BOOL iterator_error;
+ uint8_t* buffer;
+ uint8_t* input;
+ uint8_t* output;
+ const char* current_input_path;
+ const char* current_output_path;
+ int64_t input_file_length; /* -1, if impossible to calculate */
+ FILE* fin;
+ FILE* fout;
+
+ /* I/O buffers */
+ size_t available_in;
+ const uint8_t* next_in;
+ size_t available_out;
+ uint8_t* next_out;
+
+ /* Reporting */
+ /* size_t would be large enough,
+ until 4GiB+ files are compressed / decompressed on 32-bit CPUs. */
+ size_t total_in;
+ size_t total_out;
+} Context;
+
+/* Parse up to 5 decimal digits. */
+static BROTLI_BOOL ParseInt(const char* s, int low, int high, int* result) {
+ int value = 0;
+ int i;
+ for (i = 0; i < 5; ++i) {
+ char c = s[i];
+ if (c == 0) break;
+ if (s[i] < '0' || s[i] > '9') return BROTLI_FALSE;
+ value = (10 * value) + (c - '0');
+ }
+ if (i == 0) return BROTLI_FALSE;
+ if (i > 1 && s[0] == '0') return BROTLI_FALSE;
+ if (s[i] != 0) return BROTLI_FALSE;
+ if (value < low || value > high) return BROTLI_FALSE;
+ *result = value;
+ return BROTLI_TRUE;
+}
+
+/* Returns "base file name" or its tail, if it contains '/' or '\'. */
+static const char* FileName(const char* path) {
+ const char* separator_position = strrchr(path, '/');
+ if (separator_position) path = separator_position + 1;
+ separator_position = strrchr(path, '\\');
+ if (separator_position) path = separator_position + 1;
+ return path;
+}
+
+/* Detect if the program name is a special alias that infers a command type. */
+static Command ParseAlias(const char* name) {
+ /* TODO: cast name to lower case? */
+ const char* unbrotli = "unbrotli";
+ size_t unbrotli_len = strlen(unbrotli);
+ name = FileName(name);
+ /* Partial comparison. On Windows there could be ".exe" suffix. */
+ if (strncmp(name, unbrotli, unbrotli_len) == 0) {
+ char terminator = name[unbrotli_len];
+ if (terminator == 0 || terminator == '.') return COMMAND_DECOMPRESS;
+ }
+ return COMMAND_COMPRESS;
+}
+
+static Command ParseParams(Context* params) {
+ int argc = params->argc;
+ char** argv = params->argv;
+ int i;
+ int next_option_index = 0;
+ size_t input_count = 0;
+ size_t longest_path_len = 1;
+ BROTLI_BOOL command_set = BROTLI_FALSE;
+ BROTLI_BOOL quality_set = BROTLI_FALSE;
+ BROTLI_BOOL output_set = BROTLI_FALSE;
+ BROTLI_BOOL keep_set = BROTLI_FALSE;
+ BROTLI_BOOL lgwin_set = BROTLI_FALSE;
+ BROTLI_BOOL suffix_set = BROTLI_FALSE;
+ BROTLI_BOOL after_dash_dash = BROTLI_FALSE;
+ Command command = ParseAlias(argv[0]);
+
+ for (i = 1; i < argc; ++i) {
+ const char* arg = argv[i];
+ /* C99 5.1.2.2.1: "members argv[0] through argv[argc-1] inclusive shall
+ contain pointers to strings"; NULL and 0-length are not forbidden. */
+ size_t arg_len = arg ? strlen(arg) : 0;
+
+ if (arg_len == 0) {
+ params->not_input_indices[next_option_index++] = i;
+ continue;
+ }
+
+ /* Too many options. The expected longest option list is:
+ "-q 0 -w 10 -o f -D d -S b -d -f -k -n -v --", i.e. 16 items in total.
+ This check is an additional guard that is never triggered, but provides
+ a guard for future changes. */
+ if (next_option_index > (MAX_OPTIONS - 2)) {
+ fprintf(stderr, "too many options passed\n");
+ return COMMAND_INVALID;
+ }
+
+ /* Input file entry. */
+ if (after_dash_dash || arg[0] != '-' || arg_len == 1) {
+ input_count++;
+ if (longest_path_len < arg_len) longest_path_len = arg_len;
+ continue;
+ }
+
+ /* Not a file entry. */
+ params->not_input_indices[next_option_index++] = i;
+
+ /* '--' entry stop parsing arguments. */
+ if (arg_len == 2 && arg[1] == '-') {
+ after_dash_dash = BROTLI_TRUE;
+ continue;
+ }
+
+ /* Simple / coalesced options. */
+ if (arg[1] != '-') {
+ size_t j;
+ for (j = 1; j < arg_len; ++j) {
+ char c = arg[j];
+ if (c >= '0' && c <= '9') {
+ if (quality_set) {
+ fprintf(stderr, "quality already set\n");
+ return COMMAND_INVALID;
+ }
+ quality_set = BROTLI_TRUE;
+ params->quality = c - '0';
+ continue;
+ } else if (c == 'c') {
+ if (output_set) {
+ fprintf(stderr, "write to standard output already set\n");
+ return COMMAND_INVALID;
+ }
+ output_set = BROTLI_TRUE;
+ params->write_to_stdout = BROTLI_TRUE;
+ continue;
+ } else if (c == 'd') {
+ if (command_set) {
+ fprintf(stderr, "command already set when parsing -d\n");
+ return COMMAND_INVALID;
+ }
+ command_set = BROTLI_TRUE;
+ command = COMMAND_DECOMPRESS;
+ continue;
+ } else if (c == 'f') {
+ if (params->force_overwrite) {
+ fprintf(stderr, "force output overwrite already set\n");
+ return COMMAND_INVALID;
+ }
+ params->force_overwrite = BROTLI_TRUE;
+ continue;
+ } else if (c == 'h') {
+ /* Don't parse further. */
+ return COMMAND_HELP;
+ } else if (c == 'j' || c == 'k') {
+ if (keep_set) {
+ fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
+ return COMMAND_INVALID;
+ }
+ keep_set = BROTLI_TRUE;
+ params->junk_source = TO_BROTLI_BOOL(c == 'j');
+ continue;
+ } else if (c == 'n') {
+ if (!params->copy_stat) {
+ fprintf(stderr, "argument --no-copy-stat / -n already set\n");
+ return COMMAND_INVALID;
+ }
+ params->copy_stat = BROTLI_FALSE;
+ continue;
+ } else if (c == 't') {
+ if (command_set) {
+ fprintf(stderr, "command already set when parsing -t\n");
+ return COMMAND_INVALID;
+ }
+ command_set = BROTLI_TRUE;
+ command = COMMAND_TEST_INTEGRITY;
+ continue;
+ } else if (c == 'v') {
+ if (params->verbosity > 0) {
+ fprintf(stderr, "argument --verbose / -v already set\n");
+ return COMMAND_INVALID;
+ }
+ params->verbosity = 1;
+ continue;
+ } else if (c == 'V') {
+ /* Don't parse further. */
+ return COMMAND_VERSION;
+ } else if (c == 'Z') {
+ if (quality_set) {
+ fprintf(stderr, "quality already set\n");
+ return COMMAND_INVALID;
+ }
+ quality_set = BROTLI_TRUE;
+ params->quality = 11;
+ continue;
+ }
+ /* o/q/w/D/S with parameter is expected */
+ if (c != 'o' && c != 'q' && c != 'w' && c != 'D' && c != 'S') {
+ fprintf(stderr, "invalid argument -%c\n", c);
+ return COMMAND_INVALID;
+ }
+ if (j + 1 != arg_len) {
+ fprintf(stderr, "expected parameter for argument -%c\n", c);
+ return COMMAND_INVALID;
+ }
+ i++;
+ if (i == argc || !argv[i] || argv[i][0] == 0) {
+ fprintf(stderr, "expected parameter for argument -%c\n", c);
+ return COMMAND_INVALID;
+ }
+ params->not_input_indices[next_option_index++] = i;
+ if (c == 'o') {
+ if (output_set) {
+ fprintf(stderr, "write to standard output already set (-o)\n");
+ return COMMAND_INVALID;
+ }
+ params->output_path = argv[i];
+ } else if (c == 'q') {
+ if (quality_set) {
+ fprintf(stderr, "quality already set\n");
+ return COMMAND_INVALID;
+ }
+ quality_set = ParseInt(argv[i], BROTLI_MIN_QUALITY,
+ BROTLI_MAX_QUALITY, &params->quality);
+ if (!quality_set) {
+ fprintf(stderr, "error parsing quality value [%s]\n", argv[i]);
+ return COMMAND_INVALID;
+ }
+ } else if (c == 'w') {
+ if (lgwin_set) {
+ fprintf(stderr, "lgwin parameter already set\n");
+ return COMMAND_INVALID;
+ }
+ lgwin_set = ParseInt(argv[i], 0,
+ BROTLI_MAX_WINDOW_BITS, &params->lgwin);
+ if (!lgwin_set) {
+ fprintf(stderr, "error parsing lgwin value [%s]\n", argv[i]);
+ return COMMAND_INVALID;
+ }
+ if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
+ fprintf(stderr,
+ "lgwin parameter (%d) smaller than the minimum (%d)\n",
+ params->lgwin, BROTLI_MIN_WINDOW_BITS);
+ return COMMAND_INVALID;
+ }
+ } else if (c == 'S') {
+ if (suffix_set) {
+ fprintf(stderr, "suffix already set\n");
+ return COMMAND_INVALID;
+ }
+ suffix_set = BROTLI_TRUE;
+ params->suffix = argv[i];
+ }
+ }
+ } else { /* Double-dash. */
+ arg = &arg[2];
+ if (strcmp("best", arg) == 0) {
+ if (quality_set) {
+ fprintf(stderr, "quality already set\n");
+ return COMMAND_INVALID;
+ }
+ quality_set = BROTLI_TRUE;
+ params->quality = 11;
+ } else if (strcmp("decompress", arg) == 0) {
+ if (command_set) {
+ fprintf(stderr, "command already set when parsing --decompress\n");
+ return COMMAND_INVALID;
+ }
+ command_set = BROTLI_TRUE;
+ command = COMMAND_DECOMPRESS;
+ } else if (strcmp("force", arg) == 0) {
+ if (params->force_overwrite) {
+ fprintf(stderr, "force output overwrite already set\n");
+ return COMMAND_INVALID;
+ }
+ params->force_overwrite = BROTLI_TRUE;
+ } else if (strcmp("help", arg) == 0) {
+ /* Don't parse further. */
+ return COMMAND_HELP;
+ } else if (strcmp("keep", arg) == 0) {
+ if (keep_set) {
+ fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
+ return COMMAND_INVALID;
+ }
+ keep_set = BROTLI_TRUE;
+ params->junk_source = BROTLI_FALSE;
+ } else if (strcmp("no-copy-stat", arg) == 0) {
+ if (!params->copy_stat) {
+ fprintf(stderr, "argument --no-copy-stat / -n already set\n");
+ return COMMAND_INVALID;
+ }
+ params->copy_stat = BROTLI_FALSE;
+ } else if (strcmp("rm", arg) == 0) {
+ if (keep_set) {
+ fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
+ return COMMAND_INVALID;
+ }
+ keep_set = BROTLI_TRUE;
+ params->junk_source = BROTLI_TRUE;
+ } else if (strcmp("stdout", arg) == 0) {
+ if (output_set) {
+ fprintf(stderr, "write to standard output already set\n");
+ return COMMAND_INVALID;
+ }
+ output_set = BROTLI_TRUE;
+ params->write_to_stdout = BROTLI_TRUE;
+ } else if (strcmp("test", arg) == 0) {
+ if (command_set) {
+ fprintf(stderr, "command already set when parsing --test\n");
+ return COMMAND_INVALID;
+ }
+ command_set = BROTLI_TRUE;
+ command = COMMAND_TEST_INTEGRITY;
+ } else if (strcmp("verbose", arg) == 0) {
+ if (params->verbosity > 0) {
+ fprintf(stderr, "argument --verbose / -v already set\n");
+ return COMMAND_INVALID;
+ }
+ params->verbosity = 1;
+ } else if (strcmp("version", arg) == 0) {
+ /* Don't parse further. */
+ return COMMAND_VERSION;
+ } else {
+ /* key=value */
+ const char* value = strrchr(arg, '=');
+ size_t key_len;
+ if (!value || value[1] == 0) {
+ fprintf(stderr, "must pass the parameter as --%s=value\n", arg);
+ return COMMAND_INVALID;
+ }
+ key_len = (size_t)(value - arg);
+ value++;
+ if (strncmp("lgwin", arg, key_len) == 0) {
+ if (lgwin_set) {
+ fprintf(stderr, "lgwin parameter already set\n");
+ return COMMAND_INVALID;
+ }
+ lgwin_set = ParseInt(value, 0,
+ BROTLI_MAX_WINDOW_BITS, &params->lgwin);
+ if (!lgwin_set) {
+ fprintf(stderr, "error parsing lgwin value [%s]\n", value);
+ return COMMAND_INVALID;
+ }
+ if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
+ fprintf(stderr,
+ "lgwin parameter (%d) smaller than the minimum (%d)\n",
+ params->lgwin, BROTLI_MIN_WINDOW_BITS);
+ return COMMAND_INVALID;
+ }
+ } else if (strncmp("large_window", arg, key_len) == 0) {
+ /* This option is intentionally not mentioned in help. */
+ if (lgwin_set) {
+ fprintf(stderr, "lgwin parameter already set\n");
+ return COMMAND_INVALID;
+ }
+ lgwin_set = ParseInt(value, 0,
+ BROTLI_LARGE_MAX_WINDOW_BITS, &params->lgwin);
+ if (!lgwin_set) {
+ fprintf(stderr, "error parsing lgwin value [%s]\n", value);
+ return COMMAND_INVALID;
+ }
+ if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
+ fprintf(stderr,
+ "lgwin parameter (%d) smaller than the minimum (%d)\n",
+ params->lgwin, BROTLI_MIN_WINDOW_BITS);
+ return COMMAND_INVALID;
+ }
+ } else if (strncmp("output", arg, key_len) == 0) {
+ if (output_set) {
+ fprintf(stderr,
+ "write to standard output already set (--output)\n");
+ return COMMAND_INVALID;
+ }
+ params->output_path = value;
+ } else if (strncmp("quality", arg, key_len) == 0) {
+ if (quality_set) {
+ fprintf(stderr, "quality already set\n");
+ return COMMAND_INVALID;
+ }
+ quality_set = ParseInt(value, BROTLI_MIN_QUALITY,
+ BROTLI_MAX_QUALITY, &params->quality);
+ if (!quality_set) {
+ fprintf(stderr, "error parsing quality value [%s]\n", value);
+ return COMMAND_INVALID;
+ }
+ } else if (strncmp("suffix", arg, key_len) == 0) {
+ if (suffix_set) {
+ fprintf(stderr, "suffix already set\n");
+ return COMMAND_INVALID;
+ }
+ suffix_set = BROTLI_TRUE;
+ params->suffix = value;
+ } else {
+ fprintf(stderr, "invalid parameter: [%s]\n", arg);
+ return COMMAND_INVALID;
+ }
+ }
+ }
+ }
+
+ params->input_count = input_count;
+ params->longest_path_len = longest_path_len;
+ params->decompress = (command == COMMAND_DECOMPRESS);
+ params->test_integrity = (command == COMMAND_TEST_INTEGRITY);
+
+ if (input_count > 1 && output_set) return COMMAND_INVALID;
+ if (params->test_integrity) {
+ if (params->output_path) return COMMAND_INVALID;
+ if (params->write_to_stdout) return COMMAND_INVALID;
+ }
+ if (strchr(params->suffix, '/') || strchr(params->suffix, '\\')) {
+ return COMMAND_INVALID;
+ }
+
+ return command;
+}
+
+static void PrintVersion(void) {
+ int major = BROTLI_VERSION >> 24;
+ int minor = (BROTLI_VERSION >> 12) & 0xFFF;
+ int patch = BROTLI_VERSION & 0xFFF;
+ fprintf(stdout, "brotli %d.%d.%d\n", major, minor, patch);
+}
+
+static void PrintHelp(const char* name, BROTLI_BOOL error) {
+ FILE* media = error ? stderr : stdout;
+ /* String is cut to pieces with length less than 509, to conform C90 spec. */
+ fprintf(media,
+"Usage: %s [OPTION]... [FILE]...\n",
+ name);
+ fprintf(media,
+"Options:\n"
+" -# compression level (0-9)\n"
+" -c, --stdout write on standard output\n"
+" -d, --decompress decompress\n"
+" -f, --force force output file overwrite\n"
+" -h, --help display this help and exit\n");
+ fprintf(media,
+" -j, --rm remove source file(s)\n"
+" -k, --keep keep source file(s) (default)\n"
+" -n, --no-copy-stat do not copy source file(s) attributes\n"
+" -o FILE, --output=FILE output file (only if 1 input file)\n");
+ fprintf(media,
+" -q NUM, --quality=NUM compression level (%d-%d)\n",
+ BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);
+ fprintf(media,
+" -t, --test test compressed file integrity\n"
+" -v, --verbose verbose mode\n");
+ fprintf(media,
+" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n"
+" window size = 2**NUM - 16\n"
+" 0 lets compressor choose the optimal value\n",
+ BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
+ fprintf(media,
+" --large_window=NUM use incompatible large-window brotli\n"
+" bitstream with window size (0, %d-%d)\n"
+" WARNING: this format is not compatible\n"
+" with brotli RFC 7932 and may not be\n"
+" decodable with regular brotli decoders\n",
+ BROTLI_MIN_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS);
+ fprintf(media,
+" -S SUF, --suffix=SUF output file suffix (default:'%s')\n",
+ DEFAULT_SUFFIX);
+ fprintf(media,
+" -V, --version display version and exit\n"
+" -Z, --best use best compression level (11) (default)\n"
+"Simple options could be coalesced, i.e. '-9kf' is equivalent to '-9 -k -f'.\n"
+"With no FILE, or when FILE is -, read standard input.\n"
+"All arguments after '--' are treated as files.\n");
+}
+
+static const char* PrintablePath(const char* path) {
+ return path ? path : "con";
+}
+
+static BROTLI_BOOL OpenInputFile(const char* input_path, FILE** f) {
+ *f = NULL;
+ if (!input_path) {
+ *f = fdopen(MAKE_BINARY(STDIN_FILENO), "rb");
+ return BROTLI_TRUE;
+ }
+ *f = fopen(input_path, "rb");
+ if (!*f) {
+ fprintf(stderr, "failed to open input file [%s]: %s\n",
+ PrintablePath(input_path), strerror(errno));
+ return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+static BROTLI_BOOL OpenOutputFile(const char* output_path, FILE** f,
+ BROTLI_BOOL force) {
+ int fd;
+ *f = NULL;
+ if (!output_path) {
+ *f = fdopen(MAKE_BINARY(STDOUT_FILENO), "wb");
+ return BROTLI_TRUE;
+ }
+ fd = open(output_path, O_CREAT | (force ? 0 : O_EXCL) | O_WRONLY | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open output file [%s]: %s\n",
+ PrintablePath(output_path), strerror(errno));
+ return BROTLI_FALSE;
+ }
+ *f = fdopen(fd, "wb");
+ if (!*f) {
+ fprintf(stderr, "failed to open output file [%s]: %s\n",
+ PrintablePath(output_path), strerror(errno));
+ return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+static int64_t FileSize(const char* path) {
+ FILE* f = fopen(path, "rb");
+ int64_t retval;
+ if (f == NULL) {
+ return -1;
+ }
+ if (fseek(f, 0L, SEEK_END) != 0) {
+ fclose(f);
+ return -1;
+ }
+ retval = ftell(f);
+ if (fclose(f) != 0) {
+ return -1;
+ }
+ return retval;
+}
+
+/* Copy file times and permissions.
+ TODO: this is a "best effort" implementation; honest cross-platform
+ fully featured implementation is way too hacky; add more hacks by request. */
+static void CopyStat(const char* input_path, const char* output_path) {
+ struct stat statbuf;
+ struct utimbuf times;
+ int res;
+ if (input_path == 0 || output_path == 0) {
+ return;
+ }
+ if (stat(input_path, &statbuf) != 0) {
+ return;
+ }
+ times.actime = statbuf.st_atime;
+ times.modtime = statbuf.st_mtime;
+ utime(output_path, &times);
+ res = chmod(output_path, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ if (res != 0) {
+ fprintf(stderr, "setting access bits failed for [%s]: %s\n",
+ PrintablePath(output_path), strerror(errno));
+ }
+ res = chown(output_path, (uid_t)-1, statbuf.st_gid);
+ if (res != 0) {
+ fprintf(stderr, "setting group failed for [%s]: %s\n",
+ PrintablePath(output_path), strerror(errno));
+ }
+ res = chown(output_path, statbuf.st_uid, (gid_t)-1);
+ if (res != 0) {
+ fprintf(stderr, "setting user failed for [%s]: %s\n",
+ PrintablePath(output_path), strerror(errno));
+ }
+}
+
+static BROTLI_BOOL NextFile(Context* context) {
+ const char* arg;
+ size_t arg_len;
+
+ /* Iterator points to last used arg; increment to search for the next one. */
+ context->iterator++;
+
+ context->input_file_length = -1;
+
+ /* No input path; read from console. */
+ if (context->input_count == 0) {
+ if (context->iterator > 1) return BROTLI_FALSE;
+ context->current_input_path = NULL;
+ /* Either write to the specified path, or to console. */
+ context->current_output_path = context->output_path;
+ return BROTLI_TRUE;
+ }
+
+ /* Skip option arguments. */
+ while (context->iterator == context->not_input_indices[context->ignore]) {
+ context->iterator++;
+ context->ignore++;
+ }
+
+ /* All args are scanned already. */
+ if (context->iterator >= context->argc) return BROTLI_FALSE;
+
+ /* Iterator now points to the input file name. */
+ arg = context->argv[context->iterator];
+ arg_len = strlen(arg);
+ /* Read from console. */
+ if (arg_len == 1 && arg[0] == '-') {
+ context->current_input_path = NULL;
+ context->current_output_path = context->output_path;
+ return BROTLI_TRUE;
+ }
+
+ context->current_input_path = arg;
+ context->input_file_length = FileSize(arg);
+ context->current_output_path = context->output_path;
+
+ if (context->output_path) return BROTLI_TRUE;
+ if (context->write_to_stdout) return BROTLI_TRUE;
+
+ strcpy(context->modified_path, arg);
+ context->current_output_path = context->modified_path;
+ /* If output is not specified, input path suffix should match. */
+ if (context->decompress) {
+ size_t suffix_len = strlen(context->suffix);
+ char* name = (char*)FileName(context->modified_path);
+ char* name_suffix;
+ size_t name_len = strlen(name);
+ if (name_len < suffix_len + 1) {
+ fprintf(stderr, "empty output file name for [%s] input file\n",
+ PrintablePath(arg));
+ context->iterator_error = BROTLI_TRUE;
+ return BROTLI_FALSE;
+ }
+ name_suffix = name + name_len - suffix_len;
+ if (strcmp(context->suffix, name_suffix) != 0) {
+ fprintf(stderr, "input file [%s] suffix mismatch\n",
+ PrintablePath(arg));
+ context->iterator_error = BROTLI_TRUE;
+ return BROTLI_FALSE;
+ }
+ name_suffix[0] = 0;
+ return BROTLI_TRUE;
+ } else {
+ strcpy(context->modified_path + arg_len, context->suffix);
+ return BROTLI_TRUE;
+ }
+}
+
+static BROTLI_BOOL OpenFiles(Context* context) {
+ BROTLI_BOOL is_ok = OpenInputFile(context->current_input_path, &context->fin);
+ if (!context->test_integrity && is_ok) {
+ is_ok = OpenOutputFile(
+ context->current_output_path, &context->fout, context->force_overwrite);
+ }
+ return is_ok;
+}
+
+static BROTLI_BOOL CloseFiles(Context* context, BROTLI_BOOL success) {
+ BROTLI_BOOL is_ok = BROTLI_TRUE;
+ if (!context->test_integrity && context->fout) {
+ if (!success && context->current_output_path) {
+ unlink(context->current_output_path);
+ }
+ if (fclose(context->fout) != 0) {
+ if (success) {
+ fprintf(stderr, "fclose failed [%s]: %s\n",
+ PrintablePath(context->current_output_path), strerror(errno));
+ }
+ is_ok = BROTLI_FALSE;
+ }
+
+ /* TOCTOU violation, but otherwise it is impossible to set file times. */
+ if (success && is_ok && context->copy_stat) {
+ CopyStat(context->current_input_path, context->current_output_path);
+ }
+ }
+
+ if (context->fin) {
+ if (fclose(context->fin) != 0) {
+ if (is_ok) {
+ fprintf(stderr, "fclose failed [%s]: %s\n",
+ PrintablePath(context->current_input_path), strerror(errno));
+ }
+ is_ok = BROTLI_FALSE;
+ }
+ }
+ if (success && context->junk_source && context->current_input_path) {
+ unlink(context->current_input_path);
+ }
+
+ context->fin = NULL;
+ context->fout = NULL;
+
+ return is_ok;
+}
+
+static const size_t kFileBufferSize = 1 << 19;
+
+static void InitializeBuffers(Context* context) {
+ context->available_in = 0;
+ context->next_in = NULL;
+ context->available_out = kFileBufferSize;
+ context->next_out = context->output;
+ context->total_in = 0;
+ context->total_out = 0;
+}
+
+static BROTLI_BOOL HasMoreInput(Context* context) {
+ return feof(context->fin) ? BROTLI_FALSE : BROTLI_TRUE;
+}
+
+static BROTLI_BOOL ProvideInput(Context* context) {
+ context->available_in =
+ fread(context->input, 1, kFileBufferSize, context->fin);
+ context->total_in += context->available_in;
+ context->next_in = context->input;
+ if (ferror(context->fin)) {
+ fprintf(stderr, "failed to read input [%s]: %s\n",
+ PrintablePath(context->current_input_path), strerror(errno));
+ return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+/* Internal: should be used only in Provide-/Flush-Output. */
+static BROTLI_BOOL WriteOutput(Context* context) {
+ size_t out_size = (size_t)(context->next_out - context->output);
+ context->total_out += out_size;
+ if (out_size == 0) return BROTLI_TRUE;
+ if (context->test_integrity) return BROTLI_TRUE;
+
+ fwrite(context->output, 1, out_size, context->fout);
+ if (ferror(context->fout)) {
+ fprintf(stderr, "failed to write output [%s]: %s\n",
+ PrintablePath(context->current_output_path), strerror(errno));
+ return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+static BROTLI_BOOL ProvideOutput(Context* context) {
+ if (!WriteOutput(context)) return BROTLI_FALSE;
+ context->available_out = kFileBufferSize;
+ context->next_out = context->output;
+ return BROTLI_TRUE;
+}
+
+static BROTLI_BOOL FlushOutput(Context* context) {
+ if (!WriteOutput(context)) return BROTLI_FALSE;
+ context->available_out = 0;
+ return BROTLI_TRUE;
+}
+
+static void PrintBytes(size_t value) {
+ if (value < 1024) {
+ fprintf(stderr, "%d B", (int)value);
+ } else if (value < 1048576) {
+ fprintf(stderr, "%0.3f KiB", (double)value / 1024.0);
+ } else if (value < 1073741824) {
+ fprintf(stderr, "%0.3f MiB", (double)value / 1048576.0);
+ } else {
+ fprintf(stderr, "%0.3f GiB", (double)value / 1073741824.0);
+ }
+}
+
+static void PrintFileProcessingProgress(Context* context) {
+ fprintf(stderr, "[%s]: ", PrintablePath(context->current_input_path));
+ PrintBytes(context->total_in);
+ fprintf(stderr, " -> ");
+ PrintBytes(context->total_out);
+}
+
+static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
+ InitializeBuffers(context);
+ for (;;) {
+ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
+ if (!HasMoreInput(context)) {
+ fprintf(stderr, "corrupt input [%s]\n",
+ PrintablePath(context->current_input_path));
+ return BROTLI_FALSE;
+ }
+ if (!ProvideInput(context)) return BROTLI_FALSE;
+ } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ if (!ProvideOutput(context)) return BROTLI_FALSE;
+ } else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
+ if (!FlushOutput(context)) return BROTLI_FALSE;
+ if (context->available_in != 0 || HasMoreInput(context)) {
+ fprintf(stderr, "corrupt input [%s]\n",
+ PrintablePath(context->current_input_path));
+ return BROTLI_FALSE;
+ }
+ if (context->verbosity > 0) {
+ fprintf(stderr, "Decompressed ");
+ PrintFileProcessingProgress(context);
+ fprintf(stderr, "\n");
+ }
+ return BROTLI_TRUE;
+ } else {
+ fprintf(stderr, "corrupt input [%s]\n",
+ PrintablePath(context->current_input_path));
+ return BROTLI_FALSE;
+ }
+
+ result = BrotliDecoderDecompressStream(s, &context->available_in,
+ &context->next_in, &context->available_out, &context->next_out, 0);
+ }
+}
+
+static BROTLI_BOOL DecompressFiles(Context* context) {
+ while (NextFile(context)) {
+ BROTLI_BOOL is_ok = BROTLI_TRUE;
+ BrotliDecoderState* s = BrotliDecoderCreateInstance(NULL, NULL, NULL);
+ if (!s) {
+ fprintf(stderr, "out of memory\n");
+ return BROTLI_FALSE;
+ }
+ /* This allows decoding "large-window" streams. Though it creates
+ fragmentation (new builds decode streams that old builds don't),
+ it is better from used experience perspective. */
+ BrotliDecoderSetParameter(s, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1u);
+ is_ok = OpenFiles(context);
+ if (is_ok && !context->current_input_path &&
+ !context->force_overwrite && isatty(STDIN_FILENO)) {
+ fprintf(stderr, "Use -h help. Use -f to force input from a terminal.\n");
+ is_ok = BROTLI_FALSE;
+ }
+ if (is_ok) is_ok = DecompressFile(context, s);
+ BrotliDecoderDestroyInstance(s);
+ if (!CloseFiles(context, is_ok)) is_ok = BROTLI_FALSE;
+ if (!is_ok) return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) {
+ BROTLI_BOOL is_eof = BROTLI_FALSE;
+ InitializeBuffers(context);
+ for (;;) {
+ if (context->available_in == 0 && !is_eof) {
+ if (!ProvideInput(context)) return BROTLI_FALSE;
+ is_eof = !HasMoreInput(context);
+ }
+
+ if (!BrotliEncoderCompressStream(s,
+ is_eof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,
+ &context->available_in, &context->next_in,
+ &context->available_out, &context->next_out, NULL)) {
+ /* Should detect OOM? */
+ fprintf(stderr, "failed to compress data [%s]\n",
+ PrintablePath(context->current_input_path));
+ return BROTLI_FALSE;
+ }
+
+ if (context->available_out == 0) {
+ if (!ProvideOutput(context)) return BROTLI_FALSE;
+ }
+
+ if (BrotliEncoderIsFinished(s)) {
+ if (!FlushOutput(context)) return BROTLI_FALSE;
+ if (context->verbosity > 0) {
+ fprintf(stderr, "Compressed ");
+ PrintFileProcessingProgress(context);
+ fprintf(stderr, "\n");
+ }
+ return BROTLI_TRUE;
+ }
+ }
+}
+
+static BROTLI_BOOL CompressFiles(Context* context) {
+ while (NextFile(context)) {
+ BROTLI_BOOL is_ok = BROTLI_TRUE;
+ BrotliEncoderState* s = BrotliEncoderCreateInstance(NULL, NULL, NULL);
+ if (!s) {
+ fprintf(stderr, "out of memory\n");
+ return BROTLI_FALSE;
+ }
+ BrotliEncoderSetParameter(s,
+ BROTLI_PARAM_QUALITY, (uint32_t)context->quality);
+ if (context->lgwin > 0) {
+ /* Specified by user. */
+ /* Do not enable "large-window" extension, if not required. */
+ if (context->lgwin > BROTLI_MAX_WINDOW_BITS) {
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, 1u);
+ }
+ BrotliEncoderSetParameter(s,
+ BROTLI_PARAM_LGWIN, (uint32_t)context->lgwin);
+ } else {
+ /* 0, or not specified by user; could be chosen by compressor. */
+ uint32_t lgwin = DEFAULT_LGWIN;
+ /* Use file size to limit lgwin. */
+ if (context->input_file_length >= 0) {
+ lgwin = BROTLI_MIN_WINDOW_BITS;
+ while (BROTLI_MAX_BACKWARD_LIMIT(lgwin) <
+ (uint64_t)context->input_file_length) {
+ lgwin++;
+ if (lgwin == BROTLI_MAX_WINDOW_BITS) break;
+ }
+ }
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, lgwin);
+ }
+ if (context->input_file_length > 0) {
+ uint32_t size_hint = context->input_file_length < (1 << 30) ?
+ (uint32_t)context->input_file_length : (1u << 30);
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, size_hint);
+ }
+ is_ok = OpenFiles(context);
+ if (is_ok && !context->current_output_path &&
+ !context->force_overwrite && isatty(STDOUT_FILENO)) {
+ fprintf(stderr, "Use -h help. Use -f to force output to a terminal.\n");
+ is_ok = BROTLI_FALSE;
+ }
+ if (is_ok) is_ok = CompressFile(context, s);
+ BrotliEncoderDestroyInstance(s);
+ if (!CloseFiles(context, is_ok)) is_ok = BROTLI_FALSE;
+ if (!is_ok) return BROTLI_FALSE;
+ }
+ return BROTLI_TRUE;
+}
+
+int main(int argc, char** argv) {
+ Command command;
+ Context context;
+ BROTLI_BOOL is_ok = BROTLI_TRUE;
+ int i;
+
+ context.quality = 11;
+ context.lgwin = -1;
+ context.verbosity = 0;
+ context.force_overwrite = BROTLI_FALSE;
+ context.junk_source = BROTLI_FALSE;
+ context.copy_stat = BROTLI_TRUE;
+ context.test_integrity = BROTLI_FALSE;
+ context.write_to_stdout = BROTLI_FALSE;
+ context.decompress = BROTLI_FALSE;
+ context.large_window = BROTLI_FALSE;
+ context.output_path = NULL;
+ context.suffix = DEFAULT_SUFFIX;
+ for (i = 0; i < MAX_OPTIONS; ++i) context.not_input_indices[i] = 0;
+ context.longest_path_len = 1;
+ context.input_count = 0;
+
+ context.argc = argc;
+ context.argv = argv;
+ context.modified_path = NULL;
+ context.iterator = 0;
+ context.ignore = 0;
+ context.iterator_error = BROTLI_FALSE;
+ context.buffer = NULL;
+ context.current_input_path = NULL;
+ context.current_output_path = NULL;
+ context.fin = NULL;
+ context.fout = NULL;
+
+ command = ParseParams(&context);
+
+ if (command == COMMAND_COMPRESS || command == COMMAND_DECOMPRESS ||
+ command == COMMAND_TEST_INTEGRITY) {
+ if (is_ok) {
+ size_t modified_path_len =
+ context.longest_path_len + strlen(context.suffix) + 1;
+ context.modified_path = (char*)malloc(modified_path_len);
+ context.buffer = (uint8_t*)malloc(kFileBufferSize * 2);
+ if (!context.modified_path || !context.buffer) {
+ fprintf(stderr, "out of memory\n");
+ is_ok = BROTLI_FALSE;
+ } else {
+ context.input = context.buffer;
+ context.output = context.buffer + kFileBufferSize;
+ }
+ }
+ }
+
+ if (!is_ok) command = COMMAND_NOOP;
+
+ switch (command) {
+ case COMMAND_NOOP:
+ break;
+
+ case COMMAND_VERSION:
+ PrintVersion();
+ break;
+
+ case COMMAND_COMPRESS:
+ is_ok = CompressFiles(&context);
+ break;
+
+ case COMMAND_DECOMPRESS:
+ case COMMAND_TEST_INTEGRITY:
+ is_ok = DecompressFiles(&context);
+ break;
+
+ case COMMAND_HELP:
+ case COMMAND_INVALID:
+ default:
+ is_ok = (command == COMMAND_HELP);
+ PrintHelp(FileName(argv[0]), is_ok);
+ break;
+ }
+
+ if (context.iterator_error) is_ok = BROTLI_FALSE;
+
+ free(context.modified_path);
+ free(context.buffer);
+
+ if (!is_ok) exit(1);
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.md
new file mode 100644
index 000000000..c029869bc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/c/tools/brotli.md
@@ -0,0 +1,107 @@
+brotli(1) -- brotli, unbrotli - compress or decompress files
+================================================================
+
+SYNOPSIS
+--------
+
+`brotli` [*OPTION|FILE*]...
+
+`unbrotli` is equivalent to `brotli --decompress`
+
+DESCRIPTION
+-----------
+`brotli` is a generic-purpose lossless compression algorithm that compresses
+data using a combination of a modern variant of the **LZ77** algorithm, Huffman
+coding and 2-nd order context modeling, with a compression ratio comparable to
+the best currently available general-purpose compression methods. It is similar
+in speed with deflate but offers more dense compression.
+
+`brotli` command line syntax similar to `gzip (1)` and `zstd (1)`.
+Unlike `gzip (1)`, source files are preserved by default. It is possible to
+remove them after processing by using the `--rm` _option_.
+
+Arguments that look like "`--name`" or "`--name=value`" are _options_. Every
+_option_ has a short form "`-x`" or "`-x value`". Multiple short form _options_
+could be coalesced:
+
+* "`--decompress --stdout --suffix=.b`" works the same as
+* "`-d -s -S .b`" and
+* "`-dsS .b`"
+
+`brotli` has 3 operation modes:
+
+* default mode is compression;
+* `--decompress` option activates decompression mode;
+* `--test` option switches to integrity test mode; this option is equivalent to
+ "`--decompress --stdout`" except that the decompressed data is discarded
+ instead of being written to standard output.
+
+Every non-option argument is a _file_ entry. If no _files_ are given or _file_
+is "`-`", `brotli` reads from standard input. All arguments after "`--`" are
+_file_ entries.
+
+Unless `--stdout` or `--output` is specified, _files_ are written to a new file
+whose name is derived from the source _file_ name:
+
+* when compressing, a suffix is appended to the source filename to
+ get the target filename
+* when decompressing, a suffix is removed from the source filename to
+ get the target filename
+
+Default suffix is `.br`, but it could be specified with `--suffix` option.
+
+Conflicting or duplicate _options_ are not allowed.
+
+OPTIONS
+-------
+
+* `-#`:
+ compression level (0-9); bigger values cause denser, but slower compression
+* `-c`, `--stdout`:
+ write on standard output
+* `-d`, `--decompress`:
+ decompress mode
+* `-f`, `--force`:
+ force output file overwrite
+* `-h`, `--help`:
+ display this help and exit
+* `-j`, `--rm`:
+ remove source file(s); `gzip (1)`-like behaviour
+* `-k`, `--keep`:
+ keep source file(s); `zstd (1)`-like behaviour
+* `-n`, `--no-copy-stat`:
+ do not copy source file(s) attributes
+* `-o FILE`, `--output=FILE`
+ output file; valid only if there is a single input entry
+* `-q NUM`, `--quality=NUM`:
+ compression level (0-11); bigger values cause denser, but slower compression
+* `-t`, `--test`:
+ test file integrity mode
+* `-v`, `--verbose`:
+ increase output verbosity
+* `-w NUM`, `--lgwin=NUM`:
+ set LZ77 window size (0, 10-24) (default: 22); window size is
+ `(2**NUM - 16)`; 0 lets compressor decide over the optimal value; bigger
+ windows size improve density; decoder might require up to window size
+ memory to operate
+* `-S SUF`, `--suffix=SUF`:
+ output file suffix (default: `.br`)
+* `-V`, `--version`:
+ display version and exit
+* `-Z`, `--best`:
+ use best compression level (default); same as "`-q 11`"
+
+SEE ALSO
+--------
+
+`brotli` file format is defined in
+[RFC 7932](https://www.ietf.org/rfc/rfc7932.txt).
+
+`brotli` is open-sourced under the
+[MIT License](https://opensource.org/licenses/MIT).
+
+Mailing list: https://groups.google.com/forum/#!forum/brotli
+
+BUGS
+----
+Report bugs at: https://github.com/google/brotli/issues
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/compiler_config_setting.bzl b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/compiler_config_setting.bzl
new file mode 100755
index 000000000..572032bf7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/compiler_config_setting.bzl
@@ -0,0 +1,28 @@
+# Copyright 2018 Google Inc. All Rights Reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+"""Creates config_setting that allows selecting based on 'compiler' value."""
+
+def create_msvc_config():
+ # The "do_not_use_tools_cpp_compiler_present" attribute exists to
+ # distinguish between older versions of Bazel that do not support
+ # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
+ # In the future, the only way to select on the compiler will be through
+ # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
+ # be removed.
+ if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
+ native.config_setting(
+ name = "msvc",
+ flag_values = {
+ "@bazel_tools//tools/cpp:compiler": "msvc-cl",
+ },
+ visibility = ["//visibility:public"],
+ )
+ else:
+ native.config_setting(
+ name = "msvc",
+ values = {"compiler": "msvc-cl"},
+ visibility = ["//visibility:public"],
+ )
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure
new file mode 100755
index 000000000..d96129a44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+echo "Use Autotools, Bazel, CMake or Premake5 to generate projects / build files."
+echo " Bazel: http://www.bazel.build/"
+echo " CMake: https://cmake.org/"
+echo " Premake5: https://premake.github.io/"
+echo "To generate Autotools 'configure' file run './bootstrap'."
+echo "Run './configure-cmake' for Autotools-like CMake configuration."
+echo "Or simply run 'make' to build and test command line tool."
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure-cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure-cmake
new file mode 100755
index 000000000..6dfb92c4e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure-cmake
@@ -0,0 +1,318 @@
+#!/usr/bin/env bash
+
+# Autotools-style (./configure) wrapper for CMake
+# <https://github.com/nemequ/configure-cmake>
+#
+# *** IMPORTANT ***
+#
+# You must include the GNUInstallDirs module (which comes with
+# CMake) in your project. Just put "include (GNUInstallDirs)" in
+# you CMakeLists.txt and you should be good.
+#
+# This script was originally written for Squash
+# <https://quixdb.github.io/squash/> by Evan Nemerson
+# <evan@nemerson.com>, but has been spun off into a separate
+# repository. Please feel free to copy it into your own repository,
+# though I would appreciate it if you would post improvements, bugs,
+# feature requests, etc. to the issue tracker at
+# <https://github.com/nemequ/configure-cmake/issues>.
+#
+# To the extent possible under law, the author(s) hereby waive all
+# copyright and related or neighboring rights to this work. For
+# details, see <https://creativecommons.org/publicdomain/zero/1.0/>
+
+TOP_SRCDIR="$(dirname $0)"
+
+if [ "${CMAKE_CMD}" = "" ]; then
+ CMAKE_CMD="cmake"
+fi
+
+BUILD_TYPE="Debug"
+PREFIX=/usr/local
+LIBDIR=
+CMAKE_ARGS=
+
+if [ -e "${TOP_SRCDIR}/scripts/.configure-custom.sh" ]; then
+ . "${TOP_SRCDIR}/scripts/.configure-custom.sh"
+fi
+
+quote() {
+ echo "$1" | sed -e "s|'|'\\\\''|g; 1s/^/'/; \$s/\$/'/"
+}
+
+extract_var_string() {
+ VAR_NAME=$1
+ VAR_NAME=$(echo $1 | sed -e 's/[ \t]*$//')
+ if [ "x$2" != "x" ]; then
+ VAR_VALUE=$2
+ else
+ VAR_VALUE=yes
+ fi
+
+ if [ "x$3" != "x" ]; then
+ VAR_UC_NAME=$3
+ else
+ VAR_UC_NAME=$(echo "$1" | tr '[:lower:]' '[:upper:]' | tr -c '[:alnum:]' '_' | sed 's/_$//g')
+ fi
+}
+
+set_config_var() {
+ is_with=n
+ case "$1" in
+ "--enable-"*)
+ name="${1#--enable-}"
+ cfg="${ENABLE_VARS}"
+ ;;
+ "--disable-"*)
+ name="${1#--disable-}";
+ cfg="${DISABLE_VARS}";
+ ;;
+ "--with-"*)
+ # IFS="=" read -ra WITHARGS <<< "${1}"
+ name="${1#--with-}"
+ cfg="${WITH_VARS}"
+ is_with=y
+ ;;
+ esac
+
+ found=n
+ for varstring in $cfg; do
+ extract_var_string $(echo "${varstring}" | tr '|' ' ')
+ if [ "x$VAR_NAME" = "x$name" ]; then
+ found=y
+ break;
+ fi
+ done
+
+ if [ "$found" = "y" ]; then
+ if [ "x$is_with" = "xy" ]; then
+ CMAKE_ARGS="$CMAKE_ARGS -D${VAR_UC_NAME}=$(quote "$2")"
+ else
+ CMAKE_ARGS="$CMAKE_ARGS -D${VAR_UC_NAME}=$(quote "${VAR_VALUE}")"
+ fi
+ else
+ echo "Unknown parameter: ${1}"
+ exit 1
+ fi
+}
+
+prefix_to_offset() {
+ expr $(echo "${1}" | awk '{ print length }') + 1
+}
+
+print_help() {
+ cat <<EOF >&2
+ -h, --help display this help and exit
+ --disable-debug disable debugging mode
+ --pass-thru pass remaining arguments through to CMake
+
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$PREFIX]
+ --bindir=DIR user executables [PREFIX/bin]
+ --sbindir=DIR system admin executables [PREFIX/sbin]
+ --libexecdir=DIR program executables [PREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [PREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PROJECT_NAME]
+EOF
+
+ first=y
+ for varstring in ${ENABLE_VARS}; do
+ if [ $first = 'y' ]; then
+ echo ""
+ first=n
+ fi
+ extract_var_string $(echo "${varstring}" | tr '|' ' ')
+ var_doc_name="ENABLE_${VAR_UC_NAME}_DOC"
+ eval "docstring=\$$var_doc_name"
+ if [ "x${docstring}" = "x" ]; then
+ printf " --enable-%-14s enable %s support\n" "${VAR_NAME}" "$(echo -n "${VAR_NAME}" | tr '-' ' ')"
+ else
+ printf " --enable-%-14s %s\n" "${VAR_NAME}" "$docstring"
+ fi
+ done
+
+ first=y
+ for varstring in ${DISABLE_VARS}; do
+ if [ $first = 'y' ]; then
+ echo ""
+ first=n
+ fi
+ extract_var_string $(echo "${varstring}" | tr '|' ' ')
+ var_doc_name="DISABLE_${VAR_UC_NAME}_DOC"
+ eval "docstring=\$$var_doc_name"
+ if [ "x${docstring}" = "x" ]; then
+ printf " --disable-%-13s disable %s support\n" "${VAR_NAME}" "$(echo -n "${VAR_NAME}" | tr '-' ' ')"
+ else
+ printf " --disable-%-13s %s\n" "${VAR_NAME}" "$docstring"
+ fi
+ done
+
+ first=y
+ for varstring in ${WITH_VARS}; do
+ if [ $first = 'y' ]; then
+ echo ""
+ first=n
+ fi
+ extract_var_string $(echo "${varstring}" | tr '|' ' ')
+ var_doc_name="WITH_${VAR_UC_NAME}_DOC"
+ eval "docstring=\$$var_doc_name"
+ paraminfo="${VAR_NAME}=${VAR_VALUE}"
+ if [ "x${docstring}" = "x" ]; then
+ printf " --with-%-16s enable %s support\n" "$paraminfo" "$(echo -n "${VAR_NAME}" | tr '-' ' ')"
+ else
+ printf " --with-%-16s %s\n" "$paraminfo" "$docstring"
+ fi
+ done
+
+ exit 0
+}
+
+while [ $# != 0 ]; do
+ case "$1" in
+ "--prefix="*)
+ PREFIX="${1#*=}";;
+ "--prefix")
+ PREFIX="${2}"; shift;;
+ "--bindir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_BINDIR=$(quote "${1#*=}")";;
+ "--bindir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_BINDIR=$(quote "$2")"; shift;;
+ "--sbindir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SBINDIR=$(quote "${1#*=}")";;
+ "--sbindir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SBINDIR=$(quote "$2")"; shift;;
+ "--libexecdir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LIBEXECDIR=$(quote "${1#*=}")";;
+ "--libexecdir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LIBEXECDIR=$(quote "$2")"; shift;;
+ "--sysconfdir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SYSCONFDIR=$(quote "${1#*=}")";;
+ "--sysconfdir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SYSCONFDIR=$(quote "$2")"; shift;;
+ "--sharedstatedir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SHAREDSTATEDIR=$(quote "${1#*=}")";;
+ "--sharedstatedir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_SHAREDSTATEDIR=$(quote "$2")"; shift;;
+ "--localstatedir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LOCALSTATEDIR=$(quote "${1#*=}")";;
+ "--localstatedir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LOCALSTATEDIR=$(quote "$2")"; shift;;
+ "--libdir="*)
+ LIBDIR="${1#*=}";;
+ "--libdir")
+ LIBDIR="${2}"; shift;;
+ "--includedir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_INCLUDEDIR=$(quote "${1#*=}")";;
+ "--includedir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_INCLUDEDIR=$(quote "$2")"; shift;;
+ "--oldincludedir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_OLDINCLUDEDIR=$(quote "${1#*=}")";;
+ "--oldincludedir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_OLDINCLUDEDIR=$(quote "$2")"; shift;;
+ "--datarootdir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DATAROOTDIR=$(quote "${1#*=}")";;
+ "--datarootdir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DATAROOTDIR=$(quote "$2")"; shift;;
+ "--datadir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DATADIR=$(quote "${1#*=}")";;
+ "--datadir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DATADIR=$(quote "$2")"; shift;;
+ "--infodir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_INFODIR=$(quote "${1#*=}")";;
+ "--infodir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_INFODIR=$(quote "$2")"; shift;;
+ "--localedir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LOCALEDIR=$(quote "${1#*=}")";;
+ "--localedir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_LOCALEDIR=$(quote "$2")"; shift;;
+ "--mandir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_MANDIR=$(quote "${1#*=}")";;
+ "--mandir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_MANDIR=$(quote "$2")"; shift;;
+ "--docdir="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DOCDIR=$(quote "${1#*=}")";;
+ "--docdir")
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DOCDIR=$(quote "$2")"; shift;;
+
+ "CC="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_COMPILER=$(quote "${1#*=}")";;
+ "CXX="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_COMPILER=$(quote "${1#*=}")";;
+ "CFLAGS="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_FLAGS=$(quote "${1#*=}")";;
+ "CXXFLAGS="*)
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_FLAGS=$(quote "${1#*=}")";;
+ "LDFLAGS="*)
+ LDFLAGS="$LDFLAGS ${1#*=}";;
+
+ "--help")
+ print_help;;
+ "-h")
+ print_help;;
+
+ # This flag is the only one which may be a bit surprising to
+ # people. Autotools always builds with debugging symbols enabled
+ # (AFAIK), but for cmake you have to do -DCMAKE_BUILD_TYPE=Debug.
+ # Unfortunately this can change other things as well, so although
+ # I realize there is no --disable-debug flag I thought it would be
+ # prudent to support one here.
+ "--disable-debug")
+ BUILD_TYPE="Release";;
+
+ "--pass-thru")
+ shift;
+ while [ $# != 0 ]; do
+ CMAKE_ARGS="$CMAKE_ARGS $(quote "${1}")";
+ shift;
+ done;;
+
+ "--enable-"*)
+ set_config_var "$1"
+ ;;
+
+ "--disable-"*)
+ set_config_var "$1"
+ ;;
+
+ "--with-"*)
+ name=$(echo "${1#--with-}" | awk '{split($1,v,"="); print v[1]}')
+ case "${1}" in
+ "--with-${name}="*)
+ set_config_var "--with-${name}" "${1#--with-${name}=}";;
+ "--with-${name}")
+ set_config_var "$1" "$2";
+ shift;;
+ esac
+ ;;
+
+ *)
+ echo "$0: error: unrecognized option: \`$1'" >&2
+ echo "Try \`$0 --help' for more information" >&2
+ exit -1
+ esac;
+ shift
+done
+
+if [ "x${LIBDIR}" = "x" ]; then
+ LIBDIR="${PREFIX}/lib"
+fi
+
+# Unlike CFLAGS/CXXFLAGS/CC/CXX, LDFLAGS isn't handled by CMake, so we
+# need to parse it here.
+if [ "x${LDFLAGS}" != "x" ]; then
+ for varname in EXE MODULE SHARED STATIC; do
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_${varname}_LINKER_FLAGS=$(quote "$LDFLAGS")"
+ done
+fi
+
+eval "${CMAKE_CMD}" "${TOP_SRCDIR}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DCMAKE_INSTALL_LIBDIR="${LIBDIR}" ${CMAKE_ARGS}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure.ac b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure.ac
new file mode 100644
index 000000000..87d579d45
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/configure.ac
@@ -0,0 +1,14 @@
+AC_PREREQ(2.57)
+
+dnl Actual version is substituted by bootstrap
+AC_INIT([brotli], [0.0.0], [https://groups.google.com/forum/#!forum/brotli])
+
+AM_INIT_AUTOMAKE()
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_PROG_CC
+LT_INIT
+
+AC_CONFIG_FILES([Makefile scripts/libbrotlicommon.pc scripts/libbrotlidec.pc scripts/libbrotlienc.pc])
+
+AC_OUTPUT \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/injected_code.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/injected_code.txt
new file mode 100644
index 000000000..64f129b0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/injected_code.txt
@@ -0,0 +1,32 @@
+// <{[INJECTED CODE]}>
+ public override bool CanRead {
+ get {return true;}
+ }
+
+ public override bool CanSeek {
+ get {return false;}
+ }
+ public override long Length {
+ get {throw new System.NotSupportedException();}
+ }
+ public override long Position {
+ get {throw new System.NotSupportedException();}
+ set {throw new System.NotSupportedException();}
+ }
+ public override long Seek(long offset, System.IO.SeekOrigin origin) {
+ throw new System.NotSupportedException();
+ }
+ public override void SetLength(long value){
+ throw new System.NotSupportedException();
+ }
+
+ public override bool CanWrite{get{return false;}}
+ public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
+ int count, System.AsyncCallback callback, object state) {
+ throw new System.NotSupportedException();
+ }
+ public override void Write(byte[] buffer, int offset, int count) {
+ throw new System.NotSupportedException();
+ }
+
+ public override void Flush() {}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReader.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReader.cs
new file mode 100644
index 000000000..d3f1a3fff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReader.cs
@@ -0,0 +1,271 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Bit reading helpers.</summary>
+ internal sealed class BitReader
+ {
+ /// <summary>
+ /// Input byte buffer, consist of a ring-buffer and a "slack" region where bytes from the start of
+ /// the ring-buffer are copied.
+ /// </summary>
+ private const int Capacity = 1024;
+
+ private const int Slack = 16;
+
+ private const int IntBufferSize = Capacity + Slack;
+
+ private const int ByteReadSize = Capacity << 2;
+
+ private const int ByteBufferSize = IntBufferSize << 2;
+
+ private readonly byte[] byteBuffer = new byte[ByteBufferSize];
+
+ private readonly int[] intBuffer = new int[IntBufferSize];
+
+ private readonly Org.Brotli.Dec.IntReader intReader = new Org.Brotli.Dec.IntReader();
+
+ private System.IO.Stream input;
+
+ /// <summary>Input stream is finished.</summary>
+ private bool endOfStreamReached;
+
+ /// <summary>Pre-fetched bits.</summary>
+ internal long accumulator;
+
+ /// <summary>Current bit-reading position in accumulator.</summary>
+ internal int bitOffset;
+
+ /// <summary>Offset of next item in intBuffer.</summary>
+ private int intOffset;
+
+ private int tailBytes = 0;
+
+ /* Number of bytes in unfinished "int" item. */
+ /// <summary>Fills up the input buffer.</summary>
+ /// <remarks>
+ /// Fills up the input buffer.
+ /// <p> No-op if there are at least 36 bytes present after current position.
+ /// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
+ /// buffer.
+ /// </remarks>
+ internal static void ReadMoreInput(Org.Brotli.Dec.BitReader br)
+ {
+ // TODO: Split to check and read; move read outside of decoding loop.
+ if (br.intOffset <= Capacity - 9)
+ {
+ return;
+ }
+ if (br.endOfStreamReached)
+ {
+ if (IntAvailable(br) >= -2)
+ {
+ return;
+ }
+ throw new Org.Brotli.Dec.BrotliRuntimeException("No more input");
+ }
+ int readOffset = br.intOffset << 2;
+ int bytesRead = ByteReadSize - readOffset;
+ System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
+ br.intOffset = 0;
+ try
+ {
+ while (bytesRead < ByteReadSize)
+ {
+ int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
+ // EOF is -1 in Java, but 0 in C#.
+ if (len <= 0)
+ {
+ br.endOfStreamReached = true;
+ br.tailBytes = bytesRead;
+ bytesRead += 3;
+ break;
+ }
+ bytesRead += len;
+ }
+ }
+ catch (System.IO.IOException e)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
+ }
+ Org.Brotli.Dec.IntReader.Convert(br.intReader, bytesRead >> 2);
+ }
+
+ internal static void CheckHealth(Org.Brotli.Dec.BitReader br, bool endOfStream)
+ {
+ if (!br.endOfStreamReached)
+ {
+ return;
+ }
+ int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;
+ if (byteOffset > br.tailBytes)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Read after end");
+ }
+ if (endOfStream && (byteOffset != br.tailBytes))
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unused bytes after end");
+ }
+ }
+
+ /// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
+ internal static void FillBitWindow(Org.Brotli.Dec.BitReader br)
+ {
+ if (br.bitOffset >= 32)
+ {
+ br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
+ br.bitOffset -= 32;
+ }
+ }
+
+ /// <summary>Reads the specified number of bits from Read Buffer.</summary>
+ internal static int ReadBits(Org.Brotli.Dec.BitReader br, int n)
+ {
+ FillBitWindow(br);
+ int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);
+ br.bitOffset += n;
+ return val;
+ }
+
+ /// <summary>Initialize bit reader.</summary>
+ /// <remarks>
+ /// Initialize bit reader.
+ /// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
+ /// accumulator. Because of that this method may block until enough data could be read from input.
+ /// </remarks>
+ /// <param name="br">BitReader POJO</param>
+ /// <param name="input">data source</param>
+ internal static void Init(Org.Brotli.Dec.BitReader br, System.IO.Stream input)
+ {
+ if (br.input != null)
+ {
+ throw new System.InvalidOperationException("Bit reader already has associated input stream");
+ }
+ Org.Brotli.Dec.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
+ br.input = input;
+ br.accumulator = 0;
+ br.bitOffset = 64;
+ br.intOffset = Capacity;
+ br.endOfStreamReached = false;
+ Prepare(br);
+ }
+
+ private static void Prepare(Org.Brotli.Dec.BitReader br)
+ {
+ ReadMoreInput(br);
+ CheckHealth(br, false);
+ FillBitWindow(br);
+ FillBitWindow(br);
+ }
+
+ internal static void Reload(Org.Brotli.Dec.BitReader br)
+ {
+ if (br.bitOffset == 64)
+ {
+ Prepare(br);
+ }
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ internal static void Close(Org.Brotli.Dec.BitReader br)
+ {
+ System.IO.Stream @is = br.input;
+ br.input = null;
+ if (@is != null)
+ {
+ @is.Close();
+ }
+ }
+
+ internal static void JumpToByteBoundary(Org.Brotli.Dec.BitReader br)
+ {
+ int padding = (64 - br.bitOffset) & 7;
+ if (padding != 0)
+ {
+ int paddingBits = Org.Brotli.Dec.BitReader.ReadBits(br, padding);
+ if (paddingBits != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted padding bits");
+ }
+ }
+ }
+
+ internal static int IntAvailable(Org.Brotli.Dec.BitReader br)
+ {
+ int limit = Capacity;
+ if (br.endOfStreamReached)
+ {
+ limit = (br.tailBytes + 3) >> 2;
+ }
+ return limit - br.intOffset;
+ }
+
+ internal static void CopyBytes(Org.Brotli.Dec.BitReader br, byte[] data, int offset, int length)
+ {
+ if ((br.bitOffset & 7) != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unaligned copyBytes");
+ }
+ // Drain accumulator.
+ while ((br.bitOffset != 64) && (length != 0))
+ {
+ data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
+ br.bitOffset += 8;
+ length--;
+ }
+ if (length == 0)
+ {
+ return;
+ }
+ // Get data from shadow buffer with "sizeof(int)" granularity.
+ int copyInts = System.Math.Min(IntAvailable(br), length >> 2);
+ if (copyInts > 0)
+ {
+ int readOffset = br.intOffset << 2;
+ System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
+ offset += copyInts << 2;
+ length -= copyInts << 2;
+ br.intOffset += copyInts;
+ }
+ if (length == 0)
+ {
+ return;
+ }
+ // Read tail bytes.
+ if (IntAvailable(br) > 0)
+ {
+ // length = 1..3
+ FillBitWindow(br);
+ while (length != 0)
+ {
+ data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
+ br.bitOffset += 8;
+ length--;
+ }
+ CheckHealth(br, false);
+ return;
+ }
+ // Now it is possible to copy bytes directly.
+ try
+ {
+ while (length > 0)
+ {
+ int len = br.input.Read(data, offset, length);
+ if (len == -1)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected end of input");
+ }
+ offset += len;
+ length -= len;
+ }
+ }
+ catch (System.IO.IOException e)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReaderTest.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReaderTest.cs
new file mode 100644
index 000000000..c5403edf7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BitReaderTest.cs
@@ -0,0 +1,33 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// Tests for
+ /// <see cref="BitReader"/>
+ /// .
+ /// </summary>
+ public class BitReaderTest
+ {
+ [NUnit.Framework.Test]
+ public virtual void TestReadAfterEos()
+ {
+ Org.Brotli.Dec.BitReader reader = new Org.Brotli.Dec.BitReader();
+ Org.Brotli.Dec.BitReader.Init(reader, new System.IO.MemoryStream(new byte[1]));
+ Org.Brotli.Dec.BitReader.ReadBits(reader, 9);
+ try
+ {
+ Org.Brotli.Dec.BitReader.CheckHealth(reader, false);
+ }
+ catch (Org.Brotli.Dec.BrotliRuntimeException)
+ {
+ // This exception is expected.
+ return;
+ }
+ NUnit.Framework.Assert.Fail("BrotliRuntimeException should have been thrown by BitReader.checkHealth");
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliInputStream.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliInputStream.cs
new file mode 100644
index 000000000..36f8128ea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliInputStream.cs
@@ -0,0 +1,223 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// <see cref="System.IO.Stream"/>
+ /// decorator that decompresses brotli data.
+ /// <p> Not thread-safe.
+ /// </summary>
+ public class BrotliInputStream : System.IO.Stream
+ {
+ public const int DefaultInternalBufferSize = 16384;
+
+ /// <summary>Internal buffer used for efficient byte-by-byte reading.</summary>
+ private byte[] buffer;
+
+ /// <summary>Number of decoded but still unused bytes in internal buffer.</summary>
+ private int remainingBufferBytes;
+
+ /// <summary>Next unused byte offset.</summary>
+ private int bufferOffset;
+
+ /// <summary>Decoder state.</summary>
+ private readonly Org.Brotli.Dec.State state = new Org.Brotli.Dec.State();
+
+ /// <summary>
+ /// Creates a
+ /// <see cref="System.IO.Stream"/>
+ /// wrapper that decompresses brotli data.
+ /// <p> For byte-by-byte reading (
+ /// <see cref="ReadByte()"/>
+ /// ) internal buffer with
+ /// <see cref="DefaultInternalBufferSize"/>
+ /// size is allocated and used.
+ /// <p> Will block the thread until first kilobyte of data of source is available.
+ /// </summary>
+ /// <param name="source">underlying data source</param>
+ /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
+ public BrotliInputStream(System.IO.Stream source)
+ : this(source, DefaultInternalBufferSize, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates a
+ /// <see cref="System.IO.Stream"/>
+ /// wrapper that decompresses brotli data.
+ /// <p> For byte-by-byte reading (
+ /// <see cref="ReadByte()"/>
+ /// ) internal buffer of specified size is
+ /// allocated and used.
+ /// <p> Will block the thread until first kilobyte of data of source is available.
+ /// </summary>
+ /// <param name="source">compressed data source</param>
+ /// <param name="byteReadBufferSize">
+ /// size of internal buffer used in case of
+ /// byte-by-byte reading
+ /// </param>
+ /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
+ public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize)
+ : this(source, byteReadBufferSize, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates a
+ /// <see cref="System.IO.Stream"/>
+ /// wrapper that decompresses brotli data.
+ /// <p> For byte-by-byte reading (
+ /// <see cref="ReadByte()"/>
+ /// ) internal buffer of specified size is
+ /// allocated and used.
+ /// <p> Will block the thread until first kilobyte of data of source is available.
+ /// </summary>
+ /// <param name="source">compressed data source</param>
+ /// <param name="byteReadBufferSize">
+ /// size of internal buffer used in case of
+ /// byte-by-byte reading
+ /// </param>
+ /// <param name="customDictionary">
+ /// custom dictionary data;
+ /// <see langword="null"/>
+ /// if not used
+ /// </param>
+ /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
+ public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize, byte[] customDictionary)
+ {
+ if (byteReadBufferSize <= 0)
+ {
+ throw new System.ArgumentException("Bad buffer size:" + byteReadBufferSize);
+ }
+ else if (source == null)
+ {
+ throw new System.ArgumentException("source is null");
+ }
+ this.buffer = new byte[byteReadBufferSize];
+ this.remainingBufferBytes = 0;
+ this.bufferOffset = 0;
+ try
+ {
+ Org.Brotli.Dec.State.SetInput(state, source);
+ }
+ catch (Org.Brotli.Dec.BrotliRuntimeException ex)
+ {
+ throw new System.IO.IOException("Brotli decoder initialization failed", ex);
+ }
+ if (customDictionary != null)
+ {
+ Org.Brotli.Dec.Decode.SetCustomDictionary(state, customDictionary);
+ }
+ }
+
+ /// <summary><inheritDoc/></summary>
+ /// <exception cref="System.IO.IOException"/>
+ public override void Close()
+ {
+ Org.Brotli.Dec.State.Close(state);
+ }
+
+ /// <summary><inheritDoc/></summary>
+ /// <exception cref="System.IO.IOException"/>
+ public override int ReadByte()
+ {
+ if (bufferOffset >= remainingBufferBytes)
+ {
+ remainingBufferBytes = Read(buffer, 0, buffer.Length);
+ bufferOffset = 0;
+ if (remainingBufferBytes == -1)
+ {
+ return -1;
+ }
+ }
+ return buffer[bufferOffset++] & unchecked((int)(0xFF));
+ }
+
+ /// <summary><inheritDoc/></summary>
+ /// <exception cref="System.IO.IOException"/>
+ public override int Read(byte[] destBuffer, int destOffset, int destLen)
+ {
+ if (destOffset < 0)
+ {
+ throw new System.ArgumentException("Bad offset: " + destOffset);
+ }
+ else if (destLen < 0)
+ {
+ throw new System.ArgumentException("Bad length: " + destLen);
+ }
+ else if (destOffset + destLen > destBuffer.Length)
+ {
+ throw new System.ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length);
+ }
+ else if (destLen == 0)
+ {
+ return 0;
+ }
+ int copyLen = System.Math.Max(remainingBufferBytes - bufferOffset, 0);
+ if (copyLen != 0)
+ {
+ copyLen = System.Math.Min(copyLen, destLen);
+ System.Array.Copy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
+ bufferOffset += copyLen;
+ destOffset += copyLen;
+ destLen -= copyLen;
+ if (destLen == 0)
+ {
+ return copyLen;
+ }
+ }
+ try
+ {
+ state.output = destBuffer;
+ state.outputOffset = destOffset;
+ state.outputLength = destLen;
+ state.outputUsed = 0;
+ Org.Brotli.Dec.Decode.Decompress(state);
+ if (state.outputUsed == 0)
+ {
+ return -1;
+ }
+ return state.outputUsed + copyLen;
+ }
+ catch (Org.Brotli.Dec.BrotliRuntimeException ex)
+ {
+ throw new System.IO.IOException("Brotli stream decoding failed", ex);
+ }
+ }
+ // <{[INJECTED CODE]}>
+ public override bool CanRead {
+ get {return true;}
+ }
+
+ public override bool CanSeek {
+ get {return false;}
+ }
+ public override long Length {
+ get {throw new System.NotSupportedException();}
+ }
+ public override long Position {
+ get {throw new System.NotSupportedException();}
+ set {throw new System.NotSupportedException();}
+ }
+ public override long Seek(long offset, System.IO.SeekOrigin origin) {
+ throw new System.NotSupportedException();
+ }
+ public override void SetLength(long value){
+ throw new System.NotSupportedException();
+ }
+
+ public override bool CanWrite{get{return false;}}
+ public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
+ int count, System.AsyncCallback callback, object state) {
+ throw new System.NotSupportedException();
+ }
+ public override void Write(byte[] buffer, int offset, int count) {
+ throw new System.NotSupportedException();
+ }
+
+ public override void Flush() {}
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliRuntimeException.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliRuntimeException.cs
new file mode 100644
index 000000000..1e0aef083
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/BrotliRuntimeException.cs
@@ -0,0 +1,22 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Unchecked exception used internally.</summary>
+ [System.Serializable]
+ internal class BrotliRuntimeException : System.Exception
+ {
+ internal BrotliRuntimeException(string message)
+ : base(message)
+ {
+ }
+
+ internal BrotliRuntimeException(string message, System.Exception cause)
+ : base(message, cause)
+ {
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Context.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Context.cs
new file mode 100644
index 000000000..ad900e490
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Context.cs
@@ -0,0 +1,57 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Common context lookup table for all context modes.</summary>
+ internal sealed class Context
+ {
+ internal static readonly int[] Lookup = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 44, 44, 44, 44, 44, 44, 44, 44
+ , 44, 44, 32, 32, 24, 40, 28, 12, 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 60, 60, 60, 60
+ , 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
+ , 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
+ , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54,
+ 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ internal static readonly int[] LookupOffsets = new int[] { 1024, 1536, 1280, 1536, 0, 256, 768, 512 };
+ // CONTEXT_UTF8, last byte.
+ // ASCII range.
+ // UTF8 continuation byte range.
+ // UTF8 lead byte range.
+ // CONTEXT_UTF8 second last byte.
+ // ASCII range.
+ // UTF8 continuation byte range.
+ // UTF8 lead byte range.
+ // CONTEXT_SIGNED, second last byte.
+ // CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits.
+ // CONTEXT_LSB6, last byte.
+ // CONTEXT_MSB6, last byte.
+ // CONTEXT_{M,L}SB6, second last byte,
+ // CONTEXT_LSB6
+ // CONTEXT_MSB6
+ // CONTEXT_UTF8
+ // CONTEXT_SIGNED
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Decode.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Decode.cs
new file mode 100644
index 000000000..bdc8709ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Decode.cs
@@ -0,0 +1,992 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>API for Brotli decompression.</summary>
+ internal sealed class Decode
+ {
+ private const int DefaultCodeLength = 8;
+
+ private const int CodeLengthRepeatCode = 16;
+
+ private const int NumLiteralCodes = 256;
+
+ private const int NumInsertAndCopyCodes = 704;
+
+ private const int NumBlockLengthCodes = 26;
+
+ private const int LiteralContextBits = 6;
+
+ private const int DistanceContextBits = 2;
+
+ private const int HuffmanTableBits = 8;
+
+ private const int HuffmanTableMask = unchecked((int)(0xFF));
+
+ private const int CodeLengthCodes = 18;
+
+ private static readonly int[] CodeLengthCodeOrder = new int[] { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+ private const int NumDistanceShortCodes = 16;
+
+ private static readonly int[] DistanceShortCodeIndexOffset = new int[] { 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
+
+ private static readonly int[] DistanceShortCodeValueOffset = new int[] { 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 };
+
+ /// <summary>Static Huffman code for the code length code lengths.</summary>
+ private static readonly int[] FixedTable = new int[] { unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003
+ )), unchecked((int)(0x040001)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int
+ )(0x040005)) };
+
+ /// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
+ private static int DecodeVarLenUnsignedByte(Org.Brotli.Dec.BitReader br)
+ {
+ if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
+ {
+ int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
+ if (n == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return Org.Brotli.Dec.BitReader.ReadBits(br, n) + (1 << n);
+ }
+ }
+ return 0;
+ }
+
+ private static void DecodeMetaBlockLength(Org.Brotli.Dec.BitReader br, Org.Brotli.Dec.State state)
+ {
+ state.inputEnd = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
+ state.metaBlockLength = 0;
+ state.isUncompressed = false;
+ state.isMetadata = false;
+ if (state.inputEnd && Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
+ {
+ return;
+ }
+ int sizeNibbles = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 4;
+ if (sizeNibbles == 7)
+ {
+ state.isMetadata = true;
+ if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted reserved bit");
+ }
+ int sizeBytes = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
+ if (sizeBytes == 0)
+ {
+ return;
+ }
+ for (int i = 0; i < sizeBytes; i++)
+ {
+ int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 8);
+ if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
+ }
+ state.metaBlockLength |= bits << (i * 8);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < sizeNibbles; i++)
+ {
+ int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 4);
+ if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
+ }
+ state.metaBlockLength |= bits << (i * 4);
+ }
+ }
+ state.metaBlockLength++;
+ if (!state.inputEnd)
+ {
+ state.isUncompressed = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
+ }
+ }
+
+ /// <summary>Decodes the next Huffman code from bit-stream.</summary>
+ private static int ReadSymbol(int[] table, int offset, Org.Brotli.Dec.BitReader br)
+ {
+ int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));
+ offset += val & HuffmanTableMask;
+ int bits = table[offset] >> 16;
+ int sym = table[offset] & unchecked((int)(0xFFFF));
+ if (bits <= HuffmanTableBits)
+ {
+ br.bitOffset += bits;
+ return sym;
+ }
+ offset += sym;
+ int mask = (1 << bits) - 1;
+ offset += (int)(((uint)(val & mask)) >> HuffmanTableBits);
+ br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
+ return table[offset] & unchecked((int)(0xFFFF));
+ }
+
+ private static int ReadBlockLength(int[] table, int offset, Org.Brotli.Dec.BitReader br)
+ {
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int code = ReadSymbol(table, offset, br);
+ int n = Org.Brotli.Dec.Prefix.BlockLengthNBits[code];
+ return Org.Brotli.Dec.Prefix.BlockLengthOffset[code] + Org.Brotli.Dec.BitReader.ReadBits(br, n);
+ }
+
+ private static int TranslateShortCodes(int code, int[] ringBuffer, int index)
+ {
+ if (code < NumDistanceShortCodes)
+ {
+ index += DistanceShortCodeIndexOffset[code];
+ index &= 3;
+ return ringBuffer[index] + DistanceShortCodeValueOffset[code];
+ }
+ return code - NumDistanceShortCodes + 1;
+ }
+
+ private static void MoveToFront(int[] v, int index)
+ {
+ int value = v[index];
+ for (; index > 0; index--)
+ {
+ v[index] = v[index - 1];
+ }
+ v[0] = value;
+ }
+
+ private static void InverseMoveToFrontTransform(byte[] v, int vLen)
+ {
+ int[] mtf = new int[256];
+ for (int i = 0; i < 256; i++)
+ {
+ mtf[i] = i;
+ }
+ for (int i = 0; i < vLen; i++)
+ {
+ int index = v[i] & unchecked((int)(0xFF));
+ v[i] = unchecked((byte)mtf[index]);
+ if (index != 0)
+ {
+ MoveToFront(mtf, index);
+ }
+ }
+ }
+
+ private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, Org.Brotli.Dec.BitReader br)
+ {
+ int symbol = 0;
+ int prevCodeLen = DefaultCodeLength;
+ int repeat = 0;
+ int repeatCodeLen = 0;
+ int space = 32768;
+ int[] table = new int[32];
+ Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
+ while (symbol < numSymbols && space > 0)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
+ br.bitOffset += table[p] >> 16;
+ int codeLen = table[p] & unchecked((int)(0xFFFF));
+ if (codeLen < CodeLengthRepeatCode)
+ {
+ repeat = 0;
+ codeLengths[symbol++] = codeLen;
+ if (codeLen != 0)
+ {
+ prevCodeLen = codeLen;
+ space -= 32768 >> codeLen;
+ }
+ }
+ else
+ {
+ int extraBits = codeLen - 14;
+ int newLen = 0;
+ if (codeLen == CodeLengthRepeatCode)
+ {
+ newLen = prevCodeLen;
+ }
+ if (repeatCodeLen != newLen)
+ {
+ repeat = 0;
+ repeatCodeLen = newLen;
+ }
+ int oldRepeat = repeat;
+ if (repeat > 0)
+ {
+ repeat -= 2;
+ repeat <<= extraBits;
+ }
+ repeat += Org.Brotli.Dec.BitReader.ReadBits(br, extraBits) + 3;
+ int repeatDelta = repeat - oldRepeat;
+ if (symbol + repeatDelta > numSymbols)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
+ }
+ // COV_NF_LINE
+ for (int i = 0; i < repeatDelta; i++)
+ {
+ codeLengths[symbol++] = repeatCodeLen;
+ }
+ if (repeatCodeLen != 0)
+ {
+ space -= repeatDelta << (15 - repeatCodeLen);
+ }
+ }
+ }
+ if (space != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unused space");
+ }
+ // COV_NF_LINE
+ // TODO: Pass max_symbol to Huffman table builder instead?
+ Org.Brotli.Dec.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
+ }
+
+ // TODO: Use specialized versions for smaller tables.
+ internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, Org.Brotli.Dec.BitReader br)
+ {
+ bool ok = true;
+ int simpleCodeOrSkip;
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ // TODO: Avoid allocation.
+ int[] codeLengths = new int[alphabetSize];
+ simpleCodeOrSkip = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
+ if (simpleCodeOrSkip == 1)
+ {
+ // Read symbols, codes & code lengths directly.
+ int maxBitsCounter = alphabetSize - 1;
+ int maxBits = 0;
+ int[] symbols = new int[4];
+ int numSymbols = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 1;
+ while (maxBitsCounter != 0)
+ {
+ maxBitsCounter >>= 1;
+ maxBits++;
+ }
+ // TODO: uncomment when codeLengths is reused.
+ // Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
+ for (int i = 0; i < numSymbols; i++)
+ {
+ symbols[i] = Org.Brotli.Dec.BitReader.ReadBits(br, maxBits) % alphabetSize;
+ codeLengths[symbols[i]] = 2;
+ }
+ codeLengths[symbols[0]] = 1;
+ switch (numSymbols)
+ {
+ case 1:
+ {
+ break;
+ }
+
+ case 2:
+ {
+ ok = symbols[0] != symbols[1];
+ codeLengths[symbols[1]] = 1;
+ break;
+ }
+
+ case 3:
+ {
+ ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
+ break;
+ }
+
+ case 4:
+ default:
+ {
+ ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
+ if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
+ {
+ codeLengths[symbols[2]] = 3;
+ codeLengths[symbols[3]] = 3;
+ }
+ else
+ {
+ codeLengths[symbols[0]] = 2;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Decode Huffman-coded code lengths.
+ int[] codeLengthCodeLengths = new int[CodeLengthCodes];
+ int space = 32;
+ int numCodes = 0;
+ for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++)
+ {
+ int codeLenIdx = CodeLengthCodeOrder[i];
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
+ // TODO: Demultiplex FIXED_TABLE.
+ br.bitOffset += FixedTable[p] >> 16;
+ int v = FixedTable[p] & unchecked((int)(0xFFFF));
+ codeLengthCodeLengths[codeLenIdx] = v;
+ if (v != 0)
+ {
+ space -= (32 >> v);
+ numCodes++;
+ }
+ }
+ ok = (numCodes == 1 || space == 0);
+ ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
+ }
+ if (!ok)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Can't readHuffmanCode");
+ }
+ // COV_NF_LINE
+ Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
+ }
+
+ private static int DecodeContextMap(int contextMapSize, byte[] contextMap, Org.Brotli.Dec.BitReader br)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ int numTrees = DecodeVarLenUnsignedByte(br) + 1;
+ if (numTrees == 1)
+ {
+ Org.Brotli.Dec.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
+ return numTrees;
+ }
+ bool useRleForZeros = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
+ int maxRunLengthPrefix = 0;
+ if (useRleForZeros)
+ {
+ maxRunLengthPrefix = Org.Brotli.Dec.BitReader.ReadBits(br, 4) + 1;
+ }
+ int[] table = new int[Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
+ ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
+ for (int i = 0; i < contextMapSize; )
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int code = ReadSymbol(table, 0, br);
+ if (code == 0)
+ {
+ contextMap[i] = 0;
+ i++;
+ }
+ else if (code <= maxRunLengthPrefix)
+ {
+ int reps = (1 << code) + Org.Brotli.Dec.BitReader.ReadBits(br, code);
+ while (reps != 0)
+ {
+ if (i >= contextMapSize)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted context map");
+ }
+ // COV_NF_LINE
+ contextMap[i] = 0;
+ i++;
+ reps--;
+ }
+ }
+ else
+ {
+ contextMap[i] = unchecked((byte)(code - maxRunLengthPrefix));
+ i++;
+ }
+ }
+ if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
+ {
+ InverseMoveToFrontTransform(contextMap, contextMapSize);
+ }
+ return numTrees;
+ }
+
+ private static void DecodeBlockTypeAndLength(Org.Brotli.Dec.State state, int treeType)
+ {
+ Org.Brotli.Dec.BitReader br = state.br;
+ int[] ringBuffers = state.blockTypeRb;
+ int offset = treeType * 2;
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int blockType = ReadSymbol(state.blockTypeTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
+ state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
+ if (blockType == 1)
+ {
+ blockType = ringBuffers[offset + 1] + 1;
+ }
+ else if (blockType == 0)
+ {
+ blockType = ringBuffers[offset];
+ }
+ else
+ {
+ blockType -= 2;
+ }
+ if (blockType >= state.numBlockTypes[treeType])
+ {
+ blockType -= state.numBlockTypes[treeType];
+ }
+ ringBuffers[offset] = ringBuffers[offset + 1];
+ ringBuffers[offset + 1] = blockType;
+ }
+
+ private static void DecodeLiteralBlockSwitch(Org.Brotli.Dec.State state)
+ {
+ DecodeBlockTypeAndLength(state, 0);
+ int literalBlockType = state.blockTypeRb[1];
+ state.contextMapSlice = literalBlockType << LiteralContextBits;
+ state.literalTreeIndex = state.contextMap[state.contextMapSlice] & unchecked((int)(0xFF));
+ state.literalTree = state.hGroup0.trees[state.literalTreeIndex];
+ int contextMode = state.contextModes[literalBlockType];
+ state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[contextMode];
+ state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[contextMode + 1];
+ }
+
+ private static void DecodeCommandBlockSwitch(Org.Brotli.Dec.State state)
+ {
+ DecodeBlockTypeAndLength(state, 1);
+ state.treeCommandOffset = state.hGroup1.trees[state.blockTypeRb[3]];
+ }
+
+ private static void DecodeDistanceBlockSwitch(Org.Brotli.Dec.State state)
+ {
+ DecodeBlockTypeAndLength(state, 2);
+ state.distContextMapSlice = state.blockTypeRb[5] << DistanceContextBits;
+ }
+
+ private static void MaybeReallocateRingBuffer(Org.Brotli.Dec.State state)
+ {
+ int newSize = state.maxRingBufferSize;
+ if ((long)newSize > state.expectedTotalSize)
+ {
+ /* TODO: Handle 2GB+ cases more gracefully. */
+ int minimalNewSize = (int)state.expectedTotalSize + state.customDictionary.Length;
+ while ((newSize >> 1) > minimalNewSize)
+ {
+ newSize >>= 1;
+ }
+ if (!state.inputEnd && newSize < 16384 && state.maxRingBufferSize >= 16384)
+ {
+ newSize = 16384;
+ }
+ }
+ if (newSize <= state.ringBufferSize)
+ {
+ return;
+ }
+ int ringBufferSizeWithSlack = newSize + Org.Brotli.Dec.Dictionary.MaxTransformedWordLength;
+ byte[] newBuffer = new byte[ringBufferSizeWithSlack];
+ if (state.ringBuffer != null)
+ {
+ System.Array.Copy(state.ringBuffer, 0, newBuffer, 0, state.ringBufferSize);
+ }
+ else if (state.customDictionary.Length != 0)
+ {
+ /* Prepend custom dictionary, if any. */
+ int length = state.customDictionary.Length;
+ int offset = 0;
+ if (length > state.maxBackwardDistance)
+ {
+ offset = length - state.maxBackwardDistance;
+ length = state.maxBackwardDistance;
+ }
+ System.Array.Copy(state.customDictionary, offset, newBuffer, 0, length);
+ state.pos = length;
+ state.bytesToIgnore = length;
+ }
+ state.ringBuffer = newBuffer;
+ state.ringBufferSize = newSize;
+ }
+
+ /// <summary>Reads next metablock header.</summary>
+ /// <param name="state">decoding state</param>
+ private static void ReadMetablockInfo(Org.Brotli.Dec.State state)
+ {
+ Org.Brotli.Dec.BitReader br = state.br;
+ if (state.inputEnd)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.Finished;
+ state.bytesToWrite = state.pos;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ return;
+ }
+ // TODO: Reset? Do we need this?
+ state.hGroup0.codes = null;
+ state.hGroup0.trees = null;
+ state.hGroup1.codes = null;
+ state.hGroup1.trees = null;
+ state.hGroup2.codes = null;
+ state.hGroup2.trees = null;
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ DecodeMetaBlockLength(br, state);
+ if (state.metaBlockLength == 0 && !state.isMetadata)
+ {
+ return;
+ }
+ if (state.isUncompressed || state.isMetadata)
+ {
+ Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
+ state.runningState = state.isMetadata ? Org.Brotli.Dec.RunningState.ReadMetadata : Org.Brotli.Dec.RunningState.CopyUncompressed;
+ }
+ else
+ {
+ state.runningState = Org.Brotli.Dec.RunningState.CompressedBlockStart;
+ }
+ if (state.isMetadata)
+ {
+ return;
+ }
+ state.expectedTotalSize += state.metaBlockLength;
+ if (state.ringBufferSize < state.maxRingBufferSize)
+ {
+ MaybeReallocateRingBuffer(state);
+ }
+ }
+
+ private static void ReadMetablockHuffmanCodesAndContextMaps(Org.Brotli.Dec.State state)
+ {
+ Org.Brotli.Dec.BitReader br = state.br;
+ for (int i = 0; i < 3; i++)
+ {
+ state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
+ state.blockLength[i] = 1 << 28;
+ if (state.numBlockTypes[i] > 1)
+ {
+ ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
+ ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
+ state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
+ }
+ }
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ state.distancePostfixBits = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
+ state.numDirectDistanceCodes = NumDistanceShortCodes + (Org.Brotli.Dec.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
+ state.distancePostfixMask = (1 << state.distancePostfixBits) - 1;
+ int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);
+ // TODO: Reuse?
+ state.contextModes = new byte[state.numBlockTypes[0]];
+ for (int i = 0; i < state.numBlockTypes[0]; )
+ {
+ /* Ensure that less than 256 bits read between readMoreInput. */
+ int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
+ for (; i < limit; ++i)
+ {
+ state.contextModes[i] = unchecked((byte)(Org.Brotli.Dec.BitReader.ReadBits(br, 2) << 1));
+ }
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ }
+ // TODO: Reuse?
+ state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
+ int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);
+ state.trivialLiteralContext = true;
+ for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++)
+ {
+ if (state.contextMap[j] != j >> LiteralContextBits)
+ {
+ state.trivialLiteralContext = false;
+ break;
+ }
+ }
+ // TODO: Reuse?
+ state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
+ int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);
+ Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
+ Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
+ Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
+ Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup0, br);
+ Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup1, br);
+ Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup2, br);
+ state.contextMapSlice = 0;
+ state.distContextMapSlice = 0;
+ state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0]];
+ state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0] + 1];
+ state.literalTreeIndex = 0;
+ state.literalTree = state.hGroup0.trees[0];
+ state.treeCommandOffset = state.hGroup1.trees[0];
+ // TODO: == 0?
+ state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
+ state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
+ }
+
+ private static void CopyUncompressedData(Org.Brotli.Dec.State state)
+ {
+ Org.Brotli.Dec.BitReader br = state.br;
+ byte[] ringBuffer = state.ringBuffer;
+ // Could happen if block ends at ring buffer end.
+ if (state.metaBlockLength <= 0)
+ {
+ Org.Brotli.Dec.BitReader.Reload(br);
+ state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
+ return;
+ }
+ int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);
+ Org.Brotli.Dec.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
+ state.metaBlockLength -= chunkLength;
+ state.pos += chunkLength;
+ if (state.pos == state.ringBufferSize)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.CopyUncompressed;
+ state.bytesToWrite = state.ringBufferSize;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ return;
+ }
+ Org.Brotli.Dec.BitReader.Reload(br);
+ state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
+ }
+
+ private static bool WriteRingBuffer(Org.Brotli.Dec.State state)
+ {
+ /* Ignore custom dictionary bytes. */
+ if (state.bytesToIgnore != 0)
+ {
+ state.bytesWritten += state.bytesToIgnore;
+ state.bytesToIgnore = 0;
+ }
+ int toWrite = System.Math.Min(state.outputLength - state.outputUsed, state.bytesToWrite - state.bytesWritten);
+ if (toWrite != 0)
+ {
+ System.Array.Copy(state.ringBuffer, state.bytesWritten, state.output, state.outputOffset + state.outputUsed, toWrite);
+ state.outputUsed += toWrite;
+ state.bytesWritten += toWrite;
+ }
+ return state.outputUsed < state.outputLength;
+ }
+
+ internal static void SetCustomDictionary(Org.Brotli.Dec.State state, byte[] data)
+ {
+ state.customDictionary = (data == null) ? new byte[0] : data;
+ }
+
+ /// <summary>Actual decompress implementation.</summary>
+ internal static void Decompress(Org.Brotli.Dec.State state)
+ {
+ if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
+ {
+ throw new System.InvalidOperationException("Can't decompress until initialized");
+ }
+ if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
+ {
+ throw new System.InvalidOperationException("Can't decompress after close");
+ }
+ Org.Brotli.Dec.BitReader br = state.br;
+ int ringBufferMask = state.ringBufferSize - 1;
+ byte[] ringBuffer = state.ringBuffer;
+ while (state.runningState != Org.Brotli.Dec.RunningState.Finished)
+ {
+ switch (state.runningState)
+ {
+ case Org.Brotli.Dec.RunningState.BlockStart:
+ {
+ // TODO: extract cases to methods for the better readability.
+ if (state.metaBlockLength < 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
+ }
+ ReadMetablockInfo(state);
+ /* Ring-buffer would be reallocated here. */
+ ringBufferMask = state.ringBufferSize - 1;
+ ringBuffer = state.ringBuffer;
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.CompressedBlockStart:
+ {
+ ReadMetablockHuffmanCodesAndContextMaps(state);
+ state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
+ goto case Org.Brotli.Dec.RunningState.MainLoop;
+ }
+
+ case Org.Brotli.Dec.RunningState.MainLoop:
+ {
+ // Fall through
+ if (state.metaBlockLength <= 0)
+ {
+ state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
+ continue;
+ }
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ if (state.blockLength[1] == 0)
+ {
+ DecodeCommandBlockSwitch(state);
+ }
+ state.blockLength[1]--;
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ int cmdCode = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
+ int rangeIdx = (int)(((uint)cmdCode) >> 6);
+ state.distanceCode = 0;
+ if (rangeIdx >= 2)
+ {
+ rangeIdx -= 2;
+ state.distanceCode = -1;
+ }
+ int insertCode = Org.Brotli.Dec.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
+ int copyCode = Org.Brotli.Dec.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
+ state.insertLength = Org.Brotli.Dec.Prefix.InsertLengthOffset[insertCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.InsertLengthNBits[insertCode]);
+ state.copyLength = Org.Brotli.Dec.Prefix.CopyLengthOffset[copyCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.CopyLengthNBits[copyCode]);
+ state.j = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.InsertLoop;
+ goto case Org.Brotli.Dec.RunningState.InsertLoop;
+ }
+
+ case Org.Brotli.Dec.RunningState.InsertLoop:
+ {
+ // Fall through
+ if (state.trivialLiteralContext)
+ {
+ while (state.j < state.insertLength)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ if (state.blockLength[0] == 0)
+ {
+ DecodeLiteralBlockSwitch(state);
+ }
+ state.blockLength[0]--;
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ ringBuffer[state.pos] = unchecked((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
+ state.j++;
+ if (state.pos++ == ringBufferMask)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
+ state.bytesToWrite = state.ringBufferSize;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ break;
+ }
+ }
+ }
+ else
+ {
+ int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked((int)(0xFF));
+ int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked((int)(0xFF));
+ while (state.j < state.insertLength)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ if (state.blockLength[0] == 0)
+ {
+ DecodeLiteralBlockSwitch(state);
+ }
+ int literalTreeIndex = state.contextMap[state.contextMapSlice + (Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset1 + prevByte1] | Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked((int)(0xFF));
+ state.blockLength[0]--;
+ prevByte2 = prevByte1;
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ prevByte1 = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
+ ringBuffer[state.pos] = unchecked((byte)prevByte1);
+ state.j++;
+ if (state.pos++ == ringBufferMask)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
+ state.bytesToWrite = state.ringBufferSize;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ break;
+ }
+ }
+ }
+ if (state.runningState != Org.Brotli.Dec.RunningState.InsertLoop)
+ {
+ continue;
+ }
+ state.metaBlockLength -= state.insertLength;
+ if (state.metaBlockLength <= 0)
+ {
+ state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
+ continue;
+ }
+ if (state.distanceCode < 0)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ if (state.blockLength[2] == 0)
+ {
+ DecodeDistanceBlockSwitch(state);
+ }
+ state.blockLength[2]--;
+ Org.Brotli.Dec.BitReader.FillBitWindow(br);
+ state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked((int)(0xFF))], br);
+ if (state.distanceCode >= state.numDirectDistanceCodes)
+ {
+ state.distanceCode -= state.numDirectDistanceCodes;
+ int postfix = state.distanceCode & state.distancePostfixMask;
+ state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
+ int n = ((int)(((uint)state.distanceCode) >> 1)) + 1;
+ int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
+ state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + Org.Brotli.Dec.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
+ }
+ }
+ // Convert the distance code to the actual distance by possibly looking up past distances
+ // from the ringBuffer.
+ state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
+ if (state.distance < 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Negative distance");
+ }
+ // COV_NF_LINE
+ if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance)
+ {
+ state.maxDistance = state.pos;
+ }
+ else
+ {
+ state.maxDistance = state.maxBackwardDistance;
+ }
+ state.copyDst = state.pos;
+ if (state.distance > state.maxDistance)
+ {
+ state.runningState = Org.Brotli.Dec.RunningState.Transform;
+ continue;
+ }
+ if (state.distanceCode > 0)
+ {
+ state.distRb[state.distRbIdx & 3] = state.distance;
+ state.distRbIdx++;
+ }
+ if (state.copyLength > state.metaBlockLength)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
+ }
+ // COV_NF_LINE
+ state.j = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.CopyLoop;
+ goto case Org.Brotli.Dec.RunningState.CopyLoop;
+ }
+
+ case Org.Brotli.Dec.RunningState.CopyLoop:
+ {
+ // fall through
+ int src = (state.pos - state.distance) & ringBufferMask;
+ int dst = state.pos;
+ int copyLength = state.copyLength - state.j;
+ if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask))
+ {
+ for (int k = 0; k < copyLength; ++k)
+ {
+ ringBuffer[dst++] = ringBuffer[src++];
+ }
+ state.j += copyLength;
+ state.metaBlockLength -= copyLength;
+ state.pos += copyLength;
+ }
+ else
+ {
+ for (; state.j < state.copyLength; )
+ {
+ ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
+ state.metaBlockLength--;
+ state.j++;
+ if (state.pos++ == ringBufferMask)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.CopyLoop;
+ state.bytesToWrite = state.ringBufferSize;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ break;
+ }
+ }
+ }
+ if (state.runningState == Org.Brotli.Dec.RunningState.CopyLoop)
+ {
+ state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
+ }
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.Transform:
+ {
+ if (state.copyLength >= Org.Brotli.Dec.Dictionary.MinWordLength && state.copyLength <= Org.Brotli.Dec.Dictionary.MaxWordLength)
+ {
+ int offset = Org.Brotli.Dec.Dictionary.OffsetsByLength[state.copyLength];
+ int wordId = state.distance - state.maxDistance - 1;
+ int shift = Org.Brotli.Dec.Dictionary.SizeBitsByLength[state.copyLength];
+ int mask = (1 << shift) - 1;
+ int wordIdx = wordId & mask;
+ int transformIdx = (int)(((uint)wordId) >> shift);
+ offset += wordIdx * state.copyLength;
+ if (transformIdx < Org.Brotli.Dec.Transform.Transforms.Length)
+ {
+ int len = Org.Brotli.Dec.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, Org.Brotli.Dec.Dictionary.GetData(), offset, state.copyLength, Org.Brotli.Dec.Transform.Transforms[transformIdx]);
+ state.copyDst += len;
+ state.pos += len;
+ state.metaBlockLength -= len;
+ if (state.copyDst >= state.ringBufferSize)
+ {
+ state.nextRunningState = Org.Brotli.Dec.RunningState.CopyWrapBuffer;
+ state.bytesToWrite = state.ringBufferSize;
+ state.bytesWritten = 0;
+ state.runningState = Org.Brotli.Dec.RunningState.Write;
+ continue;
+ }
+ }
+ else
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
+ }
+ }
+ else
+ {
+ // COV_NF_LINE
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
+ }
+ // COV_NF_LINE
+ state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.CopyWrapBuffer:
+ {
+ System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
+ state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.ReadMetadata:
+ {
+ while (state.metaBlockLength > 0)
+ {
+ Org.Brotli.Dec.BitReader.ReadMoreInput(br);
+ // Optimize
+ Org.Brotli.Dec.BitReader.ReadBits(br, 8);
+ state.metaBlockLength--;
+ }
+ state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.CopyUncompressed:
+ {
+ CopyUncompressedData(state);
+ continue;
+ }
+
+ case Org.Brotli.Dec.RunningState.Write:
+ {
+ if (!WriteRingBuffer(state))
+ {
+ // Output buffer is full.
+ return;
+ }
+ if (state.pos >= state.maxBackwardDistance)
+ {
+ state.maxDistance = state.maxBackwardDistance;
+ }
+ state.pos &= ringBufferMask;
+ state.runningState = state.nextRunningState;
+ continue;
+ }
+
+ default:
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected state " + state.runningState);
+ }
+ }
+ }
+ if (state.runningState == Org.Brotli.Dec.RunningState.Finished)
+ {
+ if (state.metaBlockLength < 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
+ }
+ Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
+ Org.Brotli.Dec.BitReader.CheckHealth(state.br, true);
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DecodeTest.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DecodeTest.cs
new file mode 100644
index 000000000..f6fad8c88
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DecodeTest.cs
@@ -0,0 +1,171 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// Tests for
+ /// <see cref="Decode"/>
+ /// .
+ /// </summary>
+ public class DecodeTest
+ {
+ /// <exception cref="System.IO.IOException"/>
+ private byte[] Decompress(byte[] data, bool byByte)
+ {
+ byte[] buffer = new byte[65536];
+ System.IO.MemoryStream input = new System.IO.MemoryStream(data);
+ System.IO.MemoryStream output = new System.IO.MemoryStream();
+ Org.Brotli.Dec.BrotliInputStream brotliInput = new Org.Brotli.Dec.BrotliInputStream(input);
+ if (byByte)
+ {
+ byte[] oneByte = new byte[1];
+ while (true)
+ {
+ int next = brotliInput.ReadByte();
+ if (next == -1)
+ {
+ break;
+ }
+ oneByte[0] = unchecked((byte)next);
+ output.Write(oneByte, 0, 1);
+ }
+ }
+ else
+ {
+ while (true)
+ {
+ int len = brotliInput.Read(buffer, 0, buffer.Length);
+ if (len <= 0)
+ {
+ break;
+ }
+ output.Write(buffer, 0, len);
+ }
+ }
+ brotliInput.Close();
+ return output.ToArray();
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ private byte[] DecompressWithDictionary(byte[] data, byte[] dictionary)
+ {
+ byte[] buffer = new byte[65536];
+ System.IO.MemoryStream input = new System.IO.MemoryStream(data);
+ System.IO.MemoryStream output = new System.IO.MemoryStream();
+ Org.Brotli.Dec.BrotliInputStream brotliInput = new Org.Brotli.Dec.BrotliInputStream(input, Org.Brotli.Dec.BrotliInputStream.DefaultInternalBufferSize, dictionary);
+ while (true)
+ {
+ int len = brotliInput.Read(buffer, 0, buffer.Length);
+ if (len <= 0)
+ {
+ break;
+ }
+ output.Write(buffer, 0, len);
+ }
+ brotliInput.Close();
+ return output.ToArray();
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ private void CheckDecodeResourceWithDictionary(string expected, string compressed, string dictionary)
+ {
+ byte[] expectedBytes = Org.Brotli.Dec.Transform.ReadUniBytes(expected);
+ byte[] compressedBytes = Org.Brotli.Dec.Transform.ReadUniBytes(compressed);
+ byte[] dictionaryBytes = Org.Brotli.Dec.Transform.ReadUniBytes(dictionary);
+ byte[] actual = DecompressWithDictionary(compressedBytes, dictionaryBytes);
+ NUnit.Framework.Assert.AreEqual(expectedBytes, actual);
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ private void CheckDecodeResource(string expected, string compressed)
+ {
+ byte[] expectedBytes = Org.Brotli.Dec.Transform.ReadUniBytes(expected);
+ byte[] compressedBytes = Org.Brotli.Dec.Transform.ReadUniBytes(compressed);
+ byte[] actual = Decompress(compressedBytes, false);
+ NUnit.Framework.Assert.AreEqual(expectedBytes, actual);
+ byte[] actualByByte = Decompress(compressedBytes, true);
+ NUnit.Framework.Assert.AreEqual(expectedBytes, actualByByte);
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestEmpty()
+ {
+ CheckDecodeResource(string.Empty, "\u0006");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestX()
+ {
+ CheckDecodeResource("X", "\u000B\u0000\u0080X\u0003");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestX10Y10()
+ {
+ CheckDecodeResource("XXXXXXXXXXYYYYYYYYYY", "\u001B\u0013\u0000\u0000\u00A4\u00B0\u00B2\u00EA\u0081G\u0002\u008A");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestX64()
+ {
+ CheckDecodeResource("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "\u001B\u003F\u0000\u0000$\u00B0\u00E2\u0099\u0080\u0012");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestUkkonooa()
+ {
+ CheckDecodeResource("ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, " + "pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.", "\u001Bv\u0000\u0000\u0014J\u00AC\u009Bz\u00BD\u00E1\u0097\u009D\u007F\u008E\u00C2\u0082" + "6\u000E\u009C\u00E0\u0090\u0003\u00F7\u008B\u009E8\u00E6\u00B6\u0000\u00AB\u00C3\u00CA"
+ + "\u00A0\u00C2\u00DAf6\u00DC\u00CD\u0080\u008D.!\u00D7n\u00E3\u00EAL\u00B8\u00F0\u00D2" + "\u00B8\u00C7\u00C2pM:\u00F0i~\u00A1\u00B8Es\u00AB\u00C4W\u001E");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestMonkey()
+ {
+ CheckDecodeResource("znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmz" + "xc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxc" + "nzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqeriou"
+ + "pqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyio" + "wtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuri" + "ouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwot"
+ + "ueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfh" + "klasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfa" + "sdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjka"
+ + "ghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj", "\u001BJ\u0003\u0000\u008C\u0094n\u00DE\u00B4\u00D7\u0096\u00B1x\u0086\u00F2-\u00E1\u001A" + "\u00BC\u000B\u001C\u00BA\u00A9\u00C7\u00F7\u00CCn\u00B2B4QD\u008BN\u0013\b\u00A0\u00CDn"
+ + "\u00E8,\u00A5S\u00A1\u009C],\u001D#\u001A\u00D2V\u00BE\u00DB\u00EB&\u00BA\u0003e|\u0096j" + "\u00A2v\u00EC\u00EF\u0087G3\u00D6\'\u000Ec\u0095\u00E2\u001D\u008D,\u00C5\u00D1(\u009F`" + "\u0094o\u0002\u008B\u00DD\u00AAd\u0094,\u001E;e|\u0007EZ\u00B2\u00E2\u00FCI\u0081,\u009F"
+ + "@\u00AE\u00EFh\u0081\u00AC\u0016z\u000F\u00F5;m\u001C\u00B9\u001E-_\u00D5\u00C8\u00AF^" + "\u0085\u00AA\u0005\u00BESu\u00C2\u00B0\"\u008A\u0015\u00C6\u00A3\u00B1\u00E6B\u0014" + "\u00F4\u0084TS\u0019_\u00BE\u00C3\u00F2\u001D\u00D1\u00B7\u00E5\u00DD\u00B6\u00D9#\u00C6"
+ + "\u00F6\u009F\u009E\u00F6Me0\u00FB\u00C0qE\u0004\u00AD\u0003\u00B5\u00BE\u00C9\u00CB" + "\u00FD\u00E2PZFt\u0004\r\u00FF \u0004w\u00B2m\'\u00BFG\u00A9\u009D\u001B\u0096,b\u0090#" + "\u008B\u00E0\u00F8\u001D\u00CF\u00AF\u001D=\u00EE\u008A\u00C8u#f\u00DD\u00DE\u00D6m"
+ + "\u00E3*\u0082\u008Ax\u008A\u00DB\u00E6 L\u00B7\\c\u00BA0\u00E3?\u00B6\u00EE\u008C\"" + "\u00A2*\u00B0\"\n\u0099\u00FF=bQ\u00EE\b\u00F6=J\u00E4\u00CC\u00EF\"\u0087\u0011\u00E2" + "\u0083(\u00E4\u00F5\u008F5\u0019c[\u00E1Z\u0092s\u00DD\u00A1P\u009D8\\\u00EB\u00B5\u0003"
+ + "jd\u0090\u0094\u00C8\u008D\u00FB/\u008A\u0086\"\u00CC\u001D\u0087\u00E0H\n\u0096w\u00909" + "\u00C6##H\u00FB\u0011GV\u00CA \u00E3B\u0081\u00F7w2\u00C1\u00A5\\@!e\u0017@)\u0017\u0017" + "lV2\u00988\u0006\u00DC\u0099M3)\u00BB\u0002\u00DFL&\u0093l\u0017\u0082\u0086 \u00D7"
+ + "\u0003y}\u009A\u0000\u00D7\u0087\u0000\u00E7\u000Bf\u00E3Lfqg\b2\u00F9\b>\u00813\u00CD" + "\u0017r1\u00F0\u00B8\u0094RK\u00901\u008Eh\u00C1\u00EF\u0090\u00C9\u00E5\u00F2a\tr%" + "\u00AD\u00EC\u00C5b\u00C0\u000B\u0012\u0005\u00F7\u0091u\r\u00EEa..\u0019\t\u00C2\u0003"
+ );
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestFox()
+ {
+ CheckDecodeResource("The quick brown fox jumps over the lazy dog", "\u001B*\u0000\u0000\u0004\u0004\u00BAF:\u0085\u0003\u00E9\u00FA\f\u0091\u0002H\u0011," + "\u00F3\u008A:\u00A3V\u007F\u001A\u00AE\u00BF\u00A4\u00AB\u008EM\u00BF\u00ED\u00E2\u0004K"
+ + "\u0091\u00FF\u0087\u00E9\u001E");
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ [NUnit.Framework.Test]
+ public virtual void TestFoxFox()
+ {
+ CheckDecodeResourceWithDictionary("The quick brown fox jumps over the lazy dog", "\u001B*\u0000\u0000 \u0000\u00C2\u0098\u00B0\u00CA\u0001", "The quick brown fox jumps over the lazy dog");
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestUtils()
+ {
+ new Org.Brotli.Dec.Context();
+ new Org.Brotli.Dec.Decode();
+ new Org.Brotli.Dec.Dictionary();
+ new Org.Brotli.Dec.Huffman();
+ new Org.Brotli.Dec.Prefix();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Dictionary.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Dictionary.cs
new file mode 100644
index 000000000..3445f80f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Dictionary.cs
@@ -0,0 +1,97 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Collection of static dictionary words.</summary>
+ /// <remarks>
+ /// Collection of static dictionary words.
+ /// <p>Dictionary content is loaded from binary resource when
+ /// <see cref="GetData()"/>
+ /// is executed for the
+ /// first time. Consequently, it saves memory and CPU in case dictionary is not required.
+ /// <p>One possible drawback is that multiple threads that need dictionary data may be blocked (only
+ /// once in each classworld). To avoid this, it is enough to call
+ /// <see cref="GetData()"/>
+ /// proactively.
+ /// </remarks>
+ internal sealed class Dictionary
+ {
+ /// <summary>"Initialization-on-demand holder idiom" implementation.</summary>
+ /// <remarks>
+ /// "Initialization-on-demand holder idiom" implementation.
+ /// <p>This static class definition is not initialized until the JVM determines that it must be
+ /// executed (when the static method
+ /// <see cref="GetData()"/>
+ /// is invoked).
+ /// </remarks>
+ private class DataHolder0
+ {
+ internal static string GetData()
+ {
+ return "timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0\"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml\"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid=\"sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$(\"#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS\"agedgreyGET\"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:\u00E5*/\r\n 100hall.\n\nA7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,\r\n\r\ncoolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px''););\">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarm\u00E2\u0080\u0099sboys[0].');\"POSTbearkids);}}marytend(UK)quadzh:\u00E6-siz----prop');\rliftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene \u00E2\u0080\u0094softrometillross<h3>pourfadepink<tr>mini)|!(minezh:\u00E8barshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json', 'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:\u00E4'));puremageparatonebond:37Z_of_']);000,zh:\u00E7tankyardbowlbush:56ZJava30px\n|}\n%C3%:34ZjeffEXPIcashvisagolfsnowzh:\u00E9quer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;\n}\nexit:35Zvarsbeat'});diet999;anne}}</[i].Langkm\u00C2\u00B2wiretoysaddssealalex;\n\t}echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}\ndustclip).\n\n70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}\r\nHEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-\n!002)ndow[1];[];\nLog salt\r\n\t\tbangtrimbath){\r\n00px\n});ko:\u00ECfeesad>\rs:// [];tollplug(){\n{\r\n .js'200pdualboat.JPG);\n}quot);\n\n');\n\r\n}\r201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comom\u00C3\u00A1sesteestaperotodohacecadaa\u00C3\u00B1obiend\u00C3\u00ADaas\u00C3\u00ADvidacasootroforosolootracualdijosidograntipotemadebealgoqu\u00C3\u00A9estonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasi\u00D0\u00B7\u00D0\u00B0\u00D0\u00BD\u00D0\u00B0\u00D0\u00BE\u00D0\u00BC\u00D1\u0080\u00D0\u00B0\u00D1\u0080\u00D1\u0083\u00D1\u0082\u00D0\u00B0\u00D0\u00BD\u00D0\u00B5\u00D0\u00BF\u00D0\u00BE\u00D0\u00BE\u00D1\u0082\u00D0\u00B8\u00D0\u00B7\u00D0\u00BD\u00D0\u00BE\u00D0\u00B4\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D0\u00B6\u00D0\u00B5\u00D0\u00BE\u00D0\u00BD\u00D0\u00B8\u00D1\u0085\u00D0\u009D\u00D0\u00B0\u00D0\u00B5\u00D0\u00B5\u00D0\u00B1\u00D1\u008B\u00D0\u00BC\u00D1\u008B\u00D0\u0092\u00D1\u008B\u00D1\u0081\u00D0\u00BE\u00D0\u00B2\u00D1\u008B\u00D0\u00B2\u00D0\u00BE\u00D0\u009D\u00D0\u00BE\u00D0\u00BE\u00D0\u00B1\u00D0\u009F\u00D0\u00BE\u00D0\u00BB\u00D0\u00B8\u00D0\u00BD\u00D0\u00B8\u00D0\u00A0\u00D0\u00A4\u00D0\u009D\u00D0\u00B5\u00D0\u009C\u00D1\u008B\u00D1\u0082\u00D1\u008B\u00D0\u009E\u00D0\u00BD\u00D0\u00B8\u00D0\u00BC\u00D0\u00B4\u00D0\u00B0\u00D0\u0097\u00D0\u00B0\u00D0\u0094\u00D0\u00B0\u00D0\u009D\u00D1\u0083\u00D0\u009E\u00D0\u00B1\u00D1\u0082\u00D0\u00B5\u00D0\u0098\u00D0\u00B7\u00D0\u00B5\u00D0\u00B9\u00D0\u00BD\u00D1\u0083\u00D0\u00BC\u00D0\u00BC\u00D0\u00A2\u00D1\u008B\u00D1\u0083\u00D0\u00B6\u00D9\u0081\u00D9\u008A\u00D8\u00A3\u00D9\u0086\u00D9\u0085\u00D8\u00A7\u00D9\u0085\u00D8\u00B9\u00D9\u0083\u00D9\u0084\u00D8\u00A3\u00D9\u0088\u00D8\u00B1\u00D8\u00AF\u00D9\u008A\u00D8\u00A7\u00D9\u0081\u00D9\u0089\u00D9\u0087\u00D9\u0088\u00D9\u0084\u00D9\u0085\u00D9\u0084\u00D9\u0083\u00D8\u00A7\u00D9\u0088\u00D9\u0084\u00D9\u0087\u00D8\u00A8\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00A5\u00D9\u0086\u00D9\u0087\u00D9\u008A\u00D8\u00A3\u00D9\u008A\u00D9\u0082\u00D8\u00AF\u00D9\u0087\u00D9\u0084\u00D8\u00AB\u00D9\u0085\u00D8\u00A8\u00D9\u0087\u00D9\u0084\u00D9\u0088\u00D9\u0084\u00D9\u008A\u00D8\u00A8\u00D9\u0084\u00D8\u00A7\u00D9\u008A\u00D8\u00A8\u00D9\u0083\u00D8\u00B4\u00D9\u008A\u00D8\u00A7\u00D9\u0085\u00D8\u00A3\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00A8\u00D9\u008A\u00D9\u0084\u00D9\u0086\u00D8\u00AD\u00D8\u00A8\u00D9\u0087\u00D9\u0085\u00D9\u0085\u00D8\u00B4\u00D9\u0088\u00D8\u00B4firstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue\"crossspentblogsbox\">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav\">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera\"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow\">genretrucklooksValueFrame.net/-->\n<try {\nvar makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top\">\n<!--POST\"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url=\"parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();\" Blocklinuxjonespixel');\">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar\">.src=toweralt=\"cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});\r\nbandsqueue= {};80px;cking{\r\n\t\taheadclockirishlike ratiostatsForm\"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg\"spainbeachtaxesmicroangel--></giftssteve-linkbody.});\n\tmount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:\u00E3\u0082simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/\"1.jpgwmodeparamSTARTleft idden, 201);\n}\nform.viruschairtransworstPagesitionpatch<!--\no-cacfirmstours,000 asiani++){adobe')[0]id=10both;menu .2.mi.png\"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120\" sweettr>\r\nname=diegopage swiss-->\n\n#fff;\">Log.com\"treatsheet) && 14px;sleepntentfiledja:\u00E3\u0083id=\"cName\"worseshots-box-delta\n&lt;bears:48Z<data-rural</a> spendbakershops= \"\";php\">ction13px;brianhellosize=o=%2F joinmaybe<img img\">, fjsimg\" \")[0]MTopBType\"newlyDanskczechtrailknows</h5>faq\">zh-cn10);\n-1\");type=bluestrulydavis.js';>\r\n<!steel you h2>\r\nform jesus100% menu.\r\n\t\r\nwalesrisksumentddingb-likteachgif\" vegasdanskeestishqipsuomisobredesdeentretodospuedea\u00C3\u00B1osest\u00C3\u00A1tienehastaotrospartedondenuevohacerformamismomejormundoaqu\u00C3\u00ADd\u00C3\u00ADass\u00C3\u00B3loayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspa\u00C3\u00ADsnuevasaludforosmedioquienmesespoderchileser\u00C3\u00A1vecesdecirjos\u00C3\u00A9estarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegoc\u00C3\u00B3moenerojuegoper\u00C3\u00BAhaberestoynuncamujervalorfueralibrogustaigualvotoscasosgu\u00C3\u00ADapuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasle\u00C3\u00B3nplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacen\u00C3\u00A1readiscopedrocercapuedapapelmenor\u00C3\u00BAtilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoni\u00C3\u00B1oquedapasarbancohijosviajepablo\u00C3\u00A9stevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaall\u00C3\u00ADjovendichaestantalessalirsuelopesosfinesllamabusco\u00C3\u00A9stalleganegroplazahumorpagarjuntadobleislasbolsaba\u00C3\u00B1ohablalucha\u00C3\u0081readicenjugarnotasvalleall\u00C3\u00A1cargadolorabajoest\u00C3\u00A9gustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo\">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother\" id=\"marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo\" bottomlist\">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename=\"amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.\n\nOnejoinedmenu\">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo\">beyond-scaleacceptservedmarineFootercamera</h1>\n_form\"leavesstress\" />\r\n.gif\" onloadloaderOxfordsistersurvivlistenfemaleDesignsize=\"appealtext\">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main\">inlinesundaywrap\">failedcensusminutebeaconquotes150px|estateremoteemail\"linkedright;signalformal1.htmlsignupprincefloat:.png\" forum.AccesspaperssoundsextendHeightsliderUTF-8\"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome\">headerensurebranchpiecesblock;statedtop\"><racingresize--&gt;pacitysexualbureau.jpg\" 10,000obtaintitlesamount, Inc.comedymenu\" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page\">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline\">body\">\n* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox\">\nSystem DavidcancertablesprovedApril reallydriveritem\">more\">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php\" assumelayerswilsonstoresreliefswedenCustomeasily your String\n\nWhiltaylorclear:resortfrenchthough\") + \"<body>buyingbrandsMembername\">oppingsector5px;\">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink\">Images=falsewhile hspace0&amp; \n\nIn powerPolski-colorjordanBottomStart -count2.htmlnews\">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml\" rights.html-blockregExp:hoverwithinvirginphones</tr>\rusing \n\tvar >');\n\t</td>\n</tr>\nbahasabrasilgalegomagyarpolskisrpski\u00D8\u00B1\u00D8\u00AF\u00D9\u0088\u00E4\u00B8\u00AD\u00E6\u0096\u0087\u00E7\u00AE\u0080\u00E4\u00BD\u0093\u00E7\u00B9\u0081\u00E9\u00AB\u0094\u00E4\u00BF\u00A1\u00E6\u0081\u00AF\u00E4\u00B8\u00AD\u00E5\u009B\u00BD\u00E6\u0088\u0091\u00E4\u00BB\u00AC\u00E4\u00B8\u0080\u00E4\u00B8\u00AA\u00E5\u0085\u00AC\u00E5\u008F\u00B8\u00E7\u00AE\u00A1\u00E7\u0090\u0086\u00E8\u00AE\u00BA\u00E5\u009D\u009B\u00E5\u008F\u00AF\u00E4\u00BB\u00A5\u00E6\u009C\u008D\u00E5\u008A\u00A1\u00E6\u0097\u00B6\u00E9\u0097\u00B4\u00E4\u00B8\u00AA\u00E4\u00BA\u00BA\u00E4\u00BA\u00A7\u00E5\u0093\u0081\u00E8\u0087\u00AA\u00E5\u00B7\u00B1\u00E4\u00BC\u0081\u00E4\u00B8\u009A\u00E6\u009F\u00A5\u00E7\u009C\u008B\u00E5\u00B7\u00A5\u00E4\u00BD\u009C\u00E8\u0081\u0094\u00E7\u00B3\u00BB\u00E6\u00B2\u00A1\u00E6\u009C\u0089\u00E7\u00BD\u0091\u00E7\u00AB\u0099\u00E6\u0089\u0080\u00E6\u009C\u0089\u00E8\u00AF\u0084\u00E8\u00AE\u00BA\u00E4\u00B8\u00AD\u00E5\u00BF\u0083\u00E6\u0096\u0087\u00E7\u00AB\u00A0\u00E7\u0094\u00A8\u00E6\u0088\u00B7\u00E9\u00A6\u0096\u00E9\u00A1\u00B5\u00E4\u00BD\u009C\u00E8\u0080\u0085\u00E6\u008A\u0080\u00E6\u009C\u00AF\u00E9\u0097\u00AE\u00E9\u00A2\u0098\u00E7\u009B\u00B8\u00E5\u0085\u00B3\u00E4\u00B8\u008B\u00E8\u00BD\u00BD\u00E6\u0090\u009C\u00E7\u00B4\u00A2\u00E4\u00BD\u00BF\u00E7\u0094\u00A8\u00E8\u00BD\u00AF\u00E4\u00BB\u00B6\u00E5\u009C\u00A8\u00E7\u00BA\u00BF\u00E4\u00B8\u00BB\u00E9\u00A2\u0098\u00E8\u00B5\u0084\u00E6\u0096\u0099\u00E8\u00A7\u0086\u00E9\u00A2\u0091\u00E5\u009B\u009E\u00E5\u00A4\u008D\u00E6\u00B3\u00A8\u00E5\u0086\u008C\u00E7\u00BD\u0091\u00E7\u00BB\u009C\u00E6\u0094\u00B6\u00E8\u0097\u008F\u00E5\u0086\u0085\u00E5\u00AE\u00B9\u00E6\u008E\u00A8\u00E8\u008D\u0090\u00E5\u00B8\u0082\u00E5\u009C\u00BA\u00E6\u00B6\u0088\u00E6\u0081\u00AF\u00E7\u00A9\u00BA\u00E9\u0097\u00B4\u00E5\u008F\u0091\u00E5\u00B8\u0083\u00E4\u00BB\u0080\u00E4\u00B9\u0088\u00E5\u00A5\u00BD\u00E5\u008F\u008B\u00E7\u0094\u009F\u00E6\u00B4\u00BB\u00E5\u009B\u00BE\u00E7\u0089\u0087\u00E5\u008F\u0091\u00E5\u00B1\u0095\u00E5\u00A6\u0082\u00E6\u009E\u009C\u00E6\u0089\u008B\u00E6\u009C\u00BA\u00E6\u0096\u00B0\u00E9\u0097\u00BB\u00E6\u009C\u0080\u00E6\u0096\u00B0\u00E6\u0096\u00B9\u00E5\u00BC\u008F\u00E5\u008C\u0097\u00E4\u00BA\u00AC\u00E6\u008F\u0090\u00E4\u00BE\u009B\u00E5\u0085\u00B3\u00E4\u00BA\u008E\u00E6\u009B\u00B4\u00E5\u00A4\u009A\u00E8\u00BF\u0099\u00E4\u00B8\u00AA\u00E7\u00B3\u00BB\u00E7\u00BB\u009F\u00E7\u009F\u00A5\u00E9\u0081\u0093\u00E6\u00B8\u00B8\u00E6\u0088\u008F\u00E5\u00B9\u00BF\u00E5\u0091\u008A\u00E5\u0085\u00B6\u00E4\u00BB\u0096\u00E5\u008F\u0091\u00E8\u00A1\u00A8\u00E5\u00AE\u0089\u00E5\u0085\u00A8\u00E7\u00AC\u00AC\u00E4\u00B8\u0080\u00E4\u00BC\u009A\u00E5\u0091\u0098\u00E8\u00BF\u009B\u00E8\u00A1\u008C\u00E7\u0082\u00B9\u00E5\u0087\u00BB\u00E7\u0089\u0088\u00E6\u009D\u0083\u00E7\u0094\u00B5\u00E5\u00AD\u0090\u00E4\u00B8\u0096\u00E7\u0095\u008C\u00E8\u00AE\u00BE\u00E8\u00AE\u00A1\u00E5\u0085\u008D\u00E8\u00B4\u00B9\u00E6\u0095\u0099\u00E8\u0082\u00B2\u00E5\u008A\u00A0\u00E5\u0085\u00A5\u00E6\u00B4\u00BB\u00E5\u008A\u00A8\u00E4\u00BB\u0096\u00E4\u00BB\u00AC\u00E5\u0095\u0086\u00E5\u0093\u0081\u00E5\u008D\u009A\u00E5\u00AE\u00A2\u00E7\u008E\u00B0\u00E5\u009C\u00A8\u00E4\u00B8\u008A\u00E6\u00B5\u00B7\u00E5\u00A6\u0082\u00E4\u00BD\u0095\u00E5\u00B7\u00B2\u00E7\u00BB\u008F\u00E7\u0095\u0099\u00E8\u00A8\u0080\u00E8\u00AF\u00A6\u00E7\u00BB\u0086\u00E7\u00A4\u00BE\u00E5\u008C\u00BA\u00E7\u0099\u00BB\u00E5\u00BD\u0095\u00E6\u009C\u00AC\u00E7\u00AB\u0099\u00E9\u009C\u0080\u00E8\u00A6\u0081\u00E4\u00BB\u00B7\u00E6\u00A0\u00BC\u00E6\u0094\u00AF\u00E6\u008C\u0081\u00E5\u009B\u00BD\u00E9\u0099\u0085\u00E9\u0093\u00BE\u00E6\u008E\u00A5\u00E5\u009B\u00BD\u00E5\u00AE\u00B6\u00E5\u00BB\u00BA\u00E8\u00AE\u00BE\u00E6\u009C\u008B\u00E5\u008F\u008B\u00E9\u0098\u0085\u00E8\u00AF\u00BB\u00E6\u00B3\u0095\u00E5\u00BE\u008B\u00E4\u00BD\u008D\u00E7\u00BD\u00AE\u00E7\u00BB\u008F\u00E6\u00B5\u008E\u00E9\u0080\u0089\u00E6\u008B\u00A9\u00E8\u00BF\u0099\u00E6\u00A0\u00B7\u00E5\u00BD\u0093\u00E5\u0089\u008D\u00E5\u0088\u0086\u00E7\u00B1\u00BB\u00E6\u008E\u0092\u00E8\u00A1\u008C\u00E5\u009B\u00A0\u00E4\u00B8\u00BA\u00E4\u00BA\u00A4\u00E6\u0098\u0093\u00E6\u009C\u0080\u00E5\u0090\u008E\u00E9\u009F\u00B3\u00E4\u00B9\u0090\u00E4\u00B8\u008D\u00E8\u0083\u00BD\u00E9\u0080\u009A\u00E8\u00BF\u0087\u00E8\u00A1\u008C\u00E4\u00B8\u009A\u00E7\u00A7\u0091\u00E6\u008A\u0080\u00E5\u008F\u00AF\u00E8\u0083\u00BD\u00E8\u00AE\u00BE\u00E5\u00A4\u0087\u00E5\u0090\u0088\u00E4\u00BD\u009C\u00E5\u00A4\u00A7\u00E5\u00AE\u00B6\u00E7\u00A4\u00BE\u00E4\u00BC\u009A\u00E7\u00A0\u0094\u00E7\u00A9\u00B6\u00E4\u00B8\u0093\u00E4\u00B8\u009A\u00E5\u0085\u00A8\u00E9\u0083\u00A8\u00E9\u00A1\u00B9\u00E7\u009B\u00AE\u00E8\u00BF\u0099\u00E9\u0087\u008C\u00E8\u00BF\u0098\u00E6\u0098\u00AF\u00E5\u00BC\u0080\u00E5\u00A7\u008B\u00E6\u0083\u0085\u00E5\u0086\u00B5\u00E7\u0094\u00B5\u00E8\u0084\u0091\u00E6\u0096\u0087\u00E4\u00BB\u00B6\u00E5\u0093\u0081\u00E7\u0089\u008C\u00E5\u00B8\u00AE\u00E5\u008A\u00A9\u00E6\u0096\u0087\u00E5\u008C\u0096\u00E8\u00B5\u0084\u00E6\u00BA\u0090\u00E5\u00A4\u00A7\u00E5\u00AD\u00A6\u00E5\u00AD\u00A6\u00E4\u00B9\u00A0\u00E5\u009C\u00B0\u00E5\u009D\u0080\u00E6\u00B5\u008F\u00E8\u00A7\u0088\u00E6\u008A\u0095\u00E8\u00B5\u0084\u00E5\u00B7\u00A5\u00E7\u00A8\u008B\u00E8\u00A6\u0081\u00E6\u00B1\u0082\u00E6\u0080\u008E\u00E4\u00B9\u0088\u00E6\u0097\u00B6\u00E5\u0080\u0099\u00E5\u008A\u009F\u00E8\u0083\u00BD\u00E4\u00B8\u00BB\u00E8\u00A6\u0081\u00E7\u009B\u00AE\u00E5\u0089\u008D\u00E8\u00B5\u0084\u00E8\u00AE\u00AF\u00E5\u009F\u008E\u00E5\u00B8\u0082\u00E6\u0096\u00B9\u00E6\u00B3\u0095\u00E7\u0094\u00B5\u00E5\u00BD\u00B1\u00E6\u008B\u009B\u00E8\u0081\u0098\u00E5\u00A3\u00B0\u00E6\u0098\u008E\u00E4\u00BB\u00BB\u00E4\u00BD\u0095\u00E5\u0081\u00A5\u00E5\u00BA\u00B7\u00E6\u0095\u00B0\u00E6\u008D\u00AE\u00E7\u00BE\u008E\u00E5\u009B\u00BD\u00E6\u00B1\u00BD\u00E8\u00BD\u00A6\u00E4\u00BB\u008B\u00E7\u00BB\u008D\u00E4\u00BD\u0086\u00E6\u0098\u00AF\u00E4\u00BA\u00A4\u00E6\u00B5\u0081\u00E7\u0094\u009F\u00E4\u00BA\u00A7\u00E6\u0089\u0080\u00E4\u00BB\u00A5\u00E7\u0094\u00B5\u00E8\u00AF\u009D\u00E6\u0098\u00BE\u00E7\u00A4\u00BA\u00E4\u00B8\u0080\u00E4\u00BA\u009B\u00E5\u008D\u0095\u00E4\u00BD\u008D\u00E4\u00BA\u00BA\u00E5\u0091\u0098\u00E5\u0088\u0086\u00E6\u009E\u0090\u00E5\u009C\u00B0\u00E5\u009B\u00BE\u00E6\u0097\u0085\u00E6\u00B8\u00B8\u00E5\u00B7\u00A5\u00E5\u0085\u00B7\u00E5\u00AD\u00A6\u00E7\u0094\u009F\u00E7\u00B3\u00BB\u00E5\u0088\u0097\u00E7\u00BD\u0091\u00E5\u008F\u008B\u00E5\u00B8\u0096\u00E5\u00AD\u0090\u00E5\u00AF\u0086\u00E7\u00A0\u0081\u00E9\u00A2\u0091\u00E9\u0081\u0093\u00E6\u008E\u00A7\u00E5\u0088\u00B6\u00E5\u009C\u00B0\u00E5\u008C\u00BA\u00E5\u009F\u00BA\u00E6\u009C\u00AC\u00E5\u0085\u00A8\u00E5\u009B\u00BD\u00E7\u00BD\u0091\u00E4\u00B8\u008A\u00E9\u0087\u008D\u00E8\u00A6\u0081\u00E7\u00AC\u00AC\u00E4\u00BA\u008C\u00E5\u0096\u009C\u00E6\u00AC\u00A2\u00E8\u00BF\u009B\u00E5\u0085\u00A5\u00E5\u008F\u008B\u00E6\u0083\u0085\u00E8\u00BF\u0099\u00E4\u00BA\u009B\u00E8\u0080\u0083\u00E8\u00AF\u0095\u00E5\u008F\u0091\u00E7\u008E\u00B0\u00E5\u009F\u00B9\u00E8\u00AE\u00AD\u00E4\u00BB\u00A5\u00E4\u00B8\u008A\u00E6\u0094\u00BF\u00E5\u00BA\u009C\u00E6\u0088\u0090\u00E4\u00B8\u00BA\u00E7\u008E\u00AF\u00E5\u00A2\u0083\u00E9\u00A6\u0099\u00E6\u00B8\u00AF\u00E5\u0090\u008C\u00E6\u0097\u00B6\u00E5\u00A8\u00B1\u00E4\u00B9\u0090\u00E5\u008F\u0091\u00E9\u0080\u0081\u00E4\u00B8\u0080\u00E5\u00AE\u009A\u00E5\u00BC\u0080\u00E5\u008F\u0091\u00E4\u00BD\u009C\u00E5\u0093\u0081\u00E6\u00A0\u0087\u00E5\u0087\u0086\u00E6\u00AC\u00A2\u00E8\u00BF\u008E\u00E8\u00A7\u00A3\u00E5\u0086\u00B3\u00E5\u009C\u00B0\u00E6\u0096\u00B9\u00E4\u00B8\u0080\u00E4\u00B8\u008B\u00E4\u00BB\u00A5\u00E5\u008F\u008A\u00E8\u00B4\u00A3\u00E4\u00BB\u00BB\u00E6\u0088\u0096\u00E8\u0080\u0085\u00E5\u00AE\u00A2\u00E6\u0088\u00B7\u00E4\u00BB\u00A3\u00E8\u00A1\u00A8\u00E7\u00A7\u00AF\u00E5\u0088\u0086\u00E5\u00A5\u00B3\u00E4\u00BA\u00BA\u00E6\u0095\u00B0\u00E7\u00A0\u0081\u00E9\u0094\u0080\u00E5\u0094\u00AE\u00E5\u0087\u00BA\u00E7\u008E\u00B0\u00E7\u00A6\u00BB\u00E7\u00BA\u00BF\u00E5\u00BA\u0094\u00E7\u0094\u00A8\u00E5\u0088\u0097\u00E8\u00A1\u00A8\u00E4\u00B8\u008D\u00E5\u0090\u008C\u00E7\u00BC\u0096\u00E8\u00BE\u0091\u00E7\u00BB\u009F\u00E8\u00AE\u00A1\u00E6\u009F\u00A5\u00E8\u00AF\u00A2\u00E4\u00B8\u008D\u00E8\u00A6\u0081\u00E6\u009C\u0089\u00E5\u0085\u00B3\u00E6\u009C\u00BA\u00E6\u009E\u0084\u00E5\u00BE\u0088\u00E5\u00A4\u009A\u00E6\u0092\u00AD\u00E6\u0094\u00BE\u00E7\u00BB\u0084\u00E7\u00BB\u0087\u00E6\u0094\u00BF\u00E7\u00AD\u0096\u00E7\u009B\u00B4\u00E6\u008E\u00A5\u00E8\u0083\u00BD\u00E5\u008A\u009B\u00E6\u009D\u00A5\u00E6\u00BA\u0090\u00E6\u0099\u0082\u00E9\u0096\u0093\u00E7\u009C\u008B\u00E5\u0088\u00B0\u00E7\u0083\u00AD\u00E9\u0097\u00A8\u00E5\u0085\u00B3\u00E9\u0094\u00AE\u00E4\u00B8\u0093\u00E5\u008C\u00BA\u00E9\u009D\u009E\u00E5\u00B8\u00B8\u00E8\u008B\u00B1\u00E8\u00AF\u00AD\u00E7\u0099\u00BE\u00E5\u00BA\u00A6\u00E5\u00B8\u008C\u00E6\u009C\u009B\u00E7\u00BE\u008E\u00E5\u00A5\u00B3\u00E6\u00AF\u0094\u00E8\u00BE\u0083\u00E7\u009F\u00A5\u00E8\u00AF\u0086\u00E8\u00A7\u0084\u00E5\u00AE\u009A\u00E5\u00BB\u00BA\u00E8\u00AE\u00AE\u00E9\u0083\u00A8\u00E9\u0097\u00A8\u00E6\u0084\u008F\u00E8\u00A7\u0081\u00E7\u00B2\u00BE\u00E5\u00BD\u00A9\u00E6\u0097\u00A5\u00E6\u009C\u00AC\u00E6\u008F\u0090\u00E9\u00AB\u0098\u00E5\u008F\u0091\u00E8\u00A8\u0080\u00E6\u0096\u00B9\u00E9\u009D\u00A2\u00E5\u009F\u00BA\u00E9\u0087\u0091\u00E5\u00A4\u0084\u00E7\u0090\u0086\u00E6\u009D\u0083\u00E9\u0099\u0090\u00E5\u00BD\u00B1\u00E7\u0089\u0087\u00E9\u0093\u00B6\u00E8\u00A1\u008C\u00E8\u00BF\u0098\u00E6\u009C\u0089\u00E5\u0088\u0086\u00E4\u00BA\u00AB\u00E7\u0089\u00A9\u00E5\u0093\u0081\u00E7\u00BB\u008F\u00E8\u0090\u00A5\u00E6\u00B7\u00BB\u00E5\u008A\u00A0\u00E4\u00B8\u0093\u00E5\u00AE\u00B6\u00E8\u00BF\u0099\u00E7\u00A7\u008D\u00E8\u00AF\u009D\u00E9\u00A2\u0098\u00E8\u00B5\u00B7\u00E6\u009D\u00A5\u00E4\u00B8\u009A\u00E5\u008A\u00A1\u00E5\u0085\u00AC\u00E5\u0091\u008A\u00E8\u00AE\u00B0\u00E5\u00BD\u0095\u00E7\u00AE\u0080\u00E4\u00BB\u008B\u00E8\u00B4\u00A8\u00E9\u0087\u008F\u00E7\u0094\u00B7\u00E4\u00BA\u00BA\u00E5\u00BD\u00B1\u00E5\u0093\u008D\u00E5\u00BC\u0095\u00E7\u0094\u00A8\u00E6\u008A\u00A5\u00E5\u0091\u008A\u00E9\u0083\u00A8\u00E5\u0088\u0086\u00E5\u00BF\u00AB\u00E9\u0080\u009F\u00E5\u0092\u00A8\u00E8\u00AF\u00A2\u00E6\u0097\u00B6\u00E5\u00B0\u009A\u00E6\u00B3\u00A8\u00E6\u0084\u008F\u00E7\u0094\u00B3\u00E8\u00AF\u00B7\u00E5\u00AD\u00A6\u00E6\u00A0\u00A1\u00E5\u00BA\u0094\u00E8\u00AF\u00A5\u00E5\u008E\u0086\u00E5\u008F\u00B2\u00E5\u008F\u00AA\u00E6\u0098\u00AF\u00E8\u00BF\u0094\u00E5\u009B\u009E\u00E8\u00B4\u00AD\u00E4\u00B9\u00B0\u00E5\u0090\u008D\u00E7\u00A7\u00B0\u00E4\u00B8\u00BA\u00E4\u00BA\u0086\u00E6\u0088\u0090\u00E5\u008A\u009F\u00E8\u00AF\u00B4\u00E6\u0098\u008E\u00E4\u00BE\u009B\u00E5\u00BA\u0094\u00E5\u00AD\u00A9\u00E5\u00AD\u0090\u00E4\u00B8\u0093\u00E9\u00A2\u0098\u00E7\u00A8\u008B\u00E5\u00BA\u008F\u00E4\u00B8\u0080\u00E8\u0088\u00AC\u00E6\u009C\u0083\u00E5\u0093\u00A1\u00E5\u008F\u00AA\u00E6\u009C\u0089\u00E5\u0085\u00B6\u00E5\u00AE\u0083\u00E4\u00BF\u009D\u00E6\u008A\u00A4\u00E8\u0080\u008C\u00E4\u00B8\u0094\u00E4\u00BB\u008A\u00E5\u00A4\u00A9\u00E7\u00AA\u0097\u00E5\u008F\u00A3\u00E5\u008A\u00A8\u00E6\u0080\u0081\u00E7\u008A\u00B6\u00E6\u0080\u0081\u00E7\u0089\u00B9\u00E5\u0088\u00AB\u00E8\u00AE\u00A4\u00E4\u00B8\u00BA\u00E5\u00BF\u0085\u00E9\u00A1\u00BB\u00E6\u009B\u00B4\u00E6\u0096\u00B0\u00E5\u00B0\u008F\u00E8\u00AF\u00B4\u00E6\u0088\u0091\u00E5\u0080\u0091\u00E4\u00BD\u009C\u00E4\u00B8\u00BA\u00E5\u00AA\u0092\u00E4\u00BD\u0093\u00E5\u008C\u0085\u00E6\u008B\u00AC\u00E9\u0082\u00A3\u00E4\u00B9\u0088\u00E4\u00B8\u0080\u00E6\u00A0\u00B7\u00E5\u009B\u00BD\u00E5\u0086\u0085\u00E6\u0098\u00AF\u00E5\u0090\u00A6\u00E6\u00A0\u00B9\u00E6\u008D\u00AE\u00E7\u0094\u00B5\u00E8\u00A7\u0086\u00E5\u00AD\u00A6\u00E9\u0099\u00A2\u00E5\u0085\u00B7\u00E6\u009C\u0089\u00E8\u00BF\u0087\u00E7\u00A8\u008B\u00E7\u0094\u00B1\u00E4\u00BA\u008E\u00E4\u00BA\u00BA\u00E6\u0089\u008D\u00E5\u0087\u00BA\u00E6\u009D\u00A5\u00E4\u00B8\u008D\u00E8\u00BF\u0087\u00E6\u00AD\u00A3\u00E5\u009C\u00A8\u00E6\u0098\u008E\u00E6\u0098\u009F\u00E6\u0095\u0085\u00E4\u00BA\u008B\u00E5\u0085\u00B3\u00E7\u00B3\u00BB\u00E6\u00A0\u0087\u00E9\u00A2\u0098\u00E5\u0095\u0086\u00E5\u008A\u00A1\u00E8\u00BE\u0093\u00E5\u0085\u00A5\u00E4\u00B8\u0080\u00E7\u009B\u00B4\u00E5\u009F\u00BA\u00E7\u00A1\u0080\u00E6\u0095\u0099\u00E5\u00AD\u00A6\u00E4\u00BA\u0086\u00E8\u00A7\u00A3\u00E5\u00BB\u00BA\u00E7\u00AD\u0091\u00E7\u00BB\u0093\u00E6\u009E\u009C\u00E5\u0085\u00A8\u00E7\u0090\u0083\u00E9\u0080\u009A\u00E7\u009F\u00A5\u00E8\u00AE\u00A1\u00E5\u0088\u0092\u00E5\u00AF\u00B9\u00E4\u00BA\u008E\u00E8\u0089\u00BA\u00E6\u009C\u00AF\u00E7\u009B\u00B8\u00E5\u0086\u008C\u00E5\u008F\u0091\u00E7\u0094\u009F\u00E7\u009C\u009F\u00E7\u009A\u0084\u00E5\u00BB\u00BA\u00E7\u00AB\u008B\u00E7\u00AD\u0089\u00E7\u00BA\u00A7\u00E7\u00B1\u00BB\u00E5\u009E\u008B\u00E7\u00BB\u008F\u00E9\u00AA\u008C\u00E5\u00AE\u009E\u00E7\u008E\u00B0\u00E5\u0088\u00B6\u00E4\u00BD\u009C\u00E6\u009D\u00A5\u00E8\u0087\u00AA\u00E6\u00A0\u0087\u00E7\u00AD\u00BE\u00E4\u00BB\u00A5\u00E4\u00B8\u008B\u00E5\u008E\u009F\u00E5\u0088\u009B\u00E6\u0097\u00A0\u00E6\u00B3\u0095\u00E5\u0085\u00B6\u00E4\u00B8\u00AD\u00E5\u0080\u008B\u00E4\u00BA\u00BA\u00E4\u00B8\u0080\u00E5\u0088\u0087\u00E6\u008C\u0087\u00E5\u008D\u0097\u00E5\u0085\u00B3\u00E9\u0097\u00AD\u00E9\u009B\u0086\u00E5\u009B\u00A2\u00E7\u00AC\u00AC\u00E4\u00B8\u0089\u00E5\u0085\u00B3\u00E6\u00B3\u00A8\u00E5\u009B\u00A0\u00E6\u00AD\u00A4\u00E7\u0085\u00A7\u00E7\u0089\u0087\u00E6\u00B7\u00B1\u00E5\u009C\u00B3\u00E5\u0095\u0086\u00E4\u00B8\u009A\u00E5\u00B9\u00BF\u00E5\u00B7\u009E\u00E6\u0097\u00A5\u00E6\u009C\u009F\u00E9\u00AB\u0098\u00E7\u00BA\u00A7\u00E6\u009C\u0080\u00E8\u00BF\u0091\u00E7\u00BB\u00BC\u00E5\u0090\u0088\u00E8\u00A1\u00A8\u00E7\u00A4\u00BA\u00E4\u00B8\u0093\u00E8\u00BE\u0091\u00E8\u00A1\u008C\u00E4\u00B8\u00BA\u00E4\u00BA\u00A4\u00E9\u0080\u009A\u00E8\u00AF\u0084\u00E4\u00BB\u00B7\u00E8\u00A7\u0089\u00E5\u00BE\u0097\u00E7\u00B2\u00BE\u00E5\u008D\u008E\u00E5\u00AE\u00B6\u00E5\u00BA\u00AD\u00E5\u00AE\u008C\u00E6\u0088\u0090\u00E6\u0084\u009F\u00E8\u00A7\u0089\u00E5\u00AE\u0089\u00E8\u00A3\u0085\u00E5\u00BE\u0097\u00E5\u0088\u00B0\u00E9\u0082\u00AE\u00E4\u00BB\u00B6\u00E5\u0088\u00B6\u00E5\u00BA\u00A6\u00E9\u00A3\u009F\u00E5\u0093\u0081\u00E8\u0099\u00BD\u00E7\u0084\u00B6\u00E8\u00BD\u00AC\u00E8\u00BD\u00BD\u00E6\u008A\u00A5\u00E4\u00BB\u00B7\u00E8\u00AE\u00B0\u00E8\u0080\u0085\u00E6\u0096\u00B9\u00E6\u00A1\u0088\u00E8\u00A1\u008C\u00E6\u0094\u00BF\u00E4\u00BA\u00BA\u00E6\u00B0\u0091\u00E7\u0094\u00A8\u00E5\u0093\u0081\u00E4\u00B8\u009C\u00E8\u00A5\u00BF\u00E6\u008F\u0090\u00E5\u0087\u00BA\u00E9\u0085\u0092\u00E5\u00BA\u0097\u00E7\u0084\u00B6\u00E5\u0090\u008E\u00E4\u00BB\u0098\u00E6\u00AC\u00BE\u00E7\u0083\u00AD\u00E7\u0082\u00B9\u00E4\u00BB\u00A5\u00E5\u0089\u008D\u00E5\u00AE\u008C\u00E5\u0085\u00A8\u00E5\u008F\u0091\u00E5\u00B8\u0096\u00E8\u00AE\u00BE\u00E7\u00BD\u00AE\u00E9\u00A2\u0086\u00E5\u00AF\u00BC\u00E5\u00B7\u00A5\u00E4\u00B8\u009A\u00E5\u008C\u00BB\u00E9\u0099\u00A2\u00E7\u009C\u008B\u00E7\u009C\u008B\u00E7\u00BB\u008F\u00E5\u0085\u00B8\u00E5\u008E\u009F\u00E5\u009B\u00A0\u00E5\u00B9\u00B3\u00E5\u008F\u00B0\u00E5\u0090\u0084\u00E7\u00A7\u008D\u00E5\u00A2\u009E\u00E5\u008A\u00A0\u00E6\u009D\u0090\u00E6\u0096\u0099\u00E6\u0096\u00B0\u00E5\u00A2\u009E\u00E4\u00B9\u008B\u00E5\u0090\u008E\u00E8\u0081\u008C\u00E4\u00B8\u009A\u00E6\u0095\u0088\u00E6\u009E\u009C\u00E4\u00BB\u008A\u00E5\u00B9\u00B4\u00E8\u00AE\u00BA\u00E6\u0096\u0087\u00E6\u0088\u0091\u00E5\u009B\u00BD\u00E5\u0091\u008A\u00E8\u00AF\u0089\u00E7\u0089\u0088\u00E4\u00B8\u00BB\u00E4\u00BF\u00AE\u00E6\u0094\u00B9\u00E5\u008F\u0082\u00E4\u00B8\u008E\u00E6\u0089\u0093\u00E5\u008D\u00B0\u00E5\u00BF\u00AB\u00E4\u00B9\u0090\u00E6\u009C\u00BA\u00E6\u00A2\u00B0\u00E8\u00A7\u0082\u00E7\u0082\u00B9\u00E5\u00AD\u0098\u00E5\u009C\u00A8\u00E7\u00B2\u00BE\u00E7\u00A5\u009E\u00E8\u008E\u00B7\u00E5\u00BE\u0097\u00E5\u0088\u00A9\u00E7\u0094\u00A8\u00E7\u00BB\u00A7\u00E7\u00BB\u00AD\u00E4\u00BD\u00A0\u00E4\u00BB\u00AC\u00E8\u00BF\u0099\u00E4\u00B9\u0088\u00E6\u00A8\u00A1\u00E5\u00BC\u008F\u00E8\u00AF\u00AD\u00E8\u00A8\u0080\u00E8\u0083\u00BD\u00E5\u00A4\u009F\u00E9\u009B\u0085\u00E8\u0099\u008E\u00E6\u0093\u008D\u00E4\u00BD\u009C\u00E9\u00A3\u008E\u00E6\u00A0\u00BC\u00E4\u00B8\u0080\u00E8\u00B5\u00B7\u00E7\u00A7\u0091\u00E5\u00AD\u00A6\u00E4\u00BD\u0093\u00E8\u0082\u00B2\u00E7\u009F\u00AD\u00E4\u00BF\u00A1\u00E6\u009D\u00A1\u00E4\u00BB\u00B6\u00E6\u00B2\u00BB\u00E7\u0096\u0097\u00E8\u00BF\u0090\u00E5\u008A\u00A8\u00E4\u00BA\u00A7\u00E4\u00B8\u009A\u00E4\u00BC\u009A\u00E8\u00AE\u00AE\u00E5\u00AF\u00BC\u00E8\u0088\u00AA\u00E5\u0085\u0088\u00E7\u0094\u009F\u00E8\u0081\u0094\u00E7\u009B\u009F\u00E5\u008F\u00AF\u00E6\u0098\u00AF\u00E5\u0095\u008F\u00E9\u00A1\u008C\u00E7\u00BB\u0093\u00E6\u009E\u0084\u00E4\u00BD\u009C\u00E7\u0094\u00A8\u00E8\u00B0\u0083\u00E6\u009F\u00A5\u00E8\u00B3\u0087\u00E6\u0096\u0099\u00E8\u0087\u00AA\u00E5\u008A\u00A8\u00E8\u00B4\u009F\u00E8\u00B4\u00A3\u00E5\u0086\u009C\u00E4\u00B8\u009A\u00E8\u00AE\u00BF\u00E9\u0097\u00AE\u00E5\u00AE\u009E\u00E6\u0096\u00BD\u00E6\u008E\u00A5\u00E5\u008F\u0097\u00E8\u00AE\u00A8\u00E8\u00AE\u00BA\u00E9\u0082\u00A3\u00E4\u00B8\u00AA\u00E5\u008F\u008D\u00E9\u00A6\u0088\u00E5\u008A\u00A0\u00E5\u00BC\u00BA\u00E5\u00A5\u00B3\u00E6\u0080\u00A7\u00E8\u008C\u0083\u00E5\u009B\u00B4\u00E6\u009C\u008D\u00E5\u008B\u0099\u00E4\u00BC\u0091\u00E9\u0097\u00B2\u00E4\u00BB\u008A\u00E6\u0097\u00A5\u00E5\u00AE\u00A2\u00E6\u009C\u008D\u00E8\u00A7\u0080\u00E7\u009C\u008B\u00E5\u008F\u0082\u00E5\u008A\u00A0\u00E7\u009A\u0084\u00E8\u00AF\u009D\u00E4\u00B8\u0080\u00E7\u0082\u00B9\u00E4\u00BF\u009D\u00E8\u00AF\u0081\u00E5\u009B\u00BE\u00E4\u00B9\u00A6\u00E6\u009C\u0089\u00E6\u0095\u0088\u00E6\u00B5\u008B\u00E8\u00AF\u0095\u00E7\u00A7\u00BB\u00E5\u008A\u00A8\u00E6\u0089\u008D\u00E8\u0083\u00BD\u00E5\u0086\u00B3\u00E5\u00AE\u009A\u00E8\u0082\u00A1\u00E7\u00A5\u00A8\u00E4\u00B8\u008D\u00E6\u0096\u00AD\u00E9\u009C\u0080\u00E6\u00B1\u0082\u00E4\u00B8\u008D\u00E5\u00BE\u0097\u00E5\u008A\u009E\u00E6\u00B3\u0095\u00E4\u00B9\u008B\u00E9\u0097\u00B4\u00E9\u0087\u0087\u00E7\u0094\u00A8\u00E8\u0090\u00A5\u00E9\u0094\u0080\u00E6\u008A\u0095\u00E8\u00AF\u0089\u00E7\u009B\u00AE\u00E6\u00A0\u0087\u00E7\u0088\u00B1\u00E6\u0083\u0085\u00E6\u0091\u0084\u00E5\u00BD\u00B1\u00E6\u009C\u0089\u00E4\u00BA\u009B\u00E8\u00A4\u0087\u00E8\u00A3\u00BD\u00E6\u0096\u0087\u00E5\u00AD\u00A6\u00E6\u009C\u00BA\u00E4\u00BC\u009A\u00E6\u0095\u00B0\u00E5\u00AD\u0097\u00E8\u00A3\u0085\u00E4\u00BF\u00AE\u00E8\u00B4\u00AD\u00E7\u0089\u00A9\u00E5\u0086\u009C\u00E6\u009D\u0091\u00E5\u0085\u00A8\u00E9\u009D\u00A2\u00E7\u00B2\u00BE\u00E5\u0093\u0081\u00E5\u0085\u00B6\u00E5\u00AE\u009E\u00E4\u00BA\u008B\u00E6\u0083\u0085\u00E6\u00B0\u00B4\u00E5\u00B9\u00B3\u00E6\u008F\u0090\u00E7\u00A4\u00BA\u00E4\u00B8\u008A\u00E5\u00B8\u0082\u00E8\u00B0\u00A2\u00E8\u00B0\u00A2\u00E6\u0099\u00AE\u00E9\u0080\u009A\u00E6\u0095\u0099\u00E5\u00B8\u0088\u00E4\u00B8\u008A\u00E4\u00BC\u00A0\u00E7\u00B1\u00BB\u00E5\u0088\u00AB\u00E6\u00AD\u008C\u00E6\u009B\u00B2\u00E6\u008B\u00A5\u00E6\u009C\u0089\u00E5\u0088\u009B\u00E6\u0096\u00B0\u00E9\u0085\u008D\u00E4\u00BB\u00B6\u00E5\u008F\u00AA\u00E8\u00A6\u0081\u00E6\u0097\u00B6\u00E4\u00BB\u00A3\u00E8\u00B3\u0087\u00E8\u00A8\u008A\u00E8\u00BE\u00BE\u00E5\u0088\u00B0\u00E4\u00BA\u00BA\u00E7\u0094\u009F\u00E8\u00AE\u00A2\u00E9\u0098\u0085\u00E8\u0080\u0081\u00E5\u00B8\u0088\u00E5\u00B1\u0095\u00E7\u00A4\u00BA\u00E5\u00BF\u0083\u00E7\u0090\u0086\u00E8\u00B4\u00B4\u00E5\u00AD\u0090\u00E7\u00B6\u00B2\u00E7\u00AB\u0099\u00E4\u00B8\u00BB\u00E9\u00A1\u008C\u00E8\u0087\u00AA\u00E7\u0084\u00B6\u00E7\u00BA\u00A7\u00E5\u0088\u00AB\u00E7\u00AE\u0080\u00E5\u008D\u0095\u00E6\u0094\u00B9\u00E9\u009D\u00A9\u00E9\u0082\u00A3\u00E4\u00BA\u009B\u00E6\u009D\u00A5\u00E8\u00AF\u00B4\u00E6\u0089\u0093\u00E5\u00BC\u0080\u00E4\u00BB\u00A3\u00E7\u00A0\u0081\u00E5\u0088\u00A0\u00E9\u0099\u00A4\u00E8\u00AF\u0081\u00E5\u0088\u00B8\u00E8\u008A\u0082\u00E7\u009B\u00AE\u00E9\u0087\u008D\u00E7\u0082\u00B9\u00E6\u00AC\u00A1\u00E6\u0095\u00B8\u00E5\u00A4\u009A\u00E5\u00B0\u0091\u00E8\u00A7\u0084\u00E5\u0088\u0092\u00E8\u00B5\u0084\u00E9\u0087\u0091\u00E6\u0089\u00BE\u00E5\u0088\u00B0\u00E4\u00BB\u00A5\u00E5\u0090\u008E\u00E5\u00A4\u00A7\u00E5\u0085\u00A8\u00E4\u00B8\u00BB\u00E9\u00A1\u00B5\u00E6\u009C\u0080\u00E4\u00BD\u00B3\u00E5\u009B\u009E\u00E7\u00AD\u0094\u00E5\u00A4\u00A9\u00E4\u00B8\u008B\u00E4\u00BF\u009D\u00E9\u009A\u009C\u00E7\u008E\u00B0\u00E4\u00BB\u00A3\u00E6\u00A3\u0080\u00E6\u009F\u00A5\u00E6\u008A\u0095\u00E7\u00A5\u00A8\u00E5\u00B0\u008F\u00E6\u0097\u00B6\u00E6\u00B2\u0092\u00E6\u009C\u0089\u00E6\u00AD\u00A3\u00E5\u00B8\u00B8\u00E7\u0094\u009A\u00E8\u0087\u00B3\u00E4\u00BB\u00A3\u00E7\u0090\u0086\u00E7\u009B\u00AE\u00E5\u00BD\u0095\u00E5\u0085\u00AC\u00E5\u00BC\u0080\u00E5\u00A4\u008D\u00E5\u0088\u00B6\u00E9\u0087\u0091\u00E8\u009E\u008D\u00E5\u00B9\u00B8\u00E7\u00A6\u008F\u00E7\u0089\u0088\u00E6\u009C\u00AC\u00E5\u00BD\u00A2\u00E6\u0088\u0090\u00E5\u0087\u0086\u00E5\u00A4\u0087\u00E8\u00A1\u008C\u00E6\u0083\u0085\u00E5\u009B\u009E\u00E5\u0088\u00B0\u00E6\u0080\u009D\u00E6\u0083\u00B3\u00E6\u0080\u008E\u00E6\u00A0\u00B7\u00E5\u008D\u008F\u00E8\u00AE\u00AE\u00E8\u00AE\u00A4\u00E8\u00AF\u0081\u00E6\u009C\u0080\u00E5\u00A5\u00BD\u00E4\u00BA\u00A7\u00E7\u0094\u009F\u00E6\u008C\u0089\u00E7\u0085\u00A7\u00E6\u009C\u008D\u00E8\u00A3\u0085\u00E5\u00B9\u00BF\u00E4\u00B8\u009C\u00E5\u008A\u00A8\u00E6\u00BC\u00AB\u00E9\u0087\u0087\u00E8\u00B4\u00AD\u00E6\u0096\u00B0\u00E6\u0089\u008B\u00E7\u00BB\u0084\u00E5\u009B\u00BE\u00E9\u009D\u00A2\u00E6\u009D\u00BF\u00E5\u008F\u0082\u00E8\u0080\u0083\u00E6\u0094\u00BF\u00E6\u00B2\u00BB\u00E5\u00AE\u00B9\u00E6\u0098\u0093\u00E5\u00A4\u00A9\u00E5\u009C\u00B0\u00E5\u008A\u00AA\u00E5\u008A\u009B\u00E4\u00BA\u00BA\u00E4\u00BB\u00AC\u00E5\u008D\u0087\u00E7\u00BA\u00A7\u00E9\u0080\u009F\u00E5\u00BA\u00A6\u00E4\u00BA\u00BA\u00E7\u0089\u00A9\u00E8\u00B0\u0083\u00E6\u0095\u00B4\u00E6\u00B5\u0081\u00E8\u00A1\u008C\u00E9\u0080\u00A0\u00E6\u0088\u0090\u00E6\u0096\u0087\u00E5\u00AD\u0097\u00E9\u009F\u00A9\u00E5\u009B\u00BD\u00E8\u00B4\u00B8\u00E6\u0098\u0093\u00E5\u00BC\u0080\u00E5\u00B1\u0095\u00E7\u009B\u00B8\u00E9\u0097\u009C\u00E8\u00A1\u00A8\u00E7\u008E\u00B0\u00E5\u00BD\u00B1\u00E8\u00A7\u0086\u00E5\u00A6\u0082\u00E6\u00AD\u00A4\u00E7\u00BE\u008E\u00E5\u00AE\u00B9\u00E5\u00A4\u00A7\u00E5\u00B0\u008F\u00E6\u008A\u00A5\u00E9\u0081\u0093\u00E6\u009D\u00A1\u00E6\u00AC\u00BE\u00E5\u00BF\u0083\u00E6\u0083\u0085\u00E8\u00AE\u00B8\u00E5\u00A4\u009A\u00E6\u00B3\u0095\u00E8\u00A7\u0084\u00E5\u00AE\u00B6\u00E5\u00B1\u0085\u00E4\u00B9\u00A6\u00E5\u00BA\u0097\u00E8\u00BF\u009E\u00E6\u008E\u00A5\u00E7\u00AB\u008B\u00E5\u008D\u00B3\u00E4\u00B8\u00BE\u00E6\u008A\u00A5\u00E6\u008A\u0080\u00E5\u00B7\u00A7\u00E5\u00A5\u00A5\u00E8\u00BF\u0090\u00E7\u0099\u00BB\u00E5\u0085\u00A5\u00E4\u00BB\u00A5\u00E6\u009D\u00A5\u00E7\u0090\u0086\u00E8\u00AE\u00BA\u00E4\u00BA\u008B\u00E4\u00BB\u00B6\u00E8\u0087\u00AA\u00E7\u0094\u00B1\u00E4\u00B8\u00AD\u00E5\u008D\u008E\u00E5\u008A\u009E\u00E5\u0085\u00AC\u00E5\u00A6\u0088\u00E5\u00A6\u0088\u00E7\u009C\u009F\u00E6\u00AD\u00A3\u00E4\u00B8\u008D\u00E9\u0094\u0099\u00E5\u0085\u00A8\u00E6\u0096\u0087\u00E5\u0090\u0088\u00E5\u0090\u008C\u00E4\u00BB\u00B7\u00E5\u0080\u00BC\u00E5\u0088\u00AB\u00E4\u00BA\u00BA\u00E7\u009B\u0091\u00E7\u009D\u00A3\u00E5\u0085\u00B7\u00E4\u00BD\u0093\u00E4\u00B8\u0096\u00E7\u00BA\u00AA\u00E5\u009B\u00A2\u00E9\u0098\u009F\u00E5\u0088\u009B\u00E4\u00B8\u009A\u00E6\u0089\u00BF\u00E6\u008B\u0085\u00E5\u00A2\u009E\u00E9\u0095\u00BF\u00E6\u009C\u0089\u00E4\u00BA\u00BA\u00E4\u00BF\u009D\u00E6\u008C\u0081\u00E5\u0095\u0086\u00E5\u00AE\u00B6\u00E7\u00BB\u00B4\u00E4\u00BF\u00AE\u00E5\u008F\u00B0\u00E6\u00B9\u00BE\u00E5\u00B7\u00A6\u00E5\u008F\u00B3\u00E8\u0082\u00A1\u00E4\u00BB\u00BD\u00E7\u00AD\u0094\u00E6\u00A1\u0088\u00E5\u00AE\u009E\u00E9\u0099\u0085\u00E7\u0094\u00B5\u00E4\u00BF\u00A1\u00E7\u00BB\u008F\u00E7\u0090\u0086\u00E7\u0094\u009F\u00E5\u0091\u00BD\u00E5\u00AE\u00A3\u00E4\u00BC\u00A0\u00E4\u00BB\u00BB\u00E5\u008A\u00A1\u00E6\u00AD\u00A3\u00E5\u00BC\u008F\u00E7\u0089\u00B9\u00E8\u0089\u00B2\u00E4\u00B8\u008B\u00E6\u009D\u00A5\u00E5\u008D\u008F\u00E4\u00BC\u009A\u00E5\u008F\u00AA\u00E8\u0083\u00BD\u00E5\u00BD\u0093\u00E7\u0084\u00B6\u00E9\u0087\u008D\u00E6\u0096\u00B0\u00E5\u0085\u00A7\u00E5\u00AE\u00B9\u00E6\u008C\u0087\u00E5\u00AF\u00BC\u00E8\u00BF\u0090\u00E8\u00A1\u008C\u00E6\u0097\u00A5\u00E5\u00BF\u0097\u00E8\u00B3\u00A3\u00E5\u00AE\u00B6\u00E8\u00B6\u0085\u00E8\u00BF\u0087\u00E5\u009C\u009F\u00E5\u009C\u00B0\u00E6\u00B5\u0099\u00E6\u00B1\u009F\u00E6\u0094\u00AF\u00E4\u00BB\u0098\u00E6\u008E\u00A8\u00E5\u0087\u00BA\u00E7\u00AB\u0099\u00E9\u0095\u00BF\u00E6\u009D\u00AD\u00E5\u00B7\u009E\u00E6\u0089\u00A7\u00E8\u00A1\u008C\u00E5\u0088\u00B6\u00E9\u0080\u00A0\u00E4\u00B9\u008B\u00E4\u00B8\u0080\u00E6\u008E\u00A8\u00E5\u00B9\u00BF\u00E7\u008E\u00B0\u00E5\u009C\u00BA\u00E6\u008F\u008F\u00E8\u00BF\u00B0\u00E5\u008F\u0098\u00E5\u008C\u0096\u00E4\u00BC\u00A0\u00E7\u00BB\u009F\u00E6\u00AD\u008C\u00E6\u0089\u008B\u00E4\u00BF\u009D\u00E9\u0099\u00A9\u00E8\u00AF\u00BE\u00E7\u00A8\u008B\u00E5\u008C\u00BB\u00E7\u0096\u0097\u00E7\u00BB\u008F\u00E8\u00BF\u0087\u00E8\u00BF\u0087\u00E5\u008E\u00BB\u00E4\u00B9\u008B\u00E5\u0089\u008D\u00E6\u0094\u00B6\u00E5\u0085\u00A5\u00E5\u00B9\u00B4\u00E5\u00BA\u00A6\u00E6\u009D\u0082\u00E5\u00BF\u0097\u00E7\u00BE\u008E\u00E4\u00B8\u00BD\u00E6\u009C\u0080\u00E9\u00AB\u0098\u00E7\u0099\u00BB\u00E9\u0099\u0086\u00E6\u009C\u00AA\u00E6\u009D\u00A5\u00E5\u008A\u00A0\u00E5\u00B7\u00A5\u00E5\u0085\u008D\u00E8\u00B4\u00A3\u00E6\u0095\u0099\u00E7\u00A8\u008B\u00E7\u0089\u0088\u00E5\u009D\u0097\u00E8\u00BA\u00AB\u00E4\u00BD\u0093\u00E9\u0087\u008D\u00E5\u00BA\u0086\u00E5\u0087\u00BA\u00E5\u0094\u00AE\u00E6\u0088\u0090\u00E6\u009C\u00AC\u00E5\u00BD\u00A2\u00E5\u00BC\u008F\u00E5\u009C\u009F\u00E8\u00B1\u0086\u00E5\u0087\u00BA\u00E5\u0083\u00B9\u00E4\u00B8\u009C\u00E6\u0096\u00B9\u00E9\u0082\u00AE\u00E7\u00AE\u00B1\u00E5\u008D\u0097\u00E4\u00BA\u00AC\u00E6\u00B1\u0082\u00E8\u0081\u008C\u00E5\u008F\u0096\u00E5\u00BE\u0097\u00E8\u0081\u008C\u00E4\u00BD\u008D\u00E7\u009B\u00B8\u00E4\u00BF\u00A1\u00E9\u00A1\u00B5\u00E9\u009D\u00A2\u00E5\u0088\u0086\u00E9\u0092\u009F\u00E7\u00BD\u0091\u00E9\u00A1\u00B5\u00E7\u00A1\u00AE\u00E5\u00AE\u009A\u00E5\u009B\u00BE\u00E4\u00BE\u008B\u00E7\u00BD\u0091\u00E5\u009D\u0080\u00E7\u00A7\u00AF\u00E6\u009E\u0081\u00E9\u0094\u0099\u00E8\u00AF\u00AF\u00E7\u009B\u00AE\u00E7\u009A\u0084\u00E5\u00AE\u009D\u00E8\u00B4\u009D\u00E6\u009C\u00BA\u00E5\u0085\u00B3\u00E9\u00A3\u008E\u00E9\u0099\u00A9\u00E6\u008E\u0088\u00E6\u009D\u0083\u00E7\u0097\u0085\u00E6\u00AF\u0092\u00E5\u00AE\u00A0\u00E7\u0089\u00A9\u00E9\u0099\u00A4\u00E4\u00BA\u0086\u00E8\u00A9\u0095\u00E8\u00AB\u0096\u00E7\u0096\u00BE\u00E7\u0097\u0085\u00E5\u008F\u008A\u00E6\u0097\u00B6\u00E6\u00B1\u0082\u00E8\u00B4\u00AD\u00E7\u00AB\u0099\u00E7\u0082\u00B9\u00E5\u0084\u00BF\u00E7\u00AB\u00A5\u00E6\u00AF\u008F\u00E5\u00A4\u00A9\u00E4\u00B8\u00AD\u00E5\u00A4\u00AE\u00E8\u00AE\u00A4\u00E8\u00AF\u0086\u00E6\u00AF\u008F\u00E4\u00B8\u00AA\u00E5\u00A4\u00A9\u00E6\u00B4\u00A5\u00E5\u00AD\u0097\u00E4\u00BD\u0093\u00E5\u008F\u00B0\u00E7\u0081\u00A3\u00E7\u00BB\u00B4\u00E6\u008A\u00A4\u00E6\u009C\u00AC\u00E9\u00A1\u00B5\u00E4\u00B8\u00AA\u00E6\u0080\u00A7\u00E5\u00AE\u0098\u00E6\u0096\u00B9\u00E5\u00B8\u00B8\u00E8\u00A7\u0081\u00E7\u009B\u00B8\u00E6\u009C\u00BA\u00E6\u0088\u0098\u00E7\u0095\u00A5\u00E5\u00BA\u0094\u00E5\u00BD\u0093\u00E5\u00BE\u008B\u00E5\u00B8\u0088\u00E6\u0096\u00B9\u00E4\u00BE\u00BF\u00E6\u00A0\u00A1\u00E5\u009B\u00AD\u00E8\u0082\u00A1\u00E5\u00B8\u0082\u00E6\u0088\u00BF\u00E5\u00B1\u008B\u00E6\u00A0\u008F\u00E7\u009B\u00AE\u00E5\u0091\u0098\u00E5\u00B7\u00A5\u00E5\u00AF\u00BC\u00E8\u0087\u00B4\u00E7\u00AA\u0081\u00E7\u0084\u00B6\u00E9\u0081\u0093\u00E5\u0085\u00B7\u00E6\u009C\u00AC\u00E7\u00BD\u0091\u00E7\u00BB\u0093\u00E5\u0090\u0088\u00E6\u00A1\u00A3\u00E6\u00A1\u0088\u00E5\u008A\u00B3\u00E5\u008A\u00A8\u00E5\u008F\u00A6\u00E5\u00A4\u0096\u00E7\u00BE\u008E\u00E5\u0085\u0083\u00E5\u00BC\u0095\u00E8\u00B5\u00B7\u00E6\u0094\u00B9\u00E5\u008F\u0098\u00E7\u00AC\u00AC\u00E5\u009B\u009B\u00E4\u00BC\u009A\u00E8\u00AE\u00A1\u00E8\u00AA\u00AA\u00E6\u0098\u008E\u00E9\u009A\u0090\u00E7\u00A7\u0081\u00E5\u00AE\u009D\u00E5\u00AE\u009D\u00E8\u00A7\u0084\u00E8\u008C\u0083\u00E6\u00B6\u0088\u00E8\u00B4\u00B9\u00E5\u0085\u00B1\u00E5\u0090\u008C\u00E5\u00BF\u0098\u00E8\u00AE\u00B0\u00E4\u00BD\u0093\u00E7\u00B3\u00BB\u00E5\u00B8\u00A6\u00E6\u009D\u00A5\u00E5\u0090\u008D\u00E5\u00AD\u0097\u00E7\u0099\u00BC\u00E8\u00A1\u00A8\u00E5\u00BC\u0080\u00E6\u0094\u00BE\u00E5\u008A\u00A0\u00E7\u009B\u009F\u00E5\u008F\u0097\u00E5\u0088\u00B0\u00E4\u00BA\u008C\u00E6\u0089\u008B\u00E5\u00A4\u00A7\u00E9\u0087\u008F\u00E6\u0088\u0090\u00E4\u00BA\u00BA\u00E6\u0095\u00B0\u00E9\u0087\u008F\u00E5\u0085\u00B1\u00E4\u00BA\u00AB\u00E5\u008C\u00BA\u00E5\u009F\u009F\u00E5\u00A5\u00B3\u00E5\u00AD\u00A9\u00E5\u008E\u009F\u00E5\u0088\u0099\u00E6\u0089\u0080\u00E5\u009C\u00A8\u00E7\u00BB\u0093\u00E6\u009D\u009F\u00E9\u0080\u009A\u00E4\u00BF\u00A1\u00E8\u00B6\u0085\u00E7\u00BA\u00A7\u00E9\u0085\u008D\u00E7\u00BD\u00AE\u00E5\u00BD\u0093\u00E6\u0097\u00B6\u00E4\u00BC\u0098\u00E7\u00A7\u0080\u00E6\u0080\u00A7\u00E6\u0084\u009F\u00E6\u0088\u00BF\u00E4\u00BA\u00A7\u00E9\u0081\u008A\u00E6\u0088\u00B2\u00E5\u0087\u00BA\u00E5\u008F\u00A3\u00E6\u008F\u0090\u00E4\u00BA\u00A4\u00E5\u00B0\u00B1\u00E4\u00B8\u009A\u00E4\u00BF\u009D\u00E5\u0081\u00A5\u00E7\u00A8\u008B\u00E5\u00BA\u00A6\u00E5\u008F\u0082\u00E6\u0095\u00B0\u00E4\u00BA\u008B\u00E4\u00B8\u009A\u00E6\u0095\u00B4\u00E4\u00B8\u00AA\u00E5\u00B1\u00B1\u00E4\u00B8\u009C\u00E6\u0083\u0085\u00E6\u0084\u009F\u00E7\u0089\u00B9\u00E6\u00AE\u008A\u00E5\u0088\u0086\u00E9\u00A1\u009E\u00E6\u0090\u009C\u00E5\u00B0\u008B\u00E5\u00B1\u009E\u00E4\u00BA\u008E\u00E9\u0097\u00A8\u00E6\u0088\u00B7\u00E8\u00B4\u00A2\u00E5\u008A\u00A1\u00E5\u00A3\u00B0\u00E9\u009F\u00B3\u00E5\u008F\u008A\u00E5\u0085\u00B6\u00E8\u00B4\u00A2\u00E7\u00BB\u008F\u00E5\u009D\u009A\u00E6\u008C\u0081\u00E5\u00B9\u00B2\u00E9\u0083\u00A8\u00E6\u0088\u0090\u00E7\u00AB\u008B\u00E5\u0088\u00A9\u00E7\u009B\u008A\u00E8\u0080\u0083\u00E8\u0099\u0091\u00E6\u0088\u0090\u00E9\u0083\u00BD\u00E5\u008C\u0085\u00E8\u00A3\u0085\u00E7\u0094\u00A8\u00E6\u0088\u00B6\u00E6\u00AF\u0094\u00E8\u00B5\u009B\u00E6\u0096\u0087\u00E6\u0098\u008E\u00E6\u008B\u009B\u00E5\u0095\u0086\u00E5\u00AE\u008C\u00E6\u0095\u00B4\u00E7\u009C\u009F\u00E6\u0098\u00AF\u00E7\u009C\u00BC\u00E7\u009D\u009B\u00E4\u00BC\u0099\u00E4\u00BC\u00B4\u00E5\u00A8\u0081\u00E6\u009C\u009B\u00E9\u00A2\u0086\u00E5\u009F\u009F\u00E5\u008D\u00AB\u00E7\u0094\u009F\u00E4\u00BC\u0098\u00E6\u0083\u00A0\u00E8\u00AB\u0096\u00E5\u00A3\u0087\u00E5\u0085\u00AC\u00E5\u0085\u00B1\u00E8\u0089\u00AF\u00E5\u00A5\u00BD\u00E5\u0085\u0085\u00E5\u0088\u0086\u00E7\u00AC\u00A6\u00E5\u0090\u0088\u00E9\u0099\u0084\u00E4\u00BB\u00B6\u00E7\u0089\u00B9\u00E7\u0082\u00B9\u00E4\u00B8\u008D\u00E5\u008F\u00AF\u00E8\u008B\u00B1\u00E6\u0096\u0087\u00E8\u00B5\u0084\u00E4\u00BA\u00A7\u00E6\u00A0\u00B9\u00E6\u009C\u00AC\u00E6\u0098\u008E\u00E6\u0098\u00BE\u00E5\u00AF\u0086\u00E7\u00A2\u00BC\u00E5\u0085\u00AC\u00E4\u00BC\u0097\u00E6\u00B0\u0091\u00E6\u0097\u008F\u00E6\u009B\u00B4\u00E5\u008A\u00A0\u00E4\u00BA\u00AB\u00E5\u008F\u0097\u00E5\u0090\u008C\u00E5\u00AD\u00A6\u00E5\u0090\u00AF\u00E5\u008A\u00A8\u00E9\u0080\u0082\u00E5\u0090\u0088\u00E5\u008E\u009F\u00E6\u009D\u00A5\u00E9\u0097\u00AE\u00E7\u00AD\u0094\u00E6\u009C\u00AC\u00E6\u0096\u0087\u00E7\u00BE\u008E\u00E9\u00A3\u009F\u00E7\u00BB\u00BF\u00E8\u0089\u00B2\u00E7\u00A8\u00B3\u00E5\u00AE\u009A\u00E7\u00BB\u0088\u00E4\u00BA\u008E\u00E7\u0094\u009F\u00E7\u0089\u00A9\u00E4\u00BE\u009B\u00E6\u00B1\u0082\u00E6\u0090\u009C\u00E7\u008B\u0090\u00E5\u008A\u009B\u00E9\u0087\u008F\u00E4\u00B8\u00A5\u00E9\u0087\u008D\u00E6\u00B0\u00B8\u00E8\u00BF\u009C\u00E5\u0086\u0099\u00E7\u009C\u009F\u00E6\u009C\u0089\u00E9\u0099\u0090\u00E7\u00AB\u009E\u00E4\u00BA\u0089\u00E5\u00AF\u00B9\u00E8\u00B1\u00A1\u00E8\u00B4\u00B9\u00E7\u0094\u00A8\u00E4\u00B8\u008D\u00E5\u00A5\u00BD\u00E7\u00BB\u009D\u00E5\u00AF\u00B9\u00E5\u008D\u0081\u00E5\u0088\u0086\u00E4\u00BF\u0083\u00E8\u00BF\u009B\u00E7\u0082\u00B9\u00E8\u00AF\u0084\u00E5\u00BD\u00B1\u00E9\u009F\u00B3\u00E4\u00BC\u0098\u00E5\u008A\u00BF\u00E4\u00B8\u008D\u00E5\u00B0\u0091\u00E6\u00AC\u00A3\u00E8\u00B5\u008F\u00E5\u00B9\u00B6\u00E4\u00B8\u0094\u00E6\u009C\u0089\u00E7\u0082\u00B9\u00E6\u0096\u00B9\u00E5\u0090\u0091\u00E5\u0085\u00A8\u00E6\u0096\u00B0\u00E4\u00BF\u00A1\u00E7\u0094\u00A8\u00E8\u00AE\u00BE\u00E6\u0096\u00BD\u00E5\u00BD\u00A2\u00E8\u00B1\u00A1\u00E8\u00B5\u0084\u00E6\u00A0\u00BC\u00E7\u00AA\u0081\u00E7\u00A0\u00B4\u00E9\u009A\u008F\u00E7\u009D\u0080\u00E9\u0087\u008D\u00E5\u00A4\u00A7\u00E4\u00BA\u008E\u00E6\u0098\u00AF\u00E6\u00AF\u0095\u00E4\u00B8\u009A\u00E6\u0099\u00BA\u00E8\u0083\u00BD\u00E5\u008C\u0096\u00E5\u00B7\u00A5\u00E5\u00AE\u008C\u00E7\u00BE\u008E\u00E5\u0095\u0086\u00E5\u009F\u008E\u00E7\u00BB\u009F\u00E4\u00B8\u0080\u00E5\u0087\u00BA\u00E7\u0089\u0088\u00E6\u0089\u0093\u00E9\u0080\u00A0\u00E7\u0094\u00A2\u00E5\u0093\u0081\u00E6\u00A6\u0082\u00E5\u0086\u00B5\u00E7\u0094\u00A8\u00E4\u00BA\u008E\u00E4\u00BF\u009D\u00E7\u0095\u0099\u00E5\u009B\u00A0\u00E7\u00B4\u00A0\u00E4\u00B8\u00AD\u00E5\u009C\u008B\u00E5\u00AD\u0098\u00E5\u0082\u00A8\u00E8\u00B4\u00B4\u00E5\u009B\u00BE\u00E6\u009C\u0080\u00E6\u0084\u009B\u00E9\u0095\u00BF\u00E6\u009C\u009F\u00E5\u008F\u00A3\u00E4\u00BB\u00B7\u00E7\u0090\u0086\u00E8\u00B4\u00A2\u00E5\u009F\u00BA\u00E5\u009C\u00B0\u00E5\u00AE\u0089\u00E6\u008E\u0092\u00E6\u00AD\u00A6\u00E6\u00B1\u0089\u00E9\u0087\u008C\u00E9\u009D\u00A2\u00E5\u0088\u009B\u00E5\u00BB\u00BA\u00E5\u00A4\u00A9\u00E7\u00A9\u00BA\u00E9\u00A6\u0096\u00E5\u0085\u0088\u00E5\u00AE\u008C\u00E5\u0096\u0084\u00E9\u00A9\u00B1\u00E5\u008A\u00A8\u00E4\u00B8\u008B\u00E9\u009D\u00A2\u00E4\u00B8\u008D\u00E5\u0086\u008D\u00E8\u00AF\u009A\u00E4\u00BF\u00A1\u00E6\u0084\u008F\u00E4\u00B9\u0089\u00E9\u0098\u00B3\u00E5\u0085\u0089\u00E8\u008B\u00B1\u00E5\u009B\u00BD\u00E6\u00BC\u0082\u00E4\u00BA\u00AE\u00E5\u0086\u009B\u00E4\u00BA\u008B\u00E7\u008E\u00A9\u00E5\u00AE\u00B6\u00E7\u00BE\u00A4\u00E4\u00BC\u0097\u00E5\u0086\u009C\u00E6\u00B0\u0091\u00E5\u008D\u00B3\u00E5\u008F\u00AF\u00E5\u0090\u008D\u00E7\u00A8\u00B1\u00E5\u00AE\u00B6\u00E5\u0085\u00B7\u00E5\u008A\u00A8\u00E7\u0094\u00BB\u00E6\u0083\u00B3\u00E5\u0088\u00B0\u00E6\u00B3\u00A8\u00E6\u0098\u008E\u00E5\u00B0\u008F\u00E5\u00AD\u00A6\u00E6\u0080\u00A7\u00E8\u0083\u00BD\u00E8\u0080\u0083\u00E7\u00A0\u0094\u00E7\u00A1\u00AC\u00E4\u00BB\u00B6\u00E8\u00A7\u0082\u00E7\u009C\u008B\u00E6\u00B8\u0085\u00E6\u00A5\u009A\u00E6\u0090\u009E\u00E7\u00AC\u0091\u00E9\u00A6\u0096\u00E9\u00A0\u0081\u00E9\u00BB\u0084\u00E9\u0087\u0091\u00E9\u0080\u0082\u00E7\u0094\u00A8\u00E6\u00B1\u009F\u00E8\u008B\u008F\u00E7\u009C\u009F\u00E5\u00AE\u009E\u00E4\u00B8\u00BB\u00E7\u00AE\u00A1\u00E9\u0098\u00B6\u00E6\u00AE\u00B5\u00E8\u00A8\u00BB\u00E5\u0086\u008A\u00E7\u00BF\u00BB\u00E8\u00AF\u0091\u00E6\u009D\u0083\u00E5\u0088\u00A9\u00E5\u0081\u009A\u00E5\u00A5\u00BD\u00E4\u00BC\u00BC\u00E4\u00B9\u008E\u00E9\u0080\u009A\u00E8\u00AE\u00AF\u00E6\u0096\u00BD\u00E5\u00B7\u00A5\u00E7\u008B\u0080\u00E6\u0085\u008B\u00E4\u00B9\u009F\u00E8\u00AE\u00B8\u00E7\u008E\u00AF\u00E4\u00BF\u009D\u00E5\u009F\u00B9\u00E5\u0085\u00BB\u00E6\u00A6\u0082\u00E5\u00BF\u00B5\u00E5\u00A4\u00A7\u00E5\u009E\u008B\u00E6\u009C\u00BA\u00E7\u00A5\u00A8\u00E7\u0090\u0086\u00E8\u00A7\u00A3\u00E5\u008C\u00BF\u00E5\u0090\u008Dcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraest\u00C3\u00A1nnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerprecioseg\u00C3\u00BAnbuenosvolverpuntossemanahab\u00C3\u00ADaagostonuevosunidoscarlosequiponi\u00C3\u00B1osmuchosalgunacorreoimagenpartirarribamar\u00C3\u00ADahombreempleoverdadcambiomuchasfueronpasadol\u00C3\u00ADneaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposser\u00C3\u00A1neuropamediosfrenteacercadem\u00C3\u00A1sofertacochesmodeloitalialetrasalg\u00C3\u00BAncompracualesexistecuerposiendoprensallegarviajesdineromurciapodr\u00C3\u00A1puestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismos\u00C3\u00BAnicocaminositiosraz\u00C3\u00B3ndebidopruebatoledoten\u00C3\u00ADajes\u00C3\u00BAsesperococinaorigentiendacientoc\u00C3\u00A1dizhablarser\u00C3\u00ADalatinafuerzaestiloguerraentrar\u00C3\u00A9xitol\u00C3\u00B3pezagendav\u00C3\u00ADdeoevitarpaginametrosjavierpadresf\u00C3\u00A1cilcabeza\u00C3\u00A1reassalidaenv\u00C3\u00ADojap\u00C3\u00B3nabusosbienestextosllevarpuedanfuertecom\u00C3\u00BAnclaseshumanotenidobilbaounidadest\u00C3\u00A1seditarcreado\u00D0\u00B4\u00D0\u00BB\u00D1\u008F\u00D1\u0087\u00D1\u0082\u00D0\u00BE\u00D0\u00BA\u00D0\u00B0\u00D0\u00BA\u00D0\u00B8\u00D0\u00BB\u00D0\u00B8\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D0\u00BF\u00D1\u0080\u00D0\u00B8\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00B5\u00D1\u0089\u00D0\u00B5\u00D1\u0083\u00D0\u00B6\u00D0\u00B5\u00D0\u009A\u00D0\u00B0\u00D0\u00BA\u00D0\u00B1\u00D0\u00B5\u00D0\u00B7\u00D0\u00B1\u00D1\u008B\u00D0\u00BB\u00D0\u00BE\u00D0\u00BD\u00D0\u00B8\u00D0\u0092\u00D1\u0081\u00D0\u00B5\u00D0\u00BF\u00D0\u00BE\u00D0\u00B4\u00D0\u00AD\u00D1\u0082\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D1\u0087\u00D0\u00B5\u00D0\u00BC\u00D0\u00BD\u00D0\u00B5\u00D1\u0082\u00D0\u00BB\u00D0\u00B5\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00BE\u00D0\u00BD\u00D0\u00B0\u00D0\u00B3\u00D0\u00B4\u00D0\u00B5\u00D0\u00BC\u00D0\u00BD\u00D0\u00B5\u00D0\u0094\u00D0\u00BB\u00D1\u008F\u00D0\u009F\u00D1\u0080\u00D0\u00B8\u00D0\u00BD\u00D0\u00B0\u00D1\u0081\u00D0\u00BD\u00D0\u00B8\u00D1\u0085\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D0\u00BA\u00D1\u0082\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D0\u00B2\u00D0\u00BE\u00D1\u0082\u00D1\u0082\u00D0\u00B0\u00D0\u00BC\u00D0\u00A1\u00D0\u00A8\u00D0\u0090\u00D0\u00BC\u00D0\u00B0\u00D1\u008F\u00D0\u00A7\u00D1\u0082\u00D0\u00BE\u00D0\u00B2\u00D0\u00B0\u00D1\u0081\u00D0\u00B2\u00D0\u00B0\u00D0\u00BC\u00D0\u00B5\u00D0\u00BC\u00D1\u0083\u00D0\u00A2\u00D0\u00B0\u00D0\u00BA\u00D0\u00B4\u00D0\u00B2\u00D0\u00B0\u00D0\u00BD\u00D0\u00B0\u00D0\u00BC\u00D1\u008D\u00D1\u0082\u00D0\u00B8\u00D1\u008D\u00D1\u0082\u00D1\u0083\u00D0\u0092\u00D0\u00B0\u00D0\u00BC\u00D1\u0082\u00D0\u00B5\u00D1\u0085\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D1\u0082\u00D1\u0083\u00D1\u0082\u00D0\u00BD\u00D0\u00B0\u00D0\u00B4\u00D0\u00B4\u00D0\u00BD\u00D1\u008F\u00D0\u0092\u00D0\u00BE\u00D1\u0082\u00D1\u0082\u00D1\u0080\u00D0\u00B8\u00D0\u00BD\u00D0\u00B5\u00D0\u00B9\u00D0\u0092\u00D0\u00B0\u00D1\u0081\u00D0\u00BD\u00D0\u00B8\u00D0\u00BC\u00D1\u0081\u00D0\u00B0\u00D0\u00BC\u00D1\u0082\u00D0\u00BE\u00D1\u0082\u00D1\u0080\u00D1\u0083\u00D0\u00B1\u00D0\u009E\u00D0\u00BD\u00D0\u00B8\u00D0\u00BC\u00D0\u00B8\u00D1\u0080\u00D0\u00BD\u00D0\u00B5\u00D0\u00B5\u00D0\u009E\u00D0\u009E\u00D0\u009E\u00D0\u00BB\u00D0\u00B8\u00D1\u0086\u00D1\u008D\u00D1\u0082\u00D0\u00B0\u00D0\u009E\u00D0\u00BD\u00D0\u00B0\u00D0\u00BD\u00D0\u00B5\u00D0\u00BC\u00D0\u00B4\u00D0\u00BE\u00D0\u00BC\u00D0\u00BC\u00D0\u00BE\u00D0\u00B9\u00D0\u00B4\u00D0\u00B2\u00D0\u00B5\u00D0\u00BE\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0083\u00D0\u00B4\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u00B9\u00E0\u00A5\u0088\u00E0\u00A4\u0095\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A5\u008B\u00E0\u00A4\u0094\u00E0\u00A4\u00B0\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u008F\u00E0\u00A4\u0095\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00AD\u00E0\u00A5\u0080\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A5\u008B\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u00AF\u00E0\u00A4\u00B9\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u0095\u00E0\u00A4\u00A5\u00E0\u00A4\u00BEjagran\u00E0\u00A4\u0086\u00E0\u00A4\u009C\u00E0\u00A4\u009C\u00E0\u00A5\u008B\u00E0\u00A4\u0085\u00E0\u00A4\u00AC\u00E0\u00A4\u00A6\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A4\u0088\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u0097\u00E0\u00A4\u008F\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A4\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u00B5\u00E0\u00A4\u00B9\u00E0\u00A4\u00AF\u00E0\u00A5\u0087\u00E0\u00A4\u00A5\u00E0\u00A5\u0087\u00E0\u00A4\u00A5\u00E0\u00A5\u0080\u00E0\u00A4\u0098\u00E0\u00A4\u00B0\u00E0\u00A4\u009C\u00E0\u00A4\u00AC\u00E0\u00A4\u00A6\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A4\u0088\u00E0\u00A4\u009C\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u0088\u00E0\u00A4\u00A8\u00E0\u00A4\u008F\u00E0\u00A4\u00B9\u00E0\u00A4\u00B0\u00E0\u00A4\u0089\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00AE\u00E0\u00A4\u00B5\u00E0\u00A5\u008B\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00AC\u00E0\u00A4\u00AE\u00E0\u00A4\u0088\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0093\u00E0\u00A4\u00B0\u00E0\u00A4\u0086\u00E0\u00A4\u00AE\u00E0\u00A4\u00AC\u00E0\u00A4\u00B8\u00E0\u00A4\u00AD\u00E0\u00A4\u00B0\u00E0\u00A4\u00AC\u00E0\u00A4\u00A8\u00E0\u00A4\u009A\u00E0\u00A4\u00B2\u00E0\u00A4\u00AE\u00E0\u00A4\u00A8\u00E0\u00A4\u0086\u00E0\u00A4\u0097\u00E0\u00A4\u00B8\u00E0\u00A5\u0080\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00D8\u00B9\u00D9\u0084\u00D9\u0089\u00D8\u00A5\u00D9\u0084\u00D9\u0089\u00D9\u0087\u00D8\u00B0\u00D8\u00A7\u00D8\u00A2\u00D8\u00AE\u00D8\u00B1\u00D8\u00B9\u00D8\u00AF\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D9\u0089\u00D9\u0087\u00D8\u00B0\u00D9\u0087\u00D8\u00B5\u00D9\u0088\u00D8\u00B1\u00D8\u00BA\u00D9\u008A\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D9\u0086\u00D9\u0088\u00D9\u0084\u00D8\u00A7\u00D8\u00A8\u00D9\u008A\u00D9\u0086\u00D8\u00B9\u00D8\u00B1\u00D8\u00B6\u00D8\u00B0\u00D9\u0084\u00D9\u0083\u00D9\u0087\u00D9\u0086\u00D8\u00A7\u00D9\u008A\u00D9\u0088\u00D9\u0085\u00D9\u0082\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D8\u00A7\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D9\u0086\u00D8\u00AD\u00D8\u00AA\u00D9\u0089\u00D9\u0082\u00D8\u00A8\u00D9\u0084\u00D9\u0088\u00D8\u00AD\u00D8\u00A9\u00D8\u00A7\u00D8\u00AE\u00D8\u00B1\u00D9\u0081\u00D9\u0082\u00D8\u00B7\u00D8\u00B9\u00D8\u00A8\u00D8\u00AF\u00D8\u00B1\u00D9\u0083\u00D9\u0086\u00D8\u00A5\u00D8\u00B0\u00D8\u00A7\u00D9\u0083\u00D9\u0085\u00D8\u00A7\u00D8\u00A7\u00D8\u00AD\u00D8\u00AF\u00D8\u00A5\u00D9\u0084\u00D8\u00A7\u00D9\u0081\u00D9\u008A\u00D9\u0087\u00D8\u00A8\u00D8\u00B9\u00D8\u00B6\u00D9\u0083\u00D9\u008A\u00D9\u0081\u00D8\u00A8\u00D8\u00AD\u00D8\u00AB\u00D9\u0088\u00D9\u0085\u00D9\u0086\u00D9\u0088\u00D9\u0087\u00D9\u0088\u00D8\u00A3\u00D9\u0086\u00D8\u00A7\u00D8\u00AC\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D9\u0087\u00D8\u00A7\u00D8\u00B3\u00D9\u0084\u00D9\u0085\u00D8\u00B9\u00D9\u0086\u00D8\u00AF\u00D9\u0084\u00D9\u008A\u00D8\u00B3\u00D8\u00B9\u00D8\u00A8\u00D8\u00B1\u00D8\u00B5\u00D9\u0084\u00D9\u0089\u00D9\u0085\u00D9\u0086\u00D8\u00B0\u00D8\u00A8\u00D9\u0087\u00D8\u00A7\u00D8\u00A3\u00D9\u0086\u00D9\u0087\u00D9\u0085\u00D8\u00AB\u00D9\u0084\u00D9\u0083\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00AD\u00D9\u008A\u00D8\u00AB\u00D9\u0085\u00D8\u00B5\u00D8\u00B1\u00D8\u00B4\u00D8\u00B1\u00D8\u00AD\u00D8\u00AD\u00D9\u0088\u00D9\u0084\u00D9\u0088\u00D9\u0081\u00D9\u008A\u00D8\u00A7\u00D8\u00B0\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D9\u0084\u00D9\u0085\u00D8\u00B1\u00D8\u00A9\u00D8\u00A7\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0081\u00D8\u00A3\u00D8\u00A8\u00D9\u0088\u00D8\u00AE\u00D8\u00A7\u00D8\u00B5\u00D8\u00A3\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D9\u0086\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D9\u008A\u00D8\u00B9\u00D8\u00B6\u00D9\u0088\u00D9\u0088\u00D9\u0082\u00D8\u00AF\u00D8\u00A7\u00D8\u00A8\u00D9\u0086\u00D8\u00AE\u00D9\u008A\u00D8\u00B1\u00D8\u00A8\u00D9\u0086\u00D8\u00AA\u00D9\u0084\u00D9\u0083\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00A1\u00D9\u0088\u00D9\u0087\u00D9\u008A\u00D8\u00A7\u00D8\u00A8\u00D9\u0088\u00D9\u0082\u00D8\u00B5\u00D8\u00B5\u00D9\u0088\u00D9\u0085\u00D8\u00A7\u00D8\u00B1\u00D9\u0082\u00D9\u0085\u00D8\u00A3\u00D8\u00AD\u00D8\u00AF\u00D9\u0086\u00D8\u00AD\u00D9\u0086\u00D8\u00B9\u00D8\u00AF\u00D9\u0085\u00D8\u00B1\u00D8\u00A3\u00D9\u008A\u00D8\u00A7\u00D8\u00AD\u00D8\u00A9\u00D9\u0083\u00D8\u00AA\u00D8\u00A8\u00D8\u00AF\u00D9\u0088\u00D9\u0086\u00D9\u008A\u00D8\u00AC\u00D8\u00A8\u00D9\u0085\u00D9\u0086\u00D9\u0087\u00D8\u00AA\u00D8\u00AD\u00D8\u00AA\u00D8\u00AC\u00D9\u0087\u00D8\u00A9\u00D8\u00B3\u00D9\u0086\u00D8\u00A9\u00D9\u008A\u00D8\u00AA\u00D9\u0085\u00D9\u0083\u00D8\u00B1\u00D8\u00A9\u00D8\u00BA\u00D8\u00B2\u00D8\u00A9\u00D9\u0086\u00D9\u0081\u00D8\u00B3\u00D8\u00A8\u00D9\u008A\u00D8\u00AA\u00D9\u0084\u00D9\u0084\u00D9\u0087\u00D9\u0084\u00D9\u0086\u00D8\u00A7\u00D8\u00AA\u00D9\u0084\u00D9\u0083\u00D9\u0082\u00D9\u0084\u00D8\u00A8\u00D9\u0084\u00D9\u0085\u00D8\u00A7\u00D8\u00B9\u00D9\u0086\u00D9\u0087\u00D8\u00A3\u00D9\u0088\u00D9\u0084\u00D8\u00B4\u00D9\u008A\u00D8\u00A1\u00D9\u0086\u00D9\u0088\u00D8\u00B1\u00D8\u00A3\u00D9\u0085\u00D8\u00A7\u00D9\u0081\u00D9\u008A\u00D9\u0083\u00D8\u00A8\u00D9\u0083\u00D9\u0084\u00D8\u00B0\u00D8\u00A7\u00D8\u00AA\u00D8\u00B1\u00D8\u00AA\u00D8\u00A8\u00D8\u00A8\u00D8\u00A3\u00D9\u0086\u00D9\u0087\u00D9\u0085\u00D8\u00B3\u00D8\u00A7\u00D9\u0086\u00D9\u0083\u00D8\u00A8\u00D9\u008A\u00D8\u00B9\u00D9\u0081\u00D9\u0082\u00D8\u00AF\u00D8\u00AD\u00D8\u00B3\u00D9\u0086\u00D9\u0084\u00D9\u0087\u00D9\u0085\u00D8\u00B4\u00D8\u00B9\u00D8\u00B1\u00D8\u00A3\u00D9\u0087\u00D9\u0084\u00D8\u00B4\u00D9\u0087\u00D8\u00B1\u00D9\u0082\u00D8\u00B7\u00D8\u00B1\u00D8\u00B7\u00D9\u0084\u00D8\u00A8profileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>\r\nwrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle=\"Mobile killingshowingItaliandroppedheavilyeffects-1']);\nconfirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.\n\nThe but notdensityBritainChineselack oftributeIreland\" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang=\"return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue=\"complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role=\"missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();\r\npaymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html\">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen\n\nWhen observe</h2>\r\nModern provide\" alt=\"borders.\n\nFor \n\nMany artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>\r\n Countryignoredloss ofjust asGeorgiastrange<head><stopped1']);\r\nislandsnotableborder:list ofcarried100,000</h3>\n severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id=\"foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login\">convertviolententeredfirst\">circuitFinlandchemistshe was10px;\">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title\">tooltipSectiondesignsTurkishyounger.match(})();\n\nburningoperatedegreessource=Richardcloselyplasticentries</tr>\r\ncolor:#ul id=\"possessrollingphysicsfailingexecutecontestlink toDefault<br />\n: true,chartertourismclassicproceedexplain</h1>\r\nonline.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src=\"/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e&quot;tradingleft\">\npersonsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy\n\t\t<!--Daniel bindingblock\">imposedutilizeAbraham(except{width:putting).html(|| [];\nDATA[ *kitchenmountedactual dialectmainly _blank'installexpertsif(typeIt also&copy; \">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref=\"/\" rel=\"developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in\n\t<!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday's.html\" target=wearingAll Rig;\n})();raising Also, crucialabout\">declare-->\n<scfirefoxas muchappliesindex, s, but type = \n\r\n<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin\" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>\r\n returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of\n\nSome 'click'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion=\"pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major\":\"httpin his menu\">\nmonthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small\">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks\">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel\">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8\">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>\nevidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>\n he left).val()false);logicalbankinghome tonaming Arizonacredits);\n});\nfounderin turnCollinsbefore But thechargedTitle\">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered']);\n has theunclearEvent',both innot all\n\n<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage\" linear painterand notrarely acronymdelivershorter00&amp;as manywidth=\"/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don'tretreat. Some ww.\");\nbombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft\"><comScorAll thejQuery.touristClassicfalse\" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>\n\n. When in bothdismissExplorealways via thespa\u00C3\u00B1olwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>\n\t\tit intoranked rate oful>\r\n attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped\").css(hostilelead tolittle groups,Picture-->\r\n\r\n rows=\" objectinverse<footerCustomV><\\/scrsolvingChamberslaverywoundedwhereas!= 'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead')[0Criticsstudios>&copy;group\">assemblmaking pressedwidget.ps:\" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass=\"but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;\">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + \"gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(\" />\n\t\there isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();\n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded=\"true\"spacingis mosta more totallyfall of});\r\n immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace\">header-well asStanleybridges/globalCroatia About [0];\n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF\"bottom\"like a employslive inas seenprintermost ofub-linkrejectsand useimage\">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older\">us.js\"> Since universlarger open to!-- endlies in']);\r\n marketwho is (\"DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting \n\t\tvar March 2grew upClimate.removeskilledway the</head>face ofacting right\">to workreduceshas haderectedshow();action=book ofan area== \"htt<header\n<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage\">MobilClements\" id=\"as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded\"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;\">\r\npushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>\npeople.in one =windowfooter_a good reklamaothers,to this_cookiepanel\">London,definescrushedbaptismcoastalstatus title\" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />\r\nAtlantanucleusCounty,purely count\">easily build aonclicka givenpointerh&quot;events else {\nditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink\"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg\" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium\"DO NOT France,with a war andsecond take a >\r\n\r\n\r\nmarket.highwaydone inctivity\"last\">obligedrise to\"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right\" bicycleacing=\"day andstatingRather,higher Office are nowtimes, when a pay foron this-link\">;borderaround annual the Newput the.com\" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks\">\n();\" rea place\\u003Caabout atr>\r\n\t\tccount gives a<SCRIPTRailwaythemes/toolboxById(\"xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>\r\n<ustomVa;&gt;</importsor thatmostly &amp;re size=\"</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>\r\n\r\n<!organis <br />Beijingcatal\u00C3\u00A0deutscheuropeueuskaragaeilgesvenskaespa\u00C3\u00B1amensajeusuariotrabajom\u00C3\u00A9xicop\u00C3\u00A1ginasiempresistemaoctubredurantea\u00C3\u00B1adirempresamomentonuestroprimeratrav\u00C3\u00A9sgraciasnuestraprocesoestadoscalidadpersonan\u00C3\u00BAmeroacuerdom\u00C3\u00BAsicamiembroofertasalgunospa\u00C3\u00ADsesejemploderechoadem\u00C3\u00A1sprivadoagregarenlacesposiblehotelessevillaprimero\u00C3\u00BAltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodise\u00C3\u00B1oturismoc\u00C3\u00B3digoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitast\u00C3\u00ADtuloconocersegundoconsejofranciaminutossegundatenemosefectosm\u00C3\u00A1lagasesi\u00C3\u00B3nrevistagranadacompraringresogarc\u00C3\u00ADaacci\u00C3\u00B3necuadorquienesinclusodeber\u00C3\u00A1materiahombresmuestrapodr\u00C3\u00ADama\u00C3\u00B1ana\u00C3\u00BAltimaestamosoficialtambienning\u00C3\u00BAnsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner\">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo\"><adaughterauthor\" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom\">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton\" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id=\"discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive\">somewhatvictoriaWestern title=\"LocationcontractvisitorsDownloadwithout right\">\nmeasureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg\" />machines</h2>\n keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow\" valuable</label>relativebringingincreasegovernorplugins/List of Header\">\" name=\" (&quot;graduate</head>\ncommercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>\n\t\t<select citizensclothingwatching<li id=\"specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split(\"lizationOctober ){returnimproved--&gt;\n\ncoveragechairman.png\" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css\" /> websitereporteddefault\"/></a>\r\nelectricscotlandcreationquantity. ISBN 0did not instance-search-\" lang=\"speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: 'http:'script'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id=\"William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout=\"approved maximumheader\"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=\"\"intervalwirelessentitledagenciesSearch\" measuredthousandspending&hellip;new Date\" size=\"pageNamemiddle\" \" /></a>hidden\">sequencepersonaloverflowopinionsillinoislinks\">\n\t<title>versionssaturdayterminalitempropengineersectionsdesignerproposal=\"false\"Espa\u00C3\u00B1olreleasessubmit\" er&quot;additionsymptomsorientedresourceright\"><pleasurestationshistory.leaving border=contentscenter\">.\n\nSome directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal\"><span>search\">operatorrequestsa &quot;allowingDocumentrevision. \n\nThe yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1\"indicatefamiliar qualitymargin:0 contentviewportcontacts-title\">portable.length eligibleinvolvesatlanticonload=\"default.suppliedpaymentsglossary\n\nAfter guidance</td><tdencodingmiddle\">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>\n\taffectedsupportspointer;toString</small>oklahomawill be investor0\" alt=\"holidaysResourcelicensed (which . After considervisitingexplorerprimary search\" android\"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js\"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions\"campbell<!-- end</span><<br />\r\n_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=\" Companyexamples<iframe believespresentsmarshallpart of properly).\n\nThe taxonomymuch of </span>\n\" data-srtugu\u00C3\u00AAsscrollTo project<head>\r\nattorneyemphasissponsorsfancyboxworld's wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix\n<head>\narticle <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent\"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.png";
+ }
+ }
+
+ private class DataHolder1
+ {
+ internal static string GetData()
+ {
+ return "japanesecodebasebutton\">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth=\"2lazyloadnovemberused in height=\"cript\">\n&nbsp;</<tr><td height:2/productcountry include footer\" &lt;!-- title\"></jquery.</form>\n(\u00E7\u00AE\u0080\u00E4\u00BD\u0093)(\u00E7\u00B9\u0081\u00E9\u00AB\u0094)hrvatskiitalianorom\u00C3\u00A2n\u00C4\u0083t\u00C3\u00BCrk\u00C3\u00A7e\u00D8\u00A7\u00D8\u00B1\u00D8\u00AF\u00D9\u0088tambi\u00C3\u00A9nnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespu\u00C3\u00A9sdeportesproyectoproductop\u00C3\u00BAbliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopini\u00C3\u00B3nimprimirmientrasam\u00C3\u00A9ricavendedorsociedadrespectorealizarregistropalabrasinter\u00C3\u00A9sentoncesespecialmiembrosrealidadc\u00C3\u00B3rdobazaragozap\u00C3\u00A1ginassocialesbloqueargesti\u00C3\u00B3nalquilersistemascienciascompletoversi\u00C3\u00B3ncompletaestudiosp\u00C3\u00BAblicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayor\u00C3\u00ADaalemaniafunci\u00C3\u00B3n\u00C3\u00BAltimoshaciendoaquellosedici\u00C3\u00B3nfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratoj\u00C3\u00B3venesdistritot\u00C3\u00A9cnicaconjuntoenerg\u00C3\u00ADatrabajarasturiasrecienteutilizarbolet\u00C3\u00ADnsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallapr\u00C3\u00B3ximoalmer\u00C3\u00ADaanimalesqui\u00C3\u00A9nescoraz\u00C3\u00B3nsecci\u00C3\u00B3nbuscandoopcionesexteriorconceptotodav\u00C3\u00ADagaler\u00C3\u00ADaescribirmedicinalicenciaconsultaaspectoscr\u00C3\u00ADticad\u00C3\u00B3laresjusticiadeber\u00C3\u00A1nper\u00C3\u00ADodonecesitamantenerpeque\u00C3\u00B1orecibidatribunaltenerifecanci\u00C3\u00B3ncanariasdescargadiversosmallorcarequieret\u00C3\u00A9cnicodeber\u00C3\u00ADaviviendafinanzasadelantefuncionaconsejosdif\u00C3\u00ADcilciudadesantiguasavanzadat\u00C3\u00A9rminounidadess\u00C3\u00A1nchezcampa\u00C3\u00B1asoftonicrevistascontienesectoresmomentosfacultadcr\u00C3\u00A9ditodiversassupuestofactoressegundospeque\u00C3\u00B1a\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D0\u00B0\u00D0\u00B5\u00D1\u0081\u00D0\u00BB\u00D0\u00B8\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D0\u00B1\u00D1\u008B\u00D0\u00BB\u00D0\u00BE\u00D0\u00B1\u00D1\u008B\u00D1\u0082\u00D1\u008C\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D0\u0095\u00D1\u0081\u00D0\u00BB\u00D0\u00B8\u00D1\u0082\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D1\u008F\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D1\u0085\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00B9\u00D0\u00B4\u00D0\u00B0\u00D0\u00B6\u00D0\u00B5\u00D0\u00B1\u00D1\u008B\u00D0\u00BB\u00D0\u00B8\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D1\u0083\u00D0\u00B4\u00D0\u00B5\u00D0\u00BD\u00D1\u008C\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D1\u0082\u00D0\u00B1\u00D1\u008B\u00D0\u00BB\u00D0\u00B0\u00D1\u0081\u00D0\u00B5\u00D0\u00B1\u00D1\u008F\u00D0\u00BE\u00D0\u00B4\u00D0\u00B8\u00D0\u00BD\u00D1\u0081\u00D0\u00B5\u00D0\u00B1\u00D0\u00B5\u00D0\u00BD\u00D0\u00B0\u00D0\u00B4\u00D0\u00BE\u00D1\u0081\u00D0\u00B0\u00D0\u00B9\u00D1\u0082\u00D1\u0084\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D0\u00BD\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B8\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B9\u00D0\u00B8\u00D0\u00B3\u00D1\u0080\u00D1\u008B\u00D1\u0082\u00D0\u00BE\u00D0\u00B6\u00D0\u00B5\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00BC\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D1\u008E\u00D0\u00BB\u00D0\u00B8\u00D1\u0088\u00D1\u008C\u00D1\u008D\u00D1\u0082\u00D0\u00B8\u00D1\u0085\u00D0\u00BF\u00D0\u00BE\u00D0\u00BA\u00D0\u00B0\u00D0\u00B4\u00D0\u00BD\u00D0\u00B5\u00D0\u00B9\u00D0\u00B4\u00D0\u00BE\u00D0\u00BC\u00D0\u00B0\u00D0\u00BC\u00D0\u00B8\u00D1\u0080\u00D0\u00B0\u00D0\u00BB\u00D0\u00B8\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D1\u0083\u00D1\u0085\u00D0\u00BE\u00D1\u0082\u00D1\u008F\u00D0\u00B4\u00D0\u00B2\u00D1\u0083\u00D1\u0085\u00D1\u0081\u00D0\u00B5\u00D1\u0082\u00D0\u00B8\u00D0\u00BB\u00D1\u008E\u00D0\u00B4\u00D0\u00B8\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00BE\u00D0\u00BC\u00D0\u00B8\u00D1\u0080\u00D0\u00B5\u00D1\u0082\u00D0\u00B5\u00D0\u00B1\u00D1\u008F\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B5\u00D0\u00B2\u00D0\u00B8\u00D0\u00B4\u00D0\u00B5\u00D1\u0087\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u008D\u00D1\u0082\u00D0\u00B8\u00D0\u00BC\u00D1\u0081\u00D1\u0087\u00D0\u00B5\u00D1\u0082\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D1\u008B\u00D1\u0086\u00D0\u00B5\u00D0\u00BD\u00D1\u008B\u00D1\u0081\u00D1\u0082\u00D0\u00B0\u00D0\u00BB\u00D0\u00B2\u00D0\u00B5\u00D0\u00B4\u00D1\u008C\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D0\u00B5\u00D0\u00B2\u00D0\u00BE\u00D0\u00B4\u00D1\u008B\u00D1\u0082\u00D0\u00B5\u00D0\u00B1\u00D0\u00B5\u00D0\u00B2\u00D1\u008B\u00D1\u0088\u00D0\u00B5\u00D0\u00BD\u00D0\u00B0\u00D0\u00BC\u00D0\u00B8\u00D1\u0082\u00D0\u00B8\u00D0\u00BF\u00D0\u00B0\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D1\u0083\u00D0\u00BF\u00D1\u0080\u00D0\u00B0\u00D0\u00B2\u00D0\u00BB\u00D0\u00B8\u00D1\u0086\u00D0\u00B0\u00D0\u00BE\u00D0\u00B4\u00D0\u00BD\u00D0\u00B0\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D1\u008B\u00D0\u00B7\u00D0\u00BD\u00D0\u00B0\u00D1\u008E\u00D0\u00BC\u00D0\u00BE\u00D0\u00B3\u00D1\u0083\u00D0\u00B4\u00D1\u0080\u00D1\u0083\u00D0\u00B3\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00B9\u00D0\u00B8\u00D0\u00B4\u00D0\u00B5\u00D1\u0082\u00D0\u00BA\u00D0\u00B8\u00D0\u00BD\u00D0\u00BE\u00D0\u00BE\u00D0\u00B4\u00D0\u00BD\u00D0\u00BE\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00B0\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00B5\u00D1\u0081\u00D1\u0080\u00D0\u00BE\u00D0\u00BA\u00D0\u00B8\u00D1\u008E\u00D0\u00BD\u00D1\u008F\u00D0\u00B2\u00D0\u00B5\u00D1\u0081\u00D1\u008C\u00D0\u0095\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00B0\u00D0\u00BD\u00D0\u00B0\u00D1\u0088\u00D0\u00B8\u00D8\u00A7\u00D9\u0084\u00D9\u0084\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D9\u008A\u00D8\u00AC\u00D9\u0085\u00D9\u008A\u00D8\u00B9\u00D8\u00AE\u00D8\u00A7\u00D8\u00B5\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B0\u00D9\u008A\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D9\u0087\u00D8\u00AC\u00D8\u00AF\u00D9\u008A\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00A2\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00AF\u00D8\u00AA\u00D8\u00AD\u00D9\u0083\u00D9\u0085\u00D8\u00B5\u00D9\u0081\u00D8\u00AD\u00D8\u00A9\u00D9\u0083\u00D8\u00A7\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0084\u00D9\u008A\u00D9\u008A\u00D9\u0083\u00D9\u0088\u00D9\u0086\u00D8\u00B4\u00D8\u00A8\u00D9\u0083\u00D8\u00A9\u00D9\u0081\u00D9\u008A\u00D9\u0087\u00D8\u00A7\u00D8\u00A8\u00D9\u0086\u00D8\u00A7\u00D8\u00AA\u00D8\u00AD\u00D9\u0088\u00D8\u00A7\u00D8\u00A1\u00D8\u00A3\u00D9\u0083\u00D8\u00AB\u00D8\u00B1\u00D8\u00AE\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00AD\u00D8\u00A8\u00D8\u00AF\u00D9\u0084\u00D9\u008A\u00D9\u0084\u00D8\u00AF\u00D8\u00B1\u00D9\u0088\u00D8\u00B3\u00D8\u00A7\u00D8\u00B6\u00D8\u00BA\u00D8\u00B7\u00D8\u00AA\u00D9\u0083\u00D9\u0088\u00D9\u0086\u00D9\u0087\u00D9\u0086\u00D8\u00A7\u00D9\u0083\u00D8\u00B3\u00D8\u00A7\u00D8\u00AD\u00D8\u00A9\u00D9\u0086\u00D8\u00A7\u00D8\u00AF\u00D9\u008A\u00D8\u00A7\u00D9\u0084\u00D8\u00B7\u00D8\u00A8\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D9\u0083\u00D8\u00B4\u00D9\u0083\u00D8\u00B1\u00D8\u00A7\u00D9\u008A\u00D9\u0085\u00D9\u0083\u00D9\u0086\u00D9\u0085\u00D9\u0086\u00D9\u0087\u00D8\u00A7\u00D8\u00B4\u00D8\u00B1\u00D9\u0083\u00D8\u00A9\u00D8\u00B1\u00D8\u00A6\u00D9\u008A\u00D8\u00B3\u00D9\u0086\u00D8\u00B4\u00D9\u008A\u00D8\u00B7\u00D9\u0085\u00D8\u00A7\u00D8\u00B0\u00D8\u00A7\u00D8\u00A7\u00D9\u0084\u00D9\u0081\u00D9\u0086\u00D8\u00B4\u00D8\u00A8\u00D8\u00A7\u00D8\u00A8\u00D8\u00AA\u00D8\u00B9\u00D8\u00A8\u00D8\u00B1\u00D8\u00B1\u00D8\u00AD\u00D9\u0085\u00D8\u00A9\u00D9\u0083\u00D8\u00A7\u00D9\u0081\u00D8\u00A9\u00D9\u008A\u00D9\u0082\u00D9\u0088\u00D9\u0084\u00D9\u0085\u00D8\u00B1\u00D9\u0083\u00D8\u00B2\u00D9\u0083\u00D9\u0084\u00D9\u0085\u00D8\u00A9\u00D8\u00A3\u00D8\u00AD\u00D9\u0085\u00D8\u00AF\u00D9\u0082\u00D9\u0084\u00D8\u00A8\u00D9\u008A\u00D9\u008A\u00D8\u00B9\u00D9\u0086\u00D9\u008A\u00D8\u00B5\u00D9\u0088\u00D8\u00B1\u00D8\u00A9\u00D8\u00B7\u00D8\u00B1\u00D9\u008A\u00D9\u0082\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00AC\u00D9\u0088\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00AE\u00D8\u00B1\u00D9\u0089\u00D9\u0085\u00D8\u00B9\u00D9\u0086\u00D8\u00A7\u00D8\u00A7\u00D8\u00A8\u00D8\u00AD\u00D8\u00AB\u00D8\u00B9\u00D8\u00B1\u00D9\u0088\u00D8\u00B6\u00D8\u00A8\u00D8\u00B4\u00D9\u0083\u00D9\u0084\u00D9\u0085\u00D8\u00B3\u00D8\u00AC\u00D9\u0084\u00D8\u00A8\u00D9\u0086\u00D8\u00A7\u00D9\u0086\u00D8\u00AE\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u0083\u00D8\u00AA\u00D8\u00A7\u00D8\u00A8\u00D9\u0083\u00D9\u0084\u00D9\u008A\u00D8\u00A9\u00D8\u00A8\u00D8\u00AF\u00D9\u0088\u00D9\u0086\u00D8\u00A3\u00D9\u008A\u00D8\u00B6\u00D8\u00A7\u00D9\u008A\u00D9\u0088\u00D8\u00AC\u00D8\u00AF\u00D9\u0081\u00D8\u00B1\u00D9\u008A\u00D9\u0082\u00D9\u0083\u00D8\u00AA\u00D8\u00A8\u00D8\u00AA\u00D8\u00A3\u00D9\u0081\u00D8\u00B6\u00D9\u0084\u00D9\u0085\u00D8\u00B7\u00D8\u00A8\u00D8\u00AE\u00D8\u00A7\u00D9\u0083\u00D8\u00AB\u00D8\u00B1\u00D8\u00A8\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D9\u0081\u00D8\u00B6\u00D9\u0084\u00D8\u00A7\u00D8\u00AD\u00D9\u0084\u00D9\u0089\u00D9\u0086\u00D9\u0081\u00D8\u00B3\u00D9\u0087\u00D8\u00A3\u00D9\u008A\u00D8\u00A7\u00D9\u0085\u00D8\u00B1\u00D8\u00AF\u00D9\u0088\u00D8\u00AF\u00D8\u00A3\u00D9\u0086\u00D9\u0087\u00D8\u00A7\u00D8\u00AF\u00D9\u008A\u00D9\u0086\u00D8\u00A7\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0086\u00D9\u0085\u00D8\u00B9\u00D8\u00B1\u00D8\u00B6\u00D8\u00AA\u00D8\u00B9\u00D9\u0084\u00D9\u0085\u00D8\u00AF\u00D8\u00A7\u00D8\u00AE\u00D9\u0084\u00D9\u0085\u00D9\u0085\u00D9\u0083\u00D9\u0086\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0007\u0006\u0005\u0004\u0003\u0002\u0001\u0000\u0008\t\n\u000B\u000C\r\u000E\u000F\u000F\u000E\r\u000C\u000B\n\t\u0008\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0017\u0016\u0015\u0014\u0013\u0012\u0011\u0010\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u001F\u001E\u001D\u001C\u001B\u001A\u0019\u0018\u00FF\u00FF\u00FF\u00FF\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u00FF\u00FF\u00FF\u00FF\u0001\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0003\u0000\u0000\u0000\u00FF\u00FF\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u00FF\u00FF\u0000\u0001\u0000\u0000\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0000\u0000\u0001\u0000\u0002\u0000\u0003\u0000\u0004\u0000\u0005\u0000\u0006\u0000\u0007resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter\" value=\"</select>Australia\" class=\"situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement\" title=\"potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>\r\nstatementattentionBiography} else {\nsolutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter\">\nexceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick=\"biographyotherwisepermanentFran\u00C3\u00A7aisHollywoodexpansionstandards</style>\nreductionDecember preferredCambridgeopponentsBusiness confusion>\n<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>\nmountainslike the essentialfinancialselectionaction=\"/abandonedEducationparseInt(stabilityunable to</title>\nrelationsNote thatefficientperformedtwo yearsSince thethereforewrapper\">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>\nsuspectedmargin: 0spiritual</head>\n\nmicrosoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header\">February numerous overflow:componentfragmentsexcellentcolspan=\"technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>\n\tsponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting\" width=\".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper\"enough toalong thedelivered-->\r\n<!--American protectedNovember </style><furnitureInternet onblur=\"suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir=\"ltr\"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;\n\nsouthwestthe rightradiationmay have unescape(spoken in\" href=\"/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip\">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>\ncame fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8\" /><![CDATA[\">ContactSouthern bgcolor=\"series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->\n<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=\">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id=\"precedingTechnicalphysicistoccurs innavigatorsection\">span id=\"sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt=\"in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent\">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id=\"right\">\r\nresidenceleave thecontent\">are often })();\r\nprobably Professor-button\" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular\">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor\n&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved\n\nIn the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also\n<head>\n<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained\"></div>\n</a></td>depend onsearch\">\npieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue=\"\">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.\n\nAfter , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover\" style=\"states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of\r\n<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href=\"y:inline;Church ofthe eventvery highofficial -height: content=\"/cgi-bin/to createafrikaansesperantofran\u00C3\u00A7aislatvie\u00C5\u00A1ulietuvi\u00C5\u00B3\u00C4\u008Ce\u00C5\u00A1tina\u00C4\u008De\u00C5\u00A1tina\u00E0\u00B9\u0084\u00E0\u00B8\u0097\u00E0\u00B8\u00A2\u00E6\u0097\u00A5\u00E6\u009C\u00AC\u00E8\u00AA\u009E\u00E7\u00AE\u0080\u00E4\u00BD\u0093\u00E5\u00AD\u0097\u00E7\u00B9\u0081\u00E9\u00AB\u0094\u00E5\u00AD\u0097\u00ED\u0095\u009C\u00EA\u00B5\u00AD\u00EC\u0096\u00B4\u00E4\u00B8\u00BA\u00E4\u00BB\u0080\u00E4\u00B9\u0088\u00E8\u00AE\u00A1\u00E7\u00AE\u0097\u00E6\u009C\u00BA\u00E7\u00AC\u0094\u00E8\u00AE\u00B0\u00E6\u009C\u00AC\u00E8\u00A8\u008E\u00E8\u00AB\u0096\u00E5\u008D\u0080\u00E6\u009C\u008D\u00E5\u008A\u00A1\u00E5\u0099\u00A8\u00E4\u00BA\u0092\u00E8\u0081\u0094\u00E7\u00BD\u0091\u00E6\u0088\u00BF\u00E5\u009C\u00B0\u00E4\u00BA\u00A7\u00E4\u00BF\u00B1\u00E4\u00B9\u0090\u00E9\u0083\u00A8\u00E5\u0087\u00BA\u00E7\u0089\u0088\u00E7\u00A4\u00BE\u00E6\u008E\u0092\u00E8\u00A1\u008C\u00E6\u00A6\u009C\u00E9\u0083\u00A8\u00E8\u0090\u00BD\u00E6\u00A0\u00BC\u00E8\u00BF\u009B\u00E4\u00B8\u0080\u00E6\u00AD\u00A5\u00E6\u0094\u00AF\u00E4\u00BB\u0098\u00E5\u00AE\u009D\u00E9\u00AA\u008C\u00E8\u00AF\u0081\u00E7\u00A0\u0081\u00E5\u00A7\u0094\u00E5\u0091\u0098\u00E4\u00BC\u009A\u00E6\u0095\u00B0\u00E6\u008D\u00AE\u00E5\u00BA\u0093\u00E6\u00B6\u0088\u00E8\u00B4\u00B9\u00E8\u0080\u0085\u00E5\u008A\u009E\u00E5\u0085\u00AC\u00E5\u00AE\u00A4\u00E8\u00AE\u00A8\u00E8\u00AE\u00BA\u00E5\u008C\u00BA\u00E6\u00B7\u00B1\u00E5\u009C\u00B3\u00E5\u00B8\u0082\u00E6\u0092\u00AD\u00E6\u0094\u00BE\u00E5\u0099\u00A8\u00E5\u008C\u0097\u00E4\u00BA\u00AC\u00E5\u00B8\u0082\u00E5\u00A4\u00A7\u00E5\u00AD\u00A6\u00E7\u0094\u009F\u00E8\u00B6\u008A\u00E6\u009D\u00A5\u00E8\u00B6\u008A\u00E7\u00AE\u00A1\u00E7\u0090\u0086\u00E5\u0091\u0098\u00E4\u00BF\u00A1\u00E6\u0081\u00AF\u00E7\u00BD\u0091serviciosart\u00C3\u00ADculoargentinabarcelonacualquierpublicadoproductospol\u00C3\u00ADticarespuestawikipediasiguienteb\u00C3\u00BAsquedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaci\u00C3\u00B3nnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconom\u00C3\u00ADaim\u00C3\u00A1genescontactardescargarnecesarioatenci\u00C3\u00B3ntel\u00C3\u00A9fonocomisi\u00C3\u00B3ncancionescapacidadencontraran\u00C3\u00A1lisisfavoritost\u00C3\u00A9rminosprovinciaetiquetaselementosfuncionesresultadocar\u00C3\u00A1cterpropiedadprincipionecesidadmunicipalcreaci\u00C3\u00B3ndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonz\u00C3\u00A1lezdocumentopel\u00C3\u00ADcularecientesgeneralestarragonapr\u00C3\u00A1cticanovedadespropuestapacientest\u00C3\u00A9cnicasobjetivoscontactos\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u008F\u00E0\u00A4\u00B9\u00E0\u00A5\u0088\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A5\u00E0\u00A4\u008F\u00E0\u00A4\u00B5\u00E0\u00A4\u0082\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A5\u008B\u00E0\u00A4\u0088\u00E0\u00A4\u0095\u00E0\u00A5\u0081\u00E0\u00A4\u009B\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u0095\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00AD\u00E0\u00A5\u0080\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u008F\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u00AE\u00E0\u00A5\u0088\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4diplodocs\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A4\u00AF\u00E0\u00A4\u00B0\u00E0\u00A5\u0082\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00AA\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00AB\u00E0\u00A4\u00BF\u00E0\u00A4\u00B0\u00E0\u00A4\u0094\u00E0\u00A4\u00B8\u00E0\u00A4\u00A4\u00E0\u00A4\u00A4\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A4\u00B2\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u0086\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u0088\u00E0\u00A4\u0096\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A4\u00AF\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00B5\u00E0\u00A5\u0087\u00E0\u00A4\u00AC\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u00A8\u00E0\u00A4\u00AC\u00E0\u00A5\u0080\u00E0\u00A4\u009A\u00E0\u00A4\u00AE\u00E0\u00A5\u008C\u00E0\u00A4\u00A4\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u009C\u00E0\u00A5\u0089\u00E0\u00A4\u00AC\u00E0\u00A4\u00AE\u00E0\u00A4\u00A6\u00E0\u00A4\u00A6\u00E0\u00A4\u00A4\u00E0\u00A4\u00A5\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u00B6\u00E0\u00A4\u00B9\u00E0\u00A4\u00B0\u00E0\u00A4\u0085\u00E0\u00A4\u00B2\u00E0\u00A4\u0097\u00E0\u00A4\u0095\u00E0\u00A4\u00AD\u00E0\u00A5\u0080\u00E0\u00A4\u00A8\u00E0\u00A4\u0097\u00E0\u00A4\u00B0\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u008F\u00E0\u00A4\u0089\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u0097\u00E0\u00A4\u00AF\u00E0\u00A5\u0080\u00E0\u00A4\u00B9\u00E0\u00A5\u0082\u00E0\u00A4\u0081\u00E0\u00A4\u0086\u00E0\u00A4\u0097\u00E0\u00A5\u0087\u00E0\u00A4\u009F\u00E0\u00A5\u0080\u00E0\u00A4\u00AE\u00E0\u00A4\u0096\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u0085\u00E0\u00A4\u00AD\u00E0\u00A5\u0080\u00E0\u00A4\u0097\u00E0\u00A4\u00AF\u00E0\u00A5\u0087\u00E0\u00A4\u00A4\u00E0\u00A5\u0081\u00E0\u00A4\u00AE\u00E0\u00A4\u00B5\u00E0\u00A5\u008B\u00E0\u00A4\u009F\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u0085\u00E0\u00A4\u0097\u00E0\u00A4\u00B0\u00E0\u00A4\u0090\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A4\u00B2\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u008A\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A4\u009A\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u0090\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00B0\u00E0\u00A4\u009C\u00E0\u00A4\u00BF\u00E0\u00A4\u00B8\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00AC\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A4\u00AC\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A5\u0082\u00E0\u00A4\u0082\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u0096\u00E0\u00A4\u009C\u00E0\u00A5\u0080\u00E0\u00A4\u00A4\u00E0\u00A4\u00AC\u00E0\u00A4\u009F\u00E0\u00A4\u00A8\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u0086\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A5\u0081\u00E0\u00A4\u00B2\u00E0\u00A4\u00B2\u00E0\u00A5\u0089\u00E0\u00A4\u0097\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u0097\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A4\u009C\u00E0\u00A4\u0097\u00E0\u00A4\u00B9\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00B2\u00E0\u00A4\u0097\u00E0\u00A5\u0087\u00E0\u00A4\u00AA\u00E0\u00A5\u0087\u00E0\u00A4\u009C\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u00A5\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u00A0\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0081\u00E0\u00A4\u00A6\u00E0\u00A5\u0082\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A4\u00B9\u00E0\u00A4\u00A4\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u0086\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u0095\u00E0\u00A5\u008C\u00E0\u00A4\u00A8\u00E0\u00A4\u00B6\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u00AF\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u0096\u00E0\u00A5\u0081\u00E0\u00A4\u00A6\u00E0\u00A4\u00B2\u00E0\u00A4\u0097\u00E0\u00A5\u0080categoriesexperience</title>\r\nCopyright javascriptconditionseverything<p class=\"technologybackground<a class=\"management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox\" techniquesprotectionapparentlyas well asunt', 'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor=\"#especially content=\"productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=\".indexOf(\"conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus=\"<form id=\"processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png\" (document,boundariesexpressionsettlementBackgroundout of theenterprise(\"https:\" unescape(\"password\" democratic<a href=\"/wrapper\">\nmembershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher\"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick=\"considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic\" height=\"link rel=\".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class=\"0px;marginmechanicalstatisticscelebratedGovernment\n\nDuring tdevelopersartificialequivalentoriginatedCommissionattachment<span id=\"there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang=\"en\" </style>\r\nabsolute; supportingextremely mainstream</strong> popularityemployment</table>\r\n colspan=\"</form>\n conversionabout the </p></div>integrated\" lang=\"enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class=\"<a title=\"(includingparametersprohibited= \"http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0\" class=\"completelyillustratefive yearsinstrumentPublishing1\" class=\"psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;\nfunction it was theConventionautomobileProtestantaggressiveafter the Similarly,\" /></div>collection\r\nfunctionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>\n</.indexOf('i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }\n</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt=\"adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to\"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css\"\tfunction innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>\n\tdiplomaticcontainingperformingextensionsmay not beconcept of onclick=\"It is alsofinancial making theLuxembourgadditionalare calledengaged in\"script\");but it waselectroniconsubmit=\"\n<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences\n</head>\r\nrecognisedinitializelimited toAlexandriaretirementAdventuresfour years\n\n&lt;!-- increasingdecorationh3 class=\"origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews\" width=\"1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class=\"Scientificclass=\"no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional\n<head>\n<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix\">the publicmany yearswhich wereover time,synonymouscontent\">\npresumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined\"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan=\"only a fewmeant thatled to the-->\r\n<div <fieldset>Archbishop class=\"nobeing usedapproachesprivilegesnoscript>\nresults inmay be theEaster eggmechanismsreasonablePopulationCollectionselected\">noscript>\r/index.phparrival of-jssdk'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>\n\t\tcomplaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype=\"absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>\npercentagebest-knowncreating a\" dir=\"ltrLieutenant\n<div id=\"they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.\n\nIn the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/\" class=\"geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid=\"searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured\">is said tostructuralreferendummost oftena separate->\n<div id Official worldwide.aria-labelthe planetand it wasd\" value=\"looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id=\"opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/\" title=\".com/indextaking thepittsburghcontent\">\r<script>(fturned outhaving the</span>\r\n occasionalbecause itstarted tophysically></div>\n created byCurrently, bgcolor=\"tabindex=\"disastrousAnalytics also has a><div id=\"</style>\n<called forsinger and.src = \"//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportugu\u00C3\u00AAs\u00D7\u00A2\u00D7\u0091\u00D7\u00A8\u00D7\u0099\u00D7\u00AA\u00D9\u0081\u00D8\u00A7\u00D8\u00B1\u00D8\u00B3\u00DB\u008Cdesarrollocomentarioeducaci\u00C3\u00B3nseptiembreregistradodirecci\u00C3\u00B3nubicaci\u00C3\u00B3npublicidadrespuestasresultadosimportantereservadosart\u00C3\u00ADculosdiferentessiguientesrep\u00C3\u00BAblicasituaci\u00C3\u00B3nministerioprivacidaddirectorioformaci\u00C3\u00B3npoblaci\u00C3\u00B3npresidentecontenidosaccesoriostechnoratipersonalescategor\u00C3\u00ADaespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopol\u00C3\u00ADticasanterioresdocumentosnaturalezamaterialesdiferenciaecon\u00C3\u00B3micatransporterodr\u00C3\u00ADguezparticiparencuentrandiscusi\u00C3\u00B3nestructurafundaci\u00C3\u00B3nfrecuentespermanentetotalmente\u00D0\u00BC\u00D0\u00BE\u00D0\u00B6\u00D0\u00BD\u00D0\u00BE\u00D0\u00B1\u00D1\u0083\u00D0\u00B4\u00D0\u00B5\u00D1\u0082\u00D0\u00BC\u00D0\u00BE\u00D0\u00B6\u00D0\u00B5\u00D1\u0082\u00D0\u00B2\u00D1\u0080\u00D0\u00B5\u00D0\u00BC\u00D1\u008F\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00B6\u00D0\u00B5\u00D1\u0087\u00D1\u0082\u00D0\u00BE\u00D0\u00B1\u00D1\u008B\u00D0\u00B1\u00D0\u00BE\u00D0\u00BB\u00D0\u00B5\u00D0\u00B5\u00D0\u00BE\u00D1\u0087\u00D0\u00B5\u00D0\u00BD\u00D1\u008C\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00BA\u00D0\u00BE\u00D0\u00B3\u00D0\u00B4\u00D0\u00B0\u00D0\u00BF\u00D0\u00BE\u00D1\u0081\u00D0\u00BB\u00D0\u00B5\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0081\u00D0\u00B0\u00D0\u00B9\u00D1\u0082\u00D0\u00B5\u00D1\u0087\u00D0\u00B5\u00D1\u0080\u00D0\u00B5\u00D0\u00B7\u00D0\u00BC\u00D0\u00BE\u00D0\u00B3\u00D1\u0083\u00D1\u0082\u00D1\u0081\u00D0\u00B0\u00D0\u00B9\u00D1\u0082\u00D0\u00B0\u00D0\u00B6\u00D0\u00B8\u00D0\u00B7\u00D0\u00BD\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D0\u00B6\u00D0\u00B4\u00D1\u0083\u00D0\u00B1\u00D1\u0083\u00D0\u00B4\u00D1\u0083\u00D1\u0082\u00D0\u009F\u00D0\u00BE\u00D0\u00B8\u00D1\u0081\u00D0\u00BA\u00D0\u00B7\u00D0\u00B4\u00D0\u00B5\u00D1\u0081\u00D1\u008C\u00D0\u00B2\u00D0\u00B8\u00D0\u00B4\u00D0\u00B5\u00D0\u00BE\u00D1\u0081\u00D0\u00B2\u00D1\u008F\u00D0\u00B7\u00D0\u00B8\u00D0\u00BD\u00D1\u0083\u00D0\u00B6\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B5\u00D0\u00B9\u00D0\u00BB\u00D1\u008E\u00D0\u00B4\u00D0\u00B5\u00D0\u00B9\u00D0\u00BF\u00D0\u00BE\u00D1\u0080\u00D0\u00BD\u00D0\u00BE\u00D0\u00BC\u00D0\u00BD\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D0\u00B5\u00D1\u0082\u00D0\u00B5\u00D0\u00B9\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B8\u00D1\u0085\u00D0\u00BF\u00D1\u0080\u00D0\u00B0\u00D0\u00B2\u00D0\u00B0\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00BE\u00D0\u00B9\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D0\u00B5\u00D1\u0082\u00D0\u00B6\u00D0\u00B8\u00D0\u00B7\u00D0\u00BD\u00D1\u008C\u00D0\u00BE\u00D0\u00B4\u00D0\u00BD\u00D0\u00BE\u00D0\u00B9\u00D0\u00BB\u00D1\u0083\u00D1\u0087\u00D1\u0088\u00D0\u00B5\u00D0\u00BF\u00D0\u00B5\u00D1\u0080\u00D0\u00B5\u00D0\u00B4\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D1\u0080\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D1\u008B\u00D1\u0085\u00D0\u00BF\u00D1\u0080\u00D0\u00B0\u00D0\u00B2\u00D0\u00BE\u00D1\u0081\u00D0\u00BE\u00D0\u00B1\u00D0\u00BE\u00D0\u00B9\u00D0\u00BF\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D0\u00B5\u00D0\u00B5\u00D1\u0087\u00D0\u00B8\u00D1\u0081\u00D0\u00BB\u00D0\u00B5\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D1\u008B\u00D0\u00B5\u00D1\u0083\u00D1\u0081\u00D0\u00BB\u00D1\u0083\u00D0\u00B3\u00D0\u00BE\u00D0\u00BA\u00D0\u00BE\u00D0\u00BB\u00D0\u00BE\u00D0\u00BD\u00D0\u00B0\u00D0\u00B7\u00D0\u00B0\u00D0\u00B4\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00BE\u00D0\u00B5\u00D1\u0082\u00D0\u00BE\u00D0\u00B3\u00D0\u00B4\u00D0\u00B0\u00D0\u00BF\u00D0\u00BE\u00D1\u0087\u00D1\u0082\u00D0\u00B8\u00D0\u009F\u00D0\u00BE\u00D1\u0081\u00D0\u00BB\u00D0\u00B5\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00B8\u00D0\u00B5\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D1\u008B\u00D0\u00B9\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D0\u00B8\u00D1\u0082\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00B8\u00D1\u0085\u00D1\u0081\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D1\u0083\u00D0\u00A1\u00D0\u00B0\u00D0\u00BD\u00D0\u00BA\u00D1\u0082\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D1\u0083\u00D0\u00BC\u00D0\u009A\u00D0\u00BE\u00D0\u00B3\u00D0\u00B4\u00D0\u00B0\u00D0\u00BA\u00D0\u00BD\u00D0\u00B8\u00D0\u00B3\u00D0\u00B8\u00D1\u0081\u00D0\u00BB\u00D0\u00BE\u00D0\u00B2\u00D0\u00B0\u00D0\u00BD\u00D0\u00B0\u00D1\u0088\u00D0\u00B5\u00D0\u00B9\u00D0\u00BD\u00D0\u00B0\u00D0\u00B9\u00D1\u0082\u00D0\u00B8\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B8\u00D0\u00BC\u00D1\u0081\u00D0\u00B2\u00D1\u008F\u00D0\u00B7\u00D1\u008C\u00D0\u00BB\u00D1\u008E\u00D0\u00B1\u00D0\u00BE\u00D0\u00B9\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D1\u0081\u00D1\u0080\u00D0\u00B5\u00D0\u00B4\u00D0\u00B8\u00D0\u009A\u00D1\u0080\u00D0\u00BE\u00D0\u00BC\u00D0\u00B5\u00D0\u00A4\u00D0\u00BE\u00D1\u0080\u00D1\u0083\u00D0\u00BC\u00D1\u0080\u00D1\u008B\u00D0\u00BD\u00D0\u00BA\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B0\u00D0\u00BB\u00D0\u00B8\u00D0\u00BF\u00D0\u00BE\u00D0\u00B8\u00D1\u0081\u00D0\u00BA\u00D1\u0082\u00D1\u008B\u00D1\u0081\u00D1\u008F\u00D1\u0087\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u008F\u00D1\u0086\u00D1\u0086\u00D0\u00B5\u00D0\u00BD\u00D1\u0082\u00D1\u0080\u00D1\u0082\u00D1\u0080\u00D1\u0083\u00D0\u00B4\u00D0\u00B0\u00D1\u0081\u00D0\u00B0\u00D0\u00BC\u00D1\u008B\u00D1\u0085\u00D1\u0080\u00D1\u008B\u00D0\u00BD\u00D0\u00BA\u00D0\u00B0\u00D0\u009D\u00D0\u00BE\u00D0\u00B2\u00D1\u008B\u00D0\u00B9\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D0\u00BE\u00D0\u00B2\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B0\u00D1\u0084\u00D0\u00B8\u00D0\u00BB\u00D1\u008C\u00D0\u00BC\u00D0\u00BC\u00D0\u00B0\u00D1\u0080\u00D1\u0082\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D0\u00BD\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B5\u00D1\u0082\u00D0\u00B5\u00D0\u00BA\u00D1\u0081\u00D1\u0082\u00D0\u00BD\u00D0\u00B0\u00D1\u0088\u00D0\u00B8\u00D1\u0085\u00D0\u00BC\u00D0\u00B8\u00D0\u00BD\u00D1\u0083\u00D1\u0082\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D1\u008E\u00D1\u0082\u00D0\u00BD\u00D0\u00BE\u00D0\u00BC\u00D0\u00B5\u00D1\u0080\u00D0\u00B3\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B4\u00D1\u0081\u00D0\u00B0\u00D0\u00BC\u00D0\u00BE\u00D0\u00BC\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D1\u0083\u00D0\u00BA\u00D0\u00BE\u00D0\u00BD\u00D1\u0086\u00D0\u00B5\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B5\u00D0\u00BC\u00D0\u00BA\u00D0\u00B0\u00D0\u00BA\u00D0\u00BE\u00D0\u00B9\u00D0\u0090\u00D1\u0080\u00D1\u0085\u00D0\u00B8\u00D0\u00B2\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00AF\u00D9\u0089\u00D8\u00A5\u00D8\u00B1\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D9\u0085\u00D9\u0083\u00D8\u00AA\u00D8\u00A8\u00D9\u0087\u00D8\u00A7\u00D8\u00A8\u00D8\u00B1\u00D8\u00A7\u00D9\u0085\u00D8\u00AC\u00D8\u00A7\u00D9\u0084\u00D9\u008A\u00D9\u0088\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D9\u0088\u00D8\u00B1\u00D8\u00AC\u00D8\u00AF\u00D9\u008A\u00D8\u00AF\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00B6\u00D9\u0088\u00D8\u00A5\u00D8\u00B6\u00D8\u00A7\u00D9\u0081\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0082\u00D8\u00B3\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D8\u00A8\u00D8\u00AA\u00D8\u00AD\u00D9\u0085\u00D9\u008A\u00D9\u0084\u00D9\u0085\u00D9\u0084\u00D9\u0081\u00D8\u00A7\u00D8\u00AA\u00D9\u0085\u00D9\u0084\u00D8\u00AA\u00D9\u0082\u00D9\u0089\u00D8\u00AA\u00D8\u00B9\u00D8\u00AF\u00D9\u008A\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00B4\u00D8\u00B9\u00D8\u00B1\u00D8\u00A3\u00D8\u00AE\u00D8\u00A8\u00D8\u00A7\u00D8\u00B1\u00D8\u00AA\u00D8\u00B7\u00D9\u0088\u00D9\u008A\u00D8\u00B1\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D9\u0083\u00D9\u0085\u00D8\u00A5\u00D8\u00B1\u00D9\u0081\u00D8\u00A7\u00D9\u0082\u00D8\u00B7\u00D9\u0084\u00D8\u00A8\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0084\u00D8\u00BA\u00D8\u00A9\u00D8\u00AA\u00D8\u00B1\u00D8\u00AA\u00D9\u008A\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D9\u0086\u00D8\u00A7\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00B4\u00D9\u008A\u00D8\u00AE\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00AF\u00D9\u008A\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00B1\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D9\u0082\u00D8\u00B5\u00D8\u00B5\u00D8\u00A7\u00D9\u0081\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D9\u0087\u00D8\u00A7\u00D8\u00AA\u00D8\u00AD\u00D8\u00AF\u00D9\u008A\u00D8\u00AB\u00D8\u00A7\u00D9\u0084\u00D9\u0084\u00D9\u0087\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D9\u0085\u00D9\u0084\u00D9\u0085\u00D9\u0083\u00D8\u00AA\u00D8\u00A8\u00D8\u00A9\u00D9\u008A\u00D9\u0085\u00D9\u0083\u00D9\u0086\u00D9\u0083\u00D8\u00A7\u00D9\u0084\u00D8\u00B7\u00D9\u0081\u00D9\u0084\u00D9\u0081\u00D9\u008A\u00D8\u00AF\u00D9\u008A\u00D9\u0088\u00D8\u00A5\u00D8\u00AF\u00D8\u00A7\u00D8\u00B1\u00D8\u00A9\u00D8\u00AA\u00D8\u00A7\u00D8\u00B1\u00D9\u008A\u00D8\u00AE\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D8\u00AD\u00D8\u00A9\u00D8\u00AA\u00D8\u00B3\u00D8\u00AC\u00D9\u008A\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D9\u0088\u00D9\u0082\u00D8\u00AA\u00D8\u00B9\u00D9\u0086\u00D8\u00AF\u00D9\u0085\u00D8\u00A7\u00D9\u0085\u00D8\u00AF\u00D9\u008A\u00D9\u0086\u00D8\u00A9\u00D8\u00AA\u00D8\u00B5\u00D9\u0085\u00D9\u008A\u00D9\u0085\u00D8\u00A3\u00D8\u00B1\u00D8\u00B4\u00D9\u008A\u00D9\u0081\u00D8\u00A7\u00D9\u0084\u00D8\u00B0\u00D9\u008A\u00D9\u0086\u00D8\u00B9\u00D8\u00B1\u00D8\u00A8\u00D9\u008A\u00D8\u00A9\u00D8\u00A8\u00D9\u0088\u00D8\u00A7\u00D8\u00A8\u00D8\u00A9\u00D8\u00A3\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D9\u0081\u00D8\u00B1\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D9\u0083\u00D9\u0084\u00D8\u00AA\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D9\u0089\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D9\u0088\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D9\u0086\u00D8\u00A9\u00D8\u00AC\u00D8\u00A7\u00D9\u0085\u00D8\u00B9\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D8\u00AD\u00D9\u0081\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u008A\u00D9\u0086\u00D9\u0083\u00D9\u0084\u00D9\u0085\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00AE\u00D8\u00A7\u00D8\u00B5\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0084\u00D9\u0081\u00D8\u00A3\u00D8\u00B9\u00D8\u00B6\u00D8\u00A7\u00D8\u00A1\u00D9\u0083\u00D8\u00AA\u00D8\u00A7\u00D8\u00A8\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AE\u00D9\u008A\u00D8\u00B1\u00D8\u00B1\u00D8\u00B3\u00D8\u00A7\u00D8\u00A6\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D9\u0082\u00D9\u0084\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00AF\u00D8\u00A8\u00D9\u0085\u00D9\u0082\u00D8\u00A7\u00D8\u00B7\u00D8\u00B9\u00D9\u0085\u00D8\u00B1\u00D8\u00A7\u00D8\u00B3\u00D9\u0084\u00D9\u0085\u00D9\u0086\u00D8\u00B7\u00D9\u0082\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D8\u00AA\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00AC\u00D9\u0084\u00D8\u00A7\u00D8\u00B4\u00D8\u00AA\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D9\u0084\u00D9\u0082\u00D8\u00AF\u00D9\u0085\u00D9\u008A\u00D8\u00B9\u00D8\u00B7\u00D9\u008A\u00D9\u0083sByTagName(.jpg\" alt=\"1px solid #.gif\" alt=\"transparentinformationapplication\" onclick=\"establishedadvertising.png\" alt=\"environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright\">0\" height=\"even thoughreplacementdestinationCorporation<ul class=\"AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class=\"hundreds of\n\nHowever, compositionclear:both;cooperationwithin the label for=\"border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength=\"switzerlandDevelopmentessentially\n\nAlthough </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics\n\t<div id=\"illustratedengineeringterritoriesauthoritiesdistributed6\" height=\"sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class=\"more recentit has beeninvasion of).getTime()fundamentalDespite the\"><div id=\"inspirationexaminationpreparationexplanation<input id=\"</a></span>versions ofinstrumentsbefore the = 'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright\" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content\">\n<td class=\"undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src=\"/<h1 class=\"publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=\";width:100%independent<h3 class=\" onchange=\").addClass(interactionOne of the daughter ofaccessoriesbranches of\r\n<div id=\"the largestdeclarationregulationsInformationtranslationdocumentaryin order to\">\n<head>\n<\" height=\"1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer\">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class=\"distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>\n</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>\n selected=\"high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1\"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex=\"it could be<noscript>\nhaving been\r\n<head>\r\n< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often\"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval\"></span></in New Yorkadditional compression\n\n<div id=\"incorporate;</script><attachEventbecame the \" target=\"_carried outSome of thescience andthe time ofContainer\">maintainingChristopherMuch of thewritings of\" height=\"2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit=\"director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class=\"Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the\" height=\"3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>\r\nContinentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name=\"TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel=\"This is the <a href=\"/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og=\"><a class=\"class=\"textConversion may be usedmanufactureafter beingclearfix\">\nquestion ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html\"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period\" name=\"q\" confined toa result ofvalue=\"\" />is actuallyEnvironment\r\n</head>\r\nConversely,>\n<div id=\"0\" width=\"1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious\">this is notthe presentif they areand finallya matter of\r\n\t</div>\r\n\r\n</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer\" class=\"frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>\n<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger\n\t</script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>\n they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight=\"0\" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class=\"btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world'scan lead torefers to aborder=\"0\" government winning theresulted in while the Washington,the subjectcity in the></div>\r\n\t\treflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=\"\"><a href=\"themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href=\"/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in\t\t<div id=\"it\" value=\"language ofas they areproduced inis that theexplain thediv></div>\nHowever thelead to the\t<a href=\"/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldsloven\u00C4\u008Dinacomentariosuniversidadcondicionesactividadesexperienciatecnolog\u00C3\u00ADaproducci\u00C3\u00B3npuntuaci\u00C3\u00B3naplicaci\u00C3\u00B3ncontrase\u00C3\u00B1acategor\u00C3\u00ADasregistrarseprofesionaltratamientoreg\u00C3\u00ADstratesecretar\u00C3\u00ADaprincipalesprotecci\u00C3\u00B3nimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociaci\u00C3\u00B3ndisponiblesevaluaci\u00C3\u00B3nestudiantesresponsableresoluci\u00C3\u00B3nguadalajararegistradosoportunidadcomercialesfotograf\u00C3\u00ADaautoridadesingenier\u00C3\u00ADatelevisi\u00C3\u00B3ncompetenciaoperacionesestablecidosimplementeactualmentenavegaci\u00C3\u00B3nconformidadline-height:font-family:\" : \"http://applicationslink\" href=\"specifically//<![CDATA[\nOrganizationdistribution0px; height:relationshipdevice-width<div class=\"<label for=\"registration</noscript>\n/index.html\"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name=\"intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class=\"organisationcivilization19th centuryarchitectureincorporated20th century-container\">most notably/></a></div>notification'undefined')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang=\"&lt;/sup&gt;dealing withphiladelphiahistorically);</script>\npadding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd\">\r\n<htgeographicalConstitution', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style=\"Encyclopediaiframe src=\"demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence\" tabindex=\"float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time\"><a class=\"In addition,description+conversationcontact withis generallyr\" content=\"representing&lt;math&gt;presentationoccasionally<img width=\"navigation\">compensationchampionshipmedia=\"all\" violation ofreference toreturn true;Strict//EN\" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}\n</script>\nChristianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=\"\"><a href=\"/introductionbelonging toclaimed thatconsequences<meta name=\"Guide to theoverwhelmingagainst the concentrated,\n.nontouch observations</a>\n</div>\nf (document.border: 1px {font-size:1treatment of0\" height=\"1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript\" neverthelesssignificanceBroadcasting>&nbsp;</td>container\">\nsuch as the influence ofa particularsrc='http://navigation\" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite\" xml:lang=\"deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype=\"image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet\t<ul class=\"installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures\n\t\t<a href=\"close to theexamples of is about the(see below).\" id=\"searchprofessionalis availablethe official\t\t</script>\n\n\t\t<div id=\"accelerationthrough the Hall of Famedescriptionstranslationsinterference type='text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the\t<li class=\"instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class=\"aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc=\"http://px; height: available tomanufacturerhuman rightslink href=\"/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>\r\nconsider thean estimatedthe National<div id=\"pagresulting incommissionedanalogous toare required/ul>\n</div>\nwas based onand became a&nbsp;&nbsp;t\" value=\"\" was capturedno more thanrespectivelycontinue to >\r\n<head>\r\n<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml\" title=\"weight:bold;creating thedisplay:nonereplaced the<img src=\"/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css\" media=\"People from available onproved to besuggestions\"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class=\"evidence forexplanationsenvironments\"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign=\"top\"principle ofat the time,</noscript>\rsaid to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style=\"input name=\"the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class=\"lastworking with'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the\n</script>\n\nan effort toincrease theto the southspacing=\"0\">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>\nthought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds\" content=\"authority ofnorthwestern</div>\n<div \"></div>\r\n consultationcommunity ofthe nationalit should beparticipants align=\"leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class=\"splace in thewhere he was<li class=\"fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions\">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class=\"effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previous";
+ }
+ }
+
+ private class DataHolder2
+ {
+ internal static string GetData()
+ {
+ return "consistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\\s+|\\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers\t<link rel=\"provided thethe story ofcompetitionsenglish (UK)english (US)\u00D0\u009C\u00D0\u00BE\u00D0\u00BD\u00D0\u00B3\u00D0\u00BE\u00D0\u00BB\u00D0\u00A1\u00D1\u0080\u00D0\u00BF\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D1\u0081\u00D1\u0080\u00D0\u00BF\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D1\u0081\u00D1\u0080\u00D0\u00BF\u00D1\u0081\u00D0\u00BA\u00D0\u00BE\u00D9\u0084\u00D8\u00B9\u00D8\u00B1\u00D8\u00A8\u00D9\u008A\u00D8\u00A9\u00E6\u00AD\u00A3\u00E9\u00AB\u0094\u00E4\u00B8\u00AD\u00E6\u0096\u0087\u00E7\u00AE\u0080\u00E4\u00BD\u0093\u00E4\u00B8\u00AD\u00E6\u0096\u0087\u00E7\u00B9\u0081\u00E4\u00BD\u0093\u00E4\u00B8\u00AD\u00E6\u0096\u0087\u00E6\u009C\u0089\u00E9\u0099\u0090\u00E5\u0085\u00AC\u00E5\u008F\u00B8\u00E4\u00BA\u00BA\u00E6\u00B0\u0091\u00E6\u0094\u00BF\u00E5\u00BA\u009C\u00E9\u0098\u00BF\u00E9\u0087\u008C\u00E5\u00B7\u00B4\u00E5\u00B7\u00B4\u00E7\u00A4\u00BE\u00E4\u00BC\u009A\u00E4\u00B8\u00BB\u00E4\u00B9\u0089\u00E6\u0093\u008D\u00E4\u00BD\u009C\u00E7\u00B3\u00BB\u00E7\u00BB\u009F\u00E6\u0094\u00BF\u00E7\u00AD\u0096\u00E6\u00B3\u0095\u00E8\u00A7\u0084informaci\u00C3\u00B3nherramientaselectr\u00C3\u00B3nicodescripci\u00C3\u00B3nclasificadosconocimientopublicaci\u00C3\u00B3nrelacionadasinform\u00C3\u00A1ticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecont\u00C3\u00A1ctenoshabitacionescumplimientorestaurantesdisposici\u00C3\u00B3nconsecuenciaelectr\u00C3\u00B3nicaaplicacionesdesconectadoinstalaci\u00C3\u00B3nrealizaci\u00C3\u00B3nutilizaci\u00C3\u00B3nenciclopediaenfermedadesinstrumentosexperienciasinstituci\u00C3\u00B3nparticularessubcategoria\u00D1\u0082\u00D0\u00BE\u00D0\u00BB\u00D1\u008C\u00D0\u00BA\u00D0\u00BE\u00D0\u00A0\u00D0\u00BE\u00D1\u0081\u00D1\u0081\u00D0\u00B8\u00D0\u00B8\u00D1\u0080\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D1\u008B\u00D0\u00B1\u00D0\u00BE\u00D0\u00BB\u00D1\u008C\u00D1\u0088\u00D0\u00B5\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D0\u00BE\u00D0\u00B6\u00D0\u00B5\u00D1\u0082\u00D0\u00B5\u00D0\u00B4\u00D1\u0080\u00D1\u0083\u00D0\u00B3\u00D0\u00B8\u00D1\u0085\u00D1\u0081\u00D0\u00BB\u00D1\u0083\u00D1\u0087\u00D0\u00B0\u00D0\u00B5\u00D1\u0081\u00D0\u00B5\u00D0\u00B9\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00B3\u00D0\u00B4\u00D0\u00B0\u00D0\u00A0\u00D0\u00BE\u00D1\u0081\u00D1\u0081\u00D0\u00B8\u00D1\u008F\u00D0\u009C\u00D0\u00BE\u00D1\u0081\u00D0\u00BA\u00D0\u00B2\u00D0\u00B5\u00D0\u00B4\u00D1\u0080\u00D1\u0083\u00D0\u00B3\u00D0\u00B8\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B4\u00D0\u00B0\u00D0\u00B2\u00D0\u00BE\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D1\u0081\u00D0\u00B4\u00D0\u00B0\u00D0\u00BD\u00D0\u00BD\u00D1\u008B\u00D1\u0085\u00D0\u00B4\u00D0\u00BE\u00D0\u00BB\u00D0\u00B6\u00D0\u00BD\u00D1\u008B\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D0\u00BD\u00D0\u00BE\u00D0\u009C\u00D0\u00BE\u00D1\u0081\u00D0\u00BA\u00D0\u00B2\u00D1\u008B\u00D1\u0080\u00D1\u0083\u00D0\u00B1\u00D0\u00BB\u00D0\u00B5\u00D0\u00B9\u00D0\u009C\u00D0\u00BE\u00D1\u0081\u00D0\u00BA\u00D0\u00B2\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D0\u00BD\u00D1\u008B\u00D0\u00BD\u00D0\u00B8\u00D1\u0087\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0080\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D0\u00B5\u00D0\u00B4\u00D0\u00BE\u00D0\u00BB\u00D0\u00B6\u00D0\u00B5\u00D0\u00BD\u00D1\u0083\u00D1\u0081\u00D0\u00BB\u00D1\u0083\u00D0\u00B3\u00D0\u00B8\u00D1\u0082\u00D0\u00B5\u00D0\u00BF\u00D0\u00B5\u00D1\u0080\u00D1\u008C\u00D0\u009E\u00D0\u00B4\u00D0\u00BD\u00D0\u00B0\u00D0\u00BA\u00D0\u00BE\u00D0\u00BF\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D1\u0083\u00D1\u0080\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D1\u0083\u00D0\u00B0\u00D0\u00BF\u00D1\u0080\u00D0\u00B5\u00D0\u00BB\u00D1\u008F\u00D0\u00B2\u00D0\u00BE\u00D0\u00BE\u00D0\u00B1\u00D1\u0089\u00D0\u00B5\u00D0\u00BE\u00D0\u00B4\u00D0\u00BD\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D1\u0081\u00D0\u00B2\u00D0\u00BE\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00B8\u00D0\u00B4\u00D1\u0080\u00D1\u0083\u00D0\u00B3\u00D0\u00BE\u00D0\u00B9\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D1\u0083\u00D0\u00BC\u00D0\u00B5\u00D1\u0085\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D1\u0088\u00D0\u00BE\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D1\u0082\u00D0\u00B8\u00D0\u00B2\u00D1\u0081\u00D1\u0081\u00D1\u008B\u00D0\u00BB\u00D0\u00BA\u00D0\u00B0\u00D0\u00BA\u00D0\u00B0\u00D0\u00B6\u00D0\u00B4\u00D1\u008B\u00D0\u00B9\u00D0\u00B2\u00D0\u00BB\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00B3\u00D1\u0080\u00D1\u0083\u00D0\u00BF\u00D0\u00BF\u00D1\u008B\u00D0\u00B2\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D0\u00B0\u00D1\u0081\u00D0\u00BA\u00D0\u00B0\u00D0\u00B7\u00D0\u00B0\u00D0\u00BB\u00D0\u00BF\u00D0\u00B5\u00D1\u0080\u00D0\u00B2\u00D1\u008B\u00D0\u00B9\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00B4\u00D0\u00B5\u00D0\u00BD\u00D1\u008C\u00D0\u00B3\u00D0\u00B8\u00D0\u00BF\u00D0\u00B5\u00D1\u0080\u00D0\u00B8\u00D0\u00BE\u00D0\u00B4\u00D0\u00B1\u00D0\u00B8\u00D0\u00B7\u00D0\u00BD\u00D0\u00B5\u00D1\u0081\u00D0\u00BE\u00D1\u0081\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D0\u00B5\u00D0\u00BC\u00D0\u00BE\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D1\u0082\u00D0\u00BA\u00D1\u0083\u00D0\u00BF\u00D0\u00B8\u00D1\u0082\u00D1\u008C\u00D0\u00B4\u00D0\u00BE\u00D0\u00BB\u00D0\u00B6\u00D0\u00BD\u00D0\u00B0\u00D1\u0080\u00D0\u00B0\u00D0\u00BC\u00D0\u00BA\u00D0\u00B0\u00D1\u0085\u00D0\u00BD\u00D0\u00B0\u00D1\u0087\u00D0\u00B0\u00D0\u00BB\u00D0\u00BE\u00D0\u00A0\u00D0\u00B0\u00D0\u00B1\u00D0\u00BE\u00D1\u0082\u00D0\u00B0\u00D0\u00A2\u00D0\u00BE\u00D0\u00BB\u00D1\u008C\u00D0\u00BA\u00D0\u00BE\u00D1\u0081\u00D0\u00BE\u00D0\u00B2\u00D1\u0081\u00D0\u00B5\u00D0\u00BC\u00D0\u00B2\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B9\u00D0\u00BD\u00D0\u00B0\u00D1\u0087\u00D0\u00B0\u00D0\u00BB\u00D0\u00B0\u00D1\u0081\u00D0\u00BF\u00D0\u00B8\u00D1\u0081\u00D0\u00BE\u00D0\u00BA\u00D1\u0081\u00D0\u00BB\u00D1\u0083\u00D0\u00B6\u00D0\u00B1\u00D1\u008B\u00D1\u0081\u00D0\u00B8\u00D1\u0081\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D0\u00BF\u00D0\u00B5\u00D1\u0087\u00D0\u00B0\u00D1\u0082\u00D0\u00B8\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00BF\u00D0\u00BE\u00D0\u00BC\u00D0\u00BE\u00D1\u0089\u00D0\u00B8\u00D1\u0081\u00D0\u00B0\u00D0\u00B9\u00D1\u0082\u00D0\u00BE\u00D0\u00B2\u00D0\u00BF\u00D0\u00BE\u00D1\u0087\u00D0\u00B5\u00D0\u00BC\u00D1\u0083\u00D0\u00BF\u00D0\u00BE\u00D0\u00BC\u00D0\u00BE\u00D1\u0089\u00D1\u008C\u00D0\u00B4\u00D0\u00BE\u00D0\u00BB\u00D0\u00B6\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0081\u00D1\u008B\u00D0\u00BB\u00D0\u00BA\u00D0\u00B8\u00D0\u00B1\u00D1\u008B\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00BE\u00D0\u00B4\u00D0\u00B0\u00D0\u00BD\u00D0\u00BD\u00D1\u008B\u00D0\u00B5\u00D0\u00BC\u00D0\u00BD\u00D0\u00BE\u00D0\u00B3\u00D0\u00B8\u00D0\u00B5\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B5\u00D0\u00BA\u00D1\u0082\u00D0\u00A1\u00D0\u00B5\u00D0\u00B9\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D0\u00BC\u00D0\u00BE\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00B8\u00D1\u0082\u00D0\u00B0\u00D0\u00BA\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D0\u00BE\u00D0\u00BD\u00D0\u00BB\u00D0\u00B0\u00D0\u00B9\u00D0\u00BD\u00D0\u00B3\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B4\u00D0\u00B5\u00D0\u00B2\u00D0\u00B5\u00D1\u0080\u00D1\u0081\u00D0\u00B8\u00D1\u008F\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D0\u00BD\u00D0\u00B5\u00D1\u0084\u00D0\u00B8\u00D0\u00BB\u00D1\u008C\u00D0\u00BC\u00D1\u008B\u00D1\u0083\u00D1\u0080\u00D0\u00BE\u00D0\u00B2\u00D0\u00BD\u00D1\u008F\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00BD\u00D1\u008B\u00D1\u0085\u00D0\u00B8\u00D1\u0081\u00D0\u00BA\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00BD\u00D0\u00B5\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D1\u008E\u00D1\u008F\u00D0\u00BD\u00D0\u00B2\u00D0\u00B0\u00D1\u0080\u00D1\u008F\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D1\u008C\u00D1\u0088\u00D0\u00B5\u00D0\u00BC\u00D0\u00BD\u00D0\u00BE\u00D0\u00B3\u00D0\u00B8\u00D1\u0085\u00D0\u00B4\u00D0\u00B0\u00D0\u00BD\u00D0\u00BD\u00D0\u00BE\u00D0\u00B9\u00D0\u00B7\u00D0\u00BD\u00D0\u00B0\u00D1\u0087\u00D0\u00B8\u00D1\u0082\u00D0\u00BD\u00D0\u00B5\u00D0\u00BB\u00D1\u008C\u00D0\u00B7\u00D1\u008F\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D1\u0083\u00D0\u00BC\u00D0\u00B0\u00D0\u00A2\u00D0\u00B5\u00D0\u00BF\u00D0\u00B5\u00D1\u0080\u00D1\u008C\u00D0\u00BC\u00D0\u00B5\u00D1\u0081\u00D1\u008F\u00D1\u0086\u00D0\u00B0\u00D0\u00B7\u00D0\u00B0\u00D1\u0089\u00D0\u00B8\u00D1\u0082\u00D1\u008B\u00D0\u009B\u00D1\u0083\u00D1\u0087\u00D1\u0088\u00D0\u00B8\u00D0\u00B5\u00E0\u00A4\u00A8\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u0082\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0085\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u0085\u00E0\u00A4\u00A8\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u0087\u00E0\u00A4\u00A1\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00B8\u00E0\u00A5\u0080\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00B9\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00BF\u00E0\u00A4\u0082\u00E0\u00A4\u00B9\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A4\u0085\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00AC\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u00A4\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u0087\u00E0\u00A4\u009F\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A4\u009F\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u00AF\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0081\u00E0\u00A4\u00B8\u00E0\u00A4\u00AC\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u00B7\u00E0\u00A4\u00BE\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A5\u0082\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u0098\u00E0\u00A4\u0082\u00E0\u00A4\u009F\u00E0\u00A5\u0087\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u0085\u00E0\u00A4\u00A7\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u0085\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00AE\u00E0\u00A5\u0081\u00E0\u00A4\u009D\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A3\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A5\u0080\u00E0\u00A4\u00AF\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u009F\u00E0\u00A4\u00B2\u00E0\u00A4\u00B6\u00E0\u00A4\u00AC\u00E0\u00A5\u008D\u00E0\u00A4\u00A6\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A4\u00A8\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A5\u0088\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00AA\u00E0\u00A5\u0082\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A5\u0080\u00E0\u00A4\u0089\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A5\u0080\u00E0\u00A4\u00AC\u00E0\u00A5\u0088\u00E0\u00A4\u00A0\u00E0\u00A4\u0095\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u0095\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00B7\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00B5\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u0095\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A4\u00A4\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A5\u0080\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A5\u0082\u00E0\u00A4\u00A6\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u009C\u00E0\u00A4\u00B8\u00E0\u00A5\u0082\u00E0\u00A4\u009A\u00E0\u00A5\u0080\u00E0\u00A4\u00AA\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A4\u00B8\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u009C\u00E0\u00A5\u0088\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00B8\u00E0\u00A4\u009C\u00E0\u00A4\u00A8\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u0098\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00B2\u00E0\u00A4\u009C\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A5\u0080\u00E0\u00A4\u009A\u00E0\u00A5\u0087\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00AA\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u0097\u00E0\u00A5\u0082\u00E0\u00A4\u0097\u00E0\u00A4\u00B2\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00B0\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00A8\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A5\u0081\u00E0\u00A4\u00AC\u00E0\u00A4\u00B9\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00B9\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00AC\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A5\u0087\u00E0\u00A4\u0098\u00E0\u00A4\u009F\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u00B6\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00B6\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00AC\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A5\u0080\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u0088\u00E0\u00A4\u009F\u00E0\u00A4\u00B6\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00A6\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00AA\u00E0\u00A4\u009F\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u0096\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A4\u0095\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u0089\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00B2\u00E0\u00A4\u00B2\u00E0\u00A4\u0097\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u0096\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u0085\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u009C\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00B9\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00E0\u00A4\u00A8\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00AE\u00E0\u00A4\u00AC\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AC\u00E0\u00A5\u0088\u00E0\u00A4\u0082\u00E0\u00A4\u0095\u00E0\u00A4\u0095\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u0082\u00E0\u00A4\u0095\u00E0\u00A4\u00B9\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00AB\u00E0\u00A5\u0080\u00E0\u00A4\u009C\u00E0\u00A4\u00AC\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A4\u00B5\u00E0\u00A4\u00B9\u00E0\u00A5\u0080\u00E0\u00A4\u0082\u00E0\u00A4\u00B0\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A4\u00BC\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00E0\u00A4\u0086\u00E0\u00A4\u00B0\u00E0\u00A5\u008B\u00E0\u00A4\u00AA\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u00B5\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00AC\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00AC\u00E0\u00A4\u00AA\u00E0\u00A5\u0082\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AC\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A5\u008C\u00E0\u00A4\u00A6\u00E0\u00A4\u00BE\u00E0\u00A4\u00B6\u00E0\u00A5\u0087\u00E0\u00A4\u00AF\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u0085\u00E0\u00A4\u0095\u00E0\u00A4\u00B8\u00E0\u00A4\u00B0\u00E0\u00A4\u00AC\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u008F\u00E0\u00A4\u00B5\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00B2\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u0095\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00B7\u00E0\u00A4\u00AF\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u0082\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A5\u0082\u00E0\u00A4\u00B9\u00E0\u00A4\u00A5\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00D8\u00AA\u00D8\u00B3\u00D8\u00AA\u00D8\u00B7\u00D9\u008A\u00D8\u00B9\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A9\u00D8\u00A8\u00D9\u0088\u00D8\u00A7\u00D8\u00B3\u00D8\u00B7\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D9\u0081\u00D8\u00AD\u00D8\u00A9\u00D9\u0085\u00D9\u0088\u00D8\u00A7\u00D8\u00B6\u00D9\u008A\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00AE\u00D8\u00A7\u00D8\u00B5\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B2\u00D9\u008A\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D9\u0085\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00AF\u00D9\u0088\u00D8\u00AF\u00D8\u00A8\u00D8\u00B1\u00D9\u0086\u00D8\u00A7\u00D9\u0085\u00D8\u00AC\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u0088\u00D9\u0084\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0088\u00D9\u0082\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00B1\u00D8\u00A8\u00D9\u008A\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D8\u00B1\u00D9\u008A\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D9\u0088\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00B0\u00D9\u0087\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AD\u00D9\u008A\u00D8\u00A7\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AD\u00D9\u0082\u00D9\u0088\u00D9\u0082\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D8\u00B1\u00D9\u008A\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00B1\u00D8\u00A7\u00D9\u0082\u00D9\u0085\u00D8\u00AD\u00D9\u0081\u00D9\u0088\u00D8\u00B8\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AB\u00D8\u00A7\u00D9\u0086\u00D9\u008A\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D9\u0087\u00D8\u00AF\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B1\u00D8\u00A3\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0082\u00D8\u00B1\u00D8\u00A2\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D8\u00B4\u00D8\u00A8\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AD\u00D9\u0088\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D8\u00AF\u00D9\u008A\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00B3\u00D8\u00B1\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D9\u0084\u00D9\u0088\u00D9\u0085\u00D9\u0085\u00D8\u00AC\u00D9\u0085\u00D9\u0088\u00D8\u00B9\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00AD\u00D9\u0085\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D9\u0086\u00D9\u0082\u00D8\u00A7\u00D8\u00B7\u00D9\u0081\u00D9\u0084\u00D8\u00B3\u00D8\u00B7\u00D9\u008A\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D9\u0088\u00D9\u008A\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u0086\u00D9\u008A\u00D8\u00A7\u00D8\u00A8\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D9\u008A\u00D8\u00A7\u00D8\u00B6\u00D8\u00AA\u00D8\u00AD\u00D9\u008A\u00D8\u00A7\u00D8\u00AA\u00D9\u008A\u00D8\u00A8\u00D8\u00AA\u00D9\u0088\u00D9\u0082\u00D9\u008A\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D9\u0088\u00D9\u0084\u00D9\u0089\u00D8\u00A7\u00D9\u0084\u00D8\u00A8\u00D8\u00B1\u00D9\u008A\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00A7\u00D8\u00A8\u00D8\u00B7\u00D8\u00A7\u00D9\u0084\u00D8\u00B4\u00D8\u00AE\u00D8\u00B5\u00D9\u008A\u00D8\u00B3\u00D9\u008A\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00AB\u00D8\u00A7\u00D9\u0084\u00D8\u00AB\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D9\u0084\u00D8\u00A7\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AD\u00D8\u00AF\u00D9\u008A\u00D8\u00AB\u00D8\u00A7\u00D9\u0084\u00D8\u00B2\u00D9\u0088\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D8\u00AE\u00D9\u0084\u00D9\u008A\u00D8\u00AC\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D9\u0085\u00D9\u008A\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D9\u0085\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D8\u00A7\u00D8\u00B9\u00D8\u00A9\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D9\u0087\u00D8\u00AF\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00A6\u00D9\u008A\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D8\u00AE\u00D9\u0088\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D9\u0081\u00D9\u0086\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D8\u00AA\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u0088\u00D8\u00B1\u00D9\u008A\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D8\u00B1\u00D9\u0088\u00D8\u00B3\u00D8\u00A7\u00D8\u00B3\u00D8\u00AA\u00D8\u00BA\u00D8\u00B1\u00D9\u0082\u00D8\u00AA\u00D8\u00B5\u00D8\u00A7\u00D9\u0085\u00D9\u008A\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A8\u00D9\u0086\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00B8\u00D9\u008A\u00D9\u0085entertainmentunderstanding = function().jpg\" width=\"configuration.png\" width=\"<body class=\"Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=\"\"><img src=\"/distinguishedthousands of communicationclear\"></div>investigationfavicon.ico\" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch\" type=\"form method=\"as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of\" maxlength=\"return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type=\"the number ofthe original comprehensiverefers to the</ul>\n</div>\nphilosophicallocation.hrefwas publishedSan Francisco(function(){\n<div id=\"mainsophisticatedmathematical /head>\r\n<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder=\"; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript\" src=\"/(function() {are available\n\t<link rel=\" src='http://interested inconventional \" alt=\"\" /></are generallyhas also beenmost popular correspondingcredited withtyle=\"border:</a></span></.gif\" width=\"<iframe src=\"table class=\"inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name=\"or\" content=\"controversialproperty=\"og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style=\"known as the shortly afterfor instance,described as /head>\n<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant\" border=\"0\">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name=\"searchattributed tocourse of themathematicianby the end ofat the end of\" border=\"0\" technological.removeClass(branch of theevidence that![endif]-->\r\nInstitute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href=\"confused with<link href=\"/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>\n</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription\" determine theavailable forAccording to wide range of\t<div class=\"more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover=\"because they async = true;problems withseems to havethe result of src=\"http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld's firstclassified asbottom of the(particularlyalign=\"left\" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout=\"New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd\">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to\t<meta name=\"are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to\t\t<ul class=\"visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style=\"equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these\n<div class=\"input class=\"replaced withis one of theeducation andinfluenced byreputation as\n<meta name=\"accommodation</div>\n</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the\n<div style=\"almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in\" value=\"\" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class=\"mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription\">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass=\"headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;\n</script>\n<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle=\"marginincluding thebahasa Melayunorsk bokm\u00C3\u00A5lnorsk nynorsksloven\u00C5\u00A1\u00C4\u008Dinainternacionalcalificaci\u00C3\u00B3ncomunicaci\u00C3\u00B3nconstrucci\u00C3\u00B3n\"><div class=\"disambiguationDomainName', 'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->\n</><meta name=\"implementationinfrastructurerepresentationborder-bottom:</head>\n<body>=http%3A%2F%2F<form method=\"method=\"post\" /favicon.ico\" });\n</script>\n.setAttribute(Administration= new Array();<![endif]-->\r\ndisplay:block;Unfortunately,\">&nbsp;</div>/favicon.ico\">='stylesheet' identification, for example,<li><a href=\"/an alternativeas a result ofpt\"></script>\ntype=\"submit\" \n(function() {recommendationform action=\"/transformationreconstruction.style.display According to hidden\" name=\"along with thedocument.body.approximately Communicationspost\" action=\"meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover=\"the governmenthref=\"https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->\n\ndepends on theUniversity of in contrast to placeholder=\"in the case ofinternational constitutionalstyle=\"border-: function() {Because of the-strict.dtd\">\n<table class=\"accompanied byaccount of the<script src=\"/nature of the the people in in addition tos); js.id = id\" width=\"100%\"regarding the Roman Catholican independentfollowing the .gif\" width=\"1the following discriminationarchaeologicalprime minister.js\"></script>combination of marginwidth=\"createElement(w.attachEvent(</a></td></tr>src=\"https://aIn particular, align=\"left\" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html\" title=\"(function () {comes from theapplication of<span class=\"sbelieved to beement('script'</a>\n</li>\n<livery different><span class=\"option value=\"(also known as\t<li><a href=\"><input name=\"separated fromreferred to as valign=\"top\">founder of theattempting to carbon dioxide\n\n<div class=\"class=\"search-/body>\n</html>opportunity tocommunications</head>\r\n<body style=\"width:Ti\u00E1\u00BA\u00BFng Vi\u00E1\u00BB\u0087tchanges in theborder-color:#0\" border=\"0\" </span></div><was discovered\" type=\"text\" );\n</script>\n\nDepartment of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>\n\n<div iwas consideredpercent of the\" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href='http://whether or notThere are alsothere are manya small numberother parts ofimpossible to class=\"buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=\" method=\"post\"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign=\"right\">many countriesfor many yearsearliest knownbecause it waspt\"></script>\r valign=\"top\" inhabitants offollowing year\r\n<div class=\"million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style=\"color:although therebest known forsubmit\" name=\"multiplicationmore than one recognition ofCouncil of theedition of the <meta name=\"Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class=\"descendants of<span class=\"i align=\"right\"</head>\n<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the\t<span class=\"is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class=\"<span class=\"t(Math.random()most prominentdescription ofConstantinoplewere published<div class=\"seappears in the1\" height=\"1\" most importantwhich includeswhich had beendestruction ofthe population\n\t<div class=\"possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle=\"clear:b\r\n</script>\r\n<was founded ininterview with_id\" content=\"capital of the\r\n<link rel=\"srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class=\"cperformance of(function() {\rif and only ifregions of theleading to therelations withUnited Nationsstyle=\"height:other than theype\" content=\"Association of\n</head>\n<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>\n<link rel=\" return false;the purpose ofthe ability to;color:#fff}\n.\n<span class=\"the subject ofdefinitions of>\r\n<link rel=\"claim that thehave developed<table width=\"celebration ofFollowing the to distinguish<span class=\"btakes place inunder the namenoted that the><![endif]-->\nstyle=\"margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id=\"was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>\r\n\r\nenvironmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made\" src=\"http://interpreted assecond half ofcrolling=\"no\" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class=\"footerand especiallytype=\"button\" </span></span>which included>\n<meta name=\"considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process <div class=\"the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class=\"ptext\" name=\"q\"\t\t<div class=\"the scientificrepresented bymathematicianselected by thethat have been><div class=\"cdiv id=\"headerin particular,converted into);\n</script>\n<philosophical srpskohrvatskiti\u00E1\u00BA\u00BFng Vi\u00E1\u00BB\u0087t\u00D0\u00A0\u00D1\u0083\u00D1\u0081\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D0\u00B9\u00D1\u0080\u00D1\u0083\u00D1\u0081\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D0\u00B9investigaci\u00C3\u00B3nparticipaci\u00C3\u00B3n\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D1\u008B\u00D0\u00B5\u00D0\u00BE\u00D0\u00B1\u00D0\u00BB\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D1\u008B\u00D0\u00B9\u00D1\u0087\u00D0\u00B5\u00D0\u00BB\u00D0\u00BE\u00D0\u00B2\u00D0\u00B5\u00D0\u00BA\u00D1\u0081\u00D0\u00B8\u00D1\u0081\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D1\u008B\u00D0\u009D\u00D0\u00BE\u00D0\u00B2\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D1\u008B\u00D1\u0085\u00D0\u00BE\u00D0\u00B1\u00D0\u00BB\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D0\u00B2\u00D1\u0080\u00D0\u00B5\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00B0\u00D1\u008F\u00D1\u0081\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D0\u00B4\u00D0\u00BD\u00D1\u008F\u00D1\u0081\u00D0\u00BA\u00D0\u00B0\u00D1\u0087\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00A3\u00D0\u00BA\u00D1\u0080\u00D0\u00B0\u00D0\u00B8\u00D0\u00BD\u00D1\u008B\u00D0\u00B2\u00D0\u00BE\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D1\u0081\u00D1\u008B\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B9\u00D1\u0081\u00D0\u00B4\u00D0\u00B5\u00D0\u00BB\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00BF\u00D0\u00BE\u00D0\u00BC\u00D0\u00BE\u00D1\u0089\u00D1\u008C\u00D1\u008E\u00D1\u0081\u00D1\u0080\u00D0\u00B5\u00D0\u00B4\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00BE\u00D0\u00B1\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00BE\u00D0\u00BC\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00BD\u00D1\u008B\u00D1\u0083\u00D1\u0087\u00D0\u00B0\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00B5\u00D1\u0082\u00D0\u00B5\u00D1\u0087\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D0\u00B5\u00D0\u0093\u00D0\u00BB\u00D0\u00B0\u00D0\u00B2\u00D0\u00BD\u00D0\u00B0\u00D1\u008F\u00D0\u00B8\u00D1\u0081\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00B8\u00D0\u00B8\u00D1\u0081\u00D0\u00B8\u00D1\u0081\u00D1\u0082\u00D0\u00B5\u00D0\u00BC\u00D0\u00B0\u00D1\u0080\u00D0\u00B5\u00D1\u0088\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00A1\u00D0\u00BA\u00D0\u00B0\u00D1\u0087\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D0\u00BF\u00D0\u00BE\u00D1\u008D\u00D1\u0082\u00D0\u00BE\u00D0\u00BC\u00D1\u0083\u00D1\u0081\u00D0\u00BB\u00D0\u00B5\u00D0\u00B4\u00D1\u0083\u00D0\u00B5\u00D1\u0082\u00D1\u0081\u00D0\u00BA\u00D0\u00B0\u00D0\u00B7\u00D0\u00B0\u00D1\u0082\u00D1\u008C\u00D1\u0082\u00D0\u00BE\u00D0\u00B2\u00D0\u00B0\u00D1\u0080\u00D0\u00BE\u00D0\u00B2\u00D0\u00BA\u00D0\u00BE\u00D0\u00BD\u00D0\u00B5\u00D1\u0087\u00D0\u00BD\u00D0\u00BE\u00D1\u0080\u00D0\u00B5\u00D1\u0088\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D0\u00B5\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B5\u00D0\u00BE\u00D1\u0080\u00D0\u00B3\u00D0\u00B0\u00D0\u00BD\u00D0\u00BE\u00D0\u00B2\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00BC\u00D0\u00A0\u00D0\u00B5\u00D0\u00BA\u00D0\u00BB\u00D0\u00B0\u00D0\u00BC\u00D0\u00B0\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00AF\u00D9\u0089\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00AF\u00D9\u008A\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0088\u00D8\u00B6\u00D9\u0088\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00A8\u00D8\u00B1\u00D8\u00A7\u00D9\u0085\u00D8\u00AC\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0088\u00D8\u00A7\u00D9\u0082\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00B3\u00D8\u00A7\u00D8\u00A6\u00D9\u0084\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00B9\u00D8\u00B6\u00D8\u00A7\u00D8\u00A1\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D9\u008A\u00D8\u00A7\u00D8\u00B6\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B5\u00D9\u0085\u00D9\u008A\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00B9\u00D8\u00B6\u00D8\u00A7\u00D8\u00A1\u00D8\u00A7\u00D9\u0084\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D8\u00A6\u00D8\u00AC\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B3\u00D8\u00AC\u00D9\u008A\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D9\u0082\u00D8\u00B3\u00D8\u00A7\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00B6\u00D8\u00BA\u00D8\u00B7\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0081\u00D9\u008A\u00D8\u00AF\u00D9\u008A\u00D9\u0088\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B1\u00D8\u00AD\u00D9\u008A\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D8\u00AF\u00D9\u008A\u00D8\u00AF\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B9\u00D9\u0084\u00D9\u008A\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00AE\u00D8\u00A8\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0081\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D9\u0081\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00A7\u00D8\u00B1\u00D9\u008A\u00D8\u00AE\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D9\u0082\u00D9\u0086\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D8\u00AE\u00D9\u0088\u00D8\u00A7\u00D8\u00B7\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00AC\u00D8\u00AA\u00D9\u0085\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00AF\u00D9\u008A\u00D9\u0083\u00D9\u0088\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D9\u008A\u00D8\u00A7\u00D8\u00AD\u00D8\u00A9\u00D8\u00B9\u00D8\u00A8\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D9\u0084\u00D9\u0087\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B1\u00D8\u00A8\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D9\u0088\u00D8\u00A7\u00D8\u00A8\u00D8\u00B7\u00D8\u00A7\u00D9\u0084\u00D8\u00A3\u00D8\u00AF\u00D8\u00A8\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00AE\u00D8\u00A8\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00AA\u00D8\u00AD\u00D8\u00AF\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00BA\u00D8\u00A7\u00D9\u0086\u00D9\u008Acursor:pointer;</title>\n<meta \" href=\"http://\"><span class=\"members of the window.locationvertical-align:/a> | <a href=\"<!doctype html>media=\"screen\" <option value=\"favicon.ico\" />\n\t\t<div class=\"characteristics\" method=\"get\" /body>\n</html>\nshortcut icon\" document.write(padding-bottom:representativessubmit\" value=\"align=\"center\" throughout the science fiction\n <div class=\"submit\" class=\"one of the most valign=\"top\"><was established);\r\n</script>\r\nreturn false;\">).style.displaybecause of the document.cookie<form action=\"/}body{margin:0;Encyclopedia ofversion of the .createElement(name\" content=\"</div>\n</div>\n\nadministrative </body>\n</html>history of the \"><input type=\"portion of the as part of the &nbsp;<a href=\"other countries\">\n<div class=\"</span></span><In other words,display: block;control of the introduction of/>\n<meta name=\"as well as the in recent years\r\n\t<div class=\"</div>\n\t</div>\ninspired by thethe end of the compatible withbecame known as style=\"margin:.js\"></script>< International there have beenGerman language style=\"color:#Communist Partyconsistent withborder=\"0\" cell marginheight=\"the majority of\" align=\"centerrelated to the many different Orthodox Churchsimilar to the />\n<link rel=\"swas one of the until his death})();\n</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling=\"no\" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign=\"center\">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style=\"width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>\n\t<div class=\"consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method=\"post\" was followed by&amp;mdash; thethe applicationjs\"></script>\r\nul></div></div>after the deathwith respect tostyle=\"padding:is particularlydisplay:inline; type=\"submit\" is divided into\u00E4\u00B8\u00AD\u00E6\u0096\u0087 (\u00E7\u00AE\u0080\u00E4\u00BD\u0093)responsabilidadadministraci\u00C3\u00B3ninternacionalescorrespondiente\u00E0\u00A4\u0089\u00E0\u00A4\u00AA\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A4\u00AA\u00E0\u00A5\u0082\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00B5\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A5\u0081\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B5\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A4\u00B8\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00AA\u00E0\u00A5\u0081\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u00B8\u00E0\u00A4\u0096\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00BF\u00E0\u00A4\u008F\u00E0\u00A4\u00AD\u00E0\u00A5\u0087\u00E0\u00A4\u009C\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00B6\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u0097\u00E0\u00A4\u00B0\u00E0\u00A4\u00A3\u00E0\u00A4\u00AC\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A5\u0081\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00AC\u00E0\u00A5\u008D\u00E0\u00A4\u00B2\u00E0\u00A5\u0089\u00E0\u00A4\u0097\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00AE\u00E0\u00A4\u00B9\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A5\u0083\u00E0\u00A4\u00B7\u00E0\u00A5\u008D\u00E0\u00A4\u00A0\u00E0\u00A4\u00AC\u00E0\u00A4\u00A2\u00E0\u00A4\u00BC\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u009F\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u0096\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u00AB\u00E0\u00A4\u00A6\u00E0\u00A5\u008C\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00AE\u00E0\u00A4\u00A4\u00E0\u00A4\u00A6\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00BE\u00E0\u00A4\u00B9\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u00AA\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u0081\u00E0\u00A4\u009A\u00E0\u00A4\u00AC\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00AA\u00E0\u00A4\u00BF\u00E0\u00A4\u009B\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00B6\u00E0\u00A5\u0087\u00E0\u00A4\u00B7\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u0089\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A4\u00B0\u00E0\u00A4\u00AE\u00E0\u00A5\u0081\u00E0\u00A4\u0082\u00E0\u00A4\u00AC\u00E0\u00A4\u0088\u00E0\u00A4\u00A6\u00E0\u00A5\u008B\u00E0\u00A4\u00A8\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u0089\u00E0\u00A4\u00AA\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A3\u00E0\u00A4\u00AA\u00E0\u00A4\u00A2\u00E0\u00A4\u00BC\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00AB\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A5\u008D\u00E0\u00A4\u00AE\u00E0\u00A4\u00AE\u00E0\u00A5\u0081\u00E0\u00A4\u0096\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u0085\u00E0\u00A4\u009A\u00E0\u00A5\u008D\u00E0\u00A4\u009B\u00E0\u00A4\u00BE\u00E0\u00A4\u009B\u00E0\u00A5\u0082\u00E0\u00A4\u009F\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A5\u0080\u00E0\u00A4\u00A4\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u008F\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u0097\u00E0\u00A4\u0098\u00E0\u00A4\u00A3\u00E0\u00A5\u008D\u00E0\u00A4\u009F\u00E0\u00A5\u0087\u00E0\u00A4\u00A6\u00E0\u00A5\u0082\u00E0\u00A4\u00B8\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00B9\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A5\u0087\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B8\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00A7\u00E0\u00A5\u0080\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00B6\u00E0\u00A5\u008D\u00E0\u00A4\u00B5\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A5\u0088\u00E0\u00A4\u009F\u00E0\u00A5\u008D\u00E0\u00A4\u00B8\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B6\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u0085\u00E0\u00A4\u00A6\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00A4\u00E0\u00A4\u00AC\u00E0\u00A4\u00BF\u00E0\u00A4\u009C\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00E0\u00A4\u00AA\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A5\u0082\u00E0\u00A4\u00B7\u00E0\u00A4\u00B9\u00E0\u00A4\u00BF\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A5\u0080\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0081\u00E0\u00A4\u00AA\u00E0\u00A4\u00AF\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A5\u008B\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A4\u00AE\u00E0\u00A5\u0081\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A5\u0083\u00E0\u00A4\u00AA\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A5\u008B\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u009F\u00E0\u00A4\u0098\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B2\u00E0\u00A5\u0082\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u009A\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00B8\u00E0\u00A5\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A5\u0082\u00E0\u00A4\u00B2\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u0096\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00B9\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u0095\u00E0\u00A5\u0082\u00E0\u00A4\u00B2\u00E0\u00A4\u00AE\u00E0\u00A5\u0088\u00E0\u00A4\u0082\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00A4\u00E0\u00A5\u0088\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u009C\u00E0\u00A4\u00BF\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u0087rss+xml\" title=\"-type\" content=\"title\" content=\"at the same time.js\"></script>\n<\" method=\"post\" </span></a></li>vertical-align:t/jquery.min.js\">.click(function( style=\"padding-})();\n</script>\n</span><a href=\"<a href=\"http://); return false;text-decoration: scrolling=\"no\" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif\" border=\"0\"</body>\n</html>\noverflow:hidden;img src=\"http://addEventListenerresponsible for s.js\"></script>\n/favicon.ico\" />operating system\" style=\"width:1target=\"_blank\">State Universitytext-align:left;\ndocument.write(, including the around the world);\r\n</script>\r\n<\" style=\"height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>\n\t\t</div>\ndisplay: none;\">\" />\n<link rel=\"\n (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the align=\"center\">University Pressdominated by theSecond World Wardistribution of style=\"position:the rest of the characterized by rel=\"nofollow\">derives from therather than the a combination ofstyle=\"width:100English-speakingcomputer scienceborder=\"0\" alt=\"the existence ofDemocratic Party\" style=\"margin-For this reason,.js\"></script>\n\tsByTagName(s)[0]js\"></script>\r\n<.js\"></script>\r\nlink rel=\"icon\" ' alt='' class='formation of theversions of the </a></div></div>/page>\n <page>\n<div class=\"contbecame the firstbahasa Indonesiaenglish (simple)\u00CE\u0095\u00CE\u00BB\u00CE\u00BB\u00CE\u00B7\u00CE\u00BD\u00CE\u00B9\u00CE\u00BA\u00CE\u00AC\u00D1\u0085\u00D1\u0080\u00D0\u00B2\u00D0\u00B0\u00D1\u0082\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D0\u00BA\u00D0\u00BE\u00D0\u00BC\u00D0\u00BF\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D0\u00B8\u00D1\u008F\u00D0\u00B2\u00D0\u00BB\u00D1\u008F\u00D0\u00B5\u00D1\u0082\u00D1\u0081\u00D1\u008F\u00D0\u0094\u00D0\u00BE\u00D0\u00B1\u00D0\u00B0\u00D0\u00B2\u00D0\u00B8\u00D1\u0082\u00D1\u008C\u00D1\u0087\u00D0\u00B5\u00D0\u00BB\u00D0\u00BE\u00D0\u00B2\u00D0\u00B5\u00D0\u00BA\u00D0\u00B0\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00B2\u00D0\u00B8\u00D1\u0082\u00D0\u00B8\u00D1\u008F\u00D0\u0098\u00D0\u00BD\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D0\u00BD\u00D0\u00B5\u00D1\u0082\u00D0\u009E\u00D1\u0082\u00D0\u00B2\u00D0\u00B5\u00D1\u0082\u00D0\u00B8\u00D1\u0082\u00D1\u008C\u00D0\u00BD\u00D0\u00B0\u00D0\u00BF\u00D1\u0080\u00D0\u00B8\u00D0\u00BC\u00D0\u00B5\u00D1\u0080\u00D0\u00B8\u00D0\u00BD\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D0\u00BD\u00D0\u00B5\u00D1\u0082\u00D0\u00BA\u00D0\u00BE\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00BE\u00D0\u00B3\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D1\u0086\u00D1\u008B\u00D0\u00BA\u00D0\u00B0\u00D1\u0087\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00B5\u00D1\u0083\u00D1\u0081\u00D0\u00BB\u00D0\u00BE\u00D0\u00B2\u00D0\u00B8\u00D1\u008F\u00D1\u0085\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B1\u00D0\u00BB\u00D0\u00B5\u00D0\u00BC\u00D1\u008B\u00D0\u00BF\u00D0\u00BE\u00D0\u00BB\u00D1\u0083\u00D1\u0087\u00D0\u00B8\u00D1\u0082\u00D1\u008C\u00D1\u008F\u00D0\u00B2\u00D0\u00BB\u00D1\u008F\u00D1\u008E\u00D1\u0082\u00D1\u0081\u00D1\u008F\u00D0\u00BD\u00D0\u00B0\u00D0\u00B8\u00D0\u00B1\u00D0\u00BE\u00D0\u00BB\u00D0\u00B5\u00D0\u00B5\u00D0\u00BA\u00D0\u00BE\u00D0\u00BC\u00D0\u00BF\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00B2\u00D0\u00BD\u00D0\u00B8\u00D0\u00BC\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D0\u00B5\u00D1\u0081\u00D1\u0080\u00D0\u00B5\u00D0\u00B4\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00B0\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0088\u00D8\u00A7\u00D8\u00B6\u00D9\u008A\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00A6\u00D9\u008A\u00D8\u00B3\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0086\u00D8\u00AA\u00D9\u0082\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D9\u0083\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D9\u008A\u00D8\u00A7\u00D8\u00B1\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0083\u00D8\u00AA\u00D9\u0088\u00D8\u00A8\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B3\u00D8\u00B9\u00D9\u0088\u00D8\u00AF\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D8\u00AD\u00D8\u00B5\u00D8\u00A7\u00D8\u00A6\u00D9\u008A\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00B9\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00B5\u00D9\u0088\u00D8\u00AA\u00D9\u008A\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0086\u00D8\u00AA\u00D8\u00B1\u00D9\u0086\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00AA\u00D8\u00B5\u00D8\u00A7\u00D9\u0085\u00D9\u008A\u00D9\u0085\u00D8\u00A7\u00D9\u0084\u00D8\u00A5\u00D8\u00B3\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D9\u008A\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B1\u00D8\u00A6\u00D9\u008A\u00D8\u00A7\u00D8\u00AArobots\" content=\"<div id=\"footer\">the United States<img src=\"http://.jpg|right|thumb|.js\"></script>\r\n<location.protocolframeborder=\"0\" s\" />\n<meta name=\"</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:\" rel=\"nofollow\" President of the twentieth centuryevision>\n </pageInternet Explorera.async = true;\r\ninformation about<div id=\"header\">\" action=\"http://<a href=\"https://<div id=\"content\"</div>\r\n</div>\r\n<derived from the <img src='http://according to the \n</body>\n</html>\nstyle=\"font-size:script language=\"Arial, Helvetica,</a><span class=\"</script><script political partiestd></tr></table><href=\"http://www.interpretation ofrel=\"stylesheet\" document.write('<charset=\"utf-8\">\nbeginning of the revealed that thetelevision series\" rel=\"nofollow\"> target=\"_blank\">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass=\"clearfix\">/div>\r\n</div>\r\n\r\nthree-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class=\"in some countriesmin.js\"></script>of the populationofficial language<img src=\"images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>\r\n</html>\r\u00CE\u0095\u00CE\u00BB\u00CE\u00BB\u00CE\u00B7\u00CE\u00BD\u00CE\u00B9\u00CE\u00BA\u00CE\u00AC\ntake advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class=\"headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype=\"text/css\">\nthe InternationalAccording to the pe=\"text/css\" />\ncoincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;\" target=\"_blank\" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type=\"application/anguage\" content=\"<meta http-equiv=\"Privacy Policy</a>e(\"%3Cscript src='\" target=\"_blank\">On the other hand,.jpg|thumb|right|2</div><div class=\"<div style=\"float:nineteenth century</body>\r\n</html>\r\n<img src=\"http://s;text-align:centerfont-weight: bold; According to the difference between\" frameborder=\"0\" \" style=\"position:link href=\"http://html4/loose.dtd\">\nduring this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type=\"text\" <span style=\"font-onreadystatechange\t<div class=\"cleardocument.location. For example, the a wide variety of <!DOCTYPE html>\r\n<&nbsp;&nbsp;&nbsp;\"><a href=\"http://style=\"float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype=\"text/css\" />it is possible to Harvard Universitytylesheet\" href=\"/the main characterOxford University name=\"keywords\" cstyle=\"text-align:the United Kingdomfederal government<div style=\"margin depending on the description of the<div class=\"header.min.js\"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc=\"http://staticsuggested that the\" src=\"http://www.a large number of Telecommunications\" rel=\"nofollow\" tHoly Roman Emperoralmost exclusively\" border=\"0\" alt=\"Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle=\"background-<li><em><a href=\"/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src=\"http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref=\"https://www.recent developmentBoard of Directors<div class=\"search| <a href=\"http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>\r\n</div>\r\n\r\n<a href=\"index.phpwas established inmin.js\"></script>\nparticipate in thea strong influencestyle=\"margin-top:represented by thegraduated from theTraditionally, theElement(\"script\");However, since the/div>\n</div>\n<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype=\"image/x-icon/div>\n<div class=\" class=\"clearfix\"><div class=\"footer\t\t</div>\n\t\t</div>\nthe motion picture\u00D0\u0091\u00D1\u008A\u00D0\u00BB\u00D0\u00B3\u00D0\u00B0\u00D1\u0080\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D0\u00B1\u00D1\u008A\u00D0\u00BB\u00D0\u00B3\u00D0\u00B0\u00D1\u0080\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\u00D0\u00A4\u00D0\u00B5\u00D0\u00B4\u00D0\u00B5\u00D1\u0080\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D0\u00B8\u00D0\u00BD\u00D0\u00B5\u00D1\u0081\u00D0\u00BA\u00D0\u00BE\u00D0\u00BB\u00D1\u008C\u00D0\u00BA\u00D0\u00BE\u00D1\u0081\u00D0\u00BE\u00D0\u00BE\u00D0\u00B1\u00D1\u0089\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D0\u00B5\u00D1\u0081\u00D0\u00BE\u00D0\u00BE\u00D0\u00B1\u00D1\u0089\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B3\u00D1\u0080\u00D0\u00B0\u00D0\u00BC\u00D0\u00BC\u00D1\u008B\u00D0\u009E\u00D1\u0082\u00D0\u00BF\u00D1\u0080\u00D0\u00B0\u00D0\u00B2\u00D0\u00B8\u00D1\u0082\u00D1\u008C\u00D0\u00B1\u00D0\u00B5\u00D1\u0081\u00D0\u00BF\u00D0\u00BB\u00D0\u00B0\u00D1\u0082\u00D0\u00BD\u00D0\u00BE\u00D0\u00BC\u00D0\u00B0\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D0\u00B8\u00D0\u00B0\u00D0\u00BB\u00D1\u008B\u00D0\u00BF\u00D0\u00BE\u00D0\u00B7\u00D0\u00B2\u00D0\u00BE\u00D0\u00BB\u00D1\u008F\u00D0\u00B5\u00D1\u0082\u00D0\u00BF\u00D0\u00BE\u00D1\u0081\u00D0\u00BB\u00D0\u00B5\u00D0\u00B4\u00D0\u00BD\u00D0\u00B8\u00D0\u00B5\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00BB\u00D0\u00B8\u00D1\u0087\u00D0\u00BD\u00D1\u008B\u00D1\u0085\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B4\u00D1\u0083\u00D0\u00BA\u00D1\u0086\u00D0\u00B8\u00D0\u00B8\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B3\u00D1\u0080\u00D0\u00B0\u00D0\u00BC\u00D0\u00BC\u00D0\u00B0\u00D0\u00BF\u00D0\u00BE\u00D0\u00BB\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D1\u008E\u00D0\u00BD\u00D0\u00B0\u00D1\u0085\u00D0\u00BE\u00D0\u00B4\u00D0\u00B8\u00D1\u0082\u00D1\u0081\u00D1\u008F\u00D0\u00B8\u00D0\u00B7\u00D0\u00B1\u00D1\u0080\u00D0\u00B0\u00D0\u00BD\u00D0\u00BD\u00D0\u00BE\u00D0\u00B5\u00D0\u00BD\u00D0\u00B0\u00D1\u0081\u00D0\u00B5\u00D0\u00BB\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00B8\u00D0\u00B7\u00D0\u00BC\u00D0\u00B5\u00D0\u00BD\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00BA\u00D0\u00B0\u00D1\u0082\u00D0\u00B5\u00D0\u00B3\u00D0\u00BE\u00D1\u0080\u00D0\u00B8\u00D0\u00B8\u00D0\u0090\u00D0\u00BB\u00D0\u00B5\u00D0\u00BA\u00D1\u0081\u00D0\u00B0\u00D0\u00BD\u00D0\u00B4\u00D1\u0080\u00E0\u00A4\u00A6\u00E0\u00A5\u008D\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A5\u0088\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u0085\u00E0\u00A4\u00B2\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00A6\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u00AF\u00E0\u00A4\u0085\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00B9\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A5\u008D\u00E0\u00A4\u00A6\u00E0\u00A5\u0080\u00E0\u00A4\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00A1\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u00BF\u00E0\u00A4\u00B2\u00E0\u00A5\u008D\u00E0\u00A4\u00B2\u00E0\u00A5\u0080\u00E0\u00A4\u0085\u00E0\u00A4\u00A7\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00B5\u00E0\u00A5\u0080\u00E0\u00A4\u00A1\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u009A\u00E0\u00A4\u00BF\u00E0\u00A4\u009F\u00E0\u00A5\u008D\u00E0\u00A4\u00A0\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u009A\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u009C\u00E0\u00A4\u0082\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B6\u00E0\u00A4\u00A8\u00E0\u00A4\u00A6\u00E0\u00A5\u0081\u00E0\u00A4\u00A8\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u0097\u00E0\u00A4\u0085\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u0091\u00E0\u00A4\u00A8\u00E0\u00A4\u00B2\u00E0\u00A4\u00BE\u00E0\u00A4\u0087\u00E0\u00A4\u00A8\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u009F\u00E0\u00A5\u0080\u00E0\u00A4\u00B6\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00B2\u00E0\u00A5\u008B\u00E0\u00A4\u0095\u00E0\u00A4\u00B8\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u00AB\u00E0\u00A4\u00BC\u00E0\u00A5\u008D\u00E0\u00A4\u00B2\u00E0\u00A5\u0088\u00E0\u00A4\u00B6\u00E0\u00A4\u00B6\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B2\u00E0\u00A5\u0087\u00E0\u00A4\u00AF\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u00A6\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00BF\u00E0\u00A4\u0089\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00AA\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A5\u008D\u00E0\u00A4\u00B9\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u009A\u00E0\u00A4\u00BF\u00E0\u00A4\u009F\u00E0\u00A5\u008D\u00E0\u00A4\u00A0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u009C\u00E0\u00A5\u008B\u00E0\u00A4\u00A1\u00E0\u00A4\u00BC\u00E0\u00A5\u0087\u00E0\u00A4\u0082\u00E0\u00A4\u0085\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00A6\u00E0\u00A4\u00B6\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00A3\u00E0\u00A5\u0080\u00E0\u00A4\u00B6\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B7\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00B9\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A4\u00BF\u00E0\u00A4\u00A3\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u00AC\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u00A1\u00E0\u00A4\u00AC\u00E0\u00A4\u009A\u00E0\u00A5\u008D\u00E0\u00A4\u009A\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u0089\u00E0\u00A4\u00AA\u00E0\u00A4\u00B2\u00E0\u00A4\u00AC\u00E0\u00A5\u008D\u00E0\u00A4\u00A7\u00E0\u00A4\u00AE\u00E0\u00A4\u0082\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u0095\u00E0\u00A4\u0089\u00E0\u00A4\u00AE\u00E0\u00A5\u008D\u00E0\u00A4\u00AE\u00E0\u00A5\u0080\u00E0\u00A4\u00A6\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00A7\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00AE\u00E0\u00A4\u00B8\u00E0\u00A4\u00B9\u00E0\u00A4\u00BE\u00E0\u00A4\u00AF\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00B6\u00E0\u00A4\u00AC\u00E0\u00A5\u008D\u00E0\u00A4\u00A6\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00AE\u00E0\u00A5\u0080\u00E0\u00A4\u00A1\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0086\u00E0\u00A4\u0088\u00E0\u00A4\u00AA\u00E0\u00A5\u0080\u00E0\u00A4\u008F\u00E0\u00A4\u00B2\u00E0\u00A4\u00AE\u00E0\u00A5\u008B\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u0087\u00E0\u00A4\u00B2\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u0096\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0086\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00A8\u00E0\u00A4\u0085\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u00AC\u00E0\u00A4\u0082\u00E0\u00A4\u00A7\u00E0\u00A4\u00AC\u00E0\u00A4\u00BE\u00E0\u00A4\u009C\u00E0\u00A4\u00BC\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A4\u00B5\u00E0\u00A5\u0080\u00E0\u00A4\u00A8\u00E0\u00A4\u00A4\u00E0\u00A4\u00AE\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00AE\u00E0\u00A5\u0081\u00E0\u00A4\u0096\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00B6\u00E0\u00A5\u008D\u00E0\u00A4\u00A8\u00E0\u00A4\u00AA\u00E0\u00A4\u00B0\u00E0\u00A4\u00BF\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A5\u0081\u00E0\u00A4\u0095\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00B8\u00E0\u00A4\u00AE\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00A8\u00E0\u00A4\u0086\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u009C\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00B8\u00E0\u00A5\u008B\u00E0\u00A4\u00AE\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D8\u00B1\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D9\u0086\u00D8\u00AA\u00D8\u00AF\u00D9\u008A\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0083\u00D9\u0085\u00D8\u00A8\u00D9\u008A\u00D9\u0088\u00D8\u00AA\u00D8\u00B1\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B4\u00D8\u00A7\u00D9\u0087\u00D8\u00AF\u00D8\u00A7\u00D8\u00AA\u00D8\u00B9\u00D8\u00AF\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00B2\u00D9\u0088\u00D8\u00A7\u00D8\u00B1\u00D8\u00B9\u00D8\u00AF\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00B1\u00D8\u00AF\u00D9\u0088\u00D8\u00AF\u00D8\u00A7\u00D9\u0084\u00D8\u00A5\u00D8\u00B3\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D9\u0081\u00D9\u0088\u00D8\u00AA\u00D9\u0088\u00D8\u00B4\u00D9\u0088\u00D8\u00A8\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B3\u00D8\u00A7\u00D8\u00A8\u00D9\u0082\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B9\u00D9\u0084\u00D9\u0088\u00D9\u0085\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00B3\u00D9\u0084\u00D8\u00B3\u00D9\u0084\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00AC\u00D8\u00B1\u00D8\u00A7\u00D9\u0081\u00D9\u008A\u00D9\u0083\u00D8\u00B3\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00B3\u00D9\u0084\u00D8\u00A7\u00D9\u0085\u00D9\u008A\u00D8\u00A9\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00AA\u00D8\u00B5\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00AAkeywords\" content=\"w3.org/1999/xhtml\"><a target=\"_blank\" text/html; charset=\" target=\"_blank\"><table cellpadding=\"autocomplete=\"off\" text-align: center;to last version by background-color: #\" href=\"http://www./div></div><div id=<a href=\"#\" class=\"\"><img src=\"http://cript\" src=\"http://\n<script language=\"//EN\" \"http://www.wencodeURIComponent(\" href=\"javascript:<div class=\"contentdocument.write('<scposition: absolute;script src=\"http:// style=\"margin-top:.min.js\"></script>\n</div>\n<div class=\"w3.org/1999/xhtml\" \n\r\n</body>\r\n</html>distinction between/\" target=\"_blank\"><link href=\"http://encoding=\"utf-8\"?>\nw.addEventListener?action=\"http://www.icon\" href=\"http:// style=\"background:type=\"text/css\" />\nmeta property=\"og:t<input type=\"text\" style=\"text-align:the development of tylesheet\" type=\"tehtml; charset=utf-8is considered to betable width=\"100%\" In addition to the contributed to the differences betweendevelopment of the It is important to </script>\n\n<script style=\"font-size:1></span><span id=gbLibrary of Congress<img src=\"http://imEnglish translationAcademy of Sciencesdiv style=\"display:construction of the.getElementById(id)in conjunction withElement('script'); <meta property=\"og:\u00D0\u0091\u00D1\u008A\u00D0\u00BB\u00D0\u00B3\u00D0\u00B0\u00D1\u0080\u00D1\u0081\u00D0\u00BA\u00D0\u00B8\n type=\"text\" name=\">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src=\"http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style=\"background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet\" href=\"/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland\n</script>\n<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv=\"X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0\" cellpadding=\"0\" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E\"));<a href=\"http://www.<li><a href=\"http://site_name\" content=\"text-decoration:nonestyle=\"display: none<meta http-equiv=\"X-new Date().getTime() type=\"image/x-icon\"</span><span class=\"language=\"javascriptwindow.location.href<a href=\"javascript:-->\r\n<script type=\"t<a href='http://www.hortcut icon\" href=\"</div>\r\n<div class=\"<script src=\"http://\" rel=\"stylesheet\" t</div>\n<script type=/a> <a href=\"http:// allowTransparency=\"X-UA-Compatible\" conrelationship between\n</script>\r\n<script </a></li></ul></div>associated with the programming language</a><a href=\"http://</a></li><li class=\"form action=\"http://<div style=\"display:type=\"text\" name=\"q\"<table width=\"100%\" background-position:\" border=\"0\" width=\"rel=\"shortcut icon\" h6><ul><li><a href=\" <meta http-equiv=\"css\" media=\"screen\" responsible for the \" type=\"application/\" style=\"background-html; charset=utf-8\" allowtransparency=\"stylesheet\" type=\"te\r\n<meta http-equiv=\"></span><span class=\"0\" cellspacing=\"0\">;\n</script>\n<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type=\"hidden\" name=\"javascript:void(0);\"effectiveness of the autocomplete=\"off\" generally considered><input type=\"text\" \"></script>\r\n<scriptthroughout the worldcommon misconceptionassociation with the</div>\n</div>\n<div cduring his lifetime,corresponding to thetype=\"image/x-icon\" an increasing numberdiplomatic relationsare often consideredmeta charset=\"utf-8\" <input type=\"text\" examples include the\"><img src=\"http://iparticipation in thethe establishment of\n</div>\n<div class=\"&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset=\"utf-8\"> type=\"text/css\" />\ninterchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type=\"text/csstype=\"submit\" name=\"families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportugu\u00C3\u00AAs (Europeu)\u00D0\u00A3\u00D0\u00BA\u00D1\u0080\u00D0\u00B0\u00D1\u0097\u00D0\u00BD\u00D1\u0081\u00D1\u008C\u00D0\u00BA\u00D0\u00B0\u00D1\u0083\u00D0\u00BA\u00D1\u0080\u00D0\u00B0\u00D1\u0097\u00D0\u00BD\u00D1\u0081\u00D1\u008C\u00D0\u00BA\u00D0\u00B0\u00D0\u00A0\u00D0\u00BE\u00D1\u0081\u00D1\u0081\u00D0\u00B8\u00D0\u00B9\u00D1\u0081\u00D0\u00BA\u00D0\u00BE\u00D0\u00B9\u00D0\u00BC\u00D0\u00B0\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D0\u00B8\u00D0\u00B0\u00D0\u00BB\u00D0\u00BE\u00D0\u00B2\u00D0\u00B8\u00D0\u00BD\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D0\u00BC\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D0\u00B8\u00D1\u0083\u00D0\u00BF\u00D1\u0080\u00D0\u00B0\u00D0\u00B2\u00D0\u00BB\u00D0\u00B5\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D0\u00BD\u00D0\u00B5\u00D0\u00BE\u00D0\u00B1\u00D1\u0085\u00D0\u00BE\u00D0\u00B4\u00D0\u00B8\u00D0\u00BC\u00D0\u00BE\u00D0\u00B8\u00D0\u00BD\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D0\u00BC\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D1\u008F\u00D0\u0098\u00D0\u00BD\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D0\u00BC\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D1\u008F\u00D0\u00A0\u00D0\u00B5\u00D1\u0081\u00D0\u00BF\u00D1\u0083\u00D0\u00B1\u00D0\u00BB\u00D0\u00B8\u00D0\u00BA\u00D0\u00B8\u00D0\u00BA\u00D0\u00BE\u00D0\u00BB\u00D0\u00B8\u00D1\u0087\u00D0\u00B5\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00BE\u00D0\u00B8\u00D0\u00BD\u00D1\u0084\u00D0\u00BE\u00D1\u0080\u00D0\u00BC\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D1\u008E\u00D1\u0082\u00D0\u00B5\u00D1\u0080\u00D1\u0080\u00D0\u00B8\u00D1\u0082\u00D0\u00BE\u00D1\u0080\u00D0\u00B8\u00D0\u00B8\u00D0\u00B4\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B0\u00D1\u0082\u00D0\u00BE\u00D1\u0087\u00D0\u00BD\u00D0\u00BE\u00D8\u00A7\u00D9\u0084\u00D9\u0085\u00D8\u00AA\u00D9\u0088\u00D8\u00A7\u00D8\u00AC\u00D8\u00AF\u00D9\u0088\u00D9\u0086\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D8\u00B4\u00D8\u00AA\u00D8\u00B1\u00D8\u00A7\u00D9\u0083\u00D8\u00A7\u00D8\u00AA\u00D8\u00A7\u00D9\u0084\u00D8\u00A7\u00D9\u0082\u00D8\u00AA\u00D8\u00B1\u00D8\u00A7\u00D8\u00AD\u00D8\u00A7\u00D8\u00AAhtml; charset=UTF-8\" setTimeout(function()display:inline-block;<input type=\"submit\" type = 'text/javascri<img src=\"http://www.\" \"http://www.w3.org/shortcut icon\" href=\"\" autocomplete=\"off\" </a></div><div class=</a></li>\n<li class=\"css\" type=\"text/css\" <form action=\"http://xt/css\" href=\"http://link rel=\"alternate\" \r\n<script type=\"text/ onclick=\"javascript:(new Date).getTime()}height=\"1\" width=\"1\" People's Republic of <a href=\"http://www.text-decoration:underthe beginning of the </div>\n</div>\n</div>\nestablishment of the </div></div></div></d#viewport{min-height:\n<script src=\"http://option><option value=often referred to as /option>\n<option valu<!DOCTYPE html>\n<!--[International Airport>\n<a href=\"http://www</a><a href=\"http://w\u00E0\u00B8\u00A0\u00E0\u00B8\u00B2\u00E0\u00B8\u00A9\u00E0\u00B8\u00B2\u00E0\u00B9\u0084\u00E0\u00B8\u0097\u00E0\u00B8\u00A2\u00E1\u0083\u00A5\u00E1\u0083\u0090\u00E1\u0083\u00A0\u00E1\u0083\u0097\u00E1\u0083\u00A3\u00E1\u0083\u009A\u00E1\u0083\u0098\u00E6\u00AD\u00A3\u00E9\u00AB\u0094\u00E4\u00B8\u00AD\u00E6\u0096\u0087 (\u00E7\u00B9\u0081\u00E9\u00AB\u0094)\u00E0\u00A4\u00A8\u00E0\u00A4\u00BF\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00A6\u00E0\u00A5\u0087\u00E0\u00A4\u00B6\u00E0\u00A4\u00A1\u00E0\u00A4\u00BE\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A4\u00B2\u00E0\u00A5\u008B\u00E0\u00A4\u00A1\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B7\u00E0\u00A5\u0087\u00E0\u00A4\u00A4\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u009C\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u00AC\u00E0\u00A4\u0082\u00E0\u00A4\u00A7\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A5\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A4\u00BE\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00B5\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00B8\u00E0\u00A4\u0082\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u0095\u00E0\u00A4\u00B0\u00E0\u00A4\u00A3\u00E0\u00A4\u00B8\u00E0\u00A4\u00BE\u00E0\u00A4\u00AE\u00E0\u00A4\u0097\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0080\u00E0\u00A4\u009A\u00E0\u00A4\u00BF\u00E0\u00A4\u009F\u00E0\u00A5\u008D\u00E0\u00A4\u00A0\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u009C\u00E0\u00A5\u008D\u00E0\u00A4\u009E\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u0085\u00E0\u00A4\u00AE\u00E0\u00A5\u0087\u00E0\u00A4\u00B0\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00AD\u00E0\u00A4\u00BF\u00E0\u00A4\u00A8\u00E0\u00A5\u008D\u00E0\u00A4\u00A8\u00E0\u00A4\u0097\u00E0\u00A4\u00BE\u00E0\u00A4\u00A1\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00BE\u00E0\u00A4\u0081\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00AF\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u0095\u00E0\u00A4\u00BF\u00E0\u00A4\u00B8\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B7\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00B9\u00E0\u00A5\u0081\u00E0\u00A4\u0081\u00E0\u00A4\u009A\u00E0\u00A4\u00A4\u00E0\u00A5\u0080\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00AC\u00E0\u00A4\u0082\u00E0\u00A4\u00A7\u00E0\u00A4\u00A8\u00E0\u00A4\u009F\u00E0\u00A4\u00BF\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00AA\u00E0\u00A4\u00A3\u00E0\u00A5\u0080\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A5\u0087\u00E0\u00A4\u009F\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u0082\u00E0\u00A4\u00AD\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00B0\u00E0\u00A4\u00AB\u00E0\u00A4\u00BC\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A4\u00A8\u00E0\u00A4\u00BF\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00AE\u00E0\u00A4\u00BE\u00E0\u00A4\u00A3\u00E0\u00A4\u00B2\u00E0\u00A4\u00BF\u00E0\u00A4\u00AE\u00E0\u00A4\u00BF\u00E0\u00A4\u009F\u00E0\u00A5\u0087\u00E0\u00A4\u00A1description\" content=\"document.location.prot.getElementsByTagName(<!DOCTYPE html>\n<html <meta charset=\"utf-8\">:url\" content=\"http://.css\" rel=\"stylesheet\"style type=\"text/css\">type=\"text/css\" href=\"w3.org/1999/xhtml\" xmltype=\"text/javascript\" method=\"get\" action=\"link rel=\"stylesheet\" = document.getElementtype=\"image/x-icon\" />cellpadding=\"0\" cellsp.css\" type=\"text/css\" </a></li><li><a href=\"\" width=\"1\" height=\"1\"\"><a href=\"http://www.style=\"display:none;\">alternate\" type=\"appli-//W3C//DTD XHTML 1.0 ellspacing=\"0\" cellpad type=\"hidden\" value=\"/a>&nbsp;<span role=\"s\n<input type=\"hidden\" language=\"JavaScript\" document.getElementsBg=\"0\" cellspacing=\"0\" ype=\"text/css\" media=\"type='text/javascript'with the exception of ype=\"text/css\" rel=\"st height=\"1\" width=\"1\" ='+encodeURIComponent(<link rel=\"alternate\" \nbody, tr, input, textmeta name=\"robots\" conmethod=\"post\" action=\">\n<a href=\"http://www.css\" rel=\"stylesheet\" </div></div><div classlanguage=\"javascript\">aria-hidden=\"true\">\u00C2\u00B7<ript\" type=\"text/javasl=0;})();\n(function(){background-image: url(/a></li><li><a href=\"h\t\t<li><a href=\"http://ator\" aria-hidden=\"tru> <a href=\"http://www.language=\"javascript\" /option>\n<option value/div></div><div class=rator\" aria-hidden=\"tre=(new Date).getTime()portugu\u00C3\u00AAs (do Brasil)\u00D0\u00BE\u00D1\u0080\u00D0\u00B3\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D0\u00B7\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D0\u00B8\u00D0\u00B2\u00D0\u00BE\u00D0\u00B7\u00D0\u00BC\u00D0\u00BE\u00D0\u00B6\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D1\u008C\u00D0\u00BE\u00D0\u00B1\u00D1\u0080\u00D0\u00B0\u00D0\u00B7\u00D0\u00BE\u00D0\u00B2\u00D0\u00B0\u00D0\u00BD\u00D0\u00B8\u00D1\u008F\u00D1\u0080\u00D0\u00B5\u00D0\u00B3\u00D0\u00B8\u00D1\u0081\u00D1\u0082\u00D1\u0080\u00D0\u00B0\u00D1\u0086\u00D0\u00B8\u00D0\u00B8\u00D0\u00B2\u00D0\u00BE\u00D0\u00B7\u00D0\u00BC\u00D0\u00BE\u00D0\u00B6\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D0\u00BE\u00D0\u00B1\u00D1\u008F\u00D0\u00B7\u00D0\u00B0\u00D1\u0082\u00D0\u00B5\u00D0\u00BB\u00D1\u008C\u00D0\u00BD\u00D0\u00B0<!DOCTYPE html PUBLIC \"nt-Type\" content=\"text/<meta http-equiv=\"Conteransitional//EN\" \"http:<html xmlns=\"http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = 'text/javascript';<meta name=\"descriptionparentNode.insertBefore<input type=\"hidden\" najs\" type=\"text/javascri(document).ready(functiscript type=\"text/javasimage\" content=\"http://UA-Compatible\" content=tml; charset=utf-8\" />\nlink rel=\"shortcut icon<link rel=\"stylesheet\" </script>\n<script type== document.createElemen<a target=\"_blank\" href= document.getElementsBinput type=\"text\" name=a.type = 'text/javascrinput type=\"hidden\" namehtml; charset=utf-8\" />dtd\">\n<html xmlns=\"http-//W3C//DTD HTML 4.01 TentsByTagName('script')input type=\"hidden\" nam<script type=\"text/javas\" style=\"display:none;\">document.getElementById(=document.createElement(' type='text/javascript'input type=\"text\" name=\"d.getElementsByTagName(snical\" href=\"http://www.C//DTD HTML 4.01 Transit<style type=\"text/css\">\n\n<style type=\"text/css\">ional.dtd\">\n<html xmlns=http-equiv=\"Content-Typeding=\"0\" cellspacing=\"0\"html; charset=utf-8\" />\n style=\"display:none;\"><<li><a href=\"http://www. type='text/javascript'>\u00D0\u00B4\u00D0\u00B5\u00D1\u008F\u00D1\u0082\u00D0\u00B5\u00D0\u00BB\u00D1\u008C\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00D1\u0081\u00D0\u00BE\u00D0\u00BE\u00D1\u0082\u00D0\u00B2\u00D0\u00B5\u00D1\u0082\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00B8\u00D0\u00B8\u00D0\u00BF\u00D1\u0080\u00D0\u00BE\u00D0\u00B8\u00D0\u00B7\u00D0\u00B2\u00D0\u00BE\u00D0\u00B4\u00D1\u0081\u00D1\u0082\u00D0\u00B2\u00D0\u00B0\u00D0\u00B1\u00D0\u00B5\u00D0\u00B7\u00D0\u00BE\u00D0\u00BF\u00D0\u00B0\u00D1\u0081\u00D0\u00BD\u00D0\u00BE\u00D1\u0081\u00D1\u0082\u00D0\u00B8\u00E0\u00A4\u00AA\u00E0\u00A5\u0081\u00E0\u00A4\u00B8\u00E0\u00A5\u008D\u00E0\u00A4\u00A4\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A5\u0087\u00E0\u00A4\u00B8\u00E0\u00A4\u0089\u00E0\u00A4\u00A8\u00E0\u00A5\u008D\u00E0\u00A4\u00B9\u00E0\u00A5\u008B\u00E0\u00A4\u0082\u00E0\u00A4\u00A8\u00E0\u00A5\u0087\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u00A7\u00E0\u00A4\u00BE\u00E0\u00A4\u00A8\u00E0\u00A4\u00B8\u00E0\u00A4\u00AD\u00E0\u00A4\u00BE\u00E0\u00A4\u00AB\u00E0\u00A4\u00BF\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B8\u00E0\u00A4\u00BF\u00E0\u00A4\u0082\u00E0\u00A4\u0097\u00E0\u00A4\u00B8\u00E0\u00A5\u0081\u00E0\u00A4\u00B0\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B7\u00E0\u00A4\u00BF\u00E0\u00A4\u00A4\u00E0\u00A4\u0095\u00E0\u00A5\u0089\u00E0\u00A4\u00AA\u00E0\u00A5\u0080\u00E0\u00A4\u00B0\u00E0\u00A4\u00BE\u00E0\u00A4\u0087\u00E0\u00A4\u009F\u00E0\u00A4\u00B5\u00E0\u00A4\u00BF\u00E0\u00A4\u009C\u00E0\u00A5\u008D\u00E0\u00A4\u009E\u00E0\u00A4\u00BE\u00E0\u00A4\u00AA\u00E0\u00A4\u00A8\u00E0\u00A4\u0095\u00E0\u00A4\u00BE\u00E0\u00A4\u00B0\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00B5\u00E0\u00A4\u00BE\u00E0\u00A4\u0088\u00E0\u00A4\u00B8\u00E0\u00A4\u0095\u00E0\u00A5\u008D\u00E0\u00A4\u00B0\u00E0\u00A4\u00BF\u00E0\u00A4\u00AF\u00E0\u00A4\u00A4\u00E0\u00A4\u00BE";
+ }
+ }
+
+ private class DataHolder
+ {
+ internal static readonly byte[] Data;
+
+ static DataHolder()
+ {
+ Data = new byte[122784];
+ string[] chunks = new string[] { Org.Brotli.Dec.Dictionary.DataHolder0.GetData(), Org.Brotli.Dec.Dictionary.DataHolder1.GetData(), Org.Brotli.Dec.Dictionary.DataHolder2.GetData() };
+ int sum = 0;
+ foreach (string chunk in chunks)
+ {
+ sum += chunk.Length;
+ }
+ if (sum != Data.Length)
+ {
+ throw new System.Exception("Corrupted brotli dictionary");
+ }
+ sum = 0;
+ foreach (string chunk in chunks)
+ {
+ for (int j = 0; j < chunk.Length; ++j)
+ {
+ Data[sum++] = unchecked((byte)chunk[j]);
+ }
+ }
+ }
+ }
+
+ internal static byte[] GetData()
+ {
+ return Org.Brotli.Dec.Dictionary.DataHolder.Data;
+ }
+
+ internal static readonly int[] OffsetsByLength = new int[] { 0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, 122016 };
+
+ internal static readonly int[] SizeBitsByLength = new int[] { 0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, 7, 6, 6, 5, 5 };
+
+ internal const int MinWordLength = 4;
+
+ internal const int MaxWordLength = 24;
+
+ internal const int MaxTransformedWordLength = 5 + MaxWordLength + 8;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DictionaryTest.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DictionaryTest.cs
new file mode 100644
index 000000000..84c35ab77
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/DictionaryTest.cs
@@ -0,0 +1,36 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// Tests for
+ /// <see cref="Dictionary"/>
+ /// .
+ /// </summary>
+ public class DictionaryTest
+ {
+ private static long Crc64(byte[] data)
+ {
+ long crc = -1;
+ for (int i = 0; i < data.Length; ++i)
+ {
+ long c = (crc ^ (long)(data[i] & unchecked((int)(0xFF)))) & unchecked((int)(0xFF));
+ for (int k = 0; k < 8; k++)
+ {
+ c = ((long)(((ulong)c) >> 1)) ^ (-(c & 1L) & -3932672073523589310L);
+ }
+ crc = c ^ ((long)(((ulong)crc) >> 8));
+ }
+ return ~crc;
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestGetData()
+ {
+ NUnit.Framework.Assert.AreEqual(37084801881332636L, Crc64(Org.Brotli.Dec.Dictionary.GetData()));
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Huffman.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Huffman.cs
new file mode 100644
index 000000000..4f10c7152
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Huffman.cs
@@ -0,0 +1,149 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Utilities for building Huffman decoding tables.</summary>
+ internal sealed class Huffman
+ {
+ /// <summary>
+ /// Maximum possible Huffman table size for an alphabet size of 704, max code length 15 and root
+ /// table bits 8.
+ /// </summary>
+ internal const int HuffmanMaxTableSize = 1080;
+
+ private const int MaxLength = 15;
+
+ /// <summary>Returns reverse(reverse(key, len) + 1, len).</summary>
+ /// <remarks>
+ /// Returns reverse(reverse(key, len) + 1, len).
+ /// <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
+ /// </remarks>
+ private static int GetNextKey(int key, int len)
+ {
+ int step = 1 << (len - 1);
+ while ((key & step) != 0)
+ {
+ step >>= 1;
+ }
+ return (key & (step - 1)) + step;
+ }
+
+ /// <summary>
+ /// Stores
+ /// <paramref name="item"/>
+ /// in
+ /// <c>table[0], table[step], table[2 * step] .., table[end]</c>
+ /// .
+ /// <p> Assumes that end is an integer multiple of step.
+ /// </summary>
+ private static void ReplicateValue(int[] table, int offset, int step, int end, int item)
+ {
+ do
+ {
+ end -= step;
+ table[offset + end] = item;
+ }
+ while (end > 0);
+ }
+
+ /// <param name="count">histogram of bit lengths for the remaining symbols,</param>
+ /// <param name="len">code length of the next processed symbol.</param>
+ /// <returns>table width of the next 2nd level table.</returns>
+ private static int NextTableBitSize(int[] count, int len, int rootBits)
+ {
+ int left = 1 << (len - rootBits);
+ while (len < MaxLength)
+ {
+ left -= count[len];
+ if (left <= 0)
+ {
+ break;
+ }
+ len++;
+ left <<= 1;
+ }
+ return len - rootBits;
+ }
+
+ /// <summary>Builds Huffman lookup table assuming code lengths are in symbol order.</summary>
+ internal static void BuildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths, int codeLengthsSize)
+ {
+ int key;
+ // Reversed prefix code.
+ int[] sorted = new int[codeLengthsSize];
+ // Symbols sorted by code length.
+ // TODO: fill with zeroes?
+ int[] count = new int[MaxLength + 1];
+ // Number of codes of each length.
+ int[] offset = new int[MaxLength + 1];
+ // Offsets in sorted table for each length.
+ int symbol;
+ // Build histogram of code lengths.
+ for (symbol = 0; symbol < codeLengthsSize; symbol++)
+ {
+ count[codeLengths[symbol]]++;
+ }
+ // Generate offsets into sorted symbol table by code length.
+ offset[1] = 0;
+ for (int len = 1; len < MaxLength; len++)
+ {
+ offset[len + 1] = offset[len] + count[len];
+ }
+ // Sort symbols by length, by symbol order within each length.
+ for (symbol = 0; symbol < codeLengthsSize; symbol++)
+ {
+ if (codeLengths[symbol] != 0)
+ {
+ sorted[offset[codeLengths[symbol]]++] = symbol;
+ }
+ }
+ int tableBits = rootBits;
+ int tableSize = 1 << tableBits;
+ int totalSize = tableSize;
+ // Special case code with only one value.
+ if (offset[MaxLength] == 1)
+ {
+ for (key = 0; key < totalSize; key++)
+ {
+ rootTable[tableOffset + key] = sorted[0];
+ }
+ return;
+ }
+ // Fill in root table.
+ key = 0;
+ symbol = 0;
+ for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1)
+ {
+ for (; count[len] > 0; count[len]--)
+ {
+ ReplicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
+ key = GetNextKey(key, len);
+ }
+ }
+ // Fill in 2nd level tables and add pointers to root table.
+ int mask = totalSize - 1;
+ int low = -1;
+ int currentOffset = tableOffset;
+ for (int len = rootBits + 1, step = 2; len <= MaxLength; len++, step <<= 1)
+ {
+ for (; count[len] > 0; count[len]--)
+ {
+ if ((key & mask) != low)
+ {
+ currentOffset += tableSize;
+ tableBits = NextTableBitSize(count, len, rootBits);
+ tableSize = 1 << tableBits;
+ totalSize += tableSize;
+ low = key & mask;
+ rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
+ }
+ ReplicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
+ key = GetNextKey(key, len);
+ }
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/HuffmanTreeGroup.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/HuffmanTreeGroup.cs
new file mode 100644
index 000000000..956ad2640
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/HuffmanTreeGroup.cs
@@ -0,0 +1,50 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Contains a collection of huffman trees with the same alphabet size.</summary>
+ internal sealed class HuffmanTreeGroup
+ {
+ /// <summary>The maximal alphabet size in this group.</summary>
+ private int alphabetSize;
+
+ /// <summary>Storage for Huffman lookup tables.</summary>
+ internal int[] codes;
+
+ /// <summary>
+ /// Offsets of distinct lookup tables in
+ /// <see cref="codes"/>
+ /// storage.
+ /// </summary>
+ internal int[] trees;
+
+ /// <summary>Initializes the Huffman tree group.</summary>
+ /// <param name="group">POJO to be initialised</param>
+ /// <param name="alphabetSize">the maximal alphabet size in this group</param>
+ /// <param name="n">number of Huffman codes</param>
+ internal static void Init(Org.Brotli.Dec.HuffmanTreeGroup group, int alphabetSize, int n)
+ {
+ group.alphabetSize = alphabetSize;
+ group.codes = new int[n * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
+ group.trees = new int[n];
+ }
+
+ /// <summary>Decodes Huffman trees from input stream and constructs lookup tables.</summary>
+ /// <param name="group">target POJO</param>
+ /// <param name="br">data source</param>
+ internal static void Decode(Org.Brotli.Dec.HuffmanTreeGroup group, Org.Brotli.Dec.BitReader br)
+ {
+ int next = 0;
+ int n = group.trees.Length;
+ for (int i = 0; i < n; i++)
+ {
+ group.trees[i] = next;
+ Org.Brotli.Dec.Decode.ReadHuffmanCode(group.alphabetSize, group.codes, next, br);
+ next += Org.Brotli.Dec.Huffman.HuffmanMaxTableSize;
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/IntReader.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/IntReader.cs
new file mode 100644
index 000000000..4363e0d30
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/IntReader.cs
@@ -0,0 +1,36 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Byte-to-int conversion magic.</summary>
+ internal sealed class IntReader
+ {
+ private byte[] byteBuffer;
+
+ private int[] intBuffer;
+
+ internal static void Init(Org.Brotli.Dec.IntReader ir, byte[] byteBuffer, int[] intBuffer)
+ {
+ ir.byteBuffer = byteBuffer;
+ ir.intBuffer = intBuffer;
+ }
+
+ /// <summary>Translates bytes to ints.</summary>
+ /// <remarks>
+ /// Translates bytes to ints.
+ /// NB: intLen == 4 * byteSize!
+ /// NB: intLen should be less or equal to intBuffer length.
+ /// </remarks>
+ internal static void Convert(Org.Brotli.Dec.IntReader ir, int intLen)
+ {
+ for (int i = 0; i < intLen; ++i)
+ {
+ ir.intBuffer[i] = ((ir.byteBuffer[i * 4] & unchecked((int)(0xFF)))) | ((ir.byteBuffer[(i * 4) + 1] & unchecked((int)(0xFF))) << 8) | ((ir.byteBuffer[(i * 4) + 2] & unchecked((int)(0xFF))) << 16) | ((ir.byteBuffer[(i * 4) + 3] & unchecked((int
+ )(0xFF))) << 24);
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Prefix.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Prefix.cs
new file mode 100644
index 000000000..abb6ccb65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Prefix.cs
@@ -0,0 +1,33 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Lookup tables to map prefix codes to value ranges.</summary>
+ /// <remarks>
+ /// Lookup tables to map prefix codes to value ranges.
+ /// <p> This is used during decoding of the block lengths, literal insertion lengths and copy
+ /// lengths.
+ /// <p> Range represents values: [offset, offset + 2 ^ n_bits)
+ /// </remarks>
+ internal sealed class Prefix
+ {
+ internal static readonly int[] BlockLengthOffset = new int[] { 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625 };
+
+ internal static readonly int[] BlockLengthNBits = new int[] { 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24 };
+
+ internal static readonly int[] InsertLengthOffset = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
+
+ internal static readonly int[] InsertLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
+
+ internal static readonly int[] CopyLengthOffset = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
+
+ internal static readonly int[] CopyLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
+
+ internal static readonly int[] InsertRangeLut = new int[] { 0, 0, 8, 8, 0, 16, 8, 16, 16 };
+
+ internal static readonly int[] CopyRangeLut = new int[] { 0, 8, 0, 8, 16, 0, 16, 8, 16 };
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/RunningState.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/RunningState.cs
new file mode 100644
index 000000000..81a374354
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/RunningState.cs
@@ -0,0 +1,37 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Enumeration of decoding state-machine.</summary>
+ internal sealed class RunningState
+ {
+ internal const int Uninitialized = 0;
+
+ internal const int BlockStart = 1;
+
+ internal const int CompressedBlockStart = 2;
+
+ internal const int MainLoop = 3;
+
+ internal const int ReadMetadata = 4;
+
+ internal const int CopyUncompressed = 5;
+
+ internal const int InsertLoop = 6;
+
+ internal const int CopyLoop = 7;
+
+ internal const int CopyWrapBuffer = 8;
+
+ internal const int Transform = 9;
+
+ internal const int Finished = 10;
+
+ internal const int Closed = 11;
+
+ internal const int Write = 12;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/State.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/State.cs
new file mode 100644
index 000000000..b35c39e1b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/State.cs
@@ -0,0 +1,171 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ internal sealed class State
+ {
+ internal int runningState = Org.Brotli.Dec.RunningState.Uninitialized;
+
+ internal int nextRunningState;
+
+ internal readonly Org.Brotli.Dec.BitReader br = new Org.Brotli.Dec.BitReader();
+
+ internal byte[] ringBuffer;
+
+ internal readonly int[] blockTypeTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
+
+ internal readonly int[] blockLenTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
+
+ internal int metaBlockLength;
+
+ internal bool inputEnd;
+
+ internal bool isUncompressed;
+
+ internal bool isMetadata;
+
+ internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup0 = new Org.Brotli.Dec.HuffmanTreeGroup();
+
+ internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup1 = new Org.Brotli.Dec.HuffmanTreeGroup();
+
+ internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup2 = new Org.Brotli.Dec.HuffmanTreeGroup();
+
+ internal readonly int[] blockLength = new int[3];
+
+ internal readonly int[] numBlockTypes = new int[3];
+
+ internal readonly int[] blockTypeRb = new int[6];
+
+ internal readonly int[] distRb = new int[] { 16, 15, 11, 4 };
+
+ internal int pos = 0;
+
+ internal int maxDistance = 0;
+
+ internal int distRbIdx = 0;
+
+ internal bool trivialLiteralContext = false;
+
+ internal int literalTreeIndex = 0;
+
+ internal int literalTree;
+
+ internal int j;
+
+ internal int insertLength;
+
+ internal byte[] contextModes;
+
+ internal byte[] contextMap;
+
+ internal int contextMapSlice;
+
+ internal int distContextMapSlice;
+
+ internal int contextLookupOffset1;
+
+ internal int contextLookupOffset2;
+
+ internal int treeCommandOffset;
+
+ internal int distanceCode;
+
+ internal byte[] distContextMap;
+
+ internal int numDirectDistanceCodes;
+
+ internal int distancePostfixMask;
+
+ internal int distancePostfixBits;
+
+ internal int distance;
+
+ internal int copyLength;
+
+ internal int copyDst;
+
+ internal int maxBackwardDistance;
+
+ internal int maxRingBufferSize;
+
+ internal int ringBufferSize = 0;
+
+ internal long expectedTotalSize = 0;
+
+ internal byte[] customDictionary = new byte[0];
+
+ internal int bytesToIgnore = 0;
+
+ internal int outputOffset;
+
+ internal int outputLength;
+
+ internal int outputUsed;
+
+ internal int bytesWritten;
+
+ internal int bytesToWrite;
+
+ internal byte[] output;
+
+ // Current meta-block header information.
+ // TODO: Update to current spec.
+ private static int DecodeWindowBits(Org.Brotli.Dec.BitReader br)
+ {
+ if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 0)
+ {
+ return 16;
+ }
+ int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
+ if (n != 0)
+ {
+ return 17 + n;
+ }
+ n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
+ if (n != 0)
+ {
+ return 8 + n;
+ }
+ return 17;
+ }
+
+ /// <summary>Associate input with decoder state.</summary>
+ /// <param name="state">uninitialized state without associated input</param>
+ /// <param name="input">compressed data source</param>
+ internal static void SetInput(Org.Brotli.Dec.State state, System.IO.Stream input)
+ {
+ if (state.runningState != Org.Brotli.Dec.RunningState.Uninitialized)
+ {
+ throw new System.InvalidOperationException("State MUST be uninitialized");
+ }
+ Org.Brotli.Dec.BitReader.Init(state.br, input);
+ int windowBits = DecodeWindowBits(state.br);
+ if (windowBits == 9)
+ {
+ /* Reserved case for future expansion. */
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid 'windowBits' code");
+ }
+ state.maxRingBufferSize = 1 << windowBits;
+ state.maxBackwardDistance = state.maxRingBufferSize - 16;
+ state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ internal static void Close(Org.Brotli.Dec.State state)
+ {
+ if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
+ {
+ throw new System.InvalidOperationException("State MUST be initialized");
+ }
+ if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
+ {
+ return;
+ }
+ state.runningState = Org.Brotli.Dec.RunningState.Closed;
+ Org.Brotli.Dec.BitReader.Close(state.br);
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/SynthTest.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/SynthTest.cs
new file mode 100644
index 000000000..92a03ae6a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/SynthTest.cs
@@ -0,0 +1,2174 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// Tests for
+ /// <see cref="Decode"/>
+ /// .
+ /// </summary>
+ public class SynthTest
+ {
+ /// <exception cref="System.IO.IOException"/>
+ private byte[] Decompress(byte[] data)
+ {
+ byte[] buffer = new byte[65536];
+ System.IO.MemoryStream input = new System.IO.MemoryStream(data);
+ System.IO.MemoryStream output = new System.IO.MemoryStream();
+ Org.Brotli.Dec.BrotliInputStream brotliInput = new Org.Brotli.Dec.BrotliInputStream(input);
+ while (true)
+ {
+ int len = brotliInput.Read(buffer, 0, buffer.Length);
+ if (len <= 0)
+ {
+ break;
+ }
+ output.Write(buffer, 0, len);
+ }
+ brotliInput.Close();
+ return output.ToArray();
+ }
+
+ private void CheckSynth(byte[] compressed, bool expectSuccess, string expectedOutput)
+ {
+ byte[] expected = Org.Brotli.Dec.Transform.ReadUniBytes(expectedOutput);
+ try
+ {
+ byte[] actual = Decompress(compressed);
+ if (!expectSuccess)
+ {
+ NUnit.Framework.Assert.Fail("expected to fail decoding, but succeeded");
+ }
+ NUnit.Framework.Assert.AreEqual(expected, actual);
+ }
+ catch (System.IO.IOException)
+ {
+ if (expectSuccess)
+ {
+ NUnit.Framework.Assert.Fail("expected to succeed decoding, but failed");
+ }
+ }
+ }
+
+ /* GENERATED CODE START */
+ [NUnit.Framework.Test]
+ public virtual void TestBaseDictWord()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x02))) };
+ CheckSynth(compressed, true, string.Empty + "time");
+ }
+
+ /*
+ // The stream consists of a base dictionary word.
+ main_header
+ metablock_header_easy: 4, 1
+ command_inscopy_easy: 0, 4
+ command_dist_easy: 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestBaseDictWordFinishBlockOnRingbufferWrap()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x1f))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x9b))), unchecked((byte)unchecked((int)(0x58))), unchecked(
+ (byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked(
+ (byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked(
+ (byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked(
+ (byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked(
+ (byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0x34))), unchecked((byte)unchecked((int)(0xd4))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "aaaaaaaaaaaaaaaaaaaaaaaaaaaatime");
+ }
+
+ /*
+ main_header
+ metablock_header_easy: 32, 1 // 32 = minimal ringbuffer size
+ command_easy: 4, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", 29
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestBaseDictWordTooLong()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x02))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ // Has an unmodified dictionary word that goes over the end of the
+ // meta-block. Same as BaseDictWord, but with a shorter meta-block length.
+ main_header
+ metablock_header_easy: 1, 1
+ command_inscopy_easy: 0, 4
+ command_dist_easy: 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestBlockCountMessage()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x0b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x8c))), unchecked((byte)unchecked((int)(0xc1))), unchecked((byte)unchecked((int)(0xc5))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x08))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x22))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0xe1))), unchecked((byte)unchecked((int)(0xfc))), unchecked((byte)unchecked((int)(0xfd))), unchecked((byte)unchecked((int)(0x22))), unchecked(
+ (byte)unchecked((int)(0x2c))), unchecked((byte)unchecked((int)(0xc4))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0xd8))), unchecked(
+ (byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x89))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x77))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x10))), unchecked((byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "aabbaaaaabab");
+ }
+
+ /*
+ // Same as BlockSwitchMessage but also uses 0-bit block-type commands.
+ main_header
+ metablock_header_begin: 1, 0, 12, 0
+ // two literal block types
+ vlq_blocktypes: 2
+ huffman_simple: 1,1,4, 1 // literal blocktype prefix code
+ huffman_fixed: 26 // literal blockcount prefix code
+ blockcount_easy: 2 // 2 a's
+ // one ins/copy and dist block type
+ vlq_blocktypes: 1
+ vlq_blocktypes: 1
+ ndirect: 0 0
+ // two MSB6 literal context modes
+ bits: "00", "00"
+ // two literal prefix codes
+ vlq_blocktypes: 2
+ // literal context map
+ vlq_rlemax: 5
+ huffman_simple: 0,3,7, 5,0,6 // context map rle huffman code
+ // context map rle: repeat 0 64 times, 1+5 64 times
+ bits: "01", "0", "11111", "11", "0", "11111"
+ bit: 1 // MTF enabled
+ // one distance prefix code
+ vlq_blocktypes: 1
+ huffman_simple: 0,1,256, 97 // only a's
+ huffman_simple: 0,1,256, 98 // only b's
+ huffman_fixed: 704
+ huffman_fixed: 64
+ // now comes the data
+ command_inscopy_easy: 12, 0
+ blockcount_easy: 2 // switch to other block type; 2 b's
+ blockcount_easy: 5 // switch to other block type; 5 a's
+ blockcount_easy: 1 // switch to other block type; 1 b
+ blockcount_easy: 1 // switch to other block type; 1 a
+ blockcount_easy: 1 // switch to other block type; 1 b
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestBlockSwitchMessage()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x0b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xd1))), unchecked((byte)unchecked((int)(0xe1))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0xc6))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0xe2))), unchecked((byte)unchecked((int)(0x06))), unchecked((byte)unchecked((int)(0x04))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x91))), unchecked((byte)unchecked((int)(0xb2))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xfe))), unchecked((byte)unchecked((int)(0x7e))), unchecked(
+ (byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x16))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x1c))), unchecked(
+ (byte)unchecked((int)(0x6c))), unchecked((byte)unchecked((int)(0x99))), unchecked((byte)unchecked((int)(0xc4))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x09))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x3b))), unchecked((byte)unchecked((int)(0x6d))), unchecked((byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x08))), unchecked((byte)unchecked((int)(0x82))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "aabbaaaaabab");
+ }
+
+ /*
+ // Uses blocks with 1-symbol huffman codes that take 0 bits, so that it
+ // is the blockswitch commands that encode the message rather than actual
+ // literals.
+ main_header
+ metablock_header_begin: 1, 0, 12, 0
+ // two literal block types
+ vlq_blocktypes: 2
+ huffman_simple: 1,4,4, 1,0,2,3 // literal blocktype prefix code
+ huffman_fixed: 26 // literal blockcount prefix code
+ blockcount_easy: 2 // 2 a's
+ // one ins/copy and dist block type
+ vlq_blocktypes: 1
+ vlq_blocktypes: 1
+ ndirect: 0 0
+ // two MSB6 literal context modes
+ bits: "00", "00"
+ // two literal prefix codes
+ vlq_blocktypes: 2
+ // literal context map
+ vlq_rlemax: 5
+ huffman_simple: 0,3,7, 5,0,6 // context map rle huffman code
+ // context map rle: repeat 0 64 times, 1+5 64 times
+ bits: "01", "0", "11111", "11", "0", "11111"
+ bit: 1 // MTF enabled
+ // one distance prefix code
+ vlq_blocktypes: 1
+ huffman_simple: 0,1,256, 97 // only a's
+ huffman_simple: 0,1,256, 98 // only b's
+ huffman_fixed: 704
+ huffman_fixed: 64
+ // now comes the data
+ command_inscopy_easy: 12, 0
+ bits: "0"; blockcount_easy: 2 // switch to other block type; 2 b's
+ bits: "0"; blockcount_easy: 5 // switch to other block type; 5 a's
+ bits: "0"; blockcount_easy: 1 // switch to other block type; 1 b
+ bits: "0"; blockcount_easy: 1 // switch to other block type; 1 a
+ bits: "0"; blockcount_easy: 1 // switch to other block type; 1 b
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestClClTreeDeficiency()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x43))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x05))), unchecked(
+ (byte)unchecked((int)(0x88))), unchecked((byte)unchecked((int)(0x55))), unchecked((byte)unchecked((int)(0x90))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x89))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x77))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0x28))), unchecked((byte)unchecked((int)(0x40))), unchecked((byte)unchecked((int)(0x23))) };
+ CheckSynth(compressed, false, string.Empty + "aaab");
+ }
+
+ /*
+ // This test is a copy of TooManySymbolsRepeated, with changed clcl table.
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ hskip: 0
+ clcl_ordered: 0,3,0,0,0,0,0,0,3,3,0,0,0,0,0,0,1,0
+ set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "101",\
+ "", "", "", "", "", "", "0", ""
+ cl_rle: 8
+ cl_rle_rep: 9, 96
+ cl_rle: 1
+ cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ command_literal_bits: 0, 0, 0, 101100010
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestClClTreeExcess()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xc3))), unchecked((byte)unchecked((int)(0x7b))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x58))), unchecked(
+ (byte)unchecked((int)(0x41))), unchecked((byte)unchecked((int)(0x06))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x60))), unchecked((byte)unchecked((int)(0xcb))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x06))), unchecked((byte)unchecked((int)(0x48))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xdc))), unchecked(
+ (byte)unchecked((int)(0x69))), unchecked((byte)unchecked((int)(0xa3))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x8d))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, false, string.Empty + "aaab");
+ }
+
+ /*
+ // This test is a copy of ClClTreeDeficiency, with changed clcl table.
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ hskip: 0
+ clcl_ordered: 0,3,0,0,0,0,0,0,3,1,0,0,0,0,0,0,1,0
+ set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "1",\
+ "", "", "", "", "", "", "0", ""
+ cl_rle: 8
+ cl_rle_rep: 9, 96
+ cl_rle: 1
+ cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ command_literal_bits: 0, 0, 0, 101100010
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestComplexHuffmanCodeTwoSymbols()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked(
+ (byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0xa2))), unchecked((byte)unchecked((int)(0x1a))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x0e))), unchecked((byte)unchecked((int)(0xb6))), unchecked((byte)unchecked((int)(0x4c))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x04))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xc0))), unchecked((byte)unchecked((int)(0x9d))), unchecked((byte)unchecked((int)(0x36))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x04))) };
+ CheckSynth(compressed, true, string.Empty + "ab");
+ }
+
+ /*
+ // This tests a complex huffman code with only two symbols followed by a
+ // tiny amount of content.
+ main_header
+ metablock_header_begin: 1, 0, 2, 0
+ metablock_header_trivial_context
+ // begin of literal huffman tree. The tree has symbol length 1 for "a",
+ // symbol length 1 for "b" and symbol length 0 for all others.
+ hskip: 0
+ clcl_ordered: 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
+ set_prefix_cl_rle: "", "0", "", "", "", "", "", "", "", "",\
+ "", "", "", "", "", "", "", "1"
+ cl_rle_rep_0: 97
+ cl_rle: 1 // literal number 97, that is, the letter 'a'
+ cl_rle: 1 // literal number 98, that is, the letter 'b'
+ // end of literal huffman tree
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 2, 0
+ command_literal_bits: 0, 1 // a followed by b
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestCompressedUncompressedShortCompressed()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x8b))), unchecked((byte)unchecked((int)(0xfe))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x9b))), unchecked((byte)unchecked((int)(0x66))), unchecked(
+ (byte)unchecked((int)(0x6f))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x0a))), unchecked((byte)unchecked((int)(0x50))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x10))), unchecked(
+ (byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked(
+ (byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked(
+ (byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaabbbbbbbbbb"
+ );
+ }
+
+ /*
+ main_header: 22
+ metablock_header_easy: 1022, 0
+ command_easy: 1021, "a", 1 // 1022 x "a"
+ metablock_uncompressed: "bbbbbb"
+ metablock_header_easy: 4, 1
+ command_easy: 4, "", 1 // 6 + 4 = 10 x "b"
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestCompressedUncompressedShortCompressedSmallWindow()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x21))), unchecked((byte)unchecked((int)(0xf4))), unchecked((byte)unchecked((int)(0x0f))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x1c))), unchecked((byte)unchecked((int)(0xa7))), unchecked((byte)unchecked((int)(0x6d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x89))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x77))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0x34))), unchecked(
+ (byte)unchecked((int)(0x7b))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x50))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x80))), unchecked(
+ (byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x62))), unchecked(
+ (byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked(
+ (byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaabbbbbbbbbb"
+ );
+ }
+
+ /*
+ main_header: 10
+ metablock_header_easy: 1022, 0
+ command_easy: 1021, "a", 1 // 1022 x "a"
+ metablock_uncompressed: "bbbbbb"
+ metablock_header_easy: 4, 1
+ command_easy: 4, "", 1 // 6 + 4 = 10 x "b"
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestCopyLengthTooLong()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x86))), unchecked((byte)unchecked((int)(0x02))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ // Has a copy length that goes over the end of the meta-block.
+ // Same as OneCommand, but with a shorter meta-block length.
+ main_header
+ metablock_header_easy: 2, 1
+ command_easy: 2, "a", 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestCustomHuffmanCode()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xc3))), unchecked((byte)unchecked((int)(0x3d))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x58))), unchecked(
+ (byte)unchecked((int)(0x82))), unchecked((byte)unchecked((int)(0x08))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xc0))), unchecked((byte)unchecked((int)(0xc1))), unchecked((byte)unchecked((int)(0x96))), unchecked(
+ (byte)unchecked((int)(0x49))), unchecked((byte)unchecked((int)(0x0c))), unchecked((byte)unchecked((int)(0x90))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xb8))), unchecked(
+ (byte)unchecked((int)(0xd3))), unchecked((byte)unchecked((int)(0x46))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x1a))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, true, string.Empty + "aaab");
+ }
+
+ /*
+ // This tests a small hand crafted huffman code followed by a tiny amount
+ // of content. This tests if the bit reader detects the end correctly even
+ // with tiny content after a larger huffman tree encoding.
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ // begin of literal huffman tree. The tree has symbol length 1 for "a",
+ // symbol length 8 for null, symbol length 9 for all others. The length 1
+ // for a is chosen on purpose here, the others must be like that to
+ // fulfill the requirement that sum of 32>>length is 32768.
+ hskip: 0
+ clcl_ordered: 0,3,0,0,0,0,0,0,3,2,0,0,0,0,0,0,1,0
+ set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "10",\
+ "", "", "", "", "", "", "0", ""
+ cl_rle: 8
+ cl_rle_rep: 9, 96
+ cl_rle: 1 // literal number 97, that is, the letter 'a'
+ cl_rle_rep: 9, 158
+ // end of literal huffman tree
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ // Here is how the code "101100010" for b is derived: remember that a has
+ // symbol length 1, null has symbol length 8, the rest 9. So in the
+ // canonical huffman code, the code for "a" is "0", for null is
+ // "10000000". The next value has "100000010" (cfr. the rules of canonical
+ // prefix code). Counting upwards +95 from there, the value "@" (ascii 96,
+ // before "a") has "101100001", and so b, the next 9-bit symbol, has the
+ // next binary value "101100010".
+ command_literal_bits: 0, 0, 0, 101100010 // 3 a's followed by a b
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestEmpty()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x3b))) };
+ CheckSynth(compressed, true, string.Empty);
+ }
+
+ /*
+ main_header
+ metablock_lastempty
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestHelloWorld()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x0a))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x9b))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x59))), unchecked((byte)unchecked((int)(0x98))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0x13))), unchecked(
+ (byte)unchecked((int)(0xb8))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x3b))), unchecked((byte)unchecked((int)(0xd9))), unchecked((byte)unchecked((int)(0x98))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, true, string.Empty + "hello world");
+ }
+
+ /*
+ main_header
+ metablock_fixed: "hello world", 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInsertTooLong()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x09))), unchecked(
+ (byte)unchecked((int)(0x86))), unchecked((byte)unchecked((int)(0x46))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ // Has an insert length that goes over the end of the meta-block.
+ // Same as OneInsert, but with a shorter meta-block length.
+ main_header
+ metablock_header_easy: 1, 1
+ command_easy: 0, "ab"
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidNoLastMetablock()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x0b))), unchecked((byte)unchecked((int)(0x06))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x9b))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x13))), unchecked((byte)unchecked((int)(0x59))), unchecked((byte)unchecked((int)(0x98))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0xd8))), unchecked(
+ (byte)unchecked((int)(0x13))), unchecked((byte)unchecked((int)(0xb8))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x3b))), unchecked((byte)unchecked((int)(0xd9))), unchecked((byte)unchecked((int)(0x98))), unchecked(
+ (byte)unchecked((int)(0xe8))), unchecked((byte)unchecked((int)(0x00))) };
+ CheckSynth(compressed, false, string.Empty + "hello world");
+ }
+
+ /*
+ main_header
+ metablock_fixed: \"hello world\", 0
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidNoMetaBlocks()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x0b))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ main_header
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidTooFarDist()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0xa1))), unchecked((byte)unchecked((int)(0x48))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x1c))), unchecked((byte)unchecked((int)(0xa7))), unchecked((byte)unchecked((int)(0x6d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x89))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x77))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0xe8))), unchecked(
+ (byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x62))), unchecked((byte)unchecked((int)(0x6f))), unchecked((byte)unchecked((int)(0x4f))), unchecked((byte)unchecked((int)(0x60))), unchecked((byte)unchecked((int)(0x66))), unchecked(
+ (byte)unchecked((int)(0xe8))), unchecked((byte)unchecked((int)(0x44))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x0f))), unchecked((byte)unchecked((int)(0x09))), unchecked((byte)unchecked((int)(0x0d))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ main_header: 10
+ metablock_header_begin: 1, 0, 10, 0
+ metablock_header_trivial_context
+ huffman_fixed: 256
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_easy: 2, "too far!", 1000000 // distance too far for 10 wbits
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidTooLargeContextMap()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xd1))), unchecked((byte)unchecked((int)(0xe1))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0xc6))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0xe2))), unchecked((byte)unchecked((int)(0x06))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x91))), unchecked((byte)unchecked((int)(0xb2))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xfe))), unchecked((byte)unchecked((int)(0xfb))), unchecked(
+ (byte)unchecked((int)(0x45))), unchecked((byte)unchecked((int)(0x58))), unchecked((byte)unchecked((int)(0x88))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked(
+ (byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, false, string.Empty + "a");
+ }
+
+ /*
+ // Has a repeat code a context map that makes the size too big -> invalid.
+ main_header
+ metablock_header_begin: 1, 0, 1, 0
+ // two literal block types
+ vlq_blocktypes: 2
+ huffman_simple: 1,4,4, 1,0,2,3 // literal blocktype prefix code
+ huffman_fixed: 26 // literal blockcount prefix code
+ blockcount_easy: 1
+ // one ins/copy and dist block type
+ vlq_blocktypes: 1
+ vlq_blocktypes: 1
+ ndirect: 0 0
+ // two MSB6 literal context modes
+ bits: "00", "00"
+ // two literal prefix codes
+ vlq_blocktypes: 2
+ // literal context map
+ vlq_rlemax: 5
+ huffman_simple: 0,3,7, 5,0,6 // context map rle huffman code
+ // Too long context map rle: repeat 0 64 times, 1+5 65 times, that is 129
+ // values which is 1 too much.
+ bits: "01", "0", "11111", "11", "11", "0", "11111"
+ bit: 1 // MTF enabled
+ // one distance prefix code
+ vlq_blocktypes: 1
+ huffman_simple: 0,1,256, 97 // only a's
+ huffman_simple: 0,1,256, 98 // only b's
+ huffman_fixed: 704
+ huffman_fixed: 64
+ // now comes the data
+ command_inscopy_easy: 1, 0
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidTransformType()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x2d))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x19))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ main_header
+ metablock_header_easy: 4, 1
+ command_inscopy_easy: 0, 4
+ command_dist_easy: 123905 // = 121 << 10 + 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestInvalidWindowBits9()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x91))), unchecked((byte)unchecked((int)(0x10))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x1c))), unchecked((byte)unchecked((int)(0xa7))), unchecked((byte)unchecked((int)(0x6d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0xd8))), unchecked((byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0x89))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x77))), unchecked((byte)unchecked((int)(0xda))), unchecked((byte)unchecked((int)(0xc8))), unchecked(
+ (byte)unchecked((int)(0x20))), unchecked((byte)unchecked((int)(0x32))), unchecked((byte)unchecked((int)(0xd4))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, false, string.Empty + "a");
+ }
+
+ /*
+ main_header: 9
+ metablock_fixed: \"a\", 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestManyTinyMetablocks()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x0b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked(
+ (byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked(
+ (byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x04))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x61))), unchecked((byte)unchecked((int)(0x34))) };
+ CheckSynth(compressed, true, string.Empty + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababababababababababababababababababababababababababab"
+ + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababababababababababababababababababababababababababab"
+ + "abababababababababababababababababababababababababababababababababababab" + "abababababababababababab");
+ }
+
+ /*
+ main_header
+ repeat: 300
+ metablock_uncompressed: "a"
+ metablock_fixed: "b"
+ end_repeat
+ metablock_lastempty
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestNegativeDistance()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x0f))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x42))), unchecked((byte)unchecked((int)(0x01))), unchecked(
+ (byte)unchecked((int)(0x1c))) };
+ CheckSynth(compressed, false, string.Empty + "timemememememeXX");
+ }
+
+ /*
+ main_header
+ metablock_header_easy: 16, 1
+ command_inscopy_easy: 0, 4 // time
+ command_dist_easy: 1
+ command_inscopy_easy: 0, 2 // me
+ command_dist_easy: 2
+ command_inscopy_easy: 0, 2 // me
+ command_dist_easy: 2
+ command_inscopy_easy: 0, 2 // me
+ command_dist_easy: 2
+ command_inscopy_easy: 0, 2 // me
+ command_dist_easy: 2
+ command_inscopy_easy: 0, 2 // me
+ command_dist_easy: 2 // All rb items are 2 now
+ command_inscopy_easy: 0, 2
+ bits: "011100" // 15 -> distance = rb[idx + 2] - 3
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestNegativeRemainingLenBetweenMetablocks()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x0b))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x09))), unchecked(
+ (byte)unchecked((int)(0x86))), unchecked((byte)unchecked((int)(0x46))), unchecked((byte)unchecked((int)(0x11))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x38))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0xdb))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked(
+ (byte)unchecked((int)(0x24))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x91))), unchecked(
+ (byte)unchecked((int)(0x60))), unchecked((byte)unchecked((int)(0x68))), unchecked((byte)unchecked((int)(0x04))) };
+ CheckSynth(compressed, false, string.Empty + "abab");
+ }
+
+ /*
+ main_header
+ metablock_header_easy: 1, 0
+ command_easy: 0, "ab" // remaining length == -1 -> invalid stream
+ metablock_header_easy: 2, 1
+ command_easy: 0, "ab"
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestOneCommand()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x11))), unchecked(
+ (byte)unchecked((int)(0x86))), unchecked((byte)unchecked((int)(0x02))) };
+ CheckSynth(compressed, true, string.Empty + "aaa");
+ }
+
+ /*
+ // The stream consists of one command with insert and copy.
+ main_header
+ metablock_header_easy: 3, 1
+ command_easy: 2, "a", 1
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestOneInsert()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x09))), unchecked(
+ (byte)unchecked((int)(0x86))), unchecked((byte)unchecked((int)(0x46))) };
+ CheckSynth(compressed, true, string.Empty + "ab");
+ }
+
+ /*
+ // The stream consists of one half command with insert only.
+ main_header
+ metablock_header_easy: 2, 1
+ command_easy: 0, "ab"
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestSimplePrefix()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xa0))), unchecked(
+ (byte)unchecked((int)(0xc3))), unchecked((byte)unchecked((int)(0xc4))), unchecked((byte)unchecked((int)(0xc6))), unchecked((byte)unchecked((int)(0xc8))), unchecked((byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x51))), unchecked((byte)unchecked((int)(0xa0))), unchecked(
+ (byte)unchecked((int)(0x1d))) };
+ CheckSynth(compressed, true, string.Empty + "abcd");
+ }
+
+ /*
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ huffman_simple: 1,4,256, 97,98,99,100 // ascii codes for a, b, c, d
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ command_literal_bits: 0, 10, 110, 111 // a, b, c, d
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestSimplePrefixDuplicateSymbols()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xa0))), unchecked(
+ (byte)unchecked((int)(0xc3))), unchecked((byte)unchecked((int)(0xc4))), unchecked((byte)unchecked((int)(0xc2))), unchecked((byte)unchecked((int)(0xc4))), unchecked((byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x70))), unchecked((byte)unchecked((int)(0xb0))), unchecked((byte)unchecked((int)(0x65))), unchecked((byte)unchecked((int)(0x12))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x24))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xee))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x51))), unchecked((byte)unchecked((int)(0xa0))), unchecked(
+ (byte)unchecked((int)(0x1d))) };
+ CheckSynth(compressed, false, string.Empty + "abab");
+ }
+
+ /*
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ huffman_simple: 1,4,256, 97,98,97,98 // ascii codes for a, b, a, b
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ command_literal_bits: 0, 10, 110, 111 // a, b, a, b
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestSimplePrefixOutOfRangeSymbols()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x4d))), unchecked((byte)unchecked((int)(0xff))), unchecked(
+ (byte)unchecked((int)(0xef))), unchecked((byte)unchecked((int)(0x7f))), unchecked((byte)unchecked((int)(0xff))), unchecked((byte)unchecked((int)(0xfc))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0xb8))), unchecked((byte)unchecked((int)(0xd3))), unchecked((byte)unchecked((int)(0x06))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+
+ /*
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ huffman_fixed: 256
+ huffman_simple: 1,4,704, 1023,1022,1021,1020
+ huffman_fixed: 64
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestTooManySymbolsRepeated()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xc3))), unchecked((byte)unchecked((int)(0x3d))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0x58))), unchecked(
+ (byte)unchecked((int)(0x82))), unchecked((byte)unchecked((int)(0x0c))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xc0))), unchecked((byte)unchecked((int)(0xc1))), unchecked((byte)unchecked((int)(0x96))), unchecked(
+ (byte)unchecked((int)(0x49))), unchecked((byte)unchecked((int)(0x0c))), unchecked((byte)unchecked((int)(0x90))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xb8))), unchecked(
+ (byte)unchecked((int)(0xd3))), unchecked((byte)unchecked((int)(0x46))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x1a))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, false, string.Empty + "aaab");
+ }
+
+ /*
+ // This test is a copy of CustomHuffmanCode, with changed repeat count.
+ main_header
+ metablock_header_begin: 1, 0, 4, 0
+ metablock_header_trivial_context
+ hskip: 0
+ clcl_ordered: 0,3,0,0,0,0,0,0,3,2,0,0,0,0,0,0,1,0
+ set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "10",\
+ "", "", "", "", "", "", "0", ""
+ cl_rle: 8
+ cl_rle_rep: 9, 96
+ cl_rle: 1
+ cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ huffman_fixed: 704
+ huffman_fixed: 64
+ command_inscopy_easy: 4, 0
+ command_literal_bits: 0, 0, 0, 101100010
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestTransformedDictWord()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x08))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x09))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, true, string.Empty + "time the ");
+ }
+
+ /*
+ // The stream consists of a transformed dictionary word.
+ main_header
+ metablock_header_easy: 9, 1
+ command_inscopy_easy: 0, 4
+ command_dist_easy: 5121
+ */
+ [NUnit.Framework.Test]
+ public virtual void TestTransformedDictWordTooLong()
+ {
+ byte[] compressed = new byte[] { unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x03))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x80))), unchecked((byte)unchecked((int)(0xe3))), unchecked((byte)unchecked((int)(0xb4))), unchecked((byte)unchecked((int)(0x0d))), unchecked((byte)unchecked((int)(0x00))), unchecked(
+ (byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0x07))), unchecked((byte)unchecked((int)(0x5b))), unchecked((byte)unchecked((int)(0x26))), unchecked((byte)unchecked((int)(0x31))), unchecked((byte)unchecked((int)(0x40))), unchecked(
+ (byte)unchecked((int)(0x02))), unchecked((byte)unchecked((int)(0x00))), unchecked((byte)unchecked((int)(0xe0))), unchecked((byte)unchecked((int)(0x4e))), unchecked((byte)unchecked((int)(0x1b))), unchecked((byte)unchecked((int)(0x41))), unchecked(
+ (byte)unchecked((int)(0x09))), unchecked((byte)unchecked((int)(0x01))), unchecked((byte)unchecked((int)(0x01))) };
+ CheckSynth(compressed, false, string.Empty);
+ }
+ /*
+ // Has a transformed dictionary word that goes over the end of the
+ // meta-block, but the base dictionary word fits in the meta-block.
+ // Same as TransformedDictWord, but with a shorter meta-block length.
+ main_header
+ metablock_header_easy: 4, 1
+ command_inscopy_easy: 0, 4
+ command_dist_easy: 5121
+ */
+ /* GENERATED CODE END */
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Transform.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Transform.cs
new file mode 100644
index 000000000..9869d6ec2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Transform.cs
@@ -0,0 +1,154 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Transformations on dictionary words.</summary>
+ internal sealed class Transform
+ {
+ private readonly byte[] prefix;
+
+ private readonly int type;
+
+ private readonly byte[] suffix;
+
+ internal Transform(string prefix, int type, string suffix)
+ {
+ this.prefix = ReadUniBytes(prefix);
+ this.type = type;
+ this.suffix = ReadUniBytes(suffix);
+ }
+
+ internal static byte[] ReadUniBytes(string uniBytes)
+ {
+ byte[] result = new byte[uniBytes.Length];
+ for (int i = 0; i < result.Length; ++i)
+ {
+ result[i] = unchecked((byte)uniBytes[i]);
+ }
+ return result;
+ }
+
+ internal static readonly Org.Brotli.Dec.Transform[] Transforms = new Org.Brotli.Dec.Transform[] { new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty,
+ Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst1, string.Empty), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " the "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity
+ , string.Empty), new Org.Brotli.Dec.Transform("s ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .UppercaseFirst, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " and "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst2, string.Empty), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, string.Empty), new Org.Brotli.Dec.Transform(", ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
+ , ", "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " in "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .Identity, " to "), new Org.Brotli.Dec.Transform("e ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\""), new Org.Brotli.Dec.Transform(string.Empty,
+ Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n"), new
+ Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "]"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .Identity, " for "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast2, string.Empty), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " a "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " that "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst
+ , string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
+ .Identity, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " with "), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " from "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
+ , " by "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst5, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst6, string.Empty), new Org.Brotli.Dec.Transform
+ (" the ", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .Identity, ". The "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " on "), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " as "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " is "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast7
+ , string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, "ing "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n\t"), new Org.Brotli.Dec.Transform(string.Empty
+ , Org.Brotli.Dec.WordTransformType.Identity, ":"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ed "), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst9, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst7, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .OmitLast6, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast8, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " at "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .Identity, "ly "), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast5, string.Empty), new Org.Brotli.Dec.Transform(
+ string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast9, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
+ , "\""), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .UppercaseFirst, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(".com/",
+ Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of the "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
+ , "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". This "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType
+ .Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " not "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "er "
+ ), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "al "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
+ .UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "='"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\""), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity,
+ "ful "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ive "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .Identity, "less "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "est "), new Org.Brotli.Dec.Transform
+ (" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\">"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "='"
+ ), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ize "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
+ .UppercaseAll, "."), new Org.Brotli.Dec.Transform("\u00c2\u00a0", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(string.Empty
+ , Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
+ , "ous "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "='"), new Org.Brotli.Dec.Transform(" ",
+ Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform
+ (string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.
+ UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
+ .UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
+ .UppercaseFirst, "='") };
+
+ internal static int TransformDictionaryWord(byte[] dst, int dstOffset, byte[] word, int wordOffset, int len, Org.Brotli.Dec.Transform transform)
+ {
+ int offset = dstOffset;
+ // Copy prefix.
+ byte[] @string = transform.prefix;
+ int tmp = @string.Length;
+ int i = 0;
+ // In most cases tmp < 10 -> no benefits from System.arrayCopy
+ while (i < tmp)
+ {
+ dst[offset++] = @string[i++];
+ }
+ // Copy trimmed word.
+ int op = transform.type;
+ tmp = Org.Brotli.Dec.WordTransformType.GetOmitFirst(op);
+ if (tmp > len)
+ {
+ tmp = len;
+ }
+ wordOffset += tmp;
+ len -= tmp;
+ len -= Org.Brotli.Dec.WordTransformType.GetOmitLast(op);
+ i = len;
+ while (i > 0)
+ {
+ dst[offset++] = word[wordOffset++];
+ i--;
+ }
+ if (op == Org.Brotli.Dec.WordTransformType.UppercaseAll || op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
+ {
+ int uppercaseOffset = offset - len;
+ if (op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
+ {
+ len = 1;
+ }
+ while (len > 0)
+ {
+ tmp = dst[uppercaseOffset] & unchecked((int)(0xFF));
+ if (tmp < unchecked((int)(0xc0)))
+ {
+ if (tmp >= 'a' && tmp <= 'z')
+ {
+ dst[uppercaseOffset] ^= unchecked((byte)32);
+ }
+ uppercaseOffset += 1;
+ len -= 1;
+ }
+ else if (tmp < unchecked((int)(0xe0)))
+ {
+ dst[uppercaseOffset + 1] ^= unchecked((byte)32);
+ uppercaseOffset += 2;
+ len -= 2;
+ }
+ else
+ {
+ dst[uppercaseOffset + 2] ^= unchecked((byte)5);
+ uppercaseOffset += 3;
+ len -= 3;
+ }
+ }
+ }
+ // Copy suffix.
+ @string = transform.suffix;
+ tmp = @string.Length;
+ i = 0;
+ while (i < tmp)
+ {
+ dst[offset++] = @string[i++];
+ }
+ return offset - dstOffset;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/TransformTest.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/TransformTest.cs
new file mode 100644
index 000000000..0f6845fde
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/TransformTest.cs
@@ -0,0 +1,74 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>
+ /// Tests for
+ /// <see cref="Transform"/>
+ /// .
+ /// </summary>
+ public class TransformTest
+ {
+ private static long Crc64(byte[] data)
+ {
+ long crc = -1;
+ for (int i = 0; i < data.Length; ++i)
+ {
+ long c = (crc ^ (long)(data[i] & unchecked((int)(0xFF)))) & unchecked((int)(0xFF));
+ for (int k = 0; k < 8; k++)
+ {
+ c = ((long)(((ulong)c) >> 1)) ^ (-(c & 1L) & -3932672073523589310L);
+ }
+ crc = c ^ ((long)(((ulong)crc) >> 8));
+ }
+ return ~crc;
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestTrimAll()
+ {
+ byte[] output = new byte[2];
+ byte[] input = new byte[] { 119, 111, 114, 100 };
+ // "word"
+ Org.Brotli.Dec.Transform transform = new Org.Brotli.Dec.Transform("[", Org.Brotli.Dec.WordTransformType.OmitFirst5, "]");
+ Org.Brotli.Dec.Transform.TransformDictionaryWord(output, 0, input, 0, input.Length, transform);
+ byte[] expectedOutput = new byte[] { 91, 93 };
+ // "[]"
+ NUnit.Framework.Assert.AreEqual(expectedOutput, output);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestCapitalize()
+ {
+ byte[] output = new byte[8];
+ byte[] input = new byte[] { 113, unchecked((byte)(-61)), unchecked((byte)(-90)), unchecked((byte)(-32)), unchecked((byte)(-92)), unchecked((byte)(-86)) };
+ // "qæप"
+ Org.Brotli.Dec.Transform transform = new Org.Brotli.Dec.Transform("[", Org.Brotli.Dec.WordTransformType.UppercaseAll, "]");
+ Org.Brotli.Dec.Transform.TransformDictionaryWord(output, 0, input, 0, input.Length, transform);
+ byte[] expectedOutput = new byte[] { 91, 81, unchecked((byte)(-61)), unchecked((byte)(-122)), unchecked((byte)(-32)), unchecked((byte)(-92)), unchecked((byte)(-81)), 93 };
+ // "[QÆय]"
+ NUnit.Framework.Assert.AreEqual(expectedOutput, output);
+ }
+
+ [NUnit.Framework.Test]
+ public virtual void TestAllTransforms()
+ {
+ /* This string allows to apply all transforms: head and tail cutting, capitalization and
+ turning to upper case; all results will be mutually different. */
+ // "o123456789abcdef"
+ byte[] testWord = new byte[] { 111, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 };
+ byte[] output = new byte[2259];
+ int offset = 0;
+ for (int i = 0; i < Org.Brotli.Dec.Transform.Transforms.Length; ++i)
+ {
+ offset += Org.Brotli.Dec.Transform.TransformDictionaryWord(output, offset, testWord, 0, testWord.Length, Org.Brotli.Dec.Transform.Transforms[i]);
+ output[offset++] = unchecked((byte)(-1));
+ }
+ NUnit.Framework.Assert.AreEqual(output.Length, offset);
+ NUnit.Framework.Assert.AreEqual(8929191060211225186L, Crc64(output));
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Utils.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Utils.cs
new file mode 100644
index 000000000..e95f87efe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/Utils.cs
@@ -0,0 +1,59 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>A set of utility methods.</summary>
+ internal sealed class Utils
+ {
+ private static readonly byte[] ByteZeroes = new byte[1024];
+
+ private static readonly int[] IntZeroes = new int[1024];
+
+ /// <summary>Fills byte array with zeroes.</summary>
+ /// <remarks>
+ /// Fills byte array with zeroes.
+ /// <p> Current implementation uses
+ /// <see cref="System.Array.Copy(object, int, object, int, int)"/>
+ /// , so it should be used for length not
+ /// less than 16.
+ /// </remarks>
+ /// <param name="dest">array to fill with zeroes</param>
+ /// <param name="offset">the first byte to fill</param>
+ /// <param name="length">number of bytes to change</param>
+ internal static void FillWithZeroes(byte[] dest, int offset, int length)
+ {
+ int cursor = 0;
+ while (cursor < length)
+ {
+ int step = System.Math.Min(cursor + 1024, length) - cursor;
+ System.Array.Copy(ByteZeroes, 0, dest, offset + cursor, step);
+ cursor += step;
+ }
+ }
+
+ /// <summary>Fills int array with zeroes.</summary>
+ /// <remarks>
+ /// Fills int array with zeroes.
+ /// <p> Current implementation uses
+ /// <see cref="System.Array.Copy(object, int, object, int, int)"/>
+ /// , so it should be used for length not
+ /// less than 16.
+ /// </remarks>
+ /// <param name="dest">array to fill with zeroes</param>
+ /// <param name="offset">the first item to fill</param>
+ /// <param name="length">number of item to change</param>
+ internal static void FillWithZeroes(int[] dest, int offset, int length)
+ {
+ int cursor = 0;
+ while (cursor < length)
+ {
+ int step = System.Math.Min(cursor + 1024, length) - cursor;
+ System.Array.Copy(IntZeroes, 0, dest, offset + cursor, step);
+ cursor += step;
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/WordTransformType.cs b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/WordTransformType.cs
new file mode 100644
index 000000000..777a5f5a5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/org/brotli/dec/WordTransformType.cs
@@ -0,0 +1,68 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Enumeration of all possible word transformations.</summary>
+ /// <remarks>
+ /// Enumeration of all possible word transformations.
+ /// <p>There are two simple types of transforms: omit X first/last symbols, two character-case
+ /// transforms and the identity transform.
+ /// </remarks>
+ internal sealed class WordTransformType
+ {
+ internal const int Identity = 0;
+
+ internal const int OmitLast1 = 1;
+
+ internal const int OmitLast2 = 2;
+
+ internal const int OmitLast3 = 3;
+
+ internal const int OmitLast4 = 4;
+
+ internal const int OmitLast5 = 5;
+
+ internal const int OmitLast6 = 6;
+
+ internal const int OmitLast7 = 7;
+
+ internal const int OmitLast8 = 8;
+
+ internal const int OmitLast9 = 9;
+
+ internal const int UppercaseFirst = 10;
+
+ internal const int UppercaseAll = 11;
+
+ internal const int OmitFirst1 = 12;
+
+ internal const int OmitFirst2 = 13;
+
+ internal const int OmitFirst3 = 14;
+
+ internal const int OmitFirst4 = 15;
+
+ internal const int OmitFirst5 = 16;
+
+ internal const int OmitFirst6 = 17;
+
+ internal const int OmitFirst7 = 18;
+
+ internal const int OmitFirst8 = 19;
+
+ internal const int OmitFirst9 = 20;
+
+ internal static int GetOmitFirst(int type)
+ {
+ return type >= OmitFirst1 ? (type - OmitFirst1 + 1) : 0;
+ }
+
+ internal static int GetOmitLast(int type)
+ {
+ return type <= OmitLast9 ? (type - OmitLast1 + 1) : 0;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/sharpen.cfg b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/sharpen.cfg
new file mode 100644
index 000000000..b69cf4316
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/sharpen.cfg
@@ -0,0 +1,18 @@
+-pascalCase+
+-nativeTypeSystem
+-separateInterfaceConstants
+-maxColumns 240
+-copySharpenCs false
+-sharpenNamespace nonamespace
+-outputFolder build/generated
+
+-namespaceMapping java.io System.IO
+
+-typeMapping java.io.ByteArrayInputStream System.IO.MemoryStream
+-typeMapping java.io.ByteArrayOutputStream System.IO.MemoryStream
+-typeMapping java.io.InputStream System.IO.Stream
+
+-methodMapping java.io.ByteArrayOutputStream.toByteArray() ToArray
+-methodMapping java.io.InputStream.read() ReadByte
+-methodMapping org.brotli.dec.BrotliInputStream.read() ReadByte
+-methodMapping org.junit.Assert.assertArrayEquals NUnit.Framework.Assert.AreEqual
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/transpile.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/transpile.sh
new file mode 100644
index 000000000..3fefb8432
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/csharp/transpile.sh
@@ -0,0 +1,94 @@
+if ! which mvn >/dev/null; then
+ echo -e '\033[01;31mMaven is not installed / configured.\033[00m'
+ exit 1
+fi
+
+if ! which mono >/dev/null; then
+ echo -e '\033[01;31mMono platform is not installed / configured.\033[00m'
+ exit 1
+fi
+
+if ! which nuget >/dev/null; then
+ echo -e '\033[01;31mNuGet compiler is not installed / configured.\033[00m'
+ exit 1
+fi
+
+if ! which mcs >/dev/null; then
+ echo -e '\033[01;31mC# compiler is not installed / configured.\033[00m'
+ exit 1
+fi
+
+rm -rf build
+mkdir build
+cd build
+
+#-------------------------------------------------------------------------------
+
+echo -e '\033[01;33mFetching Sharpen sources.\033[00m'
+
+git clone https://github.com/stanislaw89/sharpen.git
+cd sharpen
+git checkout 4f609ed42862a1f9aab1be00374ff86534a5e6d6 || exit 1
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mCompiling Sharpen.\033[00m'
+
+mvn clean package -DskipTests
+mvn dependency:copy -Dartifact=junit:junit:4.12 -DoutputDirectory=..
+cd ..
+cp sharpen/target/sharpencore-0.0.1-SNAPSHOT-jar-with-dependencies.jar ./sharpen.jar
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mTranspiling.\033[00m'
+
+cd ..
+java -jar build/sharpen.jar ../java/org/brotli/dec/ -cp build/junit-4.12.jar @sharpen.cfg
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mPatching.\033[00m'
+
+# TODO: detect "dead" files, that are not generated by sharpen anymore.
+cp -r build/generated/* ./
+
+# Reflection does not work without Sharpen.cs
+rm org/brotli/dec/EnumTest.cs
+
+PATTERN='\/\/ \<\{\[INJECTED CODE\]\}\>'
+CODE=$(<org/brotli/dec/BrotliInputStream.cs)
+REPLACEMENT=$(<injected_code.txt)
+echo "${CODE//$PATTERN/$REPLACEMENT}" > org/brotli/dec/BrotliInputStream.cs
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mDowloading dependencies.\033[00m'
+
+cd build
+nuget install NUnit -Version 3.6.1
+nuget install NUnit.ConsoleRunner -Version 3.6.1
+cd ..
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mCompiling generated code.\033[00m'
+
+SOURCES=`find org/brotli -type file ! -path "*Test.cs"`
+TESTS_SOURCES=`find org/brotli -type file -path "*Test.cs"`
+
+mcs $SOURCES -target:library -out:build/brotlidec.dll
+mcs $SOURCES $TESTS_SOURCES -target:library -out:build/brotlidec_test.dll -r:build/NUnit.3.6.1/lib/net45/nunit.framework.dll
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mRunning tests.\033[00m'
+
+export MONO_PATH=$MONO_PATH:`pwd`/build/NUnit.3.6.1/lib/net45
+mono --debug build/NUnit.ConsoleRunner.3.6.1/tools/nunit3-console.exe build/brotlidec_test.dll
+
+#-------------------------------------------------------------------------------
+
+echo -e '\n\033[01;33mCleanup.\033[00m'
+rm TestResult.xml
+rm -rf build
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli-comparison-study-2015-09-22.pdf b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli-comparison-study-2015-09-22.pdf
new file mode 100644
index 000000000..040f179e2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli-comparison-study-2015-09-22.pdf
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli.1 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli.1
new file mode 100644
index 000000000..7242a3255
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/brotli.1
@@ -0,0 +1,132 @@
+.TH "BROTLI" "1" "February 2018" "brotli 1.0.0" "User commands"
+.SH "NAME"
+\fBbrotli\fR \- brotli, unbrotli \- compress or decompress files
+.SH SYNOPSIS
+.P
+\fBbrotli\fP [\fIOPTION|FILE\fR]\.\.\.
+.P
+\fBunbrotli\fP is equivalent to \fBbrotli \-\-decompress\fP
+.SH DESCRIPTION
+.P
+\fBbrotli\fP is a generic\-purpose lossless compression algorithm that compresses
+data using a combination of a modern variant of the \fBLZ77\fR algorithm, Huffman
+coding and 2\-nd order context modeling, with a compression ratio comparable to
+the best currently available general\-purpose compression methods\. It is similar
+in speed with deflate but offers more dense compression\.
+.P
+\fBbrotli\fP command line syntax similar to \fBgzip (1)\fP and \fBzstd (1)\fP\|\.
+Unlike \fBgzip (1)\fP, source files are preserved by default\. It is possible to
+remove them after processing by using the \fB\-\-rm\fP \fIoption\fR\|\.
+.P
+Arguments that look like "\fB\-\-name\fP" or "\fB\-\-name=value\fP" are \fIoptions\fR\|\. Every
+\fIoption\fR has a short form "\fB\-x\fP" or "\fB\-x value\fP"\. Multiple short form \fIoptions\fR
+could be coalesced:
+.RS 0
+.IP \(bu 2
+"\fB\-\-decompress \-\-stdout \-\-suffix=\.b\fP" works the same as
+.IP \(bu 2
+"\fB\-d \-s \-S \.b\fP" and
+.IP \(bu 2
+"\fB\-dsS \.b\fP"
+
+.RE
+.P
+\fBbrotli\fP has 3 operation modes:
+.RS 0
+.IP \(bu 2
+default mode is compression;
+.IP \(bu 2
+\fB\-\-decompress\fP option activates decompression mode;
+.IP \(bu 2
+\fB\-\-test\fP option switches to integrity test mode; this option is equivalent to
+"\fB\-\-decompress \-\-stdout\fP" except that the decompressed data is discarded
+instead of being written to standard output\.
+
+.RE
+.P
+Every non\-option argument is a \fIfile\fR entry\. If no \fIfiles\fR are given or \fIfile\fR
+is "\fB\-\fP", \fBbrotli\fP reads from standard input\. All arguments after "\fB\-\-\fP" are
+\fIfile\fR entries\.
+.P
+Unless \fB\-\-stdout\fP or \fB\-\-output\fP is specified, \fIfiles\fR are written to a new file
+whose name is derived from the source \fIfile\fR name:
+.RS 0
+.IP \(bu 2
+when compressing, a suffix is appended to the source filename to
+get the target filename
+.IP \(bu 2
+when decompressing, a suffix is removed from the source filename to
+get the target filename
+
+.RE
+.P
+Default suffix is \fB\|\.br\fP, but it could be specified with \fB\-\-suffix\fP option\.
+.P
+Conflicting or duplicate \fIoptions\fR are not allowed\.
+.SH OPTIONS
+.RS 0
+.IP \(bu 2
+\fB\-#\fP:
+ compression level (0\-9); bigger values cause denser, but slower compression
+.IP \(bu 2
+\fB\-c\fP, \fB\-\-stdout\fP:
+ write on standard output
+.IP \(bu 2
+\fB\-d\fP, \fB\-\-decompress\fP:
+ decompress mode
+.IP \(bu 2
+\fB\-f\fP, \fB\-\-force\fP:
+ force output file overwrite
+.IP \(bu 2
+\fB\-h\fP, \fB\-\-help\fP:
+ display this help and exit
+.IP \(bu 2
+\fB\-j\fP, \fB\-\-rm\fP:
+ remove source file(s); \fBgzip (1)\fP\-like behaviour
+.IP \(bu 2
+\fB\-k\fP, \fB\-\-keep\fP:
+ keep source file(s); \fBzstd (1)\fP\-like behaviour
+.IP \(bu 2
+\fB\-n\fP, \fB\-\-no\-copy\-stat\fP:
+ do not copy source file(s) attributes
+.IP \(bu 2
+\fB\-o FILE\fP, \fB\-\-output=FILE\fP
+ output file; valid only if there is a single input entry
+.IP \(bu 2
+\fB\-q NUM\fP, \fB\-\-quality=NUM\fP:
+ compression level (0\-11); bigger values cause denser, but slower compression
+.IP \(bu 2
+\fB\-t\fP, \fB\-\-test\fP:
+ test file integrity mode
+.IP \(bu 2
+\fB\-v\fP, \fB\-\-verbose\fP:
+ increase output verbosity
+.IP \(bu 2
+\fB\-w NUM\fP, \fB\-\-lgwin=NUM\fP:
+ set LZ77 window size (0, 10\-24) (default: 22); window size is
+ \fB(2**NUM \- 16)\fP; 0 lets compressor decide over the optimal value; bigger
+ windows size improve density; decoder might require up to window size
+ memory to operate
+.IP \(bu 2
+\fB\-S SUF\fP, \fB\-\-suffix=SUF\fP:
+ output file suffix (default: \fB\|\.br\fP)
+.IP \(bu 2
+\fB\-V\fP, \fB\-\-version\fP:
+ display version and exit
+.IP \(bu 2
+\fB\-Z\fP, \fB\-\-best\fP:
+ use best compression level (default); same as "\fB\-q 11\fP"
+
+.RE
+.SH SEE ALSO
+.P
+\fBbrotli\fP file format is defined in
+RFC 7932 \fIhttps://www\.ietf\.org/rfc/rfc7932\.txt\fR\|\.
+.P
+\fBbrotli\fP is open\-sourced under the
+MIT License \fIhttps://opensource\.org/licenses/MIT\fR\|\.
+.P
+Mailing list: https://groups\.google\.com/forum/#!forum/brotli
+.SH BUGS
+.P
+Report bugs at: https://github\.com/google/brotli/issues
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/decode.h.3 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/decode.h.3
new file mode 100644
index 000000000..7b8581cc2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/decode.h.3
@@ -0,0 +1,415 @@
+.TH "decode.h" 3 "Thu Feb 22 2018" "Brotli" \" -*- nroff -*-
+.ad l
+.nh
+.SH NAME
+decode.h \- API for Brotli decompression\&.
+
+.SH SYNOPSIS
+.br
+.PP
+.SS "Macros"
+
+.in +1c
+.ti -1c
+.RI "#define \fBBROTLI_DECODER_ERROR_CODES_LIST\fP(BROTLI_ERROR_CODE, SEPARATOR) "
+.br
+.RI "\fITemplate that evaluates items of \fBBrotliDecoderErrorCode\fP\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_LAST_ERROR_CODE\fP BROTLI_DECODER_ERROR_UNREACHABLE"
+.br
+.RI "\fIThe value of the last error code, negative integer\&. \fP"
+.in -1c
+.SS "Typedefs"
+
+.in +1c
+.ti -1c
+.RI "typedef enum \fBBrotliDecoderParameter\fP \fBBrotliDecoderParameter\fP"
+.br
+.RI "\fIOptions to be used with \fBBrotliDecoderSetParameter\fP\&. \fP"
+.ti -1c
+.RI "typedef struct BrotliDecoderStateStruct \fBBrotliDecoderState\fP"
+.br
+.RI "\fIOpaque structure that holds decoder state\&. \fP"
+.in -1c
+.SS "Enumerations"
+.SS "Functions"
+
+.in +1c
+.ti -1c
+.RI "\fBBrotliDecoderState\fP * \fBBrotliDecoderCreateInstance\fP (\fBbrotli_alloc_func\fP alloc_func, \fBbrotli_free_func\fP free_func, void *opaque)"
+.br
+.RI "\fICreates an instance of \fBBrotliDecoderState\fP and initializes it\&. \fP"
+.ti -1c
+.RI "\fBBrotliDecoderResult\fP \fBBrotliDecoderDecompress\fP (size_t encoded_size, const uint8_t encoded_buffer[encoded_size], size_t *decoded_size, uint8_t decoded_buffer[*decoded_size])"
+.br
+.RI "\fIPerforms one-shot memory-to-memory decompression\&. \fP"
+.ti -1c
+.RI "\fBBrotliDecoderResult\fP \fBBrotliDecoderDecompressStream\fP (\fBBrotliDecoderState\fP *state, size_t *available_in, const uint8_t **next_in, size_t *available_out, uint8_t **next_out, size_t *total_out)"
+.br
+.RI "\fIDecompresses the input stream to the output stream\&. \fP"
+.ti -1c
+.RI "void \fBBrotliDecoderDestroyInstance\fP (\fBBrotliDecoderState\fP *state)"
+.br
+.RI "\fIDeinitializes and frees \fBBrotliDecoderState\fP instance\&. \fP"
+.ti -1c
+.RI "const char * \fBBrotliDecoderErrorString\fP (\fBBrotliDecoderErrorCode\fP c)"
+.br
+.RI "\fIConverts error code to a c-string\&. \fP"
+.ti -1c
+.RI "\fBBrotliDecoderErrorCode\fP \fBBrotliDecoderGetErrorCode\fP (const \fBBrotliDecoderState\fP *state)"
+.br
+.RI "\fIAcquires a detailed error code\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliDecoderHasMoreOutput\fP (const \fBBrotliDecoderState\fP *state)"
+.br
+.RI "\fIChecks if decoder has more output\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliDecoderIsFinished\fP (const \fBBrotliDecoderState\fP *state)"
+.br
+.RI "\fIChecks if decoder instance reached the final state\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliDecoderIsUsed\fP (const \fBBrotliDecoderState\fP *state)"
+.br
+.RI "\fIChecks if instance has already consumed input\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliDecoderSetParameter\fP (\fBBrotliDecoderState\fP *state, \fBBrotliDecoderParameter\fP param, uint32_t value)"
+.br
+.RI "\fISets the specified parameter to the given decoder instance\&. \fP"
+.ti -1c
+.RI "const uint8_t * \fBBrotliDecoderTakeOutput\fP (\fBBrotliDecoderState\fP *state, size_t *size)"
+.br
+.RI "\fIAcquires pointer to internal output buffer\&. \fP"
+.ti -1c
+.RI "uint32_t \fBBrotliDecoderVersion\fP (void)"
+.br
+.RI "\fIGets a decoder library version\&. \fP"
+.in -1c
+.SH "Detailed Description"
+.PP
+API for Brotli decompression\&.
+
+
+.SH "Macro Definition Documentation"
+.PP
+.SS "#define BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR)"
+
+.PP
+Template that evaluates items of \fBBrotliDecoderErrorCode\fP\&. Example:
+.PP
+.nf
+// Log Brotli error code\&.
+switch (brotliDecoderErrorCode) {
+#define CASE_(PREFIX, NAME, CODE) \
+ case BROTLI_DECODER ## PREFIX ## NAME: \
+ LOG(INFO) << "error code:" << #NAME; \
+ break;
+#define NEWLINE_
+BROTLI_DECODER_ERROR_CODES_LIST(CASE_, NEWLINE_)
+#undef CASE_
+#undef NEWLINE_
+ default: LOG(FATAL) << "unknown brotli error code";
+}
+
+.fi
+.PP
+
+.SS "#define BROTLI_LAST_ERROR_CODE BROTLI_DECODER_ERROR_UNREACHABLE"
+
+.PP
+The value of the last error code, negative integer\&. All other error code values are in the range from \fBBROTLI_LAST_ERROR_CODE\fP to \fC-1\fP\&. There are also 4 other possible non-error codes \fC0\fP \&.\&. \fC3\fP in \fBBrotliDecoderErrorCode\fP enumeration\&.
+.SH "Typedef Documentation"
+.PP
+.SS "typedef enum \fBBrotliDecoderParameter\fP \fBBrotliDecoderParameter\fP"
+
+.PP
+Options to be used with \fBBrotliDecoderSetParameter\fP\&.
+.SS "typedef struct BrotliDecoderStateStruct \fBBrotliDecoderState\fP"
+
+.PP
+Opaque structure that holds decoder state\&. Allocated and initialized with \fBBrotliDecoderCreateInstance\fP\&. Cleaned up and deallocated with \fBBrotliDecoderDestroyInstance\fP\&.
+.SH "Enumeration Type Documentation"
+.PP
+.SS "enum \fBBrotliDecoderErrorCode\fP"
+
+.PP
+Error code for detailed logging / production debugging\&. See \fBBrotliDecoderGetErrorCode\fP and \fBBROTLI_LAST_ERROR_CODE\fP\&.
+.SS "enum \fBBrotliDecoderParameter\fP"
+
+.PP
+Options to be used with \fBBrotliDecoderSetParameter\fP\&.
+.PP
+\fBEnumerator\fP
+.in +1c
+.TP
+\fB\fIBROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION \fP\fP
+Disable 'canny' ring buffer allocation strategy\&. Ring buffer is allocated according to window size, despite the real size of the content\&.
+.TP
+\fB\fIBROTLI_DECODER_PARAM_LARGE_WINDOW \fP\fP
+Flag that determines if 'Large Window Brotli' is used\&.
+.SS "enum \fBBrotliDecoderResult\fP"
+
+.PP
+Result type for \fBBrotliDecoderDecompress\fP and \fBBrotliDecoderDecompressStream\fP functions\&.
+.PP
+\fBEnumerator\fP
+.in +1c
+.TP
+\fB\fIBROTLI_DECODER_RESULT_ERROR \fP\fP
+Decoding error, e\&.g\&. corrupted input or memory allocation problem\&.
+.TP
+\fB\fIBROTLI_DECODER_RESULT_SUCCESS \fP\fP
+Decoding successfully completed\&.
+.TP
+\fB\fIBROTLI_DECODER_RESULT_NEEDS_MORE_INPUT \fP\fP
+Partially done; should be called again with more input\&.
+.TP
+\fB\fIBROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT \fP\fP
+Partially done; should be called again with more output\&.
+.SH "Function Documentation"
+.PP
+.SS "\fBBrotliDecoderState\fP* BrotliDecoderCreateInstance (\fBbrotli_alloc_func\fP alloc_func, \fBbrotli_free_func\fP free_func, void * opaque)"
+
+.PP
+Creates an instance of \fBBrotliDecoderState\fP and initializes it\&. The instance can be used once for decoding and should then be destroyed with \fBBrotliDecoderDestroyInstance\fP, it cannot be reused for a new decoding session\&.
+.PP
+\fCalloc_func\fP and \fCfree_func\fP \fBMUST\fP be both zero or both non-zero\&. In the case they are both zero, default memory allocators are used\&. \fCopaque\fP is passed to \fCalloc_func\fP and \fCfree_func\fP when they are called\&. \fCfree_func\fP has to return without doing anything when asked to free a NULL pointer\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIalloc_func\fP custom memory allocation function
+.br
+\fIfree_func\fP custom memory free function
+.br
+\fIopaque\fP custom memory manager handle
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fC0\fP if instance can not be allocated or initialized
+.PP
+pointer to initialized \fBBrotliDecoderState\fP otherwise
+.RE
+.PP
+
+.SS "\fBBrotliDecoderResult\fP BrotliDecoderDecompress (size_t encoded_size, const uint8_t encoded_buffer[encoded_size], size_t * decoded_size, uint8_t decoded_buffer[*decoded_size])"
+
+.PP
+Performs one-shot memory-to-memory decompression\&. Decompresses the data in \fCencoded_buffer\fP into \fCdecoded_buffer\fP, and sets \fC*decoded_size\fP to the decompressed length\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIencoded_size\fP size of \fCencoded_buffer\fP
+.br
+\fIencoded_buffer\fP compressed data buffer with at least \fCencoded_size\fP addressable bytes
+.br
+\fIdecoded_size\fP \fBin:\fP size of \fCdecoded_buffer\fP;
+.br
+ \fBout:\fP length of decompressed data written to \fCdecoded_buffer\fP
+.br
+\fIdecoded_buffer\fP decompressed data destination buffer
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_DECODER_RESULT_ERROR\fP if input is corrupted, memory allocation failed, or \fCdecoded_buffer\fP is not large enough;
+.PP
+\fBBROTLI_DECODER_RESULT_SUCCESS\fP otherwise
+.RE
+.PP
+
+.SS "\fBBrotliDecoderResult\fP BrotliDecoderDecompressStream (\fBBrotliDecoderState\fP * state, size_t * available_in, const uint8_t ** next_in, size_t * available_out, uint8_t ** next_out, size_t * total_out)"
+
+.PP
+Decompresses the input stream to the output stream\&. The values \fC*available_in\fP and \fC*available_out\fP must specify the number of bytes addressable at \fC*next_in\fP and \fC*next_out\fP respectively\&. When \fC*available_out\fP is \fC0\fP, \fCnext_out\fP is allowed to be \fCNULL\fP\&.
+.PP
+After each call, \fC*available_in\fP will be decremented by the amount of input bytes consumed, and the \fC*next_in\fP pointer will be incremented by that amount\&. Similarly, \fC*available_out\fP will be decremented by the amount of output bytes written, and the \fC*next_out\fP pointer will be incremented by that amount\&.
+.PP
+\fCtotal_out\fP, if it is not a null-pointer, will be set to the number of bytes decompressed since the last \fCstate\fP initialization\&.
+.PP
+\fBNote:\fP
+.RS 4
+Input is never overconsumed, so \fCnext_in\fP and \fCavailable_in\fP could be passed to the next consumer after decoding is complete\&.
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.br
+\fIavailable_in\fP \fBin:\fP amount of available input;
+.br
+ \fBout:\fP amount of unused input
+.br
+\fInext_in\fP pointer to the next compressed byte
+.br
+\fIavailable_out\fP \fBin:\fP length of output buffer;
+.br
+ \fBout:\fP remaining size of output buffer
+.br
+\fInext_out\fP output buffer cursor; can be \fCNULL\fP if \fCavailable_out\fP is \fC0\fP
+.br
+\fItotal_out\fP number of bytes decompressed so far; can be \fCNULL\fP
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_DECODER_RESULT_ERROR\fP if input is corrupted, memory allocation failed, arguments were invalid, etc\&.; use \fBBrotliDecoderGetErrorCode\fP to get detailed error code
+.PP
+\fBBROTLI_DECODER_RESULT_NEEDS_MORE_INPUT\fP decoding is blocked until more input data is provided
+.PP
+\fBBROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT\fP decoding is blocked until more output space is provided
+.PP
+\fBBROTLI_DECODER_RESULT_SUCCESS\fP decoding is finished, no more input might be consumed and no more output will be produced
+.RE
+.PP
+
+.SS "void BrotliDecoderDestroyInstance (\fBBrotliDecoderState\fP * state)"
+
+.PP
+Deinitializes and frees \fBBrotliDecoderState\fP instance\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance to be cleaned up and deallocated
+.RE
+.PP
+
+.SS "\fBBrotliDecoderErrorCode\fP BrotliDecoderGetErrorCode (const \fBBrotliDecoderState\fP * state)"
+
+.PP
+Acquires a detailed error code\&. Should be used only after \fBBrotliDecoderDecompressStream\fP returns \fBBROTLI_DECODER_RESULT_ERROR\fP\&.
+.PP
+See also \fBBrotliDecoderErrorString\fP
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+last saved error code
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliDecoderHasMoreOutput (const \fBBrotliDecoderState\fP * state)"
+
+.PP
+Checks if decoder has more output\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_TRUE\fP, if decoder has some unconsumed output
+.PP
+\fBBROTLI_FALSE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliDecoderIsFinished (const \fBBrotliDecoderState\fP * state)"
+
+.PP
+Checks if decoder instance reached the final state\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_TRUE\fP if decoder is in a state where it reached the end of the input and produced all of the output
+.PP
+\fBBROTLI_FALSE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliDecoderIsUsed (const \fBBrotliDecoderState\fP * state)"
+
+.PP
+Checks if instance has already consumed input\&. Instance that returns \fBBROTLI_FALSE\fP is considered 'fresh' and could be reused\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_TRUE\fP if decoder has already used some input bytes
+.PP
+\fBBROTLI_FALSE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliDecoderSetParameter (\fBBrotliDecoderState\fP * state, \fBBrotliDecoderParameter\fP param, uint32_t value)"
+
+.PP
+Sets the specified parameter to the given decoder instance\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.br
+\fIparam\fP parameter to set
+.br
+\fIvalue\fP new parameter value
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_FALSE\fP if parameter is unrecognized, or value is invalid
+.PP
+\fBBROTLI_TRUE\fP if value is accepted
+.RE
+.PP
+
+.SS "const uint8_t* BrotliDecoderTakeOutput (\fBBrotliDecoderState\fP * state, size_t * size)"
+
+.PP
+Acquires pointer to internal output buffer\&. This method is used to make language bindings easier and more efficient:
+.IP "1." 4
+push data to \fBBrotliDecoderDecompressStream\fP, until \fBBROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT\fP is reported
+.IP "2." 4
+use \fBBrotliDecoderTakeOutput\fP to peek bytes and copy to language-specific entity
+.PP
+.PP
+Also this could be useful if there is an output stream that is able to consume all the provided data (e\&.g\&. when data is saved to file system)\&.
+.PP
+\fBAttention:\fP
+.RS 4
+After every call to \fBBrotliDecoderTakeOutput\fP \fC*size\fP bytes of output are considered consumed for all consecutive calls to the instance methods; returned pointer becomes invalidated as well\&.
+.RE
+.PP
+\fBNote:\fP
+.RS 4
+Decoder output is not guaranteed to be contiguous\&. This means that after the size-unrestricted call to \fBBrotliDecoderTakeOutput\fP, immediate next call to \fBBrotliDecoderTakeOutput\fP may return more data\&.
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance
+.br
+\fIsize\fP \fBin:\fP number of bytes caller is ready to take, \fC0\fP if any amount could be handled;
+.br
+ \fBout:\fP amount of data pointed by returned pointer and considered consumed;
+.br
+ out value is never greater than in value, unless it is \fC0\fP
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+pointer to output data
+.RE
+.PP
+
+.SS "uint32_t BrotliDecoderVersion (void)"
+
+.PP
+Gets a decoder library version\&. Look at BROTLI_VERSION for more information\&.
+.SH "Author"
+.PP
+Generated automatically by Doxygen for Brotli from the source code\&.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/encode.h.3 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/encode.h.3
new file mode 100644
index 000000000..0cab81668
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/encode.h.3
@@ -0,0 +1,586 @@
+.TH "encode.h" 3 "Thu Feb 22 2018" "Brotli" \" -*- nroff -*-
+.ad l
+.nh
+.SH NAME
+encode.h \- API for Brotli compression\&.
+
+.SH SYNOPSIS
+.br
+.PP
+.SS "Macros"
+
+.in +1c
+.ti -1c
+.RI "#define \fBBROTLI_DEFAULT_MODE\fP \fBBROTLI_MODE_GENERIC\fP"
+.br
+.RI "\fIDefault value for \fBBROTLI_PARAM_MODE\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_DEFAULT_QUALITY\fP 11"
+.br
+.RI "\fIDefault value for \fBBROTLI_PARAM_QUALITY\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_DEFAULT_WINDOW\fP 22"
+.br
+.RI "\fIDefault value for \fBBROTLI_PARAM_LGWIN\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_LARGE_MAX_WINDOW_BITS\fP 30"
+.br
+.RI "\fIMaximal value for \fBBROTLI_PARAM_LGWIN\fP parameter in 'Large Window Brotli' (32-bit)\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MAX_INPUT_BLOCK_BITS\fP 24"
+.br
+.RI "\fIMaximal value for \fBBROTLI_PARAM_LGBLOCK\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MAX_QUALITY\fP 11"
+.br
+.RI "\fIMaximal value for \fBBROTLI_PARAM_QUALITY\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MAX_WINDOW_BITS\fP 24"
+.br
+.RI "\fIMaximal value for \fBBROTLI_PARAM_LGWIN\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MIN_INPUT_BLOCK_BITS\fP 16"
+.br
+.RI "\fIMinimal value for \fBBROTLI_PARAM_LGBLOCK\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MIN_QUALITY\fP 0"
+.br
+.RI "\fIMinimal value for \fBBROTLI_PARAM_QUALITY\fP parameter\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_MIN_WINDOW_BITS\fP 10"
+.br
+.RI "\fIMinimal value for \fBBROTLI_PARAM_LGWIN\fP parameter\&. \fP"
+.in -1c
+.SS "Typedefs"
+
+.in +1c
+.ti -1c
+.RI "typedef enum \fBBrotliEncoderMode\fP \fBBrotliEncoderMode\fP"
+.br
+.RI "\fIOptions for \fBBROTLI_PARAM_MODE\fP parameter\&. \fP"
+.ti -1c
+.RI "typedef enum \fBBrotliEncoderOperation\fP \fBBrotliEncoderOperation\fP"
+.br
+.RI "\fIOperations that can be performed by streaming encoder\&. \fP"
+.ti -1c
+.RI "typedef enum \fBBrotliEncoderParameter\fP \fBBrotliEncoderParameter\fP"
+.br
+.RI "\fIOptions to be used with \fBBrotliEncoderSetParameter\fP\&. \fP"
+.ti -1c
+.RI "typedef struct BrotliEncoderStateStruct \fBBrotliEncoderState\fP"
+.br
+.RI "\fIOpaque structure that holds encoder state\&. \fP"
+.in -1c
+.SS "Enumerations"
+.SS "Functions"
+
+.in +1c
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliEncoderCompress\fP (int quality, int lgwin, \fBBrotliEncoderMode\fP mode, size_t input_size, const uint8_t input_buffer[input_size], size_t *encoded_size, uint8_t encoded_buffer[*encoded_size])"
+.br
+.RI "\fIPerforms one-shot memory-to-memory compression\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliEncoderCompressStream\fP (\fBBrotliEncoderState\fP *state, \fBBrotliEncoderOperation\fP op, size_t *available_in, const uint8_t **next_in, size_t *available_out, uint8_t **next_out, size_t *total_out)"
+.br
+.RI "\fICompresses input stream to output stream\&. \fP"
+.ti -1c
+.RI "\fBBrotliEncoderState\fP * \fBBrotliEncoderCreateInstance\fP (\fBbrotli_alloc_func\fP alloc_func, \fBbrotli_free_func\fP free_func, void *opaque)"
+.br
+.RI "\fICreates an instance of \fBBrotliEncoderState\fP and initializes it\&. \fP"
+.ti -1c
+.RI "void \fBBrotliEncoderDestroyInstance\fP (\fBBrotliEncoderState\fP *state)"
+.br
+.RI "\fIDeinitializes and frees \fBBrotliEncoderState\fP instance\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliEncoderHasMoreOutput\fP (\fBBrotliEncoderState\fP *state)"
+.br
+.RI "\fIChecks if encoder has more output\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliEncoderIsFinished\fP (\fBBrotliEncoderState\fP *state)"
+.br
+.RI "\fIChecks if encoder instance reached the final state\&. \fP"
+.ti -1c
+.RI "size_t \fBBrotliEncoderMaxCompressedSize\fP (size_t input_size)"
+.br
+.RI "\fICalculates the output size bound for the given \fCinput_size\fP\&. \fP"
+.ti -1c
+.RI "\fBBROTLI_BOOL\fP \fBBrotliEncoderSetParameter\fP (\fBBrotliEncoderState\fP *state, \fBBrotliEncoderParameter\fP param, uint32_t value)"
+.br
+.RI "\fISets the specified parameter to the given encoder instance\&. \fP"
+.ti -1c
+.RI "const uint8_t * \fBBrotliEncoderTakeOutput\fP (\fBBrotliEncoderState\fP *state, size_t *size)"
+.br
+.RI "\fIAcquires pointer to internal output buffer\&. \fP"
+.ti -1c
+.RI "uint32_t \fBBrotliEncoderVersion\fP (void)"
+.br
+.RI "\fIGets an encoder library version\&. \fP"
+.in -1c
+.SH "Detailed Description"
+.PP
+API for Brotli compression\&.
+
+
+.SH "Macro Definition Documentation"
+.PP
+.SS "#define BROTLI_DEFAULT_MODE \fBBROTLI_MODE_GENERIC\fP"
+
+.PP
+Default value for \fBBROTLI_PARAM_MODE\fP parameter\&.
+.SS "#define BROTLI_DEFAULT_QUALITY 11"
+
+.PP
+Default value for \fBBROTLI_PARAM_QUALITY\fP parameter\&.
+.SS "#define BROTLI_DEFAULT_WINDOW 22"
+
+.PP
+Default value for \fBBROTLI_PARAM_LGWIN\fP parameter\&.
+.SS "#define BROTLI_MAX_INPUT_BLOCK_BITS 24"
+
+.PP
+Maximal value for \fBBROTLI_PARAM_LGBLOCK\fP parameter\&.
+.SS "#define BROTLI_MAX_QUALITY 11"
+
+.PP
+Maximal value for \fBBROTLI_PARAM_QUALITY\fP parameter\&.
+.SS "#define BROTLI_MAX_WINDOW_BITS 24"
+
+.PP
+Maximal value for \fBBROTLI_PARAM_LGWIN\fP parameter\&.
+.PP
+\fBNote:\fP
+.RS 4
+equal to \fCBROTLI_MAX_DISTANCE_BITS\fP constant\&.
+.RE
+.PP
+
+.SS "#define BROTLI_MIN_INPUT_BLOCK_BITS 16"
+
+.PP
+Minimal value for \fBBROTLI_PARAM_LGBLOCK\fP parameter\&.
+.SS "#define BROTLI_MIN_QUALITY 0"
+
+.PP
+Minimal value for \fBBROTLI_PARAM_QUALITY\fP parameter\&.
+.SS "#define BROTLI_MIN_WINDOW_BITS 10"
+
+.PP
+Minimal value for \fBBROTLI_PARAM_LGWIN\fP parameter\&.
+.SH "Typedef Documentation"
+.PP
+.SS "typedef enum \fBBrotliEncoderMode\fP \fBBrotliEncoderMode\fP"
+
+.PP
+Options for \fBBROTLI_PARAM_MODE\fP parameter\&.
+.SS "typedef enum \fBBrotliEncoderOperation\fP \fBBrotliEncoderOperation\fP"
+
+.PP
+Operations that can be performed by streaming encoder\&.
+.SS "typedef enum \fBBrotliEncoderParameter\fP \fBBrotliEncoderParameter\fP"
+
+.PP
+Options to be used with \fBBrotliEncoderSetParameter\fP\&.
+.SS "typedef struct BrotliEncoderStateStruct \fBBrotliEncoderState\fP"
+
+.PP
+Opaque structure that holds encoder state\&. Allocated and initialized with \fBBrotliEncoderCreateInstance\fP\&. Cleaned up and deallocated with \fBBrotliEncoderDestroyInstance\fP\&.
+.SH "Enumeration Type Documentation"
+.PP
+.SS "enum \fBBrotliEncoderMode\fP"
+
+.PP
+Options for \fBBROTLI_PARAM_MODE\fP parameter\&.
+.PP
+\fBEnumerator\fP
+.in +1c
+.TP
+\fB\fIBROTLI_MODE_GENERIC \fP\fP
+Default compression mode\&. In this mode compressor does not know anything in advance about the properties of the input\&.
+.TP
+\fB\fIBROTLI_MODE_TEXT \fP\fP
+Compression mode for UTF-8 formatted text input\&.
+.TP
+\fB\fIBROTLI_MODE_FONT \fP\fP
+Compression mode used in WOFF 2\&.0\&.
+.SS "enum \fBBrotliEncoderOperation\fP"
+
+.PP
+Operations that can be performed by streaming encoder\&.
+.PP
+\fBEnumerator\fP
+.in +1c
+.TP
+\fB\fIBROTLI_OPERATION_PROCESS \fP\fP
+Process input\&. Encoder may postpone producing output, until it has processed enough input\&.
+.TP
+\fB\fIBROTLI_OPERATION_FLUSH \fP\fP
+Produce output for all processed input\&. Actual flush is performed when input stream is depleted and there is enough space in output stream\&. This means that client should repeat \fBBROTLI_OPERATION_FLUSH\fP operation until \fCavailable_in\fP becomes \fC0\fP, and \fBBrotliEncoderHasMoreOutput\fP returns \fBBROTLI_FALSE\fP\&. If output is acquired via \fBBrotliEncoderTakeOutput\fP, then operation should be repeated after output buffer is drained\&.
+.PP
+\fBWarning:\fP
+.RS 4
+Until flush is complete, client \fBSHOULD\fP \fBNOT\fP swap, reduce or extend input stream\&.
+.RE
+.PP
+When flush is complete, output data will be sufficient for decoder to reproduce all the given input\&.
+.TP
+\fB\fIBROTLI_OPERATION_FINISH \fP\fP
+Finalize the stream\&. Actual finalization is performed when input stream is depleted and there is enough space in output stream\&. This means that client should repeat \fBBROTLI_OPERATION_FINISH\fP operation until \fCavailable_in\fP becomes \fC0\fP, and \fBBrotliEncoderHasMoreOutput\fP returns \fBBROTLI_FALSE\fP\&. If output is acquired via \fBBrotliEncoderTakeOutput\fP, then operation should be repeated after output buffer is drained\&.
+.PP
+\fBWarning:\fP
+.RS 4
+Until finalization is complete, client \fBSHOULD\fP \fBNOT\fP swap, reduce or extend input stream\&.
+.RE
+.PP
+Helper function \fBBrotliEncoderIsFinished\fP checks if stream is finalized and output fully dumped\&.
+.PP
+Adding more input data to finalized stream is impossible\&.
+.TP
+\fB\fIBROTLI_OPERATION_EMIT_METADATA \fP\fP
+Emit metadata block to stream\&. Metadata is opaque to Brotli: neither encoder, nor decoder processes this data or relies on it\&. It may be used to pass some extra information from encoder client to decoder client without interfering with main data stream\&.
+.PP
+\fBNote:\fP
+.RS 4
+Encoder may emit empty metadata blocks internally, to pad encoded stream to byte boundary\&.
+.RE
+.PP
+\fBWarning:\fP
+.RS 4
+Until emitting metadata is complete client \fBSHOULD\fP \fBNOT\fP swap, reduce or extend input stream\&.
+.PP
+The whole content of input buffer is considered to be the content of metadata block\&. Do \fBNOT\fP \fIappend\fP metadata to input stream, before it is depleted with other operations\&.
+.RE
+.PP
+Stream is soft-flushed before metadata block is emitted\&. Metadata block \fBMUST\fP be no longer than than 16MiB\&.
+.SS "enum \fBBrotliEncoderParameter\fP"
+
+.PP
+Options to be used with \fBBrotliEncoderSetParameter\fP\&.
+.PP
+\fBEnumerator\fP
+.in +1c
+.TP
+\fB\fIBROTLI_PARAM_MODE \fP\fP
+Tune encoder for specific input\&. \fBBrotliEncoderMode\fP enumerates all available values\&.
+.TP
+\fB\fIBROTLI_PARAM_QUALITY \fP\fP
+The main compression speed-density lever\&. The higher the quality, the slower the compression\&. Range is from \fBBROTLI_MIN_QUALITY\fP to \fBBROTLI_MAX_QUALITY\fP\&.
+.TP
+\fB\fIBROTLI_PARAM_LGWIN \fP\fP
+Recommended sliding LZ77 window size\&. Encoder may reduce this value, e\&.g\&. if input is much smaller than window size\&.
+.PP
+Window size is \fC(1 << value) - 16\fP\&.
+.PP
+Range is from \fBBROTLI_MIN_WINDOW_BITS\fP to \fBBROTLI_MAX_WINDOW_BITS\fP\&.
+.TP
+\fB\fIBROTLI_PARAM_LGBLOCK \fP\fP
+Recommended input block size\&. Encoder may reduce this value, e\&.g\&. if input is much smaller than input block size\&.
+.PP
+Range is from \fBBROTLI_MIN_INPUT_BLOCK_BITS\fP to \fBBROTLI_MAX_INPUT_BLOCK_BITS\fP\&.
+.PP
+\fBNote:\fP
+.RS 4
+Bigger input block size allows better compression, but consumes more memory\&.
+.br
+ The rough formula of memory used for temporary input storage is \fC3 << lgBlock\fP\&.
+.RE
+.PP
+
+.TP
+\fB\fIBROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING \fP\fP
+Flag that affects usage of 'literal context modeling' format feature\&. This flag is a 'decoding-speed vs compression ratio' trade-off\&.
+.TP
+\fB\fIBROTLI_PARAM_SIZE_HINT \fP\fP
+Estimated total input size for all \fBBrotliEncoderCompressStream\fP calls\&. The default value is 0, which means that the total input size is unknown\&.
+.TP
+\fB\fIBROTLI_PARAM_LARGE_WINDOW \fP\fP
+Flag that determines if 'Large Window Brotli' is used\&.
+.TP
+\fB\fIBROTLI_PARAM_NPOSTFIX \fP\fP
+Recommended number of postfix bits (NPOSTFIX)\&. Encoder may change this value\&.
+.PP
+Range is from 0 to \fBBROTLI_MAX_NPOSTFIX\fP\&.
+.TP
+\fB\fIBROTLI_PARAM_NDIRECT \fP\fP
+Recommended number of direct distance codes (NDIRECT)\&. Encoder may change this value\&.
+.PP
+Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX)\&.
+.TP
+\fB\fIBROTLI_PARAM_STREAM_OFFSET \fP\fP
+Number of bytes of input stream already processed by a different instance\&.
+.PP
+\fBNote:\fP
+.RS 4
+It is important to configure all the encoder instances with same parameters (except this one) in order to allow all the encoded parts obey the same restrictions implied by header\&.
+.RE
+.PP
+If offset is not 0, then stream header is omitted\&. In any case output start is byte aligned, so for proper streams stitching 'predecessor' stream must be flushed\&.
+.PP
+Range is not artificially limited, but all the values greater or equal to maximal window size have the same effect\&. Values greater than 2**30 are not allowed\&.
+.SH "Function Documentation"
+.PP
+.SS "\fBBROTLI_BOOL\fP BrotliEncoderCompress (int quality, int lgwin, \fBBrotliEncoderMode\fP mode, size_t input_size, const uint8_t input_buffer[input_size], size_t * encoded_size, uint8_t encoded_buffer[*encoded_size])"
+
+.PP
+Performs one-shot memory-to-memory compression\&. Compresses the data in \fCinput_buffer\fP into \fCencoded_buffer\fP, and sets \fC*encoded_size\fP to the compressed length\&.
+.PP
+\fBNote:\fP
+.RS 4
+If \fBBrotliEncoderMaxCompressedSize\fP(\fCinput_size\fP) returns non-zero value, then output is guaranteed to be no longer than that\&.
+.PP
+If \fClgwin\fP is greater than \fBBROTLI_MAX_WINDOW_BITS\fP then resulting stream might be incompatible with RFC 7932; to decode such streams, decoder should be configured with \fBBROTLI_DECODER_PARAM_LARGE_WINDOW\fP = \fC1\fP
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIquality\fP quality parameter value, e\&.g\&. \fBBROTLI_DEFAULT_QUALITY\fP
+.br
+\fIlgwin\fP lgwin parameter value, e\&.g\&. \fBBROTLI_DEFAULT_WINDOW\fP
+.br
+\fImode\fP mode parameter value, e\&.g\&. \fBBROTLI_DEFAULT_MODE\fP
+.br
+\fIinput_size\fP size of \fCinput_buffer\fP
+.br
+\fIinput_buffer\fP input data buffer with at least \fCinput_size\fP addressable bytes
+.br
+\fIencoded_size\fP \fBin:\fP size of \fCencoded_buffer\fP;
+.br
+ \fBout:\fP length of compressed data written to \fCencoded_buffer\fP, or \fC0\fP if compression fails
+.br
+\fIencoded_buffer\fP compressed data destination buffer
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_FALSE\fP in case of compression error
+.PP
+\fBBROTLI_FALSE\fP if output buffer is too small
+.PP
+\fBBROTLI_TRUE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliEncoderCompressStream (\fBBrotliEncoderState\fP * state, \fBBrotliEncoderOperation\fP op, size_t * available_in, const uint8_t ** next_in, size_t * available_out, uint8_t ** next_out, size_t * total_out)"
+
+.PP
+Compresses input stream to output stream\&. The values \fC*available_in\fP and \fC*available_out\fP must specify the number of bytes addressable at \fC*next_in\fP and \fC*next_out\fP respectively\&. When \fC*available_out\fP is \fC0\fP, \fCnext_out\fP is allowed to be \fCNULL\fP\&.
+.PP
+After each call, \fC*available_in\fP will be decremented by the amount of input bytes consumed, and the \fC*next_in\fP pointer will be incremented by that amount\&. Similarly, \fC*available_out\fP will be decremented by the amount of output bytes written, and the \fC*next_out\fP pointer will be incremented by that amount\&.
+.PP
+\fCtotal_out\fP, if it is not a null-pointer, will be set to the number of bytes compressed since the last \fCstate\fP initialization\&.
+.PP
+Internally workflow consists of 3 tasks:
+.IP "1." 4
+(optionally) copy input data to internal buffer
+.IP "2." 4
+actually compress data and (optionally) store it to internal buffer
+.IP "3." 4
+(optionally) copy compressed bytes from internal buffer to output stream
+.PP
+.PP
+Whenever all 3 tasks can't move forward anymore, or error occurs, this method returns the control flow to caller\&.
+.PP
+\fCop\fP is used to perform flush, finish the stream, or inject metadata block\&. See \fBBrotliEncoderOperation\fP for more information\&.
+.PP
+Flushing the stream means forcing encoding of all input passed to encoder and completing the current output block, so it could be fully decoded by stream decoder\&. To perform flush set \fCop\fP to \fBBROTLI_OPERATION_FLUSH\fP\&. Under some circumstances (e\&.g\&. lack of output stream capacity) this operation would require several calls to \fBBrotliEncoderCompressStream\fP\&. The method must be called again until both input stream is depleted and encoder has no more output (see \fBBrotliEncoderHasMoreOutput\fP) after the method is called\&.
+.PP
+Finishing the stream means encoding of all input passed to encoder and adding specific 'final' marks, so stream decoder could determine that stream is complete\&. To perform finish set \fCop\fP to \fBBROTLI_OPERATION_FINISH\fP\&. Under some circumstances (e\&.g\&. lack of output stream capacity) this operation would require several calls to \fBBrotliEncoderCompressStream\fP\&. The method must be called again until both input stream is depleted and encoder has no more output (see \fBBrotliEncoderHasMoreOutput\fP) after the method is called\&.
+.PP
+\fBWarning:\fP
+.RS 4
+When flushing and finishing, \fCop\fP should not change until operation is complete; input stream should not be swapped, reduced or extended as well\&.
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP encoder instance
+.br
+\fIop\fP requested operation
+.br
+\fIavailable_in\fP \fBin:\fP amount of available input;
+.br
+ \fBout:\fP amount of unused input
+.br
+\fInext_in\fP pointer to the next input byte
+.br
+\fIavailable_out\fP \fBin:\fP length of output buffer;
+.br
+ \fBout:\fP remaining size of output buffer
+.br
+\fInext_out\fP compressed output buffer cursor; can be \fCNULL\fP if \fCavailable_out\fP is \fC0\fP
+.br
+\fItotal_out\fP number of bytes produced so far; can be \fCNULL\fP
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_FALSE\fP if there was an error
+.PP
+\fBBROTLI_TRUE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBrotliEncoderState\fP* BrotliEncoderCreateInstance (\fBbrotli_alloc_func\fP alloc_func, \fBbrotli_free_func\fP free_func, void * opaque)"
+
+.PP
+Creates an instance of \fBBrotliEncoderState\fP and initializes it\&. \fCalloc_func\fP and \fCfree_func\fP \fBMUST\fP be both zero or both non-zero\&. In the case they are both zero, default memory allocators are used\&. \fCopaque\fP is passed to \fCalloc_func\fP and \fCfree_func\fP when they are called\&. \fCfree_func\fP has to return without doing anything when asked to free a NULL pointer\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIalloc_func\fP custom memory allocation function
+.br
+\fIfree_func\fP custom memory free function
+.br
+\fIopaque\fP custom memory manager handle
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fC0\fP if instance can not be allocated or initialized
+.PP
+pointer to initialized \fBBrotliEncoderState\fP otherwise
+.RE
+.PP
+
+.SS "void BrotliEncoderDestroyInstance (\fBBrotliEncoderState\fP * state)"
+
+.PP
+Deinitializes and frees \fBBrotliEncoderState\fP instance\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance to be cleaned up and deallocated
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliEncoderHasMoreOutput (\fBBrotliEncoderState\fP * state)"
+
+.PP
+Checks if encoder has more output\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP encoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_TRUE\fP, if encoder has some unconsumed output
+.PP
+\fBBROTLI_FALSE\fP otherwise
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliEncoderIsFinished (\fBBrotliEncoderState\fP * state)"
+
+.PP
+Checks if encoder instance reached the final state\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP encoder instance
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_TRUE\fP if encoder is in a state where it reached the end of the input and produced all of the output
+.PP
+\fBBROTLI_FALSE\fP otherwise
+.RE
+.PP
+
+.SS "size_t BrotliEncoderMaxCompressedSize (size_t input_size)"
+
+.PP
+Calculates the output size bound for the given \fCinput_size\fP\&.
+.PP
+\fBWarning:\fP
+.RS 4
+Result is only valid if quality is at least \fC2\fP and, in case \fBBrotliEncoderCompressStream\fP was used, no flushes (\fBBROTLI_OPERATION_FLUSH\fP) were performed\&.
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIinput_size\fP size of projected input
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fC0\fP if result does not fit \fCsize_t\fP
+.RE
+.PP
+
+.SS "\fBBROTLI_BOOL\fP BrotliEncoderSetParameter (\fBBrotliEncoderState\fP * state, \fBBrotliEncoderParameter\fP param, uint32_t value)"
+
+.PP
+Sets the specified parameter to the given encoder instance\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP encoder instance
+.br
+\fIparam\fP parameter to set
+.br
+\fIvalue\fP new parameter value
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fBBROTLI_FALSE\fP if parameter is unrecognized, or value is invalid
+.PP
+\fBBROTLI_FALSE\fP if value of parameter can not be changed at current encoder state (e\&.g\&. when encoding is started, window size might be already encoded and therefore it is impossible to change it)
+.PP
+\fBBROTLI_TRUE\fP if value is accepted
+.RE
+.PP
+\fBWarning:\fP
+.RS 4
+invalid values might be accepted in case they would not break encoding process\&.
+.RE
+.PP
+
+.SS "const uint8_t* BrotliEncoderTakeOutput (\fBBrotliEncoderState\fP * state, size_t * size)"
+
+.PP
+Acquires pointer to internal output buffer\&. This method is used to make language bindings easier and more efficient:
+.IP "1." 4
+push data to \fBBrotliEncoderCompressStream\fP, until \fBBrotliEncoderHasMoreOutput\fP returns BROTL_TRUE
+.IP "2." 4
+use \fBBrotliEncoderTakeOutput\fP to peek bytes and copy to language-specific entity
+.PP
+.PP
+Also this could be useful if there is an output stream that is able to consume all the provided data (e\&.g\&. when data is saved to file system)\&.
+.PP
+\fBAttention:\fP
+.RS 4
+After every call to \fBBrotliEncoderTakeOutput\fP \fC*size\fP bytes of output are considered consumed for all consecutive calls to the instance methods; returned pointer becomes invalidated as well\&.
+.RE
+.PP
+\fBNote:\fP
+.RS 4
+Encoder output is not guaranteed to be contiguous\&. This means that after the size-unrestricted call to \fBBrotliEncoderTakeOutput\fP, immediate next call to \fBBrotliEncoderTakeOutput\fP may return more data\&.
+.RE
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP encoder instance
+.br
+\fIsize\fP \fBin:\fP number of bytes caller is ready to take, \fC0\fP if any amount could be handled;
+.br
+ \fBout:\fP amount of data pointed by returned pointer and considered consumed;
+.br
+ out value is never greater than in value, unless it is \fC0\fP
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+pointer to output data
+.RE
+.PP
+
+.SS "uint32_t BrotliEncoderVersion (void)"
+
+.PP
+Gets an encoder library version\&. Look at BROTLI_VERSION for more information\&.
+.SH "Author"
+.PP
+Generated automatically by Doxygen for Brotli from the source code\&.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/types.h.3 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/types.h.3
new file mode 100644
index 000000000..bef931303
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/docs/types.h.3
@@ -0,0 +1,117 @@
+.TH "types.h" 3 "Thu Feb 22 2018" "Brotli" \" -*- nroff -*-
+.ad l
+.nh
+.SH NAME
+types.h \- Common types used in decoder and encoder API\&.
+
+.SH SYNOPSIS
+.br
+.PP
+.SS "Macros"
+
+.in +1c
+.ti -1c
+.RI "#define \fBBROTLI_BOOL\fP int"
+.br
+.RI "\fIA portable \fCbool\fP replacement\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_FALSE\fP 0"
+.br
+.RI "\fIPortable \fCfalse\fP replacement\&. \fP"
+.ti -1c
+.RI "#define \fBBROTLI_TRUE\fP 1"
+.br
+.RI "\fIPortable \fCtrue\fP replacement\&. \fP"
+.ti -1c
+.RI "#define \fBTO_BROTLI_BOOL\fP(X) (!!(X) ? \fBBROTLI_TRUE\fP : \fBBROTLI_FALSE\fP)"
+.br
+.RI "\fI\fCbool\fP to \fBBROTLI_BOOL\fP conversion macros\&. \fP"
+.in -1c
+.SS "Typedefs"
+
+.in +1c
+.ti -1c
+.RI "typedef void *(* \fBbrotli_alloc_func\fP) (void *opaque, size_t size)"
+.br
+.RI "\fIAllocating function pointer type\&. \fP"
+.ti -1c
+.RI "typedef void(* \fBbrotli_free_func\fP) (void *opaque, void *address)"
+.br
+.RI "\fIDeallocating function pointer type\&. \fP"
+.in -1c
+.SH "Detailed Description"
+.PP
+Common types used in decoder and encoder API\&.
+
+
+.SH "Macro Definition Documentation"
+.PP
+.SS "#define BROTLI_BOOL int"
+
+.PP
+A portable \fCbool\fP replacement\&. \fBBROTLI_BOOL\fP is a 'documentation' type: actually it is \fCint\fP, but in API it denotes a type, whose only values are \fBBROTLI_TRUE\fP and \fBBROTLI_FALSE\fP\&.
+.PP
+\fBBROTLI_BOOL\fP values passed to Brotli should either be \fBBROTLI_TRUE\fP or \fBBROTLI_FALSE\fP, or be a result of \fBTO_BROTLI_BOOL\fP macros\&.
+.PP
+\fBBROTLI_BOOL\fP values returned by Brotli should not be tested for equality with \fCtrue\fP, \fCfalse\fP, \fBBROTLI_TRUE\fP, \fBBROTLI_FALSE\fP, but rather should be evaluated, for example:
+.PP
+.nf
+if (SomeBrotliFunction(encoder, BROTLI_TRUE) &&
+ !OtherBrotliFunction(decoder, BROTLI_FALSE)) {
+ bool x = !!YetAnotherBrotliFunction(encoder, TO_BROLTI_BOOL(2 * 2 == 4));
+ DoSomething(x);
+}
+
+.fi
+.PP
+
+.SS "#define BROTLI_FALSE 0"
+
+.PP
+Portable \fCfalse\fP replacement\&.
+.SS "#define BROTLI_TRUE 1"
+
+.PP
+Portable \fCtrue\fP replacement\&.
+.SS "#define TO_BROTLI_BOOL(X) (!!(X) ? \fBBROTLI_TRUE\fP : \fBBROTLI_FALSE\fP)"
+
+.PP
+\fCbool\fP to \fBBROTLI_BOOL\fP conversion macros\&.
+.SH "Typedef Documentation"
+.PP
+.SS "typedef void*(* brotli_alloc_func) (void *opaque, size_t size)"
+
+.PP
+Allocating function pointer type\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIopaque\fP custom memory manager handle provided by client
+.br
+\fIsize\fP requested memory region size; can not be \fC0\fP
+.RE
+.PP
+\fBReturns:\fP
+.RS 4
+\fC0\fP in the case of failure
+.PP
+a valid pointer to a memory region of at least \fCsize\fP bytes long otherwise
+.RE
+.PP
+
+.SS "typedef void(* brotli_free_func) (void *opaque, void *address)"
+
+.PP
+Deallocating function pointer type\&. This function \fBSHOULD\fP do nothing if \fCaddress\fP is \fC0\fP\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIopaque\fP custom memory manager handle provided by client
+.br
+\fIaddress\fP memory region pointer returned by \fBbrotli_alloc_func\fP, or \fC0\fP
+.RE
+.PP
+
+.SH "Author"
+.PP
+Generated automatically by Doxygen for Brotli from the source code\&.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/fetch-spec/shared-brotli-fetch-spec.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/fetch-spec/shared-brotli-fetch-spec.txt
new file mode 100644
index 000000000..ea2d11712
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/fetch-spec/shared-brotli-fetch-spec.txt
@@ -0,0 +1,116 @@
+[DRAFT]
+
+Introduction:
+
+This document is a draft proposal for Shard Brotli dictionaries in the fetch spec
+(https://fetch.spec.whatwg.org/).
+
+The goal is to add support for custom dictionaries for Brotli. A dictionary is used
+to improve compression. A client can download a dictionary from a server and then
+use it to decompress resources compressed with this dictionary.
+
+This document specifies how the client and server negotiate the dictionary over HTTP.
+A high level overview is as follows: The server adds an HTTP header to the response
+with a URL of the dictionary. The browser downloads the dictionary from the URL and
+then caches it so it can be reused. The server also adds a checksum to an HTTP header
+which the client uses to verify the dictionary. Caching, CORS, and other existing
+mechanisms are used. A dictionary can be a pre-made static dictionary, but does not
+have to be, for example a previous page loaded from this server, or an old version
+of a page, can be used as well.
+
+Below are changes and additions to add Shared Brotli dictionaries to the fetch spec
+at https://fetch.spec.whatwg.org/:
+
+Additions to `4.5. HTTP-network-or-cache fetch`
+
+Add to point `15. Modify httpRequest’s header list per HTTP.`:
+
+ If the recursive-sbr flag is enabled, `Accept-Encoding` may not contain `sbr`
+ [NOTE-BOX] When sbr can be used, it is possible to add a header Available-Dict
+ with the URL and hash code of a cached resource. The server may then use it as
+ shared dictionary.
+
+Additions to `4.6. HTTP-network fetch`
+
+Add after point `10. Run these steps, but abort if the ongoing fetch is terminated`:
+
+ 11. Let codings be the result of extracting header list values given
+ `Content-Encoding` and response’s header list.
+ 12. If codings contains `sbr`
+ 1. If the header list does not contain `Sbr-Dict`, return a network error
+ 2. Let dictionaryId be the result of extracting header list values given
+ `Sbr-Dict` and response’s header list.
+
+To point `12. Run these substeps in parallel:`, add new first sub-point:
+
+ 1. If codings contains `sbr`, run these subsubsteps:
+ 1. Let dictionaryResponse be the result of performing a
+ Shared-Brotli-dictionary fetch given dictionaryId and request.
+ 2. If dictionaryResponse is a network error, return a network error.
+
+Change point `12.4. Set bytes to the result of handling content codings given codings and bytes.` to:
+
+ 4. Set bytes to the result of handling content codings given codings, bytes
+ and, if codings contains `sbr`, also dictionaryResponse's body.
+ [NOTE-BOX] If the dictionary is still being fetched, which happens in
+ parallel, enqueue bytes in a compressed buffer and handle content coding
+ once the dictionary is fetched
+
+Additions to `2.2.4. Bodies`
+
+
+Change last section `To handle content codings ...` to:
+
+ To handle content codings given codings, bytes and optionally a dictionary, run these substeps:
+ 1. If codings are not supported, return bytes.
+ 2. If the codings has `sbr`, run these subsubsteps:
+ a. Return the result of decoding bytes and dictionary with the Shared
+ Brotli decoder.
+ [Shared Brotli Spec] [IANA Brotli](https://www.iana.org/assignments/http-parameters/http-parameters.xhtml)
+ 3. Else:
+ a. Return the result of decoding bytes with the given codings, as
+ explained in HTTP. [HTTP] [HTTP-SEMANTICS] [HTTP-COND] [HTTP-CACHING]
+ [HTTP-AUTH]
+
+New section `4.10. Shared-Brotli-dictionary fetch`
+
+ To perform a Shared-Brotli-dictionary fetch using dictionaryId, and parentRequest, perform these steps:
+
+ 1. Let dictionaryURL be the URL extracted from dictionaryId
+ 2. Let dictionaryHash be the hash id extracted from dictionaryId
+ 3. Let dictionaryRequest be a new request whose method is `GET`, url is
+ dictionaryURL, mode is "cors", and client is parentRequest's client.
+ 4. Let dictionaryResponse be the result of performing an
+ [HTTP-network-or-cache](https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch)
+ fetch using dictionaryRequest with the recursive-sbr flag set to true.
+ [NOTE-BOX] For compression benefits, the dictionary should be reused to
+ decode multiple different responses. We rely on caching to achieve this.
+ It is suggested for servers to not add any "no-cache" or short "max-age"
+ Cache-Control directives, and it is suggested for the client to effectively
+ support caching it.
+ [NOTE-BOX] Since the same dictionary can be identified by a hash code, a
+ browser can avoid fetching a dictionary if it already has one with the same
+ hashed cached from a different source URL.
+ [NOTE-BOX] It is suggested that a server does not reuse the same URL
+ to host an updated or different dictionary. Instead the same dictionary URL
+ should contain a dictionary with the same content and same hash.
+ 5. If dictionaryResponse is a network error, return a network error.
+ 6. If dictionaryResponse's status is not an ok status, return a network error.
+ 7. Let tokens be the result of
+ [parsing metadata](https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata)
+ given dictionaryHash.
+ [Subresource Integrity](https://w3c.github.io/webappsec-subresource-integrity/)
+ 8. If tokens is no metadata or the length of tokens is not 1, return a network
+ error
+ 9. Let algorithm be the alg component of tokens[0]. If alg is 'hw3', set
+ algorithm to 256-bit HighwayHash
+ 10. Let digest be the val component of tokens[1].
+ 11. Let hashValue be the result of base64 decoding digest
+ [base64](https://tools.ietf.org/html/rfc4648)
+ 12. If hashValue is not a valid base64 encoding, return a network error
+ [NOTE-BOX] All of the supported hashing algorithms are cryptographically
+ secure.
+ 13. Compute the hash code of dictionaryResponse's body using algorithm and
+ compare this checksum for equality with hashValue. If the computed
+ checksum does not match hashValue, return a network error.
+ 14. Return dictionaryResponse.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/BUILD
new file mode 100644
index 000000000..72a5317f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/BUILD
@@ -0,0 +1,2 @@
+# Description:
+# cbrotli is a CGo wrapper for Brotli, a generic-purpose lossless compression algorithm.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/WORKSPACE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/WORKSPACE
new file mode 100644
index 000000000..e9652697c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/WORKSPACE
@@ -0,0 +1,21 @@
+workspace(name = "org_brotli_go")
+
+local_repository(
+ name = "org_brotli",
+ path = "..",
+)
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "io_bazel_rules_go",
+ urls = [
+ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
+ "https://github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
+ ],
+ sha256 = "9fb16af4d4836c8222142e54c9efa0bb5fc562ffc893ce2abeac3e25daead144",
+)
+
+load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
+go_rules_dependencies()
+go_register_toolchains()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/BUILD
new file mode 100644
index 000000000..ce594ad19
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/BUILD
@@ -0,0 +1,26 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "cbrotli",
+ srcs = [
+ "reader.go",
+ "writer.go",
+ ],
+ cdeps = [
+ "@org_brotli//:brotlidec",
+ "@org_brotli//:brotlienc",
+ ],
+ cgo = True,
+ importpath = "github.com/google/brotli/go/cbrotli",
+)
+
+go_test(
+ name = "cbrotli_test",
+ size = "small",
+ srcs = ["cbrotli_test.go"],
+ embed = [":cbrotli"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cbrotli_test.go b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cbrotli_test.go
new file mode 100644
index 000000000..f59ec582d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cbrotli_test.go
@@ -0,0 +1,367 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Distributed under MIT license.
+// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+package cbrotli
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "math/rand"
+ "testing"
+ "time"
+)
+
+func checkCompressedData(compressedData, wantOriginalData []byte) error {
+ uncompressed, err := Decode(compressedData)
+ if err != nil {
+ return fmt.Errorf("brotli decompress failed: %v", err)
+ }
+ if !bytes.Equal(uncompressed, wantOriginalData) {
+ if len(wantOriginalData) != len(uncompressed) {
+ return fmt.Errorf(""+
+ "Data doesn't uncompress to the original value.\n"+
+ "Length of original: %v\n"+
+ "Length of uncompressed: %v",
+ len(wantOriginalData), len(uncompressed))
+ }
+ for i := range wantOriginalData {
+ if wantOriginalData[i] != uncompressed[i] {
+ return fmt.Errorf(""+
+ "Data doesn't uncompress to the original value.\n"+
+ "Original at %v is %v\n"+
+ "Uncompressed at %v is %v",
+ i, wantOriginalData[i], i, uncompressed[i])
+ }
+ }
+ }
+ return nil
+}
+
+func TestEncoderNoWrite(t *testing.T) {
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 5})
+ if err := e.Close(); err != nil {
+ t.Errorf("Close()=%v, want nil", err)
+ }
+ // Check Write after close.
+ if _, err := e.Write([]byte("hi")); err == nil {
+ t.Errorf("No error after Close() + Write()")
+ }
+}
+
+func TestEncoderEmptyWrite(t *testing.T) {
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 5})
+ n, err := e.Write([]byte(""))
+ if n != 0 || err != nil {
+ t.Errorf("Write()=%v,%v, want 0, nil", n, err)
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close()=%v, want nil", err)
+ }
+}
+
+func TestWriter(t *testing.T) {
+ // Test basic encoder usage.
+ input := []byte("<html><body><H1>Hello world</H1></body></html>")
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 1})
+ in := bytes.NewReader([]byte(input))
+ n, err := io.Copy(e, in)
+ if err != nil {
+ t.Errorf("Copy Error: %v", err)
+ }
+ if int(n) != len(input) {
+ t.Errorf("Copy() n=%v, want %v", n, len(input))
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close Error after copied %d bytes: %v", n, err)
+ }
+ if err := checkCompressedData(out.Bytes(), input); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestEncoderStreams(t *testing.T) {
+ // Test that output is streamed.
+ // Adjust window size to ensure the encoder outputs at least enough bytes
+ // to fill the window.
+ const lgWin = 16
+ windowSize := int(math.Pow(2, lgWin))
+ input := make([]byte, 8*windowSize)
+ rand.Read(input)
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 11, LGWin: lgWin})
+ halfInput := input[:len(input)/2]
+ in := bytes.NewReader(halfInput)
+
+ n, err := io.Copy(e, in)
+ if err != nil {
+ t.Errorf("Copy Error: %v", err)
+ }
+
+ // We've fed more data than the sliding window size. Check that some
+ // compressed data has been output.
+ if out.Len() == 0 {
+ t.Errorf("Output length is 0 after %d bytes written", n)
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close Error after copied %d bytes: %v", n, err)
+ }
+ if err := checkCompressedData(out.Bytes(), halfInput); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestEncoderLargeInput(t *testing.T) {
+ input := make([]byte, 1000000)
+ rand.Read(input)
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 5})
+ in := bytes.NewReader(input)
+
+ n, err := io.Copy(e, in)
+ if err != nil {
+ t.Errorf("Copy Error: %v", err)
+ }
+ if int(n) != len(input) {
+ t.Errorf("Copy() n=%v, want %v", n, len(input))
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close Error after copied %d bytes: %v", n, err)
+ }
+ if err := checkCompressedData(out.Bytes(), input); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestEncoderFlush(t *testing.T) {
+ input := make([]byte, 1000)
+ rand.Read(input)
+ out := bytes.Buffer{}
+ e := NewWriter(&out, WriterOptions{Quality: 5})
+ in := bytes.NewReader(input)
+ _, err := io.Copy(e, in)
+ if err != nil {
+ t.Fatalf("Copy Error: %v", err)
+ }
+ if err := e.Flush(); err != nil {
+ t.Fatalf("Flush(): %v", err)
+ }
+ if out.Len() == 0 {
+ t.Fatalf("0 bytes written after Flush()")
+ }
+ decompressed := make([]byte, 1000)
+ reader := NewReader(bytes.NewReader(out.Bytes()))
+ n, err := reader.Read(decompressed)
+ if n != len(decompressed) || err != nil {
+ t.Errorf("Expected <%v, nil>, but <%v, %v>", len(decompressed), n, err)
+ }
+ reader.Close()
+ if !bytes.Equal(decompressed, input) {
+ t.Errorf(""+
+ "Decompress after flush: %v\n"+
+ "%q\n"+
+ "want:\n%q",
+ err, decompressed, input)
+ }
+ if err := e.Close(); err != nil {
+ t.Errorf("Close(): %v", err)
+ }
+}
+
+type readerWithTimeout struct {
+ io.ReadCloser
+}
+
+func (r readerWithTimeout) Read(p []byte) (int, error) {
+ type result struct {
+ n int
+ err error
+ }
+ ch := make(chan result)
+ go func() {
+ n, err := r.ReadCloser.Read(p)
+ ch <- result{n, err}
+ }()
+ select {
+ case result := <-ch:
+ return result.n, result.err
+ case <-time.After(5 * time.Second):
+ return 0, fmt.Errorf("read timed out")
+ }
+}
+
+func TestDecoderStreaming(t *testing.T) {
+ pr, pw := io.Pipe()
+ writer := NewWriter(pw, WriterOptions{Quality: 5, LGWin: 20})
+ reader := readerWithTimeout{NewReader(pr)}
+ defer func() {
+ if err := reader.Close(); err != nil {
+ t.Errorf("reader.Close: %v", err)
+ }
+ go ioutil.ReadAll(pr) // swallow the "EOF" token from writer.Close
+ if err := writer.Close(); err != nil {
+ t.Errorf("writer.Close: %v", err)
+ }
+ }()
+
+ ch := make(chan []byte)
+ errch := make(chan error)
+ go func() {
+ for {
+ segment, ok := <-ch
+ if !ok {
+ return
+ }
+ if n, err := writer.Write(segment); err != nil || n != len(segment) {
+ errch <- fmt.Errorf("write=%v,%v, want %v,%v", n, err, len(segment), nil)
+ return
+ }
+ if err := writer.Flush(); err != nil {
+ errch <- fmt.Errorf("flush: %v", err)
+ return
+ }
+ }
+ }()
+ defer close(ch)
+
+ segments := [...][]byte{
+ []byte("first"),
+ []byte("second"),
+ []byte("third"),
+ }
+ for k, segment := range segments {
+ t.Run(fmt.Sprintf("Segment%d", k), func(t *testing.T) {
+ select {
+ case ch <- segment:
+ case err := <-errch:
+ t.Fatalf("write: %v", err)
+ case <-time.After(5 * time.Second):
+ t.Fatalf("timed out")
+ }
+ wantLen := len(segment)
+ got := make([]byte, wantLen)
+ if n, err := reader.Read(got); err != nil || n != wantLen || !bytes.Equal(got, segment) {
+ t.Fatalf("read[%d]=%q,%v,%v, want %q,%v,%v", k, got, n, err, segment, wantLen, nil)
+ }
+ })
+ }
+}
+
+func TestReader(t *testing.T) {
+ content := bytes.Repeat([]byte("hello world!"), 10000)
+ encoded, _ := Encode(content, WriterOptions{Quality: 5})
+ r := NewReader(bytes.NewReader(encoded))
+ var decodedOutput bytes.Buffer
+ n, err := io.Copy(&decodedOutput, r)
+ if err != nil {
+ t.Fatalf("Copy(): n=%v, err=%v", n, err)
+ }
+ if err := r.Close(); err != nil {
+ t.Errorf("Close(): %v", err)
+ }
+ if got := decodedOutput.Bytes(); !bytes.Equal(got, content) {
+ t.Errorf(""+
+ "Reader output:\n"+
+ "%q\n"+
+ "want:\n"+
+ "<%d bytes>",
+ got, len(content))
+ }
+}
+
+func TestDecode(t *testing.T) {
+ content := bytes.Repeat([]byte("hello world!"), 10000)
+ encoded, _ := Encode(content, WriterOptions{Quality: 5})
+ decoded, err := Decode(encoded)
+ if err != nil {
+ t.Errorf("Decode: %v", err)
+ }
+ if !bytes.Equal(decoded, content) {
+ t.Errorf(""+
+ "Decode content:\n"+
+ "%q\n"+
+ "want:\n"+
+ "<%d bytes>",
+ decoded, len(content))
+ }
+}
+
+func TestDecodeFuzz(t *testing.T) {
+ // Test that the decoder terminates with corrupted input.
+ content := bytes.Repeat([]byte("hello world!"), 100)
+ src := rand.NewSource(0)
+ encoded, err := Encode(content, WriterOptions{Quality: 5})
+ if err != nil {
+ t.Fatalf("Encode(<%d bytes>, _) = _, %s", len(content), err)
+ }
+ if len(encoded) == 0 {
+ t.Fatalf("Encode(<%d bytes>, _) produced empty output", len(content))
+ }
+ for i := 0; i < 100; i++ {
+ enc := append([]byte{}, encoded...)
+ for j := 0; j < 5; j++ {
+ enc[int(src.Int63())%len(enc)] = byte(src.Int63() % 256)
+ }
+ Decode(enc)
+ }
+}
+
+func TestDecodeTrailingData(t *testing.T) {
+ content := bytes.Repeat([]byte("hello world!"), 100)
+ encoded, _ := Encode(content, WriterOptions{Quality: 5})
+ _, err := Decode(append(encoded, 0))
+ if err == nil {
+ t.Errorf("Expected 'excessive input' error")
+ }
+}
+
+func TestEncodeDecode(t *testing.T) {
+ for _, test := range []struct {
+ data []byte
+ repeats int
+ }{
+ {nil, 0},
+ {[]byte("A"), 1},
+ {[]byte("<html><body><H1>Hello world</H1></body></html>"), 10},
+ {[]byte("<html><body><H1>Hello world</H1></body></html>"), 1000},
+ } {
+ t.Logf("case %q x %d", test.data, test.repeats)
+ input := bytes.Repeat(test.data, test.repeats)
+ encoded, err := Encode(input, WriterOptions{Quality: 5})
+ if err != nil {
+ t.Errorf("Encode: %v", err)
+ }
+ // Inputs are compressible, but may be too small to compress.
+ if maxSize := len(input)/2 + 20; len(encoded) >= maxSize {
+ t.Errorf(""+
+ "Encode returned %d bytes, want <%d\n"+
+ "Encoded=%q",
+ len(encoded), maxSize, encoded)
+ }
+ decoded, err := Decode(encoded)
+ if err != nil {
+ t.Errorf("Decode: %v", err)
+ }
+ if !bytes.Equal(decoded, input) {
+ var want string
+ if len(input) > 320 {
+ want = fmt.Sprintf("<%d bytes>", len(input))
+ } else {
+ want = fmt.Sprintf("%q", input)
+ }
+ t.Errorf(""+
+ "Decode content:\n"+
+ "%q\n"+
+ "want:\n"+
+ "%s",
+ decoded, want)
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cgo.go b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cgo.go
new file mode 100644
index 000000000..f953f72cd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/cgo.go
@@ -0,0 +1,13 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Distributed under MIT license.
+// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+package cbrotli
+
+// Inform golang build system that it should link brotli libraries.
+
+// #cgo LDFLAGS: -lbrotlicommon
+// #cgo LDFLAGS: -lbrotlidec
+// #cgo LDFLAGS: -lbrotlienc
+import "C"
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/reader.go b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/reader.go
new file mode 100644
index 000000000..3d8d42450
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/reader.go
@@ -0,0 +1,161 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Distributed under MIT license.
+// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+// Package cbrotli compresses and decompresses data with C-Brotli library.
+package cbrotli
+
+/*
+#include <stddef.h>
+#include <stdint.h>
+
+#include <brotli/decode.h>
+
+static BrotliDecoderResult DecompressStream(BrotliDecoderState* s,
+ uint8_t* out, size_t out_len,
+ const uint8_t* in, size_t in_len,
+ size_t* bytes_written,
+ size_t* bytes_consumed) {
+ size_t in_remaining = in_len;
+ size_t out_remaining = out_len;
+ BrotliDecoderResult result = BrotliDecoderDecompressStream(
+ s, &in_remaining, &in, &out_remaining, &out, NULL);
+ *bytes_written = out_len - out_remaining;
+ *bytes_consumed = in_len - in_remaining;
+ return result;
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "io/ioutil"
+)
+
+type decodeError C.BrotliDecoderErrorCode
+
+func (err decodeError) Error() string {
+ return "cbrotli: " +
+ C.GoString(C.BrotliDecoderErrorString(C.BrotliDecoderErrorCode(err)))
+}
+
+var errExcessiveInput = errors.New("cbrotli: excessive input")
+var errInvalidState = errors.New("cbrotli: invalid state")
+var errReaderClosed = errors.New("cbrotli: Reader is closed")
+
+// Reader implements io.ReadCloser by reading Brotli-encoded data from an
+// underlying Reader.
+type Reader struct {
+ src io.Reader
+ state *C.BrotliDecoderState
+ buf []byte // scratch space for reading from src
+ in []byte // current chunk to decode; usually aliases buf
+}
+
+// readBufSize is a "good" buffer size that avoids excessive round-trips
+// between C and Go but doesn't waste too much memory on buffering.
+// It is arbitrarily chosen to be equal to the constant used in io.Copy.
+const readBufSize = 32 * 1024
+
+// NewReader initializes new Reader instance.
+// Close MUST be called to free resources.
+func NewReader(src io.Reader) *Reader {
+ return &Reader{
+ src: src,
+ state: C.BrotliDecoderCreateInstance(nil, nil, nil),
+ buf: make([]byte, readBufSize),
+ }
+}
+
+// Close implements io.Closer. Close MUST be invoked to free native resources.
+func (r *Reader) Close() error {
+ if r.state == nil {
+ return errReaderClosed
+ }
+ // Close despite the state; i.e. there might be some unread decoded data.
+ C.BrotliDecoderDestroyInstance(r.state)
+ r.state = nil
+ return nil
+}
+
+func (r *Reader) Read(p []byte) (n int, err error) {
+ if int(C.BrotliDecoderHasMoreOutput(r.state)) == 0 && len(r.in) == 0 {
+ m, readErr := r.src.Read(r.buf)
+ if m == 0 {
+ // If readErr is `nil`, we just proxy underlying stream behavior.
+ return 0, readErr
+ }
+ r.in = r.buf[:m]
+ }
+
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ for {
+ var written, consumed C.size_t
+ var data *C.uint8_t
+ if len(r.in) != 0 {
+ data = (*C.uint8_t)(&r.in[0])
+ }
+ result := C.DecompressStream(r.state,
+ (*C.uint8_t)(&p[0]), C.size_t(len(p)),
+ data, C.size_t(len(r.in)),
+ &written, &consumed)
+ r.in = r.in[int(consumed):]
+ n = int(written)
+
+ switch result {
+ case C.BROTLI_DECODER_RESULT_SUCCESS:
+ if len(r.in) > 0 {
+ return n, errExcessiveInput
+ }
+ return n, nil
+ case C.BROTLI_DECODER_RESULT_ERROR:
+ return n, decodeError(C.BrotliDecoderGetErrorCode(r.state))
+ case C.BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
+ if n == 0 {
+ return 0, io.ErrShortBuffer
+ }
+ return n, nil
+ case C.BROTLI_DECODER_NEEDS_MORE_INPUT:
+ }
+
+ if len(r.in) != 0 {
+ return 0, errInvalidState
+ }
+
+ // Calling r.src.Read may block. Don't block if we have data to return.
+ if n > 0 {
+ return n, nil
+ }
+
+ // Top off the buffer.
+ encN, err := r.src.Read(r.buf)
+ if encN == 0 {
+ // Not enough data to complete decoding.
+ if err == io.EOF {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ r.in = r.buf[:encN]
+ }
+
+ return n, nil
+}
+
+// Decode decodes Brotli encoded data.
+func Decode(encodedData []byte) ([]byte, error) {
+ r := &Reader{
+ src: bytes.NewReader(nil),
+ state: C.BrotliDecoderCreateInstance(nil, nil, nil),
+ buf: make([]byte, 4), // arbitrarily small but nonzero so that r.src.Read returns io.EOF
+ in: encodedData,
+ }
+ defer r.Close()
+ return ioutil.ReadAll(r)
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/writer.go b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/writer.go
new file mode 100644
index 000000000..9fa75ab06
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/go/cbrotli/writer.go
@@ -0,0 +1,159 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Distributed under MIT license.
+// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+package cbrotli
+
+/*
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <brotli/encode.h>
+
+struct CompressStreamResult {
+ size_t bytes_consumed;
+ const uint8_t* output_data;
+ size_t output_data_size;
+ int success;
+ int has_more;
+};
+
+static struct CompressStreamResult CompressStream(
+ BrotliEncoderState* s, BrotliEncoderOperation op,
+ const uint8_t* data, size_t data_size) {
+ struct CompressStreamResult result;
+ size_t available_in = data_size;
+ const uint8_t* next_in = data;
+ size_t available_out = 0;
+ result.success = BrotliEncoderCompressStream(s, op,
+ &available_in, &next_in, &available_out, 0, 0) ? 1 : 0;
+ result.bytes_consumed = data_size - available_in;
+ result.output_data = 0;
+ result.output_data_size = 0;
+ if (result.success) {
+ result.output_data = BrotliEncoderTakeOutput(s, &result.output_data_size);
+ }
+ result.has_more = BrotliEncoderHasMoreOutput(s) ? 1 : 0;
+ return result;
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "unsafe"
+)
+
+// WriterOptions configures Writer.
+type WriterOptions struct {
+ // Quality controls the compression-speed vs compression-density trade-offs.
+ // The higher the quality, the slower the compression. Range is 0 to 11.
+ Quality int
+ // LGWin is the base 2 logarithm of the sliding window size.
+ // Range is 10 to 24. 0 indicates automatic configuration based on Quality.
+ LGWin int
+}
+
+// Writer implements io.WriteCloser by writing Brotli-encoded data to an
+// underlying Writer.
+type Writer struct {
+ dst io.Writer
+ state *C.BrotliEncoderState
+ buf, encoded []byte
+}
+
+var (
+ errEncode = errors.New("cbrotli: encode error")
+ errWriterClosed = errors.New("cbrotli: Writer is closed")
+)
+
+// NewWriter initializes new Writer instance.
+// Close MUST be called to free resources.
+func NewWriter(dst io.Writer, options WriterOptions) *Writer {
+ state := C.BrotliEncoderCreateInstance(nil, nil, nil)
+ C.BrotliEncoderSetParameter(
+ state, C.BROTLI_PARAM_QUALITY, (C.uint32_t)(options.Quality))
+ if options.LGWin > 0 {
+ C.BrotliEncoderSetParameter(
+ state, C.BROTLI_PARAM_LGWIN, (C.uint32_t)(options.LGWin))
+ }
+ return &Writer{
+ dst: dst,
+ state: state,
+ }
+}
+
+func (w *Writer) writeChunk(p []byte, op C.BrotliEncoderOperation) (n int, err error) {
+ if w.state == nil {
+ return 0, errWriterClosed
+ }
+
+ for {
+ var data *C.uint8_t
+ if len(p) != 0 {
+ data = (*C.uint8_t)(&p[0])
+ }
+ result := C.CompressStream(w.state, op, data, C.size_t(len(p)))
+ if result.success == 0 {
+ return n, errEncode
+ }
+ p = p[int(result.bytes_consumed):]
+ n += int(result.bytes_consumed)
+
+ length := int(result.output_data_size)
+ if length != 0 {
+ // It is a workaround for non-copying-wrapping of native memory.
+ // C-encoder never pushes output block longer than ((2 << 25) + 502).
+ // TODO: use natural wrapper, when it becomes available, see
+ // https://golang.org/issue/13656.
+ output := (*[1 << 30]byte)(unsafe.Pointer(result.output_data))[:length:length]
+ _, err = w.dst.Write(output)
+ if err != nil {
+ return n, err
+ }
+ }
+ if len(p) == 0 && result.has_more == 0 {
+ return n, nil
+ }
+ }
+}
+
+// Flush outputs encoded data for all input provided to Write. The resulting
+// output can be decoded to match all input before Flush, but the stream is
+// not yet complete until after Close.
+// Flush has a negative impact on compression.
+func (w *Writer) Flush() error {
+ _, err := w.writeChunk(nil, C.BROTLI_OPERATION_FLUSH)
+ return err
+}
+
+// Close flushes remaining data to the decorated writer and frees C resources.
+func (w *Writer) Close() error {
+ // If stream is already closed, it is reported by `writeChunk`.
+ _, err := w.writeChunk(nil, C.BROTLI_OPERATION_FINISH)
+ // C-Brotli tolerates `nil` pointer here.
+ C.BrotliEncoderDestroyInstance(w.state)
+ w.state = nil
+ return err
+}
+
+// Write implements io.Writer. Flush or Close must be called to ensure that the
+// encoded bytes are actually flushed to the underlying Writer.
+func (w *Writer) Write(p []byte) (n int, err error) {
+ return w.writeChunk(p, C.BROTLI_OPERATION_PROCESS)
+}
+
+// Encode returns content encoded with Brotli.
+func Encode(content []byte, options WriterOptions) ([]byte, error) {
+ var buf bytes.Buffer
+ writer := NewWriter(&buf, options)
+ _, err := writer.Write(content)
+ if closeErr := writer.Close(); err == nil {
+ err = closeErr
+ }
+ return buf.Bytes(), err
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/BUILD
new file mode 100644
index 000000000..cd55c5477
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/BUILD
@@ -0,0 +1,98 @@
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+# >>> JNI headers
+
+genrule(
+ name = "copy_link_jni_header",
+ srcs = ["@openjdk_jni_h//file"],
+ outs = ["jni/jni.h"],
+ cmd = "cp -f $< $@",
+)
+
+genrule(
+ name = "copy_link_jni_md_header",
+ srcs = select({
+ "@org_brotli//:darwin": ["@openjdk_macosx_jni_md_h//file"],
+ "@org_brotli//:darwin_x86_64": ["@openjdk_macosx_jni_md_h//file"],
+ "@org_brotli//:windows_msys": ["@openjdk_windows_jni_md_h//file"],
+ "@org_brotli//:windows_msvc": ["@openjdk_windows_jni_md_h//file"],
+ "@org_brotli//:windows": ["@openjdk_windows_jni_md_h//file"],
+ "//conditions:default": ["@openjdk_solaris_jni_md_h//file"],
+ }),
+ outs = ["jni/jni_md.h"],
+ cmd = "cp -f $< $@",
+)
+
+cc_library(
+ name = "jni_inc",
+ hdrs = [
+ ":jni/jni.h",
+ ":jni/jni_md.h",
+ ],
+ includes = ["jni"],
+)
+
+# <<< JNI headers
+
+genrule(
+ name = "license_resource",
+ srcs = ["@org_brotli//:LICENSE"],
+ outs = ["META-INF/LICENSE"],
+ cmd = "cp -f $< $@",
+)
+
+java_library(
+ name = "license",
+ resources = [":license_resource"],
+)
+
+########################################################
+# WARNING: do not (transitively) depend on this target!
+########################################################
+cc_binary(
+ name = "brotli_jni.dll",
+ srcs = [
+ "//org/brotli/wrapper/common:jni_src",
+ "//org/brotli/wrapper/dec:jni_src",
+ "//org/brotli/wrapper/enc:jni_src",
+ "@org_brotli//:common_headers",
+ "@org_brotli//:common_sources",
+ "@org_brotli//:dec_headers",
+ "@org_brotli//:dec_sources",
+ "@org_brotli//:enc_headers",
+ "@org_brotli//:enc_sources",
+ ],
+ linkshared = 1,
+ deps = [
+ ":jni_inc",
+ "@org_brotli//:brotli_inc",
+ ],
+)
+
+########################################################
+# WARNING: do not (transitively) depend on this target!
+########################################################
+cc_binary(
+ name = "brotli_jni_no_dictionary_data.dll",
+ srcs = [
+ "//org/brotli/wrapper/common:jni_src",
+ "//org/brotli/wrapper/dec:jni_src",
+ "//org/brotli/wrapper/enc:jni_src",
+ "@org_brotli//:common_headers",
+ "@org_brotli//:common_sources",
+ "@org_brotli//:dec_headers",
+ "@org_brotli//:dec_sources",
+ "@org_brotli//:enc_headers",
+ "@org_brotli//:enc_sources",
+ ],
+ defines = [
+ "BROTLI_EXTERNAL_DICTIONARY_DATA=",
+ ],
+ linkshared = 1,
+ deps = [
+ ":jni_inc",
+ "@org_brotli//:brotli_inc",
+ ],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/WORKSPACE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/WORKSPACE
new file mode 100644
index 000000000..06fbdfeea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/WORKSPACE
@@ -0,0 +1,41 @@
+workspace(name = "org_brotli_java")
+
+local_repository(
+ name = "org_brotli",
+ path = "..",
+)
+
+maven_jar(
+ name = "junit_junit",
+ artifact = "junit:junit:4.12",
+)
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
+
+http_file(
+ name = "openjdk_jni_h",
+ downloaded_file_path = "jni.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/share/javavm/export/jni.h"],
+ sha256 = "ed99792df48670072b78028faf704a8dcb6868fe140ccc7eced9b01dfa62fef4",
+)
+
+http_file(
+ name = "openjdk_solaris_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/solaris/javavm/export/jni_md.h"],
+ sha256 = "ecbe6944fe1a4290644d5a6b3c8f68576798a53b9da12cd31c58c48569595ff7",
+)
+
+http_file(
+ name = "openjdk_macosx_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/macosx/javavm/export/jni_md.h"],
+ sha256 = "8f718071022e7e7f2fc9a229984b7e83582db91ed83861b49ce1461436fe8dc4",
+)
+
+http_file(
+ name = "openjdk_windows_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/windows/javavm/export/jni_md.h"],
+ sha256 = "5479fb385ea1e11619f5c0cdfd9ccb3ea3a3fea0f5bc6176fb3ce62be29d759b",
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BUILD
new file mode 100644
index 000000000..0cc0cbf18
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BUILD
@@ -0,0 +1,59 @@
+# Description:
+# Java port of Brotli decoder.
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+TEST_DEPS = [
+ ":dec",
+ "@junit_junit//jar",
+]
+
+java_library(
+ name = "dec",
+ srcs = glob(
+ ["*.java"],
+ exclude = ["*Test*.java"],
+ ),
+ proguard_specs = ["proguard.pgcfg"],
+ resource_jars = ["//:license"],
+)
+
+load(":build_defs.bzl", "brotli_java_test")
+
+brotli_java_test(
+ name = "BitReaderTest",
+ srcs = ["BitReaderTest.java"],
+ deps = TEST_DEPS,
+)
+
+brotli_java_test(
+ name = "DecodeTest",
+ srcs = ["DecodeTest.java"],
+ deps = TEST_DEPS,
+)
+
+brotli_java_test(
+ name = "DictionaryTest",
+ srcs = ["DictionaryTest.java"],
+ deps = TEST_DEPS,
+)
+
+brotli_java_test(
+ name = "EagerStreamTest",
+ srcs = ["EagerStreamTest.java"],
+ deps = TEST_DEPS,
+)
+
+brotli_java_test(
+ name = "SynthTest",
+ srcs = ["SynthTest.java"],
+ deps = TEST_DEPS,
+)
+
+brotli_java_test(
+ name = "TransformTest",
+ srcs = ["TransformTest.java"],
+ deps = TEST_DEPS,
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReader.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReader.java
new file mode 100644
index 000000000..6dfeedca8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReader.java
@@ -0,0 +1,289 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+/**
+ * Bit reading helpers.
+ */
+final class BitReader {
+
+ // Possible values: {5, 6}. 5 corresponds to 32-bit build, 6 to 64-bit. This value is used for
+ // JIT conditional compilation.
+ private static final int LOG_BITNESS = Utils.getLogBintness();
+
+ // Not only Java compiler prunes "if (const false)" code, but JVM as well.
+ // Code under "if (DEBUG != 0)" have zero performance impact (outside unit tests).
+ private static final int DEBUG = Utils.isDebugMode();
+
+ static final int BITNESS = 1 << LOG_BITNESS;
+
+ private static final int BYTENESS = BITNESS / 8;
+ private static final int CAPACITY = 4096;
+ // After encountering the end of the input stream, this amount of zero bytes will be appended.
+ private static final int SLACK = 64;
+ private static final int BUFFER_SIZE = CAPACITY + SLACK;
+ // Don't bother to replenish the buffer while this number of bytes is available.
+ private static final int SAFEGUARD = 36;
+ private static final int WATERLINE = CAPACITY - SAFEGUARD;
+
+ // "Half" refers to "half of native integer type", i.e. on 64-bit machines it is 32-bit type,
+ // on 32-bit machines it is 16-bit.
+ private static final int HALF_BITNESS = BITNESS / 2;
+ private static final int HALF_SIZE = BYTENESS / 2;
+ private static final int HALVES_CAPACITY = CAPACITY / HALF_SIZE;
+ private static final int HALF_BUFFER_SIZE = BUFFER_SIZE / HALF_SIZE;
+ private static final int HALF_WATERLINE = WATERLINE / HALF_SIZE;
+
+ private static final int LOG_HALF_SIZE = LOG_BITNESS - 4;
+
+ /**
+ * Fills up the input buffer.
+ *
+ * <p> No-op if there are at least 36 bytes present after current position.
+ *
+ * <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
+ * buffer.
+ */
+ static void readMoreInput(State s) {
+ if (s.halfOffset > HALF_WATERLINE) {
+ doReadMoreInput(s);
+ }
+ }
+
+ static void doReadMoreInput(State s) {
+ if (s.endOfStreamReached != 0) {
+ if (halfAvailable(s) >= -2) {
+ return;
+ }
+ throw new BrotliRuntimeException("No more input");
+ }
+ int readOffset = s.halfOffset << LOG_HALF_SIZE;
+ int bytesInBuffer = CAPACITY - readOffset;
+ // Move unused bytes to the head of the buffer.
+ Utils.copyBytesWithin(s.byteBuffer, 0, readOffset, CAPACITY);
+ s.halfOffset = 0;
+ while (bytesInBuffer < CAPACITY) {
+ int spaceLeft = CAPACITY - bytesInBuffer;
+ int len = Utils.readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
+ // EOF is -1 in Java, but 0 in C#.
+ if (len <= 0) {
+ s.endOfStreamReached = 1;
+ s.tailBytes = bytesInBuffer;
+ bytesInBuffer += HALF_SIZE - 1;
+ break;
+ }
+ bytesInBuffer += len;
+ }
+ bytesToNibbles(s, bytesInBuffer);
+ }
+
+ static void checkHealth(State s, int endOfStream) {
+ if (s.endOfStreamReached == 0) {
+ return;
+ }
+ int byteOffset = (s.halfOffset << LOG_HALF_SIZE) + ((s.bitOffset + 7) >> 3) - BYTENESS;
+ if (byteOffset > s.tailBytes) {
+ throw new BrotliRuntimeException("Read after end");
+ }
+ if ((endOfStream != 0) && (byteOffset != s.tailBytes)) {
+ throw new BrotliRuntimeException("Unused bytes after end");
+ }
+ }
+
+ static void assertAccumulatorHealthy(State s) {
+ if (s.bitOffset > BITNESS) {
+ throw new IllegalStateException("Accumulator underloaded: " + s.bitOffset);
+ }
+ }
+
+ static void fillBitWindow(State s) {
+ if (DEBUG != 0) {
+ assertAccumulatorHealthy(s);
+ }
+ if (s.bitOffset >= HALF_BITNESS) {
+ // Same as doFillBitWindow. JVM fails to inline it.
+ if (BITNESS == 64) {
+ s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
+ | (s.accumulator64 >>> HALF_BITNESS);
+ } else {
+ s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
+ | (s.accumulator32 >>> HALF_BITNESS);
+ }
+ s.bitOffset -= HALF_BITNESS;
+ }
+ }
+
+ static void doFillBitWindow(State s) {
+ if (DEBUG != 0) {
+ assertAccumulatorHealthy(s);
+ }
+ if (BITNESS == 64) {
+ s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
+ | (s.accumulator64 >>> HALF_BITNESS);
+ } else {
+ s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
+ | (s.accumulator32 >>> HALF_BITNESS);
+ }
+ s.bitOffset -= HALF_BITNESS;
+ }
+
+ static int peekBits(State s) {
+ if (BITNESS == 64) {
+ return (int) (s.accumulator64 >>> s.bitOffset);
+ } else {
+ return s.accumulator32 >>> s.bitOffset;
+ }
+ }
+
+ /**
+ * Fetches bits from accumulator.
+ *
+ * WARNING: accumulator MUST contain at least the specified amount of bits,
+ * otherwise BitReader will become broken.
+ */
+ static int readFewBits(State s, int n) {
+ int val = peekBits(s) & ((1 << n) - 1);
+ s.bitOffset += n;
+ return val;
+ }
+
+ static int readBits(State s, int n) {
+ if (HALF_BITNESS >= 24) {
+ return readFewBits(s, n);
+ } else {
+ return (n <= 16) ? readFewBits(s, n) : readManyBits(s, n);
+ }
+ }
+
+ private static int readManyBits(State s, int n) {
+ int low = readFewBits(s, 16);
+ doFillBitWindow(s);
+ return low | (readFewBits(s, n - 16) << 16);
+ }
+
+ static void initBitReader(State s) {
+ s.byteBuffer = new byte[BUFFER_SIZE];
+ if (BITNESS == 64) {
+ s.accumulator64 = 0;
+ s.intBuffer = new int[HALF_BUFFER_SIZE];
+ } else {
+ s.accumulator32 = 0;
+ s.shortBuffer = new short[HALF_BUFFER_SIZE];
+ }
+ s.bitOffset = BITNESS;
+ s.halfOffset = HALVES_CAPACITY;
+ s.endOfStreamReached = 0;
+ prepare(s);
+ }
+
+ private static void prepare(State s) {
+ readMoreInput(s);
+ checkHealth(s, 0);
+ doFillBitWindow(s);
+ doFillBitWindow(s);
+ }
+
+ static void reload(State s) {
+ if (s.bitOffset == BITNESS) {
+ prepare(s);
+ }
+ }
+
+ static void jumpToByteBoundary(State s) {
+ int padding = (BITNESS - s.bitOffset) & 7;
+ if (padding != 0) {
+ int paddingBits = readFewBits(s, padding);
+ if (paddingBits != 0) {
+ throw new BrotliRuntimeException("Corrupted padding bits");
+ }
+ }
+ }
+
+ static int halfAvailable(State s) {
+ int limit = HALVES_CAPACITY;
+ if (s.endOfStreamReached != 0) {
+ limit = (s.tailBytes + (HALF_SIZE - 1)) >> LOG_HALF_SIZE;
+ }
+ return limit - s.halfOffset;
+ }
+
+ static void copyBytes(State s, byte[] data, int offset, int length) {
+ if ((s.bitOffset & 7) != 0) {
+ throw new BrotliRuntimeException("Unaligned copyBytes");
+ }
+
+ // Drain accumulator.
+ while ((s.bitOffset != BITNESS) && (length != 0)) {
+ data[offset++] = (byte) peekBits(s);
+ s.bitOffset += 8;
+ length--;
+ }
+ if (length == 0) {
+ return;
+ }
+
+ // Get data from shadow buffer with "sizeof(int)" granularity.
+ int copyNibbles = Math.min(halfAvailable(s), length >> LOG_HALF_SIZE);
+ if (copyNibbles > 0) {
+ int readOffset = s.halfOffset << LOG_HALF_SIZE;
+ int delta = copyNibbles << LOG_HALF_SIZE;
+ System.arraycopy(s.byteBuffer, readOffset, data, offset, delta);
+ offset += delta;
+ length -= delta;
+ s.halfOffset += copyNibbles;
+ }
+ if (length == 0) {
+ return;
+ }
+
+ // Read tail bytes.
+ if (halfAvailable(s) > 0) {
+ // length = 1..3
+ fillBitWindow(s);
+ while (length != 0) {
+ data[offset++] = (byte) peekBits(s);
+ s.bitOffset += 8;
+ length--;
+ }
+ checkHealth(s, 0);
+ return;
+ }
+
+ // Now it is possible to copy bytes directly.
+ while (length > 0) {
+ int len = Utils.readInput(s.input, data, offset, length);
+ if (len == -1) {
+ throw new BrotliRuntimeException("Unexpected end of input");
+ }
+ offset += len;
+ length -= len;
+ }
+ }
+
+ /**
+ * Translates bytes to halves (int/short).
+ */
+ static void bytesToNibbles(State s, int byteLen) {
+ byte[] byteBuffer = s.byteBuffer;
+ int halfLen = byteLen >> LOG_HALF_SIZE;
+ if (BITNESS == 64) {
+ int[] intBuffer = s.intBuffer;
+ for (int i = 0; i < halfLen; ++i) {
+ intBuffer[i] = ((byteBuffer[i * 4] & 0xFF))
+ | ((byteBuffer[(i * 4) + 1] & 0xFF) << 8)
+ | ((byteBuffer[(i * 4) + 2] & 0xFF) << 16)
+ | ((byteBuffer[(i * 4) + 3] & 0xFF) << 24);
+ }
+ } else {
+ short[] shortBuffer = s.shortBuffer;
+ for (int i = 0; i < halfLen; ++i) {
+ shortBuffer[i] = (short) ((byteBuffer[i * 2] & 0xFF)
+ | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8));
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReaderTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReaderTest.java
new file mode 100644
index 000000000..da59ebcea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BitReaderTest.java
@@ -0,0 +1,54 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link BitReader}.
+ */
+@RunWith(JUnit4.class)
+public class BitReaderTest {
+
+ @Test
+ public void testReadAfterEos() {
+ State reader = new State();
+ Decode.initState(reader, new ByteArrayInputStream(new byte[1]));
+ BitReader.readBits(reader, 9);
+ try {
+ BitReader.checkHealth(reader, 0);
+ } catch (BrotliRuntimeException ex) {
+ // This exception is expected.
+ return;
+ }
+ fail("BrotliRuntimeException should have been thrown by BitReader.checkHealth");
+ }
+
+ @Test
+ public void testAccumulatorUnderflowDetected() {
+ State reader = new State();
+ Decode.initState(reader, new ByteArrayInputStream(new byte[8]));
+ // 65 bits is enough for both 32 and 64 bit systems.
+ BitReader.readBits(reader, 13);
+ BitReader.readBits(reader, 13);
+ BitReader.readBits(reader, 13);
+ BitReader.readBits(reader, 13);
+ BitReader.readBits(reader, 13);
+ try {
+ BitReader.fillBitWindow(reader);
+ } catch (IllegalStateException ex) {
+ // This exception is expected.
+ return;
+ }
+ fail("IllegalStateException should have been thrown by 'broken' BitReader");
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliInputStream.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliInputStream.java
new file mode 100644
index 000000000..b99e40a26
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliInputStream.java
@@ -0,0 +1,160 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link InputStream} decorator that decompresses brotli data.
+ *
+ * <p> Not thread-safe.
+ */
+public class BrotliInputStream extends InputStream {
+
+ public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 256;
+
+ /**
+ * Internal buffer used for efficient byte-by-byte reading.
+ */
+ private byte[] buffer;
+
+ /**
+ * Number of decoded but still unused bytes in internal buffer.
+ */
+ private int remainingBufferBytes;
+
+ /**
+ * Next unused byte offset.
+ */
+ private int bufferOffset;
+
+ /**
+ * Decoder state.
+ */
+ private final State state = new State();
+
+ /**
+ * Creates a {@link InputStream} wrapper that decompresses brotli data.
+ *
+ * <p> For byte-by-byte reading ({@link #read()}) internal buffer with
+ * {@link #DEFAULT_INTERNAL_BUFFER_SIZE} size is allocated and used.
+ *
+ * <p> Will block the thread until first {@link BitReader#CAPACITY} bytes of data of source
+ * are available.
+ *
+ * @param source underlying data source
+ * @throws IOException in case of corrupted data or source stream problems
+ */
+ public BrotliInputStream(InputStream source) throws IOException {
+ this(source, DEFAULT_INTERNAL_BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a {@link InputStream} wrapper that decompresses brotli data.
+ *
+ * <p> For byte-by-byte reading ({@link #read()}) internal buffer of specified size is
+ * allocated and used.
+ *
+ * <p> Will block the thread until first {@link BitReader#CAPACITY} bytes of data of source
+ * are available.
+ *
+ * @param source compressed data source
+ * @param byteReadBufferSize size of internal buffer used in case of
+ * byte-by-byte reading
+ * @throws IOException in case of corrupted data or source stream problems
+ */
+ public BrotliInputStream(InputStream source, int byteReadBufferSize) throws IOException {
+ if (byteReadBufferSize <= 0) {
+ throw new IllegalArgumentException("Bad buffer size:" + byteReadBufferSize);
+ } else if (source == null) {
+ throw new IllegalArgumentException("source is null");
+ }
+ this.buffer = new byte[byteReadBufferSize];
+ this.remainingBufferBytes = 0;
+ this.bufferOffset = 0;
+ try {
+ Decode.initState(state, source);
+ } catch (BrotliRuntimeException ex) {
+ throw new IOException("Brotli decoder initialization failed", ex);
+ }
+ }
+
+ public void enableEagerOutput() {
+ Decode.enableEagerOutput(state);
+ }
+
+ public void enableLargeWindow() {
+ Decode.enableLargeWindow(state);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() throws IOException {
+ Decode.close(state);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read() throws IOException {
+ if (bufferOffset >= remainingBufferBytes) {
+ remainingBufferBytes = read(buffer, 0, buffer.length);
+ bufferOffset = 0;
+ if (remainingBufferBytes == -1) {
+ return -1;
+ }
+ }
+ return buffer[bufferOffset++] & 0xFF;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read(byte[] destBuffer, int destOffset, int destLen) throws IOException {
+ if (destOffset < 0) {
+ throw new IllegalArgumentException("Bad offset: " + destOffset);
+ } else if (destLen < 0) {
+ throw new IllegalArgumentException("Bad length: " + destLen);
+ } else if (destOffset + destLen > destBuffer.length) {
+ throw new IllegalArgumentException(
+ "Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.length);
+ } else if (destLen == 0) {
+ return 0;
+ }
+ int copyLen = Math.max(remainingBufferBytes - bufferOffset, 0);
+ if (copyLen != 0) {
+ copyLen = Math.min(copyLen, destLen);
+ System.arraycopy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
+ bufferOffset += copyLen;
+ destOffset += copyLen;
+ destLen -= copyLen;
+ if (destLen == 0) {
+ return copyLen;
+ }
+ }
+ try {
+ state.output = destBuffer;
+ state.outputOffset = destOffset;
+ state.outputLength = destLen;
+ state.outputUsed = 0;
+ Decode.decompress(state);
+ if (state.outputUsed == 0) {
+ return -1;
+ }
+ return state.outputUsed + copyLen;
+ } catch (BrotliRuntimeException ex) {
+ throw new IOException("Brotli stream decoding failed", ex);
+ }
+
+ // <{[INJECTED CODE]}>
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliRuntimeException.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliRuntimeException.java
new file mode 100644
index 000000000..184490722
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/BrotliRuntimeException.java
@@ -0,0 +1,21 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+/**
+ * Unchecked exception used internally.
+ */
+class BrotliRuntimeException extends RuntimeException {
+
+ BrotliRuntimeException(String message) {
+ super(message);
+ }
+
+ BrotliRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Context.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Context.java
new file mode 100644
index 000000000..d9f3f91f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Context.java
@@ -0,0 +1,58 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+/**
+ * Common context lookup table for all context modes.
+ */
+final class Context {
+
+ static final int[] LOOKUP = new int[2048];
+
+ private static final String UTF_MAP = " !! ! \"#$##%#$&'##(#)#+++++++++"
+ + "+((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# ";
+ private static final String UTF_RLE = "A/* ': & : $ \u0081 @";
+
+ private static void unpackLookupTable(int[] lookup, String map, String rle) {
+ // LSB6, MSB6, SIGNED
+ for (int i = 0; i < 256; ++i) {
+ lookup[i] = i & 0x3F;
+ lookup[512 + i] = i >> 2;
+ lookup[1792 + i] = 2 + (i >> 6);
+ }
+ // UTF8
+ for (int i = 0; i < 128; ++i) {
+ lookup[1024 + i] = 4 * (map.charAt(i) - 32);
+ }
+ for (int i = 0; i < 64; ++i) {
+ lookup[1152 + i] = i & 1;
+ lookup[1216 + i] = 2 + (i & 1);
+ }
+ int offset = 1280;
+ for (int k = 0; k < 19; ++k) {
+ int value = k & 3;
+ int rep = rle.charAt(k) - 32;
+ for (int i = 0; i < rep; ++i) {
+ lookup[offset++] = value;
+ }
+ }
+ // SIGNED
+ for (int i = 0; i < 16; ++i) {
+ lookup[1792 + i] = 1;
+ lookup[2032 + i] = 6;
+ }
+ lookup[1792] = 0;
+ lookup[2047] = 7;
+ for (int i = 0; i < 256; ++i) {
+ lookup[1536 + i] = lookup[1792 + i] << 3;
+ }
+ }
+
+ static {
+ unpackLookupTable(LOOKUP, UTF_MAP, UTF_RLE);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Decode.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Decode.java
new file mode 100644
index 000000000..560c635df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Decode.java
@@ -0,0 +1,1251 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * API for Brotli decompression.
+ */
+final class Decode {
+
+ static final int MIN_LARGE_WINDOW_BITS = 10;
+ /* Maximum was chosen to be 30 to allow efficient decoder implementation.
+ * Format allows bigger window, but Java does not support 2G+ arrays. */
+ static final int MAX_LARGE_WINDOW_BITS = 30;
+
+ //----------------------------------------------------------------------------
+ // RunningState
+ //----------------------------------------------------------------------------
+ private static final int UNINITIALIZED = 0;
+ private static final int INITIALIZED = 1;
+ private static final int BLOCK_START = 2;
+ private static final int COMPRESSED_BLOCK_START = 3;
+ private static final int MAIN_LOOP = 4;
+ private static final int READ_METADATA = 5;
+ private static final int COPY_UNCOMPRESSED = 6;
+ private static final int INSERT_LOOP = 7;
+ private static final int COPY_LOOP = 8;
+ private static final int TRANSFORM = 9;
+ private static final int FINISHED = 10;
+ private static final int CLOSED = 11;
+ private static final int INIT_WRITE = 12;
+ private static final int WRITE = 13;
+
+ private static final int DEFAULT_CODE_LENGTH = 8;
+ private static final int CODE_LENGTH_REPEAT_CODE = 16;
+ private static final int NUM_LITERAL_CODES = 256;
+ private static final int NUM_COMMAND_CODES = 704;
+ private static final int NUM_BLOCK_LENGTH_CODES = 26;
+ private static final int LITERAL_CONTEXT_BITS = 6;
+ private static final int DISTANCE_CONTEXT_BITS = 2;
+
+ private static final int HUFFMAN_TABLE_BITS = 8;
+ private static final int HUFFMAN_TABLE_MASK = 0xFF;
+
+ /**
+ * Maximum possible Huffman table size for an alphabet size of (index * 32),
+ * max code length 15 and root table bits 8.
+ * The biggest alphabet is "command" - 704 symbols. Though "distance" alphabet could theoretically
+ * outreach that limit (for 62 extra bit distances), practically it is limited by
+ * MAX_ALLOWED_DISTANCE and never gets bigger than 544 symbols.
+ */
+ static final int[] MAX_HUFFMAN_TABLE_SIZE = {
+ 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
+ 854, 886, 920, 952, 984, 1016, 1048, 1080
+ };
+
+ private static final int HUFFMAN_TABLE_SIZE_26 = 396;
+ private static final int HUFFMAN_TABLE_SIZE_258 = 632;
+
+ private static final int CODE_LENGTH_CODES = 18;
+ private static final int[] CODE_LENGTH_CODE_ORDER = {
+ 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ };
+
+ private static final int NUM_DISTANCE_SHORT_CODES = 16;
+ private static final int[] DISTANCE_SHORT_CODE_INDEX_OFFSET = {
+ 0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3
+ };
+
+ private static final int[] DISTANCE_SHORT_CODE_VALUE_OFFSET = {
+ 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
+ };
+
+ /**
+ * Static Huffman code for the code length code lengths.
+ */
+ private static final int[] FIXED_TABLE = {
+ 0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001,
+ 0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005
+ };
+
+ static final int[] DICTIONARY_OFFSETS_BY_LENGTH = {
+ 0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864,
+ 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, 122016
+ };
+
+ static final int[] DICTIONARY_SIZE_BITS_BY_LENGTH = {
+ 0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, 7, 6, 6, 5, 5
+ };
+
+ static final int MIN_WORD_LENGTH = 4;
+
+ static final int MAX_WORD_LENGTH = 24;
+
+ static final int MAX_TRANSFORMED_WORD_LENGTH = 5 + MAX_WORD_LENGTH + 8;
+
+ private static final int MAX_DISTANCE_BITS = 24;
+ private static final int MAX_LARGE_WINDOW_DISTANCE_BITS = 62;
+
+ /**
+ * Safe distance limit.
+ *
+ * Limit ((1 << 31) - 4) allows safe distance calculation without overflows,
+ * given the distance alphabet size is limited to corresponding size.
+ */
+ private static final int MAX_ALLOWED_DISTANCE = 0x7FFFFFFC;
+
+ //----------------------------------------------------------------------------
+ // Prefix code LUT.
+ //----------------------------------------------------------------------------
+ static final int[] BLOCK_LENGTH_OFFSET = {
+ 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497,
+ 753, 1265, 2289, 4337, 8433, 16625
+ };
+
+ static final int[] BLOCK_LENGTH_N_BITS = {
+ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24
+ };
+
+ static final short[] INSERT_LENGTH_N_BITS = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
+ 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18
+ };
+
+ static final short[] COPY_LENGTH_N_BITS = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
+ 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18
+ };
+
+ // Each command is represented with 4x16-bit values:
+ // * [insertLenExtraBits, copyLenExtraBits]
+ // * insertLenOffset
+ // * copyLenOffset
+ // * distanceContext
+ static final short[] CMD_LOOKUP = new short[NUM_COMMAND_CODES * 4];
+
+ static {
+ unpackCommandLookupTable(CMD_LOOKUP);
+ }
+
+ private static int log2floor(int i) {
+ int result = -1;
+ int step = 16;
+ while (step > 0) {
+ if ((i >>> step) != 0) {
+ result += step;
+ i = i >>> step;
+ }
+ step = step >> 1;
+ }
+ return result + i;
+ }
+
+ private static int calculateDistanceAlphabetSize(int npostfix, int ndirect, int maxndistbits) {
+ return NUM_DISTANCE_SHORT_CODES + ndirect + 2 * (maxndistbits << npostfix);
+ }
+
+ // TODO: add a correctness test for this function when
+ // large-window and dictionary are implemented.
+ private static int calculateDistanceAlphabetLimit(int maxDistance, int npostfix, int ndirect) {
+ if (maxDistance < ndirect + (2 << npostfix)) {
+ throw new IllegalArgumentException("maxDistance is too small");
+ }
+ int offset = ((maxDistance - ndirect) >> npostfix) + 4;
+ int ndistbits = log2floor(offset) - 1;
+ int group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1);
+ return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + NUM_DISTANCE_SHORT_CODES;
+ }
+
+ private static void unpackCommandLookupTable(short[] cmdLookup) {
+ short[] insertLengthOffsets = new short[24];
+ short[] copyLengthOffsets = new short[24];
+ copyLengthOffsets[0] = 2;
+ for (int i = 0; i < 23; ++i) {
+ insertLengthOffsets[i + 1] =
+ (short) (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]));
+ copyLengthOffsets[i + 1] =
+ (short) (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]));
+ }
+
+ for (int cmdCode = 0; cmdCode < NUM_COMMAND_CODES; ++cmdCode) {
+ int rangeIdx = cmdCode >>> 6;
+ /* -4 turns any regular distance code to negative. */
+ int distanceContextOffset = -4;
+ if (rangeIdx >= 2) {
+ rangeIdx -= 2;
+ distanceContextOffset = 0;
+ }
+ int insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
+ int copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
+ short copyLengthOffset = copyLengthOffsets[copyCode];
+ int distanceContext =
+ distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2);
+ int index = cmdCode * 4;
+ cmdLookup[index + 0] =
+ (short) (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8));
+ cmdLookup[index + 1] = insertLengthOffsets[insertCode];
+ cmdLookup[index + 2] = copyLengthOffsets[copyCode];
+ cmdLookup[index + 3] = (short) distanceContext;
+ }
+ }
+
+ /**
+ * Reads brotli stream header and parses "window bits".
+ *
+ * @param s initialized state, before any read is performed.
+ * @return -1 if header is invalid
+ */
+ private static int decodeWindowBits(State s) {
+ /* Change the meaning of flag. Before that step it means "decoder must be capable of reading
+ * "large-window" brotli stream. After this step it means that "large-window" feature
+ * is actually detected. Despite the window size could be same as before (lgwin = 10..24),
+ * encoded distances are allowed to be much greater, thus bigger dictinary could be used. */
+ int largeWindowEnabled = s.isLargeWindow;
+ s.isLargeWindow = 0;
+
+ BitReader.fillBitWindow(s);
+ if (BitReader.readFewBits(s, 1) == 0) {
+ return 16;
+ }
+ int n = BitReader.readFewBits(s, 3);
+ if (n != 0) {
+ return 17 + n;
+ }
+ n = BitReader.readFewBits(s, 3);
+ if (n != 0) {
+ if (n == 1) {
+ if (largeWindowEnabled == 0) {
+ /* Reserved value in regular brotli stream. */
+ return -1;
+ }
+ s.isLargeWindow = 1;
+ /* Check "reserved" bit for future (post-large-window) extensions. */
+ if (BitReader.readFewBits(s, 1) == 1) {
+ return -1;
+ }
+ n = BitReader.readFewBits(s, 6);
+ if (n < MIN_LARGE_WINDOW_BITS || n > MAX_LARGE_WINDOW_BITS) {
+ /* Encoded window bits value is too small or too big. */
+ return -1;
+ }
+ return n;
+ } else {
+ return 8 + n;
+ }
+ }
+ return 17;
+ }
+
+ /**
+ * Switch decoder to "eager" mode.
+ *
+ * In "eager" mode decoder returns as soon as there is enough data to fill output buffer.
+ *
+ * @param s initialized state, before any read is performed.
+ */
+ static void enableEagerOutput(State s) {
+ if (s.runningState != INITIALIZED) {
+ throw new IllegalStateException("State MUST be freshly initialized");
+ }
+ s.isEager = 1;
+ }
+
+ static void enableLargeWindow(State s) {
+ if (s.runningState != INITIALIZED) {
+ throw new IllegalStateException("State MUST be freshly initialized");
+ }
+ s.isLargeWindow = 1;
+ }
+
+ /**
+ * Associate input with decoder state.
+ *
+ * @param s uninitialized state without associated input
+ * @param input compressed data source
+ */
+ static void initState(State s, InputStream input) {
+ if (s.runningState != UNINITIALIZED) {
+ throw new IllegalStateException("State MUST be uninitialized");
+ }
+ /* 6 trees + 1 extra "offset" slot to simplify table decoding logic. */
+ s.blockTrees = new int[7 + 3 * (HUFFMAN_TABLE_SIZE_258 + HUFFMAN_TABLE_SIZE_26)];
+ s.blockTrees[0] = 7;
+ s.distRbIdx = 3;
+ int maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(MAX_ALLOWED_DISTANCE, 3, 15 << 3);
+ s.distExtraBits = new byte[maxDistanceAlphabetLimit];
+ s.distOffset = new int[maxDistanceAlphabetLimit];
+ s.input = input;
+ BitReader.initBitReader(s);
+ s.runningState = INITIALIZED;
+ }
+
+ static void close(State s) throws IOException {
+ if (s.runningState == UNINITIALIZED) {
+ throw new IllegalStateException("State MUST be initialized");
+ }
+ if (s.runningState == CLOSED) {
+ return;
+ }
+ s.runningState = CLOSED;
+ if (s.input != null) {
+ Utils.closeInput(s.input);
+ s.input = null;
+ }
+ }
+
+ /**
+ * Decodes a number in the range [0..255], by reading 1 - 11 bits.
+ */
+ private static int decodeVarLenUnsignedByte(State s) {
+ BitReader.fillBitWindow(s);
+ if (BitReader.readFewBits(s, 1) != 0) {
+ int n = BitReader.readFewBits(s, 3);
+ if (n == 0) {
+ return 1;
+ } else {
+ return BitReader.readFewBits(s, n) + (1 << n);
+ }
+ }
+ return 0;
+ }
+
+ private static void decodeMetaBlockLength(State s) {
+ BitReader.fillBitWindow(s);
+ s.inputEnd = BitReader.readFewBits(s, 1);
+ s.metaBlockLength = 0;
+ s.isUncompressed = 0;
+ s.isMetadata = 0;
+ if ((s.inputEnd != 0) && BitReader.readFewBits(s, 1) != 0) {
+ return;
+ }
+ int sizeNibbles = BitReader.readFewBits(s, 2) + 4;
+ if (sizeNibbles == 7) {
+ s.isMetadata = 1;
+ if (BitReader.readFewBits(s, 1) != 0) {
+ throw new BrotliRuntimeException("Corrupted reserved bit");
+ }
+ int sizeBytes = BitReader.readFewBits(s, 2);
+ if (sizeBytes == 0) {
+ return;
+ }
+ for (int i = 0; i < sizeBytes; i++) {
+ BitReader.fillBitWindow(s);
+ int bits = BitReader.readFewBits(s, 8);
+ if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
+ throw new BrotliRuntimeException("Exuberant nibble");
+ }
+ s.metaBlockLength |= bits << (i * 8);
+ }
+ } else {
+ for (int i = 0; i < sizeNibbles; i++) {
+ BitReader.fillBitWindow(s);
+ int bits = BitReader.readFewBits(s, 4);
+ if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
+ throw new BrotliRuntimeException("Exuberant nibble");
+ }
+ s.metaBlockLength |= bits << (i * 4);
+ }
+ }
+ s.metaBlockLength++;
+ if (s.inputEnd == 0) {
+ s.isUncompressed = BitReader.readFewBits(s, 1);
+ }
+ }
+
+ /**
+ * Decodes the next Huffman code from bit-stream.
+ */
+ private static int readSymbol(int[] tableGroup, int tableIdx, State s) {
+ int offset = tableGroup[tableIdx];
+ int val = BitReader.peekBits(s);
+ offset += val & HUFFMAN_TABLE_MASK;
+ int bits = tableGroup[offset] >> 16;
+ int sym = tableGroup[offset] & 0xFFFF;
+ if (bits <= HUFFMAN_TABLE_BITS) {
+ s.bitOffset += bits;
+ return sym;
+ }
+ offset += sym;
+ int mask = (1 << bits) - 1;
+ offset += (val & mask) >>> HUFFMAN_TABLE_BITS;
+ s.bitOffset += ((tableGroup[offset] >> 16) + HUFFMAN_TABLE_BITS);
+ return tableGroup[offset] & 0xFFFF;
+ }
+
+ private static int readBlockLength(int[] tableGroup, int tableIdx, State s) {
+ BitReader.fillBitWindow(s);
+ int code = readSymbol(tableGroup, tableIdx, s);
+ int n = BLOCK_LENGTH_N_BITS[code];
+ BitReader.fillBitWindow(s);
+ return BLOCK_LENGTH_OFFSET[code] + BitReader.readBits(s, n);
+ }
+
+ private static void moveToFront(int[] v, int index) {
+ int value = v[index];
+ for (; index > 0; index--) {
+ v[index] = v[index - 1];
+ }
+ v[0] = value;
+ }
+
+ private static void inverseMoveToFrontTransform(byte[] v, int vLen) {
+ int[] mtf = new int[256];
+ for (int i = 0; i < 256; i++) {
+ mtf[i] = i;
+ }
+ for (int i = 0; i < vLen; i++) {
+ int index = v[i] & 0xFF;
+ v[i] = (byte) mtf[index];
+ if (index != 0) {
+ moveToFront(mtf, index);
+ }
+ }
+ }
+
+ private static void readHuffmanCodeLengths(
+ int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, State s) {
+ int symbol = 0;
+ int prevCodeLen = DEFAULT_CODE_LENGTH;
+ int repeat = 0;
+ int repeatCodeLen = 0;
+ int space = 32768;
+ int[] table = new int[32 + 1]; /* Speculative single entry table group. */
+ int tableIdx = table.length - 1;
+ Huffman.buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, CODE_LENGTH_CODES);
+
+ while (symbol < numSymbols && space > 0) {
+ BitReader.readMoreInput(s);
+ BitReader.fillBitWindow(s);
+ int p = BitReader.peekBits(s) & 31;
+ s.bitOffset += table[p] >> 16;
+ int codeLen = table[p] & 0xFFFF;
+ if (codeLen < CODE_LENGTH_REPEAT_CODE) {
+ repeat = 0;
+ codeLengths[symbol++] = codeLen;
+ if (codeLen != 0) {
+ prevCodeLen = codeLen;
+ space -= 32768 >> codeLen;
+ }
+ } else {
+ int extraBits = codeLen - 14;
+ int newLen = 0;
+ if (codeLen == CODE_LENGTH_REPEAT_CODE) {
+ newLen = prevCodeLen;
+ }
+ if (repeatCodeLen != newLen) {
+ repeat = 0;
+ repeatCodeLen = newLen;
+ }
+ int oldRepeat = repeat;
+ if (repeat > 0) {
+ repeat -= 2;
+ repeat <<= extraBits;
+ }
+ BitReader.fillBitWindow(s);
+ repeat += BitReader.readFewBits(s, extraBits) + 3;
+ int repeatDelta = repeat - oldRepeat;
+ if (symbol + repeatDelta > numSymbols) {
+ throw new BrotliRuntimeException("symbol + repeatDelta > numSymbols"); // COV_NF_LINE
+ }
+ for (int i = 0; i < repeatDelta; i++) {
+ codeLengths[symbol++] = repeatCodeLen;
+ }
+ if (repeatCodeLen != 0) {
+ space -= repeatDelta << (15 - repeatCodeLen);
+ }
+ }
+ }
+ if (space != 0) {
+ throw new BrotliRuntimeException("Unused space"); // COV_NF_LINE
+ }
+ // TODO: Pass max_symbol to Huffman table builder instead?
+ Utils.fillIntsWithZeroes(codeLengths, symbol, numSymbols);
+ }
+
+ private static void checkDupes(int[] symbols, int length) {
+ for (int i = 0; i < length - 1; ++i) {
+ for (int j = i + 1; j < length; ++j) {
+ if (symbols[i] == symbols[j]) {
+ throw new BrotliRuntimeException("Duplicate simple Huffman code symbol"); // COV_NF_LINE
+ }
+ }
+ }
+ }
+
+ /**
+ * Reads up to 4 symbols directly and applies predefined histograms.
+ */
+ private static int readSimpleHuffmanCode(int alphabetSizeMax, int alphabetSizeLimit,
+ int[] tableGroup, int tableIdx, State s) {
+ // TODO: Avoid allocation?
+ int[] codeLengths = new int[alphabetSizeLimit];
+ int[] symbols = new int[4];
+
+ int maxBits = 1 + log2floor(alphabetSizeMax - 1);
+
+ int numSymbols = BitReader.readFewBits(s, 2) + 1;
+ for (int i = 0; i < numSymbols; i++) {
+ BitReader.fillBitWindow(s);
+ int symbol = BitReader.readFewBits(s, maxBits);
+ if (symbol >= alphabetSizeLimit) {
+ throw new BrotliRuntimeException("Can't readHuffmanCode"); // COV_NF_LINE
+ }
+ symbols[i] = symbol;
+ }
+ checkDupes(symbols, numSymbols);
+
+ int histogramId = numSymbols;
+ if (numSymbols == 4) {
+ histogramId += BitReader.readFewBits(s, 1);
+ }
+
+ switch (histogramId) {
+ case 1:
+ codeLengths[symbols[0]] = 1;
+ break;
+
+ case 2:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 1;
+ break;
+
+ case 3:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ break;
+
+ case 4: // uniform 4-symbol histogram
+ codeLengths[symbols[0]] = 2;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ codeLengths[symbols[3]] = 2;
+ break;
+
+ case 5: // prioritized 4-symbol histogram
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 3;
+ codeLengths[symbols[3]] = 3;
+ break;
+
+ default:
+ break;
+ }
+
+ // TODO: Use specialized version?
+ return Huffman.buildHuffmanTable(
+ tableGroup, tableIdx, HUFFMAN_TABLE_BITS, codeLengths, alphabetSizeLimit);
+ }
+
+ // Decode Huffman-coded code lengths.
+ private static int readComplexHuffmanCode(int alphabetSizeLimit, int skip,
+ int[] tableGroup, int tableIdx, State s) {
+ // TODO: Avoid allocation?
+ int[] codeLengths = new int[alphabetSizeLimit];
+ int[] codeLengthCodeLengths = new int[CODE_LENGTH_CODES];
+ int space = 32;
+ int numCodes = 0;
+ for (int i = skip; i < CODE_LENGTH_CODES && space > 0; i++) {
+ int codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
+ BitReader.fillBitWindow(s);
+ int p = BitReader.peekBits(s) & 15;
+ // TODO: Demultiplex FIXED_TABLE.
+ s.bitOffset += FIXED_TABLE[p] >> 16;
+ int v = FIXED_TABLE[p] & 0xFFFF;
+ codeLengthCodeLengths[codeLenIdx] = v;
+ if (v != 0) {
+ space -= (32 >> v);
+ numCodes++;
+ }
+ }
+ if (space != 0 && numCodes != 1) {
+ throw new BrotliRuntimeException("Corrupted Huffman code histogram"); // COV_NF_LINE
+ }
+
+ readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSizeLimit, codeLengths, s);
+
+ return Huffman.buildHuffmanTable(
+ tableGroup, tableIdx, HUFFMAN_TABLE_BITS, codeLengths, alphabetSizeLimit);
+ }
+
+ /**
+ * Decodes Huffman table from bit-stream.
+ *
+ * @return number of slots used by resulting Huffman table
+ */
+ private static int readHuffmanCode(int alphabetSizeMax, int alphabetSizeLimit,
+ int[] tableGroup, int tableIdx, State s) {
+ BitReader.readMoreInput(s);
+ BitReader.fillBitWindow(s);
+ int simpleCodeOrSkip = BitReader.readFewBits(s, 2);
+ if (simpleCodeOrSkip == 1) {
+ return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s);
+ } else {
+ return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s);
+ }
+ }
+
+ private static int decodeContextMap(int contextMapSize, byte[] contextMap, State s) {
+ BitReader.readMoreInput(s);
+ int numTrees = decodeVarLenUnsignedByte(s) + 1;
+
+ if (numTrees == 1) {
+ Utils.fillBytesWithZeroes(contextMap, 0, contextMapSize);
+ return numTrees;
+ }
+
+ BitReader.fillBitWindow(s);
+ int useRleForZeros = BitReader.readFewBits(s, 1);
+ int maxRunLengthPrefix = 0;
+ if (useRleForZeros != 0) {
+ maxRunLengthPrefix = BitReader.readFewBits(s, 4) + 1;
+ }
+ int alphabetSize = numTrees + maxRunLengthPrefix;
+ int tableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSize + 31) >> 5];
+ /* Speculative single entry table group. */
+ int[] table = new int[tableSize + 1];
+ int tableIdx = table.length - 1;
+ readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
+ for (int i = 0; i < contextMapSize; ) {
+ BitReader.readMoreInput(s);
+ BitReader.fillBitWindow(s);
+ int code = readSymbol(table, tableIdx, s);
+ if (code == 0) {
+ contextMap[i] = 0;
+ i++;
+ } else if (code <= maxRunLengthPrefix) {
+ BitReader.fillBitWindow(s);
+ int reps = (1 << code) + BitReader.readFewBits(s, code);
+ while (reps != 0) {
+ if (i >= contextMapSize) {
+ throw new BrotliRuntimeException("Corrupted context map"); // COV_NF_LINE
+ }
+ contextMap[i] = 0;
+ i++;
+ reps--;
+ }
+ } else {
+ contextMap[i] = (byte) (code - maxRunLengthPrefix);
+ i++;
+ }
+ }
+ BitReader.fillBitWindow(s);
+ if (BitReader.readFewBits(s, 1) == 1) {
+ inverseMoveToFrontTransform(contextMap, contextMapSize);
+ }
+ return numTrees;
+ }
+
+ private static int decodeBlockTypeAndLength(State s, int treeType, int numBlockTypes) {
+ final int[] ringBuffers = s.rings;
+ final int offset = 4 + treeType * 2;
+ BitReader.fillBitWindow(s);
+ int blockType = readSymbol(s.blockTrees, 2 * treeType, s);
+ int result = readBlockLength(s.blockTrees, 2 * treeType + 1, s);
+
+ if (blockType == 1) {
+ blockType = ringBuffers[offset + 1] + 1;
+ } else if (blockType == 0) {
+ blockType = ringBuffers[offset];
+ } else {
+ blockType -= 2;
+ }
+ if (blockType >= numBlockTypes) {
+ blockType -= numBlockTypes;
+ }
+ ringBuffers[offset] = ringBuffers[offset + 1];
+ ringBuffers[offset + 1] = blockType;
+ return result;
+ }
+
+ private static void decodeLiteralBlockSwitch(State s) {
+ s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);
+ int literalBlockType = s.rings[5];
+ s.contextMapSlice = literalBlockType << LITERAL_CONTEXT_BITS;
+ s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xFF;
+ int contextMode = s.contextModes[literalBlockType];
+ s.contextLookupOffset1 = contextMode << 9;
+ s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
+ }
+
+ private static void decodeCommandBlockSwitch(State s) {
+ s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes);
+ s.commandTreeIdx = s.rings[7];
+ }
+
+ private static void decodeDistanceBlockSwitch(State s) {
+ s.distanceBlockLength = decodeBlockTypeAndLength(s, 2, s.numDistanceBlockTypes);
+ s.distContextMapSlice = s.rings[9] << DISTANCE_CONTEXT_BITS;
+ }
+
+ private static void maybeReallocateRingBuffer(State s) {
+ int newSize = s.maxRingBufferSize;
+ if (newSize > s.expectedTotalSize) {
+ /* TODO: Handle 2GB+ cases more gracefully. */
+ int minimalNewSize = s.expectedTotalSize;
+ while ((newSize >> 1) > minimalNewSize) {
+ newSize >>= 1;
+ }
+ if ((s.inputEnd == 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
+ newSize = 16384;
+ }
+ }
+ if (newSize <= s.ringBufferSize) {
+ return;
+ }
+ int ringBufferSizeWithSlack = newSize + MAX_TRANSFORMED_WORD_LENGTH;
+ byte[] newBuffer = new byte[ringBufferSizeWithSlack];
+ if (s.ringBuffer.length != 0) {
+ System.arraycopy(s.ringBuffer, 0, newBuffer, 0, s.ringBufferSize);
+ }
+ s.ringBuffer = newBuffer;
+ s.ringBufferSize = newSize;
+ }
+
+ private static void readNextMetablockHeader(State s) {
+ if (s.inputEnd != 0) {
+ s.nextRunningState = FINISHED;
+ s.runningState = INIT_WRITE;
+ return;
+ }
+ // TODO: Reset? Do we need this?
+ s.literalTreeGroup = new int[0];
+ s.commandTreeGroup = new int[0];
+ s.distanceTreeGroup = new int[0];
+
+ BitReader.readMoreInput(s);
+ decodeMetaBlockLength(s);
+ if ((s.metaBlockLength == 0) && (s.isMetadata == 0)) {
+ return;
+ }
+ if ((s.isUncompressed != 0) || (s.isMetadata != 0)) {
+ BitReader.jumpToByteBoundary(s);
+ s.runningState = (s.isMetadata != 0) ? READ_METADATA : COPY_UNCOMPRESSED;
+ } else {
+ s.runningState = COMPRESSED_BLOCK_START;
+ }
+
+ if (s.isMetadata != 0) {
+ return;
+ }
+ s.expectedTotalSize += s.metaBlockLength;
+ if (s.expectedTotalSize > 1 << 30) {
+ s.expectedTotalSize = 1 << 30;
+ }
+ if (s.ringBufferSize < s.maxRingBufferSize) {
+ maybeReallocateRingBuffer(s);
+ }
+ }
+
+ private static int readMetablockPartition(State s, int treeType, int numBlockTypes) {
+ int offset = s.blockTrees[2 * treeType];
+ if (numBlockTypes <= 1) {
+ s.blockTrees[2 * treeType + 1] = offset;
+ s.blockTrees[2 * treeType + 2] = offset;
+ return 1 << 28;
+ }
+
+ int blockTypeAlphabetSize = numBlockTypes + 2;
+ offset += readHuffmanCode(
+ blockTypeAlphabetSize, blockTypeAlphabetSize, s.blockTrees, 2 * treeType, s);
+ s.blockTrees[2 * treeType + 1] = offset;
+
+ int blockLengthAlphabetSize = NUM_BLOCK_LENGTH_CODES;
+ offset += readHuffmanCode(
+ blockLengthAlphabetSize, blockLengthAlphabetSize, s.blockTrees, 2 * treeType + 1, s);
+ s.blockTrees[2 * treeType + 2] = offset;
+
+ return readBlockLength(s.blockTrees, 2 * treeType + 1, s);
+ }
+
+ private static void calculateDistanceLut(State s, int alphabetSizeLimit) {
+ byte[] distExtraBits = s.distExtraBits;
+ int[] distOffset = s.distOffset;
+ int npostfix = s.distancePostfixBits;
+ int ndirect = s.numDirectDistanceCodes;
+ int postfix = 1 << npostfix;
+ int bits = 1;
+ int half = 0;
+
+ /* Skip short codes. */
+ int i = NUM_DISTANCE_SHORT_CODES;
+
+ /* Fill direct codes. */
+ for (int j = 0; j < ndirect; ++j) {
+ distExtraBits[i] = 0;
+ distOffset[i] = j + 1;
+ ++i;
+ }
+
+ /* Fill regular distance codes. */
+ while (i < alphabetSizeLimit) {
+ int base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
+ /* Always fill the complete group. */
+ for (int j = 0; j < postfix; ++j) {
+ distExtraBits[i] = (byte) bits;
+ distOffset[i] = base + j;
+ ++i;
+ }
+ bits = bits + half;
+ half = half ^ 1;
+ }
+ }
+
+ private static void readMetablockHuffmanCodesAndContextMaps(State s) {
+ s.numLiteralBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.literalBlockLength = readMetablockPartition(s, 0, s.numLiteralBlockTypes);
+ s.numCommandBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.commandBlockLength = readMetablockPartition(s, 1, s.numCommandBlockTypes);
+ s.numDistanceBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.distanceBlockLength = readMetablockPartition(s, 2, s.numDistanceBlockTypes);
+
+ BitReader.readMoreInput(s);
+ BitReader.fillBitWindow(s);
+ s.distancePostfixBits = BitReader.readFewBits(s, 2);
+ s.numDirectDistanceCodes = BitReader.readFewBits(s, 4) << s.distancePostfixBits;
+ s.distancePostfixMask = (1 << s.distancePostfixBits) - 1;
+ // TODO: Reuse?
+ s.contextModes = new byte[s.numLiteralBlockTypes];
+ for (int i = 0; i < s.numLiteralBlockTypes;) {
+ /* Ensure that less than 256 bits read between readMoreInput. */
+ int limit = Math.min(i + 96, s.numLiteralBlockTypes);
+ for (; i < limit; ++i) {
+ BitReader.fillBitWindow(s);
+ s.contextModes[i] = (byte) BitReader.readFewBits(s, 2);
+ }
+ BitReader.readMoreInput(s);
+ }
+
+ // TODO: Reuse?
+ s.contextMap = new byte[s.numLiteralBlockTypes << LITERAL_CONTEXT_BITS];
+ int numLiteralTrees = decodeContextMap(s.numLiteralBlockTypes << LITERAL_CONTEXT_BITS,
+ s.contextMap, s);
+ s.trivialLiteralContext = 1;
+ for (int j = 0; j < s.numLiteralBlockTypes << LITERAL_CONTEXT_BITS; j++) {
+ if (s.contextMap[j] != j >> LITERAL_CONTEXT_BITS) {
+ s.trivialLiteralContext = 0;
+ break;
+ }
+ }
+
+ // TODO: Reuse?
+ s.distContextMap = new byte[s.numDistanceBlockTypes << DISTANCE_CONTEXT_BITS];
+ int numDistTrees = decodeContextMap(s.numDistanceBlockTypes << DISTANCE_CONTEXT_BITS,
+ s.distContextMap, s);
+
+ s.literalTreeGroup = decodeHuffmanTreeGroup(NUM_LITERAL_CODES, NUM_LITERAL_CODES,
+ numLiteralTrees, s);
+ s.commandTreeGroup = decodeHuffmanTreeGroup(NUM_COMMAND_CODES, NUM_COMMAND_CODES,
+ s.numCommandBlockTypes, s);
+ int distanceAlphabetSizeMax = calculateDistanceAlphabetSize(
+ s.distancePostfixBits, s.numDirectDistanceCodes, MAX_DISTANCE_BITS);
+ int distanceAlphabetSizeLimit = distanceAlphabetSizeMax;
+ if (s.isLargeWindow == 1) {
+ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(
+ s.distancePostfixBits, s.numDirectDistanceCodes, MAX_LARGE_WINDOW_DISTANCE_BITS);
+ distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit(
+ MAX_ALLOWED_DISTANCE, s.distancePostfixBits, s.numDirectDistanceCodes);
+ }
+ s.distanceTreeGroup = decodeHuffmanTreeGroup(distanceAlphabetSizeMax, distanceAlphabetSizeLimit,
+ numDistTrees, s);
+ calculateDistanceLut(s, distanceAlphabetSizeLimit);
+
+ s.contextMapSlice = 0;
+ s.distContextMapSlice = 0;
+ s.contextLookupOffset1 = s.contextModes[0] * 512;
+ s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
+ s.literalTreeIdx = 0;
+ s.commandTreeIdx = 0;
+
+ s.rings[4] = 1;
+ s.rings[5] = 0;
+ s.rings[6] = 1;
+ s.rings[7] = 0;
+ s.rings[8] = 1;
+ s.rings[9] = 0;
+ }
+
+ private static void copyUncompressedData(State s) {
+ final byte[] ringBuffer = s.ringBuffer;
+
+ // Could happen if block ends at ring buffer end.
+ if (s.metaBlockLength <= 0) {
+ BitReader.reload(s);
+ s.runningState = BLOCK_START;
+ return;
+ }
+
+ int chunkLength = Math.min(s.ringBufferSize - s.pos, s.metaBlockLength);
+ BitReader.copyBytes(s, ringBuffer, s.pos, chunkLength);
+ s.metaBlockLength -= chunkLength;
+ s.pos += chunkLength;
+ if (s.pos == s.ringBufferSize) {
+ s.nextRunningState = COPY_UNCOMPRESSED;
+ s.runningState = INIT_WRITE;
+ return;
+ }
+
+ BitReader.reload(s);
+ s.runningState = BLOCK_START;
+ }
+
+ private static int writeRingBuffer(State s) {
+ int toWrite = Math.min(s.outputLength - s.outputUsed,
+ s.ringBufferBytesReady - s.ringBufferBytesWritten);
+ if (toWrite != 0) {
+ System.arraycopy(s.ringBuffer, s.ringBufferBytesWritten, s.output,
+ s.outputOffset + s.outputUsed, toWrite);
+ s.outputUsed += toWrite;
+ s.ringBufferBytesWritten += toWrite;
+ }
+
+ if (s.outputUsed < s.outputLength) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ private static int[] decodeHuffmanTreeGroup(int alphabetSizeMax, int alphabetSizeLimit,
+ int n, State s) {
+ int maxTableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSizeLimit + 31) >> 5];
+ int[] group = new int[n + n * maxTableSize];
+ int next = n;
+ for (int i = 0; i < n; ++i) {
+ group[i] = next;
+ next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s);
+ }
+ return group;
+ }
+
+ // Returns offset in ringBuffer that should trigger WRITE when filled.
+ private static int calculateFence(State s) {
+ int result = s.ringBufferSize;
+ if (s.isEager != 0) {
+ result = Math.min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed);
+ }
+ return result;
+ }
+
+ /**
+ * Actual decompress implementation.
+ */
+ static void decompress(State s) {
+ if (s.runningState == UNINITIALIZED) {
+ throw new IllegalStateException("Can't decompress until initialized");
+ }
+ if (s.runningState == CLOSED) {
+ throw new IllegalStateException("Can't decompress after close");
+ }
+ if (s.runningState == INITIALIZED) {
+ int windowBits = decodeWindowBits(s);
+ if (windowBits == -1) { /* Reserved case for future expansion. */
+ throw new BrotliRuntimeException("Invalid 'windowBits' code");
+ }
+ s.maxRingBufferSize = 1 << windowBits;
+ s.maxBackwardDistance = s.maxRingBufferSize - 16;
+ s.runningState = BLOCK_START;
+ }
+
+ int fence = calculateFence(s);
+ int ringBufferMask = s.ringBufferSize - 1;
+ byte[] ringBuffer = s.ringBuffer;
+
+ while (s.runningState != FINISHED) {
+ // TODO: extract cases to methods for the better readability.
+ switch (s.runningState) {
+ case BLOCK_START:
+ if (s.metaBlockLength < 0) {
+ throw new BrotliRuntimeException("Invalid metablock length");
+ }
+ readNextMetablockHeader(s);
+ /* Ring-buffer would be reallocated here. */
+ fence = calculateFence(s);
+ ringBufferMask = s.ringBufferSize - 1;
+ ringBuffer = s.ringBuffer;
+ continue;
+
+ case COMPRESSED_BLOCK_START:
+ readMetablockHuffmanCodesAndContextMaps(s);
+ s.runningState = MAIN_LOOP;
+ // Fall through
+
+ case MAIN_LOOP:
+ if (s.metaBlockLength <= 0) {
+ s.runningState = BLOCK_START;
+ continue;
+ }
+ BitReader.readMoreInput(s);
+ if (s.commandBlockLength == 0) {
+ decodeCommandBlockSwitch(s);
+ }
+ s.commandBlockLength--;
+ BitReader.fillBitWindow(s);
+ int cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2;
+ short insertAndCopyExtraBits = CMD_LOOKUP[cmdCode];
+ int insertLengthOffset = CMD_LOOKUP[cmdCode + 1];
+ int copyLengthOffset = CMD_LOOKUP[cmdCode + 2];
+ s.distanceCode = CMD_LOOKUP[cmdCode + 3];
+ BitReader.fillBitWindow(s);
+ {
+ int extraBits = insertAndCopyExtraBits & 0xFF;
+ s.insertLength = insertLengthOffset + BitReader.readBits(s, extraBits);
+ }
+ BitReader.fillBitWindow(s);
+ {
+ int extraBits = insertAndCopyExtraBits >> 8;
+ s.copyLength = copyLengthOffset + BitReader.readBits(s, extraBits);
+ }
+
+ s.j = 0;
+ s.runningState = INSERT_LOOP;
+
+ // Fall through
+ case INSERT_LOOP:
+ if (s.trivialLiteralContext != 0) {
+ while (s.j < s.insertLength) {
+ BitReader.readMoreInput(s);
+ if (s.literalBlockLength == 0) {
+ decodeLiteralBlockSwitch(s);
+ }
+ s.literalBlockLength--;
+ BitReader.fillBitWindow(s);
+ ringBuffer[s.pos] = (byte) readSymbol(s.literalTreeGroup, s.literalTreeIdx, s);
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = INSERT_LOOP;
+ s.runningState = INIT_WRITE;
+ break;
+ }
+ }
+ } else {
+ int prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF;
+ int prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF;
+ while (s.j < s.insertLength) {
+ BitReader.readMoreInput(s);
+ if (s.literalBlockLength == 0) {
+ decodeLiteralBlockSwitch(s);
+ }
+ int literalContext = Context.LOOKUP[s.contextLookupOffset1 + prevByte1]
+ | Context.LOOKUP[s.contextLookupOffset2 + prevByte2];
+ int literalTreeIdx = s.contextMap[s.contextMapSlice + literalContext] & 0xFF;
+ s.literalBlockLength--;
+ prevByte2 = prevByte1;
+ BitReader.fillBitWindow(s);
+ prevByte1 = readSymbol(s.literalTreeGroup, literalTreeIdx, s);
+ ringBuffer[s.pos] = (byte) prevByte1;
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = INSERT_LOOP;
+ s.runningState = INIT_WRITE;
+ break;
+ }
+ }
+ }
+ if (s.runningState != INSERT_LOOP) {
+ continue;
+ }
+ s.metaBlockLength -= s.insertLength;
+ if (s.metaBlockLength <= 0) {
+ s.runningState = MAIN_LOOP;
+ continue;
+ }
+ int distanceCode = s.distanceCode;
+ if (distanceCode < 0) {
+ // distanceCode in untouched; assigning it 0 won't affect distance ring buffer rolling.
+ s.distance = s.rings[s.distRbIdx];
+ } else {
+ BitReader.readMoreInput(s);
+ if (s.distanceBlockLength == 0) {
+ decodeDistanceBlockSwitch(s);
+ }
+ s.distanceBlockLength--;
+ BitReader.fillBitWindow(s);
+ int distTreeIdx = s.distContextMap[s.distContextMapSlice + distanceCode] & 0xFF;
+ distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s);
+ if (distanceCode < NUM_DISTANCE_SHORT_CODES) {
+ int index = (s.distRbIdx + DISTANCE_SHORT_CODE_INDEX_OFFSET[distanceCode]) & 0x3;
+ s.distance = s.rings[index] + DISTANCE_SHORT_CODE_VALUE_OFFSET[distanceCode];
+ if (s.distance < 0) {
+ throw new BrotliRuntimeException("Negative distance"); // COV_NF_LINE
+ }
+ } else {
+ int extraBits = s.distExtraBits[distanceCode];
+ int bits;
+ if (s.bitOffset + extraBits <= BitReader.BITNESS) {
+ bits = BitReader.readFewBits(s, extraBits);
+ } else {
+ BitReader.fillBitWindow(s);
+ bits = BitReader.readBits(s, extraBits);
+ }
+ s.distance = s.distOffset[distanceCode] + (bits << s.distancePostfixBits);
+ }
+ }
+
+ if (s.maxDistance != s.maxBackwardDistance
+ && s.pos < s.maxBackwardDistance) {
+ s.maxDistance = s.pos;
+ } else {
+ s.maxDistance = s.maxBackwardDistance;
+ }
+
+ if (s.distance > s.maxDistance) {
+ s.runningState = TRANSFORM;
+ continue;
+ }
+
+ if (distanceCode > 0) {
+ s.distRbIdx = (s.distRbIdx + 1) & 0x3;
+ s.rings[s.distRbIdx] = s.distance;
+ }
+
+ if (s.copyLength > s.metaBlockLength) {
+ throw new BrotliRuntimeException("Invalid backward reference"); // COV_NF_LINE
+ }
+ s.j = 0;
+ s.runningState = COPY_LOOP;
+ // fall through
+ case COPY_LOOP:
+ int src = (s.pos - s.distance) & ringBufferMask;
+ int dst = s.pos;
+ int copyLength = s.copyLength - s.j;
+ int srcEnd = src + copyLength;
+ int dstEnd = dst + copyLength;
+ if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
+ if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
+ for (int k = 0; k < copyLength; k += 4) {
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ }
+ } else {
+ Utils.copyBytesWithin(ringBuffer, dst, src, srcEnd);
+ }
+ s.j += copyLength;
+ s.metaBlockLength -= copyLength;
+ s.pos += copyLength;
+ } else {
+ for (; s.j < s.copyLength;) {
+ ringBuffer[s.pos] =
+ ringBuffer[(s.pos - s.distance) & ringBufferMask];
+ s.metaBlockLength--;
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = COPY_LOOP;
+ s.runningState = INIT_WRITE;
+ break;
+ }
+ }
+ }
+ if (s.runningState == COPY_LOOP) {
+ s.runningState = MAIN_LOOP;
+ }
+ continue;
+
+ case TRANSFORM:
+ // This check is done here to unburden the hot loop.
+ if (s.distance > MAX_ALLOWED_DISTANCE) {
+ throw new BrotliRuntimeException("Invalid backward reference"); // COV_NF_LINE
+ }
+ if (s.copyLength >= MIN_WORD_LENGTH
+ && s.copyLength <= MAX_WORD_LENGTH) {
+ int offset = DICTIONARY_OFFSETS_BY_LENGTH[s.copyLength];
+ int wordId = s.distance - s.maxDistance - 1;
+ int shift = DICTIONARY_SIZE_BITS_BY_LENGTH[s.copyLength];
+ int mask = (1 << shift) - 1;
+ int wordIdx = wordId & mask;
+ int transformIdx = wordId >>> shift;
+ offset += wordIdx * s.copyLength;
+ if (transformIdx < Transform.NUM_RFC_TRANSFORMS) {
+ int len = Transform.transformDictionaryWord(ringBuffer, s.pos, Dictionary.getData(),
+ offset, s.copyLength, Transform.RFC_TRANSFORMS, transformIdx);
+ s.pos += len;
+ s.metaBlockLength -= len;
+ if (s.pos >= fence) {
+ s.nextRunningState = MAIN_LOOP;
+ s.runningState = INIT_WRITE;
+ continue;
+ }
+ } else {
+ throw new BrotliRuntimeException("Invalid backward reference"); // COV_NF_LINE
+ }
+ } else {
+ throw new BrotliRuntimeException("Invalid backward reference"); // COV_NF_LINE
+ }
+ s.runningState = MAIN_LOOP;
+ continue;
+
+ case READ_METADATA:
+ while (s.metaBlockLength > 0) {
+ BitReader.readMoreInput(s);
+ // Optimize
+ BitReader.fillBitWindow(s);
+ BitReader.readFewBits(s, 8);
+ s.metaBlockLength--;
+ }
+ s.runningState = BLOCK_START;
+ continue;
+
+
+ case COPY_UNCOMPRESSED:
+ copyUncompressedData(s);
+ continue;
+
+ case INIT_WRITE:
+ s.ringBufferBytesReady = Math.min(s.pos, s.ringBufferSize);
+ s.runningState = WRITE;
+ // fall through
+ case WRITE:
+ if (writeRingBuffer(s) == 0) {
+ // Output buffer is full.
+ return;
+ }
+ if (s.pos >= s.maxBackwardDistance) {
+ s.maxDistance = s.maxBackwardDistance;
+ }
+ // Wrap the ringBuffer.
+ if (s.pos >= s.ringBufferSize) {
+ if (s.pos > s.ringBufferSize) {
+ Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.pos);
+ }
+ s.pos &= ringBufferMask;
+ s.ringBufferBytesWritten = 0;
+ }
+ s.runningState = s.nextRunningState;
+ continue;
+
+ default:
+ throw new BrotliRuntimeException("Unexpected state " + s.runningState);
+ }
+ }
+ if (s.runningState == FINISHED) {
+ if (s.metaBlockLength < 0) {
+ throw new BrotliRuntimeException("Invalid metablock length");
+ }
+ BitReader.jumpToByteBoundary(s);
+ BitReader.checkHealth(s, 1);
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DecodeTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DecodeTest.java
new file mode 100644
index 000000000..a0c2784b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DecodeTest.java
@@ -0,0 +1,160 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Decode}.
+ */
+@RunWith(JUnit4.class)
+public class DecodeTest {
+
+ static byte[] readUniBytes(String uniBytes) {
+ byte[] result = new byte[uniBytes.length()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = (byte) uniBytes.charAt(i);
+ }
+ return result;
+ }
+
+ private byte[] decompress(byte[] data, boolean byByte) throws IOException {
+ byte[] buffer = new byte[65536];
+ ByteArrayInputStream input = new ByteArrayInputStream(data);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ BrotliInputStream brotliInput = new BrotliInputStream(input);
+ if (byByte) {
+ byte[] oneByte = new byte[1];
+ while (true) {
+ int next = brotliInput.read();
+ if (next == -1) {
+ break;
+ }
+ oneByte[0] = (byte) next;
+ output.write(oneByte, 0, 1);
+ }
+ } else {
+ while (true) {
+ int len = brotliInput.read(buffer, 0, buffer.length);
+ if (len <= 0) {
+ break;
+ }
+ output.write(buffer, 0, len);
+ }
+ }
+ brotliInput.close();
+ return output.toByteArray();
+ }
+
+ private void checkDecodeResource(String expected, String compressed) throws IOException {
+ byte[] expectedBytes = readUniBytes(expected);
+ byte[] compressedBytes = readUniBytes(compressed);
+ byte[] actual = decompress(compressedBytes, false);
+ assertArrayEquals(expectedBytes, actual);
+ byte[] actualByByte = decompress(compressedBytes, true);
+ assertArrayEquals(expectedBytes, actualByByte);
+ }
+
+ @Test
+ public void testEmpty() throws IOException {
+ checkDecodeResource(
+ "",
+ "\u0006");
+ }
+
+ @Test
+ public void testX() throws IOException {
+ checkDecodeResource(
+ "X",
+ "\u000B\u0000\u0080X\u0003");
+ }
+
+ @Test
+ public void testX10Y10() throws IOException {
+ checkDecodeResource(
+ "XXXXXXXXXXYYYYYYYYYY",
+ "\u001B\u0013\u0000\u0000\u00A4\u00B0\u00B2\u00EA\u0081G\u0002\u008A");
+ }
+
+ @Test
+ public void testX64() throws IOException {
+ checkDecodeResource(
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "\u001B\u003F\u0000\u0000$\u00B0\u00E2\u0099\u0080\u0012");
+ }
+
+ @Test
+ public void testUkkonooa() throws IOException {
+ checkDecodeResource(
+ "ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, "
+ + "pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.",
+ "\u001Bv\u0000\u0000\u0014J\u00AC\u009Bz\u00BD\u00E1\u0097\u009D\u007F\u008E\u00C2\u0082"
+ + "6\u000E\u009C\u00E0\u0090\u0003\u00F7\u008B\u009E8\u00E6\u00B6\u0000\u00AB\u00C3\u00CA"
+ + "\u00A0\u00C2\u00DAf6\u00DC\u00CD\u0080\u008D.!\u00D7n\u00E3\u00EAL\u00B8\u00F0\u00D2"
+ + "\u00B8\u00C7\u00C2pM:\u00F0i~\u00A1\u00B8Es\u00AB\u00C4W\u001E");
+ }
+
+ @Test
+ public void testMonkey() throws IOException {
+ checkDecodeResource(
+ "znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmz"
+ + "xc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxc"
+ + "nzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqeriou"
+ + "pqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyio"
+ + "wtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuri"
+ + "ouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwot"
+ + "ueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfh"
+ + "klasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfa"
+ + "sdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjka"
+ + "ghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj",
+ "\u001BJ\u0003\u0000\u008C\u0094n\u00DE\u00B4\u00D7\u0096\u00B1x\u0086\u00F2-\u00E1\u001A"
+ + "\u00BC\u000B\u001C\u00BA\u00A9\u00C7\u00F7\u00CCn\u00B2B4QD\u008BN\u0013\b\u00A0\u00CDn"
+ + "\u00E8,\u00A5S\u00A1\u009C],\u001D#\u001A\u00D2V\u00BE\u00DB\u00EB&\u00BA\u0003e|\u0096j"
+ + "\u00A2v\u00EC\u00EF\u0087G3\u00D6\'\u000Ec\u0095\u00E2\u001D\u008D,\u00C5\u00D1(\u009F`"
+ + "\u0094o\u0002\u008B\u00DD\u00AAd\u0094,\u001E;e|\u0007EZ\u00B2\u00E2\u00FCI\u0081,\u009F"
+ + "@\u00AE\u00EFh\u0081\u00AC\u0016z\u000F\u00F5;m\u001C\u00B9\u001E-_\u00D5\u00C8\u00AF^"
+ + "\u0085\u00AA\u0005\u00BESu\u00C2\u00B0\"\u008A\u0015\u00C6\u00A3\u00B1\u00E6B\u0014"
+ + "\u00F4\u0084TS\u0019_\u00BE\u00C3\u00F2\u001D\u00D1\u00B7\u00E5\u00DD\u00B6\u00D9#\u00C6"
+ + "\u00F6\u009F\u009E\u00F6Me0\u00FB\u00C0qE\u0004\u00AD\u0003\u00B5\u00BE\u00C9\u00CB"
+ + "\u00FD\u00E2PZFt\u0004\r\u00FF \u0004w\u00B2m\'\u00BFG\u00A9\u009D\u001B\u0096,b\u0090#"
+ + "\u008B\u00E0\u00F8\u001D\u00CF\u00AF\u001D=\u00EE\u008A\u00C8u#f\u00DD\u00DE\u00D6m"
+ + "\u00E3*\u0082\u008Ax\u008A\u00DB\u00E6 L\u00B7\\c\u00BA0\u00E3?\u00B6\u00EE\u008C\""
+ + "\u00A2*\u00B0\"\n\u0099\u00FF=bQ\u00EE\b\u00F6=J\u00E4\u00CC\u00EF\"\u0087\u0011\u00E2"
+ + "\u0083(\u00E4\u00F5\u008F5\u0019c[\u00E1Z\u0092s\u00DD\u00A1P\u009D8\\\u00EB\u00B5\u0003"
+ + "jd\u0090\u0094\u00C8\u008D\u00FB/\u008A\u0086\"\u00CC\u001D\u0087\u00E0H\n\u0096w\u00909"
+ + "\u00C6##H\u00FB\u0011GV\u00CA \u00E3B\u0081\u00F7w2\u00C1\u00A5\\@!e\u0017@)\u0017\u0017"
+ + "lV2\u00988\u0006\u00DC\u0099M3)\u00BB\u0002\u00DFL&\u0093l\u0017\u0082\u0086 \u00D7"
+ + "\u0003y}\u009A\u0000\u00D7\u0087\u0000\u00E7\u000Bf\u00E3Lfqg\b2\u00F9\b>\u00813\u00CD"
+ + "\u0017r1\u00F0\u00B8\u0094RK\u00901\u008Eh\u00C1\u00EF\u0090\u00C9\u00E5\u00F2a\tr%"
+ + "\u00AD\u00EC\u00C5b\u00C0\u000B\u0012\u0005\u00F7\u0091u\r\u00EEa..\u0019\t\u00C2\u0003"
+ );
+ }
+
+ @Test
+ public void testFox() throws IOException {
+ checkDecodeResource(
+ "The quick brown fox jumps over the lazy dog",
+ "\u001B*\u0000\u0000\u0004\u0004\u00BAF:\u0085\u0003\u00E9\u00FA\f\u0091\u0002H\u0011,"
+ + "\u00F3\u008A:\u00A3V\u007F\u001A\u00AE\u00BF\u00A4\u00AB\u008EM\u00BF\u00ED\u00E2\u0004K"
+ + "\u0091\u00FF\u0087\u00E9\u001E");
+ }
+
+ @Test
+ public void testUtils() {
+ new Context();
+ new Decode();
+ new Dictionary();
+ new Huffman();
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Dictionary.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Dictionary.java
new file mode 100644
index 000000000..a6867b7d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Dictionary.java
@@ -0,0 +1,54 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Collection of static dictionary words.
+ *
+ * <p>Dictionary content is loaded from binary resource when {@link #getData()} is executed for the
+ * first time. Consequently, it saves memory and CPU in case dictionary is not required.
+ *
+ * <p>One possible drawback is that multiple threads that need dictionary data may be blocked (only
+ * once in each classworld). To avoid this, it is enough to call {@link #getData()} proactively.
+ */
+public final class Dictionary {
+ private static volatile ByteBuffer data;
+
+ private static class DataLoader {
+ static final boolean OK;
+
+ static {
+ boolean ok = true;
+ try {
+ Class.forName(Dictionary.class.getPackage().getName() + ".DictionaryData");
+ } catch (Throwable ex) {
+ ok = false;
+ }
+ OK = ok;
+ }
+ }
+
+ public static void setData(ByteBuffer data) {
+ if (!data.isDirect() || !data.isReadOnly()) {
+ throw new BrotliRuntimeException("data must be a direct read-only byte buffer");
+ }
+ Dictionary.data = data;
+ }
+
+ public static ByteBuffer getData() {
+ if (data != null) {
+ return data;
+ }
+ if (!DataLoader.OK) {
+ throw new BrotliRuntimeException("brotli dictionary is not set");
+ }
+ /* Might have been set when {@link DictionaryData} was loaded.*/
+ return data;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryData.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryData.java
new file mode 100644
index 000000000..f969df35f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryData.java
@@ -0,0 +1,51 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Built-in dictionary data.
+ *
+ * When this class is loaded, it sets its data: {@link Dictionary#setData(ByteBuffer)}.
+ */
+final class DictionaryData {
+ private static final String DATA0 = "timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0\"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml\"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid=\"sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$(\"#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS\"agedgreyGET\"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:e*/\r\n 100hall.\n\nA7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,\r\n\r\ncoolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px''););\">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarmb\u0000\u0019sboys[0].');\"POSTbearkids);}}marytend(UK)quadzh:f-siz----prop');\rliftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene b\u0000\u0014softrometillross<h3>pourfadepink<tr>mini)|!(minezh:hbarshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json', 'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:d'));puremageparatonebond:37Z_of_']);000,zh:gtankyardbowlbush:56ZJava30px\n|}\n%C3%:34ZjeffEXPIcashvisagolfsnowzh:iquer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;\n}\nexit:35Zvarsbeat'});diet999;anne}}</[i].LangkmB2wiretoysaddssealalex;\n\t}echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}\ndustclip).\n\n70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}\r\nHEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-\n!002)ndow[1];[];\nLog salt\r\n\t\tbangtrimbath){\r\n00px\n});ko:lfeesad>\rs:// [];tollplug(){\n{\r\n .js'200pdualboat.JPG);\n}quot);\n\n');\n\r\n}\r201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomC!sesteestaperotodohacecadaaC1obiendC-aasC-vidacasootroforosolootracualdijosidograntipotemadebealgoquC)estonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiP7P0P=P0P>P<Q\u0000P0Q\u0000Q\u0003Q\u0002P0P=P5P?P>P>Q\u0002P8P7P=P>P4P>Q\u0002P>P6P5P>P=P8Q\u0005P\u001DP0P5P5P1Q\u000BP<Q\u000BP\u0012Q\u000BQ\u0001P>P2Q\u000BP2P>P\u001DP>P>P1P\u001FP>P;P8P=P8P P$P\u001DP5P\u001CQ\u000BQ\u0002Q\u000BP\u001EP=P8P<P4P0P\u0017P0P\u0014P0P\u001DQ\u0003P\u001EP1Q\u0002P5P\u0018P7P5P9P=Q\u0003P<P<P\"Q\u000BQ\u0003P6Y\u0001Y\nX#Y\u0006Y\u0005X'Y\u0005X9Y\u0003Y\u0004X#Y\u0008X1X/Y\nX'Y\u0001Y\tY\u0007Y\u0008Y\u0004Y\u0005Y\u0004Y\u0003X'Y\u0008Y\u0004Y\u0007X(X3X'Y\u0004X%Y\u0006Y\u0007Y\nX#Y\nY\u0002X/Y\u0007Y\u0004X+Y\u0005X(Y\u0007Y\u0004Y\u0008Y\u0004Y\nX(Y\u0004X'Y\nX(Y\u0003X4Y\nX'Y\u0005X#Y\u0005Y\u0006X*X(Y\nY\u0004Y\u0006X-X(Y\u0007Y\u0005Y\u0005X4Y\u0008X4firstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue\"crossspentblogsbox\">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav\">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera\"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow\">genretrucklooksValueFrame.net/-->\n<try {\nvar makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top\">\n<!--POST\"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url=\"parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();\" Blocklinuxjonespixel');\">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar\">.src=toweralt=\"cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});\r\nbandsqueue= {};80px;cking{\r\n\t\taheadclockirishlike ratiostatsForm\"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg\"spainbeachtaxesmicroangel--></giftssteve-linkbody.});\n\tmount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:c\u0002simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/\"1.jpgwmodeparamSTARTleft idden, 201);\n}\nform.viruschairtransworstPagesitionpatch<!--\no-cacfirmstours,000 asiani++){adobe')[0]id=10both;menu .2.mi.png\"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120\" sweettr>\r\nname=diegopage swiss-->\n\n#fff;\">Log.com\"treatsheet) && 14px;sleepntentfiledja:c\u0003id=\"cName\"worseshots-box-delta\n&lt;bears:48Z<data-rural</a> spendbakershops= \"\";php\">ction13px;brianhellosize=o=%2F joinmaybe<img img\">, fjsimg\" \")[0]MTopBType\"newlyDanskczechtrailknows</h5>faq\">zh-cn10);\n-1\");type=bluestrulydavis.js';>\r\n<!steel you h2>\r\nform jesus100% menu.\r\n\t\r\nwalesrisksumentddingb-likteachgif\" vegasdanskeestishqipsuomisobredesdeentretodospuedeaC1osestC!tienehastaotrospartedondenuevohacerformamismomejormundoaquC-dC-assC3loayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaC-snuevasaludforosmedioquienmesespoderchileserC!vecesdecirjosC)estarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocC3moenerojuegoperC:haberestoynuncamujervalorfueralibrogustaigualvotoscasosguC-apuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleC3nplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenC!readiscopedrocercapuedapapelmenorC:tilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniC1oquedapasarbancohijosviajepabloC)stevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallC-jovendichaestantalessalirsuelopesosfinesllamabuscoC)stalleganegroplazahumorpagarjuntadobleislasbolsabaC1ohablaluchaC\u0001readicenjugarnotasvalleallC!cargadolorabajoestC)gustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo\">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother\" id=\"marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo\" bottomlist\">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename=\"amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.\n\nOnejoinedmenu\">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo\">beyond-scaleacceptservedmarineFootercamera</h1>\n_form\"leavesstress\" />\r\n.gif\" onloadloaderOxfordsistersurvivlistenfemaleDesignsize=\"appealtext\">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main\">inlinesundaywrap\">failedcensusminutebeaconquotes150px|estateremoteemail\"linkedright;signalformal1.htmlsignupprincefloat:.png\" forum.AccesspaperssoundsextendHeightsliderUTF-8\"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome\">headerensurebranchpiecesblock;statedtop\"><racingresize--&gt;pacitysexualbureau.jpg\" 10,000obtaintitlesamount, Inc.comedymenu\" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page\">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline\">body\">\n* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox\">\nSystem DavidcancertablesprovedApril reallydriveritem\">more\">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php\" assumelayerswilsonstoresreliefswedenCustomeasily your String\n\nWhiltaylorclear:resortfrenchthough\") + \"<body>buyingbrandsMembername\">oppingsector5px;\">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink\">Images=falsewhile hspace0&amp; \n\nIn powerPolski-colorjordanBottomStart -count2.htmlnews\">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml\" rights.html-blockregExp:hoverwithinvirginphones</tr>\rusing \n\tvar >');\n\t</td>\n</tr>\nbahasabrasilgalegomagyarpolskisrpskiX1X/Y\u0008d8-f\u0016\u0007g.\u0000d=\u0013g9\u0001i+\u0014d?!f\u0001/d8-e\u001B=f\u0008\u0011d;,d8\u0000d8*e\u0005,e\u000F8g.!g\u0010\u0006h.:e\u001D\u001Be\u000F/d;%f\u001C\re\n!f\u00176i\u00174d8*d::d:'e\u0013\u0001h\u0007*e71d<\u0001d8\u001Af\u001F%g\u001C\u000Be7%d=\u001Ch\u0001\u0014g3;f2!f\u001C\tg=\u0011g+\u0019f\t\u0000f\u001C\th/\u0004h.:d8-e?\u0003f\u0016\u0007g+ g\u0014(f\u00087i&\u0016i!5d=\u001Ch\u0000\u0005f\n\u0000f\u001C/i\u0017.i\"\u0018g\u001B8e\u00053d8\u000Bh==f\u0010\u001Cg4\"d=?g\u0014(h=/d;6e\u001C(g:?d8;i\"\u0018h5\u0004f\u0016\u0019h'\u0006i\"\u0011e\u001B\u001Ee$\rf3(e\u0006\u000Cg=\u0011g;\u001Cf\u00146h\u0017\u000Fe\u0006\u0005e.9f\u000E(h\r\u0010e8\u0002e\u001C:f6\u0008f\u0001/g):i\u00174e\u000F\u0011e8\u0003d;\u0000d9\u0008e%=e\u000F\u000Bg\u0014\u001Ff4;e\u001B>g\t\u0007e\u000F\u0011e1\u0015e&\u0002f\u001E\u001Cf\t\u000Bf\u001C:f\u00160i\u0017;f\u001C\u0000f\u00160f\u00169e<\u000Fe\u000C\u0017d:,f\u000F\u0010d>\u001Be\u00053d:\u000Ef\u001B4e$\u001Ah?\u0019d8*g3;g;\u001Fg\u001F%i\u0001\u0013f88f\u0008\u000Fe9?e\u0011\ne\u00056d;\u0016e\u000F\u0011h!(e.\te\u0005(g,,d8\u0000d<\u001Ae\u0011\u0018h?\u001Bh!\u000Cg\u00029e\u0007;g\t\u0008f\u001D\u0003g\u00145e-\u0010d8\u0016g\u0015\u000Ch.>h.!e\u0005\rh49f\u0015\u0019h\u00022e\n e\u0005%f4;e\n(d;\u0016d;,e\u0015\u0006e\u0013\u0001e\r\u001Ae.\"g\u000E0e\u001C(d8\nf57e&\u0002d=\u0015e72g;\u000Fg\u0015\u0019h(\u0000h/&g;\u0006g$>e\u000C:g\u0019;e=\u0015f\u001C,g+\u0019i\u001C\u0000h&\u0001d;7f <f\u0014/f\u000C\u0001e\u001B=i\u0019\u0005i\u0013>f\u000E%e\u001B=e.6e;:h.>f\u001C\u000Be\u000F\u000Bi\u0018\u0005h/;f3\u0015e>\u000Bd=\rg=.g;\u000Ff5\u000Ei\u0000\tf\u000B)h?\u0019f 7e=\u0013e\t\re\u0008\u0006g1;f\u000E\u0012h!\u000Ce\u001B d8:d:$f\u0018\u0013f\u001C\u0000e\u0010\u000Ei\u001F3d9\u0010d8\rh\u0003=i\u0000\u001Ah?\u0007h!\u000Cd8\u001Ag'\u0011f\n\u0000e\u000F/h\u0003=h.>e$\u0007e\u0010\u0008d=\u001Ce$'e.6g$>d<\u001Ag \u0014g)6d8\u0013d8\u001Ae\u0005(i\u0003(i!9g\u001B.h?\u0019i\u0007\u000Ch?\u0018f\u0018/e<\u0000e'\u000Bf\u0003\u0005e\u00065g\u00145h\u0004\u0011f\u0016\u0007d;6e\u0013\u0001g\t\u000Ce8.e\n)f\u0016\u0007e\u000C\u0016h5\u0004f:\u0010e$'e-&e-&d9 e\u001C0e\u001D\u0000f5\u000Fh'\u0008f\n\u0015h5\u0004e7%g(\u000Bh&\u0001f1\u0002f\u0000\u000Ed9\u0008f\u00176e\u0000\u0019e\n\u001Fh\u0003=d8;h&\u0001g\u001B.e\t\rh5\u0004h./e\u001F\u000Ee8\u0002f\u00169f3\u0015g\u00145e=1f\u000B\u001Bh\u0001\u0018e#0f\u0018\u000Ed;;d=\u0015e\u0001%e:7f\u00150f\r.g>\u000Ee\u001B=f1=h=&d;\u000Bg;\rd=\u0006f\u0018/d:$f5\u0001g\u0014\u001Fd:'f\t\u0000d;%g\u00145h/\u001Df\u0018>g$:d8\u0000d:\u001Be\r\u0015d=\rd::e\u0011\u0018e\u0008\u0006f\u001E\u0010e\u001C0e\u001B>f\u0017\u0005f88e7%e\u00057e-&g\u0014\u001Fg3;e\u0008\u0017g=\u0011e\u000F\u000Be8\u0016e-\u0010e/\u0006g \u0001i\"\u0011i\u0001\u0013f\u000E'e\u00086e\u001C0e\u000C:e\u001F:f\u001C,e\u0005(e\u001B=g=\u0011d8\ni\u0007\rh&\u0001g,,d:\u000Ce\u0016\u001Cf,\"h?\u001Be\u0005%e\u000F\u000Bf\u0003\u0005h?\u0019d:\u001Bh\u0000\u0003h/\u0015e\u000F\u0011g\u000E0e\u001F9h.-d;%d8\nf\u0014?e:\u001Cf\u0008\u0010d8:g\u000E/e\"\u0003i&\u0019f8/e\u0010\u000Cf\u00176e(1d9\u0010e\u000F\u0011i\u0000\u0001d8\u0000e.\u001Ae<\u0000e\u000F\u0011d=\u001Ce\u0013\u0001f \u0007e\u0007\u0006f,\"h?\u000Eh'#e\u00063e\u001C0f\u00169d8\u0000d8\u000Bd;%e\u000F\nh4#d;;f\u0008\u0016h\u0000\u0005e.\"f\u00087d;#h!(g'/e\u0008\u0006e%3d::f\u00150g \u0001i\u0014\u0000e\u0014.e\u0007:g\u000E0g&;g:?e:\u0014g\u0014(e\u0008\u0017h!(d8\re\u0010\u000Cg<\u0016h>\u0011g;\u001Fh.!f\u001F%h/\"d8\rh&\u0001f\u001C\te\u00053f\u001C:f\u001E\u0004e>\u0008e$\u001Af\u0012-f\u0014>g;\u0004g;\u0007f\u0014?g-\u0016g\u001B4f\u000E%h\u0003=e\n\u001Bf\u001D%f:\u0010f\u0019\u0002i\u0016\u0013g\u001C\u000Be\u00080g\u0003-i\u0017(e\u00053i\u0014.d8\u0013e\u000C:i\u001D\u001Ee88h\u000B1h/-g\u0019>e:&e8\u000Cf\u001C\u001Bg>\u000Ee%3f/\u0014h>\u0003g\u001F%h/\u0006h'\u0004e.\u001Ae;:h..i\u0003(i\u0017(f\u0004\u000Fh'\u0001g2>e=)f\u0017%f\u001C,f\u000F\u0010i+\u0018e\u000F\u0011h(\u0000f\u00169i\u001D\"e\u001F:i\u0007\u0011e$\u0004g\u0010\u0006f\u001D\u0003i\u0019\u0010e=1g\t\u0007i\u00136h!\u000Ch?\u0018f\u001C\te\u0008\u0006d:+g\t)e\u0013\u0001g;\u000Fh\u0010%f7;e\n d8\u0013e.6h?\u0019g'\rh/\u001Di\"\u0018h57f\u001D%d8\u001Ae\n!e\u0005,e\u0011\nh.0e=\u0015g.\u0000d;\u000Bh4(i\u0007\u000Fg\u00147d::e=1e\u0013\re<\u0015g\u0014(f\n%e\u0011\ni\u0003(e\u0008\u0006e?+i\u0000\u001Fe\u0012(h/\"f\u00176e0\u001Af3(f\u0004\u000Fg\u00143h/7e-&f !e:\u0014h/%e\u000E\u0006e\u000F2e\u000F*f\u0018/h?\u0014e\u001B\u001Eh4-d90e\u0010\rg'0d8:d:\u0006f\u0008\u0010e\n\u001Fh/4f\u0018\u000Ed>\u001Be:\u0014e-)e-\u0010d8\u0013i\"\u0018g(\u000Be:\u000Fd8\u0000h\u0008,f\u001C\u0003e\u0013!e\u000F*f\u001C\te\u00056e.\u0003d?\u001Df\n$h\u0000\u000Cd8\u0014d;\ne$)g*\u0017e\u000F#e\n(f\u0000\u0001g\n6f\u0000\u0001g\t9e\u0008+h.$d8:e?\u0005i!;f\u001B4f\u00160e0\u000Fh/4f\u0008\u0011e\u0000\u0011d=\u001Cd8:e*\u0012d=\u0013e\u000C\u0005f\u000B,i\u0002#d9\u0008d8\u0000f 7e\u001B=e\u0006\u0005f\u0018/e\u0010&f 9f\r.g\u00145h'\u0006e-&i\u0019\"e\u00057f\u001C\th?\u0007g(\u000Bg\u00141d:\u000Ed::f\t\re\u0007:f\u001D%d8\rh?\u0007f-#e\u001C(f\u0018\u000Ef\u0018\u001Ff\u0015\u0005d:\u000Be\u00053g3;f \u0007i\"\u0018e\u0015\u0006e\n!h>\u0013e\u0005%d8\u0000g\u001B4e\u001F:g!\u0000f\u0015\u0019e-&d:\u0006h'#e;:g-\u0011g;\u0013f\u001E\u001Ce\u0005(g\u0010\u0003i\u0000\u001Ag\u001F%h.!e\u0008\u0012e/9d:\u000Eh\t:f\u001C/g\u001B8e\u0006\u000Ce\u000F\u0011g\u0014\u001Fg\u001C\u001Fg\u001A\u0004e;:g+\u000Bg-\tg:'g1;e\u001E\u000Bg;\u000Fi*\u000Ce.\u001Eg\u000E0e\u00086d=\u001Cf\u001D%h\u0007*f \u0007g->d;%d8\u000Be\u000E\u001Fe\u0008\u001Bf\u0017 f3\u0015e\u00056d8-e\u0000\u000Bd::d8\u0000e\u0008\u0007f\u000C\u0007e\r\u0017e\u00053i\u0017-i\u001B\u0006e\u001B\"g,,d8\te\u00053f3(e\u001B f-$g\u0005'g\t\u0007f71e\u001C3e\u0015\u0006d8\u001Ae9?e7\u001Ef\u0017%f\u001C\u001Fi+\u0018g:'f\u001C\u0000h?\u0011g;<e\u0010\u0008h!(g$:d8\u0013h>\u0011h!\u000Cd8:d:$i\u0000\u001Ah/\u0004d;7h'\te>\u0017g2>e\r\u000Ee.6e:-e.\u000Cf\u0008\u0010f\u0004\u001Fh'\te.\th#\u0005e>\u0017e\u00080i\u0002.d;6e\u00086e:&i#\u001Fe\u0013\u0001h\u0019=g\u00046h=,h==f\n%d;7h.0h\u0000\u0005f\u00169f!\u0008h!\u000Cf\u0014?d::f0\u0011g\u0014(e\u0013\u0001d8\u001Ch%?f\u000F\u0010e\u0007:i\u0005\u0012e:\u0017g\u00046e\u0010\u000Ed;\u0018f,>g\u0003-g\u00029d;%e\t\re.\u000Ce\u0005(e\u000F\u0011e8\u0016h.>g=.i\"\u0006e/<e7%d8\u001Ae\u000C;i\u0019\"g\u001C\u000Bg\u001C\u000Bg;\u000Fe\u00058e\u000E\u001Fe\u001B e93e\u000F0e\u0010\u0004g'\re\"\u001Ee\n f\u001D\u0010f\u0016\u0019f\u00160e\"\u001Ed9\u000Be\u0010\u000Eh\u0001\u000Cd8\u001Af\u0015\u0008f\u001E\u001Cd;\ne94h.:f\u0016\u0007f\u0008\u0011e\u001B=e\u0011\nh/\tg\t\u0008d8;d?.f\u00149e\u000F\u0002d8\u000Ef\t\u0013e\r0e?+d9\u0010f\u001C:f\"0h'\u0002g\u00029e-\u0018e\u001C(g2>g%\u001Eh\u000E7e>\u0017e\u0008)g\u0014(g;'g;-d= d;,h?\u0019d9\u0008f(!e<\u000Fh/-h(\u0000h\u0003=e$\u001Fi\u001B\u0005h\u0019\u000Ef\u0013\rd=\u001Ci#\u000Ef <d8\u0000h57g'\u0011e-&d=\u0013h\u00022g\u001F-d?!f\u001D!d;6f2;g\u0016\u0017h?\u0010e\n(d:'d8\u001Ad<\u001Ah..e/<h\u0008*e\u0005\u0008g\u0014\u001Fh\u0001\u0014g\u001B\u001Fe\u000F/f\u0018/e\u0015\u000Fi!\u000Cg;\u0013f\u001E\u0004d=\u001Cg\u0014(h0\u0003f\u001F%h3\u0007f\u0016\u0019h\u0007*e\n(h4\u001Fh4#e\u0006\u001Cd8\u001Ah.?i\u0017.e.\u001Ef\u0016=f\u000E%e\u000F\u0017h.(h.:i\u0002#d8*e\u000F\ri&\u0008e\n e<:e%3f\u0000'h\u000C\u0003e\u001B4f\u001C\re\u000B\u0019d<\u0011i\u00172d;\nf\u0017%e.\"f\u001C\rh'\u0000g\u001C\u000Be\u000F\u0002e\n g\u001A\u0004h/\u001Dd8\u0000g\u00029d?\u001Dh/\u0001e\u001B>d9&f\u001C\tf\u0015\u0008f5\u000Bh/\u0015g';e\n(f\t\rh\u0003=e\u00063e.\u001Ah\u0002!g%(d8\rf\u0016-i\u001C\u0000f1\u0002d8\re>\u0017e\n\u001Ef3\u0015d9\u000Bi\u00174i\u0007\u0007g\u0014(h\u0010%i\u0014\u0000f\n\u0015h/\tg\u001B.f \u0007g\u00081f\u0003\u0005f\u0011\u0004e=1f\u001C\td:\u001Bh$\u0007h#=f\u0016\u0007e-&f\u001C:d<\u001Af\u00150e-\u0017h#\u0005d?.h4-g\t)e\u0006\u001Cf\u001D\u0011e\u0005(i\u001D\"g2>e\u0013\u0001e\u00056e.\u001Ed:\u000Bf\u0003\u0005f04e93f\u000F\u0010g$:d8\ne8\u0002h0\"h0\"f\u0019.i\u0000\u001Af\u0015\u0019e8\u0008d8\nd< g1;e\u0008+f-\u000Cf\u001B2f\u000B%f\u001C\te\u0008\u001Bf\u00160i\u0005\rd;6e\u000F*h&\u0001f\u00176d;#h3\u0007h(\nh>>e\u00080d::g\u0014\u001Fh.\"i\u0018\u0005h\u0000\u0001e8\u0008e1\u0015g$:e?\u0003g\u0010\u0006h44e-\u0010g62g+\u0019d8;i!\u000Ch\u0007*g\u00046g:'e\u0008+g.\u0000e\r\u0015f\u00149i\u001D)i\u0002#d:\u001Bf\u001D%h/4f\t\u0013e<\u0000d;#g \u0001e\u0008 i\u0019$h/\u0001e\u00088h\n\u0002g\u001B.i\u0007\rg\u00029f,!f\u00158e$\u001Ae0\u0011h'\u0004e\u0008\u0012h5\u0004i\u0007\u0011f\t>e\u00080d;%e\u0010\u000Ee$'e\u0005(d8;i!5f\u001C\u0000d=3e\u001B\u001Eg-\u0014e$)d8\u000Bd?\u001Di\u001A\u001Cg\u000E0d;#f#\u0000f\u001F%f\n\u0015g%(e0\u000Ff\u00176f2\u0012f\u001C\tf-#e88g\u0014\u001Ah\u00073d;#g\u0010\u0006g\u001B.e=\u0015e\u0005,e<\u0000e$\re\u00086i\u0007\u0011h\u001E\re98g&\u000Fg\t\u0008f\u001C,e=\"f\u0008\u0010e\u0007\u0006e$\u0007h!\u000Cf\u0003\u0005e\u001B\u001Ee\u00080f\u0000\u001Df\u00033f\u0000\u000Ef 7e\r\u000Fh..h.$h/\u0001f\u001C\u0000e%=d:'g\u0014\u001Ff\u000C\tg\u0005'f\u001C\rh#\u0005e9?d8\u001Ce\n(f<+i\u0007\u0007h4-f\u00160f\t\u000Bg;\u0004e\u001B>i\u001D\"f\u001D?e\u000F\u0002h\u0000\u0003f\u0014?f2;e.9f\u0018\u0013e$)e\u001C0e\n*e\n\u001Bd::d;,e\r\u0007g:'i\u0000\u001Fe:&d::g\t)h0\u0003f\u00154f5\u0001h!\u000Ci\u0000 f\u0008\u0010f\u0016\u0007e-\u0017i\u001F)e\u001B=h48f\u0018\u0013e<\u0000e1\u0015g\u001B8i\u0017\u001Ch!(g\u000E0e=1h'\u0006e&\u0002f-$g>\u000Ee.9e$'e0\u000Ff\n%i\u0001\u0013f\u001D!f,>e?\u0003f\u0003\u0005h.8e$\u001Af3\u0015h'\u0004e.6e1\u0005d9&e:\u0017h?\u001Ef\u000E%g+\u000Be\r3d8>f\n%f\n\u0000e7'e%%h?\u0010g\u0019;e\u0005%d;%f\u001D%g\u0010\u0006h.:d:\u000Bd;6h\u0007*g\u00141d8-e\r\u000Ee\n\u001Ee\u0005,e&\u0008e&\u0008g\u001C\u001Ff-#d8\ri\u0014\u0019e\u0005(f\u0016\u0007e\u0010\u0008e\u0010\u000Cd;7e\u0000<e\u0008+d::g\u001B\u0011g\u001D#e\u00057d=\u0013d8\u0016g:*e\u001B\"i\u0018\u001Fe\u0008\u001Bd8\u001Af\t?f\u000B\u0005e\"\u001Ei\u0015?f\u001C\td::d?\u001Df\u000C\u0001e\u0015\u0006e.6g;4d?.e\u000F0f9>e7&e\u000F3h\u0002!d;=g-\u0014f!\u0008e.\u001Ei\u0019\u0005g\u00145d?!g;\u000Fg\u0010\u0006g\u0014\u001Fe\u0011=e.#d< d;;e\n!f-#e<\u000Fg\t9h\t2d8\u000Bf\u001D%e\r\u000Fd<\u001Ae\u000F*h\u0003=e=\u0013g\u00046i\u0007\rf\u00160e\u0005'e.9f\u000C\u0007e/<h?\u0010h!\u000Cf\u0017%e?\u0017h3#e.6h6\u0005h?\u0007e\u001C\u001Fe\u001C0f5\u0019f1\u001Ff\u0014/d;\u0018f\u000E(e\u0007:g+\u0019i\u0015?f\u001D-e7\u001Ef\t'h!\u000Ce\u00086i\u0000 d9\u000Bd8\u0000f\u000E(e9?g\u000E0e\u001C:f\u000F\u000Fh?0e\u000F\u0018e\u000C\u0016d< g;\u001Ff-\u000Cf\t\u000Bd?\u001Di\u0019)h/>g(\u000Be\u000C;g\u0016\u0017g;\u000Fh?\u0007h?\u0007e\u000E;d9\u000Be\t\rf\u00146e\u0005%e94e:&f\u001D\u0002e?\u0017g>\u000Ed8=f\u001C\u0000i+\u0018g\u0019;i\u0019\u0006f\u001C*f\u001D%e\n e7%e\u0005\rh4#f\u0015\u0019g(\u000Bg\t\u0008e\u001D\u0017h:+d=\u0013i\u0007\re:\u0006e\u0007:e\u0014.f\u0008\u0010f\u001C,e=\"e<\u000Fe\u001C\u001Fh1\u0006e\u0007:e\u00039d8\u001Cf\u00169i\u0002.g.1e\r\u0017d:,f1\u0002h\u0001\u000Ce\u000F\u0016e>\u0017h\u0001\u000Cd=\rg\u001B8d?!i!5i\u001D\"e\u0008\u0006i\u0012\u001Fg=\u0011i!5g!.e.\u001Ae\u001B>d>\u000Bg=\u0011e\u001D\u0000g'/f\u001E\u0001i\u0014\u0019h//g\u001B.g\u001A\u0004e.\u001Dh4\u001Df\u001C:e\u00053i#\u000Ei\u0019)f\u000E\u0008f\u001D\u0003g\u0017\u0005f/\u0012e. g\t)i\u0019$d:\u0006h)\u0015h+\u0016g\u0016>g\u0017\u0005e\u000F\nf\u00176f1\u0002h4-g+\u0019g\u00029e\u0004?g+%f/\u000Fe$)d8-e$.h.$h/\u0006f/\u000Fd8*e$)f4%e-\u0017d=\u0013e\u000F0g\u0001#g;4f\n$f\u001C,i!5d8*f\u0000'e.\u0018f\u00169e88h'\u0001g\u001B8f\u001C:f\u0008\u0018g\u0015%e:\u0014e=\u0013e>\u000Be8\u0008f\u00169d>?f !e\u001B-h\u0002!e8\u0002f\u0008?e1\u000Bf \u000Fg\u001B.e\u0011\u0018e7%e/<h\u00074g*\u0001g\u00046i\u0001\u0013e\u00057f\u001C,g=\u0011g;\u0013e\u0010\u0008f!#f!\u0008e\n3e\n(e\u000F&e$\u0016g>\u000Ee\u0005\u0003e<\u0015h57f\u00149e\u000F\u0018g,,e\u001B\u001Bd<\u001Ah.!h**f\u0018\u000Ei\u001A\u0010g'\u0001e.\u001De.\u001Dh'\u0004h\u000C\u0003f6\u0008h49e\u00051e\u0010\u000Ce?\u0018h.0d=\u0013g3;e8&f\u001D%e\u0010\re-\u0017g\u0019<h!(e<\u0000f\u0014>e\n g\u001B\u001Fe\u000F\u0017e\u00080d:\u000Cf\t\u000Be$'i\u0007\u000Ff\u0008\u0010d::f\u00150i\u0007\u000Fe\u00051d:+e\u000C:e\u001F\u001Fe%3e-)e\u000E\u001Fe\u0008\u0019f\t\u0000e\u001C(g;\u0013f\u001D\u001Fi\u0000\u001Ad?!h6\u0005g:'i\u0005\rg=.e=\u0013f\u00176d<\u0018g'\u0000f\u0000'f\u0004\u001Ff\u0008?d:'i\u0001\nf\u00082e\u0007:e\u000F#f\u000F\u0010d:$e01d8\u001Ad?\u001De\u0001%g(\u000Be:&e\u000F\u0002f\u00150d:\u000Bd8\u001Af\u00154d8*e11d8\u001Cf\u0003\u0005f\u0004\u001Fg\t9f.\ne\u0008\u0006i!\u001Ef\u0010\u001Ce0\u000Be1\u001Ed:\u000Ei\u0017(f\u00087h4\"e\n!e#0i\u001F3e\u000F\ne\u00056h4\"g;\u000Fe\u001D\u001Af\u000C\u0001e92i\u0003(f\u0008\u0010g+\u000Be\u0008)g\u001B\nh\u0000\u0003h\u0019\u0011f\u0008\u0010i\u0003=e\u000C\u0005h#\u0005g\u0014(f\u00086f/\u0014h5\u001Bf\u0016\u0007f\u0018\u000Ef\u000B\u001Be\u0015\u0006e.\u000Cf\u00154g\u001C\u001Ff\u0018/g\u001C<g\u001D\u001Bd<\u0019d<4e(\u0001f\u001C\u001Bi\"\u0006e\u001F\u001Fe\r+g\u0014\u001Fd<\u0018f\u0003 h+\u0016e#\u0007e\u0005,e\u00051h\t/e%=e\u0005\u0005e\u0008\u0006g,&e\u0010\u0008i\u0019\u0004d;6g\t9g\u00029d8\re\u000F/h\u000B1f\u0016\u0007h5\u0004d:'f 9f\u001C,f\u0018\u000Ef\u0018>e/\u0006g\"<e\u0005,d<\u0017f0\u0011f\u0017\u000Ff\u001B4e\n d:+e\u000F\u0017e\u0010\u000Ce-&e\u0010/e\n(i\u0000\u0002e\u0010\u0008e\u000E\u001Ff\u001D%i\u0017.g-\u0014f\u001C,f\u0016\u0007g>\u000Ei#\u001Fg;?h\t2g(3e.\u001Ag;\u0008d:\u000Eg\u0014\u001Fg\t)d>\u001Bf1\u0002f\u0010\u001Cg\u000B\u0010e\n\u001Bi\u0007\u000Fd8%i\u0007\rf08h?\u001Ce\u0006\u0019g\u001C\u001Ff\u001C\ti\u0019\u0010g+\u001Ed:\te/9h1!h49g\u0014(d8\re%=g;\u001De/9e\r\u0001e\u0008\u0006d?\u0003h?\u001Bg\u00029h/\u0004e=1i\u001F3d<\u0018e\n?d8\re0\u0011f,#h5\u000Fe96d8\u0014f\u001C\tg\u00029f\u00169e\u0010\u0011e\u0005(f\u00160d?!g\u0014(h.>f\u0016=e=\"h1!h5\u0004f <g*\u0001g 4i\u001A\u000Fg\u001D\u0000i\u0007\re$'d:\u000Ef\u0018/f/\u0015d8\u001Af\u0019:h\u0003=e\u000C\u0016e7%e.\u000Cg>\u000Ee\u0015\u0006e\u001F\u000Eg;\u001Fd8\u0000e\u0007:g\t\u0008f\t\u0013i\u0000 g\u0014\"e\u0013\u0001f&\u0002e\u00065g\u0014(d:\u000Ed?\u001Dg\u0015\u0019e\u001B g4 d8-e\u001C\u000Be-\u0018e\u0002(h44e\u001B>f\u001C\u0000f\u0004\u001Bi\u0015?f\u001C\u001Fe\u000F#d;7g\u0010\u0006h4\"e\u001F:e\u001C0e.\tf\u000E\u0012f-&f1\ti\u0007\u000Ci\u001D\"e\u0008\u001Be;:e$)g):i&\u0016e\u0005\u0008e.\u000Ce\u0016\u0004i)1e\n(d8\u000Bi\u001D\"d8\re\u0006\rh/\u001Ad?!f\u0004\u000Fd9\ti\u00183e\u0005\th\u000B1e\u001B=f<\u0002d:.e\u0006\u001Bd:\u000Bg\u000E)e.6g>$d<\u0017e\u0006\u001Cf0\u0011e\r3e\u000F/e\u0010\rg(1e.6e\u00057e\n(g\u0014;f\u00033e\u00080f3(f\u0018\u000Ee0\u000Fe-&f\u0000'h\u0003=h\u0000\u0003g \u0014g!,d;6h'\u0002g\u001C\u000Bf8\u0005f%\u001Af\u0010\u001Eg,\u0011i&\u0016i \u0001i;\u0004i\u0007\u0011i\u0000\u0002g\u0014(f1\u001Fh\u000B\u000Fg\u001C\u001Fe.\u001Ed8;g.!i\u00186f.5h(;e\u0006\ng?;h/\u0011f\u001D\u0003e\u0008)e\u0001\u001Ae%=d<<d9\u000Ei\u0000\u001Ah./f\u0016=e7%g\u000B\u0000f\u0005\u000Bd9\u001Fh.8g\u000E/d?\u001De\u001F9e\u0005;f&\u0002e?5e$'e\u001E\u000Bf\u001C:g%(g\u0010\u0006h'#e\u000C?e\u0010\rcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestC!nnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegC:nbuenosvolverpuntossemanahabC-aagostonuevosunidoscarlosequiponiC1osmuchosalgunacorreoimagenpartirarribamarC-ahombreempleoverdadcambiomuchasfueronpasadolC-neaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposserC!neuropamediosfrenteacercademC!sofertacochesmodeloitalialetrasalgC:ncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrC!puestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosC:nicocaminositiosrazC3ndebidopruebatoledotenC-ajesC:sesperococinaorigentiendacientocC!dizhablarserC-alatinafuerzaestiloguerraentrarC)xitolC3pezagendavC-deoevitarpaginametrosjavierpadresfC!cilcabezaC!reassalidaenvC-ojapC3nabusosbienestextosllevarpuedanfuertecomC:nclaseshumanotenidobilbaounidadestC!seditarcreadoP4P;Q\u000FQ\u0007Q\u0002P>P:P0P:P8P;P8Q\rQ\u0002P>P2Q\u0001P5P5P3P>P?Q\u0000P8Q\u0002P0P:P5Q\tP5Q\u0003P6P5P\u001AP0P:P1P5P7P1Q\u000BP;P>P=P8P\u0012Q\u0001P5P?P>P4P-Q\u0002P>Q\u0002P>P<Q\u0007P5P<P=P5Q\u0002P;P5Q\u0002Q\u0000P0P7P>P=P0P3P4P5P<P=P5P\u0014P;Q\u000FP\u001FQ\u0000P8P=P0Q\u0001P=P8Q\u0005Q\u0002P5P<P:Q\u0002P>P3P>P4P2P>Q\u0002Q\u0002P0P<P!P(P\u0010P<P0Q\u000FP'Q\u0002P>P2P0Q\u0001P2P0P<P5P<Q\u0003P\"P0P:P4P2P0P=P0P<Q\rQ\u0002P8Q\rQ\u0002Q\u0003P\u0012P0P<Q\u0002P5Q\u0005P?Q\u0000P>Q\u0002Q\u0003Q\u0002P=P0P4P4P=Q\u000FP\u0012P>Q\u0002Q\u0002Q\u0000P8P=P5P9P\u0012P0Q\u0001P=P8P<Q\u0001P0P<Q\u0002P>Q\u0002Q\u0000Q\u0003P1P\u001EP=P8P<P8Q\u0000P=P5P5P\u001EP\u001EP\u001EP;P8Q\u0006Q\rQ\u0002P0P\u001EP=P0P=P5P<P4P>P<P<P>P9P4P2P5P>P=P>Q\u0001Q\u0003P4`$\u0015`%\u0007`$9`%\u0008`$\u0015`%\u0000`$8`%\u0007`$\u0015`$>`$\u0015`%\u000B`$\u0014`$0`$*`$0`$(`%\u0007`$\u000F`$\u0015`$\u0015`$?`$-`%\u0000`$\u0007`$8`$\u0015`$0`$$`%\u000B`$9`%\u000B`$\u0006`$*`$9`%\u0000`$/`$9`$/`$>`$$`$\u0015`$%`$>jagran`$\u0006`$\u001C`$\u001C`%\u000B`$\u0005`$,`$&`%\u000B`$\u0017`$\u0008`$\u001C`$>`$\u0017`$\u000F`$9`$.`$\u0007`$(`$5`$9`$/`%\u0007`$%`%\u0007`$%`%\u0000`$\u0018`$0`$\u001C`$,`$&`%\u0000`$\u0015`$\u0008`$\u001C`%\u0000`$5`%\u0007`$(`$\u0008`$(`$\u000F`$9`$0`$\t`$8`$.`%\u0007`$\u0015`$.`$5`%\u000B`$2`%\u0007`$8`$,`$.`$\u0008`$&`%\u0007`$\u0013`$0`$\u0006`$.`$,`$8`$-`$0`$,`$(`$\u001A`$2`$.`$(`$\u0006`$\u0017`$8`%\u0000`$2`%\u0000X9Y\u0004Y\tX%Y\u0004Y\tY\u0007X0X'X\"X.X1X9X/X/X'Y\u0004Y\tY\u0007X0Y\u0007X5Y\u0008X1X:Y\nX1Y\u0003X'Y\u0006Y\u0008Y\u0004X'X(Y\nY\u0006X9X1X6X0Y\u0004Y\u0003Y\u0007Y\u0006X'Y\nY\u0008Y\u0005Y\u0002X'Y\u0004X9Y\u0004Y\nX'Y\u0006X'Y\u0004Y\u0003Y\u0006X-X*Y\tY\u0002X(Y\u0004Y\u0008X-X)X'X.X1Y\u0001Y\u0002X7X9X(X/X1Y\u0003Y\u0006X%X0X'Y\u0003Y\u0005X'X'X-X/X%Y\u0004X'Y\u0001Y\nY\u0007X(X9X6Y\u0003Y\nY\u0001X(X-X+Y\u0008Y\u0005Y\u0006Y\u0008Y\u0007Y\u0008X#Y\u0006X'X,X/X'Y\u0004Y\u0007X'X3Y\u0004Y\u0005X9Y\u0006X/Y\u0004Y\nX3X9X(X1X5Y\u0004Y\tY\u0005Y\u0006X0X(Y\u0007X'X#Y\u0006Y\u0007Y\u0005X+Y\u0004Y\u0003Y\u0006X*X'Y\u0004X'X-Y\nX+Y\u0005X5X1X4X1X-X-Y\u0008Y\u0004Y\u0008Y\u0001Y\nX'X0X'Y\u0004Y\u0003Y\u0004Y\u0005X1X)X'Y\u0006X*X'Y\u0004Y\u0001X#X(Y\u0008X.X'X5X#Y\u0006X*X'Y\u0006Y\u0007X'Y\u0004Y\nX9X6Y\u0008Y\u0008Y\u0002X/X'X(Y\u0006X.Y\nX1X(Y\u0006X*Y\u0004Y\u0003Y\u0005X4X'X!Y\u0008Y\u0007Y\nX'X(Y\u0008Y\u0002X5X5Y\u0008Y\u0005X'X1Y\u0002Y\u0005X#X-X/Y\u0006X-Y\u0006X9X/Y\u0005X1X#Y\nX'X-X)Y\u0003X*X(X/Y\u0008Y\u0006Y\nX,X(Y\u0005Y\u0006Y\u0007X*X-X*X,Y\u0007X)X3Y\u0006X)Y\nX*Y\u0005Y\u0003X1X)X:X2X)Y\u0006Y\u0001X3X(Y\nX*Y\u0004Y\u0004Y\u0007Y\u0004Y\u0006X'X*Y\u0004Y\u0003Y\u0002Y\u0004X(Y\u0004Y\u0005X'X9Y\u0006Y\u0007X#Y\u0008Y\u0004X4Y\nX!Y\u0006Y\u0008X1X#Y\u0005X'Y\u0001Y\nY\u0003X(Y\u0003Y\u0004X0X'X*X1X*X(X(X#Y\u0006Y\u0007Y\u0005X3X'Y\u0006Y\u0003X(Y\nX9Y\u0001Y\u0002X/X-X3Y\u0006Y\u0004Y\u0007Y\u0005X4X9X1X#Y\u0007Y\u0004X4Y\u0007X1Y\u0002X7X1X7Y\u0004X(profileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>\r\nwrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle=\"Mobile killingshowingItaliandroppedheavilyeffects-1']);\nconfirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.\n\nThe but notdensityBritainChineselack oftributeIreland\" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang=\"return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue=\"complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role=\"missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();\r\npaymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html\">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen\n\nWhen observe</h2>\r\nModern provide\" alt=\"borders.\n\nFor \n\nMany artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>\r\n Countryignoredloss ofjust asGeorgiastrange<head><stopped1']);\r\nislandsnotableborder:list ofcarried100,000</h3>\n severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id=\"foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login\">convertviolententeredfirst\">circuitFinlandchemistshe was10px;\">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title\">tooltipSectiondesignsTurkishyounger.match(})();\n\nburningoperatedegreessource=Richardcloselyplasticentries</tr>\r\ncolor:#ul id=\"possessrollingphysicsfailingexecutecontestlink toDefault<br />\n: true,chartertourismclassicproceedexplain</h1>\r\nonline.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src=\"/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e&quot;tradingleft\">\npersonsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy\n\t\t<!--Daniel bindingblock\">imposedutilizeAbraham(except{width:putting).html(|| [];\nDATA[ *kitchenmountedactual dialectmainly _blank'installexpertsif(typeIt also&copy; \">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref=\"/\" rel=\"developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in\n\t<!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday's.html\" target=wearingAll Rig;\n})();raising Also, crucialabout\">declare-->\n<scfirefoxas muchappliesindex, s, but type = \n\r\n<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin\" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>\r\n returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of\n\nSome 'click'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion=\"pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major\":\"httpin his menu\">\nmonthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small\">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks\">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel\">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8\">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>\nevidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>\n he left).val()false);logicalbankinghome tonaming Arizonacredits);\n});\nfounderin turnCollinsbefore But thechargedTitle\">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered']);\n has theunclearEvent',both innot all\n\n<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage\" linear painterand notrarely acronymdelivershorter00&amp;as manywidth=\"/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don'tretreat. Some ww.\");\nbombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft\"><comScorAll thejQuery.touristClassicfalse\" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>\n\n. When in bothdismissExplorealways via thespaC1olwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>\n\t\tit intoranked rate oful>\r\n attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped\").css(hostilelead tolittle groups,Picture-->\r\n\r\n rows=\" objectinverse<footerCustomV><\\/scrsolvingChamberslaverywoundedwhereas!= 'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead')[0Criticsstudios>&copy;group\">assemblmaking pressedwidget.ps:\" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass=\"but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;\">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + \"gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(\" />\n\t\there isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();\n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded=\"true\"spacingis mosta more totallyfall of});\r\n immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace\">header-well asStanleybridges/globalCroatia About [0];\n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF\"bottom\"like a employslive inas seenprintermost ofub-linkrejectsand useimage\">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older\">us.js\"> Since universlarger open to!-- endlies in']);\r\n marketwho is (\"DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting \n\t\tvar March 2grew upClimate.removeskilledway the</head>face ofacting right\">to workreduceshas haderectedshow();action=book ofan area== \"htt<header\n<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage\">MobilClements\" id=\"as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded\"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;\">\r\npushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>\npeople.in one =windowfooter_a good reklamaothers,to this_cookiepanel\">London,definescrushedbaptismcoastalstatus title\" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />\r\nAtlantanucleusCounty,purely count\">easily build aonclicka givenpointerh&quot;events else {\nditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink\"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg\" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium\"DO NOT France,with a war andsecond take a >\r\n\r\n\r\nmarket.highwaydone inctivity\"last\">obligedrise to\"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right\" bicycleacing=\"day andstatingRather,higher Office are nowtimes, when a pay foron this-link\">;borderaround annual the Newput the.com\" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks\">\n();\" rea place\\u003Caabout atr>\r\n\t\tccount gives a<SCRIPTRailwaythemes/toolboxById(\"xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>\r\n<ustomVa;&gt;</importsor thatmostly &amp;re size=\"</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>\r\n\r\n<!organis <br />BeijingcatalC deutscheuropeueuskaragaeilgesvenskaespaC1amensajeusuariotrabajomC)xicopC!ginasiempresistemaoctubreduranteaC1adirempresamomentonuestroprimeratravC)sgraciasnuestraprocesoestadoscalidadpersonanC:meroacuerdomC:sicamiembroofertasalgunospaC-sesejemploderechoademC!sprivadoagregarenlacesposiblehotelessevillaprimeroC:ltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseC1oturismocC3digoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastC-tuloconocersegundoconsejofranciaminutossegundatenemosefectosmC!lagasesiC3nrevistagranadacompraringresogarcC-aacciC3necuadorquienesinclusodeberC!materiahombresmuestrapodrC-amaC1anaC:ltimaestamosoficialtambienningC:nsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner\">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo\"><adaughterauthor\" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom\">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton\" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id=\"discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive\">somewhatvictoriaWestern title=\"LocationcontractvisitorsDownloadwithout right\">\nmeasureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg\" />machines</h2>\n keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow\" valuable</label>relativebringingincreasegovernorplugins/List of Header\">\" name=\" (&quot;graduate</head>\ncommercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>\n\t\t<select citizensclothingwatching<li id=\"specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split(\"lizationOctober ){returnimproved--&gt;\n\ncoveragechairman.png\" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css\" /> websitereporteddefault\"/></a>\r\nelectricscotlandcreationquantity. ISBN 0did not instance-search-\" lang=\"speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: 'http:'script'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id=\"William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout=\"approved maximumheader\"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=\"\"intervalwirelessentitledagenciesSearch\" measuredthousandspending&hellip;new Date\" size=\"pageNamemiddle\" \" /></a>hidden\">sequencepersonaloverflowopinionsillinoislinks\">\n\t<title>versionssaturdayterminalitempropengineersectionsdesignerproposal=\"false\"EspaC1olreleasessubmit\" er&quot;additionsymptomsorientedresourceright\"><pleasurestationshistory.leaving border=contentscenter\">.\n\nSome directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal\"><span>search\">operatorrequestsa &quot;allowingDocumentrevision. \n\nThe yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1\"indicatefamiliar qualitymargin:0 contentviewportcontacts-title\">portable.length eligibleinvolvesatlanticonload=\"default.suppliedpaymentsglossary\n\nAfter guidance</td><tdencodingmiddle\">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>\n\taffectedsupportspointer;toString</small>oklahomawill be investor0\" alt=\"holidaysResourcelicensed (which . After considervisitingexplorerprimary search\" android\"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js\"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions\"campbell<!-- end</span><<br />\r\n_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=\" Companyexamples<iframe believespresentsmarshallpart of properly).\n\nThe taxonomymuch of </span>\n\" data-srtuguC*sscrollTo project<head>\r\nattorneyemphasissponsorsfancyboxworld's wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix\n<head>\narticle <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent\"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton\">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth=\"2lazyloadnovemberused in height=\"cript\">\n&nbsp;</<tr><td height:2/productcountry include footer\" &lt;!-- title\"></jquery.</form>\n(g.\u0000d=\u0013)(g9\u0001i+\u0014)hrvatskiitalianoromC\"nD\u0003tC<rkC'eX'X1X/Y\u0008tambiC)nnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuC)sdeportesproyectoproductopC:bliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniC3nimprimirmientrasamC)ricavendedorsociedadrespectorealizarregistropalabrasinterC)sentoncesespecialmiembrosrealidadcC3rdobazaragozapC!ginassocialesbloqueargestiC3nalquilersistemascienciascompletoversiC3ncompletaestudiospC:blicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayorC-aalemaniafunciC3nC:ltimoshaciendoaquellosediciC3nfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojC3venesdistritotC)cnicaconjuntoenergC-atrabajarasturiasrecienteutilizarboletC-nsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallaprC3ximoalmerC-aanimalesquiC)nescorazC3nsecciC3nbuscandoopcionesexteriorconceptotodavC-agalerC-aescribirmedicinalicenciaconsultaaspectoscrC-ticadC3laresjusticiadeberC!nperC-odonecesitamantenerpequeC1orecibidatribunaltenerifecanciC3ncanariasdescargadiversosmallorcarequieretC)cnicodeberC-aviviendafinanzasadelantefuncionaconsejosdifC-cilciudadesantiguasavanzadatC)rminounidadessC!nchezcampaC1asoftonicrevistascontienesectoresmomentosfacultadcrC)ditodiversassupuestofactoressegundospequeC1aP3P>P4P0P5Q\u0001P;P8P5Q\u0001Q\u0002Q\u000CP1Q\u000BP;P>P1Q\u000BQ\u0002Q\u000CQ\rQ\u0002P>P<P\u0015Q\u0001P;P8Q\u0002P>P3P>P<P5P=Q\u000FP2Q\u0001P5Q\u0005Q\rQ\u0002P>P9P4P0P6P5P1Q\u000BP;P8P3P>P4Q\u0003P4P5P=Q\u000CQ\rQ\u0002P>Q\u0002P1Q\u000BP;P0Q\u0001P5P1Q\u000FP>P4P8P=Q\u0001P5P1P5P=P0P4P>Q\u0001P0P9Q\u0002Q\u0004P>Q\u0002P>P=P5P3P>Q\u0001P2P>P8Q\u0001P2P>P9P8P3Q\u0000Q\u000BQ\u0002P>P6P5P2Q\u0001P5P<Q\u0001P2P>Q\u000EP;P8Q\u0008Q\u000CQ\rQ\u0002P8Q\u0005P?P>P:P0P4P=P5P9P4P>P<P0P<P8Q\u0000P0P;P8P1P>Q\u0002P5P<Q\u0003Q\u0005P>Q\u0002Q\u000FP4P2Q\u0003Q\u0005Q\u0001P5Q\u0002P8P;Q\u000EP4P8P4P5P;P>P<P8Q\u0000P5Q\u0002P5P1Q\u000FQ\u0001P2P>P5P2P8P4P5Q\u0007P5P3P>Q\rQ\u0002P8P<Q\u0001Q\u0007P5Q\u0002Q\u0002P5P<Q\u000BQ\u0006P5P=Q\u000BQ\u0001Q\u0002P0P;P2P5P4Q\u000CQ\u0002P5P<P5P2P>P4Q\u000BQ\u0002P5P1P5P2Q\u000BQ\u0008P5P=P0P<P8Q\u0002P8P?P0Q\u0002P>P<Q\u0003P?Q\u0000P0P2P;P8Q\u0006P0P>P4P=P0P3P>P4Q\u000BP7P=P0Q\u000EP<P>P3Q\u0003P4Q\u0000Q\u0003P3P2Q\u0001P5P9P8P4P5Q\u0002P:P8P=P>P>P4P=P>P4P5P;P0P4P5P;P5Q\u0001Q\u0000P>P:P8Q\u000EP=Q\u000FP2P5Q\u0001Q\u000CP\u0015Q\u0001Q\u0002Q\u000CQ\u0000P0P7P0P=P0Q\u0008P8X'Y\u0004Y\u0004Y\u0007X'Y\u0004X*Y\nX,Y\u0005Y\nX9X.X'X5X)X'Y\u0004X0Y\nX9Y\u0004Y\nY\u0007X,X/Y\nX/X'Y\u0004X\"Y\u0006X'Y\u0004X1X/X*X-Y\u0003Y\u0005X5Y\u0001X-X)Y\u0003X'Y\u0006X*X'Y\u0004Y\u0004Y\nY\nY\u0003Y\u0008Y\u0006X4X(Y\u0003X)Y\u0001Y\nY\u0007X'X(Y\u0006X'X*X-Y\u0008X'X!X#Y\u0003X+X1X.Y\u0004X'Y\u0004X'Y\u0004X-X(X/Y\u0004Y\nY\u0004X/X1Y\u0008X3X'X6X:X7X*Y\u0003Y\u0008Y\u0006Y\u0007Y\u0006X'Y\u0003X3X'X-X)Y\u0006X'X/Y\nX'Y\u0004X7X(X9Y\u0004Y\nY\u0003X4Y\u0003X1X'Y\nY\u0005Y\u0003Y\u0006Y\u0005Y\u0006Y\u0007X'X4X1Y\u0003X)X1X&Y\nX3Y\u0006X4Y\nX7Y\u0005X'X0X'X'Y\u0004Y\u0001Y\u0006X4X(X'X(X*X9X(X1X1X-Y\u0005X)Y\u0003X'Y\u0001X)Y\nY\u0002Y\u0008Y\u0004Y\u0005X1Y\u0003X2Y\u0003Y\u0004Y\u0005X)X#X-Y\u0005X/Y\u0002Y\u0004X(Y\nY\nX9Y\u0006Y\nX5Y\u0008X1X)X7X1Y\nY\u0002X4X'X1Y\u0003X,Y\u0008X'Y\u0004X#X.X1Y\tY\u0005X9Y\u0006X'X'X(X-X+X9X1Y\u0008X6X(X4Y\u0003Y\u0004Y\u0005X3X,Y\u0004X(Y\u0006X'Y\u0006X.X'Y\u0004X/Y\u0003X*X'X(Y\u0003Y\u0004Y\nX)X(X/Y\u0008Y\u0006X#Y\nX6X'Y\nY\u0008X,X/Y\u0001X1Y\nY\u0002Y\u0003X*X(X*X#Y\u0001X6Y\u0004Y\u0005X7X(X.X'Y\u0003X+X1X(X'X1Y\u0003X'Y\u0001X6Y\u0004X'X-Y\u0004Y\tY\u0006Y\u0001X3Y\u0007X#Y\nX'Y\u0005X1X/Y\u0008X/X#Y\u0006Y\u0007X'X/Y\nY\u0006X'X'Y\u0004X'Y\u0006Y\u0005X9X1X6X*X9Y\u0004Y\u0005X/X'X.Y\u0004Y\u0005Y\u0005Y\u0003Y\u0006\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0007\u0006\u0005\u0004\u0003\u0002\u0001\u0000\u0008\t\n\u000B\u000C\r\u000E\u000F\u000F\u000E\r\u000C\u000B\n\t\u0008\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0017\u0016\u0015\u0014\u0013\u0012\u0011\u0010\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u001F\u001E\u001D\u001C\u001B\u001A\u0019\u0018\u007F\u007F\u007F\u007F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u007F\u007F\u007F\u007F\u0001\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0003\u0000\u0000\u0000\u007F\u007F\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u007F\u007F\u0000\u0001\u0000\u0000\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0000\u0000\u0001\u0000\u0002\u0000\u0003\u0000\u0004\u0000\u0005\u0000\u0006\u0000\u0007resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter\" value=\"</select>Australia\" class=\"situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement\" title=\"potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>\r\nstatementattentionBiography} else {\nsolutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter\">\nexceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick=\"biographyotherwisepermanentFranC'aisHollywoodexpansionstandards</style>\nreductionDecember preferredCambridgeopponentsBusiness confusion>\n<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>\nmountainslike the essentialfinancialselectionaction=\"/abandonedEducationparseInt(stabilityunable to</title>\nrelationsNote thatefficientperformedtwo yearsSince thethereforewrapper\">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>\nsuspectedmargin: 0spiritual</head>\n\nmicrosoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header\">February numerous overflow:componentfragmentsexcellentcolspan=\"technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>\n\tsponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting\" width=\".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper\"enough toalong thedelivered-->\r\n<!--American protectedNovember </style><furnitureInternet onblur=\"suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir=\"ltr\"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;\n\nsouthwestthe rightradiationmay have unescape(spoken in\" href=\"/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip\">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>\ncame fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8\" /><![CDATA[\">ContactSouthern bgcolor=\"series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->\n<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=\">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id=\"precedingTechnicalphysicistoccurs innavigatorsection\">span id=\"sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt=\"in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent\">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id=\"right\">\r\nresidenceleave thecontent\">are often })();\r\nprobably Professor-button\" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular\">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor\n&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved\n\nIn the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also\n<head>\n<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained\"></div>\n</a></td>depend onsearch\">\npieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue=\"\">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.\n\nAfter , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover\" style=\"states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of\r\n<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href=\"y:inline;Church ofthe eventvery highofficial -height: content=\"/cgi-bin/to createafrikaansesperantofranC'aislatvieE!ulietuviE3D\u000CeE!tinaD\reE!tina`9\u0004`8\u0017`8\"f\u0017%f\u001C,h*\u001Eg.\u0000d=\u0013e-\u0017g9\u0001i+\u0014e-\u0017m\u0015\u001Cj5-l\u00164d8:d;\u0000d9\u0008h.!g.\u0017f\u001C:g,\u0014h.0f\u001C,h(\u000Eh+\u0016e\r\u0000f\u001C\re\n!e\u0019(d:\u0012h\u0001\u0014g=\u0011f\u0008?e\u001C0d:'d?1d9\u0010i\u0003(e\u0007:g\t\u0008g$>f\u000E\u0012h!\u000Cf&\u001Ci\u0003(h\u0010=f <h?\u001Bd8\u0000f-%f\u0014/d;\u0018e.\u001Di*\u000Ch/\u0001g \u0001e'\u0014e\u0011\u0018d<\u001Af\u00150f\r.e:\u0013f6\u0008h49h\u0000\u0005e\n\u001Ee\u0005,e.$h.(h.:e\u000C:f71e\u001C3e8\u0002f\u0012-f\u0014>e\u0019(e\u000C\u0017d:,e8\u0002e$'e-&g\u0014\u001Fh6\nf\u001D%h6\ng.!g\u0010\u0006e\u0011\u0018d?!f\u0001/g=\u0011serviciosartC-culoargentinabarcelonacualquierpublicadoproductospolC-ticarespuestawikipediasiguientebC:squedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciC3nnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomC-aimC!genescontactardescargarnecesarioatenciC3ntelC)fonocomisiC3ncancionescapacidadencontraranC!lisisfavoritostC)rminosprovinciaetiquetaselementosfuncionesresultadocarC!cterpropiedadprincipionecesidadmunicipalcreaciC3ndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzC!lezdocumentopelC-cularecientesgeneralestarragonaprC!cticanovedadespropuestapacientestC)cnicasobjetivoscontactos`$.`%\u0007`$\u0002`$2`$?`$\u000F`$9`%\u0008`$\u0002`$\u0017`$/`$>`$8`$>`$%`$\u000F`$5`$\u0002`$0`$9`%\u0007`$\u0015`%\u000B`$\u0008`$\u0015`%\u0001`$\u001B`$0`$9`$>`$,`$>`$&`$\u0015`$9`$>`$8`$-`%\u0000`$9`%\u0001`$\u000F`$0`$9`%\u0000`$.`%\u0008`$\u0002`$&`$?`$(`$,`$>`$$diplodocs`$8`$.`$/`$0`%\u0002`$*`$(`$>`$.`$*`$$`$>`$+`$?`$0`$\u0014`$8`$$`$$`$0`$9`$2`%\u000B`$\u0017`$9`%\u0001`$\u0006`$,`$>`$0`$&`%\u0007`$6`$9`%\u0001`$\u0008`$\u0016`%\u0007`$2`$/`$&`$?`$\u0015`$>`$.`$5`%\u0007`$,`$$`%\u0000`$(`$,`%\u0000`$\u001A`$.`%\u000C`$$`$8`$>`$2`$2`%\u0007`$\u0016`$\u001C`%\t`$,`$.`$&`$&`$$`$%`$>`$(`$9`%\u0000`$6`$9`$0`$\u0005`$2`$\u0017`$\u0015`$-`%\u0000`$(`$\u0017`$0`$*`$>`$8`$0`$>`$$`$\u0015`$?`$\u000F`$\t`$8`%\u0007`$\u0017`$/`%\u0000`$9`%\u0002`$\u0001`$\u0006`$\u0017`%\u0007`$\u001F`%\u0000`$.`$\u0016`%\u000B`$\u001C`$\u0015`$>`$0`$\u0005`$-`%\u0000`$\u0017`$/`%\u0007`$$`%\u0001`$.`$5`%\u000B`$\u001F`$&`%\u0007`$\u0002`$\u0005`$\u0017`$0`$\u0010`$8`%\u0007`$.`%\u0007`$2`$2`$\u0017`$>`$9`$>`$2`$\n`$*`$0`$\u001A`$>`$0`$\u0010`$8`$>`$&`%\u0007`$0`$\u001C`$?`$8`$&`$?`$2`$,`$\u0002`$&`$,`$(`$>`$9`%\u0002`$\u0002`$2`$>`$\u0016`$\u001C`%\u0000`$$`$,`$\u001F`$(`$.`$?`$2`$\u0007`$8`%\u0007`$\u0006`$(`%\u0007`$(`$/`$>`$\u0015`%\u0001`$2`$2`%\t`$\u0017`$-`$>`$\u0017`$0`%\u0007`$2`$\u001C`$\u0017`$9`$0`$>`$.`$2`$\u0017`%\u0007`$*`%\u0007`$\u001C`$9`$>`$%`$\u0007`$8`%\u0000`$8`$9`%\u0000`$\u0015`$2`$>`$ `%\u0000`$\u0015`$9`$>`$\u0001`$&`%\u0002`$0`$$`$9`$$`$8`$>`$$`$/`$>`$&`$\u0006`$/`$>`$*`$>`$\u0015`$\u0015`%\u000C`$(`$6`$>`$.`$&`%\u0007`$\u0016`$/`$9`%\u0000`$0`$>`$/`$\u0016`%\u0001`$&`$2`$\u0017`%\u0000categoriesexperience</title>\r\nCopyright javascriptconditionseverything<p class=\"technologybackground<a class=\"management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox\" techniquesprotectionapparentlyas well asunt', 'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor=\"#especially content=\"productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=\".indexOf(\"conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus=\"<form id=\"processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png\" (document,boundariesexpressionsettlementBackgroundout of theenterprise(\"https:\" unescape(\"password\" democratic<a href=\"/wrapper\">\nmembershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher\"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick=\"considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic\" height=\"link rel=\".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class=\"0px;marginmechanicalstatisticscelebratedGovernment\n\nDuring tdevelopersartificialequivalentoriginatedCommissionattachment<span id=\"there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang=\"en\" </style>\r\nabsolute; supportingextremely mainstream</strong> popularityemployment</table>\r\n colspan=\"</form>\n conversionabout the </p></div>integrated\" lang=\"enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class=\"<a title=\"(includingparametersprohibited= \"http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0\" class=\"completelyillustratefive yearsinstrumentPublishing1\" class=\"psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;\nfunction it was theConventionautomobileProtestantaggressiveafter the Similarly,\" /></div>collection\r\nfunctionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>\n</.indexOf('i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }\n</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt=\"adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to\"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css\"\tfunction innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>\n\tdiplomaticcontainingperformingextensionsmay not beconcept of onclick=\"It is alsofinancial making theLuxembourgadditionalare calledengaged in\"script\");but it waselectroniconsubmit=\"\n<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences\n</head>\r\nrecognisedinitializelimited toAlexandriaretirementAdventuresfour years\n\n&lt;!-- increasingdecorationh3 class=\"origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews\" width=\"1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class=\"Scientificclass=\"no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional\n<head>\n<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix\">the publicmany yearswhich wereover time,synonymouscontent\">\npresumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined\"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan=\"only a fewmeant thatled to the-->\r\n<div <fieldset>Archbishop class=\"nobeing usedapproachesprivilegesnoscript>\nresults inmay be theEaster eggmechanismsreasonablePopulationCollectionselected\">noscript>\r/index.phparrival of-jssdk'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>\n\t\tcomplaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype=\"absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>\npercentagebest-knowncreating a\" dir=\"ltrLieutenant\n<div id=\"they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.\n\nIn the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/\" class=\"geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid=\"searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured\">is said tostructuralreferendummost oftena separate->\n<div id Official worldwide.aria-labelthe planetand it wasd\" value=\"looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id=\"opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/\" title=\".com/indextaking thepittsburghcontent\">\r<script>(fturned outhaving the</span>\r\n occasionalbecause itstarted tophysically></div>\n created byCurrently, bgcolor=\"tabindex=\"disastrousAnalytics also has a><div id=\"</style>\n<called forsinger and.src = \"//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportuguC*sW\"W\u0011W(W\u0019W*Y\u0001X'X1X3[\u000CdesarrollocomentarioeducaciC3nseptiembreregistradodirecciC3nubicaciC3npublicidadrespuestasresultadosimportantereservadosartC-culosdiferentessiguientesrepC:blicasituaciC3nministerioprivacidaddirectorioformaciC3npoblaciC3npresidentecont";
+ private static final String DATA1 = "enidosaccesoriostechnoratipersonalescategorC-aespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopolC-ticasanterioresdocumentosnaturalezamaterialesdiferenciaeconC3micatransporterodrC-guezparticiparencuentrandiscusiC3nestructurafundaciC3nfrecuentespermanentetotalmenteP<P>P6P=P>P1Q\u0003P4P5Q\u0002P<P>P6P5Q\u0002P2Q\u0000P5P<Q\u000FQ\u0002P0P:P6P5Q\u0007Q\u0002P>P1Q\u000BP1P>P;P5P5P>Q\u0007P5P=Q\u000CQ\rQ\u0002P>P3P>P:P>P3P4P0P?P>Q\u0001P;P5P2Q\u0001P5P3P>Q\u0001P0P9Q\u0002P5Q\u0007P5Q\u0000P5P7P<P>P3Q\u0003Q\u0002Q\u0001P0P9Q\u0002P0P6P8P7P=P8P<P5P6P4Q\u0003P1Q\u0003P4Q\u0003Q\u0002P\u001FP>P8Q\u0001P:P7P4P5Q\u0001Q\u000CP2P8P4P5P>Q\u0001P2Q\u000FP7P8P=Q\u0003P6P=P>Q\u0001P2P>P5P9P;Q\u000EP4P5P9P?P>Q\u0000P=P>P<P=P>P3P>P4P5Q\u0002P5P9Q\u0001P2P>P8Q\u0005P?Q\u0000P0P2P0Q\u0002P0P:P>P9P<P5Q\u0001Q\u0002P>P8P<P5P5Q\u0002P6P8P7P=Q\u000CP>P4P=P>P9P;Q\u0003Q\u0007Q\u0008P5P?P5Q\u0000P5P4Q\u0007P0Q\u0001Q\u0002P8Q\u0007P0Q\u0001Q\u0002Q\u000CQ\u0000P0P1P>Q\u0002P=P>P2Q\u000BQ\u0005P?Q\u0000P0P2P>Q\u0001P>P1P>P9P?P>Q\u0002P>P<P<P5P=P5P5Q\u0007P8Q\u0001P;P5P=P>P2Q\u000BP5Q\u0003Q\u0001P;Q\u0003P3P>P:P>P;P>P=P0P7P0P4Q\u0002P0P:P>P5Q\u0002P>P3P4P0P?P>Q\u0007Q\u0002P8P\u001FP>Q\u0001P;P5Q\u0002P0P:P8P5P=P>P2Q\u000BP9Q\u0001Q\u0002P>P8Q\u0002Q\u0002P0P:P8Q\u0005Q\u0001Q\u0000P0P7Q\u0003P!P0P=P:Q\u0002Q\u0004P>Q\u0000Q\u0003P<P\u001AP>P3P4P0P:P=P8P3P8Q\u0001P;P>P2P0P=P0Q\u0008P5P9P=P0P9Q\u0002P8Q\u0001P2P>P8P<Q\u0001P2Q\u000FP7Q\u000CP;Q\u000EP1P>P9Q\u0007P0Q\u0001Q\u0002P>Q\u0001Q\u0000P5P4P8P\u001AQ\u0000P>P<P5P$P>Q\u0000Q\u0003P<Q\u0000Q\u000BP=P:P5Q\u0001Q\u0002P0P;P8P?P>P8Q\u0001P:Q\u0002Q\u000BQ\u0001Q\u000FQ\u0007P<P5Q\u0001Q\u000FQ\u0006Q\u0006P5P=Q\u0002Q\u0000Q\u0002Q\u0000Q\u0003P4P0Q\u0001P0P<Q\u000BQ\u0005Q\u0000Q\u000BP=P:P0P\u001DP>P2Q\u000BP9Q\u0007P0Q\u0001P>P2P<P5Q\u0001Q\u0002P0Q\u0004P8P;Q\u000CP<P<P0Q\u0000Q\u0002P0Q\u0001Q\u0002Q\u0000P0P=P<P5Q\u0001Q\u0002P5Q\u0002P5P:Q\u0001Q\u0002P=P0Q\u0008P8Q\u0005P<P8P=Q\u0003Q\u0002P8P<P5P=P8P8P<P5Q\u000EQ\u0002P=P>P<P5Q\u0000P3P>Q\u0000P>P4Q\u0001P0P<P>P<Q\rQ\u0002P>P<Q\u0003P:P>P=Q\u0006P5Q\u0001P2P>P5P<P:P0P:P>P9P\u0010Q\u0000Q\u0005P8P2Y\u0005Y\u0006X*X/Y\tX%X1X3X'Y\u0004X1X3X'Y\u0004X)X'Y\u0004X9X'Y\u0005Y\u0003X*X(Y\u0007X'X(X1X'Y\u0005X,X'Y\u0004Y\nY\u0008Y\u0005X'Y\u0004X5Y\u0008X1X,X/Y\nX/X)X'Y\u0004X9X6Y\u0008X%X6X'Y\u0001X)X'Y\u0004Y\u0002X3Y\u0005X'Y\u0004X9X'X(X*X-Y\u0005Y\nY\u0004Y\u0005Y\u0004Y\u0001X'X*Y\u0005Y\u0004X*Y\u0002Y\tX*X9X/Y\nY\u0004X'Y\u0004X4X9X1X#X.X(X'X1X*X7Y\u0008Y\nX1X9Y\u0004Y\nY\u0003Y\u0005X%X1Y\u0001X'Y\u0002X7Y\u0004X(X'X*X'Y\u0004Y\u0004X:X)X*X1X*Y\nX(X'Y\u0004Y\u0006X'X3X'Y\u0004X4Y\nX.Y\u0005Y\u0006X*X/Y\nX'Y\u0004X9X1X(X'Y\u0004Y\u0002X5X5X'Y\u0001Y\u0004X'Y\u0005X9Y\u0004Y\nY\u0007X'X*X-X/Y\nX+X'Y\u0004Y\u0004Y\u0007Y\u0005X'Y\u0004X9Y\u0005Y\u0004Y\u0005Y\u0003X*X(X)Y\nY\u0005Y\u0003Y\u0006Y\u0003X'Y\u0004X7Y\u0001Y\u0004Y\u0001Y\nX/Y\nY\u0008X%X/X'X1X)X*X'X1Y\nX.X'Y\u0004X5X-X)X*X3X,Y\nY\u0004X'Y\u0004Y\u0008Y\u0002X*X9Y\u0006X/Y\u0005X'Y\u0005X/Y\nY\u0006X)X*X5Y\u0005Y\nY\u0005X#X1X4Y\nY\u0001X'Y\u0004X0Y\nY\u0006X9X1X(Y\nX)X(Y\u0008X'X(X)X#Y\u0004X9X'X(X'Y\u0004X3Y\u0001X1Y\u0005X4X'Y\u0003Y\u0004X*X9X'Y\u0004Y\tX'Y\u0004X#Y\u0008Y\u0004X'Y\u0004X3Y\u0006X)X,X'Y\u0005X9X)X'Y\u0004X5X-Y\u0001X'Y\u0004X/Y\nY\u0006Y\u0003Y\u0004Y\u0005X'X*X'Y\u0004X.X'X5X'Y\u0004Y\u0005Y\u0004Y\u0001X#X9X6X'X!Y\u0003X*X'X(X)X'Y\u0004X.Y\nX1X1X3X'X&Y\u0004X'Y\u0004Y\u0002Y\u0004X(X'Y\u0004X#X/X(Y\u0005Y\u0002X'X7X9Y\u0005X1X'X3Y\u0004Y\u0005Y\u0006X7Y\u0002X)X'Y\u0004Y\u0003X*X(X'Y\u0004X1X,Y\u0004X'X4X*X1Y\u0003X'Y\u0004Y\u0002X/Y\u0005Y\nX9X7Y\nY\u0003sByTagName(.jpg\" alt=\"1px solid #.gif\" alt=\"transparentinformationapplication\" onclick=\"establishedadvertising.png\" alt=\"environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright\">0\" height=\"even thoughreplacementdestinationCorporation<ul class=\"AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class=\"hundreds of\n\nHowever, compositionclear:both;cooperationwithin the label for=\"border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength=\"switzerlandDevelopmentessentially\n\nAlthough </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics\n\t<div id=\"illustratedengineeringterritoriesauthoritiesdistributed6\" height=\"sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class=\"more recentit has beeninvasion of).getTime()fundamentalDespite the\"><div id=\"inspirationexaminationpreparationexplanation<input id=\"</a></span>versions ofinstrumentsbefore the = 'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright\" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content\">\n<td class=\"undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src=\"/<h1 class=\"publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=\";width:100%independent<h3 class=\" onchange=\").addClass(interactionOne of the daughter ofaccessoriesbranches of\r\n<div id=\"the largestdeclarationregulationsInformationtranslationdocumentaryin order to\">\n<head>\n<\" height=\"1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer\">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class=\"distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>\n</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>\n selected=\"high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1\"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex=\"it could be<noscript>\nhaving been\r\n<head>\r\n< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often\"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval\"></span></in New Yorkadditional compression\n\n<div id=\"incorporate;</script><attachEventbecame the \" target=\"_carried outSome of thescience andthe time ofContainer\">maintainingChristopherMuch of thewritings of\" height=\"2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit=\"director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class=\"Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the\" height=\"3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>\r\nContinentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name=\"TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel=\"This is the <a href=\"/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og=\"><a class=\"class=\"textConversion may be usedmanufactureafter beingclearfix\">\nquestion ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html\"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period\" name=\"q\" confined toa result ofvalue=\"\" />is actuallyEnvironment\r\n</head>\r\nConversely,>\n<div id=\"0\" width=\"1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious\">this is notthe presentif they areand finallya matter of\r\n\t</div>\r\n\r\n</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer\" class=\"frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>\n<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger\n\t</script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>\n they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight=\"0\" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class=\"btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world'scan lead torefers to aborder=\"0\" government winning theresulted in while the Washington,the subjectcity in the></div>\r\n\t\treflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=\"\"><a href=\"themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href=\"/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in\t\t<div id=\"it\" value=\"language ofas they areproduced inis that theexplain thediv></div>\nHowever thelead to the\t<a href=\"/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldslovenD\rinacomentariosuniversidadcondicionesactividadesexperienciatecnologC-aproducciC3npuntuaciC3naplicaciC3ncontraseC1acategorC-asregistrarseprofesionaltratamientoregC-stratesecretarC-aprincipalesprotecciC3nimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociaciC3ndisponiblesevaluaciC3nestudiantesresponsableresoluciC3nguadalajararegistradosoportunidadcomercialesfotografC-aautoridadesingenierC-atelevisiC3ncompetenciaoperacionesestablecidosimplementeactualmentenavegaciC3nconformidadline-height:font-family:\" : \"http://applicationslink\" href=\"specifically//<![CDATA[\nOrganizationdistribution0px; height:relationshipdevice-width<div class=\"<label for=\"registration</noscript>\n/index.html\"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name=\"intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class=\"organisationcivilization19th centuryarchitectureincorporated20th century-container\">most notably/></a></div>notification'undefined')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang=\"&lt;/sup&gt;dealing withphiladelphiahistorically);</script>\npadding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd\">\r\n<htgeographicalConstitution', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style=\"Encyclopediaiframe src=\"demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence\" tabindex=\"float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time\"><a class=\"In addition,description+conversationcontact withis generallyr\" content=\"representing&lt;math&gt;presentationoccasionally<img width=\"navigation\">compensationchampionshipmedia=\"all\" violation ofreference toreturn true;Strict//EN\" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}\n</script>\nChristianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=\"\"><a href=\"/introductionbelonging toclaimed thatconsequences<meta name=\"Guide to theoverwhelmingagainst the concentrated,\n.nontouch observations</a>\n</div>\nf (document.border: 1px {font-size:1treatment of0\" height=\"1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript\" neverthelesssignificanceBroadcasting>&nbsp;</td>container\">\nsuch as the influence ofa particularsrc='http://navigation\" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite\" xml:lang=\"deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype=\"image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet\t<ul class=\"installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures\n\t\t<a href=\"close to theexamples of is about the(see below).\" id=\"searchprofessionalis availablethe official\t\t</script>\n\n\t\t<div id=\"accelerationthrough the Hall of Famedescriptionstranslationsinterference type='text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the\t<li class=\"instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class=\"aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc=\"http://px; height: available tomanufacturerhuman rightslink href=\"/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>\r\nconsider thean estimatedthe National<div id=\"pagresulting incommissionedanalogous toare required/ul>\n</div>\nwas based onand became a&nbsp;&nbsp;t\" value=\"\" was capturedno more thanrespectivelycontinue to >\r\n<head>\r\n<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml\" title=\"weight:bold;creating thedisplay:nonereplaced the<img src=\"/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css\" media=\"People from available onproved to besuggestions\"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class=\"evidence forexplanationsenvironments\"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign=\"top\"principle ofat the time,</noscript>\rsaid to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style=\"input name=\"the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class=\"lastworking with'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the\n</script>\n\nan effort toincrease theto the southspacing=\"0\">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>\nthought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds\" content=\"authority ofnorthwestern</div>\n<div \"></div>\r\n consultationcommunity ofthe nationalit should beparticipants align=\"leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class=\"splace in thewhere he was<li class=\"fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions\">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class=\"effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previousconsistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\\s+|\\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers\t<link rel=\"provided thethe story ofcompetitionsenglish (UK)english (US)P\u001CP>P=P3P>P;P!Q\u0000P?Q\u0001P:P8Q\u0001Q\u0000P?Q\u0001P:P8Q\u0001Q\u0000P?Q\u0001P:P>Y\u0004X9X1X(Y\nX)f-#i+\u0014d8-f\u0016\u0007g.\u0000d=\u0013d8-f\u0016\u0007g9\u0001d=\u0013d8-f\u0016\u0007f\u001C\ti\u0019\u0010e\u0005,e\u000F8d::f0\u0011f\u0014?e:\u001Ci\u0018?i\u0007\u000Ce74e74g$>d<\u001Ad8;d9\tf\u0013\rd=\u001Cg3;g;\u001Ff\u0014?g-\u0016f3\u0015h'\u0004informaciC3nherramientaselectrC3nicodescripciC3nclasificadosconocimientopublicaciC3nrelacionadasinformC!ticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecontC!ctenoshabitacionescumplimientorestaurantesdisposiciC3nconsecuenciaelectrC3nicaaplicacionesdesconectadoinstalaciC3nrealizaciC3nutilizaciC3nenciclopediaenfermedadesinstrumentosexperienciasinstituciC3nparticularessubcategoriaQ\u0002P>P;Q\u000CP:P>P P>Q\u0001Q\u0001P8P8Q\u0000P0P1P>Q\u0002Q\u000BP1P>P;Q\u000CQ\u0008P5P?Q\u0000P>Q\u0001Q\u0002P>P<P>P6P5Q\u0002P5P4Q\u0000Q\u0003P3P8Q\u0005Q\u0001P;Q\u0003Q\u0007P0P5Q\u0001P5P9Q\u0007P0Q\u0001P2Q\u0001P5P3P4P0P P>Q\u0001Q\u0001P8Q\u000FP\u001CP>Q\u0001P:P2P5P4Q\u0000Q\u0003P3P8P5P3P>Q\u0000P>P4P0P2P>P?Q\u0000P>Q\u0001P4P0P=P=Q\u000BQ\u0005P4P>P;P6P=Q\u000BP8P<P5P=P=P>P\u001CP>Q\u0001P:P2Q\u000BQ\u0000Q\u0003P1P;P5P9P\u001CP>Q\u0001P:P2P0Q\u0001Q\u0002Q\u0000P0P=Q\u000BP=P8Q\u0007P5P3P>Q\u0000P0P1P>Q\u0002P5P4P>P;P6P5P=Q\u0003Q\u0001P;Q\u0003P3P8Q\u0002P5P?P5Q\u0000Q\u000CP\u001EP4P=P0P:P>P?P>Q\u0002P>P<Q\u0003Q\u0000P0P1P>Q\u0002Q\u0003P0P?Q\u0000P5P;Q\u000FP2P>P>P1Q\tP5P>P4P=P>P3P>Q\u0001P2P>P5P3P>Q\u0001Q\u0002P0Q\u0002Q\u000CP8P4Q\u0000Q\u0003P3P>P9Q\u0004P>Q\u0000Q\u0003P<P5Q\u0005P>Q\u0000P>Q\u0008P>P?Q\u0000P>Q\u0002P8P2Q\u0001Q\u0001Q\u000BP;P:P0P:P0P6P4Q\u000BP9P2P;P0Q\u0001Q\u0002P8P3Q\u0000Q\u0003P?P?Q\u000BP2P<P5Q\u0001Q\u0002P5Q\u0000P0P1P>Q\u0002P0Q\u0001P:P0P7P0P;P?P5Q\u0000P2Q\u000BP9P4P5P;P0Q\u0002Q\u000CP4P5P=Q\u000CP3P8P?P5Q\u0000P8P>P4P1P8P7P=P5Q\u0001P>Q\u0001P=P>P2P5P<P>P<P5P=Q\u0002P:Q\u0003P?P8Q\u0002Q\u000CP4P>P;P6P=P0Q\u0000P0P<P:P0Q\u0005P=P0Q\u0007P0P;P>P P0P1P>Q\u0002P0P\"P>P;Q\u000CP:P>Q\u0001P>P2Q\u0001P5P<P2Q\u0002P>Q\u0000P>P9P=P0Q\u0007P0P;P0Q\u0001P?P8Q\u0001P>P:Q\u0001P;Q\u0003P6P1Q\u000BQ\u0001P8Q\u0001Q\u0002P5P<P?P5Q\u0007P0Q\u0002P8P=P>P2P>P3P>P?P>P<P>Q\tP8Q\u0001P0P9Q\u0002P>P2P?P>Q\u0007P5P<Q\u0003P?P>P<P>Q\tQ\u000CP4P>P;P6P=P>Q\u0001Q\u0001Q\u000BP;P:P8P1Q\u000BQ\u0001Q\u0002Q\u0000P>P4P0P=P=Q\u000BP5P<P=P>P3P8P5P?Q\u0000P>P5P:Q\u0002P!P5P9Q\u0007P0Q\u0001P<P>P4P5P;P8Q\u0002P0P:P>P3P>P>P=P;P0P9P=P3P>Q\u0000P>P4P5P2P5Q\u0000Q\u0001P8Q\u000FQ\u0001Q\u0002Q\u0000P0P=P5Q\u0004P8P;Q\u000CP<Q\u000BQ\u0003Q\u0000P>P2P=Q\u000FQ\u0000P0P7P=Q\u000BQ\u0005P8Q\u0001P:P0Q\u0002Q\u000CP=P5P4P5P;Q\u000EQ\u000FP=P2P0Q\u0000Q\u000FP<P5P=Q\u000CQ\u0008P5P<P=P>P3P8Q\u0005P4P0P=P=P>P9P7P=P0Q\u0007P8Q\u0002P=P5P;Q\u000CP7Q\u000FQ\u0004P>Q\u0000Q\u0003P<P0P\"P5P?P5Q\u0000Q\u000CP<P5Q\u0001Q\u000FQ\u0006P0P7P0Q\tP8Q\u0002Q\u000BP\u001BQ\u0003Q\u0007Q\u0008P8P5`$(`$9`%\u0000`$\u0002`$\u0015`$0`$(`%\u0007`$\u0005`$*`$(`%\u0007`$\u0015`$?`$/`$>`$\u0015`$0`%\u0007`$\u0002`$\u0005`$(`%\r`$/`$\u0015`%\r`$/`$>`$\u0017`$>`$\u0007`$!`$,`$>`$0`%\u0007`$\u0015`$?`$8`%\u0000`$&`$?`$/`$>`$*`$9`$2`%\u0007`$8`$?`$\u0002`$9`$-`$>`$0`$$`$\u0005`$*`$(`%\u0000`$5`$>`$2`%\u0007`$8`%\u0007`$5`$>`$\u0015`$0`$$`%\u0007`$.`%\u0007`$0`%\u0007`$9`%\u000B`$(`%\u0007`$8`$\u0015`$$`%\u0007`$,`$9`%\u0001`$$`$8`$>`$\u0007`$\u001F`$9`%\u000B`$\u0017`$>`$\u001C`$>`$(`%\u0007`$.`$?`$(`$\u001F`$\u0015`$0`$$`$>`$\u0015`$0`$(`$>`$\t`$(`$\u0015`%\u0007`$/`$9`$>`$\u0001`$8`$,`$8`%\u0007`$-`$>`$7`$>`$\u0006`$*`$\u0015`%\u0007`$2`$?`$/`%\u0007`$6`%\u0001`$0`%\u0002`$\u0007`$8`$\u0015`%\u0007`$\u0018`$\u0002`$\u001F`%\u0007`$.`%\u0007`$0`%\u0000`$8`$\u0015`$$`$>`$.`%\u0007`$0`$>`$2`%\u0007`$\u0015`$0`$\u0005`$'`$?`$\u0015`$\u0005`$*`$(`$>`$8`$.`$>`$\u001C`$.`%\u0001`$\u001D`%\u0007`$\u0015`$>`$0`$#`$9`%\u000B`$$`$>`$\u0015`$!`$<`%\u0000`$/`$9`$>`$\u0002`$9`%\u000B`$\u001F`$2`$6`$,`%\r`$&`$2`$?`$/`$>`$\u001C`%\u0000`$5`$(`$\u001C`$>`$$`$>`$\u0015`%\u0008`$8`%\u0007`$\u0006`$*`$\u0015`$>`$5`$>`$2`%\u0000`$&`%\u0007`$(`%\u0007`$*`%\u0002`$0`%\u0000`$*`$>`$(`%\u0000`$\t`$8`$\u0015`%\u0007`$9`%\u000B`$\u0017`%\u0000`$,`%\u0008`$ `$\u0015`$\u0006`$*`$\u0015`%\u0000`$5`$0`%\r`$7`$\u0017`$>`$\u0002`$5`$\u0006`$*`$\u0015`%\u000B`$\u001C`$?`$2`$>`$\u001C`$>`$(`$>`$8`$9`$.`$$`$9`$.`%\u0007`$\u0002`$\t`$(`$\u0015`%\u0000`$/`$>`$9`%\u0002`$&`$0`%\r`$\u001C`$8`%\u0002`$\u001A`%\u0000`$*`$8`$\u0002`$&`$8`$5`$>`$2`$9`%\u000B`$(`$>`$9`%\u000B`$$`%\u0000`$\u001C`%\u0008`$8`%\u0007`$5`$>`$*`$8`$\u001C`$(`$$`$>`$(`%\u0007`$$`$>`$\u001C`$>`$0`%\u0000`$\u0018`$>`$/`$2`$\u001C`$?`$2`%\u0007`$(`%\u0000`$\u001A`%\u0007`$\u001C`$>`$\u0002`$\u001A`$*`$$`%\r`$0`$\u0017`%\u0002`$\u0017`$2`$\u001C`$>`$$`%\u0007`$,`$>`$9`$0`$\u0006`$*`$(`%\u0007`$5`$>`$9`$(`$\u0007`$8`$\u0015`$>`$8`%\u0001`$,`$9`$0`$9`$(`%\u0007`$\u0007`$8`$8`%\u0007`$8`$9`$?`$$`$,`$!`$<`%\u0007`$\u0018`$\u001F`$(`$>`$$`$2`$>`$6`$*`$>`$\u0002`$\u001A`$6`%\r`$0`%\u0000`$,`$!`$<`%\u0000`$9`%\u000B`$$`%\u0007`$8`$>`$\u0008`$\u001F`$6`$>`$/`$&`$8`$\u0015`$$`%\u0000`$\u001C`$>`$$`%\u0000`$5`$>`$2`$>`$9`$\u001C`$>`$0`$*`$\u001F`$(`$>`$0`$\u0016`$(`%\u0007`$8`$!`$<`$\u0015`$.`$?`$2`$>`$\t`$8`$\u0015`%\u0000`$\u0015`%\u0007`$5`$2`$2`$\u0017`$$`$>`$\u0016`$>`$(`$>`$\u0005`$0`%\r`$%`$\u001C`$9`$>`$\u0002`$&`%\u0007`$\u0016`$>`$*`$9`$2`%\u0000`$(`$?`$/`$.`$,`$?`$(`$>`$,`%\u0008`$\u0002`$\u0015`$\u0015`$9`%\u0000`$\u0002`$\u0015`$9`$(`$>`$&`%\u0007`$$`$>`$9`$.`$2`%\u0007`$\u0015`$>`$+`%\u0000`$\u001C`$,`$\u0015`$?`$$`%\u0001`$0`$$`$.`$>`$\u0002`$\u0017`$5`$9`%\u0000`$\u0002`$0`%\u000B`$\u001C`$<`$.`$?`$2`%\u0000`$\u0006`$0`%\u000B`$*`$8`%\u0007`$(`$>`$/`$>`$&`$5`$2`%\u0007`$(`%\u0007`$\u0016`$>`$$`$>`$\u0015`$0`%\u0000`$,`$\t`$(`$\u0015`$>`$\u001C`$5`$>`$,`$*`%\u0002`$0`$>`$,`$!`$<`$>`$8`%\u000C`$&`$>`$6`%\u0007`$/`$0`$\u0015`$?`$/`%\u0007`$\u0015`$9`$>`$\u0002`$\u0005`$\u0015`$8`$0`$,`$(`$>`$\u000F`$5`$9`$>`$\u0002`$8`%\r`$%`$2`$.`$?`$2`%\u0007`$2`%\u0007`$\u0016`$\u0015`$5`$?`$7`$/`$\u0015`%\r`$0`$\u0002`$8`$.`%\u0002`$9`$%`$>`$(`$>X*X3X*X7Y\nX9Y\u0005X4X'X1Y\u0003X)X(Y\u0008X'X3X7X)X'Y\u0004X5Y\u0001X-X)Y\u0005Y\u0008X'X6Y\nX9X'Y\u0004X.X'X5X)X'Y\u0004Y\u0005X2Y\nX/X'Y\u0004X9X'Y\u0005X)X'Y\u0004Y\u0003X'X*X(X'Y\u0004X1X/Y\u0008X/X(X1Y\u0006X'Y\u0005X,X'Y\u0004X/Y\u0008Y\u0004X)X'Y\u0004X9X'Y\u0004Y\u0005X'Y\u0004Y\u0005Y\u0008Y\u0002X9X'Y\u0004X9X1X(Y\nX'Y\u0004X3X1Y\nX9X'Y\u0004X,Y\u0008X'Y\u0004X'Y\u0004X0Y\u0007X'X(X'Y\u0004X-Y\nX'X)X'Y\u0004X-Y\u0002Y\u0008Y\u0002X'Y\u0004Y\u0003X1Y\nY\u0005X'Y\u0004X9X1X'Y\u0002Y\u0005X-Y\u0001Y\u0008X8X)X'Y\u0004X+X'Y\u0006Y\nY\u0005X4X'Y\u0007X/X)X'Y\u0004Y\u0005X1X#X)X'Y\u0004Y\u0002X1X\"Y\u0006X'Y\u0004X4X(X'X(X'Y\u0004X-Y\u0008X'X1X'Y\u0004X,X/Y\nX/X'Y\u0004X#X3X1X)X'Y\u0004X9Y\u0004Y\u0008Y\u0005Y\u0005X,Y\u0005Y\u0008X9X)X'Y\u0004X1X-Y\u0005Y\u0006X'Y\u0004Y\u0006Y\u0002X'X7Y\u0001Y\u0004X3X7Y\nY\u0006X'Y\u0004Y\u0003Y\u0008Y\nX*X'Y\u0004X/Y\u0006Y\nX'X(X1Y\u0003X'X*Y\u0007X'Y\u0004X1Y\nX'X6X*X-Y\nX'X*Y\nX(X*Y\u0008Y\u0002Y\nX*X'Y\u0004X#Y\u0008Y\u0004Y\tX'Y\u0004X(X1Y\nX/X'Y\u0004Y\u0003Y\u0004X'Y\u0005X'Y\u0004X1X'X(X7X'Y\u0004X4X.X5Y\nX3Y\nX'X1X'X*X'Y\u0004X+X'Y\u0004X+X'Y\u0004X5Y\u0004X'X)X'Y\u0004X-X/Y\nX+X'Y\u0004X2Y\u0008X'X1X'Y\u0004X.Y\u0004Y\nX,X'Y\u0004X,Y\u0005Y\nX9X'Y\u0004X9X'Y\u0005Y\u0007X'Y\u0004X,Y\u0005X'Y\u0004X'Y\u0004X3X'X9X)Y\u0005X4X'Y\u0007X/Y\u0007X'Y\u0004X1X&Y\nX3X'Y\u0004X/X.Y\u0008Y\u0004X'Y\u0004Y\u0001Y\u0006Y\nX)X'Y\u0004Y\u0003X*X'X(X'Y\u0004X/Y\u0008X1Y\nX'Y\u0004X/X1Y\u0008X3X'X3X*X:X1Y\u0002X*X5X'Y\u0005Y\nY\u0005X'Y\u0004X(Y\u0006X'X*X'Y\u0004X9X8Y\nY\u0005entertainmentunderstanding = function().jpg\" width=\"configuration.png\" width=\"<body class=\"Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=\"\"><img src=\"/distinguishedthousands of communicationclear\"></div>investigationfavicon.ico\" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch\" type=\"form method=\"as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of\" maxlength=\"return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type=\"the number ofthe original comprehensiverefers to the</ul>\n</div>\nphilosophicallocation.hrefwas publishedSan Francisco(function(){\n<div id=\"mainsophisticatedmathematical /head>\r\n<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder=\"; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript\" src=\"/(function() {are available\n\t<link rel=\" src='http://interested inconventional \" alt=\"\" /></are generallyhas also beenmost popular correspondingcredited withtyle=\"border:</a></span></.gif\" width=\"<iframe src=\"table class=\"inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name=\"or\" content=\"controversialproperty=\"og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style=\"known as the shortly afterfor instance,described as /head>\n<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant\" border=\"0\">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name=\"searchattributed tocourse of themathematicianby the end ofat the end of\" border=\"0\" technological.removeClass(branch of theevidence that![endif]-->\r\nInstitute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href=\"confused with<link href=\"/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>\n</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription\" determine theavailable forAccording to wide range of\t<div class=\"more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover=\"because they async = true;problems withseems to havethe result of src=\"http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld's firstclassified asbottom of the(particularlyalign=\"left\" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout=\"New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd\">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to\t<meta name=\"are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to\t\t<ul class=\"visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style=\"equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these\n<div class=\"input class=\"replaced withis one of theeducation andinfluenced byreputation as\n<meta name=\"accommodation</div>\n</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the\n<div style=\"almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in\" value=\"\" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class=\"mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription\">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass=\"headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;\n</script>\n<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle=\"marginincluding thebahasa Melayunorsk bokmC%lnorsk nynorskslovenE!D\rinainternacionalcalificaciC3ncomunicaciC3nconstrucciC3n\"><div class=\"disambiguationDomainName', 'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->\n</><meta name=\"implementationinfrastructurerepresentationborder-bottom:</head>\n<body>=http%3A%2F%2F<form method=\"method=\"post\" /favicon.ico\" });\n</script>\n.setAttribute(Administration= new Array();<![endif]-->\r\ndisplay:block;Unfortunately,\">&nbsp;</div>/favicon.ico\">='stylesheet' identification, for example,<li><a href=\"/an alternativeas a result ofpt\"></script>\ntype=\"submit\" \n(function() {recommendationform action=\"/transformationreconstruction.style.display According to hidden\" name=\"along with thedocument.body.approximately Communicationspost\" action=\"meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover=\"the governmenthref=\"https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->\n\ndepends on theUniversity of in contrast to placeholder=\"in the case ofinternational constitutionalstyle=\"border-: function() {Because of the-strict.dtd\">\n<table class=\"accompanied byaccount of the<script src=\"/nature of the the people in in addition tos); js.id = id\" width=\"100%\"regarding the Roman Catholican independentfollowing the .gif\" width=\"1the following discriminationarchaeologicalprime minister.js\"></script>combination of marginwidth=\"createElement(w.attachEvent(</a></td></tr>src=\"https://aIn particular, align=\"left\" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html\" title=\"(function () {comes from theapplication of<span class=\"sbelieved to beement('script'</a>\n</li>\n<livery different><span class=\"option value=\"(also known as\t<li><a href=\"><input name=\"separated fromreferred to as valign=\"top\">founder of theattempting to carbon dioxide\n\n<div class=\"class=\"search-/body>\n</html>opportunity tocommunications</head>\r\n<body style=\"width:Tia:?ng Via;\u0007tchanges in theborder-color:#0\" border=\"0\" </span></div><was discovered\" type=\"text\" );\n</script>\n\nDepartment of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>\n\n<div iwas consideredpercent of the\" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href='http://whether or notThere are alsothere are manya small numberother parts ofimpossible to class=\"buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=\" method=\"post\"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign=\"right\">many countriesfor many yearsearliest knownbecause it waspt\"></script>\r valign=\"top\" inhabitants offollowing year\r\n<div class=\"million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style=\"color:although therebest known forsubmit\" name=\"multiplicationmore than one recognition ofCouncil of theedition of the <meta name=\"Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class=\"descendants of<span class=\"i align=\"right\"</head>\n<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the\t<span class=\"is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class=\"<span class=\"t(Math.random()most prominentdescription ofConstantinoplewere published<div class=\"seappears in the1\" height=\"1\" most importantwhich includeswhich had beendestruction ofthe population\n\t<div class=\"possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle=\"clear:b\r\n</script>\r\n<was founded ininterview with_id\" content=\"capital of the\r\n<link rel=\"srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class=\"cperformance of(function() {\rif and only ifregions of theleading to therelations withUnited Nationsstyle=\"height:other than theype\" content=\"Association of\n</head>\n<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>\n<link rel=\" return false;the purpose ofthe ability to;color:#fff}\n.\n<span class=\"the subject ofdefinitions of>\r\n<link rel=\"claim that thehave developed<table width=\"celebration ofFollowing the to distinguish<span class=\"btakes place inunder the namenoted that the><![endif]-->\nstyle=\"margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id=\"was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>\r\n\r\nenvironmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made\" src=\"http://interpreted assecond half ofcrolling=\"no\" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class=\"footerand especiallytype=\"button\" </span></span>which included>\n<meta name=\"considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process <div class=\"the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class=\"ptext\" name=\"q\"\t\t<div class=\"the scientificrepresented bymathematicianselected by thethat have been><div class=\"cdiv id=\"headerin particular,converted into);\n</script>\n<philosophical srpskohrvatskitia:?ng Via;\u0007tP Q\u0003Q\u0001Q\u0001P:P8P9Q\u0000Q\u0003Q\u0001Q\u0001P:P8P9investigaciC3nparticipaciC3nP:P>Q\u0002P>Q\u0000Q\u000BP5P>P1P;P0Q\u0001Q\u0002P8P:P>Q\u0002P>Q\u0000Q\u000BP9Q\u0007P5P;P>P2P5P:Q\u0001P8Q\u0001Q\u0002P5P<Q\u000BP\u001DP>P2P>Q\u0001Q\u0002P8P:P>Q\u0002P>Q\u0000Q\u000BQ\u0005P>P1P;P0Q\u0001Q\u0002Q\u000CP2Q\u0000P5P<P5P=P8P:P>Q\u0002P>Q\u0000P0Q\u000FQ\u0001P5P3P>P4P=Q\u000FQ\u0001P:P0Q\u0007P0Q\u0002Q\u000CP=P>P2P>Q\u0001Q\u0002P8P#P:Q\u0000P0P8P=Q\u000BP2P>P?Q\u0000P>Q\u0001Q\u000BP:P>Q\u0002P>Q\u0000P>P9Q\u0001P4P5P;P0Q\u0002Q\u000CP?P>P<P>Q\tQ\u000CQ\u000EQ\u0001Q\u0000P5P4Q\u0001Q\u0002P2P>P1Q\u0000P0P7P>P<Q\u0001Q\u0002P>Q\u0000P>P=Q\u000BQ\u0003Q\u0007P0Q\u0001Q\u0002P8P5Q\u0002P5Q\u0007P5P=P8P5P\u0013P;P0P2P=P0Q\u000FP8Q\u0001Q\u0002P>Q\u0000P8P8Q\u0001P8Q\u0001Q\u0002P5P<P0Q\u0000P5Q\u0008P5P=P8Q\u000FP!P:P0Q\u0007P0Q\u0002Q\u000CP?P>Q\rQ\u0002P>P<Q\u0003Q\u0001P;P5P4Q\u0003P5Q\u0002Q\u0001P:P0P7P0Q\u0002Q\u000CQ\u0002P>P2P0Q\u0000P>P2P:P>P=P5Q\u0007P=P>Q\u0000P5Q\u0008P5P=P8P5P:P>Q\u0002P>Q\u0000P>P5P>Q\u0000P3P0P=P>P2P:P>Q\u0002P>Q\u0000P>P<P P5P:P;P0P<P0X'Y\u0004Y\u0005Y\u0006X*X/Y\tY\u0005Y\u0006X*X/Y\nX'X*X'Y\u0004Y\u0005Y\u0008X6Y\u0008X9X'Y\u0004X(X1X'Y\u0005X,X'Y\u0004Y\u0005Y\u0008X'Y\u0002X9X'Y\u0004X1X3X'X&Y\u0004Y\u0005X4X'X1Y\u0003X'X*X'Y\u0004X#X9X6X'X!X'Y\u0004X1Y\nX'X6X)X'Y\u0004X*X5Y\u0005Y\nY\u0005X'Y\u0004X'X9X6X'X!X'Y\u0004Y\u0006X*X'X&X,X'Y\u0004X#Y\u0004X9X'X(X'Y\u0004X*X3X,Y\nY\u0004X'Y\u0004X#Y\u0002X3X'Y\u0005X'Y\u0004X6X:X7X'X*X'Y\u0004Y\u0001Y\nX/Y\nY\u0008X'Y\u0004X*X1X-Y\nX(X'Y\u0004X,X/Y\nX/X)X'Y\u0004X*X9Y\u0004Y\nY\u0005X'Y\u0004X#X.X(X'X1X'Y\u0004X'Y\u0001Y\u0004X'Y\u0005X'Y\u0004X#Y\u0001Y\u0004X'Y\u0005X'Y\u0004X*X'X1Y\nX.X'Y\u0004X*Y\u0002Y\u0006Y\nX)X'Y\u0004X'Y\u0004X9X'X(X'Y\u0004X.Y\u0008X'X7X1X'Y\u0004Y\u0005X,X*Y\u0005X9X'Y\u0004X/Y\nY\u0003Y\u0008X1X'Y\u0004X3Y\nX'X-X)X9X(X/X'Y\u0004Y\u0004Y\u0007X'Y\u0004X*X1X(Y\nX)X'Y\u0004X1Y\u0008X'X(X7X'Y\u0004X#X/X(Y\nX)X'Y\u0004X'X.X(X'X1X'Y\u0004Y\u0005X*X-X/X)X'Y\u0004X'X:X'Y\u0006Y\ncursor:pointer;</title>\n<meta \" href=\"http://\"><span class=\"members of the window.locationvertical-align:/a> | <a href=\"<!doctype html>media=\"screen\" <option value=\"favicon.ico\" />\n\t\t<div class=\"characteristics\" method=\"get\" /body>\n</html>\nshortcut icon\" document.write(padding-bottom:representativessubmit\" value=\"align=\"center\" throughout the science fiction\n <div class=\"submit\" class=\"one of the most valign=\"top\"><was established);\r\n</script>\r\nreturn false;\">).style.displaybecause of the document.cookie<form action=\"/}body{margin:0;Encyclopedia ofversion of the .createElement(name\" content=\"</div>\n</div>\n\nadministrative </body>\n</html>history of the \"><input type=\"portion of the as part of the &nbsp;<a href=\"other countries\">\n<div class=\"</span></span><In other words,display: block;control of the introduction of/>\n<meta name=\"as well as the in recent years\r\n\t<div class=\"</div>\n\t</div>\ninspired by thethe end of the compatible withbecame known as style=\"margin:.js\"></script>< International there have beenGerman language style=\"color:#Communist Partyconsistent withborder=\"0\" cell marginheight=\"the majority of\" align=\"centerrelated to the many different Orthodox Churchsimilar to the />\n<link rel=\"swas one of the until his death})();\n</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling=\"no\" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign=\"center\">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style=\"width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>\n\t<div class=\"consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method=\"post\" was followed by&amp;mdash; thethe applicationjs\"></script>\r\nul></div></div>after the deathwith respect tostyle=\"padding:is particularlydisplay:inline; type=\"submit\" is divided intod8-f\u0016\u0007 (g.\u0000d=\u0013)responsabilidadadministraciC3ninternacionalescorrespondiente`$\t`$*`$/`%\u000B`$\u0017`$*`%\u0002`$0`%\r`$5`$9`$.`$>`$0`%\u0007`$2`%\u000B`$\u0017`%\u000B`$\u0002`$\u001A`%\u0001`$(`$>`$5`$2`%\u0007`$\u0015`$?`$(`$8`$0`$\u0015`$>`$0`$*`%\u0001`$2`$?`$8`$\u0016`%\u000B`$\u001C`%\u0007`$\u0002`$\u001A`$>`$9`$?`$\u000F`$-`%\u0007`$\u001C`%\u0007`$\u0002`$6`$>`$.`$?`$2`$9`$.`$>`$0`%\u0000`$\u001C`$>`$\u0017`$0`$#`$,`$(`$>`$(`%\u0007`$\u0015`%\u0001`$.`$>`$0`$,`%\r`$2`%\t`$\u0017`$.`$>`$2`$?`$\u0015`$.`$9`$?`$2`$>`$*`%\u0003`$7`%\r`$ `$,`$\"`$<`$$`%\u0007`$-`$>`$\u001C`$*`$>`$\u0015`%\r`$2`$?`$\u0015`$\u001F`%\r`$0`%\u0007`$(`$\u0016`$?`$2`$>`$+`$&`%\u000C`$0`$>`$(`$.`$>`$.`$2`%\u0007`$.`$$`$&`$>`$(`$,`$>`$\u001C`$>`$0`$5`$?`$\u0015`$>`$8`$\u0015`%\r`$/`%\u000B`$\u0002`$\u001A`$>`$9`$$`%\u0007`$*`$9`%\u0001`$\u0001`$\u001A`$,`$$`$>`$/`$>`$8`$\u0002`$5`$>`$&`$&`%\u0007`$\u0016`$(`%\u0007`$*`$?`$\u001B`$2`%\u0007`$5`$?`$6`%\u0007`$7`$0`$>`$\u001C`%\r`$/`$\t`$$`%\r`$$`$0`$.`%\u0001`$\u0002`$,`$\u0008`$&`%\u000B`$(`%\u000B`$\u0002`$\t`$*`$\u0015`$0`$#`$*`$\"`$<`%\u0007`$\u0002`$8`%\r`$%`$?`$$`$+`$?`$2`%\r`$.`$.`%\u0001`$\u0016`%\r`$/`$\u0005`$\u001A`%\r`$\u001B`$>`$\u001B`%\u0002`$\u001F`$$`%\u0000`$8`$\u0002`$\u0017`%\u0000`$$`$\u001C`$>`$\u000F`$\u0017`$>`$5`$?`$-`$>`$\u0017`$\u0018`$#`%\r`$\u001F`%\u0007`$&`%\u0002`$8`$0`%\u0007`$&`$?`$(`%\u000B`$\u0002`$9`$$`%\r`$/`$>`$8`%\u0007`$\u0015`%\r`$8`$\u0017`$>`$\u0002`$'`%\u0000`$5`$?`$6`%\r`$5`$0`$>`$$`%\u0007`$\u0002`$&`%\u0008`$\u001F`%\r`$8`$(`$\u0015`%\r`$6`$>`$8`$>`$.`$(`%\u0007`$\u0005`$&`$>`$2`$$`$,`$?`$\u001C`$2`%\u0000`$*`%\u0001`$0`%\u0002`$7`$9`$?`$\u0002`$&`%\u0000`$.`$?`$$`%\r`$0`$\u0015`$5`$?`$$`$>`$0`%\u0001`$*`$/`%\u0007`$8`%\r`$%`$>`$(`$\u0015`$0`%\u000B`$!`$<`$.`%\u0001`$\u0015`%\r`$$`$/`%\u000B`$\u001C`$(`$>`$\u0015`%\u0003`$*`$/`$>`$*`%\u000B`$8`%\r`$\u001F`$\u0018`$0`%\u0007`$2`%\u0002`$\u0015`$>`$0`%\r`$/`$5`$?`$\u001A`$>`$0`$8`%\u0002`$\u001A`$(`$>`$.`%\u0002`$2`%\r`$/`$&`%\u0007`$\u0016`%\u0007`$\u0002`$9`$.`%\u0007`$6`$>`$8`%\r`$\u0015`%\u0002`$2`$.`%\u0008`$\u0002`$(`%\u0007`$$`%\u0008`$/`$>`$0`$\u001C`$?`$8`$\u0015`%\u0007rss+xml\" title=\"-type\" content=\"title\" content=\"at the same time.js\"></script>\n<\" method=\"post\" </span></a></li>vertical-align:t/jquery.min.js\">.click(function( style=\"padding-})();\n</script>\n</span><a href=\"<a href=\"http://); return false;text-decoration: scrolling=\"no\" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif\" border=\"0\"</body>\n</html>\noverflow:hidden;img src=\"http://addEventListenerresponsible for s.js\"></script>\n/favicon.ico\" />operating system\" style=\"width:1target=\"_blank\">State Universitytext-align:left;\ndocument.write(, including the around the world);\r\n</script>\r\n<\" style=\"height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>\n\t\t</div>\ndisplay: none;\">\" />\n<link rel=\"\n (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the align=\"center\">University Pressdominated by theSecond World Wardistribution of style=\"position:the rest of the characterized by rel=\"nofollow\">derives from therather than the a combination ofstyle=\"width:100English-speakingcomputer scienceborder=\"0\" alt=\"the existence ofDemocratic Party\" style=\"margin-For this reason,.js\"></script>\n\tsByTagName(s)[0]js\"></script>\r\n<.js\"></script>\r\nlink rel=\"icon\" ' alt='' class='formation of theversions of the </a></div></div>/page>\n <page>\n<div class=\"contbecame the firstbahasa Indonesiaenglish (simple)N\u0015N;N;N7N=N9N:N,Q\u0005Q\u0000P2P0Q\u0002Q\u0001P:P8P:P>P<P?P0P=P8P8Q\u000FP2P;Q\u000FP5Q\u0002Q\u0001Q\u000FP\u0014P>P1P0P2P8Q\u0002Q\u000CQ\u0007P5P;P>P2P5P:P0Q\u0000P0P7P2P8Q\u0002P8Q\u000FP\u0018P=Q\u0002P5Q\u0000P=P5Q\u0002P\u001EQ\u0002P2P5Q\u0002P8Q\u0002Q\u000CP=P0P?Q\u0000P8P<P5Q\u0000P8P=Q\u0002P5Q\u0000P=P5Q\u0002P:P>Q\u0002P>Q\u0000P>P3P>Q\u0001Q\u0002Q\u0000P0P=P8Q\u0006Q\u000BP:P0Q\u0007P5Q\u0001Q\u0002P2P5Q\u0003Q\u0001P;P>P2P8Q\u000FQ\u0005P?Q\u0000P>P1P;P5P<Q\u000BP?P>P;Q\u0003Q\u0007P8Q\u0002Q\u000CQ\u000FP2P;Q\u000FQ\u000EQ\u0002Q\u0001Q\u000FP=P0P8P1P>P;P5P5P:P>P<P?P0P=P8Q\u000FP2P=P8P<P0P=P8P5Q\u0001Q\u0000P5P4Q\u0001Q\u0002P2P0X'Y\u0004Y\u0005Y\u0008X'X6Y\nX9X'Y\u0004X1X&Y\nX3Y\nX)X'Y\u0004X'Y\u0006X*Y\u0002X'Y\u0004Y\u0005X4X'X1Y\u0003X'X*Y\u0003X'Y\u0004X3Y\nX'X1X'X*X'Y\u0004Y\u0005Y\u0003X*Y\u0008X(X)X'Y\u0004X3X9Y\u0008X/Y\nX)X'X-X5X'X&Y\nX'X*X'Y\u0004X9X'Y\u0004Y\u0005Y\nX)X'Y\u0004X5Y\u0008X*Y\nX'X*X'Y\u0004X'Y\u0006X*X1Y\u0006X*X'Y\u0004X*X5X'Y\u0005Y\nY\u0005X'Y\u0004X%X3Y\u0004X'Y\u0005Y\nX'Y\u0004Y\u0005X4X'X1Y\u0003X)X'Y\u0004Y\u0005X1X&Y\nX'X*robots\" content=\"<div id=\"footer\">the United States<img src=\"http://.jpg|right|thumb|.js\"></script>\r\n<location.protocolframeborder=\"0\" s\" />\n<meta name=\"</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:\" rel=\"nofollow\" President of the twentieth centuryevision>\n </pageInternet Explorera.async = true;\r\ninformation about<div id=\"header\">\" action=\"http://<a href=\"https://<div id=\"content\"</div>\r\n</div>\r\n<derived from the <img src='http://according to the \n</body>\n</html>\nstyle=\"font-size:script language=\"Arial, Helvetica,</a><span class=\"</script><script political partiestd></tr></table><href=\"http://www.interpretation ofrel=\"stylesheet\" document.write('<charset=\"utf-8\">\nbeginning of the revealed that thetelevision series\" rel=\"nofollow\"> target=\"_blank\">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass=\"clearfix\">/div>\r\n</div>\r\n\r\nthree-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class=\"in some countriesmin.js\"></script>of the populationofficial language<img src=\"images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>\r\n</html>\rN\u0015N;N;N7N=N9N:N,\ntake advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class=\"headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype=\"text/css\">\nthe InternationalAccording to the pe=\"text/css\" />\ncoincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;\" target=\"_blank\" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type=\"application/anguage\" content=\"<meta http-equiv=\"Privacy Policy</a>e(\"%3Cscript src='\" target=\"_blank\">On the other hand,.jpg|thumb|right|2</div><div class=\"<div style=\"float:nineteenth century</body>\r\n</html>\r\n<img src=\"http://s;text-align:centerfont-weight: bold; According to the difference between\" frameborder=\"0\" \" style=\"position:link href=\"http://html4/loose.dtd\">\nduring this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type=\"text\" <span style=\"font-onreadystatechange\t<div class=\"cleardocument.location. For example, the a wide variety of <!DOCTYPE html>\r\n<&nbsp;&nbsp;&nbsp;\"><a href=\"http://style=\"float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype=\"text/css\" />it is possible to Harvard Universitytylesheet\" href=\"/the main characterOxford University name=\"keywords\" cstyle=\"text-align:the United Kingdomfederal government<div style=\"margin depending on the description of the<div class=\"header.min.js\"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc=\"http://staticsuggested that the\" src=\"http://www.a large number of Telecommunications\" rel=\"nofollow\" tHoly Roman Emperoralmost exclusively\" border=\"0\" alt=\"Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle=\"background-<li><em><a href=\"/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src=\"http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref=\"https://www.recent developmentBoard of Directors<div class=\"search| <a href=\"http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>\r\n</div>\r\n\r\n<a href=\"index.phpwas established inmin.js\"></script>\nparticipate in thea strong influencestyle=\"margin-top:represented by thegraduated from theTraditionally, theElement(\"script\");However, since the/div>\n</div>\n<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype=\"image/x-icon/div>\n<div class=\" class=\"clearfix\"><div class=\"footer\t\t</div>\n\t\t</div>\nthe motion pictureP\u0011Q\nP;P3P0Q\u0000Q\u0001P:P8P1Q\nP;P3P0Q\u0000Q\u0001P:P8P$P5P4P5Q\u0000P0Q\u0006P8P8P=P5Q\u0001P:P>P;Q\u000CP:P>Q\u0001P>P>P1Q\tP5P=P8P5Q\u0001P>P>P1Q\tP5P=P8Q\u000FP?Q\u0000P>P3Q\u0000P0P<P<Q\u000BP\u001EQ\u0002P?Q\u0000P0P2P8Q\u0002Q\u000CP1P5Q\u0001P?P;P0Q\u0002P=P>P<P0Q\u0002P5Q\u0000P8P0P;Q\u000BP?P>P7P2P>P;Q\u000FP5Q\u0002P?P>Q\u0001P;P5P4P=P8P5Q\u0000P0P7P;P8Q\u0007P=Q\u000BQ\u0005P?Q\u0000P>P4Q\u0003P:Q\u0006P8P8P?Q\u0000P>P3Q\u0000P0P<P<P0P?P>P;P=P>Q\u0001Q\u0002Q\u000CQ\u000EP=P0Q\u0005P>P4P8Q\u0002Q\u0001Q\u000FP8P7P1Q\u0000P0P=P=P>P5P=P0Q\u0001P5P;P5P=P8Q\u000FP8P7P<P5P=P5P=P8Q\u000FP:P0Q\u0002P5P3P>Q\u0000P8P8P\u0010P;P5P:Q\u0001P0P=P4Q\u0000`$&`%\r`$5`$>`$0`$>`$.`%\u0008`$(`%\u0001`$\u0005`$2`$*`%\r`$0`$&`$>`$(`$-`$>`$0`$$`%\u0000`$/`$\u0005`$(`%\u0001`$&`%\u0007`$6`$9`$?`$(`%\r`$&`%\u0000`$\u0007`$\u0002`$!`$?`$/`$>`$&`$?`$2`%\r`$2`%\u0000`$\u0005`$'`$?`$\u0015`$>`$0`$5`%\u0000`$!`$?`$/`%\u000B`$\u001A`$?`$\u001F`%\r`$ `%\u0007`$8`$.`$>`$\u001A`$>`$0`$\u001C`$\u0002`$\u0015`%\r`$6`$(`$&`%\u0001`$(`$?`$/`$>`$*`%\r`$0`$/`%\u000B`$\u0017`$\u0005`$(`%\u0001`$8`$>`$0`$\u0011`$(`$2`$>`$\u0007`$(`$*`$>`$0`%\r`$\u001F`%\u0000`$6`$0`%\r`$$`%\u000B`$\u0002`$2`%\u000B`$\u0015`$8`$-`$>`$+`$<`%\r`$2`%\u0008`$6`$6`$0`%\r`$$`%\u0007`$\u0002`$*`%\r`$0`$&`%\u0007`$6`$*`%\r`$2`%\u0007`$/`$0`$\u0015`%\u0007`$\u0002`$&`%\r`$0`$8`%\r`$%`$?`$$`$?`$\t`$$`%\r`$*`$>`$&`$\t`$(`%\r`$9`%\u0007`$\u0002`$\u001A`$?`$\u001F`%\r`$ `$>`$/`$>`$$`%\r`$0`$>`$\u001C`%\r`$/`$>`$&`$>`$*`%\u0001`$0`$>`$(`%\u0007`$\u001C`%\u000B`$!`$<`%\u0007`$\u0002`$\u0005`$(`%\u0001`$5`$>`$&`$6`%\r`$0`%\u0007`$#`%\u0000`$6`$?`$\u0015`%\r`$7`$>`$8`$0`$\u0015`$>`$0`%\u0000`$8`$\u0002`$\u0017`%\r`$0`$9`$*`$0`$?`$#`$>`$.`$,`%\r`$0`$>`$\u0002`$!`$,`$\u001A`%\r`$\u001A`%\u000B`$\u0002`$\t`$*`$2`$,`%\r`$'`$.`$\u0002`$$`%\r`$0`%\u0000`$8`$\u0002`$*`$0`%\r`$\u0015`$\t`$.`%\r`$.`%\u0000`$&`$.`$>`$'`%\r`$/`$.`$8`$9`$>`$/`$$`$>`$6`$,`%\r`$&`%\u000B`$\u0002`$.`%\u0000`$!`$?`$/`$>`$\u0006`$\u0008`$*`%\u0000`$\u000F`$2`$.`%\u000B`$,`$>`$\u0007`$2`$8`$\u0002`$\u0016`%\r`$/`$>`$\u0006`$*`$0`%\u0007`$6`$(`$\u0005`$(`%\u0001`$,`$\u0002`$'`$,`$>`$\u001C`$<`$>`$0`$(`$5`%\u0000`$(`$$`$.`$*`%\r`$0`$.`%\u0001`$\u0016`$*`%\r`$0`$6`%\r`$(`$*`$0`$?`$5`$>`$0`$(`%\u0001`$\u0015`$8`$>`$(`$8`$.`$0`%\r`$%`$(`$\u0006`$/`%\u000B`$\u001C`$?`$$`$8`%\u000B`$.`$5`$>`$0X'Y\u0004Y\u0005X4X'X1Y\u0003X'X*X'Y\u0004Y\u0005Y\u0006X*X/Y\nX'X*X'Y\u0004Y\u0003Y\u0005X(Y\nY\u0008X*X1X'Y\u0004Y\u0005X4X'Y\u0007X/X'X*X9X/X/X'Y\u0004X2Y\u0008X'X1X9X/X/X'Y\u0004X1X/Y\u0008X/X'Y\u0004X%X3Y\u0004X'Y\u0005Y\nX)X'Y\u0004Y\u0001Y\u0008X*Y\u0008X4Y\u0008X(X'Y\u0004Y\u0005X3X'X(Y\u0002X'X*X'Y\u0004Y\u0005X9Y\u0004Y\u0008Y\u0005X'X*X'Y\u0004Y\u0005X3Y\u0004X3Y\u0004X'X*X'Y\u0004X,X1X'Y\u0001Y\nY\u0003X3X'Y\u0004X'X3Y\u0004X'Y\u0005Y\nX)X'Y\u0004X'X*X5X'Y\u0004X'X*keywords\" content=\"w3.org/1999/xhtml\"><a target=\"_blank\" text/html; charset=\" target=\"_blank\"><table cellpadding=\"autocomplete=\"off\" text-align: center;to last version by background-color: #\" href=\"http://www./div></div><div id=<a href=\"#\" class=\"\"><img src=\"http://cript\" src=\"http://\n<script language=\"//EN\" \"http://www.wencodeURIComponent(\" href=\"javascript:<div class=\"contentdocument.write('<scposition: absolute;script src=\"http:// style=\"margin-top:.min.js\"></script>\n</div>\n<div class=\"w3.org/1999/xhtml\" \n\r\n</body>\r\n</html>distinction between/\" target=\"_blank\"><link href=\"http://encoding=\"utf-8\"?>\nw.addEventListener?action=\"http://www.icon\" href=\"http:// style=\"background:type=\"text/css\" />\nmeta property=\"og:t<input type=\"text\" style=\"text-align:the development of tylesheet\" type=\"tehtml; charset=utf-8is considered to betable width=\"100%\" In addition to the contributed to the differences betweendevelopment of the It is important to </script>\n\n<script style=\"font-size:1></span><span id=gbLibrary of Congress<img src=\"http://imEnglish translationAcademy of Sciencesdiv style=\"display:construction of the.getElementById(id)in conjunction withElement('script'); <meta property=\"og:P\u0011Q\nP;P3P0Q\u0000Q\u0001P:P8\n type=\"text\" name=\">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src=\"http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style=\"background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet\" href=\"/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland\n</script>\n<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv=\"X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0\" cellpadding=\"0\" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E\"));<a href=\"http://www.<li><a href=\"http://site_name\" content=\"text-decoration:nonestyle=\"display: none<meta http-equiv=\"X-new Date().getTime() type=\"image/x-icon\"</span><span class=\"language=\"javascriptwindow.location.href<a href=\"javascript:-->\r\n<script type=\"t<a href='http://www.hortcut icon\" href=\"</div>\r\n<div class=\"<script src=\"http://\" rel=\"stylesheet\" t</div>\n<script type=/a> <a href=\"http:// allowTransparency=\"X-UA-Compatible\" conrelationship between\n</script>\r\n<script </a></li></ul></div>associated with the programming language</a><a href=\"http://</a></li><li class=\"form action=\"http://<div style=\"display:type=\"text\" name=\"q\"<table width=\"100%\" background-position:\" border=\"0\" width=\"rel=\"shortcut icon\" h6><ul><li><a href=\" <meta http-equiv=\"css\" media=\"screen\" responsible for the \" type=\"application/\" style=\"background-html; charset=utf-8\" allowtransparency=\"stylesheet\" type=\"te\r\n<meta http-equiv=\"></span><span class=\"0\" cellspacing=\"0\">;\n</script>\n<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type=\"hidden\" name=\"javascript:void(0);\"effectiveness of the autocomplete=\"off\" generally considered><input type=\"text\" \"></script>\r\n<scriptthroughout the worldcommon misconceptionassociation with the</div>\n</div>\n<div cduring his lifetime,corresponding to thetype=\"image/x-icon\" an increasing numberdiplomatic relationsare often consideredmeta charset=\"utf-8\" <input type=\"text\" examples include the\"><img src=\"http://iparticipation in thethe establishment of\n</div>\n<div class=\"&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset=\"utf-8\"> type=\"text/css\" />\ninterchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type=\"text/csstype=\"submit\" name=\"families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportuguC*s (Europeu)P#P:Q\u0000P0Q\u0017P=Q\u0001Q\u000CP:P0Q\u0003P:Q\u0000P0Q\u0017P=Q\u0001Q\u000CP:P0P P>Q\u0001Q\u0001P8P9Q\u0001P:P>P9P<P0Q\u0002P5Q\u0000P8P0P;P>P2P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8P8Q\u0003P?Q\u0000P0P2P;P5P=P8Q\u000FP=P5P>P1Q\u0005P>P4P8P<P>P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000FP\u0018P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000FP P5Q\u0001P?Q\u0003P1P;P8P:P8P:P>P;P8Q\u0007P5Q\u0001Q\u0002P2P>P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000EQ\u0002P5Q\u0000Q\u0000P8Q\u0002P>Q\u0000P8P8P4P>Q\u0001Q\u0002P0Q\u0002P>Q\u0007P=P>X'Y\u0004Y\u0005X*Y\u0008X'X,X/Y\u0008Y\u0006X'Y\u0004X'X4X*X1X'Y\u0003X'X*X'Y\u0004X'Y\u0002X*X1X'X-X'X*html; charset=UTF-8\" setTimeout(function()display:inline-block;<input type=\"submit\" type = 'text/javascri<img src=\"http://www.\" \"http://www.w3.org/shortcut icon\" href=\"\" autocomplete=\"off\" </a></div><div class=</a></li>\n<li class=\"css\" type=\"text/css\" <form action=\"http://xt/css\" href=\"http://link rel=\"alternate\" \r\n<script type=\"text/ onclick=\"javascript:(new Date).getTime()}height=\"1\" width=\"1\" People's Republic of <a href=\"http://www.text-decoration:underthe beginning of the </div>\n</div>\n</div>\nestablishment of the </div></div></div></d#viewport{min-height:\n<script src=\"http://option><option value=often referred to as /option>\n<option valu<!DOCTYPE html>\n<!--[International Airport>\n<a href=\"http://www</a><a href=\"http://w`8 `82`8)`82`9\u0004`8\u0017`8\"a\u0003%a\u0003\u0010a\u0003 a\u0003\u0017a\u0003#a\u0003\u001Aa\u0003\u0018f-#i+\u0014d8-f\u0016\u0007 (g9\u0001i+\u0014)`$(`$?`$0`%\r`$&`%\u0007`$6`$!`$>`$\t`$(`$2`%\u000B`$!`$\u0015`%\r`$7`%\u0007`$$`%\r`$0`$\u001C`$>`$(`$\u0015`$>`$0`%\u0000`$8`$\u0002`$,`$\u0002`$'`$?`$$`$8`%\r`$%`$>`$*`$(`$>`$8`%\r`$5`%\u0000`$\u0015`$>`$0`$8`$\u0002`$8`%\r`$\u0015`$0`$#`$8`$>`$.`$\u0017`%\r`$0`%\u0000`$\u001A`$?`$\u001F`%\r`$ `%\u000B`$\u0002`$5`$?`$\u001C`%\r`$\u001E`$>`$(`$\u0005`$.`%\u0007`$0`$?`$\u0015`$>`$5`$?`$-`$?`$(`%\r`$(`$\u0017`$>`$!`$?`$/`$>`$\u0001`$\u0015`%\r`$/`%\u000B`$\u0002`$\u0015`$?`$8`%\u0001`$0`$\u0015`%\r`$7`$>`$*`$9`%\u0001`$\u0001`$\u001A`$$`%\u0000`$*`%\r`$0`$,`$\u0002`$'`$(`$\u001F`$?`$*`%\r`$*`$#`%\u0000`$\u0015`%\r`$0`$?`$\u0015`%\u0007`$\u001F`$*`%\r`$0`$>`$0`$\u0002`$-`$*`%\r`$0`$>`$*`%\r`$$`$.`$>`$2`$?`$\u0015`%\u000B`$\u0002`$0`$+`$<`%\r`$$`$>`$0`$(`$?`$0`%\r`$.`$>`$#`$2`$?`$.`$?`$\u001F`%\u0007`$!description\" content=\"document.location.prot.getElementsByTagName(<!DOCTYPE html>\n<html <meta charset=\"utf-8\">:url\" content=\"http://.css\" rel=\"stylesheet\"style type=\"text/css\">type=\"text/css\" href=\"w3.org/1999/xhtml\" xmltype=\"text/javascript\" method=\"get\" action=\"link rel=\"stylesheet\" = document.getElementtype=\"image/x-icon\" />cellpadding=\"0\" cellsp.css\" type=\"text/css\" </a></li><li><a href=\"\" width=\"1\" height=\"1\"\"><a href=\"http://www.style=\"display:none;\">alternate\" type=\"appli-//W3C//DTD XHTML 1.0 ellspacing=\"0\" cellpad type=\"hidden\" value=\"/a>&nbsp;<span role=\"s\n<input type=\"hidden\" language=\"JavaScript\" document.getElementsBg=\"0\" cellspacing=\"0\" ype=\"text/css\" media=\"type='text/javascript'with the exception of ype=\"text/css\" rel=\"st height=\"1\" width=\"1\" ='+encodeURIComponent(<link rel=\"alternate\" \nbody, tr, input, textmeta name=\"robots\" conmethod=\"post\" action=\">\n<a href=\"http://www.css\" rel=\"stylesheet\" </div></div><div classlanguage=\"javascript\">aria-hidden=\"true\">B7<ript\" type=\"text/javasl=0;})();\n(function(){background-image: url(/a></li><li><a href=\"h\t\t<li><a href=\"http://ator\" aria-hidden=\"tru> <a href=\"http://www.language=\"javascript\" /option>\n<option value/div></div><div class=rator\" aria-hidden=\"tre=(new Date).getTime()portuguC*s (do Brasil)P>Q\u0000P3P0P=P8P7P0Q\u0006P8P8P2P>P7P<P>P6P=P>Q\u0001Q\u0002Q\u000CP>P1Q\u0000P0P7P>P2P0P=P8Q\u000FQ\u0000P5P3P8Q\u0001Q\u0002Q\u0000P0Q\u0006P8P8P2P>P7P<P>P6P=P>Q\u0001Q\u0002P8P>P1Q\u000FP7P0Q\u0002P5P;Q\u000CP=P0<!DOCTYPE html PUBLIC \"nt-Type\" content=\"text/<meta http-equiv=\"Conteransitional//EN\" \"http:<html xmlns=\"http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = 'text/javascript';<meta name=\"descriptionparentNode.insertBefore<input type=\"hidden\" najs\" type=\"text/javascri(document).ready(functiscript type=\"text/javasimage\" content=\"http://UA-Compatible\" content=tml; charset=utf-8\" />\nlink rel=\"shortcut icon<link rel=\"stylesheet\" </script>\n<script type== document.createElemen<a target=\"_blank\" href= document.getElementsBinput type=\"text\" name=a.type = 'text/javascrinput type=\"hidden\" namehtml; charset=utf-8\" />dtd\">\n<html xmlns=\"http-//W3C//DTD HTML 4.01 TentsByTagName('script')input type=\"hidden\" nam<script type=\"text/javas\" style=\"display:none;\">document.getElementById(=document.createElement(' type='text/javascript'input type=\"text\" name=\"d.getElementsByTagName(snical\" href=\"http://www.C//DTD HTML 4.01 Transit<style type=\"text/css\">\n\n<style type=\"text/css\">ional.dtd\">\n<html xmlns=http-equiv=\"Content-Typeding=\"0\" cellspacing=\"0\"html; charset=utf-8\" />\n style=\"display:none;\"><<li><a href=\"http://www. type='text/javascript'>P4P5Q\u000FQ\u0002P5P;Q\u000CP=P>Q\u0001Q\u0002P8Q\u0001P>P>Q\u0002P2P5Q\u0002Q\u0001Q\u0002P2P8P8P?Q\u0000P>P8P7P2P>P4Q\u0001Q\u0002P2P0P1P5P7P>P?P0Q\u0001P=P>Q\u0001Q\u0002P8`$*`%\u0001`$8`%\r`$$`$?`$\u0015`$>`$\u0015`$>`$\u0002`$\u0017`%\r`$0`%\u0007`$8`$\t`$(`%\r`$9`%\u000B`$\u0002`$(`%\u0007`$5`$?`$'`$>`$(`$8`$-`$>`$+`$?`$\u0015`%\r`$8`$?`$\u0002`$\u0017`$8`%\u0001`$0`$\u0015`%\r`$7`$?`$$`$\u0015`%\t`$*`%\u0000`$0`$>`$\u0007`$\u001F`$5`$?`$\u001C`%\r`$\u001E`$>`$*`$(`$\u0015`$>`$0`%\r`$0`$5`$>`$\u0008`$8`$\u0015`%\r`$0`$?`$/`$$`$>";
+ private static final String SKIP_FLIP = "\u06F7%\u018C'T%\u0085'W%\u00D7%O%g%\u00A6&\u0193%\u01E5&>&*&'&^&\u0088\u0178\u0C3E&\u01AD&\u0192&)&^&%&'&\u0082&P&1&\u00B1&3&]&m&u&E&t&C&\u00CF&V&V&/&>&6&\u0F76\u177Co&p&@&E&M&P&x&@&F&e&\u00CC&7&:&(&D&0&C&)&.&F&-&1&(&L&F&1\u025E*\u03EA\u21F3&\u1372&K&;&)&E&H&P&0&?&9&V&\u0081&-&v&a&,&E&)&?&=&'&'&B&\u0D2E&\u0503&\u0316*&*8&%&%&&&%,)&\u009A&>&\u0086&7&]&F&2&>&J&6&n&2&%&?&\u008E&2&6&J&g&-&0&,&*&J&*&O&)&6&(&<&B&N&.&P&@&2&.&W&M&%\u053C\u0084(,(<&,&\u03DA&\u18C7&-&,(%&(&%&(\u013B0&X&D&\u0081&j&'&J&(&.&B&3&Z&R&h&3&E&E&<\u00C6-\u0360\u1EF3&%8?&@&,&Z&@&0&J&,&^&x&_&6&C&6&C\u072C\u2A25&f&-&-&-&-&,&J&2&8&z&8&C&Y&8&-&d&\u1E78\u00CC-&7&1&F&7&t&W&7&I&.&.&^&=\u0F9C\u19D3&8(>&/&/&\u077B')'\u1065')'%@/&0&%\u043E\u09C0*&*@&C\u053D\u05D4\u0274\u05EB4\u0DD7\u071A\u04D16\u0D84&/\u0178\u0303Z&*%\u0246\u03FF&\u0134&1\u00A8\u04B4\u0174";
+
+ private static void unpackDictionaryData(
+ ByteBuffer dictionary, String data0, String data1, String skipFlip) {
+ // Initialize lower 7 bits of every byte in the dictionary.
+ byte[] dict = Utils.toUsAsciiBytes(data0 + data1);
+ if (dict.length != dictionary.capacity()) {
+ throw new RuntimeException("Corrupted brotli dictionary");
+ }
+
+ // Toggle high bit using run-length delta encoded "skipFlip".
+ int offset = 0;
+ int n = skipFlip.length();
+ for (int i = 0; i < n; i += 2) {
+ int skip = skipFlip.charAt(i) - 36;
+ int flip = skipFlip.charAt(i + 1) - 36;
+ offset += skip;
+ for (int j = 0; j < flip; ++j) {
+ dict[offset] |= 0x80;
+ offset++;
+ }
+ }
+
+ dictionary.put(dict);
+ }
+
+ static {
+ ByteBuffer dictionary = ByteBuffer.allocateDirect(122784);
+ unpackDictionaryData(dictionary, DATA0, DATA1, SKIP_FLIP);
+ Utils.flipBuffer(dictionary);
+ Dictionary.setData(dictionary.asReadOnlyBuffer());
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryTest.java
new file mode 100644
index 000000000..b2ea04b10
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/DictionaryTest.java
@@ -0,0 +1,38 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Dictionary}.
+ */
+@RunWith(JUnit4.class)
+public class DictionaryTest {
+
+ private static long crc64(ByteBuffer data) {
+ long crc = -1;
+ for (int i = 0; i < data.capacity(); ++i) {
+ long c = (crc ^ (long) (data.get(i) & 0xFF)) & 0xFF;
+ for (int k = 0; k < 8; k++) {
+ c = (c >>> 1) ^ (-(c & 1L) & -3932672073523589310L);
+ }
+ crc = c ^ (crc >>> 8);
+ }
+ return ~crc;
+ }
+
+ @Test
+ public void testGetData() {
+ assertEquals(37084801881332636L, crc64(Dictionary.getData()));
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/EagerStreamTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/EagerStreamTest.java
new file mode 100755
index 000000000..8e079c042
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/EagerStreamTest.java
@@ -0,0 +1,386 @@
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Decode}.
+ */
+@RunWith(JUnit4.class)
+public class EagerStreamTest {
+
+ private static final byte[] DATA = {
+ 31, 118, -122, 17, -43, -92, 84, 0, -76, 42, -80, -101, 95, -74, -104, -120, -89, -127, 30, 58,
+ -4, 11, 91, -104, -99, -81, 44, 86, 61, 108, -74, -97, 68, 32, -120, -78, 97, -107, 88, -52,
+ -22, -55, -8, -56, -106, -117, 49, 113, -106, -82, -43, -12, -11, -91, -66, 55, 68, 118, -127,
+ -77, -104, -12, 103, -14, -94, -30, -112, 100, 79, -72, -42, 121, 62, -99, 76, -39, -89, 42, 58,
+ -110, 91, 65, 32, -102, -113, 49, 4, 73, 60, 122, -106, 107, 16, -123, 30, -97, 90, -102, -83,
+ -65, -90, 34, 26, -26, 52, 75, -118, 43, -47, -47, 52, 84, -10, -121, -68, -2, 20, 80, 101, 53,
+ 101, -119, -17, -111, -75, -21, -66, -96, -80, -114, 4, -65, 124, -89, -3, -25, -25, -21, -35,
+ -15, -114, 55, 14, -76, -68, 71, 9, 123, 46, 78, 67, -18, -127, 70, -93, -128, -44, -87, 3, 36,
+ -107, -3, 62, 83, 75, -123, -125, -11, 50, 46, -68, 80, 54, 9, -116, -29, 82, -14, -87, -94, 92,
+ -88, -86, -18, -1, 22, 3, 46, -98, -128, -27, 121, -56, 88, -37, 85, -43, 61, -60, 12, -122,
+ 107, -64, -27, -45, -110, 123, 60, 99, 108, 46, -29, -77, 76, 65, 100, 92, -104, 40, 63, 19, 36,
+ -89, 80, -39, 37, -95, -74, 97, 90, -109, 54, 105, -10, -38, 100, 95, 27, 36, 33, -60, 39, 100,
+ 32, -18, 93, -46, -99, 103, 127, -91, -62, 82, 76, 56, -66, -110, -16, 83, -116, -76, -9, -47,
+ -5, -32, -65, 111, 0, 55, 47, -60, -95, -56, -100, 65, 125, 38, 77, 38, -32, -62, 55, 119, 10,
+ 120, -69, 33, -111, -62, -87, 17, 102, -95, -106, 26, -50, -16, -109, 94, 83, -79, 90, 2, 42,
+ -47, 37, -124, 114, -68, 6, 104, -65, 38, -108, -114, -110, 73, -95, -83, -90, -86, -36, -48,
+ -63, -97, -120, -25, -53, 93, -77, -50, 59, -74, -9, 36, 85, 11, 76, 95, 74, -61, -9, 116, -14,
+ -38, 73, 78, 44, -92, 58, -27, -54, 38, 81, 50, -36, -46, -117, 126, 89, 53, -37, -58, -12, 61,
+ 77, -56, -85, -21, -128, 43, -111, 14, 54, 57, 116, 52, -85, 70, 88, -72, -26, 54, 109, -70,
+ -84, -13, -1, -54, 91, 81, 101, -65, 49, -48, -16, 26, -115, -39, 100, -21, 105, -121, 38, 72,
+ -115, 104, -100, 36, 120, 15, -109, 115, 64, 118, -68, -14, -26, -57, -71, 9, -118, -113, 15,
+ 94, 108, 114, 109, -14, -80, -31, -57, -6, 57, 111, -36, -92, -25, -23, -71, -61, 120, 93, -65,
+ 104, -123, -53, 35, -77, -8, -23, -31, 99, -3, 73, 75, 98, -2, -94, 73, 91, -109, -38, -78,
+ -106, -121, -17, -21, 55, 45, -26, -7, -93, 38, 59, -90, -116, 3, -68, -2, -110, 19, -96, 28,
+ -23, -39, 102, 99, 8, -82, -41, 63, 88, -70, 115, -123, -11, 111, 92, 47, -12, -16, -70, -2,
+ -29, 101, 61, -45, -57, 54, 24, -125, 20, -37, -75, 89, -56, 52, 125, 22, -68, -63, 105, -91,
+ -20, 91, 56, -99, -56, 35, -77, -78, -24, -79, 57, 5, -55, 101, -127, 75, -35, -113, -51, -103,
+ 79, 102, 16, -124, -79, -128, -45, -65, -84, -97, -91, -90, -105, 76, 90, -93, 90, -49, -41,
+ 104, 44, 81, -37, -84, 103, -120, -51, 79, -43, -114, -101, 38, -78, -94, -1, 15, 109, -62, 34,
+ -65, -127, 98, 32, 46, -72, 70, 58, -61, -55, 90, 30, -103, 5, 109, -105, -119, 81, 92, -40,
+ -75, -23, -77, 36, 18, 62, -33, -51, -38, -19, -12, 89, -101, 117, 94, 71, 127, -43, 54, 115,
+ -67, 34, -83, -115, 127, 127, 42, 126, -121, -121, -40, 56, -113, 60, -27, 30, 44, -21, 98,
+ -123, -14, 91, -69, 15, -81, 119, -101, 25, -73, 40, 105, 26, -86, -31, 86, -75, 74, 94, -74,
+ 19, -4, -20, 69, 24, 43, -5, -91, 6, -89, 52, 77, -65, -71, 82, -81, -52, 22, -61, -15, 51, 22,
+ 1, 70, -43, -3, -39, -27, 123, -13, -127, -86, 65, 51, 45, 127, -101, -27, -3, -44, -34, 75, 69,
+ 77, 71, -34, 7, -51, 93, -83, -84, -57, -38, -100, 59, -105, -1, 44, -47, 63, 96, -127, 32, -63,
+ 16, 80, -64, -127, 6, 54, 12, 44, 28, 48, -128, 4, 10, -104, 64, 3, 11, -47, 59, -79, -125, 52,
+ -16, -78, -66, 19, -6, -33, -107, -10, -4, -42, 102, -31, -32, 99, 115, -22, -96, -45, -112, 28,
+ 126, -44, -4, -47, -99, 127, -84, 37, -112, -34, 36, 1, -68, -14, -16, 55, 83, -99, 120, -69,
+ -30, 89, 48, 126, -80, -43, 15, 13, -18, 14, -4, -126, -120, -118, -11, 100, 16, 76, 17, 54,
+ -75, 114, 101, 37, 121, -23, -65, 39, 94, -48, -78, 67, -61, 75, 48, 23, -127, 83, -124, 95, -5,
+ 67, 13, 87, 18, -2, 117, -36, -121, 115, -112, -107, -54, -36, 14, -4, -68, 35, 32, 79, -118,
+ 81, 94, -56, -110, 37, -84, -121, 72, -7, -52, -40, -44, -1, 73, 123, 12, 42, -67, -87, 63, -2,
+ -100, 29, -41, 112, 98, -125, 88, 97, -56, 90, 7, -40, -111, -126, 74, 121, -95, -45, -69, 48,
+ -98, 18, -20, -124, 3, 46, -5, 26, 24, -79, 109, 4, 43, 60, 97, 96, -76, -21, 95, -52, -40, -45,
+ 2, -103, -107, -9, 79, -79, -82, -73, -51, -74, -10, 81, -77, 111, -96, -41, -120, -38, 24, -87,
+ 93, -41, 64, 72, 57, -81, -32, 60, -79, 36, -84, -89, -7, -25, 81, -98, 36, -22, -69, 86, 123,
+ 120, -16, -113, -70, 47, -125, 2, 97, 78, -91, 102, 120, -91, 5, -71, 39, 116, -12, -79, -29,
+ -9, 87, -5, -37, 87, -73, 116, -15, -10, -106, -49, -3, -21, 5, 120, 47, 72, -40, 79, -3, 85,
+ -84, -87, 57, -83, -67, -64, 122, -39, 36, 70, -27, 71, -73, 42, -100, -99, 124, -90, 90, -29,
+ -54, -115, 7, 89, -51, 9, -43, 32, 79, -104, 127, -38, 7, 93, -80, -124, 27, 96, 54, -51, -7,
+ 57, 57, 63, 21, 110, 70, 122, 76, 51, 124, 78, -5, 126, -100, -98, 116, 59, 125, -106, -113,
+ -111, -128, 92, 43, -19, -2, 105, -90, 96, -116, -116, -30, 115, -20, -106, 64, -108, -111, 94,
+ -9, -123, 52, -71, -88, -84, 87, -25, -54, -117, -2, -29, 29, -85, -22, -20, -94, -25, 98, 101,
+ 114, 80, -55, -51, 97, 99, 117, -86, 2, 79, 48, 110, 44, -94, -127, -85, 61, -95, 30, -91, -125,
+ 83, 113, -93, -4, -126, -98, -93, -68, -99, -70, -37, -73, -90, 4, 53, -2, 78, -35, 101, 42, -6,
+ -3, 106, -117, -127, 48, 31, 88, 117, 116, 106, -98, -23, -117, -7, -57, -128, -118, -117, -118,
+ 115, 30, -61, 6, -38, -114, -103, 37, 53, -4, -100, -121, 98, -110, -113, 2, -20, 26, -88, -118,
+ 19, -71, 39, -54, -11, -28, 47, 28, 89, 35, -13, -20, -48, 14, -6, -91, -85, -119, -7, 116, 112,
+ 114, 41, 44, -1, -39, 60, -85, -54, 101, -119, 95, -77, -64, -121, 47, 75, -78, -30, -66, -38,
+ -15, 98, 14, 82, -60, 85, -90, -78, 112, -7, 64, 5, 28, 64, 41, -64, 57, 85, 21, 122, -52, 90,
+ 70, -73, 17, 47, -125, 40, -45, -7, -91, 100, -21, -120, -51, 21, 65, 31, 110, -105, -79, -80,
+ 105, -43, 73, -61, 45, -30, -4, 83, 95, 3, 109, 55, -92, 120, 74, -36, -111, 54, -26, 76, -69,
+ 7, -20, 55, 4, 70, -124, -31, -32, 127, -63, -58, 73, 106, 109, -41, -45, 96, 30, 63, 14, 8, 16,
+ -88, 69, -115, -17, -14, -116, 115, -88, 119, -65, 16, -64, -112, -73, -10, -46, -7, 113, 5, 54,
+ -38, -47, -18, 106, 23, 12, -117, 120, -107, 121, -62, -35, -6, -56, 112, 81, 3, 5, 31, -11,
+ -92, -85, -29, 102, 43, 108, 88, -69, 55, -74, 110, 97, -128, 29, -63, -114, -19, 77, 123, 23,
+ 76, 81, 57, 51, 117, -74, -1, 74, 84, 70, 86, -109, -127, 122, 10, 9, 23, 71, 110, -116, -30,
+ -85, -104, 2, 40, -62, 20, 46, 8, 95, 46, 13, 113, -83, 124, 33, 38, 105, -99, 72, -62, -80,
+ -16, -118, 92, -66, -14, -124, 112, 79, 103, 53, -127, 61, -31, -92, 92, -42, -37, -37, -24,
+ -116, 2, -81, 40, 46, -44, 23, -68, -113, 88, 92, 95, 11, 118, 98, 19, -80, -102, 96, 73, -20,
+ 47, -105, -120, -74, -83, -77, -87, -59, -97, 112, 99, -52, 80, 116, -119, -44, 18, 62, 108, 73,
+ -34, 70, 28, 73, 81, -26, 87, -125, -55, 64, -53, -73, 114, -3, -45, -109, 19, -2, 68, 119, 14,
+ 26, 72, 19, 13, -121, -98, 26, -52, 85, 34, 17, -95, -7, 20, -12, 106, -11, 104, 20, -106, -42,
+ -26, 107, -106, 112, 103, -53, -62, 13, -58, -23, 23, 65, -104, -55, -90, 107, 55, -77, -25,
+ -125, 63, -61, -21, 117, -102, -70, -93, -67, -45, -61, 18, -63, 7, -127, 90, 16, -25, 116, 80,
+ 35, 105, 80, -93, 105, -44, 114, -126, -103, 88, -102, -76, -94, -66, 69, -35, 22, 36, 95, -55,
+ 22, 43, 78, -111, 109, 72, 104, -49, -9, -48, 59, 102, -54, -43, -128, 111, 127, -9, 35, 23,
+ -79, 40, -122, -52, 36, -81, -4, -102, -2, -62, 53, -111, -117, 40, 122, -95, 55, 32, -127, -9,
+ -91, 79, -109, -81, -3, 98, -78, 56, -119, 69, -41, 76, -102, 18, 90, -15, 12, -60, 86, -106,
+ 34, -118, -43, -13, 61, -106, -56, 48, 27, -15, -70, -41, 127, 61, -2, -80, -13, 86, 28, 91,
+ -10, -8, 98, -20, 54, 122, -116, -55, -70, -94, 54, -64, 71, 102, -106, -1, 99, -73, -71, -18,
+ -11, 56, 11, -27, -5, 11, -86, 126, 8, 46, -21, 63, -66, -43, 88, 46, -113, -5, 113, 26, -9,
+ -32, 18, -3, -6, -38, 81, 38, -110, 111, 97, 34, 65, 114, -71, -118, 9, -110, -109, -61, -113,
+ 31, -82, -102, -127, 16, -7, -16, -11, -87, -76, -41, -52, 58, -116, 100, 102, -127, 6, 127, 64,
+ 14, 110, 112, 43, 44, 87, 42, -118, -119, -39, 64, -7, 57, 16, 2, -69, -12, -54, -94, 36, -48,
+ 123, -119, 82, 46, 26, -62, 30, 97, -17, 34, 80, 32, -15, 116, -96, -3, 33, 34, 51, 59, -63,
+ -100, -7, -79, -126, -21, -15, -18, -113, 30, -25, 107, -25, -125, 53, 82, -15, -80, 96, -24,
+ -47, 94, -25, -109, -94, 114, -62, 112, -104, 26, -107, -68, -14, -36, -9, -89, 27, -75, 62, 62,
+ -20, -125, -77, -57, -127, 80, 58, -118, 63, -27, -82, -126, 74, -23, -91, -28, -95, 8, -122,
+ -73, 28, -87, -74, 80, -15, -119, 14, 32, 124, 73, 15, 61, -32, -68, 81, 56, -119, 66, 105, 3,
+ -15, 20, -86, 124, -70, -113, 100, -72, -117, -97, 127, 103, 16, 105, 8, 39, -128, -64, -47, 66,
+ 123, -110, 13, 123, -124, -24, 42, 102, -4, 47, 107, 125, 63, -52, -35, 113, -74, 13, 8, 17, 16,
+ -106, -21, -69, 47, -3, 103, -2, 19, -100, 111, -11, 1, 112, 90, -38, -31, -45, -55, 25, 92,
+ -122, 66, -18, -98, -82, -49, 119, -35, -128, 26, 60, -79, -23, 127, 82, -52, 115, 77, -109,
+ -111, 17, -99, 31, 33, 41, 35, 87, -47, -126, -18, -25, 81, -71, 9, -72, -92, 64, -92, 23, 116,
+ 96, 40, 55, -87, 119, -105, 66, 49, 46, -10, 26, -25, -105, 127, -124, 86, -2, 39, 116, -108, 6,
+ 21, 15, 1, 75, -5, 101, 13, 57, 70, 126, -50, -97, 123, -73, -77, 53, -11, -73, 44, -99, 91, 85,
+ 21, -59, -1, 117, 64, -100, 47, 75, 93, 9, -4, 83, -55, 15, 99, 31, 43, -49, 15, -89, -115,
+ -114, -50, -35, -19, -65, 122, -39, 92, -21, -3, -66, 8, -70, 107, -55, -86, -36, -23, -21, 80,
+ -79, 48, 116, 57, -71, 33, -111, -68, -75, 37, 55, 39, 124, 96, -66, 10, 14, 118, 50, 85, -33,
+ 54, -101, -7, 21, 88, -122, 50, -92, 123, 37, 109, -60, -127, 26, 110, -20, -31, -66, -56, -24,
+ 47, -14, -60, -101, 69, -38, 78, 0, 44, -71, 108, 4, 25, -68, -106, 20, -40, -103, 108, -70,
+ -56, 78, 12, 82, 81, 46, -105, -123, -46, -20, -127, -67, -77, 76, -74, 40, 105, 2, 27, 112,
+ -107, -121, -53, 6, -88, -11, 26, 41, 64, -69, -44, 27, 47, 24, -31, -86, -4, 4, -46, 42, 50,
+ -55, 37, -11, -95, 108, 54, 37, 67, 37, -14, -40, 41, 124, 22, 108, 99, 16, 55, 88, 19, 49, -87,
+ 27, 17, -68, -107, 15, -62, 84, 109, 72, -26, 71, 63, -17, -72, -63, -101, -8, 62, 24, -112,
+ 126, -102, -64, 29, -19, -75, 74, 29, 90, -90, 83, -22, 106, -27, -114, 56, -111, -33, 11, 3,
+ -16, 94, 115, -97, 67, -78, 62, -93, -36, 60, -65, -54, 72, 70, 44, -77, 73, 29, -106, 38, 72,
+ -37, -110, 79, -98, -15, -58, 96, -85, -68, -15, 73, 57, -127, 14, -123, -40, 70, 63, -64, 115,
+ -63, 127, 94, 85, 52, 30, -62, 83, -30, -97, 82, 39, 2, 36, -50, 106, 116, 66, 104, -14, 73, 14,
+ -106, -127, 11, 41, -27, 56, -99, -74, 55, 123, 124, 9, 46, 12, -97, -37, -10, 122, 124, -27,
+ -64, 93, -70, 9, 119, 13, -9, -71, -118, 19, 50, -36, 114, 120, -24, -62, 40, 127, 9, -62, 84,
+ 57, 66, 91, -114, 120, -49, 63, 99, -73, -66, -64, 84, -31, 67, -52, 12, 38, -62, 37, -122, -50,
+ -95, 24, 19, 54, -80, 57, -118, -84, 124, 90, 53, 72, 29, -123, 67, -65, 99, -58, -28, 20, -110,
+ -103, 92, -91, -108, 23, -118, 44, 74, 76, -29, 94, -121, -37, -32, 107, -62, -67, -55, -45,
+ -50, -44, 25, -77, -102, 90, -128, -31, -5, -64, 110, 122, 88, -18, -53, -85, 122, -11, 100,
+ -106, 97, 59, -103, -110, 5, -16, 59, -126, -74, 9, -119, 115, 49, -73, -42, 32, 100, 59, -98,
+ 106, 55, -101, 87, 126, 59, -23, 106, -102, 100, -69, -46, 76, 53, -107, -119, -113, 104, 117,
+ -27, 75, -32, 8, -81, -10, 50, 108, -32, 51, -79, -53, -2, 66, -9, 113, 14, 99, -100, -34, -21,
+ 13, 2, 45, -33, 0, -16, -64, -126, 69, -25, -34, 28, 105, -48, -38, 82, 12, 27, -71, 35, 13, 11,
+ 21, 26, -19, -4, 44, -52, -126, -63, -32, -84, -22, -63, -29, 96, -97, -82, -12, -53, 98, 41,
+ -69, -38, 101, -31, 47, -9, 16, -10, 9, -36, -103, -91, -65, -36, -93, -45, 94, 110, 54, -94,
+ 68, -39, -116, -40, 61, -112, -91, -79, 98, -36, 87, 35, 88, -61, 125, 112, -84, 48, -38, 105,
+ -92, 69, -68, 92, 0, 27, -72, -65, 97, 98, 66, 97, -74, 29, 46, -21, 102, 61, 120, -62, 38,
+ -125, -60, -43, 4, 5, -27, 113, -43, 105, -22, -110, 68, 13, -14, -23, 18, 95, -79, -108, 87,
+ 19, -80, 16, 54, -121, 88, -64, -113, 73, 3, -20, 17, 0, 26, -88, -49, -2, 21, 120, -105, -85,
+ -113, 76, 106, 37, -13, -75, 29, -127, 10, -17, -53, -124, 24, 37, -31, 26, -1, 109, 88, -88,
+ -37, -51, -32, -125, 48, -40, 123, -108, 55, -120, -62, -91, 47, 62, -127, -25, 99, 68, 22, -40,
+ 58, 119, -31, -93, -122, 39, -92, 25, -127, -42, 97, 69, -6, 110, -61, -21, -94, 82, 123, -93,
+ -51, -90, 50, -96, 127, -32, 125, -76, 117, 75, -52, 79, 110, -51, -15, -81, 49, 62, 118, 120,
+ -27, 22, 84, -22, 77, -105, 87, -7, -23, 47, -8, 108, 82, -12, 84, -52, -85, 68, -89, -24, -32,
+ 6, -34, -83, 80, 44, 12, -51, 50, 74, -121, -106, 6, 85, 32, 42, 76, -59, -52, -99, 102, 108,
+ -127, -49, 0, 60, 62, 2, 13, -19, -92, -41, -69, 55, -70, 94, 23, 36, 89, 70, -115, -51, 26,
+ -95, 13, -69, 42, 62, 59, -24, -63, -50, -6, -86, -97, -115, -58, -107, 69, -12, -109, 73, 4,
+ 63, 12, 32, 13, -123, -72, -41, -7, -81, 37, -91, -128, 109, -79, -80, 88, -22, 108, 126, 103,
+ 27, -29, -81, 52, 55, -91, -13, -43, -75, -59, 80, -6, 6, 83, -103, -64, 8, 63, -34, -59, 21,
+ 55, -115, 62, 77, 30, -50, -71, -66, 87, 99, -47, 0, 124, 76, 120, 79, -12, 54, -16, -98, -72,
+ -41, -66, -14, 114, -27, 108, 57, -49, 107, -73, 90, 107, -103, 25, -107, 112, -119, -54, 106,
+ -54, -8, -13, -81, -62, 92, -84, 113, 77, 74, -63, 104, 92, -94, -128, -43, -54, -71, 117, 27,
+ 14, 98, 52, 119, -93, -77, -80, -46, 88, 35, 123, 86, 87, 122, 62, 108, 19, 27, 111, 2, 62, -67,
+ 89, 14, -82, 41, 123, -117, 74, 109, -124, -115, 15, 123, -65, 42, -81, -105, 19, -30, 86, -72,
+ 84, 63, -109, 34, -65, -127, 6, -104, 77, 103, -111, 90, 16, 31, -74, -33, 122, 58, 52, 10, 2,
+ 65, 72, 68, 79, 52, 31, -19, 100, -86, 21, -49, 116, 101, 82, 111, -96, -76, 67, -40, -62, -15,
+ -79, 109, -58, 6, 11, -91, -29, 65, 21, 75, 74, -28, 21, 103, 46, 48, -42, 51, -110, 80, -95,
+ -102, -9, 8, -95, 102, 102, 16, 105, 103, 92, -106, -109, 77, 93, 32, -12, -25, 5, 17, -86, -34,
+ 58, -50, 55, 63, -8, -72, 3, 26, 91, 72, 71, -77, 94, 91, 39, 45, 7, 0, 30, -45, -100, 35, 43,
+ -41, -72, 16, -103, -115, -4, 51, 39, -23, -89, -84, 105, 94, -91, -88, 82, 123, -26, 51, -16,
+ 97, 47, -39, 35, 46, -89, 74, 7, -80, 116, -21, 82, -84, -13, -99, 31, -58, -93, 36, 99, 36, 44,
+ -65, 45, 94, -91, -41, 115, -10, 116, -67, 45, 19, -20, 113, -62, 111, 124, 108, 71, -121, -64,
+ 122, -121, -105, 114, 115, -126, -93, -108, -113, -1, -80, -86, 116, -111, -29, 53, -76, 87, 19,
+ 45, -30, 91, 91, -7, -49, 12, 112, -8, -26, 82, 58, -82, -76, 119, -50, 14, 85, 113, 20, 48,
+ -102, 37, 24, -120, -107, -52, 67, -44, -92, -79, -40, 28, 21, 55, 116, 88, 19, -49, -78, 86,
+ -89, 74, -4, 118, 75, 11, -103, -127, -47, -16, -77, -78, 8, 2, -88, 50, 23, -99, 102, -100,
+ -116, -99, -109, -112, -115, 78, 55, -39, -84, 100, -91, -101, 73, -9, 39, -23, 62, -125, -106,
+ -55, 119, -118, 114, -33, -99, 20, -53, 91, 115, 47, -93, 51, -99, -9, 92, -71, 120, 57, -44,
+ -87, -11, 108, 30, 43, -4, 118, 90, 126, -54, -99, -47, -2, -61, -3, -62, 45, 92, -70, -105, 30,
+ 98, 112, -94, 56, 35, -22, 32, -93, -6, -36, -5, -77, -78, 120, 45, 104, 69, -49, -30, 39, 75,
+ 38, -94, -12, 34, 34, -44, 48, -100, 74, 34, 69, 94, -12, 73, 27, -111, 90, 33, -38, 93, 40,
+ -16, 89, 26, -110, -116, -10, -65, 85, -57, 48, -86, 121, 118, -41, 63, 33, 109, -78, -26, 122,
+ 111, -115, -52, 95, 26, -70, -14, -86, -80, -27, -6, 12, -44, 123, 28, 93, -74, 14, -124, 87,
+ -28, -12, 111, -117, -83, 48, -41, -3, 60, -51, -91, 118, 54, 110, 18, -2, -120, -66, 46, -35,
+ -91, 106, 94, -91, -11, 41, -92, -22, 96, -113, -109, 105, 56, -80, 17, -118, 124, -16, 30, 30,
+ 117, 126, -99, -106, -69, -28, 85, 85, -41, 21, -95, -85, -112, -125, -45, 69, 10, -34, -120,
+ 33, -58, 120, 51, -22, -7, 31, -34, 4, 55, -102, -70, 118, -83, 49, 111, -45, -9, 69, -95, -66,
+ 116, -3, 104, -61, 17, 21, -20, 121, 117, 127, -70, 5, 89, -89, 51, 15, 64, 126, -73, 97, 90,
+ 119, -22, -37, -54, 52, -33, 26, -54, 75, 79, 73, 100, 44, 3, 53, -25, 49, -123, -101, -80, -54,
+ -81, -32, 88, 49, -14, -4, 18, 42, 52, -65, -33, 68, 83, -89, -11, 57, 102, 71, 122, 74, -92,
+ -44, -94, -108, 14, 104, -107, -124, -63, 8, 32, 85, -18, -16, -91, -63, -38, 27, -108, 24, 19,
+ -33, 53, 70, -32, 41, 38, -77, -30, 89, 28, -15, -89, -86, 32, 51, 28, 67, 124, -96, -103, -34,
+ -113, 22, 15, -8, 104, -38, -56, 65, -96, -111, 104, -9, -38, 107, 55, 112, 47, 99, 50, -18, 90,
+ -69, 116, 80, 95, 52, -27, -98, 6, 12, -11, 124, -120, -96, -91, 118, -51, -120, 90, -92, -104,
+ -83, -73, 84, 61, 78, -39, -99, 33, 58, -45, -14, 127, -20, -44, 125, 21, -26, -21, -36, 51, 73,
+ 71, 73, -17, 83, 11, 107, 91, 36, -65, -24, 56, 117, 114, -126, -34, 1, 120, 66, -50, 14, 91,
+ 97, -35, 75, 87, 123, -53, 63, -38, -74, -62, -117, -45, -40, 125, -5, 53, 50, 0, -110, 7, 7,
+ 45, 37, -71, -21, 70, -95, -60, 74, -55, -54, -96, 115, -62, -32, -3, -121, -18, 27, -107, 49,
+ -39, 58, -39, 91, 107, 65, -99, -64, -19, -10, -126, 38, -40, -112, 0, 16, 107, -59, 119, -70,
+ 79, 49, -18, -76, -22, -38, -98, 35, -99, 61, 67, -100, 29, -104, -17, 22, 108, 105, 88, -114,
+ -65, 84, 99, -69, -84, -87, -81, -28, 68, -66, 3, 69, -69, 83, 16, 61, -102, 50, 67, 46, -98,
+ -77, -40, -78, 48, 68, -85, 123, -92, 37, 14, 75, 13, -23, -110, 23, 26, 90, -81, -1, -109, 85,
+ 121, -68, -55, -7, 21, -81, -35, 41, 3, -72, -52, 36, 35, -83, -9, -81, -124, -104, 31, 54, 8,
+ -32, 80, 73, 89, -41, 116, 127, -110, 68, -82, 82, -79, 105, 113, -110, -70, 121, -24, -54, 37,
+ -12, -70, -77, 15, 14, 105, -19, 16, -6, 73, 102, 121, -116, -62, 54, 65, 119, 43, 60, -79, -66,
+ -17, 1, 97, -1, -11, -5, 104, 10, 59, -108, 21, -8, 64, -71, -86, 14, -98, -87, -49, 30, -45,
+ 109, 43, -67, 10, -122, 25, 98, -102, 127, -27, -52, -61, -66, -47, 114, -94, -126, 4, 0, -65,
+ -11, -51, -67, 84, -43, 44, 88, 53, -6, 124, 11, -123, 34, 12, 102, -13, -106, 47, 62, -71, 43,
+ -65, 28, 37, 32, 80, 23, 6, 75, -103, 73, 112, 33, 84, -89, 12, -81, 42, 65, 58, 14, -102, 90,
+ 29, -116, 104, 107, -99, -1, -43, 122, 118, 88, -2, 117, 84, 1, -123, -2, 2, -32, -18, -122,
+ -36, -58, 16, 76, 115, 27, -121, -2, -79, -44, -39, 33, -29, 33, -34, 55, 71, 61, 117, -22,
+ -126, 51, 29, 55, -34, -48, 17, -57, 74, 71, -33, -50, 60, 41, -119, -93, -45, -127, -30, 104,
+ 35, 60, -117, -113, 81, -59, -39, -84, -39, -46, -106, 57, 77, 62, -11, -44, -87, 71, 35, -117,
+ -87, -77, -98, 68, -29, -121, -16, -16, 39, 48, -74, 23, 82, -62, 32, 62, 27, 125, 84, 39, -91,
+ -91, -93, 76, -24, 98, 123, -58, -114, 17, 28, 93, -17, 74, 92, -17, 9, -86, -116, -72, 54, -74,
+ 71, 9, -97, -33, -20, -126, -50, 117, 102, 54, 123, 124, -70, 30, -102, 27, 23, 105, -40, -35,
+ -89, -33, 89, 3, 44, 18, -15, 10, 116, -111, 1, -81, -31, -125, -102, 103, -93, -15, 72, 84, 19,
+ -30, -17, -115, 99, 43, 5, -92, 52, 59, -55, -105, -128, 19, 8, -78, 43, 7, -55, -126, -106, 11,
+ 69, 118, 24, -128, -54, -86, 22, -121, -43, 69, -15, 96, 52, 52, 90, -118, -10, -58, 121, 63,
+ -48, -13, 22, -101, 17, 42, -28, -54, -63, 121, -96, 111, 113, 103, 126, 37, -52, -40, -106,
+ -104, 123, -48, -92, 83, 100, -70, -52, -59, -93, -116, -90, -93, 82, -117, 103, 52, -71, -42,
+ 57, 25, 57, -74, 71, 7, 32, 96, -60, 11, 121, 58, 71, 40, -92, 35, 88, -12, -109, -56, -122,
+ -30, -118, 103, 65, -5, -90, -97, 103, -117, 66, -20, -42, -46, 67, -29, -23, 72, -97, 26, -54,
+ -103, -76, -47, -71, 23, -83, -20, 95, 111, 101, -83, 106, -71, -70, -63, 55, -85, -41, 117, -9,
+ 37, 96, -71, -118, -44, -43, 2, 107, 113, -39, -107, 41, -13, 0, -87, 77, 83, 99, 68, -84, -6,
+ -1, 67, 124, -57, 115, 29, 24, 26, -42, 104, 58, -87, -38, 12, -98, 11, 109, 62, 59, -66, -48,
+ -20, 70, -111, 11, 120, 21, -58, -29, -76, 44, -7, 26, -119, -59, -87, 44, 122, 8, 114, -58,
+ -109, -119, -63, -58, -51, 33, 35, -109, 81, 110, -90, 121, -21, 64, -60, 68, 18, 75, -82, -81,
+ -103, -76, -116, 23, 53, 58, -41, -23, 49, -102, 81, 101, 39, -59, -91, -98, 111, 2, 65, 110,
+ 121, 5, 13, 97, -119, 109, 40, 82, 47, -51, 47, -57, 35, -109, 53, -42, 10, 3, -15, 122, -25,
+ -67, -62, -121, -120, -31, 18, -20, 87, -88, 75, 95, -121, -93, 33, 61, -88, -96, 88, -69, -54,
+ -121, -99, 49, 122, -53, -49, -125, 53, -79, -46, -128, 109, 125, -93, -83, 44, -101, 69, 68,
+ -91, -17, 55, -13, -75, -80, 21, 32, -13, 40, 86, -65, 85, 80, -82, -38, -52, 110, -119, 100, 8,
+ 77, -23, 67, -41, 73, 27, 38, 9, -11, -32, -30, 75, -15, 67, -41, 46, 27, -89, 9, 117, -38, -14,
+ -81, -4, 71, 113, -79, 81, -36, 63, 15, -70, 104, 34, -56, -39, 93, -34, -127, 90, -36, 73, 47,
+ -76, 113, 55, 123, -92, 48, 116, 108, -123, 31, -67, -39, 3, -9, 6, 13, -17, -50, -125, 1, 105,
+ 121, 100, 79, 82, -85, 123, -33, -73, 54, -61, -113, 121, -110, 69, 119, 94, -112, -120, -34,
+ -35, -104, -116, 44, 85, 109, -104, 127, 120, 87, 75, -48, -115, 74, 85, -47, -53, 16, -5, 92,
+ 67, -32, 12, 79, 109, 105, 5, -92, 51, 46, 96, -96, 63, 106, 82, -54, -95, 20, -60, -23, 48, -5,
+ -128, 22, 23, -93, 93, -64, 35, 21, -121, -79, 59, -1, -50, 55, -7, -10, -85, 3, -7, 121, 98, 5,
+ -19, 76, -78, -128, -47, -42, 61, -59, -46, -24, -16, -51, -48, 122, -26, 74, -91, 54, 53, 46,
+ 74, 25, -30, -74, 52, -22, 118, -103, -53, -113, 44, -19, 70, -86, 106, 72, -68, -86, 110, 34,
+ -35, 57, -43, 32, -4, 14, 102, 25, -76, -84, -86, -83, -2, -107, -4, 49, -97, -83, -95, 6, 100,
+ -73, 6, 34, 49, 59, 50, 30, -8, 6, -55, 24, -6, 67, -121, 115, 40, -50, -75, -46, -26, 111, -20,
+ -75, -83, -16, -48, 65, -64, 119, 62, -59, 3, -12, 109, 0, -118, -94, 17, -51, 124, 63, 42, -3,
+ 44, 53, -81, -35, -33, -83, 115, -114, -4, -104, 44, 7, -81, -97, -102, 104, 29, -97, 70, 91, 3,
+ 88, 67, -127, 78, -92, -16, -34, -18, -81, -125, -38, 117, -78, -36, 9, 76, -85, 121, 2, 10,
+ 114, 65, -5, -29, -34, 101, 20, -108, 46, -90, -98, 85, -62, -51, 108, -72, -51, 44, 22, 112,
+ 121, 58, -58, 109, -96, 58, 103, 27, -88, -81, 99, -7, -33, -113, 64, -122, 115, 19, -93, 37,
+ -19, 93, -98, 78, 115, 91, -88, -82, -36, 61, 90, 77, 27, 26, -116, 80, 90, 85, 6, -87, 59, 110,
+ 63, 20, -81, -127, -53, 18, -73, 39, 75, 79, -106, 29, -50, -13, 43, -99, -92, 109, 80, -83, 69,
+ -102, 38, 90, -41, 48, -47, -93, 18, 116, 32, 90, -73, -96, 90, 49, 19, 73, -35, 60, 53, -72,
+ -52, 84, 52, 27, -67, -114, 82, 79, -89, -80, -111, 124, -51, 80, 110, -76, 125, 18, -73, 44,
+ -100, 118, -16, -64, -35, 22, -86, -116, -19, -101, -35, 42, 85, -83, 69, -65, 37, -104, -88,
+ -108, -25, -9, 15, 91, -100, -86, 8, -75, -37, 103, 3, -69, -9, 114, -25, 25, -87, 118, -75,
+ -115, -8, 74, 53, 73, 46, -22, -108, 30, 71, -96, 40, -76, 121, 71, -63, 95, 96, 113, -54, 87,
+ 1, -79, 2, -40, 11, 22, -118, -117, 94, -44, -112, -27, -86, 96, -4, -58, 121, -71, 54, -58,
+ -71, -125, -65, 126, -116, -107, 125, -28, -74, 97, 15, -76, 59, -26, 58, -38, -39, 122, 55, 85,
+ -109, -114, 75, 25, -74, 57, -78, -10, -76, -115, -12, 29, 84, 86, 97, 5, 116, -114, 62, -98,
+ -36, 105, -119, -19, 12, 11, 49, 76, 21, 56, 1, 115, 115, 42, -67, 60, -40, 19, 38, 50, 33, 112,
+ 98, 123, -76, -74, 50, 66, 18, -61, -114, 36, -95, 92, 124, 20, -56, 29, -41, 28, -4, -106, 115,
+ -83, 98, -47, 96, 87, -72, 96, -83, -93, 1, 112, -43, 59, -80, -24, 46, -45, 87, 92, -108, -78,
+ 101, -112, 111, -119, -67, 26, 97, 1, 36, -128, 120, 8, -20, 84, 107, -9, -104, 25, 0, -36, 58,
+ 111, 81, -83, 65, 42, 51, 61, -71, 118, 111, 29, -93, 39, -56, -72, -18, -53, 0, 34, -77, -59,
+ 112, -79, 51, 86, 82, -24, 64, -120, -1, -102, -3, 42, -93, 16, 38, 100, 39, -124, 92, -89, 31,
+ 94, -32, 40, 19, -8, 48, -83, -66, -68, 110, -72, 36, -38, -91, -63, 33, 35, -96, -121, -119,
+ -59, 56, 89, -117, -123, -79, -68, 42, -4, -116, -108, -104, -84, -111, -26, 94, -38, 61, 94,
+ -72, -85, -18, -30, 118, -14, -94, -74, -24, -21, -90, -83, -116, -38, -8, 9, -17, 72, -62, -78,
+ -75, 47, -117, 109, 127, -87, -36, 53, 90, 16, -72, -50, 40, 87, 97, -51, -96, -55, -120, -32,
+ -58, -21, 102, 117, -121, -98, 74, -67, 104, -122, 108, -3, -96, 64, -114, -3, 30, 48, -14, 44,
+ -41, 91, 54, 58, 80, -13, -88, 121, 32, 122, 25, 24, 9, 72, 17, -1, -93, -66, 96, -84, 4, 37,
+ 69, 91, 64, 32, 46, 89, 7, -32, -120, 10, -38, -3, -59, -75, 14, 116, 115, 121, 99, 122, -95,
+ 107, 1, 65, 70, -45, 35, -52, -87, -56, 43, 121, 12, -93, -8, 83, -118, 15, -33, -67, 45, 74,
+ -66, -31, -28, 5, 104, -13, 113, 19, -89, 105, 66, -82, 74, 54, -104, 69, 103, 86, 118, -44,
+ -75, -47, 81, -75, 8, -32, -95, 121, 48, -121, -106, -88, -15, -52, -99, -78, 58, 113, 16, 71,
+ -48, 76, 80, 81, 59, 43, -106, 27, -49, 2, -11, -71, -30, -80, -44, 62, -113, -20, 12, -60, -87,
+ 22, -30, 64, -120, 127, 121, 47, 127, 58, -98, -4, 79, -72, -117, 115, 52, 95, 40, -59, -125,
+ -33, 125, -96, -93, -92, 17, -99, -85, 10, -119, 91, -115, -63, -32, -11, -102, -105, -93, 90,
+ 37, 94, -104, -47, -63, -94, 15, -34, 20, 73, -59, 85, -31, 6, 106, -67, 14, -125, 28, -63, 40,
+ 86, -68, 104, -22, 124, -27, -84, -13, 43, -45, -30, -95, 95, 16, 79, 23, -66, -78, -74, 43, 86,
+ 70, -95, 90, -65, -1, -58, 54, 12, 47, -47, 28, 91, -54, -19, -75, -43, 12, -108, 12, 71, 38,
+ 118, -8, 1, 42, -113, -6, 1, -93, 118, 67, -79, 25, -80, 118, 34, -29, 0, -23, 86, 53, -118, 89,
+ 112, 0, -61, -88, 76, -24, 59, -75, 23, -1, 64, -80, -52, -40, 34, -50, -19, -127, 57, 79, 43,
+ 92, -113, -96, 73, 0, 33, 122, 42, 104, -62, -66, -108, -104, 45, -120, 69, -3, -20, -113, -40,
+ -70, -96, 72, -21, -95, 1, -16, -124, -87, 125, 56, -108, 7, -112, -104, 105, 80, -34, -93, 24,
+ -6, 35, -38, 42, -4, 23, -112, 40, 45, 106, -72, 29, 44, -36, -61, -8, -93, -34, 3, -41, -26,
+ 121, 6, 100, -14, -112, -117, -15, -120, -92, 44, -43, 94, -13, 121, -59, -82, -68, 7, -19,
+ -110, -121, -58, -118, -121, 92, -8, 33, -120, -28, -95, -31, -120, -62, 49, 51, 3, 68, 4, -56,
+ 51, -13, -90, 47, -16, -24, 63, 125, -11, -94, 99, 69, -84, -54, 127, 81, -120, 42, -47, -128,
+ -13, 38, 115, 59, -112, -30, -9, -116, 121, 63, 111, 32, -116, -2, 0, -33, 79, -67, 90, -65,
+ -108, -107, -5, -107, 11, -102, 91, 106, -42, 74, 45, -80, -65, 54, 36, 121, -125, -118, -34,
+ -51, 36, -85, -78, 86, 121, -103, -39, 35, -76, 17, 59, 68, -40, -43, -27, 63, -76, 126, -94,
+ 18, 87, 20, 92, 38, -6, -54, 9, 45, 93, -57, 53, -11, -44, -38, -24, -126, -40, -24, -35, -121,
+ -55, -87, -63, 70, -88, 13, -78, -89, 2, 50, 59, 4, -14, 81, 25, 34, -20, 87, 116, -76, -31,
+ -93, 15, 112, 61, -43, -11, -86, -25, 10, 41, 1, 60, 105, -42, -90, -44, 38, 98, 126, -128, 28,
+ 99, 20, -97, 105, -101, 27, -106, 13, -108, -18, 23, -79, 121, 57, 93, -16, -37, -82, -1, -128,
+ -67, 99, 117, 79, 85, 83, 12, 53, -101, -52, -75, 72, -128, -62, 45, -54, 11, 0, -58, -88, 11,
+ 121, 33, 86, -87, 31, -54, 109, -37, 10, 119, -9, 55, -7, 77, -52, 93, 64, -62, 115, -88, -4,
+ 67, -1, -37, 31, 107, 90, -109, -121, 71, 105, -123, 61, 75, 89, 108, -91, -6, 115, 45, 109, 10,
+ -35, -84, 41, 127, 104, -84, -70, -6, -118, 6, 110, 99, -7, -112, 15, -79, -20, 51, -41, 78, 25,
+ -97, -2, -121, -117, 7, -87, -76, 60, -7, -7, 0, 51, 91, 34, 85, 21, -1, 108, 41, 8, 126, -25,
+ -30, 68, 109, -52, -51, 1, -111, 11, -22, -70, -33, 95, 40, 6, 63, 52, -66, -20, -6, -104, 81,
+ 57, 22, 82, 119, 126, 76, -10, -108, -63, -123, 19, 23, -106, -1, 117, 26, 112, -85, -78, 81,
+ -116, 53, 86, -126, -80, 122, 36, 67, 18, 19, -114, 73, 125, -3, -69, 99, 10, -30, 19, 112,
+ -103, 0, -61, 47, -106, -45, -105, -107, -56, 23, 14, 51, -70, 30, -32, 30, 7, 22, -31, -41, 19,
+ -47, -64, -52, 119, -66, 54, -109, -87, 3, 95, -124, 94, -48, 36, -40, 13, 19, 91, -14, -115,
+ 103, 66, 20, 44, 47, 8, -40, 4, -114, -110, -47, -28, -108, 89, 0, -7, -71, -91, -43, 98, 8,
+ -85, -98, -113, 103, -71, 69, 14, -95, -36, 92, -17, -66, -95, 123, -15, 52, 88, -60, -23, 123,
+ -61, -4, -33, -45, 77, 57, -121, 119, 116, -40, -31, -15, 96, 54, -49, -44, 36, -37, 111, -45,
+ -17, 12, 14, 21, 105, 48, 51, 42, -89, 55, 61, -5, -2, -36, -88, 36, -35, -29, -7, -68, -28,
+ -76, 5, -38, -66, -72, 24, -120, 8, -86, -28, 0, 71, -89, 20, -40, -100, 61, -57, 52, 23, 66,
+ -2, -24, -7, 86, -100, 111, -114, -47, -25, -40, -61, -67, -104, 33, 49, 16, -115, 9, -64, 27,
+ 122, 34, -33, -89, -113, -50, 42, 111, -14, 110, 43, 32, -112, 101, -59, 28, 76, -2, -117, 47,
+ 5, -73, -75, 21, -91, 99, 81, 93, -17, -119, 68, -21, -84, -51, -64, -98, 58, -33, 77, 4, 18,
+ 116, 62, 111, -105, -13, 91, -92, 81, -34, 40, 17, -128, 85, -19, 20, 8, 92, 83, 10, 3, 40, 89,
+ 60, 109, -23, 59, -66, -22, 43, 124, 25, -105, 77, 14, 75, -111, 13, 45, -90, -108, -79, 78,
+ -45, -55, -44, -86, -20, -41, -11, 65, 76, -79, 91, -23, 77, -84, 114, -109, 2, -71, 68, 8, -31,
+ 99, 97, -104, -94, 69, 64, -16, -48, -78, 99, -58, -17, 95, 96, -64, 47, 96, -69, 60, 28, 114,
+ 64, -128, -128, 114, 28, -124, 72, -41, -48, 82, -6, 63, -27, -126, -86, -121, 0, 4, 4, 35,
+ -111, 66, 64, -61, 117, -92, 48, 88, -128, 116, 7, -24, -111, -55, 96, -59, -96, 49, -70, -41,
+ -47, 85, 86, -37, -32, 53, -49, 62, 68, 80, -37, 95, 29, -114, 11, -65, 90, -99, -97, 101, 96,
+ -88, 5, 34, 3, 23, -22, 42, 4, -4, 17, -121, 106, -60, 33, -38, -32, -8, 41, -87, -4, -35, -102,
+ 7, 18, 35, -7, 85, -18, 60, 15, 34, 82, 46, 68, 63, 80, -38, 4, 51, -74, -34, 83, -33, -8, 44,
+ 87, -18, -8, 46, -53, -109, -121, -114, 10, 63, -36, -1, -123, 69, 107, -58, 33, -11, 63, -117,
+ 60, 22, 73, -36, 22, -76, -92, -74, -37, -35, 87, 40, -97, -6, 95, -25, -2, -99, -101, 102, -48,
+ 45, -55, 85, 94, -48, 57, -100, 34, 16, -63, -16, 106, -75, -7, -109, 71, -74, 20, -16, 37, 90,
+ -61, 69, 19, -111, 95, -104, 116, 75, -68, 85, -80, 66, 127, 127, 67, -98, 121, 53, 23, -3, 56,
+ -89, 99, 57, 9, 122, 76, 119, 1, -117, 47, -105, -42, -7, 51, -8, -81, 48, -60, -69, -29, 24,
+ 19, -81, 43, 31, -36, 62, 96, 20, -58, 39, -122, -115, 7, -114, 118, 27, 27, 78, -101, 75, -93,
+ -104, -8, 119, 121, -97, -84, 58, 33, 18, -35, -29, 20, 20, 7, 112, 60, 31, -12, 7, -128, -55,
+ -68, -7, -12, -115, 97, 115, 44, -46, -68, 108, 36, 121, -1, 84, -4, -26, -126, 85, -32, 36, 26,
+ -19, 71, -121, -92, -51, -116, 81, -71, -83, -50, 21, -119, -60, -78, -84, 102, 19, -26, 118,
+ -53, -13, 16, 36, -64, -83, -66, 32, -99, 54, 83, 104, 61, -19, 107, 95, -66, -42, -6, 25, 86,
+ -13, -53, -49, -9, 74, -13, 58, 125, -96, -32, -22, -21, -12, -38, -114, -88, -100, 35, -87,
+ -108, -2, -103, 87, -119, -109, 50, -28, -101, -4, -43, 105, 119, -118, 103, -104, 41, 47, 71,
+ 53, 11, -53, 59, -13, -11, 83, -33, 28, 11, 78, -59, 73, -33, -60, 119, -73, -127, 98, 39, 77,
+ 21, -8, -103, 103, 44, -87, -52, -74, 56, -63, -70, -121, 40, 103, 7, -100, 113, 53, -46, 44,
+ 16, 31, 102, -31, 104, -38, -120, 118, -122, -55, 25, 1, 92, 22, -14, 24, 108, 92, -90, -93,
+ -16, -99, -13, -127, 75, 101, -42, -86, -29, -51, -49, -105, -118, 91, -56, -51, -73, 117, 53,
+ -39, -73, 121, 83, -49, -10, -86, 11, -97, 40, -33, 6, -40, -9, -32, 92, -101, -83, 116, -5,
+ -57, -93, -121, 2, 38, -65, -6, 45, 100, 92, 92, 74, 115, 45, -33, 92, -11, 70, 33, 76, 85, 94,
+ 1, -111, -103, 6, -4, -31, 44, -53, -77, -45, 100, -83, 92, -11, 10, -7, 126, 23, 36, 61, -18,
+ -28, 67, 126, 53, -45, -77, 95, 43, -73, 30, -37, 122, -53, -79, -77, -42, 71, -124, 43, -89,
+ 60, -80, -89, -68, 96, 29, 103, -50, -93, 105, 7
+ };
+
+ static class ProxyStream extends FilterInputStream {
+ int readBytes;
+
+ ProxyStream(InputStream is) {
+ super(is);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int result = super.read(b, off, len);
+ if (result > 0) {
+ readBytes += result;
+ }
+ return result;
+ }
+ }
+
+ @Test
+ public void testEagerStream() throws IOException {
+ ProxyStream ps = new ProxyStream(new ByteArrayInputStream(DATA));
+ BrotliInputStream reader = new BrotliInputStream(ps, 1);
+ byte[] buffer = new byte[1];
+ reader.read(buffer);
+ reader.close();
+ int normalReadBytes = ps.readBytes;
+
+ ps = new ProxyStream(new ByteArrayInputStream(DATA));
+ reader = new BrotliInputStream(ps, 1);
+ reader.enableEagerOutput();
+ reader.read(buffer);
+ reader.close();
+ int eagerReadBytes = ps.readBytes;
+
+ // Did not continue decoding - suspended as soon as enough data was decoded.
+ assertTrue(eagerReadBytes < normalReadBytes);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Huffman.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Huffman.java
new file mode 100644
index 000000000..38f7f293d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Huffman.java
@@ -0,0 +1,137 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+/**
+ * Utilities for building Huffman decoding tables.
+ */
+final class Huffman {
+
+ private static final int MAX_LENGTH = 15;
+
+ /**
+ * Returns reverse(reverse(key, len) + 1, len).
+ *
+ * <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
+ */
+ private static int getNextKey(int key, int len) {
+ int step = 1 << (len - 1);
+ while ((key & step) != 0) {
+ step >>= 1;
+ }
+ return (key & (step - 1)) + step;
+ }
+
+ /**
+ * Stores {@code item} in {@code table[0], table[step], table[2 * step] .., table[end]}.
+ *
+ * <p> Assumes that end is an integer multiple of step.
+ */
+ private static void replicateValue(int[] table, int offset, int step, int end, int item) {
+ do {
+ end -= step;
+ table[offset + end] = item;
+ } while (end > 0);
+ }
+
+ /**
+ * @param count histogram of bit lengths for the remaining symbols,
+ * @param len code length of the next processed symbol.
+ * @return table width of the next 2nd level table.
+ */
+ private static int nextTableBitSize(int[] count, int len, int rootBits) {
+ int left = 1 << (len - rootBits);
+ while (len < MAX_LENGTH) {
+ left -= count[len];
+ if (left <= 0) {
+ break;
+ }
+ len++;
+ left <<= 1;
+ }
+ return len - rootBits;
+ }
+
+ /**
+ * Builds Huffman lookup table assuming code lengths are in symbol order.
+ *
+ * @return number of slots used by resulting Huffman table
+ */
+ static int buildHuffmanTable(int[] tableGroup, int tableIdx, int rootBits, int[] codeLengths,
+ int codeLengthsSize) {
+ int tableOffset = tableGroup[tableIdx];
+ int key; // Reversed prefix code.
+ int[] sorted = new int[codeLengthsSize]; // Symbols sorted by code length.
+ // TODO: fill with zeroes?
+ int[] count = new int[MAX_LENGTH + 1]; // Number of codes of each length.
+ int[] offset = new int[MAX_LENGTH + 1]; // Offsets in sorted table for each length.
+ int symbol;
+
+ // Build histogram of code lengths.
+ for (symbol = 0; symbol < codeLengthsSize; symbol++) {
+ count[codeLengths[symbol]]++;
+ }
+
+ // Generate offsets into sorted symbol table by code length.
+ offset[1] = 0;
+ for (int len = 1; len < MAX_LENGTH; len++) {
+ offset[len + 1] = offset[len] + count[len];
+ }
+
+ // Sort symbols by length, by symbol order within each length.
+ for (symbol = 0; symbol < codeLengthsSize; symbol++) {
+ if (codeLengths[symbol] != 0) {
+ sorted[offset[codeLengths[symbol]]++] = symbol;
+ }
+ }
+
+ int tableBits = rootBits;
+ int tableSize = 1 << tableBits;
+ int totalSize = tableSize;
+
+ // Special case code with only one value.
+ if (offset[MAX_LENGTH] == 1) {
+ for (key = 0; key < totalSize; key++) {
+ tableGroup[tableOffset + key] = sorted[0];
+ }
+ return totalSize;
+ }
+
+ // Fill in root table.
+ key = 0;
+ symbol = 0;
+ for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
+ for (; count[len] > 0; count[len]--) {
+ replicateValue(tableGroup, tableOffset + key, step, tableSize,
+ len << 16 | sorted[symbol++]);
+ key = getNextKey(key, len);
+ }
+ }
+
+ // Fill in 2nd level tables and add pointers to root table.
+ int mask = totalSize - 1;
+ int low = -1;
+ int currentOffset = tableOffset;
+ for (int len = rootBits + 1, step = 2; len <= MAX_LENGTH; len++, step <<= 1) {
+ for (; count[len] > 0; count[len]--) {
+ if ((key & mask) != low) {
+ currentOffset += tableSize;
+ tableBits = nextTableBitSize(count, len, rootBits);
+ tableSize = 1 << tableBits;
+ totalSize += tableSize;
+ low = key & mask;
+ tableGroup[tableOffset + low] =
+ (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
+ }
+ replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize,
+ (len - rootBits) << 16 | sorted[symbol++]);
+ key = getNextKey(key, len);
+ }
+ }
+ return totalSize;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SetDictionaryTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SetDictionaryTest.java
new file mode 100644
index 000000000..f462c49eb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SetDictionaryTest.java
@@ -0,0 +1,76 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Dictionary}.
+ */
+@RunWith(JUnit4.class)
+public class SetDictionaryTest {
+
+ /** See {@link SynthTest} */
+ private static final byte[] BASE_DICT_WORD = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x02
+ };
+
+ /** See {@link SynthTest} */
+ private static final byte[] ONE_COMMAND = {
+ (byte) 0x1b, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x11, (byte) 0x86, (byte) 0x02
+ };
+
+ @Test
+ public void testSetDictionary() throws IOException {
+ byte[] buffer = new byte[16];
+ BrotliInputStream decoder;
+
+ // No dictionary set; still decoding should succeed, if no dictionary entries are used.
+ decoder = new BrotliInputStream(new ByteArrayInputStream(ONE_COMMAND));
+ assertEquals(3, decoder.read(buffer, 0, buffer.length));
+ assertEquals("aaa", new String(buffer, 0, 3, "US-ASCII"));
+ decoder.close();
+
+ // Decoding of dictionary item must fail.
+ decoder = new BrotliInputStream(new ByteArrayInputStream(BASE_DICT_WORD));
+ boolean decodingFailed = false;
+ try {
+ decoder.read(buffer, 0, buffer.length);
+ } catch (IOException ex) {
+ decodingFailed = true;
+ }
+ assertEquals(true, decodingFailed);
+ decoder.close();
+
+ // Load dictionary data.
+ FileChannel dictionaryChannel =
+ new FileInputStream(System.getProperty("RFC_DICTIONARY")).getChannel();
+ ByteBuffer dictionary = dictionaryChannel.map(FileChannel.MapMode.READ_ONLY, 0, 122784).load();
+ Dictionary.setData(dictionary);
+
+ // Retry decoding of dictionary item.
+ decoder = new BrotliInputStream(new ByteArrayInputStream(BASE_DICT_WORD));
+ assertEquals(4, decoder.read(buffer, 0, buffer.length));
+ assertEquals("time", new String(buffer, 0, 4, "US-ASCII"));
+ decoder.close();
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/State.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/State.java
new file mode 100644
index 000000000..54a5a2d91
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/State.java
@@ -0,0 +1,89 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.io.InputStream;
+
+final class State {
+ byte[] ringBuffer;
+ byte[] contextModes;
+ byte[] contextMap;
+ byte[] distContextMap;
+ byte[] distExtraBits;
+ byte[] output;
+ byte[] byteBuffer; // BitReader
+
+ short[] shortBuffer; // BitReader
+
+ int[] intBuffer; // BitReader
+ int[] rings;
+ int[] blockTrees;
+ int[] literalTreeGroup;
+ int[] commandTreeGroup;
+ int[] distanceTreeGroup;
+ int[] distOffset;
+
+ long accumulator64; // BitReader: pre-fetched bits.
+
+ int runningState; // Default value is 0 == Decode.UNINITIALIZED
+ int nextRunningState;
+ int accumulator32; // BitReader: pre-fetched bits.
+ int bitOffset; // BitReader: bit-reading position in accumulator.
+ int halfOffset; // BitReader: offset of next item in intBuffer/shortBuffer.
+ int tailBytes; // BitReader: number of bytes in unfinished half.
+ int endOfStreamReached; // BitReader: input stream is finished.
+ int metaBlockLength;
+ int inputEnd;
+ int isUncompressed;
+ int isMetadata;
+ int literalBlockLength;
+ int numLiteralBlockTypes;
+ int commandBlockLength;
+ int numCommandBlockTypes;
+ int distanceBlockLength;
+ int numDistanceBlockTypes;
+ int pos;
+ int maxDistance;
+ int distRbIdx;
+ int trivialLiteralContext;
+ int literalTreeIdx;
+ int commandTreeIdx;
+ int j;
+ int insertLength;
+ int contextMapSlice;
+ int distContextMapSlice;
+ int contextLookupOffset1;
+ int contextLookupOffset2;
+ int distanceCode;
+ int numDirectDistanceCodes;
+ int distancePostfixMask;
+ int distancePostfixBits;
+ int distance;
+ int copyLength;
+ int maxBackwardDistance;
+ int maxRingBufferSize;
+ int ringBufferSize;
+ int expectedTotalSize;
+ int outputOffset;
+ int outputLength;
+ int outputUsed;
+ int ringBufferBytesWritten;
+ int ringBufferBytesReady;
+ int isEager;
+ int isLargeWindow;
+
+ InputStream input; // BitReader
+
+ State() {
+ this.ringBuffer = new byte[0];
+ this.rings = new int[10];
+ this.rings[0] = 16;
+ this.rings[1] = 15;
+ this.rings[2] = 11;
+ this.rings[3] = 4;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SynthTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SynthTest.java
new file mode 100644
index 000000000..e269e6b03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/SynthTest.java
@@ -0,0 +1,2940 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Decode}.
+ */
+@RunWith(JUnit4.class)
+public class SynthTest {
+
+ static byte[] readUniBytes(String uniBytes) {
+ byte[] result = new byte[uniBytes.length()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = (byte) uniBytes.charAt(i);
+ }
+ return result;
+ }
+
+ private byte[] decompress(byte[] data) throws IOException {
+ byte[] buffer = new byte[65536];
+ ByteArrayInputStream input = new ByteArrayInputStream(data);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ BrotliInputStream brotliInput = new BrotliInputStream(input);
+ while (true) {
+ int len = brotliInput.read(buffer, 0, buffer.length);
+ if (len <= 0) {
+ break;
+ }
+ output.write(buffer, 0, len);
+ }
+ brotliInput.close();
+ return output.toByteArray();
+ }
+
+ private void checkSynth(byte[] compressed, boolean expectSuccess,
+ String expectedOutput) {
+ byte[] expected = readUniBytes(expectedOutput);
+ try {
+ byte[] actual = decompress(compressed);
+ if (!expectSuccess) {
+ fail("expected to fail decoding, but succeeded");
+ }
+ assertArrayEquals(expected, actual);
+ } catch (IOException ex) {
+ if (expectSuccess) {
+ fail("expected to succeed decoding, but failed");
+ }
+ }
+ }
+
+/* GENERATED CODE START */
+
+ @Test
+ public void testAllTransforms10() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0xfc, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x13, (byte) 0x7c, (byte) 0x84, (byte) 0x26, (byte) 0xf8, (byte) 0x04,
+ (byte) 0x10, (byte) 0x4c, (byte) 0xf0, (byte) 0x89, (byte) 0x38, (byte) 0x30, (byte) 0xc1,
+ (byte) 0x27, (byte) 0x4e, (byte) 0xc1, (byte) 0x04, (byte) 0x9f, (byte) 0x64, (byte) 0x06,
+ (byte) 0x26, (byte) 0xf8, (byte) 0x24, (byte) 0x3f, (byte) 0x34, (byte) 0xc1, (byte) 0x27,
+ (byte) 0x7d, (byte) 0x82, (byte) 0x09, (byte) 0x3e, (byte) 0xe9, (byte) 0x16, (byte) 0x4d,
+ (byte) 0xf0, (byte) 0xc9, (byte) 0xd2, (byte) 0xc0, (byte) 0x04, (byte) 0x9f, (byte) 0x0c,
+ (byte) 0x8f, (byte) 0x4c, (byte) 0xf0, (byte) 0xc9, (byte) 0x06, (byte) 0xd1, (byte) 0x04,
+ (byte) 0x9f, (byte) 0x6c, (byte) 0x92, (byte) 0x4d, (byte) 0xf0, (byte) 0xc9, (byte) 0x39,
+ (byte) 0xc1, (byte) 0x04, (byte) 0x9f, (byte) 0xdc, (byte) 0x94, (byte) 0x4c, (byte) 0xf0,
+ (byte) 0xc9, (byte) 0x69, (byte) 0xd1, (byte) 0x04, (byte) 0x9f, (byte) 0x3c, (byte) 0x98,
+ (byte) 0x4d, (byte) 0xf0, (byte) 0x29, (byte) 0x9c, (byte) 0x81, (byte) 0x09, (byte) 0x3e,
+ (byte) 0x45, (byte) 0x37, (byte) 0x31, (byte) 0xc1, (byte) 0xa7, (byte) 0x60, (byte) 0x47,
+ (byte) 0x26, (byte) 0xf8, (byte) 0x14, (byte) 0xfa, (byte) 0xcc, (byte) 0x04, (byte) 0x9f,
+ (byte) 0xc2, (byte) 0x20, (byte) 0x9a, (byte) 0xe0, (byte) 0x53, (byte) 0x48, (byte) 0x54,
+ (byte) 0x13, (byte) 0x7c, (byte) 0x8a, (byte) 0x8f, (byte) 0x6c, (byte) 0x82, (byte) 0x4f,
+ (byte) 0xb1, (byte) 0xd2, (byte) 0x4d, (byte) 0xf0, (byte) 0x29, (byte) 0x67, (byte) 0x82,
+ (byte) 0x09, (byte) 0x3e, (byte) 0xe5, (byte) 0x4f, (byte) 0x31, (byte) 0xc1, (byte) 0xa7,
+ (byte) 0x7c, (byte) 0x4a, (byte) 0x26, (byte) 0xf8, (byte) 0x94, (byte) 0x57, (byte) 0xcd,
+ (byte) 0x04, (byte) 0x9f, (byte) 0x12, (byte) 0x2c, (byte) 0x9a, (byte) 0xe0, (byte) 0x53,
+ (byte) 0xba, (byte) 0x55, (byte) 0x13, (byte) 0x7c, (byte) 0xca, (byte) 0xbf, (byte) 0x6c,
+ (byte) 0x82, (byte) 0x4f, (byte) 0xb9, (byte) 0xd8, (byte) 0x4d, (byte) 0xf0, (byte) 0xa9,
+ (byte) 0x30, (byte) 0x03, (byte) 0x13, (byte) 0x7c, (byte) 0x2a, (byte) 0xd2, (byte) 0xc2,
+ (byte) 0x04, (byte) 0x9f, (byte) 0x4a, (byte) 0x36, (byte) 0x31, (byte) 0xc1, (byte) 0xa7,
+ (byte) 0xca, (byte) 0x6d, (byte) 0x4c, (byte) 0xf0, (byte) 0xa9, (byte) 0x94, (byte) 0x23,
+ (byte) 0x13, (byte) 0x7c, (byte) 0x2a, (byte) 0xeb, (byte) 0xca, (byte) 0x04, (byte) 0x9f,
+ (byte) 0xea, (byte) 0x3c, (byte) 0x33, (byte) 0xc1, (byte) 0xa7, (byte) 0xb2, (byte) 0xef,
+ (byte) 0x4c, (byte) 0xf0, (byte) 0xa9, (byte) 0xf8, (byte) 0x43, (byte) 0x13, (byte) 0x7c,
+ (byte) 0xaa, (byte) 0x00, (byte) 0xd3, (byte) 0x04, (byte) 0x9f, (byte) 0x2a, (byte) 0x42,
+ (byte) 0x35, (byte) 0xc1, (byte) 0xa7, (byte) 0xc2, (byte) 0x70, (byte) 0x4d, (byte) 0xf0,
+ (byte) 0xa9, (byte) 0x52, (byte) 0x64, (byte) 0x13, (byte) 0x7c, (byte) 0x2a, (byte) 0x1a,
+ (byte) 0xdb, (byte) 0x04, (byte) 0x9f, (byte) 0x6a, (byte) 0x48, (byte) 0x37, (byte) 0xc1,
+ (byte) 0xa7, (byte) 0x92, (byte) 0xf2, (byte) 0x4d, (byte) 0xf0, (byte) 0xa9, (byte) 0xc3,
+ (byte) 0x04, (byte) 0x13, (byte) 0x7c, (byte) 0xea, (byte) 0x32, (byte) 0xc3, (byte) 0x04,
+ (byte) 0x9f, (byte) 0x7a, (byte) 0x4e, (byte) 0x31, (byte) 0xc1, (byte) 0xa7, (byte) 0x06,
+ (byte) 0x74, (byte) 0x4c, (byte) 0xf0, (byte) 0xa9, (byte) 0x19, (byte) 0x25, (byte) 0x13,
+ (byte) 0x7c, (byte) 0x6a, (byte) 0x4d, (byte) 0xcb, (byte) 0x04, (byte) 0x9f, (byte) 0x1a,
+ (byte) 0x55, (byte) 0x33, (byte) 0xc1, (byte) 0xa7, (byte) 0x56, (byte) 0xf5, (byte) 0x4c,
+ (byte) 0xf0, (byte) 0xa9, (byte) 0x5d, (byte) 0x45, (byte) 0x13, (byte) 0x7c, (byte) 0xea,
+ (byte) 0x59, (byte) 0xd3, (byte) 0x04, (byte) 0x9f, (byte) 0xfa, (byte) 0x57, (byte) 0x35,
+ (byte) 0xc1, (byte) 0xa7, (byte) 0x66, (byte) 0x76, (byte) 0x4d, (byte) 0xf0, (byte) 0xa9,
+ (byte) 0x9f, (byte) 0x65, (byte) 0x13, (byte) 0x7c, (byte) 0x6a, (byte) 0x6f, (byte) 0xdb,
+ (byte) 0x04, (byte) 0x9f, (byte) 0x9a, (byte) 0x5d, (byte) 0x37, (byte) 0xc1, (byte) 0xa7,
+ (byte) 0x06, (byte) 0xf8, (byte) 0x4d, (byte) 0xf0, (byte) 0x69, (byte) 0x0c, (byte) 0x06,
+ (byte) 0x26, (byte) 0xf8, (byte) 0x34, (byte) 0x08, (byte) 0x07, (byte) 0x13, (byte) 0x7c,
+ (byte) 0x1a, (byte) 0x8b, (byte) 0x85, (byte) 0x09, (byte) 0x3e, (byte) 0x8d, (byte) 0xc8,
+ (byte) 0xc3, (byte) 0x04, (byte) 0x9f, (byte) 0xe6, (byte) 0x65, (byte) 0x62, (byte) 0x82,
+ (byte) 0x4f, (byte) 0xb3, (byte) 0x73, (byte) 0x31, (byte) 0xc1, (byte) 0xa7, (byte) 0x41,
+ (byte) 0xda, (byte) 0x98, (byte) 0xe0, (byte) 0xd3, (byte) 0x54, (byte) 0x7d, (byte) 0x4c,
+ (byte) 0xf0, (byte) 0x69, (byte) 0xc4, (byte) 0x46, (byte) 0x26, (byte) 0xf8, (byte) 0x34,
+ (byte) 0x72, (byte) 0x27, (byte) 0x13, (byte) 0x7c, (byte) 0x1a, (byte) 0xc5, (byte) 0x95,
+ (byte) 0x09, (byte) 0x3e, (byte) 0x8d, (byte) 0xe5, (byte) 0xcb, (byte) 0x04, (byte) 0x9f,
+ (byte) 0x06, (byte) 0x75, (byte) 0x66, (byte) 0x82, (byte) 0x4f, (byte) 0x43, (byte) 0x7b,
+ (byte) 0x33, (byte) 0xc1, (byte) 0xa7, (byte) 0x09, (byte) 0xde, (byte) 0x99, (byte) 0xe0,
+ (byte) 0xd3, (byte) 0x34, (byte) 0xff, (byte) 0x4c, (byte) 0xf0, (byte) 0x69, (byte) 0xb2,
+ (byte) 0x87, (byte) 0x26, (byte) 0xf8, (byte) 0x34, (byte) 0xe9, (byte) 0x47, (byte) 0x13,
+ (byte) 0x7c, (byte) 0x9a, (byte) 0xfb, (byte) 0xa5, (byte) 0x09, (byte) 0x3e, (byte) 0x4d,
+ (byte) 0x01, (byte) 0xd4, (byte) 0x04, (byte) 0x9f, (byte) 0x46, (byte) 0x82, (byte) 0x6a,
+ (byte) 0x82, (byte) 0x4f, (byte) 0x03, (byte) 0x82, (byte) 0x35, (byte) 0xc1, (byte) 0xa7,
+ (byte) 0x61, (byte) 0xe1, (byte) 0x9a, (byte) 0xe0, (byte) 0xd3, (byte) 0xe4, (byte) 0x80,
+ (byte) 0x4d, (byte) 0xf0, (byte) 0x69, (byte) 0x8a, (byte) 0xc8, (byte) 0x26, (byte) 0xf8,
+ (byte) 0x34, (byte) 0x52, (byte) 0x68, (byte) 0x13, (byte) 0x7c, (byte) 0x9a, (byte) 0x2f,
+ (byte) 0xb6, (byte) 0x09, (byte) 0x3e, (byte) 0x8d, (byte) 0x1b, (byte) 0xdc, (byte) 0x04,
+ (byte) 0x9f, (byte) 0x86, (byte) 0x8f, (byte) 0x6e, (byte) 0x82, (byte) 0x4f, (byte) 0xb3,
+ (byte) 0x88, (byte) 0x37, (byte) 0xc1, (byte) 0xa7, (byte) 0xd9, (byte) 0xe4, (byte) 0x9b,
+ (byte) 0xe0, (byte) 0xd3, (byte) 0x9e, (byte) 0x02, (byte) 0x4c, (byte) 0xf0, (byte) 0x69,
+ (byte) 0x6d, (byte) 0x09, (byte) 0x26, (byte) 0xf8, (byte) 0xb4, (byte) 0xc3, (byte) 0x08,
+ (byte) 0x13, (byte) 0x7c, (byte) 0x5a, (byte) 0x68, (byte) 0x86, (byte) 0x09, (byte) 0x3e,
+ (byte) 0xad, (byte) 0x37, (byte) 0xc4, (byte) 0x04, (byte) 0x9f, (byte) 0x56, (byte) 0x9d,
+ (byte) 0x62, (byte) 0x82, (byte) 0x4f, (byte) 0x9b, (byte) 0x8f, (byte) 0x31, (byte) 0xc1,
+ (byte) 0xa7, (byte) 0x2d, (byte) 0xe8, (byte) 0x98, (byte) 0xe0, (byte) 0xd3, (byte) 0x4a,
+ (byte) 0x84, (byte) 0x4c, (byte) 0xf0, (byte) 0x69, (byte) 0x3f, (byte) 0x4a, (byte) 0x26,
+ (byte) 0xf8, (byte) 0xb4, (byte) 0x2c, (byte) 0x29, (byte) 0x13, (byte) 0x7c, (byte) 0xda,
+ (byte) 0x9c, (byte) 0x96, (byte) 0x09, (byte) 0x3e, (byte) 0x2d, (byte) 0x52, (byte) 0xcc,
+ (byte) 0x04, (byte) 0x9f, (byte) 0xb6, (byte) 0xaa, (byte) 0x66, (byte) 0x82, (byte) 0x4f,
+ (byte) 0x2b, (byte) 0x96, (byte) 0x33, (byte) 0xc1, (byte) 0xa7, (byte) 0x7d, (byte) 0xeb,
+ (byte) 0x99, (byte) 0xe0, (byte) 0xd3, (byte) 0xf6, (byte) 0x05, (byte) 0x4d, (byte) 0xf0,
+ (byte) 0x69, (byte) 0x17, (byte) 0x8b, (byte) 0x26, (byte) 0xf8, (byte) 0xb4, (byte) 0x97,
+ (byte) 0x49, (byte) 0x13, (byte) 0x7c, (byte) 0xda, (byte) 0xd1, (byte) 0xa6, (byte) 0x09,
+ (byte) 0x3e, (byte) 0x2d, (byte) 0x6c, (byte) 0xd4, (byte) 0x04, (byte) 0x9f, (byte) 0xb6,
+ (byte) 0xb7, (byte) 0x6a, (byte) 0x82, (byte) 0x4f, (byte) 0xab, (byte) 0x9c, (byte) 0x35,
+ (byte) 0xc1, (byte) 0xa7, (byte) 0xc5, (byte) 0xee, (byte) 0x9a, (byte) 0xe0, (byte) 0xd3,
+ (byte) 0x9a, (byte) 0x87, (byte) 0x4d, (byte) 0xf0, (byte) 0x69, (byte) 0xe9, (byte) 0xcb
+ };
+ checkSynth(
+ /*
+ * // The stream consists of word "time" with all possible transforms.
+ * main_header
+ * metablock_header_easy: 1533, 1
+ * command_easy: 10, "|", 2 // = 0 << 10 + 1 + 1
+ * command_easy: 10, "|", 1037 // = 1 << 10 + 1 + 12
+ * command_easy: 10, "|", 2073 // = 2 << 10 + 1 + 24
+ * command_easy: 10, "|", 3110 // = 3 << 10 + 1 + 37
+ * command_easy: 10, "|", 4144 // = 4 << 10 + 1 + 47
+ * command_easy: 10, "|", 5180 // = 5 << 10 + 1 + 59
+ * command_easy: 10, "|", 6220 // = 6 << 10 + 1 + 75
+ * command_easy: 10, "|", 7256 // = 7 << 10 + 1 + 87
+ * command_easy: 10, "|", 8294 // = 8 << 10 + 1 + 101
+ * command_easy: 10, "|", 9333 // = 9 << 10 + 1 + 116
+ * command_easy: 10, "|", 10368 // = 10 << 10 + 1 + 127
+ * command_easy: 10, "|", 11408 // = 11 << 10 + 1 + 143
+ * command_easy: 10, "|", 12441 // = 12 << 10 + 1 + 152
+ * command_easy: 10, "|", 13475 // = 13 << 10 + 1 + 162
+ * command_easy: 10, "|", 14513 // = 14 << 10 + 1 + 176
+ * command_easy: 10, "|", 15550 // = 15 << 10 + 1 + 189
+ * command_easy: 10, "|", 16587 // = 16 << 10 + 1 + 202
+ * command_easy: 10, "|", 17626 // = 17 << 10 + 1 + 217
+ * command_easy: 10, "|", 18665 // = 18 << 10 + 1 + 232
+ * command_easy: 10, "|", 19703 // = 19 << 10 + 1 + 246
+ * command_easy: 10, "|", 20739 // = 20 << 10 + 1 + 258
+ * command_easy: 10, "|", 21775 // = 21 << 10 + 1 + 270
+ * command_easy: 10, "|", 22812 // = 22 << 10 + 1 + 283
+ * command_easy: 10, "|", 23848 // = 23 << 10 + 1 + 295
+ * command_easy: 10, "|", 24880 // = 24 << 10 + 1 + 303
+ * command_easy: 10, "|", 25916 // = 25 << 10 + 1 + 315
+ * command_easy: 10, "|", 26956 // = 26 << 10 + 1 + 331
+ * command_easy: 10, "|", 27988 // = 27 << 10 + 1 + 339
+ * command_easy: 10, "|", 29021 // = 28 << 10 + 1 + 348
+ * command_easy: 10, "|", 30059 // = 29 << 10 + 1 + 362
+ * command_easy: 10, "|", 31100 // = 30 << 10 + 1 + 379
+ * command_easy: 10, "|", 32136 // = 31 << 10 + 1 + 391
+ * command_easy: 10, "|", 33173 // = 32 << 10 + 1 + 404
+ * command_easy: 10, "|", 34209 // = 33 << 10 + 1 + 416
+ * command_easy: 10, "|", 35247 // = 34 << 10 + 1 + 430
+ * command_easy: 10, "|", 36278 // = 35 << 10 + 1 + 437
+ * command_easy: 10, "|", 37319 // = 36 << 10 + 1 + 454
+ * command_easy: 10, "|", 38355 // = 37 << 10 + 1 + 466
+ * command_easy: 10, "|", 39396 // = 38 << 10 + 1 + 483
+ * command_easy: 10, "|", 40435 // = 39 << 10 + 1 + 498
+ * command_easy: 10, "|", 41465 // = 40 << 10 + 1 + 504
+ * command_easy: 10, "|", 42494 // = 41 << 10 + 1 + 509
+ * command_easy: 10, "|", 43534 // = 42 << 10 + 1 + 525
+ * command_easy: 10, "|", 44565 // = 43 << 10 + 1 + 532
+ * command_easy: 10, "|", 45606 // = 44 << 10 + 1 + 549
+ * command_easy: 10, "|", 46641 // = 45 << 10 + 1 + 560
+ * command_easy: 10, "|", 47680 // = 46 << 10 + 1 + 575
+ * command_easy: 10, "|", 48719 // = 47 << 10 + 1 + 590
+ * command_easy: 10, "|", 49758 // = 48 << 10 + 1 + 605
+ * command_easy: 10, "|", 50786 // = 49 << 10 + 1 + 609
+ * command_easy: 10, "|", 51824 // = 50 << 10 + 1 + 623
+ * command_easy: 10, "|", 52861 // = 51 << 10 + 1 + 636
+ * command_easy: 10, "|", 53897 // = 52 << 10 + 1 + 648
+ * command_easy: 10, "|", 54935 // = 53 << 10 + 1 + 662
+ * command_easy: 10, "|", 55973 // = 54 << 10 + 1 + 676
+ * command_easy: 10, "|", 56999 // = 55 << 10 + 1 + 678
+ * command_easy: 10, "|", 58027 // = 56 << 10 + 1 + 682
+ * command_easy: 10, "|", 59056 // = 57 << 10 + 1 + 687
+ * command_easy: 10, "|", 60092 // = 58 << 10 + 1 + 699
+ * command_easy: 10, "|", 61129 // = 59 << 10 + 1 + 712
+ * command_easy: 10, "|", 62156 // = 60 << 10 + 1 + 715
+ * command_easy: 10, "|", 63195 // = 61 << 10 + 1 + 730
+ * command_easy: 10, "|", 64233 // = 62 << 10 + 1 + 744
+ * command_easy: 10, "|", 65277 // = 63 << 10 + 1 + 764
+ * command_easy: 10, "|", 66307 // = 64 << 10 + 1 + 770
+ * command_easy: 10, "|", 67333 // = 65 << 10 + 1 + 772
+ * command_easy: 10, "|", 68371 // = 66 << 10 + 1 + 786
+ * command_easy: 10, "|", 69407 // = 67 << 10 + 1 + 798
+ * command_easy: 10, "|", 70444 // = 68 << 10 + 1 + 811
+ * command_easy: 10, "|", 71480 // = 69 << 10 + 1 + 823
+ * command_easy: 10, "|", 72517 // = 70 << 10 + 1 + 836
+ * command_easy: 10, "|", 73554 // = 71 << 10 + 1 + 849
+ * command_easy: 10, "|", 74591 // = 72 << 10 + 1 + 862
+ * command_easy: 10, "|", 75631 // = 73 << 10 + 1 + 878
+ * command_easy: 10, "|", 76679 // = 74 << 10 + 1 + 902
+ * command_easy: 10, "|", 77715 // = 75 << 10 + 1 + 914
+ * command_easy: 10, "|", 78757 // = 76 << 10 + 1 + 932
+ * command_easy: 10, "|", 79793 // = 77 << 10 + 1 + 944
+ * command_easy: 10, "|", 80830 // = 78 << 10 + 1 + 957
+ * command_easy: 10, "|", 81866 // = 79 << 10 + 1 + 969
+ * command_easy: 10, "|", 82902 // = 80 << 10 + 1 + 981
+ * command_easy: 10, "|", 83942 // = 81 << 10 + 1 + 997
+ * command_easy: 10, "|", 84980 // = 82 << 10 + 1 + 1011
+ * command_easy: 10, "|", 86018 // = 83 << 10 + 1 + 1025
+ * command_easy: 10, "|", 87055 // = 84 << 10 + 1 + 1038
+ * command_easy: 10, "|", 88093 // = 85 << 10 + 1 + 1052
+ * command_easy: 10, "|", 89129 // = 86 << 10 + 1 + 1064
+ * command_easy: 10, "|", 90166 // = 87 << 10 + 1 + 1077
+ * command_easy: 10, "|", 91202 // = 88 << 10 + 1 + 1089
+ * command_easy: 10, "|", 92239 // = 89 << 10 + 1 + 1102
+ * command_easy: 10, "|", 93276 // = 90 << 10 + 1 + 1115
+ * command_easy: 10, "|", 94315 // = 91 << 10 + 1 + 1130
+ * command_easy: 10, "|", 95353 // = 92 << 10 + 1 + 1144
+ * command_easy: 10, "|", 96392 // = 93 << 10 + 1 + 1159
+ * command_easy: 10, "|", 97432 // = 94 << 10 + 1 + 1175
+ * command_easy: 10, "|", 98468 // = 95 << 10 + 1 + 1187
+ * command_easy: 10, "|", 99507 // = 96 << 10 + 1 + 1202
+ * command_easy: 10, "|", 100544 // = 97 << 10 + 1 + 1215
+ * command_easy: 10, "|", 101581 // = 98 << 10 + 1 + 1228
+ * command_easy: 10, "|", 102619 // = 99 << 10 + 1 + 1242
+ * command_easy: 10, "|", 103655 // = 100 << 10 + 1 + 1254
+ * command_easy: 10, "|", 104694 // = 101 << 10 + 1 + 1269
+ * command_easy: 10, "|", 105730 // = 102 << 10 + 1 + 1281
+ * command_easy: 10, "|", 106767 // = 103 << 10 + 1 + 1294
+ * command_easy: 10, "|", 107804 // = 104 << 10 + 1 + 1307
+ * command_easy: 10, "|", 108841 // = 105 << 10 + 1 + 1320
+ * command_easy: 10, "|", 109878 // = 106 << 10 + 1 + 1333
+ * command_easy: 10, "|", 110917 // = 107 << 10 + 1 + 1348
+ * command_easy: 10, "|", 111954 // = 108 << 10 + 1 + 1361
+ * command_easy: 10, "|", 112991 // = 109 << 10 + 1 + 1374
+ * command_easy: 10, "|", 114028 // = 110 << 10 + 1 + 1387
+ * command_easy: 10, "|", 115066 // = 111 << 10 + 1 + 1401
+ * command_easy: 10, "|", 116104 // = 112 << 10 + 1 + 1415
+ * command_easy: 10, "|", 117140 // = 113 << 10 + 1 + 1427
+ * command_easy: 10, "|", 118176 // = 114 << 10 + 1 + 1439
+ * command_easy: 10, "|", 119213 // = 115 << 10 + 1 + 1452
+ * command_easy: 10, "|", 120250 // = 116 << 10 + 1 + 1465
+ * command_easy: 10, "|", 121287 // = 117 << 10 + 1 + 1478
+ * command_easy: 10, "|", 122325 // = 118 << 10 + 1 + 1492
+ * command_easy: 10, "|", 123363 // = 119 << 10 + 1 + 1506
+ * command_easy: 10, "|", 124401 // = 120 << 10 + 1 + 1520
+ */
+ compressed,
+ true,
+ "|categories|categories | categories |ategories|Categories |categories the | categories|s cat"
+ + "egories |categories of |Categories|categories and |tegories|categorie|, categories |catego"
+ + "ries, | Categories |categories in |categories to |e categories |categories\"|categories.|c"
+ + "ategories\">|categories\n|categor|categories]|categories for |egories|categori|categories "
+ + "a |categories that | Categories|categories. |.categories| categories, |gories|categories w"
+ + "ith |categories'|categories from |categories by |ories|ries| the categories|catego|categor"
+ + "ies. The |CATEGORIES|categories on |categories as |categories is |cat|categorieing |catego"
+ + "ries\n\t|categories:| categories. |categoriesed |s|ies|cate|categories(|Categories, |ca|ca"
+ + "tegories at |categoriesly | the categories of |categ|c| Categories, |Categories\"|.categor"
+ + "ies(|CATEGORIES |Categories\">|categories=\"| categories.|.com/categories| the categories "
+ + "of the |Categories'|categories. This |categories,|.categories |Categories(|Categories.|cat"
+ + "egories not | categories=\"|categorieser | CATEGORIES |categoriesal | CATEGORIES|categorie"
+ + "s='|CATEGORIES\"|Categories. | categories(|categoriesful | Categories. |categoriesive |cat"
+ + "egoriesless |CATEGORIES'|categoriesest | Categories.|CATEGORIES\">| categories='|Categorie"
+ + "s,|categoriesize |CATEGORIES.|\302\240categories| categories,|Categories=\"|CATEGORIES="
+ + "\"|categoriesous |CATEGORIES, |Categories='| Categories,| CATEGORIES=\"| CATEGORIES, |CATE"
+ + "GORIES,|CATEGORIES(|CATEGORIES. | CATEGORIES.|CATEGORIES='| CATEGORIES. | Categories=\"| C"
+ + "ATEGORIES='| Categories='"
+ );
+ }
+
+ @Test
+ public void testAllTransforms4() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x40, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x51, (byte) 0x3e, (byte) 0x42, (byte) 0x51, (byte) 0x3e, (byte) 0x81,
+ (byte) 0x02, (byte) 0x51, (byte) 0x3e, (byte) 0x11, (byte) 0x04, (byte) 0xa2, (byte) 0x7c,
+ (byte) 0xe2, (byte) 0x0b, (byte) 0x44, (byte) 0xf9, (byte) 0x24, (byte) 0x1b, (byte) 0x10,
+ (byte) 0xe5, (byte) 0x93, (byte) 0x84, (byte) 0x50, (byte) 0x94, (byte) 0x4f, (byte) 0xba,
+ (byte) 0x02, (byte) 0x51, (byte) 0x3e, (byte) 0x69, (byte) 0x0c, (byte) 0x45, (byte) 0xf9,
+ (byte) 0x64, (byte) 0x39, (byte) 0x20, (byte) 0xca, (byte) 0x27, (byte) 0x13, (byte) 0x22,
+ (byte) 0x51, (byte) 0x3e, (byte) 0xd9, (byte) 0x11, (byte) 0x8a, (byte) 0xf2, (byte) 0xc9,
+ (byte) 0xa2, (byte) 0x58, (byte) 0x94, (byte) 0x4f, (byte) 0x4e, (byte) 0x05, (byte) 0xa2,
+ (byte) 0x7c, (byte) 0x72, (byte) 0x2c, (byte) 0x12, (byte) 0xe5, (byte) 0x93, (byte) 0x83,
+ (byte) 0xa1, (byte) 0x28, (byte) 0x9f, (byte) 0xfc, (byte) 0x8c, (byte) 0x45, (byte) 0xf9,
+ (byte) 0x14, (byte) 0x6e, (byte) 0x40, (byte) 0x94, (byte) 0x4f, (byte) 0x71, (byte) 0x47,
+ (byte) 0x44, (byte) 0xf9, (byte) 0x14, (byte) 0x80, (byte) 0x48, (byte) 0x94, (byte) 0x4f,
+ (byte) 0x81, (byte) 0xc8, (byte) 0x44, (byte) 0xf9, (byte) 0x14, (byte) 0x8e, (byte) 0x50,
+ (byte) 0x94, (byte) 0x4f, (byte) 0x41, (byte) 0x49, (byte) 0x45, (byte) 0xf9, (byte) 0x14,
+ (byte) 0x9b, (byte) 0x58, (byte) 0x94, (byte) 0x4f, (byte) 0x11, (byte) 0xca, (byte) 0x45,
+ (byte) 0xf9, (byte) 0x94, (byte) 0xa3, (byte) 0x40, (byte) 0x94, (byte) 0x4f, (byte) 0x99,
+ (byte) 0x4a, (byte) 0x44, (byte) 0xf9, (byte) 0x94, (byte) 0xb3, (byte) 0x48, (byte) 0x94,
+ (byte) 0x4f, (byte) 0x59, (byte) 0xcb, (byte) 0x44, (byte) 0xf9, (byte) 0x94, (byte) 0xb8,
+ (byte) 0x50, (byte) 0x94, (byte) 0x4f, (byte) 0x09, (byte) 0x4c, (byte) 0x45, (byte) 0xf9,
+ (byte) 0x94, (byte) 0xcb, (byte) 0x58, (byte) 0x94, (byte) 0x4f, (byte) 0x19, (byte) 0xcd,
+ (byte) 0x45, (byte) 0xf9, (byte) 0x54, (byte) 0xd8, (byte) 0x80, (byte) 0x28, (byte) 0x9f,
+ (byte) 0xca, (byte) 0x9b, (byte) 0x10, (byte) 0xe5, (byte) 0x53, (byte) 0x99, (byte) 0x23,
+ (byte) 0xa2, (byte) 0x7c, (byte) 0xaa, (byte) 0x73, (byte) 0x46, (byte) 0x94, (byte) 0x4f,
+ (byte) 0x25, (byte) 0x0f, (byte) 0x89, (byte) 0xf2, (byte) 0xa9, (byte) 0xf0, (byte) 0x29,
+ (byte) 0x51, (byte) 0x3e, (byte) 0xd5, (byte) 0x40, (byte) 0x26, (byte) 0xca, (byte) 0xa7,
+ (byte) 0x62, (byte) 0xe8, (byte) 0x44, (byte) 0xf9, (byte) 0x54, (byte) 0x0d, (byte) 0xa1,
+ (byte) 0x28, (byte) 0x9f, (byte) 0xca, (byte) 0xa1, (byte) 0x14, (byte) 0xe5, (byte) 0x53,
+ (byte) 0x61, (byte) 0xa4, (byte) 0xa2, (byte) 0x7c, (byte) 0xaa, (byte) 0x8c, (byte) 0x56,
+ (byte) 0x94, (byte) 0x4f, (byte) 0x45, (byte) 0x12, (byte) 0x8b, (byte) 0xf2, (byte) 0xa9,
+ (byte) 0x52, (byte) 0x6a, (byte) 0x51, (byte) 0x3e, (byte) 0x95, (byte) 0x4c, (byte) 0x2e,
+ (byte) 0xca, (byte) 0xa7, (byte) 0xda, (byte) 0xe9, (byte) 0x45, (byte) 0xf9, (byte) 0xd4,
+ (byte) 0x44, (byte) 0x81, (byte) 0x28, (byte) 0x9f, (byte) 0xba, (byte) 0xa8, (byte) 0x10,
+ (byte) 0xe5, (byte) 0x53, (byte) 0x37, (byte) 0x25, (byte) 0xa2, (byte) 0x7c, (byte) 0x6a,
+ (byte) 0xaa, (byte) 0x46, (byte) 0x94, (byte) 0x4f, (byte) 0xad, (byte) 0x15, (byte) 0x89,
+ (byte) 0xf2, (byte) 0xa9, (byte) 0xc5, (byte) 0x2a, (byte) 0x51, (byte) 0x3e, (byte) 0xb5,
+ (byte) 0x5a, (byte) 0x26, (byte) 0xca, (byte) 0xa7, (byte) 0x5e, (byte) 0xeb, (byte) 0x44,
+ (byte) 0xf9, (byte) 0xd4, (byte) 0x6c, (byte) 0xa1, (byte) 0x28, (byte) 0x9f, (byte) 0xba,
+ (byte) 0xad, (byte) 0x14, (byte) 0xe5, (byte) 0x53, (byte) 0xcf, (byte) 0xa5, (byte) 0xa2,
+ (byte) 0x7c, (byte) 0x6a, (byte) 0xbd, (byte) 0x56, (byte) 0x94, (byte) 0x4f, (byte) 0xbd,
+ (byte) 0x17, (byte) 0x8b, (byte) 0xf2, (byte) 0xa9, (byte) 0x09, (byte) 0x6b, (byte) 0x51,
+ (byte) 0x3e, (byte) 0x35, (byte) 0x63, (byte) 0x2e, (byte) 0xca, (byte) 0xa7, (byte) 0xd6,
+ (byte) 0xec, (byte) 0x45, (byte) 0xf9, (byte) 0x34, (byte) 0x9b, (byte) 0x01, (byte) 0x51,
+ (byte) 0x3e, (byte) 0x0d, (byte) 0x67, (byte) 0x41, (byte) 0x94, (byte) 0x4f, (byte) 0x43,
+ (byte) 0x9a, (byte) 0x10, (byte) 0xe5, (byte) 0xd3, (byte) 0xa8, (byte) 0x36, (byte) 0x44,
+ (byte) 0xf9, (byte) 0x34, (byte) 0xb1, (byte) 0x11, (byte) 0x51, (byte) 0x3e, (byte) 0xcd,
+ (byte) 0x6d, (byte) 0x45, (byte) 0x94, (byte) 0x4f, (byte) 0xe3, (byte) 0x9b, (byte) 0x11,
+ (byte) 0xe5, (byte) 0xd3, (byte) 0x14, (byte) 0x77, (byte) 0x44, (byte) 0xf9, (byte) 0x34,
+ (byte) 0xcc, (byte) 0x21, (byte) 0x51, (byte) 0x3e, (byte) 0x8d, (byte) 0x75, (byte) 0x49,
+ (byte) 0x94, (byte) 0x4f, (byte) 0x83, (byte) 0x9e, (byte) 0x12, (byte) 0xe5, (byte) 0xd3,
+ (byte) 0xb8, (byte) 0xb7, (byte) 0x44, (byte) 0xf9, (byte) 0x34, (byte) 0xfa, (byte) 0x31,
+ (byte) 0x51, (byte) 0x3e, (byte) 0x0d, (byte) 0x80, (byte) 0x4d, (byte) 0x94, (byte) 0x4f,
+ (byte) 0x73, (byte) 0xa0, (byte) 0x13, (byte) 0xe5, (byte) 0xd3, (byte) 0x34, (byte) 0xf8,
+ (byte) 0x44, (byte) 0xf9, (byte) 0x34, (byte) 0x13, (byte) 0x42, (byte) 0x51, (byte) 0x3e,
+ (byte) 0x4d, (byte) 0x87, (byte) 0x51, (byte) 0x94, (byte) 0x4f, (byte) 0x53, (byte) 0xa2,
+ (byte) 0x14, (byte) 0xe5, (byte) 0xd3, (byte) 0xb4, (byte) 0x38, (byte) 0x45, (byte) 0xf9,
+ (byte) 0x34, (byte) 0x34, (byte) 0x52, (byte) 0x51, (byte) 0x3e, (byte) 0x0d, (byte) 0x8f,
+ (byte) 0x55, (byte) 0x94, (byte) 0x4f, (byte) 0x23, (byte) 0xa4, (byte) 0x15, (byte) 0xe5,
+ (byte) 0xd3, (byte) 0x24, (byte) 0x79, (byte) 0x45, (byte) 0xf9, (byte) 0x34, (byte) 0x4f,
+ (byte) 0x62, (byte) 0x51, (byte) 0x3e, (byte) 0x8d, (byte) 0x95, (byte) 0x59, (byte) 0x94,
+ (byte) 0x4f, (byte) 0xd3, (byte) 0xa5, (byte) 0x16, (byte) 0xe5, (byte) 0xd3, (byte) 0x98,
+ (byte) 0xb9, (byte) 0x45, (byte) 0xf9, (byte) 0x34, (byte) 0x6e, (byte) 0x72, (byte) 0x51,
+ (byte) 0x3e, (byte) 0xcd, (byte) 0x9d, (byte) 0x5d, (byte) 0x94, (byte) 0x4f, (byte) 0x13,
+ (byte) 0xa8, (byte) 0x17, (byte) 0xe5, (byte) 0xd3, (byte) 0x1c, (byte) 0xfa, (byte) 0x45,
+ (byte) 0xf9, (byte) 0xb4, (byte) 0x90, (byte) 0x02, (byte) 0x51, (byte) 0x3e, (byte) 0xed,
+ (byte) 0xa5, (byte) 0x41, (byte) 0x94, (byte) 0x4f, (byte) 0xeb, (byte) 0xa9, (byte) 0x10,
+ (byte) 0xe5, (byte) 0xd3, (byte) 0x9a, (byte) 0x3a, (byte) 0x44, (byte) 0xf9, (byte) 0xb4,
+ (byte) 0xac, (byte) 0x12, (byte) 0x51, (byte) 0x3e, (byte) 0x6d, (byte) 0xad, (byte) 0x45,
+ (byte) 0x94, (byte) 0x4f, (byte) 0xbb, (byte) 0xab, (byte) 0x11, (byte) 0xe5, (byte) 0xd3,
+ (byte) 0x0a, (byte) 0x7b, (byte) 0x44, (byte) 0xf9, (byte) 0xb4, (byte) 0xc9, (byte) 0x22,
+ (byte) 0x51, (byte) 0x3e, (byte) 0x2d, (byte) 0xb4, (byte) 0x49, (byte) 0x94, (byte) 0x4f,
+ (byte) 0x7b, (byte) 0xad, (byte) 0x12, (byte) 0xe5, (byte) 0xd3, (byte) 0x82, (byte) 0xbb,
+ (byte) 0x44, (byte) 0xf9, (byte) 0xb4, (byte) 0xe7, (byte) 0x32, (byte) 0x51, (byte) 0x3e,
+ (byte) 0xad, (byte) 0xbb, (byte) 0x4d, (byte) 0x94, (byte) 0x4f, (byte) 0x5b, (byte) 0xaf,
+ (byte) 0x13, (byte) 0xe5, (byte) 0xd3, (byte) 0xf6, (byte) 0xfb, (byte) 0x44, (byte) 0xf9,
+ (byte) 0xb4, (byte) 0x05, (byte) 0x43, (byte) 0x51, (byte) 0x3e, (byte) 0xed, (byte) 0xc2,
+ (byte) 0x51, (byte) 0x94, (byte) 0x4f, (byte) 0x1b, (byte) 0xb1, (byte) 0x14, (byte) 0xe5,
+ (byte) 0xd3, (byte) 0x62, (byte) 0x3c, (byte) 0x45, (byte) 0xf9, (byte) 0xb4, (byte) 0x1f,
+ (byte) 0x53, (byte) 0x51, (byte) 0x3e, (byte) 0xad, (byte) 0xc9, (byte) 0x55, (byte) 0x94,
+ (byte) 0x4f, (byte) 0xeb, (byte) 0xb2, (byte) 0x15, (byte) 0xe5, (byte) 0xd3, (byte) 0xda,
+ (byte) 0x7c, (byte) 0x45, (byte) 0xf9, (byte) 0xb4, (byte) 0x3e, (byte) 0x63
+ };
+ checkSynth(
+ /*
+ * // The stream consists of word "time" with all possible transforms.
+ * main_header
+ * metablock_header_easy: 833, 1
+ * command_easy: 4, "|", 2 // = 0 << 10 + 1 + 1
+ * command_easy: 4, "|", 1031 // = 1 << 10 + 1 + 6
+ * command_easy: 4, "|", 2061 // = 2 << 10 + 1 + 12
+ * command_easy: 4, "|", 3092 // = 3 << 10 + 1 + 19
+ * command_easy: 4, "|", 4120 // = 4 << 10 + 1 + 23
+ * command_easy: 4, "|", 5150 // = 5 << 10 + 1 + 29
+ * command_easy: 4, "|", 6184 // = 6 << 10 + 1 + 39
+ * command_easy: 4, "|", 7214 // = 7 << 10 + 1 + 45
+ * command_easy: 4, "|", 8246 // = 8 << 10 + 1 + 53
+ * command_easy: 4, "|", 9279 // = 9 << 10 + 1 + 62
+ * command_easy: 4, "|", 10308 // = 10 << 10 + 1 + 67
+ * command_easy: 4, "|", 11342 // = 11 << 10 + 1 + 77
+ * command_easy: 4, "|", 12369 // = 12 << 10 + 1 + 80
+ * command_easy: 4, "|", 13397 // = 13 << 10 + 1 + 84
+ * command_easy: 4, "|", 14429 // = 14 << 10 + 1 + 92
+ * command_easy: 4, "|", 15460 // = 15 << 10 + 1 + 99
+ * command_easy: 4, "|", 16491 // = 16 << 10 + 1 + 106
+ * command_easy: 4, "|", 17524 // = 17 << 10 + 1 + 115
+ * command_easy: 4, "|", 18557 // = 18 << 10 + 1 + 124
+ * command_easy: 4, "|", 19589 // = 19 << 10 + 1 + 132
+ * command_easy: 4, "|", 20619 // = 20 << 10 + 1 + 138
+ * command_easy: 4, "|", 21649 // = 21 << 10 + 1 + 144
+ * command_easy: 4, "|", 22680 // = 22 << 10 + 1 + 151
+ * command_easy: 4, "|", 23710 // = 23 << 10 + 1 + 157
+ * command_easy: 4, "|", 24736 // = 24 << 10 + 1 + 159
+ * command_easy: 4, "|", 25766 // = 25 << 10 + 1 + 165
+ * command_easy: 4, "|", 26800 // = 26 << 10 + 1 + 175
+ * command_easy: 4, "|", 27826 // = 27 << 10 + 1 + 177
+ * command_easy: 4, "|", 28853 // = 28 << 10 + 1 + 180
+ * command_easy: 4, "|", 29885 // = 29 << 10 + 1 + 188
+ * command_easy: 4, "|", 30920 // = 30 << 10 + 1 + 199
+ * command_easy: 4, "|", 31950 // = 31 << 10 + 1 + 205
+ * command_easy: 4, "|", 32981 // = 32 << 10 + 1 + 212
+ * command_easy: 4, "|", 34011 // = 33 << 10 + 1 + 218
+ * command_easy: 4, "|", 35043 // = 34 << 10 + 1 + 226
+ * command_easy: 4, "|", 36068 // = 35 << 10 + 1 + 227
+ * command_easy: 4, "|", 37103 // = 36 << 10 + 1 + 238
+ * command_easy: 4, "|", 38133 // = 37 << 10 + 1 + 244
+ * command_easy: 4, "|", 39168 // = 38 << 10 + 1 + 255
+ * command_easy: 4, "|", 40201 // = 39 << 10 + 1 + 264
+ * command_easy: 4, "|", 41226 // = 40 << 10 + 1 + 265
+ * command_easy: 4, "|", 42251 // = 41 << 10 + 1 + 266
+ * command_easy: 4, "|", 43285 // = 42 << 10 + 1 + 276
+ * command_easy: 4, "|", 44310 // = 43 << 10 + 1 + 277
+ * command_easy: 4, "|", 45345 // = 44 << 10 + 1 + 288
+ * command_easy: 4, "|", 46374 // = 45 << 10 + 1 + 293
+ * command_easy: 4, "|", 47407 // = 46 << 10 + 1 + 302
+ * command_easy: 4, "|", 48440 // = 47 << 10 + 1 + 311
+ * command_easy: 4, "|", 49473 // = 48 << 10 + 1 + 320
+ * command_easy: 4, "|", 50498 // = 49 << 10 + 1 + 321
+ * command_easy: 4, "|", 51530 // = 50 << 10 + 1 + 329
+ * command_easy: 4, "|", 52561 // = 51 << 10 + 1 + 336
+ * command_easy: 4, "|", 53591 // = 52 << 10 + 1 + 342
+ * command_easy: 4, "|", 54623 // = 53 << 10 + 1 + 350
+ * command_easy: 4, "|", 55655 // = 54 << 10 + 1 + 358
+ * command_easy: 4, "|", 56680 // = 55 << 10 + 1 + 359
+ * command_easy: 4, "|", 57705 // = 56 << 10 + 1 + 360
+ * command_easy: 4, "|", 58730 // = 57 << 10 + 1 + 361
+ * command_easy: 4, "|", 59760 // = 58 << 10 + 1 + 367
+ * command_easy: 4, "|", 60791 // = 59 << 10 + 1 + 374
+ * command_easy: 4, "|", 61816 // = 60 << 10 + 1 + 375
+ * command_easy: 4, "|", 62849 // = 61 << 10 + 1 + 384
+ * command_easy: 4, "|", 63881 // = 62 << 10 + 1 + 392
+ * command_easy: 4, "|", 64919 // = 63 << 10 + 1 + 406
+ * command_easy: 4, "|", 65944 // = 64 << 10 + 1 + 407
+ * command_easy: 4, "|", 66969 // = 65 << 10 + 1 + 408
+ * command_easy: 4, "|", 68001 // = 66 << 10 + 1 + 416
+ * command_easy: 4, "|", 69031 // = 67 << 10 + 1 + 422
+ * command_easy: 4, "|", 70062 // = 68 << 10 + 1 + 429
+ * command_easy: 4, "|", 71092 // = 69 << 10 + 1 + 435
+ * command_easy: 4, "|", 72123 // = 70 << 10 + 1 + 442
+ * command_easy: 4, "|", 73154 // = 71 << 10 + 1 + 449
+ * command_easy: 4, "|", 74185 // = 72 << 10 + 1 + 456
+ * command_easy: 4, "|", 75219 // = 73 << 10 + 1 + 466
+ * command_easy: 4, "|", 76261 // = 74 << 10 + 1 + 484
+ * command_easy: 4, "|", 77291 // = 75 << 10 + 1 + 490
+ * command_easy: 4, "|", 78327 // = 76 << 10 + 1 + 502
+ * command_easy: 4, "|", 79357 // = 77 << 10 + 1 + 508
+ * command_easy: 4, "|", 80388 // = 78 << 10 + 1 + 515
+ * command_easy: 4, "|", 81418 // = 79 << 10 + 1 + 521
+ * command_easy: 4, "|", 82448 // = 80 << 10 + 1 + 527
+ * command_easy: 4, "|", 83482 // = 81 << 10 + 1 + 537
+ * command_easy: 4, "|", 84514 // = 82 << 10 + 1 + 545
+ * command_easy: 4, "|", 85546 // = 83 << 10 + 1 + 553
+ * command_easy: 4, "|", 86577 // = 84 << 10 + 1 + 560
+ * command_easy: 4, "|", 87609 // = 85 << 10 + 1 + 568
+ * command_easy: 4, "|", 88639 // = 86 << 10 + 1 + 574
+ * command_easy: 4, "|", 89670 // = 87 << 10 + 1 + 581
+ * command_easy: 4, "|", 90700 // = 88 << 10 + 1 + 587
+ * command_easy: 4, "|", 91731 // = 89 << 10 + 1 + 594
+ * command_easy: 4, "|", 92762 // = 90 << 10 + 1 + 601
+ * command_easy: 4, "|", 93795 // = 91 << 10 + 1 + 610
+ * command_easy: 4, "|", 94827 // = 92 << 10 + 1 + 618
+ * command_easy: 4, "|", 95860 // = 93 << 10 + 1 + 627
+ * command_easy: 4, "|", 96894 // = 94 << 10 + 1 + 637
+ * command_easy: 4, "|", 97924 // = 95 << 10 + 1 + 643
+ * command_easy: 4, "|", 98957 // = 96 << 10 + 1 + 652
+ * command_easy: 4, "|", 99988 // = 97 << 10 + 1 + 659
+ * command_easy: 4, "|", 101019 // = 98 << 10 + 1 + 666
+ * command_easy: 4, "|", 102051 // = 99 << 10 + 1 + 674
+ * command_easy: 4, "|", 103081 // = 100 << 10 + 1 + 680
+ * command_easy: 4, "|", 104114 // = 101 << 10 + 1 + 689
+ * command_easy: 4, "|", 105144 // = 102 << 10 + 1 + 695
+ * command_easy: 4, "|", 106175 // = 103 << 10 + 1 + 702
+ * command_easy: 4, "|", 107206 // = 104 << 10 + 1 + 709
+ * command_easy: 4, "|", 108237 // = 105 << 10 + 1 + 716
+ * command_easy: 4, "|", 109268 // = 106 << 10 + 1 + 723
+ * command_easy: 4, "|", 110301 // = 107 << 10 + 1 + 732
+ * command_easy: 4, "|", 111332 // = 108 << 10 + 1 + 739
+ * command_easy: 4, "|", 112363 // = 109 << 10 + 1 + 746
+ * command_easy: 4, "|", 113394 // = 110 << 10 + 1 + 753
+ * command_easy: 4, "|", 114426 // = 111 << 10 + 1 + 761
+ * command_easy: 4, "|", 115458 // = 112 << 10 + 1 + 769
+ * command_easy: 4, "|", 116488 // = 113 << 10 + 1 + 775
+ * command_easy: 4, "|", 117518 // = 114 << 10 + 1 + 781
+ * command_easy: 4, "|", 118549 // = 115 << 10 + 1 + 788
+ * command_easy: 4, "|", 119580 // = 116 << 10 + 1 + 795
+ * command_easy: 4, "|", 120611 // = 117 << 10 + 1 + 802
+ * command_easy: 4, "|", 121643 // = 118 << 10 + 1 + 810
+ * command_easy: 4, "|", 122675 // = 119 << 10 + 1 + 818
+ * command_easy: 4, "|", 123707 // = 120 << 10 + 1 + 826
+ */
+ compressed,
+ true,
+ "|time|time | time |ime|Time |time the | time|s time |time of |Time|time and |me|tim|, time |"
+ + "time, | Time |time in |time to |e time |time\"|time.|time\">|time\n|t|time]|time for |e|ti"
+ + "|time a |time that | Time|time. |.time| time, ||time with |time'|time from |time by ||| th"
+ + "e time||time. The |TIME|time on |time as |time is ||timing |time\n\t|time:| time. |timeed "
+ + "||||time(|Time, ||time at |timely | the time of ||| Time, |Time\"|.time(|TIME |Time\">|tim"
+ + "e=\"| time.|.com/time| the time of the |Time'|time. This |time,|.time |Time(|Time.|time no"
+ + "t | time=\"|timeer | TIME |timeal | TIME|time='|TIME\"|Time. | time(|timeful | Time. |time"
+ + "ive |timeless |TIME'|timeest | Time.|TIME\">| time='|Time,|timeize |TIME.|\302\240time| ti"
+ + "me,|Time=\"|TIME=\"|timeous |TIME, |Time='| Time,| TIME=\"| TIME, |TIME,|TIME(|TIME. | TIM"
+ + "E.|TIME='| TIME. | Time=\"| TIME='| Time='"
+ );
+ }
+
+ @Test
+ public void testBaseDictWord() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x02
+ };
+ checkSynth(
+ /*
+ * // The stream consists of a base dictionary word.
+ * main_header
+ * metablock_header_easy: 4, 1
+ * command_inscopy_easy: 0, 4
+ * command_dist_easy: 1
+ */
+ compressed,
+ true,
+ "time"
+ );
+ }
+
+ @Test
+ public void testBaseDictWordFinishBlockOnRingbufferWrap() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x1f, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x9b, (byte) 0x58, (byte) 0x32, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34,
+ (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34,
+ (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34,
+ (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34, (byte) 0x34,
+ (byte) 0x34, (byte) 0x34, (byte) 0xd4, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 32, 1 // 32 = minimal ringbuffer size
+ * command_easy: 4, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", 29
+ */
+ compressed,
+ true,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaatime"
+ );
+ }
+
+ @Test
+ public void testBaseDictWordTooLong() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x02
+ };
+ checkSynth(
+ /*
+ * // Has an unmodified dictionary word that goes over the end of the
+ * // meta-block. Same as BaseDictWord, but with a shorter meta-block length.
+ * main_header
+ * metablock_header_easy: 1, 1
+ * command_inscopy_easy: 0, 4
+ * command_dist_easy: 1
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testBlockCountMessage() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0b, (byte) 0x00, (byte) 0x11, (byte) 0x01, (byte) 0x8c, (byte) 0xc1,
+ (byte) 0xc5, (byte) 0x0d, (byte) 0x08, (byte) 0x00, (byte) 0x22, (byte) 0x65, (byte) 0xe1,
+ (byte) 0xfc, (byte) 0xfd, (byte) 0x22, (byte) 0x2c, (byte) 0xc4, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0xd8, (byte) 0x32, (byte) 0x89, (byte) 0x01, (byte) 0x12, (byte) 0x00,
+ (byte) 0x00, (byte) 0x77, (byte) 0xda, (byte) 0x04, (byte) 0x10, (byte) 0x42, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * // Same as BlockSwitchMessage but also uses 0-bit block-type commands.
+ * main_header
+ * metablock_header_begin: 1, 0, 12, 0
+ * // two literal block types
+ * vlq_blocktypes: 2
+ * huffman_simple: 1,1,4, 1 // literal blocktype prefix code
+ * huffman_fixed: 26 // literal blockcount prefix code
+ * blockcount_easy: 2 // 2 a's
+ * // one ins/copy and dist block type
+ * vlq_blocktypes: 1
+ * vlq_blocktypes: 1
+ * ndirect: 0, 0
+ * // two MSB6 literal context modes
+ * bits: "00", "00"
+ * // two literal prefix codes
+ * vlq_blocktypes: 2
+ * // literal context map
+ * vlq_rlemax: 5
+ * huffman_simple: 0,3,7, 5,0,6 // context map RLE Huffman code
+ * // context map RLE: repeat 0 64 times, 1+5 64 times
+ * bits: "01", "0", "11111", "11", "0", "11111"
+ * bit: 1 // MTF enabled
+ * // one distance prefix code
+ * vlq_blocktypes: 1
+ * huffman_simple: 0,1,256, 97 // only a's
+ * huffman_simple: 0,1,256, 98 // only b's
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * // now comes the data
+ * command_inscopy_easy: 12, 0
+ * blockcount_easy: 2 // switch to other block type; 2 b's
+ * blockcount_easy: 5 // switch to other block type; 5 a's
+ * blockcount_easy: 1 // switch to other block type; 1 b
+ * blockcount_easy: 1 // switch to other block type; 1 a
+ * blockcount_easy: 1 // switch to other block type; 1 b
+ */
+ compressed,
+ true,
+ "aabbaaaaabab"
+ );
+ }
+
+ @Test
+ public void testBlockSwitchMessage() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0b, (byte) 0x00, (byte) 0xd1, (byte) 0xe1, (byte) 0x01, (byte) 0xc6,
+ (byte) 0xe0, (byte) 0xe2, (byte) 0x06, (byte) 0x04, (byte) 0x00, (byte) 0x91, (byte) 0xb2,
+ (byte) 0x70, (byte) 0xfe, (byte) 0x7e, (byte) 0x11, (byte) 0x16, (byte) 0x62, (byte) 0x00,
+ (byte) 0x00, (byte) 0x1c, (byte) 0x6c, (byte) 0x99, (byte) 0xc4, (byte) 0x00, (byte) 0x09,
+ (byte) 0x00, (byte) 0x80, (byte) 0x3b, (byte) 0x6d, (byte) 0x02, (byte) 0x08, (byte) 0x82,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * // Uses blocks with 1-symbol Huffman codes that take 0 bits, so that it
+ * // is the block-switch commands that encode the message rather than actual
+ * // literals.
+ * main_header
+ * metablock_header_begin: 1, 0, 12, 0
+ * // two literal block types
+ * vlq_blocktypes: 2
+ * huffman_simple: 1,4,4, 1,0,2,3 // literal blocktype prefix code
+ * huffman_fixed: 26 // literal blockcount prefix code
+ * blockcount_easy: 2 // 2 a's
+ * // one ins/copy and dist block type
+ * vlq_blocktypes: 1
+ * vlq_blocktypes: 1
+ * ndirect: 0, 0
+ * // two MSB6 literal context modes
+ * bits: "00", "00"
+ * // two literal prefix codes
+ * vlq_blocktypes: 2
+ * // literal context map
+ * vlq_rlemax: 5
+ * huffman_simple: 0,3,7, 5,0,6 // context map RLE Huffman code
+ * // context map RLE: repeat 0 64 times, 1+5 64 times
+ * bits: "01", "0", "11111", "11", "0", "11111"
+ * bit: 1 // MTF enabled
+ * // one distance prefix code
+ * vlq_blocktypes: 1
+ * huffman_simple: 0,1,256, 97 // only a's
+ * huffman_simple: 0,1,256, 98 // only b's
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * // now comes the data
+ * command_inscopy_easy: 12, 0
+ * bits: "0"; blockcount_easy: 2 // switch to other block type; 2 b's
+ * bits: "0"; blockcount_easy: 5 // switch to other block type; 5 a's
+ * bits: "0"; blockcount_easy: 1 // switch to other block type; 1 b
+ * bits: "0"; blockcount_easy: 1 // switch to other block type; 1 a
+ * bits: "0"; blockcount_easy: 1 // switch to other block type; 1 b
+ */
+ compressed,
+ true,
+ "aabbaaaaabab"
+ );
+ }
+
+ @Test
+ public void testClClTreeDeficiency() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x80,
+ (byte) 0x43, (byte) 0x01, (byte) 0xe0, (byte) 0x05, (byte) 0x88, (byte) 0x55, (byte) 0x90,
+ (byte) 0x01, (byte) 0x00, (byte) 0x38, (byte) 0xd8, (byte) 0x32, (byte) 0x89, (byte) 0x01,
+ (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77, (byte) 0xda, (byte) 0x28, (byte) 0x40,
+ (byte) 0x23
+ };
+ checkSynth(
+ /*
+ * // This test is a copy of TooManySymbolsRepeated, with changed clcl table.
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * hskip: 0
+ * clcl_ordered: 0,3,0,0,0,0,0,0,3,3,0,0,0,0,0,0,1,0
+ * set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "101",\
+ * "", "", "", "", "", "", "0", ""
+ * cl_rle: 8
+ * cl_rle_rep: 9, 96
+ * cl_rle: 1
+ * cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * command_literal_bits: 0, 0, 0, 101100010
+ */
+ compressed,
+ false,
+ "aaab"
+ );
+ }
+
+ @Test
+ public void testClClTreeExcess() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x80,
+ (byte) 0xc3, (byte) 0x7b, (byte) 0x80, (byte) 0x58, (byte) 0x41, (byte) 0x06, (byte) 0x00,
+ (byte) 0xe0, (byte) 0x60, (byte) 0xcb, (byte) 0x24, (byte) 0x06, (byte) 0x48, (byte) 0x00,
+ (byte) 0x00, (byte) 0xdc, (byte) 0x69, (byte) 0xa3, (byte) 0x00, (byte) 0x8d, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * // This test is a copy of ClClTreeDeficiency, with changed clcl table.
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * hskip: 0
+ * clcl_ordered: 0,3,0,0,0,0,0,0,3,1,0,0,0,0,0,0,1,0
+ * set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "1",\
+ * "", "", "", "", "", "", "0", ""
+ * cl_rle: 8
+ * cl_rle_rep: 9, 96
+ * cl_rle: 1
+ * cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * command_literal_bits: 0, 0, 0, 101100010
+ */
+ compressed,
+ false,
+ "aaab"
+ );
+ }
+
+ @Test
+ public void testComplexHuffmanCodeTwoSymbols() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x03, (byte) 0xe0,
+ (byte) 0xa2, (byte) 0x1a, (byte) 0x00, (byte) 0x00, (byte) 0x0e, (byte) 0xb6, (byte) 0x4c,
+ (byte) 0x62, (byte) 0x80, (byte) 0x04, (byte) 0x00, (byte) 0xc0, (byte) 0x9d, (byte) 0x36,
+ (byte) 0x12, (byte) 0x04
+ };
+ checkSynth(
+ /*
+ * // This tests a complex Huffman code with only two symbols followed by a
+ * // tiny amount of content.
+ * main_header
+ * metablock_header_begin: 1, 0, 2, 0
+ * metablock_header_trivial_context
+ * // begin of literal Huffman tree. The tree has symbol length 1 for "a",
+ * // symbol length 1 for "b" and symbol length 0 for all others.
+ * hskip: 0
+ * clcl_ordered: 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
+ * set_prefix_cl_rle: "", "0", "", "", "", "", "", "", "", "",\
+ * "", "", "", "", "", "", "", "1"
+ * cl_rle_rep_0: 97
+ * cl_rle: 1 // literal number 97, that is, the letter 'a'
+ * cl_rle: 1 // literal number 98, that is, the letter 'b'
+ * // end of literal Huffman tree
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 2, 0
+ * command_literal_bits: 0, 1 // a followed by b
+ */
+ compressed,
+ true,
+ "ab"
+ );
+ }
+
+ @Test
+ public void testCompressedUncompressedShortCompressed() {
+ byte[] compressed = {
+ (byte) 0x8b, (byte) 0xfe, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x9b, (byte) 0x66, (byte) 0x6f, (byte) 0x1b, (byte) 0x0a, (byte) 0x50, (byte) 0x00,
+ (byte) 0x10, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62,
+ (byte) 0x31, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x24, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header: 22
+ * metablock_header_easy: 1022, 0
+ * command_easy: 1021, "a", 1 // 1022 x "a"
+ * metablock_uncompressed: "bbbbbb"
+ * metablock_header_easy: 4, 1
+ * command_easy: 4, "", 1 // 6 + 4 = 10 x "b"
+ */
+ compressed,
+ true,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbb"
+ );
+ }
+
+ @Test
+ public void testCompressedUncompressedShortCompressedSmallWindow() {
+ byte[] compressed = {
+ (byte) 0x21, (byte) 0xf4, (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x1c, (byte) 0xa7, (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8,
+ (byte) 0x32, (byte) 0x89, (byte) 0x01, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77,
+ (byte) 0xda, (byte) 0x34, (byte) 0x7b, (byte) 0xdb, (byte) 0x50, (byte) 0x80, (byte) 0x02,
+ (byte) 0x80, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62, (byte) 0x62,
+ (byte) 0x31, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x24, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header: 10
+ * metablock_header_easy: 1022, 0
+ * command_easy: 1021, "a", 1 // 1022 x "a"
+ * metablock_uncompressed: "bbbbbb"
+ * metablock_header_easy: 4, 1
+ * command_easy: 4, "", 1 // 6 + 4 = 10 x "b"
+ */
+ compressed,
+ true,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbb"
+ );
+ }
+
+ @Test
+ public void testCopyLengthTooLong() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x11, (byte) 0x86, (byte) 0x02
+ };
+ checkSynth(
+ /*
+ * // Has a copy length that goes over the end of the meta-block.
+ * // Same as OneCommand, but with a shorter meta-block length.
+ * main_header
+ * metablock_header_easy: 2, 1
+ * command_easy: 2, "a", 1
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testCopyTooLong() {
+ byte[] compressed = {
+ (byte) 0xa1, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x1c, (byte) 0xa7, (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8,
+ (byte) 0x32, (byte) 0x89, (byte) 0x01, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77,
+ (byte) 0xda, (byte) 0x34, (byte) 0xab, (byte) 0xdb, (byte) 0x50, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * // Has a copy length that goes over the end of the meta-block,
+ * // with a ringbuffer wrap.
+ * main_header: 10
+ * metablock_header_easy: 2, 1
+ * command_easy: 1024, "a", 1
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testCustomHuffmanCode() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x80,
+ (byte) 0xc3, (byte) 0x3d, (byte) 0x80, (byte) 0x58, (byte) 0x82, (byte) 0x08, (byte) 0x00,
+ (byte) 0xc0, (byte) 0xc1, (byte) 0x96, (byte) 0x49, (byte) 0x0c, (byte) 0x90, (byte) 0x00,
+ (byte) 0x00, (byte) 0xb8, (byte) 0xd3, (byte) 0x46, (byte) 0x01, (byte) 0x1a, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * // This tests a small hand crafted Huffman code followed by a tiny amount
+ * // of content. This tests if the bit reader detects the end correctly even
+ * // with tiny content after a larger Huffman tree encoding.
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * // begin of literal Huffman tree. The tree has symbol length 1 for "a",
+ * // symbol length 8 for null, symbol length 9 for all others. The length 1
+ * // for a is chosen on purpose here, the others must be like that to
+ * // fulfill the requirement that sum of 32>>length is 32768.
+ * hskip: 0
+ * clcl_ordered: 0,3,0,0,0,0,0,0,3,2,0,0,0,0,0,0,1,0
+ * set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "10",\
+ * "", "", "", "", "", "", "0", ""
+ * cl_rle: 8
+ * cl_rle_rep: 9, 96
+ * cl_rle: 1 // literal number 97, that is, the letter 'a'
+ * cl_rle_rep: 9, 158
+ * // end of literal Huffman tree
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * // Here is how the code "101100010" for b is derived: remember that a has
+ * // symbol length 1, null has symbol length 8, the rest 9. So in the
+ * // canonical Huffman code, the code for "a" is "0", for null is
+ * // "10000000". The next value has "100000010" (cfr. the rules of canonical
+ * // prefix code). Counting upwards +95 from there, the value "@" (ASCII 96,
+ * // before "a") has "101100001", and so b, the next 9-bit symbol, has the
+ * // next binary value "101100010".
+ * command_literal_bits: 0, 0, 0, 101100010 // 3 a's followed by a b
+ */
+ compressed,
+ true,
+ "aaab"
+ );
+ }
+
+ @Test
+ public void testDistanceLut() {
+ byte[] compressed = {
+ (byte) 0x8b, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x99, (byte) 0x86, (byte) 0x46, (byte) 0xc6, (byte) 0x22, (byte) 0x14,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x1c, (byte) 0xa7,
+ (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8, (byte) 0x32, (byte) 0x89,
+ (byte) 0x01, (byte) 0x12, (byte) 0x21, (byte) 0x91, (byte) 0x69, (byte) 0x62, (byte) 0x6a,
+ (byte) 0x36
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 6, 0 // implicit ndirect: 0, 0
+ * command_easy: 3, "abc", 3 // Insert "abc", copy "abc"
+ * metablock_header_begin: 0, 0, 6, 0
+ * vlq_blocktypes: 1 // num litetal block types
+ * vlq_blocktypes: 1 // num command block types
+ * vlq_blocktypes: 1 // num distance block types
+ * ndirect: 3, 0
+ * bits: "00" // literal context modes
+ * vlq_blocktypes: 1 // num literal Huffman trees
+ * // command has no context -> num trees == num block types
+ * vlq_blocktypes: 1 // num distance Huffman trees
+ * huffman_fixed: 256
+ * huffman_fixed: 704
+ * huffman_simple: 0,1,67, 18
+ * command_inscopy_easy: 3, 3 // Insert 3, copy 3
+ * command_literals_easy: "def"
+ * // 0-bit Huffman code : dcode = 18 -> third direct distance
+ * metablock_lastempty // make sure that no extra distance bits are read
+ */
+ compressed,
+ true,
+ "abcabcdefdef"
+ );
+ }
+
+ @Test
+ public void testEmpty() {
+ byte[] compressed = {
+ (byte) 0x3b
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_lastempty
+ */
+ compressed,
+ true,
+ ""
+ );
+ }
+
+ @Test
+ public void testHelloWorld() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x9b, (byte) 0x00, (byte) 0x59, (byte) 0x98, (byte) 0xda, (byte) 0xd8, (byte) 0xd8,
+ (byte) 0x13, (byte) 0xb8, (byte) 0xdb, (byte) 0x3b, (byte) 0xd9, (byte) 0x98, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_fixed: "hello world", 1
+ */
+ compressed,
+ true,
+ "hello world"
+ );
+ }
+
+ @Test
+ public void testInsertTooLong() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x09, (byte) 0x86, (byte) 0x46
+ };
+ checkSynth(
+ /*
+ * // Has an insert length that goes over the end of the meta-block.
+ * // Same as OneInsert, but with a shorter meta-block length.
+ * main_header
+ * metablock_header_easy: 1, 1
+ * command_easy: 0, "ab"
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testIntactDistanceRingBuffer0() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0xa1, (byte) 0x80, (byte) 0x20, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 11, 1
+ * command_inscopy_easy: 0, 7 // "himself" from dictionary
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // copy "self"
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ */
+ compressed,
+ true,
+ "himselfself"
+ );
+ }
+
+ @Test
+ public void testIntactDistanceRingBuffer1() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x09, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x21, (byte) 0xa0, (byte) 0x20, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 10, 1
+ * command_inscopy_easy: 0, 6 // "scroll" from dictionary
+ * bits: "100000" // distance = 11 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // copy "roll"
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ */
+ compressed,
+ true,
+ "scrollroll"
+ );
+ }
+
+ @Test
+ public void testIntactDistanceRingBuffer2() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x80, (byte) 0x20, (byte) 0x50, (byte) 0x10, (byte) 0x24,
+ (byte) 0x08, (byte) 0x06
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 16, 1
+ * command_inscopy_easy: 0, 4 // "left" from dictionary (index = 3 = 4 - 1)
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "data" from dictionary (index = 6 = 11 - 5)
+ * bits: "100000" // distance = 11 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "data" from dictionary (index = 6 = 15 - 9)
+ * bits: "010000" // distance = 15 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "left" from dictionary (index = 3 = 16 - 13)
+ * bits: "110000" // distance = 16 from RB; RB remains intact
+ */
+ compressed,
+ true,
+ "leftdatadataleft"
+ );
+ }
+
+ @Test
+ public void testIntactDistanceRingBufferNoDistanceValue0() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x17, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x40, (byte) 0x82, (byte) 0x40, (byte) 0x41, (byte) 0x90, (byte) 0x20,
+ (byte) 0x58, (byte) 0x18, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 24, 1
+ * // cmd is {ins_extra, copy_extra, distance_code, ctx, ins_off, copy_off}
+ * // cmd.2 = {0x00, 0x00, 0, 0x02, 0x0000, 0x0004}
+ * // cmd.2 = no insert, copy length = 4, distance_code = 0 (last distance)
+ * command_short: 2 // "left" from dictionary (index = 3 = 4 - 1)
+ * // Check that RB is untouched after the first command...
+ * command_inscopy_easy: 0, 4 // "data" from dictionary (index = 6 = 11 - 5)
+ * bits: "100000" // distance = 11 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "data" from dictionary (index = 6 = 15 - 9)
+ * bits: "010000" // distance = 15 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "left" from dictionary (index = 3 = 16 - 13)
+ * bits: "110000" // distance = 16 from RB; RB remains intact
+ * command_inscopy_easy: 0, 8 // copy "leftleft"
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ */
+ compressed,
+ true,
+ "leftdatadataleftleftleft"
+ );
+ }
+
+ @Test
+ public void testIntactDistanceRingBufferNoDistanceValue1() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x19, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0xc0, (byte) 0x82, (byte) 0x41, (byte) 0x41, (byte) 0x90, (byte) 0x20,
+ (byte) 0x58, (byte) 0x18, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 26, 1
+ * // cmd is {ins_extra, copy_extra, distance_code, ctx, ins_off, copy_off}
+ * // cmd.3 = {0x00, 0x00, 0, 0x03, 0x0000, 0x0005}
+ * // cmd.3 = no insert, copy length = 5, distance_code = 0 (last distance)
+ * command_short: 3 // "world" from dictionary (index = 3 = 4 - 1)
+ * // Check that RB is untouched after the first command...
+ * command_inscopy_easy: 0, 5 // "white" from dictionary (index = 5 = 11 - 6)
+ * bits: "100000" // distance = 11 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "back" from dictionary (index = 4 = 15 - 11)
+ * bits: "010000" // distance = 15 from RB; RB remains intact
+ * command_inscopy_easy: 0, 4 // "down" from dictionary (index = 1 = 16 - 15)
+ * bits: "110000" // distance = 16 from RB; RB remains intact
+ * command_inscopy_easy: 0, 8 // copy "downdown"
+ * bits: "000000" // distance = 4 from RB; RB remains intact
+ */
+ compressed,
+ true,
+ "worldwhitebackdowndowndown"
+ );
+ }
+
+ @Test
+ public void testInvalidNoLastMetablock() {
+ byte[] compressed = {
+ (byte) 0x0b, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x9b, (byte) 0x00, (byte) 0x13, (byte) 0x59, (byte) 0x98, (byte) 0xda, (byte) 0xd8,
+ (byte) 0xd8, (byte) 0x13, (byte) 0xb8, (byte) 0xdb, (byte) 0x3b, (byte) 0xd9, (byte) 0x98,
+ (byte) 0xe8, (byte) 0x00
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_fixed: \"hello world\", 0
+ */
+ compressed,
+ false,
+ "hello world"
+ );
+ }
+
+ @Test
+ public void testInvalidNoMetaBlocks() {
+ byte[] compressed = {
+ (byte) 0x0b
+ };
+ checkSynth(
+ /*
+ * main_header
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testInvalidTooFarDist() {
+ byte[] compressed = {
+ (byte) 0xa1, (byte) 0x48, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x1c, (byte) 0xa7, (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8,
+ (byte) 0x32, (byte) 0x89, (byte) 0x01, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77,
+ (byte) 0xda, (byte) 0xe8, (byte) 0xe0, (byte) 0x62, (byte) 0x6f, (byte) 0x4f, (byte) 0x60,
+ (byte) 0x66, (byte) 0xe8, (byte) 0x44, (byte) 0x38, (byte) 0x0f, (byte) 0x09, (byte) 0x0d
+ };
+ checkSynth(
+ /*
+ * main_header: 10
+ * metablock_header_begin: 1, 0, 10, 0
+ * metablock_header_trivial_context
+ * huffman_fixed: 256
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_easy: 2, "too far!", 1000000 // distance too far for 10 wbits
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testInvalidTooLargeContextMap() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x00, (byte) 0x00, (byte) 0xd1, (byte) 0xe1, (byte) 0x01, (byte) 0xc6,
+ (byte) 0xe0, (byte) 0xe2, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x91, (byte) 0xb2,
+ (byte) 0x70, (byte) 0xfe, (byte) 0xfb, (byte) 0x45, (byte) 0x58, (byte) 0x88, (byte) 0x01,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * // Has a repeat code a context map that makes the size too big -> invalid.
+ * main_header
+ * metablock_header_begin: 1, 0, 1, 0
+ * // two literal block types
+ * vlq_blocktypes: 2
+ * huffman_simple: 1,4,4, 1,0,2,3 // literal blocktype prefix code
+ * huffman_fixed: 26 // literal blockcount prefix code
+ * blockcount_easy: 1
+ * // one ins/copy and dist block type
+ * vlq_blocktypes: 1
+ * vlq_blocktypes: 1
+ * ndirect: 0, 0
+ * // two MSB6 literal context modes
+ * bits: "00", "00"
+ * // two literal prefix codes
+ * vlq_blocktypes: 2
+ * // literal context map
+ * vlq_rlemax: 5
+ * huffman_simple: 0,3,7, 5,0,6 // context map RLE Huffman code
+ * // Too long context map RLE: repeat 0 64 times, 1+5 65 times, that is 129
+ * // values which is 1 too much.
+ * bits: "01", "0", "11111", "11", "11", "0", "11111"
+ * bit: 1 // MTF enabled
+ * // one distance prefix code
+ * vlq_blocktypes: 1
+ * huffman_simple: 0,1,256, 97 // only a's
+ * huffman_simple: 0,1,256, 98 // only b's
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * // now comes the data
+ * command_inscopy_easy: 1, 0
+ */
+ compressed,
+ false,
+ "a"
+ );
+ }
+
+ @Test
+ public void testInvalidTransformType() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x2d, (byte) 0x01, (byte) 0x19
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 4, 1
+ * command_inscopy_easy: 0, 4
+ * command_dist_easy: 123905 // = 121 << 10 + 1
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testInvalidWindowBits9() {
+ byte[] compressed = {
+ (byte) 0x91, (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x1c, (byte) 0xa7, (byte) 0x6d, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8,
+ (byte) 0x32, (byte) 0x89, (byte) 0x01, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77,
+ (byte) 0xda, (byte) 0xc8, (byte) 0x20, (byte) 0x32, (byte) 0xd4, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * main_header: 9
+ * metablock_fixed: \"a\", 1
+ */
+ compressed,
+ false,
+ "a"
+ );
+ }
+
+ @Test
+ public void testManyTinyMetablocks() {
+ byte[] compressed = {
+ (byte) 0x0b, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb,
+ (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03,
+ (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61,
+ (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04,
+ (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00,
+ (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00,
+ (byte) 0x80, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70,
+ (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00,
+ (byte) 0xee, (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80,
+ (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee,
+ (byte) 0xb4, (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38,
+ (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x11, (byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x80, (byte) 0x61, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e,
+ (byte) 0xdb, (byte) 0x00, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12,
+ (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x11,
+ (byte) 0x61, (byte) 0x34
+ };
+ checkSynth(
+ /*
+ * main_header
+ * repeat: 300
+ * metablock_uncompressed: "a"
+ * metablock_fixed: "b"
+ * end_repeat
+ * metablock_lastempty
+ */
+ compressed,
+ true,
+ "abababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababababababababababababababababababab"
+ + "ababababababababababababababababababababababababababababab"
+ );
+ }
+
+ @Test
+ public void testNegativeDistance() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x02, (byte) 0x01, (byte) 0x42, (byte) 0x01, (byte) 0x42,
+ (byte) 0x01, (byte) 0x42, (byte) 0x01, (byte) 0x42, (byte) 0x01, (byte) 0x42, (byte) 0x01,
+ (byte) 0x1c
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 16, 1
+ * command_inscopy_easy: 0, 4 // time
+ * command_dist_easy: 1
+ * command_inscopy_easy: 0, 2 // me
+ * command_dist_easy: 2
+ * command_inscopy_easy: 0, 2 // me
+ * command_dist_easy: 2
+ * command_inscopy_easy: 0, 2 // me
+ * command_dist_easy: 2
+ * command_inscopy_easy: 0, 2 // me
+ * command_dist_easy: 2
+ * command_inscopy_easy: 0, 2 // me
+ * command_dist_easy: 2 // All rb items are 2 now
+ * command_inscopy_easy: 0, 2
+ * bits: "011100" // 15 -> distance = rb[idx + 2] - 3
+ */
+ compressed,
+ false,
+ "timemememememeXX"
+ );
+ }
+
+ @Test
+ public void testNegativeRemainingLenBetweenMetablocks() {
+ byte[] compressed = {
+ (byte) 0x0b, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x09, (byte) 0x86, (byte) 0x46, (byte) 0x11, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00,
+ (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24,
+ (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4, (byte) 0x91, (byte) 0x60, (byte) 0x68,
+ (byte) 0x04
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_easy: 1, 0
+ * command_easy: 0, "ab" // remaining length == -1 -> invalid stream
+ * metablock_header_easy: 2, 1
+ * command_easy: 0, "ab"
+ */
+ compressed,
+ false,
+ "abab"
+ );
+ }
+
+ @Test
+ public void testOneCommand() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x11, (byte) 0x86, (byte) 0x02
+ };
+ checkSynth(
+ /*
+ * // The stream consists of one command with insert and copy.
+ * main_header
+ * metablock_header_easy: 3, 1
+ * command_easy: 2, "a", 1
+ */
+ compressed,
+ true,
+ "aaa"
+ );
+ }
+
+ @Test
+ public void testOneInsert() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x09, (byte) 0x86, (byte) 0x46
+ };
+ checkSynth(
+ /*
+ * // The stream consists of one half command with insert only.
+ * main_header
+ * metablock_header_easy: 2, 1
+ * command_easy: 0, "ab"
+ */
+ compressed,
+ true,
+ "ab"
+ );
+ }
+
+ @Test
+ public void testSimplePrefix() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xc3, (byte) 0xc4,
+ (byte) 0xc6, (byte) 0xc8, (byte) 0x02, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x51, (byte) 0xa0, (byte) 0x1d
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * huffman_simple: 1,4,256, 97,98,99,100 // ASCII codes for a, b, c, d
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * command_literal_bits: 0, 10, 110, 111 // a, b, c, d
+ */
+ compressed,
+ true,
+ "abcd"
+ );
+ }
+
+ @Test
+ public void testSimplePrefixDuplicateSymbols() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xc3, (byte) 0xc4,
+ (byte) 0xc2, (byte) 0xc4, (byte) 0x02, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x51, (byte) 0xa0, (byte) 0x1d
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * huffman_simple: 1,4,256, 97,98,97,98 // ASCII codes for a, b, a, b
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * command_literal_bits: 0, 10, 110, 111 // a, b, a, b
+ */
+ compressed,
+ false,
+ "abab"
+ );
+ }
+
+ @Test
+ public void testSimplePrefixOutOfRangeSymbols() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x4d, (byte) 0xff, (byte) 0xef, (byte) 0x7f, (byte) 0xff,
+ (byte) 0xfc, (byte) 0x07, (byte) 0x00, (byte) 0xb8, (byte) 0xd3, (byte) 0x06
+ };
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * huffman_fixed: 256
+ * huffman_simple: 1,4,704, 1023,1022,1021,1020
+ * huffman_fixed: 64
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+/* DISABLED: Java decoder does not tolerate extra input after the brotli stream.
+ @Test
+ public void testSimplePrefixPlusExtraData() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xc3, (byte) 0xc4,
+ (byte) 0xc6, (byte) 0xc8, (byte) 0x02, (byte) 0x00, (byte) 0x70, (byte) 0xb0, (byte) 0x65,
+ (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0x00, (byte) 0x00, (byte) 0xee, (byte) 0xb4,
+ (byte) 0x51, (byte) 0xa0, (byte) 0x1d, (byte) 0x55, (byte) 0xaa
+ };
+ checkSynth(
+ compressed,
+ true,
+ "abcd"
+ );
+ }
+*/
+
+ @Test
+ public void testStressReadDistanceExtraBits() {
+ byte[] compressed = {
+ (byte) 0x4f, (byte) 0xfe, (byte) 0xff, (byte) 0x3f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x80, (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07,
+ (byte) 0x5b, (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0,
+ (byte) 0x4e, (byte) 0x9b, (byte) 0xf6, (byte) 0x69, (byte) 0xef, (byte) 0xff, (byte) 0x0c,
+ (byte) 0x8d, (byte) 0x8c, (byte) 0x05, (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0x4e, (byte) 0xdb, (byte) 0x00, (byte) 0x00,
+ (byte) 0x70, (byte) 0xb0, (byte) 0x65, (byte) 0x12, (byte) 0x03, (byte) 0x24, (byte) 0xa8,
+ (byte) 0xaa, (byte) 0xef, (byte) 0xab, (byte) 0xaa, (byte) 0x7f, (byte) 0x24, (byte) 0x16,
+ (byte) 0x35, (byte) 0x8f, (byte) 0xac, (byte) 0x9e, (byte) 0x3d, (byte) 0xf7, (byte) 0xf3,
+ (byte) 0xe3, (byte) 0x0a, (byte) 0xfc, (byte) 0xff, (byte) 0x03, (byte) 0x00, (byte) 0x00,
+ (byte) 0x78, (byte) 0x01, (byte) 0x08, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33,
+ (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x30, (byte) 0x31,
+ (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38,
+ (byte) 0x39, (byte) 0x41, (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46,
+ (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36,
+ (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x41, (byte) 0x42, (byte) 0x43, (byte) 0x44,
+ (byte) 0x45, (byte) 0x46, (byte) 0x03
+ };
+ /* This line is added manually. */
+ char[] stub = new char[8388602]; Arrays.fill(stub, 'c'); String hex = "0123456789ABCDEF";
+ checkSynth(
+ /*
+ * main_header: 24
+ * metablock_header_easy: 8388605, 0 // 2^23 - 3 = shortest 22-bit distance
+ * command_easy: 8388602, "abc", 1
+ * metablock_header_begin: 0, 0, 3, 0
+ * vlq_blocktypes: 1 // num litetal block types
+ * vlq_blocktypes: 1 // num command block types
+ * vlq_blocktypes: 1 // num distance block types
+ * ndirect: 0, 0
+ * bits: "00" // literal context modes
+ * vlq_blocktypes: 1 // num literal Huffman trees
+ * // command has no context -> num trees == num block types
+ * vlq_blocktypes: 1 // num distance Huffman trees
+ * huffman_fixed: 256
+ * huffman_fixed: 704
+ * // Begin of distance Huffman tree. First 15 codes have lengths 1 to 15.
+ * // Symbol that corresponds to first half of 22-bit distance range is also
+ * // 15. All other symbols are 0.
+ * hskip: 0
+ * clcl_ordered: 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4, 5,5,5,5
+ * set_prefix_cl_rle: "0000", "0001", "0010", "0011", \
+ * "0100", "0101", "0110", "0111", \
+ * "1000", "1001", "1010", "1011", \
+ * "1100", "1101", \
+ * "11100", "11101", "11110", "11111"
+ * cl_rle: 1
+ * cl_rle: 2
+ * cl_rle: 3
+ * cl_rle: 4
+ * cl_rle: 5
+ * cl_rle: 6
+ * cl_rle: 7
+ * cl_rle: 8
+ * cl_rle: 9
+ * cl_rle: 10
+ * cl_rle: 11
+ * cl_rle: 12
+ * cl_rle: 13
+ * cl_rle: 14
+ * cl_rle: 15
+ * cl_rle_rep_0: 43
+ * cl_rle: 15 // literal number 97, that is, the letter 'a'
+ * // end of literal Huffman tree
+ * command_inscopy_easy: 0, 3 // Insert 0, copy 3
+ * // 15 bits of distance code plus 22 extra bits
+ * command_dist_bits: "111111111111111", "0000000000000000000000"
+ * metablock_uncompressed: "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
+ * metablock_lastempty
+ */
+ compressed,
+ true,
+ /* This line is modified manually. */
+ "abc" + new String(stub) + "abc" + hex + hex + hex
+ );
+ }
+
+ @Test
+ public void testTooManySymbolsRepeated() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x80,
+ (byte) 0xc3, (byte) 0x3d, (byte) 0x80, (byte) 0x58, (byte) 0x82, (byte) 0x0c, (byte) 0x00,
+ (byte) 0xc0, (byte) 0xc1, (byte) 0x96, (byte) 0x49, (byte) 0x0c, (byte) 0x90, (byte) 0x00,
+ (byte) 0x00, (byte) 0xb8, (byte) 0xd3, (byte) 0x46, (byte) 0x01, (byte) 0x1a, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * // This test is a copy of CustomHuffmanCode, with changed repeat count.
+ * main_header
+ * metablock_header_begin: 1, 0, 4, 0
+ * metablock_header_trivial_context
+ * hskip: 0
+ * clcl_ordered: 0,3,0,0,0,0,0,0,3,2,0,0,0,0,0,0,1,0
+ * set_prefix_cl_rle: "", "110", "", "", "", "", "", "", "111", "10",\
+ * "", "", "", "", "", "", "0", ""
+ * cl_rle: 8
+ * cl_rle_rep: 9, 96
+ * cl_rle: 1
+ * cl_rle_rep: 9, 159 // 1 + 96 + 1 + 159 = 257 > 256 = alphabet size
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 4, 0
+ * command_literal_bits: 0, 0, 0, 101100010
+ */
+ compressed,
+ false,
+ "aaab"
+ );
+ }
+
+ @Test
+ public void testTransformedDictWord() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x09, (byte) 0x01, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * // The stream consists of a transformed dictionary word.
+ * main_header
+ * metablock_header_easy: 9, 1
+ * command_inscopy_easy: 0, 4
+ * command_dist_easy: 5121 // 5 << 10 + 1
+ */
+ compressed,
+ true,
+ "time the "
+ );
+ }
+
+ @Test
+ public void testTransformedDictWordTooLong() {
+ byte[] compressed = {
+ (byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
+ (byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
+ (byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
+ (byte) 0x1b, (byte) 0x41, (byte) 0x09, (byte) 0x01, (byte) 0x01
+ };
+ checkSynth(
+ /*
+ * // Has a transformed dictionary word that goes over the end of the
+ * // meta-block, but the base dictionary word fits in the meta-block.
+ * // Same as TransformedDictWord, but with a shorter meta-block length.
+ * main_header
+ * metablock_header_easy: 4, 1
+ * command_inscopy_easy: 0, 4
+ * command_dist_easy: 5121 // 5 << 10 + 1
+ */
+ compressed,
+ false,
+ ""
+ );
+ }
+
+ @Test
+ public void testZeroCostLiterals() {
+ byte[] compressed = {
+ (byte) 0x9b, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x20, (byte) 0x54,
+ (byte) 0x00, (byte) 0x00, (byte) 0x38, (byte) 0xd8, (byte) 0x32, (byte) 0x89, (byte) 0x01,
+ (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x77, (byte) 0xda, (byte) 0xcc, (byte) 0xe1,
+ (byte) 0x7b, (byte) 0xfa, (byte) 0x0f
+ };
+ /* This lines is added manually. */
+ char[] expected = new char[16777216]; Arrays.fill(expected, '*');
+ checkSynth(
+ /*
+ * main_header
+ * metablock_header_begin: 1, 0, 16777216, 0
+ * metablock_header_trivial_context
+ * huffman_simple: 0,1,256, 42 // Single symbol alphabet
+ * huffman_fixed: 704
+ * huffman_fixed: 64
+ * command_inscopy_easy: 16777216, 0
+ * // 16777216 times 0 bits
+ */
+ compressed,
+ true,
+ /* This line is modified manually. */
+ new String(expected)
+ );
+ }
+
+/* GENERATED CODE END */
+
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Transform.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Transform.java
new file mode 100644
index 000000000..3279ee739
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Transform.java
@@ -0,0 +1,236 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Transformations on dictionary words.
+ *
+ * Transform descriptor is a triplet: {prefix, operator, suffix}.
+ * "prefix" and "suffix" are short strings inserted before and after transformed dictionary word.
+ * "operator" is applied to dictionary word itself.
+ *
+ * Some operators has "built-in" parameters, i.e. parameter is defined by operator ordinal. Other
+ * operators have "external" parameters, supplied via additional table encoded in shared dictionary.
+ *
+ * Operators:
+ * - IDENTITY (0): dictionary word is inserted "as is"
+ * - OMIT_LAST_N (1 - 9): last N octets of dictionary word are not inserted; N == ordinal
+ * - OMIT_FIRST_M (12-20): first M octets of dictionary word are not inserted; M == ordinal - 11
+ * - UPPERCASE_FIRST (10): first "scalar" is XOR'ed with number 32
+ * - UPPERCASE_ALL (11): all "scalars" are XOR'ed with number 32
+ * - SHIFT_FIRST (21): first "scalar" is shifted by number form parameter table
+ * - SHIFT_ALL (22): all "scalar" is shifted by number form parameter table
+ *
+ * Here "scalar" is a variable length character coding similar to UTF-8 encoding.
+ * UPPERCASE_XXX / SHIFT_XXX operators were designed to change the case of UTF-8 encoded characters.
+ * While UPPERCASE_XXX works well only on ASCII charset, SHIFT is much more generic and could be
+ * used for most (all?) alphabets.
+ */
+final class Transform {
+
+ static final class Transforms {
+ final int numTransforms;
+ final int[] triplets;
+ final byte[] prefixSuffixStorage;
+ final int[] prefixSuffixHeads;
+ final short[] params;
+
+ Transforms(int numTransforms, int prefixSuffixLen, int prefixSuffixCount) {
+ this.numTransforms = numTransforms;
+ this.triplets = new int[numTransforms * 3];
+ this.params = new short[numTransforms];
+ this.prefixSuffixStorage = new byte[prefixSuffixLen];
+ this.prefixSuffixHeads = new int[prefixSuffixCount + 1];
+ }
+ }
+
+ static final int NUM_RFC_TRANSFORMS = 121;
+ static final Transforms RFC_TRANSFORMS = new Transforms(NUM_RFC_TRANSFORMS, 167, 50);
+
+ private static final int OMIT_FIRST_LAST_LIMIT = 9;
+
+ private static final int IDENTITY = 0;
+ private static final int OMIT_LAST_BASE = IDENTITY + 1 - 1; // there is no OMIT_LAST_0.
+ private static final int UPPERCASE_FIRST = OMIT_LAST_BASE + OMIT_FIRST_LAST_LIMIT + 1;
+ private static final int UPPERCASE_ALL = UPPERCASE_FIRST + 1;
+ private static final int OMIT_FIRST_BASE = UPPERCASE_ALL + 1 - 1; // there is no OMIT_FIRST_0.
+ private static final int SHIFT_FIRST = OMIT_FIRST_BASE + OMIT_FIRST_LAST_LIMIT + 1;
+ private static final int SHIFT_ALL = SHIFT_FIRST + 1;
+
+ // Bundle of 0-terminated strings.
+ private static final String PREFIX_SUFFIX_SRC = "# #s #, #e #.# the #.com/#\u00C2\u00A0# of # and"
+ + " # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing"
+ + " #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #"
+ + "ous #";
+ private static final String TRANSFORMS_SRC = " !! ! , *! &! \" ! ) * * - ! # ! #!*! "
+ + "+ ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : "
+ + " ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F "
+ + " G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D "
+ + " Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K";
+
+ private static void unpackTransforms(byte[] prefixSuffix,
+ int[] prefixSuffixHeads, int[] transforms, String prefixSuffixSrc, String transformsSrc) {
+ int n = prefixSuffixSrc.length();
+ int index = 1;
+ int j = 0;
+ for (int i = 0; i < n; ++i) {
+ char c = prefixSuffixSrc.charAt(i);
+ if (c == 35) { // == #
+ prefixSuffixHeads[index++] = j;
+ } else {
+ prefixSuffix[j++] = (byte) c;
+ }
+ }
+
+ for (int i = 0; i < NUM_RFC_TRANSFORMS * 3; ++i) {
+ transforms[i] = transformsSrc.charAt(i) - 32;
+ }
+ }
+
+ static {
+ unpackTransforms(RFC_TRANSFORMS.prefixSuffixStorage, RFC_TRANSFORMS.prefixSuffixHeads,
+ RFC_TRANSFORMS.triplets, PREFIX_SUFFIX_SRC, TRANSFORMS_SRC);
+ }
+
+ static int transformDictionaryWord(byte[] dst, int dstOffset, ByteBuffer src, int srcOffset,
+ int len, Transforms transforms, int transformIndex) {
+ int offset = dstOffset;
+ int[] triplets = transforms.triplets;
+ byte[] prefixSuffixStorage = transforms.prefixSuffixStorage;
+ int[] prefixSuffixHeads = transforms.prefixSuffixHeads;
+ int transformOffset = 3 * transformIndex;
+ int prefixIdx = triplets[transformOffset];
+ int transformType = triplets[transformOffset + 1];
+ int suffixIdx = triplets[transformOffset + 2];
+ int prefix = prefixSuffixHeads[prefixIdx];
+ int prefixEnd = prefixSuffixHeads[prefixIdx + 1];
+ int suffix = prefixSuffixHeads[suffixIdx];
+ int suffixEnd = prefixSuffixHeads[suffixIdx + 1];
+
+ int omitFirst = transformType - OMIT_FIRST_BASE;
+ int omitLast = transformType - OMIT_LAST_BASE;
+ if (omitFirst < 1 || omitFirst > OMIT_FIRST_LAST_LIMIT) {
+ omitFirst = 0;
+ }
+ if (omitLast < 1 || omitLast > OMIT_FIRST_LAST_LIMIT) {
+ omitLast = 0;
+ }
+
+ // Copy prefix.
+ while (prefix != prefixEnd) {
+ dst[offset++] = prefixSuffixStorage[prefix++];
+ }
+
+ // Copy trimmed word.
+ if (omitFirst > len) {
+ omitFirst = len;
+ }
+ srcOffset += omitFirst;
+ len -= omitFirst;
+ len -= omitLast;
+ int i = len;
+ while (i > 0) {
+ dst[offset++] = src.get(srcOffset++);
+ i--;
+ }
+
+ // Ferment.
+ if (transformType == UPPERCASE_FIRST || transformType == UPPERCASE_ALL) {
+ int uppercaseOffset = offset - len;
+ if (transformType == UPPERCASE_FIRST) {
+ len = 1;
+ }
+ while (len > 0) {
+ int c0 = dst[uppercaseOffset] & 0xFF;
+ if (c0 < 0xC0) {
+ if (c0 >= 97 && c0 <= 122) { // in [a..z] range
+ dst[uppercaseOffset] ^= (byte) 32;
+ }
+ uppercaseOffset += 1;
+ len -= 1;
+ } else if (c0 < 0xE0) {
+ dst[uppercaseOffset + 1] ^= (byte) 32;
+ uppercaseOffset += 2;
+ len -= 2;
+ } else {
+ dst[uppercaseOffset + 2] ^= (byte) 5;
+ uppercaseOffset += 3;
+ len -= 3;
+ }
+ }
+ } else if (transformType == SHIFT_FIRST || transformType == SHIFT_ALL) {
+ int shiftOffset = offset - len;
+ short param = transforms.params[transformIndex];
+ /* Limited sign extension: scalar < (1 << 24). */
+ int scalar = (param & 0x7FFF) + (0x1000000 - (param & 0x8000));
+ while (len > 0) {
+ int step = 1;
+ int c0 = dst[shiftOffset] & 0xFF;
+ if (c0 < 0x80) {
+ /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
+ scalar += c0;
+ dst[shiftOffset] = (byte) (scalar & 0x7F);
+ } else if (c0 < 0xC0) {
+ /* Continuation / 10AAAAAA. */
+ } else if (c0 < 0xE0) {
+ /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
+ if (len >= 2) {
+ byte c1 = dst[shiftOffset + 1];
+ scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
+ dst[shiftOffset] = (byte) (0xC0 | ((scalar >> 6) & 0x1F));
+ dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | (scalar & 0x3F));
+ step = 2;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF0) {
+ /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
+ if (len >= 3) {
+ byte c1 = dst[shiftOffset + 1];
+ byte c2 = dst[shiftOffset + 2];
+ scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
+ dst[shiftOffset] = (byte) (0xE0 | ((scalar >> 12) & 0x0F));
+ dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 2] = (byte) ((c2 & 0xC0) | (scalar & 0x3F));
+ step = 3;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF8) {
+ /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
+ if (len >= 4) {
+ byte c1 = dst[shiftOffset + 1];
+ byte c2 = dst[shiftOffset + 2];
+ byte c3 = dst[shiftOffset + 3];
+ scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
+ dst[shiftOffset] = (byte) (0xF0 | ((scalar >> 18) & 0x07));
+ dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 12) & 0x3F));
+ dst[shiftOffset + 2] = (byte) ((c2 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 3] = (byte) ((c3 & 0xC0) | (scalar & 0x3F));
+ step = 4;
+ } else {
+ step = len;
+ }
+ }
+ shiftOffset += step;
+ len -= step;
+ if (transformType == SHIFT_FIRST) {
+ len = 0;
+ }
+ }
+ }
+
+ // Copy suffix.
+ while (suffix != suffixEnd) {
+ dst[offset++] = prefixSuffixStorage[suffix++];
+ }
+
+ return offset - dstOffset;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/TransformTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/TransformTest.java
new file mode 100644
index 000000000..6e04f0dc6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/TransformTest.java
@@ -0,0 +1,71 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link Transform}.
+ */
+@RunWith(JUnit4.class)
+public class TransformTest {
+
+ private static long crc64(byte[] data) {
+ long crc = -1;
+ for (int i = 0; i < data.length; ++i) {
+ long c = (crc ^ (long) (data[i] & 0xFF)) & 0xFF;
+ for (int k = 0; k < 8; k++) {
+ c = (c >>> 1) ^ (-(c & 1L) & -3932672073523589310L);
+ }
+ crc = c ^ (crc >>> 8);
+ }
+ return ~crc;
+ }
+
+ @Test
+ public void testTrimAll() {
+ byte[] output = new byte[0];
+ byte[] input = {119, 111, 114, 100}; // "word"
+ Transform.transformDictionaryWord(output, 0,
+ ByteBuffer.wrap(input), 0, input.length, Transform.RFC_TRANSFORMS, 39);
+ byte[] expectedOutput = new byte[0];
+ assertArrayEquals(expectedOutput, output);
+ }
+
+ @Test
+ public void testCapitalize() {
+ byte[] output = new byte[6];
+ byte[] input = {113, -61, -90, -32, -92, -86}; // "qæप"
+ Transform.transformDictionaryWord(output, 0,
+ ByteBuffer.wrap(input), 0, input.length, Transform.RFC_TRANSFORMS, 44);
+ byte[] expectedOutput = {81, -61, -122, -32, -92, -81}; // "QÆय"
+ assertArrayEquals(expectedOutput, output);
+ }
+
+ @Test
+ public void testAllTransforms() {
+ /* This string allows to apply all transforms: head and tail cutting, capitalization and
+ turning to upper case; all results will be mutually different. */
+ // "o123456789abcdef"
+ byte[] testWord = {111, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
+ byte[] output = new byte[2259];
+ int offset = 0;
+ for (int i = 0; i < Transform.NUM_RFC_TRANSFORMS; ++i) {
+ offset += Transform.transformDictionaryWord(output, offset,
+ ByteBuffer.wrap(testWord), 0, testWord.length, Transform.RFC_TRANSFORMS, i);
+ output[offset++] = -1;
+ }
+ assertEquals(output.length, offset);
+ assertEquals(8929191060211225186L, crc64(output));
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Utils.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Utils.java
new file mode 100644
index 000000000..2d04aecd3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/Utils.java
@@ -0,0 +1,102 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.dec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.Buffer;
+
+/**
+ * A set of utility methods.
+ */
+final class Utils {
+
+ private static final byte[] BYTE_ZEROES = new byte[1024];
+
+ private static final int[] INT_ZEROES = new int[1024];
+
+ /**
+ * Fills byte array with zeroes.
+ *
+ * <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
+ * less than 16.
+ *
+ * @param dest array to fill with zeroes
+ * @param offset the first byte to fill
+ * @param length number of bytes to change
+ */
+ static void fillBytesWithZeroes(byte[] dest, int start, int end) {
+ int cursor = start;
+ while (cursor < end) {
+ int step = Math.min(cursor + 1024, end) - cursor;
+ System.arraycopy(BYTE_ZEROES, 0, dest, cursor, step);
+ cursor += step;
+ }
+ }
+
+ /**
+ * Fills int array with zeroes.
+ *
+ * <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
+ * less than 16.
+ *
+ * @param dest array to fill with zeroes
+ * @param offset the first item to fill
+ * @param length number of item to change
+ */
+ static void fillIntsWithZeroes(int[] dest, int start, int end) {
+ int cursor = start;
+ while (cursor < end) {
+ int step = Math.min(cursor + 1024, end) - cursor;
+ System.arraycopy(INT_ZEROES, 0, dest, cursor, step);
+ cursor += step;
+ }
+ }
+
+ static void copyBytesWithin(byte[] bytes, int target, int start, int end) {
+ System.arraycopy(bytes, start, bytes, target, end - start);
+ }
+
+ static int readInput(InputStream src, byte[] dst, int offset, int length) {
+ try {
+ return src.read(dst, offset, length);
+ } catch (IOException e) {
+ throw new BrotliRuntimeException("Failed to read input", e);
+ }
+ }
+
+ static void closeInput(InputStream src) throws IOException {
+ src.close();
+ }
+
+ static byte[] toUsAsciiBytes(String src) {
+ try {
+ // NB: String#getBytes(String) is present in JDK 1.1, while other variants require JDK 1.6 and
+ // above.
+ return src.getBytes("US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // cannot happen
+ }
+ }
+
+ // Crazy pills factory: code compiled for JDK8 does not work on JRE9.
+ static void flipBuffer(Buffer buffer) {
+ buffer.flip();
+ }
+
+ static int isDebugMode() {
+ boolean assertsEnabled = Boolean.parseBoolean(System.getProperty("BROTLI_ENABLE_ASSERTS"));
+ return assertsEnabled ? 1 : 0;
+ }
+
+ // See BitReader.LOG_BITNESS
+ static int getLogBintness() {
+ boolean isLongExpensive = Boolean.parseBoolean(System.getProperty("BROTLI_32_BIT_CPU"));
+ return isLongExpensive ? 5 : 6;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/build_defs.bzl b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/build_defs.bzl
new file mode 100644
index 000000000..d0a015c0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/build_defs.bzl
@@ -0,0 +1,34 @@
+"""Utilities for Java brotli tests."""
+
+_TEST_JVM_FLAGS = [
+ "-DBROTLI_ENABLE_ASSERTS=true",
+]
+
+def brotli_java_test(name, main_class = None, jvm_flags = None, **kwargs):
+ """test duplication rule that creates 32/64-bit test pair."""
+
+ if jvm_flags == None:
+ jvm_flags = []
+ jvm_flags = jvm_flags + _TEST_JVM_FLAGS
+
+ test_package = native.package_name().replace("/", ".")
+ if main_class == None:
+ test_class = test_package + "." + name
+ else:
+ test_class = None
+
+ native.java_test(
+ name = name + "_32",
+ main_class = main_class,
+ test_class = test_class,
+ jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=true"],
+ **kwargs
+ )
+
+ native.java_test(
+ name = name + "_64",
+ main_class = main_class,
+ test_class = test_class,
+ jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=false"],
+ **kwargs
+ )
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/pom.xml b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/pom.xml
new file mode 100644
index 000000000..946fddf2d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/pom.xml
@@ -0,0 +1,172 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.brotli</groupId>
+ <artifactId>parent</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>dec</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>${project.groupId}:${project.artifactId}</name>
+
+ <properties>
+ <manifestdir>${project.build.directory}/osgi</manifestdir>
+ <manifestfile>${manifestdir}/MANIFEST.MF</manifestfile>
+ </properties>
+
+ <build>
+ <sourceDirectory>../../..</sourceDirectory>
+ <testSourceDirectory>../../..</testSourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>org/brotli/dec/*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*Test*.java</exclude>
+ </excludes>
+ <testIncludes>
+ <include>org/brotli/dec/*Test*.java</include>
+ </testIncludes>
+ <testExcludes>
+ <exclude>org/brotli/dec/SetDictionaryTest.java</exclude>
+ </testExcludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>3.0.0-M3</version>
+ <configuration>
+ <systemPropertyVariables>
+ <BROTLI_ENABLE_ASSERTS>true</BROTLI_ENABLE_ASSERTS>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>org/brotli/dec/*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*Test*.java</exclude>
+ </excludes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <sourcepath>.</sourcepath>
+ <sourceFileExcludes>
+ <exclude>**/*Test*.java</exclude>
+ </sourceFileExcludes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>3.0.1</version>
+ <configuration>
+ <archive>
+ <forced>true</forced>
+ </archive>
+ <excludeDependencies>true</excludeDependencies>
+ <manifestLocation>${manifestdir}</manifestLocation>
+ <instructions>
+ <_nouses>true</_nouses>
+ <Bundle-SymbolicName>org.brotli.${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Description>${project.description}</Bundle-Description>
+ <Export-Package>org.brotli.dec;version=${project.version};-noimport:=true</Export-Package>
+ <Private-Package></Private-Package>
+ <Import-Package>*</Import-Package>
+ <DynamicImport-Package></DynamicImport-Package>
+ <Bundle-DocURL>${project.url}</Bundle-DocURL>
+ </instructions>
+ </configuration>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.5</version>
+ <configuration>
+ <archive>
+ <manifestFile>${manifestfile}</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-license</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.outputDirectory}/META-INF</outputDirectory>
+ <resources>
+ <resource>
+ <directory>../../../../</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/proguard.pgcfg b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/proguard.pgcfg
new file mode 100644
index 000000000..4c545dce5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/dec/proguard.pgcfg
@@ -0,0 +1,6 @@
+# DictionaryData is an optionally / dynamically loaded built-in dictionary.
+-keep class org.brotli.dec.DictionaryData
+
+# We get the fully-qualified name of DictionaryData from Dictionary, so avoid
+# renaming it.
+-keepnames class org.brotli.dec.Dictionary
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BUILD
new file mode 100644
index 000000000..5b773251a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BUILD
@@ -0,0 +1,73 @@
+# Description:
+# Integration test runner + corpus for Java port of Brotli decoder.
+
+java_library(
+ name = "brotli_jni_test_base",
+ srcs = ["BrotliJniTestBase.java"],
+ visibility = [
+ "//org/brotli/wrapper/common:__pkg__",
+ "//org/brotli/wrapper/dec:__pkg__",
+ "//org/brotli/wrapper/enc:__pkg__",
+ ],
+)
+
+java_library(
+ name = "bundle_helper",
+ srcs = ["BundleHelper.java"],
+ visibility = [
+ "//org/brotli/wrapper/dec:__pkg__",
+ "//org/brotli/wrapper/enc:__pkg__",
+ ],
+)
+
+java_library(
+ name = "bundle_checker",
+ srcs = ["BundleChecker.java"],
+ deps = [
+ ":bundle_helper",
+ "//org/brotli/dec",
+ ],
+)
+
+java_binary(
+ name = "bundle_checker_bin",
+ main_class = "org.brotli.integration.BundleChecker",
+ runtime_deps = [":bundle_checker"],
+)
+
+java_test(
+ name = "bundle_checker_data_test",
+ args = ["org/brotli/integration/test_data.zip"],
+ data = ["test_data.zip"],
+ main_class = "org.brotli.integration.BundleChecker",
+ use_testrunner = 0,
+ runtime_deps = [":bundle_checker"],
+)
+
+java_test(
+ name = "bundle_checker_fuzz_test",
+ args = [
+ "-s",
+ "org/brotli/integration/fuzz_data.zip",
+ ],
+ data = ["fuzz_data.zip"],
+ main_class = "org.brotli.integration.BundleChecker",
+ use_testrunner = 0,
+ runtime_deps = [":bundle_checker"],
+)
+
+filegroup(
+ name = "test_data",
+ srcs = ["test_data.zip"],
+ visibility = [
+ "//org/brotli/wrapper/dec:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "test_corpus",
+ srcs = ["test_corpus.zip"],
+ visibility = [
+ "//org/brotli/wrapper/enc:__pkg__",
+ ],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BrotliJniTestBase.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BrotliJniTestBase.java
new file mode 100644
index 000000000..4d699d5cf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BrotliJniTestBase.java
@@ -0,0 +1,13 @@
+package org.brotli.integration;
+
+/**
+ * Optionally loads brotli JNI wrapper native library.
+ */
+public class BrotliJniTestBase {
+ static {
+ String jniLibrary = System.getProperty("BROTLI_JNI_LIBRARY");
+ if (jniLibrary != null) {
+ System.load(new java.io.File(jniLibrary).getAbsolutePath());
+ }
+ }
+} \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleChecker.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleChecker.java
new file mode 100644
index 000000000..e3ddb33b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleChecker.java
@@ -0,0 +1,112 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.integration;
+
+import org.brotli.dec.BrotliInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Decompress files and (optionally) checks their checksums.
+ *
+ * <p> File are read from ZIP archive passed as an array of bytes. Multiple checkers negotiate about
+ * task distribution via shared AtomicInteger counter.
+ * <p> All entries are expected to be valid brotli compressed streams and output CRC64 checksum
+ * is expected to match the checksum hex-encoded in the first part of entry name.
+ */
+public class BundleChecker implements Runnable {
+ private final AtomicInteger nextJob;
+ private final InputStream input;
+ private final boolean sanityCheck;
+
+ /**
+ * @param sanityCheck do not calculate checksum and ignore {@link IOException}.
+ */
+ public BundleChecker(InputStream input, AtomicInteger nextJob, boolean sanityCheck) {
+ this.input = input;
+ this.nextJob = nextJob;
+ this.sanityCheck = sanityCheck;
+ }
+
+ private long decompressAndCalculateCrc(ZipInputStream input) throws IOException {
+ /* Do not allow entry readers to close the whole ZipInputStream. */
+ FilterInputStream entryStream = new FilterInputStream(input) {
+ @Override
+ public void close() {}
+ };
+
+ BrotliInputStream decompressedStream = new BrotliInputStream(entryStream);
+ long crc;
+ try {
+ crc = BundleHelper.fingerprintStream(decompressedStream);
+ } finally {
+ decompressedStream.close();
+ }
+ return crc;
+ }
+
+ @Override
+ public void run() {
+ String entryName = "";
+ ZipInputStream zis = new ZipInputStream(input);
+ try {
+ int entryIndex = 0;
+ ZipEntry entry;
+ int jobIndex = nextJob.getAndIncrement();
+ while ((entry = zis.getNextEntry()) != null) {
+ if (entry.isDirectory()) {
+ continue;
+ }
+ if (entryIndex++ != jobIndex) {
+ zis.closeEntry();
+ continue;
+ }
+ entryName = entry.getName();
+ long entryCrc = BundleHelper.getExpectedFingerprint(entryName);
+ try {
+ if (entryCrc != decompressAndCalculateCrc(zis) && !sanityCheck) {
+ throw new RuntimeException("CRC mismatch");
+ }
+ } catch (IOException iox) {
+ if (!sanityCheck) {
+ throw new RuntimeException("Decompression failed", iox);
+ }
+ }
+ zis.closeEntry();
+ entryName = "";
+ jobIndex = nextJob.getAndIncrement();
+ }
+ zis.close();
+ input.close();
+ } catch (Throwable ex) {
+ throw new RuntimeException(entryName, ex);
+ }
+ }
+
+ public static void main(String[] args) throws FileNotFoundException {
+ int argsOffset = 0;
+ boolean sanityCheck = false;
+ if (args.length != 0) {
+ if (args[0].equals("-s")) {
+ sanityCheck = true;
+ argsOffset = 1;
+ }
+ }
+ if (args.length == argsOffset) {
+ throw new RuntimeException("Usage: BundleChecker [-s] <fileX.zip> ...");
+ }
+ for (int i = argsOffset; i < args.length; ++i) {
+ new BundleChecker(new FileInputStream(args[i]), new AtomicInteger(0), sanityCheck).run();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleHelper.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleHelper.java
new file mode 100644
index 000000000..0eab7bcb1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/BundleHelper.java
@@ -0,0 +1,113 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.integration;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Utilities to work test files bundles in zip archive.
+ */
+public class BundleHelper {
+ private BundleHelper() { }
+
+ public static List<String> listEntries(InputStream input) throws IOException {
+ List<String> result = new ArrayList<String>();
+ ZipInputStream zis = new ZipInputStream(input);
+ ZipEntry entry;
+ try {
+ while ((entry = zis.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ result.add(entry.getName());
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+ return result;
+ }
+
+ public static byte[] readStream(InputStream input) throws IOException {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[65536];
+ int bytesRead;
+ while ((bytesRead = input.read(buffer)) != -1) {
+ result.write(buffer, 0, bytesRead);
+ }
+ return result.toByteArray();
+ }
+
+ public static byte[] readEntry(InputStream input, String entryName) throws IOException {
+ ZipInputStream zis = new ZipInputStream(input);
+ ZipEntry entry;
+ try {
+ while ((entry = zis.getNextEntry()) != null) {
+ if (entry.getName().equals(entryName)) {
+ byte[] result = readStream(zis);
+ zis.closeEntry();
+ return result;
+ }
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+ /* entry not found */
+ return null;
+ }
+
+ /** ECMA CRC64 polynomial. */
+ private static final long CRC_64_POLY =
+ new BigInteger("C96C5795D7870F42", 16).longValue();
+
+ /**
+ * Rolls CRC64 calculation.
+ *
+ * <p> {@code CRC64(data) = -1 ^ updateCrc64((... updateCrc64(-1, firstBlock), ...), lastBlock);}
+ * <p> This simple and reliable checksum is chosen to make is easy to calculate the same value
+ * across the variety of languages (C++, Java, Go, ...).
+ */
+ public static long updateCrc64(long crc, byte[] data, int offset, int length) {
+ for (int i = offset; i < offset + length; ++i) {
+ long c = (crc ^ (long) (data[i] & 0xFF)) & 0xFF;
+ for (int k = 0; k < 8; k++) {
+ c = ((c & 1) == 1) ? CRC_64_POLY ^ (c >>> 1) : c >>> 1;
+ }
+ crc = c ^ (crc >>> 8);
+ }
+ return crc;
+ }
+
+ /**
+ * Calculates CRC64 of stream contents.
+ */
+ public static long fingerprintStream(InputStream input) throws IOException {
+ byte[] buffer = new byte[65536];
+ long crc = -1;
+ while (true) {
+ int len = input.read(buffer);
+ if (len <= 0) {
+ break;
+ }
+ crc = updateCrc64(crc, buffer, 0, len);
+ }
+ return ~crc;
+ }
+
+ public static long getExpectedFingerprint(String entryName) {
+ int dotIndex = entryName.indexOf('.');
+ String entryCrcString = (dotIndex == -1) ? entryName : entryName.substring(0, dotIndex);
+ return new BigInteger(entryCrcString, 16).longValue();
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/fuzz_data.zip b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/fuzz_data.zip
new file mode 100644
index 000000000..7a7eedaa0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/fuzz_data.zip
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/pom.xml b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/pom.xml
new file mode 100644
index 000000000..2858a12ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/pom.xml
@@ -0,0 +1,65 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.brotli</groupId>
+ <artifactId>parent</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>integration</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>${project.groupId}:${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.brotli</groupId>
+ <artifactId>dec</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>.</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.5.0</version>
+ <executions>
+ <execution>
+ <id>data</id>
+ <phase>test</phase>
+ <goals>
+ <goal>java</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <mainClass>org.brotli.integration.BundleChecker</mainClass>
+ <arguments>
+ <argument>test_data.zip</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>fuzz</id>
+ <phase>test</phase>
+ <goals>
+ <goal>java</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <mainClass>org.brotli.integration.BundleChecker</mainClass>
+ <arguments>
+ <argument>-s</argument>
+ <argument>fuzz_data.zip</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_corpus.zip b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_corpus.zip
new file mode 100644
index 000000000..8450112d9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_corpus.zip
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_data.zip b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_data.zip
new file mode 100644
index 000000000..15ed86207
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/integration/test_data.zip
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/pom.xml b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/pom.xml
new file mode 100644
index 000000000..9a7abd095
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/pom.xml
@@ -0,0 +1,101 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.brotli</groupId>
+ <artifactId>parent</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <name>${project.groupId}:${project.artifactId}</name>
+ <description>Brotli is a generic-purpose lossless compression algorithm.</description>
+ <url>http://brotli.org</url>
+ <licenses>
+ <license>
+ <name>MIT License</name>
+ <url>http://www.opensource.org/licenses/mit-license.php</url>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <organization>Google</organization>
+ <organizationUrl>https://github.com/google</organizationUrl>
+ </developer>
+ </developers>
+ <scm>
+ <connection>scm:git:git://github.com/google/brotli.git</connection>
+ <developerConnection>scm:git:ssh://git@github.com/google/brotli.git</developerConnection>
+ <url>https://github.com/google/brotli</url>
+ </scm>
+
+ <modules>
+ <module>dec</module>
+ </modules>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+
+ <profiles>
+ <profile>
+ <id>release-sign-artifacts</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>ossrh</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>false</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BUILD
new file mode 100644
index 000000000..7c3480a09
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BUILD
@@ -0,0 +1,61 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+filegroup(
+ name = "jni_src",
+ srcs = ["common_jni.cc"],
+)
+
+filegroup(
+ name = "brotli_jni_no_dictionary_data",
+ srcs = ["//:brotli_jni_no_dictionary_data.dll"],
+)
+
+java_library(
+ name = "common",
+ srcs = glob(
+ ["*.java"],
+ exclude = ["*Test*.java"],
+ ),
+ resource_jars = ["//:license"],
+)
+
+java_library(
+ name = "test_lib",
+ testonly = 1,
+ srcs = glob(["*Test*.java"]),
+ deps = [
+ ":common",
+ "//org/brotli/dec",
+ "//org/brotli/integration:brotli_jni_test_base",
+ "//org/brotli/wrapper/dec",
+ "@junit_junit//jar",
+ ],
+)
+
+java_test(
+ name = "SetZeroDictionaryTest",
+ size = "small",
+ data = [
+ ":brotli_jni_no_dictionary_data", # Bazel JNI workaround
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
+ ],
+ test_class = "org.brotli.wrapper.common.SetZeroDictionaryTest",
+ runtime_deps = [":test_lib"],
+)
+
+java_test(
+ name = "SetRfcDictionaryTest",
+ size = "small",
+ data = [
+ ":brotli_jni_no_dictionary_data", # Bazel JNI workaround
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
+ ],
+ test_class = "org.brotli.wrapper.common.SetRfcDictionaryTest",
+ runtime_deps = [":test_lib"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BrotliCommon.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BrotliCommon.java
new file mode 100644
index 000000000..9419e42d6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/BrotliCommon.java
@@ -0,0 +1,130 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * JNI wrapper for brotli common.
+ */
+public class BrotliCommon {
+ public static final int RFC_DICTIONARY_SIZE = 122784;
+
+ /* 96cecd2ee7a666d5aa3627d74735b32a */
+ private static final byte[] RFC_DICTIONARY_MD5 = {
+ -106, -50, -51, 46, -25, -90, 102, -43, -86, 54, 39, -41, 71, 53, -77, 42
+ };
+
+ /* 72b41051cb61a9281ba3c4414c289da50d9a7640 */
+ private static final byte[] RFC_DICTIONARY_SHA_1 = {
+ 114, -76, 16, 81, -53, 97, -87, 40, 27, -93, -60, 65, 76, 40, -99, -91, 13, -102, 118, 64
+ };
+
+ /* 20e42eb1b511c21806d4d227d07e5dd06877d8ce7b3a817f378f313653f35c70 */
+ private static final byte[] RFC_DICTIONARY_SHA_256 = {
+ 32, -28, 46, -79, -75, 17, -62, 24, 6, -44, -46, 39, -48, 126, 93, -48,
+ 104, 119, -40, -50, 123, 58, -127, 127, 55, -113, 49, 54, 83, -13, 92, 112
+ };
+
+ private static boolean isDictionaryDataSet;
+ private static final Object mutex = new Object();
+
+ /**
+ * Checks if the given checksum matches MD5 checksum of the RFC dictionary.
+ */
+ public static boolean checkDictionaryDataMd5(byte[] digest) {
+ return Arrays.equals(RFC_DICTIONARY_MD5, digest);
+ }
+
+ /**
+ * Checks if the given checksum matches SHA-1 checksum of the RFC dictionary.
+ */
+ public static boolean checkDictionaryDataSha1(byte[] digest) {
+ return Arrays.equals(RFC_DICTIONARY_SHA_1, digest);
+ }
+
+ /**
+ * Checks if the given checksum matches SHA-256 checksum of the RFC dictionary.
+ */
+ public static boolean checkDictionaryDataSha256(byte[] digest) {
+ return Arrays.equals(RFC_DICTIONARY_SHA_256, digest);
+ }
+
+ /**
+ * Copy bytes to a new direct ByteBuffer.
+ *
+ * Direct byte buffers are used to supply native code with large data chunks.
+ */
+ public static ByteBuffer makeNative(byte[] data) {
+ ByteBuffer result = ByteBuffer.allocateDirect(data.length);
+ result.put(data);
+ return result;
+ }
+
+ /**
+ * Copies data and sets it to be brotli dictionary.
+ */
+ public static void setDictionaryData(byte[] data) {
+ if (data.length != RFC_DICTIONARY_SIZE) {
+ throw new IllegalArgumentException("invalid dictionary size");
+ }
+ synchronized (mutex) {
+ if (isDictionaryDataSet) {
+ return;
+ }
+ setDictionaryData(makeNative(data));
+ }
+ }
+
+ /**
+ * Reads data and sets it to be brotli dictionary.
+ */
+ public static void setDictionaryData(InputStream src) throws IOException {
+ synchronized (mutex) {
+ if (isDictionaryDataSet) {
+ return;
+ }
+ ByteBuffer copy = ByteBuffer.allocateDirect(RFC_DICTIONARY_SIZE);
+ byte[] buffer = new byte[4096];
+ int readBytes;
+ while ((readBytes = src.read(buffer)) != -1) {
+ if (copy.remaining() < readBytes) {
+ throw new IllegalArgumentException("invalid dictionary size");
+ }
+ copy.put(buffer, 0, readBytes);
+ }
+ if (copy.remaining() != 0) {
+ throw new IllegalArgumentException("invalid dictionary size " + copy.remaining());
+ }
+ setDictionaryData(copy);
+ }
+ }
+
+ /**
+ * Sets data to be brotli dictionary.
+ */
+ public static void setDictionaryData(ByteBuffer data) {
+ if (!data.isDirect()) {
+ throw new IllegalArgumentException("direct byte buffer is expected");
+ }
+ if (data.capacity() != RFC_DICTIONARY_SIZE) {
+ throw new IllegalArgumentException("invalid dictionary size");
+ }
+ synchronized (mutex) {
+ if (isDictionaryDataSet) {
+ return;
+ }
+ if (!CommonJNI.nativeSetDictionaryData(data)) {
+ throw new RuntimeException("setting dictionary failed");
+ }
+ isDictionaryDataSet = true;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/CommonJNI.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/CommonJNI.java
new file mode 100644
index 000000000..d6625461b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/CommonJNI.java
@@ -0,0 +1,16 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.common;
+
+import java.nio.ByteBuffer;
+
+/**
+ * JNI wrapper for brotli common.
+ */
+class CommonJNI {
+ static native boolean nativeSetDictionaryData(ByteBuffer data);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java
new file mode 100644
index 000000000..a986eaee4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java
@@ -0,0 +1,74 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.common;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.brotli.dec.Dictionary;
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.wrapper.dec.BrotliInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link BrotliCommon}.
+ */
+@RunWith(JUnit4.class)
+public class SetRfcDictionaryTest extends BrotliJniTestBase {
+
+ @Test
+ public void testRfcDictionaryChecksums() throws NoSuchAlgorithmException {
+ System.err.println(Dictionary.getData().slice().remaining());
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(Dictionary.getData().slice());
+ assertTrue(BrotliCommon.checkDictionaryDataMd5(md5.digest()));
+
+ MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+ sha1.update(Dictionary.getData().slice());
+ assertTrue(BrotliCommon.checkDictionaryDataSha1(sha1.digest()));
+
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ sha256.update(Dictionary.getData().slice());
+ assertTrue(BrotliCommon.checkDictionaryDataSha256(sha256.digest()));
+ }
+
+ @Test
+ public void testSetRfcDictionary() throws IOException {
+ /* "leftdatadataleft" encoded with dictionary words. */
+ byte[] data = {27, 15, 0, 0, 0, 0, -128, -29, -76, 13, 0, 0, 7, 91, 38, 49, 64, 2, 0, -32, 78,
+ 27, 65, -128, 32, 80, 16, 36, 8, 6};
+ BrotliCommon.setDictionaryData(Dictionary.getData());
+
+ BrotliInputStream decoder = new BrotliInputStream(new ByteArrayInputStream(data));
+ byte[] output = new byte[17];
+ int offset = 0;
+ try {
+ int bytesRead;
+ while ((bytesRead = decoder.read(output, offset, 17 - offset)) != -1) {
+ offset += bytesRead;
+ }
+ } finally {
+ decoder.close();
+ }
+ assertEquals(16, offset);
+ byte[] expected = {
+ 'l', 'e', 'f', 't',
+ 'd', 'a', 't', 'a',
+ 'd', 'a', 't', 'a',
+ 'l', 'e', 'f', 't',
+ 0
+ };
+ assertArrayEquals(expected, output);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetZeroDictionaryTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetZeroDictionaryTest.java
new file mode 100644
index 000000000..669939c9f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/SetZeroDictionaryTest.java
@@ -0,0 +1,48 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.common;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.wrapper.dec.BrotliInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link BrotliCommon}.
+ */
+@RunWith(JUnit4.class)
+public class SetZeroDictionaryTest extends BrotliJniTestBase {
+
+ @Test
+ public void testZeroDictionary() throws IOException {
+ /* "leftdatadataleft" encoded with dictionary words. */
+ byte[] data = {27, 15, 0, 0, 0, 0, -128, -29, -76, 13, 0, 0, 7, 91, 38, 49, 64, 2, 0, -32, 78,
+ 27, 65, -128, 32, 80, 16, 36, 8, 6};
+ byte[] dictionary = new byte[BrotliCommon.RFC_DICTIONARY_SIZE];
+ BrotliCommon.setDictionaryData(dictionary);
+
+ BrotliInputStream decoder = new BrotliInputStream(new ByteArrayInputStream(data));
+ byte[] output = new byte[17];
+ int offset = 0;
+ try {
+ int bytesRead;
+ while ((bytesRead = decoder.read(output, offset, 17 - offset)) != -1) {
+ offset += bytesRead;
+ }
+ } finally {
+ decoder.close();
+ }
+ assertEquals(16, offset);
+ assertArrayEquals(new byte[17], output);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/common_jni.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/common_jni.cc
new file mode 100644
index 000000000..c71ca4955
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/common/common_jni.cc
@@ -0,0 +1,47 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <jni.h>
+
+#include "c/common/dictionary.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set data to be brotli dictionary data.
+ *
+ * @param buffer direct ByteBuffer
+ * @returns false if dictionary data was already set; otherwise true
+ */
+JNIEXPORT jint JNICALL
+Java_org_brotli_wrapper_common_CommonJNI_nativeSetDictionaryData(
+ JNIEnv* env, jobject /*jobj*/, jobject buffer) {
+ jobject buffer_ref = env->NewGlobalRef(buffer);
+ if (!buffer_ref) {
+ return false;
+ }
+ uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+ if (!data) {
+ env->DeleteGlobalRef(buffer_ref);
+ return false;
+ }
+
+ BrotliSetDictionaryData(data);
+
+ const BrotliDictionary* dictionary = BrotliGetDictionary();
+ if (dictionary->data != data) {
+ env->DeleteGlobalRef(buffer_ref);
+ } else {
+ /* Don't release reference; it is an intended memory leak. */
+ }
+ return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BUILD
new file mode 100644
index 000000000..d1c8f5ba1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BUILD
@@ -0,0 +1,84 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+filegroup(
+ name = "jni_src",
+ srcs = ["decoder_jni.cc"],
+)
+
+java_library(
+ name = "dec",
+ srcs = glob(
+ ["*.java"],
+ exclude = ["*Test*.java"],
+ ),
+ resource_jars = ["//:license"],
+)
+
+java_library(
+ name = "test_lib",
+ testonly = 1,
+ srcs = glob(["*Test*.java"]),
+ deps = [
+ ":dec",
+ "//org/brotli/integration:brotli_jni_test_base",
+ "//org/brotli/integration:bundle_helper",
+ "@junit_junit//jar",
+ ],
+)
+
+filegroup(
+ name = "brotli_jni",
+ srcs = ["//:brotli_jni.dll"],
+)
+
+filegroup(
+ name = "test_bundle",
+ srcs = ["//org/brotli/integration:test_data"],
+)
+
+java_test(
+ name = "BrotliDecoderChannelTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ test_class = "org.brotli.wrapper.dec.BrotliDecoderChannelTest",
+ runtime_deps = [":test_lib"],
+)
+
+java_test(
+ name = "BrotliInputStreamTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ test_class = "org.brotli.wrapper.dec.BrotliInputStreamTest",
+ runtime_deps = [":test_lib"],
+)
+
+java_test(
+ name = "DecoderTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ test_class = "org.brotli.wrapper.dec.DecoderTest",
+ runtime_deps = [":test_lib"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannel.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannel.java
new file mode 100644
index 000000000..6dfe8f21a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannel.java
@@ -0,0 +1,69 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * ReadableByteChannel that wraps native brotli decoder.
+ */
+public class BrotliDecoderChannel extends Decoder implements ReadableByteChannel {
+ /** The default internal buffer size used by the decoder. */
+ private static final int DEFAULT_BUFFER_SIZE = 16384;
+
+ private final Object mutex = new Object();
+
+ /**
+ * Creates a BrotliDecoderChannel.
+ *
+ * @param source underlying source
+ * @param bufferSize intermediate buffer size
+ * @param customDictionary initial LZ77 dictionary
+ */
+ public BrotliDecoderChannel(ReadableByteChannel source, int bufferSize) throws IOException {
+ super(source, bufferSize);
+ }
+
+ public BrotliDecoderChannel(ReadableByteChannel source) throws IOException {
+ this(source, DEFAULT_BUFFER_SIZE);
+ }
+
+ @Override
+ public boolean isOpen() {
+ synchronized (mutex) {
+ return !closed;
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ synchronized (mutex) {
+ super.close();
+ }
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ synchronized (mutex) {
+ if (closed) {
+ throw new ClosedChannelException();
+ }
+ int result = 0;
+ while (dst.hasRemaining()) {
+ int outputSize = decode();
+ if (outputSize <= 0) {
+ return result == 0 ? outputSize : result;
+ }
+ result += consume(dst);
+ }
+ return result;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannelTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannelTest.java
new file mode 100644
index 000000000..71d8f68ad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliDecoderChannelTest.java
@@ -0,0 +1,84 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.dec.BrotliDecoderChannel}. */
+@RunWith(AllTests.class)
+public class BrotliDecoderChannelTest extends BrotliJniTestBase {
+
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new ChannelTestCase(entry));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class ChannelTestCase extends TestCase {
+ final String entryName;
+ ChannelTestCase(String entryName) {
+ super("BrotliDecoderChannelTest." + entryName);
+ this.entryName = entryName;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ BrotliDecoderChannelTest.run(entryName);
+ }
+ }
+
+ private static void run(String entryName) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] compressed;
+ try {
+ compressed = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (compressed == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ ReadableByteChannel src = Channels.newChannel(new ByteArrayInputStream(compressed));
+ ReadableByteChannel decoder = new BrotliDecoderChannel(src);
+ long crc;
+ try {
+ crc = BundleHelper.fingerprintStream(Channels.newInputStream(decoder));
+ } finally {
+ decoder.close();
+ }
+ assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStream.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStream.java
new file mode 100644
index 000000000..6e2e6e5fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStream.java
@@ -0,0 +1,115 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.Channels;
+
+/**
+ * InputStream that wraps native brotli decoder.
+ */
+public class BrotliInputStream extends InputStream {
+ /** The default internal buffer size used by the decoder. */
+ private static final int DEFAULT_BUFFER_SIZE = 16384;
+
+ private final Decoder decoder;
+
+ /**
+ * Creates a BrotliInputStream.
+ *
+ * @param source underlying source
+ * @param bufferSize intermediate buffer size
+ */
+ public BrotliInputStream(InputStream source, int bufferSize)
+ throws IOException {
+ this.decoder = new Decoder(Channels.newChannel(source), bufferSize);
+ }
+
+ public BrotliInputStream(InputStream source) throws IOException {
+ this(source, DEFAULT_BUFFER_SIZE);
+ }
+
+ public void enableEagerOutput() {
+ decoder.enableEagerOutput();
+ }
+
+ @Override
+ public void close() throws IOException {
+ decoder.close();
+ }
+
+ @Override
+ public int available() {
+ return (decoder.buffer != null) ? decoder.buffer.remaining() : 0;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (decoder.closed) {
+ throw new IOException("read after close");
+ }
+ int decoded;
+ // Iterate until at leat one byte is decoded, or EOF reached.
+ while (true) {
+ decoded = decoder.decode();
+ if (decoded != 0) {
+ break;
+ }
+ }
+
+ if (decoded == -1) {
+ return -1;
+ }
+ return decoder.buffer.get() & 0xFF;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (decoder.closed) {
+ throw new IOException("read after close");
+ }
+ if (decoder.decode() == -1) {
+ return -1;
+ }
+ int result = 0;
+ while (len > 0) {
+ int limit = Math.min(len, decoder.buffer.remaining());
+ decoder.buffer.get(b, off, limit);
+ off += limit;
+ len -= limit;
+ result += limit;
+ if (decoder.decode() == -1) {
+ break;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (decoder.closed) {
+ throw new IOException("read after close");
+ }
+ long result = 0;
+ while (n > 0) {
+ if (decoder.decode() == -1) {
+ break;
+ }
+ int limit = (int) Math.min(n, (long) decoder.buffer.remaining());
+ decoder.discard(limit);
+ result += limit;
+ n -= limit;
+ }
+ return result;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStreamTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStreamTest.java
new file mode 100644
index 000000000..5da7115b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/BrotliInputStreamTest.java
@@ -0,0 +1,82 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.dec.BrotliInputStream}. */
+@RunWith(AllTests.class)
+public class BrotliInputStreamTest extends BrotliJniTestBase {
+
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new StreamTestCase(entry));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class StreamTestCase extends TestCase {
+ final String entryName;
+ StreamTestCase(String entryName) {
+ super("BrotliInputStreamTest." + entryName);
+ this.entryName = entryName;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ BrotliInputStreamTest.run(entryName);
+ }
+ }
+
+ private static void run(String entryName) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] compressed;
+ try {
+ compressed = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (compressed == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ InputStream src = new ByteArrayInputStream(compressed);
+ InputStream decoder = new BrotliInputStream(src);
+ long crc;
+ try {
+ crc = BundleHelper.fingerprintStream(decoder);
+ } finally {
+ decoder.close();
+ }
+ assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/Decoder.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/Decoder.java
new file mode 100644
index 000000000..26183aba6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/Decoder.java
@@ -0,0 +1,177 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.util.ArrayList;
+
+/**
+ * Base class for InputStream / Channel implementations.
+ */
+public class Decoder {
+ private static final ByteBuffer EMPTY_BUFER = ByteBuffer.allocate(0);
+ private final ReadableByteChannel source;
+ private final DecoderJNI.Wrapper decoder;
+ ByteBuffer buffer;
+ boolean closed;
+ boolean eager;
+
+ /**
+ * Creates a Decoder wrapper.
+ *
+ * @param source underlying source
+ * @param inputBufferSize read buffer size
+ */
+ public Decoder(ReadableByteChannel source, int inputBufferSize)
+ throws IOException {
+ if (inputBufferSize <= 0) {
+ throw new IllegalArgumentException("buffer size must be positive");
+ }
+ if (source == null) {
+ throw new NullPointerException("source can not be null");
+ }
+ this.source = source;
+ this.decoder = new DecoderJNI.Wrapper(inputBufferSize);
+ }
+
+ private void fail(String message) throws IOException {
+ try {
+ close();
+ } catch (IOException ex) {
+ /* Ignore */
+ }
+ throw new IOException(message);
+ }
+
+ public void enableEagerOutput() {
+ this.eager = true;
+ }
+
+ /**
+ * Continue decoding.
+ *
+ * @return -1 if stream is finished, or number of bytes available in read buffer (> 0)
+ */
+ int decode() throws IOException {
+ while (true) {
+ if (buffer != null) {
+ if (!buffer.hasRemaining()) {
+ buffer = null;
+ } else {
+ return buffer.remaining();
+ }
+ }
+
+ switch (decoder.getStatus()) {
+ case DONE:
+ return -1;
+
+ case OK:
+ decoder.push(0);
+ break;
+
+ case NEEDS_MORE_INPUT:
+ // In "eager" more pulling preempts pushing.
+ if (eager && decoder.hasOutput()) {
+ buffer = decoder.pull();
+ break;
+ }
+ ByteBuffer inputBuffer = decoder.getInputBuffer();
+ ((Buffer) inputBuffer).clear();
+ int bytesRead = source.read(inputBuffer);
+ if (bytesRead == -1) {
+ fail("unexpected end of input");
+ }
+ if (bytesRead == 0) {
+ // No input data is currently available.
+ buffer = EMPTY_BUFER;
+ return 0;
+ }
+ decoder.push(bytesRead);
+ break;
+
+ case NEEDS_MORE_OUTPUT:
+ buffer = decoder.pull();
+ break;
+
+ default:
+ fail("corrupted input");
+ }
+ }
+ }
+
+ void discard(int length) {
+ ((Buffer) buffer).position(buffer.position() + length);
+ if (!buffer.hasRemaining()) {
+ buffer = null;
+ }
+ }
+
+ int consume(ByteBuffer dst) {
+ ByteBuffer slice = buffer.slice();
+ int limit = Math.min(slice.remaining(), dst.remaining());
+ ((Buffer) slice).limit(limit);
+ dst.put(slice);
+ discard(limit);
+ return limit;
+ }
+
+ void close() throws IOException {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ decoder.destroy();
+ source.close();
+ }
+
+ /**
+ * Decodes the given data buffer.
+ */
+ public static byte[] decompress(byte[] data) throws IOException {
+ DecoderJNI.Wrapper decoder = new DecoderJNI.Wrapper(data.length);
+ ArrayList<byte[]> output = new ArrayList<byte[]>();
+ int totalOutputSize = 0;
+ try {
+ decoder.getInputBuffer().put(data);
+ decoder.push(data.length);
+ while (decoder.getStatus() != DecoderJNI.Status.DONE) {
+ switch (decoder.getStatus()) {
+ case OK:
+ decoder.push(0);
+ break;
+
+ case NEEDS_MORE_OUTPUT:
+ ByteBuffer buffer = decoder.pull();
+ byte[] chunk = new byte[buffer.remaining()];
+ buffer.get(chunk);
+ output.add(chunk);
+ totalOutputSize += chunk.length;
+ break;
+
+ default:
+ throw new IOException("corrupted input");
+ }
+ }
+ } finally {
+ decoder.destroy();
+ }
+ if (output.size() == 1) {
+ return output.get(0);
+ }
+ byte[] result = new byte[totalOutputSize];
+ int offset = 0;
+ for (byte[] chunk : output) {
+ System.arraycopy(chunk, 0, result, offset, chunk.length);
+ offset += chunk.length;
+ }
+ return result;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderJNI.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderJNI.java
new file mode 100644
index 000000000..2319b1eae
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderJNI.java
@@ -0,0 +1,121 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * JNI wrapper for brotli decoder.
+ */
+public class DecoderJNI {
+ private static native ByteBuffer nativeCreate(long[] context);
+ private static native void nativePush(long[] context, int length);
+ private static native ByteBuffer nativePull(long[] context);
+ private static native void nativeDestroy(long[] context);
+
+ public enum Status {
+ ERROR,
+ DONE,
+ NEEDS_MORE_INPUT,
+ NEEDS_MORE_OUTPUT,
+ OK
+ };
+
+ public static class Wrapper {
+ private final long[] context = new long[3];
+ private final ByteBuffer inputBuffer;
+ private Status lastStatus = Status.NEEDS_MORE_INPUT;
+ private boolean fresh = true;
+
+ public Wrapper(int inputBufferSize) throws IOException {
+ this.context[1] = inputBufferSize;
+ this.inputBuffer = nativeCreate(this.context);
+ if (this.context[0] == 0) {
+ throw new IOException("failed to initialize native brotli decoder");
+ }
+ }
+
+ public void push(int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("negative block length");
+ }
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli decoder is already destroyed");
+ }
+ if (lastStatus != Status.NEEDS_MORE_INPUT && lastStatus != Status.OK) {
+ throw new IllegalStateException("pushing input to decoder in " + lastStatus + " state");
+ }
+ if (lastStatus == Status.OK && length != 0) {
+ throw new IllegalStateException("pushing input to decoder in OK state");
+ }
+ fresh = false;
+ nativePush(context, length);
+ parseStatus();
+ }
+
+ private void parseStatus() {
+ long status = context[1];
+ if (status == 1) {
+ lastStatus = Status.DONE;
+ } else if (status == 2) {
+ lastStatus = Status.NEEDS_MORE_INPUT;
+ } else if (status == 3) {
+ lastStatus = Status.NEEDS_MORE_OUTPUT;
+ } else if (status == 4) {
+ lastStatus = Status.OK;
+ } else {
+ lastStatus = Status.ERROR;
+ }
+ }
+
+ public Status getStatus() {
+ return lastStatus;
+ }
+
+ public ByteBuffer getInputBuffer() {
+ return inputBuffer;
+ }
+
+ public boolean hasOutput() {
+ return context[2] != 0;
+ }
+
+ public ByteBuffer pull() {
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli decoder is already destroyed");
+ }
+ if (lastStatus != Status.NEEDS_MORE_OUTPUT && !hasOutput()) {
+ throw new IllegalStateException("pulling output from decoder in " + lastStatus + " state");
+ }
+ fresh = false;
+ ByteBuffer result = nativePull(context);
+ parseStatus();
+ return result;
+ }
+
+ /**
+ * Releases native resources.
+ */
+ public void destroy() {
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli decoder is already destroyed");
+ }
+ nativeDestroy(context);
+ context[0] = 0;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (context[0] != 0) {
+ /* TODO: log resource leak? */
+ destroy();
+ }
+ super.finalize();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderTest.java
new file mode 100644
index 000000000..74b77d30a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/DecoderTest.java
@@ -0,0 +1,77 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.dec.Decoder}. */
+@RunWith(AllTests.class)
+public class DecoderTest extends BrotliJniTestBase {
+
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new DecoderTestCase(entry));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class DecoderTestCase extends TestCase {
+ final String entryName;
+ DecoderTestCase(String entryName) {
+ super("DecoderTest." + entryName);
+ this.entryName = entryName;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ DecoderTest.run(entryName);
+ }
+ }
+
+ private static void run(String entryName) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] compressed;
+ try {
+ compressed = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (compressed == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ byte[] decompressed = Decoder.decompress(compressed);
+
+ long crc = BundleHelper.fingerprintStream(new ByteArrayInputStream(decompressed));
+ assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/EagerStreamTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/EagerStreamTest.java
new file mode 100755
index 000000000..919f6e3b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/EagerStreamTest.java
@@ -0,0 +1,75 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.dec;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link org.brotli.wrapper.dec.BrotliInputStream}. */
+@RunWith(JUnit4.class)
+public class EagerStreamTest extends BrotliJniTestBase {
+
+ @Test
+ public void testEagerReading() throws IOException {
+ final StringBuilder log = new StringBuilder();
+ final byte[] data = {0, 0, 16, 42, 3};
+ InputStream source = new InputStream() {
+ int index;
+
+ @Override
+ public int read() {
+ if (index < data.length) {
+ log.append("<").append(index);
+ return data[index++];
+ } else {
+ log.append("<#");
+ return -1;
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (len < 1) {
+ return 0;
+ }
+ int d = read();
+ if (d == -1) {
+ return 0;
+ }
+ b[off] = (byte) d;
+ return 1;
+ }
+ };
+ BrotliInputStream reader = new BrotliInputStream(source);
+ reader.enableEagerOutput();
+ int count = 0;
+ while (true) {
+ log.append("^").append(count);
+ int b = reader.read();
+ if (b == -1) {
+ log.append(">#");
+ break;
+ } else {
+ log.append(">").append(count++);
+ }
+ }
+ // Lazy log: ^0<0<1<2<3<4>0^1>#
+ assertEquals("^0<0<1<2<3>0^1<4>#", log.toString());
+ }
+
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/decoder_jni.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/decoder_jni.cc
new file mode 100644
index 000000000..268a10b60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/dec/decoder_jni.cc
@@ -0,0 +1,202 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <jni.h>
+
+#include <new>
+
+#include <brotli/decode.h>
+
+namespace {
+/* A structure used to persist the decoder's state in between calls. */
+typedef struct DecoderHandle {
+ BrotliDecoderState* state;
+
+ uint8_t* input_start;
+ size_t input_offset;
+ size_t input_length;
+} DecoderHandle;
+
+/* Obtain handle from opaque pointer. */
+DecoderHandle* getHandle(void* opaque) {
+ return static_cast<DecoderHandle*>(opaque);
+}
+
+} /* namespace */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new Decoder.
+ *
+ * Cookie to address created decoder is stored in out_cookie. In case of failure
+ * cookie is 0.
+ *
+ * @param ctx {out_cookie, in_directBufferSize} tuple
+ * @returns direct ByteBuffer if directBufferSize is not 0; otherwise null
+ */
+JNIEXPORT jobject JNICALL
+Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ bool ok = true;
+ DecoderHandle* handle = nullptr;
+ jlong context[3];
+ env->GetLongArrayRegion(ctx, 0, 3, context);
+ size_t input_size = context[1];
+ context[0] = 0;
+ context[2] = 0;
+ handle = new (std::nothrow) DecoderHandle();
+ ok = !!handle;
+
+ if (ok) {
+ handle->input_offset = 0;
+ handle->input_length = 0;
+ handle->input_start = nullptr;
+
+ if (input_size == 0) {
+ ok = false;
+ } else {
+ handle->input_start = new (std::nothrow) uint8_t[input_size];
+ ok = !!handle->input_start;
+ }
+ }
+
+ if (ok) {
+ handle->state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+ ok = !!handle->state;
+ }
+
+ if (ok) {
+ /* TODO: future versions (e.g. when 128-bit architecture comes)
+ might require thread-safe cookie<->handle mapping. */
+ context[0] = reinterpret_cast<jlong>(handle);
+ } else if (!!handle) {
+ if (!!handle->input_start) delete[] handle->input_start;
+ delete handle;
+ }
+
+ env->SetLongArrayRegion(ctx, 0, 3, context);
+
+ if (!ok) {
+ return nullptr;
+ }
+
+ return env->NewDirectByteBuffer(handle->input_start, input_size);
+}
+
+/**
+ * Push data to decoder.
+ *
+ * status codes:
+ * - 0 error happened
+ * - 1 stream is finished, no more input / output expected
+ * - 2 needs more input to process further
+ * - 3 needs more output to process further
+ * - 4 ok, can proceed further without additional input
+ *
+ * @param ctx {in_cookie, out_status} tuple
+ * @param input_length number of bytes provided in input or direct input;
+ * 0 to process further previous input
+ */
+JNIEXPORT void JNICALL
+Java_org_brotli_wrapper_dec_DecoderJNI_nativePush(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length) {
+ jlong context[3];
+ env->GetLongArrayRegion(ctx, 0, 3, context);
+ DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ context[1] = 0; /* ERROR */
+ context[2] = 0;
+ env->SetLongArrayRegion(ctx, 0, 3, context);
+
+ if (input_length != 0) {
+ /* Still have unconsumed data. Workflow is broken. */
+ if (handle->input_offset < handle->input_length) {
+ return;
+ }
+ handle->input_offset = 0;
+ handle->input_length = input_length;
+ }
+
+ /* Actual decompression. */
+ const uint8_t* in = handle->input_start + handle->input_offset;
+ size_t in_size = handle->input_length - handle->input_offset;
+ size_t out_size = 0;
+ BrotliDecoderResult status = BrotliDecoderDecompressStream(
+ handle->state, &in_size, &in, &out_size, nullptr, nullptr);
+ handle->input_offset = handle->input_length - in_size;
+ switch (status) {
+ case BROTLI_DECODER_RESULT_SUCCESS:
+ /* Bytes after stream end are not allowed. */
+ context[1] = (handle->input_offset == handle->input_length) ? 1 : 0;
+ break;
+
+ case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
+ context[1] = 2;
+ break;
+
+ case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
+ context[1] = 3;
+ break;
+
+ default:
+ context[1] = 0;
+ break;
+ }
+ context[2] = BrotliDecoderHasMoreOutput(handle->state) ? 1 : 0;
+ env->SetLongArrayRegion(ctx, 0, 3, context);
+}
+
+/**
+ * Pull decompressed data from decoder.
+ *
+ * @param ctx {in_cookie, out_status} tuple
+ * @returns direct ByteBuffer; all the produced data MUST be consumed before
+ * any further invocation; null in case of error
+ */
+JNIEXPORT jobject JNICALL
+Java_org_brotli_wrapper_dec_DecoderJNI_nativePull(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ jlong context[3];
+ env->GetLongArrayRegion(ctx, 0, 3, context);
+ DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ size_t data_length = 0;
+ const uint8_t* data = BrotliDecoderTakeOutput(handle->state, &data_length);
+ bool hasMoreOutput = !!BrotliDecoderHasMoreOutput(handle->state);
+ if (hasMoreOutput) {
+ context[1] = 3;
+ } else if (BrotliDecoderIsFinished(handle->state)) {
+ /* Bytes after stream end are not allowed. */
+ context[1] = (handle->input_offset == handle->input_length) ? 1 : 0;
+ } else {
+ /* Can proceed, or more data is required? */
+ context[1] = (handle->input_offset == handle->input_length) ? 2 : 4;
+ }
+ context[2] = hasMoreOutput ? 1 : 0;
+ env->SetLongArrayRegion(ctx, 0, 3, context);
+ return env->NewDirectByteBuffer(const_cast<uint8_t*>(data), data_length);
+}
+
+/**
+ * Releases all used resources.
+ *
+ * @param ctx {in_cookie} tuple
+ */
+JNIEXPORT void JNICALL
+Java_org_brotli_wrapper_dec_DecoderJNI_nativeDestroy(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ jlong context[3];
+ env->GetLongArrayRegion(ctx, 0, 3, context);
+ DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ BrotliDecoderDestroyInstance(handle->state);
+ delete[] handle->input_start;
+ delete handle;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BUILD
new file mode 100644
index 000000000..9aea6ba0a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BUILD
@@ -0,0 +1,88 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+filegroup(
+ name = "jni_src",
+ srcs = ["encoder_jni.cc"],
+)
+
+filegroup(
+ name = "brotli_jni",
+ srcs = ["//:brotli_jni.dll"],
+)
+
+java_library(
+ name = "enc",
+ srcs = glob(
+ ["*.java"],
+ exclude = ["*Test*.java"],
+ ),
+ resource_jars = ["//:license"],
+)
+
+java_library(
+ name = "test_lib",
+ testonly = 1,
+ srcs = glob(["*Test*.java"]),
+ deps = [
+ ":enc",
+ "//org/brotli/integration:brotli_jni_test_base",
+ "//org/brotli/integration:bundle_helper",
+ "//org/brotli/wrapper/dec",
+ "@junit_junit//jar",
+ ],
+)
+
+filegroup(
+ name = "test_bundle",
+ srcs = ["//org/brotli/integration:test_corpus"],
+)
+
+java_test(
+ name = "BrotliEncoderChannelTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ shard_count = 15,
+ test_class = "org.brotli.wrapper.enc.BrotliEncoderChannelTest",
+ runtime_deps = [":test_lib"],
+)
+
+java_test(
+ name = "BrotliOutputStreamTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ shard_count = 15,
+ test_class = "org.brotli.wrapper.enc.BrotliOutputStreamTest",
+ runtime_deps = [":test_lib"],
+)
+
+java_test(
+ name = "EncoderTest",
+ size = "large",
+ data = [
+ ":brotli_jni", # Bazel JNI workaround
+ ":test_bundle",
+ ],
+ jvm_flags = [
+ "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
+ "-DTEST_BUNDLE=$(location :test_bundle)",
+ ],
+ shard_count = 15,
+ test_class = "org.brotli.wrapper.enc.EncoderTest",
+ runtime_deps = [":test_lib"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannel.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannel.java
new file mode 100644
index 000000000..047c3562e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannel.java
@@ -0,0 +1,77 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.enc;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * WritableByteChannel that wraps native brotli encoder.
+ */
+public class BrotliEncoderChannel extends Encoder implements WritableByteChannel {
+ /** The default internal buffer size used by the decoder. */
+ private static final int DEFAULT_BUFFER_SIZE = 16384;
+
+ private final Object mutex = new Object();
+
+ /**
+ * Creates a BrotliEncoderChannel.
+ *
+ * @param destination underlying destination
+ * @param params encoding settings
+ * @param bufferSize intermediate buffer size
+ */
+ public BrotliEncoderChannel(WritableByteChannel destination, Encoder.Parameters params,
+ int bufferSize) throws IOException {
+ super(destination, params, bufferSize);
+ }
+
+ public BrotliEncoderChannel(WritableByteChannel destination, Encoder.Parameters params)
+ throws IOException {
+ this(destination, params, DEFAULT_BUFFER_SIZE);
+ }
+
+ public BrotliEncoderChannel(WritableByteChannel destination) throws IOException {
+ this(destination, new Encoder.Parameters());
+ }
+
+ @Override
+ public boolean isOpen() {
+ synchronized (mutex) {
+ return !closed;
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ synchronized (mutex) {
+ super.close();
+ }
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ synchronized (mutex) {
+ if (closed) {
+ throw new ClosedChannelException();
+ }
+ int result = 0;
+ while (src.hasRemaining() && encode(EncoderJNI.Operation.PROCESS)) {
+ int limit = Math.min(src.remaining(), inputBuffer.remaining());
+ ByteBuffer slice = src.slice();
+ ((Buffer) slice).limit(limit);
+ inputBuffer.put(slice);
+ result += limit;
+ ((Buffer) src).position(src.position() + limit);
+ }
+ return result;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannelTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannelTest.java
new file mode 100644
index 000000000..aacc6daea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliEncoderChannelTest.java
@@ -0,0 +1,118 @@
+package org.brotli.wrapper.enc;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import org.brotli.wrapper.dec.BrotliInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.enc.BrotliEncoderChannel}. */
+@RunWith(AllTests.class)
+public class BrotliEncoderChannelTest extends BrotliJniTestBase {
+
+ private enum TestMode {
+ WRITE_ALL,
+ WRITE_CHUNKS
+ }
+
+ private static final int CHUNK_SIZE = 256;
+
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new ChannleTestCase(entry, TestMode.WRITE_ALL));
+ suite.addTest(new ChannleTestCase(entry, TestMode.WRITE_CHUNKS));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class ChannleTestCase extends TestCase {
+ final String entryName;
+ final TestMode mode;
+ ChannleTestCase(String entryName, TestMode mode) {
+ super("BrotliEncoderChannelTest." + entryName + "." + mode.name());
+ this.entryName = entryName;
+ this.mode = mode;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ BrotliEncoderChannelTest.run(entryName, mode);
+ }
+ }
+
+ private static void run(String entryName, TestMode mode) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] original;
+ try {
+ original = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (original == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ if ((mode == TestMode.WRITE_CHUNKS) && (original.length <= CHUNK_SIZE)) {
+ return;
+ }
+
+ ByteArrayOutputStream dst = new ByteArrayOutputStream();
+ WritableByteChannel encoder = new BrotliEncoderChannel(Channels.newChannel(dst));
+ ByteBuffer src = ByteBuffer.wrap(original);
+ try {
+ switch (mode) {
+ case WRITE_ALL:
+ encoder.write(src);
+ break;
+
+ case WRITE_CHUNKS:
+ while (src.hasRemaining()) {
+ int limit = Math.min(CHUNK_SIZE, src.remaining());
+ ByteBuffer slice = src.slice();
+ ((Buffer) slice).limit(limit);
+ ((Buffer) src).position(src.position() + limit);
+ encoder.write(slice);
+ }
+ break;
+ }
+ } finally {
+ encoder.close();
+ }
+
+ InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(dst.toByteArray()));
+ try {
+ long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
+ long crc = BundleHelper.fingerprintStream(decoder);
+ assertEquals(originalCrc, crc);
+ } finally {
+ decoder.close();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStream.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStream.java
new file mode 100644
index 000000000..5bd395777
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStream.java
@@ -0,0 +1,87 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.enc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.Channels;
+
+/**
+ * Output stream that wraps native brotli encoder.
+ */
+public class BrotliOutputStream extends OutputStream {
+ /** The default internal buffer size used by the encoder. */
+ private static final int DEFAULT_BUFFER_SIZE = 16384;
+
+ private final Encoder encoder;
+
+ /**
+ * Creates a BrotliOutputStream.
+ *
+ * @param destination underlying destination
+ * @param params encoding settings
+ * @param bufferSize intermediate buffer size
+ */
+ public BrotliOutputStream(OutputStream destination, Encoder.Parameters params, int bufferSize)
+ throws IOException {
+ this.encoder = new Encoder(Channels.newChannel(destination), params, bufferSize);
+ }
+
+ public BrotliOutputStream(OutputStream destination, Encoder.Parameters params)
+ throws IOException {
+ this(destination, params, DEFAULT_BUFFER_SIZE);
+ }
+
+ public BrotliOutputStream(OutputStream destination) throws IOException {
+ this(destination, new Encoder.Parameters());
+ }
+
+ @Override
+ public void close() throws IOException {
+ encoder.close();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (encoder.closed) {
+ throw new IOException("write after close");
+ }
+ encoder.flush();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if (encoder.closed) {
+ throw new IOException("write after close");
+ }
+ while (!encoder.encode(EncoderJNI.Operation.PROCESS)) {
+ // Busy-wait loop.
+ }
+ encoder.inputBuffer.put((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ this.write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (encoder.closed) {
+ throw new IOException("write after close");
+ }
+ while (len > 0) {
+ if (!encoder.encode(EncoderJNI.Operation.PROCESS)) {
+ continue;
+ }
+ int limit = Math.min(len, encoder.inputBuffer.remaining());
+ encoder.inputBuffer.put(b, off, limit);
+ off += limit;
+ len -= limit;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStreamTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStreamTest.java
new file mode 100644
index 000000000..699b4b203
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/BrotliOutputStreamTest.java
@@ -0,0 +1,118 @@
+package org.brotli.wrapper.enc;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import org.brotli.wrapper.dec.BrotliInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.enc.BrotliOutputStream}. */
+@RunWith(AllTests.class)
+public class BrotliOutputStreamTest extends BrotliJniTestBase {
+
+ private enum TestMode {
+ WRITE_ALL,
+ WRITE_CHUNKS,
+ WRITE_BYTE
+ }
+
+ private static final int CHUNK_SIZE = 256;
+
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new StreamTestCase(entry, TestMode.WRITE_ALL));
+ suite.addTest(new StreamTestCase(entry, TestMode.WRITE_CHUNKS));
+ suite.addTest(new StreamTestCase(entry, TestMode.WRITE_BYTE));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class StreamTestCase extends TestCase {
+ final String entryName;
+ final TestMode mode;
+ StreamTestCase(String entryName, TestMode mode) {
+ super("BrotliOutputStreamTest." + entryName + "." + mode.name());
+ this.entryName = entryName;
+ this.mode = mode;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ BrotliOutputStreamTest.run(entryName, mode);
+ }
+ }
+
+ private static void run(String entryName, TestMode mode) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] original;
+ try {
+ original = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (original == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ if ((mode == TestMode.WRITE_CHUNKS) && (original.length <= CHUNK_SIZE)) {
+ return;
+ }
+
+ ByteArrayOutputStream dst = new ByteArrayOutputStream();
+ OutputStream encoder = new BrotliOutputStream(dst);
+ try {
+ switch (mode) {
+ case WRITE_ALL:
+ encoder.write(original);
+ break;
+
+ case WRITE_CHUNKS:
+ for (int offset = 0; offset < original.length; offset += CHUNK_SIZE) {
+ encoder.write(original, offset, Math.min(CHUNK_SIZE, original.length - offset));
+ }
+ break;
+
+ case WRITE_BYTE:
+ for (byte singleByte : original) {
+ encoder.write(singleByte);
+ }
+ break;
+ }
+ } finally {
+ encoder.close();
+ }
+
+ InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(dst.toByteArray()));
+ try {
+ long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
+ long crc = BundleHelper.fingerprintStream(decoder);
+ assertEquals(originalCrc, crc);
+ } finally {
+ decoder.close();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EmptyInputTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EmptyInputTest.java
new file mode 100755
index 000000000..a536381af
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EmptyInputTest.java
@@ -0,0 +1,29 @@
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.enc;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.wrapper.dec.Decoder;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link org.brotli.wrapper.enc.Encoder}. */
+@RunWith(JUnit4.class)
+public class EmptyInputTest extends BrotliJniTestBase {
+ @Test
+ public void testEmptyInput() throws IOException {
+ byte[] data = new byte[0];
+ byte[] encoded = Encoder.compress(data);
+ assertEquals(1, encoded.length);
+ byte[] decoded = Decoder.decompress(encoded);
+ assertEquals(0, decoded.length);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/Encoder.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/Encoder.java
new file mode 100644
index 000000000..1fde8d64f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/Encoder.java
@@ -0,0 +1,205 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.enc;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+
+/**
+ * Base class for OutputStream / Channel implementations.
+ */
+public class Encoder {
+ private final WritableByteChannel destination;
+ private final EncoderJNI.Wrapper encoder;
+ private ByteBuffer buffer;
+ final ByteBuffer inputBuffer;
+ boolean closed;
+
+ /**
+ * Brotli encoder settings.
+ */
+ public static final class Parameters {
+ private int quality = -1;
+ private int lgwin = -1;
+
+ public Parameters() { }
+
+ private Parameters(Parameters other) {
+ this.quality = other.quality;
+ this.lgwin = other.lgwin;
+ }
+
+ /**
+ * @param quality compression quality, or -1 for default
+ */
+ public Parameters setQuality(int quality) {
+ if (quality < -1 || quality > 11) {
+ throw new IllegalArgumentException("quality should be in range [0, 11], or -1");
+ }
+ this.quality = quality;
+ return this;
+ }
+
+ /**
+ * @param lgwin log2(LZ window size), or -1 for default
+ */
+ public Parameters setWindow(int lgwin) {
+ if ((lgwin != -1) && ((lgwin < 10) || (lgwin > 24))) {
+ throw new IllegalArgumentException("lgwin should be in range [10, 24], or -1");
+ }
+ this.lgwin = lgwin;
+ return this;
+ }
+ }
+
+ /**
+ * Creates a Encoder wrapper.
+ *
+ * @param destination underlying destination
+ * @param params encoding parameters
+ * @param inputBufferSize read buffer size
+ */
+ Encoder(WritableByteChannel destination, Parameters params, int inputBufferSize)
+ throws IOException {
+ if (inputBufferSize <= 0) {
+ throw new IllegalArgumentException("buffer size must be positive");
+ }
+ if (destination == null) {
+ throw new NullPointerException("destination can not be null");
+ }
+ this.destination = destination;
+ this.encoder = new EncoderJNI.Wrapper(inputBufferSize, params.quality, params.lgwin);
+ this.inputBuffer = this.encoder.getInputBuffer();
+ }
+
+ private void fail(String message) throws IOException {
+ try {
+ close();
+ } catch (IOException ex) {
+ /* Ignore */
+ }
+ throw new IOException(message);
+ }
+
+ /**
+ * @param force repeat pushing until all output is consumed
+ * @return true if all encoder output is consumed
+ */
+ boolean pushOutput(boolean force) throws IOException {
+ while (buffer != null) {
+ if (buffer.hasRemaining()) {
+ destination.write(buffer);
+ }
+ if (!buffer.hasRemaining()) {
+ buffer = null;
+ } else if (!force) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return true if there is space in inputBuffer.
+ */
+ boolean encode(EncoderJNI.Operation op) throws IOException {
+ boolean force = (op != EncoderJNI.Operation.PROCESS);
+ if (force) {
+ ((Buffer) inputBuffer).limit(inputBuffer.position());
+ } else if (inputBuffer.hasRemaining()) {
+ return true;
+ }
+ boolean hasInput = true;
+ while (true) {
+ if (!encoder.isSuccess()) {
+ fail("encoding failed");
+ } else if (!pushOutput(force)) {
+ return false;
+ } else if (encoder.hasMoreOutput()) {
+ buffer = encoder.pull();
+ } else if (encoder.hasRemainingInput()) {
+ encoder.push(op, 0);
+ } else if (hasInput) {
+ encoder.push(op, inputBuffer.limit());
+ hasInput = false;
+ } else {
+ ((Buffer) inputBuffer).clear();
+ return true;
+ }
+ }
+ }
+
+ void flush() throws IOException {
+ encode(EncoderJNI.Operation.FLUSH);
+ }
+
+ void close() throws IOException {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ try {
+ encode(EncoderJNI.Operation.FINISH);
+ } finally {
+ encoder.destroy();
+ destination.close();
+ }
+ }
+
+ /**
+ * Encodes the given data buffer.
+ */
+ public static byte[] compress(byte[] data, Parameters params) throws IOException {
+ if (data.length == 0) {
+ byte[] empty = new byte[1];
+ empty[0] = 6;
+ return empty;
+ }
+ /* data.length > 0 */
+ EncoderJNI.Wrapper encoder = new EncoderJNI.Wrapper(data.length, params.quality, params.lgwin);
+ ArrayList<byte[]> output = new ArrayList<byte[]>();
+ int totalOutputSize = 0;
+ try {
+ encoder.getInputBuffer().put(data);
+ encoder.push(EncoderJNI.Operation.FINISH, data.length);
+ while (true) {
+ if (!encoder.isSuccess()) {
+ throw new IOException("encoding failed");
+ } else if (encoder.hasMoreOutput()) {
+ ByteBuffer buffer = encoder.pull();
+ byte[] chunk = new byte[buffer.remaining()];
+ buffer.get(chunk);
+ output.add(chunk);
+ totalOutputSize += chunk.length;
+ } else if (!encoder.isFinished()) {
+ encoder.push(EncoderJNI.Operation.FINISH, 0);
+ } else {
+ break;
+ }
+ }
+ } finally {
+ encoder.destroy();
+ }
+ if (output.size() == 1) {
+ return output.get(0);
+ }
+ byte[] result = new byte[totalOutputSize];
+ int offset = 0;
+ for (byte[] chunk : output) {
+ System.arraycopy(chunk, 0, result, offset, chunk.length);
+ offset += chunk.length;
+ }
+ return result;
+ }
+
+ public static byte[] compress(byte[] data) throws IOException {
+ return compress(data, new Parameters());
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderJNI.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderJNI.java
new file mode 100644
index 000000000..501362957
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderJNI.java
@@ -0,0 +1,118 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+package org.brotli.wrapper.enc;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * JNI wrapper for brotli encoder.
+ */
+class EncoderJNI {
+ private static native ByteBuffer nativeCreate(long[] context);
+ private static native void nativePush(long[] context, int length);
+ private static native ByteBuffer nativePull(long[] context);
+ private static native void nativeDestroy(long[] context);
+
+ enum Operation {
+ PROCESS,
+ FLUSH,
+ FINISH
+ }
+
+ static class Wrapper {
+ protected final long[] context = new long[5];
+ private final ByteBuffer inputBuffer;
+ private boolean fresh = true;
+
+ Wrapper(int inputBufferSize, int quality, int lgwin)
+ throws IOException {
+ if (inputBufferSize <= 0) {
+ throw new IOException("buffer size must be positive");
+ }
+ this.context[1] = inputBufferSize;
+ this.context[2] = quality;
+ this.context[3] = lgwin;
+ this.inputBuffer = nativeCreate(this.context);
+ if (this.context[0] == 0) {
+ throw new IOException("failed to initialize native brotli encoder");
+ }
+ this.context[1] = 1;
+ this.context[2] = 0;
+ this.context[3] = 0;
+ }
+
+ void push(Operation op, int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("negative block length");
+ }
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli encoder is already destroyed");
+ }
+ if (!isSuccess() || hasMoreOutput()) {
+ throw new IllegalStateException("pushing input to encoder in unexpected state");
+ }
+ if (hasRemainingInput() && length != 0) {
+ throw new IllegalStateException("pushing input to encoder over previous input");
+ }
+ context[1] = op.ordinal();
+ fresh = false;
+ nativePush(context, length);
+ }
+
+ boolean isSuccess() {
+ return context[1] != 0;
+ }
+
+ boolean hasMoreOutput() {
+ return context[2] != 0;
+ }
+
+ boolean hasRemainingInput() {
+ return context[3] != 0;
+ }
+
+ boolean isFinished() {
+ return context[4] != 0;
+ }
+
+ ByteBuffer getInputBuffer() {
+ return inputBuffer;
+ }
+
+ ByteBuffer pull() {
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli encoder is already destroyed");
+ }
+ if (!isSuccess() || !hasMoreOutput()) {
+ throw new IllegalStateException("pulling while data is not ready");
+ }
+ fresh = false;
+ return nativePull(context);
+ }
+
+ /**
+ * Releases native resources.
+ */
+ void destroy() {
+ if (context[0] == 0) {
+ throw new IllegalStateException("brotli encoder is already destroyed");
+ }
+ nativeDestroy(context);
+ context[0] = 0;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (context[0] != 0) {
+ /* TODO: log resource leak? */
+ destroy();
+ }
+ super.finalize();
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderTest.java b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderTest.java
new file mode 100644
index 000000000..18ed6470a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/EncoderTest.java
@@ -0,0 +1,80 @@
+package org.brotli.wrapper.enc;
+
+import static org.junit.Assert.assertEquals;
+
+import org.brotli.integration.BrotliJniTestBase;
+import org.brotli.integration.BundleHelper;
+import org.brotli.wrapper.dec.BrotliInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+
+/** Tests for {@link org.brotli.wrapper.enc.Encoder}. */
+@RunWith(AllTests.class)
+public class EncoderTest extends BrotliJniTestBase {
+ static InputStream getBundle() throws IOException {
+ return new FileInputStream(System.getProperty("TEST_BUNDLE"));
+ }
+
+ /** Creates a test suite. */
+ public static TestSuite suite() throws IOException {
+ TestSuite suite = new TestSuite();
+ InputStream bundle = getBundle();
+ try {
+ List<String> entries = BundleHelper.listEntries(bundle);
+ for (String entry : entries) {
+ suite.addTest(new EncoderTestCase(entry));
+ }
+ } finally {
+ bundle.close();
+ }
+ return suite;
+ }
+
+ /** Test case with a unique name. */
+ static class EncoderTestCase extends TestCase {
+ final String entryName;
+ EncoderTestCase(String entryName) {
+ super("EncoderTest." + entryName);
+ this.entryName = entryName;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ EncoderTest.run(entryName);
+ }
+ }
+
+ private static void run(String entryName) throws Throwable {
+ InputStream bundle = getBundle();
+ byte[] original;
+ try {
+ original = BundleHelper.readEntry(bundle, entryName);
+ } finally {
+ bundle.close();
+ }
+ if (original == null) {
+ throw new RuntimeException("Can't read bundle entry: " + entryName);
+ }
+
+ for (int window = 10; window <= 22; window++) {
+ byte[] compressed =
+ Encoder.compress(original, new Encoder.Parameters().setQuality(6).setWindow(window));
+
+ InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(compressed));
+ try {
+ long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
+ long crc = BundleHelper.fingerprintStream(decoder);
+ assertEquals(originalCrc, crc);
+ } finally {
+ decoder.close();
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/encoder_jni.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/encoder_jni.cc
new file mode 100644
index 000000000..5cde6dfb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/java/org/brotli/wrapper/enc/encoder_jni.cc
@@ -0,0 +1,195 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <jni.h>
+
+#include <new>
+
+#include <brotli/encode.h>
+
+namespace {
+/* A structure used to persist the encoder's state in between calls. */
+typedef struct EncoderHandle {
+ BrotliEncoderState* state;
+
+ uint8_t* input_start;
+ size_t input_offset;
+ size_t input_last;
+} EncoderHandle;
+
+/* Obtain handle from opaque pointer. */
+EncoderHandle* getHandle(void* opaque) {
+ return static_cast<EncoderHandle*>(opaque);
+}
+
+} /* namespace */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new Encoder.
+ *
+ * Cookie to address created encoder is stored in out_cookie. In case of failure
+ * cookie is 0.
+ *
+ * @param ctx {out_cookie, in_directBufferSize, in_quality, in_lgwin} tuple
+ * @returns direct ByteBuffer if directBufferSize is not 0; otherwise null
+ */
+JNIEXPORT jobject JNICALL
+Java_org_brotli_wrapper_enc_EncoderJNI_nativeCreate(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ bool ok = true;
+ EncoderHandle* handle = nullptr;
+ jlong context[5];
+ env->GetLongArrayRegion(ctx, 0, 5, context);
+ size_t input_size = context[1];
+ context[0] = 0;
+ handle = new (std::nothrow) EncoderHandle();
+ ok = !!handle;
+
+ if (ok) {
+ handle->input_offset = 0;
+ handle->input_last = 0;
+ handle->input_start = nullptr;
+
+ if (input_size == 0) {
+ ok = false;
+ } else {
+ handle->input_start = new (std::nothrow) uint8_t[input_size];
+ ok = !!handle->input_start;
+ }
+ }
+
+ if (ok) {
+ handle->state = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
+ ok = !!handle->state;
+ }
+
+ if (ok) {
+ int quality = context[2];
+ if (quality >= 0) {
+ BrotliEncoderSetParameter(handle->state, BROTLI_PARAM_QUALITY, quality);
+ }
+ int lgwin = context[3];
+ if (lgwin >= 0) {
+ BrotliEncoderSetParameter(handle->state, BROTLI_PARAM_LGWIN, lgwin);
+ }
+ }
+
+ if (ok) {
+ /* TODO: future versions (e.g. when 128-bit architecture comes)
+ might require thread-safe cookie<->handle mapping. */
+ context[0] = reinterpret_cast<jlong>(handle);
+ } else if (!!handle) {
+ if (!!handle->input_start) delete[] handle->input_start;
+ delete handle;
+ }
+
+ env->SetLongArrayRegion(ctx, 0, 1, context);
+
+ if (!ok) {
+ return nullptr;
+ }
+
+ return env->NewDirectByteBuffer(handle->input_start, input_size);
+}
+
+/**
+ * Push data to encoder.
+ *
+ * @param ctx {in_cookie, in_operation_out_success, out_has_more_output,
+ * out_has_remaining_input} tuple
+ * @param input_length number of bytes provided in input or direct input;
+ * 0 to process further previous input
+ */
+JNIEXPORT void JNICALL
+Java_org_brotli_wrapper_enc_EncoderJNI_nativePush(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length) {
+ jlong context[5];
+ env->GetLongArrayRegion(ctx, 0, 5, context);
+ EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ int operation = context[1];
+ context[1] = 0; /* ERROR */
+ env->SetLongArrayRegion(ctx, 0, 5, context);
+
+ BrotliEncoderOperation op;
+ switch (operation) {
+ case 0: op = BROTLI_OPERATION_PROCESS; break;
+ case 1: op = BROTLI_OPERATION_FLUSH; break;
+ case 2: op = BROTLI_OPERATION_FINISH; break;
+ default: return; /* ERROR */
+ }
+
+ if (input_length != 0) {
+ /* Still have unconsumed data. Workflow is broken. */
+ if (handle->input_offset < handle->input_last) {
+ return;
+ }
+ handle->input_offset = 0;
+ handle->input_last = input_length;
+ }
+
+ /* Actual compression. */
+ const uint8_t* in = handle->input_start + handle->input_offset;
+ size_t in_size = handle->input_last - handle->input_offset;
+ size_t out_size = 0;
+ BROTLI_BOOL status = BrotliEncoderCompressStream(
+ handle->state, op, &in_size, &in, &out_size, nullptr, nullptr);
+ handle->input_offset = handle->input_last - in_size;
+ if (!!status) {
+ context[1] = 1;
+ context[2] = BrotliEncoderHasMoreOutput(handle->state) ? 1 : 0;
+ context[3] = (handle->input_offset != handle->input_last) ? 1 : 0;
+ context[4] = BrotliEncoderIsFinished(handle->state) ? 1 : 0;
+ }
+ env->SetLongArrayRegion(ctx, 0, 5, context);
+}
+
+/**
+ * Pull decompressed data from encoder.
+ *
+ * @param ctx {in_cookie, out_success, out_has_more_output,
+ * out_has_remaining_input} tuple
+ * @returns direct ByteBuffer; all the produced data MUST be consumed before
+ * any further invocation; null in case of error
+ */
+JNIEXPORT jobject JNICALL
+Java_org_brotli_wrapper_enc_EncoderJNI_nativePull(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ jlong context[5];
+ env->GetLongArrayRegion(ctx, 0, 5, context);
+ EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ size_t data_length = 0;
+ const uint8_t* data = BrotliEncoderTakeOutput(handle->state, &data_length);
+ context[1] = 1;
+ context[2] = BrotliEncoderHasMoreOutput(handle->state) ? 1 : 0;
+ context[3] = (handle->input_offset != handle->input_last) ? 1 : 0;
+ context[4] = BrotliEncoderIsFinished(handle->state) ? 1 : 0;
+ env->SetLongArrayRegion(ctx, 0, 5, context);
+ return env->NewDirectByteBuffer(const_cast<uint8_t*>(data), data_length);
+}
+
+/**
+ * Releases all used resources.
+ *
+ * @param ctx {in_cookie} tuple
+ */
+JNIEXPORT void JNICALL
+Java_org_brotli_wrapper_enc_EncoderJNI_nativeDestroy(
+ JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
+ jlong context[2];
+ env->GetLongArrayRegion(ctx, 0, 2, context);
+ EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
+ BrotliEncoderDestroyInstance(handle->state);
+ delete[] handle->input_start;
+ delete handle;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/BUILD
new file mode 100644
index 000000000..49c17287c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/BUILD
@@ -0,0 +1,43 @@
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"]) # MIT
+
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
+
+# Not a real polyfill. Do NOT use for anything, but tests.
+closure_js_library(
+ name = "polyfill",
+ srcs = ["polyfill.js"],
+ suppress = [
+ "JSC_INVALID_OPERAND_TYPE",
+ "JSC_MISSING_JSDOC",
+ "JSC_STRICT_INEXISTENT_PROPERTY",
+ "JSC_TYPE_MISMATCH",
+ "JSC_UNKNOWN_EXPR_TYPE",
+ ],
+)
+
+# Do NOT use this artifact; it is for test purposes only.
+closure_js_library(
+ name = "decode",
+ srcs = ["decode.js"],
+ suppress = [
+ "JSC_DUP_VAR_DECLARATION",
+ "JSC_USELESS_BLOCK",
+ ],
+ deps = [":polyfill"],
+)
+
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_test")
+
+closure_js_test(
+ name = "all_tests",
+ srcs = ["decode_test.js"],
+ deps = [
+ ":decode",
+ ":polyfill",
+ "@io_bazel_rules_closure//closure/library:testing",
+ ],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/WORKSPACE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/WORKSPACE
new file mode 100644
index 000000000..f15740a69
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/WORKSPACE
@@ -0,0 +1,12 @@
+workspace(name = "org_brotli_js")
+
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
+git_repository(
+ name = "io_bazel_rules_closure",
+ commit = "29ec97e7c85d607ba9e41cab3993fbb13f812c4b",
+ remote = "https://github.com/bazelbuild/rules_closure.git",
+)
+
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
+closure_repositories()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.js b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.js
new file mode 100644
index 000000000..7896a5024
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.js
@@ -0,0 +1,2029 @@
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/** @return {function(!Int8Array):!Int8Array} */
+function BrotliDecodeClosure() {
+ "use strict";
+
+ /** @type {!Int8Array} */
+ var DICTIONARY_DATA = new Int8Array(0);
+
+ /**
+ * @constructor
+ * @param {!Int8Array} bytes
+ * @struct
+ */
+ function InputStream(bytes) {
+ /** @type {!Int8Array} */
+ this.data = bytes;
+ /** @type {!number} */
+ this.offset = 0;
+ }
+ var MAX_HUFFMAN_TABLE_SIZE = Int32Array.from([256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, 854, 886, 920, 952, 984, 1016, 1048, 1080]);
+ var CODE_LENGTH_CODE_ORDER = Int32Array.from([1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
+ var DISTANCE_SHORT_CODE_INDEX_OFFSET = Int32Array.from([0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]);
+ var DISTANCE_SHORT_CODE_VALUE_OFFSET = Int32Array.from([0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3]);
+ var FIXED_TABLE = Int32Array.from([0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001, 0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005]);
+ var DICTIONARY_OFFSETS_BY_LENGTH = Int32Array.from([0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, 122016]);
+ var DICTIONARY_SIZE_BITS_BY_LENGTH = Int32Array.from([0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, 7, 6, 6, 5, 5]);
+ var BLOCK_LENGTH_OFFSET = Int32Array.from([1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625]);
+ var BLOCK_LENGTH_N_BITS = Int32Array.from([2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24]);
+ var INSERT_LENGTH_N_BITS = Int16Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18]);
+ var COPY_LENGTH_N_BITS = Int16Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18]);
+ var CMD_LOOKUP = new Int16Array(2816);
+ {
+ unpackCommandLookupTable(CMD_LOOKUP);
+ }
+ /**
+ * @param {number} i
+ * @return {number}
+ */
+ function log2floor(i) {
+ var /** number */ result = -1;
+ var /** number */ step = 16;
+ while (step > 0) {
+ if ((i >>> step) != 0) {
+ result += step;
+ i = i >>> step;
+ }
+ step = step >> 1;
+ }
+ return result + i;
+ }
+ /**
+ * @param {number} npostfix
+ * @param {number} ndirect
+ * @param {number} maxndistbits
+ * @return {number}
+ */
+ function calculateDistanceAlphabetSize(npostfix, ndirect, maxndistbits) {
+ return 16 + ndirect + 2 * (maxndistbits << npostfix);
+ }
+ /**
+ * @param {number} maxDistance
+ * @param {number} npostfix
+ * @param {number} ndirect
+ * @return {number}
+ */
+ function calculateDistanceAlphabetLimit(maxDistance, npostfix, ndirect) {
+ if (maxDistance < ndirect + (2 << npostfix)) {
+ throw "maxDistance is too small";
+ }
+ var /** number */ offset = ((maxDistance - ndirect) >> npostfix) + 4;
+ var /** number */ ndistbits = log2floor(offset) - 1;
+ var /** number */ group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1);
+ return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16;
+ }
+ /**
+ * @param {!Int16Array} cmdLookup
+ * @return {void}
+ */
+ function unpackCommandLookupTable(cmdLookup) {
+ var /** !Int16Array */ insertLengthOffsets = new Int16Array(24);
+ var /** !Int16Array */ copyLengthOffsets = new Int16Array(24);
+ copyLengthOffsets[0] = 2;
+ for (var /** number */ i = 0; i < 23; ++i) {
+ insertLengthOffsets[i + 1] = (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]));
+ copyLengthOffsets[i + 1] = (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]));
+ }
+ for (var /** number */ cmdCode = 0; cmdCode < 704; ++cmdCode) {
+ var /** number */ rangeIdx = cmdCode >>> 6;
+ var /** number */ distanceContextOffset = -4;
+ if (rangeIdx >= 2) {
+ rangeIdx -= 2;
+ distanceContextOffset = 0;
+ }
+ var /** number */ insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
+ var /** number */ copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
+ var /** number */ copyLengthOffset = copyLengthOffsets[copyCode];
+ var /** number */ distanceContext = distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2);
+ var /** number */ index = cmdCode * 4;
+ cmdLookup[index + 0] = (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8));
+ cmdLookup[index + 1] = insertLengthOffsets[insertCode];
+ cmdLookup[index + 2] = copyLengthOffsets[copyCode];
+ cmdLookup[index + 3] = distanceContext;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {number}
+ */
+ function decodeWindowBits(s) {
+ var /** number */ largeWindowEnabled = s.isLargeWindow;
+ s.isLargeWindow = 0;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ if (readFewBits(s, 1) == 0) {
+ return 16;
+ }
+ var /** number */ n = readFewBits(s, 3);
+ if (n != 0) {
+ return 17 + n;
+ }
+ n = readFewBits(s, 3);
+ if (n != 0) {
+ if (n == 1) {
+ if (largeWindowEnabled == 0) {
+ return -1;
+ }
+ s.isLargeWindow = 1;
+ if (readFewBits(s, 1) == 1) {
+ return -1;
+ }
+ n = readFewBits(s, 6);
+ if (n < 10 || n > 30) {
+ return -1;
+ }
+ return n;
+ } else {
+ return 8 + n;
+ }
+ }
+ return 17;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function enableEagerOutput(s) {
+ if (s.runningState != 1) {
+ throw "State MUST be freshly initialized";
+ }
+ s.isEager = 1;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function enableLargeWindow(s) {
+ if (s.runningState != 1) {
+ throw "State MUST be freshly initialized";
+ }
+ s.isLargeWindow = 1;
+ }
+ /**
+ * @param {!State} s
+ * @param {!InputStream} input
+ * @return {void}
+ */
+ function initState(s, input) {
+ if (s.runningState != 0) {
+ throw "State MUST be uninitialized";
+ }
+ s.blockTrees = new Int32Array(3091);
+ s.blockTrees[0] = 7;
+ s.distRbIdx = 3;
+ var /** number */ maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(0x7FFFFFFC, 3, 15 << 3);
+ s.distExtraBits = new Int8Array(maxDistanceAlphabetLimit);
+ s.distOffset = new Int32Array(maxDistanceAlphabetLimit);
+ s.input = input;
+ initBitReader(s);
+ s.runningState = 1;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function close(s) {
+ if (s.runningState == 0) {
+ throw "State MUST be initialized";
+ }
+ if (s.runningState == 11) {
+ return;
+ }
+ s.runningState = 11;
+ if (s.input != null) {
+ closeInput(s.input);
+ s.input = null;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {number}
+ */
+ function decodeVarLenUnsignedByte(s) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ if (readFewBits(s, 1) != 0) {
+ var /** number */ n = readFewBits(s, 3);
+ if (n == 0) {
+ return 1;
+ } else {
+ return readFewBits(s, n) + (1 << n);
+ }
+ }
+ return 0;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function decodeMetaBlockLength(s) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ s.inputEnd = readFewBits(s, 1);
+ s.metaBlockLength = 0;
+ s.isUncompressed = 0;
+ s.isMetadata = 0;
+ if ((s.inputEnd != 0) && readFewBits(s, 1) != 0) {
+ return;
+ }
+ var /** number */ sizeNibbles = readFewBits(s, 2) + 4;
+ if (sizeNibbles == 7) {
+ s.isMetadata = 1;
+ if (readFewBits(s, 1) != 0) {
+ throw "Corrupted reserved bit";
+ }
+ var /** number */ sizeBytes = readFewBits(s, 2);
+ if (sizeBytes == 0) {
+ return;
+ }
+ for (var /** number */ i = 0; i < sizeBytes; i++) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ bits = readFewBits(s, 8);
+ if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
+ throw "Exuberant nibble";
+ }
+ s.metaBlockLength |= bits << (i * 8);
+ }
+ } else {
+ for (var /** number */ i = 0; i < sizeNibbles; i++) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ bits = readFewBits(s, 4);
+ if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
+ throw "Exuberant nibble";
+ }
+ s.metaBlockLength |= bits << (i * 4);
+ }
+ }
+ s.metaBlockLength++;
+ if (s.inputEnd == 0) {
+ s.isUncompressed = readFewBits(s, 1);
+ }
+ }
+ /**
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readSymbol(tableGroup, tableIdx, s) {
+ var /** number */ offset = tableGroup[tableIdx];
+ var /** number */ val = (s.accumulator32 >>> s.bitOffset);
+ offset += val & 0xFF;
+ var /** number */ bits = tableGroup[offset] >> 16;
+ var /** number */ sym = tableGroup[offset] & 0xFFFF;
+ if (bits <= 8) {
+ s.bitOffset += bits;
+ return sym;
+ }
+ offset += sym;
+ var /** number */ mask = (1 << bits) - 1;
+ offset += (val & mask) >>> 8;
+ s.bitOffset += ((tableGroup[offset] >> 16) + 8);
+ return tableGroup[offset] & 0xFFFF;
+ }
+ /**
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readBlockLength(tableGroup, tableIdx, s) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ code = readSymbol(tableGroup, tableIdx, s);
+ var /** number */ n = BLOCK_LENGTH_N_BITS[code];
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ return BLOCK_LENGTH_OFFSET[code] + ((n <= 16) ? readFewBits(s, n) : readManyBits(s, n));
+ }
+ /**
+ * @param {!Int32Array} v
+ * @param {number} index
+ * @return {void}
+ */
+ function moveToFront(v, index) {
+ var /** number */ value = v[index];
+ for (; index > 0; index--) {
+ v[index] = v[index - 1];
+ }
+ v[0] = value;
+ }
+ /**
+ * @param {!Int8Array} v
+ * @param {number} vLen
+ * @return {void}
+ */
+ function inverseMoveToFrontTransform(v, vLen) {
+ var /** !Int32Array */ mtf = new Int32Array(256);
+ for (var /** number */ i = 0; i < 256; i++) {
+ mtf[i] = i;
+ }
+ for (var /** number */ i = 0; i < vLen; i++) {
+ var /** number */ index = v[i] & 0xFF;
+ v[i] = mtf[index];
+ if (index != 0) {
+ moveToFront(mtf, index);
+ }
+ }
+ }
+ /**
+ * @param {!Int32Array} codeLengthCodeLengths
+ * @param {number} numSymbols
+ * @param {!Int32Array} codeLengths
+ * @param {!State} s
+ * @return {void}
+ */
+ function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths, s) {
+ var /** number */ symbol = 0;
+ var /** number */ prevCodeLen = 8;
+ var /** number */ repeat = 0;
+ var /** number */ repeatCodeLen = 0;
+ var /** number */ space = 32768;
+ var /** !Int32Array */ table = new Int32Array(32 + 1);
+ var /** number */ tableIdx = table.length - 1;
+ buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, 18);
+ while (symbol < numSymbols && space > 0) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ p = (s.accumulator32 >>> s.bitOffset) & 31;
+ s.bitOffset += table[p] >> 16;
+ var /** number */ codeLen = table[p] & 0xFFFF;
+ if (codeLen < 16) {
+ repeat = 0;
+ codeLengths[symbol++] = codeLen;
+ if (codeLen != 0) {
+ prevCodeLen = codeLen;
+ space -= 32768 >> codeLen;
+ }
+ } else {
+ var /** number */ extraBits = codeLen - 14;
+ var /** number */ newLen = 0;
+ if (codeLen == 16) {
+ newLen = prevCodeLen;
+ }
+ if (repeatCodeLen != newLen) {
+ repeat = 0;
+ repeatCodeLen = newLen;
+ }
+ var /** number */ oldRepeat = repeat;
+ if (repeat > 0) {
+ repeat -= 2;
+ repeat <<= extraBits;
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ repeat += readFewBits(s, extraBits) + 3;
+ var /** number */ repeatDelta = repeat - oldRepeat;
+ if (symbol + repeatDelta > numSymbols) {
+ throw "symbol + repeatDelta > numSymbols";
+ }
+ for (var /** number */ i = 0; i < repeatDelta; i++) {
+ codeLengths[symbol++] = repeatCodeLen;
+ }
+ if (repeatCodeLen != 0) {
+ space -= repeatDelta << (15 - repeatCodeLen);
+ }
+ }
+ }
+ if (space != 0) {
+ throw "Unused space";
+ }
+ codeLengths.fill(0, symbol, numSymbols);
+ }
+ /**
+ * @param {!Int32Array} symbols
+ * @param {number} length
+ * @return {void}
+ */
+ function checkDupes(symbols, length) {
+ for (var /** number */ i = 0; i < length - 1; ++i) {
+ for (var /** number */ j = i + 1; j < length; ++j) {
+ if (symbols[i] == symbols[j]) {
+ throw "Duplicate simple Huffman code symbol";
+ }
+ }
+ }
+ }
+ /**
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
+ var /** !Int32Array */ codeLengths = new Int32Array(alphabetSizeLimit);
+ var /** !Int32Array */ symbols = new Int32Array(4);
+ var /** number */ maxBits = 1 + log2floor(alphabetSizeMax - 1);
+ var /** number */ numSymbols = readFewBits(s, 2) + 1;
+ for (var /** number */ i = 0; i < numSymbols; i++) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ symbol = readFewBits(s, maxBits);
+ if (symbol >= alphabetSizeLimit) {
+ throw "Can't readHuffmanCode";
+ }
+ symbols[i] = symbol;
+ }
+ checkDupes(symbols, numSymbols);
+ var /** number */ histogramId = numSymbols;
+ if (numSymbols == 4) {
+ histogramId += readFewBits(s, 1);
+ }
+ switch(histogramId) {
+ case 1:
+ codeLengths[symbols[0]] = 1;
+ break;
+ case 2:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 1;
+ break;
+ case 3:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ break;
+ case 4:
+ codeLengths[symbols[0]] = 2;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ codeLengths[symbols[3]] = 2;
+ break;
+ case 5:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 3;
+ codeLengths[symbols[3]] = 3;
+ break;
+ default:
+ break;
+ }
+ return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);
+ }
+ /**
+ * @param {number} alphabetSizeLimit
+ * @param {number} skip
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readComplexHuffmanCode(alphabetSizeLimit, skip, tableGroup, tableIdx, s) {
+ var /** !Int32Array */ codeLengths = new Int32Array(alphabetSizeLimit);
+ var /** !Int32Array */ codeLengthCodeLengths = new Int32Array(18);
+ var /** number */ space = 32;
+ var /** number */ numCodes = 0;
+ for (var /** number */ i = skip; i < 18 && space > 0; i++) {
+ var /** number */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ p = (s.accumulator32 >>> s.bitOffset) & 15;
+ s.bitOffset += FIXED_TABLE[p] >> 16;
+ var /** number */ v = FIXED_TABLE[p] & 0xFFFF;
+ codeLengthCodeLengths[codeLenIdx] = v;
+ if (v != 0) {
+ space -= (32 >> v);
+ numCodes++;
+ }
+ }
+ if (space != 0 && numCodes != 1) {
+ throw "Corrupted Huffman code histogram";
+ }
+ readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSizeLimit, codeLengths, s);
+ return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);
+ }
+ /**
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ simpleCodeOrSkip = readFewBits(s, 2);
+ if (simpleCodeOrSkip == 1) {
+ return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s);
+ } else {
+ return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s);
+ }
+ }
+ /**
+ * @param {number} contextMapSize
+ * @param {!Int8Array} contextMap
+ * @param {!State} s
+ * @return {number}
+ */
+ function decodeContextMap(contextMapSize, contextMap, s) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ var /** number */ numTrees = decodeVarLenUnsignedByte(s) + 1;
+ if (numTrees == 1) {
+ contextMap.fill(0, 0, contextMapSize);
+ return numTrees;
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ useRleForZeros = readFewBits(s, 1);
+ var /** number */ maxRunLengthPrefix = 0;
+ if (useRleForZeros != 0) {
+ maxRunLengthPrefix = readFewBits(s, 4) + 1;
+ }
+ var /** number */ alphabetSize = numTrees + maxRunLengthPrefix;
+ var /** number */ tableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSize + 31) >> 5];
+ var /** !Int32Array */ table = new Int32Array(tableSize + 1);
+ var /** number */ tableIdx = table.length - 1;
+ readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
+ for (var /** number */ i = 0; i < contextMapSize; ) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ code = readSymbol(table, tableIdx, s);
+ if (code == 0) {
+ contextMap[i] = 0;
+ i++;
+ } else if (code <= maxRunLengthPrefix) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ reps = (1 << code) + readFewBits(s, code);
+ while (reps != 0) {
+ if (i >= contextMapSize) {
+ throw "Corrupted context map";
+ }
+ contextMap[i] = 0;
+ i++;
+ reps--;
+ }
+ } else {
+ contextMap[i] = (code - maxRunLengthPrefix);
+ i++;
+ }
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ if (readFewBits(s, 1) == 1) {
+ inverseMoveToFrontTransform(contextMap, contextMapSize);
+ }
+ return numTrees;
+ }
+ /**
+ * @param {!State} s
+ * @param {number} treeType
+ * @param {number} numBlockTypes
+ * @return {number}
+ */
+ function decodeBlockTypeAndLength(s, treeType, numBlockTypes) {
+ var /** !Int32Array */ ringBuffers = s.rings;
+ var /** number */ offset = 4 + treeType * 2;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ blockType = readSymbol(s.blockTrees, 2 * treeType, s);
+ var /** number */ result = readBlockLength(s.blockTrees, 2 * treeType + 1, s);
+ if (blockType == 1) {
+ blockType = ringBuffers[offset + 1] + 1;
+ } else if (blockType == 0) {
+ blockType = ringBuffers[offset];
+ } else {
+ blockType -= 2;
+ }
+ if (blockType >= numBlockTypes) {
+ blockType -= numBlockTypes;
+ }
+ ringBuffers[offset] = ringBuffers[offset + 1];
+ ringBuffers[offset + 1] = blockType;
+ return result;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function decodeLiteralBlockSwitch(s) {
+ s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);
+ var /** number */ literalBlockType = s.rings[5];
+ s.contextMapSlice = literalBlockType << 6;
+ s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xFF;
+ var /** number */ contextMode = s.contextModes[literalBlockType];
+ s.contextLookupOffset1 = contextMode << 9;
+ s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function decodeCommandBlockSwitch(s) {
+ s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes);
+ s.commandTreeIdx = s.rings[7];
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function decodeDistanceBlockSwitch(s) {
+ s.distanceBlockLength = decodeBlockTypeAndLength(s, 2, s.numDistanceBlockTypes);
+ s.distContextMapSlice = s.rings[9] << 2;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function maybeReallocateRingBuffer(s) {
+ var /** number */ newSize = s.maxRingBufferSize;
+ if (newSize > s.expectedTotalSize) {
+ var /** number */ minimalNewSize = s.expectedTotalSize;
+ while ((newSize >> 1) > minimalNewSize) {
+ newSize >>= 1;
+ }
+ if ((s.inputEnd == 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
+ newSize = 16384;
+ }
+ }
+ if (newSize <= s.ringBufferSize) {
+ return;
+ }
+ var /** number */ ringBufferSizeWithSlack = newSize + 37;
+ var /** !Int8Array */ newBuffer = new Int8Array(ringBufferSizeWithSlack);
+ if (s.ringBuffer.length != 0) {
+ newBuffer.set(s.ringBuffer.subarray(0, 0 + s.ringBufferSize), 0);
+ }
+ s.ringBuffer = newBuffer;
+ s.ringBufferSize = newSize;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function readNextMetablockHeader(s) {
+ if (s.inputEnd != 0) {
+ s.nextRunningState = 10;
+ s.runningState = 12;
+ return;
+ }
+ s.literalTreeGroup = new Int32Array(0);
+ s.commandTreeGroup = new Int32Array(0);
+ s.distanceTreeGroup = new Int32Array(0);
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ decodeMetaBlockLength(s);
+ if ((s.metaBlockLength == 0) && (s.isMetadata == 0)) {
+ return;
+ }
+ if ((s.isUncompressed != 0) || (s.isMetadata != 0)) {
+ jumpToByteBoundary(s);
+ s.runningState = (s.isMetadata != 0) ? 5 : 6;
+ } else {
+ s.runningState = 3;
+ }
+ if (s.isMetadata != 0) {
+ return;
+ }
+ s.expectedTotalSize += s.metaBlockLength;
+ if (s.expectedTotalSize > 1 << 30) {
+ s.expectedTotalSize = 1 << 30;
+ }
+ if (s.ringBufferSize < s.maxRingBufferSize) {
+ maybeReallocateRingBuffer(s);
+ }
+ }
+ /**
+ * @param {!State} s
+ * @param {number} treeType
+ * @param {number} numBlockTypes
+ * @return {number}
+ */
+ function readMetablockPartition(s, treeType, numBlockTypes) {
+ var /** number */ offset = s.blockTrees[2 * treeType];
+ if (numBlockTypes <= 1) {
+ s.blockTrees[2 * treeType + 1] = offset;
+ s.blockTrees[2 * treeType + 2] = offset;
+ return 1 << 28;
+ }
+ var /** number */ blockTypeAlphabetSize = numBlockTypes + 2;
+ offset += readHuffmanCode(blockTypeAlphabetSize, blockTypeAlphabetSize, s.blockTrees, 2 * treeType, s);
+ s.blockTrees[2 * treeType + 1] = offset;
+ var /** number */ blockLengthAlphabetSize = 26;
+ offset += readHuffmanCode(blockLengthAlphabetSize, blockLengthAlphabetSize, s.blockTrees, 2 * treeType + 1, s);
+ s.blockTrees[2 * treeType + 2] = offset;
+ return readBlockLength(s.blockTrees, 2 * treeType + 1, s);
+ }
+ /**
+ * @param {!State} s
+ * @param {number} alphabetSizeLimit
+ * @return {void}
+ */
+ function calculateDistanceLut(s, alphabetSizeLimit) {
+ var /** !Int8Array */ distExtraBits = s.distExtraBits;
+ var /** !Int32Array */ distOffset = s.distOffset;
+ var /** number */ npostfix = s.distancePostfixBits;
+ var /** number */ ndirect = s.numDirectDistanceCodes;
+ var /** number */ postfix = 1 << npostfix;
+ var /** number */ bits = 1;
+ var /** number */ half = 0;
+ var /** number */ i = 16;
+ for (var /** number */ j = 0; j < ndirect; ++j) {
+ distExtraBits[i] = 0;
+ distOffset[i] = j + 1;
+ ++i;
+ }
+ while (i < alphabetSizeLimit) {
+ var /** number */ base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
+ for (var /** number */ j = 0; j < postfix; ++j) {
+ distExtraBits[i] = bits;
+ distOffset[i] = base + j;
+ ++i;
+ }
+ bits = bits + half;
+ half = half ^ 1;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function readMetablockHuffmanCodesAndContextMaps(s) {
+ s.numLiteralBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.literalBlockLength = readMetablockPartition(s, 0, s.numLiteralBlockTypes);
+ s.numCommandBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.commandBlockLength = readMetablockPartition(s, 1, s.numCommandBlockTypes);
+ s.numDistanceBlockTypes = decodeVarLenUnsignedByte(s) + 1;
+ s.distanceBlockLength = readMetablockPartition(s, 2, s.numDistanceBlockTypes);
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ s.distancePostfixBits = readFewBits(s, 2);
+ s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;
+ s.distancePostfixMask = (1 << s.distancePostfixBits) - 1;
+ s.contextModes = new Int8Array(s.numLiteralBlockTypes);
+ for (var /** number */ i = 0; i < s.numLiteralBlockTypes; ) {
+ var /** number */ limit = min(i + 96, s.numLiteralBlockTypes);
+ for (; i < limit; ++i) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ s.contextModes[i] = readFewBits(s, 2);
+ }
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ }
+ s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6);
+ var /** number */ numLiteralTrees = decodeContextMap(s.numLiteralBlockTypes << 6, s.contextMap, s);
+ s.trivialLiteralContext = 1;
+ for (var /** number */ j = 0; j < s.numLiteralBlockTypes << 6; j++) {
+ if (s.contextMap[j] != j >> 6) {
+ s.trivialLiteralContext = 0;
+ break;
+ }
+ }
+ s.distContextMap = new Int8Array(s.numDistanceBlockTypes << 2);
+ var /** number */ numDistTrees = decodeContextMap(s.numDistanceBlockTypes << 2, s.distContextMap, s);
+ s.literalTreeGroup = decodeHuffmanTreeGroup(256, 256, numLiteralTrees, s);
+ s.commandTreeGroup = decodeHuffmanTreeGroup(704, 704, s.numCommandBlockTypes, s);
+ var /** number */ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, 24);
+ var /** number */ distanceAlphabetSizeLimit = distanceAlphabetSizeMax;
+ if (s.isLargeWindow == 1) {
+ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, 62);
+ distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit(0x7FFFFFFC, s.distancePostfixBits, s.numDirectDistanceCodes);
+ }
+ s.distanceTreeGroup = decodeHuffmanTreeGroup(distanceAlphabetSizeMax, distanceAlphabetSizeLimit, numDistTrees, s);
+ calculateDistanceLut(s, distanceAlphabetSizeLimit);
+ s.contextMapSlice = 0;
+ s.distContextMapSlice = 0;
+ s.contextLookupOffset1 = s.contextModes[0] * 512;
+ s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
+ s.literalTreeIdx = 0;
+ s.commandTreeIdx = 0;
+ s.rings[4] = 1;
+ s.rings[5] = 0;
+ s.rings[6] = 1;
+ s.rings[7] = 0;
+ s.rings[8] = 1;
+ s.rings[9] = 0;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function copyUncompressedData(s) {
+ var /** !Int8Array */ ringBuffer = s.ringBuffer;
+ if (s.metaBlockLength <= 0) {
+ reload(s);
+ s.runningState = 2;
+ return;
+ }
+ var /** number */ chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength);
+ copyBytes(s, ringBuffer, s.pos, chunkLength);
+ s.metaBlockLength -= chunkLength;
+ s.pos += chunkLength;
+ if (s.pos == s.ringBufferSize) {
+ s.nextRunningState = 6;
+ s.runningState = 12;
+ return;
+ }
+ reload(s);
+ s.runningState = 2;
+ }
+ /**
+ * @param {!State} s
+ * @return {number}
+ */
+ function writeRingBuffer(s) {
+ var /** number */ toWrite = min(s.outputLength - s.outputUsed, s.ringBufferBytesReady - s.ringBufferBytesWritten);
+ if (toWrite != 0) {
+ s.output.set(s.ringBuffer.subarray(s.ringBufferBytesWritten, s.ringBufferBytesWritten + toWrite), s.outputOffset + s.outputUsed);
+ s.outputUsed += toWrite;
+ s.ringBufferBytesWritten += toWrite;
+ }
+ if (s.outputUsed < s.outputLength) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ /**
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {number} n
+ * @param {!State} s
+ * @return {!Int32Array}
+ */
+ function decodeHuffmanTreeGroup(alphabetSizeMax, alphabetSizeLimit, n, s) {
+ var /** number */ maxTableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSizeLimit + 31) >> 5];
+ var /** !Int32Array */ group = new Int32Array(n + n * maxTableSize);
+ var /** number */ next = n;
+ for (var /** number */ i = 0; i < n; ++i) {
+ group[i] = next;
+ next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s);
+ }
+ return group;
+ }
+ /**
+ * @param {!State} s
+ * @return {number}
+ */
+ function calculateFence(s) {
+ var /** number */ result = s.ringBufferSize;
+ if (s.isEager != 0) {
+ result = min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed);
+ }
+ return result;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function decompress(s) {
+ if (s.runningState == 0) {
+ throw "Can't decompress until initialized";
+ }
+ if (s.runningState == 11) {
+ throw "Can't decompress after close";
+ }
+ if (s.runningState == 1) {
+ var /** number */ windowBits = decodeWindowBits(s);
+ if (windowBits == -1) {
+ throw "Invalid 'windowBits' code";
+ }
+ s.maxRingBufferSize = 1 << windowBits;
+ s.maxBackwardDistance = s.maxRingBufferSize - 16;
+ s.runningState = 2;
+ }
+ var /** number */ fence = calculateFence(s);
+ var /** number */ ringBufferMask = s.ringBufferSize - 1;
+ var /** !Int8Array */ ringBuffer = s.ringBuffer;
+ while (s.runningState != 10) {
+ switch(s.runningState) {
+ case 2:
+ if (s.metaBlockLength < 0) {
+ throw "Invalid metablock length";
+ }
+ readNextMetablockHeader(s);
+ fence = calculateFence(s);
+ ringBufferMask = s.ringBufferSize - 1;
+ ringBuffer = s.ringBuffer;
+ continue;
+ case 3:
+ readMetablockHuffmanCodesAndContextMaps(s);
+ s.runningState = 4;
+ case 4:
+ if (s.metaBlockLength <= 0) {
+ s.runningState = 2;
+ continue;
+ }
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.commandBlockLength == 0) {
+ decodeCommandBlockSwitch(s);
+ }
+ s.commandBlockLength--;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2;
+ var /** number */ insertAndCopyExtraBits = CMD_LOOKUP[cmdCode];
+ var /** number */ insertLengthOffset = CMD_LOOKUP[cmdCode + 1];
+ var /** number */ copyLengthOffset = CMD_LOOKUP[cmdCode + 2];
+ s.distanceCode = CMD_LOOKUP[cmdCode + 3];
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ extraBits = insertAndCopyExtraBits & 0xFF;
+ s.insertLength = insertLengthOffset + ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ extraBits = insertAndCopyExtraBits >> 8;
+ s.copyLength = copyLengthOffset + ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
+ s.j = 0;
+ s.runningState = 7;
+ case 7:
+ if (s.trivialLiteralContext != 0) {
+ while (s.j < s.insertLength) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.literalBlockLength == 0) {
+ decodeLiteralBlockSwitch(s);
+ }
+ s.literalBlockLength--;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ ringBuffer[s.pos] = readSymbol(s.literalTreeGroup, s.literalTreeIdx, s);
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = 7;
+ s.runningState = 12;
+ break;
+ }
+ }
+ } else {
+ var /** number */ prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF;
+ var /** number */ prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF;
+ while (s.j < s.insertLength) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.literalBlockLength == 0) {
+ decodeLiteralBlockSwitch(s);
+ }
+ var /** number */ literalContext = LOOKUP[s.contextLookupOffset1 + prevByte1] | LOOKUP[s.contextLookupOffset2 + prevByte2];
+ var /** number */ literalTreeIdx = s.contextMap[s.contextMapSlice + literalContext] & 0xFF;
+ s.literalBlockLength--;
+ prevByte2 = prevByte1;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ prevByte1 = readSymbol(s.literalTreeGroup, literalTreeIdx, s);
+ ringBuffer[s.pos] = prevByte1;
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = 7;
+ s.runningState = 12;
+ break;
+ }
+ }
+ }
+ if (s.runningState != 7) {
+ continue;
+ }
+ s.metaBlockLength -= s.insertLength;
+ if (s.metaBlockLength <= 0) {
+ s.runningState = 4;
+ continue;
+ }
+ var /** number */ distanceCode = s.distanceCode;
+ if (distanceCode < 0) {
+ s.distance = s.rings[s.distRbIdx];
+ } else {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.distanceBlockLength == 0) {
+ decodeDistanceBlockSwitch(s);
+ }
+ s.distanceBlockLength--;
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ distTreeIdx = s.distContextMap[s.distContextMapSlice + distanceCode] & 0xFF;
+ distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s);
+ if (distanceCode < 16) {
+ var /** number */ index = (s.distRbIdx + DISTANCE_SHORT_CODE_INDEX_OFFSET[distanceCode]) & 0x3;
+ s.distance = s.rings[index] + DISTANCE_SHORT_CODE_VALUE_OFFSET[distanceCode];
+ if (s.distance < 0) {
+ throw "Negative distance";
+ }
+ } else {
+ var /** number */ extraBits = s.distExtraBits[distanceCode];
+ var /** number */ bits;
+ if (s.bitOffset + extraBits <= 32) {
+ bits = readFewBits(s, extraBits);
+ } else {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ bits = ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
+ }
+ s.distance = s.distOffset[distanceCode] + (bits << s.distancePostfixBits);
+ }
+ }
+ if (s.maxDistance != s.maxBackwardDistance && s.pos < s.maxBackwardDistance) {
+ s.maxDistance = s.pos;
+ } else {
+ s.maxDistance = s.maxBackwardDistance;
+ }
+ if (s.distance > s.maxDistance) {
+ s.runningState = 9;
+ continue;
+ }
+ if (distanceCode > 0) {
+ s.distRbIdx = (s.distRbIdx + 1) & 0x3;
+ s.rings[s.distRbIdx] = s.distance;
+ }
+ if (s.copyLength > s.metaBlockLength) {
+ throw "Invalid backward reference";
+ }
+ s.j = 0;
+ s.runningState = 8;
+ case 8:
+ var /** number */ src = (s.pos - s.distance) & ringBufferMask;
+ var /** number */ dst = s.pos;
+ var /** number */ copyLength = s.copyLength - s.j;
+ var /** number */ srcEnd = src + copyLength;
+ var /** number */ dstEnd = dst + copyLength;
+ if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
+ if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
+ for (var /** number */ k = 0; k < copyLength; k += 4) {
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ ringBuffer[dst++] = ringBuffer[src++];
+ }
+ } else {
+ ringBuffer.copyWithin(dst, src, srcEnd);
+ }
+ s.j += copyLength;
+ s.metaBlockLength -= copyLength;
+ s.pos += copyLength;
+ } else {
+ for (; s.j < s.copyLength; ) {
+ ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask];
+ s.metaBlockLength--;
+ s.pos++;
+ s.j++;
+ if (s.pos >= fence) {
+ s.nextRunningState = 8;
+ s.runningState = 12;
+ break;
+ }
+ }
+ }
+ if (s.runningState == 8) {
+ s.runningState = 4;
+ }
+ continue;
+ case 9:
+ if (s.distance > 0x7FFFFFFC) {
+ throw "Invalid backward reference";
+ }
+ if (s.copyLength >= 4 && s.copyLength <= 24) {
+ var /** number */ offset = DICTIONARY_OFFSETS_BY_LENGTH[s.copyLength];
+ var /** number */ wordId = s.distance - s.maxDistance - 1;
+ var /** number */ shift = DICTIONARY_SIZE_BITS_BY_LENGTH[s.copyLength];
+ var /** number */ mask = (1 << shift) - 1;
+ var /** number */ wordIdx = wordId & mask;
+ var /** number */ transformIdx = wordId >>> shift;
+ offset += wordIdx * s.copyLength;
+ if (transformIdx < 121) {
+ var /** number */ len = transformDictionaryWord(ringBuffer, s.pos, DICTIONARY_DATA, offset, s.copyLength, RFC_TRANSFORMS, transformIdx);
+ s.pos += len;
+ s.metaBlockLength -= len;
+ if (s.pos >= fence) {
+ s.nextRunningState = 4;
+ s.runningState = 12;
+ continue;
+ }
+ } else {
+ throw "Invalid backward reference";
+ }
+ } else {
+ throw "Invalid backward reference";
+ }
+ s.runningState = 4;
+ continue;
+ case 5:
+ while (s.metaBlockLength > 0) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ readFewBits(s, 8);
+ s.metaBlockLength--;
+ }
+ s.runningState = 2;
+ continue;
+ case 6:
+ copyUncompressedData(s);
+ continue;
+ case 12:
+ s.ringBufferBytesReady = min(s.pos, s.ringBufferSize);
+ s.runningState = 13;
+ case 13:
+ if (writeRingBuffer(s) == 0) {
+ return;
+ }
+ if (s.pos >= s.maxBackwardDistance) {
+ s.maxDistance = s.maxBackwardDistance;
+ }
+ if (s.pos >= s.ringBufferSize) {
+ if (s.pos > s.ringBufferSize) {
+ ringBuffer.copyWithin(0, s.ringBufferSize, s.pos);
+ }
+ s.pos &= ringBufferMask;
+ s.ringBufferBytesWritten = 0;
+ }
+ s.runningState = s.nextRunningState;
+ continue;
+ default:
+ throw "Unexpected state " + s.runningState;
+ }
+ }
+ if (s.runningState == 10) {
+ if (s.metaBlockLength < 0) {
+ throw "Invalid metablock length";
+ }
+ jumpToByteBoundary(s);
+ checkHealth(s, 1);
+ }
+ }
+
+ /**
+ * @constructor
+ * @param {number} numTransforms
+ * @param {number} prefixSuffixLen
+ * @param {number} prefixSuffixCount
+ * @struct
+ */
+ function Transforms(numTransforms, prefixSuffixLen, prefixSuffixCount) {
+ /** @type {!number} */
+ this.numTransforms = 0;
+ /** @type {!Int32Array} */
+ this.triplets = new Int32Array(0);
+ /** @type {!Int8Array} */
+ this.prefixSuffixStorage = new Int8Array(0);
+ /** @type {!Int32Array} */
+ this.prefixSuffixHeads = new Int32Array(0);
+ /** @type {!Int16Array} */
+ this.params = new Int16Array(0);
+ this.numTransforms = numTransforms;
+ this.triplets = new Int32Array(numTransforms * 3);
+ this.params = new Int16Array(numTransforms);
+ this.prefixSuffixStorage = new Int8Array(prefixSuffixLen);
+ this.prefixSuffixHeads = new Int32Array(prefixSuffixCount + 1);
+ }
+
+ var RFC_TRANSFORMS = new Transforms(121, 167, 50);
+ /**
+ * @param {!Int8Array} prefixSuffix
+ * @param {!Int32Array} prefixSuffixHeads
+ * @param {!Int32Array} transforms
+ * @param {!string} prefixSuffixSrc
+ * @param {!string} transformsSrc
+ * @return {void}
+ */
+ function unpackTransforms(prefixSuffix, prefixSuffixHeads, transforms, prefixSuffixSrc, transformsSrc) {
+ var /** number */ n = prefixSuffixSrc.length;
+ var /** number */ index = 1;
+ var /** number */ j = 0;
+ for (var /** number */ i = 0; i < n; ++i) {
+ var /** number */ c = prefixSuffixSrc.charCodeAt(i);
+ if (c == 35) {
+ prefixSuffixHeads[index++] = j;
+ } else {
+ prefixSuffix[j++] = c;
+ }
+ }
+ for (var /** number */ i = 0; i < 363; ++i) {
+ transforms[i] = transformsSrc.charCodeAt(i) - 32;
+ }
+ }
+ {
+ unpackTransforms(RFC_TRANSFORMS.prefixSuffixStorage, RFC_TRANSFORMS.prefixSuffixHeads, RFC_TRANSFORMS.triplets, "# #s #, #e #.# the #.com/#\u00C2\u00A0# of # and # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #ous #", " !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");
+ }
+ /**
+ * @param {!Int8Array} dst
+ * @param {number} dstOffset
+ * @param {!Int8Array} src
+ * @param {number} srcOffset
+ * @param {number} len
+ * @param {!Transforms} transforms
+ * @param {number} transformIndex
+ * @return {number}
+ */
+ function transformDictionaryWord(dst, dstOffset, src, srcOffset, len, transforms, transformIndex) {
+ var /** number */ offset = dstOffset;
+ var /** !Int32Array */ triplets = transforms.triplets;
+ var /** !Int8Array */ prefixSuffixStorage = transforms.prefixSuffixStorage;
+ var /** !Int32Array */ prefixSuffixHeads = transforms.prefixSuffixHeads;
+ var /** number */ transformOffset = 3 * transformIndex;
+ var /** number */ prefixIdx = triplets[transformOffset];
+ var /** number */ transformType = triplets[transformOffset + 1];
+ var /** number */ suffixIdx = triplets[transformOffset + 2];
+ var /** number */ prefix = prefixSuffixHeads[prefixIdx];
+ var /** number */ prefixEnd = prefixSuffixHeads[prefixIdx + 1];
+ var /** number */ suffix = prefixSuffixHeads[suffixIdx];
+ var /** number */ suffixEnd = prefixSuffixHeads[suffixIdx + 1];
+ var /** number */ omitFirst = transformType - 11;
+ var /** number */ omitLast = transformType - 0;
+ if (omitFirst < 1 || omitFirst > 9) {
+ omitFirst = 0;
+ }
+ if (omitLast < 1 || omitLast > 9) {
+ omitLast = 0;
+ }
+ while (prefix != prefixEnd) {
+ dst[offset++] = prefixSuffixStorage[prefix++];
+ }
+ if (omitFirst > len) {
+ omitFirst = len;
+ }
+ srcOffset += omitFirst;
+ len -= omitFirst;
+ len -= omitLast;
+ var /** number */ i = len;
+ while (i > 0) {
+ dst[offset++] = src[srcOffset++];
+ i--;
+ }
+ if (transformType == 10 || transformType == 11) {
+ var /** number */ uppercaseOffset = offset - len;
+ if (transformType == 10) {
+ len = 1;
+ }
+ while (len > 0) {
+ var /** number */ c0 = dst[uppercaseOffset] & 0xFF;
+ if (c0 < 0xC0) {
+ if (c0 >= 97 && c0 <= 122) {
+ dst[uppercaseOffset] ^= 32;
+ }
+ uppercaseOffset += 1;
+ len -= 1;
+ } else if (c0 < 0xE0) {
+ dst[uppercaseOffset + 1] ^= 32;
+ uppercaseOffset += 2;
+ len -= 2;
+ } else {
+ dst[uppercaseOffset + 2] ^= 5;
+ uppercaseOffset += 3;
+ len -= 3;
+ }
+ }
+ } else if (transformType == 21 || transformType == 22) {
+ var /** number */ shiftOffset = offset - len;
+ var /** number */ param = transforms.params[transformIndex];
+ var /** number */ scalar = (param & 0x7FFF) + (0x1000000 - (param & 0x8000));
+ while (len > 0) {
+ var /** number */ step = 1;
+ var /** number */ c0 = dst[shiftOffset] & 0xFF;
+ if (c0 < 0x80) {
+ scalar += c0;
+ dst[shiftOffset] = (scalar & 0x7F);
+ } else if (c0 < 0xC0) {
+ } else if (c0 < 0xE0) {
+ if (len >= 2) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
+ dst[shiftOffset] = (0xC0 | ((scalar >> 6) & 0x1F));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | (scalar & 0x3F));
+ step = 2;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF0) {
+ if (len >= 3) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ var /** number */ c2 = dst[shiftOffset + 2];
+ scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
+ dst[shiftOffset] = (0xE0 | ((scalar >> 12) & 0x0F));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 2] = ((c2 & 0xC0) | (scalar & 0x3F));
+ step = 3;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF8) {
+ if (len >= 4) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ var /** number */ c2 = dst[shiftOffset + 2];
+ var /** number */ c3 = dst[shiftOffset + 3];
+ scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
+ dst[shiftOffset] = (0xF0 | ((scalar >> 18) & 0x07));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 12) & 0x3F));
+ dst[shiftOffset + 2] = ((c2 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 3] = ((c3 & 0xC0) | (scalar & 0x3F));
+ step = 4;
+ } else {
+ step = len;
+ }
+ }
+ shiftOffset += step;
+ len -= step;
+ if (transformType == 21) {
+ len = 0;
+ }
+ }
+ }
+ while (suffix != suffixEnd) {
+ dst[offset++] = prefixSuffixStorage[suffix++];
+ }
+ return offset - dstOffset;
+ }
+
+ /**
+ * @param {number} key
+ * @param {number} len
+ * @return {number}
+ */
+ function getNextKey(key, len) {
+ var /** number */ step = 1 << (len - 1);
+ while ((key & step) != 0) {
+ step >>= 1;
+ }
+ return (key & (step - 1)) + step;
+ }
+ /**
+ * @param {!Int32Array} table
+ * @param {number} offset
+ * @param {number} step
+ * @param {number} end
+ * @param {number} item
+ * @return {void}
+ */
+ function replicateValue(table, offset, step, end, item) {
+ do {
+ end -= step;
+ table[offset + end] = item;
+ } while (end > 0);
+ }
+ /**
+ * @param {!Int32Array} count
+ * @param {number} len
+ * @param {number} rootBits
+ * @return {number}
+ */
+ function nextTableBitSize(count, len, rootBits) {
+ var /** number */ left = 1 << (len - rootBits);
+ while (len < 15) {
+ left -= count[len];
+ if (left <= 0) {
+ break;
+ }
+ len++;
+ left <<= 1;
+ }
+ return len - rootBits;
+ }
+ /**
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {number} rootBits
+ * @param {!Int32Array} codeLengths
+ * @param {number} codeLengthsSize
+ * @return {number}
+ */
+ function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLengthsSize) {
+ var /** number */ tableOffset = tableGroup[tableIdx];
+ var /** number */ key;
+ var /** !Int32Array */ sorted = new Int32Array(codeLengthsSize);
+ var /** !Int32Array */ count = new Int32Array(16);
+ var /** !Int32Array */ offset = new Int32Array(16);
+ var /** number */ symbol;
+ for (symbol = 0; symbol < codeLengthsSize; symbol++) {
+ count[codeLengths[symbol]]++;
+ }
+ offset[1] = 0;
+ for (var /** number */ len = 1; len < 15; len++) {
+ offset[len + 1] = offset[len] + count[len];
+ }
+ for (symbol = 0; symbol < codeLengthsSize; symbol++) {
+ if (codeLengths[symbol] != 0) {
+ sorted[offset[codeLengths[symbol]]++] = symbol;
+ }
+ }
+ var /** number */ tableBits = rootBits;
+ var /** number */ tableSize = 1 << tableBits;
+ var /** number */ totalSize = tableSize;
+ if (offset[15] == 1) {
+ for (key = 0; key < totalSize; key++) {
+ tableGroup[tableOffset + key] = sorted[0];
+ }
+ return totalSize;
+ }
+ key = 0;
+ symbol = 0;
+ for (var /** number */ len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
+ for (; count[len] > 0; count[len]--) {
+ replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
+ key = getNextKey(key, len);
+ }
+ }
+ var /** number */ mask = totalSize - 1;
+ var /** number */ low = -1;
+ var /** number */ currentOffset = tableOffset;
+ for (var /** number */ len = rootBits + 1, step = 2; len <= 15; len++, step <<= 1) {
+ for (; count[len] > 0; count[len]--) {
+ if ((key & mask) != low) {
+ currentOffset += tableSize;
+ tableBits = nextTableBitSize(count, len, rootBits);
+ tableSize = 1 << tableBits;
+ totalSize += tableSize;
+ low = key & mask;
+ tableGroup[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
+ }
+ replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
+ key = getNextKey(key, len);
+ }
+ }
+ return totalSize;
+ }
+
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function doReadMoreInput(s) {
+ if (s.endOfStreamReached != 0) {
+ if (halfAvailable(s) >= -2) {
+ return;
+ }
+ throw "No more input";
+ }
+ var /** number */ readOffset = s.halfOffset << 1;
+ var /** number */ bytesInBuffer = 4096 - readOffset;
+ s.byteBuffer.copyWithin(0, readOffset, 4096);
+ s.halfOffset = 0;
+ while (bytesInBuffer < 4096) {
+ var /** number */ spaceLeft = 4096 - bytesInBuffer;
+ var /** number */ len = readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
+ if (len <= 0) {
+ s.endOfStreamReached = 1;
+ s.tailBytes = bytesInBuffer;
+ bytesInBuffer += 1;
+ break;
+ }
+ bytesInBuffer += len;
+ }
+ bytesToNibbles(s, bytesInBuffer);
+ }
+ /**
+ * @param {!State} s
+ * @param {number} endOfStream
+ * @return {void}
+ */
+ function checkHealth(s, endOfStream) {
+ if (s.endOfStreamReached == 0) {
+ return;
+ }
+ var /** number */ byteOffset = (s.halfOffset << 1) + ((s.bitOffset + 7) >> 3) - 4;
+ if (byteOffset > s.tailBytes) {
+ throw "Read after end";
+ }
+ if ((endOfStream != 0) && (byteOffset != s.tailBytes)) {
+ throw "Unused bytes after end";
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function assertAccumulatorHealthy(s) {
+ if (s.bitOffset > 32) {
+ throw "Accumulator underloaded: " + s.bitOffset;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @param {number} n
+ * @return {number}
+ */
+ function readFewBits(s, n) {
+ var /** number */ val = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1);
+ s.bitOffset += n;
+ return val;
+ }
+ /**
+ * @param {!State} s
+ * @param {number} n
+ * @return {number}
+ */
+ function readManyBits(s, n) {
+ var /** number */ low = readFewBits(s, 16);
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ return low | (readFewBits(s, n - 16) << 16);
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function initBitReader(s) {
+ s.byteBuffer = new Int8Array(4160);
+ s.accumulator32 = 0;
+ s.shortBuffer = new Int16Array(2080);
+ s.bitOffset = 32;
+ s.halfOffset = 2048;
+ s.endOfStreamReached = 0;
+ prepare(s);
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function prepare(s) {
+ if (s.halfOffset > 2030) {
+ doReadMoreInput(s);
+ }
+ checkHealth(s, 0);
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function reload(s) {
+ if (s.bitOffset == 32) {
+ prepare(s);
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function jumpToByteBoundary(s) {
+ var /** number */ padding = (32 - s.bitOffset) & 7;
+ if (padding != 0) {
+ var /** number */ paddingBits = readFewBits(s, padding);
+ if (paddingBits != 0) {
+ throw "Corrupted padding bits";
+ }
+ }
+ }
+ /**
+ * @param {!State} s
+ * @return {number}
+ */
+ function halfAvailable(s) {
+ var /** number */ limit = 2048;
+ if (s.endOfStreamReached != 0) {
+ limit = (s.tailBytes + 1) >> 1;
+ }
+ return limit - s.halfOffset;
+ }
+ /**
+ * @param {!State} s
+ * @param {!Int8Array} data
+ * @param {number} offset
+ * @param {number} length
+ * @return {void}
+ */
+ function copyBytes(s, data, offset, length) {
+ if ((s.bitOffset & 7) != 0) {
+ throw "Unaligned copyBytes";
+ }
+ while ((s.bitOffset != 32) && (length != 0)) {
+ data[offset++] = (s.accumulator32 >>> s.bitOffset);
+ s.bitOffset += 8;
+ length--;
+ }
+ if (length == 0) {
+ return;
+ }
+ var /** number */ copyNibbles = min(halfAvailable(s), length >> 1);
+ if (copyNibbles > 0) {
+ var /** number */ readOffset = s.halfOffset << 1;
+ var /** number */ delta = copyNibbles << 1;
+ data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), offset);
+ offset += delta;
+ length -= delta;
+ s.halfOffset += copyNibbles;
+ }
+ if (length == 0) {
+ return;
+ }
+ if (halfAvailable(s) > 0) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ while (length != 0) {
+ data[offset++] = (s.accumulator32 >>> s.bitOffset);
+ s.bitOffset += 8;
+ length--;
+ }
+ checkHealth(s, 0);
+ return;
+ }
+ while (length > 0) {
+ var /** number */ len = readInput(s.input, data, offset, length);
+ if (len == -1) {
+ throw "Unexpected end of input";
+ }
+ offset += len;
+ length -= len;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @param {number} byteLen
+ * @return {void}
+ */
+ function bytesToNibbles(s, byteLen) {
+ var /** !Int8Array */ byteBuffer = s.byteBuffer;
+ var /** number */ halfLen = byteLen >> 1;
+ var /** !Int16Array */ shortBuffer = s.shortBuffer;
+ for (var /** number */ i = 0; i < halfLen; ++i) {
+ shortBuffer[i] = ((byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8));
+ }
+ }
+
+ var LOOKUP = new Int32Array(2048);
+ /**
+ * @param {!Int32Array} lookup
+ * @param {!string} map
+ * @param {!string} rle
+ * @return {void}
+ */
+ function unpackLookupTable(lookup, map, rle) {
+ for (var /** number */ i = 0; i < 256; ++i) {
+ lookup[i] = i & 0x3F;
+ lookup[512 + i] = i >> 2;
+ lookup[1792 + i] = 2 + (i >> 6);
+ }
+ for (var /** number */ i = 0; i < 128; ++i) {
+ lookup[1024 + i] = 4 * (map.charCodeAt(i) - 32);
+ }
+ for (var /** number */ i = 0; i < 64; ++i) {
+ lookup[1152 + i] = i & 1;
+ lookup[1216 + i] = 2 + (i & 1);
+ }
+ var /** number */ offset = 1280;
+ for (var /** number */ k = 0; k < 19; ++k) {
+ var /** number */ value = k & 3;
+ var /** number */ rep = rle.charCodeAt(k) - 32;
+ for (var /** number */ i = 0; i < rep; ++i) {
+ lookup[offset++] = value;
+ }
+ }
+ for (var /** number */ i = 0; i < 16; ++i) {
+ lookup[1792 + i] = 1;
+ lookup[2032 + i] = 6;
+ }
+ lookup[1792] = 0;
+ lookup[2047] = 7;
+ for (var /** number */ i = 0; i < 256; ++i) {
+ lookup[1536 + i] = lookup[1792 + i] << 3;
+ }
+ }
+ {
+ unpackLookupTable(LOOKUP, " !! ! \"#$##%#$&'##(#)#++++++++++((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# ", "A/* ': & : $ \u0081 @");
+ }
+
+ /**
+ * @constructor
+ * @struct
+ */
+ function State() {
+ /** @type {!Int8Array} */
+ this.ringBuffer = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.contextModes = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.contextMap = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.distContextMap = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.distExtraBits = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.output = new Int8Array(0);
+ /** @type {!Int8Array} */
+ this.byteBuffer = new Int8Array(0);
+ /** @type {!Int16Array} */
+ this.shortBuffer = new Int16Array(0);
+ /** @type {!Int32Array} */
+ this.intBuffer = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.rings = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.blockTrees = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.literalTreeGroup = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.commandTreeGroup = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.distanceTreeGroup = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.distOffset = new Int32Array(0);
+ /** @type {!number} */
+ this.runningState = 0;
+ /** @type {!number} */
+ this.nextRunningState = 0;
+ /** @type {!number} */
+ this.accumulator32 = 0;
+ /** @type {!number} */
+ this.bitOffset = 0;
+ /** @type {!number} */
+ this.halfOffset = 0;
+ /** @type {!number} */
+ this.tailBytes = 0;
+ /** @type {!number} */
+ this.endOfStreamReached = 0;
+ /** @type {!number} */
+ this.metaBlockLength = 0;
+ /** @type {!number} */
+ this.inputEnd = 0;
+ /** @type {!number} */
+ this.isUncompressed = 0;
+ /** @type {!number} */
+ this.isMetadata = 0;
+ /** @type {!number} */
+ this.literalBlockLength = 0;
+ /** @type {!number} */
+ this.numLiteralBlockTypes = 0;
+ /** @type {!number} */
+ this.commandBlockLength = 0;
+ /** @type {!number} */
+ this.numCommandBlockTypes = 0;
+ /** @type {!number} */
+ this.distanceBlockLength = 0;
+ /** @type {!number} */
+ this.numDistanceBlockTypes = 0;
+ /** @type {!number} */
+ this.pos = 0;
+ /** @type {!number} */
+ this.maxDistance = 0;
+ /** @type {!number} */
+ this.distRbIdx = 0;
+ /** @type {!number} */
+ this.trivialLiteralContext = 0;
+ /** @type {!number} */
+ this.literalTreeIdx = 0;
+ /** @type {!number} */
+ this.commandTreeIdx = 0;
+ /** @type {!number} */
+ this.j = 0;
+ /** @type {!number} */
+ this.insertLength = 0;
+ /** @type {!number} */
+ this.contextMapSlice = 0;
+ /** @type {!number} */
+ this.distContextMapSlice = 0;
+ /** @type {!number} */
+ this.contextLookupOffset1 = 0;
+ /** @type {!number} */
+ this.contextLookupOffset2 = 0;
+ /** @type {!number} */
+ this.distanceCode = 0;
+ /** @type {!number} */
+ this.numDirectDistanceCodes = 0;
+ /** @type {!number} */
+ this.distancePostfixMask = 0;
+ /** @type {!number} */
+ this.distancePostfixBits = 0;
+ /** @type {!number} */
+ this.distance = 0;
+ /** @type {!number} */
+ this.copyLength = 0;
+ /** @type {!number} */
+ this.maxBackwardDistance = 0;
+ /** @type {!number} */
+ this.maxRingBufferSize = 0;
+ /** @type {!number} */
+ this.ringBufferSize = 0;
+ /** @type {!number} */
+ this.expectedTotalSize = 0;
+ /** @type {!number} */
+ this.outputOffset = 0;
+ /** @type {!number} */
+ this.outputLength = 0;
+ /** @type {!number} */
+ this.outputUsed = 0;
+ /** @type {!number} */
+ this.ringBufferBytesWritten = 0;
+ /** @type {!number} */
+ this.ringBufferBytesReady = 0;
+ /** @type {!number} */
+ this.isEager = 0;
+ /** @type {!number} */
+ this.isLargeWindow = 0;
+ /** @type {!InputStream|null} */
+ this.input = null;
+ this.ringBuffer = new Int8Array(0);
+ this.rings = new Int32Array(10);
+ this.rings[0] = 16;
+ this.rings[1] = 15;
+ this.rings[2] = 11;
+ this.rings[3] = 4;
+ }
+
+ /**
+ * @param {!Int8Array} dictionary
+ * @param {!string} data0
+ * @param {!string} data1
+ * @param {!string} skipFlip
+ * @return {void}
+ */
+ function unpackDictionaryData(dictionary, data0, data1, skipFlip) {
+ var /** !Int8Array */ dict = toUsAsciiBytes(data0 + data1);
+ if (dict.length != dictionary.length) {
+ throw "Corrupted brotli dictionary";
+ }
+ var /** number */ offset = 0;
+ var /** number */ n = skipFlip.length;
+ for (var /** number */ i = 0; i < n; i += 2) {
+ var /** number */ skip = skipFlip.charCodeAt(i) - 36;
+ var /** number */ flip = skipFlip.charCodeAt(i + 1) - 36;
+ offset += skip;
+ for (var /** number */ j = 0; j < flip; ++j) {
+ dict[offset] |= 0x80;
+ offset++;
+ }
+ }
+ dictionary.set(dict);
+ }
+ {
+ var /** !Int8Array */ dictionary = new Int8Array(122784);
+ unpackDictionaryData(dictionary, "timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0\"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml\"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid=\"sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$(\"#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS\"agedgreyGET\"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:e*/\r\n 100hall.\n\nA7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,\r\n\r\ncoolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px''););\">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarmb\u0000\u0019sboys[0].');\"POSTbearkids);}}marytend(UK)quadzh:f-siz----prop');\rliftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene b\u0000\u0014softrometillross<h3>pourfadepink<tr>mini)|!(minezh:hbarshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json', 'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:d'));puremageparatonebond:37Z_of_']);000,zh:gtankyardbowlbush:56ZJava30px\n|}\n%C3%:34ZjeffEXPIcashvisagolfsnowzh:iquer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;\n}\nexit:35Zvarsbeat'});diet999;anne}}</[i].LangkmB2wiretoysaddssealalex;\n\t}echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}\ndustclip).\n\n70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}\r\nHEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-\n!002)ndow[1];[];\nLog salt\r\n\t\tbangtrimbath){\r\n00px\n});ko:lfeesad>\rs:// [];tollplug(){\n{\r\n .js'200pdualboat.JPG);\n}quot);\n\n');\n\r\n}\r201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomC!sesteestaperotodohacecadaaC1obiendC-aasC-vidacasootroforosolootracualdijosidograntipotemadebealgoquC)estonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiP7P0P=P0P>P<Q\u0000P0Q\u0000Q\u0003Q\u0002P0P=P5P?P>P>Q\u0002P8P7P=P>P4P>Q\u0002P>P6P5P>P=P8Q\u0005P\u001DP0P5P5P1Q\u000BP<Q\u000BP\u0012Q\u000BQ\u0001P>P2Q\u000BP2P>P\u001DP>P>P1P\u001FP>P;P8P=P8P P$P\u001DP5P\u001CQ\u000BQ\u0002Q\u000BP\u001EP=P8P<P4P0P\u0017P0P\u0014P0P\u001DQ\u0003P\u001EP1Q\u0002P5P\u0018P7P5P9P=Q\u0003P<P<P\"Q\u000BQ\u0003P6Y\u0001Y\nX#Y\u0006Y\u0005X'Y\u0005X9Y\u0003Y\u0004X#Y\u0008X1X/Y\nX'Y\u0001Y\tY\u0007Y\u0008Y\u0004Y\u0005Y\u0004Y\u0003X'Y\u0008Y\u0004Y\u0007X(X3X'Y\u0004X%Y\u0006Y\u0007Y\nX#Y\nY\u0002X/Y\u0007Y\u0004X+Y\u0005X(Y\u0007Y\u0004Y\u0008Y\u0004Y\nX(Y\u0004X'Y\nX(Y\u0003X4Y\nX'Y\u0005X#Y\u0005Y\u0006X*X(Y\nY\u0004Y\u0006X-X(Y\u0007Y\u0005Y\u0005X4Y\u0008X4firstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue\"crossspentblogsbox\">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav\">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera\"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow\">genretrucklooksValueFrame.net/-->\n<try {\nvar makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top\">\n<!--POST\"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url=\"parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();\" Blocklinuxjonespixel');\">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar\">.src=toweralt=\"cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});\r\nbandsqueue= {};80px;cking{\r\n\t\taheadclockirishlike ratiostatsForm\"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg\"spainbeachtaxesmicroangel--></giftssteve-linkbody.});\n\tmount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:c\u0002simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/\"1.jpgwmodeparamSTARTleft idden, 201);\n}\nform.viruschairtransworstPagesitionpatch<!--\no-cacfirmstours,000 asiani++){adobe')[0]id=10both;menu .2.mi.png\"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120\" sweettr>\r\nname=diegopage swiss-->\n\n#fff;\">Log.com\"treatsheet) && 14px;sleepntentfiledja:c\u0003id=\"cName\"worseshots-box-delta\n&lt;bears:48Z<data-rural</a> spendbakershops= \"\";php\">ction13px;brianhellosize=o=%2F joinmaybe<img img\">, fjsimg\" \")[0]MTopBType\"newlyDanskczechtrailknows</h5>faq\">zh-cn10);\n-1\");type=bluestrulydavis.js';>\r\n<!steel you h2>\r\nform jesus100% menu.\r\n\t\r\nwalesrisksumentddingb-likteachgif\" vegasdanskeestishqipsuomisobredesdeentretodospuedeaC1osestC!tienehastaotrospartedondenuevohacerformamismomejormundoaquC-dC-assC3loayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaC-snuevasaludforosmedioquienmesespoderchileserC!vecesdecirjosC)estarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocC3moenerojuegoperC:haberestoynuncamujervalorfueralibrogustaigualvotoscasosguC-apuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleC3nplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenC!readiscopedrocercapuedapapelmenorC:tilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniC1oquedapasarbancohijosviajepabloC)stevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallC-jovendichaestantalessalirsuelopesosfinesllamabuscoC)stalleganegroplazahumorpagarjuntadobleislasbolsabaC1ohablaluchaC\u0001readicenjugarnotasvalleallC!cargadolorabajoestC)gustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo\">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother\" id=\"marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo\" bottomlist\">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename=\"amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.\n\nOnejoinedmenu\">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo\">beyond-scaleacceptservedmarineFootercamera</h1>\n_form\"leavesstress\" />\r\n.gif\" onloadloaderOxfordsistersurvivlistenfemaleDesignsize=\"appealtext\">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main\">inlinesundaywrap\">failedcensusminutebeaconquotes150px|estateremoteemail\"linkedright;signalformal1.htmlsignupprincefloat:.png\" forum.AccesspaperssoundsextendHeightsliderUTF-8\"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome\">headerensurebranchpiecesblock;statedtop\"><racingresize--&gt;pacitysexualbureau.jpg\" 10,000obtaintitlesamount, Inc.comedymenu\" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page\">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline\">body\">\n* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox\">\nSystem DavidcancertablesprovedApril reallydriveritem\">more\">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php\" assumelayerswilsonstoresreliefswedenCustomeasily your String\n\nWhiltaylorclear:resortfrenchthough\") + \"<body>buyingbrandsMembername\">oppingsector5px;\">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink\">Images=falsewhile hspace0&amp; \n\nIn powerPolski-colorjordanBottomStart -count2.htmlnews\">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml\" rights.html-blockregExp:hoverwithinvirginphones</tr>\rusing \n\tvar >');\n\t</td>\n</tr>\nbahasabrasilgalegomagyarpolskisrpskiX1X/Y\u0008d8-f\u0016\u0007g.\u0000d=\u0013g9\u0001i+\u0014d?!f\u0001/d8-e\u001B=f\u0008\u0011d;,d8\u0000d8*e\u0005,e\u000F8g.!g\u0010\u0006h.:e\u001D\u001Be\u000F/d;%f\u001C\re\n!f\u00176i\u00174d8*d::d:'e\u0013\u0001h\u0007*e71d<\u0001d8\u001Af\u001F%g\u001C\u000Be7%d=\u001Ch\u0001\u0014g3;f2!f\u001C\tg=\u0011g+\u0019f\t\u0000f\u001C\th/\u0004h.:d8-e?\u0003f\u0016\u0007g+ g\u0014(f\u00087i&\u0016i!5d=\u001Ch\u0000\u0005f\n\u0000f\u001C/i\u0017.i\"\u0018g\u001B8e\u00053d8\u000Bh==f\u0010\u001Cg4\"d=?g\u0014(h=/d;6e\u001C(g:?d8;i\"\u0018h5\u0004f\u0016\u0019h'\u0006i\"\u0011e\u001B\u001Ee$\rf3(e\u0006\u000Cg=\u0011g;\u001Cf\u00146h\u0017\u000Fe\u0006\u0005e.9f\u000E(h\r\u0010e8\u0002e\u001C:f6\u0008f\u0001/g):i\u00174e\u000F\u0011e8\u0003d;\u0000d9\u0008e%=e\u000F\u000Bg\u0014\u001Ff4;e\u001B>g\t\u0007e\u000F\u0011e1\u0015e&\u0002f\u001E\u001Cf\t\u000Bf\u001C:f\u00160i\u0017;f\u001C\u0000f\u00160f\u00169e<\u000Fe\u000C\u0017d:,f\u000F\u0010d>\u001Be\u00053d:\u000Ef\u001B4e$\u001Ah?\u0019d8*g3;g;\u001Fg\u001F%i\u0001\u0013f88f\u0008\u000Fe9?e\u0011\ne\u00056d;\u0016e\u000F\u0011h!(e.\te\u0005(g,,d8\u0000d<\u001Ae\u0011\u0018h?\u001Bh!\u000Cg\u00029e\u0007;g\t\u0008f\u001D\u0003g\u00145e-\u0010d8\u0016g\u0015\u000Ch.>h.!e\u0005\rh49f\u0015\u0019h\u00022e\n e\u0005%f4;e\n(d;\u0016d;,e\u0015\u0006e\u0013\u0001e\r\u001Ae.\"g\u000E0e\u001C(d8\nf57e&\u0002d=\u0015e72g;\u000Fg\u0015\u0019h(\u0000h/&g;\u0006g$>e\u000C:g\u0019;e=\u0015f\u001C,g+\u0019i\u001C\u0000h&\u0001d;7f <f\u0014/f\u000C\u0001e\u001B=i\u0019\u0005i\u0013>f\u000E%e\u001B=e.6e;:h.>f\u001C\u000Be\u000F\u000Bi\u0018\u0005h/;f3\u0015e>\u000Bd=\rg=.g;\u000Ff5\u000Ei\u0000\tf\u000B)h?\u0019f 7e=\u0013e\t\re\u0008\u0006g1;f\u000E\u0012h!\u000Ce\u001B d8:d:$f\u0018\u0013f\u001C\u0000e\u0010\u000Ei\u001F3d9\u0010d8\rh\u0003=i\u0000\u001Ah?\u0007h!\u000Cd8\u001Ag'\u0011f\n\u0000e\u000F/h\u0003=h.>e$\u0007e\u0010\u0008d=\u001Ce$'e.6g$>d<\u001Ag \u0014g)6d8\u0013d8\u001Ae\u0005(i\u0003(i!9g\u001B.h?\u0019i\u0007\u000Ch?\u0018f\u0018/e<\u0000e'\u000Bf\u0003\u0005e\u00065g\u00145h\u0004\u0011f\u0016\u0007d;6e\u0013\u0001g\t\u000Ce8.e\n)f\u0016\u0007e\u000C\u0016h5\u0004f:\u0010e$'e-&e-&d9 e\u001C0e\u001D\u0000f5\u000Fh'\u0008f\n\u0015h5\u0004e7%g(\u000Bh&\u0001f1\u0002f\u0000\u000Ed9\u0008f\u00176e\u0000\u0019e\n\u001Fh\u0003=d8;h&\u0001g\u001B.e\t\rh5\u0004h./e\u001F\u000Ee8\u0002f\u00169f3\u0015g\u00145e=1f\u000B\u001Bh\u0001\u0018e#0f\u0018\u000Ed;;d=\u0015e\u0001%e:7f\u00150f\r.g>\u000Ee\u001B=f1=h=&d;\u000Bg;\rd=\u0006f\u0018/d:$f5\u0001g\u0014\u001Fd:'f\t\u0000d;%g\u00145h/\u001Df\u0018>g$:d8\u0000d:\u001Be\r\u0015d=\rd::e\u0011\u0018e\u0008\u0006f\u001E\u0010e\u001C0e\u001B>f\u0017\u0005f88e7%e\u00057e-&g\u0014\u001Fg3;e\u0008\u0017g=\u0011e\u000F\u000Be8\u0016e-\u0010e/\u0006g \u0001i\"\u0011i\u0001\u0013f\u000E'e\u00086e\u001C0e\u000C:e\u001F:f\u001C,e\u0005(e\u001B=g=\u0011d8\ni\u0007\rh&\u0001g,,d:\u000Ce\u0016\u001Cf,\"h?\u001Be\u0005%e\u000F\u000Bf\u0003\u0005h?\u0019d:\u001Bh\u0000\u0003h/\u0015e\u000F\u0011g\u000E0e\u001F9h.-d;%d8\nf\u0014?e:\u001Cf\u0008\u0010d8:g\u000E/e\"\u0003i&\u0019f8/e\u0010\u000Cf\u00176e(1d9\u0010e\u000F\u0011i\u0000\u0001d8\u0000e.\u001Ae<\u0000e\u000F\u0011d=\u001Ce\u0013\u0001f \u0007e\u0007\u0006f,\"h?\u000Eh'#e\u00063e\u001C0f\u00169d8\u0000d8\u000Bd;%e\u000F\nh4#d;;f\u0008\u0016h\u0000\u0005e.\"f\u00087d;#h!(g'/e\u0008\u0006e%3d::f\u00150g \u0001i\u0014\u0000e\u0014.e\u0007:g\u000E0g&;g:?e:\u0014g\u0014(e\u0008\u0017h!(d8\re\u0010\u000Cg<\u0016h>\u0011g;\u001Fh.!f\u001F%h/\"d8\rh&\u0001f\u001C\te\u00053f\u001C:f\u001E\u0004e>\u0008e$\u001Af\u0012-f\u0014>g;\u0004g;\u0007f\u0014?g-\u0016g\u001B4f\u000E%h\u0003=e\n\u001Bf\u001D%f:\u0010f\u0019\u0002i\u0016\u0013g\u001C\u000Be\u00080g\u0003-i\u0017(e\u00053i\u0014.d8\u0013e\u000C:i\u001D\u001Ee88h\u000B1h/-g\u0019>e:&e8\u000Cf\u001C\u001Bg>\u000Ee%3f/\u0014h>\u0003g\u001F%h/\u0006h'\u0004e.\u001Ae;:h..i\u0003(i\u0017(f\u0004\u000Fh'\u0001g2>e=)f\u0017%f\u001C,f\u000F\u0010i+\u0018e\u000F\u0011h(\u0000f\u00169i\u001D\"e\u001F:i\u0007\u0011e$\u0004g\u0010\u0006f\u001D\u0003i\u0019\u0010e=1g\t\u0007i\u00136h!\u000Ch?\u0018f\u001C\te\u0008\u0006d:+g\t)e\u0013\u0001g;\u000Fh\u0010%f7;e\n d8\u0013e.6h?\u0019g'\rh/\u001Di\"\u0018h57f\u001D%d8\u001Ae\n!e\u0005,e\u0011\nh.0e=\u0015g.\u0000d;\u000Bh4(i\u0007\u000Fg\u00147d::e=1e\u0013\re<\u0015g\u0014(f\n%e\u0011\ni\u0003(e\u0008\u0006e?+i\u0000\u001Fe\u0012(h/\"f\u00176e0\u001Af3(f\u0004\u000Fg\u00143h/7e-&f !e:\u0014h/%e\u000E\u0006e\u000F2e\u000F*f\u0018/h?\u0014e\u001B\u001Eh4-d90e\u0010\rg'0d8:d:\u0006f\u0008\u0010e\n\u001Fh/4f\u0018\u000Ed>\u001Be:\u0014e-)e-\u0010d8\u0013i\"\u0018g(\u000Be:\u000Fd8\u0000h\u0008,f\u001C\u0003e\u0013!e\u000F*f\u001C\te\u00056e.\u0003d?\u001Df\n$h\u0000\u000Cd8\u0014d;\ne$)g*\u0017e\u000F#e\n(f\u0000\u0001g\n6f\u0000\u0001g\t9e\u0008+h.$d8:e?\u0005i!;f\u001B4f\u00160e0\u000Fh/4f\u0008\u0011e\u0000\u0011d=\u001Cd8:e*\u0012d=\u0013e\u000C\u0005f\u000B,i\u0002#d9\u0008d8\u0000f 7e\u001B=e\u0006\u0005f\u0018/e\u0010&f 9f\r.g\u00145h'\u0006e-&i\u0019\"e\u00057f\u001C\th?\u0007g(\u000Bg\u00141d:\u000Ed::f\t\re\u0007:f\u001D%d8\rh?\u0007f-#e\u001C(f\u0018\u000Ef\u0018\u001Ff\u0015\u0005d:\u000Be\u00053g3;f \u0007i\"\u0018e\u0015\u0006e\n!h>\u0013e\u0005%d8\u0000g\u001B4e\u001F:g!\u0000f\u0015\u0019e-&d:\u0006h'#e;:g-\u0011g;\u0013f\u001E\u001Ce\u0005(g\u0010\u0003i\u0000\u001Ag\u001F%h.!e\u0008\u0012e/9d:\u000Eh\t:f\u001C/g\u001B8e\u0006\u000Ce\u000F\u0011g\u0014\u001Fg\u001C\u001Fg\u001A\u0004e;:g+\u000Bg-\tg:'g1;e\u001E\u000Bg;\u000Fi*\u000Ce.\u001Eg\u000E0e\u00086d=\u001Cf\u001D%h\u0007*f \u0007g->d;%d8\u000Be\u000E\u001Fe\u0008\u001Bf\u0017 f3\u0015e\u00056d8-e\u0000\u000Bd::d8\u0000e\u0008\u0007f\u000C\u0007e\r\u0017e\u00053i\u0017-i\u001B\u0006e\u001B\"g,,d8\te\u00053f3(e\u001B f-$g\u0005'g\t\u0007f71e\u001C3e\u0015\u0006d8\u001Ae9?e7\u001Ef\u0017%f\u001C\u001Fi+\u0018g:'f\u001C\u0000h?\u0011g;<e\u0010\u0008h!(g$:d8\u0013h>\u0011h!\u000Cd8:d:$i\u0000\u001Ah/\u0004d;7h'\te>\u0017g2>e\r\u000Ee.6e:-e.\u000Cf\u0008\u0010f\u0004\u001Fh'\te.\th#\u0005e>\u0017e\u00080i\u0002.d;6e\u00086e:&i#\u001Fe\u0013\u0001h\u0019=g\u00046h=,h==f\n%d;7h.0h\u0000\u0005f\u00169f!\u0008h!\u000Cf\u0014?d::f0\u0011g\u0014(e\u0013\u0001d8\u001Ch%?f\u000F\u0010e\u0007:i\u0005\u0012e:\u0017g\u00046e\u0010\u000Ed;\u0018f,>g\u0003-g\u00029d;%e\t\re.\u000Ce\u0005(e\u000F\u0011e8\u0016h.>g=.i\"\u0006e/<e7%d8\u001Ae\u000C;i\u0019\"g\u001C\u000Bg\u001C\u000Bg;\u000Fe\u00058e\u000E\u001Fe\u001B e93e\u000F0e\u0010\u0004g'\re\"\u001Ee\n f\u001D\u0010f\u0016\u0019f\u00160e\"\u001Ed9\u000Be\u0010\u000Eh\u0001\u000Cd8\u001Af\u0015\u0008f\u001E\u001Cd;\ne94h.:f\u0016\u0007f\u0008\u0011e\u001B=e\u0011\nh/\tg\t\u0008d8;d?.f\u00149e\u000F\u0002d8\u000Ef\t\u0013e\r0e?+d9\u0010f\u001C:f\"0h'\u0002g\u00029e-\u0018e\u001C(g2>g%\u001Eh\u000E7e>\u0017e\u0008)g\u0014(g;'g;-d= d;,h?\u0019d9\u0008f(!e<\u000Fh/-h(\u0000h\u0003=e$\u001Fi\u001B\u0005h\u0019\u000Ef\u0013\rd=\u001Ci#\u000Ef <d8\u0000h57g'\u0011e-&d=\u0013h\u00022g\u001F-d?!f\u001D!d;6f2;g\u0016\u0017h?\u0010e\n(d:'d8\u001Ad<\u001Ah..e/<h\u0008*e\u0005\u0008g\u0014\u001Fh\u0001\u0014g\u001B\u001Fe\u000F/f\u0018/e\u0015\u000Fi!\u000Cg;\u0013f\u001E\u0004d=\u001Cg\u0014(h0\u0003f\u001F%h3\u0007f\u0016\u0019h\u0007*e\n(h4\u001Fh4#e\u0006\u001Cd8\u001Ah.?i\u0017.e.\u001Ef\u0016=f\u000E%e\u000F\u0017h.(h.:i\u0002#d8*e\u000F\ri&\u0008e\n e<:e%3f\u0000'h\u000C\u0003e\u001B4f\u001C\re\u000B\u0019d<\u0011i\u00172d;\nf\u0017%e.\"f\u001C\rh'\u0000g\u001C\u000Be\u000F\u0002e\n g\u001A\u0004h/\u001Dd8\u0000g\u00029d?\u001Dh/\u0001e\u001B>d9&f\u001C\tf\u0015\u0008f5\u000Bh/\u0015g';e\n(f\t\rh\u0003=e\u00063e.\u001Ah\u0002!g%(d8\rf\u0016-i\u001C\u0000f1\u0002d8\re>\u0017e\n\u001Ef3\u0015d9\u000Bi\u00174i\u0007\u0007g\u0014(h\u0010%i\u0014\u0000f\n\u0015h/\tg\u001B.f \u0007g\u00081f\u0003\u0005f\u0011\u0004e=1f\u001C\td:\u001Bh$\u0007h#=f\u0016\u0007e-&f\u001C:d<\u001Af\u00150e-\u0017h#\u0005d?.h4-g\t)e\u0006\u001Cf\u001D\u0011e\u0005(i\u001D\"g2>e\u0013\u0001e\u00056e.\u001Ed:\u000Bf\u0003\u0005f04e93f\u000F\u0010g$:d8\ne8\u0002h0\"h0\"f\u0019.i\u0000\u001Af\u0015\u0019e8\u0008d8\nd< g1;e\u0008+f-\u000Cf\u001B2f\u000B%f\u001C\te\u0008\u001Bf\u00160i\u0005\rd;6e\u000F*h&\u0001f\u00176d;#h3\u0007h(\nh>>e\u00080d::g\u0014\u001Fh.\"i\u0018\u0005h\u0000\u0001e8\u0008e1\u0015g$:e?\u0003g\u0010\u0006h44e-\u0010g62g+\u0019d8;i!\u000Ch\u0007*g\u00046g:'e\u0008+g.\u0000e\r\u0015f\u00149i\u001D)i\u0002#d:\u001Bf\u001D%h/4f\t\u0013e<\u0000d;#g \u0001e\u0008 i\u0019$h/\u0001e\u00088h\n\u0002g\u001B.i\u0007\rg\u00029f,!f\u00158e$\u001Ae0\u0011h'\u0004e\u0008\u0012h5\u0004i\u0007\u0011f\t>e\u00080d;%e\u0010\u000Ee$'e\u0005(d8;i!5f\u001C\u0000d=3e\u001B\u001Eg-\u0014e$)d8\u000Bd?\u001Di\u001A\u001Cg\u000E0d;#f#\u0000f\u001F%f\n\u0015g%(e0\u000Ff\u00176f2\u0012f\u001C\tf-#e88g\u0014\u001Ah\u00073d;#g\u0010\u0006g\u001B.e=\u0015e\u0005,e<\u0000e$\re\u00086i\u0007\u0011h\u001E\re98g&\u000Fg\t\u0008f\u001C,e=\"f\u0008\u0010e\u0007\u0006e$\u0007h!\u000Cf\u0003\u0005e\u001B\u001Ee\u00080f\u0000\u001Df\u00033f\u0000\u000Ef 7e\r\u000Fh..h.$h/\u0001f\u001C\u0000e%=d:'g\u0014\u001Ff\u000C\tg\u0005'f\u001C\rh#\u0005e9?d8\u001Ce\n(f<+i\u0007\u0007h4-f\u00160f\t\u000Bg;\u0004e\u001B>i\u001D\"f\u001D?e\u000F\u0002h\u0000\u0003f\u0014?f2;e.9f\u0018\u0013e$)e\u001C0e\n*e\n\u001Bd::d;,e\r\u0007g:'i\u0000\u001Fe:&d::g\t)h0\u0003f\u00154f5\u0001h!\u000Ci\u0000 f\u0008\u0010f\u0016\u0007e-\u0017i\u001F)e\u001B=h48f\u0018\u0013e<\u0000e1\u0015g\u001B8i\u0017\u001Ch!(g\u000E0e=1h'\u0006e&\u0002f-$g>\u000Ee.9e$'e0\u000Ff\n%i\u0001\u0013f\u001D!f,>e?\u0003f\u0003\u0005h.8e$\u001Af3\u0015h'\u0004e.6e1\u0005d9&e:\u0017h?\u001Ef\u000E%g+\u000Be\r3d8>f\n%f\n\u0000e7'e%%h?\u0010g\u0019;e\u0005%d;%f\u001D%g\u0010\u0006h.:d:\u000Bd;6h\u0007*g\u00141d8-e\r\u000Ee\n\u001Ee\u0005,e&\u0008e&\u0008g\u001C\u001Ff-#d8\ri\u0014\u0019e\u0005(f\u0016\u0007e\u0010\u0008e\u0010\u000Cd;7e\u0000<e\u0008+d::g\u001B\u0011g\u001D#e\u00057d=\u0013d8\u0016g:*e\u001B\"i\u0018\u001Fe\u0008\u001Bd8\u001Af\t?f\u000B\u0005e\"\u001Ei\u0015?f\u001C\td::d?\u001Df\u000C\u0001e\u0015\u0006e.6g;4d?.e\u000F0f9>e7&e\u000F3h\u0002!d;=g-\u0014f!\u0008e.\u001Ei\u0019\u0005g\u00145d?!g;\u000Fg\u0010\u0006g\u0014\u001Fe\u0011=e.#d< d;;e\n!f-#e<\u000Fg\t9h\t2d8\u000Bf\u001D%e\r\u000Fd<\u001Ae\u000F*h\u0003=e=\u0013g\u00046i\u0007\rf\u00160e\u0005'e.9f\u000C\u0007e/<h?\u0010h!\u000Cf\u0017%e?\u0017h3#e.6h6\u0005h?\u0007e\u001C\u001Fe\u001C0f5\u0019f1\u001Ff\u0014/d;\u0018f\u000E(e\u0007:g+\u0019i\u0015?f\u001D-e7\u001Ef\t'h!\u000Ce\u00086i\u0000 d9\u000Bd8\u0000f\u000E(e9?g\u000E0e\u001C:f\u000F\u000Fh?0e\u000F\u0018e\u000C\u0016d< g;\u001Ff-\u000Cf\t\u000Bd?\u001Di\u0019)h/>g(\u000Be\u000C;g\u0016\u0017g;\u000Fh?\u0007h?\u0007e\u000E;d9\u000Be\t\rf\u00146e\u0005%e94e:&f\u001D\u0002e?\u0017g>\u000Ed8=f\u001C\u0000i+\u0018g\u0019;i\u0019\u0006f\u001C*f\u001D%e\n e7%e\u0005\rh4#f\u0015\u0019g(\u000Bg\t\u0008e\u001D\u0017h:+d=\u0013i\u0007\re:\u0006e\u0007:e\u0014.f\u0008\u0010f\u001C,e=\"e<\u000Fe\u001C\u001Fh1\u0006e\u0007:e\u00039d8\u001Cf\u00169i\u0002.g.1e\r\u0017d:,f1\u0002h\u0001\u000Ce\u000F\u0016e>\u0017h\u0001\u000Cd=\rg\u001B8d?!i!5i\u001D\"e\u0008\u0006i\u0012\u001Fg=\u0011i!5g!.e.\u001Ae\u001B>d>\u000Bg=\u0011e\u001D\u0000g'/f\u001E\u0001i\u0014\u0019h//g\u001B.g\u001A\u0004e.\u001Dh4\u001Df\u001C:e\u00053i#\u000Ei\u0019)f\u000E\u0008f\u001D\u0003g\u0017\u0005f/\u0012e. g\t)i\u0019$d:\u0006h)\u0015h+\u0016g\u0016>g\u0017\u0005e\u000F\nf\u00176f1\u0002h4-g+\u0019g\u00029e\u0004?g+%f/\u000Fe$)d8-e$.h.$h/\u0006f/\u000Fd8*e$)f4%e-\u0017d=\u0013e\u000F0g\u0001#g;4f\n$f\u001C,i!5d8*f\u0000'e.\u0018f\u00169e88h'\u0001g\u001B8f\u001C:f\u0008\u0018g\u0015%e:\u0014e=\u0013e>\u000Be8\u0008f\u00169d>?f !e\u001B-h\u0002!e8\u0002f\u0008?e1\u000Bf \u000Fg\u001B.e\u0011\u0018e7%e/<h\u00074g*\u0001g\u00046i\u0001\u0013e\u00057f\u001C,g=\u0011g;\u0013e\u0010\u0008f!#f!\u0008e\n3e\n(e\u000F&e$\u0016g>\u000Ee\u0005\u0003e<\u0015h57f\u00149e\u000F\u0018g,,e\u001B\u001Bd<\u001Ah.!h**f\u0018\u000Ei\u001A\u0010g'\u0001e.\u001De.\u001Dh'\u0004h\u000C\u0003f6\u0008h49e\u00051e\u0010\u000Ce?\u0018h.0d=\u0013g3;e8&f\u001D%e\u0010\re-\u0017g\u0019<h!(e<\u0000f\u0014>e\n g\u001B\u001Fe\u000F\u0017e\u00080d:\u000Cf\t\u000Be$'i\u0007\u000Ff\u0008\u0010d::f\u00150i\u0007\u000Fe\u00051d:+e\u000C:e\u001F\u001Fe%3e-)e\u000E\u001Fe\u0008\u0019f\t\u0000e\u001C(g;\u0013f\u001D\u001Fi\u0000\u001Ad?!h6\u0005g:'i\u0005\rg=.e=\u0013f\u00176d<\u0018g'\u0000f\u0000'f\u0004\u001Ff\u0008?d:'i\u0001\nf\u00082e\u0007:e\u000F#f\u000F\u0010d:$e01d8\u001Ad?\u001De\u0001%g(\u000Be:&e\u000F\u0002f\u00150d:\u000Bd8\u001Af\u00154d8*e11d8\u001Cf\u0003\u0005f\u0004\u001Fg\t9f.\ne\u0008\u0006i!\u001Ef\u0010\u001Ce0\u000Be1\u001Ed:\u000Ei\u0017(f\u00087h4\"e\n!e#0i\u001F3e\u000F\ne\u00056h4\"g;\u000Fe\u001D\u001Af\u000C\u0001e92i\u0003(f\u0008\u0010g+\u000Be\u0008)g\u001B\nh\u0000\u0003h\u0019\u0011f\u0008\u0010i\u0003=e\u000C\u0005h#\u0005g\u0014(f\u00086f/\u0014h5\u001Bf\u0016\u0007f\u0018\u000Ef\u000B\u001Be\u0015\u0006e.\u000Cf\u00154g\u001C\u001Ff\u0018/g\u001C<g\u001D\u001Bd<\u0019d<4e(\u0001f\u001C\u001Bi\"\u0006e\u001F\u001Fe\r+g\u0014\u001Fd<\u0018f\u0003 h+\u0016e#\u0007e\u0005,e\u00051h\t/e%=e\u0005\u0005e\u0008\u0006g,&e\u0010\u0008i\u0019\u0004d;6g\t9g\u00029d8\re\u000F/h\u000B1f\u0016\u0007h5\u0004d:'f 9f\u001C,f\u0018\u000Ef\u0018>e/\u0006g\"<e\u0005,d<\u0017f0\u0011f\u0017\u000Ff\u001B4e\n d:+e\u000F\u0017e\u0010\u000Ce-&e\u0010/e\n(i\u0000\u0002e\u0010\u0008e\u000E\u001Ff\u001D%i\u0017.g-\u0014f\u001C,f\u0016\u0007g>\u000Ei#\u001Fg;?h\t2g(3e.\u001Ag;\u0008d:\u000Eg\u0014\u001Fg\t)d>\u001Bf1\u0002f\u0010\u001Cg\u000B\u0010e\n\u001Bi\u0007\u000Fd8%i\u0007\rf08h?\u001Ce\u0006\u0019g\u001C\u001Ff\u001C\ti\u0019\u0010g+\u001Ed:\te/9h1!h49g\u0014(d8\re%=g;\u001De/9e\r\u0001e\u0008\u0006d?\u0003h?\u001Bg\u00029h/\u0004e=1i\u001F3d<\u0018e\n?d8\re0\u0011f,#h5\u000Fe96d8\u0014f\u001C\tg\u00029f\u00169e\u0010\u0011e\u0005(f\u00160d?!g\u0014(h.>f\u0016=e=\"h1!h5\u0004f <g*\u0001g 4i\u001A\u000Fg\u001D\u0000i\u0007\re$'d:\u000Ef\u0018/f/\u0015d8\u001Af\u0019:h\u0003=e\u000C\u0016e7%e.\u000Cg>\u000Ee\u0015\u0006e\u001F\u000Eg;\u001Fd8\u0000e\u0007:g\t\u0008f\t\u0013i\u0000 g\u0014\"e\u0013\u0001f&\u0002e\u00065g\u0014(d:\u000Ed?\u001Dg\u0015\u0019e\u001B g4 d8-e\u001C\u000Be-\u0018e\u0002(h44e\u001B>f\u001C\u0000f\u0004\u001Bi\u0015?f\u001C\u001Fe\u000F#d;7g\u0010\u0006h4\"e\u001F:e\u001C0e.\tf\u000E\u0012f-&f1\ti\u0007\u000Ci\u001D\"e\u0008\u001Be;:e$)g):i&\u0016e\u0005\u0008e.\u000Ce\u0016\u0004i)1e\n(d8\u000Bi\u001D\"d8\re\u0006\rh/\u001Ad?!f\u0004\u000Fd9\ti\u00183e\u0005\th\u000B1e\u001B=f<\u0002d:.e\u0006\u001Bd:\u000Bg\u000E)e.6g>$d<\u0017e\u0006\u001Cf0\u0011e\r3e\u000F/e\u0010\rg(1e.6e\u00057e\n(g\u0014;f\u00033e\u00080f3(f\u0018\u000Ee0\u000Fe-&f\u0000'h\u0003=h\u0000\u0003g \u0014g!,d;6h'\u0002g\u001C\u000Bf8\u0005f%\u001Af\u0010\u001Eg,\u0011i&\u0016i \u0001i;\u0004i\u0007\u0011i\u0000\u0002g\u0014(f1\u001Fh\u000B\u000Fg\u001C\u001Fe.\u001Ed8;g.!i\u00186f.5h(;e\u0006\ng?;h/\u0011f\u001D\u0003e\u0008)e\u0001\u001Ae%=d<<d9\u000Ei\u0000\u001Ah./f\u0016=e7%g\u000B\u0000f\u0005\u000Bd9\u001Fh.8g\u000E/d?\u001De\u001F9e\u0005;f&\u0002e?5e$'e\u001E\u000Bf\u001C:g%(g\u0010\u0006h'#e\u000C?e\u0010\rcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestC!nnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegC:nbuenosvolverpuntossemanahabC-aagostonuevosunidoscarlosequiponiC1osmuchosalgunacorreoimagenpartirarribamarC-ahombreempleoverdadcambiomuchasfueronpasadolC-neaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposserC!neuropamediosfrenteacercademC!sofertacochesmodeloitalialetrasalgC:ncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrC!puestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosC:nicocaminositiosrazC3ndebidopruebatoledotenC-ajesC:sesperococinaorigentiendacientocC!dizhablarserC-alatinafuerzaestiloguerraentrarC)xitolC3pezagendavC-deoevitarpaginametrosjavierpadresfC!cilcabezaC!reassalidaenvC-ojapC3nabusosbienestextosllevarpuedanfuertecomC:nclaseshumanotenidobilbaounidadestC!seditarcreadoP4P;Q\u000FQ\u0007Q\u0002P>P:P0P:P8P;P8Q\rQ\u0002P>P2Q\u0001P5P5P3P>P?Q\u0000P8Q\u0002P0P:P5Q\tP5Q\u0003P6P5P\u001AP0P:P1P5P7P1Q\u000BP;P>P=P8P\u0012Q\u0001P5P?P>P4P-Q\u0002P>Q\u0002P>P<Q\u0007P5P<P=P5Q\u0002P;P5Q\u0002Q\u0000P0P7P>P=P0P3P4P5P<P=P5P\u0014P;Q\u000FP\u001FQ\u0000P8P=P0Q\u0001P=P8Q\u0005Q\u0002P5P<P:Q\u0002P>P3P>P4P2P>Q\u0002Q\u0002P0P<P!P(P\u0010P<P0Q\u000FP'Q\u0002P>P2P0Q\u0001P2P0P<P5P<Q\u0003P\"P0P:P4P2P0P=P0P<Q\rQ\u0002P8Q\rQ\u0002Q\u0003P\u0012P0P<Q\u0002P5Q\u0005P?Q\u0000P>Q\u0002Q\u0003Q\u0002P=P0P4P4P=Q\u000FP\u0012P>Q\u0002Q\u0002Q\u0000P8P=P5P9P\u0012P0Q\u0001P=P8P<Q\u0001P0P<Q\u0002P>Q\u0002Q\u0000Q\u0003P1P\u001EP=P8P<P8Q\u0000P=P5P5P\u001EP\u001EP\u001EP;P8Q\u0006Q\rQ\u0002P0P\u001EP=P0P=P5P<P4P>P<P<P>P9P4P2P5P>P=P>Q\u0001Q\u0003P4`$\u0015`%\u0007`$9`%\u0008`$\u0015`%\u0000`$8`%\u0007`$\u0015`$>`$\u0015`%\u000B`$\u0014`$0`$*`$0`$(`%\u0007`$\u000F`$\u0015`$\u0015`$?`$-`%\u0000`$\u0007`$8`$\u0015`$0`$$`%\u000B`$9`%\u000B`$\u0006`$*`$9`%\u0000`$/`$9`$/`$>`$$`$\u0015`$%`$>jagran`$\u0006`$\u001C`$\u001C`%\u000B`$\u0005`$,`$&`%\u000B`$\u0017`$\u0008`$\u001C`$>`$\u0017`$\u000F`$9`$.`$\u0007`$(`$5`$9`$/`%\u0007`$%`%\u0007`$%`%\u0000`$\u0018`$0`$\u001C`$,`$&`%\u0000`$\u0015`$\u0008`$\u001C`%\u0000`$5`%\u0007`$(`$\u0008`$(`$\u000F`$9`$0`$\t`$8`$.`%\u0007`$\u0015`$.`$5`%\u000B`$2`%\u0007`$8`$,`$.`$\u0008`$&`%\u0007`$\u0013`$0`$\u0006`$.`$,`$8`$-`$0`$,`$(`$\u001A`$2`$.`$(`$\u0006`$\u0017`$8`%\u0000`$2`%\u0000X9Y\u0004Y\tX%Y\u0004Y\tY\u0007X0X'X\"X.X1X9X/X/X'Y\u0004Y\tY\u0007X0Y\u0007X5Y\u0008X1X:Y\nX1Y\u0003X'Y\u0006Y\u0008Y\u0004X'X(Y\nY\u0006X9X1X6X0Y\u0004Y\u0003Y\u0007Y\u0006X'Y\nY\u0008Y\u0005Y\u0002X'Y\u0004X9Y\u0004Y\nX'Y\u0006X'Y\u0004Y\u0003Y\u0006X-X*Y\tY\u0002X(Y\u0004Y\u0008X-X)X'X.X1Y\u0001Y\u0002X7X9X(X/X1Y\u0003Y\u0006X%X0X'Y\u0003Y\u0005X'X'X-X/X%Y\u0004X'Y\u0001Y\nY\u0007X(X9X6Y\u0003Y\nY\u0001X(X-X+Y\u0008Y\u0005Y\u0006Y\u0008Y\u0007Y\u0008X#Y\u0006X'X,X/X'Y\u0004Y\u0007X'X3Y\u0004Y\u0005X9Y\u0006X/Y\u0004Y\nX3X9X(X1X5Y\u0004Y\tY\u0005Y\u0006X0X(Y\u0007X'X#Y\u0006Y\u0007Y\u0005X+Y\u0004Y\u0003Y\u0006X*X'Y\u0004X'X-Y\nX+Y\u0005X5X1X4X1X-X-Y\u0008Y\u0004Y\u0008Y\u0001Y\nX'X0X'Y\u0004Y\u0003Y\u0004Y\u0005X1X)X'Y\u0006X*X'Y\u0004Y\u0001X#X(Y\u0008X.X'X5X#Y\u0006X*X'Y\u0006Y\u0007X'Y\u0004Y\nX9X6Y\u0008Y\u0008Y\u0002X/X'X(Y\u0006X.Y\nX1X(Y\u0006X*Y\u0004Y\u0003Y\u0005X4X'X!Y\u0008Y\u0007Y\nX'X(Y\u0008Y\u0002X5X5Y\u0008Y\u0005X'X1Y\u0002Y\u0005X#X-X/Y\u0006X-Y\u0006X9X/Y\u0005X1X#Y\nX'X-X)Y\u0003X*X(X/Y\u0008Y\u0006Y\nX,X(Y\u0005Y\u0006Y\u0007X*X-X*X,Y\u0007X)X3Y\u0006X)Y\nX*Y\u0005Y\u0003X1X)X:X2X)Y\u0006Y\u0001X3X(Y\nX*Y\u0004Y\u0004Y\u0007Y\u0004Y\u0006X'X*Y\u0004Y\u0003Y\u0002Y\u0004X(Y\u0004Y\u0005X'X9Y\u0006Y\u0007X#Y\u0008Y\u0004X4Y\nX!Y\u0006Y\u0008X1X#Y\u0005X'Y\u0001Y\nY\u0003X(Y\u0003Y\u0004X0X'X*X1X*X(X(X#Y\u0006Y\u0007Y\u0005X3X'Y\u0006Y\u0003X(Y\nX9Y\u0001Y\u0002X/X-X3Y\u0006Y\u0004Y\u0007Y\u0005X4X9X1X#Y\u0007Y\u0004X4Y\u0007X1Y\u0002X7X1X7Y\u0004X(profileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>\r\nwrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle=\"Mobile killingshowingItaliandroppedheavilyeffects-1']);\nconfirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.\n\nThe but notdensityBritainChineselack oftributeIreland\" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang=\"return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue=\"complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role=\"missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();\r\npaymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html\">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen\n\nWhen observe</h2>\r\nModern provide\" alt=\"borders.\n\nFor \n\nMany artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>\r\n Countryignoredloss ofjust asGeorgiastrange<head><stopped1']);\r\nislandsnotableborder:list ofcarried100,000</h3>\n severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id=\"foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login\">convertviolententeredfirst\">circuitFinlandchemistshe was10px;\">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title\">tooltipSectiondesignsTurkishyounger.match(})();\n\nburningoperatedegreessource=Richardcloselyplasticentries</tr>\r\ncolor:#ul id=\"possessrollingphysicsfailingexecutecontestlink toDefault<br />\n: true,chartertourismclassicproceedexplain</h1>\r\nonline.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src=\"/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e&quot;tradingleft\">\npersonsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy\n\t\t<!--Daniel bindingblock\">imposedutilizeAbraham(except{width:putting).html(|| [];\nDATA[ *kitchenmountedactual dialectmainly _blank'installexpertsif(typeIt also&copy; \">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref=\"/\" rel=\"developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in\n\t<!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday's.html\" target=wearingAll Rig;\n})();raising Also, crucialabout\">declare-->\n<scfirefoxas muchappliesindex, s, but type = \n\r\n<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin\" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>\r\n returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of\n\nSome 'click'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion=\"pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major\":\"httpin his menu\">\nmonthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small\">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks\">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel\">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8\">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>\nevidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>\n he left).val()false);logicalbankinghome tonaming Arizonacredits);\n});\nfounderin turnCollinsbefore But thechargedTitle\">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered']);\n has theunclearEvent',both innot all\n\n<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage\" linear painterand notrarely acronymdelivershorter00&amp;as manywidth=\"/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don'tretreat. Some ww.\");\nbombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft\"><comScorAll thejQuery.touristClassicfalse\" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>\n\n. When in bothdismissExplorealways via thespaC1olwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>\n\t\tit intoranked rate oful>\r\n attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped\").css(hostilelead tolittle groups,Picture-->\r\n\r\n rows=\" objectinverse<footerCustomV><\\/scrsolvingChamberslaverywoundedwhereas!= 'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead')[0Criticsstudios>&copy;group\">assemblmaking pressedwidget.ps:\" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass=\"but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;\">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + \"gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(\" />\n\t\there isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();\n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded=\"true\"spacingis mosta more totallyfall of});\r\n immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace\">header-well asStanleybridges/globalCroatia About [0];\n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF\"bottom\"like a employslive inas seenprintermost ofub-linkrejectsand useimage\">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older\">us.js\"> Since universlarger open to!-- endlies in']);\r\n marketwho is (\"DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting \n\t\tvar March 2grew upClimate.removeskilledway the</head>face ofacting right\">to workreduceshas haderectedshow();action=book ofan area== \"htt<header\n<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage\">MobilClements\" id=\"as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded\"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;\">\r\npushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>\npeople.in one =windowfooter_a good reklamaothers,to this_cookiepanel\">London,definescrushedbaptismcoastalstatus title\" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />\r\nAtlantanucleusCounty,purely count\">easily build aonclicka givenpointerh&quot;events else {\nditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink\"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg\" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium\"DO NOT France,with a war andsecond take a >\r\n\r\n\r\nmarket.highwaydone inctivity\"last\">obligedrise to\"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right\" bicycleacing=\"day andstatingRather,higher Office are nowtimes, when a pay foron this-link\">;borderaround annual the Newput the.com\" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks\">\n();\" rea place\\u003Caabout atr>\r\n\t\tccount gives a<SCRIPTRailwaythemes/toolboxById(\"xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>\r\n<ustomVa;&gt;</importsor thatmostly &amp;re size=\"</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>\r\n\r\n<!organis <br />BeijingcatalC deutscheuropeueuskaragaeilgesvenskaespaC1amensajeusuariotrabajomC)xicopC!ginasiempresistemaoctubreduranteaC1adirempresamomentonuestroprimeratravC)sgraciasnuestraprocesoestadoscalidadpersonanC:meroacuerdomC:sicamiembroofertasalgunospaC-sesejemploderechoademC!sprivadoagregarenlacesposiblehotelessevillaprimeroC:ltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseC1oturismocC3digoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastC-tuloconocersegundoconsejofranciaminutossegundatenemosefectosmC!lagasesiC3nrevistagranadacompraringresogarcC-aacciC3necuadorquienesinclusodeberC!materiahombresmuestrapodrC-amaC1anaC:ltimaestamosoficialtambienningC:nsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner\">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo\"><adaughterauthor\" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom\">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton\" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id=\"discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive\">somewhatvictoriaWestern title=\"LocationcontractvisitorsDownloadwithout right\">\nmeasureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg\" />machines</h2>\n keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow\" valuable</label>relativebringingincreasegovernorplugins/List of Header\">\" name=\" (&quot;graduate</head>\ncommercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>\n\t\t<select citizensclothingwatching<li id=\"specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split(\"lizationOctober ){returnimproved--&gt;\n\ncoveragechairman.png\" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css\" /> websitereporteddefault\"/></a>\r\nelectricscotlandcreationquantity. ISBN 0did not instance-search-\" lang=\"speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: 'http:'script'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id=\"William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout=\"approved maximumheader\"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=\"\"intervalwirelessentitledagenciesSearch\" measuredthousandspending&hellip;new Date\" size=\"pageNamemiddle\" \" /></a>hidden\">sequencepersonaloverflowopinionsillinoislinks\">\n\t<title>versionssaturdayterminalitempropengineersectionsdesignerproposal=\"false\"EspaC1olreleasessubmit\" er&quot;additionsymptomsorientedresourceright\"><pleasurestationshistory.leaving border=contentscenter\">.\n\nSome directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal\"><span>search\">operatorrequestsa &quot;allowingDocumentrevision. \n\nThe yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1\"indicatefamiliar qualitymargin:0 contentviewportcontacts-title\">portable.length eligibleinvolvesatlanticonload=\"default.suppliedpaymentsglossary\n\nAfter guidance</td><tdencodingmiddle\">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>\n\taffectedsupportspointer;toString</small>oklahomawill be investor0\" alt=\"holidaysResourcelicensed (which . After considervisitingexplorerprimary search\" android\"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js\"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions\"campbell<!-- end</span><<br />\r\n_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=\" Companyexamples<iframe believespresentsmarshallpart of properly).\n\nThe taxonomymuch of </span>\n\" data-srtuguC*sscrollTo project<head>\r\nattorneyemphasissponsorsfancyboxworld's wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix\n<head>\narticle <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent\"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton\">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth=\"2lazyloadnovemberused in height=\"cript\">\n&nbsp;</<tr><td height:2/productcountry include footer\" &lt;!-- title\"></jquery.</form>\n(g.\u0000d=\u0013)(g9\u0001i+\u0014)hrvatskiitalianoromC\"nD\u0003tC<rkC'eX'X1X/Y\u0008tambiC)nnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuC)sdeportesproyectoproductopC:bliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniC3nimprimirmientrasamC)ricavendedorsociedadrespectorealizarregistropalabrasinterC)sentoncesespecialmiembrosrealidadcC3rdobazaragozapC!ginassocialesbloqueargestiC3nalquilersistemascienciascompletoversiC3ncompletaestudiospC:blicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayorC-aalemaniafunciC3nC:ltimoshaciendoaquellosediciC3nfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojC3venesdistritotC)cnicaconjuntoenergC-atrabajarasturiasrecienteutilizarboletC-nsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallaprC3ximoalmerC-aanimalesquiC)nescorazC3nsecciC3nbuscandoopcionesexteriorconceptotodavC-agalerC-aescribirmedicinalicenciaconsultaaspectoscrC-ticadC3laresjusticiadeberC!nperC-odonecesitamantenerpequeC1orecibidatribunaltenerifecanciC3ncanariasdescargadiversosmallorcarequieretC)cnicodeberC-aviviendafinanzasadelantefuncionaconsejosdifC-cilciudadesantiguasavanzadatC)rminounidadessC!nchezcampaC1asoftonicrevistascontienesectoresmomentosfacultadcrC)ditodiversassupuestofactoressegundospequeC1aP3P>P4P0P5Q\u0001P;P8P5Q\u0001Q\u0002Q\u000CP1Q\u000BP;P>P1Q\u000BQ\u0002Q\u000CQ\rQ\u0002P>P<P\u0015Q\u0001P;P8Q\u0002P>P3P>P<P5P=Q\u000FP2Q\u0001P5Q\u0005Q\rQ\u0002P>P9P4P0P6P5P1Q\u000BP;P8P3P>P4Q\u0003P4P5P=Q\u000CQ\rQ\u0002P>Q\u0002P1Q\u000BP;P0Q\u0001P5P1Q\u000FP>P4P8P=Q\u0001P5P1P5P=P0P4P>Q\u0001P0P9Q\u0002Q\u0004P>Q\u0002P>P=P5P3P>Q\u0001P2P>P8Q\u0001P2P>P9P8P3Q\u0000Q\u000BQ\u0002P>P6P5P2Q\u0001P5P<Q\u0001P2P>Q\u000EP;P8Q\u0008Q\u000CQ\rQ\u0002P8Q\u0005P?P>P:P0P4P=P5P9P4P>P<P0P<P8Q\u0000P0P;P8P1P>Q\u0002P5P<Q\u0003Q\u0005P>Q\u0002Q\u000FP4P2Q\u0003Q\u0005Q\u0001P5Q\u0002P8P;Q\u000EP4P8P4P5P;P>P<P8Q\u0000P5Q\u0002P5P1Q\u000FQ\u0001P2P>P5P2P8P4P5Q\u0007P5P3P>Q\rQ\u0002P8P<Q\u0001Q\u0007P5Q\u0002Q\u0002P5P<Q\u000BQ\u0006P5P=Q\u000BQ\u0001Q\u0002P0P;P2P5P4Q\u000CQ\u0002P5P<P5P2P>P4Q\u000BQ\u0002P5P1P5P2Q\u000BQ\u0008P5P=P0P<P8Q\u0002P8P?P0Q\u0002P>P<Q\u0003P?Q\u0000P0P2P;P8Q\u0006P0P>P4P=P0P3P>P4Q\u000BP7P=P0Q\u000EP<P>P3Q\u0003P4Q\u0000Q\u0003P3P2Q\u0001P5P9P8P4P5Q\u0002P:P8P=P>P>P4P=P>P4P5P;P0P4P5P;P5Q\u0001Q\u0000P>P:P8Q\u000EP=Q\u000FP2P5Q\u0001Q\u000CP\u0015Q\u0001Q\u0002Q\u000CQ\u0000P0P7P0P=P0Q\u0008P8X'Y\u0004Y\u0004Y\u0007X'Y\u0004X*Y\nX,Y\u0005Y\nX9X.X'X5X)X'Y\u0004X0Y\nX9Y\u0004Y\nY\u0007X,X/Y\nX/X'Y\u0004X\"Y\u0006X'Y\u0004X1X/X*X-Y\u0003Y\u0005X5Y\u0001X-X)Y\u0003X'Y\u0006X*X'Y\u0004Y\u0004Y\nY\nY\u0003Y\u0008Y\u0006X4X(Y\u0003X)Y\u0001Y\nY\u0007X'X(Y\u0006X'X*X-Y\u0008X'X!X#Y\u0003X+X1X.Y\u0004X'Y\u0004X'Y\u0004X-X(X/Y\u0004Y\nY\u0004X/X1Y\u0008X3X'X6X:X7X*Y\u0003Y\u0008Y\u0006Y\u0007Y\u0006X'Y\u0003X3X'X-X)Y\u0006X'X/Y\nX'Y\u0004X7X(X9Y\u0004Y\nY\u0003X4Y\u0003X1X'Y\nY\u0005Y\u0003Y\u0006Y\u0005Y\u0006Y\u0007X'X4X1Y\u0003X)X1X&Y\nX3Y\u0006X4Y\nX7Y\u0005X'X0X'X'Y\u0004Y\u0001Y\u0006X4X(X'X(X*X9X(X1X1X-Y\u0005X)Y\u0003X'Y\u0001X)Y\nY\u0002Y\u0008Y\u0004Y\u0005X1Y\u0003X2Y\u0003Y\u0004Y\u0005X)X#X-Y\u0005X/Y\u0002Y\u0004X(Y\nY\nX9Y\u0006Y\nX5Y\u0008X1X)X7X1Y\nY\u0002X4X'X1Y\u0003X,Y\u0008X'Y\u0004X#X.X1Y\tY\u0005X9Y\u0006X'X'X(X-X+X9X1Y\u0008X6X(X4Y\u0003Y\u0004Y\u0005X3X,Y\u0004X(Y\u0006X'Y\u0006X.X'Y\u0004X/Y\u0003X*X'X(Y\u0003Y\u0004Y\nX)X(X/Y\u0008Y\u0006X#Y\nX6X'Y\nY\u0008X,X/Y\u0001X1Y\nY\u0002Y\u0003X*X(X*X#Y\u0001X6Y\u0004Y\u0005X7X(X.X'Y\u0003X+X1X(X'X1Y\u0003X'Y\u0001X6Y\u0004X'X-Y\u0004Y\tY\u0006Y\u0001X3Y\u0007X#Y\nX'Y\u0005X1X/Y\u0008X/X#Y\u0006Y\u0007X'X/Y\nY\u0006X'X'Y\u0004X'Y\u0006Y\u0005X9X1X6X*X9Y\u0004Y\u0005X/X'X.Y\u0004Y\u0005Y\u0005Y\u0003Y\u0006\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0002\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0004\u0000\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0007\u0006\u0005\u0004\u0003\u0002\u0001\u0000\u0008\t\n\u000B\u000C\r\u000E\u000F\u000F\u000E\r\u000C\u000B\n\t\u0008\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0017\u0016\u0015\u0014\u0013\u0012\u0011\u0010\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u001F\u001E\u001D\u001C\u001B\u001A\u0019\u0018\u007F\u007F\u007F\u007F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u007F\u007F\u007F\u007F\u0001\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0003\u0000\u0000\u0000\u007F\u007F\u0000\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u007F\u007F\u0000\u0001\u0000\u0000\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0008\u0000\u0000\u0000\u0001\u0000\u0002\u0000\u0003\u0000\u0004\u0000\u0005\u0000\u0006\u0000\u0007resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter\" value=\"</select>Australia\" class=\"situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement\" title=\"potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>\r\nstatementattentionBiography} else {\nsolutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter\">\nexceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick=\"biographyotherwisepermanentFranC'aisHollywoodexpansionstandards</style>\nreductionDecember preferredCambridgeopponentsBusiness confusion>\n<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>\nmountainslike the essentialfinancialselectionaction=\"/abandonedEducationparseInt(stabilityunable to</title>\nrelationsNote thatefficientperformedtwo yearsSince thethereforewrapper\">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>\nsuspectedmargin: 0spiritual</head>\n\nmicrosoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header\">February numerous overflow:componentfragmentsexcellentcolspan=\"technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>\n\tsponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting\" width=\".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper\"enough toalong thedelivered-->\r\n<!--American protectedNovember </style><furnitureInternet onblur=\"suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir=\"ltr\"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;\n\nsouthwestthe rightradiationmay have unescape(spoken in\" href=\"/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip\">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>\ncame fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8\" /><![CDATA[\">ContactSouthern bgcolor=\"series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->\n<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=\">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id=\"precedingTechnicalphysicistoccurs innavigatorsection\">span id=\"sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt=\"in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent\">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id=\"right\">\r\nresidenceleave thecontent\">are often })();\r\nprobably Professor-button\" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular\">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor\n&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved\n\nIn the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also\n<head>\n<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained\"></div>\n</a></td>depend onsearch\">\npieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue=\"\">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.\n\nAfter , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover\" style=\"states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of\r\n<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href=\"y:inline;Church ofthe eventvery highofficial -height: content=\"/cgi-bin/to createafrikaansesperantofranC'aislatvieE!ulietuviE3D\u000CeE!tinaD\reE!tina`9\u0004`8\u0017`8\"f\u0017%f\u001C,h*\u001Eg.\u0000d=\u0013e-\u0017g9\u0001i+\u0014e-\u0017m\u0015\u001Cj5-l\u00164d8:d;\u0000d9\u0008h.!g.\u0017f\u001C:g,\u0014h.0f\u001C,h(\u000Eh+\u0016e\r\u0000f\u001C\re\n!e\u0019(d:\u0012h\u0001\u0014g=\u0011f\u0008?e\u001C0d:'d?1d9\u0010i\u0003(e\u0007:g\t\u0008g$>f\u000E\u0012h!\u000Cf&\u001Ci\u0003(h\u0010=f <h?\u001Bd8\u0000f-%f\u0014/d;\u0018e.\u001Di*\u000Ch/\u0001g \u0001e'\u0014e\u0011\u0018d<\u001Af\u00150f\r.e:\u0013f6\u0008h49h\u0000\u0005e\n\u001Ee\u0005,e.$h.(h.:e\u000C:f71e\u001C3e8\u0002f\u0012-f\u0014>e\u0019(e\u000C\u0017d:,e8\u0002e$'e-&g\u0014\u001Fh6\nf\u001D%h6\ng.!g\u0010\u0006e\u0011\u0018d?!f\u0001/g=\u0011serviciosartC-culoargentinabarcelonacualquierpublicadoproductospolC-ticarespuestawikipediasiguientebC:squedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciC3nnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomC-aimC!genescontactardescargarnecesarioatenciC3ntelC)fonocomisiC3ncancionescapacidadencontraranC!lisisfavoritostC)rminosprovinciaetiquetaselementosfuncionesresultadocarC!cterpropiedadprincipionecesidadmunicipalcreaciC3ndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzC!lezdocumentopelC-cularecientesgeneralestarragonaprC!cticanovedadespropuestapacientestC)cnicasobjetivoscontactos`$.`%\u0007`$\u0002`$2`$?`$\u000F`$9`%\u0008`$\u0002`$\u0017`$/`$>`$8`$>`$%`$\u000F`$5`$\u0002`$0`$9`%\u0007`$\u0015`%\u000B`$\u0008`$\u0015`%\u0001`$\u001B`$0`$9`$>`$,`$>`$&`$\u0015`$9`$>`$8`$-`%\u0000`$9`%\u0001`$\u000F`$0`$9`%\u0000`$.`%\u0008`$\u0002`$&`$?`$(`$,`$>`$$diplodocs`$8`$.`$/`$0`%\u0002`$*`$(`$>`$.`$*`$$`$>`$+`$?`$0`$\u0014`$8`$$`$$`$0`$9`$2`%\u000B`$\u0017`$9`%\u0001`$\u0006`$,`$>`$0`$&`%\u0007`$6`$9`%\u0001`$\u0008`$\u0016`%\u0007`$2`$/`$&`$?`$\u0015`$>`$.`$5`%\u0007`$,`$$`%\u0000`$(`$,`%\u0000`$\u001A`$.`%\u000C`$$`$8`$>`$2`$2`%\u0007`$\u0016`$\u001C`%\t`$,`$.`$&`$&`$$`$%`$>`$(`$9`%\u0000`$6`$9`$0`$\u0005`$2`$\u0017`$\u0015`$-`%\u0000`$(`$\u0017`$0`$*`$>`$8`$0`$>`$$`$\u0015`$?`$\u000F`$\t`$8`%\u0007`$\u0017`$/`%\u0000`$9`%\u0002`$\u0001`$\u0006`$\u0017`%\u0007`$\u001F`%\u0000`$.`$\u0016`%\u000B`$\u001C`$\u0015`$>`$0`$\u0005`$-`%\u0000`$\u0017`$/`%\u0007`$$`%\u0001`$.`$5`%\u000B`$\u001F`$&`%\u0007`$\u0002`$\u0005`$\u0017`$0`$\u0010`$8`%\u0007`$.`%\u0007`$2`$2`$\u0017`$>`$9`$>`$2`$\n`$*`$0`$\u001A`$>`$0`$\u0010`$8`$>`$&`%\u0007`$0`$\u001C`$?`$8`$&`$?`$2`$,`$\u0002`$&`$,`$(`$>`$9`%\u0002`$\u0002`$2`$>`$\u0016`$\u001C`%\u0000`$$`$,`$\u001F`$(`$.`$?`$2`$\u0007`$8`%\u0007`$\u0006`$(`%\u0007`$(`$/`$>`$\u0015`%\u0001`$2`$2`%\t`$\u0017`$-`$>`$\u0017`$0`%\u0007`$2`$\u001C`$\u0017`$9`$0`$>`$.`$2`$\u0017`%\u0007`$*`%\u0007`$\u001C`$9`$>`$%`$\u0007`$8`%\u0000`$8`$9`%\u0000`$\u0015`$2`$>`$ `%\u0000`$\u0015`$9`$>`$\u0001`$&`%\u0002`$0`$$`$9`$$`$8`$>`$$`$/`$>`$&`$\u0006`$/`$>`$*`$>`$\u0015`$\u0015`%\u000C`$(`$6`$>`$.`$&`%\u0007`$\u0016`$/`$9`%\u0000`$0`$>`$/`$\u0016`%\u0001`$&`$2`$\u0017`%\u0000categoriesexperience</title>\r\nCopyright javascriptconditionseverything<p class=\"technologybackground<a class=\"management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox\" techniquesprotectionapparentlyas well asunt', 'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor=\"#especially content=\"productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=\".indexOf(\"conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus=\"<form id=\"processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png\" (document,boundariesexpressionsettlementBackgroundout of theenterprise(\"https:\" unescape(\"password\" democratic<a href=\"/wrapper\">\nmembershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher\"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick=\"considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic\" height=\"link rel=\".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class=\"0px;marginmechanicalstatisticscelebratedGovernment\n\nDuring tdevelopersartificialequivalentoriginatedCommissionattachment<span id=\"there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang=\"en\" </style>\r\nabsolute; supportingextremely mainstream</strong> popularityemployment</table>\r\n colspan=\"</form>\n conversionabout the </p></div>integrated\" lang=\"enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class=\"<a title=\"(includingparametersprohibited= \"http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0\" class=\"completelyillustratefive yearsinstrumentPublishing1\" class=\"psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;\nfunction it was theConventionautomobileProtestantaggressiveafter the Similarly,\" /></div>collection\r\nfunctionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>\n</.indexOf('i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }\n</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt=\"adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to\"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css\"\tfunction innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>\n\tdiplomaticcontainingperformingextensionsmay not beconcept of onclick=\"It is alsofinancial making theLuxembourgadditionalare calledengaged in\"script\");but it waselectroniconsubmit=\"\n<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences\n</head>\r\nrecognisedinitializelimited toAlexandriaretirementAdventuresfour years\n\n&lt;!-- increasingdecorationh3 class=\"origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews\" width=\"1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class=\"Scientificclass=\"no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional\n<head>\n<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix\">the publicmany yearswhich wereover time,synonymouscontent\">\npresumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined\"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan=\"only a fewmeant thatled to the-->\r\n<div <fieldset>Archbishop class=\"nobeing usedapproachesprivilegesnoscript>\nresults inmay be theEaster eggmechanismsreasonablePopulationCollectionselected\">noscript>\r/index.phparrival of-jssdk'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>\n\t\tcomplaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype=\"absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>\npercentagebest-knowncreating a\" dir=\"ltrLieutenant\n<div id=\"they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.\n\nIn the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/\" class=\"geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid=\"searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured\">is said tostructuralreferendummost oftena separate->\n<div id Official worldwide.aria-labelthe planetand it wasd\" value=\"looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id=\"opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/\" title=\".com/indextaking thepittsburghcontent\">\r<script>(fturned outhaving the</span>\r\n occasionalbecause itstarted tophysically></div>\n created byCurrently, bgcolor=\"tabindex=\"disastrousAnalytics also has a><div id=\"</style>\n<called forsinger and.src = \"//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportuguC*sW\"W\u0011W(W\u0019W*Y\u0001X'X1X3[\u000CdesarrollocomentarioeducaciC3nseptiembreregistradodirecciC3nubicaciC3npublicidadrespuestasresultadosimportantereservadosartC-culosdiferentessiguientesrepC:blicasituaciC3nministerioprivacidaddirectorioformaciC3npoblaciC3npresidentecont", "enidosaccesoriostechnoratipersonalescategorC-aespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopolC-ticasanterioresdocumentosnaturalezamaterialesdiferenciaeconC3micatransporterodrC-guezparticiparencuentrandiscusiC3nestructurafundaciC3nfrecuentespermanentetotalmenteP<P>P6P=P>P1Q\u0003P4P5Q\u0002P<P>P6P5Q\u0002P2Q\u0000P5P<Q\u000FQ\u0002P0P:P6P5Q\u0007Q\u0002P>P1Q\u000BP1P>P;P5P5P>Q\u0007P5P=Q\u000CQ\rQ\u0002P>P3P>P:P>P3P4P0P?P>Q\u0001P;P5P2Q\u0001P5P3P>Q\u0001P0P9Q\u0002P5Q\u0007P5Q\u0000P5P7P<P>P3Q\u0003Q\u0002Q\u0001P0P9Q\u0002P0P6P8P7P=P8P<P5P6P4Q\u0003P1Q\u0003P4Q\u0003Q\u0002P\u001FP>P8Q\u0001P:P7P4P5Q\u0001Q\u000CP2P8P4P5P>Q\u0001P2Q\u000FP7P8P=Q\u0003P6P=P>Q\u0001P2P>P5P9P;Q\u000EP4P5P9P?P>Q\u0000P=P>P<P=P>P3P>P4P5Q\u0002P5P9Q\u0001P2P>P8Q\u0005P?Q\u0000P0P2P0Q\u0002P0P:P>P9P<P5Q\u0001Q\u0002P>P8P<P5P5Q\u0002P6P8P7P=Q\u000CP>P4P=P>P9P;Q\u0003Q\u0007Q\u0008P5P?P5Q\u0000P5P4Q\u0007P0Q\u0001Q\u0002P8Q\u0007P0Q\u0001Q\u0002Q\u000CQ\u0000P0P1P>Q\u0002P=P>P2Q\u000BQ\u0005P?Q\u0000P0P2P>Q\u0001P>P1P>P9P?P>Q\u0002P>P<P<P5P=P5P5Q\u0007P8Q\u0001P;P5P=P>P2Q\u000BP5Q\u0003Q\u0001P;Q\u0003P3P>P:P>P;P>P=P0P7P0P4Q\u0002P0P:P>P5Q\u0002P>P3P4P0P?P>Q\u0007Q\u0002P8P\u001FP>Q\u0001P;P5Q\u0002P0P:P8P5P=P>P2Q\u000BP9Q\u0001Q\u0002P>P8Q\u0002Q\u0002P0P:P8Q\u0005Q\u0001Q\u0000P0P7Q\u0003P!P0P=P:Q\u0002Q\u0004P>Q\u0000Q\u0003P<P\u001AP>P3P4P0P:P=P8P3P8Q\u0001P;P>P2P0P=P0Q\u0008P5P9P=P0P9Q\u0002P8Q\u0001P2P>P8P<Q\u0001P2Q\u000FP7Q\u000CP;Q\u000EP1P>P9Q\u0007P0Q\u0001Q\u0002P>Q\u0001Q\u0000P5P4P8P\u001AQ\u0000P>P<P5P$P>Q\u0000Q\u0003P<Q\u0000Q\u000BP=P:P5Q\u0001Q\u0002P0P;P8P?P>P8Q\u0001P:Q\u0002Q\u000BQ\u0001Q\u000FQ\u0007P<P5Q\u0001Q\u000FQ\u0006Q\u0006P5P=Q\u0002Q\u0000Q\u0002Q\u0000Q\u0003P4P0Q\u0001P0P<Q\u000BQ\u0005Q\u0000Q\u000BP=P:P0P\u001DP>P2Q\u000BP9Q\u0007P0Q\u0001P>P2P<P5Q\u0001Q\u0002P0Q\u0004P8P;Q\u000CP<P<P0Q\u0000Q\u0002P0Q\u0001Q\u0002Q\u0000P0P=P<P5Q\u0001Q\u0002P5Q\u0002P5P:Q\u0001Q\u0002P=P0Q\u0008P8Q\u0005P<P8P=Q\u0003Q\u0002P8P<P5P=P8P8P<P5Q\u000EQ\u0002P=P>P<P5Q\u0000P3P>Q\u0000P>P4Q\u0001P0P<P>P<Q\rQ\u0002P>P<Q\u0003P:P>P=Q\u0006P5Q\u0001P2P>P5P<P:P0P:P>P9P\u0010Q\u0000Q\u0005P8P2Y\u0005Y\u0006X*X/Y\tX%X1X3X'Y\u0004X1X3X'Y\u0004X)X'Y\u0004X9X'Y\u0005Y\u0003X*X(Y\u0007X'X(X1X'Y\u0005X,X'Y\u0004Y\nY\u0008Y\u0005X'Y\u0004X5Y\u0008X1X,X/Y\nX/X)X'Y\u0004X9X6Y\u0008X%X6X'Y\u0001X)X'Y\u0004Y\u0002X3Y\u0005X'Y\u0004X9X'X(X*X-Y\u0005Y\nY\u0004Y\u0005Y\u0004Y\u0001X'X*Y\u0005Y\u0004X*Y\u0002Y\tX*X9X/Y\nY\u0004X'Y\u0004X4X9X1X#X.X(X'X1X*X7Y\u0008Y\nX1X9Y\u0004Y\nY\u0003Y\u0005X%X1Y\u0001X'Y\u0002X7Y\u0004X(X'X*X'Y\u0004Y\u0004X:X)X*X1X*Y\nX(X'Y\u0004Y\u0006X'X3X'Y\u0004X4Y\nX.Y\u0005Y\u0006X*X/Y\nX'Y\u0004X9X1X(X'Y\u0004Y\u0002X5X5X'Y\u0001Y\u0004X'Y\u0005X9Y\u0004Y\nY\u0007X'X*X-X/Y\nX+X'Y\u0004Y\u0004Y\u0007Y\u0005X'Y\u0004X9Y\u0005Y\u0004Y\u0005Y\u0003X*X(X)Y\nY\u0005Y\u0003Y\u0006Y\u0003X'Y\u0004X7Y\u0001Y\u0004Y\u0001Y\nX/Y\nY\u0008X%X/X'X1X)X*X'X1Y\nX.X'Y\u0004X5X-X)X*X3X,Y\nY\u0004X'Y\u0004Y\u0008Y\u0002X*X9Y\u0006X/Y\u0005X'Y\u0005X/Y\nY\u0006X)X*X5Y\u0005Y\nY\u0005X#X1X4Y\nY\u0001X'Y\u0004X0Y\nY\u0006X9X1X(Y\nX)X(Y\u0008X'X(X)X#Y\u0004X9X'X(X'Y\u0004X3Y\u0001X1Y\u0005X4X'Y\u0003Y\u0004X*X9X'Y\u0004Y\tX'Y\u0004X#Y\u0008Y\u0004X'Y\u0004X3Y\u0006X)X,X'Y\u0005X9X)X'Y\u0004X5X-Y\u0001X'Y\u0004X/Y\nY\u0006Y\u0003Y\u0004Y\u0005X'X*X'Y\u0004X.X'X5X'Y\u0004Y\u0005Y\u0004Y\u0001X#X9X6X'X!Y\u0003X*X'X(X)X'Y\u0004X.Y\nX1X1X3X'X&Y\u0004X'Y\u0004Y\u0002Y\u0004X(X'Y\u0004X#X/X(Y\u0005Y\u0002X'X7X9Y\u0005X1X'X3Y\u0004Y\u0005Y\u0006X7Y\u0002X)X'Y\u0004Y\u0003X*X(X'Y\u0004X1X,Y\u0004X'X4X*X1Y\u0003X'Y\u0004Y\u0002X/Y\u0005Y\nX9X7Y\nY\u0003sByTagName(.jpg\" alt=\"1px solid #.gif\" alt=\"transparentinformationapplication\" onclick=\"establishedadvertising.png\" alt=\"environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright\">0\" height=\"even thoughreplacementdestinationCorporation<ul class=\"AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class=\"hundreds of\n\nHowever, compositionclear:both;cooperationwithin the label for=\"border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength=\"switzerlandDevelopmentessentially\n\nAlthough </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics\n\t<div id=\"illustratedengineeringterritoriesauthoritiesdistributed6\" height=\"sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class=\"more recentit has beeninvasion of).getTime()fundamentalDespite the\"><div id=\"inspirationexaminationpreparationexplanation<input id=\"</a></span>versions ofinstrumentsbefore the = 'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright\" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content\">\n<td class=\"undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src=\"/<h1 class=\"publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=\";width:100%independent<h3 class=\" onchange=\").addClass(interactionOne of the daughter ofaccessoriesbranches of\r\n<div id=\"the largestdeclarationregulationsInformationtranslationdocumentaryin order to\">\n<head>\n<\" height=\"1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer\">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class=\"distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>\n</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>\n selected=\"high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1\"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex=\"it could be<noscript>\nhaving been\r\n<head>\r\n< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often\"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval\"></span></in New Yorkadditional compression\n\n<div id=\"incorporate;</script><attachEventbecame the \" target=\"_carried outSome of thescience andthe time ofContainer\">maintainingChristopherMuch of thewritings of\" height=\"2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit=\"director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class=\"Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the\" height=\"3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>\r\nContinentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name=\"TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel=\"This is the <a href=\"/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og=\"><a class=\"class=\"textConversion may be usedmanufactureafter beingclearfix\">\nquestion ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html\"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period\" name=\"q\" confined toa result ofvalue=\"\" />is actuallyEnvironment\r\n</head>\r\nConversely,>\n<div id=\"0\" width=\"1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious\">this is notthe presentif they areand finallya matter of\r\n\t</div>\r\n\r\n</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer\" class=\"frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>\n<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger\n\t</script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>\n they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight=\"0\" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class=\"btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world'scan lead torefers to aborder=\"0\" government winning theresulted in while the Washington,the subjectcity in the></div>\r\n\t\treflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=\"\"><a href=\"themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href=\"/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in\t\t<div id=\"it\" value=\"language ofas they areproduced inis that theexplain thediv></div>\nHowever thelead to the\t<a href=\"/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldslovenD\rinacomentariosuniversidadcondicionesactividadesexperienciatecnologC-aproducciC3npuntuaciC3naplicaciC3ncontraseC1acategorC-asregistrarseprofesionaltratamientoregC-stratesecretarC-aprincipalesprotecciC3nimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociaciC3ndisponiblesevaluaciC3nestudiantesresponsableresoluciC3nguadalajararegistradosoportunidadcomercialesfotografC-aautoridadesingenierC-atelevisiC3ncompetenciaoperacionesestablecidosimplementeactualmentenavegaciC3nconformidadline-height:font-family:\" : \"http://applicationslink\" href=\"specifically//<![CDATA[\nOrganizationdistribution0px; height:relationshipdevice-width<div class=\"<label for=\"registration</noscript>\n/index.html\"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name=\"intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class=\"organisationcivilization19th centuryarchitectureincorporated20th century-container\">most notably/></a></div>notification'undefined')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang=\"&lt;/sup&gt;dealing withphiladelphiahistorically);</script>\npadding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd\">\r\n<htgeographicalConstitution', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style=\"Encyclopediaiframe src=\"demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence\" tabindex=\"float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time\"><a class=\"In addition,description+conversationcontact withis generallyr\" content=\"representing&lt;math&gt;presentationoccasionally<img width=\"navigation\">compensationchampionshipmedia=\"all\" violation ofreference toreturn true;Strict//EN\" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}\n</script>\nChristianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=\"\"><a href=\"/introductionbelonging toclaimed thatconsequences<meta name=\"Guide to theoverwhelmingagainst the concentrated,\n.nontouch observations</a>\n</div>\nf (document.border: 1px {font-size:1treatment of0\" height=\"1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript\" neverthelesssignificanceBroadcasting>&nbsp;</td>container\">\nsuch as the influence ofa particularsrc='http://navigation\" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite\" xml:lang=\"deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype=\"image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet\t<ul class=\"installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures\n\t\t<a href=\"close to theexamples of is about the(see below).\" id=\"searchprofessionalis availablethe official\t\t</script>\n\n\t\t<div id=\"accelerationthrough the Hall of Famedescriptionstranslationsinterference type='text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the\t<li class=\"instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class=\"aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc=\"http://px; height: available tomanufacturerhuman rightslink href=\"/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>\r\nconsider thean estimatedthe National<div id=\"pagresulting incommissionedanalogous toare required/ul>\n</div>\nwas based onand became a&nbsp;&nbsp;t\" value=\"\" was capturedno more thanrespectivelycontinue to >\r\n<head>\r\n<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml\" title=\"weight:bold;creating thedisplay:nonereplaced the<img src=\"/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css\" media=\"People from available onproved to besuggestions\"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class=\"evidence forexplanationsenvironments\"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign=\"top\"principle ofat the time,</noscript>\rsaid to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style=\"input name=\"the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class=\"lastworking with'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the\n</script>\n\nan effort toincrease theto the southspacing=\"0\">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>\nthought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds\" content=\"authority ofnorthwestern</div>\n<div \"></div>\r\n consultationcommunity ofthe nationalit should beparticipants align=\"leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class=\"splace in thewhere he was<li class=\"fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions\">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class=\"effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previousconsistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\\s+|\\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers\t<link rel=\"provided thethe story ofcompetitionsenglish (UK)english (US)P\u001CP>P=P3P>P;P!Q\u0000P?Q\u0001P:P8Q\u0001Q\u0000P?Q\u0001P:P8Q\u0001Q\u0000P?Q\u0001P:P>Y\u0004X9X1X(Y\nX)f-#i+\u0014d8-f\u0016\u0007g.\u0000d=\u0013d8-f\u0016\u0007g9\u0001d=\u0013d8-f\u0016\u0007f\u001C\ti\u0019\u0010e\u0005,e\u000F8d::f0\u0011f\u0014?e:\u001Ci\u0018?i\u0007\u000Ce74e74g$>d<\u001Ad8;d9\tf\u0013\rd=\u001Cg3;g;\u001Ff\u0014?g-\u0016f3\u0015h'\u0004informaciC3nherramientaselectrC3nicodescripciC3nclasificadosconocimientopublicaciC3nrelacionadasinformC!ticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecontC!ctenoshabitacionescumplimientorestaurantesdisposiciC3nconsecuenciaelectrC3nicaaplicacionesdesconectadoinstalaciC3nrealizaciC3nutilizaciC3nenciclopediaenfermedadesinstrumentosexperienciasinstituciC3nparticularessubcategoriaQ\u0002P>P;Q\u000CP:P>P P>Q\u0001Q\u0001P8P8Q\u0000P0P1P>Q\u0002Q\u000BP1P>P;Q\u000CQ\u0008P5P?Q\u0000P>Q\u0001Q\u0002P>P<P>P6P5Q\u0002P5P4Q\u0000Q\u0003P3P8Q\u0005Q\u0001P;Q\u0003Q\u0007P0P5Q\u0001P5P9Q\u0007P0Q\u0001P2Q\u0001P5P3P4P0P P>Q\u0001Q\u0001P8Q\u000FP\u001CP>Q\u0001P:P2P5P4Q\u0000Q\u0003P3P8P5P3P>Q\u0000P>P4P0P2P>P?Q\u0000P>Q\u0001P4P0P=P=Q\u000BQ\u0005P4P>P;P6P=Q\u000BP8P<P5P=P=P>P\u001CP>Q\u0001P:P2Q\u000BQ\u0000Q\u0003P1P;P5P9P\u001CP>Q\u0001P:P2P0Q\u0001Q\u0002Q\u0000P0P=Q\u000BP=P8Q\u0007P5P3P>Q\u0000P0P1P>Q\u0002P5P4P>P;P6P5P=Q\u0003Q\u0001P;Q\u0003P3P8Q\u0002P5P?P5Q\u0000Q\u000CP\u001EP4P=P0P:P>P?P>Q\u0002P>P<Q\u0003Q\u0000P0P1P>Q\u0002Q\u0003P0P?Q\u0000P5P;Q\u000FP2P>P>P1Q\tP5P>P4P=P>P3P>Q\u0001P2P>P5P3P>Q\u0001Q\u0002P0Q\u0002Q\u000CP8P4Q\u0000Q\u0003P3P>P9Q\u0004P>Q\u0000Q\u0003P<P5Q\u0005P>Q\u0000P>Q\u0008P>P?Q\u0000P>Q\u0002P8P2Q\u0001Q\u0001Q\u000BP;P:P0P:P0P6P4Q\u000BP9P2P;P0Q\u0001Q\u0002P8P3Q\u0000Q\u0003P?P?Q\u000BP2P<P5Q\u0001Q\u0002P5Q\u0000P0P1P>Q\u0002P0Q\u0001P:P0P7P0P;P?P5Q\u0000P2Q\u000BP9P4P5P;P0Q\u0002Q\u000CP4P5P=Q\u000CP3P8P?P5Q\u0000P8P>P4P1P8P7P=P5Q\u0001P>Q\u0001P=P>P2P5P<P>P<P5P=Q\u0002P:Q\u0003P?P8Q\u0002Q\u000CP4P>P;P6P=P0Q\u0000P0P<P:P0Q\u0005P=P0Q\u0007P0P;P>P P0P1P>Q\u0002P0P\"P>P;Q\u000CP:P>Q\u0001P>P2Q\u0001P5P<P2Q\u0002P>Q\u0000P>P9P=P0Q\u0007P0P;P0Q\u0001P?P8Q\u0001P>P:Q\u0001P;Q\u0003P6P1Q\u000BQ\u0001P8Q\u0001Q\u0002P5P<P?P5Q\u0007P0Q\u0002P8P=P>P2P>P3P>P?P>P<P>Q\tP8Q\u0001P0P9Q\u0002P>P2P?P>Q\u0007P5P<Q\u0003P?P>P<P>Q\tQ\u000CP4P>P;P6P=P>Q\u0001Q\u0001Q\u000BP;P:P8P1Q\u000BQ\u0001Q\u0002Q\u0000P>P4P0P=P=Q\u000BP5P<P=P>P3P8P5P?Q\u0000P>P5P:Q\u0002P!P5P9Q\u0007P0Q\u0001P<P>P4P5P;P8Q\u0002P0P:P>P3P>P>P=P;P0P9P=P3P>Q\u0000P>P4P5P2P5Q\u0000Q\u0001P8Q\u000FQ\u0001Q\u0002Q\u0000P0P=P5Q\u0004P8P;Q\u000CP<Q\u000BQ\u0003Q\u0000P>P2P=Q\u000FQ\u0000P0P7P=Q\u000BQ\u0005P8Q\u0001P:P0Q\u0002Q\u000CP=P5P4P5P;Q\u000EQ\u000FP=P2P0Q\u0000Q\u000FP<P5P=Q\u000CQ\u0008P5P<P=P>P3P8Q\u0005P4P0P=P=P>P9P7P=P0Q\u0007P8Q\u0002P=P5P;Q\u000CP7Q\u000FQ\u0004P>Q\u0000Q\u0003P<P0P\"P5P?P5Q\u0000Q\u000CP<P5Q\u0001Q\u000FQ\u0006P0P7P0Q\tP8Q\u0002Q\u000BP\u001BQ\u0003Q\u0007Q\u0008P8P5`$(`$9`%\u0000`$\u0002`$\u0015`$0`$(`%\u0007`$\u0005`$*`$(`%\u0007`$\u0015`$?`$/`$>`$\u0015`$0`%\u0007`$\u0002`$\u0005`$(`%\r`$/`$\u0015`%\r`$/`$>`$\u0017`$>`$\u0007`$!`$,`$>`$0`%\u0007`$\u0015`$?`$8`%\u0000`$&`$?`$/`$>`$*`$9`$2`%\u0007`$8`$?`$\u0002`$9`$-`$>`$0`$$`$\u0005`$*`$(`%\u0000`$5`$>`$2`%\u0007`$8`%\u0007`$5`$>`$\u0015`$0`$$`%\u0007`$.`%\u0007`$0`%\u0007`$9`%\u000B`$(`%\u0007`$8`$\u0015`$$`%\u0007`$,`$9`%\u0001`$$`$8`$>`$\u0007`$\u001F`$9`%\u000B`$\u0017`$>`$\u001C`$>`$(`%\u0007`$.`$?`$(`$\u001F`$\u0015`$0`$$`$>`$\u0015`$0`$(`$>`$\t`$(`$\u0015`%\u0007`$/`$9`$>`$\u0001`$8`$,`$8`%\u0007`$-`$>`$7`$>`$\u0006`$*`$\u0015`%\u0007`$2`$?`$/`%\u0007`$6`%\u0001`$0`%\u0002`$\u0007`$8`$\u0015`%\u0007`$\u0018`$\u0002`$\u001F`%\u0007`$.`%\u0007`$0`%\u0000`$8`$\u0015`$$`$>`$.`%\u0007`$0`$>`$2`%\u0007`$\u0015`$0`$\u0005`$'`$?`$\u0015`$\u0005`$*`$(`$>`$8`$.`$>`$\u001C`$.`%\u0001`$\u001D`%\u0007`$\u0015`$>`$0`$#`$9`%\u000B`$$`$>`$\u0015`$!`$<`%\u0000`$/`$9`$>`$\u0002`$9`%\u000B`$\u001F`$2`$6`$,`%\r`$&`$2`$?`$/`$>`$\u001C`%\u0000`$5`$(`$\u001C`$>`$$`$>`$\u0015`%\u0008`$8`%\u0007`$\u0006`$*`$\u0015`$>`$5`$>`$2`%\u0000`$&`%\u0007`$(`%\u0007`$*`%\u0002`$0`%\u0000`$*`$>`$(`%\u0000`$\t`$8`$\u0015`%\u0007`$9`%\u000B`$\u0017`%\u0000`$,`%\u0008`$ `$\u0015`$\u0006`$*`$\u0015`%\u0000`$5`$0`%\r`$7`$\u0017`$>`$\u0002`$5`$\u0006`$*`$\u0015`%\u000B`$\u001C`$?`$2`$>`$\u001C`$>`$(`$>`$8`$9`$.`$$`$9`$.`%\u0007`$\u0002`$\t`$(`$\u0015`%\u0000`$/`$>`$9`%\u0002`$&`$0`%\r`$\u001C`$8`%\u0002`$\u001A`%\u0000`$*`$8`$\u0002`$&`$8`$5`$>`$2`$9`%\u000B`$(`$>`$9`%\u000B`$$`%\u0000`$\u001C`%\u0008`$8`%\u0007`$5`$>`$*`$8`$\u001C`$(`$$`$>`$(`%\u0007`$$`$>`$\u001C`$>`$0`%\u0000`$\u0018`$>`$/`$2`$\u001C`$?`$2`%\u0007`$(`%\u0000`$\u001A`%\u0007`$\u001C`$>`$\u0002`$\u001A`$*`$$`%\r`$0`$\u0017`%\u0002`$\u0017`$2`$\u001C`$>`$$`%\u0007`$,`$>`$9`$0`$\u0006`$*`$(`%\u0007`$5`$>`$9`$(`$\u0007`$8`$\u0015`$>`$8`%\u0001`$,`$9`$0`$9`$(`%\u0007`$\u0007`$8`$8`%\u0007`$8`$9`$?`$$`$,`$!`$<`%\u0007`$\u0018`$\u001F`$(`$>`$$`$2`$>`$6`$*`$>`$\u0002`$\u001A`$6`%\r`$0`%\u0000`$,`$!`$<`%\u0000`$9`%\u000B`$$`%\u0007`$8`$>`$\u0008`$\u001F`$6`$>`$/`$&`$8`$\u0015`$$`%\u0000`$\u001C`$>`$$`%\u0000`$5`$>`$2`$>`$9`$\u001C`$>`$0`$*`$\u001F`$(`$>`$0`$\u0016`$(`%\u0007`$8`$!`$<`$\u0015`$.`$?`$2`$>`$\t`$8`$\u0015`%\u0000`$\u0015`%\u0007`$5`$2`$2`$\u0017`$$`$>`$\u0016`$>`$(`$>`$\u0005`$0`%\r`$%`$\u001C`$9`$>`$\u0002`$&`%\u0007`$\u0016`$>`$*`$9`$2`%\u0000`$(`$?`$/`$.`$,`$?`$(`$>`$,`%\u0008`$\u0002`$\u0015`$\u0015`$9`%\u0000`$\u0002`$\u0015`$9`$(`$>`$&`%\u0007`$$`$>`$9`$.`$2`%\u0007`$\u0015`$>`$+`%\u0000`$\u001C`$,`$\u0015`$?`$$`%\u0001`$0`$$`$.`$>`$\u0002`$\u0017`$5`$9`%\u0000`$\u0002`$0`%\u000B`$\u001C`$<`$.`$?`$2`%\u0000`$\u0006`$0`%\u000B`$*`$8`%\u0007`$(`$>`$/`$>`$&`$5`$2`%\u0007`$(`%\u0007`$\u0016`$>`$$`$>`$\u0015`$0`%\u0000`$,`$\t`$(`$\u0015`$>`$\u001C`$5`$>`$,`$*`%\u0002`$0`$>`$,`$!`$<`$>`$8`%\u000C`$&`$>`$6`%\u0007`$/`$0`$\u0015`$?`$/`%\u0007`$\u0015`$9`$>`$\u0002`$\u0005`$\u0015`$8`$0`$,`$(`$>`$\u000F`$5`$9`$>`$\u0002`$8`%\r`$%`$2`$.`$?`$2`%\u0007`$2`%\u0007`$\u0016`$\u0015`$5`$?`$7`$/`$\u0015`%\r`$0`$\u0002`$8`$.`%\u0002`$9`$%`$>`$(`$>X*X3X*X7Y\nX9Y\u0005X4X'X1Y\u0003X)X(Y\u0008X'X3X7X)X'Y\u0004X5Y\u0001X-X)Y\u0005Y\u0008X'X6Y\nX9X'Y\u0004X.X'X5X)X'Y\u0004Y\u0005X2Y\nX/X'Y\u0004X9X'Y\u0005X)X'Y\u0004Y\u0003X'X*X(X'Y\u0004X1X/Y\u0008X/X(X1Y\u0006X'Y\u0005X,X'Y\u0004X/Y\u0008Y\u0004X)X'Y\u0004X9X'Y\u0004Y\u0005X'Y\u0004Y\u0005Y\u0008Y\u0002X9X'Y\u0004X9X1X(Y\nX'Y\u0004X3X1Y\nX9X'Y\u0004X,Y\u0008X'Y\u0004X'Y\u0004X0Y\u0007X'X(X'Y\u0004X-Y\nX'X)X'Y\u0004X-Y\u0002Y\u0008Y\u0002X'Y\u0004Y\u0003X1Y\nY\u0005X'Y\u0004X9X1X'Y\u0002Y\u0005X-Y\u0001Y\u0008X8X)X'Y\u0004X+X'Y\u0006Y\nY\u0005X4X'Y\u0007X/X)X'Y\u0004Y\u0005X1X#X)X'Y\u0004Y\u0002X1X\"Y\u0006X'Y\u0004X4X(X'X(X'Y\u0004X-Y\u0008X'X1X'Y\u0004X,X/Y\nX/X'Y\u0004X#X3X1X)X'Y\u0004X9Y\u0004Y\u0008Y\u0005Y\u0005X,Y\u0005Y\u0008X9X)X'Y\u0004X1X-Y\u0005Y\u0006X'Y\u0004Y\u0006Y\u0002X'X7Y\u0001Y\u0004X3X7Y\nY\u0006X'Y\u0004Y\u0003Y\u0008Y\nX*X'Y\u0004X/Y\u0006Y\nX'X(X1Y\u0003X'X*Y\u0007X'Y\u0004X1Y\nX'X6X*X-Y\nX'X*Y\nX(X*Y\u0008Y\u0002Y\nX*X'Y\u0004X#Y\u0008Y\u0004Y\tX'Y\u0004X(X1Y\nX/X'Y\u0004Y\u0003Y\u0004X'Y\u0005X'Y\u0004X1X'X(X7X'Y\u0004X4X.X5Y\nX3Y\nX'X1X'X*X'Y\u0004X+X'Y\u0004X+X'Y\u0004X5Y\u0004X'X)X'Y\u0004X-X/Y\nX+X'Y\u0004X2Y\u0008X'X1X'Y\u0004X.Y\u0004Y\nX,X'Y\u0004X,Y\u0005Y\nX9X'Y\u0004X9X'Y\u0005Y\u0007X'Y\u0004X,Y\u0005X'Y\u0004X'Y\u0004X3X'X9X)Y\u0005X4X'Y\u0007X/Y\u0007X'Y\u0004X1X&Y\nX3X'Y\u0004X/X.Y\u0008Y\u0004X'Y\u0004Y\u0001Y\u0006Y\nX)X'Y\u0004Y\u0003X*X'X(X'Y\u0004X/Y\u0008X1Y\nX'Y\u0004X/X1Y\u0008X3X'X3X*X:X1Y\u0002X*X5X'Y\u0005Y\nY\u0005X'Y\u0004X(Y\u0006X'X*X'Y\u0004X9X8Y\nY\u0005entertainmentunderstanding = function().jpg\" width=\"configuration.png\" width=\"<body class=\"Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=\"\"><img src=\"/distinguishedthousands of communicationclear\"></div>investigationfavicon.ico\" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch\" type=\"form method=\"as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of\" maxlength=\"return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type=\"the number ofthe original comprehensiverefers to the</ul>\n</div>\nphilosophicallocation.hrefwas publishedSan Francisco(function(){\n<div id=\"mainsophisticatedmathematical /head>\r\n<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder=\"; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript\" src=\"/(function() {are available\n\t<link rel=\" src='http://interested inconventional \" alt=\"\" /></are generallyhas also beenmost popular correspondingcredited withtyle=\"border:</a></span></.gif\" width=\"<iframe src=\"table class=\"inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name=\"or\" content=\"controversialproperty=\"og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style=\"known as the shortly afterfor instance,described as /head>\n<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant\" border=\"0\">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name=\"searchattributed tocourse of themathematicianby the end ofat the end of\" border=\"0\" technological.removeClass(branch of theevidence that![endif]-->\r\nInstitute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href=\"confused with<link href=\"/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>\n</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription\" determine theavailable forAccording to wide range of\t<div class=\"more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover=\"because they async = true;problems withseems to havethe result of src=\"http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld's firstclassified asbottom of the(particularlyalign=\"left\" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout=\"New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd\">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to\t<meta name=\"are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to\t\t<ul class=\"visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style=\"equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these\n<div class=\"input class=\"replaced withis one of theeducation andinfluenced byreputation as\n<meta name=\"accommodation</div>\n</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the\n<div style=\"almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in\" value=\"\" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class=\"mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription\">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass=\"headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;\n</script>\n<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle=\"marginincluding thebahasa Melayunorsk bokmC%lnorsk nynorskslovenE!D\rinainternacionalcalificaciC3ncomunicaciC3nconstrucciC3n\"><div class=\"disambiguationDomainName', 'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->\n</><meta name=\"implementationinfrastructurerepresentationborder-bottom:</head>\n<body>=http%3A%2F%2F<form method=\"method=\"post\" /favicon.ico\" });\n</script>\n.setAttribute(Administration= new Array();<![endif]-->\r\ndisplay:block;Unfortunately,\">&nbsp;</div>/favicon.ico\">='stylesheet' identification, for example,<li><a href=\"/an alternativeas a result ofpt\"></script>\ntype=\"submit\" \n(function() {recommendationform action=\"/transformationreconstruction.style.display According to hidden\" name=\"along with thedocument.body.approximately Communicationspost\" action=\"meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover=\"the governmenthref=\"https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->\n\ndepends on theUniversity of in contrast to placeholder=\"in the case ofinternational constitutionalstyle=\"border-: function() {Because of the-strict.dtd\">\n<table class=\"accompanied byaccount of the<script src=\"/nature of the the people in in addition tos); js.id = id\" width=\"100%\"regarding the Roman Catholican independentfollowing the .gif\" width=\"1the following discriminationarchaeologicalprime minister.js\"></script>combination of marginwidth=\"createElement(w.attachEvent(</a></td></tr>src=\"https://aIn particular, align=\"left\" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html\" title=\"(function () {comes from theapplication of<span class=\"sbelieved to beement('script'</a>\n</li>\n<livery different><span class=\"option value=\"(also known as\t<li><a href=\"><input name=\"separated fromreferred to as valign=\"top\">founder of theattempting to carbon dioxide\n\n<div class=\"class=\"search-/body>\n</html>opportunity tocommunications</head>\r\n<body style=\"width:Tia:?ng Via;\u0007tchanges in theborder-color:#0\" border=\"0\" </span></div><was discovered\" type=\"text\" );\n</script>\n\nDepartment of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>\n\n<div iwas consideredpercent of the\" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href='http://whether or notThere are alsothere are manya small numberother parts ofimpossible to class=\"buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=\" method=\"post\"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign=\"right\">many countriesfor many yearsearliest knownbecause it waspt\"></script>\r valign=\"top\" inhabitants offollowing year\r\n<div class=\"million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style=\"color:although therebest known forsubmit\" name=\"multiplicationmore than one recognition ofCouncil of theedition of the <meta name=\"Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class=\"descendants of<span class=\"i align=\"right\"</head>\n<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the\t<span class=\"is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class=\"<span class=\"t(Math.random()most prominentdescription ofConstantinoplewere published<div class=\"seappears in the1\" height=\"1\" most importantwhich includeswhich had beendestruction ofthe population\n\t<div class=\"possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle=\"clear:b\r\n</script>\r\n<was founded ininterview with_id\" content=\"capital of the\r\n<link rel=\"srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class=\"cperformance of(function() {\rif and only ifregions of theleading to therelations withUnited Nationsstyle=\"height:other than theype\" content=\"Association of\n</head>\n<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>\n<link rel=\" return false;the purpose ofthe ability to;color:#fff}\n.\n<span class=\"the subject ofdefinitions of>\r\n<link rel=\"claim that thehave developed<table width=\"celebration ofFollowing the to distinguish<span class=\"btakes place inunder the namenoted that the><![endif]-->\nstyle=\"margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id=\"was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>\r\n\r\nenvironmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made\" src=\"http://interpreted assecond half ofcrolling=\"no\" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class=\"footerand especiallytype=\"button\" </span></span>which included>\n<meta name=\"considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process <div class=\"the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class=\"ptext\" name=\"q\"\t\t<div class=\"the scientificrepresented bymathematicianselected by thethat have been><div class=\"cdiv id=\"headerin particular,converted into);\n</script>\n<philosophical srpskohrvatskitia:?ng Via;\u0007tP Q\u0003Q\u0001Q\u0001P:P8P9Q\u0000Q\u0003Q\u0001Q\u0001P:P8P9investigaciC3nparticipaciC3nP:P>Q\u0002P>Q\u0000Q\u000BP5P>P1P;P0Q\u0001Q\u0002P8P:P>Q\u0002P>Q\u0000Q\u000BP9Q\u0007P5P;P>P2P5P:Q\u0001P8Q\u0001Q\u0002P5P<Q\u000BP\u001DP>P2P>Q\u0001Q\u0002P8P:P>Q\u0002P>Q\u0000Q\u000BQ\u0005P>P1P;P0Q\u0001Q\u0002Q\u000CP2Q\u0000P5P<P5P=P8P:P>Q\u0002P>Q\u0000P0Q\u000FQ\u0001P5P3P>P4P=Q\u000FQ\u0001P:P0Q\u0007P0Q\u0002Q\u000CP=P>P2P>Q\u0001Q\u0002P8P#P:Q\u0000P0P8P=Q\u000BP2P>P?Q\u0000P>Q\u0001Q\u000BP:P>Q\u0002P>Q\u0000P>P9Q\u0001P4P5P;P0Q\u0002Q\u000CP?P>P<P>Q\tQ\u000CQ\u000EQ\u0001Q\u0000P5P4Q\u0001Q\u0002P2P>P1Q\u0000P0P7P>P<Q\u0001Q\u0002P>Q\u0000P>P=Q\u000BQ\u0003Q\u0007P0Q\u0001Q\u0002P8P5Q\u0002P5Q\u0007P5P=P8P5P\u0013P;P0P2P=P0Q\u000FP8Q\u0001Q\u0002P>Q\u0000P8P8Q\u0001P8Q\u0001Q\u0002P5P<P0Q\u0000P5Q\u0008P5P=P8Q\u000FP!P:P0Q\u0007P0Q\u0002Q\u000CP?P>Q\rQ\u0002P>P<Q\u0003Q\u0001P;P5P4Q\u0003P5Q\u0002Q\u0001P:P0P7P0Q\u0002Q\u000CQ\u0002P>P2P0Q\u0000P>P2P:P>P=P5Q\u0007P=P>Q\u0000P5Q\u0008P5P=P8P5P:P>Q\u0002P>Q\u0000P>P5P>Q\u0000P3P0P=P>P2P:P>Q\u0002P>Q\u0000P>P<P P5P:P;P0P<P0X'Y\u0004Y\u0005Y\u0006X*X/Y\tY\u0005Y\u0006X*X/Y\nX'X*X'Y\u0004Y\u0005Y\u0008X6Y\u0008X9X'Y\u0004X(X1X'Y\u0005X,X'Y\u0004Y\u0005Y\u0008X'Y\u0002X9X'Y\u0004X1X3X'X&Y\u0004Y\u0005X4X'X1Y\u0003X'X*X'Y\u0004X#X9X6X'X!X'Y\u0004X1Y\nX'X6X)X'Y\u0004X*X5Y\u0005Y\nY\u0005X'Y\u0004X'X9X6X'X!X'Y\u0004Y\u0006X*X'X&X,X'Y\u0004X#Y\u0004X9X'X(X'Y\u0004X*X3X,Y\nY\u0004X'Y\u0004X#Y\u0002X3X'Y\u0005X'Y\u0004X6X:X7X'X*X'Y\u0004Y\u0001Y\nX/Y\nY\u0008X'Y\u0004X*X1X-Y\nX(X'Y\u0004X,X/Y\nX/X)X'Y\u0004X*X9Y\u0004Y\nY\u0005X'Y\u0004X#X.X(X'X1X'Y\u0004X'Y\u0001Y\u0004X'Y\u0005X'Y\u0004X#Y\u0001Y\u0004X'Y\u0005X'Y\u0004X*X'X1Y\nX.X'Y\u0004X*Y\u0002Y\u0006Y\nX)X'Y\u0004X'Y\u0004X9X'X(X'Y\u0004X.Y\u0008X'X7X1X'Y\u0004Y\u0005X,X*Y\u0005X9X'Y\u0004X/Y\nY\u0003Y\u0008X1X'Y\u0004X3Y\nX'X-X)X9X(X/X'Y\u0004Y\u0004Y\u0007X'Y\u0004X*X1X(Y\nX)X'Y\u0004X1Y\u0008X'X(X7X'Y\u0004X#X/X(Y\nX)X'Y\u0004X'X.X(X'X1X'Y\u0004Y\u0005X*X-X/X)X'Y\u0004X'X:X'Y\u0006Y\ncursor:pointer;</title>\n<meta \" href=\"http://\"><span class=\"members of the window.locationvertical-align:/a> | <a href=\"<!doctype html>media=\"screen\" <option value=\"favicon.ico\" />\n\t\t<div class=\"characteristics\" method=\"get\" /body>\n</html>\nshortcut icon\" document.write(padding-bottom:representativessubmit\" value=\"align=\"center\" throughout the science fiction\n <div class=\"submit\" class=\"one of the most valign=\"top\"><was established);\r\n</script>\r\nreturn false;\">).style.displaybecause of the document.cookie<form action=\"/}body{margin:0;Encyclopedia ofversion of the .createElement(name\" content=\"</div>\n</div>\n\nadministrative </body>\n</html>history of the \"><input type=\"portion of the as part of the &nbsp;<a href=\"other countries\">\n<div class=\"</span></span><In other words,display: block;control of the introduction of/>\n<meta name=\"as well as the in recent years\r\n\t<div class=\"</div>\n\t</div>\ninspired by thethe end of the compatible withbecame known as style=\"margin:.js\"></script>< International there have beenGerman language style=\"color:#Communist Partyconsistent withborder=\"0\" cell marginheight=\"the majority of\" align=\"centerrelated to the many different Orthodox Churchsimilar to the />\n<link rel=\"swas one of the until his death})();\n</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling=\"no\" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign=\"center\">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style=\"width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>\n\t<div class=\"consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method=\"post\" was followed by&amp;mdash; thethe applicationjs\"></script>\r\nul></div></div>after the deathwith respect tostyle=\"padding:is particularlydisplay:inline; type=\"submit\" is divided intod8-f\u0016\u0007 (g.\u0000d=\u0013)responsabilidadadministraciC3ninternacionalescorrespondiente`$\t`$*`$/`%\u000B`$\u0017`$*`%\u0002`$0`%\r`$5`$9`$.`$>`$0`%\u0007`$2`%\u000B`$\u0017`%\u000B`$\u0002`$\u001A`%\u0001`$(`$>`$5`$2`%\u0007`$\u0015`$?`$(`$8`$0`$\u0015`$>`$0`$*`%\u0001`$2`$?`$8`$\u0016`%\u000B`$\u001C`%\u0007`$\u0002`$\u001A`$>`$9`$?`$\u000F`$-`%\u0007`$\u001C`%\u0007`$\u0002`$6`$>`$.`$?`$2`$9`$.`$>`$0`%\u0000`$\u001C`$>`$\u0017`$0`$#`$,`$(`$>`$(`%\u0007`$\u0015`%\u0001`$.`$>`$0`$,`%\r`$2`%\t`$\u0017`$.`$>`$2`$?`$\u0015`$.`$9`$?`$2`$>`$*`%\u0003`$7`%\r`$ `$,`$\"`$<`$$`%\u0007`$-`$>`$\u001C`$*`$>`$\u0015`%\r`$2`$?`$\u0015`$\u001F`%\r`$0`%\u0007`$(`$\u0016`$?`$2`$>`$+`$&`%\u000C`$0`$>`$(`$.`$>`$.`$2`%\u0007`$.`$$`$&`$>`$(`$,`$>`$\u001C`$>`$0`$5`$?`$\u0015`$>`$8`$\u0015`%\r`$/`%\u000B`$\u0002`$\u001A`$>`$9`$$`%\u0007`$*`$9`%\u0001`$\u0001`$\u001A`$,`$$`$>`$/`$>`$8`$\u0002`$5`$>`$&`$&`%\u0007`$\u0016`$(`%\u0007`$*`$?`$\u001B`$2`%\u0007`$5`$?`$6`%\u0007`$7`$0`$>`$\u001C`%\r`$/`$\t`$$`%\r`$$`$0`$.`%\u0001`$\u0002`$,`$\u0008`$&`%\u000B`$(`%\u000B`$\u0002`$\t`$*`$\u0015`$0`$#`$*`$\"`$<`%\u0007`$\u0002`$8`%\r`$%`$?`$$`$+`$?`$2`%\r`$.`$.`%\u0001`$\u0016`%\r`$/`$\u0005`$\u001A`%\r`$\u001B`$>`$\u001B`%\u0002`$\u001F`$$`%\u0000`$8`$\u0002`$\u0017`%\u0000`$$`$\u001C`$>`$\u000F`$\u0017`$>`$5`$?`$-`$>`$\u0017`$\u0018`$#`%\r`$\u001F`%\u0007`$&`%\u0002`$8`$0`%\u0007`$&`$?`$(`%\u000B`$\u0002`$9`$$`%\r`$/`$>`$8`%\u0007`$\u0015`%\r`$8`$\u0017`$>`$\u0002`$'`%\u0000`$5`$?`$6`%\r`$5`$0`$>`$$`%\u0007`$\u0002`$&`%\u0008`$\u001F`%\r`$8`$(`$\u0015`%\r`$6`$>`$8`$>`$.`$(`%\u0007`$\u0005`$&`$>`$2`$$`$,`$?`$\u001C`$2`%\u0000`$*`%\u0001`$0`%\u0002`$7`$9`$?`$\u0002`$&`%\u0000`$.`$?`$$`%\r`$0`$\u0015`$5`$?`$$`$>`$0`%\u0001`$*`$/`%\u0007`$8`%\r`$%`$>`$(`$\u0015`$0`%\u000B`$!`$<`$.`%\u0001`$\u0015`%\r`$$`$/`%\u000B`$\u001C`$(`$>`$\u0015`%\u0003`$*`$/`$>`$*`%\u000B`$8`%\r`$\u001F`$\u0018`$0`%\u0007`$2`%\u0002`$\u0015`$>`$0`%\r`$/`$5`$?`$\u001A`$>`$0`$8`%\u0002`$\u001A`$(`$>`$.`%\u0002`$2`%\r`$/`$&`%\u0007`$\u0016`%\u0007`$\u0002`$9`$.`%\u0007`$6`$>`$8`%\r`$\u0015`%\u0002`$2`$.`%\u0008`$\u0002`$(`%\u0007`$$`%\u0008`$/`$>`$0`$\u001C`$?`$8`$\u0015`%\u0007rss+xml\" title=\"-type\" content=\"title\" content=\"at the same time.js\"></script>\n<\" method=\"post\" </span></a></li>vertical-align:t/jquery.min.js\">.click(function( style=\"padding-})();\n</script>\n</span><a href=\"<a href=\"http://); return false;text-decoration: scrolling=\"no\" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif\" border=\"0\"</body>\n</html>\noverflow:hidden;img src=\"http://addEventListenerresponsible for s.js\"></script>\n/favicon.ico\" />operating system\" style=\"width:1target=\"_blank\">State Universitytext-align:left;\ndocument.write(, including the around the world);\r\n</script>\r\n<\" style=\"height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>\n\t\t</div>\ndisplay: none;\">\" />\n<link rel=\"\n (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the align=\"center\">University Pressdominated by theSecond World Wardistribution of style=\"position:the rest of the characterized by rel=\"nofollow\">derives from therather than the a combination ofstyle=\"width:100English-speakingcomputer scienceborder=\"0\" alt=\"the existence ofDemocratic Party\" style=\"margin-For this reason,.js\"></script>\n\tsByTagName(s)[0]js\"></script>\r\n<.js\"></script>\r\nlink rel=\"icon\" ' alt='' class='formation of theversions of the </a></div></div>/page>\n <page>\n<div class=\"contbecame the firstbahasa Indonesiaenglish (simple)N\u0015N;N;N7N=N9N:N,Q\u0005Q\u0000P2P0Q\u0002Q\u0001P:P8P:P>P<P?P0P=P8P8Q\u000FP2P;Q\u000FP5Q\u0002Q\u0001Q\u000FP\u0014P>P1P0P2P8Q\u0002Q\u000CQ\u0007P5P;P>P2P5P:P0Q\u0000P0P7P2P8Q\u0002P8Q\u000FP\u0018P=Q\u0002P5Q\u0000P=P5Q\u0002P\u001EQ\u0002P2P5Q\u0002P8Q\u0002Q\u000CP=P0P?Q\u0000P8P<P5Q\u0000P8P=Q\u0002P5Q\u0000P=P5Q\u0002P:P>Q\u0002P>Q\u0000P>P3P>Q\u0001Q\u0002Q\u0000P0P=P8Q\u0006Q\u000BP:P0Q\u0007P5Q\u0001Q\u0002P2P5Q\u0003Q\u0001P;P>P2P8Q\u000FQ\u0005P?Q\u0000P>P1P;P5P<Q\u000BP?P>P;Q\u0003Q\u0007P8Q\u0002Q\u000CQ\u000FP2P;Q\u000FQ\u000EQ\u0002Q\u0001Q\u000FP=P0P8P1P>P;P5P5P:P>P<P?P0P=P8Q\u000FP2P=P8P<P0P=P8P5Q\u0001Q\u0000P5P4Q\u0001Q\u0002P2P0X'Y\u0004Y\u0005Y\u0008X'X6Y\nX9X'Y\u0004X1X&Y\nX3Y\nX)X'Y\u0004X'Y\u0006X*Y\u0002X'Y\u0004Y\u0005X4X'X1Y\u0003X'X*Y\u0003X'Y\u0004X3Y\nX'X1X'X*X'Y\u0004Y\u0005Y\u0003X*Y\u0008X(X)X'Y\u0004X3X9Y\u0008X/Y\nX)X'X-X5X'X&Y\nX'X*X'Y\u0004X9X'Y\u0004Y\u0005Y\nX)X'Y\u0004X5Y\u0008X*Y\nX'X*X'Y\u0004X'Y\u0006X*X1Y\u0006X*X'Y\u0004X*X5X'Y\u0005Y\nY\u0005X'Y\u0004X%X3Y\u0004X'Y\u0005Y\nX'Y\u0004Y\u0005X4X'X1Y\u0003X)X'Y\u0004Y\u0005X1X&Y\nX'X*robots\" content=\"<div id=\"footer\">the United States<img src=\"http://.jpg|right|thumb|.js\"></script>\r\n<location.protocolframeborder=\"0\" s\" />\n<meta name=\"</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:\" rel=\"nofollow\" President of the twentieth centuryevision>\n </pageInternet Explorera.async = true;\r\ninformation about<div id=\"header\">\" action=\"http://<a href=\"https://<div id=\"content\"</div>\r\n</div>\r\n<derived from the <img src='http://according to the \n</body>\n</html>\nstyle=\"font-size:script language=\"Arial, Helvetica,</a><span class=\"</script><script political partiestd></tr></table><href=\"http://www.interpretation ofrel=\"stylesheet\" document.write('<charset=\"utf-8\">\nbeginning of the revealed that thetelevision series\" rel=\"nofollow\"> target=\"_blank\">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass=\"clearfix\">/div>\r\n</div>\r\n\r\nthree-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class=\"in some countriesmin.js\"></script>of the populationofficial language<img src=\"images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>\r\n</html>\rN\u0015N;N;N7N=N9N:N,\ntake advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class=\"headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype=\"text/css\">\nthe InternationalAccording to the pe=\"text/css\" />\ncoincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;\" target=\"_blank\" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type=\"application/anguage\" content=\"<meta http-equiv=\"Privacy Policy</a>e(\"%3Cscript src='\" target=\"_blank\">On the other hand,.jpg|thumb|right|2</div><div class=\"<div style=\"float:nineteenth century</body>\r\n</html>\r\n<img src=\"http://s;text-align:centerfont-weight: bold; According to the difference between\" frameborder=\"0\" \" style=\"position:link href=\"http://html4/loose.dtd\">\nduring this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type=\"text\" <span style=\"font-onreadystatechange\t<div class=\"cleardocument.location. For example, the a wide variety of <!DOCTYPE html>\r\n<&nbsp;&nbsp;&nbsp;\"><a href=\"http://style=\"float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype=\"text/css\" />it is possible to Harvard Universitytylesheet\" href=\"/the main characterOxford University name=\"keywords\" cstyle=\"text-align:the United Kingdomfederal government<div style=\"margin depending on the description of the<div class=\"header.min.js\"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc=\"http://staticsuggested that the\" src=\"http://www.a large number of Telecommunications\" rel=\"nofollow\" tHoly Roman Emperoralmost exclusively\" border=\"0\" alt=\"Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle=\"background-<li><em><a href=\"/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src=\"http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref=\"https://www.recent developmentBoard of Directors<div class=\"search| <a href=\"http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>\r\n</div>\r\n\r\n<a href=\"index.phpwas established inmin.js\"></script>\nparticipate in thea strong influencestyle=\"margin-top:represented by thegraduated from theTraditionally, theElement(\"script\");However, since the/div>\n</div>\n<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype=\"image/x-icon/div>\n<div class=\" class=\"clearfix\"><div class=\"footer\t\t</div>\n\t\t</div>\nthe motion pictureP\u0011Q\nP;P3P0Q\u0000Q\u0001P:P8P1Q\nP;P3P0Q\u0000Q\u0001P:P8P$P5P4P5Q\u0000P0Q\u0006P8P8P=P5Q\u0001P:P>P;Q\u000CP:P>Q\u0001P>P>P1Q\tP5P=P8P5Q\u0001P>P>P1Q\tP5P=P8Q\u000FP?Q\u0000P>P3Q\u0000P0P<P<Q\u000BP\u001EQ\u0002P?Q\u0000P0P2P8Q\u0002Q\u000CP1P5Q\u0001P?P;P0Q\u0002P=P>P<P0Q\u0002P5Q\u0000P8P0P;Q\u000BP?P>P7P2P>P;Q\u000FP5Q\u0002P?P>Q\u0001P;P5P4P=P8P5Q\u0000P0P7P;P8Q\u0007P=Q\u000BQ\u0005P?Q\u0000P>P4Q\u0003P:Q\u0006P8P8P?Q\u0000P>P3Q\u0000P0P<P<P0P?P>P;P=P>Q\u0001Q\u0002Q\u000CQ\u000EP=P0Q\u0005P>P4P8Q\u0002Q\u0001Q\u000FP8P7P1Q\u0000P0P=P=P>P5P=P0Q\u0001P5P;P5P=P8Q\u000FP8P7P<P5P=P5P=P8Q\u000FP:P0Q\u0002P5P3P>Q\u0000P8P8P\u0010P;P5P:Q\u0001P0P=P4Q\u0000`$&`%\r`$5`$>`$0`$>`$.`%\u0008`$(`%\u0001`$\u0005`$2`$*`%\r`$0`$&`$>`$(`$-`$>`$0`$$`%\u0000`$/`$\u0005`$(`%\u0001`$&`%\u0007`$6`$9`$?`$(`%\r`$&`%\u0000`$\u0007`$\u0002`$!`$?`$/`$>`$&`$?`$2`%\r`$2`%\u0000`$\u0005`$'`$?`$\u0015`$>`$0`$5`%\u0000`$!`$?`$/`%\u000B`$\u001A`$?`$\u001F`%\r`$ `%\u0007`$8`$.`$>`$\u001A`$>`$0`$\u001C`$\u0002`$\u0015`%\r`$6`$(`$&`%\u0001`$(`$?`$/`$>`$*`%\r`$0`$/`%\u000B`$\u0017`$\u0005`$(`%\u0001`$8`$>`$0`$\u0011`$(`$2`$>`$\u0007`$(`$*`$>`$0`%\r`$\u001F`%\u0000`$6`$0`%\r`$$`%\u000B`$\u0002`$2`%\u000B`$\u0015`$8`$-`$>`$+`$<`%\r`$2`%\u0008`$6`$6`$0`%\r`$$`%\u0007`$\u0002`$*`%\r`$0`$&`%\u0007`$6`$*`%\r`$2`%\u0007`$/`$0`$\u0015`%\u0007`$\u0002`$&`%\r`$0`$8`%\r`$%`$?`$$`$?`$\t`$$`%\r`$*`$>`$&`$\t`$(`%\r`$9`%\u0007`$\u0002`$\u001A`$?`$\u001F`%\r`$ `$>`$/`$>`$$`%\r`$0`$>`$\u001C`%\r`$/`$>`$&`$>`$*`%\u0001`$0`$>`$(`%\u0007`$\u001C`%\u000B`$!`$<`%\u0007`$\u0002`$\u0005`$(`%\u0001`$5`$>`$&`$6`%\r`$0`%\u0007`$#`%\u0000`$6`$?`$\u0015`%\r`$7`$>`$8`$0`$\u0015`$>`$0`%\u0000`$8`$\u0002`$\u0017`%\r`$0`$9`$*`$0`$?`$#`$>`$.`$,`%\r`$0`$>`$\u0002`$!`$,`$\u001A`%\r`$\u001A`%\u000B`$\u0002`$\t`$*`$2`$,`%\r`$'`$.`$\u0002`$$`%\r`$0`%\u0000`$8`$\u0002`$*`$0`%\r`$\u0015`$\t`$.`%\r`$.`%\u0000`$&`$.`$>`$'`%\r`$/`$.`$8`$9`$>`$/`$$`$>`$6`$,`%\r`$&`%\u000B`$\u0002`$.`%\u0000`$!`$?`$/`$>`$\u0006`$\u0008`$*`%\u0000`$\u000F`$2`$.`%\u000B`$,`$>`$\u0007`$2`$8`$\u0002`$\u0016`%\r`$/`$>`$\u0006`$*`$0`%\u0007`$6`$(`$\u0005`$(`%\u0001`$,`$\u0002`$'`$,`$>`$\u001C`$<`$>`$0`$(`$5`%\u0000`$(`$$`$.`$*`%\r`$0`$.`%\u0001`$\u0016`$*`%\r`$0`$6`%\r`$(`$*`$0`$?`$5`$>`$0`$(`%\u0001`$\u0015`$8`$>`$(`$8`$.`$0`%\r`$%`$(`$\u0006`$/`%\u000B`$\u001C`$?`$$`$8`%\u000B`$.`$5`$>`$0X'Y\u0004Y\u0005X4X'X1Y\u0003X'X*X'Y\u0004Y\u0005Y\u0006X*X/Y\nX'X*X'Y\u0004Y\u0003Y\u0005X(Y\nY\u0008X*X1X'Y\u0004Y\u0005X4X'Y\u0007X/X'X*X9X/X/X'Y\u0004X2Y\u0008X'X1X9X/X/X'Y\u0004X1X/Y\u0008X/X'Y\u0004X%X3Y\u0004X'Y\u0005Y\nX)X'Y\u0004Y\u0001Y\u0008X*Y\u0008X4Y\u0008X(X'Y\u0004Y\u0005X3X'X(Y\u0002X'X*X'Y\u0004Y\u0005X9Y\u0004Y\u0008Y\u0005X'X*X'Y\u0004Y\u0005X3Y\u0004X3Y\u0004X'X*X'Y\u0004X,X1X'Y\u0001Y\nY\u0003X3X'Y\u0004X'X3Y\u0004X'Y\u0005Y\nX)X'Y\u0004X'X*X5X'Y\u0004X'X*keywords\" content=\"w3.org/1999/xhtml\"><a target=\"_blank\" text/html; charset=\" target=\"_blank\"><table cellpadding=\"autocomplete=\"off\" text-align: center;to last version by background-color: #\" href=\"http://www./div></div><div id=<a href=\"#\" class=\"\"><img src=\"http://cript\" src=\"http://\n<script language=\"//EN\" \"http://www.wencodeURIComponent(\" href=\"javascript:<div class=\"contentdocument.write('<scposition: absolute;script src=\"http:// style=\"margin-top:.min.js\"></script>\n</div>\n<div class=\"w3.org/1999/xhtml\" \n\r\n</body>\r\n</html>distinction between/\" target=\"_blank\"><link href=\"http://encoding=\"utf-8\"?>\nw.addEventListener?action=\"http://www.icon\" href=\"http:// style=\"background:type=\"text/css\" />\nmeta property=\"og:t<input type=\"text\" style=\"text-align:the development of tylesheet\" type=\"tehtml; charset=utf-8is considered to betable width=\"100%\" In addition to the contributed to the differences betweendevelopment of the It is important to </script>\n\n<script style=\"font-size:1></span><span id=gbLibrary of Congress<img src=\"http://imEnglish translationAcademy of Sciencesdiv style=\"display:construction of the.getElementById(id)in conjunction withElement('script'); <meta property=\"og:P\u0011Q\nP;P3P0Q\u0000Q\u0001P:P8\n type=\"text\" name=\">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src=\"http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style=\"background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet\" href=\"/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland\n</script>\n<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv=\"X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0\" cellpadding=\"0\" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E\"));<a href=\"http://www.<li><a href=\"http://site_name\" content=\"text-decoration:nonestyle=\"display: none<meta http-equiv=\"X-new Date().getTime() type=\"image/x-icon\"</span><span class=\"language=\"javascriptwindow.location.href<a href=\"javascript:-->\r\n<script type=\"t<a href='http://www.hortcut icon\" href=\"</div>\r\n<div class=\"<script src=\"http://\" rel=\"stylesheet\" t</div>\n<script type=/a> <a href=\"http:// allowTransparency=\"X-UA-Compatible\" conrelationship between\n</script>\r\n<script </a></li></ul></div>associated with the programming language</a><a href=\"http://</a></li><li class=\"form action=\"http://<div style=\"display:type=\"text\" name=\"q\"<table width=\"100%\" background-position:\" border=\"0\" width=\"rel=\"shortcut icon\" h6><ul><li><a href=\" <meta http-equiv=\"css\" media=\"screen\" responsible for the \" type=\"application/\" style=\"background-html; charset=utf-8\" allowtransparency=\"stylesheet\" type=\"te\r\n<meta http-equiv=\"></span><span class=\"0\" cellspacing=\"0\">;\n</script>\n<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type=\"hidden\" name=\"javascript:void(0);\"effectiveness of the autocomplete=\"off\" generally considered><input type=\"text\" \"></script>\r\n<scriptthroughout the worldcommon misconceptionassociation with the</div>\n</div>\n<div cduring his lifetime,corresponding to thetype=\"image/x-icon\" an increasing numberdiplomatic relationsare often consideredmeta charset=\"utf-8\" <input type=\"text\" examples include the\"><img src=\"http://iparticipation in thethe establishment of\n</div>\n<div class=\"&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset=\"utf-8\"> type=\"text/css\" />\ninterchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type=\"text/csstype=\"submit\" name=\"families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportuguC*s (Europeu)P#P:Q\u0000P0Q\u0017P=Q\u0001Q\u000CP:P0Q\u0003P:Q\u0000P0Q\u0017P=Q\u0001Q\u000CP:P0P P>Q\u0001Q\u0001P8P9Q\u0001P:P>P9P<P0Q\u0002P5Q\u0000P8P0P;P>P2P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8P8Q\u0003P?Q\u0000P0P2P;P5P=P8Q\u000FP=P5P>P1Q\u0005P>P4P8P<P>P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000FP\u0018P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000FP P5Q\u0001P?Q\u0003P1P;P8P:P8P:P>P;P8Q\u0007P5Q\u0001Q\u0002P2P>P8P=Q\u0004P>Q\u0000P<P0Q\u0006P8Q\u000EQ\u0002P5Q\u0000Q\u0000P8Q\u0002P>Q\u0000P8P8P4P>Q\u0001Q\u0002P0Q\u0002P>Q\u0007P=P>X'Y\u0004Y\u0005X*Y\u0008X'X,X/Y\u0008Y\u0006X'Y\u0004X'X4X*X1X'Y\u0003X'X*X'Y\u0004X'Y\u0002X*X1X'X-X'X*html; charset=UTF-8\" setTimeout(function()display:inline-block;<input type=\"submit\" type = 'text/javascri<img src=\"http://www.\" \"http://www.w3.org/shortcut icon\" href=\"\" autocomplete=\"off\" </a></div><div class=</a></li>\n<li class=\"css\" type=\"text/css\" <form action=\"http://xt/css\" href=\"http://link rel=\"alternate\" \r\n<script type=\"text/ onclick=\"javascript:(new Date).getTime()}height=\"1\" width=\"1\" People's Republic of <a href=\"http://www.text-decoration:underthe beginning of the </div>\n</div>\n</div>\nestablishment of the </div></div></div></d#viewport{min-height:\n<script src=\"http://option><option value=often referred to as /option>\n<option valu<!DOCTYPE html>\n<!--[International Airport>\n<a href=\"http://www</a><a href=\"http://w`8 `82`8)`82`9\u0004`8\u0017`8\"a\u0003%a\u0003\u0010a\u0003 a\u0003\u0017a\u0003#a\u0003\u001Aa\u0003\u0018f-#i+\u0014d8-f\u0016\u0007 (g9\u0001i+\u0014)`$(`$?`$0`%\r`$&`%\u0007`$6`$!`$>`$\t`$(`$2`%\u000B`$!`$\u0015`%\r`$7`%\u0007`$$`%\r`$0`$\u001C`$>`$(`$\u0015`$>`$0`%\u0000`$8`$\u0002`$,`$\u0002`$'`$?`$$`$8`%\r`$%`$>`$*`$(`$>`$8`%\r`$5`%\u0000`$\u0015`$>`$0`$8`$\u0002`$8`%\r`$\u0015`$0`$#`$8`$>`$.`$\u0017`%\r`$0`%\u0000`$\u001A`$?`$\u001F`%\r`$ `%\u000B`$\u0002`$5`$?`$\u001C`%\r`$\u001E`$>`$(`$\u0005`$.`%\u0007`$0`$?`$\u0015`$>`$5`$?`$-`$?`$(`%\r`$(`$\u0017`$>`$!`$?`$/`$>`$\u0001`$\u0015`%\r`$/`%\u000B`$\u0002`$\u0015`$?`$8`%\u0001`$0`$\u0015`%\r`$7`$>`$*`$9`%\u0001`$\u0001`$\u001A`$$`%\u0000`$*`%\r`$0`$,`$\u0002`$'`$(`$\u001F`$?`$*`%\r`$*`$#`%\u0000`$\u0015`%\r`$0`$?`$\u0015`%\u0007`$\u001F`$*`%\r`$0`$>`$0`$\u0002`$-`$*`%\r`$0`$>`$*`%\r`$$`$.`$>`$2`$?`$\u0015`%\u000B`$\u0002`$0`$+`$<`%\r`$$`$>`$0`$(`$?`$0`%\r`$.`$>`$#`$2`$?`$.`$?`$\u001F`%\u0007`$!description\" content=\"document.location.prot.getElementsByTagName(<!DOCTYPE html>\n<html <meta charset=\"utf-8\">:url\" content=\"http://.css\" rel=\"stylesheet\"style type=\"text/css\">type=\"text/css\" href=\"w3.org/1999/xhtml\" xmltype=\"text/javascript\" method=\"get\" action=\"link rel=\"stylesheet\" = document.getElementtype=\"image/x-icon\" />cellpadding=\"0\" cellsp.css\" type=\"text/css\" </a></li><li><a href=\"\" width=\"1\" height=\"1\"\"><a href=\"http://www.style=\"display:none;\">alternate\" type=\"appli-//W3C//DTD XHTML 1.0 ellspacing=\"0\" cellpad type=\"hidden\" value=\"/a>&nbsp;<span role=\"s\n<input type=\"hidden\" language=\"JavaScript\" document.getElementsBg=\"0\" cellspacing=\"0\" ype=\"text/css\" media=\"type='text/javascript'with the exception of ype=\"text/css\" rel=\"st height=\"1\" width=\"1\" ='+encodeURIComponent(<link rel=\"alternate\" \nbody, tr, input, textmeta name=\"robots\" conmethod=\"post\" action=\">\n<a href=\"http://www.css\" rel=\"stylesheet\" </div></div><div classlanguage=\"javascript\">aria-hidden=\"true\">B7<ript\" type=\"text/javasl=0;})();\n(function(){background-image: url(/a></li><li><a href=\"h\t\t<li><a href=\"http://ator\" aria-hidden=\"tru> <a href=\"http://www.language=\"javascript\" /option>\n<option value/div></div><div class=rator\" aria-hidden=\"tre=(new Date).getTime()portuguC*s (do Brasil)P>Q\u0000P3P0P=P8P7P0Q\u0006P8P8P2P>P7P<P>P6P=P>Q\u0001Q\u0002Q\u000CP>P1Q\u0000P0P7P>P2P0P=P8Q\u000FQ\u0000P5P3P8Q\u0001Q\u0002Q\u0000P0Q\u0006P8P8P2P>P7P<P>P6P=P>Q\u0001Q\u0002P8P>P1Q\u000FP7P0Q\u0002P5P;Q\u000CP=P0<!DOCTYPE html PUBLIC \"nt-Type\" content=\"text/<meta http-equiv=\"Conteransitional//EN\" \"http:<html xmlns=\"http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = 'text/javascript';<meta name=\"descriptionparentNode.insertBefore<input type=\"hidden\" najs\" type=\"text/javascri(document).ready(functiscript type=\"text/javasimage\" content=\"http://UA-Compatible\" content=tml; charset=utf-8\" />\nlink rel=\"shortcut icon<link rel=\"stylesheet\" </script>\n<script type== document.createElemen<a target=\"_blank\" href= document.getElementsBinput type=\"text\" name=a.type = 'text/javascrinput type=\"hidden\" namehtml; charset=utf-8\" />dtd\">\n<html xmlns=\"http-//W3C//DTD HTML 4.01 TentsByTagName('script')input type=\"hidden\" nam<script type=\"text/javas\" style=\"display:none;\">document.getElementById(=document.createElement(' type='text/javascript'input type=\"text\" name=\"d.getElementsByTagName(snical\" href=\"http://www.C//DTD HTML 4.01 Transit<style type=\"text/css\">\n\n<style type=\"text/css\">ional.dtd\">\n<html xmlns=http-equiv=\"Content-Typeding=\"0\" cellspacing=\"0\"html; charset=utf-8\" />\n style=\"display:none;\"><<li><a href=\"http://www. type='text/javascript'>P4P5Q\u000FQ\u0002P5P;Q\u000CP=P>Q\u0001Q\u0002P8Q\u0001P>P>Q\u0002P2P5Q\u0002Q\u0001Q\u0002P2P8P8P?Q\u0000P>P8P7P2P>P4Q\u0001Q\u0002P2P0P1P5P7P>P?P0Q\u0001P=P>Q\u0001Q\u0002P8`$*`%\u0001`$8`%\r`$$`$?`$\u0015`$>`$\u0015`$>`$\u0002`$\u0017`%\r`$0`%\u0007`$8`$\t`$(`%\r`$9`%\u000B`$\u0002`$(`%\u0007`$5`$?`$'`$>`$(`$8`$-`$>`$+`$?`$\u0015`%\r`$8`$?`$\u0002`$\u0017`$8`%\u0001`$0`$\u0015`%\r`$7`$?`$$`$\u0015`%\t`$*`%\u0000`$0`$>`$\u0007`$\u001F`$5`$?`$\u001C`%\r`$\u001E`$>`$*`$(`$\u0015`$>`$0`%\r`$0`$5`$>`$\u0008`$8`$\u0015`%\r`$0`$?`$/`$$`$>", "\u06F7%\u018C'T%\u0085'W%\u00D7%O%g%\u00A6&\u0193%\u01E5&>&*&'&^&\u0088\u0178\u0C3E&\u01AD&\u0192&)&^&%&'&\u0082&P&1&\u00B1&3&]&m&u&E&t&C&\u00CF&V&V&/&>&6&\u0F76\u177Co&p&@&E&M&P&x&@&F&e&\u00CC&7&:&(&D&0&C&)&.&F&-&1&(&L&F&1\u025E*\u03EA\u21F3&\u1372&K&;&)&E&H&P&0&?&9&V&\u0081&-&v&a&,&E&)&?&=&'&'&B&\u0D2E&\u0503&\u0316*&*8&%&%&&&%,)&\u009A&>&\u0086&7&]&F&2&>&J&6&n&2&%&?&\u008E&2&6&J&g&-&0&,&*&J&*&O&)&6&(&<&B&N&.&P&@&2&.&W&M&%\u053C\u0084(,(<&,&\u03DA&\u18C7&-&,(%&(&%&(\u013B0&X&D&\u0081&j&'&J&(&.&B&3&Z&R&h&3&E&E&<\u00C6-\u0360\u1EF3&%8?&@&,&Z&@&0&J&,&^&x&_&6&C&6&C\u072C\u2A25&f&-&-&-&-&,&J&2&8&z&8&C&Y&8&-&d&\u1E78\u00CC-&7&1&F&7&t&W&7&I&.&.&^&=\u0F9C\u19D3&8(>&/&/&\u077B')'\u1065')'%@/&0&%\u043E\u09C0*&*@&C\u053D\u05D4\u0274\u05EB4\u0DD7\u071A\u04D16\u0D84&/\u0178\u0303Z&*%\u0246\u03FF&\u0134&1\u00A8\u04B4\u0174");
+ flipBuffer(dictionary);
+ DICTIONARY_DATA = dictionary;
+ }
+
+
+ /**
+ * @param {!number} a
+ * @param {!number} b
+ * @return {!number}
+ */
+ function min(a, b) {
+ return a <= b ? a : b;
+ }
+
+ /**
+ * @param {!InputStream|null} src
+ * @param {!Int8Array} dst
+ * @param {!number} offset
+ * @param {!number} length
+ * @return {!number}
+ */
+ function readInput(src, dst, offset, length) {
+ if (src == null) return -1;
+ var /** number */ end = min(src.offset + length, src.data.length);
+ var /** number */ bytesRead = end - src.offset;
+ dst.set(src.data.subarray(src.offset, end), offset);
+ src.offset += bytesRead;
+ return bytesRead;
+ }
+
+ /**
+ * @param {!InputStream} src
+ * @return {!number}
+ */
+ function closeInput(src) { return 0; }
+
+ /**
+ * @param {!Int8Array} buffer
+ * @return {void}
+ */
+ function flipBuffer(buffer) { /* no-op */ }
+
+ /**
+ * @param {!string} src
+ * @return {!Int8Array}
+ */
+ function toUsAsciiBytes(src) {
+ var /** !number */ n = src.length;
+ var /** !Int8Array */ result = new Int8Array(n);
+ for (var /** !number */ i = 0; i < n; ++i) {
+ result[i] = src.charCodeAt(i);
+ }
+ return result;
+ }
+
+ /**
+ * @param {!Int8Array} bytes
+ * @return {!Int8Array}
+ */
+ function decode(bytes) {
+ var /** !State */ s = new State();
+ initState(s, new InputStream(bytes));
+ var /** !number */ totalOutput = 0;
+ var /** !Array<!Int8Array> */ chunks = [];
+ while (true) {
+ var /** !Int8Array */ chunk = new Int8Array(16384);
+ chunks.push(chunk);
+ s.output = chunk;
+ s.outputOffset = 0;
+ s.outputLength = 16384;
+ s.outputUsed = 0;
+ decompress(s);
+ totalOutput += s.outputUsed;
+ if (s.outputUsed < 16384) break;
+ }
+ close(s);
+ var /** !Int8Array */ result = new Int8Array(totalOutput);
+ var /** !number */ offset = 0;
+ for (var /** !number */ i = 0; i < chunks.length; ++i) {
+ var /** !Int8Array */ chunk = chunks[i];
+ var /** !number */ end = min(totalOutput, offset + 16384);
+ var /** !number */ len = end - offset;
+ if (len < 16384) {
+ result.set(chunk.subarray(0, len), offset);
+ } else {
+ result.set(chunk, offset);
+ }
+ offset += len;
+ }
+ return result;
+ }
+
+ return decode;
+}
+
+/** @export */
+var BrotliDecode = BrotliDecodeClosure();
+
+window["BrotliDecode"] = BrotliDecode;
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.min.js b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.min.js
new file mode 100755
index 000000000..5fee00121
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode.min.js
@@ -0,0 +1,2 @@
+function BrotliDecodeClosure(){"use strict";function e(e){this.a=e,this.b=0}function t(e){for(var t=-1,i=16;i>0;)e>>>i!=0&&(t+=i,e>>>=i),i>>=1;return t+e}function i(e,t,i){return 16+t+2*(i<<e)}function n(e,i,n){if(e<n+(2<<i))throw"maxDistance is too small";var a=(e-n>>i)+4,o=t(a)-1,r=o-1<<1|a>>o&1;return(r-1<<i)+(1<<i)+n+16}function a(e){var t=new Int16Array(24),i=new Int16Array(24);i[0]=2;for(var n=0;n<23;++n)t[n+1]=t[n]+(1<<Pe[n]),i[n+1]=i[n]+(1<<$e[n]);for(var a=0;a<704;++a){var o=a>>>6,r=-4;o>=2&&(o-=2,r=0);var s=(170064>>>2*o&3)<<3|a>>>3&7,l=(156228>>>2*o&3)<<3|7&a,c=i[l],d=r+(c>4?3:c-2),h=4*a;e[h+0]=Pe[s]|$e[l]<<8,e[h+1]=t[s],e[h+2]=i[l],e[h+3]=d}}function o(e){var t=e.c;if(e.c=0,e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),0==H(e,1))return 16;var i=H(e,3);return 0!=i?17+i:(i=H(e,3),0!=i?1==i?0==t?-1:(e.c=1,1==H(e,1)?-1:(i=H(e,6),i<10||i>30?-1:i)):8+i:17)}function r(e,t){if(0!=e.h)throw"State MUST be uninitialized";e.j=new Int32Array(3091),e.j[0]=7,e.k=3;var i=n(2147483644,3,120);e.l=new Int8Array(i),e.m=new Int32Array(i),e.input=t,U(e),e.h=1}function s(e){if(0==e.h)throw"State MUST be initialized";11!=e.h&&(e.h=11,null!=e.input&&(ne(e.input),e.input=null))}function l(e){if(e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),0!=H(e,1)){var t=H(e,3);return 0==t?1:H(e,t)+(1<<t)}return 0}function c(e){if(e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),e.n=H(e,1),e.o=0,e.p=0,e.q=0,0==e.n||0==H(e,1)){var t=H(e,2)+4;if(7==t){if(e.q=1,0!=H(e,1))throw"Corrupted reserved bit";var i=H(e,2);if(0==i)return;for(var n=0;n<i;n++){e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var a=H(e,8);if(0==a&&n+1==i&&i>1)throw"Exuberant nibble";e.o|=a<<8*n}}else for(var n=0;n<t;n++){e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var a=H(e,4);if(0==a&&n+1==t&&t>4)throw"Exuberant nibble";e.o|=a<<4*n}e.o++,0==e.n&&(e.p=H(e,1))}}function d(e,t,i){var n=e[t],a=i.e>>>i.d;n+=255&a;var o=e[n]>>16,r=65535&e[n];if(o<=8)return i.d+=o,r;n+=r;var s=(1<<o)-1;return n+=(a&s)>>>8,i.d+=(e[n]>>16)+8,65535&e[n]}function h(e,t,i){i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16);var n=d(e,t,i),a=ge[n];return i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16),me[n]+(a<=16?H(i,a):R(i,a))}function f(e,t){for(var i=e[t];t>0;t--)e[t]=e[t-1];e[0]=i}function p(e,t){for(var i=new Int32Array(256),n=0;n<256;n++)i[n]=n;for(var n=0;n<t;n++){var a=255&e[n];e[n]=i[a],0!=a&&f(i,a)}}function u(e,t,i,n){var a=0,o=8,r=0,s=0,l=32768,c=new Int32Array(33),d=c.length-1;for(W(c,d,5,e,18);a<t&&l>0;){n.g>2030&&B(n),n.d>=16&&(n.e=n.f[n.g++]<<16|n.e>>>16,n.d-=16);var h=n.e>>>n.d&31;n.d+=c[h]>>16;var f=65535&c[h];if(f<16)r=0,i[a++]=f,0!=f&&(o=f,l-=32768>>f);else{var p=f-14,u=0;16==f&&(u=o),s!=u&&(r=0,s=u);var m=r;r>0&&(r-=2,r<<=p),n.d>=16&&(n.e=n.f[n.g++]<<16|n.e>>>16,n.d-=16),r+=H(n,p)+3;var g=r-m;if(a+g>t)throw"symbol + repeatDelta > numSymbols";for(var P=0;P<g;P++)i[a++]=s;0!=s&&(l-=g<<15-s)}}if(0!=l)throw"Unused space";i.fill(0,a,t)}function m(e,t){for(var i=0;i<t-1;++i)for(var n=i+1;n<t;++n)if(e[i]==e[n])throw"Duplicate simple Huffman code symbol"}function g(e,i,n,a,o){for(var r=new Int32Array(i),s=new Int32Array(4),l=1+t(e-1),c=H(o,2)+1,d=0;d<c;d++){o.d>=16&&(o.e=o.f[o.g++]<<16|o.e>>>16,o.d-=16);var h=H(o,l);if(h>=i)throw"Can't readHuffmanCode";s[d]=h}m(s,c);var f=c;switch(4==c&&(f+=H(o,1)),f){case 1:r[s[0]]=1;break;case 2:r[s[0]]=1,r[s[1]]=1;break;case 3:r[s[0]]=1,r[s[1]]=2,r[s[2]]=2;break;case 4:r[s[0]]=2,r[s[1]]=2,r[s[2]]=2,r[s[3]]=2;break;case 5:r[s[0]]=1,r[s[1]]=2,r[s[2]]=3,r[s[3]]=3}return W(n,a,8,r,i)}function P(e,t,i,n,a){for(var o=new Int32Array(e),r=new Int32Array(18),s=32,l=0,c=t;c<18&&s>0;c++){var d=ce[c];a.d>=16&&(a.e=a.f[a.g++]<<16|a.e>>>16,a.d-=16);var h=a.e>>>a.d&15;a.d+=fe[h]>>16;var f=65535&fe[h];r[d]=f,0!=f&&(s-=32>>f,l++)}if(0!=s&&1!=l)throw"Corrupted Huffman code histogram";return u(r,e,o,a),W(i,n,8,o,e)}function $(e,t,i,n,a){a.g>2030&&B(a),a.d>=16&&(a.e=a.f[a.g++]<<16|a.e>>>16,a.d-=16);var o=H(a,2);return 1==o?g(e,t,i,n,a):P(t,o,i,n,a)}function b(e,t,i){i.g>2030&&B(i);var n=l(i)+1;if(1==n)return t.fill(0,0,e),n;i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16);var a=H(i,1),o=0;0!=a&&(o=H(i,4)+1);var r=n+o,s=le[r+31>>5],c=new Int32Array(s+1),h=c.length-1;$(r,r,c,h,i);for(var f=0;f<e;){i.g>2030&&B(i),i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16);var u=d(c,h,i);if(0==u)t[f]=0,f++;else if(u<=o){i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16);for(var m=(1<<u)+H(i,u);0!=m;){if(f>=e)throw"Corrupted context map";t[f]=0,f++,m--}}else t[f]=u-o,f++}return i.d>=16&&(i.e=i.f[i.g++]<<16|i.e>>>16,i.d-=16),1==H(i,1)&&p(t,e),n}function v(e,t,i){var n=e.r,a=4+2*t;e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var o=d(e.j,2*t,e),r=h(e.j,2*t+1,e);return 1==o?o=n[a+1]+1:0==o?o=n[a]:o-=2,o>=i&&(o-=i),n[a]=n[a+1],n[a+1]=o,r}function y(e){e.s=v(e,0,e.t);var t=e.r[5];e.u=t<<6,e.v=255&e.w[e.u];var i=e.x[t];e.y=i<<9,e.z=e.y+256}function X(e){e.A=v(e,1,e.B),e.C=e.r[7]}function w(e){e.D=v(e,2,e.F),e.G=e.r[9]<<2}function Y(e){var t=e.H;if(t>e.I){for(var i=e.I;t>>1>i;)t>>=1;0==e.n&&t<16384&&e.H>=16384&&(t=16384)}if(!(t<=e.J)){var n=t+37,a=new Int8Array(n);0!=e.K.length&&a.L(e.K.M(0,0+e.J),0),e.K=a,e.J=t}}function Q(e){return 0!=e.n?(e.N=10,void(e.h=12)):(e.O=new Int32Array(0),e.P=new Int32Array(0),e.Q=new Int32Array(0),e.g>2030&&B(e),c(e),void(0==e.o&&0==e.q||(0!=e.p||0!=e.q?(J(e),e.h=0!=e.q?5:6):e.h=3,0==e.q&&(e.I+=e.o,e.I>1<<30&&(e.I=1<<30),e.J<e.H&&Y(e)))))}function k(e,t,i){var n=e.j[2*t];if(i<=1)return e.j[2*t+1]=n,e.j[2*t+2]=n,1<<28;var a=i+2;n+=$(a,a,e.j,2*t,e),e.j[2*t+1]=n;var o=26;return n+=$(o,o,e.j,2*t+1,e),e.j[2*t+2]=n,h(e.j,2*t+1,e)}function x(e,t){for(var i=e.l,n=e.m,a=e.R,o=e.S,r=1<<a,s=1,l=0,c=16,d=0;d<o;++d)i[c]=0,n[c]=d+1,++c;for(;c<t;){for(var h=o+((2+l<<s)-4<<a)+1,d=0;d<r;++d)i[c]=s,n[c]=h+d,++c;s+=l,l^=1}}function C(e){e.t=l(e)+1,e.s=k(e,0,e.t),e.B=l(e)+1,e.A=k(e,1,e.B),e.F=l(e)+1,e.D=k(e,2,e.F),e.g>2030&&B(e),e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),e.R=H(e,2),e.S=H(e,4)<<e.R,e.T=(1<<e.R)-1,e.x=new Int8Array(e.t);for(var t=0;t<e.t;){for(var a=te(t+96,e.t);t<a;++t)e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),e.x[t]=H(e,2);e.g>2030&&B(e)}e.w=new Int8Array(e.t<<6);var o=b(e.t<<6,e.w,e);e.U=1;for(var r=0;r<e.t<<6;r++)if(e.w[r]!=r>>6){e.U=0;break}e.V=new Int8Array(e.F<<2);var s=b(e.F<<2,e.V,e);e.O=I(256,256,o,e),e.P=I(704,704,e.B,e);var c=i(e.R,e.S,24),d=c;1==e.c&&(c=i(e.R,e.S,62),d=n(2147483644,e.R,e.S)),e.Q=I(c,d,s,e),x(e,d),e.u=0,e.G=0,e.y=512*e.x[0],e.z=e.y+256,e.v=0,e.C=0,e.r[4]=1,e.r[5]=0,e.r[6]=1,e.r[7]=0,e.r[8]=1,e.r[9]=0}function j(e){var t=e.K;if(e.o<=0)return L(e),void(e.h=2);var i=te(e.J-e.W,e.o);return G(e,t,e.W,i),e.o-=i,e.W+=i,e.W==e.J?(e.N=6,void(e.h=12)):(L(e),void(e.h=2))}function A(e){var t=te(e.X-e.Y,e.Z-e.$);return 0!=t&&(e._.L(e.K.M(e.$,e.$+t),e.aa+e.Y),e.Y+=t,e.$+=t),e.Y<e.X?1:0}function I(e,t,i,n){for(var a=le[t+31>>5],o=new Int32Array(i+i*a),r=i,s=0;s<i;++s)o[s]=r,r+=$(e,t,o,s,n);return o}function q(e){var t=e.J;return 0!=e.i&&(t=te(t,e.$+e.X-e.Y)),t}function T(e){if(0==e.h)throw"Can't decompress until initialized";if(11==e.h)throw"Can't decompress after close";if(1==e.h){var t=o(e);if(t==-1)throw"Invalid 'windowBits' code";e.H=1<<t,e.ba=e.H-16,e.h=2}for(var i=q(e),n=e.J-1,a=e.K;10!=e.h;)switch(e.h){case 2:if(e.o<0)throw"Invalid metablock length";Q(e),i=q(e),n=e.J-1,a=e.K;continue;case 3:C(e),e.h=4;case 4:if(e.o<=0){e.h=2;continue}e.g>2030&&B(e),0==e.A&&X(e),e.A--,e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var r=d(e.P,e.C,e)<<2,s=be[r],l=be[r+1],c=be[r+2];e.ca=be[r+3],e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var h=255&s;e.da=l+(h<=16?H(e,h):R(e,h)),e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var h=s>>8;e.ea=c+(h<=16?H(e,h):R(e,h)),e.fa=0,e.h=7;case 7:if(0!=e.U){for(;e.fa<e.da;)if(e.g>2030&&B(e),0==e.s&&y(e),e.s--,e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),a[e.W]=d(e.O,e.v,e),e.W++,e.fa++,e.W>=i){e.N=7,e.h=12;break}}else for(var f=255&a[e.W-1&n],p=255&a[e.W-2&n];e.fa<e.da;){e.g>2030&&B(e),0==e.s&&y(e);var u=ye[e.y+f]|ye[e.z+p],m=255&e.w[e.u+u];if(e.s--,p=f,e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),f=d(e.O,m,e),a[e.W]=f,e.W++,e.fa++,e.W>=i){e.N=7,e.h=12;break}}if(7!=e.h)continue;if(e.o-=e.da,e.o<=0){e.h=4;continue}var g=e.ca;if(g<0)e.ga=e.r[e.k];else{e.g>2030&&B(e),0==e.D&&w(e),e.D--,e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);var P=255&e.V[e.G+g];if(g=d(e.Q,P,e),g<16){var $=e.k+de[g]&3;if(e.ga=e.r[$]+he[g],e.ga<0)throw"Negative distance"}else{var b,h=e.l[g];e.d+h<=32?b=H(e,h):(e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),b=h<=16?H(e,h):R(e,h)),e.ga=e.m[g]+(b<<e.R)}}if(e.ha!=e.ba&&e.W<e.ba?e.ha=e.W:e.ha=e.ba,e.ga>e.ha){e.h=9;continue}if(g>0&&(e.k=e.k+1&3,e.r[e.k]=e.ga),e.ea>e.o)throw"Invalid backward reference";e.fa=0,e.h=8;case 8:var v=e.W-e.ga&n,Y=e.W,k=e.ea-e.fa,x=v+k,I=Y+k;if(x<n&&I<n){if(k<12||x>Y&&I>v)for(var T=0;T<k;T+=4)a[Y++]=a[v++],a[Y++]=a[v++],a[Y++]=a[v++],a[Y++]=a[v++];else a.copyWithin(Y,v,x);e.fa+=k,e.o-=k,e.W+=k}else for(;e.fa<e.ea;)if(a[e.W]=a[e.W-e.ga&n],e.o--,e.W++,e.fa++,e.W>=i){e.N=8,e.h=12;break}8==e.h&&(e.h=4);continue;case 9:if(e.ga>2147483644)throw"Invalid backward reference";if(!(e.ea>=4&&e.ea<=24))throw"Invalid backward reference";var S=pe[e.ea],E=e.ga-e.ha-1,D=ue[e.ea],N=(1<<D)-1,F=E&N,W=E>>>D;if(S+=F*e.ea,!(W<121))throw"Invalid backward reference";var U=z(a,e.W,se,S,e.ea,ve,W);if(e.W+=U,e.o-=U,e.W>=i){e.N=4,e.h=12;continue}e.h=4;continue;case 5:for(;e.o>0;)e.g>2030&&B(e),e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16),H(e,8),e.o--;e.h=2;continue;case 6:j(e);continue;case 12:e.Z=te(e.W,e.J),e.h=13;case 13:if(0==A(e))return;e.W>=e.ba&&(e.ha=e.ba),e.W>=e.J&&(e.W>e.J&&a.copyWithin(0,e.J,e.W),e.W&=n,e.$=0),e.h=e.N;continue;default:throw"Unexpected state "+e.h}if(10==e.h){if(e.o<0)throw"Invalid metablock length";J(e),M(e,1)}}function S(e,t,i){this.ia=0,this.ja=new Int32Array(0),this.ka=new Int8Array(0),this.la=new Int32Array(0),this.ma=new Int16Array(0),this.ia=e,this.ja=new Int32Array(3*e),this.ma=new Int16Array(e),this.ka=new Int8Array(t),this.la=new Int32Array(i+1)}function E(e,t,i,n,a){for(var o=n.length,r=1,s=0,l=0;l<o;++l){var c=n.charCodeAt(l);35==c?t[r++]=s:e[s++]=c}for(var l=0;l<363;++l)i[l]=a.charCodeAt(l)-32}function z(e,t,i,n,a,o,r){var s=t,l=o.ja,c=o.ka,d=o.la,h=3*r,f=l[h],p=l[h+1],u=l[h+2],m=d[f],g=d[f+1],P=d[u],$=d[u+1],b=p-11,v=p-0;for((b<1||b>9)&&(b=0),(v<1||v>9)&&(v=0);m!=g;)e[s++]=c[m++];b>a&&(b=a),n+=b,a-=b,a-=v;for(var y=a;y>0;)e[s++]=i[n++],y--;if(10==p||11==p){var X=s-a;for(10==p&&(a=1);a>0;){var w=255&e[X];w<192?(w>=97&&w<=122&&(e[X]^=32),X+=1,a-=1):w<224?(e[X+1]^=32,X+=2,a-=2):(e[X+2]^=5,X+=3,a-=3)}}else if(21==p||22==p)for(var Y=s-a,Q=o.ma[r],k=(32767&Q)+(16777216-(32768&Q));a>0;){var x=1,w=255&e[Y];if(w<128)k+=w,e[Y]=127&k;else if(w<192);else if(w<224)if(a>=2){var C=e[Y+1];k+=63&C|(31&w)<<6,e[Y]=192|k>>6&31,e[Y+1]=192&C|63&k,x=2}else x=a;else if(w<240)if(a>=3){var C=e[Y+1],j=e[Y+2];k+=63&j|(63&C)<<6|(15&w)<<12,e[Y]=224|k>>12&15,e[Y+1]=192&C|k>>6&63,e[Y+2]=192&j|63&k,x=3}else x=a;else if(w<248)if(a>=4){var C=e[Y+1],j=e[Y+2],A=e[Y+3];k+=63&A|(63&j)<<6|(63&C)<<12|(7&w)<<18,e[Y]=240|k>>18&7,e[Y+1]=192&C|k>>12&63,e[Y+2]=192&j|k>>6&63,e[Y+3]=192&A|63&k,x=4}else x=a;Y+=x,a-=x,21==p&&(a=0)}for(;P!=$;)e[s++]=c[P++];return s-t}function D(e,t){for(var i=1<<t-1;0!=(e&i);)i>>=1;return(e&i-1)+i}function N(e,t,i,n,a){do n-=i,e[t+n]=a;while(n>0)}function F(e,t,i){for(var n=1<<t-i;t<15&&(n-=e[t],!(n<=0));)t++,n<<=1;return t-i}function W(e,t,i,n,a){var o,r,s=e[t],l=new Int32Array(a),c=new Int32Array(16),d=new Int32Array(16);for(r=0;r<a;r++)c[n[r]]++;d[1]=0;for(var h=1;h<15;h++)d[h+1]=d[h]+c[h];for(r=0;r<a;r++)0!=n[r]&&(l[d[n[r]]++]=r);var f=i,p=1<<f,u=p;if(1==d[15]){for(o=0;o<u;o++)e[s+o]=l[0];return u}o=0,r=0;for(var h=1,m=2;h<=i;h++,m<<=1)for(;c[h]>0;c[h]--)N(e,s+o,m,p,h<<16|l[r++]),o=D(o,h);for(var g=u-1,P=-1,$=s,h=i+1,m=2;h<=15;h++,m<<=1)for(;c[h]>0;c[h]--)(o&g)!=P&&($+=p,f=F(c,h,i),p=1<<f,u+=p,P=o&g,e[s+P]=f+i<<16|$-s-P),N(e,$+(o>>i),m,p,h-i<<16|l[r++]),o=D(o,h);return u}function B(e){if(0!=e.na){if(_(e)>=-2)return;throw"No more input"}var t=e.g<<1,i=4096-t;for(e.oa.copyWithin(0,t,4096),e.g=0;i<4096;){var n=4096-i,a=ie(e.input,e.oa,i,n);if(a<=0){e.na=1,e.pa=i,i+=1;break}i+=a}K(e,i)}function M(e,t){if(0!=e.na){var i=(e.g<<1)+(e.d+7>>3)-4;if(i>e.pa)throw"Read after end";if(0!=t&&i!=e.pa)throw"Unused bytes after end"}}function H(e,t){var i=e.e>>>e.d&(1<<t)-1;return e.d+=t,i}function R(e,t){var i=H(e,16);return e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16,i|H(e,t-16)<<16}function U(e){e.oa=new Int8Array(4160),e.e=0,e.f=new Int16Array(2080),e.d=32,e.g=2048,e.na=0,O(e)}function O(e){e.g>2030&&B(e),M(e,0),e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16,e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16}function L(e){32==e.d&&O(e)}function J(e){var t=32-e.d&7;if(0!=t){var i=H(e,t);if(0!=i)throw"Corrupted padding bits"}}function _(e){var t=2048;return 0!=e.na&&(t=e.pa+1>>1),t-e.g}function G(e,t,i,n){if(0!=(7&e.d))throw"Unaligned copyBytes";for(;32!=e.d&&0!=n;)t[i++]=e.e>>>e.d,e.d+=8,n--;if(0!=n){var a=te(_(e),n>>1);if(a>0){var o=e.g<<1,r=a<<1;t.L(e.oa.M(o,o+r),i),i+=r,n-=r,e.g+=a}if(0!=n){if(_(e)>0){for(e.d>=16&&(e.e=e.f[e.g++]<<16|e.e>>>16,e.d-=16);0!=n;)t[i++]=e.e>>>e.d,e.d+=8,n--;return void M(e,0)}for(;n>0;){var s=ie(e.input,t,i,n);if(s==-1)throw"Unexpected end of input";i+=s,n-=s}}}}function K(e,t){for(var i=e.oa,n=t>>1,a=e.f,o=0;o<n;++o)a[o]=255&i[2*o]|(255&i[2*o+1])<<8}function V(e,t,i){for(var n=0;n<256;++n)e[n]=63&n,e[512+n]=n>>2,e[1792+n]=2+(n>>6);for(var n=0;n<128;++n)e[1024+n]=4*(t.charCodeAt(n)-32);for(var n=0;n<64;++n)e[1152+n]=1&n,e[1216+n]=2+(1&n);for(var a=1280,o=0;o<19;++o)for(var r=3&o,s=i.charCodeAt(o)-32,n=0;n<s;++n)e[a++]=r;for(var n=0;n<16;++n)e[1792+n]=1,e[2032+n]=6;e[1792]=0,e[2047]=7;for(var n=0;n<256;++n)e[1536+n]=e[1792+n]<<3}function Z(){this.K=new Int8Array(0),this.x=new Int8Array(0),this.w=new Int8Array(0),this.V=new Int8Array(0),this.l=new Int8Array(0),this._=new Int8Array(0),this.oa=new Int8Array(0),this.f=new Int16Array(0),this.qa=new Int32Array(0),this.r=new Int32Array(0),this.j=new Int32Array(0),this.O=new Int32Array(0),this.P=new Int32Array(0),this.Q=new Int32Array(0),this.m=new Int32Array(0),this.h=0,this.N=0,this.e=0,this.d=0,this.g=0,this.pa=0,this.na=0,this.o=0,this.n=0,this.p=0,this.q=0,this.s=0,this.t=0,this.A=0,this.B=0,this.D=0,this.F=0,this.W=0,this.ha=0,this.k=0,this.U=0,this.v=0,this.C=0,this.fa=0,this.da=0,this.u=0,this.G=0,this.y=0,this.z=0,this.ca=0,this.S=0,this.T=0,this.R=0,this.ga=0,this.ea=0,this.ba=0,this.H=0,this.J=0,this.I=0,this.aa=0,this.X=0,this.Y=0,this.$=0,this.Z=0,this.i=0,this.c=0,this.input=null,this.K=new Int8Array(0),this.r=new Int32Array(10),this.r[0]=16,this.r[1]=15,this.r[2]=11,this.r[3]=4}function ee(e,t,i,n){var a=oe(t+i);if(a.length!=e.length)throw"Corrupted brotli dictionary";for(var o=0,r=n.length,s=0;s<r;s+=2){var l=n.charCodeAt(s)-36,c=n.charCodeAt(s+1)-36;o+=l;for(var d=0;d<c;++d)a[o]|=128,o++}e.L(a)}function te(e,t){return e<=t?e:t}function ie(e,t,i,n){if(null==e)return-1;var a=te(e.b+n,e.a.length),o=a-e.b;return t.L(e.a.M(e.b,a),i),e.b+=o,o}function ne(e){return 0}function ae(e){}function oe(e){for(var t=e.length,i=new Int8Array(t),n=0;n<t;++n)i[n]=e.charCodeAt(n);return i}function re(t){var i=new Z;r(i,new e(t));for(var n=0,a=[];;){var o=new Int8Array(16384);if(a.push(o),i._=o,i.aa=0,i.X=16384,i.Y=0,T(i),n+=i.Y,i.Y<16384)break}s(i);for(var l=new Int8Array(n),c=0,d=0;d<a.length;++d){var o=a[d],h=te(n,c+16384),f=h-c;f<16384?l.L(o.M(0,f),c):l.L(o,c),c+=f}return l}var se=new Int8Array(0),le=Int32Array.from([256,402,436,468,500,534,566,598,630,662,694,726,758,790,822,854,886,920,952,984,1016,1048,1080]),ce=Int32Array.from([1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15]),de=Int32Array.from([0,3,2,1,0,0,0,0,0,0,3,3,3,3,3,3]),he=Int32Array.from([0,0,0,0,-1,1,-2,2,-3,3,-1,1,-2,2,-3,3]),fe=Int32Array.from([131072,131076,131075,196610,131072,131076,131075,262145,131072,131076,131075,196610,131072,131076,131075,262149]),pe=Int32Array.from([0,0,0,0,0,4096,9216,21504,35840,44032,53248,63488,74752,87040,93696,100864,104704,106752,108928,113536,115968,118528,119872,121280,122016]),ue=Int32Array.from([0,0,0,0,10,10,11,11,10,10,10,10,10,9,9,8,7,7,8,7,7,6,6,5,5]),me=Int32Array.from([1,5,9,13,17,25,33,41,49,65,81,97,113,145,177,209,241,305,369,497,753,1265,2289,4337,8433,16625]),ge=Int32Array.from([2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,7,8,9,10,11,12,13,24]),Pe=Int16Array.from([0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,12,14,24]),$e=Int16Array.from([0,0,0,0,0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,24]),be=new Int16Array(2816);a(be);var ve=new S(121,167,50);E(ve.ka,ve.la,ve.ja,'# #s #, #e #.# the #.com/#\xc2\xa0# of # and # in # to #"#">#\n#]# for # a # that #. # with #\'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #="# of the #. This #,# not #er #al #=\'#ful #ive #less #est #ize #ous #'," !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");var ye=new Int32Array(2048);V(ye," !! ! \"#$##%#$&'##(#)#++++++++++((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# ","A/* ': & : $ \x81 @");var Xe=new Int8Array(122784);return ee(Xe,'timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser\') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast\'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$(\'#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid="sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$("#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS"agedgreyGET"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:e*/\r\n 100hall.\n\nA7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,\r\n\r\ncoolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px\'\'););">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarmb\0\x19sboys[0].\');"POSTbearkids);}}marytend(UK)quadzh:f-siz----prop\');\rliftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene b\0\x14softrometillross<h3>pourfadepink<tr>mini)|!(minezh:hbarshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json\', \'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:d\'));puremageparatonebond:37Z_of_\']);000,zh:gtankyardbowlbush:56ZJava30px\n|}\n%C3%:34ZjeffEXPIcashvisagolfsnowzh:iquer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;\n}\nexit:35Zvarsbeat\'});diet999;anne}}</[i].LangkmB2wiretoysaddssealalex;\n\t}echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$(\'.50pxPh.Dmiscalanloandeskmileryanunixdisc);}\ndustclip).\n\n70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}\r\nHEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-\n!002)ndow[1];[];\nLog salt\r\n\t\tbangtrimbath){\r\n00px\n});ko:lfeesad>\rs:// [];tollplug(){\n{\r\n .js\'200pdualboat.JPG);\n}quot);\n\n\');\n\r\n}\r201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomC!sesteestaperotodohacecadaaC1obiendC-aasC-vidacasootroforosolootracualdijosidograntipotemadebealgoquC)estonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiP7P0P=P0P>P<Q\0P0Q\0Q\x03Q\x02P0P=P5P?P>P>Q\x02P8P7P=P>P4P>Q\x02P>P6P5P>P=P8Q\x05P\x1dP0P5P5P1Q\vP<Q\vP\x12Q\vQ\x01P>P2Q\vP2P>P\x1dP>P>P1P\x1fP>P;P8P=P8P P$P\x1dP5P\x1cQ\vQ\x02Q\vP\x1eP=P8P<P4P0P\x17P0P\x14P0P\x1dQ\x03P\x1eP1Q\x02P5P\x18P7P5P9P=Q\x03P<P<P"Q\vQ\x03P6Y\x01Y\nX#Y\x06Y\x05X\'Y\x05X9Y\x03Y\x04X#Y\bX1X/Y\nX\'Y\x01Y\tY\x07Y\bY\x04Y\x05Y\x04Y\x03X\'Y\bY\x04Y\x07X(X3X\'Y\x04X%Y\x06Y\x07Y\nX#Y\nY\x02X/Y\x07Y\x04X+Y\x05X(Y\x07Y\x04Y\bY\x04Y\nX(Y\x04X\'Y\nX(Y\x03X4Y\nX\'Y\x05X#Y\x05Y\x06X*X(Y\nY\x04Y\x06X-X(Y\x07Y\x05Y\x05X4Y\bX4firstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue"crossspentblogsbox">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow">genretrucklooksValueFrame.net/-->\n<try {\nvar makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top">\n<!--POST"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url="parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();" Blocklinuxjonespixel\');">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar">.src=toweralt="cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});\r\nbandsqueue= {};80px;cking{\r\n\t\taheadclockirishlike ratiostatsForm"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg"spainbeachtaxesmicroangel--></giftssteve-linkbody.});\n\tmount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:c\x02simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/"1.jpgwmodeparamSTARTleft idden, 201);\n}\nform.viruschairtransworstPagesitionpatch<!--\no-cacfirmstours,000 asiani++){adobe\')[0]id=10both;menu .2.mi.png"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120" sweettr>\r\nname=diegopage swiss-->\n\n#fff;">Log.com"treatsheet) && 14px;sleepntentfiledja:c\x03id="cName"worseshots-box-delta\n&lt;bears:48Z<data-rural</a> spendbakershops= "";php">ction13px;brianhellosize=o=%2F joinmaybe<img img">, fjsimg" ")[0]MTopBType"newlyDanskczechtrailknows</h5>faq">zh-cn10);\n-1");type=bluestrulydavis.js\';>\r\n<!steel you h2>\r\nform jesus100% menu.\r\n\t\r\nwalesrisksumentddingb-likteachgif" vegasdanskeestishqipsuomisobredesdeentretodospuedeaC1osestC!tienehastaotrospartedondenuevohacerformamismomejormundoaquC-dC-assC3loayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaC-snuevasaludforosmedioquienmesespoderchileserC!vecesdecirjosC)estarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocC3moenerojuegoperC:haberestoynuncamujervalorfueralibrogustaigualvotoscasosguC-apuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleC3nplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenC!readiscopedrocercapuedapapelmenorC:tilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniC1oquedapasarbancohijosviajepabloC)stevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallC-jovendichaestantalessalirsuelopesosfinesllamabuscoC)stalleganegroplazahumorpagarjuntadobleislasbolsabaC1ohablaluchaC\x01readicenjugarnotasvalleallC!cargadolorabajoestC)gustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother" id="marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo" bottomlist">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename="amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.\n\nOnejoinedmenu">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo">beyond-scaleacceptservedmarineFootercamera</h1>\n_form"leavesstress" />\r\n.gif" onloadloaderOxfordsistersurvivlistenfemaleDesignsize="appealtext">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main">inlinesundaywrap">failedcensusminutebeaconquotes150px|estateremoteemail"linkedright;signalformal1.htmlsignupprincefloat:.png" forum.AccesspaperssoundsextendHeightsliderUTF-8"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome">headerensurebranchpiecesblock;statedtop"><racingresize--&gt;pacitysexualbureau.jpg" 10,000obtaintitlesamount, Inc.comedymenu" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline">body">\n* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox">\nSystem DavidcancertablesprovedApril reallydriveritem">more">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php" assumelayerswilsonstoresreliefswedenCustomeasily your String\n\nWhiltaylorclear:resortfrenchthough") + "<body>buyingbrandsMembername">oppingsector5px;">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink">Images=falsewhile hspace0&amp; \n\nIn powerPolski-colorjordanBottomStart -count2.htmlnews">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml" rights.html-blockregExp:hoverwithinvirginphones</tr>\rusing \n\tvar >\');\n\t</td>\n</tr>\nbahasabrasilgalegomagyarpolskisrpskiX1X/Y\bd8-f\x16\x07g.\0d=\x13g9\x01i+\x14d?!f\x01/d8-e\x1b=f\b\x11d;,d8\0d8*e\x05,e\x0f8g.!g\x10\x06h.:e\x1d\x1be\x0f/d;%f\x1c\re\n!f\x176i\x174d8*d::d:\'e\x13\x01h\x07*e71d<\x01d8\x1af\x1f%g\x1c\ve7%d=\x1ch\x01\x14g3;f2!f\x1c\tg=\x11g+\x19f\t\0f\x1c\th/\x04h.:d8-e?\x03f\x16\x07g+ g\x14(f\b7i&\x16i!5d=\x1ch\0\x05f\n\0f\x1c/i\x17.i"\x18g\x1b8e\x053d8\vh==f\x10\x1cg4"d=?g\x14(h=/d;6e\x1c(g:?d8;i"\x18h5\x04f\x16\x19h\'\x06i"\x11e\x1b\x1ee$\rf3(e\x06\fg=\x11g;\x1cf\x146h\x17\x0fe\x06\x05e.9f\x0e(h\r\x10e8\x02e\x1c:f6\bf\x01/g):i\x174e\x0f\x11e8\x03d;\0d9\be%=e\x0f\vg\x14\x1ff4;e\x1b>g\t\x07e\x0f\x11e1\x15e&\x02f\x1e\x1cf\t\vf\x1c:f\x160i\x17;f\x1c\0f\x160f\x169e<\x0fe\f\x17d:,f\x0f\x10d>\x1be\x053d:\x0ef\x1b4e$\x1ah?\x19d8*g3;g;\x1fg\x1f%i\x01\x13f88f\b\x0fe9?e\x11\ne\x056d;\x16e\x0f\x11h!(e.\te\x05(g,,d8\0d<\x1ae\x11\x18h?\x1bh!\fg\x029e\x07;g\t\bf\x1d\x03g\x145e-\x10d8\x16g\x15\fh.>h.!e\x05\rh49f\x15\x19h\x022e\n e\x05%f4;e\n(d;\x16d;,e\x15\x06e\x13\x01e\r\x1ae."g\x0e0e\x1c(d8\nf57e&\x02d=\x15e72g;\x0fg\x15\x19h(\0h/&g;\x06g$>e\f:g\x19;e=\x15f\x1c,g+\x19i\x1c\0h&\x01d;7f <f\x14/f\f\x01e\x1b=i\x19\x05i\x13>f\x0e%e\x1b=e.6e;:h.>f\x1c\ve\x0f\vi\x18\x05h/;f3\x15e>\vd=\rg=.g;\x0ff5\x0ei\0\tf\v)h?\x19f 7e=\x13e\t\re\b\x06g1;f\x0e\x12h!\fe\x1b d8:d:$f\x18\x13f\x1c\0e\x10\x0ei\x1f3d9\x10d8\rh\x03=i\0\x1ah?\x07h!\fd8\x1ag\'\x11f\n\0e\x0f/h\x03=h.>e$\x07e\x10\bd=\x1ce$\'e.6g$>d<\x1ag \x14g)6d8\x13d8\x1ae\x05(i\x03(i!9g\x1b.h?\x19i\x07\fh?\x18f\x18/e<\0e\'\vf\x03\x05e\x065g\x145h\x04\x11f\x16\x07d;6e\x13\x01g\t\fe8.e\n)f\x16\x07e\f\x16h5\x04f:\x10e$\'e-&e-&d9 e\x1c0e\x1d\0f5\x0fh\'\bf\n\x15h5\x04e7%g(\vh&\x01f1\x02f\0\x0ed9\bf\x176e\0\x19e\n\x1fh\x03=d8;h&\x01g\x1b.e\t\rh5\x04h./e\x1f\x0ee8\x02f\x169f3\x15g\x145e=1f\v\x1bh\x01\x18e#0f\x18\x0ed;;d=\x15e\x01%e:7f\x150f\r.g>\x0ee\x1b=f1=h=&d;\vg;\rd=\x06f\x18/d:$f5\x01g\x14\x1fd:\'f\t\0d;%g\x145h/\x1df\x18>g$:d8\0d:\x1be\r\x15d=\rd::e\x11\x18e\b\x06f\x1e\x10e\x1c0e\x1b>f\x17\x05f88e7%e\x057e-&g\x14\x1fg3;e\b\x17g=\x11e\x0f\ve8\x16e-\x10e/\x06g \x01i"\x11i\x01\x13f\x0e\'e\b6e\x1c0e\f:e\x1f:f\x1c,e\x05(e\x1b=g=\x11d8\ni\x07\rh&\x01g,,d:\fe\x16\x1cf,"h?\x1be\x05%e\x0f\vf\x03\x05h?\x19d:\x1bh\0\x03h/\x15e\x0f\x11g\x0e0e\x1f9h.-d;%d8\nf\x14?e:\x1cf\b\x10d8:g\x0e/e"\x03i&\x19f8/e\x10\ff\x176e(1d9\x10e\x0f\x11i\0\x01d8\0e.\x1ae<\0e\x0f\x11d=\x1ce\x13\x01f \x07e\x07\x06f,"h?\x0eh\'#e\x063e\x1c0f\x169d8\0d8\vd;%e\x0f\nh4#d;;f\b\x16h\0\x05e."f\b7d;#h!(g\'/e\b\x06e%3d::f\x150g \x01i\x14\0e\x14.e\x07:g\x0e0g&;g:?e:\x14g\x14(e\b\x17h!(d8\re\x10\fg<\x16h>\x11g;\x1fh.!f\x1f%h/"d8\rh&\x01f\x1c\te\x053f\x1c:f\x1e\x04e>\be$\x1af\x12-f\x14>g;\x04g;\x07f\x14?g-\x16g\x1b4f\x0e%h\x03=e\n\x1bf\x1d%f:\x10f\x19\x02i\x16\x13g\x1c\ve\b0g\x03-i\x17(e\x053i\x14.d8\x13e\f:i\x1d\x1ee88h\v1h/-g\x19>e:&e8\ff\x1c\x1bg>\x0ee%3f/\x14h>\x03g\x1f%h/\x06h\'\x04e.\x1ae;:h..i\x03(i\x17(f\x04\x0fh\'\x01g2>e=)f\x17%f\x1c,f\x0f\x10i+\x18e\x0f\x11h(\0f\x169i\x1d"e\x1f:i\x07\x11e$\x04g\x10\x06f\x1d\x03i\x19\x10e=1g\t\x07i\x136h!\fh?\x18f\x1c\te\b\x06d:+g\t)e\x13\x01g;\x0fh\x10%f7;e\n d8\x13e.6h?\x19g\'\rh/\x1di"\x18h57f\x1d%d8\x1ae\n!e\x05,e\x11\nh.0e=\x15g.\0d;\vh4(i\x07\x0fg\x147d::e=1e\x13\re<\x15g\x14(f\n%e\x11\ni\x03(e\b\x06e?+i\0\x1fe\x12(h/"f\x176e0\x1af3(f\x04\x0fg\x143h/7e-&f !e:\x14h/%e\x0e\x06e\x0f2e\x0f*f\x18/h?\x14e\x1b\x1eh4-d90e\x10\rg\'0d8:d:\x06f\b\x10e\n\x1fh/4f\x18\x0ed>\x1be:\x14e-)e-\x10d8\x13i"\x18g(\ve:\x0fd8\0h\b,f\x1c\x03e\x13!e\x0f*f\x1c\te\x056e.\x03d?\x1df\n$h\0\fd8\x14d;\ne$)g*\x17e\x0f#e\n(f\0\x01g\n6f\0\x01g\t9e\b+h.$d8:e?\x05i!;f\x1b4f\x160e0\x0fh/4f\b\x11e\0\x11d=\x1cd8:e*\x12d=\x13e\f\x05f\v,i\x02#d9\bd8\0f 7e\x1b=e\x06\x05f\x18/e\x10&f 9f\r.g\x145h\'\x06e-&i\x19"e\x057f\x1c\th?\x07g(\vg\x141d:\x0ed::f\t\re\x07:f\x1d%d8\rh?\x07f-#e\x1c(f\x18\x0ef\x18\x1ff\x15\x05d:\ve\x053g3;f \x07i"\x18e\x15\x06e\n!h>\x13e\x05%d8\0g\x1b4e\x1f:g!\0f\x15\x19e-&d:\x06h\'#e;:g-\x11g;\x13f\x1e\x1ce\x05(g\x10\x03i\0\x1ag\x1f%h.!e\b\x12e/9d:\x0eh\t:f\x1c/g\x1b8e\x06\fe\x0f\x11g\x14\x1fg\x1c\x1fg\x1a\x04e;:g+\vg-\tg:\'g1;e\x1e\vg;\x0fi*\fe.\x1eg\x0e0e\b6d=\x1cf\x1d%h\x07*f \x07g->d;%d8\ve\x0e\x1fe\b\x1bf\x17 f3\x15e\x056d8-e\0\vd::d8\0e\b\x07f\f\x07e\r\x17e\x053i\x17-i\x1b\x06e\x1b"g,,d8\te\x053f3(e\x1b f-$g\x05\'g\t\x07f71e\x1c3e\x15\x06d8\x1ae9?e7\x1ef\x17%f\x1c\x1fi+\x18g:\'f\x1c\0h?\x11g;<e\x10\bh!(g$:d8\x13h>\x11h!\fd8:d:$i\0\x1ah/\x04d;7h\'\te>\x17g2>e\r\x0ee.6e:-e.\ff\b\x10f\x04\x1fh\'\te.\th#\x05e>\x17e\b0i\x02.d;6e\b6e:&i#\x1fe\x13\x01h\x19=g\x046h=,h==f\n%d;7h.0h\0\x05f\x169f!\bh!\ff\x14?d::f0\x11g\x14(e\x13\x01d8\x1ch%?f\x0f\x10e\x07:i\x05\x12e:\x17g\x046e\x10\x0ed;\x18f,>g\x03-g\x029d;%e\t\re.\fe\x05(e\x0f\x11e8\x16h.>g=.i"\x06e/<e7%d8\x1ae\f;i\x19"g\x1c\vg\x1c\vg;\x0fe\x058e\x0e\x1fe\x1b e93e\x0f0e\x10\x04g\'\re"\x1ee\n f\x1d\x10f\x16\x19f\x160e"\x1ed9\ve\x10\x0eh\x01\fd8\x1af\x15\bf\x1e\x1cd;\ne94h.:f\x16\x07f\b\x11e\x1b=e\x11\nh/\tg\t\bd8;d?.f\x149e\x0f\x02d8\x0ef\t\x13e\r0e?+d9\x10f\x1c:f"0h\'\x02g\x029e-\x18e\x1c(g2>g%\x1eh\x0e7e>\x17e\b)g\x14(g;\'g;-d= d;,h?\x19d9\bf(!e<\x0fh/-h(\0h\x03=e$\x1fi\x1b\x05h\x19\x0ef\x13\rd=\x1ci#\x0ef <d8\0h57g\'\x11e-&d=\x13h\x022g\x1f-d?!f\x1d!d;6f2;g\x16\x17h?\x10e\n(d:\'d8\x1ad<\x1ah..e/<h\b*e\x05\bg\x14\x1fh\x01\x14g\x1b\x1fe\x0f/f\x18/e\x15\x0fi!\fg;\x13f\x1e\x04d=\x1cg\x14(h0\x03f\x1f%h3\x07f\x16\x19h\x07*e\n(h4\x1fh4#e\x06\x1cd8\x1ah.?i\x17.e.\x1ef\x16=f\x0e%e\x0f\x17h.(h.:i\x02#d8*e\x0f\ri&\be\n e<:e%3f\0\'h\f\x03e\x1b4f\x1c\re\v\x19d<\x11i\x172d;\nf\x17%e."f\x1c\rh\'\0g\x1c\ve\x0f\x02e\n g\x1a\x04h/\x1dd8\0g\x029d?\x1dh/\x01e\x1b>d9&f\x1c\tf\x15\bf5\vh/\x15g\';e\n(f\t\rh\x03=e\x063e.\x1ah\x02!g%(d8\rf\x16-i\x1c\0f1\x02d8\re>\x17e\n\x1ef3\x15d9\vi\x174i\x07\x07g\x14(h\x10%i\x14\0f\n\x15h/\tg\x1b.f \x07g\b1f\x03\x05f\x11\x04e=1f\x1c\td:\x1bh$\x07h#=f\x16\x07e-&f\x1c:d<\x1af\x150e-\x17h#\x05d?.h4-g\t)e\x06\x1cf\x1d\x11e\x05(i\x1d"g2>e\x13\x01e\x056e.\x1ed:\vf\x03\x05f04e93f\x0f\x10g$:d8\ne8\x02h0"h0"f\x19.i\0\x1af\x15\x19e8\bd8\nd< g1;e\b+f-\ff\x1b2f\v%f\x1c\te\b\x1bf\x160i\x05\rd;6e\x0f*h&\x01f\x176d;#h3\x07h(\nh>>e\b0d::g\x14\x1fh."i\x18\x05h\0\x01e8\be1\x15g$:e?\x03g\x10\x06h44e-\x10g62g+\x19d8;i!\fh\x07*g\x046g:\'e\b+g.\0e\r\x15f\x149i\x1d)i\x02#d:\x1bf\x1d%h/4f\t\x13e<\0d;#g \x01e\b i\x19$h/\x01e\b8h\n\x02g\x1b.i\x07\rg\x029f,!f\x158e$\x1ae0\x11h\'\x04e\b\x12h5\x04i\x07\x11f\t>e\b0d;%e\x10\x0ee$\'e\x05(d8;i!5f\x1c\0d=3e\x1b\x1eg-\x14e$)d8\vd?\x1di\x1a\x1cg\x0e0d;#f#\0f\x1f%f\n\x15g%(e0\x0ff\x176f2\x12f\x1c\tf-#e88g\x14\x1ah\x073d;#g\x10\x06g\x1b.e=\x15e\x05,e<\0e$\re\b6i\x07\x11h\x1e\re98g&\x0fg\t\bf\x1c,e="f\b\x10e\x07\x06e$\x07h!\ff\x03\x05e\x1b\x1ee\b0f\0\x1df\x033f\0\x0ef 7e\r\x0fh..h.$h/\x01f\x1c\0e%=d:\'g\x14\x1ff\f\tg\x05\'f\x1c\rh#\x05e9?d8\x1ce\n(f<+i\x07\x07h4-f\x160f\t\vg;\x04e\x1b>i\x1d"f\x1d?e\x0f\x02h\0\x03f\x14?f2;e.9f\x18\x13e$)e\x1c0e\n*e\n\x1bd::d;,e\r\x07g:\'i\0\x1fe:&d::g\t)h0\x03f\x154f5\x01h!\fi\0 f\b\x10f\x16\x07e-\x17i\x1f)e\x1b=h48f\x18\x13e<\0e1\x15g\x1b8i\x17\x1ch!(g\x0e0e=1h\'\x06e&\x02f-$g>\x0ee.9e$\'e0\x0ff\n%i\x01\x13f\x1d!f,>e?\x03f\x03\x05h.8e$\x1af3\x15h\'\x04e.6e1\x05d9&e:\x17h?\x1ef\x0e%g+\ve\r3d8>f\n%f\n\0e7\'e%%h?\x10g\x19;e\x05%d;%f\x1d%g\x10\x06h.:d:\vd;6h\x07*g\x141d8-e\r\x0ee\n\x1ee\x05,e&\be&\bg\x1c\x1ff-#d8\ri\x14\x19e\x05(f\x16\x07e\x10\be\x10\fd;7e\0<e\b+d::g\x1b\x11g\x1d#e\x057d=\x13d8\x16g:*e\x1b"i\x18\x1fe\b\x1bd8\x1af\t?f\v\x05e"\x1ei\x15?f\x1c\td::d?\x1df\f\x01e\x15\x06e.6g;4d?.e\x0f0f9>e7&e\x0f3h\x02!d;=g-\x14f!\be.\x1ei\x19\x05g\x145d?!g;\x0fg\x10\x06g\x14\x1fe\x11=e.#d< d;;e\n!f-#e<\x0fg\t9h\t2d8\vf\x1d%e\r\x0fd<\x1ae\x0f*h\x03=e=\x13g\x046i\x07\rf\x160e\x05\'e.9f\f\x07e/<h?\x10h!\ff\x17%e?\x17h3#e.6h6\x05h?\x07e\x1c\x1fe\x1c0f5\x19f1\x1ff\x14/d;\x18f\x0e(e\x07:g+\x19i\x15?f\x1d-e7\x1ef\t\'h!\fe\b6i\0 d9\vd8\0f\x0e(e9?g\x0e0e\x1c:f\x0f\x0fh?0e\x0f\x18e\f\x16d< g;\x1ff-\ff\t\vd?\x1di\x19)h/>g(\ve\f;g\x16\x17g;\x0fh?\x07h?\x07e\x0e;d9\ve\t\rf\x146e\x05%e94e:&f\x1d\x02e?\x17g>\x0ed8=f\x1c\0i+\x18g\x19;i\x19\x06f\x1c*f\x1d%e\n e7%e\x05\rh4#f\x15\x19g(\vg\t\be\x1d\x17h:+d=\x13i\x07\re:\x06e\x07:e\x14.f\b\x10f\x1c,e="e<\x0fe\x1c\x1fh1\x06e\x07:e\x039d8\x1cf\x169i\x02.g.1e\r\x17d:,f1\x02h\x01\fe\x0f\x16e>\x17h\x01\fd=\rg\x1b8d?!i!5i\x1d"e\b\x06i\x12\x1fg=\x11i!5g!.e.\x1ae\x1b>d>\vg=\x11e\x1d\0g\'/f\x1e\x01i\x14\x19h//g\x1b.g\x1a\x04e.\x1dh4\x1df\x1c:e\x053i#\x0ei\x19)f\x0e\bf\x1d\x03g\x17\x05f/\x12e. g\t)i\x19$d:\x06h)\x15h+\x16g\x16>g\x17\x05e\x0f\nf\x176f1\x02h4-g+\x19g\x029e\x04?g+%f/\x0fe$)d8-e$.h.$h/\x06f/\x0fd8*e$)f4%e-\x17d=\x13e\x0f0g\x01#g;4f\n$f\x1c,i!5d8*f\0\'e.\x18f\x169e88h\'\x01g\x1b8f\x1c:f\b\x18g\x15%e:\x14e=\x13e>\ve8\bf\x169d>?f !e\x1b-h\x02!e8\x02f\b?e1\vf \x0fg\x1b.e\x11\x18e7%e/<h\x074g*\x01g\x046i\x01\x13e\x057f\x1c,g=\x11g;\x13e\x10\bf!#f!\be\n3e\n(e\x0f&e$\x16g>\x0ee\x05\x03e<\x15h57f\x149e\x0f\x18g,,e\x1b\x1bd<\x1ah.!h**f\x18\x0ei\x1a\x10g\'\x01e.\x1de.\x1dh\'\x04h\f\x03f6\bh49e\x051e\x10\fe?\x18h.0d=\x13g3;e8&f\x1d%e\x10\re-\x17g\x19<h!(e<\0f\x14>e\n g\x1b\x1fe\x0f\x17e\b0d:\ff\t\ve$\'i\x07\x0ff\b\x10d::f\x150i\x07\x0fe\x051d:+e\f:e\x1f\x1fe%3e-)e\x0e\x1fe\b\x19f\t\0e\x1c(g;\x13f\x1d\x1fi\0\x1ad?!h6\x05g:\'i\x05\rg=.e=\x13f\x176d<\x18g\'\0f\0\'f\x04\x1ff\b?d:\'i\x01\nf\b2e\x07:e\x0f#f\x0f\x10d:$e01d8\x1ad?\x1de\x01%g(\ve:&e\x0f\x02f\x150d:\vd8\x1af\x154d8*e11d8\x1cf\x03\x05f\x04\x1fg\t9f.\ne\b\x06i!\x1ef\x10\x1ce0\ve1\x1ed:\x0ei\x17(f\b7h4"e\n!e#0i\x1f3e\x0f\ne\x056h4"g;\x0fe\x1d\x1af\f\x01e92i\x03(f\b\x10g+\ve\b)g\x1b\nh\0\x03h\x19\x11f\b\x10i\x03=e\f\x05h#\x05g\x14(f\b6f/\x14h5\x1bf\x16\x07f\x18\x0ef\v\x1be\x15\x06e.\ff\x154g\x1c\x1ff\x18/g\x1c<g\x1d\x1bd<\x19d<4e(\x01f\x1c\x1bi"\x06e\x1f\x1fe\r+g\x14\x1fd<\x18f\x03 h+\x16e#\x07e\x05,e\x051h\t/e%=e\x05\x05e\b\x06g,&e\x10\bi\x19\x04d;6g\t9g\x029d8\re\x0f/h\v1f\x16\x07h5\x04d:\'f 9f\x1c,f\x18\x0ef\x18>e/\x06g"<e\x05,d<\x17f0\x11f\x17\x0ff\x1b4e\n d:+e\x0f\x17e\x10\fe-&e\x10/e\n(i\0\x02e\x10\be\x0e\x1ff\x1d%i\x17.g-\x14f\x1c,f\x16\x07g>\x0ei#\x1fg;?h\t2g(3e.\x1ag;\bd:\x0eg\x14\x1fg\t)d>\x1bf1\x02f\x10\x1cg\v\x10e\n\x1bi\x07\x0fd8%i\x07\rf08h?\x1ce\x06\x19g\x1c\x1ff\x1c\ti\x19\x10g+\x1ed:\te/9h1!h49g\x14(d8\re%=g;\x1de/9e\r\x01e\b\x06d?\x03h?\x1bg\x029h/\x04e=1i\x1f3d<\x18e\n?d8\re0\x11f,#h5\x0fe96d8\x14f\x1c\tg\x029f\x169e\x10\x11e\x05(f\x160d?!g\x14(h.>f\x16=e="h1!h5\x04f <g*\x01g 4i\x1a\x0fg\x1d\0i\x07\re$\'d:\x0ef\x18/f/\x15d8\x1af\x19:h\x03=e\f\x16e7%e.\fg>\x0ee\x15\x06e\x1f\x0eg;\x1fd8\0e\x07:g\t\bf\t\x13i\0 g\x14"e\x13\x01f&\x02e\x065g\x14(d:\x0ed?\x1dg\x15\x19e\x1b g4 d8-e\x1c\ve-\x18e\x02(h44e\x1b>f\x1c\0f\x04\x1bi\x15?f\x1c\x1fe\x0f#d;7g\x10\x06h4"e\x1f:e\x1c0e.\tf\x0e\x12f-&f1\ti\x07\fi\x1d"e\b\x1be;:e$)g):i&\x16e\x05\be.\fe\x16\x04i)1e\n(d8\vi\x1d"d8\re\x06\rh/\x1ad?!f\x04\x0fd9\ti\x183e\x05\th\v1e\x1b=f<\x02d:.e\x06\x1bd:\vg\x0e)e.6g>$d<\x17e\x06\x1cf0\x11e\r3e\x0f/e\x10\rg(1e.6e\x057e\n(g\x14;f\x033e\b0f3(f\x18\x0ee0\x0fe-&f\0\'h\x03=h\0\x03g \x14g!,d;6h\'\x02g\x1c\vf8\x05f%\x1af\x10\x1eg,\x11i&\x16i \x01i;\x04i\x07\x11i\0\x02g\x14(f1\x1fh\v\x0fg\x1c\x1fe.\x1ed8;g.!i\x186f.5h(;e\x06\ng?;h/\x11f\x1d\x03e\b)e\x01\x1ae%=d<<d9\x0ei\0\x1ah./f\x16=e7%g\v\0f\x05\vd9\x1fh.8g\x0e/d?\x1de\x1f9e\x05;f&\x02e?5e$\'e\x1e\vf\x1c:g%(g\x10\x06h\'#e\f?e\x10\rcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestC!nnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegC:nbuenosvolverpuntossemanahabC-aagostonuevosunidoscarlosequiponiC1osmuchosalgunacorreoimagenpartirarribamarC-ahombreempleoverdadcambiomuchasfueronpasadolC-neaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposserC!neuropamediosfrenteacercademC!sofertacochesmodeloitalialetrasalgC:ncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrC!puestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosC:nicocaminositiosrazC3ndebidopruebatoledotenC-ajesC:sesperococinaorigentiendacientocC!dizhablarserC-alatinafuerzaestiloguerraentrarC)xitolC3pezagendavC-deoevitarpaginametrosjavierpadresfC!cilcabezaC!reassalidaenvC-ojapC3nabusosbienestextosllevarpuedanfuertecomC:nclaseshumanotenidobilbaounidadestC!seditarcreadoP4P;Q\x0fQ\x07Q\x02P>P:P0P:P8P;P8Q\rQ\x02P>P2Q\x01P5P5P3P>P?Q\0P8Q\x02P0P:P5Q\tP5Q\x03P6P5P\x1aP0P:P1P5P7P1Q\vP;P>P=P8P\x12Q\x01P5P?P>P4P-Q\x02P>Q\x02P>P<Q\x07P5P<P=P5Q\x02P;P5Q\x02Q\0P0P7P>P=P0P3P4P5P<P=P5P\x14P;Q\x0fP\x1fQ\0P8P=P0Q\x01P=P8Q\x05Q\x02P5P<P:Q\x02P>P3P>P4P2P>Q\x02Q\x02P0P<P!P(P\x10P<P0Q\x0fP\'Q\x02P>P2P0Q\x01P2P0P<P5P<Q\x03P"P0P:P4P2P0P=P0P<Q\rQ\x02P8Q\rQ\x02Q\x03P\x12P0P<Q\x02P5Q\x05P?Q\0P>Q\x02Q\x03Q\x02P=P0P4P4P=Q\x0fP\x12P>Q\x02Q\x02Q\0P8P=P5P9P\x12P0Q\x01P=P8P<Q\x01P0P<Q\x02P>Q\x02Q\0Q\x03P1P\x1eP=P8P<P8Q\0P=P5P5P\x1eP\x1eP\x1eP;P8Q\x06Q\rQ\x02P0P\x1eP=P0P=P5P<P4P>P<P<P>P9P4P2P5P>P=P>Q\x01Q\x03P4`$\x15`%\x07`$9`%\b`$\x15`%\0`$8`%\x07`$\x15`$>`$\x15`%\v`$\x14`$0`$*`$0`$(`%\x07`$\x0f`$\x15`$\x15`$?`$-`%\0`$\x07`$8`$\x15`$0`$$`%\v`$9`%\v`$\x06`$*`$9`%\0`$/`$9`$/`$>`$$`$\x15`$%`$>jagran`$\x06`$\x1c`$\x1c`%\v`$\x05`$,`$&`%\v`$\x17`$\b`$\x1c`$>`$\x17`$\x0f`$9`$.`$\x07`$(`$5`$9`$/`%\x07`$%`%\x07`$%`%\0`$\x18`$0`$\x1c`$,`$&`%\0`$\x15`$\b`$\x1c`%\0`$5`%\x07`$(`$\b`$(`$\x0f`$9`$0`$\t`$8`$.`%\x07`$\x15`$.`$5`%\v`$2`%\x07`$8`$,`$.`$\b`$&`%\x07`$\x13`$0`$\x06`$.`$,`$8`$-`$0`$,`$(`$\x1a`$2`$.`$(`$\x06`$\x17`$8`%\0`$2`%\0X9Y\x04Y\tX%Y\x04Y\tY\x07X0X\'X"X.X1X9X/X/X\'Y\x04Y\tY\x07X0Y\x07X5Y\bX1X:Y\nX1Y\x03X\'Y\x06Y\bY\x04X\'X(Y\nY\x06X9X1X6X0Y\x04Y\x03Y\x07Y\x06X\'Y\nY\bY\x05Y\x02X\'Y\x04X9Y\x04Y\nX\'Y\x06X\'Y\x04Y\x03Y\x06X-X*Y\tY\x02X(Y\x04Y\bX-X)X\'X.X1Y\x01Y\x02X7X9X(X/X1Y\x03Y\x06X%X0X\'Y\x03Y\x05X\'X\'X-X/X%Y\x04X\'Y\x01Y\nY\x07X(X9X6Y\x03Y\nY\x01X(X-X+Y\bY\x05Y\x06Y\bY\x07Y\bX#Y\x06X\'X,X/X\'Y\x04Y\x07X\'X3Y\x04Y\x05X9Y\x06X/Y\x04Y\nX3X9X(X1X5Y\x04Y\tY\x05Y\x06X0X(Y\x07X\'X#Y\x06Y\x07Y\x05X+Y\x04Y\x03Y\x06X*X\'Y\x04X\'X-Y\nX+Y\x05X5X1X4X1X-X-Y\bY\x04Y\bY\x01Y\nX\'X0X\'Y\x04Y\x03Y\x04Y\x05X1X)X\'Y\x06X*X\'Y\x04Y\x01X#X(Y\bX.X\'X5X#Y\x06X*X\'Y\x06Y\x07X\'Y\x04Y\nX9X6Y\bY\bY\x02X/X\'X(Y\x06X.Y\nX1X(Y\x06X*Y\x04Y\x03Y\x05X4X\'X!Y\bY\x07Y\nX\'X(Y\bY\x02X5X5Y\bY\x05X\'X1Y\x02Y\x05X#X-X/Y\x06X-Y\x06X9X/Y\x05X1X#Y\nX\'X-X)Y\x03X*X(X/Y\bY\x06Y\nX,X(Y\x05Y\x06Y\x07X*X-X*X,Y\x07X)X3Y\x06X)Y\nX*Y\x05Y\x03X1X)X:X2X)Y\x06Y\x01X3X(Y\nX*Y\x04Y\x04Y\x07Y\x04Y\x06X\'X*Y\x04Y\x03Y\x02Y\x04X(Y\x04Y\x05X\'X9Y\x06Y\x07X#Y\bY\x04X4Y\nX!Y\x06Y\bX1X#Y\x05X\'Y\x01Y\nY\x03X(Y\x03Y\x04X0X\'X*X1X*X(X(X#Y\x06Y\x07Y\x05X3X\'Y\x06Y\x03X(Y\nX9Y\x01Y\x02X/X-X3Y\x06Y\x04Y\x07Y\x05X4X9X1X#Y\x07Y\x04X4Y\x07X1Y\x02X7X1X7Y\x04X(profileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>\r\nwrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle="Mobile killingshowingItaliandroppedheavilyeffects-1\']);\nconfirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.\n\nThe but notdensityBritainChineselack oftributeIreland" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang="return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue="complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role="missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();\r\npaymenttroubleconceptcompareparentsplayersregionsmonitor \'\'The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen\n\nWhen observe</h2>\r\nModern provide" alt="borders.\n\nFor \n\nMany artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>\r\n Countryignoredloss ofjust asGeorgiastrange<head><stopped1\']);\r\nislandsnotableborder:list ofcarried100,000</h3>\n severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id="foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login">convertviolententeredfirst">circuitFinlandchemistshe was10px;">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title">tooltipSectiondesignsTurkishyounger.match(})();\n\nburningoperatedegreessource=Richardcloselyplasticentries</tr>\r\ncolor:#ul id="possessrollingphysicsfailingexecutecontestlink toDefault<br />\n: true,chartertourismclassicproceedexplain</h1>\r\nonline.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src="/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn\'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and width=e&quot;tradingleft">\npersonsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy\n\t\t<!--Daniel bindingblock">imposedutilizeAbraham(except{width:putting).html(|| [];\nDATA[ *kitchenmountedactual dialectmainly _blank\'installexpertsif(typeIt also&copy; ">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref="/" rel="developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in\n\t<!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday\'s.html" target=wearingAll Rig;\n})();raising Also, crucialabout">declare-->\n<scfirefoxas muchappliesindex, s, but type = \n\r\n<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>\r\n returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of\n\nSome \'click\'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion="pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major":"httpin his menu">\nmonthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>\nevidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>\n he left).val()false);logicalbankinghome tonaming Arizonacredits);\n});\nfounderin turnCollinsbefore But thechargedTitle">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered\']);\n has theunclearEvent\',both innot all\n\n<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage" linear painterand notrarely acronymdelivershorter00&amp;as manywidth="/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong simple}catch(seventhinfoboxwent topaintedcitizenI don\'tretreat. Some ww.");\nbombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft"><comScorAll thejQuery.touristClassicfalse" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>\n\n. When in bothdismissExplorealways via thespaC1olwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>\n\t\tit intoranked rate oful>\r\n attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped").css(hostilelead tolittle groups,Picture-->\r\n\r\n rows=" objectinverse<footerCustomV><\\/scrsolvingChamberslaverywoundedwhereas!= \'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead\')[0Criticsstudios>&copy;group">assemblmaking pressedwidget.ps:" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass="but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + "gconsultdecimalhelpfulrevivedis veryr\'+\'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(" />\n\t\there isencoded. The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();\n is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded="true"spacingis mosta more totallyfall of});\r\n immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace">header-well asStanleybridges/globalCroatia About [0];\n it, andgroupedbeing a){throwhe madelighterethicalFFFFFF"bottom"like a employslive inas seenprintermost ofub-linkrejectsand useimage">succeedfeedingNuclearinformato helpWomen\'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older">us.js"> Since universlarger open to!-- endlies in\']);\r\n marketwho is ("DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = \'make a securedBaptistvoting \n\t\tvar March 2grew upClimate.removeskilledway the</head>face ofacting right">to workreduceshas haderectedshow();action=book ofan area== "htt<header\n<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage">MobilClements" id="as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;">\r\npushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>\npeople.in one =windowfooter_a good reklamaothers,to this_cookiepanel">London,definescrushedbaptismcoastalstatus title" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />\r\nAtlantanucleusCounty,purely count">easily build aonclicka givenpointerh&quot;events else {\nditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium"DO NOT France,with a war andsecond take a >\r\n\r\n\r\nmarket.highwaydone inctivity"last">obligedrise to"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right" bicycleacing="day andstatingRather,higher Office are nowtimes, when a pay foron this-link">;borderaround annual the Newput the.com" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks">\n();" rea place\\u003Caabout atr>\r\n\t\tccount gives a<SCRIPTRailwaythemes/toolboxById("xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>\r\n<ustomVa;&gt;</importsor thatmostly &amp;re size="</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>\r\n\r\n<!organis <br />BeijingcatalC deutscheuropeueuskaragaeilgesvenskaespaC1amensajeusuariotrabajomC)xicopC!ginasiempresistemaoctubreduranteaC1adirempresamomentonuestroprimeratravC)sgraciasnuestraprocesoestadoscalidadpersonanC:meroacuerdomC:sicamiembroofertasalgunospaC-sesejemploderechoademC!sprivadoagregarenlacesposiblehotelessevillaprimeroC:ltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseC1oturismocC3digoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastC-tuloconocersegundoconsejofranciaminutossegundatenemosefectosmC!lagasesiC3nrevistagranadacompraringresogarcC-aacciC3necuadorquienesinclusodeberC!materiahombresmuestrapodrC-amaC1anaC:ltimaestamosoficialtambienningC:nsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo"><adaughterauthor" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id="discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive">somewhatvictoriaWestern title="LocationcontractvisitorsDownloadwithout right">\nmeasureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg" />machines</h2>\n keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow" valuable</label>relativebringingincreasegovernorplugins/List of Header">" name=" (&quot;graduate</head>\ncommercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>\n\t\t<select citizensclothingwatching<li id="specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split("lizationOctober ){returnimproved--&gt;\n\ncoveragechairman.png" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css" /> websitereporteddefault"/></a>\r\nelectricscotlandcreationquantity. ISBN 0did not instance-search-" lang="speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: \'http:\'script\'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id="William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout="approved maximumheader"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=""intervalwirelessentitledagenciesSearch" measuredthousandspending&hellip;new Date" size="pageNamemiddle" " /></a>hidden">sequencepersonaloverflowopinionsillinoislinks">\n\t<title>versionssaturdayterminalitempropengineersectionsdesignerproposal="false"EspaC1olreleasessubmit" er&quot;additionsymptomsorientedresourceright"><pleasurestationshistory.leaving border=contentscenter">.\n\nSome directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal"><span>search">operatorrequestsa &quot;allowingDocumentrevision. \n\nThe yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1"indicatefamiliar qualitymargin:0 contentviewportcontacts-title">portable.length eligibleinvolvesatlanticonload="default.suppliedpaymentsglossary\n\nAfter guidance</td><tdencodingmiddle">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>\n\taffectedsupportspointer;toString</small>oklahomawill be investor0" alt="holidaysResourcelicensed (which . After considervisitingexplorerprimary search" android"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions"campbell<!-- end</span><<br />\r\n_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=" Companyexamples<iframe believespresentsmarshallpart of properly).\n\nThe taxonomymuch of </span>\n" data-srtuguC*sscrollTo project<head>\r\nattorneyemphasissponsorsfancyboxworld\'s wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix\n<head>\narticle <sectionfindingsrole in popular Octoberwebsite exposureused to changesoperatedclickingenteringcommandsinformed numbers </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth="2lazyloadnovemberused in height="cript">\n&nbsp;</<tr><td height:2/productcountry include footer" &lt;!-- title"></jquery.</form>\n(g.\0d=\x13)(g9\x01i+\x14)hrvatskiitalianoromC"nD\x03tC<rkC\'eX\'X1X/Y\btambiC)nnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuC)sdeportesproyectoproductopC:bliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniC3nimprimirmientrasamC)ricavendedorsociedadrespectorealizarregistropalabrasinterC)sentoncesespecialmiembrosrealidadcC3rdobazaragozapC!ginassocialesbloqueargestiC3nalquilersistemascienciascompletoversiC3ncompletaestudiospC:blicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayorC-aalemaniafunciC3nC:ltimoshaciendoaquellosediciC3nfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojC3venesdistritotC)cnicaconjuntoenergC-atrabajarasturiasrecienteutilizarboletC-nsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallaprC3ximoalmerC-aanimalesquiC)nescorazC3nsecciC3nbuscandoopcionesexteriorconceptotodavC-agalerC-aescribirmedicinalicenciaconsultaaspectoscrC-ticadC3laresjusticiadeberC!nperC-odonecesitamantenerpequeC1orecibidatribunaltenerifecanciC3ncanariasdescargadiversosmallorcarequieretC)cnicodeberC-aviviendafinanzasadelantefuncionaconsejosdifC-cilciudadesantiguasavanzadatC)rminounidadessC!nchezcampaC1asoftonicrevistascontienesectoresmomentosfacultadcrC)ditodiversassupuestofactoressegundospequeC1aP3P>P4P0P5Q\x01P;P8P5Q\x01Q\x02Q\fP1Q\vP;P>P1Q\vQ\x02Q\fQ\rQ\x02P>P<P\x15Q\x01P;P8Q\x02P>P3P>P<P5P=Q\x0fP2Q\x01P5Q\x05Q\rQ\x02P>P9P4P0P6P5P1Q\vP;P8P3P>P4Q\x03P4P5P=Q\fQ\rQ\x02P>Q\x02P1Q\vP;P0Q\x01P5P1Q\x0fP>P4P8P=Q\x01P5P1P5P=P0P4P>Q\x01P0P9Q\x02Q\x04P>Q\x02P>P=P5P3P>Q\x01P2P>P8Q\x01P2P>P9P8P3Q\0Q\vQ\x02P>P6P5P2Q\x01P5P<Q\x01P2P>Q\x0eP;P8Q\bQ\fQ\rQ\x02P8Q\x05P?P>P:P0P4P=P5P9P4P>P<P0P<P8Q\0P0P;P8P1P>Q\x02P5P<Q\x03Q\x05P>Q\x02Q\x0fP4P2Q\x03Q\x05Q\x01P5Q\x02P8P;Q\x0eP4P8P4P5P;P>P<P8Q\0P5Q\x02P5P1Q\x0fQ\x01P2P>P5P2P8P4P5Q\x07P5P3P>Q\rQ\x02P8P<Q\x01Q\x07P5Q\x02Q\x02P5P<Q\vQ\x06P5P=Q\vQ\x01Q\x02P0P;P2P5P4Q\fQ\x02P5P<P5P2P>P4Q\vQ\x02P5P1P5P2Q\vQ\bP5P=P0P<P8Q\x02P8P?P0Q\x02P>P<Q\x03P?Q\0P0P2P;P8Q\x06P0P>P4P=P0P3P>P4Q\vP7P=P0Q\x0eP<P>P3Q\x03P4Q\0Q\x03P3P2Q\x01P5P9P8P4P5Q\x02P:P8P=P>P>P4P=P>P4P5P;P0P4P5P;P5Q\x01Q\0P>P:P8Q\x0eP=Q\x0fP2P5Q\x01Q\fP\x15Q\x01Q\x02Q\fQ\0P0P7P0P=P0Q\bP8X\'Y\x04Y\x04Y\x07X\'Y\x04X*Y\nX,Y\x05Y\nX9X.X\'X5X)X\'Y\x04X0Y\nX9Y\x04Y\nY\x07X,X/Y\nX/X\'Y\x04X"Y\x06X\'Y\x04X1X/X*X-Y\x03Y\x05X5Y\x01X-X)Y\x03X\'Y\x06X*X\'Y\x04Y\x04Y\nY\nY\x03Y\bY\x06X4X(Y\x03X)Y\x01Y\nY\x07X\'X(Y\x06X\'X*X-Y\bX\'X!X#Y\x03X+X1X.Y\x04X\'Y\x04X\'Y\x04X-X(X/Y\x04Y\nY\x04X/X1Y\bX3X\'X6X:X7X*Y\x03Y\bY\x06Y\x07Y\x06X\'Y\x03X3X\'X-X)Y\x06X\'X/Y\nX\'Y\x04X7X(X9Y\x04Y\nY\x03X4Y\x03X1X\'Y\nY\x05Y\x03Y\x06Y\x05Y\x06Y\x07X\'X4X1Y\x03X)X1X&Y\nX3Y\x06X4Y\nX7Y\x05X\'X0X\'X\'Y\x04Y\x01Y\x06X4X(X\'X(X*X9X(X1X1X-Y\x05X)Y\x03X\'Y\x01X)Y\nY\x02Y\bY\x04Y\x05X1Y\x03X2Y\x03Y\x04Y\x05X)X#X-Y\x05X/Y\x02Y\x04X(Y\nY\nX9Y\x06Y\nX5Y\bX1X)X7X1Y\nY\x02X4X\'X1Y\x03X,Y\bX\'Y\x04X#X.X1Y\tY\x05X9Y\x06X\'X\'X(X-X+X9X1Y\bX6X(X4Y\x03Y\x04Y\x05X3X,Y\x04X(Y\x06X\'Y\x06X.X\'Y\x04X/Y\x03X*X\'X(Y\x03Y\x04Y\nX)X(X/Y\bY\x06X#Y\nX6X\'Y\nY\bX,X/Y\x01X1Y\nY\x02Y\x03X*X(X*X#Y\x01X6Y\x04Y\x05X7X(X.X\'Y\x03X+X1X(X\'X1Y\x03X\'Y\x01X6Y\x04X\'X-Y\x04Y\tY\x06Y\x01X3Y\x07X#Y\nX\'Y\x05X1X/Y\bX/X#Y\x06Y\x07X\'X/Y\nY\x06X\'X\'Y\x04X\'Y\x06Y\x05X9X1X6X*X9Y\x04Y\x05X/X\'X.Y\x04Y\x05Y\x05Y\x03Y\x06\0\0\0\0\0\0\0\0\x01\0\x01\0\x01\0\x01\0\x02\0\x02\0\x02\0\x02\0\x04\0\x04\0\x04\0\x04\0\0\x01\x02\x03\x04\x05\x06\x07\x07\x06\x05\x04\x03\x02\x01\0\b\t\n\v\f\r\x0e\x0f\x0f\x0e\r\f\v\n\t\b\x10\x11\x12\x13\x14\x15\x16\x17\x17\x16\x15\x14\x13\x12\x11\x10\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18\x7f\x7f\x7f\x7f\0\0\0\0\0\0\0\0\x7f\x7f\x7f\x7f\x01\0\0\0\x02\0\0\0\x02\0\0\0\x01\0\0\0\x01\0\0\0\x03\0\0\0\x7f\x7f\0\x01\0\0\0\x01\0\0\x7f\x7f\0\x01\0\0\0\b\0\b\0\b\0\b\0\0\0\x01\0\x02\0\x03\0\x04\0\x05\0\x06\0\x07resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter" value="</select>Australia" class="situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement" title="potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>\r\nstatementattentionBiography} else {\nsolutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter">\nexceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick="biographyotherwisepermanentFranC\'aisHollywoodexpansionstandards</style>\nreductionDecember preferredCambridgeopponentsBusiness confusion>\n<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>\nmountainslike the essentialfinancialselectionaction="/abandonedEducationparseInt(stabilityunable to</title>\nrelationsNote thatefficientperformedtwo yearsSince thethereforewrapper">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>\nsuspectedmargin: 0spiritual</head>\n\nmicrosoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header">February numerous overflow:componentfragmentsexcellentcolspan="technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>\n\tsponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting" width=".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper"enough toalong thedelivered-->\r\n<!--American protectedNovember </style><furnitureInternet onblur="suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir="ltr"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;\n\nsouthwestthe rightradiationmay have unescape(spoken in" href="/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>\ncame fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8" /><![CDATA[">ContactSouthern bgcolor="series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->\n<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id="precedingTechnicalphysicistoccurs innavigatorsection">span id="sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt="in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id="right">\r\nresidenceleave thecontent">are often })();\r\nprobably Professor-button" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor\n&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved\n\nIn the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also\n<head>\n<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained"></div>\n</a></td>depend onsearch">\npieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue="">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.\n\nAfter , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover" style="states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as Serviceslocation and oftenmeasuringand it ispaperbackvalues of\r\n<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href="y:inline;Church ofthe eventvery highofficial -height: content="/cgi-bin/to createafrikaansesperantofranC\'aislatvieE!ulietuviE3D\feE!tinaD\reE!tina`9\x04`8\x17`8"f\x17%f\x1c,h*\x1eg.\0d=\x13e-\x17g9\x01i+\x14e-\x17m\x15\x1cj5-l\x164d8:d;\0d9\bh.!g.\x17f\x1c:g,\x14h.0f\x1c,h(\x0eh+\x16e\r\0f\x1c\re\n!e\x19(d:\x12h\x01\x14g=\x11f\b?e\x1c0d:\'d?1d9\x10i\x03(e\x07:g\t\bg$>f\x0e\x12h!\ff&\x1ci\x03(h\x10=f <h?\x1bd8\0f-%f\x14/d;\x18e.\x1di*\fh/\x01g \x01e\'\x14e\x11\x18d<\x1af\x150f\r.e:\x13f6\bh49h\0\x05e\n\x1ee\x05,e.$h.(h.:e\f:f71e\x1c3e8\x02f\x12-f\x14>e\x19(e\f\x17d:,e8\x02e$\'e-&g\x14\x1fh6\nf\x1d%h6\ng.!g\x10\x06e\x11\x18d?!f\x01/g=\x11serviciosartC-culoargentinabarcelonacualquierpublicadoproductospolC-ticarespuestawikipediasiguientebC:squedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciC3nnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomC-aimC!genescontactardescargarnecesarioatenciC3ntelC)fonocomisiC3ncancionescapacidadencontraranC!lisisfavoritostC)rminosprovinciaetiquetaselementosfuncionesresultadocarC!cterpropiedadprincipionecesidadmunicipalcreaciC3ndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzC!lezdocumentopelC-cularecientesgeneralestarragonaprC!cticanovedadespropuestapacientestC)cnicasobjetivoscontactos`$.`%\x07`$\x02`$2`$?`$\x0f`$9`%\b`$\x02`$\x17`$/`$>`$8`$>`$%`$\x0f`$5`$\x02`$0`$9`%\x07`$\x15`%\v`$\b`$\x15`%\x01`$\x1b`$0`$9`$>`$,`$>`$&`$\x15`$9`$>`$8`$-`%\0`$9`%\x01`$\x0f`$0`$9`%\0`$.`%\b`$\x02`$&`$?`$(`$,`$>`$$diplodocs`$8`$.`$/`$0`%\x02`$*`$(`$>`$.`$*`$$`$>`$+`$?`$0`$\x14`$8`$$`$$`$0`$9`$2`%\v`$\x17`$9`%\x01`$\x06`$,`$>`$0`$&`%\x07`$6`$9`%\x01`$\b`$\x16`%\x07`$2`$/`$&`$?`$\x15`$>`$.`$5`%\x07`$,`$$`%\0`$(`$,`%\0`$\x1a`$.`%\f`$$`$8`$>`$2`$2`%\x07`$\x16`$\x1c`%\t`$,`$.`$&`$&`$$`$%`$>`$(`$9`%\0`$6`$9`$0`$\x05`$2`$\x17`$\x15`$-`%\0`$(`$\x17`$0`$*`$>`$8`$0`$>`$$`$\x15`$?`$\x0f`$\t`$8`%\x07`$\x17`$/`%\0`$9`%\x02`$\x01`$\x06`$\x17`%\x07`$\x1f`%\0`$.`$\x16`%\v`$\x1c`$\x15`$>`$0`$\x05`$-`%\0`$\x17`$/`%\x07`$$`%\x01`$.`$5`%\v`$\x1f`$&`%\x07`$\x02`$\x05`$\x17`$0`$\x10`$8`%\x07`$.`%\x07`$2`$2`$\x17`$>`$9`$>`$2`$\n`$*`$0`$\x1a`$>`$0`$\x10`$8`$>`$&`%\x07`$0`$\x1c`$?`$8`$&`$?`$2`$,`$\x02`$&`$,`$(`$>`$9`%\x02`$\x02`$2`$>`$\x16`$\x1c`%\0`$$`$,`$\x1f`$(`$.`$?`$2`$\x07`$8`%\x07`$\x06`$(`%\x07`$(`$/`$>`$\x15`%\x01`$2`$2`%\t`$\x17`$-`$>`$\x17`$0`%\x07`$2`$\x1c`$\x17`$9`$0`$>`$.`$2`$\x17`%\x07`$*`%\x07`$\x1c`$9`$>`$%`$\x07`$8`%\0`$8`$9`%\0`$\x15`$2`$>`$ `%\0`$\x15`$9`$>`$\x01`$&`%\x02`$0`$$`$9`$$`$8`$>`$$`$/`$>`$&`$\x06`$/`$>`$*`$>`$\x15`$\x15`%\f`$(`$6`$>`$.`$&`%\x07`$\x16`$/`$9`%\0`$0`$>`$/`$\x16`%\x01`$&`$2`$\x17`%\0categoriesexperience</title>\r\nCopyright javascriptconditionseverything<p class="technologybackground<a class="management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox" techniquesprotectionapparentlyas well asunt\', \'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor="#especially content="productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=".indexOf("conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus="<form id="processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png" (document,boundariesexpressionsettlementBackgroundout of theenterprise("https:" unescape("password" democratic<a href="/wrapper">\nmembershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick="considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic" height="link rel=".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class="0px;marginmechanicalstatisticscelebratedGovernment\n\nDuring tdevelopersartificialequivalentoriginatedCommissionattachment<span id="there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang="en" </style>\r\nabsolute; supportingextremely mainstream</strong> popularityemployment</table>\r\n colspan="</form>\n conversionabout the </p></div>integrated" lang="enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class="<a title="(includingparametersprohibited= "http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0" class="completelyillustratefive yearsinstrumentPublishing1" class="psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;\nfunction it was theConventionautomobileProtestantaggressiveafter the Similarly," /></div>collection\r\nfunctionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>\n</.indexOf(\'i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }\n</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt="adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css"\tfunction innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>\n\tdiplomaticcontainingperformingextensionsmay not beconcept of onclick="It is alsofinancial making theLuxembourgadditionalare calledengaged in"script");but it waselectroniconsubmit="\n<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences\n</head>\r\nrecognisedinitializelimited toAlexandriaretirementAdventuresfour years\n\n&lt;!-- increasingdecorationh3 class="origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews" width="1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class="Scientificclass="no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional\n<head>\n<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix">the publicmany yearswhich wereover time,synonymouscontent">\npresumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan="only a fewmeant thatled to the-->\r\n<div <fieldset>Archbishop class="nobeing usedapproachesprivilegesnoscript>\nresults inmay be theEaster eggmechanismsreasonablePopulationCollectionselected">noscript>\r/index.phparrival of-jssdk\'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>\n\t\tcomplaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype="absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>\npercentagebest-knowncreating a" dir="ltrLieutenant\n<div id="they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren\'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.\n\nIn the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/" class="geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid="searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured">is said tostructuralreferendummost oftena separate->\n<div id Official worldwide.aria-labelthe planetand it wasd" value="looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id="opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/" title=".com/indextaking thepittsburghcontent">\r<script>(fturned outhaving the</span>\r\n occasionalbecause itstarted tophysically></div>\n created byCurrently, bgcolor="tabindex="disastrousAnalytics also has a><div id="</style>\n<called forsinger and.src = "//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportuguC*sW"W\x11W(W\x19W*Y\x01X\'X1X3[\fdesarrollocomentarioeducaciC3nseptiembreregistradodirecciC3nubicaciC3npublicidadrespuestasresultadosimportantereservadosartC-culosdiferentessiguientesrepC:blicasituaciC3nministerioprivacidaddirectorioformaciC3npoblaciC3npresidentecont','enidosaccesoriostechnoratipersonalescategorC-aespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopolC-ticasanterioresdocumentosnaturalezamaterialesdiferenciaeconC3micatransporterodrC-guezparticiparencuentrandiscusiC3nestructurafundaciC3nfrecuentespermanentetotalmenteP<P>P6P=P>P1Q\x03P4P5Q\x02P<P>P6P5Q\x02P2Q\0P5P<Q\x0fQ\x02P0P:P6P5Q\x07Q\x02P>P1Q\vP1P>P;P5P5P>Q\x07P5P=Q\fQ\rQ\x02P>P3P>P:P>P3P4P0P?P>Q\x01P;P5P2Q\x01P5P3P>Q\x01P0P9Q\x02P5Q\x07P5Q\0P5P7P<P>P3Q\x03Q\x02Q\x01P0P9Q\x02P0P6P8P7P=P8P<P5P6P4Q\x03P1Q\x03P4Q\x03Q\x02P\x1fP>P8Q\x01P:P7P4P5Q\x01Q\fP2P8P4P5P>Q\x01P2Q\x0fP7P8P=Q\x03P6P=P>Q\x01P2P>P5P9P;Q\x0eP4P5P9P?P>Q\0P=P>P<P=P>P3P>P4P5Q\x02P5P9Q\x01P2P>P8Q\x05P?Q\0P0P2P0Q\x02P0P:P>P9P<P5Q\x01Q\x02P>P8P<P5P5Q\x02P6P8P7P=Q\fP>P4P=P>P9P;Q\x03Q\x07Q\bP5P?P5Q\0P5P4Q\x07P0Q\x01Q\x02P8Q\x07P0Q\x01Q\x02Q\fQ\0P0P1P>Q\x02P=P>P2Q\vQ\x05P?Q\0P0P2P>Q\x01P>P1P>P9P?P>Q\x02P>P<P<P5P=P5P5Q\x07P8Q\x01P;P5P=P>P2Q\vP5Q\x03Q\x01P;Q\x03P3P>P:P>P;P>P=P0P7P0P4Q\x02P0P:P>P5Q\x02P>P3P4P0P?P>Q\x07Q\x02P8P\x1fP>Q\x01P;P5Q\x02P0P:P8P5P=P>P2Q\vP9Q\x01Q\x02P>P8Q\x02Q\x02P0P:P8Q\x05Q\x01Q\0P0P7Q\x03P!P0P=P:Q\x02Q\x04P>Q\0Q\x03P<P\x1aP>P3P4P0P:P=P8P3P8Q\x01P;P>P2P0P=P0Q\bP5P9P=P0P9Q\x02P8Q\x01P2P>P8P<Q\x01P2Q\x0fP7Q\fP;Q\x0eP1P>P9Q\x07P0Q\x01Q\x02P>Q\x01Q\0P5P4P8P\x1aQ\0P>P<P5P$P>Q\0Q\x03P<Q\0Q\vP=P:P5Q\x01Q\x02P0P;P8P?P>P8Q\x01P:Q\x02Q\vQ\x01Q\x0fQ\x07P<P5Q\x01Q\x0fQ\x06Q\x06P5P=Q\x02Q\0Q\x02Q\0Q\x03P4P0Q\x01P0P<Q\vQ\x05Q\0Q\vP=P:P0P\x1dP>P2Q\vP9Q\x07P0Q\x01P>P2P<P5Q\x01Q\x02P0Q\x04P8P;Q\fP<P<P0Q\0Q\x02P0Q\x01Q\x02Q\0P0P=P<P5Q\x01Q\x02P5Q\x02P5P:Q\x01Q\x02P=P0Q\bP8Q\x05P<P8P=Q\x03Q\x02P8P<P5P=P8P8P<P5Q\x0eQ\x02P=P>P<P5Q\0P3P>Q\0P>P4Q\x01P0P<P>P<Q\rQ\x02P>P<Q\x03P:P>P=Q\x06P5Q\x01P2P>P5P<P:P0P:P>P9P\x10Q\0Q\x05P8P2Y\x05Y\x06X*X/Y\tX%X1X3X\'Y\x04X1X3X\'Y\x04X)X\'Y\x04X9X\'Y\x05Y\x03X*X(Y\x07X\'X(X1X\'Y\x05X,X\'Y\x04Y\nY\bY\x05X\'Y\x04X5Y\bX1X,X/Y\nX/X)X\'Y\x04X9X6Y\bX%X6X\'Y\x01X)X\'Y\x04Y\x02X3Y\x05X\'Y\x04X9X\'X(X*X-Y\x05Y\nY\x04Y\x05Y\x04Y\x01X\'X*Y\x05Y\x04X*Y\x02Y\tX*X9X/Y\nY\x04X\'Y\x04X4X9X1X#X.X(X\'X1X*X7Y\bY\nX1X9Y\x04Y\nY\x03Y\x05X%X1Y\x01X\'Y\x02X7Y\x04X(X\'X*X\'Y\x04Y\x04X:X)X*X1X*Y\nX(X\'Y\x04Y\x06X\'X3X\'Y\x04X4Y\nX.Y\x05Y\x06X*X/Y\nX\'Y\x04X9X1X(X\'Y\x04Y\x02X5X5X\'Y\x01Y\x04X\'Y\x05X9Y\x04Y\nY\x07X\'X*X-X/Y\nX+X\'Y\x04Y\x04Y\x07Y\x05X\'Y\x04X9Y\x05Y\x04Y\x05Y\x03X*X(X)Y\nY\x05Y\x03Y\x06Y\x03X\'Y\x04X7Y\x01Y\x04Y\x01Y\nX/Y\nY\bX%X/X\'X1X)X*X\'X1Y\nX.X\'Y\x04X5X-X)X*X3X,Y\nY\x04X\'Y\x04Y\bY\x02X*X9Y\x06X/Y\x05X\'Y\x05X/Y\nY\x06X)X*X5Y\x05Y\nY\x05X#X1X4Y\nY\x01X\'Y\x04X0Y\nY\x06X9X1X(Y\nX)X(Y\bX\'X(X)X#Y\x04X9X\'X(X\'Y\x04X3Y\x01X1Y\x05X4X\'Y\x03Y\x04X*X9X\'Y\x04Y\tX\'Y\x04X#Y\bY\x04X\'Y\x04X3Y\x06X)X,X\'Y\x05X9X)X\'Y\x04X5X-Y\x01X\'Y\x04X/Y\nY\x06Y\x03Y\x04Y\x05X\'X*X\'Y\x04X.X\'X5X\'Y\x04Y\x05Y\x04Y\x01X#X9X6X\'X!Y\x03X*X\'X(X)X\'Y\x04X.Y\nX1X1X3X\'X&Y\x04X\'Y\x04Y\x02Y\x04X(X\'Y\x04X#X/X(Y\x05Y\x02X\'X7X9Y\x05X1X\'X3Y\x04Y\x05Y\x06X7Y\x02X)X\'Y\x04Y\x03X*X(X\'Y\x04X1X,Y\x04X\'X4X*X1Y\x03X\'Y\x04Y\x02X/Y\x05Y\nX9X7Y\nY\x03sByTagName(.jpg" alt="1px solid #.gif" alt="transparentinformationapplication" onclick="establishedadvertising.png" alt="environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright">0" height="even thoughreplacementdestinationCorporation<ul class="AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class="hundreds of\n\nHowever, compositionclear:both;cooperationwithin the label for="border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength="switzerlandDevelopmentessentially\n\nAlthough </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics\n\t<div id="illustratedengineeringterritoriesauthoritiesdistributed6" height="sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class="more recentit has beeninvasion of).getTime()fundamentalDespite the"><div id="inspirationexaminationpreparationexplanation<input id="</a></span>versions ofinstrumentsbefore the = \'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content">\n<td class="undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src="/<h1 class="publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=";width:100%independent<h3 class=" onchange=").addClass(interactionOne of the daughter ofaccessoriesbranches of\r\n<div id="the largestdeclarationregulationsInformationtranslationdocumentaryin order to">\n<head>\n<" height="1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class="distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>\n</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>\n selected="high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex="it could be<noscript>\nhaving been\r\n<head>\r\n< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval"></span></in New Yorkadditional compression\n\n<div id="incorporate;</script><attachEventbecame the " target="_carried outSome of thescience andthe time ofContainer">maintainingChristopherMuch of thewritings of" height="2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit="director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class="Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the" height="3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>\r\nContinentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name="TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel="This is the <a href="/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og="><a class="class="textConversion may be usedmanufactureafter beingclearfix">\nquestion ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period" name="q" confined toa result ofvalue="" />is actuallyEnvironment\r\n</head>\r\nConversely,>\n<div id="0" width="1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious">this is notthe presentif they areand finallya matter of\r\n\t</div>\r\n\r\n</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer" class="frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>\n<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger\n\t</script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>\n they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight="0" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class="btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world\'scan lead torefers to aborder="0" government winning theresulted in while the Washington,the subjectcity in the></div>\r\n\t\treflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=""><a href="themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href="/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in\t\t<div id="it" value="language ofas they areproduced inis that theexplain thediv></div>\nHowever thelead to the\t<a href="/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldslovenD\rinacomentariosuniversidadcondicionesactividadesexperienciatecnologC-aproducciC3npuntuaciC3naplicaciC3ncontraseC1acategorC-asregistrarseprofesionaltratamientoregC-stratesecretarC-aprincipalesprotecciC3nimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociaciC3ndisponiblesevaluaciC3nestudiantesresponsableresoluciC3nguadalajararegistradosoportunidadcomercialesfotografC-aautoridadesingenierC-atelevisiC3ncompetenciaoperacionesestablecidosimplementeactualmentenavegaciC3nconformidadline-height:font-family:" : "http://applicationslink" href="specifically//<![CDATA[\nOrganizationdistribution0px; height:relationshipdevice-width<div class="<label for="registration</noscript>\n/index.html"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name="intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class="organisationcivilization19th centuryarchitectureincorporated20th century-container">most notably/></a></div>notification\'undefined\')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang="&lt;/sup&gt;dealing withphiladelphiahistorically);</script>\npadding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd">\r\n<htgeographicalConstitution\', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style="Encyclopediaiframe src="demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence" tabindex="float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time"><a class="In addition,description+conversationcontact withis generallyr" content="representing&lt;math&gt;presentationoccasionally<img width="navigation">compensationchampionshipmedia="all" violation ofreference toreturn true;Strict//EN" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}\n</script>\nChristianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=""><a href="/introductionbelonging toclaimed thatconsequences<meta name="Guide to theoverwhelmingagainst the concentrated,\n.nontouch observations</a>\n</div>\nf (document.border: 1px {font-size:1treatment of0" height="1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript" neverthelesssignificanceBroadcasting>&nbsp;</td>container">\nsuch as the influence ofa particularsrc=\'http://navigation" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite" xml:lang="deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype="image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet\t<ul class="installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures\n\t\t<a href="close to theexamples of is about the(see below)." id="searchprofessionalis availablethe official\t\t</script>\n\n\t\t<div id="accelerationthrough the Hall of Famedescriptionstranslationsinterference type=\'text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the\t<li class="instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class="aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc="http://px; height: available tomanufacturerhuman rightslink href="/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>\r\nconsider thean estimatedthe National<div id="pagresulting incommissionedanalogous toare required/ul>\n</div>\nwas based onand became a&nbsp;&nbsp;t" value="" was capturedno more thanrespectivelycontinue to >\r\n<head>\r\n<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml" title="weight:bold;creating thedisplay:nonereplaced the<img src="/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css" media="People from available onproved to besuggestions"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class="evidence forexplanationsenvironments"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign="top"principle ofat the time,</noscript>\rsaid to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style="input name="the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class="lastworking with\'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the\n</script>\n\nan effort toincrease theto the southspacing="0">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>\nthought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds" content="authority ofnorthwestern</div>\n<div "></div>\r\n consultationcommunity ofthe nationalit should beparticipants align="leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class="splace in thewhere he was<li class="fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class="effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previousconsistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\\s+|\\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers\t<link rel="provided thethe story ofcompetitionsenglish (UK)english (US)P\x1cP>P=P3P>P;P!Q\0P?Q\x01P:P8Q\x01Q\0P?Q\x01P:P8Q\x01Q\0P?Q\x01P:P>Y\x04X9X1X(Y\nX)f-#i+\x14d8-f\x16\x07g.\0d=\x13d8-f\x16\x07g9\x01d=\x13d8-f\x16\x07f\x1c\ti\x19\x10e\x05,e\x0f8d::f0\x11f\x14?e:\x1ci\x18?i\x07\fe74e74g$>d<\x1ad8;d9\tf\x13\rd=\x1cg3;g;\x1ff\x14?g-\x16f3\x15h\'\x04informaciC3nherramientaselectrC3nicodescripciC3nclasificadosconocimientopublicaciC3nrelacionadasinformC!ticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecontC!ctenoshabitacionescumplimientorestaurantesdisposiciC3nconsecuenciaelectrC3nicaaplicacionesdesconectadoinstalaciC3nrealizaciC3nutilizaciC3nenciclopediaenfermedadesinstrumentosexperienciasinstituciC3nparticularessubcategoriaQ\x02P>P;Q\fP:P>P P>Q\x01Q\x01P8P8Q\0P0P1P>Q\x02Q\vP1P>P;Q\fQ\bP5P?Q\0P>Q\x01Q\x02P>P<P>P6P5Q\x02P5P4Q\0Q\x03P3P8Q\x05Q\x01P;Q\x03Q\x07P0P5Q\x01P5P9Q\x07P0Q\x01P2Q\x01P5P3P4P0P P>Q\x01Q\x01P8Q\x0fP\x1cP>Q\x01P:P2P5P4Q\0Q\x03P3P8P5P3P>Q\0P>P4P0P2P>P?Q\0P>Q\x01P4P0P=P=Q\vQ\x05P4P>P;P6P=Q\vP8P<P5P=P=P>P\x1cP>Q\x01P:P2Q\vQ\0Q\x03P1P;P5P9P\x1cP>Q\x01P:P2P0Q\x01Q\x02Q\0P0P=Q\vP=P8Q\x07P5P3P>Q\0P0P1P>Q\x02P5P4P>P;P6P5P=Q\x03Q\x01P;Q\x03P3P8Q\x02P5P?P5Q\0Q\fP\x1eP4P=P0P:P>P?P>Q\x02P>P<Q\x03Q\0P0P1P>Q\x02Q\x03P0P?Q\0P5P;Q\x0fP2P>P>P1Q\tP5P>P4P=P>P3P>Q\x01P2P>P5P3P>Q\x01Q\x02P0Q\x02Q\fP8P4Q\0Q\x03P3P>P9Q\x04P>Q\0Q\x03P<P5Q\x05P>Q\0P>Q\bP>P?Q\0P>Q\x02P8P2Q\x01Q\x01Q\vP;P:P0P:P0P6P4Q\vP9P2P;P0Q\x01Q\x02P8P3Q\0Q\x03P?P?Q\vP2P<P5Q\x01Q\x02P5Q\0P0P1P>Q\x02P0Q\x01P:P0P7P0P;P?P5Q\0P2Q\vP9P4P5P;P0Q\x02Q\fP4P5P=Q\fP3P8P?P5Q\0P8P>P4P1P8P7P=P5Q\x01P>Q\x01P=P>P2P5P<P>P<P5P=Q\x02P:Q\x03P?P8Q\x02Q\fP4P>P;P6P=P0Q\0P0P<P:P0Q\x05P=P0Q\x07P0P;P>P P0P1P>Q\x02P0P"P>P;Q\fP:P>Q\x01P>P2Q\x01P5P<P2Q\x02P>Q\0P>P9P=P0Q\x07P0P;P0Q\x01P?P8Q\x01P>P:Q\x01P;Q\x03P6P1Q\vQ\x01P8Q\x01Q\x02P5P<P?P5Q\x07P0Q\x02P8P=P>P2P>P3P>P?P>P<P>Q\tP8Q\x01P0P9Q\x02P>P2P?P>Q\x07P5P<Q\x03P?P>P<P>Q\tQ\fP4P>P;P6P=P>Q\x01Q\x01Q\vP;P:P8P1Q\vQ\x01Q\x02Q\0P>P4P0P=P=Q\vP5P<P=P>P3P8P5P?Q\0P>P5P:Q\x02P!P5P9Q\x07P0Q\x01P<P>P4P5P;P8Q\x02P0P:P>P3P>P>P=P;P0P9P=P3P>Q\0P>P4P5P2P5Q\0Q\x01P8Q\x0fQ\x01Q\x02Q\0P0P=P5Q\x04P8P;Q\fP<Q\vQ\x03Q\0P>P2P=Q\x0fQ\0P0P7P=Q\vQ\x05P8Q\x01P:P0Q\x02Q\fP=P5P4P5P;Q\x0eQ\x0fP=P2P0Q\0Q\x0fP<P5P=Q\fQ\bP5P<P=P>P3P8Q\x05P4P0P=P=P>P9P7P=P0Q\x07P8Q\x02P=P5P;Q\fP7Q\x0fQ\x04P>Q\0Q\x03P<P0P"P5P?P5Q\0Q\fP<P5Q\x01Q\x0fQ\x06P0P7P0Q\tP8Q\x02Q\vP\x1bQ\x03Q\x07Q\bP8P5`$(`$9`%\0`$\x02`$\x15`$0`$(`%\x07`$\x05`$*`$(`%\x07`$\x15`$?`$/`$>`$\x15`$0`%\x07`$\x02`$\x05`$(`%\r`$/`$\x15`%\r`$/`$>`$\x17`$>`$\x07`$!`$,`$>`$0`%\x07`$\x15`$?`$8`%\0`$&`$?`$/`$>`$*`$9`$2`%\x07`$8`$?`$\x02`$9`$-`$>`$0`$$`$\x05`$*`$(`%\0`$5`$>`$2`%\x07`$8`%\x07`$5`$>`$\x15`$0`$$`%\x07`$.`%\x07`$0`%\x07`$9`%\v`$(`%\x07`$8`$\x15`$$`%\x07`$,`$9`%\x01`$$`$8`$>`$\x07`$\x1f`$9`%\v`$\x17`$>`$\x1c`$>`$(`%\x07`$.`$?`$(`$\x1f`$\x15`$0`$$`$>`$\x15`$0`$(`$>`$\t`$(`$\x15`%\x07`$/`$9`$>`$\x01`$8`$,`$8`%\x07`$-`$>`$7`$>`$\x06`$*`$\x15`%\x07`$2`$?`$/`%\x07`$6`%\x01`$0`%\x02`$\x07`$8`$\x15`%\x07`$\x18`$\x02`$\x1f`%\x07`$.`%\x07`$0`%\0`$8`$\x15`$$`$>`$.`%\x07`$0`$>`$2`%\x07`$\x15`$0`$\x05`$\'`$?`$\x15`$\x05`$*`$(`$>`$8`$.`$>`$\x1c`$.`%\x01`$\x1d`%\x07`$\x15`$>`$0`$#`$9`%\v`$$`$>`$\x15`$!`$<`%\0`$/`$9`$>`$\x02`$9`%\v`$\x1f`$2`$6`$,`%\r`$&`$2`$?`$/`$>`$\x1c`%\0`$5`$(`$\x1c`$>`$$`$>`$\x15`%\b`$8`%\x07`$\x06`$*`$\x15`$>`$5`$>`$2`%\0`$&`%\x07`$(`%\x07`$*`%\x02`$0`%\0`$*`$>`$(`%\0`$\t`$8`$\x15`%\x07`$9`%\v`$\x17`%\0`$,`%\b`$ `$\x15`$\x06`$*`$\x15`%\0`$5`$0`%\r`$7`$\x17`$>`$\x02`$5`$\x06`$*`$\x15`%\v`$\x1c`$?`$2`$>`$\x1c`$>`$(`$>`$8`$9`$.`$$`$9`$.`%\x07`$\x02`$\t`$(`$\x15`%\0`$/`$>`$9`%\x02`$&`$0`%\r`$\x1c`$8`%\x02`$\x1a`%\0`$*`$8`$\x02`$&`$8`$5`$>`$2`$9`%\v`$(`$>`$9`%\v`$$`%\0`$\x1c`%\b`$8`%\x07`$5`$>`$*`$8`$\x1c`$(`$$`$>`$(`%\x07`$$`$>`$\x1c`$>`$0`%\0`$\x18`$>`$/`$2`$\x1c`$?`$2`%\x07`$(`%\0`$\x1a`%\x07`$\x1c`$>`$\x02`$\x1a`$*`$$`%\r`$0`$\x17`%\x02`$\x17`$2`$\x1c`$>`$$`%\x07`$,`$>`$9`$0`$\x06`$*`$(`%\x07`$5`$>`$9`$(`$\x07`$8`$\x15`$>`$8`%\x01`$,`$9`$0`$9`$(`%\x07`$\x07`$8`$8`%\x07`$8`$9`$?`$$`$,`$!`$<`%\x07`$\x18`$\x1f`$(`$>`$$`$2`$>`$6`$*`$>`$\x02`$\x1a`$6`%\r`$0`%\0`$,`$!`$<`%\0`$9`%\v`$$`%\x07`$8`$>`$\b`$\x1f`$6`$>`$/`$&`$8`$\x15`$$`%\0`$\x1c`$>`$$`%\0`$5`$>`$2`$>`$9`$\x1c`$>`$0`$*`$\x1f`$(`$>`$0`$\x16`$(`%\x07`$8`$!`$<`$\x15`$.`$?`$2`$>`$\t`$8`$\x15`%\0`$\x15`%\x07`$5`$2`$2`$\x17`$$`$>`$\x16`$>`$(`$>`$\x05`$0`%\r`$%`$\x1c`$9`$>`$\x02`$&`%\x07`$\x16`$>`$*`$9`$2`%\0`$(`$?`$/`$.`$,`$?`$(`$>`$,`%\b`$\x02`$\x15`$\x15`$9`%\0`$\x02`$\x15`$9`$(`$>`$&`%\x07`$$`$>`$9`$.`$2`%\x07`$\x15`$>`$+`%\0`$\x1c`$,`$\x15`$?`$$`%\x01`$0`$$`$.`$>`$\x02`$\x17`$5`$9`%\0`$\x02`$0`%\v`$\x1c`$<`$.`$?`$2`%\0`$\x06`$0`%\v`$*`$8`%\x07`$(`$>`$/`$>`$&`$5`$2`%\x07`$(`%\x07`$\x16`$>`$$`$>`$\x15`$0`%\0`$,`$\t`$(`$\x15`$>`$\x1c`$5`$>`$,`$*`%\x02`$0`$>`$,`$!`$<`$>`$8`%\f`$&`$>`$6`%\x07`$/`$0`$\x15`$?`$/`%\x07`$\x15`$9`$>`$\x02`$\x05`$\x15`$8`$0`$,`$(`$>`$\x0f`$5`$9`$>`$\x02`$8`%\r`$%`$2`$.`$?`$2`%\x07`$2`%\x07`$\x16`$\x15`$5`$?`$7`$/`$\x15`%\r`$0`$\x02`$8`$.`%\x02`$9`$%`$>`$(`$>X*X3X*X7Y\nX9Y\x05X4X\'X1Y\x03X)X(Y\bX\'X3X7X)X\'Y\x04X5Y\x01X-X)Y\x05Y\bX\'X6Y\nX9X\'Y\x04X.X\'X5X)X\'Y\x04Y\x05X2Y\nX/X\'Y\x04X9X\'Y\x05X)X\'Y\x04Y\x03X\'X*X(X\'Y\x04X1X/Y\bX/X(X1Y\x06X\'Y\x05X,X\'Y\x04X/Y\bY\x04X)X\'Y\x04X9X\'Y\x04Y\x05X\'Y\x04Y\x05Y\bY\x02X9X\'Y\x04X9X1X(Y\nX\'Y\x04X3X1Y\nX9X\'Y\x04X,Y\bX\'Y\x04X\'Y\x04X0Y\x07X\'X(X\'Y\x04X-Y\nX\'X)X\'Y\x04X-Y\x02Y\bY\x02X\'Y\x04Y\x03X1Y\nY\x05X\'Y\x04X9X1X\'Y\x02Y\x05X-Y\x01Y\bX8X)X\'Y\x04X+X\'Y\x06Y\nY\x05X4X\'Y\x07X/X)X\'Y\x04Y\x05X1X#X)X\'Y\x04Y\x02X1X"Y\x06X\'Y\x04X4X(X\'X(X\'Y\x04X-Y\bX\'X1X\'Y\x04X,X/Y\nX/X\'Y\x04X#X3X1X)X\'Y\x04X9Y\x04Y\bY\x05Y\x05X,Y\x05Y\bX9X)X\'Y\x04X1X-Y\x05Y\x06X\'Y\x04Y\x06Y\x02X\'X7Y\x01Y\x04X3X7Y\nY\x06X\'Y\x04Y\x03Y\bY\nX*X\'Y\x04X/Y\x06Y\nX\'X(X1Y\x03X\'X*Y\x07X\'Y\x04X1Y\nX\'X6X*X-Y\nX\'X*Y\nX(X*Y\bY\x02Y\nX*X\'Y\x04X#Y\bY\x04Y\tX\'Y\x04X(X1Y\nX/X\'Y\x04Y\x03Y\x04X\'Y\x05X\'Y\x04X1X\'X(X7X\'Y\x04X4X.X5Y\nX3Y\nX\'X1X\'X*X\'Y\x04X+X\'Y\x04X+X\'Y\x04X5Y\x04X\'X)X\'Y\x04X-X/Y\nX+X\'Y\x04X2Y\bX\'X1X\'Y\x04X.Y\x04Y\nX,X\'Y\x04X,Y\x05Y\nX9X\'Y\x04X9X\'Y\x05Y\x07X\'Y\x04X,Y\x05X\'Y\x04X\'Y\x04X3X\'X9X)Y\x05X4X\'Y\x07X/Y\x07X\'Y\x04X1X&Y\nX3X\'Y\x04X/X.Y\bY\x04X\'Y\x04Y\x01Y\x06Y\nX)X\'Y\x04Y\x03X*X\'X(X\'Y\x04X/Y\bX1Y\nX\'Y\x04X/X1Y\bX3X\'X3X*X:X1Y\x02X*X5X\'Y\x05Y\nY\x05X\'Y\x04X(Y\x06X\'X*X\'Y\x04X9X8Y\nY\x05entertainmentunderstanding = function().jpg" width="configuration.png" width="<body class="Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=""><img src="/distinguishedthousands of communicationclear"></div>investigationfavicon.ico" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch" type="form method="as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of" maxlength="return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type="the number ofthe original comprehensiverefers to the</ul>\n</div>\nphilosophicallocation.hrefwas publishedSan Francisco(function(){\n<div id="mainsophisticatedmathematical /head>\r\n<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder="; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript" src="/(function() {are available\n\t<link rel=" src=\'http://interested inconventional " alt="" /></are generallyhas also beenmost popular correspondingcredited withtyle="border:</a></span></.gif" width="<iframe src="table class="inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name="or" content="controversialproperty="og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style="known as the shortly afterfor instance,described as /head>\n<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant" border="0">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name="searchattributed tocourse of themathematicianby the end ofat the end of" border="0" technological.removeClass(branch of theevidence that![endif]-->\r\nInstitute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href="confused with<link href="/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>\n</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription" determine theavailable forAccording to wide range of\t<div class="more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover="because they async = true;problems withseems to havethe result of src="http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld\'s firstclassified asbottom of the(particularlyalign="left" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout="New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to\t<meta name="are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to\t\t<ul class="visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style="equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these\n<div class="input class="replaced withis one of theeducation andinfluenced byreputation as\n<meta name="accommodation</div>\n</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the\n<div style="almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in" value="" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class="mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass="headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;\n</script>\n<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle="marginincluding thebahasa Melayunorsk bokmC%lnorsk nynorskslovenE!D\rinainternacionalcalificaciC3ncomunicaciC3nconstrucciC3n"><div class="disambiguationDomainName\', \'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->\n</><meta name="implementationinfrastructurerepresentationborder-bottom:</head>\n<body>=http%3A%2F%2F<form method="method="post" /favicon.ico" });\n</script>\n.setAttribute(Administration= new Array();<![endif]-->\r\ndisplay:block;Unfortunately,">&nbsp;</div>/favicon.ico">=\'stylesheet\' identification, for example,<li><a href="/an alternativeas a result ofpt"></script>\ntype="submit" \n(function() {recommendationform action="/transformationreconstruction.style.display According to hidden" name="along with thedocument.body.approximately Communicationspost" action="meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover="the governmenthref="https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->\n\ndepends on theUniversity of in contrast to placeholder="in the case ofinternational constitutionalstyle="border-: function() {Because of the-strict.dtd">\n<table class="accompanied byaccount of the<script src="/nature of the the people in in addition tos); js.id = id" width="100%"regarding the Roman Catholican independentfollowing the .gif" width="1the following discriminationarchaeologicalprime minister.js"></script>combination of marginwidth="createElement(w.attachEvent(</a></td></tr>src="https://aIn particular, align="left" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html" title="(function () {comes from theapplication of<span class="sbelieved to beement(\'script\'</a>\n</li>\n<livery different><span class="option value="(also known as\t<li><a href="><input name="separated fromreferred to as valign="top">founder of theattempting to carbon dioxide\n\n<div class="class="search-/body>\n</html>opportunity tocommunications</head>\r\n<body style="width:Tia:?ng Via;\x07tchanges in theborder-color:#0" border="0" </span></div><was discovered" type="text" );\n</script>\n\nDepartment of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>\n\n<div iwas consideredpercent of the" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href=\'http://whether or notThere are alsothere are manya small numberother parts ofimpossible to class="buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=" method="post"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign="right">many countriesfor many yearsearliest knownbecause it waspt"></script>\r valign="top" inhabitants offollowing year\r\n<div class="million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style="color:although therebest known forsubmit" name="multiplicationmore than one recognition ofCouncil of theedition of the <meta name="Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class="descendants of<span class="i align="right"</head>\n<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the\t<span class="is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class="<span class="t(Math.random()most prominentdescription ofConstantinoplewere published<div class="seappears in the1" height="1" most importantwhich includeswhich had beendestruction ofthe population\n\t<div class="possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle="clear:b\r\n</script>\r\n<was founded ininterview with_id" content="capital of the\r\n<link rel="srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class="cperformance of(function() {\rif and only ifregions of theleading to therelations withUnited Nationsstyle="height:other than theype" content="Association of\n</head>\n<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>\n<link rel=" return false;the purpose ofthe ability to;color:#fff}\n.\n<span class="the subject ofdefinitions of>\r\n<link rel="claim that thehave developed<table width="celebration ofFollowing the to distinguish<span class="btakes place inunder the namenoted that the><![endif]-->\nstyle="margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id="was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>\r\n\r\nenvironmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made" src="http://interpreted assecond half ofcrolling="no" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class="footerand especiallytype="button" </span></span>which included>\n<meta name="considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process <div class="the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class="ptext" name="q"\t\t<div class="the scientificrepresented bymathematicianselected by thethat have been><div class="cdiv id="headerin particular,converted into);\n</script>\n<philosophical srpskohrvatskitia:?ng Via;\x07tP Q\x03Q\x01Q\x01P:P8P9Q\0Q\x03Q\x01Q\x01P:P8P9investigaciC3nparticipaciC3nP:P>Q\x02P>Q\0Q\vP5P>P1P;P0Q\x01Q\x02P8P:P>Q\x02P>Q\0Q\vP9Q\x07P5P;P>P2P5P:Q\x01P8Q\x01Q\x02P5P<Q\vP\x1dP>P2P>Q\x01Q\x02P8P:P>Q\x02P>Q\0Q\vQ\x05P>P1P;P0Q\x01Q\x02Q\fP2Q\0P5P<P5P=P8P:P>Q\x02P>Q\0P0Q\x0fQ\x01P5P3P>P4P=Q\x0fQ\x01P:P0Q\x07P0Q\x02Q\fP=P>P2P>Q\x01Q\x02P8P#P:Q\0P0P8P=Q\vP2P>P?Q\0P>Q\x01Q\vP:P>Q\x02P>Q\0P>P9Q\x01P4P5P;P0Q\x02Q\fP?P>P<P>Q\tQ\fQ\x0eQ\x01Q\0P5P4Q\x01Q\x02P2P>P1Q\0P0P7P>P<Q\x01Q\x02P>Q\0P>P=Q\vQ\x03Q\x07P0Q\x01Q\x02P8P5Q\x02P5Q\x07P5P=P8P5P\x13P;P0P2P=P0Q\x0fP8Q\x01Q\x02P>Q\0P8P8Q\x01P8Q\x01Q\x02P5P<P0Q\0P5Q\bP5P=P8Q\x0fP!P:P0Q\x07P0Q\x02Q\fP?P>Q\rQ\x02P>P<Q\x03Q\x01P;P5P4Q\x03P5Q\x02Q\x01P:P0P7P0Q\x02Q\fQ\x02P>P2P0Q\0P>P2P:P>P=P5Q\x07P=P>Q\0P5Q\bP5P=P8P5P:P>Q\x02P>Q\0P>P5P>Q\0P3P0P=P>P2P:P>Q\x02P>Q\0P>P<P P5P:P;P0P<P0X\'Y\x04Y\x05Y\x06X*X/Y\tY\x05Y\x06X*X/Y\nX\'X*X\'Y\x04Y\x05Y\bX6Y\bX9X\'Y\x04X(X1X\'Y\x05X,X\'Y\x04Y\x05Y\bX\'Y\x02X9X\'Y\x04X1X3X\'X&Y\x04Y\x05X4X\'X1Y\x03X\'X*X\'Y\x04X#X9X6X\'X!X\'Y\x04X1Y\nX\'X6X)X\'Y\x04X*X5Y\x05Y\nY\x05X\'Y\x04X\'X9X6X\'X!X\'Y\x04Y\x06X*X\'X&X,X\'Y\x04X#Y\x04X9X\'X(X\'Y\x04X*X3X,Y\nY\x04X\'Y\x04X#Y\x02X3X\'Y\x05X\'Y\x04X6X:X7X\'X*X\'Y\x04Y\x01Y\nX/Y\nY\bX\'Y\x04X*X1X-Y\nX(X\'Y\x04X,X/Y\nX/X)X\'Y\x04X*X9Y\x04Y\nY\x05X\'Y\x04X#X.X(X\'X1X\'Y\x04X\'Y\x01Y\x04X\'Y\x05X\'Y\x04X#Y\x01Y\x04X\'Y\x05X\'Y\x04X*X\'X1Y\nX.X\'Y\x04X*Y\x02Y\x06Y\nX)X\'Y\x04X\'Y\x04X9X\'X(X\'Y\x04X.Y\bX\'X7X1X\'Y\x04Y\x05X,X*Y\x05X9X\'Y\x04X/Y\nY\x03Y\bX1X\'Y\x04X3Y\nX\'X-X)X9X(X/X\'Y\x04Y\x04Y\x07X\'Y\x04X*X1X(Y\nX)X\'Y\x04X1Y\bX\'X(X7X\'Y\x04X#X/X(Y\nX)X\'Y\x04X\'X.X(X\'X1X\'Y\x04Y\x05X*X-X/X)X\'Y\x04X\'X:X\'Y\x06Y\ncursor:pointer;</title>\n<meta " href="http://"><span class="members of the window.locationvertical-align:/a> | <a href="<!doctype html>media="screen" <option value="favicon.ico" />\n\t\t<div class="characteristics" method="get" /body>\n</html>\nshortcut icon" document.write(padding-bottom:representativessubmit" value="align="center" throughout the science fiction\n <div class="submit" class="one of the most valign="top"><was established);\r\n</script>\r\nreturn false;">).style.displaybecause of the document.cookie<form action="/}body{margin:0;Encyclopedia ofversion of the .createElement(name" content="</div>\n</div>\n\nadministrative </body>\n</html>history of the "><input type="portion of the as part of the &nbsp;<a href="other countries">\n<div class="</span></span><In other words,display: block;control of the introduction of/>\n<meta name="as well as the in recent years\r\n\t<div class="</div>\n\t</div>\ninspired by thethe end of the compatible withbecame known as style="margin:.js"></script>< International there have beenGerman language style="color:#Communist Partyconsistent withborder="0" cell marginheight="the majority of" align="centerrelated to the many different Orthodox Churchsimilar to the />\n<link rel="swas one of the until his death})();\n</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling="no" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign="center">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style="width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>\n\t<div class="consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method="post" was followed by&amp;mdash; thethe applicationjs"></script>\r\nul></div></div>after the deathwith respect tostyle="padding:is particularlydisplay:inline; type="submit" is divided intod8-f\x16\x07 (g.\0d=\x13)responsabilidadadministraciC3ninternacionalescorrespondiente`$\t`$*`$/`%\v`$\x17`$*`%\x02`$0`%\r`$5`$9`$.`$>`$0`%\x07`$2`%\v`$\x17`%\v`$\x02`$\x1a`%\x01`$(`$>`$5`$2`%\x07`$\x15`$?`$(`$8`$0`$\x15`$>`$0`$*`%\x01`$2`$?`$8`$\x16`%\v`$\x1c`%\x07`$\x02`$\x1a`$>`$9`$?`$\x0f`$-`%\x07`$\x1c`%\x07`$\x02`$6`$>`$.`$?`$2`$9`$.`$>`$0`%\0`$\x1c`$>`$\x17`$0`$#`$,`$(`$>`$(`%\x07`$\x15`%\x01`$.`$>`$0`$,`%\r`$2`%\t`$\x17`$.`$>`$2`$?`$\x15`$.`$9`$?`$2`$>`$*`%\x03`$7`%\r`$ `$,`$"`$<`$$`%\x07`$-`$>`$\x1c`$*`$>`$\x15`%\r`$2`$?`$\x15`$\x1f`%\r`$0`%\x07`$(`$\x16`$?`$2`$>`$+`$&`%\f`$0`$>`$(`$.`$>`$.`$2`%\x07`$.`$$`$&`$>`$(`$,`$>`$\x1c`$>`$0`$5`$?`$\x15`$>`$8`$\x15`%\r`$/`%\v`$\x02`$\x1a`$>`$9`$$`%\x07`$*`$9`%\x01`$\x01`$\x1a`$,`$$`$>`$/`$>`$8`$\x02`$5`$>`$&`$&`%\x07`$\x16`$(`%\x07`$*`$?`$\x1b`$2`%\x07`$5`$?`$6`%\x07`$7`$0`$>`$\x1c`%\r`$/`$\t`$$`%\r`$$`$0`$.`%\x01`$\x02`$,`$\b`$&`%\v`$(`%\v`$\x02`$\t`$*`$\x15`$0`$#`$*`$"`$<`%\x07`$\x02`$8`%\r`$%`$?`$$`$+`$?`$2`%\r`$.`$.`%\x01`$\x16`%\r`$/`$\x05`$\x1a`%\r`$\x1b`$>`$\x1b`%\x02`$\x1f`$$`%\0`$8`$\x02`$\x17`%\0`$$`$\x1c`$>`$\x0f`$\x17`$>`$5`$?`$-`$>`$\x17`$\x18`$#`%\r`$\x1f`%\x07`$&`%\x02`$8`$0`%\x07`$&`$?`$(`%\v`$\x02`$9`$$`%\r`$/`$>`$8`%\x07`$\x15`%\r`$8`$\x17`$>`$\x02`$\'`%\0`$5`$?`$6`%\r`$5`$0`$>`$$`%\x07`$\x02`$&`%\b`$\x1f`%\r`$8`$(`$\x15`%\r`$6`$>`$8`$>`$.`$(`%\x07`$\x05`$&`$>`$2`$$`$,`$?`$\x1c`$2`%\0`$*`%\x01`$0`%\x02`$7`$9`$?`$\x02`$&`%\0`$.`$?`$$`%\r`$0`$\x15`$5`$?`$$`$>`$0`%\x01`$*`$/`%\x07`$8`%\r`$%`$>`$(`$\x15`$0`%\v`$!`$<`$.`%\x01`$\x15`%\r`$$`$/`%\v`$\x1c`$(`$>`$\x15`%\x03`$*`$/`$>`$*`%\v`$8`%\r`$\x1f`$\x18`$0`%\x07`$2`%\x02`$\x15`$>`$0`%\r`$/`$5`$?`$\x1a`$>`$0`$8`%\x02`$\x1a`$(`$>`$.`%\x02`$2`%\r`$/`$&`%\x07`$\x16`%\x07`$\x02`$9`$.`%\x07`$6`$>`$8`%\r`$\x15`%\x02`$2`$.`%\b`$\x02`$(`%\x07`$$`%\b`$/`$>`$0`$\x1c`$?`$8`$\x15`%\x07rss+xml" title="-type" content="title" content="at the same time.js"></script>\n<" method="post" </span></a></li>vertical-align:t/jquery.min.js">.click(function( style="padding-})();\n</script>\n</span><a href="<a href="http://); return false;text-decoration: scrolling="no" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif" border="0"</body>\n</html>\noverflow:hidden;img src="http://addEventListenerresponsible for s.js"></script>\n/favicon.ico" />operating system" style="width:1target="_blank">State Universitytext-align:left;\ndocument.write(, including the around the world);\r\n</script>\r\n<" style="height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>\n\t\t</div>\ndisplay: none;">" />\n<link rel="\n (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the align="center">University Pressdominated by theSecond World Wardistribution of style="position:the rest of the characterized by rel="nofollow">derives from therather than the a combination ofstyle="width:100English-speakingcomputer scienceborder="0" alt="the existence ofDemocratic Party" style="margin-For this reason,.js"></script>\n\tsByTagName(s)[0]js"></script>\r\n<.js"></script>\r\nlink rel="icon" \' alt=\'\' class=\'formation of theversions of the </a></div></div>/page>\n <page>\n<div class="contbecame the firstbahasa Indonesiaenglish (simple)N\x15N;N;N7N=N9N:N,Q\x05Q\0P2P0Q\x02Q\x01P:P8P:P>P<P?P0P=P8P8Q\x0fP2P;Q\x0fP5Q\x02Q\x01Q\x0fP\x14P>P1P0P2P8Q\x02Q\fQ\x07P5P;P>P2P5P:P0Q\0P0P7P2P8Q\x02P8Q\x0fP\x18P=Q\x02P5Q\0P=P5Q\x02P\x1eQ\x02P2P5Q\x02P8Q\x02Q\fP=P0P?Q\0P8P<P5Q\0P8P=Q\x02P5Q\0P=P5Q\x02P:P>Q\x02P>Q\0P>P3P>Q\x01Q\x02Q\0P0P=P8Q\x06Q\vP:P0Q\x07P5Q\x01Q\x02P2P5Q\x03Q\x01P;P>P2P8Q\x0fQ\x05P?Q\0P>P1P;P5P<Q\vP?P>P;Q\x03Q\x07P8Q\x02Q\fQ\x0fP2P;Q\x0fQ\x0eQ\x02Q\x01Q\x0fP=P0P8P1P>P;P5P5P:P>P<P?P0P=P8Q\x0fP2P=P8P<P0P=P8P5Q\x01Q\0P5P4Q\x01Q\x02P2P0X\'Y\x04Y\x05Y\bX\'X6Y\nX9X\'Y\x04X1X&Y\nX3Y\nX)X\'Y\x04X\'Y\x06X*Y\x02X\'Y\x04Y\x05X4X\'X1Y\x03X\'X*Y\x03X\'Y\x04X3Y\nX\'X1X\'X*X\'Y\x04Y\x05Y\x03X*Y\bX(X)X\'Y\x04X3X9Y\bX/Y\nX)X\'X-X5X\'X&Y\nX\'X*X\'Y\x04X9X\'Y\x04Y\x05Y\nX)X\'Y\x04X5Y\bX*Y\nX\'X*X\'Y\x04X\'Y\x06X*X1Y\x06X*X\'Y\x04X*X5X\'Y\x05Y\nY\x05X\'Y\x04X%X3Y\x04X\'Y\x05Y\nX\'Y\x04Y\x05X4X\'X1Y\x03X)X\'Y\x04Y\x05X1X&Y\nX\'X*robots" content="<div id="footer">the United States<img src="http://.jpg|right|thumb|.js"></script>\r\n<location.protocolframeborder="0" s" />\n<meta name="</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:" rel="nofollow" President of the twentieth centuryevision>\n </pageInternet Explorera.async = true;\r\ninformation about<div id="header">" action="http://<a href="https://<div id="content"</div>\r\n</div>\r\n<derived from the <img src=\'http://according to the \n</body>\n</html>\nstyle="font-size:script language="Arial, Helvetica,</a><span class="</script><script political partiestd></tr></table><href="http://www.interpretation ofrel="stylesheet" document.write(\'<charset="utf-8">\nbeginning of the revealed that thetelevision series" rel="nofollow"> target="_blank">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass="clearfix">/div>\r\n</div>\r\n\r\nthree-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class="in some countriesmin.js"></script>of the populationofficial language<img src="images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>\r\n</html>\rN\x15N;N;N7N=N9N:N,\ntake advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class="headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype="text/css">\nthe InternationalAccording to the pe="text/css" />\ncoincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;" target="_blank" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type="application/anguage" content="<meta http-equiv="Privacy Policy</a>e("%3Cscript src=\'" target="_blank">On the other hand,.jpg|thumb|right|2</div><div class="<div style="float:nineteenth century</body>\r\n</html>\r\n<img src="http://s;text-align:centerfont-weight: bold; According to the difference between" frameborder="0" " style="position:link href="http://html4/loose.dtd">\nduring this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type="text" <span style="font-onreadystatechange\t<div class="cleardocument.location. For example, the a wide variety of <!DOCTYPE html>\r\n<&nbsp;&nbsp;&nbsp;"><a href="http://style="float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype="text/css" />it is possible to Harvard Universitytylesheet" href="/the main characterOxford University name="keywords" cstyle="text-align:the United Kingdomfederal government<div style="margin depending on the description of the<div class="header.min.js"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc="http://staticsuggested that the" src="http://www.a large number of Telecommunications" rel="nofollow" tHoly Roman Emperoralmost exclusively" border="0" alt="Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle="background-<li><em><a href="/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src="http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref="https://www.recent developmentBoard of Directors<div class="search| <a href="http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>\r\n</div>\r\n\r\n<a href="index.phpwas established inmin.js"></script>\nparticipate in thea strong influencestyle="margin-top:represented by thegraduated from theTraditionally, theElement("script");However, since the/div>\n</div>\n<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype="image/x-icon/div>\n<div class=" class="clearfix"><div class="footer\t\t</div>\n\t\t</div>\nthe motion pictureP\x11Q\nP;P3P0Q\0Q\x01P:P8P1Q\nP;P3P0Q\0Q\x01P:P8P$P5P4P5Q\0P0Q\x06P8P8P=P5Q\x01P:P>P;Q\fP:P>Q\x01P>P>P1Q\tP5P=P8P5Q\x01P>P>P1Q\tP5P=P8Q\x0fP?Q\0P>P3Q\0P0P<P<Q\vP\x1eQ\x02P?Q\0P0P2P8Q\x02Q\fP1P5Q\x01P?P;P0Q\x02P=P>P<P0Q\x02P5Q\0P8P0P;Q\vP?P>P7P2P>P;Q\x0fP5Q\x02P?P>Q\x01P;P5P4P=P8P5Q\0P0P7P;P8Q\x07P=Q\vQ\x05P?Q\0P>P4Q\x03P:Q\x06P8P8P?Q\0P>P3Q\0P0P<P<P0P?P>P;P=P>Q\x01Q\x02Q\fQ\x0eP=P0Q\x05P>P4P8Q\x02Q\x01Q\x0fP8P7P1Q\0P0P=P=P>P5P=P0Q\x01P5P;P5P=P8Q\x0fP8P7P<P5P=P5P=P8Q\x0fP:P0Q\x02P5P3P>Q\0P8P8P\x10P;P5P:Q\x01P0P=P4Q\0`$&`%\r`$5`$>`$0`$>`$.`%\b`$(`%\x01`$\x05`$2`$*`%\r`$0`$&`$>`$(`$-`$>`$0`$$`%\0`$/`$\x05`$(`%\x01`$&`%\x07`$6`$9`$?`$(`%\r`$&`%\0`$\x07`$\x02`$!`$?`$/`$>`$&`$?`$2`%\r`$2`%\0`$\x05`$\'`$?`$\x15`$>`$0`$5`%\0`$!`$?`$/`%\v`$\x1a`$?`$\x1f`%\r`$ `%\x07`$8`$.`$>`$\x1a`$>`$0`$\x1c`$\x02`$\x15`%\r`$6`$(`$&`%\x01`$(`$?`$/`$>`$*`%\r`$0`$/`%\v`$\x17`$\x05`$(`%\x01`$8`$>`$0`$\x11`$(`$2`$>`$\x07`$(`$*`$>`$0`%\r`$\x1f`%\0`$6`$0`%\r`$$`%\v`$\x02`$2`%\v`$\x15`$8`$-`$>`$+`$<`%\r`$2`%\b`$6`$6`$0`%\r`$$`%\x07`$\x02`$*`%\r`$0`$&`%\x07`$6`$*`%\r`$2`%\x07`$/`$0`$\x15`%\x07`$\x02`$&`%\r`$0`$8`%\r`$%`$?`$$`$?`$\t`$$`%\r`$*`$>`$&`$\t`$(`%\r`$9`%\x07`$\x02`$\x1a`$?`$\x1f`%\r`$ `$>`$/`$>`$$`%\r`$0`$>`$\x1c`%\r`$/`$>`$&`$>`$*`%\x01`$0`$>`$(`%\x07`$\x1c`%\v`$!`$<`%\x07`$\x02`$\x05`$(`%\x01`$5`$>`$&`$6`%\r`$0`%\x07`$#`%\0`$6`$?`$\x15`%\r`$7`$>`$8`$0`$\x15`$>`$0`%\0`$8`$\x02`$\x17`%\r`$0`$9`$*`$0`$?`$#`$>`$.`$,`%\r`$0`$>`$\x02`$!`$,`$\x1a`%\r`$\x1a`%\v`$\x02`$\t`$*`$2`$,`%\r`$\'`$.`$\x02`$$`%\r`$0`%\0`$8`$\x02`$*`$0`%\r`$\x15`$\t`$.`%\r`$.`%\0`$&`$.`$>`$\'`%\r`$/`$.`$8`$9`$>`$/`$$`$>`$6`$,`%\r`$&`%\v`$\x02`$.`%\0`$!`$?`$/`$>`$\x06`$\b`$*`%\0`$\x0f`$2`$.`%\v`$,`$>`$\x07`$2`$8`$\x02`$\x16`%\r`$/`$>`$\x06`$*`$0`%\x07`$6`$(`$\x05`$(`%\x01`$,`$\x02`$\'`$,`$>`$\x1c`$<`$>`$0`$(`$5`%\0`$(`$$`$.`$*`%\r`$0`$.`%\x01`$\x16`$*`%\r`$0`$6`%\r`$(`$*`$0`$?`$5`$>`$0`$(`%\x01`$\x15`$8`$>`$(`$8`$.`$0`%\r`$%`$(`$\x06`$/`%\v`$\x1c`$?`$$`$8`%\v`$.`$5`$>`$0X\'Y\x04Y\x05X4X\'X1Y\x03X\'X*X\'Y\x04Y\x05Y\x06X*X/Y\nX\'X*X\'Y\x04Y\x03Y\x05X(Y\nY\bX*X1X\'Y\x04Y\x05X4X\'Y\x07X/X\'X*X9X/X/X\'Y\x04X2Y\bX\'X1X9X/X/X\'Y\x04X1X/Y\bX/X\'Y\x04X%X3Y\x04X\'Y\x05Y\nX)X\'Y\x04Y\x01Y\bX*Y\bX4Y\bX(X\'Y\x04Y\x05X3X\'X(Y\x02X\'X*X\'Y\x04Y\x05X9Y\x04Y\bY\x05X\'X*X\'Y\x04Y\x05X3Y\x04X3Y\x04X\'X*X\'Y\x04X,X1X\'Y\x01Y\nY\x03X3X\'Y\x04X\'X3Y\x04X\'Y\x05Y\nX)X\'Y\x04X\'X*X5X\'Y\x04X\'X*keywords" content="w3.org/1999/xhtml"><a target="_blank" text/html; charset=" target="_blank"><table cellpadding="autocomplete="off" text-align: center;to last version by background-color: #" href="http://www./div></div><div id=<a href="#" class=""><img src="http://cript" src="http://\n<script language="//EN" "http://www.wencodeURIComponent(" href="javascript:<div class="contentdocument.write(\'<scposition: absolute;script src="http:// style="margin-top:.min.js"></script>\n</div>\n<div class="w3.org/1999/xhtml" \n\r\n</body>\r\n</html>distinction between/" target="_blank"><link href="http://encoding="utf-8"?>\nw.addEventListener?action="http://www.icon" href="http:// style="background:type="text/css" />\nmeta property="og:t<input type="text" style="text-align:the development of tylesheet" type="tehtml; charset=utf-8is considered to betable width="100%" In addition to the contributed to the differences betweendevelopment of the It is important to </script>\n\n<script style="font-size:1></span><span id=gbLibrary of Congress<img src="http://imEnglish translationAcademy of Sciencesdiv style="display:construction of the.getElementById(id)in conjunction withElement(\'script\'); <meta property="og:P\x11Q\nP;P3P0Q\0Q\x01P:P8\n type="text" name=">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src="http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style="background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet" href="/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland\n</script>\n<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv="X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0" cellpadding="0" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E"));<a href="http://www.<li><a href="http://site_name" content="text-decoration:nonestyle="display: none<meta http-equiv="X-new Date().getTime() type="image/x-icon"</span><span class="language="javascriptwindow.location.href<a href="javascript:-->\r\n<script type="t<a href=\'http://www.hortcut icon" href="</div>\r\n<div class="<script src="http://" rel="stylesheet" t</div>\n<script type=/a> <a href="http:// allowTransparency="X-UA-Compatible" conrelationship between\n</script>\r\n<script </a></li></ul></div>associated with the programming language</a><a href="http://</a></li><li class="form action="http://<div style="display:type="text" name="q"<table width="100%" background-position:" border="0" width="rel="shortcut icon" h6><ul><li><a href=" <meta http-equiv="css" media="screen" responsible for the " type="application/" style="background-html; charset=utf-8" allowtransparency="stylesheet" type="te\r\n<meta http-equiv="></span><span class="0" cellspacing="0">;\n</script>\n<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type="hidden" name="javascript:void(0);"effectiveness of the autocomplete="off" generally considered><input type="text" "></script>\r\n<scriptthroughout the worldcommon misconceptionassociation with the</div>\n</div>\n<div cduring his lifetime,corresponding to thetype="image/x-icon" an increasing numberdiplomatic relationsare often consideredmeta charset="utf-8" <input type="text" examples include the"><img src="http://iparticipation in thethe establishment of\n</div>\n<div class="&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset="utf-8"> type="text/css" />\ninterchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type="text/csstype="submit" name="families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportuguC*s (Europeu)P#P:Q\0P0Q\x17P=Q\x01Q\fP:P0Q\x03P:Q\0P0Q\x17P=Q\x01Q\fP:P0P P>Q\x01Q\x01P8P9Q\x01P:P>P9P<P0Q\x02P5Q\0P8P0P;P>P2P8P=Q\x04P>Q\0P<P0Q\x06P8P8Q\x03P?Q\0P0P2P;P5P=P8Q\x0fP=P5P>P1Q\x05P>P4P8P<P>P8P=Q\x04P>Q\0P<P0Q\x06P8Q\x0fP\x18P=Q\x04P>Q\0P<P0Q\x06P8Q\x0fP P5Q\x01P?Q\x03P1P;P8P:P8P:P>P;P8Q\x07P5Q\x01Q\x02P2P>P8P=Q\x04P>Q\0P<P0Q\x06P8Q\x0eQ\x02P5Q\0Q\0P8Q\x02P>Q\0P8P8P4P>Q\x01Q\x02P0Q\x02P>Q\x07P=P>X\'Y\x04Y\x05X*Y\bX\'X,X/Y\bY\x06X\'Y\x04X\'X4X*X1X\'Y\x03X\'X*X\'Y\x04X\'Y\x02X*X1X\'X-X\'X*html; charset=UTF-8" setTimeout(function()display:inline-block;<input type="submit" type = \'text/javascri<img src="http://www." "http://www.w3.org/shortcut icon" href="" autocomplete="off" </a></div><div class=</a></li>\n<li class="css" type="text/css" <form action="http://xt/css" href="http://link rel="alternate" \r\n<script type="text/ onclick="javascript:(new Date).getTime()}height="1" width="1" People\'s Republic of <a href="http://www.text-decoration:underthe beginning of the </div>\n</div>\n</div>\nestablishment of the </div></div></div></d#viewport{min-height:\n<script src="http://option><option value=often referred to as /option>\n<option valu<!DOCTYPE html>\n<!--[International Airport>\n<a href="http://www</a><a href="http://w`8 `82`8)`82`9\x04`8\x17`8"a\x03%a\x03\x10a\x03 a\x03\x17a\x03#a\x03\x1aa\x03\x18f-#i+\x14d8-f\x16\x07 (g9\x01i+\x14)`$(`$?`$0`%\r`$&`%\x07`$6`$!`$>`$\t`$(`$2`%\v`$!`$\x15`%\r`$7`%\x07`$$`%\r`$0`$\x1c`$>`$(`$\x15`$>`$0`%\0`$8`$\x02`$,`$\x02`$\'`$?`$$`$8`%\r`$%`$>`$*`$(`$>`$8`%\r`$5`%\0`$\x15`$>`$0`$8`$\x02`$8`%\r`$\x15`$0`$#`$8`$>`$.`$\x17`%\r`$0`%\0`$\x1a`$?`$\x1f`%\r`$ `%\v`$\x02`$5`$?`$\x1c`%\r`$\x1e`$>`$(`$\x05`$.`%\x07`$0`$?`$\x15`$>`$5`$?`$-`$?`$(`%\r`$(`$\x17`$>`$!`$?`$/`$>`$\x01`$\x15`%\r`$/`%\v`$\x02`$\x15`$?`$8`%\x01`$0`$\x15`%\r`$7`$>`$*`$9`%\x01`$\x01`$\x1a`$$`%\0`$*`%\r`$0`$,`$\x02`$\'`$(`$\x1f`$?`$*`%\r`$*`$#`%\0`$\x15`%\r`$0`$?`$\x15`%\x07`$\x1f`$*`%\r`$0`$>`$0`$\x02`$-`$*`%\r`$0`$>`$*`%\r`$$`$.`$>`$2`$?`$\x15`%\v`$\x02`$0`$+`$<`%\r`$$`$>`$0`$(`$?`$0`%\r`$.`$>`$#`$2`$?`$.`$?`$\x1f`%\x07`$!description" content="document.location.prot.getElementsByTagName(<!DOCTYPE html>\n<html <meta charset="utf-8">:url" content="http://.css" rel="stylesheet"style type="text/css">type="text/css" href="w3.org/1999/xhtml" xmltype="text/javascript" method="get" action="link rel="stylesheet" = document.getElementtype="image/x-icon" />cellpadding="0" cellsp.css" type="text/css" </a></li><li><a href="" width="1" height="1""><a href="http://www.style="display:none;">alternate" type="appli-//W3C//DTD XHTML 1.0 ellspacing="0" cellpad type="hidden" value="/a>&nbsp;<span role="s\n<input type="hidden" language="JavaScript" document.getElementsBg="0" cellspacing="0" ype="text/css" media="type=\'text/javascript\'with the exception of ype="text/css" rel="st height="1" width="1" =\'+encodeURIComponent(<link rel="alternate" \nbody, tr, input, textmeta name="robots" conmethod="post" action=">\n<a href="http://www.css" rel="stylesheet" </div></div><div classlanguage="javascript">aria-hidden="true">B7<ript" type="text/javasl=0;})();\n(function(){background-image: url(/a></li><li><a href="h\t\t<li><a href="http://ator" aria-hidden="tru> <a href="http://www.language="javascript" /option>\n<option value/div></div><div class=rator" aria-hidden="tre=(new Date).getTime()portuguC*s (do Brasil)P>Q\0P3P0P=P8P7P0Q\x06P8P8P2P>P7P<P>P6P=P>Q\x01Q\x02Q\fP>P1Q\0P0P7P>P2P0P=P8Q\x0fQ\0P5P3P8Q\x01Q\x02Q\0P0Q\x06P8P8P2P>P7P<P>P6P=P>Q\x01Q\x02P8P>P1Q\x0fP7P0Q\x02P5P;Q\fP=P0<!DOCTYPE html PUBLIC "nt-Type" content="text/<meta http-equiv="Conteransitional//EN" "http:<html xmlns="http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = \'text/javascript\';<meta name="descriptionparentNode.insertBefore<input type="hidden" najs" type="text/javascri(document).ready(functiscript type="text/javasimage" content="http://UA-Compatible" content=tml; charset=utf-8" />\nlink rel="shortcut icon<link rel="stylesheet" </script>\n<script type== document.createElemen<a target="_blank" href= document.getElementsBinput type="text" name=a.type = \'text/javascrinput type="hidden" namehtml; charset=utf-8" />dtd">\n<html xmlns="http-//W3C//DTD HTML 4.01 TentsByTagName(\'script\')input type="hidden" nam<script type="text/javas" style="display:none;">document.getElementById(=document.createElement(\' type=\'text/javascript\'input type="text" name="d.getElementsByTagName(snical" href="http://www.C//DTD HTML 4.01 Transit<style type="text/css">\n\n<style type="text/css">ional.dtd">\n<html xmlns=http-equiv="Content-Typeding="0" cellspacing="0"html; charset=utf-8" />\n style="display:none;"><<li><a href="http://www. type=\'text/javascript\'>P4P5Q\x0fQ\x02P5P;Q\fP=P>Q\x01Q\x02P8Q\x01P>P>Q\x02P2P5Q\x02Q\x01Q\x02P2P8P8P?Q\0P>P8P7P2P>P4Q\x01Q\x02P2P0P1P5P7P>P?P0Q\x01P=P>Q\x01Q\x02P8`$*`%\x01`$8`%\r`$$`$?`$\x15`$>`$\x15`$>`$\x02`$\x17`%\r`$0`%\x07`$8`$\t`$(`%\r`$9`%\v`$\x02`$(`%\x07`$5`$?`$\'`$>`$(`$8`$-`$>`$+`$?`$\x15`%\r`$8`$?`$\x02`$\x17`$8`%\x01`$0`$\x15`%\r`$7`$?`$$`$\x15`%\t`$*`%\0`$0`$>`$\x07`$\x1f`$5`$?`$\x1c`%\r`$\x1e`$>`$*`$(`$\x15`$>`$0`%\r`$0`$5`$>`$\b`$8`$\x15`%\r`$0`$?`$/`$$`$>',"\u06f7%\u018c'T%\x85'W%\xd7%O%g%\xa6&\u0193%\u01e5&>&*&'&^&\x88\u0178\u0c3e&\u01ad&\u0192&)&^&%&'&\x82&P&1&\xb1&3&]&m&u&E&t&C&\xcf&V&V&/&>&6&\u0f76\u177co&p&@&E&M&P&x&@&F&e&\xcc&7&:&(&D&0&C&)&.&F&-&1&(&L&F&1\u025e*\u03ea\u21f3&\u1372&K&;&)&E&H&P&0&?&9&V&\x81&-&v&a&,&E&)&?&=&'&'&B&\u0d2e&\u0503&\u0316*&*8&%&%&&&%,)&\x9a&>&\x86&7&]&F&2&>&J&6&n&2&%&?&\x8e&2&6&J&g&-&0&,&*&J&*&O&)&6&(&<&B&N&.&P&@&2&.&W&M&%\u053c\x84(,(<&,&\u03da&\u18c7&-&,(%&(&%&(\u013b0&X&D&\x81&j&'&J&(&.&B&3&Z&R&h&3&E&E&<\xc6-\u0360\u1ef3&%8?&@&,&Z&@&0&J&,&^&x&_&6&C&6&C\u072c\u2a25&f&-&-&-&-&,&J&2&8&z&8&C&Y&8&-&d&\u1e78\xcc-&7&1&F&7&t&W&7&I&.&.&^&=\u0f9c\u19d3&8(>&/&/&\u077b')'\u1065')'%@/&0&%\u043e\u09c0*&*@&C\u053d\u05d4\u0274\u05eb4\u0dd7\u071a\u04d16\u0d84&/\u0178\u0303Z&*%\u0246\u03ff&\u0134&1\xa8\u04b4\u0174"),
+ae(Xe),se=Xe,re}var BrotliDecode=BrotliDecodeClosure();window.ra=BrotliDecode; \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode_test.js b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode_test.js
new file mode 100644
index 000000000..0c18f44fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/decode_test.js
@@ -0,0 +1,79 @@
+goog.require('goog.testing.asserts');
+goog.require('goog.testing.jsunit');
+
+/**
+ * @param {!Int8Array} bytes
+ * @return {string}
+ */
+function bytesToString(bytes) {
+ return String.fromCharCode.apply(null, new Uint16Array(bytes));
+}
+
+function testMetadata() {
+ assertEquals("", bytesToString(BrotliDecode(Int8Array.from([1, 11, 0, 42, 3]))));
+}
+
+function testEmpty() {
+ assertEquals("", bytesToString(BrotliDecode(Int8Array.from([6]))));
+ assertEquals("", bytesToString(BrotliDecode(Int8Array.from([0x81, 1]))));
+}
+
+function testBaseDictWord() {
+ var input = Int8Array.from([
+ 0x1b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe3, 0xb4, 0x0d, 0x00, 0x00,
+ 0x07, 0x5b, 0x26, 0x31, 0x40, 0x02, 0x00, 0xe0, 0x4e, 0x1b, 0x41, 0x02
+ ]);
+ /** @type {!Int8Array} */
+ var output = BrotliDecode(input);
+ assertEquals("time", bytesToString(output));
+}
+
+function testBlockCountMessage() {
+ var input = Int8Array.from([
+ 0x1b, 0x0b, 0x00, 0x11, 0x01, 0x8c, 0xc1, 0xc5, 0x0d, 0x08, 0x00, 0x22,
+ 0x65, 0xe1, 0xfc, 0xfd, 0x22, 0x2c, 0xc4, 0x00, 0x00, 0x38, 0xd8, 0x32,
+ 0x89, 0x01, 0x12, 0x00, 0x00, 0x77, 0xda, 0x04, 0x10, 0x42, 0x00, 0x00, 0x00
+ ]);
+ /** @type {!Int8Array} */
+ var output = BrotliDecode(input);
+ assertEquals("aabbaaaaabab", bytesToString(output));
+}
+
+function testCompressedUncompressedShortCompressedSmallWindow() {
+ var input = Int8Array.from([
+ 0x21, 0xf4, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xa7, 0x6d, 0x00, 0x00,
+ 0x38, 0xd8, 0x32, 0x89, 0x01, 0x12, 0x00, 0x00, 0x77, 0xda, 0x34, 0x7b,
+ 0xdb, 0x50, 0x80, 0x02, 0x80, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x4e, 0xdb, 0x00, 0x00, 0x70, 0xb0,
+ 0x65, 0x12, 0x03, 0x24, 0x00, 0x00, 0xee, 0xb4, 0x11, 0x24, 0x00
+ ]);
+ /** @type {!Int8Array} */
+ var output = BrotliDecode(input);
+ assertEquals(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+ "aaaaaaaaaaaaaabbbbbbbbbb", bytesToString(output));
+}
+
+function testIntactDistanceRingBuffer0() {
+ var input = Int8Array.from([
+ 0x1b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe3, 0xb4, 0x0d, 0x00, 0x00,
+ 0x07, 0x5b, 0x26, 0x31, 0x40, 0x02, 0x00, 0xe0, 0x4e, 0x1b, 0xa1, 0x80,
+ 0x20, 0x00
+ ]);
+ /** @type {!Int8Array} */
+ var output = BrotliDecode(input);
+ assertEquals("himselfself", bytesToString(output));
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/polyfill.js b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/polyfill.js
new file mode 100644
index 000000000..707a89a6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/js/polyfill.js
@@ -0,0 +1,65 @@
+if (!Int32Array.__proto__.from) {
+ Object.defineProperty(Int32Array.__proto__, 'from', {
+ value: function(obj) {
+ obj = Object(obj);
+ if (!obj['length']) {
+ return new this(0);
+ }
+ var typed_array = new this(obj.length);
+ for(var i = 0; i < typed_array.length; i++) {
+ typed_array[i] = obj[i];
+ }
+ return typed_array;
+ }
+ });
+}
+
+if (!Array.prototype.copyWithin) {
+ Array.prototype.copyWithin = function(target, start, end) {
+ var O = Object(this);
+ var len = O.length >>> 0;
+ var to = target | 0;
+ var from = start | 0;
+ var count = Math.min(Math.min(end | 0, len) - from, len - to);
+ var direction = 1;
+ if (from < to && to < (from + count)) {
+ direction = -1;
+ from += count - 1;
+ to += count - 1;
+ }
+ while (count > 0) {
+ O[to] = O[from];
+ from += direction;
+ to += direction;
+ count--;
+ }
+ return O;
+ };
+}
+
+if (!Array.prototype.fill) {
+ Object.defineProperty(Array.prototype, 'fill', {
+ value: function(value, start, end) {
+ end = end | 0;
+ var O = Object(this);
+ var k = start | 0;
+ while (k < end) {
+ O[k] = value;
+ k++;
+ }
+ return O;
+ }
+ });
+}
+
+if (!Int8Array.prototype.copyWithin) {
+ Int8Array.prototype.copyWithin = Array.prototype.copyWithin;
+}
+
+if (!Int8Array.prototype.fill) {
+ Int8Array.prototype.fill = Array.prototype.fill;
+}
+
+if (!Int32Array.prototype.fill) {
+ Int32Array.prototype.fill = Array.prototype.fill;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/premake5.lua b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/premake5.lua
new file mode 100644
index 000000000..555263e00
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/premake5.lua
@@ -0,0 +1,78 @@
+-- A solution contains projects, and defines the available configurations
+solution "brotli"
+configurations { "Release", "Debug" }
+platforms { "x64", "x86" }
+targetdir "bin"
+location "buildfiles"
+flags "RelativeLinks"
+includedirs { "c/include" }
+
+filter "configurations:Release"
+ optimize "Speed"
+ flags { "StaticRuntime" }
+
+filter "configurations:Debug"
+ flags { "Symbols" }
+
+filter { "platforms:x64" }
+ architecture "x86_64"
+
+filter { "platforms:x86" }
+ architecture "x86"
+
+configuration { "gmake" }
+ buildoptions { "-Wall -fno-omit-frame-pointer" }
+ location "buildfiles/gmake"
+
+configuration { "xcode4" }
+ location "buildfiles/xcode4"
+
+configuration "linux"
+ links "m"
+
+configuration { "macosx" }
+ defines { "OS_MACOSX" }
+
+project "brotlicommon"
+ kind "SharedLib"
+ language "C"
+ files { "c/common/**.h", "c/common/**.c" }
+
+project "brotlicommon_static"
+ kind "StaticLib"
+ targetname "brotlicommon"
+ language "C"
+ files { "c/common/**.h", "c/common/**.c" }
+
+project "brotlidec"
+ kind "SharedLib"
+ language "C"
+ files { "c/dec/**.h", "c/dec/**.c" }
+ links "brotlicommon"
+
+project "brotlidec_static"
+ kind "StaticLib"
+ targetname "brotlidec"
+ language "C"
+ files { "c/dec/**.h", "c/dec/**.c" }
+ links "brotlicommon_static"
+
+project "brotlienc"
+ kind "SharedLib"
+ language "C"
+ files { "c/enc/**.h", "c/enc/**.c" }
+ links "brotlicommon"
+
+project "brotlienc_static"
+ kind "StaticLib"
+ targetname "brotlienc"
+ language "C"
+ files { "c/enc/**.h", "c/enc/**.c" }
+ links "brotlicommon_static"
+
+project "brotli"
+ kind "ConsoleApp"
+ language "C"
+ linkoptions "-static"
+ files { "c/tools/brotli.c" }
+ links { "brotlicommon_static", "brotlidec_static", "brotlienc_static" }
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/Makefile b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/Makefile
new file mode 100644
index 000000000..d5d88f87f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/Makefile
@@ -0,0 +1,57 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+
+# Default (Build)
+.PHONY: all
+# Build
+.PHONY: build
+# Develop
+.PHONY: develop
+# Install
+.PHONY: install
+# Test
+.PHONY: test
+# Clean
+.PHONY: clean
+# Format
+.PHONY: fix
+
+
+PYTHON ?= python
+YAPF ?= yapf
+
+EXT_SUFFIX=$(shell $(PYTHON) -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX"))')
+EXT_SOURCES=$(shell find . -name '*.cc')
+EXTENSIONS=$(EXT_SOURCES:%.cc=%$(EXT_SUFFIX))
+
+
+all: build
+
+build: $(EXTENSIONS)
+
+$(EXTENSIONS): $(EXT_SOURCES)
+ @cd .. && $(PYTHON) setup.py build_ext --inplace
+
+develop:
+ @cd .. && $(PYTHON) setup.py develop
+
+install:
+ @cd .. && $(PYTHON) setup.py install
+
+test: build
+ @echo 'running tests'
+ @$(PYTHON) -m unittest discover -v -p '*_test.py'
+
+clean:
+ @cd .. && $(PYTHON) setup.py clean
+ @find .. -name '*.pyc' | xargs rm -v
+ @find .. -name '*.so' | xargs rm -v
+ @find .. -type d -name '__pycache__' | xargs rm -v -r
+ @find .. -type d -name '*.egg-info' | xargs rm -v -r
+
+fix:
+ @echo 'formatting code'
+ -@$(YAPF) --in-place --recursive --verify .
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/README.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/README.md
new file mode 100644
index 000000000..6a9068aa4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/README.md
@@ -0,0 +1,54 @@
+This directory contains the code for the Python `brotli` module,
+`bro.py` tool, and roundtrip tests.
+
+Only Python 2.7+ is supported.
+
+We provide a `Makefile` to simplify common development commands.
+
+### Installation
+
+If you just want to install the latest release of the Python `brotli`
+module, we recommend installing from [PyPI][]:
+
+ $ pip install brotli
+
+Alternatively, you may install directly from source by running the
+following command from this directory:
+
+ $ make install
+
+### Development
+
+You may run the following commands from this directory:
+
+ $ make # Build the module in-place
+
+ $ make test # Test the module
+
+ $ make clean # Remove all temporary files and build output
+
+If you wish to make the module available while still being
+able to edit the source files, you can use the `setuptools`
+"[development mode][]":
+
+ $ make develop # Install the module in "development mode"
+
+### Code Style
+
+Brotli's code follows the [Google Python Style Guide][]. To
+automatically format your code, first install [YAPF][]:
+
+ $ pip install yapf
+
+Then, to format all files in the project, you can run:
+
+ $ make fix # Automatically format code
+
+See the [YAPF usage][] documentation for more information.
+
+
+[PyPI]: https://pypi.org/project/Brotli/
+[development mode]: https://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode
+[Google Python Style Guide]: https://google.github.io/styleguide/pyguide.html
+[YAPF]: https://github.com/google/yapf
+[YAPF usage]: https://github.com/google/yapf#usage
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/_brotli.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/_brotli.cc
new file mode 100644
index 000000000..d4075bd45
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/_brotli.cc
@@ -0,0 +1,753 @@
+#define PY_SSIZE_T_CLEAN 1
+#include <Python.h>
+#include <bytesobject.h>
+#include <structmember.h>
+#include <vector>
+#include "../common/version.h"
+#include <brotli/decode.h>
+#include <brotli/encode.h>
+
+#if PY_MAJOR_VERSION >= 3
+#define PyInt_Check PyLong_Check
+#define PyInt_AsLong PyLong_AsLong
+#endif
+
+static PyObject *BrotliError;
+
+static int as_bounded_int(PyObject *o, int* result, int lower_bound, int upper_bound) {
+ long value = PyInt_AsLong(o);
+ if ((value < (long) lower_bound) || (value > (long) upper_bound)) {
+ return 0;
+ }
+ *result = (int) value;
+ return 1;
+}
+
+static int mode_convertor(PyObject *o, BrotliEncoderMode *mode) {
+ if (!PyInt_Check(o)) {
+ PyErr_SetString(BrotliError, "Invalid mode");
+ return 0;
+ }
+
+ int mode_value = -1;
+ if (!as_bounded_int(o, &mode_value, 0, 255)) {
+ PyErr_SetString(BrotliError, "Invalid mode");
+ return 0;
+ }
+ *mode = (BrotliEncoderMode) mode_value;
+ if (*mode != BROTLI_MODE_GENERIC &&
+ *mode != BROTLI_MODE_TEXT &&
+ *mode != BROTLI_MODE_FONT) {
+ PyErr_SetString(BrotliError, "Invalid mode");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int quality_convertor(PyObject *o, int *quality) {
+ if (!PyInt_Check(o)) {
+ PyErr_SetString(BrotliError, "Invalid quality");
+ return 0;
+ }
+
+ if (!as_bounded_int(o, quality, 0, 11)) {
+ PyErr_SetString(BrotliError, "Invalid quality. Range is 0 to 11.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int lgwin_convertor(PyObject *o, int *lgwin) {
+ if (!PyInt_Check(o)) {
+ PyErr_SetString(BrotliError, "Invalid lgwin");
+ return 0;
+ }
+
+ if (!as_bounded_int(o, lgwin, 10, 24)) {
+ PyErr_SetString(BrotliError, "Invalid lgwin. Range is 10 to 24.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int lgblock_convertor(PyObject *o, int *lgblock) {
+ if (!PyInt_Check(o)) {
+ PyErr_SetString(BrotliError, "Invalid lgblock");
+ return 0;
+ }
+
+ if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) {
+ PyErr_SetString(BrotliError, "Invalid lgblock. Can be 0 or in range 16 to 24.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static BROTLI_BOOL compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation op,
+ std::vector<uint8_t>* output,
+ uint8_t* input, size_t input_length) {
+ BROTLI_BOOL ok = BROTLI_TRUE;
+ Py_BEGIN_ALLOW_THREADS
+
+ size_t available_in = input_length;
+ const uint8_t* next_in = input;
+ size_t available_out = 0;
+ uint8_t* next_out = NULL;
+
+ while (ok) {
+ ok = BrotliEncoderCompressStream(enc, op,
+ &available_in, &next_in,
+ &available_out, &next_out, NULL);
+ if (!ok)
+ break;
+
+ size_t buffer_length = 0; // Request all available output.
+ const uint8_t* buffer = BrotliEncoderTakeOutput(enc, &buffer_length);
+ if (buffer_length) {
+ (*output).insert((*output).end(), buffer, buffer + buffer_length);
+ }
+
+ if (available_in || BrotliEncoderHasMoreOutput(enc)) {
+ continue;
+ }
+
+ break;
+ }
+
+ Py_END_ALLOW_THREADS
+ return ok;
+}
+
+PyDoc_STRVAR(brotli_Compressor_doc,
+"An object to compress a byte string.\n"
+"\n"
+"Signature:\n"
+" Compressor(mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0)\n"
+"\n"
+"Args:\n"
+" mode (int, optional): The compression mode can be MODE_GENERIC (default),\n"
+" MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0). \n"
+" quality (int, optional): Controls the compression-speed vs compression-\n"
+" density tradeoff. The higher the quality, the slower the compression.\n"
+" Range is 0 to 11. Defaults to 11.\n"
+" lgwin (int, optional): Base 2 logarithm of the sliding window size. Range\n"
+" is 10 to 24. Defaults to 22.\n"
+" lgblock (int, optional): Base 2 logarithm of the maximum input block size.\n"
+" Range is 16 to 24. If set to 0, the value will be set based on the\n"
+" quality. Defaults to 0.\n"
+"\n"
+"Raises:\n"
+" brotli.error: If arguments are invalid.\n");
+
+typedef struct {
+ PyObject_HEAD
+ BrotliEncoderState* enc;
+} brotli_Compressor;
+
+static void brotli_Compressor_dealloc(brotli_Compressor* self) {
+ BrotliEncoderDestroyInstance(self->enc);
+ #if PY_MAJOR_VERSION >= 3
+ Py_TYPE(self)->tp_free((PyObject*)self);
+ #else
+ self->ob_type->tp_free((PyObject*)self);
+ #endif
+}
+
+static PyObject* brotli_Compressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) {
+ brotli_Compressor *self;
+ self = (brotli_Compressor *)type->tp_alloc(type, 0);
+
+ if (self != NULL) {
+ self->enc = BrotliEncoderCreateInstance(0, 0, 0);
+ }
+
+ return (PyObject *)self;
+}
+
+static int brotli_Compressor_init(brotli_Compressor *self, PyObject *args, PyObject *keywds) {
+ BrotliEncoderMode mode = (BrotliEncoderMode) -1;
+ int quality = -1;
+ int lgwin = -1;
+ int lgblock = -1;
+ int ok;
+
+ static const char *kwlist[] = {"mode", "quality", "lgwin", "lgblock", NULL};
+
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor",
+ const_cast<char **>(kwlist),
+ &mode_convertor, &mode,
+ &quality_convertor, &quality,
+ &lgwin_convertor, &lgwin,
+ &lgblock_convertor, &lgblock);
+ if (!ok)
+ return -1;
+ if (!self->enc)
+ return -1;
+
+ if ((int) mode != -1)
+ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode);
+ if (quality != -1)
+ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY, (uint32_t)quality);
+ if (lgwin != -1)
+ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
+ if (lgblock != -1)
+ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, (uint32_t)lgblock);
+
+ return 0;
+}
+
+PyDoc_STRVAR(brotli_Compressor_process_doc,
+"Process \"string\" for compression, returning a string that contains \n"
+"compressed output data. This data should be concatenated to the output \n"
+"produced by any preceding calls to the \"process()\" or flush()\" methods. \n"
+"Some or all of the input may be kept in internal buffers for later \n"
+"processing, and the compressed output data may be empty until enough input \n"
+"has been accumulated.\n"
+"\n"
+"Signature:\n"
+" compress(string)\n"
+"\n"
+"Args:\n"
+" string (bytes): The input data\n"
+"\n"
+"Returns:\n"
+" The compressed output data (bytes)\n"
+"\n"
+"Raises:\n"
+" brotli.error: If compression fails\n");
+
+static PyObject* brotli_Compressor_process(brotli_Compressor *self, PyObject *args) {
+ PyObject* ret = NULL;
+ std::vector<uint8_t> output;
+ Py_buffer input;
+ BROTLI_BOOL ok = BROTLI_TRUE;
+
+#if PY_MAJOR_VERSION >= 3
+ ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input);
+#else
+ ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input);
+#endif
+
+ if (!ok)
+ return NULL;
+
+ if (!self->enc) {
+ ok = BROTLI_FALSE;
+ goto end;
+ }
+
+ ok = compress_stream(self->enc, BROTLI_OPERATION_PROCESS,
+ &output, static_cast<uint8_t*>(input.buf), input.len);
+
+end:
+ PyBuffer_Release(&input);
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while processing the stream");
+ }
+
+ return ret;
+}
+
+PyDoc_STRVAR(brotli_Compressor_flush_doc,
+"Process all pending input, returning a string containing the remaining\n"
+"compressed data. This data should be concatenated to the output produced by\n"
+"any preceding calls to the \"process()\" or \"flush()\" methods.\n"
+"\n"
+"Signature:\n"
+" flush()\n"
+"\n"
+"Returns:\n"
+" The compressed output data (bytes)\n"
+"\n"
+"Raises:\n"
+" brotli.error: If compression fails\n");
+
+static PyObject* brotli_Compressor_flush(brotli_Compressor *self) {
+ PyObject *ret = NULL;
+ std::vector<uint8_t> output;
+ BROTLI_BOOL ok = BROTLI_TRUE;
+
+ if (!self->enc) {
+ ok = BROTLI_FALSE;
+ goto end;
+ }
+
+ ok = compress_stream(self->enc, BROTLI_OPERATION_FLUSH,
+ &output, NULL, 0);
+
+end:
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while flushing the stream");
+ }
+
+ return ret;
+}
+
+PyDoc_STRVAR(brotli_Compressor_finish_doc,
+"Process all pending input and complete all compression, returning a string\n"
+"containing the remaining compressed data. This data should be concatenated\n"
+"to the output produced by any preceding calls to the \"process()\" or\n"
+"\"flush()\" methods.\n"
+"After calling \"finish()\", the \"process()\" and \"flush()\" methods\n"
+"cannot be called again, and a new \"Compressor\" object should be created.\n"
+"\n"
+"Signature:\n"
+" finish(string)\n"
+"\n"
+"Returns:\n"
+" The compressed output data (bytes)\n"
+"\n"
+"Raises:\n"
+" brotli.error: If compression fails\n");
+
+static PyObject* brotli_Compressor_finish(brotli_Compressor *self) {
+ PyObject *ret = NULL;
+ std::vector<uint8_t> output;
+ BROTLI_BOOL ok = BROTLI_TRUE;
+
+ if (!self->enc) {
+ ok = BROTLI_FALSE;
+ goto end;
+ }
+
+ ok = compress_stream(self->enc, BROTLI_OPERATION_FINISH,
+ &output, NULL, 0);
+
+ if (ok) {
+ ok = BrotliEncoderIsFinished(self->enc);
+ }
+
+end:
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while finishing the stream");
+ }
+
+ return ret;
+}
+
+static PyMemberDef brotli_Compressor_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef brotli_Compressor_methods[] = {
+ {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc},
+ {"flush", (PyCFunction)brotli_Compressor_flush, METH_NOARGS, brotli_Compressor_flush_doc},
+ {"finish", (PyCFunction)brotli_Compressor_finish, METH_NOARGS, brotli_Compressor_finish_doc},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject brotli_CompressorType = {
+ #if PY_MAJOR_VERSION >= 3
+ PyVarObject_HEAD_INIT(NULL, 0)
+ #else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size*/
+ #endif
+ "brotli.Compressor", /* tp_name */
+ sizeof(brotli_Compressor), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)brotli_Compressor_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ brotli_Compressor_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ brotli_Compressor_methods, /* tp_methods */
+ brotli_Compressor_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)brotli_Compressor_init, /* tp_init */
+ 0, /* tp_alloc */
+ brotli_Compressor_new, /* tp_new */
+};
+
+static BROTLI_BOOL decompress_stream(BrotliDecoderState* dec,
+ std::vector<uint8_t>* output,
+ uint8_t* input, size_t input_length) {
+ BROTLI_BOOL ok = BROTLI_TRUE;
+ Py_BEGIN_ALLOW_THREADS
+
+ size_t available_in = input_length;
+ const uint8_t* next_in = input;
+ size_t available_out = 0;
+ uint8_t* next_out = NULL;
+
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+ while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ result = BrotliDecoderDecompressStream(dec,
+ &available_in, &next_in,
+ &available_out, &next_out, NULL);
+ size_t buffer_length = 0; // Request all available output.
+ const uint8_t* buffer = BrotliDecoderTakeOutput(dec, &buffer_length);
+ if (buffer_length) {
+ (*output).insert((*output).end(), buffer, buffer + buffer_length);
+ }
+ }
+ ok = result != BROTLI_DECODER_RESULT_ERROR && !available_in;
+
+ Py_END_ALLOW_THREADS
+ return ok;
+}
+
+PyDoc_STRVAR(brotli_Decompressor_doc,
+"An object to decompress a byte string.\n"
+"\n"
+"Signature:\n"
+" Decompressor()\n"
+"\n"
+"Raises:\n"
+" brotli.error: If arguments are invalid.\n");
+
+typedef struct {
+ PyObject_HEAD
+ BrotliDecoderState* dec;
+} brotli_Decompressor;
+
+static void brotli_Decompressor_dealloc(brotli_Decompressor* self) {
+ BrotliDecoderDestroyInstance(self->dec);
+ #if PY_MAJOR_VERSION >= 3
+ Py_TYPE(self)->tp_free((PyObject*)self);
+ #else
+ self->ob_type->tp_free((PyObject*)self);
+ #endif
+}
+
+static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) {
+ brotli_Decompressor *self;
+ self = (brotli_Decompressor *)type->tp_alloc(type, 0);
+
+ if (self != NULL) {
+ self->dec = BrotliDecoderCreateInstance(0, 0, 0);
+ }
+
+ return (PyObject *)self;
+}
+
+static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, PyObject *keywds) {
+ int ok;
+
+ static const char *kwlist[] = {NULL};
+
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "|:Decompressor",
+ const_cast<char **>(kwlist));
+ if (!ok)
+ return -1;
+ if (!self->dec)
+ return -1;
+
+ return 0;
+}
+
+PyDoc_STRVAR(brotli_Decompressor_process_doc,
+"Process \"string\" for decompression, returning a string that contains \n"
+"decompressed output data. This data should be concatenated to the output \n"
+"produced by any preceding calls to the \"process()\" method. \n"
+"Some or all of the input may be kept in internal buffers for later \n"
+"processing, and the decompressed output data may be empty until enough input \n"
+"has been accumulated.\n"
+"\n"
+"Signature:\n"
+" decompress(string)\n"
+"\n"
+"Args:\n"
+" string (bytes): The input data\n"
+"\n"
+"Returns:\n"
+" The decompressed output data (bytes)\n"
+"\n"
+"Raises:\n"
+" brotli.error: If decompression fails\n");
+
+static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args) {
+ PyObject* ret = NULL;
+ std::vector<uint8_t> output;
+ Py_buffer input;
+ BROTLI_BOOL ok = BROTLI_TRUE;
+
+#if PY_MAJOR_VERSION >= 3
+ ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input);
+#else
+ ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input);
+#endif
+
+ if (!ok)
+ return NULL;
+
+ if (!self->dec) {
+ ok = BROTLI_FALSE;
+ goto end;
+ }
+
+ ok = decompress_stream(self->dec, &output, static_cast<uint8_t*>(input.buf), input.len);
+
+end:
+ PyBuffer_Release(&input);
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while processing the stream");
+ }
+
+ return ret;
+}
+
+PyDoc_STRVAR(brotli_Decompressor_is_finished_doc,
+"Checks if decoder instance reached the final state.\n"
+"\n"
+"Signature:\n"
+" is_finished()\n"
+"\n"
+"Returns:\n"
+" True if the decoder is in a state where it reached the end of the input\n"
+" and produced all of the output\n"
+" False otherwise\n"
+"\n"
+"Raises:\n"
+" brotli.error: If decompression fails\n");
+
+static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) {
+ PyObject *ret = NULL;
+ std::vector<uint8_t> output;
+ BROTLI_BOOL ok = BROTLI_TRUE;
+
+ if (!self->dec) {
+ ok = BROTLI_FALSE;
+ PyErr_SetString(BrotliError, "BrotliDecoderState is NULL while checking is_finished");
+ goto end;
+ }
+
+ if (BrotliDecoderIsFinished(self->dec)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+
+end:
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while finishing the stream");
+ }
+
+ return ret;
+}
+
+static PyMemberDef brotli_Decompressor_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef brotli_Decompressor_methods[] = {
+ {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS, brotli_Decompressor_process_doc},
+ {"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject brotli_DecompressorType = {
+ #if PY_MAJOR_VERSION >= 3
+ PyVarObject_HEAD_INIT(NULL, 0)
+ #else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size*/
+ #endif
+ "brotli.Decompressor", /* tp_name */
+ sizeof(brotli_Decompressor), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)brotli_Decompressor_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ brotli_Decompressor_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ brotli_Decompressor_methods, /* tp_methods */
+ brotli_Decompressor_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)brotli_Decompressor_init, /* tp_init */
+ 0, /* tp_alloc */
+ brotli_Decompressor_new, /* tp_new */
+};
+
+PyDoc_STRVAR(brotli_decompress__doc__,
+"Decompress a compressed byte string.\n"
+"\n"
+"Signature:\n"
+" decompress(string)\n"
+"\n"
+"Args:\n"
+" string (bytes): The compressed input data.\n"
+"\n"
+"Returns:\n"
+" The decompressed byte string.\n"
+"\n"
+"Raises:\n"
+" brotli.error: If decompressor fails.\n");
+
+static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *keywds) {
+ PyObject *ret = NULL;
+ Py_buffer input;
+ const uint8_t* next_in;
+ size_t available_in;
+ int ok;
+
+ static const char *kwlist[] = {"string", NULL};
+
+#if PY_MAJOR_VERSION >= 3
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|:decompress",
+ const_cast<char **>(kwlist), &input);
+#else
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|:decompress",
+ const_cast<char **>(kwlist), &input);
+#endif
+
+ if (!ok)
+ return NULL;
+
+ std::vector<uint8_t> output;
+
+ /* >>> Pure C block; release python GIL. */
+ Py_BEGIN_ALLOW_THREADS
+
+ BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0);
+
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+ next_in = static_cast<uint8_t*>(input.buf);
+ available_in = input.len;
+ while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ size_t available_out = 0;
+ result = BrotliDecoderDecompressStream(state, &available_in, &next_in,
+ &available_out, 0, 0);
+ const uint8_t* next_out = BrotliDecoderTakeOutput(state, &available_out);
+ if (available_out != 0)
+ output.insert(output.end(), next_out, next_out + available_out);
+ }
+ ok = result == BROTLI_DECODER_RESULT_SUCCESS && !available_in;
+ BrotliDecoderDestroyInstance(state);
+
+ Py_END_ALLOW_THREADS
+ /* <<< Pure C block end. Python GIL reacquired. */
+
+ PyBuffer_Release(&input);
+ if (ok) {
+ ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size());
+ } else {
+ PyErr_SetString(BrotliError, "BrotliDecompress failed");
+ }
+
+ return ret;
+}
+
+static PyMethodDef brotli_methods[] = {
+ {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(brotli_doc, "Implementation module for the Brotli library.");
+
+#if PY_MAJOR_VERSION >= 3
+#define INIT_BROTLI PyInit__brotli
+#define CREATE_BROTLI PyModule_Create(&brotli_module)
+#define RETURN_BROTLI return m
+#define RETURN_NULL return NULL
+
+static struct PyModuleDef brotli_module = {
+ PyModuleDef_HEAD_INIT,
+ "_brotli", /* m_name */
+ brotli_doc, /* m_doc */
+ 0, /* m_size */
+ brotli_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL /* m_free */
+};
+#else
+#define INIT_BROTLI init_brotli
+#define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc)
+#define RETURN_BROTLI return
+#define RETURN_NULL return
+#endif
+
+PyMODINIT_FUNC INIT_BROTLI(void) {
+ PyObject *m = CREATE_BROTLI;
+
+ BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL);
+ if (BrotliError != NULL) {
+ Py_INCREF(BrotliError);
+ PyModule_AddObject(m, "error", BrotliError);
+ }
+
+ if (PyType_Ready(&brotli_CompressorType) < 0) {
+ RETURN_NULL;
+ }
+ Py_INCREF(&brotli_CompressorType);
+ PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType);
+
+ if (PyType_Ready(&brotli_DecompressorType) < 0) {
+ RETURN_NULL;
+ }
+ Py_INCREF(&brotli_DecompressorType);
+ PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType);
+
+ PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC);
+ PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT);
+ PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT);
+
+ char version[16];
+ snprintf(version, sizeof(version), "%d.%d.%d",
+ BROTLI_VERSION >> 24, (BROTLI_VERSION >> 12) & 0xFFF, BROTLI_VERSION & 0xFFF);
+ PyModule_AddStringConstant(m, "__version__", version);
+
+ RETURN_BROTLI;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/bro.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/bro.py
new file mode 100755
index 000000000..7a094b4c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/bro.py
@@ -0,0 +1,160 @@
+#! /usr/bin/env python
+"""Compression/decompression utility using the Brotli algorithm."""
+
+from __future__ import print_function
+import argparse
+import sys
+import os
+import platform
+
+import brotli
+
+# default values of encoder parameters
+DEFAULT_PARAMS = {
+ 'mode': brotli.MODE_GENERIC,
+ 'quality': 11,
+ 'lgwin': 22,
+ 'lgblock': 0,
+}
+
+
+def get_binary_stdio(stream):
+ """ Return the specified standard input, output or errors stream as a
+ 'raw' buffer object suitable for reading/writing binary data from/to it.
+ """
+ assert stream in ['stdin', 'stdout', 'stderr'], 'invalid stream name'
+ stdio = getattr(sys, stream)
+ if sys.version_info[0] < 3:
+ if sys.platform == 'win32':
+ # set I/O stream binary flag on python2.x (Windows)
+ runtime = platform.python_implementation()
+ if runtime == 'PyPy':
+ # the msvcrt trick doesn't work in pypy, so I use fdopen
+ mode = 'rb' if stream == 'stdin' else 'wb'
+ stdio = os.fdopen(stdio.fileno(), mode, 0)
+ else:
+ # this works with CPython -- untested on other implementations
+ import msvcrt
+ msvcrt.setmode(stdio.fileno(), os.O_BINARY)
+ return stdio
+ else:
+ # get 'buffer' attribute to read/write binary data on python3.x
+ if hasattr(stdio, 'buffer'):
+ return stdio.buffer
+ else:
+ orig_stdio = getattr(sys, '__%s__' % stream)
+ return orig_stdio.buffer
+
+
+def main(args=None):
+
+ parser = argparse.ArgumentParser(
+ prog=os.path.basename(__file__), description=__doc__)
+ parser.add_argument(
+ '--version', action='version', version=brotli.__version__)
+ parser.add_argument(
+ '-i',
+ '--input',
+ metavar='FILE',
+ type=str,
+ dest='infile',
+ help='Input file',
+ default=None)
+ parser.add_argument(
+ '-o',
+ '--output',
+ metavar='FILE',
+ type=str,
+ dest='outfile',
+ help='Output file',
+ default=None)
+ parser.add_argument(
+ '-f',
+ '--force',
+ action='store_true',
+ help='Overwrite existing output file',
+ default=False)
+ parser.add_argument(
+ '-d',
+ '--decompress',
+ action='store_true',
+ help='Decompress input file',
+ default=False)
+ params = parser.add_argument_group('optional encoder parameters')
+ params.add_argument(
+ '-m',
+ '--mode',
+ metavar='MODE',
+ type=int,
+ choices=[0, 1, 2],
+ help='The compression mode can be 0 for generic input, '
+ '1 for UTF-8 encoded text, or 2 for WOFF 2.0 font data. '
+ 'Defaults to 0.')
+ params.add_argument(
+ '-q',
+ '--quality',
+ metavar='QUALITY',
+ type=int,
+ choices=list(range(0, 12)),
+ help='Controls the compression-speed vs compression-density '
+ 'tradeoff. The higher the quality, the slower the '
+ 'compression. Range is 0 to 11. Defaults to 11.')
+ params.add_argument(
+ '--lgwin',
+ metavar='LGWIN',
+ type=int,
+ choices=list(range(10, 25)),
+ help='Base 2 logarithm of the sliding window size. Range is '
+ '10 to 24. Defaults to 22.')
+ params.add_argument(
+ '--lgblock',
+ metavar='LGBLOCK',
+ type=int,
+ choices=[0] + list(range(16, 25)),
+ help='Base 2 logarithm of the maximum input block size. '
+ 'Range is 16 to 24. If set to 0, the value will be set based '
+ 'on the quality. Defaults to 0.')
+ # set default values using global DEFAULT_PARAMS dictionary
+ parser.set_defaults(**DEFAULT_PARAMS)
+
+ options = parser.parse_args(args=args)
+
+ if options.infile:
+ if not os.path.isfile(options.infile):
+ parser.error('file "%s" not found' % options.infile)
+ with open(options.infile, 'rb') as infile:
+ data = infile.read()
+ else:
+ if sys.stdin.isatty():
+ # interactive console, just quit
+ parser.error('no input')
+ infile = get_binary_stdio('stdin')
+ data = infile.read()
+
+ if options.outfile:
+ if os.path.isfile(options.outfile) and not options.force:
+ parser.error('output file exists')
+ outfile = open(options.outfile, 'wb')
+ else:
+ outfile = get_binary_stdio('stdout')
+
+ try:
+ if options.decompress:
+ data = brotli.decompress(data)
+ else:
+ data = brotli.compress(
+ data,
+ mode=options.mode,
+ quality=options.quality,
+ lgwin=options.lgwin,
+ lgblock=options.lgblock)
+ except brotli.error as e:
+ parser.exit(1,
+ 'bro: error: %s: %s' % (e, options.infile or 'sys.stdin'))
+
+ outfile.write(data)
+ outfile.close()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/brotli.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/brotli.py
new file mode 100644
index 000000000..d66966ba6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/brotli.py
@@ -0,0 +1,56 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+"""Functions to compress and decompress data using the Brotli library."""
+
+import _brotli
+
+
+# The library version.
+__version__ = _brotli.__version__
+
+# The compression mode.
+MODE_GENERIC = _brotli.MODE_GENERIC
+MODE_TEXT = _brotli.MODE_TEXT
+MODE_FONT = _brotli.MODE_FONT
+
+# The Compressor object.
+Compressor = _brotli.Compressor
+
+# The Decompressor object.
+Decompressor = _brotli.Decompressor
+
+# Compress a byte string.
+def compress(string, mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0):
+ """Compress a byte string.
+
+ Args:
+ string (bytes): The input data.
+ mode (int, optional): The compression mode can be MODE_GENERIC (default),
+ MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0).
+ quality (int, optional): Controls the compression-speed vs compression-
+ density tradeoff. The higher the quality, the slower the compression.
+ Range is 0 to 11. Defaults to 11.
+ lgwin (int, optional): Base 2 logarithm of the sliding window size. Range
+ is 10 to 24. Defaults to 22.
+ lgblock (int, optional): Base 2 logarithm of the maximum input block size.
+ Range is 16 to 24. If set to 0, the value will be set based on the
+ quality. Defaults to 0.
+
+ Returns:
+ The compressed byte string.
+
+ Raises:
+ brotli.error: If arguments are invalid, or compressor fails.
+ """
+ compressor = Compressor(mode=mode, quality=quality, lgwin=lgwin,
+ lgblock=lgblock)
+ return compressor.process(string) + compressor.finish()
+
+# Decompress a compressed byte string.
+decompress = _brotli.decompress
+
+# Raised if compression or decompression fails.
+error = _brotli.error
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/__init__.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/__init__.py
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/_test_utils.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/_test_utils.py
new file mode 100644
index 000000000..104e6548e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/_test_utils.py
@@ -0,0 +1,112 @@
+from __future__ import print_function
+import filecmp
+import glob
+import itertools
+import os
+import sys
+import sysconfig
+import tempfile
+import unittest
+
+
+project_dir = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
+src_dir = os.path.join(project_dir, 'python')
+test_dir = os.path.join(project_dir, 'tests')
+
+python_exe = sys.executable or 'python'
+bro_path = os.path.join(src_dir, 'bro.py')
+BRO_ARGS = [python_exe, bro_path]
+
+# Get the platform/version-specific build folder.
+# By default, the distutils build base is in the same location as setup.py.
+platform_lib_name = 'lib.{platform}-{version[0]}.{version[1]}'.format(
+ platform=sysconfig.get_platform(), version=sys.version_info)
+build_dir = os.path.join(project_dir, 'bin', platform_lib_name)
+
+# Prepend the build folder to sys.path and the PYTHONPATH environment variable.
+if build_dir not in sys.path:
+ sys.path.insert(0, build_dir)
+TEST_ENV = os.environ.copy()
+if 'PYTHONPATH' not in TEST_ENV:
+ TEST_ENV['PYTHONPATH'] = build_dir
+else:
+ TEST_ENV['PYTHONPATH'] = build_dir + os.pathsep + TEST_ENV['PYTHONPATH']
+
+TESTDATA_DIR = os.path.join(test_dir, 'testdata')
+
+TESTDATA_FILES = [
+ 'empty', # Empty file
+ '10x10y', # Small text
+ 'alice29.txt', # Large text
+ 'random_org_10k.bin', # Small data
+ 'mapsdatazrh', # Large data
+]
+
+TESTDATA_PATHS = [os.path.join(TESTDATA_DIR, f) for f in TESTDATA_FILES]
+
+TESTDATA_PATHS_FOR_DECOMPRESSION = glob.glob(
+ os.path.join(TESTDATA_DIR, '*.compressed'))
+
+TEMP_DIR = tempfile.mkdtemp()
+
+
+def get_temp_compressed_name(filename):
+ return os.path.join(TEMP_DIR, os.path.basename(filename + '.bro'))
+
+
+def get_temp_uncompressed_name(filename):
+ return os.path.join(TEMP_DIR, os.path.basename(filename + '.unbro'))
+
+
+def bind_method_args(method, *args, **kwargs):
+ return lambda self: method(self, *args, **kwargs)
+
+
+def generate_test_methods(test_case_class,
+ for_decompression=False,
+ variants=None):
+ # Add test methods for each test data file. This makes identifying problems
+ # with specific compression scenarios easier.
+ if for_decompression:
+ paths = TESTDATA_PATHS_FOR_DECOMPRESSION
+ else:
+ paths = TESTDATA_PATHS
+ opts = []
+ if variants:
+ opts_list = []
+ for k, v in variants.items():
+ opts_list.append([r for r in itertools.product([k], v)])
+ for o in itertools.product(*opts_list):
+ opts_name = '_'.join([str(i) for i in itertools.chain(*o)])
+ opts_dict = dict(o)
+ opts.append([opts_name, opts_dict])
+ else:
+ opts.append(['', {}])
+ for method in [m for m in dir(test_case_class) if m.startswith('_test')]:
+ for testdata in paths:
+ for (opts_name, opts_dict) in opts:
+ f = os.path.splitext(os.path.basename(testdata))[0]
+ name = 'test_{method}_{options}_{file}'.format(
+ method=method, options=opts_name, file=f)
+ func = bind_method_args(
+ getattr(test_case_class, method), testdata, **opts_dict)
+ setattr(test_case_class, name, func)
+
+
+class TestCase(unittest.TestCase):
+
+ def tearDown(self):
+ for f in TESTDATA_PATHS:
+ try:
+ os.unlink(get_temp_compressed_name(f))
+ except OSError:
+ pass
+ try:
+ os.unlink(get_temp_uncompressed_name(f))
+ except OSError:
+ pass
+
+ def assertFilesMatch(self, first, second):
+ self.assertTrue(
+ filecmp.cmp(first, second, shallow=False),
+ 'File {} differs from {}'.format(first, second))
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/bro_test.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/bro_test.py
new file mode 100644
index 000000000..b55129def
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/bro_test.py
@@ -0,0 +1,102 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import subprocess
+import unittest
+
+from . import _test_utils
+import brotli
+
+BRO_ARGS = _test_utils.BRO_ARGS
+TEST_ENV = _test_utils.TEST_ENV
+
+
+def _get_original_name(test_data):
+ return test_data.split('.compressed')[0]
+
+
+class TestBroDecompress(_test_utils.TestCase):
+
+ def _check_decompression(self, test_data):
+ # Verify decompression matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ original = _get_original_name(test_data)
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _decompress_file(self, test_data):
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ args = BRO_ARGS + ['-f', '-d', '-i', test_data, '-o', temp_uncompressed]
+ subprocess.check_call(args, env=TEST_ENV)
+
+ def _decompress_pipe(self, test_data):
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ args = BRO_ARGS + ['-d']
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ subprocess.check_call(
+ args, stdin=in_file, stdout=out_file, env=TEST_ENV)
+
+ def _test_decompress_file(self, test_data):
+ self._decompress_file(test_data)
+ self._check_decompression(test_data)
+
+ def _test_decompress_pipe(self, test_data):
+ self._decompress_pipe(test_data)
+ self._check_decompression(test_data)
+
+
+_test_utils.generate_test_methods(TestBroDecompress, for_decompression=True)
+
+
+class TestBroCompress(_test_utils.TestCase):
+
+ VARIANTS = {'quality': (1, 6, 9, 11), 'lgwin': (10, 15, 20, 24)}
+
+ def _check_decompression(self, test_data, **kwargs):
+ # Write decompression to temp file and verify it matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ original = test_data
+ args = BRO_ARGS + ['-f', '-d']
+ args.extend(['-i', temp_compressed, '-o', temp_uncompressed])
+ subprocess.check_call(args, env=TEST_ENV)
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _compress_file(self, test_data, **kwargs):
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ args = BRO_ARGS + ['-f']
+ if 'quality' in kwargs:
+ args.extend(['-q', str(kwargs['quality'])])
+ if 'lgwin' in kwargs:
+ args.extend(['--lgwin', str(kwargs['lgwin'])])
+ args.extend(['-i', test_data, '-o', temp_compressed])
+ subprocess.check_call(args, env=TEST_ENV)
+
+ def _compress_pipe(self, test_data, **kwargs):
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ args = BRO_ARGS
+ if 'quality' in kwargs:
+ args.extend(['-q', str(kwargs['quality'])])
+ if 'lgwin' in kwargs:
+ args.extend(['--lgwin', str(kwargs['lgwin'])])
+ with open(temp_compressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ subprocess.check_call(
+ args, stdin=in_file, stdout=out_file, env=TEST_ENV)
+
+ def _test_compress_file(self, test_data, **kwargs):
+ self._compress_file(test_data, **kwargs)
+ self._check_decompression(test_data)
+
+ def _test_compress_pipe(self, test_data, **kwargs):
+ self._compress_pipe(test_data, **kwargs)
+ self._check_decompression(test_data)
+
+
+_test_utils.generate_test_methods(
+ TestBroCompress, variants=TestBroCompress.VARIANTS)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compress_test.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compress_test.py
new file mode 100644
index 000000000..46ff68f50
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compress_test.py
@@ -0,0 +1,41 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import unittest
+
+from . import _test_utils
+import brotli
+
+
+class TestCompress(_test_utils.TestCase):
+
+ VARIANTS = {'quality': (1, 6, 9, 11), 'lgwin': (10, 15, 20, 24)}
+
+ def _check_decompression(self, test_data, **kwargs):
+ kwargs = {}
+ # Write decompression to temp file and verify it matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ original = test_data
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(temp_compressed, 'rb') as in_file:
+ out_file.write(brotli.decompress(in_file.read(), **kwargs))
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _compress(self, test_data, **kwargs):
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ with open(temp_compressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ out_file.write(brotli.compress(in_file.read(), **kwargs))
+
+ def _test_compress(self, test_data, **kwargs):
+ self._compress(test_data, **kwargs)
+ self._check_decompression(test_data, **kwargs)
+
+
+_test_utils.generate_test_methods(TestCompress, variants=TestCompress.VARIANTS)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compressor_test.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compressor_test.py
new file mode 100644
index 000000000..2d4791996
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/compressor_test.py
@@ -0,0 +1,94 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import functools
+import unittest
+
+from . import _test_utils
+import brotli
+
+
+# Do not inherit from TestCase here to ensure that test methods
+# are not run automatically and instead are run as part of a specific
+# configuration below.
+class _TestCompressor(object):
+
+ CHUNK_SIZE = 2048
+
+ def tearDown(self):
+ self.compressor = None
+
+ def _check_decompression(self, test_data):
+ # Write decompression to temp file and verify it matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ original = test_data
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(temp_compressed, 'rb') as in_file:
+ out_file.write(brotli.decompress(in_file.read()))
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _test_single_process(self, test_data):
+ # Write single-shot compression to temp file.
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ with open(temp_compressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ out_file.write(self.compressor.process(in_file.read()))
+ out_file.write(self.compressor.finish())
+ self._check_decompression(test_data)
+
+ def _test_multiple_process(self, test_data):
+ # Write chunked compression to temp file.
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ with open(temp_compressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ read_chunk = functools.partial(in_file.read, self.CHUNK_SIZE)
+ for data in iter(read_chunk, b''):
+ out_file.write(self.compressor.process(data))
+ out_file.write(self.compressor.finish())
+ self._check_decompression(test_data)
+
+ def _test_multiple_process_and_flush(self, test_data):
+ # Write chunked and flushed compression to temp file.
+ temp_compressed = _test_utils.get_temp_compressed_name(test_data)
+ with open(temp_compressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ read_chunk = functools.partial(in_file.read, self.CHUNK_SIZE)
+ for data in iter(read_chunk, b''):
+ out_file.write(self.compressor.process(data))
+ out_file.write(self.compressor.flush())
+ out_file.write(self.compressor.finish())
+ self._check_decompression(test_data)
+
+
+_test_utils.generate_test_methods(_TestCompressor)
+
+
+class TestCompressorQuality1(_TestCompressor, _test_utils.TestCase):
+
+ def setUp(self):
+ self.compressor = brotli.Compressor(quality=1)
+
+
+class TestCompressorQuality6(_TestCompressor, _test_utils.TestCase):
+
+ def setUp(self):
+ self.compressor = brotli.Compressor(quality=6)
+
+
+class TestCompressorQuality9(_TestCompressor, _test_utils.TestCase):
+
+ def setUp(self):
+ self.compressor = brotli.Compressor(quality=9)
+
+
+class TestCompressorQuality11(_TestCompressor, _test_utils.TestCase):
+
+ def setUp(self):
+ self.compressor = brotli.Compressor(quality=11)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompress_test.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompress_test.py
new file mode 100644
index 000000000..814e56332
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompress_test.py
@@ -0,0 +1,42 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import unittest
+
+from . import _test_utils
+import brotli
+
+
+def _get_original_name(test_data):
+ return test_data.split('.compressed')[0]
+
+
+class TestDecompress(_test_utils.TestCase):
+
+ def _check_decompression(self, test_data):
+ # Verify decompression matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ original = _get_original_name(test_data)
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _decompress(self, test_data):
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ out_file.write(brotli.decompress(in_file.read()))
+
+ def _test_decompress(self, test_data):
+ self._decompress(test_data)
+ self._check_decompression(test_data)
+
+ def test_garbage_appended(self):
+ with self.assertRaises(brotli.error):
+ brotli.decompress(brotli.compress(b'a') + b'a')
+
+
+_test_utils.generate_test_methods(TestDecompress, for_decompression=True)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompressor_test.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompressor_test.py
new file mode 100644
index 000000000..05918ada8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/python/tests/decompressor_test.py
@@ -0,0 +1,59 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import functools
+import unittest
+
+from . import _test_utils
+import brotli
+
+
+def _get_original_name(test_data):
+ return test_data.split('.compressed')[0]
+
+
+class TestDecompressor(_test_utils.TestCase):
+
+ CHUNK_SIZE = 1
+
+ def setUp(self):
+ self.decompressor = brotli.Decompressor()
+
+ def tearDown(self):
+ self.decompressor = None
+
+ def _check_decompression(self, test_data):
+ # Verify decompression matches the original.
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ original = _get_original_name(test_data)
+ self.assertFilesMatch(temp_uncompressed, original)
+
+ def _decompress(self, test_data):
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ read_chunk = functools.partial(in_file.read, self.CHUNK_SIZE)
+ for data in iter(read_chunk, b''):
+ out_file.write(self.decompressor.process(data))
+ self.assertTrue(self.decompressor.is_finished())
+
+ def _test_decompress(self, test_data):
+ self._decompress(test_data)
+ self._check_decompression(test_data)
+
+ def test_garbage_appended(self):
+ with self.assertRaises(brotli.error):
+ self.decompressor.process(brotli.compress(b'a') + b'a')
+
+ def test_already_finished(self):
+ self.decompressor.process(brotli.compress(b'a'))
+ with self.assertRaises(brotli.error):
+ self.decompressor.process(b'a')
+
+
+_test_utils.generate_test_methods(TestDecompressor, for_decompression=True)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD
new file mode 100755
index 000000000..7b7d81b83
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD
@@ -0,0 +1,44 @@
+# Description: brotli research tools.
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # MIT
+
+cc_library(
+ name = "dm",
+ srcs = ["deorummolae.cc"],
+ hdrs = [
+ "deorummolae.h",
+ "esaxx/sais.hxx",
+ ],
+)
+
+cc_library(
+ name = "durchschlag",
+ srcs = ["durchschlag.cc"],
+ hdrs = ["durchschlag.h"],
+ deps = ["@divsufsort//:libdivsufsort"],
+)
+
+cc_library(
+ name = "sieve",
+ srcs = ["sieve.cc"],
+ hdrs = ["sieve.h"],
+)
+
+cc_binary(
+ name = "dictionary_generator",
+ srcs = ["dictionary_generator.cc"],
+ deps = [
+ ":dm",
+ ":durchschlag",
+ ":sieve",
+ ],
+)
+
+cc_binary(
+ name = "brotli_decoder",
+ srcs = ["brotli_decoder.c"],
+ linkstatic = 1,
+ deps = ["@org_brotli//:brotlidec"],
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD.libdivsufsort b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD.libdivsufsort
new file mode 100644
index 000000000..ce60e9c20
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/BUILD.libdivsufsort
@@ -0,0 +1,55 @@
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "libdivsufsort",
+ srcs = [
+ "lib/divsufsort.c",
+ "lib/sssort.c",
+ "lib/trsort.c",
+ "lib/utils.c",
+ ],
+ hdrs = [
+ "include/config.h",
+ "include/divsufsort.h",
+ "include/divsufsort_private.h",
+ ],
+ copts = [
+ "-DHAVE_CONFIG_H=1",
+ ],
+ includes = ["include"],
+)
+
+commom_awk_replaces = (
+ "gsub(/#cmakedefine/, \"#define\"); " +
+ "gsub(/@DIVSUFSORT_EXPORT@/, \"\"); " +
+ "gsub(/@DIVSUFSORT_IMPORT@/, \"\"); " +
+ "gsub(/@INLINE@/, \"inline\"); " +
+ "gsub(/@INCFILE@/, \"#include <inttypes.h>\"); " +
+ "gsub(/@SAUCHAR_TYPE@/, \"uint8_t\"); " +
+ "gsub(/@SAINT32_TYPE@/, \"int32_t\"); " +
+ "gsub(/@SAINT_PRId@/, \"PRId32\"); "
+)
+
+genrule(
+ name = "config_h",
+ srcs = ["include/config.h.cmake"],
+ outs = ["include/config.h"],
+ cmd = ("awk '{ " +
+ "gsub(/@HAVE_IO_H 1@/, \"HAVE_IO_H 0\"); " +
+ commom_awk_replaces +
+ "print; }' $(<) > $(@)"),
+)
+
+genrule(
+ name = "divsufsort_h",
+ srcs = ["include/divsufsort.h.cmake"],
+ outs = ["include/divsufsort.h"],
+ cmd = ("awk '{ " +
+ "gsub(/@W64BIT@/, \"\"); " +
+ "gsub(/@SAINDEX_TYPE@/, \"int32_t\"); " +
+ "gsub(/@SAINDEX_PRId@/, \"PRId32\"); " +
+ commom_awk_replaces +
+ "print; }' $(<) > $(@)"),
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/Makefile b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/Makefile
new file mode 100644
index 000000000..751b3162c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/Makefile
@@ -0,0 +1,17 @@
+CC = g++
+CFLAGS += -O2
+CPPFLAGS += -std=c++11
+SOURCES = $(wildcard *.cc)
+EXECUTABLES = $(SOURCES:.cc=)
+BINDIR = bin
+
+all: $(EXECUTABLES)
+
+$(BINDIR):
+ mkdir -p $@
+
+$(EXECUTABLES): $(BINDIR)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(addsuffix .cc, $@) -o $(BINDIR)/$@ -lgflags_nothreads
+
+clean:
+ rm -rf $(BINDIR)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/README.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/README.md
new file mode 100644
index 000000000..9c87ef820
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/README.md
@@ -0,0 +1,67 @@
+## Introduction
+
+In this directory we publish simple tools to analyze backward reference distance distributions in LZ77 compression. We developed these tools to be able to make more efficient encoding of distances in large-window brotli. In large-window compression the average cost of a backward reference distance is higher, and this may allow for more advanced encoding strategies, such as delta coding or an increase in context size, to bring significant compression density improvements. Our tools visualize the backward references as histogram images, i.e., one pixel in the image shows how many distances of a certain range exist at a certain locality in the data. The human visual system is excellent at pattern detection, so we tried to roughly identify patterns visually before going into more quantitative analysis. These tools can turn out to be useful in development of other LZ77-based compressors and we hope you try them out.
+
+
+## Tools
+### find\_opt\_references
+
+This tool generates optimal (match-length-wise) backward references for every position in the input files and stores them in `*.dist` file described below.
+
+Example usage:
+
+ find_opt_references input.txt output.dist
+
+### draw\_histogram
+
+This tool generates a visualization of the distribution of backward references stored in `*.dist` file. The original file size has to be specified as a second parameter. The output is a grayscale PGM (binary) image.
+
+Example usage:
+
+ draw_histogram input.dist 65536 output.pgm
+
+Here's an example of resulting image:
+
+![](img/enwik9_brotli.png)
+
+### draw\_diff
+
+This tool generates a diff PPM (binary) image between two input 8-bit PGM (binary) images. Input images must be of same size. Useful for comparing different backward references distributions for same input file. Normally used for comparison of output images from `draw_histogram` tool.
+
+Example usage:
+
+ draw_diff image1.pgm image2.pgm diff.ppm
+
+For example the diff of this image
+
+![](img/enwik9_brotli.png)
+
+and this image
+
+![](img/enwik9_opt.png)
+
+looks like this:
+
+![](img/enwik9_diff.png)
+
+
+## Backward distance file format
+
+The format of `*.dist` files is as follows:
+
+ [[ 0| match length][ 1|position|distance]...]
+ [1 byte| 4 bytes][1 byte| 4 bytes| 4 bytes]
+
+More verbose explanation: for each backward reference there is a position-distance pair, also a copy length may be specified. Copy length is prefixed with flag byte 0, position-distance pair is prefixed with flag byte 1. Each number is a 32-bit integer. Copy length always comes before position-distance pair. Standalone copy length is allowed, in this case it is ignored.
+
+Here's an example of how to read from `*.dist` file:
+
+```c++
+#include "read_dist.h"
+
+FILE* f;
+int copy, pos, dist;
+while (ReadBackwardReference(fin, &copy, &pos, &dist)) {
+ ...
+}
+```
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/WORKSPACE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/WORKSPACE
new file mode 100644
index 000000000..bb0f8ca08
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/WORKSPACE
@@ -0,0 +1,12 @@
+workspace(name = "org_brotli_research")
+
+local_repository(
+ name = "org_brotli",
+ path = "..",
+)
+
+new_local_repository(
+ name = "divsufsort",
+ build_file = "BUILD.libdivsufsort",
+ path = "libdivsufsort",
+)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotli_decoder.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotli_decoder.c
new file mode 100644
index 000000000..b1d556d23
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotli_decoder.c
@@ -0,0 +1,93 @@
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <brotli/decode.h>
+
+#define BUFFER_SIZE (1u << 20)
+
+typedef struct Context {
+ FILE* fin;
+ FILE* fout;
+ uint8_t* input_buffer;
+ uint8_t* output_buffer;
+ BrotliDecoderState* decoder;
+} Context;
+
+void init(Context* ctx) {
+ ctx->fin = 0;
+ ctx->fout = 0;
+ ctx->input_buffer = 0;
+ ctx->output_buffer = 0;
+ ctx->decoder = 0;
+}
+
+void cleanup(Context* ctx) {
+ if (ctx->decoder) BrotliDecoderDestroyInstance(ctx->decoder);
+ if (ctx->output_buffer) free(ctx->output_buffer);
+ if (ctx->input_buffer) free(ctx->input_buffer);
+ if (ctx->fout) fclose(ctx->fout);
+ if (ctx->fin) fclose(ctx->fin);
+}
+
+void fail(Context* ctx, const char* message) {
+ fprintf(stderr, "%s\n", message);
+ exit(1);
+}
+
+int main(int argc, char** argv) {
+ Context ctx;
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
+ size_t available_in;
+ const uint8_t* next_in;
+ size_t available_out = BUFFER_SIZE;
+ uint8_t* next_out;
+ init(&ctx);
+
+ ctx.fin = fdopen(STDIN_FILENO, "rb");
+ if (!ctx.fin) fail(&ctx, "can't open input file");
+ ctx.fout = fdopen(STDOUT_FILENO, "wb");
+ if (!ctx.fout) fail(&ctx, "can't open output file");
+ ctx.input_buffer = (uint8_t*)malloc(BUFFER_SIZE);
+ if (!ctx.input_buffer) fail(&ctx, "out of memory / input buffer");
+ ctx.output_buffer = (uint8_t*)malloc(BUFFER_SIZE);
+ if (!ctx.output_buffer) fail(&ctx, "out of memory / output buffer");
+ ctx.decoder = BrotliDecoderCreateInstance(0, 0, 0);
+ if (!ctx.decoder) fail(&ctx, "out of memory / decoder");
+ BrotliDecoderSetParameter(ctx.decoder, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1);
+
+ next_out = ctx.output_buffer;
+ while (1) {
+ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
+ if (feof(ctx.fin)) break;
+ available_in = fread(ctx.input_buffer, 1, BUFFER_SIZE, ctx.fin);
+ next_in = ctx.input_buffer;
+ if (ferror(ctx.fin)) break;
+ } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ fwrite(ctx.output_buffer, 1, BUFFER_SIZE, ctx.fout);
+ if (ferror(ctx.fout)) break;
+ available_out = BUFFER_SIZE;
+ next_out = ctx.output_buffer;
+ } else {
+ break;
+ }
+ result = BrotliDecoderDecompressStream(
+ ctx.decoder, &available_in, &next_in, &available_out, &next_out, 0);
+ }
+ if (next_out != ctx.output_buffer) {
+ fwrite(ctx.output_buffer, 1, next_out - ctx.output_buffer, ctx.fout);
+ }
+ if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(ctx.fout)) {
+ fail(&ctx, "failed to write output");
+ } else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
+ fail(&ctx, "corrupt input");
+ }
+ cleanup(&ctx);
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotlidump.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotlidump.py
new file mode 100644
index 000000000..701893456
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/brotlidump.py
@@ -0,0 +1,2362 @@
+#!python3
+"""Program to dump contents of Brotli compressed files showing the compression format.
+Jurjen N.E. Bos, 2016.
+I found the following issues with the Brotli format:
+- The distance alphabet has size 16+(48<<POSTFIX),
+ but the last symbols are useless.
+ It could be lowered to 16+(44-POSTFIX<<POSTFIX), and this could matter.
+- The block type code is useless if NBLTYPES==2, you would only need 1 symbol
+ anyway, so why don't you just switch to "the other" type?
+"""
+import struct
+from operator import itemgetter, methodcaller
+from itertools import accumulate, repeat
+from collections import defaultdict, deque
+from functools import partial
+
+class InvalidStream(Exception): pass
+#lookup table
+L, I, D = "literal", "insert&copy", "distance"
+pL, pI, pD = 'P'+L, 'P'+I, 'P'+D
+
+def outputCharFormatter(c):
+ """Show character in readable format
+ """
+ #TODO 2: allow hex only output
+ if 32<c<127: return chr(c)
+ elif c==10: return '\\n'
+ elif c==13: return '\\r'
+ elif c==32: return '" "'
+ else: return '\\x{:02x}'.format(c)
+
+def outputFormatter(s):
+ """Show string or char.
+ """
+ result = ''
+ def formatSubString(s):
+ for c in s:
+ if c==32: yield ' '
+ else: yield outputCharFormatter(c)
+ if len(result)<200: return ''.join(formatSubString(s))
+ else:
+ return ''.join(formatSubString(s[:100]))+'...'+ \
+ ''.join(formatSubString(s[-100:]))
+
+
+class BitStream:
+ """Represent a bytes object. Can read bits and prefix codes the way
+ Brotli does.
+ """
+ def __init__(self, byteString):
+ self.data = byteString
+ #position in bits: byte pos is pos>>3, bit pos is pos&7
+ self.pos = 0
+
+ def __repr__(self):
+ """Representation
+ >>> olleke
+ BitStream(pos=0:0)
+ """
+ return "BitStream(pos={:x}:{})".format(self.pos>>3, self.pos&7)
+
+ def read(self, n):
+ """Read n bits from the stream and return as an integer.
+ Produces zero bits beyond the stream.
+ >>> olleke.data[0]==27
+ True
+ >>> olleke.read(5)
+ 27
+
+ >>> olleke
+ BitStream(pos=0:5)
+ """
+ value = self.peek(n)
+ self.pos += n
+ if self.pos>len(self.data)*8:
+ raise ValueError('Read past end of stream')
+ return value
+
+ def peek(self, n):
+ """Peek an n bit integer from the stream without updating the pointer.
+ It is not an error to read beyond the end of the stream.
+ >>> olleke.data[:2]==b'\x1b\x2e' and 0x2e1b==11803
+ True
+ >>> olleke.peek(15)
+ 11803
+ >>> hex(olleke.peek(32))
+ '0x2e1b'
+ """
+ #read bytes that contain the data: self.data[self.pos>>3:self.pos+n+7>>3]
+ #convert to int: int.from_bytes(..., 'little')
+ #shift out the bits from the first byte: >>(self.pos&7)
+ #mask unwanted bits: & (1<<n)-1
+ return int.from_bytes(
+ self.data[self.pos>>3:self.pos+n+7>>3],
+ 'little')>>(self.pos&7) & (1<<n)-1
+
+ def readBytes(self, n):
+ """Read n bytes from the stream on a byte boundary.
+ """
+ if self.pos&7: raise ValueError('readBytes: need byte boundary')
+ result = self.data[self.pos>>3:(self.pos>>3)+n]
+ self.pos += 8*n
+ return result
+
+#-----------------------Symbol-------------------------------------------
+class Symbol:
+ """A symbol in a code.
+ Refers back to the code that contains it.
+ Index is the place in the alphabet of the symbol.
+ """
+ __slots__ = 'code', 'index'
+ def __init__(self, code, value):
+ self.code = code
+ self.index = value
+
+ def __repr__(self):
+ return 'Symbol({}, {})'.format(self.code.name, self.index)
+
+ def __len__(self):
+ """Number of bits in the prefix notation of this symbol
+ """
+ return self.code.length(self.index)
+
+ def __int__(self):
+ return self.index
+
+ #these routines call equivalent routine in Code class
+ def bitPattern(self):
+ """Value of the symbol in the stream
+ """
+ return self.code.bitPattern(self.index)
+
+ def extraBits(self):
+ """Number of extra bits to read for this symbol
+ """
+ return self.code.extraBits(self.index)
+
+ def __str__(self):
+ """Short descriptor of the symbol without extra bits.
+ """
+ return self.code.mnemonic(self.index)
+
+ #requiring optional extra bits, if self.code supports them
+ def value(self, extra=None):
+ """The value used for processing. Can be a tuple.
+ with optional extra bits
+ """
+ if isinstance(self.code, WithExtra):
+ if not 0<=extra<1<<self.extraBits():
+ raise ValueError("value: extra value doesn't fit in extraBits")
+ return self.code.value(self.index, extra)
+ if extra is not None:
+ raise ValueError('value: no extra bits for this code')
+ return self.code.value(self.index)
+
+ def explanation(self, extra=None):
+ """Long explanation of the value from the numeric value
+ with optional extra bits
+ Used by Layout.verboseRead when printing the value
+ """
+ if isinstance(self.code, WithExtra):
+ return self.code.callback(self, extra)
+ return self.code.callback(self)
+
+#========================Code definitions==================================
+class RangeDecoder:
+ """A decoder for the Code class that assumes the symbols
+ are encoded consecutively in binary.
+ It all depends on the "alphabetSize" property.
+ The range runs from 0 to alphabetSize-1.
+ This is the default decoder.
+ """
+ def __init__(self, *, alphabetSize=None, bitLength=None, **args):
+ if bitLength is not None: alphabetSize = 1<<bitLength
+ if alphabetSize is not None:
+ self.alphabetSize = alphabetSize
+ self.maxLength = (alphabetSize-1).bit_length()
+
+ def __len__(self):
+ return self.alphabetSize
+
+ def __iter__(self):
+ """Produce all symbols.
+ """
+ return map(partial(Symbol, self), range(len(self)))
+
+ def __getitem__(self, index):
+ if index>=self.alphabetSize: raise ValueError('index out of range')
+ return Symbol(self, index)
+
+ def bitPattern(self, index):
+ return '{:0{}b}'.format(index, self.maxLength)
+
+ def length(self, index):
+ """Encoding length of given symbol.
+ Does not depend on index in this case.
+ """
+ return self.maxLength
+
+ def decodePeek(self, data):
+ """Find which symbol index matches the given data (from peek, as a number)
+ and return the number of bits decoded.
+ Can also be used to figure out length of a symbol.
+ """
+ return self.maxLength, Symbol(self, data&(1<<self.maxLength)-1)
+
+class PrefixDecoder:
+ """A decoder for the Code class that uses a prefix code.
+ The code is determined by encoding:
+ encode[p] gives the index corresponding to bit pattern p.
+ Used setDecode(decodeTable) to switch the decoder from the default
+ to a prefix decoder, or pass decodeTable at init.
+ You can also use setLength(lengthTable)
+ to define the encoding from the lengths.
+ The set of symbol values does not need to be consecutive.
+ """
+ def __init__(self, *, decodeTable=None, **args):
+ if decodeTable is not None: self.setDecode(decodeTable)
+
+ def __len__(self):
+ return len(self.decodeTable)
+
+ def __iter__(self):
+ def revBits(index):
+ return self.bitPattern(index)[::-1]
+ return (
+ Symbol(self, index)
+ for index in sorted(self.decodeTable.values(), key=revBits)
+ )
+
+ def __getitem__(self, index):
+ if index not in self.lengthTable:
+ raise ValueError('No symbol {}[{}]'.format(
+ self.__class__.__name__, index))
+ return Symbol(self, index)
+
+ def bitPattern(self, index):
+ bits = next(b for (b,s) in self.decodeTable.items() if s==index)
+ return '{:0{}b}'.format(bits, self.length(index))
+
+ def length(self, index):
+ """Encoding length of given symbol.
+ """
+ return self.lengthTable[index]
+
+ def decodePeek(self, data):
+ """Find which symbol index matches the given data (from peek, as a number)
+ and return the number of bits decoded.
+ Can also be used to figure out length of a symbol.
+ """
+ #do binary search for word length
+ #invariant: lo<=length<=hi
+ lo, hi = self.minLength, self.maxLength
+ while lo<=hi:
+ mid = lo+hi>>1
+ #note lo<=mid<hi at this point
+ mask = (1<<mid)-1
+ #lets see what happens if we guess length is mid
+ try: index = self.decodeTable[data&mask]
+ except KeyError:
+ #too many bits specified, reduce estimated length
+ hi = mid-1
+ continue
+ #we found a symbol, but there could be a longer match
+ symbolLength = self.lengthTable[index]
+ if symbolLength<=mid:
+ #all bits match, symbol must be right
+ return symbolLength, Symbol(self, index)
+ #there must be more bits to match
+ lo = mid+1
+ return lo, Symbol(self, index)
+
+ #routine to set up the tables
+ def setDecode(self, decodeTable):
+ """Store decodeTable,
+ and compute lengthTable, minLength, maxLength from encodings.
+ """
+ self.decodeTable = decodeTable
+ #set of symbols with unknown length
+ todo = set(decodeTable)
+ #bit size under investigation
+ maskLength = 0
+ lengthTable = {}
+ while todo:
+ mask = (1<<maskLength)-1
+ #split the encodings that we didn't find yet using b bits
+ splitSymbols = defaultdict(list)
+ for s in todo: splitSymbols[s&mask].append(s)
+ #unique encodings have a length of maskLength bits
+ #set length, and remove from todo list
+ for s,subset in splitSymbols.items():
+ if len(subset)==1:
+ lengthTable[self.decodeTable[s]] = maskLength
+ todo.remove(s)
+ #now investigate with longer mask
+ maskLength +=1
+ #save result
+ self.lengthTable = lengthTable
+ self.minLength = min(lengthTable.values())
+ self.maxLength = max(lengthTable.values())
+ self.switchToPrefix()
+
+ def setLength(self, lengthTable):
+ """Given the bit pattern lengths for symbols given in lengthTable,
+ set decodeTable, minLength, maxLength
+ """
+ self.lengthTable = lengthTable
+ self.minLength = min(lengthTable.values())
+ self.maxLength = max(lengthTable.values())
+ #compute the backwards codes first; then reverse them
+ #compute (backwards) first code for every separate lengths
+ nextCodes = []
+ #build codes for each length, from right to left
+ code = 0
+ for bits in range(self.maxLength+1):
+ code <<= 1
+ nextCodes.append(code)
+ code += sum(x==bits for x in lengthTable.values())
+ self.decodeTable = {}
+ #count codes for each length, and store reversed in the table
+ for symbol in sorted(lengthTable):
+ bits = lengthTable[symbol]
+ bitpattern = '{:0{}b}'.format(nextCodes[bits], bits)
+ self.decodeTable[int(bitpattern[::-1], 2)] = symbol
+ nextCodes[bits] += 1
+ self.switchToPrefix()
+
+ def switchToPrefix(self):
+ """This routine makes sure the prefix decoder is activated.
+ """
+ self.mode = PrefixDecoder
+
+class Code(RangeDecoder, PrefixDecoder):
+ """An alphabet of symbols, that can be read from a stream.
+ If you use setDecode or setLength, you have a prefix code,
+ otherwise you have a range code.
+ Features:
+ code[index] produces symbol with given index
+ value(index): value of symbol
+ mnemonic(index): short description of symbol
+ explanation(index): show meaning of symbol, shown in Layout.verboseRead
+ iter(code): produce all symbols in some order
+ name: show as context in Layout.verboseRead
+ """
+ name = '?'
+ #callback is a function that gets the symbol and the extra bits
+ #default callback calls explanation
+ def __init__(self, name=None, *, callback=None, description='', **args):
+ """Don't forget to set either alphabetSize or decodeTable
+ """
+ #set name when provided, otherwise take class variable
+ if name is not None: self.name = name
+ if callback is not None: self.callback = callback
+ self.description = description
+ #mode switch
+ if 'bitLength' in args or 'alphabetSize' in args:
+ self.mode = RangeDecoder
+ RangeDecoder.__init__(self, **args)
+ elif 'decodeTable' in args:
+ self.mode = PrefixDecoder
+ PrefixDecoder.__init__(self, **args)
+ else:
+ super().__init__(**args)
+
+ def __repr__(self):
+ return self.__class__.__name__+' '+self.name
+
+ #the routines that get switched between RangeDecoder and PrefixDecoder
+ def __len__(self): return self.mode.__len__(self)
+ def __iter__(self): return self.mode.__iter__(self)
+ def __getitem__(self, index): return self.mode.__getitem__(self, index)
+ def bitPattern(self, index): return self.mode.bitPattern(self, index)
+ def length(self, index): return self.mode.length(self, index)
+ def decodePeek(self, data): return self.mode.decodePeek(self, data)
+ #general routines
+ def value(self, index, extra=None):
+ """Get value of symbol for computations.
+ Override where needed.
+ """
+ if extra is not None:
+ raise ValueError('value: no extra for this symbol')
+ return index
+
+ def mnemonic(self, index):
+ """Give mnemonic of symbol.
+ Override where needed.
+ """
+ return str(self.value(index))
+
+ def callback(self, symbol):
+ return self.explanation(symbol.index)
+
+ def explanation(self, index):
+ """Long explanation of the value from the numeric value
+ This is a default routine.
+ You can customize in three ways:
+ - set description to add some text
+ - override to get more control
+ - set callback to make it dependent on you local variables
+ """
+ value = self.value(index)
+ return '{0}{1}: {2}'.format(
+ self.description and self.description+': ',
+ self.bitPattern(index),
+ value,
+ )
+
+ def extraBits(self, index):
+ return 0
+
+ #Routines that use the decode interface
+ def showCode(self, width=80):
+ """Show all words of the code in a nice format.
+ """
+ #make table of all symbols with binary strings
+ symbolStrings = [
+ (self.bitPattern(s.index), self.mnemonic(s.index))
+ for s in self
+ ]
+ #determine column widths the way Lisp programmers do it
+ leftColWidth, rightColWidth = map(max, map(
+ map,
+ repeat(len),
+ zip(*symbolStrings)
+ ))
+ colwidth = leftColWidth+rightColWidth
+ columns = 81//(colwidth+2)
+ rows = -(-len(symbolStrings)//columns)
+ def justify(bs):
+ b,s = bs
+ return b.rjust(leftColWidth)+':'+s.ljust(rightColWidth)
+ for i in range(rows):
+ print(' '.join(map(justify, symbolStrings[i::rows])).rstrip())
+
+ def readTuple(self, stream):
+ """Read symbol from stream. Returns symbol, length.
+ """
+ length, symbol = self.decodePeek(stream.peek(self.maxLength))
+ stream.pos += length
+ return length, symbol
+
+ def readTupleAndExtra(self, stream):
+ return self.readTuple(stream)+(0, None)
+
+class WithExtra(Code):
+ """Extension for Code so that symbol may have extra bits associated.
+ If you supply an extraTable, you can use extraBits
+ You can define an extraTable,
+ which allows to call extraBits to get the number of extraBits.
+ Otherwise, you can supply extraBits yourself.
+ Routine readTupleAndExtra now reads the extra bits too.
+ Value probably needs to be overridden; see Enumerator.
+ Note: this does not give you an decodeTable.
+ """
+ #redefine these if you don't want to use an extraTable
+ def extraBits(self, index):
+ """Get the number of extra bits for this symbol.
+ """
+ return self.extraTable[index]
+
+ def mnemonic(self, index):
+ """This value must be independent of extra.
+ """
+ return str(index)
+
+ def readTupleAndExtra(self, stream):
+ """Read symbol and extrabits from stream.
+ Returns symbol length, symbol, extraBits, extra
+ >>> olleke.pos = 6
+ >>> MetablockLengthAlphabet().readTupleAndExtra(olleke)
+ (2, Symbol(MLEN, 4), 16, 46)
+ """
+ length, symbol = self.decodePeek(stream.peek(self.maxLength))
+ stream.pos += length
+ extraBits = self.extraBits(symbol.index)
+ return length, symbol, extraBits, stream.read(extraBits)
+
+ def explanation(self, index, extra=None):
+ """Expanded version of Code.explanation supporting extra bits.
+ If you don't supply extra, it is not mentioned.
+ """
+ extraBits = 0 if extra is None else self.extraBits(index)
+ if not hasattr(self, 'extraTable'):
+ formatString = '{0}{3}'
+ lo = hi = value = self.value(index, extra)
+ elif extraBits==0:
+ formatString = '{0}{2}: {3}'
+ lo, hi = self.span(index)
+ value = lo
+ else:
+ formatString = '{0}{1} {2}: {3}-{4}; {3}+{5}={6}'
+ lo, hi = self.span(index)
+ value = lo+extra
+ return formatString.format(
+ self.description and self.description+': ',
+ 'x'*extraBits,
+ self.bitPattern(index),
+ lo, hi,
+ extra,
+ value,
+ )
+
+ def callback(self, symbol, extra):
+ return self.explanation(symbol.index, extra)
+
+class BoolCode(Code):
+ """Same as Code(bitLength=1), but shows a boolean.
+ """
+ def __init__(self, name=None, **args):
+ super().__init__(name, bitLength=1, **args)
+
+ def value(self, index, extra=None):
+ return bool(super().value(index, extra))
+
+class Enumerator(WithExtra):
+ """Code that is defined by the ExtraTable.
+ extraTable is a class variable that contains
+ the extraBits of the symbols from 0
+ value0 contains the value of symbol 0
+ encodings is not neccessary, but allowed.
+ Note: place for FixedCode to make sure extraBits works
+ """
+ def __init__(self, name=None, **args):
+ #if there is no decodeTable to determine length, compute it ourselves
+ if 'decodeTable' not in args:
+ args['alphabetSize'] = len(self.extraTable)
+ super().__init__(name, **args)
+
+ def __len__(self):
+ return len(self.extraTable)
+
+ def __getitem__(self, index):
+ """Faster than PrefixDecoder
+ """
+ if index>=len(self.extraTable):
+ raise ValueError("No symbol {}[{}]".format(
+ self.__class__.__name__, index))
+ return Symbol(self, index)
+
+ def value(self, index, extra):
+ """Override if you don't define value0 and extraTable
+ """
+ lower, upper = self.span(index)
+ value = lower+(extra or 0)
+ if value>upper:
+ raise ValueError('value: extra out of range')
+ return value
+
+ def span(self, index):
+ """Give the range of possible values in a tuple
+ Useful for mnemonic and explanation
+ """
+ lower = self.value0+sum(1<<x for x in self.extraTable[:index])
+ upper = lower+(1<<self.extraTable[index])
+ return lower, upper-1
+
+#======================Code subclasses======================================
+#Alphabets used in the metablock header----------------------------------
+#For prefix codes
+class PrefixCodeHeader(WithExtra):
+ """Header of prefix codes.
+ """
+ def __init__(self, codename):
+ super().__init__('PFX', bitLength=2)
+ #this is the name of the code that it describes
+ self.codename = codename
+
+ def extraBits(self, index):
+ return 2 if index==1 else 0
+
+ def value(self, index, extra):
+ """Returns ('Simple', #codewords) or ('Complex', HSKIP)
+ """
+ if index==1:
+ if extra>3:
+ raise ValueError('value: extra out of range')
+ return 'Simple', extra+1
+ if extra:
+ raise ValueError('value: extra out of range')
+ return 'Complex', index
+
+ def explanation(self, index, extra):
+ if index==1:
+ return '{} is simple with {} code word{}'.format(
+ self.codename, extra+1, 's' if extra else '')
+ lengths = [1, 2, 3, 4, 0, 5, 17, 6]
+ return '{} is complex with lengths {}...'.format(
+ self.codename,
+ ','.join(
+ map(str, lengths[index:index+5]))
+ )
+
+class TreeShapeAlhabet(BoolCode):
+ """The bit used to indicate if four word code is "deep" or "wide"
+ """
+ name = 'SHAPE'
+ def value(self, index):
+ return [(2,2,2,2), (1,2,3,3)][index]
+
+ def explanation(self, index):
+ return str(bool(index))+': lengths {},{},{},{}'.format(*self.value(index))
+
+class LengthOfLengthAlphabet(Code):
+ """For use in decoding complex code descriptors.
+ >>> lengthOfLengthAlphabet = LengthOfLengthAlphabet('')
+ >>> print(lengthOfLengthAlphabet[2])
+ coded with 2 bits
+ >>> len(lengthOfLengthAlphabet[0])
+ 2
+ >>> [len(lengthOfLengthAlphabet[x]) for x in range(6)]
+ [2, 4, 3, 2, 2, 4]
+ >>> lengthOfLengthAlphabet.showCode()
+ 00:skipped 01:coded with 4 bits 0111:coded with 1 bits
+ 10:coded with 3 bits 011:coded with 2 bits 1111:coded with 5 bits
+ """
+ decodeTable = {
+ 0b00:0, 0b10:3,
+ 0b0111:1, 0b01:4,
+ 0b011:2, 0b1111:5,
+ }
+
+ def __init__(self, name=None, **args):
+ super().__init__(name, decodeTable=self.decodeTable, **args)
+
+ def mnemonic(self, index):
+ if index==0: return 'skipped'
+ return 'coded with {} bits'.format(index)
+
+ def explanation(self, index, extra=None):
+ return self.description+': '+self.mnemonic(index)
+
+class LengthAlphabet(WithExtra):
+ """Length of symbols
+ Used during construction of a code.
+ """
+ def __init__(self, name):
+ super().__init__(name, alphabetSize=18)
+
+ def extraBits(self, index):
+ return {16:2, 17:3}.get(index, 0)
+
+ def mnemonic(self, index):
+ if index==0: return 'unused'
+ elif index==16: return 'rep xx'
+ elif index==17: return 'zero xxx'
+ else: return 'len {}'.format(index)
+
+ def explanation(self, index, extra):
+ return self.description.format(self[index], extra)
+
+ def value(self, index, extra):
+ #the caller got the length already, so extra is enough
+ return extra
+
+#Stream header
+class WindowSizeAlphabet(Code):
+ """The alphabet used for window size in the stream header.
+ >>> WindowSizeAlphabet()[10].explanation()
+ 'windowsize=(1<<10)-16=1008'
+ """
+ decodeTable = {
+ 0b0100001: 10, 0b1100001: 14, 0b0011: 18, 0b1011: 22,
+ 0b0110001: 11, 0b1110001: 15, 0b0101: 19, 0b1101: 23,
+ 0b1000001: 12, 0b0: 16, 0b0111: 20, 0b1111: 24,
+ 0b1010001: 13, 0b0000001: 17, 0b1001: 21,
+ 0b0010001: None,
+ }
+
+ name = 'WSIZE'
+
+ def __init__(self, name=None):
+ super().__init__(name, decodeTable=self.decodeTable)
+
+ def value(self, index):
+ #missing value gives index None
+ if index is None: return None
+ return (1<<index)-16
+
+ def explanation(self, index):
+ return 'windowsize=(1<<{})-16={}'.format(
+ index, (1<<index)-16)
+
+#Metablock
+class MetablockLengthAlphabet(WithExtra):
+ """Used for the meta block length;
+ also indicates a block with no data
+ >>> metablockLengthAlphabet = MetablockLengthAlphabet()
+ >>> metablockLengthAlphabet[0]; str(metablockLengthAlphabet[0])
+ Symbol(MLEN, 0)
+ 'empty'
+ >>> metablockLengthAlphabet[3]
+ Traceback (most recent call last):
+ ...
+ ValueError: No symbol MetablockLengthAlphabet[3]
+ >>> print(metablockLengthAlphabet[4])
+ hhhh00
+ >>> metablockLengthAlphabet[4].value(0x1000)
+ 4097
+ >>> metablockLengthAlphabet[5].value(0x1000)
+ Traceback (most recent call last):
+ ...
+ InvalidStream: Zeros in high nibble of MLEN
+ >>> metablockLengthAlphabet[5].explanation(0x12345)
+ 'data length: 12345h+1=74566'
+ >>> metablockLengthAlphabet.showCode()
+ 00:hhhh00 10:hhhhhh10 01:hhhhh01 11:empty
+ """
+ decodeTable = {0b11:0, 0b00:4, 0b01:5, 0b10:6}
+
+ name = 'MLEN'
+ def __init__(self, name=None):
+ super().__init__(name, decodeTable=self.decodeTable)
+
+ def extraBits(self, index):
+ return index*4
+
+ def mnemonic(self, index):
+ if index==0: return 'empty'
+ return 'h'*(self.extraBits(index)//4)+self.bitPattern(index)
+
+ def value(self, index, extra):
+ extraBits = self.extraBits(index)
+ if not 0<=extra<1<<extraBits:
+ raise ValueError('value: extra out of range')
+ if index==0: return 0
+ if index>4 and extra>>extraBits-4==0: raise InvalidStream(
+ 'Zeros in high nibble of MLEN')
+ return extra+1
+
+ def explanation(self, index, extra):
+ if index==0: return '11: empty block'
+ extraBits = self.extraBits(index)
+ return 'data length: {:0{}x}h+1={}'.format(extra, extraBits//4, extra+1)
+
+
+class ReservedAlphabet(BoolCode):
+ """The reserved bit that must be zero.
+ """
+ name = 'RSVD'
+ def value(self, index):
+ if index: raise ValueError('Reserved bit is not zero')
+
+ def explanation(self, index):
+ return 'Reserved (must be zero)'
+
+class FillerAlphabet(Code):
+ def __init__(self, *, streamPos):
+ super().__init__('SKIP', bitLength=(-streamPos)&7)
+
+ def explanation(self, index):
+ return '{} bit{} ignored'.format(
+ self.length(index),
+ '' if self.length(index)==1 else 's',
+ )
+
+class SkipLengthAlphabet(WithExtra):
+ """Used for the skip length in an empty metablock
+ >>> skipLengthAlphabet = SkipLengthAlphabet()
+ >>> skipLengthAlphabet[0]; str(skipLengthAlphabet[0])
+ Symbol(SKIP, 0)
+ 'empty'
+ >>> skipLengthAlphabet[4]
+ Traceback (most recent call last):
+ ...
+ ValueError: index out of range
+ >>> print(skipLengthAlphabet[3])
+ hhhhhh11
+ >>> skipLengthAlphabet[2].value(0x1000)
+ 4097
+ >>> skipLengthAlphabet[3].value(0x1000)
+ Traceback (most recent call last):
+ ...
+ InvalidStream: Zeros in high byte of SKIPBYTES
+ >>> skipLengthAlphabet[3].explanation(0x12345)
+ 'skip length: 12345h+1=74566'
+ >>> skipLengthAlphabet.showCode()
+ 00:empty 01:hh01 10:hhhh10 11:hhhhhh11
+ """
+ def __init__(self):
+ super().__init__('SKIP', bitLength=2)
+
+ def extraBits(self, index):
+ return index*8
+
+ def mnemonic(self, index):
+ if index==0: return 'empty'
+ return 'h'*(self.extraBits(index)//4)+self.bitPattern(index)
+
+ def value(self, index, extra):
+ extraBits = self.extraBits(index)
+ if not 0<=extra<1<<extraBits:
+ raise ValueError('value: extra out of range')
+ if index==0: return 0
+ if index>1 and extra>>extraBits-8==0:
+ raise InvalidStream('Zeros in high byte of SKIPBYTES')
+ return extra+1
+
+ def explanation(self, index, extra):
+ if index==0: return '00: no skip'
+ extraBits = self.extraBits(index)
+ return 'skip length: {:{}x}h+1={}'.format(extra, extraBits//8, extra+1)
+
+
+class TypeCountAlphabet(Enumerator):
+ """Used for giving block type counts and tree counts.
+ >>> TypeCountAlphabet(description='').showCode()
+ 0:0 0101:xx,0101 1011:xxxxx,1011
+ 0001:0001 1101:xxxxxx,1101 0111:xxx,0111
+ 1001:xxxx,1001 0011:x,0011 1111:xxxxxxx,1111
+ """
+ decodeTable = {
+ 0b0: 0, 0b1001: 5,
+ 0b0001: 1, 0b1011: 6,
+ 0b0011: 2, 0b1101: 7,
+ 0b0101: 3, 0b1111: 8,
+ 0b0111: 4,
+ }
+
+ value0 = 1
+ extraTable = [0, 0, 1, 2, 3, 4, 5, 6, 7]
+ name = 'BT#'
+
+ def __init__(self, name=None, *, description):
+ super().__init__(
+ name,
+ decodeTable=self.decodeTable,
+ description=description)
+
+ def mnemonic(self, index):
+ if index==0: return '0'
+ if index==1: return '0001'
+ return 'x'*(self.extraBits(index))+','+self.bitPattern(index)
+
+ def explanation(self, index, extra):
+ value = self.value(index, extra)
+ description = self.description
+ if value==1: description = description[:-1]
+ return '{}: {} {}'.format(
+ self.mnemonic(index),
+ value,
+ description)
+
+class BlockTypeAlphabet(Code):
+ """The block types; this code works for all three kinds.
+ >>> b = BlockTypeAlphabet('T', NBLTYPES=5)
+ >>> print(*(x for x in b))
+ prev +1 #0 #1 #2 #3 #4
+ """
+ def __init__(self, name, NBLTYPES, **args):
+ super().__init__(name, alphabetSize=NBLTYPES+2, **args)
+ self.NBLTYPES = NBLTYPES
+
+ def mnemonic(self, index):
+ if index==0: return 'prev'
+ elif index==1: return '+1'
+ else: return '#'+str(index-2)
+
+ def value(self, index):
+ return index-2
+
+ def explanation(self, index):
+ if index==0: return '0: previous'
+ elif index==1: return '1: increment'
+ else: return 'Set block type to: '+str(index-2)
+
+class BlockCountAlphabet(Enumerator):
+ """Block counts
+ >>> b = BlockCountAlphabet('L')
+ >>> print(b[25])
+ [24*x]: BC16625-16793840
+ """
+
+ value0 = 1
+ extraTable = [2,2,2,2,3, 3,3,3,4,4, 4,4,5,5,5, 5,6,6,7,8, 9,10,11,12,13, 24]
+ def __init__(self, name, **args):
+ super().__init__(name, alphabetSize=26, **args)
+
+ def mnemonic(self, index):
+ extraBits = self.extraBits(index)
+ return '{}: BC{}-{}'.format(
+ 'x'*extraBits if index<5 else '[{}*x]'.format(extraBits),
+ *self.span(index))
+
+ def explanation(self, index, extra):
+ return 'Block count: '+super().explanation(index, extra)
+
+class DistanceParamAlphabet(WithExtra):
+ """The distance parameters NPOSTFIX and NDIRECT.
+ Although these are treated as two in the description, this is easier.
+ """
+ def __init__(self):
+ super().__init__('DIST', bitLength=2)
+
+ def extraBits(self, index):
+ return 4
+
+ def value(self, index, extra):
+ """Returns NPOSTFIX and NDIRECT<<NPOSTFIX
+ """
+ if extra>15:
+ raise ValueError('value: extra out of range')
+ return index, extra<<index
+
+ def explanation(self, index, extra):
+ return '{} postfix bits and {:04b}<<{}={} direct codes'.format(
+ index, extra, index, extra<<index)
+
+ def mnemonic(self, index):
+ return 'PF'+str(index)
+
+class LiteralContextMode(Code):
+ """For the literal context modes.
+ >>> LiteralContextMode().showCode()
+ 00:LSB6 01:MSB6 10:UTF8 11:Signed
+ >>> LiteralContextMode().explanation(2)
+ 'Context mode for type 9: 2(UTF8)'
+ """
+
+ def __init__(self, *, number=9):
+ super().__init__('LC'+str(number), bitLength=2)
+ self.number = number
+
+ def mnemonic(self, index):
+ return ['LSB6', 'MSB6', 'UTF8', 'Signed'][index]
+
+ def explanation(self, index):
+ return 'Context mode for type {}: {}({})'.format(
+ self.number,
+ index,
+ self.mnemonic(index))
+
+class RLEmaxAlphabet(Enumerator):
+ """Used for describing the run length encoding used for describing context maps.
+ >>> RLEmaxAlphabet().showCode()
+ 0:1 1:more
+ """
+ value0 = 0
+ extraTable = [0, 4]
+ name = 'RLE#'
+
+ def mnemonic(self, index):
+ return ['1', 'more'][index]
+
+ def explanation(self, index, extra):
+ description = self.description and self.description+': '
+ if index==0: return description+'No RLE coding'
+ return '{}xxxx 1: RLEMAX={}'.format(description, extra+1)
+
+class TreeAlphabet(WithExtra):
+ """The alphabet to enumerate entries (called trees) in the context map.
+ parameters are RLEMAX and NTREES
+ >>> t = TreeAlphabet('', RLEMAX=3, NTREES=5)
+ >>> len(t)
+ 8
+ >>> print(t[2])
+ xx+4 zeroes
+ >>> t[3].explanation(2)
+ '8+010=10 zeroes'
+ >>> t[0].value(0)
+ (1, 0)
+ """
+ name = 'CMI'
+ def __init__(self, name=None, *, RLEMAX, NTREES, **args):
+ super().__init__(name, alphabetSize=RLEMAX+NTREES, **args)
+ self.RLEMAX = RLEMAX
+ self.NTREES = NTREES
+
+ def extraBits(self, index):
+ if 0<index<=self.RLEMAX: return index
+ return 0
+
+ def mnemonic(self, index):
+ if index==0: return 'map #0'
+ if index<=self.RLEMAX:
+ return '{}+{} zeroes'.format('x'*index, 1<<index)
+ return 'map #{}'.format(index-self.RLEMAX)
+
+ def value(self, index, extra):
+ """Give count and value."""
+ index = index
+ if index==0: return 1, 0
+ if index<=self.RLEMAX: return (1<<index)+extra, 0
+ return 1, index-self.RLEMAX
+
+ def explanation(self, index, extra):
+ description = self.description and self.description+': '
+ if index==0: return description+'map #0'
+ if index<=self.RLEMAX:
+ return '{}+{:0{}b}={} zeroes'.format(
+ (1<<index),
+ extra, self.extraBits(index),
+ (1<<index)+extra)
+ return '{}map #{}-{}={}'.format(
+ description,
+ index, self.RLEMAX, index-self.RLEMAX)
+
+#Prefix alphabets for the data stream----------------------------------
+class LiteralAlphabet(Code):
+ """Alphabet of symbols.
+ """
+ minLength = maxLength = 8
+ def __init__(self, number):
+ super().__init__('L'+str(number), alphabetSize=1<<8)
+
+ def mnemonic(self, index):
+ return outputCharFormatter(index)
+
+ def value(self, index, extra=None):
+ return index
+
+ def explanation(self, index, extra=None):
+ return self.mnemonic(index)
+
+class InsertLengthAlphabet(Enumerator):
+ """Intern code for insert counts
+ """
+ value0 = 0
+ extraTable = [0,0,0,0,0, 0,1,1,2,2, 3,3,4,4,5, 5,6,7,8,9, 10,12,14,24]
+
+class CopyLengthAlphabet(Enumerator):
+ value0 = 2
+ extraTable = [0,0,0,0,0, 0,0,0,1,1, 2,2,3,3,4, 4,5,5,6,7, 8,9,10,24]
+
+class InsertAndCopyAlphabet(WithExtra):
+ """The insert and copy code
+ >>> for x in range(0,704,704//13):
+ ... print('{:10b}'.format(x), InsertAndCopyAlphabet()[x])
+ 0 I0C2&D=0
+ 110110 I6+xC8&D=0
+ 1101100 I5C22+xxx&D=0
+ 10100010 I4C4
+ 11011000 I3C10+x
+ 100001110 I14+xxC8
+ 101000100 I10+xxC22+xxx
+ 101111010 I98+xxxxxC14+xx
+ 110110000 I6+xC70+xxxxx
+ 111100110 I1090+[10*x]C8
+ 1000011100 I26+xxxC326+[8*x]
+ 1001010010 I322+[8*x]C14+xx
+ 1010001000 I194+[7*x]C70+xxxxx
+ 1010111110 I22594+[24*x]C1094+[10*x]
+ """
+ insertLengthAlphabet = InsertLengthAlphabet(None)
+ copyLengthAlphabet = CopyLengthAlphabet(None)
+
+ def __init__(self, number=''):
+ super().__init__('IC'+str(number), bitLength=10)
+
+ def __len__(self):
+ return 704
+
+ def extraBits(self, index):
+ insertSymbol, copySymbol, dist0 = self.splitSymbol(index)
+ return InsertLengthAlphabet.extraTable[insertSymbol.index] + \
+ CopyLengthAlphabet.extraTable[copySymbol.index]
+
+ def splitSymbol(self, index):
+ """Give relevant values for computations:
+ (insertSymbol, copySymbol, dist0flag)
+ """
+ #determine insert and copy upper bits from table
+ row = [0,0,1,1,2,2,1,3,2,3,3][index>>6]
+ col = [0,1,0,1,0,1,2,0,2,1,2][index>>6]
+ #determine inserts and copy sub codes
+ insertLengthCode = row<<3 | index>>3&7
+ if row: insertLengthCode -= 8
+ copyLengthCode = col<<3 | index&7
+ return (
+ Symbol(self.insertLengthAlphabet, insertLengthCode),
+ Symbol(self.copyLengthAlphabet, copyLengthCode),
+ row==0
+ )
+
+ def mnemonic(self, index):
+ """Make a nice mnemonic
+ """
+ i,c,d0 = self.splitSymbol(index)
+ iLower, _ = i.code.span(i.index)
+ iExtra = i.extraBits()
+ cLower, _ = c.code.span(c.index)
+ cExtra = c.extraBits()
+ return 'I{}{}{}C{}{}{}{}'.format(
+ iLower,
+ '+' if iExtra else '',
+ 'x'*iExtra if iExtra<6 else '[{}*x]'.format(iExtra),
+ cLower,
+ '+' if cExtra else '',
+ 'x'*cExtra if cExtra<6 else '[{}*x]'.format(cExtra),
+ '&D=0' if d0 else '')
+
+ def value(self, index, extra):
+ i,c,d0 = self.splitSymbol(index)
+ iExtra = i.extraBits()
+ ce, ie = extra>>iExtra, extra&(1<<iExtra)-1
+ insert = i.value(ie)
+ copy = c.value(ce)
+ return insert, copy, d0
+
+ def explanation(self, index, extra):
+ insert, copy, d0 = self.value(index, extra)
+ if d0: return 'Literal: {}, copy: {}, same distance'.format(insert, copy)
+ else: return 'Literal: {}, copy: {}'.format(insert, copy)
+
+class DistanceAlphabet(WithExtra):
+ """Represent the distance encoding.
+ Dynamically generated alphabet.
+ This is what the documentation should have said:
+ Ignoring offsets for the moment, the "long" encoding works as follows:
+ Write the distance in binary as follows:
+ 1xy..yz..z, then the distance symbol consists of n..nxz..z
+ Where:
+ n is one less than number of bits in y
+ x is a single bit
+ y..y are n+1 extra bits (encoded in the bit stream)
+ z..z is NPOSTFIX bits that are part of the symbol
+ The offsets are so as to start at the lowest useable value:
+ if 1xyyyyz = distance +(4<<POSTFIX)-NDIRECT-1
+ then n..nxz..z is symbol -NDIRECT-16
+ >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10)
+ >>> print(d[4], d[17], d[34])
+ last-1 1 10xx00-5
+ >>> [str(d[x]) for x in range(26, 32)]
+ ['10x00-5', '10x01-5', '10x10-5', '10x11-5', '11x00-5', '11x01-5']
+ """
+ def __init__(self, number, *, NPOSTFIX, NDIRECT):
+ self.NPOSTFIX = NPOSTFIX
+ self.NDIRECT = NDIRECT
+ #set length
+ #Actually, not all symbols are used,
+ #only NDIRECT+16+(44-2*POSTFIX<<NPOSTFIX)
+ super().__init__('D'+str(number),
+ alphabetSize=self.NDIRECT+16+(48<<self.NPOSTFIX))
+
+ def extraBits(self, index):
+ """Indicate how many extra bits are needed to interpret symbol
+ >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10)
+ >>> [d[i].extraBits() for i in range(26)]
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ >>> [d[i].extraBits() for i in range(26,36)]
+ [1, 1, 1, 1, 1, 1, 1, 1, 2, 2]
+ """
+ if index<16+self.NDIRECT: return 0
+ return 1 + ((index - self.NDIRECT - 16) >> (self.NPOSTFIX + 1))
+
+ def value(self, dcode, dextra):
+ """Decode value of symbol together with the extra bits.
+ >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10)
+ >>> d[34].value(2)
+ (0, 35)
+ """
+ if dcode<16:
+ return [(1,0),(2,0),(3,0),(4,0),
+ (1,-1),(1,+1),(1,-2),(1,+2),(1,-3),(1,+3),
+ (2,-1),(2,+1),(2,-2),(2,+2),(2,-3),(2,+3)
+ ][dcode]
+ if dcode<16+self.NDIRECT:
+ return (0,dcode-16)
+ #we use the original formulas, instead of my clear explanation
+ POSTFIX_MASK = (1 << self.NPOSTFIX) - 1
+ ndistbits = 1 + ((dcode - self.NDIRECT - 16) >> (self.NPOSTFIX + 1))
+ hcode = (dcode - self.NDIRECT - 16) >> self.NPOSTFIX
+ lcode = (dcode - self.NDIRECT - 16) & POSTFIX_MASK
+ offset = ((2 + (hcode & 1)) << ndistbits) - 4
+ distance = ((offset + dextra) << self.NPOSTFIX) + lcode + self.NDIRECT + 1
+ return (0,distance)
+
+ def mnemonic(self, index, verbose=False):
+ """Give mnemonic representation of meaning.
+ verbose compresses strings of x's
+ """
+ if index<16:
+ return ['last', '2last', '3last', '4last',
+ 'last-1', 'last+1', 'last-2', 'last+2', 'last-3', 'last+3',
+ '2last-1', '2last+1', '2last-2', '2last+2', '2last-3', '2last+3'
+ ][index]
+ if index<16+self.NDIRECT:
+ return str(index-16)
+ #construct strings like "1xx01-15"
+ index -= self.NDIRECT+16
+ hcode = index >> self.NPOSTFIX
+ lcode = index & (1<<self.NPOSTFIX)-1
+ if self.NPOSTFIX: formatString = '1{0}{1}{2:0{3}b}{4:+d}'
+ else: formatString = '1{0}{1}{4:+d}'
+ return formatString.format(
+ hcode&1,
+ 'x'*(2+hcode>>1) if hcode<13 or verbose else '[{}*x]'.format(2+hcode>>1),
+ lcode, self.NPOSTFIX,
+ self.NDIRECT+1-(4<<self.NPOSTFIX))
+
+ def explanation(self, index, extra):
+ """
+ >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10)
+ >>> d[55].explanation(13)
+ '11[1101]01-5: [0]+240'
+ """
+ extraBits = self.extraBits(index)
+ extraString = '[{:0{}b}]'.format(extra, extraBits)
+ return '{0}: [{1[0]}]{1[1]:+d}'.format(
+ self.mnemonic(index, True).replace('x'*(extraBits or 1), extraString),
+ self.value(index, extra))
+
+#Classes for doing actual work------------------------------------------
+class ContextModeKeeper:
+ """For computing the literal context mode.
+ You feed it characters, and it computes indices in the context map.
+ """
+ def __init__(self, mode):
+ self.chars = deque([0,0], maxlen=2)
+ self.mode = mode
+
+ def setContextMode(self, mode):
+ """Switch to given context mode (0..3)"""
+ self.mode = mode
+ def getIndex(self):
+ if self.mode==0: #LSB6
+ return self.chars[1]&0x3f
+ elif self.mode==1: #MSB6
+ return self.chars[1]>>2
+ elif self.mode==2: #UTF8: character class of previous and a bit of the second
+ p2,p1 = self.chars
+ return self.lut0[p1]|self.lut1[p2]
+ elif self.mode==3: #Signed: initial bits of last two bytes
+ p2,p1 = self.chars
+ return self.lut2[p1]<<3|self.lut2[p2]
+
+ def add(self, index):
+ """Adjust the context for output char (as int)."""
+ self.chars.append(index)
+
+ #0: control #16: quote #32: ,:; #48: AEIOU
+ #4: tab/lf/cr #20: % #36: . #52: BC..Z
+ #8: space #24: (<[{ #40: = #56: aeiou
+ #12:!#$&*+-/?@| #28: )>]} #44: 0-9 #60: bc..z
+ lut0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
+ 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
+ 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
+ 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
+ 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0
+ ]+[0,1]*32+[2,3]*32
+ #0: space 1:punctuation 2:digit/upper 3:lower
+ lut1 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0
+ ]+[0]*96+[2]*32
+ #initial bits: 8*0, 4*0, 2*0, 1*0, 1*1, 2*1, 4*1, 8*1
+ lut2 = [0]+[1]*15+[2]*48+[3]*64+[4]*64+[5]*48+[6]*15+[7]
+ assert len(lut0)==len(lut1)==len(lut2)==256
+
+class WordList:
+ """Word list.
+ >>> WordList().word(7, 35555)
+ b'Program to '
+ """
+ NDBITS = [0, 0, 0, 0, 10, 10, 11, 11, 10, 10,
+ 10, 10, 10, 9, 9, 8, 7, 7, 8, 7,
+ 7, 6, 6, 5, 5]
+ def __init__(self):
+ self.file = open('dict', 'rb')
+ self.compileActions()
+
+ def word(self, size, dist):
+ """Get word
+ """
+ #split dist in index and action
+ ndbits = self.NDBITS[size]
+ index = dist&(1<<ndbits)-1
+ action = dist>>ndbits
+ #compute position in file
+ position = sum(n<<self.NDBITS[n] for n in range(4,size))+size*index
+ self.file.seek(position)
+ return self.doAction(self.file.read(size), action)
+
+ def upperCase1(self, word):
+ word = word.decode('utf8')
+ word = word[0].upper()+word[1:]
+ return word.encode('utf8')
+
+
+ #Super compact form of action table.
+ #_ means space, .U means UpperCaseAll, U(w) means UpperCaseFirst
+ actionTable = r"""
+ 0:w 25:w+_for_ 50:w+\n\t 75:w+. This_100:w+ize_
+ 1:w+_ 26:w[3:] 51:w+: 76:w+, 101:w.U+.
+ 2:_+w+_ 27:w[:-2] 52:_+w+._ 77:.+w+_ 102:\xc2\xa0+w
+ 3:w[1:] 28:w+_a_ 53:w+ed_ 78:U(w)+( 103:_+w+,
+ 4:U(w)+_ 29:w+_that_ 54:w[9:] 79:U(w)+. 104:U(w)+="
+ 5:w+_the_ 30:_+U(w) 55:w[7:] 80:w+_not_ 105:w.U+="
+ 6:_+w 31:w+._ 56:w[:-6] 81:_+w+=" 106:w+ous_
+ 7:s_+w+_ 32:.+w 57:w+( 82:w+er_ 107:w.U+,_
+ 8:w+_of_ 33:_+w+,_ 58:U(w)+,_ 83:_+w.U+_ 108:U(w)+=\'
+ 9:U(w) 34:w[4:] 59:w[:-8] 84:w+al_ 109:_+U(w)+,
+ 10:w+_and_ 35:w+_with_ 60:w+_at_ 85:_+w.U 110:_+w.U+="
+ 11:w[2:] 36:w+\' 61:w+ly_ 86:w+=\' 111:_+w.U+,_
+ 12:w[:-1] 37:w+_from_ 62:_the_+w+_of_ 87:w.U+" 112:_+w.U+,
+ 13:,_+w+_ 38:w+_by_ 63:w[:-5] 88:U(w)+._ 113:w.U+(
+ 14:w+,_ 39:w[5:] 64:w[:-9] 89:_+w+( 114:w.U+._
+ 15:_+U(w)+_ 40:w[6:] 65:_+U(w)+,_ 90:w+ful_ 115:_+w.U+.
+ 16:w+_in_ 41:_the_+w 66:U(w)+" 91:_+U(w)+._116:w.U+=\'
+ 17:w+_to_ 42:w[:-4] 67:.+w+( 92:w+ive_ 117:_+w.U+._
+ 18:e_+w+_ 43:w+. The_ 68:w.U+_ 93:w+less_ 118:_+U(w)+="
+ 19:w+" 44:w.U 69:U(w)+"> 94:w.U+\' 119:_+w.U+=\'
+ 20:w+. 45:w+_on_ 70:w+=" 95:w+est_ 120:_+U(w)+=\'
+ 21:w+"> 46:w+_as_ 71:_+w+. 96:_+U(w)+.
+ 22:w+\n 47:w+_is_ 72:.com/+w 97:w.U+">
+ 23:w[:-3] 48:w[:-7] 98:_+w+=\'
+ 24:w+] 49:w[:-1]+ing_ 74:U(w)+\' 99:U(w)+,
+ """
+
+ def compileActions(self):
+ """Build the action table from the text above
+ """
+ import re
+ self.actionList = actions = [None]*121
+ #Action 73, which is too long, looks like this when expanded:
+ actions[73] = "b' the '+w+b' of the '"
+ #find out what the columns are
+ actionLines = self.actionTable.splitlines()
+ colonPositions = [m.start()
+ for m in re.finditer(':',actionLines[1])
+ ]+[100]
+ columns = [(colonPositions[i]-3,colonPositions[i+1]-3)
+ for i in range(len(colonPositions)-1)]
+ for line in self.actionTable.splitlines(keepends=False):
+ for start,end in columns:
+ action = line[start:end]
+ #skip empty actions
+ if not action or action.isspace(): continue
+ #chop it up, and check if the colon is properly placed
+ index, colon, action = action[:3], action[3], action[4:]
+ assert colon==':'
+ #remove filler spaces at right
+ action = action.rstrip()
+ #replace space symbols
+ action = action.replace('_', ' ')
+ wPos = action.index('w')
+ #add quotes around left string when present
+ #translation: any pattern from beginning, up to
+ #(but not including) a + following by a w later on
+ action = re.sub(r"^(.*)(?=\+[U(]*w)", r"b'\1'", action)
+ #add quotes around right string when present
+ #translation: anything with a w in it, followed by a +
+ #and a pattern up to the end
+ #(there is no variable lookbehind assertion,
+ #so we have to copy the pattern)
+ action = re.sub(r"(w[[:\-1\]).U]*)\+(.*)$", r"\1+b'\2'", action)
+ #expand shortcut for uppercaseAll
+ action = action.replace(".U", ".upper()")
+ #store action
+ actions[int(index)] = action
+
+ def doAction(self, w, action):
+ """Perform the proper action
+ """
+ #set environment for the UpperCaseFirst
+ U = self.upperCase1
+ return eval(self.actionList[action], locals())
+
+class Layout:
+ """Class to layout the output.
+ """
+ #display width of hexdata+bitdata
+ width = 25
+ #general
+ def __init__(self, stream):
+ self.stream = stream
+ self.bitPtr = self.width
+
+ def makeHexData(self, pos):
+ """Produce hex dump of all data containing the bits
+ from pos to stream.pos
+ """
+ firstAddress = pos+7>>3
+ lastAddress = self.stream.pos+7>>3
+ return ''.join(map('{:02x} '.format,
+ self.stream.data[firstAddress:lastAddress]))
+
+ def formatBitData(self, pos, width1, width2=0):
+ """Show formatted bit data:
+ Bytes are separated by commas
+ whole bytes are displayed in hex
+ >>> Layout(olleke).formatBitData(6, 2, 16)
+ '|00h|2Eh,|00'
+ >>> Layout(olleke).formatBitData(4, 1, 0)
+ '1'
+ """
+ result = []
+ #make empty prefix code explicit
+ if width1==0: result = ['()', ',']
+ for width in width1, width2:
+ #skip empty width2
+ if width==0: continue
+ #build result backwards in a list
+ while width>0:
+ availableBits = 8-(pos&7)
+ if width<availableBits:
+ #read partial byte, beginning nor ending at boundary
+ data = self.stream.data[pos>>3] >> (pos&7) & (1<<width)-1
+ result.append('{:0{}b}'.format(data, width))
+ elif availableBits<8:
+ #read rest of byte, ending at boundary
+ data = self.stream.data[pos>>3] >> (pos&7)
+ result.append('|{:0{}b}'.format(data, availableBits))
+ else:
+ #read whole byte (in hex), beginning and ending at boundary
+ data = self.stream.data[pos>>3]
+ result.append('|{:02X}h'.format(data))
+ width -= availableBits
+ pos += availableBits
+ #if width overshot from the availableBits subtraction, fix it
+ pos += width
+ #add comma to separate fields
+ result.append(',')
+ #concatenate pieces, reversed, skipping the last space
+ return ''.join(result[-2::-1])
+
+ def readPrefixCode(self, alphabet):
+ """give alphabet the prefix code that is read from the stream
+ Called for the following alphabets, in this order:
+ The alphabet in question must have a "logical" order,
+ otherwise the assignment of symbols doesn't work.
+ """
+ mode, numberOfSymbols = self.verboseRead(PrefixCodeHeader(alphabet.name))
+ if mode=='Complex':
+ #for a complex code, numberOfSymbols means hskip
+ self.readComplexCode(numberOfSymbols, alphabet)
+ return alphabet
+ else:
+ table = []
+ #Set table of lengths for mnemonic function
+ lengths = [[0], [1,1], [1,2,2], '????'][numberOfSymbols-1]
+ #adjust mnemonic function of alphabet class
+ def myMnemonic(index):
+ return '{} bit{}: {}'.format(
+ lengths[i],
+ '' if lengths[i]==1 else 's',
+ alphabet.__class__.mnemonic(alphabet, index)
+ )
+ alphabet.mnemonic = myMnemonic
+ for i in range(numberOfSymbols):
+ table.append(self.verboseRead(alphabet, skipExtra=True).index)
+ #restore mnemonic
+ del alphabet.mnemonic
+ if numberOfSymbols==4:
+ #read tree shape to redefine lengths
+ lengths = self.verboseRead(TreeShapeAlhabet())
+ #construct the alphabet prefix code
+ alphabet.setLength(dict(zip(table, lengths)))
+ return alphabet
+
+ def readComplexCode(self, hskip, alphabet):
+ """Read complex code"""
+ stream = self.stream
+ #read the lengths for the length code
+ lengths = [1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15][hskip:]
+ codeLengths = {}
+ total = 0
+ lol = LengthOfLengthAlphabet('##'+alphabet.name)
+ #lengthCode will be used for coding the lengths of the new code
+ #we use it for display until now; definition comes below
+ lengthCode = LengthAlphabet('#'+alphabet.name)
+ lengthIter = iter(lengths)
+ lengthsLeft = len(lengths)
+ while total<32 and lengthsLeft>0:
+ lengthsLeft -= 1
+ newSymbol = next(lengthIter)
+ lol.description = str(lengthCode[newSymbol])
+ length = self.verboseRead(lol)
+ if length:
+ codeLengths[newSymbol] = length
+ total += 32>>length
+ if total>32: raise ValueError("Stream format")
+ if len(codeLengths)==1: codeLengths[list(codeLengths.keys())[0]] = 0
+ #Now set the encoding of the lengthCode
+ lengthCode.setLength(codeLengths)
+ print("***** Lengths for {} will be coded as:".format(alphabet.name))
+ lengthCode.showCode()
+ #Now determine the symbol lengths with the lengthCode
+ symbolLengths = {}
+ total = 0
+ lastLength = 8
+ alphabetIter = iter(alphabet)
+ while total<32768:
+ #look ahead to see what is going to happen
+ length = lengthCode.decodePeek(
+ self.stream.peek(lengthCode.maxLength))[1].index
+ #in every branch, set lengthCode.description to explanatory text
+ #lengthCode calls format(symbol, extra) with this string
+ if length==0:
+ symbol = next(alphabetIter)
+ lengthCode.description = 'symbol {} unused'.format(symbol)
+ self.verboseRead(lengthCode)
+ #unused symbol
+ continue
+ if length==16:
+ lengthCode.description = \
+ '{1}+3 symbols of length '+str(lastLength)
+ extra = self.verboseRead(lengthCode)
+ #scan series of 16s (repeat counts)
+ #start with repeat count 2
+ repeat = 2
+ startSymbol = next(alphabetIter)
+ endSymbol = next(alphabetIter)
+ symbolLengths[startSymbol.index] = \
+ symbolLengths[endSymbol.index] = lastLength
+ #count the two just defined symbols
+ total += 2*32768>>lastLength
+ #note: loop may end because we're there
+ #even if a 16 _appears_ to follow
+ while True:
+ #determine last symbol
+ oldRepeat = repeat
+ repeat = (repeat-2<<2)+extra+3
+ #read as many symbols as repeat increased
+ for i in range(oldRepeat, repeat):
+ endSymbol = next(alphabetIter)
+ symbolLengths[endSymbol.index] = lastLength
+ #compute new total; it may be end of loop
+ total += (repeat-oldRepeat)*32768>>lastLength
+ if total>=32768: break
+ #see if there is more to do
+ length = lengthCode.decodePeek(
+ self.stream.peek(lengthCode.maxLength))[1].index
+ if length!=16: break
+ lengthCode.description = 'total {}+{{1}} symbols'.format(
+ (repeat-2<<2)+3)
+ extra = self.verboseRead(lengthCode)
+ elif length==17:
+ #read, and show explanation
+ lengthCode.description = '{1}+3 unused'
+ extra = self.verboseRead(lengthCode)
+ #scan series of 17s (groups of zero counts)
+ #start with repeat count 2
+ repeat = 2
+ startSymbol = next(alphabetIter)
+ endSymbol = next(alphabetIter)
+ #note: loop will not end with total==32768,
+ #since total doesn't change here
+ while True:
+ #determine last symbol
+ oldRepeat = repeat
+ repeat = (repeat-2<<3)+extra+3
+ #read as many symbols as repeat increases
+ for i in range(repeat-oldRepeat):
+ endSymbol = next(alphabetIter)
+ #see if there is more to do
+ length = lengthCode.decodePeek(
+ self.stream.peek(lengthCode.maxLength))[1].index
+ if length!=17: break
+ lengthCode.description = 'total {}+{{1}} unused'.format(
+ (repeat-2<<3)+3)
+ extra = self.verboseRead(lengthCode)
+ else:
+ symbol = next(alphabetIter)
+ #double braces for format
+ char = str(symbol)
+ if char in '{}': char *= 2
+ lengthCode.description = \
+ 'Length for {} is {{0.index}} bits'.format(char)
+ #output is not needed (will be 0)
+ self.verboseRead(lengthCode)
+ symbolLengths[symbol.index] = length
+ total += 32768>>length
+ lastLength = length
+ assert total==32768
+ alphabet.setLength(symbolLengths)
+ print('End of table. Prefix code '+alphabet.name+':')
+ alphabet.showCode()
+
+ #stream
+ def processStream(self):
+ """Process a brotli stream.
+ """
+ print('addr hex{:{}s}binary context explanation'.format(
+ '', self.width-10))
+ print('Stream header'.center(60, '-'))
+ self.windowSize = self.verboseRead(WindowSizeAlphabet())
+ print('Metablock header'.center(60, '='))
+ self.ISLAST = False
+ self.output = bytearray()
+ while not self.ISLAST:
+ self.ISLAST = self.verboseRead(
+ BoolCode('LAST', description="Last block"))
+ if self.ISLAST:
+ if self.verboseRead(
+ BoolCode('EMPTY', description="Empty block")): break
+ if self.metablockLength(): continue
+ if not self.ISLAST and self.uncompressed(): continue
+ print('Block type descriptors'.center(60, '-'))
+ self.numberOfBlockTypes = {}
+ self.currentBlockCounts = {}
+ self.blockTypeCodes = {}
+ self.blockCountCodes = {}
+ for blockType in (L,I,D): self.blockType(blockType)
+ print('Distance code parameters'.center(60, '-'))
+ self.NPOSTFIX, self.NDIRECT = self.verboseRead(DistanceParamAlphabet())
+ self.readLiteralContextModes()
+ print('Context maps'.center(60, '-'))
+ self.cmaps = {}
+ #keep the number of each kind of prefix tree for the last loop
+ numberOfTrees = {I: self.numberOfBlockTypes[I]}
+ for blockType in (L,D):
+ numberOfTrees[blockType] = self.contextMap(blockType)
+ print('Prefix code lists'.center(60, '-'))
+ self.prefixCodes = {}
+ for blockType in (L,I,D):
+ self.readPrefixArray(blockType, numberOfTrees[blockType])
+ self.metablock()
+
+ #metablock header
+ def verboseRead(self, alphabet, context='', skipExtra=False):
+ """Read symbol and extra from stream and explain what happens.
+ Returns the value of the symbol
+ >>> olleke.pos = 0
+ >>> l = Layout(olleke)
+ >>> l.verboseRead(WindowSizeAlphabet())
+ 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288
+ 4194288
+ """
+ #TODO 2: verbosity level, e.g. show only codes and maps in header
+ stream = self.stream
+ pos = stream.pos
+ if skipExtra:
+ length, symbol = alphabet.readTuple(stream)
+ extraBits, extra = 0, None
+ else:
+ length, symbol, extraBits, extra = alphabet.readTupleAndExtra(
+ stream)
+ #fields: address, hex data, binary data, name of alphabet, explanation
+ hexdata = self.makeHexData(pos)
+ addressField = '{:04x}'.format(pos+7>>3) if hexdata else ''
+ bitdata = self.formatBitData(pos, length, extraBits)
+ #bitPtr moves bitdata so that the bytes are easier to read
+ #jump back to right if a new byte starts
+ if '|' in bitdata[1:]:
+ #start over on the right side
+ self.bitPtr = self.width
+ fillWidth = self.bitPtr-(len(hexdata)+len(bitdata))
+ if fillWidth<0: fillWidth = 0
+ print('{:<5s} {:<{}s} {:7s} {}'.format(
+ addressField,
+ hexdata+' '*fillWidth+bitdata, self.width,
+ context+alphabet.name,
+ symbol if skipExtra else symbol.explanation(extra),
+ ))
+ #jump to the right if we started with a '|'
+ #because we didn't jump before printing
+ if bitdata.startswith('|'): self.bitPtr = self.width
+ else: self.bitPtr -= len(bitdata)
+ return symbol if skipExtra else symbol.value(extra)
+
+ def metablockLength(self):
+ """Read MNIBBLES and meta block length;
+ if empty block, skip block and return true.
+ """
+ self.MLEN = self.verboseRead(MetablockLengthAlphabet())
+ if self.MLEN:
+ return False
+ #empty block; skip and return False
+ self.verboseRead(ReservedAlphabet())
+ MSKIP = self.verboseRead(SkipLengthAlphabet())
+ self.verboseRead(FillerAlphabet(streamPos=self.stream.pos))
+ self.stream.pos += 8*MSKIP
+ print("Skipping to {:x}".format(self.stream.pos>>3))
+ return True
+
+ def uncompressed(self):
+ """If true, handle uncompressed data
+ """
+ ISUNCOMPRESSED = self.verboseRead(
+ BoolCode('UNCMPR', description='Is uncompressed?'))
+ if ISUNCOMPRESSED:
+ self.verboseRead(FillerAlphabet(streamPos=self.stream.pos))
+ print('Uncompressed data:')
+ self.output += self.stream.readBytes(self.MLEN)
+ print(outputFormatter(self.output[-self.MLEN:]))
+ return ISUNCOMPRESSED
+
+ def blockType(self, kind):
+ """Read block type switch descriptor for given kind of blockType."""
+ NBLTYPES = self.verboseRead(TypeCountAlphabet(
+ 'BT#'+kind[0].upper(),
+ description='{} block types'.format(kind),
+ ))
+ self.numberOfBlockTypes[kind] = NBLTYPES
+ if NBLTYPES>=2:
+ self.blockTypeCodes[kind] = self.readPrefixCode(
+ BlockTypeAlphabet('BT'+kind[0].upper(), NBLTYPES))
+ self.blockCountCodes[kind] = self.readPrefixCode(
+ BlockCountAlphabet('BC'+kind[0].upper()))
+ blockCount = self.verboseRead(self.blockCountCodes[kind])
+ else:
+ blockCount = 1<<24
+ self.currentBlockCounts[kind] = blockCount
+
+ def readLiteralContextModes(self):
+ """Read literal context modes.
+ LSB6: lower 6 bits of last char
+ MSB6: upper 6 bits of last char
+ UTF8: rougly dependent on categories:
+ upper 4 bits depend on category of last char:
+ control/whitespace/space/ punctuation/quote/%/open/close/
+ comma/period/=/digits/ VOWEL/CONSONANT/vowel/consonant
+ lower 2 bits depend on category of 2nd last char:
+ space/punctuation/digit or upper/lowercase
+ signed: hamming weight of last 2 chars
+ """
+ print('Context modes'.center(60, '-'))
+ self.literalContextModes = []
+ for i in range(self.numberOfBlockTypes[L]):
+ self.literalContextModes.append(
+ self.verboseRead(LiteralContextMode(number=i)))
+
+ def contextMap(self, kind):
+ """Read context maps
+ Returns the number of differnt values on the context map
+ (In other words, the number of prefix trees)
+ """
+ NTREES = self.verboseRead(TypeCountAlphabet(
+ kind[0].upper()+'T#',
+ description='{} prefix trees'.format(kind)))
+ mapSize = {L:64, D:4}[kind]
+ if NTREES<2:
+ self.cmaps[kind] = [0]*mapSize
+ else:
+ #read CMAPkind
+ RLEMAX = self.verboseRead(RLEmaxAlphabet(
+ 'RLE#'+kind[0].upper(),
+ description=kind+' context map'))
+ alphabet = TreeAlphabet('CM'+kind[0].upper(), NTREES=NTREES, RLEMAX=RLEMAX)
+ cmapCode = self.readPrefixCode(alphabet)
+ tableSize = mapSize*self.numberOfBlockTypes[kind]
+ cmap = []
+ while len(cmap)<tableSize:
+ cmapCode.description = 'map {}, entry {}'.format(
+ *divmod(len(cmap), mapSize))
+ count, value = self.verboseRead(cmapCode)
+ cmap.extend([value]*count)
+ assert len(cmap)==tableSize
+ IMTF = self.verboseRead(BoolCode('IMTF', description='Apply inverse MTF'))
+ if IMTF:
+ self.IMTF(cmap)
+ if kind==L:
+ print('Context maps for literal data:')
+ for i in range(0, len(cmap), 64):
+ print(*(
+ ''.join(map(str, cmap[j:j+8]))
+ for j in range(i, i+64, 8)
+ ))
+ else:
+ print('Context map for distances:')
+ print(*(
+ ''.join(map('{:x}'.format, cmap[i:i+4]))
+ for i in range(0, len(cmap), 4)
+ ))
+ self.cmaps[kind] = cmap
+ return NTREES
+
+ @staticmethod
+ def IMTF(v):
+ """In place inverse move to front transform.
+ """
+ #mtf is initialized virtually with range(infinity)
+ mtf = []
+ for i, vi in enumerate(v):
+ #get old value from mtf. If never seen, take virtual value
+ try: value = mtf.pop(vi)
+ except IndexError: value = vi
+ #put value at front
+ mtf.insert(0, value)
+ #replace transformed value
+ v[i] = value
+
+ def readPrefixArray(self, kind, numberOfTrees):
+ """Read prefix code array"""
+ prefixes = []
+ for i in range(numberOfTrees):
+ if kind==L: alphabet = LiteralAlphabet(i)
+ elif kind==I: alphabet = InsertAndCopyAlphabet(i)
+ elif kind==D: alphabet = DistanceAlphabet(
+ i, NPOSTFIX=self.NPOSTFIX, NDIRECT=self.NDIRECT)
+ self.readPrefixCode(alphabet)
+ prefixes.append(alphabet)
+ self.prefixCodes[kind] = prefixes
+
+ #metablock data
+ def metablock(self):
+ """Process the data.
+ Relevant variables of self:
+ numberOfBlockTypes[kind]: number of block types
+ currentBlockTypes[kind]: current block types (=0)
+ literalContextModes: the context modes for the literal block types
+ currentBlockCounts[kind]: counters for block types
+ blockTypeCodes[kind]: code for block type
+ blockCountCodes[kind]: code for block count
+ cmaps[kind]: the context maps (not for I)
+ prefixCodes[kind][#]: the prefix codes
+ lastDistances: the last four distances
+ lastChars: the last two chars
+ output: the result
+ """
+ print('Meta block contents'.center(60, '='))
+ self.currentBlockTypes = {L:0, I:0, D:0, pL:1, pI:1, pD:1}
+ self.lastDistances = deque([17,16,11,4], maxlen=4)
+ #the current context mode is for block type 0
+ self.contextMode = ContextModeKeeper(self.literalContextModes[0])
+ wordList = WordList()
+
+ #setup distance callback function
+ def distanceCallback(symbol, extra):
+ "callback function for displaying decoded distance"
+ index, offset = symbol.value(extra)
+ if index:
+ #recent distance
+ distance = self.lastDistances[-index]+offset
+ return 'Distance: {}last{:+d}={}'.format(index, offset, distance)
+ #absolute value
+ if offset<=maxDistance:
+ return 'Absolute value: {} (pos {})'.format(offset, maxDistance-offset)
+ #word list value
+ action, word = divmod(offset-maxDistance, 1<<wordList.NDBITS[copyLen])
+ return '{}-{} gives word {},{} action {}'.format(
+ offset, maxDistance, copyLen, word, action)
+ for dpc in self.prefixCodes[D]: dpc.callback = distanceCallback
+
+ blockLen = 0
+ #there we go
+ while blockLen<self.MLEN:
+ #get insert&copy command
+ litLen, copyLen, dist0Flag = self.verboseRead(
+ self.prefixCodes[I][
+ self.figureBlockType(I)])
+ #literal data
+ for i in range(litLen):
+ bt = self.figureBlockType(L)
+ cm = self.contextMode.getIndex()
+ ct = self.cmaps[L][bt<<6|cm]
+ char = self.verboseRead(
+ self.prefixCodes[L][ct],
+ context='{},{}='.format(bt,cm))
+ self.contextMode.add(char)
+ self.output.append(char)
+ blockLen += litLen
+ #check if we're done
+ if blockLen>=self.MLEN: return
+ #distance
+ #distances are computed relative to output length, at most window size
+ maxDistance = min(len(self.output), self.windowSize)
+ if dist0Flag:
+ distance = self.lastDistances[-1]
+ else:
+ bt = self.figureBlockType(D)
+ cm = {2:0, 3:1, 4:2}.get(copyLen, 3)
+ ct = self.cmaps[D][bt<<2|cm]
+ index, offset = self.verboseRead(
+ self.prefixCodes[D][ct],
+ context='{},{}='.format(bt,cm))
+ distance = self.lastDistances[-index]+offset if index else offset
+ if index==1 and offset==0:
+ #to make sure distance is not put in last distance list
+ dist0Flag = True
+ if distance<=maxDistance:
+ #copy from output
+ for i in range(
+ maxDistance-distance,
+ maxDistance-distance+copyLen):
+ self.output.append(self.output[i])
+ if not dist0Flag: self.lastDistances.append(distance)
+ comment = 'Seen before'
+ else:
+ #fetch from wordlist
+ newWord = wordList.word(copyLen, distance-maxDistance-1)
+ self.output.extend(newWord)
+ #adjust copyLen to reflect actual new data
+ copyLen = len(newWord)
+ comment = 'From wordlist'
+ blockLen += copyLen
+ print(' '*40,
+ comment,
+ ': "',
+ outputFormatter(self.output[-copyLen:]),
+ '"',
+ sep='')
+ self.contextMode.add(self.output[-2])
+ self.contextMode.add(self.output[-1])
+
+ def figureBlockType(self, kind):
+ counts, types = self.currentBlockCounts, self.currentBlockTypes
+ if counts[kind]==0:
+ newType = self.verboseRead(self.blockTypeCodes[kind])
+ if newType==-2: newType = types['P'+kind]
+ elif newType==-1:
+ newType = (types[kind]+1)%self.numberOfBlockTypes[kind]
+ types['P'+kind] = types[kind]
+ types[kind] = newType
+ counts[kind] = self.verboseRead(self.blockCountCodes[kind])
+ counts[kind] -=1
+ return types[kind]
+
+__test__ = {
+'BitStream': """
+ >>> bs = BitStream(b'Jurjen')
+ >>> bs.readBytes(2)
+ b'Ju'
+ >>> bs.read(6) #r=01110010
+ 50
+ >>> bs
+ BitStream(pos=2:6)
+ >>> bs.peek(5) #j=01101010
+ 9
+ >>> bs.readBytes(2)
+ Traceback (most recent call last):
+ ...
+ ValueError: readBytes: need byte boundary
+ """,
+
+'Symbol': """
+ >>> a=Symbol(MetablockLengthAlphabet(),5)
+ >>> len(a)
+ 2
+ >>> int(a)
+ 5
+ >>> a.bitPattern()
+ '01'
+ >>> a.value(200000)
+ 200001
+ >>> a.explanation(300000)
+ 'data length: 493e0h+1=300001'
+ """,
+
+'RangeDecoder': """
+ >>> a=RangeDecoder(bitLength=3)
+ >>> len(a)
+ 8
+ >>> a.name='t'
+ >>> list(a)
+ [Symbol(t, 0), Symbol(t, 1), Symbol(t, 2), Symbol(t, 3), Symbol(t, 4), Symbol(t, 5), Symbol(t, 6), Symbol(t, 7)]
+ >>> a[2]
+ Symbol(t, 2)
+ >>> a.bitPattern(4)
+ '100'
+ >>> a.length(2)
+ 3
+ >>> a.decodePeek(15)
+ (3, Symbol(t, 7))
+ >>>
+
+ """,
+
+'PrefixDecoder': """
+ >>> a=PrefixDecoder(decodeTable={0:1,1:2,3:3,7:4})
+ >>> len(a)
+ 4
+ >>> a.name='t'
+ >>> list(a)
+ [Symbol(t, 1), Symbol(t, 2), Symbol(t, 3), Symbol(t, 4)]
+ >>> a.decodePeek(22)
+ (1, Symbol(t, 1))
+ >>> a.decodePeek(27)
+ (3, Symbol(t, 3))
+ >>> a.length(1)
+ 1
+ >>> a.length(4)
+ 3
+ """,
+
+'Code': """
+ >>> a=Code('t',alphabetSize=10)
+ >>> len(a)
+ 10
+ >>> a.showCode()
+ 0000:0 0001:1 0010:2 0011:3 0100:4 0101:5 0110:6 0111:7 1000:8 1001:9
+ >>> a.setLength({2:1,3:2,5:3,6:3})
+ >>> a.showCode()
+ 0:2 01:3 011:5 111:6
+ >>> len(a)
+ 4
+ >>> def callback(i): return 'call{}back'.format(i)
+ >>> a=Code('t',callback=callback,bitLength=3)
+ >>> a[6].explanation()
+ 'call6back'
+ """,
+
+'WithExtra': """
+ >>> class A(WithExtra):
+ ... extraTable = [0,1,1,2,2]
+ >>> a=A('t',alphabetSize=5)
+ >>> a[1]
+ Symbol(t, 1)
+ >>> a.extraBits(2)
+ 1
+ >>> a.mnemonic(4)
+ '4'
+ >>> a.readTupleAndExtra(BitStream(b'\x5b'))
+ (3, Symbol(t, 3), 2, 3)
+ """,
+
+'BoolCode': """
+ >>> BoolCode('test')[0].explanation()
+ '0: False'
+ """,
+
+'Enumerator': """
+ >>> class A(Enumerator):
+ ... extraTable = [0,1,1,2,2]
+ ... value0=3
+ >>> a=A(alphabetLength=5)
+ >>> a.value(3)
+ Traceback (most recent call last):
+ ...
+ TypeError: value() missing 1 required positional argument: 'extra'
+ >>> a.explanation(3,4)
+ 'xx 011: 8-11; 8+4=12'
+ """,
+
+'WindowSizeAlphabet': """
+ >>> windowSizeAlphabet = WindowSizeAlphabet()
+ >>> windowSizeAlphabet[0]
+ Traceback (most recent call last):
+ ...
+ ValueError: No symbol WindowSizeAlphabet[0]
+ >>> len(windowSizeAlphabet)
+ 16
+ >>> windowSizeAlphabet[21]
+ Symbol(WSIZE, 21)
+ >>> windowSizeAlphabet[21].bitPattern()
+ '1001'
+ >>> windowSizeAlphabet[21].extraBits()
+ 0
+ >>> windowSizeAlphabet[21].index
+ 21
+ >>> windowSizeAlphabet[10].value()
+ 1008
+ >>> windowSizeAlphabet[10].explanation()
+ 'windowsize=(1<<10)-16=1008'
+ >>> windowSizeAlphabet.showCode()
+ 0:65520 1100001:16368 1110001:32752 0011:262128
+ 0000001:131056 0010001:None 1001:2097136 1011:4194288
+ 1000001:4080 1010001:8176 0101:524272 0111:1048560
+ 0100001:1008 0110001:2032 1101:8388592 1111:16777200
+ """,
+
+'TypeCountAlphabet': """
+ >>> typeCountAlphabet = TypeCountAlphabet(description='bananas')
+ >>> len(typeCountAlphabet)
+ 9
+ >>> typeCountAlphabet[3]
+ Symbol(BT#, 3)
+ >>> typeCountAlphabet[9]
+ Traceback (most recent call last):
+ ...
+ ValueError: No symbol TypeCountAlphabet[9]
+ >>> print(typeCountAlphabet[3])
+ xx,0101
+ >>> typeCountAlphabet[8].value(127)
+ 256
+ >>> typeCountAlphabet[4].explanation(2)
+ 'xxx,0111: 11 bananas'
+ >>> typeCountAlphabet[0].explanation()
+ '0: 1 banana'
+ """,
+
+'DistanceParamAlphabet': """
+ >>> dpa = DistanceParamAlphabet()
+ >>> dpa.showCode()
+ 00:PF0 01:PF1 10:PF2 11:PF3
+ >>> dpa.readTupleAndExtra(BitStream(b'\\x29'))
+ (2, Symbol(DIST, 1), 4, 10)
+ >>> dpa.explanation(2, 5)
+ '2 postfix bits and 0101<<2=20 direct codes'
+ """,
+
+'LiteralAlphabet': """
+ >>> LiteralAlphabet(-1).showCode() #doctest: +ELLIPSIS
+ 00000000:\\x00 00110100:4 01101000:h 10011100:\\x9c 11010000:\\xd0
+ 00000001:\\x01 00110101:5 01101001:i 10011101:\\x9d 11010001:\\xd1
+ 00000010:\\x02 00110110:6 01101010:j 10011110:\\x9e 11010010:\\xd2
+ ...
+ 00101111:/ 01100011:c 10010111:\\x97 11001011:\\xcb 11111111:\\xff
+ 00110000:0 01100100:d 10011000:\\x98 11001100:\\xcc
+ 00110001:1 01100101:e 10011001:\\x99 11001101:\\xcd
+ 00110010:2 01100110:f 10011010:\\x9a 11001110:\\xce
+ 00110011:3 01100111:g 10011011:\\x9b 11001111:\\xcf
+ """,
+
+'BlockCountAlphabet': """
+ >>> bc=BlockCountAlphabet('BCL')
+ >>> len(bc)
+ 26
+ >>> bs=BitStream(b'\\x40\\x83\\xc8\\x59\\12\\x02')
+ >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3])
+ 'Block count: xx 00000: 1-4; 1+2=3'
+ >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3])
+ 'Block count: xxx 00110: 33-40; 33+0=33'
+ >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3])
+ 'Block count: xxxxxx 10001: 305-368; 305+28=333'
+ >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3])
+ 'Block count: xxxxxxxxxxx 10110: 2289-4336; 2289+1044=3333'
+ """,
+
+'Layout': """
+ >>> olleke.pos = 0
+ >>> l = Layout(olleke)
+ >>> l.verboseRead(WindowSizeAlphabet())
+ 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288
+ 4194288
+ >>> l.verboseRead(BoolCode('LAST', description="Last block"))
+ 1 LAST Last block: 1: True
+ True
+ >>> l.verboseRead(BoolCode('EMPTY', description="Empty block"))
+ 0 EMPTY Empty block: 0: False
+ False
+ >>> l.verboseRead(MetablockLengthAlphabet())
+ 0001 2e 00 |00h|2Eh,|00 MLEN data length: 002eh+1=47
+ 47
+ >>> olleke.pos = 76
+ >>> l = Layout(olleke)
+ >>> x = l.verboseRead(DistanceAlphabet(0,NPOSTFIX=0,NDIRECT=0), skipExtra=True)
+ 000a 82 10|1100 D0 10[15*x]-3
+ >>> x.explanation(0x86a3)
+ '10[1000011010100011]-3: [0]+100000'
+ """,
+
+'olleke': """
+ >>> olleke.pos = 0
+ >>> try: Layout(olleke).processStream()
+ ... except NotImplementedError: pass
+ ... #doctest: +REPORT_NDIFF
+ addr hex binary context explanation
+ -----------------------Stream header------------------------
+ 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288
+ ======================Metablock header======================
+ 1 LAST Last block: 1: True
+ 0 EMPTY Empty block: 0: False
+ 0001 2e 00 |00h|2Eh,|00 MLEN data length: 002eh+1=47
+ -------------------Block type descriptors-------------------
+ 0003 00 0 BT#L 0: 1 literal block type
+ 0 BT#I 0: 1 insert&copy block type
+ 0 BT#D 0: 1 distance block type
+ ------------------Distance code parameters------------------
+ 0004 44 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes
+ -----------------------Context modes------------------------
+ 10 LC0 Context mode for type 0: 2(UTF8)
+ ------------------------Context maps------------------------
+ 0 LT# 0: 1 literal prefix tree
+ 0 DT# 0: 1 distance prefix tree
+ ---------------------Prefix code lists----------------------
+ 10 PFX L0 is complex with lengths 3,4,0,5,17...
+ 0005 4f 1|0 ##L0 len 3: coded with 3 bits
+ 0111 ##L0 len 4: coded with 1 bits
+ 10 ##L0 unused: coded with 3 bits
+ 0006 d6 0|0 ##L0 len 5: skipped
+ 011 ##L0 zero xxx: coded with 2 bits
+ ***** Lengths for L0 will be coded as:
+ 0:len 4 01:zero xxx 011:unused 111:len 3
+ 0007 95 1|11,01 #L0 7+3 unused
+ 0 #L0 Length for \\n is 4 bits
+ 001,01 #L0 1+3 unused
+ 0008 44 010,0|1 #L0 total 19+2 unused
+ 0 #L0 Length for " " is 4 bits
+ 0 #L0 Length for ! is 4 bits
+ 0009 cb 011,|01 #L0 3+3 unused
+ |110,01 #L0 total 35+6 unused
+ 000a 82 0 #L0 Length for K is 4 bits
+ 000,01 #L0 0+3 unused
+ 0 #L0 Length for O is 4 bits
+ 000b 4d 01|1 #L0 symbol P unused
+ 011 #L0 symbol Q unused
+ 0 #L0 Length for R is 4 bits
+ 000c 88 000,|01 #L0 0+3 unused
+ |100,01 #L0 total 11+4 unused
+ 000d b6 0 #L0 Length for b is 4 bits
+ 011 #L0 symbol c unused
+ 011 #L0 symbol d unused
+ 000e 27 11|1 #L0 Length for e is 3 bits
+ 010,01 #L0 2+3 unused
+ |0 #L0 Length for k is 4 bits
+ 000f 1f 111 #L0 Length for l is 3 bits
+ 011 #L0 symbol m unused
+ 0 #L0 Length for n is 4 bits
+ |0 #L0 Length for o is 4 bits
+ 0010 c1 000,01 #L0 0+3 unused
+ 0 #L0 Length for s is 4 bits
+ 0011 b4 0|11 #L0 symbol t unused
+ 0 #L0 Length for u is 4 bits
+ End of table. Prefix code L0:
+ 000:e 0010:\\n 0110:! 0001:O 0101:b 0011:n 0111:s
+ 100:l 1010:" " 1110:K 1001:R 1101:k 1011:o 1111:u
+ 11,01 PFX IC0 is simple with 4 code words
+ 0012 2a |2Ah|10 IC0 ? bits: I5C4
+ 0013 b5 ec 00|B5h IC0 ? bits: I6+xC7
+ 0015 22 0010|111011 IC0 ? bits: I8+xC5
+ 0016 8c 001100|0010 IC0 ? bits: I0C14+xx
+ 0 SHAPE False: lengths 2,2,2,2
+ 0017 74 10,0|1 PFX D0 is simple with 3 code words
+ 0018 a6 0|01110 D0 1 bit: 2last-3
+ 010011 D0 2 bits: 11xx-3
+ 0019 aa 01010|1 D0 2 bits: 11xxx-3
+ ====================Meta block contents=====================
+ |1,01 IC0 Literal: 9, copy: 5
+ 001a 41 0001 0,0=L0 O
+ 100 0,48=L0 l
+ 001b a2 10|0 0,62=L0 l
+ 000 0,63=L0 e
+ 001c a1 1|101 0,59=L0 k
+ 000 0,63=L0 e
+ |1010 0,59=L0 " "
+ 001d b5 0101 0,11=L0 b
+ |1011 0,60=L0 o
+ 001e 24 0 0,3=D0 Distance: 2last-3=8
+ Seen before: "lleke"
+ 0,10 IC0 Literal: 6, copy: 7
+ |0010 0,59=L0 \\n
+ 001f 89 1001 0,7=L0 R
+ 000 0,52=L0 e
+ 0020 fa 010|1 0,58=L0 b
+ 1111 0,63=L0 u
+ 0021 eb 011|1 0,59=L0 s
+ 11,01 0,3=D0 Absolute value: 12 (pos 8)
+ Seen before: "olleke\\n"
+ 0022 db 01,1|1 IC0 Literal: 0, copy: 15
+ |110,11 0,3=D0 Absolute value: 27 (pos 0)
+ Seen before: "Olleke bolleke\\n"
+ 0023 f8 00 IC0 Literal: 5, copy: 4
+ 1110 0,7=L0 K
+ 0024 2c 00|11 0,52=L0 n
+ 1011 0,62=L0 o
+ 0025 0d 1|00 0,59=L0 l
+ 0110 0,63=L0 !
+ """,
+
+'file': """
+ >>> try: Layout(BitStream(
+ ... open("H:/Downloads/brotli-master/tests/testdata/10x10y.compressed",'rb')
+ ... .read())).processStream()
+ ... except NotImplementedError: pass
+ addr hex binary context explanation
+ -----------------------Stream header------------------------
+ 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288
+ ======================Metablock header======================
+ 1 LAST Last block: 1: True
+ 0 EMPTY Empty block: 0: False
+ 0001 13 00 |00h|13h,|00 MLEN data length: 0013h+1=20
+ -------------------Block type descriptors-------------------
+ 0003 00 0 BT#L 0: 1 literal block type
+ 0 BT#I 0: 1 insert&copy block type
+ 0 BT#D 0: 1 distance block type
+ ------------------Distance code parameters------------------
+ 0004 a4 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes
+ -----------------------Context modes------------------------
+ 10 LC0 Context mode for type 0: 2(UTF8)
+ ------------------------Context maps------------------------
+ 0 LT# 0: 1 literal prefix tree
+ 0 DT# 0: 1 distance prefix tree
+ ---------------------Prefix code lists----------------------
+ 0005 b0 0|1,01 PFX L0 is simple with 2 code words
+ 0006 b2 0|1011000 L0 1 bit: X
+ 0007 ea 0|1011001 L0 1 bit: Y
+ 01,01 PFX IC0 is simple with 2 code words
+ 0008 81 0000001|111 IC0 1 bit: I1C9&D=0
+ 0009 47 02 0|47h|1 IC0 1 bit: I1C9
+ 00,01 PFX D0 is simple with 1 code word
+ 000b 8a 010|000 D0 0 bits: 10x-3
+ ====================Meta block contents=====================
+ 1 IC0 Literal: 1, copy: 9
+ 0 0,0=L0 X
+ 0,() 0,3=D0 Absolute value: 1 (pos 0)
+ Seen before: "XXXXXXXXX"
+ 0 IC0 Literal: 1, copy: 9, same distance
+ |1 0,54=L0 Y
+ Seen before: "YYYYYYYYY"
+ """,
+
+'XY': """
+ >>> try: Layout(BitStream(brotli.compress('X'*10+'Y'*10))).processStream()
+ ... except NotImplementedError: pass
+ addr hex binary context explanation
+ -----------------------Stream header------------------------
+ 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288
+ ======================Metablock header======================
+ 1 LAST Last block: 1: True
+ 0 EMPTY Empty block: 0: False
+ 0001 13 00 |00h|13h,|00 MLEN data length: 0013h+1=20
+ -------------------Block type descriptors-------------------
+ 0003 00 0 BT#L 0: 1 literal block type
+ 0 BT#I 0: 1 insert&copy block type
+ 0 BT#D 0: 1 distance block type
+ ------------------Distance code parameters------------------
+ 0004 a4 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes
+ -----------------------Context modes------------------------
+ 10 LC0 Context mode for type 0: 2(UTF8)
+ ------------------------Context maps------------------------
+ 0 LT# 0: 1 literal prefix tree
+ 0 DT# 0: 1 distance prefix tree
+ ---------------------Prefix code lists----------------------
+ 0005 b0 0|1,01 PFX L0 is simple with 2 code words
+ 0006 b2 0|1011000 L0 1 bit: X
+ 0007 82 0|1011001 L0 1 bit: Y
+ 00,01 PFX IC0 is simple with 1 code word
+ 0008 84 0000100|100 IC0 0 bits: I4C6&D=0
+ 0009 00 00,0|1 PFX D0 is simple with 1 code word
+ 000a e0 0|00000 D0 0 bits: last
+ ====================Meta block contents=====================
+ () IC0 Literal: 4, copy: 6, same distance
+ 0 0,0=L0 X
+ 0 0,52=L0 X
+ 0 0,54=L0 X
+ 0 0,54=L0 X
+ Seen before: "XXXXXX"
+ () IC0 Literal: 4, copy: 6, same distance
+ 1 0,54=L0 Y
+ 1 0,54=L0 Y
+ |1 0,54=L0 Y
+ 000b 01 1 0,54=L0 Y
+ Seen before: "YYYYYY"
+ """,
+
+'empty': """
+ >>> try: Layout(BitStream(b'\\x81\\x16\\x00\\x58')).processStream()
+ ... except NotImplementedError: pass
+ addr hex binary context explanation
+ -----------------------Stream header------------------------
+ 0000 81 0000001 WSIZE windowsize=(1<<17)-16=131056
+ ======================Metablock header======================
+ |1 LAST Last block: 1: True
+ 0001 16 0 EMPTY Empty block: 0: False
+ 11 MLEN 11: empty block
+ 0 RSVD Reserved (must be zero)
+ 0002 00 000000|00,01 SKIP skip length: 0h+1=1
+ |00 SKIP 2 bits ignored
+ Skipping to 4
+ """,
+
+}
+
+if __name__=='__main__':
+ import sys
+ if len(sys.argv)>1:
+ l = Layout(BitStream(open(sys.argv[1],'rb').read()))
+ l.processStream()
+ else:
+ sys.path.append("h:/Persoonlijk/bin")
+ try:
+ import brotli
+ open('brotlidump.br', 'wb').write(
+ brotli.compress(
+ open('brotlidump.py', 'r').read()
+ ))
+ olleke = BitStream(brotli.compress(
+ 'Olleke bolleke\nRebusolleke\nOlleke bolleke\nKnol!'))
+ except ImportError: pass
+ import doctest
+ doctest.testmod(optionflags=doctest.REPORT_NDIFF
+ #|doctest.FAIL_FAST
+ )
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.cc
new file mode 100644
index 000000000..d15b7ee55
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.cc
@@ -0,0 +1,302 @@
+#include "./deorummolae.h"
+
+#include <array>
+#include <cstdio>
+
+#include "./esaxx/sais.hxx"
+
+/* Used for quick SA-entry to file mapping. Each file is padded to size that
+ is a multiple of chunk size. */
+#define CHUNK_SIZE 64
+/* Length of substring that is considered to be covered by dictionary string. */
+#define CUT_MATCH 6
+/* Minimal dictionary entry size. */
+#define MIN_MATCH 24
+
+/* Non tunable definitions. */
+#define CHUNK_MASK (CHUNK_SIZE - 1)
+#define COVERAGE_SIZE (1 << (DM_LOG_MAX_FILES - 6))
+
+/* File coverage: every bit set to 1 denotes a file covered by an isle. */
+typedef std::array<uint64_t, COVERAGE_SIZE> Coverage;
+
+/* Symbol of text alphabet. */
+typedef int32_t TextChar;
+
+/* Pointer to position in text. */
+typedef uint32_t TextIdx;
+
+/* SAIS sarray_type; unfortunately, must be a signed type. */
+typedef int32_t TextSaIdx;
+
+static size_t popcount(uint64_t u) {
+ return static_cast<size_t>(__builtin_popcountll(u));
+}
+
+/* Condense terminators and pad file entries. */
+static void rewriteText(std::vector<TextChar>* text) {
+ TextChar terminator = text->back();
+ TextChar prev = terminator;
+ TextIdx to = 0;
+ for (TextIdx from = 0; from < text->size(); ++from) {
+ TextChar next = text->at(from);
+ if (next < 256 || prev < 256) {
+ text->at(to++) = next;
+ if (next >= 256) terminator = next;
+ }
+ prev = next;
+ }
+ text->resize(to);
+ if (text->empty()) text->push_back(terminator);
+ while (text->size() & CHUNK_MASK) text->push_back(terminator);
+}
+
+/* Reenumerate terminators for smaller alphabet. */
+static void remapTerminators(std::vector<TextChar>* text,
+ TextChar* next_terminator) {
+ TextChar prev = -1;
+ TextChar x = 256;
+ for (TextIdx i = 0; i < text->size(); ++i) {
+ TextChar next = text->at(i);
+ if (next < 256) { // Char.
+ // Do nothing.
+ } else if (prev < 256) { // Terminator after char.
+ next = x++;
+ } else { // Terminator after terminator.
+ next = prev;
+ }
+ text->at(i) = next;
+ prev = next;
+ }
+ *next_terminator = x;
+}
+
+/* Combine all file entries; create mapping position->file. */
+static void buildFullText(std::vector<std::vector<TextChar>>* data,
+ std::vector<TextChar>* full_text, std::vector<TextIdx>* file_map,
+ std::vector<TextIdx>* file_offset, TextChar* next_terminator) {
+ file_map->resize(0);
+ file_offset->resize(0);
+ full_text->resize(0);
+ for (TextIdx i = 0; i < data->size(); ++i) {
+ file_offset->push_back(full_text->size());
+ std::vector<TextChar>& file = data->at(i);
+ rewriteText(&file);
+ full_text->insert(full_text->end(), file.begin(), file.end());
+ file_map->insert(file_map->end(), file.size() / CHUNK_SIZE, i);
+ }
+ if (false) remapTerminators(full_text, next_terminator);
+}
+
+/* Build longest-common-prefix based on suffix array and text.
+ TODO: borrowed -> unknown efficiency. */
+static void buildLcp(std::vector<TextChar>* text, std::vector<TextIdx>* sa,
+ std::vector<TextIdx>* lcp, std::vector<TextIdx>* invese_sa) {
+ TextIdx size = static_cast<TextIdx>(text->size());
+ lcp->resize(size);
+ TextIdx k = 0;
+ lcp->at(size - 1) = 0;
+ for (TextIdx i = 0; i < size; ++i) {
+ if (invese_sa->at(i) == size - 1) {
+ k = 0;
+ continue;
+ }
+ // Suffix which follow i-th suffix.
+ TextIdx j = sa->at(invese_sa->at(i) + 1);
+ while (i + k < size && j + k < size && text->at(i + k) == text->at(j + k)) {
+ ++k;
+ }
+ lcp->at(invese_sa->at(i)) = k;
+ if (k > 0) --k;
+ }
+}
+
+/* Isle is a range in SA with LCP not less than some value.
+ When we raise the LCP requirement, the isle sunks and smaller isles appear
+ instead. */
+typedef struct {
+ TextIdx lcp;
+ TextIdx l;
+ TextIdx r;
+ Coverage coverage;
+} Isle;
+
+/* Helper routine for `cutMatch`. */
+static void poisonData(TextIdx pos, TextIdx length,
+ std::vector<std::vector<TextChar>>* data, std::vector<TextIdx>* file_map,
+ std::vector<TextIdx>* file_offset, TextChar* next_terminator) {
+ TextIdx f = file_map->at(pos / CHUNK_SIZE);
+ pos -= file_offset->at(f);
+ std::vector<TextChar>& file = data->at(f);
+ TextIdx l = (length == CUT_MATCH) ? CUT_MATCH : 1;
+ for (TextIdx j = 0; j < l; j++, pos++) {
+ if (file[pos] >= 256) continue;
+ if (file[pos + 1] >= 256) {
+ file[pos] = file[pos + 1];
+ } else if (pos > 0 && file[pos - 1] >= 256) {
+ file[pos] = file[pos - 1];
+ } else {
+ file[pos] = (*next_terminator)++;
+ }
+ }
+}
+
+/* Remove substrings of a given match from files.
+ Substrings are replaced with unique terminators, so next iteration SA would
+ not allow to cross removed areas. */
+static void cutMatch(std::vector<std::vector<TextChar>>* data, TextIdx index,
+ TextIdx length, std::vector<TextIdx>* sa, std::vector<TextIdx>* lcp,
+ std::vector<TextIdx>* invese_sa, TextChar* next_terminator,
+ std::vector<TextIdx>* file_map, std::vector<TextIdx>* file_offset) {
+ while (length >= CUT_MATCH) {
+ TextIdx i = index;
+ while (lcp->at(i) >= length) {
+ i++;
+ poisonData(
+ sa->at(i), length, data, file_map, file_offset, next_terminator);
+ }
+ while (true) {
+ poisonData(
+ sa->at(index), length, data, file_map, file_offset, next_terminator);
+ if (index == 0 || lcp->at(index - 1) < length) break;
+ index--;
+ }
+ length--;
+ index = invese_sa->at(sa->at(index) + 1);
+ }
+}
+
+std::string DM_generate(size_t dictionary_size_limit,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data) {
+ {
+ TextIdx tmp = static_cast<TextIdx>(dictionary_size_limit);
+ if ((tmp != dictionary_size_limit) || (tmp > 1u << 30)) {
+ fprintf(stderr, "dictionary_size_limit is too large\n");
+ return "";
+ }
+ }
+
+ /* Could use 256 + '0' for easier debugging. */
+ TextChar next_terminator = 256;
+
+ std::string output;
+ std::vector<std::vector<TextChar>> data;
+
+ TextIdx offset = 0;
+ size_t num_samples = sample_sizes.size();
+ if (num_samples > DM_MAX_FILES) num_samples = DM_MAX_FILES;
+ for (size_t n = 0; n < num_samples; ++n) {
+ TextIdx delta = static_cast<TextIdx>(sample_sizes[n]);
+ if (delta != sample_sizes[n]) {
+ fprintf(stderr, "sample is too large\n");
+ return "";
+ }
+ if (delta == 0) {
+ fprintf(stderr, "0-length samples are prohibited\n");
+ return "";
+ }
+ TextIdx next_offset = offset + delta;
+ if (next_offset <= offset) {
+ fprintf(stderr, "corpus is too large\n");
+ return "";
+ }
+ data.push_back(
+ std::vector<TextChar>(sample_data + offset, sample_data + next_offset));
+ offset = next_offset;
+ data.back().push_back(next_terminator++);
+ }
+
+ /* Most arrays are allocated once, and then just resized to smaller and
+ smaller sizes. */
+ std::vector<TextChar> full_text;
+ std::vector<TextIdx> file_map;
+ std::vector<TextIdx> file_offset;
+ std::vector<TextIdx> sa;
+ std::vector<TextIdx> invese_sa;
+ std::vector<TextIdx> lcp;
+ std::vector<Isle> isles;
+ std::vector<char> output_data;
+ TextIdx total = 0;
+ TextIdx total_cost = 0;
+ TextIdx best_cost;
+ Isle best_isle;
+ size_t min_count = num_samples;
+
+ while (true) {
+ TextIdx max_match = static_cast<TextIdx>(dictionary_size_limit) - total;
+ buildFullText(&data, &full_text, &file_map, &file_offset, &next_terminator);
+ sa.resize(full_text.size());
+ /* Hopefully, non-negative TextSaIdx is the same sa TextIdx counterpart. */
+ saisxx(full_text.data(), reinterpret_cast<TextSaIdx*>(sa.data()),
+ static_cast<TextChar>(full_text.size()), next_terminator);
+ invese_sa.resize(full_text.size());
+ for (TextIdx i = 0; i < full_text.size(); ++i) {
+ invese_sa[sa[i]] = i;
+ }
+ buildLcp(&full_text, &sa, &lcp, &invese_sa);
+
+ /* Do not rebuild SA/LCP, just use different selection. */
+ retry:
+ best_cost = 0;
+ best_isle = {0, 0, 0, {{0}}};
+ isles.resize(0);
+ isles.push_back(best_isle);
+
+ for (TextIdx i = 0; i < lcp.size(); ++i) {
+ TextIdx l = i;
+ Coverage cov = {{0}};
+ size_t f = file_map[sa[i] / CHUNK_SIZE];
+ cov[f >> 6] = (static_cast<uint64_t>(1)) << (f & 63);
+ while (lcp[i] < isles.back().lcp) {
+ Isle& top = isles.back();
+ top.r = i;
+ l = top.l;
+ for (size_t x = 0; x < cov.size(); ++x) cov[x] |= top.coverage[x];
+ size_t count = 0;
+ for (size_t x = 0; x < cov.size(); ++x) count += popcount(cov[x]);
+ TextIdx effective_lcp = top.lcp;
+ /* Restrict (last) dictionary entry length. */
+ if (effective_lcp > max_match) effective_lcp = max_match;
+ TextIdx cost = count * effective_lcp;
+ if (cost > best_cost && count >= min_count &&
+ effective_lcp >= MIN_MATCH) {
+ best_cost = cost;
+ best_isle = top;
+ best_isle.lcp = effective_lcp;
+ }
+ isles.pop_back();
+ for (size_t x = 0; x < cov.size(); ++x) {
+ isles.back().coverage[x] |= cov[x];
+ }
+ }
+ if (lcp[i] > isles.back().lcp) isles.push_back({lcp[i], l, 0, {{0}}});
+ for (size_t x = 0; x < cov.size(); ++x) {
+ isles.back().coverage[x] |= cov[x];
+ }
+ }
+
+ /* When saturated matches do not match length restrictions, lower the
+ saturation requirements. */
+ if (best_cost == 0 || best_isle.lcp < MIN_MATCH) {
+ if (min_count >= 8) {
+ min_count = (min_count * 7) / 8;
+ fprintf(stderr, "Retry: min_count=%zu\n", min_count);
+ goto retry;
+ }
+ break;
+ }
+
+ /* Save the entry. */
+ fprintf(stderr, "Savings: %d+%d, dictionary: %d+%d\n",
+ total_cost, best_cost, total, best_isle.lcp);
+ int* piece = &full_text[sa[best_isle.l]];
+ output.insert(output.end(), piece, piece + best_isle.lcp);
+ total += best_isle.lcp;
+ total_cost += best_cost;
+ cutMatch(&data, best_isle.l, best_isle.lcp, &sa, &lcp, &invese_sa,
+ &next_terminator, &file_map, &file_offset);
+ if (total >= dictionary_size_limit) break;
+ }
+
+ return output;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.h
new file mode 100644
index 000000000..581509726
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/deorummolae.h
@@ -0,0 +1,26 @@
+#ifndef BROTLI_RESEARCH_DEORUMMOLAE_H_
+#define BROTLI_RESEARCH_DEORUMMOLAE_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+/* log2(maximal number of files). Value 6 provides some speedups. */
+#define DM_LOG_MAX_FILES 6
+
+/* Non tunable definitions. */
+#define DM_MAX_FILES (1 << DM_LOG_MAX_FILES)
+
+/**
+ * Generate a dictionary for given samples.
+ *
+ * @param dictionary_size_limit maximal dictionary size
+ * @param sample_sizes vector with sample sizes
+ * @param sample_data concatenated samples
+ * @return generated dictionary
+ */
+std::string DM_generate(size_t dictionary_size_limit,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data);
+
+#endif // BROTLI_RESEARCH_DEORUMMOLAE_H_
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/dictionary_generator.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/dictionary_generator.cc
new file mode 100755
index 000000000..dcdf2fa12
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/dictionary_generator.cc
@@ -0,0 +1,326 @@
+#include <climits>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <vector>
+
+#include "./deorummolae.h"
+#include "./durchschlag.h"
+#include "./sieve.h"
+
+/* This isn't a definitive list of "--foo" arguments, only those that take an
+ * additional "=#" integer parameter, like "--foo=20" or "--foo=32K".
+ */
+#define LONG_ARG_BLOCK_LEN "--block_len="
+#define LONG_ARG_SLICE_LEN "--slice_len="
+#define LONG_ARG_TARGET_DICT_LEN "--target_dict_len="
+#define LONG_ARG_MIN_SLICE_POP "--min_slice_pop="
+#define LONG_ARG_CHUNK_LEN "--chunk_len="
+#define LONG_ARG_OVERLAP_LEN "--overlap_len="
+
+#define METHOD_DM 0
+#define METHOD_SIEVE 1
+#define METHOD_DURCHSCHLAG 2
+#define METHOD_DISTILL 3
+#define METHOD_PURIFY 4
+
+static size_t readInt(const char* str) {
+ size_t result = 0;
+ if (str[0] == 0 || str[0] == '0') {
+ return 0;
+ }
+ for (size_t i = 0; i < 13; ++i) {
+ if (str[i] == 0) {
+ return result;
+ }
+ if (str[i] == 'k' || str[i] == 'K') {
+ if ((str[i + 1] == 0) && ((result << 10) > result)) {
+ return result << 10;
+ }
+ return 0;
+ }
+ if (str[i] == 'm' || str[i] == 'M') {
+ if ((str[i + 1] == 0) && ((result << 20) > result)) {
+ return result << 20;
+ }
+ return 0;
+ }
+ if (str[i] < '0' || str[i] > '9') {
+ return 0;
+ }
+ size_t next = (10 * result) + (str[i] - '0');
+ if (next <= result) {
+ return 0;
+ }
+ result = next;
+ }
+ return 0;
+}
+
+static std::string readFile(const std::string& path) {
+ std::ifstream file(path);
+ std::string content(
+ (std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
+ return content;
+}
+
+static void writeFile(const char* file, const std::string& content) {
+ std::ofstream outfile(file, std::ofstream::binary);
+ outfile.write(content.c_str(), static_cast<std::streamsize>(content.size()));
+ outfile.close();
+}
+
+static void writeSamples(char const* argv[], const std::vector<int>& pathArgs,
+ const std::vector<size_t>& sizes, const uint8_t* data) {
+ size_t offset = 0;
+ for (size_t i = 0; i < pathArgs.size(); ++i) {
+ int j = pathArgs[i];
+ const char* file = argv[j];
+ size_t sampleSize = sizes[i];
+ std::ofstream outfile(file, std::ofstream::binary);
+ outfile.write(reinterpret_cast<const char*>(data + offset),
+ static_cast<std::streamsize>(sampleSize));
+ outfile.close();
+ offset += sampleSize;
+ }
+}
+
+/* Returns "base file name" or its tail, if it contains '/' or '\'. */
+static const char* fileName(const char* path) {
+ const char* separator_position = strrchr(path, '/');
+ if (separator_position) path = separator_position + 1;
+ separator_position = strrchr(path, '\\');
+ if (separator_position) path = separator_position + 1;
+ return path;
+}
+
+static void printHelp(const char* name) {
+ fprintf(stderr, "Usage: %s [OPTION]... DICTIONARY [SAMPLE]...\n", name);
+ fprintf(stderr,
+ "Options:\n"
+ " --dm use 'deorummolae' engine\n"
+ " --distill rewrite samples; unique text parts are removed\n"
+ " --dsh use 'durchschlag' engine (default)\n"
+ " --purify rewrite samples; unique text parts are zeroed out\n"
+ " --sieve use 'sieve' engine\n"
+ " -b#, --block_len=#\n"
+ " set block length for 'durchschlag'; default: 1024\n"
+ " -s#, --slice_len=#\n"
+ " set slice length for 'distill', 'durchschlag', 'purify'\n"
+ " and 'sieve'; default: 16\n"
+ " -t#, --target_dict_len=#\n"
+ " set target dictionary length (limit); default: 16K\n"
+ " -u#, --min_slice_pop=#\n"
+ " set minimum slice population (for rewrites); default: 2\n"
+ " -c#, --chunk_len=#\n"
+ " if positive, samples are cut into chunks of this length;\n"
+ " default: 0; cannot mix with 'rewrite samples'\n"
+ " -o#, --overlap_len=#\n"
+ " set chunk overlap length; default 0\n"
+ "# is a decimal number with optional k/K/m/M suffix.\n"
+ "WARNING: 'distill' and 'purify' will overwrite original samples!\n"
+ " Completely unique samples might become empty files.\n\n");
+}
+
+int main(int argc, char const* argv[]) {
+ int dictionaryArg = -1;
+ int method = METHOD_DURCHSCHLAG;
+ size_t sliceLen = 16;
+ size_t targetSize = 16 << 10;
+ size_t blockSize = 1024;
+ size_t minimumPopulation = 2;
+ size_t chunkLen = 0;
+ size_t overlapLen = 0;
+
+ std::vector<uint8_t> data;
+ std::vector<size_t> sizes;
+ std::vector<int> pathArgs;
+ size_t total = 0;
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i] == nullptr) {
+ continue;
+ }
+
+ if (argv[i][0] == '-') {
+ char arg1 = argv[i][1];
+ const char* arg2 = arg1 ? &argv[i][2] : nullptr;
+ if (arg1 == '-') {
+ if (dictionaryArg != -1) {
+ fprintf(stderr,
+ "Method should be specified before dictionary / sample '%s'\n",
+ argv[i]);
+ exit(1);
+ }
+
+ /* Look for "--long_arg" via exact match. */
+ if (std::strcmp(argv[i], "--sieve") == 0) {
+ method = METHOD_SIEVE;
+ continue;
+ }
+ if (std::strcmp(argv[i], "--dm") == 0) {
+ method = METHOD_DM;
+ continue;
+ }
+ if (std::strcmp(argv[i], "--dsh") == 0) {
+ method = METHOD_DURCHSCHLAG;
+ continue;
+ }
+ if (std::strcmp(argv[i], "--distill") == 0) {
+ method = METHOD_DISTILL;
+ continue;
+ }
+ if (std::strcmp(argv[i], "--purify") == 0) {
+ method = METHOD_PURIFY;
+ continue;
+ }
+
+ /* Look for "--long_arg=#" via prefix match. */
+ if (std::strncmp(argv[i], LONG_ARG_BLOCK_LEN,
+ std::strlen(LONG_ARG_BLOCK_LEN)) == 0) {
+ arg1 = 'b';
+ arg2 = &argv[i][std::strlen(LONG_ARG_BLOCK_LEN)];
+ } else if (std::strncmp(argv[i], LONG_ARG_SLICE_LEN,
+ std::strlen(LONG_ARG_SLICE_LEN)) == 0) {
+ arg1 = 's';
+ arg2 = &argv[i][std::strlen(LONG_ARG_SLICE_LEN)];
+ } else if (std::strncmp(argv[i], LONG_ARG_TARGET_DICT_LEN,
+ std::strlen(LONG_ARG_TARGET_DICT_LEN)) == 0) {
+ arg1 = 't';
+ arg2 = &argv[i][std::strlen(LONG_ARG_TARGET_DICT_LEN)];
+ } else if (std::strncmp(argv[i], LONG_ARG_MIN_SLICE_POP,
+ std::strlen(LONG_ARG_MIN_SLICE_POP)) == 0) {
+ arg1 = 'u';
+ arg2 = &argv[i][std::strlen(LONG_ARG_MIN_SLICE_POP)];
+ } else if (std::strncmp(argv[i], LONG_ARG_CHUNK_LEN,
+ std::strlen(LONG_ARG_CHUNK_LEN)) == 0) {
+ arg1 = 'c';
+ arg2 = &argv[i][std::strlen(LONG_ARG_CHUNK_LEN)];
+ } else if (std::strncmp(argv[i], LONG_ARG_OVERLAP_LEN,
+ std::strlen(LONG_ARG_OVERLAP_LEN)) == 0) {
+ arg1 = 'o';
+ arg2 = &argv[i][std::strlen(LONG_ARG_OVERLAP_LEN)];
+ } else {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ }
+
+ /* Look for "-f" short args or "--foo=#" long args. */
+ if (arg1 == 'b') {
+ blockSize = readInt(arg2);
+ if (blockSize < 16 || blockSize > 65536) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else if (arg1 == 's') {
+ sliceLen = readInt(arg2);
+ if (sliceLen < 4 || sliceLen > 256) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else if (arg1 == 't') {
+ targetSize = readInt(arg2);
+ if (targetSize < 256 || targetSize > (1 << 25)) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else if (arg1 == 'u') {
+ minimumPopulation = readInt(arg2);
+ if (minimumPopulation < 256 || minimumPopulation > 65536) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else if (arg1 == 'c') {
+ chunkLen = readInt(arg2);
+ if (chunkLen < 0 || chunkLen > INT_MAX) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else if (arg1 == 'o') {
+ overlapLen = readInt(arg2);
+ if (overlapLen < 0 || overlapLen > INT_MAX) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
+ exit(1);
+ }
+ continue;
+ }
+
+ if (dictionaryArg == -1) {
+ if (method != METHOD_DISTILL && method != METHOD_PURIFY) {
+ dictionaryArg = i;
+ continue;
+ }
+ }
+
+ std::string content = readFile(argv[i]);
+ if (chunkLen == 0) {
+ pathArgs.push_back(i);
+ data.insert(data.end(), content.begin(), content.end());
+ total += content.size();
+ sizes.push_back(content.size());
+ continue;
+ } else if (chunkLen <= overlapLen) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Invalid chunkLen - overlapLen combination\n");
+ exit(1);
+ }
+ for (size_t chunkStart = 0;
+ chunkStart < content.size();
+ chunkStart += chunkLen - overlapLen) {
+ std::string chunk = content.substr(chunkStart, chunkLen);
+ data.insert(data.end(), chunk.begin(), chunk.end());
+ total += chunk.size();
+ sizes.push_back(chunk.size());
+ }
+ }
+
+ bool wantDictionary = (dictionaryArg == -1);
+ if (method == METHOD_DISTILL || method == METHOD_PURIFY) {
+ wantDictionary = false;
+ if (chunkLen != 0) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Cannot mix 'rewrite samples' with positive chunk_len\n");
+ exit(1);
+ }
+ }
+ if (wantDictionary || total == 0) {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Not enough arguments\n");
+ exit(1);
+ }
+
+ if (method == METHOD_SIEVE) {
+ writeFile(argv[dictionaryArg], sieve_generate(
+ targetSize, sliceLen, sizes, data.data()));
+ } else if (method == METHOD_DM) {
+ writeFile(argv[dictionaryArg], DM_generate(
+ targetSize, sizes, data.data()));
+ } else if (method == METHOD_DURCHSCHLAG) {
+ writeFile(argv[dictionaryArg], durchschlag_generate(
+ targetSize, sliceLen, blockSize, sizes, data.data()));
+ } else if (method == METHOD_DISTILL) {
+ durchschlag_distill(sliceLen, minimumPopulation, &sizes, data.data());
+ writeSamples(argv, pathArgs, sizes, data.data());
+ } else if (method == METHOD_PURIFY) {
+ durchschlag_purify(sliceLen, minimumPopulation, sizes, data.data());
+ writeSamples(argv, pathArgs, sizes, data.data());
+ } else {
+ printHelp(fileName(argv[0]));
+ fprintf(stderr, "Unknown generator\n");
+ exit(1);
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_diff.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_diff.cc
new file mode 100644
index 000000000..1a5286960
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_diff.cc
@@ -0,0 +1,117 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ Author: zip753@gmail.com (Ivan Nikulin)
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Tool for drawing diff PPM images between two input PGM images. Normally used
+ with backward reference histogram drawing tool. */
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib> /* exit, EXIT_FAILURE */
+#include <vector>
+
+#if !defined(CHECK)
+#define CHECK(X) if (!(X)) exit(EXIT_FAILURE);
+#endif
+
+typedef uint8_t* ScanLine;
+typedef ScanLine* Image;
+
+void ReadPGM(FILE* f, Image* image, size_t* height, size_t* width) {
+ int colors;
+ CHECK(fscanf(f, "P5\n%lu %lu\n%d\n", width, height, &colors) == 3);
+ assert(colors == 255);
+ ScanLine* lines = new ScanLine[*height];
+ *image = lines;
+ for (int i = *height - 1; i >= 0; --i) {
+ ScanLine line = new uint8_t[*width];
+ lines[i] = line;
+ CHECK(fread(line, 1, *width, f) == *width);
+ }
+}
+
+void CalculateDiff(int** diff, Image image1, Image image2,
+ size_t height, size_t width) {
+ for (size_t i = 0; i < height; ++i) {
+ for (size_t j = 0; j < width; ++j) {
+ diff[i][j] = static_cast<int>(image1[i][j]) - image2[i][j];
+ }
+ }
+}
+
+void DrawDiff(int** diff, Image image1, Image image2,
+ size_t height, size_t width, FILE* f) {
+ int max = -1234;
+ int min = +1234;
+ for (size_t i = 0; i < height; ++i) {
+ for (size_t j = 0; j < width; ++j) {
+ if (max < diff[i][j]) max = diff[i][j];
+ if (min > diff[i][j]) min = diff[i][j];
+ int img_min = std::min(255 - image1[i][j], 255 - image2[i][j]);
+ if (max < img_min) max = img_min;
+ }
+ }
+
+ int abs_max = -min;
+ if (abs_max < max) abs_max = max;
+
+ fprintf(f, "P6\n%lu %lu\n%d\n", width, height, abs_max);
+
+ uint8_t* row = new uint8_t[3 * width];
+ for (int i = height - 1; i >= 0; --i) {
+ for (int j = 0; j < width; ++j) {
+ int min_val = std::min(255 - image1[i][j], 255 - image2[i][j]);
+ int max_val = std::max(min_val, abs(diff[i][j]));
+ if (diff[i][j] > 0) { /* red */
+ row[3 * j + 0] = abs_max - max_val + diff[i][j];
+ row[3 * j + 1] = abs_max - max_val;
+ row[3 * j + 2] = abs_max - max_val + min_val;
+ } else { /* green */
+ row[3 * j + 0] = abs_max - max_val;
+ row[3 * j + 1] = abs_max - max_val - diff[i][j];
+ row[3 * j + 2] = abs_max - max_val + min_val;
+ }
+ }
+ fwrite(row, 1, 3 * width, f);
+ }
+ delete[] row;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 4) {
+ printf("usage: %s pgm1 pgm2 diff_ppm_path\n", argv[0]);
+ return 1;
+ }
+
+ Image image1, image2;
+ size_t h1, w1, h2, w2;
+
+ FILE* fimage1 = fopen(argv[1], "rb");
+ ReadPGM(fimage1, &image1, &h1, &w1);
+ fclose(fimage1);
+
+ FILE* fimage2 = fopen(argv[2], "rb");
+ ReadPGM(fimage2, &image2, &h2, &w2);
+ fclose(fimage2);
+
+ if (!(h1 == h2 && w1 == w2)) {
+ printf("Images must have the same size.\n");
+ return 1;
+ }
+
+ int** diff = new int*[h1];
+ for (size_t i = 0; i < h1; ++i) diff[i] = new int[w1];
+ CalculateDiff(diff, image1, image2, h1, w1);
+
+ FILE* fdiff = fopen(argv[3], "wb");
+ DrawDiff(diff, image1, image2, h1, w1, fdiff);
+ fclose(fdiff);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_histogram.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_histogram.cc
new file mode 100644
index 000000000..b0192a217
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/draw_histogram.cc
@@ -0,0 +1,197 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ Author: zip753@gmail.com (Ivan Nikulin)
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Backward reference visualization tool. Accepts file with backward references
+ as an input and produces PGM image with histogram of those references. */
+
+#include <algorithm> /* min */
+#include <cassert>
+#include <cstring> /* memset */
+#include <cmath> /* log, round */
+#include <cstdio> /* fscanf, fprintf */
+#include <cstdint>
+
+#include <gflags/gflags.h>
+using gflags::ParseCommandLineFlags;
+
+#include "./read_dist.h"
+
+DEFINE_int32(height, 1000, "Height of the resulting histogam.");
+DEFINE_int32(width, 8000, "Width of the resulting histogam.");
+DEFINE_int32(size, 1e8, "Size of the compressed file.");
+DEFINE_int32(brotli_window, -1, "Size of brotli window in bits.");
+DEFINE_uint64(min_distance, 0, "Minimum distance.");
+DEFINE_uint64(max_distance, 1 << 30, "Maximum distance.");
+DEFINE_bool(with_copies, false, "True if input contains copy length.");
+DEFINE_bool(simple, false, "True if using only black and white pixels.");
+DEFINE_bool(linear, false, "True if using linear distance mapping.");
+DEFINE_uint64(skip, 0, "Number of bytes to skip.");
+
+inline double DistanceTransform(double x) {
+ static bool linear = FLAGS_linear;
+ if (linear) {
+ return x;
+ } else {
+ /* Using log^2 scale because log scale produces big white gap at the bottom
+ of image. */
+ return log(x) * log(x);
+ }
+}
+
+/* Mapping pixel density on arc function to increase contrast. */
+inline double DensityTransform(double x) {
+ double z = 255 - x;
+ return sqrt(255 * 255 - z * z);
+}
+
+inline int GetMaxDistance() {
+ return FLAGS_max_distance;
+}
+
+void AdjustPosition(int* pos) {
+ static uint32_t offset = 0;
+ static int last = 0;
+ static uint32_t window_size = (1 << FLAGS_brotli_window);
+ assert(*pos >= 0 && *pos < window_size);
+ if (*pos < last) {
+ offset += window_size;
+ }
+ last = *pos;
+ *pos += offset;
+}
+
+void BuildHistogram(FILE* fin, int** histo) {
+ int height = FLAGS_height;
+ int width = FLAGS_width;
+ int skip = FLAGS_skip;
+ size_t min_distance = FLAGS_min_distance;
+
+ printf("height = %d, width = %d\n", height, width);
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ histo[i][j] = 0;
+ }
+ }
+
+ int max_pos = FLAGS_size - skip;
+ double min_dist = min_distance > 0 ? DistanceTransform(min_distance) : 0;
+ double max_dist = DistanceTransform(GetMaxDistance()) - min_dist;
+ int copy, pos, distance, x, y;
+ double dist;
+ while (ReadBackwardReference(fin, &copy, &pos, &distance)) {
+ if (pos == -1) continue; // In case when only insert is present.
+ if (distance < min_distance || distance >= GetMaxDistance()) continue;
+ if (FLAGS_brotli_window != -1) {
+ AdjustPosition(&pos);
+ }
+ if (pos >= skip && distance <= pos) {
+ pos -= skip;
+ if (pos >= max_pos) break;
+ dist = DistanceTransform(static_cast<double>(distance)) - min_dist;
+
+ x = std::min(static_cast<int>(round(dist / max_dist * height)),
+ height - 1);
+ y = 1ul * pos * width / max_pos;
+ if (!(y >= 0 && y < width)) {
+ printf("pos = %d, max_pos = %d, y = %d\n", pos, max_pos, y);
+ assert(y >= 0 && y < width);
+ }
+
+ if (FLAGS_with_copies) {
+ int right = 1ul * (pos + copy - 1) * width / max_pos;
+ if (right < 0) {
+ printf("pos = %d, distance = %d, copy = %d, y = %d, right = %d\n",
+ pos, distance, copy, y, right);
+ assert(right >= 0);
+ }
+ if (y == right) {
+ histo[x][y] += copy;
+ } else {
+ int pos2 = static_cast<int>(ceil(1.0 * (y + 1) * max_pos / width));
+ histo[x][y] += pos2 - pos;
+ for (int i = y + 1; i < right && i < width; ++i) {
+ histo[x][i] += max_pos / width; // Sometimes 1 more, but who cares.
+ }
+ // Make sure the match doesn't go beyond the image.
+ if (right < width) {
+ pos2 = static_cast<int>(ceil(1.0 * right * max_pos / width));
+ histo[x][right] += pos + copy - 1 - pos2 + 1;
+ }
+ }
+ } else {
+ histo[x][y]++;
+ }
+ }
+ }
+}
+
+void ConvertToPixels(int** histo, uint8_t** pixel) {
+ int height = FLAGS_height;
+ int width = FLAGS_width;
+
+ int maxs = 0;
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ if (maxs < histo[i][j]) maxs = histo[i][j];
+ }
+ }
+
+ bool simple = FLAGS_simple;
+ double max_histo = static_cast<double>(maxs);
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ if (simple) {
+ pixel[i][j] = histo[i][j] > 0 ? 0 : 255;
+ } else {
+ pixel[i][j] = static_cast<uint8_t>(
+ 255 - DensityTransform(histo[i][j] / max_histo * 255));
+ }
+ }
+ }
+}
+
+void DrawPixels(uint8_t** pixel, FILE* fout) {
+ int height = FLAGS_height;
+ int width = FLAGS_width;
+
+ fprintf(fout, "P5\n%d %d\n255\n", width, height);
+ for (int i = height - 1; i >= 0; i--) {
+ fwrite(pixel[i], 1, width, fout);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ ParseCommandLineFlags(&argc, &argv, true);
+ if (argc != 3) {
+ printf("usage: draw_histogram.cc data output_file\n");
+ return 1;
+ }
+
+ int height = FLAGS_height;
+ int width = FLAGS_width;
+
+ FILE* fin = fopen(argv[1], "r");
+ FILE* fout = fopen(argv[2], "wb");
+
+ uint8_t** pixel = new uint8_t*[height];
+ int** histo = new int*[height];
+ for (int i = 0; i < height; i++) {
+ pixel[i] = new uint8_t[width];
+ histo[i] = new int[width];
+ }
+
+ BuildHistogram(fin, histo);
+ fclose(fin);
+
+ ConvertToPixels(histo, pixel);
+
+ DrawPixels(pixel, fout);
+ fclose(fout);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.cc
new file mode 100755
index 000000000..2fbf41b58
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.cc
@@ -0,0 +1,726 @@
+#include "./durchschlag.h"
+
+#include <algorithm>
+#include <exception> /* terminate */
+
+#include "divsufsort.h"
+
+/* Pointer to position in text. */
+typedef DurchschlagTextIdx TextIdx;
+
+/* (Sum of) value(s) of slice(s). */
+typedef uint32_t Score;
+
+typedef struct HashSlot {
+ TextIdx next;
+ TextIdx offset;
+} HashSlot;
+
+typedef struct MetaSlot {
+ TextIdx mark;
+ Score score;
+} MetaSlot;
+
+typedef struct Range {
+ TextIdx start;
+ TextIdx end;
+} Range;
+
+typedef struct Candidate {
+ Score score;
+ TextIdx position;
+} Candidate;
+
+struct greaterScore {
+ bool operator()(const Candidate& a, const Candidate& b) const {
+ return (a.score > b.score) ||
+ ((a.score == b.score) && (a.position < b.position));
+ }
+};
+
+struct lessScore {
+ bool operator()(const Candidate& a, const Candidate& b) const {
+ return (a.score < b.score) ||
+ ((a.score == b.score) && (a.position > b.position));
+ }
+};
+
+#define CANDIDATE_BUNDLE_SIZE (1 << 18)
+
+static void fatal(const char* error) {
+ fprintf(stderr, "%s\n", error);
+ std::terminate();
+}
+
+static TextIdx calculateDictionarySize(const std::vector<Range>& ranges) {
+ TextIdx result = 0;
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ const Range& r = ranges[i];
+ result += r.end - r.start;
+ }
+ return result;
+}
+
+static std::string createDictionary(
+ const uint8_t* data, const std::vector<Range>& ranges, size_t limit) {
+ std::string output;
+ output.reserve(calculateDictionarySize(ranges));
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ const Range& r = ranges[i];
+ output.insert(output.end(), &data[r.start], &data[r.end]);
+ }
+ if (output.size() > limit) {
+ output.resize(limit);
+ }
+ return output;
+}
+
+/* precondition: span > 0
+ precondition: end + span == len(shortcut) */
+static Score buildCandidatesList(std::vector<Candidate>* candidates,
+ std::vector<MetaSlot>* map, TextIdx span, const TextIdx* shortcut,
+ TextIdx end) {
+ candidates->resize(0);
+
+ size_t n = map->size();
+ MetaSlot* slots = map->data();
+ for (size_t j = 0; j < n; ++j) {
+ slots[j].mark = 0;
+ }
+
+ Score score = 0;
+ /* Consider the whole span, except one last item. The following loop will
+ add the last item to the end of the "chain", evaluate it, and cut one
+ "link" form the beginning. */
+ for (size_t j = 0; j < span - 1; ++j) {
+ MetaSlot& item = slots[shortcut[j]];
+ if (item.mark == 0) {
+ score += item.score;
+ }
+ item.mark++;
+ }
+
+ TextIdx i = 0;
+ TextIdx limit = std::min<TextIdx>(end, CANDIDATE_BUNDLE_SIZE);
+ Score maxScore = 0;
+ for (; i < limit; ++i) {
+ TextIdx slice = shortcut[i + span - 1];
+ MetaSlot& pick = slots[slice];
+ if (pick.mark == 0) {
+ score += pick.score;
+ }
+ pick.mark++;
+
+ if (score > maxScore) {
+ maxScore = score;
+ }
+ candidates->push_back({score, i});
+
+ MetaSlot& drop = slots[shortcut[i]];
+ drop.mark--;
+ if (drop.mark == 0) {
+ score -= drop.score;
+ }
+ }
+
+ std::make_heap(candidates->begin(), candidates->end(), greaterScore());
+ Score minScore = candidates->at(0).score;
+ for (; i < end; ++i) {
+ TextIdx slice = shortcut[i + span - 1];
+ MetaSlot& pick = slots[slice];
+ if (pick.mark == 0) {
+ score += pick.score;
+ }
+ pick.mark++;
+
+ if (score > maxScore) {
+ maxScore = score;
+ }
+ if (score >= minScore) {
+ candidates->push_back({score, i});
+ std::push_heap(candidates->begin(), candidates->end(), greaterScore());
+ if (candidates->size() > CANDIDATE_BUNDLE_SIZE && maxScore != minScore) {
+ while (candidates->at(0).score == minScore) {
+ std::pop_heap(candidates->begin(), candidates->end(), greaterScore());
+ candidates->pop_back();
+ }
+ minScore = candidates->at(0).score;
+ }
+ }
+
+ MetaSlot& drop = slots[shortcut[i]];
+ drop.mark--;
+ if (drop.mark == 0) {
+ score -= drop.score;
+ }
+ }
+
+ for (size_t j = 0; j < n; ++j) {
+ slots[j].mark = 0;
+ }
+
+ std::make_heap(candidates->begin(), candidates->end(), lessScore());
+ return minScore;
+}
+
+/* precondition: span > 0
+ precondition: end + span == len(shortcut) */
+static Score rebuildCandidatesList(std::vector<TextIdx>* candidates,
+ std::vector<MetaSlot>* map, TextIdx span, const TextIdx* shortcut,
+ TextIdx end, TextIdx* next) {
+ size_t n = candidates->size();
+ TextIdx* data = candidates->data();
+ for (size_t i = 0; i < n; ++i) {
+ data[i] = 0;
+ }
+
+ n = map->size();
+ MetaSlot* slots = map->data();
+ for (size_t i = 0; i < n; ++i) {
+ slots[i].mark = 0;
+ }
+
+ Score score = 0;
+ /* Consider the whole span, except one last item. The following loop will
+ add the last item to the end of the "chain", evaluate it, and cut one
+ "link" form the beginning. */
+ for (TextIdx i = 0; i < span - 1; ++i) {
+ MetaSlot& item = slots[shortcut[i]];
+ if (item.mark == 0) {
+ score += item.score;
+ }
+ item.mark++;
+ }
+
+ Score maxScore = 0;
+ for (TextIdx i = 0; i < end; ++i) {
+ MetaSlot& pick = slots[shortcut[i + span - 1]];
+ if (pick.mark == 0) {
+ score += pick.score;
+ }
+ pick.mark++;
+
+ if (candidates->size() <= score) {
+ candidates->resize(score + 1);
+ }
+ if (score > maxScore) {
+ maxScore = score;
+ }
+ next[i] = candidates->at(score);
+ candidates->at(score) = i;
+
+ MetaSlot& drop = slots[shortcut[i]];
+ drop.mark--;
+ if (drop.mark == 0) {
+ score -= drop.score;
+ }
+ }
+
+ for (size_t i = 0; i < n; ++i) {
+ slots[i].mark = 0;
+ }
+
+ candidates->resize(maxScore + 1);
+ return maxScore;
+}
+
+static void addRange(std::vector<Range>* ranges, TextIdx start, TextIdx end) {
+ for (auto it = ranges->begin(); it != ranges->end();) {
+ if (end < it->start) {
+ ranges->insert(it, {start, end});
+ return;
+ }
+ if (it->end < start) {
+ it++;
+ continue;
+ }
+ // Combine with existing.
+ start = std::min(start, it->start);
+ end = std::max(end, it->end);
+ // Remove consumed vector and continue.
+ it = ranges->erase(it);
+ }
+ ranges->push_back({start, end});
+}
+
+std::string durchschlag_generate(
+ size_t dictionary_size_limit, size_t slice_len, size_t block_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data) {
+ DurchschlagContext ctx = durchschlag_prepare(
+ slice_len, sample_sizes, sample_data);
+ return durchschlag_generate(DURCHSCHLAG_COLLABORATIVE,
+ dictionary_size_limit, block_len, ctx, sample_data);
+}
+
+DurchschlagContext durchschlag_prepare(size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data) {
+ /* Parameters aliasing */
+ TextIdx sliceLen = static_cast<TextIdx>(slice_len);
+ if (sliceLen != slice_len) fatal("slice_len is too large");
+ if (sliceLen < 1) fatal("slice_len is too small");
+ const uint8_t* data = sample_data;
+
+ TextIdx total = 0;
+ std::vector<TextIdx> offsets;
+ offsets.reserve(sample_sizes.size());
+ for (size_t i = 0; i < sample_sizes.size(); ++i) {
+ TextIdx delta = static_cast<TextIdx>(sample_sizes[i]);
+ if (delta != sample_sizes[i]) fatal("sample is too large");
+ if (delta == 0) fatal("0-length samples are prohibited");
+ TextIdx next_total = total + delta;
+ if (next_total <= total) fatal("corpus is too large");
+ total = next_total;
+ offsets.push_back(total);
+ }
+
+ if (total < sliceLen) fatal("slice_len is larger than corpus size");
+ TextIdx end = total - static_cast<TextIdx>(sliceLen) + 1;
+ TextIdx hashLen = 11;
+ while (hashLen < 29 && ((1u << hashLen) < end)) {
+ hashLen += 3;
+ }
+ hashLen -= 3;
+ TextIdx hashMask = (1u << hashLen) - 1u;
+ std::vector<TextIdx> hashHead(1 << hashLen);
+ TextIdx hash = 0;
+ TextIdx lShift = 3;
+ TextIdx rShift = hashLen - lShift;
+ for (TextIdx i = 0; i < sliceLen - 1; ++i) {
+ TextIdx v = data[i];
+ hash = (((hash << lShift) | (hash >> rShift)) & hashMask) ^ v;
+ }
+ TextIdx lShiftX = (lShift * (sliceLen - 1)) % hashLen;
+ TextIdx rShiftX = hashLen - lShiftX;
+
+ std::vector<HashSlot> map;
+ map.push_back({0, 0});
+ TextIdx hashSlot = 1;
+ std::vector<TextIdx> sliceMap;
+ sliceMap.reserve(end);
+ for (TextIdx i = 0; i < end; ++i) {
+ TextIdx v = data[i + sliceLen - 1];
+ TextIdx bucket = (((hash << lShift) | (hash >> rShift)) & hashMask) ^ v;
+ v = data[i];
+ hash = bucket ^ (((v << lShiftX) | (v >> rShiftX)) & hashMask);
+ TextIdx slot = hashHead[bucket];
+ while (slot != 0) {
+ HashSlot& item = map[slot];
+ TextIdx start = item.offset;
+ bool miss = false;
+ for (TextIdx j = 0; j < sliceLen; ++j) {
+ if (data[i + j] != data[start + j]) {
+ miss = true;
+ break;
+ }
+ }
+ if (!miss) {
+ sliceMap.push_back(slot);
+ break;
+ }
+ slot = item.next;
+ }
+ if (slot == 0) {
+ map.push_back({hashHead[bucket], i});
+ hashHead[bucket] = hashSlot;
+ sliceMap.push_back(hashSlot);
+ hashSlot++;
+ }
+ }
+
+ return {total, sliceLen, static_cast<TextIdx>(map.size()),
+ std::move(offsets), std::move(sliceMap)};
+}
+
+DurchschlagContext durchschlag_prepare(size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const DurchschlagIndex& index) {
+ /* Parameters aliasing */
+ TextIdx sliceLen = static_cast<TextIdx>(slice_len);
+ if (sliceLen != slice_len) fatal("slice_len is too large");
+ if (sliceLen < 1) fatal("slice_len is too small");
+ const TextIdx* lcp = index.lcp.data();
+ const TextIdx* sa = index.sa.data();
+
+ TextIdx total = 0;
+ std::vector<TextIdx> offsets;
+ offsets.reserve(sample_sizes.size());
+ for (size_t i = 0; i < sample_sizes.size(); ++i) {
+ TextIdx delta = static_cast<TextIdx>(sample_sizes[i]);
+ if (delta != sample_sizes[i]) fatal("sample is too large");
+ if (delta == 0) fatal("0-length samples are prohibited");
+ TextIdx next_total = total + delta;
+ if (next_total <= total) fatal("corpus is too large");
+ total = next_total;
+ offsets.push_back(total);
+ }
+
+ if (total < sliceLen) fatal("slice_len is larger than corpus size");
+ TextIdx counter = 1;
+ TextIdx end = total - sliceLen + 1;
+ std::vector<TextIdx> sliceMap(total);
+ TextIdx last = 0;
+ TextIdx current = 1;
+ while (current <= total) {
+ if (lcp[current - 1] < sliceLen) {
+ for (TextIdx i = last; i < current; ++i) {
+ sliceMap[sa[i]] = counter;
+ }
+ counter++;
+ last = current;
+ }
+ current++;
+ }
+ sliceMap.resize(end);
+
+ // Reorder items for the better locality.
+ std::vector<TextIdx> reorder(counter);
+ counter = 1;
+ for (TextIdx i = 0; i < end; ++i) {
+ if (reorder[sliceMap[i]] == 0) {
+ reorder[sliceMap[i]] = counter++;
+ }
+ }
+ for (TextIdx i = 0; i < end; ++i) {
+ sliceMap[i] = reorder[sliceMap[i]];
+ }
+
+ return {total, sliceLen, counter, std::move(offsets), std::move(sliceMap)};
+}
+
+DurchschlagIndex durchschlag_index(const std::vector<uint8_t>& data) {
+ TextIdx total = static_cast<TextIdx>(data.size());
+ if (total != data.size()) fatal("corpus is too large");
+ saidx_t saTotal = static_cast<saidx_t>(total);
+ if (saTotal < 0) fatal("corpus is too large");
+ if (static_cast<TextIdx>(saTotal) != total) fatal("corpus is too large");
+ std::vector<TextIdx> sa(total);
+ /* Hopefully, non-negative int32_t values match TextIdx ones. */
+ if (sizeof(TextIdx) != sizeof(int32_t)) fatal("type length mismatch");
+ int32_t* saData = reinterpret_cast<int32_t*>(sa.data());
+ divsufsort(data.data(), saData, saTotal);
+
+ std::vector<TextIdx> isa(total);
+ for (TextIdx i = 0; i < total; ++i) isa[sa[i]] = i;
+
+ // TODO: borrowed -> unknown efficiency.
+ std::vector<TextIdx> lcp(total);
+ TextIdx k = 0;
+ lcp[total - 1] = 0;
+ for (TextIdx i = 0; i < total; ++i) {
+ TextIdx current = isa[i];
+ if (current == total - 1) {
+ k = 0;
+ continue;
+ }
+ TextIdx j = sa[current + 1]; // Suffix which follow i-th suffix.
+ while ((i + k < total) && (j + k < total) && (data[i + k] == data[j + k])) {
+ ++k;
+ }
+ lcp[current] = k;
+ if (k > 0) --k;
+ }
+
+ return {std::move(lcp), std::move(sa)};
+}
+
+static void ScoreSlices(const std::vector<TextIdx>& offsets,
+ std::vector<MetaSlot>& map, const TextIdx* shortcut, TextIdx end) {
+ TextIdx piece = 0;
+ /* Fresh map contains all zeroes -> initial mark should be different. */
+ TextIdx mark = 1;
+ for (TextIdx i = 0; i < end; ++i) {
+ if (offsets[piece] == i) {
+ piece++;
+ mark++;
+ }
+ MetaSlot& item = map[shortcut[i]];
+ if (item.mark != mark) {
+ item.mark = mark;
+ item.score++;
+ }
+ }
+}
+
+static std::string durchschlagGenerateExclusive(
+ size_t dictionary_size_limit, size_t block_len,
+ const DurchschlagContext& context, const uint8_t* sample_data) {
+ /* Parameters aliasing */
+ TextIdx targetSize = static_cast<TextIdx>(dictionary_size_limit);
+ if (targetSize != dictionary_size_limit) {
+ fprintf(stderr, "dictionary_size_limit is too large\n");
+ return "";
+ }
+ TextIdx sliceLen = context.sliceLen;
+ TextIdx total = context.dataSize;
+ TextIdx blockLen = static_cast<TextIdx>(block_len);
+ if (blockLen != block_len) {
+ fprintf(stderr, "block_len is too large\n");
+ return "";
+ }
+ const uint8_t* data = sample_data;
+ const std::vector<TextIdx>& offsets = context.offsets;
+ std::vector<MetaSlot> map(context.numUniqueSlices);
+ const TextIdx* shortcut = context.sliceMap.data();
+
+ /* Initialization */
+ if (blockLen < sliceLen) {
+ fprintf(stderr, "sliceLen is larger than block_len\n");
+ return "";
+ }
+ if (targetSize < blockLen || total < blockLen) {
+ fprintf(stderr, "block_len is too large\n");
+ return "";
+ }
+ TextIdx end = total - sliceLen + 1;
+ ScoreSlices(offsets, map, shortcut, end);
+ TextIdx span = blockLen - sliceLen + 1;
+ end = static_cast<TextIdx>(context.sliceMap.size()) - span;
+ std::vector<TextIdx> candidates;
+ std::vector<TextIdx> next(end);
+ Score maxScore = rebuildCandidatesList(
+ &candidates, &map, span, shortcut, end, next.data());
+
+ /* Block selection */
+ const size_t triesLimit = (600 * 1000000) / span;
+ const size_t candidatesLimit = (150 * 1000000) / span;
+ std::vector<Range> ranges;
+ TextIdx mark = 0;
+ size_t numTries = 0;
+ while (true) {
+ TextIdx dictSize = calculateDictionarySize(ranges);
+ size_t numCandidates = 0;
+ if (dictSize > targetSize - blockLen) {
+ break;
+ }
+ if (maxScore == 0) {
+ break;
+ }
+ while (true) {
+ TextIdx candidate = 0;
+ while (maxScore > 0) {
+ if (candidates[maxScore] != 0) {
+ candidate = candidates[maxScore];
+ candidates[maxScore] = next[candidate];
+ break;
+ }
+ maxScore--;
+ }
+ if (maxScore == 0) {
+ break;
+ }
+ mark++;
+ numTries++;
+ numCandidates++;
+ Score score = 0;
+ for (size_t j = candidate; j < candidate + span; ++j) {
+ MetaSlot& item = map[shortcut[j]];
+ if (item.mark != mark) {
+ score += item.score;
+ item.mark = mark;
+ }
+ }
+ if (score < maxScore) {
+ if (numTries < triesLimit && numCandidates < candidatesLimit) {
+ next[candidate] = candidates[score];
+ candidates[score] = candidate;
+ } else {
+ maxScore = rebuildCandidatesList(
+ &candidates, &map, span, shortcut, end, next.data());
+ mark = 0;
+ numTries = 0;
+ numCandidates = 0;
+ }
+ continue;
+ } else if (score > maxScore) {
+ fprintf(stderr, "Broken invariant\n");
+ return "";
+ }
+ for (TextIdx j = candidate; j < candidate + span; ++j) {
+ MetaSlot& item = map[shortcut[j]];
+ item.score = 0;
+ }
+ addRange(&ranges, candidate, candidate + blockLen);
+ break;
+ }
+ }
+
+ return createDictionary(data, ranges, targetSize);
+}
+
+static std::string durchschlagGenerateCollaborative(
+ size_t dictionary_size_limit, size_t block_len,
+ const DurchschlagContext& context, const uint8_t* sample_data) {
+ /* Parameters aliasing */
+ TextIdx targetSize = static_cast<TextIdx>(dictionary_size_limit);
+ if (targetSize != dictionary_size_limit) {
+ fprintf(stderr, "dictionary_size_limit is too large\n");
+ return "";
+ }
+ TextIdx sliceLen = context.sliceLen;
+ TextIdx total = context.dataSize;
+ TextIdx blockLen = static_cast<TextIdx>(block_len);
+ if (blockLen != block_len) {
+ fprintf(stderr, "block_len is too large\n");
+ return "";
+ }
+ const uint8_t* data = sample_data;
+ const std::vector<TextIdx>& offsets = context.offsets;
+ std::vector<MetaSlot> map(context.numUniqueSlices);
+ const TextIdx* shortcut = context.sliceMap.data();
+
+ /* Initialization */
+ if (blockLen < sliceLen) {
+ fprintf(stderr, "sliceLen is larger than block_len\n");
+ return "";
+ }
+ if (targetSize < blockLen || total < blockLen) {
+ fprintf(stderr, "block_len is too large\n");
+ return "";
+ }
+ TextIdx end = total - sliceLen + 1;
+ ScoreSlices(offsets, map, shortcut, end);
+ TextIdx span = blockLen - sliceLen + 1;
+ end = static_cast<TextIdx>(context.sliceMap.size()) - span;
+ std::vector<Candidate> candidates;
+ candidates.reserve(CANDIDATE_BUNDLE_SIZE + 1024);
+ Score minScore = buildCandidatesList(&candidates, &map, span, shortcut, end);
+
+ /* Block selection */
+ std::vector<Range> ranges;
+ TextIdx mark = 0;
+ while (true) {
+ TextIdx dictSize = calculateDictionarySize(ranges);
+ if (dictSize > targetSize - blockLen) {
+ break;
+ }
+ if (minScore == 0 && candidates.empty()) {
+ break;
+ }
+ while (true) {
+ if (candidates.empty()) {
+ minScore = buildCandidatesList(&candidates, &map, span, shortcut, end);
+ mark = 0;
+ }
+ TextIdx candidate = candidates[0].position;
+ Score expectedScore = candidates[0].score;
+ if (expectedScore == 0) {
+ candidates.resize(0);
+ break;
+ }
+ std::pop_heap(candidates.begin(), candidates.end(), lessScore());
+ candidates.pop_back();
+ mark++;
+ Score score = 0;
+ for (TextIdx j = candidate; j < candidate + span; ++j) {
+ MetaSlot& item = map[shortcut[j]];
+ if (item.mark != mark) {
+ score += item.score;
+ item.mark = mark;
+ }
+ }
+ if (score < expectedScore) {
+ if (score >= minScore) {
+ candidates.push_back({score, candidate});
+ std::push_heap(candidates.begin(), candidates.end(), lessScore());
+ }
+ continue;
+ } else if (score > expectedScore) {
+ fatal("Broken invariant");
+ }
+ for (TextIdx j = candidate; j < candidate + span; ++j) {
+ MetaSlot& item = map[shortcut[j]];
+ item.score = 0;
+ }
+ addRange(&ranges, candidate, candidate + blockLen);
+ break;
+ }
+ }
+
+ return createDictionary(data, ranges, targetSize);
+}
+
+std::string durchschlag_generate(DurchschalgResourceStrategy strategy,
+ size_t dictionary_size_limit, size_t block_len,
+ const DurchschlagContext& context, const uint8_t* sample_data) {
+ if (strategy == DURCHSCHLAG_COLLABORATIVE) {
+ return durchschlagGenerateCollaborative(
+ dictionary_size_limit, block_len, context, sample_data);
+ } else {
+ return durchschlagGenerateExclusive(
+ dictionary_size_limit, block_len, context, sample_data);
+ }
+}
+
+void durchschlag_distill(size_t slice_len, size_t minimum_population,
+ std::vector<size_t>* sample_sizes, uint8_t* sample_data) {
+ /* Parameters aliasing */
+ uint8_t* data = sample_data;
+
+ /* Build slice map. */
+ DurchschlagContext context = durchschlag_prepare(
+ slice_len, *sample_sizes, data);
+
+ /* Calculate slice population. */
+ const std::vector<TextIdx>& offsets = context.offsets;
+ std::vector<MetaSlot> map(context.numUniqueSlices);
+ const TextIdx* shortcut = context.sliceMap.data();
+ TextIdx sliceLen = context.sliceLen;
+ TextIdx total = context.dataSize;
+ TextIdx end = total - sliceLen + 1;
+ ScoreSlices(offsets, map, shortcut, end);
+
+ /* Condense samples, omitting unique slices. */
+ TextIdx readPos = 0;
+ TextIdx writePos = 0;
+ TextIdx lastNonUniquePos = 0;
+ for (TextIdx i = 0; i < sample_sizes->size(); ++i) {
+ TextIdx sampleStart = writePos;
+ TextIdx oldSampleEnd =
+ readPos + static_cast<TextIdx>(sample_sizes->at(i));
+ while (readPos < oldSampleEnd) {
+ if (readPos < end) {
+ MetaSlot& item = map[shortcut[readPos]];
+ if (item.score >= minimum_population) {
+ lastNonUniquePos = readPos + sliceLen;
+ }
+ }
+ if (readPos < lastNonUniquePos) {
+ data[writePos++] = data[readPos];
+ }
+ readPos++;
+ }
+ sample_sizes->at(i) = writePos - sampleStart;
+ }
+}
+
+void durchschlag_purify(size_t slice_len, size_t minimum_population,
+ const std::vector<size_t>& sample_sizes, uint8_t* sample_data) {
+ /* Parameters aliasing */
+ uint8_t* data = sample_data;
+
+ /* Build slice map. */
+ DurchschlagContext context = durchschlag_prepare(
+ slice_len, sample_sizes, data);
+
+ /* Calculate slice population. */
+ const std::vector<TextIdx>& offsets = context.offsets;
+ std::vector<MetaSlot> map(context.numUniqueSlices);
+ const TextIdx* shortcut = context.sliceMap.data();
+ TextIdx sliceLen = context.sliceLen;
+ TextIdx total = context.dataSize;
+ TextIdx end = total - sliceLen + 1;
+ ScoreSlices(offsets, map, shortcut, end);
+
+ /* Rewrite samples, zeroing out unique slices. */
+ TextIdx lastNonUniquePos = 0;
+ for (TextIdx readPos = 0; readPos < total; ++readPos) {
+ if (readPos < end) {
+ MetaSlot& item = map[shortcut[readPos]];
+ if (item.score >= minimum_population) {
+ lastNonUniquePos = readPos + sliceLen;
+ }
+ }
+ if (readPos >= lastNonUniquePos) {
+ data[readPos] = 0;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.h
new file mode 100755
index 000000000..adbc53141
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/durchschlag.h
@@ -0,0 +1,99 @@
+#ifndef BROTLI_RESEARCH_DURCHSCHLAG_H_
+#define BROTLI_RESEARCH_DURCHSCHLAG_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+/**
+ * Generate a dictionary for given samples.
+ *
+ * @param dictionary_size_limit maximal dictionary size
+ * @param slice_len text slice size
+ * @param block_len score block length
+ * @param sample_sizes vector with sample sizes
+ * @param sample_data concatenated samples
+ * @return generated dictionary
+ */
+std::string durchschlag_generate(
+ size_t dictionary_size_limit, size_t slice_len, size_t block_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data);
+
+//------------------------------------------------------------------------------
+// Lower level API for repetitive dictionary generation.
+//------------------------------------------------------------------------------
+
+/* Pointer to position in text. */
+typedef uint32_t DurchschlagTextIdx;
+
+/* Context is made public for flexible serialization / deserialization. */
+typedef struct DurchschlagContext {
+ DurchschlagTextIdx dataSize;
+ DurchschlagTextIdx sliceLen;
+ DurchschlagTextIdx numUniqueSlices;
+ std::vector<DurchschlagTextIdx> offsets;
+ std::vector<DurchschlagTextIdx> sliceMap;
+} DurchschlagContext;
+
+DurchschlagContext durchschlag_prepare(size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data);
+
+typedef enum DurchschalgResourceStrategy {
+ // Faster
+ DURCHSCHLAG_EXCLUSIVE = 0,
+ // Uses much less memory
+ DURCHSCHLAG_COLLABORATIVE = 1
+} DurchschalgResourceStrategy;
+
+std::string durchschlag_generate(DurchschalgResourceStrategy strategy,
+ size_t dictionary_size_limit, size_t block_len,
+ const DurchschlagContext& context, const uint8_t* sample_data);
+
+//------------------------------------------------------------------------------
+// Suffix Array based preparation.
+//------------------------------------------------------------------------------
+
+typedef struct DurchschlagIndex {
+ std::vector<DurchschlagTextIdx> lcp;
+ std::vector<DurchschlagTextIdx> sa;
+} DurchschlagIndex;
+
+DurchschlagIndex durchschlag_index(const std::vector<uint8_t>& data);
+
+DurchschlagContext durchschlag_prepare(size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const DurchschlagIndex& index);
+
+//------------------------------------------------------------------------------
+// Data preparation.
+//------------------------------------------------------------------------------
+
+/**
+ * Cut out unique slices.
+ *
+ * Both @p sample_sizes and @p sample_data are modified in-place. Number of
+ * samples remains unchanged, but some samples become shorter.
+ *
+ * @param slice_len (unique) slice size
+ * @param minimum_population minimum non-unique slice occurrence
+ * @param sample_sizes [in / out] vector with sample sizes
+ * @param sample_data [in / out] concatenated samples
+ */
+void durchschlag_distill(size_t slice_len, size_t minimum_population,
+ std::vector<size_t>* sample_sizes, uint8_t* sample_data);
+
+/**
+ * Replace unique slices with zeroes.
+ *
+ * @p sample_data is modified in-place. Number of samples and their length
+ * remain unchanged.
+ *
+ * @param slice_len (unique) slice size
+ * @param minimum_population minimum non-unique slice occurrence
+ * @param sample_sizes vector with sample sizes
+ * @param sample_data [in / out] concatenated samples
+ */
+void durchschlag_purify(size_t slice_len, size_t minimum_population,
+ const std::vector<size_t>& sample_sizes, uint8_t* sample_data);
+
+#endif // BROTLI_RESEARCH_DURCHSCHLAG_H_
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/COPYING b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/COPYING
new file mode 100644
index 000000000..07394df7c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/COPYING
@@ -0,0 +1,24 @@
+This is the esaxx copyright.
+
+Copyright (c) 2010 Daisuke Okanohara All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/README b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/README
new file mode 100644
index 000000000..c3afa09de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/README
@@ -0,0 +1,34 @@
+ESAXX
+----------------------
+
+This library provides the implementation of enhanced suffix array.
+For an input text of length N, this library builds an enhanced suffix array in O(N) time
+using 20N bytes.
+
+For a suffix array construction, I use sais.hxx, the induced sorting algorithm
+implemented by Yuta Mori.
+
+It also provides the program to enumerate the statistics of all substrings in the text.
+
+> enum_substring
+ Enumerate all substring
+> enum_substring -w
+ Input are words separated by space.
+
+Example:
+------------------
+$ cat abra
+abracadabra
+$ enum_substring < abra
+ n:11
+alpha:256
+ node:5
+0 2 4 abra
+1 5 1 a
+2 2 3 bra
+3 2 2 ra
+4 11 0
+
+$ enum_substring -w < wiki.txt >
+
+Daisuke Okanohara <daisuke dot okanohara at gmail.com>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/cmdline.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/cmdline.h
new file mode 100644
index 000000000..2fc0260cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/cmdline.h
@@ -0,0 +1,704 @@
+/*
+Copyright (c) 2009, Hideyuki Tanaka
+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.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY <copyright holder> ''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 <copyright holder> 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.
+*/
+
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <map>
+#include <string>
+#include <stdexcept>
+#include <typeinfo>
+#include <cstring>
+#include <algorithm>
+#include <cxxabi.h>
+
+namespace cmdline{
+
+namespace detail{
+
+template <typename Target, typename Source, bool Same>
+class lexical_cast_t{
+public:
+ static Target cast(const Source &arg){
+ Target ret;
+ std::stringstream ss;
+ if (!(ss<<arg && ss>>ret && ss.eof()))
+ throw std::bad_cast();
+
+ return ret;
+ }
+};
+
+template <typename Target, typename Source>
+class lexical_cast_t<Target, Source, true>{
+public:
+ static Target cast(const Source &arg){
+ return arg;
+ }
+};
+
+template <typename Source>
+class lexical_cast_t<std::string, Source, false>{
+public:
+ static std::string cast(const Source &arg){
+ std::ostringstream ss;
+ ss<<arg;
+ return ss.str();
+ }
+};
+
+template <typename Target>
+class lexical_cast_t<Target, std::string, false>{
+public:
+ static Target cast(const std::string &arg){
+ Target ret;
+ std::istringstream ss(arg);
+ if (!(ss>>ret && ss.eof()))
+ throw std::bad_cast();
+ return ret;
+ }
+};
+
+template <typename T1, typename T2>
+struct is_same {
+ static const bool value = false;
+};
+
+template <typename T>
+struct is_same<T, T>{
+ static const bool value = true;
+};
+
+template<typename Target, typename Source>
+Target lexical_cast(const Source &arg)
+{
+ return lexical_cast_t<Target, Source, detail::is_same<Target, Source>::value>::cast(arg);
+}
+
+static inline std::string demangle(const std::string &name)
+{
+ int status=0;
+ char *p=abi::__cxa_demangle(name.c_str(), 0, 0, &status);
+ std::string ret(p);
+ free(p);
+ return ret;
+}
+
+template <class T>
+std::string readable_typename()
+{
+ return demangle(typeid(T).name());
+}
+
+template <>
+std::string readable_typename<std::string>()
+{
+ return "string";
+}
+
+} // detail
+
+//-----
+
+class cmdline_error : public std::exception {
+public:
+ cmdline_error(const std::string &msg): msg(msg){}
+ ~cmdline_error() throw() {}
+ const char *what() const throw() { return msg.c_str(); }
+private:
+ std::string msg;
+};
+
+template <class T>
+struct default_reader{
+ T operator()(const std::string &str){
+ return detail::lexical_cast<T>(str);
+ }
+};
+
+template <class T>
+struct range_reader{
+ range_reader(const T &low, const T &high): low(low), high(high) {}
+ T operator()(const std::string &s) const {
+ T ret=default_reader<T>()(s);
+ if (!(ret>=low && ret<=high)) throw cmdline::cmdline_error("range_error");
+ return ret;
+ }
+private:
+ T low, high;
+};
+
+template <class T>
+range_reader<T> range(const T &low, const T &high)
+{
+ return range_reader<T>(low, high);
+}
+
+template <class T>
+struct oneof_reader{
+ T operator()(const std::string &s){
+ T ret=default_reader<T>()(s);
+ if (std::find(alt.begin(), alt.end(), s)==alt.end())
+ throw cmdline_error("");
+ return ret;
+ }
+ void add(const T &v){ alt.push_back(v); }
+private:
+ std::vector<T> alt;
+};
+
+template <class T>
+oneof_reader<T> oneof(T a1)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ ret.add(a6);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ ret.add(a6);
+ ret.add(a7);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ ret.add(a6);
+ ret.add(a7);
+ ret.add(a8);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ ret.add(a6);
+ ret.add(a7);
+ ret.add(a8);
+ ret.add(a9);
+ return ret;
+}
+
+template <class T>
+oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10)
+{
+ oneof_reader<T> ret;
+ ret.add(a1);
+ ret.add(a2);
+ ret.add(a3);
+ ret.add(a4);
+ ret.add(a5);
+ ret.add(a6);
+ ret.add(a7);
+ ret.add(a8);
+ ret.add(a9);
+ ret.add(a10);
+ return ret;
+}
+
+//-----
+
+class parser{
+public:
+ parser(){
+ }
+ ~parser(){
+ for (std::map<std::string, option_base*>::iterator p=options.begin();
+ p!=options.end(); p++)
+ delete p->second;
+ }
+
+ void add(const std::string &name,
+ char short_name=0,
+ const std::string &desc=""){
+ if (options.count(name)) throw cmdline_error("multiple definition: "+name);
+ options[name]=new option_without_value(name, short_name, desc);
+ ordered.push_back(options[name]);
+ }
+
+ template <class T>
+ void add(const std::string &name,
+ char short_name=0,
+ const std::string &desc="",
+ bool need=true,
+ const T def=T()){
+ add(name, short_name, desc, need, def, default_reader<T>());
+ }
+
+ template <class T, class F>
+ void add(const std::string &name,
+ char short_name=0,
+ const std::string &desc="",
+ bool need=true,
+ const T def=T(),
+ F reader=F()){
+ if (options.count(name)) throw cmdline_error("multiple definition: "+name);
+ options[name]=new option_with_value_with_reader<T, F>(name, short_name, need, def, desc, reader);
+ ordered.push_back(options[name]);
+ }
+
+ void footer(const std::string &f){
+ ftr=f;
+ }
+
+ void set_program_name(const std::string &name){
+ prog_name=name;
+ }
+
+ bool exist(const std::string &name){
+ if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name);
+ return options[name]->has_set();
+ }
+
+ template <class T>
+ const T &get(const std::string &name) const {
+ if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name);
+ const option_with_value<T> *p=dynamic_cast<const option_with_value<T>*>(options.find(name)->second);
+ if (p==NULL) throw cmdline_error("type mismatch flag '"+name+"'");
+ return p->get();
+ }
+
+ const std::vector<std::string> &rest() const {
+ return others;
+ }
+
+ bool parse(int argc, char *argv[]){
+ errors.clear();
+ others.clear();
+
+ if (argc<1){
+ errors.push_back("argument number must be longer than 0");
+ return false;
+ }
+ if (prog_name=="")
+ prog_name=argv[0];
+
+ std::map<char, std::string> lookup;
+ for (std::map<std::string, option_base*>::iterator p=options.begin();
+ p!=options.end(); p++){
+ if (p->first.length()==0) continue;
+ char initial=p->second->short_name();
+ if (initial){
+ if (lookup.count(initial)>0){
+ lookup[initial]="";
+ errors.push_back(std::string("short option '")+initial+"' is ambiguous");
+ return false;
+ }
+ else lookup[initial]=p->first;
+ }
+ }
+
+ for (int i=1; i<argc; i++){
+ if (strncmp(argv[i], "--", 2)==0){
+ char *p=strchr(argv[i]+2, '=');
+ if (p){
+ std::string name(argv[i]+2, p);
+ std::string val(p+1);
+ set_option(name, val);
+ }
+ else{
+ std::string name(argv[i]+2);
+ set_option(name);
+ }
+ }
+ else if (strncmp(argv[i], "-", 1)==0){
+ if (!argv[i][1]) continue;
+ char last=argv[i][1];
+ for (int j=2; argv[i][j]; j++){
+ last=argv[i][j];
+ if (lookup.count(argv[i][j-1])==0){
+ errors.push_back(std::string("undefined short option: -")+argv[i][j-1]);
+ continue;
+ }
+ if (lookup[argv[i][j-1]]==""){
+ errors.push_back(std::string("ambiguous short option: -")+argv[i][j-1]);
+ continue;
+ }
+ set_option(lookup[argv[i][j-1]]);
+ }
+
+ if (lookup.count(last)==0){
+ errors.push_back(std::string("undefined short option: -")+last);
+ continue;
+ }
+ if (lookup[last]==""){
+ errors.push_back(std::string("ambiguous short option: -")+last);
+ continue;
+ }
+
+ if (i+1<argc && options[lookup[last]]->has_value()){
+ set_option(lookup[last], argv[i+1]);
+ i++;
+ }
+ else{
+ set_option(lookup[last]);
+ }
+ }
+ else{
+ others.push_back(argv[i]);
+ }
+ }
+
+ for (std::map<std::string, option_base*>::iterator p=options.begin();
+ p!=options.end(); p++)
+ if (!p->second->valid())
+ errors.push_back("need option: --"+std::string(p->first));
+
+ return errors.size()==0;
+ }
+
+ std::string error() const{
+ return errors.size()>0?errors[0]:"";
+ }
+
+ std::string error_full() const{
+ std::ostringstream oss;
+ for (size_t i=0; i<errors.size(); i++)
+ oss<<errors[i]<<std::endl;
+ return oss.str();
+ }
+
+ std::string usage() const {
+ std::ostringstream oss;
+ oss<<"usage: "<<prog_name<<" ";
+ for (size_t i=0; i<ordered.size(); i++){
+ if (ordered[i]->must())
+ oss<<ordered[i]->short_description()<<" ";
+ }
+
+ oss<<"[options] ... "<<ftr<<std::endl;
+ oss<<"options:"<<std::endl;
+
+ size_t max_width=0;
+ for (size_t i=0; i<ordered.size(); i++){
+ max_width=std::max(max_width, ordered[i]->name().length());
+ }
+ for (size_t i=0; i<ordered.size(); i++){
+ if (ordered[i]->short_name()){
+ oss<<" -"<<ordered[i]->short_name()<<", ";
+ }
+ else{
+ oss<<" ";
+ }
+
+ oss<<"--"<<ordered[i]->name();
+ for (size_t j=ordered[i]->name().length(); j<max_width+4; j++)
+ oss<<' ';
+ oss<<ordered[i]->description()<<std::endl;
+ }
+ return oss.str();
+ }
+
+private:
+
+ void set_option(const std::string &name){
+ if (options.count(name)==0){
+ errors.push_back("undefined option: --"+name);
+ return;
+ }
+ if (!options[name]->set()){
+ errors.push_back("option needs value: --"+name);
+ return;
+ }
+ }
+
+ void set_option(const std::string &name, const std::string &value){
+ if (options.count(name)==0){
+ errors.push_back("undefined option: --"+name);
+ return;
+ }
+ if (!options[name]->set(value)){
+ errors.push_back("option value is invalid: --"+name+"="+value);
+ return;
+ }
+ }
+
+ class option_base{
+ public:
+ virtual ~option_base(){}
+
+ virtual bool has_value() const=0;
+ virtual bool set()=0;
+ virtual bool set(const std::string &value)=0;
+ virtual bool has_set() const=0;
+ virtual bool valid() const=0;
+ virtual bool must() const=0;
+
+ virtual const std::string &name() const=0;
+ virtual char short_name() const=0;
+ virtual const std::string &description() const=0;
+ virtual std::string short_description() const=0;
+ };
+
+ class option_without_value : public option_base {
+ public:
+ option_without_value(const std::string &name,
+ char short_name,
+ const std::string &desc)
+ :nam(name), snam(short_name), desc(desc), has(false){
+ }
+ ~option_without_value(){}
+
+ bool has_value() const { return false; }
+
+ bool set(){
+ has=true;
+ return true;
+ }
+
+ bool set(const std::string &){
+ return false;
+ }
+
+ bool has_set() const {
+ return has;
+ }
+
+ bool valid() const{
+ return true;
+ }
+
+ bool must() const{
+ return false;
+ }
+
+ const std::string &name() const{
+ return nam;
+ }
+
+ char short_name() const{
+ return snam;
+ }
+
+ const std::string &description() const {
+ return desc;
+ }
+
+ std::string short_description() const{
+ return "--"+nam;
+ }
+
+ private:
+ std::string nam;
+ char snam;
+ std::string desc;
+ bool has;
+ };
+
+ template <class T>
+ class option_with_value : public option_base {
+ public:
+ option_with_value(const std::string &name,
+ char short_name,
+ bool need,
+ const T &def,
+ const std::string &desc)
+ : nam(name), snam(short_name), need(need), has(false)
+ , def(def), actual(def) {
+ this->desc=full_description(desc);
+ }
+ ~option_with_value(){}
+
+ const T &get() const {
+ return actual;
+ }
+
+ bool has_value() const { return true; }
+
+ bool set(){
+ return false;
+ }
+
+ bool set(const std::string &value){
+ try{
+ actual=read(value);
+ has=true;
+ }
+ catch(const std::exception &e){
+ return false;
+ }
+ return true;
+ }
+
+ bool has_set() const{
+ return has;
+ }
+
+ bool valid() const{
+ if (need && !has) return false;
+ return true;
+ }
+
+ bool must() const{
+ return need;
+ }
+
+ const std::string &name() const{
+ return nam;
+ }
+
+ char short_name() const{
+ return snam;
+ }
+
+ const std::string &description() const {
+ return desc;
+ }
+
+ std::string short_description() const{
+ return "--"+nam+"="+detail::readable_typename<T>();
+ }
+
+ protected:
+ std::string full_description(const std::string &desc){
+ return
+ desc+" ("+detail::readable_typename<T>()+
+ (need?"":" [="+detail::lexical_cast<std::string>(def)+"]")
+ +")";
+ }
+
+ virtual T read(const std::string &s)=0;
+
+ std::string nam;
+ char snam;
+ bool need;
+ std::string desc;
+
+ bool has;
+ T def;
+ T actual;
+ };
+
+ template <class T, class F>
+ class option_with_value_with_reader : public option_with_value<T> {
+ public:
+ option_with_value_with_reader(const std::string &name,
+ char short_name,
+ bool need,
+ const T def,
+ const std::string &desc,
+ F reader)
+ : option_with_value<T>(name, short_name, need, def, desc), reader(reader){
+ }
+
+ private:
+ T read(const std::string &s){
+ return reader(s);
+ }
+
+ F reader;
+ };
+
+ std::map<std::string, option_base*> options;
+ std::vector<option_base*> ordered;
+ std::string ftr;
+
+ std::string prog_name;
+ std::vector<std::string> others;
+
+ std::vector<std::string> errors;
+};
+
+} // cmdline
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/enumSubstring.cpp b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/enumSubstring.cpp
new file mode 100644
index 000000000..e34842fd2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/enumSubstring.cpp
@@ -0,0 +1,140 @@
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "cmdline.h"
+#include "esa.hxx"
+
+using namespace std;
+
+int readFile(const char* fn, vector<int>& T){
+ FILE* fp = fopen(fn, "rb");
+ if (fp == NULL){
+ cerr << "cannot open " << fn << endl;
+ return -1;
+ }
+
+ if (fseek(fp, 0, SEEK_END) != 0){
+ cerr << "cannot fseek " << fn << endl;
+ fclose(fp);
+ return -1;
+ }
+ int n = ftell(fp);
+ rewind(fp);
+ if (n < 0){
+ cerr << "cannot ftell " << fn << endl;
+ fclose(fp);
+ return -1;
+ }
+ T.resize(n);
+ if (fread(&T[0], sizeof(unsigned char), (size_t)n, fp) != (size_t) n){
+ cerr << "fread error " << fn << endl;
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+int getID(const string& str, map<string, int>& word2id){
+ map<string, int>::const_iterator it = word2id.find(str);
+ if (it == word2id.end()){
+ int newID = (int)word2id.size();
+ word2id[str] = newID;
+ return newID;
+ } else {
+ return it->second;
+ }
+}
+
+void printSnipet(const vector<int>& T, const int beg, const int len, const vector<string>& id2word){
+ for (int i = 0; i < len; ++i){
+ int c = T[beg + i];
+ if (id2word.size() > 0){
+ cout << id2word[c] << " ";
+ } else {
+ cout << (isspace((char)c) ? '_' : (char)c);
+ }
+ }
+}
+
+int main(int argc, char* argv[]){
+ cmdline::parser p;
+ p.add("word", 'w', "word type");
+
+ if (!p.parse(argc, argv)){
+ cerr << p.error() << endl
+ << p.usage() << endl;
+ return -1;
+ }
+
+ if (p.rest().size() > 0){
+ cerr << p.usage() << endl;
+ return -1;
+ }
+
+ vector<int> T;
+
+ bool isWord = p.exist("word");
+ map<string, int> word2id;
+ istreambuf_iterator<char> isit(cin);
+ istreambuf_iterator<char> end;
+
+ size_t origLen = 0;
+ if (isWord){
+ string word;
+ while (isit != end){
+ char c = *isit++;
+ if (!isspace(c)){
+ word += c;
+ } else if (word.size() > 0){
+ T.push_back(getID(word, word2id));
+ word = "";
+ }
+ ++origLen;
+ }
+ if (word.size() > 0){
+ T.push_back(getID(word, word2id));
+ }
+ } else {
+ while (isit != end){
+ T.push_back((unsigned char)(*isit++));
+ }
+ origLen = T.size();
+ }
+
+ vector<string> id2word(word2id.size());
+ for (map<string, int>::const_iterator it = word2id.begin();
+ it != word2id.end(); ++it){
+ id2word[it->second] = it->first;
+ }
+
+ vector<int> SA(T.size());
+ vector<int> L (T.size());
+ vector<int> R (T.size());
+ vector<int> D (T.size());
+
+ int k = (isWord) ? (int)id2word.size() : 0x100;
+ if (isWord){
+ cerr << "origN:" << origLen << endl;
+ }
+ cerr << " n:" << T.size() << endl;
+ cerr << "alpha:" << k << endl;
+
+ int nodeNum = 0;
+ if (esaxx(T.begin(), SA.begin(),
+ L.begin(), R.begin(), D.begin(),
+ (int)T.size(), k, nodeNum) == -1){
+ return -1;
+ }
+ cerr << " node:" << nodeNum << endl;
+
+ for (int i = 0; i < nodeNum; ++i){
+ cout << i << "\t" << R[i] - L[i] << "\t" << D[i] << "\t";
+ printSnipet(T, SA[L[i]], D[i], id2word);
+ cout << endl;
+ }
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/esa.hxx b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/esa.hxx
new file mode 100644
index 000000000..acb5c7a1b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/esa.hxx
@@ -0,0 +1,125 @@
+/*
+ * esa.hxx
+ * Copyright (c) 2010 Daisuke Okanohara All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _ESA_HXX
+#define _ESA_HXX
+
+#include <vector>
+#include <utility>
+#include <cassert>
+#include "sais.hxx"
+
+namespace esaxx_private {
+template<typename string_type, typename sarray_type, typename index_type>
+index_type suffixtree(string_type T, sarray_type SA, sarray_type L, sarray_type R, sarray_type D, index_type n){
+ if (n == 0){
+ return 0;
+ }
+ sarray_type Psi = L;
+ Psi[SA[0]] = SA[n-1];
+ for (index_type i = 1; i < n; ++i){
+ Psi[SA[i]] = SA[i-1];
+ }
+
+ // Compare at most 2n log n charcters. Practically fastest
+ // "Permuted Longest-Common-Prefix Array", Juha Karkkainen, CPM 09
+ sarray_type PLCP = R;
+ index_type h = 0;
+ for (index_type i = 0; i < n; ++i){
+ index_type j = Psi[i];
+ while (i+h < n && j+h < n &&
+ T[i+h] == T[j+h]){
+ ++h;
+ }
+ PLCP[i] = h;
+ if (h > 0) --h;
+ }
+
+ sarray_type H = L;
+ for (index_type i = 0; i < n; ++i){
+ H[i] = PLCP[SA[i]];
+ }
+ H[0] = -1;
+
+ std::vector<std::pair<index_type, index_type> > S;
+ S.push_back(std::make_pair((index_type)-1, (index_type)-1));
+ size_t nodeNum = 0;
+ for (index_type i = 0; ; ++i){
+ std::pair<index_type, index_type> cur (i, (i == n) ? -1 : H[i]);
+ std::pair<index_type, index_type> cand(S.back());
+ while (cand.second > cur.second){
+ if (i - cand.first > 1){
+ L[nodeNum] = cand.first;
+ R[nodeNum] = i;
+ D[nodeNum] = cand.second;
+ ++nodeNum;
+ }
+ cur.first = cand.first;
+ S.pop_back();
+ cand = S.back();
+ }
+ if (cand.second < cur.second){
+ S.push_back(cur);
+ }
+ if (i == n) break;
+ S.push_back(std::make_pair(i, n - SA[i] + 1));
+ }
+ return nodeNum;
+}
+}
+
+/**
+ * @brief Build an enhanced suffix array of a given string in linear time
+ * For an input text T, esaxx() builds an enhancd suffix array in linear time.
+ * i-th internal node is represented as a triple (L[i], R[i], D[i]);
+ * L[i] and R[i] is the left/right boundary of the suffix array as SA[L[i]....R[i]-1]
+ * D[i] is the depth of the internal node
+ * The number of internal node is at most N-1 and return the actual number by
+ * @param T[0...n-1] The input string. (random access iterator)
+ * @param SA[0...n-1] The output suffix array (random access iterator)
+ * @param L[0...n-1] The output left boundary of internal node (random access iterator)
+ * @param R[0...n-1] The output right boundary of internal node (random access iterator)
+ * @param D[0...n-1] The output depth of internal node (random access iterator)
+ * @param n The length of the input string
+ * @param k The alphabet size
+ * @pram nodeNum The output the number of internal node
+ * @return 0 if succeded, -1 or -2 otherwise
+ */
+
+template<typename string_type, typename sarray_type, typename index_type>
+int esaxx(string_type T, sarray_type SA, sarray_type L, sarray_type R, sarray_type D,
+ index_type n, index_type k, index_type& nodeNum) {
+ if ((n < 0) || (k <= 0)) return -1;
+ int err = saisxx(T, SA, n, k);
+ if (err != 0){
+ return err;
+ }
+ nodeNum = esaxx_private::suffixtree(T, SA, L, R, D, n);
+ return 0;
+}
+
+
+#endif // _ESA_HXX
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/sais.hxx b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/sais.hxx
new file mode 100644
index 000000000..20e69dfec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/sais.hxx
@@ -0,0 +1,364 @@
+/*
+ * sais.hxx for sais-lite
+ * Copyright (c) 2008-2009 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SAIS_HXX
+#define _SAIS_HXX 1
+#ifdef __cplusplus
+
+#ifdef __INTEL_COMPILER
+#pragma warning(disable : 383 981 1418)
+// for icc 64-bit
+//#define __builtin_vsnprintf(a, b, c, d) __builtin_vsnprintf(a, b, c, (char *)d)
+#endif
+
+#include <iterator>
+#ifdef _OPENMP
+# include <omp.h>
+#endif
+
+namespace saisxx_private {
+
+/* find the start or end of each bucket */
+template<typename string_type, typename bucket_type, typename index_type>
+void
+getCounts(const string_type T, bucket_type C, index_type n, index_type k) {
+#ifdef _OPENMP
+ bucket_type D;
+ index_type i, j, p, sum, first, last;
+ int thnum, maxthreads = omp_get_max_threads();
+#pragma omp parallel default(shared) private(D, i, thnum, first, last)
+ {
+ thnum = omp_get_thread_num();
+ D = C + thnum * k;
+ first = n / maxthreads * thnum;
+ last = (thnum < (maxthreads - 1)) ? n / maxthreads * (thnum + 1) : n;
+ for(i = 0; i < k; ++i) { D[i] = 0; }
+ for(i = first; i < last; ++i) { ++D[T[i]]; }
+ }
+ if(1 < maxthreads) {
+#pragma omp parallel for default(shared) private(i, j, p, sum)
+ for(i = 0; i < k; ++i) {
+ for(j = 1, p = i + k, sum = C[i]; j < maxthreads; ++j, p += k) {
+ sum += C[p];
+ }
+ C[i] = sum;
+ }
+ }
+#else
+ index_type i;
+ for(i = 0; i < k; ++i) { C[i] = 0; }
+ for(i = 0; i < n; ++i) { ++C[T[i]]; }
+#endif
+}
+template<typename bucket_type, typename index_type>
+void
+getBuckets(const bucket_type C, bucket_type B, index_type k, bool end) {
+ index_type i, sum = 0;
+ if(end) { for(i = 0; i < k; ++i) { sum += C[i]; B[i] = sum; } }
+ else { for(i = 0; i < k; ++i) { sum += C[i]; B[i] = sum - C[i]; } }
+}
+
+/* compute SA and BWT */
+template<typename string_type, typename sarray_type,
+ typename bucket_type, typename index_type>
+void
+induceSA(string_type T, sarray_type SA, bucket_type C, bucket_type B,
+ index_type n, index_type k) {
+typedef typename std::iterator_traits<string_type>::value_type char_type;
+ sarray_type b;
+ index_type i, j;
+ char_type c0, c1;
+ /* compute SAl */
+ if(C == B) { getCounts(T, C, n, k); }
+ getBuckets(C, B, k, false); /* find starts of buckets */
+ b = SA + B[c1 = T[j = n - 1]];
+ *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j;
+ for(i = 0; i < n; ++i) {
+ j = SA[i], SA[i] = ~j;
+ if(0 < j) {
+ if((c0 = T[--j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; }
+ *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j;
+ }
+ }
+ /* compute SAs */
+ if(C == B) { getCounts(T, C, n, k); }
+ getBuckets(C, B, k, true); /* find ends of buckets */
+ for(i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
+ if(0 < (j = SA[i])) {
+ if((c0 = T[--j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; }
+ *--b = ((j == 0) || (T[j - 1] > c1)) ? ~j : j;
+ } else {
+ SA[i] = ~j;
+ }
+ }
+}
+template<typename string_type, typename sarray_type,
+ typename bucket_type, typename index_type>
+int
+computeBWT(string_type T, sarray_type SA, bucket_type C, bucket_type B,
+ index_type n, index_type k) {
+typedef typename std::iterator_traits<string_type>::value_type char_type;
+ sarray_type b;
+ index_type i, j, pidx = -1;
+ char_type c0, c1;
+ /* compute SAl */
+ if(C == B) { getCounts(T, C, n, k); }
+ getBuckets(C, B, k, false); /* find starts of buckets */
+ b = SA + B[c1 = T[j = n - 1]];
+ *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j;
+ for(i = 0; i < n; ++i) {
+ if(0 < (j = SA[i])) {
+ SA[i] = ~(c0 = T[--j]);
+ if(c0 != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; }
+ *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j;
+ } else if(j != 0) {
+ SA[i] = ~j;
+ }
+ }
+ /* compute SAs */
+ if(C == B) { getCounts(T, C, n, k); }
+ getBuckets(C, B, k, true); /* find ends of buckets */
+ for(i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) {
+ if(0 < (j = SA[i])) {
+ SA[i] = (c0 = T[--j]);
+ if(c0 != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; }
+ *--b = ((0 < j) && (T[j - 1] > c1)) ? ~((index_type)T[j - 1]) : j;
+ } else if(j != 0) {
+ SA[i] = ~j;
+ } else {
+ pidx = i;
+ }
+ }
+ return pidx;
+}
+
+/* find the suffix array SA of T[0..n-1] in {0..k}^n
+ use a working space (excluding s and SA) of at most 2n+O(1) for a constant alphabet */
+template<typename string_type, typename sarray_type, typename index_type>
+int
+suffixsort(string_type T, sarray_type SA,
+ index_type fs, index_type n, index_type k,
+ bool isbwt) {
+typedef typename std::iterator_traits<string_type>::value_type char_type;
+ sarray_type RA;
+ index_type i, j, m, p, q, plen, qlen, name, pidx = 0;
+ bool diff;
+ int c;
+#ifdef _OPENMP
+ int maxthreads = omp_get_max_threads();
+#else
+# define maxthreads 1
+#endif
+ char_type c0, c1;
+
+ /* stage 1: reduce the problem by at least 1/2
+ sort all the S-substrings */
+ if(fs < (maxthreads * k)) {
+ index_type *C, *B;
+ if((C = new index_type[maxthreads * k]) == 0) { return -2; }
+ B = (1 < maxthreads) ? C + k : C;
+ getCounts(T, C, n, k); getBuckets(C, B, k, true); /* find ends of buckets */
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = 0; i < n; ++i) { SA[i] = 0; }
+ for(i = n - 2, c = 0, c1 = T[n - 1]; 0 <= i; --i, c1 = c0) {
+ if((c0 = T[i]) < (c1 + c)) { c = 1; }
+ else if(c != 0) { SA[--B[c1]] = i + 1, c = 0; }
+ }
+ induceSA(T, SA, C, B, n, k);
+ delete [] C;
+ } else {
+ sarray_type C, B;
+ C = SA + n;
+ B = ((1 < maxthreads) || (k <= (fs - k))) ? C + k : C;
+ getCounts(T, C, n, k); getBuckets(C, B, k, true); /* find ends of buckets */
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = 0; i < n; ++i) { SA[i] = 0; }
+ for(i = n - 2, c = 0, c1 = T[n - 1]; 0 <= i; --i, c1 = c0) {
+ if((c0 = T[i]) < (c1 + c)) { c = 1; }
+ else if(c != 0) { SA[--B[c1]] = i + 1, c = 0; }
+ }
+ induceSA(T, SA, C, B, n, k);
+ }
+
+ /* compact all the sorted substrings into the first m items of SA
+ 2*m must be not larger than n (proveable) */
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i, j, p, c0, c1)
+ for(i = 0; i < n; ++i) {
+ p = SA[i];
+ if((0 < p) && (T[p - 1] > (c0 = T[p]))) {
+ for(j = p + 1; (j < n) && (c0 == (c1 = T[j])); ++j) { }
+ if((j < n) && (c0 < c1)) { SA[i] = ~p; }
+ }
+ }
+ for(i = 0, m = 0; i < n; ++i) { if((p = SA[i]) < 0) { SA[m++] = ~p; } }
+#else
+ for(i = 0, m = 0; i < n; ++i) {
+ p = SA[i];
+ if((0 < p) && (T[p - 1] > (c0 = T[p]))) {
+ for(j = p + 1; (j < n) && (c0 == (c1 = T[j])); ++j) { }
+ if((j < n) && (c0 < c1)) { SA[m++] = p; }
+ }
+ }
+#endif
+ j = m + (n >> 1);
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = m; i < j; ++i) { SA[i] = 0; } /* init the name array buffer */
+ /* store the length of all substrings */
+ for(i = n - 2, j = n, c = 0, c1 = T[n - 1]; 0 <= i; --i, c1 = c0) {
+ if((c0 = T[i]) < (c1 + c)) { c = 1; }
+ else if(c != 0) { SA[m + ((i + 1) >> 1)] = j - i - 1; j = i + 1; c = 0; }
+ }
+ /* find the lexicographic names of all substrings */
+ for(i = 0, name = 0, q = n, qlen = 0; i < m; ++i) {
+ p = SA[i], plen = SA[m + (p >> 1)], diff = true;
+ if(plen == qlen) {
+ for(j = 0; (j < plen) && (T[p + j] == T[q + j]); ++j) { }
+ if(j == plen) { diff = false; }
+ }
+ if(diff != false) { ++name, q = p, qlen = plen; }
+ SA[m + (p >> 1)] = name;
+ }
+
+ /* stage 2: solve the reduced problem
+ recurse if names are not yet unique */
+ if(name < m) {
+ RA = SA + n + fs - m;
+ for(i = m + (n >> 1) - 1, j = m - 1; m <= i; --i) {
+ if(SA[i] != 0) { RA[j--] = SA[i] - 1; }
+ }
+ if(suffixsort(RA, SA, fs + n - m * 2, m, name, false) != 0) { return -2; }
+ for(i = n - 2, j = m - 1, c = 0, c1 = T[n - 1]; 0 <= i; --i, c1 = c0) {
+ if((c0 = T[i]) < (c1 + c)) { c = 1; }
+ else if(c != 0) { RA[j--] = i + 1, c = 0; } /* get p1 */
+ }
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = 0; i < m; ++i) { SA[i] = RA[SA[i]]; } /* get index in s */
+ }
+
+ /* stage 3: induce the result for the original problem */
+ if(fs < (maxthreads * k)) {
+ index_type *B, *C;
+ if((C = new index_type[maxthreads * k]) == 0) { return -2; }
+ B = (1 < maxthreads) ? C + k : C;
+ /* put all left-most S characters into their buckets */
+ getCounts(T, C, n, k); getBuckets(C, B, k, true); /* find ends of buckets */
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = m; i < n; ++i) { SA[i] = 0; } /* init SA[m..n-1] */
+ for(i = m - 1; 0 <= i; --i) {
+ j = SA[i], SA[i] = 0;
+ SA[--B[T[j]]] = j;
+ }
+ if(isbwt == false) { induceSA(T, SA, C, B, n, k); }
+ else { pidx = computeBWT(T, SA, C, B, n, k); }
+ delete [] C;
+ } else {
+ sarray_type C, B;
+ C = SA + n;
+ B = ((1 < maxthreads) || (k <= (fs - k))) ? C + k : C;
+ /* put all left-most S characters into their buckets */
+ getCounts(T, C, n, k); getBuckets(C, B, k, true); /* find ends of buckets */
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) private(i)
+#endif
+ for(i = m; i < n; ++i) { SA[i] = 0; } /* init SA[m..n-1] */
+ for(i = m - 1; 0 <= i; --i) {
+ j = SA[i], SA[i] = 0;
+ SA[--B[T[j]]] = j;
+ }
+ if(isbwt == false) { induceSA(T, SA, C, B, n, k); }
+ else { pidx = computeBWT(T, SA, C, B, n, k); }
+ }
+
+ return pidx;
+#ifndef _OPENMP
+# undef maxthreads
+#endif
+}
+
+} /* namespace saisxx_private */
+
+
+/**
+ * @brief Constructs the suffix array of a given string in linear time.
+ * @param T[0..n-1] The input string. (random access iterator)
+ * @param SA[0..n-1] The output array of suffixes. (random access iterator)
+ * @param n The length of the given string.
+ * @param k The alphabet size.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+template<typename string_type, typename sarray_type, typename index_type>
+int
+saisxx(string_type T, sarray_type SA, index_type n, index_type k = 256) {
+ int err;
+ if((n < 0) || (k <= 0)) { return -1; }
+ if(n <= 1) { if(n == 1) { SA[0] = 0; } return 0; }
+ try { err = saisxx_private::suffixsort(T, SA, 0, n, k, false); }
+ catch(...) { err = -2; }
+ return err;
+}
+
+/**
+ * @brief Constructs the burrows-wheeler transformed string of a given string in linear time.
+ * @param T[0..n-1] The input string. (random access iterator)
+ * @param U[0..n-1] The output string. (random access iterator)
+ * @param A[0..n-1] The temporary array. (random access iterator)
+ * @param n The length of the given string.
+ * @param k The alphabet size.
+ * @return The primary index if no error occurred, -1 or -2 otherwise.
+ */
+template<typename string_type, typename sarray_type, typename index_type>
+index_type
+saisxx_bwt(string_type T, string_type U, sarray_type A, index_type n, index_type k = 256) {
+typedef typename std::iterator_traits<string_type>::value_type char_type;
+ index_type i, pidx;
+ if((n < 0) || (k <= 0)) { return -1; }
+ if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; }
+ try {
+ pidx = saisxx_private::suffixsort(T, A, 0, n, k, true);
+ if(0 <= pidx) {
+ U[0] = T[n - 1];
+ for(i = 0; i < pidx; ++i) { U[i + 1] = (char_type)A[i]; }
+ for(i += 1; i < n; ++i) { U[i] = (char_type)A[i]; }
+ pidx += 1;
+ }
+ } catch(...) { pidx = -2; }
+ return pidx;
+}
+
+
+#endif /* __cplusplus */
+#endif /* _SAIS_HXX */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/waf b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/waf
new file mode 100755
index 000000000..d99146fa4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/waf
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/wscript b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/wscript
new file mode 100644
index 000000000..a58f45826
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/esaxx/wscript
@@ -0,0 +1,23 @@
+VERSION= '0.0.4'
+APPNAME= 'esaxx'
+
+srcdir= '.'
+blddir= 'bin'
+
+def set_options(ctx):
+ ctx.tool_options('compiler_cxx')
+
+def configure(ctx):
+ ctx.check_tool('compiler_cxx')
+ ctx.env.CXXFLAGS += ['-O2', '-Wall', '-g']
+
+def build(bld):
+ task1= bld(features='cxx cprogram',
+ source = 'enumSubstring.cpp',
+ name = 'enum_substring',
+ target = 'enum_substring',
+ includes = '.')
+
+def dist_hook():
+ import os
+ os.remove('googlecode_upload.py')
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/find_opt_references.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/find_opt_references.cc
new file mode 100644
index 000000000..378d3b521
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/find_opt_references.cc
@@ -0,0 +1,267 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ Author: zip753@gmail.com (Ivan Nikulin)
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Tool for generating optimal backward references for the input file. Uses
+ sais-lite library for building suffix array. */
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include <gflags/gflags.h>
+using gflags::ParseCommandLineFlags;
+
+#include "./esaxx/sais.hxx"
+
+DEFINE_bool(advanced, false, "Advanced searching mode: finds all longest "
+ "matches at positions that are not covered by matches of length at least "
+ "max_length. WARNING: uses much more memory than simple mode, especially "
+ "for small values of min_length.");
+DEFINE_int32(min_length, 1, "Minimal length of found backward references.");
+/* For advanced mode. */
+DEFINE_int32(long_length, 32,
+ "Maximal length of found backward references for advanced mode.");
+DEFINE_int32(skip, 1, "Number of bytes to skip.");
+
+const size_t kFileBufferSize = (1 << 16); // 64KB
+
+typedef int sarray_type; // Can't make it unsigned because of templates :(
+typedef uint8_t input_type;
+typedef uint32_t lcp_type;
+typedef std::pair<int, std::vector<int> > entry_type;
+typedef std::function<void(sarray_type*, lcp_type*, size_t, int, int, int, int,
+ int)> Fn;
+
+void ReadInput(FILE* fin, input_type* storage, size_t input_size) {
+ size_t last_pos = 0;
+ size_t available_in;
+ fseek(fin, 0, SEEK_SET);
+ do {
+ available_in = fread(storage + last_pos, 1, kFileBufferSize, fin);
+ last_pos += available_in;
+ } while (available_in != 0);
+ assert(last_pos == input_size);
+}
+
+void BuildLCP(input_type* storage, sarray_type* sarray, lcp_type* lcp,
+ size_t size, uint32_t* pos) {
+ for (int i = 0; i < size; ++i) {
+ pos[sarray[i]] = i;
+ }
+ uint32_t k = 0;
+ lcp[size - 1] = 0;
+ for (int i = 0; i < size; ++i) {
+ if (pos[i] == size - 1) {
+ k = 0;
+ continue;
+ }
+ uint32_t j = sarray[pos[i] + 1]; // Suffix which follow i-th suffix in SA.
+ while (i + k < size && j + k < size && storage[i + k] == storage[j + k]) {
+ ++k;
+ }
+ lcp[pos[i]] = k;
+ if (k > 0) --k;
+ }
+}
+
+inline void PrintReference(sarray_type* sarray, lcp_type* lcp, size_t size,
+ int idx, int left_ix, int right_ix, int left_lcp,
+ int right_lcp, FILE* fout) {
+ int max_lcp_ix;
+ if (right_ix == size - 1 || (left_ix >= 0 && left_lcp >= right_lcp)) {
+ max_lcp_ix = left_ix;
+ } else {
+ max_lcp_ix = right_ix;
+ }
+ int dist = idx - sarray[max_lcp_ix];
+ assert(dist > 0);
+ fputc(1, fout);
+ fwrite(&idx, sizeof(int), 1, fout); // Position in input.
+ fwrite(&dist, sizeof(int), 1, fout); // Backward distance.
+}
+
+inline void GoLeft(sarray_type* sarray, lcp_type* lcp, int idx, int left_ix,
+ int left_lcp, entry_type* entry) {
+ entry->first = left_lcp;
+ if (left_lcp > FLAGS_long_length) return;
+ for (; left_ix >= 0; --left_ix) {
+ if (lcp[left_ix] < left_lcp) break;
+ if (sarray[left_ix] < idx) {
+ entry->second.push_back(idx - sarray[left_ix]);
+ }
+ }
+}
+
+inline void GoRight(sarray_type* sarray, lcp_type* lcp, int idx, size_t size,
+ int right_ix, int right_lcp, entry_type* entry) {
+ entry->first = right_lcp;
+ if (right_lcp > FLAGS_long_length) return;
+ for (; right_ix < size - 1; ++right_ix) {
+ if (lcp[right_ix] < right_lcp) break;
+ if (sarray[right_ix] < idx) {
+ entry->second.push_back(idx - sarray[right_ix]);
+ }
+ }
+}
+
+inline void StoreReference(sarray_type* sarray, lcp_type* lcp, size_t size,
+ int idx, int left_ix, int right_ix, int left_lcp,
+ int right_lcp, entry_type* entries) {
+ if (right_ix == size - 1 || (left_ix >= 0 && left_lcp > right_lcp)) {
+ // right is invalid or left is better
+ GoLeft(sarray, lcp, idx, left_ix, left_lcp, &entries[idx]);
+ } else if (left_ix < 0 || (right_ix < size - 1 && right_lcp > left_lcp)) {
+ // left is invalid or right is better
+ GoRight(sarray, lcp, idx, size, right_ix, right_lcp, &entries[idx]);
+ } else { // both are valid and of equal length
+ GoLeft(sarray, lcp, idx, left_ix, left_lcp, &entries[idx]);
+ GoRight(sarray, lcp, idx, size, right_ix, right_lcp, &entries[idx]);
+ }
+}
+
+void ProcessReferences(sarray_type* sarray, lcp_type* lcp, size_t size,
+ uint32_t* pos, const Fn& process_output) {
+ int min_length = FLAGS_min_length;
+ for (int idx = FLAGS_skip; idx < size; ++idx) {
+ int left_lcp = -1;
+ int left_ix;
+ for (left_ix = pos[idx] - 1; left_ix >= 0; --left_ix) {
+ if (left_lcp == -1 || left_lcp > lcp[left_ix]) {
+ left_lcp = lcp[left_ix];
+ }
+ if (left_lcp == 0) break;
+ if (sarray[left_ix] < idx) break;
+ }
+
+ int right_lcp = -1;
+ int right_ix;
+ for (right_ix = pos[idx]; right_ix < size - 1; ++right_ix) {
+ if (right_lcp == -1 || right_lcp > lcp[right_ix]) {
+ right_lcp = lcp[right_ix];
+ }
+ // Stop if we have better result from the left side already.
+ if (right_lcp < left_lcp && left_ix >= 0) break;
+ if (right_lcp == 0) break;
+ if (sarray[right_ix] < idx) break;
+ }
+
+ if ((left_ix >= 0 && left_lcp >= min_length) ||
+ (right_ix < size - 1 && right_lcp >= min_length)) {
+ process_output(sarray, lcp, size, idx, left_ix, right_ix, left_lcp,
+ right_lcp);
+ }
+ }
+}
+
+void ProcessEntries(entry_type* entries, size_t size, FILE* fout) {
+ int long_length = FLAGS_long_length;
+ std::vector<std::pair<int, int> > segments;
+ size_t idx;
+ for (idx = 0; idx < size;) {
+ entry_type& entry = entries[idx];
+ if (entry.first > long_length) {
+ // Add segment.
+ if (segments.empty() || segments.back().second < idx) {
+ segments.push_back({idx, idx + entry.first});
+ } else {
+ segments.back().second = idx + entry.first;
+ }
+ }
+ ++idx;
+ }
+ printf("Segments generated.\n");
+ size_t segments_ix = 0;
+ for (idx = 0; idx < size;) {
+ if (idx == segments[segments_ix].first) {
+ // Skip segment.
+ idx = segments[segments_ix].second;
+ } else {
+ for (auto& dist : entries[idx].second) {
+ fputc(1, fout);
+ fwrite(&idx, sizeof(int), 1, fout); // Position in input.
+ fwrite(&dist, sizeof(int), 1, fout); // Backward distance.
+ }
+ ++idx;
+ }
+ }
+}
+
+int main(int argc, char* argv[]) {
+ ParseCommandLineFlags(&argc, &argv, true);
+ if (argc != 3) {
+ printf("usage: %s input_file output_file\n", argv[0]);
+ return 1;
+ }
+
+ FILE* fin = fopen(argv[1], "rb");
+ FILE* fout = fopen(argv[2], "w");
+
+ fseek(fin, 0, SEEK_END);
+ int input_size = ftell(fin);
+ fseek(fin, 0, SEEK_SET);
+ printf("The file size is %u bytes\n", input_size);
+
+ input_type* storage = new input_type[input_size];
+
+ ReadInput(fin, storage, input_size);
+ fclose(fin);
+
+ sarray_type* sarray = new sarray_type[input_size];
+ saisxx(storage, sarray, input_size);
+ printf("Suffix array calculated.\n");
+
+ // Inverse suffix array.
+ uint32_t* pos = new uint32_t[input_size];
+
+ lcp_type* lcp = new lcp_type[input_size];
+ BuildLCP(storage, sarray, lcp, input_size, pos);
+ printf("LCP array constructed.\n");
+ delete[] storage;
+
+ using std::placeholders::_1;
+ using std::placeholders::_2;
+ using std::placeholders::_3;
+ using std::placeholders::_4;
+ using std::placeholders::_5;
+ using std::placeholders::_6;
+ using std::placeholders::_7;
+ using std::placeholders::_8;
+ entry_type* entries;
+ if (FLAGS_advanced) {
+ entries = new entry_type[input_size];
+ for (size_t i = 0; i < input_size; ++i) entries[i].first = -1;
+ }
+ Fn print = std::bind(PrintReference, _1, _2, _3, _4, _5, _6, _7, _8, fout);
+ Fn store = std::bind(StoreReference, _1, _2, _3, _4, _5, _6, _7, _8, entries);
+
+ ProcessReferences(sarray, lcp, input_size, pos,
+ FLAGS_advanced ? store : print);
+ printf("References processed.\n");
+
+ if (FLAGS_advanced) {
+ int good_cnt = 0;
+ uint64_t avg_cnt = 0;
+ for (size_t i = 0; i < input_size; ++i) {
+ if (entries[i].first != -1) {
+ ++good_cnt;
+ avg_cnt += entries[i].second.size();
+ }
+ }
+ printf("Number of covered positions = %d\n", good_cnt);
+ printf("Average number of references per covered position = %.4lf\n",
+ static_cast<double>(avg_cnt) / good_cnt);
+ ProcessEntries(entries, input_size, fout);
+ printf("Entries processed.\n");
+ }
+
+ fclose(fout);
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_brotli.png b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_brotli.png
new file mode 100644
index 000000000..c95eba967
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_brotli.png
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_diff.png b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_diff.png
new file mode 100644
index 000000000..5df6748e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_diff.png
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_opt.png b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_opt.png
new file mode 100644
index 000000000..43c655d44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/img/enwik9_opt.png
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/.gitignore b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/.gitignore
new file mode 100644
index 000000000..a0a066640
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/.gitignore
@@ -0,0 +1,32 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# CMake files/directories
+build/
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CHANGELOG.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CHANGELOG.md
new file mode 100644
index 000000000..fe9d00405
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CHANGELOG.md
@@ -0,0 +1,21 @@
+# libdivsufsort Change Log
+
+See full changelog at: https://github.com/y-256/libdivsufsort/commits
+
+## [2.0.1] - 2010-11-11
+### Fixed
+* Wrong variable used in `divbwt` function
+* Enclose some string variables with double quotation marks in include/CMakeLists.txt
+* Fix typo in include/CMakeLists.txt
+
+## 2.0.0 - 2008-08-23
+### Changed
+* Switch the build system to [CMake](http://www.cmake.org/)
+* Improve the performance of the suffix-sorting algorithm
+
+### Added
+* OpenMP support
+* 64-bit version of divsufsort
+
+[Unreleased]: https://github.com/y-256/libdivsufsort/compare/2.0.1...HEAD
+[2.0.1]: https://github.com/y-256/libdivsufsort/compare/2.0.0...2.0.1
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeLists.txt
new file mode 100644
index 000000000..785994393
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeLists.txt
@@ -0,0 +1,99 @@
+### cmake file for building libdivsufsort Package ###
+cmake_minimum_required(VERSION 2.4.4)
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
+include(AppendCompilerFlags)
+
+## Project information ##
+project(libdivsufsort C)
+set(PROJECT_VENDOR "Yuta Mori")
+set(PROJECT_CONTACT "yuta.256@gmail.com")
+set(PROJECT_URL "https://github.com/y-256/libdivsufsort")
+set(PROJECT_DESCRIPTION "A lightweight suffix sorting library")
+include(VERSION.cmake)
+
+## CPack configuration ##
+set(CPACK_GENERATOR "TGZ;TBZ2;ZIP")
+set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2;ZIP")
+include(ProjectCPack)
+
+## Project options ##
+option(BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON)
+option(BUILD_EXAMPLES "Build examples" ON)
+option(BUILD_DIVSUFSORT64 "Build libdivsufsort64" OFF)
+option(USE_OPENMP "Use OpenMP for parallelization" OFF)
+option(WITH_LFS "Enable Large File Support" ON)
+
+## Installation directories ##
+set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32 or 64)")
+
+set(CMAKE_INSTALL_RUNTIMEDIR "" CACHE PATH "Specify the output directory for dll runtimes (default is bin)")
+if(NOT CMAKE_INSTALL_RUNTIMEDIR)
+ set(CMAKE_INSTALL_RUNTIMEDIR "${CMAKE_INSTALL_PREFIX}/bin")
+endif(NOT CMAKE_INSTALL_RUNTIMEDIR)
+
+set(CMAKE_INSTALL_LIBDIR "" CACHE PATH "Specify the output directory for libraries (default is lib)")
+if(NOT CMAKE_INSTALL_LIBDIR)
+ set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}")
+endif(NOT CMAKE_INSTALL_LIBDIR)
+
+set(CMAKE_INSTALL_INCLUDEDIR "" CACHE PATH "Specify the output directory for header files (default is include)")
+if(NOT CMAKE_INSTALL_INCLUDEDIR)
+ set(CMAKE_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
+endif(NOT CMAKE_INSTALL_INCLUDEDIR)
+
+set(CMAKE_INSTALL_PKGCONFIGDIR "" CACHE PATH "Specify the output directory for pkgconfig files (default is lib/pkgconfig)")
+if(NOT CMAKE_INSTALL_PKGCONFIGDIR)
+ set(CMAKE_INSTALL_PKGCONFIGDIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif(NOT CMAKE_INSTALL_PKGCONFIGDIR)
+
+## Build type ##
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release")
+elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(CMAKE_VERBOSE_MAKEFILE ON)
+endif(NOT CMAKE_BUILD_TYPE)
+
+## Compiler options ##
+if(MSVC)
+ append_c_compiler_flags("/W4" "VC" CMAKE_C_FLAGS)
+ append_c_compiler_flags("/Oi;/Ot;/Ox;/Oy" "VC" CMAKE_C_FLAGS_RELEASE)
+ if(USE_OPENMP)
+ append_c_compiler_flags("/openmp" "VC" CMAKE_C_FLAGS)
+ endif(USE_OPENMP)
+elseif(BORLAND)
+ append_c_compiler_flags("-w" "BCC" CMAKE_C_FLAGS)
+ append_c_compiler_flags("-Oi;-Og;-Os;-Ov;-Ox" "BCC" CMAKE_C_FLAGS_RELEASE)
+else(MSVC)
+ if(CMAKE_COMPILER_IS_GNUCC)
+ append_c_compiler_flags("-Wall" "GCC" CMAKE_C_FLAGS)
+ append_c_compiler_flags("-fomit-frame-pointer" "GCC" CMAKE_C_FLAGS_RELEASE)
+ if(USE_OPENMP)
+ append_c_compiler_flags("-fopenmp" "GCC" CMAKE_C_FLAGS)
+ endif(USE_OPENMP)
+ else(CMAKE_COMPILER_IS_GNUCC)
+ append_c_compiler_flags("-Wall" "UNKNOWN" CMAKE_C_FLAGS)
+ append_c_compiler_flags("-fomit-frame-pointer" "UNKNOWN" CMAKE_C_FLAGS_RELEASE)
+ if(USE_OPENMP)
+ append_c_compiler_flags("-fopenmp;-openmp;-omp" "UNKNOWN" CMAKE_C_FLAGS)
+ endif(USE_OPENMP)
+ endif(CMAKE_COMPILER_IS_GNUCC)
+endif(MSVC)
+
+## Add definitions ##
+add_definitions(-DHAVE_CONFIG_H=1 -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
+
+## Add subdirectories ##
+add_subdirectory(pkgconfig)
+add_subdirectory(include)
+add_subdirectory(lib)
+if(BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif(BUILD_EXAMPLES)
+
+## Add 'uninstall' target ##
+CONFIGURE_FILE(
+ "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+ADD_CUSTOM_TARGET(uninstall
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake
new file mode 100644
index 000000000..58d3f99ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/AppendCompilerFlags.cmake
@@ -0,0 +1,38 @@
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+
+macro(append_c_compiler_flags _flags _name _result)
+ set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}")
+ string(TOUPPER "${cname}" cname)
+ foreach(flag ${_flags})
+ string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}")
+ string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${cname}_${flagname}")
+ set(CMAKE_REQUIRED_FLAGS "${flag}")
+ check_c_source_compiles("int main() { return 0; }" ${have_flag})
+ if(${have_flag})
+ set(${_result} "${${_result}} ${flag}")
+ endif(${have_flag})
+ endforeach(flag)
+ set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS})
+endmacro(append_c_compiler_flags)
+
+macro(append_cxx_compiler_flags _flags _name _result)
+ set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}")
+ string(TOUPPER "${cname}" cname)
+ foreach(flag ${_flags})
+ string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}")
+ string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${cname}_${flagname}")
+ set(CMAKE_REQUIRED_FLAGS "${flag}")
+ check_cxx_source_compiles("int main() { return 0; }" ${have_flag})
+ if(${have_flag})
+ set(${_result} "${${_result}} ${flag}")
+ endif(${have_flag})
+ endforeach(flag)
+ set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS})
+endmacro(append_cxx_compiler_flags)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake
new file mode 100644
index 000000000..44601fd4e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckFunctionKeywords.cmake
@@ -0,0 +1,15 @@
+include(CheckCSourceCompiles)
+
+macro(check_function_keywords _wordlist)
+ set(${_result} "")
+ foreach(flag ${_wordlist})
+ string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${flagname}")
+ check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag})
+ if(${have_flag} AND NOT ${_result})
+ set(${_result} "${flag}")
+# break()
+ endif(${have_flag} AND NOT ${_result})
+ endforeach(flag)
+endmacro(check_function_keywords)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckLFS.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckLFS.cmake
new file mode 100644
index 000000000..e2b009914
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/CheckLFS.cmake
@@ -0,0 +1,109 @@
+## Checks for large file support ##
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckTypeSize)
+
+macro(check_lfs _isenable)
+ set(LFS_OFF_T "")
+ set(LFS_FOPEN "")
+ set(LFS_FSEEK "")
+ set(LFS_FTELL "")
+ set(LFS_PRID "")
+
+ if(${_isenable})
+ set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ -D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64
+ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
+
+ check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
+ check_include_file("inttypes.h" HAVE_INTTYPES_H)
+ check_include_file("stddef.h" HAVE_STDDEF_H)
+ check_include_file("stdint.h" HAVE_STDINT_H)
+
+ # LFS type1: 8 <= sizeof(off_t), fseeko, ftello
+ check_type_size("off_t" SIZEOF_OFF_T)
+ if(SIZEOF_OFF_T GREATER 7)
+ check_symbol_exists("fseeko" "stdio.h" HAVE_FSEEKO)
+ check_symbol_exists("ftello" "stdio.h" HAVE_FTELLO)
+ if(HAVE_FSEEKO AND HAVE_FTELLO)
+ set(LFS_OFF_T "off_t")
+ set(LFS_FOPEN "fopen")
+ set(LFS_FSEEK "fseeko")
+ set(LFS_FTELL "ftello")
+ check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX)
+ if(HAVE_PRIDMAX)
+ set(LFS_PRID "PRIdMAX")
+ else(HAVE_PRIDMAX)
+ check_type_size("long" SIZEOF_LONG)
+ check_type_size("int" SIZEOF_INT)
+ if(SIZEOF_OFF_T GREATER SIZEOF_LONG)
+ set(LFS_PRID "\"lld\"")
+ elseif(SIZEOF_LONG GREATER SIZEOF_INT)
+ set(LFS_PRID "\"ld\"")
+ else(SIZEOF_OFF_T GREATER SIZEOF_LONG)
+ set(LFS_PRID "\"d\"")
+ endif(SIZEOF_OFF_T GREATER SIZEOF_LONG)
+ endif(HAVE_PRIDMAX)
+ endif(HAVE_FSEEKO AND HAVE_FTELLO)
+ endif(SIZEOF_OFF_T GREATER 7)
+
+ # LFS type2: 8 <= sizeof(off64_t), fopen64, fseeko64, ftello64
+ if(NOT LFS_OFF_T)
+ check_type_size("off64_t" SIZEOF_OFF64_T)
+ if(SIZEOF_OFF64_T GREATER 7)
+ check_symbol_exists("fopen64" "stdio.h" HAVE_FOPEN64)
+ check_symbol_exists("fseeko64" "stdio.h" HAVE_FSEEKO64)
+ check_symbol_exists("ftello64" "stdio.h" HAVE_FTELLO64)
+ if(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64)
+ set(LFS_OFF_T "off64_t")
+ set(LFS_FOPEN "fopen64")
+ set(LFS_FSEEK "fseeko64")
+ set(LFS_FTELL "ftello64")
+ check_symbol_exists("PRIdMAX" "inttypes.h" HAVE_PRIDMAX)
+ if(HAVE_PRIDMAX)
+ set(LFS_PRID "PRIdMAX")
+ else(HAVE_PRIDMAX)
+ check_type_size("long" SIZEOF_LONG)
+ check_type_size("int" SIZEOF_INT)
+ if(SIZEOF_OFF64_T GREATER SIZEOF_LONG)
+ set(LFS_PRID "\"lld\"")
+ elseif(SIZEOF_LONG GREATER SIZEOF_INT)
+ set(LFS_PRID "\"ld\"")
+ else(SIZEOF_OFF64_T GREATER SIZEOF_LONG)
+ set(LFS_PRID "\"d\"")
+ endif(SIZEOF_OFF64_T GREATER SIZEOF_LONG)
+ endif(HAVE_PRIDMAX)
+ endif(HAVE_FOPEN64 AND HAVE_FSEEKO64 AND HAVE_FTELLO64)
+ endif(SIZEOF_OFF64_T GREATER 7)
+ endif(NOT LFS_OFF_T)
+
+ # LFS type3: 8 <= sizeof(__int64), _fseeki64, _ftelli64
+ if(NOT LFS_OFF_T)
+ check_type_size("__int64" SIZEOF___INT64)
+ if(SIZEOF___INT64 GREATER 7)
+ check_symbol_exists("_fseeki64" "stdio.h" HAVE__FSEEKI64)
+ check_symbol_exists("_ftelli64" "stdio.h" HAVE__FTELLI64)
+ if(HAVE__FSEEKI64 AND HAVE__FTELLI64)
+ set(LFS_OFF_T "__int64")
+ set(LFS_FOPEN "fopen")
+ set(LFS_FSEEK "_fseeki64")
+ set(LFS_FTELL "_ftelli64")
+ set(LFS_PRID "\"I64d\"")
+ endif(HAVE__FSEEKI64 AND HAVE__FTELLI64)
+ endif(SIZEOF___INT64 GREATER 7)
+ endif(NOT LFS_OFF_T)
+
+ set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ endif(${_isenable})
+
+ if(NOT LFS_OFF_T)
+ ## not found
+ set(LFS_OFF_T "long")
+ set(LFS_FOPEN "fopen")
+ set(LFS_FSEEK "fseek")
+ set(LFS_FTELL "ftell")
+ set(LFS_PRID "\"ld\"")
+ endif(NOT LFS_OFF_T)
+
+endmacro(check_lfs)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/ProjectCPack.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/ProjectCPack.cmake
new file mode 100644
index 000000000..7c105f933
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/ProjectCPack.cmake
@@ -0,0 +1,38 @@
+# If the cmake version includes cpack, use it
+IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
+ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}")
+ SET(CPACK_PACKAGE_VENDOR "${PROJECT_VENDOR}")
+ SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+ SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+ SET(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
+ SET(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
+ SET(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
+# SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${PROJECT_VERSION}")
+ SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_FULL}")
+
+ IF(NOT DEFINED CPACK_SYSTEM_NAME)
+ SET(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
+ ENDIF(NOT DEFINED CPACK_SYSTEM_NAME)
+
+ IF(${CPACK_SYSTEM_NAME} MATCHES Windows)
+ IF(CMAKE_CL_64)
+ SET(CPACK_SYSTEM_NAME win64-${CMAKE_SYSTEM_PROCESSOR})
+ ELSE(CMAKE_CL_64)
+ SET(CPACK_SYSTEM_NAME win32-${CMAKE_SYSTEM_PROCESSOR})
+ ENDIF(CMAKE_CL_64)
+ ENDIF(${CPACK_SYSTEM_NAME} MATCHES Windows)
+
+ IF(NOT DEFINED CPACK_PACKAGE_FILE_NAME)
+ SET(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}-${CPACK_SYSTEM_NAME}")
+ ENDIF(NOT DEFINED CPACK_PACKAGE_FILE_NAME)
+
+ SET(CPACK_PACKAGE_CONTACT "${PROJECT_CONTACT}")
+ IF(UNIX)
+ SET(CPACK_STRIP_FILES "")
+ SET(CPACK_SOURCE_STRIP_FILES "")
+# SET(CPACK_PACKAGE_EXECUTABLES "ccmake" "CMake")
+ ENDIF(UNIX)
+ SET(CPACK_SOURCE_IGNORE_FILES "/CVS/" "/build/" "/\\\\.build/" "/\\\\.svn/" "~$")
+ # include CPack model once all variables are set
+ INCLUDE(CPack)
+ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in
new file mode 100644
index 000000000..8366a8353
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/CMakeModules/cmake_uninstall.cmake.in
@@ -0,0 +1,36 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+
+SET(NUM 0)
+FOREACH(file ${files})
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found")
+ SET(UNINSTALL_CHECK_${NUM} 1)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found")
+ SET(UNINSTALL_CHECK_${NUM} 0)
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ MATH(EXPR NUM "1 + ${NUM}")
+ENDFOREACH(file)
+
+SET(NUM 0)
+FOREACH(file ${files})
+ IF(${UNINSTALL_CHECK_${NUM}})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ENDIF(${UNINSTALL_CHECK_${NUM}})
+ MATH(EXPR NUM "1 + ${NUM}")
+ENDFOREACH(file)
+
+FILE(REMOVE "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/LICENSE b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/LICENSE
new file mode 100644
index 000000000..249efa49a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2003 Yuta Mori All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/README.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/README.md
new file mode 100644
index 000000000..381a18888
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/README.md
@@ -0,0 +1,140 @@
+# libdivsufsort
+
+libdivsufsort is a software library that implements a lightweight suffix array construction algorithm.
+
+## News
+* 2015-03-21: The project has moved from [Google Code](http://code.google.com/p/libdivsufsort/) to [GitHub](https://github.com/y-256/libdivsufsort)
+
+## Introduction
+This library provides a simple and an efficient C API to construct a suffix array and a Burrows-Wheeler transformed string from a given string over a constant-size alphabet.
+The algorithm runs in O(n log n) worst-case time using only 5n+O(1) bytes of memory space, where n is the length of
+the string.
+
+## Build requirements
+* An ANSI C Compiler (e.g. GNU GCC)
+* [CMake](http://www.cmake.org/ "CMake") version 2.4.2 or newer
+* CMake-supported build tool
+
+## Building on GNU/Linux
+1. Get the source code from GitHub. You can either
+ * use git to clone the repository
+ ```
+ git clone https://github.com/y-256/libdivsufsort.git
+ ```
+ * or download a [zip file](../../archive/master.zip) directly
+2. Create a `build` directory in the package source directory.
+```shell
+$ cd libdivsufsort
+$ mkdir build
+$ cd build
+```
+3. Configure the package for your system.
+If you want to install to a different location, change the -DCMAKE_INSTALL_PREFIX option.
+```shell
+$ cmake -DCMAKE_BUILD_TYPE="Release" \
+-DCMAKE_INSTALL_PREFIX="/usr/local" ..
+```
+4. Compile the package.
+```shell
+$ make
+```
+5. (Optional) Install the library and header files.
+```shell
+$ sudo make install
+```
+
+## API
+```c
+/* Data types */
+typedef int32_t saint_t;
+typedef int32_t saidx_t;
+typedef uint8_t sauchar_t;
+
+/*
+ * Constructs the suffix array of a given string.
+ * @param T[0..n-1] The input string.
+ * @param SA[0..n-1] The output array or suffixes.
+ * @param n The length of the given string.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+saint_t
+divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n);
+
+/*
+ * Constructs the burrows-wheeler transformed string of a given string.
+ * @param T[0..n-1] The input string.
+ * @param U[0..n-1] The output string. (can be T)
+ * @param A[0..n-1] The temporary array. (can be NULL)
+ * @param n The length of the given string.
+ * @return The primary index if no error occurred, -1 or -2 otherwise.
+ */
+saidx_t
+divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n);
+```
+
+## Example Usage
+```c
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <divsufsort.h>
+
+int main() {
+ // intput data
+ char *Text = "abracadabra";
+ int n = strlen(Text);
+ int i, j;
+
+ // allocate
+ int *SA = (int *)malloc(n * sizeof(int));
+
+ // sort
+ divsufsort((unsigned char *)Text, SA, n);
+
+ // output
+ for(i = 0; i < n; ++i) {
+ printf("SA[%2d] = %2d: ", i, SA[i]);
+ for(j = SA[i]; j < n; ++j) {
+ printf("%c", Text[j]);
+ }
+ printf("$\n");
+ }
+
+ // deallocate
+ free(SA);
+
+ return 0;
+}
+```
+See the [examples](examples) directory for a few other examples.
+
+## Benchmarks
+See [Benchmarks](https://github.com/y-256/libdivsufsort/blob/wiki/SACA_Benchmarks.md) page for details.
+
+## License
+libdivsufsort is released under the [MIT license](LICENSE "MIT license").
+> The MIT License (MIT)
+>
+> Copyright (c) 2003 Yuta Mori All rights reserved.
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in all
+> copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+> SOFTWARE.
+
+## Author
+* Yuta Mori
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/VERSION.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/VERSION.cmake
new file mode 100644
index 000000000..3f11ac18c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/VERSION.cmake
@@ -0,0 +1,23 @@
+set(PROJECT_VERSION_MAJOR "2")
+set(PROJECT_VERSION_MINOR "0")
+set(PROJECT_VERSION_PATCH "2")
+set(PROJECT_VERSION_EXTRA "-1")
+set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+set(PROJECT_VERSION_FULL "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_EXTRA}")
+
+set(LIBRARY_VERSION "3.0.1")
+set(LIBRARY_SOVERSION "3")
+
+## Git revision number ##
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")
+ execute_process(COMMAND git describe --tags HEAD
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ OUTPUT_VARIABLE GIT_DESCRIBE_TAGS ERROR_QUIET)
+ if(GIT_DESCRIBE_TAGS)
+ string(REGEX REPLACE "^v(.*)" "\\1" GIT_REVISION "${GIT_DESCRIBE_TAGS}")
+ string(STRIP "${GIT_REVISION}" GIT_REVISION)
+ if(GIT_REVISION)
+ set(PROJECT_VERSION_FULL "${GIT_REVISION}")
+ endif(GIT_REVISION)
+ endif(GIT_DESCRIBE_TAGS)
+endif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/CMakeLists.txt
new file mode 100644
index 000000000..e801c81a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/CMakeLists.txt
@@ -0,0 +1,11 @@
+## Add definitions ##
+add_definitions(-D_LARGEFILE_SOURCE -D_LARGE_FILES -D_FILE_OFFSET_BITS=64)
+
+## Targets ##
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include"
+ "${CMAKE_CURRENT_BINARY_DIR}/../include")
+link_directories("${CMAKE_CURRENT_BINARY_DIR}/../lib")
+foreach(src suftest mksary sasearch bwt unbwt)
+ add_executable(${src} ${src}.c)
+ target_link_libraries(${src} divsufsort)
+endforeach(src)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/bwt.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/bwt.c
new file mode 100644
index 000000000..5a362d017
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/bwt.c
@@ -0,0 +1,220 @@
+/*
+ * bwt.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_IO_H && HAVE_FCNTL_H
+# include <io.h>
+# include <fcntl.h>
+#endif
+#include <time.h>
+#include <divsufsort.h>
+#include "lfs.h"
+
+
+static
+size_t
+write_int(FILE *fp, saidx_t n) {
+ unsigned char c[4];
+ c[0] = (unsigned char)((n >> 0) & 0xff), c[1] = (unsigned char)((n >> 8) & 0xff),
+ c[2] = (unsigned char)((n >> 16) & 0xff), c[3] = (unsigned char)((n >> 24) & 0xff);
+ return fwrite(c, sizeof(unsigned char), 4, fp);
+}
+
+static
+void
+print_help(const char *progname, int status) {
+ fprintf(stderr,
+ "bwt, a burrows-wheeler transform program, version %s.\n",
+ divsufsort_version());
+ fprintf(stderr, "usage: %s [-b num] INFILE OUTFILE\n", progname);
+ fprintf(stderr, " -b num set block size to num MiB [1..512] (default: 32)\n\n");
+ exit(status);
+}
+
+int
+main(int argc, const char *argv[]) {
+ FILE *fp, *ofp;
+ const char *fname, *ofname;
+ sauchar_t *T;
+ saidx_t *SA;
+ LFS_OFF_T n;
+ size_t m;
+ saidx_t pidx;
+ clock_t start,finish;
+ saint_t i, blocksize = 32, needclose = 3;
+
+ /* Check arguments. */
+ if((argc == 1) ||
+ (strcmp(argv[1], "-h") == 0) ||
+ (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); }
+ if((argc != 3) && (argc != 5)) { print_help(argv[0], EXIT_FAILURE); }
+ i = 1;
+ if(argc == 5) {
+ if(strcmp(argv[i], "-b") != 0) { print_help(argv[0], EXIT_FAILURE); }
+ blocksize = atoi(argv[i + 1]);
+ if(blocksize < 0) { blocksize = 1; }
+ else if(512 < blocksize) { blocksize = 512; }
+ i += 2;
+ }
+ blocksize <<= 20;
+
+ /* Open a file for reading. */
+ if(strcmp(argv[i], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, fname = argv[i], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(fname = argv[i], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdin), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ fp = stdin;
+ fname = "stdin";
+ needclose ^= 1;
+ }
+ i += 1;
+
+ /* Open a file for writing. */
+ if(strcmp(argv[i], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&ofp, ofname = argv[i], "wb") != 0) {
+#else
+ if((ofp = LFS_FOPEN(ofname = argv[i], "wb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdout), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ ofp = stdout;
+ ofname = "stdout";
+ needclose ^= 2;
+ }
+
+ /* Get the file size. */
+ if(LFS_FSEEK(fp, 0, SEEK_END) == 0) {
+ n = LFS_FTELL(fp);
+ rewind(fp);
+ if(n < 0) {
+ fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(0x20000000L < n) { n = 0x20000000L; }
+ if((blocksize == 0) || (n < blocksize)) { blocksize = (saidx_t)n; }
+ } else if(blocksize == 0) { blocksize = 32 << 20; }
+
+ /* Allocate 5blocksize bytes of memory. */
+ T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t));
+ SA = (saidx_t *)malloc(blocksize * sizeof(saidx_t));
+ if((T == NULL) || (SA == NULL)) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Write the blocksize. */
+ if(write_int(ofp, blocksize) != 4) {
+ fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, " BWT (blocksize %" PRIdSAINT_T ") ... ", blocksize);
+ start = clock();
+ for(n = 0; 0 < (m = fread(T, sizeof(sauchar_t), blocksize, fp)); n += m) {
+ /* Burrows-Wheeler Transform. */
+ pidx = divbwt(T, T, SA, m);
+ if(pidx < 0) {
+ fprintf(stderr, "%s (bw_transform): %s.\n",
+ argv[0],
+ (pidx == -1) ? "Invalid arguments" : "Cannot allocate memory");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Write the bwted data. */
+ if((write_int(ofp, pidx) != 4) ||
+ (fwrite(T, sizeof(sauchar_t), m, ofp) != m)) {
+ fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if(ferror(fp)) {
+ fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ finish = clock();
+ fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n",
+ n, (double)(finish - start) / (double)CLOCKS_PER_SEC);
+
+ /* Close files */
+ if(needclose & 1) { fclose(fp); }
+ if(needclose & 2) { fclose(ofp); }
+
+ /* Deallocate memory. */
+ free(SA);
+ free(T);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/mksary.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/mksary.c
new file mode 100644
index 000000000..b48177cf8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/mksary.c
@@ -0,0 +1,193 @@
+/*
+ * mksary.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_IO_H && HAVE_FCNTL_H
+# include <io.h>
+# include <fcntl.h>
+#endif
+#include <time.h>
+#include <divsufsort.h>
+#include "lfs.h"
+
+
+static
+void
+print_help(const char *progname, int status) {
+ fprintf(stderr,
+ "mksary, a simple suffix array builder, version %s.\n",
+ divsufsort_version());
+ fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname);
+ exit(status);
+}
+
+int
+main(int argc, const char *argv[]) {
+ FILE *fp, *ofp;
+ const char *fname, *ofname;
+ sauchar_t *T;
+ saidx_t *SA;
+ LFS_OFF_T n;
+ clock_t start, finish;
+ saint_t needclose = 3;
+
+ /* Check arguments. */
+ if((argc == 1) ||
+ (strcmp(argv[1], "-h") == 0) ||
+ (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); }
+ if(argc != 3) { print_help(argv[0], EXIT_FAILURE); }
+
+ /* Open a file for reading. */
+ if(strcmp(argv[1], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, fname = argv[1], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdin), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ fp = stdin;
+ fname = "stdin";
+ needclose ^= 1;
+ }
+
+ /* Open a file for writing. */
+ if(strcmp(argv[2], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) {
+#else
+ if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdout), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ ofp = stdout;
+ ofname = "stdout";
+ needclose ^= 2;
+ }
+
+ /* Get the file size. */
+ if(LFS_FSEEK(fp, 0, SEEK_END) == 0) {
+ n = LFS_FTELL(fp);
+ rewind(fp);
+ if(n < 0) {
+ fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(0x7fffffff <= n) {
+ fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate 5blocksize bytes of memory. */
+ T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t));
+ SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t));
+ if((T == NULL) || (SA == NULL)) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read n bytes of data. */
+ if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) {
+ fprintf(stderr, "%s: %s `%s': ",
+ argv[0],
+ (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in",
+ fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(needclose & 1) { fclose(fp); }
+
+ /* Construct the suffix array. */
+ fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n);
+ start = clock();
+ if(divsufsort(T, SA, (saidx_t)n) != 0) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ finish = clock();
+ fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC);
+
+ /* Write the suffix array. */
+ if(fwrite(SA, sizeof(saidx_t), (size_t)n, ofp) != (size_t)n) {
+ fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(needclose & 2) { fclose(ofp); }
+
+ /* Deallocate memory. */
+ free(SA);
+ free(T);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/sasearch.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/sasearch.c
new file mode 100644
index 000000000..7e5ca4fe0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/sasearch.c
@@ -0,0 +1,165 @@
+/*
+ * sasearch.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_IO_H && HAVE_FCNTL_H
+# include <io.h>
+# include <fcntl.h>
+#endif
+#include <divsufsort.h>
+#include "lfs.h"
+
+
+static
+void
+print_help(const char *progname, int status) {
+ fprintf(stderr,
+ "sasearch, a simple SA-based full-text search tool, version %s\n",
+ divsufsort_version());
+ fprintf(stderr, "usage: %s PATTERN FILE SAFILE\n\n", progname);
+ exit(status);
+}
+
+int
+main(int argc, const char *argv[]) {
+ FILE *fp;
+ const char *P;
+ sauchar_t *T;
+ saidx_t *SA;
+ LFS_OFF_T n;
+ size_t Psize;
+ saidx_t i, size, left;
+
+ if((argc == 1) ||
+ (strcmp(argv[1], "-h") == 0) ||
+ (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); }
+ if(argc != 4) { print_help(argv[0], EXIT_FAILURE); }
+
+ P = argv[1];
+ Psize = strlen(P);
+
+ /* Open a file for reading. */
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, argv[2], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(argv[2], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[2]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the file size. */
+ if(LFS_FSEEK(fp, 0, SEEK_END) == 0) {
+ n = LFS_FTELL(fp);
+ rewind(fp);
+ if(n < 0) {
+ fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], argv[2]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], argv[2]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate 5n bytes of memory. */
+ T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t));
+ SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t));
+ if((T == NULL) || (SA == NULL)) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read n bytes of data. */
+ if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) {
+ fprintf(stderr, "%s: %s `%s': ",
+ argv[0],
+ (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in",
+ argv[2]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp);
+
+ /* Open the SA file for reading. */
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, argv[3], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(argv[3], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], argv[3]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read n * sizeof(saidx_t) bytes of data. */
+ if(fread(SA, sizeof(saidx_t), (size_t)n, fp) != (size_t)n) {
+ fprintf(stderr, "%s: %s `%s': ",
+ argv[0],
+ (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in",
+ argv[3]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp);
+
+ /* Search and print */
+ size = sa_search(T, (saidx_t)n,
+ (const sauchar_t *)P, (saidx_t)Psize,
+ SA, (saidx_t)n, &left);
+ for(i = 0; i < size; ++i) {
+ fprintf(stdout, "%" PRIdSAIDX_T "\n", SA[left + i]);
+ }
+
+ /* Deallocate memory. */
+ free(SA);
+ free(T);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/suftest.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/suftest.c
new file mode 100644
index 000000000..71892ac17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/suftest.c
@@ -0,0 +1,164 @@
+/*
+ * suftest.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_IO_H && HAVE_FCNTL_H
+# include <io.h>
+# include <fcntl.h>
+#endif
+#include <time.h>
+#include <divsufsort.h>
+#include "lfs.h"
+
+
+static
+void
+print_help(const char *progname, int status) {
+ fprintf(stderr,
+ "suftest, a suffixsort tester, version %s.\n",
+ divsufsort_version());
+ fprintf(stderr, "usage: %s FILE\n\n", progname);
+ exit(status);
+}
+
+int
+main(int argc, const char *argv[]) {
+ FILE *fp;
+ const char *fname;
+ sauchar_t *T;
+ saidx_t *SA;
+ LFS_OFF_T n;
+ clock_t start, finish;
+ saint_t needclose = 1;
+
+ /* Check arguments. */
+ if((argc == 1) ||
+ (strcmp(argv[1], "-h") == 0) ||
+ (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); }
+ if(argc != 2) { print_help(argv[0], EXIT_FAILURE); }
+
+ /* Open a file for reading. */
+ if(strcmp(argv[1], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, fname = argv[1], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdin), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ fp = stdin;
+ fname = "stdin";
+ needclose = 0;
+ }
+
+ /* Get the file size. */
+ if(LFS_FSEEK(fp, 0, SEEK_END) == 0) {
+ n = LFS_FTELL(fp);
+ rewind(fp);
+ if(n < 0) {
+ fprintf(stderr, "%s: Cannot ftell `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(0x7fffffff <= n) {
+ fprintf(stderr, "%s: Input file `%s' is too big.\n", argv[0], fname);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ fprintf(stderr, "%s: Cannot fseek `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate 5n bytes of memory. */
+ T = (sauchar_t *)malloc((size_t)n * sizeof(sauchar_t));
+ SA = (saidx_t *)malloc((size_t)n * sizeof(saidx_t));
+ if((T == NULL) || (SA == NULL)) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read n bytes of data. */
+ if(fread(T, sizeof(sauchar_t), (size_t)n, fp) != (size_t)n) {
+ fprintf(stderr, "%s: %s `%s': ",
+ argv[0],
+ (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in",
+ argv[1]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ if(needclose & 1) { fclose(fp); }
+
+ /* Construct the suffix array. */
+ fprintf(stderr, "%s: %" PRIdOFF_T " bytes ... ", fname, n);
+ start = clock();
+ if(divsufsort(T, SA, (saidx_t)n) != 0) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ finish = clock();
+ fprintf(stderr, "%.4f sec\n", (double)(finish - start) / (double)CLOCKS_PER_SEC);
+
+ /* Check the suffix array. */
+ if(sufcheck(T, SA, (saidx_t)n, 1) != 0) { exit(EXIT_FAILURE); }
+
+ /* Deallocate memory. */
+ free(SA);
+ free(T);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/unbwt.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/unbwt.c
new file mode 100644
index 000000000..c0f19e97a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/examples/unbwt.c
@@ -0,0 +1,207 @@
+/*
+ * unbwt.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_IO_H && HAVE_FCNTL_H
+# include <io.h>
+# include <fcntl.h>
+#endif
+#include <time.h>
+#include <divsufsort.h>
+#include "lfs.h"
+
+
+static
+size_t
+read_int(FILE *fp, saidx_t *n) {
+ unsigned char c[4];
+ size_t m = fread(c, sizeof(unsigned char), 4, fp);
+ if(m == 4) {
+ *n = (c[0] << 0) | (c[1] << 8) |
+ (c[2] << 16) | (c[3] << 24);
+ }
+ return m;
+}
+
+static
+void
+print_help(const char *progname, int status) {
+ fprintf(stderr,
+ "unbwt, an inverse burrows-wheeler transform program, version %s.\n",
+ divsufsort_version());
+ fprintf(stderr, "usage: %s INFILE OUTFILE\n\n", progname);
+ exit(status);
+}
+
+int
+main(int argc, const char *argv[]) {
+ FILE *fp, *ofp;
+ const char *fname, *ofname;
+ sauchar_t *T;
+ saidx_t *A;
+ LFS_OFF_T n;
+ size_t m;
+ saidx_t pidx;
+ clock_t start, finish;
+ saint_t err, blocksize, needclose = 3;
+
+ /* Check arguments. */
+ if((argc == 1) ||
+ (strcmp(argv[1], "-h") == 0) ||
+ (strcmp(argv[1], "--help") == 0)) { print_help(argv[0], EXIT_SUCCESS); }
+ if(argc != 3) { print_help(argv[0], EXIT_FAILURE); }
+
+ /* Open a file for reading. */
+ if(strcmp(argv[1], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&fp, fname = argv[1], "rb") != 0) {
+#else
+ if((fp = LFS_FOPEN(fname = argv[1], "rb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdin), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ fp = stdin;
+ fname = "stdin";
+ needclose ^= 1;
+ }
+
+ /* Open a file for writing. */
+ if(strcmp(argv[2], "-") != 0) {
+#if HAVE_FOPEN_S
+ if(fopen_s(&ofp, ofname = argv[2], "wb") != 0) {
+#else
+ if((ofp = LFS_FOPEN(ofname = argv[2], "wb")) == NULL) {
+#endif
+ fprintf(stderr, "%s: Cannot open file `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+#if HAVE__SETMODE && HAVE__FILENO
+ if(_setmode(_fileno(stdout), _O_BINARY) == -1) {
+ fprintf(stderr, "%s: Cannot set mode: ", argv[0]);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ ofp = stdout;
+ ofname = "stdout";
+ needclose ^= 2;
+ }
+
+ /* Read the blocksize. */
+ if(read_int(fp, &blocksize) != 4) {
+ fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate 5blocksize bytes of memory. */
+ T = (sauchar_t *)malloc(blocksize * sizeof(sauchar_t));
+ A = (saidx_t *)malloc(blocksize * sizeof(saidx_t));
+ if((T == NULL) || (A == NULL)) {
+ fprintf(stderr, "%s: Cannot allocate memory.\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, "UnBWT (blocksize %" PRIdSAINT_T ") ... ", blocksize);
+ start = clock();
+ for(n = 0; (m = read_int(fp, &pidx)) != 0; n += m) {
+ /* Read blocksize bytes of data. */
+ if((m != 4) || ((m = fread(T, sizeof(sauchar_t), blocksize, fp)) == 0)) {
+ fprintf(stderr, "%s: %s `%s': ",
+ argv[0],
+ (ferror(fp) || !feof(fp)) ? "Cannot read from" : "Unexpected EOF in",
+ fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Inverse Burrows-Wheeler Transform. */
+ if((err = inverse_bw_transform(T, T, A, m, pidx)) != 0) {
+ fprintf(stderr, "%s (reverseBWT): %s.\n",
+ argv[0],
+ (err == -1) ? "Invalid data" : "Cannot allocate memory");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Write m bytes of data. */
+ if(fwrite(T, sizeof(sauchar_t), m, ofp) != m) {
+ fprintf(stderr, "%s: Cannot write to `%s': ", argv[0], ofname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if(ferror(fp)) {
+ fprintf(stderr, "%s: Cannot read from `%s': ", argv[0], fname);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ finish = clock();
+ fprintf(stderr, "%" PRIdOFF_T " bytes: %.4f sec\n",
+ n, (double)(finish - start) / (double)CLOCKS_PER_SEC);
+
+ /* Close files */
+ if(needclose & 1) { fclose(fp); }
+ if(needclose & 2) { fclose(ofp); }
+
+ /* Deallocate memory. */
+ free(A);
+ free(T);
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/CMakeLists.txt
new file mode 100644
index 000000000..37781ccb3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/CMakeLists.txt
@@ -0,0 +1,162 @@
+include(CheckIncludeFiles)
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckTypeSize)
+include(CheckFunctionKeywords)
+include(CheckLFS)
+
+## Checks for header files ##
+check_include_file("inttypes.h" HAVE_INTTYPES_H)
+check_include_file("memory.h" HAVE_MEMORY_H)
+check_include_file("stddef.h" HAVE_STDDEF_H)
+check_include_file("stdint.h" HAVE_STDINT_H)
+check_include_file("stdlib.h" HAVE_STDLIB_H)
+check_include_file("string.h" HAVE_STRING_H)
+check_include_file("strings.h" HAVE_STRINGS_H)
+check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
+if(HAVE_INTTYPES_H)
+ set(INCFILE "#include <inttypes.h>")
+elseif(HAVE_STDINT_H)
+ set(INCFILE "#include <stdint.h>")
+else(HAVE_INTTYPES_H)
+ set(INCFILE "")
+endif(HAVE_INTTYPES_H)
+
+## create configuration files from .cmake file ##
+if(BUILD_EXAMPLES)
+ ## Checks for WinIO ##
+ if(WIN32)
+ check_include_file("io.h" HAVE_IO_H)
+ check_include_file("fcntl.h" HAVE_FCNTL_H)
+ check_symbol_exists("_setmode" "io.h;fcntl.h" HAVE__SETMODE)
+ if(NOT HAVE__SETMODE)
+ check_symbol_exists("setmode" "io.h;fcntl.h" HAVE_SETMODE)
+ endif(NOT HAVE__SETMODE)
+ check_symbol_exists("_fileno" "stdio.h" HAVE__FILENO)
+ check_symbol_exists("fopen_s" "stdio.h" HAVE_FOPEN_S)
+ check_symbol_exists("_O_BINARY" "fcntl.h" HAVE__O_BINARY)
+ endif(WIN32)
+
+ ## Checks for large file support ##
+ check_lfs(WITH_LFS)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lfs.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lfs.h" @ONLY)
+endif(BUILD_EXAMPLES)
+
+## generate config.h ##
+check_function_keywords("inline;__inline;__inline__;__declspec(dllexport);__declspec(dllimport)")
+if(HAVE_INLINE)
+ set(INLINE "inline")
+elseif(HAVE___INLINE)
+ set(INLINE "__inline")
+elseif(HAVE___INLINE__)
+ set(INLINE "__inline__")
+else(HAVE_INLINE)
+ set(INLINE "")
+endif(HAVE_INLINE)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h")
+
+## Checks for types ##
+# sauchar_t (8bit)
+check_type_size("uint8_t" UINT8_T)
+if(HAVE_UINT8_T)
+ set(SAUCHAR_TYPE "uint8_t")
+else(HAVE_UINT8_T)
+ check_type_size("unsigned char" SIZEOF_UNSIGNED_CHAR)
+ if("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1")
+ set(SAUCHAR_TYPE "unsigned char")
+ else("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1")
+ message(FATAL_ERROR "Cannot find unsigned 8-bit integer type")
+ endif("${SIZEOF_UNSIGNED_CHAR}" STREQUAL "1")
+endif(HAVE_UINT8_T)
+# saint_t (32bit)
+check_type_size("int32_t" INT32_T)
+if(HAVE_INT32_T)
+ set(SAINT32_TYPE "int32_t")
+ check_symbol_exists("PRId32" "inttypes.h" HAVE_PRID32)
+ if(HAVE_PRID32)
+ set(SAINT32_PRId "PRId32")
+ else(HAVE_PRID32)
+ set(SAINT32_PRId "\"d\"")
+ endif(HAVE_PRID32)
+else(HAVE_INT32_T)
+ check_type_size("int" SIZEOF_INT)
+ check_type_size("long" SIZEOF_LONG)
+ check_type_size("short" SIZEOF_SHORT)
+ check_type_size("__int32" SIZEOF___INT32)
+ if("${SIZEOF_INT}" STREQUAL "4")
+ set(SAINT32_TYPE "int")
+ set(SAINT32_PRId "\"d\"")
+ elseif("${SIZEOF_LONG}" STREQUAL "4")
+ set(SAINT32_TYPE "long")
+ set(SAINT32_PRId "\"ld\"")
+ elseif("${SIZEOF_SHORT}" STREQUAL "4")
+ set(SAINT32_TYPE "short")
+ set(SAINT32_PRId "\"d\"")
+ elseif("${SIZEOF___INT32}" STREQUAL "4")
+ set(SAINT32_TYPE "__int32")
+ set(SAINT32_PRId "\"d\"")
+ else("${SIZEOF_INT}" STREQUAL "4")
+ message(FATAL_ERROR "Cannot find 32-bit integer type")
+ endif("${SIZEOF_INT}" STREQUAL "4")
+endif(HAVE_INT32_T)
+# saint64_t (64bit)
+if(BUILD_DIVSUFSORT64)
+ check_type_size("int64_t" INT64_T)
+ if(HAVE_INT64_T)
+ set(SAINT64_TYPE "int64_t")
+ check_symbol_exists("PRId64" "inttypes.h" HAVE_PRID64)
+ if(HAVE_PRID64)
+ set(SAINT64_PRId "PRId64")
+ else(HAVE_PRID64)
+ set(SAINT64_PRId "\"lld\"")
+ endif(HAVE_PRID64)
+ else(HAVE_INT64_T)
+ check_type_size("int" SIZEOF_INT)
+ check_type_size("long" SIZEOF_LONG)
+ check_type_size("long long" SIZEOF_LONG_LONG)
+ check_type_size("__int64" SIZEOF___INT64)
+ if("${SIZEOF_INT}" STREQUAL "8")
+ set(SAINT64_TYPE "int")
+ set(SAINT64_PRId "\"d\"")
+ elseif("${SIZEOF_LONG}" STREQUAL "8")
+ set(SAINT64_TYPE "long")
+ set(SAINT64_PRId "\"ld\"")
+ elseif("${SIZEOF_LONG_LONG}" STREQUAL "8")
+ set(SAINT64_TYPE "long long")
+ set(SAINT64_PRId "\"lld\"")
+ elseif("${SIZEOF___INT64}" STREQUAL "8")
+ set(SAINT64_TYPE "__int64")
+ set(SAINT64_PRId "\"I64d\"")
+ else("${SIZEOF_INT}" STREQUAL "8")
+ message(SEND_ERROR "Cannot find 64-bit integer type")
+ set(BUILD_DIVSUFSORT64 OFF)
+ endif("${SIZEOF_INT}" STREQUAL "8")
+ endif(HAVE_INT64_T)
+endif(BUILD_DIVSUFSORT64)
+
+## generate divsufsort.h ##
+set(DIVSUFSORT_IMPORT "")
+set(DIVSUFSORT_EXPORT "")
+if(BUILD_SHARED_LIBS)
+ if(HAVE___DECLSPEC_DLLIMPORT_)
+ set(DIVSUFSORT_IMPORT "__declspec(dllimport)")
+ endif(HAVE___DECLSPEC_DLLIMPORT_)
+ if(HAVE___DECLSPEC_DLLEXPORT_)
+ set(DIVSUFSORT_EXPORT "__declspec(dllexport)")
+ endif(HAVE___DECLSPEC_DLLEXPORT_)
+endif(BUILD_SHARED_LIBS)
+set(W64BIT "")
+set(SAINDEX_TYPE "${SAINT32_TYPE}")
+set(SAINDEX_PRId "${SAINT32_PRId}")
+set(SAINT_PRId "${SAINT32_PRId}")
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+if(BUILD_DIVSUFSORT64)
+ set(W64BIT "64")
+ set(SAINDEX_TYPE "${SAINT64_TYPE}")
+ set(SAINDEX_PRId "${SAINT64_PRId}")
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/divsufsort.h.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" @ONLY)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/divsufsort64.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+endif(BUILD_DIVSUFSORT64)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/config.h.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/config.h.cmake
new file mode 100644
index 000000000..6a1cf47d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/config.h.cmake
@@ -0,0 +1,81 @@
+/*
+ * config.h for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** Define to the version of this package. **/
+#cmakedefine PROJECT_VERSION_FULL "${PROJECT_VERSION_FULL}"
+
+/** Define to 1 if you have the header files. **/
+#cmakedefine HAVE_INTTYPES_H 1
+#cmakedefine HAVE_STDDEF_H 1
+#cmakedefine HAVE_STDINT_H 1
+#cmakedefine HAVE_STDLIB_H 1
+#cmakedefine HAVE_STRING_H 1
+#cmakedefine HAVE_STRINGS_H 1
+#cmakedefine HAVE_MEMORY_H 1
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/** for WinIO **/
+#cmakedefine HAVE_IO_H 1
+#cmakedefine HAVE_FCNTL_H 1
+#cmakedefine HAVE__SETMODE 1
+#cmakedefine HAVE_SETMODE 1
+#cmakedefine HAVE__FILENO 1
+#cmakedefine HAVE_FOPEN_S 1
+#cmakedefine HAVE__O_BINARY 1
+#ifndef HAVE__SETMODE
+# if HAVE_SETMODE
+# define _setmode setmode
+# define HAVE__SETMODE 1
+# endif
+# if HAVE__SETMODE && !HAVE__O_BINARY
+# define _O_BINARY 0
+# define HAVE__O_BINARY 1
+# endif
+#endif
+
+/** for inline **/
+#ifndef INLINE
+# define INLINE @INLINE@
+#endif
+
+/** for VC++ warning **/
+#ifdef _MSC_VER
+#pragma warning(disable: 4127)
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _CONFIG_H */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort.h.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort.h.cmake
new file mode 100644
index 000000000..bcaba7c64
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort.h.cmake
@@ -0,0 +1,180 @@
+/*
+ * divsufsort@W64BIT@.h for libdivsufsort@W64BIT@
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DIVSUFSORT@W64BIT@_H
+#define _DIVSUFSORT@W64BIT@_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+@INCFILE@
+
+#ifndef DIVSUFSORT_API
+# ifdef DIVSUFSORT_BUILD_DLL
+# define DIVSUFSORT_API @DIVSUFSORT_EXPORT@
+# else
+# define DIVSUFSORT_API @DIVSUFSORT_IMPORT@
+# endif
+#endif
+
+/*- Datatypes -*/
+#ifndef SAUCHAR_T
+#define SAUCHAR_T
+typedef @SAUCHAR_TYPE@ sauchar_t;
+#endif /* SAUCHAR_T */
+#ifndef SAINT_T
+#define SAINT_T
+typedef @SAINT32_TYPE@ saint_t;
+#endif /* SAINT_T */
+#ifndef SAIDX@W64BIT@_T
+#define SAIDX@W64BIT@_T
+typedef @SAINDEX_TYPE@ saidx@W64BIT@_t;
+#endif /* SAIDX@W64BIT@_T */
+#ifndef PRIdSAINT_T
+#define PRIdSAINT_T @SAINT_PRId@
+#endif /* PRIdSAINT_T */
+#ifndef PRIdSAIDX@W64BIT@_T
+#define PRIdSAIDX@W64BIT@_T @SAINDEX_PRId@
+#endif /* PRIdSAIDX@W64BIT@_T */
+
+
+/*- Prototypes -*/
+
+/**
+ * Constructs the suffix array of a given string.
+ * @param T[0..n-1] The input string.
+ * @param SA[0..n-1] The output array of suffixes.
+ * @param n The length of the given string.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+DIVSUFSORT_API
+saint_t
+divsufsort@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t *SA, saidx@W64BIT@_t n);
+
+/**
+ * Constructs the burrows-wheeler transformed string of a given string.
+ * @param T[0..n-1] The input string.
+ * @param U[0..n-1] The output string. (can be T)
+ * @param A[0..n-1] The temporary array. (can be NULL)
+ * @param n The length of the given string.
+ * @return The primary index if no error occurred, -1 or -2 otherwise.
+ */
+DIVSUFSORT_API
+saidx@W64BIT@_t
+divbwt@W64BIT@(const sauchar_t *T, sauchar_t *U, saidx@W64BIT@_t *A, saidx@W64BIT@_t n);
+
+/**
+ * Returns the version of the divsufsort library.
+ * @return The version number string.
+ */
+DIVSUFSORT_API
+const char *
+divsufsort@W64BIT@_version(void);
+
+
+/**
+ * Constructs the burrows-wheeler transformed string of a given string and suffix array.
+ * @param T[0..n-1] The input string.
+ * @param U[0..n-1] The output string. (can be T)
+ * @param SA[0..n-1] The suffix array. (can be NULL)
+ * @param n The length of the given string.
+ * @param idx The output primary index.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+DIVSUFSORT_API
+saint_t
+bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U,
+ saidx@W64BIT@_t *SA /* can NULL */,
+ saidx@W64BIT@_t n, saidx@W64BIT@_t *idx);
+
+/**
+ * Inverse BW-transforms a given BWTed string.
+ * @param T[0..n-1] The input string.
+ * @param U[0..n-1] The output string. (can be T)
+ * @param A[0..n-1] The temporary array. (can be NULL)
+ * @param n The length of the given string.
+ * @param idx The primary index.
+ * @return 0 if no error occurred, -1 or -2 otherwise.
+ */
+DIVSUFSORT_API
+saint_t
+inverse_bw_transform@W64BIT@(const sauchar_t *T, sauchar_t *U,
+ saidx@W64BIT@_t *A /* can NULL */,
+ saidx@W64BIT@_t n, saidx@W64BIT@_t idx);
+
+/**
+ * Checks the correctness of a given suffix array.
+ * @param T[0..n-1] The input string.
+ * @param SA[0..n-1] The input suffix array.
+ * @param n The length of the given string.
+ * @param verbose The verbose mode.
+ * @return 0 if no error occurred.
+ */
+DIVSUFSORT_API
+saint_t
+sufcheck@W64BIT@(const sauchar_t *T, const saidx@W64BIT@_t *SA, saidx@W64BIT@_t n, saint_t verbose);
+
+/**
+ * Search for the pattern P in the string T.
+ * @param T[0..Tsize-1] The input string.
+ * @param Tsize The length of the given string.
+ * @param P[0..Psize-1] The input pattern string.
+ * @param Psize The length of the given pattern string.
+ * @param SA[0..SAsize-1] The input suffix array.
+ * @param SAsize The length of the given suffix array.
+ * @param idx The output index.
+ * @return The count of matches if no error occurred, -1 otherwise.
+ */
+DIVSUFSORT_API
+saidx@W64BIT@_t
+sa_search@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize,
+ const sauchar_t *P, saidx@W64BIT@_t Psize,
+ const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize,
+ saidx@W64BIT@_t *left);
+
+/**
+ * Search for the character c in the string T.
+ * @param T[0..Tsize-1] The input string.
+ * @param Tsize The length of the given string.
+ * @param SA[0..SAsize-1] The input suffix array.
+ * @param SAsize The length of the given suffix array.
+ * @param c The input character.
+ * @param idx The output index.
+ * @return The count of matches if no error occurred, -1 otherwise.
+ */
+DIVSUFSORT_API
+saidx@W64BIT@_t
+sa_simplesearch@W64BIT@(const sauchar_t *T, saidx@W64BIT@_t Tsize,
+ const saidx@W64BIT@_t *SA, saidx@W64BIT@_t SAsize,
+ saint_t c, saidx@W64BIT@_t *left);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _DIVSUFSORT@W64BIT@_H */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort_private.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort_private.h
new file mode 100644
index 000000000..7e261c19d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/divsufsort_private.h
@@ -0,0 +1,207 @@
+/*
+ * divsufsort_private.h for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DIVSUFSORT_PRIVATE_H
+#define _DIVSUFSORT_PRIVATE_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if defined(BUILD_DIVSUFSORT64)
+# include "divsufsort64.h"
+# ifndef SAIDX_T
+# define SAIDX_T
+# define saidx_t saidx64_t
+# endif /* SAIDX_T */
+# ifndef PRIdSAIDX_T
+# define PRIdSAIDX_T PRIdSAIDX64_T
+# endif /* PRIdSAIDX_T */
+# define divsufsort divsufsort64
+# define divbwt divbwt64
+# define divsufsort_version divsufsort64_version
+# define bw_transform bw_transform64
+# define inverse_bw_transform inverse_bw_transform64
+# define sufcheck sufcheck64
+# define sa_search sa_search64
+# define sa_simplesearch sa_simplesearch64
+# define sssort sssort64
+# define trsort trsort64
+#else
+# include "divsufsort.h"
+#endif
+
+
+/*- Constants -*/
+#if !defined(UINT8_MAX)
+# define UINT8_MAX (255)
+#endif /* UINT8_MAX */
+#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1)
+# undef ALPHABET_SIZE
+#endif
+#if !defined(ALPHABET_SIZE)
+# define ALPHABET_SIZE (UINT8_MAX + 1)
+#endif
+/* for divsufsort.c */
+#define BUCKET_A_SIZE (ALPHABET_SIZE)
+#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE)
+/* for sssort.c */
+#if defined(SS_INSERTIONSORT_THRESHOLD)
+# if SS_INSERTIONSORT_THRESHOLD < 1
+# undef SS_INSERTIONSORT_THRESHOLD
+# define SS_INSERTIONSORT_THRESHOLD (1)
+# endif
+#else
+# define SS_INSERTIONSORT_THRESHOLD (8)
+#endif
+#if defined(SS_BLOCKSIZE)
+# if SS_BLOCKSIZE < 0
+# undef SS_BLOCKSIZE
+# define SS_BLOCKSIZE (0)
+# elif 32768 <= SS_BLOCKSIZE
+# undef SS_BLOCKSIZE
+# define SS_BLOCKSIZE (32767)
+# endif
+#else
+# define SS_BLOCKSIZE (1024)
+#endif
+/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */
+#if SS_BLOCKSIZE == 0
+# if defined(BUILD_DIVSUFSORT64)
+# define SS_MISORT_STACKSIZE (96)
+# else
+# define SS_MISORT_STACKSIZE (64)
+# endif
+#elif SS_BLOCKSIZE <= 4096
+# define SS_MISORT_STACKSIZE (16)
+#else
+# define SS_MISORT_STACKSIZE (24)
+#endif
+#if defined(BUILD_DIVSUFSORT64)
+# define SS_SMERGE_STACKSIZE (64)
+#else
+# define SS_SMERGE_STACKSIZE (32)
+#endif
+/* for trsort.c */
+#define TR_INSERTIONSORT_THRESHOLD (8)
+#if defined(BUILD_DIVSUFSORT64)
+# define TR_STACKSIZE (96)
+#else
+# define TR_STACKSIZE (64)
+#endif
+
+
+/*- Macros -*/
+#ifndef SWAP
+# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0)
+#endif /* SWAP */
+#ifndef MIN
+# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif /* MIN */
+#ifndef MAX
+# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif /* MAX */
+#define STACK_PUSH(_a, _b, _c, _d)\
+ do {\
+ assert(ssize < STACK_SIZE);\
+ stack[ssize].a = (_a), stack[ssize].b = (_b),\
+ stack[ssize].c = (_c), stack[ssize++].d = (_d);\
+ } while(0)
+#define STACK_PUSH5(_a, _b, _c, _d, _e)\
+ do {\
+ assert(ssize < STACK_SIZE);\
+ stack[ssize].a = (_a), stack[ssize].b = (_b),\
+ stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\
+ } while(0)
+#define STACK_POP(_a, _b, _c, _d)\
+ do {\
+ assert(0 <= ssize);\
+ if(ssize == 0) { return; }\
+ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+ (_c) = stack[ssize].c, (_d) = stack[ssize].d;\
+ } while(0)
+#define STACK_POP5(_a, _b, _c, _d, _e)\
+ do {\
+ assert(0 <= ssize);\
+ if(ssize == 0) { return; }\
+ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\
+ (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\
+ } while(0)
+/* for divsufsort.c */
+#define BUCKET_A(_c0) bucket_A[(_c0)]
+#if ALPHABET_SIZE == 256
+#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)])
+#else
+#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)])
+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)])
+#endif
+
+
+/*- Private Prototypes -*/
+/* sssort.c */
+void
+sssort(const sauchar_t *Td, const saidx_t *PA,
+ saidx_t *first, saidx_t *last,
+ saidx_t *buf, saidx_t bufsize,
+ saidx_t depth, saidx_t n, saint_t lastsuffix);
+/* trsort.c */
+void
+trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _DIVSUFSORT_PRIVATE_H */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/lfs.h.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/lfs.h.cmake
new file mode 100644
index 000000000..d5b84a842
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/include/lfs.h.cmake
@@ -0,0 +1,56 @@
+/*
+ * lfs.h for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LFS_H
+#define _LFS_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef __STRICT_ANSI__
+# define LFS_OFF_T @LFS_OFF_T@
+# define LFS_FOPEN @LFS_FOPEN@
+# define LFS_FTELL @LFS_FTELL@
+# define LFS_FSEEK @LFS_FSEEK@
+# define LFS_PRId @LFS_PRID@
+#else
+# define LFS_OFF_T long
+# define LFS_FOPEN fopen
+# define LFS_FTELL ftell
+# define LFS_FSEEK fseek
+# define LFS_PRId "ld"
+#endif
+#ifndef PRIdOFF_T
+# define PRIdOFF_T LFS_PRId
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* _LFS_H */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/CMakeLists.txt
new file mode 100644
index 000000000..abc90e61d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/CMakeLists.txt
@@ -0,0 +1,31 @@
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include"
+ "${CMAKE_CURRENT_BINARY_DIR}/../include")
+
+set(divsufsort_SRCS divsufsort.c sssort.c trsort.c utils.c)
+
+## libdivsufsort ##
+add_library(divsufsort ${divsufsort_SRCS})
+install(TARGETS divsufsort
+ RUNTIME DESTINATION ${CMAKE_INSTALL_RUNTIMEDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+set_target_properties(divsufsort PROPERTIES
+ VERSION "${LIBRARY_VERSION}"
+ SOVERSION "${LIBRARY_SOVERSION}"
+ DEFINE_SYMBOL DIVSUFSORT_BUILD_DLL
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../examples")
+
+## libdivsufsort64 ##
+if(BUILD_DIVSUFSORT64)
+ add_library(divsufsort64 ${divsufsort_SRCS})
+ install(TARGETS divsufsort64
+ RUNTIME DESTINATION ${CMAKE_INSTALL_RUNTIMEDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ set_target_properties(divsufsort64 PROPERTIES
+ VERSION "${LIBRARY_VERSION}"
+ SOVERSION "${LIBRARY_SOVERSION}"
+ DEFINE_SYMBOL DIVSUFSORT_BUILD_DLL
+ COMPILE_FLAGS "-DBUILD_DIVSUFSORT64"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../examples")
+endif(BUILD_DIVSUFSORT64)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/divsufsort.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/divsufsort.c
new file mode 100644
index 000000000..9f64b4f48
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/divsufsort.c
@@ -0,0 +1,398 @@
+/*
+ * divsufsort.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "divsufsort_private.h"
+#ifdef _OPENMP
+# include <omp.h>
+#endif
+
+
+/*- Private Functions -*/
+
+/* Sorts suffixes of type B*. */
+static
+saidx_t
+sort_typeBstar(const sauchar_t *T, saidx_t *SA,
+ saidx_t *bucket_A, saidx_t *bucket_B,
+ saidx_t n) {
+ saidx_t *PAb, *ISAb, *buf;
+#ifdef _OPENMP
+ saidx_t *curbuf;
+ saidx_t l;
+#endif
+ saidx_t i, j, k, t, m, bufsize;
+ saint_t c0, c1;
+#ifdef _OPENMP
+ saint_t d0, d1;
+ int tmp;
+#endif
+
+ /* Initialize bucket arrays. */
+ for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; }
+ for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; }
+
+ /* Count the number of occurrences of the first one or two characters of each
+ type A, B and B* suffix. Moreover, store the beginning position of all
+ type B* suffixes into the array SA. */
+ for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) {
+ /* type A suffix. */
+ do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1));
+ if(0 <= i) {
+ /* type B* suffix. */
+ ++BUCKET_BSTAR(c0, c1);
+ SA[--m] = i;
+ /* type B suffix. */
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) {
+ ++BUCKET_B(c0, c1);
+ }
+ }
+ }
+ m = n - m;
+/*
+note:
+ A type B* suffix is lexicographically smaller than a type B suffix that
+ begins with the same first two characters.
+*/
+
+ /* Calculate the index of start/end point of each bucket. */
+ for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) {
+ t = i + BUCKET_A(c0);
+ BUCKET_A(c0) = i + j; /* start point */
+ i = t + BUCKET_B(c0, c0);
+ for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) {
+ j += BUCKET_BSTAR(c0, c1);
+ BUCKET_BSTAR(c0, c1) = j; /* end point */
+ i += BUCKET_B(c0, c1);
+ }
+ }
+
+ if(0 < m) {
+ /* Sort the type B* suffixes by their first two characters. */
+ PAb = SA + n - m; ISAb = SA + m;
+ for(i = m - 2; 0 <= i; --i) {
+ t = PAb[i], c0 = T[t], c1 = T[t + 1];
+ SA[--BUCKET_BSTAR(c0, c1)] = i;
+ }
+ t = PAb[m - 1], c0 = T[t], c1 = T[t + 1];
+ SA[--BUCKET_BSTAR(c0, c1)] = m - 1;
+
+ /* Sort the type B* substrings using sssort. */
+#ifdef _OPENMP
+ tmp = omp_get_max_threads();
+ buf = SA + m, bufsize = (n - (2 * m)) / tmp;
+ c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m;
+#pragma omp parallel default(shared) private(curbuf, k, l, d0, d1, tmp)
+ {
+ tmp = omp_get_thread_num();
+ curbuf = buf + tmp * bufsize;
+ k = 0;
+ for(;;) {
+ #pragma omp critical(sssort_lock)
+ {
+ if(0 < (l = j)) {
+ d0 = c0, d1 = c1;
+ do {
+ k = BUCKET_BSTAR(d0, d1);
+ if(--d1 <= d0) {
+ d1 = ALPHABET_SIZE - 1;
+ if(--d0 < 0) { break; }
+ }
+ } while(((l - k) <= 1) && (0 < (l = k)));
+ c0 = d0, c1 = d1, j = k;
+ }
+ }
+ if(l == 0) { break; }
+ sssort(T, PAb, SA + k, SA + l,
+ curbuf, bufsize, 2, n, *(SA + k) == (m - 1));
+ }
+ }
+#else
+ buf = SA + m, bufsize = n - (2 * m);
+ for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {
+ for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {
+ i = BUCKET_BSTAR(c0, c1);
+ if(1 < (j - i)) {
+ sssort(T, PAb, SA + i, SA + j,
+ buf, bufsize, 2, n, *(SA + i) == (m - 1));
+ }
+ }
+ }
+#endif
+
+ /* Compute ranks of type B* substrings. */
+ for(i = m - 1; 0 <= i; --i) {
+ if(0 <= SA[i]) {
+ j = i;
+ do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i]));
+ SA[i + 1] = i - j;
+ if(i <= 0) { break; }
+ }
+ j = i;
+ do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0);
+ ISAb[SA[i]] = j;
+ }
+
+ /* Construct the inverse suffix array of type B* suffixes using trsort. */
+ trsort(ISAb, SA, m, 1);
+
+ /* Set the sorted order of tyoe B* suffixes. */
+ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) {
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { }
+ if(0 <= i) {
+ t = i;
+ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { }
+ SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t;
+ }
+ }
+
+ /* Calculate the index of start/end point of each bucket. */
+ BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */
+ for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) {
+ i = BUCKET_A(c0 + 1) - 1;
+ for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) {
+ t = i - BUCKET_B(c0, c1);
+ BUCKET_B(c0, c1) = i; /* end point */
+
+ /* Move all type B* suffixes to the correct position. */
+ for(i = t, j = BUCKET_BSTAR(c0, c1);
+ j <= k;
+ --i, --k) { SA[i] = SA[k]; }
+ }
+ BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */
+ BUCKET_B(c0, c0) = i; /* end point */
+ }
+ }
+
+ return m;
+}
+
+/* Constructs the suffix array by using the sorted order of type B* suffixes. */
+static
+void
+construct_SA(const sauchar_t *T, saidx_t *SA,
+ saidx_t *bucket_A, saidx_t *bucket_B,
+ saidx_t n, saidx_t m) {
+ saidx_t *i, *j, *k;
+ saidx_t s;
+ saint_t c0, c1, c2;
+
+ if(0 < m) {
+ /* Construct the sorted order of type B suffixes by using
+ the sorted order of type B* suffixes. */
+ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+ /* Scan the suffix array from right to left. */
+ for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+ j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+ i <= j;
+ --j) {
+ if(0 < (s = *j)) {
+ assert(T[s] == c1);
+ assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+ assert(T[s - 1] <= T[s]);
+ *j = ~s;
+ c0 = T[--s];
+ if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+ if(c0 != c2) {
+ if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+ k = SA + BUCKET_B(c2 = c0, c1);
+ }
+ assert(k < j);
+ *k-- = s;
+ } else {
+ assert(((s == 0) && (T[s] == c1)) || (s < 0));
+ *j = ~s;
+ }
+ }
+ }
+ }
+
+ /* Construct the suffix array by using
+ the sorted order of type B suffixes. */
+ k = SA + BUCKET_A(c2 = T[n - 1]);
+ *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1);
+ /* Scan the suffix array from left to right. */
+ for(i = SA, j = SA + n; i < j; ++i) {
+ if(0 < (s = *i)) {
+ assert(T[s - 1] >= T[s]);
+ c0 = T[--s];
+ if((s == 0) || (T[s - 1] < c0)) { s = ~s; }
+ if(c0 != c2) {
+ BUCKET_A(c2) = k - SA;
+ k = SA + BUCKET_A(c2 = c0);
+ }
+ assert(i < k);
+ *k++ = s;
+ } else {
+ assert(s < 0);
+ *i = ~s;
+ }
+ }
+}
+
+/* Constructs the burrows-wheeler transformed string directly
+ by using the sorted order of type B* suffixes. */
+static
+saidx_t
+construct_BWT(const sauchar_t *T, saidx_t *SA,
+ saidx_t *bucket_A, saidx_t *bucket_B,
+ saidx_t n, saidx_t m) {
+ saidx_t *i, *j, *k, *orig;
+ saidx_t s;
+ saint_t c0, c1, c2;
+
+ if(0 < m) {
+ /* Construct the sorted order of type B suffixes by using
+ the sorted order of type B* suffixes. */
+ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {
+ /* Scan the suffix array from right to left. */
+ for(i = SA + BUCKET_BSTAR(c1, c1 + 1),
+ j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;
+ i <= j;
+ --j) {
+ if(0 < (s = *j)) {
+ assert(T[s] == c1);
+ assert(((s + 1) < n) && (T[s] <= T[s + 1]));
+ assert(T[s - 1] <= T[s]);
+ c0 = T[--s];
+ *j = ~((saidx_t)c0);
+ if((0 < s) && (T[s - 1] > c0)) { s = ~s; }
+ if(c0 != c2) {
+ if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }
+ k = SA + BUCKET_B(c2 = c0, c1);
+ }
+ assert(k < j);
+ *k-- = s;
+ } else if(s != 0) {
+ *j = ~s;
+#ifndef NDEBUG
+ } else {
+ assert(T[s] == c1);
+#endif
+ }
+ }
+ }
+ }
+
+ /* Construct the BWTed string by using
+ the sorted order of type B suffixes. */
+ k = SA + BUCKET_A(c2 = T[n - 1]);
+ *k++ = (T[n - 2] < c2) ? ~((saidx_t)T[n - 2]) : (n - 1);
+ /* Scan the suffix array from left to right. */
+ for(i = SA, j = SA + n, orig = SA; i < j; ++i) {
+ if(0 < (s = *i)) {
+ assert(T[s - 1] >= T[s]);
+ c0 = T[--s];
+ *i = c0;
+ if((0 < s) && (T[s - 1] < c0)) { s = ~((saidx_t)T[s - 1]); }
+ if(c0 != c2) {
+ BUCKET_A(c2) = k - SA;
+ k = SA + BUCKET_A(c2 = c0);
+ }
+ assert(i < k);
+ *k++ = s;
+ } else if(s != 0) {
+ *i = ~s;
+ } else {
+ orig = i;
+ }
+ }
+
+ return orig - SA;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/*- Function -*/
+
+saint_t
+divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n) {
+ saidx_t *bucket_A, *bucket_B;
+ saidx_t m;
+ saint_t err = 0;
+
+ /* Check arguments. */
+ if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; }
+ else if(n == 0) { return 0; }
+ else if(n == 1) { SA[0] = 0; return 0; }
+ else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; }
+
+ bucket_A = (saidx_t *)malloc(BUCKET_A_SIZE * sizeof(saidx_t));
+ bucket_B = (saidx_t *)malloc(BUCKET_B_SIZE * sizeof(saidx_t));
+
+ /* Suffixsort. */
+ if((bucket_A != NULL) && (bucket_B != NULL)) {
+ m = sort_typeBstar(T, SA, bucket_A, bucket_B, n);
+ construct_SA(T, SA, bucket_A, bucket_B, n, m);
+ } else {
+ err = -2;
+ }
+
+ free(bucket_B);
+ free(bucket_A);
+
+ return err;
+}
+
+saidx_t
+divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n) {
+ saidx_t *B;
+ saidx_t *bucket_A, *bucket_B;
+ saidx_t m, pidx, i;
+
+ /* Check arguments. */
+ if((T == NULL) || (U == NULL) || (n < 0)) { return -1; }
+ else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; }
+
+ if((B = A) == NULL) { B = (saidx_t *)malloc((size_t)(n + 1) * sizeof(saidx_t)); }
+ bucket_A = (saidx_t *)malloc(BUCKET_A_SIZE * sizeof(saidx_t));
+ bucket_B = (saidx_t *)malloc(BUCKET_B_SIZE * sizeof(saidx_t));
+
+ /* Burrows-Wheeler Transform. */
+ if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) {
+ m = sort_typeBstar(T, B, bucket_A, bucket_B, n);
+ pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m);
+
+ /* Copy to output string. */
+ U[0] = T[n - 1];
+ for(i = 0; i < pidx; ++i) { U[i + 1] = (sauchar_t)B[i]; }
+ for(i += 1; i < n; ++i) { U[i] = (sauchar_t)B[i]; }
+ pidx += 1;
+ } else {
+ pidx = -2;
+ }
+
+ free(bucket_B);
+ free(bucket_A);
+ if(A == NULL) { free(B); }
+
+ return pidx;
+}
+
+const char *
+divsufsort_version(void) {
+ return PROJECT_VERSION_FULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/sssort.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/sssort.c
new file mode 100644
index 000000000..4a18fd2ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/sssort.c
@@ -0,0 +1,815 @@
+/*
+ * sssort.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "divsufsort_private.h"
+
+
+/*- Private Functions -*/
+
+static const saint_t lg_table[256]= {
+ -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+saint_t
+ss_ilg(saidx_t n) {
+#if SS_BLOCKSIZE == 0
+# if defined(BUILD_DIVSUFSORT64)
+ return (n >> 32) ?
+ ((n >> 48) ?
+ ((n >> 56) ?
+ 56 + lg_table[(n >> 56) & 0xff] :
+ 48 + lg_table[(n >> 48) & 0xff]) :
+ ((n >> 40) ?
+ 40 + lg_table[(n >> 40) & 0xff] :
+ 32 + lg_table[(n >> 32) & 0xff])) :
+ ((n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]));
+# else
+ return (n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]);
+# endif
+#elif SS_BLOCKSIZE < 256
+ return lg_table[n];
+#else
+ return (n & 0xff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff];
+#endif
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+#if SS_BLOCKSIZE != 0
+
+static const saint_t sqq_table[256] = {
+ 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61,
+ 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89,
+ 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109,
+110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,
+156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
+169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,
+181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,
+192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,
+202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
+212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,
+221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,
+230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
+239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
+247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
+};
+
+static INLINE
+saidx_t
+ss_isqrt(saidx_t x) {
+ saidx_t y, e;
+
+ if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }
+ e = (x & 0xffff0000) ?
+ ((x & 0xff000000) ?
+ 24 + lg_table[(x >> 24) & 0xff] :
+ 16 + lg_table[(x >> 16) & 0xff]) :
+ ((x & 0x0000ff00) ?
+ 8 + lg_table[(x >> 8) & 0xff] :
+ 0 + lg_table[(x >> 0) & 0xff]);
+
+ if(e >= 16) {
+ y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);
+ if(e >= 24) { y = (y + 1 + x / y) >> 1; }
+ y = (y + 1 + x / y) >> 1;
+ } else if(e >= 8) {
+ y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;
+ } else {
+ return sqq_table[x] >> 4;
+ }
+
+ return (x < (y * y)) ? y - 1 : y;
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Compares two suffixes. */
+static INLINE
+saint_t
+ss_compare(const sauchar_t *T,
+ const saidx_t *p1, const saidx_t *p2,
+ saidx_t depth) {
+ const sauchar_t *U1, *U2, *U1n, *U2n;
+
+ for(U1 = T + depth + *p1,
+ U2 = T + depth + *p2,
+ U1n = T + *(p1 + 1) + 2,
+ U2n = T + *(p2 + 1) + 2;
+ (U1 < U1n) && (U2 < U2n) && (*U1 == *U2);
+ ++U1, ++U2) {
+ }
+
+ return U1 < U1n ?
+ (U2 < U2n ? *U1 - *U2 : 1) :
+ (U2 < U2n ? -1 : 0);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)
+
+/* Insertionsort for small size groups */
+static
+void
+ss_insertionsort(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *last, saidx_t depth) {
+ saidx_t *i, *j;
+ saidx_t t;
+ saint_t r;
+
+ for(i = last - 2; first <= i; --i) {
+ for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {
+ do { *(j - 1) = *j; } while((++j < last) && (*j < 0));
+ if(last <= j) { break; }
+ }
+ if(r == 0) { *j = ~*j; }
+ *(j - 1) = t;
+ }
+}
+
+#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
+
+static INLINE
+void
+ss_fixdown(const sauchar_t *Td, const saidx_t *PA,
+ saidx_t *SA, saidx_t i, saidx_t size) {
+ saidx_t j, k;
+ saidx_t v;
+ saint_t c, d, e;
+
+ for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+ d = Td[PA[SA[k = j++]]];
+ if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }
+ if(d <= c) { break; }
+ }
+ SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+ss_heapsort(const sauchar_t *Td, const saidx_t *PA, saidx_t *SA, saidx_t size) {
+ saidx_t i, m;
+ saidx_t t;
+
+ m = size;
+ if((size % 2) == 0) {
+ m--;
+ if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }
+ }
+
+ for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }
+ if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }
+ for(i = m - 1; 0 < i; --i) {
+ t = SA[0], SA[0] = SA[i];
+ ss_fixdown(Td, PA, SA, 0, i);
+ SA[i] = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+saidx_t *
+ss_median3(const sauchar_t *Td, const saidx_t *PA,
+ saidx_t *v1, saidx_t *v2, saidx_t *v3) {
+ saidx_t *t;
+ if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }
+ if(Td[PA[*v2]] > Td[PA[*v3]]) {
+ if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }
+ else { return v3; }
+ }
+ return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+saidx_t *
+ss_median5(const sauchar_t *Td, const saidx_t *PA,
+ saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) {
+ saidx_t *t;
+ if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }
+ if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }
+ if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }
+ if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }
+ if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }
+ if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }
+ return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+saidx_t *
+ss_pivot(const sauchar_t *Td, const saidx_t *PA, saidx_t *first, saidx_t *last) {
+ saidx_t *middle;
+ saidx_t t;
+
+ t = last - first;
+ middle = first + t / 2;
+
+ if(t <= 512) {
+ if(t <= 32) {
+ return ss_median3(Td, PA, first, middle, last - 1);
+ } else {
+ t >>= 2;
+ return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);
+ }
+ }
+ t >>= 3;
+ first = ss_median3(Td, PA, first, first + t, first + (t << 1));
+ middle = ss_median3(Td, PA, middle - t, middle, middle + t);
+ last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);
+ return ss_median3(Td, PA, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Binary partition for substrings. */
+static INLINE
+saidx_t *
+ss_partition(const saidx_t *PA,
+ saidx_t *first, saidx_t *last, saidx_t depth) {
+ saidx_t *a, *b;
+ saidx_t t;
+ for(a = first - 1, b = last;;) {
+ for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }
+ for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { }
+ if(b <= a) { break; }
+ t = ~*b;
+ *b = *a;
+ *a = t;
+ }
+ if(first < a) { *first = ~*first; }
+ return a;
+}
+
+/* Multikey introsort for medium size groups. */
+static
+void
+ss_mintrosort(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *last,
+ saidx_t depth) {
+#define STACK_SIZE SS_MISORT_STACKSIZE
+ struct { saidx_t *a, *b, c; saint_t d; } stack[STACK_SIZE];
+ const sauchar_t *Td;
+ saidx_t *a, *b, *c, *d, *e, *f;
+ saidx_t s, t;
+ saint_t ssize;
+ saint_t limit;
+ saint_t v, x = 0;
+
+ for(ssize = 0, limit = ss_ilg(last - first);;) {
+
+ if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {
+#if 1 < SS_INSERTIONSORT_THRESHOLD
+ if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }
+#endif
+ STACK_POP(first, last, depth, limit);
+ continue;
+ }
+
+ Td = T + depth;
+ if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }
+ if(limit < 0) {
+ for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {
+ if((x = Td[PA[*a]]) != v) {
+ if(1 < (a - first)) { break; }
+ v = x;
+ first = a;
+ }
+ }
+ if(Td[PA[*first] - 1] < v) {
+ first = ss_partition(PA, first, a, depth);
+ }
+ if((a - first) <= (last - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH(a, last, depth, -1);
+ last = a, depth += 1, limit = ss_ilg(a - first);
+ } else {
+ first = a, limit = -1;
+ }
+ } else {
+ if(1 < (last - a)) {
+ STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));
+ first = a, limit = -1;
+ } else {
+ last = a, depth += 1, limit = ss_ilg(a - first);
+ }
+ }
+ continue;
+ }
+
+ /* choose pivot */
+ a = ss_pivot(Td, PA, first, last);
+ v = Td[PA[*a]];
+ SWAP(*first, *a);
+
+ /* partition */
+ for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }
+ if(((a = b) < last) && (x < v)) {
+ for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ }
+ for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }
+ if((b < (d = c)) && (x > v)) {
+ for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+ for(; b < c;) {
+ SWAP(*b, *c);
+ for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+
+ if(a <= d) {
+ c = b - 1;
+
+ if((s = a - first) > (t = b - a)) { s = t; }
+ for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ if((s = d - c) > (t = last - d - 1)) { s = t; }
+ for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+
+ a = first + (b - a), c = last - (d - c);
+ b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);
+
+ if((a - first) <= (last - c)) {
+ if((last - c) <= (c - b)) {
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ STACK_PUSH(c, last, depth, limit);
+ last = a;
+ } else if((a - first) <= (c - b)) {
+ STACK_PUSH(c, last, depth, limit);
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ last = a;
+ } else {
+ STACK_PUSH(c, last, depth, limit);
+ STACK_PUSH(first, a, depth, limit);
+ first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+ }
+ } else {
+ if((a - first) <= (c - b)) {
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ STACK_PUSH(first, a, depth, limit);
+ first = c;
+ } else if((last - c) <= (c - b)) {
+ STACK_PUSH(first, a, depth, limit);
+ STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
+ first = c;
+ } else {
+ STACK_PUSH(first, a, depth, limit);
+ STACK_PUSH(c, last, depth, limit);
+ first = b, last = c, depth += 1, limit = ss_ilg(c - b);
+ }
+ }
+ } else {
+ limit += 1;
+ if(Td[PA[*first] - 1] < v) {
+ first = ss_partition(PA, first, last, depth);
+ limit = ss_ilg(last - first);
+ }
+ depth += 1;
+ }
+ }
+#undef STACK_SIZE
+}
+
+#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
+
+
+/*---------------------------------------------------------------------------*/
+
+#if SS_BLOCKSIZE != 0
+
+static INLINE
+void
+ss_blockswap(saidx_t *a, saidx_t *b, saidx_t n) {
+ saidx_t t;
+ for(; 0 < n; --n, ++a, ++b) {
+ t = *a, *a = *b, *b = t;
+ }
+}
+
+static INLINE
+void
+ss_rotate(saidx_t *first, saidx_t *middle, saidx_t *last) {
+ saidx_t *a, *b, t;
+ saidx_t l, r;
+ l = middle - first, r = last - middle;
+ for(; (0 < l) && (0 < r);) {
+ if(l == r) { ss_blockswap(first, middle, l); break; }
+ if(l < r) {
+ a = last - 1, b = middle - 1;
+ t = *a;
+ do {
+ *a-- = *b, *b-- = *a;
+ if(b < first) {
+ *a = t;
+ last = a;
+ if((r -= l + 1) <= l) { break; }
+ a -= 1, b = middle - 1;
+ t = *a;
+ }
+ } while(1);
+ } else {
+ a = first, b = middle;
+ t = *a;
+ do {
+ *a++ = *b, *b++ = *a;
+ if(last <= b) {
+ *a = t;
+ first = a + 1;
+ if((l -= r + 1) <= r) { break; }
+ a += 1, b = middle;
+ t = *a;
+ }
+ } while(1);
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static
+void
+ss_inplacemerge(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *middle, saidx_t *last,
+ saidx_t depth) {
+ const saidx_t *p;
+ saidx_t *a, *b;
+ saidx_t len, half;
+ saint_t q, r;
+ saint_t x;
+
+ for(;;) {
+ if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }
+ else { x = 0; p = PA + *(last - 1); }
+ for(a = first, len = middle - first, half = len >> 1, r = -1;
+ 0 < len;
+ len = half, half >>= 1) {
+ b = a + half;
+ q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);
+ if(q < 0) {
+ a = b + 1;
+ half -= (len & 1) ^ 1;
+ } else {
+ r = q;
+ }
+ }
+ if(a < middle) {
+ if(r == 0) { *a = ~*a; }
+ ss_rotate(a, middle, last);
+ last -= middle - a;
+ middle = a;
+ if(first == middle) { break; }
+ }
+ --last;
+ if(x != 0) { while(*--last < 0) { } }
+ if(middle == last) { break; }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Merge-forward with internal buffer. */
+static
+void
+ss_mergeforward(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *middle, saidx_t *last,
+ saidx_t *buf, saidx_t depth) {
+ saidx_t *a, *b, *c, *bufend;
+ saidx_t t;
+ saint_t r;
+
+ bufend = buf + (middle - first) - 1;
+ ss_blockswap(buf, first, middle - first);
+
+ for(t = *(a = first), b = buf, c = middle;;) {
+ r = ss_compare(T, PA + *b, PA + *c, depth);
+ if(r < 0) {
+ do {
+ *a++ = *b;
+ if(bufend <= b) { *bufend = t; return; }
+ *b++ = *a;
+ } while(*b < 0);
+ } else if(r > 0) {
+ do {
+ *a++ = *c, *c++ = *a;
+ if(last <= c) {
+ while(b < bufend) { *a++ = *b, *b++ = *a; }
+ *a = *b, *b = t;
+ return;
+ }
+ } while(*c < 0);
+ } else {
+ *c = ~*c;
+ do {
+ *a++ = *b;
+ if(bufend <= b) { *bufend = t; return; }
+ *b++ = *a;
+ } while(*b < 0);
+
+ do {
+ *a++ = *c, *c++ = *a;
+ if(last <= c) {
+ while(b < bufend) { *a++ = *b, *b++ = *a; }
+ *a = *b, *b = t;
+ return;
+ }
+ } while(*c < 0);
+ }
+ }
+}
+
+/* Merge-backward with internal buffer. */
+static
+void
+ss_mergebackward(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *middle, saidx_t *last,
+ saidx_t *buf, saidx_t depth) {
+ const saidx_t *p1, *p2;
+ saidx_t *a, *b, *c, *bufend;
+ saidx_t t;
+ saint_t r;
+ saint_t x;
+
+ bufend = buf + (last - middle) - 1;
+ ss_blockswap(buf, middle, last - middle);
+
+ x = 0;
+ if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; }
+ else { p1 = PA + *bufend; }
+ if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }
+ else { p2 = PA + *(middle - 1); }
+ for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {
+ r = ss_compare(T, p1, p2, depth);
+ if(0 < r) {
+ if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+ *a-- = *b;
+ if(b <= buf) { *buf = t; break; }
+ *b-- = *a;
+ if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+ else { p1 = PA + *b; }
+ } else if(r < 0) {
+ if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+ *a-- = *c, *c-- = *a;
+ if(c < first) {
+ while(buf < b) { *a-- = *b, *b-- = *a; }
+ *a = *b, *b = t;
+ break;
+ }
+ if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+ else { p2 = PA + *c; }
+ } else {
+ if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
+ *a-- = ~*b;
+ if(b <= buf) { *buf = t; break; }
+ *b-- = *a;
+ if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
+ *a-- = *c, *c-- = *a;
+ if(c < first) {
+ while(buf < b) { *a-- = *b, *b-- = *a; }
+ *a = *b, *b = t;
+ break;
+ }
+ if(*b < 0) { p1 = PA + ~*b; x |= 1; }
+ else { p1 = PA + *b; }
+ if(*c < 0) { p2 = PA + ~*c; x |= 2; }
+ else { p2 = PA + *c; }
+ }
+ }
+}
+
+/* D&C based merge. */
+static
+void
+ss_swapmerge(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *middle, saidx_t *last,
+ saidx_t *buf, saidx_t bufsize, saidx_t depth) {
+#define STACK_SIZE SS_SMERGE_STACKSIZE
+#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))
+#define MERGE_CHECK(a, b, c)\
+ do {\
+ if(((c) & 1) ||\
+ (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\
+ *(a) = ~*(a);\
+ }\
+ if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\
+ *(b) = ~*(b);\
+ }\
+ } while(0)
+ struct { saidx_t *a, *b, *c; saint_t d; } stack[STACK_SIZE];
+ saidx_t *l, *r, *lm, *rm;
+ saidx_t m, len, half;
+ saint_t ssize;
+ saint_t check, next;
+
+ for(check = 0, ssize = 0;;) {
+ if((last - middle) <= bufsize) {
+ if((first < middle) && (middle < last)) {
+ ss_mergebackward(T, PA, first, middle, last, buf, depth);
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ continue;
+ }
+
+ if((middle - first) <= bufsize) {
+ if(first < middle) {
+ ss_mergeforward(T, PA, first, middle, last, buf, depth);
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ continue;
+ }
+
+ for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;
+ 0 < len;
+ len = half, half >>= 1) {
+ if(ss_compare(T, PA + GETIDX(*(middle + m + half)),
+ PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {
+ m += half + 1;
+ half -= (len & 1) ^ 1;
+ }
+ }
+
+ if(0 < m) {
+ lm = middle - m, rm = middle + m;
+ ss_blockswap(lm, middle, m);
+ l = r = middle, next = 0;
+ if(rm < last) {
+ if(*rm < 0) {
+ *rm = ~*rm;
+ if(first < lm) { for(; *--l < 0;) { } next |= 4; }
+ next |= 1;
+ } else if(first < lm) {
+ for(; *r < 0; ++r) { }
+ next |= 2;
+ }
+ }
+
+ if((l - first) <= (last - r)) {
+ STACK_PUSH(r, rm, last, (next & 3) | (check & 4));
+ middle = lm, last = l, check = (check & 3) | (next & 4);
+ } else {
+ if((next & 2) && (r == middle)) { next ^= 6; }
+ STACK_PUSH(first, lm, l, (check & 3) | (next & 4));
+ first = r, middle = rm, check = (next & 3) | (check & 4);
+ }
+ } else {
+ if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {
+ *middle = ~*middle;
+ }
+ MERGE_CHECK(first, last, check);
+ STACK_POP(first, middle, last, check);
+ }
+ }
+#undef STACK_SIZE
+}
+
+#endif /* SS_BLOCKSIZE != 0 */
+
+
+/*---------------------------------------------------------------------------*/
+
+/*- Function -*/
+
+/* Substring sort */
+void
+sssort(const sauchar_t *T, const saidx_t *PA,
+ saidx_t *first, saidx_t *last,
+ saidx_t *buf, saidx_t bufsize,
+ saidx_t depth, saidx_t n, saint_t lastsuffix) {
+ saidx_t *a;
+#if SS_BLOCKSIZE != 0
+ saidx_t *b, *middle, *curbuf;
+ saidx_t j, k, curbufsize, limit;
+#endif
+ saidx_t i;
+
+ if(lastsuffix != 0) { ++first; }
+
+#if SS_BLOCKSIZE == 0
+ ss_mintrosort(T, PA, first, last, depth);
+#else
+ if((bufsize < SS_BLOCKSIZE) &&
+ (bufsize < (last - first)) &&
+ (bufsize < (limit = ss_isqrt(last - first)))) {
+ if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }
+ buf = middle = last - limit, bufsize = limit;
+ } else {
+ middle = last, limit = 0;
+ }
+ for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);
+#endif
+ curbufsize = last - (a + SS_BLOCKSIZE);
+ curbuf = a + SS_BLOCKSIZE;
+ if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }
+ for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {
+ ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);
+ }
+ }
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, a, middle, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, a, middle, depth);
+#endif
+ for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {
+ if(i & 1) {
+ ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);
+ a -= k;
+ }
+ }
+ if(limit != 0) {
+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
+ ss_mintrosort(T, PA, middle, last, depth);
+#elif 1 < SS_BLOCKSIZE
+ ss_insertionsort(T, PA, middle, last, depth);
+#endif
+ ss_inplacemerge(T, PA, first, middle, last, depth);
+ }
+#endif
+
+ if(lastsuffix != 0) {
+ /* Insert last type B* suffix. */
+ saidx_t PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;
+ for(a = first, i = *(first - 1);
+ (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));
+ ++a) {
+ *(a - 1) = *a;
+ }
+ *(a - 1) = i;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/trsort.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/trsort.c
new file mode 100644
index 000000000..6fe3e67ba
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/trsort.c
@@ -0,0 +1,586 @@
+/*
+ * trsort.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "divsufsort_private.h"
+
+
+/*- Private Functions -*/
+
+static const saint_t lg_table[256]= {
+ -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+static INLINE
+saint_t
+tr_ilg(saidx_t n) {
+#if defined(BUILD_DIVSUFSORT64)
+ return (n >> 32) ?
+ ((n >> 48) ?
+ ((n >> 56) ?
+ 56 + lg_table[(n >> 56) & 0xff] :
+ 48 + lg_table[(n >> 48) & 0xff]) :
+ ((n >> 40) ?
+ 40 + lg_table[(n >> 40) & 0xff] :
+ 32 + lg_table[(n >> 32) & 0xff])) :
+ ((n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]));
+#else
+ return (n & 0xffff0000) ?
+ ((n & 0xff000000) ?
+ 24 + lg_table[(n >> 24) & 0xff] :
+ 16 + lg_table[(n >> 16) & 0xff]) :
+ ((n & 0x0000ff00) ?
+ 8 + lg_table[(n >> 8) & 0xff] :
+ 0 + lg_table[(n >> 0) & 0xff]);
+#endif
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Simple insertionsort for small size groups. */
+static
+void
+tr_insertionsort(const saidx_t *ISAd, saidx_t *first, saidx_t *last) {
+ saidx_t *a, *b;
+ saidx_t t, r;
+
+ for(a = first + 1; a < last; ++a) {
+ for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) {
+ do { *(b + 1) = *b; } while((first <= --b) && (*b < 0));
+ if(b < first) { break; }
+ }
+ if(r == 0) { *b = ~*b; }
+ *(b + 1) = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_fixdown(const saidx_t *ISAd, saidx_t *SA, saidx_t i, saidx_t size) {
+ saidx_t j, k;
+ saidx_t v;
+ saidx_t c, d, e;
+
+ for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
+ d = ISAd[SA[k = j++]];
+ if(d < (e = ISAd[SA[j]])) { k = j; d = e; }
+ if(d <= c) { break; }
+ }
+ SA[i] = v;
+}
+
+/* Simple top-down heapsort. */
+static
+void
+tr_heapsort(const saidx_t *ISAd, saidx_t *SA, saidx_t size) {
+ saidx_t i, m;
+ saidx_t t;
+
+ m = size;
+ if((size % 2) == 0) {
+ m--;
+ if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); }
+ }
+
+ for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); }
+ if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); }
+ for(i = m - 1; 0 < i; --i) {
+ t = SA[0], SA[0] = SA[i];
+ tr_fixdown(ISAd, SA, 0, i);
+ SA[i] = t;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Returns the median of three elements. */
+static INLINE
+saidx_t *
+tr_median3(const saidx_t *ISAd, saidx_t *v1, saidx_t *v2, saidx_t *v3) {
+ saidx_t *t;
+ if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); }
+ if(ISAd[*v2] > ISAd[*v3]) {
+ if(ISAd[*v1] > ISAd[*v3]) { return v1; }
+ else { return v3; }
+ }
+ return v2;
+}
+
+/* Returns the median of five elements. */
+static INLINE
+saidx_t *
+tr_median5(const saidx_t *ISAd,
+ saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) {
+ saidx_t *t;
+ if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); }
+ if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); }
+ if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); }
+ if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); }
+ if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); }
+ if(ISAd[*v3] > ISAd[*v4]) { return v4; }
+ return v3;
+}
+
+/* Returns the pivot element. */
+static INLINE
+saidx_t *
+tr_pivot(const saidx_t *ISAd, saidx_t *first, saidx_t *last) {
+ saidx_t *middle;
+ saidx_t t;
+
+ t = last - first;
+ middle = first + t / 2;
+
+ if(t <= 512) {
+ if(t <= 32) {
+ return tr_median3(ISAd, first, middle, last - 1);
+ } else {
+ t >>= 2;
+ return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1);
+ }
+ }
+ t >>= 3;
+ first = tr_median3(ISAd, first, first + t, first + (t << 1));
+ middle = tr_median3(ISAd, middle - t, middle, middle + t);
+ last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1);
+ return tr_median3(ISAd, first, middle, last);
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _trbudget_t trbudget_t;
+struct _trbudget_t {
+ saidx_t chance;
+ saidx_t remain;
+ saidx_t incval;
+ saidx_t count;
+};
+
+static INLINE
+void
+trbudget_init(trbudget_t *budget, saidx_t chance, saidx_t incval) {
+ budget->chance = chance;
+ budget->remain = budget->incval = incval;
+}
+
+static INLINE
+saint_t
+trbudget_check(trbudget_t *budget, saidx_t size) {
+ if(size <= budget->remain) { budget->remain -= size; return 1; }
+ if(budget->chance == 0) { budget->count += size; return 0; }
+ budget->remain += budget->incval - size;
+ budget->chance -= 1;
+ return 1;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static INLINE
+void
+tr_partition(const saidx_t *ISAd,
+ saidx_t *first, saidx_t *middle, saidx_t *last,
+ saidx_t **pa, saidx_t **pb, saidx_t v) {
+ saidx_t *a, *b, *c, *d, *e, *f;
+ saidx_t t, s;
+ saidx_t x = 0;
+
+ for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { }
+ if(((a = b) < last) && (x < v)) {
+ for(; (++b < last) && ((x = ISAd[*b]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ }
+ for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { }
+ if((b < (d = c)) && (x > v)) {
+ for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+ for(; b < c;) {
+ SWAP(*b, *c);
+ for(; (++b < c) && ((x = ISAd[*b]) <= v);) {
+ if(x == v) { SWAP(*b, *a); ++a; }
+ }
+ for(; (b < --c) && ((x = ISAd[*c]) >= v);) {
+ if(x == v) { SWAP(*c, *d); --d; }
+ }
+ }
+
+ if(a <= d) {
+ c = b - 1;
+ if((s = a - first) > (t = b - a)) { s = t; }
+ for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ if((s = d - c) > (t = last - d - 1)) { s = t; }
+ for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
+ first += (b - a), last -= (d - c);
+ }
+ *pa = first, *pb = last;
+}
+
+static
+void
+tr_copy(saidx_t *ISA, const saidx_t *SA,
+ saidx_t *first, saidx_t *a, saidx_t *b, saidx_t *last,
+ saidx_t depth) {
+ /* sort suffixes of middle partition
+ by using sorted order of suffixes of left and right partition. */
+ saidx_t *c, *d, *e;
+ saidx_t s, v;
+
+ v = b - SA - 1;
+ for(c = first, d = a - 1; c <= d; ++c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *++d = s;
+ ISA[s] = d - SA;
+ }
+ }
+ for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *--d = s;
+ ISA[s] = d - SA;
+ }
+ }
+}
+
+static
+void
+tr_partialcopy(saidx_t *ISA, const saidx_t *SA,
+ saidx_t *first, saidx_t *a, saidx_t *b, saidx_t *last,
+ saidx_t depth) {
+ saidx_t *c, *d, *e;
+ saidx_t s, v;
+ saidx_t rank, lastrank, newrank = -1;
+
+ v = b - SA - 1;
+ lastrank = -1;
+ for(c = first, d = a - 1; c <= d; ++c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *++d = s;
+ rank = ISA[s + depth];
+ if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+ ISA[s] = newrank;
+ }
+ }
+
+ lastrank = -1;
+ for(e = d; first <= e; --e) {
+ rank = ISA[*e];
+ if(lastrank != rank) { lastrank = rank; newrank = e - SA; }
+ if(newrank != rank) { ISA[*e] = newrank; }
+ }
+
+ lastrank = -1;
+ for(c = last - 1, e = d + 1, d = b; e < d; --c) {
+ if((0 <= (s = *c - depth)) && (ISA[s] == v)) {
+ *--d = s;
+ rank = ISA[s + depth];
+ if(lastrank != rank) { lastrank = rank; newrank = d - SA; }
+ ISA[s] = newrank;
+ }
+ }
+}
+
+static
+void
+tr_introsort(saidx_t *ISA, const saidx_t *ISAd,
+ saidx_t *SA, saidx_t *first, saidx_t *last,
+ trbudget_t *budget) {
+#define STACK_SIZE TR_STACKSIZE
+ struct { const saidx_t *a; saidx_t *b, *c; saint_t d, e; }stack[STACK_SIZE];
+ saidx_t *a, *b, *c;
+ saidx_t t;
+ saidx_t v, x = 0;
+ saidx_t incr = ISAd - ISA;
+ saint_t limit, next;
+ saint_t ssize, trlink = -1;
+
+ for(ssize = 0, limit = tr_ilg(last - first);;) {
+
+ if(limit < 0) {
+ if(limit == -1) {
+ /* tandem repeat partition */
+ tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1);
+
+ /* update ranks */
+ if(a < last) {
+ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+ }
+ if(b < last) {
+ for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; }
+ }
+
+ /* push */
+ if(1 < (b - a)) {
+ STACK_PUSH5(NULL, a, b, 0, 0);
+ STACK_PUSH5(ISAd - incr, first, last, -2, trlink);
+ trlink = ssize - 2;
+ }
+ if((a - first) <= (last - b)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink);
+ last = a, limit = tr_ilg(a - first);
+ } else if(1 < (last - b)) {
+ first = b, limit = tr_ilg(last - b);
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ } else {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink);
+ first = b, limit = tr_ilg(last - b);
+ } else if(1 < (a - first)) {
+ last = a, limit = tr_ilg(a - first);
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ } else if(limit == -2) {
+ /* tandem repeat copy */
+ a = stack[--ssize].b, b = stack[ssize].c;
+ if(stack[ssize].d == 0) {
+ tr_copy(ISA, SA, first, a, b, last, ISAd - ISA);
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA);
+ }
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ } else {
+ /* sorted partition */
+ if(0 <= *first) {
+ a = first;
+ do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a));
+ first = a;
+ }
+ if(first < last) {
+ a = first; do { *a = ~*a; } while(*++a < 0);
+ next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1;
+ if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } }
+
+ /* push */
+ if(trbudget_check(budget, a - first)) {
+ if((a - first) <= (last - a)) {
+ STACK_PUSH5(ISAd, a, last, -3, trlink);
+ ISAd += incr, last = a, limit = next;
+ } else {
+ if(1 < (last - a)) {
+ STACK_PUSH5(ISAd + incr, first, a, next, trlink);
+ first = a, limit = -3;
+ } else {
+ ISAd += incr, last = a, limit = next;
+ }
+ }
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ if(1 < (last - a)) {
+ first = a, limit = -3;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ continue;
+ }
+
+ if((last - first) <= TR_INSERTIONSORT_THRESHOLD) {
+ tr_insertionsort(ISAd, first, last);
+ limit = -3;
+ continue;
+ }
+
+ if(limit-- == 0) {
+ tr_heapsort(ISAd, first, last - first);
+ for(a = last - 1; first < a; a = b) {
+ for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; }
+ }
+ limit = -3;
+ continue;
+ }
+
+ /* choose pivot */
+ a = tr_pivot(ISAd, first, last);
+ SWAP(*first, *a);
+ v = ISAd[*first];
+
+ /* partition */
+ tr_partition(ISAd, first, first + 1, last, &a, &b, v);
+ if((last - first) != (b - a)) {
+ next = (ISA[*a] != v) ? tr_ilg(b - a) : -1;
+
+ /* update ranks */
+ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }
+ if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } }
+
+ /* push */
+ if((1 < (b - a)) && (trbudget_check(budget, b - a))) {
+ if((a - first) <= (last - b)) {
+ if((last - b) <= (b - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ last = a;
+ } else if(1 < (last - b)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ first = b;
+ } else {
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else if((a - first) <= (b - a)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ last = a;
+ } else {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ if((a - first) <= (b - a)) {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ first = b;
+ } else if(1 < (a - first)) {
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ last = a;
+ } else {
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else if((last - b) <= (b - a)) {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ STACK_PUSH5(ISAd + incr, a, b, next, trlink);
+ first = b;
+ } else {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ } else {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ ISAd += incr, first = a, last = b, limit = next;
+ }
+ }
+ } else {
+ if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; }
+ if((a - first) <= (last - b)) {
+ if(1 < (a - first)) {
+ STACK_PUSH5(ISAd, b, last, limit, trlink);
+ last = a;
+ } else if(1 < (last - b)) {
+ first = b;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ } else {
+ if(1 < (last - b)) {
+ STACK_PUSH5(ISAd, first, a, limit, trlink);
+ first = b;
+ } else if(1 < (a - first)) {
+ last = a;
+ } else {
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ }
+ } else {
+ if(trbudget_check(budget, last - first)) {
+ limit = tr_ilg(last - first), ISAd += incr;
+ } else {
+ if(0 <= trlink) { stack[trlink].d = -1; }
+ STACK_POP5(ISAd, first, last, limit, trlink);
+ }
+ }
+ }
+#undef STACK_SIZE
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+
+/*- Function -*/
+
+/* Tandem repeat sort */
+void
+trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth) {
+ saidx_t *ISAd;
+ saidx_t *first, *last;
+ trbudget_t budget;
+ saidx_t t, skip, unsorted;
+
+ trbudget_init(&budget, tr_ilg(n) * 2 / 3, n);
+/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */
+ for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) {
+ first = SA;
+ skip = 0;
+ unsorted = 0;
+ do {
+ if((t = *first) < 0) { first -= t; skip += t; }
+ else {
+ if(skip != 0) { *(first + skip) = skip; skip = 0; }
+ last = SA + ISA[t] + 1;
+ if(1 < (last - first)) {
+ budget.count = 0;
+ tr_introsort(ISA, ISAd, SA, first, last, &budget);
+ if(budget.count != 0) { unsorted += budget.count; }
+ else { skip = first - last; }
+ } else if((last - first) == 1) {
+ skip = -1;
+ }
+ first = last;
+ }
+ } while(first < (SA + n));
+ if(skip != 0) { *(first + skip) = skip; }
+ if(unsorted == 0) { break; }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/utils.c b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/utils.c
new file mode 100644
index 000000000..90fb23efa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/lib/utils.c
@@ -0,0 +1,381 @@
+/*
+ * utils.c for libdivsufsort
+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "divsufsort_private.h"
+
+
+/*- Private Function -*/
+
+/* Binary search for inverse bwt. */
+static
+saidx_t
+binarysearch_lower(const saidx_t *A, saidx_t size, saidx_t value) {
+ saidx_t half, i;
+ for(i = 0, half = size >> 1;
+ 0 < size;
+ size = half, half >>= 1) {
+ if(A[i + half] < value) {
+ i += half + 1;
+ half -= (size & 1) ^ 1;
+ }
+ }
+ return i;
+}
+
+
+/*- Functions -*/
+
+/* Burrows-Wheeler transform. */
+saint_t
+bw_transform(const sauchar_t *T, sauchar_t *U, saidx_t *SA,
+ saidx_t n, saidx_t *idx) {
+ saidx_t *A, i, j, p, t;
+ saint_t c;
+
+ /* Check arguments. */
+ if((T == NULL) || (U == NULL) || (n < 0) || (idx == NULL)) { return -1; }
+ if(n <= 1) {
+ if(n == 1) { U[0] = T[0]; }
+ *idx = n;
+ return 0;
+ }
+
+ if((A = SA) == NULL) {
+ i = divbwt(T, U, NULL, n);
+ if(0 <= i) { *idx = i; i = 0; }
+ return (saint_t)i;
+ }
+
+ /* BW transform. */
+ if(T == U) {
+ t = n;
+ for(i = 0, j = 0; i < n; ++i) {
+ p = t - 1;
+ t = A[i];
+ if(0 <= p) {
+ c = T[j];
+ U[j] = (j <= p) ? T[p] : (sauchar_t)A[p];
+ A[j] = c;
+ j++;
+ } else {
+ *idx = i;
+ }
+ }
+ p = t - 1;
+ if(0 <= p) {
+ c = T[j];
+ U[j] = (j <= p) ? T[p] : (sauchar_t)A[p];
+ A[j] = c;
+ } else {
+ *idx = i;
+ }
+ } else {
+ U[0] = T[n - 1];
+ for(i = 0; A[i] != 0; ++i) { U[i + 1] = T[A[i] - 1]; }
+ *idx = i + 1;
+ for(++i; i < n; ++i) { U[i] = T[A[i] - 1]; }
+ }
+
+ if(SA == NULL) {
+ /* Deallocate memory. */
+ free(A);
+ }
+
+ return 0;
+}
+
+/* Inverse Burrows-Wheeler transform. */
+saint_t
+inverse_bw_transform(const sauchar_t *T, sauchar_t *U, saidx_t *A,
+ saidx_t n, saidx_t idx) {
+ saidx_t C[ALPHABET_SIZE];
+ sauchar_t D[ALPHABET_SIZE];
+ saidx_t *B;
+ saidx_t i, p;
+ saint_t c, d;
+
+ /* Check arguments. */
+ if((T == NULL) || (U == NULL) || (n < 0) || (idx < 0) ||
+ (n < idx) || ((0 < n) && (idx == 0))) {
+ return -1;
+ }
+ if(n <= 1) { return 0; }
+
+ if((B = A) == NULL) {
+ /* Allocate n*sizeof(saidx_t) bytes of memory. */
+ if((B = (saidx_t *)malloc((size_t)n * sizeof(saidx_t))) == NULL) { return -2; }
+ }
+
+ /* Inverse BW transform. */
+ for(c = 0; c < ALPHABET_SIZE; ++c) { C[c] = 0; }
+ for(i = 0; i < n; ++i) { ++C[T[i]]; }
+ for(c = 0, d = 0, i = 0; c < ALPHABET_SIZE; ++c) {
+ p = C[c];
+ if(0 < p) {
+ C[c] = i;
+ D[d++] = (sauchar_t)c;
+ i += p;
+ }
+ }
+ for(i = 0; i < idx; ++i) { B[C[T[i]]++] = i; }
+ for( ; i < n; ++i) { B[C[T[i]]++] = i + 1; }
+ for(c = 0; c < d; ++c) { C[c] = C[D[c]]; }
+ for(i = 0, p = idx; i < n; ++i) {
+ U[i] = D[binarysearch_lower(C, d, p)];
+ p = B[p - 1];
+ }
+
+ if(A == NULL) {
+ /* Deallocate memory. */
+ free(B);
+ }
+
+ return 0;
+}
+
+/* Checks the suffix array SA of the string T. */
+saint_t
+sufcheck(const sauchar_t *T, const saidx_t *SA,
+ saidx_t n, saint_t verbose) {
+ saidx_t C[ALPHABET_SIZE];
+ saidx_t i, p, q, t;
+ saint_t c;
+
+ if(verbose) { fprintf(stderr, "sufcheck: "); }
+
+ /* Check arguments. */
+ if((T == NULL) || (SA == NULL) || (n < 0)) {
+ if(verbose) { fprintf(stderr, "Invalid arguments.\n"); }
+ return -1;
+ }
+ if(n == 0) {
+ if(verbose) { fprintf(stderr, "Done.\n"); }
+ return 0;
+ }
+
+ /* check range: [0..n-1] */
+ for(i = 0; i < n; ++i) {
+ if((SA[i] < 0) || (n <= SA[i])) {
+ if(verbose) {
+ fprintf(stderr, "Out of the range [0,%" PRIdSAIDX_T "].\n"
+ " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "\n",
+ n - 1, i, SA[i]);
+ }
+ return -2;
+ }
+ }
+
+ /* check first characters. */
+ for(i = 1; i < n; ++i) {
+ if(T[SA[i - 1]] > T[SA[i]]) {
+ if(verbose) {
+ fprintf(stderr, "Suffixes in wrong order.\n"
+ " T[SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "]=%d"
+ " > T[SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "]=%d\n",
+ i - 1, SA[i - 1], T[SA[i - 1]], i, SA[i], T[SA[i]]);
+ }
+ return -3;
+ }
+ }
+
+ /* check suffixes. */
+ for(i = 0; i < ALPHABET_SIZE; ++i) { C[i] = 0; }
+ for(i = 0; i < n; ++i) { ++C[T[i]]; }
+ for(i = 0, p = 0; i < ALPHABET_SIZE; ++i) {
+ t = C[i];
+ C[i] = p;
+ p += t;
+ }
+
+ q = C[T[n - 1]];
+ C[T[n - 1]] += 1;
+ for(i = 0; i < n; ++i) {
+ p = SA[i];
+ if(0 < p) {
+ c = T[--p];
+ t = C[c];
+ } else {
+ c = T[p = n - 1];
+ t = q;
+ }
+ if((t < 0) || (p != SA[t])) {
+ if(verbose) {
+ fprintf(stderr, "Suffix in wrong position.\n"
+ " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T " or\n"
+ " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "\n",
+ t, (0 <= t) ? SA[t] : -1, i, SA[i]);
+ }
+ return -4;
+ }
+ if(t != q) {
+ ++C[c];
+ if((n <= C[c]) || (T[SA[C[c]]] != c)) { C[c] = -1; }
+ }
+ }
+
+ if(1 <= verbose) { fprintf(stderr, "Done.\n"); }
+ return 0;
+}
+
+
+static
+int
+_compare(const sauchar_t *T, saidx_t Tsize,
+ const sauchar_t *P, saidx_t Psize,
+ saidx_t suf, saidx_t *match) {
+ saidx_t i, j;
+ saint_t r;
+ for(i = suf + *match, j = *match, r = 0;
+ (i < Tsize) && (j < Psize) && ((r = T[i] - P[j]) == 0); ++i, ++j) { }
+ *match = j;
+ return (r == 0) ? -(j != Psize) : r;
+}
+
+/* Search for the pattern P in the string T. */
+saidx_t
+sa_search(const sauchar_t *T, saidx_t Tsize,
+ const sauchar_t *P, saidx_t Psize,
+ const saidx_t *SA, saidx_t SAsize,
+ saidx_t *idx) {
+ saidx_t size, lsize, rsize, half;
+ saidx_t match, lmatch, rmatch;
+ saidx_t llmatch, lrmatch, rlmatch, rrmatch;
+ saidx_t i, j, k;
+ saint_t r;
+
+ if(idx != NULL) { *idx = -1; }
+ if((T == NULL) || (P == NULL) || (SA == NULL) ||
+ (Tsize < 0) || (Psize < 0) || (SAsize < 0)) { return -1; }
+ if((Tsize == 0) || (SAsize == 0)) { return 0; }
+ if(Psize == 0) { if(idx != NULL) { *idx = 0; } return SAsize; }
+
+ for(i = j = k = 0, lmatch = rmatch = 0, size = SAsize, half = size >> 1;
+ 0 < size;
+ size = half, half >>= 1) {
+ match = MIN(lmatch, rmatch);
+ r = _compare(T, Tsize, P, Psize, SA[i + half], &match);
+ if(r < 0) {
+ i += half + 1;
+ half -= (size & 1) ^ 1;
+ lmatch = match;
+ } else if(r > 0) {
+ rmatch = match;
+ } else {
+ lsize = half, j = i, rsize = size - half - 1, k = i + half + 1;
+
+ /* left part */
+ for(llmatch = lmatch, lrmatch = match, half = lsize >> 1;
+ 0 < lsize;
+ lsize = half, half >>= 1) {
+ lmatch = MIN(llmatch, lrmatch);
+ r = _compare(T, Tsize, P, Psize, SA[j + half], &lmatch);
+ if(r < 0) {
+ j += half + 1;
+ half -= (lsize & 1) ^ 1;
+ llmatch = lmatch;
+ } else {
+ lrmatch = lmatch;
+ }
+ }
+
+ /* right part */
+ for(rlmatch = match, rrmatch = rmatch, half = rsize >> 1;
+ 0 < rsize;
+ rsize = half, half >>= 1) {
+ rmatch = MIN(rlmatch, rrmatch);
+ r = _compare(T, Tsize, P, Psize, SA[k + half], &rmatch);
+ if(r <= 0) {
+ k += half + 1;
+ half -= (rsize & 1) ^ 1;
+ rlmatch = rmatch;
+ } else {
+ rrmatch = rmatch;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if(idx != NULL) { *idx = (0 < (k - j)) ? j : i; }
+ return k - j;
+}
+
+/* Search for the character c in the string T. */
+saidx_t
+sa_simplesearch(const sauchar_t *T, saidx_t Tsize,
+ const saidx_t *SA, saidx_t SAsize,
+ saint_t c, saidx_t *idx) {
+ saidx_t size, lsize, rsize, half;
+ saidx_t i, j, k, p;
+ saint_t r;
+
+ if(idx != NULL) { *idx = -1; }
+ if((T == NULL) || (SA == NULL) || (Tsize < 0) || (SAsize < 0)) { return -1; }
+ if((Tsize == 0) || (SAsize == 0)) { return 0; }
+
+ for(i = j = k = 0, size = SAsize, half = size >> 1;
+ 0 < size;
+ size = half, half >>= 1) {
+ p = SA[i + half];
+ r = (p < Tsize) ? T[p] - c : -1;
+ if(r < 0) {
+ i += half + 1;
+ half -= (size & 1) ^ 1;
+ } else if(r == 0) {
+ lsize = half, j = i, rsize = size - half - 1, k = i + half + 1;
+
+ /* left part */
+ for(half = lsize >> 1;
+ 0 < lsize;
+ lsize = half, half >>= 1) {
+ p = SA[j + half];
+ r = (p < Tsize) ? T[p] - c : -1;
+ if(r < 0) {
+ j += half + 1;
+ half -= (lsize & 1) ^ 1;
+ }
+ }
+
+ /* right part */
+ for(half = rsize >> 1;
+ 0 < rsize;
+ rsize = half, half >>= 1) {
+ p = SA[k + half];
+ r = (p < Tsize) ? T[p] - c : -1;
+ if(r <= 0) {
+ k += half + 1;
+ half -= (rsize & 1) ^ 1;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if(idx != NULL) { *idx = (0 < (k - j)) ? j : i; }
+ return k - j;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/CMakeLists.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/CMakeLists.txt
new file mode 100644
index 000000000..ee7063c98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/CMakeLists.txt
@@ -0,0 +1,9 @@
+## generate libdivsufsort.pc ##
+set(W64BIT "")
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR})
+if(BUILD_DIVSUFSORT64)
+ set(W64BIT "64")
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libdivsufsort.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" @ONLY)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libdivsufsort64.pc" DESTINATION ${CMAKE_INSTALL_PKGCONFIGDIR})
+endif(BUILD_DIVSUFSORT64)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake
new file mode 100644
index 000000000..6419d1ea8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/libdivsufsort/pkgconfig/libdivsufsort.pc.cmake
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=@CMAKE_INSTALL_LIBDIR@
+includedir=@CMAKE_INSTALL_INCLUDEDIR@
+
+Name: @PROJECT_NAME@@W64BIT@
+Description: @PROJECT_DESCRIPTION@
+Version: @PROJECT_VERSION_FULL@
+URL: @PROJECT_URL@
+Libs: -L${libdir} -ldivsufsort@W64BIT@
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/read_dist.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/read_dist.h
new file mode 100644
index 000000000..63d3b97ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/read_dist.h
@@ -0,0 +1,50 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ Author: zip753@gmail.com (Ivan Nikulin)
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* API for reading distances from *.dist file.
+ The format of *.dist file is as follows: for each backward reference there is
+ a position-distance pair, also a copy length may be specified. Copy length is
+ prefixed with flag byte 0, position-distance pair is prefixed with flag
+ byte 1. Each number is a 32-bit integer. Copy length always comes before
+ position-distance pair. Standalone copy length is allowed, in this case it is
+ ignored. */
+
+#ifndef BROTLI_RESEARCH_READ_DIST_H_
+#define BROTLI_RESEARCH_READ_DIST_H_
+
+#include <cstdio>
+#include <cstdlib> /* exit, EXIT_FAILURE */
+
+#if !defined(CHECK)
+#define CHECK(X) if (!(X)) exit(EXIT_FAILURE);
+#endif
+
+/* Reads backwards reference from .dist file. Sets all missing fields to -1.
+ Returns false when EOF is met or input is corrupt. */
+bool ReadBackwardReference(FILE* fin, int* copy, int* pos, int* dist) {
+ int c = getc(fin);
+ if (c == EOF) return false;
+ if (c == 0) {
+ CHECK(fread(copy, sizeof(int), 1, fin) == 1);
+ if ((c = getc(fin)) != 1) {
+ ungetc(c, fin);
+ *pos = *dist = -1;
+ } else {
+ CHECK(fread(pos, sizeof(int), 1, fin) == 1);
+ CHECK(fread(dist, sizeof(int), 1, fin) == 1);
+ }
+ } else if (c != 1) {
+ return false;
+ } else {
+ CHECK(fread(pos, sizeof(int), 1, fin) == 1);
+ CHECK(fread(dist, sizeof(int), 1, fin) == 1);
+ *copy = -1;
+ }
+ return true;
+}
+
+#endif /* BROTLI_RESEARCH_READ_DIST_H_ */
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.cc b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.cc
new file mode 100755
index 000000000..4d147e112
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.cc
@@ -0,0 +1,259 @@
+#include "./sieve.h"
+
+/* Pointer to position in (combined corpus) text. */
+typedef uint32_t TextIdx;
+
+/* Index of sample / generation. */
+typedef uint16_t SampleIdx;
+
+typedef struct Slot {
+ TextIdx next;
+ TextIdx offset;
+ SampleIdx presence;
+ SampleIdx mark;
+} Slot;
+
+static const TextIdx kNowhere = static_cast<TextIdx>(-1);
+
+static TextIdx dryRun(TextIdx sliceLen, Slot* map, TextIdx* shortcut,
+ TextIdx end, TextIdx middle, SampleIdx minPresence, SampleIdx iteration) {
+ TextIdx from = kNowhere;
+ TextIdx to = kNowhere;
+ TextIdx result = 0;
+ SampleIdx targetPresence = minPresence;
+ for (TextIdx i = 0; i < end; ++i) {
+ if (i == middle) {
+ targetPresence++;
+ }
+ Slot& item = map[shortcut[i]];
+ if (item.mark != iteration) {
+ item.mark = iteration;
+ if (item.presence >= targetPresence) {
+ if ((to == kNowhere) || (to < i)) {
+ if (from != kNowhere) {
+ result += to - from;
+ }
+ from = i;
+ }
+ to = i + sliceLen;
+ }
+ }
+ }
+ if (from != kNowhere) {
+ result += to - from;
+ }
+ return result;
+}
+
+static std::string createDictionary(const uint8_t* data, TextIdx sliceLen,
+ Slot* map, TextIdx* shortcut, TextIdx end, TextIdx middle,
+ SampleIdx minPresence, SampleIdx iteration) {
+ std::string output;
+ TextIdx from = kNowhere;
+ TextIdx to = kNowhere;
+ SampleIdx targetPresence = minPresence;
+ for (TextIdx i = 0; i < end; ++i) {
+ if (i == middle) {
+ targetPresence++;
+ }
+ Slot& item = map[shortcut[i]];
+ if (item.mark != iteration) {
+ item.mark = iteration;
+ if (item.presence >= targetPresence) {
+ if ((to == kNowhere) || (to < i)) {
+ if (from != kNowhere) {
+ output.insert(output.end(), &data[from], &data[to]);
+ }
+ from = i;
+ }
+ to = i + sliceLen;
+ }
+ }
+ }
+ if (from != kNowhere) {
+ output.insert(output.end(), &data[from], &data[to]);
+ }
+ return output;
+}
+
+std::string sieve_generate(size_t dictionary_size_limit, size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data) {
+ /* Parameters aliasing */
+ TextIdx targetSize = static_cast<TextIdx>(dictionary_size_limit);
+ if (targetSize != dictionary_size_limit) {
+ fprintf(stderr, "dictionary_size_limit is too large\n");
+ return "";
+ }
+ TextIdx sliceLen = static_cast<TextIdx>(slice_len);
+ if (sliceLen != slice_len) {
+ fprintf(stderr, "slice_len is too large\n");
+ return "";
+ }
+ if (sliceLen < 1) {
+ fprintf(stderr, "slice_len is too small\n");
+ return "";
+ }
+ SampleIdx numSamples = static_cast<SampleIdx>(sample_sizes.size());
+ if ((numSamples != sample_sizes.size()) || (numSamples * 2 < numSamples)) {
+ fprintf(stderr, "too many samples\n");
+ return "";
+ }
+ const uint8_t* data = sample_data;
+
+ TextIdx total = 0;
+ std::vector<TextIdx> offsets;
+ for (SampleIdx i = 0; i < numSamples; ++i) {
+ TextIdx delta = static_cast<TextIdx>(sample_sizes[i]);
+ if (delta != sample_sizes[i]) {
+ fprintf(stderr, "sample is too large\n");
+ return "";
+ }
+ if (delta == 0) {
+ fprintf(stderr, "empty samples are prohibited\n");
+ return "";
+ }
+ if (total + delta <= total) {
+ fprintf(stderr, "corpus is too large\n");
+ return "";
+ }
+ total += delta;
+ offsets.push_back(total);
+ }
+
+ if (total * 2 < total) {
+ fprintf(stderr, "corpus is too large\n");
+ return "";
+ }
+
+ if (total < sliceLen) {
+ fprintf(stderr, "slice_len is larger than corpus size\n");
+ return "";
+ }
+
+ /*****************************************************************************
+ * Build coverage map.
+ ****************************************************************************/
+ std::vector<Slot> map;
+ std::vector<TextIdx> shortcut;
+ map.push_back({0, 0, 0, 0});
+ TextIdx end = total - sliceLen;
+ TextIdx hashLen = 11;
+ while (hashLen < 29 && ((1u << hashLen) < end)) {
+ hashLen += 3;
+ }
+ hashLen -= 3;
+ TextIdx hashMask = (1u << hashLen) - 1u;
+ std::vector<TextIdx> hashHead(1 << hashLen);
+ TextIdx hashSlot = 1;
+ SampleIdx piece = 0;
+ TextIdx hash = 0;
+ TextIdx lShift = 3;
+ TextIdx rShift = hashLen - lShift;
+ for (TextIdx i = 0; i < sliceLen - 1; ++i) {
+ TextIdx v = data[i];
+ hash = (((hash << lShift) | (hash >> rShift)) & hashMask) ^ v;
+ }
+ TextIdx lShiftX = (lShift * (sliceLen - 1)) % hashLen;
+ TextIdx rShiftX = hashLen - lShiftX;
+ for (TextIdx i = 0; i < end; ++i) {
+ TextIdx v = data[i + sliceLen - 1];
+ hash = (((hash << lShift) | (hash >> rShift)) & hashMask) ^ v;
+
+ if (offsets[piece] == i) {
+ piece++;
+ }
+ TextIdx slot = hashHead[hash];
+ while (slot != 0) {
+ Slot& item = map[slot];
+ TextIdx start = item.offset;
+ bool miss = false;
+ for (TextIdx j = 0; j < sliceLen; ++j) {
+ if (data[i + j] != data[start + j]) {
+ miss = true;
+ break;
+ }
+ }
+ if (!miss) {
+ if (item.mark != piece) {
+ item.mark = piece;
+ item.presence++;
+ }
+ shortcut.push_back(slot);
+ break;
+ }
+ slot = item.next;
+ }
+ if (slot == 0) {
+ map.push_back({hashHead[hash], i, 1, piece});
+ hashHead[hash] = hashSlot;
+ shortcut.push_back(hashSlot);
+ hashSlot++;
+ }
+ v = data[i];
+ hash ^= ((v << lShiftX) | (v >> rShiftX)) & hashMask;
+ }
+
+ /*****************************************************************************
+ * Build dictionary of specified size.
+ ****************************************************************************/
+ SampleIdx a = 1;
+ TextIdx size = dryRun(
+ sliceLen, map.data(), shortcut.data(), end, end, a, ++piece);
+ /* Maximal output is smaller than target. */
+ if (size <= targetSize) {
+ return createDictionary(
+ data, sliceLen, map.data(), shortcut.data(), end, end, a, ++piece);
+ }
+
+ SampleIdx b = numSamples;
+ size = dryRun(sliceLen, map.data(), shortcut.data(), end, end, b, ++piece);
+ if (size == targetSize) {
+ return createDictionary(
+ data, sliceLen, map.data(), shortcut.data(), end, end, b, ++piece);
+ }
+ /* Run binary search. */
+ if (size < targetSize) {
+ /* size(a) > targetSize > size(b) && a < m < b */
+ while (a + 1 < b) {
+ SampleIdx m = static_cast<SampleIdx>((a + b) / 2);
+ size = dryRun(
+ sliceLen, map.data(), shortcut.data(), end, end, m, ++piece);
+ if (size < targetSize) {
+ b = m;
+ } else if (size > targetSize) {
+ a = m;
+ } else {
+ return createDictionary(
+ data, sliceLen, map.data(), shortcut.data(), end, end, b, ++piece);
+ }
+ }
+ } else {
+ a = b;
+ }
+ /* size(minPresence) > targetSize > size(minPresence + 1) */
+ SampleIdx minPresence = a;
+ TextIdx c = 0;
+ TextIdx d = end;
+ /* size(a) < targetSize < size(b) && a < m < b */
+ while (c + 1 < d) {
+ TextIdx m = (c + d) / 2;
+ size = dryRun(
+ sliceLen, map.data(), shortcut.data(), end, m, minPresence, ++piece);
+ if (size < targetSize) {
+ c = m;
+ } else if (size > targetSize) {
+ d = m;
+ } else {
+ return createDictionary(data, sliceLen, map.data(), shortcut.data(), end,
+ m, minPresence, ++piece);
+ }
+ }
+
+ bool unrestricted = false;
+ if (minPresence <= 2 && !unrestricted) {
+ minPresence = 2;
+ c = end;
+ }
+ return createDictionary(data, sliceLen, map.data(), shortcut.data(), end, c,
+ minPresence, ++piece);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.h
new file mode 100755
index 000000000..6c65dc8e0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/research/sieve.h
@@ -0,0 +1,21 @@
+#ifndef BROTLI_RESEARCH_SIEVE_H_
+#define BROTLI_RESEARCH_SIEVE_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+/**
+ * Generate a dictionary for given samples.
+ *
+ * @param dictionary_size_limit maximal dictionary size
+ * @param slice_len text slice size
+ * @param sample_sizes vector with sample sizes
+ * @param sample_data concatenated samples
+ * @return generated dictionary
+ */
+std::string sieve_generate(size_t dictionary_size_limit, size_t slice_len,
+ const std::vector<size_t>& sample_sizes, const uint8_t* sample_data);
+
+#endif // BROTLI_RESEARCH_SIEVE_H_
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.bintray.json b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.bintray.json
new file mode 100644
index 000000000..ef2ea9d8e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.bintray.json
@@ -0,0 +1,19 @@
+{
+ "package": {
+ "name": "bin",
+ "repo": "brotli",
+ "subject": "eustas"
+ },
+
+ "version": {"name": "snapshot"},
+
+ "files": [
+ {
+ "includePattern": "brotli.zip",
+ "uploadPattern": "brotli-${TRAVIS_OS_NAME}-${RELEASE_DATE}.zip",
+ "matrix_params": {"override": 1}
+ }
+ ],
+
+ "publish": true
+}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.configure-custom.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.configure-custom.sh
new file mode 100644
index 000000000..f1f641af1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.configure-custom.sh
@@ -0,0 +1 @@
+#!/usr/bin/env bash
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.travis.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.travis.sh
new file mode 100755
index 000000000..8b7e2b314
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/.travis.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+case "$1" in
+ "before_install")
+ ;;
+ "install")
+ case "${TRAVIS_OS_NAME}" in
+ "osx")
+ brew update
+ brew install binutils
+
+ case "${CC}" in
+ "gcc-"*)
+ which ${CC} || brew install $(echo "${CC}" | sed 's/\-/@/') || brew link --overwrite $(echo "${CC}" | sed 's/\-/@/')
+ ;;
+ esac
+
+ case "${BUILD_SYSTEM}" in
+ "bazel")
+ brew install bazel
+ brew upgrade python
+ ;;
+ esac
+ ;;
+ "linux")
+ case "${CC}" in
+ "pgcc")
+ wget 'https://raw.githubusercontent.com/nemequ/pgi-travis/de6212d94fd0e7d07a6ef730c23548c337c436a7/install-pgi.sh'
+ echo 'acd3ef995ad93cfb87d26f65147395dcbedd4c3c844ee6ec39616f1a347c8df5 install-pgi.sh' | sha256sum -c --strict || exit 1
+ /bin/sh install-pgi.sh
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ "script")
+ case "${BUILD_SYSTEM}" in
+ "cmake")
+ mkdir builddir && cd builddir
+ CMAKE_FLAGS=
+ if [ "${CROSS_COMPILE}" = "yes" ]; then
+ CMAKE_FLAGS="-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_RC_COMPILER=${RC_COMPILER}"
+ fi
+ cmake ${CMAKE_FLAGS} -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" -DENABLE_SANITIZER="${SANITIZER}" -DCMAKE_C_FLAGS="${CFLAGS}" .. || exit 1
+ make VERBOSE=1 || exit 1
+ ctest -V || exit 1
+ ;;
+ "python")
+ python setup.py test
+ ;;
+ "maven")
+ cd java/org/brotli
+ mvn install && cd integration && mvn verify
+ ;;
+ "autotools")
+ ./bootstrap && ./configure && make
+ ;;
+ "fuzz")
+ ./c/fuzz/test_fuzzer.sh
+ ;;
+ "bazel")
+ bazel build -c opt ...:all &&
+ cd go && bazel test -c opt ...:all && cd .. &&
+ cd java && bazel test -c opt ...:all && cd .. &&
+ cd js && bazel test -c opt ...:all && cd .. &&
+ cd research && bazel build -c opt ...:all && cd ..
+ ;;
+ esac
+ ;;
+ "after_success")
+ ;;
+ "before_deploy")
+ case "${BUILD_SYSTEM}" in
+ "bazel")
+ export RELEASE_DATE=`date +%Y-%m-%d`
+ perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' scripts/.bintray.json
+ zip -j9 brotli.zip bazel-bin/libbrotli*.a bazel-bin/libbrotli*.so bazel-bin/brotli
+ ;;
+ esac
+ ;;
+esac
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/appveyor.yml b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/appveyor.yml
new file mode 100644
index 000000000..e22a8c689
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/appveyor.yml
@@ -0,0 +1,111 @@
+branches:
+ only:
+ - master
+
+environment:
+ matrix:
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ BUILD_SYSTEM: CMake
+ GENERATOR: Visual Studio 15 2017 Win64
+ CONFIG: Release
+
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ BUILD_SYSTEM: CMake
+ GENERATOR: Visual Studio 15 2017 Win64
+ CONFIG: Debug
+
+ - BUILD_SYSTEM: CMake
+ GENERATOR: Visual Studio 14 2015 Win64
+ CONFIG: Debug
+
+ - BUILD_SYSTEM: CMake
+ GENERATOR: Visual Studio 14 2015
+ CONFIG: Debug
+
+ - BUILD_SYSTEM: Python
+ PYTHON: "C:\\Python27"
+ PYTHON_VERSION: "2.7.x"
+ PYTHON_ARCH: "32"
+
+ - BUILD_SYSTEM: Python
+ PYTHON: "C:\\Python36-x64"
+ PYTHON_VERSION: "3.6.x"
+ PYTHON_ARCH: "64"
+
+ - BUILD_SYSTEM: make
+ ARCH: "i686"
+
+ - BUILD_SYSTEM: make
+ ARCH: "x86_64"
+
+ - BUILD_SYSTEM: bazel
+
+install:
+- IF "%BUILD_SYSTEM%"=="Python" (
+ SET "PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%" &&
+ python -m pip install --upgrade pip &&
+ pip install --upgrade setuptools
+ )
+- IF "%BUILD_SYSTEM%"=="make" (
+ IF "%ARCH%"=="i686" (
+ SET "TOOLCHAIN=i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32"
+ ) ELSE (
+ SET "TOOLCHAIN=x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64"
+ )
+ )
+- IF "%BUILD_SYSTEM%"=="bazel" (
+ appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/0.18.0/bazel-0.18.0-windows-x86_64.exe -FileName bazel.exe
+ )
+
+before_build:
+- FOR /f %%i in ('C:\cygwin64\bin\date.exe +%%Y-%%m-%%d') DO SET "RELEASE_DATE=%%i"
+- IF "%BUILD_SYSTEM%"=="CMake" ( mkdir builddir && cd builddir && cmake -G "%GENERATOR%" .. )
+- IF "%BUILD_SYSTEM%"=="make" (
+ SET "CC=gcc" &&
+ SET "PATH=C:\mingw-w64\%TOOLCHAIN%\bin;%PATH%" &&
+ COPY C:\msys64\usr\bin\make.exe C:\mingw-w64\%TOOLCHAIN%\bin\make.exe
+ )
+- SET "ROOT=%APPVEYOR_BUILD_FOLDER%"
+
+build_script:
+- IF "%BUILD_SYSTEM%"=="CMake" ( cmake --build . --config %CONFIG% )
+- IF "%BUILD_SYSTEM%"=="Python" ( python setup.py build_ext )
+- IF "%BUILD_SYSTEM%"=="make" (
+ sh -c "make brotli" &&
+ cd bin && 7z a -tzip -mx9 brotli-win-%ARCH%-%RELEASE_DATE%.zip brotli.exe &&
+ appveyor PushArtifact brotli-win-%ARCH%-%RELEASE_DATE%.zip && cd ..
+ )
+- IF "%BUILD_SYSTEM%"=="bazel" (
+ cd java &&
+ %ROOT%\bazel.exe --batch build -c opt org/brotli/wrapper/...:all &&
+ python %ROOT%\scripts\fix-win-bazel-build.py &&
+ cd bazel-bin &&
+ 7z a -tzip -mx9 brotli-win-bazel-jni-%RELEASE_DATE%.zip brotli_jni.dll &&
+ appveyor PushArtifact brotli-win-bazel-jni-%RELEASE_DATE%.zip &&
+ cd .. &&
+ cd ..
+ )
+
+test_script:
+- IF "%BUILD_SYSTEM%"=="CMake" ( ctest --output-on-failure --interactive-debug-mode 0 -C %CONFIG% )
+- IF "%BUILD_SYSTEM%"=="Python" ( python setup.py test )
+- IF "%BUILD_SYSTEM%"=="make" ( sh -c "make test" )
+- IF "%BUILD_SYSTEM%"=="bazel" (
+ cd java &&
+ %ROOT%\bazel.exe --batch test -c opt --test_output streamed org/brotli/wrapper/...:all &&
+ cd ..
+ )
+
+deploy:
+- provider: BinTray
+ on:
+ branch: master
+ username: eustas
+ api_key:
+ secure: B3rM8JYeIHIw6BfOjHggAeyTmxEf8ZDYmyF9gCwqyWaxyxECD9BuN50SiV2KE/RI
+ subject: eustas
+ repo: brotli
+ package: bin
+ version: snapshot
+ publish: true
+ override: true
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/README.md b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/README.md
new file mode 100644
index 000000000..366a82c3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/README.md
@@ -0,0 +1,3 @@
+Set of tools that can be used to download brotli RFC, extract and validate
+binary dictionary, and generate dictionary derivatives
+(e.g. Java `DictionaryData` class constants).
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-01-download-rfc.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-01-download-rfc.py
new file mode 100644
index 000000000..14f65cc42
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-01-download-rfc.py
@@ -0,0 +1,16 @@
+# Step 01 - download RFC7932.
+#
+# RFC is the ultimate source for brotli format and constants, including
+# static dictionary.
+
+import urllib2
+
+response = urllib2.urlopen('https://tools.ietf.org/rfc/rfc7932.txt')
+
+text = response.read()
+path = "rfc7932.txt"
+
+with open(path, "w") as rfc:
+ rfc.write(text)
+
+print("Downloaded and saved " + str(len(text)) + " bytes to " + path)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-02-rfc-to-bin.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-02-rfc-to-bin.py
new file mode 100644
index 000000000..27737c583
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-02-rfc-to-bin.py
@@ -0,0 +1,34 @@
+# Step 02 - parse RFC.
+#
+# Static dictionary is described in "Appendix A" section in a hexadecimal form.
+# This tool locates dictionary data in RFC and converts it to raw binary format.
+
+import re
+
+rfc_path = "rfc7932.txt"
+
+with open(rfc_path, "r") as rfc:
+ lines = rfc.readlines()
+
+re_data_line = re.compile("^ [0-9a-f]{64}$")
+
+appendix_a_found = False
+dictionary = []
+for line in lines:
+ if appendix_a_found:
+ if re_data_line.match(line) is not None:
+ data = line.strip()
+ for i in range(32):
+ dictionary.append(int(data[2 * i : 2 * i + 2], 16))
+ if len(dictionary) == 122784:
+ break
+ else:
+ if line.startswith("Appendix A."):
+ appendix_a_found = True
+
+bin_path = "dictionary.bin"
+
+with open(bin_path, "wb") as output:
+ output.write(bytearray(dictionary))
+
+print("Parsed and saved " + str(len(dictionary)) + " bytes to " + bin_path)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-03-validate-bin.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-03-validate-bin.py
new file mode 100644
index 000000000..171cc9b8c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-03-validate-bin.py
@@ -0,0 +1,38 @@
+# Step 03 - validate raw dictionary file.
+#
+# CRC32, MD5, SHA1 and SHA256 checksums for raw binary dictionary are checked.
+
+import hashlib
+import zlib
+
+bin_path = "dictionary.bin"
+
+with open(bin_path, "rb") as raw:
+ data = raw.read()
+
+def check_digest(name, expected, actual):
+ if expected == actual:
+ print("[OK] " + name)
+ else:
+ print("[ERROR] " + name + " | " + expected + " != " + actual)
+
+
+check_digest(
+ "CRC32", # This is the only checksum provided in RFC.
+ "0x5136cb04",
+ hex(zlib.crc32(data)))
+
+check_digest(
+ "MD5",
+ "96cecd2ee7a666d5aa3627d74735b32a",
+ hashlib.md5(data).hexdigest())
+
+check_digest(
+ "SHA1",
+ "72b41051cb61a9281ba3c4414c289da50d9a7640",
+ hashlib.sha1(data).hexdigest())
+
+check_digest(
+ "SHA256",
+ "20e42eb1b511c21806d4d227d07e5dd06877d8ce7b3a817f378f313653f35c70",
+ hashlib.sha256(data).hexdigest())
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-04-generate-java-literals.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-04-generate-java-literals.py
new file mode 100644
index 000000000..fd3c64e00
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/dictionary/step-04-generate-java-literals.py
@@ -0,0 +1,79 @@
+# Step 04 - generate Java literals.
+#
+# Java byte-code has ridiculous restrictions. There is no such thing as
+# "array literal" - those are implemented as series of data[x] = y;
+# as a consequence N-byte array will use 7N bytes in class, plus N bytes
+# in instantiated variable. Also no literal could be longer than 64KiB.
+#
+# To keep dictionary data compact both in source code and in compiled format
+# we use the following tricks:
+# * use String as a data container
+# * store only lowest 7 bits; i.e. all characters fit ASCII table; this allows
+# efficient conversion to byte array; also ASCII characters use only 1 byte
+#. of memory (UTF-8 encoding)
+# * RLE-compress sequence of 8-th bits
+#
+# This script generates literals used in Java code.
+
+bin_path = "dictionary.bin"
+
+with open(bin_path, "rb") as raw:
+ data = raw.read()
+
+low = []
+hi = []
+is_skip = True
+skip_flip_offset = 36
+cntr = skip_flip_offset
+for b in data:
+ value = ord(b)
+ low.append(chr(value & 0x7F))
+ if is_skip:
+ if value < 0x80:
+ cntr += 1
+ else:
+ is_skip = False
+ hi.append(unichr(cntr))
+ cntr = skip_flip_offset + 1
+ else:
+ if value >= 0x80:
+ cntr += 1
+ else:
+ is_skip = True
+ hi.append(unichr(cntr))
+ cntr = skip_flip_offset + 1
+hi.append(unichr(cntr))
+
+low0 = low[0 : len(low) // 2]
+low1 = low[len(low) // 2 : len(low)]
+
+def escape(chars):
+ result = []
+ for c in chars:
+ if "\r" == c:
+ result.append("\\r")
+ elif "\n" == c:
+ result.append("\\n")
+ elif "\t" == c:
+ result.append("\\t")
+ elif "\"" == c:
+ result.append("\\\"")
+ elif "\\" == c:
+ result.append("\\\\")
+ elif ord(c) < 32 or ord(c) >= 127:
+ result.append("\\u%04X" % ord(c))
+ else:
+ result.append(c);
+ return result
+
+
+source_code = [
+ " private static final String DATA0 = \"", "".join(escape(low0)), "\";\n",
+ " private static final String DATA1 = \"", "".join(escape(low1)), "\";\n",
+ " private static final String SKIP_FLIP = \"", "".join(escape(hi)), "\";\n"
+]
+
+src_path = "DictionaryData.inc.java"
+
+with open(src_path, "w") as source:
+ source.write("".join(source_code))
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/fix-win-bazel-build.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/fix-win-bazel-build.py
new file mode 100644
index 000000000..7a9b21198
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/fix-win-bazel-build.py
@@ -0,0 +1,36 @@
+import fnmatch
+import os
+import os.path
+from shutil import copyfile
+
+print('Searching for manifests...')
+
+matches = []
+for root, dirnames, filenames in os.walk('bazel-bin\\org\\brotli'):
+ for filename in fnmatch.filter(filenames, '*.runfiles_manifest'):
+ matches.append(os.path.join(root, filename))
+
+for match in matches:
+ print('Scanning manifest ' + match)
+ runfiles = match[:-len('_manifest')]
+ with open(match) as manifest:
+ for entry in manifest:
+ entry = entry.strip()
+ if not entry.startswith("org_brotli_java"):
+ continue
+ if entry.startswith('org_brotli_java/external'):
+ continue
+ (alias, space, link) = entry.partition(' ')
+ if alias.endswith('.jar') or alias.endswith('.exe'):
+ continue
+ link = link.replace('/', '\\')
+ alias = alias.replace('/', '\\')
+ dst = os.path.join(runfiles, alias)
+ if not os.path.exists(dst):
+ print(link + ' -> ' + dst)
+ parent = os.path.dirname(dst)
+ if not os.path.exists(parent):
+ os.makedirs(parent)
+ copyfile(link, dst)
+
+print('Finished resolving symlinks')
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlicommon.pc.in b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlicommon.pc.in
new file mode 100644
index 000000000..2a8cf7a35
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlicommon.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libbrotlicommon
+URL: https://github.com/google/brotli
+Description: Brotli common dictionary library
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbrotlicommon
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlidec.pc.in b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlidec.pc.in
new file mode 100644
index 000000000..6f8ef2e41
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlidec.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libbrotlidec
+URL: https://github.com/google/brotli
+Description: Brotli decoder library
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbrotlidec
+Requires.private: libbrotlicommon >= 1.0.2
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlienc.pc.in b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlienc.pc.in
new file mode 100644
index 000000000..2098afe2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/libbrotlienc.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libbrotlienc
+URL: https://github.com/google/brotli
+Description: Brotli encoder library
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbrotlienc
+Requires.private: libbrotlicommon >= 1.0.2
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/sources.lst b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/sources.lst
new file mode 100644
index 000000000..5e8e817c9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/scripts/sources.lst
@@ -0,0 +1,99 @@
+# IT WOULD BE FOOLISH TO USE COMPUTERS TO AUTOMATE REPETITIVE TASKS:
+# ENLIST EVERY USED HEADER AND SOURCE FILE MANUALLY!
+
+BROTLI_CLI_C = \
+ c/tools/brotli.c
+
+BROTLI_COMMON_C = \
+ c/common/dictionary.c \
+ c/common/transform.c
+
+BROTLI_COMMON_H = \
+ c/common/constants.h \
+ c/common/context.h \
+ c/common/dictionary.h \
+ c/common/platform.h \
+ c/common/transform.h \
+ c/common/version.h
+
+BROTLI_DEC_C = \
+ c/dec/bit_reader.c \
+ c/dec/decode.c \
+ c/dec/huffman.c \
+ c/dec/state.c
+
+BROTLI_DEC_H = \
+ c/dec/bit_reader.h \
+ c/dec/huffman.h \
+ c/dec/prefix.h \
+ c/dec/state.h
+
+BROTLI_ENC_C = \
+ c/enc/backward_references.c \
+ c/enc/backward_references_hq.c \
+ c/enc/bit_cost.c \
+ c/enc/block_splitter.c \
+ c/enc/brotli_bit_stream.c \
+ c/enc/cluster.c \
+ c/enc/compress_fragment.c \
+ c/enc/compress_fragment_two_pass.c \
+ c/enc/dictionary_hash.c \
+ c/enc/encode.c \
+ c/enc/encoder_dict.c \
+ c/enc/entropy_encode.c \
+ c/enc/histogram.c \
+ c/enc/literal_cost.c \
+ c/enc/memory.c \
+ c/enc/metablock.c \
+ c/enc/static_dict.c \
+ c/enc/utf8_util.c
+
+BROTLI_ENC_H = \
+ c/enc/backward_references.h \
+ c/enc/backward_references_hq.h \
+ c/enc/backward_references_inc.h \
+ c/enc/bit_cost.h \
+ c/enc/bit_cost_inc.h \
+ c/enc/block_encoder_inc.h \
+ c/enc/block_splitter.h \
+ c/enc/block_splitter_inc.h \
+ c/enc/brotli_bit_stream.h \
+ c/enc/cluster.h \
+ c/enc/cluster_inc.h \
+ c/enc/command.h \
+ c/enc/compress_fragment.h \
+ c/enc/compress_fragment_two_pass.h \
+ c/enc/dictionary_hash.h \
+ c/enc/encoder_dict.h \
+ c/enc/entropy_encode.h \
+ c/enc/entropy_encode_static.h \
+ c/enc/fast_log.h \
+ c/enc/find_match_length.h \
+ c/enc/hash.h \
+ c/enc/hash_composite_inc.h \
+ c/enc/hash_forgetful_chain_inc.h \
+ c/enc/hash_longest_match64_inc.h \
+ c/enc/hash_longest_match_inc.h \
+ c/enc/hash_longest_match_quickly_inc.h \
+ c/enc/hash_rolling_inc.h \
+ c/enc/hash_to_binary_tree_inc.h \
+ c/enc/histogram.h \
+ c/enc/histogram_inc.h \
+ c/enc/literal_cost.h \
+ c/enc/memory.h \
+ c/enc/metablock.h \
+ c/enc/metablock_inc.h \
+ c/enc/params.h \
+ c/enc/prefix.h \
+ c/enc/quality.h \
+ c/enc/ringbuffer.h \
+ c/enc/static_dict.h \
+ c/enc/static_dict_lut.h \
+ c/enc/utf8_util.h \
+ c/enc/write_bits.h
+
+BROTLI_INCLUDE = \
+ c/include/brotli/decode.h \
+ c/include/brotli/encode.h \
+ c/include/brotli/port.h \
+ c/include/brotli/types.h
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.cfg b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.cfg
new file mode 100644
index 000000000..990b9e1a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.cfg
@@ -0,0 +1,5 @@
+[build]
+build-base=bin
+
+[yapf]
+based_on_style=google
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.py b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.py
new file mode 100644
index 000000000..78672103b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/setup.py
@@ -0,0 +1,288 @@
+# Copyright 2015 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+import os
+import platform
+import re
+import unittest
+
+try:
+ from setuptools import Extension
+ from setuptools import setup
+except:
+ from distutils.core import Extension
+ from distutils.core import setup
+from distutils.command.build_ext import build_ext
+from distutils import errors
+from distutils import dep_util
+from distutils import log
+
+
+CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
+
+
+def get_version():
+ """ Return BROTLI_VERSION string as defined in 'common/version.h' file. """
+ version_file_path = os.path.join(CURR_DIR, 'c', 'common', 'version.h')
+ version = 0
+ with open(version_file_path, 'r') as f:
+ for line in f:
+ m = re.match(r'#define\sBROTLI_VERSION\s+0x([0-9a-fA-F]+)', line)
+ if m:
+ version = int(m.group(1), 16)
+ if version == 0:
+ return ''
+ # Semantic version is calculated as (MAJOR << 24) | (MINOR << 12) | PATCH.
+ major = version >> 24
+ minor = (version >> 12) & 0xFFF
+ patch = version & 0xFFF
+ return '{0}.{1}.{2}'.format(major, minor, patch)
+
+
+def get_test_suite():
+ test_loader = unittest.TestLoader()
+ test_suite = test_loader.discover('python', pattern='*_test.py')
+ return test_suite
+
+
+class BuildExt(build_ext):
+
+ def get_source_files(self):
+ filenames = build_ext.get_source_files(self)
+ for ext in self.extensions:
+ filenames.extend(ext.depends)
+ return filenames
+
+ def build_extension(self, ext):
+ if ext.sources is None or not isinstance(ext.sources, (list, tuple)):
+ raise errors.DistutilsSetupError(
+ "in 'ext_modules' option (extension '%s'), "
+ "'sources' must be present and must be "
+ "a list of source filenames" % ext.name)
+
+ ext_path = self.get_ext_fullpath(ext.name)
+ depends = ext.sources + ext.depends
+ if not (self.force or dep_util.newer_group(depends, ext_path, 'newer')):
+ log.debug("skipping '%s' extension (up-to-date)", ext.name)
+ return
+ else:
+ log.info("building '%s' extension", ext.name)
+
+ c_sources = []
+ cxx_sources = []
+ for source in ext.sources:
+ if source.endswith('.c'):
+ c_sources.append(source)
+ else:
+ cxx_sources.append(source)
+ extra_args = ext.extra_compile_args or []
+
+ objects = []
+ for lang, sources in (('c', c_sources), ('c++', cxx_sources)):
+ if lang == 'c++':
+ if self.compiler.compiler_type == 'msvc':
+ extra_args.append('/EHsc')
+
+ macros = ext.define_macros[:]
+ if platform.system() == 'Darwin':
+ macros.append(('OS_MACOSX', '1'))
+ elif self.compiler.compiler_type == 'mingw32':
+ # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot",
+ # This clashes with GCC's cmath, and causes compilation errors when
+ # building under MinGW: http://bugs.python.org/issue11566
+ macros.append(('_hypot', 'hypot'))
+ for undef in ext.undef_macros:
+ macros.append((undef,))
+
+ objs = self.compiler.compile(
+ sources,
+ output_dir=self.build_temp,
+ macros=macros,
+ include_dirs=ext.include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_args,
+ depends=ext.depends)
+ objects.extend(objs)
+
+ self._built_objects = objects[:]
+ if ext.extra_objects:
+ objects.extend(ext.extra_objects)
+ extra_args = ext.extra_link_args or []
+ # when using GCC on Windows, we statically link libgcc and libstdc++,
+ # so that we don't need to package extra DLLs
+ if self.compiler.compiler_type == 'mingw32':
+ extra_args.extend(['-static-libgcc', '-static-libstdc++'])
+
+ ext_path = self.get_ext_fullpath(ext.name)
+ # Detect target language, if not provided
+ language = ext.language or self.compiler.detect_language(sources)
+
+ self.compiler.link_shared_object(
+ objects,
+ ext_path,
+ libraries=self.get_libraries(ext),
+ library_dirs=ext.library_dirs,
+ runtime_library_dirs=ext.runtime_library_dirs,
+ extra_postargs=extra_args,
+ export_symbols=self.get_export_symbols(ext),
+ debug=self.debug,
+ build_temp=self.build_temp,
+ target_lang=language)
+
+
+NAME = 'Brotli'
+
+VERSION = get_version()
+
+URL = 'https://github.com/google/brotli'
+
+DESCRIPTION = 'Python bindings for the Brotli compression library'
+
+AUTHOR = 'The Brotli Authors'
+
+LICENSE = 'MIT'
+
+PLATFORMS = ['Posix', 'MacOS X', 'Windows']
+
+CLASSIFIERS = [
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Console',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: C',
+ 'Programming Language :: C++',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Unix Shell',
+ 'Topic :: Software Development :: Libraries',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: System :: Archiving',
+ 'Topic :: System :: Archiving :: Compression',
+ 'Topic :: Text Processing :: Fonts',
+ 'Topic :: Utilities',
+]
+
+PACKAGE_DIR = {'': 'python'}
+
+PY_MODULES = ['brotli']
+
+EXT_MODULES = [
+ Extension(
+ '_brotli',
+ sources=[
+ 'python/_brotli.cc',
+ 'c/common/dictionary.c',
+ 'c/common/transform.c',
+ 'c/dec/bit_reader.c',
+ 'c/dec/decode.c',
+ 'c/dec/huffman.c',
+ 'c/dec/state.c',
+ 'c/enc/backward_references.c',
+ 'c/enc/backward_references_hq.c',
+ 'c/enc/bit_cost.c',
+ 'c/enc/block_splitter.c',
+ 'c/enc/brotli_bit_stream.c',
+ 'c/enc/cluster.c',
+ 'c/enc/compress_fragment.c',
+ 'c/enc/compress_fragment_two_pass.c',
+ 'c/enc/dictionary_hash.c',
+ 'c/enc/encode.c',
+ 'c/enc/encoder_dict.c',
+ 'c/enc/entropy_encode.c',
+ 'c/enc/histogram.c',
+ 'c/enc/literal_cost.c',
+ 'c/enc/memory.c',
+ 'c/enc/metablock.c',
+ 'c/enc/static_dict.c',
+ 'c/enc/utf8_util.c',
+ ],
+ depends=[
+ 'c/common/constants.h',
+ 'c/common/context.h',
+ 'c/common/dictionary.h',
+ 'c/common/platform.h',
+ 'c/common/transform.h',
+ 'c/common/version.h',
+ 'c/dec/bit_reader.h',
+ 'c/dec/huffman.h',
+ 'c/dec/prefix.h',
+ 'c/dec/state.h',
+ 'c/enc/backward_references.h',
+ 'c/enc/backward_references_hq.h',
+ 'c/enc/backward_references_inc.h',
+ 'c/enc/bit_cost.h',
+ 'c/enc/bit_cost_inc.h',
+ 'c/enc/block_encoder_inc.h',
+ 'c/enc/block_splitter.h',
+ 'c/enc/block_splitter_inc.h',
+ 'c/enc/brotli_bit_stream.h',
+ 'c/enc/cluster.h',
+ 'c/enc/cluster_inc.h',
+ 'c/enc/command.h',
+ 'c/enc/compress_fragment.h',
+ 'c/enc/compress_fragment_two_pass.h',
+ 'c/enc/dictionary_hash.h',
+ 'c/enc/encoder_dict.h',
+ 'c/enc/entropy_encode.h',
+ 'c/enc/entropy_encode_static.h',
+ 'c/enc/fast_log.h',
+ 'c/enc/find_match_length.h',
+ 'c/enc/hash.h',
+ 'c/enc/hash_composite_inc.h',
+ 'c/enc/hash_forgetful_chain_inc.h',
+ 'c/enc/hash_longest_match64_inc.h',
+ 'c/enc/hash_longest_match_inc.h',
+ 'c/enc/hash_longest_match_quickly_inc.h',
+ 'c/enc/hash_rolling_inc.h',
+ 'c/enc/hash_to_binary_tree_inc.h',
+ 'c/enc/histogram.h',
+ 'c/enc/histogram_inc.h',
+ 'c/enc/literal_cost.h',
+ 'c/enc/memory.h',
+ 'c/enc/metablock.h',
+ 'c/enc/metablock_inc.h',
+ 'c/enc/params.h',
+ 'c/enc/prefix.h',
+ 'c/enc/quality.h',
+ 'c/enc/ringbuffer.h',
+ 'c/enc/static_dict.h',
+ 'c/enc/static_dict_lut.h',
+ 'c/enc/utf8_util.h',
+ 'c/enc/write_bits.h',
+ ],
+ include_dirs=[
+ 'c/include',
+ ],
+ language='c++'),
+]
+
+TEST_SUITE = 'setup.get_test_suite'
+
+CMD_CLASS = {
+ 'build_ext': BuildExt,
+}
+
+setup(
+ name=NAME,
+ description=DESCRIPTION,
+ version=VERSION,
+ url=URL,
+ author=AUTHOR,
+ license=LICENSE,
+ platforms=PLATFORMS,
+ classifiers=CLASSIFIERS,
+ package_dir=PACKAGE_DIR,
+ py_modules=PY_MODULES,
+ ext_modules=EXT_MODULES,
+ test_suite=TEST_SUITE,
+ cmdclass=CMD_CLASS)
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/Makefile b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/Makefile
new file mode 100644
index 000000000..28da198f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/Makefile
@@ -0,0 +1,17 @@
+#brotli/tests
+
+BROTLI = ..
+
+all: test
+
+test: deps
+ ./compatibility_test.sh
+ ./roundtrip_test.sh
+
+deps :
+ $(MAKE) -C $(BROTLI) brotli
+
+clean :
+ rm -f testdata/*.{br,unbr,uncompressed}
+ rm -f $(BROTLI)/{enc,dec,tools}/*.{un,}br
+ $(MAKE) -C $(BROTLI)/tools clean
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/compatibility_test.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/compatibility_test.sh
new file mode 100755
index 000000000..c5af8bf1a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/compatibility_test.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+#
+# Test that the brotli command-line tool can decompress old brotli-compressed
+# files.
+#
+# The first argument may be a wrapper for brotli, such as 'qemu-arm'.
+
+set -o errexit
+
+BROTLI_WRAPPER=$1
+BROTLI="${BROTLI_WRAPPER} bin/brotli"
+TMP_DIR=bin/tmp
+
+for file in tests/testdata/*.compressed*; do
+ echo "Testing decompression of file $file"
+ expected=${file%.compressed*}
+ uncompressed=${TMP_DIR}/${expected##*/}.uncompressed
+ echo $uncompressed
+ $BROTLI $file -fdo $uncompressed
+ diff -q $uncompressed $expected
+ # Test the streaming version
+ cat $file | $BROTLI -dc > $uncompressed
+ diff -q $uncompressed $expected
+ rm -f $uncompressed
+done
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/roundtrip_test.sh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/roundtrip_test.sh
new file mode 100755
index 000000000..90027af52
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/roundtrip_test.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+#
+# Roundtrip test for the brotli command-line tool.
+#
+# The first argument may be a wrapper for brotli, such as 'qemu-arm'.
+
+set -o errexit
+
+BROTLI_WRAPPER=$1
+BROTLI="${BROTLI_WRAPPER} bin/brotli"
+TMP_DIR=bin/tmp
+INPUTS="""
+tests/testdata/alice29.txt
+tests/testdata/asyoulik.txt
+tests/testdata/lcet10.txt
+tests/testdata/plrabn12.txt
+c/enc/encode.c
+c/common/dictionary.h
+c/dec/decode.c
+"""
+
+for file in $INPUTS; do
+ for quality in 1 6 9 11; do
+ echo "Roundtrip testing $file at quality $quality"
+ compressed=${TMP_DIR}/${file##*/}.br
+ uncompressed=${TMP_DIR}/${file##*/}.unbr
+ $BROTLI -fq $quality $file -o $compressed
+ $BROTLI $compressed -fdo $uncompressed
+ diff -q $file $uncompressed
+ # Test the streaming version
+ cat $file | $BROTLI -cq $quality | $BROTLI -cd >$uncompressed
+ diff -q $file $uncompressed
+ done
+done
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-compatibility-test.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-compatibility-test.cmake
new file mode 100644
index 000000000..f594d9829
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-compatibility-test.cmake
@@ -0,0 +1,31 @@
+string(REGEX REPLACE "([a-zA-Z0-9\\.]+)\\.compressed(\\.[0-9]+)?$" "\\1" REFERENCE_DATA "${INPUT}")
+string(REGEX REPLACE "\\.compressed" "" OUTPUT_FILE "${INPUT}")
+get_filename_component(OUTPUT_NAME "${OUTPUT_FILE}" NAME)
+
+set(ENV{QEMU_LD_PREFIX} "${BROTLI_WRAPPER_LD_PREFIX}")
+
+execute_process(
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --decompress ${INPUT} --output=${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.unbr
+ RESULT_VARIABLE result)
+if(result)
+ message(FATAL_ERROR "Decompression failed")
+endif()
+
+function(test_file_equality f1 f2)
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.7)
+ file(SHA512 "${f1}" f1_cs)
+ file(SHA512 "${f2}" f2_cs)
+ if(NOT "${f1_cs}" STREQUAL "${f2_cs}")
+ message(FATAL_ERROR "Files do not match")
+ endif()
+ else()
+ file(READ "${f1}" f1_contents)
+ file(READ "${f2}" f2_contents)
+ if(NOT "${f1_contents}" STREQUAL "${f2_contents}")
+ message(FATAL_ERROR "Files do not match")
+ endif()
+ endif()
+endfunction()
+
+test_file_equality("${REFERENCE_DATA}" "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.unbr")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-roundtrip-test.cmake b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-roundtrip-test.cmake
new file mode 100644
index 000000000..39303d33f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/run-roundtrip-test.cmake
@@ -0,0 +1,36 @@
+set(ENV{QEMU_LD_PREFIX} "${BROTLI_WRAPPER_LD_PREFIX}")
+
+execute_process(
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --quality=${QUALITY} ${INPUT} --output=${OUTPUT}.br
+ RESULT_VARIABLE result
+ ERROR_VARIABLE result_stderr)
+if(result)
+ message(FATAL_ERROR "Compression failed: ${result_stderr}")
+endif()
+
+execute_process(
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --decompress ${OUTPUT}.br --output=${OUTPUT}.unbr
+ RESULT_VARIABLE result)
+if(result)
+ message(FATAL_ERROR "Decompression failed")
+endif()
+
+function(test_file_equality f1 f2)
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.7)
+ file(SHA512 "${f1}" f1_cs)
+ file(SHA512 "${f2}" f2_cs)
+ if(NOT "${f1_cs}" STREQUAL "${f2_cs}")
+ message(FATAL_ERROR "Files do not match")
+ endif()
+ else()
+ file(READ "${f1}" f1_contents)
+ file(READ "${f2}" f2_contents)
+ if(NOT "${f1_contents}" STREQUAL "${f2_contents}")
+ message(FATAL_ERROR "Files do not match")
+ endif()
+ endif()
+endfunction()
+
+test_file_equality("${INPUT}" "${OUTPUT}.unbr")
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y
new file mode 100644
index 000000000..3f9cf8651
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y
@@ -0,0 +1 @@
+XXXXXXXXXXYYYYYYYYYY \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y.compressed
new file mode 100644
index 000000000..3769516d9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/10x10y.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x
new file mode 100644
index 000000000..caa41718c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x
@@ -0,0 +1 @@
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x.compressed
new file mode 100644
index 000000000..74d0be10a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/64x.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt
new file mode 100644
index 000000000..703365523
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt
@@ -0,0 +1,3609 @@
+
+
+
+
+ ALICE'S ADVENTURES IN WONDERLAND
+
+ Lewis Carroll
+
+ THE MILLENNIUM FULCRUM EDITION 2.9
+
+
+
+
+ CHAPTER I
+
+ Down the Rabbit-Hole
+
+
+ Alice was beginning to get very tired of sitting by her sister
+on the bank, and of having nothing to do: once or twice she had
+peeped into the book her sister was reading, but it had no
+pictures or conversations in it, `and what is the use of a book,'
+thought Alice `without pictures or conversation?'
+
+ So she was considering in her own mind (as well as she could,
+for the hot day made her feel very sleepy and stupid), whether
+the pleasure of making a daisy-chain would be worth the trouble
+of getting up and picking the daisies, when suddenly a White
+Rabbit with pink eyes ran close by her.
+
+ There was nothing so VERY remarkable in that; nor did Alice
+think it so VERY much out of the way to hear the Rabbit say to
+itself, `Oh dear! Oh dear! I shall be late!' (when she thought
+it over afterwards, it occurred to her that she ought to have
+wondered at this, but at the time it all seemed quite natural);
+but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT-
+POCKET, and looked at it, and then hurried on, Alice started to
+her feet, for it flashed across her mind that she had never
+before seen a rabbit with either a waistcoat-pocket, or a watch to
+take out of it, and burning with curiosity, she ran across the
+field after it, and fortunately was just in time to see it pop
+down a large rabbit-hole under the hedge.
+
+ In another moment down went Alice after it, never once
+considering how in the world she was to get out again.
+
+ The rabbit-hole went straight on like a tunnel for some way,
+and then dipped suddenly down, so suddenly that Alice had not a
+moment to think about stopping herself before she found herself
+falling down a very deep well.
+
+ Either the well was very deep, or she fell very slowly, for she
+had plenty of time as she went down to look about her and to
+wonder what was going to happen next. First, she tried to look
+down and make out what she was coming to, but it was too dark to
+see anything; then she looked at the sides of the well, and
+noticed that they were filled with cupboards and book-shelves;
+here and there she saw maps and pictures hung upon pegs. She
+took down a jar from one of the shelves as she passed; it was
+labelled `ORANGE MARMALADE', but to her great disappointment it
+was empty: she did not like to drop the jar for fear of killing
+somebody, so managed to put it into one of the cupboards as she
+fell past it.
+
+ `Well!' thought Alice to herself, `after such a fall as this, I
+shall think nothing of tumbling down stairs! How brave they'll
+all think me at home! Why, I wouldn't say anything about it,
+even if I fell off the top of the house!' (Which was very likely
+true.)
+
+ Down, down, down. Would the fall NEVER come to an end! `I
+wonder how many miles I've fallen by this time?' she said aloud.
+`I must be getting somewhere near the centre of the earth. Let
+me see: that would be four thousand miles down, I think--' (for,
+you see, Alice had learnt several things of this sort in her
+lessons in the schoolroom, and though this was not a VERY good
+opportunity for showing off her knowledge, as there was no one to
+listen to her, still it was good practice to say it over) `--yes,
+that's about the right distance--but then I wonder what Latitude
+or Longitude I've got to?' (Alice had no idea what Latitude was,
+or Longitude either, but thought they were nice grand words to
+say.)
+
+ Presently she began again. `I wonder if I shall fall right
+THROUGH the earth! How funny it'll seem to come out among the
+people that walk with their heads downward! The Antipathies, I
+think--' (she was rather glad there WAS no one listening, this
+time, as it didn't sound at all the right word) `--but I shall
+have to ask them what the name of the country is, you know.
+Please, Ma'am, is this New Zealand or Australia?' (and she tried
+to curtsey as she spoke--fancy CURTSEYING as you're falling
+through the air! Do you think you could manage it?) `And what
+an ignorant little girl she'll think me for asking! No, it'll
+never do to ask: perhaps I shall see it written up somewhere.'
+
+ Down, down, down. There was nothing else to do, so Alice soon
+began talking again. `Dinah'll miss me very much to-night, I
+should think!' (Dinah was the cat.) `I hope they'll remember
+her saucer of milk at tea-time. Dinah my dear! I wish you were
+down here with me! There are no mice in the air, I'm afraid, but
+you might catch a bat, and that's very like a mouse, you know.
+But do cats eat bats, I wonder?' And here Alice began to get
+rather sleepy, and went on saying to herself, in a dreamy sort of
+way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do
+bats eat cats?' for, you see, as she couldn't answer either
+question, it didn't much matter which way she put it. She felt
+that she was dozing off, and had just begun to dream that she
+was walking hand in hand with Dinah, and saying to her very
+earnestly, `Now, Dinah, tell me the truth: did you ever eat a
+bat?' when suddenly, thump! thump! down she came upon a heap of
+sticks and dry leaves, and the fall was over.
+
+ Alice was not a bit hurt, and she jumped up on to her feet in a
+moment: she looked up, but it was all dark overhead; before her
+was another long passage, and the White Rabbit was still in
+sight, hurrying down it. There was not a moment to be lost:
+away went Alice like the wind, and was just in time to hear it
+say, as it turned a corner, `Oh my ears and whiskers, how late
+it's getting!' She was close behind it when she turned the
+corner, but the Rabbit was no longer to be seen: she found
+herself in a long, low hall, which was lit up by a row of lamps
+hanging from the roof.
+
+ There were doors all round the hall, but they were all locked;
+and when Alice had been all the way down one side and up the
+other, trying every door, she walked sadly down the middle,
+wondering how she was ever to get out again.
+
+ Suddenly she came upon a little three-legged table, all made of
+solid glass; there was nothing on it except a tiny golden key,
+and Alice's first thought was that it might belong to one of the
+doors of the hall; but, alas! either the locks were too large, or
+the key was too small, but at any rate it would not open any of
+them. However, on the second time round, she came upon a low
+curtain she had not noticed before, and behind it was a little
+door about fifteen inches high: she tried the little golden key
+in the lock, and to her great delight it fitted!
+
+ Alice opened the door and found that it led into a small
+passage, not much larger than a rat-hole: she knelt down and
+looked along the passage into the loveliest garden you ever saw.
+How she longed to get out of that dark hall, and wander about
+among those beds of bright flowers and those cool fountains, but
+she could not even get her head though the doorway; `and even if
+my head would go through,' thought poor Alice, `it would be of
+very little use without my shoulders. Oh, how I wish
+I could shut up like a telescope! I think I could, if I only
+know how to begin.' For, you see, so many out-of-the-way things
+had happened lately, that Alice had begun to think that very few
+things indeed were really impossible.
+
+ There seemed to be no use in waiting by the little door, so she
+went back to the table, half hoping she might find another key on
+it, or at any rate a book of rules for shutting people up like
+telescopes: this time she found a little bottle on it, (`which
+certainly was not here before,' said Alice,) and round the neck
+of the bottle was a paper label, with the words `DRINK ME'
+beautifully printed on it in large letters.
+
+ It was all very well to say `Drink me,' but the wise little
+Alice was not going to do THAT in a hurry. `No, I'll look
+first,' she said, `and see whether it's marked "poison" or not';
+for she had read several nice little histories about children who
+had got burnt, and eaten up by wild beasts and other unpleasant
+things, all because they WOULD not remember the simple rules
+their friends had taught them: such as, that a red-hot poker
+will burn you if you hold it too long; and that if you cut your
+finger VERY deeply with a knife, it usually bleeds; and she had
+never forgotten that, if you drink much from a bottle marked
+`poison,' it is almost certain to disagree with you, sooner or
+later.
+
+ However, this bottle was NOT marked `poison,' so Alice ventured
+to taste it, and finding it very nice, (it had, in fact, a sort
+of mixed flavour of cherry-tart, custard, pine-apple, roast
+turkey, toffee, and hot buttered toast,) she very soon finished
+it off.
+
+ * * * * * * *
+
+ * * * * * *
+
+ * * * * * * *
+
+ `What a curious feeling!' said Alice; `I must be shutting up
+like a telescope.'
+
+ And so it was indeed: she was now only ten inches high, and
+her face brightened up at the thought that she was now the right
+size for going though the little door into that lovely garden.
+First, however, she waited for a few minutes to see if she was
+going to shrink any further: she felt a little nervous about
+this; `for it might end, you know,' said Alice to herself, `in my
+going out altogether, like a candle. I wonder what I should be
+like then?' And she tried to fancy what the flame of a candle is
+like after the candle is blown out, for she could not remember
+ever having seen such a thing.
+
+ After a while, finding that nothing more happened, she decided
+on going into the garden at once; but, alas for poor Alice! when
+she got to the door, she found he had forgotten the little golden
+key, and when she went back to the table for it, she found she
+could not possibly reach it: she could see it quite plainly
+through the glass, and she tried her best to climb up one of the
+legs of the table, but it was too slippery; and when she had
+tired herself out with trying, the poor little thing sat down and
+cried.
+
+ `Come, there's no use in crying like that!' said Alice to
+herself, rather sharply; `I advise you to leave off this minute!'
+She generally gave herself very good advice, (though she very
+seldom followed it), and sometimes she scolded herself so
+severely as to bring tears into her eyes; and once she remembered
+trying to box her own ears for having cheated herself in a game
+of croquet she was playing against herself, for this curious
+child was very fond of pretending to be two people. `But it's no
+use now,' thought poor Alice, `to pretend to be two people! Why,
+there's hardly enough of me left to make ONE respectable
+person!'
+
+ Soon her eye fell on a little glass box that was lying under
+the table: she opened it, and found in it a very small cake, on
+which the words `EAT ME' were beautifully marked in currants.
+`Well, I'll eat it,' said Alice, `and if it makes me grow larger,
+I can reach the key; and if it makes me grow smaller, I can creep
+under the door; so either way I'll get into the garden, and I
+don't care which happens!'
+
+ She ate a little bit, and said anxiously to herself, `Which
+way? Which way?', holding her hand on the top of her head to
+feel which way it was growing, and she was quite surprised to
+find that she remained the same size: to be sure, this generally
+happens when one eats cake, but Alice had got so much into the
+way of expecting nothing but out-of-the-way things to happen,
+that it seemed quite dull and stupid for life to go on in the
+common way.
+
+ So she set to work, and very soon finished off the cake.
+
+ * * * * * * *
+
+ * * * * * *
+
+ * * * * * * *
+
+
+
+
+ CHAPTER II
+
+ The Pool of Tears
+
+
+ `Curiouser and curiouser!' cried Alice (she was so much
+surprised, that for the moment she quite forgot how to speak good
+English); `now I'm opening out like the largest telescope that
+ever was! Good-bye, feet!' (for when she looked down at her
+feet, they seemed to be almost out of sight, they were getting so
+far off). `Oh, my poor little feet, I wonder who will put on
+your shoes and stockings for you now, dears? I'm sure _I_ shan't
+be able! I shall be a great deal too far off to trouble myself
+about you: you must manage the best way you can; --but I must be
+kind to them,' thought Alice, `or perhaps they won't walk the
+way I want to go! Let me see: I'll give them a new pair of
+boots every Christmas.'
+
+ And she went on planning to herself how she would manage it.
+`They must go by the carrier,' she thought; `and how funny it'll
+seem, sending presents to one's own feet! And how odd the
+directions will look!
+
+ ALICE'S RIGHT FOOT, ESQ.
+ HEARTHRUG,
+ NEAR THE FENDER,
+ (WITH ALICE'S LOVE).
+
+Oh dear, what nonsense I'm talking!'
+
+ Just then her head struck against the roof of the hall: in
+fact she was now more than nine feet high, and she at once took
+up the little golden key and hurried off to the garden door.
+
+ Poor Alice! It was as much as she could do, lying down on one
+side, to look through into the garden with one eye; but to get
+through was more hopeless than ever: she sat down and began to
+cry again.
+
+ `You ought to be ashamed of yourself,' said Alice, `a great
+girl like you,' (she might well say this), `to go on crying in
+this way! Stop this moment, I tell you!' But she went on all
+the same, shedding gallons of tears, until there was a large pool
+all round her, about four inches deep and reaching half down the
+hall.
+
+ After a time she heard a little pattering of feet in the
+distance, and she hastily dried her eyes to see what was coming.
+It was the White Rabbit returning, splendidly dressed, with a
+pair of white kid gloves in one hand and a large fan in the
+other: he came trotting along in a great hurry, muttering to
+himself as he came, `Oh! the Duchess, the Duchess! Oh! won't she
+be savage if I've kept her waiting!' Alice felt so desperate
+that she was ready to ask help of any one; so, when the Rabbit
+came near her, she began, in a low, timid voice, `If you please,
+sir--' The Rabbit started violently, dropped the white kid
+gloves and the fan, and skurried away into the darkness as hard
+as he could go.
+
+ Alice took up the fan and gloves, and, as the hall was very
+hot, she kept fanning herself all the time she went on talking:
+`Dear, dear! How queer everything is to-day! And yesterday
+things went on just as usual. I wonder if I've been changed in
+the night? Let me think: was I the same when I got up this
+morning? I almost think I can remember feeling a little
+different. But if I'm not the same, the next question is, Who in
+the world am I? Ah, THAT'S the great puzzle!' And she began
+thinking over all the children she knew that were of the same age
+as herself, to see if she could have been changed for any of
+them.
+
+ `I'm sure I'm not Ada,' she said, `for her hair goes in such
+long ringlets, and mine doesn't go in ringlets at all; and I'm
+sure I can't be Mabel, for I know all sorts of things, and she,
+oh! she knows such a very little! Besides, SHE'S she, and I'm I,
+and--oh dear, how puzzling it all is! I'll try if I know all the
+things I used to know. Let me see: four times five is twelve,
+and four times six is thirteen, and four times seven is--oh dear!
+I shall never get to twenty at that rate! However, the
+Multiplication Table doesn't signify: let's try Geography.
+London is the capital of Paris, and Paris is the capital of Rome,
+and Rome--no, THAT'S all wrong, I'm certain! I must have been
+changed for Mabel! I'll try and say "How doth the little--"'
+and she crossed her hands on her lap as if she were saying lessons,
+and began to repeat it, but her voice sounded hoarse and
+strange, and the words did not come the same as they used to do:--
+
+ `How doth the little crocodile
+ Improve his shining tail,
+ And pour the waters of the Nile
+ On every golden scale!
+
+ `How cheerfully he seems to grin,
+ How neatly spread his claws,
+ And welcome little fishes in
+ With gently smiling jaws!'
+
+ `I'm sure those are not the right words,' said poor Alice, and
+her eyes filled with tears again as she went on, `I must be Mabel
+after all, and I shall have to go and live in that poky little
+house, and have next to no toys to play with, and oh! ever so
+many lessons to learn! No, I've made up my mind about it; if I'm
+Mabel, I'll stay down here! It'll be no use their putting their
+heads down and saying "Come up again, dear!" I shall only look
+up and say "Who am I then? Tell me that first, and then, if I
+like being that person, I'll come up: if not, I'll stay down
+here till I'm somebody else"--but, oh dear!' cried Alice, with a
+sudden burst of tears, `I do wish they WOULD put their heads
+down! I am so VERY tired of being all alone here!'
+
+ As she said this she looked down at her hands, and was
+surprised to see that she had put on one of the Rabbit's little
+white kid gloves while she was talking. `How CAN I have done
+that?' she thought. `I must be growing small again.' She got up
+and went to the table to measure herself by it, and found that,
+as nearly as she could guess, she was now about two feet high,
+and was going on shrinking rapidly: she soon found out that the
+cause of this was the fan she was holding, and she dropped it
+hastily, just in time to avoid shrinking away altogether.
+
+`That WAS a narrow escape!' said Alice, a good deal frightened at
+the sudden change, but very glad to find herself still in
+existence; `and now for the garden!' and she ran with all speed
+back to the little door: but, alas! the little door was shut
+again, and the little golden key was lying on the glass table as
+before, `and things are worse than ever,' thought the poor child,
+`for I never was so small as this before, never! And I declare
+it's too bad, that it is!'
+
+ As she said these words her foot slipped, and in another
+moment, splash! she was up to her chin in salt water. He first
+idea was that she had somehow fallen into the sea, `and in that
+case I can go back by railway,' she said to herself. (Alice had
+been to the seaside once in her life, and had come to the general
+conclusion, that wherever you go to on the English coast you find
+a number of bathing machines in the sea, some children digging in
+the sand with wooden spades, then a row of lodging houses, and
+behind them a railway station.) However, she soon made out that
+she was in the pool of tears which she had wept when she was nine
+feet high.
+
+ `I wish I hadn't cried so much!' said Alice, as she swam about,
+trying to find her way out. `I shall be punished for it now, I
+suppose, by being drowned in my own tears! That WILL be a queer
+thing, to be sure! However, everything is queer to-day.'
+
+ Just then she heard something splashing about in the pool a
+little way off, and she swam nearer to make out what it was: at
+first she thought it must be a walrus or hippopotamus, but then
+she remembered how small she was now, and she soon made out that
+it was only a mouse that had slipped in like herself.
+
+ `Would it be of any use, now,' thought Alice, `to speak to this
+mouse? Everything is so out-of-the-way down here, that I should
+think very likely it can talk: at any rate, there's no harm in
+trying.' So she began: `O Mouse, do you know the way out of
+this pool? I am very tired of swimming about here, O Mouse!'
+(Alice thought this must be the right way of speaking to a mouse:
+she had never done such a thing before, but she remembered having
+seen in her brother's Latin Grammar, `A mouse--of a mouse--to a
+mouse--a mouse--O mouse!' The Mouse looked at her rather
+inquisitively, and seemed to her to wink with one of its little
+eyes, but it said nothing.
+
+ `Perhaps it doesn't understand English,' thought Alice; `I
+daresay it's a French mouse, come over with William the
+Conqueror.' (For, with all her knowledge of history, Alice had
+no very clear notion how long ago anything had happened.) So she
+began again: `Ou est ma chatte?' which was the first sentence in
+her French lesson-book. The Mouse gave a sudden leap out of the
+water, and seemed to quiver all over with fright. `Oh, I beg
+your pardon!' cried Alice hastily, afraid that she had hurt the
+poor animal's feelings. `I quite forgot you didn't like cats.'
+
+ `Not like cats!' cried the Mouse, in a shrill, passionate
+voice. `Would YOU like cats if you were me?'
+
+ `Well, perhaps not,' said Alice in a soothing tone: `don't be
+angry about it. And yet I wish I could show you our cat Dinah:
+I think you'd take a fancy to cats if you could only see her.
+She is such a dear quiet thing,' Alice went on, half to herself,
+as she swam lazily about in the pool, `and she sits purring so
+nicely by the fire, licking her paws and washing her face--and
+she is such a nice soft thing to nurse--and she's such a capital
+one for catching mice--oh, I beg your pardon!' cried Alice again,
+for this time the Mouse was bristling all over, and she felt
+certain it must be really offended. `We won't talk about her any
+more if you'd rather not.'
+
+ `We indeed!' cried the Mouse, who was trembling down to the end
+of his tail. `As if I would talk on such a subject! Our family
+always HATED cats: nasty, low, vulgar things! Don't let me hear
+the name again!'
+
+ `I won't indeed!' said Alice, in a great hurry to change the
+subject of conversation. `Are you--are you fond--of--of dogs?'
+The Mouse did not answer, so Alice went on eagerly: `There is
+such a nice little dog near our house I should like to show you!
+A little bright-eyed terrier, you know, with oh, such long curly
+brown hair! And it'll fetch things when you throw them, and
+it'll sit up and beg for its dinner, and all sorts of things--I
+can't remember half of them--and it belongs to a farmer, you
+know, and he says it's so useful, it's worth a hundred pounds!
+He says it kills all the rats and--oh dear!' cried Alice in a
+sorrowful tone, `I'm afraid I've offended it again!' For the
+Mouse was swimming away from her as hard as it could go, and
+making quite a commotion in the pool as it went.
+
+ So she called softly after it, `Mouse dear! Do come back
+again, and we won't talk about cats or dogs either, if you don't
+like them!' When the Mouse heard this, it turned round and swam
+slowly back to her: its face was quite pale (with passion, Alice
+thought), and it said in a low trembling voice, `Let us get to
+the shore, and then I'll tell you my history, and you'll
+understand why it is I hate cats and dogs.'
+
+ It was high time to go, for the pool was getting quite crowded
+with the birds and animals that had fallen into it: there were a
+Duck and a Dodo, a Lory and an Eaglet, and several other curious
+creatures. Alice led the way, and the whole party swam to the
+shore.
+
+
+
+ CHAPTER III
+
+ A Caucus-Race and a Long Tale
+
+
+ They were indeed a queer-looking party that assembled on the
+bank--the birds with draggled feathers, the animals with their
+fur clinging close to them, and all dripping wet, cross, and
+uncomfortable.
+
+ The first question of course was, how to get dry again: they
+had a consultation about this, and after a few minutes it seemed
+quite natural to Alice to find herself talking familiarly with
+them, as if she had known them all her life. Indeed, she had
+quite a long argument with the Lory, who at last turned sulky,
+and would only say, `I am older than you, and must know better';
+and this Alice would not allow without knowing how old it was,
+and, as the Lory positively refused to tell its age, there was no
+more to be said.
+
+ At last the Mouse, who seemed to be a person of authority among
+them, called out, `Sit down, all of you, and listen to me! I'LL
+soon make you dry enough!' They all sat down at once, in a large
+ring, with the Mouse in the middle. Alice kept her eyes
+anxiously fixed on it, for she felt sure she would catch a bad
+cold if she did not get dry very soon.
+
+ `Ahem!' said the Mouse with an important air, `are you all ready?
+This is the driest thing I know. Silence all round, if you please!
+"William the Conqueror, whose cause was favoured by the pope, was
+soon submitted to by the English, who wanted leaders, and had been
+of late much accustomed to usurpation and conquest. Edwin and
+Morcar, the earls of Mercia and Northumbria--"'
+
+ `Ugh!' said the Lory, with a shiver.
+
+ `I beg your pardon!' said the Mouse, frowning, but very
+politely: `Did you speak?'
+
+ `Not I!' said the Lory hastily.
+
+ `I thought you did,' said the Mouse. `--I proceed. "Edwin and
+Morcar, the earls of Mercia and Northumbria, declared for him:
+and even Stigand, the patriotic archbishop of Canterbury, found
+it advisable--"'
+
+ `Found WHAT?' said the Duck.
+
+ `Found IT,' the Mouse replied rather crossly: `of course you
+know what "it" means.'
+
+ `I know what "it" means well enough, when I find a thing,' said
+the Duck: `it's generally a frog or a worm. The question is,
+what did the archbishop find?'
+
+ The Mouse did not notice this question, but hurriedly went on,
+`"--found it advisable to go with Edgar Atheling to meet William
+and offer him the crown. William's conduct at first was
+moderate. But the insolence of his Normans--" How are you
+getting on now, my dear?' it continued, turning to Alice as it
+spoke.
+
+ `As wet as ever,' said Alice in a melancholy tone: `it doesn't
+seem to dry me at all.'
+
+ `In that case,' said the Dodo solemnly, rising to its feet, `I
+move that the meeting adjourn, for the immediate adoption of more
+energetic remedies--'
+
+ `Speak English!' said the Eaglet. `I don't know the meaning of
+half those long words, and, what's more, I don't believe you do
+either!' And the Eaglet bent down its head to hide a smile:
+some of the other birds tittered audibly.
+
+ `What I was going to say,' said the Dodo in an offended tone,
+`was, that the best thing to get us dry would be a Caucus-race.'
+
+ `What IS a Caucus-race?' said Alice; not that she wanted much
+to know, but the Dodo had paused as if it thought that SOMEBODY
+ought to speak, and no one else seemed inclined to say anything.
+
+ `Why,' said the Dodo, `the best way to explain it is to do it.'
+(And, as you might like to try the thing yourself, some winter
+day, I will tell you how the Dodo managed it.)
+
+ First it marked out a race-course, in a sort of circle, (`the
+exact shape doesn't matter,' it said,) and then all the party
+were placed along the course, here and there. There was no `One,
+two, three, and away,' but they began running when they liked,
+and left off when they liked, so that it was not easy to know
+when the race was over. However, when they had been running half
+an hour or so, and were quite dry again, the Dodo suddenly called
+out `The race is over!' and they all crowded round it, panting,
+and asking, `But who has won?'
+
+ This question the Dodo could not answer without a great deal of
+thought, and it sat for a long time with one finger pressed upon
+its forehead (the position in which you usually see Shakespeare,
+in the pictures of him), while the rest waited in silence. At
+last the Dodo said, `EVERYBODY has won, and all must have
+prizes.'
+
+ `But who is to give the prizes?' quite a chorus of voices
+asked.
+
+ `Why, SHE, of course,' said the Dodo, pointing to Alice with
+one finger; and the whole party at once crowded round her,
+calling out in a confused way, `Prizes! Prizes!'
+
+ Alice had no idea what to do, and in despair she put her hand
+in her pocket, and pulled out a box of comfits, (luckily the salt
+water had not got into it), and handed them round as prizes.
+There was exactly one a-piece all round.
+
+ `But she must have a prize herself, you know,' said the Mouse.
+
+ `Of course,' the Dodo replied very gravely. `What else have
+you got in your pocket?' he went on, turning to Alice.
+
+ `Only a thimble,' said Alice sadly.
+
+ `Hand it over here,' said the Dodo.
+
+ Then they all crowded round her once more, while the Dodo
+solemnly presented the thimble, saying `We beg your acceptance of
+this elegant thimble'; and, when it had finished this short
+speech, they all cheered.
+
+ Alice thought the whole thing very absurd, but they all looked
+so grave that she did not dare to laugh; and, as she could not
+think of anything to say, she simply bowed, and took the thimble,
+looking as solemn as she could.
+
+ The next thing was to eat the comfits: this caused some noise
+and confusion, as the large birds complained that they could not
+taste theirs, and the small ones choked and had to be patted on
+the back. However, it was over at last, and they sat down again
+in a ring, and begged the Mouse to tell them something more.
+
+ `You promised to tell me your history, you know,' said Alice,
+`and why it is you hate--C and D,' she added in a whisper, half
+afraid that it would be offended again.
+
+ `Mine is a long and a sad tale!' said the Mouse, turning to
+Alice, and sighing.
+
+ `It IS a long tail, certainly,' said Alice, looking down with
+wonder at the Mouse's tail; `but why do you call it sad?' And
+she kept on puzzling about it while the Mouse was speaking, so
+that her idea of the tale was something like this:--
+
+ `Fury said to a
+ mouse, That he
+ met in the
+ house,
+ "Let us
+ both go to
+ law: I will
+ prosecute
+ YOU. --Come,
+ I'll take no
+ denial; We
+ must have a
+ trial: For
+ really this
+ morning I've
+ nothing
+ to do."
+ Said the
+ mouse to the
+ cur, "Such
+ a trial,
+ dear Sir,
+ With
+ no jury
+ or judge,
+ would be
+ wasting
+ our
+ breath."
+ "I'll be
+ judge, I'll
+ be jury,"
+ Said
+ cunning
+ old Fury:
+ "I'll
+ try the
+ whole
+ cause,
+ and
+ condemn
+ you
+ to
+ death."'
+
+
+ `You are not attending!' said the Mouse to Alice severely.
+`What are you thinking of?'
+
+ `I beg your pardon,' said Alice very humbly: `you had got to
+the fifth bend, I think?'
+
+ `I had NOT!' cried the Mouse, sharply and very angrily.
+
+ `A knot!' said Alice, always ready to make herself useful, and
+looking anxiously about her. `Oh, do let me help to undo it!'
+
+ `I shall do nothing of the sort,' said the Mouse, getting up
+and walking away. `You insult me by talking such nonsense!'
+
+ `I didn't mean it!' pleaded poor Alice. `But you're so easily
+offended, you know!'
+
+ The Mouse only growled in reply.
+
+ `Please come back and finish your story!' Alice called after
+it; and the others all joined in chorus, `Yes, please do!' but
+the Mouse only shook its head impatiently, and walked a little
+quicker.
+
+ `What a pity it wouldn't stay!' sighed the Lory, as soon as it
+was quite out of sight; and an old Crab took the opportunity of
+saying to her daughter `Ah, my dear! Let this be a lesson to you
+never to lose YOUR temper!' `Hold your tongue, Ma!' said the
+young Crab, a little snappishly. `You're enough to try the
+patience of an oyster!'
+
+ `I wish I had our Dinah here, I know I do!' said Alice aloud,
+addressing nobody in particular. `She'd soon fetch it back!'
+
+ `And who is Dinah, if I might venture to ask the question?'
+said the Lory.
+
+ Alice replied eagerly, for she was always ready to talk about
+her pet: `Dinah's our cat. And she's such a capital one for
+catching mice you can't think! And oh, I wish you could see her
+after the birds! Why, she'll eat a little bird as soon as look
+at it!'
+
+ This speech caused a remarkable sensation among the party.
+Some of the birds hurried off at once: one the old Magpie began
+wrapping itself up very carefully, remarking, `I really must be
+getting home; the night-air doesn't suit my throat!' and a Canary
+called out in a trembling voice to its children, `Come away, my
+dears! It's high time you were all in bed!' On various pretexts
+they all moved off, and Alice was soon left alone.
+
+ `I wish I hadn't mentioned Dinah!' she said to herself in a
+melancholy tone. `Nobody seems to like her, down here, and I'm
+sure she's the best cat in the world! Oh, my dear Dinah! I
+wonder if I shall ever see you any more!' And here poor Alice
+began to cry again, for she felt very lonely and low-spirited.
+In a little while, however, she again heard a little pattering of
+footsteps in the distance, and she looked up eagerly, half hoping
+that the Mouse had changed his mind, and was coming back to
+finish his story.
+
+
+
+ CHAPTER IV
+
+ The Rabbit Sends in a Little Bill
+
+
+ It was the White Rabbit, trotting slowly back again, and
+looking anxiously about as it went, as if it had lost something;
+and she heard it muttering to itself `The Duchess! The Duchess!
+Oh my dear paws! Oh my fur and whiskers! She'll get me
+executed, as sure as ferrets are ferrets! Where CAN I have
+dropped them, I wonder?' Alice guessed in a moment that it was
+looking for the fan and the pair of white kid gloves, and she
+very good-naturedly began hunting about for them, but they were
+nowhere to be seen--everything seemed to have changed since her
+swim in the pool, and the great hall, with the glass table and
+the little door, had vanished completely.
+
+ Very soon the Rabbit noticed Alice, as she went hunting about,
+and called out to her in an angry tone, `Why, Mary Ann, what ARE
+you doing out here? Run home this moment, and fetch me a pair of
+gloves and a fan! Quick, now!' And Alice was so much frightened
+that she ran off at once in the direction it pointed to, without
+trying to explain the mistake it had made.
+
+ `He took me for his housemaid,' she said to herself as she ran.
+`How surprised he'll be when he finds out who I am! But I'd
+better take him his fan and gloves--that is, if I can find them.'
+As she said this, she came upon a neat little house, on the door
+of which was a bright brass plate with the name `W. RABBIT'
+engraved upon it. She went in without knocking, and hurried
+upstairs, in great fear lest she should meet the real Mary Ann,
+and be turned out of the house before she had found the fan and
+gloves.
+
+ `How queer it seems,' Alice said to herself, `to be going
+messages for a rabbit! I suppose Dinah'll be sending me on
+messages next!' And she began fancying the sort of thing that
+would happen: `"Miss Alice! Come here directly, and get ready
+for your walk!" "Coming in a minute, nurse! But I've got to see
+that the mouse doesn't get out." Only I don't think,' Alice went
+on, `that they'd let Dinah stop in the house if it began ordering
+people about like that!'
+
+ By this time she had found her way into a tidy little room with
+a table in the window, and on it (as she had hoped) a fan and two
+or three pairs of tiny white kid gloves: she took up the fan and
+a pair of the gloves, and was just going to leave the room, when
+her eye fell upon a little bottle that stood near the looking-
+glass. There was no label this time with the words `DRINK ME,'
+but nevertheless she uncorked it and put it to her lips. `I know
+SOMETHING interesting is sure to happen,' she said to herself,
+`whenever I eat or drink anything; so I'll just see what this
+bottle does. I do hope it'll make me grow large again, for
+really I'm quite tired of being such a tiny little thing!'
+
+ It did so indeed, and much sooner than she had expected:
+before she had drunk half the bottle, she found her head pressing
+against the ceiling, and had to stoop to save her neck from being
+broken. She hastily put down the bottle, saying to herself
+`That's quite enough--I hope I shan't grow any more--As it is, I
+can't get out at the door--I do wish I hadn't drunk quite so
+much!'
+
+ Alas! it was too late to wish that! She went on growing, and
+growing, and very soon had to kneel down on the floor: in
+another minute there was not even room for this, and she tried
+the effect of lying down with one elbow against the door, and the
+other arm curled round her head. Still she went on growing, and,
+as a last resource, she put one arm out of the window, and one
+foot up the chimney, and said to herself `Now I can do no more,
+whatever happens. What WILL become of me?'
+
+ Luckily for Alice, the little magic bottle had now had its full
+effect, and she grew no larger: still it was very uncomfortable,
+and, as there seemed to be no sort of chance of her ever getting
+out of the room again, no wonder she felt unhappy.
+
+ `It was much pleasanter at home,' thought poor Alice, `when one
+wasn't always growing larger and smaller, and being ordered about
+by mice and rabbits. I almost wish I hadn't gone down that
+rabbit-hole--and yet--and yet--it's rather curious, you know,
+this sort of life! I do wonder what CAN have happened to me!
+When I used to read fairy-tales, I fancied that kind of thing
+never happened, and now here I am in the middle of one! There
+ought to be a book written about me, that there ought! And when
+I grow up, I'll write one--but I'm grown up now,' she added in a
+sorrowful tone; `at least there's no room to grow up any more
+HERE.'
+
+ `But then,' thought Alice, `shall I NEVER get any older than I
+am now? That'll be a comfort, one way--never to be an old woman-
+-but then--always to have lessons to learn! Oh, I shouldn't like
+THAT!'
+
+ `Oh, you foolish Alice!' she answered herself. `How can you
+learn lessons in here? Why, there's hardly room for YOU, and no
+room at all for any lesson-books!'
+
+ And so she went on, taking first one side and then the other,
+and making quite a conversation of it altogether; but after a few
+minutes she heard a voice outside, and stopped to listen.
+
+ `Mary Ann! Mary Ann!' said the voice. `Fetch me my gloves
+this moment!' Then came a little pattering of feet on the
+stairs. Alice knew it was the Rabbit coming to look for her, and
+she trembled till she shook the house, quite forgetting that she
+was now about a thousand times as large as the Rabbit, and had no
+reason to be afraid of it.
+
+ Presently the Rabbit came up to the door, and tried to open it;
+but, as the door opened inwards, and Alice's elbow was pressed
+hard against it, that attempt proved a failure. Alice heard it
+say to itself `Then I'll go round and get in at the window.'
+
+ `THAT you won't' thought Alice, and, after waiting till she
+fancied she heard the Rabbit just under the window, she suddenly
+spread out her hand, and made a snatch in the air. She did not
+get hold of anything, but she heard a little shriek and a fall,
+and a crash of broken glass, from which she concluded that it was
+just possible it had fallen into a cucumber-frame, or something
+of the sort.
+
+ Next came an angry voice--the Rabbit's--`Pat! Pat! Where are
+you?' And then a voice she had never heard before, `Sure then
+I'm here! Digging for apples, yer honour!'
+
+ `Digging for apples, indeed!' said the Rabbit angrily. `Here!
+Come and help me out of THIS!' (Sounds of more broken glass.)
+
+ `Now tell me, Pat, what's that in the window?'
+
+ `Sure, it's an arm, yer honour!' (He pronounced it `arrum.')
+
+ `An arm, you goose! Who ever saw one that size? Why, it
+fills the whole window!'
+
+ `Sure, it does, yer honour: but it's an arm for all that.'
+
+ `Well, it's got no business there, at any rate: go and take it
+away!'
+
+ There was a long silence after this, and Alice could only hear
+whispers now and then; such as, `Sure, I don't like it, yer
+honour, at all, at all!' `Do as I tell you, you coward!' and at
+last she spread out her hand again, and made another snatch in
+the air. This time there were TWO little shrieks, and more
+sounds of broken glass. `What a number of cucumber-frames there
+must be!' thought Alice. `I wonder what they'll do next! As for
+pulling me out of the window, I only wish they COULD! I'm sure I
+don't want to stay in here any longer!'
+
+ She waited for some time without hearing anything more: at
+last came a rumbling of little cartwheels, and the sound of a
+good many voice all talking together: she made out the words:
+`Where's the other ladder?--Why, I hadn't to bring but one;
+Bill's got the other--Bill! fetch it here, lad!--Here, put 'em up
+at this corner--No, tie 'em together first--they don't reach half
+high enough yet--Oh! they'll do well enough; don't be particular-
+-Here, Bill! catch hold of this rope--Will the roof bear?--Mind
+that loose slate--Oh, it's coming down! Heads below!' (a loud
+crash)--`Now, who did that?--It was Bill, I fancy--Who's to go
+down the chimney?--Nay, I shan't! YOU do it!--That I won't,
+then!--Bill's to go down--Here, Bill! the master says you're to
+go down the chimney!'
+
+ `Oh! So Bill's got to come down the chimney, has he?' said
+Alice to herself. `Shy, they seem to put everything upon Bill!
+I wouldn't be in Bill's place for a good deal: this fireplace is
+narrow, to be sure; but I THINK I can kick a little!'
+
+ She drew her foot as far down the chimney as she could, and
+waited till she heard a little animal (she couldn't guess of what
+sort it was) scratching and scrambling about in the chimney close
+above her: then, saying to herself `This is Bill,' she gave one
+sharp kick, and waited to see what would happen next.
+
+ The first thing she heard was a general chorus of `There goes
+Bill!' then the Rabbit's voice along--`Catch him, you by the
+hedge!' then silence, and then another confusion of voices--`Hold
+up his head--Brandy now--Don't choke him--How was it, old fellow?
+What happened to you? Tell us all about it!'
+
+ Last came a little feeble, squeaking voice, (`That's Bill,'
+thought Alice,) `Well, I hardly know--No more, thank ye; I'm
+better now--but I'm a deal too flustered to tell you--all I know
+is, something comes at me like a Jack-in-the-box, and up I goes
+like a sky-rocket!'
+
+ `So you did, old fellow!' said the others.
+
+ `We must burn the house down!' said the Rabbit's voice; and
+Alice called out as loud as she could, `If you do. I'll set
+Dinah at you!'
+
+ There was a dead silence instantly, and Alice thought to
+herself, `I wonder what they WILL do next! If they had any
+sense, they'd take the roof off.' After a minute or two, they
+began moving about again, and Alice heard the Rabbit say, `A
+barrowful will do, to begin with.'
+
+ `A barrowful of WHAT?' thought Alice; but she had not long to
+doubt, for the next moment a shower of little pebbles came
+rattling in at the window, and some of them hit her in the face.
+`I'll put a stop to this,' she said to herself, and shouted out,
+`You'd better not do that again!' which produced another dead
+silence.
+
+ Alice noticed with some surprise that the pebbles were all
+turning into little cakes as they lay on the floor, and a bright
+idea came into her head. `If I eat one of these cakes,' she
+thought, `it's sure to make SOME change in my size; and as it
+can't possibly make me larger, it must make me smaller, I
+suppose.'
+
+ So she swallowed one of the cakes, and was delighted to find
+that she began shrinking directly. As soon as she was small
+enough to get through the door, she ran out of the house, and
+found quite a crowd of little animals and birds waiting outside.
+The poor little Lizard, Bill, was in the middle, being held up by
+two guinea-pigs, who were giving it something out of a bottle.
+They all made a rush at Alice the moment she appeared; but she
+ran off as hard as she could, and soon found herself safe in a
+thick wood.
+
+ `The first thing I've got to do,' said Alice to herself, as she
+wandered about in the wood, `is to grow to my right size again;
+and the second thing is to find my way into that lovely garden.
+I think that will be the best plan.'
+
+ It sounded an excellent plan, no doubt, and very neatly and
+simply arranged; the only difficulty was, that she had not the
+smallest idea how to set about it; and while she was peering
+about anxiously among the trees, a little sharp bark just over
+her head made her look up in a great hurry.
+
+ An enormous puppy was looking down at her with large round
+eyes, and feebly stretching out one paw, trying to touch her.
+`Poor little thing!' said Alice, in a coaxing tone, and she tried
+hard to whistle to it; but she was terribly frightened all the
+time at the thought that it might be hungry, in which case it
+would be very likely to eat her up in spite of all her coaxing.
+
+ Hardly knowing what she did, she picked up a little bit of
+stick, and held it out to the puppy; whereupon the puppy jumped
+into the air off all its feet at once, with a yelp of delight,
+and rushed at the stick, and made believe to worry it; then Alice
+dodged behind a great thistle, to keep herself from being run
+over; and the moment she appeared on the other side, the puppy
+made another rush at the stick, and tumbled head over heels in
+its hurry to get hold of it; then Alice, thinking it was very
+like having a game of play with a cart-horse, and expecting every
+moment to be trampled under its feet, ran round the thistle
+again; then the puppy began a series of short charges at the
+stick, running a very little way forwards each time and a long
+way back, and barking hoarsely all the while, till at last it sat
+down a good way off, panting, with its tongue hanging out of its
+mouth, and its great eyes half shut.
+
+ This seemed to Alice a good opportunity for making her escape;
+so she set off at once, and ran till she was quite tired and out
+of breath, and till the puppy's bark sounded quite faint in the
+distance.
+
+ `And yet what a dear little puppy it was!' said Alice, as she
+leant against a buttercup to rest herself, and fanned herself
+with one of the leaves: `I should have liked teaching it tricks
+very much, if--if I'd only been the right size to do it! Oh
+dear! I'd nearly forgotten that I've got to grow up again! Let
+me see--how IS it to be managed? I suppose I ought to eat or
+drink something or other; but the great question is, what?'
+
+ The great question certainly was, what? Alice looked all round
+her at the flowers and the blades of grass, but she did not see
+anything that looked like the right thing to eat or drink under
+the circumstances. There was a large mushroom growing near her,
+about the same height as herself; and when she had looked under
+it, and on both sides of it, and behind it, it occurred to her
+that she might as well look and see what was on the top of it.
+
+ She stretched herself up on tiptoe, and peeped over the edge of
+the mushroom, and her eyes immediately met those of a large
+caterpillar, that was sitting on the top with its arms folded,
+quietly smoking a long hookah, and taking not the smallest notice
+of her or of anything else.
+
+
+
+ CHAPTER V
+
+ Advice from a Caterpillar
+
+
+ The Caterpillar and Alice looked at each other for some time in
+silence: at last the Caterpillar took the hookah out of its
+mouth, and addressed her in a languid, sleepy voice.
+
+ `Who are YOU?' said the Caterpillar.
+
+ This was not an encouraging opening for a conversation. Alice
+replied, rather shyly, `I--I hardly know, sir, just at present--
+at least I know who I WAS when I got up this morning, but I think
+I must have been changed several times since then.'
+
+ `What do you mean by that?' said the Caterpillar sternly.
+`Explain yourself!'
+
+ `I can't explain MYSELF, I'm afraid, sir' said Alice, `because
+I'm not myself, you see.'
+
+ `I don't see,' said the Caterpillar.
+
+ `I'm afraid I can't put it more clearly,' Alice replied very
+politely, `for I can't understand it myself to begin with; and
+being so many different sizes in a day is very confusing.'
+
+ `It isn't,' said the Caterpillar.
+
+ `Well, perhaps you haven't found it so yet,' said Alice; `but
+when you have to turn into a chrysalis--you will some day, you
+know--and then after that into a butterfly, I should think you'll
+feel it a little queer, won't you?'
+
+ `Not a bit,' said the Caterpillar.
+
+ `Well, perhaps your feelings may be different,' said Alice;
+`all I know is, it would feel very queer to ME.'
+
+ `You!' said the Caterpillar contemptuously. `Who are YOU?'
+
+ Which brought them back again to the beginning of the
+conversation. Alice felt a little irritated at the Caterpillar's
+making such VERY short remarks, and she drew herself up and said,
+very gravely, `I think, you ought to tell me who YOU are, first.'
+
+ `Why?' said the Caterpillar.
+
+ Here was another puzzling question; and as Alice could not
+think of any good reason, and as the Caterpillar seemed to be in
+a VERY unpleasant state of mind, she turned away.
+
+ `Come back!' the Caterpillar called after her. `I've something
+important to say!'
+
+ This sounded promising, certainly: Alice turned and came back
+again.
+
+ `Keep your temper,' said the Caterpillar.
+
+ `Is that all?' said Alice, swallowing down her anger as well as
+she could.
+
+ `No,' said the Caterpillar.
+
+ Alice thought she might as well wait, as she had nothing else
+to do, and perhaps after all it might tell her something worth
+hearing. For some minutes it puffed away without speaking, but
+at last it unfolded its arms, took the hookah out of its mouth
+again, and said, `So you think you're changed, do you?'
+
+ `I'm afraid I am, sir,' said Alice; `I can't remember things as
+I used--and I don't keep the same size for ten minutes together!'
+
+ `Can't remember WHAT things?' said the Caterpillar.
+
+ `Well, I've tried to say "HOW DOTH THE LITTLE BUSY BEE," but it
+all came different!' Alice replied in a very melancholy voice.
+
+ `Repeat, "YOU ARE OLD, FATHER WILLIAM,"' said the Caterpillar.
+
+ Alice folded her hands, and began:--
+
+ `You are old, Father William,' the young man said,
+ `And your hair has become very white;
+ And yet you incessantly stand on your head--
+ Do you think, at your age, it is right?'
+
+ `In my youth,' Father William replied to his son,
+ `I feared it might injure the brain;
+ But, now that I'm perfectly sure I have none,
+ Why, I do it again and again.'
+
+ `You are old,' said the youth, `as I mentioned before,
+ And have grown most uncommonly fat;
+ Yet you turned a back-somersault in at the door--
+ Pray, what is the reason of that?'
+
+ `In my youth,' said the sage, as he shook his grey locks,
+ `I kept all my limbs very supple
+ By the use of this ointment--one shilling the box--
+ Allow me to sell you a couple?'
+
+ `You are old,' said the youth, `and your jaws are too weak
+ For anything tougher than suet;
+ Yet you finished the goose, with the bones and the beak--
+ Pray how did you manage to do it?'
+
+ `In my youth,' said his father, `I took to the law,
+ And argued each case with my wife;
+ And the muscular strength, which it gave to my jaw,
+ Has lasted the rest of my life.'
+
+ `You are old,' said the youth, `one would hardly suppose
+ That your eye was as steady as ever;
+ Yet you balanced an eel on the end of your nose--
+ What made you so awfully clever?'
+
+ `I have answered three questions, and that is enough,'
+ Said his father; `don't give yourself airs!
+ Do you think I can listen all day to such stuff?
+ Be off, or I'll kick you down stairs!'
+
+
+ `That is not said right,' said the Caterpillar.
+
+ `Not QUITE right, I'm afraid,' said Alice, timidly; `some of the
+words have got altered.'
+
+ `It is wrong from beginning to end,' said the Caterpillar
+decidedly, and there was silence for some minutes.
+
+ The Caterpillar was the first to speak.
+
+ `What size do you want to be?' it asked.
+
+ `Oh, I'm not particular as to size,' Alice hastily replied;
+`only one doesn't like changing so often, you know.'
+
+ `I DON'T know,' said the Caterpillar.
+
+ Alice said nothing: she had never been so much contradicted in
+her life before, and she felt that she was losing her temper.
+
+ `Are you content now?' said the Caterpillar.
+
+ `Well, I should like to be a LITTLE larger, sir, if you
+wouldn't mind,' said Alice: `three inches is such a wretched
+height to be.'
+
+ `It is a very good height indeed!' said the Caterpillar
+angrily, rearing itself upright as it spoke (it was exactly three
+inches high).
+
+ `But I'm not used to it!' pleaded poor Alice in a piteous tone.
+And she thought of herself, `I wish the creatures wouldn't be so
+easily offended!'
+
+ `You'll get used to it in time,' said the Caterpillar; and it
+put the hookah into its mouth and began smoking again.
+
+ This time Alice waited patiently until it chose to speak again.
+In a minute or two the Caterpillar took the hookah out of its
+mouth and yawned once or twice, and shook itself. Then it got
+down off the mushroom, and crawled away in the grass, merely
+remarking as it went, `One side will make you grow taller, and
+the other side will make you grow shorter.'
+
+ `One side of WHAT? The other side of WHAT?' thought Alice to
+herself.
+
+ `Of the mushroom,' said the Caterpillar, just as if she had
+asked it aloud; and in another moment it was out of sight.
+
+ Alice remained looking thoughtfully at the mushroom for a
+minute, trying to make out which were the two sides of it; and as
+it was perfectly round, she found this a very difficult question.
+However, at last she stretched her arms round it as far as they
+would go, and broke off a bit of the edge with each hand.
+
+ `And now which is which?' she said to herself, and nibbled a
+little of the right-hand bit to try the effect: the next moment
+she felt a violent blow underneath her chin: it had struck her
+foot!
+
+ She was a good deal frightened by this very sudden change, but
+she felt that there was no time to be lost, as she was shrinking
+rapidly; so she set to work at once to eat some of the other bit.
+Her chin was pressed so closely against her foot, that there was
+hardly room to open her mouth; but she did it at last, and
+managed to swallow a morsel of the lefthand bit.
+
+
+ * * * * * * *
+
+ * * * * * *
+
+ * * * * * * *
+
+ `Come, my head's free at last!' said Alice in a tone of
+delight, which changed into alarm in another moment, when she
+found that her shoulders were nowhere to be found: all she could
+see, when she looked down, was an immense length of neck, which
+seemed to rise like a stalk out of a sea of green leaves that lay
+far below her.
+
+ `What CAN all that green stuff be?' said Alice. `And where
+HAVE my shoulders got to? And oh, my poor hands, how is it I
+can't see you?' She was moving them about as she spoke, but no
+result seemed to follow, except a little shaking among the
+distant green leaves.
+
+ As there seemed to be no chance of getting her hands up to her
+head, she tried to get her head down to them, and was delighted
+to find that her neck would bend about easily in any direction,
+like a serpent. She had just succeeded in curving it down into a
+graceful zigzag, and was going to dive in among the leaves, which
+she found to be nothing but the tops of the trees under which she
+had been wandering, when a sharp hiss made her draw back in a
+hurry: a large pigeon had flown into her face, and was beating
+her violently with its wings.
+
+ `Serpent!' screamed the Pigeon.
+
+ `I'm NOT a serpent!' said Alice indignantly. `Let me alone!'
+
+ `Serpent, I say again!' repeated the Pigeon, but in a more
+subdued tone, and added with a kind of sob, `I've tried every
+way, and nothing seems to suit them!'
+
+ `I haven't the least idea what you're talking about,' said
+Alice.
+
+ `I've tried the roots of trees, and I've tried banks, and I've
+tried hedges,' the Pigeon went on, without attending to her; `but
+those serpents! There's no pleasing them!'
+
+ Alice was more and more puzzled, but she thought there was no
+use in saying anything more till the Pigeon had finished.
+
+ `As if it wasn't trouble enough hatching the eggs,' said the
+Pigeon; `but I must be on the look-out for serpents night and
+day! Why, I haven't had a wink of sleep these three weeks!'
+
+ `I'm very sorry you've been annoyed,' said Alice, who was
+beginning to see its meaning.
+
+ `And just as I'd taken the highest tree in the wood,' continued
+the Pigeon, raising its voice to a shriek, `and just as I was
+thinking I should be free of them at last, they must needs come
+wriggling down from the sky! Ugh, Serpent!'
+
+ `But I'm NOT a serpent, I tell you!' said Alice. `I'm a--I'm
+a--'
+
+ `Well! WHAT are you?' said the Pigeon. `I can see you're
+trying to invent something!'
+
+ `I--I'm a little girl,' said Alice, rather doubtfully, as she
+remembered the number of changes she had gone through that day.
+
+ `A likely story indeed!' said the Pigeon in a tone of the
+deepest contempt. `I've seen a good many little girls in my
+time, but never ONE with such a neck as that! No, no! You're a
+serpent; and there's no use denying it. I suppose you'll be
+telling me next that you never tasted an egg!'
+
+ `I HAVE tasted eggs, certainly,' said Alice, who was a very
+truthful child; `but little girls eat eggs quite as much as
+serpents do, you know.'
+
+ `I don't believe it,' said the Pigeon; `but if they do, why
+then they're a kind of serpent, that's all I can say.'
+
+ This was such a new idea to Alice, that she was quite silent
+for a minute or two, which gave the Pigeon the opportunity of
+adding, `You're looking for eggs, I know THAT well enough; and
+what does it matter to me whether you're a little girl or a
+serpent?'
+
+ `It matters a good deal to ME,' said Alice hastily; `but I'm
+not looking for eggs, as it happens; and if I was, I shouldn't
+want YOURS: I don't like them raw.'
+
+ `Well, be off, then!' said the Pigeon in a sulky tone, as it
+settled down again into its nest. Alice crouched down among the
+trees as well as she could, for her neck kept getting entangled
+among the branches, and every now and then she had to stop and
+untwist it. After a while she remembered that she still held the
+pieces of mushroom in her hands, and she set to work very
+carefully, nibbling first at one and then at the other, and
+growing sometimes taller and sometimes shorter, until she had
+succeeded in bringing herself down to her usual height.
+
+ It was so long since she had been anything near the right size,
+that it felt quite strange at first; but she got used to it in a
+few minutes, and began talking to herself, as usual. `Come,
+there's half my plan done now! How puzzling all these changes
+are! I'm never sure what I'm going to be, from one minute to
+another! However, I've got back to my right size: the next
+thing is, to get into that beautiful garden--how IS that to be
+done, I wonder?' As she said this, she came suddenly upon an
+open place, with a little house in it about four feet high.
+`Whoever lives there,' thought Alice, `it'll never do to come
+upon them THIS size: why, I should frighten them out of their
+wits!' So she began nibbling at the righthand bit again, and did
+not venture to go near the house till she had brought herself
+down to nine inches high.
+
+
+
+ CHAPTER VI
+
+ Pig and Pepper
+
+
+ For a minute or two she stood looking at the house, and
+wondering what to do next, when suddenly a footman in livery came
+running out of the wood--(she considered him to be a footman
+because he was in livery: otherwise, judging by his face only,
+she would have called him a fish)--and rapped loudly at the door
+with his knuckles. It was opened by another footman in livery,
+with a round face, and large eyes like a frog; and both footmen,
+Alice noticed, had powdered hair that curled all over their
+heads. She felt very curious to know what it was all about, and
+crept a little way out of the wood to listen.
+
+ The Fish-Footman began by producing from under his arm a great
+letter, nearly as large as himself, and this he handed over to
+the other, saying, in a solemn tone, `For the Duchess. An
+invitation from the Queen to play croquet.' The Frog-Footman
+repeated, in the same solemn tone, only changing the order of the
+words a little, `From the Queen. An invitation for the Duchess
+to play croquet.'
+
+ Then they both bowed low, and their curls got entangled
+together.
+
+ Alice laughed so much at this, that she had to run back into
+the wood for fear of their hearing her; and when she next peeped
+out the Fish-Footman was gone, and the other was sitting on the
+ground near the door, staring stupidly up into the sky.
+
+ Alice went timidly up to the door, and knocked.
+
+ `There's no sort of use in knocking,' said the Footman, `and
+that for two reasons. First, because I'm on the same side of the
+door as you are; secondly, because they're making such a noise
+inside, no one could possibly hear you.' And certainly there was
+a most extraordinary noise going on within--a constant howling
+and sneezing, and every now and then a great crash, as if a dish
+or kettle had been broken to pieces.
+
+ `Please, then,' said Alice, `how am I to get in?'
+
+ `There might be some sense in your knocking,' the Footman went
+on without attending to her, `if we had the door between us. For
+instance, if you were INSIDE, you might knock, and I could let
+you out, you know.' He was looking up into the sky all the time
+he was speaking, and this Alice thought decidedly uncivil. `But
+perhaps he can't help it,' she said to herself; `his eyes are so
+VERY nearly at the top of his head. But at any rate he might
+answer questions.--How am I to get in?' she repeated, aloud.
+
+ `I shall sit here,' the Footman remarked, `till tomorrow--'
+
+ At this moment the door of the house opened, and a large plate
+came skimming out, straight at the Footman's head: it just
+grazed his nose, and broke to pieces against one of the trees
+behind him.
+
+ `--or next day, maybe,' the Footman continued in the same tone,
+exactly as if nothing had happened.
+
+ `How am I to get in?' asked Alice again, in a louder tone.
+
+ `ARE you to get in at all?' said the Footman. `That's the
+first question, you know.'
+
+ It was, no doubt: only Alice did not like to be told so.
+`It's really dreadful,' she muttered to herself, `the way all the
+creatures argue. It's enough to drive one crazy!'
+
+ The Footman seemed to think this a good opportunity for
+repeating his remark, with variations. `I shall sit here,' he
+said, `on and off, for days and days.'
+
+ `But what am I to do?' said Alice.
+
+ `Anything you like,' said the Footman, and began whistling.
+
+ `Oh, there's no use in talking to him,' said Alice desperately:
+`he's perfectly idiotic!' And she opened the door and went in.
+
+ The door led right into a large kitchen, which was full of
+smoke from one end to the other: the Duchess was sitting on a
+three-legged stool in the middle, nursing a baby; the cook was
+leaning over the fire, stirring a large cauldron which seemed to
+be full of soup.
+
+ `There's certainly too much pepper in that soup!' Alice said to
+herself, as well as she could for sneezing.
+
+ There was certainly too much of it in the air. Even the
+Duchess sneezed occasionally; and as for the baby, it was
+sneezing and howling alternately without a moment's pause. The
+only things in the kitchen that did not sneeze, were the cook,
+and a large cat which was sitting on the hearth and grinning from
+ear to ear.
+
+ `Please would you tell me,' said Alice, a little timidly, for
+she was not quite sure whether it was good manners for her to
+speak first, `why your cat grins like that?'
+
+ `It's a Cheshire cat,' said the Duchess, `and that's why.
+Pig!'
+
+ She said the last word with such sudden violence that Alice
+quite jumped; but she saw in another moment that it was addressed
+to the baby, and not to her, so she took courage, and went on
+again:--
+
+ `I didn't know that Cheshire cats always grinned; in fact, I
+didn't know that cats COULD grin.'
+
+ `They all can,' said the Duchess; `and most of 'em do.'
+
+ `I don't know of any that do,' Alice said very politely,
+feeling quite pleased to have got into a conversation.
+
+ `You don't know much,' said the Duchess; `and that's a fact.'
+
+ Alice did not at all like the tone of this remark, and thought
+it would be as well to introduce some other subject of
+conversation. While she was trying to fix on one, the cook took
+the cauldron of soup off the fire, and at once set to work
+throwing everything within her reach at the Duchess and the baby
+--the fire-irons came first; then followed a shower of saucepans,
+plates, and dishes. The Duchess took no notice of them even when
+they hit her; and the baby was howling so much already, that it
+was quite impossible to say whether the blows hurt it or not.
+
+ `Oh, PLEASE mind what you're doing!' cried Alice, jumping up
+and down in an agony of terror. `Oh, there goes his PRECIOUS
+nose'; as an unusually large saucepan flew close by it, and very
+nearly carried it off.
+
+ `If everybody minded their own business,' the Duchess said in a
+hoarse growl, `the world would go round a deal faster than it
+does.'
+
+ `Which would NOT be an advantage,' said Alice, who felt very
+glad to get an opportunity of showing off a little of her
+knowledge. `Just think of what work it would make with the day
+and night! You see the earth takes twenty-four hours to turn
+round on its axis--'
+
+ `Talking of axes,' said the Duchess, `chop off her head!'
+
+ Alice glanced rather anxiously at the cook, to see if she meant
+to take the hint; but the cook was busily stirring the soup, and
+seemed not to be listening, so she went on again: `Twenty-four
+hours, I THINK; or is it twelve? I--'
+
+ `Oh, don't bother ME,' said the Duchess; `I never could abide
+figures!' And with that she began nursing her child again,
+singing a sort of lullaby to it as she did so, and giving it a
+violent shake at the end of every line:
+
+ `Speak roughly to your little boy,
+ And beat him when he sneezes:
+ He only does it to annoy,
+ Because he knows it teases.'
+
+ CHORUS.
+
+ (In which the cook and the baby joined):--
+
+ `Wow! wow! wow!'
+
+ While the Duchess sang the second verse of the song, she kept
+tossing the baby violently up and down, and the poor little thing
+howled so, that Alice could hardly hear the words:--
+
+ `I speak severely to my boy,
+ I beat him when he sneezes;
+ For he can thoroughly enjoy
+ The pepper when he pleases!'
+
+ CHORUS.
+
+ `Wow! wow! wow!'
+
+ `Here! you may nurse it a bit, if you like!' the Duchess said
+to Alice, flinging the baby at her as she spoke. `I must go and
+get ready to play croquet with the Queen,' and she hurried out of
+the room. The cook threw a frying-pan after her as she went out,
+but it just missed her.
+
+ Alice caught the baby with some difficulty, as it was a queer-
+shaped little creature, and held out its arms and legs in all
+directions, `just like a star-fish,' thought Alice. The poor
+little thing was snorting like a steam-engine when she caught it,
+and kept doubling itself up and straightening itself out again,
+so that altogether, for the first minute or two, it was as much
+as she could do to hold it.
+
+ As soon as she had made out the proper way of nursing it,
+(which was to twist it up into a sort of knot, and then keep
+tight hold of its right ear and left foot, so as to prevent its
+undoing itself,) she carried it out into the open air. `IF I
+don't take this child away with me,' thought Alice, `they're sure
+to kill it in a day or two: wouldn't it be murder to leave it
+behind?' She said the last words out loud, and the little thing
+grunted in reply (it had left off sneezing by this time). `Don't
+grunt,' said Alice; `that's not at all a proper way of expressing
+yourself.'
+
+ The baby grunted again, and Alice looked very anxiously into
+its face to see what was the matter with it. There could be no
+doubt that it had a VERY turn-up nose, much more like a snout
+than a real nose; also its eyes were getting extremely small for
+a baby: altogether Alice did not like the look of the thing at
+all. `But perhaps it was only sobbing,' she thought, and looked
+into its eyes again, to see if there were any tears.
+
+ No, there were no tears. `If you're going to turn into a pig,
+my dear,' said Alice, seriously, `I'll have nothing more to do
+with you. Mind now!' The poor little thing sobbed again (or
+grunted, it was impossible to say which), and they went on for
+some while in silence.
+
+ Alice was just beginning to think to herself, `Now, what am I
+to do with this creature when I get it home?' when it grunted
+again, so violently, that she looked down into its face in some
+alarm. This time there could be NO mistake about it: it was
+neither more nor less than a pig, and she felt that it would be
+quite absurd for her to carry it further.
+
+ So she set the little creature down, and felt quite relieved to
+see it trot away quietly into the wood. `If it had grown up,'
+she said to herself, `it would have made a dreadfully ugly child:
+but it makes rather a handsome pig, I think.' And she began
+thinking over other children she knew, who might do very well as
+pigs, and was just saying to herself, `if one only knew the right
+way to change them--' when she was a little startled by seeing
+the Cheshire Cat sitting on a bough of a tree a few yards off.
+
+ The Cat only grinned when it saw Alice. It looked good-
+natured, she thought: still it had VERY long claws and a great
+many teeth, so she felt that it ought to be treated with respect.
+
+ `Cheshire Puss,' she began, rather timidly, as she did not at
+all know whether it would like the name: however, it only
+grinned a little wider. `Come, it's pleased so far,' thought
+Alice, and she went on. `Would you tell me, please, which way I
+ought to go from here?'
+
+ `That depends a good deal on where you want to get to,' said
+the Cat.
+
+ `I don't much care where--' said Alice.
+
+ `Then it doesn't matter which way you go,' said the Cat.
+
+ `--so long as I get SOMEWHERE,' Alice added as an explanation.
+
+ `Oh, you're sure to do that,' said the Cat, `if you only walk
+long enough.'
+
+ Alice felt that this could not be denied, so she tried another
+question. `What sort of people live about here?'
+
+ `In THAT direction,' the Cat said, waving its right paw round,
+`lives a Hatter: and in THAT direction,' waving the other paw,
+`lives a March Hare. Visit either you like: they're both mad.'
+
+ `But I don't want to go among mad people,' Alice remarked.
+
+ `Oh, you can't help that,' said the Cat: `we're all mad here.
+I'm mad. You're mad.'
+
+ `How do you know I'm mad?' said Alice.
+
+ `You must be,' said the Cat, `or you wouldn't have come here.'
+
+ Alice didn't think that proved it at all; however, she went on
+`And how do you know that you're mad?'
+
+ `To begin with,' said the Cat, `a dog's not mad. You grant
+that?'
+
+ `I suppose so,' said Alice.
+
+ `Well, then,' the Cat went on, `you see, a dog growls when it's
+angry, and wags its tail when it's pleased. Now I growl when I'm
+pleased, and wag my tail when I'm angry. Therefore I'm mad.'
+
+ `I call it purring, not growling,' said Alice.
+
+ `Call it what you like,' said the Cat. `Do you play croquet
+with the Queen to-day?'
+
+ `I should like it very much,' said Alice, `but I haven't been
+invited yet.'
+
+ `You'll see me there,' said the Cat, and vanished.
+
+ Alice was not much surprised at this, she was getting so used
+to queer things happening. While she was looking at the place
+where it had been, it suddenly appeared again.
+
+ `By-the-bye, what became of the baby?' said the Cat. `I'd
+nearly forgotten to ask.'
+
+ `It turned into a pig,' Alice quietly said, just as if it had
+come back in a natural way.
+
+ `I thought it would,' said the Cat, and vanished again.
+
+ Alice waited a little, half expecting to see it again, but it
+did not appear, and after a minute or two she walked on in the
+direction in which the March Hare was said to live. `I've seen
+hatters before,' she said to herself; `the March Hare will be
+much the most interesting, and perhaps as this is May it won't be
+raving mad--at least not so mad as it was in March.' As she said
+this, she looked up, and there was the Cat again, sitting on a
+branch of a tree.
+
+ `Did you say pig, or fig?' said the Cat.
+
+ `I said pig,' replied Alice; `and I wish you wouldn't keep
+appearing and vanishing so suddenly: you make one quite giddy.'
+
+ `All right,' said the Cat; and this time it vanished quite
+slowly, beginning with the end of the tail, and ending with the
+grin, which remained some time after the rest of it had gone.
+
+ `Well! I've often seen a cat without a grin,' thought Alice;
+`but a grin without a cat! It's the most curious thing I ever
+say in my life!'
+
+ She had not gone much farther before she came in sight of the
+house of the March Hare: she thought it must be the right house,
+because the chimneys were shaped like ears and the roof was
+thatched with fur. It was so large a house, that she did not
+like to go nearer till she had nibbled some more of the lefthand
+bit of mushroom, and raised herself to about two feet high: even
+then she walked up towards it rather timidly, saying to herself
+`Suppose it should be raving mad after all! I almost wish I'd
+gone to see the Hatter instead!'
+
+
+
+ CHAPTER VII
+
+ A Mad Tea-Party
+
+
+ There was a table set out under a tree in front of the house,
+and the March Hare and the Hatter were having tea at it: a
+Dormouse was sitting between them, fast asleep, and the other two
+were using it as a cushion, resting their elbows on it, and the
+talking over its head. `Very uncomfortable for the Dormouse,'
+thought Alice; `only, as it's asleep, I suppose it doesn't mind.'
+
+ The table was a large one, but the three were all crowded
+together at one corner of it: `No room! No room!' they cried
+out when they saw Alice coming. `There's PLENTY of room!' said
+Alice indignantly, and she sat down in a large arm-chair at one
+end of the table.
+
+ `Have some wine,' the March Hare said in an encouraging tone.
+
+ Alice looked all round the table, but there was nothing on it
+but tea. `I don't see any wine,' she remarked.
+
+ `There isn't any,' said the March Hare.
+
+ `Then it wasn't very civil of you to offer it,' said Alice
+angrily.
+
+ `It wasn't very civil of you to sit down without being
+invited,' said the March Hare.
+
+ `I didn't know it was YOUR table,' said Alice; `it's laid for a
+great many more than three.'
+
+ `Your hair wants cutting,' said the Hatter. He had been
+looking at Alice for some time with great curiosity, and this was
+his first speech.
+
+ `You should learn not to make personal remarks,' Alice said
+with some severity; `it's very rude.'
+
+ The Hatter opened his eyes very wide on hearing this; but all
+he SAID was, `Why is a raven like a writing-desk?'
+
+ `Come, we shall have some fun now!' thought Alice. `I'm glad
+they've begun asking riddles.--I believe I can guess that,' she
+added aloud.
+
+ `Do you mean that you think you can find out the answer to it?'
+said the March Hare.
+
+ `Exactly so,' said Alice.
+
+ `Then you should say what you mean,' the March Hare went on.
+
+ `I do,' Alice hastily replied; `at least--at least I mean what
+I say--that's the same thing, you know.'
+
+ `Not the same thing a bit!' said the Hatter. `You might just
+as well say that "I see what I eat" is the same thing as "I eat
+what I see"!'
+
+ `You might just as well say,' added the March Hare, `that "I
+like what I get" is the same thing as "I get what I like"!'
+
+ `You might just as well say,' added the Dormouse, who seemed to
+be talking in his sleep, `that "I breathe when I sleep" is the
+same thing as "I sleep when I breathe"!'
+
+ `It IS the same thing with you,' said the Hatter, and here the
+conversation dropped, and the party sat silent for a minute,
+while Alice thought over all she could remember about ravens and
+writing-desks, which wasn't much.
+
+ The Hatter was the first to break the silence. `What day of
+the month is it?' he said, turning to Alice: he had taken his
+watch out of his pocket, and was looking at it uneasily, shaking
+it every now and then, and holding it to his ear.
+
+ Alice considered a little, and then said `The fourth.'
+
+ `Two days wrong!' sighed the Hatter. `I told you butter
+wouldn't suit the works!' he added looking angrily at the March
+Hare.
+
+ `It was the BEST butter,' the March Hare meekly replied.
+
+ `Yes, but some crumbs must have got in as well,' the Hatter
+grumbled: `you shouldn't have put it in with the bread-knife.'
+
+ The March Hare took the watch and looked at it gloomily: then
+he dipped it into his cup of tea, and looked at it again: but he
+could think of nothing better to say than his first remark, `It
+was the BEST butter, you know.'
+
+ Alice had been looking over his shoulder with some curiosity.
+`What a funny watch!' she remarked. `It tells the day of the
+month, and doesn't tell what o'clock it is!'
+
+ `Why should it?' muttered the Hatter. `Does YOUR watch tell
+you what year it is?'
+
+ `Of course not,' Alice replied very readily: `but that's
+because it stays the same year for such a long time together.'
+
+ `Which is just the case with MINE,' said the Hatter.
+
+ Alice felt dreadfully puzzled. The Hatter's remark seemed to
+have no sort of meaning in it, and yet it was certainly English.
+`I don't quite understand you,' she said, as politely as she
+could.
+
+ `The Dormouse is asleep again,' said the Hatter, and he poured
+a little hot tea upon its nose.
+
+ The Dormouse shook its head impatiently, and said, without
+opening its eyes, `Of course, of course; just what I was going to
+remark myself.'
+
+ `Have you guessed the riddle yet?' the Hatter said, turning to
+Alice again.
+
+ `No, I give it up,' Alice replied: `what's the answer?'
+
+ `I haven't the slightest idea,' said the Hatter.
+
+ `Nor I,' said the March Hare.
+
+ Alice sighed wearily. `I think you might do something better
+with the time,' she said, `than waste it in asking riddles that
+have no answers.'
+
+ `If you knew Time as well as I do,' said the Hatter, `you
+wouldn't talk about wasting IT. It's HIM.'
+
+ `I don't know what you mean,' said Alice.
+
+ `Of course you don't!' the Hatter said, tossing his head
+contemptuously. `I dare say you never even spoke to Time!'
+
+ `Perhaps not,' Alice cautiously replied: `but I know I have to
+beat time when I learn music.'
+
+ `Ah! that accounts for it,' said the Hatter. `He won't stand
+beating. Now, if you only kept on good terms with him, he'd do
+almost anything you liked with the clock. For instance, suppose
+it were nine o'clock in the morning, just time to begin lessons:
+you'd only have to whisper a hint to Time, and round goes the
+clock in a twinkling! Half-past one, time for dinner!'
+
+ (`I only wish it was,' the March Hare said to itself in a
+whisper.)
+
+ `That would be grand, certainly,' said Alice thoughtfully:
+`but then--I shouldn't be hungry for it, you know.'
+
+ `Not at first, perhaps,' said the Hatter: `but you could keep
+it to half-past one as long as you liked.'
+
+ `Is that the way YOU manage?' Alice asked.
+
+ The Hatter shook his head mournfully. `Not I!' he replied.
+`We quarrelled last March--just before HE went mad, you know--'
+(pointing with his tea spoon at the March Hare,) `--it was at the
+great concert given by the Queen of Hearts, and I had to sing
+
+ "Twinkle, twinkle, little bat!
+ How I wonder what you're at!"
+
+You know the song, perhaps?'
+
+ `I've heard something like it,' said Alice.
+
+ `It goes on, you know,' the Hatter continued, `in this way:--
+
+ "Up above the world you fly,
+ Like a tea-tray in the sky.
+ Twinkle, twinkle--"'
+
+Here the Dormouse shook itself, and began singing in its sleep
+`Twinkle, twinkle, twinkle, twinkle--' and went on so long that
+they had to pinch it to make it stop.
+
+ `Well, I'd hardly finished the first verse,' said the Hatter,
+`when the Queen jumped up and bawled out, "He's murdering the
+time! Off with his head!"'
+
+ `How dreadfully savage!' exclaimed Alice.
+
+ `And ever since that,' the Hatter went on in a mournful tone,
+`he won't do a thing I ask! It's always six o'clock now.'
+
+ A bright idea came into Alice's head. `Is that the reason so
+many tea-things are put out here?' she asked.
+
+ `Yes, that's it,' said the Hatter with a sigh: `it's always
+tea-time, and we've no time to wash the things between whiles.'
+
+ `Then you keep moving round, I suppose?' said Alice.
+
+ `Exactly so,' said the Hatter: `as the things get used up.'
+
+ `But what happens when you come to the beginning again?' Alice
+ventured to ask.
+
+ `Suppose we change the subject,' the March Hare interrupted,
+yawning. `I'm getting tired of this. I vote the young lady
+tells us a story.'
+
+ `I'm afraid I don't know one,' said Alice, rather alarmed at
+the proposal.
+
+ `Then the Dormouse shall!' they both cried. `Wake up,
+Dormouse!' And they pinched it on both sides at once.
+
+ The Dormouse slowly opened his eyes. `I wasn't asleep,' he
+said in a hoarse, feeble voice: `I heard every word you fellows
+were saying.'
+
+ `Tell us a story!' said the March Hare.
+
+ `Yes, please do!' pleaded Alice.
+
+ `And be quick about it,' added the Hatter, `or you'll be asleep
+again before it's done.'
+
+ `Once upon a time there were three little sisters,' the
+Dormouse began in a great hurry; `and their names were Elsie,
+Lacie, and Tillie; and they lived at the bottom of a well--'
+
+ `What did they live on?' said Alice, who always took a great
+interest in questions of eating and drinking.
+
+ `They lived on treacle,' said the Dormouse, after thinking a
+minute or two.
+
+ `They couldn't have done that, you know,' Alice gently
+remarked; `they'd have been ill.'
+
+ `So they were,' said the Dormouse; `VERY ill.'
+
+ Alice tried to fancy to herself what such an extraordinary ways
+of living would be like, but it puzzled her too much, so she went
+on: `But why did they live at the bottom of a well?'
+
+ `Take some more tea,' the March Hare said to Alice, very
+earnestly.
+
+ `I've had nothing yet,' Alice replied in an offended tone, `so
+I can't take more.'
+
+ `You mean you can't take LESS,' said the Hatter: `it's very
+easy to take MORE than nothing.'
+
+ `Nobody asked YOUR opinion,' said Alice.
+
+ `Who's making personal remarks now?' the Hatter asked
+triumphantly.
+
+ Alice did not quite know what to say to this: so she helped
+herself to some tea and bread-and-butter, and then turned to the
+Dormouse, and repeated her question. `Why did they live at the
+bottom of a well?'
+
+ The Dormouse again took a minute or two to think about it, and
+then said, `It was a treacle-well.'
+
+ `There's no such thing!' Alice was beginning very angrily, but
+the Hatter and the March Hare went `Sh! sh!' and the Dormouse
+sulkily remarked, `If you can't be civil, you'd better finish the
+story for yourself.'
+
+ `No, please go on!' Alice said very humbly; `I won't interrupt
+again. I dare say there may be ONE.'
+
+ `One, indeed!' said the Dormouse indignantly. However, he
+consented to go on. `And so these three little sisters--they
+were learning to draw, you know--'
+
+ `What did they draw?' said Alice, quite forgetting her promise.
+
+ `Treacle,' said the Dormouse, without considering at all this
+time.
+
+ `I want a clean cup,' interrupted the Hatter: `let's all move
+one place on.'
+
+ He moved on as he spoke, and the Dormouse followed him: the
+March Hare moved into the Dormouse's place, and Alice rather
+unwillingly took the place of the March Hare. The Hatter was the
+only one who got any advantage from the change: and Alice was a
+good deal worse off than before, as the March Hare had just upset
+the milk-jug into his plate.
+
+ Alice did not wish to offend the Dormouse again, so she began
+very cautiously: `But I don't understand. Where did they draw
+the treacle from?'
+
+ `You can draw water out of a water-well,' said the Hatter; `so
+I should think you could draw treacle out of a treacle-well--eh,
+stupid?'
+
+ `But they were IN the well,' Alice said to the Dormouse, not
+choosing to notice this last remark.
+
+ `Of course they were', said the Dormouse; `--well in.'
+
+ This answer so confused poor Alice, that she let the Dormouse
+go on for some time without interrupting it.
+
+ `They were learning to draw,' the Dormouse went on, yawning and
+rubbing its eyes, for it was getting very sleepy; `and they drew
+all manner of things--everything that begins with an M--'
+
+ `Why with an M?' said Alice.
+
+ `Why not?' said the March Hare.
+
+ Alice was silent.
+
+ The Dormouse had closed its eyes by this time, and was going
+off into a doze; but, on being pinched by the Hatter, it woke up
+again with a little shriek, and went on: `--that begins with an
+M, such as mouse-traps, and the moon, and memory, and muchness--
+you know you say things are "much of a muchness"--did you ever
+see such a thing as a drawing of a muchness?'
+
+ `Really, now you ask me,' said Alice, very much confused, `I
+don't think--'
+
+ `Then you shouldn't talk,' said the Hatter.
+
+ This piece of rudeness was more than Alice could bear: she got
+up in great disgust, and walked off; the Dormouse fell asleep
+instantly, and neither of the others took the least notice of her
+going, though she looked back once or twice, half hoping that
+they would call after her: the last time she saw them, they were
+trying to put the Dormouse into the teapot.
+
+ `At any rate I'll never go THERE again!' said Alice as she
+picked her way through the wood. `It's the stupidest tea-party I
+ever was at in all my life!'
+
+ Just as she said this, she noticed that one of the trees had a
+door leading right into it. `That's very curious!' she thought.
+`But everything's curious today. I think I may as well go in at
+once.' And in she went.
+
+ Once more she found herself in the long hall, and close to the
+little glass table. `Now, I'll manage better this time,' she
+said to herself, and began by taking the little golden key, and
+unlocking the door that led into the garden. Then she went to
+work nibbling at the mushroom (she had kept a piece of it in her
+pocked) till she was about a foot high: then she walked down the
+little passage: and THEN--she found herself at last in the
+beautiful garden, among the bright flower-beds and the cool
+fountains.
+
+
+
+ CHAPTER VIII
+
+ The Queen's Croquet-Ground
+
+
+ A large rose-tree stood near the entrance of the garden: the
+roses growing on it were white, but there were three gardeners at
+it, busily painting them red. Alice thought this a very curious
+thing, and she went nearer to watch them, and just as she came up
+to them she heard one of them say, `Look out now, Five! Don't go
+splashing paint over me like that!'
+
+ `I couldn't help it,' said Five, in a sulky tone; `Seven jogged
+my elbow.'
+
+ On which Seven looked up and said, `That's right, Five! Always
+lay the blame on others!'
+
+ `YOU'D better not talk!' said Five. `I heard the Queen say only
+yesterday you deserved to be beheaded!'
+
+ `What for?' said the one who had spoken first.
+
+ `That's none of YOUR business, Two!' said Seven.
+
+ `Yes, it IS his business!' said Five, `and I'll tell him--it
+was for bringing the cook tulip-roots instead of onions.'
+
+ Seven flung down his brush, and had just begun `Well, of all
+the unjust things--' when his eye chanced to fall upon Alice, as
+she stood watching them, and he checked himself suddenly: the
+others looked round also, and all of them bowed low.
+
+ `Would you tell me,' said Alice, a little timidly, `why you are
+painting those roses?'
+
+ Five and Seven said nothing, but looked at Two. Two began in a
+low voice, `Why the fact is, you see, Miss, this here ought to
+have been a RED rose-tree, and we put a white one in by mistake;
+and if the Queen was to find it out, we should all have our heads
+cut off, you know. So you see, Miss, we're doing our best, afore
+she comes, to--' At this moment Five, who had been anxiously
+looking across the garden, called out `The Queen! The Queen!'
+and the three gardeners instantly threw themselves flat upon
+their faces. There was a sound of many footsteps, and Alice
+looked round, eager to see the Queen.
+
+ First came ten soldiers carrying clubs; these were all shaped
+like the three gardeners, oblong and flat, with their hands and
+feet at the corners: next the ten courtiers; these were
+ornamented all over with diamonds, and walked two and two, as the
+soldiers did. After these came the royal children; there were
+ten of them, and the little dears came jumping merrily along hand
+in hand, in couples: they were all ornamented with hearts. Next
+came the guests, mostly Kings and Queens, and among them Alice
+recognised the White Rabbit: it was talking in a hurried nervous
+manner, smiling at everything that was said, and went by without
+noticing her. Then followed the Knave of Hearts, carrying the
+King's crown on a crimson velvet cushion; and, last of all this
+grand procession, came THE KING AND QUEEN OF HEARTS.
+
+ Alice was rather doubtful whether she ought not to lie down on
+her face like the three gardeners, but she could not remember
+every having heard of such a rule at processions; `and besides,
+what would be the use of a procession,' thought she, `if people
+had all to lie down upon their faces, so that they couldn't see
+it?' So she stood still where she was, and waited.
+
+ When the procession came opposite to Alice, they all stopped
+and looked at her, and the Queen said severely `Who is this?'
+She said it to the Knave of Hearts, who only bowed and smiled in
+reply.
+
+ `Idiot!' said the Queen, tossing her head impatiently; and,
+turning to Alice, she went on, `What's your name, child?'
+
+ `My name is Alice, so please your Majesty,' said Alice very
+politely; but she added, to herself, `Why, they're only a pack of
+cards, after all. I needn't be afraid of them!'
+
+ `And who are THESE?' said the Queen, pointing to the three
+gardeners who were lying round the rosetree; for, you see, as
+they were lying on their faces, and the pattern on their backs
+was the same as the rest of the pack, she could not tell whether
+they were gardeners, or soldiers, or courtiers, or three of her
+own children.
+
+ `How should I know?' said Alice, surprised at her own courage.
+`It's no business of MINE.'
+
+ The Queen turned crimson with fury, and, after glaring at her
+for a moment like a wild beast, screamed `Off with her head!
+Off--'
+
+ `Nonsense!' said Alice, very loudly and decidedly, and the
+Queen was silent.
+
+ The King laid his hand upon her arm, and timidly said
+`Consider, my dear: she is only a child!'
+
+ The Queen turned angrily away from him, and said to the Knave
+`Turn them over!'
+
+ The Knave did so, very carefully, with one foot.
+
+ `Get up!' said the Queen, in a shrill, loud voice, and the
+three gardeners instantly jumped up, and began bowing to the
+King, the Queen, the royal children, and everybody else.
+
+ `Leave off that!' screamed the Queen. `You make me giddy.'
+And then, turning to the rose-tree, she went on, `What HAVE you
+been doing here?'
+
+ `May it please your Majesty,' said Two, in a very humble tone,
+going down on one knee as he spoke, `we were trying--'
+
+ `I see!' said the Queen, who had meanwhile been examining the
+roses. `Off with their heads!' and the procession moved on,
+three of the soldiers remaining behind to execute the unfortunate
+gardeners, who ran to Alice for protection.
+
+ `You shan't be beheaded!' said Alice, and she put them into a
+large flower-pot that stood near. The three soldiers wandered
+about for a minute or two, looking for them, and then quietly
+marched off after the others.
+
+ `Are their heads off?' shouted the Queen.
+
+ `Their heads are gone, if it please your Majesty!' the soldiers
+shouted in reply.
+
+ `That's right!' shouted the Queen. `Can you play croquet?'
+
+ The soldiers were silent, and looked at Alice, as the question
+was evidently meant for her.
+
+ `Yes!' shouted Alice.
+
+ `Come on, then!' roared the Queen, and Alice joined the
+procession, wondering very much what would happen next.
+
+ `It's--it's a very fine day!' said a timid voice at her side.
+She was walking by the White Rabbit, who was peeping anxiously
+into her face.
+
+ `Very,' said Alice: `--where's the Duchess?'
+
+ `Hush! Hush!' said the Rabbit in a low, hurried tone. He
+looked anxiously over his shoulder as he spoke, and then raised
+himself upon tiptoe, put his mouth close to her ear, and
+whispered `She's under sentence of execution.'
+
+ `What for?' said Alice.
+
+ `Did you say "What a pity!"?' the Rabbit asked.
+
+ `No, I didn't,' said Alice: `I don't think it's at all a pity.
+I said "What for?"'
+
+ `She boxed the Queen's ears--' the Rabbit began. Alice gave a
+little scream of laughter. `Oh, hush!' the Rabbit whispered in a
+frightened tone. `The Queen will hear you! You see, she came
+rather late, and the Queen said--'
+
+ `Get to your places!' shouted the Queen in a voice of thunder,
+and people began running about in all directions, tumbling up
+against each other; however, they got settled down in a minute or
+two, and the game began. Alice thought she had never seen such a
+curious croquet-ground in her life; it was all ridges and
+furrows; the balls were live hedgehogs, the mallets live
+flamingoes, and the soldiers had to double themselves up and to
+stand on their hands and feet, to make the arches.
+
+ The chief difficulty Alice found at first was in managing her
+flamingo: she succeeded in getting its body tucked away,
+comfortably enough, under her arm, with its legs hanging down,
+but generally, just as she had got its neck nicely straightened
+out, and was going to give the hedgehog a blow with its head, it
+WOULD twist itself round and look up in her face, with such a
+puzzled expression that she could not help bursting out laughing:
+and when she had got its head down, and was going to begin again,
+it was very provoking to find that the hedgehog had unrolled
+itself, and was in the act of crawling away: besides all this,
+there was generally a ridge or furrow in the way wherever she
+wanted to send the hedgehog to, and, as the doubled-up soldiers
+were always getting up and walking off to other parts of the
+ground, Alice soon came to the conclusion that it was a very
+difficult game indeed.
+
+ The players all played at once without waiting for turns,
+quarrelling all the while, and fighting for the hedgehogs; and in
+a very short time the Queen was in a furious passion, and went
+stamping about, and shouting `Off with his head!' or `Off with
+her head!' about once in a minute.
+
+ Alice began to feel very uneasy: to be sure, she had not as
+yet had any dispute with the Queen, but she knew that it might
+happen any minute, `and then,' thought she, `what would become of
+me? They're dreadfully fond of beheading people here; the great
+wonder is, that there's any one left alive!'
+
+ She was looking about for some way of escape, and wondering
+whether she could get away without being seen, when she noticed a
+curious appearance in the air: it puzzled her very much at
+first, but, after watching it a minute or two, she made it out to
+be a grin, and she said to herself `It's the Cheshire Cat: now I
+shall have somebody to talk to.'
+
+ `How are you getting on?' said the Cat, as soon as there was
+mouth enough for it to speak with.
+
+ Alice waited till the eyes appeared, and then nodded. `It's no
+use speaking to it,' she thought, `till its ears have come, or at
+least one of them.' In another minute the whole head appeared,
+and then Alice put down her flamingo, and began an account of the
+game, feeling very glad she had someone to listen to her. The
+Cat seemed to think that there was enough of it now in sight, and
+no more of it appeared.
+
+ `I don't think they play at all fairly,' Alice began, in rather
+a complaining tone, `and they all quarrel so dreadfully one can't
+hear oneself speak--and they don't seem to have any rules in
+particular; at least, if there are, nobody attends to them--and
+you've no idea how confusing it is all the things being alive;
+for instance, there's the arch I've got to go through next
+walking about at the other end of the ground--and I should have
+croqueted the Queen's hedgehog just now, only it ran away when it
+saw mine coming!'
+
+ `How do you like the Queen?' said the Cat in a low voice.
+
+ `Not at all,' said Alice: `she's so extremely--' Just then
+she noticed that the Queen was close behind her, listening: so
+she went on, `--likely to win, that it's hardly worth while
+finishing the game.'
+
+ The Queen smiled and passed on.
+
+ `Who ARE you talking to?' said the King, going up to Alice, and
+looking at the Cat's head with great curiosity.
+
+ `It's a friend of mine--a Cheshire Cat,' said Alice: `allow me
+to introduce it.'
+
+ `I don't like the look of it at all,' said the King: `however,
+it may kiss my hand if it likes.'
+
+ `I'd rather not,' the Cat remarked.
+
+ `Don't be impertinent,' said the King, `and don't look at me
+like that!' He got behind Alice as he spoke.
+
+ `A cat may look at a king,' said Alice. `I've read that in
+some book, but I don't remember where.'
+
+ `Well, it must be removed,' said the King very decidedly, and
+he called the Queen, who was passing at the moment, `My dear! I
+wish you would have this cat removed!'
+
+ The Queen had only one way of settling all difficulties, great
+or small. `Off with his head!' she said, without even looking
+round.
+
+ `I'll fetch the executioner myself,' said the King eagerly, and
+he hurried off.
+
+ Alice thought she might as well go back, and see how the game
+was going on, as she heard the Queen's voice in the distance,
+screaming with passion. She had already heard her sentence three
+of the players to be executed for having missed their turns, and
+she did not like the look of things at all, as the game was in
+such confusion that she never knew whether it was her turn or
+not. So she went in search of her hedgehog.
+
+ The hedgehog was engaged in a fight with another hedgehog,
+which seemed to Alice an excellent opportunity for croqueting one
+of them with the other: the only difficulty was, that her
+flamingo was gone across to the other side of the garden, where
+Alice could see it trying in a helpless sort of way to fly up
+into a tree.
+
+ By the time she had caught the flamingo and brought it back,
+the fight was over, and both the hedgehogs were out of sight:
+`but it doesn't matter much,' thought Alice, `as all the arches
+are gone from this side of the ground.' So she tucked it away
+under her arm, that it might not escape again, and went back for
+a little more conversation with her friend.
+
+ When she got back to the Cheshire Cat, she was surprised to
+find quite a large crowd collected round it: there was a dispute
+going on between the executioner, the King, and the Queen, who
+were all talking at once, while all the rest were quite silent,
+and looked very uncomfortable.
+
+ The moment Alice appeared, she was appealed to by all three to
+settle the question, and they repeated their arguments to her,
+though, as they all spoke at once, she found it very hard indeed
+to make out exactly what they said.
+
+ The executioner's argument was, that you couldn't cut off a
+head unless there was a body to cut it off from: that he had
+never had to do such a thing before, and he wasn't going to begin
+at HIS time of life.
+
+ The King's argument was, that anything that had a head could be
+beheaded, and that you weren't to talk nonsense.
+
+ The Queen's argument was, that if something wasn't done about
+it in less than no time she'd have everybody executed, all round.
+(It was this last remark that had made the whole party look so
+grave and anxious.)
+
+ Alice could think of nothing else to say but `It belongs to the
+Duchess: you'd better ask HER about it.'
+
+ `She's in prison,' the Queen said to the executioner: `fetch
+her here.' And the executioner went off like an arrow.
+
+ The Cat's head began fading away the moment he was gone, and,
+by the time he had come back with the Dutchess, it had entirely
+disappeared; so the King and the executioner ran wildly up and
+down looking for it, while the rest of the party went back to the game.
+
+
+
+ CHAPTER IX
+
+ The Mock Turtle's Story
+
+
+ `You can't think how glad I am to see you again, you dear old
+thing!' said the Duchess, as she tucked her arm affectionately
+into Alice's, and they walked off together.
+
+ Alice was very glad to find her in such a pleasant temper, and
+thought to herself that perhaps it was only the pepper that had
+made her so savage when they met in the kitchen.
+
+ `When I'M a Duchess,' she said to herself, (not in a very
+hopeful tone though), `I won't have any pepper in my kitchen AT
+ALL. Soup does very well without--Maybe it's always pepper that
+makes people hot-tempered,' she went on, very much pleased at
+having found out a new kind of rule, `and vinegar that makes them
+sour--and camomile that makes them bitter--and--and barley-sugar
+and such things that make children sweet-tempered. I only wish
+people knew that: then they wouldn't be so stingy about it, you
+know--'
+
+ She had quite forgotten the Duchess by this time, and was a
+little startled when she heard her voice close to her ear.
+`You're thinking about something, my dear, and that makes you
+forget to talk. I can't tell you just now what the moral of that
+is, but I shall remember it in a bit.'
+
+ `Perhaps it hasn't one,' Alice ventured to remark.
+
+ `Tut, tut, child!' said the Duchess. `Everything's got a
+moral, if only you can find it.' And she squeezed herself up
+closer to Alice's side as she spoke.
+
+ Alice did not much like keeping so close to her: first,
+because the Duchess was VERY ugly; and secondly, because she was
+exactly the right height to rest her chin upon Alice's shoulder,
+and it was an uncomfortably sharp chin. However, she did not
+like to be rude, so she bore it as well as she could.
+
+ `The game's going on rather better now,' she said, by way of
+keeping up the conversation a little.
+
+ `'Tis so,' said the Duchess: `and the moral of that is--"Oh,
+'tis love, 'tis love, that makes the world go round!"'
+
+ `Somebody said,' Alice whispered, `that it's done by everybody
+minding their own business!'
+
+ `Ah, well! It means much the same thing,' said the Duchess,
+digging her sharp little chin into Alice's shoulder as she added,
+`and the moral of THAT is--"Take care of the sense, and the
+sounds will take care of themselves."'
+
+ `How fond she is of finding morals in things!' Alice thought to
+herself.
+
+ `I dare say you're wondering why I don't put my arm round your
+waist,' the Duchess said after a pause: `the reason is, that I'm
+doubtful about the temper of your flamingo. Shall I try the
+experiment?'
+
+ `HE might bite,' Alice cautiously replied, not feeling at all
+anxious to have the experiment tried.
+
+ `Very true,' said the Duchess: `flamingoes and mustard both
+bite. And the moral of that is--"Birds of a feather flock
+together."'
+
+ `Only mustard isn't a bird,' Alice remarked.
+
+ `Right, as usual,' said the Duchess: `what a clear way you
+have of putting things!'
+
+ `It's a mineral, I THINK,' said Alice.
+
+ `Of course it is,' said the Duchess, who seemed ready to agree
+to everything that Alice said; `there's a large mustard-mine near
+here. And the moral of that is--"The more there is of mine, the
+less there is of yours."'
+
+ `Oh, I know!' exclaimed Alice, who had not attended to this
+last remark, `it's a vegetable. It doesn't look like one, but it
+is.'
+
+ `I quite agree with you,' said the Duchess; `and the moral of
+that is--"Be what you would seem to be"--or if you'd like it put
+more simply--"Never imagine yourself not to be otherwise than
+what it might appear to others that what you were or might have
+been was not otherwise than what you had been would have appeared
+to them to be otherwise."'
+
+ `I think I should understand that better,' Alice said very
+politely, `if I had it written down: but I can't quite follow it
+as you say it.'
+
+ `That's nothing to what I could say if I chose,' the Duchess
+replied, in a pleased tone.
+
+ `Pray don't trouble yourself to say it any longer than that,'
+said Alice.
+
+ `Oh, don't talk about trouble!' said the Duchess. `I make you
+a present of everything I've said as yet.'
+
+ `A cheap sort of present!' thought Alice. `I'm glad they don't
+give birthday presents like that!' But she did not venture to
+say it out loud.
+
+ `Thinking again?' the Duchess asked, with another dig of her
+sharp little chin.
+
+ `I've a right to think,' said Alice sharply, for she was
+beginning to feel a little worried.
+
+ `Just about as much right,' said the Duchess, `as pigs have to
+fly; and the m--'
+
+ But here, to Alice's great surprise, the Duchess's voice died
+away, even in the middle of her favourite word `moral,' and the
+arm that was linked into hers began to tremble. Alice looked up,
+and there stood the Queen in front of them, with her arms folded,
+frowning like a thunderstorm.
+
+ `A fine day, your Majesty!' the Duchess began in a low, weak
+voice.
+
+ `Now, I give you fair warning,' shouted the Queen, stamping on
+the ground as she spoke; `either you or your head must be off,
+and that in about half no time! Take your choice!'
+
+ The Duchess took her choice, and was gone in a moment.
+
+ `Let's go on with the game,' the Queen said to Alice; and Alice
+was too much frightened to say a word, but slowly followed her
+back to the croquet-ground.
+
+ The other guests had taken advantage of the Queen's absence,
+and were resting in the shade: however, the moment they saw her,
+they hurried back to the game, the Queen merely remarking that a
+moment's delay would cost them their lives.
+
+ All the time they were playing the Queen never left off
+quarrelling with the other players, and shouting `Off with his
+head!' or `Off with her head!' Those whom she sentenced were
+taken into custody by the soldiers, who of course had to leave
+off being arches to do this, so that by the end of half an hour
+or so there were no arches left, and all the players, except the
+King, the Queen, and Alice, were in custody and under sentence of
+execution.
+
+ Then the Queen left off, quite out of breath, and said to
+Alice, `Have you seen the Mock Turtle yet?'
+
+ `No,' said Alice. `I don't even know what a Mock Turtle is.'
+
+ `It's the thing Mock Turtle Soup is made from,' said the Queen.
+
+ `I never saw one, or heard of one,' said Alice.
+
+ `Come on, then,' said the Queen, `and he shall tell you his
+history,'
+
+ As they walked off together, Alice heard the King say in a low
+voice, to the company generally, `You are all pardoned.' `Come,
+THAT'S a good thing!' she said to herself, for she had felt quite
+unhappy at the number of executions the Queen had ordered.
+
+ They very soon came upon a Gryphon, lying fast asleep in the
+sun. (IF you don't know what a Gryphon is, look at the picture.)
+`Up, lazy thing!' said the Queen, `and take this young lady to
+see the Mock Turtle, and to hear his history. I must go back and
+see after some executions I have ordered'; and she walked off,
+leaving Alice alone with the Gryphon. Alice did not quite like
+the look of the creature, but on the whole she thought it would
+be quite as safe to stay with it as to go after that savage
+Queen: so she waited.
+
+ The Gryphon sat up and rubbed its eyes: then it watched the
+Queen till she was out of sight: then it chuckled. `What fun!'
+said the Gryphon, half to itself, half to Alice.
+
+ `What IS the fun?' said Alice.
+
+ `Why, SHE,' said the Gryphon. `It's all her fancy, that: they
+never executes nobody, you know. Come on!'
+
+ `Everybody says "come on!" here,' thought Alice, as she went
+slowly after it: `I never was so ordered about in all my life,
+never!'
+
+ They had not gone far before they saw the Mock Turtle in the
+distance, sitting sad and lonely on a little ledge of rock, and,
+as they came nearer, Alice could hear him sighing as if his heart
+would break. She pitied him deeply. `What is his sorrow?' she
+asked the Gryphon, and the Gryphon answered, very nearly in the
+same words as before, `It's all his fancy, that: he hasn't got
+no sorrow, you know. Come on!'
+
+ So they went up to the Mock Turtle, who looked at them with
+large eyes full of tears, but said nothing.
+
+ `This here young lady,' said the Gryphon, `she wants for to
+know your history, she do.'
+
+ `I'll tell it her,' said the Mock Turtle in a deep, hollow
+tone: `sit down, both of you, and don't speak a word till I've
+finished.'
+
+ So they sat down, and nobody spoke for some minutes. Alice
+thought to herself, `I don't see how he can EVEN finish, if he
+doesn't begin.' But she waited patiently.
+
+ `Once,' said the Mock Turtle at last, with a deep sigh, `I was
+a real Turtle.'
+
+ These words were followed by a very long silence, broken only
+by an occasional exclamation of `Hjckrrh!' from the Gryphon, and
+the constant heavy sobbing of the Mock Turtle. Alice was very
+nearly getting up and saying, `Thank you, sir, for your
+interesting story,' but she could not help thinking there MUST be
+more to come, so she sat still and said nothing.
+
+ `When we were little,' the Mock Turtle went on at last, more
+calmly, though still sobbing a little now and then, `we went to
+school in the sea. The master was an old Turtle--we used to call
+him Tortoise--'
+
+ `Why did you call him Tortoise, if he wasn't one?' Alice asked.
+
+ `We called him Tortoise because he taught us,' said the Mock
+Turtle angrily: `really you are very dull!'
+
+ `You ought to be ashamed of yourself for asking such a simple
+question,' added the Gryphon; and then they both sat silent and
+looked at poor Alice, who felt ready to sink into the earth. At
+last the Gryphon said to the Mock Turtle, `Drive on, old fellow!
+Don't be all day about it!' and he went on in these words:
+
+ `Yes, we went to school in the sea, though you mayn't believe
+it--'
+
+ `I never said I didn't!' interrupted Alice.
+
+ `You did,' said the Mock Turtle.
+
+ `Hold your tongue!' added the Gryphon, before Alice could speak
+again. The Mock Turtle went on.
+
+ `We had the best of educations--in fact, we went to school
+every day--'
+
+ `I'VE been to a day-school, too,' said Alice; `you needn't be
+so proud as all that.'
+
+ `With extras?' asked the Mock Turtle a little anxiously.
+
+ `Yes,' said Alice, `we learned French and music.'
+
+ `And washing?' said the Mock Turtle.
+
+ `Certainly not!' said Alice indignantly.
+
+ `Ah! then yours wasn't a really good school,' said the Mock
+Turtle in a tone of great relief. `Now at OURS they had at the
+end of the bill, "French, music, AND WASHING--extra."'
+
+ `You couldn't have wanted it much,' said Alice; `living at the
+bottom of the sea.'
+
+ `I couldn't afford to learn it.' said the Mock Turtle with a
+sigh. `I only took the regular course.'
+
+ `What was that?' inquired Alice.
+
+ `Reeling and Writhing, of course, to begin with,' the Mock
+Turtle replied; `and then the different branches of Arithmetic--
+Ambition, Distraction, Uglification, and Derision.'
+
+ `I never heard of "Uglification,"' Alice ventured to say. `What
+is it?'
+
+ The Gryphon lifted up both its paws in surprise. `What! Never
+heard of uglifying!' it exclaimed. `You know what to beautify
+is, I suppose?'
+
+ `Yes,' said Alice doubtfully: `it means--to--make--anything--
+prettier.'
+
+ `Well, then,' the Gryphon went on, `if you don't know what to
+uglify is, you ARE a simpleton.'
+
+ Alice did not feel encouraged to ask any more questions about
+it, so she turned to the Mock Turtle, and said `What else had you
+to learn?'
+
+ `Well, there was Mystery,' the Mock Turtle replied, counting
+off the subjects on his flappers, `--Mystery, ancient and modern,
+with Seaography: then Drawling--the Drawling-master was an old
+conger-eel, that used to come once a week: HE taught us
+Drawling, Stretching, and Fainting in Coils.'
+
+ `What was THAT like?' said Alice.
+
+ `Well, I can't show it you myself,' the Mock Turtle said: `I'm
+too stiff. And the Gryphon never learnt it.'
+
+ `Hadn't time,' said the Gryphon: `I went to the Classics
+master, though. He was an old crab, HE was.'
+
+ `I never went to him,' the Mock Turtle said with a sigh: `he
+taught Laughing and Grief, they used to say.'
+
+ `So he did, so he did,' said the Gryphon, sighing in his turn;
+and both creatures hid their faces in their paws.
+
+ `And how many hours a day did you do lessons?' said Alice, in a
+hurry to change the subject.
+
+ `Ten hours the first day,' said the Mock Turtle: `nine the
+next, and so on.'
+
+ `What a curious plan!' exclaimed Alice.
+
+ `That's the reason they're called lessons,' the Gryphon
+remarked: `because they lessen from day to day.'
+
+ This was quite a new idea to Alice, and she thought it over a
+little before she made her next remark. `Then the eleventh day
+must have been a holiday?'
+
+ `Of course it was,' said the Mock Turtle.
+
+ `And how did you manage on the twelfth?' Alice went on eagerly.
+
+ `That's enough about lessons,' the Gryphon interrupted in a
+very decided tone: `tell her something about the games now.'
+
+
+
+ CHAPTER X
+
+ The Lobster Quadrille
+
+
+ The Mock Turtle sighed deeply, and drew the back of one flapper
+across his eyes. He looked at Alice, and tried to speak, but for
+a minute or two sobs choked his voice. `Same as if he had a bone
+in his throat,' said the Gryphon: and it set to work shaking him
+and punching him in the back. At last the Mock Turtle recovered
+his voice, and, with tears running down his cheeks, he went on
+again:--
+
+ `You may not have lived much under the sea--' (`I haven't,'
+said Alice)--`and perhaps you were never even introduced to a lobster--'
+(Alice began to say `I once tasted--' but checked herself hastily,
+and said `No, never') `--so you can have no idea what a delightful
+thing a Lobster Quadrille is!'
+
+ `No, indeed,' said Alice. `What sort of a dance is it?'
+
+ `Why,' said the Gryphon, `you first form into a line along the
+sea-shore--'
+
+ `Two lines!' cried the Mock Turtle. `Seals, turtles, salmon,
+and so on; then, when you've cleared all the jelly-fish out of
+the way--'
+
+ `THAT generally takes some time,' interrupted the Gryphon.
+
+ `--you advance twice--'
+
+ `Each with a lobster as a partner!' cried the Gryphon.
+
+ `Of course,' the Mock Turtle said: `advance twice, set to
+partners--'
+
+ `--change lobsters, and retire in same order,' continued the
+Gryphon.
+
+ `Then, you know,' the Mock Turtle went on, `you throw the--'
+
+ `The lobsters!' shouted the Gryphon, with a bound into the air.
+
+ `--as far out to sea as you can--'
+
+ `Swim after them!' screamed the Gryphon.
+
+ `Turn a somersault in the sea!' cried the Mock Turtle,
+capering wildly about.
+
+ `Back to land again, and that's all the first figure,' said the
+Mock Turtle, suddenly dropping his voice; and the two creatures,
+who had been jumping about like mad things all this time, sat
+down again very sadly and quietly, and looked at Alice.
+
+ `It must be a very pretty dance,' said Alice timidly.
+
+ `Would you like to see a little of it?' said the Mock Turtle.
+
+ `Very much indeed,' said Alice.
+
+ `Come, let's try the first figure!' said the Mock Turtle to the
+Gryphon. `We can do without lobsters, you know. Which shall
+sing?'
+
+ `Oh, YOU sing,' said the Gryphon. `I've forgotten the words.'
+
+ So they began solemnly dancing round and round Alice, every now
+and then treading on her toes when they passed too close, and
+waving their forepaws to mark the time, while the Mock Turtle
+sang this, very slowly and sadly:--
+
+
+`"Will you walk a little faster?" said a whiting to a snail.
+"There's a porpoise close behind us, and he's treading on my
+ tail.
+See how eagerly the lobsters and the turtles all advance!
+They are waiting on the shingle--will you come and join the
+dance?
+
+Will you, won't you, will you, won't you, will you join the
+dance?
+Will you, won't you, will you, won't you, won't you join the
+dance?
+
+
+"You can really have no notion how delightful it will be
+When they take us up and throw us, with the lobsters, out to
+ sea!"
+But the snail replied "Too far, too far!" and gave a look
+ askance--
+Said he thanked the whiting kindly, but he would not join the
+ dance.
+ Would not, could not, would not, could not, would not join
+ the dance.
+ Would not, could not, would not, could not, could not join
+ the dance.
+
+`"What matters it how far we go?" his scaly friend replied.
+"There is another shore, you know, upon the other side.
+The further off from England the nearer is to France--
+Then turn not pale, beloved snail, but come and join the dance.
+
+ Will you, won't you, will you, won't you, will you join the
+ dance?
+ Will you, won't you, will you, won't you, won't you join the
+ dance?"'
+
+
+
+ `Thank you, it's a very interesting dance to watch,' said
+Alice, feeling very glad that it was over at last: `and I do so
+like that curious song about the whiting!'
+
+ `Oh, as to the whiting,' said the Mock Turtle, `they--you've
+seen them, of course?'
+
+ `Yes,' said Alice, `I've often seen them at dinn--' she
+checked herself hastily.
+
+ `I don't know where Dinn may be,' said the Mock Turtle, `but
+if you've seen them so often, of course you know what they're
+like.'
+
+ `I believe so,' Alice replied thoughtfully. `They have their
+tails in their mouths--and they're all over crumbs.'
+
+ `You're wrong about the crumbs,' said the Mock Turtle:
+`crumbs would all wash off in the sea. But they HAVE their tails
+in their mouths; and the reason is--' here the Mock Turtle
+yawned and shut his eyes.--`Tell her about the reason and all
+that,' he said to the Gryphon.
+
+ `The reason is,' said the Gryphon, `that they WOULD go with
+the lobsters to the dance. So they got thrown out to sea. So
+they had to fall a long way. So they got their tails fast in
+their mouths. So they couldn't get them out again. That's all.'
+
+ `Thank you,' said Alice, `it's very interesting. I never knew
+so much about a whiting before.'
+
+ `I can tell you more than that, if you like,' said the
+Gryphon. `Do you know why it's called a whiting?'
+
+ `I never thought about it,' said Alice. `Why?'
+
+ `IT DOES THE BOOTS AND SHOES.' the Gryphon replied very
+solemnly.
+
+ Alice was thoroughly puzzled. `Does the boots and shoes!' she
+repeated in a wondering tone.
+
+ `Why, what are YOUR shoes done with?' said the Gryphon. `I
+mean, what makes them so shiny?'
+
+ Alice looked down at them, and considered a little before she
+gave her answer. `They're done with blacking, I believe.'
+
+ `Boots and shoes under the sea,' the Gryphon went on in a deep
+voice, `are done with a whiting. Now you know.'
+
+ `And what are they made of?' Alice asked in a tone of great
+curiosity.
+
+ `Soles and eels, of course,' the Gryphon replied rather
+impatiently: `any shrimp could have told you that.'
+
+ `If I'd been the whiting,' said Alice, whose thoughts were
+still running on the song, `I'd have said to the porpoise, "Keep
+back, please: we don't want YOU with us!"'
+
+ `They were obliged to have him with them,' the Mock Turtle
+said: `no wise fish would go anywhere without a porpoise.'
+
+ `Wouldn't it really?' said Alice in a tone of great surprise.
+
+ `Of course not,' said the Mock Turtle: `why, if a fish came
+to ME, and told me he was going a journey, I should say "With
+what porpoise?"'
+
+ `Don't you mean "purpose"?' said Alice.
+
+ `I mean what I say,' the Mock Turtle replied in an offended
+tone. And the Gryphon added `Come, let's hear some of YOUR
+adventures.'
+
+ `I could tell you my adventures--beginning from this morning,'
+said Alice a little timidly: `but it's no use going back to
+yesterday, because I was a different person then.'
+
+ `Explain all that,' said the Mock Turtle.
+
+ `No, no! The adventures first,' said the Gryphon in an
+impatient tone: `explanations take such a dreadful time.'
+
+ So Alice began telling them her adventures from the time when
+she first saw the White Rabbit. She was a little nervous about
+it just at first, the two creatures got so close to her, one on
+each side, and opened their eyes and mouths so VERY wide, but she
+gained courage as she went on. Her listeners were perfectly
+quiet till she got to the part about her repeating `YOU ARE OLD,
+FATHER WILLIAM,' to the Caterpillar, and the words all coming
+different, and then the Mock Turtle drew a long breath, and said
+`That's very curious.'
+
+ `It's all about as curious as it can be,' said the Gryphon.
+
+ `It all came different!' the Mock Turtle repeated
+thoughtfully. `I should like to hear her try and repeat
+something now. Tell her to begin.' He looked at the Gryphon as
+if he thought it had some kind of authority over Alice.
+
+ `Stand up and repeat "'TIS THE VOICE OF THE SLUGGARD,"' said
+the Gryphon.
+
+ `How the creatures order one about, and make one repeat
+lessons!' thought Alice; `I might as well be at school at once.'
+However, she got up, and began to repeat it, but her head was so
+full of the Lobster Quadrille, that she hardly knew what she was
+saying, and the words came very queer indeed:--
+
+ `'Tis the voice of the Lobster; I heard him declare,
+ "You have baked me too brown, I must sugar my hair."
+ As a duck with its eyelids, so he with his nose
+ Trims his belt and his buttons, and turns out his toes.'
+
+ [later editions continued as follows
+ When the sands are all dry, he is gay as a lark,
+ And will talk in contemptuous tones of the Shark,
+ But, when the tide rises and sharks are around,
+ His voice has a timid and tremulous sound.]
+
+ `That's different from what I used to say when I was a child,'
+said the Gryphon.
+
+ `Well, I never heard it before,' said the Mock Turtle; `but it
+sounds uncommon nonsense.'
+
+ Alice said nothing; she had sat down with her face in her
+hands, wondering if anything would EVER happen in a natural way
+again.
+
+ `I should like to have it explained,' said the Mock Turtle.
+
+ `She can't explain it,' said the Gryphon hastily. `Go on with
+the next verse.'
+
+ `But about his toes?' the Mock Turtle persisted. `How COULD
+he turn them out with his nose, you know?'
+
+ `It's the first position in dancing.' Alice said; but was
+dreadfully puzzled by the whole thing, and longed to change the
+subject.
+
+ `Go on with the next verse,' the Gryphon repeated impatiently:
+`it begins "I passed by his garden."'
+
+ Alice did not dare to disobey, though she felt sure it would
+all come wrong, and she went on in a trembling voice:--
+
+ `I passed by his garden, and marked, with one eye,
+ How the Owl and the Panther were sharing a pie--'
+
+ [later editions continued as follows
+ The Panther took pie-crust, and gravy, and meat,
+ While the Owl had the dish as its share of the treat.
+ When the pie was all finished, the Owl, as a boon,
+ Was kindly permitted to pocket the spoon:
+ While the Panther received knife and fork with a growl,
+ And concluded the banquet--]
+
+ `What IS the use of repeating all that stuff,' the Mock Turtle
+interrupted, `if you don't explain it as you go on? It's by far
+the most confusing thing I ever heard!'
+
+ `Yes, I think you'd better leave off,' said the Gryphon: and
+Alice was only too glad to do so.
+
+ `Shall we try another figure of the Lobster Quadrille?' the
+Gryphon went on. `Or would you like the Mock Turtle to sing you
+a song?'
+
+ `Oh, a song, please, if the Mock Turtle would be so kind,'
+Alice replied, so eagerly that the Gryphon said, in a rather
+offended tone, `Hm! No accounting for tastes! Sing her "Turtle
+Soup," will you, old fellow?'
+
+ The Mock Turtle sighed deeply, and began, in a voice sometimes
+choked with sobs, to sing this:--
+
+
+ `Beautiful Soup, so rich and green,
+ Waiting in a hot tureen!
+ Who for such dainties would not stoop?
+ Soup of the evening, beautiful Soup!
+ Soup of the evening, beautiful Soup!
+ Beau--ootiful Soo--oop!
+ Beau--ootiful Soo--oop!
+ Soo--oop of the e--e--evening,
+ Beautiful, beautiful Soup!
+
+ `Beautiful Soup! Who cares for fish,
+ Game, or any other dish?
+ Who would not give all else for two p
+ ennyworth only of beautiful Soup?
+ Pennyworth only of beautiful Soup?
+ Beau--ootiful Soo--oop!
+ Beau--ootiful Soo--oop!
+ Soo--oop of the e--e--evening,
+ Beautiful, beauti--FUL SOUP!'
+
+ `Chorus again!' cried the Gryphon, and the Mock Turtle had
+just begun to repeat it, when a cry of `The trial's beginning!'
+was heard in the distance.
+
+ `Come on!' cried the Gryphon, and, taking Alice by the hand,
+it hurried off, without waiting for the end of the song.
+
+ `What trial is it?' Alice panted as she ran; but the Gryphon
+only answered `Come on!' and ran the faster, while more and more
+faintly came, carried on the breeze that followed them, the
+melancholy words:--
+
+ `Soo--oop of the e--e--evening,
+ Beautiful, beautiful Soup!'
+
+
+
+ CHAPTER XI
+
+ Who Stole the Tarts?
+
+
+ The King and Queen of Hearts were seated on their throne when
+they arrived, with a great crowd assembled about them--all sorts
+of little birds and beasts, as well as the whole pack of cards:
+the Knave was standing before them, in chains, with a soldier on
+each side to guard him; and near the King was the White Rabbit,
+with a trumpet in one hand, and a scroll of parchment in the
+other. In the very middle of the court was a table, with a large
+dish of tarts upon it: they looked so good, that it made Alice
+quite hungry to look at them--`I wish they'd get the trial done,'
+she thought, `and hand round the refreshments!' But there seemed
+to be no chance of this, so she began looking at everything about
+her, to pass away the time.
+
+ Alice had never been in a court of justice before, but she had
+read about them in books, and she was quite pleased to find that
+she knew the name of nearly everything there. `That's the
+judge,' she said to herself, `because of his great wig.'
+
+ The judge, by the way, was the King; and as he wore his crown
+over the wig, (look at the frontispiece if you want to see how he
+did it,) he did not look at all comfortable, and it was certainly
+not becoming.
+
+ `And that's the jury-box,' thought Alice, `and those twelve
+creatures,' (she was obliged to say `creatures,' you see, because
+some of them were animals, and some were birds,) `I suppose they
+are the jurors.' She said this last word two or three times over
+to herself, being rather proud of it: for she thought, and
+rightly too, that very few little girls of her age knew the
+meaning of it at all. However, `jury-men' would have done just
+as well.
+
+ The twelve jurors were all writing very busily on slates.
+`What are they doing?' Alice whispered to the Gryphon. `They
+can't have anything to put down yet, before the trial's begun.'
+
+ `They're putting down their names,' the Gryphon whispered in
+reply, `for fear they should forget them before the end of the
+trial.'
+
+ `Stupid things!' Alice began in a loud, indignant voice, but
+she stopped hastily, for the White Rabbit cried out, `Silence in
+the court!' and the King put on his spectacles and looked
+anxiously round, to make out who was talking.
+
+ Alice could see, as well as if she were looking over their
+shoulders, that all the jurors were writing down `stupid things!'
+on their slates, and she could even make out that one of them
+didn't know how to spell `stupid,' and that he had to ask his
+neighbour to tell him. `A nice muddle their slates'll be in
+before the trial's over!' thought Alice.
+
+ One of the jurors had a pencil that squeaked. This of course,
+Alice could not stand, and she went round the court and got
+behind him, and very soon found an opportunity of taking it
+away. She did it so quickly that the poor little juror (it was
+Bill, the Lizard) could not make out at all what had become of
+it; so, after hunting all about for it, he was obliged to write
+with one finger for the rest of the day; and this was of very
+little use, as it left no mark on the slate.
+
+ `Herald, read the accusation!' said the King.
+
+ On this the White Rabbit blew three blasts on the trumpet, and
+then unrolled the parchment scroll, and read as follows:--
+
+ `The Queen of Hearts, she made some tarts,
+ All on a summer day:
+ The Knave of Hearts, he stole those tarts,
+ And took them quite away!'
+
+ `Consider your verdict,' the King said to the jury.
+
+ `Not yet, not yet!' the Rabbit hastily interrupted. `There's
+a great deal to come before that!'
+
+ `Call the first witness,' said the King; and the White Rabbit
+blew three blasts on the trumpet, and called out, `First
+witness!'
+
+ The first witness was the Hatter. He came in with a teacup in
+one hand and a piece of bread-and-butter in the other. `I beg
+pardon, your Majesty,' he began, `for bringing these in: but I
+hadn't quite finished my tea when I was sent for.'
+
+ `You ought to have finished,' said the King. `When did you
+begin?'
+
+ The Hatter looked at the March Hare, who had followed him into
+the court, arm-in-arm with the Dormouse. `Fourteenth of March, I
+think it was,' he said.
+
+ `Fifteenth,' said the March Hare.
+
+ `Sixteenth,' added the Dormouse.
+
+ `Write that down,' the King said to the jury, and the jury
+eagerly wrote down all three dates on their slates, and then
+added them up, and reduced the answer to shillings and pence.
+
+ `Take off your hat,' the King said to the Hatter.
+
+ `It isn't mine,' said the Hatter.
+
+ `Stolen!' the King exclaimed, turning to the jury, who
+instantly made a memorandum of the fact.
+
+ `I keep them to sell,' the Hatter added as an explanation;
+`I've none of my own. I'm a hatter.'
+
+ Here the Queen put on her spectacles, and began staring at the
+Hatter, who turned pale and fidgeted.
+
+ `Give your evidence,' said the King; `and don't be nervous, or
+I'll have you executed on the spot.'
+
+ This did not seem to encourage the witness at all: he kept
+shifting from one foot to the other, looking uneasily at the
+Queen, and in his confusion he bit a large piece out of his
+teacup instead of the bread-and-butter.
+
+ Just at this moment Alice felt a very curious sensation, which
+puzzled her a good deal until she made out what it was: she was
+beginning to grow larger again, and she thought at first she
+would get up and leave the court; but on second thoughts she
+decided to remain where she was as long as there was room for
+her.
+
+ `I wish you wouldn't squeeze so.' said the Dormouse, who was
+sitting next to her. `I can hardly breathe.'
+
+ `I can't help it,' said Alice very meekly: `I'm growing.'
+
+ `You've no right to grow here,' said the Dormouse.
+
+ `Don't talk nonsense,' said Alice more boldly: `you know
+you're growing too.'
+
+ `Yes, but I grow at a reasonable pace,' said the Dormouse:
+`not in that ridiculous fashion.' And he got up very sulkily
+and crossed over to the other side of the court.
+
+ All this time the Queen had never left off staring at the
+Hatter, and, just as the Dormouse crossed the court, she said to
+one of the officers of the court, `Bring me the list of the
+singers in the last concert!' on which the wretched Hatter
+trembled so, that he shook both his shoes off.
+
+ `Give your evidence,' the King repeated angrily, `or I'll have
+you executed, whether you're nervous or not.'
+
+ `I'm a poor man, your Majesty,' the Hatter began, in a
+trembling voice, `--and I hadn't begun my tea--not above a week
+or so--and what with the bread-and-butter getting so thin--and
+the twinkling of the tea--'
+
+ `The twinkling of the what?' said the King.
+
+ `It began with the tea,' the Hatter replied.
+
+ `Of course twinkling begins with a T!' said the King sharply.
+`Do you take me for a dunce? Go on!'
+
+ `I'm a poor man,' the Hatter went on, `and most things
+twinkled after that--only the March Hare said--'
+
+ `I didn't!' the March Hare interrupted in a great hurry.
+
+ `You did!' said the Hatter.
+
+ `I deny it!' said the March Hare.
+
+ `He denies it,' said the King: `leave out that part.'
+
+ `Well, at any rate, the Dormouse said--' the Hatter went on,
+looking anxiously round to see if he would deny it too: but the
+Dormouse denied nothing, being fast asleep.
+
+ `After that,' continued the Hatter, `I cut some more bread-
+and-butter--'
+
+ `But what did the Dormouse say?' one of the jury asked.
+
+ `That I can't remember,' said the Hatter.
+
+ `You MUST remember,' remarked the King, `or I'll have you
+executed.'
+
+ The miserable Hatter dropped his teacup and bread-and-butter,
+and went down on one knee. `I'm a poor man, your Majesty,' he
+began.
+
+ `You're a very poor speaker,' said the King.
+
+ Here one of the guinea-pigs cheered, and was immediately
+suppressed by the officers of the court. (As that is rather a
+hard word, I will just explain to you how it was done. They had
+a large canvas bag, which tied up at the mouth with strings:
+into this they slipped the guinea-pig, head first, and then sat
+upon it.)
+
+ `I'm glad I've seen that done,' thought Alice. `I've so often
+read in the newspapers, at the end of trials, "There was some
+attempts at applause, which was immediately suppressed by the
+officers of the court," and I never understood what it meant
+till now.'
+
+ `If that's all you know about it, you may stand down,'
+continued the King.
+
+ `I can't go no lower,' said the Hatter: `I'm on the floor, as
+it is.'
+
+ `Then you may SIT down,' the King replied.
+
+ Here the other guinea-pig cheered, and was suppressed.
+
+ `Come, that finished the guinea-pigs!' thought Alice. `Now we
+shall get on better.'
+
+ `I'd rather finish my tea,' said the Hatter, with an anxious
+look at the Queen, who was reading the list of singers.
+
+ `You may go,' said the King, and the Hatter hurriedly left the
+court, without even waiting to put his shoes on.
+
+ `--and just take his head off outside,' the Queen added to one
+of the officers: but the Hatter was out of sight before the
+officer could get to the door.
+
+ `Call the next witness!' said the King.
+
+ The next witness was the Duchess's cook. She carried the
+pepper-box in her hand, and Alice guessed who it was, even before
+she got into the court, by the way the people near the door began
+sneezing all at once.
+
+ `Give your evidence,' said the King.
+
+ `Shan't,' said the cook.
+
+ The King looked anxiously at the White Rabbit, who said in a
+low voice, `Your Majesty must cross-examine THIS witness.'
+
+ `Well, if I must, I must,' the King said, with a melancholy
+air, and, after folding his arms and frowning at the cook till
+his eyes were nearly out of sight, he said in a deep voice, `What
+are tarts made of?'
+
+ `Pepper, mostly,' said the cook.
+
+ `Treacle,' said a sleepy voice behind her.
+
+ `Collar that Dormouse,' the Queen shrieked out. `Behead that
+Dormouse! Turn that Dormouse out of court! Suppress him! Pinch
+him! Off with his whiskers!'
+
+ For some minutes the whole court was in confusion, getting the
+Dormouse turned out, and, by the time they had settled down
+again, the cook had disappeared.
+
+ `Never mind!' said the King, with an air of great relief.
+`Call the next witness.' And he added in an undertone to the
+Queen, `Really, my dear, YOU must cross-examine the next witness.
+It quite makes my forehead ache!'
+
+ Alice watched the White Rabbit as he fumbled over the list,
+feeling very curious to see what the next witness would be like,
+`--for they haven't got much evidence YET,' she said to herself.
+Imagine her surprise, when the White Rabbit read out, at the top
+of his shrill little voice, the name `Alice!'
+
+
+
+ CHAPTER XII
+
+ Alice's Evidence
+
+
+ `Here!' cried Alice, quite forgetting in the flurry of the
+moment how large she had grown in the last few minutes, and she
+jumped up in such a hurry that she tipped over the jury-box with
+the edge of her skirt, upsetting all the jurymen on to the heads
+of the crowd below, and there they lay sprawling about, reminding
+her very much of a globe of goldfish she had accidentally upset
+the week before.
+
+ `Oh, I BEG your pardon!' she exclaimed in a tone of great
+dismay, and began picking them up again as quickly as she could,
+for the accident of the goldfish kept running in her head, and
+she had a vague sort of idea that they must be collected at once
+and put back into the jury-box, or they would die.
+
+ `The trial cannot proceed,' said the King in a very grave
+voice, `until all the jurymen are back in their proper places--
+ALL,' he repeated with great emphasis, looking hard at Alice as
+he said do.
+
+ Alice looked at the jury-box, and saw that, in her haste, she
+had put the Lizard in head downwards, and the poor little thing
+was waving its tail about in a melancholy way, being quite unable
+to move. She soon got it out again, and put it right; `not that
+it signifies much,' she said to herself; `I should think it
+would be QUITE as much use in the trial one way up as the other.'
+
+ As soon as the jury had a little recovered from the shock of
+being upset, and their slates and pencils had been found and
+handed back to them, they set to work very diligently to write
+out a history of the accident, all except the Lizard, who seemed
+too much overcome to do anything but sit with its mouth open,
+gazing up into the roof of the court.
+
+ `What do you know about this business?' the King said to
+Alice.
+
+ `Nothing,' said Alice.
+
+ `Nothing WHATEVER?' persisted the King.
+
+ `Nothing whatever,' said Alice.
+
+ `That's very important,' the King said, turning to the jury.
+They were just beginning to write this down on their slates, when
+the White Rabbit interrupted: `UNimportant, your Majesty means,
+of course,' he said in a very respectful tone, but frowning and
+making faces at him as he spoke.
+
+ `UNimportant, of course, I meant,' the King hastily said, and
+went on to himself in an undertone, `important--unimportant--
+unimportant--important--' as if he were trying which word
+sounded best.
+
+ Some of the jury wrote it down `important,' and some
+`unimportant.' Alice could see this, as she was near enough to
+look over their slates; `but it doesn't matter a bit,' she
+thought to herself.
+
+ At this moment the King, who had been for some time busily
+writing in his note-book, cackled out `Silence!' and read out
+from his book, `Rule Forty-two. ALL PERSONS MORE THAN A MILE
+HIGH TO LEAVE THE COURT.'
+
+ Everybody looked at Alice.
+
+ `I'M not a mile high,' said Alice.
+
+ `You are,' said the King.
+
+ `Nearly two miles high,' added the Queen.
+
+ `Well, I shan't go, at any rate,' said Alice: `besides,
+that's not a regular rule: you invented it just now.'
+
+ `It's the oldest rule in the book,' said the King.
+
+ `Then it ought to be Number One,' said Alice.
+
+ The King turned pale, and shut his note-book hastily.
+`Consider your verdict,' he said to the jury, in a low, trembling
+voice.
+
+ `There's more evidence to come yet, please your Majesty,' said
+the White Rabbit, jumping up in a great hurry; `this paper has
+just been picked up.'
+
+ `What's in it?' said the Queen.
+
+ `I haven't opened it yet,' said the White Rabbit, `but it seems
+to be a letter, written by the prisoner to--to somebody.'
+
+ `It must have been that,' said the King, `unless it was
+written to nobody, which isn't usual, you know.'
+
+ `Who is it directed to?' said one of the jurymen.
+
+ `It isn't directed at all,' said the White Rabbit; `in fact,
+there's nothing written on the OUTSIDE.' He unfolded the paper
+as he spoke, and added `It isn't a letter, after all: it's a set
+of verses.'
+
+ `Are they in the prisoner's handwriting?' asked another of
+they jurymen.
+
+ `No, they're not,' said the White Rabbit, `and that's the
+queerest thing about it.' (The jury all looked puzzled.)
+
+ `He must have imitated somebody else's hand,' said the King.
+(The jury all brightened up again.)
+
+ `Please your Majesty,' said the Knave, `I didn't write it, and
+they can't prove I did: there's no name signed at the end.'
+
+ `If you didn't sign it,' said the King, `that only makes the
+matter worse. You MUST have meant some mischief, or else you'd
+have signed your name like an honest man.'
+
+ There was a general clapping of hands at this: it was the
+first really clever thing the King had said that day.
+
+ `That PROVES his guilt,' said the Queen.
+
+ `It proves nothing of the sort!' said Alice. `Why, you don't
+even know what they're about!'
+
+ `Read them,' said the King.
+
+ The White Rabbit put on his spectacles. `Where shall I begin,
+please your Majesty?' he asked.
+
+ `Begin at the beginning,' the King said gravely, `and go on
+till you come to the end: then stop.'
+
+ These were the verses the White Rabbit read:--
+
+ `They told me you had been to her,
+ And mentioned me to him:
+ She gave me a good character,
+ But said I could not swim.
+
+ He sent them word I had not gone
+ (We know it to be true):
+ If she should push the matter on,
+ What would become of you?
+
+ I gave her one, they gave him two,
+ You gave us three or more;
+ They all returned from him to you,
+ Though they were mine before.
+
+ If I or she should chance to be
+ Involved in this affair,
+ He trusts to you to set them free,
+ Exactly as we were.
+
+ My notion was that you had been
+ (Before she had this fit)
+ An obstacle that came between
+ Him, and ourselves, and it.
+
+ Don't let him know she liked them best,
+ For this must ever be
+ A secret, kept from all the rest,
+ Between yourself and me.'
+
+ `That's the most important piece of evidence we've heard yet,'
+said the King, rubbing his hands; `so now let the jury--'
+
+ `If any one of them can explain it,' said Alice, (she had
+grown so large in the last few minutes that she wasn't a bit
+afraid of interrupting him,) `I'll give him sixpence. _I_ don't
+believe there's an atom of meaning in it.'
+
+ The jury all wrote down on their slates, `SHE doesn't believe
+there's an atom of meaning in it,' but none of them attempted to
+explain the paper.
+
+ `If there's no meaning in it,' said the King, `that saves a
+world of trouble, you know, as we needn't try to find any. And
+yet I don't know,' he went on, spreading out the verses on his
+knee, and looking at them with one eye; `I seem to see some
+meaning in them, after all. "--SAID I COULD NOT SWIM--" you
+can't swim, can you?' he added, turning to the Knave.
+
+ The Knave shook his head sadly. `Do I look like it?' he said.
+(Which he certainly did NOT, being made entirely of cardboard.)
+
+ `All right, so far,' said the King, and he went on muttering
+over the verses to himself: `"WE KNOW IT TO BE TRUE--" that's
+the jury, of course-- "I GAVE HER ONE, THEY GAVE HIM TWO--" why,
+that must be what he did with the tarts, you know--'
+
+ `But, it goes on "THEY ALL RETURNED FROM HIM TO YOU,"' said
+Alice.
+
+ `Why, there they are!' said the King triumphantly, pointing to
+the tarts on the table. `Nothing can be clearer than THAT.
+Then again--"BEFORE SHE HAD THIS FIT--" you never had fits, my
+dear, I think?' he said to the Queen.
+
+ `Never!' said the Queen furiously, throwing an inkstand at the
+Lizard as she spoke. (The unfortunate little Bill had left off
+writing on his slate with one finger, as he found it made no
+mark; but he now hastily began again, using the ink, that was
+trickling down his face, as long as it lasted.)
+
+ `Then the words don't FIT you,' said the King, looking round
+the court with a smile. There was a dead silence.
+
+ `It's a pun!' the King added in an offended tone, and
+everybody laughed, `Let the jury consider their verdict,' the
+King said, for about the twentieth time that day.
+
+ `No, no!' said the Queen. `Sentence first--verdict afterwards.'
+
+ `Stuff and nonsense!' said Alice loudly. `The idea of having
+the sentence first!'
+
+ `Hold your tongue!' said the Queen, turning purple.
+
+ `I won't!' said Alice.
+
+ `Off with her head!' the Queen shouted at the top of her voice.
+Nobody moved.
+
+ `Who cares for you?' said Alice, (she had grown to her full
+size by this time.) `You're nothing but a pack of cards!'
+
+ At this the whole pack rose up into the air, and came flying
+down upon her: she gave a little scream, half of fright and half
+of anger, and tried to beat them off, and found herself lying on
+the bank, with her head in the lap of her sister, who was gently
+brushing away some dead leaves that had fluttered down from the
+trees upon her face.
+
+ `Wake up, Alice dear!' said her sister; `Why, what a long
+sleep you've had!'
+
+ `Oh, I've had such a curious dream!' said Alice, and she told
+her sister, as well as she could remember them, all these strange
+Adventures of hers that you have just been reading about; and
+when she had finished, her sister kissed her, and said, `It WAS a
+curious dream, dear, certainly: but now run in to your tea; it's
+getting late.' So Alice got up and ran off, thinking while she
+ran, as well she might, what a wonderful dream it had been.
+
+ But her sister sat still just as she left her, leaning her
+head on her hand, watching the setting sun, and thinking of
+little Alice and all her wonderful Adventures, till she too began
+dreaming after a fashion, and this was her dream:--
+
+ First, she dreamed of little Alice herself, and once again the
+tiny hands were clasped upon her knee, and the bright eager eyes
+were looking up into hers--she could hear the very tones of her
+voice, and see that queer little toss of her head to keep back
+the wandering hair that WOULD always get into her eyes--and
+still as she listened, or seemed to listen, the whole place
+around her became alive the strange creatures of her little
+sister's dream.
+
+ The long grass rustled at her feet as the White Rabbit hurried
+by--the frightened Mouse splashed his way through the
+neighbouring pool--she could hear the rattle of the teacups as
+the March Hare and his friends shared their never-ending meal,
+and the shrill voice of the Queen ordering off her unfortunate
+guests to execution--once more the pig-baby was sneezing on the
+Duchess's knee, while plates and dishes crashed around it--once
+more the shriek of the Gryphon, the squeaking of the Lizard's
+slate-pencil, and the choking of the suppressed guinea-pigs,
+filled the air, mixed up with the distant sobs of the miserable
+Mock Turtle.
+
+ So she sat on, with closed eyes, and half believed herself in
+Wonderland, though she knew she had but to open them again, and
+all would change to dull reality--the grass would be only
+rustling in the wind, and the pool rippling to the waving of the
+reeds--the rattling teacups would change to tinkling sheep-
+bells, and the Queen's shrill cries to the voice of the shepherd
+boy--and the sneeze of the baby, the shriek of the Gryphon, and
+all thy other queer noises, would change (she knew) to the
+confused clamour of the busy farm-yard--while the lowing of the
+cattle in the distance would take the place of the Mock Turtle's
+heavy sobs.
+
+ Lastly, she pictured to herself how this same little sister of
+hers would, in the after-time, be herself a grown woman; and how
+she would keep, through all her riper years, the simple and
+loving heart of her childhood: and how she would gather about
+her other little children, and make THEIR eyes bright and eager
+with many a strange tale, perhaps even with the dream of
+Wonderland of long ago: and how she would feel with all their
+simple sorrows, and find a pleasure in all their simple joys,
+remembering her own child-life, and the happy summer days.
+
+ THE END
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt.compressed
new file mode 100644
index 000000000..37d86e253
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/alice29.txt.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt
new file mode 100644
index 000000000..88dc7b60f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt
@@ -0,0 +1,4122 @@
+ AS YOU LIKE IT
+
+
+ DRAMATIS PERSONAE
+
+
+DUKE SENIOR living in banishment.
+
+DUKE FREDERICK his brother, an usurper of his dominions.
+
+
+AMIENS |
+ | lords attending on the banished duke.
+JAQUES |
+
+
+LE BEAU a courtier attending upon Frederick.
+
+CHARLES wrestler to Frederick.
+
+
+OLIVER |
+ |
+JAQUES (JAQUES DE BOYS:) | sons of Sir Rowland de Boys.
+ |
+ORLANDO |
+
+
+ADAM |
+ | servants to Oliver.
+DENNIS |
+
+
+TOUCHSTONE a clown.
+
+SIR OLIVER MARTEXT a vicar.
+
+
+CORIN |
+ | shepherds.
+SILVIUS |
+
+
+WILLIAM a country fellow in love with Audrey.
+
+ A person representing HYMEN. (HYMEN:)
+
+ROSALIND daughter to the banished duke.
+
+CELIA daughter to Frederick.
+
+PHEBE a shepherdess.
+
+AUDREY a country wench.
+
+ Lords, pages, and attendants, &c.
+ (Forester:)
+ (A Lord:)
+ (First Lord:)
+ (Second Lord:)
+ (First Page:)
+ (Second Page:)
+
+
+SCENE Oliver's house; Duke Frederick's court; and the
+ Forest of Arden.
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT I
+
+
+
+SCENE I Orchard of Oliver's house.
+
+
+ [Enter ORLANDO and ADAM]
+
+ORLANDO As I remember, Adam, it was upon this fashion
+ bequeathed me by will but poor a thousand crowns,
+ and, as thou sayest, charged my brother, on his
+ blessing, to breed me well: and there begins my
+ sadness. My brother Jaques he keeps at school, and
+ report speaks goldenly of his profit: for my part,
+ he keeps me rustically at home, or, to speak more
+ properly, stays me here at home unkept; for call you
+ that keeping for a gentleman of my birth, that
+ differs not from the stalling of an ox? His horses
+ are bred better; for, besides that they are fair
+ with their feeding, they are taught their manage,
+ and to that end riders dearly hired: but I, his
+ brother, gain nothing under him but growth; for the
+ which his animals on his dunghills are as much
+ bound to him as I. Besides this nothing that he so
+ plentifully gives me, the something that nature gave
+ me his countenance seems to take from me: he lets
+ me feed with his hinds, bars me the place of a
+ brother, and, as much as in him lies, mines my
+ gentility with my education. This is it, Adam, that
+ grieves me; and the spirit of my father, which I
+ think is within me, begins to mutiny against this
+ servitude: I will no longer endure it, though yet I
+ know no wise remedy how to avoid it.
+
+ADAM Yonder comes my master, your brother.
+
+ORLANDO Go apart, Adam, and thou shalt hear how he will
+ shake me up.
+
+ [Enter OLIVER]
+
+OLIVER Now, sir! what make you here?
+
+ORLANDO Nothing: I am not taught to make any thing.
+
+OLIVER What mar you then, sir?
+
+ORLANDO Marry, sir, I am helping you to mar that which God
+ made, a poor unworthy brother of yours, with idleness.
+
+OLIVER Marry, sir, be better employed, and be naught awhile.
+
+ORLANDO Shall I keep your hogs and eat husks with them?
+ What prodigal portion have I spent, that I should
+ come to such penury?
+
+OLIVER Know you where your are, sir?
+
+ORLANDO O, sir, very well; here in your orchard.
+
+OLIVER Know you before whom, sir?
+
+ORLANDO Ay, better than him I am before knows me. I know
+ you are my eldest brother; and, in the gentle
+ condition of blood, you should so know me. The
+ courtesy of nations allows you my better, in that
+ you are the first-born; but the same tradition
+ takes not away my blood, were there twenty brothers
+ betwixt us: I have as much of my father in me as
+ you; albeit, I confess, your coming before me is
+ nearer to his reverence.
+
+OLIVER What, boy!
+
+ORLANDO Come, come, elder brother, you are too young in this.
+
+OLIVER Wilt thou lay hands on me, villain?
+
+ORLANDO I am no villain; I am the youngest son of Sir
+ Rowland de Boys; he was my father, and he is thrice
+ a villain that says such a father begot villains.
+ Wert thou not my brother, I would not take this hand
+ from thy throat till this other had pulled out thy
+ tongue for saying so: thou hast railed on thyself.
+
+ADAM Sweet masters, be patient: for your father's
+ remembrance, be at accord.
+
+OLIVER Let me go, I say.
+
+ORLANDO I will not, till I please: you shall hear me. My
+ father charged you in his will to give me good
+ education: you have trained me like a peasant,
+ obscuring and hiding from me all gentleman-like
+ qualities. The spirit of my father grows strong in
+ me, and I will no longer endure it: therefore allow
+ me such exercises as may become a gentleman, or
+ give me the poor allottery my father left me by
+ testament; with that I will go buy my fortunes.
+
+OLIVER And what wilt thou do? beg, when that is spent?
+ Well, sir, get you in: I will not long be troubled
+ with you; you shall have some part of your will: I
+ pray you, leave me.
+
+ORLANDO I will no further offend you than becomes me for my good.
+
+OLIVER Get you with him, you old dog.
+
+ADAM Is 'old dog' my reward? Most true, I have lost my
+ teeth in your service. God be with my old master!
+ he would not have spoke such a word.
+
+ [Exeunt ORLANDO and ADAM]
+
+OLIVER Is it even so? begin you to grow upon me? I will
+ physic your rankness, and yet give no thousand
+ crowns neither. Holla, Dennis!
+
+ [Enter DENNIS]
+
+DENNIS Calls your worship?
+
+OLIVER Was not Charles, the duke's wrestler, here to speak with me?
+
+DENNIS So please you, he is here at the door and importunes
+ access to you.
+
+OLIVER Call him in.
+
+ [Exit DENNIS]
+
+ 'Twill be a good way; and to-morrow the wrestling is.
+
+ [Enter CHARLES]
+
+CHARLES Good morrow to your worship.
+
+OLIVER Good Monsieur Charles, what's the new news at the
+ new court?
+
+CHARLES There's no news at the court, sir, but the old news:
+ that is, the old duke is banished by his younger
+ brother the new duke; and three or four loving lords
+ have put themselves into voluntary exile with him,
+ whose lands and revenues enrich the new duke;
+ therefore he gives them good leave to wander.
+
+OLIVER Can you tell if Rosalind, the duke's daughter, be
+ banished with her father?
+
+CHARLES O, no; for the duke's daughter, her cousin, so loves
+ her, being ever from their cradles bred together,
+ that she would have followed her exile, or have died
+ to stay behind her. She is at the court, and no
+ less beloved of her uncle than his own daughter; and
+ never two ladies loved as they do.
+
+OLIVER Where will the old duke live?
+
+CHARLES They say he is already in the forest of Arden, and
+ a many merry men with him; and there they live like
+ the old Robin Hood of England: they say many young
+ gentlemen flock to him every day, and fleet the time
+ carelessly, as they did in the golden world.
+
+OLIVER What, you wrestle to-morrow before the new duke?
+
+CHARLES Marry, do I, sir; and I came to acquaint you with a
+ matter. I am given, sir, secretly to understand
+ that your younger brother Orlando hath a disposition
+ to come in disguised against me to try a fall.
+ To-morrow, sir, I wrestle for my credit; and he that
+ escapes me without some broken limb shall acquit him
+ well. Your brother is but young and tender; and,
+ for your love, I would be loath to foil him, as I
+ must, for my own honour, if he come in: therefore,
+ out of my love to you, I came hither to acquaint you
+ withal, that either you might stay him from his
+ intendment or brook such disgrace well as he shall
+ run into, in that it is a thing of his own search
+ and altogether against my will.
+
+OLIVER Charles, I thank thee for thy love to me, which
+ thou shalt find I will most kindly requite. I had
+ myself notice of my brother's purpose herein and
+ have by underhand means laboured to dissuade him from
+ it, but he is resolute. I'll tell thee, Charles:
+ it is the stubbornest young fellow of France, full
+ of ambition, an envious emulator of every man's
+ good parts, a secret and villanous contriver against
+ me his natural brother: therefore use thy
+ discretion; I had as lief thou didst break his neck
+ as his finger. And thou wert best look to't; for if
+ thou dost him any slight disgrace or if he do not
+ mightily grace himself on thee, he will practise
+ against thee by poison, entrap thee by some
+ treacherous device and never leave thee till he
+ hath ta'en thy life by some indirect means or other;
+ for, I assure thee, and almost with tears I speak
+ it, there is not one so young and so villanous this
+ day living. I speak but brotherly of him; but
+ should I anatomize him to thee as he is, I must
+ blush and weep and thou must look pale and wonder.
+
+CHARLES I am heartily glad I came hither to you. If he come
+ to-morrow, I'll give him his payment: if ever he go
+ alone again, I'll never wrestle for prize more: and
+ so God keep your worship!
+
+OLIVER Farewell, good Charles.
+
+ [Exit CHARLES]
+
+ Now will I stir this gamester: I hope I shall see
+ an end of him; for my soul, yet I know not why,
+ hates nothing more than he. Yet he's gentle, never
+ schooled and yet learned, full of noble device, of
+ all sorts enchantingly beloved, and indeed so much
+ in the heart of the world, and especially of my own
+ people, who best know him, that I am altogether
+ misprised: but it shall not be so long; this
+ wrestler shall clear all: nothing remains but that
+ I kindle the boy thither; which now I'll go about.
+
+ [Exit]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT I
+
+
+
+SCENE II Lawn before the Duke's palace.
+
+
+ [Enter CELIA and ROSALIND]
+
+CELIA I pray thee, Rosalind, sweet my coz, be merry.
+
+ROSALIND Dear Celia, I show more mirth than I am mistress of;
+ and would you yet I were merrier? Unless you could
+ teach me to forget a banished father, you must not
+ learn me how to remember any extraordinary pleasure.
+
+CELIA Herein I see thou lovest me not with the full weight
+ that I love thee. If my uncle, thy banished father,
+ had banished thy uncle, the duke my father, so thou
+ hadst been still with me, I could have taught my
+ love to take thy father for mine: so wouldst thou,
+ if the truth of thy love to me were so righteously
+ tempered as mine is to thee.
+
+ROSALIND Well, I will forget the condition of my estate, to
+ rejoice in yours.
+
+CELIA You know my father hath no child but I, nor none is
+ like to have: and, truly, when he dies, thou shalt
+ be his heir, for what he hath taken away from thy
+ father perforce, I will render thee again in
+ affection; by mine honour, I will; and when I break
+ that oath, let me turn monster: therefore, my
+ sweet Rose, my dear Rose, be merry.
+
+ROSALIND From henceforth I will, coz, and devise sports. Let
+ me see; what think you of falling in love?
+
+CELIA Marry, I prithee, do, to make sport withal: but
+ love no man in good earnest; nor no further in sport
+ neither than with safety of a pure blush thou mayst
+ in honour come off again.
+
+ROSALIND What shall be our sport, then?
+
+CELIA Let us sit and mock the good housewife Fortune from
+ her wheel, that her gifts may henceforth be bestowed equally.
+
+ROSALIND I would we could do so, for her benefits are
+ mightily misplaced, and the bountiful blind woman
+ doth most mistake in her gifts to women.
+
+CELIA 'Tis true; for those that she makes fair she scarce
+ makes honest, and those that she makes honest she
+ makes very ill-favouredly.
+
+ROSALIND Nay, now thou goest from Fortune's office to
+ Nature's: Fortune reigns in gifts of the world,
+ not in the lineaments of Nature.
+
+ [Enter TOUCHSTONE]
+
+CELIA No? when Nature hath made a fair creature, may she
+ not by Fortune fall into the fire? Though Nature
+ hath given us wit to flout at Fortune, hath not
+ Fortune sent in this fool to cut off the argument?
+
+ROSALIND Indeed, there is Fortune too hard for Nature, when
+ Fortune makes Nature's natural the cutter-off of
+ Nature's wit.
+
+CELIA Peradventure this is not Fortune's work neither, but
+ Nature's; who perceiveth our natural wits too dull
+ to reason of such goddesses and hath sent this
+ natural for our whetstone; for always the dulness of
+ the fool is the whetstone of the wits. How now,
+ wit! whither wander you?
+
+TOUCHSTONE Mistress, you must come away to your father.
+
+CELIA Were you made the messenger?
+
+TOUCHSTONE No, by mine honour, but I was bid to come for you.
+
+ROSALIND Where learned you that oath, fool?
+
+TOUCHSTONE Of a certain knight that swore by his honour they
+ were good pancakes and swore by his honour the
+ mustard was naught: now I'll stand to it, the
+ pancakes were naught and the mustard was good, and
+ yet was not the knight forsworn.
+
+CELIA How prove you that, in the great heap of your
+ knowledge?
+
+ROSALIND Ay, marry, now unmuzzle your wisdom.
+
+TOUCHSTONE Stand you both forth now: stroke your chins, and
+ swear by your beards that I am a knave.
+
+CELIA By our beards, if we had them, thou art.
+
+TOUCHSTONE By my knavery, if I had it, then I were; but if you
+ swear by that that is not, you are not forsworn: no
+ more was this knight swearing by his honour, for he
+ never had any; or if he had, he had sworn it away
+ before ever he saw those pancakes or that mustard.
+
+CELIA Prithee, who is't that thou meanest?
+
+TOUCHSTONE One that old Frederick, your father, loves.
+
+CELIA My father's love is enough to honour him: enough!
+ speak no more of him; you'll be whipped for taxation
+ one of these days.
+
+TOUCHSTONE The more pity, that fools may not speak wisely what
+ wise men do foolishly.
+
+CELIA By my troth, thou sayest true; for since the little
+ wit that fools have was silenced, the little foolery
+ that wise men have makes a great show. Here comes
+ Monsieur Le Beau.
+
+ROSALIND With his mouth full of news.
+
+CELIA Which he will put on us, as pigeons feed their young.
+
+ROSALIND Then shall we be news-crammed.
+
+CELIA All the better; we shall be the more marketable.
+
+ [Enter LE BEAU]
+
+ Bon jour, Monsieur Le Beau: what's the news?
+
+LE BEAU Fair princess, you have lost much good sport.
+
+CELIA Sport! of what colour?
+
+LE BEAU What colour, madam! how shall I answer you?
+
+ROSALIND As wit and fortune will.
+
+TOUCHSTONE Or as the Destinies decree.
+
+CELIA Well said: that was laid on with a trowel.
+
+TOUCHSTONE Nay, if I keep not my rank,--
+
+ROSALIND Thou losest thy old smell.
+
+LE BEAU You amaze me, ladies: I would have told you of good
+ wrestling, which you have lost the sight of.
+
+ROSALIND You tell us the manner of the wrestling.
+
+LE BEAU I will tell you the beginning; and, if it please
+ your ladyships, you may see the end; for the best is
+ yet to do; and here, where you are, they are coming
+ to perform it.
+
+CELIA Well, the beginning, that is dead and buried.
+
+LE BEAU There comes an old man and his three sons,--
+
+CELIA I could match this beginning with an old tale.
+
+LE BEAU Three proper young men, of excellent growth and presence.
+
+ROSALIND With bills on their necks, 'Be it known unto all men
+ by these presents.'
+
+LE BEAU The eldest of the three wrestled with Charles, the
+ duke's wrestler; which Charles in a moment threw him
+ and broke three of his ribs, that there is little
+ hope of life in him: so he served the second, and
+ so the third. Yonder they lie; the poor old man,
+ their father, making such pitiful dole over them
+ that all the beholders take his part with weeping.
+
+ROSALIND Alas!
+
+TOUCHSTONE But what is the sport, monsieur, that the ladies
+ have lost?
+
+LE BEAU Why, this that I speak of.
+
+TOUCHSTONE Thus men may grow wiser every day: it is the first
+ time that ever I heard breaking of ribs was sport
+ for ladies.
+
+CELIA Or I, I promise thee.
+
+ROSALIND But is there any else longs to see this broken music
+ in his sides? is there yet another dotes upon
+ rib-breaking? Shall we see this wrestling, cousin?
+
+LE BEAU You must, if you stay here; for here is the place
+ appointed for the wrestling, and they are ready to
+ perform it.
+
+CELIA Yonder, sure, they are coming: let us now stay and see it.
+
+ [Flourish. Enter DUKE FREDERICK, Lords, ORLANDO,
+ CHARLES, and Attendants]
+
+DUKE FREDERICK Come on: since the youth will not be entreated, his
+ own peril on his forwardness.
+
+ROSALIND Is yonder the man?
+
+LE BEAU Even he, madam.
+
+CELIA Alas, he is too young! yet he looks successfully.
+
+DUKE FREDERICK How now, daughter and cousin! are you crept hither
+ to see the wrestling?
+
+ROSALIND Ay, my liege, so please you give us leave.
+
+DUKE FREDERICK You will take little delight in it, I can tell you;
+ there is such odds in the man. In pity of the
+ challenger's youth I would fain dissuade him, but he
+ will not be entreated. Speak to him, ladies; see if
+ you can move him.
+
+CELIA Call him hither, good Monsieur Le Beau.
+
+DUKE FREDERICK Do so: I'll not be by.
+
+LE BEAU Monsieur the challenger, the princesses call for you.
+
+ORLANDO I attend them with all respect and duty.
+
+ROSALIND Young man, have you challenged Charles the wrestler?
+
+ORLANDO No, fair princess; he is the general challenger: I
+ come but in, as others do, to try with him the
+ strength of my youth.
+
+CELIA Young gentleman, your spirits are too bold for your
+ years. You have seen cruel proof of this man's
+ strength: if you saw yourself with your eyes or
+ knew yourself with your judgment, the fear of your
+ adventure would counsel you to a more equal
+ enterprise. We pray you, for your own sake, to
+ embrace your own safety and give over this attempt.
+
+ROSALIND Do, young sir; your reputation shall not therefore
+ be misprised: we will make it our suit to the duke
+ that the wrestling might not go forward.
+
+ORLANDO I beseech you, punish me not with your hard
+ thoughts; wherein I confess me much guilty, to deny
+ so fair and excellent ladies any thing. But let
+ your fair eyes and gentle wishes go with me to my
+ trial: wherein if I be foiled, there is but one
+ shamed that was never gracious; if killed, but one
+ dead that was willing to be so: I shall do my
+ friends no wrong, for I have none to lament me, the
+ world no injury, for in it I have nothing; only in
+ the world I fill up a place, which may be better
+ supplied when I have made it empty.
+
+ROSALIND The little strength that I have, I would it were with you.
+
+CELIA And mine, to eke out hers.
+
+ROSALIND Fare you well: pray heaven I be deceived in you!
+
+CELIA Your heart's desires be with you!
+
+CHARLES Come, where is this young gallant that is so
+ desirous to lie with his mother earth?
+
+ORLANDO Ready, sir; but his will hath in it a more modest working.
+
+DUKE FREDERICK You shall try but one fall.
+
+CHARLES No, I warrant your grace, you shall not entreat him
+ to a second, that have so mightily persuaded him
+ from a first.
+
+ORLANDO An you mean to mock me after, you should not have
+ mocked me before: but come your ways.
+
+ROSALIND Now Hercules be thy speed, young man!
+
+CELIA I would I were invisible, to catch the strong
+ fellow by the leg.
+
+ [They wrestle]
+
+ROSALIND O excellent young man!
+
+CELIA If I had a thunderbolt in mine eye, I can tell who
+ should down.
+
+ [Shout. CHARLES is thrown]
+
+DUKE FREDERICK No more, no more.
+
+ORLANDO Yes, I beseech your grace: I am not yet well breathed.
+
+DUKE FREDERICK How dost thou, Charles?
+
+LE BEAU He cannot speak, my lord.
+
+DUKE FREDERICK Bear him away. What is thy name, young man?
+
+ORLANDO Orlando, my liege; the youngest son of Sir Rowland de Boys.
+
+DUKE FREDERICK I would thou hadst been son to some man else:
+ The world esteem'd thy father honourable,
+ But I did find him still mine enemy:
+ Thou shouldst have better pleased me with this deed,
+ Hadst thou descended from another house.
+ But fare thee well; thou art a gallant youth:
+ I would thou hadst told me of another father.
+
+ [Exeunt DUKE FREDERICK, train, and LE BEAU]
+
+CELIA Were I my father, coz, would I do this?
+
+ORLANDO I am more proud to be Sir Rowland's son,
+ His youngest son; and would not change that calling,
+ To be adopted heir to Frederick.
+
+ROSALIND My father loved Sir Rowland as his soul,
+ And all the world was of my father's mind:
+ Had I before known this young man his son,
+ I should have given him tears unto entreaties,
+ Ere he should thus have ventured.
+
+CELIA Gentle cousin,
+ Let us go thank him and encourage him:
+ My father's rough and envious disposition
+ Sticks me at heart. Sir, you have well deserved:
+ If you do keep your promises in love
+ But justly, as you have exceeded all promise,
+ Your mistress shall be happy.
+
+ROSALIND Gentleman,
+
+ [Giving him a chain from her neck]
+
+ Wear this for me, one out of suits with fortune,
+ That could give more, but that her hand lacks means.
+ Shall we go, coz?
+
+CELIA Ay. Fare you well, fair gentleman.
+
+ORLANDO Can I not say, I thank you? My better parts
+ Are all thrown down, and that which here stands up
+ Is but a quintain, a mere lifeless block.
+
+ROSALIND He calls us back: my pride fell with my fortunes;
+ I'll ask him what he would. Did you call, sir?
+ Sir, you have wrestled well and overthrown
+ More than your enemies.
+
+CELIA Will you go, coz?
+
+ROSALIND Have with you. Fare you well.
+
+ [Exeunt ROSALIND and CELIA]
+
+ORLANDO What passion hangs these weights upon my tongue?
+ I cannot speak to her, yet she urged conference.
+ O poor Orlando, thou art overthrown!
+ Or Charles or something weaker masters thee.
+
+ [Re-enter LE BEAU]
+
+LE BEAU Good sir, I do in friendship counsel you
+ To leave this place. Albeit you have deserved
+ High commendation, true applause and love,
+ Yet such is now the duke's condition
+ That he misconstrues all that you have done.
+ The duke is humorous; what he is indeed,
+ More suits you to conceive than I to speak of.
+
+ORLANDO I thank you, sir: and, pray you, tell me this:
+ Which of the two was daughter of the duke
+ That here was at the wrestling?
+
+LE BEAU Neither his daughter, if we judge by manners;
+ But yet indeed the lesser is his daughter
+ The other is daughter to the banish'd duke,
+ And here detain'd by her usurping uncle,
+ To keep his daughter company; whose loves
+ Are dearer than the natural bond of sisters.
+ But I can tell you that of late this duke
+ Hath ta'en displeasure 'gainst his gentle niece,
+ Grounded upon no other argument
+ But that the people praise her for her virtues
+ And pity her for her good father's sake;
+ And, on my life, his malice 'gainst the lady
+ Will suddenly break forth. Sir, fare you well:
+ Hereafter, in a better world than this,
+ I shall desire more love and knowledge of you.
+
+ORLANDO I rest much bounden to you: fare you well.
+
+ [Exit LE BEAU]
+
+ Thus must I from the smoke into the smother;
+ From tyrant duke unto a tyrant brother:
+ But heavenly Rosalind!
+
+ [Exit]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT I
+
+
+
+SCENE III A room in the palace.
+
+
+ [Enter CELIA and ROSALIND]
+
+CELIA Why, cousin! why, Rosalind! Cupid have mercy! not a word?
+
+ROSALIND Not one to throw at a dog.
+
+CELIA No, thy words are too precious to be cast away upon
+ curs; throw some of them at me; come, lame me with reasons.
+
+ROSALIND Then there were two cousins laid up; when the one
+ should be lamed with reasons and the other mad
+ without any.
+
+CELIA But is all this for your father?
+
+ROSALIND No, some of it is for my child's father. O, how
+ full of briers is this working-day world!
+
+CELIA They are but burs, cousin, thrown upon thee in
+ holiday foolery: if we walk not in the trodden
+ paths our very petticoats will catch them.
+
+ROSALIND I could shake them off my coat: these burs are in my heart.
+
+CELIA Hem them away.
+
+ROSALIND I would try, if I could cry 'hem' and have him.
+
+CELIA Come, come, wrestle with thy affections.
+
+ROSALIND O, they take the part of a better wrestler than myself!
+
+CELIA O, a good wish upon you! you will try in time, in
+ despite of a fall. But, turning these jests out of
+ service, let us talk in good earnest: is it
+ possible, on such a sudden, you should fall into so
+ strong a liking with old Sir Rowland's youngest son?
+
+ROSALIND The duke my father loved his father dearly.
+
+CELIA Doth it therefore ensue that you should love his son
+ dearly? By this kind of chase, I should hate him,
+ for my father hated his father dearly; yet I hate
+ not Orlando.
+
+ROSALIND No, faith, hate him not, for my sake.
+
+CELIA Why should I not? doth he not deserve well?
+
+ROSALIND Let me love him for that, and do you love him
+ because I do. Look, here comes the duke.
+
+CELIA With his eyes full of anger.
+
+ [Enter DUKE FREDERICK, with Lords]
+
+DUKE FREDERICK Mistress, dispatch you with your safest haste
+ And get you from our court.
+
+ROSALIND Me, uncle?
+
+DUKE FREDERICK You, cousin
+ Within these ten days if that thou be'st found
+ So near our public court as twenty miles,
+ Thou diest for it.
+
+ROSALIND I do beseech your grace,
+ Let me the knowledge of my fault bear with me:
+ If with myself I hold intelligence
+ Or have acquaintance with mine own desires,
+ If that I do not dream or be not frantic,--
+ As I do trust I am not--then, dear uncle,
+ Never so much as in a thought unborn
+ Did I offend your highness.
+
+DUKE FREDERICK Thus do all traitors:
+ If their purgation did consist in words,
+ They are as innocent as grace itself:
+ Let it suffice thee that I trust thee not.
+
+ROSALIND Yet your mistrust cannot make me a traitor:
+ Tell me whereon the likelihood depends.
+
+DUKE FREDERICK Thou art thy father's daughter; there's enough.
+
+ROSALIND So was I when your highness took his dukedom;
+ So was I when your highness banish'd him:
+ Treason is not inherited, my lord;
+ Or, if we did derive it from our friends,
+ What's that to me? my father was no traitor:
+ Then, good my liege, mistake me not so much
+ To think my poverty is treacherous.
+
+CELIA Dear sovereign, hear me speak.
+
+DUKE FREDERICK Ay, Celia; we stay'd her for your sake,
+ Else had she with her father ranged along.
+
+CELIA I did not then entreat to have her stay;
+ It was your pleasure and your own remorse:
+ I was too young that time to value her;
+ But now I know her: if she be a traitor,
+ Why so am I; we still have slept together,
+ Rose at an instant, learn'd, play'd, eat together,
+ And wheresoever we went, like Juno's swans,
+ Still we went coupled and inseparable.
+
+DUKE FREDERICK She is too subtle for thee; and her smoothness,
+ Her very silence and her patience
+ Speak to the people, and they pity her.
+ Thou art a fool: she robs thee of thy name;
+ And thou wilt show more bright and seem more virtuous
+ When she is gone. Then open not thy lips:
+ Firm and irrevocable is my doom
+ Which I have pass'd upon her; she is banish'd.
+
+CELIA Pronounce that sentence then on me, my liege:
+ I cannot live out of her company.
+
+DUKE FREDERICK You are a fool. You, niece, provide yourself:
+ If you outstay the time, upon mine honour,
+ And in the greatness of my word, you die.
+
+ [Exeunt DUKE FREDERICK and Lords]
+
+CELIA O my poor Rosalind, whither wilt thou go?
+ Wilt thou change fathers? I will give thee mine.
+ I charge thee, be not thou more grieved than I am.
+
+ROSALIND I have more cause.
+
+CELIA Thou hast not, cousin;
+ Prithee be cheerful: know'st thou not, the duke
+ Hath banish'd me, his daughter?
+
+ROSALIND That he hath not.
+
+CELIA No, hath not? Rosalind lacks then the love
+ Which teacheth thee that thou and I am one:
+ Shall we be sunder'd? shall we part, sweet girl?
+ No: let my father seek another heir.
+ Therefore devise with me how we may fly,
+ Whither to go and what to bear with us;
+ And do not seek to take your change upon you,
+ To bear your griefs yourself and leave me out;
+ For, by this heaven, now at our sorrows pale,
+ Say what thou canst, I'll go along with thee.
+
+ROSALIND Why, whither shall we go?
+
+CELIA To seek my uncle in the forest of Arden.
+
+ROSALIND Alas, what danger will it be to us,
+ Maids as we are, to travel forth so far!
+ Beauty provoketh thieves sooner than gold.
+
+CELIA I'll put myself in poor and mean attire
+ And with a kind of umber smirch my face;
+ The like do you: so shall we pass along
+ And never stir assailants.
+
+ROSALIND Were it not better,
+ Because that I am more than common tall,
+ That I did suit me all points like a man?
+ A gallant curtle-axe upon my thigh,
+ A boar-spear in my hand; and--in my heart
+ Lie there what hidden woman's fear there will--
+ We'll have a swashing and a martial outside,
+ As many other mannish cowards have
+ That do outface it with their semblances.
+
+CELIA What shall I call thee when thou art a man?
+
+ROSALIND I'll have no worse a name than Jove's own page;
+ And therefore look you call me Ganymede.
+ But what will you be call'd?
+
+CELIA Something that hath a reference to my state
+ No longer Celia, but Aliena.
+
+ROSALIND But, cousin, what if we assay'd to steal
+ The clownish fool out of your father's court?
+ Would he not be a comfort to our travel?
+
+CELIA He'll go along o'er the wide world with me;
+ Leave me alone to woo him. Let's away,
+ And get our jewels and our wealth together,
+ Devise the fittest time and safest way
+ To hide us from pursuit that will be made
+ After my flight. Now go we in content
+ To liberty and not to banishment.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE I The Forest of Arden.
+
+
+ [Enter DUKE SENIOR, AMIENS, and two or three Lords,
+ like foresters]
+
+DUKE SENIOR Now, my co-mates and brothers in exile,
+ Hath not old custom made this life more sweet
+ Than that of painted pomp? Are not these woods
+ More free from peril than the envious court?
+ Here feel we but the penalty of Adam,
+ The seasons' difference, as the icy fang
+ And churlish chiding of the winter's wind,
+ Which, when it bites and blows upon my body,
+ Even till I shrink with cold, I smile and say
+ 'This is no flattery: these are counsellors
+ That feelingly persuade me what I am.'
+ Sweet are the uses of adversity,
+ Which, like the toad, ugly and venomous,
+ Wears yet a precious jewel in his head;
+ And this our life exempt from public haunt
+ Finds tongues in trees, books in the running brooks,
+ Sermons in stones and good in every thing.
+ I would not change it.
+
+AMIENS Happy is your grace,
+ That can translate the stubbornness of fortune
+ Into so quiet and so sweet a style.
+
+DUKE SENIOR Come, shall we go and kill us venison?
+ And yet it irks me the poor dappled fools,
+ Being native burghers of this desert city,
+ Should in their own confines with forked heads
+ Have their round haunches gored.
+
+First Lord Indeed, my lord,
+ The melancholy Jaques grieves at that,
+ And, in that kind, swears you do more usurp
+ Than doth your brother that hath banish'd you.
+ To-day my Lord of Amiens and myself
+ Did steal behind him as he lay along
+ Under an oak whose antique root peeps out
+ Upon the brook that brawls along this wood:
+ To the which place a poor sequester'd stag,
+ That from the hunter's aim had ta'en a hurt,
+ Did come to languish, and indeed, my lord,
+ The wretched animal heaved forth such groans
+ That their discharge did stretch his leathern coat
+ Almost to bursting, and the big round tears
+ Coursed one another down his innocent nose
+ In piteous chase; and thus the hairy fool
+ Much marked of the melancholy Jaques,
+ Stood on the extremest verge of the swift brook,
+ Augmenting it with tears.
+
+DUKE SENIOR But what said Jaques?
+ Did he not moralize this spectacle?
+
+First Lord O, yes, into a thousand similes.
+ First, for his weeping into the needless stream;
+ 'Poor deer,' quoth he, 'thou makest a testament
+ As worldlings do, giving thy sum of more
+ To that which had too much:' then, being there alone,
+ Left and abandon'd of his velvet friends,
+ ''Tis right:' quoth he; 'thus misery doth part
+ The flux of company:' anon a careless herd,
+ Full of the pasture, jumps along by him
+ And never stays to greet him; 'Ay' quoth Jaques,
+ 'Sweep on, you fat and greasy citizens;
+ 'Tis just the fashion: wherefore do you look
+ Upon that poor and broken bankrupt there?'
+ Thus most invectively he pierceth through
+ The body of the country, city, court,
+ Yea, and of this our life, swearing that we
+ Are mere usurpers, tyrants and what's worse,
+ To fright the animals and to kill them up
+ In their assign'd and native dwelling-place.
+
+DUKE SENIOR And did you leave him in this contemplation?
+
+Second Lord We did, my lord, weeping and commenting
+ Upon the sobbing deer.
+
+DUKE SENIOR Show me the place:
+ I love to cope him in these sullen fits,
+ For then he's full of matter.
+
+First Lord I'll bring you to him straight.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE II A room in the palace.
+
+
+ [Enter DUKE FREDERICK, with Lords]
+
+DUKE FREDERICK Can it be possible that no man saw them?
+ It cannot be: some villains of my court
+ Are of consent and sufferance in this.
+
+First Lord I cannot hear of any that did see her.
+ The ladies, her attendants of her chamber,
+ Saw her abed, and in the morning early
+ They found the bed untreasured of their mistress.
+
+Second Lord My lord, the roynish clown, at whom so oft
+ Your grace was wont to laugh, is also missing.
+ Hisperia, the princess' gentlewoman,
+ Confesses that she secretly o'erheard
+ Your daughter and her cousin much commend
+ The parts and graces of the wrestler
+ That did but lately foil the sinewy Charles;
+ And she believes, wherever they are gone,
+ That youth is surely in their company.
+
+DUKE FREDERICK Send to his brother; fetch that gallant hither;
+ If he be absent, bring his brother to me;
+ I'll make him find him: do this suddenly,
+ And let not search and inquisition quail
+ To bring again these foolish runaways.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE III Before OLIVER'S house.
+
+
+ [Enter ORLANDO and ADAM, meeting]
+
+ORLANDO Who's there?
+
+ADAM What, my young master? O, my gentle master!
+ O my sweet master! O you memory
+ Of old Sir Rowland! why, what make you here?
+ Why are you virtuous? why do people love you?
+ And wherefore are you gentle, strong and valiant?
+ Why would you be so fond to overcome
+ The bonny priser of the humorous duke?
+ Your praise is come too swiftly home before you.
+ Know you not, master, to some kind of men
+ Their graces serve them but as enemies?
+ No more do yours: your virtues, gentle master,
+ Are sanctified and holy traitors to you.
+ O, what a world is this, when what is comely
+ Envenoms him that bears it!
+
+ORLANDO Why, what's the matter?
+
+ADAM O unhappy youth!
+ Come not within these doors; within this roof
+ The enemy of all your graces lives:
+ Your brother--no, no brother; yet the son--
+ Yet not the son, I will not call him son
+ Of him I was about to call his father--
+ Hath heard your praises, and this night he means
+ To burn the lodging where you use to lie
+ And you within it: if he fail of that,
+ He will have other means to cut you off.
+ I overheard him and his practises.
+ This is no place; this house is but a butchery:
+ Abhor it, fear it, do not enter it.
+
+ORLANDO Why, whither, Adam, wouldst thou have me go?
+
+ADAM No matter whither, so you come not here.
+
+ORLANDO What, wouldst thou have me go and beg my food?
+ Or with a base and boisterous sword enforce
+ A thievish living on the common road?
+ This I must do, or know not what to do:
+ Yet this I will not do, do how I can;
+ I rather will subject me to the malice
+ Of a diverted blood and bloody brother.
+
+ADAM But do not so. I have five hundred crowns,
+ The thrifty hire I saved under your father,
+ Which I did store to be my foster-nurse
+ When service should in my old limbs lie lame
+ And unregarded age in corners thrown:
+ Take that, and He that doth the ravens feed,
+ Yea, providently caters for the sparrow,
+ Be comfort to my age! Here is the gold;
+ And all this I give you. Let me be your servant:
+ Though I look old, yet I am strong and lusty;
+ For in my youth I never did apply
+ Hot and rebellious liquors in my blood,
+ Nor did not with unbashful forehead woo
+ The means of weakness and debility;
+ Therefore my age is as a lusty winter,
+ Frosty, but kindly: let me go with you;
+ I'll do the service of a younger man
+ In all your business and necessities.
+
+ORLANDO O good old man, how well in thee appears
+ The constant service of the antique world,
+ When service sweat for duty, not for meed!
+ Thou art not for the fashion of these times,
+ Where none will sweat but for promotion,
+ And having that, do choke their service up
+ Even with the having: it is not so with thee.
+ But, poor old man, thou prunest a rotten tree,
+ That cannot so much as a blossom yield
+ In lieu of all thy pains and husbandry
+ But come thy ways; well go along together,
+ And ere we have thy youthful wages spent,
+ We'll light upon some settled low content.
+
+ADAM Master, go on, and I will follow thee,
+ To the last gasp, with truth and loyalty.
+ From seventeen years till now almost fourscore
+ Here lived I, but now live here no more.
+ At seventeen years many their fortunes seek;
+ But at fourscore it is too late a week:
+ Yet fortune cannot recompense me better
+ Than to die well and not my master's debtor.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE IV The Forest of Arden.
+
+
+ [Enter ROSALIND for Ganymede, CELIA for Aliena,
+ and TOUCHSTONE]
+
+ROSALIND O Jupiter, how weary are my spirits!
+
+TOUCHSTONE I care not for my spirits, if my legs were not weary.
+
+ROSALIND I could find in my heart to disgrace my man's
+ apparel and to cry like a woman; but I must comfort
+ the weaker vessel, as doublet and hose ought to show
+ itself courageous to petticoat: therefore courage,
+ good Aliena!
+
+CELIA I pray you, bear with me; I cannot go no further.
+
+TOUCHSTONE For my part, I had rather bear with you than bear
+ you; yet I should bear no cross if I did bear you,
+ for I think you have no money in your purse.
+
+ROSALIND Well, this is the forest of Arden.
+
+TOUCHSTONE Ay, now am I in Arden; the more fool I; when I was
+ at home, I was in a better place: but travellers
+ must be content.
+
+ROSALIND Ay, be so, good Touchstone.
+
+ [Enter CORIN and SILVIUS]
+
+ Look you, who comes here; a young man and an old in
+ solemn talk.
+
+CORIN That is the way to make her scorn you still.
+
+SILVIUS O Corin, that thou knew'st how I do love her!
+
+CORIN I partly guess; for I have loved ere now.
+
+SILVIUS No, Corin, being old, thou canst not guess,
+ Though in thy youth thou wast as true a lover
+ As ever sigh'd upon a midnight pillow:
+ But if thy love were ever like to mine--
+ As sure I think did never man love so--
+ How many actions most ridiculous
+ Hast thou been drawn to by thy fantasy?
+
+CORIN Into a thousand that I have forgotten.
+
+SILVIUS O, thou didst then ne'er love so heartily!
+ If thou remember'st not the slightest folly
+ That ever love did make thee run into,
+ Thou hast not loved:
+ Or if thou hast not sat as I do now,
+ Wearying thy hearer in thy mistress' praise,
+ Thou hast not loved:
+ Or if thou hast not broke from company
+ Abruptly, as my passion now makes me,
+ Thou hast not loved.
+ O Phebe, Phebe, Phebe!
+
+ [Exit]
+
+ROSALIND Alas, poor shepherd! searching of thy wound,
+ I have by hard adventure found mine own.
+
+TOUCHSTONE And I mine. I remember, when I was in love I broke
+ my sword upon a stone and bid him take that for
+ coming a-night to Jane Smile; and I remember the
+ kissing of her batlet and the cow's dugs that her
+ pretty chopt hands had milked; and I remember the
+ wooing of a peascod instead of her, from whom I took
+ two cods and, giving her them again, said with
+ weeping tears 'Wear these for my sake.' We that are
+ true lovers run into strange capers; but as all is
+ mortal in nature, so is all nature in love mortal in folly.
+
+ROSALIND Thou speakest wiser than thou art ware of.
+
+TOUCHSTONE Nay, I shall ne'er be ware of mine own wit till I
+ break my shins against it.
+
+ROSALIND Jove, Jove! this shepherd's passion
+ Is much upon my fashion.
+
+TOUCHSTONE And mine; but it grows something stale with me.
+
+CELIA I pray you, one of you question yond man
+ If he for gold will give us any food:
+ I faint almost to death.
+
+TOUCHSTONE Holla, you clown!
+
+ROSALIND Peace, fool: he's not thy kinsman.
+
+CORIN Who calls?
+
+TOUCHSTONE Your betters, sir.
+
+CORIN Else are they very wretched.
+
+ROSALIND Peace, I say. Good even to you, friend.
+
+CORIN And to you, gentle sir, and to you all.
+
+ROSALIND I prithee, shepherd, if that love or gold
+ Can in this desert place buy entertainment,
+ Bring us where we may rest ourselves and feed:
+ Here's a young maid with travel much oppress'd
+ And faints for succor.
+
+CORIN Fair sir, I pity her
+ And wish, for her sake more than for mine own,
+ My fortunes were more able to relieve her;
+ But I am shepherd to another man
+ And do not shear the fleeces that I graze:
+ My master is of churlish disposition
+ And little recks to find the way to heaven
+ By doing deeds of hospitality:
+ Besides, his cote, his flocks and bounds of feed
+ Are now on sale, and at our sheepcote now,
+ By reason of his absence, there is nothing
+ That you will feed on; but what is, come see.
+ And in my voice most welcome shall you be.
+
+ROSALIND What is he that shall buy his flock and pasture?
+
+CORIN That young swain that you saw here but erewhile,
+ That little cares for buying any thing.
+
+ROSALIND I pray thee, if it stand with honesty,
+ Buy thou the cottage, pasture and the flock,
+ And thou shalt have to pay for it of us.
+
+CELIA And we will mend thy wages. I like this place.
+ And willingly could waste my time in it.
+
+CORIN Assuredly the thing is to be sold:
+ Go with me: if you like upon report
+ The soil, the profit and this kind of life,
+ I will your very faithful feeder be
+ And buy it with your gold right suddenly.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE V The Forest.
+
+
+ [Enter AMIENS, JAQUES, and others]
+
+ SONG.
+AMIENS Under the greenwood tree
+ Who loves to lie with me,
+ And turn his merry note
+ Unto the sweet bird's throat,
+ Come hither, come hither, come hither:
+ Here shall he see No enemy
+ But winter and rough weather.
+
+JAQUES More, more, I prithee, more.
+
+AMIENS It will make you melancholy, Monsieur Jaques.
+
+JAQUES I thank it. More, I prithee, more. I can suck
+ melancholy out of a song, as a weasel sucks eggs.
+ More, I prithee, more.
+
+AMIENS My voice is ragged: I know I cannot please you.
+
+JAQUES I do not desire you to please me; I do desire you to
+ sing. Come, more; another stanzo: call you 'em stanzos?
+
+AMIENS What you will, Monsieur Jaques.
+
+JAQUES Nay, I care not for their names; they owe me
+ nothing. Will you sing?
+
+AMIENS More at your request than to please myself.
+
+JAQUES Well then, if ever I thank any man, I'll thank you;
+ but that they call compliment is like the encounter
+ of two dog-apes, and when a man thanks me heartily,
+ methinks I have given him a penny and he renders me
+ the beggarly thanks. Come, sing; and you that will
+ not, hold your tongues.
+
+AMIENS Well, I'll end the song. Sirs, cover the while; the
+ duke will drink under this tree. He hath been all
+ this day to look you.
+
+JAQUES And I have been all this day to avoid him. He is
+ too disputable for my company: I think of as many
+ matters as he, but I give heaven thanks and make no
+ boast of them. Come, warble, come.
+
+ SONG.
+ Who doth ambition shun
+
+ [All together here]
+
+ And loves to live i' the sun,
+ Seeking the food he eats
+ And pleased with what he gets,
+ Come hither, come hither, come hither:
+ Here shall he see No enemy
+ But winter and rough weather.
+
+JAQUES I'll give you a verse to this note that I made
+ yesterday in despite of my invention.
+
+AMIENS And I'll sing it.
+
+JAQUES Thus it goes:--
+
+ If it do come to pass
+ That any man turn ass,
+ Leaving his wealth and ease,
+ A stubborn will to please,
+ Ducdame, ducdame, ducdame:
+ Here shall he see
+ Gross fools as he,
+ An if he will come to me.
+
+AMIENS What's that 'ducdame'?
+
+JAQUES 'Tis a Greek invocation, to call fools into a
+ circle. I'll go sleep, if I can; if I cannot, I'll
+ rail against all the first-born of Egypt.
+
+AMIENS And I'll go seek the duke: his banquet is prepared.
+
+ [Exeunt severally]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE VI The forest.
+
+
+ [Enter ORLANDO and ADAM]
+
+ADAM Dear master, I can go no further. O, I die for food!
+ Here lie I down, and measure out my grave. Farewell,
+ kind master.
+
+ORLANDO Why, how now, Adam! no greater heart in thee? Live
+ a little; comfort a little; cheer thyself a little.
+ If this uncouth forest yield any thing savage, I
+ will either be food for it or bring it for food to
+ thee. Thy conceit is nearer death than thy powers.
+ For my sake be comfortable; hold death awhile at
+ the arm's end: I will here be with thee presently;
+ and if I bring thee not something to eat, I will
+ give thee leave to die: but if thou diest before I
+ come, thou art a mocker of my labour. Well said!
+ thou lookest cheerly, and I'll be with thee quickly.
+ Yet thou liest in the bleak air: come, I will bear
+ thee to some shelter; and thou shalt not die for
+ lack of a dinner, if there live any thing in this
+ desert. Cheerly, good Adam!
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT II
+
+
+
+SCENE VII The forest.
+
+
+ [A table set out. Enter DUKE SENIOR, AMIENS, and
+ Lords like outlaws]
+
+DUKE SENIOR I think he be transform'd into a beast;
+ For I can no where find him like a man.
+
+First Lord My lord, he is but even now gone hence:
+ Here was he merry, hearing of a song.
+
+DUKE SENIOR If he, compact of jars, grow musical,
+ We shall have shortly discord in the spheres.
+ Go, seek him: tell him I would speak with him.
+
+ [Enter JAQUES]
+
+First Lord He saves my labour by his own approach.
+
+DUKE SENIOR Why, how now, monsieur! what a life is this,
+ That your poor friends must woo your company?
+ What, you look merrily!
+
+JAQUES A fool, a fool! I met a fool i' the forest,
+ A motley fool; a miserable world!
+ As I do live by food, I met a fool
+ Who laid him down and bask'd him in the sun,
+ And rail'd on Lady Fortune in good terms,
+ In good set terms and yet a motley fool.
+ 'Good morrow, fool,' quoth I. 'No, sir,' quoth he,
+ 'Call me not fool till heaven hath sent me fortune:'
+ And then he drew a dial from his poke,
+ And, looking on it with lack-lustre eye,
+ Says very wisely, 'It is ten o'clock:
+ Thus we may see,' quoth he, 'how the world wags:
+ 'Tis but an hour ago since it was nine,
+ And after one hour more 'twill be eleven;
+ And so, from hour to hour, we ripe and ripe,
+ And then, from hour to hour, we rot and rot;
+ And thereby hangs a tale.' When I did hear
+ The motley fool thus moral on the time,
+ My lungs began to crow like chanticleer,
+ That fools should be so deep-contemplative,
+ And I did laugh sans intermission
+ An hour by his dial. O noble fool!
+ A worthy fool! Motley's the only wear.
+
+DUKE SENIOR What fool is this?
+
+JAQUES O worthy fool! One that hath been a courtier,
+ And says, if ladies be but young and fair,
+ They have the gift to know it: and in his brain,
+ Which is as dry as the remainder biscuit
+ After a voyage, he hath strange places cramm'd
+ With observation, the which he vents
+ In mangled forms. O that I were a fool!
+ I am ambitious for a motley coat.
+
+DUKE SENIOR Thou shalt have one.
+
+JAQUES It is my only suit;
+ Provided that you weed your better judgments
+ Of all opinion that grows rank in them
+ That I am wise. I must have liberty
+ Withal, as large a charter as the wind,
+ To blow on whom I please; for so fools have;
+ And they that are most galled with my folly,
+ They most must laugh. And why, sir, must they so?
+ The 'why' is plain as way to parish church:
+ He that a fool doth very wisely hit
+ Doth very foolishly, although he smart,
+ Not to seem senseless of the bob: if not,
+ The wise man's folly is anatomized
+ Even by the squandering glances of the fool.
+ Invest me in my motley; give me leave
+ To speak my mind, and I will through and through
+ Cleanse the foul body of the infected world,
+ If they will patiently receive my medicine.
+
+DUKE SENIOR Fie on thee! I can tell what thou wouldst do.
+
+JAQUES What, for a counter, would I do but good?
+
+DUKE SENIOR Most mischievous foul sin, in chiding sin:
+ For thou thyself hast been a libertine,
+ As sensual as the brutish sting itself;
+ And all the embossed sores and headed evils,
+ That thou with licence of free foot hast caught,
+ Wouldst thou disgorge into the general world.
+
+JAQUES Why, who cries out on pride,
+ That can therein tax any private party?
+ Doth it not flow as hugely as the sea,
+ Till that the weary very means do ebb?
+ What woman in the city do I name,
+ When that I say the city-woman bears
+ The cost of princes on unworthy shoulders?
+ Who can come in and say that I mean her,
+ When such a one as she such is her neighbour?
+ Or what is he of basest function
+ That says his bravery is not of my cost,
+ Thinking that I mean him, but therein suits
+ His folly to the mettle of my speech?
+ There then; how then? what then? Let me see wherein
+ My tongue hath wrong'd him: if it do him right,
+ Then he hath wrong'd himself; if he be free,
+ Why then my taxing like a wild-goose flies,
+ Unclaim'd of any man. But who comes here?
+
+ [Enter ORLANDO, with his sword drawn]
+
+ORLANDO Forbear, and eat no more.
+
+JAQUES Why, I have eat none yet.
+
+ORLANDO Nor shalt not, till necessity be served.
+
+JAQUES Of what kind should this cock come of?
+
+DUKE SENIOR Art thou thus bolden'd, man, by thy distress,
+ Or else a rude despiser of good manners,
+ That in civility thou seem'st so empty?
+
+ORLANDO You touch'd my vein at first: the thorny point
+ Of bare distress hath ta'en from me the show
+ Of smooth civility: yet am I inland bred
+ And know some nurture. But forbear, I say:
+ He dies that touches any of this fruit
+ Till I and my affairs are answered.
+
+JAQUES An you will not be answered with reason, I must die.
+
+DUKE SENIOR What would you have? Your gentleness shall force
+ More than your force move us to gentleness.
+
+ORLANDO I almost die for food; and let me have it.
+
+DUKE SENIOR Sit down and feed, and welcome to our table.
+
+ORLANDO Speak you so gently? Pardon me, I pray you:
+ I thought that all things had been savage here;
+ And therefore put I on the countenance
+ Of stern commandment. But whate'er you are
+ That in this desert inaccessible,
+ Under the shade of melancholy boughs,
+ Lose and neglect the creeping hours of time
+ If ever you have look'd on better days,
+ If ever been where bells have knoll'd to church,
+ If ever sat at any good man's feast,
+ If ever from your eyelids wiped a tear
+ And know what 'tis to pity and be pitied,
+ Let gentleness my strong enforcement be:
+ In the which hope I blush, and hide my sword.
+
+DUKE SENIOR True is it that we have seen better days,
+ And have with holy bell been knoll'd to church
+ And sat at good men's feasts and wiped our eyes
+ Of drops that sacred pity hath engender'd:
+ And therefore sit you down in gentleness
+ And take upon command what help we have
+ That to your wanting may be minister'd.
+
+ORLANDO Then but forbear your food a little while,
+ Whiles, like a doe, I go to find my fawn
+ And give it food. There is an old poor man,
+ Who after me hath many a weary step
+ Limp'd in pure love: till he be first sufficed,
+ Oppress'd with two weak evils, age and hunger,
+ I will not touch a bit.
+
+DUKE SENIOR Go find him out,
+ And we will nothing waste till you return.
+
+ORLANDO I thank ye; and be blest for your good comfort!
+
+ [Exit]
+
+DUKE SENIOR Thou seest we are not all alone unhappy:
+ This wide and universal theatre
+ Presents more woeful pageants than the scene
+ Wherein we play in.
+
+JAQUES All the world's a stage,
+ And all the men and women merely players:
+ They have their exits and their entrances;
+ And one man in his time plays many parts,
+ His acts being seven ages. At first the infant,
+ Mewling and puking in the nurse's arms.
+ And then the whining school-boy, with his satchel
+ And shining morning face, creeping like snail
+ Unwillingly to school. And then the lover,
+ Sighing like furnace, with a woeful ballad
+ Made to his mistress' eyebrow. Then a soldier,
+ Full of strange oaths and bearded like the pard,
+ Jealous in honour, sudden and quick in quarrel,
+ Seeking the bubble reputation
+ Even in the cannon's mouth. And then the justice,
+ In fair round belly with good capon lined,
+ With eyes severe and beard of formal cut,
+ Full of wise saws and modern instances;
+ And so he plays his part. The sixth age shifts
+ Into the lean and slipper'd pantaloon,
+ With spectacles on nose and pouch on side,
+ His youthful hose, well saved, a world too wide
+ For his shrunk shank; and his big manly voice,
+ Turning again toward childish treble, pipes
+ And whistles in his sound. Last scene of all,
+ That ends this strange eventful history,
+ Is second childishness and mere oblivion,
+ Sans teeth, sans eyes, sans taste, sans everything.
+
+ [Re-enter ORLANDO, with ADAM]
+
+DUKE SENIOR Welcome. Set down your venerable burthen,
+ And let him feed.
+
+ORLANDO I thank you most for him.
+
+ADAM So had you need:
+ I scarce can speak to thank you for myself.
+
+DUKE SENIOR Welcome; fall to: I will not trouble you
+ As yet, to question you about your fortunes.
+ Give us some music; and, good cousin, sing.
+
+ SONG.
+AMIENS Blow, blow, thou winter wind.
+ Thou art not so unkind
+ As man's ingratitude;
+ Thy tooth is not so keen,
+ Because thou art not seen,
+ Although thy breath be rude.
+ Heigh-ho! sing, heigh-ho! unto the green holly:
+ Most friendship is feigning, most loving mere folly:
+ Then, heigh-ho, the holly!
+ This life is most jolly.
+ Freeze, freeze, thou bitter sky,
+ That dost not bite so nigh
+ As benefits forgot:
+ Though thou the waters warp,
+ Thy sting is not so sharp
+ As friend remember'd not.
+ Heigh-ho! sing, &c.
+
+DUKE SENIOR If that you were the good Sir Rowland's son,
+ As you have whisper'd faithfully you were,
+ And as mine eye doth his effigies witness
+ Most truly limn'd and living in your face,
+ Be truly welcome hither: I am the duke
+ That loved your father: the residue of your fortune,
+ Go to my cave and tell me. Good old man,
+ Thou art right welcome as thy master is.
+ Support him by the arm. Give me your hand,
+ And let me all your fortunes understand.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT III
+
+
+
+SCENE I A room in the palace.
+
+
+ [Enter DUKE FREDERICK, Lords, and OLIVER]
+
+DUKE FREDERICK Not see him since? Sir, sir, that cannot be:
+ But were I not the better part made mercy,
+ I should not seek an absent argument
+ Of my revenge, thou present. But look to it:
+ Find out thy brother, wheresoe'er he is;
+ Seek him with candle; bring him dead or living
+ Within this twelvemonth, or turn thou no more
+ To seek a living in our territory.
+ Thy lands and all things that thou dost call thine
+ Worth seizure do we seize into our hands,
+ Till thou canst quit thee by thy brothers mouth
+ Of what we think against thee.
+
+OLIVER O that your highness knew my heart in this!
+ I never loved my brother in my life.
+
+DUKE FREDERICK More villain thou. Well, push him out of doors;
+ And let my officers of such a nature
+ Make an extent upon his house and lands:
+ Do this expediently and turn him going.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT III
+
+
+
+SCENE II The forest.
+
+
+ [Enter ORLANDO, with a paper]
+
+ORLANDO Hang there, my verse, in witness of my love:
+ And thou, thrice-crowned queen of night, survey
+ With thy chaste eye, from thy pale sphere above,
+ Thy huntress' name that my full life doth sway.
+ O Rosalind! these trees shall be my books
+ And in their barks my thoughts I'll character;
+ That every eye which in this forest looks
+ Shall see thy virtue witness'd every where.
+ Run, run, Orlando; carve on every tree
+ The fair, the chaste and unexpressive she.
+
+ [Exit]
+
+ [Enter CORIN and TOUCHSTONE]
+
+CORIN And how like you this shepherd's life, Master Touchstone?
+
+TOUCHSTONE Truly, shepherd, in respect of itself, it is a good
+ life, but in respect that it is a shepherd's life,
+ it is naught. In respect that it is solitary, I
+ like it very well; but in respect that it is
+ private, it is a very vile life. Now, in respect it
+ is in the fields, it pleaseth me well; but in
+ respect it is not in the court, it is tedious. As
+ is it a spare life, look you, it fits my humour well;
+ but as there is no more plenty in it, it goes much
+ against my stomach. Hast any philosophy in thee, shepherd?
+
+CORIN No more but that I know the more one sickens the
+ worse at ease he is; and that he that wants money,
+ means and content is without three good friends;
+ that the property of rain is to wet and fire to
+ burn; that good pasture makes fat sheep, and that a
+ great cause of the night is lack of the sun; that
+ he that hath learned no wit by nature nor art may
+ complain of good breeding or comes of a very dull kindred.
+
+TOUCHSTONE Such a one is a natural philosopher. Wast ever in
+ court, shepherd?
+
+CORIN No, truly.
+
+TOUCHSTONE Then thou art damned.
+
+CORIN Nay, I hope.
+
+TOUCHSTONE Truly, thou art damned like an ill-roasted egg, all
+ on one side.
+
+CORIN For not being at court? Your reason.
+
+TOUCHSTONE Why, if thou never wast at court, thou never sawest
+ good manners; if thou never sawest good manners,
+ then thy manners must be wicked; and wickedness is
+ sin, and sin is damnation. Thou art in a parlous
+ state, shepherd.
+
+CORIN Not a whit, Touchstone: those that are good manners
+ at the court are as ridiculous in the country as the
+ behavior of the country is most mockable at the
+ court. You told me you salute not at the court, but
+ you kiss your hands: that courtesy would be
+ uncleanly, if courtiers were shepherds.
+
+TOUCHSTONE Instance, briefly; come, instance.
+
+CORIN Why, we are still handling our ewes, and their
+ fells, you know, are greasy.
+
+TOUCHSTONE Why, do not your courtier's hands sweat? and is not
+ the grease of a mutton as wholesome as the sweat of
+ a man? Shallow, shallow. A better instance, I say; come.
+
+CORIN Besides, our hands are hard.
+
+TOUCHSTONE Your lips will feel them the sooner. Shallow again.
+ A more sounder instance, come.
+
+CORIN And they are often tarred over with the surgery of
+ our sheep: and would you have us kiss tar? The
+ courtier's hands are perfumed with civet.
+
+TOUCHSTONE Most shallow man! thou worms-meat, in respect of a
+ good piece of flesh indeed! Learn of the wise, and
+ perpend: civet is of a baser birth than tar, the
+ very uncleanly flux of a cat. Mend the instance, shepherd.
+
+CORIN You have too courtly a wit for me: I'll rest.
+
+TOUCHSTONE Wilt thou rest damned? God help thee, shallow man!
+ God make incision in thee! thou art raw.
+
+CORIN Sir, I am a true labourer: I earn that I eat, get
+ that I wear, owe no man hate, envy no man's
+ happiness, glad of other men's good, content with my
+ harm, and the greatest of my pride is to see my ewes
+ graze and my lambs suck.
+
+TOUCHSTONE That is another simple sin in you, to bring the ewes
+ and the rams together and to offer to get your
+ living by the copulation of cattle; to be bawd to a
+ bell-wether, and to betray a she-lamb of a
+ twelvemonth to a crooked-pated, old, cuckoldly ram,
+ out of all reasonable match. If thou beest not
+ damned for this, the devil himself will have no
+ shepherds; I cannot see else how thou shouldst
+ 'scape.
+
+CORIN Here comes young Master Ganymede, my new mistress's brother.
+
+ [Enter ROSALIND, with a paper, reading]
+
+ROSALIND From the east to western Ind,
+ No jewel is like Rosalind.
+ Her worth, being mounted on the wind,
+ Through all the world bears Rosalind.
+ All the pictures fairest lined
+ Are but black to Rosalind.
+ Let no fair be kept in mind
+ But the fair of Rosalind.
+
+TOUCHSTONE I'll rhyme you so eight years together, dinners and
+ suppers and sleeping-hours excepted: it is the
+ right butter-women's rank to market.
+
+ROSALIND Out, fool!
+
+TOUCHSTONE For a taste:
+ If a hart do lack a hind,
+ Let him seek out Rosalind.
+ If the cat will after kind,
+ So be sure will Rosalind.
+ Winter garments must be lined,
+ So must slender Rosalind.
+ They that reap must sheaf and bind;
+ Then to cart with Rosalind.
+ Sweetest nut hath sourest rind,
+ Such a nut is Rosalind.
+ He that sweetest rose will find
+ Must find love's prick and Rosalind.
+ This is the very false gallop of verses: why do you
+ infect yourself with them?
+
+ROSALIND Peace, you dull fool! I found them on a tree.
+
+TOUCHSTONE Truly, the tree yields bad fruit.
+
+ROSALIND I'll graff it with you, and then I shall graff it
+ with a medlar: then it will be the earliest fruit
+ i' the country; for you'll be rotten ere you be half
+ ripe, and that's the right virtue of the medlar.
+
+TOUCHSTONE You have said; but whether wisely or no, let the
+ forest judge.
+
+ [Enter CELIA, with a writing]
+
+ROSALIND Peace! Here comes my sister, reading: stand aside.
+
+CELIA [Reads]
+
+ Why should this a desert be?
+ For it is unpeopled? No:
+ Tongues I'll hang on every tree,
+ That shall civil sayings show:
+ Some, how brief the life of man
+ Runs his erring pilgrimage,
+ That the stretching of a span
+ Buckles in his sum of age;
+ Some, of violated vows
+ 'Twixt the souls of friend and friend:
+ But upon the fairest boughs,
+ Or at every sentence end,
+ Will I Rosalinda write,
+ Teaching all that read to know
+ The quintessence of every sprite
+ Heaven would in little show.
+ Therefore Heaven Nature charged
+ That one body should be fill'd
+ With all graces wide-enlarged:
+ Nature presently distill'd
+ Helen's cheek, but not her heart,
+ Cleopatra's majesty,
+ Atalanta's better part,
+ Sad Lucretia's modesty.
+ Thus Rosalind of many parts
+ By heavenly synod was devised,
+ Of many faces, eyes and hearts,
+ To have the touches dearest prized.
+ Heaven would that she these gifts should have,
+ And I to live and die her slave.
+
+ROSALIND O most gentle pulpiter! what tedious homily of love
+ have you wearied your parishioners withal, and never
+ cried 'Have patience, good people!'
+
+CELIA How now! back, friends! Shepherd, go off a little.
+ Go with him, sirrah.
+
+TOUCHSTONE Come, shepherd, let us make an honourable retreat;
+ though not with bag and baggage, yet with scrip and scrippage.
+
+ [Exeunt CORIN and TOUCHSTONE]
+
+CELIA Didst thou hear these verses?
+
+ROSALIND O, yes, I heard them all, and more too; for some of
+ them had in them more feet than the verses would bear.
+
+CELIA That's no matter: the feet might bear the verses.
+
+ROSALIND Ay, but the feet were lame and could not bear
+ themselves without the verse and therefore stood
+ lamely in the verse.
+
+CELIA But didst thou hear without wondering how thy name
+ should be hanged and carved upon these trees?
+
+ROSALIND I was seven of the nine days out of the wonder
+ before you came; for look here what I found on a
+ palm-tree. I was never so be-rhymed since
+ Pythagoras' time, that I was an Irish rat, which I
+ can hardly remember.
+
+CELIA Trow you who hath done this?
+
+ROSALIND Is it a man?
+
+CELIA And a chain, that you once wore, about his neck.
+ Change you colour?
+
+ROSALIND I prithee, who?
+
+CELIA O Lord, Lord! it is a hard matter for friends to
+ meet; but mountains may be removed with earthquakes
+ and so encounter.
+
+ROSALIND Nay, but who is it?
+
+CELIA Is it possible?
+
+ROSALIND Nay, I prithee now with most petitionary vehemence,
+ tell me who it is.
+
+CELIA O wonderful, wonderful, and most wonderful
+ wonderful! and yet again wonderful, and after that,
+ out of all hooping!
+
+ROSALIND Good my complexion! dost thou think, though I am
+ caparisoned like a man, I have a doublet and hose in
+ my disposition? One inch of delay more is a
+ South-sea of discovery; I prithee, tell me who is it
+ quickly, and speak apace. I would thou couldst
+ stammer, that thou mightst pour this concealed man
+ out of thy mouth, as wine comes out of a narrow-
+ mouthed bottle, either too much at once, or none at
+ all. I prithee, take the cork out of thy mouth that
+ may drink thy tidings.
+
+CELIA So you may put a man in your belly.
+
+ROSALIND Is he of God's making? What manner of man? Is his
+ head worth a hat, or his chin worth a beard?
+
+CELIA Nay, he hath but a little beard.
+
+ROSALIND Why, God will send more, if the man will be
+ thankful: let me stay the growth of his beard, if
+ thou delay me not the knowledge of his chin.
+
+CELIA It is young Orlando, that tripped up the wrestler's
+ heels and your heart both in an instant.
+
+ROSALIND Nay, but the devil take mocking: speak, sad brow and
+ true maid.
+
+CELIA I' faith, coz, 'tis he.
+
+ROSALIND Orlando?
+
+CELIA Orlando.
+
+ROSALIND Alas the day! what shall I do with my doublet and
+ hose? What did he when thou sawest him? What said
+ he? How looked he? Wherein went he? What makes
+ him here? Did he ask for me? Where remains he?
+ How parted he with thee? and when shalt thou see
+ him again? Answer me in one word.
+
+CELIA You must borrow me Gargantua's mouth first: 'tis a
+ word too great for any mouth of this age's size. To
+ say ay and no to these particulars is more than to
+ answer in a catechism.
+
+ROSALIND But doth he know that I am in this forest and in
+ man's apparel? Looks he as freshly as he did the
+ day he wrestled?
+
+CELIA It is as easy to count atomies as to resolve the
+ propositions of a lover; but take a taste of my
+ finding him, and relish it with good observance.
+ I found him under a tree, like a dropped acorn.
+
+ROSALIND It may well be called Jove's tree, when it drops
+ forth such fruit.
+
+CELIA Give me audience, good madam.
+
+ROSALIND Proceed.
+
+CELIA There lay he, stretched along, like a wounded knight.
+
+ROSALIND Though it be pity to see such a sight, it well
+ becomes the ground.
+
+CELIA Cry 'holla' to thy tongue, I prithee; it curvets
+ unseasonably. He was furnished like a hunter.
+
+ROSALIND O, ominous! he comes to kill my heart.
+
+CELIA I would sing my song without a burden: thou bringest
+ me out of tune.
+
+ROSALIND Do you not know I am a woman? when I think, I must
+ speak. Sweet, say on.
+
+CELIA You bring me out. Soft! comes he not here?
+
+ [Enter ORLANDO and JAQUES]
+
+ROSALIND 'Tis he: slink by, and note him.
+
+JAQUES I thank you for your company; but, good faith, I had
+ as lief have been myself alone.
+
+ORLANDO And so had I; but yet, for fashion sake, I thank you
+ too for your society.
+
+JAQUES God be wi' you: let's meet as little as we can.
+
+ORLANDO I do desire we may be better strangers.
+
+JAQUES I pray you, mar no more trees with writing
+ love-songs in their barks.
+
+ORLANDO I pray you, mar no more of my verses with reading
+ them ill-favouredly.
+
+JAQUES Rosalind is your love's name?
+
+ORLANDO Yes, just.
+
+JAQUES I do not like her name.
+
+ORLANDO There was no thought of pleasing you when she was
+ christened.
+
+JAQUES What stature is she of?
+
+ORLANDO Just as high as my heart.
+
+JAQUES You are full of pretty answers. Have you not been
+ acquainted with goldsmiths' wives, and conned them
+ out of rings?
+
+ORLANDO Not so; but I answer you right painted cloth, from
+ whence you have studied your questions.
+
+JAQUES You have a nimble wit: I think 'twas made of
+ Atalanta's heels. Will you sit down with me? and
+ we two will rail against our mistress the world and
+ all our misery.
+
+ORLANDO I will chide no breather in the world but myself,
+ against whom I know most faults.
+
+JAQUES The worst fault you have is to be in love.
+
+ORLANDO 'Tis a fault I will not change for your best virtue.
+ I am weary of you.
+
+JAQUES By my troth, I was seeking for a fool when I found
+ you.
+
+ORLANDO He is drowned in the brook: look but in, and you
+ shall see him.
+
+JAQUES There I shall see mine own figure.
+
+ORLANDO Which I take to be either a fool or a cipher.
+
+JAQUES I'll tarry no longer with you: farewell, good
+ Signior Love.
+
+ORLANDO I am glad of your departure: adieu, good Monsieur
+ Melancholy.
+
+ [Exit JAQUES]
+
+ROSALIND [Aside to CELIA] I will speak to him, like a saucy
+ lackey and under that habit play the knave with him.
+ Do you hear, forester?
+
+ORLANDO Very well: what would you?
+
+ROSALIND I pray you, what is't o'clock?
+
+ORLANDO You should ask me what time o' day: there's no clock
+ in the forest.
+
+ROSALIND Then there is no true lover in the forest; else
+ sighing every minute and groaning every hour would
+ detect the lazy foot of Time as well as a clock.
+
+ORLANDO And why not the swift foot of Time? had not that
+ been as proper?
+
+ROSALIND By no means, sir: Time travels in divers paces with
+ divers persons. I'll tell you who Time ambles
+ withal, who Time trots withal, who Time gallops
+ withal and who he stands still withal.
+
+ORLANDO I prithee, who doth he trot withal?
+
+ROSALIND Marry, he trots hard with a young maid between the
+ contract of her marriage and the day it is
+ solemnized: if the interim be but a se'nnight,
+ Time's pace is so hard that it seems the length of
+ seven year.
+
+ORLANDO Who ambles Time withal?
+
+ROSALIND With a priest that lacks Latin and a rich man that
+ hath not the gout, for the one sleeps easily because
+ he cannot study, and the other lives merrily because
+ he feels no pain, the one lacking the burden of lean
+ and wasteful learning, the other knowing no burden
+ of heavy tedious penury; these Time ambles withal.
+
+ORLANDO Who doth he gallop withal?
+
+ROSALIND With a thief to the gallows, for though he go as
+ softly as foot can fall, he thinks himself too soon there.
+
+ORLANDO Who stays it still withal?
+
+ROSALIND With lawyers in the vacation, for they sleep between
+ term and term and then they perceive not how Time moves.
+
+ORLANDO Where dwell you, pretty youth?
+
+ROSALIND With this shepherdess, my sister; here in the
+ skirts of the forest, like fringe upon a petticoat.
+
+ORLANDO Are you native of this place?
+
+ROSALIND As the cony that you see dwell where she is kindled.
+
+ORLANDO Your accent is something finer than you could
+ purchase in so removed a dwelling.
+
+ROSALIND I have been told so of many: but indeed an old
+ religious uncle of mine taught me to speak, who was
+ in his youth an inland man; one that knew courtship
+ too well, for there he fell in love. I have heard
+ him read many lectures against it, and I thank God
+ I am not a woman, to be touched with so many
+ giddy offences as he hath generally taxed their
+ whole sex withal.
+
+ORLANDO Can you remember any of the principal evils that he
+ laid to the charge of women?
+
+ROSALIND There were none principal; they were all like one
+ another as half-pence are, every one fault seeming
+ monstrous till his fellow fault came to match it.
+
+ORLANDO I prithee, recount some of them.
+
+ROSALIND No, I will not cast away my physic but on those that
+ are sick. There is a man haunts the forest, that
+ abuses our young plants with carving 'Rosalind' on
+ their barks; hangs odes upon hawthorns and elegies
+ on brambles, all, forsooth, deifying the name of
+ Rosalind: if I could meet that fancy-monger I would
+ give him some good counsel, for he seems to have the
+ quotidian of love upon him.
+
+ORLANDO I am he that is so love-shaked: I pray you tell me
+ your remedy.
+
+ROSALIND There is none of my uncle's marks upon you: he
+ taught me how to know a man in love; in which cage
+ of rushes I am sure you are not prisoner.
+
+ORLANDO What were his marks?
+
+ROSALIND A lean cheek, which you have not, a blue eye and
+ sunken, which you have not, an unquestionable
+ spirit, which you have not, a beard neglected,
+ which you have not; but I pardon you for that, for
+ simply your having in beard is a younger brother's
+ revenue: then your hose should be ungartered, your
+ bonnet unbanded, your sleeve unbuttoned, your shoe
+ untied and every thing about you demonstrating a
+ careless desolation; but you are no such man; you
+ are rather point-device in your accoutrements as
+ loving yourself than seeming the lover of any other.
+
+ORLANDO Fair youth, I would I could make thee believe I love.
+
+ROSALIND Me believe it! you may as soon make her that you
+ love believe it; which, I warrant, she is apter to
+ do than to confess she does: that is one of the
+ points in the which women still give the lie to
+ their consciences. But, in good sooth, are you he
+ that hangs the verses on the trees, wherein Rosalind
+ is so admired?
+
+ORLANDO I swear to thee, youth, by the white hand of
+ Rosalind, I am that he, that unfortunate he.
+
+ROSALIND But are you so much in love as your rhymes speak?
+
+ORLANDO Neither rhyme nor reason can express how much.
+
+ROSALIND Love is merely a madness, and, I tell you, deserves
+ as well a dark house and a whip as madmen do: and
+ the reason why they are not so punished and cured
+ is, that the lunacy is so ordinary that the whippers
+ are in love too. Yet I profess curing it by counsel.
+
+ORLANDO Did you ever cure any so?
+
+ROSALIND Yes, one, and in this manner. He was to imagine me
+ his love, his mistress; and I set him every day to
+ woo me: at which time would I, being but a moonish
+ youth, grieve, be effeminate, changeable, longing
+ and liking, proud, fantastical, apish, shallow,
+ inconstant, full of tears, full of smiles, for every
+ passion something and for no passion truly any
+ thing, as boys and women are for the most part
+ cattle of this colour; would now like him, now loathe
+ him; then entertain him, then forswear him; now weep
+ for him, then spit at him; that I drave my suitor
+ from his mad humour of love to a living humour of
+ madness; which was, to forswear the full stream of
+ the world, and to live in a nook merely monastic.
+ And thus I cured him; and this way will I take upon
+ me to wash your liver as clean as a sound sheep's
+ heart, that there shall not be one spot of love in't.
+
+ORLANDO I would not be cured, youth.
+
+ROSALIND I would cure you, if you would but call me Rosalind
+ and come every day to my cote and woo me.
+
+ORLANDO Now, by the faith of my love, I will: tell me
+ where it is.
+
+ROSALIND Go with me to it and I'll show it you and by the way
+ you shall tell me where in the forest you live.
+ Will you go?
+
+ORLANDO With all my heart, good youth.
+
+ROSALIND Nay you must call me Rosalind. Come, sister, will you go?
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT III
+
+
+
+SCENE III The forest.
+
+
+ [Enter TOUCHSTONE and AUDREY; JAQUES behind]
+
+TOUCHSTONE Come apace, good Audrey: I will fetch up your
+ goats, Audrey. And how, Audrey? am I the man yet?
+ doth my simple feature content you?
+
+AUDREY Your features! Lord warrant us! what features!
+
+TOUCHSTONE I am here with thee and thy goats, as the most
+ capricious poet, honest Ovid, was among the Goths.
+
+JAQUES [Aside] O knowledge ill-inhabited, worse than Jove
+ in a thatched house!
+
+TOUCHSTONE When a man's verses cannot be understood, nor a
+ man's good wit seconded with the forward child
+ Understanding, it strikes a man more dead than a
+ great reckoning in a little room. Truly, I would
+ the gods had made thee poetical.
+
+AUDREY I do not know what 'poetical' is: is it honest in
+ deed and word? is it a true thing?
+
+TOUCHSTONE No, truly; for the truest poetry is the most
+ feigning; and lovers are given to poetry, and what
+ they swear in poetry may be said as lovers they do feign.
+
+AUDREY Do you wish then that the gods had made me poetical?
+
+TOUCHSTONE I do, truly; for thou swearest to me thou art
+ honest: now, if thou wert a poet, I might have some
+ hope thou didst feign.
+
+AUDREY Would you not have me honest?
+
+TOUCHSTONE No, truly, unless thou wert hard-favoured; for
+ honesty coupled to beauty is to have honey a sauce to sugar.
+
+JAQUES [Aside] A material fool!
+
+AUDREY Well, I am not fair; and therefore I pray the gods
+ make me honest.
+
+TOUCHSTONE Truly, and to cast away honesty upon a foul slut
+ were to put good meat into an unclean dish.
+
+AUDREY I am not a slut, though I thank the gods I am foul.
+
+TOUCHSTONE Well, praised be the gods for thy foulness!
+ sluttishness may come hereafter. But be it as it may
+ be, I will marry thee, and to that end I have been
+ with Sir Oliver Martext, the vicar of the next
+ village, who hath promised to meet me in this place
+ of the forest and to couple us.
+
+JAQUES [Aside] I would fain see this meeting.
+
+AUDREY Well, the gods give us joy!
+
+TOUCHSTONE Amen. A man may, if he were of a fearful heart,
+ stagger in this attempt; for here we have no temple
+ but the wood, no assembly but horn-beasts. But what
+ though? Courage! As horns are odious, they are
+ necessary. It is said, 'many a man knows no end of
+ his goods:' right; many a man has good horns, and
+ knows no end of them. Well, that is the dowry of
+ his wife; 'tis none of his own getting. Horns?
+ Even so. Poor men alone? No, no; the noblest deer
+ hath them as huge as the rascal. Is the single man
+ therefore blessed? No: as a walled town is more
+ worthier than a village, so is the forehead of a
+ married man more honourable than the bare brow of a
+ bachelor; and by how much defence is better than no
+ skill, by so much is a horn more precious than to
+ want. Here comes Sir Oliver.
+
+ [Enter SIR OLIVER MARTEXT]
+
+ Sir Oliver Martext, you are well met: will you
+ dispatch us here under this tree, or shall we go
+ with you to your chapel?
+
+SIR OLIVER MARTEXT Is there none here to give the woman?
+
+TOUCHSTONE I will not take her on gift of any man.
+
+SIR OLIVER MARTEXT Truly, she must be given, or the marriage is not lawful.
+
+JAQUES [Advancing]
+
+ Proceed, proceed I'll give her.
+
+TOUCHSTONE Good even, good Master What-ye-call't: how do you,
+ sir? You are very well met: God 'ild you for your
+ last company: I am very glad to see you: even a
+ toy in hand here, sir: nay, pray be covered.
+
+JAQUES Will you be married, motley?
+
+TOUCHSTONE As the ox hath his bow, sir, the horse his curb and
+ the falcon her bells, so man hath his desires; and
+ as pigeons bill, so wedlock would be nibbling.
+
+JAQUES And will you, being a man of your breeding, be
+ married under a bush like a beggar? Get you to
+ church, and have a good priest that can tell you
+ what marriage is: this fellow will but join you
+ together as they join wainscot; then one of you will
+ prove a shrunk panel and, like green timber, warp, warp.
+
+TOUCHSTONE [Aside] I am not in the mind but I were better to be
+ married of him than of another: for he is not like
+ to marry me well; and not being well married, it
+ will be a good excuse for me hereafter to leave my wife.
+
+JAQUES Go thou with me, and let me counsel thee.
+
+TOUCHSTONE 'Come, sweet Audrey:
+ We must be married, or we must live in bawdry.
+ Farewell, good Master Oliver: not,--
+ O sweet Oliver,
+ O brave Oliver,
+ Leave me not behind thee: but,--
+ Wind away,
+ Begone, I say,
+ I will not to wedding with thee.
+
+ [Exeunt JAQUES, TOUCHSTONE and AUDREY]
+
+SIR OLIVER MARTEXT 'Tis no matter: ne'er a fantastical knave of them
+ all shall flout me out of my calling.
+
+ [Exit]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT III
+
+
+
+SCENE IV The forest.
+
+
+ [Enter ROSALIND and CELIA]
+
+ROSALIND Never talk to me; I will weep.
+
+CELIA Do, I prithee; but yet have the grace to consider
+ that tears do not become a man.
+
+ROSALIND But have I not cause to weep?
+
+CELIA As good cause as one would desire; therefore weep.
+
+ROSALIND His very hair is of the dissembling colour.
+
+CELIA Something browner than Judas's marry, his kisses are
+ Judas's own children.
+
+ROSALIND I' faith, his hair is of a good colour.
+
+CELIA An excellent colour: your chestnut was ever the only colour.
+
+ROSALIND And his kissing is as full of sanctity as the touch
+ of holy bread.
+
+CELIA He hath bought a pair of cast lips of Diana: a nun
+ of winter's sisterhood kisses not more religiously;
+ the very ice of chastity is in them.
+
+ROSALIND But why did he swear he would come this morning, and
+ comes not?
+
+CELIA Nay, certainly, there is no truth in him.
+
+ROSALIND Do you think so?
+
+CELIA Yes; I think he is not a pick-purse nor a
+ horse-stealer, but for his verity in love, I do
+ think him as concave as a covered goblet or a
+ worm-eaten nut.
+
+ROSALIND Not true in love?
+
+CELIA Yes, when he is in; but I think he is not in.
+
+ROSALIND You have heard him swear downright he was.
+
+CELIA 'Was' is not 'is:' besides, the oath of a lover is
+ no stronger than the word of a tapster; they are
+ both the confirmer of false reckonings. He attends
+ here in the forest on the duke your father.
+
+ROSALIND I met the duke yesterday and had much question with
+ him: he asked me of what parentage I was; I told
+ him, of as good as he; so he laughed and let me go.
+ But what talk we of fathers, when there is such a
+ man as Orlando?
+
+CELIA O, that's a brave man! he writes brave verses,
+ speaks brave words, swears brave oaths and breaks
+ them bravely, quite traverse, athwart the heart of
+ his lover; as a puisny tilter, that spurs his horse
+ but on one side, breaks his staff like a noble
+ goose: but all's brave that youth mounts and folly
+ guides. Who comes here?
+
+ [Enter CORIN]
+
+CORIN Mistress and master, you have oft inquired
+ After the shepherd that complain'd of love,
+ Who you saw sitting by me on the turf,
+ Praising the proud disdainful shepherdess
+ That was his mistress.
+
+CELIA Well, and what of him?
+
+CORIN If you will see a pageant truly play'd,
+ Between the pale complexion of true love
+ And the red glow of scorn and proud disdain,
+ Go hence a little and I shall conduct you,
+ If you will mark it.
+
+ROSALIND O, come, let us remove:
+ The sight of lovers feedeth those in love.
+ Bring us to this sight, and you shall say
+ I'll prove a busy actor in their play.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT III
+
+
+
+SCENE V Another part of the forest.
+
+
+ [Enter SILVIUS and PHEBE]
+
+SILVIUS Sweet Phebe, do not scorn me; do not, Phebe;
+ Say that you love me not, but say not so
+ In bitterness. The common executioner,
+ Whose heart the accustom'd sight of death makes hard,
+ Falls not the axe upon the humbled neck
+ But first begs pardon: will you sterner be
+ Than he that dies and lives by bloody drops?
+
+ [Enter ROSALIND, CELIA, and CORIN, behind]
+
+PHEBE I would not be thy executioner:
+ I fly thee, for I would not injure thee.
+ Thou tell'st me there is murder in mine eye:
+ 'Tis pretty, sure, and very probable,
+ That eyes, that are the frail'st and softest things,
+ Who shut their coward gates on atomies,
+ Should be call'd tyrants, butchers, murderers!
+ Now I do frown on thee with all my heart;
+ And if mine eyes can wound, now let them kill thee:
+ Now counterfeit to swoon; why now fall down;
+ Or if thou canst not, O, for shame, for shame,
+ Lie not, to say mine eyes are murderers!
+ Now show the wound mine eye hath made in thee:
+ Scratch thee but with a pin, and there remains
+ Some scar of it; lean but upon a rush,
+ The cicatrice and capable impressure
+ Thy palm some moment keeps; but now mine eyes,
+ Which I have darted at thee, hurt thee not,
+ Nor, I am sure, there is no force in eyes
+ That can do hurt.
+
+SILVIUS O dear Phebe,
+ If ever,--as that ever may be near,--
+ You meet in some fresh cheek the power of fancy,
+ Then shall you know the wounds invisible
+ That love's keen arrows make.
+
+PHEBE But till that time
+ Come not thou near me: and when that time comes,
+ Afflict me with thy mocks, pity me not;
+ As till that time I shall not pity thee.
+
+ROSALIND And why, I pray you? Who might be your mother,
+ That you insult, exult, and all at once,
+ Over the wretched? What though you have no beauty,--
+ As, by my faith, I see no more in you
+ Than without candle may go dark to bed--
+ Must you be therefore proud and pitiless?
+ Why, what means this? Why do you look on me?
+ I see no more in you than in the ordinary
+ Of nature's sale-work. 'Od's my little life,
+ I think she means to tangle my eyes too!
+ No, faith, proud mistress, hope not after it:
+ 'Tis not your inky brows, your black silk hair,
+ Your bugle eyeballs, nor your cheek of cream,
+ That can entame my spirits to your worship.
+ You foolish shepherd, wherefore do you follow her,
+ Like foggy south puffing with wind and rain?
+ You are a thousand times a properer man
+ Than she a woman: 'tis such fools as you
+ That makes the world full of ill-favour'd children:
+ 'Tis not her glass, but you, that flatters her;
+ And out of you she sees herself more proper
+ Than any of her lineaments can show her.
+ But, mistress, know yourself: down on your knees,
+ And thank heaven, fasting, for a good man's love:
+ For I must tell you friendly in your ear,
+ Sell when you can: you are not for all markets:
+ Cry the man mercy; love him; take his offer:
+ Foul is most foul, being foul to be a scoffer.
+ So take her to thee, shepherd: fare you well.
+
+PHEBE Sweet youth, I pray you, chide a year together:
+ I had rather hear you chide than this man woo.
+
+ROSALIND He's fallen in love with your foulness and she'll
+ fall in love with my anger. If it be so, as fast as
+ she answers thee with frowning looks, I'll sauce her
+ with bitter words. Why look you so upon me?
+
+PHEBE For no ill will I bear you.
+
+ROSALIND I pray you, do not fall in love with me,
+ For I am falser than vows made in wine:
+ Besides, I like you not. If you will know my house,
+ 'Tis at the tuft of olives here hard by.
+ Will you go, sister? Shepherd, ply her hard.
+ Come, sister. Shepherdess, look on him better,
+ And be not proud: though all the world could see,
+ None could be so abused in sight as he.
+ Come, to our flock.
+
+ [Exeunt ROSALIND, CELIA and CORIN]
+
+PHEBE Dead Shepherd, now I find thy saw of might,
+ 'Who ever loved that loved not at first sight?'
+
+SILVIUS Sweet Phebe,--
+
+PHEBE Ha, what say'st thou, Silvius?
+
+SILVIUS Sweet Phebe, pity me.
+
+PHEBE Why, I am sorry for thee, gentle Silvius.
+
+SILVIUS Wherever sorrow is, relief would be:
+ If you do sorrow at my grief in love,
+ By giving love your sorrow and my grief
+ Were both extermined.
+
+PHEBE Thou hast my love: is not that neighbourly?
+
+SILVIUS I would have you.
+
+PHEBE Why, that were covetousness.
+ Silvius, the time was that I hated thee,
+ And yet it is not that I bear thee love;
+ But since that thou canst talk of love so well,
+ Thy company, which erst was irksome to me,
+ I will endure, and I'll employ thee too:
+ But do not look for further recompense
+ Than thine own gladness that thou art employ'd.
+
+SILVIUS So holy and so perfect is my love,
+ And I in such a poverty of grace,
+ That I shall think it a most plenteous crop
+ To glean the broken ears after the man
+ That the main harvest reaps: loose now and then
+ A scatter'd smile, and that I'll live upon.
+
+PHEBE Know'st now the youth that spoke to me erewhile?
+
+SILVIUS Not very well, but I have met him oft;
+ And he hath bought the cottage and the bounds
+ That the old carlot once was master of.
+
+PHEBE Think not I love him, though I ask for him:
+ 'Tis but a peevish boy; yet he talks well;
+ But what care I for words? yet words do well
+ When he that speaks them pleases those that hear.
+ It is a pretty youth: not very pretty:
+ But, sure, he's proud, and yet his pride becomes him:
+ He'll make a proper man: the best thing in him
+ Is his complexion; and faster than his tongue
+ Did make offence his eye did heal it up.
+ He is not very tall; yet for his years he's tall:
+ His leg is but so so; and yet 'tis well:
+ There was a pretty redness in his lip,
+ A little riper and more lusty red
+ Than that mix'd in his cheek; 'twas just the difference
+ Between the constant red and mingled damask.
+ There be some women, Silvius, had they mark'd him
+ In parcels as I did, would have gone near
+ To fall in love with him; but, for my part,
+ I love him not nor hate him not; and yet
+ I have more cause to hate him than to love him:
+ For what had he to do to chide at me?
+ He said mine eyes were black and my hair black:
+ And, now I am remember'd, scorn'd at me:
+ I marvel why I answer'd not again:
+ But that's all one; omittance is no quittance.
+ I'll write to him a very taunting letter,
+ And thou shalt bear it: wilt thou, Silvius?
+
+SILVIUS Phebe, with all my heart.
+
+PHEBE I'll write it straight;
+ The matter's in my head and in my heart:
+ I will be bitter with him and passing short.
+ Go with me, Silvius.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT IV
+
+
+
+SCENE I The forest.
+
+
+ [Enter ROSALIND, CELIA, and JAQUES]
+
+JAQUES I prithee, pretty youth, let me be better acquainted
+ with thee.
+
+ROSALIND They say you are a melancholy fellow.
+
+JAQUES I am so; I do love it better than laughing.
+
+ROSALIND Those that are in extremity of either are abominable
+ fellows and betray themselves to every modern
+ censure worse than drunkards.
+
+JAQUES Why, 'tis good to be sad and say nothing.
+
+ROSALIND Why then, 'tis good to be a post.
+
+JAQUES I have neither the scholar's melancholy, which is
+ emulation, nor the musician's, which is fantastical,
+ nor the courtier's, which is proud, nor the
+ soldier's, which is ambitious, nor the lawyer's,
+ which is politic, nor the lady's, which is nice, nor
+ the lover's, which is all these: but it is a
+ melancholy of mine own, compounded of many simples,
+ extracted from many objects, and indeed the sundry's
+ contemplation of my travels, in which my often
+ rumination wraps me m a most humorous sadness.
+
+ROSALIND A traveller! By my faith, you have great reason to
+ be sad: I fear you have sold your own lands to see
+ other men's; then, to have seen much and to have
+ nothing, is to have rich eyes and poor hands.
+
+JAQUES Yes, I have gained my experience.
+
+ROSALIND And your experience makes you sad: I had rather have
+ a fool to make me merry than experience to make me
+ sad; and to travel for it too!
+
+ [Enter ORLANDO]
+
+ORLANDO Good day and happiness, dear Rosalind!
+
+JAQUES Nay, then, God be wi' you, an you talk in blank verse.
+
+ [Exit]
+
+ROSALIND Farewell, Monsieur Traveller: look you lisp and
+ wear strange suits, disable all the benefits of your
+ own country, be out of love with your nativity and
+ almost chide God for making you that countenance you
+ are, or I will scarce think you have swam in a
+ gondola. Why, how now, Orlando! where have you been
+ all this while? You a lover! An you serve me such
+ another trick, never come in my sight more.
+
+ORLANDO My fair Rosalind, I come within an hour of my promise.
+
+ROSALIND Break an hour's promise in love! He that will
+ divide a minute into a thousand parts and break but
+ a part of the thousandth part of a minute in the
+ affairs of love, it may be said of him that Cupid
+ hath clapped him o' the shoulder, but I'll warrant
+ him heart-whole.
+
+ORLANDO Pardon me, dear Rosalind.
+
+ROSALIND Nay, an you be so tardy, come no more in my sight: I
+ had as lief be wooed of a snail.
+
+ORLANDO Of a snail?
+
+ROSALIND Ay, of a snail; for though he comes slowly, he
+ carries his house on his head; a better jointure,
+ I think, than you make a woman: besides he brings
+ his destiny with him.
+
+ORLANDO What's that?
+
+ROSALIND Why, horns, which such as you are fain to be
+ beholding to your wives for: but he comes armed in
+ his fortune and prevents the slander of his wife.
+
+ORLANDO Virtue is no horn-maker; and my Rosalind is virtuous.
+
+ROSALIND And I am your Rosalind.
+
+CELIA It pleases him to call you so; but he hath a
+ Rosalind of a better leer than you.
+
+ROSALIND Come, woo me, woo me, for now I am in a holiday
+ humour and like enough to consent. What would you
+ say to me now, an I were your very very Rosalind?
+
+ORLANDO I would kiss before I spoke.
+
+ROSALIND Nay, you were better speak first, and when you were
+ gravelled for lack of matter, you might take
+ occasion to kiss. Very good orators, when they are
+ out, they will spit; and for lovers lacking--God
+ warn us!--matter, the cleanliest shift is to kiss.
+
+ORLANDO How if the kiss be denied?
+
+ROSALIND Then she puts you to entreaty, and there begins new matter.
+
+ORLANDO Who could be out, being before his beloved mistress?
+
+ROSALIND Marry, that should you, if I were your mistress, or
+ I should think my honesty ranker than my wit.
+
+ORLANDO What, of my suit?
+
+ROSALIND Not out of your apparel, and yet out of your suit.
+ Am not I your Rosalind?
+
+ORLANDO I take some joy to say you are, because I would be
+ talking of her.
+
+ROSALIND Well in her person I say I will not have you.
+
+ORLANDO Then in mine own person I die.
+
+ROSALIND No, faith, die by attorney. The poor world is
+ almost six thousand years old, and in all this time
+ there was not any man died in his own person,
+ videlicit, in a love-cause. Troilus had his brains
+ dashed out with a Grecian club; yet he did what he
+ could to die before, and he is one of the patterns
+ of love. Leander, he would have lived many a fair
+ year, though Hero had turned nun, if it had not been
+ for a hot midsummer night; for, good youth, he went
+ but forth to wash him in the Hellespont and being
+ taken with the cramp was drowned and the foolish
+ coroners of that age found it was 'Hero of Sestos.'
+ But these are all lies: men have died from time to
+ time and worms have eaten them, but not for love.
+
+ORLANDO I would not have my right Rosalind of this mind,
+ for, I protest, her frown might kill me.
+
+ROSALIND By this hand, it will not kill a fly. But come, now
+ I will be your Rosalind in a more coming-on
+ disposition, and ask me what you will. I will grant
+ it.
+
+ORLANDO Then love me, Rosalind.
+
+ROSALIND Yes, faith, will I, Fridays and Saturdays and all.
+
+ORLANDO And wilt thou have me?
+
+ROSALIND Ay, and twenty such.
+
+ORLANDO What sayest thou?
+
+ROSALIND Are you not good?
+
+ORLANDO I hope so.
+
+ROSALIND Why then, can one desire too much of a good thing?
+ Come, sister, you shall be the priest and marry us.
+ Give me your hand, Orlando. What do you say, sister?
+
+ORLANDO Pray thee, marry us.
+
+CELIA I cannot say the words.
+
+ROSALIND You must begin, 'Will you, Orlando--'
+
+CELIA Go to. Will you, Orlando, have to wife this Rosalind?
+
+ORLANDO I will.
+
+ROSALIND Ay, but when?
+
+ORLANDO Why now; as fast as she can marry us.
+
+ROSALIND Then you must say 'I take thee, Rosalind, for wife.'
+
+ORLANDO I take thee, Rosalind, for wife.
+
+ROSALIND I might ask you for your commission; but I do take
+ thee, Orlando, for my husband: there's a girl goes
+ before the priest; and certainly a woman's thought
+ runs before her actions.
+
+ORLANDO So do all thoughts; they are winged.
+
+ROSALIND Now tell me how long you would have her after you
+ have possessed her.
+
+ORLANDO For ever and a day.
+
+ROSALIND Say 'a day,' without the 'ever.' No, no, Orlando;
+ men are April when they woo, December when they wed:
+ maids are May when they are maids, but the sky
+ changes when they are wives. I will be more jealous
+ of thee than a Barbary cock-pigeon over his hen,
+ more clamorous than a parrot against rain, more
+ new-fangled than an ape, more giddy in my desires
+ than a monkey: I will weep for nothing, like Diana
+ in the fountain, and I will do that when you are
+ disposed to be merry; I will laugh like a hyen, and
+ that when thou art inclined to sleep.
+
+ORLANDO But will my Rosalind do so?
+
+ROSALIND By my life, she will do as I do.
+
+ORLANDO O, but she is wise.
+
+ROSALIND Or else she could not have the wit to do this: the
+ wiser, the waywarder: make the doors upon a woman's
+ wit and it will out at the casement; shut that and
+ 'twill out at the key-hole; stop that, 'twill fly
+ with the smoke out at the chimney.
+
+ORLANDO A man that had a wife with such a wit, he might say
+ 'Wit, whither wilt?'
+
+ROSALIND Nay, you might keep that cheque for it till you met
+ your wife's wit going to your neighbour's bed.
+
+ORLANDO And what wit could wit have to excuse that?
+
+ROSALIND Marry, to say she came to seek you there. You shall
+ never take her without her answer, unless you take
+ her without her tongue. O, that woman that cannot
+ make her fault her husband's occasion, let her
+ never nurse her child herself, for she will breed
+ it like a fool!
+
+ORLANDO For these two hours, Rosalind, I will leave thee.
+
+ROSALIND Alas! dear love, I cannot lack thee two hours.
+
+ORLANDO I must attend the duke at dinner: by two o'clock I
+ will be with thee again.
+
+ROSALIND Ay, go your ways, go your ways; I knew what you
+ would prove: my friends told me as much, and I
+ thought no less: that flattering tongue of yours
+ won me: 'tis but one cast away, and so, come,
+ death! Two o'clock is your hour?
+
+ORLANDO Ay, sweet Rosalind.
+
+ROSALIND By my troth, and in good earnest, and so God mend
+ me, and by all pretty oaths that are not dangerous,
+ if you break one jot of your promise or come one
+ minute behind your hour, I will think you the most
+ pathetical break-promise and the most hollow lover
+ and the most unworthy of her you call Rosalind that
+ may be chosen out of the gross band of the
+ unfaithful: therefore beware my censure and keep
+ your promise.
+
+ORLANDO With no less religion than if thou wert indeed my
+ Rosalind: so adieu.
+
+ROSALIND Well, Time is the old justice that examines all such
+ offenders, and let Time try: adieu.
+
+ [Exit ORLANDO]
+
+CELIA You have simply misused our sex in your love-prate:
+ we must have your doublet and hose plucked over your
+ head, and show the world what the bird hath done to
+ her own nest.
+
+ROSALIND O coz, coz, coz, my pretty little coz, that thou
+ didst know how many fathom deep I am in love! But
+ it cannot be sounded: my affection hath an unknown
+ bottom, like the bay of Portugal.
+
+CELIA Or rather, bottomless, that as fast as you pour
+ affection in, it runs out.
+
+ROSALIND No, that same wicked bastard of Venus that was begot
+ of thought, conceived of spleen and born of madness,
+ that blind rascally boy that abuses every one's eyes
+ because his own are out, let him be judge how deep I
+ am in love. I'll tell thee, Aliena, I cannot be out
+ of the sight of Orlando: I'll go find a shadow and
+ sigh till he come.
+
+CELIA And I'll sleep.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT IV
+
+
+
+SCENE II The forest.
+
+
+ [Enter JAQUES, Lords, and Foresters]
+
+JAQUES Which is he that killed the deer?
+
+A Lord Sir, it was I.
+
+JAQUES Let's present him to the duke, like a Roman
+ conqueror; and it would do well to set the deer's
+ horns upon his head, for a branch of victory. Have
+ you no song, forester, for this purpose?
+
+Forester Yes, sir.
+
+JAQUES Sing it: 'tis no matter how it be in tune, so it
+ make noise enough.
+
+ SONG.
+Forester What shall he have that kill'd the deer?
+ His leather skin and horns to wear.
+ Then sing him home;
+
+ [The rest shall bear this burden]
+
+ Take thou no scorn to wear the horn;
+ It was a crest ere thou wast born:
+ Thy father's father wore it,
+ And thy father bore it:
+ The horn, the horn, the lusty horn
+ Is not a thing to laugh to scorn.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT IV
+
+
+
+SCENE III The forest.
+
+
+ [Enter ROSALIND and CELIA]
+
+ROSALIND How say you now? Is it not past two o'clock? and
+ here much Orlando!
+
+CELIA I warrant you, with pure love and troubled brain, he
+ hath ta'en his bow and arrows and is gone forth to
+ sleep. Look, who comes here.
+
+ [Enter SILVIUS]
+
+SILVIUS My errand is to you, fair youth;
+ My gentle Phebe bid me give you this:
+ I know not the contents; but, as I guess
+ By the stern brow and waspish action
+ Which she did use as she was writing of it,
+ It bears an angry tenor: pardon me:
+ I am but as a guiltless messenger.
+
+ROSALIND Patience herself would startle at this letter
+ And play the swaggerer; bear this, bear all:
+ She says I am not fair, that I lack manners;
+ She calls me proud, and that she could not love me,
+ Were man as rare as phoenix. 'Od's my will!
+ Her love is not the hare that I do hunt:
+ Why writes she so to me? Well, shepherd, well,
+ This is a letter of your own device.
+
+SILVIUS No, I protest, I know not the contents:
+ Phebe did write it.
+
+ROSALIND Come, come, you are a fool
+ And turn'd into the extremity of love.
+ I saw her hand: she has a leathern hand.
+ A freestone-colour'd hand; I verily did think
+ That her old gloves were on, but 'twas her hands:
+ She has a huswife's hand; but that's no matter:
+ I say she never did invent this letter;
+ This is a man's invention and his hand.
+
+SILVIUS Sure, it is hers.
+
+ROSALIND Why, 'tis a boisterous and a cruel style.
+ A style for-challengers; why, she defies me,
+ Like Turk to Christian: women's gentle brain
+ Could not drop forth such giant-rude invention
+ Such Ethiope words, blacker in their effect
+ Than in their countenance. Will you hear the letter?
+
+SILVIUS So please you, for I never heard it yet;
+ Yet heard too much of Phebe's cruelty.
+
+ROSALIND She Phebes me: mark how the tyrant writes.
+
+ [Reads]
+
+ Art thou god to shepherd turn'd,
+ That a maiden's heart hath burn'd?
+ Can a woman rail thus?
+
+SILVIUS Call you this railing?
+
+ROSALIND [Reads]
+
+ Why, thy godhead laid apart,
+ Warr'st thou with a woman's heart?
+ Did you ever hear such railing?
+ Whiles the eye of man did woo me,
+ That could do no vengeance to me.
+ Meaning me a beast.
+ If the scorn of your bright eyne
+ Have power to raise such love in mine,
+ Alack, in me what strange effect
+ Would they work in mild aspect!
+ Whiles you chid me, I did love;
+ How then might your prayers move!
+ He that brings this love to thee
+ Little knows this love in me:
+ And by him seal up thy mind;
+ Whether that thy youth and kind
+ Will the faithful offer take
+ Of me and all that I can make;
+ Or else by him my love deny,
+ And then I'll study how to die.
+
+SILVIUS Call you this chiding?
+
+CELIA Alas, poor shepherd!
+
+ROSALIND Do you pity him? no, he deserves no pity. Wilt
+ thou love such a woman? What, to make thee an
+ instrument and play false strains upon thee! not to
+ be endured! Well, go your way to her, for I see
+ love hath made thee a tame snake, and say this to
+ her: that if she love me, I charge her to love
+ thee; if she will not, I will never have her unless
+ thou entreat for her. If you be a true lover,
+ hence, and not a word; for here comes more company.
+
+ [Exit SILVIUS]
+
+ [Enter OLIVER]
+
+OLIVER Good morrow, fair ones: pray you, if you know,
+ Where in the purlieus of this forest stands
+ A sheep-cote fenced about with olive trees?
+
+CELIA West of this place, down in the neighbour bottom:
+ The rank of osiers by the murmuring stream
+ Left on your right hand brings you to the place.
+ But at this hour the house doth keep itself;
+ There's none within.
+
+OLIVER If that an eye may profit by a tongue,
+ Then should I know you by description;
+ Such garments and such years: 'The boy is fair,
+ Of female favour, and bestows himself
+ Like a ripe sister: the woman low
+ And browner than her brother.' Are not you
+ The owner of the house I did inquire for?
+
+CELIA It is no boast, being ask'd, to say we are.
+
+OLIVER Orlando doth commend him to you both,
+ And to that youth he calls his Rosalind
+ He sends this bloody napkin. Are you he?
+
+ROSALIND I am: what must we understand by this?
+
+OLIVER Some of my shame; if you will know of me
+ What man I am, and how, and why, and where
+ This handkercher was stain'd.
+
+CELIA I pray you, tell it.
+
+OLIVER When last the young Orlando parted from you
+ He left a promise to return again
+ Within an hour, and pacing through the forest,
+ Chewing the food of sweet and bitter fancy,
+ Lo, what befell! he threw his eye aside,
+ And mark what object did present itself:
+ Under an oak, whose boughs were moss'd with age
+ And high top bald with dry antiquity,
+ A wretched ragged man, o'ergrown with hair,
+ Lay sleeping on his back: about his neck
+ A green and gilded snake had wreathed itself,
+ Who with her head nimble in threats approach'd
+ The opening of his mouth; but suddenly,
+ Seeing Orlando, it unlink'd itself,
+ And with indented glides did slip away
+ Into a bush: under which bush's shade
+ A lioness, with udders all drawn dry,
+ Lay couching, head on ground, with catlike watch,
+ When that the sleeping man should stir; for 'tis
+ The royal disposition of that beast
+ To prey on nothing that doth seem as dead:
+ This seen, Orlando did approach the man
+ And found it was his brother, his elder brother.
+
+CELIA O, I have heard him speak of that same brother;
+ And he did render him the most unnatural
+ That lived amongst men.
+
+OLIVER And well he might so do,
+ For well I know he was unnatural.
+
+ROSALIND But, to Orlando: did he leave him there,
+ Food to the suck'd and hungry lioness?
+
+OLIVER Twice did he turn his back and purposed so;
+ But kindness, nobler ever than revenge,
+ And nature, stronger than his just occasion,
+ Made him give battle to the lioness,
+ Who quickly fell before him: in which hurtling
+ From miserable slumber I awaked.
+
+CELIA Are you his brother?
+
+ROSALIND Wast you he rescued?
+
+CELIA Was't you that did so oft contrive to kill him?
+
+OLIVER 'Twas I; but 'tis not I I do not shame
+ To tell you what I was, since my conversion
+ So sweetly tastes, being the thing I am.
+
+ROSALIND But, for the bloody napkin?
+
+OLIVER By and by.
+ When from the first to last betwixt us two
+ Tears our recountments had most kindly bathed,
+ As how I came into that desert place:--
+ In brief, he led me to the gentle duke,
+ Who gave me fresh array and entertainment,
+ Committing me unto my brother's love;
+ Who led me instantly unto his cave,
+ There stripp'd himself, and here upon his arm
+ The lioness had torn some flesh away,
+ Which all this while had bled; and now he fainted
+ And cried, in fainting, upon Rosalind.
+ Brief, I recover'd him, bound up his wound;
+ And, after some small space, being strong at heart,
+ He sent me hither, stranger as I am,
+ To tell this story, that you might excuse
+ His broken promise, and to give this napkin
+ Dyed in his blood unto the shepherd youth
+ That he in sport doth call his Rosalind.
+
+ [ROSALIND swoons]
+
+CELIA Why, how now, Ganymede! sweet Ganymede!
+
+OLIVER Many will swoon when they do look on blood.
+
+CELIA There is more in it. Cousin Ganymede!
+
+OLIVER Look, he recovers.
+
+ROSALIND I would I were at home.
+
+CELIA We'll lead you thither.
+ I pray you, will you take him by the arm?
+
+OLIVER Be of good cheer, youth: you a man! you lack a
+ man's heart.
+
+ROSALIND I do so, I confess it. Ah, sirrah, a body would
+ think this was well counterfeited! I pray you, tell
+ your brother how well I counterfeited. Heigh-ho!
+
+OLIVER This was not counterfeit: there is too great
+ testimony in your complexion that it was a passion
+ of earnest.
+
+ROSALIND Counterfeit, I assure you.
+
+OLIVER Well then, take a good heart and counterfeit to be a man.
+
+ROSALIND So I do: but, i' faith, I should have been a woman by right.
+
+CELIA Come, you look paler and paler: pray you, draw
+ homewards. Good sir, go with us.
+
+OLIVER That will I, for I must bear answer back
+ How you excuse my brother, Rosalind.
+
+ROSALIND I shall devise something: but, I pray you, commend
+ my counterfeiting to him. Will you go?
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT V
+
+
+
+SCENE I The forest.
+
+
+ [Enter TOUCHSTONE and AUDREY]
+
+TOUCHSTONE We shall find a time, Audrey; patience, gentle Audrey.
+
+AUDREY Faith, the priest was good enough, for all the old
+ gentleman's saying.
+
+TOUCHSTONE A most wicked Sir Oliver, Audrey, a most vile
+ Martext. But, Audrey, there is a youth here in the
+ forest lays claim to you.
+
+AUDREY Ay, I know who 'tis; he hath no interest in me in
+ the world: here comes the man you mean.
+
+TOUCHSTONE It is meat and drink to me to see a clown: by my
+ troth, we that have good wits have much to answer
+ for; we shall be flouting; we cannot hold.
+
+ [Enter WILLIAM]
+
+WILLIAM Good even, Audrey.
+
+AUDREY God ye good even, William.
+
+WILLIAM And good even to you, sir.
+
+TOUCHSTONE Good even, gentle friend. Cover thy head, cover thy
+ head; nay, prithee, be covered. How old are you, friend?
+
+WILLIAM Five and twenty, sir.
+
+TOUCHSTONE A ripe age. Is thy name William?
+
+WILLIAM William, sir.
+
+TOUCHSTONE A fair name. Wast born i' the forest here?
+
+WILLIAM Ay, sir, I thank God.
+
+TOUCHSTONE 'Thank God;' a good answer. Art rich?
+
+WILLIAM Faith, sir, so so.
+
+TOUCHSTONE 'So so' is good, very good, very excellent good; and
+ yet it is not; it is but so so. Art thou wise?
+
+WILLIAM Ay, sir, I have a pretty wit.
+
+TOUCHSTONE Why, thou sayest well. I do now remember a saying,
+ 'The fool doth think he is wise, but the wise man
+ knows himself to be a fool.' The heathen
+ philosopher, when he had a desire to eat a grape,
+ would open his lips when he put it into his mouth;
+ meaning thereby that grapes were made to eat and
+ lips to open. You do love this maid?
+
+WILLIAM I do, sir.
+
+TOUCHSTONE Give me your hand. Art thou learned?
+
+WILLIAM No, sir.
+
+TOUCHSTONE Then learn this of me: to have, is to have; for it
+ is a figure in rhetoric that drink, being poured out
+ of a cup into a glass, by filling the one doth empty
+ the other; for all your writers do consent that ipse
+ is he: now, you are not ipse, for I am he.
+
+WILLIAM Which he, sir?
+
+TOUCHSTONE He, sir, that must marry this woman. Therefore, you
+ clown, abandon,--which is in the vulgar leave,--the
+ society,--which in the boorish is company,--of this
+ female,--which in the common is woman; which
+ together is, abandon the society of this female, or,
+ clown, thou perishest; or, to thy better
+ understanding, diest; or, to wit I kill thee, make
+ thee away, translate thy life into death, thy
+ liberty into bondage: I will deal in poison with
+ thee, or in bastinado, or in steel; I will bandy
+ with thee in faction; I will o'errun thee with
+ policy; I will kill thee a hundred and fifty ways:
+ therefore tremble and depart.
+
+AUDREY Do, good William.
+
+WILLIAM God rest you merry, sir.
+
+ [Exit]
+
+ [Enter CORIN]
+
+CORIN Our master and mistress seeks you; come, away, away!
+
+TOUCHSTONE Trip, Audrey! trip, Audrey! I attend, I attend.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT V
+
+
+
+SCENE II The forest.
+
+
+ [Enter ORLANDO and OLIVER]
+
+ORLANDO Is't possible that on so little acquaintance you
+ should like her? that but seeing you should love
+ her? and loving woo? and, wooing, she should
+ grant? and will you persever to enjoy her?
+
+OLIVER Neither call the giddiness of it in question, the
+ poverty of her, the small acquaintance, my sudden
+ wooing, nor her sudden consenting; but say with me,
+ I love Aliena; say with her that she loves me;
+ consent with both that we may enjoy each other: it
+ shall be to your good; for my father's house and all
+ the revenue that was old Sir Rowland's will I
+ estate upon you, and here live and die a shepherd.
+
+ORLANDO You have my consent. Let your wedding be to-morrow:
+ thither will I invite the duke and all's contented
+ followers. Go you and prepare Aliena; for look
+ you, here comes my Rosalind.
+
+ [Enter ROSALIND]
+
+ROSALIND God save you, brother.
+
+OLIVER And you, fair sister.
+
+ [Exit]
+
+ROSALIND O, my dear Orlando, how it grieves me to see thee
+ wear thy heart in a scarf!
+
+ORLANDO It is my arm.
+
+ROSALIND I thought thy heart had been wounded with the claws
+ of a lion.
+
+ORLANDO Wounded it is, but with the eyes of a lady.
+
+ROSALIND Did your brother tell you how I counterfeited to
+ swoon when he showed me your handkerchief?
+
+ORLANDO Ay, and greater wonders than that.
+
+ROSALIND O, I know where you are: nay, 'tis true: there was
+ never any thing so sudden but the fight of two rams
+ and Caesar's thrasonical brag of 'I came, saw, and
+ overcame:' for your brother and my sister no sooner
+ met but they looked, no sooner looked but they
+ loved, no sooner loved but they sighed, no sooner
+ sighed but they asked one another the reason, no
+ sooner knew the reason but they sought the remedy;
+ and in these degrees have they made a pair of stairs
+ to marriage which they will climb incontinent, or
+ else be incontinent before marriage: they are in
+ the very wrath of love and they will together; clubs
+ cannot part them.
+
+ORLANDO They shall be married to-morrow, and I will bid the
+ duke to the nuptial. But, O, how bitter a thing it
+ is to look into happiness through another man's
+ eyes! By so much the more shall I to-morrow be at
+ the height of heart-heaviness, by how much I shall
+ think my brother happy in having what he wishes for.
+
+ROSALIND Why then, to-morrow I cannot serve your turn for Rosalind?
+
+ORLANDO I can live no longer by thinking.
+
+ROSALIND I will weary you then no longer with idle talking.
+ Know of me then, for now I speak to some purpose,
+ that I know you are a gentleman of good conceit: I
+ speak not this that you should bear a good opinion
+ of my knowledge, insomuch I say I know you are;
+ neither do I labour for a greater esteem than may in
+ some little measure draw a belief from you, to do
+ yourself good and not to grace me. Believe then, if
+ you please, that I can do strange things: I have,
+ since I was three year old, conversed with a
+ magician, most profound in his art and yet not
+ damnable. If you do love Rosalind so near the heart
+ as your gesture cries it out, when your brother
+ marries Aliena, shall you marry her: I know into
+ what straits of fortune she is driven; and it is
+ not impossible to me, if it appear not inconvenient
+ to you, to set her before your eyes tomorrow human
+ as she is and without any danger.
+
+ORLANDO Speakest thou in sober meanings?
+
+ROSALIND By my life, I do; which I tender dearly, though I
+ say I am a magician. Therefore, put you in your
+ best array: bid your friends; for if you will be
+ married to-morrow, you shall, and to Rosalind, if you will.
+
+ [Enter SILVIUS and PHEBE]
+
+ Look, here comes a lover of mine and a lover of hers.
+
+PHEBE Youth, you have done me much ungentleness,
+ To show the letter that I writ to you.
+
+ROSALIND I care not if I have: it is my study
+ To seem despiteful and ungentle to you:
+ You are there followed by a faithful shepherd;
+ Look upon him, love him; he worships you.
+
+PHEBE Good shepherd, tell this youth what 'tis to love.
+
+SILVIUS It is to be all made of sighs and tears;
+ And so am I for Phebe.
+
+PHEBE And I for Ganymede.
+
+ORLANDO And I for Rosalind.
+
+ROSALIND And I for no woman.
+
+SILVIUS It is to be all made of faith and service;
+ And so am I for Phebe.
+
+PHEBE And I for Ganymede.
+
+ORLANDO And I for Rosalind.
+
+ROSALIND And I for no woman.
+
+SILVIUS It is to be all made of fantasy,
+ All made of passion and all made of wishes,
+ All adoration, duty, and observance,
+ All humbleness, all patience and impatience,
+ All purity, all trial, all observance;
+ And so am I for Phebe.
+
+PHEBE And so am I for Ganymede.
+
+ORLANDO And so am I for Rosalind.
+
+ROSALIND And so am I for no woman.
+
+PHEBE If this be so, why blame you me to love you?
+
+SILVIUS If this be so, why blame you me to love you?
+
+ORLANDO If this be so, why blame you me to love you?
+
+ROSALIND Who do you speak to, 'Why blame you me to love you?'
+
+ORLANDO To her that is not here, nor doth not hear.
+
+ROSALIND Pray you, no more of this; 'tis like the howling
+ of Irish wolves against the moon.
+
+ [To SILVIUS]
+
+ I will help you, if I can:
+
+ [To PHEBE]
+
+ I would love you, if I could. To-morrow meet me all together.
+
+ [To PHEBE]
+
+ I will marry you, if ever I marry woman, and I'll be
+ married to-morrow:
+
+ [To ORLANDO]
+
+ I will satisfy you, if ever I satisfied man, and you
+ shall be married to-morrow:
+
+ [To SILVIUS]
+
+ I will content you, if what pleases you contents
+ you, and you shall be married to-morrow.
+
+ [To ORLANDO]
+
+ As you love Rosalind, meet:
+
+ [To SILVIUS]
+
+ as you love Phebe, meet: and as I love no woman,
+ I'll meet. So fare you well: I have left you commands.
+
+SILVIUS I'll not fail, if I live.
+
+PHEBE Nor I.
+
+ORLANDO Nor I.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT V
+
+
+
+SCENE III The forest.
+
+
+ [Enter TOUCHSTONE and AUDREY]
+
+TOUCHSTONE To-morrow is the joyful day, Audrey; to-morrow will
+ we be married.
+
+AUDREY I do desire it with all my heart; and I hope it is
+ no dishonest desire to desire to be a woman of the
+ world. Here comes two of the banished duke's pages.
+
+ [Enter two Pages]
+
+First Page Well met, honest gentleman.
+
+TOUCHSTONE By my troth, well met. Come, sit, sit, and a song.
+
+Second Page We are for you: sit i' the middle.
+
+First Page Shall we clap into't roundly, without hawking or
+ spitting or saying we are hoarse, which are the only
+ prologues to a bad voice?
+
+Second Page I'faith, i'faith; and both in a tune, like two
+ gipsies on a horse.
+
+ SONG.
+ It was a lover and his lass,
+ With a hey, and a ho, and a hey nonino,
+ That o'er the green corn-field did pass
+ In the spring time, the only pretty ring time,
+ When birds do sing, hey ding a ding, ding:
+ Sweet lovers love the spring.
+
+ Between the acres of the rye,
+ With a hey, and a ho, and a hey nonino
+ These pretty country folks would lie,
+ In spring time, &c.
+
+ This carol they began that hour,
+ With a hey, and a ho, and a hey nonino,
+ How that a life was but a flower
+ In spring time, &c.
+
+ And therefore take the present time,
+ With a hey, and a ho, and a hey nonino;
+ For love is crowned with the prime
+ In spring time, &c.
+
+TOUCHSTONE Truly, young gentlemen, though there was no great
+ matter in the ditty, yet the note was very
+ untuneable.
+
+First Page You are deceived, sir: we kept time, we lost not our time.
+
+TOUCHSTONE By my troth, yes; I count it but time lost to hear
+ such a foolish song. God be wi' you; and God mend
+ your voices! Come, Audrey.
+
+ [Exeunt]
+
+
+
+
+ AS YOU LIKE IT
+
+
+ACT V
+
+
+
+SCENE IV The forest.
+
+
+ [Enter DUKE SENIOR, AMIENS, JAQUES, ORLANDO, OLIVER,
+ and CELIA]
+
+DUKE SENIOR Dost thou believe, Orlando, that the boy
+ Can do all this that he hath promised?
+
+ORLANDO I sometimes do believe, and sometimes do not;
+ As those that fear they hope, and know they fear.
+
+ [Enter ROSALIND, SILVIUS, and PHEBE]
+
+ROSALIND Patience once more, whiles our compact is urged:
+ You say, if I bring in your Rosalind,
+ You will bestow her on Orlando here?
+
+DUKE SENIOR That would I, had I kingdoms to give with her.
+
+ROSALIND And you say, you will have her, when I bring her?
+
+ORLANDO That would I, were I of all kingdoms king.
+
+ROSALIND You say, you'll marry me, if I be willing?
+
+PHEBE That will I, should I die the hour after.
+
+ROSALIND But if you do refuse to marry me,
+ You'll give yourself to this most faithful shepherd?
+
+PHEBE So is the bargain.
+
+ROSALIND You say, that you'll have Phebe, if she will?
+
+SILVIUS Though to have her and death were both one thing.
+
+ROSALIND I have promised to make all this matter even.
+ Keep you your word, O duke, to give your daughter;
+ You yours, Orlando, to receive his daughter:
+ Keep your word, Phebe, that you'll marry me,
+ Or else refusing me, to wed this shepherd:
+ Keep your word, Silvius, that you'll marry her.
+ If she refuse me: and from hence I go,
+ To make these doubts all even.
+
+ [Exeunt ROSALIND and CELIA]
+
+DUKE SENIOR I do remember in this shepherd boy
+ Some lively touches of my daughter's favour.
+
+ORLANDO My lord, the first time that I ever saw him
+ Methought he was a brother to your daughter:
+ But, my good lord, this boy is forest-born,
+ And hath been tutor'd in the rudiments
+ Of many desperate studies by his uncle,
+ Whom he reports to be a great magician,
+ Obscured in the circle of this forest.
+
+ [Enter TOUCHSTONE and AUDREY]
+
+JAQUES There is, sure, another flood toward, and these
+ couples are coming to the ark. Here comes a pair of
+ very strange beasts, which in all tongues are called fools.
+
+TOUCHSTONE Salutation and greeting to you all!
+
+JAQUES Good my lord, bid him welcome: this is the
+ motley-minded gentleman that I have so often met in
+ the forest: he hath been a courtier, he swears.
+
+TOUCHSTONE If any man doubt that, let him put me to my
+ purgation. I have trod a measure; I have flattered
+ a lady; I have been politic with my friend, smooth
+ with mine enemy; I have undone three tailors; I have
+ had four quarrels, and like to have fought one.
+
+JAQUES And how was that ta'en up?
+
+TOUCHSTONE Faith, we met, and found the quarrel was upon the
+ seventh cause.
+
+JAQUES How seventh cause? Good my lord, like this fellow.
+
+DUKE SENIOR I like him very well.
+
+TOUCHSTONE God 'ild you, sir; I desire you of the like. I
+ press in here, sir, amongst the rest of the country
+ copulatives, to swear and to forswear: according as
+ marriage binds and blood breaks: a poor virgin,
+ sir, an ill-favoured thing, sir, but mine own; a poor
+ humour of mine, sir, to take that that no man else
+ will: rich honesty dwells like a miser, sir, in a
+ poor house; as your pearl in your foul oyster.
+
+DUKE SENIOR By my faith, he is very swift and sententious.
+
+TOUCHSTONE According to the fool's bolt, sir, and such dulcet diseases.
+
+JAQUES But, for the seventh cause; how did you find the
+ quarrel on the seventh cause?
+
+TOUCHSTONE Upon a lie seven times removed:--bear your body more
+ seeming, Audrey:--as thus, sir. I did dislike the
+ cut of a certain courtier's beard: he sent me word,
+ if I said his beard was not cut well, he was in the
+ mind it was: this is called the Retort Courteous.
+ If I sent him word again 'it was not well cut,' he
+ would send me word, he cut it to please himself:
+ this is called the Quip Modest. If again 'it was
+ not well cut,' he disabled my judgment: this is
+ called the Reply Churlish. If again 'it was not
+ well cut,' he would answer, I spake not true: this
+ is called the Reproof Valiant. If again 'it was not
+ well cut,' he would say I lied: this is called the
+ Counter-cheque Quarrelsome: and so to the Lie
+ Circumstantial and the Lie Direct.
+
+JAQUES And how oft did you say his beard was not well cut?
+
+TOUCHSTONE I durst go no further than the Lie Circumstantial,
+ nor he durst not give me the Lie Direct; and so we
+ measured swords and parted.
+
+JAQUES Can you nominate in order now the degrees of the lie?
+
+TOUCHSTONE O sir, we quarrel in print, by the book; as you have
+ books for good manners: I will name you the degrees.
+ The first, the Retort Courteous; the second, the
+ Quip Modest; the third, the Reply Churlish; the
+ fourth, the Reproof Valiant; the fifth, the
+ Countercheque Quarrelsome; the sixth, the Lie with
+ Circumstance; the seventh, the Lie Direct. All
+ these you may avoid but the Lie Direct; and you may
+ avoid that too, with an If. I knew when seven
+ justices could not take up a quarrel, but when the
+ parties were met themselves, one of them thought but
+ of an If, as, 'If you said so, then I said so;' and
+ they shook hands and swore brothers. Your If is the
+ only peacemaker; much virtue in If.
+
+JAQUES Is not this a rare fellow, my lord? he's as good at
+ any thing and yet a fool.
+
+DUKE SENIOR He uses his folly like a stalking-horse and under
+ the presentation of that he shoots his wit.
+
+ [Enter HYMEN, ROSALIND, and CELIA]
+
+ [Still Music]
+
+HYMEN Then is there mirth in heaven,
+ When earthly things made even
+ Atone together.
+ Good duke, receive thy daughter
+ Hymen from heaven brought her,
+ Yea, brought her hither,
+ That thou mightst join her hand with his
+ Whose heart within his bosom is.
+
+ROSALIND [To DUKE SENIOR] To you I give myself, for I am yours.
+
+ [To ORLANDO]
+
+ To you I give myself, for I am yours.
+
+DUKE SENIOR If there be truth in sight, you are my daughter.
+
+ORLANDO If there be truth in sight, you are my Rosalind.
+
+PHEBE If sight and shape be true,
+ Why then, my love adieu!
+
+ROSALIND I'll have no father, if you be not he:
+ I'll have no husband, if you be not he:
+ Nor ne'er wed woman, if you be not she.
+
+HYMEN Peace, ho! I bar confusion:
+ 'Tis I must make conclusion
+ Of these most strange events:
+ Here's eight that must take hands
+ To join in Hymen's bands,
+ If truth holds true contents.
+ You and you no cross shall part:
+ You and you are heart in heart
+ You to his love must accord,
+ Or have a woman to your lord:
+ You and you are sure together,
+ As the winter to foul weather.
+ Whiles a wedlock-hymn we sing,
+ Feed yourselves with questioning;
+ That reason wonder may diminish,
+ How thus we met, and these things finish.
+
+ SONG.
+ Wedding is great Juno's crown:
+ O blessed bond of board and bed!
+ 'Tis Hymen peoples every town;
+ High wedlock then be honoured:
+ Honour, high honour and renown,
+ To Hymen, god of every town!
+
+DUKE SENIOR O my dear niece, welcome thou art to me!
+ Even daughter, welcome, in no less degree.
+
+PHEBE I will not eat my word, now thou art mine;
+ Thy faith my fancy to thee doth combine.
+
+ [Enter JAQUES DE BOYS]
+
+JAQUES DE BOYS Let me have audience for a word or two:
+ I am the second son of old Sir Rowland,
+ That bring these tidings to this fair assembly.
+ Duke Frederick, hearing how that every day
+ Men of great worth resorted to this forest,
+ Address'd a mighty power; which were on foot,
+ In his own conduct, purposely to take
+ His brother here and put him to the sword:
+ And to the skirts of this wild wood he came;
+ Where meeting with an old religious man,
+ After some question with him, was converted
+ Both from his enterprise and from the world,
+ His crown bequeathing to his banish'd brother,
+ And all their lands restored to them again
+ That were with him exiled. This to be true,
+ I do engage my life.
+
+DUKE SENIOR Welcome, young man;
+ Thou offer'st fairly to thy brothers' wedding:
+ To one his lands withheld, and to the other
+ A land itself at large, a potent dukedom.
+ First, in this forest, let us do those ends
+ That here were well begun and well begot:
+ And after, every of this happy number
+ That have endured shrewd days and nights with us
+ Shall share the good of our returned fortune,
+ According to the measure of their states.
+ Meantime, forget this new-fall'n dignity
+ And fall into our rustic revelry.
+ Play, music! And you, brides and bridegrooms all,
+ With measure heap'd in joy, to the measures fall.
+
+JAQUES Sir, by your patience. If I heard you rightly,
+ The duke hath put on a religious life
+ And thrown into neglect the pompous court?
+
+JAQUES DE BOYS He hath.
+
+JAQUES To him will I : out of these convertites
+ There is much matter to be heard and learn'd.
+
+ [To DUKE SENIOR]
+
+ You to your former honour I bequeath;
+ Your patience and your virtue well deserves it:
+
+ [To ORLANDO]
+
+ You to a love that your true faith doth merit:
+
+ [To OLIVER]
+
+ You to your land and love and great allies:
+
+ [To SILVIUS]
+
+ You to a long and well-deserved bed:
+
+ [To TOUCHSTONE]
+
+ And you to wrangling; for thy loving voyage
+ Is but for two months victuall'd. So, to your pleasures:
+ I am for other than for dancing measures.
+
+DUKE SENIOR Stay, Jaques, stay.
+
+JAQUES To see no pastime I what you would have
+ I'll stay to know at your abandon'd cave.
+
+ [Exit]
+
+DUKE SENIOR Proceed, proceed: we will begin these rites,
+ As we do trust they'll end, in true delights.
+
+ [A dance]
+
+
+
+
+ AS YOU LIKE IT
+
+ EPILOGUE
+
+
+ROSALIND It is not the fashion to see the lady the epilogue;
+ but it is no more unhandsome than to see the lord
+ the prologue. If it be true that good wine needs
+ no bush, 'tis true that a good play needs no
+ epilogue; yet to good wine they do use good bushes,
+ and good plays prove the better by the help of good
+ epilogues. What a case am I in then, that am
+ neither a good epilogue nor cannot insinuate with
+ you in the behalf of a good play! I am not
+ furnished like a beggar, therefore to beg will not
+ become me: my way is to conjure you; and I'll begin
+ with the women. I charge you, O women, for the love
+ you bear to men, to like as much of this play as
+ please you: and I charge you, O men, for the love
+ you bear to women--as I perceive by your simpering,
+ none of you hates them--that between you and the
+ women the play may please. If I were a woman I
+ would kiss as many of you as had beards that pleased
+ me, complexions that liked me and breaths that I
+ defied not: and, I am sure, as many as have good
+ beards or good faces or sweet breaths will, for my
+ kind offer, when I make curtsy, bid me farewell.
+
+ [Exeunt]
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt.compressed
new file mode 100644
index 000000000..3a7621100
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/asyoulik.txt.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536
new file mode 100644
index 000000000..40efb3c11
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536.compressed
new file mode 100644
index 000000000..07152197d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/backward65536.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/bb.binast b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/bb.binast
new file mode 100644
index 000000000..9b7f07399
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/bb.binast
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file
new file mode 100644
index 000000000..37d86e253
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file.compressed
new file mode 100644
index 000000000..8834f3275
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_file.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated
new file mode 100644
index 000000000..9870b5fdc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated.compressed
new file mode 100644
index 000000000..092754589
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/compressed_repeated.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed
new file mode 100644
index 000000000..f8fa5a235
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.00 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.00
new file mode 100644
index 000000000..f8fa5a235
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.00
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.01 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.01
new file mode 100644
index 000000000..17bb34721
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.01
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.02 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.02
new file mode 100644
index 000000000..c183df6a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.02
@@ -0,0 +1 @@
+¡ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.03 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.03
new file mode 100644
index 000000000..ae60db8f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.03
@@ -0,0 +1 @@
+± \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.04 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.04
new file mode 100644
index 000000000..8fac0345c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.04
@@ -0,0 +1 @@
+Á \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.05 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.05
new file mode 100644
index 000000000..98c9dcca2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.05
@@ -0,0 +1 @@
+Ñ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.06 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.06
new file mode 100644
index 000000000..84f606f03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.06
@@ -0,0 +1 @@
+á \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.07 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.07
new file mode 100644
index 000000000..0941d5368
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.07
@@ -0,0 +1 @@
+ñ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.08 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.08
new file mode 100644
index 000000000..e440e5c84
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.08
@@ -0,0 +1 @@
+3 \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.09 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.09
new file mode 100644
index 000000000..7813681f5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.09
@@ -0,0 +1 @@
+5 \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.10 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.10
new file mode 100644
index 000000000..c7930257d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.10
@@ -0,0 +1 @@
+7 \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.11 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.11
new file mode 100644
index 000000000..f11c82a4c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.11
@@ -0,0 +1 @@
+9 \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.12 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.12
new file mode 100644
index 000000000..1c8a0e797
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.12
@@ -0,0 +1 @@
+; \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.13 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.13
new file mode 100644
index 000000000..851c75cc5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.13
@@ -0,0 +1 @@
+= \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.14 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.14
new file mode 100644
index 000000000..0d758c9c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.14
@@ -0,0 +1 @@
+? \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.15 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.15
new file mode 100644
index 000000000..152f9ed5a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.15
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.16 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.16
new file mode 100644
index 000000000..e136a792a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.16
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.17 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.17
new file mode 100644
index 000000000..81f0388bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.17
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.18 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.18
new file mode 100644
index 000000000..524e34198
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/empty.compressed.18
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt
new file mode 100644
index 000000000..25dda6b3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt
@@ -0,0 +1,7519 @@
+
+
+The Project Gutenberg Etext of LOC WORKSHOP ON ELECTRONIC TEXTS
+
+
+
+
+ WORKSHOP ON ELECTRONIC TEXTS
+
+ PROCEEDINGS
+
+
+
+ Edited by James Daly
+
+
+
+
+
+
+
+ 9-10 June 1992
+
+
+ Library of Congress
+ Washington, D.C.
+
+
+
+ Supported by a Grant from the David and Lucile Packard Foundation
+
+
+ *** *** *** ****** *** *** ***
+
+
+ TABLE OF CONTENTS
+
+
+Acknowledgements
+
+Introduction
+
+Proceedings
+ Welcome
+ Prosser Gifford and Carl Fleischhauer
+
+ Session I. Content in a New Form: Who Will Use It and What Will They Do?
+ James Daly (Moderator)
+ Avra Michelson, Overview
+ Susan H. Veccia, User Evaluation
+ Joanne Freeman, Beyond the Scholar
+ Discussion
+
+ Session II. Show and Tell
+ Jacqueline Hess (Moderator)
+ Elli Mylonas, Perseus Project
+ Discussion
+ Eric M. Calaluca, Patrologia Latina Database
+ Carl Fleischhauer and Ricky Erway, American Memory
+ Discussion
+ Dorothy Twohig, The Papers of George Washington
+ Discussion
+ Maria L. Lebron, The Online Journal of Current Clinical Trials
+ Discussion
+ Lynne K. Personius, Cornell mathematics books
+ Discussion
+
+ Session III. Distribution, Networks, and Networking:
+ Options for Dissemination
+ Robert G. Zich (Moderator)
+ Clifford A. Lynch
+ Discussion
+ Howard Besser
+ Discussion
+ Ronald L. Larsen
+ Edwin B. Brownrigg
+ Discussion
+
+ Session IV. Image Capture, Text Capture, Overview of Text and
+ Image Storage Formats
+ William L. Hooton (Moderator)
+ A) Principal Methods for Image Capture of Text:
+ direct scanning, use of microform
+ Anne R. Kenney
+ Pamela Q.J. Andre
+ Judith A. Zidar
+ Donald J. Waters
+ Discussion
+ B) Special Problems: bound volumes, conservation,
+ reproducing printed halftones
+ George Thoma
+ Carl Fleischhauer
+ Discussion
+ C) Image Standards and Implications for Preservation
+ Jean Baronas
+ Patricia Battin
+ Discussion
+ D) Text Conversion: OCR vs. rekeying, standards of accuracy
+ and use of imperfect texts, service bureaus
+ Michael Lesk
+ Ricky Erway
+ Judith A. Zidar
+ Discussion
+
+ Session V. Approaches to Preparing Electronic Texts
+ Susan Hockey (Moderator)
+ Stuart Weibel
+ Discussion
+ C.M. Sperberg-McQueen
+ Discussion
+ Eric M. Calaluca
+ Discussion
+
+ Session VI. Copyright Issues
+ Marybeth Peters
+
+ Session VII. Conclusion
+ Prosser Gifford (Moderator)
+ General discussion
+
+Appendix I: Program
+
+Appendix II: Abstracts
+
+Appendix III: Directory of Participants
+
+
+ *** *** *** ****** *** *** ***
+
+
+ Acknowledgements
+
+I would like to thank Carl Fleischhauer and Prosser Gifford for the
+opportunity to learn about areas of human activity unknown to me a scant
+ten months ago, and the David and Lucile Packard Foundation for
+supporting that opportunity. The help given by others is acknowledged on
+a separate page.
+
+ 19 October 1992
+
+
+ *** *** *** ****** *** *** ***
+
+
+ INTRODUCTION
+
+The Workshop on Electronic Texts (1) drew together representatives of
+various projects and interest groups to compare ideas, beliefs,
+experiences, and, in particular, methods of placing and presenting
+historical textual materials in computerized form. Most attendees gained
+much in insight and outlook from the event. But the assembly did not
+form a new nation, or, to put it another way, the diversity of projects
+and interests was too great to draw the representatives into a cohesive,
+action-oriented body.(2)
+
+Everyone attending the Workshop shared an interest in preserving and
+providing access to historical texts. But within this broad field the
+attendees represented a variety of formal, informal, figurative, and
+literal groups, with many individuals belonging to more than one. These
+groups may be defined roughly according to the following topics or
+activities:
+
+* Imaging
+* Searchable coded texts
+* National and international computer networks
+* CD-ROM production and dissemination
+* Methods and technology for converting older paper materials into
+electronic form
+* Study of the use of digital materials by scholars and others
+
+This summary is arranged thematically and does not follow the actual
+sequence of presentations.
+
+NOTES:
+ (1) In this document, the phrase electronic text is used to mean
+ any computerized reproduction or version of a document, book,
+ article, or manuscript (including images), and not merely a machine-
+ readable or machine-searchable text.
+
+ (2) The Workshop was held at the Library of Congress on 9-10 June
+ 1992, with funding from the David and Lucile Packard Foundation.
+ The document that follows represents a summary of the presentations
+ made at the Workshop and was compiled by James DALY. This
+ introduction was written by DALY and Carl FLEISCHHAUER.
+
+
+PRESERVATION AND IMAGING
+
+Preservation, as that term is used by archivists,(3) was most explicitly
+discussed in the context of imaging. Anne KENNEY and Lynne PERSONIUS
+explained how the concept of a faithful copy and the user-friendliness of
+the traditional book have guided their project at Cornell University.(4)
+Although interested in computerized dissemination, participants in the
+Cornell project are creating digital image sets of older books in the
+public domain as a source for a fresh paper facsimile or, in a future
+phase, microfilm. The books returned to the library shelves are
+high-quality and useful replacements on acid-free paper that should last
+a long time. To date, the Cornell project has placed little or no
+emphasis on creating searchable texts; one would not be surprised to find
+that the project participants view such texts as new editions, and thus
+not as faithful reproductions.
+
+In her talk on preservation, Patricia BATTIN struck an ecumenical and
+flexible note as she endorsed the creation and dissemination of a variety
+of types of digital copies. Do not be too narrow in defining what counts
+as a preservation element, BATTIN counseled; for the present, at least,
+digital copies made with preservation in mind cannot be as narrowly
+standardized as, say, microfilm copies with the same objective. Setting
+standards precipitously can inhibit creativity, but delay can result in
+chaos, she advised.
+
+In part, BATTIN's position reflected the unsettled nature of image-format
+standards, and attendees could hear echoes of this unsettledness in the
+comments of various speakers. For example, Jean BARONAS reviewed the
+status of several formal standards moving through committees of experts;
+and Clifford LYNCH encouraged the use of a new guideline for transmitting
+document images on Internet. Testimony from participants in the National
+Agricultural Library's (NAL) Text Digitization Program and LC's American
+Memory project highlighted some of the challenges to the actual creation
+or interchange of images, including difficulties in converting
+preservation microfilm to digital form. Donald WATERS reported on the
+progress of a master plan for a project at Yale University to convert
+books on microfilm to digital image sets, Project Open Book (POB).
+
+The Workshop offered rather less of an imaging practicum than planned,
+but "how-to" hints emerge at various points, for example, throughout
+KENNEY's presentation and in the discussion of arcana such as
+thresholding and dithering offered by George THOMA and FLEISCHHAUER.
+
+NOTES:
+ (3) Although there is a sense in which any reproductions of
+ historical materials preserve the human record, specialists in the
+ field have developed particular guidelines for the creation of
+ acceptable preservation copies.
+
+ (4) Titles and affiliations of presenters are given at the
+ beginning of their respective talks and in the Directory of
+ Participants (Appendix III).
+
+
+THE MACHINE-READABLE TEXT: MARKUP AND USE
+
+The sections of the Workshop that dealt with machine-readable text tended
+to be more concerned with access and use than with preservation, at least
+in the narrow technical sense. Michael SPERBERG-McQUEEN made a forceful
+presentation on the Text Encoding Initiative's (TEI) implementation of
+the Standard Generalized Markup Language (SGML). His ideas were echoed
+by Susan HOCKEY, Elli MYLONAS, and Stuart WEIBEL. While the
+presentations made by the TEI advocates contained no practicum, their
+discussion focused on the value of the finished product, what the
+European Community calls reusability, but what may also be termed
+durability. They argued that marking up--that is, coding--a text in a
+well-conceived way will permit it to be moved from one computer
+environment to another, as well as to be used by various users. Two
+kinds of markup were distinguished: 1) procedural markup, which
+describes the features of a text (e.g., dots on a page), and 2)
+descriptive markup, which describes the structure or elements of a
+document (e.g., chapters, paragraphs, and front matter).
+
+The TEI proponents emphasized the importance of texts to scholarship.
+They explained how heavily coded (and thus analyzed and annotated) texts
+can underlie research, play a role in scholarly communication, and
+facilitate classroom teaching. SPERBERG-McQUEEN reminded listeners that
+a written or printed item (e.g., a particular edition of a book) is
+merely a representation of the abstraction we call a text. To concern
+ourselves with faithfully reproducing a printed instance of the text,
+SPERBERG-McQUEEN argued, is to concern ourselves with the representation
+of a representation ("images as simulacra for the text"). The TEI proponents'
+interest in images tends to focus on corollary materials for use in teaching,
+for example, photographs of the Acropolis to accompany a Greek text.
+
+By the end of the Workshop, SPERBERG-McQUEEN confessed to having been
+converted to a limited extent to the view that electronic images
+constitute a promising alternative to microfilming; indeed, an
+alternative probably superior to microfilming. But he was not convinced
+that electronic images constitute a serious attempt to represent text in
+electronic form. HOCKEY and MYLONAS also conceded that their experience
+at the Pierce Symposium the previous week at Georgetown University and
+the present conference at the Library of Congress had compelled them to
+reevaluate their perspective on the usefulness of text as images.
+Attendees could see that the text and image advocates were in
+constructive tension, so to say.
+
+Three nonTEI presentations described approaches to preparing
+machine-readable text that are less rigorous and thus less expensive. In
+the case of the Papers of George Washington, Dorothy TWOHIG explained
+that the digital version will provide a not-quite-perfect rendering of
+the transcribed text--some 135,000 documents, available for research
+during the decades while the perfect or print version is completed.
+Members of the American Memory team and the staff of NAL's Text
+Digitization Program (see below) also outlined a middle ground concerning
+searchable texts. In the case of American Memory, contractors produce
+texts with about 99-percent accuracy that serve as "browse" or
+"reference" versions of written or printed originals. End users who need
+faithful copies or perfect renditions must refer to accompanying sets of
+digital facsimile images or consult copies of the originals in a nearby
+library or archive. American Memory staff argued that the high cost of
+producing 100-percent accurate copies would prevent LC from offering
+access to large parts of its collections.
+
+
+THE MACHINE-READABLE TEXT: METHODS OF CONVERSION
+
+Although the Workshop did not include a systematic examination of the
+methods for converting texts from paper (or from facsimile images) into
+machine-readable form, nevertheless, various speakers touched upon this
+matter. For example, WEIBEL reported that OCLC has experimented with a
+merging of multiple optical character recognition systems that will
+reduce errors from an unacceptable rate of 5 characters out of every
+l,000 to an unacceptable rate of 2 characters out of every l,000.
+
+Pamela ANDRE presented an overview of NAL's Text Digitization Program and
+Judith ZIDAR discussed the technical details. ZIDAR explained how NAL
+purchased hardware and software capable of performing optical character
+recognition (OCR) and text conversion and used its own staff to convert
+texts. The process, ZIDAR said, required extensive editing and project
+staff found themselves considering alternatives, including rekeying
+and/or creating abstracts or summaries of texts. NAL reckoned costs at
+$7 per page. By way of contrast, Ricky ERWAY explained that American
+Memory had decided from the start to contract out conversion to external
+service bureaus. The criteria used to select these contractors were cost
+and quality of results, as opposed to methods of conversion. ERWAY noted
+that historical documents or books often do not lend themselves to OCR.
+Bound materials represent a special problem. In her experience, quality
+control--inspecting incoming materials, counting errors in samples--posed
+the most time-consuming aspect of contracting out conversion. ERWAY
+reckoned American Memory's costs at $4 per page, but cautioned that fewer
+cost-elements had been included than in NAL's figure.
+
+
+OPTIONS FOR DISSEMINATION
+
+The topic of dissemination proper emerged at various points during the
+Workshop. At the session devoted to national and international computer
+networks, LYNCH, Howard BESSER, Ronald LARSEN, and Edwin BROWNRIGG
+highlighted the virtues of Internet today and of the network that will
+evolve from Internet. Listeners could discern in these narratives a
+vision of an information democracy in which millions of citizens freely
+find and use what they need. LYNCH noted that a lack of standards
+inhibits disseminating multimedia on the network, a topic also discussed
+by BESSER. LARSEN addressed the issues of network scalability and
+modularity and commented upon the difficulty of anticipating the effects
+of growth in orders of magnitude. BROWNRIGG talked about the ability of
+packet radio to provide certain links in a network without the need for
+wiring. However, the presenters also called attention to the
+shortcomings and incongruities of present-day computer networks. For
+example: 1) Network use is growing dramatically, but much network
+traffic consists of personal communication (E-mail). 2) Large bodies of
+information are available, but a user's ability to search across their
+entirety is limited. 3) There are significant resources for science and
+technology, but few network sources provide content in the humanities.
+4) Machine-readable texts are commonplace, but the capability of the
+system to deal with images (let alone other media formats) lags behind.
+A glimpse of a multimedia future for networks, however, was provided by
+Maria LEBRON in her overview of the Online Journal of Current Clinical
+Trials (OJCCT), and the process of scholarly publishing on-line.
+
+The contrasting form of the CD-ROM disk was never systematically
+analyzed, but attendees could glean an impression from several of the
+show-and-tell presentations. The Perseus and American Memory examples
+demonstrated recently published disks, while the descriptions of the
+IBYCUS version of the Papers of George Washington and Chadwyck-Healey's
+Patrologia Latina Database (PLD) told of disks to come. According to
+Eric CALALUCA, PLD's principal focus has been on converting Jacques-Paul
+Migne's definitive collection of Latin texts to machine-readable form.
+Although everyone could share the network advocates' enthusiasm for an
+on-line future, the possibility of rolling up one's sleeves for a session
+with a CD-ROM containing both textual materials and a powerful retrieval
+engine made the disk seem an appealing vessel indeed. The overall
+discussion suggested that the transition from CD-ROM to on-line networked
+access may prove far slower and more difficult than has been anticipated.
+
+
+WHO ARE THE USERS AND WHAT DO THEY DO?
+
+Although concerned with the technicalities of production, the Workshop
+never lost sight of the purposes and uses of electronic versions of
+textual materials. As noted above, those interested in imaging discussed
+the problematical matter of digital preservation, while the TEI proponents
+described how machine-readable texts can be used in research. This latter
+topic received thorough treatment in the paper read by Avra MICHELSON.
+She placed the phenomenon of electronic texts within the context of
+broader trends in information technology and scholarly communication.
+
+Among other things, MICHELSON described on-line conferences that
+represent a vigorous and important intellectual forum for certain
+disciplines. Internet now carries more than 700 conferences, with about
+80 percent of these devoted to topics in the social sciences and the
+humanities. Other scholars use on-line networks for "distance learning."
+Meanwhile, there has been a tremendous growth in end-user computing;
+professors today are less likely than their predecessors to ask the
+campus computer center to process their data. Electronic texts are one
+key to these sophisticated applications, MICHELSON reported, and more and
+more scholars in the humanities now work in an on-line environment.
+Toward the end of the Workshop, Michael LESK presented a corollary to
+MICHELSON's talk, reporting the results of an experiment that compared
+the work of one group of chemistry students using traditional printed
+texts and two groups using electronic sources. The experiment
+demonstrated that in the event one does not know what to read, one needs
+the electronic systems; the electronic systems hold no advantage at the
+moment if one knows what to read, but neither do they impose a penalty.
+
+DALY provided an anecdotal account of the revolutionizing impact of the
+new technology on his previous methods of research in the field of classics.
+His account, by extrapolation, served to illustrate in part the arguments
+made by MICHELSON concerning the positive effects of the sudden and radical
+transformation being wrought in the ways scholars work.
+
+Susan VECCIA and Joanne FREEMAN delineated the use of electronic
+materials outside the university. The most interesting aspect of their
+use, FREEMAN said, could be seen as a paradox: teachers in elementary
+and secondary schools requested access to primary source materials but,
+at the same time, found that "primariness" itself made these materials
+difficult for their students to use.
+
+
+OTHER TOPICS
+
+Marybeth PETERS reviewed copyright law in the United States and offered
+advice during a lively discussion of this subject. But uncertainty
+remains concerning the price of copyright in a digital medium, because a
+solution remains to be worked out concerning management and synthesis of
+copyrighted and out-of-copyright pieces of a database.
+
+As moderator of the final session of the Workshop, Prosser GIFFORD directed
+discussion to future courses of action and the potential role of LC in
+advancing them. Among the recommendations that emerged were the following:
+
+ * Workshop participants should 1) begin to think about working
+ with image material, but structure and digitize it in such a
+ way that at a later stage it can be interpreted into text, and
+ 2) find a common way to build text and images together so that
+ they can be used jointly at some stage in the future, with
+ appropriate network support, because that is how users will want
+ to access these materials. The Library might encourage attempts
+ to bring together people who are working on texts and images.
+
+ * A network version of American Memory should be developed or
+ consideration should be given to making the data in it
+ available to people interested in doing network multimedia.
+ Given the current dearth of digital data that is appealing and
+ unencumbered by extremely complex rights problems, developing a
+ network version of American Memory could do much to help make
+ network multimedia a reality.
+
+ * Concerning the thorny issue of electronic deposit, LC should
+ initiate a catalytic process in terms of distributed
+ responsibility, that is, bring together the distributed
+ organizations and set up a study group to look at all the
+ issues related to electronic deposit and see where we as a
+ nation should move. For example, LC might attempt to persuade
+ one major library in each state to deal with its state
+ equivalent publisher, which might produce a cooperative project
+ that would be equitably distributed around the country, and one
+ in which LC would be dealing with a minimal number of publishers
+ and minimal copyright problems. LC must also deal with the
+ concept of on-line publishing, determining, among other things,
+ how serials such as OJCCT might be deposited for copyright.
+
+ * Since a number of projects are planning to carry out
+ preservation by creating digital images that will end up in
+ on-line or near-line storage at some institution, LC might play
+ a helpful role, at least in the near term, by accelerating how
+ to catalog that information into the Research Library Information
+ Network (RLIN) and then into OCLC, so that it would be accessible.
+ This would reduce the possibility of multiple institutions digitizing
+ the same work.
+
+
+CONCLUSION
+
+The Workshop was valuable because it brought together partisans from
+various groups and provided an occasion to compare goals and methods.
+The more committed partisans frequently communicate with others in their
+groups, but less often across group boundaries. The Workshop was also
+valuable to attendees--including those involved with American Memory--who
+came less committed to particular approaches or concepts. These
+attendees learned a great deal, and plan to select and employ elements of
+imaging, text-coding, and networked distribution that suit their
+respective projects and purposes.
+
+Still, reality rears its ugly head: no breakthrough has been achieved.
+On the imaging side, one confronts a proliferation of competing
+data-interchange standards and a lack of consensus on the role of digital
+facsimiles in preservation. In the realm of machine-readable texts, one
+encounters a reasonably mature standard but methodological difficulties
+and high costs. These latter problems, of course, represent a special
+impediment to the desire, as it is sometimes expressed in the popular
+press, "to put the [contents of the] Library of Congress on line." In
+the words of one participant, there was "no solution to the economic
+problems--the projects that are out there are surviving, but it is going
+to be a lot of work to transform the information industry, and so far the
+investment to do that is not forthcoming" (LESK, per litteras).
+
+
+ *** *** *** ****** *** *** ***
+
+
+ PROCEEDINGS
+
+
+WELCOME
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+GIFFORD * Origin of Workshop in current Librarian's desire to make LC's
+collections more widely available * Desiderata arising from the prospect
+of greater interconnectedness *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+After welcoming participants on behalf of the Library of Congress,
+American Memory (AM), and the National Demonstration Lab, Prosser
+GIFFORD, director for scholarly programs, Library of Congress, located
+the origin of the Workshop on Electronic Texts in a conversation he had
+had considerably more than a year ago with Carl FLEISCHHAUER concerning
+some of the issues faced by AM. On the assumption that numerous other
+people were asking the same questions, the decision was made to bring
+together as many of these people as possible to ask the same questions
+together. In a deeper sense, GIFFORD said, the origin of the Workshop
+lay in the desire of the current Librarian of Congress, James H.
+Billington, to make the collections of the Library, especially those
+offering unique or unusual testimony on aspects of the American
+experience, available to a much wider circle of users than those few
+people who can come to Washington to use them. This meant that the
+emphasis of AM, from the outset, has been on archival collections of the
+basic material, and on making these collections themselves available,
+rather than selected or heavily edited products.
+
+From AM's emphasis followed the questions with which the Workshop began:
+who will use these materials, and in what form will they wish to use
+them. But an even larger issue deserving mention, in GIFFORD's view, was
+the phenomenal growth in Internet connectivity. He expressed the hope
+that the prospect of greater interconnectedness than ever before would
+lead to: 1) much more cooperative and mutually supportive endeavors; 2)
+development of systems of shared and distributed responsibilities to
+avoid duplication and to ensure accuracy and preservation of unique
+materials; and 3) agreement on the necessary standards and development of
+the appropriate directories and indices to make navigation
+straightforward among the varied resources that are, and increasingly
+will be, available. In this connection, GIFFORD requested that
+participants reflect from the outset upon the sorts of outcomes they
+thought the Workshop might have. Did those present constitute a group
+with sufficient common interests to propose a next step or next steps,
+and if so, what might those be? They would return to these questions the
+following afternoon.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+FLEISCHHAUER * Core of Workshop concerns preparation and production of
+materials * Special challenge in conversion of textual materials *
+Quality versus quantity * Do the several groups represented share common
+interests? *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Carl FLEISCHHAUER, coordinator, American Memory, Library of Congress,
+emphasized that he would attempt to represent the people who perform some
+of the work of converting or preparing materials and that the core of
+the Workshop had to do with preparation and production. FLEISCHHAUER
+then drew a distinction between the long term, when many things would be
+available and connected in the ways that GIFFORD described, and the short
+term, in which AM not only has wrestled with the issue of what is the
+best course to pursue but also has faced a variety of technical
+challenges.
+
+FLEISCHHAUER remarked AM's endeavors to deal with a wide range of library
+formats, such as motion picture collections, sound-recording collections,
+and pictorial collections of various sorts, especially collections of
+photographs. In the course of these efforts, AM kept coming back to
+textual materials--manuscripts or rare printed matter, bound materials,
+etc. Text posed the greatest conversion challenge of all. Thus, the
+genesis of the Workshop, which reflects the problems faced by AM. These
+problems include physical problems. For example, those in the library
+and archive business deal with collections made up of fragile and rare
+manuscript items, bound materials, especially the notoriously brittle
+bound materials of the late nineteenth century. These are precious
+cultural artifacts, however, as well as interesting sources of
+information, and LC desires to retain and conserve them. AM needs to
+handle things without damaging them. Guillotining a book to run it
+through a sheet feeder must be avoided at all costs.
+
+Beyond physical problems, issues pertaining to quality arose. For
+example, the desire to provide users with a searchable text is affected
+by the question of acceptable level of accuracy. One hundred percent
+accuracy is tremendously expensive. On the other hand, the output of
+optical character recognition (OCR) can be tremendously inaccurate.
+Although AM has attempted to find a middle ground, uncertainty persists
+as to whether or not it has discovered the right solution.
+
+Questions of quality arose concerning images as well. FLEISCHHAUER
+contrasted the extremely high level of quality of the digital images in
+the Cornell Xerox Project with AM's efforts to provide a browse-quality
+or access-quality image, as opposed to an archival or preservation image.
+FLEISCHHAUER therefore welcomed the opportunity to compare notes.
+
+FLEISCHHAUER observed in passing that conversations he had had about
+networks have begun to signal that for various forms of media a
+determination may be made that there is a browse-quality item, or a
+distribution-and-access-quality item that may coexist in some systems
+with a higher quality archival item that would be inconvenient to send
+through the network because of its size. FLEISCHHAUER referred, of
+course, to images more than to searchable text.
+
+As AM considered those questions, several conceptual issues arose: ought
+AM occasionally to reproduce materials entirely through an image set, at
+other times, entirely through a text set, and in some cases, a mix?
+There probably would be times when the historical authenticity of an
+artifact would require that its image be used. An image might be
+desirable as a recourse for users if one could not provide 100-percent
+accurate text. Again, AM wondered, as a practical matter, if a
+distinction could be drawn between rare printed matter that might exist
+in multiple collections--that is, in ten or fifteen libraries. In such
+cases, the need for perfect reproduction would be less than for unique
+items. Implicit in his remarks, FLEISCHHAUER conceded, was the admission
+that AM has been tilting strongly towards quantity and drawing back a
+little from perfect quality. That is, it seemed to AM that society would
+be better served if more things were distributed by LC--even if they were
+not quite perfect--than if fewer things, perfectly represented, were
+distributed. This was stated as a proposition to be tested, with
+responses to be gathered from users.
+
+In thinking about issues related to reproduction of materials and seeing
+other people engaged in parallel activities, AM deemed it useful to
+convene a conference. Hence, the Workshop. FLEISCHHAUER thereupon
+surveyed the several groups represented: 1) the world of images (image
+users and image makers); 2) the world of text and scholarship and, within
+this group, those concerned with language--FLEISCHHAUER confessed to finding
+delightful irony in the fact that some of the most advanced thinkers on
+computerized texts are those dealing with ancient Greek and Roman materials;
+3) the network world; and 4) the general world of library science, which
+includes people interested in preservation and cataloging.
+
+FLEISCHHAUER concluded his remarks with special thanks to the David and
+Lucile Packard Foundation for its support of the meeting, the American
+Memory group, the Office for Scholarly Programs, the National
+Demonstration Lab, and the Office of Special Events. He expressed the
+hope that David Woodley Packard might be able to attend, noting that
+Packard's work and the work of the foundation had sponsored a number of
+projects in the text area.
+
+ ******
+
+SESSION I. CONTENT IN A NEW FORM: WHO WILL USE IT AND WHAT WILL THEY DO?
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DALY * Acknowledgements * A new Latin authors disk * Effects of the new
+technology on previous methods of research *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Serving as moderator, James DALY acknowledged the generosity of all the
+presenters for giving of their time, counsel, and patience in planning
+the Workshop, as well as of members of the American Memory project and
+other Library of Congress staff, and the David and Lucile Packard
+Foundation and its executive director, Colburn S. Wilbur.
+
+DALY then recounted his visit in March to the Center for Electronic Texts
+in the Humanities (CETH) and the Department of Classics at Rutgers
+University, where an old friend, Lowell Edmunds, introduced him to the
+department's IBYCUS scholarly personal computer, and, in particular, the
+new Latin CD-ROM, containing, among other things, almost all classical
+Latin literary texts through A.D. 200. Packard Humanities Institute
+(PHI), Los Altos, California, released this disk late in 1991, with a
+nominal triennial licensing fee.
+
+Playing with the disk for an hour or so at Rutgers brought home to DALY
+at once the revolutionizing impact of the new technology on his previous
+methods of research. Had this disk been available two or three years
+earlier, DALY contended, when he was engaged in preparing a commentary on
+Book 10 of Virgil's Aeneid for Cambridge University Press, he would not
+have required a forty-eight-square-foot table on which to spread the
+numerous, most frequently consulted items, including some ten or twelve
+concordances to key Latin authors, an almost equal number of lexica to
+authors who lacked concordances, and where either lexica or concordances
+were lacking, numerous editions of authors antedating and postdating Virgil.
+
+Nor, when checking each of the average six to seven words contained in
+the Virgilian hexameter for its usage elsewhere in Virgil's works or
+other Latin authors, would DALY have had to maintain the laborious
+mechanical process of flipping through these concordances, lexica, and
+editions each time. Nor would he have had to frequent as often the
+Milton S. Eisenhower Library at the Johns Hopkins University to consult
+the Thesaurus Linguae Latinae. Instead of devoting countless hours, or
+the bulk of his research time, to gathering data concerning Virgil's use
+of words, DALY--now freed by PHI's Latin authors disk from the
+tyrannical, yet in some ways paradoxically happy scholarly drudgery--
+would have been able to devote that same bulk of time to analyzing and
+interpreting Virgilian verbal usage.
+
+Citing Theodore Brunner, Gregory Crane, Elli MYLONAS, and Avra MICHELSON,
+DALY argued that this reversal in his style of work, made possible by the
+new technology, would perhaps have resulted in better, more productive
+research. Indeed, even in the course of his browsing the Latin authors
+disk at Rutgers, its powerful search, retrieval, and highlighting
+capabilities suggested to him several new avenues of research into
+Virgil's use of sound effects. This anecdotal account, DALY maintained,
+may serve to illustrate in part the sudden and radical transformation
+being wrought in the ways scholars work.
+
+ ******
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+MICHELSON * Elements related to scholarship and technology * Electronic
+texts within the context of broader trends within information technology
+and scholarly communication * Evaluation of the prospects for the use of
+electronic texts * Relationship of electronic texts to processes of
+scholarly communication in humanities research * New exchange formats
+created by scholars * Projects initiated to increase scholarly access to
+converted text * Trend toward making electronic resources available
+through research and education networks * Changes taking place in
+scholarly communication among humanities scholars * Network-mediated
+scholarship transforming traditional scholarly practices * Key
+information technology trends affecting the conduct of scholarly
+communication over the next decade * The trend toward end-user computing
+* The trend toward greater connectivity * Effects of these trends * Key
+transformations taking place * Summary of principal arguments *
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Avra MICHELSON, Archival Research and Evaluation Staff, National Archives
+and Records Administration (NARA), argued that establishing who will use
+electronic texts and what they will use them for involves a consideration
+of both information technology and scholarship trends. This
+consideration includes several elements related to scholarship and
+technology: 1) the key trends in information technology that are most
+relevant to scholarship; 2) the key trends in the use of currently
+available technology by scholars in the nonscientific community; and 3)
+the relationship between these two very distinct but interrelated trends.
+The investment in understanding this relationship being made by
+information providers, technologists, and public policy developers, as
+well as by scholars themselves, seems to be pervasive and growing,
+MICHELSON contended. She drew on collaborative work with Jeff Rothenberg
+on the scholarly use of technology.
+
+MICHELSON sought to place the phenomenon of electronic texts within the
+context of broader trends within information technology and scholarly
+communication. She argued that electronic texts are of most use to
+researchers to the extent that the researchers' working context (i.e.,
+their relevant bibliographic sources, collegial feedback, analytic tools,
+notes, drafts, etc.), along with their field's primary and secondary
+sources, also is accessible in electronic form and can be integrated in
+ways that are unique to the on-line environment.
+
+Evaluation of the prospects for the use of electronic texts includes two
+elements: 1) an examination of the ways in which researchers currently
+are using electronic texts along with other electronic resources, and 2)
+an analysis of key information technology trends that are affecting the
+long-term conduct of scholarly communication. MICHELSON limited her
+discussion of the use of electronic texts to the practices of humanists
+and noted that the scientific community was outside the panel's overview.
+
+MICHELSON examined the nature of the current relationship of electronic
+texts in particular, and electronic resources in general, to what she
+maintained were, essentially, five processes of scholarly communication
+in humanities research. Researchers 1) identify sources, 2) communicate
+with their colleagues, 3) interpret and analyze data, 4) disseminate
+their research findings, and 5) prepare curricula to instruct the next
+generation of scholars and students. This examination would produce a
+clearer understanding of the synergy among these five processes that
+fuels the tendency of the use of electronic resources for one process to
+stimulate its use for other processes of scholarly communication.
+
+For the first process of scholarly communication, the identification of
+sources, MICHELSON remarked the opportunity scholars now enjoy to
+supplement traditional word-of-mouth searches for sources among their
+colleagues with new forms of electronic searching. So, for example,
+instead of having to visit the library, researchers are able to explore
+descriptions of holdings in their offices. Furthermore, if their own
+institutions' holdings prove insufficient, scholars can access more than
+200 major American library catalogues over Internet, including the
+universities of California, Michigan, Pennsylvania, and Wisconsin.
+Direct access to the bibliographic databases offers intellectual
+empowerment to scholars by presenting a comprehensive means of browsing
+through libraries from their homes and offices at their convenience.
+
+The second process of communication involves communication among
+scholars. Beyond the most common methods of communication, scholars are
+using E-mail and a variety of new electronic communications formats
+derived from it for further academic interchange. E-mail exchanges are
+growing at an astonishing rate, reportedly 15 percent a month. They
+currently constitute approximately half the traffic on research and
+education networks. Moreover, the global spread of E-mail has been so
+rapid that it is now possible for American scholars to use it to
+communicate with colleagues in close to 140 other countries.
+
+Other new exchange formats created by scholars and operating on Internet
+include more than 700 conferences, with about 80 percent of these devoted
+to topics in the social sciences and humanities. The rate of growth of
+these scholarly electronic conferences also is astonishing. From l990 to
+l991, 200 new conferences were identified on Internet. From October 1991
+to June 1992, an additional 150 conferences in the social sciences and
+humanities were added to this directory of listings. Scholars have
+established conferences in virtually every field, within every different
+discipline. For example, there are currently close to 600 active social
+science and humanities conferences on topics such as art and
+architecture, ethnomusicology, folklore, Japanese culture, medical
+education, and gifted and talented education. The appeal to scholars of
+communicating through these conferences is that, unlike any other medium,
+electronic conferences today provide a forum for global communication
+with peers at the front end of the research process.
+
+Interpretation and analysis of sources constitutes the third process of
+scholarly communication that MICHELSON discussed in terms of texts and
+textual resources. The methods used to analyze sources fall somewhere on
+a continuum from quantitative analysis to qualitative analysis.
+Typically, evidence is culled and evaluated using methods drawn from both
+ends of this continuum. At one end, quantitative analysis involves the
+use of mathematical processes such as a count of frequencies and
+distributions of occurrences or, on a higher level, regression analysis.
+At the other end of the continuum, qualitative analysis typically
+involves nonmathematical processes oriented toward language
+interpretation or the building of theory. Aspects of this work involve
+the processing--either manual or computational--of large and sometimes
+massive amounts of textual sources, although the use of nontextual
+sources as evidence, such as photographs, sound recordings, film footage,
+and artifacts, is significant as well.
+
+Scholars have discovered that many of the methods of interpretation and
+analysis that are related to both quantitative and qualitative methods
+are processes that can be performed by computers. For example, computers
+can count. They can count brush strokes used in a Rembrandt painting or
+perform regression analysis for understanding cause and effect. By means
+of advanced technologies, computers can recognize patterns, analyze text,
+and model concepts. Furthermore, computers can complete these processes
+faster with more sources and with greater precision than scholars who
+must rely on manual interpretation of data. But if scholars are to use
+computers for these processes, source materials must be in a form
+amenable to computer-assisted analysis. For this reason many scholars,
+once they have identified the sources that are key to their research, are
+converting them to machine-readable form. Thus, a representative example
+of the numerous textual conversion projects organized by scholars around
+the world in recent years to support computational text analysis is the
+TLG, the Thesaurus Linguae Graecae. This project is devoted to
+converting the extant ancient texts of classical Greece. (Editor's note:
+according to the TLG Newsletter of May l992, TLG was in use in thirty-two
+different countries. This figure updates MICHELSON's previous count by one.)
+
+The scholars performing these conversions have been asked to recognize
+that the electronic sources they are converting for one use possess value
+for other research purposes as well. As a result, during the past few
+years, humanities scholars have initiated a number of projects to
+increase scholarly access to converted text. So, for example, the Text
+Encoding Initiative (TEI), about which more is said later in the program,
+was established as an effort by scholars to determine standard elements
+and methods for encoding machine-readable text for electronic exchange.
+In a second effort to facilitate the sharing of converted text, scholars
+have created a new institution, the Center for Electronic Texts in the
+Humanities (CETH). The center estimates that there are 8,000 series of
+source texts in the humanities that have been converted to
+machine-readable form worldwide. CETH is undertaking an international
+search for converted text in the humanities, compiling it into an
+electronic library, and preparing bibliographic descriptions of the
+sources for the Research Libraries Information Network's (RLIN)
+machine-readable data file. The library profession has begun to initiate
+large conversion projects as well, such as American Memory.
+
+While scholars have been making converted text available to one another,
+typically on disk or on CD-ROM, the clear trend is toward making these
+resources available through research and education networks. Thus, the
+American and French Research on the Treasury of the French Language
+(ARTFL) and the Dante Project are already available on Internet.
+MICHELSON summarized this section on interpretation and analysis by
+noting that: 1) increasing numbers of humanities scholars in the library
+community are recognizing the importance to the advancement of
+scholarship of retrospective conversion of source materials in the arts
+and humanities; and 2) there is a growing realization that making the
+sources available on research and education networks maximizes their
+usefulness for the analysis performed by humanities scholars.
+
+The fourth process of scholarly communication is dissemination of
+research findings, that is, publication. Scholars are using existing
+research and education networks to engineer a new type of publication:
+scholarly-controlled journals that are electronically produced and
+disseminated. Although such journals are still emerging as a
+communication format, their number has grown, from approximately twelve
+to thirty-six during the past year (July 1991 to June 1992). Most of
+these electronic scholarly journals are devoted to topics in the
+humanities. As with network conferences, scholarly enthusiasm for these
+electronic journals stems from the medium's unique ability to advance
+scholarship in a way that no other medium can do by supporting global
+feedback and interchange, practically in real time, early in the research
+process. Beyond scholarly journals, MICHELSON remarked the delivery of
+commercial full-text products, such as articles in professional journals,
+newsletters, magazines, wire services, and reference sources. These are
+being delivered via on-line local library catalogues, especially through
+CD-ROMs. Furthermore, according to MICHELSON, there is general optimism
+that the copyright and fees issues impeding the delivery of full text on
+existing research and education networks soon will be resolved.
+
+The final process of scholarly communication is curriculum development
+and instruction, and this involves the use of computer information
+technologies in two areas. The first is the development of
+computer-oriented instructional tools, which includes simulations,
+multimedia applications, and computer tools that are used to assist in
+the analysis of sources in the classroom, etc. The Perseus Project, a
+database that provides a multimedia curriculum on classical Greek
+civilization, is a good example of the way in which entire curricula are
+being recast using information technologies. It is anticipated that the
+current difficulty in exchanging electronically computer-based
+instructional software, which in turn makes it difficult for one scholar
+to build upon the work of others, will be resolved before too long.
+Stand-alone curricular applications that involve electronic text will be
+sharable through networks, reinforcing their significance as intellectual
+products as well as instructional tools.
+
+The second aspect of electronic learning involves the use of research and
+education networks for distance education programs. Such programs
+interactively link teachers with students in geographically scattered
+locations and rely on the availability of electronic instructional
+resources. Distance education programs are gaining wide appeal among
+state departments of education because of their demonstrated capacity to
+bring advanced specialized course work and an array of experts to many
+classrooms. A recent report found that at least 32 states operated at
+least one statewide network for education in 1991, with networks under
+development in many of the remaining states.
+
+MICHELSON summarized this section by noting two striking changes taking
+place in scholarly communication among humanities scholars. First is the
+extent to which electronic text in particular, and electronic resources
+in general, are being infused into each of the five processes described
+above. As mentioned earlier, there is a certain synergy at work here.
+The use of electronic resources for one process tends to stimulate its
+use for other processes, because the chief course of movement is toward a
+comprehensive on-line working context for humanities scholars that
+includes on-line availability of key bibliographies, scholarly feedback,
+sources, analytical tools, and publications. MICHELSON noted further
+that the movement toward a comprehensive on-line working context for
+humanities scholars is not new. In fact, it has been underway for more
+than forty years in the humanities, since Father Roberto Busa began
+developing an electronic concordance of the works of Saint Thomas Aquinas
+in 1949. What we are witnessing today, MICHELSON contended, is not the
+beginning of this on-line transition but, for at least some humanities
+scholars, the turning point in the transition from a print to an
+electronic working context. Coinciding with the on-line transition, the
+second striking change is the extent to which research and education
+networks are becoming the new medium of scholarly communication. The
+existing Internet and the pending National Education and Research Network
+(NREN) represent the new meeting ground where scholars are going for
+bibliographic information, scholarly dialogue and feedback, the most
+current publications in their field, and high-level educational
+offerings. Traditional scholarly practices are undergoing tremendous
+transformations as a result of the emergence and growing prominence of
+what is called network-mediated scholarship.
+
+MICHELSON next turned to the second element of the framework she proposed
+at the outset of her talk for evaluating the prospects for electronic
+text, namely the key information technology trends affecting the conduct
+of scholarly communication over the next decade: 1) end-user computing
+and 2) connectivity.
+
+End-user computing means that the person touching the keyboard, or
+performing computations, is the same as the person who initiates or
+consumes the computation. The emergence of personal computers, along
+with a host of other forces, such as ubiquitous computing, advances in
+interface design, and the on-line transition, is prompting the consumers
+of computation to do their own computing, and is thus rendering obsolete
+the traditional distinction between end users and ultimate users.
+
+The trend toward end-user computing is significant to consideration of
+the prospects for electronic texts because it means that researchers are
+becoming more adept at doing their own computations and, thus, more
+competent in the use of electronic media. By avoiding programmer
+intermediaries, computation is becoming central to the researcher's
+thought process. This direct involvement in computing is changing the
+researcher's perspective on the nature of research itself, that is, the
+kinds of questions that can be posed, the analytical methodologies that
+can be used, the types and amount of sources that are appropriate for
+analyses, and the form in which findings are presented. The trend toward
+end-user computing means that, increasingly, electronic media and
+computation are being infused into all processes of humanities
+scholarship, inspiring remarkable transformations in scholarly
+communication.
+
+The trend toward greater connectivity suggests that researchers are using
+computation increasingly in network environments. Connectivity is
+important to scholarship because it erases the distance that separates
+students from teachers and scholars from their colleagues, while allowing
+users to access remote databases, share information in many different
+media, connect to their working context wherever they are, and
+collaborate in all phases of research.
+
+The combination of the trend toward end-user computing and the trend
+toward connectivity suggests that the scholarly use of electronic
+resources, already evident among some researchers, will soon become an
+established feature of scholarship. The effects of these trends, along
+with ongoing changes in scholarly practices, point to a future in which
+humanities researchers will use computation and electronic communication
+to help them formulate ideas, access sources, perform research,
+collaborate with colleagues, seek peer review, publish and disseminate
+results, and engage in many other professional and educational activities.
+
+In summary, MICHELSON emphasized four points: 1) A portion of humanities
+scholars already consider electronic texts the preferred format for
+analysis and dissemination. 2) Scholars are using these electronic
+texts, in conjunction with other electronic resources, in all the
+processes of scholarly communication. 3) The humanities scholars'
+working context is in the process of changing from print technology to
+electronic technology, in many ways mirroring transformations that have
+occurred or are occurring within the scientific community. 4) These
+changes are occurring in conjunction with the development of a new
+communication medium: research and education networks that are
+characterized by their capacity to advance scholarship in a wholly unique
+way.
+
+MICHELSON also reiterated her three principal arguments: l) Electronic
+texts are best understood in terms of the relationship to other
+electronic resources and the growing prominence of network-mediated
+scholarship. 2) The prospects for electronic texts lie in their capacity
+to be integrated into the on-line network of electronic resources that
+comprise the new working context for scholars. 3) Retrospective conversion
+of portions of the scholarly record should be a key strategy as information
+providers respond to changes in scholarly communication practices.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+VECCIA * AM's evaluation project and public users of electronic resources
+* AM and its design * Site selection and evaluating the Macintosh
+implementation of AM * Characteristics of the six public libraries
+selected * Characteristics of AM's users in these libraries * Principal
+ways AM is being used *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Susan VECCIA, team leader, and Joanne FREEMAN, associate coordinator,
+American Memory, Library of Congress, gave a joint presentation. First,
+by way of introduction, VECCIA explained her and FREEMAN's roles in
+American Memory (AM). Serving principally as an observer, VECCIA has
+assisted with the evaluation project of AM, placing AM collections in a
+variety of different sites around the country and helping to organize and
+implement that project. FREEMAN has been an associate coordinator of AM
+and has been involved principally with the interpretative materials,
+preparing some of the electronic exhibits and printed historical
+information that accompanies AM and that is requested by users. VECCIA
+and FREEMAN shared anecdotal observations concerning AM with public users
+of electronic resources. Notwithstanding a fairly structured evaluation
+in progress, both VECCIA and FREEMAN chose not to report on specifics in
+terms of numbers, etc., because they felt it was too early in the
+evaluation project to do so.
+
+AM is an electronic archive of primary source materials from the Library
+of Congress, selected collections representing a variety of formats--
+photographs, graphic arts, recorded sound, motion pictures, broadsides,
+and soon, pamphlets and books. In terms of the design of this system,
+the interpretative exhibits have been kept separate from the primary
+resources, with good reason. Accompanying this collection are printed
+documentation and user guides, as well as guides that FREEMAN prepared for
+teachers so that they may begin using the content of the system at once.
+
+VECCIA described the evaluation project before talking about the public
+users of AM, limiting her remarks to public libraries, because FREEMAN
+would talk more specifically about schools from kindergarten to twelfth
+grade (K-12). Having started in spring 1991, the evaluation currently
+involves testing of the Macintosh implementation of AM. Since the
+primary goal of this evaluation is to determine the most appropriate
+audience or audiences for AM, very different sites were selected. This
+makes evaluation difficult because of the varying degrees of technology
+literacy among the sites. AM is situated in forty-four locations, of
+which six are public libraries and sixteen are schools. Represented
+among the schools are elementary, junior high, and high schools.
+District offices also are involved in the evaluation, which will
+conclude in summer 1993.
+
+VECCIA focused the remainder of her talk on the six public libraries, one
+of which doubles as a state library. They represent a range of
+geographic areas and a range of demographic characteristics. For
+example, three are located in urban settings, two in rural settings, and
+one in a suburban setting. A range of technical expertise is to be found
+among these facilities as well. For example, one is an "Apple library of
+the future," while two others are rural one-room libraries--in one, AM
+sits at the front desk next to a tractor manual.
+
+All public libraries have been extremely enthusiastic, supportive, and
+appreciative of the work that AM has been doing. VECCIA characterized
+various users: Most users in public libraries describe themselves as
+general readers; of the students who use AM in the public libraries,
+those in fourth grade and above seem most interested. Public libraries
+in rural sites tend to attract retired people, who have been highly
+receptive to AM. Users tend to fall into two additional categories:
+people interested in the content and historical connotations of these
+primary resources, and those fascinated by the technology. The format
+receiving the most comments has been motion pictures. The adult users in
+public libraries are more comfortable with IBM computers, whereas young
+people seem comfortable with either IBM or Macintosh, although most of
+them seem to come from a Macintosh background. This same tendency is
+found in the schools.
+
+What kinds of things do users do with AM? In a public library there are
+two main goals or ways that AM is being used: as an individual learning
+tool, and as a leisure activity. Adult learning was one area that VECCIA
+would highlight as a possible application for a tool such as AM. She
+described a patron of a rural public library who comes in every day on
+his lunch hour and literally reads AM, methodically going through the
+collection image by image. At the end of his hour he makes an electronic
+bookmark, puts it in his pocket, and returns to work. The next day he
+comes in and resumes where he left off. Interestingly, this man had
+never been in the library before he used AM. In another small, rural
+library, the coordinator reports that AM is a popular activity for some
+of the older, retired people in the community, who ordinarily would not
+use "those things,"--computers. Another example of adult learning in
+public libraries is book groups, one of which, in particular, is using AM
+as part of its reading on industrialization, integration, and urbanization
+in the early 1900s.
+
+One library reports that a family is using AM to help educate their
+children. In another instance, individuals from a local museum came in
+to use AM to prepare an exhibit on toys of the past. These two examples
+emphasize the mission of the public library as a cultural institution,
+reaching out to people who do not have the same resources available to
+those who live in a metropolitan area or have access to a major library.
+One rural library reports that junior high school students in large
+numbers came in one afternoon to use AM for entertainment. A number of
+public libraries reported great interest among postcard collectors in the
+Detroit collection, which was essentially a collection of images used on
+postcards around the turn of the century. Train buffs are similarly
+interested because that was a time of great interest in railroading.
+People, it was found, relate to things that they know of firsthand. For
+example, in both rural public libraries where AM was made available,
+observers reported that the older people with personal remembrances of
+the turn of the century were gravitating to the Detroit collection.
+These examples served to underscore MICHELSON's observation re the
+integration of electronic tools and ideas--that people learn best when
+the material relates to something they know.
+
+VECCIA made the final point that in many cases AM serves as a
+public-relations tool for the public libraries that are testing it. In
+one case, AM is being used as a vehicle to secure additional funding for
+the library. In another case, AM has served as an inspiration to the
+staff of a major local public library in the South to think about ways to
+make its own collection of photographs more accessible to the public.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+FREEMAN * AM and archival electronic resources in a school environment *
+Questions concerning context * Questions concerning the electronic format
+itself * Computer anxiety * Access and availability of the system *
+Hardware * Strengths gained through the use of archival resources in
+schools *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Reiterating an observation made by VECCIA, that AM is an archival
+resource made up of primary materials with very little interpretation,
+FREEMAN stated that the project has attempted to bridge the gap between
+these bare primary materials and a school environment, and in that cause
+has created guided introductions to AM collections. Loud demand from the
+educational community, chiefly from teachers working with the upper
+grades of elementary school through high school, greeted the announcement
+that AM would be tested around the country.
+
+FREEMAN reported not only on what was learned about AM in a school
+environment, but also on several universal questions that were raised
+concerning archival electronic resources in schools. She discussed
+several strengths of this type of material in a school environment as
+opposed to a highly structured resource that offers a limited number of
+paths to follow.
+
+FREEMAN first raised several questions about using AM in a school
+environment. There is often some difficulty in developing a sense of
+what the system contains. Many students sit down at a computer resource
+and assume that, because AM comes from the Library of Congress, all of
+American history is now at their fingertips. As a result of that sort of
+mistaken judgment, some students are known to conclude that AM contains
+nothing of use to them when they look for one or two things and do not
+find them. It is difficult to discover that middle ground where one has
+a sense of what the system contains. Some students grope toward the idea
+of an archive, a new idea to them, since they have not previously
+experienced what it means to have access to a vast body of somewhat
+random information.
+
+Other questions raised by FREEMAN concerned the electronic format itself.
+For instance, in a school environment it is often difficult both for
+teachers and students to gain a sense of what it is they are viewing.
+They understand that it is a visual image, but they do not necessarily
+know that it is a postcard from the turn of the century, a panoramic
+photograph, or even machine-readable text of an eighteenth-century
+broadside, a twentieth-century printed book, or a nineteenth-century
+diary. That distinction is often difficult for people in a school
+environment to grasp. Because of that, it occasionally becomes difficult
+to draw conclusions from what one is viewing.
+
+FREEMAN also noted the obvious fear of the computer, which constitutes a
+difficulty in using an electronic resource. Though students in general
+did not suffer from this anxiety, several older students feared that they
+were computer-illiterate, an assumption that became self-fulfilling when
+they searched for something but failed to find it. FREEMAN said she
+believed that some teachers also fear computer resources, because they
+believe they lack complete control. FREEMAN related the example of
+teachers shooing away students because it was not their time to use the
+system. This was a case in which the situation had to be extremely
+structured so that the teachers would not feel that they had lost their
+grasp on what the system contained.
+
+A final question raised by FREEMAN concerned access and availability of
+the system. She noted the occasional existence of a gap in communication
+between school librarians and teachers. Often AM sits in a school
+library and the librarian is the person responsible for monitoring the
+system. Teachers do not always take into their world new library
+resources about which the librarian is excited. Indeed, at the sites
+where AM had been used most effectively within a library, the librarian
+was required to go to specific teachers and instruct them in its use. As
+a result, several AM sites will have in-service sessions over a summer,
+in the hope that perhaps, with a more individualized link, teachers will
+be more likely to use the resource.
+
+A related issue in the school context concerned the number of
+workstations available at any one location. Centralization of equipment
+at the district level, with teachers invited to download things and walk
+away with them, proved unsuccessful because the hours these offices were
+open were also school hours.
+
+Another issue was hardware. As VECCIA observed, a range of sites exists,
+some technologically advanced and others essentially acquiring their
+first computer for the primary purpose of using it in conjunction with
+AM's testing. Users at technologically sophisticated sites want even
+more sophisticated hardware, so that they can perform even more
+sophisticated tasks with the materials in AM. But once they acquire a
+newer piece of hardware, they must learn how to use that also; at an
+unsophisticated site it takes an extremely long time simply to become
+accustomed to the computer, not to mention the program offered with the
+computer. All of these small issues raise one large question, namely,
+are systems like AM truly rewarding in a school environment, or do they
+simply act as innovative toys that do little more than spark interest?
+
+FREEMAN contended that the evaluation project has revealed several strengths
+that were gained through the use of archival resources in schools, including:
+
+ * Psychic rewards from using AM as a vast, rich database, with
+ teachers assigning various projects to students--oral presentations,
+ written reports, a documentary, a turn-of-the-century newspaper--
+ projects that start with the materials in AM but are completed using
+ other resources; AM thus is used as a research tool in conjunction
+ with other electronic resources, as well as with books and items in
+ the library where the system is set up.
+
+ * Students are acquiring computer literacy in a humanities context.
+
+ * This sort of system is overcoming the isolation between disciplines
+ that often exists in schools. For example, many English teachers are
+ requiring their students to write papers on historical topics
+ represented in AM. Numerous teachers have reported that their
+ students are learning critical thinking skills using the system.
+
+ * On a broader level, AM is introducing primary materials, not only
+ to students but also to teachers, in an environment where often
+ simply none exist--an exciting thing for the students because it
+ helps them learn to conduct research, to interpret, and to draw
+ their own conclusions. In learning to conduct research and what it
+ means, students are motivated to seek knowledge. That relates to
+ another positive outcome--a high level of personal involvement of
+ students with the materials in this system and greater motivation to
+ conduct their own research and draw their own conclusions.
+
+ * Perhaps the most ironic strength of these kinds of archival
+ electronic resources is that many of the teachers AM interviewed
+ were desperate, it is no exaggeration to say, not only for primary
+ materials but for unstructured primary materials. These would, they
+ thought, foster personally motivated research, exploration, and
+ excitement in their students. Indeed, these materials have done
+ just that. Ironically, however, this lack of structure produces
+ some of the confusion to which the newness of these kinds of
+ resources may also contribute. The key to effective use of archival
+ products in a school environment is a clear, effective introduction
+ to the system and to what it contains.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Nothing known, quantitatively, about the number of
+humanities scholars who must see the original versus those who would
+settle for an edited transcript, or about the ways in which humanities
+scholars are using information technology * Firm conclusions concerning
+the manner and extent of the use of supporting materials in print
+provided by AM to await completion of evaluative study * A listener's
+reflections on additional applications of electronic texts * Role of
+electronic resources in teaching elementary research skills to students *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the discussion that followed the presentations by MICHELSON,
+VECCIA, and FREEMAN, additional points emerged.
+
+LESK asked if MICHELSON could give any quantitative estimate of the
+number of humanities scholars who must see or want to see the original,
+or the best possible version of the material, versus those who typically
+would settle for an edited transcript. While unable to provide a figure,
+she offered her impressions as an archivist who has done some reference
+work and has discussed this issue with other archivists who perform
+reference, that those who use archives and those who use primary sources
+for what would be considered very high-level scholarly research, as
+opposed to, say, undergraduate papers, were few in number, especially
+given the public interest in using primary sources to conduct
+genealogical or avocational research and the kind of professional
+research done by people in private industry or the federal government.
+More important in MICHELSON's view was that, quantitatively, nothing is
+known about the ways in which, for example, humanities scholars are using
+information technology. No studies exist to offer guidance in creating
+strategies. The most recent study was conducted in 1985 by the American
+Council of Learned Societies (ACLS), and what it showed was that 50
+percent of humanities scholars at that time were using computers. That
+constitutes the extent of our knowledge.
+
+Concerning AM's strategy for orienting people toward the scope of
+electronic resources, FREEMAN could offer no hard conclusions at this
+point, because she and her colleagues were still waiting to see,
+particularly in the schools, what has been made of their efforts. Within
+the system, however, AM has provided what are called electronic exhibits-
+-such as introductions to time periods and materials--and these are
+intended to offer a student user a sense of what a broadside is and what
+it might tell her or him. But FREEMAN conceded that the project staff
+would have to talk with students next year, after teachers have had a
+summer to use the materials, and attempt to discover what the students
+were learning from the materials. In addition, FREEMAN described
+supporting materials in print provided by AM at the request of local
+teachers during a meeting held at LC. These included time lines,
+bibliographies, and other materials that could be reproduced on a
+photocopier in a classroom. Teachers could walk away with and use these,
+and in this way gain a better understanding of the contents. But again,
+reaching firm conclusions concerning the manner and extent of their use
+would have to wait until next year.
+
+As to the changes she saw occurring at the National Archives and Records
+Administration (NARA) as a result of the increasing emphasis on
+technology in scholarly research, MICHELSON stated that NARA at this
+point was absorbing the report by her and Jeff Rothenberg addressing
+strategies for the archival profession in general, although not for the
+National Archives specifically. NARA is just beginning to establish its
+role and what it can do. In terms of changes and initiatives that NARA
+can take, no clear response could be given at this time.
+
+GREENFIELD remarked two trends mentioned in the session. Reflecting on
+DALY's opening comments on how he could have used a Latin collection of
+text in an electronic form, he said that at first he thought most scholars
+would be unwilling to do that. But as he thought of that in terms of the
+original meaning of research--that is, having already mastered these texts,
+researching them for critical and comparative purposes--for the first time,
+the electronic format made a lot of sense. GREENFIELD could envision
+growing numbers of scholars learning the new technologies for that very
+aspect of their scholarship and for convenience's sake.
+
+Listening to VECCIA and FREEMAN, GREENFIELD thought of an additional
+application of electronic texts. He realized that AM could be used as a
+guide to lead someone to original sources. Students cannot be expected
+to have mastered these sources, things they have never known about
+before. Thus, AM is leading them, in theory, to a vast body of
+information and giving them a superficial overview of it, enabling them
+to select parts of it. GREENFIELD asked if any evidence exists that this
+resource will indeed teach the new user, the K-12 students, how to do
+research. Scholars already know how to do research and are applying
+these new tools. But he wondered why students would go beyond picking
+out things that were most exciting to them.
+
+FREEMAN conceded the correctness of GREENFIELD's observation as applied
+to a school environment. The risk is that a student would sit down at a
+system, play with it, find some things of interest, and then walk away.
+But in the relatively controlled situation of a school library, much will
+depend on the instructions a teacher or a librarian gives a student. She
+viewed the situation not as one of fine-tuning research skills but of
+involving students at a personal level in understanding and researching
+things. Given the guidance one can receive at school, it then becomes
+possible to teach elementary research skills to students, which in fact
+one particular librarian said she was teaching her fifth graders.
+FREEMAN concluded that introducing the idea of following one's own path
+of inquiry, which is essentially what research entails, involves more
+than teaching specific skills. To these comments VECCIA added the
+observation that the individual teacher and the use of a creative
+resource, rather than AM itself, seemed to make the key difference.
+Some schools and some teachers are making excellent use of the nature
+of critical thinking and teaching skills, she said.
+
+Concurring with these remarks, DALY closed the session with the thought that
+the more that producers produced for teachers and for scholars to use with
+their students, the more successful their electronic products would prove.
+
+ ******
+
+SESSION II. SHOW AND TELL
+
+Jacqueline HESS, director, National Demonstration Laboratory, served as
+moderator of the "show-and-tell" session. She noted that a
+question-and-answer period would follow each presentation.
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+MYLONAS * Overview and content of Perseus * Perseus' primary materials
+exist in a system-independent, archival form * A concession * Textual
+aspects of Perseus * Tools to use with the Greek text * Prepared indices
+and full-text searches in Perseus * English-Greek word search leads to
+close study of words and concepts * Navigating Perseus by tracing down
+indices * Using the iconography to perform research *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Elli MYLONAS, managing editor, Perseus Project, Harvard University, first
+gave an overview of Perseus, a large, collaborative effort based at
+Harvard University but with contributors and collaborators located at
+numerous universities and colleges in the United States (e.g., Bowdoin,
+Maryland, Pomona, Chicago, Virginia). Funded primarily by the
+Annenberg/CPB Project, with additional funding from Apple, Harvard, and
+the Packard Humanities Institute, among others, Perseus is a multimedia,
+hypertextual database for teaching and research on classical Greek
+civilization, which was released in February 1992 in version 1.0 and
+distributed by Yale University Press.
+
+Consisting entirely of primary materials, Perseus includes ancient Greek
+texts and translations of those texts; catalog entries--that is, museum
+catalog entries, not library catalog entries--on vases, sites, coins,
+sculpture, and archaeological objects; maps; and a dictionary, among
+other sources. The number of objects and the objects for which catalog
+entries exist are accompanied by thousands of color images, which
+constitute a major feature of the database. Perseus contains
+approximately 30 megabytes of text, an amount that will double in
+subsequent versions. In addition to these primary materials, the Perseus
+Project has been building tools for using them, making access and
+navigation easier, the goal being to build part of the electronic
+environment discussed earlier in the morning in which students or
+scholars can work with their sources.
+
+The demonstration of Perseus will show only a fraction of the real work
+that has gone into it, because the project had to face the dilemma of
+what to enter when putting something into machine-readable form: should
+one aim for very high quality or make concessions in order to get the
+material in? Since Perseus decided to opt for very high quality, all of
+its primary materials exist in a system-independent--insofar as it is
+possible to be system-independent--archival form. Deciding what that
+archival form would be and attaining it required much work and thought.
+For example, all the texts are marked up in SGML, which will be made
+compatible with the guidelines of the Text Encoding Initiative (TEI) when
+they are issued.
+
+Drawings are postscript files, not meeting international standards, but
+at least designed to go across platforms. Images, or rather the real
+archival forms, consist of the best available slides, which are being
+digitized. Much of the catalog material exists in database form--a form
+that the average user could use, manipulate, and display on a personal
+computer, but only at great cost. Thus, this is where the concession
+comes in: All of this rich, well-marked-up information is stripped of
+much of its content; the images are converted into bit-maps and the text
+into small formatted chunks. All this information can then be imported
+into HyperCard and run on a mid-range Macintosh, which is what Perseus
+users have. This fact has made it possible for Perseus to attain wide
+use fairly rapidly. Without those archival forms the HyperCard version
+being demonstrated could not be made easily, and the project could not
+have the potential to move to other forms and machines and software as
+they appear, none of which information is in Perseus on the CD.
+
+Of the numerous multimedia aspects of Perseus, MYLONAS focused on the
+textual. Part of what makes Perseus such a pleasure to use, MYLONAS
+said, is this effort at seamless integration and the ability to move
+around both visual and textual material. Perseus also made the decision
+not to attempt to interpret its material any more than one interprets by
+selecting. But, MYLONAS emphasized, Perseus is not courseware: No
+syllabus exists. There is no effort to define how one teaches a topic
+using Perseus, although the project may eventually collect papers by
+people who have used it to teach. Rather, Perseus aims to provide
+primary material in a kind of electronic library, an electronic sandbox,
+so to say, in which students and scholars who are working on this
+material can explore by themselves. With that, MYLONAS demonstrated
+Perseus, beginning with the Perseus gateway, the first thing one sees
+upon opening Perseus--an effort in part to solve the contextualizing
+problem--which tells the user what the system contains.
+
+MYLONAS demonstrated only a very small portion, beginning with primary
+texts and running off the CD-ROM. Having selected Aeschylus' Prometheus
+Bound, which was viewable in Greek and English pretty much in the same
+segments together, MYLONAS demonstrated tools to use with the Greek text,
+something not possible with a book: looking up the dictionary entry form
+of an unfamiliar word in Greek after subjecting it to Perseus'
+morphological analysis for all the texts. After finding out about a
+word, a user may then decide to see if it is used anywhere else in Greek.
+Because vast amounts of indexing support all of the primary material, one
+can find out where else all forms of a particular Greek word appear--
+often not a trivial matter because Greek is highly inflected. Further,
+since the story of Prometheus has to do with the origins of sacrifice, a
+user may wish to study and explore sacrifice in Greek literature; by
+typing sacrifice into a small window, a user goes to the English-Greek
+word list--something one cannot do without the computer (Perseus has
+indexed the definitions of its dictionary)--the string sacrifice appears
+in the definitions of these sixty-five words. One may then find out
+where any of those words is used in the work(s) of a particular author.
+The English definitions are not lemmatized.
+
+All of the indices driving this kind of usage were originally devised for
+speed, MYLONAS observed; in other words, all that kind of information--
+all forms of all words, where they exist, the dictionary form they belong
+to--were collected into databases, which will expedite searching. Then
+it was discovered that one can do things searching in these databases
+that could not be done searching in the full texts. Thus, although there
+are full-text searches in Perseus, much of the work is done behind the
+scenes, using prepared indices. Re the indexing that is done behind the
+scenes, MYLONAS pointed out that without the SGML forms of the text, it
+could not be done effectively. Much of this indexing is based on the
+structures that are made explicit by the SGML tagging.
+
+It was found that one of the things many of Perseus' non-Greek-reading
+users do is start from the dictionary and then move into the close study
+of words and concepts via this kind of English-Greek word search, by which
+means they might select a concept. This exercise has been assigned to
+students in core courses at Harvard--to study a concept by looking for the
+English word in the dictionary, finding the Greek words, and then finding
+the words in the Greek but, of course, reading across in the English.
+That tells them a great deal about what a translation means as well.
+
+Should one also wish to see images that have to do with sacrifice, that
+person would go to the object key word search, which allows one to
+perform a similar kind of index retrieval on the database of
+archaeological objects. Without words, pictures are useless; Perseus has
+not reached the point where it can do much with images that are not
+cataloged. Thus, although it is possible in Perseus with text and images
+to navigate by knowing where one wants to end up--for example, a
+red-figure vase from the Boston Museum of Fine Arts--one can perform this
+kind of navigation very easily by tracing down indices. MYLONAS
+illustrated several generic scenes of sacrifice on vases. The features
+demonstrated derived from Perseus 1.0; version 2.0 will implement even
+better means of retrieval.
+
+MYLONAS closed by looking at one of the pictures and noting again that
+one can do a great deal of research using the iconography as well as the
+texts. For instance, students in a core course at Harvard this year were
+highly interested in Greek concepts of foreigners and representations of
+non-Greeks. So they performed a great deal of research, both with texts
+(e.g., Herodotus) and with iconography on vases and coins, on how the
+Greeks portrayed non-Greeks. At the same time, art historians who study
+iconography were also interested, and were able to use this material.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Indexing and searchability of all English words in Perseus *
+Several features of Perseus 1.0 * Several levels of customization
+possible * Perseus used for general education * Perseus' effects on
+education * Contextual information in Perseus * Main challenge and
+emphasis of Perseus *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Several points emerged in the discussion that followed MYLONAS's presentation.
+
+Although MYLONAS had not demonstrated Perseus' ability to cross-search
+documents, she confirmed that all English words in Perseus are indexed
+and can be searched. So, for example, sacrifice could have been searched
+in all texts, the historical essay, and all the catalogue entries with
+their descriptions--in short, in all of Perseus.
+
+Boolean logic is not in Perseus 1.0 but will be added to the next
+version, although an effort is being made not to restrict Perseus to a
+database in which one just performs searching, Boolean or otherwise. It
+is possible to move laterally through the documents by selecting a word
+one is interested in and selecting an area of information one is
+interested in and trying to look that word up in that area.
+
+Since Perseus was developed in HyperCard, several levels of customization
+are possible. Simple authoring tools exist that allow one to create
+annotated paths through the information, which are useful for note-taking
+and for guided tours for teaching purposes and for expository writing.
+With a little more ingenuity it is possible to begin to add or substitute
+material in Perseus.
+
+Perseus has not been used so much for classics education as for general
+education, where it seemed to have an impact on the students in the core
+course at Harvard (a general required course that students must take in
+certain areas). Students were able to use primary material much more.
+
+The Perseus Project has an evaluation team at the University of Maryland
+that has been documenting Perseus' effects on education. Perseus is very
+popular, and anecdotal evidence indicates that it is having an effect at
+places other than Harvard, for example, test sites at Ball State
+University, Drury College, and numerous small places where opportunities
+to use vast amounts of primary data may not exist. One documented effect
+is that archaeological, anthropological, and philological research is
+being done by the same person instead of by three different people.
+
+The contextual information in Perseus includes an overview essay, a
+fairly linear historical essay on the fifth century B.C. that provides
+links into the primary material (e.g., Herodotus, Thucydides, and
+Plutarch), via small gray underscoring (on the screen) of linked
+passages. These are handmade links into other material.
+
+To different extents, most of the production work was done at Harvard,
+where the people and the equipment are located. Much of the
+collaborative activity involved data collection and structuring, because
+the main challenge and the emphasis of Perseus is the gathering of
+primary material, that is, building a useful environment for studying
+classical Greece, collecting data, and making it useful.
+Systems-building is definitely not the main concern. Thus, much of the
+work has involved writing essays, collecting information, rewriting it,
+and tagging it. That can be done off site. The creative link for the
+overview essay as well as for both systems and data was collaborative,
+and was forged via E-mail and paper mail with professors at Pomona and
+Bowdoin.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+CALALUCA * PLD's principal focus and contribution to scholarship *
+Various questions preparatory to beginning the project * Basis for
+project * Basic rule in converting PLD * Concerning the images in PLD *
+Running PLD under a variety of retrieval softwares * Encoding the
+database a hard-fought issue * Various features demonstrated * Importance
+of user documentation * Limitations of the CD-ROM version *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Eric CALALUCA, vice president, Chadwyck-Healey, Inc., demonstrated a
+software interpretation of the Patrologia Latina Database (PLD). PLD's
+principal focus from the beginning of the project about three-and-a-half
+years ago was on converting Migne's Latin series, and in the end,
+CALALUCA suggested, conversion of the text will be the major contribution
+to scholarship. CALALUCA stressed that, as possibly the only private
+publishing organization at the Workshop, Chadwyck-Healey had sought no
+federal funds or national foundation support before embarking upon the
+project, but instead had relied upon a great deal of homework and
+marketing to accomplish the task of conversion.
+
+Ever since the possibilities of computer-searching have emerged, scholars
+in the field of late ancient and early medieval studies (philosophers,
+theologians, classicists, and those studying the history of natural law
+and the history of the legal development of Western civilization) have
+been longing for a fully searchable version of Western literature, for
+example, all the texts of Augustine and Bernard of Clairvaux and
+Boethius, not to mention all the secondary and tertiary authors.
+
+Various questions arose, CALALUCA said. Should one convert Migne?
+Should the database be encoded? Is it necessary to do that? How should
+it be delivered? What about CD-ROM? Since this is a transitional
+medium, why even bother to create software to run on a CD-ROM? Since
+everybody knows people will be networking information, why go to the
+trouble--which is far greater with CD-ROM than with the production of
+magnetic data? Finally, how does one make the data available? Can many
+of the hurdles to using electronic information that some publishers have
+imposed upon databases be eliminated?
+
+The PLD project was based on the principle that computer-searching of
+texts is most effective when it is done with a large database. Because
+PLD represented a collection that serves so many disciplines across so
+many periods, it was irresistible.
+
+The basic rule in converting PLD was to do no harm, to avoid the sins of
+intrusion in such a database: no introduction of newer editions, no
+on-the-spot changes, no eradicating of all possible falsehoods from an
+edition. Thus, PLD is not the final act in electronic publishing for
+this discipline, but simply the beginning. The conversion of PLD has
+evoked numerous unanticipated questions: How will information be used?
+What about networking? Can the rights of a database be protected?
+Should one protect the rights of a database? How can it be made
+available?
+
+Those converting PLD also tried to avoid the sins of omission, that is,
+excluding portions of the collections or whole sections. What about the
+images? PLD is full of images, some are extremely pious
+nineteenth-century representations of the Fathers, while others contain
+highly interesting elements. The goal was to cover all the text of Migne
+(including notes, in Greek and in Hebrew, the latter of which, in
+particular, causes problems in creating a search structure), all the
+indices, and even the images, which are being scanned in separately
+searchable files.
+
+Several North American institutions that have placed acquisition requests
+for the PLD database have requested it in magnetic form without software,
+which means they are already running it without software, without
+anything demonstrated at the Workshop.
+
+What cannot practically be done is go back and reconvert and re-encode
+data, a time-consuming and extremely costly enterprise. CALALUCA sees
+PLD as a database that can, and should, be run under a variety of
+retrieval softwares. This will permit the widest possible searches.
+Consequently, the need to produce a CD-ROM of PLD, as well as to develop
+software that could handle some 1.3 gigabyte of heavily encoded text,
+developed out of conversations with collection development and reference
+librarians who wanted software both compassionate enough for the
+pedestrian but also capable of incorporating the most detailed
+lexicographical studies that a user desires to conduct. In the end, the
+encoding and conversion of the data will prove the most enduring
+testament to the value of the project.
+
+The encoding of the database was also a hard-fought issue: Did the
+database need to be encoded? Were there normative structures for encoding
+humanist texts? Should it be SGML? What about the TEI--will it last,
+will it prove useful? CALALUCA expressed some minor doubts as to whether
+a data bank can be fully TEI-conformant. Every effort can be made, but
+in the end to be TEI-conformant means to accept the need to make some
+firm encoding decisions that can, indeed, be disputed. The TEI points
+the publisher in a proper direction but does not presume to make all the
+decisions for him or her. Essentially, the goal of encoding was to
+eliminate, as much as possible, the hindrances to information-networking,
+so that if an institution acquires a database, everybody associated with
+the institution can have access to it.
+
+CALALUCA demonstrated a portion of Volume 160, because it had the most
+anomalies in it. The software was created by Electronic Book
+Technologies of Providence, RI, and is called Dynatext. The software
+works only with SGML-coded data.
+
+Viewing a table of contents on the screen, the audience saw how Dynatext
+treats each element as a book and attempts to simplify movement through a
+volume. Familiarity with the Patrologia in print (i.e., the text, its
+source, and the editions) will make the machine-readable versions highly
+useful. (Software with a Windows application was sought for PLD,
+CALALUCA said, because this was the main trend for scholarly use.)
+
+CALALUCA also demonstrated how a user can perform a variety of searches
+and quickly move to any part of a volume; the look-up screen provides
+some basic, simple word-searching.
+
+CALALUCA argued that one of the major difficulties is not the software.
+Rather, in creating a product that will be used by scholars representing
+a broad spectrum of computer sophistication, user documentation proves
+to be the most important service one can provide.
+
+CALALUCA next illustrated a truncated search under mysterium within ten
+words of virtus and how one would be able to find its contents throughout
+the entire database. He said that the exciting thing about PLD is that
+many of the applications in the retrieval software being written for it
+will exceed the capabilities of the software employed now for the CD-ROM
+version. The CD-ROM faces genuine limitations, in terms of speed and
+comprehensiveness, in the creation of a retrieval software to run it.
+CALALUCA said he hoped that individual scholars will download the data,
+if they wish, to their personal computers, and have ready access to
+important texts on a constant basis, which they will be able to use in
+their research and from which they might even be able to publish.
+
+(CALALUCA explained that the blue numbers represented Migne's column numbers,
+which are the standard scholarly references. Pulling up a note, he stated
+that these texts were heavily edited and the image files would appear simply
+as a note as well, so that one could quickly access an image.)
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+FLEISCHHAUER/ERWAY * Several problems with which AM is still wrestling *
+Various search and retrieval capabilities * Illustration of automatic
+stemming and a truncated search * AM's attempt to find ways to connect
+cataloging to the texts * AM's gravitation towards SGML * Striking a
+balance between quantity and quality * How AM furnishes users recourse to
+images * Conducting a search in a full-text environment * Macintosh and
+IBM prototypes of AM * Multimedia aspects of AM *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+A demonstration of American Memory by its coordinator, Carl FLEISCHHAUER,
+and Ricky ERWAY, associate coordinator, Library of Congress, concluded
+the morning session. Beginning with a collection of broadsides from the
+Continental Congress and the Constitutional Convention, the only text
+collection in a presentable form at the time of the Workshop, FLEISCHHAUER
+highlighted several of the problems with which AM is still wrestling.
+(In its final form, the disk will contain two collections, not only the
+broadsides but also the full text with illustrations of a set of
+approximately 300 African-American pamphlets from the period 1870 to 1910.)
+
+As FREEMAN had explained earlier, AM has attempted to use a small amount
+of interpretation to introduce collections. In the present case, the
+contractor, a company named Quick Source, in Silver Spring, MD., used
+software called Toolbook and put together a modestly interactive
+introduction to the collection. Like the two preceding speakers,
+FLEISCHHAUER argued that the real asset was the underlying collection.
+
+FLEISCHHAUER proceeded to describe various search and retrieval
+capabilities while ERWAY worked the computer. In this particular package
+the "go to" pull-down allowed the user in effect to jump out of Toolbook,
+where the interactive program was located, and enter the third-party
+software used by AM for this text collection, which is called Personal
+Librarian. This was the Windows version of Personal Librarian, a
+software application put together by a company in Rockville, Md.
+
+Since the broadsides came from the Revolutionary War period, a search was
+conducted using the words British or war, with the default operator reset
+as or. FLEISCHHAUER demonstrated both automatic stemming (which finds
+other forms of the same root) and a truncated search. One of Personal
+Librarian's strongest features, the relevance ranking, was represented by
+a chart that indicated how often words being sought appeared in
+documents, with the one receiving the most "hits" obtaining the highest
+score. The "hit list" that is supplied takes the relevance ranking into
+account, making the first hit, in effect, the one the software has
+selected as the most relevant example.
+
+While in the text of one of the broadside documents, FLEISCHHAUER
+remarked AM's attempt to find ways to connect cataloging to the texts,
+which it does in different ways in different manifestations. In the case
+shown, the cataloging was pasted on: AM took MARC records that were
+written as on-line records right into one of the Library's mainframe
+retrieval programs, pulled them out, and handed them off to the contractor,
+who massaged them somewhat to display them in the manner shown. One of
+AM's questions is, Does the cataloguing normally performed in the mainframe
+work in this context, or had AM ought to think through adjustments?
+
+FLEISCHHAUER made the additional point that, as far as the text goes, AM
+has gravitated towards SGML (he pointed to the boldface in the upper part
+of the screen). Although extremely limited in its ability to translate
+or interpret SGML, Personal Librarian will furnish both bold and italics
+on screen; a fairly easy thing to do, but it is one of the ways in which
+SGML is useful.
+
+Striking a balance between quantity and quality has been a major concern
+of AM, with accuracy being one of the places where project staff have
+felt that less than 100-percent accuracy was not unacceptable.
+FLEISCHHAUER cited the example of the standard of the rekeying industry,
+namely 99.95 percent; as one service bureau informed him, to go from
+99.95 to 100 percent would double the cost.
+
+FLEISCHHAUER next demonstrated how AM furnishes users recourse to images,
+and at the same time recalled LESK's pointed question concerning the
+number of people who would look at those images and the number who would
+work only with the text. If the implication of LESK's question was
+sound, FLEISCHHAUER said, it raised the stakes for text accuracy and
+reduced the value of the strategy for images.
+
+Contending that preservation is always a bugaboo, FLEISCHHAUER
+demonstrated several images derived from a scan of a preservation
+microfilm that AM had made. He awarded a grade of C at best, perhaps a
+C minus or a C plus, for how well it worked out. Indeed, the matter of
+learning if other people had better ideas about scanning in general, and,
+in particular, scanning from microfilm, was one of the factors that drove
+AM to attempt to think through the agenda for the Workshop. Skew, for
+example, was one of the issues that AM in its ignorance had not reckoned
+would prove so difficult.
+
+Further, the handling of images of the sort shown, in a desktop computer
+environment, involved a considerable amount of zooming and scrolling.
+Ultimately, AM staff feel that perhaps the paper copy that is printed out
+might be the most useful one, but they remain uncertain as to how much
+on-screen reading users will do.
+
+Returning to the text, FLEISCHHAUER asked viewers to imagine a person who
+might be conducting a search in a full-text environment. With this
+scenario, he proceeded to illustrate other features of Personal Librarian
+that he considered helpful; for example, it provides the ability to
+notice words as one reads. Clicking the "include" button on the bottom
+of the search window pops the words that have been highlighted into the
+search. Thus, a user can refine the search as he or she reads,
+re-executing the search and continuing to find things in the quest for
+materials. This software not only contains relevance ranking, Boolean
+operators, and truncation, it also permits one to perform word algebra,
+so to say, where one puts two or three words in parentheses and links
+them with one Boolean operator and then a couple of words in another set
+of parentheses and asks for things within so many words of others.
+
+Until they became acquainted recently with some of the work being done in
+classics, the AM staff had not realized that a large number of the
+projects that involve electronic texts were being done by people with a
+profound interest in language and linguistics. Their search strategies
+and thinking are oriented to those fields, as is shown in particular by
+the Perseus example. As amateur historians, the AM staff were thinking
+more of searching for concepts and ideas than for particular words.
+Obviously, FLEISCHHAUER conceded, searching for concepts and ideas and
+searching for words may be two rather closely related things.
+
+While displaying several images, FLEISCHHAUER observed that the Macintosh
+prototype built by AM contains a greater diversity of formats. Echoing a
+previous speaker, he said that it was easier to stitch things together in
+the Macintosh, though it tended to be a little more anemic in search and
+retrieval. AM, therefore, increasingly has been investigating
+sophisticated retrieval engines in the IBM format.
+
+FLEISCHHAUER demonstrated several additional examples of the prototype
+interfaces: One was AM's metaphor for the network future, in which a
+kind of reading-room graphic suggests how one would be able to go around
+to different materials. AM contains a large number of photographs in
+analog video form worked up from a videodisc, which enable users to make
+copies to print or incorporate in digital documents. A frame-grabber is
+built into the system, making it possible to bring an image into a window
+and digitize or print it out.
+
+FLEISCHHAUER next demonstrated sound recording, which included texts.
+Recycled from a previous project, the collection included sixty 78-rpm
+phonograph records of political speeches that were made during and
+immediately after World War I. These constituted approximately three
+hours of audio, as AM has digitized it, which occupy 150 megabytes on a
+CD. Thus, they are considerably compressed. From the catalogue card,
+FLEISCHHAUER proceeded to a transcript of a speech with the audio
+available and with highlighted text following it as it played.
+A photograph has been added and a transcription made.
+
+Considerable value has been added beyond what the Library of Congress
+normally would do in cataloguing a sound recording, which raises several
+questions for AM concerning where to draw lines about how much value it can
+afford to add and at what point, perhaps, this becomes more than AM could
+reasonably do or reasonably wish to do. FLEISCHHAUER also demonstrated
+a motion picture. As FREEMAN had reported earlier, the motion picture
+materials have proved the most popular, not surprisingly. This says more
+about the medium, he thought, than about AM's presentation of it.
+
+Because AM's goal was to bring together things that could be used by
+historians or by people who were curious about history,
+turn-of-the-century footage seemed to represent the most appropriate
+collections from the Library of Congress in motion pictures. These were
+the very first films made by Thomas Edison's company and some others at
+that time. The particular example illustrated was a Biograph film,
+brought in with a frame-grabber into a window. A single videodisc
+contains about fifty titles and pieces of film from that period, all of
+New York City. Taken together, AM believes, they provide an interesting
+documentary resource.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Using the frame-grabber in AM * Volume of material processed
+and to be processed * Purpose of AM within LC * Cataloguing and the
+nature of AM's material * SGML coding and the question of quality versus
+quantity *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the question-and-answer period that followed FLEISCHHAUER's
+presentation, several clarifications were made.
+
+AM is bringing in motion pictures from a videodisc. The frame-grabber
+devices create a window on a computer screen, which permits users to
+digitize a single frame of the movie or one of the photographs. It
+produces a crude, rough-and-ready image that high school students can
+incorporate into papers, and that has worked very nicely in this way.
+
+Commenting on FLEISCHHAUER's assertion that AM was looking more at
+searching ideas than words, MYLONAS argued that without words an idea
+does not exist. FLEISCHHAUER conceded that he ought to have articulated
+his point more clearly. MYLONAS stated that they were in fact both
+talking about the same thing. By searching for words and by forcing
+people to focus on the word, the Perseus Project felt that they would get
+them to the idea. The way one reviews results is tailored more to one
+kind of user than another.
+
+Concerning the total volume of material that has been processed in this
+way, AM at this point has in retrievable form seven or eight collections,
+all of them photographic. In the Macintosh environment, for example,
+there probably are 35,000-40,000 photographs. The sound recordings
+number sixty items. The broadsides number about 300 items. There are
+500 political cartoons in the form of drawings. The motion pictures, as
+individual items, number sixty to seventy.
+
+AM also has a manuscript collection, the life history portion of one of
+the federal project series, which will contain 2,900 individual
+documents, all first-person narratives. AM has in process about 350
+African-American pamphlets, or about 12,000 printed pages for the period
+1870-1910. Also in the works are some 4,000 panoramic photographs. AM
+has recycled a fair amount of the work done by LC's Prints and
+Photographs Division during the Library's optical disk pilot project in
+the 1980s. For example, a special division of LC has tooled up and
+thought through all the ramifications of electronic presentation of
+photographs. Indeed, they are wheeling them out in great barrel loads.
+The purpose of AM within the Library, it is hoped, is to catalyze several
+of the other special collection divisions which have no particular
+experience with, in some cases, mixed feelings about, an activity such as
+AM. Moreover, in many cases the divisions may be characterized as not
+only lacking experience in "electronifying" things but also in automated
+cataloguing. MARC cataloguing as practiced in the United States is
+heavily weighted toward the description of monograph and serial
+materials, but is much thinner when one enters the world of manuscripts
+and things that are held in the Library's music collection and other
+units. In response to a comment by LESK, that AM's material is very
+heavily photographic, and is so primarily because individual records have
+been made for each photograph, FLEISCHHAUER observed that an item-level
+catalog record exists, for example, for each photograph in the Detroit
+Publishing collection of 25,000 pictures. In the case of the Federal
+Writers Project, for which nearly 3,000 documents exist, representing
+information from twenty-six different states, AM with the assistance of
+Karen STUART of the Manuscript Division will attempt to find some way not
+only to have a collection-level record but perhaps a MARC record for each
+state, which will then serve as an umbrella for the 100-200 documents
+that come under it. But that drama remains to be enacted. The AM staff
+is conservative and clings to cataloguing, though of course visitors tout
+artificial intelligence and neural networks in a manner that suggests that
+perhaps one need not have cataloguing or that much of it could be put aside.
+
+The matter of SGML coding, FLEISCHHAUER conceded, returned the discussion
+to the earlier treated question of quality versus quantity in the Library
+of Congress. Of course, text conversion can be done with 100-percent
+accuracy, but it means that when one's holdings are as vast as LC's only
+a tiny amount will be exposed, whereas permitting lower levels of
+accuracy can lead to exposing or sharing larger amounts, but with the
+quality correspondingly impaired.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+TWOHIG * A contrary experience concerning electronic options * Volume of
+material in the Washington papers and a suggestion of David Packard *
+Implications of Packard's suggestion * Transcribing the documents for the
+CD-ROM * Accuracy of transcriptions * The CD-ROM edition of the Founding
+Fathers documents *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Finding encouragement in a comment of MICHELSON's from the morning
+session--that numerous people in the humanities were choosing electronic
+options to do their work--Dorothy TWOHIG, editor, The Papers of George
+Washington, opened her illustrated talk by noting that her experience
+with literary scholars and numerous people in editing was contrary to
+MICHELSON's. TWOHIG emphasized literary scholars' complete ignorance of
+the technological options available to them or their reluctance or, in
+some cases, their downright hostility toward these options.
+
+After providing an overview of the five Founding Fathers projects
+(Jefferson at Princeton, Franklin at Yale, John Adams at the
+Massachusetts Historical Society, and Madison down the hall from her at
+the University of Virginia), TWOHIG observed that the Washington papers,
+like all of the projects, include both sides of the Washington
+correspondence and deal with some 135,000 documents to be published with
+extensive annotation in eighty to eighty-five volumes, a project that
+will not be completed until well into the next century. Thus, it was
+with considerable enthusiasm several years ago that the Washington Papers
+Project (WPP) greeted David Packard's suggestion that the papers of the
+Founding Fathers could be published easily and inexpensively, and to the
+great benefit of American scholarship, via CD-ROM.
+
+In pragmatic terms, funding from the Packard Foundation would expedite
+the transcription of thousands of documents waiting to be put on disk in
+the WPP offices. Further, since the costs of collecting, editing, and
+converting the Founding Fathers documents into letterpress editions were
+running into the millions of dollars, and the considerable staffs
+involved in all of these projects were devoting their careers to
+producing the work, the Packard Foundation's suggestion had a
+revolutionary aspect: Transcriptions of the entire corpus of the
+Founding Fathers papers would be available on CD-ROM to public and
+college libraries, even high schools, at a fraction of the cost--
+$100-$150 for the annual license fee--to produce a limited university
+press run of 1,000 of each volume of the published papers at $45-$150 per
+printed volume. Given the current budget crunch in educational systems
+and the corresponding constraints on librarians in smaller institutions
+who wish to add these volumes to their collections, producing the
+documents on CD-ROM would likely open a greatly expanded audience for the
+papers. TWOHIG stressed, however, that development of the Founding
+Fathers CD-ROM is still in its infancy. Serious software problems remain
+to be resolved before the material can be put into readable form.
+
+Funding from the Packard Foundation resulted in a major push to
+transcribe the 75,000 or so documents of the Washington papers remaining
+to be transcribed onto computer disks. Slides illustrated several of the
+problems encountered, for example, the present inability of CD-ROM to
+indicate the cross-outs (deleted material) in eighteenth century
+documents. TWOHIG next described documents from various periods in the
+eighteenth century that have been transcribed in chronological order and
+delivered to the Packard offices in California, where they are converted
+to the CD-ROM, a process that is expected to consume five years to
+complete (that is, reckoning from David Packard's suggestion made several
+years ago, until about July 1994). TWOHIG found an encouraging
+indication of the project's benefits in the ongoing use made by scholars
+of the search functions of the CD-ROM, particularly in reducing the time
+spent in manually turning the pages of the Washington papers.
+
+TWOHIG next furnished details concerning the accuracy of transcriptions.
+For instance, the insertion of thousands of documents on the CD-ROM
+currently does not permit each document to be verified against the
+original manuscript several times as in the case of documents that appear
+in the published edition. However, the transcriptions receive a cursory
+check for obvious typos, the misspellings of proper names, and other
+errors from the WPP CD-ROM editor. Eventually, all documents that appear
+in the electronic version will be checked by project editors. Although
+this process has met with opposition from some of the editors on the
+grounds that imperfect work may leave their offices, the advantages in
+making this material available as a research tool outweigh fears about the
+misspelling of proper names and other relatively minor editorial matters.
+
+Completion of all five Founding Fathers projects (i.e., retrievability
+and searchability of all of the documents by proper names, alternate
+spellings, or varieties of subjects) will provide one of the richest
+sources of this size for the history of the United States in the latter
+part of the eighteenth century. Further, publication on CD-ROM will
+allow editors to include even minutiae, such as laundry lists, not
+included in the printed volumes.
+
+It seems possible that the extensive annotation provided in the printed
+volumes eventually will be added to the CD-ROM edition, pending
+negotiations with the publishers of the papers. At the moment, the
+Founding Fathers CD-ROM is accessible only on the IBYCUS, a computer
+developed out of the Thesaurus Linguae Graecae project and designed for
+the use of classical scholars. There are perhaps 400 IBYCUS computers in
+the country, most of which are in university classics departments.
+Ultimately, it is anticipated that the CD-ROM edition of the Founding
+Fathers documents will run on any IBM-compatible or Macintosh computer
+with a CD-ROM drive. Numerous changes in the software will also occur
+before the project is completed. (Editor's note: an IBYCUS was
+unavailable to demonstrate the CD-ROM.)
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Several additional features of WPP clarified *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Discussion following TWOHIG's presentation served to clarify several
+additional features, including (1) that the project's primary
+intellectual product consists in the electronic transcription of the
+material; (2) that the text transmitted to the CD-ROM people is not
+marked up; (3) that cataloging and subject-indexing of the material
+remain to be worked out (though at this point material can be retrieved
+by name); and (4) that because all the searching is done in the hardware,
+the IBYCUS is designed to read a CD-ROM which contains only sequential
+text files. Technically, it then becomes very easy to read the material
+off and put it on another device.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LEBRON * Overview of the history of the joint project between AAAS and
+OCLC * Several practices the on-line environment shares with traditional
+publishing on hard copy * Several technical and behavioral barriers to
+electronic publishing * How AAAS and OCLC arrived at the subject of
+clinical trials * Advantages of the electronic format and other features
+of OJCCT * An illustrated tour of the journal *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Maria LEBRON, managing editor, The Online Journal of Current Clinical
+Trials (OJCCT), presented an illustrated overview of the history of the
+joint project between the American Association for the Advancement of
+Science (AAAS) and the Online Computer Library Center, Inc. (OCLC). The
+joint venture between AAAS and OCLC owes its beginning to a
+reorganization launched by the new chief executive officer at OCLC about
+three years ago and combines the strengths of these two disparate
+organizations. In short, OJCCT represents the process of scholarly
+publishing on line.
+
+LEBRON next discussed several practices the on-line environment shares
+with traditional publishing on hard copy--for example, peer review of
+manuscripts--that are highly important in the academic world. LEBRON
+noted in particular the implications of citation counts for tenure
+committees and grants committees. In the traditional hard-copy
+environment, citation counts are readily demonstrable, whereas the
+on-line environment represents an ethereal medium to most academics.
+
+LEBRON remarked several technical and behavioral barriers to electronic
+publishing, for instance, the problems in transmission created by special
+characters or by complex graphics and halftones. In addition, she noted
+economic limitations such as the storage costs of maintaining back issues
+and market or audience education.
+
+Manuscripts cannot be uploaded to OJCCT, LEBRON explained, because it is
+not a bulletin board or E-mail, forms of electronic transmission of
+information that have created an ambience clouding people's understanding
+of what the journal is attempting to do. OJCCT, which publishes
+peer-reviewed medical articles dealing with the subject of clinical
+trials, includes text, tabular material, and graphics, although at this
+time it can transmit only line illustrations.
+
+Next, LEBRON described how AAAS and OCLC arrived at the subject of
+clinical trials: It is 1) a highly statistical discipline that 2) does
+not require halftones but can satisfy the needs of its audience with line
+illustrations and graphic material, and 3) there is a need for the speedy
+dissemination of high-quality research results. Clinical trials are
+research activities that involve the administration of a test treatment
+to some experimental unit in order to test its usefulness before it is
+made available to the general population. LEBRON proceeded to give
+additional information on OJCCT concerning its editor-in-chief, editorial
+board, editorial content, and the types of articles it publishes
+(including peer-reviewed research reports and reviews), as well as
+features shared by other traditional hard-copy journals.
+
+Among the advantages of the electronic format are faster dissemination of
+information, including raw data, and the absence of space constraints
+because pages do not exist. (This latter fact creates an interesting
+situation when it comes to citations.) Nor are there any issues. AAAS's
+capacity to download materials directly from the journal to a
+subscriber's printer, hard drive, or floppy disk helps ensure highly
+accurate transcription. Other features of OJCCT include on-screen alerts
+that allow linkage of subsequently published documents to the original
+documents; on-line searching by subject, author, title, etc.; indexing of
+every single word that appears in an article; viewing access to an
+article by component (abstract, full text, or graphs); numbered
+paragraphs to replace page counts; publication in Science every thirty
+days of indexing of all articles published in the journal;
+typeset-quality screens; and Hypertext links that enable subscribers to
+bring up Medline abstracts directly without leaving the journal.
+
+After detailing the two primary ways to gain access to the journal,
+through the OCLC network and Compuserv if one desires graphics or through
+the Internet if just an ASCII file is desired, LEBRON illustrated the
+speedy editorial process and the coding of the document using SGML tags
+after it has been accepted for publication. She also gave an illustrated
+tour of the journal, its search-and-retrieval capabilities in particular,
+but also including problems associated with scanning in illustrations,
+and the importance of on-screen alerts to the medical profession re
+retractions or corrections, or more frequently, editorials, letters to
+the editors, or follow-up reports. She closed by inviting the audience
+to join AAAS on 1 July, when OJCCT was scheduled to go on-line.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Additional features of OJCCT *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+In the lengthy discussion that followed LEBRON's presentation, these
+points emerged:
+
+ * The SGML text can be tailored as users wish.
+
+ * All these articles have a fairly simple document definition.
+
+ * Document-type definitions (DTDs) were developed and given to OJCCT
+ for coding.
+
+ * No articles will be removed from the journal. (Because there are
+ no back issues, there are no lost issues either. Once a subscriber
+ logs onto the journal he or she has access not only to the currently
+ published materials, but retrospectively to everything that has been
+ published in it. Thus the table of contents grows bigger. The date
+ of publication serves to distinguish between currently published
+ materials and older materials.)
+
+ * The pricing system for the journal resembles that for most medical
+ journals: for 1992, $95 for a year, plus telecommunications charges
+ (there are no connect time charges); for 1993, $110 for the
+ entire year for single users, though the journal can be put on a
+ local area network (LAN). However, only one person can access the
+ journal at a time. Site licenses may come in the future.
+
+ * AAAS is working closely with colleagues at OCLC to display
+ mathematical equations on screen.
+
+ * Without compromising any steps in the editorial process, the
+ technology has reduced the time lag between when a manuscript is
+ originally submitted and the time it is accepted; the review process
+ does not differ greatly from the standard six-to-eight weeks
+ employed by many of the hard-copy journals. The process still
+ depends on people.
+
+ * As far as a preservation copy is concerned, articles will be
+ maintained on the computer permanently and subscribers, as part of
+ their subscription, will receive a microfiche-quality archival copy
+ of everything published during that year; in addition, reprints can
+ be purchased in much the same way as in a hard-copy environment.
+ Hard copies are prepared but are not the primary medium for the
+ dissemination of the information.
+
+ * Because OJCCT is not yet on line, it is difficult to know how many
+ people would simply browse through the journal on the screen as
+ opposed to downloading the whole thing and printing it out; a mix of
+ both types of users likely will result.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+PERSONIUS * Developments in technology over the past decade * The CLASS
+Project * Advantages for technology and for the CLASS Project *
+Developing a network application an underlying assumption of the project
+* Details of the scanning process * Print-on-demand copies of books *
+Future plans include development of a browsing tool *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Lynne PERSONIUS, assistant director, Cornell Information Technologies for
+Scholarly Information Services, Cornell University, first commented on
+the tremendous impact that developments in technology over the past ten
+years--networking, in particular--have had on the way information is
+handled, and how, in her own case, these developments have counterbalanced
+Cornell's relative geographical isolation. Other significant technologies
+include scanners, which are much more sophisticated than they were ten years
+ago; mass storage and the dramatic savings that result from it in terms of
+both space and money relative to twenty or thirty years ago; new and
+improved printing technologies, which have greatly affected the distribution
+of information; and, of course, digital technologies, whose applicability to
+library preservation remains at issue.
+
+Given that context, PERSONIUS described the College Library Access and
+Storage System (CLASS) Project, a library preservation project,
+primarily, and what has been accomplished. Directly funded by the
+Commission on Preservation and Access and by the Xerox Corporation, which
+has provided a significant amount of hardware, the CLASS Project has been
+working with a development team at Xerox to develop a software
+application tailored to library preservation requirements. Within
+Cornell, participants in the project have been working jointly with both
+library and information technologies. The focus of the project has been
+on reformatting and saving books that are in brittle condition.
+PERSONIUS showed Workshop participants a brittle book, and described how
+such books were the result of developments in papermaking around the
+beginning of the Industrial Revolution. The papermaking process was
+changed so that a significant amount of acid was introduced into the
+actual paper itself, which deteriorates as it sits on library shelves.
+
+One of the advantages for technology and for the CLASS Project is that
+the information in brittle books is mostly out of copyright and thus
+offers an opportunity to work with material that requires library
+preservation, and to create and work on an infrastructure to save the
+material. Acknowledging the familiarity of those working in preservation
+with this information, PERSONIUS noted that several things are being
+done: the primary preservation technology used today is photocopying of
+brittle material. Saving the intellectual content of the material is the
+main goal. With microfilm copy, the intellectual content is preserved on
+the assumption that in the future the image can be reformatted in any
+other way that then exists.
+
+An underlying assumption of the CLASS Project from the beginning was
+that it would develop a network application. Project staff scan books
+at a workstation located in the library, near the brittle material.
+An image-server filing system is located at a distance from that
+workstation, and a printer is located in another building. All of the
+materials digitized and stored on the image-filing system are cataloged
+in the on-line catalogue. In fact, a record for each of these electronic
+books is stored in the RLIN database so that a record exists of what is
+in the digital library throughout standard catalogue procedures. In the
+future, researchers working from their own workstations in their offices,
+or their networks, will have access--wherever they might be--through a
+request server being built into the new digital library. A second
+assumption is that the preferred means of finding the material will be by
+looking through a catalogue. PERSONIUS described the scanning process,
+which uses a prototype scanner being developed by Xerox and which scans a
+very high resolution image at great speed. Another significant feature,
+because this is a preservation application, is the placing of the pages
+that fall apart one for one on the platen. Ordinarily, a scanner could
+be used with some sort of a document feeder, but because of this
+application that is not feasible. Further, because CLASS is a
+preservation application, after the paper replacement is made there, a
+very careful quality control check is performed. An original book is
+compared to the printed copy and verification is made, before proceeding,
+that all of the image, all of the information, has been captured. Then,
+a new library book is produced: The printed images are rebound by a
+commercial binder and a new book is returned to the shelf.
+Significantly, the books returned to the library shelves are beautiful
+and useful replacements on acid-free paper that should last a long time,
+in effect, the equivalent of preservation photocopies. Thus, the project
+has a library of digital books. In essence, CLASS is scanning and
+storing books as 600 dot-per-inch bit-mapped images, compressed using
+Group 4 CCITT (i.e., the French acronym for International Consultative
+Committee for Telegraph and Telephone) compression. They are stored as
+TIFF files on an optical filing system that is composed of a database
+used for searching and locating the books and an optical jukebox that
+stores 64 twelve-inch platters. A very-high-resolution printed copy of
+these books at 600 dots per inch is created, using a Xerox DocuTech
+printer to make the paper replacements on acid-free paper.
+
+PERSONIUS maintained that the CLASS Project presents an opportunity to
+introduce people to books as digital images by using a paper medium.
+Books are returned to the shelves while people are also given the ability
+to print on demand--to make their own copies of books. (PERSONIUS
+distributed copies of an engineering journal published by engineering
+students at Cornell around 1900 as an example of what a print-on-demand
+copy of material might be like. This very cheap copy would be available
+to people to use for their own research purposes and would bridge the gap
+between an electronic work and the paper that readers like to have.)
+PERSONIUS then attempted to illustrate a very early prototype of
+networked access to this digital library. Xerox Corporation has
+developed a prototype of a view station that can send images across the
+network to be viewed.
+
+The particular library brought down for demonstration contained two
+mathematics books. CLASS is developing and will spend the next year
+developing an application that allows people at workstations to browse
+the books. Thus, CLASS is developing a browsing tool, on the assumption
+that users do not want to read an entire book from a workstation, but
+would prefer to be able to look through and decide if they would like to
+have a printed copy of it.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Re retrieval software * "Digital file copyright" * Scanning
+rate during production * Autosegmentation * Criteria employed in
+selecting books for scanning * Compression and decompression of images *
+OCR not precluded *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the question-and-answer period that followed her presentation,
+PERSONIUS made these additional points:
+
+ * Re retrieval software, Cornell is developing a Unix-based server
+ as well as clients for the server that support multiple platforms
+ (Macintosh, IBM and Sun workstations), in the hope that people from
+ any of those platforms will retrieve books; a further operating
+ assumption is that standard interfaces will be used as much as
+ possible, where standards can be put in place, because CLASS
+ considers this retrieval software a library application and would
+ like to be able to look at material not only at Cornell but at other
+ institutions.
+
+ * The phrase "digital file copyright by Cornell University" was
+ added at the advice of Cornell's legal staff with the caveat that it
+ probably would not hold up in court. Cornell does not want people
+ to copy its books and sell them but would like to keep them
+ available for use in a library environment for library purposes.
+
+ * In production the scanner can scan about 300 pages per hour,
+ capturing 600 dots per inch.
+
+ * The Xerox software has filters to scan halftone material and avoid
+ the moire patterns that occur when halftone material is scanned.
+ Xerox has been working on hardware and software that would enable
+ the scanner itself to recognize this situation and deal with it
+ appropriately--a kind of autosegmentation that would enable the
+ scanner to handle halftone material as well as text on a single page.
+
+ * The books subjected to the elaborate process described above were
+ selected because CLASS is a preservation project, with the first 500
+ books selected coming from Cornell's mathematics collection, because
+ they were still being heavily used and because, although they were
+ in need of preservation, the mathematics library and the mathematics
+ faculty were uncomfortable having them microfilmed. (They wanted a
+ printed copy.) Thus, these books became a logical choice for this
+ project. Other books were chosen by the project's selection committees
+ for experiments with the technology, as well as to meet a demand or need.
+
+ * Images will be decompressed before they are sent over the line; at
+ this time they are compressed and sent to the image filing system
+ and then sent to the printer as compressed images; they are returned
+ to the workstation as compressed 600-dpi images and the workstation
+ decompresses and scales them for display--an inefficient way to
+ access the material though it works quite well for printing and
+ other purposes.
+
+ * CLASS is also decompressing on Macintosh and IBM, a slow process
+ right now. Eventually, compression and decompression will take
+ place on an image conversion server. Trade-offs will be made, based
+ on future performance testing, concerning where the file is
+ compressed and what resolution image is sent.
+
+ * OCR has not been precluded; images are being stored that have been
+ scanned at a high resolution, which presumably would suit them well
+ to an OCR process. Because the material being scanned is about 100
+ years old and was printed with less-than-ideal technologies, very
+ early and preliminary tests have not produced good results. But the
+ project is capturing an image that is of sufficient resolution to be
+ subjected to OCR in the future. Moreover, the system architecture
+ and the system plan have a logical place to store an OCR image if it
+ has been captured. But that is not being done now.
+
+ ******
+
+SESSION III. DISTRIBUTION, NETWORKS, AND NETWORKING: OPTIONS FOR
+DISSEMINATION
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ZICH * Issues pertaining to CD-ROMs * Options for publishing in CD-ROM *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Robert ZICH, special assistant to the associate librarian for special
+projects, Library of Congress, and moderator of this session, first noted
+the blessed but somewhat awkward circumstance of having four very
+distinguished people representing networks and networking or at least
+leaning in that direction, while lacking anyone to speak from the
+strongest possible background in CD-ROMs. ZICH expressed the hope that
+members of the audience would join the discussion. He stressed the
+subtitle of this particular session, "Options for Dissemination," and,
+concerning CD-ROMs, the importance of determining when it would be wise
+to consider dissemination in CD-ROM versus networks. A shopping list of
+issues pertaining to CD-ROMs included: the grounds for selecting
+commercial publishers, and in-house publication where possible versus
+nonprofit or government publication. A similar list for networks
+included: determining when one should consider dissemination through a
+network, identifying the mechanisms or entities that exist to place items
+on networks, identifying the pool of existing networks, determining how a
+producer would choose between networks, and identifying the elements of
+a business arrangement in a network.
+
+Options for publishing in CD-ROM: an outside publisher versus
+self-publication. If an outside publisher is used, it can be nonprofit,
+such as the Government Printing Office (GPO) or the National Technical
+Information Service (NTIS), in the case of government. The pros and cons
+associated with employing an outside publisher are obvious. Among the
+pros, there is no trouble getting accepted. One pays the bill and, in
+effect, goes one's way. Among the cons, when one pays an outside
+publisher to perform the work, that publisher will perform the work it is
+obliged to do, but perhaps without the production expertise and skill in
+marketing and dissemination that some would seek. There is the body of
+commercial publishers that do possess that kind of expertise in
+distribution and marketing but that obviously are selective. In
+self-publication, one exercises full control, but then one must handle
+matters such as distribution and marketing. Such are some of the options
+for publishing in the case of CD-ROM.
+
+In the case of technical and design issues, which are also important,
+there are many matters which many at the Workshop already knew a good
+deal about: retrieval system requirements and costs, what to do about
+images, the various capabilities and platforms, the trade-offs between
+cost and performance, concerns about local-area networkability,
+interoperability, etc.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LYNCH * Creating networked information is different from using networks
+as an access or dissemination vehicle * Networked multimedia on a large
+scale does not yet work * Typical CD-ROM publication model a two-edged
+sword * Publishing information on a CD-ROM in the present world of
+immature standards * Contrast between CD-ROM and network pricing *
+Examples demonstrated earlier in the day as a set of insular information
+gems * Paramount need to link databases * Layering to become increasingly
+necessary * Project NEEDS and the issues of information reuse and active
+versus passive use * X-Windows as a way of differentiating between
+network access and networked information * Barriers to the distribution
+of networked multimedia information * Need for good, real-time delivery
+protocols * The question of presentation integrity in client-server
+computing in the academic world * Recommendations for producing multimedia
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Clifford LYNCH, director, Library Automation, University of California,
+opened his talk with the general observation that networked information
+constituted a difficult and elusive topic because it is something just
+starting to develop and not yet fully understood. LYNCH contended that
+creating genuinely networked information was different from using
+networks as an access or dissemination vehicle and was more sophisticated
+and more subtle. He invited the members of the audience to extrapolate,
+from what they heard about the preceding demonstration projects, to what
+sort of a world of electronics information--scholarly, archival,
+cultural, etc.--they wished to end up with ten or fifteen years from now.
+LYNCH suggested that to extrapolate directly from these projects would
+produce unpleasant results.
+
+Putting the issue of CD-ROM in perspective before getting into
+generalities on networked information, LYNCH observed that those engaged
+in multimedia today who wish to ship a product, so to say, probably do
+not have much choice except to use CD-ROM: networked multimedia on a
+large scale basically does not yet work because the technology does not
+exist. For example, anybody who has tried moving images around over the
+Internet knows that this is an exciting touch-and-go process, a
+fascinating and fertile area for experimentation, research, and
+development, but not something that one can become deeply enthusiastic
+about committing to production systems at this time.
+
+This situation will change, LYNCH said. He differentiated CD-ROM from
+the practices that have been followed up to now in distributing data on
+CD-ROM. For LYNCH the problem with CD-ROM is not its portability or its
+slowness but the two-edged sword of having the retrieval application and
+the user interface inextricably bound up with the data, which is the
+typical CD-ROM publication model. It is not a case of publishing data
+but of distributing a typically stand-alone, typically closed system,
+all--software, user interface, and data--on a little disk. Hence, all
+the between-disk navigational issues as well as the impossibility in most
+cases of integrating data on one disk with that on another. Most CD-ROM
+retrieval software does not network very gracefully at present. However,
+in the present world of immature standards and lack of understanding of
+what network information is or what the ground rules are for creating or
+using it, publishing information on a CD-ROM does add value in a very
+real sense.
+
+LYNCH drew a contrast between CD-ROM and network pricing and in doing so
+highlighted something bizarre in information pricing. A large
+institution such as the University of California has vendors who will
+offer to sell information on CD-ROM for a price per year in four digits,
+but for the same data (e.g., an abstracting and indexing database) on
+magnetic tape, regardless of how many people may use it concurrently,
+will quote a price in six digits.
+
+What is packaged with the CD-ROM in one sense adds value--a complete
+access system, not just raw, unrefined information--although it is not
+generally perceived that way. This is because the access software,
+although it adds value, is viewed by some people, particularly in the
+university environment where there is a very heavy commitment to
+networking, as being developed in the wrong direction.
+
+Given that context, LYNCH described the examples demonstrated as a set of
+insular information gems--Perseus, for example, offers nicely linked
+information, but would be very difficult to integrate with other
+databases, that is, to link together seamlessly with other source files
+from other sources. It resembles an island, and in this respect is
+similar to numerous stand-alone projects that are based on videodiscs,
+that is, on the single-workstation concept.
+
+As scholarship evolves in a network environment, the paramount need will
+be to link databases. We must link personal databases to public
+databases, to group databases, in fairly seamless ways--which is
+extremely difficult in the environments under discussion with copies of
+databases proliferating all over the place.
+
+The notion of layering also struck LYNCH as lurking in several of the
+projects demonstrated. Several databases in a sense constitute
+information archives without a significant amount of navigation built in.
+Educators, critics, and others will want a layered structure--one that
+defines or links paths through the layers to allow users to reach
+specific points. In LYNCH's view, layering will become increasingly
+necessary, and not just within a single resource but across resources
+(e.g., tracing mythology and cultural themes across several classics
+databases as well as a database of Renaissance culture). This ability to
+organize resources, to build things out of multiple other things on the
+network or select pieces of it, represented for LYNCH one of the key
+aspects of network information.
+
+Contending that information reuse constituted another significant issue,
+LYNCH commended to the audience's attention Project NEEDS (i.e., National
+Engineering Education Delivery System). This project's objective is to
+produce a database of engineering courseware as well as the components
+that can be used to develop new courseware. In a number of the existing
+applications, LYNCH said, the issue of reuse (how much one can take apart
+and reuse in other applications) was not being well considered. He also
+raised the issue of active versus passive use, one aspect of which is
+how much information will be manipulated locally by users. Most people,
+he argued, may do a little browsing and then will wish to print. LYNCH
+was uncertain how these resources would be used by the vast majority of
+users in the network environment.
+
+LYNCH next said a few words about X-Windows as a way of differentiating
+between network access and networked information. A number of the
+applications demonstrated at the Workshop could be rewritten to use X
+across the network, so that one could run them from any X-capable device-
+-a workstation, an X terminal--and transact with a database across the
+network. Although this opens up access a little, assuming one has enough
+network to handle it, it does not provide an interface to develop a
+program that conveniently integrates information from multiple databases.
+X is a viewing technology that has limits. In a real sense, it is just a
+graphical version of remote log-in across the network. X-type applications
+represent only one step in the progression towards real access.
+
+LYNCH next discussed barriers to the distribution of networked multimedia
+information. The heart of the problem is a lack of standards to provide
+the ability for computers to talk to each other, retrieve information,
+and shuffle it around fairly casually. At the moment, little progress is
+being made on standards for networked information; for example, present
+standards do not cover images, digital voice, and digital video. A
+useful tool kit of exchange formats for basic texts is only now being
+assembled. The synchronization of content streams (i.e., synchronizing a
+voice track to a video track, establishing temporal relations between
+different components in a multimedia object) constitutes another issue
+for networked multimedia that is just beginning to receive attention.
+
+Underlying network protocols also need some work; good, real-time
+delivery protocols on the Internet do not yet exist. In LYNCH's view,
+highly important in this context is the notion of networked digital
+object IDs, the ability of one object on the network to point to another
+object (or component thereof) on the network. Serious bandwidth issues
+also exist. LYNCH was uncertain if billion-bit-per-second networks would
+prove sufficient if numerous people ran video in parallel.
+
+LYNCH concluded by offering an issue for database creators to consider,
+as well as several comments about what might constitute good trial
+multimedia experiments. In a networked information world the database
+builder or service builder (publisher) does not exercise the same
+extensive control over the integrity of the presentation; strange
+programs "munge" with one's data before the user sees it. Serious
+thought must be given to what guarantees integrity of presentation. Part
+of that is related to where one draws the boundaries around a networked
+information service. This question of presentation integrity in
+client-server computing has not been stressed enough in the academic
+world, LYNCH argued, though commercial service providers deal with it
+regularly.
+
+Concerning multimedia, LYNCH observed that good multimedia at the moment
+is hideously expensive to produce. He recommended producing multimedia
+with either very high sale value, or multimedia with a very long life
+span, or multimedia that will have a very broad usage base and whose
+costs therefore can be amortized among large numbers of users. In this
+connection, historical and humanistically oriented material may be a good
+place to start, because it tends to have a longer life span than much of
+the scientific material, as well as a wider user base. LYNCH noted, for
+example, that American Memory fits many of the criteria outlined. He
+remarked the extensive discussion about bringing the Internet or the
+National Research and Education Network (NREN) into the K-12 environment
+as a way of helping the American educational system.
+
+LYNCH closed by noting that the kinds of applications demonstrated struck
+him as excellent justifications of broad-scale networking for K-12, but
+that at this time no "killer" application exists to mobilize the K-12
+community to obtain connectivity.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Dearth of genuinely interesting applications on the network
+a slow-changing situation * The issue of the integrity of presentation in
+a networked environment * Several reasons why CD-ROM software does not
+network *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the discussion period that followed LYNCH's presentation, several
+additional points were made.
+
+LYNCH reiterated even more strongly his contention that, historically,
+once one goes outside high-end science and the group of those who need
+access to supercomputers, there is a great dearth of genuinely
+interesting applications on the network. He saw this situation changing
+slowly, with some of the scientific databases and scholarly discussion
+groups and electronic journals coming on as well as with the availability
+of Wide Area Information Servers (WAIS) and some of the databases that
+are being mounted there. However, many of those things do not seem to
+have piqued great popular interest. For instance, most high school
+students of LYNCH's acquaintance would not qualify as devotees of serious
+molecular biology.
+
+Concerning the issue of the integrity of presentation, LYNCH believed
+that a couple of information providers have laid down the law at least on
+certain things. For example, his recollection was that the National
+Library of Medicine feels strongly that one needs to employ the
+identifier field if he or she is to mount a database commercially. The
+problem with a real networked environment is that one does not know who
+is reformatting and reprocessing one's data when one enters a client
+server mode. It becomes anybody's guess, for example, if the network
+uses a Z39.50 server, or what clients are doing with one's data. A data
+provider can say that his contract will only permit clients to have
+access to his data after he vets them and their presentation and makes
+certain it suits him. But LYNCH held out little expectation that the
+network marketplace would evolve in that way, because it required too
+much prior negotiation.
+
+CD-ROM software does not network for a variety of reasons, LYNCH said.
+He speculated that CD-ROM publishers are not eager to have their products
+really hook into wide area networks, because they fear it will make their
+data suppliers nervous. Moreover, until relatively recently, one had to
+be rather adroit to run a full TCP/IP stack plus applications on a
+PC-size machine, whereas nowadays it is becoming easier as PCs grow
+bigger and faster. LYNCH also speculated that software providers had not
+heard from their customers until the last year or so, or had not heard
+from enough of their customers.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BESSER * Implications of disseminating images on the network; planning
+the distribution of multimedia documents poses two critical
+implementation problems * Layered approach represents the way to deal
+with users' capabilities * Problems in platform design; file size and its
+implications for networking * Transmission of megabyte size images
+impractical * Compression and decompression at the user's end * Promising
+trends for compression * A disadvantage of using X-Windows * A project at
+the Smithsonian that mounts images on several networks *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Howard BESSER, School of Library and Information Science, University of
+Pittsburgh, spoke primarily about multimedia, focusing on images and the
+broad implications of disseminating them on the network. He argued that
+planning the distribution of multimedia documents posed two critical
+implementation problems, which he framed in the form of two questions:
+1) What platform will one use and what hardware and software will users
+have for viewing of the material? and 2) How can one deliver a
+sufficiently robust set of information in an accessible format in a
+reasonable amount of time? Depending on whether network or CD-ROM is the
+medium used, this question raises different issues of storage,
+compression, and transmission.
+
+Concerning the design of platforms (e.g., sound, gray scale, simple
+color, etc.) and the various capabilities users may have, BESSER
+maintained that a layered approach was the way to deal with users'
+capabilities. A result would be that users with less powerful
+workstations would simply have less functionality. He urged members of
+the audience to advocate standards and accompanying software that handle
+layered functionality across a wide variety of platforms.
+
+BESSER also addressed problems in platform design, namely, deciding how
+large a machine to design for situations when the largest number of users
+have the lowest level of the machine, and one desires higher
+functionality. BESSER then proceeded to the question of file size and
+its implications for networking. He discussed still images in the main.
+For example, a digital color image that fills the screen of a standard
+mega-pel workstation (Sun or Next) will require one megabyte of storage
+for an eight-bit image or three megabytes of storage for a true color or
+twenty-four-bit image. Lossless compression algorithms (that is,
+computational procedures in which no data is lost in the process of
+compressing [and decompressing] an image--the exact bit-representation is
+maintained) might bring storage down to a third of a megabyte per image,
+but not much further than that. The question of size makes it difficult
+to fit an appropriately sized set of these images on a single disk or to
+transmit them quickly enough on a network.
+
+With these full screen mega-pel images that constitute a third of a
+megabyte, one gets 1,000-3,000 full-screen images on a one-gigabyte disk;
+a standard CD-ROM represents approximately 60 percent of that. Storing
+images the size of a PC screen (just 8 bit color) increases storage
+capacity to 4,000-12,000 images per gigabyte; 60 percent of that gives
+one the size of a CD-ROM, which in turn creates a major problem. One
+cannot have full-screen, full-color images with lossless compression; one
+must compress them or use a lower resolution. For megabyte-size images,
+anything slower than a T-1 speed is impractical. For example, on a
+fifty-six-kilobaud line, it takes three minutes to transfer a
+one-megabyte file, if it is not compressed; and this speed assumes ideal
+circumstances (no other user contending for network bandwidth). Thus,
+questions of disk access, remote display, and current telephone
+connection speed make transmission of megabyte-size images impractical.
+
+BESSER then discussed ways to deal with these large images, for example,
+compression and decompression at the user's end. In this connection, the
+issues of how much one is willing to lose in the compression process and
+what image quality one needs in the first place are unknown. But what is
+known is that compression entails some loss of data. BESSER urged that
+more studies be conducted on image quality in different situations, for
+example, what kind of images are needed for what kind of disciplines, and
+what kind of image quality is needed for a browsing tool, an intermediate
+viewing tool, and archiving.
+
+BESSER remarked two promising trends for compression: from a technical
+perspective, algorithms that use what is called subjective redundancy
+employ principles from visual psycho-physics to identify and remove
+information from the image that the human eye cannot perceive; from an
+interchange and interoperability perspective, the JPEG (i.e., Joint
+Photographic Experts Group, an ISO standard) compression algorithms also
+offer promise. These issues of compression and decompression, BESSER
+argued, resembled those raised earlier concerning the design of different
+platforms. Gauging the capabilities of potential users constitutes a
+primary goal. BESSER advocated layering or separating the images from
+the applications that retrieve and display them, to avoid tying them to
+particular software.
+
+BESSER detailed several lessons learned from his work at Berkeley with
+Imagequery, especially the advantages and disadvantages of using
+X-Windows. In the latter category, for example, retrieval is tied
+directly to one's data, an intolerable situation in the long run on a
+networked system. Finally, BESSER described a project of Jim Wallace at
+the Smithsonian Institution, who is mounting images in a extremely
+rudimentary way on the Compuserv and Genie networks and is preparing to
+mount them on America On Line. Although the average user takes over
+thirty minutes to download these images (assuming a fairly fast modem),
+nevertheless, images have been downloaded 25,000 times.
+
+BESSER concluded his talk with several comments on the business
+arrangement between the Smithsonian and Compuserv. He contended that not
+enough is known concerning the value of images.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Creating digitized photographic collections nearly
+impossible except with large organizations like museums * Need for study
+to determine quality of images users will tolerate *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the brief exchange between LESK and BESSER that followed, several
+clarifications emerged.
+
+LESK argued that the photographers were far ahead of BESSER: It is
+almost impossible to create such digitized photographic collections
+except with large organizations like museums, because all the
+photographic agencies have been going crazy about this and will not sign
+licensing agreements on any sort of reasonable terms. LESK had heard
+that National Geographic, for example, had tried to buy the right to use
+some image in some kind of educational production for $100 per image, but
+the photographers will not touch it. They want accounting and payment
+for each use, which cannot be accomplished within the system. BESSER
+responded that a consortium of photographers, headed by a former National
+Geographic photographer, had started assembling its own collection of
+electronic reproductions of images, with the money going back to the
+cooperative.
+
+LESK contended that BESSER was unnecessarily pessimistic about multimedia
+images, because people are accustomed to low-quality images, particularly
+from video. BESSER urged the launching of a study to determine what
+users would tolerate, what they would feel comfortable with, and what
+absolutely is the highest quality they would ever need. Conceding that
+he had adopted a dire tone in order to arouse people about the issue,
+BESSER closed on a sanguine note by saying that he would not be in this
+business if he did not think that things could be accomplished.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LARSEN * Issues of scalability and modularity * Geometric growth of the
+Internet and the role played by layering * Basic functions sustaining
+this growth * A library's roles and functions in a network environment *
+Effects of implementation of the Z39.50 protocol for information
+retrieval on the library system * The trade-off between volumes of data
+and its potential usage * A snapshot of current trends *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Ronald LARSEN, associate director for information technology, University
+of Maryland at College Park, first addressed the issues of scalability
+and modularity. He noted the difficulty of anticipating the effects of
+orders-of-magnitude growth, reflecting on the twenty years of experience
+with the Arpanet and Internet. Recalling the day's demonstrations of
+CD-ROM and optical disk material, he went on to ask if the field has yet
+learned how to scale new systems to enable delivery and dissemination
+across large-scale networks.
+
+LARSEN focused on the geometric growth of the Internet from its inception
+circa 1969 to the present, and the adjustments required to respond to
+that rapid growth. To illustrate the issue of scalability, LARSEN
+considered computer networks as including three generic components:
+computers, network communication nodes, and communication media. Each
+component scales (e.g., computers range from PCs to supercomputers;
+network nodes scale from interface cards in a PC through sophisticated
+routers and gateways; and communication media range from 2,400-baud
+dial-up facilities through 4.5-Mbps backbone links, and eventually to
+multigigabit-per-second communication lines), and architecturally, the
+components are organized to scale hierarchically from local area networks
+to international-scale networks. Such growth is made possible by
+building layers of communication protocols, as BESSER pointed out.
+By layering both physically and logically, a sense of scalability is
+maintained from local area networks in offices, across campuses, through
+bridges, routers, campus backbones, fiber-optic links, etc., up into
+regional networks and ultimately into national and international
+networks.
+
+LARSEN then illustrated the geometric growth over a two-year period--
+through September 1991--of the number of networks that comprise the
+Internet. This growth has been sustained largely by the availability of
+three basic functions: electronic mail, file transfer (ftp), and remote
+log-on (telnet). LARSEN also reviewed the growth in the kind of traffic
+that occurs on the network. Network traffic reflects the joint contributions
+of a larger population of users and increasing use per user. Today one sees
+serious applications involving moving images across the network--a rarity
+ten years ago. LARSEN recalled and concurred with BESSER's main point
+that the interesting problems occur at the application level.
+
+LARSEN then illustrated a model of a library's roles and functions in a
+network environment. He noted, in particular, the placement of on-line
+catalogues onto the network and patrons obtaining access to the library
+increasingly through local networks, campus networks, and the Internet.
+LARSEN supported LYNCH's earlier suggestion that we need to address
+fundamental questions of networked information in order to build
+environments that scale in the information sense as well as in the
+physical sense.
+
+LARSEN supported the role of the library system as the access point into
+the nation's electronic collections. Implementation of the Z39.50
+protocol for information retrieval would make such access practical and
+feasible. For example, this would enable patrons in Maryland to search
+California libraries, or other libraries around the world that are
+conformant with Z39.50 in a manner that is familiar to University of
+Maryland patrons. This client-server model also supports moving beyond
+secondary content into primary content. (The notion of how one links
+from secondary content to primary content, LARSEN said, represents a
+fundamental problem that requires rigorous thought.) After noting
+numerous network experiments in accessing full-text materials, including
+projects supporting the ordering of materials across the network, LARSEN
+revisited the issue of transmitting high-density, high-resolution color
+images across the network and the large amounts of bandwidth they
+require. He went on to address the bandwidth and synchronization
+problems inherent in sending full-motion video across the network.
+
+LARSEN illustrated the trade-off between volumes of data in bytes or
+orders of magnitude and the potential usage of that data. He discussed
+transmission rates (particularly, the time it takes to move various forms
+of information), and what one could do with a network supporting
+multigigabit-per-second transmission. At the moment, the network
+environment includes a composite of data-transmission requirements,
+volumes and forms, going from steady to bursty (high-volume) and from
+very slow to very fast. This aggregate must be considered in the design,
+construction, and operation of multigigabyte networks.
+
+LARSEN's objective is to use the networks and library systems now being
+constructed to increase access to resources wherever they exist, and
+thus, to evolve toward an on-line electronic virtual library.
+
+LARSEN concluded by offering a snapshot of current trends: continuing
+geometric growth in network capacity and number of users; slower
+development of applications; and glacial development and adoption of
+standards. The challenge is to design and develop each new application
+system with network access and scalability in mind.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BROWNRIGG * Access to the Internet cannot be taken for granted * Packet
+radio and the development of MELVYL in 1980-81 in the Division of Library
+Automation at the University of California * Design criteria for packet
+radio * A demonstration project in San Diego and future plans * Spread
+spectrum * Frequencies at which the radios will run and plans to
+reimplement the WAIS server software in the public domain * Need for an
+infrastructure of radios that do not move around *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Edwin BROWNRIGG, executive director, Memex Research Institute, first
+polled the audience in order to seek out regular users of the Internet as
+well as those planning to use it some time in the future. With nearly
+everybody in the room falling into one category or the other, BROWNRIGG
+made a point re access, namely that numerous individuals, especially those
+who use the Internet every day, take for granted their access to it, the
+speeds with which they are connected, and how well it all works.
+However, as BROWNRIGG discovered between 1987 and 1989 in Australia,
+if one wants access to the Internet but cannot afford it or has some
+physical boundary that prevents her or him from gaining access, it can
+be extremely frustrating. He suggested that because of economics and
+physical barriers we were beginning to create a world of haves and have-nots
+in the process of scholarly communication, even in the United States.
+
+BROWNRIGG detailed the development of MELVYL in academic year 1980-81 in
+the Division of Library Automation at the University of California, in
+order to underscore the issue of access to the system, which at the
+outset was extremely limited. In short, the project needed to build a
+network, which at that time entailed use of satellite technology, that is,
+putting earth stations on campus and also acquiring some terrestrial links
+from the State of California's microwave system. The installation of
+satellite links, however, did not solve the problem (which actually
+formed part of a larger problem involving politics and financial resources).
+For while the project team could get a signal onto a campus, it had no means
+of distributing the signal throughout the campus. The solution involved
+adopting a recent development in wireless communication called packet radio,
+which combined the basic notion of packet-switching with radio. The project
+used this technology to get the signal from a point on campus where it
+came down, an earth station for example, into the libraries, because it
+found that wiring the libraries, especially the older marble buildings,
+would cost $2,000-$5,000 per terminal.
+
+BROWNRIGG noted that, ten years ago, the project had neither the public
+policy nor the technology that would have allowed it to use packet radio
+in any meaningful way. Since then much had changed. He proceeded to
+detail research and development of the technology, how it is being
+deployed in California, and what direction he thought it would take.
+The design criteria are to produce a high-speed, one-time, low-cost,
+high-quality, secure, license-free device (packet radio) that one can
+plug in and play today, forget about it, and have access to the Internet.
+By high speed, BROWNRIGG meant 1 megabyte and 1.5 megabytes. Those units
+have been built, he continued, and are in the process of being
+type-certified by an independent underwriting laboratory so that they can
+be type-licensed by the Federal Communications Commission. As is the
+case with citizens band, one will be able to purchase a unit and not have
+to worry about applying for a license.
+
+The basic idea, BROWNRIGG elaborated, is to take high-speed radio data
+transmission and create a backbone network that at certain strategic
+points in the network will "gateway" into a medium-speed packet radio
+(i.e., one that runs at 38.4 kilobytes), so that perhaps by 1994-1995
+people, like those in the audience for the price of a VCR could purchase
+a medium-speed radio for the office or home, have full network connectivity
+to the Internet, and partake of all its services, with no need for an FCC
+license and no regular bill from the local common carrier. BROWNRIGG
+presented several details of a demonstration project currently taking
+place in San Diego and described plans, pending funding, to install a
+full-bore network in the San Francisco area. This network will have 600
+nodes running at backbone speeds, and 100 of these nodes will be libraries,
+which in turn will be the gateway ports to the 38.4 kilobyte radios that
+will give coverage for the neighborhoods surrounding the libraries.
+
+BROWNRIGG next explained Part 15.247, a new rule within Title 47 of the
+Code of Federal Regulations enacted by the FCC in 1985. This rule
+challenged the industry, which has only now risen to the occasion, to
+build a radio that would run at no more than one watt of output power and
+use a fairly exotic method of modulating the radio wave called spread
+spectrum. Spread spectrum in fact permits the building of networks so
+that numerous data communications can occur simultaneously, without
+interfering with each other, within the same wide radio channel.
+
+BROWNRIGG explained that the frequencies at which the radios would run
+are very short wave signals. They are well above standard microwave and
+radar. With a radio wave that small, one watt becomes a tremendous punch
+per bit and thus makes transmission at reasonable speed possible. In
+order to minimize the potential for congestion, the project is
+undertaking to reimplement software which has been available in the
+networking business and is taken for granted now, for example, TCP/IP,
+routing algorithms, bridges, and gateways. In addition, the project
+plans to take the WAIS server software in the public domain and
+reimplement it so that one can have a WAIS server on a Mac instead of a
+Unix machine. The Memex Research Institute believes that libraries, in
+particular, will want to use the WAIS servers with packet radio. This
+project, which has a team of about twelve people, will run through 1993
+and will include the 100 libraries already mentioned as well as other
+professionals such as those in the medical profession, engineering, and
+law. Thus, the need is to create an infrastructure of radios that do not
+move around, which, BROWNRIGG hopes, will solve a problem not only for
+libraries but for individuals who, by and large today, do not have access
+to the Internet from their homes and offices.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Project operating frequencies *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During a brief discussion period, which also concluded the day's
+proceedings, BROWNRIGG stated that the project was operating in four
+frequencies. The slow speed is operating at 435 megahertz, and it would
+later go up to 920 megahertz. With the high-speed frequency, the
+one-megabyte radios will run at 2.4 gigabits, and 1.5 will run at 5.7.
+At 5.7, rain can be a factor, but it would have to be tropical rain,
+unlike what falls in most parts of the United States.
+
+ ******
+
+SESSION IV. IMAGE CAPTURE, TEXT CAPTURE, OVERVIEW OF TEXT AND
+ IMAGE STORAGE FORMATS
+
+William HOOTON, vice president of operations, I-NET, moderated this session.
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+KENNEY * Factors influencing development of CXP * Advantages of using
+digital technology versus photocopy and microfilm * A primary goal of
+CXP; publishing challenges * Characteristics of copies printed * Quality
+of samples achieved in image capture * Several factors to be considered
+in choosing scanning * Emphasis of CXP on timely and cost-effective
+production of black-and-white printed facsimiles * Results of producing
+microfilm from digital files * Advantages of creating microfilm * Details
+concerning production * Costs * Role of digital technology in library
+preservation *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Anne KENNEY, associate director, Department of Preservation and
+Conservation, Cornell University, opened her talk by observing that the
+Cornell Xerox Project (CXP) has been guided by the assumption that the
+ability to produce printed facsimiles or to replace paper with paper
+would be important, at least for the present generation of users and
+equipment. She described three factors that influenced development of
+the project: 1) Because the project has emphasized the preservation of
+deteriorating brittle books, the quality of what was produced had to be
+sufficiently high to return a paper replacement to the shelf. CXP was
+only interested in using: 2) a system that was cost-effective, which
+meant that it had to be cost-competitive with the processes currently
+available, principally photocopy and microfilm, and 3) new or currently
+available product hardware and software.
+
+KENNEY described the advantages that using digital technology offers over
+both photocopy and microfilm: 1) The potential exists to create a higher
+quality reproduction of a deteriorating original than conventional
+light-lens technology. 2) Because a digital image is an encoded
+representation, it can be reproduced again and again with no resulting
+loss of quality, as opposed to the situation with light-lens processes,
+in which there is discernible difference between a second and a
+subsequent generation of an image. 3) A digital image can be manipulated
+in a number of ways to improve image capture; for example, Xerox has
+developed a windowing application that enables one to capture a page
+containing both text and illustrations in a manner that optimizes the
+reproduction of both. (With light-lens technology, one must choose which
+to optimize, text or the illustration; in preservation microfilming, the
+current practice is to shoot an illustrated page twice, once to highlight
+the text and the second time to provide the best capture for the
+illustration.) 4) A digital image can also be edited, density levels
+adjusted to remove underlining and stains, and to increase legibility for
+faint documents. 5) On-screen inspection can take place at the time of
+initial setup and adjustments made prior to scanning, factors that
+substantially reduce the number of retakes required in quality control.
+
+A primary goal of CXP has been to evaluate the paper output printed on
+the Xerox DocuTech, a high-speed printer that produces 600-dpi pages from
+scanned images at a rate of 135 pages a minute. KENNEY recounted several
+publishing challenges to represent faithful and legible reproductions of
+the originals that the 600-dpi copy for the most part successfully
+captured. For example, many of the deteriorating volumes in the project
+were heavily illustrated with fine line drawings or halftones or came in
+languages such as Japanese, in which the buildup of characters comprised
+of varying strokes is difficult to reproduce at lower resolutions; a
+surprising number of them came with annotations and mathematical
+formulas, which it was critical to be able to duplicate exactly.
+
+KENNEY noted that 1) the copies are being printed on paper that meets the
+ANSI standards for performance, 2) the DocuTech printer meets the machine
+and toner requirements for proper adhesion of print to page, as described
+by the National Archives, and thus 3) paper product is considered to be
+the archival equivalent of preservation photocopy.
+
+KENNEY then discussed several samples of the quality achieved in the
+project that had been distributed in a handout, for example, a copy of a
+print-on-demand version of the 1911 Reed lecture on the steam turbine,
+which contains halftones, line drawings, and illustrations embedded in
+text; the first four loose pages in the volume compared the capture
+capabilities of scanning to photocopy for a standard test target, the
+IEEE standard 167A 1987 test chart. In all instances scanning proved
+superior to photocopy, though only slightly more so in one.
+
+Conceding the simplistic nature of her review of the quality of scanning
+to photocopy, KENNEY described it as one representation of the kinds of
+settings that could be used with scanning capabilities on the equipment
+CXP uses. KENNEY also pointed out that CXP investigated the quality
+achieved with binary scanning only, and noted the great promise in gray
+scale and color scanning, whose advantages and disadvantages need to be
+examined. She argued further that scanning resolutions and file formats
+can represent a complex trade-off between the time it takes to capture
+material, file size, fidelity to the original, and on-screen display; and
+printing and equipment availability. All these factors must be taken
+into consideration.
+
+CXP placed primary emphasis on the production in a timely and
+cost-effective manner of printed facsimiles that consisted largely of
+black-and-white text. With binary scanning, large files may be
+compressed efficiently and in a lossless manner (i.e., no data is lost in
+the process of compressing [and decompressing] an image--the exact
+bit-representation is maintained) using Group 4 CCITT (i.e., the French
+acronym for International Consultative Committee for Telegraph and
+Telephone) compression. CXP was getting compression ratios of about
+forty to one. Gray-scale compression, which primarily uses JPEG, is much
+less economical and can represent a lossy compression (i.e., not
+lossless), so that as one compresses and decompresses, the illustration
+is subtly changed. While binary files produce a high-quality printed
+version, it appears 1) that other combinations of spatial resolution with
+gray and/or color hold great promise as well, and 2) that gray scale can
+represent a tremendous advantage for on-screen viewing. The quality
+associated with binary and gray scale also depends on the equipment used.
+For instance, binary scanning produces a much better copy on a binary
+printer.
+
+Among CXP's findings concerning the production of microfilm from digital
+files, KENNEY reported that the digital files for the same Reed lecture
+were used to produce sample film using an electron beam recorder. The
+resulting film was faithful to the image capture of the digital files,
+and while CXP felt that the text and image pages represented in the Reed
+lecture were superior to that of the light-lens film, the resolution
+readings for the 600 dpi were not as high as standard microfilming.
+KENNEY argued that the standards defined for light-lens technology are
+not totally transferable to a digital environment. Moreover, they are
+based on definition of quality for a preservation copy. Although making
+this case will prove to be a long, uphill struggle, CXP plans to continue
+to investigate the issue over the course of the next year.
+
+KENNEY concluded this portion of her talk with a discussion of the
+advantages of creating film: it can serve as a primary backup and as a
+preservation master to the digital file; it could then become the print
+or production master and service copies could be paper, film, optical
+disks, magnetic media, or on-screen display.
+
+Finally, KENNEY presented details re production:
+
+ * Development and testing of a moderately-high resolution production
+ scanning workstation represented a third goal of CXP; to date, 1,000
+ volumes have been scanned, or about 300,000 images.
+
+ * The resulting digital files are stored and used to produce
+ hard-copy replacements for the originals and additional prints on
+ demand; although the initial costs are high, scanning technology
+ offers an affordable means for reformatting brittle material.
+
+ * A technician in production mode can scan 300 pages per hour when
+ performing single-sheet scanning, which is a necessity when working
+ with truly brittle paper; this figure is expected to increase
+ significantly with subsequent iterations of the software from Xerox;
+ a three-month time-and-cost study of scanning found that the average
+ 300-page book would take about an hour and forty minutes to scan
+ (this figure included the time for setup, which involves keying in
+ primary bibliographic data, going into quality control mode to
+ define page size, establishing front-to-back registration, and
+ scanning sample pages to identify a default range of settings for
+ the entire book--functions not dissimilar to those performed by
+ filmers or those preparing a book for photocopy).
+
+ * The final step in the scanning process involved rescans, which
+ happily were few and far between, representing well under 1 percent
+ of the total pages scanned.
+
+In addition to technician time, CXP costed out equipment, amortized over
+four years, the cost of storing and refreshing the digital files every
+four years, and the cost of printing and binding, book-cloth binding, a
+paper reproduction. The total amounted to a little under $65 per single
+300-page volume, with 30 percent overhead included--a figure competitive
+with the prices currently charged by photocopy vendors.
+
+Of course, with scanning, in addition to the paper facsimile, one is left
+with a digital file from which subsequent copies of the book can be
+produced for a fraction of the cost of photocopy, with readers afforded
+choices in the form of these copies.
+
+KENNEY concluded that digital technology offers an electronic means for a
+library preservation effort to pay for itself. If a brittle-book program
+included the means of disseminating reprints of books that are in demand
+by libraries and researchers alike, the initial investment in capture
+could be recovered and used to preserve additional but less popular
+books. She disclosed that an economic model for a self-sustaining
+program could be developed for CXP's report to the Commission on
+Preservation and Access (CPA).
+
+KENNEY stressed that the focus of CXP has been on obtaining high quality
+in a production environment. The use of digital technology is viewed as
+an affordable alternative to other reformatting options.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ANDRE * Overview and history of NATDP * Various agricultural CD-ROM
+products created inhouse and by service bureaus * Pilot project on
+Internet transmission * Additional products in progress *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Pamela ANDRE, associate director for automation, National Agricultural
+Text Digitizing Program (NATDP), National Agricultural Library (NAL),
+presented an overview of NATDP, which has been underway at NAL the last
+four years, before Judith ZIDAR discussed the technical details. ANDRE
+defined agricultural information as a broad range of material going from
+basic and applied research in the hard sciences to the one-page pamphlets
+that are distributed by the cooperative state extension services on such
+things as how to grow blueberries.
+
+NATDP began in late 1986 with a meeting of representatives from the
+land-grant library community to deal with the issue of electronic
+information. NAL and forty-five of these libraries banded together to
+establish this project--to evaluate the technology for converting what
+were then source documents in paper form into electronic form, to provide
+access to that digital information, and then to distribute it.
+Distributing that material to the community--the university community as
+well as the extension service community, potentially down to the county
+level--constituted the group's chief concern.
+
+Since January 1988 (when the microcomputer-based scanning system was
+installed at NAL), NATDP has done a variety of things, concerning which
+ZIDAR would provide further details. For example, the first technology
+considered in the project's discussion phase was digital videodisc, which
+indicates how long ago it was conceived.
+
+Over the four years of this project, four separate CD-ROM products on
+four different agricultural topics were created, two at a
+scanning-and-OCR station installed at NAL, and two by service bureaus.
+Thus, NATDP has gained comparative information in terms of those relative
+costs. Each of these products contained the full ASCII text as well as
+page images of the material, or between 4,000 and 6,000 pages of material
+on these disks. Topics included aquaculture, food, agriculture and
+science (i.e., international agriculture and research), acid rain, and
+Agent Orange, which was the final product distributed (approximately
+eighteen months before the Workshop).
+
+The third phase of NATDP focused on delivery mechanisms other than
+CD-ROM. At the suggestion of Clifford LYNCH, who was a technical
+consultant to the project at this point, NATDP became involved with the
+Internet and initiated a project with the help of North Carolina State
+University, in which fourteen of the land-grant university libraries are
+transmitting digital images over the Internet in response to interlibrary
+loan requests--a topic for another meeting. At this point, the pilot
+project had been completed for about a year and the final report would be
+available shortly after the Workshop. In the meantime, the project's
+success had led to its extension. (ANDRE noted that one of the first
+things done under the program title was to select a retrieval package to
+use with subsequent products; Windows Personal Librarian was the package
+of choice after a lengthy evaluation.)
+
+Three additional products had been planned and were in progress:
+
+ 1) An arrangement with the American Society of Agronomy--a
+ professional society that has published the Agronomy Journal since
+ about 1908--to scan and create bit-mapped images of its journal.
+ ASA granted permission first to put and then to distribute this
+ material in electronic form, to hold it at NAL, and to use these
+ electronic images as a mechanism to deliver documents or print out
+ material for patrons, among other uses. Effectively, NAL has the
+ right to use this material in support of its program.
+ (Significantly, this arrangement offers a potential cooperative
+ model for working with other professional societies in agriculture
+ to try to do the same thing--put the journals of particular interest
+ to agriculture research into electronic form.)
+
+ 2) An extension of the earlier product on aquaculture.
+
+ 3) The George Washington Carver Papers--a joint project with
+ Tuskegee University to scan and convert from microfilm some 3,500
+ images of Carver's papers, letters, and drawings.
+
+It was anticipated that all of these products would appear no more than
+six months after the Workshop.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ZIDAR * (A separate arena for scanning) * Steps in creating a database *
+Image capture, with and without performing OCR * Keying in tracking data
+* Scanning, with electronic and manual tracking * Adjustments during
+scanning process * Scanning resolutions * Compression * De-skewing and
+filtering * Image capture from microform: the papers and letters of
+George Washington Carver * Equipment used for a scanning system *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Judith ZIDAR, coordinator, National Agricultural Text Digitizing Program
+(NATDP), National Agricultural Library (NAL), illustrated the technical
+details of NATDP, including her primary responsibility, scanning and
+creating databases on a topic and putting them on CD-ROM.
+
+(ZIDAR remarked a separate arena from the CD-ROM projects, although the
+processing of the material is nearly identical, in which NATDP is also
+scanning material and loading it on a Next microcomputer, which in turn
+is linked to NAL's integrated library system. Thus, searches in NAL's
+bibliographic database will enable people to pull up actual page images
+and text for any documents that have been entered.)
+
+In accordance with the session's topic, ZIDAR focused her illustrated
+talk on image capture, offering a primer on the three main steps in the
+process: 1) assemble the printed publications; 2) design the database
+(database design occurs in the process of preparing the material for
+scanning; this step entails reviewing and organizing the material,
+defining the contents--what will constitute a record, what kinds of
+fields will be captured in terms of author, title, etc.); 3) perform a
+certain amount of markup on the paper publications. NAL performs this
+task record by record, preparing work sheets or some other sort of
+tracking material and designing descriptors and other enhancements to be
+added to the data that will not be captured from the printed publication.
+Part of this process also involves determining NATDP's file and directory
+structure: NATDP attempts to avoid putting more than approximately 100
+images in a directory, because placing more than that on a CD-ROM would
+reduce the access speed.
+
+This up-front process takes approximately two weeks for a
+6,000-7,000-page database. The next step is to capture the page images.
+How long this process takes is determined by the decision whether or not
+to perform OCR. Not performing OCR speeds the process, whereas text
+capture requires greater care because of the quality of the image: it
+has to be straighter and allowance must be made for text on a page, not
+just for the capture of photographs.
+
+NATDP keys in tracking data, that is, a standard bibliographic record
+including the title of the book and the title of the chapter, which will
+later either become the access information or will be attached to the
+front of a full-text record so that it is searchable.
+
+Images are scanned from a bound or unbound publication, chiefly from
+bound publications in the case of NATDP, however, because often they are
+the only copies and the publications are returned to the shelves. NATDP
+usually scans one record at a time, because its database tracking system
+tracks the document in that way and does not require further logical
+separating of the images. After performing optical character
+recognition, NATDP moves the images off the hard disk and maintains a
+volume sheet. Though the system tracks electronically, all the
+processing steps are also tracked manually with a log sheet.
+
+ZIDAR next illustrated the kinds of adjustments that one can make when
+scanning from paper and microfilm, for example, redoing images that need
+special handling, setting for dithering or gray scale, and adjusting for
+brightness or for the whole book at one time.
+
+NATDP is scanning at 300 dots per inch, a standard scanning resolution.
+Though adequate for capturing text that is all of a standard size, 300
+dpi is unsuitable for any kind of photographic material or for very small
+text. Many scanners allow for different image formats, TIFF, of course,
+being a de facto standard. But if one intends to exchange images with
+other people, the ability to scan other image formats, even if they are
+less common, becomes highly desirable.
+
+CCITT Group 4 is the standard compression for normal black-and-white
+images, JPEG for gray scale or color. ZIDAR recommended 1) using the
+standard compressions, particularly if one attempts to make material
+available and to allow users to download images and reuse them from
+CD-ROMs; and 2) maintaining the ability to output an uncompressed image,
+because in image exchange uncompressed images are more likely to be able
+to cross platforms.
+
+ZIDAR emphasized the importance of de-skewing and filtering as
+requirements on NATDP's upgraded system. For instance, scanning bound
+books, particularly books published by the federal government whose pages
+are skewed, and trying to scan them straight if OCR is to be performed,
+is extremely time-consuming. The same holds for filtering of
+poor-quality or older materials.
+
+ZIDAR described image capture from microform, using as an example three
+reels from a sixty-seven-reel set of the papers and letters of George
+Washington Carver that had been produced by Tuskegee University. These
+resulted in approximately 3,500 images, which NATDP had had scanned by
+its service contractor, Science Applications International Corporation
+(SAIC). NATDP also created bibliographic records for access. (NATDP did
+not have such specialized equipment as a microfilm scanner.
+
+Unfortunately, the process of scanning from microfilm was not an
+unqualified success, ZIDAR reported: because microfilm frame sizes vary,
+occasionally some frames were missed, which without spending much time
+and money could not be recaptured.
+
+OCR could not be performed from the scanned images of the frames. The
+bleeding in the text simply output text, when OCR was run, that could not
+even be edited. NATDP tested for negative versus positive images,
+landscape versus portrait orientation, and single- versus dual-page
+microfilm, none of which seemed to affect the quality of the image; but
+also on none of them could OCR be performed.
+
+In selecting the microfilm they would use, therefore, NATDP had other
+factors in mind. ZIDAR noted two factors that influenced the quality of
+the images: 1) the inherent quality of the original and 2) the amount of
+size reduction on the pages.
+
+The Carver papers were selected because they are informative and visually
+interesting, treat a single subject, and are valuable in their own right.
+The images were scanned and divided into logical records by SAIC, then
+delivered, and loaded onto NATDP's system, where bibliographic
+information taken directly from the images was added. Scanning was
+completed in summer 1991 and by the end of summer 1992 the disk was
+scheduled to be published.
+
+Problems encountered during processing included the following: Because
+the microfilm scanning had to be done in a batch, adjustment for
+individual page variations was not possible. The frame size varied on
+account of the nature of the material, and therefore some of the frames
+were missed while others were just partial frames. The only way to go
+back and capture this material was to print out the page with the
+microfilm reader from the missing frame and then scan it in from the
+page, which was extremely time-consuming. The quality of the images
+scanned from the printout of the microfilm compared unfavorably with that
+of the original images captured directly from the microfilm. The
+inability to perform OCR also was a major disappointment. At the time,
+computer output microfilm was unavailable to test.
+
+The equipment used for a scanning system was the last topic addressed by
+ZIDAR. The type of equipment that one would purchase for a scanning
+system included: a microcomputer, at least a 386, but preferably a 486;
+a large hard disk, 380 megabyte at minimum; a multi-tasking operating
+system that allows one to run some things in batch in the background
+while scanning or doing text editing, for example, Unix or OS/2 and,
+theoretically, Windows; a high-speed scanner and scanning software that
+allows one to make the various adjustments mentioned earlier; a
+high-resolution monitor (150 dpi ); OCR software and hardware to perform
+text recognition; an optical disk subsystem on which to archive all the
+images as the processing is done; file management and tracking software.
+
+ZIDAR opined that the software one purchases was more important than the
+hardware and might also cost more than the hardware, but it was likely to
+prove critical to the success or failure of one's system. In addition to
+a stand-alone scanning workstation for image capture, then, text capture
+requires one or two editing stations networked to this scanning station
+to perform editing. Editing the text takes two or three times as long as
+capturing the images.
+
+Finally, ZIDAR stressed the importance of buying an open system that allows
+for more than one vendor, complies with standards, and can be upgraded.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+WATERS *Yale University Library's master plan to convert microfilm to
+digital imagery (POB) * The place of electronic tools in the library of
+the future * The uses of images and an image library * Primary input from
+preservation microfilm * Features distinguishing POB from CXP and key
+hypotheses guiding POB * Use of vendor selection process to facilitate
+organizational work * Criteria for selecting vendor * Finalists and
+results of process for Yale * Key factor distinguishing vendors *
+Components, design principles, and some estimated costs of POB * Role of
+preservation materials in developing imaging market * Factors affecting
+quality and cost * Factors affecting the usability of complex documents
+in image form *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Donald WATERS, head of the Systems Office, Yale University Library,
+reported on the progress of a master plan for a project at Yale to
+convert microfilm to digital imagery, Project Open Book (POB). Stating
+that POB was in an advanced stage of planning, WATERS detailed, in
+particular, the process of selecting a vendor partner and several key
+issues under discussion as Yale prepares to move into the project itself.
+He commented first on the vision that serves as the context of POB and
+then described its purpose and scope.
+
+WATERS sees the library of the future not necessarily as an electronic
+library but as a place that generates, preserves, and improves for its
+clients ready access to both intellectual and physical recorded
+knowledge. Electronic tools must find a place in the library in the
+context of this vision. Several roles for electronic tools include
+serving as: indirect sources of electronic knowledge or as "finding"
+aids (the on-line catalogues, the article-level indices, registers for
+documents and archives); direct sources of recorded knowledge; full-text
+images; and various kinds of compound sources of recorded knowledge (the
+so-called compound documents of Hypertext, mixed text and image,
+mixed-text image format, and multimedia).
+
+POB is looking particularly at images and an image library, the uses to
+which images will be put (e.g., storage, printing, browsing, and then use
+as input for other processes), OCR as a subsequent process to image
+capture, or creating an image library, and also possibly generating
+microfilm.
+
+While input will come from a variety of sources, POB is considering
+especially input from preservation microfilm. A possible outcome is that
+the film and paper which provide the input for the image library
+eventually may go off into remote storage, and that the image library may
+be the primary access tool.
+
+The purpose and scope of POB focus on imaging. Though related to CXP,
+POB has two features which distinguish it: 1) scale--conversion of
+10,000 volumes into digital image form; and 2) source--conversion from
+microfilm. Given these features, several key working hypotheses guide
+POB, including: 1) Since POB is using microfilm, it is not concerned with
+the image library as a preservation medium. 2) Digital imagery can improve
+access to recorded knowledge through printing and network distribution at
+a modest incremental cost of microfilm. 3) Capturing and storing documents
+in a digital image form is necessary to further improvements in access.
+(POB distinguishes between the imaging, digitizing process and OCR,
+which at this stage it does not plan to perform.)
+
+Currently in its first or organizational phase, POB found that it could
+use a vendor selection process to facilitate a good deal of the
+organizational work (e.g., creating a project team and advisory board,
+confirming the validity of the plan, establishing the cost of the project
+and a budget, selecting the materials to convert, and then raising the
+necessary funds).
+
+POB developed numerous selection criteria, including: a firm committed
+to image-document management, the ability to serve as systems integrator
+in a large-scale project over several years, interest in developing the
+requisite software as a standard rather than a custom product, and a
+willingness to invest substantial resources in the project itself.
+
+Two vendors, DEC and Xerox, were selected as finalists in October 1991,
+and with the support of the Commission on Preservation and Access, each
+was commissioned to generate a detailed requirements analysis for the
+project and then to submit a formal proposal for the completion of the
+project, which included a budget and costs. The terms were that POB would
+pay the loser. The results for Yale of involving a vendor included:
+broad involvement of Yale staff across the board at a relatively low
+cost, which may have long-term significance in carrying out the project
+(twenty-five to thirty university people are engaged in POB); better
+understanding of the factors that affect corporate response to markets
+for imaging products; a competitive proposal; and a more sophisticated
+view of the imaging markets.
+
+The most important factor that distinguished the vendors under
+consideration was their identification with the customer. The size and
+internal complexity of the company also was an important factor. POB was
+looking at large companies that had substantial resources. In the end,
+the process generated for Yale two competitive proposals, with Xerox's
+the clear winner. WATERS then described the components of the proposal,
+the design principles, and some of the costs estimated for the process.
+
+Components are essentially four: a conversion subsystem, a
+network-accessible storage subsystem for 10,000 books (and POB expects
+200 to 600 dpi storage), browsing stations distributed on the campus
+network, and network access to the image printers.
+
+Among the design principles, POB wanted conversion at the highest
+possible resolution. Assuming TIFF files, TIFF files with Group 4
+compression, TCP/IP, and ethernet network on campus, POB wanted a
+client-server approach with image documents distributed to the
+workstations and made accessible through native workstation interfaces
+such as Windows. POB also insisted on a phased approach to
+implementation: 1) a stand-alone, single-user, low-cost entry into the
+business with a workstation focused on conversion and allowing POB to
+explore user access; 2) movement into a higher-volume conversion with
+network-accessible storage and multiple access stations; and 3) a
+high-volume conversion, full-capacity storage, and multiple browsing
+stations distributed throughout the campus.
+
+The costs proposed for start-up assumed the existence of the Yale network
+and its two DocuTech image printers. Other start-up costs are estimated
+at $1 million over the three phases. At the end of the project, the annual
+operating costs estimated primarily for the software and hardware proposed
+come to about $60,000, but these exclude costs for labor needed in the
+conversion process, network and printer usage, and facilities management.
+
+Finally, the selection process produced for Yale a more sophisticated
+view of the imaging markets: the management of complex documents in
+image form is not a preservation problem, not a library problem, but a
+general problem in a broad, general industry. Preservation materials are
+useful for developing that market because of the qualities of the
+material. For example, much of it is out of copyright. The resolution
+of key issues such as the quality of scanning and image browsing also
+will affect development of that market.
+
+The technology is readily available but changing rapidly. In this
+context of rapid change, several factors affect quality and cost, to
+which POB intends to pay particular attention, for example, the various
+levels of resolution that can be achieved. POB believes it can bring
+resolution up to 600 dpi, but an interpolation process from 400 to 600 is
+more likely. The variation quality in microfilm will prove to be a
+highly important factor. POB may reexamine the standards used to film in
+the first place by looking at this process as a follow-on to microfilming.
+
+Other important factors include: the techniques available to the
+operator for handling material, the ways of integrating quality control
+into the digitizing work flow, and a work flow that includes indexing and
+storage. POB's requirement was to be able to deal with quality control
+at the point of scanning. Thus, thanks to Xerox, POB anticipates having
+a mechanism which will allow it not only to scan in batch form, but to
+review the material as it goes through the scanner and control quality
+from the outset.
+
+The standards for measuring quality and costs depend greatly on the uses
+of the material, including subsequent OCR, storage, printing, and
+browsing. But especially at issue for POB is the facility for browsing.
+This facility, WATERS said, is perhaps the weakest aspect of imaging
+technology and the most in need of development.
+
+A variety of factors affect the usability of complex documents in image
+form, among them: 1) the ability of the system to handle the full range
+of document types, not just monographs but serials, multi-part
+monographs, and manuscripts; 2) the location of the database of record
+for bibliographic information about the image document, which POB wants
+to enter once and in the most useful place, the on-line catalog; 3) a
+document identifier for referencing the bibliographic information in one
+place and the images in another; 4) the technique for making the basic
+internal structure of the document accessible to the reader; and finally,
+5) the physical presentation on the CRT of those documents. POB is ready
+to complete this phase now. One last decision involves deciding which
+material to scan.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * TIFF files constitute de facto standard * NARA's experience
+with image conversion software and text conversion * RFC 1314 *
+Considerable flux concerning available hardware and software solutions *
+NAL through-put rate during scanning * Window management questions *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+In the question-and-answer period that followed WATERS's presentation,
+the following points emerged:
+
+ * ZIDAR's statement about using TIFF files as a standard meant de
+ facto standard. This is what most people use and typically exchange
+ with other groups, across platforms, or even occasionally across
+ display software.
+
+ * HOLMES commented on the unsuccessful experience of NARA in
+ attempting to run image-conversion software or to exchange between
+ applications: What are supposedly TIFF files go into other software
+ that is supposed to be able to accept TIFF but cannot recognize the
+ format and cannot deal with it, and thus renders the exchange
+ useless. Re text conversion, he noted the different recognition
+ rates obtained by substituting the make and model of scanners in
+ NARA's recent test of an "intelligent" character-recognition product
+ for a new company. In the selection of hardware and software,
+ HOLMES argued, software no longer constitutes the overriding factor
+ it did until about a year ago; rather it is perhaps important to
+ look at both now.
+
+ * Danny Cohen and Alan Katz of the University of Southern California
+ Information Sciences Institute began circulating as an Internet RFC
+ (RFC 1314) about a month ago a standard for a TIFF interchange
+ format for Internet distribution of monochrome bit-mapped images,
+ which LYNCH said he believed would be used as a de facto standard.
+
+ * FLEISCHHAUER's impression from hearing these reports and thinking
+ about AM's experience was that there is considerable flux concerning
+ available hardware and software solutions. HOOTON agreed and
+ commented at the same time on ZIDAR's statement that the equipment
+ employed affects the results produced. One cannot draw a complete
+ conclusion by saying it is difficult or impossible to perform OCR
+ from scanning microfilm, for example, with that device, that set of
+ parameters, and system requirements, because numerous other people
+ are accomplishing just that, using other components, perhaps.
+ HOOTON opined that both the hardware and the software were highly
+ important. Most of the problems discussed today have been solved in
+ numerous different ways by other people. Though it is good to be
+ cognizant of various experiences, this is not to say that it will
+ always be thus.
+
+ * At NAL, the through-put rate of the scanning process for paper,
+ page by page, performing OCR, ranges from 300 to 600 pages per day;
+ not performing OCR is considerably faster, although how much faster
+ is not known. This is for scanning from bound books, which is much
+ slower.
+
+ * WATERS commented on window management questions: DEC proposed an
+ X-Windows solution which was problematical for two reasons. One was
+ POB's requirement to be able to manipulate images on the workstation
+ and bring them down to the workstation itself and the other was
+ network usage.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+THOMA * Illustration of deficiencies in scanning and storage process *
+Image quality in this process * Different costs entailed by better image
+quality * Techniques for overcoming various de-ficiencies: fixed
+thresholding, dynamic thresholding, dithering, image merge * Page edge
+effects *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+George THOMA, chief, Communications Engineering Branch, National Library
+of Medicine (NLM), illustrated several of the deficiencies discussed by
+the previous speakers. He introduced the topic of special problems by
+noting the advantages of electronic imaging. For example, it is regenerable
+because it is a coded file, and real-time quality control is possible with
+electronic capture, whereas in photographic capture it is not.
+
+One of the difficulties discussed in the scanning and storage process was
+image quality which, without belaboring the obvious, means different
+things for maps, medical X-rays, or broadcast television. In the case of
+documents, THOMA said, image quality boils down to legibility of the
+textual parts, and fidelity in the case of gray or color photo print-type
+material. Legibility boils down to scan density, the standard in most
+cases being 300 dpi. Increasing the resolution with scanners that
+perform 600 or 1200 dpi, however, comes at a cost.
+
+Better image quality entails at least four different kinds of costs: 1)
+equipment costs, because the CCD (i.e., charge-couple device) with
+greater number of elements costs more; 2) time costs that translate to
+the actual capture costs, because manual labor is involved (the time is
+also dependent on the fact that more data has to be moved around in the
+machine in the scanning or network devices that perform the scanning as
+well as the storage); 3) media costs, because at high resolutions larger
+files have to be stored; and 4) transmission costs, because there is just
+more data to be transmitted.
+
+But while resolution takes care of the issue of legibility in image
+quality, other deficiencies have to do with contrast and elements on the
+page scanned or the image that needed to be removed or clarified. Thus,
+THOMA proceeded to illustrate various deficiencies, how they are
+manifested, and several techniques to overcome them.
+
+Fixed thresholding was the first technique described, suitable for
+black-and-white text, when the contrast does not vary over the page. One
+can have many different threshold levels in scanning devices. Thus,
+THOMA offered an example of extremely poor contrast, which resulted from
+the fact that the stock was a heavy red. This is the sort of image that
+when microfilmed fails to provide any legibility whatsoever. Fixed
+thresholding is the way to change the black-to-red contrast to the
+desired black-to-white contrast.
+
+Other examples included material that had been browned or yellowed by
+age. This was also a case of contrast deficiency, and correction was
+done by fixed thresholding. A final example boils down to the same
+thing, slight variability, but it is not significant. Fixed thresholding
+solves this problem as well. The microfilm equivalent is certainly legible,
+but it comes with dark areas. Though THOMA did not have a slide of the
+microfilm in this case, he did show the reproduced electronic image.
+
+When one has variable contrast over a page or the lighting over the page
+area varies, especially in the case where a bound volume has light
+shining on it, the image must be processed by a dynamic thresholding
+scheme. One scheme, dynamic averaging, allows the threshold level not to
+be fixed but to be recomputed for every pixel from the neighboring
+characteristics. The neighbors of a pixel determine where the threshold
+should be set for that pixel.
+
+THOMA showed an example of a page that had been made deficient by a
+variety of techniques, including a burn mark, coffee stains, and a yellow
+marker. Application of a fixed-thresholding scheme, THOMA argued, might
+take care of several deficiencies on the page but not all of them.
+Performing the calculation for a dynamic threshold setting, however,
+removes most of the deficiencies so that at least the text is legible.
+
+Another problem is representing a gray level with black-and-white pixels
+by a process known as dithering or electronic screening. But dithering
+does not provide good image quality for pure black-and-white textual
+material. THOMA illustrated this point with examples. Although its
+suitability for photoprint is the reason for electronic screening or
+dithering, it cannot be used for every compound image. In the document
+that was distributed by CXP, THOMA noticed that the dithered image of the
+IEEE test chart evinced some deterioration in the text. He presented an
+extreme example of deterioration in the text in which compounded
+documents had to be set right by other techniques. The technique
+illustrated by the present example was an image merge in which the page
+is scanned twice and the settings go from fixed threshold to the
+dithering matrix; the resulting images are merged to give the best
+results with each technique.
+
+THOMA illustrated how dithering is also used in nonphotographic or
+nonprint materials with an example of a grayish page from a medical text,
+which was reproduced to show all of the gray that appeared in the
+original. Dithering provided a reproduction of all the gray in the
+original of another example from the same text.
+
+THOMA finally illustrated the problem of bordering, or page-edge,
+effects. Books and bound volumes that are placed on a photocopy machine
+or a scanner produce page-edge effects that are undesirable for two
+reasons: 1) the aesthetics of the image; after all, if the image is to
+be preserved, one does not necessarily want to keep all of its
+deficiencies; 2) compression (with the bordering problem THOMA
+illustrated, the compression ratio deteriorated tremendously). One way
+to eliminate this more serious problem is to have the operator at the
+point of scanning window the part of the image that is desirable and
+automatically turn all of the pixels out of that picture to white.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+FLEISCHHAUER * AM's experience with scanning bound materials * Dithering
+*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Carl FLEISCHHAUER, coordinator, American Memory, Library of Congress,
+reported AM's experience with scanning bound materials, which he likened
+to the problems involved in using photocopying machines. Very few
+devices in the industry offer book-edge scanning, let alone book cradles.
+The problem may be unsolvable, FLEISCHHAUER said, because a large enough
+market does not exist for a preservation-quality scanner. AM is using a
+Kurzweil scanner, which is a book-edge scanner now sold by Xerox.
+
+Devoting the remainder of his brief presentation to dithering,
+FLEISCHHAUER related AM's experience with a contractor who was using
+unsophisticated equipment and software to reduce moire patterns from
+printed halftones. AM took the same image and used the dithering
+algorithm that forms part of the same Kurzweil Xerox scanner; it
+disguised moire patterns much more effectively.
+
+FLEISCHHAUER also observed that dithering produces a binary file which is
+useful for numerous purposes, for example, printing it on a laser printer
+without having to "re-halftone" it. But it tends to defeat efficient
+compression, because the very thing that dithers to reduce moire patterns
+also tends to work against compression schemes. AM thought the
+difference in image quality was worth it.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Relative use as a criterion for POB's selection of books to
+be converted into digital form *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the discussion period, WATERS noted that one of the criteria for
+selecting books among the 10,000 to be converted into digital image form
+would be how much relative use they would receive--a subject still
+requiring evaluation. The challenge will be to understand whether
+coherent bodies of material will increase usage or whether POB should
+seek material that is being used, scan that, and make it more accessible.
+POB might decide to digitize materials that are already heavily used, in
+order to make them more accessible and decrease wear on them. Another
+approach would be to provide a large body of intellectually coherent
+material that may be used more in digital form than it is currently used
+in microfilm. POB would seek material that was out of copyright.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BARONAS * Origin and scope of AIIM * Types of documents produced in
+AIIM's standards program * Domain of AIIM's standardization work * AIIM's
+structure * TC 171 and MS23 * Electronic image management standards *
+Categories of EIM standardization where AIIM standards are being
+developed *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Jean BARONAS, senior manager, Department of Standards and Technology,
+Association for Information and Image Management (AIIM), described the
+not-for-profit association and the national and international programs
+for standardization in which AIIM is active.
+
+Accredited for twenty-five years as the nation's standards development
+organization for document image management, AIIM began life in a library
+community developing microfilm standards. Today the association
+maintains both its library and business-image management standardization
+activities--and has moved into electronic image-management
+standardization (EIM).
+
+BARONAS defined the program's scope. AIIM deals with: 1) the
+terminology of standards and of the technology it uses; 2) methods of
+measurement for the systems, as well as quality; 3) methodologies for
+users to evaluate and measure quality; 4) the features of apparatus used
+to manage and edit images; and 5) the procedures used to manage images.
+
+BARONAS noted that three types of documents are produced in the AIIM
+standards program: the first two, accredited by the American National
+Standards Institute (ANSI), are standards and standard recommended
+practices. Recommended practices differ from standards in that they
+contain more tutorial information. A technical report is not an ANSI
+standard. Because AIIM's policies and procedures for developing
+standards are approved by ANSI, its standards are labeled ANSI/AIIM,
+followed by the number and title of the standard.
+
+BARONAS then illustrated the domain of AIIM's standardization work. For
+example, AIIM is the administrator of the U.S. Technical Advisory Group
+(TAG) to the International Standards Organization's (ISO) technical
+committee, TC l7l Micrographics and Optical Memories for Document and
+Image Recording, Storage, and Use. AIIM officially works through ANSI in
+the international standardization process.
+
+BARONAS described AIIM's structure, including its board of directors, its
+standards board of twelve individuals active in the image-management
+industry, its strategic planning and legal admissibility task forces, and
+its National Standards Council, which is comprised of the members of a
+number of organizations who vote on every AIIM standard before it is
+published. BARONAS pointed out that AIIM's liaisons deal with numerous
+other standards developers, including the optical disk community, office
+and publishing systems, image-codes-and-character set committees, and the
+National Information Standards Organization (NISO).
+
+BARONAS illustrated the procedures of TC l7l, which covers all aspects of
+image management. When AIIM's national program has conceptualized a new
+project, it is usually submitted to the international level, so that the
+member countries of TC l7l can simultaneously work on the development of
+the standard or the technical report. BARONAS also illustrated a classic
+microfilm standard, MS23, which deals with numerous imaging concepts that
+apply to electronic imaging. Originally developed in the l970s, revised
+in the l980s, and revised again in l991, this standard is scheduled for
+another revision. MS23 is an active standard whereby users may propose
+new density ranges and new methods of evaluating film images in the
+standard's revision.
+
+BARONAS detailed several electronic image-management standards, for
+instance, ANSI/AIIM MS44, a quality-control guideline for scanning 8.5"
+by 11" black-and-white office documents. This standard is used with the
+IEEE fax image--a continuous tone photographic image with gray scales,
+text, and several continuous tone pictures--and AIIM test target number
+2, a representative document used in office document management.
+
+BARONAS next outlined the four categories of EIM standardization in which
+AIIM standards are being developed: transfer and retrieval, evaluation,
+optical disc and document scanning applications, and design and
+conversion of documents. She detailed several of the main projects of
+each: 1) in the category of image transfer and retrieval, a bi-level
+image transfer format, ANSI/AIIM MS53, which is a proposed standard that
+describes a file header for image transfer between unlike systems when
+the images are compressed using G3 and G4 compression; 2) the category of
+image evaluation, which includes the AIIM-proposed TR26 tutorial on image
+resolution (this technical report will treat the differences and
+similarities between classical or photographic and electronic imaging);
+3) design and conversion, which includes a proposed technical report
+called "Forms Design Optimization for EIM" (this report considers how
+general-purpose business forms can be best designed so that scanning is
+optimized; reprographic characteristics such as type, rules, background,
+tint, and color will likewise be treated in the technical report); 4)
+disk and document scanning applications includes a project a) on planning
+platters and disk management, b) on generating an application profile for
+EIM when images are stored and distributed on CD-ROM, and c) on
+evaluating SCSI2, and how a common command set can be generated for SCSI2
+so that document scanners are more easily integrated. (ANSI/AIIM MS53
+will also apply to compressed images.)
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+BATTIN * The implications of standards for preservation * A major
+obstacle to successful cooperation * A hindrance to access in the digital
+environment * Standards a double-edged sword for those concerned with the
+preservation of the human record * Near-term prognosis for reliable
+archival standards * Preservation concerns for electronic media * Need
+for reconceptualizing our preservation principles * Standards in the real
+world and the politics of reproduction * Need to redefine the concept of
+archival and to begin to think in terms of life cycles * Cooperation and
+the La Guardia Eight * Concerns generated by discussions on the problems
+of preserving text and image * General principles to be adopted in a
+world without standards *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Patricia BATTIN, president, the Commission on Preservation and Access
+(CPA), addressed the implications of standards for preservation. She
+listed several areas where the library profession and the analog world of
+the printed book had made enormous contributions over the past hundred
+years--for example, in bibliographic formats, binding standards, and, most
+important, in determining what constitutes longevity or archival quality.
+
+Although standards have lightened the preservation burden through the
+development of national and international collaborative programs,
+nevertheless, a pervasive mistrust of other people's standards remains a
+major obstacle to successful cooperation, BATTIN said.
+
+The zeal to achieve perfection, regardless of the cost, has hindered
+rather than facilitated access in some instances, and in the digital
+environment, where no real standards exist, has brought an ironically
+just reward.
+
+BATTIN argued that standards are a double-edged sword for those concerned
+with the preservation of the human record, that is, the provision of
+access to recorded knowledge in a multitude of media as far into the
+future as possible. Standards are essential to facilitate
+interconnectivity and access, but, BATTIN said, as LYNCH pointed out
+yesterday, if set too soon they can hinder creativity, expansion of
+capability, and the broadening of access. The characteristics of
+standards for digital imagery differ radically from those for analog
+imagery. And the nature of digital technology implies continuing
+volatility and change. To reiterate, precipitous standard-setting can
+inhibit creativity, but delayed standard-setting results in chaos.
+
+Since in BATTIN'S opinion the near-term prognosis for reliable archival
+standards, as defined by librarians in the analog world, is poor, two
+alternatives remain: standing pat with the old technology, or
+reconceptualizing.
+
+Preservation concerns for electronic media fall into two general domains.
+One is the continuing assurance of access to knowledge originally
+generated, stored, disseminated, and used in electronic form. This
+domain contains several subdivisions, including 1) the closed,
+proprietary systems discussed the previous day, bundled information such
+as electronic journals and government agency records, and electronically
+produced or captured raw data; and 2) the application of digital
+technologies to the reformatting of materials originally published on a
+deteriorating analog medium such as acid paper or videotape.
+
+The preservation of electronic media requires a reconceptualizing of our
+preservation principles during a volatile, standardless transition which
+may last far longer than any of us envision today. BATTIN urged the
+necessity of shifting focus from assessing, measuring, and setting
+standards for the permanence of the medium to the concept of managing
+continuing access to information stored on a variety of media and
+requiring a variety of ever-changing hardware and software for access--a
+fundamental shift for the library profession.
+
+BATTIN offered a primer on how to move forward with reasonable confidence
+in a world without standards. Her comments fell roughly into two sections:
+1) standards in the real world and 2) the politics of reproduction.
+
+In regard to real-world standards, BATTIN argued the need to redefine the
+concept of archive and to begin to think in terms of life cycles. In
+the past, the naive assumption that paper would last forever produced a
+cavalier attitude toward life cycles. The transient nature of the
+electronic media has compelled people to recognize and accept upfront the
+concept of life cycles in place of permanency.
+
+Digital standards have to be developed and set in a cooperative context
+to ensure efficient exchange of information. Moreover, during this
+transition period, greater flexibility concerning how concepts such as
+backup copies and archival copies in the CXP are defined is necessary,
+or the opportunity to move forward will be lost.
+
+In terms of cooperation, particularly in the university setting, BATTIN
+also argued the need to avoid going off in a hundred different
+directions. The CPA has catalyzed a small group of universities called
+the La Guardia Eight--because La Guardia Airport is where meetings take
+place--Harvard, Yale, Cornell, Princeton, Penn State, Tennessee,
+Stanford, and USC, to develop a digital preservation consortium to look
+at all these issues and develop de facto standards as we move along,
+instead of waiting for something that is officially blessed. Continuing
+to apply analog values and definitions of standards to the digital
+environment, BATTIN said, will effectively lead to forfeiture of the
+benefits of digital technology to research and scholarship.
+
+Under the second rubric, the politics of reproduction, BATTIN reiterated
+an oft-made argument concerning the electronic library, namely, that it
+is more difficult to transform than to create, and nowhere is that belief
+expressed more dramatically than in the conversion of brittle books to
+new media. Preserving information published in electronic media involves
+making sure the information remains accessible and that digital
+information is not lost through reproduction. In the analog world of
+photocopies and microfilm, the issue of fidelity to the original becomes
+paramount, as do issues of "Whose fidelity?" and "Whose original?"
+
+BATTIN elaborated these arguments with a few examples from a recent study
+conducted by the CPA on the problems of preserving text and image.
+Discussions with scholars, librarians, and curators in a variety of
+disciplines dependent on text and image generated a variety of concerns,
+for example: 1) Copy what is, not what the technology is capable of.
+This is very important for the history of ideas. Scholars wish to know
+what the author saw and worked from. And make available at the
+workstation the opportunity to erase all the defects and enhance the
+presentation. 2) The fidelity of reproduction--what is good enough, what
+can we afford, and the difference it makes--issues of subjective versus
+objective resolution. 3) The differences between primary and secondary
+users. Restricting the definition of primary user to the one in whose
+discipline the material has been published runs one headlong into the
+reality that these printed books have had a host of other users from a
+host of other disciplines, who not only were looking for very different
+things, but who also shared values very different from those of the
+primary user. 4) The relationship of the standard of reproduction to new
+capabilities of scholarship--the browsing standard versus an archival
+standard. How good must the archival standard be? Can a distinction be
+drawn between potential users in setting standards for reproduction?
+Archival storage, use copies, browsing copies--ought an attempt to set
+standards even be made? 5) Finally, costs. How much are we prepared to
+pay to capture absolute fidelity? What are the trade-offs between vastly
+enhanced access, degrees of fidelity, and costs?
+
+These standards, BATTIN concluded, serve to complicate further the
+reproduction process, and add to the long list of technical standards
+that are necessary to ensure widespread access. Ways to articulate and
+analyze the costs that are attached to the different levels of standards
+must be found.
+
+Given the chaos concerning standards, which promises to linger for the
+foreseeable future, BATTIN urged adoption of the following general
+principles:
+
+ * Strive to understand the changing information requirements of
+ scholarly disciplines as more and more technology is integrated into
+ the process of research and scholarly communication in order to meet
+ future scholarly needs, not to build for the past. Capture
+ deteriorating information at the highest affordable resolution, even
+ though the dissemination and display technologies will lag.
+
+ * Develop cooperative mechanisms to foster agreement on protocols
+ for document structure and other interchange mechanisms necessary
+ for widespread dissemination and use before official standards are
+ set.
+
+ * Accept that, in a transition period, de facto standards will have
+ to be developed.
+
+ * Capture information in a way that keeps all options open and
+ provides for total convertibility: OCR, scanning of microfilm,
+ producing microfilm from scanned documents, etc.
+
+ * Work closely with the generators of information and the builders
+ of networks and databases to ensure that continuing accessibility is
+ a primary concern from the beginning.
+
+ * Piggyback on standards under development for the broad market, and
+ avoid library-specific standards; work with the vendors, in order to
+ take advantage of that which is being standardized for the rest of
+ the world.
+
+ * Concentrate efforts on managing permanence in the digital world,
+ rather than perfecting the longevity of a particular medium.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Additional comments on TIFF *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the brief discussion period that followed BATTIN's presentation,
+BARONAS explained that TIFF was not developed in collaboration with or
+under the auspices of AIIM. TIFF is a company product, not a standard,
+is owned by two corporations, and is always changing. BARONAS also
+observed that ANSI/AIIM MS53, a bi-level image file transfer format that
+allows unlike systems to exchange images, is compatible with TIFF as well
+as with DEC's architecture and IBM's MODCA/IOCA.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+HOOTON * Several questions to be considered in discussing text conversion
+*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+HOOTON introduced the final topic, text conversion, by noting that it is
+becoming an increasingly important part of the imaging business. Many
+people now realize that it enhances their system to be able to have more
+and more character data as part of their imaging system. Re the issue of
+OCR versus rekeying, HOOTON posed several questions: How does one get
+text into computer-readable form? Does one use automated processes?
+Does one attempt to eliminate the use of operators where possible?
+Standards for accuracy, he said, are extremely important: it makes a
+major difference in cost and time whether one sets as a standard 98.5
+percent acceptance or 99.5 percent. He mentioned outsourcing as a
+possibility for converting text. Finally, what one does with the image
+to prepare it for the recognition process is also important, he said,
+because such preparation changes how recognition is viewed, as well as
+facilitates recognition itself.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LESK * Roles of participants in CORE * Data flow * The scanning process *
+The image interface * Results of experiments involving the use of
+electronic resources and traditional paper copies * Testing the issue of
+serendipity * Conclusions *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Michael LESK, executive director, Computer Science Research, Bell
+Communications Research, Inc. (Bellcore), discussed the Chemical Online
+Retrieval Experiment (CORE), a cooperative project involving Cornell
+University, OCLC, Bellcore, and the American Chemical Society (ACS).
+
+LESK spoke on 1) how the scanning was performed, including the unusual
+feature of page segmentation, and 2) the use made of the text and the
+image in experiments.
+
+Working with the chemistry journals (because ACS has been saving its
+typesetting tapes since the mid-1970s and thus has a significant back-run
+of the most important chemistry journals in the United States), CORE is
+attempting to create an automated chemical library. Approximately a
+quarter of the pages by square inch are made up of images of
+quasi-pictorial material; dealing with the graphic components of the
+pages is extremely important. LESK described the roles of participants
+in CORE: 1) ACS provides copyright permission, journals on paper,
+journals on microfilm, and some of the definitions of the files; 2) at
+Bellcore, LESK chiefly performs the data preparation, while Dennis Egan
+performs experiments on the users of chemical abstracts, and supplies the
+indexing and numerous magnetic tapes; 3) Cornell provides the site of the
+experiment; 4) OCLC develops retrieval software and other user interfaces.
+Various manufacturers and publishers have furnished other help.
+
+Concerning data flow, Bellcore receives microfilm and paper from ACS; the
+microfilm is scanned by outside vendors, while the paper is scanned
+inhouse on an Improvision scanner, twenty pages per minute at 300 dpi,
+which provides sufficient quality for all practical uses. LESK would
+prefer to have more gray level, because one of the ACS journals prints on
+some colored pages, which creates a problem.
+
+Bellcore performs all this scanning, creates a page-image file, and also
+selects from the pages the graphics, to mix with the text file (which is
+discussed later in the Workshop). The user is always searching the ASCII
+file, but she or he may see a display based on the ASCII or a display
+based on the images.
+
+LESK illustrated how the program performs page analysis, and the image
+interface. (The user types several words, is presented with a list--
+usually of the titles of articles contained in an issue--that derives
+from the ASCII, clicks on an icon and receives an image that mirrors an
+ACS page.) LESK also illustrated an alternative interface, based on text
+on the ASCII, the so-called SuperBook interface from Bellcore.
+
+LESK next presented the results of an experiment conducted by Dennis Egan
+and involving thirty-six students at Cornell, one third of them
+undergraduate chemistry majors, one third senior undergraduate chemistry
+majors, and one third graduate chemistry students. A third of them
+received the paper journals, the traditional paper copies and chemical
+abstracts on paper. A third received image displays of the pictures of
+the pages, and a third received the text display with pop-up graphics.
+
+The students were given several questions made up by some chemistry
+professors. The questions fell into five classes, ranging from very easy
+to very difficult, and included questions designed to simulate browsing
+as well as a traditional information retrieval-type task.
+
+LESK furnished the following results. In the straightforward question
+search--the question being, what is the phosphorus oxygen bond distance
+and hydroxy phosphate?--the students were told that they could take
+fifteen minutes and, then, if they wished, give up. The students with
+paper took more than fifteen minutes on average, and yet most of them
+gave up. The students with either electronic format, text or image,
+received good scores in reasonable time, hardly ever had to give up, and
+usually found the right answer.
+
+In the browsing study, the students were given a list of eight topics,
+told to imagine that an issue of the Journal of the American Chemical
+Society had just appeared on their desks, and were also told to flip
+through it and to find topics mentioned in the issue. The average scores
+were about the same. (The students were told to answer yes or no about
+whether or not particular topics appeared.) The errors, however, were
+quite different. The students with paper rarely said that something
+appeared when it had not. But they often failed to find something
+actually mentioned in the issue. The computer people found numerous
+things, but they also frequently said that a topic was mentioned when it
+was not. (The reason, of course, was that they were performing word
+searches. They were finding that words were mentioned and they were
+concluding that they had accomplished their task.)
+
+This question also contained a trick to test the issue of serendipity.
+The students were given another list of eight topics and instructed,
+without taking a second look at the journal, to recall how many of this
+new list of eight topics were in this particular issue. This was an
+attempt to see if they performed better at remembering what they were not
+looking for. They all performed about the same, paper or electronics,
+about 62 percent accurate. In short, LESK said, people were not very
+good when it came to serendipity, but they were no worse at it with
+computers than they were with paper.
+
+(LESK gave a parenthetical illustration of the learning curve of students
+who used SuperBook.)
+
+The students using the electronic systems started off worse than the ones
+using print, but by the third of the three sessions in the series had
+caught up to print. As one might expect, electronics provide a much
+better means of finding what one wants to read; reading speeds, once the
+object of the search has been found, are about the same.
+
+Almost none of the students could perform the hard task--the analogous
+transformation. (It would require the expertise of organic chemists to
+complete.) But an interesting result was that the students using the text
+search performed terribly, while those using the image system did best.
+That the text search system is driven by text offers the explanation.
+Everything is focused on the text; to see the pictures, one must press
+on an icon. Many students found the right article containing the answer
+to the question, but they did not click on the icon to bring up the right
+figure and see it. They did not know that they had found the right place,
+and thus got it wrong.
+
+The short answer demonstrated by this experiment was that in the event
+one does not know what to read, one needs the electronic systems; the
+electronic systems hold no advantage at the moment if one knows what to
+read, but neither do they impose a penalty.
+
+LESK concluded by commenting that, on one hand, the image system was easy
+to use. On the other hand, the text display system, which represented
+twenty man-years of work in programming and polishing, was not winning,
+because the text was not being read, just searched. The much easier
+system is highly competitive as well as remarkably effective for the
+actual chemists.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ERWAY * Most challenging aspect of working on AM * Assumptions guiding
+AM's approach * Testing different types of service bureaus * AM's
+requirement for 99.95 percent accuracy * Requirements for text-coding *
+Additional factors influencing AM's approach to coding * Results of AM's
+experience with rekeying * Other problems in dealing with service bureaus
+* Quality control the most time-consuming aspect of contracting out
+conversion * Long-term outlook uncertain *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+To Ricky ERWAY, associate coordinator, American Memory, Library of
+Congress, the constant variety of conversion projects taking place
+simultaneously represented perhaps the most challenging aspect of working
+on AM. Thus, the challenge was not to find a solution for text
+conversion but a tool kit of solutions to apply to LC's varied
+collections that need to be converted. ERWAY limited her remarks to the
+process of converting text to machine-readable form, and the variety of
+LC's text collections, for example, bound volumes, microfilm, and
+handwritten manuscripts.
+
+Two assumptions have guided AM's approach, ERWAY said: 1) A desire not
+to perform the conversion inhouse. Because of the variety of formats and
+types of texts, to capitalize the equipment and have the talents and
+skills to operate them at LC would be extremely expensive. Further, the
+natural inclination to upgrade to newer and better equipment each year
+made it reasonable for AM to focus on what it did best and seek external
+conversion services. Using service bureaus also allowed AM to have
+several types of operations take place at the same time. 2) AM was not a
+technology project, but an effort to improve access to library
+collections. Hence, whether text was converted using OCR or rekeying
+mattered little to AM. What mattered were cost and accuracy of results.
+
+AM considered different types of service bureaus and selected three to
+perform several small tests in order to acquire a sense of the field.
+The sample collections with which they worked included handwritten
+correspondence, typewritten manuscripts from the 1940s, and
+eighteenth-century printed broadsides on microfilm. On none of these
+samples was OCR performed; they were all rekeyed. AM had several special
+requirements for the three service bureaus it had engaged. For instance,
+any errors in the original text were to be retained. Working from bound
+volumes or anything that could not be sheet-fed also constituted a factor
+eliminating companies that would have performed OCR.
+
+AM requires 99.95 percent accuracy, which, though it sounds high, often
+means one or two errors per page. The initial batch of test samples
+contained several handwritten materials for which AM did not require
+text-coding. The results, ERWAY reported, were in all cases fairly
+comparable: for the most part, all three service bureaus achieved 99.95
+percent accuracy. AM was satisfied with the work but surprised at the cost.
+
+As AM began converting whole collections, it retained the requirement for
+99.95 percent accuracy and added requirements for text-coding. AM needed
+to begin performing work more than three years ago before LC requirements
+for SGML applications had been established. Since AM's goal was simply
+to retain any of the intellectual content represented by the formatting
+of the document (which would be lost if one performed a straight ASCII
+conversion), AM used "SGML-like" codes. These codes resembled SGML tags
+but were used without the benefit of document-type definitions. AM found
+that many service bureaus were not yet SGML-proficient.
+
+Additional factors influencing the approach AM took with respect to
+coding included: 1) the inability of any known microcomputer-based
+user-retrieval software to take advantage of SGML coding; and 2) the
+multiple inconsistencies in format of the older documents, which
+confirmed AM in its desire not to attempt to force the different formats
+to conform to a single document-type definition (DTD) and thus create the
+need for a separate DTD for each document.
+
+The five text collections that AM has converted or is in the process of
+converting include a collection of eighteenth-century broadsides, a
+collection of pamphlets, two typescript document collections, and a
+collection of 150 books.
+
+ERWAY next reviewed the results of AM's experience with rekeying, noting
+again that because the bulk of AM's materials are historical, the quality
+of the text often does not lend itself to OCR. While non-English
+speakers are less likely to guess or elaborate or correct typos in the
+original text, they are also less able to infer what we would; they also
+are nearly incapable of converting handwritten text. Another
+disadvantage of working with overseas keyers is that they are much less
+likely to telephone with questions, especially on the coding, with the
+result that they develop their own rules as they encounter new
+situations.
+
+Government contracting procedures and time frames posed a major challenge
+to performing the conversion. Many service bureaus are not accustomed to
+retaining the image, even if they perform OCR. Thus, questions of image
+format and storage media were somewhat novel to many of them. ERWAY also
+remarked other problems in dealing with service bureaus, for example,
+their inability to perform text conversion from the kind of microfilm
+that LC uses for preservation purposes.
+
+But quality control, in ERWAY's experience, was the most time-consuming
+aspect of contracting out conversion. AM has been attempting to perform
+a 10-percent quality review, looking at either every tenth document or
+every tenth page to make certain that the service bureaus are maintaining
+99.95 percent accuracy. But even if they are complying with the
+requirement for accuracy, finding errors produces a desire to correct
+them and, in turn, to clean up the whole collection, which defeats the
+purpose to some extent. Even a double entry requires a
+character-by-character comparison to the original to meet the accuracy
+requirement. LC is not accustomed to publish imperfect texts, which
+makes attempting to deal with the industry standard an emotionally
+fraught issue for AM. As was mentioned in the previous day's discussion,
+going from 99.95 to 99.99 percent accuracy usually doubles costs and
+means a third keying or another complete run-through of the text.
+
+Although AM has learned much from its experiences with various collections
+and various service bureaus, ERWAY concluded pessimistically that no
+breakthrough has been achieved. Incremental improvements have occurred
+in some of the OCR technology, some of the processes, and some of the
+standards acceptances, which, though they may lead to somewhat lower costs,
+do not offer much encouragement to many people who are anxiously awaiting
+the day that the entire contents of LC are available on-line.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ZIDAR * Several answers to why one attempts to perform full-text
+conversion * Per page cost of performing OCR * Typical problems
+encountered during editing * Editing poor copy OCR vs. rekeying *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Judith ZIDAR, coordinator, National Agricultural Text Digitizing Program
+(NATDP), National Agricultural Library (NAL), offered several answers to
+the question of why one attempts to perform full-text conversion: 1)
+Text in an image can be read by a human but not by a computer, so of
+course it is not searchable and there is not much one can do with it. 2)
+Some material simply requires word-level access. For instance, the legal
+profession insists on full-text access to its material; with taxonomic or
+geographic material, which entails numerous names, one virtually requires
+word-level access. 3) Full text permits rapid browsing and searching,
+something that cannot be achieved in an image with today's technology.
+4) Text stored as ASCII and delivered in ASCII is standardized and highly
+portable. 5) People just want full-text searching, even those who do not
+know how to do it. NAL, for the most part, is performing OCR at an
+actual cost per average-size page of approximately $7. NAL scans the
+page to create the electronic image and passes it through the OCR device.
+
+ZIDAR next rehearsed several typical problems encountered during editing.
+Praising the celerity of her student workers, ZIDAR observed that editing
+requires approximately five to ten minutes per page, assuming that there
+are no large tables to audit. Confusion among the three characters I, 1,
+and l, constitutes perhaps the most common problem encountered. Zeroes
+and O's also are frequently confused. Double M's create a particular
+problem, even on clean pages. They are so wide in most fonts that they
+touch, and the system simply cannot tell where one letter ends and the
+other begins. Complex page formats occasionally fail to columnate
+properly, which entails rescanning as though one were working with a
+single column, entering the ASCII, and decolumnating for better
+searching. With proportionally spaced text, OCR can have difficulty
+discerning what is a space and what are merely spaces between letters, as
+opposed to spaces between words, and therefore will merge text or break
+up words where it should not.
+
+ZIDAR said that it can often take longer to edit a poor-copy OCR than to
+key it from scratch. NAL has also experimented with partial editing of
+text, whereby project workers go into and clean up the format, removing
+stray characters but not running a spell-check. NAL corrects typos in
+the title and authors' names, which provides a foothold for searching and
+browsing. Even extremely poor-quality OCR (e.g., 60-percent accuracy)
+can still be searched, because numerous words are correct, while the
+important words are probably repeated often enough that they are likely
+to be found correct somewhere. Librarians, however, cannot tolerate this
+situation, though end users seem more willing to use this text for
+searching, provided that NAL indicates that it is unedited. ZIDAR
+concluded that rekeying of text may be the best route to take, in spite
+of numerous problems with quality control and cost.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Modifying an image before performing OCR * NAL's costs per
+page *AM's costs per page and experience with Federal Prison Industries *
+Elements comprising NATDP's costs per page * OCR and structured markup *
+Distinction between the structure of a document and its representation
+when put on the screen or printed *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+HOOTON prefaced the lengthy discussion that followed with several
+comments about modifying an image before one reaches the point of
+performing OCR. For example, in regard to an application containing a
+significant amount of redundant data, such as form-type data, numerous
+companies today are working on various kinds of form renewal, prior to
+going through a recognition process, by using dropout colors. Thus,
+acquiring access to form design or using electronic means are worth
+considering. HOOTON also noted that conversion usually makes or breaks
+one's imaging system. It is extremely important, extremely costly in
+terms of either capital investment or service, and determines the quality
+of the remainder of one's system, because it determines the character of
+the raw material used by the system.
+
+Concerning the four projects undertaken by NAL, two inside and two
+performed by outside contractors, ZIDAR revealed that an in-house service
+bureau executed the first at a cost between $8 and $10 per page for
+everything, including building of the database. The project undertaken
+by the Consultative Group on International Agricultural Research (CGIAR)
+cost approximately $10 per page for the conversion, plus some expenses
+for the software and building of the database. The Acid Rain Project--a
+two-disk set produced by the University of Vermont, consisting of
+Canadian publications on acid rain--cost $6.70 per page for everything,
+including keying of the text, which was double keyed, scanning of the
+images, and building of the database. The in-house project offered
+considerable ease of convenience and greater control of the process. On
+the other hand, the service bureaus know their job and perform it
+expeditiously, because they have more people.
+
+As a useful comparison, ERWAY revealed AM's costs as follows: $0.75
+cents to $0.85 cents per thousand characters, with an average page
+containing 2,700 characters. Requirements for coding and imaging
+increase the costs. Thus, conversion of the text, including the coding,
+costs approximately $3 per page. (This figure does not include the
+imaging and database-building included in the NAL costs.) AM also
+enjoyed a happy experience with Federal Prison Industries, which
+precluded the necessity of going through the request-for-proposal process
+to award a contract, because it is another government agency. The
+prisoners performed AM's rekeying just as well as other service bureaus
+and proved handy as well. AM shipped them the books, which they would
+photocopy on a book-edge scanner. They would perform the markup on
+photocopies, return the books as soon as they were done with them,
+perform the keying, and return the material to AM on WORM disks.
+
+ZIDAR detailed the elements that constitute the previously noted cost of
+approximately $7 per page. Most significant is the editing, correction
+of errors, and spell-checkings, which though they may sound easy to
+perform require, in fact, a great deal of time. Reformatting text also
+takes a while, but a significant amount of NAL's expenses are for equipment,
+which was extremely expensive when purchased because it was one of the few
+systems on the market. The costs of equipment are being amortized over
+five years but are still quite high, nearly $2,000 per month.
+
+HOCKEY raised a general question concerning OCR and the amount of editing
+required (substantial in her experience) to generate the kind of
+structured markup necessary for manipulating the text on the computer or
+loading it into any retrieval system. She wondered if the speakers could
+extend the previous question about the cost-benefit of adding or exerting
+structured markup. ERWAY noted that several OCR systems retain italics,
+bolding, and other spatial formatting. While the material may not be in
+the format desired, these systems possess the ability to remove the
+original materials quickly from the hands of the people performing the
+conversion, as well as to retain that information so that users can work
+with it. HOCKEY rejoined that the current thinking on markup is that one
+should not say that something is italic or bold so much as why it is that
+way. To be sure, one needs to know that something was italicized, but
+how can one get from one to the other? One can map from the structure to
+the typographic representation.
+
+FLEISCHHAUER suggested that, given the 100 million items the Library
+holds, it may not be possible for LC to do more than report that a thing
+was in italics as opposed to why it was italics, although that may be
+desirable in some contexts. Promising to talk a bit during the afternoon
+session about several experiments OCLC performed on automatic recognition
+of document elements, and which they hoped to extend, WEIBEL said that in
+fact one can recognize the major elements of a document with a fairly
+high degree of reliability, at least as good as OCR. STEVENS drew a
+useful distinction between standard, generalized markup (i.e., defining
+for a document-type definition the structure of the document), and what
+he termed a style sheet, which had to do with italics, bolding, and other
+forms of emphasis. Thus, two different components are at work, one being
+the structure of the document itself (its logic), and the other being its
+representation when it is put on the screen or printed.
+
+ ******
+
+SESSION V. APPROACHES TO PREPARING ELECTRONIC TEXTS
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+HOCKEY * Text in ASCII and the representation of electronic text versus
+an image * The need to look at ways of using markup to assist retrieval *
+The need for an encoding format that will be reusable and multifunctional
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Susan HOCKEY, director, Center for Electronic Texts in the Humanities
+(CETH), Rutgers and Princeton Universities, announced that one talk
+(WEIBEL's) was moved into this session from the morning and that David
+Packard was unable to attend. The session would attempt to focus more on
+what one can do with a text in ASCII and the representation of electronic
+text rather than just an image, what one can do with a computer that
+cannot be done with a book or an image. It would be argued that one can
+do much more than just read a text, and from that starting point one can
+use markup and methods of preparing the text to take full advantage of
+the capability of the computer. That would lead to a discussion of what
+the European Community calls REUSABILITY, what may better be termed
+DURABILITY, that is, how to prepare or make a text that will last a long
+time and that can be used for as many applications as possible, which
+would lead to issues of improving intellectual access.
+
+HOCKEY urged the need to look at ways of using markup to facilitate retrieval,
+not just for referencing or to help locate an item that is retrieved, but also to put markup tags in
+a text to help retrieve the thing sought either with linguistic tagging or
+interpretation. HOCKEY also argued that little advancement had occurred in
+the software tools currently available for retrieving and searching text.
+She pressed the desideratum of going beyond Boolean searches and performing
+more sophisticated searching, which the insertion of more markup in the text
+would facilitate. Thinking about electronic texts as opposed to images means
+considering material that will never appear in print form, or print will not
+be its primary form, that is, material which only appears in electronic form.
+HOCKEY alluded to the history and the need for markup and tagging and
+electronic text, which was developed through the use of computers in the
+humanities; as MICHELSON had observed, Father Busa had started in 1949
+to prepare the first-ever text on the computer.
+
+HOCKEY remarked several large projects, particularly in Europe, for the
+compilation of dictionaries, language studies, and language analysis, in
+which people have built up archives of text and have begun to recognize
+the need for an encoding format that will be reusable and multifunctional,
+that can be used not just to print the text, which may be assumed to be a
+byproduct of what one wants to do, but to structure it inside the computer
+so that it can be searched, built into a Hypertext system, etc.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+WEIBEL * OCLC's approach to preparing electronic text: retroconversion,
+keying of texts, more automated ways of developing data * Project ADAPT
+and the CORE Project * Intelligent character recognition does not exist *
+Advantages of SGML * Data should be free of procedural markup;
+descriptive markup strongly advocated * OCLC's interface illustrated *
+Storage requirements and costs for putting a lot of information on line *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Stuart WEIBEL, senior research scientist, Online Computer Library Center,
+Inc. (OCLC), described OCLC's approach to preparing electronic text. He
+argued that the electronic world into which we are moving must
+accommodate not only the future but the past as well, and to some degree
+even the present. Thus, starting out at one end with retroconversion and
+keying of texts, one would like to move toward much more automated ways
+of developing data.
+
+For example, Project ADAPT had to do with automatically converting
+document images into a structured document database with OCR text as
+indexing and also a little bit of automatic formatting and tagging of
+that text. The CORE project hosted by Cornell University, Bellcore,
+OCLC, the American Chemical Society, and Chemical Abstracts, constitutes
+WEIBEL's principal concern at the moment. This project is an example of
+converting text for which one already has a machine-readable version into
+a format more suitable for electronic delivery and database searching.
+(Since Michael LESK had previously described CORE, WEIBEL would say
+little concerning it.) Borrowing a chemical phrase, de novo synthesis,
+WEIBEL cited the Online Journal of Current Clinical Trials as an example
+of de novo electronic publishing, that is, a form in which the primary
+form of the information is electronic.
+
+Project ADAPT, then, which OCLC completed a couple of years ago and in
+fact is about to resume, is a model in which one takes page images either
+in paper or microfilm and converts them automatically to a searchable
+electronic database, either on-line or local. The operating assumption
+is that accepting some blemishes in the data, especially for
+retroconversion of materials, will make it possible to accomplish more.
+Not enough money is available to support perfect conversion.
+
+WEIBEL related several steps taken to perform image preprocessing
+(processing on the image before performing optical character
+recognition), as well as image postprocessing. He denied the existence
+of intelligent character recognition and asserted that what is wanted is
+page recognition, which is a long way off. OCLC has experimented with
+merging of multiple optical character recognition systems that will
+reduce errors from an unacceptable rate of 5 characters out of every
+l,000 to an unacceptable rate of 2 characters out of every l,000, but it
+is not good enough. It will never be perfect.
+
+Concerning the CORE Project, WEIBEL observed that Bellcore is taking the
+topography files, extracting the page images, and converting those
+topography files to SGML markup. LESK hands that data off to OCLC, which
+builds that data into a Newton database, the same system that underlies
+the on-line system in virtually all of the reference products at OCLC.
+The long-term goal is to make the systems interoperable so that not just
+Bellcore's system and OCLC's system can access this data, but other
+systems can as well, and the key to that is the Z39.50 common command
+language and the full-text extension. Z39.50 is fine for MARC records,
+but is not enough to do it for full text (that is, make full texts
+interoperable).
+
+WEIBEL next outlined the critical role of SGML for a variety of purposes,
+for example, as noted by HOCKEY, in the world of extremely large
+databases, using highly structured data to perform field searches.
+WEIBEL argued that by building the structure of the data in (i.e., the
+structure of the data originally on a printed page), it becomes easy to
+look at a journal article even if one cannot read the characters and know
+where the title or author is, or what the sections of that document would be.
+OCLC wants to make that structure explicit in the database, because it will
+be important for retrieval purposes.
+
+The second big advantage of SGML is that it gives one the ability to
+build structure into the database that can be used for display purposes
+without contaminating the data with instructions about how to format
+things. The distinction lies between procedural markup, which tells one
+where to put dots on the page, and descriptive markup, which describes
+the elements of a document.
+
+WEIBEL believes that there should be no procedural markup in the data at
+all, that the data should be completely unsullied by information about
+italics or boldness. That should be left up to the display device,
+whether that display device is a page printer or a screen display device.
+By keeping one's database free of that kind of contamination, one can
+make decisions down the road, for example, reorganize the data in ways
+that are not cramped by built-in notions of what should be italic and
+what should be bold. WEIBEL strongly advocated descriptive markup. As
+an example, he illustrated the index structure in the CORE data. With
+subsequent illustrated examples of markup, WEIBEL acknowledged the common
+complaint that SGML is hard to read in its native form, although markup
+decreases considerably once one gets into the body. Without the markup,
+however, one would not have the structure in the data. One can pass
+markup through a LaTeX processor and convert it relatively easily to a
+printed version of the document.
+
+WEIBEL next illustrated an extremely cluttered screen dump of OCLC's
+system, in order to show as much as possible the inherent capability on
+the screen. (He noted parenthetically that he had become a supporter of
+X-Windows as a result of the progress of the CORE Project.) WEIBEL also
+illustrated the two major parts of the interface: l) a control box that
+allows one to generate lists of items, which resembles a small table of
+contents based on key words one wishes to search, and 2) a document
+viewer, which is a separate process in and of itself. He demonstrated
+how to follow links through the electronic database simply by selecting
+the appropriate button and bringing them up. He also noted problems that
+remain to be accommodated in the interface (e.g., as pointed out by LESK,
+what happens when users do not click on the icon for the figure).
+
+Given the constraints of time, WEIBEL omitted a large number of ancillary
+items in order to say a few words concerning storage requirements and
+what will be required to put a lot of things on line. Since it is
+extremely expensive to reconvert all of this data, especially if it is
+just in paper form (and even if it is in electronic form in typesetting
+tapes), he advocated building journals electronically from the start. In
+that case, if one only has text graphics and indexing (which is all that
+one needs with de novo electronic publishing, because there is no need to
+go back and look at bit-maps of pages), one can get 10,000 journals of
+full text, or almost 6 million pages per year. These pages can be put in
+approximately 135 gigabytes of storage, which is not all that much,
+WEIBEL said. For twenty years, something less than three terabytes would
+be required. WEIBEL calculated the costs of storing this information as
+follows: If a gigabyte costs approximately $1,000, then a terabyte costs
+approximately $1 million to buy in terms of hardware. One also needs a
+building to put it in and a staff like OCLC to handle that information.
+So, to support a terabyte, multiply by five, which gives $5 million per
+year for a supported terabyte of data.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Tapes saved by ACS are the typography files originally
+supporting publication of the journal * Cost of building tagged text into
+the database *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the question-and-answer period that followed WEIBEL's
+presentation, these clarifications emerged. The tapes saved by the
+American Chemical Society are the typography files that originally
+supported the publication of the journal. Although they are not tagged
+in SGML, they are tagged in very fine detail. Every single sentence is
+marked, all the registry numbers, all the publications issues, dates, and
+volumes. No cost figures on tagging material on a per-megabyte basis
+were available. Because ACS's typesetting system runs from tagged text,
+there is no extra cost per article. It was unknown what it costs ACS to
+keyboard the tagged text rather than just keyboard the text in the
+cheapest process. In other words, since one intends to publish things
+and will need to build tagged text into a typography system in any case,
+if one does that in such a way that it can drive not only typography but
+an electronic system (which is what ACS intends to do--move to SGML
+publishing), the marginal cost is zero. The marginal cost represents the
+cost of building tagged text into the database, which is small.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+SPERBERG-McQUEEN * Distinction between texts and computers * Implications
+of recognizing that all representation is encoding * Dealing with
+complicated representations of text entails the need for a grammar of
+documents * Variety of forms of formal grammars * Text as a bit-mapped
+image does not represent a serious attempt to represent text in
+electronic form * SGML, the TEI, document-type declarations, and the
+reusability and longevity of data * TEI conformance explicitly allows
+extension or modification of the TEI tag set * Administrative background
+of the TEI * Several design goals for the TEI tag set * An absolutely
+fixed requirement of the TEI Guidelines * Challenges the TEI has
+attempted to face * Good texts not beyond economic feasibility * The
+issue of reproducibility or processability * The issue of mages as
+simulacra for the text redux * One's model of text determines what one's
+software can do with a text and has economic consequences *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Prior to speaking about SGML and markup, Michael SPERBERG-McQUEEN, editor,
+Text Encoding Initiative (TEI), University of Illinois-Chicago, first drew
+a distinction between texts and computers: Texts are abstract cultural
+and linguistic objects while computers are complicated physical devices,
+he said. Abstract objects cannot be placed inside physical devices; with
+computers one can only represent text and act upon those representations.
+
+The recognition that all representation is encoding, SPERBERG-McQUEEN
+argued, leads to the recognition of two things: 1) The topic description
+for this session is slightly misleading, because there can be no discussion
+of pros and cons of text-coding unless what one means is pros and cons of
+working with text with computers. 2) No text can be represented in a
+computer without some sort of encoding; images are one way of encoding text,
+ASCII is another, SGML yet another. There is no encoding without some
+information loss, that is, there is no perfect reproduction of a text that
+allows one to do away with the original. Thus, the question becomes,
+What is the most useful representation of text for a serious work?
+This depends on what kind of serious work one is talking about.
+
+The projects demonstrated the previous day all involved highly complex
+information and fairly complex manipulation of the textual material.
+In order to use that complicated information, one has to calculate it
+slowly or manually and store the result. It needs to be stored, therefore,
+as part of one's representation of the text. Thus, one needs to store the
+structure in the text. To deal with complicated representations of text,
+one needs somehow to control the complexity of the representation of a text;
+that means one needs a way of finding out whether a document and an
+electronic representation of a document is legal or not; and that
+means one needs a grammar of documents.
+
+SPERBERG-McQUEEN discussed the variety of forms of formal grammars,
+implicit and explicit, as applied to text, and their capabilities. He
+argued that these grammars correspond to different models of text that
+different developers have. For example, one implicit model of the text
+is that there is no internal structure, but just one thing after another,
+a few characters and then perhaps a start-title command, and then a few
+more characters and an end-title command. SPERBERG-McQUEEN also
+distinguished several kinds of text that have a sort of hierarchical
+structure that is not very well defined, which, typically, corresponds
+to grammars that are not very well defined, as well as hierarchies that
+are very well defined (e.g., the Thesaurus Linguae Graecae) and extremely
+complicated things such as SGML, which handle strictly hierarchical data
+very nicely.
+
+SPERBERG-McQUEEN conceded that one other model not illustrated on his two
+displays was the model of text as a bit-mapped image, an image of a page,
+and confessed to having been converted to a limited extent by the
+Workshop to the view that electronic images constitute a promising,
+probably superior alternative to microfilming. But he was not convinced
+that electronic images represent a serious attempt to represent text in
+electronic form. Many of their problems stem from the fact that they are
+not direct attempts to represent the text but attempts to represent the
+page, thus making them representations of representations.
+
+In this situation of increasingly complicated textual information and the
+need to control that complexity in a useful way (which begs the question
+of the need for good textual grammars), one has the introduction of SGML.
+With SGML, one can develop specific document-type declarations
+for specific text types or, as with the TEI, attempts to generate
+general document-type declarations that can handle all sorts of text.
+The TEI is an attempt to develop formats for text representation that
+will ensure the kind of reusability and longevity of data discussed earlier.
+It offers a way to stay alive in the state of permanent technological
+revolution.
+
+It has been a continuing challenge in the TEI to create document grammars
+that do some work in controlling the complexity of the textual object but
+also allowing one to represent the real text that one will find.
+Fundamental to the notion of the TEI is that TEI conformance allows one
+the ability to extend or modify the TEI tag set so that it fits the text
+that one is attempting to represent.
+
+SPERBERG-McQUEEN next outlined the administrative background of the TEI.
+The TEI is an international project to develop and disseminate guidelines
+for the encoding and interchange of machine-readable text. It is
+sponsored by the Association for Computers in the Humanities, the
+Association for Computational Linguistics, and the Association for
+Literary and Linguistic Computing. Representatives of numerous other
+professional societies sit on its advisory board. The TEI has a number
+of affiliated projects that have provided assistance by testing drafts of
+the guidelines.
+
+Among the design goals for the TEI tag set, the scheme first of all must
+meet the needs of research, because the TEI came out of the research
+community, which did not feel adequately served by existing tag sets.
+The tag set must be extensive as well as compatible with existing and
+emerging standards. In 1990, version 1.0 of the Guidelines was released
+(SPERBERG-McQUEEN illustrated their contents).
+
+SPERBERG-McQUEEN noted that one problem besetting electronic text has
+been the lack of adequate internal or external documentation for many
+existing electronic texts. The TEI guidelines as currently formulated
+contain few fixed requirements, but one of them is this: There must
+always be a document header, an in-file SGML tag that provides
+1) a bibliographic description of the electronic object one is talking
+about (that is, who included it, when, what for, and under which title);
+and 2) the copy text from which it was derived, if any. If there was
+no copy text or if the copy text is unknown, then one states as much.
+Version 2.0 of the Guidelines was scheduled to be completed in fall 1992
+and a revised third version is to be presented to the TEI advisory board
+for its endorsement this coming winter. The TEI itself exists to provide
+a markup language, not a marked-up text.
+
+Among the challenges the TEI has attempted to face is the need for a
+markup language that will work for existing projects, that is, handle the
+level of markup that people are using now to tag only chapter, section,
+and paragraph divisions and not much else. At the same time, such a
+language also will be able to scale up gracefully to handle the highly
+detailed markup which many people foresee as the future destination of
+much electronic text, and which is not the future destination but the
+present home of numerous electronic texts in specialized areas.
+
+SPERBERG-McQUEEN dismissed the lowest-common-denominator approach as
+unable to support the kind of applications that draw people who have
+never been in the public library regularly before, and make them come
+back. He advocated more interesting text and more intelligent text.
+Asserting that it is not beyond economic feasibility to have good texts,
+SPERBERG-McQUEEN noted that the TEI Guidelines listing 200-odd tags
+contains tags that one is expected to enter every time the relevant
+textual feature occurs. It contains all the tags that people need now,
+and it is not expected that everyone will tag things in the same way.
+
+The question of how people will tag the text is in large part a function
+of their reaction to what SPERBERG-McQUEEN termed the issue of
+reproducibility. What one needs to be able to reproduce are the things
+one wants to work with. Perhaps a more useful concept than that of
+reproducibility or recoverability is that of processability, that is,
+what can one get from an electronic text without reading it again
+in the original. He illustrated this contention with a page from
+Jan Comenius's bilingual Introduction to Latin.
+
+SPERBERG-McQUEEN returned at length to the issue of images as simulacra
+for the text, in order to reiterate his belief that in the long run more
+than images of pages of particular editions of the text are needed,
+because just as second-generation photocopies and second-generation
+microfilm degenerate, so second-generation representations tend to
+degenerate, and one tends to overstress some relatively trivial aspects
+of the text such as its layout on the page, which is not always
+significant, despite what the text critics might say, and slight other
+pieces of information such as the very important lexical ties between the
+English and Latin versions of Comenius's bilingual text, for example.
+Moreover, in many crucial respects it is easy to fool oneself concerning
+what a scanned image of the text will accomplish. For example, in order
+to study the transmission of texts, information concerning the text
+carrier is necessary, which scanned images simply do not always handle.
+Further, even the high-quality materials being produced at Cornell use
+much of the information that one would need if studying those books as
+physical objects. It is a choice that has been made. It is an arguably
+justifiable choice, but one does not know what color those pen strokes in
+the margin are or whether there was a stain on the page, because it has
+been filtered out. One does not know whether there were rips in the page
+because they do not show up, and on a couple of the marginal marks one
+loses half of the mark because the pen is very light and the scanner
+failed to pick it up, and so what is clearly a checkmark in the margin of
+the original becomes a little scoop in the margin of the facsimile.
+Standard problems for facsimile editions, not new to electronics, but
+also true of light-lens photography, and are remarked here because it is
+important that we not fool ourselves that even if we produce a very nice
+image of this page with good contrast, we are not replacing the
+manuscript any more than microfilm has replaced the manuscript.
+
+The TEI comes from the research community, where its first allegiance
+lies, but it is not just an academic exercise. It has relevance far
+beyond those who spend all of their time studying text, because one's
+model of text determines what one's software can do with a text. Good
+models lead to good software. Bad models lead to bad software. That has
+economic consequences, and it is these economic consequences that have
+led the European Community to help support the TEI, and that will lead,
+SPERBERG-McQUEEN hoped, some software vendors to realize that if they
+provide software with a better model of the text they can make a killing.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Implications of different DTDs and tag sets * ODA versus SGML *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+During the discussion that followed, several additional points were made.
+Neither AAP (i.e., Association of American Publishers) nor CALS (i.e.,
+Computer-aided Acquisition and Logistics Support) has a document-type
+definition for ancient Greek drama, although the TEI will be able to
+handle that. Given this state of affairs and assuming that the
+technical-journal producers and the commercial vendors decide to use the
+other two types, then an institution like the Library of Congress, which
+might receive all of their publications, would have to be able to handle
+three different types of document definitions and tag sets and be able to
+distinguish among them.
+
+Office Document Architecture (ODA) has some advantages that flow from its
+tight focus on office documents and clear directions for implementation.
+Much of the ODA standard is easier to read and clearer at first reading
+than the SGML standard, which is extremely general. What that means is
+that if one wants to use graphics in TIFF and ODA, one is stuck, because
+ODA defines graphics formats while TIFF does not, whereas SGML says the
+world is not waiting for this work group to create another graphics format.
+What is needed is an ability to use whatever graphics format one wants.
+
+The TEI provides a socket that allows one to connect the SGML document to
+the graphics. The notation that the graphics are in is clearly a choice
+that one needs to make based on her or his environment, and that is one
+advantage. SGML is less megalomaniacal in attempting to define formats
+for all kinds of information, though more megalomaniacal in attempting to
+cover all sorts of documents. The other advantage is that the model of
+text represented by SGML is simply an order of magnitude richer and more
+flexible than the model of text offered by ODA. Both offer hierarchical
+structures, but SGML recognizes that the hierarchical model of the text
+that one is looking at may not have been in the minds of the designers,
+whereas ODA does not.
+
+ODA is not really aiming for the kind of document that the TEI wants to
+encompass. The TEI can handle the kind of material ODA has, as well as a
+significantly broader range of material. ODA seems to be very much
+focused on office documents, which is what it started out being called--
+office document architecture.
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+CALALUCA * Text-encoding from a publisher's perspective *
+Responsibilities of a publisher * Reproduction of Migne's Latin series
+whole and complete with SGML tags based on perceived need and expected
+use * Particular decisions arising from the general decision to produce
+and publish PLD *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The final speaker in this session, Eric CALALUCA, vice president,
+Chadwyck-Healey, Inc., spoke from the perspective of a publisher re
+text-encoding, rather than as one qualified to discuss methods of
+encoding data, and observed that the presenters sitting in the room,
+whether they had chosen to or not, were acting as publishers: making
+choices, gathering data, gathering information, and making assessments.
+CALALUCA offered the hard-won conviction that in publishing very large
+text files (such as PLD), one cannot avoid making personal judgments of
+appropriateness and structure.
+
+In CALALUCA's view, encoding decisions stem from prior judgments. Two
+notions have become axioms for him in the consideration of future sources
+for electronic publication: 1) electronic text publishing is as personal
+as any other kind of publishing, and questions of if and how to encode
+the data are simply a consequence of that prior decision; 2) all
+personal decisions are open to criticism, which is unavoidable.
+
+CALALUCA rehearsed his role as a publisher or, better, as an intermediary
+between what is viewed as a sound idea and the people who would make use
+of it. Finding the specialist to advise in this process is the core of
+that function. The publisher must monitor and hug the fine line between
+giving users what they want and suggesting what they might need. One
+responsibility of a publisher is to represent the desires of scholars and
+research librarians as opposed to bullheadedly forcing them into areas
+they would not choose to enter.
+
+CALALUCA likened the questions being raised today about data structure
+and standards to the decisions faced by the Abbe Migne himself during
+production of the Patrologia series in the mid-nineteenth century.
+Chadwyck-Healey's decision to reproduce Migne's Latin series whole and
+complete with SGML tags was also based upon a perceived need and an
+expected use. In the same way that Migne's work came to be far more than
+a simple handbook for clerics, PLD is already far more than a database
+for theologians. It is a bedrock source for the study of Western
+civilization, CALALUCA asserted.
+
+In regard to the decision to produce and publish PLD, the editorial board
+offered direct judgments on the question of appropriateness of these
+texts for conversion, their encoding and their distribution, and
+concluded that the best possible project was one that avoided overt
+intrusions or exclusions in so important a resource. Thus, the general
+decision to transmit the original collection as clearly as possible with
+the widest possible avenues for use led to other decisions: 1) To encode
+the data or not, SGML or not, TEI or not. Again, the expected user
+community asserted the need for normative tagging structures of important
+humanities texts, and the TEI seemed the most appropriate structure for
+that purpose. Research librarians, who are trained to view the larger
+impact of electronic text sources on 80 or 90 or 100 doctoral
+disciplines, loudly approved the decision to include tagging. They see
+what is coming better than the specialist who is completely focused on
+one edition of Ambrose's De Anima, and they also understand that the
+potential uses exceed present expectations. 2) What will be tagged and
+what will not. Once again, the board realized that one must tag the
+obvious. But in no way should one attempt to identify through encoding
+schemes every single discrete area of a text that might someday be
+searched. That was another decision. Searching by a column number, an
+author, a word, a volume, permitting combination searches, and tagging
+notations seemed logical choices as core elements. 3) How does one make
+the data available? Tieing it to a CD-ROM edition creates limitations,
+but a magnetic tape file that is very large, is accompanied by the
+encoding specifications, and that allows one to make local modifications
+also allows one to incorporate any changes one may desire within the
+bounds of private research, though exporting tag files from a CD-ROM
+could serve just as well. Since no one on the board could possibly
+anticipate each and every way in which a scholar might choose to mine
+this data bank, it was decided to satisfy the basics and make some
+provisions for what might come. 4) Not to encode the database would rob
+it of the interchangeability and portability these important texts should
+accommodate. For CALALUCA, the extensive options presented by full-text
+searching require care in text selection and strongly support encoding of
+data to facilitate the widest possible search strategies. Better
+software can always be created, but summoning the resources, the people,
+and the energy to reconvert the text is another matter.
+
+PLD is being encoded, captured, and distributed, because to
+Chadwyck-Healey and the board it offers the widest possible array of
+future research applications that can be seen today. CALALUCA concluded
+by urging the encoding of all important text sources in whatever way
+seems most appropriate and durable at the time, without blanching at the
+thought that one's work may require emendation in the future. (Thus,
+Chadwyck-Healey produced a very large humanities text database before the
+final release of the TEI Guidelines.)
+
+ ******
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+DISCUSSION * Creating texts with markup advocated * Trends in encoding *
+The TEI and the issue of interchangeability of standards * A
+misconception concerning the TEI * Implications for an institution like
+LC in the event that a multiplicity of DTDs develops * Producing images
+as a first step towards possible conversion to full text through
+character recognition * The AAP tag sets as a common starting point and
+the need for caution *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+HOCKEY prefaced the discussion that followed with several comments in
+favor of creating texts with markup and on trends in encoding. In the
+future, when many more texts are available for on-line searching, real
+problems in finding what is wanted will develop, if one is faced with
+millions of words of data. It therefore becomes important to consider
+putting markup in texts to help searchers home in on the actual things
+they wish to retrieve. Various approaches to refining retrieval methods
+toward this end include building on a computer version of a dictionary
+and letting the computer look up words in it to obtain more information
+about the semantic structure or semantic field of a word, its grammatical
+structure, and syntactic structure.
+
+HOCKEY commented on the present keen interest in the encoding world
+in creating: 1) machine-readable versions of dictionaries that can be
+initially tagged in SGML, which gives a structure to the dictionary entry;
+these entries can then be converted into a more rigid or otherwise
+different database structure inside the computer, which can be treated as
+a dynamic tool for searching mechanisms; 2) large bodies of text to study
+the language. In order to incorporate more sophisticated mechanisms,
+more about how words behave needs to be known, which can be learned in
+part from information in dictionaries. However, the last ten years have
+seen much interest in studying the structure of printed dictionaries
+converted into computer-readable form. The information one derives about
+many words from those is only partial, one or two definitions of the
+common or the usual meaning of a word, and then numerous definitions of
+unusual usages. If the computer is using a dictionary to help retrieve
+words in a text, it needs much more information about the common usages,
+because those are the ones that occur over and over again. Hence the
+current interest in developing large bodies of text in computer-readable
+form in order to study the language. Several projects are engaged in
+compiling, for example, 100 million words. HOCKEY described one with
+which she was associated briefly at Oxford University involving
+compilation of 100 million words of British English: about 10 percent of
+that will contain detailed linguistic tagging encoded in SGML; it will
+have word class taggings, with words identified as nouns, verbs,
+adjectives, or other parts of speech. This tagging can then be used by
+programs which will begin to learn a bit more about the structure of the
+language, and then, can go to tag more text.
+
+HOCKEY said that the more that is tagged accurately, the more one can
+refine the tagging process and thus the bigger body of text one can build
+up with linguistic tagging incorporated into it. Hence, the more tagging
+or annotation there is in the text, the more one may begin to learn about
+language and the more it will help accomplish more intelligent OCR. She
+recommended the development of software tools that will help one begin to
+understand more about a text, which can then be applied to scanning
+images of that text in that format and to using more intelligence to help
+one interpret or understand the text.
+
+HOCKEY posited the need to think about common methods of text-encoding
+for a long time to come, because building these large bodies of text is
+extremely expensive and will only be done once.
+
+In the more general discussion on approaches to encoding that followed,
+these points were made:
+
+BESSER identified the underlying problem with standards that all have to
+struggle with in adopting a standard, namely, the tension between a very
+highly defined standard that is very interchangeable but does not work
+for everyone because something is lacking, and a standard that is less
+defined, more open, more adaptable, but less interchangeable. Contending
+that the way in which people use SGML is not sufficiently defined, BESSER
+wondered 1) if people resist the TEI because they think it is too defined
+in certain things they do not fit into, and 2) how progress with
+interchangeability can be made without frightening people away.
+
+SPERBERG-McQUEEN replied that the published drafts of the TEI had met
+with surprisingly little objection on the grounds that they do not allow
+one to handle X or Y or Z. Particular concerns of the affiliated
+projects have led, in practice, to discussions of how extensions are to
+be made; the primary concern of any project has to be how it can be
+represented locally, thus making interchange secondary. The TEI has
+received much criticism based on the notion that everything in it is
+required or even recommended, which, as it happens, is a misconception
+from the beginning, because none of it is required and very little is
+actually actively recommended for all cases, except that one document
+one's source.
+
+SPERBERG-McQUEEN agreed with BESSER about this trade-off: all the
+projects in a set of twenty TEI-conformant projects will not necessarily
+tag the material in the same way. One result of the TEI will be that the
+easiest problems will be solved--those dealing with the external form of
+the information; but the problem that is hardest in interchange is that
+one is not encoding what another wants, and vice versa. Thus, after
+the adoption of a common notation, the differences in the underlying
+conceptions of what is interesting about texts become more visible.
+The success of a standard like the TEI will lie in the ability of
+the recipient of interchanged texts to use some of what it contains
+and to add the information that was not encoded that one wants, in a
+layered way, so that texts can be gradually enriched and one does not
+have to put in everything all at once. Hence, having a well-behaved
+markup scheme is important.
+
+STEVENS followed up on the paradoxical analogy that BESSER alluded to in
+the example of the MARC records, namely, the formats that are the same
+except that they are different. STEVENS drew a parallel between
+document-type definitions and MARC records for books and serials and maps,
+where one has a tagging structure and there is a text-interchange.
+STEVENS opined that the producers of the information will set the terms
+for the standard (i.e., develop document-type definitions for the users
+of their products), creating a situation that will be problematical for
+an institution like the Library of Congress, which will have to deal with
+the DTDs in the event that a multiplicity of them develops. Thus,
+numerous people are seeking a standard but cannot find the tag set that
+will be acceptable to them and their clients. SPERBERG-McQUEEN agreed
+with this view, and said that the situation was in a way worse: attempting
+to unify arbitrary DTDs resembled attempting to unify a MARC record with a
+bibliographic record done according to the Prussian instructions.
+According to STEVENS, this situation occurred very early in the process.
+
+WATERS recalled from early discussions on Project Open Book the concern
+of many people that merely by producing images, POB was not really
+enhancing intellectual access to the material. Nevertheless, not wishing
+to overemphasize the opposition between imaging and full text, WATERS
+stated that POB views getting the images as a first step toward possibly
+converting to full text through character recognition, if the technology
+is appropriate. WATERS also emphasized that encoding is involved even
+with a set of images.
+
+SPERBERG-McQUEEN agreed with WATERS that one can create an SGML document
+consisting wholly of images. At first sight, organizing graphic images
+with an SGML document may not seem to offer great advantages, but the
+advantages of the scheme WATERS described would be precisely that
+ability to move into something that is more of a multimedia document:
+a combination of transcribed text and page images. WEIBEL concurred in
+this judgment, offering evidence from Project ADAPT, where a page is
+divided into text elements and graphic elements, and in fact the text
+elements are organized by columns and lines. These lines may be used as
+the basis for distributing documents in a network environment. As one
+develops software intelligent enough to recognize what those elements
+are, it makes sense to apply SGML to an image initially, that may, in
+fact, ultimately become more and more text, either through OCR or edited
+OCR or even just through keying. For WATERS, the labor of composing the
+document and saying this set of documents or this set of images belongs
+to this document constitutes a significant investment.
+
+WEIBEL also made the point that the AAP tag sets, while not excessively
+prescriptive, offer a common starting point; they do not define the
+structure of the documents, though. They have some recommendations about
+DTDs one could use as examples, but they do just suggest tag sets. For
+example, the CORE project attempts to use the AAP markup as much as
+possible, but there are clearly areas where structure must be added.
+That in no way contradicts the use of AAP tag sets.
+
+SPERBERG-McQUEEN noted that the TEI prepared a long working paper early
+on about the AAP tag set and what it lacked that the TEI thought it
+needed, and a fairly long critique of the naming conventions, which has
+led to a very different style of naming in the TEI. He stressed the
+importance of the opposition between prescriptive markup, the kind that a
+publisher or anybody can do when producing documents de novo, and
+descriptive markup, in which one has to take what the text carrier
+provides. In these particular tag sets it is easy to overemphasize this
+opposition, because the AAP tag set is extremely flexible. Even if one
+just used the DTDs, they allow almost anything to appear almost anywhere.
+
+ ******
+
+SESSION VI. COPYRIGHT ISSUES
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+PETERS * Several cautions concerning copyright in an electronic
+environment * Review of copyright law in the United States * The notion
+of the public good and the desirability of incentives to promote it *
+What copyright protects * Works not protected by copyright * The rights
+of copyright holders * Publishers' concerns in today's electronic
+environment * Compulsory licenses * The price of copyright in a digital
+medium and the need for cooperation * Additional clarifications * Rough
+justice oftentimes the outcome in numerous copyright matters * Copyright
+in an electronic society * Copyright law always only sets up the
+boundaries; anything can be changed by contract *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Marybeth PETERS, policy planning adviser to the Register of Copyrights,
+Library of Congress, made several general comments and then opened the
+floor to discussion of subjects of interest to the audience.
+
+Having attended several sessions in an effort to gain a sense of what
+people did and where copyright would affect their lives, PETERS expressed
+the following cautions:
+
+ * If one takes and converts materials and puts them in new forms,
+ then, from a copyright point of view, one is creating something and
+ will receive some rights.
+
+ * However, if what one is converting already exists, a question
+ immediately arises about the status of the materials in question.
+
+ * Putting something in the public domain in the United States offers
+ some freedom from anxiety, but distributing it throughout the world
+ on a network is another matter, even if one has put it in the public
+ domain in the United States. Re foreign laws, very frequently a
+ work can be in the public domain in the United States but protected
+ in other countries. Thus, one must consider all of the places a
+ work may reach, lest one unwittingly become liable to being faced
+ with a suit for copyright infringement, or at least a letter
+ demanding discussion of what one is doing.
+
+PETERS reviewed copyright law in the United States. The U.S.
+Constitution effectively states that Congress has the power to enact
+copyright laws for two purposes: 1) to encourage the creation and
+dissemination of intellectual works for the good of society as a whole;
+and, significantly, 2) to give creators and those who package and
+disseminate materials the economic rewards that are due them.
+
+Congress strives to strike a balance, which at times can become an
+emotional issue. The United States has never accepted the notion of the
+natural right of an author so much as it has accepted the notion of the
+public good and the desirability of incentives to promote it. This state
+of affairs, however, has created strains on the international level and
+is the reason for several of the differences in the laws that we have.
+Today the United States protects almost every kind of work that can be
+called an expression of an author. The standard for gaining copyright
+protection is simply originality. This is a low standard and means that
+a work is not copied from something else, as well as shows a certain
+minimal amount of authorship. One can also acquire copyright protection
+for making a new version of preexisting material, provided it manifests
+some spark of creativity.
+
+However, copyright does not protect ideas, methods, systems--only the way
+that one expresses those things. Nor does copyright protect anything
+that is mechanical, anything that does not involve choice, or criteria
+concerning whether or not one should do a thing. For example, the
+results of a process called declicking, in which one mechanically removes
+impure sounds from old recordings, are not copyrightable. On the other
+hand, the choice to record a song digitally and to increase the sound of
+violins or to bring up the tympani constitutes the results of conversion
+that are copyrightable. Moreover, if a work is protected by copyright in
+the United States, one generally needs the permission of the copyright
+owner to convert it. Normally, who will own the new--that is, converted-
+-material is a matter of contract. In the absence of a contract, the
+person who creates the new material is the author and owner. But people
+do not generally think about the copyright implications until after the
+fact. PETERS stressed the need when dealing with copyrighted works to
+think about copyright in advance. One's bargaining power is much greater
+up front than it is down the road.
+
+PETERS next discussed works not protected by copyright, for example, any
+work done by a federal employee as part of his or her official duties is
+in the public domain in the United States. The issue is not wholly free
+of doubt concerning whether or not the work is in the public domain
+outside the United States. Other materials in the public domain include:
+any works published more than seventy-five years ago, and any work
+published in the United States more than twenty-eight years ago, whose
+copyright was not renewed. In talking about the new technology and
+putting material in a digital form to send all over the world, PETERS
+cautioned, one must keep in mind that while the rights may not be an
+issue in the United States, they may be in different parts of the world,
+where most countries previously employed a copyright term of the life of
+the author plus fifty years.
+
+PETERS next reviewed the economics of copyright holding. Simply,
+economic rights are the rights to control the reproduction of a work in
+any form. They belong to the author, or in the case of a work made for
+hire, the employer. The second right, which is critical to conversion,
+is the right to change a work. The right to make new versions is perhaps
+one of the most significant rights of authors, particularly in an
+electronic world. The third right is the right to publish the work and
+the right to disseminate it, something that everyone who deals in an
+electronic medium needs to know. The basic rule is if a copy is sold,
+all rights of distribution are extinguished with the sale of that copy.
+The key is that it must be sold. A number of companies overcome this
+obstacle by leasing or renting their product. These companies argue that
+if the material is rented or leased and not sold, they control the uses
+of a work. The fourth right, and one very important in a digital world,
+is a right of public performance, which means the right to show the work
+sequentially. For example, copyright owners control the showing of a
+CD-ROM product in a public place such as a public library. The reverse
+side of public performance is something called the right of public
+display. Moral rights also exist, which at the federal level apply only
+to very limited visual works of art, but in theory may apply under
+contract and other principles. Moral rights may include the right of an
+author to have his or her name on a work, the right of attribution, and
+the right to object to distortion or mutilation--the right of integrity.
+
+The way copyright law is worded gives much latitude to activities such as
+preservation; to use of material for scholarly and research purposes when
+the user does not make multiple copies; and to the generation of
+facsimile copies of unpublished works by libraries for themselves and
+other libraries. But the law does not allow anyone to become the
+distributor of the product for the entire world. In today's electronic
+environment, publishers are extremely concerned that the entire world is
+networked and can obtain the information desired from a single copy in a
+single library. Hence, if there is to be only one sale, which publishers
+may choose to live with, they will obtain their money in other ways, for
+example, from access and use. Hence, the development of site licenses
+and other kinds of agreements to cover what publishers believe they
+should be compensated for. Any solution that the United States takes
+today has to consider the international arena.
+
+Noting that the United States is a member of the Berne Convention and
+subscribes to its provisions, PETERS described the permissions process.
+She also defined compulsory licenses. A compulsory license, of which the
+United States has had a few, builds into the law the right to use a work
+subject to certain terms and conditions. In the international arena,
+however, the ability to use compulsory licenses is extremely limited.
+Thus, clearinghouses and other collectives comprise one option that has
+succeeded in providing for use of a work. Often overlooked when one
+begins to use copyrighted material and put products together is how
+expensive the permissions process and managing it is. According to
+PETERS, the price of copyright in a digital medium, whatever solution is
+worked out, will include managing and assembling the database. She
+strongly recommended that publishers and librarians or people with
+various backgrounds cooperate to work out administratively feasible
+systems, in order to produce better results.
+
+In the lengthy question-and-answer period that followed PETERS's
+presentation, the following points emerged:
+
+ * The Copyright Office maintains that anything mechanical and
+ totally exhaustive probably is not protected. In the event that
+ what an individual did in developing potentially copyrightable
+ material is not understood, the Copyright Office will ask about the
+ creative choices the applicant chose to make or not to make. As a
+ practical matter, if one believes she or he has made enough of those
+ choices, that person has a right to assert a copyright and someone
+ else must assert that the work is not copyrightable. The more
+ mechanical, the more automatic, a thing is, the less likely it is to
+ be copyrightable.
+
+ * Nearly all photographs are deemed to be copyrightable, but no one
+ worries about them much, because everyone is free to take the same
+ image. Thus, a photographic copyright represents what is called a
+ "thin" copyright. The photograph itself must be duplicated, in
+ order for copyright to be violated.
+
+ * The Copyright Office takes the position that X-rays are not
+ copyrightable because they are mechanical. It can be argued
+ whether or not image enhancement in scanning can be protected. One
+ must exercise care with material created with public funds and
+ generally in the public domain. An article written by a federal
+ employee, if written as part of official duties, is not
+ copyrightable. However, control over a scientific article written
+ by a National Institutes of Health grantee (i.e., someone who
+ receives money from the U.S. government), depends on NIH policy. If
+ the government agency has no policy (and that policy can be
+ contained in its regulations, the contract, or the grant), the
+ author retains copyright. If a provision of the contract, grant, or
+ regulation states that there will be no copyright, then it does not
+ exist. When a work is created, copyright automatically comes into
+ existence unless something exists that says it does not.
+
+ * An enhanced electronic copy of a print copy of an older reference
+ work in the public domain that does not contain copyrightable new
+ material is a purely mechanical rendition of the original work, and
+ is not copyrightable.
+
+ * Usually, when a work enters the public domain, nothing can remove
+ it. For example, Congress recently passed into law the concept of
+ automatic renewal, which means that copyright on any work published
+ between l964 and l978 does not have to be renewed in order to
+ receive a seventy-five-year term. But any work not renewed before
+ 1964 is in the public domain.
+
+ * Concerning whether or not the United States keeps track of when
+ authors die, nothing was ever done, nor is anything being done at
+ the moment by the Copyright Office.
+
+ * Software that drives a mechanical process is itself copyrightable.
+ If one changes platforms, the software itself has a copyright. The
+ World Intellectual Property Organization will hold a symposium 28
+ March through 2 April l993, at Harvard University, on digital
+ technology, and will study this entire issue. If one purchases a
+ computer software package, such as MacPaint, and creates something
+ new, one receives protection only for that which has been added.
+
+PETERS added that often in copyright matters, rough justice is the
+outcome, for example, in collective licensing, ASCAP (i.e., American
+Society of Composers, Authors, and Publishers), and BMI (i.e., Broadcast
+Music, Inc.), where it may seem that the big guys receive more than their
+due. Of course, people ought not to copy a creative product without
+paying for it; there should be some compensation. But the truth of the
+world, and it is not a great truth, is that the big guy gets played on
+the radio more frequently than the little guy, who has to do much more
+until he becomes a big guy. That is true of every author, every
+composer, everyone, and, unfortunately, is part of life.
+
+Copyright always originates with the author, except in cases of works
+made for hire. (Most software falls into this category.) When an author
+sends his article to a journal, he has not relinquished copyright, though
+he retains the right to relinquish it. The author receives absolutely
+everything. The less prominent the author, the more leverage the
+publisher will have in contract negotiations. In order to transfer the
+rights, the author must sign an agreement giving them away.
+
+In an electronic society, it is important to be able to license a writer
+and work out deals. With regard to use of a work, it usually is much
+easier when a publisher holds the rights. In an electronic era, a real
+problem arises when one is digitizing and making information available.
+PETERS referred again to electronic licensing clearinghouses. Copyright
+ought to remain with the author, but as one moves forward globally in the
+electronic arena, a middleman who can handle the various rights becomes
+increasingly necessary.
+
+The notion of copyright law is that it resides with the individual, but
+in an on-line environment, where a work can be adapted and tinkered with
+by many individuals, there is concern. If changes are authorized and
+there is no agreement to the contrary, the person who changes a work owns
+the changes. To put it another way, the person who acquires permission
+to change a work technically will become the author and the owner, unless
+some agreement to the contrary has been made. It is typical for the
+original publisher to try to control all of the versions and all of the
+uses. Copyright law always only sets up the boundaries. Anything can be
+changed by contract.
+
+ ******
+
+SESSION VII. CONCLUSION
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+GENERAL DISCUSSION * Two questions for discussion * Different emphases in
+the Workshop * Bringing the text and image partisans together *
+Desiderata in planning the long-term development of something * Questions
+surrounding the issue of electronic deposit * Discussion of electronic
+deposit as an allusion to the issue of standards * Need for a directory
+of preservation projects in digital form and for access to their
+digitized files * CETH's catalogue of machine-readable texts in the
+humanities * What constitutes a publication in the electronic world? *
+Need for LC to deal with the concept of on-line publishing * LC's Network
+Development Office exploring the limits of MARC as a standard in terms
+of handling electronic information * Magnitude of the problem and the
+need for distributed responsibility in order to maintain and store
+electronic information * Workshop participants to be viewed as a starting
+point * Development of a network version of AM urged * A step toward AM's
+construction of some sort of apparatus for network access * A delicate
+and agonizing policy question for LC * Re the issue of electronic
+deposit, LC urged to initiate a catalytic process in terms of distributed
+responsibility * Suggestions for cooperative ventures * Commercial
+publishers' fears * Strategic questions for getting the image and text
+people to think through long-term cooperation * Clarification of the
+driving force behind both the Perseus and the Cornell Xerox projects *
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+In his role as moderator of the concluding session, GIFFORD raised two
+questions he believed would benefit from discussion: 1) Are there enough
+commonalities among those of us that have been here for two days so that
+we can see courses of action that should be taken in the future? And, if
+so, what are they and who might take them? 2) Partly derivative from
+that, but obviously very dangerous to LC as host, do you see a role for
+the Library of Congress in all this? Of course, the Library of Congress
+holds a rather special status in a number of these matters, because it is
+not perceived as a player with an economic stake in them, but are there
+roles that LC can play that can help advance us toward where we are heading?
+
+Describing himself as an uninformed observer of the technicalities of the
+last two days, GIFFORD detected three different emphases in the Workshop:
+1) people who are very deeply committed to text; 2) people who are almost
+passionate about images; and 3) a few people who are very committed to
+what happens to the networks. In other words, the new networking
+dimension, the accessibility of the processability, the portability of
+all this across the networks. How do we pull those three together?
+
+Adding a question that reflected HOCKEY's comment that this was the
+fourth workshop she had attended in the previous thirty days, FLEISCHHAUER
+wondered to what extent this meeting had reinvented the wheel, or if it
+had contributed anything in the way of bringing together a different group
+of people from those who normally appear on the workshop circuit.
+
+HOCKEY confessed to being struck at this meeting and the one the
+Electronic Pierce Consortium organized the previous week that this was a
+coming together of people working on texts and not images. Attempting to
+bring the two together is something we ought to be thinking about for the
+future: How one can think about working with image material to begin
+with, but structuring it and digitizing it in such a way that at a later
+stage it can be interpreted into text, and find a common way of building
+text and images together so that they can be used jointly in the future,
+with the network support to begin there because that is how people will
+want to access it.
+
+In planning the long-term development of something, which is what is
+being done in electronic text, HOCKEY stressed the importance not only
+of discussing the technical aspects of how one does it but particularly
+of thinking about what the people who use the stuff will want to do.
+But conversely, there are numerous things that people start to do with
+electronic text or material that nobody ever thought of in the beginning.
+
+LESK, in response to the question concerning the role of the Library of
+Congress, remarked the often suggested desideratum of having electronic
+deposit: Since everything is now computer-typeset, an entire decade of
+material that was machine-readable exists, but the publishers frequently
+did not save it; has LC taken any action to have its copyright deposit
+operation start collecting these machine-readable versions? In the
+absence of PETERS, GIFFORD replied that the question was being
+actively considered but that that was only one dimension of the problem.
+Another dimension is the whole question of the integrity of the original
+electronic document. It becomes highly important in science to prove
+authorship. How will that be done?
+
+ERWAY explained that, under the old policy, to make a claim for a
+copyright for works that were published in electronic form, including
+software, one had to submit a paper copy of the first and last twenty
+pages of code--something that represented the work but did not include
+the entire work itself and had little value to anyone. As a temporary
+measure, LC has claimed the right to demand electronic versions of
+electronic publications. This measure entails a proactive role for the
+Library to say that it wants a particular electronic version. Publishers
+then have perhaps a year to submit it. But the real problem for LC is
+what to do with all this material in all these different formats. Will
+the Library mount it? How will it give people access to it? How does LC
+keep track of the appropriate computers, software, and media? The situation
+is so hard to control, ERWAY said, that it makes sense for each publishing
+house to maintain its own archive. But LC cannot enforce that either.
+
+GIFFORD acknowledged LESK's suggestion that establishing a priority
+offered the solution, albeit a fairly complicated one. But who maintains
+that register?, he asked. GRABER noted that LC does attempt to collect a
+Macintosh version and the IBM-compatible version of software. It does
+not collect other versions. But while true for software, BYRUM observed,
+this reply does not speak to materials, that is, all the materials that
+were published that were on somebody's microcomputer or driver tapes
+at a publishing office across the country. LC does well to acquire
+specific machine-readable products selectively that were intended to be
+machine-readable. Materials that were in machine-readable form at one time,
+BYRUM said, would be beyond LC's capability at the moment, insofar as
+attempting to acquire, organize, and preserve them are concerned--and
+preservation would be the most important consideration. In this
+connection, GIFFORD reiterated the need to work out some sense of
+distributive responsibility for a number of these issues, which
+inevitably will require significant cooperation and discussion.
+Nobody can do it all.
+
+LESK suggested that some publishers may look with favor on LC beginning
+to serve as a depository of tapes in an electronic manuscript standard.
+Publishers may view this as a service that they did not have to perform
+and they might send in tapes. However, SPERBERG-McQUEEN countered,
+although publishers have had equivalent services available to them for a
+long time, the electronic text archive has never turned away or been
+flooded with tapes and is forever sending feedback to the depositor.
+Some publishers do send in tapes.
+
+ANDRE viewed this discussion as an allusion to the issue of standards.
+She recommended that the AAP standard and the TEI, which has already been
+somewhat harmonized internationally and which also shares several
+compatibilities with the AAP, be harmonized to ensure sufficient
+compatibility in the software. She drew the line at saying LC ought to
+be the locus or forum for such harmonization.
+
+Taking the group in a slightly different direction, but one where at
+least in the near term LC might play a helpful role, LYNCH remarked the
+plans of a number of projects to carry out preservation by creating
+digital images that will end up in on-line or near-line storage at some
+institution. Presumably, LC will link this material somehow to its
+on-line catalog in most cases. Thus, it is in a digital form. LYNCH had
+the impression that many of these institutions would be willing to make
+those files accessible to other people outside the institution, provided
+that there is no copyright problem. This desideratum will require
+propagating the knowledge that those digitized files exist, so that they
+can end up in other on-line catalogs. Although uncertain about the
+mechanism for achieving this result, LYNCH said that it warranted
+scrutiny because it seemed to be connected to some of the basic issues of
+cataloging and distribution of records. It would be foolish, given the
+amount of work that all of us have to do and our meager resources, to
+discover multiple institutions digitizing the same work. Re microforms,
+LYNCH said, we are in pretty good shape.
+
+BATTIN called this a big problem and noted that the Cornell people (who
+had already departed) were working on it. At issue from the beginning
+was to learn how to catalog that information into RLIN and then into
+OCLC, so that it would be accessible. That issue remains to be resolved.
+LYNCH rejoined that putting it into OCLC or RLIN was helpful insofar as
+somebody who is thinking of performing preservation activity on that work
+could learn about it. It is not necessarily helpful for institutions to
+make that available. BATTIN opined that the idea was that it not only be
+for preservation purposes but for the convenience of people looking for
+this material. She endorsed LYNCH's dictum that duplication of this
+effort was to be avoided by every means.
+
+HOCKEY informed the Workshop about one major current activity of CETH,
+namely a catalogue of machine-readable texts in the humanities. Held on
+RLIN at present, the catalogue has been concentrated on ASCII as opposed
+to digitized images of text. She is exploring ways to improve the
+catalogue and make it more widely available, and welcomed suggestions
+about these concerns. CETH owns the records, which are not just
+restricted to RLIN, and can distribute them however it wishes.
+
+Taking up LESK's earlier question, BATTIN inquired whether LC, since it
+is accepting electronic files and designing a mechanism for dealing with
+that rather than putting books on shelves, would become responsible for
+the National Copyright Depository of Electronic Materials. Of course
+that could not be accomplished overnight, but it would be something LC
+could plan for. GIFFORD acknowledged that much thought was being devoted
+to that set of problems and returned the discussion to the issue raised
+by LYNCH--whether or not putting the kind of records that both BATTIN and
+HOCKEY have been talking about in RLIN is not a satisfactory solution.
+It seemed to him that RLIN answered LYNCH's original point concerning
+some kind of directory for these kinds of materials. In a situation
+where somebody is attempting to decide whether or not to scan this or
+film that or to learn whether or not someone has already done so, LYNCH
+suggested, RLIN is helpful, but it is not helpful in the case of a local,
+on-line catalogue. Further, one would like to have her or his system be
+aware that that exists in digital form, so that one can present it to a
+patron, even though one did not digitize it, if it is out of copyright.
+The only way to make those linkages would be to perform a tremendous
+amount of real-time look-up, which would be awkward at best, or
+periodically to yank the whole file from RLIN and match it against one's
+own stuff, which is a nuisance.
+
+But where, ERWAY inquired, does one stop including things that are
+available with Internet, for instance, in one's local catalogue?
+It almost seems that that is LC's means to acquire access to them.
+That represents LC's new form of library loan. Perhaps LC's new on-line
+catalogue is an amalgamation of all these catalogues on line. LYNCH
+conceded that perhaps that was true in the very long term, but was not
+applicable to scanning in the short term. In his view, the totals cited
+by Yale, 10,000 books over perhaps a four-year period, and 1,000-1,500
+books from Cornell, were not big numbers, while searching all over
+creation for relatively rare occurrences will prove to be less efficient.
+As GIFFORD wondered if this would not be a separable file on RLIN and
+could be requested from them, BATTIN interjected that it was easily
+accessible to an institution. SEVERTSON pointed out that that file, cum
+enhancements, was available with reference information on CD-ROM, which
+makes it a little more available.
+
+In HOCKEY's view, the real question facing the Workshop is what to put in
+this catalogue, because that raises the question of what constitutes a
+publication in the electronic world. (WEIBEL interjected that Eric Joule
+in OCLC's Office of Research is also wrestling with this particular
+problem, while GIFFORD thought it sounded fairly generic.) HOCKEY
+contended that a majority of texts in the humanities are in the hands
+of either a small number of large research institutions or individuals
+and are not generally available for anyone else to access at all.
+She wondered if these texts ought to be catalogued.
+
+After argument proceeded back and forth for several minutes over why
+cataloguing might be a necessary service, LEBRON suggested that this
+issue involved the responsibility of a publisher. The fact that someone
+has created something electronically and keeps it under his or her
+control does not constitute publication. Publication implies
+dissemination. While it would be important for a scholar to let other
+people know that this creation exists, in many respects this is no
+different from an unpublished manuscript. That is what is being accessed
+in there, except that now one is not looking at it in the hard-copy but
+in the electronic environment.
+
+LEBRON expressed puzzlement at the variety of ways electronic publishing
+has been viewed. Much of what has been discussed throughout these two
+days has concerned CD-ROM publishing, whereas in the on-line environment
+that she confronts, the constraints and challenges are very different.
+Sooner or later LC will have to deal with the concept of on-line
+publishing. Taking up the comment ERWAY made earlier about storing
+copies, LEBRON gave her own journal as an example. How would she deposit
+OJCCT for copyright?, she asked, because the journal will exist in the
+mainframe at OCLC and people will be able to access it. Here the
+situation is different, ownership versus access, and is something that
+arises with publication in the on-line environment, faster than is
+sometimes realized. Lacking clear answers to all of these questions
+herself, LEBRON did not anticipate that LC would be able to take a role
+in helping to define some of them for quite a while.
+
+GREENFIELD observed that LC's Network Development Office is attempting,
+among other things, to explore the limits of MARC as a standard in terms
+of handling electronic information. GREENFIELD also noted that Rebecca
+GUENTHER from that office gave a paper to the American Society for
+Information Science (ASIS) summarizing several of the discussion papers
+that were coming out of the Network Development Office. GREENFIELD said
+he understood that that office had a list-server soliciting just the kind
+of feedback received today concerning the difficulties of identifying and
+cataloguing electronic information. GREENFIELD hoped that everybody
+would be aware of that and somehow contribute to that conversation.
+
+Noting two of LC's roles, first, to act as a repository of record for
+material that is copyrighted in this country, and second, to make
+materials it holds available in some limited form to a clientele that
+goes beyond Congress, BESSER suggested that it was incumbent on LC to
+extend those responsibilities to all the things being published in
+electronic form. This would mean eventually accepting electronic
+formats. LC could require that at some point they be in a certain
+limited set of formats, and then develop mechanisms for allowing people
+to access those in the same way that other things are accessed. This
+does not imply that they are on the network and available to everyone.
+LC does that with most of its bibliographic records, BESSER said, which
+end up migrating to the utility (e.g., OCLC) or somewhere else. But just
+as most of LC's books are available in some form through interlibrary
+loan or some other mechanism, so in the same way electronic formats ought
+to be available to others in some format, though with some copyright
+considerations. BESSER was not suggesting that these mechanisms be
+established tomorrow, only that they seemed to fall within LC's purview,
+and that there should be long-range plans to establish them.
+
+Acknowledging that those from LC in the room agreed with BESSER
+concerning the need to confront difficult questions, GIFFORD underscored
+the magnitude of the problem of what to keep and what to select. GIFFORD
+noted that LC currently receives some 31,000 items per day, not counting
+electronic materials, and argued for much more distributed responsibility
+in order to maintain and store electronic information.
+
+BESSER responded that the assembled group could be viewed as a starting
+point, whose initial operating premise could be helping to move in this
+direction and defining how LC could do so, for example, in areas of
+standardization or distribution of responsibility.
+
+FLEISCHHAUER added that AM was fully engaged, wrestling with some of the
+questions that pertain to the conversion of older historical materials,
+which would be one thing that the Library of Congress might do. Several
+points mentioned by BESSER and several others on this question have a
+much greater impact on those who are concerned with cataloguing and the
+networking of bibliographic information, as well as preservation itself.
+
+Speaking directly to AM, which he considered was a largely uncopyrighted
+database, LYNCH urged development of a network version of AM, or
+consideration of making the data in it available to people interested in
+doing network multimedia. On account of the current great shortage of
+digital data that is both appealing and unencumbered by complex rights
+problems, this course of action could have a significant effect on making
+network multimedia a reality.
+
+In this connection, FLEISCHHAUER reported on a fragmentary prototype in
+LC's Office of Information Technology Services that attempts to associate
+digital images of photographs with cataloguing information in ways that
+work within a local area network--a step, so to say, toward AM's
+construction of some sort of apparatus for access. Further, AM has
+attempted to use standard data forms in order to help make that
+distinction between the access tools and the underlying data, and thus
+believes that the database is networkable.
+
+A delicate and agonizing policy question for LC, however, which comes
+back to resources and unfortunately has an impact on this, is to find
+some appropriate, honorable, and legal cost-recovery possibilities. A
+certain skittishness concerning cost-recovery has made people unsure
+exactly what to do. AM would be highly receptive to discussing further
+LYNCH's offer to test or demonstrate its database in a network
+environment, FLEISCHHAUER said.
+
+Returning the discussion to what she viewed as the vital issue of
+electronic deposit, BATTIN recommended that LC initiate a catalytic
+process in terms of distributed responsibility, that is, bring together
+the distributed organizations and set up a study group to look at all
+these issues and see where we as a nation should move. The broader
+issues of how we deal with the management of electronic information will
+not disappear, but only grow worse.
+
+LESK took up this theme and suggested that LC attempt to persuade one
+major library in each state to deal with its state equivalent publisher,
+which might produce a cooperative project that would be equitably
+distributed around the country, and one in which LC would be dealing with
+a minimal number of publishers and minimal copyright problems.
+
+GRABER remarked the recent development in the scientific community of a
+willingness to use SGML and either deposit or interchange on a fairly
+standardized format. He wondered if a similar movement was taking place
+in the humanities. Although the National Library of Medicine found only
+a few publishers to cooperate in a like venture two or three years ago, a
+new effort might generate a much larger number willing to cooperate.
+
+KIMBALL recounted his unit's (Machine-Readable Collections Reading Room)
+troubles with the commercial publishers of electronic media in acquiring
+materials for LC's collections, in particular the publishers' fear that
+they would not be able to cover their costs and would lose control of
+their products, that LC would give them away or sell them and make
+profits from them. He doubted that the publishing industry was prepared
+to move into this area at the moment, given its resistance to allowing LC
+to use its machine-readable materials as the Library would like.
+
+The copyright law now addresses compact disk as a medium, and LC can
+request one copy of that, or two copies if it is the only version, and
+can request copies of software, but that fails to address magazines or
+books or anything like that which is in machine-readable form.
+
+GIFFORD acknowledged the thorny nature of this issue, which he illustrated
+with the example of the cumbersome process involved in putting a copy of a
+scientific database on a LAN in LC's science reading room. He also
+acknowledged that LC needs help and could enlist the energies and talents
+of Workshop participants in thinking through a number of these problems.
+
+GIFFORD returned the discussion to getting the image and text people to
+think through together where they want to go in the long term. MYLONAS
+conceded that her experience at the Pierce Symposium the previous week at
+Georgetown University and this week at LC had forced her to reevaluate
+her perspective on the usefulness of text as images. MYLONAS framed the
+issues in a series of questions: How do we acquire machine-readable
+text? Do we take pictures of it and perform OCR on it later? Is it
+important to obtain very high-quality images and text, etc.?
+FLEISCHHAUER agreed with MYLONAS's framing of strategic questions, adding
+that a large institution such as LC probably has to do all of those
+things at different times. Thus, the trick is to exercise judgment. The
+Workshop had added to his and AM's considerations in making those
+judgments. Concerning future meetings or discussions, MYLONAS suggested
+that screening priorities would be helpful.
+
+WEIBEL opined that the diversity reflected in this group was a sign both
+of the health and of the immaturity of the field, and more time would
+have to pass before we convince one another concerning standards.
+
+An exchange between MYLONAS and BATTIN clarified the point that the
+driving force behind both the Perseus and the Cornell Xerox projects was
+the preservation of knowledge for the future, not simply for particular
+research use. In the case of Perseus, MYLONAS said, the assumption was
+that the texts would not be entered again into electronically readable
+form. SPERBERG-McQUEEN added that a scanned image would not serve as an
+archival copy for purposes of preservation in the case of, say, the Bill
+of Rights, in the sense that the scanned images are effectively the
+archival copies for the Cornell mathematics books.
+
+
+ *** *** *** ****** *** *** ***
+
+
+ Appendix I: PROGRAM
+
+
+
+ WORKSHOP
+ ON
+ ELECTRONIC
+ TEXTS
+
+
+
+ 9-10 June 1992
+
+ Library of Congress
+ Washington, D.C.
+
+
+
+ Supported by a Grant from the David and Lucile Packard Foundation
+
+
+Tuesday, 9 June 1992
+
+NATIONAL DEMONSTRATION LAB, ATRIUM, LIBRARY MADISON
+
+8:30 AM Coffee and Danish, registration
+
+9:00 AM Welcome
+
+ Prosser Gifford, Director for Scholarly Programs, and Carl
+ Fleischhauer, Coordinator, American Memory, Library of
+ Congress
+
+9:l5 AM Session I. Content in a New Form: Who Will Use It and What
+ Will They Do?
+
+ Broad description of the range of electronic information.
+ Characterization of who uses it and how it is or may be used.
+ In addition to a look at scholarly uses, this session will
+ include a presentation on use by students (K-12 and college)
+ and the general public.
+
+ Moderator: James Daly
+ Avra Michelson, Archival Research and Evaluation Staff,
+ National Archives and Records Administration (Overview)
+ Susan H. Veccia, Team Leader, American Memory, User Evaluation,
+ and
+ Joanne Freeman, Associate Coordinator, American Memory, Library
+ of Congress (Beyond the scholar)
+
+10:30-
+11:00 AM Break
+
+11:00 AM Session II. Show and Tell.
+
+ Each presentation to consist of a fifteen-minute
+ statement/show; group discussion will follow lunch.
+
+ Moderator: Jacqueline Hess, Director, National Demonstration
+ Lab
+
+ 1. A classics project, stressing texts and text retrieval
+ more than multimedia: Perseus Project, Harvard
+ University
+ Elli Mylonas, Managing Editor
+
+ 2. Other humanities projects employing the emerging norms of
+ the Text Encoding Initiative (TEI): Chadwyck-Healey's
+ The English Poetry Full Text Database and/or Patrologia
+ Latina Database
+ Eric M. Calaluca, Vice President, Chadwyck-Healey, Inc.
+
+ 3. American Memory
+ Carl Fleischhauer, Coordinator, and
+ Ricky Erway, Associate Coordinator, Library of Congress
+
+ 4. Founding Fathers example from Packard Humanities
+ Institute: The Papers of George Washington, University
+ of Virginia
+ Dorothy Twohig, Managing Editor, and/or
+ David Woodley Packard
+
+ 5. An electronic medical journal offering graphics and
+ full-text searchability: The Online Journal of Current
+ Clinical Trials, American Association for the Advancement
+ of Science
+ Maria L. Lebron, Managing Editor
+
+ 6. A project that offers facsimile images of pages but omits
+ searchable text: Cornell math books
+ Lynne K. Personius, Assistant Director, Cornell
+ Information Technologies for Scholarly Information
+ Sources, Cornell University
+
+12:30 PM Lunch (Dining Room A, Library Madison 620. Exhibits
+ available.)
+
+1:30 PM Session II. Show and Tell (Cont'd.).
+
+3:00-
+3:30 PM Break
+
+3:30-
+5:30 PM Session III. Distribution, Networks, and Networking: Options
+ for Dissemination.
+
+ Published disks: University presses and public-sector
+ publishers, private-sector publishers
+ Computer networks
+
+ Moderator: Robert G. Zich, Special Assistant to the Associate
+ Librarian for Special Projects, Library of Congress
+ Clifford A. Lynch, Director, Library Automation, University of
+ California
+ Howard Besser, School of Library and Information Science,
+ University of Pittsburgh
+ Ronald L. Larsen, Associate Director of Libraries for
+ Information Technology, University of Maryland at College
+ Park
+ Edwin B. Brownrigg, Executive Director, Memex Research
+ Institute
+
+6:30 PM Reception (Montpelier Room, Library Madison 619.)
+
+ ******
+
+Wednesday, 10 June 1992
+
+DINING ROOM A, LIBRARY MADISON 620
+
+8:30 AM Coffee and Danish
+
+9:00 AM Session IV. Image Capture, Text Capture, Overview of Text and
+ Image Storage Formats.
+
+ Moderator: William L. Hooton, Vice President of Operations,
+ I-NET
+
+ A) Principal Methods for Image Capture of Text:
+ Direct scanning
+ Use of microform
+
+ Anne R. Kenney, Assistant Director, Department of Preservation
+ and Conservation, Cornell University
+ Pamela Q.J. Andre, Associate Director, Automation, and
+ Judith A. Zidar, Coordinator, National Agricultural Text
+ Digitizing Program (NATDP), National Agricultural Library
+ (NAL)
+ Donald J. Waters, Head, Systems Office, Yale University Library
+
+ B) Special Problems:
+ Bound volumes
+ Conservation
+ Reproducing printed halftones
+
+ Carl Fleischhauer, Coordinator, American Memory, Library of
+ Congress
+ George Thoma, Chief, Communications Engineering Branch,
+ National Library of Medicine (NLM)
+
+10:30-
+11:00 AM Break
+
+11:00 AM Session IV. Image Capture, Text Capture, Overview of Text and
+ Image Storage Formats (Cont'd.).
+
+ C) Image Standards and Implications for Preservation
+
+ Jean Baronas, Senior Manager, Department of Standards and
+ Technology, Association for Information and Image Management
+ (AIIM)
+ Patricia Battin, President, The Commission on Preservation and
+ Access (CPA)
+
+ D) Text Conversion:
+ OCR vs. rekeying
+ Standards of accuracy and use of imperfect texts
+ Service bureaus
+
+ Stuart Weibel, Senior Research Specialist, Online Computer
+ Library Center, Inc. (OCLC)
+ Michael Lesk, Executive Director, Computer Science Research,
+ Bellcore
+ Ricky Erway, Associate Coordinator, American Memory, Library of
+ Congress
+ Pamela Q.J. Andre, Associate Director, Automation, and
+ Judith A. Zidar, Coordinator, National Agricultural Text
+ Digitizing Program (NATDP), National Agricultural Library
+ (NAL)
+
+12:30-
+1:30 PM Lunch
+
+1:30 PM Session V. Approaches to Preparing Electronic Texts.
+
+ Discussion of approaches to structuring text for the computer;
+ pros and cons of text coding, description of methods in
+ practice, and comparison of text-coding methods.
+
+ Moderator: Susan Hockey, Director, Center for Electronic Texts
+ in the Humanities (CETH), Rutgers and Princeton Universities
+ David Woodley Packard
+ C.M. Sperberg-McQueen, Editor, Text Encoding Initiative (TEI),
+ University of Illinois-Chicago
+ Eric M. Calaluca, Vice President, Chadwyck-Healey, Inc.
+
+3:30-
+4:00 PM Break
+
+4:00 PM Session VI. Copyright Issues.
+
+ Marybeth Peters, Policy Planning Adviser to the Register of
+ Copyrights, Library of Congress
+
+5:00 PM Session VII. Conclusion.
+
+ General discussion.
+ What topics were omitted or given short shrift that anyone
+ would like to talk about now?
+ Is there a "group" here? What should the group do next, if
+ anything? What should the Library of Congress do next, if
+ anything?
+ Moderator: Prosser Gifford, Director for Scholarly Programs,
+ Library of Congress
+
+6:00 PM Adjourn
+
+
+ *** *** *** ****** *** *** ***
+
+
+ Appendix II: ABSTRACTS
+
+
+SESSION I
+
+Avra MICHELSON Forecasting the Use of Electronic Texts by
+ Social Sciences and Humanities Scholars
+
+This presentation explores the ways in which electronic texts are likely
+to be used by the non-scientific scholarly community. Many of the
+remarks are drawn from a report the speaker coauthored with Jeff
+Rothenberg, a computer scientist at The RAND Corporation.
+
+The speaker assesses 1) current scholarly use of information technology
+and 2) the key trends in information technology most relevant to the
+research process, in order to predict how social sciences and humanities
+scholars are apt to use electronic texts. In introducing the topic,
+current use of electronic texts is explored broadly within the context of
+scholarly communication. From the perspective of scholarly
+communication, the work of humanities and social sciences scholars
+involves five processes: 1) identification of sources, 2) communication
+with colleagues, 3) interpretation and analysis of data, 4) dissemination
+of research findings, and 5) curriculum development and instruction. The
+extent to which computation currently permeates aspects of scholarly
+communication represents a viable indicator of the prospects for
+electronic texts.
+
+The discussion of current practice is balanced by an analysis of key
+trends in the scholarly use of information technology. These include the
+trends toward end-user computing and connectivity, which provide a
+framework for forecasting the use of electronic texts through this
+millennium. The presentation concludes with a summary of the ways in
+which the nonscientific scholarly community can be expected to use
+electronic texts, and the implications of that use for information
+providers.
+
+Susan VECCIA and Joanne FREEMAN Electronic Archives for the Public:
+ Use of American Memory in Public and
+ School Libraries
+
+This joint discussion focuses on nonscholarly applications of electronic
+library materials, specifically addressing use of the Library of Congress
+American Memory (AM) program in a small number of public and school
+libraries throughout the United States. AM consists of selected Library
+of Congress primary archival materials, stored on optical media
+(CD-ROM/videodisc), and presented with little or no editing. Many
+collections are accompanied by electronic introductions and user's guides
+offering background information and historical context. Collections
+represent a variety of formats including photographs, graphic arts,
+motion pictures, recorded sound, music, broadsides and manuscripts,
+books, and pamphlets.
+
+In 1991, the Library of Congress began a nationwide evaluation of AM in
+different types of institutions. Test sites include public libraries,
+elementary and secondary school libraries, college and university
+libraries, state libraries, and special libraries. Susan VECCIA and
+Joanne FREEMAN will discuss their observations on the use of AM by the
+nonscholarly community, using evidence gleaned from this ongoing
+evaluation effort.
+
+VECCIA will comment on the overall goals of the evaluation project, and
+the types of public and school libraries included in this study. Her
+comments on nonscholarly use of AM will focus on the public library as a
+cultural and community institution, often bridging the gap between formal
+and informal education. FREEMAN will discuss the use of AM in school
+libraries. Use by students and teachers has revealed some broad
+questions about the use of electronic resources, as well as definite
+benefits gained by the "nonscholar." Topics will include the problem of
+grasping content and context in an electronic environment, the stumbling
+blocks created by "new" technologies, and the unique skills and interests
+awakened through use of electronic resources.
+
+SESSION II
+
+Elli MYLONAS The Perseus Project: Interactive Sources and
+ Studies in Classical Greece
+
+The Perseus Project (5) has just released Perseus 1.0, the first publicly
+available version of its hypertextual database of multimedia materials on
+classical Greece. Perseus is designed to be used by a wide audience,
+comprised of readers at the student and scholar levels. As such, it must
+be able to locate information using different strategies, and it must
+contain enough detail to serve the different needs of its users. In
+addition, it must be delivered so that it is affordable to its target
+audience. [These problems and the solutions we chose are described in
+Mylonas, "An Interface to Classical Greek Civilization," JASIS 43:2,
+March 1992.]
+
+In order to achieve its objective, the project staff decided to make a
+conscious separation between selecting and converting textual, database,
+and image data on the one hand, and putting it into a delivery system on
+the other. That way, it is possible to create the electronic data
+without thinking about the restrictions of the delivery system. We have
+made a great effort to choose system-independent formats for our data,
+and to put as much thought and work as possible into structuring it so
+that the translation from paper to electronic form will enhance the value
+of the data. [A discussion of these solutions as of two years ago is in
+Elli Mylonas, Gregory Crane, Kenneth Morrell, and D. Neel Smith, "The
+Perseus Project: Data in the Electronic Age," in Accessing Antiquity:
+The Computerization of Classical Databases, J. Solomon and T. Worthen
+(eds.), University of Arizona Press, in press.]
+
+Much of the work on Perseus is focused on collecting and converting the
+data on which the project is based. At the same time, it is necessary to
+provide means of access to the information, in order to make it usable,
+and them to investigate how it is used. As we learn more about what
+students and scholars from different backgrounds do with Perseus, we can
+adjust our data collection, and also modify the system to accommodate
+them. In creating a delivery system for general use, we have tried to
+avoid favoring any one type of use by allowing multiple forms of access
+to and navigation through the system.
+
+The way text is handled exemplifies some of these principles. All text
+in Perseus is tagged using SGML, following the guidelines of the Text
+Encoding Initiative (TEI). This markup is used to index the text, and
+process it so that it can be imported into HyperCard. No SGML markup
+remains in the text that reaches the user, because currently it would be
+too expensive to create a system that acts on SGML in real time.
+However, the regularity provided by SGML is essential for verifying the
+content of the texts, and greatly speeds all the processing performed on
+them. The fact that the texts exist in SGML ensures that they will be
+relatively easy to port to different hardware and software, and so will
+outlast the current delivery platform. Finally, the SGML markup
+incorporates existing canonical reference systems (chapter, verse, line,
+etc.); indexing and navigation are based on these features. This ensures
+that the same canonical reference will always resolve to the same point
+within a text, and that all versions of our texts, regardless of delivery
+platform (even paper printouts) will function the same way.
+
+In order to provide tools for users, the text is processed by a
+morphological analyzer, and the results are stored in a database.
+Together with the index, the Greek-English Lexicon, and the index of all
+the English words in the definitions of the lexicon, the morphological
+analyses comprise a set of linguistic tools that allow users of all
+levels to work with the textual information, and to accomplish different
+tasks. For example, students who read no Greek may explore a concept as
+it appears in Greek texts by using the English-Greek index, and then
+looking up works in the texts and translations, or scholars may do
+detailed morphological studies of word use by using the morphological
+analyses of the texts. Because these tools were not designed for any one
+use, the same tools and the same data can be used by both students and
+scholars.
+
+NOTES:
+ (5) Perseus is based at Harvard University, with collaborators at
+ several other universities. The project has been funded primarily
+ by the Annenberg/CPB Project, as well as by Harvard University,
+ Apple Computer, and others. It is published by Yale University
+ Press. Perseus runs on Macintosh computers, under the HyperCard
+ program.
+
+Eric CALALUCA
+
+Chadwyck-Healey embarked last year on two distinct yet related full-text
+humanities database projects.
+
+The English Poetry Full-Text Database and the Patrologia Latina Database
+represent new approaches to linguistic research resources. The size and
+complexity of the projects present problems for electronic publishers,
+but surmountable ones if they remain abreast of the latest possibilities
+in data capture and retrieval software techniques.
+
+The issues which required address prior to the commencement of the
+projects were legion:
+
+ 1. Editorial selection (or exclusion) of materials in each
+ database
+
+ 2. Deciding whether or not to incorporate a normative encoding
+ structure into the databases?
+ A. If one is selected, should it be SGML?
+ B. If SGML, then the TEI?
+
+ 3. Deliver as CD-ROM, magnetic tape, or both?
+
+ 4. Can one produce retrieval software advanced enough for the
+ postdoctoral linguist, yet accessible enough for unattended
+ general use? Should one try?
+
+ 5. Re fair and liberal networking policies, what are the risks to
+ an electronic publisher?
+
+ 6. How does the emergence of national and international education
+ networks affect the use and viability of research projects
+ requiring high investment? Do the new European Community
+ directives concerning database protection necessitate two
+ distinct publishing projects, one for North America and one for
+ overseas?
+
+From new notions of "scholarly fair use" to the future of optical media,
+virtually every issue related to electronic publishing was aired. The
+result is two projects which have been constructed to provide the quality
+research resources with the fewest encumbrances to use by teachers and
+private scholars.
+
+Dorothy TWOHIG
+
+In spring 1988 the editors of the papers of George Washington, John
+Adams, Thomas Jefferson, James Madison, and Benjamin Franklin were
+approached by classics scholar David Packard on behalf of the Packard
+Humanities Foundation with a proposal to produce a CD-ROM edition of the
+complete papers of each of the Founding Fathers. This electronic edition
+will supplement the published volumes, making the documents widely
+available to students and researchers at reasonable cost. We estimate
+that our CD-ROM edition of Washington's Papers will be substantially
+completed within the next two years and ready for publication. Within
+the next ten years or so, similar CD-ROM editions of the Franklin, Adams,
+Jefferson, and Madison papers also will be available. At the Library of
+Congress's session on technology, I would like to discuss not only the
+experience of the Washington Papers in producing the CD-ROM edition, but
+the impact technology has had on these major editorial projects.
+Already, we are editing our volumes with an eye to the material that will
+be readily available in the CD-ROM edition. The completed electronic
+edition will provide immense possibilities for the searching of documents
+for information in a way never possible before. The kind of technical
+innovations that are currently available and on the drawing board will
+soon revolutionize historical research and the production of historical
+documents. Unfortunately, much of this new technology is not being used
+in the planning stages of historical projects, simply because many
+historians are aware only in the vaguest way of its existence. At least
+two major new historical editing projects are considering microfilm
+editions, simply because they are not aware of the possibilities of
+electronic alternatives and the advantages of the new technology in terms
+of flexibility and research potential compared to microfilm. In fact,
+too many of us in history and literature are still at the stage of
+struggling with our PCs. There are many historical editorial projects in
+progress presently, and an equal number of literary projects. While the
+two fields have somewhat different approaches to textual editing, there
+are ways in which electronic technology can be of service to both.
+
+Since few of the editors involved in the Founding Fathers CD-ROM editions
+are technical experts in any sense, I hope to point out in my discussion
+of our experience how many of these electronic innovations can be used
+successfully by scholars who are novices in the world of new technology.
+One of the major concerns of the sponsors of the multitude of new
+scholarly editions is the limited audience reached by the published
+volumes. Most of these editions are being published in small quantities
+and the publishers' price for them puts them out of the reach not only of
+individual scholars but of most public libraries and all but the largest
+educational institutions. However, little attention is being given to
+ways in which technology can bypass conventional publication to make
+historical and literary documents more widely available.
+
+What attracted us most to the CD-ROM edition of The Papers of George
+Washington was the fact that David Packard's aim was to make a complete
+edition of all of the 135,000 documents we have collected available in an
+inexpensive format that would be placed in public libraries, small
+colleges, and even high schools. This would provide an audience far
+beyond our present 1,000-copy, $45 published edition. Since the CD-ROM
+edition will carry none of the explanatory annotation that appears in the
+published volumes, we also feel that the use of the CD-ROM will lead many
+researchers to seek out the published volumes.
+
+In addition to ignorance of new technical advances, I have found that too
+many editors--and historians and literary scholars--are resistant and
+even hostile to suggestions that electronic technology may enhance their
+work. I intend to discuss some of the arguments traditionalists are
+advancing to resist technology, ranging from distrust of the speed with
+which it changes (we are already wondering what is out there that is
+better than CD-ROM) to suspicion of the technical language used to
+describe electronic developments.
+
+Maria LEBRON
+
+The Online Journal of Current Clinical Trials, a joint venture of the
+American Association for the Advancement of Science (AAAS) and the Online
+Computer Library Center, Inc. (OCLC), is the first peer-reviewed journal
+to provide full text, tabular material, and line illustrations on line.
+This presentation will discuss the genesis and start-up period of the
+journal. Topics of discussion will include historical overview,
+day-to-day management of the editorial peer review, and manuscript
+tagging and publication. A demonstration of the journal and its features
+will accompany the presentation.
+
+Lynne PERSONIUS
+
+Cornell University Library, Cornell Information Technologies, and Xerox
+Corporation, with the support of the Commission on Preservation and
+Access, and Sun Microsystems, Inc., have been collaborating in a project
+to test a prototype system for recording brittle books as digital images
+and producing, on demand, high-quality archival paper replacements. The
+project goes beyond that, however, to investigate some of the issues
+surrounding scanning, storing, retrieving, and providing access to
+digital images in a network environment.
+
+The Joint Study in Digital Preservation began in January 1990. Xerox
+provided the College Library Access and Storage System (CLASS) software,
+a prototype 600-dots-per-inch (dpi) scanner, and the hardware necessary
+to support network printing on the DocuTech printer housed in Cornell's
+Computing and Communications Center (CCC).
+
+The Cornell staff using the hardware and software became an integral part
+of the development and testing process for enhancements to the CLASS
+software system. The collaborative nature of this relationship is
+resulting in a system that is specifically tailored to the preservation
+application.
+
+A digital library of 1,000 volumes (or approximately 300,000 images) has
+been created and is stored on an optical jukebox that resides in CCC.
+The library includes a collection of select mathematics monographs that
+provides mathematics faculty with an opportunity to use the electronic
+library. The remaining volumes were chosen for the library to test the
+various capabilities of the scanning system.
+
+One project objective is to provide users of the Cornell library and the
+library staff with the ability to request facsimiles of digitized images
+or to retrieve the actual electronic image for browsing. A prototype
+viewing workstation has been created by Xerox, with input into the design
+by a committee of Cornell librarians and computer professionals. This
+will allow us to experiment with patron access to the images that make up
+the digital library. The viewing station provides search, retrieval, and
+(ultimately) printing functions with enhancements to facilitate
+navigation through multiple documents.
+
+Cornell currently is working to extend access to the digital library to
+readers using workstations from their offices. This year is devoted to
+the development of a network resident image conversion and delivery
+server, and client software that will support readers who use Apple
+Macintosh computers, IBM windows platforms, and Sun workstations.
+Equipment for this development was provided by Sun Microsystems with
+support from the Commission on Preservation and Access.
+
+During the show-and-tell session of the Workshop on Electronic Texts, a
+prototype view station will be demonstrated. In addition, a display of
+original library books that have been digitized will be available for
+review with associated printed copies for comparison. The fifteen-minute
+overview of the project will include a slide presentation that
+constitutes a "tour" of the preservation digitizing process.
+
+The final network-connected version of the viewing station will provide
+library users with another mechanism for accessing the digital library,
+and will also provide the capability of viewing images directly. This
+will not require special software, although a powerful computer with good
+graphics will be needed.
+
+The Joint Study in Digital Preservation has generated a great deal of
+interest in the library community. Unfortunately, or perhaps
+fortunately, this project serves to raise a vast number of other issues
+surrounding the use of digital technology for the preservation and use of
+deteriorating library materials, which subsequent projects will need to
+examine. Much work remains.
+
+SESSION III
+
+Howard BESSER Networking Multimedia Databases
+
+What do we have to consider in building and distributing databases of
+visual materials in a multi-user environment? This presentation examines
+a variety of concerns that need to be addressed before a multimedia
+database can be set up in a networked environment.
+
+In the past it has not been feasible to implement databases of visual
+materials in shared-user environments because of technological barriers.
+Each of the two basic models for multi-user multimedia databases has
+posed its own problem. The analog multimedia storage model (represented
+by Project Athena's parallel analog and digital networks) has required an
+incredibly complex (and expensive) infrastructure. The economies of
+scale that make multi-user setups cheaper per user served do not operate
+in an environment that requires a computer workstation, videodisc player,
+and two display devices for each user.
+
+The digital multimedia storage model has required vast amounts of storage
+space (as much as one gigabyte per thirty still images). In the past the
+cost of such a large amount of storage space made this model a
+prohibitive choice as well. But plunging storage costs are finally
+making this second alternative viable.
+
+If storage no longer poses such an impediment, what do we need to
+consider in building digitally stored multi-user databases of visual
+materials? This presentation will examine the networking and
+telecommunication constraints that must be overcome before such databases
+can become commonplace and useful to a large number of people.
+
+The key problem is the vast size of multimedia documents, and how this
+affects not only storage but telecommunications transmission time.
+Anything slower than T-1 speed is impractical for files of 1 megabyte or
+larger (which is likely to be small for a multimedia document). For
+instance, even on a 56 Kb line it would take three minutes to transfer a
+1-megabyte file. And these figures assume ideal circumstances, and do
+not take into consideration other users contending for network bandwidth,
+disk access time, or the time needed for remote display. Current common
+telephone transmission rates would be completely impractical; few users
+would be willing to wait the hour necessary to transmit a single image at
+2400 baud.
+
+This necessitates compression, which itself raises a number of other
+issues. In order to decrease file sizes significantly, we must employ
+lossy compression algorithms. But how much quality can we afford to
+lose? To date there has been only one significant study done of
+image-quality needs for a particular user group, and this study did not
+look at loss resulting from compression. Only after identifying
+image-quality needs can we begin to address storage and network bandwidth
+needs.
+
+Experience with X-Windows-based applications (such as Imagequery, the
+University of California at Berkeley image database) demonstrates the
+utility of a client-server topology, but also points to the limitation of
+current software for a distributed environment. For example,
+applications like Imagequery can incorporate compression, but current X
+implementations do not permit decompression at the end user's
+workstation. Such decompression at the host computer alleviates storage
+capacity problems while doing nothing to address problems of
+telecommunications bandwidth.
+
+We need to examine the effects on network through-put of moving
+multimedia documents around on a network. We need to examine various
+topologies that will help us avoid bottlenecks around servers and
+gateways. Experience with applications such as these raise still broader
+questions. How closely is the multimedia document tied to the software
+for viewing it? Can it be accessed and viewed from other applications?
+Experience with the MARC format (and more recently with the Z39.50
+protocols) shows how useful it can be to store documents in a form in
+which they can be accessed by a variety of application software.
+
+Finally, from an intellectual-access standpoint, we need to address the
+issue of providing access to these multimedia documents in
+interdisciplinary environments. We need to examine terminology and
+indexing strategies that will allow us to provide access to this material
+in a cross-disciplinary way.
+
+Ronald LARSEN Directions in High-Performance Networking for
+ Libraries
+
+The pace at which computing technology has advanced over the past forty
+years shows no sign of abating. Roughly speaking, each five-year period
+has yielded an order-of-magnitude improvement in price and performance of
+computing equipment. No fundamental hurdles are likely to prevent this
+pace from continuing for at least the next decade. It is only in the
+past five years, though, that computing has become ubiquitous in
+libraries, affecting all staff and patrons, directly or indirectly.
+
+During these same five years, communications rates on the Internet, the
+principal academic computing network, have grown from 56 kbps to 1.5
+Mbps, and the NSFNet backbone is now running 45 Mbps. Over the next five
+years, communication rates on the backbone are expected to exceed 1 Gbps.
+Growth in both the population of network users and the volume of network
+traffic has continued to grow geometrically, at rates approaching 15
+percent per month. This flood of capacity and use, likened by some to
+"drinking from a firehose," creates immense opportunities and challenges
+for libraries. Libraries must anticipate the future implications of this
+technology, participate in its development, and deploy it to ensure
+access to the world's information resources.
+
+The infrastructure for the information age is being put in place.
+Libraries face strategic decisions about their role in the development,
+deployment, and use of this infrastructure. The emerging infrastructure
+is much more than computers and communication lines. It is more than the
+ability to compute at a remote site, send electronic mail to a peer
+across the country, or move a file from one library to another. The next
+five years will witness substantial development of the information
+infrastructure of the network.
+
+In order to provide appropriate leadership, library professionals must
+have a fundamental understanding of and appreciation for computer
+networking, from local area networks to the National Research and
+Education Network (NREN). This presentation addresses these
+fundamentals, and how they relate to libraries today and in the near
+future.
+
+Edwin BROWNRIGG Electronic Library Visions and Realities
+
+The electronic library has been a vision desired by many--and rejected by
+some--since Vannevar Bush coined the term memex to describe an automated,
+intelligent, personal information system. Variations on this vision have
+included Ted Nelson's Xanadau, Alan Kay's Dynabook, and Lancaster's
+"paperless library," with the most recent incarnation being the
+"Knowledge Navigator" described by John Scully of Apple. But the reality
+of library service has been less visionary and the leap to the electronic
+library has eluded universities, publishers, and information technology
+files.
+
+The Memex Research Institute (MemRI), an independent, nonprofit research
+and development organization, has created an Electronic Library Program
+of shared research and development in order to make the collective vision
+more concrete. The program is working toward the creation of large,
+indexed publicly available electronic image collections of published
+documents in academic, special, and public libraries. This strategic
+plan is the result of the first stage of the program, which has been an
+investigation of the information technologies available to support such
+an effort, the economic parameters of electronic service compared to
+traditional library operations, and the business and political factors
+affecting the shift from print distribution to electronic networked
+access.
+
+The strategic plan envisions a combination of publicly searchable access
+databases, image (and text) document collections stored on network "file
+servers," local and remote network access, and an intellectual property
+management-control system. This combination of technology and
+information content is defined in this plan as an E-library or E-library
+collection. Some participating sponsors are already developing projects
+based on MemRI's recommended directions.
+
+The E-library strategy projected in this plan is a visionary one that can
+enable major changes and improvements in academic, public, and special
+library service. This vision is, though, one that can be realized with
+today's technology. At the same time, it will challenge the political
+and social structure within which libraries operate: in academic
+libraries, the traditional emphasis on local collections, extending to
+accreditation issues; in public libraries, the potential of electronic
+branch and central libraries fully available to the public; and for
+special libraries, new opportunities for shared collections and networks.
+
+The environment in which this strategic plan has been developed is, at
+the moment, dominated by a sense of library limits. The continued
+expansion and rapid growth of local academic library collections is now
+clearly at an end. Corporate libraries, and even law libraries, are
+faced with operating within a difficult economic climate, as well as with
+very active competition from commercial information sources. For
+example, public libraries may be seen as a desirable but not critical
+municipal service in a time when the budgets of safety and health
+agencies are being cut back.
+
+Further, libraries in general have a very high labor-to-cost ratio in
+their budgets, and labor costs are still increasing, notwithstanding
+automation investments. It is difficult for libraries to obtain capital,
+startup, or seed funding for innovative activities, and those
+technology-intensive initiatives that offer the potential of decreased
+labor costs can provoke the opposition of library staff.
+
+However, libraries have achieved some considerable successes in the past
+two decades by improving both their service and their credibility within
+their organizations--and these positive changes have been accomplished
+mostly with judicious use of information technologies. The advances in
+computing and information technology have been well-chronicled: the
+continuing precipitous drop in computing costs, the growth of the
+Internet and private networks, and the explosive increase in publicly
+available information databases.
+
+For example, OCLC has become one of the largest computer network
+organizations in the world by creating a cooperative cataloging network
+of more than 6,000 libraries worldwide. On-line public access catalogs
+now serve millions of users on more than 50,000 dedicated terminals in
+the United States alone. The University of California MELVYL on-line
+catalog system has now expanded into an index database reference service
+and supports more than six million searches a year. And, libraries have
+become the largest group of customers of CD-ROM publishing technology;
+more than 30,000 optical media publications such as those offered by
+InfoTrac and Silver Platter are subscribed to by U.S. libraries.
+
+This march of technology continues and in the next decade will result in
+further innovations that are extremely difficult to predict. What is
+clear is that libraries can now go beyond automation of their order files
+and catalogs to automation of their collections themselves--and it is
+possible to circumvent the fiscal limitations that appear to obtain
+today.
+
+This Electronic Library Strategic Plan recommends a paradigm shift in
+library service, and demonstrates the steps necessary to provide improved
+library services with limited capacities and operating investments.
+
+SESSION IV-A
+
+Anne KENNEY
+
+The Cornell/Xerox Joint Study in Digital Preservation resulted in the
+recording of 1,000 brittle books as 600-dpi digital images and the
+production, on demand, of high-quality and archivally sound paper
+replacements. The project, which was supported by the Commission on
+Preservation and Access, also investigated some of the issues surrounding
+scanning, storing, retrieving, and providing access to digital images in
+a network environment.
+
+Anne Kenney will focus on some of the issues surrounding direct scanning
+as identified in the Cornell Xerox Project. Among those to be discussed
+are: image versus text capture; indexing and access; image-capture
+capabilities; a comparison to photocopy and microfilm; production and
+cost analysis; storage formats, protocols, and standards; and the use of
+this scanning technology for preservation purposes.
+
+The 600-dpi digital images produced in the Cornell Xerox Project proved
+highly acceptable for creating paper replacements of deteriorating
+originals. The 1,000 scanned volumes provided an array of image-capture
+challenges that are common to nineteenth-century printing techniques and
+embrittled material, and that defy the use of text-conversion processes.
+These challenges include diminished contrast between text and background,
+fragile and deteriorated pages, uneven printing, elaborate type faces,
+faint and bold text adjacency, handwritten text and annotations, nonRoman
+languages, and a proliferation of illustrated material embedded in text.
+The latter category included high-frequency and low-frequency halftones,
+continuous tone photographs, intricate mathematical drawings, maps,
+etchings, reverse-polarity drawings, and engravings.
+
+The Xerox prototype scanning system provided a number of important
+features for capturing this diverse material. Technicians used multiple
+threshold settings, filters, line art and halftone definitions,
+autosegmentation, windowing, and software-editing programs to optimize
+image capture. At the same time, this project focused on production.
+The goal was to make scanning as affordable and acceptable as
+photocopying and microfilming for preservation reformatting. A
+time-and-cost study conducted during the last three months of this
+project confirmed the economic viability of digital scanning, and these
+findings will be discussed here.
+
+From the outset, the Cornell Xerox Project was predicated on the use of
+nonproprietary standards and the use of common protocols when standards
+did not exist. Digital files were created as TIFF images which were
+compressed prior to storage using Group 4 CCITT compression. The Xerox
+software is MS DOS based and utilizes off-the shelf programs such as
+Microsoft Windows and Wang Image Wizard. The digital library is designed
+to be hardware-independent and to provide interchangeability with other
+institutions through network connections. Access to the digital files
+themselves is two-tiered: Bibliographic records for the computer files
+are created in RLIN and Cornell's local system and access into the actual
+digital images comprising a book is provided through a document control
+structure and a networked image file-server, both of which will be
+described.
+
+The presentation will conclude with a discussion of some of the issues
+surrounding the use of this technology as a preservation tool (storage,
+refreshing, backup).
+
+Pamela ANDRE and Judith ZIDAR
+
+The National Agricultural Library (NAL) has had extensive experience with
+raster scanning of printed materials. Since 1987, the Library has
+participated in the National Agricultural Text Digitizing Project (NATDP)
+a cooperative effort between NAL and forty-five land grant university
+libraries. An overview of the project will be presented, giving its
+history and NAL's strategy for the future.
+
+An in-depth discussion of NATDP will follow, including a description of
+the scanning process, from the gathering of the printed materials to the
+archiving of the electronic pages. The type of equipment required for a
+stand-alone scanning workstation and the importance of file management
+software will be discussed. Issues concerning the images themselves will
+be addressed briefly, such as image format; black and white versus color;
+gray scale versus dithering; and resolution.
+
+Also described will be a study currently in progress by NAL to evaluate
+the usefulness of converting microfilm to electronic images in order to
+improve access. With the cooperation of Tuskegee University, NAL has
+selected three reels of microfilm from a collection of sixty-seven reels
+containing the papers, letters, and drawings of George Washington Carver.
+The three reels were converted into 3,500 electronic images using a
+specialized microfilm scanner. The selection, filming, and indexing of
+this material will be discussed.
+
+Donald WATERS
+
+Project Open Book, the Yale University Library's effort to convert 10,
+000 books from microfilm to digital imagery, is currently in an advanced
+state of planning and organization. The Yale Library has selected a
+major vendor to serve as a partner in the project and as systems
+integrator. In its proposal, the successful vendor helped isolate areas
+of risk and uncertainty as well as key issues to be addressed during the
+life of the project. The Yale Library is now poised to decide what
+material it will convert to digital image form and to seek funding,
+initially for the first phase and then for the entire project.
+
+The proposal that Yale accepted for the implementation of Project Open
+Book will provide at the end of three phases a conversion subsystem,
+browsing stations distributed on the campus network within the Yale
+Library, a subsystem for storing 10,000 books at 200 and 600 dots per
+inch, and network access to the image printers. Pricing for the system
+implementation assumes the existence of Yale's campus ethernet network
+and its high-speed image printers, and includes other requisite hardware
+and software, as well as system integration services. Proposed operating
+costs include hardware and software maintenance, but do not include
+estimates for the facilities management of the storage devices and image
+servers.
+
+Yale selected its vendor partner in a formal process, partly funded by
+the Commission for Preservation and Access. Following a request for
+proposal, the Yale Library selected two vendors as finalists to work with
+Yale staff to generate a detailed analysis of requirements for Project
+Open Book. Each vendor used the results of the requirements analysis to
+generate and submit a formal proposal for the entire project. This
+competitive process not only enabled the Yale Library to select its
+primary vendor partner but also revealed much about the state of the
+imaging industry, about the varying, corporate commitments to the markets
+for imaging technology, and about the varying organizational dynamics
+through which major companies are responding to and seeking to develop
+these markets.
+
+Project Open Book is focused specifically on the conversion of images
+from microfilm to digital form. The technology for scanning microfilm is
+readily available but is changing rapidly. In its project requirements,
+the Yale Library emphasized features of the technology that affect the
+technical quality of digital image production and the costs of creating
+and storing the image library: What levels of digital resolution can be
+achieved by scanning microfilm? How does variation in the quality of
+microfilm, particularly in film produced to preservation standards,
+affect the quality of the digital images? What technologies can an
+operator effectively and economically apply when scanning film to
+separate two-up images and to control for and correct image
+imperfections? How can quality control best be integrated into
+digitizing work flow that includes document indexing and storage?
+
+The actual and expected uses of digital images--storage, browsing,
+printing, and OCR--help determine the standards for measuring their
+quality. Browsing is especially important, but the facilities available
+for readers to browse image documents is perhaps the weakest aspect of
+imaging technology and most in need of development. As it defined its
+requirements, the Yale Library concentrated on some fundamental aspects
+of usability for image documents: Does the system have sufficient
+flexibility to handle the full range of document types, including
+monographs, multi-part and multivolume sets, and serials, as well as
+manuscript collections? What conventions are necessary to identify a
+document uniquely for storage and retrieval? Where is the database of
+record for storing bibliographic information about the image document?
+How are basic internal structures of documents, such as pagination, made
+accessible to the reader? How are the image documents physically
+presented on the screen to the reader?
+
+The Yale Library designed Project Open Book on the assumption that
+microfilm is more than adequate as a medium for preserving the content of
+deteriorated library materials. As planning in the project has advanced,
+it is increasingly clear that the challenge of digital image technology
+and the key to the success of efforts like Project Open Book is to
+provide a means of both preserving and improving access to those
+deteriorated materials.
+
+SESSION IV-B
+
+George THOMA
+
+In the use of electronic imaging for document preservation, there are
+several issues to consider, such as: ensuring adequate image quality,
+maintaining substantial conversion rates (through-put), providing unique
+identification for automated access and retrieval, and accommodating
+bound volumes and fragile material.
+
+To maintain high image quality, image processing functions are required
+to correct the deficiencies in the scanned image. Some commercially
+available systems include these functions, while some do not. The
+scanned raw image must be processed to correct contrast deficiencies--
+both poor overall contrast resulting from light print and/or dark
+background, and variable contrast resulting from stains and
+bleed-through. Furthermore, the scan density must be adequate to allow
+legibility of print and sufficient fidelity in the pseudo-halftoned gray
+material. Borders or page-edge effects must be removed for both
+compactibility and aesthetics. Page skew must be corrected for aesthetic
+reasons and to enable accurate character recognition if desired.
+Compound images consisting of both two-toned text and gray-scale
+illustrations must be processed appropriately to retain the quality of
+each.
+
+SESSION IV-C
+
+Jean BARONAS
+
+Standards publications being developed by scientists, engineers, and
+business managers in Association for Information and Image Management
+(AIIM) standards committees can be applied to electronic image management
+(EIM) processes including: document (image) transfer, retrieval and
+evaluation; optical disk and document scanning; and document design and
+conversion. When combined with EIM system planning and operations,
+standards can assist in generating image databases that are
+interchangeable among a variety of systems. The applications of
+different approaches for image-tagging, indexing, compression, and
+transfer often cause uncertainty concerning EIM system compatibility,
+calibration, performance, and upward compatibility, until standard
+implementation parameters are established. The AIIM standards that are
+being developed for these applications can be used to decrease the
+uncertainty, successfully integrate imaging processes, and promote "open
+systems." AIIM is an accredited American National Standards Institute
+(ANSI) standards developer with more than twenty committees comprised of
+300 volunteers representing users, vendors, and manufacturers. The
+standards publications that are developed in these committees have
+national acceptance and provide the basis for international harmonization
+in the development of new International Organization for Standardization
+(ISO) standards.
+
+This presentation describes the development of AIIM's EIM standards and a
+new effort at AIIM, a database on standards projects in a wide framework
+of imaging industries including capture, recording, processing,
+duplication, distribution, display, evaluation, and preservation. The
+AIIM Imagery Database will cover imaging standards being developed by
+many organizations in many different countries. It will contain
+standards publications' dates, origins, related national and
+international projects, status, key words, and abstracts. The ANSI Image
+Technology Standards Board requested that such a database be established,
+as did the ISO/International Electrotechnical Commission Joint Task Force
+on Imagery. AIIM will take on the leadership role for the database and
+coordinate its development with several standards developers.
+
+Patricia BATTIN
+
+ Characteristics of standards for digital imagery:
+
+ * Nature of digital technology implies continuing volatility.
+
+ * Precipitous standard-setting not possible and probably not
+ desirable.
+
+ * Standards are a complex issue involving the medium, the
+ hardware, the software, and the technical capacity for
+ reproductive fidelity and clarity.
+
+ * The prognosis for reliable archival standards (as defined by
+ librarians) in the foreseeable future is poor.
+
+ Significant potential and attractiveness of digital technology as a
+ preservation medium and access mechanism.
+
+ Productive use of digital imagery for preservation requires a
+ reconceptualizing of preservation principles in a volatile,
+ standardless world.
+
+ Concept of managing continuing access in the digital environment
+ rather than focusing on the permanence of the medium and long-term
+ archival standards developed for the analog world.
+
+ Transition period: How long and what to do?
+
+ * Redefine "archival."
+
+ * Remove the burden of "archival copy" from paper artifacts.
+
+ * Use digital technology for storage, develop management
+ strategies for refreshing medium, hardware and software.
+
+ * Create acid-free paper copies for transition period backup
+ until we develop reliable procedures for ensuring continuing
+ access to digital files.
+
+SESSION IV-D
+
+Stuart WEIBEL The Role of SGML Markup in the CORE Project (6)
+
+The emergence of high-speed telecommunications networks as a basic
+feature of the scholarly workplace is driving the demand for electronic
+document delivery. Three distinct categories of electronic
+publishing/republishing are necessary to support access demands in this
+emerging environment:
+
+ 1.) Conversion of paper or microfilm archives to electronic format
+ 2.) Conversion of electronic files to formats tailored to
+ electronic retrieval and display
+ 3.) Primary electronic publishing (materials for which the
+ electronic version is the primary format)
+
+OCLC has experimental or product development activities in each of these
+areas. Among the challenges that lie ahead is the integration of these
+three types of information stores in coherent distributed systems.
+
+The CORE (Chemistry Online Retrieval Experiment) Project is a model for
+the conversion of large text and graphics collections for which
+electronic typesetting files are available (category 2). The American
+Chemical Society has made available computer typography files dating from
+1980 for its twenty journals. This collection of some 250 journal-years
+is being converted to an electronic format that will be accessible
+through several end-user applications.
+
+The use of Standard Generalized Markup Language (SGML) offers the means
+to capture the structural richness of the original articles in a way that
+will support a variety of retrieval, navigation, and display options
+necessary to navigate effectively in very large text databases.
+
+An SGML document consists of text that is marked up with descriptive tags
+that specify the function of a given element within the document. As a
+formal language construct, an SGML document can be parsed against a
+document-type definition (DTD) that unambiguously defines what elements
+are allowed and where in the document they can (or must) occur. This
+formalized map of article structure allows the user interface design to
+be uncoupled from the underlying database system, an important step
+toward interoperability. Demonstration of this separability is a part of
+the CORE project, wherein user interface designs born of very different
+philosophies will access the same database.
+
+NOTES:
+ (6) The CORE project is a collaboration among Cornell University's
+ Mann Library, Bell Communications Research (Bellcore), the American
+ Chemical Society (ACS), the Chemical Abstracts Service (CAS), and
+ OCLC.
+
+Michael LESK The CORE Electronic Chemistry Library
+
+A major on-line file of chemical journal literature complete with
+graphics is being developed to test the usability of fully electronic
+access to documents, as a joint project of Cornell University, the
+American Chemical Society, the Chemical Abstracts Service, OCLC, and
+Bellcore (with additional support from Sun Microsystems, Springer-Verlag,
+DigitaI Equipment Corporation, Sony Corporation of America, and Apple
+Computers). Our file contains the American Chemical Society's on-line
+journals, supplemented with the graphics from the paper publication. The
+indexing of the articles from Chemical Abstracts Documents is available
+in both image and text format, and several different interfaces can be
+used. Our goals are (1) to assess the effectiveness and acceptability of
+electronic access to primary journals as compared with paper, and (2) to
+identify the most desirable functions of the user interface to an
+electronic system of journals, including in particular a comparison of
+page-image display with ASCII display interfaces. Early experiments with
+chemistry students on a variety of tasks suggest that searching tasks are
+completed much faster with any electronic system than with paper, but
+that for reading all versions of the articles are roughly equivalent.
+
+Pamela ANDRE and Judith ZIDAR
+
+Text conversion is far more expensive and time-consuming than image
+capture alone. NAL's experience with optical character recognition (OCR)
+will be related and compared with the experience of having text rekeyed.
+What factors affect OCR accuracy? How accurate does full text have to be
+in order to be useful? How do different users react to imperfect text?
+These are questions that will be explored. For many, a service bureau
+may be a better solution than performing the work inhouse; this will also
+be discussed.
+
+SESSION VI
+
+Marybeth PETERS
+
+Copyright law protects creative works. Protection granted by the law to
+authors and disseminators of works includes the right to do or authorize
+the following: reproduce the work, prepare derivative works, distribute
+the work to the public, and publicly perform or display the work. In
+addition, copyright owners of sound recordings and computer programs have
+the right to control rental of their works. These rights are not
+unlimited; there are a number of exceptions and limitations.
+
+An electronic environment places strains on the copyright system.
+Copyright owners want to control uses of their work and be paid for any
+use; the public wants quick and easy access at little or no cost. The
+marketplace is working in this area. Contracts, guidelines on electronic
+use, and collective licensing are in use and being refined.
+
+Issues concerning the ability to change works without detection are more
+difficult to deal with. Questions concerning the integrity of the work
+and the status of the changed version under the copyright law are to be
+addressed. These are public policy issues which require informed
+dialogue.
+
+
+ *** *** *** ****** *** *** ***
+
+
+ Appendix III: DIRECTORY OF PARTICIPANTS
+
+
+PRESENTERS:
+
+ Pamela Q.J. Andre
+ Associate Director, Automation
+ National Agricultural Library
+ 10301 Baltimore Boulevard
+ Beltsville, MD 20705-2351
+ Phone: (301) 504-6813
+ Fax: (301) 504-7473
+ E-mail: INTERNET: PANDRE@ASRR.ARSUSDA.GOV
+
+ Jean Baronas, Senior Manager
+ Department of Standards and Technology
+ Association for Information and Image Management (AIIM)
+ 1100 Wayne Avenue, Suite 1100
+ Silver Spring, MD 20910
+ Phone: (301) 587-8202
+ Fax: (301) 587-2711
+
+ Patricia Battin, President
+ The Commission on Preservation and Access
+ 1400 16th Street, N.W.
+ Suite 740
+ Washington, DC 20036-2217
+ Phone: (202) 939-3400
+ Fax: (202) 939-3407
+ E-mail: CPA@GWUVM.BITNET
+
+ Howard Besser
+ Centre Canadien d'Architecture
+ (Canadian Center for Architecture)
+ 1920, rue Baile
+ Montreal, Quebec H3H 2S6
+ CANADA
+ Phone: (514) 939-7001
+ Fax: (514) 939-7020
+ E-mail: howard@lis.pitt.edu
+
+ Edwin B. Brownrigg, Executive Director
+ Memex Research Institute
+ 422 Bonita Avenue
+ Roseville, CA 95678
+ Phone: (916) 784-2298
+ Fax: (916) 786-7559
+ E-mail: BITNET: MEMEX@CALSTATE.2
+
+ Eric M. Calaluca, Vice President
+ Chadwyck-Healey, Inc.
+ 1101 King Street
+ Alexandria, VA 223l4
+ Phone: (800) 752-05l5
+ Fax: (703) 683-7589
+
+ James Daly
+ 4015 Deepwood Road
+ Baltimore, MD 21218-1404
+ Phone: (410) 235-0763
+
+ Ricky Erway, Associate Coordinator
+ American Memory
+ Library of Congress
+ Phone: (202) 707-6233
+ Fax: (202) 707-3764
+
+ Carl Fleischhauer, Coordinator
+ American Memory
+ Library of Congress
+ Phone: (202) 707-6233
+ Fax: (202) 707-3764
+
+ Joanne Freeman
+ 2000 Jefferson Park Avenue, No. 7
+ Charlottesville, VA 22903
+
+ Prosser Gifford
+ Director for Scholarly Programs
+ Library of Congress
+ Phone: (202) 707-1517
+ Fax: (202) 707-9898
+ E-mail: pgif@seq1.loc.gov
+
+ Jacqueline Hess, Director
+ National Demonstration Laboratory
+ for Interactive Information Technologies
+ Library of Congress
+ Phone: (202) 707-4157
+ Fax: (202) 707-2829
+
+ Susan Hockey, Director
+ Center for Electronic Texts in the Humanities (CETH)
+ Alexander Library
+ Rutgers University
+ 169 College Avenue
+ New Brunswick, NJ 08903
+ Phone: (908) 932-1384
+ Fax: (908) 932-1386
+ E-mail: hockey@zodiac.rutgers.edu
+
+ William L. Hooton, Vice President
+ Business & Technical Development
+ Imaging & Information Systems Group
+ I-NET
+ 6430 Rockledge Drive, Suite 400
+ Bethesda, MD 208l7
+ Phone: (301) 564-6750
+ Fax: (513) 564-6867
+
+ Anne R. Kenney, Associate Director
+ Department of Preservation and Conservation
+ 701 Olin Library
+ Cornell University
+ Ithaca, NY 14853
+ Phone: (607) 255-6875
+ Fax: (607) 255-9346
+ E-mail: LYDY@CORNELLA.BITNET
+
+ Ronald L. Larsen
+ Associate Director for Information Technology
+ University of Maryland at College Park
+ Room B0224, McKeldin Library
+ College Park, MD 20742-7011
+ Phone: (301) 405-9194
+ Fax: (301) 314-9865
+ E-mail: rlarsen@libr.umd.edu
+
+ Maria L. Lebron, Managing Editor
+ The Online Journal of Current Clinical Trials
+ l333 H Street, N.W.
+ Washington, DC 20005
+ Phone: (202) 326-6735
+ Fax: (202) 842-2868
+ E-mail: PUBSAAAS@GWUVM.BITNET
+
+ Michael Lesk, Executive Director
+ Computer Science Research
+ Bell Communications Research, Inc.
+ Rm 2A-385
+ 445 South Street
+ Morristown, NJ 07960-l9l0
+ Phone: (201) 829-4070
+ Fax: (201) 829-5981
+ E-mail: lesk@bellcore.com (Internet) or bellcore!lesk (uucp)
+
+ Clifford A. Lynch
+ Director, Library Automation
+ University of California,
+ Office of the President
+ 300 Lakeside Drive, 8th Floor
+ Oakland, CA 94612-3350
+ Phone: (510) 987-0522
+ Fax: (510) 839-3573
+ E-mail: calur@uccmvsa
+
+ Avra Michelson
+ National Archives and Records Administration
+ NSZ Rm. 14N
+ 7th & Pennsylvania, N.W.
+ Washington, D.C. 20408
+ Phone: (202) 501-5544
+ Fax: (202) 501-5533
+ E-mail: tmi@cu.nih.gov
+
+ Elli Mylonas, Managing Editor
+ Perseus Project
+ Department of the Classics
+ Harvard University
+ 319 Boylston Hall
+ Cambridge, MA 02138
+ Phone: (617) 495-9025, (617) 495-0456 (direct)
+ Fax: (617) 496-8886
+ E-mail: Elli@IKAROS.Harvard.EDU or elli@wjh12.harvard.edu
+
+ David Woodley Packard
+ Packard Humanities Institute
+ 300 Second Street, Suite 201
+ Los Altos, CA 94002
+ Phone: (415) 948-0150 (PHI)
+ Fax: (415) 948-5793
+
+ Lynne K. Personius, Assistant Director
+ Cornell Information Technologies for
+ Scholarly Information Sources
+ 502 Olin Library
+ Cornell University
+ Ithaca, NY 14853
+ Phone: (607) 255-3393
+ Fax: (607) 255-9346
+ E-mail: JRN@CORNELLC.BITNET
+
+ Marybeth Peters
+ Policy Planning Adviser to the
+ Register of Copyrights
+ Library of Congress
+ Office LM 403
+ Phone: (202) 707-8350
+ Fax: (202) 707-8366
+
+ C. Michael Sperberg-McQueen
+ Editor, Text Encoding Initiative
+ Computer Center (M/C 135)
+ University of Illinois at Chicago
+ Box 6998
+ Chicago, IL 60680
+ Phone: (312) 413-0317
+ Fax: (312) 996-6834
+ E-mail: u35395@uicvm..cc.uic.edu or u35395@uicvm.bitnet
+
+ George R. Thoma, Chief
+ Communications Engineering Branch
+ National Library of Medicine
+ 8600 Rockville Pike
+ Bethesda, MD 20894
+ Phone: (301) 496-4496
+ Fax: (301) 402-0341
+ E-mail: thoma@lhc.nlm.nih.gov
+
+ Dorothy Twohig, Editor
+ The Papers of George Washington
+ 504 Alderman Library
+ University of Virginia
+ Charlottesville, VA 22903-2498
+ Phone: (804) 924-0523
+ Fax: (804) 924-4337
+
+ Susan H. Veccia, Team leader
+ American Memory, User Evaluation
+ Library of Congress
+ American Memory Evaluation Project
+ Phone: (202) 707-9104
+ Fax: (202) 707-3764
+ E-mail: svec@seq1.loc.gov
+
+ Donald J. Waters, Head
+ Systems Office
+ Yale University Library
+ New Haven, CT 06520
+ Phone: (203) 432-4889
+ Fax: (203) 432-7231
+ E-mail: DWATERS@YALEVM.BITNET or DWATERS@YALEVM.YCC.YALE.EDU
+
+ Stuart Weibel, Senior Research Scientist
+ OCLC
+ 6565 Frantz Road
+ Dublin, OH 43017
+ Phone: (614) 764-608l
+ Fax: (614) 764-2344
+ E-mail: INTERNET: Stu@rsch.oclc.org
+
+ Robert G. Zich
+ Special Assistant to the Associate Librarian
+ for Special Projects
+ Library of Congress
+ Phone: (202) 707-6233
+ Fax: (202) 707-3764
+ E-mail: rzic@seq1.loc.gov
+
+ Judith A. Zidar, Coordinator
+ National Agricultural Text Digitizing Program
+ Information Systems Division
+ National Agricultural Library
+ 10301 Baltimore Boulevard
+ Beltsville, MD 20705-2351
+ Phone: (301) 504-6813 or 504-5853
+ Fax: (301) 504-7473
+ E-mail: INTERNET: JZIDAR@ASRR.ARSUSDA.GOV
+
+
+OBSERVERS:
+
+ Helen Aguera, Program Officer
+ Division of Research
+ Room 318
+ National Endowment for the Humanities
+ 1100 Pennsylvania Avenue, N.W.
+ Washington, D.C. 20506
+ Phone: (202) 786-0358
+ Fax: (202) 786-0243
+
+ M. Ellyn Blanton, Deputy Director
+ National Demonstration Laboratory
+ for Interactive Information Technologies
+ Library of Congress
+ Phone: (202) 707-4157
+ Fax: (202) 707-2829
+
+ Charles M. Dollar
+ National Archives and Records Administration
+ NSZ Rm. 14N
+ 7th & Pennsylvania, N.W.
+ Washington, DC 20408
+ Phone: (202) 501-5532
+ Fax: (202) 501-5512
+
+ Jeffrey Field, Deputy to the Director
+ Division of Preservation and Access
+ Room 802
+ National Endowment for the Humanities
+ 1100 Pennsylvania Avenue, N.W.
+ Washington, DC 20506
+ Phone: (202) 786-0570
+ Fax: (202) 786-0243
+
+ Lorrin Garson
+ American Chemical Society
+ Research and Development Department
+ 1155 16th Street, N.W.
+ Washington, D.C. 20036
+ Phone: (202) 872-4541
+ Fax: E-mail: INTERNET: LRG96@ACS.ORG
+
+ William M. Holmes, Jr.
+ National Archives and Records Administration
+ NSZ Rm. 14N
+ 7th & Pennsylvania, N.W.
+ Washington, DC 20408
+ Phone: (202) 501-5540
+ Fax: (202) 501-5512
+ E-mail: WHOLMES@AMERICAN.EDU
+
+ Sperling Martin
+ Information Resource Management
+ 20030 Doolittle Street
+ Gaithersburg, MD 20879
+ Phone: (301) 924-1803
+
+ Michael Neuman, Director
+ The Center for Text and Technology
+ Academic Computing Center
+ 238 Reiss Science Building
+ Georgetown University
+ Washington, DC 20057
+ Phone: (202) 687-6096
+ Fax: (202) 687-6003
+ E-mail: neuman@guvax.bitnet, neuman@guvax.georgetown.edu
+
+ Barbara Paulson, Program Officer
+ Division of Preservation and Access
+ Room 802
+ National Endowment for the Humanities
+ 1100 Pennsylvania Avenue, N.W.
+ Washington, DC 20506
+ Phone: (202) 786-0577
+ Fax: (202) 786-0243
+
+ Allen H. Renear
+ Senior Academic Planning Analyst
+ Brown University Computing and Information Services
+ 115 Waterman Street
+ Campus Box 1885
+ Providence, R.I. 02912
+ Phone: (401) 863-7312
+ Fax: (401) 863-7329
+ E-mail: BITNET: Allen@BROWNVM or
+ INTERNET: Allen@brownvm.brown.edu
+
+ Susan M. Severtson, President
+ Chadwyck-Healey, Inc.
+ 1101 King Street
+ Alexandria, VA 223l4
+ Phone: (800) 752-05l5
+ Fax: (703) 683-7589
+
+ Frank Withrow
+ U.S. Department of Education
+ 555 New Jersey Avenue, N.W.
+ Washington, DC 20208-5644
+ Phone: (202) 219-2200
+ Fax: (202) 219-2106
+
+
+(LC STAFF)
+
+ Linda L. Arret
+ Machine-Readable Collections Reading Room LJ 132
+ (202) 707-1490
+
+ John D. Byrum, Jr.
+ Descriptive Cataloging Division LM 540
+ (202) 707-5194
+
+ Mary Jane Cavallo
+ Science and Technology Division LA 5210
+ (202) 707-1219
+
+ Susan Thea David
+ Congressional Research Service LM 226
+ (202) 707-7169
+
+ Robert Dierker
+ Senior Adviser for Multimedia Activities LM 608
+ (202) 707-6151
+
+ William W. Ellis
+ Associate Librarian for Science and Technology LM 611
+ (202) 707-6928
+
+ Ronald Gephart
+ Manuscript Division LM 102
+ (202) 707-5097
+
+ James Graber
+ Information Technology Services LM G51
+ (202) 707-9628
+
+ Rich Greenfield
+ American Memory LM 603
+ (202) 707-6233
+
+ Rebecca Guenther
+ Network Development LM 639
+ (202) 707-5092
+
+ Kenneth E. Harris
+ Preservation LM G21
+ (202) 707-5213
+
+ Staley Hitchcock
+ Manuscript Division LM 102
+ (202) 707-5383
+
+ Bohdan Kantor
+ Office of Special Projects LM 612
+ (202) 707-0180
+
+ John W. Kimball, Jr
+ Machine-Readable Collections Reading Room LJ 132
+ (202) 707-6560
+
+ Basil Manns
+ Information Technology Services LM G51
+ (202) 707-8345
+
+ Sally Hart McCallum
+ Network Development LM 639
+ (202) 707-6237
+
+ Dana J. Pratt
+ Publishing Office LM 602
+ (202) 707-6027
+
+ Jane Riefenhauser
+ American Memory LM 603
+ (202) 707-6233
+
+ William Z. Schenck
+ Collections Development LM 650
+ (202) 707-7706
+
+ Chandru J. Shahani
+ Preservation Research and Testing Office (R&T) LM G38
+ (202) 707-5607
+
+ William J. Sittig
+ Collections Development LM 650
+ (202) 707-7050
+
+ Paul Smith
+ Manuscript Division LM 102
+ (202) 707-5097
+
+ James L. Stevens
+ Information Technology Services LM G51
+ (202) 707-9688
+
+ Karen Stuart
+ Manuscript Division LM 130
+ (202) 707-5389
+
+ Tamara Swora
+ Preservation Microfilming Office LM G05
+ (202) 707-6293
+
+ Sarah Thomas
+ Collections Cataloging LM 642
+ (202) 707-5333
+
+
+ END
+ *************************************************************
+
+Note: This file has been edited for use on computer networks. This
+editing required the removal of diacritics, underlining, and fonts such
+as italics and bold.
+
+kde 11/92
+
+[A few of the italics (when used for emphasis) were replaced by CAPS mh]
+
+*End of The Project Gutenberg Etext of LOC WORKSHOP ON ELECTRONIC ETEXTS
+
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt.compressed
new file mode 100644
index 000000000..b7d0f633c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/lcet10.txt.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh
new file mode 100644
index 000000000..037118364
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh.compressed
new file mode 100644
index 000000000..77bfa4717
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/mapsdatazrh.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey
new file mode 100644
index 000000000..47408cd68
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey
@@ -0,0 +1 @@
+znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmzxc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxcnzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqerioupqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyiowtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuriouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwotueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfhklasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfasdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjkaghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey.compressed
new file mode 100644
index 000000000..bbcf13440
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/monkey.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt
new file mode 100644
index 000000000..34088b82c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt
@@ -0,0 +1,10699 @@
+
+This is the February 1992 Project Gutenberg release of:
+
+Paradise Lost by John Milton
+
+The oldest etext known to Project Gutenberg (ca. 1964-1965)
+(If you know of any older ones, please let us know.)
+
+
+Introduction (one page)
+
+This etext was originally created in 1964-1965 according to Dr.
+Joseph Raben of Queens College, NY, to whom it is attributed by
+Project Gutenberg. We had heard of this etext for years but it
+was not until 1991 that we actually managed to track it down to
+a specific location, and then it took months to convince people
+to let us have a copy, then more months for them actually to do
+the copying and get it to us. Then another month to convert to
+something we could massage with our favorite 486 in DOS. After
+that is was only a matter of days to get it into this shape you
+will see below. The original was, of course, in CAPS only, and
+so were all the other etexts of the 60's and early 70's. Don't
+let anyone fool you into thinking any etext with both upper and
+lower case is an original; all those original Project Gutenberg
+etexts were also in upper case and were translated or rewritten
+many times to get them into their current condition. They have
+been worked on by many people throughout the world.
+
+In the course of our searches for Professor Raben and his etext
+we were never able to determine where copies were or which of a
+variety of editions he may have used as a source. We did get a
+little information here and there, but even after we received a
+copy of the etext we were unwilling to release it without first
+determining that it was in fact Public Domain and finding Raben
+to verify this and get his permission. Interested enough, in a
+totally unrelated action to our searches for him, the professor
+subscribed to the Project Gutenberg listserver and we happened,
+by accident, to notice his name. (We don't really look at every
+subscription request as the computers usually handle them.) The
+etext was then properly identified, copyright analyzed, and the
+current edition prepared.
+
+To give you an estimation of the difference in the original and
+what we have today: the original was probably entered on cards
+commonly known at the time as "IBM cards" (Do Not Fold, Spindle
+or Mutilate) and probably took in excess of 100,000 of them. A
+single card could hold 80 characters (hence 80 characters is an
+accepted standard for so many computer margins), and the entire
+original edition we received in all caps was over 800,000 chars
+in length, including line enumeration, symbols for caps and the
+punctuation marks, etc., since they were not available keyboard
+characters at the time (probably the keyboards operated at baud
+rates of around 113, meaning the typists had to type slowly for
+the keyboard to keep up).
+
+This is the second version of Paradise Lost released by Project
+Gutenberg. The first was released as our October, 1991 etext.
+
+
+
+
+
+Paradise Lost
+
+
+
+
+Book I
+
+
+Of Man's first disobedience, and the fruit
+Of that forbidden tree whose mortal taste
+Brought death into the World, and all our woe,
+With loss of Eden, till one greater Man
+Restore us, and regain the blissful seat,
+Sing, Heavenly Muse, that, on the secret top
+Of Oreb, or of Sinai, didst inspire
+That shepherd who first taught the chosen seed
+In the beginning how the heavens and earth
+Rose out of Chaos: or, if Sion hill
+Delight thee more, and Siloa's brook that flowed
+Fast by the oracle of God, I thence
+Invoke thy aid to my adventurous song,
+That with no middle flight intends to soar
+Above th' Aonian mount, while it pursues
+Things unattempted yet in prose or rhyme.
+And chiefly thou, O Spirit, that dost prefer
+Before all temples th' upright heart and pure,
+Instruct me, for thou know'st; thou from the first
+Wast present, and, with mighty wings outspread,
+Dove-like sat'st brooding on the vast Abyss,
+And mad'st it pregnant: what in me is dark
+Illumine, what is low raise and support;
+That, to the height of this great argument,
+I may assert Eternal Providence,
+And justify the ways of God to men.
+ Say first--for Heaven hides nothing from thy view,
+Nor the deep tract of Hell--say first what cause
+Moved our grand parents, in that happy state,
+Favoured of Heaven so highly, to fall off
+From their Creator, and transgress his will
+For one restraint, lords of the World besides.
+Who first seduced them to that foul revolt?
+ Th' infernal Serpent; he it was whose guile,
+Stirred up with envy and revenge, deceived
+The mother of mankind, what time his pride
+Had cast him out from Heaven, with all his host
+Of rebel Angels, by whose aid, aspiring
+To set himself in glory above his peers,
+He trusted to have equalled the Most High,
+If he opposed, and with ambitious aim
+Against the throne and monarchy of God,
+Raised impious war in Heaven and battle proud,
+With vain attempt. Him the Almighty Power
+Hurled headlong flaming from th' ethereal sky,
+With hideous ruin and combustion, down
+To bottomless perdition, there to dwell
+In adamantine chains and penal fire,
+Who durst defy th' Omnipotent to arms.
+ Nine times the space that measures day and night
+To mortal men, he, with his horrid crew,
+Lay vanquished, rolling in the fiery gulf,
+Confounded, though immortal. But his doom
+Reserved him to more wrath; for now the thought
+Both of lost happiness and lasting pain
+Torments him: round he throws his baleful eyes,
+That witnessed huge affliction and dismay,
+Mixed with obdurate pride and steadfast hate.
+At once, as far as Angels ken, he views
+The dismal situation waste and wild.
+A dungeon horrible, on all sides round,
+As one great furnace flamed; yet from those flames
+No light; but rather darkness visible
+Served only to discover sights of woe,
+Regions of sorrow, doleful shades, where peace
+And rest can never dwell, hope never comes
+That comes to all, but torture without end
+Still urges, and a fiery deluge, fed
+With ever-burning sulphur unconsumed.
+Such place Eternal Justice has prepared
+For those rebellious; here their prison ordained
+In utter darkness, and their portion set,
+As far removed from God and light of Heaven
+As from the centre thrice to th' utmost pole.
+Oh how unlike the place from whence they fell!
+There the companions of his fall, o'erwhelmed
+With floods and whirlwinds of tempestuous fire,
+He soon discerns; and, weltering by his side,
+One next himself in power, and next in crime,
+Long after known in Palestine, and named
+Beelzebub. To whom th' Arch-Enemy,
+And thence in Heaven called Satan, with bold words
+Breaking the horrid silence, thus began:--
+ "If thou beest he--but O how fallen! how changed
+From him who, in the happy realms of light
+Clothed with transcendent brightness, didst outshine
+Myriads, though bright!--if he whom mutual league,
+United thoughts and counsels, equal hope
+And hazard in the glorious enterprise
+Joined with me once, now misery hath joined
+In equal ruin; into what pit thou seest
+From what height fallen: so much the stronger proved
+He with his thunder; and till then who knew
+The force of those dire arms? Yet not for those,
+Nor what the potent Victor in his rage
+Can else inflict, do I repent, or change,
+Though changed in outward lustre, that fixed mind,
+And high disdain from sense of injured merit,
+That with the Mightiest raised me to contend,
+And to the fierce contentions brought along
+Innumerable force of Spirits armed,
+That durst dislike his reign, and, me preferring,
+His utmost power with adverse power opposed
+In dubious battle on the plains of Heaven,
+And shook his throne. What though the field be lost?
+All is not lost--the unconquerable will,
+And study of revenge, immortal hate,
+And courage never to submit or yield:
+And what is else not to be overcome?
+That glory never shall his wrath or might
+Extort from me. To bow and sue for grace
+With suppliant knee, and deify his power
+Who, from the terror of this arm, so late
+Doubted his empire--that were low indeed;
+That were an ignominy and shame beneath
+This downfall; since, by fate, the strength of Gods,
+And this empyreal sybstance, cannot fail;
+Since, through experience of this great event,
+In arms not worse, in foresight much advanced,
+We may with more successful hope resolve
+To wage by force or guile eternal war,
+Irreconcilable to our grand Foe,
+Who now triumphs, and in th' excess of joy
+Sole reigning holds the tyranny of Heaven."
+ So spake th' apostate Angel, though in pain,
+Vaunting aloud, but racked with deep despair;
+And him thus answered soon his bold compeer:--
+ "O Prince, O Chief of many throned Powers
+That led th' embattled Seraphim to war
+Under thy conduct, and, in dreadful deeds
+Fearless, endangered Heaven's perpetual King,
+And put to proof his high supremacy,
+Whether upheld by strength, or chance, or fate,
+Too well I see and rue the dire event
+That, with sad overthrow and foul defeat,
+Hath lost us Heaven, and all this mighty host
+In horrible destruction laid thus low,
+As far as Gods and heavenly Essences
+Can perish: for the mind and spirit remains
+Invincible, and vigour soon returns,
+Though all our glory extinct, and happy state
+Here swallowed up in endless misery.
+But what if he our Conqueror (whom I now
+Of force believe almighty, since no less
+Than such could have o'erpowered such force as ours)
+Have left us this our spirit and strength entire,
+Strongly to suffer and support our pains,
+That we may so suffice his vengeful ire,
+Or do him mightier service as his thralls
+By right of war, whate'er his business be,
+Here in the heart of Hell to work in fire,
+Or do his errands in the gloomy Deep?
+What can it the avail though yet we feel
+Strength undiminished, or eternal being
+To undergo eternal punishment?"
+ Whereto with speedy words th' Arch-Fiend replied:--
+"Fallen Cherub, to be weak is miserable,
+Doing or suffering: but of this be sure--
+To do aught good never will be our task,
+But ever to do ill our sole delight,
+As being the contrary to his high will
+Whom we resist. If then his providence
+Out of our evil seek to bring forth good,
+Our labour must be to pervert that end,
+And out of good still to find means of evil;
+Which ofttimes may succeed so as perhaps
+Shall grieve him, if I fail not, and disturb
+His inmost counsels from their destined aim.
+But see! the angry Victor hath recalled
+His ministers of vengeance and pursuit
+Back to the gates of Heaven: the sulphurous hail,
+Shot after us in storm, o'erblown hath laid
+The fiery surge that from the precipice
+Of Heaven received us falling; and the thunder,
+Winged with red lightning and impetuous rage,
+Perhaps hath spent his shafts, and ceases now
+To bellow through the vast and boundless Deep.
+Let us not slip th' occasion, whether scorn
+Or satiate fury yield it from our Foe.
+Seest thou yon dreary plain, forlorn and wild,
+The seat of desolation, void of light,
+Save what the glimmering of these livid flames
+Casts pale and dreadful? Thither let us tend
+From off the tossing of these fiery waves;
+There rest, if any rest can harbour there;
+And, re-assembling our afflicted powers,
+Consult how we may henceforth most offend
+Our enemy, our own loss how repair,
+How overcome this dire calamity,
+What reinforcement we may gain from hope,
+If not, what resolution from despair."
+ Thus Satan, talking to his nearest mate,
+With head uplift above the wave, and eyes
+That sparkling blazed; his other parts besides
+Prone on the flood, extended long and large,
+Lay floating many a rood, in bulk as huge
+As whom the fables name of monstrous size,
+Titanian or Earth-born, that warred on Jove,
+Briareos or Typhon, whom the den
+By ancient Tarsus held, or that sea-beast
+Leviathan, which God of all his works
+Created hugest that swim th' ocean-stream.
+Him, haply slumbering on the Norway foam,
+The pilot of some small night-foundered skiff,
+Deeming some island, oft, as seamen tell,
+With fixed anchor in his scaly rind,
+Moors by his side under the lee, while night
+Invests the sea, and wished morn delays.
+So stretched out huge in length the Arch-fiend lay,
+Chained on the burning lake; nor ever thence
+Had risen, or heaved his head, but that the will
+And high permission of all-ruling Heaven
+Left him at large to his own dark designs,
+That with reiterated crimes he might
+Heap on himself damnation, while he sought
+Evil to others, and enraged might see
+How all his malice served but to bring forth
+Infinite goodness, grace, and mercy, shewn
+On Man by him seduced, but on himself
+Treble confusion, wrath, and vengeance poured.
+ Forthwith upright he rears from off the pool
+His mighty stature; on each hand the flames
+Driven backward slope their pointing spires, and,rolled
+In billows, leave i' th' midst a horrid vale.
+Then with expanded wings he steers his flight
+Aloft, incumbent on the dusky air,
+That felt unusual weight; till on dry land
+He lights--if it were land that ever burned
+With solid, as the lake with liquid fire,
+And such appeared in hue as when the force
+Of subterranean wind transprots a hill
+Torn from Pelorus, or the shattered side
+Of thundering Etna, whose combustible
+And fuelled entrails, thence conceiving fire,
+Sublimed with mineral fury, aid the winds,
+And leave a singed bottom all involved
+With stench and smoke. Such resting found the sole
+Of unblest feet. Him followed his next mate;
+Both glorying to have scaped the Stygian flood
+As gods, and by their own recovered strength,
+Not by the sufferance of supernal Power.
+ "Is this the region, this the soil, the clime,"
+Said then the lost Archangel, "this the seat
+That we must change for Heaven?--this mournful gloom
+For that celestial light? Be it so, since he
+Who now is sovereign can dispose and bid
+What shall be right: farthest from him is best
+Whom reason hath equalled, force hath made supreme
+Above his equals. Farewell, happy fields,
+Where joy for ever dwells! Hail, horrors! hail,
+Infernal world! and thou, profoundest Hell,
+Receive thy new possessor--one who brings
+A mind not to be changed by place or time.
+The mind is its own place, and in itself
+Can make a Heaven of Hell, a Hell of Heaven.
+What matter where, if I be still the same,
+And what I should be, all but less than he
+Whom thunder hath made greater? Here at least
+We shall be free; th' Almighty hath not built
+Here for his envy, will not drive us hence:
+Here we may reigh secure; and, in my choice,
+To reign is worth ambition, though in Hell:
+Better to reign in Hell than serve in Heaven.
+But wherefore let we then our faithful friends,
+Th' associates and co-partners of our loss,
+Lie thus astonished on th' oblivious pool,
+And call them not to share with us their part
+In this unhappy mansion, or once more
+With rallied arms to try what may be yet
+Regained in Heaven, or what more lost in Hell?"
+ So Satan spake; and him Beelzebub
+Thus answered:--"Leader of those armies bright
+Which, but th' Omnipotent, none could have foiled!
+If once they hear that voice, their liveliest pledge
+Of hope in fears and dangers--heard so oft
+In worst extremes, and on the perilous edge
+Of battle, when it raged, in all assaults
+Their surest signal--they will soon resume
+New courage and revive, though now they lie
+Grovelling and prostrate on yon lake of fire,
+As we erewhile, astounded and amazed;
+No wonder, fallen such a pernicious height!"
+ He scare had ceased when the superior Fiend
+Was moving toward the shore; his ponderous shield,
+Ethereal temper, massy, large, and round,
+Behind him cast. The broad circumference
+Hung on his shoulders like the moon, whose orb
+Through optic glass the Tuscan artist views
+At evening, from the top of Fesole,
+Or in Valdarno, to descry new lands,
+Rivers, or mountains, in her spotty globe.
+His spear--to equal which the tallest pine
+Hewn on Norwegian hills, to be the mast
+Of some great ammiral, were but a wand--
+He walked with, to support uneasy steps
+Over the burning marl, not like those steps
+On Heaven's azure; and the torrid clime
+Smote on him sore besides, vaulted with fire.
+Nathless he so endured, till on the beach
+Of that inflamed sea he stood, and called
+His legions--Angel Forms, who lay entranced
+Thick as autumnal leaves that strow the brooks
+In Vallombrosa, where th' Etrurian shades
+High over-arched embower; or scattered sedge
+Afloat, when with fierce winds Orion armed
+Hath vexed the Red-Sea coast, whose waves o'erthrew
+Busiris and his Memphian chivalry,
+While with perfidious hatred they pursued
+The sojourners of Goshen, who beheld
+From the safe shore their floating carcases
+And broken chariot-wheels. So thick bestrown,
+Abject and lost, lay these, covering the flood,
+Under amazement of their hideous change.
+He called so loud that all the hollow deep
+Of Hell resounded:--"Princes, Potentates,
+Warriors, the Flower of Heaven--once yours; now lost,
+If such astonishment as this can seize
+Eternal Spirits! Or have ye chosen this place
+After the toil of battle to repose
+Your wearied virtue, for the ease you find
+To slumber here, as in the vales of Heaven?
+Or in this abject posture have ye sworn
+To adore the Conqueror, who now beholds
+Cherub and Seraph rolling in the flood
+With scattered arms and ensigns, till anon
+His swift pursuers from Heaven-gates discern
+Th' advantage, and, descending, tread us down
+Thus drooping, or with linked thunderbolts
+Transfix us to the bottom of this gulf?
+Awake, arise, or be for ever fallen!"
+ They heard, and were abashed, and up they sprung
+Upon the wing, as when men wont to watch
+On duty, sleeping found by whom they dread,
+Rouse and bestir themselves ere well awake.
+Nor did they not perceive the evil plight
+In which they were, or the fierce pains not feel;
+Yet to their General's voice they soon obeyed
+Innumerable. As when the potent rod
+Of Amram's son, in Egypt's evil day,
+Waved round the coast, up-called a pitchy cloud
+Of locusts, warping on the eastern wind,
+That o'er the realm of impious Pharaoh hung
+Like Night, and darkened all the land of Nile;
+So numberless were those bad Angels seen
+Hovering on wing under the cope of Hell,
+'Twixt upper, nether, and surrounding fires;
+Till, as a signal given, th' uplifted spear
+Of their great Sultan waving to direct
+Their course, in even balance down they light
+On the firm brimstone, and fill all the plain:
+A multitude like which the populous North
+Poured never from her frozen loins to pass
+Rhene or the Danaw, when her barbarous sons
+Came like a deluge on the South, and spread
+Beneath Gibraltar to the Libyan sands.
+Forthwith, form every squadron and each band,
+The heads and leaders thither haste where stood
+Their great Commander--godlike Shapes, and Forms
+Excelling human; princely Dignities;
+And Powers that erst in Heaven sat on thrones,
+Though on their names in Heavenly records now
+Be no memorial, blotted out and rased
+By their rebellion from the Books of Life.
+Nor had they yet among the sons of Eve
+Got them new names, till, wandering o'er the earth,
+Through God's high sufferance for the trial of man,
+By falsities and lies the greatest part
+Of mankind they corrupted to forsake
+God their Creator, and th' invisible
+Glory of him that made them to transform
+Oft to the image of a brute, adorned
+With gay religions full of pomp and gold,
+And devils to adore for deities:
+Then were they known to men by various names,
+And various idols through the heathen world.
+ Say, Muse, their names then known, who first, who last,
+Roused from the slumber on that fiery couch,
+At their great Emperor's call, as next in worth
+Came singly where he stood on the bare strand,
+While the promiscuous crowd stood yet aloof?
+ The chief were those who, from the pit of Hell
+Roaming to seek their prey on Earth, durst fix
+Their seats, long after, next the seat of God,
+Their altars by his altar, gods adored
+Among the nations round, and durst abide
+Jehovah thundering out of Sion, throned
+Between the Cherubim; yea, often placed
+Within his sanctuary itself their shrines,
+Abominations; and with cursed things
+His holy rites and solemn feasts profaned,
+And with their darkness durst affront his light.
+First, Moloch, horrid king, besmeared with blood
+Of human sacrifice, and parents' tears;
+Though, for the noise of drums and timbrels loud,
+Their children's cries unheard that passed through fire
+To his grim idol. Him the Ammonite
+Worshiped in Rabba and her watery plain,
+In Argob and in Basan, to the stream
+Of utmost Arnon. Nor content with such
+Audacious neighbourhood, the wisest heart
+Of Solomon he led by fraoud to build
+His temple right against the temple of God
+On that opprobrious hill, and made his grove
+The pleasant valley of Hinnom, Tophet thence
+And black Gehenna called, the type of Hell.
+Next Chemos, th' obscene dread of Moab's sons,
+From Aroar to Nebo and the wild
+Of southmost Abarim; in Hesebon
+And Horonaim, Seon's real, beyond
+The flowery dale of Sibma clad with vines,
+And Eleale to th' Asphaltic Pool:
+Peor his other name, when he enticed
+Israel in Sittim, on their march from Nile,
+To do him wanton rites, which cost them woe.
+Yet thence his lustful orgies he enlarged
+Even to that hill of scandal, by the grove
+Of Moloch homicide, lust hard by hate,
+Till good Josiah drove them thence to Hell.
+With these came they who, from the bordering flood
+Of old Euphrates to the brook that parts
+Egypt from Syrian ground, had general names
+Of Baalim and Ashtaroth--those male,
+These feminine. For Spirits, when they please,
+Can either sex assume, or both; so soft
+And uncompounded is their essence pure,
+Not tried or manacled with joint or limb,
+Nor founded on the brittle strength of bones,
+Like cumbrous flesh; but, in what shape they choose,
+Dilated or condensed, bright or obscure,
+Can execute their airy purposes,
+And works of love or enmity fulfil.
+For those the race of Israel oft forsook
+Their Living Strength, and unfrequented left
+His righteous altar, bowing lowly down
+To bestial gods; for which their heads as low
+Bowed down in battle, sunk before the spear
+Of despicable foes. With these in troop
+Came Astoreth, whom the Phoenicians called
+Astarte, queen of heaven, with crescent horns;
+To whose bright image nigntly by the moon
+Sidonian virgins paid their vows and songs;
+In Sion also not unsung, where stood
+Her temple on th' offensive mountain, built
+By that uxorious king whose heart, though large,
+Beguiled by fair idolatresses, fell
+To idols foul. Thammuz came next behind,
+Whose annual wound in Lebanon allured
+The Syrian damsels to lament his fate
+In amorous ditties all a summer's day,
+While smooth Adonis from his native rock
+Ran purple to the sea, supposed with blood
+Of Thammuz yearly wounded: the love-tale
+Infected Sion's daughters with like heat,
+Whose wanton passions in the sacred proch
+Ezekiel saw, when, by the vision led,
+His eye surveyed the dark idolatries
+Of alienated Judah. Next came one
+Who mourned in earnest, when the captive ark
+Maimed his brute image, head and hands lopt off,
+In his own temple, on the grunsel-edge,
+Where he fell flat and shamed his worshippers:
+Dagon his name, sea-monster,upward man
+And downward fish; yet had his temple high
+Reared in Azotus, dreaded through the coast
+Of Palestine, in Gath and Ascalon,
+And Accaron and Gaza's frontier bounds.
+Him followed Rimmon, whose delightful seat
+Was fair Damascus, on the fertile banks
+Of Abbana and Pharphar, lucid streams.
+He also against the house of God was bold:
+A leper once he lost, and gained a king--
+Ahaz, his sottish conqueror, whom he drew
+God's altar to disparage and displace
+For one of Syrian mode, whereon to burn
+His odious offerings, and adore the gods
+Whom he had vanquished. After these appeared
+A crew who, under names of old renown--
+Osiris, Isis, Orus, and their train--
+With monstrous shapes and sorceries abused
+Fanatic Egypt and her priests to seek
+Their wandering gods disguised in brutish forms
+Rather than human. Nor did Israel scape
+Th' infection, when their borrowed gold composed
+The calf in Oreb; and the rebel king
+Doubled that sin in Bethel and in Dan,
+Likening his Maker to the grazed ox--
+Jehovah, who, in one night, when he passed
+From Egypt marching, equalled with one stroke
+Both her first-born and all her bleating gods.
+Belial came last; than whom a Spirit more lewd
+Fell not from Heaven, or more gross to love
+Vice for itself. To him no temple stood
+Or altar smoked; yet who more oft than he
+In temples and at altars, when the priest
+Turns atheist, as did Eli's sons, who filled
+With lust and violence the house of God?
+In courts and palaces he also reigns,
+And in luxurious cities, where the noise
+Of riot ascends above their loftiest towers,
+And injury and outrage; and, when night
+Darkens the streets, then wander forth the sons
+Of Belial, flown with insolence and wine.
+Witness the streets of Sodom, and that night
+In Gibeah, when the hospitable door
+Exposed a matron, to avoid worse rape.
+ These were the prime in order and in might:
+The rest were long to tell; though far renowned
+Th' Ionian gods--of Javan's issue held
+Gods, yet confessed later than Heaven and Earth,
+Their boasted parents;--Titan, Heaven's first-born,
+With his enormous brood, and birthright seized
+By younger Saturn: he from mightier Jove,
+His own and Rhea's son, like measure found;
+So Jove usurping reigned. These, first in Crete
+And Ida known, thence on the snowy top
+Of cold Olympus ruled the middle air,
+Their highest heaven; or on the Delphian cliff,
+Or in Dodona, and through all the bounds
+Of Doric land; or who with Saturn old
+Fled over Adria to th' Hesperian fields,
+And o'er the Celtic roamed the utmost Isles.
+ All these and more came flocking; but with looks
+Downcast and damp; yet such wherein appeared
+Obscure some glimpse of joy to have found their Chief
+Not in despair, to have found themselves not lost
+In loss itself; which on his countenance cast
+Like doubtful hue. But he, his wonted pride
+Soon recollecting, with high words, that bore
+Semblance of worth, not substance, gently raised
+Their fainting courage, and dispelled their fears.
+Then straight commands that, at the warlike sound
+Of trumpets loud and clarions, be upreared
+His mighty standard. That proud honour claimed
+Azazel as his right, a Cherub tall:
+Who forthwith from the glittering staff unfurled
+Th' imperial ensign; which, full high advanced,
+Shone like a meteor streaming to the wind,
+With gems and golden lustre rich emblazed,
+Seraphic arms and trophies; all the while
+Sonorous metal blowing martial sounds:
+At which the universal host up-sent
+A shout that tore Hell's concave, and beyond
+Frighted the reign of Chaos and old Night.
+All in a moment through the gloom were seen
+Ten thousand banners rise into the air,
+With orient colours waving: with them rose
+A forest huge of spears; and thronging helms
+Appeared, and serried shields in thick array
+Of depth immeasurable. Anon they move
+In perfect phalanx to the Dorian mood
+Of flutes and soft recorders--such as raised
+To height of noblest temper heroes old
+Arming to battle, and instead of rage
+Deliberate valour breathed, firm, and unmoved
+With dread of death to flight or foul retreat;
+Nor wanting power to mitigate and swage
+With solemn touches troubled thoughts, and chase
+Anguish and doubt and fear and sorrow and pain
+From mortal or immortal minds. Thus they,
+Breathing united force with fixed thought,
+Moved on in silence to soft pipes that charmed
+Their painful steps o'er the burnt soil. And now
+Advanced in view they stand--a horrid front
+Of dreadful length and dazzling arms, in guise
+Of warriors old, with ordered spear and shield,
+Awaiting what command their mighty Chief
+Had to impose. He through the armed files
+Darts his experienced eye, and soon traverse
+The whole battalion views--their order due,
+Their visages and stature as of gods;
+Their number last he sums. And now his heart
+Distends with pride, and, hardening in his strength,
+Glories: for never, since created Man,
+Met such embodied force as, named with these,
+Could merit more than that small infantry
+Warred on by cranes--though all the giant brood
+Of Phlegra with th' heroic race were joined
+That fought at Thebes and Ilium, on each side
+Mixed with auxiliar gods; and what resounds
+In fable or romance of Uther's son,
+Begirt with British and Armoric knights;
+And all who since, baptized or infidel,
+Jousted in Aspramont, or Montalban,
+Damasco, or Marocco, or Trebisond,
+Or whom Biserta sent from Afric shore
+When Charlemain with all his peerage fell
+By Fontarabbia. Thus far these beyond
+Compare of mortal prowess, yet observed
+Their dread Commander. He, above the rest
+In shape and gesture proudly eminent,
+Stood like a tower. His form had yet not lost
+All her original brightness, nor appeared
+Less than Archangel ruined, and th' excess
+Of glory obscured: as when the sun new-risen
+Looks through the horizontal misty air
+Shorn of his beams, or, from behind the moon,
+In dim eclipse, disastrous twilight sheds
+On half the nations, and with fear of change
+Perplexes monarchs. Darkened so, yet shone
+Above them all th' Archangel: but his face
+Deep scars of thunder had intrenched, and care
+Sat on his faded cheek, but under brows
+Of dauntless courage, and considerate pride
+Waiting revenge. Cruel his eye, but cast
+Signs of remorse and passion, to behold
+The fellows of his crime, the followers rather
+(Far other once beheld in bliss), condemned
+For ever now to have their lot in pain--
+Millions of Spirits for his fault amerced
+Of Heaven, and from eteranl splendours flung
+For his revolt--yet faithful how they stood,
+Their glory withered; as, when heaven's fire
+Hath scathed the forest oaks or mountain pines,
+With singed top their stately growth, though bare,
+Stands on the blasted heath. He now prepared
+To speak; whereat their doubled ranks they bend
+From wing to wing, and half enclose him round
+With all his peers: attention held them mute.
+Thrice he assayed, and thrice, in spite of scorn,
+Tears, such as Angels weep, burst forth: at last
+Words interwove with sighs found out their way:--
+ "O myriads of immortal Spirits! O Powers
+Matchless, but with th' Almighth!--and that strife
+Was not inglorious, though th' event was dire,
+As this place testifies, and this dire change,
+Hateful to utter. But what power of mind,
+Forseeing or presaging, from the depth
+Of knowledge past or present, could have feared
+How such united force of gods, how such
+As stood like these, could ever know repulse?
+For who can yet believe, though after loss,
+That all these puissant legions, whose exile
+Hath emptied Heaven, shall fail to re-ascend,
+Self-raised, and repossess their native seat?
+For me, be witness all the host of Heaven,
+If counsels different, or danger shunned
+By me, have lost our hopes. But he who reigns
+Monarch in Heaven till then as one secure
+Sat on his throne, upheld by old repute,
+Consent or custom, and his regal state
+Put forth at full, but still his strength concealed--
+Which tempted our attempt, and wrought our fall.
+Henceforth his might we know, and know our own,
+So as not either to provoke, or dread
+New war provoked: our better part remains
+To work in close design, by fraud or guile,
+What force effected not; that he no less
+At length from us may find, who overcomes
+By force hath overcome but half his foe.
+Space may produce new Worlds; whereof so rife
+There went a fame in Heaven that he ere long
+Intended to create, and therein plant
+A generation whom his choice regard
+Should favour equal to the Sons of Heaven.
+Thither, if but to pry, shall be perhaps
+Our first eruption--thither, or elsewhere;
+For this infernal pit shall never hold
+Celestial Spirits in bondage, nor th' Abyss
+Long under darkness cover. But these thoughts
+Full counsel must mature. Peace is despaired;
+For who can think submission? War, then, war
+Open or understood, must be resolved."
+ He spake; and, to confirm his words, outflew
+Millions of flaming swords, drawn from the thighs
+Of mighty Cherubim; the sudden blaze
+Far round illumined Hell. Highly they raged
+Against the Highest, and fierce with grasped arms
+Clashed on their sounding shields the din of war,
+Hurling defiance toward the vault of Heaven.
+ There stood a hill not far, whose grisly top
+Belched fire and rolling smoke; the rest entire
+Shone with a glossy scurf--undoubted sign
+That in his womb was hid metallic ore,
+The work of sulphur. Thither, winged with speed,
+A numerous brigade hastened: as when bands
+Of pioneers, with spade and pickaxe armed,
+Forerun the royal camp, to trench a field,
+Or cast a rampart. Mammon led them on--
+Mammon, the least erected Spirit that fell
+From Heaven; for even in Heaven his looks and thoughts
+Were always downward bent, admiring more
+The riches of heaven's pavement, trodden gold,
+Than aught divine or holy else enjoyed
+In vision beatific. By him first
+Men also, and by his suggestion taught,
+Ransacked the centre, and with impious hands
+Rifled the bowels of their mother Earth
+For treasures better hid. Soon had his crew
+Opened into the hill a spacious wound,
+And digged out ribs of gold. Let none admire
+That riches grow in Hell; that soil may best
+Deserve the precious bane. And here let those
+Who boast in mortal things, and wondering tell
+Of Babel, and the works of Memphian kings,
+Learn how their greatest monuments of fame
+And strength, and art, are easily outdone
+By Spirits reprobate, and in an hour
+What in an age they, with incessant toil
+And hands innumerable, scarce perform.
+Nigh on the plain, in many cells prepared,
+That underneath had veins of liquid fire
+Sluiced from the lake, a second multitude
+With wondrous art founded the massy ore,
+Severing each kind, and scummed the bullion-dross.
+A third as soon had formed within the ground
+A various mould, and from the boiling cells
+By strange conveyance filled each hollow nook;
+As in an organ, from one blast of wind,
+To many a row of pipes the sound-board breathes.
+Anon out of the earth a fabric huge
+Rose like an exhalation, with the sound
+Of dulcet symphonies and voices sweet--
+Built like a temple, where pilasters round
+Were set, and Doric pillars overlaid
+With golden architrave; nor did there want
+Cornice or frieze, with bossy sculptures graven;
+The roof was fretted gold. Not Babylon
+Nor great Alcairo such magnificence
+Equalled in all their glories, to enshrine
+Belus or Serapis their gods, or seat
+Their kings, when Egypt with Assyria strove
+In wealth and luxury. Th' ascending pile
+Stood fixed her stately height, and straight the doors,
+Opening their brazen folds, discover, wide
+Within, her ample spaces o'er the smooth
+And level pavement: from the arched roof,
+Pendent by subtle magic, many a row
+Of starry lamps and blazing cressets, fed
+With naptha and asphaltus, yielded light
+As from a sky. The hasty multitude
+Admiring entered; and the work some praise,
+And some the architect. His hand was known
+In Heaven by many a towered structure high,
+Where sceptred Angels held their residence,
+And sat as Princes, whom the supreme King
+Exalted to such power, and gave to rule,
+Each in his Hierarchy, the Orders bright.
+Nor was his name unheard or unadored
+In ancient Greece; and in Ausonian land
+Men called him Mulciber; and how he fell
+From Heaven they fabled, thrown by angry Jove
+Sheer o'er the crystal battlements: from morn
+To noon he fell, from noon to dewy eve,
+A summer's day, and with the setting sun
+Dropt from the zenith, like a falling star,
+On Lemnos, th' Aegaean isle. Thus they relate,
+Erring; for he with this rebellious rout
+Fell long before; nor aught aviled him now
+To have built in Heaven high towers; nor did he scape
+By all his engines, but was headlong sent,
+With his industrious crew, to build in Hell.
+ Meanwhile the winged Heralds, by command
+Of sovereign power, with awful ceremony
+And trumpet's sound, throughout the host proclaim
+A solemn council forthwith to be held
+At Pandemonium, the high capital
+Of Satan and his peers. Their summons called
+From every band and squared regiment
+By place or choice the worthiest: they anon
+With hundreds and with thousands trooping came
+Attended. All access was thronged; the gates
+And porches wide, but chief the spacious hall
+(Though like a covered field, where champions bold
+Wont ride in armed, and at the Soldan's chair
+Defied the best of Paynim chivalry
+To mortal combat, or career with lance),
+Thick swarmed, both on the ground and in the air,
+Brushed with the hiss of rustling wings. As bees
+In spring-time, when the Sun with Taurus rides.
+Pour forth their populous youth about the hive
+In clusters; they among fresh dews and flowers
+Fly to and fro, or on the smoothed plank,
+The suburb of their straw-built citadel,
+New rubbed with balm, expatiate, and confer
+Their state-affairs: so thick the airy crowd
+Swarmed and were straitened; till, the signal given,
+Behold a wonder! They but now who seemed
+In bigness to surpass Earth's giant sons,
+Now less than smallest dwarfs, in narrow room
+Throng numberless--like that pygmean race
+Beyond the Indian mount; or faery elves,
+Whose midnight revels, by a forest-side
+Or fountain, some belated peasant sees,
+Or dreams he sees, while overhead the Moon
+Sits arbitress, and nearer to the Earth
+Wheels her pale course: they, on their mirth and dance
+Intent, with jocund music charm his ear;
+At once with joy and fear his heart rebounds.
+Thus incorporeal Spirits to smallest forms
+Reduced their shapes immense, and were at large,
+Though without number still, amidst the hall
+Of that infernal court. But far within,
+And in their own dimensions like themselves,
+The great Seraphic Lords and Cherubim
+In close recess and secret conclave sat,
+A thousand demi-gods on golden seats,
+Frequent and full. After short silence then,
+And summons read, the great consult began.
+
+
+
+Book II
+
+
+High on a throne of royal state, which far
+Outshone the wealth or Ormus and of Ind,
+Or where the gorgeous East with richest hand
+Showers on her kings barbaric pearl and gold,
+Satan exalted sat, by merit raised
+To that bad eminence; and, from despair
+Thus high uplifted beyond hope, aspires
+Beyond thus high, insatiate to pursue
+Vain war with Heaven; and, by success untaught,
+His proud imaginations thus displayed:--
+ "Powers and Dominions, Deities of Heaven!--
+For, since no deep within her gulf can hold
+Immortal vigour, though oppressed and fallen,
+I give not Heaven for lost: from this descent
+Celestial Virtues rising will appear
+More glorious and more dread than from no fall,
+And trust themselves to fear no second fate!--
+Me though just right, and the fixed laws of Heaven,
+Did first create your leader--next, free choice
+With what besides in council or in fight
+Hath been achieved of merit--yet this loss,
+Thus far at least recovered, hath much more
+Established in a safe, unenvied throne,
+Yielded with full consent. The happier state
+In Heaven, which follows dignity, might draw
+Envy from each inferior; but who here
+Will envy whom the highest place exposes
+Foremost to stand against the Thunderer's aim
+Your bulwark, and condemns to greatest share
+Of endless pain? Where there is, then, no good
+For which to strive, no strife can grow up there
+From faction: for none sure will claim in Hell
+Precedence; none whose portion is so small
+Of present pain that with ambitious mind
+Will covet more! With this advantage, then,
+To union, and firm faith, and firm accord,
+More than can be in Heaven, we now return
+To claim our just inheritance of old,
+Surer to prosper than prosperity
+Could have assured us; and by what best way,
+Whether of open war or covert guile,
+We now debate. Who can advise may speak."
+ He ceased; and next him Moloch, sceptred king,
+Stood up--the strongest and the fiercest Spirit
+That fought in Heaven, now fiercer by despair.
+His trust was with th' Eternal to be deemed
+Equal in strength, and rather than be less
+Cared not to be at all; with that care lost
+Went all his fear: of God, or Hell, or worse,
+He recked not, and these words thereafter spake:--
+ "My sentence is for open war. Of wiles,
+More unexpert, I boast not: them let those
+Contrive who need, or when they need; not now.
+For, while they sit contriving, shall the rest--
+Millions that stand in arms, and longing wait
+The signal to ascend--sit lingering here,
+Heaven's fugitives, and for their dwelling-place
+Accept this dark opprobrious den of shame,
+The prison of his ryranny who reigns
+By our delay? No! let us rather choose,
+Armed with Hell-flames and fury, all at once
+O'er Heaven's high towers to force resistless way,
+Turning our tortures into horrid arms
+Against the Torturer; when, to meet the noise
+Of his almighty engine, he shall hear
+Infernal thunder, and, for lightning, see
+Black fire and horror shot with equal rage
+Among his Angels, and his throne itself
+Mixed with Tartarean sulphur and strange fire,
+His own invented torments. But perhaps
+The way seems difficult, and steep to scale
+With upright wing against a higher foe!
+Let such bethink them, if the sleepy drench
+Of that forgetful lake benumb not still,
+That in our porper motion we ascend
+Up to our native seat; descent and fall
+To us is adverse. Who but felt of late,
+When the fierce foe hung on our broken rear
+Insulting, and pursued us through the Deep,
+With what compulsion and laborious flight
+We sunk thus low? Th' ascent is easy, then;
+Th' event is feared! Should we again provoke
+Our stronger, some worse way his wrath may find
+To our destruction, if there be in Hell
+Fear to be worse destroyed! What can be worse
+Than to dwell here, driven out from bliss, condemned
+In this abhorred deep to utter woe!
+Where pain of unextinguishable fire
+Must exercise us without hope of end
+The vassals of his anger, when the scourge
+Inexorably, and the torturing hour,
+Calls us to penance? More destroyed than thus,
+We should be quite abolished, and expire.
+What fear we then? what doubt we to incense
+His utmost ire? which, to the height enraged,
+Will either quite consume us, and reduce
+To nothing this essential--happier far
+Than miserable to have eternal being!--
+Or, if our substance be indeed divine,
+And cannot cease to be, we are at worst
+On this side nothing; and by proof we feel
+Our power sufficient to disturb his Heaven,
+And with perpetual inroads to alarm,
+Though inaccessible, his fatal throne:
+Which, if not victory, is yet revenge."
+ He ended frowning, and his look denounced
+Desperate revenge, and battle dangerous
+To less than gods. On th' other side up rose
+Belial, in act more graceful and humane.
+A fairer person lost not Heaven; he seemed
+For dignity composed, and high exploit.
+But all was false and hollow; though his tongue
+Dropped manna, and could make the worse appear
+The better reason, to perplex and dash
+Maturest counsels: for his thoughts were low--
+ To vice industrious, but to nobler deeds
+Timorous and slothful. Yet he pleased the ear,
+And with persuasive accent thus began:--
+ "I should be much for open war, O Peers,
+As not behind in hate, if what was urged
+Main reason to persuade immediate war
+Did not dissuade me most, and seem to cast
+Ominous conjecture on the whole success;
+When he who most excels in fact of arms,
+In what he counsels and in what excels
+Mistrustful, grounds his courage on despair
+And utter dissolution, as the scope
+Of all his aim, after some dire revenge.
+First, what revenge? The towers of Heaven are filled
+With armed watch, that render all access
+Impregnable: oft on the bodering Deep
+Encamp their legions, or with obscure wing
+Scout far and wide into the realm of Night,
+Scorning surprise. Or, could we break our way
+By force, and at our heels all Hell should rise
+With blackest insurrection to confound
+Heaven's purest light, yet our great Enemy,
+All incorruptible, would on his throne
+Sit unpolluted, and th' ethereal mould,
+Incapable of stain, would soon expel
+Her mischief, and purge off the baser fire,
+Victorious. Thus repulsed, our final hope
+Is flat despair: we must exasperate
+Th' Almighty Victor to spend all his rage;
+And that must end us; that must be our cure--
+To be no more. Sad cure! for who would lose,
+Though full of pain, this intellectual being,
+Those thoughts that wander through eternity,
+To perish rather, swallowed up and lost
+In the wide womb of uncreated Night,
+Devoid of sense and motion? And who knows,
+Let this be good, whether our angry Foe
+Can give it, or will ever? How he can
+Is doubtful; that he never will is sure.
+Will he, so wise, let loose at once his ire,
+Belike through impotence or unaware,
+To give his enemies their wish, and end
+Them in his anger whom his anger saves
+To punish endless? 'Wherefore cease we, then?'
+Say they who counsel war; 'we are decreed,
+Reserved, and destined to eternal woe;
+Whatever doing, what can we suffer more,
+What can we suffer worse?' Is this, then, worst--
+Thus sitting, thus consulting, thus in arms?
+What when we fled amain, pursued and struck
+With Heaven's afflicting thunder, and besought
+The Deep to shelter us? This Hell then seemed
+A refuge from those wounds. Or when we lay
+Chained on the burning lake? That sure was worse.
+What if the breath that kindled those grim fires,
+Awaked, should blow them into sevenfold rage,
+And plunge us in the flames; or from above
+Should intermitted vengeance arm again
+His red right hand to plague us? What if all
+Her stores were opened, and this firmament
+Of Hell should spout her cataracts of fire,
+Impendent horrors, threatening hideous fall
+One day upon our heads; while we perhaps,
+Designing or exhorting glorious war,
+Caught in a fiery tempest, shall be hurled,
+Each on his rock transfixed, the sport and prey
+Or racking whirlwinds, or for ever sunk
+Under yon boiling ocean, wrapt in chains,
+There to converse with everlasting groans,
+Unrespited, unpitied, unreprieved,
+Ages of hopeless end? This would be worse.
+War, therefore, open or concealed, alike
+My voice dissuades; for what can force or guile
+With him, or who deceive his mind, whose eye
+Views all things at one view? He from Heaven's height
+All these our motions vain sees and derides,
+Not more almighty to resist our might
+Than wise to frustrate all our plots and wiles.
+Shall we, then, live thus vile--the race of Heaven
+Thus trampled, thus expelled, to suffer here
+Chains and these torments? Better these than worse,
+By my advice; since fate inevitable
+Subdues us, and omnipotent decree,
+The Victor's will. To suffer, as to do,
+Our strength is equal; nor the law unjust
+That so ordains. This was at first resolved,
+If we were wise, against so great a foe
+Contending, and so doubtful what might fall.
+I laugh when those who at the spear are bold
+And venturous, if that fail them, shrink, and fear
+What yet they know must follow--to endure
+Exile, or igominy, or bonds, or pain,
+The sentence of their Conqueror. This is now
+Our doom; which if we can sustain and bear,
+Our Supreme Foe in time may much remit
+His anger, and perhaps, thus far removed,
+Not mind us not offending, satisfied
+With what is punished; whence these raging fires
+Will slacken, if his breath stir not their flames.
+Our purer essence then will overcome
+Their noxious vapour; or, inured, not feel;
+Or, changed at length, and to the place conformed
+In temper and in nature, will receive
+Familiar the fierce heat; and, void of pain,
+This horror will grow mild, this darkness light;
+Besides what hope the never-ending flight
+Of future days may bring, what chance, what change
+Worth waiting--since our present lot appears
+For happy though but ill, for ill not worst,
+If we procure not to ourselves more woe."
+ Thus Belial, with words clothed in reason's garb,
+Counselled ignoble ease and peaceful sloth,
+Not peace; and after him thus Mammon spake:--
+ "Either to disenthrone the King of Heaven
+We war, if war be best, or to regain
+Our own right lost. Him to unthrone we then
+May hope, when everlasting Fate shall yield
+To fickle Chance, and Chaos judge the strife.
+The former, vain to hope, argues as vain
+The latter; for what place can be for us
+Within Heaven's bound, unless Heaven's Lord supreme
+We overpower? Suppose he should relent
+And publish grace to all, on promise made
+Of new subjection; with what eyes could we
+Stand in his presence humble, and receive
+Strict laws imposed, to celebrate his throne
+With warbled hyms, and to his Godhead sing
+Forced hallelujahs, while he lordly sits
+Our envied sovereign, and his altar breathes
+Ambrosial odours and ambrosial flowers,
+Our servile offerings? This must be our task
+In Heaven, this our delight. How wearisome
+Eternity so spent in worship paid
+To whom we hate! Let us not then pursue,
+By force impossible, by leave obtained
+Unacceptable, though in Heaven, our state
+Of splendid vassalage; but rather seek
+Our own good from ourselves, and from our own
+Live to ourselves, though in this vast recess,
+Free and to none accountable, preferring
+Hard liberty before the easy yoke
+Of servile pomp. Our greatness will appear
+Then most conspicuous when great things of small,
+Useful of hurtful, prosperous of adverse,
+We can create, and in what place soe'er
+Thrive under evil, and work ease out of pain
+Through labour and endurance. This deep world
+Of darkness do we dread? How oft amidst
+Thick clouds and dark doth Heaven's all-ruling Sire
+Choose to reside, his glory unobscured,
+And with the majesty of darkness round
+Covers his throne, from whence deep thunders roar.
+Mustering their rage, and Heaven resembles Hell!
+As he our darkness, cannot we his light
+Imitate when we please? This desert soil
+Wants not her hidden lustre, gems and gold;
+Nor want we skill or art from whence to raise
+Magnificence; and what can Heaven show more?
+Our torments also may, in length of time,
+Become our elements, these piercing fires
+As soft as now severe, our temper changed
+Into their temper; which must needs remove
+The sensible of pain. All things invite
+To peaceful counsels, and the settled state
+Of order, how in safety best we may
+Compose our present evils, with regard
+Of what we are and where, dismissing quite
+All thoughts of war. Ye have what I advise."
+ He scarce had finished, when such murmur filled
+Th' assembly as when hollow rocks retain
+The sound of blustering winds, which all night long
+Had roused the sea, now with hoarse cadence lull
+Seafaring men o'erwatched, whose bark by chance
+Or pinnace, anchors in a craggy bay
+After the tempest. Such applause was heard
+As Mammon ended, and his sentence pleased,
+Advising peace: for such another field
+They dreaded worse than Hell; so much the fear
+Of thunder and the sword of Michael
+Wrought still within them; and no less desire
+To found this nether empire, which might rise,
+By policy and long process of time,
+In emulation opposite to Heaven.
+Which when Beelzebub perceived--than whom,
+Satan except, none higher sat--with grave
+Aspect he rose, and in his rising seemed
+A pillar of state. Deep on his front engraven
+Deliberation sat, and public care;
+And princely counsel in his face yet shone,
+Majestic, though in ruin. Sage he stood
+With Atlantean shoulders, fit to bear
+The weight of mightiest monarchies; his look
+Drew audience and attention still as night
+Or summer's noontide air, while thus he spake:--
+ "Thrones and Imperial Powers, Offspring of Heaven,
+Ethereal Virtues! or these titles now
+Must we renounce, and, changing style, be called
+Princes of Hell? for so the popular vote
+Inclines--here to continue, and build up here
+A growing empire; doubtless! while we dream,
+And know not that the King of Heaven hath doomed
+This place our dungeon, not our safe retreat
+Beyond his potent arm, to live exempt
+From Heaven's high jurisdiction, in new league
+Banded against his throne, but to remain
+In strictest bondage, though thus far removed,
+Under th' inevitable curb, reserved
+His captive multitude. For he, to be sure,
+In height or depth, still first and last will reign
+Sole king, and of his kingdom lose no part
+By our revolt, but over Hell extend
+His empire, and with iron sceptre rule
+Us here, as with his golden those in Heaven.
+What sit we then projecting peace and war?
+War hath determined us and foiled with loss
+Irreparable; terms of peace yet none
+Vouchsafed or sought; for what peace will be given
+To us enslaved, but custody severe,
+And stripes and arbitrary punishment
+Inflicted? and what peace can we return,
+But, to our power, hostility and hate,
+Untamed reluctance, and revenge, though slow,
+Yet ever plotting how the Conqueror least
+May reap his conquest, and may least rejoice
+In doing what we most in suffering feel?
+Nor will occasion want, nor shall we need
+With dangerous expedition to invade
+Heaven, whose high walls fear no assault or siege,
+Or ambush from the Deep. What if we find
+Some easier enterprise? There is a place
+(If ancient and prophetic fame in Heaven
+Err not)--another World, the happy seat
+Of some new race, called Man, about this time
+To be created like to us, though less
+In power and excellence, but favoured more
+Of him who rules above; so was his will
+Pronounced among the Gods, and by an oath
+That shook Heaven's whole circumference confirmed.
+Thither let us bend all our thoughts, to learn
+What creatures there inhabit, of what mould
+Or substance, how endued, and what their power
+And where their weakness: how attempted best,
+By force of subtlety. Though Heaven be shut,
+And Heaven's high Arbitrator sit secure
+In his own strength, this place may lie exposed,
+The utmost border of his kingdom, left
+To their defence who hold it: here, perhaps,
+Some advantageous act may be achieved
+By sudden onset--either with Hell-fire
+To waste his whole creation, or possess
+All as our own, and drive, as we were driven,
+The puny habitants; or, if not drive,
+Seduce them to our party, that their God
+May prove their foe, and with repenting hand
+Abolish his own works. This would surpass
+Common revenge, and interrupt his joy
+In our confusion, and our joy upraise
+In his disturbance; when his darling sons,
+Hurled headlong to partake with us, shall curse
+Their frail original, and faded bliss--
+Faded so soon! Advise if this be worth
+Attempting, or to sit in darkness here
+Hatching vain empires." Thus beelzebub
+Pleaded his devilish counsel--first devised
+By Satan, and in part proposed: for whence,
+But from the author of all ill, could spring
+So deep a malice, to confound the race
+Of mankind in one root, and Earth with Hell
+To mingle and involve, done all to spite
+The great Creator? But their spite still serves
+His glory to augment. The bold design
+Pleased highly those infernal States, and joy
+Sparkled in all their eyes: with full assent
+They vote: whereat his speech he thus renews:--
+"Well have ye judged, well ended long debate,
+Synod of Gods, and, like to what ye are,
+Great things resolved, which from the lowest deep
+Will once more lift us up, in spite of fate,
+Nearer our ancient seat--perhaps in view
+Of those bright confines, whence, with neighbouring arms,
+And opportune excursion, we may chance
+Re-enter Heaven; or else in some mild zone
+Dwell, not unvisited of Heaven's fair light,
+Secure, and at the brightening orient beam
+Purge off this gloom: the soft delicious air,
+To heal the scar of these corrosive fires,
+Shall breathe her balm. But, first, whom shall we send
+In search of this new World? whom shall we find
+Sufficient? who shall tempt with wandering feet
+The dark, unbottomed, infinite Abyss,
+And through the palpable obscure find out
+His uncouth way, or spread his airy flight,
+Upborne with indefatigable wings
+Over the vast abrupt, ere he arrive
+The happy Isle? What strength, what art, can then
+Suffice, or what evasion bear him safe,
+Through the strict senteries and stations thick
+Of Angels watching round? Here he had need
+All circumspection: and we now no less
+Choice in our suffrage; for on whom we send
+The weight of all, and our last hope, relies."
+ This said, he sat; and expectation held
+His look suspense, awaiting who appeared
+To second, or oppose, or undertake
+The perilous attempt. But all sat mute,
+Pondering the danger with deep thoughts; and each
+In other's countenance read his own dismay,
+Astonished. None among the choice and prime
+Of those Heaven-warring champions could be found
+So hardy as to proffer or accept,
+Alone, the dreadful voyage; till, at last,
+Satan, whom now transcendent glory raised
+Above his fellows, with monarchal pride
+Conscious of highest worth, unmoved thus spake:--
+ "O Progeny of Heaven! Empyreal Thrones!
+With reason hath deep silence and demur
+Seized us, though undismayed. Long is the way
+And hard, that out of Hell leads up to light.
+Our prison strong, this huge convex of fire,
+Outrageous to devour, immures us round
+Ninefold; and gates of burning adamant,
+Barred over us, prohibit all egress.
+These passed, if any pass, the void profound
+Of unessential Night receives him next,
+Wide-gaping, and with utter loss of being
+Threatens him, plunged in that abortive gulf.
+If thence he scape, into whatever world,
+Or unknown region, what remains him less
+Than unknown dangers, and as hard escape?
+But I should ill become this throne, O Peers,
+And this imperial sovereignty, adorned
+With splendour, armed with power, if aught proposed
+And judged of public moment in the shape
+Of difficulty or danger, could deter
+Me from attempting. Wherefore do I assume
+These royalties, and not refuse to reign,
+Refusing to accept as great a share
+Of hazard as of honour, due alike
+To him who reigns, and so much to him due
+Of hazard more as he above the rest
+High honoured sits? Go, therefore, mighty Powers,
+Terror of Heaven, though fallen; intend at home,
+While here shall be our home, what best may ease
+The present misery, and render Hell
+More tolerable; if there be cure or charm
+To respite, or deceive, or slack the pain
+Of this ill mansion: intermit no watch
+Against a wakeful foe, while I abroad
+Through all the coasts of dark destruction seek
+Deliverance for us all. This enterprise
+None shall partake with me." Thus saying, rose
+The Monarch, and prevented all reply;
+Prudent lest, from his resolution raised,
+Others among the chief might offer now,
+Certain to be refused, what erst they feared,
+And, so refused, might in opinion stand
+His rivals, winning cheap the high repute
+Which he through hazard huge must earn. But they
+Dreaded not more th' adventure than his voice
+Forbidding; and at once with him they rose.
+Their rising all at once was as the sound
+Of thunder heard remote. Towards him they bend
+With awful reverence prone, and as a God
+Extol him equal to the Highest in Heaven.
+Nor failed they to express how much they praised
+That for the general safety he despised
+His own: for neither do the Spirits damned
+Lose all their virtue; lest bad men should boast
+Their specious deeds on earth, which glory excites,
+Or close ambition varnished o'er with zeal.
+ Thus they their doubtful consultations dark
+Ended, rejoicing in their matchless Chief:
+As, when from mountain-tops the dusky clouds
+Ascending, while the north wind sleeps, o'erspread
+Heaven's cheerful face, the louring element
+Scowls o'er the darkened landscape snow or shower,
+If chance the radiant sun, with farewell sweet,
+Extend his evening beam, the fields revive,
+The birds their notes renew, and bleating herds
+Attest their joy, that hill and valley rings.
+O shame to men! Devil with devil damned
+Firm concord holds; men only disagree
+Of creatures rational, though under hope
+Of heavenly grace, and, God proclaiming peace,
+Yet live in hatred, enmity, and strife
+Among themselves, and levy cruel wars
+Wasting the earth, each other to destroy:
+As if (which might induce us to accord)
+Man had not hellish foes enow besides,
+That day and night for his destruction wait!
+ The Stygian council thus dissolved; and forth
+In order came the grand infernal Peers:
+Midst came their mighty Paramount, and seemed
+Alone th' antagonist of Heaven, nor less
+Than Hell's dread Emperor, with pomp supreme,
+And god-like imitated state: him round
+A globe of fiery Seraphim enclosed
+With bright emblazonry, and horrent arms.
+Then of their session ended they bid cry
+With trumpet's regal sound the great result:
+Toward the four winds four speedy Cherubim
+Put to their mouths the sounding alchemy,
+By herald's voice explained; the hollow Abyss
+Heard far adn wide, and all the host of Hell
+With deafening shout returned them loud acclaim.
+Thence more at ease their minds, and somewhat raised
+By false presumptuous hope, the ranged Powers
+Disband; and, wandering, each his several way
+Pursues, as inclination or sad choice
+Leads him perplexed, where he may likeliest find
+Truce to his restless thoughts, and entertain
+The irksome hours, till his great Chief return.
+Part on the plain, or in the air sublime,
+Upon the wing or in swift race contend,
+As at th' Olympian games or Pythian fields;
+Part curb their fiery steeds, or shun the goal
+With rapid wheels, or fronted brigades form:
+As when, to warn proud cities, war appears
+Waged in the troubled sky, and armies rush
+To battle in the clouds; before each van
+Prick forth the airy knights, and couch their spears,
+Till thickest legions close; with feats of arms
+From either end of heaven the welkin burns.
+Others, with vast Typhoean rage, more fell,
+Rend up both rocks and hills, and ride the air
+In whirlwind; Hell scarce holds the wild uproar:--
+As when Alcides, from Oechalia crowned
+With conquest, felt th' envenomed robe, and tore
+Through pain up by the roots Thessalian pines,
+And Lichas from the top of Oeta threw
+Into th' Euboic sea. Others, more mild,
+Retreated in a silent valley, sing
+With notes angelical to many a harp
+Their own heroic deeds, and hapless fall
+By doom of battle, and complain that Fate
+Free Virtue should enthrall to Force or Chance.
+Their song was partial; but the harmony
+(What could it less when Spirits immortal sing?)
+Suspended Hell, and took with ravishment
+The thronging audience. In discourse more sweet
+(For Eloquence the Soul, Song charms the Sense)
+Others apart sat on a hill retired,
+In thoughts more elevate, and reasoned high
+Of Providence, Foreknowledge, Will, and Fate--
+Fixed fate, free will, foreknowledge absolute,
+And found no end, in wandering mazes lost.
+Of good and evil much they argued then,
+Of happiness and final misery,
+Passion and apathy, and glory and shame:
+Vain wisdom all, and false philosophy!--
+Yet, with a pleasing sorcery, could charm
+Pain for a while or anguish, and excite
+Fallacious hope, or arm th' obdured breast
+With stubborn patience as with triple steel.
+Another part, in squadrons and gross bands,
+On bold adventure to discover wide
+That dismal world, if any clime perhaps
+Might yield them easier habitation, bend
+Four ways their flying march, along the banks
+Of four infernal rivers, that disgorge
+Into the burning lake their baleful streams--
+Abhorred Styx, the flood of deadly hate;
+Sad Acheron of sorrow, black and deep;
+Cocytus, named of lamentation loud
+Heard on the rueful stream; fierce Phlegeton,
+Whose waves of torrent fire inflame with rage.
+Far off from these, a slow and silent stream,
+Lethe, the river of oblivion, rolls
+Her watery labyrinth, whereof who drinks
+Forthwith his former state and being forgets--
+Forgets both joy and grief, pleasure and pain.
+Beyond this flood a frozen continent
+Lies dark and wild, beat with perpetual storms
+Of whirlwind and dire hail, which on firm land
+Thaws not, but gathers heap, and ruin seems
+Of ancient pile; all else deep snow and ice,
+A gulf profound as that Serbonian bog
+Betwixt Damiata and Mount Casius old,
+Where armies whole have sunk: the parching air
+Burns frore, and cold performs th' effect of fire.
+Thither, by harpy-footed Furies haled,
+At certain revolutions all the damned
+Are brought; and feel by turns the bitter change
+Of fierce extremes, extremes by change more fierce,
+From beds of raging fire to starve in ice
+Their soft ethereal warmth, and there to pine
+Immovable, infixed, and frozen round
+Periods of time,--thence hurried back to fire.
+They ferry over this Lethean sound
+Both to and fro, their sorrow to augment,
+And wish and struggle, as they pass, to reach
+The tempting stream, with one small drop to lose
+In sweet forgetfulness all pain and woe,
+All in one moment, and so near the brink;
+But Fate withstands, and, to oppose th' attempt,
+Medusa with Gorgonian terror guards
+The ford, and of itself the water flies
+All taste of living wight, as once it fled
+The lip of Tantalus. Thus roving on
+In confused march forlorn, th' adventurous bands,
+With shuddering horror pale, and eyes aghast,
+Viewed first their lamentable lot, and found
+No rest. Through many a dark and dreary vale
+They passed, and many a region dolorous,
+O'er many a frozen, many a fiery alp,
+Rocks, caves, lakes, fens, bogs, dens, and shades of death--
+A universe of death, which God by curse
+Created evil, for evil only good;
+Where all life dies, death lives, and Nature breeds,
+Perverse, all monstrous, all prodigious things,
+Obominable, inutterable, and worse
+Than fables yet have feigned or fear conceived,
+Gorgons, and Hydras, and Chimeras dire.
+ Meanwhile the Adversary of God and Man,
+Satan, with thoughts inflamed of highest design,
+Puts on swift wings, and toward the gates of Hell
+Explores his solitary flight: sometimes
+He scours the right hand coast, sometimes the left;
+Now shaves with level wing the deep, then soars
+Up to the fiery concave towering high.
+As when far off at sea a fleet descried
+Hangs in the clouds, by equinoctial winds
+Close sailing from Bengala, or the isles
+Of Ternate and Tidore, whence merchants bring
+Their spicy drugs; they on the trading flood,
+Through the wide Ethiopian to the Cape,
+Ply stemming nightly toward the pole: so seemed
+Far off the flying Fiend. At last appear
+Hell-bounds, high reaching to the horrid roof,
+And thrice threefold the gates; three folds were brass,
+Three iron, three of adamantine rock,
+Impenetrable, impaled with circling fire,
+Yet unconsumed. Before the gates there sat
+On either side a formidable Shape.
+The one seemed woman to the waist, and fair,
+But ended foul in many a scaly fold,
+Voluminous and vast--a serpent armed
+With mortal sting. About her middle round
+A cry of Hell-hounds never-ceasing barked
+With wide Cerberean mouths full loud, and rung
+A hideous peal; yet, when they list, would creep,
+If aught disturbed their noise, into her womb,
+And kennel there; yet there still barked and howled
+Within unseen. Far less abhorred than these
+Vexed Scylla, bathing in the sea that parts
+Calabria from the hoarse Trinacrian shore;
+Nor uglier follow the night-hag, when, called
+In secret, riding through the air she comes,
+Lured with the smell of infant blood, to dance
+With Lapland witches, while the labouring moon
+Eclipses at their charms. The other Shape--
+If shape it might be called that shape had none
+Distinguishable in member, joint, or limb;
+Or substance might be called that shadow seemed,
+For each seemed either--black it stood as Night,
+Fierce as ten Furies, terrible as Hell,
+And shook a dreadful dart: what seemed his head
+The likeness of a kingly crown had on.
+Satan was now at hand, and from his seat
+The monster moving onward came as fast
+With horrid strides; Hell trembled as he strode.
+Th' undaunted Fiend what this might be admired--
+Admired, not feared (God and his Son except,
+Created thing naught valued he nor shunned),
+And with disdainful look thus first began:--
+ "Whence and what art thou, execrable Shape,
+That dar'st, though grim and terrible, advance
+Thy miscreated front athwart my way
+To yonder gates? Through them I mean to pass,
+That be assured, without leave asked of thee.
+Retire; or taste thy folly, and learn by proof,
+Hell-born, not to contend with Spirits of Heaven."
+ To whom the Goblin, full of wrath, replied:--
+"Art thou that traitor Angel? art thou he,
+Who first broke peace in Heaven and faith, till then
+Unbroken, and in proud rebellious arms
+Drew after him the third part of Heaven's sons,
+Conjured against the Highest--for which both thou
+And they, outcast from God, are here condemned
+To waste eternal days in woe and pain?
+And reckon'st thou thyself with Spirits of Heaven
+Hell-doomed, and breath'st defiance here and scorn,
+Where I reign king, and, to enrage thee more,
+Thy king and lord? Back to thy punishment,
+False fugitive; and to thy speed add wings,
+Lest with a whip of scorpions I pursue
+Thy lingering, or with one stroke of this dart
+Strange horror seize thee, and pangs unfelt before."
+ So spake the grisly Terror, and in shape,
+So speaking and so threatening, grew tenfold,
+More dreadful and deform. On th' other side,
+Incensed with indignation, Satan stood
+Unterrified, and like a comet burned,
+That fires the length of Ophiuchus huge
+In th' arctic sky, and from his horrid hair
+Shakes pestilence and war. Each at the head
+Levelled his deadly aim; their fatal hands
+No second stroke intend; and such a frown
+Each cast at th' other as when two black clouds,
+With heaven's artillery fraught, came rattling on
+Over the Caspian,--then stand front to front
+Hovering a space, till winds the signal blow
+To join their dark encounter in mid-air.
+So frowned the mighty combatants that Hell
+Grew darker at their frown; so matched they stood;
+For never but once more was wither like
+To meet so great a foe. And now great deeds
+Had been achieved, whereof all Hell had rung,
+Had not the snaky Sorceress, that sat
+Fast by Hell-gate and kept the fatal key,
+Risen, and with hideous outcry rushed between.
+ "O father, what intends thy hand," she cried,
+"Against thy only son? What fury, O son,
+Possesses thee to bend that mortal dart
+Against thy father's head? And know'st for whom?
+For him who sits above, and laughs the while
+At thee, ordained his drudge to execute
+Whate'er his wrath, which he calls justice, bids--
+His wrath, which one day will destroy ye both!"
+ She spake, and at her words the hellish Pest
+Forbore: then these to her Satan returned:--
+ "So strange thy outcry, and thy words so strange
+Thou interposest, that my sudden hand,
+Prevented, spares to tell thee yet by deeds
+What it intends, till first I know of thee
+What thing thou art, thus double-formed, and why,
+In this infernal vale first met, thou call'st
+Me father, and that phantasm call'st my son.
+I know thee not, nor ever saw till now
+Sight more detestable than him and thee."
+ T' whom thus the Portress of Hell-gate replied:--
+"Hast thou forgot me, then; and do I seem
+Now in thine eye so foul?--once deemed so fair
+In Heaven, when at th' assembly, and in sight
+Of all the Seraphim with thee combined
+In bold conspiracy against Heaven's King,
+All on a sudden miserable pain
+Surprised thee, dim thine eyes and dizzy swum
+In darkness, while thy head flames thick and fast
+Threw forth, till on the left side opening wide,
+Likest to thee in shape and countenance bright,
+Then shining heavenly fair, a goddess armed,
+Out of thy head I sprung. Amazement seized
+All th' host of Heaven; back they recoiled afraid
+At first, and called me Sin, and for a sign
+Portentous held me; but, familiar grown,
+I pleased, and with attractive graces won
+The most averse--thee chiefly, who, full oft
+Thyself in me thy perfect image viewing,
+Becam'st enamoured; and such joy thou took'st
+With me in secret that my womb conceived
+A growing burden. Meanwhile war arose,
+And fields were fought in Heaven: wherein remained
+(For what could else?) to our Almighty Foe
+Clear victory; to our part loss and rout
+Through all the Empyrean. Down they fell,
+Driven headlong from the pitch of Heaven, down
+Into this Deep; and in the general fall
+I also: at which time this powerful key
+Into my hands was given, with charge to keep
+These gates for ever shut, which none can pass
+Without my opening. Pensive here I sat
+Alone; but long I sat not, till my womb,
+Pregnant by thee, and now excessive grown,
+Prodigious motion felt and rueful throes.
+At last this odious offspring whom thou seest,
+Thine own begotten, breaking violent way,
+Tore through my entrails, that, with fear and pain
+Distorted, all my nether shape thus grew
+Transformed: but he my inbred enemy
+Forth issued, brandishing his fatal dart,
+Made to destroy. I fled, and cried out Death!
+Hell trembled at the hideous name, and sighed
+From all her caves, and back resounded Death!
+I fled; but he pursued (though more, it seems,
+Inflamed with lust than rage), and, swifter far,
+Me overtook, his mother, all dismayed,
+And, in embraces forcible and foul
+Engendering with me, of that rape begot
+These yelling monsters, that with ceaseless cry
+Surround me, as thou saw'st--hourly conceived
+And hourly born, with sorrow infinite
+To me; for, when they list, into the womb
+That bred them they return, and howl, and gnaw
+My bowels, their repast; then, bursting forth
+Afresh, with conscious terrors vex me round,
+That rest or intermission none I find.
+Before mine eyes in opposition sits
+Grim Death, my son and foe, who set them on,
+And me, his parent, would full soon devour
+For want of other prey, but that he knows
+His end with mine involved, and knows that I
+Should prove a bitter morsel, and his bane,
+Whenever that shall be: so Fate pronounced.
+But thou, O father, I forewarn thee, shun
+His deadly arrow; neither vainly hope
+To be invulnerable in those bright arms,
+Through tempered heavenly; for that mortal dint,
+Save he who reigns above, none can resist."
+ She finished; and the subtle Fiend his lore
+Soon learned, now milder, and thus answered smooth:--
+ "Dear daughter--since thou claim'st me for thy sire,
+And my fair son here show'st me, the dear pledge
+Of dalliance had with thee in Heaven, and joys
+Then sweet, now sad to mention, through dire change
+Befallen us unforeseen, unthought-of--know,
+I come no enemy, but to set free
+From out this dark and dismal house of pain
+Both him and thee, and all the heavenly host
+Of Spirits that, in our just pretences armed,
+Fell with us from on high. From them I go
+This uncouth errand sole, and one for all
+Myself expose, with lonely steps to tread
+Th' unfounded Deep, and through the void immense
+To search, with wandering quest, a place foretold
+Should be--and, by concurring signs, ere now
+Created vast and round--a place of bliss
+In the purlieus of Heaven; and therein placed
+A race of upstart creatures, to supply
+Perhaps our vacant room, though more removed,
+Lest Heaven, surcharged with potent multitude,
+Might hap to move new broils. Be this, or aught
+Than this more secret, now designed, I haste
+To know; and, this once known, shall soon return,
+And bring ye to the place where thou and Death
+Shall dwell at ease, and up and down unseen
+Wing silently the buxom air, embalmed
+With odours. There ye shall be fed and filled
+Immeasurably; all things shall be your prey."
+ He ceased; for both seemed highly pleased, and Death
+Grinned horrible a ghastly smile, to hear
+His famine should be filled, and blessed his maw
+Destined to that good hour. No less rejoiced
+His mother bad, and thus bespake her sire:--
+ "The key of this infernal Pit, by due
+And by command of Heaven's all-powerful King,
+I keep, by him forbidden to unlock
+These adamantine gates; against all force
+Death ready stands to interpose his dart,
+Fearless to be o'ermatched by living might.
+But what owe I to his commands above,
+Who hates me, and hath hither thrust me down
+Into this gloom of Tartarus profound,
+To sit in hateful office here confined,
+Inhabitant of Heaven and heavenly born--
+Here in perpetual agony and pain,
+With terrors and with clamours compassed round
+Of mine own brood, that on my bowels feed?
+Thou art my father, thou my author, thou
+My being gav'st me; whom should I obey
+But thee? whom follow? Thou wilt bring me soon
+To that new world of light and bliss, among
+The gods who live at ease, where I shall reign
+At thy right hand voluptuous, as beseems
+Thy daughter and thy darling, without end."
+ Thus saying, from her side the fatal key,
+Sad instrument of all our woe, she took;
+And, towards the gate rolling her bestial train,
+Forthwith the huge portcullis high up-drew,
+Which, but herself, not all the Stygian Powers
+Could once have moved; then in the key-hole turns
+Th' intricate wards, and every bolt and bar
+Of massy iron or solid rock with ease
+Unfastens. On a sudden open fly,
+With impetuous recoil and jarring sound,
+Th' infernal doors, and on their hinges grate
+Harsh thunder, that the lowest bottom shook
+Of Erebus. She opened; but to shut
+Excelled her power: the gates wide open stood,
+That with extended wings a bannered host,
+Under spread ensigns marching, mibht pass through
+With horse and chariots ranked in loose array;
+So wide they stood, and like a furnace-mouth
+Cast forth redounding smoke and ruddy flame.
+Before their eyes in sudden view appear
+The secrets of the hoary Deep--a dark
+Illimitable ocean, without bound,
+Without dimension; where length, breadth, and height,
+And time, and place, are lost; where eldest Night
+And Chaos, ancestors of Nature, hold
+Eternal anarchy, amidst the noise
+Of endless wars, and by confusion stand.
+For Hot, Cold, Moist, and Dry, four champions fierce,
+Strive here for mastery, and to battle bring
+Their embryon atoms: they around the flag
+Of each his faction, in their several clans,
+Light-armed or heavy, sharp, smooth, swift, or slow,
+Swarm populous, unnumbered as the sands
+Of Barca or Cyrene's torrid soil,
+Levied to side with warring winds, and poise
+Their lighter wings. To whom these most adhere
+He rules a moment: Chaos umpire sits,
+And by decision more embroils the fray
+By which he reigns: next him, high arbiter,
+Chance governs all. Into this wild Abyss,
+The womb of Nature, and perhaps her grave,
+Of neither sea, nor shore, nor air, nor fire,
+But all these in their pregnant causes mixed
+Confusedly, and which thus must ever fight,
+Unless th' Almighty Maker them ordain
+His dark materials to create more worlds--
+Into this wild Abyss the wary Fiend
+Stood on the brink of Hell and looked a while,
+Pondering his voyage; for no narrow frith
+He had to cross. Nor was his ear less pealed
+With noises loud and ruinous (to compare
+Great things with small) than when Bellona storms
+With all her battering engines, bent to rase
+Some capital city; or less than if this frame
+Of Heaven were falling, and these elements
+In mutiny had from her axle torn
+The steadfast Earth. At last his sail-broad vans
+He spread for flight, and, in the surging smoke
+Uplifted, spurns the ground; thence many a league,
+As in a cloudy chair, ascending rides
+Audacious; but, that seat soon failing, meets
+A vast vacuity. All unawares,
+Fluttering his pennons vain, plumb-down he drops
+Ten thousand fathom deep, and to this hour
+Down had been falling, had not, by ill chance,
+The strong rebuff of some tumultuous cloud,
+Instinct with fire and nitre, hurried him
+As many miles aloft. That fury stayed--
+Quenched in a boggy Syrtis, neither sea,
+Nor good dry land--nigh foundered, on he fares,
+Treading the crude consistence, half on foot,
+Half flying; behoves him now both oar and sail.
+As when a gryphon through the wilderness
+With winged course, o'er hill or moory dale,
+Pursues the Arimaspian, who by stealth
+Had from his wakeful custody purloined
+The guarded gold; so eagerly the Fiend
+O'er bog or steep, through strait, rough, dense, or rare,
+With head, hands, wings, or feet, pursues his way,
+And swims, or sinks, or wades, or creeps, or flies.
+At length a universal hubbub wild
+Of stunning sounds, and voices all confused,
+Borne through the hollow dark, assaults his ear
+With loudest vehemence. Thither he plies
+Undaunted, to meet there whatever Power
+Or Spirit of the nethermost Abyss
+Might in that noise reside, of whom to ask
+Which way the nearest coast of darkness lies
+Bordering on light; when straight behold the throne
+Of Chaos, and his dark pavilion spread
+Wide on the wasteful Deep! With him enthroned
+Sat sable-vested Night, eldest of things,
+The consort of his reign; and by them stood
+Orcus and Ades, and the dreaded name
+Of Demogorgon; Rumour next, and Chance,
+And Tumult, and Confusion, all embroiled,
+And Discord with a thousand various mouths.
+ T' whom Satan, turning boldly, thus:--"Ye Powers
+And Spirtis of this nethermost Abyss,
+Chaos and ancient Night, I come no spy
+With purpose to explore or to disturb
+The secrets of your realm; but, by constraint
+Wandering this darksome desert, as my way
+Lies through your spacious empire up to light,
+Alone and without guide, half lost, I seek,
+What readiest path leads where your gloomy bounds
+Confine with Heaven; or, if some other place,
+From your dominion won, th' Ethereal King
+Possesses lately, thither to arrive
+I travel this profound. Direct my course:
+Directed, no mean recompense it brings
+To your behoof, if I that region lost,
+All usurpation thence expelled, reduce
+To her original darkness and your sway
+(Which is my present journey), and once more
+Erect the standard there of ancient Night.
+Yours be th' advantage all, mine the revenge!"
+ Thus Satan; and him thus the Anarch old,
+With faltering speech and visage incomposed,
+Answered: "I know thee, stranger, who thou art-- ***
+That mighty leading Angel, who of late
+Made head against Heaven's King, though overthrown.
+I saw and heard; for such a numerous host
+Fled not in silence through the frighted Deep,
+With ruin upon ruin, rout on rout,
+Confusion worse confounded; and Heaven-gates
+Poured out by millions her victorious bands,
+Pursuing. I upon my frontiers here
+Keep residence; if all I can will serve
+That little which is left so to defend,
+Encroached on still through our intestine broils
+Weakening the sceptre of old Night: first, Hell,
+Your dungeon, stretching far and wide beneath;
+Now lately Heaven and Earth, another world
+Hung o'er my realm, linked in a golden chain
+To that side Heaven from whence your legions fell!
+If that way be your walk, you have not far;
+So much the nearer danger. Go, and speed;
+Havoc, and spoil, and ruin, are my gain."
+ He ceased; and Satan stayed not to reply,
+But, glad that now his sea should find a shore,
+With fresh alacrity and force renewed
+Springs upward, like a pyramid of fire,
+Into the wild expanse, and through the shock
+Of fighting elements, on all sides round
+Environed, wins his way; harder beset
+And more endangered than when Argo passed
+Through Bosporus betwixt the justling rocks,
+Or when Ulysses on the larboard shunned
+Charybdis, and by th' other whirlpool steered.
+So he with difficulty and labour hard
+Moved on, with difficulty and labour he;
+But, he once passed, soon after, when Man fell,
+Strange alteration! Sin and Death amain,
+Following his track (such was the will of Heaven)
+Paved after him a broad and beaten way
+Over the dark Abyss, whose boiling gulf
+Tamely endured a bridge of wondrous length,
+From Hell continued, reaching th' utmost orb
+Of this frail World; by which the Spirits perverse
+With easy intercourse pass to and fro
+To tempt or punish mortals, except whom
+God and good Angels guard by special grace.
+ But now at last the sacred influence
+Of light appears, and from the walls of Heaven
+Shoots far into the bosom of dim Night
+A glimmering dawn. Here Nature first begins
+Her farthest verge, and Chaos to retire,
+As from her outmost works, a broken foe,
+With tumult less and with less hostile din;
+That Satan with less toil, and now with ease,
+Wafts on the calmer wave by dubious light,
+And, like a weather-beaten vessel, holds
+Gladly the port, though shrouds and tackle torn;
+Or in the emptier waste, resembling air,
+Weighs his spread wings, at leisure to behold
+Far off th' empyreal Heaven, extended wide
+In circuit, undetermined square or round,
+With opal towers and battlements adorned
+Of living sapphire, once his native seat;
+And, fast by, hanging in a golden chain,
+This pendent World, in bigness as a star
+Of smallest magnitude close by the moon.
+Thither, full fraught with mischievous revenge,
+Accursed, and in a cursed hour, he hies.
+
+
+
+Book III
+
+
+Hail, holy Light, offspring of Heaven firstborn,
+Or of the Eternal coeternal beam
+May I express thee unblam'd? since God is light,
+And never but in unapproached light
+Dwelt from eternity, dwelt then in thee
+Bright effluence of bright essence increate.
+Or hear"st thou rather pure ethereal stream,
+Whose fountain who shall tell? before the sun,
+Before the Heavens thou wert, and at the voice
+Of God, as with a mantle, didst invest ***
+The rising world of waters dark and deep,
+Won from the void and formless infinite.
+Thee I re-visit now with bolder wing,
+Escap'd the Stygian pool, though long detain'd
+In that obscure sojourn, while in my flight
+Through utter and through middle darkness borne,
+With other notes than to the Orphean lyre
+I sung of Chaos and eternal Night;
+Taught by the heavenly Muse to venture down
+The dark descent, and up to re-ascend,
+Though hard and rare: Thee I revisit safe,
+And feel thy sovran vital lamp; but thou
+Revisit'st not these eyes, that roll in vain
+To find thy piercing ray, and find no dawn;
+So thick a drop serene hath quench'd their orbs,
+Or dim suffusion veil'd. Yet not the more
+Cease I to wander, where the Muses haunt,
+Clear spring, or shady grove, or sunny hill,
+Smit with the love of sacred song; but chief
+Thee, Sion, and the flowery brooks beneath,
+That wash thy hallow'd feet, and warbling flow,
+Nightly I visit: nor sometimes forget
+So were I equall'd with them in renown,
+Thy sovran command, that Man should find grace;
+Blind Thamyris, and blind Maeonides,
+And Tiresias, and Phineus, prophets old:
+Then feed on thoughts, that voluntary move
+Harmonious numbers; as the wakeful bird
+Sings darkling, and in shadiest covert hid
+Tunes her nocturnal note. Thus with the year
+Seasons return; but not to me returns
+Day, or the sweet approach of even or morn,
+Or sight of vernal bloom, or summer's rose,
+Or flocks, or herds, or human face divine;
+But cloud instead, and ever-during dark
+Surrounds me, from the cheerful ways of men
+Cut off, and for the book of knowledge fair
+Presented with a universal blank
+Of nature's works to me expung'd and ras'd,
+And wisdom at one entrance quite shut out.
+So much the rather thou, celestial Light,
+Shine inward, and the mind through all her powers
+Irradiate; there plant eyes, all mist from thence
+Purge and disperse, that I may see and tell
+Of things invisible to mortal sight.
+Now had the Almighty Father from above,
+From the pure empyrean where he sits
+High thron'd above all highth, bent down his eye
+His own works and their works at once to view:
+About him all the Sanctities of Heaven
+Stood thick as stars, and from his sight receiv'd
+Beatitude past utterance; on his right
+The radiant image of his glory sat,
+His only son; on earth he first beheld
+Our two first parents, yet the only two
+Of mankind in the happy garden plac'd
+Reaping immortal fruits of joy and love,
+Uninterrupted joy, unrivall'd love,
+In blissful solitude; he then survey'd
+Hell and the gulf between, and Satan there
+Coasting the wall of Heaven on this side Night
+In the dun air sublime, and ready now
+To stoop with wearied wings, and willing feet,
+On the bare outside of this world, that seem'd
+Firm land imbosom'd, without firmament,
+Uncertain which, in ocean or in air.
+Him God beholding from his prospect high,
+Wherein past, present, future, he beholds,
+Thus to his only Son foreseeing spake.
+Only begotten Son, seest thou what rage
+Transports our Adversary? whom no bounds
+Prescrib'd no bars of Hell, nor all the chains
+Heap'd on him there, nor yet the main abyss
+Wide interrupt, can hold; so bent he seems
+On desperate revenge, that shall redound
+Upon his own rebellious head. And now,
+Through all restraint broke loose, he wings his way
+Not far off Heaven, in the precincts of light,
+Directly towards the new created world,
+And man there plac'd, with purpose to assay
+If him by force he can destroy, or, worse,
+By some false guile pervert; and shall pervert;
+For man will hearken to his glozing lies,
+And easily transgress the sole command,
+Sole pledge of his obedience: So will fall
+He and his faithless progeny: Whose fault?
+Whose but his own? ingrate, he had of me
+All he could have; I made him just and right,
+Sufficient to have stood, though free to fall.
+Such I created all the ethereal Powers
+And Spirits, both them who stood, and them who fail'd;
+Freely they stood who stood, and fell who fell.
+Not free, what proof could they have given sincere
+Of true allegiance, constant faith or love,
+Where only what they needs must do appear'd,
+Not what they would? what praise could they receive?
+What pleasure I from such obedience paid,
+When will and reason (reason also is choice)
+Useless and vain, of freedom both despoil'd,
+Made passive both, had serv'd necessity,
+Not me? they therefore, as to right belong$ 'd,
+So were created, nor can justly accuse
+Their Maker, or their making, or their fate,
+As if predestination over-rul'd
+Their will dispos'd by absolute decree
+Or high foreknowledge they themselves decreed
+Their own revolt, not I; if I foreknew,
+Foreknowledge had no influence on their fault,
+Which had no less proved certain unforeknown.
+So without least impulse or shadow of fate,
+Or aught by me immutably foreseen,
+They trespass, authors to themselves in all
+Both what they judge, and what they choose; for so
+I form'd them free: and free they must remain,
+Till they enthrall themselves; I else must change
+Their nature, and revoke the high decree
+Unchangeable, eternal, which ordain'd
+$THeir freedom: they themselves ordain'd their fall.
+The first sort by their own suggestion fell,
+Self-tempted, self-deprav'd: Man falls, deceiv'd
+By the other first: Man therefore shall find grace,
+The other none: In mercy and justice both,
+Through Heaven and Earth, so shall my glory excel;
+But Mercy, first and last, shall brightest shine.
+Thus while God spake, ambrosial fragrance fill'd
+All Heaven, and in the blessed Spirits elect
+Sense of new joy ineffable diffus'd.
+Beyond compare the Son of God was seen
+Most glorious; in him all his Father shone
+Substantially express'd; and in his face
+Divine compassion visibly appear'd,
+Love without end, and without measure grace,
+Which uttering, thus he to his Father spake.
+O Father, gracious was that word which clos'd
+Thy sovran command, that Man should find grace;
+, that Man should find grace;
+For which both Heaven and earth shall high extol
+Thy praises, with the innumerable sound
+Of hymns and sacred songs, wherewith thy throne
+Encompass'd shall resound thee ever blest.
+For should Man finally be lost, should Man,
+Thy creature late so lov'd, thy youngest son,
+Fall circumvented thus by fraud, though join'd
+With his own folly? that be from thee far,
+That far be from thee, Father, who art judge
+Of all things made, and judgest only right.
+Or shall the Adversary thus obtain
+His end, and frustrate thine? shall he fulfill
+His malice, and thy goodness bring to nought,
+Or proud return, though to his heavier doom,
+Yet with revenge accomplish'd, and to Hell
+Draw after him the whole race of mankind,
+By him corrupted? or wilt thou thyself
+Abolish thy creation, and unmake
+For him, what for thy glory thou hast made?
+So should thy goodness and thy greatness both
+Be question'd and blasphem'd without defence.
+To whom the great Creator thus replied.
+O son, in whom my soul hath chief delight,
+Son of my bosom, Son who art alone.
+My word, my wisdom, and effectual might,
+All hast thou spoken as my thoughts are, all
+As my eternal purpose hath decreed;
+Man shall not quite be lost, but sav'd who will;
+Yet not of will in him, but grace in me
+Freely vouchsaf'd; once more I will renew
+His lapsed powers, though forfeit; and enthrall'd
+By sin to foul exorbitant desires;
+Upheld by me, yet once more he shall stand
+On even ground against his mortal foe;
+By me upheld, that he may know how frail
+His fallen condition is, and to me owe
+All his deliverance, and to none but me.
+Some I have chosen of peculiar grace,
+Elect above the rest; so is my will:
+The rest shall hear me call, and oft be warn'd
+Their sinful state, and to appease betimes
+The incensed Deity, while offer'd grace
+Invites; for I will clear their senses dark,
+What may suffice, and soften stony hearts
+To pray, repent, and bring obedience due.
+To prayer, repentance, and obedience due,
+Though but endeavour'd with sincere intent,
+Mine ear shall not be slow, mine eye not shut.
+And I will place within them as a guide,
+My umpire Conscience; whom if they will hear,
+Light after light, well us'd, they shall attain,
+And to the end, persisting, safe arrive.
+This my long sufferance, and my day of grace,
+They who neglect and scorn, shall never taste;
+But hard be harden'd, blind be blinded more,
+That they may stumble on, and deeper fall;
+And none but such from mercy I exclude.
+But yet all is not done; Man disobeying,
+Disloyal, breaks his fealty, and sins
+Against the high supremacy of Heaven,
+Affecting God-head, and, so losing all,
+To expiate his treason hath nought left,
+But to destruction sacred and devote,
+He, with his whole posterity, must die,
+Die he or justice must; unless for him
+Some other able, and as willing, pay
+The rigid satisfaction, death for death.
+Say, heavenly Powers, where shall we find such love?
+Which of you will be mortal, to redeem
+Man's mortal crime, and just the unjust to save?
+Dwells in all Heaven charity so dear?
+And silence was in Heaven: $ on Man's behalf
+He ask'd, but all the heavenly quire stood mute,
+Patron or intercessour none appear'd,
+Much less that durst upon his own head draw
+The deadly forfeiture, and ransom set.
+And now without redemption all mankind
+Must have been lost, adjudg'd to Death and Hell
+By doom severe, had not the Son of God,
+In whom the fulness dwells of love divine,
+His dearest mediation thus renew'd.
+Father, thy word is past, Man shall find grace;
+And shall grace not find means, that finds her way,
+The speediest of thy winged messengers,
+To visit all thy creatures, and to all
+Comes unprevented, unimplor'd, unsought?
+Happy for Man, so coming; he her aid
+Can never seek, once dead in sins, and lost;
+Atonement for himself, or offering meet,
+Indebted and undone, hath none to bring;
+Behold me then: me for him, life for life
+I offer: on me let thine anger fall;
+Account me Man; I for his sake will leave
+ Thy bosom, and this glory next to thee
+ Freely put off, and for him lastly die
+ Well pleased; on me let Death wreak all his rage.
+ Under his gloomy power I shall not long
+ Lie vanquished. Thou hast given me to possess
+ Life in myself for ever; by thee I live;
+ Though now to Death I yield, and am his due,
+ All that of me can die, yet, that debt paid,
+ $ thou wilt not leave me in the loathsome grave
+ His prey, nor suffer my unspotted soul
+ For ever with corruption there to dwell;
+ But I shall rise victorious, and subdue
+ My vanquisher, spoiled of his vaunted spoil.
+ Death his death's wound shall then receive, and stoop
+ Inglorious, of his mortal sting disarmed;
+ I through the ample air in triumph high
+ Shall lead Hell captive maugre Hell, and show
+The powers of darkness bound. Thou, at the sight
+ Pleased, out of Heaven shalt look down and smile,
+ While, by thee raised, I ruin all my foes;
+ Death last, and with his carcase glut the grave;
+ Then, with the multitude of my redeemed,
+ Shall enter Heaven, long absent, and return,
+ Father, to see thy face, wherein no cloud
+ Of anger shall remain, but peace assured
+ And reconcilement: wrath shall be no more
+ Thenceforth, but in thy presence joy entire.
+ His words here ended; but his meek aspect
+ Silent yet spake, and breathed immortal love
+ To mortal men, above which only shone
+ Filial obedience: as a sacrifice
+ Glad to be offered, he attends the will
+ Of his great Father. Admiration seized
+ All Heaven, what this might mean, and whither tend,
+ Wondering; but soon th' Almighty thus replied.
+ O thou in Heaven and Earth the only peace
+ Found out for mankind under wrath, O thou
+ My sole complacence! Well thou know'st how dear
+ To me are all my works; nor Man the least,
+ Though last created, that for him I spare
+ Thee from my bosom and right hand, to save,
+ By losing thee a while, the whole race lost.
+
+ 00021053
+ Thou, therefore, whom thou only canst redeem,
+ Their nature also to thy nature join;
+ And be thyself Man among men on Earth,
+ Made flesh, when time shall be, of virgin seed,
+ By wondrous birth; be thou in Adam's room
+The head of all mankind, though Adam's son.
+As in him perish all men, so in thee,
+As from a second root, shall be restored
+As many as are restored, without thee none.
+His crime makes guilty all his sons; thy merit,
+Imputed, shall absolve them who renounce
+Their own both righteous and unrighteous deeds,
+And live in thee transplanted, and from thee
+Receive new life. So Man, as is most just,
+Shall satisfy for Man, be judged and die,
+And dying rise, and rising with him raise
+His brethren, ransomed with his own dear life.
+So heavenly love shall outdo hellish hate,
+Giving to death, and dying to redeem,
+So dearly to redeem what hellish hate
+So easily destroyed, and still destroys
+In those who, when they may, accept not grace.
+Nor shalt thou, by descending to assume
+Man's nature, lessen or degrade thine own.
+Because thou hast, though throned in highest bliss
+Equal to God, and equally enjoying
+God-like fruition, quitted all, to save
+A world from utter loss, and hast been found
+By merit more than birthright Son of God,
+Found worthiest to be so by being good,
+Far more than great or high; because in thee
+Love hath abounded more than glory abounds;
+Therefore thy humiliation shall exalt
+With thee thy manhood also to this throne:
+Here shalt thou sit incarnate, here shalt reign
+Both God and Man, Son both of God and Man,
+Anointed universal King; all power
+I give thee; reign for ever, and assume
+Thy merits; under thee, as head supreme,
+Thrones, Princedoms, Powers, Dominions, I reduce:
+All knees to thee shall bow, of them that bide
+In Heaven, or Earth, or under Earth in Hell.
+When thou, attended gloriously from Heaven,
+Shalt in the sky appear, and from thee send
+The summoning Arch-Angels to proclaim
+Thy dread tribunal; forthwith from all winds,
+The living, and forthwith the cited dead
+Of all past ages, to the general doom
+Shall hasten; such a peal shall rouse their sleep.
+Then, all thy saints assembled, thou shalt judge
+Bad Men and Angels; they, arraigned, shall sink
+Beneath thy sentence; Hell, her numbers full,
+Thenceforth shall be for ever shut. Mean while
+The world shall burn, and from her ashes spring
+New Heaven and Earth, wherein the just shall dwell,
+And, after all their tribulations long,
+See golden days, fruitful of golden deeds,
+With joy and peace triumphing, and fair truth.
+Then thou thy regal scepter shalt lay by,
+For regal scepter then no more shall need,
+God shall be all in all. But, all ye Gods,
+Adore him, who to compass all this dies;
+Adore the Son, and honour him as me.
+No sooner had the Almighty ceased, but all
+The multitude of Angels, with a shout
+Loud as from numbers without number, sweet
+As from blest voices, uttering joy, Heaven rung
+With jubilee, and loud Hosannas filled
+The eternal regions: Lowly reverent
+Towards either throne they bow, and to the ground
+With solemn adoration down they cast
+Their crowns inwove with amarant and gold;
+Immortal amarant, a flower which once
+In Paradise, fast by the tree of life,
+Began to bloom; but soon for man's offence
+To Heaven removed, where first it grew, there grows,
+And flowers aloft shading the fount of life,
+And where the river of bliss through midst of Heaven
+Rolls o'er Elysian flowers her amber stream;
+With these that never fade the Spirits elect
+Bind their resplendent locks inwreathed with beams;
+Now in loose garlands thick thrown off, the bright
+Pavement, that like a sea of jasper shone,
+Impurpled with celestial roses smiled.
+Then, crowned again, their golden harps they took,
+Harps ever tuned, that glittering by their side
+Like quivers hung, and with preamble sweet
+Of charming symphony they introduce
+Their sacred song, and waken raptures high;
+No voice exempt, no voice but well could join
+Melodious part, such concord is in Heaven.
+Thee, Father, first they sung Omnipotent,
+Immutable, Immortal, Infinite,
+Eternal King; the Author of all being,
+Fonntain of light, thyself invisible
+Amidst the glorious brightness where thou sit'st
+Throned inaccessible, but when thou shadest
+The full blaze of thy beams, and, through a cloud
+Drawn round about thee like a radiant shrine,
+Dark with excessive bright thy skirts appear,
+Yet dazzle Heaven, that brightest Seraphim
+Approach not, but with both wings veil their eyes.
+Thee next they sang of all creation first,
+Begotten Son, Divine Similitude,
+In whose conspicuous countenance, without cloud
+Made visible, the Almighty Father shines,
+Whom else no creature can behold; on thee
+Impressed the effulgence of his glory abides,
+Transfused on thee his ample Spirit rests.
+He Heaven of Heavens and all the Powers therein
+By thee created; and by thee threw down
+The aspiring Dominations: Thou that day
+Thy Father's dreadful thunder didst not spare,
+Nor stop thy flaming chariot-wheels, that shook
+Heaven's everlasting frame, while o'er the necks
+Thou drovest of warring Angels disarrayed.
+Back from pursuit thy Powers with loud acclaim
+Thee only extolled, Son of thy Father's might,
+To execute fierce vengeance on his foes,
+Not so on Man: Him through their malice fallen,
+Father of mercy and grace, thou didst not doom
+So strictly, but much more to pity incline:
+No sooner did thy dear and only Son
+Perceive thee purposed not to doom frail Man
+So strictly, but much more to pity inclined,
+He to appease thy wrath, and end the strife
+Of mercy and justice in thy face discerned,
+Regardless of the bliss wherein he sat
+Second to thee, offered himself to die
+For Man's offence. O unexampled love,
+Love no where to be found less than Divine!
+Hail, Son of God, Saviour of Men! Thy name
+Shall be the copious matter of my song
+Henceforth, and never shall my heart thy praise
+Forget, nor from thy Father's praise disjoin.
+Thus they in Heaven, above the starry sphere,
+Their happy hours in joy and hymning spent.
+Mean while upon the firm opacous globe
+Of this round world, whose first convex divides
+The luminous inferiour orbs, enclosed
+From Chaos, and the inroad of Darkness old,
+Satan alighted walks: A globe far off
+It seemed, now seems a boundless continent
+Dark, waste, and wild, under the frown of Night
+Starless exposed, and ever-threatening storms
+Of Chaos blustering round, inclement sky;
+Save on that side which from the wall of Heaven,
+Though distant far, some small reflection gains
+Of glimmering air less vexed with tempest loud:
+Here walked the Fiend at large in spacious field.
+As when a vultur on Imaus bred,
+Whose snowy ridge the roving Tartar bounds,
+Dislodging from a region scarce of prey
+To gorge the flesh of lambs or yeanling kids,
+On hills where flocks are fed, flies toward the springs
+Of Ganges or Hydaspes, Indian streams;
+But in his way lights on the barren plains
+Of Sericana, where Chineses drive
+With sails and wind their cany waggons light:
+So, on this windy sea of land, the Fiend
+Walked up and down alone, bent on his prey;
+Alone, for other creature in this place,
+Living or lifeless, to be found was none;
+None yet, but store hereafter from the earth
+Up hither like aereal vapours flew
+Of all things transitory and vain, when sin
+With vanity had filled the works of men:
+Both all things vain, and all who in vain things
+Built their fond hopes of glory or lasting fame,
+Or happiness in this or the other life;
+All who have their reward on earth, the fruits
+Of painful superstition and blind zeal,
+Nought seeking but the praise of men, here find
+Fit retribution, empty as their deeds;
+All the unaccomplished works of Nature's hand,
+Abortive, monstrous, or unkindly mixed,
+Dissolved on earth, fleet hither, and in vain,
+Till final dissolution, wander here;
+Not in the neighbouring moon as some have dreamed;
+Those argent fields more likely habitants,
+Translated Saints, or middle Spirits hold
+Betwixt the angelical and human kind.
+Hither of ill-joined sons and daughters born
+First from the ancient world those giants came
+With many a vain exploit, though then renowned:
+The builders next of Babel on the plain
+Of Sennaar, and still with vain design,
+New Babels, had they wherewithal, would build:
+Others came single; he, who, to be deemed
+A God, leaped fondly into Aetna flames,
+Empedocles; and he, who, to enjoy
+Plato's Elysium, leaped into the sea,
+Cleombrotus; and many more too long,
+Embryos, and idiots, eremites, and friars
+White, black, and gray, with all their trumpery.
+Here pilgrims roam, that strayed so far to seek
+In Golgotha him dead, who lives in Heaven;
+And they, who to be sure of Paradise,
+Dying, put on the weeds of Dominick,
+Or in Franciscan think to pass disguised;
+They pass the planets seven, and pass the fixed,
+And that crystalling sphere whose balance weighs
+The trepidation talked, and that first moved;
+And now Saint Peter at Heaven's wicket seems
+To wait them with his keys, and now at foot
+Of Heaven's ascent they lift their feet, when lo
+A violent cross wind from either coast
+Blows them transverse, ten thousand leagues awry
+Into the devious air: Then might ye see
+Cowls, hoods, and habits, with their wearers, tost
+And fluttered into rags; then reliques, beads,
+Indulgences, dispenses, pardons, bulls,
+The sport of winds: All these, upwhirled aloft,
+Fly o'er the backside of the world far off
+Into a Limbo large and broad, since called
+The Paradise of Fools, to few unknown
+Long after; now unpeopled, and untrod.
+All this dark globe the Fiend found as he passed,
+And long he wandered, till at last a gleam
+Of dawning light turned thither-ward in haste
+His travelled steps: far distant he descries
+Ascending by degrees magnificent
+Up to the wall of Heaven a structure high;
+At top whereof, but far more rich, appeared
+The work as of a kingly palace-gate,
+With frontispiece of diamond and gold
+Embellished; thick with sparkling orient gems
+The portal shone, inimitable on earth
+By model, or by shading pencil, drawn.
+These stairs were such as whereon Jacob saw
+Angels ascending and descending, bands
+Of guardians bright, when he from Esau fled
+To Padan-Aram, in the field of Luz
+Dreaming by night under the open sky
+And waking cried, This is the gate of Heaven.
+Each stair mysteriously was meant, nor stood
+There always, but drawn up to Heaven sometimes
+Viewless; and underneath a bright sea flowed
+Of jasper, or of liquid pearl, whereon
+Who after came from earth, failing arrived
+Wafted by Angels, or flew o'er the lake
+Rapt in a chariot drawn by fiery steeds.
+The stairs were then let down, whether to dare
+The Fiend by easy ascent, or aggravate
+His sad exclusion from the doors of bliss:
+Direct against which opened from beneath,
+Just o'er the blissful seat of Paradise,
+A passage down to the Earth, a passage wide,
+Wider by far than that of after-times
+Over mount Sion, and, though that were large,
+Over the Promised Land to God so dear;
+By which, to visit oft those happy tribes,
+On high behests his angels to and fro
+Passed frequent, and his eye with choice regard
+From Paneas, the fount of Jordan's flood,
+To Beersaba, where the Holy Land
+Borders on Egypt and the Arabian shore;
+So wide the opening seemed, where bounds were set
+To darkness, such as bound the ocean wave.
+Satan from hence, now on the lower stair,
+That scaled by steps of gold to Heaven-gate,
+Looks down with wonder at the sudden view
+Of all this world at once. As when a scout,
+Through dark?;nd desart ways with?oeril gone
+All?might,?;t?kast by break of cheerful dawn
+Obtains the brow of some high-climbing hill,
+Which to his eye discovers unaware
+The goodly prospect of some foreign land
+First seen, or some renowned metropolis
+With glistering spires and pinnacles adorned,
+Which now the rising sun gilds with his beams:
+Such wonder seised, though after Heaven seen,
+The Spirit malign, but much more envy seised,
+At sight of all this world beheld so fair.
+Round he surveys (and well might, where he stood
+So high above the circling canopy
+Of night's extended shade,) from eastern point
+Of Libra to the fleecy star that bears
+Andromeda far off Atlantick seas
+Beyond the horizon; then from pole to pole
+He views in breadth, and without longer pause
+Down right into the world's first region throws
+His flight precipitant, and winds with ease
+Through the pure marble air his oblique way
+Amongst innumerable stars, that shone
+Stars distant, but nigh hand seemed other worlds;
+Or other worlds they seemed, or happy isles,
+Like those Hesperian gardens famed of old,
+Fortunate fields, and groves, and flowery vales,
+Thrice happy isles; but who dwelt happy there
+He staid not to inquire: Above them all
+The golden sun, in splendour likest Heaven,
+Allured his eye; thither his course he bends
+Through the calm firmament, (but up or down,
+By center, or eccentrick, hard to tell,
+Or longitude,) where the great luminary
+Aloof the vulgar constellations thick,
+That from his lordly eye keep distance due,
+Dispenses light from far; they, as they move
+Their starry dance in numbers that compute
+Days, months, and years, towards his all-cheering lamp
+Turn swift their various motions, or are turned
+By his magnetick beam, that gently warms
+The universe, and to each inward part
+With gentle penetration, though unseen,
+Shoots invisible virtue even to the deep;
+So wonderously was set his station bright.
+There lands the Fiend, a spot like which perhaps
+Astronomer in the sun's lucent orb
+Through his glazed optick tube yet never saw.
+The place he found beyond expression bright,
+Compared with aught on earth, metal or stone;
+Not all parts like, but all alike informed
+With radiant light, as glowing iron with fire;
+If metal, part seemed gold, part silver clear;
+If stone, carbuncle most or chrysolite,
+Ruby or topaz, to the twelve that shone
+In Aaron's breast-plate, and a stone besides
+Imagined rather oft than elsewhere seen,
+That stone, or like to that which here below
+Philosophers in vain so long have sought,
+In vain, though by their powerful art they bind
+Volatile Hermes, and call up unbound
+In various shapes old Proteus from the sea,
+Drained through a limbeck to his native form.
+What wonder then if fields and regions here
+Breathe forth Elixir pure, and rivers run
+Potable gold, when with one virtuous touch
+The arch-chemick sun, so far from us remote,
+Produces, with terrestrial humour mixed,
+Here in the dark so many precious things
+Of colour glorious, and effect so rare?
+Here matter new to gaze the Devil met
+Undazzled; far and wide his eye commands;
+For sight no obstacle found here, nor shade,
+But all sun-shine, as when his beams at noon
+Culminate from the equator, as they now
+Shot upward still direct, whence no way round
+Shadow from body opaque can fall; and the air,
+No where so clear, sharpened his visual ray
+To objects distant far, whereby he soon
+Saw within ken a glorious Angel stand,
+The same whom John saw also in the sun:
+His back was turned, but not his brightness hid;
+Of beaming sunny rays a golden tiar
+Circled his head, nor less his locks behind
+Illustrious on his shoulders fledge with wings
+Lay waving round; on some great charge employed
+He seemed, or fixed in cogitation deep.
+Glad was the Spirit impure, as now in hope
+To find who might direct his wandering flight
+To Paradise, the happy seat of Man,
+His journey's end and our beginning woe.
+But first he casts to change his proper shape,
+Which else might work him danger or delay:
+And now a stripling Cherub he appears,
+Not of the prime, yet such as in his face
+Youth smiled celestial, and to every limb
+Suitable grace diffused, so well he feigned:
+Under a coronet his flowing hair
+In curls on either cheek played; wings he wore
+Of many a coloured plume, sprinkled with gold;
+His habit fit for speed succinct, and held
+Before his decent steps a silver wand.
+He drew not nigh unheard; the Angel bright,
+Ere he drew nigh, his radiant visage turned,
+Admonished by his ear, and straight was known
+The Arch-Angel Uriel, one of the seven
+Who in God's presence, nearest to his throne,
+Stand ready at command, and are his eyes
+That run through all the Heavens, or down to the Earth
+Bear his swift errands over moist and dry,
+O'er sea and land: him Satan thus accosts.
+Uriel, for thou of those seven Spirits that stand
+In sight of God's high throne, gloriously bright,
+The first art wont his great authentick will
+Interpreter through highest Heaven to bring,
+Where all his sons thy embassy attend;
+And here art likeliest by supreme decree
+Like honour to obtain, and as his eye
+To visit oft this new creation round;
+Unspeakable desire to see, and know
+All these his wonderous works, but chiefly Man,
+His chief delight and favour, him for whom
+All these his works so wonderous he ordained,
+Hath brought me from the quires of Cherubim
+Alone thus wandering. Brightest Seraph, tell
+In which of all these shining orbs hath Man
+His fixed seat, or fixed seat hath none,
+But all these shining orbs his choice to dwell;
+That I may find him, and with secret gaze
+Or open admiration him behold,
+On whom the great Creator hath bestowed
+Worlds, and on whom hath all these graces poured;
+That both in him and all things, as is meet,
+The universal Maker we may praise;
+Who justly hath driven out his rebel foes
+To deepest Hell, and, to repair that loss,
+Created this new happy race of Men
+To serve him better: Wise are all his ways.
+So spake the false dissembler unperceived;
+For neither Man nor Angel can discern
+Hypocrisy, the only evil that walks
+Invisible, except to God alone,
+By his permissive will, through Heaven and Earth:
+And oft, though wisdom wake, suspicion sleeps
+At wisdom's gate, and to simplicity
+Resigns her charge, while goodness thinks no ill
+Where no ill seems: Which now for once beguiled
+Uriel, though regent of the sun, and held
+The sharpest-sighted Spirit of all in Heaven;
+Who to the fraudulent impostor foul,
+In his uprightness, answer thus returned.
+Fair Angel, thy desire, which tends to know
+The works of God, thereby to glorify
+The great Work-master, leads to no excess
+That reaches blame, but rather merits praise
+The more it seems excess, that led thee hither
+From thy empyreal mansion thus alone,
+To witness with thine eyes what some perhaps,
+Contented with report, hear only in Heaven:
+For wonderful indeed are all his works,
+Pleasant to know, and worthiest to be all
+Had in remembrance always with delight;
+But what created mind can comprehend
+Their number, or the wisdom infinite
+That brought them forth, but hid their causes deep?
+I saw when at his word the formless mass,
+This world's material mould, came to a heap:
+Confusion heard his voice, and wild uproar
+Stood ruled, stood vast infinitude confined;
+Till at his second bidding Darkness fled,
+Light shone, and order from disorder sprung:
+Swift to their several quarters hasted then
+The cumbrous elements, earth, flood, air, fire;
+And this ethereal quintessence of Heaven
+Flew upward, spirited with various forms,
+That rolled orbicular, and turned to stars
+Numberless, as thou seest, and how they move;
+Each had his place appointed, each his course;
+The rest in circuit walls this universe.
+Look downward on that globe, whose hither side
+With light from hence, though but reflected, shines;
+That place is Earth, the seat of Man; that light
+His day, which else, as the other hemisphere,
+Night would invade; but there the neighbouring moon
+So call that opposite fair star) her aid
+Timely interposes, and her monthly round
+Still ending, still renewing, through mid Heaven,
+With borrowed light her countenance triform
+Hence fills and empties to enlighten the Earth,
+And in her pale dominion checks the night.
+That spot, to which I point, is Paradise,
+Adam's abode; those lofty shades, his bower.
+Thy way thou canst not miss, me mine requires.
+Thus said, he turned; and Satan, bowing low,
+As to superiour Spirits is wont in Heaven,
+Where honour due and reverence none neglects,
+Took leave, and toward the coast of earth beneath,
+Down from the ecliptick, sped with hoped success,
+Throws his steep flight in many an aery wheel;
+Nor staid, till on Niphates' top he lights.
+
+
+
+Book IV
+
+
+O, for that warning voice, which he, who saw
+The Apocalypse, heard cry in Heaven aloud,
+Then when the Dragon, put to second rout,
+Came furious down to be revenged on men,
+Woe to the inhabitants on earth! that now,
+While time was, our first parents had been warned
+The coming of their secret foe, and 'scaped,
+Haply so 'scaped his mortal snare: For now
+Satan, now first inflamed with rage, came down,
+The tempter ere the accuser of mankind,
+To wreak on innocent frail Man his loss
+Of that first battle, and his flight to Hell:
+Yet, not rejoicing in his speed, though bold
+Far off and fearless, nor with cause to boast,
+Begins his dire attempt; which nigh the birth
+Now rolling boils in his tumultuous breast,
+And like a devilish engine back recoils
+Upon himself; horrour and doubt distract
+His troubled thoughts, and from the bottom stir
+The Hell within him; for within him Hell
+He brings, and round about him, nor from Hell
+One step, no more than from himself, can fly
+By change of place: Now conscience wakes despair,
+That slumbered; wakes the bitter memory
+Of what he was, what is, and what must be
+Worse; of worse deeds worse sufferings must ensue.
+Sometimes towards Eden, which now in his view
+Lay pleasant, his grieved look he fixes sad;
+Sometimes towards Heaven, and the full-blazing sun,
+Which now sat high in his meridian tower:
+Then, much revolving, thus in sighs began.
+O thou, that, with surpassing glory crowned,
+Lookest from thy sole dominion like the God
+Of this new world; at whose sight all the stars
+Hide their diminished heads; to thee I call,
+But with no friendly voice, and add thy name,
+Of Sun! to tell thee how I hate thy beams,
+That bring to my remembrance from what state
+I fell, how glorious once above thy sphere;
+Till pride and worse ambition threw me down
+Warring in Heaven against Heaven's matchless King:
+Ah, wherefore! he deserved no such return
+From me, whom he created what I was
+In that bright eminence, and with his good
+Upbraided none; nor was his service hard.
+What could be less than to afford him praise,
+The easiest recompence, and pay him thanks,
+How due! yet all his good proved ill in me,
+And wrought but malice; lifted up so high
+I sdeined subjection, and thought one step higher
+Would set me highest, and in a moment quit
+The debt immense of endless gratitude,
+So burdensome still paying, still to owe,
+Forgetful what from him I still received,
+And understood not that a grateful mind
+By owing owes not, but still pays, at once
+Indebted and discharged; what burden then
+O, had his powerful destiny ordained
+Me some inferiour Angel, I had stood
+Then happy; no unbounded hope had raised
+Ambition! Yet why not some other Power
+As great might have aspired, and me, though mean,
+Drawn to his part; but other Powers as great
+Fell not, but stand unshaken, from within
+Or from without, to all temptations armed.
+Hadst thou the same free will and power to stand?
+Thou hadst: whom hast thou then or what to accuse,
+But Heaven's free love dealt equally to all?
+Be then his love accursed, since love or hate,
+To me alike, it deals eternal woe.
+Nay, cursed be thou; since against his thy will
+Chose freely what it now so justly rues.
+Me miserable! which way shall I fly
+Infinite wrath, and infinite despair?
+Which way I fly is Hell; myself am Hell;
+And, in the lowest deep, a lower deep
+Still threatening to devour me opens wide,
+To which the Hell I suffer seems a Heaven.
+O, then, at last relent: Is there no place
+Left for repentance, none for pardon left?
+None left but by submission; and that word
+Disdain forbids me, and my dread of shame
+Among the Spirits beneath, whom I seduced
+With other promises and other vaunts
+Than to submit, boasting I could subdue
+The Omnipotent. Ay me! they little know
+How dearly I abide that boast so vain,
+Under what torments inwardly I groan,
+While they adore me on the throne of Hell.
+With diadem and scepter high advanced,
+The lower still I fall, only supreme
+In misery: Such joy ambition finds.
+But say I could repent, and could obtain,
+By act of grace, my former state; how soon
+Would highth recall high thoughts, how soon unsay
+What feigned submission swore? Ease would recant
+Vows made in pain, as violent and void.
+For never can true reconcilement grow,
+Where wounds of deadly hate have pierced so deep:
+Which would but lead me to a worse relapse
+And heavier fall: so should I purchase dear
+Short intermission bought with double smart.
+This knows my Punisher; therefore as far
+From granting he, as I from begging, peace;
+All hope excluded thus, behold, in stead
+Mankind created, and for him this world.
+So farewell, hope; and with hope farewell, fear;
+Farewell, remorse! all good to me is lost;
+Evil, be thou my good; by thee at least
+Divided empire with Heaven's King I hold,
+By thee, and more than half perhaps will reign;
+As Man ere long, and this new world, shall know.
+Thus while he spake, each passion dimmed his face
+Thrice changed with pale, ire, envy, and despair;
+Which marred his borrowed visage, and betrayed
+Him counterfeit, if any eye beheld.
+For heavenly minds from such distempers foul
+Are ever clear. Whereof he soon aware,
+Each perturbation smoothed with outward calm,
+Artificer of fraud; and was the first
+That practised falsehood under saintly show,
+Deep malice to conceal, couched with revenge:
+Yet not enough had practised to deceive
+Uriel once warned; whose eye pursued him down
+ The way he went, and on the Assyrian mount
+ Saw him disfigured, more than could befall
+ Spirit of happy sort; his gestures fierce
+ He marked and mad demeanour, then alone,
+ As he supposed, all unobserved, unseen.
+ So on he fares, and to the border comes
+ Of Eden, where delicious Paradise,
+ Now nearer, crowns with her enclosure green,
+ As with a rural mound, the champaign head
+ Of a steep wilderness, whose hairy sides
+Access denied; and overhead upgrew
+ Insuperable height of loftiest shade,
+ Cedar, and pine, and fir, and branching palm,
+ A sylvan scene, and, as the ranks ascend,
+ Shade above shade, a woody theatre
+ Of stateliest view. Yet higher than their tops
+ The verdurous wall of Paradise upsprung;
+
+ 00081429
+Which to our general sire gave prospect large
+Into his nether empire neighbouring round.
+And higher than that wall a circling row
+Of goodliest trees, loaden with fairest fruit,
+Blossoms and fruits at once of golden hue,
+Appeared, with gay enamelled colours mixed:
+On which the sun more glad impressed his beams
+Than in fair evening cloud, or humid bow,
+When God hath showered the earth; so lovely seemed
+That landskip: And of pure now purer air
+Meets his approach, and to the heart inspires
+Vernal delight and joy, able to drive
+All sadness but despair: Now gentle gales,
+Fanning their odoriferous wings, dispense
+Native perfumes, and whisper whence they stole
+Those balmy spoils. As when to them who fail
+Beyond the Cape of Hope, and now are past
+Mozambick, off at sea north-east winds blow
+Sabean odours from the spicy shore
+Of Araby the blest; with such delay
+Well pleased they slack their course, and many a league
+Cheered with the grateful smell old Ocean smiles:
+So entertained those odorous sweets the Fiend,
+Who came their bane; though with them better pleased
+Than Asmodeus with the fishy fume
+That drove him, though enamoured, from the spouse
+Of Tobit's son, and with a vengeance sent
+From Media post to Egypt, there fast bound.
+Now to the ascent of that steep savage hill
+Satan had journeyed on, pensive and slow;
+But further way found none, so thick entwined,
+As one continued brake, the undergrowth
+Of shrubs and tangling bushes had perplexed
+All path of man or beast that passed that way.
+One gate there only was, and that looked east
+On the other side: which when the arch-felon saw,
+Due entrance he disdained; and, in contempt,
+At one flight bound high over-leaped all bound
+Of hill or highest wall, and sheer within
+Lights on his feet. As when a prowling wolf,
+Whom hunger drives to seek new haunt for prey,
+Watching where shepherds pen their flocks at eve
+In hurdled cotes amid the field secure,
+Leaps o'er the fence with ease into the fold:
+Or as a thief, bent to unhoard the cash
+Of some rich burgher, whose substantial doors,
+Cross-barred and bolted fast, fear no assault,
+In at the window climbs, or o'er the tiles:
+So clomb this first grand thief into God's fold;
+So since into his church lewd hirelings climb.
+Thence up he flew, and on the tree of life,
+The middle tree and highest there that grew,
+Sat like a cormorant; yet not true life
+Thereby regained, but sat devising death
+To them who lived; nor on the virtue thought
+Of that life-giving plant, but only used
+For prospect, what well used had been the pledge
+Of immortality. So little knows
+Any, but God alone, to value right
+The good before him, but perverts best things
+To worst abuse, or to their meanest use.
+Beneath him with new wonder now he views,
+To all delight of human sense exposed,
+In narrow room, Nature's whole wealth, yea more,
+A Heaven on Earth: For blissful Paradise
+Of God the garden was, by him in the east
+Of Eden planted; Eden stretched her line
+From Auran eastward to the royal towers
+Of great Seleucia, built by Grecian kings,
+Of where the sons of Eden long before
+Dwelt in Telassar: In this pleasant soil
+His far more pleasant garden God ordained;
+Out of the fertile ground he caused to grow
+All trees of noblest kind for sight, smell, taste;
+And all amid them stood the tree of life,
+High eminent, blooming ambrosial fruit
+Of vegetable gold; and next to life,
+Our death, the tree of knowledge, grew fast by,
+Knowledge of good bought dear by knowing ill.
+Southward through Eden went a river large,
+Nor changed his course, but through the shaggy hill
+Passed underneath ingulfed; for God had thrown
+That mountain as his garden-mould high raised
+Upon the rapid current, which, through veins
+Of porous earth with kindly thirst up-drawn,
+Rose a fresh fountain, and with many a rill
+Watered the garden; thence united fell
+Down the steep glade, and met the nether flood,
+Which from his darksome passage now appears,
+And now, divided into four main streams,
+Runs diverse, wandering many a famous realm
+And country, whereof here needs no account;
+But rather to tell how, if Art could tell,
+How from that sapphire fount the crisped brooks,
+Rolling on orient pearl and sands of gold,
+With mazy errour under pendant shades
+Ran nectar, visiting each plant, and fed
+Flowers worthy of Paradise, which not nice Art
+In beds and curious knots, but Nature boon
+Poured forth profuse on hill, and dale, and plain,
+Both where the morning sun first warmly smote
+The open field, and where the unpierced shade
+Imbrowned the noontide bowers: Thus was this place
+A happy rural seat of various view;
+Groves whose rich trees wept odorous gums and balm,
+Others whose fruit, burnished with golden rind,
+Hung amiable, Hesperian fables true,
+If true, here only, and of delicious taste:
+Betwixt them lawns, or level downs, and flocks
+Grazing the tender herb, were interposed,
+Or palmy hillock; or the flowery lap
+Of some irriguous valley spread her store,
+Flowers of all hue, and without thorn the rose:
+Another side, umbrageous grots and caves
+Of cool recess, o'er which the mantling vine
+Lays forth her purple grape, and gently creeps
+Luxuriant; mean while murmuring waters fall
+Down the slope hills, dispersed, or in a lake,
+That to the fringed bank with myrtle crowned
+Her crystal mirrour holds, unite their streams.
+The birds their quire apply; airs, vernal airs,
+Breathing the smell of field and grove, attune
+The trembling leaves, while universal Pan,
+Knit with the Graces and the Hours in dance,
+Led on the eternal Spring. Not that fair field
+Of Enna, where Proserpine gathering flowers,
+Herself a fairer flower by gloomy Dis
+Was gathered, which cost Ceres all that pain
+To seek her through the world; nor that sweet grove
+Of Daphne by Orontes, and the inspired
+Castalian spring, might with this Paradise
+Of Eden strive; nor that Nyseian isle
+Girt with the river Triton, where old Cham,
+Whom Gentiles Ammon call and Libyan Jove,
+Hid Amalthea, and her florid son
+Young Bacchus, from his stepdame Rhea's eye;
+Nor where Abassin kings their issue guard,
+Mount Amara, though this by some supposed
+True Paradise under the Ethiop line
+By Nilus' head, enclosed with shining rock,
+A whole day's journey high, but wide remote
+From this Assyrian garden, where the Fiend
+Saw, undelighted, all delight, all kind
+Of living creatures, new to sight, and strange
+Two of far nobler shape, erect and tall,
+Godlike erect, with native honour clad
+In naked majesty seemed lords of all:
+And worthy seemed; for in their looks divine
+The image of their glorious Maker shone,
+Truth, wisdom, sanctitude severe and pure,
+(Severe, but in true filial freedom placed,)
+Whence true authority in men; though both
+Not equal, as their sex not equal seemed;
+For contemplation he and valour formed;
+For softness she and sweet attractive grace;
+He for God only, she for God in him:
+His fair large front and eye sublime declared
+Absolute rule; and hyacinthine locks
+Round from his parted forelock manly hung
+Clustering, but not beneath his shoulders broad:
+She, as a veil, down to the slender waist
+Her unadorned golden tresses wore
+Dishevelled, but in wanton ringlets waved
+As the vine curls her tendrils, which implied
+Subjection, but required with gentle sway,
+And by her yielded, by him best received,
+Yielded with coy submission, modest pride,
+And sweet, reluctant, amorous delay.
+Nor those mysterious parts were then concealed;
+Then was not guilty shame, dishonest shame
+Of nature's works, honour dishonourable,
+Sin-bred, how have ye troubled all mankind
+With shows instead, mere shows of seeming pure,
+And banished from man's life his happiest life,
+Simplicity and spotless innocence!
+So passed they naked on, nor shunned the sight
+Of God or Angel; for they thought no ill:
+So hand in hand they passed, the loveliest pair,
+That ever since in love's embraces met;
+Adam the goodliest man of men since born
+His sons, the fairest of her daughters Eve.
+Under a tuft of shade that on a green
+Stood whispering soft, by a fresh fountain side
+They sat them down; and, after no more toil
+Of their sweet gardening labour than sufficed
+To recommend cool Zephyr, and made ease
+More easy, wholesome thirst and appetite
+More grateful, to their supper-fruits they fell,
+Nectarine fruits which the compliant boughs
+Yielded them, side-long as they sat recline
+On the soft downy bank damasked with flowers:
+The savoury pulp they chew, and in the rind,
+Still as they thirsted, scoop the brimming stream;
+Nor gentle purpose, nor endearing smiles
+Wanted, nor youthful dalliance, as beseems
+Fair couple, linked in happy nuptial league,
+Alone as they. About them frisking played
+All beasts of the earth, since wild, and of all chase
+In wood or wilderness, forest or den;
+Sporting the lion ramped, and in his paw
+Dandled the kid; bears, tigers, ounces, pards,
+Gambolled before them; the unwieldy elephant,
+To make them mirth, used all his might, and wreathed
+His?kithetmroboscis; close the serpent sly,
+Insinuating, wove with Gordian twine
+His braided train, and of his fatal guile
+Gave proof unheeded; others on the grass
+Couched, and now filled with pasture gazing sat,
+Or bedward ruminating; for the sun,
+Declined, was hasting now with prone career
+To the ocean isles, and in the ascending scale
+Of Heaven the stars that usher evening rose:
+When Satan still in gaze, as first he stood,
+Scarce thus at length failed speech recovered sad.
+O Hell! what do mine eyes with grief behold!
+Into our room of bliss thus high advanced
+Creatures of other mould, earth-born perhaps,
+Not Spirits, yet to heavenly Spirits bright
+Little inferiour; whom my thoughts pursue
+With wonder, and could love, so lively shines
+In them divine resemblance, and such grace
+The hand that formed them on their shape hath poured.
+Ah! gentle pair, ye little think how nigh
+Your change approaches, when all these delights
+Will vanish, and deliver ye to woe;
+More woe, the more your taste is now of joy;
+Happy, but for so happy ill secured
+Long to continue, and this high seat your Heaven
+Ill fenced for Heaven to keep out such a foe
+As now is entered; yet no purposed foe
+To you, whom I could pity thus forlorn,
+Though I unpitied: League with you I seek,
+And mutual amity, so strait, so close,
+That I with you must dwell, or you with me
+Henceforth; my dwelling haply may not please,
+Like this fair Paradise, your sense; yet such
+Accept your Maker's work; he gave it me,
+Which I as freely give: Hell shall unfold,
+To entertain you two, her widest gates,
+And send forth all her kings; there will be room,
+Not like these narrow limits, to receive
+Your numerous offspring; if no better place,
+Thank him who puts me loth to this revenge
+On you who wrong me not for him who wronged.
+And should I at your harmless innocence
+Melt, as I do, yet publick reason just,
+Honour and empire with revenge enlarged,
+By conquering this new world, compels me now
+To do what else, though damned, I should abhor.
+So spake the Fiend, and with necessity,
+The tyrant's plea, excused his devilish deeds.
+Then from his lofty stand on that high tree
+Down he alights among the sportful herd
+Of those four-footed kinds, himself now one,
+Now other, as their shape served best his end
+Nearer to view his prey, and, unespied,
+To mark what of their state he more might learn,
+By word or action marked. About them round
+A lion now he stalks with fiery glare;
+Then as a tiger, who by chance hath spied
+In some purlieu two gentle fawns at play,
+Straight couches close, then, rising, changes oft
+His couchant watch, as one who chose his ground,
+Whence rushing, he might surest seize them both,
+Griped in each paw: when, Adam first of men
+To first of women Eve thus moving speech,
+Turned him, all ear to hear new utterance flow.
+Sole partner, and sole part, of all these joys,
+Dearer thyself than all; needs must the Power
+That made us, and for us this ample world,
+Be infinitely good, and of his good
+As liberal and free as infinite;
+That raised us from the dust, and placed us here
+In all this happiness, who at his hand
+Have nothing merited, nor can perform
+Aught whereof he hath need; he who requires
+From us no other service than to keep
+This one, this easy charge, of all the trees
+In Paradise that bear delicious fruit
+So various, not to taste that only tree
+Of knowledge, planted by the tree of life;
+So near grows death to life, whate'er death is,
+Some dreadful thing no doubt; for well thou knowest
+God hath pronounced it death to taste that tree,
+The only sign of our obedience left,
+Among so many signs of power and rule
+Conferred upon us, and dominion given
+Over all other creatures that possess
+Earth, air, and sea. Then let us not think hard
+One easy prohibition, who enjoy
+Free leave so large to all things else, and choice
+Unlimited of manifold delights:
+But let us ever praise him, and extol
+His bounty, following our delightful task,
+To prune these growing plants, and tend these flowers,
+Which were it toilsome, yet with thee were sweet.
+To whom thus Eve replied. O thou for whom
+And from whom I was formed, flesh of thy flesh,
+And without whom am to no end, my guide
+And head! what thou hast said is just and right.
+For we to him indeed all praises owe,
+And daily thanks; I chiefly, who enjoy
+So far the happier lot, enjoying thee
+Pre-eminent by so much odds, while thou
+Like consort to thyself canst no where find.
+That day I oft remember, when from sleep
+I first awaked, and found myself reposed
+Under a shade on flowers, much wondering where
+And what I was, whence thither brought, and how.
+Not distant far from thence a murmuring sound
+Of waters issued from a cave, and spread
+Into a liquid plain, then stood unmoved
+Pure as the expanse of Heaven; I thither went
+With unexperienced thought, and laid me down
+On the green bank, to look into the clear
+Smooth lake, that to me seemed another sky.
+As I bent down to look, just opposite
+A shape within the watery gleam appeared,
+Bending to look on me: I started back,
+It started back; but pleased I soon returned,
+Pleased it returned as soon with answering looks
+Of sympathy and love: There I had fixed
+Mine eyes till now, and pined with vain desire,
+Had not a voice thus warned me; 'What thou seest,
+'What there thou seest, fair Creature, is thyself;
+'With thee it came and goes: but follow me,
+'And I will bring thee where no shadow stays
+'Thy coming, and thy soft embraces, he
+'Whose image thou art; him thou shalt enjoy
+'Inseparably thine, to him shalt bear
+'Multitudes like thyself, and thence be called
+'Mother of human race.' What could I do,
+But follow straight, invisibly thus led?
+Till I espied thee, fair indeed and tall,
+Under a platane; yet methought less fair,
+Less winning soft, less amiably mild,
+Than that smooth watery image: Back I turned;
+Thou following cryedst aloud, 'Return, fair Eve;
+'Whom flyest thou? whom thou flyest, of him thou art,
+'His flesh, his bone; to give thee being I lent
+'Out of my side to thee, nearest my heart,
+'Substantial life, to have thee by my side
+'Henceforth an individual solace dear;
+'Part of my soul I seek thee, and thee claim
+'My other half:' With that thy gentle hand
+Seised mine: I yielded;and from that time see
+How beauty is excelled by manly grace,
+And wisdom, which alone is truly fair.
+So spake our general mother, and with eyes
+Of conjugal attraction unreproved,
+And meek surrender, half-embracing leaned
+On our first father; half her swelling breast
+Naked met his, under the flowing gold
+Of her loose tresses hid: he in delight
+Both of her beauty, and submissive charms,
+Smiled with superiour love, as Jupiter
+On Juno smiles, when he impregns the clouds
+That shed Mayflowers; and pressed her matron lip
+With kisses pure: Aside the Devil turned
+For envy; yet with jealous leer malign
+Eyed them askance, and to himself thus plained.
+Sight hateful, sight tormenting! thus these two,
+Imparadised in one another's arms,
+The happier Eden, shall enjoy their fill
+Of bliss on bliss; while I to Hell am thrust,
+Where neither joy nor love, but fierce desire,
+Among our other torments not the least,
+Still unfulfilled with pain of longing pines.
+Yet let me not forget what I have gained
+From their own mouths: All is not theirs, it seems;
+One fatal tree there stands, of knowledge called,
+Forbidden them to taste: Knowledge forbidden
+Suspicious, reasonless. Why should their Lord
+Envy them that? Can it be sin to know?
+Can it be death? And do they only stand
+By ignorance? Is that their happy state,
+The proof of their obedience and their faith?
+O fair foundation laid whereon to build
+Their ruin! hence I will excite their minds
+With more desire to know, and to reject
+Envious commands, invented with design
+To keep them low, whom knowledge might exalt
+Equal with Gods: aspiring to be such,
+They taste and die: What likelier can ensue
+But first with narrow search I must walk round
+This garden, and no corner leave unspied;
+A chance but chance may lead where I may meet
+Some wandering Spirit of Heaven by fountain side,
+Or in thick shade retired, from him to draw
+What further would be learned. Live while ye may,
+Yet happy pair; enjoy, till I return,
+Short pleasures, for long woes are to succeed!
+So saying, his proud step he scornful turned,
+But with sly circumspection, and began
+Through wood, through waste, o'er hill, o'er dale, his roam
+Mean while in utmost longitude, where Heaven
+With earth and ocean meets, the setting sun
+Slowly descended, and with right aspect
+Against the eastern gate of Paradise
+Levelled his evening rays: It was a rock
+Of alabaster, piled up to the clouds,
+Conspicuous far, winding with one ascent
+Accessible from earth, one entrance high;
+The rest was craggy cliff, that overhung
+Still as it rose, impossible to climb.
+Betwixt these rocky pillars Gabriel sat,
+Chief of the angelick guards, awaiting night;
+About him exercised heroick games
+The unarmed youth of Heaven, but nigh at hand
+Celestial armoury, shields, helms, and spears,
+Hung high with diamond flaming, and with gold.
+Thither came Uriel, gliding through the even
+On a sun-beam, swift as a shooting star
+In autumn thwarts the night, when vapours fired
+Impress the air, and shows the mariner
+From what point of his compass to beware
+Impetuous winds: He thus began in haste.
+Gabriel, to thee thy course by lot hath given
+Charge and strict watch, that to this happy place
+No evil thing approach or enter in.
+This day at highth of noon came to my sphere
+A Spirit, zealous, as he seemed, to know
+More of the Almighty's works, and chiefly Man,
+God's latest image: I described his way
+Bent all on speed, and marked his aery gait;
+But in the mount that lies from Eden north,
+Where he first lighted, soon discerned his looks
+Alien from Heaven, with passions foul obscured:
+Mine eye pursued him still, but under shade
+Lost sight of him: One of the banished crew,
+I fear, hath ventured from the deep, to raise
+New troubles; him thy care must be to find.
+To whom the winged warriour thus returned.
+Uriel, no wonder if thy perfect sight,
+Amid the sun's bright circle where thou sitst,
+See far and wide: In at this gate none pass
+The vigilance here placed, but such as come
+Well known from Heaven; and since meridian hour
+No creature thence: If Spirit of other sort,
+So minded, have o'er-leaped these earthly bounds
+On purpose, hard thou knowest it to exclude
+Spiritual substance with corporeal bar.
+But if within the circuit of these walks,
+In whatsoever shape he lurk, of whom
+Thou tellest, by morrow dawning I shall know.
+So promised he; and Uriel to his charge
+Returned on that bright beam, whose point now raised
+Bore him slope downward to the sun now fallen
+Beneath the Azores; whether the prime orb,
+Incredible how swift, had thither rolled
+Diurnal, or this less volubil earth,
+By shorter flight to the east, had left him there
+Arraying with reflected purple and gold
+The clouds that on his western throne attend.
+Now came still Evening on, and Twilight gray
+Had in her sober livery all things clad;
+Silence accompanied; for beast and bird,
+They to their grassy couch, these to their nests
+Were slunk, all but the wakeful nightingale;
+She all night long her amorous descant sung;
+Silence was pleased: Now glowed the firmament
+With living sapphires: Hesperus, that led
+The starry host, rode brightest, till the moon,
+Rising in clouded majesty, at length
+Apparent queen unveiled her peerless light,
+And o'er the dark her silver mantle threw.
+When Adam thus to Eve. Fair Consort, the hour
+Of night, and all things now retired to rest,
+Mind us of like repose; since God hath set
+Labour and rest, as day and night, to men
+Successive; and the timely dew of sleep,
+Now falling with soft slumbrous weight, inclines
+Our eye-lids: Other creatures all day long
+Rove idle, unemployed, and less need rest;
+Man hath his daily work of body or mind
+Appointed, which declares his dignity,
+And the regard of Heaven on all his ways;
+While other animals unactive range,
+And of their doings God takes no account.
+To-morrow, ere fresh morning streak the east
+With first approach of light, we must be risen,
+And at our pleasant labour, to reform
+Yon flowery arbours, yonder alleys green,
+Our walk at noon, with branches overgrown,
+That mock our scant manuring, and require
+More hands than ours to lop their wanton growth:
+Those blossoms also, and those dropping gums,
+That lie bestrown, unsightly and unsmooth,
+Ask riddance, if we mean to tread with ease;
+Mean while, as Nature wills, night bids us rest.
+To whom thus Eve, with perfect beauty adorned
+My Author and Disposer, what thou bidst
+Unargued I obey: So God ordains;
+God is thy law, thou mine: To know no more
+Is woman's happiest knowledge, and her praise.
+With thee conversing I forget all time;
+All seasons, and their change, all please alike.
+Sweet is the breath of Morn, her rising sweet,
+With charm of earliest birds: pleasant the sun,
+When first on this delightful land he spreads
+His orient beams, on herb, tree, fruit, and flower,
+Glistering with dew; fragrant the fertile earth
+After soft showers; and sweet the coming on
+Of grateful Evening mild; then silent Night,
+With this her solemn bird, and this fair moon,
+And these the gems of Heaven, her starry train:
+But neither breath of Morn, when she ascends
+With charm of earliest birds; nor rising sun
+On this delightful land; nor herb, fruit, flower,
+Glistering with dew; nor fragrance after showers;
+Nor grateful Evening mild; nor silent Night,
+With this her solemn bird, nor walk by moon,
+Or glittering star-light, without thee is sweet.
+But wherefore all night long shine these? for whom
+This glorious sight, when sleep hath shut all eyes?
+To whom our general ancestor replied.
+Daughter of God and Man, accomplished Eve,
+These have their course to finish round the earth,
+By morrow evening, and from land to land
+In order, though to nations yet unborn,
+Ministring light prepared, they set and rise;
+Lest total Darkness should by night regain
+Her old possession, and extinguish life
+In Nature and all things; which these soft fires
+Not only enlighten, but with kindly heat
+Of various influence foment and warm,
+Temper or nourish, or in part shed down
+Their stellar virtue on all kinds that grow
+On earth, made hereby apter to receive
+Perfection from the sun's more potent ray.
+These then, though unbeheld in deep of night,
+Shine not in vain; nor think, though men were none,
+That Heaven would want spectators, God want praise:
+Millions of spiritual creatures walk the earth
+Unseen, both when we wake, and when we sleep:
+All these with ceaseless praise his works behold
+Both day and night: How often from the steep
+Of echoing hill or thicket have we heard
+Celestial voices to the midnight air,
+Sole, or responsive each to others note,
+Singing their great Creator? oft in bands
+While they keep watch, or nightly rounding walk,
+With heavenly touch of instrumental sounds
+In full harmonick number joined, their songs
+Divide the night, and lift our thoughts to Heaven.
+Thus talking, hand in hand alone they passed
+On to their blissful bower: it was a place
+Chosen by the sovran Planter, when he framed
+All things to Man's delightful use; the roof
+Of thickest covert was inwoven shade
+Laurel and myrtle, and what higher grew
+Of firm and fragrant leaf; on either side
+Acanthus, and each odorous bushy shrub,
+Fenced up the verdant wall; each beauteous flower,
+Iris all hues, roses, and jessamin,
+Reared high their flourished heads between, and wrought
+Mosaick; underfoot the violet,
+Crocus, and hyacinth, with rich inlay
+Broidered the ground, more coloured than with stone
+Of costliest emblem: Other creature here,
+Bird, beast, insect, or worm, durst enter none,
+Such was their awe of Man. In shadier bower
+More sacred and sequestered, though but feigned,
+Pan or Sylvanus never slept, nor Nymph
+Nor Faunus haunted. Here, in close recess,
+With flowers, garlands, and sweet-smelling herbs,
+Espoused Eve decked first her nuptial bed;
+And heavenly quires the hymenaean sung,
+What day the genial Angel to our sire
+Brought her in naked beauty more adorned,
+More lovely, than Pandora, whom the Gods
+Endowed with all their gifts, and O! too like
+In sad event, when to the unwiser son
+Of Japhet brought by Hermes, she ensnared
+Mankind with her fair looks, to be avenged
+On him who had stole Jove's authentick fire.
+Thus, at their shady lodge arrived, both stood,
+Both turned, and under open sky adored
+The God that made both sky, air, earth, and heaven,
+Which they beheld, the moon's resplendent globe,
+And starry pole: Thou also madest the night,
+Maker Omnipotent, and thou the day,
+Which we, in our appointed work employed,
+Have finished, happy in our mutual help
+And mutual love, the crown of all our bliss
+Ordained by thee; and this delicious place
+For us too large, where thy abundance wants
+Partakers, and uncropt falls to the ground.
+But thou hast promised from us two a race
+To fill the earth, who shall with us extol
+Thy goodness infinite, both when we wake,
+And when we seek, as now, thy gift of sleep.
+This said unanimous, and other rites
+Observing none, but adoration pure
+Which God likes best, into their inmost bower
+Handed they went; and, eased the putting off
+These troublesome disguises which we wear,
+Straight side by side were laid; nor turned, I ween,
+Adam from his fair spouse, nor Eve the rites
+Mysterious of connubial love refused:
+Whatever hypocrites austerely talk
+Of purity, and place, and innocence,
+Defaming as impure what God declares
+Pure, and commands to some, leaves free to all.
+Our Maker bids encrease; who bids abstain
+But our Destroyer, foe to God and Man?
+Hail, wedded Love, mysterious law, true source
+Of human offspring, sole propriety
+In Paradise of all things common else!
+By thee adulterous Lust was driven from men
+Among the bestial herds to range; by thee
+Founded in reason, loyal, just, and pure,
+Relations dear, and all the charities
+Of father, son, and brother, first were known.
+Far be it, that I should write thee sin or blame,
+Or think thee unbefitting holiest place,
+Perpetual fountain of domestick sweets,
+Whose bed is undefiled and chaste pronounced,
+Present, or past, as saints and patriarchs used.
+Here Love his golden shafts employs, here lights
+His constant lamp, and waves his purple wings,
+Reigns here and revels; not in the bought smile
+Of harlots, loveless, joyless, unendeared,
+Casual fruition; nor in court-amours,
+Mixed dance, or wanton mask, or midnight ball,
+Or serenate, which the starved lover sings
+To his proud fair, best quitted with disdain.
+These, lulled by nightingales, embracing slept,
+And on their naked limbs the flowery roof
+Showered roses, which the morn repaired. Sleep on,
+Blest pair; and O!yet happiest, if ye seek
+No happier state, and know to know no more.
+Now had night measured with her shadowy cone
+Half way up hill this vast sublunar vault,
+And from their ivory port the Cherubim,
+Forth issuing at the accustomed hour, stood armed
+To their night watches in warlike parade;
+When Gabriel to his next in power thus spake.
+Uzziel, half these draw off, and coast the south
+With strictest watch; these other wheel the north;
+Our circuit meets full west. As flame they part,
+Half wheeling to the shield, half to the spear.
+From these, two strong and subtle Spirits he called
+That near him stood, and gave them thus in charge.
+Ithuriel and Zephon, with winged speed
+Search through this garden, leave unsearched no nook;
+But chiefly where those two fair creatures lodge,
+Now laid perhaps asleep, secure of harm.
+This evening from the sun's decline arrived,
+Who tells of some infernal Spirit seen
+Hitherward bent (who could have thought?) escaped
+The bars of Hell, on errand bad no doubt:
+Such, where ye find, seise fast, and hither bring.
+So saying, on he led his radiant files,
+Dazzling the moon; these to the bower direct
+In search of whom they sought: Him there they found
+Squat like a toad, close at the ear of Eve,
+Assaying by his devilish art to reach
+The organs of her fancy, and with them forge
+Illusions, as he list, phantasms and dreams;
+Or if, inspiring venom, he might taint
+The animal spirits, that from pure blood arise
+Like gentle breaths from rivers pure, thence raise
+At least distempered, discontented thoughts,
+Vain hopes, vain aims, inordinate desires,
+Blown up with high conceits ingendering pride.
+Him thus intent Ithuriel with his spear
+Touched lightly; for no falshood can endure
+Touch of celestial temper, but returns
+Of force to its own likeness: Up he starts
+Discovered and surprised. As when a spark
+Lights on a heap of nitrous powder, laid
+Fit for the tun some magazine to store
+Against a rumoured war, the smutty grain,
+With sudden blaze diffused, inflames the air;
+So started up in his own shape the Fiend.
+Back stept those two fair Angels, half amazed
+So sudden to behold the grisly king;
+Yet thus, unmoved with fear, accost him soon.
+Which of those rebel Spirits adjudged to Hell
+Comest thou, escaped thy prison? and, transformed,
+Why sat'st thou like an enemy in wait,
+Here watching at the head of these that sleep?
+Know ye not then said Satan, filled with scorn,
+Know ye not me? ye knew me once no mate
+For you, there sitting where ye durst not soar:
+Not to know me argues yourselves unknown,
+The lowest of your throng; or, if ye know,
+Why ask ye, and superfluous begin
+Your message, like to end as much in vain?
+To whom thus Zephon, answering scorn with scorn.
+Think not, revolted Spirit, thy shape the same,
+Or undiminished brightness to be known,
+As when thou stoodest in Heaven upright and pure;
+That glory then, when thou no more wast good,
+Departed from thee; and thou resemblest now
+Thy sin and place of doom obscure and foul.
+But come, for thou, be sure, shalt give account
+To him who sent us, whose charge is to keep
+This place inviolable, and these from harm.
+So spake the Cherub; and his grave rebuke,
+Severe in youthful beauty, added grace
+Invincible: Abashed the Devil stood,
+And felt how awful goodness is, and saw
+Virtue in her shape how lovely; saw, and pined
+His loss; but chiefly to find here observed
+His lustre visibly impaired; yet seemed
+Undaunted. If I must contend, said he,
+Best with the best, the sender, not the sent,
+Or all at once; more glory will be won,
+Or less be lost. Thy fear, said Zephon bold,
+Will save us trial what the least can do
+Single against thee wicked, and thence weak.
+The Fiend replied not, overcome with rage;
+But, like a proud steed reined, went haughty on,
+Champing his iron curb: To strive or fly
+He held it vain; awe from above had quelled
+His heart, not else dismayed. Now drew they nigh
+The western point, where those half-rounding guards
+Just met, and closing stood in squadron joined,
+A waiting next command. To whom their Chief,
+Gabriel, from the front thus called aloud.
+O friends! I hear the tread of nimble feet
+Hasting this way, and now by glimpse discern
+Ithuriel and Zephon through the shade;
+And with them comes a third of regal port,
+But faded splendour wan; who by his gait
+And fierce demeanour seems the Prince of Hell,
+Not likely to part hence without contest;
+Stand firm, for in his look defiance lours.
+He scarce had ended, when those two approached,
+And brief related whom they brought, where found,
+How busied, in what form and posture couched.
+To whom with stern regard thus Gabriel spake.
+Why hast thou, Satan, broke the bounds prescribed
+To thy transgressions, and disturbed the charge
+Of others, who approve not to transgress
+By thy example, but have power and right
+To question thy bold entrance on this place;
+Employed, it seems, to violate sleep, and those
+Whose dwelling God hath planted here in bliss!
+To whom thus Satan with contemptuous brow.
+Gabriel? thou hadst in Heaven the esteem of wise,
+And such I held thee; but this question asked
+Puts me in doubt. Lives there who loves his pain!
+Who would not, finding way, break loose from Hell,
+Though thither doomed! Thou wouldst thyself, no doubt
+And boldly venture to whatever place
+Farthest from pain, where thou mightst hope to change
+Torment with ease, and soonest recompense
+Dole with delight, which in this place I sought;
+To thee no reason, who knowest only good,
+But evil hast not tried: and wilt object
+His will who bounds us! Let him surer bar
+His iron gates, if he intends our stay
+In that dark durance: Thus much what was asked.
+The rest is true, they found me where they say;
+But that implies not violence or harm.
+Thus he in scorn. The warlike Angel moved,
+Disdainfully half smiling, thus replied.
+O loss of one in Heaven to judge of wise
+Since Satan fell, whom folly overthrew,
+And now returns him from his prison 'scaped,
+Gravely in doubt whether to hold them wise
+Or not, who ask what boldness brought him hither
+Unlicensed from his bounds in Hell prescribed;
+So wise he judges it to fly from pain
+However, and to 'scape his punishment!
+So judge thou still, presumptuous! till the wrath,
+Which thou incurrest by flying, meet thy flight
+Sevenfold, and scourge that wisdom back to Hell,
+Which taught thee yet no better, that no pain
+Can equal anger infinite provoked.
+But wherefore thou alone? wherefore with thee
+Came not all hell broke loose? or thou than they
+Less hardy to endure? Courageous Chief!
+The first in flight from pain! hadst thou alleged
+To thy deserted host this cause of flight,
+Thou surely hadst not come sole fugitive.
+To which the Fiend thus answered, frowning stern.
+Not that I less endure, or shrink from pain,
+Insulting Angel! well thou knowest I stood
+Thy fiercest, when in battle to thy aid
+The blasting vollied thunder made all speed,
+And seconded thy else not dreaded spear.
+But still thy words at random, as before,
+Argue thy inexperience what behoves
+From hard assays and ill successes past
+A faithful leader, not to hazard all
+Through ways of danger by himself untried:
+I, therefore, I alone first undertook
+To wing the desolate abyss, and spy
+This new created world, whereof in Hell
+Fame is not silent, here in hope to find
+Better abode, and my afflicted Powers
+To settle here on earth, or in mid air;
+Though for possession put to try once more
+What thou and thy gay legions dare against;
+Whose easier business were to serve their Lord
+High up in Heaven, with songs to hymn his throne,
+And practised distances to cringe, not fight,
+To whom the warriour Angel soon replied.
+To say and straight unsay, pretending first
+Wise to fly pain, professing next the spy,
+Argues no leader but a liear traced,
+Satan, and couldst thou faithful add? O name,
+O sacred name of faithfulness profaned!
+Faithful to whom? to thy rebellious crew?
+Army of Fiends, fit body to fit head.
+Was this your discipline and faith engaged,
+Your military obedience, to dissolve
+Allegiance to the acknowledged Power supreme?
+And thou, sly hypocrite, who now wouldst seem
+Patron of liberty, who more than thou
+Once fawned, and cringed, and servily adored
+Heaven's awful Monarch? wherefore, but in hope
+To dispossess him, and thyself to reign?
+But mark what I arreed thee now, Avant;
+Fly neither whence thou fledst! If from this hour
+Within these hallowed limits thou appear,
+Back to the infernal pit I drag thee chained,
+And seal thee so, as henceforth not to scorn
+The facile gates of Hell too slightly barred.
+So threatened he; but Satan to no threats
+Gave heed, but waxing more in rage replied.
+Then when I am thy captive talk of chains,
+Proud limitary Cherub! but ere then
+Far heavier load thyself expect to feel
+From my prevailing arm, though Heaven's King
+Ride on thy wings, and thou with thy compeers,
+Us'd to the yoke, drawest his triumphant wheels
+In progress through the road of Heaven star-paved.
+While thus he spake, the angelick squadron bright
+Turned fiery red, sharpening in mooned horns
+Their phalanx, and began to hem him round
+With ported spears, as thick as when a field
+Of Ceres ripe for harvest waving bends
+Her bearded grove of ears, which way the wind
+Sways them; the careful plowman doubting stands,
+Left on the threshing floor his hopeless sheaves
+Prove chaff. On the other side, Satan, alarmed,
+Collecting all his might, dilated stood,
+Like Teneriff or Atlas, unremoved:
+His stature reached the sky, and on his crest
+Sat Horrour plumed; nor wanted in his grasp
+What seemed both spear and shield: Now dreadful deeds
+Might have ensued, nor only Paradise
+In this commotion, but the starry cope
+Of Heaven perhaps, or all the elements
+At least had gone to wrack, disturbed and torn
+With violence of this conflict, had not soon
+The Eternal, to prevent such horrid fray,
+Hung forth in Heaven his golden scales, yet seen
+Betwixt Astrea and the Scorpion sign,
+Wherein all things created first he weighed,
+The pendulous round earth with balanced air
+In counterpoise, now ponders all events,
+Battles and realms: In these he put two weights,
+The sequel each of parting and of fight:
+The latter quick up flew, and kicked the beam,
+Which Gabriel spying, thus bespake the Fiend.
+Satan, I know thy strength, and thou knowest mine;
+Neither our own, but given: What folly then
+To boast what arms can do? since thine no more
+Than Heaven permits, nor mine, though doubled now
+To trample thee as mire: For proof look up,
+And read thy lot in yon celestial sign;
+Where thou art weighed, and shown how light, how weak,
+If thou resist. The Fiend looked up, and knew
+His mounted scale aloft: Nor more;but fled
+Murmuring, and with him fled the shades of night.
+
+
+
+Book V
+
+
+Now Morn, her rosy steps in the eastern clime
+Advancing, sowed the earth with orient pearl,
+When Adam waked, so customed; for his sleep
+Was aery-light, from pure digestion bred,
+And temperate vapours bland, which the only sound
+Of leaves and fuming rills, Aurora's fan,
+Lightly dispersed, and the shrill matin song
+Of birds on every bough; so much the more
+His wonder was to find unwakened Eve
+With tresses discomposed, and glowing cheek,
+As through unquiet rest: He, on his side
+Leaning half raised, with looks of cordial love
+Hung over her enamoured, and beheld
+Beauty, which, whether waking or asleep,
+Shot forth peculiar graces; then with voice
+Mild, as when Zephyrus on Flora breathes,
+Her hand soft touching, whispered thus. Awake,
+My fairest, my espoused, my latest found,
+Heaven's last best gift, my ever new delight!
+Awake: The morning shines, and the fresh field
+Calls us; we lose the prime, to mark how spring
+Our tender plants, how blows the citron grove,
+What drops the myrrh, and what the balmy reed,
+How nature paints her colours, how the bee
+Sits on the bloom extracting liquid sweet.
+Such whispering waked her, but with startled eye
+On Adam, whom embracing, thus she spake.
+O sole in whom my thoughts find all repose,
+My glory, my perfection! glad I see
+Thy face, and morn returned; for I this night
+(Such night till this I never passed) have dreamed,
+If dreamed, not, as I oft am wont, of thee,
+Works of day past, or morrow's next design,
+But of offence and trouble, which my mind
+Knew never till this irksome night: Methought,
+Close at mine ear one called me forth to walk
+With gentle voice; I thought it thine: It said,
+'Why sleepest thou, Eve? now is the pleasant time,
+'The cool, the silent, save where silence yields
+'To the night-warbling bird, that now awake
+'Tunes sweetest his love-laboured song; now reigns
+'Full-orbed the moon, and with more pleasing light
+'Shadowy sets off the face of things; in vain,
+'If none regard; Heaven wakes with all his eyes,
+'Whom to behold but thee, Nature's desire?
+'In whose sight all things joy, with ravishment
+'Attracted by thy beauty still to gaze.'
+I rose as at thy call, but found thee not;
+To find thee I directed then my walk;
+And on, methought, alone I passed through ways
+That brought me on a sudden to the tree
+Of interdicted knowledge: fair it seemed,
+Much fairer to my fancy than by day:
+And, as I wondering looked, beside it stood
+One shaped and winged like one of those from Heaven
+By us oft seen; his dewy locks distilled
+Ambrosia; on that tree he also gazed;
+And 'O fair plant,' said he, 'with fruit surcharged,
+'Deigns none to ease thy load, and taste thy sweet,
+'Nor God, nor Man? Is knowledge so despised?
+'Or envy, or what reserve forbids to taste?
+'Forbid who will, none shall from me withhold
+'Longer thy offered good; why else set here?
+This said, he paused not, but with venturous arm
+He plucked, he tasted; me damp horrour chilled
+At such bold words vouched with a deed so bold:
+But he thus, overjoyed; 'O fruit divine,
+'Sweet of thyself, but much more sweet thus cropt,
+'Forbidden here, it seems, as only fit
+'For Gods, yet able to make Gods of Men:
+'And why not Gods of Men; since good, the more
+'Communicated, more abundant grows,
+'The author not impaired, but honoured more?
+'Here, happy creature, fair angelick Eve!
+'Partake thou also; happy though thou art,
+'Happier thou mayest be, worthier canst not be:
+'Taste this, and be henceforth among the Gods
+'Thyself a Goddess, not to earth confined,
+'But sometimes in the air, as we, sometimes
+'Ascend to Heaven, by merit thine, and see
+'What life the Gods live there, and such live thou!'
+So saying, he drew nigh, and to me held,
+Even to my mouth of that same fruit held part
+Which he had plucked; the pleasant savoury smell
+So quickened appetite, that I, methought,
+Could not but taste. Forthwith up to the clouds
+With him I flew, and underneath beheld
+The earth outstretched immense, a prospect wide
+And various: Wondering at my flight and change
+To this high exaltation; suddenly
+My guide was gone, and I, methought, sunk down,
+And fell asleep; but O, how glad I waked
+To find this but a dream! Thus Eve her night
+Related, and thus Adam answered sad.
+Best image of myself, and dearer half,
+The trouble of thy thoughts this night in sleep
+Affects me equally; nor can I like
+This uncouth dream, of evil sprung, I fear;
+Yet evil whence? in thee can harbour none,
+Created pure. But know that in the soul
+Are many lesser faculties, that serve
+Reason as chief; among these Fancy next
+Her office holds; of all external things
+Which the five watchful senses represent,
+She forms imaginations, aery shapes,
+Which Reason, joining or disjoining, frames
+All what we affirm or what deny, and call
+Our knowledge or opinion; then retires
+Into her private cell, when nature rests.
+Oft in her absence mimick Fancy wakes
+To imitate her; but, misjoining shapes,
+Wild work produces oft, and most in dreams;
+Ill matching words and deeds long past or late.
+Some such resemblances, methinks, I find
+Of our last evening's talk, in this thy dream,
+But with addition strange; yet be not sad.
+Evil into the mind of God or Man
+May come and go, so unreproved, and leave
+No spot or blame behind: Which gives me hope
+That what in sleep thou didst abhor to dream,
+Waking thou never will consent to do.
+Be not disheartened then, nor cloud those looks,
+That wont to be more cheerful and serene,
+Than when fair morning first smiles on the world;
+And let us to our fresh employments rise
+Among the groves, the fountains, and the flowers
+That open now their choisest bosomed smells,
+Reserved from night, and kept for thee in store.
+So cheered he his fair spouse, and she was cheered;
+But silently a gentle tear let fall
+From either eye, and wiped them with her hair;
+Two other precious drops that ready stood,
+Each in their crystal sluice, he ere they fell
+Kissed, as the gracious signs of sweet remorse
+And pious awe, that feared to have offended.
+So all was cleared, and to the field they haste.
+But first, from under shady arborous roof
+Soon as they forth were come to open sight
+Of day-spring, and the sun, who, scarce up-risen,
+With wheels yet hovering o'er the ocean-brim,
+Shot parallel to the earth his dewy ray,
+Discovering in wide landskip all the east
+Of Paradise and Eden's happy plains,
+Lowly they bowed adoring, and began
+Their orisons, each morning duly paid
+In various style; for neither various style
+Nor holy rapture wanted they to praise
+Their Maker, in fit strains pronounced, or sung
+Unmeditated; such prompt eloquence
+Flowed from their lips, in prose or numerous verse,
+More tuneable than needed lute or harp
+To add more sweetness; and they thus began.
+These are thy glorious works, Parent of good,
+Almighty! Thine this universal frame,
+Thus wonderous fair; Thyself how wonderous then!
+Unspeakable, who sitst above these heavens
+To us invisible, or dimly seen
+In these thy lowest works; yet these declare
+Thy goodness beyond thought, and power divine.
+Speak, ye who best can tell, ye sons of light,
+Angels; for ye behold him, and with songs
+And choral symphonies, day without night,
+Circle his throne rejoicing; ye in Heaven
+On Earth join all ye Creatures to extol
+Him first, him last, him midst, and without end.
+Fairest of stars, last in the train of night,
+If better thou belong not to the dawn,
+Sure pledge of day, that crownest the smiling morn
+With thy bright circlet, praise him in thy sphere,
+While day arises, that sweet hour of prime.
+Thou Sun, of this great world both eye and soul,
+Acknowledge him thy greater; sound his praise
+In thy eternal course, both when thou climbest,
+And when high noon hast gained, and when thou fallest.
+Moon, that now meetest the orient sun, now flyest,
+With the fixed Stars, fixed in their orb that flies;
+And ye five other wandering Fires, that move
+In mystick dance not without song, resound
+His praise, who out of darkness called up light.
+Air, and ye Elements, the eldest birth
+Of Nature's womb, that in quaternion run
+Perpetual circle, multiform; and mix
+And nourish all things; let your ceaseless change
+Vary to our great Maker still new praise.
+Ye Mists and Exhalations, that now rise
+From hill or steaming lake, dusky or gray,
+Till the sun paint your fleecy skirts with gold,
+In honour to the world's great Author rise;
+Whether to deck with clouds the uncoloured sky,
+Or wet the thirsty earth with falling showers,
+Rising or falling still advance his praise.
+His praise, ye Winds, that from four quarters blow,
+Breathe soft or loud; and, wave your tops, ye Pines,
+With every plant, in sign of worship wave.
+Fountains, and ye that warble, as ye flow,
+Melodious murmurs, warbling tune his praise.
+Join voices, all ye living Souls: Ye Birds,
+That singing up to Heaven-gate ascend,
+Bear on your wings and in your notes his praise.
+Ye that in waters glide, and ye that walk
+The earth, and stately tread, or lowly creep;
+Witness if I be silent, morn or even,
+To hill, or valley, fountain, or fresh shade,
+Made vocal by my song, and taught his praise.
+Hail, universal Lord, be bounteous still
+To give us only good; and if the night
+Have gathered aught of evil, or concealed,
+Disperse it, as now light dispels the dark!
+So prayed they innocent, and to their thoughts
+Firm peace recovered soon, and wonted calm.
+On to their morning's rural work they haste,
+Among sweet dews and flowers; where any row
+Of fruit-trees over-woody reached too far
+Their pampered boughs, and needed hands to check
+Fruitless embraces: or they led the vine
+To wed her elm; she, spoused, about him twines
+Her marriageable arms, and with him brings
+Her dower, the adopted clusters, to adorn
+His barren leaves. Them thus employed beheld
+With pity Heaven's high King, and to him called
+Raphael, the sociable Spirit, that deigned
+To travel with Tobias, and secured
+His marriage with the seventimes-wedded maid.
+Raphael, said he, thou hearest what stir on Earth
+Satan, from Hell 'scaped through the darksome gulf,
+Hath raised in Paradise; and how disturbed
+This night the human pair; how he designs
+In them at once to ruin all mankind.
+Go therefore, half this day as friend with friend
+Converse with Adam, in what bower or shade
+Thou findest him from the heat of noon retired,
+To respite his day-labour with repast,
+Or with repose; and such discourse bring on,
+As may advise him of his happy state,
+Happiness in his power left free to will,
+Left to his own free will, his will though free,
+Yet mutable; whence warn him to beware
+He swerve not, too secure: Tell him withal
+His danger, and from whom; what enemy,
+Late fallen himself from Heaven, is plotting now
+The fall of others from like state of bliss;
+By violence? no, for that shall be withstood;
+But by deceit and lies: This let him know,
+Lest, wilfully transgressing, he pretend
+Surprisal, unadmonished, unforewarned.
+So spake the Eternal Father, and fulfilled
+All justice: Nor delayed the winged Saint
+After his charge received; but from among
+Thousand celestial Ardours, where he stood
+Veiled with his gorgeous wings, up springing light,
+Flew through the midst of Heaven; the angelick quires,
+On each hand parting, to his speed gave way
+Through all the empyreal road; till, at the gate
+Of Heaven arrived, the gate self-opened wide
+On golden hinges turning, as by work
+Divine the sovran Architect had framed.
+From hence no cloud, or, to obstruct his sight,
+Star interposed, however small he sees,
+Not unconformed to other shining globes,
+Earth, and the garden of God, with cedars crowned
+Above all hills. As when by night the glass
+Of Galileo, less assured, observes
+Imagined lands and regions in the moon:
+Or pilot, from amidst the Cyclades
+Delos or Samos first appearing, kens
+A cloudy spot. Down thither prone in flight
+He speeds, and through the vast ethereal sky
+Sails between worlds and worlds, with steady wing
+Now on the polar winds, then with quick fan
+Winnows the buxom air; till, within soar
+Of towering eagles, to all the fowls he seems
+A phoenix, gazed by all as that sole bird,
+When, to enshrine his reliques in the Sun's
+Bright temple, to Egyptian Thebes he flies.
+At once on the eastern cliff of Paradise
+He lights, and to his proper shape returns
+A Seraph winged: Six wings he wore, to shade
+His lineaments divine; the pair that clad
+Each shoulder broad, came mantling o'er his breast
+With regal ornament; the middle pair
+Girt like a starry zone his waist, and round
+Skirted his loins and thighs with downy gold
+And colours dipt in Heaven; the third his feet
+Shadowed from either heel with feathered mail,
+Sky-tinctured grain. Like Maia's son he stood,
+And shook his plumes, that heavenly fragrance filled
+The circuit wide. Straight knew him all the bands
+Of Angels under watch; and to his state,
+And to his message high, in honour rise;
+For on some message high they guessed him bound.
+Their glittering tents he passed, and now is come
+Into the blissful field, through groves of myrrh,
+And flowering odours, cassia, nard, and balm;
+A wilderness of sweets; for Nature here
+Wantoned as in her prime, and played at will
+Her virgin fancies pouring forth more sweet,
+Wild above rule or art, enormous bliss.
+Him through the spicy forest onward come
+Adam discerned, as in the door he sat
+Of his cool bower, while now the mounted sun
+Shot down direct his fervid rays to warm
+Earth's inmost womb, more warmth than Adam needs:
+And Eve within, due at her hour prepared
+For dinner savoury fruits, of taste to please
+True appetite, and not disrelish thirst
+Of nectarous draughts between, from milky stream,
+Berry or grape: To whom thus Adam called.
+Haste hither, Eve, and worth thy sight behold
+Eastward among those trees, what glorious shape
+Comes this way moving; seems another morn
+Risen on mid-noon; some great behest from Heaven
+To us perhaps he brings, and will vouchsafe
+This day to be our guest. But go with speed,
+And, what thy stores contain, bring forth, and pour
+Abundance, fit to honour and receive
+Our heavenly stranger: Well we may afford
+Our givers their own gifts, and large bestow
+From large bestowed, where Nature multiplies
+Her fertile growth, and by disburthening grows
+More fruitful, which instructs us not to spare.
+To whom thus Eve. Adam, earth's hallowed mould,
+Of God inspired! small store will serve, where store,
+All seasons, ripe for use hangs on the stalk;
+Save what by frugal storing firmness gains
+To nourish, and superfluous moist consumes:
+But I will haste, and from each bough and brake,
+Each plant and juciest gourd, will pluck such choice
+To entertain our Angel-guest, as he
+Beholding shall confess, that here on Earth
+God hath dispensed his bounties as in Heaven.
+So saying, with dispatchful looks in haste
+She turns, on hospitable thoughts intent
+What choice to choose for delicacy best,
+What order, so contrived as not to mix
+Tastes, not well joined, inelegant, but bring
+Taste after taste upheld with kindliest change;
+Bestirs her then, and from each tender stalk
+Whatever Earth, all-bearing mother, yields
+In India East or West, or middle shore
+In Pontus or the Punick coast, or where
+Alcinous reigned, fruit of all kinds, in coat
+Rough, or smooth rind, or bearded husk, or shell,
+She gathers, tribute large, and on the board
+Heaps with unsparing hand; for drink the grape
+She crushes, inoffensive must, and meaths
+From many a berry, and from sweet kernels pressed
+She tempers dulcet creams; nor these to hold
+Wants her fit vessels pure; then strows the ground
+With rose and odours from the shrub unfumed.
+Mean while our primitive great sire, to meet
+His God-like guest, walks forth, without more train
+Accompanied than with his own complete
+Perfections; in himself was all his state,
+More solemn than the tedious pomp that waits
+On princes, when their rich retinue long
+Of horses led, and grooms besmeared with gold,
+Dazzles the croud, and sets them all agape.
+Nearer his presence Adam, though not awed,
+Yet with submiss approach and reverence meek,
+As to a superiour nature bowing low,
+Thus said. Native of Heaven, for other place
+None can than Heaven such glorious shape contain;
+Since, by descending from the thrones above,
+Those happy places thou hast deigned a while
+To want, and honour these, vouchsafe with us
+Two only, who yet by sovran gift possess
+This spacious ground, in yonder shady bower
+To rest; and what the garden choicest bears
+To sit and taste, till this meridian heat
+Be over, and the sun more cool decline.
+Whom thus the angelick Virtue answered mild.
+Adam, I therefore came; nor art thou such
+Created, or such place hast here to dwell,
+As may not oft invite, though Spirits of Heaven,
+To visit thee; lead on then where thy bower
+O'ershades; for these mid-hours, till evening rise,
+I have at will. So to the sylvan lodge
+They came, that like Pomona's arbour smiled,
+With flowerets decked, and fragrant smells; but Eve,
+Undecked save with herself, more lovely fair
+Than Wood-Nymph, or the fairest Goddess feigned
+Of three that in mount Ida naked strove,
+Stood to entertain her guest from Heaven; no veil
+She needed, virtue-proof; no thought infirm
+Altered her cheek. On whom the Angel Hail
+Bestowed, the holy salutation used
+Long after to blest Mary, second Eve.
+Hail, Mother of Mankind, whose fruitful womb
+Shall fill the world more numerous with thy sons,
+Than with these various fruits the trees of God
+Have heaped this table!--Raised of grassy turf
+Their table was, and mossy seats had round,
+And on her ample square from side to side
+All autumn piled, though spring and autumn here
+Danced hand in hand. A while discourse they hold;
+No fear lest dinner cool; when thus began
+Our author. Heavenly stranger, please to taste
+These bounties, which our Nourisher, from whom
+All perfect good, unmeasured out, descends,
+To us for food and for delight hath caused
+The earth to yield; unsavoury food perhaps
+To spiritual natures; only this I know,
+That one celestial Father gives to all.
+To whom the Angel. Therefore what he gives
+(Whose praise be ever sung) to Man in part
+Spiritual, may of purest Spirits be found
+No ingrateful food: And food alike those pure
+Intelligential substances require,
+As doth your rational; and both contain
+Within them every lower faculty
+Of sense, whereby they hear, see, smell, touch, taste,
+Tasting concoct, digest, assimilate,
+And corporeal to incorporeal turn.
+For know, whatever was created, needs
+To be sustained and fed: Of elements
+The grosser feeds the purer, earth the sea,
+Earth and the sea feed air, the air those fires
+Ethereal, and as lowest first the moon;
+Whence in her visage round those spots, unpurged
+Vapours not yet into her substance turned.
+Nor doth the moon no nourishment exhale
+From her moist continent to higher orbs.
+The sun that light imparts to all, receives
+From all his alimental recompence
+In humid exhalations, and at even
+Sups with the ocean. Though in Heaven the trees
+Of life ambrosial fruitage bear, and vines
+Yield nectar; though from off the boughs each morn
+We brush mellifluous dews, and find the ground
+Covered with pearly grain: Yet God hath here
+Varied his bounty so with new delights,
+As may compare with Heaven; and to taste
+Think not I shall be nice. So down they sat,
+And to their viands fell; nor seemingly
+The Angel, nor in mist, the common gloss
+Of Theologians; but with keen dispatch
+Of real hunger, and concoctive heat
+To transubstantiate: What redounds, transpires
+Through Spirits with ease; nor wonder;if by fire
+Of sooty coal the empirick alchemist
+Can turn, or holds it possible to turn,
+Metals of drossiest ore to perfect gold,
+As from the mine. Mean while at table Eve
+Ministered naked, and their flowing cups
+With pleasant liquours crowned: O innocence
+Deserving Paradise! if ever, then,
+Then had the sons of God excuse to have been
+Enamoured at that sight; but in those hearts
+Love unlibidinous reigned, nor jealousy
+Was understood, the injured lover's hell.
+Thus when with meats and drinks they had sufficed,
+Not burdened nature, sudden mind arose
+In Adam, not to let the occasion pass
+Given him by this great conference to know
+Of things above his world, and of their being
+Who dwell in Heaven, whose excellence he saw
+Transcend his own so far; whose radiant forms,
+Divine effulgence, whose high power, so far
+Exceeded human; and his wary speech
+Thus to the empyreal minister he framed.
+Inhabitant with God, now know I well
+Thy favour, in this honour done to Man;
+Under whose lowly roof thou hast vouchsafed
+To enter, and these earthly fruits to taste,
+Food not of Angels, yet accepted so,
+As that more willingly thou couldst not seem
+At Heaven's high feasts to have fed: yet what compare
+To whom the winged Hierarch replied.
+O Adam, One Almighty is, from whom
+All things proceed, and up to him return,
+If not depraved from good, created all
+Such to perfection, one first matter all,
+Endued with various forms, various degrees
+Of substance, and, in things that live, of life;
+But more refined, more spiritous, and pure,
+As nearer to him placed, or nearer tending
+Each in their several active spheres assigned,
+Till body up to spirit work, in bounds
+Proportioned to each kind. So from the root
+Springs lighter the green stalk, from thence the leaves
+More aery, last the bright consummate flower
+Spirits odorous breathes: flowers and their fruit,
+Man's nourishment, by gradual scale sublimed,
+To vital spirits aspire, to animal,
+To intellectual; give both life and sense,
+Fancy and understanding; whence the soul
+Reason receives, and reason is her being,
+Discursive, or intuitive; discourse
+Is oftest yours, the latter most is ours,
+Differing but in degree, of kind the same.
+Wonder not then, what God for you saw good
+If I refuse not, but convert, as you
+To proper substance. Time may come, when Men
+With Angels may participate, and find
+No inconvenient diet, nor too light fare;
+And from these corporal nutriments perhaps
+Your bodies may at last turn all to spirit,
+Improved by tract of time, and, winged, ascend
+Ethereal, as we; or may, at choice,
+Here or in heavenly Paradises dwell;
+If ye be found obedient, and retain
+Unalterably firm his love entire,
+Whose progeny you are. Mean while enjoy
+Your fill what happiness this happy state
+Can comprehend, incapable of more.
+To whom the patriarch of mankind replied.
+O favourable Spirit, propitious guest,
+Well hast thou taught the way that might direct
+Our knowledge, and the scale of nature set
+From center to circumference; whereon,
+In contemplation of created things,
+By steps we may ascend to God. But say,
+What meant that caution joined, If ye be found
+Obedient? Can we want obedience then
+To him, or possibly his love desert,
+Who formed us from the dust and placed us here
+Full to the utmost measure of what bliss
+Human desires can seek or apprehend?
+To whom the Angel. Son of Heaven and Earth,
+Attend! That thou art happy, owe to God;
+That thou continuest such, owe to thyself,
+That is, to thy obedience; therein stand.
+This was that caution given thee; be advised.
+God made thee perfect, not immutable;
+And good he made thee, but to persevere
+He left it in thy power; ordained thy will
+By nature free, not over-ruled by fate
+Inextricable, or strict necessity:
+Our voluntary service he requires,
+Not our necessitated; such with him
+Finds no acceptance, nor can find; for how
+Can hearts, not free, be tried whether they serve
+Willing or no, who will but what they must
+By destiny, and can no other choose?
+Myself, and all the angelick host, that stand
+In sight of God, enthroned, our happy state
+Hold, as you yours, while our obedience holds;
+On other surety none: Freely we serve,
+Because we freely love, as in our will
+To love or not; in this we stand or fall:
+And some are fallen, to disobedience fallen,
+And so from Heaven to deepest Hell; O fall
+From what high state of bliss, into what woe!
+To whom our great progenitor. Thy words
+Attentive, and with more delighted ear,
+Divine instructer, I have heard, than when
+Cherubick songs by night from neighbouring hills
+Aereal musick send: Nor knew I not
+To be both will and deed created free;
+Yet that we never shall forget to love
+Our Maker, and obey him whose command
+Single is yet so just, my constant thoughts
+Assured me, and still assure: Though what thou tellest
+Hath passed in Heaven, some doubt within me move,
+But more desire to hear, if thou consent,
+The full relation, which must needs be strange,
+Worthy of sacred silence to be heard;
+And we have yet large day, for scarce the sun
+Hath finished half his journey, and scarce begins
+His other half in the great zone of Heaven.
+Thus Adam made request; and Raphael,
+After short pause assenting, thus began.
+High matter thou enjoinest me, O prime of men,
+Sad task and hard: For how shall I relate
+To human sense the invisible exploits
+Of warring Spirits? how, without remorse,
+The ruin of so many glorious once
+And perfect while they stood? how last unfold
+The secrets of another world, perhaps
+Not lawful to reveal? yet for thy good
+This is dispensed; and what surmounts the reach
+Of human sense, I shall delineate so,
+By likening spiritual to corporal forms,
+As may express them best; though what if Earth
+Be but a shadow of Heaven, and things therein
+Each to other like, more than on earth is thought?
+As yet this world was not, and Chaos wild
+Reigned where these Heavens now roll, where Earth now rests
+Upon her center poised; when on a day
+(For time, though in eternity, applied
+To motion, measures all things durable
+By present, past, and future,) on such day
+As Heaven's great year brings forth, the empyreal host
+Of Angels by imperial summons called,
+Innumerable before the Almighty's throne
+Forthwith, from all the ends of Heaven, appeared
+Under their Hierarchs in orders bright:
+Ten thousand thousand ensigns high advanced,
+Standards and gonfalons 'twixt van and rear
+Stream in the air, and for distinction serve
+Of hierarchies, of orders, and degrees;
+Or in their glittering tissues bear imblazed
+Holy memorials, acts of zeal and love
+Recorded eminent. Thus when in orbs
+Of circuit inexpressible they stood,
+Orb within orb, the Father Infinite,
+By whom in bliss imbosomed sat the Son,
+Amidst as from a flaming mount, whose top
+Brightness had made invisible, thus spake.
+Hear, all ye Angels, progeny of light,
+Thrones, Dominations, Princedoms, Virtues, Powers;
+Hear my decree, which unrevoked shall stand.
+This day I have begot whom I declare
+My only Son, and on this holy hill
+Him have anointed, whom ye now behold
+At my right hand; your head I him appoint;
+And by myself have sworn, to him shall bow
+All knees in Heaven, and shall confess him Lord:
+Under his great vice-gerent reign abide
+United, as one individual soul,
+For ever happy: Him who disobeys,
+Me disobeys, breaks union, and that day,
+Cast out from God and blessed vision, falls
+Into utter darkness, deep ingulfed, his place
+Ordained without redemption, without end.
+So spake the Omnipotent, and with his words
+All seemed well pleased; all seemed, but were not all.
+That day, as other solemn days, they spent
+In song and dance about the sacred hill;
+Mystical dance, which yonder starry sphere
+Of planets, and of fixed, in all her wheels
+Resembles nearest, mazes intricate,
+Eccentrick, intervolved, yet regular
+Then most, when most irregular they seem;
+And in their motions harmony divine
+So smooths her charming tones, that God's own ear
+Listens delighted. Evening now approached,
+(For we have also our evening and our morn,
+We ours for change delectable, not need;)
+Forthwith from dance to sweet repast they turn
+Desirous; all in circles as they stood,
+Tables are set, and on a sudden piled
+With Angels food, and rubied nectar flows
+In pearl, in diamond, and massy gold,
+Fruit of delicious vines, the growth of Heaven.
+On flowers reposed, and with fresh flowerets crowned,
+They eat, they drink, and in communion sweet
+Quaff immortality and joy, secure
+Of surfeit, where full measure only bounds
+Excess, before the all-bounteous King, who showered
+With copious hand, rejoicing in their joy.
+Now when ambrosial night with clouds exhaled
+From that high mount of God, whence light and shade
+Spring both, the face of brightest Heaven had changed
+To grateful twilight, (for night comes not there
+In darker veil,) and roseat dews disposed
+All but the unsleeping eyes of God to rest;
+Wide over all the plain, and wider far
+Than all this globous earth in plain outspread,
+(Such are the courts of God) the angelick throng,
+Dispersed in bands and files, their camp extend
+By living streams among the trees of life,
+Pavilions numberless, and sudden reared,
+Celestial tabernacles, where they slept
+Fanned with cool winds; save those, who, in their course,
+Melodious hymns about the sovran throne
+Alternate all night long: but not so waked
+Satan; so call him now, his former name
+Is heard no more in Heaven; he of the first,
+If not the first Arch-Angel, great in power,
+In favour and pre-eminence, yet fraught
+With envy against the Son of God, that day
+Honoured by his great Father, and proclaimed
+Messiah King anointed, could not bear
+Through pride that sight, and thought himself impaired.
+Deep malice thence conceiving and disdain,
+Soon as midnight brought on the dusky hour
+Friendliest to sleep and silence, he resolved
+With all his legions to dislodge, and leave
+Unworshipt, unobeyed, the throne supreme,
+Contemptuous; and his next subordinate
+Awakening, thus to him in secret spake.
+Sleepest thou, Companion dear? What sleep can close
+Thy eye-lids? and rememberest what decree
+Of yesterday, so late hath passed the lips
+Of Heaven's Almighty. Thou to me thy thoughts
+Wast wont, I mine to thee was wont to impart;
+Both waking we were one; how then can now
+Thy sleep dissent? New laws thou seest imposed;
+New laws from him who reigns, new minds may raise
+In us who serve, new counsels to debate
+What doubtful may ensue: More in this place
+To utter is not safe. Assemble thou
+Of all those myriads which we lead the chief;
+Tell them, that by command, ere yet dim night
+Her shadowy cloud withdraws, I am to haste,
+And all who under me their banners wave,
+Homeward, with flying march, where we possess
+The quarters of the north; there to prepare
+Fit entertainment to receive our King,
+The great Messiah, and his new commands,
+Who speedily through all the hierarchies
+Intends to pass triumphant, and give laws.
+So spake the false Arch-Angel, and infused
+Bad influence into the unwary breast
+Of his associate: He together calls,
+Or several one by one, the regent Powers,
+Under him Regent; tells, as he was taught,
+That the Most High commanding, now ere night,
+Now ere dim night had disincumbered Heaven,
+The great hierarchal standard was to move;
+Tells the suggested cause, and casts between
+Ambiguous words and jealousies, to sound
+Or taint integrity: But all obeyed
+The wonted signal, and superiour voice
+Of their great Potentate; for great indeed
+His name, and high was his degree in Heaven;
+His countenance, as the morning-star that guides
+The starry flock, allured them, and with lies
+Drew after him the third part of Heaven's host.
+Mean while the Eternal eye, whose sight discerns
+Abstrusest thoughts, from forth his holy mount,
+And from within the golden lamps that burn
+Nightly before him, saw without their light
+Rebellion rising; saw in whom, how spread
+Among the sons of morn, what multitudes
+Were banded to oppose his high decree;
+And, smiling, to his only Son thus said.
+Son, thou in whom my glory I behold
+In full resplendence, Heir of all my might,
+Nearly it now concerns us to be sure
+Of our Omnipotence, and with what arms
+We mean to hold what anciently we claim
+Of deity or empire: Such a foe
+Is rising, who intends to erect his throne
+Equal to ours, throughout the spacious north;
+Nor so content, hath in his thought to try
+In battle, what our power is, or our right.
+Let us advise, and to this hazard draw
+With speed what force is left, and all employ
+In our defence; lest unawares we lose
+This our high place, our sanctuary, our hill.
+To whom the Son with calm aspect and clear,
+Lightning divine, ineffable, serene,
+Made answer. Mighty Father, thou thy foes
+Justly hast in derision, and, secure,
+Laughest at their vain designs and tumults vain,
+Matter to me of glory, whom their hate
+Illustrates, when they see all regal power
+Given me to quell their pride, and in event
+Know whether I be dextrous to subdue
+Thy rebels, or be found the worst in Heaven.
+So spake the Son; but Satan, with his Powers,
+Far was advanced on winged speed; an host
+Innumerable as the stars of night,
+Or stars of morning, dew-drops, which the sun
+Impearls on every leaf and every flower.
+Regions they passed, the mighty regencies
+Of Seraphim, and Potentates, and Thrones,
+In their triple degrees; regions to which
+All thy dominion, Adam, is no more
+Than what this garden is to all the earth,
+And all the sea, from one entire globose
+Stretched into longitude; which having passed,
+At length into the limits of the north
+They came; and Satan to his royal seat
+High on a hill, far blazing, as a mount
+Raised on a mount, with pyramids and towers
+From diamond quarries hewn, and rocks of gold;
+The palace of great Lucifer, (so call
+That structure in the dialect of men
+Interpreted,) which not long after, he
+Affecting all equality with God,
+In imitation of that mount whereon
+Messiah was declared in sight of Heaven,
+The Mountain of the Congregation called;
+For thither he assembled all his train,
+Pretending so commanded to consult
+About the great reception of their King,
+Thither to come, and with calumnious art
+Of counterfeited truth thus held their ears.
+Thrones, Dominations, Princedoms, Virtues, Powers;
+If these magnifick titles yet remain
+Not merely titular, since by decree
+Another now hath to himself engrossed
+All power, and us eclipsed under the name
+Of King anointed, for whom all this haste
+Of midnight-march, and hurried meeting here,
+This only to consult how we may best,
+With what may be devised of honours new,
+Receive him coming to receive from us
+Knee-tribute yet unpaid, prostration vile!
+Too much to one! but double how endured,
+To one, and to his image now proclaimed?
+But what if better counsels might erect
+Our minds, and teach us to cast off this yoke?
+Will ye submit your necks, and choose to bend
+The supple knee? Ye will not, if I trust
+To know ye right, or if ye know yourselves
+Natives and sons of Heaven possessed before
+By none; and if not equal all, yet free,
+Equally free; for orders and degrees
+Jar not with liberty, but well consist.
+Who can in reason then, or right, assume
+Monarchy over such as live by right
+His equals, if in power and splendour less,
+In freedom equal? or can introduce
+Law and edict on us, who without law
+Err not? much less for this to be our Lord,
+And look for adoration, to the abuse
+Of those imperial titles, which assert
+Our being ordained to govern, not to serve.
+Thus far his bold discourse without controul
+Had audience; when among the Seraphim
+Abdiel, than whom none with more zeal adored
+The Deity, and divine commands obeyed,
+Stood up, and in a flame of zeal severe
+The current of his fury thus opposed.
+O argument blasphemous, false, and proud!
+Words which no ear ever to hear in Heaven
+Expected, least of all from thee, Ingrate,
+In place thyself so high above thy peers.
+Canst thou with impious obloquy condemn
+The just decree of God, pronounced and sworn,
+That to his only Son, by right endued
+With regal scepter, every soul in Heaven
+Shall bend the knee, and in that honour due
+Confess him rightful King? unjust, thou sayest,
+Flatly unjust, to bind with laws the free,
+And equal over equals to let reign,
+One over all with unsucceeded power.
+Shalt thou give law to God? shalt thou dispute
+With him the points of liberty, who made
+Thee what thou art, and formed the Powers of Heaven
+Such as he pleased, and circumscribed their being?
+Yet, by experience taught, we know how good,
+And of our good and of our dignity
+How provident he is; how far from thought
+To make us less, bent rather to exalt
+Our happy state, under one head more near
+United. But to grant it thee unjust,
+That equal over equals monarch reign:
+Thyself, though great and glorious, dost thou count,
+Or all angelick nature joined in one,
+Equal to him begotten Son? by whom,
+As by his Word, the Mighty Father made
+All things, even thee; and all the Spirits of Heaven
+By him created in their bright degrees,
+Crowned them with glory, and to their glory named
+Thrones, Dominations, Princedoms, Virtues, Powers,
+Essential Powers; nor by his reign obscured,
+But more illustrious made; since he the head
+One of our number thus reduced becomes;
+His laws our laws; all honour to him done
+Returns our own. Cease then this impious rage,
+And tempt not these; but hasten to appease
+The incensed Father, and the incensed Son,
+While pardon may be found in time besought.
+So spake the fervent Angel; but his zeal
+None seconded, as out of season judged,
+Or singular and rash: Whereat rejoiced
+The Apostate, and, more haughty, thus replied.
+That we were formed then sayest thou? and the work
+Of secondary hands, by task transferred
+From Father to his Son? strange point and new!
+Doctrine which we would know whence learned: who saw
+When this creation was? rememberest thou
+Thy making, while the Maker gave thee being?
+We know no time when we were not as now;
+Know none before us, self-begot, self-raised
+By our own quickening power, when fatal course
+Had circled his full orb, the birth mature
+Of this our native Heaven, ethereal sons.
+Our puissance is our own; our own right hand
+Shall teach us highest deeds, by proof to try
+Who is our equal: Then thou shalt behold
+Whether by supplication we intend
+Address, and to begirt the almighty throne
+Beseeching or besieging. This report,
+These tidings carry to the anointed King;
+And fly, ere evil intercept thy flight.
+He said; and, as the sound of waters deep,
+Hoarse murmur echoed to his words applause
+Through the infinite host; nor less for that
+The flaming Seraph fearless, though alone
+Encompassed round with foes, thus answered bold.
+O alienate from God, O Spirit accursed,
+Forsaken of all good! I see thy fall
+Determined, and thy hapless crew involved
+In this perfidious fraud, contagion spread
+Both of thy crime and punishment: Henceforth
+No more be troubled how to quit the yoke
+Of God's Messiah; those indulgent laws
+Will not be now vouchsafed; other decrees
+Against thee are gone forth without recall;
+That golden scepter, which thou didst reject,
+Is now an iron rod to bruise and break
+Thy disobedience. Well thou didst advise;
+Yet not for thy advice or threats I fly
+These wicked tents devoted, lest the wrath
+Impendent, raging into sudden flame,
+Distinguish not: For soon expect to feel
+His thunder on thy head, devouring fire.
+Then who created thee lamenting learn,
+When who can uncreate thee thou shalt know.
+So spake the Seraph Abdiel, faithful found
+Among the faithless, faithful only he;
+Among innumerable false, unmoved,
+Unshaken, unseduced, unterrified,
+His loyalty he kept, his love, his zeal;
+Nor number, nor example, with him wrought
+To swerve from truth, or change his constant mind,
+Though single. From amidst them forth he passed,
+Long way through hostile scorn, which he sustained
+Superiour, nor of violence feared aught;
+And, with retorted scorn, his back he turned
+On those proud towers to swift destruction doomed.
+
+
+
+Book VI
+
+
+All night the dreadless Angel, unpursued,
+Through Heaven's wide champain held his way; till Morn,
+Waked by the circling Hours, with rosy hand
+Unbarred the gates of light. There is a cave
+Within the mount of God, fast by his throne,
+Where light and darkness in perpetual round
+Lodge and dislodge by turns, which makes through Heaven
+Grateful vicissitude, like day and night;
+Light issues forth, and at the other door
+Obsequious darkness enters, till her hour
+To veil the Heaven, though darkness there might well
+Seem twilight here: And now went forth the Morn
+Such as in highest Heaven arrayed in gold
+Empyreal; from before her vanished Night,
+Shot through with orient beams; when all the plain
+Covered with thick embattled squadrons bright,
+Chariots, and flaming arms, and fiery steeds,
+Reflecting blaze on blaze, first met his view:
+War he perceived, war in procinct; and found
+Already known what he for news had thought
+To have reported: Gladly then he mixed
+Among those friendly Powers, who him received
+With joy and acclamations loud, that one,
+That of so many myriads fallen, yet one
+Returned not lost. On to the sacred hill
+They led him high applauded, and present
+Before the seat supreme; from whence a voice,
+From midst a golden cloud, thus mild was heard.
+Servant of God. Well done; well hast thou fought
+The better fight, who single hast maintained
+Against revolted multitudes the cause
+Of truth, in word mightier than they in arms;
+And for the testimony of truth hast borne
+Universal reproach, far worse to bear
+Than violence; for this was all thy care
+To stand approved in sight of God, though worlds
+Judged thee perverse: The easier conquest now
+Remains thee, aided by this host of friends,
+Back on thy foes more glorious to return,
+Than scorned thou didst depart; and to subdue
+By force, who reason for their law refuse,
+Right reason for their law, and for their King
+Messiah, who by right of merit reigns.
+Go, Michael, of celestial armies prince,
+And thou, in military prowess next,
+Gabriel, lead forth to battle these my sons
+Invincible; lead forth my armed Saints,
+By thousands and by millions, ranged for fight,
+Equal in number to that Godless crew
+Rebellious: Them with fire and hostile arms
+Fearless assault; and, to the brow of Heaven
+Pursuing, drive them out from God and bliss,
+Into their place of punishment, the gulf
+Of Tartarus, which ready opens wide
+His fiery Chaos to receive their fall.
+So spake the Sovran Voice, and clouds began
+To darken all the hill, and smoke to roll
+In dusky wreaths, reluctant flames, the sign
+Of wrath awaked; nor with less dread the loud
+Ethereal trumpet from on high 'gan blow:
+At which command the Powers militant,
+That stood for Heaven, in mighty quadrate joined
+Of union irresistible, moved on
+In silence their bright legions, to the sound
+Of instrumental harmony, that breathed
+Heroick ardour to adventurous deeds
+Under their God-like leaders, in the cause
+Of God and his Messiah. On they move
+Indissolubly firm; nor obvious hill,
+Nor straitening vale, nor wood, nor stream, divides
+Their perfect ranks; for high above the ground
+Their march was, and the passive air upbore
+Their nimble tread; as when the total kind
+Of birds, in orderly array on wing,
+Came summoned over Eden to receive
+Their names of thee; so over many a tract
+Of Heaven they marched, and many a province wide,
+Tenfold the length of this terrene: At last,
+Far in the horizon to the north appeared
+From skirt to skirt a fiery region, stretched
+In battailous aspect, and nearer view
+Bristled with upright beams innumerable
+Of rigid spears, and helmets thronged, and shields
+Various, with boastful argument portrayed,
+The banded Powers of Satan hasting on
+With furious expedition; for they weened
+That self-same day, by fight or by surprise,
+To win the mount of God, and on his throne
+To set the Envier of his state, the proud
+Aspirer; but their thoughts proved fond and vain
+In the mid way: Though strange to us it seemed
+At first, that Angel should with Angel war,
+And in fierce hosting meet, who wont to meet
+So oft in festivals of joy and love
+Unanimous, as sons of one great Sire,
+Hymning the Eternal Father: But the shout
+Of battle now began, and rushing sound
+Of onset ended soon each milder thought.
+High in the midst, exalted as a God,
+The Apostate in his sun-bright chariot sat,
+Idol of majesty divine, enclosed
+With flaming Cherubim, and golden shields;
+Then lighted from his gorgeous throne, for now
+"twixt host and host but narrow space was left,
+A dreadful interval, and front to front
+Presented stood in terrible array
+Of hideous length: Before the cloudy van,
+On the rough edge of battle ere it joined,
+Satan, with vast and haughty strides advanced,
+Came towering, armed in adamant and gold;
+Abdiel that sight endured not, where he stood
+Among the mightiest, bent on highest deeds,
+And thus his own undaunted heart explores.
+O Heaven! that such resemblance of the Highest
+Should yet remain, where faith and realty
+Remain not: Wherefore should not strength and might
+There fail where virtue fails, or weakest prove
+Where boldest, though to fight unconquerable?
+His puissance, trusting in the Almighty's aid,
+I mean to try, whose reason I have tried
+Unsound and false; nor is it aught but just,
+That he, who in debate of truth hath won,
+Should win in arms, in both disputes alike
+Victor; though brutish that contest and foul,
+When reason hath to deal with force, yet so
+Most reason is that reason overcome.
+So pondering, and from his armed peers
+Forth stepping opposite, half-way he met
+His daring foe, at this prevention more
+Incensed, and thus securely him defied.
+Proud, art thou met? thy hope was to have reached
+The highth of thy aspiring unopposed,
+The throne of God unguarded, and his side
+Abandoned, at the terrour of thy power
+Or potent tongue: Fool!not to think how vain
+Against the Omnipotent to rise in arms;
+Who out of smallest things could, without end,
+Have raised incessant armies to defeat
+Thy folly; or with solitary hand
+Reaching beyond all limit, at one blow,
+Unaided, could have finished thee, and whelmed
+Thy legions under darkness: But thou seest
+All are not of thy train; there be, who faith
+Prefer, and piety to God, though then
+To thee not visible, when I alone
+Seemed in thy world erroneous to dissent
+From all: My sect thou seest;now learn too late
+How few sometimes may know, when thousands err.
+Whom the grand foe, with scornful eye askance,
+Thus answered. Ill for thee, but in wished hour
+Of my revenge, first sought for, thou returnest
+From flight, seditious Angel! to receive
+Thy merited reward, the first assay
+Of this right hand provoked, since first that tongue,
+Inspired with contradiction, durst oppose
+A third part of the Gods, in synod met
+Their deities to assert; who, while they feel
+Vigour divine within them, can allow
+Omnipotence to none. But well thou comest
+Before thy fellows, ambitious to win
+From me some plume, that thy success may show
+Destruction to the rest: This pause between,
+(Unanswered lest thou boast) to let thee know,
+At first I thought that Liberty and Heaven
+To heavenly souls had been all one; but now
+I see that most through sloth had rather serve,
+Ministring Spirits, trained up in feast and song!
+Such hast thou armed, the minstrelsy of Heaven,
+Servility with freedom to contend,
+As both their deeds compared this day shall prove.
+To whom in brief thus Abdiel stern replied.
+Apostate! still thou errest, nor end wilt find
+Of erring, from the path of truth remote:
+Unjustly thou depravest it with the name
+Of servitude, to serve whom God ordains,
+Or Nature: God and Nature bid the same,
+When he who rules is worthiest, and excels
+Them whom he governs. This is servitude,
+To serve the unwise, or him who hath rebelled
+Against his worthier, as thine now serve thee,
+Thyself not free, but to thyself enthralled;
+Yet lewdly darest our ministring upbraid.
+Reign thou in Hell, thy kingdom; let me serve
+In Heaven God ever blest, and his divine
+Behests obey, worthiest to be obeyed;
+Yet chains in Hell, not realms, expect: Mean while
+From me returned, as erst thou saidst, from flight,
+This greeting on thy impious crest receive.
+So saying, a noble stroke he lifted high,
+Which hung not, but so swift with tempest fell
+On the proud crest of Satan, that no sight,
+Nor motion of swift thought, less could his shield,
+Such ruin intercept: Ten paces huge
+He back recoiled; the tenth on bended knee
+His massy spear upstaid; as if on earth
+Winds under ground, or waters forcing way,
+Sidelong had pushed a mountain from his seat,
+Half sunk with all his pines. Amazement seised
+The rebel Thrones, but greater rage, to see
+Thus foiled their mightiest; ours joy filled, and shout,
+Presage of victory, and fierce desire
+Of battle: Whereat Michael bid sound
+The Arch-Angel trumpet; through the vast of Heaven
+It sounded, and the faithful armies rung
+Hosanna to the Highest: Nor stood at gaze
+The adverse legions, nor less hideous joined
+The horrid shock. Now storming fury rose,
+And clamour such as heard in Heaven till now
+Was never; arms on armour clashing brayed
+Horrible discord, and the madding wheels
+Of brazen chariots raged; dire was the noise
+Of conflict; over head the dismal hiss
+Of fiery darts in flaming vollies flew,
+And flying vaulted either host with fire.
+So under fiery cope together rushed
+Both battles main, with ruinous assault
+And inextinguishable rage. All Heaven
+Resounded; and had Earth been then, all Earth
+Had to her center shook. What wonder? when
+Millions of fierce encountering Angels fought
+On either side, the least of whom could wield
+These elements, and arm him with the force
+Of all their regions: How much more of power
+Army against army numberless to raise
+Dreadful combustion warring, and disturb,
+Though not destroy, their happy native seat;
+Had not the Eternal King Omnipotent,
+From his strong hold of Heaven, high over-ruled
+And limited their might; though numbered such
+As each divided legion might have seemed
+A numerous host; in strength each armed hand
+A legion; led in fight, yet leader seemed
+Each warriour single as in chief, expert
+When to advance, or stand, or turn the sway
+Of battle, open when, and when to close
+The ridges of grim war: No thought of flight,
+None of retreat, no unbecoming deed
+That argued fear; each on himself relied,
+As only in his arm the moment lay
+Of victory: Deeds of eternal fame
+Were done, but infinite; for wide was spread
+That war and various; sometimes on firm ground
+A standing fight, then, soaring on main wing,
+Tormented all the air; all air seemed then
+Conflicting fire. Long time in even scale
+The battle hung; till Satan, who that day
+Prodigious power had shown, and met in arms
+No equal, ranging through the dire attack
+Of fighting Seraphim confused, at length
+Saw where the sword of Michael smote, and felled
+Squadrons at once; with huge two-handed sway
+Brandished aloft, the horrid edge came down
+Wide-wasting; such destruction to withstand
+He hasted, and opposed the rocky orb
+Of tenfold adamant, his ample shield,
+A vast circumference. At his approach
+The great Arch-Angel from his warlike toil
+Surceased, and glad, as hoping here to end
+Intestine war in Heaven, the arch-foe subdued
+Or captive dragged in chains, with hostile frown
+And visage all inflamed first thus began.
+Author of evil, unknown till thy revolt,
+Unnamed in Heaven, now plenteous as thou seest
+These acts of hateful strife, hateful to all,
+Though heaviest by just measure on thyself,
+And thy adherents: How hast thou disturbed
+Heaven's blessed peace, and into nature brought
+Misery, uncreated till the crime
+Of thy rebellion! how hast thou instilled
+Thy malice into thousands, once upright
+And faithful, now proved false! But think not here
+To trouble holy rest; Heaven casts thee out
+From all her confines. Heaven, the seat of bliss,
+Brooks not the works of violence and war.
+Hence then, and evil go with thee along,
+Thy offspring, to the place of evil, Hell;
+Thou and thy wicked crew! there mingle broils,
+Ere this avenging sword begin thy doom,
+Or some more sudden vengeance, winged from God,
+Precipitate thee with augmented pain.
+So spake the Prince of Angels; to whom thus
+The Adversary. Nor think thou with wind
+Of aery threats to awe whom yet with deeds
+Thou canst not. Hast thou turned the least of these
+To flight, or if to fall, but that they rise
+Unvanquished, easier to transact with me
+That thou shouldst hope, imperious, and with threats
+To chase me hence? err not, that so shall end
+The strife which thou callest evil, but we style
+The strife of glory; which we mean to win,
+Or turn this Heaven itself into the Hell
+Thou fablest; here however to dwell free,
+If not to reign: Mean while thy utmost force,
+And join him named Almighty to thy aid,
+I fly not, but have sought thee far and nigh.
+They ended parle, and both addressed for fight
+Unspeakable; for who, though with the tongue
+Of Angels, can relate, or to what things
+Liken on earth conspicuous, that may lift
+Human imagination to such highth
+Of Godlike power? for likest Gods they seemed,
+Stood they or moved, in stature, motion, arms,
+Fit to decide the empire of great Heaven.
+Now waved their fiery swords, and in the air
+Made horrid circles; two broad suns their shields
+Blazed opposite, while Expectation stood
+In horrour: From each hand with speed retired,
+Where erst was thickest fight, the angelick throng,
+And left large field, unsafe within the wind
+Of such commotion; such as, to set forth
+Great things by small, if, nature's concord broke,
+Among the constellations war were sprung,
+Two planets, rushing from aspect malign
+Of fiercest opposition, in mid sky
+Should combat, and their jarring spheres confound.
+Together both with next to almighty arm
+Up-lifted imminent, one stroke they aimed
+That might determine, and not need repeat,
+As not of power at once; nor odds appeared
+In might or swift prevention: But the sword
+Of Michael from the armoury of God
+Was given him tempered so, that neither keen
+Nor solid might resist that edge: it met
+The sword of Satan, with steep force to smite
+Descending, and in half cut sheer; nor staid,
+But with swift wheel reverse, deep entering, shared
+All his right side: Then Satan first knew pain,
+And writhed him to and fro convolved; so sore
+The griding sword with discontinuous wound
+Passed through him: But the ethereal substance closed,
+Not long divisible; and from the gash
+A stream of necturous humour issuing flowed
+Sanguine, such as celestial Spirits may bleed,
+And all his armour stained, ere while so bright.
+Forthwith on all sides to his aid was run
+By Angels many and strong, who interposed
+Defence, while others bore him on their shields
+Back to his chariot, where it stood retired
+From off the files of war: There they him laid
+Gnashing for anguish, and despite, and shame,
+To find himself not matchless, and his pride
+Humbled by such rebuke, so far beneath
+His confidence to equal God in power.
+Yet soon he healed; for Spirits that live throughout
+Vital in every part, not as frail man
+In entrails, heart of head, liver or reins,
+Cannot but by annihilating die;
+Nor in their liquid texture mortal wound
+Receive, no more than can the fluid air:
+All heart they live, all head, all eye, all ear,
+All intellect, all sense; and, as they please,
+They limb themselves, and colour, shape, or size
+Assume, as?kikes them best, condense or rare.
+Mean while in other parts like deeds deserved
+Memorial, where the might of Gabriel fought,
+And with fierce ensigns pierced the deep array
+Of Moloch, furious king; who him defied,
+And at his chariot-wheels to drag him bound
+Threatened, nor from the Holy One of Heaven
+Refrained his tongue blasphemous; but anon
+Down cloven to the waist, with shattered arms
+And uncouth pain fled bellowing. On each wing
+Uriel, and Raphael, his vaunting foe,
+Though huge, and in a rock of diamond armed,
+Vanquished Adramelech, and Asmadai,
+Two potent Thrones, that to be less than Gods
+Disdained, but meaner thoughts learned in their flight,
+Mangled with ghastly wounds through plate and mail.
+Nor stood unmindful Abdiel to annoy
+The atheist crew, but with redoubled blow
+Ariel, and Arioch, and the violence
+Of Ramiel scorched and blasted, overthrew.
+I might relate of thousands, and their names
+Eternize here on earth; but those elect
+Angels, contented with their fame in Heaven,
+Seek not the praise of men: The other sort,
+In might though wonderous and in acts of war,
+Nor of renown less eager, yet by doom
+Cancelled from Heaven and sacred memory,
+Nameless in dark oblivion let them dwell.
+For strength from truth divided, and from just,
+Illaudable, nought merits but dispraise
+And ignominy; yet to glory aspires
+Vain-glorious, and through infamy seeks fame:
+Therefore eternal silence be their doom.
+And now, their mightiest quelled, the battle swerved,
+With many an inroad gored; deformed rout
+Entered, and foul disorder; all the ground
+With shivered armour strown, and on a heap
+Chariot and charioteer lay overturned,
+And fiery-foaming steeds; what stood, recoiled
+O'er-wearied, through the faint Satanick host
+Defensive scarce, or with pale fear surprised,
+Then first with fear surprised, and sense of pain,
+Fled ignominious, to such evil brought
+By sin of disobedience; till that hour
+Not liable to fear, or flight, or pain.
+Far otherwise the inviolable Saints,
+In cubick phalanx firm, advanced entire,
+Invulnerable, impenetrably armed;
+Such high advantages their innocence
+Gave them above their foes; not to have sinned,
+Not to have disobeyed; in fight they stood
+Unwearied, unobnoxious to be pained
+By wound, though from their place by violence moved,
+Now Night her course began, and, over Heaven
+Inducing darkness, grateful truce imposed,
+And silence on the odious din of war:
+Under her cloudy covert both retired,
+Victor and vanquished: On the foughten field
+Michael and his Angels prevalent
+Encamping, placed in guard their watches round,
+Cherubick waving fires: On the other part,
+Satan with his rebellious disappeared,
+Far in the dark dislodged; and, void of rest,
+His potentates to council called by night;
+And in the midst thus undismayed began.
+O now in danger tried, now known in arms
+Not to be overpowered, Companions dear,
+Found worthy not of liberty alone,
+Too mean pretence! but what we more affect,
+Honour, dominion, glory, and renown;
+Who have sustained one day in doubtful fight,
+(And if one day, why not eternal days?)
+What Heaven's Lord had powerfullest to send
+Against us from about his throne, and judged
+Sufficient to subdue us to his will,
+But proves not so: Then fallible, it seems,
+Of future we may deem him, though till now
+Omniscient thought. True is, less firmly armed,
+Some disadvantage we endured and pain,
+Till now not known, but, known, as soon contemned;
+Since now we find this our empyreal form
+Incapable of mortal injury,
+Imperishable, and, though pierced with wound,
+Soon closing, and by native vigour healed.
+Of evil then so small as easy think
+The remedy; perhaps more valid arms,
+Weapons more violent, when next we meet,
+May serve to better us, and worse our foes,
+Or equal what between us made the odds,
+In nature none: If other hidden cause
+Left them superiour, while we can preserve
+Unhurt our minds, and understanding sound,
+Due search and consultation will disclose.
+He sat; and in the assembly next upstood
+Nisroch, of Principalities the prime;
+As one he stood escaped from cruel fight,
+Sore toiled, his riven arms to havock hewn,
+And cloudy in aspect thus answering spake.
+Deliverer from new Lords, leader to free
+Enjoyment of our right as Gods; yet hard
+For Gods, and too unequal work we find,
+Against unequal arms to fight in pain,
+Against unpained, impassive; from which evil
+Ruin must needs ensue; for what avails
+Valour or strength, though matchless, quelled with pain
+Which all subdues, and makes remiss the hands
+Of mightiest? Sense of pleasure we may well
+Spare out of life perhaps, and not repine,
+But live content, which is the calmest life:
+But pain is perfect misery, the worst
+Of evils, and, excessive, overturns
+All patience. He, who therefore can invent
+With what more forcible we may offend
+Our yet unwounded enemies, or arm
+Ourselves with like defence, to me deserves
+No less than for deliverance what we owe.
+Whereto with look composed Satan replied.
+Not uninvented that, which thou aright
+Believest so main to our success, I bring.
+Which of us who beholds the bright surface
+Of this ethereous mould whereon we stand,
+This continent of spacious Heaven, adorned
+With plant, fruit, flower ambrosial, gems, and gold;
+Whose eye so superficially surveys
+These things, as not to mind from whence they grow
+Deep under ground, materials dark and crude,
+Of spiritous and fiery spume, till touched
+With Heaven's ray, and tempered, they shoot forth
+So beauteous, opening to the ambient light?
+These in their dark nativity the deep
+Shall yield us, pregnant with infernal flame;
+Which, into hollow engines, long and round,
+Thick rammed, at the other bore with touch of fire
+Dilated and infuriate, shall send forth
+From far, with thundering noise, among our foes
+Such implements of mischief, as shall dash
+To pieces, and o'erwhelm whatever stands
+Adverse, that they shall fear we have disarmed
+The Thunderer of his only dreaded bolt.
+Nor long shall be our labour; yet ere dawn,
+Effect shall end our wish. Mean while revive;
+Abandon fear; to strength and counsel joined
+Think nothing hard, much less to be despaired.
+He ended, and his words their drooping cheer
+Enlightened, and their languished hope revived.
+The invention all admired, and each, how he
+To be the inventer missed; so easy it seemed
+Once found, which yet unfound most would have thought
+Impossible: Yet, haply, of thy race
+In future days, if malice should abound,
+Some one intent on mischief, or inspired
+With devilish machination, might devise
+Like instrument to plague the sons of men
+For sin, on war and mutual slaughter bent.
+Forthwith from council to the work they flew;
+None arguing stood; innumerable hands
+Were ready; in a moment up they turned
+Wide the celestial soil, and saw beneath
+The originals of nature in their crude
+Conception; sulphurous and nitrous foam
+They found, they mingled, and, with subtle art,
+Concocted and adusted they reduced
+To blackest grain, and into store conveyed:
+Part hidden veins digged up (nor hath this earth
+Entrails unlike) of mineral and stone,
+Whereof to found their engines and their balls
+Of missive ruin; part incentive reed
+Provide, pernicious with one touch to fire.
+So all ere day-spring, under conscious night,
+Secret they finished, and in order set,
+With silent circumspection, unespied.
+Now when fair morn orient in Heaven appeared,
+Up rose the victor-Angels, and to arms
+The matin trumpet sung: In arms they stood
+Of golden panoply, refulgent host,
+Soon banded; others from the dawning hills
+Look round, and scouts each coast light-armed scour,
+Each quarter to descry the distant foe,
+Where lodged, or whither fled, or if for fight,
+In motion or in halt: Him soon they met
+Under spread ensigns moving nigh, in slow
+But firm battalion; back with speediest sail
+Zophiel, of Cherubim the swiftest wing,
+Came flying, and in mid air aloud thus cried.
+Arm, Warriours, arm for fight; the foe at hand,
+Whom fled we thought, will save us long pursuit
+This day; fear not his flight;so thick a cloud
+He comes, and settled in his face I see
+Sad resolution, and secure: Let each
+His adamantine coat gird well, and each
+Fit well his helm, gripe fast his orbed shield,
+Borne even or high; for this day will pour down,
+If I conjecture aught, no drizzling shower,
+But rattling storm of arrows barbed with fire.
+So warned he them, aware themselves, and soon
+In order, quit of all impediment;
+Instant without disturb they took alarm,
+And onward moved embattled: When behold!
+Not distant far with heavy pace the foe
+Approaching gross and huge, in hollow cube
+Training his devilish enginery, impaled
+On every side with shadowing squadrons deep,
+To hide the fraud. At interview both stood
+A while; but suddenly at head appeared
+Satan, and thus was heard commanding loud.
+Vanguard, to right and left the front unfold;
+That all may see who hate us, how we seek
+Peace and composure, and with open breast
+Stand ready to receive them, if they like
+Our overture; and turn not back perverse:
+But that I doubt; however witness, Heaven!
+Heaven, witness thou anon! while we discharge
+Freely our part: ye, who appointed stand
+Do as you have in charge, and briefly touch
+What we propound, and loud that all may hear!
+So scoffing in ambiguous words, he scarce
+Had ended; when to right and left the front
+Divided, and to either flank retired:
+Which to our eyes discovered, new and strange,
+A triple mounted row of pillars laid
+On wheels (for like to pillars most they seemed,
+Or hollowed bodies made of oak or fir,
+With branches lopt, in wood or mountain felled,)
+Brass, iron, stony mould, had not their mouths
+With hideous orifice gaped on us wide,
+Portending hollow truce: At each behind
+A Seraph stood, and in his hand a reed
+Stood waving tipt with fire; while we, suspense,
+Collected stood within our thoughts amused,
+Not long; for sudden all at once their reeds
+Put forth, and to a narrow vent applied
+With nicest touch. Immediate in a flame,
+But soon obscured with smoke, all Heaven appeared,
+From those deep-throated engines belched, whose roar
+Embowelled with outrageous noise the air,
+And all her entrails tore, disgorging foul
+Their devilish glut, chained thunderbolts and hail
+Of iron globes; which, on the victor host
+Levelled, with such impetuous fury smote,
+That, whom they hit, none on their feet might stand,
+Though standing else as rocks, but down they fell
+By thousands, Angel on Arch-Angel rolled;
+The sooner for their arms; unarmed, they might
+Have easily, as Spirits, evaded swift
+By quick contraction or remove; but now
+Foul dissipation followed, and forced rout;
+Nor served it to relax their serried files.
+What should they do? if on they rushed, repulse
+Repeated, and indecent overthrow
+Doubled, would render them yet more despised,
+And to their foes a laughter; for in view
+Stood ranked of Seraphim another row,
+In posture to displode their second tire
+Of thunder: Back defeated to return
+They worse abhorred. Satan beheld their plight,
+And to his mates thus in derision called.
+O Friends! why come not on these victors proud
+Ere while they fierce were coming; and when we,
+To entertain them fair with open front
+And breast, (what could we more?) propounded terms
+Of composition, straight they changed their minds,
+Flew off, and into strange vagaries fell,
+As they would dance; yet for a dance they seemed
+Somewhat extravagant and wild; perhaps
+For joy of offered peace: But I suppose,
+If our proposals once again were heard,
+We should compel them to a quick result.
+To whom thus Belial, in like gamesome mood.
+Leader! the terms we sent were terms of weight,
+Of hard contents, and full of force urged home;
+Such as we might perceive amused them all,
+And stumbled many: Who receives them right,
+Had need from head to foot well understand;
+Not understood, this gift they have besides,
+They show us when our foes walk not upright.
+So they among themselves in pleasant vein
+Stood scoffing, hightened in their thoughts beyond
+All doubt of victory: Eternal Might
+To match with their inventions they presumed
+So easy, and of his thunder made a scorn,
+And all his host derided, while they stood
+A while in trouble: But they stood not long;
+Rage prompted them at length, and found them arms
+Against such hellish mischief fit to oppose.
+Forthwith (behold the excellence, the power,
+Which God hath in his mighty Angels placed!)
+Their arms away they threw, and to the hills
+(For Earth hath this variety from Heaven
+Of pleasure situate in hill and dale,)
+Light as the lightning glimpse they ran, they flew;
+From their foundations loosening to and fro,
+They plucked the seated hills, with all their load,
+Rocks, waters, woods, and by the shaggy tops
+Up-lifting bore them in their hands: Amaze,
+Be sure, and terrour, seized the rebel host,
+When coming towards them so dread they saw
+The bottom of the mountains upward turned;
+Till on those cursed engines' triple-row
+They saw them whelmed, and all their confidence
+Under the weight of mountains buried deep;
+Themselves invaded next, and on their heads
+Main promontories flung, which in the air
+Came shadowing, and oppressed whole legions armed;
+Their armour helped their harm, crushed in and bruised
+Into their substance pent, which wrought them pain
+Implacable, and many a dolorous groan;
+Long struggling underneath, ere they could wind
+Out of such prison, though Spirits of purest light,
+Purest at first, now gross by sinning grown.
+The rest, in imitation, to like arms
+Betook them, and the neighbouring hills uptore:
+So hills amid the air encountered hills,
+Hurled to and fro with jaculation dire;
+That under ground they fought in dismal shade;
+Infernal noise! war seemed a civil game
+To this uproar; horrid confusion heaped
+Upon confusion rose: And now all Heaven
+Had gone to wrack, with ruin overspread;
+Had not the Almighty Father, where he sits
+Shrined in his sanctuary of Heaven secure,
+Consulting on the sum of things, foreseen
+This tumult, and permitted all, advised:
+That his great purpose he might so fulfil,
+To honour his anointed Son avenged
+Upon his enemies, and to declare
+All power on him transferred: Whence to his Son,
+The Assessour of his throne, he thus began.
+Effulgence of my glory, Son beloved,
+Son, in whose face invisible is beheld
+Visibly, what by Deity I am;
+And in whose hand what by decree I do,
+Second Omnipotence! two days are past,
+Two days, as we compute the days of Heaven,
+Since Michael and his Powers went forth to tame
+These disobedient: Sore hath been their fight,
+As likeliest was, when two such foes met armed;
+For to themselves I left them; and thou knowest,
+Equal in their creation they were formed,
+Save what sin hath impaired; which yet hath wrought
+Insensibly, for I suspend their doom;
+Whence in perpetual fight they needs must last
+Endless, and no solution will be found:
+War wearied hath performed what war can do,
+And to disordered rage let loose the reins
+With mountains, as with weapons, armed; which makes
+Wild work in Heaven, and dangerous to the main.
+Two days are therefore past, the third is thine;
+For thee I have ordained it; and thus far
+Have suffered, that the glory may be thine
+Of ending this great war, since none but Thou
+Can end it. Into thee such virtue and grace
+Immense I have transfused, that all may know
+In Heaven and Hell thy power above compare;
+And, this perverse commotion governed thus,
+To manifest thee worthiest to be Heir
+Of all things; to be Heir, and to be King
+By sacred unction, thy deserved right.
+Go then, Thou Mightiest, in thy Father's might;
+Ascend my chariot, guide the rapid wheels
+That shake Heaven's basis, bring forth all my war,
+My bow and thunder, my almighty arms
+Gird on, and sword upon thy puissant thigh;
+Pursue these sons of darkness, drive them out
+From all Heaven's bounds into the utter deep:
+There let them learn, as likes them, to despise
+God, and Messiah his anointed King.
+He said, and on his Son with rays direct
+Shone full; he all his Father full expressed
+Ineffably into his face received;
+And thus the Filial Godhead answering spake.
+O Father, O Supreme of heavenly Thrones,
+First, Highest, Holiest, Best; thou always seek'st
+To glorify thy Son, I always thee,
+As is most just: This I my glory account,
+My exaltation, and my whole delight,
+That thou, in me well pleased, declarest thy will
+Fulfilled, which to fulfil is all my bliss.
+Scepter and power, thy giving, I assume,
+And gladlier shall resign, when in the end
+Thou shalt be all in all, and I in thee
+For ever; and in me all whom thou lovest:
+But whom thou hatest, I hate, and can put on
+Thy terrours, as I put thy mildness on,
+Image of thee in all things; and shall soon,
+Armed with thy might, rid Heaven of these rebelled;
+To their prepared ill mansion driven down,
+To chains of darkness, and the undying worm;
+That from thy just obedience could revolt,
+Whom to obey is happiness entire.
+Then shall thy Saints unmixed, and from the impure
+Far separate, circling thy holy mount,
+Unfeigned Halleluiahs to thee sing,
+Hymns of high praise, and I among them Chief.
+So said, he, o'er his scepter bowing, rose
+From the right hand of Glory where he sat;
+And the third sacred morn began to shine,
+Dawning through Heaven. Forth rushed with whirlwind sound
+The chariot of Paternal Deity,
+Flashing thick flames, wheel within wheel undrawn,
+Itself instinct with Spirit, but convoyed
+By four Cherubick shapes; four faces each
+Had wonderous; as with stars, their bodies all
+And wings were set with eyes; with eyes the wheels
+Of beryl, and careering fires between;
+Over their heads a crystal firmament,
+Whereon a sapphire throne, inlaid with pure
+Amber, and colours of the showery arch.
+He, in celestial panoply all armed
+Of radiant Urim, work divinely wrought,
+Ascended; at his right hand Victory
+Sat eagle-winged; beside him hung his bow
+And quiver with three-bolted thunder stored;
+And from about him fierce effusion rolled
+Of smoke, and bickering flame, and sparkles dire:
+Attended with ten thousand thousand Saints,
+He onward came; far off his coming shone;
+And twenty thousand (I their number heard)
+Chariots of God, half on each hand, were seen;
+He on the wings of Cherub rode sublime
+On the crystalline sky, in sapphire throned,
+Illustrious far and wide; but by his own
+First seen: Them unexpected joy surprised,
+When the great ensign of Messiah blazed
+Aloft by Angels borne, his sign in Heaven;
+Under whose conduct Michael soon reduced
+His army, circumfused on either wing,
+Under their Head imbodied all in one.
+Before him Power Divine his way prepared;
+At his command the uprooted hills retired
+Each to his place; they heard his voice, and went
+Obsequious; Heaven his wonted face renewed,
+And with fresh flowerets hill and valley smiled.
+This saw his hapless foes, but stood obdured,
+And to rebellious fight rallied their Powers,
+Insensate, hope conceiving from despair.
+In heavenly Spirits could such perverseness dwell?
+But to convince the proud what signs avail,
+Or wonders move the obdurate to relent?
+They, hardened more by what might most reclaim,
+Grieving to see his glory, at the sight
+Took envy; and, aspiring to his highth,
+Stood re-embattled fierce, by force or fraud
+Weening to prosper, and at length prevail
+Against God and Messiah, or to fall
+In universal ruin last; and now
+To final battle drew, disdaining flight,
+Or faint retreat; when the great Son of God
+To all his host on either hand thus spake.
+Stand still in bright array, ye Saints; here stand,
+Ye Angels armed; this day from battle rest:
+Faithful hath been your warfare, and of God
+Accepted, fearless in his righteous cause;
+And as ye have received, so have ye done,
+Invincibly: But of this cursed crew
+The punishment to other hand belongs;
+Vengeance is his, or whose he sole appoints:
+Number to this day's work is not ordained,
+Nor multitude; stand only, and behold
+God's indignation on these godless poured
+By me; not you, but me, they have despised,
+Yet envied; against me is all their rage,
+Because the Father, to whom in Heaven s'preme
+Kingdom, and power, and glory appertains,
+Hath honoured me, according to his will.
+Therefore to me their doom he hath assigned;
+That they may have their wish, to try with me
+In battle which the stronger proves; they all,
+Or I alone against them; since by strength
+They measure all, of other excellence
+Not emulous, nor care who them excels;
+Nor other strife with them do I vouchsafe.
+So spake the Son, and into terrour changed
+His countenance too severe to be beheld,
+And full of wrath bent on his enemies.
+At once the Four spread out their starry wings
+With dreadful shade contiguous, and the orbs
+Of his fierce chariot rolled, as with the sound
+Of torrent floods, or of a numerous host.
+He on his impious foes right onward drove,
+Gloomy as night; under his burning wheels
+The stedfast empyrean shook throughout,
+All but the throne itself of God. Full soon
+Among them he arrived; in his right hand
+Grasping ten thousand thunders, which he sent
+Before him, such as in their souls infixed
+Plagues: They, astonished, all resistance lost,
+All courage; down their idle weapons dropt:
+O'er shields, and helms, and helmed heads he rode
+Of Thrones and mighty Seraphim prostrate,
+That wished the mountains now might be again
+Thrown on them, as a shelter from his ire.
+Nor less on either side tempestuous fell
+His arrows, from the fourfold-visaged Four
+Distinct with eyes, and from the living wheels
+Distinct alike with multitude of eyes;
+One Spirit in them ruled; and every eye
+Glared lightning, and shot forth pernicious fire
+Among the accursed, that withered all their strength,
+And of their wonted vigour left them drained,
+Exhausted, spiritless, afflicted, fallen.
+Yet half his strength he put not forth, but checked
+His thunder in mid volley; for he meant
+Not to destroy, but root them out of Heaven:
+The overthrown he raised, and as a herd
+Of goats or timorous flock together thronged
+Drove them before him thunder-struck, pursued
+With terrours, and with furies, to the bounds
+And crystal wall of Heaven; which, opening wide,
+Rolled inward, and a spacious gap disclosed
+Into the wasteful deep: The monstrous sight
+Struck them with horrour backward, but far worse
+Urged them behind: Headlong themselves they threw
+Down from the verge of Heaven; eternal wrath
+Burnt after them to the bottomless pit.
+Hell heard the unsufferable noise, Hell saw
+Heaven ruining from Heaven, and would have fled
+Affrighted; but strict Fate had cast too deep
+Her dark foundations, and too fast had bound.
+Nine days they fell: Confounded Chaos roared,
+And felt tenfold confusion in their fall
+Through his wild anarchy, so huge a rout
+Incumbered him with ruin: Hell at last
+Yawning received them whole, and on them closed;
+Hell, their fit habitation, fraught with fire
+Unquenchable, the house of woe and pain.
+Disburdened Heaven rejoiced, and soon repaired
+Her mural breach, returning whence it rolled.
+Sole victor, from the expulsion of his foes,
+Messiah his triumphal chariot turned:
+To meet him all his Saints, who silent stood
+Eye-witnesses of his almighty acts,
+With jubilee advanced; and, as they went,
+Shaded with branching palm, each Order bright,
+Sung triumph, and him sung victorious King,
+Son, Heir, and Lord, to him dominion given,
+Worthiest to reign: He, celebrated, rode
+Triumphant through mid Heaven, into the courts
+And temple of his Mighty Father throned
+On high; who into glory him received,
+Where now he sits at the right hand of bliss.
+Thus, measuring things in Heaven by things on Earth,
+At thy request, and that thou mayest beware
+By what is past, to thee I have revealed
+What might have else to human race been hid;
+The discord which befel, and war in Heaven
+Among the angelick Powers, and the deep fall
+Of those too high aspiring, who rebelled
+With Satan; he who envies now thy state,
+Who now is plotting how he may seduce
+Thee also from obedience, that, with him
+Bereaved of happiness, thou mayest partake
+His punishment, eternal misery;
+Which would be all his solace and revenge,
+As a despite done against the Most High,
+Thee once to gain companion of his woe.
+But listen not to his temptations, warn
+Thy weaker; let it profit thee to have heard,
+By terrible example, the reward
+Of disobedience; firm they might have stood,
+Yet fell; remember, and fear to transgress.
+
+
+
+Book VII
+
+
+Descend from Heaven, Urania, by that name
+If rightly thou art called, whose voice divine
+Following, above the Olympian hill I soar,
+Above the flight of Pegasean wing!
+The meaning, not the name, I call: for thou
+Nor of the Muses nine, nor on the top
+Of old Olympus dwellest; but, heavenly-born,
+Before the hills appeared, or fountain flowed,
+Thou with eternal Wisdom didst converse,
+Wisdom thy sister, and with her didst play
+In presence of the Almighty Father, pleased
+With thy celestial song. Up led by thee
+Into the Heaven of Heavens I have presumed,
+An earthly guest, and drawn empyreal air,
+Thy tempering: with like safety guided down
+Return me to my native element:
+Lest from this flying steed unreined, (as once
+Bellerophon, though from a lower clime,)
+Dismounted, on the Aleian field I fall,
+Erroneous there to wander, and forlorn.
+Half yet remains unsung, but narrower bound
+Within the visible diurnal sphere;
+Standing on earth, not rapt above the pole,
+More safe I sing with mortal voice, unchanged
+To hoarse or mute, though fallen on evil days,
+On evil days though fallen, and evil tongues;
+In darkness, and with dangers compassed round,
+And solitude; yet not alone, while thou
+Visitest my slumbers nightly, or when morn
+Purples the east: still govern thou my song,
+Urania, and fit audience find, though few.
+But drive far off the barbarous dissonance
+Of Bacchus and his revellers, the race
+Of that wild rout that tore the Thracian bard
+In Rhodope, where woods and rocks had ears
+To rapture, till the savage clamour drowned
+Both harp and voice; nor could the Muse defend
+Her son. So fail not thou, who thee implores:
+For thou art heavenly, she an empty dream.
+Say, Goddess, what ensued when Raphael,
+The affable Arch-Angel, had forewarned
+Adam, by dire example, to beware
+Apostasy, by what befel in Heaven
+To those apostates; lest the like befall
+In Paradise to Adam or his race,
+Charged not to touch the interdicted tree,
+If they transgress, and slight that sole command,
+So easily obeyed amid the choice
+Of all tastes else to please their appetite,
+Though wandering. He, with his consorted Eve,
+The story heard attentive, and was filled
+With admiration and deep muse, to hear
+Of things so high and strange; things, to their thought
+So unimaginable, as hate in Heaven,
+And war so near the peace of God in bliss,
+With such confusion: but the evil, soon
+Driven back, redounded as a flood on those
+From whom it sprung; impossible to mix
+With blessedness. Whence Adam soon repealed
+The doubts that in his heart arose: and now
+Led on, yet sinless, with desire to know
+What nearer might concern him, how this world
+Of Heaven and Earth conspicuous first began;
+When, and whereof created; for what cause;
+What within Eden, or without, was done
+Before his memory; as one whose drouth
+Yet scarce allayed still eyes the current stream,
+Whose liquid murmur heard new thirst excites,
+Proceeded thus to ask his heavenly guest.
+Great things, and full of wonder in our ears,
+Far differing from this world, thou hast revealed,
+Divine interpreter! by favour sent
+Down from the empyrean, to forewarn
+Us timely of what might else have been our loss,
+Unknown, which human knowledge could not reach;
+For which to the infinitely Good we owe
+Immortal thanks, and his admonishment
+Receive, with solemn purpose to observe
+Immutably his sovran will, the end
+Of what we are. But since thou hast vouchsafed
+Gently, for our instruction, to impart
+Things above earthly thought, which yet concerned
+Our knowing, as to highest wisdom seemed,
+Deign to descend now lower, and relate
+What may no less perhaps avail us known,
+How first began this Heaven which we behold
+Distant so high, with moving fires adorned
+Innumerable; and this which yields or fills
+All space, the ambient air wide interfused
+Embracing round this floried Earth; what cause
+Moved the Creator, in his holy rest
+Through all eternity, so late to build
+In Chaos; and the work begun, how soon
+Absolved; if unforbid thou mayest unfold
+What we, not to explore the secrets ask
+Of his eternal empire, but the more
+To magnify his works, the more we know.
+And the great light of day yet wants to run
+Much of his race though steep; suspense in Heaven,
+Held by thy voice, thy potent voice, he hears,
+And longer will delay to hear thee tell
+His generation, and the rising birth
+Of Nature from the unapparent Deep:
+Or if the star of evening and the moon
+Haste to thy audience, Night with her will bring,
+Silence; and Sleep, listening to thee, will watch;
+Or we can bid his absence, till thy song
+End, and dismiss thee ere the morning shine.
+Thus Adam his illustrious guest besought:
+And thus the Godlike Angel answered mild.
+This also thy request, with caution asked,
+Obtain; though to recount almighty works
+What words or tongue of Seraph can suffice,
+Or heart of man suffice to comprehend?
+Yet what thou canst attain, which best may serve
+To glorify the Maker, and infer
+Thee also happier, shall not be withheld
+Thy hearing; such commission from above
+I have received, to answer thy desire
+Of knowledge within bounds; beyond, abstain
+To ask; nor let thine own inventions hope
+Things not revealed, which the invisible King,
+Only Omniscient, hath suppressed in night;
+To none communicable in Earth or Heaven:
+Enough is left besides to search and know.
+But knowledge is as food, and needs no less
+Her temperance over appetite, to know
+In measure what the mind may well contain;
+Oppresses else with surfeit, and soon turns
+Wisdom to folly, as nourishment to wind.
+Know then, that, after Lucifer from Heaven
+(So call him, brighter once amidst the host
+Of Angels, than that star the stars among,)
+Fell with his flaming legions through the deep
+Into his place, and the great Son returned
+Victorious with his Saints, the Omnipotent
+Eternal Father from his throne beheld
+Their multitude, and to his Son thus spake.
+At least our envious Foe hath failed, who thought
+All like himself rebellious, by whose aid
+This inaccessible high strength, the seat
+Of Deity supreme, us dispossessed,
+He trusted to have seised, and into fraud
+Drew many, whom their place knows here no more:
+Yet far the greater part have kept, I see,
+Their station; Heaven, yet populous, retains
+Number sufficient to possess her realms
+Though wide, and this high temple to frequent
+With ministeries due, and solemn rites:
+But, lest his heart exalt him in the harm
+Already done, to have dispeopled Heaven,
+My damage fondly deemed, I can repair
+That detriment, if such it be to lose
+Self-lost; and in a moment will create
+Another world, out of one man a race
+Of men innumerable, there to dwell,
+Not here; till, by degrees of merit raised,
+They open to themselves at length the way
+Up hither, under long obedience tried;
+And Earth be changed to Heaven, and Heaven to Earth,
+One kingdom, joy and union without end.
+Mean while inhabit lax, ye Powers of Heaven;
+And thou my Word, begotten Son, by thee
+This I perform; speak thou, and be it done!
+My overshadowing Spirit and Might with thee
+I send along; ride forth, and bid the Deep
+Within appointed bounds be Heaven and Earth;
+Boundless the Deep, because I Am who fill
+Infinitude, nor vacuous the space.
+Though I, uncircumscribed myself, retire,
+And put not forth my goodness, which is free
+To act or not, Necessity and Chance
+Approach not me, and what I will is Fate.
+So spake the Almighty, and to what he spake
+His Word, the Filial Godhead, gave effect.
+Immediate are the acts of God, more swift
+Than time or motion, but to human ears
+Cannot without process of speech be told,
+So told as earthly notion can receive.
+Great triumph and rejoicing was in Heaven,
+When such was heard declared the Almighty's will;
+Glory they sung to the Most High, good will
+To future men, and in their dwellings peace;
+Glory to Him, whose just avenging ire
+Had driven out the ungodly from his sight
+And the habitations of the just; to Him
+Glory and praise, whose wisdom had ordained
+Good out of evil to create; instead
+Of Spirits malign, a better race to bring
+Into their vacant room, and thence diffuse
+His good to worlds and ages infinite.
+So sang the Hierarchies: Mean while the Son
+On his great expedition now appeared,
+Girt with Omnipotence, with radiance crowned
+Of Majesty Divine; sapience and love
+Immense, and all his Father in him shone.
+About his chariot numberless were poured
+Cherub, and Seraph, Potentates, and Thrones,
+And Virtues, winged Spirits, and chariots winged
+From the armoury of God; where stand of old
+Myriads, between two brazen mountains lodged
+Against a solemn day, harnessed at hand,
+Celestial equipage; and now came forth
+Spontaneous, for within them Spirit lived,
+Attendant on their Lord: Heaven opened wide
+Her ever-during gates, harmonious sound
+On golden hinges moving, to let forth
+The King of Glory, in his powerful Word
+And Spirit, coming to create new worlds.
+On heavenly ground they stood; and from the shore
+They viewed the vast immeasurable abyss
+Outrageous as a sea, dark, wasteful, wild,
+Up from the bottom turned by furious winds
+And surging waves, as mountains, to assault
+Heaven's highth, and with the center mix the pole.
+Silence, ye troubled Waves, and thou Deep, peace,
+Said then the Omnifick Word; your discord end!
+Nor staid; but, on the wings of Cherubim
+Uplifted, in paternal glory rode
+Far into Chaos, and the world unborn;
+For Chaos heard his voice: Him all his train
+Followed in bright procession, to behold
+Creation, and the wonders of his might.
+Then staid the fervid wheels, and in his hand
+He took the golden compasses, prepared
+In God's eternal store, to circumscribe
+This universe, and all created things:
+One foot he centered, and the other turned
+Round through the vast profundity obscure;
+And said, Thus far extend, thus far thy bounds,
+This be thy just circumference, O World!
+Thus God the Heaven created, thus the Earth,
+Matter unformed and void: Darkness profound
+Covered the abyss: but on the watery calm
+His brooding wings the Spirit of God outspread,
+And vital virtue infused, and vital warmth
+Throughout the fluid mass; but downward purged
+The black tartareous cold infernal dregs,
+Adverse to life: then founded, then conglobed
+Like things to like; the rest to several place
+Disparted, and between spun out the air;
+And Earth self-balanced on her center hung.
+Let there be light, said God; and forthwith Light
+Ethereal, first of things, quintessence pure,
+Sprung from the deep; and from her native east
+To journey through the aery gloom began,
+Sphered in a radiant cloud, for yet the sun
+Was not; she in a cloudy tabernacle
+Sojourned the while. God saw the light was good;
+And light from darkness by the hemisphere
+Divided: light the Day, and darkness Night,
+He named. Thus was the first day even and morn:
+Nor past uncelebrated, nor unsung
+By the celestial quires, when orient light
+Exhaling first from darkness they beheld;
+Birth-day of Heaven and Earth; with joy and shout
+The hollow universal orb they filled,
+And touched their golden harps, and hymning praised
+God and his works; Creator him they sung,
+Both when first evening was, and when first morn.
+Again, God said, Let there be firmament
+Amid the waters, and let it divide
+The waters from the waters; and God made
+The firmament, expanse of liquid, pure,
+Transparent, elemental air, diffused
+In circuit to the uttermost convex
+Of this great round; partition firm and sure,
+The waters underneath from those above
+Dividing: for as earth, so he the world
+Built on circumfluous waters calm, in wide
+Crystalline ocean, and the loud misrule
+Of Chaos far removed; lest fierce extremes
+Contiguous might distemper the whole frame:
+And Heaven he named the Firmament: So even
+And morning chorus sung the second day.
+The Earth was formed, but in the womb as yet
+Of waters, embryon immature involved,
+Appeared not: over all the face of Earth
+Main ocean flowed, not idle; but, with warm
+Prolifick humour softening all her globe,
+Fermented the great mother to conceive,
+Satiate with genial moisture; when God said,
+Be gathered now ye waters under Heaven
+Into one place, and let dry land appear.
+Immediately the mountains huge appear
+Emergent, and their broad bare backs upheave
+Into the clouds; their tops ascend the sky:
+So high as heaved the tumid hills, so low
+Down sunk a hollow bottom broad and deep,
+Capacious bed of waters: Thither they
+Hasted with glad precipitance, uprolled,
+As drops on dust conglobing from the dry:
+Part rise in crystal wall, or ridge direct,
+For haste; such flight the great command impressed
+On the swift floods: As armies at the call
+Of trumpet (for of armies thou hast heard)
+Troop to their standard; so the watery throng,
+Wave rolling after wave, where way they found,
+If steep, with torrent rapture, if through plain,
+Soft-ebbing; nor withstood them rock or hill;
+But they, or under ground, or circuit wide
+With serpent errour wandering, found their way,
+And on the washy oose deep channels wore;
+Easy, ere God had bid the ground be dry,
+All but within those banks, where rivers now
+Stream, and perpetual draw their humid train.
+The dry land, Earth; and the great receptacle
+Of congregated waters, he called Seas:
+And saw that it was good; and said, Let the Earth
+Put forth the verdant grass, herb yielding seed,
+And fruit-tree yielding fruit after her kind,
+Whose seed is in herself upon the Earth.
+He scarce had said, when the bare Earth, till then
+Desart and bare, unsightly, unadorned,
+Brought forth the tender grass, whose verdure clad
+Her universal face with pleasant green;
+Then herbs of every leaf, that sudden flowered
+Opening their various colours, and made gay
+Her bosom, smelling sweet: and, these scarce blown,
+Forth flourished thick the clustering vine, forth crept
+The swelling gourd, up stood the corny reed
+Embattled in her field, and the humble shrub,
+And bush with frizzled hair implicit: Last
+Rose, as in dance, the stately trees, and spread
+Their branches hung with copious fruit, or gemmed
+Their blossoms: With high woods the hills were crowned;
+With tufts the valleys, and each fountain side;
+With borders long the rivers: that Earth now
+Seemed like to Heaven, a seat where Gods might dwell,
+Or wander with delight, and love to haunt
+Her sacred shades: though God had yet not rained
+Upon the Earth, and man to till the ground
+None was; but from the Earth a dewy mist
+Went up, and watered all the ground, and each
+Plant of the field; which, ere it was in the Earth,
+God made, and every herb, before it grew
+On the green stem: God saw that it was good:
+So even and morn recorded the third day.
+Again the Almighty spake, Let there be lights
+High in the expanse of Heaven, to divide
+The day from night; and let them be for signs,
+For seasons, and for days, and circling years;
+And let them be for lights, as I ordain
+Their office in the firmament of Heaven,
+To give light on the Earth; and it was so.
+And God made two great lights, great for their use
+To Man, the greater to have rule by day,
+The less by night, altern; and made the stars,
+And set them in the firmament of Heaven
+To illuminate the Earth, and rule the day
+In their vicissitude, and rule the night,
+And light from darkness to divide. God saw,
+Surveying his great work, that it was good:
+For of celestial bodies first the sun
+A mighty sphere he framed, unlightsome first,
+Though of ethereal mould: then formed the moon
+Globose, and every magnitude of stars,
+And sowed with stars the Heaven, thick as a field:
+Of light by far the greater part he took,
+Transplanted from her cloudy shrine, and placed
+In the sun's orb, made porous to receive
+And drink the liquid light; firm to retain
+Her gathered beams, great palace now of light.
+Hither, as to their fountain, other stars
+Repairing, in their golden urns draw light,
+And hence the morning-planet gilds her horns;
+By tincture or reflection they augment
+Their small peculiar, though from human sight
+So far remote, with diminution seen,
+First in his east the glorious lamp was seen,
+Regent of day, and all the horizon round
+Invested with bright rays, jocund to run
+His longitude through Heaven's high road; the gray
+Dawn, and the Pleiades, before him danced,
+Shedding sweet influence: Less bright the moon,
+But opposite in levelled west was set,
+His mirrour, with full face borrowing her light
+From him; for other light she needed none
+In that aspect, and still that distance keeps
+Till night; then in the east her turn she shines,
+Revolved on Heaven's great axle, and her reign
+With thousand lesser lights dividual holds,
+With thousand thousand stars, that then appeared
+Spangling the hemisphere: Then first adorned
+With their bright luminaries that set and rose,
+Glad evening and glad morn crowned the fourth day.
+And God said, Let the waters generate
+Reptile with spawn abundant, living soul:
+And let fowl fly above the Earth, with wings
+Displayed on the open firmament of Heaven.
+And God created the great whales, and each
+Soul living, each that crept, which plenteously
+The waters generated by their kinds;
+And every bird of wing after his kind;
+And saw that it was good, and blessed them, saying.
+Be fruitful, multiply, and in the seas,
+And lakes, and running streams, the waters fill;
+And let the fowl be multiplied, on the Earth.
+Forthwith the sounds and seas, each creek and bay,
+With fry innumerable swarm, and shoals
+Of fish that with their fins, and shining scales,
+Glide under the green wave, in sculls that oft
+Bank the mid sea: part single, or with mate,
+Graze the sea-weed their pasture, and through groves
+Of coral stray; or, sporting with quick glance,
+Show to the sun their waved coats dropt with gold;
+Or, in their pearly shells at ease, attend
+Moist nutriment; or under rocks their food
+In jointed armour watch: on smooth the seal
+And bended dolphins play: part huge of bulk
+Wallowing unwieldy, enormous in their gait,
+Tempest the ocean: there leviathan,
+Hugest of living creatures, on the deep
+Stretched like a promontory sleeps or swims,
+And seems a moving land; and at his gills
+Draws in, and at his trunk spouts out, a sea.
+Mean while the tepid caves, and fens, and shores,
+Their brood as numerous hatch, from the egg that soon
+Bursting with kindly rupture forth disclosed
+Their callow young; but feathered soon and fledge
+They summed their pens; and, soaring the air sublime,
+With clang despised the ground, under a cloud
+In prospect; there the eagle and the stork
+On cliffs and cedar tops their eyries build:
+Part loosely wing the region, part more wise
+In common, ranged in figure, wedge their way,
+Intelligent of seasons, and set forth
+Their aery caravan, high over seas
+Flying, and over lands, with mutual wing
+Easing their flight; so steers the prudent crane
+Her annual voyage, borne on winds; the air
+Floats as they pass, fanned with unnumbered plumes:
+From branch to branch the smaller birds with song
+Solaced the woods, and spread their painted wings
+Till even; nor then the solemn nightingale
+Ceased warbling, but all night tun'd her soft lays:
+Others, on silver lakes and rivers, bathed
+Their downy breast; the swan with arched neck,
+Between her white wings mantling proudly, rows
+Her state with oary feet; yet oft they quit
+The dank, and, rising on stiff pennons, tower
+The mid aereal sky: Others on ground
+Walked firm; the crested cock whose clarion sounds
+The silent hours, and the other whose gay train
+Adorns him, coloured with the florid hue
+Of rainbows and starry eyes. The waters thus
+With fish replenished, and the air with fowl,
+Evening and morn solemnized the fifth day.
+The sixth, and of creation last, arose
+With evening harps and matin; when God said,
+Let the Earth bring forth soul living in her kind,
+Cattle, and creeping things, and beast of the Earth,
+Each in their kind. The Earth obeyed, and straight
+Opening her fertile womb teemed at a birth
+Innumerous living creatures, perfect forms,
+Limbed and full grown: Out of the ground up rose,
+As from his lair, the wild beast where he wons
+In forest wild, in thicket, brake, or den;
+Among the trees in pairs they rose, they walked:
+The cattle in the fields and meadows green:
+Those rare and solitary, these in flocks
+Pasturing at once, and in broad herds upsprung.
+The grassy clods now calved; now half appeared
+The tawny lion, pawing to get free
+His hinder parts, then springs as broke from bonds,
+And rampant shakes his brinded mane; the ounce,
+The libbard, and the tiger, as the mole
+Rising, the crumbled earth above them threw
+In hillocks: The swift stag from under ground
+Bore up his branching head: Scarce from his mould
+Behemoth biggest born of earth upheaved
+His vastness: Fleeced the flocks and bleating rose,
+As plants: Ambiguous between sea and land
+The river-horse, and scaly crocodile.
+At once came forth whatever creeps the ground,
+Insect or worm: those waved their limber fans
+For wings, and smallest lineaments exact
+In all the liveries decked of summer's pride
+With spots of gold and purple, azure and green:
+These, as a line, their long dimension drew,
+Streaking the ground with sinuous trace; not all
+Minims of nature; some of serpent-kind,
+Wonderous in length and corpulence, involved
+Their snaky folds, and added wings. First crept
+The parsimonious emmet, provident
+Of future; in small room large heart enclosed;
+Pattern of just equality perhaps
+Hereafter, joined in her popular tribes
+Of commonalty: Swarming next appeared
+The female bee, that feeds her husband drone
+Deliciously, and builds her waxen cells
+With honey stored: The rest are numberless,
+And thou their natures knowest, and gavest them names,
+Needless to thee repeated; nor unknown
+The serpent, subtlest beast of all the field,
+Of huge extent sometimes, with brazen eyes
+And hairy mane terrifick, though to thee
+Not noxious, but obedient at thy call.
+Now Heaven in all her glory shone, and rolled
+Her motions, as the great first Mover's hand
+First wheeled their course: Earth in her rich attire
+Consummate lovely smiled; air, water, earth,
+By fowl, fish, beast, was flown, was swum, was walked,
+Frequent; and of the sixth day yet remained:
+There wanted yet the master-work, the end
+Of all yet done; a creature, who, not prone
+And brute as other creatures, but endued
+With sanctity of reason, might erect
+His stature, and upright with front serene
+Govern the rest, self-knowing; and from thence
+Magnanimous to correspond with Heaven,
+But grateful to acknowledge whence his good
+Descends, thither with heart, and voice, and eyes
+Directed in devotion, to adore
+And worship God Supreme, who made him chief
+Of all his works: therefore the Omnipotent
+Eternal Father (for where is not he
+Present?) thus to his Son audibly spake.
+Let us make now Man in our image, Man
+In our similitude, and let them rule
+Over the fish and fowl of sea and air,
+Beast of the field, and over all the Earth,
+And every creeping thing that creeps the ground.
+This said, he formed thee, Adam, thee, O Man,
+Dust of the ground, and in thy nostrils breathed
+The breath of life; in his own image he
+Created thee, in the image of God
+Express; and thou becamest a living soul.
+Male he created thee; but thy consort
+Female, for race; then blessed mankind, and said,
+Be fruitful, multiply, and fill the Earth;
+Subdue it, and throughout dominion hold
+Over fish of the sea, and fowl of the air,
+And every living thing that moves on the Earth.
+Wherever thus created, for no place
+Is yet distinct by name, thence, as thou knowest,
+He brought thee into this delicious grove,
+This garden, planted with the trees of God,
+Delectable both to behold and taste;
+And freely all their pleasant fruit for food
+Gave thee; all sorts are here that all the Earth yields,
+Variety without end; but of the tree,
+Which, tasted, works knowledge of good and evil,
+Thou mayest not; in the day thou eatest, thou diest;
+Death is the penalty imposed; beware,
+And govern well thy appetite; lest Sin
+Surprise thee, and her black attendant Death.
+Here finished he, and all that he had made
+Viewed, and behold all was entirely good;
+So even and morn accomplished the sixth day:
+Yet not till the Creator from his work
+Desisting, though unwearied, up returned,
+Up to the Heaven of Heavens, his high abode;
+Thence to behold this new created world,
+The addition of his empire, how it showed
+In prospect from his throne, how good, how fair,
+Answering his great idea. Up he rode
+Followed with acclamation, and the sound
+Symphonious of ten thousand harps, that tuned
+Angelick harmonies: The earth, the air
+Resounded, (thou rememberest, for thou heardst,)
+The heavens and all the constellations rung,
+The planets in their station listening stood,
+While the bright pomp ascended jubilant.
+Open, ye everlasting gates! they sung,
+Open, ye Heavens! your living doors;let in
+The great Creator from his work returned
+Magnificent, his six days work, a World;
+Open, and henceforth oft; for God will deign
+To visit oft the dwellings of just men,
+Delighted; and with frequent intercourse
+Thither will send his winged messengers
+On errands of supernal grace. So sung
+The glorious train ascending: He through Heaven,
+That opened wide her blazing portals, led
+To God's eternal house direct the way;
+A broad and ample road, whose dust is gold
+And pavement stars, as stars to thee appear,
+Seen in the galaxy, that milky way,
+Which nightly, as a circling zone, thou seest
+Powdered with stars. And now on Earth the seventh
+Evening arose in Eden, for the sun
+Was set, and twilight from the east came on,
+Forerunning night; when at the holy mount
+Of Heaven's high-seated top, the imperial throne
+Of Godhead, fixed for ever firm and sure,
+The Filial Power arrived, and sat him down
+With his great Father; for he also went
+Invisible, yet staid, (such privilege
+Hath Omnipresence) and the work ordained,
+Author and End of all things; and, from work
+Now resting, blessed and hallowed the seventh day,
+As resting on that day from all his work,
+But not in silence holy kept: the harp
+Had work and rested not; the solemn pipe,
+And dulcimer, all organs of sweet stop,
+All sounds on fret by string or golden wire,
+Tempered soft tunings, intermixed with voice
+Choral or unison: of incense clouds,
+Fuming from golden censers, hid the mount.
+Creation and the six days acts they sung:
+Great are thy works, Jehovah! infinite
+Thy power! what thought can measure thee, or tongue
+Relate thee! Greater now in thy return
+Than from the giant Angels: Thee that day
+Thy thunders magnified; but to create
+Is greater than created to destroy.
+Who can impair thee, Mighty King, or bound
+Thy empire! Easily the proud attempt
+Of Spirits apostate, and their counsels vain,
+Thou hast repelled; while impiously they thought
+Thee to diminish, and from thee withdraw
+The number of thy worshippers. Who seeks
+To lessen thee, against his purpose serves
+To manifest the more thy might: his evil
+Thou usest, and from thence createst more good.
+Witness this new-made world, another Heaven
+From Heaven-gate not far, founded in view
+On the clear hyaline, the glassy sea;
+Of amplitude almost immense, with stars
+Numerous, and every star perhaps a world
+Of destined habitation; but thou knowest
+Their seasons: among these the seat of Men,
+Earth, with her nether ocean circumfused,
+Their pleasant dwelling-place. Thrice happy Men,
+And sons of Men, whom God hath thus advanced!
+Created in his image, there to dwell
+And worship him; and in reward to rule
+Over his works, on earth, in sea, or air,
+And multiply a race of worshippers
+Holy and just: Thrice happy, if they know
+Their happiness, and persevere upright!
+So sung they, and the empyrean rung
+With halleluiahs: Thus was sabbath kept.
+And thy request think now fulfilled, that asked
+How first this world and face of things began,
+And what before thy memory was done
+From the beginning; that posterity,
+Informed by thee, might know: If else thou seekest
+Aught, not surpassing human measure, say.
+
+
+
+Book VIII
+
+
+The Angel ended, and in Adam's ear
+So charming left his voice, that he a while
+Thought him still speaking, still stood fixed to hear;
+Then, as new waked, thus gratefully replied.
+What thanks sufficient, or what recompence
+Equal, have I to render thee, divine
+Historian, who thus largely hast allayed
+The thirst I had of knowledge, and vouchsafed
+This friendly condescension to relate
+Things, else by me unsearchable; now heard
+With wonder, but delight, and, as is due,
+With glory attributed to the high
+Creator! Something yet of doubt remains,
+Which only thy solution can resolve.
+When I behold this goodly frame, this world,
+Of Heaven and Earth consisting; and compute
+Their magnitudes; this Earth, a spot, a grain,
+An atom, with the firmament compared
+And all her numbered stars, that seem to roll
+Spaces incomprehensible, (for such
+Their distance argues, and their swift return
+Diurnal,) merely to officiate light
+Round this opacous Earth, this punctual spot,
+One day and night; in all her vast survey
+Useless besides; reasoning I oft admire,
+How Nature wise and frugal could commit
+Such disproportions, with superfluous hand
+So many nobler bodies to create,
+Greater so manifold, to this one use,
+For aught appears, and on their orbs impose
+Such restless revolution day by day
+Repeated; while the sedentary Earth,
+That better might with far less compass move,
+Served by more noble than herself, attains
+Her end without least motion, and receives,
+As tribute, such a sumless journey brought
+Of incorporeal speed, her warmth and light;
+Speed, to describe whose swiftness number fails.
+So spake our sire, and by his countenance seemed
+Entering on studious thoughts abstruse; which Eve
+Perceiving, where she sat retired in sight,
+With lowliness majestick from her seat,
+And grace that won who saw to wish her stay,
+Rose, and went forth among her fruits and flowers,
+To visit how they prospered, bud and bloom,
+Her nursery; they at her coming sprung,
+And, touched by her fair tendance, gladlier grew.
+Yet went she not, as not with such discourse
+Delighted, or not capable her ear
+Of what was high: such pleasure she reserved,
+Adam relating, she sole auditress;
+Her husband the relater she preferred
+Before the Angel, and of him to ask
+Chose rather; he, she knew, would intermix
+Grateful digressions, and solve high dispute
+With conjugal caresses: from his lip
+Not words alone pleased her. O! when meet now
+Such pairs, in love and mutual honour joined?
+With Goddess-like demeanour forth she went,
+Not unattended; for on her, as Queen,
+A pomp of winning Graces waited still,
+And from about her shot darts of desire
+Into all eyes, to wish her still in sight.
+And Raphael now, to Adam's doubt proposed,
+Benevolent and facile thus replied.
+To ask or search, I blame thee not; for Heaven
+Is as the book of God before thee set,
+Wherein to read his wonderous works, and learn
+His seasons, hours, or days, or months, or years:
+This to attain, whether Heaven move or Earth,
+Imports not, if thou reckon right; the rest
+From Man or Angel the great Architect
+Did wisely to conceal, and not divulge
+His secrets to be scanned by them who ought
+Rather admire; or, if they list to try
+Conjecture, he his fabrick of the Heavens
+Hath left to their disputes, perhaps to move
+His laughter at their quaint opinions wide
+Hereafter; when they come to model Heaven
+And calculate the stars, how they will wield
+The mighty frame; how build, unbuild, contrive
+To save appearances; how gird the sphere
+With centrick and eccentrick scribbled o'er,
+Cycle and epicycle, orb in orb:
+Already by thy reasoning this I guess,
+Who art to lead thy offspring, and supposest
+That bodies bright and greater should not serve
+The less not bright, nor Heaven such journeys run,
+Earth sitting still, when she alone receives
+The benefit: Consider first, that great
+Or bright infers not excellence: the Earth
+Though, in comparison of Heaven, so small,
+Nor glistering, may of solid good contain
+More plenty than the sun that barren shines;
+Whose virtue on itself works no effect,
+But in the fruitful Earth; there first received,
+His beams, unactive else, their vigour find.
+Yet not to Earth are those bright luminaries
+Officious; but to thee, Earth's habitant.
+And for the Heaven's wide circuit, let it speak
+The Maker's high magnificence, who built
+So spacious, and his line stretched out so far;
+That Man may know he dwells not in his own;
+An edifice too large for him to fill,
+Lodged in a small partition; and the rest
+Ordained for uses to his Lord best known.
+The swiftness of those circles attribute,
+Though numberless, to his Omnipotence,
+That to corporeal substances could add
+Speed almost spiritual: Me thou thinkest not slow,
+Who since the morning-hour set out from Heaven
+Where God resides, and ere mid-day arrived
+In Eden; distance inexpressible
+By numbers that have name. But this I urge,
+Admitting motion in the Heavens, to show
+Invalid that which thee to doubt it moved;
+Not that I so affirm, though so it seem
+To thee who hast thy dwelling here on Earth.
+God, to remove his ways from human sense,
+Placed Heaven from Earth so far, that earthly sight,
+If it presume, might err in things too high,
+And no advantage gain. What if the sun
+Be center to the world; and other stars,
+By his attractive virtue and their own
+Incited, dance about him various rounds?
+Their wandering course now high, now low, then hid,
+Progressive, retrograde, or standing still,
+In six thou seest; and what if seventh to these
+The planet earth, so stedfast though she seem,
+Insensibly three different motions move?
+Which else to several spheres thou must ascribe,
+Moved contrary with thwart obliquities;
+Or save the sun his labour, and that swift
+Nocturnal and diurnal rhomb supposed,
+Invisible else above all stars, the wheel
+Of day and night; which needs not thy belief,
+If earth, industrious of herself, fetch day
+Travelling east, and with her part averse
+From the sun's beam meet night, her other part
+Still luminous by his ray. What if that light,
+Sent from her through the wide transpicuous air,
+To the terrestrial moon be as a star,
+Enlightening her by day, as she by night
+This earth? reciprocal, if land be there,
+Fields and inhabitants: Her spots thou seest
+As clouds, and clouds may rain, and rain produce
+Fruits in her softened soil for some to eat
+Allotted there; and other suns perhaps,
+With their attendant moons, thou wilt descry,
+Communicating male and female light;
+Which two great sexes animate the world,
+Stored in each orb perhaps with some that live.
+For such vast room in Nature unpossessed
+By living soul, desart and desolate,
+Only to shine, yet scarce to contribute
+Each orb a glimpse of light, conveyed so far
+Down to this habitable, which returns
+Light back to them, is obvious to dispute.
+But whether thus these things, or whether not;
+But whether the sun, predominant in Heaven,
+Rise on the earth; or earth rise on the sun;
+He from the east his flaming road begin;
+Or she from west her silent course advance,
+With inoffensive pace that spinning sleeps
+On her soft axle, while she paces even,
+And bears thee soft with the smooth hair along;
+Sollicit not thy thoughts with matters hid;
+Leave them to God above; him serve, and fear!
+Of other creatures, as him pleases best,
+Wherever placed, let him dispose; joy thou
+In what he gives to thee, this Paradise
+And thy fair Eve; Heaven is for thee too high
+To know what passes there; be lowly wise:
+Think only what concerns thee, and thy being;
+Dream not of other worlds, what creatures there
+Live, in what state, condition, or degree;
+Contented that thus far hath been revealed
+Not of Earth only, but of highest Heaven.
+To whom thus Adam, cleared of doubt, replied.
+How fully hast thou satisfied me, pure
+Intelligence of Heaven, Angel serene!
+And, freed from intricacies, taught to live
+The easiest way; nor with perplexing thoughts
+To interrupt the sweet of life, from which
+God hath bid dwell far off all anxious cares,
+And not molest us; unless we ourselves
+Seek them with wandering thoughts, and notions vain.
+But apt the mind or fancy is to rove
+Unchecked, and of her roving is no end;
+Till warned, or by experience taught, she learn,
+That, not to know at large of things remote
+From use, obscure and subtle; but, to know
+That which before us lies in daily life,
+Is the prime wisdom: What is more, is fume,
+Or emptiness, or fond impertinence:
+And renders us, in things that most concern,
+Unpractised, unprepared, and still to seek.
+Therefore from this high pitch let us descend
+A lower flight, and speak of things at hand
+Useful; whence, haply, mention may arise
+Of something not unseasonable to ask,
+By sufferance, and thy wonted favour, deigned.
+Thee I have heard relating what was done
+Ere my remembrance: now, hear me relate
+My story, which perhaps thou hast not heard;
+And day is not yet spent; till then thou seest
+How subtly to detain thee I devise;
+Inviting thee to hear while I relate;
+Fond! were it not in hope of thy reply:
+For, while I sit with thee, I seem in Heaven;
+And sweeter thy discourse is to my ear
+Than fruits of palm-tree pleasantest to thirst
+And hunger both, from labour, at the hour
+Of sweet repast; they satiate, and soon fill,
+Though pleasant; but thy words, with grace divine
+Imbued, bring to their sweetness no satiety.
+To whom thus Raphael answered heavenly meek.
+Nor are thy lips ungraceful, Sire of men,
+Nor tongue ineloquent; for God on thee
+Abundantly his gifts hath also poured
+Inward and outward both, his image fair:
+Speaking, or mute, all comeliness and grace
+Attends thee; and each word, each motion, forms;
+Nor less think we in Heaven of thee on Earth
+Than of our fellow-servant, and inquire
+Gladly into the ways of God with Man:
+For God, we see, hath honoured thee, and set
+On Man his equal love: Say therefore on;
+For I that day was absent, as befel,
+Bound on a voyage uncouth and obscure,
+Far on excursion toward the gates of Hell;
+Squared in full legion (such command we had)
+To see that none thence issued forth a spy,
+Or enemy, while God was in his work;
+Lest he, incensed at such eruption bold,
+Destruction with creation might have mixed.
+Not that they durst without his leave attempt;
+But us he sends upon his high behests
+For state, as Sovran King; and to inure
+Our prompt obedience. Fast we found, fast shut,
+The dismal gates, and barricadoed strong;
+But long ere our approaching heard within
+Noise, other than the sound of dance or song,
+Torment, and loud lament, and furious rage.
+Glad we returned up to the coasts of light
+Ere sabbath-evening: so we had in charge.
+But thy relation now; for I attend,
+Pleased with thy words no less than thou with mine.
+So spake the Godlike Power, and thus our Sire.
+For Man to tell how human life began
+Is hard; for who himself beginning knew
+Desire with thee still longer to converse
+Induced me. As new waked from soundest sleep,
+Soft on the flowery herb I found me laid,
+In balmy sweat; which with his beams the sun
+Soon dried, and on the reeking moisture fed.
+Straight toward Heaven my wondering eyes I turned,
+And gazed a while the ample sky; till, raised
+By quick instinctive motion, up I sprung,
+As thitherward endeavouring, and upright
+Stood on my feet: about me round I saw
+Hill, dale, and shady woods, and sunny plains,
+And liquid lapse of murmuring streams; by these,
+Creatures that lived and moved, and walked, or flew;
+Birds on the branches warbling; all things smiled;
+With fragrance and with joy my heart o'erflowed.
+Myself I then perused, and limb by limb
+Surveyed, and sometimes went, and sometimes ran
+With supple joints, as lively vigour led:
+But who I was, or where, or from what cause,
+Knew not; to speak I tried, and forthwith spake;
+My tongue obeyed, and readily could name
+Whate'er I saw. Thou Sun, said I, fair light,
+And thou enlightened Earth, so fresh and gay,
+Ye Hills, and Dales, ye Rivers, Woods, and Plains,
+And ye that live and move, fair Creatures, tell,
+Tell, if ye saw, how I came thus, how here?--
+Not of myself;--by some great Maker then,
+In goodness and in power pre-eminent:
+Tell me, how may I know him, how adore,
+From whom I have that thus I move and live,
+And feel that I am happier than I know.--
+While thus I called, and strayed I knew not whither,
+From where I first drew air, and first beheld
+This happy light; when, answer none returned,
+On a green shady bank, profuse of flowers,
+Pensive I sat me down: There gentle sleep
+First found me, and with soft oppression seised
+My droused sense, untroubled, though I thought
+I then was passing to my former state
+Insensible, and forthwith to dissolve:
+When suddenly stood at my head a dream,
+Whose inward apparition gently moved
+My fancy to believe I yet had being,
+And lived: One came, methought, of shape divine,
+And said, 'Thy mansion wants thee, Adam; rise,
+'First Man, of men innumerable ordained
+'First Father! called by thee, I come thy guide
+'To the garden of bliss, thy seat prepared.'
+So saying, by the hand he took me raised,
+And over fields and waters, as in air
+Smooth-sliding without step, last led me up
+A woody mountain; whose high top was plain,
+A circuit wide, enclosed, with goodliest trees
+Planted, with walks, and bowers; that what I saw
+Of Earth before scarce pleasant seemed. Each tree,
+Loaden with fairest fruit that hung to the eye
+Tempting, stirred in me sudden appetite
+To pluck and eat; whereat I waked, and found
+Before mine eyes all real, as the dream
+Had lively shadowed: Here had new begun
+My wandering, had not he, who was my guide
+Up hither, from among the trees appeared,
+Presence Divine. Rejoicing, but with awe,
+In adoration at his feet I fell
+Submiss: He reared me, and 'Whom thou soughtest I am,'
+Said mildly, 'Author of all this thou seest
+'Above, or round about thee, or beneath.
+'This Paradise I give thee, count it thine
+'To till and keep, and of the fruit to eat:
+'Of every tree that in the garden grows
+'Eat freely with glad heart; fear here no dearth:
+'But of the tree whose operation brings
+'Knowledge of good and ill, which I have set
+'The pledge of thy obedience and thy faith,
+'Amid the garden by the tree of life,
+'Remember what I warn thee, shun to taste,
+'And shun the bitter consequence: for know,
+'The day thou eatest thereof, my sole command
+'Transgressed, inevitably thou shalt die,
+'From that day mortal; and this happy state
+'Shalt lose, expelled from hence into a world
+'Of woe and sorrow.' Sternly he pronounced
+The rigid interdiction, which resounds
+Yet dreadful in mine ear, though in my choice
+Not to incur; but soon his clear aspect
+Returned, and gracious purpose thus renewed.
+'Not only these fair bounds, but all the Earth
+'To thee and to thy race I give; as lords
+'Possess it, and all things that therein live,
+'Or live in sea, or air; beast, fish, and fowl.
+'In sign whereof, each bird and beast behold
+'After their kinds; I bring them to receive
+'From thee their names, and pay thee fealty
+'With low subjection; understand the same
+'Of fish within their watery residence,
+'Not hither summoned, since they cannot change
+'Their element, to draw the thinner air.'
+As thus he spake, each bird and beast behold
+Approaching two and two; these cowering low
+With blandishment; each bird stooped on his wing.
+I named them, as they passed, and understood
+Their nature, with such knowledge God endued
+My sudden apprehension: But in these
+I found not what methought I wanted still;
+And to the heavenly Vision thus presumed.
+O, by what name, for thou above all these,
+Above mankind, or aught than mankind higher,
+Surpassest far my naming; how may I
+Adore thee, Author of this universe,
+And all this good to man? for whose well being
+So amply, and with hands so liberal,
+Thou hast provided all things: But with me
+I see not who partakes. In solitude
+What happiness, who can enjoy alone,
+Or, all enjoying, what contentment find?
+Thus I presumptuous; and the Vision bright,
+As with a smile more brightened, thus replied.
+What callest thou solitude? Is not the Earth
+With various living creatures, and the air
+Replenished, and all these at thy command
+To come and play before thee? Knowest thou not
+Their language and their ways? They also know,
+And reason not contemptibly: With these
+Find pastime, and bear rule; thy realm is large.
+So spake the Universal Lord, and seemed
+So ordering: I, with leave of speech implored,
+And humble deprecation, thus replied.
+Let not my words offend thee, Heavenly Power;
+My Maker, be propitious while I speak.
+Hast thou not made me here thy substitute,
+And these inferiour far beneath me set?
+Among unequals what society
+Can sort, what harmony, or true delight?
+Which must be mutual, in proportion due
+Given and received; but, in disparity
+The one intense, the other still remiss,
+Cannot well suit with either, but soon prove
+Tedious alike: Of fellowship I speak
+Such as I seek, fit to participate
+All rational delight: wherein the brute
+Cannot be human consort: They rejoice
+Each with their kind, lion with lioness;
+So fitly them in pairs thou hast combined:
+Much less can bird with beast, or fish with fowl
+So well converse, nor with the ox the ape;
+Worse then can man with beast, and least of all.
+Whereto the Almighty answered, not displeased.
+A nice and subtle happiness, I see,
+Thou to thyself proposest, in the choice
+Of thy associates, Adam! and wilt taste
+No pleasure, though in pleasure, solitary.
+What thinkest thou then of me, and this my state?
+Seem I to thee sufficiently possessed
+Of happiness, or not? who am alone
+From all eternity; for none I know
+Second to me or like, equal much less.
+How have I then with whom to hold converse,
+Save with the creatures which I made, and those
+To me inferiour, infinite descents
+Beneath what other creatures are to thee?
+He ceased; I lowly answered. To attain
+The highth and depth of thy eternal ways
+All human thoughts come short, Supreme of things!
+Thou in thyself art perfect, and in thee
+Is no deficience found: Not so is Man,
+But in degree; the cause of his desire
+By conversation with his like to help
+Or solace his defects. No need that thou
+Shouldst propagate, already Infinite;
+And through all numbers absolute, though One:
+But Man by number is to manifest
+His single imperfection, and beget
+Like of his like, his image multiplied,
+In unity defective; which requires
+Collateral love, and dearest amity.
+Thou in thy secresy although alone,
+Best with thyself accompanied, seekest not
+Social communication; yet, so pleased,
+Canst raise thy creature to what highth thou wilt
+Of union or communion, deified:
+I, by conversing, cannot these erect
+From prone; nor in their ways complacence find.
+Thus I emboldened spake, and freedom used
+Permissive, and acceptance found; which gained
+This answer from the gracious Voice Divine.
+Thus far to try thee, Adam, I was pleased;
+And find thee knowing, not of beasts alone,
+Which thou hast rightly named, but of thyself;
+Expressing well the spirit within thee free,
+My image, not imparted to the brute;
+Whose fellowship therefore unmeet for thee
+Good reason was thou freely shouldst dislike;
+And be so minded still: I, ere thou spakest,
+Knew it not good for Man to be alone;
+And no such company as then thou sawest
+Intended thee; for trial only brought,
+To see how thou couldest judge of fit and meet:
+What next I bring shall please thee, be assured,
+Thy likeness, thy fit help, thy other self,
+Thy wish exactly to thy heart's desire.
+He ended, or I heard no more; for now
+My earthly by his heavenly overpowered,
+Which it had long stood under, strained to the highth
+In that celestial colloquy sublime,
+As with an object that excels the sense
+Dazzled and spent, sunk down; and sought repair
+Of sleep, which instantly fell on me, called
+By Nature as in aid, and closed mine eyes.
+Mine eyes he closed, but open left the cell
+Of fancy, my internal sight; by which,
+Abstract as in a trance, methought I saw,
+Though sleeping, where I lay, and saw the shape
+Still glorious before whom awake I stood:
+Who stooping opened my left side, and took
+From thence a rib, with cordial spirits warm,
+And life-blood streaming fresh; wide was the wound,
+But suddenly with flesh filled up and healed:
+The rib he formed and fashioned with his hands;
+Under his forming hands a creature grew,
+Man-like, but different sex; so lovely fair,
+That what seemed fair in all the world, seemed now
+Mean, or in her summed up, in her contained
+And in her looks; which from that time infused
+Sweetness into my heart, unfelt before,
+And into all things from her air inspired
+The spirit of love and amorous delight.
+She disappeared, and left me dark; I waked
+To find her, or for ever to deplore
+Her loss, and other pleasures all abjure:
+When out of hope, behold her, not far off,
+Such as I saw her in my dream, adorned
+With what all Earth or Heaven could bestow
+To make her amiable: On she came,
+Led by her heavenly Maker, though unseen,
+And guided by his voice; nor uninformed
+Of nuptial sanctity, and marriage rites:
+Grace was in all her steps, Heaven in her eye,
+In every gesture dignity and love.
+I, overjoyed, could not forbear aloud.
+This turn hath made amends; thou hast fulfilled
+Thy words, Creator bounteous and benign,
+Giver of all things fair! but fairest this
+Of all thy gifts! nor enviest. I now see
+Bone of my bone, flesh of my flesh, myself
+Before me: Woman is her name;of Man
+Extracted: for this cause he shall forego
+Father and mother, and to his wife adhere;
+And they shall be one flesh, one heart, one soul.
+She heard me thus; and though divinely brought,
+Yet innocence, and virgin modesty,
+Her virtue, and the conscience of her worth,
+That would be wooed, and not unsought be won,
+Not obvious, not obtrusive, but, retired,
+The more desirable; or, to say all,
+Nature herself, though pure of sinful thought,
+Wrought in her so, that, seeing me, she turned:
+I followed her; she what was honour knew,
+And with obsequious majesty approved
+My pleaded reason. To the nuptial bower
+I led her blushing like the morn: All Heaven,
+And happy constellations, on that hour
+Shed their selectest influence; the Earth
+Gave sign of gratulation, and each hill;
+Joyous the birds; fresh gales and gentle airs
+Whispered it to the woods, and from their wings
+Flung rose, flung odours from the spicy shrub,
+Disporting, till the amorous bird of night
+Sung spousal, and bid haste the evening-star
+On his hill top, to light the bridal lamp.
+Thus have I told thee all my state, and brought
+My story to the sum of earthly bliss,
+Which I enjoy; and must confess to find
+In all things else delight indeed, but such
+As, used or not, works in the mind no change,
+Nor vehement desire; these delicacies
+I mean of taste, sight, smell, herbs, fruits, and flowers,
+Walks, and the melody of birds: but here
+Far otherwise, transported I behold,
+Transported touch; here passion first I felt,
+Commotion strange! in all enjoyments else
+Superiour and unmoved; here only weak
+Against the charm of Beauty's powerful glance.
+Or Nature failed in me, and left some part
+Not proof enough such object to sustain;
+Or, from my side subducting, took perhaps
+More than enough; at least on her bestowed
+Too much of ornament, in outward show
+Elaborate, of inward less exact.
+For well I understand in the prime end
+Of Nature her the inferiour, in the mind
+And inward faculties, which most excel;
+In outward also her resembling less
+His image who made both, and less expressing
+The character of that dominion given
+O'er other creatures: Yet when I approach
+Her loveliness, so absolute she seems
+And in herself complete, so well to know
+Her own, that what she wills to do or say,
+Seems wisest, virtuousest, discreetest, best:
+All higher knowledge in her presence falls
+Degraded; Wisdom in discourse with her
+Loses discountenanced, and like Folly shows;
+Authority and Reason on her wait,
+As one intended first, not after made
+Occasionally; and, to consummate all,
+Greatness of mind and Nobleness their seat
+Build in her loveliest, and create an awe
+About her, as a guard angelick placed.
+To whom the Angel with contracted brow.
+Accuse not Nature, she hath done her part;
+Do thou but thine; and be not diffident
+Of Wisdom; she deserts thee not, if thou
+Dismiss not her, when most thou needest her nigh,
+By attributing overmuch to things
+Less excellent, as thou thyself perceivest.
+For, what admirest thou, what transports thee so,
+An outside? fair, no doubt, and worthy well
+Thy cherishing, thy honouring, and thy love;
+Not thy subjection: Weigh with her thyself;
+Then value: Oft-times nothing profits more
+Than self-esteem, grounded on just and right
+Well managed; of that skill the more thou knowest,
+The more she will acknowledge thee her head,
+And to realities yield all her shows:
+Made so adorn for thy delight the more,
+So awful, that with honour thou mayest love
+Thy mate, who sees when thou art seen least wise.
+But if the sense of touch, whereby mankind
+Is propagated, seem such dear delight
+Beyond all other; think the same vouchsafed
+To cattle and each beast; which would not be
+To them made common and divulged, if aught
+Therein enjoyed were worthy to subdue
+The soul of man, or passion in him move.
+What higher in her society thou findest
+Attractive, human, rational, love still;
+In loving thou dost well, in passion not,
+Wherein true love consists not: Love refines
+The thoughts, and heart enlarges; hath his seat
+In reason, and is judicious; is the scale
+By which to heavenly love thou mayest ascend,
+Not sunk in carnal pleasure; for which cause,
+Among the beasts no mate for thee was found.
+To whom thus, half abashed, Adam replied.
+Neither her outside formed so fair, nor aught
+In procreation common to all kinds,
+(Though higher of the genial bed by far,
+And with mysterious reverence I deem,)
+So much delights me, as those graceful acts,
+Those thousand decencies, that daily flow
+From all her words and actions mixed with love
+And sweet compliance, which declare unfeigned
+Union of mind, or in us both one soul;
+Harmony to behold in wedded pair
+More grateful than harmonious sound to the ear.
+Yet these subject not; I to thee disclose
+What inward thence I feel, not therefore foiled,
+Who meet with various objects, from the sense
+Variously representing; yet, still free,
+Approve the best, and follow what I approve.
+To love, thou blamest me not; for Love, thou sayest,
+Leads up to Heaven, is both the way and guide;
+Bear with me then, if lawful what I ask:
+Love not the heavenly Spirits, and how their love
+Express they? by looks only? or do they mix
+Irradiance, virtual or immediate touch?
+To whom the Angel, with a smile that glowed
+Celestial rosy red, Love's proper hue,
+Answered. Let it suffice thee that thou knowest
+Us happy, and without love no happiness.
+Whatever pure thou in the body enjoyest,
+(And pure thou wert created) we enjoy
+In eminence; and obstacle find none
+Of membrane, joint, or limb, exclusive bars;
+Easier than air with air, if Spirits embrace,
+Total they mix, union of pure with pure
+Desiring, nor restrained conveyance need,
+As flesh to mix with flesh, or soul with soul.
+But I can now no more; the parting sun
+Beyond the Earth's green Cape and verdant Isles
+Hesperian sets, my signal to depart.
+Be strong, live happy, and love! But, first of all,
+Him, whom to love is to obey, and keep
+His great command; take heed lest passion sway
+Thy judgement to do aught, which else free will
+Would not admit: thine, and of all thy sons,
+The weal or woe in thee is placed; beware!
+I in thy persevering shall rejoice,
+And all the Blest: Stand fast;to stand or fall
+Free in thine own arbitrement it lies.
+Perfect within, no outward aid require;
+And all temptation to transgress repel.
+So saying, he arose; whom Adam thus
+Followed with benediction. Since to part,
+Go, heavenly guest, ethereal Messenger,
+Sent from whose sovran goodness I adore!
+Gentle to me and affable hath been
+Thy condescension, and shall be honoured ever
+With grateful memory: Thou to mankind
+Be good and friendly still, and oft return!
+So parted they; the Angel up to Heaven
+From the thick shade, and Adam to his bower.
+
+
+
+Book IX
+
+
+No more of talk where God or Angel guest
+With Man, as with his friend, familiar us'd,
+To sit indulgent, and with him partake
+Rural repast; permitting him the while
+Venial discourse unblam'd. I now must change
+Those notes to tragick; foul distrust, and breach
+Disloyal on the part of Man, revolt,
+And disobedience: on the part of Heaven
+Now alienated, distance and distaste,
+Anger and just rebuke, and judgement given,
+That brought into this world a world of woe,
+Sin and her shadow Death, and Misery
+Death's harbinger: Sad talk!yet argument
+Not less but more heroick than the wrath
+Of stern Achilles on his foe pursued
+Thrice fugitive about Troy wall; or rage
+Of Turnus for Lavinia disespous'd;
+Or Neptune's ire, or Juno's, that so long
+Perplexed the Greek, and Cytherea's son:
+
+ 00482129
+If answerable style I can obtain
+Of my celestial patroness, who deigns
+Her nightly visitation unimplor'd,
+And dictates to me slumbering; or inspires
+Easy my unpremeditated verse:
+Since first this subject for heroick song
+Pleas'd me long choosing, and beginning late;
+Not sedulous by nature to indite
+Wars, hitherto the only argument
+Heroick deem'd chief mastery to dissect
+With long and tedious havock fabled knights
+In battles feign'd; the better fortitude
+Of patience and heroick martyrdom
+Unsung; or to describe races and games,
+Or tilting furniture, imblazon'd shields,
+Impresses quaint, caparisons and steeds,
+Bases and tinsel trappings, gorgeous knights
+At joust and tournament; then marshall'd feast
+Serv'd up in hall with sewers and seneshals;
+The skill of artifice or office mean,
+Not that which justly gives heroick name
+To person, or to poem. Me, of these
+Nor skill'd nor studious, higher argument
+Remains; sufficient of itself to raise
+That name, unless an age too late, or cold
+Climate, or years, damp my intended wing
+Depress'd; and much they may, if all be mine,
+Not hers, who brings it nightly to my ear.
+The sun was sunk, and after him the star
+Of Hesperus, whose office is to bring
+Twilight upon the earth, short arbiter
+"twixt day and night, and now from end to end
+Night's hemisphere had veil'd the horizon round:
+When satan, who late fled before the threats
+Of Gabriel out of Eden, now improv'd
+In meditated fraud and malice, bent
+On Man's destruction, maugre what might hap
+Of heavier on himself, fearless returned
+From compassing the earth; cautious of day,
+Since Uriel, regent of the sun, descried
+His entrance, and foreworned the Cherubim
+That kept their watch; thence full of anguish driven,
+The space of seven continued nights he rode
+With darkness; thrice the equinoctial line
+He circled; four times crossed the car of night
+From pole to pole, traversing each colure;
+On the eighth returned; and, on the coast averse
+From entrance or Cherubick watch, by stealth
+Found unsuspected way. There was a place,
+Now not, though sin, not time, first wrought the change,
+Where Tigris, at the foot of Paradise,
+Into a gulf shot under ground, till part
+Rose up a fountain by the tree of life:
+In with the river sunk, and with it rose
+Satan, involved in rising mist; then sought
+Where to lie hid; sea he had searched, and land,
+From Eden over Pontus and the pool
+Maeotis, up beyond the river Ob;
+Downward as far antarctick; and in length,
+West from Orontes to the ocean barred
+At Darien ; thence to the land where flows
+Ganges and Indus: Thus the orb he roamed
+With narrow search; and with inspection deep
+Considered every creature, which of all
+Most opportune might serve his wiles; and found
+The Serpent subtlest beast of all the field.
+Him after long debate, irresolute
+Of thoughts revolved, his final sentence chose
+Fit vessel, fittest imp of fraud, in whom
+To enter, and his dark suggestions hide
+From sharpest sight: for, in the wily snake
+Whatever sleights, none would suspicious mark,
+As from his wit and native subtlety
+Proceeding; which, in other beasts observed,
+Doubt might beget of diabolick power
+Active within, beyond the sense of brute.
+Thus he resolved, but first from inward grief
+His bursting passion into plaints thus poured.
+More justly, seat worthier of Gods, as built
+With second thoughts, reforming what was old!
+O Earth, how like to Heaven, if not preferred
+For what God, after better, worse would build?
+Terrestrial Heaven, danced round by other Heavens
+That shine, yet bear their bright officious lamps,
+Light above light, for thee alone, as seems,
+In thee concentring all their precious beams
+Of sacred influence! As God in Heaven
+Is center, yet extends to all; so thou,
+Centring, receivest from all those orbs: in thee,
+Not in themselves, all their known virtue appears
+Productive in herb, plant, and nobler birth
+Of creatures animate with gradual life
+Of growth, sense, reason, all summed up in Man.
+With what delight could I have walked thee round,
+If I could joy in aught, sweet interchange
+Of hill, and valley, rivers, woods, and plains,
+Now land, now sea and shores with forest crowned,
+Rocks, dens, and caves! But I in none of these
+Find place or refuge; and the more I see
+Pleasures about me, so much more I feel
+Torment within me, as from the hateful siege
+Of contraries: all good to me becomes
+Bane, and in Heaven much worse would be my state.
+But neither here seek I, no nor in Heaven
+To dwell, unless by mastering Heaven's Supreme;
+Nor hope to be myself less miserable
+By what I seek, but others to make such
+As I, though thereby worse to me redound:
+For only in destroying I find ease
+To my relentless thoughts; and, him destroyed,
+Or won to what may work his utter loss,
+For whom all this was made, all this will soon
+Follow, as to him linked in weal or woe;
+In woe then; that destruction wide may range:
+To me shall be the glory sole among
+The infernal Powers, in one day to have marred
+What he, Almighty styled, six nights and days
+Continued making; and who knows how long
+Before had been contriving? though perhaps
+Not longer than since I, in one night, freed
+From servitude inglorious well nigh half
+The angelick name, and thinner left the throng
+Of his adorers: He, to be avenged,
+And to repair his numbers thus impaired,
+Whether such virtue spent of old now failed
+More Angels to create, if they at least
+Are his created, or, to spite us more,
+Determined to advance into our room
+A creature formed of earth, and him endow,
+Exalted from so base original,
+With heavenly spoils, our spoils: What he decreed,
+He effected; Man he made, and for him built
+Magnificent this world, and earth his seat,
+Him lord pronounced; and, O indignity!
+Subjected to his service angel-wings,
+And flaming ministers to watch and tend
+Their earthly charge: Of these the vigilance
+I dread; and, to elude, thus wrapt in mist
+Of midnight vapour glide obscure, and pry
+In every bush and brake, where hap may find
+The serpent sleeping; in whose mazy folds
+To hide me, and the dark intent I bring.
+O foul descent! that I, who erst contended
+With Gods to sit the highest, am now constrained
+Into a beast; and, mixed with bestial slime,
+This essence to incarnate and imbrute,
+That to the highth of Deity aspired!
+But what will not ambition and revenge
+Descend to? Who aspires, must down as low
+As high he soared; obnoxious, first or last,
+To basest things. Revenge, at first though sweet,
+Bitter ere long, back on itself recoils:
+Let it; I reck not, so it light well aimed,
+Since higher I fall short, on him who next
+Provokes my envy, this new favourite
+Of Heaven, this man of clay, son of despite,
+Whom, us the more to spite, his Maker raised
+From dust: Spite then with spite is best repaid.
+So saying, through each thicket dank or dry,
+Like a black mist low-creeping, he held on
+His midnight-search, where soonest he might find
+The serpent; him fast-sleeping soon he found
+In labyrinth of many a round self-rolled,
+His head the midst, well stored with subtile wiles:
+Not yet in horrid shade or dismal den,
+Nor nocent yet; but, on the grassy herb,
+Fearless unfeared he slept: in at his mouth
+The Devil entered; and his brutal sense,
+In heart or head, possessing, soon inspired
+With act intelligential; but his sleep
+Disturbed not, waiting close the approach of morn.
+Now, when as sacred light began to dawn
+In Eden on the humid flowers, that breathed
+Their morning incense, when all things, that breathe,
+From the Earth's great altar send up silent praise
+To the Creator, and his nostrils fill
+With grateful smell, forth came the human pair,
+And joined their vocal worship to the quire
+Of creatures wanting voice; that done, partake
+The season prime for sweetest scents and airs:
+Then commune, how that day they best may ply
+Their growing work: for much their work out-grew
+The hands' dispatch of two gardening so wide,
+And Eve first to her husband thus began.
+Adam, well may we labour still to dress
+This garden, still to tend plant, herb, and flower,
+Our pleasant task enjoined; but, till more hands
+Aid us, the work under our labour grows,
+Luxurious by restraint; what we by day
+Lop overgrown, or prune, or prop, or bind,
+One night or two with wanton growth derides
+Tending to wild. Thou therefore now advise,
+Or bear what to my mind first thoughts present:
+Let us divide our labours; thou, where choice
+Leads thee, or where most needs, whether to wind
+The woodbine round this arbour, or direct
+The clasping ivy where to climb; while I,
+In yonder spring of roses intermixed
+With myrtle, find what to redress till noon:
+For, while so near each other thus all day
+Our task we choose, what wonder if so near
+Looks intervene and smiles, or object new
+Casual discourse draw on; which intermits
+Our day's work, brought to little, though begun
+Early, and the hour of supper comes unearned?
+To whom mild answer Adam thus returned.
+Sole Eve, associate sole, to me beyond
+Compare above all living creatures dear!
+Well hast thou motioned, well thy thoughts employed,
+How we might best fulfil the work which here
+God hath assigned us; nor of me shalt pass
+Unpraised: for nothing lovelier can be found
+In woman, than to study houshold good,
+And good works in her husband to promote.
+Yet not so strictly hath our Lord imposed
+Labour, as to debar us when we need
+Refreshment, whether food, or talk between,
+Food of the mind, or this sweet intercourse
+Of looks and smiles; for smiles from reason flow,
+To brute denied, and are of love the food;
+Love, not the lowest end of human life.
+For not to irksome toil, but to delight,
+He made us, and delight to reason joined.
+These paths and bowers doubt not but our joint hands
+Will keep from wilderness with ease, as wide
+As we need walk, till younger hands ere long
+Assist us; But, if much converse perhaps
+Thee satiate, to short absence I could yield:
+For solitude sometimes is best society,
+And short retirement urges sweet return.
+But other doubt possesses me, lest harm
+Befall thee severed from me; for thou knowest
+What hath been warned us, what malicious foe
+Envying our happiness, and of his own
+Despairing, seeks to work us woe and shame
+By sly assault; and somewhere nigh at hand
+Watches, no doubt, with greedy hope to find
+His wish and best advantage, us asunder;
+Hopeless to circumvent us joined, where each
+To other speedy aid might lend at need:
+Whether his first design be to withdraw
+Our fealty from God, or to disturb
+Conjugal love, than which perhaps no bliss
+Enjoyed by us excites his envy more;
+Or this, or worse, leave not the faithful side
+That gave thee being, still shades thee, and protects.
+The wife, where danger or dishonour lurks,
+Safest and seemliest by her husband stays,
+Who guards her, or with her the worst endures.
+To whom the virgin majesty of Eve,
+As one who loves, and some unkindness meets,
+With sweet austere composure thus replied.
+Offspring of Heaven and Earth, and all Earth's Lord!
+That such an enemy we have, who seeks
+Our ruin, both by thee informed I learn,
+And from the parting Angel over-heard,
+As in a shady nook I stood behind,
+Just then returned at shut of evening flowers.
+But, that thou shouldst my firmness therefore doubt
+To God or thee, because we have a foe
+May tempt it, I expected not to hear.
+His violence thou fearest not, being such
+As we, not capable of death or pain,
+Can either not receive, or can repel.
+His fraud is then thy fear; which plain infers
+Thy equal fear, that my firm faith and love
+Can by his fraud be shaken or seduced;
+Thoughts, which how found they harbour in thy breast,
+Adam, mis-thought of her to thee so dear?
+To whom with healing words Adam replied.
+Daughter of God and Man, immortal Eve!
+For such thou art; from sin and blame entire:
+Not diffident of thee do I dissuade
+Thy absence from my sight, but to avoid
+The attempt itself, intended by our foe.
+For he who tempts, though in vain, at least asperses
+The tempted with dishonour foul; supposed
+Not incorruptible of faith, not proof
+Against temptation: Thou thyself with scorn
+And anger wouldst resent the offered wrong,
+Though ineffectual found: misdeem not then,
+If such affront I labour to avert
+From thee alone, which on us both at once
+The enemy, though bold, will hardly dare;
+Or daring, first on me the assault shall light.
+Nor thou his malice and false guile contemn;
+Subtle he needs must be, who could seduce
+Angels; nor think superfluous other's aid.
+I, from the influence of thy looks, receive
+Access in every virtue; in thy sight
+More wise, more watchful, stronger, if need were
+Of outward strength; while shame, thou looking on,
+Shame to be overcome or over-reached,
+Would utmost vigour raise, and raised unite.
+Why shouldst not thou like sense within thee feel
+When I am present, and thy trial choose
+With me, best witness of thy virtue tried?
+So spake domestick Adam in his care
+And matrimonial love; but Eve, who thought
+Less attributed to her faith sincere,
+Thus her reply with accent sweet renewed.
+If this be our condition, thus to dwell
+In narrow circuit straitened by a foe,
+Subtle or violent, we not endued
+Single with like defence, wherever met;
+How are we happy, still in fear of harm?
+But harm precedes not sin: only our foe,
+Tempting, affronts us with his foul esteem
+Of our integrity: his foul esteem
+Sticks no dishonour on our front, but turns
+Foul on himself; then wherefore shunned or feared
+By us? who rather double honour gain
+From his surmise proved false; find peace within,
+Favour from Heaven, our witness, from the event.
+And what is faith, love, virtue, unassayed
+Alone, without exteriour help sustained?
+Let us not then suspect our happy state
+Left so imperfect by the Maker wise,
+As not secure to single or combined.
+Frail is our happiness, if this be so,
+And Eden were no Eden, thus exposed.
+To whom thus Adam fervently replied.
+O Woman, best are all things as the will
+Of God ordained them: His creating hand
+Nothing imperfect or deficient left
+Of all that he created, much less Man,
+Or aught that might his happy state secure,
+Secure from outward force; within himself
+The danger lies, yet lies within his power:
+Against his will he can receive no harm.
+But God left free the will; for what obeys
+Reason, is free; and Reason he made right,
+But bid her well be ware, and still erect;
+Lest, by some fair-appearing good surprised,
+She dictate false; and mis-inform the will
+To do what God expressly hath forbid.
+Not then mistrust, but tender love, enjoins,
+That I should mind thee oft; and mind thou me.
+Firm we subsist, yet possible to swerve;
+Since Reason not impossibly may meet
+Some specious object by the foe suborned,
+And fall into deception unaware,
+Not keeping strictest watch, as she was warned.
+Seek not temptation then, which to avoid
+Were better, and most likely if from me
+Thou sever not: Trial will come unsought.
+Wouldst thou approve thy constancy, approve
+First thy obedience; the other who can know,
+Not seeing thee attempted, who attest?
+But, if thou think, trial unsought may find
+Us both securer than thus warned thou seemest,
+Go; for thy stay, not free, absents thee more;
+Go in thy native innocence, rely
+On what thou hast of virtue; summon all!
+For God towards thee hath done his part, do thine.
+So spake the patriarch of mankind; but Eve
+Persisted; yet submiss, though last, replied.
+With thy permission then, and thus forewarned
+Chiefly by what thy own last reasoning words
+Touched only; that our trial, when least sought,
+May find us both perhaps far less prepared,
+The willinger I go, nor much expect
+A foe so proud will first the weaker seek;
+So bent, the more shall shame him his repulse.
+Thus saying, from her husband's hand her hand
+Soft she withdrew; and, like a Wood-Nymph light,
+Oread or Dryad, or of Delia's train,
+Betook her to the groves; but Delia's self
+In gait surpassed, and Goddess-like deport,
+Though not as she with bow and quiver armed,
+But with such gardening tools as Art yet rude,
+Guiltless of fire, had formed, or Angels brought.
+To Pales, or Pomona, thus adorned,
+Likest she seemed, Pomona when she fled
+Vertumnus, or to Ceres in her prime,
+Yet virgin of Proserpina from Jove.
+Her long with ardent look his eye pursued
+Delighted, but desiring more her stay.
+Oft he to her his charge of quick return
+Repeated; she to him as oft engaged
+To be returned by noon amid the bower,
+And all things in best order to invite
+Noontide repast, or afternoon's repose.
+O much deceived, much failing, hapless Eve,
+Of thy presumed return! event perverse!
+Thou never from that hour in Paradise
+Foundst either sweet repast, or sound repose;
+Such ambush, hid among sweet flowers and shades,
+Waited with hellish rancour imminent
+To intercept thy way, or send thee back
+Despoiled of innocence, of faith, of bliss!
+For now, and since first break of dawn, the Fiend,
+Mere serpent in appearance, forth was come;
+And on his quest, where likeliest he might find
+The only two of mankind, but in them
+The whole included race, his purposed prey.
+In bower and field he sought, where any tuft
+Of grove or garden-plot more pleasant lay,
+Their tendance, or plantation for delight;
+By fountain or by shady rivulet
+He sought them both, but wished his hap might find
+Eve separate; he wished, but not with hope
+Of what so seldom chanced; when to his wish,
+Beyond his hope, Eve separate he spies,
+Veiled in a cloud of fragrance, where she stood,
+Half spied, so thick the roses blushing round
+About her glowed, oft stooping to support
+Each flower of slender stalk, whose head, though gay
+Carnation, purple, azure, or specked with gold,
+Hung drooping unsustained; them she upstays
+Gently with myrtle band, mindless the while
+Herself, though fairest unsupported flower,
+From her best prop so far, and storm so nigh.
+Nearer he drew, and many a walk traversed
+Of stateliest covert, cedar, pine, or palm;
+Then voluble and bold, now hid, now seen,
+Among thick-woven arborets, and flowers
+Imbordered on each bank, the hand of Eve:
+Spot more delicious than those gardens feigned
+Or of revived Adonis, or renowned
+Alcinous, host of old Laertes' son;
+Or that, not mystick, where the sapient king
+Held dalliance with his fair Egyptian spouse.
+Much he the place admired, the person more.
+As one who long in populous city pent,
+Where houses thick and sewers annoy the air,
+Forth issuing on a summer's morn, to breathe
+Among the pleasant villages and farms
+Adjoined, from each thing met conceives delight;
+The smell of grain, or tedded grass, or kine,
+Or dairy, each rural sight, each rural sound;
+If chance, with nymph-like step, fair virgin pass,
+What pleasing seemed, for her now pleases more;
+She most, and in her look sums all delight:
+Such pleasure took the Serpent to behold
+This flowery plat, the sweet recess of Eve
+Thus early, thus alone: Her heavenly form
+Angelick, but more soft, and feminine,
+Her graceful innocence, her every air
+Of gesture, or least action, overawed
+His malice, and with rapine sweet bereaved
+His fierceness of the fierce intent it brought:
+That space the Evil-one abstracted stood
+From his own evil, and for the time remained
+Stupidly good; of enmity disarmed,
+Of guile, of hate, of envy, of revenge:
+But the hot Hell that always in him burns,
+Though in mid Heaven, soon ended his delight,
+And tortures him now more, the more he sees
+Of pleasure, not for him ordained: then soon
+Fierce hate he recollects, and all his thoughts
+Of mischief, gratulating, thus excites.
+Thoughts, whither have ye led me! with what sweet
+Compulsion thus transported, to forget
+What hither brought us! hate, not love;nor hope
+Of Paradise for Hell, hope here to taste
+Of pleasure; but all pleasure to destroy,
+Save what is in destroying; other joy
+To me is lost. Then, let me not let pass
+Occasion which now smiles; behold alone
+The woman, opportune to all attempts,
+Her husband, for I view far round, not nigh,
+Whose higher intellectual more I shun,
+And strength, of courage haughty, and of limb
+Heroick built, though of terrestrial mould;
+Foe not informidable! exempt from wound,
+I not; so much hath Hell debased, and pain
+Enfeebled me, to what I was in Heaven.
+She fair, divinely fair, fit love for Gods!
+Not terrible, though terrour be in love
+And beauty, not approached by stronger hate,
+Hate stronger, under show of love well feigned;
+The way which to her ruin now I tend.
+So spake the enemy of mankind, enclosed
+In serpent, inmate bad! and toward Eve
+Addressed his way: not with indented wave,
+Prone on the ground, as since; but on his rear,
+Circular base of rising folds, that towered
+Fold above fold, a surging maze! his head
+Crested aloft, and carbuncle his eyes;
+With burnished neck of verdant gold, erect
+Amidst his circling spires, that on the grass
+Floated redundant: pleasing was his shape
+And lovely; never since of serpent-kind
+Lovelier, not those that in Illyria changed,
+Hermione and Cadmus, or the god
+In Epidaurus; nor to which transformed
+Ammonian Jove, or Capitoline, was seen;
+He with Olympias; this with her who bore
+Scipio, the highth of Rome. With tract oblique
+At first, as one who sought access, but feared
+To interrupt, side-long he works his way.
+As when a ship, by skilful steersmen wrought
+Nigh river's mouth or foreland, where the wind
+Veers oft, as oft so steers, and shifts her sail:
+So varied he, and of his tortuous train
+Curled many a wanton wreath in sight of Eve,
+To lure her eye; she, busied, heard the sound
+Of rusling leaves, but minded not, as used
+To such disport before her through the field,
+From every beast; more duteous at her call,
+Than at Circean call the herd disguised.
+He, bolder now, uncalled before her stood,
+But as in gaze admiring: oft he bowed
+His turret crest, and sleek enamelled neck,
+Fawning; and licked the ground whereon she trod.
+His gentle dumb expression turned at length
+The eye of Eve to mark his play; he, glad
+Of her attention gained, with serpent-tongue
+Organick, or impulse of vocal air,
+His fraudulent temptation thus began.
+Wonder not, sovran Mistress, if perhaps
+Thou canst, who art sole wonder! much less arm
+Thy looks, the Heaven of mildness, with disdain,
+Displeased that I approach thee thus, and gaze
+Insatiate; I thus single;nor have feared
+Thy awful brow, more awful thus retired.
+Fairest resemblance of thy Maker fair,
+Thee all things living gaze on, all things thine
+By gift, and thy celestial beauty adore
+With ravishment beheld! there best beheld,
+Where universally admired; but here
+In this enclosure wild, these beasts among,
+Beholders rude, and shallow to discern
+Half what in thee is fair, one man except,
+Who sees thee? and what is one? who should be seen
+A Goddess among Gods, adored and served
+By Angels numberless, thy daily train.
+So glozed the Tempter, and his proem tuned:
+Into the heart of Eve his words made way,
+Though at the voice much marvelling; at length,
+Not unamazed, she thus in answer spake.
+What may this mean? language of man pronounced
+By tongue of brute, and human sense expressed?
+The first, at least, of these I thought denied
+To beasts; whom God, on their creation-day,
+Created mute to all articulate sound:
+The latter I demur; for in their looks
+Much reason, and in their actions, oft appears.
+Thee, Serpent, subtlest beast of all the field
+I knew, but not with human voice endued;
+Redouble then this miracle, and say,
+How camest thou speakable of mute, and how
+To me so friendly grown above the rest
+Of brutal kind, that daily are in sight?
+Say, for such wonder claims attention due.
+To whom the guileful Tempter thus replied.
+Empress of this fair world, resplendent Eve!
+Easy to me it is to tell thee all
+What thou commandest; and right thou shouldst be obeyed:
+I was at first as other beasts that graze
+The trodden herb, of abject thoughts and low,
+As was my food; nor aught but food discerned
+Or sex, and apprehended nothing high:
+Till, on a day roving the field, I chanced
+A goodly tree far distant to behold
+Loaden with fruit of fairest colours mixed,
+Ruddy and gold: I nearer drew to gaze;
+When from the boughs a savoury odour blown,
+Grateful to appetite, more pleased my sense
+Than smell of sweetest fennel, or the teats
+Of ewe or goat dropping with milk at even,
+Unsucked of lamb or kid, that tend their play.
+To satisfy the sharp desire I had
+Of tasting those fair apples, I resolved
+Not to defer; hunger and thirst at once,
+Powerful persuaders, quickened at the scent
+Of that alluring fruit, urged me so keen.
+About the mossy trunk I wound me soon;
+For, high from ground, the branches would require
+Thy utmost reach or Adam's: Round the tree
+All other beasts that saw, with like desire
+Longing and envying stood, but could not reach.
+Amid the tree now got, where plenty hung
+Tempting so nigh, to pluck and eat my fill
+I spared not; for, such pleasure till that hour,
+At feed or fountain, never had I found.
+Sated at length, ere long I might perceive
+Strange alteration in me, to degree
+Of reason in my inward powers; and speech
+Wanted not long; though to this shape retained.
+Thenceforth to speculations high or deep
+I turned my thoughts, and with capacious mind
+Considered all things visible in Heaven,
+Or Earth, or Middle; all things fair and good:
+But all that fair and good in thy divine
+Semblance, and in thy beauty's heavenly ray,
+United I beheld; no fair to thine
+Equivalent or second! which compelled
+Me thus, though importune perhaps, to come
+And gaze, and worship thee of right declared
+Sovran of creatures, universal Dame!
+So talked the spirited sly Snake; and Eve,
+Yet more amazed, unwary thus replied.
+Serpent, thy overpraising leaves in doubt
+The virtue of that fruit, in thee first proved:
+But say, where grows the tree? from hence how far?
+For many are the trees of God that grow
+In Paradise, and various, yet unknown
+To us; in such abundance lies our choice,
+As leaves a greater store of fruit untouched,
+Still hanging incorruptible, till men
+Grow up to their provision, and more hands
+Help to disburden Nature of her birth.
+To whom the wily Adder, blithe and glad.
+Empress, the way is ready, and not long;
+Beyond a row of myrtles, on a flat,
+Fast by a fountain, one small thicket past
+Of blowing myrrh and balm: if thou accept
+My conduct, I can bring thee thither soon
+Lead then, said Eve. He, leading, swiftly rolled
+In tangles, and made intricate seem straight,
+To mischief swift. Hope elevates, and joy
+Brightens his crest; as when a wandering fire,
+Compact of unctuous vapour, which the night
+Condenses, and the cold environs round,
+Kindled through agitation to a flame,
+Which oft, they say, some evil Spirit attends,
+Hovering and blazing with delusive light,
+Misleads the amazed night-wanderer from his way
+To bogs and mires, and oft through pond or pool;
+There swallowed up and lost, from succour far.
+So glistered the dire Snake, and into fraud
+Led Eve, our credulous mother, to the tree
+Of prohibition, root of all our woe;
+Which when she saw, thus to her guide she spake.
+Serpent, we might have spared our coming hither,
+Fruitless to me, though fruit be here to excess,
+The credit of whose virtue rest with thee;
+Wonderous indeed, if cause of such effects.
+But of this tree we may not taste nor touch;
+God so commanded, and left that command
+Sole daughter of his voice; the rest, we live
+Law to ourselves; our reason is our law.
+To whom the Tempter guilefully replied.
+Indeed! hath God then said that of the fruit
+Of all these garden-trees ye shall not eat,
+Yet Lords declared of all in earth or air$?
+To whom thus Eve, yet sinless. Of the fruit
+Of each tree in the garden we may eat;
+But of the fruit of this fair tree amidst
+The garden, God hath said, Ye shall not eat
+Thereof, nor shall ye touch it, lest ye die.
+She scarce had said, though brief, when now more bold
+The Tempter, but with show of zeal and love
+To Man, and indignation at his wrong,
+New part puts on; and, as to passion moved,
+Fluctuates disturbed, yet comely and in act
+Raised, as of some great matter to begin.
+As when of old some orator renowned,
+In Athens or free Rome, where eloquence
+Flourished, since mute! to some great cause addressed,
+Stood in himself collected; while each part,
+Motion, each act, won audience ere the tongue;
+Sometimes in highth began, as no delay
+Of preface brooking, through his zeal of right:
+So standing, moving, or to highth up grown,
+The Tempter, all impassioned, thus began.
+O sacred, wise, and wisdom-giving Plant,
+Mother of science! now I feel thy power
+Within me clear; not only to discern
+Things in their causes, but to trace the ways
+Of highest agents, deemed however wise.
+Queen of this universe! do not believe
+Those rigid threats of death: ye shall not die:
+How should you? by the fruit? it gives you life
+To knowledge; by the threatener? look on me,
+Me, who have touched and tasted; yet both live,
+And life more perfect have attained than Fate
+Meant me, by venturing higher than my lot.
+Shall that be shut to Man, which to the Beast
+Is open? or will God incense his ire
+For such a petty trespass? and not praise
+Rather your dauntless virtue, whom the pain
+Of death denounced, whatever thing death be,
+Deterred not from achieving what might lead
+To happier life, knowledge of good and evil;
+Of good, how just? of evil, if what is evil
+Be real, why not known, since easier shunned?
+God therefore cannot hurt ye, and be just;
+Not just, not God; not feared then, nor obeyed:
+Your fear itself of death removes the fear.
+Why then was this forbid? Why, but to awe;
+Why, but to keep ye low and ignorant,
+His worshippers? He knows that in the day
+Ye eat thereof, your eyes that seem so clear,
+Yet are but dim, shall perfectly be then
+Opened and cleared, and ye shall be as Gods,
+Knowing both good and evil, as they know.
+That ye shall be as Gods, since I as Man,
+Internal Man, is but proportion meet;
+I, of brute, human; ye, of human, Gods.
+So ye shall die perhaps, by putting off
+Human, to put on Gods; death to be wished,
+Though threatened, which no worse than this can bring.
+And what are Gods, that Man may not become
+As they, participating God-like food?
+The Gods are first, and that advantage use
+On our belief, that all from them proceeds:
+I question it; for this fair earth I see,
+Warmed by the sun, producing every kind;
+Them, nothing: if they all things, who enclosed
+Knowledge of good and evil in this tree,
+That whoso eats thereof, forthwith attains
+Wisdom without their leave? and wherein lies
+The offence, that Man should thus attain to know?
+What can your knowledge hurt him, or this tree
+Impart against his will, if all be his?
+Or is it envy? and can envy dwell
+In heavenly breasts? These, these, and many more
+Causes import your need of this fair fruit.
+Goddess humane, reach then, and freely taste!
+He ended; and his words, replete with guile,
+Into her heart too easy entrance won:
+Fixed on the fruit she gazed, which to behold
+Might tempt alone; and in her ears the sound
+Yet rung of his persuasive words, impregned
+With reason, to her seeming, and with truth:
+Mean while the hour of noon drew on, and waked
+An eager appetite, raised by the smell
+So savoury of that fruit, which with desire,
+Inclinable now grown to touch or taste,
+Solicited her longing eye; yet first
+Pausing a while, thus to herself she mused.
+Great are thy virtues, doubtless, best of fruits,
+Though kept from man, and worthy to be admired;
+Whose taste, too long forborn, at first assay
+Gave elocution to the mute, and taught
+The tongue not made for speech to speak thy praise:
+Thy praise he also, who forbids thy use,
+Conceals not from us, naming thee the tree
+Of knowledge, knowledge both of good and evil;
+Forbids us then to taste! but his forbidding
+Commends thee more, while it infers the good
+By thee communicated, and our want:
+For good unknown sure is not had; or, had
+And yet unknown, is as not had at all.
+In plain then, what forbids he but to know,
+Forbids us good, forbids us to be wise?
+Such prohibitions bind not. But, if death
+Bind us with after-bands, what profits then
+Our inward freedom? In the day we eat
+Of this fair fruit, our doom is, we shall die!
+How dies the Serpent? he hath eaten and lives,
+And knows, and speaks, and reasons, and discerns,
+Irrational till then. For us alone
+Was death invented? or to us denied
+This intellectual food, for beasts reserved?
+For beasts it seems: yet that one beast which first
+Hath tasted envies not, but brings with joy
+The good befallen him, author unsuspect,
+Friendly to man, far from deceit or guile.
+What fear I then? rather, what know to fear
+Under this ignorance of good and evil,
+Of God or death, of law or penalty?
+Here grows the cure of all, this fruit divine,
+Fair to the eye, inviting to the taste,
+Of virtue to make wise: What hinders then
+To reach, and feed at once both body and mind?
+So saying, her rash hand in evil hour
+Forth reaching to the fruit, she plucked, she eat!
+Earth felt the wound; and Nature from her seat,
+Sighing through all her works, gave signs of woe,
+That all was lost. Back to the thicket slunk
+The guilty Serpent; and well might;for Eve,
+Intent now wholly on her taste, nought else
+Regarded; such delight till then, as seemed,
+In fruit she never tasted, whether true
+Or fancied so, through expectation high
+Of knowledge; not was Godhead from her thought.
+Greedily she ingorged without restraint,
+And knew not eating death: Satiate at length,
+And hightened as with wine, jocund and boon,
+Thus to herself she pleasingly began.
+O sovran, virtuous, precious of all trees
+In Paradise! of operation blest
+To sapience, hitherto obscured, infamed.
+And thy fair fruit let hang, as to no end
+Created; but henceforth my early care,
+Not without song, each morning, and due praise,
+Shall tend thee, and the fertile burden ease
+Of thy full branches offered free to all;
+Till, dieted by thee, I grow mature
+In knowledge, as the Gods, who all things know;
+Though others envy what they cannot give:
+For, had the gift been theirs, it had not here
+Thus grown. Experience, next, to thee I owe,
+Best guide; not following thee, I had remained
+In ignorance; thou openest wisdom's way,
+And givest access, though secret she retire.
+And I perhaps am secret: Heaven is high,
+High, and remote to see from thence distinct
+Each thing on Earth; and other care perhaps
+May have diverted from continual watch
+Our great Forbidder, safe with all his spies
+About him. But to Adam in what sort
+Shall I appear? shall I to him make known
+As yet my change, and give him to partake
+Full happiness with me, or rather not,
+But keeps the odds of knowledge in my power
+Without copartner? so to add what wants
+In female sex, the more to draw his love,
+And render me more equal; and perhaps,
+A thing not undesirable, sometime
+Superiour; for, inferiour, who is free
+This may be well: But what if God have seen,
+And death ensue? then I shall be no more!
+And Adam, wedded to another Eve,
+Shall live with her enjoying, I extinct;
+A death to think! Confirmed then I resolve,
+Adam shall share with me in bliss or woe:
+So dear I love him, that with him all deaths
+I could endure, without him live no life.
+So saying, from the tree her step she turned;
+But first low reverence done, as to the Power
+That dwelt within, whose presence had infused
+Into the plant sciential sap, derived
+From nectar, drink of Gods. Adam the while,
+Waiting desirous her return, had wove
+Of choicest flowers a garland, to adorn
+Her tresses, and her rural labours crown;
+As reapers oft are wont their harvest-queen.
+Great joy he promised to his thoughts, and new
+Solace in her return, so long delayed:
+Yet oft his heart, divine of something ill,
+Misgave him; he the faltering measure felt;
+And forth to meet her went, the way she took
+That morn when first they parted: by the tree
+Of knowledge he must pass; there he her met,
+Scarce from the tree returning; in her hand
+A bough of fairest fruit, that downy smiled,
+New gathered, and ambrosial smell diffused.
+To him she hasted; in her face excuse
+Came prologue, and apology too prompt;
+Which, with bland words at will, she thus addressed.
+Hast thou not wondered, Adam, at my stay?
+Thee I have missed, and thought it long, deprived
+Thy presence; agony of love till now
+Not felt, nor shall be twice; for never more
+Mean I to try, what rash untried I sought,
+The pain of absence from thy sight. But strange
+Hath been the cause, and wonderful to hear:
+This tree is not, as we are told, a tree
+Of danger tasted, nor to evil unknown
+Opening the way, but of divine effect
+To open eyes, and make them Gods who taste;
+And hath been tasted such: The serpent wise,
+Or not restrained as we, or not obeying,
+Hath eaten of the fruit; and is become,
+Not dead, as we are threatened, but thenceforth
+Endued with human voice and human sense,
+Reasoning to admiration; and with me
+Persuasively hath so prevailed, that I
+Have also tasted, and have also found
+The effects to correspond; opener mine eyes,
+Dim erst, dilated spirits, ampler heart,
+And growing up to Godhead; which for thee
+Chiefly I sought, without thee can despise.
+For bliss, as thou hast part, to me is bliss;
+Tedious, unshared with thee, and odious soon.
+Thou therefore also taste, that equal lot
+May join us, equal joy, as equal love;
+Lest, thou not tasting, different degree
+Disjoin us, and I then too late renounce
+Deity for thee, when Fate will not permit.
+Thus Eve with countenance blithe her story told;
+But in her cheek distemper flushing glowed.
+On the other side Adam, soon as he heard
+The fatal trespass done by Eve, amazed,
+Astonied stood and blank, while horrour chill
+Ran through his veins, and all his joints relaxed;
+From his slack hand the garland wreathed for Eve
+Down dropt, and all the faded roses shed:
+Speechless he stood and pale, till thus at length
+First to himself he inward silence broke.
+O fairest of Creation, last and best
+Of all God's works, Creature in whom excelled
+Whatever can to sight or thought be formed,
+Holy, divine, good, amiable, or sweet!
+How art thou lost! how on a sudden lost,
+Defaced, deflowered, and now to death devote!
+Rather, how hast thou yielded to transgress
+The strict forbiddance, how to violate
+The sacred fruit forbidden! Some cursed fraud
+Of enemy hath beguiled thee, yet unknown,
+And me with thee hath ruined; for with thee
+Certain my resolution is to die:
+How can I live without thee! how forego
+Thy sweet converse, and love so dearly joined,
+To live again in these wild woods forlorn!
+Should God create another Eve, and I
+Another rib afford, yet loss of thee
+Would never from my heart: no, no!I feel
+The link of Nature draw me: flesh of flesh,
+Bone of my bone thou art, and from thy state
+Mine never shall be parted, bliss or woe.
+So having said, as one from sad dismay
+Recomforted, and after thoughts disturbed
+Submitting to what seemed remediless,
+Thus in calm mood his words to Eve he turned.
+Bold deed thou hast presumed, adventurous Eve,
+And peril great provoked, who thus hast dared,
+Had it been only coveting to eye
+That sacred fruit, sacred to abstinence,
+Much more to taste it under ban to touch.
+But past who can recall, or done undo?
+Not God Omnipotent, nor Fate; yet so
+Perhaps thou shalt not die, perhaps the fact
+Is not so heinous now, foretasted fruit,
+Profaned first by the serpent, by him first
+Made common, and unhallowed, ere our taste;
+Nor yet on him found deadly; yet he lives;
+Lives, as thou saidst, and gains to live, as Man,
+Higher degree of life; inducement strong
+To us, as likely tasting to attain
+Proportional ascent; which cannot be
+But to be Gods, or Angels, demi-Gods.
+Nor can I think that God, Creator wise,
+Though threatening, will in earnest so destroy
+Us his prime creatures, dignified so high,
+Set over all his works; which in our fall,
+For us created, needs with us must fail,
+Dependant made; so God shall uncreate,
+Be frustrate, do, undo, and labour lose;
+Not well conceived of God, who, though his power
+Creation could repeat, yet would be loth
+Us to abolish, lest the Adversary
+Triumph, and say; "Fickle their state whom God
+"Most favours; who can please him long? Me first
+"He ruined, now Mankind; whom will he next?"
+Matter of scorn, not to be given the Foe.
+However I with thee have fixed my lot,
+Certain to undergo like doom: If death
+Consort with thee, death is to me as life;
+So forcible within my heart I feel
+The bond of Nature draw me to my own;
+My own in thee, for what thou art is mine;
+Our state cannot be severed; we are one,
+One flesh; to lose thee were to lose myself.
+So Adam; and thus Eve to him replied.
+O glorious trial of exceeding love,
+Illustrious evidence, example high!
+Engaging me to emulate; but, short
+Of thy perfection, how shall I attain,
+Adam, from whose dear side I boast me sprung,
+And gladly of our union hear thee speak,
+One heart, one soul in both; whereof good proof
+This day affords, declaring thee resolved,
+Rather than death, or aught than death more dread,
+Shall separate us, linked in love so dear,
+To undergo with me one guilt, one crime,
+If any be, of tasting this fair fruit;
+Whose virtue for of good still good proceeds,
+Direct, or by occasion, hath presented
+This happy trial of thy love, which else
+So eminently never had been known?
+Were it I thought death menaced would ensue
+This my attempt, I would sustain alone
+The worst, and not persuade thee, rather die
+Deserted, than oblige thee with a fact
+Pernicious to thy peace; chiefly assured
+Remarkably so late of thy so true,
+So faithful, love unequalled: but I feel
+Far otherwise the event; not death, but life
+Augmented, opened eyes, new hopes, new joys,
+Taste so divine, that what of sweet before
+Hath touched my sense, flat seems to this, and harsh.
+On my experience, Adam, freely taste,
+And fear of death deliver to the winds.
+So saying, she embraced him, and for joy
+Tenderly wept; much won, that he his love
+Had so ennobled, as of choice to incur
+Divine displeasure for her sake, or death.
+In recompence for such compliance bad
+Such recompence best merits from the bough
+She gave him of that fair enticing fruit
+With liberal hand: he scrupled not to eat,
+Against his better knowledge; not deceived,
+But fondly overcome with female charm.
+Earth trembled from her entrails, as again
+In pangs; and Nature gave a second groan;
+Sky loured; and, muttering thunder, some sad drops
+Wept at completing of the mortal sin
+Original: while Adam took no thought,
+Eating his fill; nor Eve to iterate
+Her former trespass feared, the more to sooth
+Him with her loved society; that now,
+As with new wine intoxicated both,
+They swim in mirth, and fancy that they feel
+Divinity within them breeding wings,
+Wherewith to scorn the earth: But that false fruit
+Far other operation first displayed,
+Carnal desire inflaming; he on Eve
+Began to cast lascivious eyes; she him
+As wantonly repaid; in lust they burn:
+Till Adam thus 'gan Eve to dalliance move.
+Eve, now I see thou art exact of taste,
+And elegant, of sapience no small part;
+Since to each meaning savour we apply,
+And palate call judicious; I the praise
+Yield thee, so well this day thou hast purveyed.
+Much pleasure we have lost, while we abstained
+From this delightful fruit, nor known till now
+True relish, tasting; if such pleasure be
+In things to us forbidden, it might be wished,
+For this one tree had been forbidden ten.
+But come, so well refreshed, now let us play,
+As meet is, after such delicious fare;
+For never did thy beauty, since the day
+I saw thee first and wedded thee, adorned
+With all perfections, so inflame my sense
+With ardour to enjoy thee, fairer now
+Than ever; bounty of this virtuous tree!
+So said he, and forbore not glance or toy
+Of amorous intent; well understood
+Of Eve, whose eye darted contagious fire.
+Her hand he seised; and to a shady bank,
+Thick over-head with verdant roof imbowered,
+He led her nothing loth; flowers were the couch,
+Pansies, and violets, and asphodel,
+And hyacinth; Earth's freshest softest lap.
+There they their fill of love and love's disport
+Took largely, of their mutual guilt the seal,
+The solace of their sin; till dewy sleep
+Oppressed them, wearied with their amorous play,
+Soon as the force of that fallacious fruit,
+That with exhilarating vapour bland
+About their spirits had played, and inmost powers
+Made err, was now exhaled; and grosser sleep,
+Bred of unkindly fumes, with conscious dreams
+Incumbered, now had left them; up they rose
+As from unrest; and, each the other viewing,
+Soon found their eyes how opened, and their minds
+How darkened; innocence, that as a veil
+Had shadowed them from knowing ill, was gone;
+Just confidence, and native righteousness,
+And honour, from about them, naked left
+To guilty Shame; he covered, but his robe
+Uncovered more. So rose the Danite strong,
+Herculean Samson, from the harlot-lap
+Of Philistean Dalilah, and waked
+Shorn of his strength. They destitute and bare
+Of all their virtue: Silent, and in face
+Confounded, long they sat, as strucken mute:
+Till Adam, though not less than Eve abashed,
+At length gave utterance to these words constrained.
+O Eve, in evil hour thou didst give ear
+To that false worm, of whomsoever taught
+To counterfeit Man's voice; true in our fall,
+False in our promised rising; since our eyes
+Opened we find indeed, and find we know
+Both good and evil; good lost, and evil got;
+Bad fruit of knowledge, if this be to know;
+Which leaves us naked thus, of honour void,
+Of innocence, of faith, of purity,
+Our wonted ornaments now soiled and stained,
+And in our faces evident the signs
+Of foul concupiscence; whence evil store;
+Even shame, the last of evils; of the first
+Be sure then.--How shall I behold the face
+Henceforth of God or Angel, erst with joy
+And rapture so oft beheld? Those heavenly shapes
+Will dazzle now this earthly with their blaze
+Insufferably bright. O! might I here
+In solitude live savage; in some glade
+Obscured, where highest woods, impenetrable
+To star or sun-light, spread their umbrage broad
+And brown as evening: Cover me, ye Pines!
+Ye Cedars, with innumerable boughs
+Hide me, where I may never see them more!--
+But let us now, as in bad plight, devise
+What best may for the present serve to hide
+The parts of each from other, that seem most
+To shame obnoxious, and unseemliest seen;
+Some tree, whose broad smooth leaves together sewed,
+And girded on our loins, may cover round
+Those middle parts; that this new comer, Shame,
+There sit not, and reproach us as unclean.
+So counselled he, and both together went
+Into the thickest wood; there soon they chose
+The fig-tree; not that kind for fruit renowned,
+But such as at this day, to Indians known,
+In Malabar or Decan spreads her arms
+Branching so broad and long, that in the ground
+The bended twigs take root, and daughters grow
+About the mother tree, a pillared shade
+High over-arched, and echoing walks between:
+There oft the Indian herdsman, shunning heat,
+Shelters in cool, and tends his pasturing herds
+At loop-holes cut through thickest shade: Those leaves
+They gathered, broad as Amazonian targe;
+And, with what skill they had, together sewed,
+To gird their waist; vain covering, if to hide
+Their guilt and dreaded shame! O, how unlike
+To that first naked glory! Such of late
+Columbus found the American, so girt
+With feathered cincture; naked else, and wild
+Among the trees on isles and woody shores.
+Thus fenced, and, as they thought, their shame in part
+Covered, but not at rest or ease of mind,
+They sat them down to weep; nor only tears
+Rained at their eyes, but high winds worse within
+Began to rise, high passions, anger, hate,
+Mistrust, suspicion, discord; and shook sore
+Their inward state of mind, calm region once
+And full of peace, now tost and turbulent:
+For Understanding ruled not, and the Will
+Heard not her lore; both in subjection now
+To sensual Appetite, who from beneath
+Usurping over sovran Reason claimed
+Superiour sway: From thus distempered breast,
+Adam, estranged in look and altered style,
+Speech intermitted thus to Eve renewed.
+Would thou hadst hearkened to my words, and staid
+With me, as I besought thee, when that strange
+Desire of wandering, this unhappy morn,
+I know not whence possessed thee; we had then
+Remained still happy; not, as now, despoiled
+Of all our good; shamed, naked, miserable!
+Let none henceforth seek needless cause to approve
+The faith they owe; when earnestly they seek
+Such proof, conclude, they then begin to fail.
+To whom, soon moved with touch of blame, thus Eve.
+What words have passed thy lips, Adam severe!
+Imputest thou that to my default, or will
+Of wandering, as thou callest it, which who knows
+But might as ill have happened thou being by,
+Or to thyself perhaps? Hadst thou been there,
+Or here the attempt, thou couldst not have discerned
+Fraud in the Serpent, speaking as he spake;
+No ground of enmity between us known,
+Why he should mean me ill, or seek to harm.
+Was I to have never parted from thy side?
+As good have grown there still a lifeless rib.
+Being as I am, why didst not thou, the head,
+Command me absolutely not to go,
+Going into such danger, as thou saidst?
+Too facile then, thou didst not much gainsay;
+Nay, didst permit, approve, and fair dismiss.
+Hadst thou been firm and fixed in thy dissent,
+Neither had I transgressed, nor thou with me.
+To whom, then first incensed, Adam replied.
+Is this the love, is this the recompence
+Of mine to thee, ingrateful Eve! expressed
+Immutable, when thou wert lost, not I;
+Who might have lived, and joyed immortal bliss,
+Yet willingly chose rather death with thee?
+And am I now upbraided as the cause
+Of thy transgressing? Not enough severe,
+It seems, in thy restraint: What could I more
+I warned thee, I admonished thee, foretold
+The danger, and the lurking enemy
+That lay in wait; beyond this, had been force;
+And force upon free will hath here no place.
+But confidence then bore thee on; secure
+Either to meet no danger, or to find
+Matter of glorious trial; and perhaps
+I also erred, in overmuch admiring
+What seemed in thee so perfect, that I thought
+No evil durst attempt thee; but I rue
+The errour now, which is become my crime,
+And thou the accuser. Thus it shall befall
+Him, who, to worth in women overtrusting,
+Lets her will rule: restraint she will not brook;
+And, left to herself, if evil thence ensue,
+She first his weak indulgence will accuse.
+Thus they in mutual accusation spent
+The fruitless hours, but neither self-condemning;
+And of their vain contest appeared no end.
+
+
+
+Book X
+
+
+Mean while the heinous and despiteful act
+Of Satan, done in Paradise; and how
+He, in the serpent, had perverted Eve,
+Her husband she, to taste the fatal fruit,
+Was known in Heaven; for what can 'scape the eye
+Of God all-seeing, or deceive his heart
+Omniscient? who, in all things wise and just,
+Hindered not Satan to attempt the mind
+Of Man, with strength entire and free will armed,
+Complete to have discovered and repulsed
+Whatever wiles of foe or seeming friend.
+For still they knew, and ought to have still remembered,
+The high injunction, not to taste that fruit,
+Whoever tempted; which they not obeying,
+(Incurred what could they less?) the penalty;
+And, manifold in sin, deserved to fall.
+Up into Heaven from Paradise in haste
+The angelick guards ascended, mute, and sad,
+For Man; for of his state by this they knew,
+Much wondering how the subtle Fiend had stolen
+Entrance unseen. Soon as the unwelcome news
+From Earth arrived at Heaven-gate, displeased
+All were who heard; dim sadness did not spare
+That time celestial visages, yet, mixed
+With pity, violated not their bliss.
+About the new-arrived, in multitudes
+The ethereal people ran, to hear and know
+How all befel: They towards the throne supreme,
+Accountable, made haste, to make appear,
+With righteous plea, their utmost vigilance
+And easily approved; when the Most High
+Eternal Father, from his secret cloud,
+Amidst in thunder uttered thus his voice.
+Assembled Angels, and ye Powers returned
+From unsuccessful charge; be not dismayed,
+Nor troubled at these tidings from the earth,
+Which your sincerest care could not prevent;
+Foretold so lately what would come to pass,
+When first this tempter crossed the gulf from Hell.
+I told ye then he should prevail, and speed
+On his bad errand; Man should be seduced,
+And flattered out of all, believing lies
+Against his Maker; no decree of mine
+Concurring to necessitate his fall,
+Or touch with lightest moment of impulse
+His free will, to her own inclining left
+In even scale. But fallen he is; and now
+What rests, but that the mortal sentence pass
+On his transgression,--death denounced that day?
+Which he presumes already vain and void,
+Because not yet inflicted, as he feared,
+By some immediate stroke; but soon shall find
+Forbearance no acquittance, ere day end.
+Justice shall not return as bounty scorned.
+But whom send I to judge them? whom but thee,
+Vicegerent Son? To thee I have transferred
+All judgement, whether in Heaven, or Earth, or Hell.
+Easy it may be seen that I intend
+Mercy colleague with justice, sending thee
+Man's friend, his Mediator, his designed
+Both ransom and Redeemer voluntary,
+And destined Man himself to judge Man fallen.
+So spake the Father; and, unfolding bright
+Toward the right hand his glory, on the Son
+Blazed forth unclouded Deity: He full
+Resplendent all his Father manifest
+Expressed, and thus divinely answered mild.
+Father Eternal, thine is to decree;
+Mine, both in Heaven and Earth, to do thy will
+Supreme; that thou in me, thy Son beloved,
+Mayest ever rest well pleased. I go to judge
+On earth these thy transgressours; but thou knowest,
+Whoever judged, the worst on me must light,
+When time shall be; for so I undertook
+Before thee; and, not repenting, this obtain
+Of right, that I may mitigate their doom
+On me derived; yet I shall temper so
+Justice with mercy, as may illustrate most
+Them fully satisfied, and thee appease.
+Attendance none shall need, nor train, where none
+Are to behold the judgement, but the judged,
+Those two; the third best absent is condemned,
+Convict by flight, and rebel to all law:
+Conviction to the serpent none belongs.
+Thus saying, from his radiant seat he rose
+Of high collateral glory: Him Thrones, and Powers,
+Princedoms, and Dominations ministrant,
+Accompanied to Heaven-gate; from whence
+Eden, and all the coast, in prospect lay.
+Down he descended straight; the speed of Gods
+Time counts not, though with swiftest minutes winged.
+Now was the sun in western cadence low
+From noon, and gentle airs, due at their hour,
+To fan the earth now waked, and usher in
+The evening cool; when he, from wrath more cool,
+Came the mild Judge, and Intercessour both,
+To sentence Man: The voice of God they heard
+Now walking in the garden, by soft winds
+Brought to their ears, while day declined; they heard,
+And from his presence hid themselves among
+The thickest trees, both man and wife; till God,
+Approaching, thus to Adam called aloud.
+Where art thou, Adam, wont with joy to meet
+My coming seen far off? I miss thee here,
+Not pleased, thus entertained with solitude,
+Where obvious duty ere while appeared unsought:
+Or come I less conspicuous, or what change
+Absents thee, or what chance detains?--Come forth!
+He came; and with him Eve, more loth, though first
+To offend; discountenanced both, and discomposed;
+Love was not in their looks, either to God,
+Or to each other; but apparent guilt,
+And shame, and perturbation, and despair,
+Anger, and obstinacy, and hate, and guile.
+Whence Adam, faltering long, thus answered brief.
+I heard thee in the garden, and of thy voice
+Afraid, being naked, hid myself. To whom
+The gracious Judge without revile replied.
+My voice thou oft hast heard, and hast not feared,
+But still rejoiced; how is it now become
+So dreadful to thee? That thou art naked, who
+Hath told thee? Hast thou eaten of the tree,
+Whereof I gave thee charge thou shouldst not eat?
+To whom thus Adam sore beset replied.
+O Heaven! in evil strait this day I stand
+Before my Judge; either to undergo
+Myself the total crime, or to accuse
+My other self, the partner of my life;
+Whose failing, while her faith to me remains,
+I should conceal, and not expose to blame
+By my complaint: but strict necessity
+Subdues me, and calamitous constraint;
+Lest on my head both sin and punishment,
+However insupportable, be all
+Devolved; though should I hold my peace, yet thou
+Wouldst easily detect what I conceal.--
+This Woman, whom thou madest to be my help,
+And gavest me as thy perfect gift, so good,
+So fit, so acceptable, so divine,
+That from her hand I could suspect no ill,
+And what she did, whatever in itself,
+Her doing seemed to justify the deed;
+She gave me of the tree, and I did eat.
+To whom the Sovran Presence thus replied.
+Was she thy God, that her thou didst obey
+Before his voice? or was she made thy guide,
+Superiour, or but equal, that to her
+Thou didst resign thy manhood, and the place
+Wherein God set thee above her made of thee,
+And for thee, whose perfection far excelled
+Hers in all real dignity? Adorned
+She was indeed, and lovely, to attract
+Thy love, not thy subjection; and her gifts
+Were such, as under government well seemed;
+Unseemly to bear rule; which was thy part
+And person, hadst thou known thyself aright.
+So having said, he thus to Eve in few.
+Say, Woman, what is this which thou hast done?
+To whom sad Eve, with shame nigh overwhelmed,
+Confessing soon, yet not before her Judge
+Bold or loquacious, thus abashed replied.
+The Serpent me beguiled, and I did eat.
+Which when the Lord God heard, without delay
+To judgement he proceeded on the accused
+Serpent, though brute; unable to transfer
+The guilt on him, who made him instrument
+Of mischief, and polluted from the end
+Of his creation; justly then accursed,
+As vitiated in nature: More to know
+Concerned not Man, (since he no further knew)
+Nor altered his offence; yet God at last
+To Satan first in sin his doom applied,
+Though in mysterious terms, judged as then best:
+And on the Serpent thus his curse let fall.
+Because thou hast done this, thou art accursed
+Above all cattle, each beast of the field;
+Upon thy belly groveling thou shalt go,
+And dust shalt eat all the days of thy life.
+Between thee and the woman I will put
+Enmity, and between thine and her seed;
+Her seed shall bruise thy head, thou bruise his heel.
+So spake this oracle, then verified
+When Jesus, Son of Mary, second Eve,
+Saw Satan fall, like lightning, down from Heaven,
+Prince of the air; then, rising from his grave
+Spoiled Principalities and Powers, triumphed
+In open show; and, with ascension bright,
+Captivity led captive through the air,
+The realm itself of Satan, long usurped;
+Whom he shall tread at last under our feet;
+Even he, who now foretold his fatal bruise;
+And to the Woman thus his sentence turned.
+Thy sorrow I will greatly multiply
+By thy conception; children thou shalt bring
+In sorrow forth; and to thy husband's will
+Thine shall submit; he over thee shall rule.
+On Adam last thus judgement he pronounced.
+Because thou hast hearkened to the voice of thy wife,
+And eaten of the tree, concerning which
+I charged thee, saying, Thou shalt not eat thereof:
+Cursed is the ground for thy sake; thou in sorrow
+Shalt eat thereof, all the days of thy life;
+Thorns also and thistles it shall bring thee forth
+Unbid; and thou shalt eat the herb of the field;
+In the sweat of thy face shalt thou eat bread,
+Till thou return unto the ground; for thou
+Out of the ground wast taken, know thy birth,
+For dust thou art, and shalt to dust return.
+So judged he Man, both Judge and Saviour sent;
+And the instant stroke of death, denounced that day,
+Removed far off; then, pitying how they stood
+Before him naked to the air, that now
+Must suffer change, disdained not to begin
+Thenceforth the form of servant to assume;
+As when he washed his servants feet; so now,
+As father of his family, he clad
+Their nakedness with skins of beasts, or slain,
+Or as the snake with youthful coat repaid;
+And thought not much to clothe his enemies;
+Nor he their outward only with the skins
+Of beasts, but inward nakedness, much more.
+Opprobrious, with his robe of righteousness,
+Arraying, covered from his Father's sight.
+To him with swift ascent he up returned,
+Into his blissful bosom reassumed
+In glory, as of old; to him appeased
+All, though all-knowing, what had passed with Man
+Recounted, mixing intercession sweet.
+Mean while, ere thus was sinned and judged on Earth,
+Within the gates of Hell sat Sin and Death,
+In counterview within the gates, that now
+Stood open wide, belching outrageous flame
+Far into Chaos, since the Fiend passed through,
+Sin opening; who thus now to Death began.
+O Son, why sit we here each other viewing
+Idly, while Satan, our great author, thrives
+In other worlds, and happier seat provides
+For us, his offspring dear? It cannot be
+But that success attends him; if mishap,
+Ere this he had returned, with fury driven
+By his avengers; since no place like this
+Can fit his punishment, or their revenge.
+Methinks I feel new strength within me rise,
+Wings growing, and dominion given me large
+Beyond this deep; whatever draws me on,
+Or sympathy, or some connatural force,
+Powerful at greatest distance to unite,
+With secret amity, things of like kind,
+By secretest conveyance. Thou, my shade
+Inseparable, must with me along;
+For Death from Sin no power can separate.
+But, lest the difficulty of passing back
+Stay his return perhaps over this gulf
+Impassable, impervious; let us try
+Adventurous work, yet to thy power and mine
+Not unagreeable, to found a path
+Over this main from Hell to that new world,
+Where Satan now prevails; a monument
+Of merit high to all the infernal host,
+Easing their passage hence, for intercourse,
+Or transmigration, as their lot shall lead.
+Nor can I miss the way, so strongly drawn
+By this new-felt attraction and instinct.
+Whom thus the meager Shadow answered soon.
+Go, whither Fate, and inclination strong,
+Leads thee; I shall not lag behind, nor err
+The way, thou leading; such a scent I draw
+Of carnage, prey innumerable, and taste
+The savour of death from all things there that live:
+Nor shall I to the work thou enterprisest
+Be wanting, but afford thee equal aid.
+So saying, with delight he snuffed the smell
+Of mortal change on earth. As when a flock
+Of ravenous fowl, though many a league remote,
+Against the day of battle, to a field,
+Where armies lie encamped, come flying, lured
+With scent of living carcasses designed
+For death, the following day, in bloody fight:
+So scented the grim Feature, and upturned
+His nostril wide into the murky air;
+Sagacious of his quarry from so far.
+Then both from out Hell-gates, into the waste
+Wide anarchy of Chaos, damp and dark,
+Flew diverse; and with power (their power was great)
+Hovering upon the waters, what they met
+Solid or slimy, as in raging sea
+Tost up and down, together crouded drove,
+From each side shoaling towards the mouth of Hell;
+As when two polar winds, blowing adverse
+Upon the Cronian sea, together drive
+Mountains of ice, that stop the imagined way
+Beyond Petsora eastward, to the rich
+Cathaian coast. The aggregated soil
+Death with his mace petrifick, cold and dry,
+As with a trident, smote; and fixed as firm
+As Delos, floating once; the rest his look
+Bound with Gorgonian rigour not to move;
+And with Asphaltick slime, broad as the gate,
+Deep to the roots of Hell the gathered beach
+They fastened, and the mole immense wrought on
+Over the foaming deep high-arched, a bridge
+Of length prodigious, joining to the wall
+Immoveable of this now fenceless world,
+Forfeit to Death; from hence a passage broad,
+Smooth, easy, inoffensive, down to Hell.
+So, if great things to small may be compared,
+Xerxes, the liberty of Greece to yoke,
+From Susa, his Memnonian palace high,
+Came to the sea: and, over Hellespont
+Bridging his way, Europe with Asia joined,
+And scourged with many a stroke the indignant waves.
+Now had they brought the work by wonderous art
+Pontifical, a ridge of pendant rock,
+Over the vexed abyss, following the track
+Of Satan to the self-same place where he
+First lighted from his wing, and landed safe
+From out of Chaos, to the outside bare
+Of this round world: With pins of adamant
+And chains they made all fast, too fast they made
+And durable! And now in little space
+The confines met of empyrean Heaven,
+And of this World; and, on the left hand, Hell
+With long reach interposed; three several ways
+In sight, to each of these three places led.
+And now their way to Earth they had descried,
+To Paradise first tending; when, behold!
+Satan, in likeness of an Angel bright,
+Betwixt the Centaur and the Scorpion steering
+His zenith, while the sun in Aries rose:
+Disguised he came; but those his children dear
+Their parent soon discerned, though in disguise.
+He, after Eve seduced, unminded slunk
+Into the wood fast by; and, changing shape,
+To observe the sequel, saw his guileful act
+By Eve, though all unweeting, seconded
+Upon her husband; saw their shame that sought
+Vain covertures; but when he saw descend
+The Son of God to judge them, terrified
+He fled; not hoping to escape, but shun
+The present; fearing, guilty, what his wrath
+Might suddenly inflict; that past, returned
+By night, and listening where the hapless pair
+Sat in their sad discourse, and various plaint,
+Thence gathered his own doom; which understood
+Not instant, but of future time, with joy
+And tidings fraught, to Hell he now returned;
+And at the brink of Chaos, near the foot
+Of this new wonderous pontifice, unhoped
+Met, who to meet him came, his offspring dear.
+Great joy was at their meeting, and at sight
+Of that stupendious bridge his joy encreased.
+Long he admiring stood, till Sin, his fair
+Enchanting daughter, thus the silence broke.
+O Parent, these are thy magnifick deeds,
+Thy trophies! which thou viewest as not thine own;
+Thou art their author, and prime architect:
+For I no sooner in my heart divined,
+My heart, which by a secret harmony
+Still moves with thine, joined in connexion sweet,
+That thou on earth hadst prospered, which thy looks
+Now also evidence, but straight I felt,
+Though distant from thee worlds between, yet felt,
+That I must after thee, with this thy son;
+Such fatal consequence unites us three!
+Hell could no longer hold us in our bounds,
+Nor this unvoyageable gulf obscure
+Detain from following thy illustrious track.
+Thou hast achieved our liberty, confined
+Within Hell-gates till now; thou us impowered
+To fortify thus far, and overlay,
+With this portentous bridge, the dark abyss.
+Thine now is all this world; thy virtue hath won
+What thy hands builded not; thy wisdom gained
+With odds what war hath lost, and fully avenged
+Our foil in Heaven; here thou shalt monarch reign,
+There didst not; there let him still victor sway,
+As battle hath adjudged; from this new world
+Retiring, by his own doom alienated;
+And henceforth monarchy with thee divide
+Of all things, parted by the empyreal bounds,
+His quadrature, from thy orbicular world;
+Or try thee now more dangerous to his throne.
+Whom thus the Prince of darkness answered glad.
+Fair Daughter, and thou Son and Grandchild both;
+High proof ye now have given to be the race
+Of Satan (for I glory in the name,
+Antagonist of Heaven's Almighty King,)
+Amply have merited of me, of all
+The infernal empire, that so near Heaven's door
+Triumphal with triumphal act have met,
+Mine, with this glorious work; and made one realm,
+Hell and this world, one realm, one continent
+Of easy thorough-fare. Therefore, while I
+Descend through darkness, on your road with ease,
+To my associate Powers, them to acquaint
+With these successes, and with them rejoice;
+You two this way, among these numerous orbs,
+All yours, right down to Paradise descend;
+There dwell, and reign in bliss; thence on the earth
+Dominion exercise and in the air,
+Chiefly on Man, sole lord of all declared;
+Him first make sure your thrall, and lastly kill.
+My substitutes I send ye, and create
+Plenipotent on earth, of matchless might
+Issuing from me: on your joint vigour now
+My hold of this new kingdom all depends,
+Through Sin to Death exposed by my exploit.
+If your joint power prevail, the affairs of Hell
+No detriment need fear; go, and be strong!
+So saying he dismissed them; they with speed
+Their course through thickest constellations held,
+Spreading their bane; the blasted stars looked wan,
+And planets, planet-struck, real eclipse
+Then suffered. The other way Satan went down
+The causey to Hell-gate: On either side
+Disparted Chaos overbuilt exclaimed,
+And with rebounding surge the bars assailed,
+That scorned his indignation: Through the gate,
+Wide open and unguarded, Satan passed,
+And all about found desolate; for those,
+Appointed to sit there, had left their charge,
+Flown to the upper world; the rest were all
+Far to the inland retired, about the walls
+Of Pandemonium; city and proud seat
+Of Lucifer, so by allusion called
+Of that bright star to Satan paragoned;
+There kept their watch the legions, while the Grand
+In council sat, solicitous what chance
+Might intercept their emperour sent; so he
+Departing gave command, and they observed.
+As when the Tartar from his Russian foe,
+By Astracan, over the snowy plains,
+Retires; or Bactrin Sophi, from the horns
+Of Turkish crescent, leaves all waste beyond
+The realm of Aladule, in his retreat
+To Tauris or Casbeen: So these, the late
+Heaven-banished host, left desart utmost Hell
+Many a dark league, reduced in careful watch
+Round their metropolis; and now expecting
+Each hour their great adventurer, from the search
+Of foreign worlds: He through the midst unmarked,
+In show plebeian Angel militant
+Of lowest order, passed; and from the door
+Of that Plutonian hall, invisible
+Ascended his high throne; which, under state
+Of richest texture spread, at the upper end
+Was placed in regal lustre. Down a while
+He sat, and round about him saw unseen:
+At last, as from a cloud, his fulgent head
+And shape star-bright appeared, or brighter; clad
+With what permissive glory since his fall
+Was left him, or false glitter: All amazed
+At that so sudden blaze the Stygian throng
+Bent their aspect, and whom they wished beheld,
+Their mighty Chief returned: loud was the acclaim:
+Forth rushed in haste the great consulting peers,
+Raised from their dark Divan, and with like joy
+Congratulant approached him; who with hand
+Silence, and with these words attention, won.
+Thrones, Dominations, Princedoms, Virtues, Powers;
+For in possession such, not only of right,
+I call ye, and declare ye now; returned
+Successful beyond hope, to lead ye forth
+Triumphant out of this infernal pit
+Abominable, accursed, the house of woe,
+And dungeon of our tyrant: Now possess,
+As Lords, a spacious world, to our native Heaven
+Little inferiour, by my adventure hard
+With peril great achieved. Long were to tell
+What I have done; what suffered;with what pain
+Voyaged th' unreal, vast, unbounded deep
+Of horrible confusion; over which
+By Sin and Death a broad way now is paved,
+To expedite your glorious march; but I
+Toiled out my uncouth passage, forced to ride
+The untractable abyss, plunged in the womb
+Of unoriginal Night and Chaos wild;
+That, jealous of their secrets, fiercely opposed
+My journey strange, with clamorous uproar
+Protesting Fate supreme; thence how I found
+The new created world, which fame in Heaven
+Long had foretold, a fabrick wonderful
+Of absolute perfection! therein Man
+Placed in a Paradise, by our exile
+Made happy: Him by fraud I have seduced
+From his Creator; and, the more to encrease
+Your wonder, with an apple; he, thereat
+Offended, worth your laughter! hath given up
+Both his beloved Man, and all his world,
+To Sin and Death a prey, and so to us,
+Without our hazard, labour, or alarm;
+To range in, and to dwell, and over Man
+To rule, as over all he should have ruled.
+True is, me also he hath judged, or rather
+Me not, but the brute serpent in whose shape
+Man I deceived: that which to me belongs,
+Is enmity which he will put between
+Me and mankind; I am to bruise his heel;
+His seed, when is not set, shall bruise my head:
+A world who would not purchase with a bruise,
+Or much more grievous pain?--Ye have the account
+Of my performance: What remains, ye Gods,
+But up, and enter now into full bliss?
+So having said, a while he stood, expecting
+Their universal shout, and high applause,
+To fill his ear; when, contrary, he hears
+On all sides, from innumerable tongues,
+A dismal universal hiss, the sound
+Of publick scorn; he wondered, but not long
+Had leisure, wondering at himself now more,
+His visage drawn he felt to sharp and spare;
+His arms clung to his ribs; his legs entwining
+Each other, till supplanted down he fell
+A monstrous serpent on his belly prone,
+Reluctant, but in vain; a greater power
+Now ruled him, punished in the shape he sinned,
+According to his doom: he would have spoke,
+But hiss for hiss returned with forked tongue
+To forked tongue; for now were all transformed
+Alike, to serpents all, as accessories
+To his bold riot: Dreadful was the din
+Of hissing through the hall, thick swarming now
+With complicated monsters head and tail,
+Scorpion, and Asp, and Amphisbaena dire,
+Cerastes horned, Hydrus, and Elops drear,
+And Dipsas; (not so thick swarmed once the soil
+Bedropt with blood of Gorgon, or the isle
+Ophiusa,) but still greatest he the midst,
+Now Dragon grown, larger than whom the sun
+Ingendered in the Pythian vale or slime,
+Huge Python, and his power no less he seemed
+Above the rest still to retain; they all
+Him followed, issuing forth to the open field,
+Where all yet left of that revolted rout,
+Heaven-fallen, in station stood or just array;
+Sublime with expectation when to see
+In triumph issuing forth their glorious Chief;
+They saw, but other sight instead! a croud
+Of ugly serpents; horrour on them fell,
+And horrid sympathy; for, what they saw,
+They felt themselves, now changing; down their arms,
+Down fell both spear and shield; down they as fast;
+And the dire hiss renewed, and the dire form
+Catched, by contagion; like in punishment,
+As in their crime. Thus was the applause they meant,
+Turned to exploding hiss, triumph to shame
+Cast on themselves from their own mouths. There stood
+A grove hard by, sprung up with this their change,
+His will who reigns above, to aggravate
+Their penance, laden with fair fruit, like that
+Which grew in Paradise, the bait of Eve
+Used by the Tempter: on that prospect strange
+Their earnest eyes they fixed, imagining
+For one forbidden tree a multitude
+Now risen, to work them further woe or shame;
+Yet, parched with scalding thirst and hunger fierce,
+Though to delude them sent, could not abstain;
+But on they rolled in heaps, and, up the trees
+Climbing, sat thicker than the snaky locks
+That curled Megaera: greedily they plucked
+The fruitage fair to sight, like that which grew
+Near that bituminous lake where Sodom flamed;
+This more delusive, not the touch, but taste
+Deceived; they, fondly thinking to allay
+Their appetite with gust, instead of fruit
+Chewed bitter ashes, which the offended taste
+With spattering noise rejected: oft they assayed,
+Hunger and thirst constraining; drugged as oft,
+With hatefullest disrelish writhed their jaws,
+With soot and cinders filled; so oft they fell
+Into the same illusion, not as Man
+Whom they triumphed once lapsed. Thus were they plagued
+And worn with famine, long and ceaseless hiss,
+Till their lost shape, permitted, they resumed;
+Yearly enjoined, some say, to undergo,
+This annual humbling certain numbered days,
+To dash their pride, and joy, for Man seduced.
+However, some tradition they dispersed
+Among the Heathen, of their purchase got,
+And fabled how the Serpent, whom they called
+Ophion, with Eurynome, the wide--
+Encroaching Eve perhaps, had first the rule
+Of high Olympus; thence by Saturn driven
+And Ops, ere yet Dictaean Jove was born.
+Mean while in Paradise the hellish pair
+Too soon arrived; Sin, there in power before,
+Once actual; now in body, and to dwell
+Habitual habitant; behind her Death,
+Close following pace for pace, not mounted yet
+On his pale horse: to whom Sin thus began.
+Second of Satan sprung, all-conquering Death!
+What thinkest thou of our empire now, though earned
+With travel difficult, not better far
+Than still at Hell's dark threshold to have sat watch,
+Unnamed, undreaded, and thyself half starved?
+Whom thus the Sin-born monster answered soon.
+To me, who with eternal famine pine,
+Alike is Hell, or Paradise, or Heaven;
+There best, where most with ravine I may meet;
+Which here, though plenteous, all too little seems
+To stuff this maw, this vast unhide-bound corps.
+To whom the incestuous mother thus replied.
+Thou therefore on these herbs, and fruits, and flowers,
+Feed first; on each beast next, and fish, and fowl;
+No homely morsels! and, whatever thing
+The sithe of Time mows down, devour unspared;
+Till I, in Man residing, through the race,
+His thoughts, his looks, words, actions, all infect;
+And season him thy last and sweetest prey.
+This said, they both betook them several ways,
+Both to destroy, or unimmortal make
+All kinds, and for destruction to mature
+Sooner or later; which the Almighty seeing,
+From his transcendent seat the Saints among,
+To those bright Orders uttered thus his voice.
+See, with what heat these dogs of Hell advance
+To waste and havock yonder world, which I
+So fair and good created; and had still
+Kept in that state, had not the folly of Man
+Let in these wasteful furies, who impute
+Folly to me; so doth the Prince of Hell
+And his adherents, that with so much ease
+I suffer them to enter and possess
+A place so heavenly; and, conniving, seem
+To gratify my scornful enemies,
+That laugh, as if, transported with some fit
+Of passion, I to them had quitted all,
+At random yielded up to their misrule;
+And know not that I called, and drew them thither,
+My Hell-hounds, to lick up the draff and filth
+Which Man's polluting sin with taint hath shed
+On what was pure; til, crammed and gorged, nigh burst
+With sucked and glutted offal, at one sling
+Of thy victorious arm, well-pleasing Son,
+Both Sin, and Death, and yawning Grave, at last,
+Through Chaos hurled, obstruct the mouth of Hell
+For ever, and seal up his ravenous jaws.
+Then Heaven and Earth renewed shall be made pure
+To sanctity, that shall receive no stain:
+Till then, the curse pronounced on both precedes.
+He ended, and the heavenly audience loud
+Sung Halleluiah, as the sound of seas,
+Through multitude that sung: Just are thy ways,
+Righteous are thy decrees on all thy works;
+Who can extenuate thee? Next, to the Son,
+Destined Restorer of mankind, by whom
+New Heaven and Earth shall to the ages rise,
+Or down from Heaven descend.--Such was their song;
+While the Creator, calling forth by name
+His mighty Angels, gave them several charge,
+As sorted best with present things. The sun
+Had first his precept so to move, so shine,
+As might affect the earth with cold and heat
+Scarce tolerable; and from the north to call
+Decrepit winter; from the south to bring
+Solstitial summer's heat. To the blanc moon
+Her office they prescribed; to the other five
+Their planetary motions, and aspects,
+In sextile, square, and trine, and opposite,
+Of noxious efficacy, and when to join
+In synod unbenign; and taught the fixed
+Their influence malignant when to shower,
+Which of them rising with the sun, or falling,
+Should prove tempestuous: To the winds they set
+Their corners, when with bluster to confound
+Sea, air, and shore; the thunder when to roll
+With terrour through the dark aereal hall.
+Some say, he bid his Angels turn ascanse
+The poles of earth, twice ten degrees and more,
+From the sun's axle; they with labour pushed
+Oblique the centrick globe: Some say, the sun
+Was bid turn reins from the equinoctial road
+Like distant breadth to Taurus with the seven
+Atlantick Sisters, and the Spartan Twins,
+Up to the Tropick Crab: thence down amain
+By Leo, and the Virgin, and the Scales,
+As deep as Capricorn; to bring in change
+Of seasons to each clime; else had the spring
+Perpetual smiled on earth with vernant flowers,
+Equal in days and nights, except to those
+Beyond the polar circles; to them day
+Had unbenighted shone, while the low sun,
+To recompense his distance, in their sight
+Had rounded still the horizon, and not known
+Or east or west; which had forbid the snow
+From cold Estotiland, and south as far
+Beneath Magellan. At that tasted fruit
+The sun, as from Thyestean banquet, turned
+His course intended; else, how had the world
+Inhabited, though sinless, more than now,
+Avoided pinching cold and scorching heat?
+These changes in the Heavens, though slow, produced
+Like change on sea and land; sideral blast,
+Vapour, and mist, and exhalation hot,
+Corrupt and pestilent: Now from the north
+Of Norumbega, and the Samoed shore,
+Bursting their brazen dungeon, armed with ice,
+And snow, and hail, and stormy gust and flaw,
+Boreas, and Caecias, and Argestes loud,
+And Thrascias, rend the woods, and seas upturn;
+With adverse blast upturns them from the south
+Notus, and Afer black with thunderous clouds
+From Serraliona; thwart of these, as fierce,
+Forth rush the Levant and the Ponent winds,
+Eurus and Zephyr, with their lateral noise,
+Sirocco and Libecchio. Thus began
+Outrage from lifeless things; but Discord first,
+Daughter of Sin, among the irrational
+Death introduced, through fierce antipathy:
+Beast now with beast 'gan war, and fowl with fowl,
+And fish with fish; to graze the herb all leaving,
+Devoured each other; nor stood much in awe
+Of Man, but fled him; or, with countenance grim,
+Glared on him passing. These were from without
+The growing miseries, which Adam saw
+Already in part, though hid in gloomiest shade,
+To sorrow abandoned, but worse felt within;
+And, in a troubled sea of passion tost,
+Thus to disburden sought with sad complaint.
+O miserable of happy! Is this the end
+Of this new glorious world, and me so late
+The glory of that glory, who now become
+Accursed, of blessed? hide me from the face
+Of God, whom to behold was then my highth
+Of happiness!--Yet well, if here would end
+The misery; I deserved it, and would bear
+My own deservings; but this will not serve:
+All that I eat or drink, or shall beget,
+Is propagated curse. O voice, once heard
+Delightfully, Encrease and multiply;
+Now death to hear! for what can I encrease,
+Or multiply, but curses on my head?
+Who of all ages to succeed, but, feeling
+The evil on him brought by me, will curse
+My head? Ill fare our ancestor impure,
+For this we may thank Adam! but his thanks
+Shall be the execration: so, besides
+Mine own that bide upon me, all from me
+Shall with a fierce reflux on me rebound;
+On me, as on their natural center, light
+Heavy, though in their place. O fleeting joys
+Of Paradise, dear bought with lasting woes!
+Did I request thee, Maker, from my clay
+To mould me Man? did I solicit thee
+From darkness to promote me, or here place
+In this delicious garden? As my will
+Concurred not to my being, it were but right
+And equal to reduce me to my dust;
+Desirous to resign and render back
+All I received; unable to perform
+Thy terms too hard, by which I was to hold
+The good I sought not. To the loss of that,
+Sufficient penalty, why hast thou added
+The sense of endless woes? Inexplicable
+Why am I mocked with death, and lengthened out
+To deathless pain? How gladly would I meet
+Mortality my sentence, and be earth
+Insensible! How glad would lay me down
+As in my mother's lap! There I should rest,
+And sleep secure; his dreadful voice no more
+Would thunder in my ears; no fear of worse
+To me, and to my offspring, would torment me
+With cruel expectation. Yet one doubt
+Pursues me still, lest all I cannot die;
+Lest that pure breath of life, the spirit of Man
+Which God inspired, cannot together perish
+With this corporeal clod; then, in the grave,
+Or in some other dismal place, who knows
+But I shall die a living death? O thought
+Horrid, if true! Yet why? It was but breath
+Of life that sinned; what dies but what had life
+And sin? The body properly had neither,
+All of me then shall die: let this appease
+The doubt, since human reach no further knows.
+For though the Lord of all be infinite,
+Is his wrath also? Be it, Man is not so,
+But mortal doomed. How can he exercise
+Wrath without end on Man, whom death must end?
+Can he make deathless death? That were to make
+Strange contradiction, which to God himself
+Impossible is held; as argument
+Of weakness, not of power. Will he draw out,
+For anger's sake, finite to infinite,
+In punished Man, to satisfy his rigour,
+Satisfied never? That were to extend
+His sentence beyond dust and Nature's law;
+By which all causes else, according still
+To the reception of their matter, act;
+Not to the extent of their own sphere. But say
+That death be not one stroke, as I supposed,
+Bereaving sense, but endless misery
+From this day onward; which I feel begun
+Both in me, and without me; and so last
+To perpetuity;--Ay me!that fear
+Comes thundering back with dreadful revolution
+On my defenceless head; both Death and I
+Am found eternal, and incorporate both;
+Nor I on my part single; in me all
+Posterity stands cursed: Fair patrimony
+That I must leave ye, Sons! O, were I able
+To waste it all myself, and leave ye none!
+So disinherited, how would you bless
+Me, now your curse! Ah, why should all mankind,
+For one man's fault, thus guiltless be condemned,
+It guiltless? But from me what can proceed,
+But all corrupt; both mind and will depraved
+Not to do only, but to will the same
+With me? How can they then acquitted stand
+In sight of God? Him, after all disputes,
+Forced I absolve: all my evasions vain,
+And reasonings, though through mazes, lead me still
+But to my own conviction: first and last
+On me, me only, as the source and spring
+Of all corruption, all the blame lights due;
+So might the wrath! Fond wish!couldst thou support
+That burden, heavier than the earth to bear;
+Than all the world much heavier, though divided
+With that bad Woman? Thus, what thou desirest,
+And what thou fearest, alike destroys all hope
+Of refuge, and concludes thee miserable
+Beyond all past example and future;
+To Satan only like both crime and doom.
+O Conscience! into what abyss of fears
+And horrours hast thou driven me; out of which
+I find no way, from deep to deeper plunged!
+Thus Adam to himself lamented loud,
+Through the still night; not now, as ere Man fell,
+Wholesome, and cool, and mild, but with black air
+Accompanied; with damps, and dreadful gloom;
+Which to his evil conscience represented
+All things with double terrour: On the ground
+Outstretched he lay, on the cold ground; and oft
+Cursed his creation; Death as oft accused
+Of tardy execution, since denounced
+The day of his offence. Why comes not Death,
+Said he, with one thrice-acceptable stroke
+To end me? Shall Truth fail to keep her word,
+Justice Divine not hasten to be just?
+But Death comes not at call; Justice Divine
+Mends not her slowest pace for prayers or cries,
+O woods, O fountains, hillocks, dales, and bowers!
+With other echo late I taught your shades
+To answer, and resound far other song.--
+Whom thus afflicted when sad Eve beheld,
+Desolate where she sat, approaching nigh,
+Soft words to his fierce passion she assayed:
+But her with stern regard he thus repelled.
+Out of my sight, thou Serpent! That name best
+Befits thee with him leagued, thyself as false
+And hateful; nothing wants, but that thy shape,
+Like his, and colour serpentine, may show
+Thy inward fraud; to warn all creatures from thee
+Henceforth; lest that too heavenly form, pretended
+To hellish falshood, snare them! But for thee
+I had persisted happy; had not thy pride
+And wandering vanity, when least was safe,
+Rejected my forewarning, and disdained
+Not to be trusted; longing to be seen,
+Though by the Devil himself; him overweening
+To over-reach; but, with the serpent meeting,
+Fooled and beguiled; by him thou, I by thee
+To trust thee from my side; imagined wise,
+Constant, mature, proof against all assaults;
+And understood not all was but a show,
+Rather than solid virtue; all but a rib
+Crooked by nature, bent, as now appears,
+More to the part sinister, from me drawn;
+Well if thrown out, as supernumerary
+To my just number found. O! why did God,
+Creator wise, that peopled highest Heaven
+With Spirits masculine, create at last
+This novelty on earth, this fair defect
+Of nature, and not fill the world at once
+With Men, as Angels, without feminine;
+Or find some other way to generate
+Mankind? This mischief had not been befallen,
+And more that shall befall; innumerable
+Disturbances on earth through female snares,
+And strait conjunction with this sex: for either
+He never shall find out fit mate, but such
+As some misfortune brings him, or mistake;
+Or whom he wishes most shall seldom gain
+Through her perverseness, but shall see her gained
+By a far worse; or, if she love, withheld
+By parents; or his happiest choice too late
+Shall meet, already linked and wedlock-bound
+To a fell adversary, his hate or shame:
+Which infinite calamity shall cause
+To human life, and houshold peace confound.
+He added not, and from her turned; but Eve,
+Not so repulsed, with tears that ceased not flowing
+And tresses all disordered, at his feet
+Fell humble; and, embracing them, besought
+His peace, and thus proceeded in her plaint.
+Forsake me not thus, Adam! witness Heaven
+What love sincere, and reverence in my heart
+I bear thee, and unweeting have offended,
+Unhappily deceived! Thy suppliant
+I beg, and clasp thy knees; bereave me not,
+Whereon I live, thy gentle looks, thy aid,
+Thy counsel, in this uttermost distress,
+My only strength and stay: Forlorn of thee,
+Whither shall I betake me, where subsist?
+While yet we live, scarce one short hour perhaps,
+Between us two let there be peace; both joining,
+As joined in injuries, one enmity
+Against a foe by doom express assigned us,
+That cruel Serpent: On me exercise not
+Thy hatred for this misery befallen;
+On me already lost, me than thyself
+More miserable! Both have sinned;but thou
+Against God only; I against God and thee;
+And to the place of judgement will return,
+There with my cries importune Heaven; that all
+The sentence, from thy head removed, may light
+On me, sole cause to thee of all this woe;
+Me, me only, just object of his ire!
+She ended weeping; and her lowly plight,
+Immoveable, till peace obtained from fault
+Acknowledged and deplored, in Adam wrought
+Commiseration: Soon his heart relented
+Towards her, his life so late, and sole delight,
+Now at his feet submissive in distress;
+Creature so fair his reconcilement seeking,
+His counsel, whom she had displeased, his aid:
+As one disarmed, his anger all he lost,
+And thus with peaceful words upraised her soon.
+Unwary, and too desirous, as before,
+So now of what thou knowest not, who desirest
+The punishment all on thyself; alas!
+Bear thine own first, ill able to sustain
+His full wrath, whose thou feelest as yet least part,
+And my displeasure bearest so ill. If prayers
+Could alter high decrees, I to that place
+Would speed before thee, and be louder heard,
+That on my head all might be visited;
+Thy frailty and infirmer sex forgiven,
+To me committed, and by me exposed.
+But rise;--let us no more contend, nor blame
+Each other, blamed enough elsewhere; but strive
+In offices of love, how we may lighten
+Each other's burden, in our share of woe;
+Since this day's death denounced, if aught I see,
+Will prove no sudden, but a slow-paced evil;
+A long day's dying, to augment our pain;
+And to our seed (O hapless seed!) derived.
+To whom thus Eve, recovering heart, replied.
+Adam, by sad experiment I know
+How little weight my words with thee can find,
+Found so erroneous; thence by just event
+Found so unfortunate: Nevertheless,
+Restored by thee, vile as I am, to place
+Of new acceptance, hopeful to regain
+Thy love, the sole contentment of my heart
+Living or dying, from thee I will not hide
+What thoughts in my unquiet breast are risen,
+Tending to some relief of our extremes,
+Or end; though sharp and sad, yet tolerable,
+As in our evils, and of easier choice.
+If care of our descent perplex us most,
+Which must be born to certain woe, devoured
+By Death at last; and miserable it is
+To be to others cause of misery,
+Our own begotten, and of our loins to bring
+Into this cursed world a woeful race,
+That after wretched life must be at last
+Food for so foul a monster; in thy power
+It lies, yet ere conception to prevent
+The race unblest, to being yet unbegot.
+Childless thou art, childless remain: so Death
+Shall be deceived his glut, and with us two
+Be forced to satisfy his ravenous maw.
+But if thou judge it hard and difficult,
+Conversing, looking, loving, to abstain
+From love's due rights, nuptial embraces sweet;
+And with desire to languish without hope,
+Before the present object languishing
+With like desire; which would be misery
+And torment less than none of what we dread;
+Then, both ourselves and seed at once to free
+From what we fear for both, let us make short, --
+Let us seek Death; -- or, he not found, supply
+With our own hands his office on ourselves:
+Why stand we longer shivering under fears,
+That show no end but death, and have the power,
+Of many ways to die the shortest choosing,
+Destruction with destruction to destroy? --
+She ended here, or vehement despair
+Broke off the rest: so much of death her thoughts
+Had entertained, as dyed her cheeks with pale.
+But Adam, with such counsel nothing swayed,
+To better hopes his more attentive mind
+Labouring had raised; and thus to Eve replied.
+Eve, thy contempt of life and pleasure seems
+To argue in thee something more sublime
+And excellent, than what thy mind contemns;
+But self-destruction therefore sought, refutes
+That excellence thought in thee; and implies,
+Not thy contempt, but anguish and regret
+For loss of life and pleasure overloved.
+Or if thou covet death, as utmost end
+Of misery, so thinking to evade
+The penalty pronounced; doubt not but God
+Hath wiselier armed his vengeful ire, than so
+To be forestalled; much more I fear lest death,
+So snatched, will not exempt us from the pain
+We are by doom to pay; rather, such acts
+Of contumacy will provoke the Highest
+To make death in us live: Then let us seek
+Some safer resolution, which methinks
+I have in view, calling to mind with heed
+Part of our sentence, that thy seed shall bruise
+The Serpent's head; piteous amends! unless
+Be meant, whom I conjecture, our grand foe,
+Satan; who, in the serpent, hath contrived
+Against us this deceit: To crush his head
+Would be revenge indeed! which will be lost
+By death brought on ourselves, or childless days
+Resolved, as thou proposest; so our foe
+Shal 'scape his punishment ordained, and we
+Instead shall double ours upon our heads.
+No more be mentioned then of violence
+Against ourselves; and wilful barrenness,
+That cuts us off from hope; and savours only
+Rancour and pride, impatience and despite,
+Reluctance against God and his just yoke
+Laid on our necks. Remember with what mild
+And gracious temper he both heard, and judged,
+Without wrath or reviling; we expected
+Immediate dissolution, which we thought
+Was meant by death that day; when lo!to thee
+Pains only in child-bearing were foretold,
+And bringing forth; soon recompensed with joy,
+Fruit of thy womb: On me the curse aslope
+Glanced on the ground; with labour I must earn
+My bread; what harm? Idleness had been worse;
+My labour will sustain me; and, lest cold
+Or heat should injure us, his timely care
+Hath, unbesought, provided; and his hands
+Clothed us unworthy, pitying while he judged;
+How much more, if we pray him, will his ear
+Be open, and his heart to pity incline,
+And teach us further by what means to shun
+The inclement seasons, rain, ice, hail, and snow!
+Which now the sky, with various face, begins
+To show us in this mountain; while the winds
+Blow moist and keen, shattering the graceful locks
+Of these fair spreading trees; which bids us seek
+Some better shroud, some better warmth to cherish
+Our limbs benummed, ere this diurnal star
+Leave cold the night, how we his gathered beams
+Reflected may with matter sere foment;
+Or, by collision of two bodies, grind
+The air attrite to fire; as late the clouds
+Justling, or pushed with winds, rude in their shock,
+Tine the slant lightning; whose thwart flame, driven down
+Kindles the gummy bark of fir or pine;
+And sends a comfortable heat from far,
+Which might supply the sun: Such fire to use,
+And what may else be remedy or cure
+To evils which our own misdeeds have wrought,
+He will instruct us praying, and of grace
+Beseeching him; so as we need not fear
+To pass commodiously this life, sustained
+By him with many comforts, till we end
+In dust, our final rest and native home.
+What better can we do, than, to the place
+Repairing where he judged us, prostrate fall
+Before him reverent; and there confess
+Humbly our faults, and pardon beg; with tears
+Watering the ground, and with our sighs the air
+Frequenting, sent from hearts contrite, in sign
+Of sorrow unfeigned, and humiliation meek
+
+
+
+Book XI
+
+
+Undoubtedly he will relent, and turn
+From his displeasure; in whose look serene,
+When angry most he seemed and most severe,
+What else but favour, grace, and mercy, shone?
+So spake our father penitent; nor Eve
+Felt less remorse: they, forthwith to the place
+Repairing where he judged them, prostrate fell
+Before him reverent; and both confessed
+Humbly their faults, and pardon begged; with tears
+Watering the ground, and with their sighs the air
+Frequenting, sent from hearts contrite, in sign
+Of sorrow unfeigned, and humiliation meek.
+Thus they, in lowliest plight, repentant stood
+Praying; for from the mercy-seat above
+Prevenient grace descending had removed
+The stony from their hearts, and made new flesh
+Regenerate grow instead; that sighs now breathed
+Unutterable; which the Spirit of prayer
+Inspired, and winged for Heaven with speedier flight
+Than loudest oratory: Yet their port
+Not of mean suitors; nor important less
+Seemed their petition, than when the ancient pair
+In fables old, less ancient yet than these,
+Deucalion and chaste Pyrrha, to restore
+The race of mankind drowned, before the shrine
+Of Themis stood devout. To Heaven their prayers
+Flew up, nor missed the way, by envious winds
+Blown vagabond or frustrate: in they passed
+Dimensionless through heavenly doors; then clad
+With incense, where the golden altar fumed,
+By their great intercessour, came in sight
+Before the Father's throne: them the glad Son
+Presenting, thus to intercede began.
+See$ Father, what first-fruits on earth are sprung
+From thy implanted grace in Man; these sighs
+And prayers, which in this golden censer mixed
+With incense, I thy priest before thee bring;
+Fruits of more pleasing savour, from thy seed
+Sown with contrition in his heart, than those
+Which, his own hand manuring, all the trees
+Of Paradise could have produced, ere fallen
+From innocence. Now therefore, bend thine ear
+To supplication; hear his sighs, though mute;
+Unskilful with what words to pray, let me
+Interpret for him; me, his advocate
+And propitiation; all his works on me,
+Good, or not good, ingraft; my merit those
+Shall perfect, and for these my death shall pay.
+Accept me; and, in me, from these receive
+The smell of peace toward mankind: let him live
+Before thee reconciled, at least his days
+Numbered, though sad; till death, his doom, (which I
+To mitigate thus plead, not to reverse,)
+To better life shall yield him: where with me
+All my redeemed may dwell in joy and bliss;
+Made one with me, as I with thee am one.
+To whom the Father, without cloud, serene.
+All thy request for Man, accepted Son,
+Obtain; all thy request was my decree:
+But, longer in that Paradise to dwell,
+The law I gave to Nature him forbids:
+Those pure immortal elements, that know,
+No gross, no unharmonious mixture foul,
+Eject him, tainted now; and purge him off,
+As a distemper, gross, to air as gross,
+And mortal food; as may dispose him best
+For dissolution wrought by sin, that first
+Distempered all things, and of incorrupt
+Corrupted. I, at first, with two fair gifts
+Created him endowed; with happiness,
+And immortality: that fondly lost,
+This other served but to eternize woe;
+Till I provided death: so death becomes
+His final remedy; and, after life,
+Tried in sharp tribulation, and refined
+By faith and faithful works, to second life,
+Waked in the renovation of the just,
+Resigns him up with Heaven and Earth renewed.
+But let us call to synod all the Blest,
+Through Heaven's wide bounds: from them I will not hide
+My judgements; how with mankind I proceed,
+As how with peccant Angels late they saw,
+And in their state, though firm, stood more confirmed.
+He ended, and the Son gave signal high
+To the bright minister that watched; he blew
+His trumpet, heard in Oreb since perhaps
+When God descended, and perhaps once more
+To sound at general doom. The angelick blast
+Filled all the regions: from their blisful bowers
+Of amarantine shade, fountain or spring,
+By the waters of life, where'er they sat
+In fellowships of joy, the sons of light
+Hasted, resorting to the summons high;
+And took their seats; till from his throne supreme
+The Almighty thus pronounced his sovran will.
+O Sons, like one of us Man is become
+To know both good and evil, since his taste
+Of that defended fruit; but let him boast
+His knowledge of good lost, and evil got;
+Happier! had it sufficed him to have known
+Good by itself, and evil not at all.
+He sorrows now, repents, and prays contrite,
+My motions in him; longer than they move,
+His heart I know, how variable and vain,
+Self-left. Lest therefore his now bolder hand
+Reach also of the tree of life, and eat,
+And live for ever, dream at least to live
+For ever, to remove him I decree,
+And send him from the garden forth to till
+The ground whence he was taken, fitter soil.
+Michael, this my behest have thou in charge;
+Take to thee from among the Cherubim
+Thy choice of flaming warriours, lest the Fiend,
+Or in behalf of Man, or to invade
+Vacant possession, some new trouble raise:
+Haste thee, and from the Paradise of God
+Without remorse drive out the sinful pair;
+From hallowed ground the unholy; and denounce
+To them, and to their progeny, from thence
+Perpetual banishment. Yet, lest they faint
+At the sad sentence rigorously urged,
+(For I behold them softened, and with tears
+Bewailing their excess,) all terrour hide.
+If patiently thy bidding they obey,
+Dismiss them not disconsolate; reveal
+To Adam what shall come in future days,
+As I shall thee enlighten; intermix
+My covenant in the Woman's seed renewed;
+So send them forth, though sorrowing, yet in peace:
+And on the east side of the garden place,
+Where entrance up from Eden easiest climbs,
+Cherubick watch; and of a sword the flame
+Wide-waving; all approach far off to fright,
+And guard all passage to the tree of life:
+Lest Paradise a receptacle prove
+To Spirits foul, and all my trees their prey;
+With whose stolen fruit Man once more to delude.
+He ceased; and the arch-angelick Power prepared
+For swift descent; with him the cohort bright
+Of watchful Cherubim: four faces each
+Had, like a double Janus; all their shape
+Spangled with eyes more numerous than those
+Of Argus, and more wakeful than to drouse,
+Charmed with Arcadian pipe, the pastoral reed
+Of Hermes, or his opiate rod. Mean while,
+To re-salute the world with sacred light,
+Leucothea waked; and with fresh dews imbalmed
+The earth; when Adam and first matron Eve
+Had ended now their orisons, and found
+Strength added from above; new hope to spring
+Out of despair; joy, but with fear yet linked;
+Which thus to Eve his welcome words renewed.
+Eve, easily my faith admit, that all
+The good which we enjoy from Heaven descends;
+But, that from us aught should ascend to Heaven
+So prevalent as to concern the mind
+Of God high-blest, or to incline his will,
+Hard to belief may seem; yet this will prayer
+Or one short sigh of human breath, upborne
+Even to the seat of God. For since I sought
+By prayer the offended Deity to appease;
+Kneeled, and before him humbled all my heart;
+Methought I saw him placable and mild,
+Bending his ear; persuasion in me grew
+That I was heard with favour; peace returned
+Home to my breast, and to my memory
+His promise, that thy seed shall bruise our foe;
+Which, then not minded in dismay, yet now
+Assures me that the bitterness of death
+Is past, and we shall live. Whence hail to thee,
+Eve rightly called, mother of all mankind,
+Mother of all things living, since by thee
+Man is to live; and all things live for Man.
+To whom thus Eve with sad demeanour meek.
+Ill-worthy I such title should belong
+To me transgressour; who, for thee ordained
+A help, became thy snare; to me reproach
+Rather belongs, distrust, and all dispraise:
+But infinite in pardon was my Judge,
+That I, who first brought death on all, am graced
+The source of life; next favourable thou,
+Who highly thus to entitle me vouchsaf'st,
+Far other name deserving. But the field
+To labour calls us, now with sweat imposed,
+Though after sleepless night; for see!the morn,
+All unconcerned with our unrest, begins
+Her rosy progress smiling: let us forth;
+I never from thy side henceforth to stray,
+Where'er our day's work lies, though now enjoined
+Laborious, till day droop; while here we dwell,
+What can be toilsome in these pleasant walks?
+Here let us live, though in fallen state, content.
+So spake, so wished much humbled Eve; but Fate
+Subscribed not: Nature first gave signs, impressed
+On bird, beast, air; air suddenly eclipsed,
+After short blush of morn; nigh in her sight
+The bird of Jove, stooped from his aery tour,
+Two birds of gayest plume before him drove;
+Down from a hill the beast that reigns in woods,
+First hunter then, pursued a gentle brace,
+Goodliest of all the forest, hart and hind;
+Direct to the eastern gate was bent their flight.
+Adam observed, and with his eye the chase
+Pursuing, not unmoved, to Eve thus spake.
+O Eve, some further change awaits us nigh,
+Which Heaven, by these mute signs in Nature, shows
+Forerunners of his purpose; or to warn
+Us, haply too secure, of our discharge
+From penalty, because from death released
+Some days: how long, and what till then our life,
+Who knows? or more than this, that we are dust,
+And thither must return, and be no more?
+Why else this double object in our sight
+Of flight pursued in the air, and o'er the ground,
+One way the self-same hour? why in the east
+Darkness ere day's mid-course, and morning-light
+More orient in yon western cloud, that draws
+O'er the blue firmament a radiant white,
+And slow descends with something heavenly fraught?
+He erred not; for by this the heavenly bands
+Down from a sky of jasper lighted now
+In Paradise, and on a hill made halt;
+A glorious apparition, had not doubt
+And carnal fear that day dimmed Adam's eye.
+Not that more glorious, when the Angels met
+Jacob in Mahanaim, where he saw
+The field pavilioned with his guardians bright;
+Nor that, which on the flaming mount appeared
+In Dothan, covered with a camp of fire,
+Against the Syrian king, who to surprise
+One man, assassin-like, had levied war,
+War unproclaimed. The princely Hierarch
+In their bright stand there left his Powers, to seise
+Possession of the garden; he alone,
+To find where Adam sheltered, took his way,
+Not unperceived of Adam; who to Eve,
+While the great visitant approached, thus spake.
+Eve$ now expect great tidings, which perhaps
+Of us will soon determine, or impose
+New laws to be observed; for I descry,
+From yonder blazing cloud that veils the hill,
+One of the heavenly host; and, by his gait,
+None of the meanest; some great Potentate
+Or of the Thrones above; such majesty
+Invests him coming! yet not terrible,
+That I should fear; nor sociably mild,
+As Raphael, that I should much confide;
+But solemn and sublime; whom not to offend,
+With reverence I must meet, and thou retire.
+He ended: and the Arch-Angel soon drew nigh,
+Not in his shape celestial, but as man
+Clad to meet man; over his lucid arms
+A military vest of purple flowed,
+Livelier than Meliboean, or the grain
+Of Sarra, worn by kings and heroes old
+In time of truce; Iris had dipt the woof;
+His starry helm unbuckled showed him prime
+In manhood where youth ended; by his side,
+As in a glistering zodiack, hung the sword,
+Satan's dire dread; and in his hand the spear.
+Adam bowed low; he, kingly, from his state
+Inclined not, but his coming thus declared.
+Adam, Heaven's high behest no preface needs:
+Sufficient that thy prayers are heard; and Death,
+Then due by sentence when thou didst transgress,
+Defeated of his seisure many days
+Given thee of grace; wherein thou mayest repent,
+And one bad act with many deeds well done
+Mayest cover: Well may then thy Lord, appeased,
+Redeem thee quite from Death's rapacious claim;
+But longer in this Paradise to dwell
+Permits not: to remove thee I am come,
+And send thee from the garden forth to till
+The ground whence thou wast taken, fitter soil.
+He added not; for Adam at the news
+Heart-struck with chilling gripe of sorrow stood,
+That all his senses bound; Eve, who unseen
+Yet all had heard, with audible lament
+Discovered soon the place of her retire.
+O unexpected stroke, worse than of Death!
+Must I thus leave thee$ Paradise? thus leave
+Thee, native soil! these happy walks and shades,
+Fit haunt of Gods? where I had hope to spend,
+Quiet though sad, the respite of that day
+That must be mortal to us both. O flowers,
+That never will in other climate grow,
+My early visitation, and my last
+ ;t even, which I bred up with tender hand
+From the first opening bud, and gave ye names!
+Who now shall rear ye to the sun, or rank
+Your tribes, and water from the ambrosial fount?
+Thee lastly, nuptial bower! by me adorned
+With what to sight or smell was sweet! from thee
+How shall I part, and whither wander down
+Into a lower world; to this obscure
+And wild? how shall we breathe in other air
+Less pure, accustomed to immortal fruits?
+Whom thus the Angel interrupted mild.
+Lament not, Eve, but patiently resign
+What justly thou hast lost, nor set thy heart,
+Thus over-fond, on that which is not thine:
+Thy going is not lonely; with thee goes
+Thy husband; whom to follow thou art bound;
+Where he abides, think there thy native soil.
+Adam, by this from the cold sudden damp
+Recovering, and his scattered spirits returned,
+To Michael thus his humble words addressed.
+Celestial, whether among the Thrones, or named
+Of them the highest; for such of shape may seem
+Prince above princes! gently hast thou told
+Thy message, which might else in telling wound,
+And in performing end us; what besides
+Of sorrow, and dejection, and despair,
+Our frailty can sustain, thy tidings bring,
+Departure from this happy place, our sweet
+Recess, and only consolation left
+Familiar to our eyes! all places else
+Inhospitable appear, and desolate;
+Nor knowing us, nor known: And, if by prayer
+Incessant I could hope to change the will
+Of Him who all things can, I would not cease
+To weary him with my assiduous cries:
+But prayer against his absolute decree
+No more avails than breath against the wind,
+Blown stifling back on him that breathes it forth:
+Therefore to his great bidding I submit.
+This most afflicts me, that, departing hence,
+As from his face I shall be hid, deprived
+His blessed countenance: Here I could frequent
+With worship place by place where he vouchsafed
+Presence Divine; and to my sons relate,
+'On this mount he appeared; under this tree
+'Stood visible; among these pines his voice
+'I heard; here with him at this fountain talked:
+So many grateful altars I would rear
+Of grassy turf, and pile up every stone
+Of lustre from the brook, in memory,
+Or monument to ages; and theron
+Offer sweet-smelling gums, and fruits, and flowers:
+In yonder nether world where shall I seek
+His bright appearances, or foot-step trace?
+For though I fled him angry, yet recalled
+To life prolonged and promised race, I now
+Gladly behold though but his utmost skirts
+Of glory; and far off his steps adore.
+To whom thus Michael with regard benign.
+Adam, thou knowest Heaven his, and all the Earth;
+Not this rock only; his Omnipresence fills
+Land, sea, and air, and every kind that lives,
+Fomented by his virtual power and warmed:
+All the earth he gave thee to possess and rule,
+No despicable gift; surmise not then
+His presence to these narrow bounds confined
+Of Paradise, or Eden: this had been
+Perhaps thy capital seat, from whence had spread
+All generations; and had hither come
+From all the ends of the earth, to celebrate
+And reverence thee, their great progenitor.
+But this pre-eminence thou hast lost, brought down
+To dwell on even ground now with thy sons:
+Yet doubt not but in valley, and in plain,
+God is, as here; and will be found alike
+Present; and of his presence many a sign
+Still following thee, still compassing thee round
+With goodness and paternal love, his face
+Express, and of his steps the track divine.
+Which that thou mayest believe, and be confirmed
+Ere thou from hence depart; know, I am sent
+To show thee what shall come in future days
+To thee, and to thy offspring: good with bad
+Expect to hear; supernal grace contending
+With sinfulness of men; thereby to learn
+True patience, and to temper joy with fear
+And pious sorrow; equally inured
+By moderation either state to bear,
+Prosperous or adverse: so shalt thou lead
+Safest thy life, and best prepared endure
+Thy mortal passage when it comes.--Ascend
+This hill; let Eve (for I have drenched her eyes)
+Here sleep below; while thou to foresight wakest;
+As once thou sleptst, while she to life was formed.
+To whom thus Adam gratefully replied.
+Ascend, I follow thee, safe Guide, the path
+Thou leadest me; and to the hand of Heaven submit,
+However chastening; to the evil turn
+My obvious breast; arming to overcome
+By suffering, and earn rest from labour won,
+If so I may attain. -- So both ascend
+In the visions of God. It was a hill,
+Of Paradise the highest; from whose top
+The hemisphere of earth, in clearest ken,
+Stretched out to the amplest reach of prospect lay.
+Not higher that hill, nor wider looking round,
+Whereon, for different cause, the Tempter set
+Our second Adam, in the wilderness;
+To show him all Earth's kingdoms, and their glory.
+His eye might there command wherever stood
+City of old or modern fame, the seat
+Of mightiest empire, from the destined walls
+Of Cambalu, seat of Cathaian Can,
+And Samarchand by Oxus, Temir's throne,
+To Paquin of Sinaean kings; and thence
+To Agra and Lahor of great Mogul,
+Down to the golden Chersonese; or where
+The Persian in Ecbatan sat, or since
+In Hispahan; or where the Russian Ksar
+In Mosco; or the Sultan in Bizance,
+Turchestan-born; nor could his eye not ken
+The empire of Negus to his utmost port
+Ercoco, and the less maritim kings
+Mombaza, and Quiloa, and Melind,
+And Sofala, thought Ophir, to the realm
+Of Congo, and Angola farthest south;
+Or thence from Niger flood to Atlas mount
+The kingdoms of Almansor, Fez and Sus,
+Morocco, and Algiers, and Tremisen;
+On Europe thence, and where Rome was to sway
+The world: in spirit perhaps he also saw
+Rich Mexico, the seat of Montezume,
+And Cusco in Peru, the richer seat
+Of Atabalipa; and yet unspoiled
+Guiana, whose great city Geryon's sons
+Call El Dorado. But to nobler sights
+Michael from Adam's eyes the film removed,
+Which that false fruit that promised clearer sight
+Had bred; then purged with euphrasy and rue
+The visual nerve, for he had much to see;
+And from the well of life three drops instilled.
+So deep the power of these ingredients pierced,
+Even to the inmost seat of mental sight,
+That Adam, now enforced to close his eyes,
+Sunk down, and all his spirits became entranced;
+But him the gentle Angel by the hand
+Soon raised, and his attention thus recalled.
+Adam, now ope thine eyes; and first behold
+The effects, which thy original crime hath wrought
+In some to spring from thee; who never touched
+The excepted tree; nor with the snake conspired;
+Nor sinned thy sin; yet from that sin derive
+Corruption, to bring forth more violent deeds.
+His eyes he opened, and beheld a field,
+Part arable and tilth, whereon were sheaves
+New reaped; the other part sheep-walks and folds;
+I' the midst an altar as the land-mark stood,
+Rustick, of grassy sord; thither anon
+A sweaty reaper from his tillage brought
+First fruits, the green ear, and the yellow sheaf,
+Unculled, as came to hand; a shepherd next,
+More meek, came with the firstlings of his flock,
+Choicest and best; then, sacrificing, laid
+The inwards and their fat, with incense strowed,
+On the cleft wood, and all due rights performed:
+His offering soon propitious fire from Heaven
+Consumed with nimble glance, and grateful steam;
+The other's not, for his was not sincere;
+Whereat he inly raged, and, as they talked,
+Smote him into the midriff with a stone
+That beat out life; he fell;and, deadly pale,
+Groaned out his soul with gushing blood effused.
+Much at that sight was Adam in his heart
+Dismayed, and thus in haste to the Angel cried.
+O Teacher, some great mischief hath befallen
+To that meek man, who well had sacrificed;
+Is piety thus and pure devotion paid?
+To whom Michael thus, he also moved, replied.
+These two are brethren, Adam, and to come
+Out of thy loins; the unjust the just hath slain,
+For envy that his brother's offering found
+From Heaven acceptance; but the bloody fact
+Will be avenged; and the other's faith, approved,
+Lose no reward; though here thou see him die,
+Rolling in dust and gore. To which our sire.
+Alas! both for the deed, and for the cause!
+But have I now seen Death? Is this the way
+I must return to native dust? O sight
+Of terrour, foul and ugly to behold,
+Horrid to think, how horrible to feel!
+To whom thus Michael. Death thou hast seen
+In his first shape on Man; but many shapes
+Of Death, and many are the ways that lead
+To his grim cave, all dismal; yet to sense
+More terrible at the entrance, than within.
+Some, as thou sawest, by violent stroke shall die;
+By fire, flood, famine, by intemperance more
+In meats and drinks, which on the earth shall bring
+Diseases dire, of which a monstrous crew
+Before thee shall appear; that thou mayest know
+What misery the inabstinence of Eve
+Shall bring on Men. Immediately a place
+Before his eyes appeared, sad, noisome, dark;
+A lazar-house it seemed; wherein were laid
+Numbers of all diseased; all maladies
+Of ghastly spasm, or racking torture, qualms
+Of heart-sick agony, all feverous kinds,
+Convulsions, epilepsies, fierce catarrhs,
+Intestine stone and ulcer, colick-pangs,
+Demoniack phrenzy, moaping melancholy,
+And moon-struck madness, pining atrophy,
+Marasmus, and wide-wasting pestilence,
+Dropsies, and asthmas, and joint-racking rheums.
+Dire was the tossing, deep the groans; Despair
+Tended the sick busiest from couch to couch;
+And over them triumphant Death his dart
+Shook, but delayed to strike, though oft invoked
+With vows, as their chief good, and final hope.
+Sight so deform what heart of rock could long
+Dry-eyed behold? Adam could not, but wept,
+Though not of woman born; compassion quelled
+His best of man, and gave him up to tears
+A space, till firmer thoughts restrained excess;
+And, scarce recovering words, his plaint renewed.
+O miserable mankind, to what fall
+Degraded, to what wretched state reserved!
+Better end here unborn. Why is life given
+To be thus wrested from us? rather, why
+Obtruded on us thus? who, if we knew
+What we receive, would either no accept
+Life offered, or soon beg to lay it down;
+Glad to be so dismissed in peace. Can thus
+The image of God in Man, created once
+So goodly and erect, though faulty since,
+To such unsightly sufferings be debased
+Under inhuman pains? Why should not Man,
+Retaining still divine similitude
+In part, from such deformities be free,
+And, for his Maker's image sake, exempt?
+Their Maker's image, answered Michael, then
+Forsook them, when themselves they vilified
+To serve ungoverned Appetite; and took
+His image whom they served, a brutish vice,
+Inductive mainly to the sin of Eve.
+Therefore so abject is their punishment,
+Disfiguring not God's likeness, but their own;
+Or if his likeness, by themselves defaced;
+While they pervert pure Nature's healthful rules
+To loathsome sickness; worthily, since they
+God's image did not reverence in themselves.
+I yield it just, said Adam, and submit.
+But is there yet no other way, besides
+These painful passages, how we may come
+To death, and mix with our connatural dust?
+There is, said Michael, if thou well observe
+The rule of Not too much; by temperance taught,
+In what thou eatest and drinkest; seeking from thence
+Due nourishment, not gluttonous delight,
+Till many years over thy head return:
+So mayest thou live; till, like ripe fruit, thou drop
+Into thy mother's lap; or be with ease
+Gathered, nor harshly plucked; for death mature:
+This is Old Age; but then, thou must outlive
+Thy youth, thy strength, thy beauty; which will change
+To withered, weak, and gray; thy senses then,
+Obtuse, all taste of pleasure must forego,
+To what thou hast; and, for the air of youth,
+Hopeful and cheerful, in thy blood will reign
+A melancholy damp of cold and dry
+To weigh thy spirits down, and last consume
+The balm of life. To whom our ancestor.
+Henceforth I fly not death, nor would prolong
+Life much; bent rather, how I may be quit,
+Fairest and easiest, of this cumbrous charge;
+Which I must keep till my appointed day
+Of rendering up, and patiently attend
+My dissolution. Michael replied.
+Nor love thy life, nor hate; but what thou livest
+Live well; how long, or short, permit to Heaven:
+And now prepare thee for another sight.
+He looked, and saw a spacious plain, whereon
+Were tents of various hue; by some, were herds
+Of cattle grazing; others, whence the sound
+Of instruments, that made melodious chime,
+Was heard, of harp and organ; and, who moved
+Their stops and chords, was seen; his volant touch,
+Instinct through all proportions, low and high,
+Fled and pursued transverse the resonant fugue.
+In other part stood one who, at the forge
+Labouring, two massy clods of iron and brass
+Had melted, (whether found where casual fire
+Had wasted woods on mountain or in vale,
+Down to the veins of earth; thence gliding hot
+To some cave's mouth; or whether washed by stream
+From underground;) the liquid ore he drained
+Into fit moulds prepared; from which he formed
+First his own tools; then, what might else be wrought
+Fusil or graven in metal. After these,
+But on the hither side, a different sort
+From the high neighbouring hills, which was their seat,
+Down to the plain descended; by their guise
+Just men they seemed, and all their study bent
+To worship God aright, and know his works
+Not hid; nor those things last, which might preserve
+Freedom and peace to Men; they on the plain
+Long had not walked, when from the tents, behold!
+A bevy of fair women, richly gay
+In gems and wanton dress; to the harp they sung
+Soft amorous ditties, and in dance came on:
+The men, though grave, eyed them; and let their eyes
+Rove without rein; till, in the amorous net
+Fast caught, they liked; and each his liking chose;
+And now of love they treat, till the evening-star,
+Love's harbinger, appeared; then, all in heat
+They light the nuptial torch, and bid invoke
+Hymen, then first to marriage rites invoked:
+With feast and musick all the tents resound.
+Such happy interview, and fair event
+Of love and youth not lost, songs, garlands, flowers,
+And charming symphonies, attached the heart
+Of Adam, soon inclined to admit delight,
+The bent of nature; which he thus expressed.
+True opener of mine eyes, prime Angel blest;
+Much better seems this vision, and more hope
+Of peaceful days portends, than those two past;
+Those were of hate and death, or pain much worse;
+Here Nature seems fulfilled in all her ends.
+To whom thus Michael. Judge not what is best
+By pleasure, though to nature seeming meet;
+Created, as thou art, to nobler end
+Holy and pure, conformity divine.
+Those tents thou sawest so pleasant, were the tents
+Of wickedness, wherein shall dwell his race
+Who slew his brother; studious they appear
+Of arts that polish life, inventers rare;
+Unmindful of their Maker, though his Spirit
+Taught them; but they his gifts acknowledged none.
+Yet they a beauteous offspring shall beget;
+For that fair female troop thou sawest, that seemed
+Of Goddesses, so blithe, so smooth, so gay,
+Yet empty of all good wherein consists
+Woman's domestick honour and chief praise;
+Bred only and completed to the taste
+Of lustful appetence, to sing, to dance,
+To dress, and troll the tongue, and roll the eye:
+To these that sober race of men, whose lives
+Religious titled them the sons of God,
+Shall yield up all their virtue, all their fame
+Ignobly, to the trains and to the smiles
+Of these fair atheists; and now swim in joy,
+Erelong to swim at large; and laugh, for which
+The world erelong a world of tears must weep.
+To whom thus Adam, of short joy bereft.
+O pity and shame, that they, who to live well
+Entered so fair, should turn aside to tread
+Paths indirect, or in the mid way faint!
+But still I see the tenour of Man's woe
+Holds on the same, from Woman to begin.
+From Man's effeminate slackness it begins,
+Said the Angel, who should better hold his place
+By wisdom, and superiour gifts received.
+But now prepare thee for another scene.
+He looked, and saw wide territory spread
+Before him, towns, and rural works between;
+Cities of men with lofty gates and towers,
+Concourse in arms, fierce faces threatening war,
+Giants of mighty bone and bold emprise;
+Part wield their arms, part curb the foaming steed,
+Single or in array of battle ranged
+Both horse and foot, nor idly mustering stood;
+One way a band select from forage drives
+A herd of beeves, fair oxen and fair kine,
+From a fat meadow ground; or fleecy flock,
+Ewes and their bleating lambs over the plain,
+Their booty; scarce with life the shepherds fly,
+But call in aid, which makes a bloody fray;
+With cruel tournament the squadrons join;
+Where cattle pastured late, now scattered lies
+With carcasses and arms the ensanguined field,
+Deserted: Others to a city strong
+Lay siege, encamped; by battery, scale, and mine,
+Assaulting; others from the wall defend
+With dart and javelin, stones, and sulphurous fire;
+On each hand slaughter, and gigantick deeds.
+In other part the sceptered heralds call
+To council, in the city-gates; anon
+Gray-headed men and grave, with warriours mixed,
+Assemble, and harangues are heard; but soon,
+In factious opposition; till at last,
+Of middle age one rising, eminent
+In wise deport, spake much of right and wrong,
+Of justice, or religion, truth, and peace,
+And judgement from above: him old and young
+Exploded, and had seized with violent hands,
+Had not a cloud descending snatched him thence
+Unseen amid the throng: so violence
+Proceeded, and oppression, and sword-law,
+Through all the plain, and refuge none was found.
+Adam was all in tears, and to his guide
+Lamenting turned full sad; O!what are these,
+Death's ministers, not men? who thus deal death
+Inhumanly to men, and multiply
+Ten thousandfold the sin of him who slew
+His brother: for of whom such massacre
+Make they, but of their brethren; men of men
+But who was that just man, whom had not Heaven
+Rescued, had in his righteousness been lost?
+To whom thus Michael. These are the product
+Of those ill-mated marriages thou sawest;
+Where good with bad were matched, who of themselves
+Abhor to join; and, by imprudence mixed,
+Produce prodigious births of body or mind.
+Such were these giants, men of high renown;
+For in those days might only shall be admired,
+And valour and heroick virtue called;
+To overcome in battle, and subdue
+Nations, and bring home spoils with infinite
+Man-slaughter, shall be held the highest pitch
+Of human glory; and for glory done
+Of triumph, to be styled great conquerours
+Patrons of mankind, Gods, and sons of Gods;
+Destroyers rightlier called, and plagues of men.
+Thus fame shall be achieved, renown on earth;
+And what most merits fame, in silence hid.
+But he, the seventh from thee, whom thou beheldst
+The only righteous in a world preverse,
+And therefore hated, therefore so beset
+With foes, for daring single to be just,
+And utter odious truth, that God would come
+To judge them with his Saints; him the Most High
+Rapt in a balmy cloud with winged steeds
+Did, as thou sawest, receive, to walk with God
+High in salvation and the climes of bliss,
+Exempt from death; to show thee what reward
+Awaits the good; the rest what punishment;
+Which now direct thine eyes and soon behold.
+He looked, and saw the face of things quite changed;
+The brazen throat of war had ceased to roar;
+All now was turned to jollity and game,
+To luxury and riot, feast and dance;
+Marrying or prostituting, as befel,
+Rape or adultery, where passing fair
+Allured them; thence from cups to civil broils.
+At length a reverend sire among them came,
+And of their doings great dislike declared,
+And testified against their ways; he oft
+Frequented their assemblies, whereso met,
+Triumphs or festivals; and to them preached
+Conversion and repentance, as to souls
+In prison, under judgements imminent:
+But all in vain: which when he saw, he ceased
+Contending, and removed his tents far off;
+Then, from the mountain hewing timber tall,
+Began to build a vessel of huge bulk;
+Measured by cubit, length, and breadth, and highth;
+Smeared round with pitch; and in the side a door
+Contrived; and of provisions laid in large,
+For man and beast: when lo, a wonder strange!
+Of every beast, and bird, and insect small,
+Came sevens, and pairs; and entered in as taught
+Their order: last the sire and his three sons,
+With their four wives; and God made fast the door.
+Mean while the south-wind rose, and, with black wings
+Wide-hovering, all the clouds together drove
+From under Heaven; the hills to their supply
+Vapour, and exhalation dusk and moist,
+Sent up amain; and now the thickened sky
+Like a dark cieling stood; down rushed the rain
+Impetuous; and continued, till the earth
+No more was seen: the floating vessel swum
+Uplifted, and secure with beaked prow
+Rode tilting o'er the waves; all dwellings else
+Flood overwhelmed, and them with all their pomp
+Deep under water rolled; sea covered sea,
+Sea without shore; and in their palaces,
+Where luxury late reigned, sea-monsters whelped
+And stabled; of mankind, so numerous late,
+All left, in one small bottom swum imbarked.
+How didst thou grieve then, Adam, to behold
+The end of all thy offspring, end so sad,
+Depopulation! Thee another flood,
+Of tears and sorrow a flood, thee also drowned,
+And sunk thee as thy sons; till, gently reared
+By the Angel, on thy feet thou stoodest at last,
+Though comfortless; as when a father mourns
+His children, all in view destroyed at once;
+And scarce to the Angel utter'dst thus thy plaint.
+O visions ill foreseen! Better had I
+Lived ignorant of future! so had borne
+My part of evil only, each day's lot
+Enough to bear; those now, that were dispensed
+The burden of many ages, on me light
+At once, by my foreknowledge gaining birth
+Abortive, to torment me ere their being,
+With thought that they must be. Let no man seek
+Henceforth to be foretold, what shall befall
+Him or his children; evil he may be sure,
+Which neither his foreknowing can prevent;
+And he the future evil shall no less
+In apprehension than in substance feel,
+Grievous to bear: but that care now is past,
+Man is not whom to warn: those few escaped
+Famine and anguish will at last consume,
+Wandering that watery desart: I had hope,
+When violence was ceased, and war on earth,
+All would have then gone well; peace would have crowned
+With length of happy days the race of Man;
+But I was far deceived; for now I see
+Peace to corrupt no less than war to waste.
+How comes it thus? unfold, celestial Guide,
+And whether here the race of Man will end.
+To whom thus Michael. Those, whom last thou sawest
+In triumph and luxurious wealth, are they
+First seen in acts of prowess eminent
+And great exploits, but of true virtue void;
+Who, having spilt much blood, and done much wast
+Subduing nations, and achieved thereby
+Fame in the world, high titles, and rich prey;
+Shall change their course to pleasure, ease, and sloth,
+Surfeit, and lust; till wantonness and pride
+Raise out of friendship hostile deeds in peace.
+The conquered also, and enslaved by war,
+Shall, with their freedom lost, all virtue lose
+And fear of God; from whom their piety feigned
+In sharp contest of battle found no aid
+Against invaders; therefore, cooled in zeal,
+Thenceforth shall practice how to live secure,
+Worldly or dissolute, on what their lords
+Shall leave them to enjoy; for the earth shall bear
+More than enough, that temperance may be tried:
+So all shall turn degenerate, all depraved;
+Justice and temperance, truth and faith, forgot;
+One man except, the only son of light
+In a dark age, against example good,
+Against allurement, custom, and a world
+Offended: fearless of reproach and scorn,
+The grand-child, with twelve sons encreased, departs
+From Canaan, to a land hereafter called
+Egypt, divided by the river Nile;
+See where it flows, disgorging at seven mouths
+Into the sea: To sojourn in that land
+He comes, invited by a younger son
+In time of dearth; a son, whose worthy deeds
+Raise him to be the second in that realm
+Of Pharaoh: There he dies, and leaves his race
+Growing into a nation, and now grown
+Suspected to a sequent king, who seeks
+To stop their overgrowth, as inmate guests
+Or violence, he of their wicked ways
+Shall them admonish; and before them set
+The paths of righteousness, how much more safe
+And full of peace; denouncing wrath to come
+On their impenitence; and shall return
+Of them derided, but of God observed
+The one just man alive; by his command
+Shall build a wonderous ark, as thou beheldst,
+To save himself, and houshold, from amidst
+A world devote to universal wrack.
+No sooner he, with them of man and beast
+Select for life, shall in the ark be lodged,
+And sheltered round; but all the cataracts
+Of Heaven set open on the Earth shall pour
+Rain, day and night; all fountains of the deep,
+Broke up, shall heave the ocean to usurp
+Beyond all bounds; till inundation rise
+Above the highest hills: Then shall this mount
+Of Paradise by might of waves be moved
+Out of his place, pushed by the horned flood,
+With all his verdure spoiled, and trees adrift,
+Down the great river to the opening gulf,
+And there take root an island salt and bare,
+The haunt of seals, and orcs, and sea-mews' clang:
+To teach thee that God attributes to place
+No sanctity, if none be thither brought
+By men who there frequent, or therein dwell.
+And now, what further shall ensue, behold.
+He looked, and saw the ark hull on the flood,
+Which now abated; for the clouds were fled,
+Driven by a keen north-wind, that, blowing dry,
+Wrinkled the face of deluge, as decayed;
+And the clear sun on his wide watery glass
+Gazed hot, and of the fresh wave largely drew,
+As after thirst; which made their flowing shrink
+From standing lake to tripping ebb, that stole
+With soft foot towards the deep; who now had stopt
+His sluces, as the Heaven his windows shut.
+The ark no more now floats, but seems on ground,
+Fast on the top of some high mountain fixed.
+And now the tops of hills, as rocks, appear;
+With clamour thence the rapid currents drive,
+Towards the retreating sea, their furious tide.
+Forthwith from out the ark a raven flies,
+And after him, the surer messenger,
+A dove sent forth once and again to spy
+Green tree or ground, whereon his foot may light:
+The second time returning, in his bill
+An olive-leaf he brings, pacifick sign:
+Anon dry ground appears, and from his ark
+The ancient sire descends, with all his train;
+Then with uplifted hands, and eyes devout,
+Grateful to Heaven, over his head beholds
+A dewy cloud, and in the cloud a bow
+Conspicuous with three lifted colours gay,
+Betokening peace from God, and covenant new.
+Whereat the heart of Adam, erst so sad,
+Greatly rejoiced; and thus his joy broke forth.
+O thou, who future things canst represent
+As present, heavenly Instructer! I revive
+At this last sight; assured that Man shall live,
+With all the creatures, and their seed preserve.
+Far less I now lament for one whole world
+Of wicked sons destroyed, than I rejoice
+For one man found so perfect, and so just,
+That God vouchsafes to raise another world
+From him, and all his anger to forget.
+But say, what mean those coloured streaks in Heaven
+Distended, as the brow of God appeased?
+Or serve they, as a flowery verge, to bind
+The fluid skirts of that same watery cloud,
+Lest it again dissolve, and shower the earth?
+To whom the Arch-Angel. Dextrously thou aimest;
+So willingly doth God remit his ire,
+Though late repenting him of Man depraved;
+Grieved at his heart, when looking down he saw
+The whole earth filled with violence, and all flesh
+Corrupting each their way; yet, those removed,
+Such grace shall one just man find in his sight,
+That he relents, not to blot out mankind;
+And makes a covenant never to destroy
+The earth again by flood; nor let the sea
+Surpass his bounds; nor rain to drown the world,
+With man therein or beast; but, when he brings
+Over the earth a cloud, will therein set
+His triple-coloured bow, whereon to look,
+And call to mind his covenant: Day and night,
+Seed-time and harvest, heat and hoary frost,
+Shall hold their course; till fire purge all things new,
+Both Heaven and Earth, wherein the just shall dwell.
+
+
+
+Book XII
+
+
+As one who in his journey bates at noon,
+Though bent on speed; so here the Arch-Angel paused
+Betwixt the world destroyed and world restored,
+If Adam aught perhaps might interpose;
+Then, with transition sweet, new speech resumes.
+Thus thou hast seen one world begin, and end;
+And Man, as from a second stock, proceed.
+Much thou hast yet to see; but I perceive
+Thy mortal sight to fail; objects divine
+Must needs impair and weary human sense:
+Henceforth what is to come I will relate;
+Thou therefore give due audience, and attend.
+This second source of Men, while yet but few,
+And while the dread of judgement past remains
+Fresh in their minds, fearing the Deity,
+With some regard to what is just and right
+Shall lead their lives, and multiply apace;
+Labouring the soil, and reaping plenteous crop,
+Corn, wine, and oil; and, from the herd or flock,
+Oft sacrificing bullock, lamb, or kid,
+With large wine-offerings poured, and sacred feast,
+Shall spend their days in joy unblamed; and dwell
+Long time in peace, by families and tribes,
+Under paternal rule: till one shall rise
+Of proud ambitious heart; who, not content
+With fair equality, fraternal state,
+Will arrogate dominion undeserved
+Over his brethren, and quite dispossess
+Concord and law of nature from the earth;
+Hunting (and men not beasts shall be his game)
+With war, and hostile snare, such as refuse
+Subjection to his empire tyrannous:
+A mighty hunter thence he shall be styled
+Before the Lord; as in despite of Heaven,
+Or from Heaven, claiming second sovranty;
+And from rebellion shall derive his name,
+Though of rebellion others he accuse.
+He with a crew, whom like ambition joins
+With him or under him to tyrannize,
+Marching from Eden towards the west, shall find
+The plain, wherein a black bituminous gurge
+Boils out from under ground, the mouth of Hell:
+Of brick, and of that stuff, they cast to build
+A city and tower, whose top may reach to Heaven;
+And get themselves a name; lest, far dispersed
+In foreign lands, their memory be lost;
+Regardless whether good or evil fame.
+But God, who oft descends to visit men
+Unseen, and through their habitations walks
+To mark their doings, them beholding soon,
+Comes down to see their city, ere the tower
+Obstruct Heaven-towers, and in derision sets
+Upon their tongues a various spirit, to rase
+Quite out their native language; and, instead,
+To sow a jangling noise of words unknown:
+Forthwith a hideous gabble rises loud,
+Among the builders; each to other calls
+Not understood; till hoarse, and all in rage,
+As mocked they storm: great laughter was in Heaven,
+And looking down, to see the hubbub strange,
+And hear the din: Thus was the building left
+Ridiculous, and the work Confusion named.
+Whereto thus Adam, fatherly displeased.
+O execrable son! so to aspire
+Above his brethren; to himself assuming
+Authority usurped, from God not given:
+He gave us only over beast, fish, fowl,
+Dominion absolute; that right we hold
+By his donation; but man over men
+He made not lord; such title to himself
+Reserving, human left from human free.
+But this usurper his encroachment proud
+Stays not on Man; to God his tower intends
+Siege and defiance: Wretched man!what food
+Will he convey up thither, to sustain
+Himself and his rash army; where thin air
+Above the clouds will pine his entrails gross,
+And famish him of breath, if not of bread?
+To whom thus Michael. Justly thou abhorrest
+That son, who on the quiet state of men
+Such trouble brought, affecting to subdue
+Rational liberty; yet know withal,
+Since thy original lapse, true liberty
+Is lost, which always with right reason dwells
+Twinned, and from her hath no dividual being:
+Reason in man obscured, or not obeyed,
+Immediately inordinate desires,
+And upstart passions, catch the government
+From reason; and to servitude reduce
+Man, till then free. Therefore, since he permits
+Within himself unworthy powers to reign
+Over free reason, God, in judgement just,
+Subjects him from without to violent lords;
+Who oft as undeservedly enthrall
+His outward freedom: Tyranny must be;
+Though to the tyrant thereby no excuse.
+Yet sometimes nations will decline so low
+From virtue, which is reason, that no wrong,
+But justice, and some fatal curse annexed,
+Deprives them of their outward liberty;
+Their inward lost: Witness the irreverent son
+Of him who built the ark; who, for the shame
+Done to his father, heard this heavy curse,
+Servant of servants, on his vicious race.
+Thus will this latter, as the former world,
+Still tend from bad to worse; till God at last,
+Wearied with their iniquities, withdraw
+His presence from among them, and avert
+His holy eyes; resolving from thenceforth
+To leave them to their own polluted ways;
+And one peculiar nation to select
+From all the rest, of whom to be invoked,
+A nation from one faithful man to spring:
+Him on this side Euphrates yet residing,
+Bred up in idol-worship: O, that men
+(Canst thou believe?) should be so stupid grown,
+While yet the patriarch lived, who 'scaped the flood,
+As to forsake the living God, and fall
+To worship their own work in wood and stone
+For Gods! Yet him God the Most High vouchsafes
+To call by vision, from his father's house,
+His kindred, and false Gods, into a land
+Which he will show him; and from him will raise
+A mighty nation; and upon him shower
+His benediction so, that in his seed
+All nations shall be blest: he straight obeys;
+Not knowing to what land, yet firm believes:
+I see him, but thou canst not, with what faith
+He leaves his Gods, his friends, and native soil,
+Ur of Chaldaea, passing now the ford
+To Haran; after him a cumbrous train
+Of herds and flocks, and numerous servitude;
+Not wandering poor, but trusting all his wealth
+With God, who called him, in a land unknown.
+Canaan he now attains; I see his tents
+Pitched about Sechem, and the neighbouring plain
+Of Moreh; there by promise he receives
+Gift to his progeny of all that land,
+From Hameth northward to the Desart south;
+(Things by their names I call, though yet unnamed;)
+From Hermon east to the great western Sea;
+Mount Hermon, yonder sea; each place behold
+In prospect, as I point them; on the shore
+Mount Carmel; here, the double-founted stream,
+Jordan, true limit eastward; but his sons
+Shall dwell to Senir, that long ridge of hills.
+This ponder, that all nations of the earth
+Shall in his seed be blessed: By that seed
+Is meant thy great Deliverer, who shall bruise
+The Serpent's head; whereof to thee anon
+Plainlier shall be revealed. This patriarch blest,
+Whom faithful Abraham due time shall call,
+A son, and of his son a grand-child, leaves;
+Like him in faith, in wisdom, and renown:
+The grandchild, with twelve sons increased, departs
+From Canaan to a land hereafter called
+Egypt, divided by the river Nile
+See where it flows, disgorging at seven mouths
+Into the sea. To sojourn in that land
+He comes, invited by a younger son
+In time of dearth, a son whose worthy deeds
+Raise him to be the second in that realm
+Of Pharaoh. There he dies, and leaves his race
+Growing into a nation, and now grown
+Suspected to a sequent king, who seeks
+To stop their overgrowth, as inmate guests
+Too numerous; whence of guests he makes them slaves
+Inhospitably, and kills their infant males:
+Till by two brethren (these two brethren call
+Moses and Aaron) sent from God to claim
+His people from enthralment, they return,
+With glory and spoil, back to their promised land.
+But first, the lawless tyrant, who denies
+To know their God, or message to regard,
+Must be compelled by signs and judgements dire;
+To blood unshed the rivers must be turned;
+Frogs, lice, and flies, must all his palace fill
+With loathed intrusion, and fill all the land;
+His cattle must of rot and murren die;
+Botches and blains must all his flesh emboss,
+And all his people; thunder mixed with hail,
+Hail mixed with fire, must rend the Egyptians sky,
+And wheel on the earth, devouring where it rolls;
+What it devours not, herb, or fruit, or grain,
+A darksome cloud of locusts swarming down
+Must eat, and on the ground leave nothing green;
+Darkness must overshadow all his bounds,
+Palpable darkness, and blot out three days;
+Last, with one midnight stroke, all the first-born
+Of Egypt must lie dead. Thus with ten wounds
+The river-dragon tamed at length submits
+To let his sojourners depart, and oft
+Humbles his stubborn heart; but still, as ice
+More hardened after thaw; till, in his rage
+Pursuing whom he late dismissed, the sea
+Swallows him with his host; but them lets pass,
+As on dry land, between two crystal walls;
+Awed by the rod of Moses so to stand
+Divided, till his rescued gain their shore:
+Such wondrous power God to his saint will lend,
+Though present in his Angel; who shall go
+Before them in a cloud, and pillar of fire;
+By day a cloud, by night a pillar of fire;
+To guide them in their journey, and remove
+Behind them, while the obdurate king pursues:
+All night he will pursue; but his approach
+Darkness defends between till morning watch;
+Then through the fiery pillar, and the cloud,
+God looking forth will trouble all his host,
+And craze their chariot-wheels: when by command
+Moses once more his potent rod extends
+Over the sea; the sea his rod obeys;
+On their embattled ranks the waves return,
+And overwhelm their war: The race elect
+Safe toward Canaan from the shore advance
+Through the wild Desart, not the readiest way;
+Lest, entering on the Canaanite alarmed,
+War terrify them inexpert, and fear
+Return them back to Egypt, choosing rather
+Inglorious life with servitude; for life
+To noble and ignoble is more sweet
+Untrained in arms, where rashness leads not on.
+This also shall they gain by their delay
+In the wide wilderness; there they shall found
+Their government, and their great senate choose
+Through the twelve tribes, to rule by laws ordained:
+God from the mount of Sinai, whose gray top
+Shall tremble, he descending, will himself
+In thunder, lightning, and loud trumpets' sound,
+Ordain them laws; part, such as appertain
+To civil justice; part, religious rites
+Of sacrifice; informing them, by types
+And shadows, of that destined Seed to bruise
+The Serpent, by what means he shall achieve
+Mankind's deliverance. But the voice of God
+To mortal ear is dreadful: They beseech
+That Moses might report to them his will,
+And terrour cease; he grants what they besought,
+Instructed that to God is no access
+Without Mediator, whose high office now
+Moses in figure bears; to introduce
+One greater, of whose day he shall foretel,
+And all the Prophets in their age the times
+Of great Messiah shall sing. Thus, laws and rites
+Established, such delight hath God in Men
+Obedient to his will, that he vouchsafes
+Among them to set up his tabernacle;
+The Holy One with mortal Men to dwell:
+By his prescript a sanctuary is framed
+Of cedar, overlaid with gold; therein
+An ark, and in the ark his testimony,
+The records of his covenant; over these
+A mercy-seat of gold, between the wings
+Of two bright Cherubim; before him burn
+Seven lamps as in a zodiack representing
+The heavenly fires; over the tent a cloud
+Shall rest by day, a fiery gleam by night;
+Save when they journey, and at length they come,
+Conducted by his Angel, to the land
+Promised to Abraham and his seed:--The rest
+Were long to tell; how many battles fought
+How many kings destroyed; and kingdoms won;
+Or how the sun shall in mid Heaven stand still
+A day entire, and night's due course adjourn,
+Man's voice commanding, 'Sun, in Gibeon stand,
+'And thou moon in the vale of Aialon,
+'Till Israel overcome! so call the third
+From Abraham, son of Isaac; and from him
+His whole descent, who thus shall Canaan win.
+Here Adam interposed. O sent from Heaven,
+Enlightener of my darkness, gracious things
+Thou hast revealed; those chiefly, which concern
+Just Abraham and his seed: now first I find
+Mine eyes true-opening, and my heart much eased;
+Erewhile perplexed with thoughts, what would become
+Of me and all mankind: But now I see
+His day, in whom all nations shall be blest;
+Favour unmerited by me, who sought
+Forbidden knowledge by forbidden means.
+This yet I apprehend not, why to those
+Among whom God will deign to dwell on earth
+So many and so various laws are given;
+So many laws argue so many sins
+Among them; how can God with such reside?
+To whom thus Michael. Doubt not but that sin
+Will reign among them, as of thee begot;
+And therefore was law given them, to evince
+Their natural pravity, by stirring up
+Sin against law to fight: that when they see
+Law can discover sin, but not remove,
+Save by those shadowy expiations weak,
+The blood of bulls and goats, they may conclude
+Some blood more precious must be paid for Man;
+Just for unjust; that, in such righteousness
+To them by faith imputed, they may find
+Justification towards God, and peace
+Of conscience; which the law by ceremonies
+Cannot appease; nor Man the mortal part
+Perform; and, not performing, cannot live.
+So law appears imperfect; and but given
+With purpose to resign them, in full time,
+Up to a better covenant; disciplined
+From shadowy types to truth; from flesh to spirit;
+From imposition of strict laws to free
+Acceptance of large grace; from servile fear
+To filial; works of law to works of faith.
+And therefore shall not Moses, though of God
+Highly beloved, being but the minister
+Of law, his people into Canaan lead;
+But Joshua, whom the Gentiles Jesus call,
+His name and office bearing, who shall quell
+The adversary-Serpent, and bring back
+Through the world's wilderness long-wandered Man
+Safe to eternal Paradise of rest.
+Mean while they, in their earthly Canaan placed,
+Long time shall dwell and prosper, but when sins
+National interrupt their publick peace,
+Provoking God to raise them enemies;
+From whom as oft he saves them penitent
+By Judges first, then under Kings; of whom
+The second, both for piety renowned
+And puissant deeds, a promise shall receive
+Irrevocable, that his regal throne
+For ever shall endure; the like shall sing
+All Prophecy, that of the royal stock
+Of David (so I name this king) shall rise
+A Son, the Woman's seed to thee foretold,
+Foretold to Abraham, as in whom shall trust
+All nations; and to kings foretold, of kings
+The last; for of his reign shall be no end.
+But first, a long succession must ensue;
+And his next son, for wealth and wisdom famed,
+The clouded ark of God, till then in tents
+Wandering, shall in a glorious temple enshrine.
+Such follow him, as shall be registered
+Part good, part bad; of bad the longer scroll;
+Whose foul idolatries, and other faults
+Heaped to the popular sum, will so incense
+God, as to leave them, and expose their land,
+Their city, his temple, and his holy ark,
+With all his sacred things, a scorn and prey
+To that proud city, whose high walls thou sawest
+Left in confusion; Babylon thence called.
+There in captivity he lets them dwell
+The space of seventy years; then brings them back,
+Remembering mercy, and his covenant sworn
+To David, stablished as the days of Heaven.
+Returned from Babylon by leave of kings
+Their lords, whom God disposed, the house of God
+They first re-edify; and for a while
+In mean estate live moderate; till, grown
+In wealth and multitude, factious they grow;
+But first among the priests dissention springs,
+Men who attend the altar, and should most
+Endeavour peace: their strife pollution brings
+Upon the temple itself: at last they seise
+The scepter, and regard not David's sons;
+Then lose it to a stranger, that the true
+Anointed King Messiah might be born
+Barred of his right; yet at his birth a star,
+Unseen before in Heaven, proclaims him come;
+And guides the eastern sages, who inquire
+His place, to offer incense, myrrh, and gold:
+His place of birth a solemn Angel tells
+To simple shepherds, keeping watch by night;
+They gladly thither haste, and by a quire
+Of squadroned Angels hear his carol sung.
+A virgin is his mother, but his sire
+The power of the Most High: He shall ascend
+The throne hereditary, and bound his reign
+With Earth's wide bounds, his glory with the Heavens.
+He ceased, discerning Adam with such joy
+Surcharged, as had like grief been dewed in tears,
+Without the vent of words; which these he breathed.
+O prophet of glad tidings, finisher
+Of utmost hope! now clear I understand
+What oft my steadiest thoughts have searched in vain;
+Why our great Expectation should be called
+The seed of Woman: Virgin Mother, hail,
+High in the love of Heaven; yet from my loins
+Thou shalt proceed, and from thy womb the Son
+Of God Most High: so God with Man unites!
+Needs must the Serpent now his capital bruise
+Expect with mortal pain: Say where and when
+Their fight, what stroke shall bruise the victor's heel.
+To whom thus Michael. Dream not of their fight,
+As of a duel, or the local wounds
+Of head or heel: Not therefore joins the Son
+Manhood to Godhead, with more strength to foil
+Thy enemy; nor so is overcome
+Satan, whose fall from Heaven, a deadlier bruise,
+Disabled, not to give thee thy death's wound:
+Which he, who comes thy Saviour, shall recure,
+Not by destroying Satan, but his works
+In thee, and in thy seed: Nor can this be,
+But by fulfilling that which thou didst want,
+Obedience to the law of God, imposed
+On penalty of death, and suffering death;
+The penalty to thy transgression due,
+And due to theirs which out of thine will grow:
+So only can high Justice rest appaid.
+The law of God exact he shall fulfil
+Both by obedience and by love, though love
+Alone fulfil the law; thy punishment
+He shall endure, by coming in the flesh
+To a reproachful life, and cursed death;
+Proclaiming life to all who shall believe
+In his redemption; and that his obedience,
+Imputed, becomes theirs by faith; his merits
+To save them, not their own, though legal, works.
+For this he shall live hated, be blasphemed,
+Seised on by force, judged, and to death condemned
+A shameful and accursed, nailed to the cross
+By his own nation; slain for bringing life:
+But to the cross he nails thy enemies,
+The law that is against thee, and the sins
+Of all mankind, with him there crucified,
+Never to hurt them more who rightly trust
+In this his satisfaction; so he dies,
+But soon revives; Death over him no power
+Shall long usurp; ere the third dawning light
+Return, the stars of morn shall see him rise
+Out of his grave, fresh as the dawning light,
+Thy ransom paid, which Man from death redeems,
+His death for Man, as many as offered life
+Neglect not, and the benefit embrace
+By faith not void of works: This God-like act
+Annuls thy doom, the death thou shouldest have died,
+In sin for ever lost from life; this act
+Shall bruise the head of Satan, crush his strength,
+Defeating Sin and Death, his two main arms;
+And fix far deeper in his head their stings
+Than temporal death shall bruise the victor's heel,
+Or theirs whom he redeems; a death, like sleep,
+A gentle wafting to immortal life.
+Nor after resurrection shall he stay
+Longer on earth, than certain times to appear
+To his disciples, men who in his life
+Still followed him; to them shall leave in charge
+To teach all nations what of him they learned
+And his salvation; them who shall believe
+Baptizing in the profluent stream, the sign
+Of washing them from guilt of sin to life
+Pure, and in mind prepared, if so befall,
+For death, like that which the Redeemer died.
+All nations they shall teach; for, from that day,
+Not only to the sons of Abraham's loins
+Salvation shall be preached, but to the sons
+Of Abraham's faith wherever through the world;
+So in his seed all nations shall be blest.
+Then to the Heaven of Heavens he shall ascend
+With victory, triumphing through the air
+Over his foes and thine; there shall surprise
+The Serpent, prince of air, and drag in chains
+Through all his realm, and there confounded leave;
+Then enter into glory, and resume
+His seat at God's right hand, exalted high
+Above all names in Heaven; and thence shall come,
+When this world's dissolution shall be ripe,
+With glory and power to judge both quick and dead;
+To judge the unfaithful dead, but to reward
+His faithful, and receive them into bliss,
+Whether in Heaven or Earth; for then the Earth
+Shall all be Paradise, far happier place
+Than this of Eden, and far happier days.
+So spake the Arch-Angel Michael; then paused,
+As at the world's great period; and our sire,
+Replete with joy and wonder, thus replied.
+O Goodness infinite, Goodness immense!
+That all this good of evil shall produce,
+And evil turn to good; more wonderful
+Than that which by creation first brought forth
+Light out of darkness! Full of doubt I stand,
+Whether I should repent me now of sin
+By me done, and occasioned; or rejoice
+Much more, that much more good thereof shall spring;
+To God more glory, more good-will to Men
+From God, and over wrath grace shall abound.
+But say, if our Deliverer up to Heaven
+Must re-ascend, what will betide the few
+His faithful, left among the unfaithful herd,
+The enemies of truth? Who then shall guide
+His people, who defend? Will they not deal
+Worse with his followers than with him they dealt?
+Be sure they will, said the Angel; but from Heaven
+He to his own a Comforter will send,
+The promise of the Father, who shall dwell
+His Spirit within them; and the law of faith,
+Working through love, upon their hearts shall write,
+To guide them in all truth; and also arm
+With spiritual armour, able to resist
+Satan's assaults, and quench his fiery darts;
+What man can do against them, not afraid,
+Though to the death; against such cruelties
+With inward consolations recompensed,
+And oft supported so as shall amaze
+Their proudest persecutors: For the Spirit,
+Poured first on his Apostles, whom he sends
+To evangelize the nations, then on all
+Baptized, shall them with wonderous gifts endue
+To speak all tongues, and do all miracles,
+As did their Lord before them. Thus they win
+Great numbers of each nation to receive
+With joy the tidings brought from Heaven: At length
+Their ministry performed, and race well run,
+Their doctrine and their story written left,
+They die; but in their room, as they forewarn,
+Wolves shall succeed for teachers, grievous wolves,
+Who all the sacred mysteries of Heaven
+To their own vile advantages shall turn
+Of lucre and ambition; and the truth
+With superstitions and traditions taint,
+Left only in those written records pure,
+Though not but by the Spirit understood.
+Then shall they seek to avail themselves of names,
+Places, and titles, and with these to join
+Secular power; though feigning still to act
+By spiritual, to themselves appropriating
+The Spirit of God, promised alike and given
+To all believers; and, from that pretence,
+Spiritual laws by carnal power shall force
+On every conscience; laws which none shall find
+Left them inrolled, or what the Spirit within
+Shall on the heart engrave. What will they then
+But force the Spirit of Grace itself, and bind
+His consort Liberty? what, but unbuild
+His living temples, built by faith to stand,
+Their own faith, not another's? for, on earth,
+Who against faith and conscience can be heard
+Infallible? yet many will presume:
+Whence heavy persecution shall arise
+On all, who in the worship persevere
+Of spirit and truth; the rest, far greater part,
+Will deem in outward rites and specious forms
+Religion satisfied; Truth shall retire
+Bestuck with slanderous darts, and works of faith
+Rarely be found: So shall the world go on,
+To good malignant, to bad men benign;
+Under her own weight groaning; till the day
+Appear of respiration to the just,
+And vengeance to the wicked, at return
+Of him so lately promised to thy aid,
+The Woman's Seed; obscurely then foretold,
+Now ampler known thy Saviour and thy Lord;
+Last, in the clouds, from Heaven to be revealed
+In glory of the Father, to dissolve
+Satan with his perverted world; then raise
+From the conflagrant mass, purged and refined,
+New Heavens, new Earth, ages of endless date,
+Founded in righteousness, and peace, and love;
+To bring forth fruits, joy and eternal bliss.
+He ended; and thus Adam last replied.
+How soon hath thy prediction, Seer blest,
+Measured this transient world, the race of time,
+Till time stand fixed! Beyond is all abyss,
+Eternity, whose end no eye can reach.
+Greatly-instructed I shall hence depart;
+Greatly in peace of thought; and have my fill
+Of knowledge, what this vessel can contain;
+Beyond which was my folly to aspire.
+Henceforth I learn, that to obey is best,
+And love with fear the only God; to walk
+As in his presence; ever to observe
+His providence; and on him sole depend,
+Merciful over all his works, with good
+Still overcoming evil, and by small
+Accomplishing great things, by things deemed weak
+Subverting worldly strong, and worldly wise
+By simply meek: that suffering for truth's sake
+Is fortitude to highest victory,
+And, to the faithful, death the gate of life;
+Taught this by his example, whom I now
+Acknowledge my Redeemer ever blest.
+To whom thus also the Angel last replied.
+This having learned, thou hast attained the sum
+Of wisdom; hope no higher, though all the stars
+Thou knewest by name, and all the ethereal powers,
+All secrets of the deep, all Nature's works,
+Or works of God in Heaven, air, earth, or sea,
+And all the riches of this world enjoyedst,
+And all the rule, one empire; only add
+Deeds to thy knowledge answerable; add faith,
+Add virtue, patience, temperance; add love,
+By name to come called charity, the soul
+Of all the rest: then wilt thou not be loth
+To leave this Paradise, but shalt possess
+A Paradise within thee, happier far.--
+Let us descend now therefore from this top
+Of speculation; for the hour precise
+Exacts our parting hence; and see!the guards,
+By me encamped on yonder hill, expect
+Their motion; at whose front a flaming sword,
+In signal of remove, waves fiercely round:
+We may no longer stay: go, waken Eve;
+Her also I with gentle dreams have calmed
+Portending good, and all her spirits composed
+To meek submission: thou, at season fit,
+Let her with thee partake what thou hast heard;
+Chiefly what may concern her faith to know,
+The great deliverance by her seed to come
+(For by the Woman's seed) on all mankind:
+That ye may live, which will be many days,
+Both in one faith unanimous, though sad,
+With cause, for evils past; yet much more cheered
+With meditation on the happy end.
+He ended, and they both descend the hill;
+Descended, Adam to the bower, where Eve
+Lay sleeping, ran before; but found her waked;
+And thus with words not sad she him received.
+Whence thou returnest, and whither wentest, I know;
+For God is also in sleep; and dreams advise,
+Which he hath sent propitious, some great good
+Presaging, since with sorrow and heart's distress
+Wearied I fell asleep: But now lead on;
+In me is no delay; with thee to go,
+Is to stay here; without thee here to stay,
+Is to go hence unwilling; thou to me
+Art all things under $Heaven, all places thou,
+Who for my wilful crime art banished hence.
+This further consolation yet secure
+I carry hence; though all by me is lost,
+Such favour I unworthy am vouchsafed,
+By me the Promised Seed shall all restore.
+So spake our mother Eve; and Adam heard
+Well pleased, but answered not: For now, too nigh
+The Arch-Angel stood; and, from the other hill
+To their fixed station, all in bright array
+The Cherubim descended; on the ground
+Gliding meteorous, as evening-mist
+Risen from a river o'er the marish glides,
+And gathers ground fast at the labourer's heel
+Homeward returning. High in front advanced,
+The brandished sword of God before them blazed,
+Fierce as a comet; which with torrid heat,
+And vapour as the Libyan air adust,
+Began to parch that temperate clime; whereat
+In either hand the hastening Angel caught
+Our lingering parents, and to the eastern gate
+Led them direct, and down the cliff as fast
+To the subjected plain; then disappeared.
+They, looking back, all the eastern side beheld
+Of Paradise, so late their happy seat,
+Waved over by that flaming brand; the gate
+With dreadful faces thronged, and fiery arms:
+Some natural tears they dropt, but wiped them soon;
+The world was all before them, where to choose
+Their place of rest, and Providence their guide:
+They, hand in hand, with wandering steps and slow,
+Through Eden took their solitary way.
+
+[The End]
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt.compressed
new file mode 100644
index 000000000..1750fa5c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/plrabn12.txt.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox
new file mode 100644
index 000000000..ff3bb6394
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox
@@ -0,0 +1 @@
+The quick brown fox jumps over the lazy dog \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox.compressed
new file mode 100644
index 000000000..b5deebc42
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox.compressed
@@ -0,0 +1 @@
+ €The quick brown fox jumps over the lazy dog \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated
new file mode 100644
index 000000000..2ed134ebc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated
@@ -0,0 +1 @@
+The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dog \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated.compressed
new file mode 100644
index 000000000..f9d797678
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/quickfox_repeated.compressed
@@ -0,0 +1,2 @@
+[ÿ¯À"y\ûZŒB;ô%UZ’™±5Èžž
+{K¹<˜È @óæÙMäme'‡_¦é0–{<ØS \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_chunks b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_chunks
new file mode 100644
index 000000000..c014f0b3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_chunks
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin
new file mode 100644
index 000000000..faf8a3a7b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin.compressed
new file mode 100644
index 000000000..5ffbaa049
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/random_org_10k.bin.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa
new file mode 100644
index 000000000..1072b69b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa
@@ -0,0 +1 @@
+ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies. \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa.compressed
new file mode 100644
index 000000000..f39f068d7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/ukkonooa.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x
new file mode 100644
index 000000000..500c0709c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x
@@ -0,0 +1 @@
+X \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed
new file mode 100644
index 000000000..2a44b5def
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.00 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.00
new file mode 100644
index 000000000..33e3a98e0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.00
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.01 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.01
new file mode 100644
index 000000000..9c8249b16
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.01
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.02 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.02
new file mode 100644
index 000000000..3a5890db7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.02
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.03 b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.03
new file mode 100644
index 000000000..842e7995c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/x.compressed.03
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy
new file mode 100644
index 000000000..fbfb23d1e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy
@@ -0,0 +1 @@
+Xyzzy \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy.compressed
new file mode 100644
index 000000000..e6982cef4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/xyzzy.compressed
@@ -0,0 +1 @@
+ €Xyzzy \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros
new file mode 100644
index 000000000..6d23118f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros.compressed b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros.compressed
new file mode 100644
index 000000000..bf05b53c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/brotli/tests/testdata/zeros.compressed
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stddef.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stddef.h
new file mode 100644
index 000000000..917a17700
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stddef.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party brotli.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BrotliDecUefiSupport.h>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdint.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdint.h
new file mode 100644
index 000000000..917a17700
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdint.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party brotli.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BrotliDecUefiSupport.h>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdlib.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdlib.h
new file mode 100644
index 000000000..917a17700
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/stdlib.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party brotli.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BrotliDecUefiSupport.h>
diff --git a/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/string.h b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/string.h
new file mode 100644
index 000000000..917a17700
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/BrotliCustomDecompressLib/string.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party brotli.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <BrotliDecUefiSupport.h>
diff --git a/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c
new file mode 100644
index 000000000..ecd0886dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c
@@ -0,0 +1,141 @@
+/** @file
+ CPU Exception Handler library implementition with empty functions.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiPei.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Display processor context.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Processor context to be display.
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+}
+
+/**
+ Initializes all CPU exceptions entries with optional extra initializations.
+
+ By default, this method should include all functionalities implemented by
+ InitializeCpuExceptionHandlers(), plus extra initialization works, if any.
+ This could be done by calling InitializeCpuExceptionHandlers() directly
+ in this method besides the extra works.
+
+ InitData is optional and its use and content are processor arch dependent.
+ The typical usage of it is to convey resources which have to be reserved
+ elsewhere and are necessary for the extra initializations of exception.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data optional for extra initializations
+ of exception.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ )
+{
+ return InitializeCpuExceptionHandlers (VectorInfo);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
new file mode 100644
index 000000000..191ae32aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
@@ -0,0 +1,31 @@
+## @file
+# Null instance of CPU Exception Handler Library with empty functions.
+#
+# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuExceptionHandlerLibNull
+ MODULE_UNI_FILE = CpuExceptionHandlerLibNull.uni
+ FILE_GUID = 3175E6B9-4B01-496a-9A2B-64AF02D87E34
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuExceptionHandlerLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ CpuExceptionHandlerLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni
new file mode 100644
index 000000000..611aad827
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null instance of CPU Exception Handler Library with empty functions.
+//
+// Null instance of CPU Exception Handler Library with empty functions.
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of CPU Exception Handler Library with empty functions."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of CPU Exception Handler Library with empty functions."
+
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h
new file mode 100644
index 000000000..f2cbb8940
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h
@@ -0,0 +1,38 @@
+/** @file
+MACRO definitions for color used in Setup Browser.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+//
+// Unicode collation protocol in
+
+#ifndef _COLORS_H_
+#define _COLORS_H_
+
+//
+// Screen Color Settings
+//
+#define PICKLIST_HIGHLIGHT_TEXT EFI_WHITE
+#define PICKLIST_HIGHLIGHT_BACKGROUND EFI_BACKGROUND_CYAN
+#define TITLE_TEXT EFI_WHITE
+#define TITLE_BACKGROUND EFI_BACKGROUND_BLUE
+#define KEYHELP_TEXT EFI_LIGHTGRAY
+#define KEYHELP_BACKGROUND EFI_BACKGROUND_BLACK
+#define SUBTITLE_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define BANNER_TEXT EFI_BLUE
+#define BANNER_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define FIELD_TEXT_GRAYED EFI_DARKGRAY
+#define FIELD_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define POPUP_TEXT EFI_LIGHTGRAY
+#define POPUP_BACKGROUND EFI_BACKGROUND_BLUE
+#define POPUP_INVERSE_TEXT EFI_LIGHTGRAY
+#define POPUP_INVERSE_BACKGROUND EFI_BACKGROUND_BLACK
+#define HELP_TEXT EFI_BLUE
+#define ERROR_TEXT EFI_RED | EFI_BRIGHT
+#define INFO_TEXT EFI_YELLOW | EFI_BRIGHT
+#define ARROW_TEXT EFI_RED | EFI_BRIGHT
+#define ARROW_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c
new file mode 100644
index 000000000..e97a2b94e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c
@@ -0,0 +1,952 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CustomizedDisplayLibInternal.h"
+
+EFI_GUID gCustomizedDisplayLibGuid = { 0x99fdc8fd, 0x849b, 0x4eba, { 0xad, 0x13, 0xfb, 0x96, 0x99, 0xc9, 0xa, 0x4d } };
+
+EFI_HII_HANDLE mCDLStringPackHandle;
+UINT16 gClassOfVfr; // Formset class information
+BOOLEAN gLibIsFirstForm = TRUE;
+BANNER_DATA *gBannerData;
+
+UINTN gFooterHeight;
+
+/**
++------------------------------------------------------------------------------+
+| Setup Page |
++------------------------------------------------------------------------------+
+
+Statement
+Statement
+Statement
+
+
+
+
+
++------------------------------------------------------------------------------+
+| F9=Reset to Defaults F10=Save |
+| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Exit |
++------------------------------------------------------------------------------+
+ StatusBar
+**/
+
+/**
+ This funtion defines Page Frame and Backgroud.
+
+ Based on the above layout, it will be responsible for HeaderHeight, FooterHeight,
+ StatusBarHeight and Backgroud. And, it will reserve Screen for Statement.
+
+ @param[in] FormData Form Data to be shown in Page.
+ @param[out] ScreenForStatement Screen to be used for Statement. (Prompt, Value and Help)
+
+ @return Status
+**/
+EFI_STATUS
+EFIAPI
+DisplayPageFrame (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT EFI_SCREEN_DESCRIPTOR *ScreenForStatement
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FormData != NULL && ScreenForStatement != NULL);
+ if (FormData == NULL || ScreenForStatement == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ScreenDiemensionInfoValidate (FormData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
+
+ ProcessExternedOpcode(FormData);
+
+ //
+ // Calculate the ScreenForStatement.
+ //
+ ScreenForStatement->BottomRow = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight;
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ ScreenForStatement->TopRow = gScreenDimensions.TopRow + FRONT_PAGE_HEADER_HEIGHT;
+ } else {
+ ScreenForStatement->TopRow = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
+ }
+ ScreenForStatement->LeftColumn = gScreenDimensions.LeftColumn;
+ ScreenForStatement->RightColumn = gScreenDimensions.RightColumn;
+
+ if ((gLibIsFirstForm) || ((FormData->Attribute & HII_DISPLAY_MODAL) != 0)) {
+ //
+ // Ensure we are in Text mode
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ ClearLines (0, gScreenDimensions.RightColumn, 0, gScreenDimensions.BottomRow, KEYHELP_BACKGROUND);
+ gLibIsFirstForm = FALSE;
+ }
+
+ //
+ // Don't print frame for modal form.
+ //
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ PrintBannerInfo (FormData);
+ }
+
+ PrintFramework (FormData);
+
+ UpdateStatusBar(NV_UPDATE_REQUIRED, FormData->SettingChangedFlag);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function updates customized key panel's help information.
+ The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-.
+ and arrange them in Footer panel.
+
+ @param[in] FormData Form Data to be shown in Page. FormData has the highlighted statement.
+ @param[in] Statement The statement current selected.
+ @param[in] Selected Whether or not a tag be selected. TRUE means Enter has hit this question.
+**/
+VOID
+EFIAPI
+RefreshKeyHelp (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN BOOLEAN Selected
+ )
+{
+ UINTN SecCol;
+ UINTN ThdCol;
+ UINTN RightColumnOfHelp;
+ UINTN TopRowOfHelp;
+ UINTN BottomRowOfHelp;
+ UINTN StartColumnOfHelp;
+ EFI_IFR_NUMERIC *NumericOp;
+ EFI_IFR_DATE *DateOp;
+ EFI_IFR_TIME *TimeOp;
+ BOOLEAN HexDisplay;
+ UINTN ColumnWidth1;
+ UINTN ColumnWidth2;
+ UINTN ColumnWidth3;
+ CHAR16 *ColumnStr1;
+ CHAR16 *ColumnStr2;
+ CHAR16 *ColumnStr3;
+
+ ASSERT (FormData != NULL);
+ if (FormData == NULL) {
+ return;
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ return;
+ }
+
+ SecCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3;
+ ThdCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3 * 2;
+
+ //
+ // + 2 means leave 1 space before the first hotkey info.
+ //
+ StartColumnOfHelp = gScreenDimensions.LeftColumn + 2;
+ RightColumnOfHelp = gScreenDimensions.RightColumn - 1;
+ TopRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
+ BottomRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
+
+ ColumnWidth1 = SecCol - StartColumnOfHelp;
+ ColumnWidth2 = ThdCol - SecCol;
+ ColumnWidth3 = RightColumnOfHelp - ThdCol;
+ ColumnStr1 = gLibEmptyString;
+ ColumnStr2 = gLibEmptyString;
+ ColumnStr3 = gLibEmptyString;
+
+ //
+ // Clean the space at gScreenDimensions.LeftColumn + 1.
+ //
+ PrintStringAtWithWidth (StartColumnOfHelp - 1, BottomRowOfHelp, gLibEmptyString, 1);
+ PrintStringAtWithWidth (StartColumnOfHelp - 1, TopRowOfHelp, gLibEmptyString, 1);
+
+ if (Statement == NULL) {
+ //
+ // Print Key for Form without showable statement.
+ //
+ PrintHotKeyHelpString (FormData, TRUE);
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, gLibEmptyString, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gLibEmptyString, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gLibEmptyString, ColumnWidth1);
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ return;
+ }
+
+ HexDisplay = FALSE;
+ NumericOp = NULL;
+ DateOp = NULL;
+ TimeOp = NULL;
+ if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
+ NumericOp = (EFI_IFR_NUMERIC *) Statement->OpCode;
+ HexDisplay = (NumericOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ DateOp = (EFI_IFR_DATE *) Statement->OpCode;
+ HexDisplay = (DateOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ TimeOp = (EFI_IFR_TIME *) Statement->OpCode;
+ HexDisplay = (TimeOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ }
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_TIME_OP:
+ case EFI_IFR_DATE_OP:
+ if (!Selected) {
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ PrintAt (
+ ColumnWidth1,
+ StartColumnOfHelp,
+ BottomRowOfHelp,
+ L"%c%c%c%c%s",
+ ARROW_UP,
+ ARROW_DOWN,
+ ARROW_RIGHT,
+ ARROW_LEFT,
+ gMoveHighlight
+ );
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterString, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber, ColumnWidth1);
+ } else {
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP && NumericOp != NULL && LibGetFieldFromNum(Statement->OpCode) != 0) {
+ ColumnStr1 = gAdjustNumber;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterString, ColumnWidth2);
+ }
+ } else {
+ PrintHotKeyHelpString (FormData, FALSE);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterCommitString, ColumnWidth2);
+
+ //
+ // If it is a selected numeric with manual input, display different message
+ //
+ if ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ ColumnStr2 = HexDisplay ? gHexNumericInput : gDecNumericInput;
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, gLibEmptyString, ColumnWidth1);
+ } else {
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ }
+
+ if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
+ ColumnStr1 = gPlusString;
+ ColumnStr3 = gMinusString;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (ThdCol, TopRowOfHelp, ColumnStr3, ColumnWidth3);
+ PrintStringAtWithWidth (SecCol, TopRowOfHelp, ColumnStr2, ColumnWidth2);
+
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, gEnterEscapeString, ColumnWidth3);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gToggleCheckBox, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gLibEmptyString, ColumnWidth1);
+ break;
+
+ case EFI_IFR_REF_OP:
+ case EFI_IFR_PASSWORD_OP:
+ case EFI_IFR_STRING_OP:
+ case EFI_IFR_TEXT_OP:
+ case EFI_IFR_ACTION_OP:
+ case EFI_IFR_RESET_BUTTON_OP:
+ case EFI_IFR_SUBTITLE_OP:
+ if (!Selected) {
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ if (Statement->OpCode->OpCode != EFI_IFR_TEXT_OP && Statement->OpCode->OpCode != EFI_IFR_SUBTITLE_OP) {
+ ColumnStr2 = gEnterString;
+ }
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, ColumnStr2, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ } else {
+ PrintHotKeyHelpString (FormData, FALSE);
+ if (Statement->OpCode->OpCode != EFI_IFR_REF_OP) {
+ ColumnStr2 = gEnterCommitString;
+ ColumnStr3 = gEnterEscapeString;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, ColumnStr2, ColumnWidth2);
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Update status bar.
+
+ This function updates the status bar on the bottom of menu screen. It just shows StatusBar.
+ Original logic in this function should be splitted out.
+
+ @param[in] MessageType The type of message to be shown. InputError or Configuration Changed.
+ @param[in] State Show or Clear Message.
+**/
+VOID
+EFIAPI
+UpdateStatusBar (
+ IN UINTN MessageType,
+ IN BOOLEAN State
+ )
+{
+ UINTN Index;
+ CHAR16 OptionWidth;
+
+ OptionWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
+
+ switch (MessageType) {
+ case INPUT_ERROR:
+ if (State) {
+ gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + OptionWidth,
+ gScreenDimensions.BottomRow - 1,
+ gInputErrorMessage
+ );
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);
+ for (Index = 0; Index < (LibGetStringWidth (gInputErrorMessage) - 2) / 2; Index++) {
+ PrintStringAt (gScreenDimensions.LeftColumn + OptionWidth + Index, gScreenDimensions.BottomRow - 1, L" ");
+ }
+ }
+ break;
+
+ case NV_UPDATE_REQUIRED:
+ //
+ // Global setting support. Show configuration change on every form.
+ //
+ if (State) {
+ gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + OptionWidth * 2,
+ gScreenDimensions.BottomRow - 1,
+ gNvUpdateMessage
+ );
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);
+ for (Index = 0; Index < (LibGetStringWidth (gNvUpdateMessage) - 2) / 2; Index++) {
+ PrintStringAt (
+ (gScreenDimensions.LeftColumn + OptionWidth * 2 + Index),
+ gScreenDimensions.BottomRow - 1,
+ L" "
+ );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create popup window. It will replace CreateDialog().
+
+ This function draws OEM/Vendor specific pop up windows.
+
+ @param[out] Key User Input Key
+ @param ... String to be shown in Popup. The variable argument list is terminated by a NULL.
+
+**/
+VOID
+EFIAPI
+CreateDialog (
+ OUT EFI_INPUT_KEY *Key, OPTIONAL
+ ...
+ )
+{
+ VA_LIST Marker;
+ EFI_INPUT_KEY KeyValue;
+ EFI_STATUS Status;
+ UINTN LargestString;
+ UINTN LineNum;
+ UINTN Index;
+ UINTN Count;
+ CHAR16 Character;
+ UINTN Start;
+ UINTN End;
+ UINTN Top;
+ UINTN Bottom;
+ CHAR16 *String;
+ UINTN DimensionsWidth;
+ UINTN DimensionsHeight;
+ UINTN CurrentAttribute;
+ BOOLEAN CursorVisible;
+
+ //
+ // If screen dimension info is not ready, get it from console.
+ //
+ if (gScreenDimensions.RightColumn == 0 || gScreenDimensions.BottomRow == 0) {
+ ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (
+ gST->ConOut,
+ gST->ConOut->Mode->Mode,
+ &gScreenDimensions.RightColumn,
+ &gScreenDimensions.BottomRow
+ );
+ }
+
+ DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
+ DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
+
+ LargestString = 0;
+ LineNum = 0;
+ VA_START (Marker, Key);
+ while ((String = VA_ARG (Marker, CHAR16 *)) != NULL) {
+ LineNum ++;
+
+ if ((LibGetStringWidth (String) / 2) > LargestString) {
+ LargestString = (LibGetStringWidth (String) / 2);
+ }
+ }
+ VA_END (Marker);
+
+ if ((LargestString + 2) > DimensionsWidth) {
+ LargestString = DimensionsWidth - 2;
+ }
+
+ CurrentAttribute = gST->ConOut->Mode->Attribute;
+ CursorVisible = gST->ConOut->Mode->CursorVisible;
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+
+ //
+ // Subtract the PopUp width from total Columns, allow for one space extra on
+ // each end plus a border.
+ //
+ Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;
+ End = Start + LargestString + 1;
+
+ Top = ((DimensionsHeight - LineNum - 2) / 2) + gScreenDimensions.TopRow - 1;
+ Bottom = Top + LineNum + 2;
+
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (Start, Top, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ Character = BOXDRAW_VERTICAL;
+
+ Count = 0;
+ VA_START (Marker, Key);
+ for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
+ String = VA_ARG (Marker, CHAR16*);
+
+ if (String[0] == CHAR_NULL) {
+ //
+ // Passing in a NULL results in a blank space
+ //
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ } else if (String[0] == L' ') {
+ //
+ // Passing in a space results in the assumption that this is where typing will occur
+ //
+ ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);
+ PrintStringAt (
+ ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
+ Index + 1,
+ String + 1
+ );
+ } else {
+ //
+ // This will clear the background of the line - we never know who might have been
+ // here before us. This differs from the next clear in that it used the non-reverse
+ // video for normal printing.
+ //
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ PrintStringAt (
+ ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
+ Index + 1,
+ String
+ );
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+ PrintCharAt (Start, Index + 1, Character);
+ PrintCharAt (End - 1, Index + 1, Character);
+ }
+ VA_END (Marker);
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (Start, Bottom - 1, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+ }
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+
+ if (Key != NULL) {
+ Status = WaitForKeyStroke (&KeyValue);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (Key, &KeyValue, sizeof (EFI_INPUT_KEY));
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
+ gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
+}
+
+/**
+ Confirm how to handle the changed data.
+
+ @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.
+**/
+UINTN
+EFIAPI
+ConfirmDataChange (
+ VOID
+ )
+{
+ CHAR16 YesResponse;
+ CHAR16 NoResponse;
+ EFI_INPUT_KEY Key;
+
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ YesResponse = gYesResponse[0];
+ NoResponse = gNoResponse[0];
+
+ //
+ // If NV flag is up, prompt user
+ //
+ do {
+ CreateDialog (&Key, gLibEmptyString, gSaveChanges, gAreYouSure, gLibEmptyString, NULL);
+ } while
+ (
+ (Key.ScanCode != SCAN_ESC) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
+ );
+
+ if (Key.ScanCode == SCAN_ESC) {
+ return BROWSER_ACTION_NONE;
+ } else if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
+ return BROWSER_ACTION_SUBMIT;
+ } else {
+ return BROWSER_ACTION_DISCARD;
+ }
+}
+
+/**
+ OEM specifies whether Setup exits Page by ESC key.
+
+ This function customized the behavior that whether Setup exits Page so that
+ system able to boot when configuration is not changed.
+
+ @retval TRUE Exits FrontPage
+ @retval FALSE Don't exit FrontPage.
+**/
+BOOLEAN
+EFIAPI
+FormExitPolicy (
+ VOID
+ )
+{
+ return gClassOfVfr == FORMSET_CLASS_FRONT_PAGE ? FALSE : TRUE;
+}
+
+/**
+ Set Timeout value for a ceratain Form to get user response.
+
+ This function allows to set timeout value on a ceratain form if necessary.
+ If timeout is not zero, the form will exit if user has no response in timeout.
+
+ @param[in] FormData Form Data to be shown in Page
+
+ @return 0 No timeout for this form.
+ @return > 0 Timeout value in 100 ns units.
+**/
+UINT64
+EFIAPI
+FormExitTimeout (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ return 0;
+}
+//
+// Print Functions
+//
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String
+ )
+{
+ return PrintAt (0, Column, Row, L"%s", String);
+}
+
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+ @param Width Width for String.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAtWithWidth (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String,
+ IN UINTN Width
+ )
+{
+ return PrintAt (Width, Column, Row, L"%s", String);
+}
+
+/**
+ Prints a character to the default console, at
+ the supplied cursor position, using L"%c" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param Character Character to print.
+
+ @return Length of string printed to the console.
+
+**/
+UINTN
+EFIAPI
+PrintCharAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ CHAR16 Character
+ )
+{
+ return PrintAt (0, Column, Row, L"%c", Character);
+}
+
+/**
+ Clear retangle with specified text attribute.
+
+ @param LeftColumn Left column of retangle.
+ @param RightColumn Right column of retangle.
+ @param TopRow Start row of retangle.
+ @param BottomRow End row of retangle.
+ @param TextAttribute The character foreground and background.
+
+**/
+VOID
+EFIAPI
+ClearLines (
+ IN UINTN LeftColumn,
+ IN UINTN RightColumn,
+ IN UINTN TopRow,
+ IN UINTN BottomRow,
+ IN UINTN TextAttribute
+ )
+{
+ CHAR16 *Buffer;
+ UINTN Row;
+
+ //
+ // For now, allocate an arbitrarily long buffer
+ //
+ Buffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer != NULL);
+
+ //
+ // Set foreground and background as defined
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);
+
+ //
+ // Much faster to buffer the long string instead of print it a character at a time
+ //
+ LibSetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');
+
+ //
+ // Clear the desired area with the appropriate foreground/background
+ //
+ for (Row = TopRow; Row <= BottomRow; Row++) {
+ PrintStringAt (LeftColumn, Row, Buffer);
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);
+
+ FreePool (Buffer);
+}
+
+//
+// Color Setting Functions
+//
+
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup color.
+**/
+UINT8
+EFIAPI
+GetPopupColor (
+ VOID
+ )
+{
+ return POPUP_TEXT | POPUP_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup inverse color.
+**/
+UINT8
+EFIAPI
+GetPopupInverseColor (
+ VOID
+ )
+{
+ return POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific PickList color attribute.
+
+ @retval Byte code color setting for pick list color.
+**/
+UINT8
+EFIAPI
+GetPickListColor (
+ VOID
+ )
+{
+ return PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific arrow color attribute.
+
+ @retval Byte code color setting for arrow color.
+**/
+UINT8
+EFIAPI
+GetArrowColor (
+ VOID
+ )
+{
+ return ARROW_TEXT | ARROW_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific info text color attribute.
+
+ @retval Byte code color setting for info text color.
+**/
+UINT8
+EFIAPI
+GetInfoTextColor (
+ VOID
+ )
+{
+ return INFO_TEXT | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific help text color attribute.
+
+ @retval Byte code color setting for help text color.
+**/
+UINT8
+EFIAPI
+GetHelpTextColor (
+ VOID
+ )
+{
+ return HELP_TEXT | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific grayed out text color attribute.
+
+ @retval Byte code color setting for grayed out text color.
+**/
+UINT8
+EFIAPI
+GetGrayedTextColor (
+ VOID
+ )
+{
+ return FIELD_TEXT_GRAYED | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific highlighted text color attribute.
+
+ @retval Byte code color setting for highlight text color.
+**/
+UINT8
+EFIAPI
+GetHighlightTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);
+}
+
+/**
+ Get OEM/Vendor specific field text color attribute.
+
+ @retval Byte code color setting for field text color.
+**/
+UINT8
+EFIAPI
+GetFieldTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific subtitle text color attribute.
+
+ @retval Byte code color setting for subtitle text color.
+**/
+UINT8
+EFIAPI
+GetSubTitleTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND;
+}
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+ClearDisplayPage (
+ VOID
+ )
+{
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gLibIsFirstForm = TRUE;
+}
+
+/**
+ Constructor 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 constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomizedDisplayLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mCDLStringPackHandle = HiiAddPackages (&gCustomizedDisplayLibGuid, ImageHandle, CustomizedDisplayLibStrings, NULL);
+ ASSERT (mCDLStringPackHandle != NULL);
+
+ InitializeLibStrings();
+
+ 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
+CustomizedDisplayLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ HiiRemovePackages(mCDLStringPackHandle);
+
+ FreeLibStrings ();
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
new file mode 100644
index 000000000..45fbdaf86
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
@@ -0,0 +1,60 @@
+## @file
+# Customize display library used by display engine.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CustomizedDisplayLib
+ MODULE_UNI_FILE = CustomizedDisplayLibModStrs.uni
+ FILE_GUID = 80B92017-EC64-4923-938D-94FAEE85832E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CustomizedDisplayLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = CustomizedDisplayLibConstructor
+ DESTRUCTOR = CustomizedDisplayLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ CustomizedDisplayLib.c
+ Colors.h
+ CustomizedDisplayLibInternal.h
+ CustomizedDisplayLibInternal.c
+ CustomizedDisplayLib.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ DevicePathLib
+ PcdLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrontPageFormSetGuid ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni
new file mode 100644
index 000000000..3f2efa562
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni
@@ -0,0 +1,57 @@
+// *++
+//
+// Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// SetupBrowserStr.uni
+//
+// Abstract:
+//
+// String definitions for Browser.
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string ENTER_STRING #language en-US "<Enter>=Select Entry"
+ #language fr-FR "<Enter>=Choisir l'Entrée"
+#string ENTER_COMMIT_STRING #language en-US "<Enter>=Complete Entry"
+ #language fr-FR "<Enter>=Compléter l'Entrée"
+#string ENTER_ESCAPE_STRING #language en-US "Esc=Exit Entry"
+ #language fr-FR "Esc=Sortir l'Entrée"
+#string ESCAPE_STRING #language en-US "Esc=Exit"
+ #language fr-FR "Esc=Sortir"
+#string ADJUST_NUMBER #language en-US "+/- =Adjust Value"
+ #language fr-FR "+/- =Ajuster la valeur"
+#string PLUS_STRING #language en-US "+ =Move Selection Up"
+ #language fr-FR "+ =Relever le choix"
+#string MINUS_STRING #language en-US "- =Move Selection Down"
+ #language fr-FR "- =Abaisser le choix"
+#string MOVE_HIGHLIGHT #language en-US "=Move Highlight"
+ #language fr-FR "=Essentiel de mouvement"
+#string DEC_NUMERIC_INPUT #language en-US "0123456789 are valid inputs"
+ #language fr-FR "0123456789 sont des données valides"
+#string HEX_NUMERIC_INPUT #language en-US "0-9 a-f are valid inputs"
+ #language fr-FR "0-9 a-f sont des données valides"
+#string TOGGLE_CHECK_BOX #language en-US "<Spacebar>Toggle Checkbox"
+ #language fr-FR "<Spacebar>Bascule la Case de pointage"
+#string NV_UPDATE_MESSAGE #language en-US "Configuration changed"
+ #language fr-FR "Configuration changed"
+#string INPUT_ERROR_MESSAGE #language en-US "!!"
+ #language fr-FR "!!"
+#string EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+#string ARE_YOU_SURE_YES #language en-US "Y"
+ #language fr-FR "Y"
+#string ARE_YOU_SURE_NO #language en-US "N"
+ #language fr-FR "N"
+#string SAVE_CHANGES #language en-US "Changes have not saved. Save Changes and exit?"
+ #language fr-FR "Enregistrer les modifications et quitter?"
+#string ARE_YOU_SURE #language en-US "Press 'Y' to save and exit, 'N' to discard and exit, 'ESC' to cancel."
+ #language fr-FR "Pressez 'Y' pour sauvegarder et quitter, 'N' de se défaire et de sortie"
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c
new file mode 100644
index 000000000..d770a0f87
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c
@@ -0,0 +1,978 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CustomizedDisplayLibInternal.h"
+
+EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+CHAR16 *mLibUnknownString;
+extern EFI_HII_HANDLE mCDLStringPackHandle;
+CHAR16 *mSpaceBuffer;
+#define SPACE_BUFFER_SIZE 1000
+
+//
+// Browser Global Strings
+//
+CHAR16 *gEnterString;
+CHAR16 *gEnterCommitString;
+CHAR16 *gEnterEscapeString;
+CHAR16 *gEscapeString;
+CHAR16 *gMoveHighlight;
+CHAR16 *gDecNumericInput;
+CHAR16 *gHexNumericInput;
+CHAR16 *gToggleCheckBox;
+CHAR16 *gLibEmptyString;
+CHAR16 *gAreYouSure;
+CHAR16 *gYesResponse;
+CHAR16 *gNoResponse;
+CHAR16 *gPlusString;
+CHAR16 *gMinusString;
+CHAR16 *gAdjustNumber;
+CHAR16 *gSaveChanges;
+CHAR16 *gNvUpdateMessage;
+CHAR16 *gInputErrorMessage;
+
+/**
+
+ Print banner info for front page.
+
+ @param[in] FormData Form Data to be shown in Page
+
+**/
+VOID
+PrintBannerInfo (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINT8 Line;
+ UINT8 Alignment;
+ CHAR16 *StrFrontPageBanner;
+ UINT8 RowIdx;
+ UINT8 ColumnIdx;
+
+ //
+ // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
+ //
+ ClearLines (
+ gScreenDimensions.LeftColumn,
+ gScreenDimensions.RightColumn,
+ gScreenDimensions.TopRow,
+ FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow,
+ BANNER_TEXT | BANNER_BACKGROUND
+ );
+
+ //
+ // for (Line = 0; Line < BANNER_HEIGHT; Line++) {
+ //
+ for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) {
+ //
+ // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
+ //
+ for (Alignment = (UINT8) gScreenDimensions.LeftColumn;
+ Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn;
+ Alignment++
+ ) {
+ RowIdx = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow);
+ ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn);
+
+ ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS);
+
+ if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {
+ StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle);
+ } else {
+ continue;
+ }
+
+ switch (Alignment - gScreenDimensions.LeftColumn) {
+ case 0:
+ //
+ // Handle left column
+ //
+ PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);
+ break;
+
+ case 1:
+ //
+ // Handle center column
+ //
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3,
+ Line,
+ StrFrontPageBanner
+ );
+ break;
+
+ case 2:
+ //
+ // Handle right column
+ //
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3,
+ Line,
+ StrFrontPageBanner
+ );
+ break;
+ }
+
+ FreePool (StrFrontPageBanner);
+ }
+ }
+}
+
+/**
+ Print framework and form title for a page.
+
+ @param[in] FormData Form Data to be shown in Page
+**/
+VOID
+PrintFramework (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINTN Index;
+ CHAR16 Character;
+ CHAR16 *Buffer;
+ UINTN Row;
+ CHAR16 *TitleStr;
+ UINTN TitleColumn;
+
+ if (gClassOfVfr != FORMSET_CLASS_PLATFORM_SETUP) {
+ //
+ // Only Setup page needs Framework
+ //
+ ClearLines (
+ gScreenDimensions.LeftColumn,
+ gScreenDimensions.RightColumn,
+ gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,
+ gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1,
+ KEYHELP_TEXT | KEYHELP_BACKGROUND
+ );
+ return;
+ }
+
+ Buffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer != NULL);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) {
+ Buffer[Index] = Character;
+ }
+
+ //
+ // Print Top border line
+ // +------------------------------------------------------------------------------+
+ // ? ?
+ // +------------------------------------------------------------------------------+
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
+ Character = BOXDRAW_DOWN_RIGHT;
+
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow, Character);
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ Character = BOXDRAW_VERTICAL;
+ for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
+ PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
+ PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
+ }
+
+ //
+ // Print Form Title
+ //
+ TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle);
+ ASSERT (TitleStr != NULL);
+ TitleColumn = (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2;
+ PrintStringAtWithWidth (gScreenDimensions.LeftColumn + 1, gScreenDimensions.TopRow + 1, gLibEmptyString, TitleColumn - gScreenDimensions.LeftColumn - 1);
+ PrintStringAtWithWidth (
+ TitleColumn,
+ gScreenDimensions.TopRow + 1,
+ TitleStr,
+ gScreenDimensions.RightColumn - 1 - TitleColumn
+ );
+ FreePool (TitleStr);
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ //
+ // Print Bottom border line
+ // +------------------------------------------------------------------------------+
+ // ? ?
+ // +------------------------------------------------------------------------------+
+ //
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);
+
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+ Character = BOXDRAW_VERTICAL;
+ for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
+ Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
+ Row++
+ ) {
+ PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
+ PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
+ }
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
+
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ FreePool (Buffer);
+}
+
+/**
+ Process some op code which is not recognized by browser core.
+
+ @param OpCodeData The pointer to the op code buffer.
+
+ @return EFI_SUCCESS Pass the statement success.
+
+**/
+VOID
+ProcessUserOpcode(
+ IN EFI_IFR_OP_HEADER *OpCodeData
+ )
+{
+ EFI_GUID * ClassGuid;
+ UINT8 ClassGuidNum;
+
+ ClassGuid = NULL;
+ ClassGuidNum = 0;
+
+ switch (OpCodeData->OpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // process the statement outside of form,if it is formset op, get its formsetguid or classguid and compared with gFrontPageFormSetGuid
+ //
+ if (CompareMem (PcdGetPtr (PcdFrontPageFormSetGuid), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) == 0){
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ } else{
+ ClassGuidNum = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *)(VOID *)((UINT8 *)OpCodeData + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0){
+ if (CompareGuid((EFI_GUID*)PcdGetPtr (PcdFrontPageFormSetGuid),ClassGuid)){
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ break;
+ }
+ ClassGuid ++;
+ }
+ }
+ break;
+
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
+ //
+ // Tiano specific GUIDed opcodes
+ //
+ switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {
+ case EFI_IFR_EXTEND_OP_LABEL:
+ //
+ // just ignore label
+ //
+ break;
+
+ case EFI_IFR_EXTEND_OP_BANNER:
+ //
+ // Only in front page form set, we care about the banner data.
+ //
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ //
+ // Initialize Driver private data
+ //
+ if (gBannerData == NULL) {
+ gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
+ ASSERT (gBannerData != NULL);
+ }
+
+ CopyMem (
+ &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][
+ ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],
+ &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,
+ sizeof (EFI_STRING_ID)
+ );
+ }
+ break;
+
+ case EFI_IFR_EXTEND_OP_SUBCLASS:
+ if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Process some op codes which is out side of current form.
+
+ @param FormData Pointer to the form data.
+
+ @return EFI_SUCCESS Pass the statement success.
+
+**/
+VOID
+ProcessExternedOpcode (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NestLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
+
+ Link = GetFirstNode (&FormData->StatementListOSF);
+ while (!IsNull (&FormData->StatementListOSF, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&FormData->StatementListOSF, Link);
+
+ ProcessUserOpcode(Statement->OpCode);
+ }
+
+ Link = GetFirstNode (&FormData->StatementListHead);
+ while (!IsNull (&FormData->StatementListHead, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&FormData->StatementListHead, Link);
+
+ ProcessUserOpcode(Statement->OpCode);
+
+ NestLink = GetFirstNode (&Statement->NestStatementList);
+ while (!IsNull (&Statement->NestStatementList, NestLink)) {
+ NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
+ NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
+
+ ProcessUserOpcode(NestStatement->OpCode);
+ }
+
+ }
+}
+
+/**
+ Validate the input screen diemenstion info.
+
+ @param FormData The input form data info.
+
+ @return EFI_SUCCESS The input screen info is acceptable.
+ @return EFI_INVALID_PARAMETER The input screen info is not acceptable.
+
+**/
+EFI_STATUS
+ScreenDiemensionInfoValidate (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN Index;
+
+ //
+ // Calculate total number of Register HotKeys.
+ //
+ Index = 0;
+ if (!IsListEmpty (&FormData->HotKeyListHead)){
+ Link = GetFirstNode (&FormData->HotKeyListHead);
+ while (!IsNull (&FormData->HotKeyListHead, Link)) {
+ Link = GetNextNode (&FormData->HotKeyListHead, Link);
+ Index ++;
+ }
+ }
+
+ //
+ // Show three HotKeys help information on one row.
+ //
+ gFooterHeight = FOOTER_HEIGHT + (Index / 3);
+
+
+ ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (
+ gST->ConOut,
+ gST->ConOut->Mode->Mode,
+ &gScreenDimensions.RightColumn,
+ &gScreenDimensions.BottomRow
+ );
+
+ //
+ // Check local dimension vs. global dimension.
+ //
+ if (FormData->ScreenDimensions != NULL) {
+ if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) ||
+ (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Local dimension validation.
+ //
+ if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) &&
+ (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) &&
+ ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) &&
+ ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
+ FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) {
+ CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+LibGetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING String;
+
+ String = HiiGetString (HiiHandle, Token, NULL);
+ if (String == NULL) {
+ String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString);
+ ASSERT (String != NULL);
+ }
+
+ return (CHAR16 *) String;
+}
+
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+LibGetStringWidth (
+ IN CHAR16 *String
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN IncrementValue;
+
+ ASSERT (String != NULL);
+ if (String == NULL) {
+ return 0;
+ }
+
+ Index = 0;
+ Count = 0;
+ IncrementValue = 1;
+
+ do {
+ //
+ // Advance to the null-terminator or to the first width directive
+ //
+ for (;
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
+ Index++, Count = Count + IncrementValue
+ )
+ ;
+
+ //
+ // We hit the null-terminator, we now have a count
+ //
+ if (String[Index] == 0) {
+ break;
+ }
+ //
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
+ //
+ if (String[Index] == NARROW_CHAR) {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 1;
+ } else {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 2;
+ }
+ } while (String[Index] != 0);
+
+ //
+ // Increment by one to include the null-terminator in the size
+ //
+ Count++;
+
+ return Count * sizeof (CHAR16);
+}
+
+/**
+ Show all registered HotKey help strings on bottom Rows.
+
+ @param FormData The curent input form data info.
+ @param SetState Set HotKey or Clear HotKey
+
+**/
+VOID
+PrintHotKeyHelpString (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN BOOLEAN SetState
+ )
+{
+ UINTN CurrentCol;
+ UINTN CurrentRow;
+ UINTN BottomRowOfHotKeyHelp;
+ UINTN ColumnIndexWidth;
+ UINTN ColumnWidth;
+ UINTN ColumnIndex;
+ UINTN Index;
+ EFI_SCREEN_DESCRIPTOR LocalScreen;
+ LIST_ENTRY *Link;
+ BROWSER_HOT_KEY *HotKey;
+ CHAR16 BakChar;
+ CHAR16 *ColumnStr;
+
+ CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
+ BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;
+ ColumnStr = gLibEmptyString;
+
+ //
+ // Calculate total number of Register HotKeys.
+ //
+ Index = 0;
+ Link = GetFirstNode (&FormData->HotKeyListHead);
+ while (!IsNull (&FormData->HotKeyListHead, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+ //
+ // Calculate help information Column and Row.
+ //
+ ColumnIndex = Index % 3;
+ if (ColumnIndex == 0) {
+ CurrentCol = LocalScreen.LeftColumn + 2 * ColumnWidth;
+ ColumnIndexWidth = ColumnWidth - 1;
+ } else if (ColumnIndex == 1) {
+ CurrentCol = LocalScreen.LeftColumn + ColumnWidth;
+ ColumnIndexWidth = ColumnWidth;
+ } else {
+ CurrentCol = LocalScreen.LeftColumn + 2;
+ ColumnIndexWidth = ColumnWidth - 2;
+ }
+ CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
+
+ //
+ // Help string can't exceed ColumnWidth. One Row will show three Help information.
+ //
+ BakChar = L'\0';
+ if (StrLen (HotKey->HelpString) > ColumnIndexWidth) {
+ BakChar = HotKey->HelpString[ColumnIndexWidth];
+ HotKey->HelpString[ColumnIndexWidth] = L'\0';
+ }
+
+ //
+ // Print HotKey help string on bottom Row.
+ //
+ if (SetState) {
+ ColumnStr = HotKey->HelpString;
+ }
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, ColumnStr, ColumnIndexWidth);
+
+ if (BakChar != L'\0') {
+ HotKey->HelpString[ColumnIndexWidth] = BakChar;
+ }
+ //
+ // Get Next Hot Key.
+ //
+ Link = GetNextNode (&FormData->HotKeyListHead, Link);
+ Index ++;
+ }
+
+ if (SetState) {
+ //
+ // Clear KeyHelp
+ //
+ CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
+ ColumnIndex = Index % 3;
+ if (ColumnIndex == 0) {
+ CurrentCol = LocalScreen.LeftColumn + 2 * ColumnWidth;
+ ColumnIndexWidth = ColumnWidth - 1;
+ ColumnIndex ++;
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
+ }
+ if (ColumnIndex == 1) {
+ CurrentCol = LocalScreen.LeftColumn + ColumnWidth;
+ ColumnIndexWidth = ColumnWidth;
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
+ }
+ }
+
+ return;
+}
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+LibGetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_NUMERIC *NumericOp;
+ UINT64 Step;
+
+ NumericOp = (EFI_IFR_NUMERIC *) OpCode;
+
+ switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ Step = NumericOp->data.u8.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ Step = NumericOp->data.u16.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ Step = NumericOp->data.u32.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ Step = NumericOp->data.u64.Step;
+ break;
+
+ default:
+ Step = 0;
+ break;
+ }
+
+ return Step;
+}
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeLibStrings (
+ VOID
+ )
+{
+ mLibUnknownString = L"!";
+
+ gEnterString = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle);
+ gEnterCommitString = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle);
+ gEnterEscapeString = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle);
+ gEscapeString = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle);
+ gMoveHighlight = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle);
+ gDecNumericInput = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle);
+ gHexNumericInput = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle);
+ gToggleCheckBox = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle);
+
+ gAreYouSure = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle);
+ gYesResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle);
+ gNoResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle);
+ gPlusString = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle);
+ gMinusString = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle);
+ gAdjustNumber = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle);
+ gSaveChanges = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle);
+
+ gLibEmptyString = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle);
+
+ gNvUpdateMessage = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle);
+ gInputErrorMessage = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle);
+
+ //
+ // SpaceBuffer;
+ //
+ mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16));
+ ASSERT (mSpaceBuffer != NULL);
+ LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' ');
+ mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0';
+}
+
+
+/**
+ Free the HII String.
+
+**/
+VOID
+FreeLibStrings (
+ VOID
+ )
+{
+ FreePool (gEnterString);
+ FreePool (gEnterCommitString);
+ FreePool (gEnterEscapeString);
+ FreePool (gEscapeString);
+ FreePool (gMoveHighlight);
+ FreePool (gDecNumericInput);
+ FreePool (gHexNumericInput);
+ FreePool (gToggleCheckBox);
+
+ FreePool (gAreYouSure);
+ FreePool (gYesResponse);
+ FreePool (gNoResponse);
+ FreePool (gPlusString);
+ FreePool (gMinusString);
+ FreePool (gAdjustNumber);
+ FreePool (gSaveChanges);
+
+ FreePool (gLibEmptyString);
+
+ FreePool (gNvUpdateMessage);
+ FreePool (gInputErrorMessage);
+
+ FreePool (mSpaceBuffer);
+}
+
+/**
+ Wait for a key to be pressed by user.
+
+ @param Key The key which is pressed by user.
+
+ @retval EFI_SUCCESS The function always completed successfully.
+
+**/
+EFI_STATUS
+WaitForKeyStroke (
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ }
+ return Status;
+}
+
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+LibSetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ )
+{
+ CHAR16 *Ptr;
+
+ Ptr = Buffer;
+ while ((Size--) != 0) {
+ *(Ptr++) = Value;
+ }
+}
+
+/**
+ The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
+ protocol instance.
+
+ @param Width Width of string to be print.
+ @param Column The position of the output string.
+ @param Row The position of the output string.
+ @param Out The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Fmt The format string.
+ @param Args The additional argument for the variables in the format string.
+
+ @return Number of Unicode character printed.
+
+**/
+UINTN
+PrintInternal (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
+ IN CHAR16 *Fmt,
+ IN VA_LIST Args
+ )
+{
+ CHAR16 *Buffer;
+ CHAR16 *BackupBuffer;
+ UINTN Index;
+ UINTN PreviousIndex;
+ UINTN Count;
+ UINTN TotalCount;
+ UINTN PrintWidth;
+ UINTN CharWidth;
+
+ //
+ // For now, allocate an arbitrarily long buffer
+ //
+ Buffer = AllocateZeroPool (0x10000);
+ BackupBuffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer);
+ ASSERT (BackupBuffer);
+
+ if (Column != (UINTN) -1) {
+ Out->SetCursorPosition (Out, Column, Row);
+ }
+
+ UnicodeVSPrint (Buffer, 0x10000, Fmt, Args);
+
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+
+ Index = 0;
+ PreviousIndex = 0;
+ Count = 0;
+ TotalCount = 0;
+ PrintWidth = 0;
+ CharWidth = 1;
+
+ do {
+ for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) {
+ BackupBuffer[Index] = Buffer[Index];
+ }
+
+ if (Buffer[Index] == 0) {
+ break;
+ }
+
+ //
+ // Print this out, we are about to switch widths
+ //
+ Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
+ Count = StrLen (&BackupBuffer[PreviousIndex]);
+ PrintWidth += Count * CharWidth;
+ TotalCount += Count;
+
+ //
+ // Preserve the current index + 1, since this is where we will start printing from next
+ //
+ PreviousIndex = Index + 1;
+
+ //
+ // We are at a narrow or wide character directive. Set attributes and strip it and print it
+ //
+ if (Buffer[Index] == NARROW_CHAR) {
+ //
+ // Preserve bits 0 - 6 and zero out the rest
+ //
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ CharWidth = 1;
+ } else {
+ //
+ // Must be wide, set bit 7 ON
+ //
+ Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ CharWidth = 2;
+ }
+
+ Index++;
+
+ } while (Buffer[Index] != 0);
+
+ //
+ // We hit the end of the string - print it
+ //
+ Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
+ Count = StrLen (&BackupBuffer[PreviousIndex]);
+ PrintWidth += Count * CharWidth;
+ TotalCount += Count;
+ if (PrintWidth < Width) {
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]);
+ }
+
+ FreePool (Buffer);
+ FreePool (BackupBuffer);
+ return TotalCount;
+}
+
+/**
+ Prints a formatted unicode string to the default console, at
+ the supplied cursor position.
+
+ @param Width Width of String to be printed.
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at.
+ @param Fmt Format string.
+ @param ... Variable argument list for format string.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintAt (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *Fmt,
+ ...
+ )
+{
+ VA_LIST Args;
+ UINTN LengthOfPrinted;
+
+ VA_START (Args, Fmt);
+ LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args);
+ VA_END (Args);
+ return LengthOfPrinted;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h
new file mode 100644
index 000000000..08a330401
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h
@@ -0,0 +1,291 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__
+#define __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__
+
+
+
+#include <PiDxe.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/FormBrowserEx2.h>
+#include <Protocol/DisplayProtocol.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/UserManager.h>
+#include <Protocol/DevicePathFromText.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/HiiFormMapMethodGuid.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CustomizedDisplayLib.h>
+
+#include "Colors.h"
+
+
+
+#define FORMSET_CLASS_PLATFORM_SETUP 0x0001
+#define FORMSET_CLASS_FRONT_PAGE 0x0002
+
+
+#define FRONT_PAGE_HEADER_HEIGHT 6
+#define NONE_FRONT_PAGE_HEADER_HEIGHT 3
+#define FOOTER_HEIGHT 4
+#define STATUS_BAR_HEIGHT 1
+
+//
+// Screen definitions
+//
+#define BANNER_HEIGHT 6
+#define BANNER_COLUMNS 3
+#define BANNER_LEFT_COLUMN_INDENT 1
+
+//
+// Character definitions
+//
+#define UPPER_LOWER_CASE_OFFSET 0x20
+
+//
+// This is the Input Error Message
+//
+#define INPUT_ERROR 1
+
+//
+// This is the NV RAM update required Message
+//
+#define NV_UPDATE_REQUIRED 2
+
+typedef struct {
+ EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS];
+} BANNER_DATA;
+
+extern UINT16 gClassOfVfr; // Formset class information
+extern BANNER_DATA *gBannerData;
+extern EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+extern UINTN gFooterHeight;
+
+//
+// Browser Global Strings
+//
+extern CHAR16 *gEnterString;
+extern CHAR16 *gEnterCommitString;
+extern CHAR16 *gEnterEscapeString;
+extern CHAR16 *gEscapeString;
+extern CHAR16 *gMoveHighlight;
+extern CHAR16 *gDecNumericInput;
+extern CHAR16 *gHexNumericInput;
+extern CHAR16 *gToggleCheckBox;
+extern CHAR16 *gLibEmptyString;
+extern CHAR16 *gAreYouSure;
+extern CHAR16 *gYesResponse;
+extern CHAR16 *gNoResponse;
+extern CHAR16 *gPlusString;
+extern CHAR16 *gMinusString;
+extern CHAR16 *gAdjustNumber;
+extern CHAR16 *gSaveChanges;
+extern CHAR16 *gNvUpdateMessage;
+extern CHAR16 *gInputErrorMessage;
+/**
+
+ Print banner info for front page.
+
+ @param[in] FormData Form Data to be shown in Page
+
+**/
+VOID
+PrintBannerInfo (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Print framework and form title for a page.
+
+ @param[in] FormData Form Data to be shown in Page
+**/
+VOID
+PrintFramework (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Validate the input screen diemenstion info.
+
+ @param FormData The input form data info.
+
+ @return EFI_SUCCESS The input screen info is acceptable.
+ @return EFI_INVALID_PARAMETER The input screen info is not acceptable.
+
+**/
+EFI_STATUS
+ScreenDiemensionInfoValidate (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+LibGetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+LibGetStringWidth (
+ IN CHAR16 *String
+ );
+
+/**
+ Show all registered HotKey help strings on bottom Rows.
+
+ @param FormData The curent input form data info.
+ @param SetState Set HotKey or Clear HotKey
+
+**/
+VOID
+PrintHotKeyHelpString (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN BOOLEAN SetState
+ );
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+LibGetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ );
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeLibStrings (
+ VOID
+ );
+
+/**
+ Free the HII String.
+
+**/
+VOID
+FreeLibStrings (
+ VOID
+ );
+
+/**
+ Wait for a key to be pressed by user.
+
+ @param Key The key which is pressed by user.
+
+ @retval EFI_SUCCESS The function always completed successfully.
+
+**/
+EFI_STATUS
+WaitForKeyStroke (
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+LibSetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ );
+
+/**
+ Prints a formatted unicode string to the default console, at
+ the supplied cursor position.
+
+ @param Width Width of String to be printed.
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at.
+ @param Fmt Format string.
+ @param ... Variable argument list for format string.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintAt (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *Fmt,
+ ...
+ );
+
+/**
+ Process some op codes which is out side of current form.
+
+ @param FormData Pointer to the form data.
+
+**/
+VOID
+ProcessExternedOpcode (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni
new file mode 100644
index 000000000..f73da2150
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni
@@ -0,0 +1,18 @@
+// /** @file
+// CustomizedDisplayLib Module Localized Abstract and Description Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Customize display library used by display engine."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Customize display library used by display engine."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c
new file mode 100644
index 000000000..b4f90e172
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c
@@ -0,0 +1,66 @@
+/** @file
+ Debug Agent library implementition with empty functions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugAgentLib.h>
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment to support source level debugging.
+ If certain Debug Agent Library instance has to save some private data in the stack,
+ this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
+ function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
+ responsible to invoke the passing-in function at the end of InitializeDebugAgent().
+
+ If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
+ passing in the Context to be its parameter.
+
+ If Function() is NULL, Debug Agent Library instance will return after setup debug
+ environment.
+
+ @param[in] InitFlag Init flag is used to decide the initialize process.
+ @param[in] Context Context needed according to InitFlag; it was optional.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ if (Function != NULL) {
+ Function (Context);
+ }
+}
+
+/**
+ Enable/Disable the interrupt of debug timer and return the interrupt state
+ prior to the operation.
+
+ If EnableStatus is TRUE, enable the interrupt of debug timer.
+ If EnableStatus is FALSE, disable the interrupt of debug timer.
+
+ @param[in] EnableStatus Enable/Disable.
+
+ @return FALSE always.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt (
+ IN BOOLEAN EnableStatus
+ )
+{
+ return FALSE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
new file mode 100644
index 000000000..b623e35a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
@@ -0,0 +1,31 @@
+## @file
+# Null instance of Debug Agent Library with empty functions.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugAgentLibNull
+ MODULE_UNI_FILE = DebugAgentLibNull.uni
+ FILE_GUID = 4904B42F-9FC0-4c2e-BB3F-A2AB35123530
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugAgentLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ DebugAgentLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni
new file mode 100644
index 000000000..eeb258b0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null instance of Debug Agent Library with empty functions.
+//
+// Null instance of Debug Agent Library with empty functions.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of Debug Agent Library with empty functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of Debug Agent Library with empty functions."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.c b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.c
new file mode 100644
index 000000000..3bc13d340
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.c
@@ -0,0 +1,941 @@
+/** @file
+The device manager reference implementation
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DeviceManager.h"
+
+DEVICE_MANAGER_CALLBACK_DATA gDeviceManagerPrivate = {
+ DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ DeviceManagerExtractConfig,
+ DeviceManagerRouteConfig,
+ DeviceManagerCallback
+ }
+};
+
+#define MAX_MAC_ADDRESS_NODE_LIST_LEN 10
+
+EFI_GUID mDeviceManagerGuid = DEVICE_MANAGER_FORMSET_GUID;
+
+//
+// Which Mac Address string is select
+// it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
+//
+EFI_STRING mSelectedMacAddrString;
+
+//
+// The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
+//
+MAC_ADDRESS_NODE_LIST mMacDeviceList;
+
+HII_VENDOR_DEVICE_PATH mDeviceManagerHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ //
+ // {102579A0-3686-466e-ACD8-80C087044F4A}
+ //
+ { 0x102579a0, 0x3686, 0x466e, { 0xac, 0xd8, 0x80, 0xc0, 0x87, 0x4, 0x4f, 0x4a } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Extract device path for given HII handle and class guid.
+
+ @param Handle The HII handle.
+
+ @retval NULL Fail to get the device path string.
+ @return PathString Get the device path string.
+
+**/
+CHAR16 *
+DmExtractDevicePathFromHiiHandle (
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ ASSERT (Handle != NULL);
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ //
+ // Get device path string.
+ //
+ return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, 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++) {
+ UnicodeValueToStringS (
+ String,
+ BufferLen - ((UINTN)String - (UINTN)*PBuffer),
+ PREFIX_ZERO | RADIX_HEX,
+ *(HwAddress++),
+ 2
+ );
+ String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
+ 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'\\';
+ UnicodeValueToStringS (
+ String,
+ BufferLen - ((UINTN)String - (UINTN)*PBuffer),
+ PREFIX_ZERO | RADIX_HEX,
+ VlanId,
+ 4
+ );
+ String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
+ }
+
+ //
+ // 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 = ReallocatePool (
+ sizeof (MENU_INFO_ITEM) * mMacDeviceList.CurListLen,
+ sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen,
+ 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);
+
+ 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 NextShowFormId FormId Which need to be show.
+ @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,
+ IN EFI_FORM_ID NextShowFormId,
+ 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 == NextShowFormId) {
+ *NeedAddItem = TRUE;
+ break;
+ }
+
+ if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
+ break;
+ }
+
+ if (NETWORK_DEVICE_FORM_ID == NextShowFormId) {
+ if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
+ *NeedAddItem = TRUE;
+ }
+ break;
+ }
+
+ if (NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) {
+ //
+ // 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 NextShowFormId The FormId of the form which will be show next time.
+ @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,
+ IN EFI_FORM_ID NextShowFormId,
+ 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, NextShowFormId,&IsNeedAdd)) {
+ if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) && 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, NextShowFormId,&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 == NextShowFormId)) {
+ 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;
+}
+
+/**
+ Dynamic create Hii information for Device Manager.
+
+ @param NextShowFormId The FormId which need to be show.
+
+**/
+VOID
+CreateDeviceManagerForm(
+ IN EFI_FORM_ID NextShowFormId
+)
+{
+ UINTN Index;
+ EFI_STRING String;
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_GUID FormSetGuid;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ BOOLEAN AddNetworkMenu;
+ UINTN AddItemCount;
+ UINTN NewStringLen;
+ EFI_STRING NewStringTitle;
+ CHAR16 *DevicePathStr;
+ EFI_STRING_ID DevicePathId;
+ EFI_IFR_FORM_SET *Buffer;
+ UINTN BufferSize;
+ UINT8 ClassGuidNum;
+ EFI_GUID *ClassGuid;
+ UINTN TempSize;
+ UINT8 *Ptr;
+ EFI_STATUS Status;
+
+ TempSize =0;
+ BufferSize = 0;
+ Buffer = NULL;
+
+ HiiHandle = gDeviceManagerPrivate.HiiHandle;
+ AddNetworkMenu = FALSE;
+ AddItemCount = 0;
+ //
+ // If need show the Network device list form, clear the old save list first.
+ //
+ if ((NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
+ mMacDeviceList.CurListLen = 0;
+ }
+
+ //
+ // Update the network device form titile.
+ //
+ if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE_HEAD), NULL);
+ if (String == NULL) {
+ return;
+ }
+ 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 + NextShowFormId);
+
+ //
+ // 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);
+
+ //
+ // Search for formset of each class type
+ //
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ Status = HiiGetFormSetFromHiiHandle(HiiHandles[Index], &Buffer,&BufferSize);
+ if (EFI_ERROR (Status)){
+ continue;
+ }
+ Ptr = (UINT8 *)Buffer;
+ while(TempSize < BufferSize) {
+ TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+ if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
+ Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+ continue;
+ }
+
+ ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0) {
+ if (CompareGuid (&gEfiHiiPlatformSetupFormsetGuid, ClassGuid)== 0) {
+ ClassGuid ++;
+ continue;
+ }
+
+ String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ }
+ Token = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->Help, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
+ ASSERT (String != NULL);
+ }
+ TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ CopyMem (&FormSetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
+
+ //
+ // Network device process
+ //
+ if (IsNeedAddNetworkMenu (HiiHandles[Index], NextShowFormId,&AddItemCount)) {
+ if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
+ //
+ // Only show one menu item "Network Config" in the device manger form.
+ //
+ if (!AddNetworkMenu) {
+ AddNetworkMenu = TRUE;
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ NETWORK_DEVICE_LIST_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 (NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
+ //
+ // In network device list form, same mac address device only show one menu.
+ //
+ while (AddItemCount > 0) {
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ NETWORK_DEVICE_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 (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
+ //
+ // In network device form, only the selected mac address device need to be show.
+ //
+ DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
+ DevicePathId = 0;
+ if (DevicePathStr != NULL){
+ DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
+ FreePool(DevicePathStr);
+ }
+ HiiCreateGotoExOpCode (
+ StartOpCodeHandle,
+ 0,
+ Token,
+ TokenHelp,
+ 0,
+ (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
+ 0,
+ &FormSetGuid,
+ DevicePathId
+ );
+ }
+ } else {
+ //
+ // Not network device process, only need to show at device manger form.
+ //
+ if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
+ DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
+ DevicePathId = 0;
+ if (DevicePathStr != NULL){
+ DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
+ FreePool(DevicePathStr);
+ }
+ HiiCreateGotoExOpCode (
+ StartOpCodeHandle,
+ 0,
+ Token,
+ TokenHelp,
+ 0,
+ (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
+ 0,
+ &FormSetGuid,
+ DevicePathId
+ );
+ }
+ }
+ break;
+ }
+
+ Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
+ }
+ FreePool(Buffer);
+ Buffer = NULL;
+ TempSize = 0;
+ BufferSize = 0;
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &mDeviceManagerGuid,
+ NextShowFormId,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ FreePool (HiiHandles);
+}
+
+/**
+ 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
+DeviceManagerExtractConfig (
+ 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
+DeviceManagerRouteConfig (
+ 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;
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function is invoked if user selected a interactive opcode from Device Manager's
+ Formset. 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) {
+ //
+ // 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 ((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);
+ }
+ }
+ CreateDeviceManagerForm(NETWORK_DEVICE_FORM_ID);
+ } else if(QuestionId == QUESTION_NETWORK_DEVICE_ID){
+ CreateDeviceManagerForm(NETWORK_DEVICE_LIST_FORM_ID);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+DeviceManagerUiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+
+ gDeviceManagerPrivate.DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gDeviceManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDeviceManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gDeviceManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data.
+ //
+ gDeviceManagerPrivate.HiiHandle = HiiAddPackages (
+ &mDeviceManagerGuid,
+ gDeviceManagerPrivate.DriverHandle,
+ DeviceManagerVfrBin,
+ DeviceManagerUiLibStrings,
+ NULL
+ );
+ ASSERT (gDeviceManagerPrivate.HiiHandle != NULL);
+
+ //
+ // The device manager form contains a page listing all the network
+ // controllers in the system. This list can only be populated if all
+ // handles have been connected, so do it here.
+ //
+ EfiBootManagerConnectAll ();
+
+ //
+ // Update boot manager page
+ //
+ CreateDeviceManagerForm (DEVICE_MANAGER_FORM_ID);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+DeviceManagerUiLibDestructor(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gDeviceManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDeviceManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gDeviceManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HiiRemovePackages (gDeviceManagerPrivate.HiiHandle);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.h b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.h
new file mode 100644
index 000000000..c53c2a1a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManager.h
@@ -0,0 +1,189 @@
+/** @file
+The device manager reference implement
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEVICE_MANAGER_H_
+#define _DEVICE_MANAGER_H_
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/UefiHiiServicesLib.h>
+
+//
+// These are defined as the same with vfr file
+//
+#define DEVICE_MANAGER_FORMSET_GUID \
+ { \
+ 0x3ebfa8e6, 0x511d, 0x4b5b, {0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27} \
+ }
+
+#define LABEL_END 0xffff
+#define LABEL_FORM_ID_OFFSET 0x0100
+
+#define DEVICE_MANAGER_FORM_ID 0x1000
+#define NETWORK_DEVICE_LIST_FORM_ID 0x1001
+#define NETWORK_DEVICE_FORM_ID 0x1002
+#define DEVICE_KEY_OFFSET 0x4000
+#define NETWORK_DEVICE_LIST_KEY_OFFSET 0x2000
+
+#define MAX_KEY_SECTION_LEN 0x1000
+
+#define QUESTION_NETWORK_DEVICE_ID 0x3FFF
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 DeviceManagerVfrBin[];
+
+#define DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('D', 'M', 'C', 'B')
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+
+ ///
+ /// Device Manager HII relative handles
+ ///
+ EFI_HII_HANDLE HiiHandle;
+
+ EFI_HANDLE DriverHandle;
+
+ ///
+ /// Device Manager Produced protocols
+ ///
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+
+ ///
+ /// Configuration data
+ ///
+ UINT8 VideoBios;
+} DEVICE_MANAGER_CALLBACK_DATA;
+
+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_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 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
+DeviceManagerExtractConfig (
+ 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
+DeviceManagerRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function is invoked if user selected a interactive opcode from Device Manager's
+ Formset. 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerStrings.uni b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerStrings.uni
new file mode 100644
index 000000000..041cf2534
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerStrings.uni
@@ -0,0 +1,58 @@
+///** @file
+//
+// String definitions for the Device Manager.
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_EDKII_MENU_TITLE #language en-US "Device Manager"
+ #language fr-FR "Device Manager"
+#string STR_EDKII_MENU_HELP #language en-US "This selection will take you to the Device Manager"
+ #language fr-FR "This selection will take you to the Device Manager"
+#string STR_DEVICES_LIST #language en-US "Devices List"
+ #language fr-FR "Devices List"
+#string STR_DISK_DEVICE #language en-US "Disk Devices"
+ #language fr-FR "Disk Devices"
+#string STR_VIDEO_DEVICE #language en-US "Video Devices"
+ #language fr-FR "Video Devices"
+#string STR_NETWORK_DEVICE #language en-US "Network Devices"
+ #language fr-FR "Network Devices"
+#string STR_INPUT_DEVICE #language en-US "Input Devices"
+ #language fr-FR "Input Devices"
+#string STR_ON_BOARD_DEVICE #language en-US "Motherboard Devices"
+ #language fr-FR "Motherboard Devices"
+#string STR_OTHER_DEVICE #language en-US "Other Devices"
+ #language fr-FR "Other Devices"
+#string STR_MISSING_STRING #language en-US "Missing String"
+ #language fr-FR "Missing String"
+#string STR_EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_EXIT_STRING #language en-US "Press ESC to exit."
+ #language fr-FR "Press ESC to exit."
+#string STR_FORM_NETWORK_DEVICE_TITLE_HEAD #language en-US "Network Device"
+#string STR_FORM_NETWORK_DEVICE_TITLE #language en-US "Network Device"
+ #language fr-FR "Network Device"
+#string STR_FORM_NETWORK_DEVICE_HELP #language en-US "Network Device Help..."
+ #language fr-FR "Network Device Help..."
+#string STR_NETWORK_DEVICE_STRING #language en-US "Network Device"
+ #language fr-FR "Network Device"
+#string STR_FORM_NETWORK_DEVICE_LIST_HELP #language en-US "Select the network device according the MAC address"
+ #language fr-FR "Select the network device according the MAC address"
+#string STR_FORM_NETWORK_DEVICE_LIST_TITLE #language en-US "Network Device List"
+ #language fr-FR "Network Device List"
+#string STR_NETWORK_DEVICE_LIST_STRING #language en-US "Network Device List"
+ #language fr-FR "Network Device List"
+#string STR_NETWORK_DEVICE_HELP #language en-US "Network Device"
+ #language fr-FR "Network Device"
+//
+// Ensure that this is the last string. We are using it programmatically
+// to do string token re-usage settings for the Device Manager since we are
+// constantly recreating this page based on HII population.
+////
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
new file mode 100644
index 000000000..d7f833d8b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
@@ -0,0 +1,52 @@
+## @file
+# Device Manager Library used by UiApp
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DeviceManagerUiLib
+ MODULE_UNI_FILE = DeviceManagerUiLib.uni
+ FILE_GUID = 75EBDC2E-5323-4F31-A41D-FD1A7A9FC65E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = DeviceManagerUiLibConstructor
+ DESTRUCTOR = DeviceManagerUiLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DeviceManager.h
+ DeviceManagerVfr.Vfr
+ DeviceManagerStrings.uni
+ DeviceManager.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiBootManagerLib
+ UefiHiiServicesLib
+
+[Guids]
+ gEfiHiiPlatformSetupFormsetGuid ## CONSUMES ## GUID (Indicate the formset class guid to be displayed)
+ gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode)
+ gEfiIfrFrontPageGuid ## CONSUMES ## GUID (Indicate the formset in this library need to dispaly in which page)
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.uni b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.uni
new file mode 100644
index 000000000..4dd0299e6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Device Manager Library used by UiApp
+//
+// Device Manager Library used by UiApp
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Device Manager Library used by UiApp"
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Device Manager Library used by UiApp"
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerVfr.Vfr b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerVfr.Vfr
new file mode 100644
index 000000000..d81c580fe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerVfr.Vfr
@@ -0,0 +1,60 @@
+///** @file
+//
+// Device Manager formset.
+//
+// Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#define FORMSET_GUID { 0x3ebfa8e6, 0x511d, 0x4b5b, 0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27 }
+
+#define LABEL_DEVICES_LIST 0x1100
+#define LABEL_NETWORK_DEVICE_LIST_ID 0x1101
+#define LABEL_NETWORK_DEVICE_ID 0x1102
+#define LABEL_END 0xffff
+
+#define DEVICE_MANAGER_FORM_ID 0x1000
+#define NETWORK_DEVICE_LIST_FORM_ID 0x1001
+#define NETWORK_DEVICE_FORM_ID 0x1002
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_EDKII_MENU_TITLE),
+ help = STRING_TOKEN(STR_EDKII_MENU_HELP),
+ classguid = gEfiIfrFrontPageGuid,
+
+ form formid = DEVICE_MANAGER_FORM_ID,
+ title = STRING_TOKEN(STR_EDKII_MENU_TITLE);
+ subtitle text = STRING_TOKEN(STR_DEVICES_LIST);
+
+ label LABEL_DEVICES_LIST;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+ 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; \ No newline at end of file
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.c b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.c
new file mode 100644
index 000000000..5f3ae6ab7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.c
@@ -0,0 +1,458 @@
+/** @file
+ Provides services to display completion progress of a firmware update on a
+ graphical console that supports the Graphics Output Protocol.
+
+ Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/BootLogo2.h>
+
+//
+// Values in percent of of logo height.
+//
+#define LOGO_BOTTOM_PADDING 20
+#define PROGRESS_BLOCK_HEIGHT 10
+
+//
+// Graphics Output Protocol instance to display progress bar
+//
+EFI_GRAPHICS_OUTPUT_PROTOCOL *mGop = NULL;
+
+//
+// Set to 100 percent so it is reset on first call.
+//
+UINTN mPreviousProgress = 100;
+
+//
+// Display coordinates for the progress bar.
+//
+UINTN mStartX = 0;
+UINTN mStartY = 0;
+
+//
+// Width and height of the progress bar.
+//
+UINTN mBlockWidth = 0;
+UINTN mBlockHeight = 0;
+
+//
+// GOP bitmap of the progress bar. Initialized on every new progress of 100%
+//
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mBlockBitmap;
+
+//
+// GOP bitmap of the progress bar backround. Initialized once.
+//
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mProgressBarBackground;
+
+//
+// Default mask used to detect the left, right , top, and bottom of logo. Only
+// green and blue pixels are used for logo detection.
+//
+const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mLogoDetectionColorMask = {
+ {
+ 0xFF, // Blue
+ 0xFF, // Green
+ 0x00, // Red
+ 0x00 // Reserved
+ }
+};
+
+//
+// Background color of progress bar. Grey.
+//
+const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarBackgroundColor = {
+ {
+ 0x80, // Blue
+ 0x80, // Green
+ 0x80, // Red
+ 0x00 // Reserved
+ }
+};
+
+//
+// Default color of progress completion. White.
+//
+const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarDefaultColor = {
+ {
+ 0xFF, // Blue
+ 0xFF, // Green
+ 0xFF, // Red
+ 0x00 // Reserved
+ }
+};
+
+//
+// Set to TRUE if a valid Graphics Output Protocol is found and the progress
+// bar fits under the boot logo using the current graphics mode.
+//
+BOOLEAN mGraphicsGood = FALSE;
+
+/**
+ Internal function used to find the bounds of the white logo (on black or
+ red background).
+
+ These bounds are then computed to find the block size, 0%, 100%, etc.
+
+**/
+VOID
+FindDim (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ INTN LogoX;
+ INTN LogoStartX;
+ INTN LogoEndX;
+ INTN LogoY;
+ INTN LogoStartY;
+ INTN LogoEndY;
+ UINTN OffsetX; // Logo screen coordinate
+ UINTN OffsetY; // Logo screen coordinate
+ UINTN Width; // Width of logo in pixels
+ UINTN Height; // Height of logo in pixels
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Logo;
+ EDKII_BOOT_LOGO2_PROTOCOL *BootLogo;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Pixel;
+
+ Logo = NULL;
+ BootLogo = NULL;
+
+ //
+ // Return if a Graphics Output Protocol ha snot been found.
+ //
+ if (mGop == NULL) {
+ DEBUG ((DEBUG_ERROR, "No GOP found. No progress bar support. \n"));
+ return;
+ }
+
+ //
+ // Get boot logo protocol so we know where on the screen to grab
+ //
+ Status = gBS->LocateProtocol (
+ &gEdkiiBootLogo2ProtocolGuid,
+ NULL,
+ (VOID **)&BootLogo
+ );
+ if ((BootLogo == NULL) || (EFI_ERROR (Status))) {
+ DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid. No Progress bar support. \n", Status));
+ return;
+ }
+
+ //
+ // Get logo location and size
+ //
+ Status = BootLogo->GetBootLogo (
+ BootLogo,
+ &Logo,
+ &OffsetX,
+ &OffsetY,
+ &Width,
+ &Height
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to Get Boot Logo Status = %r. No Progress bar support. \n", Status));
+ return;
+ }
+
+ //
+ // Within logo buffer find where the actual logo starts/ends
+ //
+ LogoEndX = 0;
+ LogoEndY = 0;
+
+ //
+ // Find left side of logo in logo coordinates
+ //
+ for (LogoX = 0, LogoStartX = Width; LogoX < LogoStartX; LogoX++) {
+ Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + LogoX);
+ for (LogoY = 0; LogoY < (INTN)Height; LogoY++) {
+ if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
+ LogoStartX = LogoX;
+ //
+ // For loop searches from right side back to this column.
+ //
+ LogoEndX = LogoX;
+ DEBUG ((DEBUG_INFO, "StartX found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
+ break;
+ }
+ Pixel = Pixel + Width;
+ }
+ }
+
+ //
+ // Find right side of logo
+ //
+ for (LogoX = Width - 1; LogoX >= LogoEndX; LogoX--) {
+ Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + LogoX);
+ for (LogoY = 0; LogoY < (INTN)Height; LogoY++) {
+ if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
+ LogoEndX = LogoX;
+ DEBUG ((DEBUG_INFO, "EndX found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
+ break;
+ }
+ Pixel = Pixel + Width;
+ }
+ }
+
+ //
+ // Compute mBlockWidth
+ //
+ mBlockWidth = ((LogoEndX - LogoStartX) + 99) / 100;
+
+ //
+ // Adjust mStartX based on block width so it is centered under logo
+ //
+ mStartX = LogoStartX + OffsetX - (((mBlockWidth * 100) - (LogoEndX - LogoStartX)) / 2);
+ DEBUG ((DEBUG_INFO, "mBlockWidth set to 0x%X\n", mBlockWidth));
+ DEBUG ((DEBUG_INFO, "mStartX set to 0x%X\n", mStartX));
+
+ //
+ // Find the top of the logo
+ //
+ for (LogoY = 0, LogoStartY = Height; LogoY < LogoStartY; LogoY++) {
+ Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + (Width * LogoY));
+ for (LogoX = 0; LogoX < (INTN)Width; LogoX++) {
+ //not black or red
+ if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
+ LogoStartY = LogoY;
+ LogoEndY = LogoY; //for next loop will search from bottom side back to this row.
+ DEBUG ((DEBUG_INFO, "StartY found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
+ break;
+ }
+ Pixel++;
+ }
+ }
+
+ //
+ // Find the bottom of the logo
+ //
+ for (LogoY = Height - 1; LogoY >= LogoEndY; LogoY--) {
+ Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + (Width * LogoY));
+ for (LogoX = 0; LogoX < (INTN)Width; LogoX++) {
+ if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
+ LogoEndY = LogoY;
+ DEBUG ((DEBUG_INFO, "EndY found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
+ break;
+ }
+ Pixel++;
+ }
+ }
+
+ //
+ // Compute bottom padding (distance between logo bottom and progress bar)
+ //
+ mStartY = (((LogoEndY - LogoStartY) * LOGO_BOTTOM_PADDING) / 100) + LogoEndY + OffsetY;
+
+ //
+ // Compute progress bar height
+ //
+ mBlockHeight = (((LogoEndY - LogoStartY) * PROGRESS_BLOCK_HEIGHT) / 100);
+
+ DEBUG ((DEBUG_INFO, "mBlockHeight set to 0x%X\n", mBlockHeight));
+
+ //
+ // Create progress bar background (one time init).
+ //
+ mProgressBarBackground = AllocatePool (mBlockWidth * 100 * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (mProgressBarBackground == NULL) {
+ DEBUG ((DEBUG_ERROR, "Failed to allocate progress bar background\n"));
+ return;
+ }
+
+ //
+ // Fill the progress bar with the background color
+ //
+ SetMem32 (
+ mProgressBarBackground,
+ (mBlockWidth * 100 * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)),
+ mProgressBarBackgroundColor.Raw
+ );
+
+ //
+ // Allocate mBlockBitmap
+ //
+ mBlockBitmap = AllocatePool (mBlockWidth * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (mBlockBitmap == NULL) {
+ FreePool (mProgressBarBackground);
+ DEBUG ((DEBUG_ERROR, "Failed to allocate block\n"));
+ return;
+ }
+
+ //
+ // Check screen width and height and make sure it fits.
+ //
+ if ((mBlockHeight > Height) || (mBlockWidth > Width) || (mBlockHeight < 1) || (mBlockWidth < 1)) {
+ DEBUG ((DEBUG_ERROR, "DisplayUpdateProgressLib - Progress - Failed to get valid width and height.\n"));
+ DEBUG ((DEBUG_ERROR, "DisplayUpdateProgressLib - Progress - mBlockHeight: 0x%X mBlockWidth: 0x%X.\n", mBlockHeight, mBlockWidth));
+ FreePool (mProgressBarBackground);
+ FreePool (mBlockBitmap);
+ return;
+ }
+
+ mGraphicsGood = TRUE;
+}
+
+/**
+ Function indicates the current completion progress of a firmware update.
+ Platform may override with its own specific function.
+
+ @param[in] Completion A value between 0 and 100 indicating the current
+ completion progress of a firmware update. This
+ value must the the same or higher than previous
+ calls to this service. The first call of 0 or a
+ value of 0 after reaching a value of 100 resets
+ the progress indicator to 0.
+ @param[in] Color Color of the progress indicator. Only used when
+ Completion is 0 to set the color of the progress
+ indicator. If Color is NULL, then the default color
+ is used.
+
+ @retval EFI_SUCCESS Progress displayed successfully.
+ @retval EFI_INVALID_PARAMETER Completion is not in range 0..100.
+ @retval EFI_INVALID_PARAMETER Completion is less than Completion value from
+ a previous call to this service.
+ @retval EFI_NOT_READY The device used to indicate progress is not
+ available.
+**/
+EFI_STATUS
+EFIAPI
+DisplayUpdateProgress (
+ IN UINTN Completion,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN PreX;
+ UINTN Index;
+
+ //
+ // Check range
+ //
+ if (Completion > 100) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if this Completion percentage has already been displayed
+ //
+ if (Completion == mPreviousProgress) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find Graphics Output Protocol if not already set. 1 time.
+ //
+ if (mGop == NULL) {
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID**)&mGop
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&mGop);
+ if (EFI_ERROR (Status)) {
+ mGop = NULL;
+ DEBUG ((DEBUG_ERROR, "Show Progress Function could not locate GOP. Status = %r\n", Status));
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Run once
+ //
+ FindDim ();
+ }
+
+ //
+ // Make sure a valid start, end, and size info are available (find the Logo)
+ //
+ if (!mGraphicsGood) {
+ DEBUG ((DEBUG_INFO, "Graphics Not Good. Not doing any onscreen visual display\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Do special init on first call of each progress session
+ //
+ if (mPreviousProgress == 100) {
+ //
+ // Draw progress bar background
+ //
+ mGop->Blt (
+ mGop,
+ mProgressBarBackground,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ mStartX,
+ mStartY,
+ (mBlockWidth * 100),
+ mBlockHeight,
+ 0
+ );
+
+ DEBUG ((DEBUG_VERBOSE, "Color is 0x%X\n",
+ (Color == NULL) ? mProgressBarDefaultColor.Raw : Color->Raw
+ ));
+
+ //
+ // Update block bitmap with correct color
+ //
+ SetMem32 (
+ mBlockBitmap,
+ (mBlockWidth * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)),
+ (Color == NULL) ? mProgressBarDefaultColor.Raw : Color->Raw
+ );
+
+ //
+ // Clear previous
+ //
+ mPreviousProgress = 0;
+ }
+
+ //
+ // Can not update progress bar if Completion is less than previous
+ //
+ if (Completion < mPreviousProgress) {
+ DEBUG ((DEBUG_WARN, "WARNING: Completion (%d) should not be lesss than Previous (%d)!!!\n", Completion, mPreviousProgress));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PreX = ((mPreviousProgress * mBlockWidth) + mStartX);
+ for (Index = 0; Index < (Completion - mPreviousProgress); Index++) {
+ //
+ // Show progress by coloring new area
+ //
+ mGop->Blt (
+ mGop,
+ mBlockBitmap,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ PreX,
+ mStartY,
+ mBlockWidth,
+ mBlockHeight,
+ 0
+ );
+ PreX += mBlockWidth;
+ }
+
+ mPreviousProgress = Completion;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf
new file mode 100644
index 000000000..175b7e434
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf
@@ -0,0 +1,43 @@
+## @file
+# Provides services to display completion progress of a firmware update on a
+# graphical console that supports the Graphics Output Protocol.
+#
+# Copyright (c) 2016, Microsoft Corporation, All rights reserved.<BR>
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DisplayUpdateProgressLibGraphics
+ MODULE_UNI_FILE = DisplayUpdateProgressLibGraphics.uni
+ FILE_GUID = 319E9E37-B2D6-4699-90F3-B8B72B6D4CBD
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DisplayUpdateProgressLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DisplayUpdateProgressLibGraphics.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseLib
+ UefiLib
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid # CONSUMES
+ gEdkiiBootLogo2ProtocolGuid # CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.uni b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.uni
new file mode 100644
index 000000000..7e8e48f5f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.uni
@@ -0,0 +1,13 @@
+// /** @file
+// Provides services to display completion progress of a firmware update on a
+// graphical console that supports the Graphics Output Protocol.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides services to display completion progress of a firmware update on a graphical console that supports the Graphics Output Protocol."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides services to display completion progress of a firmware update on a graphical console that supports the Graphics Output Protocol."
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.c b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.c
new file mode 100644
index 000000000..960a4165f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.c
@@ -0,0 +1,157 @@
+/** @file
+ Provides services to display completion progress of a firmware update on a
+ text console.
+
+ Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+//
+// Control Style. Set to 100 so it is reset on first call.
+//
+UINTN mPreviousProgress = 100;
+
+//
+// Text foreground color of progress bar
+//
+UINTN mProgressBarForegroundColor;
+
+/**
+ Function indicates the current completion progress of a firmware update.
+ Platform may override with its own specific function.
+
+ @param[in] Completion A value between 0 and 100 indicating the current
+ completion progress of a firmware update. This
+ value must the the same or higher than previous
+ calls to this service. The first call of 0 or a
+ value of 0 after reaching a value of 100 resets
+ the progress indicator to 0.
+ @param[in] Color Color of the progress indicator. Only used when
+ Completion is 0 to set the color of the progress
+ indicator. If Color is NULL, then the default color
+ is used.
+
+ @retval EFI_SUCCESS Progress displayed successfully.
+ @retval EFI_INVALID_PARAMETER Completion is not in range 0..100.
+ @retval EFI_INVALID_PARAMETER Completion is less than Completion value from
+ a previous call to this service.
+ @retval EFI_NOT_READY The device used to indicate progress is not
+ available.
+**/
+EFI_STATUS
+EFIAPI
+DisplayUpdateProgress (
+ IN UINTN Completion,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color OPTIONAL
+ )
+{
+ UINTN Index;
+ UINTN CurrentAttribute;
+
+ //
+ // Check range
+ //
+ if (Completion > 100) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if this Completion percentage has already been displayed
+ //
+ if (Completion == mPreviousProgress) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do special init on first call of each progress session
+ //
+ if (mPreviousProgress == 100) {
+ Print (L"\n");
+
+ //
+ // Convert pixel color to text foreground color
+ //
+ if (Color == NULL) {
+ mProgressBarForegroundColor = EFI_WHITE;
+ } else {
+ mProgressBarForegroundColor = EFI_BLACK;
+ if (Color->Pixel.Blue >= 0x40) {
+ mProgressBarForegroundColor |= EFI_BLUE;
+ }
+ if (Color->Pixel.Green >= 0x40) {
+ mProgressBarForegroundColor |= EFI_GREEN;
+ }
+ if (Color->Pixel.Red >= 0x40) {
+ mProgressBarForegroundColor |= EFI_RED;
+ }
+ if (Color->Pixel.Blue >= 0xC0 || Color->Pixel.Green >= 0xC0 || Color->Pixel.Red >= 0xC0) {
+ mProgressBarForegroundColor |= EFI_BRIGHT;
+ }
+ if (mProgressBarForegroundColor == EFI_BLACK) {
+ mProgressBarForegroundColor = EFI_WHITE;
+ }
+ }
+
+ //
+ // Clear previous
+ //
+ mPreviousProgress = 0;
+ }
+
+ //
+ // Can not update progress bar if Completion is less than previous
+ //
+ if (Completion < mPreviousProgress) {
+ DEBUG ((DEBUG_WARN, "WARNING: Completion (%d) should not be lesss than Previous (%d)!!!\n", Completion, mPreviousProgress));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Save current text color
+ //
+ CurrentAttribute = (UINTN)gST->ConOut->Mode->Attribute;
+
+ //
+ // Print progress percentage
+ //
+ Print (L"\rUpdate Progress - %3d%% ", Completion);
+
+ //
+ // Set progress bar color
+ //
+ gST->ConOut->SetAttribute (
+ gST->ConOut,
+ EFI_TEXT_ATTR (mProgressBarForegroundColor, EFI_BLACK)
+ );
+
+ //
+ // Print completed portion of progress bar
+ //
+ for (Index = 0; Index < Completion / 2; Index++) {
+ Print (L"%c", BLOCKELEMENT_FULL_BLOCK);
+ }
+
+ //
+ // Restore text color
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
+
+ //
+ // Print remaining portion of progress bar
+ //
+ for (; Index < 50; Index++) {
+ Print (L"%c", BLOCKELEMENT_LIGHT_SHADE);
+ }
+
+ mPreviousProgress = Completion;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf
new file mode 100644
index 000000000..4fc25c8cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf
@@ -0,0 +1,36 @@
+## @file
+# Provides services to display completion progress of a firmware update on a
+# text console.
+#
+# Copyright (c) 2016, Microsoft Corporation, All rights reserved.<BR>
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DisplayUpdateProgressLibText
+ MODULE_UNI_FILE = DisplayUpdateProgressLibText.uni
+ FILE_GUID = CDEF83AE-1900-4B41-BF47-AAE9BD729CA5
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DisplayUpdateProgressLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DisplayUpdateProgressLibText.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiBootServicesTableLib
+ UefiLib
diff --git a/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.uni b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.uni
new file mode 100644
index 000000000..f2b0c3e0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.uni
@@ -0,0 +1,13 @@
+// /** @file
+// Provides services to display completion progress of a firmware update on a
+// text console.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides services to display completion progress of a firmware update on a text console."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides services to display completion progress of a firmware update on a text console."
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
new file mode 100644
index 000000000..4c32c6cdc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
@@ -0,0 +1,1975 @@
+/** @file
+ The implementation supports Capusle on Disk.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleOnDisk.h"
+
+/**
+ Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a capsule name capsule.
+ @retval FALSE It is not a capsule name capsule.
+**/
+BOOLEAN
+IsCapsuleNameCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ Check the integrity of the capsule name capsule.
+ If the capsule is vaild, return the physical address of each capsule name string.
+
+ This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so
+ capsule memory overflow is not going to happen in this routine.
+
+ @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.
+ @param[out] CapsuleNameNum Number of capsule name.
+
+ @retval NULL Capsule name capsule is not valid.
+ @retval CapsuleNameBuf Array of capsule name physical address.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+ValidateCapsuleNameCapsuleIntegrity (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ OUT UINTN *CapsuleNameNum
+ )
+{
+ UINT8 *CapsuleNamePtr;
+ UINT8 *CapsuleNameBufStart;
+ UINT8 *CapsuleNameBufEnd;
+ UINTN Index;
+ UINTN StringSize;
+ EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;
+
+ if (!IsCapsuleNameCapsule (CapsuleHeader)) {
+ return NULL;
+ }
+
+ //
+ // Total string size must be even.
+ //
+ if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {
+ return NULL;
+ }
+
+ *CapsuleNameNum = 0;
+ Index = 0;
+ CapsuleNameBufStart = (UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize;
+
+ //
+ // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
+ //
+ if (((UINTN) CapsuleNameBufStart & BIT0) != 0) {
+ CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
+ if (CapsuleNameBufStart == NULL) {
+ return NULL;
+ }
+ }
+
+ CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ CapsuleNamePtr = CapsuleNameBufStart;
+ while (CapsuleNamePtr < CapsuleNameBufEnd) {
+ StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));
+ CapsuleNamePtr += StringSize;
+ (*CapsuleNameNum) ++;
+ }
+
+ //
+ // Integrity check.
+ //
+ if (CapsuleNamePtr != CapsuleNameBufEnd) {
+ if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
+ FreePool (CapsuleNameBufStart);
+ }
+ return NULL;
+ }
+
+ CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));
+ if (CapsuleNameBuf == NULL) {
+ if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
+ FreePool (CapsuleNameBufStart);
+ }
+ return NULL;
+ }
+
+ CapsuleNamePtr = CapsuleNameBufStart;
+ while (CapsuleNamePtr < CapsuleNameBufEnd) {
+ StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));
+ CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN) CapsuleNamePtr;
+ CapsuleNamePtr += StringSize;
+ Index ++;
+ }
+
+ return CapsuleNameBuf;
+}
+
+/**
+ This routine is called to upper case given unicode string.
+
+ @param[in] Str String to upper case
+
+ @retval upper cased string after process
+
+**/
+static
+CHAR16 *
+UpperCaseString (
+ IN CHAR16 *Str
+ )
+{
+ CHAR16 *Cptr;
+
+ for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
+ if (L'a' <= *Cptr && *Cptr <= L'z') {
+ *Cptr = *Cptr - L'a' + L'A';
+ }
+ }
+
+ return Str;
+}
+
+/**
+ This routine is used to return substring before period '.' or '\0'
+ Caller should respsonsible of substr space allocation & free
+
+ @param[in] Str String to check
+ @param[out] SubStr First part of string before period or '\0'
+ @param[out] SubStrLen Length of first part of string
+
+**/
+static
+VOID
+GetSubStringBeforePeriod (
+ IN CHAR16 *Str,
+ OUT CHAR16 *SubStr,
+ OUT UINTN *SubStrLen
+ )
+{
+ UINTN Index;
+ for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
+ SubStr[Index] = Str[Index];
+ }
+
+ SubStr[Index] = L'\0';
+ *SubStrLen = Index;
+}
+
+/**
+ This routine pad the string in tail with input character.
+
+ @param[in] StrBuf Str buffer to be padded, should be enough room for
+ @param[in] PadLen Expected padding length
+ @param[in] Character Character used to pad
+
+**/
+static
+VOID
+PadStrInTail (
+ IN CHAR16 *StrBuf,
+ IN UINTN PadLen,
+ IN CHAR16 Character
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; StrBuf[Index] != L'\0'; Index++);
+
+ while(PadLen != 0) {
+ StrBuf[Index] = Character;
+ Index++;
+ PadLen--;
+ }
+
+ StrBuf[Index] = L'\0';
+}
+
+/**
+ This routine find the offset of the last period '.' of string. If No period exists
+ function FileNameExtension is set to L'\0'
+
+ @param[in] FileName File name to split between last period
+ @param[out] FileNameFirst First FileName before last period
+ @param[out] FileNameExtension FileName after last period
+
+**/
+static
+VOID
+SplitFileNameExtension (
+ IN CHAR16 *FileName,
+ OUT CHAR16 *FileNameFirst,
+ OUT CHAR16 *FileNameExtension
+ )
+{
+ UINTN Index;
+ UINTN StringLen;
+
+ StringLen = StrnLenS(FileName, MAX_FILE_NAME_SIZE);
+ for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);
+
+ //
+ // No period exists. No FileName Extension
+ //
+ if (Index == 0 && FileName[Index] != L'.') {
+ FileNameExtension[0] = L'\0';
+ Index = StringLen;
+ } else {
+ StrCpyS(FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);
+ }
+
+ //
+ // Copy First file name
+ //
+ StrnCpyS(FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
+ FileNameFirst[Index] = L'\0';
+}
+
+/**
+ This routine is called to get all boot options in the order determnined by:
+ 1. "OptionBuf"
+ 2. "BootOrder"
+
+ @param[out] OptionBuf BootList buffer to all boot options returned
+ @param[out] OptionCount BootList count of all boot options returned
+
+ @retval EFI_SUCCESS There is no error when processing capsule
+
+**/
+EFI_STATUS
+GetBootOptionInOrder(
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,
+ OUT UINTN *OptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT16 BootNext;
+ CHAR16 BootOptionName[20];
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;
+ UINTN BootOrderCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
+ UINTN BootNextCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;
+
+ BootOrderOptionBuf = NULL;
+ TempBuf = NULL;
+ BootNextCount = 0;
+ BootOrderCount = 0;
+ *OptionBuf = NULL;
+ *OptionCount = 0;
+
+ //
+ // First Get BootOption from "BootNext"
+ //
+ DataSize = sizeof(BootNext);
+ Status = gRT->GetVariable (
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ (VOID *)&BootNext
+ );
+ //
+ // BootNext variable is a single UINT16
+ //
+ if (!EFI_ERROR(Status) && DataSize == sizeof(UINT16)) {
+ //
+ // Add the boot next boot option
+ //
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);
+ ZeroMem(&BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
+
+ if (!EFI_ERROR(Status)) {
+ BootNextCount = 1;
+ }
+ }
+
+ //
+ // Second get BootOption from "BootOrder"
+ //
+ BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);
+ if (BootNextCount == 0 && BootOrderCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // At least one BootOption is found
+ //
+ TempBuf = AllocatePool(sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));
+ if (TempBuf != NULL) {
+ if (BootNextCount == 1) {
+ CopyMem(TempBuf, &BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
+ }
+
+ if (BootOrderCount > 0) {
+ CopyMem(TempBuf + BootNextCount, BootOrderOptionBuf, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
+ }
+
+ *OptionBuf = TempBuf;
+ *OptionCount = BootNextCount + BootOrderCount;
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ FreePool(BootOrderOptionBuf);
+
+ return Status;
+}
+
+/**
+ This routine is called to get boot option by OptionNumber.
+
+ @param[in] Number The OptionNumber of boot option
+ @param[out] OptionBuf BootList buffer to all boot options returned
+
+ @retval EFI_SUCCESS There is no error when getting boot option
+
+**/
+EFI_STATUS
+GetBootOptionByNumber(
+ IN UINT16 Number,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 BootOptionName[20];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);
+ ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);
+
+ if (!EFI_ERROR (Status)) {
+ *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ if (*OptionBuf != NULL) {
+ CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Get Active EFI System Partition within GPT based on device path.
+
+ @param[in] DevicePath Device path to find a active EFI System Partition
+ @param[out] FsHandle BootList points to all boot options returned
+
+ @retval EFI_SUCCESS Active EFI System Partition is succesfully found
+ @retval EFI_NOT_FOUND No Active EFI System Partition is found
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromDevPath(
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_HANDLE *FsHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+
+ //
+ // Check if the device path contains GPT node
+ //
+ TempDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
+ Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+ if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
+ break;
+ }
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
+
+ //
+ // Search for simple file system on this handler
+ //
+ if (!EFI_ERROR(Status)) {
+ Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (!EFI_ERROR(Status)) {
+ *FsHandle = Handle;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This routine is called to get Simple File System protocol on the first EFI system partition found in
+ active boot option. The boot option list is detemined in order by
+ 1. "BootNext"
+ 2. "BootOrder"
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ device like USB can get enumerated.
+ @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.
+ On output, return the OptionNumber of the boot option where EFI
+ system partition is got from.
+ @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition
+
+ @retval EFI_SUCCESS Simple File System protocol found for EFI system partition
+ @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromActiveBootOption(
+ IN UINTN MaxRetry,
+ IN OUT UINT16 **LoadOptionNumber,
+ OUT EFI_HANDLE *FsHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;
+ UINTN BootOptionNum;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+
+ *FsHandle = NULL;
+ CurFullPath = NULL;
+
+ if (*LoadOptionNumber != NULL) {
+ BootOptionNum = 1;
+ Status = GetBootOptionByNumber(**LoadOptionNumber, &BootOptionBuf);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));
+ return Status;
+ }
+ } else {
+ Status = GetBootOptionInOrder(&BootOptionBuf, &BootOptionNum);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Search BootOptionList to check if it is an active boot option with EFI system partition
+ // 1. Connect device path
+ // 2. expend short/plug in devicepath
+ // 3. LoadImage
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ //
+ // Get the boot option from the link list
+ //
+ DevicePath = BootOptionBuf[Index].FilePath;
+
+ //
+ // Skip inactive or legacy boot options
+ //
+ if ((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
+ DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
+ continue;
+ }
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr;
+
+ DevicePathStr = ConvertDevicePathToText(DevicePath, TRUE, TRUE);
+ if (DevicePathStr != NULL){
+ DEBUG((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
+ FreePool(DevicePathStr);
+ } else {
+ DEBUG((DEBUG_INFO, "DevicePathToStr failed\n"));
+ }
+ );
+
+ CurFullPath = NULL;
+ //
+ // Try every full device Path generated from bootoption
+ //
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath(DevicePath, CurFullPath);
+
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+
+ if (CurFullPath == NULL) {
+ //
+ // No Active EFI system partition is found in BootOption device path
+ //
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr1;
+
+ DevicePathStr1 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
+ if (DevicePathStr1 != NULL){
+ DEBUG((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
+ FreePool(DevicePathStr1);
+ }
+ );
+
+ //
+ // Make sure the boot option device path connected.
+ // Only handle first device in boot option. Other optional device paths are described as OSV specific
+ // FullDevice could contain extra directory & file info. So don't check connection status here.
+ //
+ EfiBootManagerConnectDevicePath (CurFullPath, NULL);
+ Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
+
+ //
+ // Some relocation device like USB need more time to get enumerated
+ //
+ while (EFI_ERROR(Status) && MaxRetry > 0) {
+ EfiBootManagerConnectDevicePath(CurFullPath, NULL);
+
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
+ if (!EFI_ERROR(Status)) {
+ break;
+ }
+ DEBUG((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));
+ //
+ // Stall 100ms if connection failed to ensure USB stack is ready
+ //
+ gBS->Stall(100000);
+ MaxRetry --;
+ }
+ } while(EFI_ERROR(Status));
+
+ //
+ // Find a qualified Simple File System
+ //
+ if (!EFI_ERROR(Status)) {
+ break;
+ }
+
+ }
+
+ //
+ // Return the OptionNumber of the boot option where EFI system partition is got from
+ //
+ if (*LoadOptionNumber == NULL) {
+ *LoadOptionNumber = AllocateCopyPool (sizeof(UINT16), (UINT16 *) &BootOptionBuf[Index].OptionNumber);
+ if (*LoadOptionNumber == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // No qualified EFI system partition found
+ //
+ if (*FsHandle == NULL) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr2;
+ if (*FsHandle != NULL) {
+ DevicePathStr2 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
+ if (DevicePathStr2 != NULL){
+ DEBUG((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));
+ FreePool(DevicePathStr2);
+ }
+ } else {
+ DEBUG((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
+ }
+ );
+
+ if (CurFullPath != NULL) {
+ FreePool(CurFullPath);
+ }
+
+ //
+ // Free BootOption Buffer
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ if (BootOptionBuf[Index].Description != NULL) {
+ FreePool(BootOptionBuf[Index].Description);
+ }
+
+ if (BootOptionBuf[Index].FilePath != NULL) {
+ FreePool(BootOptionBuf[Index].FilePath);
+ }
+
+ if (BootOptionBuf[Index].OptionalData != NULL) {
+ FreePool(BootOptionBuf[Index].OptionalData);
+ }
+ }
+
+ FreePool(BootOptionBuf);
+
+ return Status;
+}
+
+
+/**
+ This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in
+ alphabetical order described in UEFI spec.
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of file to be red from directory
+ @param[out] FileInfoList File images info list red from directory
+ @param[out] FileNum File images number red from directory
+
+ @retval EFI_SUCCESS File FileInfo list in the given
+
+**/
+EFI_STATUS
+GetFileInfoListInAlphabetFromDir(
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr,
+ OUT LIST_ENTRY *FileInfoList,
+ OUT UINTN *FileNum
+ )
+{
+ EFI_STATUS Status;
+ FILE_INFO_ENTRY *NewFileInfoEntry;
+ FILE_INFO_ENTRY *TempFileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ CHAR16 *NewFileName;
+ CHAR16 *ListedFileName;
+ CHAR16 *NewFileNameExtension;
+ CHAR16 *ListedFileNameExtension;
+ CHAR16 *TempNewSubStr;
+ CHAR16 *TempListedSubStr;
+ LIST_ENTRY *Link;
+ BOOLEAN NoFile;
+ UINTN FileCount;
+ UINTN IndexNew;
+ UINTN IndexListed;
+ UINTN NewSubStrLen;
+ UINTN ListedSubStrLen;
+ INTN SubStrCmpResult;
+
+ Status = EFI_SUCCESS;
+ NewFileName = NULL;
+ ListedFileName = NULL;
+ NewFileNameExtension = NULL;
+ ListedFileNameExtension = NULL;
+ TempNewSubStr = NULL;
+ TempListedSubStr = NULL;
+ FileInfo = NULL;
+ NoFile = FALSE;
+ FileCount = 0;
+
+ InitializeListHead(FileInfoList);
+
+ TempNewSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
+ TempListedSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
+
+ if (TempNewSubStr == NULL || TempListedSubStr == NULL ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ for ( Status = FileHandleFindFirstFile(Dir, &FileInfo)
+ ; !EFI_ERROR(Status) && !NoFile
+ ; Status = FileHandleFindNextFile(Dir, FileInfo, &NoFile)
+ ){
+ if (FileInfo == NULL) {
+ goto EXIT;
+ }
+
+ //
+ // Skip file with mismatching File attribute
+ //
+ if ((FileInfo->Attribute & (FileAttr)) == 0) {
+ continue;
+ }
+
+ NewFileInfoEntry = NULL;
+ NewFileInfoEntry = (FILE_INFO_ENTRY*)AllocateZeroPool(sizeof(FILE_INFO_ENTRY));
+ if (NewFileInfoEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+ NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
+ NewFileInfoEntry->FileInfo = AllocateCopyPool((UINTN) FileInfo->Size, FileInfo);
+ if (NewFileInfoEntry->FileInfo == NULL) {
+ FreePool(NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ NewFileInfoEntry->FileNameFirstPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
+ if (NewFileInfoEntry->FileNameFirstPart == NULL) {
+ FreePool(NewFileInfoEntry->FileInfo);
+ FreePool(NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+ NewFileInfoEntry->FileNameSecondPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);
+ if (NewFileInfoEntry->FileNameSecondPart == NULL) {
+ FreePool(NewFileInfoEntry->FileInfo);
+ FreePool(NewFileInfoEntry->FileNameFirstPart);
+ FreePool(NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension
+ // If no period in the whole file name. NewFileExtension is set to L'\0'
+ //
+ NewFileName = NewFileInfoEntry->FileNameFirstPart;
+ NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
+ SplitFileNameExtension(FileInfo->FileName, NewFileName, NewFileNameExtension);
+ UpperCaseString(NewFileName);
+ UpperCaseString(NewFileNameExtension);
+
+ //
+ // Insert capsule file in alphabetical ordered list
+ //
+ for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {
+ //
+ // Get the FileInfo from the link list
+ //
+ TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ ListedFileName = TempFileInfoEntry->FileNameFirstPart;
+ ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
+
+ //
+ // Follow rule in UEFI spec 8.5.5 to compare file name
+ //
+ IndexListed = 0;
+ IndexNew = 0;
+ while (TRUE){
+ //
+ // First compare each substrings in NewFileName & ListedFileName between periods
+ //
+ GetSubStringBeforePeriod(&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);
+ GetSubStringBeforePeriod(&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);
+ if (NewSubStrLen > ListedSubStrLen) {
+ //
+ // Substr in NewFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail(TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');
+ } else if (NewSubStrLen < ListedSubStrLen){
+ //
+ // Substr in ListedFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail(TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
+ }
+
+ SubStrCmpResult = StrnCmp(TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);
+ if (SubStrCmpResult != 0) {
+ break;
+ }
+
+ //
+ // Move to skip this substring
+ //
+ IndexNew += NewSubStrLen;
+ IndexListed += ListedSubStrLen;
+ //
+ // Reach File First Name end
+ //
+ if (NewFileName[IndexNew] == L'\0' || ListedFileName[IndexListed] == L'\0') {
+ break;
+ }
+
+ //
+ // Skip the period L'.'
+ //
+ IndexNew++;
+ IndexListed++;
+ }
+
+ if (SubStrCmpResult < 0) {
+ //
+ // NewFileName is smaller. Find the right place to insert New file
+ //
+ break;
+ } else if (SubStrCmpResult == 0) {
+ //
+ // 2 cases whole NewFileName is smaller than ListedFileName
+ // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension
+ // 2. if NewFileName is shorter than ListedFileName
+ //
+ if (NewFileName[IndexNew] == L'\0') {
+ if (ListedFileName[IndexListed] != L'\0' || (StrnCmp(NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Other case, ListedFileName is smaller. Continue to compare the next file in the list
+ //
+ }
+
+ //
+ // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order
+ // Insert it before this entry
+ // else
+ // Insert at the tail of this list (Link = FileInfoList)
+ //
+ InsertTailList(Link, &NewFileInfoEntry->Link);
+
+ FileCount++;
+ }
+
+ *FileNum = FileCount;
+
+EXIT:
+
+ if (TempNewSubStr != NULL) {
+ FreePool(TempNewSubStr);
+ }
+
+ if (TempListedSubStr != NULL) {
+ FreePool(TempListedSubStr);
+ }
+
+ if (EFI_ERROR(Status)) {
+ while(!IsListEmpty(FileInfoList)) {
+ Link = FileInfoList->ForwardLink;
+ RemoveEntryList(Link);
+
+ TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool(TempFileInfoEntry->FileInfo);
+ FreePool(TempFileInfoEntry->FileNameFirstPart);
+ FreePool(TempFileInfoEntry->FileNameSecondPart);
+ FreePool(TempFileInfoEntry);
+ }
+ *FileNum = 0;
+ }
+
+ return Status;
+}
+
+
+/**
+ This routine is called to get all qualified image from file from an given directory
+ in alphabetic order. All the file image is copied to allocated boottime memory.
+ Caller should free these memory
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of file to be red from directory
+ @param[out] FilePtr File images Info buffer red from directory
+ @param[out] FileNum File images number red from directory
+
+ @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.
+
+**/
+EFI_STATUS
+GetFileImageInAlphabetFromDir(
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr,
+ OUT IMAGE_INFO **FilePtr,
+ OUT UINTN *FileNum
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_FILE_HANDLE FileHandle;
+ FILE_INFO_ENTRY *FileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileCount;
+ IMAGE_INFO *TempFilePtrBuf;
+ UINTN Size;
+ LIST_ENTRY FileInfoList;
+
+ FileHandle = NULL;
+ FileCount = 0;
+ TempFilePtrBuf = NULL;
+ *FilePtr = NULL;
+
+ //
+ // Get file list in Dir in alphabetical order
+ //
+ Status = GetFileInfoListInAlphabetFromDir(
+ Dir,
+ FileAttr,
+ &FileInfoList,
+ &FileCount
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
+ goto EXIT;
+ }
+
+ if (FileCount == 0) {
+ DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
+ Status = EFI_NOT_FOUND;
+ goto EXIT;
+ }
+
+ TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool(sizeof(IMAGE_INFO) * FileCount);
+ if (TempFilePtrBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Read all files from FileInfoList to BS memory
+ //
+ FileCount = 0;
+ for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
+ //
+ // Get FileInfo from the link list
+ //
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+
+ Status = Dir->Open(
+ Dir,
+ &FileHandle,
+ FileInfo->FileName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR(Status)){
+ continue;
+ }
+
+ Size = (UINTN)FileInfo->FileSize;
+ TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool(Size);
+ if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
+ DEBUG((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));
+ break;
+ }
+
+ Status = FileHandle->Read(
+ FileHandle,
+ &Size,
+ TempFilePtrBuf[FileCount].ImageAddress
+ );
+
+ FileHandle->Close(FileHandle);
+
+ //
+ // Skip read error file
+ //
+ if (EFI_ERROR(Status) || Size != (UINTN)FileInfo->FileSize) {
+ //
+ // Remove this error file info accordingly
+ // & move Link to BackLink
+ //
+ Link = RemoveEntryList(Link);
+ Link = Link->BackLink;
+
+ FreePool(FileInfoEntry->FileInfo);
+ FreePool(FileInfoEntry->FileNameFirstPart);
+ FreePool(FileInfoEntry->FileNameSecondPart);
+ FreePool(FileInfoEntry);
+
+ FreePool(TempFilePtrBuf[FileCount].ImageAddress);
+ TempFilePtrBuf[FileCount].ImageAddress = NULL;
+ TempFilePtrBuf[FileCount].FileInfo = NULL;
+
+ continue;
+ }
+ TempFilePtrBuf[FileCount].FileInfo = FileInfo;
+ FileCount++;
+ }
+
+ DEBUG_CODE (
+ for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+ DEBUG((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));
+ }
+ );
+
+EXIT:
+
+ *FilePtr = TempFilePtrBuf;
+ *FileNum = FileCount;
+
+ //
+ // FileInfo will be freed by Calller
+ //
+ while(!IsListEmpty(&FileInfoList)) {
+ Link = FileInfoList.ForwardLink;
+ RemoveEntryList(Link);
+
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool(FileInfoEntry->FileNameFirstPart);
+ FreePool(FileInfoEntry->FileNameSecondPart);
+ FreePool(FileInfoEntry);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to remove all qualified image from file from an given directory.
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of files to be deleted
+
+ @retval EFI_SUCCESS Succeed to remove all files from an given directory.
+
+**/
+EFI_STATUS
+RemoveFileFromDir(
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ LIST_ENTRY FileInfoList;
+ EFI_FILE_HANDLE FileHandle;
+ FILE_INFO_ENTRY *FileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileCount;
+
+ FileHandle = NULL;
+
+ //
+ // Get file list in Dir in alphabetical order
+ //
+ Status = GetFileInfoListInAlphabetFromDir(
+ Dir,
+ FileAttr,
+ &FileInfoList,
+ &FileCount
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
+ goto EXIT;
+ }
+
+ if (FileCount == 0) {
+ DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
+ Status = EFI_NOT_FOUND;
+ goto EXIT;
+ }
+
+ //
+ // Delete all files with given attribute in Dir
+ //
+ for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {
+ //
+ // Get FileInfo from the link list
+ //
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+
+ Status = Dir->Open(
+ Dir,
+ &FileHandle,
+ FileInfo->FileName,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (EFI_ERROR(Status)){
+ continue;
+ }
+
+ Status = FileHandle->Delete(FileHandle);
+ }
+
+EXIT:
+
+ while(!IsListEmpty(&FileInfoList)) {
+ Link = FileInfoList.ForwardLink;
+ RemoveEntryList(Link);
+
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool(FileInfoEntry->FileInfo);
+ FreePool(FileInfoEntry);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to get all caspules from file. The capsule file image is
+ copied to BS memory. Caller is responsible to free them.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+ @param[out] CapsulePtr Copied Capsule file Image Info buffer
+ @param[out] CapsuleNum CapsuleNumber
+ @param[out] FsHandle File system handle
+ @param[out] LoadOptionNumber OptionNumber of boot option
+
+ @retval EFI_SUCCESS Succeed to get all capsules.
+
+**/
+EFI_STATUS
+GetAllCapsuleOnDisk(
+ IN UINTN MaxRetry,
+ OUT IMAGE_INFO **CapsulePtr,
+ OUT UINTN *CapsuleNum,
+ OUT EFI_HANDLE *FsHandle,
+ OUT UINT16 *LoadOptionNumber
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE FileDir;
+ UINT16 *TempOptionNumber;
+
+ TempOptionNumber = NULL;
+ *CapsuleNum = 0;
+
+ Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &TempOptionNumber, FsHandle);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol(*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = Fs->OpenVolume(Fs, &RootDir);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = RootDir->Open(
+ RootDir,
+ &FileDir,
+ EFI_CAPSULE_FILE_DIRECTORY,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));
+ RootDir->Close (RootDir);
+ return Status;
+ }
+ RootDir->Close (RootDir);
+
+ //
+ // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
+ // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY
+ //
+ Status = GetFileImageInAlphabetFromDir(
+ FileDir,
+ EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
+ CapsulePtr,
+ CapsuleNum
+ );
+ DEBUG((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));
+
+ //
+ // Always remove file to avoid deadloop in capsule process
+ //
+ Status = RemoveFileFromDir(FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);
+ DEBUG((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
+
+ FileDir->Close (FileDir);
+
+ if (LoadOptionNumber != NULL) {
+ *LoadOptionNumber = *TempOptionNumber;
+ }
+
+ return Status;
+}
+
+/**
+ Build Gather list for a list of capsule images.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] CapsuleSize An array of UINTN to capsule images size
+ @param[in] CapsuleNum The count of capsule images
+ @param[out] BlockDescriptors The block descriptors for the capsule images
+
+ @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
+
+**/
+EFI_STATUS
+BuildGatherList (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *CapsuleSize,
+ IN UINTN CapsuleNum,
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
+ )
+{
+ EFI_STATUS Status;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
+ UINTN Index;
+
+ BlockDescriptors1 = NULL;
+ BlockDescriptorPre = NULL;
+ BlockDescriptorsHeader = NULL;
+
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ //
+ // Allocate memory for the descriptors.
+ //
+ BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));
+ if (BlockDescriptors1 == NULL) {
+ DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ERREXIT;
+ } else {
+ DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1));
+ }
+
+ //
+ // Record descirptor header
+ //
+ if (Index == 0) {
+ BlockDescriptorsHeader = BlockDescriptors1;
+ }
+
+ if (BlockDescriptorPre != NULL) {
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
+ BlockDescriptorPre->Length = 0;
+ }
+
+ BlockDescriptors1->Union.DataBlock = (UINTN) CapsuleBuffer[Index];
+ BlockDescriptors1->Length = CapsuleSize[Index];
+
+ BlockDescriptorPre = BlockDescriptors1 + 1;
+ BlockDescriptors1 = NULL;
+ }
+
+ //
+ // Null-terminate.
+ //
+ if (BlockDescriptorPre != NULL) {
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
+ BlockDescriptorPre->Length = 0;
+ *BlockDescriptors = BlockDescriptorsHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ERREXIT:
+ if (BlockDescriptors1 != NULL) {
+ FreePool (BlockDescriptors1);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
+ is enabled.
+
+ @retval TRUE Flag is enabled
+ @retval FALSE Flag is not enabled
+
+**/
+BOOLEAN
+EFIAPI
+CoDCheckCapsuleOnDiskFlag(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ //
+ // Check File Capsule Delivery Supported Flag in OsIndication variable
+ //
+ OsIndication = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (!EFI_ERROR(Status) &&
+ (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
+
+ @retval EFI_SUCCESS All Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+EFIAPI
+CoDClearCapsuleOnDiskFlag(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ //
+ // Reset File Capsule Delivery Supported Flag in OsIndication variable
+ //
+ OsIndication = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR(Status) ||
+ (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {
+ return Status;
+ }
+
+ OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ Status = gRT->SetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof(UINT64),
+ &OsIndication
+ );
+ ASSERT(!EFI_ERROR(Status));
+
+ //
+ // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable
+ //
+ Status = gRT->SetVariable (
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is called to clear CapsuleOnDisk Relocation Info variable.
+ Total Capsule On Disk length is recorded in this variable
+
+ @retval EFI_SUCCESS Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+CoDClearCapsuleRelocationInfo(
+ VOID
+ )
+{
+ return gRT->SetVariable (
+ COD_RELOCATION_INFO_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ 0,
+ 0,
+ NULL
+ );
+}
+
+/**
+ Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device
+ with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must
+ be a full device path.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems
+ of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+
+ @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.
+
+**/
+EFI_STATUS
+RelocateCapsuleToDisk(
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN CapsuleOnDiskNum;
+ UINTN Index;
+ UINTN DataSize;
+ UINT64 TotalImageSize;
+ UINT64 TotalImageNameSize;
+ IMAGE_INFO *CapsuleOnDiskBuf;
+ EFI_HANDLE Handle;
+ EFI_HANDLE TempHandle;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINT8 *CapsuleDataBuf;
+ UINT8 *CapsulePtr;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE TempCodFile;
+ UINT64 TempCodFileSize;
+ EFI_DEVICE_PATH *TempDevicePath;
+ BOOLEAN RelocationInfo;
+ UINT16 LoadOptionNumber;
+ EFI_CAPSULE_HEADER FileNameCapsuleHeader;
+
+ RootDir = NULL;
+ TempCodFile = NULL;
+ HandleBuffer = NULL;
+ CapsuleDataBuf = NULL;
+ CapsuleOnDiskBuf = NULL;
+ NumberOfHandles = 0;
+
+ DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
+
+ //
+ // 1. Load all Capsule On Disks in to memory
+ //
+ Status = GetAllCapsuleOnDisk(MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
+ if (EFI_ERROR(Status) || CapsuleOnDiskNum == 0 || CapsuleOnDiskBuf == NULL) {
+ DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 2. Connect platform special device path as relocation device.
+ // If no platform special device path specified or the device path is invalid, use the EFI system partition where
+ // stores the capsules as relocation device.
+ //
+ if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), PcdGetSize(PcdCodRelocationDevPath))) {
+ Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), &TempHandle);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Connect all the child handle. Partition & FAT drivers are allowed in this case
+ //
+ gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Find first Simple File System Handle which can match PcdCodRelocationDevPath
+ //
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ DataSize = GetDevicePathSize((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath)) - sizeof(EFI_DEVICE_PATH);
+ if (0 == CompareMem((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
+ Handle = HandleBuffer[Index];
+ break;
+ }
+ }
+
+ FreePool(HandleBuffer);
+
+ if (Index == NumberOfHandles) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ Status = gBS->HandleProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR(Status) || BlockIo->Media->ReadOnly) {
+ DEBUG((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));
+ goto EXIT;
+ }
+
+ Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Check if device used to relocate Capsule On Disk is big enough
+ //
+ TotalImageSize = 0;
+ TotalImageNameSize = 0;
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ //
+ // Overflow check
+ //
+ if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ TotalImageNameSize += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ DEBUG((DEBUG_INFO, "RelocateCapsule: %x Size %x\n",CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));
+ }
+
+ DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));
+ DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));
+
+ if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof(UINT64) * 2 ||
+ MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof(UINT64) * 2) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ TempCodFileSize = sizeof(UINT64) + TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
+
+ //
+ // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly
+ //
+ if (DivU64x32(TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {
+ DEBUG((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));
+ DEBUG((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
+ DEBUG((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));
+ DEBUG((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ CapsuleDataBuf = AllocatePool((UINTN) TempCodFileSize);
+ if (CapsuleDataBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // First UINT64 reserved for total image size, including capsule name capsule.
+ //
+ *(UINT64 *) CapsuleDataBuf = TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
+
+ //
+ // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write
+ //
+ for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof(UINT64); Index < CapsuleOnDiskNum; Index++) {
+ CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize);
+ CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ }
+
+ //
+ // Line the capsule header for capsule name capsule.
+ //
+ CopyGuid(&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
+ FileNameCapsuleHeader.CapsuleImageSize = (UINT32) TotalImageNameSize + sizeof(EFI_CAPSULE_HEADER);
+ FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+ FileNameCapsuleHeader.HeaderSize = sizeof(EFI_CAPSULE_HEADER);
+ CopyMem(CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);
+ CapsulePtr += FileNameCapsuleHeader.HeaderSize;
+
+ //
+ // Line up all the Capsule file names.
+ //
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName));
+ CapsulePtr += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ }
+
+ //
+ // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
+ //
+ Status = Fs->OpenVolume(Fs, &RootDir);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));
+ goto EXIT;
+ }
+
+ Status = RootDir->Open(
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (!EFI_ERROR(Status)) {
+ //
+ // Error handling code to prevent malicious code to hold this file to block capsule on disk
+ //
+ TempCodFile->Delete(TempCodFile);
+ }
+ Status = RootDir->Open(
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
+ 0
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Always write at the begining of TempCap file
+ //
+ DataSize = (UINTN) TempCodFileSize;
+ Status = TempCodFile->Write(
+ TempCodFile,
+ &DataSize,
+ CapsuleDataBuf
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));
+ goto EXIT;
+ }
+
+ if (DataSize != TempCodFileSize) {
+ Status = EFI_DEVICE_ERROR;
+ goto EXIT;
+ }
+
+ //
+ // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
+ // It is used in next reboot by TCB
+ //
+ RelocationInfo = TRUE;
+ Status = gRT->SetVariable(
+ COD_RELOCATION_INFO_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (BOOLEAN),
+ &RelocationInfo
+ );
+ //
+ // Save the LoadOptionNumber of the boot option, where the capsule is relocated,
+ // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is
+ // updated out of TCB to remove the TempCoDFile.
+ //
+ Status = gRT->SetVariable(
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT16),
+ &LoadOptionNumber
+ );
+
+EXIT:
+
+ if (CapsuleDataBuf != NULL) {
+ FreePool(CapsuleDataBuf);
+ }
+
+ if (CapsuleOnDiskBuf != NULL) {
+ //
+ // Free resources allocated by CodLibGetAllCapsuleOnDisk
+ //
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
+ FreePool(CapsuleOnDiskBuf[Index].ImageAddress);
+ FreePool(CapsuleOnDiskBuf[Index].FileInfo);
+ }
+ FreePool(CapsuleOnDiskBuf);
+ }
+
+ if (TempCodFile != NULL) {
+ if (EFI_ERROR(Status)) {
+ TempCodFile->Delete (TempCodFile);
+ } else {
+ TempCodFile->Close (TempCodFile);
+ }
+ }
+
+ if (RootDir != NULL) {
+ RootDir->Close (RootDir);
+ }
+
+ return Status;
+}
+
+/**
+ For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.
+ Relocate Capsule On Disk to memory and call UpdateCapsule().
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+
+ @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.
+
+**/
+EFI_STATUS
+RelocateCapsuleToRam (
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN CapsuleOnDiskNum;
+ IMAGE_INFO *CapsuleOnDiskBuf;
+ EFI_HANDLE Handle;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
+ VOID **CapsuleBuffer;
+ UINTN *CapsuleSize;
+ EFI_CAPSULE_HEADER *FileNameCapsule;
+ UINTN Index;
+ UINT8 *StringBuf;
+ UINTN StringSize;
+ UINTN TotalStringSize;
+
+ CapsuleOnDiskBuf = NULL;
+ BlockDescriptors = NULL;
+ CapsuleBuffer = NULL;
+ CapsuleSize = NULL;
+ FileNameCapsule = NULL;
+ TotalStringSize = 0;
+
+ //
+ // 1. Load all Capsule On Disks into memory
+ //
+ Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);
+ if (EFI_ERROR (Status) || CapsuleOnDiskNum == 0 || CapsuleOnDiskBuf == NULL) {
+ DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 2. Add a capsule for Capsule file name strings
+ //
+ CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));
+ if (CapsuleBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));
+ if (CapsuleSize == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
+ FreePool (CapsuleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ CapsuleBuffer[Index] = (VOID *)(UINTN) CapsuleOnDiskBuf[Index].ImageAddress;
+ CapsuleSize[Index] = (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ }
+
+ FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
+ if (FileNameCapsule == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));
+ FreePool (CapsuleBuffer);
+ FreePool (CapsuleSize);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileNameCapsule->CapsuleImageSize = (UINT32) (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
+ FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+ FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);
+ CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);
+
+ StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
+ for (Index = 0; Index < CapsuleOnDiskNum; Index ++) {
+ StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);
+ StringBuf += StringSize;
+ }
+
+ CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
+ CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);
+
+ //
+ // 3. Build Gather list for the capsules
+ //
+ Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsuleOnDiskNum + 1, &BlockDescriptors);
+ if (EFI_ERROR (Status) || BlockDescriptors == NULL) {
+ FreePool (CapsuleBuffer);
+ FreePool (CapsuleSize);
+ FreePool (FileNameCapsule);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // 4. Call UpdateCapsule() service
+ //
+ Status = gRT->UpdateCapsule((EFI_CAPSULE_HEADER **) CapsuleBuffer, CapsuleOnDiskNum + 1, (UINTN) BlockDescriptors);
+
+ return Status;
+}
+
+/**
+ Relocate Capsule on Disk from EFI system partition.
+
+ Two solution to deliver Capsule On Disk:
+ Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
+ Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
+ device with BlockIo protocol.
+
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
+ Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
+ systems of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRelocateCapsule(
+ UINTN MaxRetry
+ )
+{
+ if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Clear CapsuleOnDisk Flag firstly.
+ //
+ CoDClearCapsuleOnDiskFlag ();
+
+ //
+ // If Capsule In Ram is supported, delivery capsules through memory
+ //
+ if (PcdGetBool (PcdCapsuleInRamSupport)) {
+ DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));
+ return RelocateCapsuleToRam (MaxRetry);
+ } else {
+ DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName)));
+ return RelocateCapsuleToDisk (MaxRetry);
+ }
+}
+
+/**
+ Remove the temp file from the root of EFI System Partition.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Remove the temp file successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRemoveTempFile (
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT16 *LoadOptionNumber;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_HANDLE FsHandle;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE TempCodFile;
+
+ RootDir = NULL;
+ TempCodFile = NULL;
+ DataSize = sizeof(UINT16);
+
+ LoadOptionNumber = AllocatePool (sizeof(UINT16));
+ if (LoadOptionNumber == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check if capsule files are relocated
+ //
+ Status = gRT->GetVariable (
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &DataSize,
+ (VOID *)LoadOptionNumber
+ );
+ if (EFI_ERROR(Status) || DataSize != sizeof(UINT16)) {
+ goto EXIT;
+ }
+
+ //
+ // Get the EFI file system from the boot option where the capsules are relocated
+ //
+ Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &LoadOptionNumber, &FsHandle);
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ Status = gBS->HandleProtocol(FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ Status = Fs->OpenVolume(Fs, &RootDir);
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Delete the TempCoDFile
+ //
+ Status = RootDir->Open(
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ TempCodFile->Delete(TempCodFile);
+
+ //
+ // Clear "CoDRelocationLoadOption" variable
+ //
+ Status = gRT->SetVariable (
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ 0,
+ 0,
+ NULL
+ );
+
+EXIT:
+ if (LoadOptionNumber != NULL) {
+ FreePool (LoadOptionNumber);
+ }
+
+ if (RootDir != NULL) {
+ RootDir->Close(RootDir);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
new file mode 100644
index 000000000..4300e3277
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
@@ -0,0 +1,75 @@
+/** @file
+ Defines several datastructures used by Capsule On Disk feature.
+ They are mainly used for FAT files.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CAPSULES_ON_DISK_H_
+#define _CAPSULES_ON_DISK_H_
+
+#include <Uefi.h>
+#include <Pi/PiMultiPhase.h>
+
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootManagerLib.h>
+
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/BlockIo.h>
+
+#include <Guid/CapsuleVendor.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+
+//
+// This data structure is the part of FILE_INFO_ENTRY
+//
+#define FILE_INFO_SIGNATURE SIGNATURE_32 ('F', 'L', 'I', 'F')
+
+//
+// LoadOptionNumber of the boot option where the capsules is relocated.
+//
+#define COD_RELOCATION_LOAD_OPTION_VAR_NAME L"CodRelocationLoadOption"
+
+//
+// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
+//
+#define MAX_FILE_NAME_SIZE 522
+#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
+#define MAX_FILE_INFO_LEN (OFFSET_OF(EFI_FILE_INFO, FileName) + MAX_FILE_NAME_LEN)
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; /// Linked list members.
+ EFI_FILE_INFO *FileInfo; /// Pointer to the FileInfo struct for this file or NULL.
+ CHAR16 *FileNameFirstPart; /// Text to the left of right-most period in the file name. String is capitialized
+ CHAR16 *FileNameSecondPart; /// Text to the right of right-most period in the file name.String is capitialized. Maybe NULL
+} FILE_INFO_ENTRY;
+
+typedef struct {
+ //
+ // image address.
+ //
+ VOID *ImageAddress;
+ //
+ // The file info of the image comes from.
+ // if FileInfo == NULL. means image does not come from file
+ //
+ EFI_FILE_INFO *FileInfo;
+} IMAGE_INFO;
+
+#endif // _CAPSULES_ON_DISK_H_
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
new file mode 100644
index 000000000..90942135d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -0,0 +1,1650 @@
+/** @file
+ DXE capsule library.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
+ ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
+ performs basic validation.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BmpSupportLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/FirmwareManagementProgress.h>
+#include <Protocol/DevicePath.h>
+
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
+BOOLEAN mIsVirtualAddrConverted = FALSE;
+
+BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
+EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
+
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ );
+
+/**
+ Record capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ );
+
+/**
+ Record FMP capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
+ IN CHAR16 *CapFileName OPTIONAL
+ );
+
+/**
+ Function indicate the current completion progress of the firmware
+ update. Platform may override with own specific progress function.
+
+ @param[in] Completion A value between 1 and 100 indicating the current
+ completion progress of the firmware update
+
+ @retval EFI_SUCESS The capsule update progress was updated.
+ @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
+**/
+EFI_STATUS
+EFIAPI
+UpdateImageProgress (
+ IN UINTN Completion
+ );
+
+/**
+ Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a capsule name capsule.
+ @retval FALSE It is not a capsule name capsule.
+**/
+BOOLEAN
+IsCapsuleNameCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
+}
+
+/**
+ Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+ @param[in] CapsuleGuid A pointer to EFI_GUID
+
+ @retval TRUE It is a FMP capsule GUID.
+ @retval FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+ IN EFI_GUID *CapsuleGuid
+ )
+{
+ if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Validate if it is valid capsule header
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller provided correct CapsuleHeader pointer
+ and CapsuleSize.
+
+ This function validates the fields in EFI_CAPSULE_HEADER.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapsuleSize Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN UINT64 CapsuleSize
+ )
+{
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+ return FALSE;
+ }
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Validate Fmp capsules layout.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller validated the capsule by using
+ IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
+ The capsule buffer size is CapsuleHeader->CapsuleImageSize.
+
+ This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
+
+ This function need support nested FMP capsule.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
+
+ @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,
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT8 *EndOfCapsule;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *EndOfPayload;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ UINTN FmpCapsuleSize;
+ UINTN FmpCapsuleHeaderSize;
+ UINT64 FmpImageSize;
+ UINTN FmpImageHeaderSize;
+
+ if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+ return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
+ }
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+ EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
+ FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
+
+ if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
+ DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ // No overflow
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
+ DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
+ return EFI_INVALID_PARAMETER;
+ }
+ FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
+
+ // Check ItemOffsetList
+ for (Index = 0; Index < ItemNum; Index++) {
+ if (ItemOffsetList[Index] >= FmpCapsuleSize) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // All the address in ItemOffsetList must be stored in ascending order
+ //
+ if (Index > 0) {
+ if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
+ DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (Index == ItemNum - 1) {
+ EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
+ } else {
+ EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
+ }
+ FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
+
+ FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
+ if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
+ (ImageHeader->Version < 1)) {
+ DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ImageHeader->Version == 1) {
+ FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else if (ImageHeader->Version == 2) {
+ FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+ if (FmpImageSize < FmpImageHeaderSize) {
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // No overflow
+ if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
+ DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (ItemNum == 0) {
+ //
+ // No driver & payload element in FMP
+ //
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
+ if (EndOfPayload != EndOfCapsule) {
+ DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EmbeddedDriverCount != NULL) {
+ *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] 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.
+**/
+EFI_STATUS
+DisplayCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
+ UINTN PayloadSize;
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINTN BltSize;
+ UINTN Height;
+ UINTN Width;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ //
+ // UX capsule doesn't have extended header entries.
+ //
+ if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
+ return EFI_UNSUPPORTED;
+ }
+ ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN) CapsuleHeader + CapsuleHeader->HeaderSize);
+ //
+ // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
+ //
+ PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ //
+ // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
+ // Further size check is performed by the logic translating BMP to GOP BLT.
+ //
+ if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImagePayload->Version != 1) {
+ return EFI_UNSUPPORTED;
+ }
+ if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Only Support Bitmap by now
+ //
+ if (ImagePayload->ImageType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open GOP
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR(Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = NULL;
+ Width = 0;
+ Height = 0;
+ Status = TranslateBmpToGopBlt (
+ ImagePayload + 1,
+ PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),
+ &Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) ImagePayload->OffsetX,
+ (UINTN) ImagePayload->OffsetY,
+ Width,
+ Height,
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+
+ FreePool(Blt);
+
+ return Status;
+}
+
+/**
+ Dump FMP information.
+
+ @param[in] ImageInfoSize The size of ImageInfo, in bytes.
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+ @param[in] PackageVersion The version of package.
+ @param[in] PackageVersionName The version name of package.
+**/
+VOID
+DumpFmpImageInfo (
+ IN UINTN ImageInfoSize,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ IN UINT32 DescriptorVersion,
+ IN UINT8 DescriptorCount,
+ IN UINTN DescriptorSize,
+ IN UINT32 PackageVersion,
+ IN CHAR16 *PackageVersionName
+ )
+{
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
+ UINTN Index;
+
+ DEBUG((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
+ DEBUG((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
+ DEBUG((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
+ DEBUG((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
+ DEBUG((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
+ CurrentImageInfo = ImageInfo;
+ for (Index = 0; Index < DescriptorCount; Index++) {
+ DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
+ DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
+ DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
+ DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
+ DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
+ DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
+ DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
+ DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
+ DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
+ DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
+ if (DescriptorVersion > 1) {
+ DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
+ if (DescriptorVersion > 2) {
+ DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
+ DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
+ DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));
+ }
+ }
+ //
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+ //
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
+ }
+}
+
+/**
+ Dump a non-nested FMP capsule.
+
+ @param[in] CapsuleHeader A pointer to CapsuleHeader
+**/
+VOID
+DumpFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINTN Index;
+ UINT64 *ItemOffsetList;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
+ DEBUG((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
+ DEBUG((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ }
+ for (; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
+ DEBUG((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+ DEBUG((DEBUG_VERBOSE, " ImageHeader:\n"));
+ DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
+ DEBUG((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
+ DEBUG((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
+ DEBUG((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
+ DEBUG((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
+ if (ImageHeader->Version >= 2) {
+ DEBUG((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+ }
+}
+
+/**
+ Dump all FMP information.
+**/
+VOID
+DumpAllFmpInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return ;
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &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 = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(FmpImageInfoBuf);
+ continue;
+ }
+
+ DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
+ DumpFmpImageInfo(
+ ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ FmpImageInfoDescriptorVer, // DescriptorVersion
+ FmpImageInfoCount, // DescriptorCount
+ DescriptorSize, // DescriptorSize
+ PackageVersion, // PackageVersion
+ PackageVersionName // PackageVersionName
+ );
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+
+ FreePool(FmpImageInfoBuf);
+ }
+
+ FreePool (HandleBuffer);
+
+ return ;
+}
+
+/**
+ Get FMP handle by ImageTypeId and HardwareInstance.
+
+ @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
+ @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
+ @param[out] NoHandles The number of handles returned in HandleBuf.
+ @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
+ @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
+ the requested array of handles.
+
+ @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
+ HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
+ was returned in NoHandles.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+**/
+EFI_STATUS
+GetFmpHandleBufferByType (
+ IN EFI_GUID *UpdateImageTypeId,
+ IN UINT64 UpdateHardwareInstance,
+ OUT UINTN *NoHandles, OPTIONAL
+ OUT EFI_HANDLE **HandleBuf, OPTIONAL
+ OUT BOOLEAN **ResetRequiredBuf OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_HANDLE *MatchedHandleBuffer;
+ BOOLEAN *MatchedResetRequiredBuffer;
+ UINTN MatchedNumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ UINTN Index2;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
+
+ if (NoHandles != NULL) {
+ *NoHandles = 0;
+ }
+ if (HandleBuf != NULL) {
+ *HandleBuf = NULL;
+ }
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = NULL;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ MatchedNumberOfHandles = 0;
+
+ MatchedHandleBuffer = NULL;
+ if (HandleBuf != NULL) {
+ MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);
+ if (MatchedHandleBuffer == NULL) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ MatchedResetRequiredBuffer = NULL;
+ if (ResetRequiredBuf != NULL) {
+ MatchedResetRequiredBuffer = AllocateZeroPool (sizeof(BOOLEAN) * NumberOfHandles);
+ if (MatchedResetRequiredBuffer == NULL) {
+ if (MatchedHandleBuffer != NULL) {
+ FreePool (MatchedHandleBuffer);
+ }
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &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 = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(FmpImageInfoBuf);
+ continue;
+ }
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+
+ TempFmpImageInfo = FmpImageInfoBuf;
+ for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
+ //
+ // Check if this FMP instance matches
+ //
+ if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
+ if ((UpdateHardwareInstance == 0) ||
+ ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
+ (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {
+ if (MatchedHandleBuffer != NULL) {
+ MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
+ }
+ if (MatchedResetRequiredBuffer != NULL) {
+ MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
+ ((TempFmpImageInfo->AttributesSetting &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
+ }
+ MatchedNumberOfHandles++;
+ break;
+ }
+ }
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
+ }
+ FreePool(FmpImageInfoBuf);
+ }
+
+ FreePool (HandleBuffer);
+
+ if (MatchedNumberOfHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (NoHandles != NULL) {
+ *NoHandles = MatchedNumberOfHandles;
+ }
+ if (HandleBuf != NULL) {
+ *HandleBuf = MatchedHandleBuffer;
+ }
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = MatchedResetRequiredBuffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return FmpImageInfoDescriptorVer by an FMP handle.
+
+ @param[in] Handle A FMP handle.
+
+ @return FmpImageInfoDescriptorVer associated with the FMP.
+**/
+UINT32
+GetFmpImageInfoDescriptorVer (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR(Status)) {
+ return 0;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return 0;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ return 0;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(FmpImageInfoBuf);
+ return 0;
+ }
+ return FmpImageInfoDescriptorVer;
+}
+
+/**
+ Set FMP image data.
+
+ @param[in] Handle A FMP handle.
+ @param[in] ImageHeader The payload image header.
+ @param[in] PayloadIndex The index of the payload.
+
+ @return The status of FMP->SetImage.
+**/
+EFI_STATUS
+SetFmpImageData (
+ IN EFI_HANDLE Handle,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN UINTN PayloadIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINT8 *Image;
+ VOID *VendorCode;
+ CHAR16 *AbortReason;
+ EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
+
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup Firmware Management Progress Protocol before SetImage() is called
+ // This is an optional protocol that may not be present on Handle.
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEdkiiFirmwareManagementProgressProtocolGuid,
+ (VOID **)&mFmpProgress
+ );
+ if (EFI_ERROR (Status)) {
+ mFmpProgress = NULL;
+ }
+
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ Image = (UINT8 *)(ImageHeader + 1);
+ } else {
+ //
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
+ // Header should exclude UpdateHardwareInstance field, and
+ // ImageCapsuleSupport field if version is 2.
+ //
+ if (ImageHeader->Version == 1) {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+ }
+
+ if (ImageHeader->UpdateVendorCodeSize == 0) {
+ VendorCode = NULL;
+ } else {
+ VendorCode = Image + ImageHeader->UpdateImageSize;
+ }
+ AbortReason = NULL;
+ DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));
+ DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
+ DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
+ DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
+ if (ImageHeader->Version >= 2) {
+ DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+ DEBUG((DEBUG_INFO, "\n"));
+
+ //
+ // Before calling SetImage(), reset the progress bar to 0%
+ //
+ ProgressCallback = UpdateImageProgress;
+ Status = UpdateImageProgress (0);
+ if (EFI_ERROR (Status)) {
+ ProgressCallback = NULL;
+ }
+
+ Status = Fmp->SetImage(
+ Fmp,
+ ImageHeader->UpdateImageIndex, // ImageIndex
+ Image, // Image
+ ImageHeader->UpdateImageSize, // ImageSize
+ VendorCode, // VendorCode
+ ProgressCallback, // Progress
+ &AbortReason // AbortReason
+ );
+ //
+ // Set the progress bar to 100% after returning from SetImage()
+ //
+ if (ProgressCallback != NULL) {
+ UpdateImageProgress (100);
+ }
+
+ DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
+ if (AbortReason != NULL) {
+ DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
+ FreePool(AbortReason);
+ }
+
+ //
+ // Clear mFmpProgress after SetImage() returns
+ //
+ mFmpProgress = NULL;
+
+ return Status;
+}
+
+/**
+ Start a UEFI image in the FMP payload.
+
+ @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
+ @param[in] ImageSize The size in bytes of ImageBuffer.
+
+ @return The status of gBS->LoadImage and gBS->StartImage.
+**/
+EFI_STATUS
+StartFmpImage (
+ IN VOID *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ MEMMAP_DEVICE_PATH MemMapNode;
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN ExitDataSize;
+
+ 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)ImageBuffer;
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
+
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
+ if (DriverDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
+ Status = gBS->LoadImage(
+ FALSE,
+ gImageHandle,
+ DriverDevicePath,
+ ImageBuffer,
+ ImageSize,
+ &ImageHandle
+ );
+ DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ FreePool(DriverDevicePath);
+ return Status;
+ }
+
+ DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
+ Status = gBS->StartImage(
+ ImageHandle,
+ &ExitDataSize,
+ NULL
+ );
+ DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ }
+
+ FreePool(DriverDevicePath);
+ return Status;
+}
+
+/**
+ Record FMP capsule status.
+
+ @param[in] Handle A FMP handle.
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] CapFileName Capsule file name
+**/
+VOID
+RecordFmpCapsuleStatus (
+ IN EFI_HANDLE Handle, OPTIONAL
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
+ UINT32 FmpImageInfoDescriptorVer;
+ EFI_STATUS StatusEsrt;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
+
+ FmpDevicePath = NULL;
+ if (Handle != NULL) {
+ gBS->HandleProtocol(
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&FmpDevicePath
+ );
+ }
+
+ RecordFmpCapsuleStatusVariable (
+ CapsuleHeader,
+ CapsuleStatus,
+ PayloadIndex,
+ ImageHeader,
+ FmpDevicePath,
+ CapFileName
+ );
+
+ //
+ // Update corresponding ESRT entry LastAttemp Status
+ //
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (Handle == NULL) {
+ return ;
+ }
+
+ //
+ // Update EsrtEntry For V1, V2 FMP instance.
+ // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
+ //
+ FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
+ StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);
+ if (!EFI_ERROR(StatusEsrt)){
+ if (!EFI_ERROR(CapsuleStatus)) {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+ } else {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+ }
+ EsrtEntry.LastAttemptVersion = 0;
+ EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);
+ }
+ }
+}
+
+/**
+ Process Firmware management protocol data capsule.
+
+ This function assumes the caller validated the capsule by using
+ ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
+
+ This function need support nested FMP capsule.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapFileName Capsule file name.
+ @param[out] ResetRequired Indicates whether reset is required or not.
+
+ @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.
+ @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName, OPTIONAL
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN *ResetRequiredBuffer;
+ UINTN NumberOfHandles;
+ UINTN DriverLen;
+ UINT64 UpdateHardwareInstance;
+ UINTN Index2;
+ BOOLEAN NotReady;
+ BOOLEAN Abort;
+
+ if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+ return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
+ }
+
+ NotReady = FALSE;
+ Abort = FALSE;
+
+ DumpFmpCapsule(CapsuleHeader);
+
+ 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. Try to load & start all the drivers within capsule
+ //
+ 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 = StartFmpImage (
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
+ DriverLen
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // 2. Route payload to right FMP instance
+ //
+ DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
+
+ DumpAllFmpInfo ();
+
+ //
+ // 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]);
+
+ UpdateHardwareInstance = 0;
+ ///
+ /// UpdateHardwareInstance field was added in Version 2
+ ///
+ if (ImageHeader->Version >= 2) {
+ UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
+ }
+
+ Status = GetFmpHandleBufferByType (
+ &ImageHeader->UpdateImageTypeId,
+ UpdateHardwareInstance,
+ &NumberOfHandles,
+ &HandleBuffer,
+ &ResetRequiredBuffer
+ );
+ if (EFI_ERROR(Status) ||
+ (HandleBuffer == NULL) ||
+ (ResetRequiredBuffer == NULL)) {
+ NotReady = TRUE;
+ RecordFmpCapsuleStatus (
+ NULL,
+ CapsuleHeader,
+ EFI_NOT_READY,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
+ if (Abort) {
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ EFI_ABORTED,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ Status = SetFmpImageData (
+ HandleBuffer[Index2],
+ ImageHeader,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount
+ );
+ if (Status != EFI_SUCCESS) {
+ Abort = TRUE;
+ } else {
+ if (ResetRequired != NULL) {
+ *ResetRequired |= ResetRequiredBuffer[Index2];
+ }
+ }
+
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ Status,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ }
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+ if (ResetRequiredBuffer != NULL) {
+ FreePool(ResetRequiredBuffer);
+ }
+ }
+
+ if (NotReady) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // always return SUCCESS to indicate this capsule is processed.
+ // The status of SetImage is recorded in capsule result variable.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if there is a FMP header below capsule header.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE There is a FMP header below capsule header.
+ @retval FALSE There is not a FMP header below capsule header
+**/
+BOOLEAN
+IsNestedFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
+ UINTN Index;
+ BOOLEAN EsrtGuidFound;
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;
+ UINTN NestedCapsuleSize;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY Entry;
+
+ EsrtGuidFound = FALSE;
+ if (mIsVirtualAddrConverted) {
+ if(mEsrtTable != NULL) {
+ EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
+ for (Index = 0; Index < mEsrtTable->FwResourceCount ; Index++, EsrtEntry++) {
+ if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
+ EsrtGuidFound = TRUE;
+ break;
+ }
+ }
+ }
+ } else {
+ //
+ // Check ESRT protocol
+ //
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (!EFI_ERROR(Status)) {
+ Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);
+ if (!EFI_ERROR(Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+
+ //
+ // Check Firmware Management Protocols
+ //
+ if (!EsrtGuidFound) {
+ Status = GetFmpHandleBufferByType (
+ &CapsuleHeader->CapsuleGuid,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR(Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+ }
+ if (!EsrtGuidFound) {
+ return FALSE;
+ }
+
+ //
+ // Check nested capsule header
+ // FMP GUID after ESRT one
+ //
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
+ if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {
+ return FALSE;
+ }
+ if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {
+ return FALSE;
+ }
+ if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {
+ return FALSE;
+ }
+ DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
+ return TRUE;
+}
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a system FMP.
+ @retval FALSE It is a device FMP.
+**/
+BOOLEAN
+IsFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+ return TRUE;
+ }
+ if (IsNestedFmpCapsule(CapsuleHeader)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] 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
+ )
+{
+ //
+ // check Display Capsule Guid
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check capsule file name capsule
+ //
+ if (IsCapsuleNameCapsule(CapsuleHeader)) {
+ return EFI_SUCCESS;
+ }
+
+ if (IsFmpCapsule(CapsuleHeader)) {
+ //
+ // Fake capsule header is valid case in QueryCapsuleCpapbilities().
+ //
+ if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Check layout of FMP capsule
+ //
+ return ValidateFmpCapsule(CapsuleHeader, NULL);
+ }
+ DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapFileName Capsule file name.
+ @param[out] ResetRequired Indicates whether reset is required or not.
+
+ @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
+ProcessThisCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName, OPTIONAL
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+ RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Display image in firmware update display capsule
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
+ Status = DisplayCapsuleImage(CapsuleHeader);
+ RecordCapsuleStatusVariable(CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Check FMP capsule layout
+ //
+ if (IsFmpCapsule (CapsuleHeader)) {
+ DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
+ Status = ValidateFmpCapsule(CapsuleHeader, NULL);
+ DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ RecordCapsuleStatusVariable(CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Process EFI FMP Capsule
+ //
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
+ Status = ProcessFmpCapsuleImage(CapsuleHeader, CapFileName, ResetRequired);
+ DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] 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
+ )
+{
+ return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mDxeCapsuleLibEndOfDxe = TRUE;
+}
+
+/**
+ The constructor 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 constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DxeCapsuleLibEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &mDxeCapsuleLibEndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitCapsuleVariable();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the End of DXE event.
+
+ @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.
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the End of DXE event.
+ //
+ Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
new file mode 100644
index 000000000..05de4299f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
@@ -0,0 +1,98 @@
+## @file
+# Capsule library instance for DXE_DRIVER.
+#
+# Capsule library instance for DXE_DRIVER module types.
+#
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCapsuleLib
+ MODULE_UNI_FILE = DxeCapsuleLib.uni
+ FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = DxeCapsuleLibConstructor
+ DESTRUCTOR = DxeCapsuleLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCapsuleLib.c
+ DxeCapsuleProcessLib.c
+ DxeCapsuleReportLib.c
+ CapsuleOnDisk.c
+ CapsuleOnDisk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ PrintLib
+ HobLib
+ BmpSupportLib
+ DisplayUpdateProgressLib
+ FileHandleLib
+ UefiBootManagerLib
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName ## CONSUMES
+
+[Protocols]
+ gEsrtManagementProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiDiskIoProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
+ gEfiCapsuleReportGuid
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CodRelocationInfo"
+ ## SOMETIMES_CONSUMES ## Variable:L"OsIndications"
+ ## SOMETIMES_PRODUCES ## Variable:L"OsIndications"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootNext"
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext"
+ gEfiGlobalVariableGuid
+ gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
new file mode 100644
index 000000000..03c61c55c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Capsule library instance for DXE_DRIVER.
+//
+// Capsule library instance for DXE_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_DRIVER module types."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
new file mode 100644
index 000000000..f2cd0ad3e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -0,0 +1,691 @@
+/** @file
+ DXE capsule process.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ ProcessCapsules(), ProcessTheseCapsules() will receive untrusted
+ input and do basic validation.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagementProgress.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DisplayUpdateProgressLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+extern EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress;
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a system FMP.
+ @retval FALSE It is a device FMP.
+**/
+BOOLEAN
+IsFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ Validate Fmp capsules layout.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller validated the capsule by using
+ IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
+ The capsule buffer size is CapsuleHeader->CapsuleImageSize.
+
+ This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
+
+ This function need support nested FMP capsule.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
+
+ @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,
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL
+ );
+
+/**
+ Validate if it is valid capsule header
+
+ This function assumes the caller provided correct CapsuleHeader pointer
+ and CapsuleSize.
+
+ This function validates the fields in EFI_CAPSULE_HEADER.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapsuleSize Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN UINT64 CapsuleSize
+ );
+
+/**
+ Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a capsule name capsule.
+ @retval FALSE It is not a capsule name capsule.
+**/
+BOOLEAN
+IsCapsuleNameCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ Check the integrity of the capsule name capsule.
+ If the capsule is vaild, return the physical address of each capsule name string.
+
+ @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.
+ @param[out] CapsuleNameNum Number of capsule name.
+
+ @retval NULL Capsule name capsule is not valid.
+ @retval CapsuleNameBuf Array of capsule name physical address.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+ValidateCapsuleNameCapsuleIntegrity (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ OUT UINTN *CapsuleNameNum
+ );
+
+extern BOOLEAN mDxeCapsuleLibEndOfDxe;
+BOOLEAN mNeedReset = FALSE;
+
+VOID **mCapsulePtr;
+CHAR16 **mCapsuleNamePtr;
+EFI_STATUS *mCapsuleStatusArray;
+UINT32 mCapsuleTotalNumber;
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapFileName Capsule file name.
+ @param[out] ResetRequired Indicates whether reset is required or not.
+
+ @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
+ProcessThisCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName, OPTIONAL
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ );
+
+/**
+ Function indicate the current completion progress of the firmware
+ update. Platform may override with own specific progress function.
+
+ @param[in] Completion A value between 1 and 100 indicating the current
+ completion progress of the firmware update
+
+ @retval EFI_SUCESS The capsule update progress was updated.
+ @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
+**/
+EFI_STATUS
+EFIAPI
+UpdateImageProgress (
+ IN UINTN Completion
+ )
+{
+ EFI_STATUS Status;
+ UINTN Seconds;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color;
+
+ DEBUG((DEBUG_INFO, "Update Progress - %d%%\n", Completion));
+
+ if (Completion > 100) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Use a default timeout of 5 minutes if there is not FMP Progress Protocol.
+ //
+ Seconds = 5 * 60;
+ Color = NULL;
+ if (mFmpProgress != NULL) {
+ Seconds = mFmpProgress->WatchdogSeconds;
+ Color = &mFmpProgress->ProgressBarForegroundColor;
+ }
+
+ //
+ // Cancel the watchdog timer
+ //
+ gBS->SetWatchdogTimer (0, 0x0000, 0, NULL);
+
+ if (Completion != 100) {
+ //
+ // Arm the watchdog timer from PCD setting
+ //
+ if (Seconds != 0) {
+ DEBUG ((DEBUG_VERBOSE, "Arm watchdog timer %d seconds\n", Seconds));
+ gBS->SetWatchdogTimer (Seconds, 0x0000, 0, NULL);
+ }
+ }
+
+ Status = DisplayUpdateProgress (Completion, Color);
+
+ return Status;
+}
+
+/**
+ This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber.
+**/
+VOID
+InitCapsulePtr (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS HobPointer;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Index3;
+ UINTN CapsuleNameNumber;
+ UINTN CapsuleNameTotalNumber;
+ UINTN CapsuleNameCapsuleTotalNumber;
+ VOID **CapsuleNameCapsulePtr;
+ EFI_PHYSICAL_ADDRESS *CapsuleNameAddress;
+
+ CapsuleNameNumber = 0;
+ CapsuleNameTotalNumber = 0;
+ CapsuleNameCapsuleTotalNumber = 0;
+ CapsuleNameCapsulePtr = NULL;
+
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
+ if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {
+ HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid
+ } else {
+ if (IsCapsuleNameCapsule((VOID *)(UINTN)HobPointer.Capsule->BaseAddress)) {
+ CapsuleNameCapsuleTotalNumber++;
+ } else {
+ mCapsuleTotalNumber++;
+ }
+ }
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));
+
+ if (mCapsuleTotalNumber == 0) {
+ return ;
+ }
+
+ //
+ // Init temp Capsule Data table.
+ //
+ mCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);
+ if (mCapsulePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));
+ mCapsuleTotalNumber = 0;
+ return ;
+ }
+ mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);
+ if (mCapsuleStatusArray == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));
+ FreePool (mCapsulePtr);
+ mCapsulePtr = NULL;
+ mCapsuleTotalNumber = 0;
+ return ;
+ }
+ SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);
+
+ CapsuleNameCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleNameCapsuleTotalNumber);
+ if (CapsuleNameCapsulePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate CapsuleNameCapsulePtr fail!\n"));
+ FreePool (mCapsulePtr);
+ FreePool (mCapsuleStatusArray);
+ mCapsulePtr = NULL;
+ mCapsuleStatusArray = NULL;
+ mCapsuleTotalNumber = 0;
+ return ;
+ }
+
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ Index = 0;
+ Index2 = 0;
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
+ if (IsCapsuleNameCapsule ((VOID *) (UINTN) HobPointer.Capsule->BaseAddress)) {
+ CapsuleNameCapsulePtr [Index2++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
+ } else {
+ mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
+ }
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ //
+ // Find Capsule On Disk Names
+ //
+ for (Index = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {
+ CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
+ if (CapsuleNameAddress != NULL ) {
+ CapsuleNameTotalNumber += CapsuleNameNumber;
+ }
+ }
+
+ if (CapsuleNameTotalNumber == mCapsuleTotalNumber) {
+ mCapsuleNamePtr = (CHAR16 **) AllocateZeroPool (sizeof (CHAR16 *) * mCapsuleTotalNumber);
+ if (mCapsuleNamePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate mCapsuleNamePtr fail!\n"));
+ FreePool (mCapsulePtr);
+ FreePool (mCapsuleStatusArray);
+ FreePool (CapsuleNameCapsulePtr);
+ mCapsulePtr = NULL;
+ mCapsuleStatusArray = NULL;
+ mCapsuleTotalNumber = 0;
+ return ;
+ }
+
+ for (Index = 0, Index3 = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {
+ CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
+ if (CapsuleNameAddress != NULL ) {
+ for (Index2 = 0; Index2 < CapsuleNameNumber; Index2 ++) {
+ mCapsuleNamePtr[Index3 ++] = (CHAR16 *)(UINTN) CapsuleNameAddress[Index2];
+ }
+ }
+ }
+ } else {
+ mCapsuleNamePtr = NULL;
+ }
+
+ FreePool (CapsuleNameCapsulePtr);
+}
+
+/**
+ This function returns if all capsule images are processed.
+
+ @retval TRUE All capsule images are processed.
+ @retval FALSE Not all capsule images are processed.
+**/
+BOOLEAN
+AreAllImagesProcessed (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
+ if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ This function populates capsule in the configuration table.
+**/
+VOID
+PopulateCapsuleInConfigurationTable (
+ VOID
+ )
+{
+ VOID **CapsulePtrCache;
+ EFI_GUID *CapsuleGuidCache;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ EFI_CAPSULE_TABLE *CapsuleTable;
+ UINT32 CacheIndex;
+ UINT32 CacheNumber;
+ UINT32 CapsuleNumber;
+ UINTN Index;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ if (mCapsuleTotalNumber == 0) {
+ return ;
+ }
+
+ CapsulePtrCache = NULL;
+ CapsuleGuidCache = NULL;
+ CacheIndex = 0;
+ CacheNumber = 0;
+
+ CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);
+ if (CapsulePtrCache == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));
+ return ;
+ }
+ CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);
+ if (CapsuleGuidCache == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));
+ FreePool (CapsulePtrCache);
+ return ;
+ }
+
+ //
+ // 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 < mCapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [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.
+ //
+ for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {
+ CapsuleNumber = 0;
+ for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [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);
+ if (CapsuleTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));
+ continue;
+ }
+ CapsuleTable->CapsuleArrayNumber = CapsuleNumber;
+ CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
+ Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));
+ }
+ }
+ }
+
+ FreePool(CapsuleGuidCache);
+ FreePool(CapsulePtrCache);
+}
+
+/**
+
+ This routine is called to process capsules.
+
+ Caution: This function may receive untrusted input.
+
+ Each individual capsule result is recorded in capsule record variable.
+
+ @param[in] FirstRound TRUE: First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.
+ FALSE: Process rest FMP capsules.
+
+ @retval EFI_SUCCESS There is no error when processing capsules.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
+
+**/
+EFI_STATUS
+ProcessTheseCapsules (
+ IN BOOLEAN FirstRound
+ )
+{
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT32 Index;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
+ UINT16 EmbeddedDriverCount;
+ BOOLEAN ResetRequired;
+ CHAR16 *CapsuleName;
+
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
+
+ if (FirstRound) {
+ InitCapsulePtr ();
+ }
+
+ if (mCapsuleTotalNumber == 0) {
+ //
+ // We didn't find a hob, so had no errors.
+ //
+ DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));
+ mNeedReset = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ if (AreAllImagesProcessed ()) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install
+ // capsuleTable to configure table with EFI_CAPSULE_GUID
+ //
+ if (FirstRound) {
+ PopulateCapsuleInConfigurationTable ();
+ }
+
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));
+
+ //
+ // If Windows UX capsule exist, process it first
+ //
+ for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
+ CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];
+ if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
+ DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));
+ DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));
+ Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, NULL);
+ mCapsuleStatusArray [Index] = EFI_SUCCESS;
+ DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - %r\n", Status));
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "Updating the firmware ......\n"));
+
+ //
+ // All capsules left are recognized by platform.
+ //
+ for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
+ if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {
+ // already processed
+ continue;
+ }
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
+ CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];
+ if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
+ //
+ // Call capsule library to process capsule image.
+ //
+ EmbeddedDriverCount = 0;
+ if (IsFmpCapsule(CapsuleHeader)) {
+ Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));
+ mCapsuleStatusArray [Index] = EFI_ABORTED;
+ continue;
+ }
+ } else {
+ mCapsuleStatusArray [Index] = EFI_ABORTED;
+ continue;
+ }
+
+ if ((!FirstRound) || (EmbeddedDriverCount == 0)) {
+ DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - 0x%x\n", CapsuleHeader));
+ ResetRequired = FALSE;
+ Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, &ResetRequired);
+ mCapsuleStatusArray [Index] = Status;
+ DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - %r\n", Status));
+
+ if (Status != EFI_NOT_READY) {
+ if (EFI_ERROR(Status)) {
+ REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));
+ DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));
+ } else {
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));
+ }
+
+ mNeedReset |= ResetRequired;
+ if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0) {
+ mNeedReset = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
+ //
+ // Always sync ESRT Cache from FMP Instance
+ //
+ if (!EFI_ERROR(Status)) {
+ EsrtManagement->SyncEsrtFmp();
+ }
+ Status = EFI_SUCCESS;
+
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
+
+ return Status;
+}
+
+/**
+ Do reset system.
+**/
+VOID
+DoResetSystem (
+ VOID
+ )
+{
+ DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));
+
+ REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeResettingSystem)));
+
+ gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ CpuDeadLoop();
+}
+
+/**
+
+ This routine is called to process capsules.
+
+ Caution: This function may receive untrusted input.
+
+ The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+ If there is no EFI_HOB_UEFI_CAPSULE, it means error occurs, force reset to
+ normal boot path.
+
+ This routine should be called twice in BDS.
+ 1) The first call must be before EndOfDxe. The system capsules is processed.
+ If device capsule FMP protocols are exposted at this time and device FMP
+ capsule has zero EmbeddedDriverCount, the device capsules are processed.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule and
+ all capsules are processed.
+ If not all capsules are processed, reset will be defered to second call.
+
+ 2) The second call must be after EndOfDxe and after ConnectAll, so that all
+ device capsule FMP protocols are exposed.
+ The system capsules are skipped. If the device capsules are NOT processed
+ in first call, they are processed here.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule
+ processed in first call and second call.
+
+ @retval EFI_SUCCESS There is no error when processing capsules.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (!mDxeCapsuleLibEndOfDxe) {
+ Status = ProcessTheseCapsules(TRUE);
+
+ //
+ // Reboot System if and only if all capsule processed.
+ // If not, defer reset to 2nd process.
+ //
+ if (mNeedReset && AreAllImagesProcessed()) {
+ DoResetSystem();
+ }
+ } else {
+ Status = ProcessTheseCapsules(FALSE);
+ //
+ // Reboot System if required after all capsule processed
+ //
+ if (mNeedReset) {
+ DoResetSystem();
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
new file mode 100644
index 000000000..9054ae446
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
@@ -0,0 +1,70 @@
+/** @file
+ DXE capsule process.
+ Dummy function for runtime module, because CapsuleDxeRuntime
+ does not need call ProcessCapsules().
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ Function indicate the current completion progress of the firmware
+ update. Platform may override with own specific progress function.
+
+ @param[in] Completion A value between 1 and 100 indicating the current
+ completion progress of the firmware update
+
+ @retval EFI_SUCESS The capsule update progress was updated.
+ @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
+**/
+EFI_STATUS
+EFIAPI
+UpdateImageProgress (
+ IN UINTN Completion
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This routine is called to process capsules.
+
+ Caution: This function may receive untrusted input.
+
+ The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+ If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
+
+ This routine should be called twice in BDS.
+ 1) The first call must be before EndOfDxe. The system capsules is processed.
+ If device capsule FMP protocols are exposted at this time and device FMP
+ capsule has zero EmbeddedDriverCount, the device capsules are processed.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule and
+ all capsules are processed.
+ If not all capsules are processed, reset will be defered to second call.
+
+ 2) The second call must be after EndOfDxe and after ConnectAll, so that all
+ device capsule FMP protocols are exposed.
+ The system capsules are skipped. If the device capsules are NOT processed
+ in first call, they are processed here.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule
+ processed in first call and second call.
+
+ @retval EFI_SUCCESS There is no error when processing capsules.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
new file mode 100644
index 000000000..0ec5f2067
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -0,0 +1,473 @@
+/** @file
+ DXE capsule report related function.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/VariableLock.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CapsuleLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+/**
+ This routine is called to clear CapsuleOnDisk Relocation Info variable.
+ Total Capsule On Disk length is recorded in this variable
+
+ @retval EFI_SUCCESS Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+CoDClearCapsuleRelocationInfo(
+ VOID
+ );
+
+/**
+ Get current capsule last variable index.
+
+ @return Current capsule last variable index.
+ @retval -1 No current capsule last variable.
+**/
+INTN
+GetCurrentCapsuleLastIndex (
+ VOID
+ )
+{
+ UINTN Size;
+ CHAR16 CapsuleLastStr[sizeof("Capsule####")];
+ EFI_STATUS Status;
+ UINT16 CurrentIndex;
+
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+ Status = gRT->GetVariable(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ NULL,
+ &Size,
+ CapsuleLastStr
+ );
+ if (EFI_ERROR(Status)) {
+ return -1;
+ }
+ CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);
+ return CurrentIndex;
+}
+
+/**
+ Get a new capsule status variable index.
+
+ @return A new capsule status variable index.
+ @retval 0 No new capsule status variable index. Rolling over.
+**/
+INTN
+GetNewCapsuleResultIndex (
+ VOID
+ )
+{
+ INTN CurrentIndex;
+
+ CurrentIndex = GetCurrentCapsuleLastIndex();
+ if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {
+ DEBUG((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));
+ return 0;
+ }
+
+ return CurrentIndex + 1;
+}
+
+/**
+ Write a new capsule status variable.
+
+ @param[in] CapsuleResult The capsule status variable
+ @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+WriteNewCapsuleResultVariable (
+ IN VOID *CapsuleResult,
+ IN UINTN CapsuleResultSize
+ )
+{
+ INTN CapsuleResultIndex;
+ CHAR16 CapsuleResultStr[sizeof("Capsule####")];
+ UINTN Size;
+ EFI_STATUS Status;
+
+ CapsuleResultIndex = GetNewCapsuleResultIndex();
+ DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));
+
+ UnicodeSPrint(
+ CapsuleResultStr,
+ sizeof(CapsuleResultStr),
+ L"Capsule%04x",
+ CapsuleResultIndex
+ );
+
+ Status = gRT->SetVariable(
+ CapsuleResultStr,
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ CapsuleResultSize,
+ CapsuleResult
+ );
+ if (!EFI_ERROR(Status)) {
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+ DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));
+ Status = gRT->SetVariable(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ CapsuleResultStr
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Record capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ )
+{
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;
+ EFI_STATUS Status;
+
+ CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);
+ CapsuleResultVariable.Reserved = 0;
+ CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+ ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));
+ gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);
+ CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
+
+ Status = EFI_SUCCESS;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
+ }
+ return Status;
+}
+
+/**
+ Record FMP capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
+ EFI_STATUS Status;
+ UINT8 *CapsuleResultVariable;
+ UINTN CapsuleResultVariableSize;
+ CHAR16 *DevicePathStr;
+ UINTN DevicePathStrSize;
+ UINTN CapFileNameSize;
+
+ DevicePathStr = NULL;
+ CapFileNameSize = sizeof(CHAR16);
+
+ if (FmpDevicePath != NULL) {
+ DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);
+ }
+ if (DevicePathStr != NULL) {
+ DevicePathStrSize = StrSize(DevicePathStr);
+ } else {
+ DevicePathStrSize = sizeof(CHAR16);
+ }
+
+ if (CapFileName != NULL) {
+ CapFileNameSize = StrSize(CapFileName);
+ }
+
+ //
+ // Allocate room for CapsuleFileName.
+ //
+ CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;
+
+ CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);
+ if (CapsuleResultVariable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;
+ CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;
+ CapsuleResultVariableHeader->Reserved = 0;
+ CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+ ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));
+ gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
+ CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
+
+ CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));
+ CapsuleResultVariableFmp->Version = 0x1;
+ CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
+ CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
+ CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
+
+ if (CapFileName != NULL) {
+ CopyMem((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);
+ }
+
+ if (DevicePathStr != NULL) {
+ CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);
+ FreePool (DevicePathStr);
+ DevicePathStr = NULL;
+ }
+
+ Status = EFI_SUCCESS;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);
+ }
+ FreePool (CapsuleResultVariable);
+ return Status;
+}
+
+/**
+ Initialize CapsuleMax variables.
+**/
+VOID
+InitCapsuleMaxVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ CHAR16 CapsuleMaxStr[sizeof("Capsule####")];
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+
+ UnicodeSPrint(
+ CapsuleMaxStr,
+ sizeof(CapsuleMaxStr),
+ L"Capsule%04x",
+ PcdGet16(PcdCapsuleMax)
+ );
+
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+ Status = gRT->SetVariable(
+ L"CapsuleMax",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ CapsuleMaxStr
+ );
+ if (!EFI_ERROR(Status)) {
+ // Lock it per UEFI spec.
+ Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
+ if (!EFI_ERROR(Status)) {
+ Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);
+ ASSERT_EFI_ERROR(Status);
+ }
+ }
+}
+
+/**
+ Initialize CapsuleLast variables.
+**/
+VOID
+InitCapsuleLastVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ VOID *CapsuleResult;
+ UINTN Size;
+ CHAR16 CapsuleLastStr[sizeof("Capsule####")];
+
+ BootMode = GetBootModeHob();
+ if (BootMode == BOOT_ON_FLASH_UPDATE) {
+ Status = gRT->SetVariable(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+ // Do not lock it because it will be updated later.
+ } else {
+ //
+ // Check if OS/APP cleared L"Capsule####"
+ //
+ ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));
+ Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+ Status = gRT->GetVariable(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ NULL,
+ &Size,
+ CapsuleLastStr
+ );
+ if (!EFI_ERROR(Status)) {
+ //
+ // L"CapsuleLast" is got, check if data is there.
+ //
+ Status = GetVariable2 (
+ CapsuleLastStr,
+ &gEfiCapsuleReportGuid,
+ (VOID **) &CapsuleResult,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // If no data, delete L"CapsuleLast"
+ //
+ Status = gRT->SetVariable(
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+ } else {
+ if (CapsuleResult != NULL) {
+ FreePool (CapsuleResult);
+ }
+ }
+ }
+
+ // Lock it in normal boot path per UEFI spec.
+ Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
+ if (!EFI_ERROR(Status)) {
+ Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);
+ ASSERT_EFI_ERROR(Status);
+ }
+ }
+}
+
+/**
+ Initialize capsule update variables.
+**/
+VOID
+InitCapsuleUpdateVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+
+ //
+ // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+ // as early as possible which will avoid the next time boot after the capsule update
+ // will still into the capsule loop
+ //
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ Index = 0;
+ while (TRUE) {
+ if (Index > 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
+ 0,
+ Index,
+ 0
+ );
+ }
+ Status = gRT->SetVariable (
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ (VOID *)NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no capsule variables, quit
+ //
+ break;
+ }
+ Index++;
+ }
+}
+
+/**
+ Initialize capsule relocation info variable.
+**/
+VOID
+InitCapsuleRelocationInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+
+ CoDClearCapsuleRelocationInfo();
+
+ //
+ // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
+ //
+ if (!CoDCheckCapsuleOnDiskFlag()) {
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLock->RequestToLock (VariableLock, COD_RELOCATION_INFO_VAR_NAME, &gEfiCapsuleVendorGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ )
+{
+ InitCapsuleUpdateVariable();
+ InitCapsuleMaxVariable();
+ InitCapsuleLastVariable();
+ InitCapsuleRelocationInfo();
+
+ //
+ // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
+ // to check status and delete them.
+ //
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
new file mode 100644
index 000000000..b09631830
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
@@ -0,0 +1,69 @@
+/** @file
+ DXE capsule report related function.
+ Dummy function for runtime module, because CapsuleDxeRuntime
+ does not need record capsule status variable.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/FmpCapsule.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ Record capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Record FMP capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ )
+{
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
new file mode 100644
index 000000000..f94044a40
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
@@ -0,0 +1,174 @@
+/** @file
+ Capsule library runtime support.
+
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;
+extern BOOLEAN mIsVirtualAddrConverted;
+EFI_EVENT mDxeRuntimeCapsuleLibVirtualAddressChangeEvent = NULL;
+EFI_EVENT mDxeRuntimeCapsuleLibReadyToBootEvent = NULL;
+
+/**
+ Convert EsrtTable physical address to virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gRT->ConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mEsrtTable);
+ mIsVirtualAddrConverted = TRUE;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+STATIC
+VOID
+EFIAPI
+DxeCapsuleLibReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *ConfigEntry;
+ EFI_SYSTEM_RESOURCE_TABLE *EsrtTable;
+
+ //
+ // Get Esrt table first
+ //
+ ConfigEntry = gST->ConfigurationTable;
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {
+ break;
+ }
+ ConfigEntry++;
+ }
+
+ //
+ // If no Esrt table installed in Configure Table
+ //
+ if (Index < gST->NumberOfTableEntries) {
+ //
+ // Search Esrt to check given capsule is qualified
+ //
+ EsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable;
+
+ mEsrtTable = AllocateRuntimeCopyPool (
+ sizeof (EFI_SYSTEM_RESOURCE_TABLE) +
+ EsrtTable->FwResourceCount * sizeof (EFI_SYSTEM_RESOURCE_ENTRY),
+ EsrtTable);
+ ASSERT (mEsrtTable != NULL);
+
+ //
+ // Set FwResourceCountMax to a sane value.
+ //
+ mEsrtTable->FwResourceCountMax = mEsrtTable->FwResourceCount;
+ }
+}
+
+/**
+ The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.
+
+ @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 .
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeCapsuleLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure we can handle virtual address changes.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DxeCapsuleLibVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mDxeRuntimeCapsuleLibVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function to cache the FMP capsule GUIDs at ReadyToBoot.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DxeCapsuleLibReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mDxeRuntimeCapsuleLibReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the VirtualAddressChange event.
+
+ @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.
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeCapsuleLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the VirtualAddressChange event.
+ //
+ Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close the ReadyToBoot event.
+ //
+ Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibReadyToBootEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
new file mode 100644
index 000000000..bf56f4623
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
@@ -0,0 +1,74 @@
+## @file
+# Capsule library instance for DXE_RUNTIME_DRIVER.
+#
+# Capsule library instance for DXE_RUNTIME_DRIVER module types.
+#
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeRuntimeCapsuleLib
+ MODULE_UNI_FILE = DxeRuntimeCapsuleLib.uni
+ FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER
+ CONSTRUCTOR = DxeCapsuleLibConstructor
+ CONSTRUCTOR = DxeRuntimeCapsuleLibConstructor
+ DESTRUCTOR = DxeCapsuleLibDestructor
+ DESTRUCTOR = DxeRuntimeCapsuleLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCapsuleLib.c
+ DxeCapsuleProcessLibNull.c
+ DxeCapsuleReportLibNull.c
+ DxeCapsuleRuntime.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ PrintLib
+ HobLib
+ BmpSupportLib
+
+
+[Protocols]
+ gEsrtManagementProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
+ gEfiCapsuleReportGuid
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
new file mode 100644
index 000000000..0e90cc3d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Capsule library instance for DXE_RUNTIME_DRIVER.
+//
+// Capsule library instance for DXE_RUNTIME_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
new file mode 100644
index 000000000..55985abd7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
@@ -0,0 +1,170 @@
+/** @file
+ Null Dxe Capsule Library instance does nothing and returns unsupport status.
+
+Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ The firmware checks whether the capsule image is supported
+ by the CapsuleGuid in CapsuleHeader or other specific information in capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param CapsuleHeader Point to the UEFI capsule image to be checked.
+
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware specific implementation processes the capsule image
+ if it recognized the format of this capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param CapsuleHeader Point to the UEFI capsule image to be processed.
+
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ This routine is called to process capsules.
+
+ Caution: This function may receive untrusted input.
+
+ The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+ If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
+
+ This routine should be called twice in BDS.
+ 1) The first call must be before EndOfDxe. The system capsules is processed.
+ If device capsule FMP protocols are exposted at this time and device FMP
+ capsule has zero EmbeddedDriverCount, the device capsules are processed.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule and
+ all capsules are processed.
+ If not all capsules are processed, reset will be defered to second call.
+
+ 2) The second call must be after EndOfDxe and after ConnectAll, so that all
+ device capsule FMP protocols are exposed.
+ The system capsules are skipped. If the device capsules are NOT processed
+ in first call, they are processed here.
+ Each individual capsule result is recorded in capsule record variable.
+ System may reset in this function, if reset is required by capsule
+ processed in first call and second call.
+
+ @retval EFI_SUCCESS There is no error when processing capsules.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
+ is enabled.
+
+ @retval TRUE Flag is enabled
+ @retval FALSE Flag is not enabled
+
+**/
+BOOLEAN
+EFIAPI
+CoDCheckCapsuleOnDiskFlag(
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
+
+ @retval EFI_SUCCESS All Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+EFIAPI
+CoDClearCapsuleOnDiskFlag(
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Relocate Capsule on Disk from EFI system partition.
+
+ Two solution to deliver Capsule On Disk:
+ Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
+ Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
+ device with BlockIo protocol.
+
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
+ Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
+ systems of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRelocateCapsule(
+ UINTN MaxRetry
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Remove the temp file from the root of EFI System Partition.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Remove the temp file successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRemoveTempFile (
+ UINTN MaxRetry
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
new file mode 100644
index 000000000..067a5b2aa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# NULL Dxe Capsule library instance.
+# It can make core modules pass package level build.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCapsuleLibNull
+ MODULE_UNI_FILE = DxeCapsuleLibNull.uni
+ FILE_GUID = 4004de5a-09a5-4f0c-94d7-82322e096aa7
+ 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 EBC
+#
+
+[Sources]
+ DxeCapsuleLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni
new file mode 100644
index 000000000..61d689263
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL Dxe Capsule library instance.
+//
+// It can make core modules pass package level build.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL DXE Capsule library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It can make core modules pass package level build."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
new file mode 100644
index 000000000..199da4ba6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Memory Allocation Library instance dedicated to DXE Core.
+# The implementation borrows the DxeCore Memory Allocation services as the primitive
+# for memory allocation instead of using UEFI boot services in an indirect way.
+# It is assumed that this library instance must be linked with DxeCore in this package.
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCoreMemoryAllocationLib
+ MODULE_UNI_FILE = DxeCoreMemoryAllocationLib.uni
+ FILE_GUID = 632F3FAC-1CA4-4725-BAA2-BDECCF9A111C
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib|DXE_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ DxeCoreMemoryAllocationServices.h
+ DxeCoreMemoryProfileLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni
new file mode 100644
index 000000000..15e782dd8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Memory Allocation Library instance dedicated to DXE Core.
+//
+// The implementation borrows the DxeCore Memory Allocation services as the primitive
+// for memory allocation instead of using UEFI boot services in an indirect way.
+// It is assumed that this library instance must be linked with DxeCore in this package.
+//
+// Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation Library instance dedicated to DXE Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the DxeCore Memory Allocation services as the primitive for memory allocation instead of using UEFI boot services in an indirect way. It is assumed that this library instance must be linked with DxeCore in this package."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.inf
new file mode 100644
index 000000000..987e1cd9c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.inf
@@ -0,0 +1,43 @@
+## @file
+# Memory Allocation/Profile Library instance dedicated to DXE Core.
+# The implementation borrows the DxeCore Memory Allocation/profile services as the primitive
+# for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way.
+# It is assumed that this library instance must be linked with DxeCore in this package.
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCoreMemoryAllocationProfileLib
+ MODULE_UNI_FILE = DxeCoreMemoryAllocationProfileLib.uni
+ FILE_GUID = 7ADD7147-74E8-4583-BE34-B6BC45353BB5
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib|DXE_CORE
+ LIBRARY_CLASS = MemoryProfileLib|DXE_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ DxeCoreMemoryAllocationServices.h
+ DxeCoreMemoryProfileLib.c
+ DxeCoreMemoryProfileServices.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.uni
new file mode 100644
index 000000000..089cfb33c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Memory Allocation/Profile Library instance dedicated to DXE Core.
+//
+// The implementation borrows the DxeCore Memory Allocation/Profile services as the primitive
+// for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way.
+// It is assumed that this library instance must be linked with DxeCore in this package.
+//
+// Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation/Profile Library instance dedicated to DXE Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the DxeCore Memory Allocation/Profile services as the primitive for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way. It is assumed that this library instance must be linked with DxeCore in this package."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h
new file mode 100644
index 000000000..73b3569b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h
@@ -0,0 +1,100 @@
+/** @file
+ Contains function prototypes for Memory Services in DxeCore.
+
+ This header file borrows the DxeCore Memory Allocation services as the primitive
+ for memory allocation.
+
+ Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
+#define _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
+
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLib.c b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLib.c
new file mode 100644
index 000000000..3ef31562c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLib.c
@@ -0,0 +1,51 @@
+/** @file
+ Support routines for memory profile for DxeCore.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/MemoryProfile.h>
+
+#include "DxeCoreMemoryProfileServices.h"
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLibNull.c b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLibNull.c
new file mode 100644
index 000000000..42d4bd26f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileLibNull.c
@@ -0,0 +1,49 @@
+/** @file
+ Null routines for memory profile for DxeCore.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/MemoryProfile.h>
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileServices.h b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileServices.h
new file mode 100644
index 000000000..3edfbaea6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryProfileServices.h
@@ -0,0 +1,48 @@
+/** @file
+ Contains function prototypes for Memory Profile Services in DxeCore.
+
+ This header file borrows the DxeCore Memory Profile services as the primitive
+ for memory profile.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_CORE_MEMORY_PROFILE_SERVICES_H_
+#define _DXE_CORE_MEMORY_PROFILE_SERVICES_H_
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c
new file mode 100644
index 000000000..cecf2ddbe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c
@@ -0,0 +1,1054 @@
+/** @file
+ Support routines for memory allocation routines based
+ on DxeCore Memory Allocation services for DxeCore,
+ with memory profile support.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiDxe.h>
+
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "DxeCoreMemoryAllocationServices.h"
+
+#include <Library/MemoryProfileLib.h>
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiBootServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
+ EfiBootServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiReservedMemoryType, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,
+ EfiReservedMemoryType,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = CoreFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,
+ EfiBootServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES,
+ EfiReservedMemoryType,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = CoreFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = CoreAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiBootServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,
+ EfiBootServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiReservedMemoryType, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiBootServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,
+ EfiBootServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,
+ EfiBootServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiBootServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,
+ EfiBootServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiReservedMemoryType, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreFreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
new file mode 100644
index 000000000..d378c59dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
@@ -0,0 +1,1822 @@
+/** @file
+ Performance library instance mainly used by DxeCore.
+
+ This library provides the performance measurement interfaces and initializes performance
+ logging for DXE phase. It first initializes its private global data structure for
+ performance logging and saves the performance GUIDed HOB passed from PEI phase.
+ It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
+ which are consumed by DxePerformanceLib to logging performance data in DXE phase.
+
+ This library is mainly used by DxeCore to start performance logging to ensure that
+ Performance Protocol is installed at the very beginning of DXE phase.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeCorePerformanceLibInternal.h"
+
+//
+// Data for FPDT performance records.
+//
+#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
+#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
+#define FIRMWARE_RECORD_BUFFER 0x10000
+#define CACHE_HANDLE_GUID_COUNT 0x800
+
+BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;
+BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
+ sizeof (BOOT_PERFORMANCE_TABLE)
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
+ },
+ 0, // Reserved
+ //
+ // These values will be updated at runtime.
+ //
+ 0, // ResetEnd
+ 0, // OsLoaderLoadImageStart
+ 0, // OsLoaderStartImageStart
+ 0, // ExitBootServicesEntry
+ 0 // ExitBootServicesExit
+ }
+};
+
+typedef struct {
+ EFI_HANDLE Handle;
+ CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ EFI_GUID ModuleGuid;
+} HANDLE_GUID_MAP;
+
+HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
+UINTN mCachePairCount = 0;
+
+UINT32 mLoadImageCount = 0;
+UINT32 mPerformanceLength = 0;
+UINT32 mMaxPerformanceLength = 0;
+UINT32 mBootRecordSize = 0;
+UINT32 mBootRecordMaxSize = 0;
+UINT32 mCachedLength = 0;
+
+BOOLEAN mFpdtBufferIsReported = FALSE;
+BOOLEAN mLackSpaceIsReported = FALSE;
+CHAR8 *mPlatformLanguage = NULL;
+UINT8 *mPerformancePointer = NULL;
+UINT8 *mBootRecordBuffer = NULL;
+BOOLEAN mLockInsertRecord = FALSE;
+CHAR8 *mDevicePathString = NULL;
+
+EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText = NULL;
+
+//
+// Interfaces for PerformanceMeasurement Protocol.
+//
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
+ CreatePerformanceMeasurement,
+ };
+
+PERFORMANCE_PROPERTY mPerformanceProperty;
+
+/**
+ Return the pointer to the FPDT record in the allocated memory.
+
+ @param RecordSize The size of FPDT record.
+ @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
+
+ @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
+ @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+ IN UINT8 RecordSize,
+ IN OUT FPDT_RECORD_PTR *FpdtRecordPtr
+)
+{
+ if (mFpdtBufferIsReported) {
+ //
+ // Append Boot records to the boot performance table.
+ //
+ if (mBootRecordSize + RecordSize > mBootRecordMaxSize) {
+ if (!mLackSpaceIsReported) {
+ DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n"));
+ mLackSpaceIsReported = TRUE;
+ }
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Save boot record into BootPerformance table
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mBootRecordSize);
+ }
+ } else {
+ //
+ // Check if pre-allocated buffer is full
+ //
+ if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+ mPerformancePointer = ReallocatePool (
+ mPerformanceLength,
+ mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
+ mPerformancePointer
+ );
+ if (mPerformancePointer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
+ }
+ //
+ // Covert buffer to FPDT Ptr Union type.
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+Check whether the Token is a known one which is uesed by core.
+
+@param Token Pointer to a Null-terminated ASCII string
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownTokens (
+ IN CONST CHAR8 *Token
+ )
+{
+ if (Token == NULL) {
+ return FALSE;
+ }
+
+ if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
+ AsciiStrCmp (Token, PEI_TOK) == 0 ||
+ AsciiStrCmp (Token, DXE_TOK) == 0 ||
+ AsciiStrCmp (Token, BDS_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
+ AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, PEIM_TOK) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+Check whether the ID is a known one which map to the known Token.
+
+@param Identifier 32-bit identifier.
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownID (
+ IN UINT32 Identifier
+ )
+{
+ if (Identifier == MODULE_START_ID ||
+ Identifier == MODULE_END_ID ||
+ Identifier == MODULE_LOADIMAGE_START_ID ||
+ Identifier == MODULE_LOADIMAGE_END_ID ||
+ Identifier == MODULE_DB_START_ID ||
+ Identifier == MODULE_DB_END_ID ||
+ Identifier == MODULE_DB_SUPPORT_START_ID ||
+ Identifier == MODULE_DB_SUPPORT_END_ID ||
+ Identifier == MODULE_DB_STOP_START_ID ||
+ Identifier == MODULE_DB_STOP_END_ID) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Allocate buffer for Boot Performance table.
+
+ @return Status code.
+
+**/
+EFI_STATUS
+AllocateBootPerformanceTable (
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINT8 *SmmBootRecordCommBuffer;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
+ SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
+ UINTN CommSize;
+ UINTN BootPerformanceDataSize;
+ UINT8 *BootPerformanceData;
+ EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
+ EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
+ UINTN Index;
+ VOID *SmmBootRecordData;
+ UINTN SmmBootRecordDataSize;
+ UINTN ReservedMemSize;
+
+ //
+ // Collect boot records from SMM drivers.
+ //
+ SmmBootRecordCommBuffer = NULL;
+ SmmCommData = NULL;
+ SmmBootRecordData = NULL;
+ SmmBootRecordDataSize = 0;
+ ReservedMemSize = 0;
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Initialize communicate buffer
+ // Get the prepared Reserved Memory Range
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &SmmCommRegionTable
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (SmmCommRegionTable != NULL);
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
+ for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) {
+ if (SmmCommMemRegion->Type == EfiConventionalMemory) {
+ break;
+ }
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
+ ASSERT (SmmCommMemRegion->PhysicalStart > 0);
+ ASSERT (SmmCommMemRegion->NumberOfPages > 0);
+ ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE;
+
+ //
+ // Check enough reserved memory space
+ //
+ if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {
+ SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart;
+ SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;
+ ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));
+
+ CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
+ SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);
+ CommSize = SMM_BOOT_RECORD_COMM_SIZE;
+
+ //
+ // Get the size of boot records.
+ //
+ SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
+ SmmCommData->BootRecordData = NULL;
+ Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+
+ if (!EFI_ERROR (Status) && !EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {
+ //
+ // Get all boot records
+ //
+ SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET;
+ SmmBootRecordDataSize = SmmCommData->BootRecordSize;
+ SmmBootRecordData = AllocateZeroPool(SmmBootRecordDataSize);
+ ASSERT (SmmBootRecordData != NULL);
+ SmmCommData->BootRecordOffset = 0;
+ SmmCommData->BootRecordData = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
+ SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
+ while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) {
+ Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);
+ if (SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
+ CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmCommData->BootRecordOffset);
+ } else {
+ CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
+ }
+ SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Prepare memory for Boot Performance table.
+ // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
+ //
+ BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mPerformanceLength + PcdGet32 (PcdExtFpdtBootRecordPadSize);
+ if (SmmCommData != NULL && SmmBootRecordData != NULL) {
+ BootPerformanceDataSize += SmmBootRecordDataSize;
+ }
+
+ //
+ // Try to allocate the same runtime buffer as last time boot.
+ //
+ ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
+ Size = sizeof (PerformanceVariable);
+ Status = gRT->GetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &Size,
+ &PerformanceVariable
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
+ &PerformanceVariable.BootPerformanceTablePointer
+ );
+ if (!EFI_ERROR (Status)) {
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
+ }
+ }
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Fail to allocate at specified address, continue to allocate at any address.
+ //
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages (
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (BootPerformanceDataSize)
+ );
+ if (mAcpiBootPerformanceTable != NULL) {
+ ZeroMem (mAcpiBootPerformanceTable, BootPerformanceDataSize);
+ }
+ }
+ DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ if (SmmCommData != NULL && SmmBootRecordData != NULL) {
+ FreePool (SmmBootRecordData);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Prepare Boot Performance Table.
+ //
+ BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;
+ //
+ // Fill Basic Boot record to Boot Performance Table.
+ //
+ CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
+ BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;
+ //
+ // Fill Boot records from boot drivers.
+ //
+ if (mPerformancePointer != NULL) {
+ CopyMem (BootPerformanceData, mPerformancePointer, mPerformanceLength);
+ mAcpiBootPerformanceTable->Header.Length += mPerformanceLength;
+ BootPerformanceData = BootPerformanceData + mPerformanceLength;
+ FreePool (mPerformancePointer);
+ mPerformancePointer = NULL;
+ mPerformanceLength = 0;
+ mMaxPerformanceLength = 0;
+ }
+ if (SmmCommData != NULL && SmmBootRecordData != NULL) {
+ //
+ // Fill Boot records from SMM drivers.
+ //
+ CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize);
+ FreePool (SmmBootRecordData);
+ mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize);
+ BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize;
+ }
+
+ mBootRecordBuffer = (UINT8 *) mAcpiBootPerformanceTable;
+ mBootRecordSize = mAcpiBootPerformanceTable->Header.Length;
+ mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a human readable module name and module guid for the given image handle.
+ If module name can't be found, "" string will return.
+ If module guid can't be found, Zero Guid will return.
+
+ @param Handle Image handle or Controller handle.
+ @param NameString The ascii string will be filled into it. If not found, null string will return.
+ @param BufferSize Size of the input NameString buffer.
+ @param ModuleGuid Point to the guid buffer to store the got module guid value.
+
+ @retval EFI_SUCCESS Successfully get module name and guid.
+ @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
+ @retval other value Module Name can't be got.
+**/
+EFI_STATUS
+GetModuleInfoFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize,
+ OUT EFI_GUID *ModuleGuid OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ CHAR8 *PdbFileName;
+ EFI_GUID *TempGuid;
+ UINTN StartIndex;
+ UINTN Index;
+ INTN Count;
+ BOOLEAN ModuleGuidIsGet;
+ UINTN StringSize;
+ CHAR16 *StringPtr;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
+
+ if (NameString == NULL || BufferSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Try to get the ModuleGuid and name string form the caached array.
+ //
+ if (mCachePairCount > 0) {
+ for (Count = mCachePairCount -1; Count >= 0; Count--) {
+ if (Handle == mCacheHandleGuidTable[Count].Handle) {
+ CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
+ AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ LoadedImage = NULL;
+ ModuleGuidIsGet = FALSE;
+
+ //
+ // Initialize GUID as zero value.
+ //
+ TempGuid = &gZeroGuid;
+ //
+ // Initialize it as "" string.
+ //
+ NameString[0] = 0;
+
+ if (Handle != NULL) {
+ //
+ // Try Handle as ImageHandle.
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**) &LoadedImage
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Try Handle as Controller Handle
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get Image protocol from ImageHandle
+ //
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**) &LoadedImage
+ );
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status) && LoadedImage != NULL) {
+ //
+ // Get Module Guid from DevicePath.
+ //
+ if (LoadedImage->FilePath != NULL &&
+ LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
+ LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
+ ) {
+ //
+ // Determine GUID associated with module logging performance
+ //
+ ModuleGuidIsGet = TRUE;
+ FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
+ TempGuid = &FvFilePath->FvFileName;
+ }
+
+ //
+ // Method 1 Get Module Name from PDB string.
+ //
+ PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
+ if (PdbFileName != NULL && BufferSize > 0) {
+ StartIndex = 0;
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string.
+ // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < BufferSize - 1; Index++) {
+ NameString[Index] = PdbFileName[Index + StartIndex];
+ if (NameString[Index] == 0 || NameString[Index] == '.') {
+ NameString[Index] = 0;
+ break;
+ }
+ }
+
+ if (Index == BufferSize - 1) {
+ NameString[Index] = 0;
+ }
+ //
+ // Module Name is got.
+ //
+ goto Done;
+ }
+ }
+
+ //
+ // Method 2: Get the name string from ComponentName2 protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the current platform language setting
+ //
+ if (mPlatformLanguage == NULL) {
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID **) &mPlatformLanguage, NULL);
+ }
+ if (mPlatformLanguage != NULL) {
+ Status = ComponentName2->GetDriverName (
+ ComponentName2,
+ mPlatformLanguage != NULL ? mPlatformLanguage : "en-US",
+ &StringPtr
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
+ NameString[Index] = (CHAR8) StringPtr[Index];
+ }
+ NameString[Index] = 0;
+ //
+ // Module Name is got.
+ //
+ goto Done;
+ }
+ }
+ }
+
+ if (ModuleGuidIsGet) {
+ //
+ // Method 3 Try to get the image's FFS UI section by image GUID
+ //
+ StringPtr = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ TempGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &StringPtr,
+ &StringSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Method 3. Get the name string from FFS UI section
+ //
+ for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
+ NameString[Index] = (CHAR8) StringPtr[Index];
+ }
+ NameString[Index] = 0;
+ FreePool (StringPtr);
+ }
+ }
+
+Done:
+ //
+ // Copy Module Guid
+ //
+ if (ModuleGuid != NULL) {
+ CopyGuid (ModuleGuid, TempGuid);
+ if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
+ // Handle is GUID
+ CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
+ }
+ }
+
+ //
+ // Cache the Handle and Guid pairs.
+ //
+ if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
+ mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
+ CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
+ AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
+ mCachePairCount ++;
+ }
+
+ return Status;
+}
+
+/**
+ Get the FPDT record identifier.
+
+ @param Attribute The attribute of the Record.
+ PerfStartEntry: Start Record.
+ PerfEndEntry: End Record.
+ @param Handle Pointer to environment specific context used to identify the component being measured.
+ @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
+ @param ProgressID On return, pointer to the ProgressID.
+
+ @retval EFI_SUCCESS Get record info successfully.
+ @retval EFI_INVALID_PARAMETER No matched FPDT record.
+
+**/
+EFI_STATUS
+GetFpdtRecordId (
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute,
+ IN CONST VOID *Handle,
+ IN CONST CHAR8 *String,
+ OUT UINT16 *ProgressID
+ )
+{
+ //
+ // Token to PerfId.
+ //
+ if (String != NULL) {
+ if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_START_ID;
+ } else {
+ *ProgressID = MODULE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_LOADIMAGE_START_ID;
+ } else {
+ *ProgressID = MODULE_LOADIMAGE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, DRIVERBINDING_START_TOK) == 0) { // "DB:Start:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_DB_START_ID;
+ } else {
+ *ProgressID = MODULE_DB_END_ID;
+ }
+ } else if (AsciiStrCmp (String, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:"
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ return RETURN_UNSUPPORTED;
+ }
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_DB_SUPPORT_START_ID;
+ } else {
+ *ProgressID = MODULE_DB_SUPPORT_END_ID;
+ }
+ } else if (AsciiStrCmp (String, DRIVERBINDING_STOP_TOK) == 0) { // "DB:Stop:"
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ return RETURN_UNSUPPORTED;
+ }
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_DB_STOP_START_ID;
+ } else {
+ *ProgressID = MODULE_DB_STOP_END_ID;
+ }
+ } else if (AsciiStrCmp (String, PEI_TOK) == 0 || // "PEI"
+ AsciiStrCmp (String, DXE_TOK) == 0 || // "DXE"
+ AsciiStrCmp (String, BDS_TOK) == 0) { // "BDS"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_CROSSMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_CROSSMODULE_END_ID;
+ }
+ } else { // Pref used in Modules.
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ }
+ } else if (Handle!= NULL) { // Pref used in Modules.
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Copies the string from Source into Destination and updates Length with the
+ size of the string.
+
+ @param Destination - destination of the string copy
+ @param Source - pointer to the source string which will get copied
+ @param Length - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+ IN OUT CHAR8 *Destination,
+ IN CONST CHAR8 *Source,
+ IN OUT UINT8 *Length
+ )
+{
+ UINTN StringLen;
+ UINTN DestMax;
+
+ ASSERT (Source != NULL);
+
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ DestMax = STRING_SIZE;
+ } else {
+ DestMax = AsciiStrSize (Source);
+ if (DestMax > STRING_SIZE) {
+ DestMax = STRING_SIZE;
+ }
+ }
+ StringLen = AsciiStrLen (Source);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+ *Length += (UINT8)DestMax;
+
+ return;
+}
+
+/**
+ Get a string description for device for the given controller handle and update record
+ length. If ComponentName2 GetControllerName is supported, the value is included in the string,
+ followed by device path, otherwise just device path.
+
+ @param Handle - Image handle
+ @param ControllerHandle - Controller handle.
+ @param ComponentNameString - Pointer to a location where the string will be saved
+ @param Length - Pointer to record length to be updated
+
+ @retval EFI_SUCCESS - Successfully got string description for device
+ @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor DevicePath were found
+
+**/
+EFI_STATUS
+GetDeviceInfoFromHandleAndUpdateLength (
+ IN CONST VOID *Handle,
+ IN EFI_HANDLE ControllerHandle,
+ OUT CHAR8 *ComponentNameString,
+ IN OUT UINT8 *Length
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+ EFI_STATUS Status;
+ CHAR16 *StringPtr;
+ CHAR8 *AsciiStringPtr;
+ UINTN ControllerNameStringSize;
+ UINTN DevicePathStringSize;
+
+ ControllerNameStringSize = 0;
+
+ Status = gBS->HandleProtocol (
+ (EFI_HANDLE) Handle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+
+ if (!EFI_ERROR(Status)) {
+ //
+ // Get the current platform language setting
+ //
+ if (mPlatformLanguage == NULL) {
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&mPlatformLanguage, NULL);
+ }
+
+ Status = ComponentName2->GetControllerName (
+ ComponentName2,
+ ControllerHandle,
+ NULL,
+ mPlatformLanguage != NULL ? mPlatformLanguage : "en-US",
+ &StringPtr
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // This will produce the size of the unicode string, which is twice as large as the ASCII one
+ // This must be an even number, so ok to divide by 2
+ //
+ ControllerNameStringSize = StrSize(StringPtr) / 2;
+
+ //
+ // The + 1 is because we want to add a space between the ControllerName and the device path
+ //
+ if ((ControllerNameStringSize + (*Length) + 1) > FPDT_MAX_PERF_RECORD_SIZE) {
+ //
+ // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the record
+ //
+ ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1;
+ }
+
+ UnicodeStrnToAsciiStrS(StringPtr, ControllerNameStringSize - 1, ComponentNameString, ControllerNameStringSize, &ControllerNameStringSize);
+
+ //
+ // Add a space in the end of the ControllerName
+ //
+ AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1;
+ *AsciiStringPtr = 0x20;
+ AsciiStringPtr++;
+ *AsciiStringPtr = 0;
+ ControllerNameStringSize++;
+
+ *Length += (UINT8)ControllerNameStringSize;
+ }
+
+ //
+ // This function returns the device path protocol from the handle specified by Handle. If Handle is
+ // NULL or Handle does not contain a device path protocol, then NULL is returned.
+ //
+ DevicePathProtocol = DevicePathFromHandle(ControllerHandle);
+
+ if (DevicePathProtocol != NULL) {
+ StringPtr = ConvertDevicePathToText (DevicePathProtocol, TRUE, FALSE);
+ if (StringPtr != NULL) {
+ //
+ // This will produce the size of the unicode string, which is twice as large as the ASCII one
+ // This must be an even number, so ok to divide by 2
+ //
+ DevicePathStringSize = StrSize(StringPtr) / 2;
+
+ if ((DevicePathStringSize + (*Length)) > FPDT_MAX_PERF_RECORD_SIZE) {
+ //
+ // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the record
+ //
+ DevicePathStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length);
+ }
+
+ if (ControllerNameStringSize != 0) {
+ AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1;
+ } else {
+ AsciiStringPtr = ComponentNameString;
+ }
+
+ UnicodeStrnToAsciiStrS(StringPtr, DevicePathStringSize - 1, AsciiStringPtr, DevicePathStringSize, &DevicePathStringSize);
+ *Length += (UINT8)DevicePathStringSize;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param Ticker - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param PerfId - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+
+ @retval EFI_SUCCESS - Successfully created performance record
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+EFI_STATUS
+InsertFpdtRecord (
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Ticker,
+ IN UINT64 Address, OPTIONAL
+ IN UINT16 PerfId,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+{
+ EFI_GUID ModuleGuid;
+ CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ FPDT_RECORD_PTR FpdtRecordPtr;
+ FPDT_RECORD_PTR CachedFpdtRecordPtr;
+ UINT64 TimeStamp;
+ CONST CHAR8 *StringPtr;
+ UINTN DestMax;
+ UINTN StringLen;
+ EFI_STATUS Status;
+ UINT16 ProgressId;
+
+ StringPtr = NULL;
+ ProgressId = 0;
+ ZeroMem (ModuleName, sizeof (ModuleName));
+
+ //
+ // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
+ // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
+ //
+ if (Attribute != PerfEntry) {
+ //
+ // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
+ // !!! Note: If the Perf is not the known Token used in the core but have same
+ // ID with the core Token, this case will not be supported.
+ // And in currtnt usage mode, for the unkown ID, there is a general rule:
+ // If it is start pref: the lower 4 bits of the ID should be 0.
+ // If it is end pref: the lower 4 bits of the ID should not be 0.
+ // If input ID doesn't follow the rule, we will adjust it.
+ //
+ if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
+ PerfId &= 0xFFF0;
+ } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+ PerfId += 1;
+ }
+ } else if (PerfId == 0) {
+ //
+ // Get ProgressID form the String Token.
+ //
+ Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PerfId = ProgressId;
+ }
+ }
+
+ //
+ // 2. Get the buffer to store the FPDT record.
+ //
+ Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ //3. Get the TimeStamp.
+ //
+ if (Ticker == 0) {
+ Ticker = GetPerformanceCounter ();
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ } else if (Ticker == 1) {
+ TimeStamp = 0;
+ } else {
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ }
+
+ //
+ // 4. Fill in the FPDT record according to different Performance Identifier.
+ //
+ switch (PerfId) {
+ case MODULE_START_ID:
+ case MODULE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ //
+ // Cache the offset of start image start record and use to update the start image end record if needed.
+ //
+ if (Attribute == PerfEntry && PerfId == MODULE_START_ID) {
+ if (mFpdtBufferIsReported) {
+ mCachedLength = mBootRecordSize;
+ } else {
+ mCachedLength = mPerformanceLength;
+ }
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
+ FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
+ FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {
+ if (mFpdtBufferIsReported) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength);
+ } else {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength);
+ }
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+ break;
+
+ case MODULE_LOADIMAGE_START_ID:
+ case MODULE_LOADIMAGE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ if (PerfId == MODULE_LOADIMAGE_START_ID) {
+ mLoadImageCount ++;
+ //
+ // Cache the offset of load image start record and use to be updated by the load image end record if needed.
+ //
+ if (CallerIdentifier == NULL && Attribute == PerfEntry) {
+ if (mFpdtBufferIsReported) {
+ mCachedLength = mBootRecordSize;
+ } else {
+ mCachedLength = mPerformanceLength;
+ }
+ }
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+ FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
+ FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
+ CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
+ if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
+ if (mFpdtBufferIsReported) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength);
+ } else {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength);
+ }
+ CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+ break;
+
+ case MODULE_DB_START_ID:
+ case MODULE_DB_SUPPORT_START_ID:
+ case MODULE_DB_SUPPORT_END_ID:
+ case MODULE_DB_STOP_START_ID:
+ case MODULE_DB_STOP_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+ FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
+ FpdtRecordPtr.GuidQwordEvent->Qword = Address;
+ CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
+ }
+ break;
+
+ case MODULE_DB_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordStringEvent->Header.Type = FPDT_GUID_QWORD_STRING_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordStringEvent->Header.Length = sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD);;
+ FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordStringEvent->Timestamp = TimeStamp;
+ FpdtRecordPtr.GuidQwordStringEvent->Qword = Address;
+ CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordStringEvent->Guid));
+ if (Address != 0) {
+ GetDeviceInfoFromHandleAndUpdateLength(CallerIdentifier, (EFI_HANDLE)(UINTN)Address, FpdtRecordPtr.GuidQwordStringEvent->String, &FpdtRecordPtr.GuidQwordStringEvent->Header.Length);
+ }
+ }
+ break;
+
+ case PERF_EVENTSIGNAL_START_ID:
+ case PERF_EVENTSIGNAL_END_ID:
+ case PERF_CALLBACK_START_ID:
+ case PERF_CALLBACK_END_ID:
+ if (String == NULL || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ StringPtr = String;
+ if (AsciiStrLen (String) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+ }
+ break;
+
+ case PERF_EVENT_ID:
+ case PERF_FUNCTION_START_ID:
+ case PERF_FUNCTION_END_ID:
+ case PERF_INMODULE_START_ID:
+ case PERF_INMODULE_END_ID:
+ case PERF_CROSSMODULE_START_ID:
+ case PERF_CROSSMODULE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (String != NULL) {
+ StringPtr = String;
+ } else {
+ StringPtr = ModuleName;
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ break;
+
+ default:
+ if (Attribute != PerfEntry) {
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (String != NULL) {
+ StringPtr = String;
+ } else {
+ StringPtr = ModuleName;
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ //
+ // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
+ //
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ if (StringPtr == NULL ||PerfId == MODULE_DB_SUPPORT_START_ID || PerfId == MODULE_DB_SUPPORT_END_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ if (Guid != NULL) {
+ //
+ // Cache the event guid in string event record.
+ //
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ } else {
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+
+ if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
+ }
+ if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {
+ if (mFpdtBufferIsReported) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength);
+ } else {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength);
+ }
+ if (PerfId == MODULE_LOADIMAGE_END_ID) {
+ DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (StringPtr);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+ CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
+ } else if (PerfId == MODULE_END_ID) {
+ DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
+ }
+ mCachedLength = 0;
+ }
+ }
+
+ //
+ // 5. Update the length of the used buffer after fill in the record.
+ //
+ if (mFpdtBufferIsReported) {
+ mBootRecordSize += FpdtRecordPtr.RecordHeader->Length;
+ mAcpiBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
+ } else {
+ mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Dumps all the PEI performance.
+
+ @param HobStart A pointer to a Guid.
+
+ This internal function dumps all the PEI performance log to the DXE performance gauge array.
+ It retrieves the optional GUID HOB for PEI performance and then saves the performance data
+ to DXE performance data structures.
+
+**/
+VOID
+InternalGetPeiPerformance (
+ VOID *HobStart
+ )
+{
+ UINT8 *FirmwarePerformanceHob;
+ FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader;
+ UINT8 *EventRec;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, HobStart);
+ while (GuidHob != NULL) {
+ FirmwarePerformanceHob = GET_GUID_HOB_DATA (GuidHob);
+ PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)FirmwarePerformanceHob;
+
+ if (mPerformanceLength + PeiPerformanceLogHeader->SizeOfAllEntries > mMaxPerformanceLength) {
+ mPerformancePointer = ReallocatePool (
+ mPerformanceLength,
+ mPerformanceLength +
+ (UINTN)PeiPerformanceLogHeader->SizeOfAllEntries +
+ FIRMWARE_RECORD_BUFFER,
+ mPerformancePointer
+ );
+ ASSERT (mPerformancePointer != NULL);
+ mMaxPerformanceLength = mPerformanceLength +
+ (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries) +
+ FIRMWARE_RECORD_BUFFER;
+ }
+
+ EventRec = mPerformancePointer + mPerformanceLength;
+ CopyMem (EventRec, FirmwarePerformanceHob + sizeof (FPDT_PEI_EXT_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries));
+ //
+ // Update the used buffer size.
+ //
+ mPerformanceLength += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries);
+ mLoadImageCount += PeiPerformanceLogHeader->LoadImageCount;
+
+ //
+ // Get next performance guid hob
+ //
+ GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
+ }
+}
+
+/**
+ Report Boot Perforamnce table address as report status code.
+
+ @param Event The event of notify protocol.
+ @param Context Notify event context.
+
+**/
+VOID
+EFIAPI
+ReportFpdtRecordBuffer (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT64 BPDTAddr;
+
+ if (!mFpdtBufferIsReported) {
+ Status = AllocateBootPerformanceTable ();
+ if (!EFI_ERROR(Status)) {
+ BPDTAddr = (UINT64)(UINTN)mAcpiBootPerformanceTable;
+ REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_SOFTWARE_DXE_BS_DRIVER,
+ 0,
+ NULL,
+ &gEdkiiFpdtExtendedFirmwarePerformanceGuid,
+ &BPDTAddr,
+ sizeof (UINT64)
+ );
+ }
+ //
+ // Set FPDT report state to TRUE.
+ //
+ mFpdtBufferIsReported = TRUE;
+ }
+}
+
+/**
+ The constructor function initializes Performance infrastructure for DXE phase.
+
+ The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance
+ and merges PEI performance data to DXE performance log.
+ It will ASSERT() if one of these operations 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
+DxeCorePerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_EVENT ReadyToBootEvent;
+ PERFORMANCE_PROPERTY *PerformanceProperty;
+
+ if (!PerformanceMeasurementEnabled ()) {
+ //
+ // Do not initialize performance infrastructure if not required.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Dump normal PEI performance records
+ //
+ InternalGetPeiPerformance (GetHobList());
+
+ //
+ // Install the protocol interfaces for DXE performance library instance.
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiPerformanceMeasurementProtocolGuid,
+ &mPerformanceMeasurementInterface,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register ReadyToBoot event to report StatusCode data
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ReportFpdtRecordBuffer,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
+ if (EFI_ERROR (Status)) {
+ //
+ // Install configuration table for performance property.
+ //
+ mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;
+ mPerformanceProperty.Reserved = 0;
+ mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
+ &mPerformanceProperty.TimerStartValue,
+ &mPerformanceProperty.TimerEndValue
+ );
+ Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+**/
+EFI_STATUS
+EFIAPI
+CreatePerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (mLockInsertRecord) {
+ return EFI_INVALID_PARAMETER;
+ }
+ mLockInsertRecord = TRUE;
+
+ Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
+
+ mLockInsertRecord = FALSE;
+
+ return Status;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ !!! Not support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ !!! Not support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
new file mode 100644
index 000000000..1c1dcc60a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
@@ -0,0 +1,77 @@
+## @file
+# Performance library instance mainly for DxeCore usage.
+#
+# This library provides the performance measurement interfaces and initializes performance
+# logging for DXE phase. It first initializes its private global data structure for
+# performance logging and saves the performance GUIDed HOB passed from PEI phase.
+# It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
+# which is consumed by DxePerformanceLib to logging performance data in DXE phase.
+# This library is mainly used by DxeCore to start performance logging to ensure that
+# Performance and PerformanceEx Protocol are installed at the very beginning of DXE phase.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCorePerformanceLib
+ MODULE_UNI_FILE = DxeCorePerformanceLib.uni
+ FILE_GUID = D0F78BBF-0A30-4c63-8A48-0F618A4AFACD
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_CORE
+
+ CONSTRUCTOR = DxeCorePerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCorePerformanceLib.c
+ DxeCorePerformanceLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+ TimerLib
+ BaseMemoryLib
+ BaseLib
+ HobLib
+ DebugLib
+ UefiLib
+ ReportStatusCodeLib
+ DxeServicesLib
+ PeCoffGetEntryPointLib
+ DevicePathLib
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES
+
+
+[Guids]
+ ## PRODUCES ## SystemTable
+ gPerformanceProtocolGuid
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiFirmwarePerformanceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # StatusCode Data
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid ## SOMETIMES_CONSUMES ## HOB # StatusCode Data
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+ gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEdkiiPerformanceMeasurementProtocolGuid ## PRODUCES ## UNDEFINED # Install protocol
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdExtFpdtBootRecordPadSize ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni
new file mode 100644
index 000000000..af31943e0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Performance library instance mainly for DxeCore usage.
+//
+// This library provides the performance measurement interfaces and initializes performance
+// logging for DXE phase. It first initializes its private global data structure for
+// performance logging and saves the performance GUIDed HOB passed from PEI phase.
+// It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
+// which is consumed by DxePerformanceLib to logging performance data in DXE phase.
+// This library is mainly used by DxeCore to start performance logging to ensure that
+// Performance and PerformanceEx Protocol are installed at the very beginning of DXE phase.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Performance library instance mainly for DxeCore usage"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides the performance measurement interfaces and initializes performance logging for DXE phase. It first initializes its private global data structure for performance logging and saves the performance GUIDed HOB passed from the PEI phase. It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol, which is consumed by DxePerformanceLib to logging performance data in DXE phase. This library is mainly used by DxeCore to start performance logging to ensure that Performance and PerformanceEx Protocol are installed at the very beginning of DXE phase."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
new file mode 100644
index 000000000..26e5b40b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
@@ -0,0 +1,78 @@
+/** @file
+ Master header files for DxeCorePerformanceLib instance.
+
+ This header file holds the prototypes of the Performance and PerformanceEx Protocol published by this
+ library instance at its constructor.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_CORE_PERFORMANCE_LIB_INTERNAL_H_
+#define _DXE_CORE_PERFORMANCE_LIB_INTERNAL_H_
+
+
+#include <PiDxe.h>
+
+#include <Guid/Performance.h>
+#include <Guid/PerformanceMeasurement.h>
+#include <Guid/ExtendedFirmwarePerformance.h>
+#include <Guid/ZeroGuid.h>
+#include <Guid/EventGroup.h>
+#include <Guid/FirmwarePerformance.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/SmmCommunication.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+**/
+EFI_STATUS
+EFIAPI
+CreatePerformanceMeasurement(
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 TimeStamp, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c
new file mode 100644
index 000000000..048b4ff38
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c
@@ -0,0 +1,230 @@
+/** @file
+
+ This library registers CRC32 guided section handler
+ to parse CRC32 encapsulation section and extract raw data.
+ It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/Crc32GuidedSectionExtraction.h>
+#include <Protocol/SecurityPolicy.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+///
+/// CRC32 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION2_HEADER;
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successfully retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for 32bit CRC value in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionCrc32Checksum;
+ UINT32 Crc32Checksum;
+ UINT32 OutputBufferSize;
+ VOID *DummyInterface;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION2_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // Init Checksum value to Zero.
+ //
+ Crc32Checksum = 0;
+
+ //
+ // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID.
+ //
+ Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SecurityPolicy Protocol exist, AUTH platform override bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_PLATFORM_OVERRIDE;
+ } else {
+ //
+ // Calculate CRC32 Checksum of Image
+ //
+ Status = gBS->CalculateCrc32 (*OutputBuffer, OutputBufferSize, &Crc32Checksum);
+ if (Status == EFI_SUCCESS) {
+ if (Crc32Checksum != SectionCrc32Checksum) {
+ //
+ // If Crc32 checksum is not matched, AUTH tested failed bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+ } else {
+ //
+ // If Crc32 checksum is not calculated, AUTH not tested bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_NOT_TESTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register the handler to extract CRC32 guided section.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
+**/
+EFI_STATUS
+EFIAPI
+DxeCrc32GuidedSectionExtractLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ Crc32GuidedSectionGetInfo,
+ Crc32GuidedSectionHandler
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
new file mode 100644
index 000000000..5165f5400
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Dxe Crc32 Guided Section Extract library.
+#
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register CRC32 guided section handler
+# that parses CRC32 encapsulation section and extracts raw data.
+#
+# It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCrc32GuidedSectionExtractLib
+ MODULE_UNI_FILE = DxeCrc32GuidedSectionExtractLib.uni
+ FILE_GUID = 387A2490-81FC-4E7C-8E0A-3E58C30FCD0B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = DxeCrc32GuidedSectionExtractLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCrc32GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiCrc32GuidedSectionExtractionGuid ## PRODUCES ## UNDEFINED
+
+[Protocols]
+ gEfiSecurityPolicyProtocolGuid ## SOMETIMES_CONSUMES # Set platform override AUTH status if exist
diff --git a/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni
new file mode 100644
index 000000000..5b0861c5e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Dxe Crc32 Guided Section Extract library.
+//
+// This library doesn't produce any library class. The constructor function uses
+// ExtractGuidedSectionLib service to register CRC32 guided section handler
+// that parses CRC32 encapsulation section and extracts raw data.
+//
+// It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Dxe Crc32 Guided Section Extract library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register CRC32 guided section handler that parses CRC32 encapsulation section and extracts raw data. It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c
new file mode 100644
index 000000000..7f3ccb06d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c
@@ -0,0 +1,382 @@
+/** @file
+ Debug Print Error Level library instance that provide compatibility with the
+ "err" shell command. This includes support for the Debug Mask Protocol
+ supports for global debug print error level mask stored in an EFI Variable.
+ This library instance only support DXE Phase modules.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/DebugPrintErrorLevelLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+
+#include <Guid/DebugMask.h>
+
+///
+/// Debug Mask Protocol function prototypes
+///
+
+/**
+ Retrieves the current debug print error level mask for a module are returns
+ it in CurrentDebugMask.
+
+ @param This The protocol instance pointer.
+ @param CurrentDebugMask Pointer to the debug print error level mask that
+ is returned.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ returned in CurrentDebugMask.
+ @retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN OUT UINTN *CurrentDebugMask
+ );
+
+/**
+ Sets the current debug print error level mask for a module to the value
+ specified by NewDebugMask.
+
+ @param This The protocol instance pointer.
+ @param NewDebugMask The new debug print error level mask for this module.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ set to the value specified by NewDebugMask.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be set to the value specified by NewDebugMask.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN UINTN NewDebugMask
+ );
+
+///
+/// Debug Mask Protocol instance
+///
+EFI_DEBUG_MASK_PROTOCOL mDebugMaskProtocol = {
+ EFI_DEBUG_MASK_REVISION,
+ GetDebugMask,
+ SetDebugMask
+};
+
+///
+/// Global variable that is set to TRUE after the first attempt is made to
+/// retrieve the global error level mask through the EFI Varibale Services.
+/// This variable prevents the EFI Variable Services from being called fort
+/// every DEBUG() macro.
+///
+BOOLEAN mGlobalErrorLevelInitialized = FALSE;
+
+///
+/// Global variable that contains the current debug error level mask for the
+/// module that is using this library instance. This variable is initially
+/// set to the PcdDebugPrintErrorLevel value. If the EFI Variable exists that
+/// contains the global debug print error level mask, then that overrides the
+/// PcdDebugPrintErrorLevel value. The EFI Variable can optionally be
+/// discovered via a HOB so early DXE drivers can access the variable. If the
+/// Debug Mask Protocol SetDebugMask() service is called, then that overrides
+/// the PcdDebugPrintErrorLevel and the EFI Variable setting.
+///
+UINT32 mDebugPrintErrorLevel = 0;
+
+///
+/// Global variable that is used to cache a pointer to the EFI System Table
+/// that is required to access the EFI Variable Services to get and set
+/// the global debug print error level mask value. The UefiBootServicesTableLib
+/// is not used to prevent a circular dependency between these libraries.
+///
+EFI_SYSTEM_TABLE *mSystemTable = NULL;
+
+/**
+ The constructor function caches the PCI Express Base Address and creates a
+ Set Virtual Address Map event to convert physical address to virtual addresses.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor completed successfully.
+ @retval Other value The constructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDebugPrintErrorLevelLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the error level mask from PCD setting.
+ //
+ mDebugPrintErrorLevel = PcdGet32 (PcdDebugPrintErrorLevel);
+
+ //
+ // Install Debug Mask Protocol onto ImageHandle
+ //
+ mSystemTable = SystemTable;
+ Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
+ NULL
+ );
+
+ //
+ // Attempt to retrieve the global debug print error level mask from the EFI Variable
+ // If the EFI Variable can not be accessed when this module's library constructors are
+ // executed a HOB can be used to set the global debug print error level. If no value
+ // was found then the EFI Variable access will be reattempted on every DEBUG() print
+ // from this module until the EFI Variable services are available.
+ //
+ GetDebugPrintErrorLevel ();
+
+ return Status;
+}
+
+/**
+ The destructor function frees any allocated buffers and closes the Set Virtual
+ Address Map event.
+
+ @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
+DxeDebugPrintErrorLevelLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Uninstall the Debug Mask Protocol from ImageHandle
+ //
+ return SystemTable->BootServices->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
+ NULL
+ );
+}
+
+/**
+ Returns the debug print error level mask for the current module.
+
+ @return Debug print error level mask for the current module.
+
+**/
+UINT32
+EFIAPI
+GetDebugPrintErrorLevel (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL CurrentTpl;
+ UINTN Size;
+ UINTN GlobalErrorLevel;
+ VOID *Hob;
+
+ //
+ // If the constructor has not been executed yet, then just return the PCD value.
+ // This case should only occur if debug print is generated by a library
+ // constructor for this module
+ //
+ if (mSystemTable == NULL) {
+ return PcdGet32 (PcdDebugPrintErrorLevel);
+ }
+
+ //
+ // Check to see if an attempt has been made to retrieve the global debug print
+ // error level mask. Since this library instance stores the global debug print
+ // error level mask in an EFI Variable, the EFI Variable should only be accessed
+ // once to reduce the overhead of reading the EFI Variable on every debug print
+ //
+ if (!mGlobalErrorLevelInitialized) {
+ //
+ // Make sure the TPL Level is low enough for EFI Variable Services to be called
+ //
+ CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
+ mSystemTable->BootServices->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_CALLBACK) {
+ //
+ // Attempt to retrieve the global debug print error level mask from the
+ // EFI Variable
+ //
+ Size = sizeof (GlobalErrorLevel);
+ Status = mSystemTable->RuntimeServices->GetVariable (
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ NULL,
+ &Size,
+ &GlobalErrorLevel
+ );
+ if (Status != EFI_NOT_AVAILABLE_YET) {
+ //
+ // If EFI Variable Services are available, then set a flag so the EFI
+ // Variable will not be read again by this module.
+ //
+ mGlobalErrorLevelInitialized = TRUE;
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the EFI Varible exists, then set this module's module's mask to
+ // the global debug print error level mask value.
+ //
+ mDebugPrintErrorLevel = (UINT32)GlobalErrorLevel;
+ }
+ } else {
+ //
+ // If variable services are not yet available optionally get the global
+ // debug print error level mask from a HOB.
+ //
+ Hob = GetFirstGuidHob (&gEfiGenericVariableGuid);
+ if (Hob != NULL) {
+ if (GET_GUID_HOB_DATA_SIZE (Hob) == sizeof (UINT32)) {
+ mDebugPrintErrorLevel = *(UINT32 *)GET_GUID_HOB_DATA (Hob);
+ mGlobalErrorLevelInitialized = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Return the current mask value for this module.
+ //
+ return mDebugPrintErrorLevel;
+}
+
+/**
+ Sets the global debug print error level mask fpr the entire platform.
+
+ @param ErrorLevel Global debug print error level
+
+ @retval TRUE The debug print error level mask was sucessfully set.
+ @retval FALSE The debug print error level mask could not be set.
+
+**/
+BOOLEAN
+EFIAPI
+SetDebugPrintErrorLevel (
+ UINT32 ErrorLevel
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL CurrentTpl;
+ UINTN Size;
+ UINTN GlobalErrorLevel;
+
+ //
+ // Make sure the constructor has been executed
+ //
+ if (mSystemTable != NULL) {
+ //
+ // Make sure the TPL Level is low enough for EFI Variable Services
+ //
+ CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
+ mSystemTable->BootServices->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_CALLBACK) {
+ //
+ // Attempt to store the global debug print error level mask in an EFI Variable
+ //
+ GlobalErrorLevel = (UINTN)ErrorLevel;
+ Size = sizeof (GlobalErrorLevel);
+ Status = mSystemTable->RuntimeServices->SetVariable (
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
+ Size,
+ &GlobalErrorLevel
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the EFI Variable was updated, then update the mask value for this
+ // module and return TRUE.
+ //
+ mGlobalErrorLevelInitialized = TRUE;
+ mDebugPrintErrorLevel = ErrorLevel;
+ return TRUE;
+ }
+ }
+ }
+ //
+ // Return FALSE since the EFI Variable could not be updated.
+ //
+ return FALSE;
+}
+
+/**
+ Retrieves the current debug print error level mask for a module are returns
+ it in CurrentDebugMask.
+
+ @param This The protocol instance pointer.
+ @param CurrentDebugMask Pointer to the debug print error level mask that
+ is returned.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ returned in CurrentDebugMask.
+ @retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN OUT UINTN *CurrentDebugMask
+ )
+{
+ if (CurrentDebugMask == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the current debug mask from mDebugPrintErrorLevel
+ //
+ *CurrentDebugMask = (UINTN)mDebugPrintErrorLevel;
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the current debug print error level mask for a module to the value
+ specified by NewDebugMask.
+
+ @param This The protocol instance pointer.
+ @param NewDebugMask The new debug print error level mask for this module.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ set to the value specified by NewDebugMask.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be set to the value specified by NewDebugMask.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN UINTN NewDebugMask
+ )
+{
+ //
+ // Store the new debug mask into mDebugPrintErrorLevel
+ //
+ mDebugPrintErrorLevel = (UINT32)NewDebugMask;
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
new file mode 100644
index 000000000..39a14f0d7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Debug Print Error Level library instance that provide compatibility with the "err" shell command.
+# This includes support for the Debug Mask Protocol supports for global debug print error level mask
+# stored in an EFI Variable. This library instance only support DXE Phase modules.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDebugPrintErrorLevelLib
+ MODULE_UNI_FILE = DxeDebugPrintErrorLevelLib.uni
+ FILE_GUID = 1D564EC9-9373-49a4-9E3F-E4D7B9974C84
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugPrintErrorLevelLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeDebugPrintErrorLevelLibConstructor
+ DESTRUCTOR = DxeDebugPrintErrorLevelLibDestructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeDebugPrintErrorLevelLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ HobLib
+
+[Protocols]
+ gEfiDebugMaskProtocolGuid ## PRODUCES
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"EFIDebug"
+ ## SOMETIMES_CONSUMES ## Variable:L"EFIDebug"
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiGenericVariableGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni
new file mode 100644
index 000000000..546a46550
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Debug Print Error Level library instance that provide compatibility with the "err" shell command.
+//
+// This includes support for the Debug Mask Protocol supports for global debug print error level mask
+// stored in an EFI Variable. This library instance only support DXE Phase modules.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Print Error Level library instance that provide compatibility with the \"err\" shell command"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This includes support for the Debug Mask Protocol supports for global debug print error level mask stored in an EFI Variable. This library instance only support DXE Phase modules."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.c b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.c
new file mode 100644
index 000000000..2a7837a00
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.c
@@ -0,0 +1,87 @@
+/** @file
+ Instance of file explorer Library based on gEfiFileExplorerProtocolGuid.
+
+ Implement the file explorer library instance by wrap the interface
+ provided in the file explorer protocol. This protocol is defined as the internal
+ protocol related to this implementation, not in the public spec. So, this
+ library instance is only for this code base.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Protocol/FileExplorer.h>
+
+#include <Library/FileExplorerLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+EFI_FILE_EXPLORER_PROTOCOL *mProtocol = NULL;
+
+/**
+ The constructor function caches the pointer to file explorer protocol.
+
+ The constructor function locates Print2 protocol from protocol database.
+ 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 always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SystemTable->BootServices->LocateProtocol (
+ &gEfiFileExplorerProtocolGuid,
+ NULL,
+ (VOID**) &mProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mProtocol != NULL);
+
+ return Status;
+}
+
+/**
+ Choose a file in the specified directory.
+
+ If user input NULL for the RootDirectory, will choose file in the system.
+
+ If user input *File != NULL, function will return the allocate device path
+ info for the choosed file, caller has to free the memory after use it.
+
+ @param RootDirectory Pointer to the root directory.
+ @param FileType The file type need to choose.
+ @param ChooseHandler Function pointer to the extra task need to do
+ after choose one file.
+ @param File Return the device path for the last time chosed file.
+
+ @retval EFI_SUCESS Choose file success.
+ @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
+ One of them must not NULL.
+ @retval Other errors Choose file failed.
+**/
+EFI_STATUS
+EFIAPI
+ChooseFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
+ IN CHAR16 *FileType, OPTIONAL
+ IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
+ OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
+ )
+{
+ return mProtocol->ChooseFile (RootDirectory, FileType, ChooseHandler, File);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf
new file mode 100644
index 000000000..ddaefca1a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf
@@ -0,0 +1,36 @@
+## @file
+# Library instance that implements File explorer Library class based on protocol gEfiFileExplorerProtocolGuid.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeFileExplorerProtocol
+ MODULE_UNI_FILE = DxeFileExplorerProtocol.uni
+ FILE_GUID = 6806C45F-13C4-4274-B8A3-055EF641A060
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FileExplorerLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = FileExplorerConstructor
+
+[Sources]
+ DxeFileExplorerProtocol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[Protocols]
+ gEfiFileExplorerProtocolGuid ## CONSUMES
+
+[Depex.common.DXE_DRIVER, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_SAL_DRIVER, Depex.common.DXE_SMM_DRIVER]
+ gEfiFileExplorerProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.uni b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.uni
new file mode 100644
index 000000000..762a0a7f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Library instance that implements File explorer Library class based on protocol gEfiFileExplorerProtocolGuid.
+//
+//
+// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements File explorer Library class based on protocol gEfiFileExplorerProtocolGuid"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Library instance that implements File explorer Library class based on protocol gEfiFileExplorerProtocolGuid."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c
new file mode 100644
index 000000000..22b96b05d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c
@@ -0,0 +1,75 @@
+/** @file
+ Implementation of Ipmi Library in DXE Phase for SMS.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/IpmiProtocol.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+IPMI_PROTOCOL *mIpmiProtocol = NULL;
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIpmiProtocol == NULL) {
+ Status = gBS->LocateProtocol (
+ &gIpmiProtocolGuid,
+ NULL,
+ (VOID **) &mIpmiProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Dxe Ipmi Protocol is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand in Dxe Phase under SMS Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = mIpmiProtocol->IpmiSubmitCommand (
+ mIpmiProtocol,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf
new file mode 100644
index 000000000..3829986b8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf
@@ -0,0 +1,36 @@
+## @file
+# Instance of IPMI Library in DXE phase for SMS.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeIpmiLibIpmiProtocol
+ MODULE_UNI_FILE = DxeIpmiLibIpmiProtocol.uni
+ FILE_GUID = 62408AD5-4EAC-432B-AB9B-C4B85BFAED02
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|DXE_RUNTIME_DRIVER DXE_DRIVER DXE_CORE UEFI_DRIVER UEFI_APPLICATION
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DxeIpmiLibIpmiProtocol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ DebugLib
+
+[Protocols]
+ gIpmiProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.uni b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.uni
new file mode 100644
index 000000000..8aa935586
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Instance of IPMI Library in DXE phase for SMS.
+//
+// Instance of IPMI Library in DXE phase for SMS.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Instance of IPMI Library in DXE phase for SMS."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Instance of IPMI Library in DXE phase for SMS."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
new file mode 100644
index 000000000..d2fdd2806
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
@@ -0,0 +1,442 @@
+/** @file
+ Performance Library
+
+ This library instance provides infrastructure for DXE phase drivers to log performance
+ data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
+ to log performance data. If both PerformanceEx and Performance Protocol is not available, it does not log any
+ performance information.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/PerformanceMeasurement.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// The cached Performance Protocol and PerformanceEx Protocol interface.
+//
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL *mPerformanceMeasurement = NULL;
+
+/**
+ The function caches the pointers to PerformanceEx protocol and Performance Protocol.
+
+ The function locates PerformanceEx protocol and Performance Protocol from protocol database.
+
+ @retval EFI_SUCCESS PerformanceEx protocol or Performance Protocol is successfully located.
+ @retval EFI_NOT_FOUND Both PerformanceEx protocol and Performance Protocol are not located to log performance.
+
+**/
+EFI_STATUS
+GetPerformanceMeasurementProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL *PerformanceMeasurement;
+
+ if (mPerformanceMeasurement != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gEdkiiPerformanceMeasurementProtocolGuid, NULL, (VOID **) &PerformanceMeasurement);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PerformanceMeasurement != NULL);
+ //
+ // Cache PerformanceMeasurement Protocol.
+ //
+ mPerformanceMeasurement = PerformanceMeasurement;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+ CONST CHAR8* String;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+ CONST CHAR8* String;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
new file mode 100644
index 000000000..cd8e82884
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Performance library instance used in DXE phase.
+#
+# This library instance provides infrastructure for DXE phase drivers to log performance
+# data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
+# to log performance data. If both PerformanceEx and Performance Protocol are not available,
+# it does not log any performance information.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxePerformanceLib
+ MODULE_UNI_FILE = DxePerformanceLib.uni
+ FILE_GUID = 8B8B4CCC-65FC-41a5-8067-308B8E42CCF2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxePerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ PcdLib
+ UefiBootServicesTableLib
+ DebugLib
+
+
+[Guids]
+ gEdkiiPerformanceMeasurementProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni
new file mode 100644
index 000000000..dc85648d6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Performance library instance used in DXE phase.
+//
+// This library instance provides infrastructure for DXE phase drivers to log performance
+// data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
+// to log performance data. If both PerformanceEx and Performance Protocol are not available,
+// it does not log any performance information.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Used in the DXE phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance provides infrastructure for DXE phase drivers to log performance data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib to log performance data. If both PerformanceEx and Performance Protocol are not available, it does not log any performance information."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf
new file mode 100644
index 000000000..800bbd543
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf
@@ -0,0 +1,41 @@
+## @file
+# Library instance that implements Print Library class based on protocol gEfiPrint2ProtocolGuid.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxePrintLibPrint2Protocol
+ MODULE_UNI_FILE = DxePrintLibPrint2Protocol.uni
+ FILE_GUID = 55D460DB-8FEA-415a-B95D-70145AE0675C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PrintLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = PrintLibConstructor
+
+[Sources]
+ PrintLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiPrint2SProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength ## SOMETIMES_CONSUMES
+
+[Depex.common.DXE_DRIVER, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_SAL_DRIVER, Depex.common.DXE_SMM_DRIVER]
+ gEfiPrint2SProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni
new file mode 100644
index 000000000..5bf6fe188
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Library instance that implements Print Library class based on protocol gEfiPrint2SProtocolGuid.
+//
+// Library instance that implements Print Library class based on protocol gEfiPrint2SProtocolGuid.
+//
+// Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements Print Library class based on protocol gEfiPrint2SProtocolGuid"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Library instance that implements Print Library class based on protocol gEfiPrint2SProtocolGuid."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c
new file mode 100644
index 000000000..3a051fd58
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c
@@ -0,0 +1,2220 @@
+/** @file
+ Instance of Print Library based on gEfiPrint2SProtocolGuid.
+
+ Implement the print library instance by wrap the interface
+ provided in the Print2S protocol. This protocol is defined as the internal
+ protocol related to this implementation, not in the public spec. So, this
+ library instance is only for this code base.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Protocol/Print2.h>
+
+#include <Library/PrintLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#define ASSERT_UNICODE_BUFFER(Buffer) ASSERT ((((UINTN) (Buffer)) & 0x01) == 0)
+
+//
+// Safe print checks
+//
+#define RSIZE_MAX (PcdGet32 (PcdMaximumUnicodeStringLength))
+#define ASCII_RSIZE_MAX (PcdGet32 (PcdMaximumAsciiStringLength))
+
+#define SAFE_PRINT_CONSTRAINT_CHECK(Expression, RetVal) \
+ do { \
+ ASSERT (Expression); \
+ if (!(Expression)) { \
+ return RetVal; \
+ } \
+ } while (FALSE)
+
+EFI_PRINT2S_PROTOCOL *mPrint2SProtocol = NULL;
+
+/**
+ The constructor function caches the pointer to Print2S protocol.
+
+ The constructor function locates Print2S protocol from protocol database.
+ 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 always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PrintLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SystemTable->BootServices->LocateProtocol (
+ &gEfiPrint2SProtocolGuid,
+ NULL,
+ (VOID**) &mPrint2SProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mPrint2SProtocol != NULL);
+
+ return Status;
+}
+
+
+/**
+ Worker function that converts a VA_LIST to a BASE_LIST based on a Null-terminated
+ format string.
+
+ @param AsciiFormat TRUE if Format is an ASCII string. FALSE if Format is a Unicode string.
+ @param Format Null-terminated format string.
+ @param VaListMarker VA_LIST style variable argument list consumed by processing Format.
+ @param BaseListMarker BASE_LIST style variable argument list consumed by processing Format.
+ @param Size The size, in bytes, of the BaseListMarker buffer.
+
+ @return TRUE The VA_LIST has been converted to BASE_LIST.
+ @return FALSE The VA_LIST has not been converted to BASE_LIST.
+
+**/
+BOOLEAN
+DxePrintLibPrint2ProtocolVaListToBaseList (
+ IN BOOLEAN AsciiFormat,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker,
+ OUT BASE_LIST BaseListMarker,
+ IN UINTN Size
+ )
+{
+ BASE_LIST BaseListStart;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ BOOLEAN Long;
+ BOOLEAN Done;
+
+ ASSERT (BaseListMarker != NULL);
+ SAFE_PRINT_CONSTRAINT_CHECK ((Format != NULL), FALSE);
+
+ BaseListStart = BaseListMarker;
+
+ if (AsciiFormat) {
+ if (ASCII_RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((AsciiStrnLenS (Format, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), FALSE);
+ }
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ } else {
+ if (RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((StrnLenS ((CHAR16 *)Format, RSIZE_MAX + 1) <= RSIZE_MAX), FALSE);
+ }
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+
+ while (FormatCharacter != 0) {
+ if (FormatCharacter == '%') {
+ Long = FALSE;
+
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+
+ switch (FormatCharacter) {
+ case '.':
+ case '-':
+ case '+':
+ case ' ':
+ case ',':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ case 'L':
+ case 'l':
+ Long = TRUE;
+ break;
+ case '*':
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ break;
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ if (sizeof (VOID *) > 4) {
+ Long = TRUE;
+ }
+ case 'X':
+ case 'x':
+ case 'u':
+ case 'd':
+ if (Long) {
+ BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);
+ } else {
+ BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);
+ }
+ break;
+ case 's':
+ case 'S':
+ case 'a':
+ case 'g':
+ case 't':
+ BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);
+ break;
+ case 'c':
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ break;
+ case 'r':
+ BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
+ break;
+ }
+ }
+
+ //
+ // If BASE_LIST is larger than Size, then return FALSE
+ //
+ if (((UINTN)BaseListMarker - (UINTN)BaseListStart) > Size) {
+ DEBUG ((DEBUG_ERROR, "The input variable argument list is too long. Please consider breaking into multiple print calls.\n"));
+ return FALSE;
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ }
+ return TRUE;
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a VA_LIST argument list.
+
+ This function is similar as vsnprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then the output buffer is unmodified and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeVSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+ BOOLEAN Converted;
+
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+ ASSERT_UNICODE_BUFFER (FormatString);
+
+ Converted = DxePrintLibPrint2ProtocolVaListToBaseList (
+ FALSE,
+ (CHAR8 *)FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+ if (!Converted) {
+ return 0;
+ }
+
+ return UnicodeBSPrint (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then the output buffer is unmodified and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeBSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+ ASSERT_UNICODE_BUFFER (FormatString);
+ return mPrint2SProtocol->UnicodeBSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then the output buffer is unmodified and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and a VA_LIST argument list.
+
+ This function is similar as vsnprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeVSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+ BOOLEAN Converted;
+
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+
+ Converted = DxePrintLibPrint2ProtocolVaListToBaseList (
+ TRUE,
+ FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+ if (!Converted) {
+ return 0;
+ }
+
+ return UnicodeBSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeBSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+ return mPrint2SProtocol->UnicodeBSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 1 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and BufferSize >
+ (PcdMaximumUnicodeStringLength * sizeof (CHAR16) + 1), then ASSERT(). Also, the output
+ buffer is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = UnicodeVSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
+
+/**
+ [ATTENTION] This function is deprecated for security reason.
+
+ Converts a decimal value to a Null-terminated Unicode string.
+
+ Converts the decimal number specified by Value to a Null-terminated Unicode
+ string specified by Buffer containing at most Width characters. No padding of spaces
+ is ever performed. If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ The number of Unicode characters in Buffer is returned not including the Null-terminator.
+ If the conversion contains more than Width characters, then only the first
+ Width characters are returned, and the total number of characters
+ required to perform the conversion is returned.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+ If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer Pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of Unicode characters in Buffer not including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeValueToString (
+ IN OUT CHAR16 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ RETURN_STATUS Status;
+ UINTN BufferSize;
+
+ if (Width == 0) {
+ BufferSize = (MAXIMUM_VALUE_CHARACTERS + 1) * sizeof (CHAR16);
+ } else {
+ BufferSize = (Width + 1) * sizeof (CHAR16);
+ }
+
+ Status = mPrint2SProtocol->UnicodeValueToStringS (Buffer, BufferSize, Flags, Value, Width);
+ if (RETURN_ERROR (Status)) {
+ return 0;
+ }
+
+ return StrnLenS (Buffer, BufferSize / sizeof (CHAR16));
+}
+
+#endif
+
+/**
+ Converts a decimal value to a Null-terminated Unicode string.
+
+ Converts the decimal number specified by Value to a Null-terminated Unicode
+ string specified by Buffer containing at most Width characters. No padding of
+ spaces is ever performed. If Width is 0 then a width of
+ MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more than
+ Width characters, then only the first Width characters are placed in Buffer.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and
+ commas are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be formatted in
+ hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in
+ Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, then
+ Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the
+ Null-terminator add up to Width characters.
+
+ If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+ If an error would be returned, then the function will also ASSERT().
+
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Unicode string.
+ @param BufferSize The size of Buffer in bytes, including the
+ Null-terminator.
+ @param Flags The bitmask of flags that specify left justification,
+ zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in
+ Buffer, not including the Null-terminator.
+
+ @retval RETURN_SUCCESS The decimal value is converted.
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted
+ value.
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
+ If PcdMaximumUnicodeStringLength is not
+ zero, and BufferSize is greater than
+ (PcdMaximumUnicodeStringLength *
+ sizeof (CHAR16) + 1).
+ If unsupported bits are set in Flags.
+ If both COMMA_TYPE and RADIX_HEX are set in
+ Flags.
+ If Width >= MAXIMUM_VALUE_CHARACTERS.
+
+**/
+RETURN_STATUS
+EFIAPI
+UnicodeValueToStringS (
+ IN OUT CHAR16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ return mPrint2SProtocol->UnicodeValueToStringS (Buffer, BufferSize, Flags, Value, Width);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a VA_LIST argument list.
+
+ This function is similar as vsnprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiVSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+ BOOLEAN Converted;
+
+ Converted = DxePrintLibPrint2ProtocolVaListToBaseList (
+ TRUE,
+ FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+ if (!Converted) {
+ return 0;
+ }
+
+ return AsciiBSPrint (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiBSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ return mPrint2SProtocol->AsciiBSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength Ascii characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = AsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ Unicode format string and a VA_LIST argument list.
+
+ This function is similar as vsnprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiVSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+ BOOLEAN Converted;
+
+ ASSERT_UNICODE_BUFFER (FormatString);
+
+ Converted = DxePrintLibPrint2ProtocolVaListToBaseList (
+ FALSE,
+ (CHAR8 *)FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+ if (!Converted) {
+ return 0;
+ }
+
+ return AsciiBSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ Unicode format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiBSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (FormatString);
+ return mPrint2SProtocol->AsciiBSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ This function is similar as snprintf_s defined in C11.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If BufferSize > 0 and FormatString is NULL, then ASSERT(). Also, the output buffer is
+ unmodified and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and BufferSize >
+ (PcdMaximumAsciiStringLength * sizeof (CHAR8)), then ASSERT(). Also, the output buffer
+ is unmodified and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT(). Also, the output buffer is unmodified and 0 is returned.
+
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = AsciiVSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+
+#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
+
+/**
+ [ATTENTION] This function is deprecated for security reason.
+
+ Converts a decimal value to a Null-terminated ASCII string.
+
+ Converts the decimal number specified by Value to a Null-terminated ASCII string
+ specified by Buffer containing at most Width characters. No padding of spaces
+ is ever performed.
+ If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ The number of ASCII characters in Buffer is returned not including the Null-terminator.
+ If the conversion contains more than Width characters, then only the first Width
+ characters are returned, and the total number of characters required to perform
+ the conversion is returned.
+ Additional conversion parameters are specified in Flags.
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+
+ If Buffer is NULL, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer Pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of ASCII characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of ASCII characters in Buffer not including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiValueToString (
+ OUT CHAR8 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ RETURN_STATUS Status;
+ UINTN BufferSize;
+
+ if (Width == 0) {
+ BufferSize = (MAXIMUM_VALUE_CHARACTERS + 1) * sizeof (CHAR8);
+ } else {
+ BufferSize = (Width + 1) * sizeof (CHAR8);
+ }
+
+ Status = mPrint2SProtocol->AsciiValueToStringS (Buffer, BufferSize, Flags, Value, Width);
+ if (RETURN_ERROR (Status)) {
+ return 0;
+ }
+
+ return AsciiStrnLenS (Buffer, BufferSize / sizeof (CHAR8));
+}
+
+#endif
+
+/**
+ Converts a decimal value to a Null-terminated Ascii string.
+
+ Converts the decimal number specified by Value to a Null-terminated Ascii
+ string specified by Buffer containing at most Width characters. No padding of
+ spaces is ever performed. If Width is 0 then a width of
+ MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more than
+ Width characters, then only the first Width characters are placed in Buffer.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and
+ commas are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be formatted in
+ hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in
+ Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, then
+ Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the
+ Null-terminator add up to Width characters.
+
+ If an error would be returned, then the function will ASSERT().
+
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Ascii string.
+ @param BufferSize The size of Buffer in bytes, including the
+ Null-terminator.
+ @param Flags The bitmask of flags that specify left justification,
+ zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Ascii characters to place in
+ Buffer, not including the Null-terminator.
+
+ @retval RETURN_SUCCESS The decimal value is converted.
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted
+ value.
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
+ If PcdMaximumAsciiStringLength is not
+ zero, and BufferSize is greater than
+ PcdMaximumAsciiStringLength.
+ If unsupported bits are set in Flags.
+ If both COMMA_TYPE and RADIX_HEX are set in
+ Flags.
+ If Width >= MAXIMUM_VALUE_CHARACTERS.
+
+**/
+RETURN_STATUS
+EFIAPI
+AsciiValueToStringS (
+ IN OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ return mPrint2SProtocol->AsciiValueToStringS (Buffer, BufferSize, Flags, Value, Width);
+}
+
+#define PREFIX_SIGN BIT1
+#define PREFIX_BLANK BIT2
+#define LONG_TYPE BIT4
+#define OUTPUT_UNICODE BIT6
+#define FORMAT_UNICODE BIT8
+#define PAD_TO_WIDTH BIT9
+#define ARGUMENT_UNICODE BIT10
+#define PRECISION BIT11
+#define ARGUMENT_REVERSED BIT12
+#define COUNT_ONLY_NO_PRINT BIT13
+#define UNSIGNED_TYPE BIT14
+
+//
+// Record date and time information
+//
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} TIME;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+/**
+ Internal function that convert a number to a string in Buffer.
+
+ Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
+
+ @param Buffer Location to place the ASCII string of Value.
+ @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.
+ @param Radix Radix of the value
+
+ @return A pointer to the end of buffer filled with ASCII string.
+
+**/
+CHAR8 *
+InternalPrintLibValueToString (
+ IN OUT CHAR8 *Buffer,
+ IN INT64 Value,
+ IN UINTN Radix
+ )
+{
+ UINT32 Remainder;
+
+ //
+ // Loop to convert one digit at a time in reverse order
+ //
+ *Buffer = 0;
+ do {
+ Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
+ *(++Buffer) = mHexStr[Remainder];
+ } while (Value != 0);
+
+ //
+ // Return pointer of the end of filled buffer.
+ //
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+InternalPrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ );
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+EFIAPI
+InternalPrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = InternalPrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+#define WARNING_STATUS_NUMBER 5
+#define ERROR_STATUS_NUMBER 33
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST mStatusString[] = {
+ "Success", // RETURN_SUCCESS = 0
+ "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1
+ "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2
+ "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3
+ "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4
+ "Warning Stale Data", // RETURN_WARN_STALE_DATA = 5
+ "Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT
+ "Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT
+ "Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT
+ "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE = 4 | MAX_BIT
+ "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, = 5 | MAX_BIT
+ "Not Ready", // RETURN_NOT_READY = 6 | MAX_BIT
+ "Device Error", // RETURN_DEVICE_ERROR = 7 | MAX_BIT
+ "Write Protected", // RETURN_WRITE_PROTECTED = 8 | MAX_BIT
+ "Out of Resources", // RETURN_OUT_OF_RESOURCES = 9 | MAX_BIT
+ "Volume Corrupt", // RETURN_VOLUME_CORRUPTED = 10 | MAX_BIT
+ "Volume Full", // RETURN_VOLUME_FULL = 11 | MAX_BIT
+ "No Media", // RETURN_NO_MEDIA = 12 | MAX_BIT
+ "Media changed", // RETURN_MEDIA_CHANGED = 13 | MAX_BIT
+ "Not Found", // RETURN_NOT_FOUND = 14 | MAX_BIT
+ "Access Denied", // RETURN_ACCESS_DENIED = 15 | MAX_BIT
+ "No Response", // RETURN_NO_RESPONSE = 16 | MAX_BIT
+ "No mapping", // RETURN_NO_MAPPING = 17 | MAX_BIT
+ "Time out", // RETURN_TIMEOUT = 18 | MAX_BIT
+ "Not started", // RETURN_NOT_STARTED = 19 | MAX_BIT
+ "Already started", // RETURN_ALREADY_STARTED = 20 | MAX_BIT
+ "Aborted", // RETURN_ABORTED = 21 | MAX_BIT
+ "ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT
+ "TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT
+ "Protocol Error", // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT
+ "Incompatible Version", // RETURN_INCOMPATIBLE_VERSION = 25 | MAX_BIT
+ "Security Violation", // RETURN_SECURITY_VIOLATION = 26 | MAX_BIT
+ "CRC Error", // RETURN_CRC_ERROR = 27 | MAX_BIT
+ "End of Media", // RETURN_END_OF_MEDIA = 28 | MAX_BIT
+ "Reserved (29)", // RESERVED = 29 | MAX_BIT
+ "Reserved (30)", // RESERVED = 30 | MAX_BIT
+ "End of File", // RETURN_END_OF_FILE = 31 | MAX_BIT
+ "Invalid Language", // RETURN_INVALID_LANGUAGE = 32 | MAX_BIT
+ "Compromised Data" // RETURN_COMPROMISED_DATA = 33 | MAX_BIT
+};
+
+/**
+ Internal function that places the character into the Buffer.
+
+ Internal function that places ASCII or Unicode character into the Buffer.
+
+ @param Buffer The buffer to place the Unicode or ASCII string.
+ @param EndBuffer The end of the input Buffer. No characters will be
+ placed after that.
+ @param Length The count of character to be placed into Buffer.
+ (Negative value indicates no buffer fill.)
+ @param Character The character to be placed into Buffer.
+ @param Increment The character increment in Buffer.
+
+ @return Buffer.
+
+**/
+CHAR8 *
+InternalPrintLibFillBuffer (
+ OUT CHAR8 *Buffer,
+ IN CHAR8 *EndBuffer,
+ IN INTN Length,
+ IN UINTN Character,
+ IN INTN Increment
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
+ *Buffer = (CHAR8) Character;
+ if (Increment != 1) {
+ *(Buffer + 1) = (CHAR8)(Character >> 8);
+ }
+ Buffer += Increment;
+ }
+
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+InternalPrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ )
+{
+ CHAR8 *OriginalBuffer;
+ CHAR8 *EndBuffer;
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
+ UINT32 BytesPerOutputCharacter;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ UINTN Width;
+ UINTN Precision;
+ INT64 Value;
+ CONST CHAR8 *ArgumentString;
+ UINTN Character;
+ GUID *TmpGuid;
+ TIME *TmpTime;
+ UINTN Count;
+ UINTN ArgumentMask;
+ INTN BytesPerArgumentCharacter;
+ UINTN ArgumentCharacter;
+ BOOLEAN Done;
+ UINTN Index;
+ CHAR8 Prefix;
+ BOOLEAN ZeroPad;
+ BOOLEAN Comma;
+ UINTN Digits;
+ UINTN Radix;
+ RETURN_STATUS Status;
+ UINT32 GuidData1;
+ UINT16 GuidData2;
+ UINT16 GuidData3;
+ UINTN LengthToReturn;
+
+ //
+ // If you change this code be sure to match the 2 versions of this function.
+ // Nearly identical logic is found in the BasePrintLib and
+ // DxePrintLibPrint2Protocol (both PrintLib instances).
+ //
+
+ //
+ // 1. Buffer shall not be a null pointer when both BufferSize > 0 and
+ // COUNT_ONLY_NO_PRINT is not set in Flags.
+ //
+ if ((BufferSize > 0) && ((Flags & COUNT_ONLY_NO_PRINT) == 0)) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), 0);
+ }
+
+ //
+ // 2. Format shall not be a null pointer when BufferSize > 0 or when
+ // COUNT_ONLY_NO_PRINT is set in Flags.
+ //
+ if ((BufferSize > 0) || ((Flags & COUNT_ONLY_NO_PRINT) != 0)) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((Format != NULL), 0);
+ }
+
+ //
+ // 3. BufferSize shall not be greater than RSIZE_MAX for Unicode output or
+ // ASCII_RSIZE_MAX for Ascii output.
+ //
+ if ((Flags & OUTPUT_UNICODE) != 0) {
+ if (RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX), 0);
+ }
+ BytesPerOutputCharacter = 2;
+ } else {
+ if (ASCII_RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), 0);
+ }
+ BytesPerOutputCharacter = 1;
+ }
+
+ //
+ // 4. Format shall not contain more than RSIZE_MAX Unicode characters or
+ // ASCII_RSIZE_MAX Ascii characters.
+ //
+ if ((Flags & FORMAT_UNICODE) != 0) {
+ if (RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((StrnLenS ((CHAR16 *)Format, RSIZE_MAX + 1) <= RSIZE_MAX), 0);
+ }
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ } else {
+ if (ASCII_RSIZE_MAX != 0) {
+ SAFE_PRINT_CONSTRAINT_CHECK ((AsciiStrnLenS (Format, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), 0);
+ }
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ }
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ if (BufferSize == 0) {
+ Buffer = NULL;
+ }
+ } else {
+ //
+ // We can run without a Buffer for counting only.
+ //
+ if (BufferSize == 0) {
+ return 0;
+ }
+ }
+
+ LengthToReturn = 0;
+ EndBuffer = NULL;
+ OriginalBuffer = NULL;
+
+ //
+ // Reserve space for the Null terminator.
+ //
+ if (Buffer != NULL) {
+ BufferSize--;
+ OriginalBuffer = Buffer;
+
+ //
+ // Set the tag for the end of the input Buffer.
+ //
+ EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+
+ //
+ // Loop until the end of the format string is reached or the output buffer is full
+ //
+ while (FormatCharacter != 0) {
+ if ((Buffer != NULL) && (Buffer >= EndBuffer)) {
+ break;
+ }
+ //
+ // Clear all the flag bits except those that may have been passed in
+ //
+ Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
+
+ //
+ // Set the default width to zero, and the default precision to 1
+ //
+ Width = 0;
+ Precision = 1;
+ Prefix = 0;
+ Comma = FALSE;
+ ZeroPad = FALSE;
+ Count = 0;
+ Digits = 0;
+
+ switch (FormatCharacter) {
+ case '%':
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ switch (FormatCharacter) {
+ case '.':
+ Flags |= PRECISION;
+ break;
+ case '-':
+ Flags |= LEFT_JUSTIFY;
+ break;
+ case '+':
+ Flags |= PREFIX_SIGN;
+ break;
+ case ' ':
+ Flags |= PREFIX_BLANK;
+ break;
+ case ',':
+ Flags |= COMMA_TYPE;
+ break;
+ case 'L':
+ case 'l':
+ Flags |= LONG_TYPE;
+ break;
+ case '*':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ if (BaseListMarker == NULL) {
+ Width = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Width = BASE_ARG (BaseListMarker, UINTN);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Precision = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Precision = BASE_ARG (BaseListMarker, UINTN);
+ }
+ }
+ break;
+ case '0':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PREFIX_ZERO;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
+ Count = (Count * 10) + FormatCharacter - '0';
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ }
+ Format -= BytesPerFormatCharacter;
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ Width = Count;
+ } else {
+ Precision = Count;
+ }
+ break;
+
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ Precision = 0;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ //
+ // Flag space, +, 0, L & l are invalid for type p.
+ //
+ Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));
+ if (sizeof (VOID *) > 4) {
+ Flags |= LONG_TYPE;
+ }
+ //
+ // break skipped on purpose
+ //
+ case 'X':
+ Flags |= PREFIX_ZERO;
+ //
+ // break skipped on purpose
+ //
+ case 'x':
+ Flags |= RADIX_HEX;
+ //
+ // break skipped on purpose
+ //
+ case 'u':
+ if ((Flags & RADIX_HEX) == 0) {
+ Flags &= ~((UINTN) (PREFIX_SIGN));
+ Flags |= UNSIGNED_TYPE;
+ }
+ //
+ // break skipped on purpose
+ //
+ case 'd':
+ if ((Flags & LONG_TYPE) == 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "int" is used in this one case.
+ //
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, int);
+ } else {
+ Value = BASE_ARG (BaseListMarker, int);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, INT64);
+ } else {
+ Value = BASE_ARG (BaseListMarker, INT64);
+ }
+ }
+ if ((Flags & PREFIX_BLANK) != 0) {
+ Prefix = ' ';
+ }
+ if ((Flags & PREFIX_SIGN) != 0) {
+ Prefix = '+';
+ }
+ if ((Flags & COMMA_TYPE) != 0) {
+ Comma = TRUE;
+ }
+ if ((Flags & RADIX_HEX) == 0) {
+ Radix = 10;
+ if (Comma) {
+ Flags &= ~((UINTN) PREFIX_ZERO);
+ Precision = 1;
+ }
+ if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {
+ Flags |= PREFIX_SIGN;
+ Prefix = '-';
+ Value = -Value;
+ } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ } else {
+ Radix = 16;
+ Comma = FALSE;
+ if ((Flags & LONG_TYPE) == 0 && Value < 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ }
+ //
+ // Convert Value to a reversed string
+ //
+ Count = InternalPrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
+ if (Value == 0 && Precision == 0) {
+ Count = 0;
+ }
+ ArgumentString = (CHAR8 *)ValueBuffer + Count;
+
+ Digits = Count % 3;
+ if (Digits != 0) {
+ Digits = 3 - Digits;
+ }
+ if (Comma && Count != 0) {
+ Count += ((Count - 1) / 3);
+ }
+ if (Prefix != 0) {
+ Count++;
+ Precision++;
+ }
+ Flags |= ARGUMENT_REVERSED;
+ ZeroPad = TRUE;
+ if ((Flags & PREFIX_ZERO) != 0) {
+ if ((Flags & LEFT_JUSTIFY) == 0) {
+ if ((Flags & PAD_TO_WIDTH) != 0) {
+ if ((Flags & PRECISION) == 0) {
+ Precision = Width;
+ }
+ }
+ }
+ }
+ break;
+
+ case 's':
+ case 'S':
+ Flags |= ARGUMENT_UNICODE;
+ //
+ // break skipped on purpose
+ //
+ case 'a':
+ if (BaseListMarker == NULL) {
+ ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
+ } else {
+ ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
+ }
+ if (ArgumentString == NULL) {
+ Flags &= (~(UINTN)ARGUMENT_UNICODE);
+ ArgumentString = "<null string>";
+ }
+ //
+ // Set the default precision for string to be zero if not specified.
+ //
+ if ((Flags & PRECISION) == 0) {
+ Precision = 0;
+ }
+ break;
+
+ case 'c':
+ if (BaseListMarker == NULL) {
+ Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
+ } else {
+ Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
+ }
+ ArgumentString = (CHAR8 *)&Character;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+
+ case 'g':
+ if (BaseListMarker == NULL) {
+ TmpGuid = VA_ARG (VaListMarker, GUID *);
+ } else {
+ TmpGuid = BASE_ARG (BaseListMarker, GUID *);
+ }
+ if (TmpGuid == NULL) {
+ ArgumentString = "<null guid>";
+ } else {
+ GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
+ GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));
+ GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));
+ InternalPrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ GuidData1,
+ GuidData2,
+ GuidData3,
+ TmpGuid->Data4[0],
+ TmpGuid->Data4[1],
+ TmpGuid->Data4[2],
+ TmpGuid->Data4[3],
+ TmpGuid->Data4[4],
+ TmpGuid->Data4[5],
+ TmpGuid->Data4[6],
+ TmpGuid->Data4[7]
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 't':
+ if (BaseListMarker == NULL) {
+ TmpTime = VA_ARG (VaListMarker, TIME *);
+ } else {
+ TmpTime = BASE_ARG (BaseListMarker, TIME *);
+ }
+ if (TmpTime == NULL) {
+ ArgumentString = "<null time>";
+ } else {
+ InternalPrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%02d/%02d/%04d %02d:%02d",
+ TmpTime->Month,
+ TmpTime->Day,
+ TmpTime->Year,
+ TmpTime->Hour,
+ TmpTime->Minute
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 'r':
+ if (BaseListMarker == NULL) {
+ Status = VA_ARG (VaListMarker, RETURN_STATUS);
+ } else {
+ Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
+ }
+ ArgumentString = ValueBuffer;
+ if (RETURN_ERROR (Status)) {
+ //
+ // Clear error bit
+ //
+ Index = Status & ~MAX_BIT;
+ if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
+ }
+ } else {
+ Index = Status;
+ if (Index <= WARNING_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index];
+ }
+ }
+ if (ArgumentString == ValueBuffer) {
+ InternalPrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '%':
+ default:
+ //
+ // if the type is '%' or unknown, then print it to the screen
+ //
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ default:
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+
+ //
+ // Retrieve the ArgumentString attriubutes
+ //
+ if ((Flags & ARGUMENT_UNICODE) != 0) {
+ ArgumentMask = 0xffff;
+ BytesPerArgumentCharacter = 2;
+ } else {
+ ArgumentMask = 0xff;
+ BytesPerArgumentCharacter = 1;
+ }
+ if ((Flags & ARGUMENT_REVERSED) != 0) {
+ BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
+ } else {
+ //
+ // Compute the number of characters in ArgumentString and store it in Count
+ // ArgumentString is either null-terminated, or it contains Precision characters
+ //
+ for (Count = 0;
+ (ArgumentString[Count * BytesPerArgumentCharacter] != '\0' ||
+ (BytesPerArgumentCharacter > 1 &&
+ ArgumentString[Count * BytesPerArgumentCharacter + 1]!= '\0')) &&
+ (Count < Precision || ((Flags & PRECISION) == 0));
+ Count++) {
+ ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
+ if (ArgumentCharacter == 0) {
+ break;
+ }
+ }
+ }
+
+ if (Precision < Count) {
+ Precision = Count;
+ }
+
+ //
+ // Pad before the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ if (ZeroPad) {
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
+ }
+ } else {
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
+ }
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ }
+
+ //
+ // Output the Prefix character if it is present
+ //
+ Index = 0;
+ if (Prefix != 0) {
+ Index++;
+ }
+
+ //
+ // Copy the string into the output buffer performing the required type conversions
+ //
+ while (Index < Count &&
+ (ArgumentString[0] != '\0' ||
+ (BytesPerArgumentCharacter > 1 && ArgumentString[1] != '\0'))) {
+ ArgumentCharacter = ((*ArgumentString & 0xff) | (((UINT8)*(ArgumentString + 1)) << 8)) & ArgumentMask;
+
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
+ }
+ ArgumentString += BytesPerArgumentCharacter;
+ Index++;
+ if (Comma) {
+ Digits++;
+ if (Digits == 3) {
+ Digits = 0;
+ Index++;
+ if (Index < Count) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Pad after the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;
+ }
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ return (LengthToReturn / BytesPerOutputCharacter);
+ }
+
+ ASSERT (Buffer != NULL);
+ //
+ // Null terminate the Unicode or ASCII string
+ //
+ InternalPrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
+
+ return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
+}
+
+/**
+ Returns the number of characters that would be produced by if the formatted
+ output were produced not including the Null-terminator.
+
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If FormatString is NULL, then ASSERT() and 0 is returned.
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more
+ than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT() and 0 is returned.
+
+ @param[in] FormatString A Null-terminated Unicode format string.
+ @param[in] Marker VA_LIST marker for the variable argument list.
+
+ @return The number of characters that would be produced, not including the
+ Null-terminator.
+**/
+UINTN
+EFIAPI
+SPrintLength (
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (FormatString);
+ return InternalPrintLibSPrintMarker (NULL, 0, FORMAT_UNICODE | OUTPUT_UNICODE | COUNT_ONLY_NO_PRINT, (CHAR8 *)FormatString, Marker, NULL);
+}
+
+/**
+ Returns the number of characters that would be produced by if the formatted
+ output were produced not including the Null-terminator.
+
+ If FormatString is NULL, then ASSERT() and 0 is returned.
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more
+ than PcdMaximumAsciiStringLength Ascii characters not including the
+ Null-terminator, then ASSERT() and 0 is returned.
+
+ @param[in] FormatString A Null-terminated ASCII format string.
+ @param[in] Marker VA_LIST marker for the variable argument list.
+
+ @return The number of characters that would be produced, not including the
+ Null-terminator.
+**/
+UINTN
+EFIAPI
+SPrintLengthAsciiFormat (
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ return InternalPrintLibSPrintMarker (NULL, 0, OUTPUT_UNICODE | COUNT_ONLY_NO_PRINT, (CHAR8 *)FormatString, Marker, NULL);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
new file mode 100644
index 000000000..620763a73
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
@@ -0,0 +1,52 @@
+## @file
+# DXE report status code library.
+#
+# Retrieve status code and report status code in DXE phase.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeReportStatusCodeLib
+ MODULE_UNI_FILE = DxeReportStatusCodeLib.uni
+ FILE_GUID = EBF144C8-70F5-4e09-ADE2-F41F5C59AFDA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_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 EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ PcdLib
+ DevicePathLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni
new file mode 100644
index 000000000..fe7e9f942
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// DXE report status code library.
+//
+// Retrieve status code and report status code in DXE phase.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "DXE report status code library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Retrieve status code and report status code in DXE phase."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 000000000..92559a54f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,622 @@
+/** @file
+ Report Status Code Library for DXE Phase.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/StatusCode.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.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_STATUS_CODE_PROTOCOL *mReportStatusCodeLibStatusCodeProtocol = NULL;
+
+/**
+ Locate the report status code service.
+
+ Retrieve ReportStatusCode() API of Report Status Code Protocol.
+
+**/
+VOID
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mReportStatusCodeLibStatusCodeProtocol != NULL) {
+ return;
+ }
+
+ //
+ // Check gBS just in case ReportStatusCode is called before gBS is initialized.
+ //
+ if (gBS != NULL && gBS->LocateProtocol != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**) &mReportStatusCodeLibStatusCodeProtocol);
+ if (EFI_ERROR (Status)) {
+ mReportStatusCodeLibStatusCodeProtocol = NULL;
+ }
+ }
+}
+
+/**
+ Internal worker function that reports a status code through the Report Status Code Protocol.
+
+ If status code service is not cached, then this function checks if Report Status Code
+ Protocol is available in system. If Report Status Code Protocol is not available, then
+ EFI_UNSUPPORTED is returned. If Report Status Code Protocol is present, then it is
+ cached in mReportStatusCodeLibStatusCodeProtocol. Finally this function reports status
+ code through the Report Status Code Protocol.
+
+ @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 Report Status Code Protocol 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 mReportStatusCodeLibStatusCodeProtocol is NULL, then check if Report Status Code Protocol is available in system.
+ //
+ InternalGetReportStatusCode ();
+ if (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // A Report Status Code Protocol is present in system, so pass in all the parameters to the service.
+ //
+ return mReportStatusCodeLibStatusCodeProtocol->ReportStatusCode (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 (ExtendedDataSize <= (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {
+ //
+ // Use Buffer instead of allocating if possible.
+ //
+ StatusCodeData = (EFI_STATUS_CODE_DATA *)Buffer;
+ } else {
+ 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);
+
+ if (Tpl > TPL_NOTIFY) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ StatusCodeData = NULL;
+ gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize, (VOID **)&StatusCodeData);
+ if (StatusCodeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // 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/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c
new file mode 100644
index 000000000..47b814fe8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.c
@@ -0,0 +1,103 @@
+/** @file
+ DXE Reset System Library instance that calls gRT->ResetSystem().
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ )
+{
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ )
+{
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ )
+{
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a systemwide reset. The exact type of the reset is
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+ the platform must pick a supported reset type to perform.The platform may
+ optionally log the parameters from any non-normal reset that occurs.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData The data buffer starts with a Null-terminated string,
+ followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+ IN UINTN DataSize,
+ IN VOID *ResetData
+ )
+{
+ gRT->ResetSystem (EfiResetPlatformSpecific, EFI_SUCCESS, DataSize, ResetData);
+}
+
+/**
+ The ResetSystem function resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ gRT->ResetSystem (ResetType, ResetStatus, DataSize, ResetData);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf
new file mode 100644
index 000000000..e9d2c0b66
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf
@@ -0,0 +1,36 @@
+## @file
+# DXE Reset System Library instance that calls gRT->ResetSystem().
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeResetSystemLib
+ MODULE_UNI_FILE = DxeResetSystemLib.uni
+ FILE_GUID = C2BDE4F6-65EE-440B-87B5-83ABF10EF45B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ResetSystemLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeResetSystemLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+
+[Depex]
+ gEfiResetArchProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.uni b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.uni
new file mode 100644
index 000000000..c2ce4a04c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// DXE Reset System Library instance that calls gRT->ResetSystem().
+//
+// DXE Reset System Library instance that calls gRT->ResetSystem().
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "DXE Reset System Library instance that calls gRT->ResetSystem()"
+
+#string STR_MODULE_DESCRIPTION #language en-US "DXE Reset System Library instance that calls gRT->ResetSystem()."
+
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c
new file mode 100644
index 000000000..3bba38b57
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTest.c
@@ -0,0 +1,312 @@
+/** @file
+ Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class
+
+ Copyright (C) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Library/UnitTestLib.h>
+#include <Library/ResetSystemLib.h>
+
+#define UNIT_TEST_APP_NAME "DxeResetSystemLib Unit Tests"
+#define UNIT_TEST_APP_VERSION "1.0"
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+**/
+STATIC
+VOID
+EFIAPI
+MockResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ check_expected_ptr (ResetType);
+ check_expected_ptr (ResetStatus);
+
+ //
+ // NOTE: Mocked functions can also return values, but that
+ // is for another demo.
+}
+
+///
+/// Mock version of the UEFI Runtime Services Table
+///
+EFI_RUNTIME_SERVICES MockRuntime = {
+ {
+ EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
+ EFI_RUNTIME_SERVICES_REVISION, // Revision
+ sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ NULL, // GetTime
+ NULL, // SetTime
+ NULL, // GetWakeupTime
+ NULL, // SetWakeupTime
+ NULL, // SetVirtualAddressMap
+ NULL, // ConvertPointer
+ NULL, // GetVariable
+ NULL, // GetNextVariableName
+ NULL, // SetVariable
+ NULL, // GetNextHighMonotonicCount
+ MockResetSystem, // ResetSystem
+ NULL, // UpdateCapsule
+ NULL, // QueryCapsuleCapabilities
+ NULL // QueryVariableInfo
+};
+
+/**
+ Unit test for ColdReset () API of the ResetSystemLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ResetColdShouldIssueAColdReset (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ expect_value (MockResetSystem, ResetType, EfiResetCold);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetCold ();
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test for WarmReset () API of the ResetSystemLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ResetWarmShouldIssueAWarmReset (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ expect_value (MockResetSystem, ResetType, EfiResetWarm);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetWarm ();
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test for ResetShutdown () API of the ResetSystemLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ResetShutdownShouldIssueAShutdown (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ expect_value (MockResetSystem, ResetType, EfiResetShutdown);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetShutdown ();
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test for ResetPlatformSpecific () API of the ResetSystemLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ResetPlatformSpecificShouldIssueAPlatformSpecificReset (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ expect_value (MockResetSystem, ResetType, EfiResetPlatformSpecific);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetPlatformSpecific (0, NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test for ResetSystem () API of the ResetSystemLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ResetSystemShouldPassTheParametersThrough (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ expect_value (MockResetSystem, ResetType, EfiResetCold);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ expect_value (MockResetSystem, ResetType, EfiResetShutdown);
+ expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS);
+
+ ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Initialze the unit test framework, suite, and unit tests for the
+ ResetSystemLib and run the ResetSystemLib unit test.
+
+ @retval EFI_SUCCESS All test cases were dispatched.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ initialize the unit tests.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UnitTestingEntry (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE ResetTests;
+
+ Framework = NULL;
+
+ DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION ));
+
+ //
+ // Start setting up the test framework for running the tests.
+ //
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Populate the ResetSytemLib Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (&ResetTests, Framework, "DxeResetSystemLib Reset Tests", "ResetSystemLib.Reset", NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ResetTests\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context-----------
+ //
+ AddTestCase (ResetTests, "ResetCold should issue a cold reset", "Cold", ResetColdShouldIssueAColdReset, NULL, NULL, NULL);
+ AddTestCase (ResetTests, "ResetWarm should issue a warm reset", "Warm", ResetWarmShouldIssueAWarmReset, NULL, NULL, NULL);
+ AddTestCase (ResetTests, "ResetShutdown should issue a shutdown", "Shutdown", ResetShutdownShouldIssueAShutdown, NULL, NULL, NULL);
+ AddTestCase (ResetTests, "ResetPlatformSpecific should issue a platform-specific reset", "Platform", ResetPlatformSpecificShouldIssueAPlatformSpecificReset, NULL, NULL, NULL);
+ AddTestCase (ResetTests, "ResetSystem should pass all parameters through", "Parameters", ResetSystemShouldPassTheParametersThrough, NULL, NULL, NULL);
+
+ //
+ // Execute the tests.
+ //
+ Status = RunAllTestSuites (Framework);
+
+EXIT:
+ if (Framework) {
+ FreeUnitTestFramework (Framework);
+ }
+
+ return Status;
+}
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ )
+{
+ return UnitTestingEntry ();
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf
new file mode 100644
index 000000000..54f968e81
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf
@@ -0,0 +1,34 @@
+## @file
+# Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class
+#
+# Copyright (C) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = DxeResetSystemLibUnitTestHost
+ FILE_GUID = 83E35653-B943-4C5F-BA08-9B2996AE9273
+ MODULE_TYPE = HOST_APPLICATION
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DxeResetSystemLibUnitTest.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ ResetSystemLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UnitTestLib
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c
new file mode 100644
index 000000000..3540e1c03
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.c
@@ -0,0 +1,13 @@
+/** @file
+ Mock implementation of the UEFI Runtime Services Table Library.
+
+ Copyright (C) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+extern EFI_RUNTIME_SERVICES MockRuntime;
+
+EFI_RUNTIME_SERVICES *gRT = &MockRuntime;
diff --git a/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf
new file mode 100644
index 000000000..e716b855a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf
@@ -0,0 +1,25 @@
+## @file
+# Mock implementation of the UEFI Runtime Services Table Library.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MockUefiRuntimeServicesTableLib
+ FILE_GUID = 4EA215EE-85C1-4A0A-847F-D2A8DE20805F
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiRuntimeServicesTableLib|HOST_APPLICATION
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MockUefiRuntimeServicesTableLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c
new file mode 100644
index 000000000..de1eb5318
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c
@@ -0,0 +1,529 @@
+/** @file
+ Provides generic security measurement functions for DXE module.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/LoadFile.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define SECURITY_HANDLER_TABLE_SIZE 0x10
+
+//
+// Secruity Operation on Image and none Image.
+//
+#define EFI_AUTH_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_VERIFY_IMAGE \
+ | EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \
+ | EFI_AUTH_OPERATION_MEASURE_IMAGE)
+#define EFI_AUTH_NONE_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_CONNECT_POLICY \
+ | EFI_AUTH_OPERATION_AUTHENTICATION_STATE)
+
+typedef struct {
+ UINT32 SecurityOperation;
+ SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler;
+} SECURITY_INFO;
+
+typedef struct {
+ UINT32 Security2Operation;
+ SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler;
+} SECURITY2_INFO;
+
+UINT32 mCurrentAuthOperation = 0;
+UINT32 mNumberOfSecurityHandler = 0;
+UINT32 mMaxNumberOfSecurityHandler = 0;
+SECURITY_INFO *mSecurityTable = NULL;
+
+UINT32 mCurrentAuthOperation2 = 0;
+UINT32 mNumberOfSecurity2Handler = 0;
+UINT32 mMaxNumberOfSecurity2Handler = 0;
+SECURITY2_INFO *mSecurity2Table = NULL;
+
+/**
+ Reallocates more global memory to store the registered Handler list.
+
+ @retval RETURN_SUCCESS Reallocate memory successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.
+**/
+RETURN_STATUS
+EFIAPI
+ReallocateSecurityHandlerTable (
+ VOID
+ )
+{
+ //
+ // Reallocate memory for security info structure.
+ //
+ mSecurityTable = ReallocatePool (
+ mMaxNumberOfSecurityHandler * sizeof (SECURITY_INFO),
+ (mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY_INFO),
+ mSecurityTable
+ );
+
+ //
+ // No enough resource is allocated.
+ //
+ if (mSecurityTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Increase max handler number
+ //
+ mMaxNumberOfSecurityHandler = mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Check whether an operation is valid according to the requirement of current operation,
+ which must make sure that the measure image operation is the last one.
+
+ @param CurrentAuthOperation Current operation.
+ @param CheckAuthOperation Operation to be checked.
+
+ @retval TRUE Operation is valid for current operation.
+ @retval FALSE Operation is invalid for current operation.
+**/
+BOOLEAN
+CheckAuthenticationOperation (
+ IN UINT32 CurrentAuthOperation,
+ IN UINT32 CheckAuthOperation
+ )
+{
+ //
+ // Make sure new auth operation can be recognized.
+ //
+ ASSERT ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK | EFI_AUTH_OPERATION_AUTHENTICATION_STATE | EFI_AUTH_OPERATION_IMAGE_REQUIRED)) == 0);
+
+ //
+ // When current operation includes measure image operation,
+ // only another measure image operation or none operation will be allowed.
+ //
+ if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {
+ if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||
+ ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == EFI_AUTH_OPERATION_NONE)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ //
+ // When current operation doesn't include measure image operation,
+ // any new operation will be allowed.
+ //
+ return TRUE;
+}
+
+/**
+ Register security measurement handler with its operation type. The different
+ handler with the same operation can all be registered.
+
+ If SecurityHandler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] SecurityHandler Security measurement service handler to be registered.
+ @param[in] AuthenticationOperation Operation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurityHandler (
+ IN SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler,
+ IN UINT32 AuthenticationOperation
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (SecurityHandler != NULL);
+
+ //
+ // Make sure AuthenticationOperation is valid in the register order.
+ //
+ ASSERT (CheckAuthenticationOperation (mCurrentAuthOperation, AuthenticationOperation));
+ mCurrentAuthOperation = mCurrentAuthOperation | AuthenticationOperation;
+
+ //
+ // Check whether the handler lists is enough to store new handler.
+ //
+ if (mNumberOfSecurityHandler == mMaxNumberOfSecurityHandler) {
+ //
+ // Allocate more resources for new handler.
+ //
+ Status = ReallocateSecurityHandlerTable();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Register new handler into the handler list.
+ //
+ mSecurityTable[mNumberOfSecurityHandler].SecurityOperation = AuthenticationOperation;
+ mSecurityTable[mNumberOfSecurityHandler].SecurityHandler = SecurityHandler;
+ mNumberOfSecurityHandler ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute registered handlers until one returns an error and that error is returned.
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+
+ Before exectue handler, get the image buffer by file device path if a handler
+ requires the image file. And return the image buffer to each handler when exectue handler.
+
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationStatus
+ This is the authentication type returned from the Section
+ Extraction protocol. See the Section Extraction Protocol
+ Specification for details on this type.
+ @param[in] FilePath This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate when more
+ than one security handler services were registered,
+ or the file did not authenticate when no security
+ handler service was registered. And the platform policy
+ dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurityHandlers (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ UINT32 HandlerAuthenticationStatus;
+ VOID *FileBuffer;
+ UINTN FileSize;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathToVerfiy;
+
+ if (FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Directly return successfully when no handler is registered.
+ //
+ if (mNumberOfSecurityHandler == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ FileBuffer = NULL;
+ FileSize = 0;
+ HandlerAuthenticationStatus = AuthenticationStatus;
+ FilePathToVerfiy = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;
+ //
+ // Run security handler in same order to their registered list
+ //
+ for (Index = 0; Index < mNumberOfSecurityHandler; Index ++) {
+ if ((mSecurityTable[Index].SecurityOperation & EFI_AUTH_OPERATION_IMAGE_REQUIRED) == EFI_AUTH_OPERATION_IMAGE_REQUIRED) {
+ //
+ // Try get file buffer when the handler requires image buffer.
+ //
+ if (FileBuffer == NULL) {
+ Node = FilePathToVerfiy;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ //
+ // Try to get image by FALSE boot policy for the exact boot file path.
+ //
+ FileBuffer = GetFileBufferByFilePath (FALSE, FilePath, &FileSize, &AuthenticationStatus);
+ if (FileBuffer == NULL) {
+ //
+ // Try to get image by TRUE boot policy for the inexact boot file path.
+ //
+ FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, &FileSize, &AuthenticationStatus);
+ }
+ if ((FileBuffer != NULL) && (!EFI_ERROR (Status))) {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ FilePathToVerfiy = AppendDevicePath (DevicePathFromHandle (Handle), Node);
+ }
+ }
+ }
+ Status = mSecurityTable[Index].SecurityHandler (
+ HandlerAuthenticationStatus,
+ FilePathToVerfiy,
+ FileBuffer,
+ FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+ if (FilePathToVerfiy != FilePath) {
+ FreePool (FilePathToVerfiy);
+ }
+
+ return Status;
+}
+
+/**
+ Reallocates more global memory to store the registered Securit2Handler list.
+
+ @retval RETURN_SUCCESS Reallocate memory successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.
+**/
+RETURN_STATUS
+EFIAPI
+ReallocateSecurity2HandlerTable (
+ VOID
+ )
+{
+ //
+ // Reallocate memory for security info structure.
+ //
+ mSecurity2Table = ReallocatePool (
+ mMaxNumberOfSecurity2Handler * sizeof (SECURITY2_INFO),
+ (mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY2_INFO),
+ mSecurity2Table
+ );
+
+ //
+ // No enough resource is allocated.
+ //
+ if (mSecurity2Table == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Increase max handler number
+ //
+ mMaxNumberOfSecurity2Handler = mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Check whether an operation is valid according to the requirement of current operation,
+ which must make sure that the measure image operation is the last one.
+
+ If AuthenticationOperation is not recongnized, return FALSE.
+ If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, return FALSE.
+ If AuthenticationOperation includes security operation and authentication operation, return FALSE.
+ If the previous register handler can't be executed before the later register handler, return FALSE.
+
+ @param CurrentAuthOperation Current operation.
+ @param CheckAuthOperation Operation to be checked.
+
+ @retval TRUE Operation is valid for current operation.
+ @retval FALSE Operation is invalid for current operation.
+**/
+BOOLEAN
+CheckAuthentication2Operation (
+ IN UINT32 CurrentAuthOperation,
+ IN UINT32 CheckAuthOperation
+ )
+{
+ //
+ // Make sure new auth operation can be recognized.
+ //
+ if (CheckAuthOperation == EFI_AUTH_OPERATION_NONE) {
+ return FALSE;
+ }
+ if ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK |
+ EFI_AUTH_NONE_IMAGE_OPERATION_MASK |
+ EFI_AUTH_OPERATION_IMAGE_REQUIRED)) != 0) {
+ return FALSE;
+ }
+
+ //
+ // When current operation includes measure image operation,
+ // only another measure image or none image operation will be allowed.
+ //
+ if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {
+ if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||
+ ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ //
+ // Any other operation will be allowed.
+ //
+ return TRUE;
+}
+
+/**
+ Register security measurement handler with its operation type. Different
+ handlers with the same operation can all be registered.
+
+ If Security2Handler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] Security2Handler The security measurement service handler to be registered.
+ @param[in] AuthenticationOperation The operation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurity2Handler (
+ IN SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler,
+ IN UINT32 AuthenticationOperation
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Security2Handler != NULL);
+
+ //
+ // Make sure AuthenticationOperation is valid in the register order.
+ //
+ ASSERT (CheckAuthentication2Operation (mCurrentAuthOperation2, AuthenticationOperation));
+ mCurrentAuthOperation2 = mCurrentAuthOperation2 | AuthenticationOperation;
+
+ //
+ // Check whether the handler lists is enough to store new handler.
+ //
+ if (mNumberOfSecurity2Handler == mMaxNumberOfSecurity2Handler) {
+ //
+ // Allocate more resources for new handler.
+ //
+ Status = ReallocateSecurity2HandlerTable();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Register new handler into the handler list.
+ //
+ mSecurity2Table[mNumberOfSecurity2Handler].Security2Operation = AuthenticationOperation;
+ mSecurity2Table[mNumberOfSecurity2Handler].Security2Handler = Security2Handler;
+ mNumberOfSecurity2Handler ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute registered handlers based on input AuthenticationOperation until
+ one returns an error and that error is returned.
+
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+ The handlers those satisfy AuthenticationOperation will only be executed.
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationOperation
+ The operation type specifies which handlers will be executed.
+ @param[in] AuthenticationStatus
+ The authentication status for the input file.
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer A pointer to the buffer with the UEFI file image
+ @param[in] FileSize The size of File buffer.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SECURITY_VIOLATION The file specified by File or FileBuffer did not
+ authenticate, and the platform policy dictates that
+ the file should be placed in the untrusted state.
+ @retval EFI_SECURITY_VIOLATION FileBuffer FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that the DXE
+ Foundation may not use File.
+ @retval EFI_INVALID_PARAMETER File and FileBuffer are both NULL.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurity2Handlers (
+ IN UINT32 AuthenticationOperation,
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+
+ //
+ // Invalid case if File and FileBuffer are both NULL.
+ //
+ if (File == NULL && FileBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Directly return successfully when no handler is registered.
+ //
+ if (mNumberOfSecurity2Handler == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Run security handler in same order to their registered list
+ //
+ for (Index = 0; Index < mNumberOfSecurity2Handler; Index ++) {
+ //
+ // If FileBuffer is not NULL, the input is Image, which will be handled by EFI_AUTH_IMAGE_OPERATION_MASK operation.
+ // If FileBuffer is NULL, the input is not Image, which will be handled by EFI_AUTH_NONE_IMAGE_OPERATION_MASK operation.
+ // Other cases are ignored.
+ //
+ if ((FileBuffer != NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_IMAGE_OPERATION_MASK) != 0) ||
+ (FileBuffer == NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_NONE_IMAGE_OPERATION_MASK) != 0)) {
+ //
+ // Execute registered handlers based on input AuthenticationOperation
+ //
+ if ((mSecurity2Table[Index].Security2Operation & AuthenticationOperation) != 0) {
+ Status = mSecurity2Table[Index].Security2Handler (
+ AuthenticationStatus,
+ File,
+ FileBuffer,
+ FileSize,
+ BootPolicy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
new file mode 100644
index 000000000..bdd488472
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
@@ -0,0 +1,43 @@
+## @file
+# Instance of SecurityManagementLib Library for DXE phase.
+#
+# This library provides generic security measurement functions for DXE module.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeSecurityManagementLib
+ MODULE_UNI_FILE = DxeSecurityManagementLib.uni
+ FILE_GUID = 7F61122C-19DF-47c3-BA0D-6C1149E30FA1
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SecurityManagementLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeSecurityManagementLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DebugLib
+ DxeServicesLib
+ DevicePathLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni
new file mode 100644
index 000000000..faf483a34
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Instance of SecurityManagementLib Library for DXE phase.
+//
+// This library provides generic security measurement functions for DXE module.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of SecurityManagementLib Library for the DXE phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides generic security measurement functions for DXE module."
+
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
new file mode 100644
index 000000000..58e491025
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
@@ -0,0 +1,1653 @@
+/** @file
+File explorer related functions.
+
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "FileExplorer.h"
+
+EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID;
+
+///
+/// File system selection menu
+///
+MENU_OPTION mFsOptionMenu = {
+ MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0,
+ FALSE
+};
+
+FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = {
+ FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ LibExtractConfig,
+ LibRouteConfig,
+ LibCallback
+ },
+ NULL,
+ &mFsOptionMenu,
+ 0
+};
+
+HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath;
+
+HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ //
+ // Will be replace with gEfiCallerIdGuid in code.
+ //
+ { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+VOID *mLibStartOpCodeHandle = NULL;
+VOID *mLibEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mLibStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mLibEndLabel = NULL;
+UINT16 mQuestionIdUpdate;
+CHAR16 mNewFileName[MAX_FILE_NAME_LEN];
+CHAR16 mNewFolderName[MAX_FOLDER_NAME_LEN];
+UINTN mNewFileQuestionId = NEW_FILE_QUESTION_ID_BASE;
+UINTN mNewFolderQuestionId = NEW_FOLDER_QUESTION_ID_BASE;
+
+/**
+ Create a new file or folder in current directory.
+
+ @param FileName Point to the fileNmae or folder.
+ @param CreateFile CreateFile== TRUE means create a new file.
+ CreateFile== FALSE means create a new Folder.
+
+**/
+EFI_STATUS
+LibCreateNewFile (
+ IN CHAR16 *FileName,
+ IN BOOLEAN CreateFile
+ );
+
+/**
+ 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_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
+LibExtractConfig (
+ 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_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRouteConfig (
+ 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;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ 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) Process the axtra action or exit file explorer when user select one file .
+ 2) update of file content if a dir is selected.
+
+ @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 other error Error occur when parse one directory.
+**/
+EFI_STATUS
+EFIAPI
+LibCallback (
+ 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
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedExit;
+ CHAR16 *NewFileName;
+ CHAR16 *NewFolderName;
+
+ NeedExit = TRUE;
+ NewFileName = NULL;
+ NewFolderName = NULL;
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (QuestionId == KEY_VALUE_CREATE_FILE_AND_EXIT) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ if (!IsZeroBuffer (mNewFileName, sizeof (mNewFileName))) {
+ Status = LibCreateNewFile (mNewFileName,TRUE);
+ ZeroMem (mNewFileName,sizeof (mNewFileName));
+ }
+ }
+
+ if (QuestionId == KEY_VALUE_NO_CREATE_FILE_AND_EXIT) {
+ ZeroMem (mNewFileName,sizeof (mNewFileName));
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+
+ if (QuestionId == KEY_VALUE_CREATE_FOLDER_AND_EXIT) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ if (!IsZeroBuffer (mNewFolderName, sizeof (mNewFolderName))) {
+ Status = LibCreateNewFile (mNewFolderName, FALSE);
+ ZeroMem (mNewFolderName,sizeof (mNewFolderName));
+ }
+ }
+
+ if (QuestionId == KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT) {
+ ZeroMem (mNewFolderName,sizeof (mNewFolderName));
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+
+ if (QuestionId == NEW_FILE_NAME_ID) {
+ NewFileName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);
+ if (NewFileName != NULL) {
+ StrCpyS (mNewFileName, MAX_FILE_NAME_LEN, NewFileName);
+ FreePool (NewFileName);
+ NewFileName = NULL;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (QuestionId == NEW_FOLDER_NAME_ID) {
+ NewFolderName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);
+ if (NewFolderName != NULL) {
+ StrCpyS (mNewFolderName, MAX_FOLDER_NAME_LEN, NewFolderName);
+ FreePool (NewFolderName);
+ NewFolderName = NULL;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (QuestionId >= FILE_OPTION_OFFSET) {
+ LibGetDevicePath(QuestionId);
+
+ //
+ // Process the extra action.
+ //
+ if (gFileExplorerPrivate.ChooseHandler != NULL) {
+ NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath);
+ }
+
+ if (NeedExit) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (QuestionId >= FILE_OPTION_OFFSET) {
+ LibGetDevicePath(QuestionId);
+ Status = LibUpdateFileExplorer (QuestionId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a menu entry by given menu type.
+
+ @retval NULL If failed to create the menu.
+ @return the new menu entry.
+
+**/
+MENU_ENTRY *
+LibCreateMenuEntry (
+ VOID
+ )
+{
+ MENU_ENTRY *MenuEntry;
+
+ //
+ // Create new menu entry
+ //
+ MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
+ if (MenuEntry == NULL) {
+ return NULL;
+ }
+
+ MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
+ if (MenuEntry->VariableContext == NULL) {
+ FreePool (MenuEntry);
+ return NULL;
+ }
+
+ MenuEntry->Signature = MENU_ENTRY_SIGNATURE;
+ return 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.
+
+**/
+MENU_ENTRY *
+LibGetMenuEntry (
+ MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ )
+{
+ 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, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+/**
+ Free up all resource allocated for a BM_MENU_ENTRY.
+
+ @param MenuEntry A pointer to BM_MENU_ENTRY.
+
+**/
+VOID
+LibDestroyMenuEntry (
+ MENU_ENTRY *MenuEntry
+ )
+{
+ FILE_CONTEXT *FileContext;
+
+ FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ if (!FileContext->IsRoot) {
+ if (FileContext->DevicePath != NULL) {
+ FreePool (FileContext->DevicePath);
+ }
+ } else {
+ if (FileContext->FileHandle != NULL) {
+ FileContext->FileHandle->Close (FileContext->FileHandle);
+ }
+ }
+
+ if (FileContext->FileName != NULL) {
+ FreePool (FileContext->FileName);
+ }
+
+ FreePool (FileContext);
+
+ if (MenuEntry->DisplayString != NULL) {
+ FreePool (MenuEntry->DisplayString);
+ }
+ if (MenuEntry->HelpString != NULL) {
+ FreePool (MenuEntry->HelpString);
+ }
+
+ FreePool (MenuEntry);
+}
+
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param FreeMenu Menu to be freed
+**/
+VOID
+LibFreeMenu (
+ MENU_OPTION *FreeMenu
+ )
+{
+ MENU_ENTRY *MenuEntry;
+ while (!IsListEmpty (&FreeMenu->Head)) {
+ MenuEntry = CR (
+ FreeMenu->Head.ForwardLink,
+ MENU_ENTRY,
+ Link,
+ MENU_ENTRY_SIGNATURE
+ );
+ RemoveEntryList (&MenuEntry->Link);
+ LibDestroyMenuEntry (MenuEntry);
+ }
+ FreeMenu->MenuNumber = 0;
+}
+
+/**
+
+ 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
+LibOpenRoot (
+ 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;
+}
+
+/**
+ 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 *
+LibDevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ToText;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+
+ if (DevPath == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevPathToText
+ );
+ ASSERT_EFI_ERROR (Status);
+ ToText = DevPathToText->ConvertDevicePathToText (
+ DevPath,
+ FALSE,
+ TRUE
+ );
+ ASSERT (ToText != NULL);
+
+ return ToText;
+}
+
+/**
+ 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 *
+LibStrDuplicate (
+ 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.
+ @param InfoType Info type need to get.
+
+ @retval A pointer to a buffer with file information or NULL is returned
+
+**/
+VOID *
+LibFileInfo (
+ IN EFI_FILE_HANDLE FHand,
+ IN EFI_GUID *InfoType
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ Buffer = NULL;
+ BufferSize = 0;
+
+ Status = FHand->GetInfo (
+ FHand,
+ InfoType,
+ &BufferSize,
+ Buffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Buffer = AllocatePool (BufferSize);
+ ASSERT (Buffer != NULL);
+ }
+
+ Status = FHand->GetInfo (
+ FHand,
+ InfoType,
+ &BufferSize,
+ Buffer
+ );
+
+ return Buffer;
+}
+
+/**
+
+ Get file type base on the file name.
+ Just cut the file name, from the ".". eg ".efi"
+
+ @param FileName File need to be checked.
+
+ @retval the file type string.
+
+**/
+CHAR16*
+LibGetTypeFromName (
+ IN CHAR16 *FileName
+ )
+{
+ UINTN Index;
+
+ Index = StrLen (FileName) - 1;
+ while ((FileName[Index] != L'.') && (Index != 0)) {
+ Index--;
+ }
+
+ return Index == 0 ? NULL : &FileName[Index];
+}
+
+/**
+ Converts the unicode character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+LibToLowerString (
+ IN CHAR16 *String
+ )
+{
+ CHAR16 *TmpStr;
+
+ for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
+ if (*TmpStr >= L'A' && *TmpStr <= L'Z') {
+ *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a');
+ }
+ }
+}
+
+/**
+
+ 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
+LibIsSupportedFileType (
+ IN UINT16 *FileName
+ )
+{
+ CHAR16 *InputFileType;
+ CHAR16 *TmpStr;
+ BOOLEAN IsSupported;
+
+ if (gFileExplorerPrivate.FileType == NULL) {
+ return TRUE;
+ }
+
+ InputFileType = LibGetTypeFromName (FileName);
+ //
+ // If the file not has *.* style, always return TRUE.
+ //
+ if (InputFileType == NULL) {
+ return TRUE;
+ }
+
+ TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
+ ASSERT(TmpStr != NULL);
+ LibToLowerString(TmpStr);
+
+ IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
+
+ FreePool (TmpStr);
+ return IsSupported;
+}
+
+/**
+
+ 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 *
+LibAppendFileName (
+ 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);
+
+ //
+ // Check overflow
+ //
+ if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof(CHAR16))) {
+ return NULL;
+ }
+
+ MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);
+ Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
+ ASSERT (TmpStr != NULL);
+
+ StrCpyS (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 - (UINTN) Str) / sizeof (CHAR16), 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 - (UINTN) Str) / sizeof (CHAR16), TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\') {
+ LastSlash = Ptr;
+ }
+
+ Ptr++;
+ }
+
+ FreePool (TmpStr);
+
+ return Str;
+}
+
+/**
+ 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.
+
+
+ @retval EFI_SUCCESS Success find the file system
+ @retval EFI_OUT_OF_RESOURCES Can not create menu entry
+
+**/
+EFI_STATUS
+LibFindFileSystem (
+ VOID
+ )
+{
+ UINTN NoSimpleFsHandles;
+ EFI_HANDLE *SimpleFsHandle;
+ UINT16 *VolumeLabel;
+ UINTN Index;
+ EFI_STATUS Status;
+ MENU_ENTRY *MenuEntry;
+ FILE_CONTEXT *FileContext;
+ UINTN OptionNumber;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
+
+ NoSimpleFsHandles = 0;
+ OptionNumber = 0;
+
+ //
+ // 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++) {
+ //
+ // Allocate pool for this load option
+ //
+ MenuEntry = LibCreateMenuEntry ();
+ if (NULL == MenuEntry) {
+ FreePool (SimpleFsHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
+ FileContext->DeviceHandle = SimpleFsHandle[Index];
+ FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle);
+ if (FileContext->FileHandle == NULL) {
+ LibDestroyMenuEntry (MenuEntry);
+ continue;
+ }
+
+ MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle));
+ FileContext->FileName = LibStrDuplicate (L"\\");
+ FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName);
+ FileContext->IsDir = TRUE;
+ FileContext->IsRoot = TRUE;
+
+ //
+ // Get current file system's Volume Label
+ //
+ Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid);
+ if (Info == NULL) {
+ VolumeLabel = L"NO FILE SYSTEM INFO";
+ } else {
+ if (Info->VolumeLabel == NULL) {
+ VolumeLabel = L"NULL VOLUME LABEL";
+ } else {
+ VolumeLabel = Info->VolumeLabel;
+ if (*VolumeLabel == 0x0000) {
+ VolumeLabel = L"NO VOLUME LABEL";
+ }
+ }
+ }
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"%s, [%s]",
+ VolumeLabel,
+ MenuEntry->HelpString
+ );
+ MenuEntry->DisplayStringToken = HiiSetString (
+ gFileExplorerPrivate.FeHiiHandle,
+ 0,
+ MenuEntry->DisplayString,
+ NULL
+ );
+
+ if (Info != NULL)
+ FreePool (Info);
+
+ OptionNumber++;
+ InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoSimpleFsHandles != 0) {
+ FreePool (SimpleFsHandle);
+ }
+
+ gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the file handle from the input menu info.
+
+ @param MenuEntry Input Menu info.
+ @param RetFileHandle Return the file handle for the input device path.
+
+ @retval EFI_SUCESS Find the file handle success.
+ @retval Other Find the file handle failure.
+**/
+EFI_STATUS
+LibGetFileHandleFromMenu (
+ IN MENU_ENTRY *MenuEntry,
+ OUT EFI_FILE_HANDLE *RetFileHandle
+ )
+{
+ EFI_FILE_HANDLE Dir;
+ EFI_FILE_HANDLE NewDir;
+ FILE_CONTEXT *FileContext;
+ EFI_STATUS Status;
+
+ FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
+ Dir = FileContext->FileHandle;
+
+ //
+ // Open current directory to get files from it
+ //
+ Status = Dir->Open (
+ Dir,
+ &NewDir,
+ FileContext->FileName,
+ EFI_FILE_READ_ONLY,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!FileContext->IsRoot) {
+ Dir->Close (Dir);
+ }
+
+ *RetFileHandle = NewDir;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the file handle from the input device path info.
+
+ @param RootDirectory Device path info.
+ @param RetFileHandle Return the file handle for the input device path.
+ @param ParentFileName Parent file name.
+ @param DeviceHandle Driver handle for this partition.
+
+ @retval EFI_SUCESS Find the file handle success.
+ @retval Other Find the file handle failure.
+**/
+EFI_STATUS
+LibGetFileHandleFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
+ OUT EFI_FILE_HANDLE *RetFileHandle,
+ OUT UINT16 **ParentFileName,
+ OUT EFI_HANDLE *DeviceHandle
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE FileHandle;
+ EFI_FILE_HANDLE LastHandle;
+ CHAR16 *TempPath;
+
+ *ParentFileName = NULL;
+
+ //
+ // Attempt to access the file via a file system interface
+ //
+ DevicePathNode = RootDirectory;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the Volume to get the File System handle
+ //
+ Status = Volume->OpenVolume (Volume, &FileHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *DeviceHandle = Handle;
+
+ if (IsDevicePathEnd(DevicePathNode)) {
+ *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\");
+ *RetFileHandle = FileHandle;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Duplicate the device path to avoid the access to unaligned device path node.
+ // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
+ // nodes, It assures the fields in device path nodes are 2 byte aligned.
+ //
+ TempDevicePathNode = DuplicateDevicePath (DevicePathNode);
+ if (TempDevicePathNode == NULL) {
+
+ //
+ // Setting Status to an EFI_ERROR value will cause the rest of
+ // the file system support below to be skipped.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
+ // directory information and filename can be seperate. The goal is to inch
+ // our way down each device path node and close the previous node
+ //
+ DevicePathNode = TempDevicePathNode;
+ while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) {
+ if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ LastHandle = FileHandle;
+ FileHandle = NULL;
+
+ Status = LastHandle->Open (
+ LastHandle,
+ &FileHandle,
+ ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (*ParentFileName == NULL) {
+ *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
+ } else {
+ TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);
+ if (TempPath == NULL) {
+ LastHandle->Close (LastHandle);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ FreePool (*ParentFileName);
+ *ParentFileName = TempPath;
+ }
+
+ //
+ // Close the previous node
+ //
+ LastHandle->Close (LastHandle);
+
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ *RetFileHandle = FileHandle;
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (TempDevicePathNode != NULL) {
+ FreePool (TempDevicePathNode);
+ }
+
+ if ((FileHandle != NULL) && (EFI_ERROR (Status))) {
+ FileHandle->Close (FileHandle);
+ }
+
+ return Status;
+}
+
+/**
+ Create a new file or folder in current directory.
+
+ @param FileName Point to the fileNmae or folder name.
+ @param CreateFile CreateFile== TRUE means create a new file.
+ CreateFile== FALSE means create a new Folder.
+
+**/
+EFI_STATUS
+LibCreateNewFile (
+ IN CHAR16 *FileName,
+ IN BOOLEAN CreateFile
+ )
+{
+ EFI_FILE_HANDLE FileHandle;
+ EFI_FILE_HANDLE NewHandle;
+ EFI_HANDLE DeviceHandle;
+ EFI_STATUS Status;
+ CHAR16 *ParentName;
+ CHAR16 *FullFileName;
+
+ NewHandle = NULL;
+ FullFileName = NULL;
+
+ LibGetFileHandleFromDevicePath(gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle);
+ FullFileName = LibAppendFileName (ParentName, FileName);
+ if (FullFileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (CreateFile) {
+ Status = FileHandle->Open(
+ FileHandle,
+ &NewHandle,
+ FullFileName,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ FileHandle->Close (FileHandle);
+ return Status;
+ }
+ } else {
+ Status = FileHandle->Open(
+ FileHandle,
+ &NewHandle,
+ FullFileName,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
+ EFI_FILE_DIRECTORY
+ );
+ if (EFI_ERROR (Status)) {
+ FileHandle->Close (FileHandle);
+ return Status;
+ }
+ }
+
+ FileHandle->Close (FileHandle);
+
+ //
+ // Return the DevicePath of the new created file or folder.
+ //
+ gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Find files under current directory.
+
+ All files and sub-directories in current directory
+ will be stored in DirectoryMenu for future use.
+
+ @param FileHandle Parent file handle.
+ @param FileName Parent file name.
+ @param DeviceHandle Driver handle for this partition.
+
+ @retval EFI_SUCCESS Get files from current dir successfully.
+ @return Other value if can't get files from current dir.
+
+**/
+EFI_STATUS
+LibFindFiles (
+ IN EFI_FILE_HANDLE FileHandle,
+ IN UINT16 *FileName,
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_FILE_INFO *DirInfo;
+ UINTN BufferSize;
+ UINTN DirBufferSize;
+ MENU_ENTRY *NewMenuEntry;
+ FILE_CONTEXT *NewFileContext;
+ UINTN Pass;
+ EFI_STATUS Status;
+ UINTN OptionNumber;
+
+ OptionNumber = 0;
+
+ 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
+ //
+ Status = EFI_SUCCESS;
+ for (Pass = 1; Pass <= 2; Pass++) {
+ FileHandle->SetPosition (FileHandle, 0);
+ for (;;) {
+ BufferSize = DirBufferSize;
+ Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo);
+ if (EFI_ERROR (Status) || BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ 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 (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) {
+ //
+ // Slip file unless it is a directory entry or a .EFI file
+ //
+ continue;
+ }
+
+ NewMenuEntry = LibCreateMenuEntry ();
+ if (NULL == NewMenuEntry) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewFileContext->DeviceHandle = DeviceHandle;
+ NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);
+ if (NewFileContext->FileName == NULL) {
+ LibDestroyMenuEntry (NewMenuEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ NewFileContext->FileHandle = FileHandle;
+ NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);
+ NewMenuEntry->HelpString = NULL;
+ 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 = LibStrDuplicate (DirInfo->FileName);
+ }
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (
+ gFileExplorerPrivate.FeHiiHandle,
+ 0,
+ NewMenuEntry->DisplayString,
+ NULL
+ );
+
+ NewFileContext->IsRoot = FALSE;
+
+ OptionNumber++;
+ InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link);
+ }
+ }
+
+ gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;
+
+Done:
+
+ FreePool (DirInfo);
+
+ return Status;
+}
+
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+LibRefreshUpdateData (
+ VOID
+ )
+{
+ //
+ // Free current updated date
+ //
+ if (mLibStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mLibStartOpCodeHandle);
+ }
+ if (mLibEndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mLibEndOpCodeHandle);
+ }
+
+ //
+ // Create new OpCode Handle
+ //
+ mLibStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ mLibEndOpCodeHandle = HiiAllocateOpCodeHandle ();
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mLibStartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ mLibStartLabel->Number = FORM_FILE_EXPLORER_ID;
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mLibEndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ mLibEndLabel->Number = LABEL_END;
+}
+
+/**
+
+ Update the File Explore page.
+
+**/
+VOID
+LibUpdateFileExplorePage (
+ VOID
+ )
+{
+ UINTN Index;
+ MENU_ENTRY *NewMenuEntry;
+ FILE_CONTEXT *NewFileContext;
+ MENU_OPTION *MenuOption;
+ BOOLEAN CreateNewFile;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ CreateNewFile = FALSE;
+
+ LibRefreshUpdateData ();
+ MenuOption = gFileExplorerPrivate.FsOptionMenu;
+
+ mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
+ NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (!NewFileContext->IsRoot && !CreateNewFile) {
+ HiiCreateGotoOpCode (
+ mLibStartOpCodeHandle,
+ FORM_ADD_NEW_FILE_ID,
+ STRING_TOKEN (STR_NEW_FILE),
+ STRING_TOKEN (STR_NEW_FILE_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (mNewFileQuestionId++)
+ );
+ HiiCreateGotoOpCode (
+ mLibStartOpCodeHandle,
+ FORM_ADD_NEW_FOLDER_ID,
+ STRING_TOKEN (STR_NEW_FOLDER),
+ STRING_TOKEN (STR_NEW_FOLDER_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (mNewFolderQuestionId++)
+ );
+ HiiCreateTextOpCode(
+ mLibStartOpCodeHandle,
+ STRING_TOKEN (STR_NULL_STRING),
+ STRING_TOKEN (STR_NULL_STRING),
+ 0
+ );
+ CreateNewFile = TRUE;
+ }
+
+ if (!NewFileContext->IsDir) {
+ //
+ // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
+ //
+ HiiCreateActionOpCode (
+ mLibStartOpCodeHandle,
+ (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate),
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ } else {
+ //
+ // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
+ //
+ HiiCreateGotoOpCode (
+ mLibStartOpCodeHandle,
+ FORM_FILE_EXPLORER_ID,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate)
+ );
+ }
+ }
+
+ HiiUpdateForm (
+ gFileExplorerPrivate.FeHiiHandle,
+ &FileExplorerGuid,
+ FORM_FILE_EXPLORER_ID,
+ mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
+ mLibEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Update the file explower page with the refershed file system.
+
+ @param KeyValue Key value to identify the type of data to expect.
+
+ @retval EFI_SUCCESS Update the file explorer form success.
+ @retval other errors Error occur when parse one directory.
+
+**/
+EFI_STATUS
+LibUpdateFileExplorer (
+ IN UINT16 KeyValue
+ )
+{
+ UINT16 FileOptionMask;
+ MENU_ENTRY *NewMenuEntry;
+ FILE_CONTEXT *NewFileContext;
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE FileHandle;
+
+ Status = EFI_SUCCESS;
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
+ NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
+ NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewFileContext->IsDir) {
+ RemoveEntryList (&NewMenuEntry->Link);
+ LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
+ LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);
+ Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ LibUpdateFileExplorePage ();
+ } else {
+ LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
+ }
+ LibDestroyMenuEntry (NewMenuEntry);
+ }
+
+ return Status;
+}
+
+/**
+ Get the device path info saved in the menu structure.
+
+ @param KeyValue Key value to identify the type of data to expect.
+
+**/
+VOID
+LibGetDevicePath (
+ IN UINT16 KeyValue
+ )
+{
+ UINT16 FileOptionMask;
+ MENU_ENTRY *NewMenuEntry;
+ FILE_CONTEXT *NewFileContext;
+
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;
+
+ NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);
+
+ NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (gFileExplorerPrivate.RetDevicePath != NULL) {
+ FreePool (gFileExplorerPrivate.RetDevicePath);
+ }
+ gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath);
+}
+
+/**
+ Choose a file in the specified directory.
+
+ If user input NULL for the RootDirectory, will choose file in the system.
+
+ If user input *File != NULL, function will return the allocate device path
+ info for the choosed file, caller has to free the memory after use it.
+
+ @param RootDirectory Pointer to the root directory.
+ @param FileType The file type need to choose.
+ @param ChooseHandler Function pointer to the extra task need to do
+ after choose one file.
+ @param File Return the device path for the last time chosed file.
+
+ @retval EFI_SUCESS Choose file success.
+ @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL
+ One of them must not NULL.
+ @retval Other errors Choose file failed.
+**/
+EFI_STATUS
+EFIAPI
+ChooseFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,
+ IN CHAR16 *FileType, OPTIONAL
+ IN CHOOSE_HANDLER ChooseHandler, OPTIONAL
+ OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL
+ )
+{
+ EFI_FILE_HANDLE FileHandle;
+ EFI_STATUS Status;
+ UINT16 *FileName;
+ EFI_HANDLE DeviceHandle;
+
+ if ((ChooseHandler == NULL) && (File == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mQuestionIdUpdate = 0;
+ FileName = NULL;
+
+ gFileExplorerPrivate.RetDevicePath = NULL;
+ gFileExplorerPrivate.ChooseHandler = ChooseHandler;
+ if (FileType != NULL) {
+ gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);
+ ASSERT(gFileExplorerPrivate.FileType != NULL);
+ LibToLowerString(gFileExplorerPrivate.FileType);
+ } else {
+ gFileExplorerPrivate.FileType = NULL;
+ }
+
+ if (RootDirectory == NULL) {
+ Status = LibFindFileSystem();
+ } else {
+ Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ LibUpdateFileExplorePage();
+
+ gFileExplorerPrivate.FormBrowser2->SendForm (
+ gFileExplorerPrivate.FormBrowser2,
+ &gFileExplorerPrivate.FeHiiHandle,
+ 1,
+ &FileExplorerGuid,
+ 0,
+ NULL,
+ NULL
+ );
+
+Done:
+ if ((Status == EFI_SUCCESS) && (File != NULL)) {
+ *File = gFileExplorerPrivate.RetDevicePath;
+ } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
+ FreePool (gFileExplorerPrivate.RetDevicePath);
+ }
+
+ if (gFileExplorerPrivate.FileType != NULL) {
+ FreePool (gFileExplorerPrivate.FileType);
+ }
+
+ LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
+
+ if (FileName != NULL) {
+ FreePool (FileName);
+ }
+
+ return Status;
+}
+
+/**
+
+ Install Boot Manager Menu driver.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS Install File explorer library success.
+
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
+ ASSERT (gHiiVendorDevicePath != NULL);
+ CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gFileExplorerPrivate.FeDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ gHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gFileExplorerPrivate.FeConfigAccess,
+ NULL
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Post our File Explorer VFR binary to the HII database.
+ //
+ gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
+ &FileExplorerGuid,
+ gFileExplorerPrivate.FeDriverHandle,
+ FileExplorerVfrBin,
+ FileExplorerLibStrings,
+ NULL
+ );
+ ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (gHiiVendorDevicePath != NULL);
+
+ if (gFileExplorerPrivate.FeDriverHandle != NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ gFileExplorerPrivate.FeDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ gHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gFileExplorerPrivate.FeConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
+ gFileExplorerPrivate.FeDriverHandle = NULL;
+ }
+
+ FreePool (gHiiVendorDevicePath);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h
new file mode 100644
index 000000000..cc84c2a65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h
@@ -0,0 +1,236 @@
+/** @file
+ File explorer lib.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _FILE_EXPLORER_H_
+#define _FILE_EXPLORER_H_
+
+#include <PiDxe.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/FileInfo.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FormBrowser2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+
+#include "FormGuid.h"
+
+#define FILE_EXPLORER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('f', 'e', 'c', 'k')
+
+
+#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()
+
+typedef struct {
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FILE_HANDLE FileHandle;
+ UINT16 *FileName;
+
+ BOOLEAN IsRoot;
+ BOOLEAN IsDir;
+} FILE_CONTEXT;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT16 *DisplayString;
+ UINT16 *HelpString;
+ EFI_STRING_ID DisplayStringToken;
+ EFI_STRING_ID HelpStringToken;
+ VOID *VariableContext;
+} MENU_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+ BOOLEAN Used;
+} MENU_OPTION;
+
+typedef struct {
+ //
+ // Shared callback data.
+ //
+ UINTN Signature;
+
+ //
+ // File explorer formset callback data.
+ //
+ EFI_HII_HANDLE FeHiiHandle;
+ EFI_HANDLE FeDriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL FeConfigAccess;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ MENU_OPTION *FsOptionMenu;
+ CHAR16 *FileType;
+ CHOOSE_HANDLER ChooseHandler;
+ EFI_DEVICE_PATH_PROTOCOL *RetDevicePath;
+
+} FILE_EXPLORER_CALLBACK_DATA;
+
+#define FILE_EXPLORER_PRIVATE_FROM_THIS(a) CR (a, FILE_EXPLORER_CALLBACK_DATA, FeConfigAccess, FILE_EXPLORER_CALLBACK_DATA_SIGNATURE)
+
+extern UINT8 FileExplorerVfrBin[];
+
+#define MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u')
+#define MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r')
+
+///
+/// Define the maximum characters that will be accepted.
+///
+#define MAX_CHAR 480
+#define FILE_OPTION_OFFSET 0x8000
+#define FILE_OPTION_MASK 0x7FFF
+#define QUESTION_ID_UPDATE_STEP 200
+#define MAX_FILE_NAME_LEN 20
+#define MAX_FOLDER_NAME_LEN 20
+#define NEW_FILE_QUESTION_ID_BASE 0x5000;
+#define NEW_FOLDER_QUESTION_ID_BASE 0x6000;
+
+/**
+ 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
+LibCallback (
+ 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
+LibExtractConfig (
+ 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
+LibRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ Update the file explower page with the refershed file system.
+
+ @param KeyValue Key value to identify the type of data to expect.
+
+ @retval EFI_SUCCESS Update the file explorer form success.
+ @retval other errors Error occur when parse one directory.
+
+**/
+EFI_STATUS
+LibUpdateFileExplorer (
+ IN UINT16 KeyValue
+ );
+
+
+/**
+ Get the device path info saved in the menu structure.
+
+ @param KeyValue Key value to identify the type of data to expect.
+
+**/
+VOID
+LibGetDevicePath (
+ IN UINT16 KeyValue
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
new file mode 100644
index 000000000..4e14cbc04
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
@@ -0,0 +1,57 @@
+## @file
+# library defines a set of interfaces for how to do file explorer.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FileExplorerLib
+ MODULE_UNI_FILE = FileExplorerLib.uni
+ FILE_GUID = 4FC9C630-0F90-4053-8F13-264CBD22FC58
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FileExplorerLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = FileExplorerLibConstructor
+ DESTRUCTOR = FileExplorerLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FileExplorer.h
+ FileExplorerVfr.vfr
+ FileExplorerString.uni
+ FileExplorer.c
+ FormGuid.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiHiiServicesLib
+
+[Guids]
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## GUID (Indicate the information type is volume)
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## GUID (Extended IFR Guid Opcode)
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## PRODUCES
+
+[Depex.common.DXE_DRIVER]
+ gEfiFormBrowser2ProtocolGuid AND gEfiHiiDatabaseProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni
new file mode 100644
index 000000000..5e7a99cb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// library defines a set of interfaces for how to do file explorer.
+//
+// library defines a set of interfaces for how to do file explorer.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"library defines a set of interfaces for how to do file explorer."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"library defines a set of interfaces for how to do file explorer."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni
new file mode 100644
index 000000000..52e5eec5f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni
@@ -0,0 +1,55 @@
+///** @file
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// FileExplorerString.uni
+//
+// Abstract:
+//
+// String definitions for file exporer library.
+//
+// Revision History:
+//
+// --*/
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_NULL_STRING #language en-US " "
+ #language fr-FR " "
+#string STR_FILE_EXPLORER_TITLE #language en-US "File Explorer"
+ #language fr-FR "File Explorer"
+#string STR_NEW_FILE #language en-US "***NEW FILE***"
+ #language fr-FR "***NEW FILE***"
+#string STR_NEW_FILE_HELP #language en-US "This menu used to create a new file in current directory, jump to next page to name the new file"
+ #language fr-FR "This menu used to create a new file in current directory, jump to next page to name the new file"
+#string STR_ADD_NEW_FILE_TITLE #language en-US "Create a new file"
+ #language fr-FR "Create a new file"
+#string STR_ADD_NEW_FOLDER_TITLE #language en-US "Create a new folder"
+ #language fr-FR "Create a new folder"
+#string STR_NEW_FILE_NAME_PROMPT #language en-US "File Name"
+ #language fr-FR "File Name"
+#string STR_NEW_FILE_NAME_HELP #language en-US "Please input a name for the new file"
+ #language fr-FR "Please input a name for the new file"
+#string STR_CREATE_FILE_AND_EXIT #language en-US "Create File and Exit"
+ #language fr-FR "Create File and Exit"
+#string STR_NO_CREATE_FILE_AND_EXIT #language en-US "Discard Create and Exit"
+ #language fr-FR "Discard Create and Exit"
+#string STR_NEW_FOLDER #language en-US "***NEW FOLDER***"
+ #language fr-FR "***NEW FOLDER***"
+#string STR_NEW_FOLDER_HELP #language en-US "This menu used to create a new folder in current directory, jump to next page to name the new folder"
+ #language fr-FR "This menu used to create a new folder in current directory, jump to next page to name the new folder"
+#string STR_ADD_NEW_FOLDER_TITLE #language en-US "Create a new folder"
+ #language fr-FR "Create a new folder"
+#string STR_NEW_FOLDER_NAME_PROMPT #language en-US "Folder Name"
+ #language fr-FR "Folder Name"
+#string STR_NEW_FOLDER_NAME_HELP #language en-US "Please input a name for the new folder"
+ #language fr-FR "Please input a name for the new folder"
+#string STR_CREATE_FOLDER_AND_EXIT #language en-US "Create Folder and Exit"
+ #language fr-FR "Create Folder and Exit"
+#string STR_NO_CREATE_FOLDER_AND_EXIT #language en-US "Discard Create and Exit"
+ #language fr-FR "Discard Create and Exit"
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr
new file mode 100644
index 000000000..a8f273299
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr
@@ -0,0 +1,79 @@
+///** @file
+//
+// File Explorer Formset
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#include "FormGuid.h"
+
+formset
+ guid = EFI_FILE_EXPLORE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = EFI_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_ADD_NEW_FILE_ID,
+ title = STRING_TOKEN(STR_ADD_NEW_FILE_TITLE);
+
+ string
+ prompt = STRING_TOKEN(STR_NEW_FILE_NAME_PROMPT),
+ help = STRING_TOKEN(STR_NEW_FILE_NAME_HELP),
+ flags = INTERACTIVE,
+ key = NEW_FILE_NAME_ID,
+ minsize = 2,
+ maxsize = 20,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT),
+ text = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_CREATE_FILE_AND_EXIT;
+
+ text
+ help = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_CREATE_FILE_AND_EXIT;
+ endform;
+
+ form formid = FORM_ADD_NEW_FOLDER_ID,
+ title = STRING_TOKEN(STR_ADD_NEW_FOLDER_TITLE);
+
+ string
+ prompt = STRING_TOKEN(STR_NEW_FOLDER_NAME_PROMPT),
+ help = STRING_TOKEN(STR_NEW_FOLDER_NAME_HELP),
+ flags = INTERACTIVE,
+ key = NEW_FOLDER_NAME_ID,
+ minsize = 2,
+ maxsize = 20,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT),
+ text = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_CREATE_FOLDER_AND_EXIT;
+
+ text
+ help = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT;
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h
new file mode 100644
index 000000000..a084a50b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h
@@ -0,0 +1,32 @@
+/** @file
+Formset guids, form id and VarStore data structure for File explorer library.
+
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _FILE_EXPLORER_FORM_GUID_H_
+#define _FILE_EXPLORER_FORM_GUID_H_
+
+
+#define EFI_FILE_EXPLORE_FORMSET_GUID \
+ { \
+ 0xfe561596, 0xe6bf, 0x41a6, {0x83, 0x76, 0xc7, 0x2b, 0x71, 0x98, 0x74, 0xd0} \
+ }
+
+#define FORM_FILE_EXPLORER_ID 0x1000
+#define FORM_ADD_NEW_FILE_ID 0x2000
+#define NEW_FILE_NAME_ID 0x2001
+#define KEY_VALUE_CREATE_FILE_AND_EXIT 0x2002
+#define KEY_VALUE_NO_CREATE_FILE_AND_EXIT 0x2003
+#define FORM_ADD_NEW_FOLDER_ID 0x3000
+#define NEW_FOLDER_NAME_ID 0x3001
+#define KEY_VALUE_CREATE_FOLDER_AND_EXIT 0x3002
+#define KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT 0x3003
+
+#define LABEL_END 0xffff
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.c b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.c
new file mode 100644
index 000000000..533e1ea5a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.c
@@ -0,0 +1,60 @@
+/** @file
+ NULL FMP authentication library.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/DebugLib.h>
+#include <Library/FmpAuthenticationLib.h>
+
+/**
+ The function is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION,
+ followed by the payload.
+
+ If the return status is RETURN_SUCCESS, the caller may continue the rest
+ FMP update process.
+ If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP
+ update process and convert the return status to LastAttemptStatus
+ to indicate that FMP update fails.
+ The LastAttemptStatus can be got from ESRT table or via
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo().
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED Image or ImageSize is invalid.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+EFIAPI
+AuthenticateFmpImage (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ )
+{
+ ASSERT(FALSE);
+ return RETURN_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf
new file mode 100644
index 000000000..5819df64c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf
@@ -0,0 +1,35 @@
+## @file
+# FmpAuthentication Library
+#
+# NULL Instance of FmpAuthentication Library.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpAuthenticationLibNull
+ MODULE_UNI_FILE = FmpAuthenticationLibNull.uni
+ FILE_GUID = 5011522C-7B0E-4ACB-8E30-9B1D133CF2E0
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FmpAuthenticationLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FmpAuthenticationLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.uni b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.uni
new file mode 100644
index 000000000..8997d0f17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// FmpAuthentication Library
+//
+// NULL Instance of FmpAuthentication Library.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "FmpAuthentication Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL Instance of FmpAuthentication Library."
+
diff --git a/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.c b/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.c
new file mode 100644
index 000000000..ff7979c96
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.c
@@ -0,0 +1,718 @@
+/** @file
+ FrameBufferBltLib - Library to perform blt operations on a frame buffer.
+
+ Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/GraphicsOutput.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FrameBufferBltLib.h>
+
+struct FRAME_BUFFER_CONFIGURE {
+ UINT32 PixelsPerScanLine;
+ UINT32 BytesPerPixel;
+ UINT32 Width;
+ UINT32 Height;
+ UINT8 *FrameBuffer;
+ EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
+ EFI_PIXEL_BITMASK PixelMasks;
+ INT8 PixelShl[4]; // R-G-B-Rsvd
+ INT8 PixelShr[4]; // R-G-B-Rsvd
+ UINT8 LineBuffer[0];
+};
+
+CONST EFI_PIXEL_BITMASK mRgbPixelMasks = {
+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
+};
+
+CONST EFI_PIXEL_BITMASK mBgrPixelMasks = {
+ 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+};
+
+/**
+ Initialize the bit mask in frame buffer configure.
+
+ @param BitMask The bit mask of pixel.
+ @param BytesPerPixel Size in bytes of pixel.
+ @param PixelShl Left shift array.
+ @param PixelShr Right shift array.
+**/
+VOID
+FrameBufferBltLibConfigurePixelFormat (
+ IN CONST EFI_PIXEL_BITMASK *BitMask,
+ OUT UINT32 *BytesPerPixel,
+ OUT INT8 *PixelShl,
+ OUT INT8 *PixelShr
+ )
+{
+ UINT8 Index;
+ UINT32 *Masks;
+ UINT32 MergedMasks;
+
+ ASSERT (BytesPerPixel != NULL);
+
+ MergedMasks = 0;
+ Masks = (UINT32*) BitMask;
+ for (Index = 0; Index < 3; Index++) {
+ ASSERT ((MergedMasks & Masks[Index]) == 0);
+
+ PixelShl[Index] = (INT8) HighBitSet32 (Masks[Index]) - 23 + (Index * 8);
+ if (PixelShl[Index] < 0) {
+ PixelShr[Index] = -PixelShl[Index];
+ PixelShl[Index] = 0;
+ } else {
+ PixelShr[Index] = 0;
+ }
+ DEBUG ((DEBUG_INFO, "%d: shl:%d shr:%d mask:%x\n", Index,
+ PixelShl[Index], PixelShr[Index], Masks[Index]));
+
+ MergedMasks = (UINT32) (MergedMasks | Masks[Index]);
+ }
+ MergedMasks = (UINT32) (MergedMasks | Masks[3]);
+
+ ASSERT (MergedMasks != 0);
+ *BytesPerPixel = (UINT32) ((HighBitSet32 (MergedMasks) + 7) / 8);
+ DEBUG ((DEBUG_INFO, "Bytes per pixel: %d\n", *BytesPerPixel));
+}
+
+/**
+ Create the configuration for a video frame buffer.
+
+ The configuration is returned in the caller provided buffer.
+
+ @param[in] FrameBuffer Pointer to the start of the frame buffer.
+ @param[in] FrameBufferInfo Describes the frame buffer characteristics.
+ @param[in,out] Configure The created configuration information.
+ @param[in,out] ConfigureSize Size of the configuration information.
+
+ @retval RETURN_SUCCESS The configuration was successful created.
+ @retval RETURN_BUFFER_TOO_SMALL The Configure is to too small. The required
+ size is returned in ConfigureSize.
+ @retval RETURN_UNSUPPORTED The requested mode is not supported by
+ this implementaion.
+
+**/
+RETURN_STATUS
+EFIAPI
+FrameBufferBltConfigure (
+ IN VOID *FrameBuffer,
+ IN EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo,
+ IN OUT FRAME_BUFFER_CONFIGURE *Configure,
+ IN OUT UINTN *ConfigureSize
+ )
+{
+ CONST EFI_PIXEL_BITMASK *BitMask;
+ UINT32 BytesPerPixel;
+ INT8 PixelShl[4];
+ INT8 PixelShr[4];
+
+ if (ConfigureSize == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ switch (FrameBufferInfo->PixelFormat) {
+ case PixelRedGreenBlueReserved8BitPerColor:
+ BitMask = &mRgbPixelMasks;
+ break;
+
+ case PixelBlueGreenRedReserved8BitPerColor:
+ BitMask = &mBgrPixelMasks;
+ break;
+
+ case PixelBitMask:
+ BitMask = &FrameBufferInfo->PixelInformation;
+ break;
+
+ case PixelBltOnly:
+ ASSERT (FrameBufferInfo->PixelFormat != PixelBltOnly);
+ return RETURN_UNSUPPORTED;
+
+ default:
+ ASSERT (FALSE);
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (FrameBufferInfo->PixelsPerScanLine < FrameBufferInfo->HorizontalResolution) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ FrameBufferBltLibConfigurePixelFormat (BitMask, &BytesPerPixel, PixelShl, PixelShr);
+
+ if (*ConfigureSize < sizeof (FRAME_BUFFER_CONFIGURE)
+ + FrameBufferInfo->HorizontalResolution * BytesPerPixel) {
+ *ConfigureSize = sizeof (FRAME_BUFFER_CONFIGURE)
+ + FrameBufferInfo->HorizontalResolution * BytesPerPixel;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+
+ if (Configure == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CopyMem (&Configure->PixelMasks, BitMask, sizeof (*BitMask));
+ CopyMem (Configure->PixelShl, PixelShl, sizeof (PixelShl));
+ CopyMem (Configure->PixelShr, PixelShr, sizeof (PixelShr));
+ Configure->BytesPerPixel = BytesPerPixel;
+ Configure->PixelFormat = FrameBufferInfo->PixelFormat;
+ Configure->FrameBuffer = (UINT8*) FrameBuffer;
+ Configure->Width = FrameBufferInfo->HorizontalResolution;
+ Configure->Height = FrameBufferInfo->VerticalResolution;
+ Configure->PixelsPerScanLine = FrameBufferInfo->PixelsPerScanLine;
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt Video Fill.
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[in] Color Color to fill the region with.
+ @param[in] DestinationX X location to start fill operation.
+ @param[in] DestinationY Y location to start fill operation.
+ @param[in] Width Width (in pixels) to fill.
+ @param[in] Height Height to fill.
+
+ @retval RETURN_INVALID_PARAMETER Invalid parameter was passed in.
+ @retval RETURN_SUCCESS The video was filled successfully.
+
+**/
+EFI_STATUS
+FrameBufferBltLibVideoFill (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Color,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ UINTN IndexX;
+ UINTN IndexY;
+ UINT8 *Destination;
+ UINT8 Uint8;
+ UINT32 Uint32;
+ UINT64 WideFill;
+ BOOLEAN UseWideFill;
+ BOOLEAN LineBufferReady;
+ UINTN Offset;
+ UINTN WidthInBytes;
+ UINTN SizeInBytes;
+
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > Configure->Height) {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (Y)\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Configure->Width) {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (X)\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill: Width or Height is 0\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ WidthInBytes = Width * Configure->BytesPerPixel;
+
+ Uint32 = *(UINT32*) Color;
+ WideFill =
+ (UINT32) (
+ (((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) &
+ Configure->PixelMasks.RedMask) |
+ (((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) &
+ Configure->PixelMasks.GreenMask) |
+ (((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) &
+ Configure->PixelMasks.BlueMask)
+ );
+ DEBUG ((EFI_D_VERBOSE, "VideoFill: color=0x%x, wide-fill=0x%x\n",
+ Uint32, WideFill));
+
+ //
+ // If the size of the pixel data evenly divides the sizeof
+ // WideFill, then a wide fill operation can be used
+ //
+ UseWideFill = TRUE;
+ if ((sizeof (WideFill) % Configure->BytesPerPixel) == 0) {
+ for (IndexX = Configure->BytesPerPixel; IndexX < sizeof (WideFill); IndexX++) {
+ ((UINT8*) &WideFill)[IndexX] = ((UINT8*) &WideFill)[IndexX % Configure->BytesPerPixel];
+ }
+ } else {
+ //
+ // If all the bytes in the pixel are the same value, then use
+ // a wide fill operation.
+ //
+ for (
+ IndexX = 1, Uint8 = ((UINT8*) &WideFill)[0];
+ IndexX < Configure->BytesPerPixel;
+ IndexX++) {
+ if (Uint8 != ((UINT8*) &WideFill)[IndexX]) {
+ UseWideFill = FALSE;
+ break;
+ }
+ }
+ if (UseWideFill) {
+ SetMem (&WideFill, sizeof (WideFill), Uint8);
+ }
+ }
+
+ if (UseWideFill && (DestinationX == 0) && (Width == Configure->PixelsPerScanLine)) {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill (wide, one-shot)\n"));
+ Offset = DestinationY * Configure->PixelsPerScanLine;
+ Offset = Configure->BytesPerPixel * Offset;
+ Destination = Configure->FrameBuffer + Offset;
+ SizeInBytes = WidthInBytes * Height;
+ if (SizeInBytes >= 8) {
+ SetMem32 (Destination, SizeInBytes & ~3, (UINT32) WideFill);
+ Destination += SizeInBytes & ~3;
+ SizeInBytes &= 3;
+ }
+ if (SizeInBytes > 0) {
+ SetMem (Destination, SizeInBytes, (UINT8) (UINTN) WideFill);
+ }
+ } else {
+ LineBufferReady = FALSE;
+ for (IndexY = DestinationY; IndexY < (Height + DestinationY); IndexY++) {
+ Offset = (IndexY * Configure->PixelsPerScanLine) + DestinationX;
+ Offset = Configure->BytesPerPixel * Offset;
+ Destination = Configure->FrameBuffer + Offset;
+
+ if (UseWideFill && (((UINTN) Destination & 7) == 0)) {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill (wide)\n"));
+ SizeInBytes = WidthInBytes;
+ if (SizeInBytes >= 8) {
+ SetMem64 (Destination, SizeInBytes & ~7, WideFill);
+ Destination += SizeInBytes & ~7;
+ SizeInBytes &= 7;
+ }
+ if (SizeInBytes > 0) {
+ CopyMem (Destination, &WideFill, SizeInBytes);
+ }
+ } else {
+ DEBUG ((EFI_D_VERBOSE, "VideoFill (not wide)\n"));
+ if (!LineBufferReady) {
+ CopyMem (Configure->LineBuffer, &WideFill, Configure->BytesPerPixel);
+ for (IndexX = 1; IndexX < Width; ) {
+ CopyMem (
+ (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)),
+ Configure->LineBuffer,
+ MIN (IndexX, Width - IndexX) * Configure->BytesPerPixel
+ );
+ IndexX += MIN (IndexX, Width - IndexX);
+ }
+ LineBufferReady = TRUE;
+ }
+ CopyMem (Destination, Configure->LineBuffer, WidthInBytes);
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation
+ with extended parameters.
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[out] BltBuffer Output buffer for pixel color data.
+ @param[in] SourceX X location within video.
+ @param[in] SourceY Y location within video.
+ @param[in] DestinationX X location within BltBuffer.
+ @param[in] DestinationY Y location within BltBuffer.
+ @param[in] Width Width (in pixels).
+ @param[in] Height Height.
+ @param[in] Delta Number of bytes in a row of BltBuffer.
+
+ @retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
+ @retval RETURN_SUCCESS The Blt operation was performed successfully.
+**/
+RETURN_STATUS
+FrameBufferBltLibVideoToBltBuffer (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ UINTN DstY;
+ UINTN SrcY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINT8 *Source;
+ UINT8 *Destination;
+ UINTN IndexX;
+ UINT32 Uint32;
+ UINTN Offset;
+ UINTN WidthInBytes;
+
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ if (SourceY + Height > Configure->Height) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > Configure->Width) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return RETURN_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);
+ }
+
+ WidthInBytes = Width * Configure->BytesPerPixel;
+
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ for (SrcY = SourceY, DstY = DestinationY;
+ DstY < (Height + DestinationY);
+ SrcY++, DstY++) {
+
+ Offset = (SrcY * Configure->PixelsPerScanLine) + SourceX;
+ Offset = Configure->BytesPerPixel * Offset;
+ Source = Configure->FrameBuffer + Offset;
+
+ if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+ Destination = (UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ } else {
+ Destination = Configure->LineBuffer;
+ }
+
+ CopyMem (Destination, Source, WidthInBytes);
+
+ if (Configure->PixelFormat != PixelBlueGreenRedReserved8BitPerColor) {
+ for (IndexX = 0; IndexX < Width; IndexX++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)
+ ((UINT8 *) BltBuffer + (DstY * Delta) +
+ (DestinationX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ Uint32 = *(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel));
+ *(UINT32*) Blt =
+ (UINT32) (
+ (((Uint32 & Configure->PixelMasks.RedMask) >>
+ Configure->PixelShl[0]) << Configure->PixelShr[0]) |
+ (((Uint32 & Configure->PixelMasks.GreenMask) >>
+ Configure->PixelShl[1]) << Configure->PixelShr[1]) |
+ (((Uint32 & Configure->PixelMasks.BlueMask) >>
+ Configure->PixelShl[2]) << Configure->PixelShr[2])
+ );
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation
+ with extended parameters.
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[in] BltBuffer Output buffer for pixel color data.
+ @param[in] SourceX X location within BltBuffer.
+ @param[in] SourceY Y location within BltBuffer.
+ @param[in] DestinationX X location within video.
+ @param[in] DestinationY Y location within video.
+ @param[in] Width Width (in pixels).
+ @param[in] Height Height.
+ @param[in] Delta Number of bytes in a row of BltBuffer.
+
+ @retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
+ @retval RETURN_SUCCESS The Blt operation was performed successfully.
+**/
+RETURN_STATUS
+FrameBufferBltLibBufferToVideo (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ UINTN DstY;
+ UINTN SrcY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINT8 *Source;
+ UINT8 *Destination;
+ UINTN IndexX;
+ UINT32 Uint32;
+ UINTN Offset;
+ UINTN WidthInBytes;
+
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > Configure->Height) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Configure->Width) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return RETURN_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);
+ }
+
+ WidthInBytes = Width * Configure->BytesPerPixel;
+
+ for (SrcY = SourceY, DstY = DestinationY;
+ SrcY < (Height + SourceY);
+ SrcY++, DstY++) {
+
+ Offset = (DstY * Configure->PixelsPerScanLine) + DestinationX;
+ Offset = Configure->BytesPerPixel * Offset;
+ Destination = Configure->FrameBuffer + Offset;
+
+ if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+ Source = (UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ } else {
+ for (IndexX = 0; IndexX < Width; IndexX++) {
+ Blt =
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (
+ (UINT8 *) BltBuffer +
+ (SrcY * Delta) +
+ ((SourceX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
+ );
+ Uint32 = *(UINT32*) Blt;
+ *(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)) =
+ (UINT32) (
+ (((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) &
+ Configure->PixelMasks.RedMask) |
+ (((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) &
+ Configure->PixelMasks.GreenMask) |
+ (((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) &
+ Configure->PixelMasks.BlueMask)
+ );
+ }
+ Source = Configure->LineBuffer;
+ }
+
+ CopyMem (Destination, Source, WidthInBytes);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt Video to Video operation
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[in] SourceX X location within video.
+ @param[in] SourceY Y location within video.
+ @param[in] DestinationX X location within video.
+ @param[in] DestinationY Y location within video.
+ @param[in] Width Width (in pixels).
+ @param[in] Height Height.
+
+ @retval RETURN_INVALID_PARAMETER Invalid parameter were passed in.
+ @retval RETURN_SUCCESS The Blt operation was performed successfully.
+**/
+RETURN_STATUS
+FrameBufferBltLibVideoToVideo (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ UINT8 *Source;
+ UINT8 *Destination;
+ UINTN Offset;
+ UINTN WidthInBytes;
+ INTN LineStride;
+
+ //
+ // Video to Video: Source is Video, destination is Video
+ //
+ if (SourceY + Height > Configure->Height) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > Configure->Width) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (DestinationY + Height > Configure->Height) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Configure->Width) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ WidthInBytes = Width * Configure->BytesPerPixel;
+
+ Offset = (SourceY * Configure->PixelsPerScanLine) + SourceX;
+ Offset = Configure->BytesPerPixel * Offset;
+ Source = Configure->FrameBuffer + Offset;
+
+ Offset = (DestinationY * Configure->PixelsPerScanLine) + DestinationX;
+ Offset = Configure->BytesPerPixel * Offset;
+ Destination = Configure->FrameBuffer + Offset;
+
+ LineStride = Configure->BytesPerPixel * Configure->PixelsPerScanLine;
+ if (Destination > Source) {
+ //
+ // Copy from last line to avoid source is corrupted by copying
+ //
+ Source += Height * LineStride;
+ Destination += Height * LineStride;
+ LineStride = -LineStride;
+ }
+
+ while (Height-- > 0) {
+ CopyMem (Destination, Source, WidthInBytes);
+
+ Source += LineStride;
+ Destination += LineStride;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs a UEFI Graphics Output Protocol Blt operation.
+
+ @param[in] Configure Pointer to a configuration which was successfully
+ created by FrameBufferBltConfigure ().
+ @param[in,out] BltBuffer The data to transfer to screen.
+ @param[in] BltOperation The operation to perform.
+ @param[in] SourceX The X coordinate of the source for BltOperation.
+ @param[in] SourceY The Y coordinate of the source for BltOperation.
+ @param[in] DestinationX The X coordinate of the destination for
+ BltOperation.
+ @param[in] DestinationY The Y coordinate of the destination for
+ BltOperation.
+ @param[in] Width The width of a rectangle in the blt rectangle
+ in pixels.
+ @param[in] Height The height of a rectangle in the blt rectangle
+ in pixels.
+ @param[in] 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 RETURN_INVALID_PARAMETER Invalid parameter were passed in.
+ @retval RETURN_SUCCESS The Blt operation was performed successfully.
+**/
+RETURN_STATUS
+EFIAPI
+FrameBufferBlt (
+ IN FRAME_BUFFER_CONFIGURE *Configure,
+ IN OUT 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
+ )
+{
+ if (Configure == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+ return FrameBufferBltLibVideoToBltBuffer (
+ Configure,
+ BltBuffer,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+
+ case EfiBltVideoToVideo:
+ return FrameBufferBltLibVideoToVideo (
+ Configure,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height
+ );
+
+ case EfiBltVideoFill:
+ return FrameBufferBltLibVideoFill (
+ Configure,
+ BltBuffer,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height
+ );
+
+ case EfiBltBufferToVideo:
+ return FrameBufferBltLibBufferToVideo (
+ Configure,
+ BltBuffer,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+
+ default:
+ return RETURN_INVALID_PARAMETER;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf b/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
new file mode 100644
index 000000000..d186ca163
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
@@ -0,0 +1,28 @@
+## @file
+# FrameBufferBltLib - Library to perform blt operations on a frame buffer.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FrameBufferBltLib
+ FILE_GUID = 243D3E8C-2780-4A25-9693-A410475BFCEC
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FrameBufferBltLib
+
+[Sources.common]
+ FrameBufferBltLib.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
new file mode 100644
index 000000000..2510a5e45
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
@@ -0,0 +1,135 @@
+/** @file
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ the original buffer to too small to hold new information.
+ @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
new file mode 100644
index 000000000..17a095617
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
@@ -0,0 +1,32 @@
+## @file
+# NULL LockBox library instance.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LockBoxNullLib
+ MODULE_UNI_FILE = LockBoxNullLib.uni
+ FILE_GUID = 0BA38EBD-E190-4df7-8EC4-0A6E2B43772D
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ LockBoxNullLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni
new file mode 100644
index 000000000..ab6d5d60e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL LockBox library instance.
+//
+// NULL LockBox library instance.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL LockBox library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL LockBox library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
new file mode 100644
index 000000000..ac3fea342
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
@@ -0,0 +1,213 @@
+/** @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 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 (
+ VOID
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaF86CustomDecompressGuid,
+ LzmaArchGuidedSectionGetInfo,
+ LzmaArchGuidedSectionExtraction
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
new file mode 100644
index 000000000..8926204d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
@@ -0,0 +1,196 @@
+/** @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 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 (
+ VOID
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaCustomDecompressGuid,
+ LzmaGuidedSectionGetInfo,
+ LzmaGuidedSectionExtraction
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
new file mode 100644
index 000000000..3f3895b4c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
@@ -0,0 +1,4 @@
+LzmaCustomDecompressLib is based on the LZMA SDK 18.05.
+LZMA SDK 18.05 was placed in the public domain on
+2018-04-30. It was released on the
+http://www.7-zip.org/sdk.html website.
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
new file mode 100644
index 000000000..d789e7dc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
@@ -0,0 +1,63 @@
+## @file
+# LzmaArchCustomDecompressLib produces LZMA custom decompression algorithm with the converter for the different arch code.
+#
+# It is based on the LZMA SDK 18.05
+# LZMA SDK 18.05 was placed in the public domain on 2018-04-30.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[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/7zTypes.h
+ Sdk/C/Precomp.h
+ Sdk/C/Compiler.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/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
new file mode 100644
index 000000000..b59634ca3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
@@ -0,0 +1,18 @@
+// /** @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 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "LzmaArchCustomDecompressLib produces LZMA custom decompression algorithm with the converter for the different arch code."
+
+#string STR_MODULE_DESCRIPTION #language en-US "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 website http://www.7-zip.org/sdk.html ."
+
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
new file mode 100644
index 000000000..4ed1d83a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
@@ -0,0 +1,59 @@
+## @file
+# LzmaCustomDecompressLib produces LZMA custom decompression algorithm.
+#
+# It is based on the LZMA SDK 18.05.
+# LZMA SDK 18.05 was placed in the public domain on 2018-04-30.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[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 AARCH64 ARM
+#
+
+[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/7zTypes.h
+ Sdk/C/Precomp.h
+ Sdk/C/Compiler.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/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
new file mode 100644
index 000000000..c58912eb6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
@@ -0,0 +1,214 @@
+/** @file
+ LZMA Decompress interfaces
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+#include "Sdk/C/7zTypes.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 (
+ CONST ISzAlloc *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 (
+ CONST ISzAlloc *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/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
new file mode 100644
index 000000000..89e20c14b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
@@ -0,0 +1,18 @@
+// /** @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 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "LzmaCustomDecompressLib produces LZMA custom decompression algorithm"
+
+#string STR_MODULE_DESCRIPTION #language en-US "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 website http://www.7-zip.org/sdk.html ."
+
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
new file mode 100644
index 000000000..26f110ba2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
@@ -0,0 +1,90 @@
+/** @file
+ LZMA Decompress Library internal header file declares Lzma decompress interfaces.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zTypes.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zTypes.h
new file mode 100644
index 000000000..c89b5c243
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zTypes.h
@@ -0,0 +1,378 @@
+/* 7zTypes.h -- Basic types
+2017-07-17 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include <windows.h> */
+#endif
+
+#ifdef EFIAPI
+#include "UefiLzma.h"
+#else
+#include <stddef.h>
+#endif
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#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; */
+typedef unsigned WRes;
+#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
+
+#else
+
+typedef int WRes;
+#define MY__FACILITY_WIN32 7
+#define MY__FACILITY__WRes MY__FACILITY_WIN32
+#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000)))
+
+#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;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#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 _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_FORCE_INLINE __forceinline
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_NO_INLINE
+#define MY_FORCE_INLINE
+#define MY_CDECL
+#define MY_FAST_CALL
+
+/* inline keyword : for C++ / C99 */
+
+/* GCC, clang: */
+/*
+#if defined (__GNUC__) && (__GNUC__ >= 4)
+#define MY_FORCE_INLINE __attribute__((always_inline))
+#define MY_NO_INLINE __attribute__((noinline))
+#endif
+*/
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct IByteIn IByteIn;
+struct IByteIn
+{
+ Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */
+};
+#define IByteIn_Read(p) (p)->Read(p)
+
+
+typedef struct IByteOut IByteOut;
+struct IByteOut
+{
+ void (*Write)(const IByteOut *p, Byte b);
+};
+#define IByteOut_Write(p, b) (p)->Write(p, b)
+
+
+typedef struct ISeqInStream ISeqInStream;
+struct ISeqInStream
+{
+ SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+};
+#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
+
+
+typedef struct ISeqOutStream ISeqOutStream;
+struct ISeqOutStream
+{
+ size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+};
+#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+
+typedef struct ISeekInStream ISeekInStream;
+struct ISeekInStream
+{
+ SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin);
+};
+#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+typedef struct ILookInStream ILookInStream;
+struct ILookInStream
+{
+ SRes (*Look)(const ILookInStream *p, const 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)(const ILookInStream *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin);
+};
+
+#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
+#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
+#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
+
+
+
+typedef struct
+{
+ ILookInStream vt;
+ const ISeekInStream *realStream;
+
+ size_t pos;
+ size_t size; /* it's data size */
+
+ /* the following variables must be set outside */
+ Byte *buf;
+ size_t bufSize;
+} CLookToRead2;
+
+void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
+
+#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ const ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ const ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+
+typedef struct ICompressProgress ICompressProgress;
+
+struct ICompressProgress
+{
+ SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+};
+#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
+
+
+
+typedef struct ISzAlloc ISzAlloc;
+typedef const ISzAlloc * ISzAllocPtr;
+
+struct ISzAlloc
+{
+ void *(*Alloc)(ISzAllocPtr p, size_t size);
+ void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
+};
+
+#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
+#define ISzAlloc_Free(p, a) (p)->Free(p, a)
+
+/* deprecated */
+#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
+#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
+
+
+
+
+
+#ifndef MY_offsetof
+ #ifdef offsetof
+ #define MY_offsetof(type, m) offsetof(type, m)
+ /*
+ #define MY_offsetof(type, m) FIELD_OFFSET(type, m)
+ */
+ #else
+ #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
+ #endif
+#endif
+
+
+
+#ifndef MY_container_of
+
+/*
+#define MY_container_of(ptr, type, m) container_of(ptr, type, m)
+#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
+#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
+#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
+*/
+
+/*
+ GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
+ GCC 3.4.4 : classes with constructor
+ GCC 4.8.1 : classes with non-public variable members"
+*/
+
+#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
+
+
+#endif
+
+#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr))
+
+/*
+#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+*/
+#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
+
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+/*
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)
+*/
+
+
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
new file mode 100644
index 000000000..ed3aa9427
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
@@ -0,0 +1,27 @@
+#define MY_VER_MAJOR 18
+#define MY_VER_MINOR 05
+#define MY_VER_BUILD 0
+#define MY_VERSION_NUMBERS "18.05"
+#define MY_VERSION MY_VERSION_NUMBERS
+
+#ifdef MY_CPU_NAME
+ #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")"
+#else
+ #define MY_VERSION_CPU MY_VERSION
+#endif
+
+#define MY_DATE "2018-04-30"
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_AUTHOR_NAME "Igor Pavlov"
+#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
+#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov"
+
+#ifdef USE_COPYRIGHT_CR
+ #define MY_COPYRIGHT MY_COPYRIGHT_CR
+#else
+ #define MY_COPYRIGHT MY_COPYRIGHT_PD
+#endif
+
+#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
new file mode 100644
index 000000000..ecf7b0c44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
@@ -0,0 +1,64 @@
+/* Bra.h -- Branch converters for executables
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+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);
+
+EXTERN_C_END
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
new file mode 100644
index 000000000..a6463c63b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
@@ -0,0 +1,82 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2017-04-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT pos = 0;
+ UInt32 mask = *state & 7;
+ if (size < 5)
+ return 0;
+ size -= 4;
+ ip += 5;
+
+ for (;;)
+ {
+ Byte *p = data + pos;
+ const Byte *limit = data + size;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+
+ {
+ SizeT d = (SizeT)(p - data - pos);
+ pos = (SizeT)(p - data);
+ if (p >= limit)
+ {
+ *state = (d > 2 ? 0 : mask >> (unsigned)d);
+ return pos;
+ }
+ if (d > 2)
+ mask = 0;
+ else
+ {
+ mask >>= (unsigned)d;
+ if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1])))
+ {
+ mask = (mask >> 1) | 4;
+ pos++;
+ continue;
+ }
+ }
+ }
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 cur = ip + (UInt32)pos;
+ pos += 5;
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ if (mask != 0)
+ {
+ unsigned sh = (mask & 6) << 2;
+ if (Test86MSByte((Byte)(v >> sh)))
+ {
+ v ^= (((UInt32)0x100 << sh) - 1);
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ }
+ mask = 0;
+ }
+ p[1] = (Byte)v;
+ p[2] = (Byte)(v >> 8);
+ p[3] = (Byte)(v >> 16);
+ p[4] = (Byte)(0 - ((v >> 24) & 1));
+ }
+ else
+ {
+ mask = (mask >> 1) | 4;
+ pos++;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Compiler.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Compiler.h
new file mode 100644
index 000000000..c788648cd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Compiler.h
@@ -0,0 +1,33 @@
+/* Compiler.h
+2017-04-03 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_COMPILER_H
+#define __7Z_COMPILER_H
+
+#ifdef _MSC_VER
+
+ #ifdef UNDER_CE
+ #define RPC_NO_WINDOWS_H
+ /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+ #endif
+
+ #if _MSC_VER >= 1300
+ #pragma warning(disable : 4996) // This function or variable may be unsafe
+ #else
+ #pragma warning(disable : 4511) // copy constructor could not be generated
+ #pragma warning(disable : 4512) // assignment operator could not be generated
+ #pragma warning(disable : 4514) // unreferenced inline function has been removed
+ #pragma warning(disable : 4702) // unreachable code
+ #pragma warning(disable : 4710) // not inlined
+ #pragma warning(disable : 4714) // function marked as __forceinline not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
new file mode 100644
index 000000000..7fb27282c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
@@ -0,0 +1,335 @@
+/* CpuArch.h -- CPU specific code
+2017-09-04 : Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+*/
+
+#if defined(_M_X64) \
+ || defined(_M_AMD64) \
+ || defined(__x86_64__) \
+ || defined(__AMD64__) \
+ || defined(__amd64__)
+ #define MY_CPU_AMD64
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "x32"
+ #else
+ #define MY_CPU_NAME "x64"
+ #endif
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_IX86) \
+ || defined(__i386__)
+ #define MY_CPU_X86
+ #define MY_CPU_NAME "x86"
+ #define MY_CPU_32BIT
+#endif
+
+
+#if defined(_M_ARM64) \
+ || defined(__AARCH64EL__) \
+ || defined(__AARCH64EB__) \
+ || defined(__aarch64__)
+ #define MY_CPU_ARM64
+ #define MY_CPU_NAME "arm64"
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_ARM) \
+ || defined(_M_ARM_NT) \
+ || defined(_M_ARMT) \
+ || defined(__arm__) \
+ || defined(__thumb__) \
+ || defined(__ARMEL__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEL__) \
+ || defined(__THUMBEB__)
+ #define MY_CPU_ARM
+ #define MY_CPU_NAME "arm"
+ #define MY_CPU_32BIT
+#endif
+
+
+#if defined(_M_IA64) \
+ || defined(__ia64__)
+ #define MY_CPU_IA64
+ #define MY_CPU_NAME "ia64"
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(__mips64) \
+ || defined(__mips64__) \
+ || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
+ #define MY_CPU_NAME "mips64"
+ #define MY_CPU_64BIT
+#elif defined(__mips__)
+ #define MY_CPU_NAME "mips"
+ /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(__ppc64__) \
+ || defined(__powerpc64__)
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "ppc64-32"
+ #else
+ #define MY_CPU_NAME "ppc64"
+ #endif
+ #define MY_CPU_64BIT
+#elif defined(__ppc__) \
+ || defined(__powerpc__)
+ #define MY_CPU_NAME "ppc"
+ #define MY_CPU_32BIT
+#endif
+
+
+#if defined(__sparc64__)
+ #define MY_CPU_NAME "sparc64"
+ #define MY_CPU_64BIT
+#elif defined(__sparc__)
+ #define MY_CPU_NAME "sparc"
+ /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+
+#ifdef _WIN32
+
+ #ifdef MY_CPU_ARM
+ #define MY_CPU_ARM_LE
+ #endif
+
+ #ifdef MY_CPU_ARM64
+ #define MY_CPU_ARM64_LE
+ #endif
+
+ #ifdef _M_IA64
+ #define MY_CPU_IA64_LE
+ #endif
+
+#endif
+
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_LE) \
+ || defined(MY_CPU_ARM64_LE) \
+ || defined(MY_CPU_IA64_LE) \
+ || defined(__LITTLE_ENDIAN__) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__AARCH64EL__) \
+ || defined(__MIPSEL__) \
+ || defined(__MIPSEL) \
+ || defined(_MIPSEL) \
+ || defined(__BFIN__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__) \
+ || defined(__AARCH64EB__) \
+ || defined(__MIPSEB__) \
+ || defined(__MIPSEB) \
+ || defined(_MIPSEB) \
+ || defined(__m68k__) \
+ || defined(__s390__) \
+ || defined(__s390x__) \
+ || defined(__zarch__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define MY_CPU_BE
+#endif
+
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+ #error Stop_Compiling_Bad_Endian
+#endif
+
+
+#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
+ #error Stop_Compiling_Bad_32_64_BIT
+#endif
+
+
+#ifndef MY_CPU_NAME
+ #ifdef MY_CPU_LE
+ #define MY_CPU_NAME "LE"
+ #elif defined(MY_CPU_BE)
+ #define MY_CPU_NAME "BE"
+ #else
+ /*
+ #define MY_CPU_NAME ""
+ */
+ #endif
+#endif
+
+
+
+
+
+#ifdef MY_CPU_LE
+ #if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM64) \
+ || defined(__ARM_FEATURE_UNALIGNED)
+ #define MY_CPU_LE_UNALIGN
+ #endif
+#endif
+
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+
+#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
+#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
+
+#else
+
+#define GetUi16(p) ( (UInt16) ( \
+ ((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 SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); }
+
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); \
+ _ppp_[2] = (Byte)(_vvv_ >> 16); \
+ _ppp_[3] = (Byte)(_vvv_ >> 24); }
+
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+ SetUi32(_ppp2_ , (UInt32)_vvv2_); \
+ SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
+
+#endif
+
+#ifdef __has_builtin
+ #define MY__has_builtin(x) __has_builtin(x)
+#else
+ #define MY__has_builtin(x) 0
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
+
+/* Note: we use bswap instruction, that is unsupported in 386 cpu */
+
+#include <stdlib.h>
+
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+
+/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
+
+#elif defined(MY_CPU_LE_UNALIGN) && ( \
+ (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
+ || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
+
+/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */
+#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
+
+#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))
+
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)(_vvv_ >> 24); \
+ _ppp_[1] = (Byte)(_vvv_ >> 16); \
+ _ppp_[2] = (Byte)(_vvv_ >> 8); \
+ _ppp_[3] = (Byte)_vvv_; }
+
+#endif
+
+
+#ifndef GetBe16
+
+#define GetBe16(p) ( (UInt16) ( \
+ ((UInt16)((const Byte *)(p))[0] << 8) | \
+ ((const Byte *)(p))[1] ))
+
+#endif
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
+#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
+#define x86cpuid_GetStepping(ver) (ver & 0xF)
+
+Bool CPU_Is_InOrder();
+Bool CPU_Is_Aes_Supported();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
new file mode 100644
index 000000000..8765cbebf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
@@ -0,0 +1,1071 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2017-06-10 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifndef EFIAPI
+#include <string.h>
+#endif
+
+#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 (~(UInt32)(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)7 << 29)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ if (!p->directInput)
+ {
+ ISzAlloc_Free(alloc, p->bufferBase);
+ p->bufferBase = NULL;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (!p->bufferBase || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != NULL);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+
+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;
+
+ /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
+
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->directInputRem -= curSize;
+ p->streamPos += curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+
+ p->result = ISeqInStream_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->directInput)
+ return 0;
+ /* 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->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = NULL;
+ p->directInput = 0;
+ p->hash = NULL;
+ p->expectedDataSize = (UInt64)(Int64)-1;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->hash);
+ p->hash = NULL;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return NULL;
+ return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAllocPtr alloc)
+{
+ UInt32 sizeReserv;
+
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+
+ sizeReserv = historySize >> 1;
+ if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
+ else 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 + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize;
+ if (hs > p->expectedDataSize)
+ hs = (UInt32)p->expectedDataSize;
+ if (hs != 0)
+ hs--;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ 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;
+ /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 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;
+ }
+
+ {
+ size_t newSize;
+ size_t numSons;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+
+ numSons = newCyclicBufferSize;
+ if (p->btMode)
+ numSons <<= 1;
+ newSize = hs + numSons;
+
+ if (p->hash && p->numRefs == newSize)
+ return 1;
+
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->numRefs = newSize;
+ p->hash = AllocRefs(newSize, alloc);
+
+ if (p->hash)
+ {
+ 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_LowHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash;
+ size_t numItems = p->fixedHashSize;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_HighHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash + p->fixedHashSize;
+ size_t numItems = (size_t)p->hashMask + 1;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_3(CMatchFinder *p, int readData)
+{
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos =
+ p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+
+ if (readData)
+ MatchFinder_ReadBlock(p);
+
+ MatchFinder_SetLimits(p);
+}
+
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ MatchFinder_Init_HighHash(p);
+ MatchFinder_Init_LowHash(p);
+ MatchFinder_Init_3(p, True);
+}
+
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
+{
+ size_t 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->numRefs);
+ 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 hv; 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;
+
+#define UPDATE_maxLen { \
+ ptrdiff_t diff = (ptrdiff_t)0 - d2; \
+ const Byte *c = cur + maxLen; \
+ const Byte *lim = cur + lenLimit; \
+ for (; c != lim; c++) if (*(c + diff) != *c) break; \
+ maxLen = (UInt32)(c - cur); }
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = 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[hv];
+ p->hash[hv] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, d2, maxLen, offset, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[h2];
+
+ curMatch = (hash + kFix3HashSize)[hv];
+
+ hash[h2] = pos;
+ (hash + kFix3HashSize)[hv] = pos;
+
+ maxLen = 2;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ UPDATE_maxLen
+ distances[0] = maxLen;
+ distances[1] = d2 - 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 h2, h3, d2, d3, maxLen, offset, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash[ h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ }
+
+ if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ maxLen = 3;
+ distances[(size_t)offset + 1] = d3 - 1;
+ offset += 2;
+ d2 = d3;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[(size_t)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 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash[ h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ if (*(cur - d2 + 2) == cur[2])
+ distances[0] = maxLen = 3;
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[2] = maxLen = 3;
+ distances[3] = d3 - 1;
+ offset = 4;
+ d2 = d3;
+ }
+ }
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[0] = maxLen = 3;
+ distances[1] = d3 - 1;
+ offset = 2;
+ d2 = d3;
+ }
+
+ if (d2 != d4 && d4 < p->cyclicBufferSize
+ && *(cur - d4) == *cur
+ && *(cur - d4 + 3) == *(cur + 3))
+ {
+ maxLen = 4;
+ distances[(size_t)offset + 1] = d4 - 1;
+ offset += 2;
+ d2 = d4;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[(size_t)offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+
+ if (maxLen < 4)
+ maxLen = 4;
+
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+*/
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, h3, d2, d3, maxLen, offset, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash[ h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ }
+
+ if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ maxLen = 3;
+ distances[(size_t)offset + 1] = d3 - 1;
+ offset += 2;
+ d2 = d3;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[(size_t)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
+}
+
+/*
+static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[ h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash[ h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ maxLen = 0;
+ offset = 0;
+
+ if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = d2 - 1;
+ offset = 2;
+ if (*(cur - d2 + 2) == cur[2])
+ distances[0] = maxLen = 3;
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[2] = maxLen = 3;
+ distances[3] = d3 - 1;
+ offset = 4;
+ d2 = d3;
+ }
+ }
+ else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+ {
+ distances[0] = maxLen = 3;
+ distances[1] = d3 - 1;
+ offset = 2;
+ d2 = d3;
+ }
+
+ if (d2 != d4 && d4 < p->cyclicBufferSize
+ && *(cur - d4) == *cur
+ && *(cur - d4 + 3) == *(cur + 3))
+ {
+ maxLen = 4;
+ distances[(size_t)offset + 1] = d4 - 1;
+ offset += 2;
+ d2 = d4;
+ }
+
+ if (offset != 0)
+ {
+ UPDATE_maxLen
+ distances[(size_t)offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+
+ if (maxLen < 4)
+ maxLen = 4;
+
+ 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[hv];
+ p->hash[hv] = 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[hv];
+ p->hash[hv] = 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[hv];
+ p->hash[hv] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2;
+ UInt32 *hash;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix3HashSize)[hv];
+ hash[h2] =
+ (hash + kFix3HashSize)[hv] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash[ h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+/*
+static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3, h4;
+ UInt32 *hash;
+ SKIP_HEADER(5)
+ HASH5_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix5HashSize)[hv];
+ hash[ h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+*/
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash[ h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+/*
+static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 h2, h3, h4;
+ UInt32 *hash;
+ SKIP_HEADER(5)
+ HASH5_CALC;
+ hash = p->hash;
+ curMatch = hash + kFix5HashSize)[hv];
+ hash[ h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = 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[hv];
+ p->hash[hv] = 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->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ /* if (p->numHashBytes <= 4) */
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ /*
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc5_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 /* if (p->numHashBytes == 4) */
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+ /*
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
+ }
+ */
+}
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
new file mode 100644
index 000000000..61bb9dd30
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
@@ -0,0 +1,121 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2017-06-10 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+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) */
+
+ Byte streamEndWasReached;
+ Byte btMode;
+ Byte bigHash;
+ Byte directInput;
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ size_t directInputRem;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ SRes result;
+ UInt32 crc[256];
+ size_t numRefs;
+
+ UInt64 expectedDataSize;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+#define Inline_MatchFinder_IsFinishedOK(p) \
+ ((p)->streamEndWasReached \
+ && (p)->streamPos == (p)->pos \
+ && (!(p)->directInput || (p)->directInputRem == 0))
+
+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,
+ ISzAllocPtr alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t 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 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_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_LowHash(CMatchFinder *p);
+void MatchFinder_Init_HighHash(CMatchFinder *p);
+void MatchFinder_Init_3(CMatchFinder *p, int readData);
+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);
+
+EXTERN_C_END
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
new file mode 100644
index 000000000..219144407
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
@@ -0,0 +1,57 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2015-04-12 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_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 hv = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ temp ^= (p->crc[cur[3]] << 5); \
+ h4 = temp & (kHash4Size - 1); \
+ hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }
+
+/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
new file mode 100644
index 000000000..a26231992
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
@@ -0,0 +1,1187 @@
+/* LzmaDec.c -- LZMA Decoder
+2018-02-28 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+/* #include "CpuArch.h" */
+#include "LzmaDec.h"
+
+#ifndef EFIAPI
+#include <string.h>
+#endif
+
+#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 TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); }
+
+#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \
+ { UPDATE_0(p + i); A0; } else \
+ { UPDATE_1(p + i); A1; }
+#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; )
+#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; )
+#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; )
+
+#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 NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte += matchByte; \
+ bit = offs; \
+ offs &= matchByte; \
+ probLit = prob + (offs + bit + symbol); \
+ GET_BIT2(probLit, symbol, offs ^= bit; , ;)
+
+
+
+#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 REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \
+ { UPDATE_0_CHECK; i += m; m += m; } else \
+ { UPDATE_1_CHECK; m += m; i += m; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenLow 0
+#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+#define LenChoice LenLow
+#define LenChoice2 (LenLow + (1 << kLenNumLowBits))
+
+#define kNumStates 12
+#define kNumStates2 16
+#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 * 2 + kLenNumHighSymbols)
+
+/* External ASM code needs same CLzmaProb array layout. So don't change it. */
+
+/* (probs_1664) is faster and better for code size at some platforms */
+/*
+#ifdef MY_CPU_X86_OR_AMD64
+*/
+#define kStartOffset 1664
+#define GET_PROBS p->probs_1664
+/*
+#define GET_PROBS p->probs + kStartOffset
+#else
+#define kStartOffset 0
+#define GET_PROBS p->probs
+#endif
+*/
+
+#define SpecPos (-kStartOffset)
+#define IsRep0Long (SpecPos + kNumFullDistances)
+#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+#define LenCoder (RepLenCoder + kNumLenProbs)
+#define IsMatch (LenCoder + kNumLenProbs)
+#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
+#define IsRep (Align + kAlignTableSize)
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define PosSlot (IsRepG2 + kNumStates)
+#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define NUM_BASE_PROBS (Literal + kStartOffset)
+
+#if Align != 0 && kStartOffset != 0
+ #error Stop_Compiling_Bad_LZMA_kAlign
+#endif
+
+#if NUM_BASE_PROBS != 1984
+ #error Stop_Compiling_Bad_LZMA_PROBS
+#endif
+
+
+#define LZMA_LIT_SIZE 0x300
+
+#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+
+#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4)
+#define COMBINED_PS_STATE (posState + state)
+#define GET_LEN_STATE (posState)
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/*
+p->remainLen : shows status of LZMA decoder:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : need init range coder
+ = kMatchSpecLenStart + 2 : need init range coder and state
+*/
+
+/* ---------- LZMA_DECODE_REAL ---------- */
+/*
+LzmaDec_DecodeReal_3() can be implemented in external ASM file.
+3 - is the code compatibility version of that function for check at link time.
+*/
+
+#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3
+
+/*
+LZMA_DECODE_REAL()
+In:
+ RangeCoder is normalized
+ if (p->dicPos == limit)
+ {
+ LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases.
+ So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol
+ is not END_OF_PAYALOAD_MARKER, then function returns error code.
+ }
+
+Processing:
+ first LZMA symbol will be decoded in any case
+ All checks for limits are at the end of main loop,
+ It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit),
+ RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.
+
+Out:
+ RangeCoder is normalized
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+*/
+
+
+#ifdef _LZMA_DEC_OPT
+
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
+
+#else
+
+static
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)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 lc = p->prop.lc;
+ unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> 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 = CALC_POS_STATE(processedPos, pbMask);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (processedPos != 0 || checkDicSize != 0)
+ prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
+ processedPos++;
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do { NORMAL_LITER_DEC } while (symbol < 0x100);
+ #else
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ #endif
+ }
+ else
+ {
+ unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ }
+ while (symbol < 0x100);
+ #else
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ }
+ #endif
+ }
+
+ dic[dicPos++] = (Byte)symbol;
+ continue;
+ }
+
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ /*
+ // that case was checked before with kBadRepCode
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ */
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + COMBINED_PS_STATE;
+ 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;
+ }
+
+ #ifdef _LZMA_SIZE_OPT
+ {
+ unsigned lim, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ lim = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, lim, len);
+ len += offset;
+ }
+ #else
+ {
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE;
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ len -= 8;
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
+ len += kLenNumLowSymbols * 2;
+ }
+ }
+ }
+ #endif
+
+ 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;
+ unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos;
+ {
+ UInt32 m = 1;
+ distance++;
+ do
+ {
+ REV_BIT_VAR(prob, distance, m);
+ }
+ while (--numDirectBits);
+ distance -= m;
+ }
+ }
+ 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);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ REV_BIT_CONST(prob, i, 1);
+ REV_BIT_CONST(prob, i, 2);
+ REV_BIT_CONST(prob, i, 4);
+ REV_BIT_LAST (prob, i, 8);
+ distance |= i;
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len = kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+ }
+
+ len += kMatchMinLen;
+
+ {
+ SizeT rem;
+ unsigned curLen;
+ SizeT pos;
+
+ if ((rem = limit - dicPos) == 0)
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+
+ curLen = ((rem < len) ? (unsigned)rem : len);
+ pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (curLen <= dicBufSize - pos)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(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;
+}
+#endif
+
+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 = (unsigned)p->remainLen;
+ SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+ SizeT rem = limit - dicPos;
+ if (rem < len)
+ len = (unsigned)(rem);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len != 0)
+ {
+ len--;
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+
+#define kRange0 0xFFFFFFFF
+#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))
+#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)))
+#if kBadRepCode != (0xC0000000 - 0x400)
+ #error Stop_Compiling_Bad_LZMA_Check
+#endif
+
+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;
+
+ if (p->processedPos == 0)
+ if (p->code >= kBadRepCode)
+ return SZ_ERROR_DATA;
+ }
+
+ RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit));
+
+ if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && 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;
+ const CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)p->state;
+ ELzmaDummy res;
+
+ {
+ const CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ 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 += ((UInt32)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;
+ const CLzmaProb *probLit;
+ matchByte += matchByte;
+ bit = offs;
+ offs &= matchByte;
+ probLit = prob + (offs + bit + symbol);
+ GET_BIT2_CHECK(probLit, symbol, 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 + COMBINED_PS_STATE;
+ 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;
+ const CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ unsigned numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ unsigned m = 1;
+ do
+ {
+ REV_BIT_CHECK(prob, i, m);
+ }
+ while (--numDirectBits);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->remainLen = kMatchSpecLenStart + 1;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->remainLen = kMatchSpecLenStart + 2;
+ }
+ if (initState)
+ p->remainLen = kMatchSpecLenStart + 2;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize != 0 && p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ p->code =
+ ((UInt32)p->tempBuf[1] << 24)
+ | ((UInt32)p->tempBuf[2] << 16)
+ | ((UInt32)p->tempBuf[3] << 8)
+ | ((UInt32)p->tempBuf[4]);
+ p->range = 0xFFFFFFFF;
+ p->tempBufSize = 0;
+
+ if (p->remainLen > kMatchSpecLenStart + 1)
+ {
+ SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+ SizeT 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->remainLen = 0;
+ }
+
+ LzmaDec_WriteRem(p, dicLimit);
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int 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->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;
+
+ {
+ unsigned kkk = (unsigned)(p->buf - p->tempBuf);
+ if (rem < kkk)
+ return SZ_ERROR_FAIL; /* some internal error */
+ rem -= kkk;
+ if (lookAhead < rem)
+ return SZ_ERROR_FAIL; /* some internal error */
+ lookAhead -= rem;
+ }
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+
+ if (p->code != 0)
+ return SZ_ERROR_DATA;
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+
+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, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->probs);
+ p->probs = NULL;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->dic);
+ p->dic = NULL;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr 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 = (Byte)(d % 9);
+ d /= 9;
+ p->pb = (Byte)(d / 5);
+ p->lp = (Byte)(d % 5);
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (!p->probs || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ if (!p->probs)
+ return SZ_ERROR_MEM;
+ p->probs_1664 = p->probs + 1664;
+ p->numProbs = numProbs;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr 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, ISzAllocPtr alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+
+ {
+ UInt32 dictSize = propNew.dicSize;
+ SizeT mask = ((UInt32)1 << 12) - 1;
+ if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+ else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
+ dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+ if (dicBufSize < dictSize)
+ dicBufSize = dictSize;
+ }
+
+ if (!p->dic || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize);
+ if (!p->dic)
+ {
+ 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, ISzAllocPtr alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ LzmaDec_Construct(&p);
+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
+ p.dic = dest;
+ p.dicBufSize = outSize;
+ LzmaDec_Init(&p);
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
new file mode 100644
index 000000000..ebc568cb4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
@@ -0,0 +1,234 @@
+/* LzmaDec.h -- LZMA Decoder
+2018-04-21 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+typedef
+#ifdef _LZMA_PROB32
+ UInt32
+#else
+ UInt16
+#endif
+ CLzmaProb;
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ Byte lc;
+ Byte lp;
+ Byte pb;
+ Byte _pad_;
+ 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
+{
+ /* Don't change this structure. ASM code can use it. */
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ CLzmaProb *probs_1664;
+ Byte *dic;
+ SizeT dicBufSize;
+ SizeT dicPos;
+ const Byte *buf;
+ UInt32 range;
+ UInt32 code;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ UInt32 reps[4];
+ UInt32 state;
+ UInt32 remainLen;
+
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ - Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ - 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, ISzAllocPtr alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr 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_Construct()
+ 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, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Precomp.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Precomp.h
new file mode 100644
index 000000000..edb581443
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Precomp.h
@@ -0,0 +1,10 @@
+/* Precomp.h -- StdAfx
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_PRECOMP_H
+#define __7Z_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-history.txt b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-history.txt
new file mode 100644
index 000000000..5ad9a5b1b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-history.txt
@@ -0,0 +1,424 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+18.05 2018-04-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased
+ by 8% for fastest/fast compression levels and
+ by 3% for normal/maximum compression levels.
+- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
+ Windows 10 because of some BUG with "Large Pages" in Windows 10.
+ Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
+- The BUG was fixed in Lzma2Enc.c
+ Lzma2Enc_Encode2() function worked incorretly,
+ if (inStream == NULL) and the number of block threads is more than 1.
+
+
+18.03 beta 2018-03-04
+-------------------------
+- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
+ for x64 with about 30% higher speed than main version of LZMA decoder written in C.
+- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
+- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
+ if there are multiple independent data chunks in LZMA2 stream.
+- 7-Zip now can use multi-threading for xz decoding,
+ if there are multiple blocks in xz stream.
+
+
+18.01 2019-01-28
+-------------------------
+- The BUG in 17.01 - 18.00 beta was fixed:
+ XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()
+ didn't work correctly for xz archives without checksum (CRC).
+
+
+18.00 beta 2019-01-10
+-------------------------
+- The BUG in xz encoder was fixed:
+ There was memory leak of 16 KB for each file compressed with
+ xz compression method, if additional filter was used.
+
+
+17.01 beta 2017-08-28
+-------------------------
+- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
+ 7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
+ CPU utilization was slightly improved.
+- 7-zip now creates multi-block xz archives by default. Block size can be
+ specified with -ms[Size]{m|g} switch.
+- xz decoder now can unpack random block from multi-block xz archives.
+- 7-Zip command line: @listfile now doesn't work after -- switch.
+ Use -i@listfile before -- switch instead.
+- The BUGs were fixed:
+ 7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
+
+
+17.00 beta 2017-04-29
+-------------------------
+- NewHandler.h / NewHandler.cpp:
+ now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
+- C/7zTypes.h : the names of variables in interface structures were changed (vt).
+- Some bugs were fixed. 7-Zip could crash in some cases.
+- Some internal changes in code.
+
+
+16.04 2016-10-04
+-------------------------
+- The bug was fixed in DllSecur.c.
+
+
+16.03 2016-09-28
+-------------------------
+- SFX modules now use some protection against DLL preloading attack.
+- Some bugs in 7z code were fixed.
+
+
+16.02 2016-05-21
+-------------------------
+- The BUG in 16.00 - 16.01 was fixed:
+ Split Handler (SplitHandler.cpp) returned incorrect
+ total size value (kpidSize) for split archives.
+
+
+16.01 2016-05-19
+-------------------------
+- Some internal changes to reduce the number of compiler warnings.
+
+
+16.00 2016-05-10
+-------------------------
+- Some bugs were fixed.
+
+
+15.12 2015-11-19
+-------------------------
+- The BUG in C version of 7z decoder was fixed:
+ 7zDec.c : SzDecodeLzma2()
+ 7z decoder could mistakenly report about decoding error for some 7z archives
+ that use LZMA2 compression method.
+ The probability to get that mistaken decoding error report was about
+ one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
+- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
+ 7zArcIn.c : SzReadHeader2()
+ 7z decoder worked incorrectly for 7z archives that contain
+ empty solid blocks, that can be placed to 7z archive, if some file is
+ unavailable for reading during archive creation.
+
+
+15.09 beta 2015-10-16
+-------------------------
+- The BUG in LZMA / LZMA2 encoding code was fixed.
+ The BUG in LzFind.c::MatchFinder_ReadBlock() function.
+ If input data size is larger than (4 GiB - dictionary_size),
+ the following code worked incorrectly:
+ - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
+ for compressing from memory to memory.
+ That BUG is not related to LZMA encoder version that works via streams.
+ - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
+ default value of chunk size (CLzma2EncProps::blockSize) is changed
+ to value larger than (4 GiB - dictionary_size).
+
+
+9.38 beta 2015-01-03
+-------------------------
+- The BUG in 9.31-9.37 was fixed:
+ IArchiveGetRawProps interface was disabled for 7z archives.
+- The BUG in 9.26-9.36 was fixed:
+ Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
+
+
+9.36 beta 2014-12-26
+-------------------------
+- The BUG in command line version was fixed:
+ 7-Zip created temporary archive in current folder during update archive
+ operation, if -w{Path} switch was not specified.
+ The fixed 7-Zip creates temporary archive in folder that contains updated archive.
+- The BUG in 9.33-9.35 was fixed:
+ 7-Zip silently ignored file reading errors during 7z or gz archive creation,
+ and the created archive contained only part of file that was read before error.
+ The fixed 7-Zip stops archive creation and it reports about error.
+
+
+9.35 beta 2014-12-07
+-------------------------
+- 7zr.exe now support AES encryption.
+- SFX mudules were added to LZMA SDK
+- Some bugs were fixed.
+
+
+9.21 beta 2011-04-11
+-------------------------
+- New class FString for file names at file systems.
+- Speed optimization in CRC code for big-endian CPUs.
+- The BUG in Lzma2Dec.c was fixed:
+ Lzma2Decode function didn't work.
+
+
+9.18 beta 2010-11-02
+-------------------------
+- New small SFX module for installers (SfxSetup).
+
+
+9.12 beta 2010-03-24
+-------------------------
+- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,
+ if more than 10 threads were used (or more than 20 threads in some modes).
+
+
+9.11 beta 2010-03-15
+-------------------------
+- PPMd compression method support
+
+
+9.09 2009-12-12
+-------------------------
+- The bug was fixed:
+ Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+ incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+- Some bugs were fixed
+
+
+9.06 2009-08-17
+-------------------------
+- Some changes in ANSI-C 7z Decoder interfaces.
+
+
+9.04 2009-05-30
+-------------------------
+- LZMA2 compression method support
+- xz format support
+
+
+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/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-sdk.txt b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-sdk.txt
new file mode 100644
index 000000000..bf0b3a5ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/DOC/lzma-sdk.txt
@@ -0,0 +1,357 @@
+LZMA SDK 18.05
+--------------
+
+LZMA SDK provides the documentation, samples, header files,
+libraries, and tools you need to develop applications that
+use 7z / LZMA / LZMA2 / XZ compression.
+
+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.
+
+LZMA2 is a LZMA based compression method. LZMA2 provides better
+multithreading support for compression than LZMA and some other improvements.
+
+7z is a file format for data compression and file archiving.
+7z is a main file format for 7-Zip compression program (www.7-zip.org).
+7z format supports different compression methods: LZMA, LZMA2 and others.
+7z also supports AES-256 based encryption.
+
+XZ is a file format for data compression that uses LZMA2 compression.
+XZ format provides additional features: SHA/CRC check, filters for
+improved compression ratio, splitting to blocks and streams,
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Some code in LZMA SDK is based on public domain code from another developers:
+ 1) PPMd var.H (2001): Dmitry Shkarin
+ 2) SHA-256: Wei Dai (Crypto++ library)
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute the
+original LZMA SDK code, either in source code form or as a compiled binary, for
+any purpose, commercial or non-commercial, and by any means.
+
+LZMA SDK code is compatible with open source licenses, for example, you can
+include it to GNU GPL or GNU LGPL code.
+
+
+LZMA SDK Contents
+-----------------
+
+ Source code:
+
+ - C / C++ / C# / Java - LZMA compression and decompression
+ - C / C++ - LZMA2 compression and decompression
+ - C / C++ - XZ compression and decompression
+ - C - 7z decompression
+ - C++ - 7z compression and decompression
+ - C - small SFXs for installers (7z decompression)
+ - C++ - SFXs and SFXs for installers (7z decompression)
+
+ Precomiled binaries:
+
+ - console programs for lzma / 7z / xz compression and decompression
+ - SFX modules for installers.
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+CPP/7zip/Bundles/LzmaCon
+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
+
+Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux):
+
+ http://p7zip.sourceforge.net/
+
+
+Files
+-----
+
+DOC/7zC.txt - 7z ANSI-C Decoder description
+DOC/7zFormat.txt - 7z Format description
+DOC/installer.txt - information about 7-Zip for installers
+DOC/lzma.txt - LZMA compression description
+DOC/lzma-sdk.txt - LZMA SDK description (this file)
+DOC/lzma-history.txt - history of LZMA SDK
+DOC/lzma-specification.txt - Specification of LZMA
+DOC/Methods.txt - Compression method IDs for .7z
+
+bin/installer/ - example script to create installer that uses SFX module,
+
+bin/7zdec.exe - simplified 7z archive decoder
+bin/7zr.exe - 7-Zip console program (reduced version)
+bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version)
+bin/lzma.exe - file->file LZMA encoder/decoder for Windows
+bin/7zS2.sfx - small SFX module for installers (GUI version)
+bin/7zS2con.sfx - small SFX module for installers (Console version)
+bin/7zSD.sfx - SFX module for installers.
+
+
+7zDec.exe
+---------
+7zDec.exe is simplified 7z archive decoder.
+It supports only LZMA, LZMA2, and PPMd methods.
+7zDec decodes whole solid block from 7z archive to RAM.
+The RAM consumption can be high.
+
+
+
+
+Source code structure
+---------------------
+
+
+Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption)
+
+C/ - C files (compression / decompression and other)
+ Util/
+ 7z - 7z decoder program (decoding 7z files)
+ Lzma - LZMA program (file->file LZMA encoder/decoder).
+ LzmaLib - LZMA library (.DLL for Windows)
+ SfxSetup - small SFX module for installers
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules (files)
+
+ Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version)
+ Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.
+ Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ LzmaCon - lzma.exe: LZMA compression/decompression
+ LzmaSpec - example code for LZMA Specification
+ SFXCon - 7zCon.sfx: Console 7z SFX module
+ SFXSetup - 7zS.sfx: 7z SFX module for installers
+ SFXWin - 7z.sfx: GUI 7z SFX module
+
+ Common - common files for 7-Zip
+
+ Compress - files for compression/decompression
+
+ Crypto - files for encryption / decompression
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console program (7z.exe)
+ Explorer - Some code from 7-Zip Shell extension
+ FileManager - Some GUI code from 7-Zip File Manager
+ GUI - Some GUI code from 7-Zip
+
+
+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)
+
+
+Note:
+ Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code.
+ 7-Zip's 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 modern 2 GHz cpu
+ - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC)
+ - 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) Mispredicted 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.
+
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
new file mode 100644
index 000000000..e1315b6ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
@@ -0,0 +1,37 @@
+/** @file
+ LZMA UEFI header file
+
+ Allows LZMA code to build under UEFI (edk2) build environment
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __UEFILZMA_H__
+#define __UEFILZMA_H__
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+
+#ifdef _WIN32
+#undef _WIN32
+#endif
+
+typedef UINTN size_t;
+
+#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/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.c b/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.c
new file mode 100644
index 000000000..807426898
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.c
@@ -0,0 +1,208 @@
+/** @file
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/NonDiscoverableDevice.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NonDiscoverableDeviceRegistrationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/NonDiscoverableDevice.h>
+
+/**
+ Get Guid form the type of non-discoverable device.
+
+ @param[in] Type The type of non-discoverable device.
+
+ @retval Return the Guid.
+
+**/
+STATIC
+CONST EFI_GUID *
+GetGuidFromType (
+ IN NON_DISCOVERABLE_DEVICE_TYPE Type
+ )
+{
+ switch (Type) {
+ case NonDiscoverableDeviceTypeAhci:
+ return &gEdkiiNonDiscoverableAhciDeviceGuid;
+
+ case NonDiscoverableDeviceTypeAmba:
+ return &gEdkiiNonDiscoverableAmbaDeviceGuid;
+
+ case NonDiscoverableDeviceTypeEhci:
+ return &gEdkiiNonDiscoverableEhciDeviceGuid;
+
+ case NonDiscoverableDeviceTypeNvme:
+ return &gEdkiiNonDiscoverableNvmeDeviceGuid;
+
+ case NonDiscoverableDeviceTypeOhci:
+ return &gEdkiiNonDiscoverableOhciDeviceGuid;
+
+ case NonDiscoverableDeviceTypeSdhci:
+ return &gEdkiiNonDiscoverableSdhciDeviceGuid;
+
+ case NonDiscoverableDeviceTypeUfs:
+ return &gEdkiiNonDiscoverableUfsDeviceGuid;
+
+ case NonDiscoverableDeviceTypeUhci:
+ return &gEdkiiNonDiscoverableUhciDeviceGuid;
+
+ case NonDiscoverableDeviceTypeXhci:
+ return &gEdkiiNonDiscoverableXhciDeviceGuid;
+
+ default:
+ return NULL;
+ }
+}
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ UINT64 BaseAddress;
+ UINT8 ResourceType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} NON_DISCOVERABLE_DEVICE_PATH;
+#pragma pack ()
+
+/**
+ Register a non-discoverable MMIO device.
+
+ @param[in] Type The type of non-discoverable device
+ @param[in] DmaType Whether the device is DMA coherent
+ @param[in] InitFunc Initialization routine to be invoked when
+ the device is enabled
+ @param[in,out] Handle The handle onto which to install the
+ non-discoverable device protocol.
+ If Handle is NULL or *Handle is NULL, a
+ new handle will be allocated.
+ @param[in] NumMmioResources The number of UINTN base/size pairs that
+ follow, each describing an MMIO region
+ owned by the device
+ @param[in] ... The variable argument list which contains the
+ info about MmioResources.
+
+ @retval EFI_SUCCESS The registration succeeded.
+ @retval EFI_INVALID_PARAMETER An invalid argument was given
+ @retval Other The registration failed.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterNonDiscoverableMmioDevice (
+ IN NON_DISCOVERABLE_DEVICE_TYPE Type,
+ IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,
+ IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,
+ IN OUT EFI_HANDLE *Handle OPTIONAL,
+ IN UINTN NumMmioResources,
+ ...
+ )
+{
+ NON_DISCOVERABLE_DEVICE *Device;
+ NON_DISCOVERABLE_DEVICE_PATH *DevicePath;
+ EFI_HANDLE LocalHandle;
+ EFI_STATUS Status;
+ UINTN AllocSize;
+ UINTN Index;
+ VA_LIST Args;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ UINTN Base, Size;
+
+ if (Type >= NonDiscoverableDeviceTypeMax ||
+ DmaType >= NonDiscoverableDeviceDmaTypeMax ||
+ NumMmioResources == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Handle == NULL) {
+ Handle = &LocalHandle;
+ LocalHandle = NULL;
+ }
+
+ AllocSize = sizeof *Device +
+ NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);
+ Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize);
+ if (Device == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Device->Type = GetGuidFromType (Type);
+ ASSERT (Device->Type != NULL);
+
+ Device->DmaType = DmaType;
+ Device->Initialize = InitFunc;
+ Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1);
+
+ VA_START (Args, NumMmioResources);
+ for (Index = 0; Index < NumMmioResources; Index++) {
+ Desc = &Device->Resources [Index];
+ Base = VA_ARG (Args, UINTN);
+ Size = VA_ARG (Args, UINTN);
+
+ Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Desc->Len = sizeof *Desc - 3;
+ Desc->AddrRangeMin = Base;
+ Desc->AddrLen = Size;
+ Desc->AddrRangeMax = Base + Size - 1;
+ Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Desc->AddrSpaceGranularity = ((EFI_PHYSICAL_ADDRESS)Base + Size > SIZE_4GB) ? 64 : 32;
+ Desc->AddrTranslationOffset = 0;
+ }
+ VA_END (Args);
+
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources [NumMmioResources];
+
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode (
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ sizeof (*DevicePath));
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FreeDevice;
+ }
+
+ CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid);
+
+ //
+ // Use the base address and type of the first region to
+ // make the device path unique
+ //
+ DevicePath->BaseAddress = Device->Resources [0].AddrRangeMin;
+ DevicePath->ResourceType = Device->Resources [0].ResType;
+
+ SetDevicePathNodeLength (&DevicePath->Vendor,
+ sizeof (*DevicePath) - sizeof (DevicePath->End));
+ SetDevicePathEndNode (&DevicePath->End);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (Handle,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid, Device,
+ &gEfiDevicePathProtocolGuid, DevicePath,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ goto FreeDevicePath;
+ }
+ return EFI_SUCCESS;
+
+FreeDevicePath:
+ FreePool (DevicePath);
+
+FreeDevice:
+ FreePool (Device);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf b/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
new file mode 100644
index 000000000..e4778b6e5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
@@ -0,0 +1,42 @@
+## @file
+# Component Description File for NonDiscoverableDeviceRegistrationLib.
+#
+# Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = NonDiscoverableDeviceRegistrationLib
+ FILE_GUID = 8802ae41-8184-49cb-8aec-62627cd7ceb4
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NonDiscoverableDeviceRegistrationLib
+
+[Sources]
+ NonDiscoverableDeviceRegistrationLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEdkiiNonDiscoverableDeviceProtocolGuid ## PRODUCES
+
+[Guids]
+ gEdkiiNonDiscoverableAhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableAmbaDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableEhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableNvmeDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableOhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableSdhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableUfsDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableUhciDeviceGuid ## CONSUMES ## GUID
+ gEdkiiNonDiscoverableXhciDeviceGuid ## CONSUMES ## GUID
diff --git a/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c
new file mode 100644
index 000000000..bbe769a08
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c
@@ -0,0 +1,56 @@
+/** @file
+ Null instance of OEM Hook Status Code Library with empty functions.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+/**
+ Initialize OEM status code device .
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OemHookStatusCodeInitialize (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Report status code to OEM 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. 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
+EFIAPI
+OemHookStatusCodeReport (
+ 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
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
new file mode 100644
index 000000000..3002a19b5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
@@ -0,0 +1,30 @@
+## @file
+# Null instance of OEM Hook Status Code Library with empty functions.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = OemHookStatusCodeLibNull
+ MODULE_UNI_FILE = OemHookStatusCodeLibNull.uni
+ FILE_GUID = 54D2878F-25CD-4a2b-8420-EBD18E609C76
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = OemHookStatusCodeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ OemHookStatusCodeLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni
new file mode 100644
index 000000000..861020c1b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null instance of OEM Hook Status Code Library with empty functions.
+//
+// Null instance of OEM Hook Status Code Library with empty functions.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of OEM Hook Status Code Library with empty functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of OEM Hook Status Code Library with empty functions."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c
new file mode 100644
index 000000000..0bf07e349
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c
@@ -0,0 +1,109 @@
+/** @file
+ Null instance of PCI Host Bridge Library with empty functions.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiDxe.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/DebugLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ )
+{
+ *Count = 0;
+ return NULL;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ return;
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+ DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (Descriptor->ResType <
+ (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+ sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+ )
+ );
+ DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
new file mode 100644
index 000000000..4083b87bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
@@ -0,0 +1,32 @@
+## @file
+# Null instance of PCI Host Bridge Library with empty functions.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHostBridgeLibNull
+ MODULE_UNI_FILE = PciHostBridgeLibNull.uni
+ FILE_GUID = A19A6C36-7053-4E2C-8BD0-E8286230E473
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PciHostBridgeLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni
new file mode 100644
index 000000000..2c891fa01
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Null instance of PCI Host Bridge Library with empty functions.
+//
+// Null instance of PCI Host Bridge Library with empty functions.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of PCI Host Bridge Library with empty functions."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of PCI Host Bridge Library with empty functions."
diff --git a/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c
new file mode 100644
index 000000000..483c0c773
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c
@@ -0,0 +1,210 @@
+/** @file
+
+ This library registers CRC32 guided section handler
+ to parse CRC32 encapsulation section and extract raw data.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Guid/Crc32GuidedSectionExtraction.h>
+#include <Library/BaseLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+///
+/// CRC32 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION2_HEADER;
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successfully retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for 32bit CRC value in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ UINT32 SectionCrc32Checksum;
+ UINT32 Crc32Checksum;
+ UINT32 OutputBufferSize;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION2_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // Calculate CRC32 Checksum of Image
+ //
+ Crc32Checksum = CalculateCrc32 (*OutputBuffer, OutputBufferSize);
+ if (Crc32Checksum != SectionCrc32Checksum) {
+ //
+ // If Crc32 checksum is not matched, AUTH tested failed bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+
+ //
+ // Temp solution until PeiCore checks AUTH Status.
+ //
+ if ((*AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register the handler to extract CRC32 guided section.
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to register this handler.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCrc32GuidedSectionExtractLibConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ Crc32GuidedSectionGetInfo,
+ Crc32GuidedSectionHandler
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
new file mode 100644
index 000000000..db370ea8f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Pei Crc32 Guided Section Extract library.
+#
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register CRC32 guided section handler
+# that parses CRC32 encapsulation section and extracts raw data.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCrc32GuidedSectionExtractLib
+ FILE_GUID = 1EBE57F5-BE42-45f0-A1F9-FA3DC633910B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|PEI_CORE PEIM
+ CONSTRUCTOR = PeiCrc32GuidedSectionExtractLibConstructor
+ MODULE_UNI_FILE = PeiCrc32GuidedSectionExtractLib.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiCrc32GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ DebugLib
+ BaseMemoryLib
+ BaseLib
+
+[Guids]
+ gEfiCrc32GuidedSectionExtractionGuid ## PRODUCES ## UNDEFINED
diff --git a/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni
new file mode 100644
index 000000000..118aa07e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Pei Crc32 Guided Section Extract library.
+//
+// This library doesn't produce any library class. The constructor function uses
+// ExtractGuidedSectionLib service to register CRC32 guided section handler
+// that parses CRC32 encapsulation section and extracts raw data.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Pei Crc32 Guided Section Extract library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register CRC32 guided section handler that parses CRC32 encapsulation section and extracts raw data."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/DebugLib.c b/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/DebugLib.c
new file mode 100644
index 000000000..05a7dab99
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/DebugLib.c
@@ -0,0 +1,454 @@
+/** @file
+ PEI debug lib instance base on gEdkiiDebugPpiGuid to save PEIM size.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/Debug.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugPrintErrorLevelLib.h>
+#include <Library/BaseLib.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().
+
+ @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,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, Format);
+ DebugVPrint (ErrorLevel, Format, Marker);
+ VA_END (Marker);
+}
+
+
+/**
+ Prints a debug message to the debug output device if the specified
+ error level is enabled.
+ This function use BASE_LIST which would provide a more compatible
+ service than VA_LIST.
+
+ 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().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param BaseListMarker BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugBPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN BASE_LIST BaseListMarker
+ )
+{
+ EFI_STATUS Status;
+ EDKII_DEBUG_PPI *DebugPpi;
+
+ //
+ // If Format is NULL, then ASSERT().
+ //
+ ASSERT (Format != NULL);
+
+ //
+ // Check driver Debug Level value and global debug level
+ //
+ if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
+ return;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gEdkiiDebugPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&DebugPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ DebugPpi->DebugBPrint (
+ ErrorLevel,
+ Format,
+ BaseListMarker
+ );
+}
+
+
+/**
+ Worker function that convert a VA_LIST to a BASE_LIST based on a
+ Null-terminated format string.
+
+ @param Format Null-terminated format string.
+ @param VaListMarker VA_LIST style variable argument list consumed
+ by processing Format.
+ @param BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+ @param Size The size, in bytes, of the BaseListMarker buffer.
+
+ @return TRUE The VA_LIST has been converted to BASE_LIST.
+ @return FALSE The VA_LIST has not been converted to BASE_LIST.
+
+**/
+BOOLEAN
+VaListToBaseList (
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker,
+ OUT BASE_LIST BaseListMarker,
+ IN UINTN Size
+ )
+{
+ BASE_LIST BaseListStart;
+ BOOLEAN Long;
+
+ ASSERT (Format != NULL);
+
+ ASSERT (BaseListMarker != NULL);
+
+ BaseListStart = BaseListMarker;
+
+ 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 size of BaseListMarker, then return FALSE
+ //
+ if (((UINTN)BaseListMarker - (UINTN)BaseListStart) > Size) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ 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().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param VaListMarker VA_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugVPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+ BOOLEAN Converted;
+
+ //
+ // Convert the VaList to BaseList
+ //
+ Converted = VaListToBaseList (
+ Format,
+ VaListMarker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+
+ if (!Converted) {
+ return;
+ }
+
+ DebugBPrint (ErrorLevel, Format, (BASE_LIST)BaseListMarker);
+}
+
+
+/**
+ 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 The 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 The pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+DebugAssert (
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ )
+{
+ EFI_STATUS Status;
+ EDKII_DEBUG_PPI *DebugPpi;
+
+ Status = PeiServicesLocatePpi (
+ &gEdkiiDebugPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&DebugPpi
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // 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 ();
+ }
+ } else {
+ DebugPpi->DebugAssert (
+ FileName,
+ LineNumber,
+ Description
+ );
+ }
+}
+
+
+/**
+ 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 The pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
+ @param Length The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
+
+ @return Buffer The 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/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf b/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf
new file mode 100644
index 000000000..4df479d74
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf
@@ -0,0 +1,59 @@
+## @file
+# Debug Lib instance through DebugServicePei for PEI phase
+#
+# This module use gEdkiiDebugPpiGuid to implement the PEI DebugLib for reduce
+# the size of PEIMs which consume DebugLib.
+#
+# Notes: this library instance can be used only the PEIM
+# DebugSerivicePei is runed and install the gEdkiiDebugPpiGuid.
+# And this library contian the depex of gEfiPeiPcdPpiGuid, that
+# means the PcdPei.inf cannot use this library instance. The
+# PcdPei.inf should use the same library instance that the
+# PEIM DebugServicePei consumes.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDebugLibDebugPpi
+ FILE_GUID = 2E08836C-4D1C-42F7-BBBE-EC5D25F1FDD4
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DebugLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ DebugPrintErrorLevelLib
+ PeiServicesLib
+ PeiServicesTablePointerLib
+ BaseLib
+
+[Ppis]
+ gEdkiiDebugPpiGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES
+
+[Depex]
+ gEdkiiDebugPpiGuid
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c
new file mode 100644
index 000000000..e545be206
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c
@@ -0,0 +1,72 @@
+/** @file
+ NULL Library class that reads Debug Mask variable and if it exists makes a
+ HOB that contains the debug mask.
+
+ Copyright (c) 2011, Apple, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Guid/DebugMask.h>
+
+
+/**
+ The constructor reads variable and sets HOB
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDebugPrintHobLibConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
+ UINTN Size;
+ UINT64 GlobalErrorLevel;
+ UINT32 HobErrorLevel;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Variable
+ );
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (GlobalErrorLevel);
+ Status = Variable->GetVariable (
+ Variable,
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ NULL,
+ &Size,
+ &GlobalErrorLevel
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Build the GUID'ed HOB for DXE
+ //
+ HobErrorLevel = (UINT32)GlobalErrorLevel;
+ BuildGuidDataHob (
+ &gEfiGenericVariableGuid,
+ &HobErrorLevel,
+ sizeof (HobErrorLevel)
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf
new file mode 100644
index 000000000..26a027e8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf
@@ -0,0 +1,45 @@
+## @file
+# NULL Library class that reads Debug Mask variable and if it exists makes a
+# HOB that contains the debug mask.
+#
+# Copyright (c) 2011, Apple, Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDebugPrintHobLib
+ MODULE_UNI_FILE = PeiDebugPrintHobLib.uni
+ FILE_GUID = EB0BDD73-DABB-E74B-BF51-62DC1DA521E1
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|PEIM
+ CONSTRUCTOR = PeiDebugPrintHobLibConstructor
+
+
+[Sources]
+ PeiDebugPrintHobLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"EFIDebug"
+ ## SOMETIMES_PRODUCES ## HOB
+ gEfiGenericVariableGuid
+
+[Depex]
+ gEfiPeiReadOnlyVariable2PpiGuid
diff --git a/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni
new file mode 100644
index 000000000..bdc221b70
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// NULL Library class that reads Debug Mask variable and if it exists makes a
+//
+// HOB that contains the debug mask.
+//
+// Copyright (c) 2011, Apple, Inc. All rights reserved.<BR>
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Reads Debug Mask variable and if it exists makes a HOB that contains the debug mask"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL Library class that reads Debug Mask variable and if it exists makes a HOB that contains the debug mask."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
new file mode 100644
index 000000000..fb4740146
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
@@ -0,0 +1,601 @@
+/** @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 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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>
+
+//
+// VA_LIST can not initialize to NULL for all compiler, so we use this to
+// indicate a null VA_LIST
+//
+VA_LIST mVaListNull;
+
+/**
+ 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,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, Format);
+ DebugVPrint (ErrorLevel, Format, Marker);
+ VA_END (Marker);
+}
+
+/**
+ Prints a debug message to the debug output device if the specified
+ error level is enabled base on Null-terminated format string and a
+ VA_LIST argument list or a BASE_LIST argument list.
+
+ 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.
+
+ Only one list type is used.
+ If BaseListMarker == NULL, then use VaListMarker.
+ Otherwise use BaseListMarker and the VaListMarker should be initilized as
+ mVaListNull.
+
+ If Format is NULL, then ASSERT().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param VaListMarker VA_LIST marker for the variable argument list.
+ @param BaseListMarker BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+DebugPrintMarker (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker,
+ IN BASE_LIST BaseListMarker
+ )
+{
+ UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
+ EFI_DEBUG_INFO *DebugInfo;
+ UINTN TotalSize;
+ BASE_LIST BaseListMarkerPointer;
+ 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)
+ // BaseListMarkerPointer->|------------------------|
+ // | ... |
+ // | 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 truncate it.
+ //
+ if (TotalSize > sizeof (Buffer)) {
+ TotalSize = sizeof (Buffer);
+ }
+
+ //
+ // Fill in EFI_DEBUG_INFO
+ //
+ // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarkerPointer is
+ // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarkerPointer will cause
+ // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
+ // just makes address of BaseListMarkerPointer, which follows DebugInfo, 64-bit aligned.
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;
+ DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
+ BaseListMarkerPointer = (BASE_LIST)(DebugInfo + 1);
+ FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
+
+ //
+ // Copy the Format string into the record. It will be truncated if it's too long.
+ //
+ AsciiStrnCpyS (
+ FormatString, sizeof(Buffer) - (4 + sizeof(EFI_DEBUG_INFO) + 12 * sizeof(UINT64)),
+ Format, sizeof(Buffer) - (4 + sizeof(EFI_DEBUG_INFO) + 12 * sizeof(UINT64)) - 1
+ );
+
+ //
+ // 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.
+ //
+
+ //
+ // Use the actual format string.
+ //
+ Format = FormatString;
+ 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.
+ //
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, 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) {
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, INT64) = VA_ARG (VaListMarker, INT64);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, INT64) = BASE_ARG (BaseListMarker, INT64);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, int) = VA_ARG (VaListMarker, int);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, int) = BASE_ARG (BaseListMarker, int);
+ }
+ }
+ } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') {
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, VOID *) = VA_ARG (VaListMarker, VOID *);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, VOID *) = BASE_ARG (BaseListMarker, VOID *);
+ }
+ } else if (*Format == 'c') {
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);
+ }
+ } else if (*Format == 'r') {
+ if (BaseListMarker == NULL) {
+ BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
+ } else {
+ BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = BASE_ARG (BaseListMarker, 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 *)BaseListMarkerPointer <= FormatString);
+
+ //
+ // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
+ //
+ if ((CHAR8 *)BaseListMarkerPointer > FormatString) {
+ return;
+ }
+ }
+
+ //
+ // 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 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().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param VaListMarker VA_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugVPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker
+ )
+{
+ DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
+}
+
+/**
+ Prints a debug message to the debug output device if the specified
+ error level is enabled.
+ This function use BASE_LIST which would provide a more compatible
+ service than VA_LIST.
+
+ 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().
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param BaseListMarker BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugBPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN BASE_LIST BaseListMarker
+ )
+{
+ DebugPrintMarker (ErrorLevel, Format, mVaListNull, BaseListMarker);
+}
+
+/**
+ 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 ModuleNameSize;
+ UINTN FileNameSize;
+ UINTN DescriptionSize;
+
+ //
+ // Get string size
+ //
+ HeaderSize = sizeof (EFI_DEBUG_ASSERT_DATA);
+ //
+ // Compute string size of module name enclosed by []
+ //
+ ModuleNameSize = 2 + AsciiStrSize (gEfiCallerBaseName);
+ FileNameSize = AsciiStrSize (FileName);
+ DescriptionSize = AsciiStrSize (Description);
+
+ //
+ // Make sure it will all fit in the passed in buffer.
+ //
+ if (HeaderSize + ModuleNameSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
+ //
+ // remove module name if it's too long to be filled into buffer
+ //
+ ModuleNameSize = 0;
+ 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);
+
+ Temp = (CHAR8 *)(AssertData + 1);
+
+ //
+ // Copy Ascii [ModuleName].
+ //
+ if (ModuleNameSize != 0) {
+ CopyMem(Temp, "[", 1);
+ CopyMem(Temp + 1, gEfiCallerBaseName, ModuleNameSize - 3);
+ CopyMem(Temp + ModuleNameSize - 2, "] ", 2);
+ }
+
+ //
+ // Copy Ascii FileName including NULL terminator.
+ //
+ Temp = CopyMem (Temp + ModuleNameSize, FileName, FileNameSize);
+ Temp[FileNameSize - 1] = 0;
+ TotalSize += (ModuleNameSize + 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/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
new file mode 100644
index 000000000..b52fc5686
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
@@ -0,0 +1,49 @@
+## @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 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[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_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 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/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
new file mode 100644
index 000000000..0b508b21f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
@@ -0,0 +1,16 @@
+// /** @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 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Library based on report status code library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Library for PEIMs and DXE drivers that sends debug messages to ReportStatusCode."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c
new file mode 100644
index 000000000..fa6b30905
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c
@@ -0,0 +1,75 @@
+/** @file
+ Implementation of Ipmi Library in PEI Phase for SMS.
+
+ Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/IpmiPpi.h>
+#include <Library/IpmiLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+ PEI_IPMI_PPI *IpmiPpi;
+
+ Status = PeiServicesLocatePpi(
+ &gPeiIpmiPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IpmiPpi
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Ipmi Ppi is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand in Pei Phase under SMS Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = IpmiPpi->IpmiSubmitCommand (
+ IpmiPpi,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf
new file mode 100644
index 000000000..110a67d4e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf
@@ -0,0 +1,37 @@
+## @file
+# Instance of IPMI Library in PEI phase for SMS.
+#
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiIpmiLibIpmiPpi
+ MODULE_UNI_FILE = PeiIpmiLibIpmiPpi.uni
+ FILE_GUID = 43679142-87C4-44AD-AF02-B47F782D6CF3
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|PEIM PEI_CORE
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PeiIpmiLibIpmiPpi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ PeiServicesLib
+
+[Ppis]
+ gPeiIpmiPpiGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.uni b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.uni
new file mode 100644
index 000000000..fb4bef440
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Instance of IPMI Library in PEI phase for SMS.
+//
+// Instance of IPMI Library in PEI phase for SMS.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Instance of IPMI Library in PEI phase for SMS."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Instance of IPMI Library in PEI phase for SMS."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
new file mode 100644
index 000000000..ddae0d381
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
@@ -0,0 +1,859 @@
+/** @file
+ Performance library instance used in PEI phase.
+
+ This file implements all APIs in Performance Library class in MdePkg. It creates
+ performance logging GUIDed HOB on the first performance logging and then logs the
+ performance data to the GUIDed HOB. Due to the limitation of temporary RAM, the maximum
+ number of performance logging entry is specified by PcdMaxPeiPerformanceLogEntries or
+ PcdMaxPeiPerformanceLogEntries16.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiPei.h>
+
+#include <Guid/ExtendedFirmwarePerformance.h>
+#include <Guid/PerformanceMeasurement.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
+#define PEI_MAX_RECORD_SIZE (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + STRING_SIZE)
+
+
+/**
+ Return the pointer to the FPDT record in the allocated memory.
+
+ @param RecordSize The size of FPDT record.
+ @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
+ @param PeiPerformanceLogHeader Pointer to the header of the PEI Performance records in the GUID Hob.
+
+ @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
+ @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+ IN UINT8 RecordSize,
+ IN OUT FPDT_RECORD_PTR *FpdtRecordPtr,
+ IN OUT FPDT_PEI_EXT_PERF_HEADER **PeiPerformanceLogHeader
+)
+{
+ UINT16 PeiPerformanceLogEntries;
+ UINTN PeiPerformanceSize;
+ UINT8 *PeiFirmwarePerformance;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Get the number of PeiPerformanceLogEntries form PCD.
+ //
+ PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?
+ PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :
+ PcdGet8 (PcdMaxPeiPerformanceLogEntries));
+
+ //
+ // Create GUID HOB Data.
+ //
+ GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);
+ PeiFirmwarePerformance = NULL;
+ while (GuidHob != NULL) {
+ //
+ // PEI Performance HOB was found, then return the existing one.
+ //
+ PeiFirmwarePerformance = (UINT8*)GET_GUID_HOB_DATA (GuidHob);
+ *PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;
+ if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize > (PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {
+ (*PeiPerformanceLogHeader)->HobIsFull = TRUE;
+ }
+ if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= (PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + (*PeiPerformanceLogHeader)->SizeOfAllEntries);
+ break;
+ }
+ //
+ // Previous HOB is used, then find next one.
+ //
+ GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
+ }
+
+ if (GuidHob == NULL) {
+ //
+ // PEI Performance HOB was not found, then build one.
+ //
+ PeiPerformanceSize = sizeof (FPDT_PEI_EXT_PERF_HEADER) +
+ PEI_MAX_RECORD_SIZE * PeiPerformanceLogEntries;
+ PeiFirmwarePerformance = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);
+ if (PeiFirmwarePerformance != NULL) {
+ ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);
+ (*PeiPerformanceLogHeader) = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER));
+ }
+ }
+
+ if (PeiFirmwarePerformance == NULL) {
+ //
+ // there is no enough resource to store performance data
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+Check whether the Token is a known one which is uesed by core.
+
+@param Token Pointer to a Null-terminated ASCII string
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownTokens (
+ IN CONST CHAR8 *Token
+ )
+{
+ if (Token == NULL) {
+ return FALSE;
+ }
+
+ if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
+ AsciiStrCmp (Token, PEI_TOK) == 0 ||
+ AsciiStrCmp (Token, DXE_TOK) == 0 ||
+ AsciiStrCmp (Token, BDS_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
+ AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, PEIM_TOK) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+Check whether the ID is a known one which map to the known Token.
+
+@param Identifier 32-bit identifier.
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownID (
+ IN UINT32 Identifier
+ )
+{
+ if (Identifier == MODULE_START_ID ||
+ Identifier == MODULE_END_ID ||
+ Identifier == MODULE_LOADIMAGE_START_ID ||
+ Identifier == MODULE_LOADIMAGE_END_ID ||
+ Identifier == MODULE_DB_START_ID ||
+ Identifier == MODULE_DB_END_ID ||
+ Identifier == MODULE_DB_SUPPORT_START_ID ||
+ Identifier == MODULE_DB_SUPPORT_END_ID ||
+ Identifier == MODULE_DB_STOP_START_ID ||
+ Identifier == MODULE_DB_STOP_END_ID) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get the FPDT record identifier.
+
+ @param Attribute The attribute of the Record.
+ PerfStartEntry: Start Record.
+ PerfEndEntry: End Record.
+ @param Handle Pointer to environment specific context used to identify the component being measured.
+ @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
+ @param ProgressID On return, pointer to the ProgressID.
+
+ @retval EFI_SUCCESS Get record info successfully.
+ @retval EFI_INVALID_PARAMETER No matched FPDT record.
+
+**/
+EFI_STATUS
+GetFpdtRecordId (
+ IN BOOLEAN Attribute,
+ IN CONST VOID *Handle,
+ IN CONST CHAR8 *String,
+ OUT UINT16 *ProgressID
+ )
+{
+ //
+ // Get the ProgressID based on the Token.
+ // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of FPDT_DYNAMIC_STRING_EVENT_TYPE.
+ //
+ if (String != NULL) {
+ if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_LOADIMAGE_START_ID;
+ } else {
+ *ProgressID = MODULE_LOADIMAGE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, SEC_TOK) == 0 || // "SEC"
+ AsciiStrCmp (String, PEI_TOK) == 0) { // "PEI"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_CROSSMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_CROSSMODULE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, PEIM_TOK) == 0) { // "PEIM"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_START_ID;
+ } else {
+ *ProgressID = MODULE_END_ID;
+ }
+ } else { //Pref used in Modules.
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ }
+ } else if (Handle != NULL) { //Pref used in Modules.
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Copies the string from Source into Destination and updates Length with the
+ size of the string.
+
+ @param Destination - destination of the string copy
+ @param Source - pointer to the source string which will get copied
+ @param Length - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+ IN OUT CHAR8 *Destination,
+ IN CONST CHAR8 *Source,
+ IN OUT UINT8 *Length
+ )
+{
+ UINTN StringLen;
+ UINTN DestMax;
+
+ ASSERT (Source != NULL);
+
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ DestMax = STRING_SIZE;
+ } else {
+ DestMax = AsciiStrSize (Source);
+ if (DestMax > STRING_SIZE) {
+ DestMax = STRING_SIZE;
+ }
+ }
+ StringLen = AsciiStrLen (Source);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+ *Length += (UINT8)DestMax;
+
+ return;
+}
+
+
+/**
+ Convert PEI performance log to FPDT String boot record.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param Ticker - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param PerfId - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+
+**/
+EFI_STATUS
+InsertFpdtRecord (
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Ticker,
+ IN UINT64 Address, OPTIONAL
+ IN UINT16 PerfId,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+{
+ FPDT_RECORD_PTR FpdtRecordPtr;
+ CONST VOID *ModuleGuid;
+ CONST CHAR8 *StringPtr;
+ EFI_STATUS Status;
+ UINT64 TimeStamp;
+ FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader;
+
+ StringPtr = NULL;
+ FpdtRecordPtr.RecordHeader = NULL;
+ PeiPerformanceLogHeader = NULL;
+
+ //
+ // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
+ // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
+ //
+ if (Attribute != PerfEntry) {
+ //
+ // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
+ // !!! Note: If the Perf is not the known Token used in the core but have same
+ // ID with the core Token, this case will not be supported.
+ // And in currtnt usage mode, for the unkown ID, there is a general rule:
+ // If it is start pref: the lower 4 bits of the ID should be 0.
+ // If it is end pref: the lower 4 bits of the ID should not be 0.
+ // If input ID doesn't follow the rule, we will adjust it.
+ //
+ if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ return EFI_UNSUPPORTED;
+ } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ if (Attribute == PerfStartEntry && ((PerfId & 0x000F) != 0)) {
+ PerfId &= 0xFFF0;
+ } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+ PerfId += 1;
+ }
+ } else if (PerfId == 0) {
+ Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &PerfId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // 2. Get the buffer to store the FPDT record.
+ //
+ Status = GetFpdtRecordPtr (PEI_MAX_RECORD_SIZE, &FpdtRecordPtr, &PeiPerformanceLogHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 3 Get the TimeStamp.
+ //
+ if (Ticker == 0) {
+ Ticker = GetPerformanceCounter ();
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ } else if (Ticker == 1) {
+ TimeStamp = 0;
+ } else {
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ }
+
+ //
+ // 4.Get the ModuleGuid.
+ //
+ if (CallerIdentifier != NULL) {
+ ModuleGuid = CallerIdentifier;
+ } else {
+ ModuleGuid = &gEfiCallerIdGuid;
+ }
+
+ //
+ // 5. Fill in the FPDT record according to different Performance Identifier.
+ //
+ switch (PerfId) {
+ case MODULE_START_ID:
+ case MODULE_END_ID:
+ StringPtr = PEIM_TOK;
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
+ FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
+ FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
+ }
+ break;
+
+ case MODULE_LOADIMAGE_START_ID:
+ case MODULE_LOADIMAGE_END_ID:
+ StringPtr = LOAD_IMAGE_TOK;
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+ FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
+ if (PerfId == MODULE_LOADIMAGE_START_ID) {
+ PeiPerformanceLogHeader->LoadImageCount++;
+ }
+ FpdtRecordPtr.GuidQwordEvent->Qword = PeiPerformanceLogHeader->LoadImageCount;
+ CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
+ }
+ break;
+
+ case PERF_EVENTSIGNAL_START_ID:
+ case PERF_EVENTSIGNAL_END_ID:
+ case PERF_CALLBACK_START_ID:
+ case PERF_CALLBACK_END_ID:
+ if (String == NULL || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ StringPtr = String;
+ if (AsciiStrLen (String) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, ModuleGuid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+ }
+ break;
+
+ case PERF_EVENT_ID:
+ case PERF_FUNCTION_START_ID:
+ case PERF_FUNCTION_END_ID:
+ case PERF_INMODULE_START_ID:
+ case PERF_INMODULE_END_ID:
+ case PERF_CROSSMODULE_START_ID:
+ case PERF_CROSSMODULE_END_ID:
+ if (String != NULL && AsciiStrLen (String) != 0) {
+ StringPtr = String;
+ } else {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ break;
+
+ default:
+ if (Attribute != PerfEntry) {
+ if (String != NULL && AsciiStrLen (String) != 0) {
+ StringPtr = String;
+ } else {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ //
+ // 5.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
+ //
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ if (Guid != NULL) {
+ //
+ // Cache the event guid in string event record.
+ //
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (EFI_GUID));
+ } else {
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
+ }
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+
+ //
+ // 6. Update the length of the used buffer after fill in the record.
+ //
+ PeiPerformanceLogHeader->SizeOfAllEntries += FpdtRecordPtr.RecordHeader->Length;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ If TimeStamp is one, then this function reads 0 as the start time.
+
+ If TimeStamp is other value, then TimeStamp is added to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfStartEntry);
+
+}
+
+/**
+
+ Creates a record for the end of a performance measurement.
+
+ If the TimeStamp is not zero or one, then TimeStamp is added to the record as the end time.
+ If the TimeStamp is zero, then this function reads the current time stamp and adds that time stamp value to the record as the end time.
+ If the TimeStamp is one, then this function reads 0 as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfEndEntry);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ !!!NOT Support yet!!!
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance of entry entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ If TimeStamp is one, then this function reads 0 as the start time.
+
+ If TimeStamp is other value, then TimeStamp is added to the record as the start time.
+
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+
+ Creates a record for the end of a performance measurement.
+
+ If the TimeStamp is not zero or one, then TimeStamp is added to the record as the end time.
+ If the TimeStamp is zero, then this function reads the current time stamp and adds that time stamp value to the record as the end time.
+ If the TimeStamp is one, then this function reads 0 as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ NOT Support yet.
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance of entry entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS)InsertFpdtRecord (CallerIdentifier, Guid, String, 0, Address, (UINT16)Identifier, PerfEntry);
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
new file mode 100644
index 000000000..80d4c50f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
@@ -0,0 +1,56 @@
+## @file
+# Performance library instance used in PEI phase.
+#
+# This library provides the performance measurement interfaces in PEI phase, it creates
+# and consumes GUIDed HOB for performance logging. The GUIDed HOB is passed to DXE phase
+# so that it can be taken over by DxeCorePerformanceLib.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiPerformanceLib
+ MODULE_UNI_FILE = PeiPerformanceLib.uni
+ FILE_GUID = F72DE735-B24F-4ef6-897F-70A85D01A047
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|PEIM PEI_CORE SEC
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiPerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ TimerLib
+ BaseLib
+ HobLib
+ DebugLib
+
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## CONSUMES ## HOB
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries16 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni
new file mode 100644
index 000000000..0ca2db724
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Performance library instance used in PEI phase.
+//
+// This library provides the performance measurement interfaces in PEI phase, it creates
+// and consumes GUIDed HOB for performance logging. The GUIDed HOB is passed to DXE phase
+// so that it can be taken over by DxeCorePerformanceLib.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Performance library instance used in the PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides the performance measurement interfaces in the PEI phase, it creates and consumes GUIDed HOB for performance logging. The GUIDed HOB is passed to the DXE phase so that it can be taken over by DxeCorePerformanceLib."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
new file mode 100644
index 000000000..73ce2ee09
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
@@ -0,0 +1,54 @@
+## @file
+# Instance of Report Status Code Library for PEI Phase.
+#
+# Instance of Report Status Code Library for PEI Phase. It first tries to report status
+# code via PEI Status Code Service. If the service is not available, it then tries calling
+# OEM Hook Status Code Library.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiReportStatusCodeLib
+ MODULE_UNI_FILE = PeiReportStatusCodeLib.uni
+ FILE_GUID = 8c690838-7a22-45c4-aa58-a33e3e515cd4
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|SEC PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ PeiServicesTablePointerLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ OemHookStatusCodeLib
+
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni
new file mode 100644
index 000000000..8402057a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Instance of Report Status Code Library for PEI Phase.
+//
+// Instance of Report Status Code Library for PEI Phase. It first tries to report status
+// code via PEI Status Code Service. If the service is not available, it then tries calling
+// OEM Hook Status Code Library.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Report Status Code Library for the PEI Phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Instance of Report Status Code Library for the PEI Phase. It first tries to report status code via PEI Status Code Service. If the service is not available, it then tries calling OEM Hook Status Code Library."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 000000000..5ea2760dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,554 @@
+/** @file
+ Instance of Report Status Code Library for PEI Phase.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/OemHookStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Define the maximum extended data size that is supported in the PEI phase
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+/**
+ Internal worker function that reports a status code through the PEI Status Code Service or
+ OEM Hook Status Code Library.
+
+ This function first tries to report status code via PEI Status Code Service. If the service
+ is not available, it then tries calling OEM Hook Status Code Library.
+
+ @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 type is not supported.
+ @retval Others Failed to report status code.
+
+**/
+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
+ )
+{
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+
+ 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)) {
+ PeiServices = GetPeiServicesTablePointer ();
+ Status = (*PeiServices)->ReportStatusCode (
+ PeiServices,
+ Type,
+ Value,
+ Instance,
+ (EFI_GUID *)CallerId,
+ Data
+ );
+ if (Status == EFI_NOT_AVAILABLE_YET) {
+ Status = OemHookStatusCodeInitialize ();
+ if (!EFI_ERROR (Status)) {
+ return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *) CallerId, Data);
+ }
+ }
+ return Status;
+ }
+
+ 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);
+ //
+ // EFI_UNSUPPORTED is returned for device path is not supported in PEI phase.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ 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 gEfiStatusCodeSpecificDatauid 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_CODE_DATA *StatusCodeData;
+ UINT64 Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ //
+ // If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ //
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ //
+ // If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+ //
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ 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;
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16) ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ return InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+}
+
+
+/**
+ 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/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c
new file mode 100644
index 000000000..6c8c770ca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.c
@@ -0,0 +1,103 @@
+/** @file
+ PEI Reset System Library instance that calls the ResetSystem2() PEI Service.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ )
+{
+ PeiServicesResetSystem2 (EfiResetCold, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ )
+{
+ PeiServicesResetSystem2 (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ )
+{
+ PeiServicesResetSystem2 (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a systemwide reset. The exact type of the reset is
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+ the platform must pick a supported reset type to perform.The platform may
+ optionally log the parameters from any non-normal reset that occurs.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData The data buffer starts with a Null-terminated string,
+ followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+ IN UINTN DataSize,
+ IN VOID *ResetData
+ )
+{
+ PeiServicesResetSystem2 (EfiResetPlatformSpecific, EFI_SUCCESS, DataSize, ResetData);
+}
+
+/**
+ The ResetSystem function resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ PeiServicesResetSystem2 (ResetType, ResetStatus, DataSize, ResetData);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf
new file mode 100644
index 000000000..173301091
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI Reset System Library instance that calls the ResetSystem2() PEI Service.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiResetSystemLib
+ MODULE_UNI_FILE = PeiResetSystemLib.uni
+ FILE_GUID = 3198FF36-FC72-42E7-B98A-A080D823AFBF
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ResetSystemLib|PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PeiResetSystemLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeiServicesLib
+
+[Depex]
+ gEfiPeiReset2PpiGuid
diff --git a/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.uni b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.uni
new file mode 100644
index 000000000..7efdf0cba
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// PEI Reset System Library instance that calls the ResetSystem2() PEI Service.
+//
+// PEI Reset System Library instance that calls the ResetSystem2() PEI Service.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PEI Reset System Library instance that calls the ResetSystem2() PEI Service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "PEI Reset System Library instance that calls the ResetSystem2() PEI Service."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
new file mode 100644
index 000000000..df7756781
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
@@ -0,0 +1,1776 @@
+/** @file
+ Interpret and execute the S3 data in S3 boot script.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "InternalBootScriptLib.h"
+
+/**
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+ executed or an error is encountered in doing the operation.
+
+ The SmbusExecute() function provides a standard way to execute an operation as defined in the System
+ Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
+ slave devices accept this transaction or that this function returns with error.
+
+ @param SmbusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
+ and PEC.
+ @param Operation Signifies which particular SMBus hardware protocol instance that
+ it will use to execute the SMBus transactions. This SMBus
+ hardware protocol is defined by the SMBus Specification and is
+ not related to EFI.
+ @param Length Signifies the number of bytes that this operation will do. The
+ maximum number of bytes can be revision specific and operation
+ specific. This field will contain the actual number of bytes that
+ are executed for this operation. Not all operations require this
+ argument.
+ @param Buffer Contains the value of data to execute to the SMBus slave device.
+ Not all operations require this argument. The length of this
+ buffer is identified by Length.
+
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll
+ exit criteria.
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
+ determined by the SMBus host controller device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was
+ reflected in the Host Status Register bit. Device errors are a
+ result of a transaction collision, illegal command field,
+ unclaimed cycle (host initiated), or bus errors (collisions).
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+ and EfiSmbusQuickWrite. Length is outside the range of valid
+ values.
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+InternalSmbusExecute (
+ IN UINTN SmbusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN OUT UINTN *Length,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN];
+
+ switch (Operation) {
+ case EfiSmbusQuickRead:
+ DEBUG ((EFI_D_INFO, "EfiSmbusQuickRead - 0x%08x\n", SmbusAddress));
+ SmBusQuickRead (SmbusAddress, &Status);
+ break;
+ case EfiSmbusQuickWrite:
+ DEBUG ((EFI_D_INFO, "EfiSmbusQuickWrite - 0x%08x\n", SmbusAddress));
+ SmBusQuickWrite (SmbusAddress, &Status);
+ break;
+ case EfiSmbusReceiveByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReceiveByte - 0x%08x\n", SmbusAddress));
+ SmBusReceiveByte (SmbusAddress, &Status);
+ break;
+ case EfiSmbusSendByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusSendByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer));
+ SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadByte - 0x%08x\n", SmbusAddress));
+ SmBusReadDataByte (SmbusAddress, &Status);
+ break;
+ case EfiSmbusWriteByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer));
+ SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadWord:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadWord - 0x%08x\n", SmbusAddress));
+ SmBusReadDataWord (SmbusAddress, &Status);
+ break;
+ case EfiSmbusWriteWord:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteWord - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer));
+ SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status);
+ break;
+ case EfiSmbusProcessCall:
+ DEBUG ((EFI_D_INFO, "EfiSmbusProcessCall - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer));
+ SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadBlock:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadBlock - 0x%08x\n", SmbusAddress));
+ SmBusReadBlock (SmbusAddress, WorkBuffer, &Status);
+ break;
+ case EfiSmbusWriteBlock:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteBlock - 0x%08x\n", SmbusAddress));
+ SmBusWriteBlock ((SmbusAddress + SMBUS_LIB_ADDRESS (0, 0, (*Length), FALSE)), Buffer, &Status);
+ break;
+ case EfiSmbusBWBRProcessCall:
+ DEBUG ((EFI_D_INFO, "EfiSmbusBWBRProcessCall - 0x%08x\n", SmbusAddress));
+ SmBusBlockProcessCall ((SmbusAddress + SMBUS_LIB_ADDRESS (0, 0, (*Length), FALSE)), Buffer, WorkBuffer, &Status);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Translates boot script width and address stride to MDE library interface.
+
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param AddressStride Instride for stepping input buffer.
+ @param BufferStride Outstride for stepping output buffer.
+
+ @retval EFI_SUCCESS Successful translation.
+ @retval EFI_INVALID_PARAMETER Width or Address is invalid.
+**/
+EFI_STATUS
+BuildLoopData (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ OUT UINTN *AddressStride,
+ OUT UINTN *BufferStride
+ )
+{
+ UINTN AlignMask;
+
+ if (Width >= S3BootScriptWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *AddressStride = (UINT32)(1 << (Width & 0x03));
+ *BufferStride = *AddressStride;
+
+ AlignMask = *AddressStride - 1;
+ if ((Address & AlignMask) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width >= S3BootScriptWidthFifoUint8 && Width <= S3BootScriptWidthFifoUint64) {
+ *AddressStride = 0;
+ }
+
+ if (Width >= S3BootScriptWidthFillUint8 && Width <= S3BootScriptWidthFillUint64) {
+ *BufferStride = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform IO read operation
+
+ @param[in] Width Width of the operation.
+ @param[in] Address Address of the operation.
+ @param[in] Count Count of the number of accesses to perform.
+ @param[out] Buffer Pointer to the buffer to read from I/O space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+ScriptIoRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+
+ Out.Buf = (UINT8 *) Buffer;
+
+ if (Address > MAX_IO_ADDRESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform IO write operation
+
+ @param[in] Width Width of the operation.
+ @param[in] Address Address of the operation.
+ @param[in] Count Count of the number of accesses to perform.
+ @param[in] Buffer Pointer to the buffer to write to I/O space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+ScriptIoWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ UINT64 OriginalAddress;
+ PTR In;
+ PTR OriginalIn;
+
+ In.Buf = (UINT8 *) Buffer;
+
+ if (Address > MAX_IO_ADDRESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalAddress = Address;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8));
+ IoWrite8 ((UINTN) Address, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8));
+ IoWrite8 ((UINTN) OriginalAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint8));
+ IoWrite8 ((UINTN) Address, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16));
+ IoWrite16 ((UINTN) Address, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16));
+ IoWrite16 ((UINTN) OriginalAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint16));
+ IoWrite16 ((UINTN) Address, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32));
+ IoWrite32 ((UINTN) Address, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32));
+ IoWrite32 ((UINTN) OriginalAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint32));
+ IoWrite32 ((UINTN) Address, *OriginalIn.Uint32);
+ break;
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64));
+ IoWrite64 ((UINTN) Address, *In.Uint64);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)OriginalAddress, *In.Uint64));
+ IoWrite64 ((UINTN) OriginalAddress, *In.Uint64);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *OriginalIn.Uint64));
+ IoWrite64 ((UINTN) Address, *OriginalIn.Uint64);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_WRITE OP code.
+
+ @param Script Pointer to the node which is to be interpreted.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+BootScriptExecuteIoWrite (
+ IN UINT8 *Script
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ VOID *Buffer;
+ EFI_BOOT_SCRIPT_IO_WRITE IoWrite;
+
+ CopyMem ((VOID*)&IoWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH) IoWrite.Width;
+ Address = IoWrite.Address;
+ Count = IoWrite.Count;
+ Buffer = Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)Address, Count, (UINTN)Width));
+ return ScriptIoWrite(Width, Address, Count, Buffer);
+}
+/**
+ Perform memory read operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer read from memory.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ 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 EFI System.
+
+**/
+EFI_STATUS
+ScriptMemoryRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+
+ Out.Buf = Buffer;
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Perform memory write operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer write to memory.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ 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 EFI System.
+
+**/
+EFI_STATUS
+ScriptMemoryWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINT64 OriginalAddress;
+ UINTN BufferStride;
+ PTR In;
+ PTR OriginalIn;
+
+ In.Buf = Buffer;
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalAddress = Address;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8));
+ MmioWrite8 ((UINTN) Address, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8));
+ MmioWrite8 ((UINTN) OriginalAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint8));
+ MmioWrite8 ((UINTN) Address, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16));
+ MmioWrite16 ((UINTN) Address, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16));
+ MmioWrite16 ((UINTN) OriginalAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint16));
+ MmioWrite16 ((UINTN) Address, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32));
+ MmioWrite32 ((UINTN) Address, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32));
+ MmioWrite32 ((UINTN) OriginalAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint32));
+ MmioWrite32 ((UINTN) Address, *OriginalIn.Uint32);
+ break;
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64));
+ MmioWrite64 ((UINTN) Address, *In.Uint64);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)OriginalAddress, *In.Uint64));
+ MmioWrite64 ((UINTN) OriginalAddress, *In.Uint64);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *OriginalIn.Uint64));
+ MmioWrite64 ((UINTN) Address, *OriginalIn.Uint64);
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_WRITE OP code.
+
+ @param[in] Script Pointer to the node which is to be interpreted.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ 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 EFI System.
+
+**/
+EFI_STATUS
+BootScriptExecuteMemoryWrite (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_MEM_WRITE MemWrite;
+
+ CopyMem((VOID*)&MemWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)MemWrite.Width;
+ Address = MemWrite.Address;
+ Count = MemWrite.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_MEM_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)Address, Count, (UINTN)Width));
+ return ScriptMemoryWrite (Width,Address, Count, Buffer);
+
+}
+/**
+ Performance PCI configuration 2 read operation
+
+ @param Width Width of the operation.
+ @param Segment Pci segment number
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer read from PCI config space
+
+ @retval EFI_SUCCESS The read succeed.
+ @retval EFI_INVALID_PARAMETER if Width is not defined
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+EFI_STATUS
+ScriptPciCfg2Read (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+ UINT64 PciAddress;
+
+ Out.Buf = (UINT8 *) Buffer;
+
+ PciAddress = PCI_ADDRESS_ENCODE (Segment, Address);
+
+ Status = BuildLoopData (Width, PciAddress, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, PciAddress += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%016lx\n", PciAddress));
+ *Out.Uint8 = PciSegmentRead8 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%016lx\n", PciAddress));
+ *Out.Uint8 = PciSegmentRead8 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%016lx\n", PciAddress));
+ *Out.Uint8 = PciSegmentRead8 (PciAddress);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%016lx\n", PciAddress));
+ *Out.Uint16 = PciSegmentRead16 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%016lx\n", PciAddress));
+ *Out.Uint16 = PciSegmentRead16 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%016lx\n", PciAddress));
+ *Out.Uint16 = PciSegmentRead16 (PciAddress);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%016lx\n", PciAddress));
+ *Out.Uint32 = PciSegmentRead32 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%016lx\n", PciAddress));
+ *Out.Uint32 = PciSegmentRead32 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%016lx\n", PciAddress));
+ *Out.Uint32 = PciSegmentRead32 (PciAddress);
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Performance PCI configuration 2 write operation
+
+ @param Width Width of the operation.
+ @param Segment Pci segment number
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer write to PCI config space
+
+ @retval EFI_SUCCESS The write succeed.
+ @retval EFI_INVALID_PARAMETER if Width is not defined
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+EFI_STATUS
+ScriptPciCfg2Write (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ UINT64 OriginalPciAddress;
+ PTR In;
+ PTR OriginalIn;
+ UINT64 PciAddress;
+
+ In.Buf = (UINT8 *) Buffer;
+
+ PciAddress = PCI_ADDRESS_ENCODE (Segment, Address);
+
+ Status = BuildLoopData (Width, PciAddress, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalPciAddress = PciAddress;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, PciAddress += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%016lx (0x%02x)\n", PciAddress, (UINTN)*In.Uint8));
+ PciSegmentWrite8 (PciAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%016lx (0x%02x)\n", OriginalPciAddress, (UINTN)*In.Uint8));
+ PciSegmentWrite8 (OriginalPciAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%016lx (0x%02x)\n", PciAddress, (UINTN)*OriginalIn.Uint8));
+ PciSegmentWrite8 (PciAddress, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%016lx (0x%04x)\n", PciAddress, (UINTN)*In.Uint16));
+ PciSegmentWrite16 (PciAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%016lx (0x%04x)\n", OriginalPciAddress, (UINTN)*In.Uint16));
+ PciSegmentWrite16 (OriginalPciAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%016lx (0x%04x)\n", PciAddress, (UINTN)*OriginalIn.Uint16));
+ PciSegmentWrite16 (PciAddress, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%016lx (0x%08x)\n", PciAddress, (UINTN)*In.Uint32));
+ PciSegmentWrite32 (PciAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%016lx (0x%08x)\n", OriginalPciAddress, (UINTN)*In.Uint32));
+ PciSegmentWrite32 (OriginalPciAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%016lx (0x%08x)\n", (UINTN)PciAddress, (UINTN)*OriginalIn.Uint32));
+ PciSegmentWrite32 (PciAddress, *OriginalIn.Uint32);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Performance PCI configuration read operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer to read from PCI config space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+ScriptPciCfgRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ return ScriptPciCfg2Read (Width, 0, Address, Count, Buffer);
+}
+/**
+ Performance PCI configuration write operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer to write to PCI config space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+EFIAPI
+ScriptPciCfgWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ return ScriptPciCfg2Write (Width, 0, Address, Count, Buffer);
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecutePciCfgWrite (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE PciCfgWrite;
+
+ CopyMem ((VOID*)&PciCfgWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
+
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)PciCfgWrite.Width;
+ Address = PciCfgWrite.Address;
+ Count = PciCfgWrite.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgWrite - 0x%016lx, 0x%08x, 0x%08x\n", PCI_ADDRESS_ENCODE (0, Address), Count, (UINTN)Width));
+ return ScriptPciCfgWrite (Width, Address, Count, Buffer);
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteIoReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_IO_READ_WRITE IoReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&IoReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)IoReadWrite.Address, AndMask, OrMask));
+
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width,
+ IoReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptIoWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width,
+ IoReadWrite.Address,
+ 1,
+ &Data
+ );
+ }
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteMemoryReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_MEM_READ_WRITE MemReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&MemReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)MemReadWrite.Address, AndMask, OrMask));
+
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width,
+ MemReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptMemoryWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width,
+ MemReadWrite.Address,
+ 1,
+ &Data
+ );
+ }
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CFG_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecutePciCfgReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE PciCfgReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&PciCfgReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgReadWrite - 0x%016lx, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (0, PciCfgReadWrite.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width,
+ PciCfgReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = (Data & AndMask) | OrMask;
+
+ Status = ScriptPciCfgWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width,
+ PciCfgReadWrite.Address,
+ 1,
+ &Data
+ );
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_SMBUS_EXECUTE OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_UNSUPPORTED Cannot locate smbus ppi or occur error of script execution
+ @retval Others Result of script execution
+**/
+EFI_STATUS
+BootScriptExecuteSmbusExecute (
+ IN UINT8 *Script
+ )
+{
+ UINTN SmBusAddress;
+ UINTN DataSize;
+ EFI_BOOT_SCRIPT_SMBUS_EXECUTE SmbusExecuteEntry;
+
+ CopyMem ((VOID*)&SmbusExecuteEntry, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_SMBUS_EXECUTE ));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteSmbusExecute - 0x%08x, 0x%08x\n", (UINTN)SmbusExecuteEntry.SmBusAddress, (UINTN)SmbusExecuteEntry.Operation));
+
+ SmBusAddress = (UINTN)SmbusExecuteEntry.SmBusAddress;
+ DataSize = (UINTN) SmbusExecuteEntry.DataSize;
+ return InternalSmbusExecute (
+ SmBusAddress,
+ (EFI_SMBUS_OPERATION) SmbusExecuteEntry.Operation,
+ &DataSize,
+ Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)
+ );
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_STALL OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteStall (
+ IN UINT8 *Script
+ )
+{
+ EFI_BOOT_SCRIPT_STALL Stall;
+
+ CopyMem ((VOID*)&Stall, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_STALL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteStall - 0x%08x\n", (UINTN)Stall.Duration));
+
+ MicroSecondDelay ((UINTN) Stall.Duration);
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_DISPATCH OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteDispatch (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;
+
+ CopyMem ((VOID*)&ScriptDispatch, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH));
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch.EntryPoint);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch - 0x%08x\n", (UINTN)ScriptDispatch.EntryPoint));
+
+ Status = EntryFunc (NULL, NULL);
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_DISPATCH_2 OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteDispatch2 (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;
+
+ CopyMem ((VOID*)&ScriptDispatch2, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch2 - 0x%08x(0x%08x)\n", (UINTN)ScriptDispatch2.EntryPoint, (UINTN)ScriptDispatch2.Context));
+
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch2.EntryPoint);
+
+ Status = EntryFunc (NULL, (VOID *) (UINTN) ScriptDispatch2.Context);
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_POLL OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_DEVICE_ERROR Data polled from memory does not equal to
+ the epecting data within the Loop Times.
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteMemPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_MEM_POLL MemPoll;
+
+ CopyMem ((VOID*)&MemPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemPoll - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)MemPoll.Address, AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width,
+ MemPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < MemPoll.LoopTimes; LoopTimes++) {
+ MicroSecondDelay ((UINTN)MemPoll.Duration);
+
+ Data = 0;
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width,
+ MemPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < MemPoll.LoopTimes) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+/**
+ Execute the boot script to interpret the Store arbitrary information.
+ This opcode is a no-op on dispatch and is only used for debugging script issues.
+
+ @param Script The pointer of node in boot script table
+
+**/
+VOID
+BootScriptExecuteInformation (
+ IN UINT8 *Script
+ )
+
+{
+ UINT32 Index;
+ EFI_BOOT_SCRIPT_INFORMATION Information;
+ UINT8 *InformationData;
+
+ CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_INFORMATION));
+
+ InformationData = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION);
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteInformation - 0x%08x\n", (UINTN) InformationData));
+
+ DEBUG ((EFI_D_INFO, "BootScriptInformation: "));
+ for (Index = 0; Index < Information.InformationLength; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", InformationData[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ Execute the boot script to interpret the Label information.
+
+ @param Script The pointer of node in boot script table
+
+**/
+VOID
+BootScriptExecuteLabel (
+ IN UINT8 *Script
+ )
+
+{
+ UINT32 Index;
+ EFI_BOOT_SCRIPT_INFORMATION Information;
+ UINT8 *InformationData;
+
+ CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_INFORMATION));
+
+ InformationData = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION);
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteLabel - 0x%08x\n", (UINTN) InformationData));
+
+ DEBUG ((EFI_D_INFO, "BootScriptLabel: "));
+ for (Index = 0; Index < Information.InformationLength; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", InformationData[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ calculate the mask value for 'and' and 'or' operation
+ @param ScriptHeader The pointer of header of node in boot script table
+ @param AndMask The Mask value for 'and' operation
+ @param OrMask The Mask value for 'or' operation
+ @param Script Pointer to the entry.
+
+**/
+VOID
+CheckAndOrMask (
+ IN EFI_BOOT_SCRIPT_COMMON_HEADER *ScriptHeader,
+ OUT UINT64 *AndMask,
+ OUT UINT64 *OrMask,
+ IN UINT8 *Script
+ )
+{
+ UINT8 *DataPtr;
+ UINTN Size;
+
+ switch (ScriptHeader->OpCode) {
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE);
+ break;
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_MEM_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_IO_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL);
+ break;
+
+ default:
+ return;
+ }
+
+ DataPtr = Script + Size;
+
+ switch (ScriptHeader->Width) {
+ case S3BootScriptWidthUint8:
+ *AndMask = (UINT64) (*(UINT8*) (DataPtr + 1));
+ *OrMask = (UINT64) (*DataPtr);
+ break;
+
+ case S3BootScriptWidthUint16:
+ *AndMask = (UINT64) (*(UINT16 *) (DataPtr + 2));
+ *OrMask = (UINT64) (*(UINT16 *) DataPtr);
+ break;
+
+ case S3BootScriptWidthUint32:
+ *AndMask = (UINT64) (*(UINT32 *) (DataPtr + 4));
+ *OrMask = (UINT64) (*(UINT32 *) DataPtr);
+ break;
+
+ case S3BootScriptWidthUint64:
+ *AndMask = (UINT64) (*(UINT64 *) (DataPtr + 8));
+ *OrMask = (UINT64) (*(UINT64 *) DataPtr);
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_POLL OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_DEVICE_ERROR Data polled from memory does not equal to
+ the epecting data within the Loop Times.
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteIoPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_BOOT_SCRIPT_IO_POLL IoPoll;
+
+ CopyMem ((VOID*)&IoPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoPoll - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)IoPoll.Address, AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width,
+ IoPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ for (LoopTimes = 0; LoopTimes < IoPoll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+ Data = 0;
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width,
+ IoPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < IoPoll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE OP code.
+
+ @param Script The pointer of S3 boot script
+
+ @retval EFI_SUCCESS The operation was executed successfully
+
+**/
+EFI_STATUS
+BootScriptExecutePciCfg2Write (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE PciCfg2Write;
+
+ CopyMem ((VOID*)&PciCfg2Write, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
+
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)PciCfg2Write.Width;
+ Segment = PciCfg2Write.Segment;
+ Address = PciCfg2Write.Address;
+ Count = PciCfg2Write.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2Write - 0x%016lx, 0x%08x, 0x%08x\n", PCI_ADDRESS_ENCODE (Segment, Address), Count, (UINTN)Width));
+ return ScriptPciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE OP code.
+
+ @param Script The pointer of S3 boot script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+
+**/
+EFI_STATUS
+BootScriptExecutePciCfg2ReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ UINT64 Data;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE PciCfg2ReadWrite;
+
+ Data = 0;
+
+ CopyMem ((VOID*)&PciCfg2ReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2ReadWrite - 0x%016lx, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (PciCfg2ReadWrite.Segment, PciCfg2ReadWrite.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width,
+ PciCfg2ReadWrite.Segment,
+ PciCfg2ReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptPciCfg2Write (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width,
+ PciCfg2ReadWrite.Segment,
+ PciCfg2ReadWrite.Address,
+ 1,
+ &Data
+ );
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG_POLL OP code.
+
+ @param Script The pointer of S3 boot script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to
+ epecting data within the Loop Times.
+**/
+EFI_STATUS
+BootScriptPciCfgPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_POLL PciCfgPoll;
+ CopyMem ((VOID*)&PciCfgPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptPciCfgPoll - 0x%016lx, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (0, PciCfgPoll.Address), AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width,
+ PciCfgPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < PciCfgPoll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+ Data = 0;
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width,
+ PciCfgPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&
+ (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < PciCfgPoll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL OP code.
+
+ @param Script The pointer of S3 Boot Script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to
+ epecting data within the Loop Times.
+
+**/
+EFI_STATUS
+BootScriptPciCfg2Poll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL PciCfg2Poll;
+
+ Data = 0;
+ CopyMem ((VOID*)&PciCfg2Poll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptPciCfg2Poll - 0x%016lx, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (PciCfg2Poll.Segment, PciCfg2Poll.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width,
+ PciCfg2Poll.Segment,
+ PciCfg2Poll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < PciCfg2Poll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+
+ Data = 0;
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width,
+ PciCfg2Poll.Segment,
+ PciCfg2Poll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < PciCfg2Poll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+}
+
+/**
+ Executes the S3 boot script table.
+
+ @retval RETURN_SUCCESS The boot script table was executed successfully.
+ @retval RETURN_UNSUPPORTED Invalid script table or opcode.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptExecute (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8* Script;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ UINT64 AndMask;
+ UINT64 OrMask;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;
+ Script = mS3BootScriptTablePtr->TableBase;
+ if (Script != 0) {
+ CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "S3BootScriptExecute:\n"));
+ if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "TableHeader - 0x%08x\n", Script));
+
+ StartAddress = (UINTN) Script;
+ TableLength = TableHeader.TableLength;
+ Script = Script + TableHeader.Length;
+ Status = EFI_SUCCESS;
+ AndMask = 0;
+ OrMask = 0;
+
+ DEBUG ((EFI_D_INFO, "TableHeader.Version - 0x%04x\n", (UINTN)TableHeader.Version));
+ DEBUG ((EFI_D_INFO, "TableHeader.TableLength - 0x%08x\n", (UINTN)TableLength));
+
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+ DEBUG ((EFI_D_INFO, "ExecuteBootScript - %08x\n", (UINTN)Script));
+
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ switch (ScriptHeader.OpCode) {
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE\n"));
+ Status = BootScriptExecuteMemoryWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteMemoryReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_WRITE_OPCODE\n"));
+ Status = BootScriptExecuteIoWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE\n"));
+ Status = BootScriptExecutePciCfgWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecutePciCfgReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE\n"));
+ Status = BootScriptExecutePciCfg2Write (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecutePciCfg2ReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_OPCODE\n"));
+ Status = BootScriptExecuteDispatch (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE\n"));
+ Status = BootScriptExecuteDispatch2 (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_INFORMATION_OPCODE\n"));
+ BootScriptExecuteInformation (Script);
+ break;
+
+ case S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE:
+ DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE\n"));
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteIoReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE\n"));
+ Status = BootScriptExecuteSmbusExecute (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_STALL_OPCODE\n"));
+ Status = BootScriptExecuteStall (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteMemPoll (Script, AndMask, OrMask);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteIoPoll (Script, AndMask, OrMask);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptPciCfgPoll (Script, AndMask, OrMask);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptPciCfg2Poll (Script, AndMask, OrMask);
+ break;
+
+ case S3_BOOT_SCRIPT_LIB_LABEL_OPCODE:
+ //
+ // For label
+ //
+ DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_LABEL_OPCODE\n"));
+ BootScriptExecuteLabel (Script);
+ break;
+ default:
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", EFI_UNSUPPORTED));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status));
+ return Status;
+ }
+
+ Script = Script + ScriptHeader.Length;
+ }
+
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status));
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h
new file mode 100644
index 000000000..85bc8af39
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h
@@ -0,0 +1,181 @@
+/** @file
+ This file declares the internal Framework Boot Script format used by
+ the PI implementation of Script Saver and Executor.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_SCRIPT_INTERNAL_FORMAT_H_
+#define _BOOT_SCRIPT_INTERNAL_FORMAT_H_
+
+#pragma pack(1)
+
+//
+// Boot Script Opcode Header Structure Definitions
+//
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+} EFI_BOOT_SCRIPT_GENERIC_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT16 Version;
+ UINT32 TableLength;
+ UINT16 Reserved[2];
+} EFI_BOOT_SCRIPT_TABLE_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+} EFI_BOOT_SCRIPT_COMMON_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_IO_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_IO_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_MEM_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_MEM_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+ UINT16 Segment;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT16 Segment;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT64 SmBusAddress;
+ UINT32 Operation;
+ UINT32 DataSize;
+} EFI_BOOT_SCRIPT_SMBUS_EXECUTE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT64 Duration;
+} EFI_BOOT_SCRIPT_STALL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+} EFI_BOOT_SCRIPT_DISPATCH;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PHYSICAL_ADDRESS Context;
+} EFI_BOOT_SCRIPT_DISPATCH_2;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Duration;
+ UINT64 LoopTimes;
+} EFI_BOOT_SCRIPT_MEM_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 InformationLength;
+// UINT8 InformationData[InformationLength];
+} EFI_BOOT_SCRIPT_INFORMATION;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_IO_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT16 Segment;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+} EFI_BOOT_SCRIPT_TERMINATE;
+
+
+#pragma pack()
+
+#define BOOT_SCRIPT_NODE_MAX_LENGTH 1024
+
+#define BOOT_SCRIPT_TABLE_VERSION 0x0001
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
new file mode 100644
index 000000000..9315fc9f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
@@ -0,0 +1,2413 @@
+/** @file
+ Save the S3 data to S3 boot script.
+
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "InternalBootScriptLib.h"
+
+/**
+
+ Data structure usage:
+
+ +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr
+ | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock)
+ | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr
+ | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm)
+ | TableMemoryPageNumber |--|-|----
+ | AtRuntime | | | |
+ | InSmm | | | |
+ | BootTimeScriptLength |--|-|---|---
+ | SmmLocked | | | | |
+ | BackFromS3 | | | | |
+ +------------------------------+ | | | |
+ | | | |
+ +------------------------------+<-- | | |
+ | EFI_BOOT_SCRIPT_TABLE_HEADER | | | |
+ | TableLength |----|-- | |
+ +------------------------------+ | | | |
+ | ...... | | | | |
+ +------------------------------+<---- | | |
+ | EFI_BOOT_SCRIPT_TERMINATE | | | |
+ +------------------------------+<------ | |
+ | |
+ | |
+ mBootScriptDataBootTimeGuid LockBox: | |
+ Used to restore data after back from S3| |
+ to handle potential INSERT boot script | |
+ at runtime. | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | Before SmmReadyToLock | | |
+ | | | |
+ | | | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | After SmmReadyToLock InSmm | | |
+ | | | |
+ +------------------------------+<-------|--|
+ | |
+ | |
+ mBootScriptDataGuid LockBox: (IN_PLACE) | |
+ Used to restore data at S3 resume. | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | Before SmmReadyToLock | | |
+ | | | |
+ | | | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | After SmmReadyToLock InSmm | | |
+ | | | |
+ +------------------------------+<-------|---
+ | Runtime Boot Script | |
+ | After SmmReadyToLock InSmm | |
+ +------------------------------+ |
+ | ...... | |
+ +------------------------------+<--------
+
+
+ mBootScriptTableBaseGuid LockBox: (IN_PLACE)
+ +------------------------------+
+ | mS3BootScriptTablePtr-> |
+ | TableBase |
+ +------------------------------+
+
+
+ mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE)
+ SMM private data with BackFromS3 = TRUE
+ at runtime. S3 will help restore it to
+ tell the Library the system is back from S3.
+ +------------------------------+
+ | SCRIPT_TABLE_PRIVATE_DATA |
+ | TableBase |
+ | TableLength |
+ | TableMemoryPageNumber |
+ | AtRuntime |
+ | InSmm |
+ | BootTimeScriptLength |
+ | SmmLocked |
+ | BackFromS3 = TRUE |
+ +------------------------------+
+
+**/
+
+SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;
+
+//
+// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm.
+//
+SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr;
+
+EFI_GUID mBootScriptDataGuid = {
+ 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }
+};
+
+EFI_GUID mBootScriptDataBootTimeGuid = {
+ 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }
+};
+
+EFI_GUID mBootScriptTableBaseGuid = {
+ 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }
+};
+
+EFI_GUID mBootScriptSmmPrivateDataGuid = {
+ 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 }
+};
+
+EFI_EVENT mEventDxeSmmReadyToLock = NULL;
+VOID *mRegistrationSmmExitBootServices = NULL;
+VOID *mRegistrationSmmLegacyBoot = NULL;
+VOID *mRegistrationSmmReadyToLock = NULL;
+BOOLEAN mS3BootScriptTableAllocated = FALSE;
+BOOLEAN mS3BootScriptTableSmmAllocated = FALSE;
+EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL;
+BOOLEAN mAcpiS3Enable = TRUE;
+
+/**
+ This is an internal function to add a terminate node the entry, recalculate the table
+ length and fill into the table.
+
+ @return the base address of the boot script table.
+ **/
+UINT8*
+S3BootScriptInternalCloseTable (
+ VOID
+ )
+{
+ UINT8 *S3TableBase;
+ EFI_BOOT_SCRIPT_TERMINATE ScriptTerminate;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+ S3TableBase = mS3BootScriptTablePtr->TableBase;
+
+ if (S3TableBase == NULL) {
+ //
+ // the table is not exist
+ //
+ return S3TableBase;
+ }
+ //
+ // Append the termination entry.
+ //
+ ScriptTerminate.OpCode = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE;
+ ScriptTerminate.Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+ //
+ // fill the table length
+ //
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase);
+ ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+
+
+
+ return S3TableBase;
+ //
+ // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to
+ // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE).
+ // Because maybe after SmmReadyToLock, we still need add entries into the table,
+ // and the entry should be added start before this TERMINATE node.
+ //
+}
+
+/**
+ This function save boot script data to LockBox.
+
+**/
+VOID
+SaveBootScriptDataToLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Save whole memory copy into LockBox.
+ // It will be used to restore data at S3 resume.
+ //
+ Status = SaveLockBox (
+ &mBootScriptDataGuid,
+ (VOID *)mS3BootScriptTablePtr->TableBase,
+ EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Just need save TableBase.
+ // Do not update other field because they will NOT be used in S3.
+ //
+ Status = SaveLockBox (
+ &mBootScriptTableBaseGuid,
+ (VOID *)&mS3BootScriptTablePtr->TableBase,
+ sizeof(mS3BootScriptTablePtr->TableBase)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This is the Event call back function to notify the Library the system is entering
+ SmmLocked phase.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+ **/
+VOID
+EFIAPI
+S3BootScriptEventCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ //
+ // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration.
+ // Just return if it is not found.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ NULL,
+ &Interface
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Here we should tell the library that we are entering SmmLocked phase.
+ // and the memory page number occupied by the table should not grow anymore.
+ //
+ if (!mS3BootScriptTablePtr->SmmLocked) {
+ //
+ // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table
+ // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate
+ // node on every add to boot script table.
+ //
+ S3BootScriptInternalCloseTable ();
+ mS3BootScriptTablePtr->SmmLocked = TRUE;
+
+ //
+ // Save BootScript data to lockbox
+ //
+ SaveBootScriptDataToLockBox ();
+ }
+}
+
+/**
+ This is the Event call back function is triggered in SMM to notify the Library
+ the system is entering SmmLocked phase and set InSmm flag.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEventCallback runs successfully
+ **/
+EFI_STATUS
+EFIAPI
+S3BootScriptSmmEventCallBack (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ //
+ // Check if it is already done
+ //
+ if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Last chance to call-out, just make sure SmmLocked is set.
+ //
+ S3BootScriptEventCallBack (NULL, NULL);
+
+ //
+ // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.
+ //
+ if (mS3BootScriptTableSmmPtr->TableBase == NULL) {
+ CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));
+
+ //
+ // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.
+ // InSmm will only be checked if SmmLocked is TRUE.
+ //
+ mS3BootScriptTableSmmPtr->InSmm = TRUE;
+ }
+ //
+ // We should not use ACPI Reserved copy, because it is not safe.
+ //
+ mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is to save boot time boot script data to LockBox.
+
+ Because there may be INSERT boot script at runtime in SMM.
+ The boot time copy will be used to restore data after back from S3.
+ Otherwise the data inserted may cause some boot time boot script data lost
+ if only BootScriptData used.
+
+**/
+VOID
+SaveBootTimeDataToLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first,
+ // and then save the data to BootScriptDataBootTime LockBox.
+ //
+ Status = RestoreLockBox (
+ &mBootScriptDataGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save BootScriptDataBootTime
+ // It will be used to restore data after back from S3.
+ //
+ Status = SaveLockBox (
+ &mBootScriptDataBootTimeGuid,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ mS3BootScriptTablePtr->BootTimeScriptLength
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime.
+ S3 resume will help restore it to tell the Library the system is back from S3.
+
+**/
+VOID
+SaveSmmPriviateDataToLockBoxAtRuntime (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Save boot script SMM private data with BackFromS3 = TRUE.
+ //
+ mS3BootScriptTablePtr->BackFromS3 = TRUE;
+ Status = SaveLockBox (
+ &mBootScriptSmmPrivateDataGuid,
+ (VOID *) mS3BootScriptTablePtr,
+ sizeof (SCRIPT_TABLE_PRIVATE_DATA)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3.
+ //
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;
+}
+
+/**
+ This is the Event call back function is triggered in SMM to notify the Library
+ the system is entering runtime phase.
+
+ @param[in] Protocol Points to the protocol's unique identifier
+ @param[in] Interface Points to the interface instance
+ @param[in] Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully
+ **/
+EFI_STATUS
+EFIAPI
+S3BootScriptSmmAtRuntimeCallBack (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ if (!mS3BootScriptTablePtr->AtRuntime) {
+ mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+ SaveBootTimeDataToLockBox ();
+
+ mS3BootScriptTablePtr->AtRuntime = TRUE;
+ SaveSmmPriviateDataToLockBoxAtRuntime ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Library Constructor.
+ this function just identify it is a smm driver or non-smm driver linked against
+ with the library
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLibInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SCRIPT_TABLE_PRIVATE_DATA *S3TablePtr;
+ SCRIPT_TABLE_PRIVATE_DATA *S3TableSmmPtr;
+ VOID *Registration;
+ EFI_SMM_BASE2_PROTOCOL *SmmBase2;
+ BOOLEAN InSmm;
+ EFI_PHYSICAL_ADDRESS Buffer;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ mAcpiS3Enable = FALSE;
+ DEBUG ((DEBUG_INFO, "%a: Skip S3BootScript because ACPI S3 disabled.\n", gEfiCallerBaseName));
+ return RETURN_SUCCESS;
+ }
+
+ S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);
+ //
+ // The Boot script private data is not be initialized. create it
+ //
+ if (S3TablePtr == 0) {
+ Buffer = SIZE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),
+ &Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ mS3BootScriptTableAllocated = TRUE;
+ S3TablePtr = (VOID *) (UINTN) Buffer;
+
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
+ //
+ // Create event to notify the library system enter the SmmLocked phase.
+ //
+ mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_CALLBACK,
+ S3BootScriptEventCallBack,
+ NULL,
+ &Registration
+ );
+ ASSERT (mEventDxeSmmReadyToLock != NULL);
+ }
+ mS3BootScriptTablePtr = S3TablePtr;
+
+ //
+ // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ Status = SmmBase2->InSmm (SmmBase2, &InSmm);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ if (!InSmm) {
+ return RETURN_SUCCESS;
+ }
+ //
+ // Good, we are in SMM
+ //
+ Status = SmmBase2->GetSmstLocation (SmmBase2, &mBootScriptSmst);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);
+ //
+ // The Boot script private data in SMM is not be initialized. create it
+ //
+ if (S3TableSmmPtr == 0) {
+ Status = mBootScriptSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof(SCRIPT_TABLE_PRIVATE_DATA),
+ (VOID **) &S3TableSmmPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+ mS3BootScriptTableSmmAllocated = TRUE;
+
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
+
+ //
+ // Register SmmExitBootServices and SmmLegacyBoot notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ S3BootScriptSmmAtRuntimeCallBack,
+ &mRegistrationSmmExitBootServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmLegacyBootProtocolGuid,
+ S3BootScriptSmmAtRuntimeCallBack,
+ &mRegistrationSmmLegacyBoot
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ mS3BootScriptTableSmmPtr = S3TableSmmPtr;
+
+ //
+ // Register SmmReadyToLock notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ S3BootScriptSmmEventCallBack,
+ &mRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Library Destructor to free the resources allocated by
+ S3BootScriptLibInitialize() and unregister callbacks.
+
+ NOTICE: The destructor doesn't support unloading as a separate action, and it
+ only supports unloading if the containing driver's entry point function fails.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLibDeinitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (!mAcpiS3Enable) {
+ return RETURN_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "%a() in %a module\n", __FUNCTION__, gEfiCallerBaseName));
+
+ if (mEventDxeSmmReadyToLock != NULL) {
+ //
+ // Close the DxeSmmReadyToLock event.
+ //
+ Status = gBS->CloseEvent (mEventDxeSmmReadyToLock);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mBootScriptSmst != NULL) {
+ if (mRegistrationSmmExitBootServices != NULL) {
+ //
+ // Unregister SmmExitBootServices notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ NULL,
+ &mRegistrationSmmExitBootServices
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mRegistrationSmmLegacyBoot != NULL) {
+ //
+ // Unregister SmmLegacyBoot notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmLegacyBootProtocolGuid,
+ NULL,
+ &mRegistrationSmmLegacyBoot
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mRegistrationSmmReadyToLock != NULL) {
+ //
+ // Unregister SmmReadyToLock notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ NULL,
+ &mRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Free the resources allocated and set PCDs to 0.
+ //
+ if (mS3BootScriptTableAllocated) {
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)));
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+ if ((mBootScriptSmst != NULL) && mS3BootScriptTableSmmAllocated) {
+ Status = mBootScriptSmst->SmmFreePool (mS3BootScriptTableSmmPtr);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ To get the start address from which a new boot time s3 boot script entry will write into.
+ If the table is not exist, the functio will first allocate a buffer for the table
+ If the table buffer is not enough for the new entry, in non-smm mode, the funtion will
+ invoke reallocate to enlarge buffer.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 boot script entry will write into
+ **/
+UINT8*
+S3BootScriptGetBootTimeEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ EFI_PHYSICAL_ADDRESS S3TableBase;
+ EFI_PHYSICAL_ADDRESS NewS3TableBase;
+ UINT8 *NewEntryPtr;
+ UINT32 TableLength;
+ UINT16 PageNumber;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+
+ S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);
+ if (S3TableBase == 0) {
+ //
+ // The table is not exist. This is the first to add entry.
+ // Allocate ACPI script table space under 4G memory.
+ //
+ S3TableBase = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
+ (EFI_PHYSICAL_ADDRESS*)&S3TableBase
+ );
+
+ if (EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+ //
+ // Fill Table Header
+ //
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;
+ ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
+ ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ ScriptTableInfo->Version = BOOT_SCRIPT_TABLE_VERSION;
+ ScriptTableInfo->TableLength = 0; // will be calculate at CloseTable
+ mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;
+ mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ }
+
+ // Here we do not count the reserved memory for runtime script table.
+ PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ if (EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {
+ //
+ // The buffer is too small to hold the table, Reallocate the buffer
+ //
+ NewS3TableBase = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
+ (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase
+ );
+
+ if (EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength);
+ gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber);
+
+ mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase;
+ mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ }
+ //
+ // calculate the the start address for the new entry.
+ //
+ NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength;
+
+ //
+ // update the table lenghth
+ //
+ mS3BootScriptTablePtr->TableLength = TableLength + EntryLength;
+
+ //
+ // In the boot time, we will not append the termination entry to the boot script
+ // table until the callers think there is no boot time data that should be added and
+ // it is caller's responsibility to explicit call the CloseTable.
+ //
+ //
+
+ return NewEntryPtr;
+}
+/**
+ To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into.
+ In this case, it should be ensured that there is enough buffer to hold the entry.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into
+ **/
+UINT8*
+S3BootScriptGetRuntimeEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ UINT8 *NewEntryPtr;
+
+ NewEntryPtr = NULL;
+ //
+ // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node.
+ //
+ if ((mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) {
+ NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength;
+ mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;
+ //
+ // Append a terminate node on every insert
+ //
+ S3BootScriptInternalCloseTable ();
+ }
+ return (UINT8*)NewEntryPtr;
+}
+
+/**
+ This function is to restore boot time boot script data from LockBox.
+
+**/
+VOID
+RestoreBootTimeDataFromLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN LockBoxLength;
+
+ //
+ // Restore boot time boot script data from LockBox.
+ //
+ LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength;
+ Status = RestoreLockBox (
+ &mBootScriptDataBootTimeGuid,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ &LockBoxLength
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update the data to BootScriptData LockBox.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ 0,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ LockBoxLength
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update TableLength.
+ //
+ mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+}
+
+/**
+ To get the start address from which a new s3 boot script entry will write into.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 boot script entry will write into
+ **/
+UINT8*
+S3BootScriptGetEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ UINT8* NewEntryPtr;
+
+ if (!mAcpiS3Enable) {
+ return NULL;
+ }
+
+ if (mS3BootScriptTablePtr->SmmLocked) {
+ //
+ // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script.
+ //
+ if (!mS3BootScriptTablePtr->InSmm) {
+ //
+ // Add DEBUG ERROR, so that we can find it after SmmReadyToLock.
+ // Do not use ASSERT, because we may have test to invoke this interface.
+ //
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n"));
+ return NULL;
+ }
+
+ if (mS3BootScriptTablePtr->BackFromS3) {
+ //
+ // Back from S3, restore boot time boot script data from LockBox
+ // and set BackFromS3 flag back to FALSE.
+ //
+ RestoreBootTimeDataFromLockBox ();
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;
+ }
+
+ NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);
+ } else {
+ NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);
+ }
+ return NewEntryPtr;
+
+}
+
+/**
+ Sync BootScript LockBox data.
+
+ @param Script The address from where the boot script has been added or updated.
+
+**/
+VOID
+SyncBootScript (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ScriptOffset;
+ UINT32 TotalScriptLength;
+
+ if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) {
+ //
+ // If it is not after SmmReadyToLock in SMM,
+ // just return.
+ //
+ return ;
+ }
+
+ ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase);
+
+ TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+
+ //
+ // Update BootScriptData
+ // So in S3 resume, the data can be restored correctly.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ ScriptOffset,
+ (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),
+ TotalScriptLength - ScriptOffset
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Now the length field is updated, need sync to lockbox.
+ // So at S3 resume, the data can be restored correctly.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),
+ &TotalScriptLength,
+ sizeof (TotalScriptLength)
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This is an function to close the S3 boot script table. The function could only be called in
+ BOOT time phase. To comply with the Framework spec definition on
+ EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things:
+ 1. Closes the specified boot script table
+ 2. It allocates a new memory pool to duplicate all the boot scripts in the specified table.
+ Once this function is called, the table maintained by the library will be destroyed
+ after it is copied into the allocated pool.
+ 3. Any attempts to add a script record after calling this function will cause a new table
+ to be created by the library.
+ 4. The base address of the allocated pool will be returned in Address. Note that after
+ using the boot script table, the CALLER is responsible for freeing the pool that is allocated
+ by this function.
+
+ In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is
+ for Framework Spec compatibility.
+
+ If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out
+ how to get the script to run at S3 resume because the boot script maintained by the lib will be
+ destroyed.
+
+ @return the base address of the new copy of the boot script table.
+ @note this function could only called in boot time phase
+
+**/
+UINT8*
+EFIAPI
+S3BootScriptCloseTable (
+ VOID
+ )
+{
+ UINT8 *S3TableBase;
+ UINT32 TableLength;
+ UINT8 *Buffer;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+
+ S3TableBase = mS3BootScriptTablePtr->TableBase;
+ if (S3TableBase == 0) {
+ return 0;
+ }
+ //
+ // Append the termination record the S3 boot script table
+ //
+ S3BootScriptInternalCloseTable();
+ TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ //
+ // Allocate the buffer and copy the boot script to the buffer.
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN)TableLength,
+ (VOID **) &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+ CopyMem (Buffer, S3TableBase, TableLength);
+
+ //
+ // Destroy the table maintained by the library so that the next write operation
+ // will write the record to the first entry of the table.
+ //
+ // Fill the table header.
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase;
+ ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
+ ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ ScriptTableInfo->TableLength = 0; // will be calculate at close the table
+
+ mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ return Buffer;
+}
+/**
+ Save I/O write to boot script
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the I/O operations.
+ @param Count The number of I/O operations to perform.
+ @param Buffer The source buffer from which to write data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_IO_WRITE ScriptIoWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ //
+ // Truncation check
+ //
+ if ((Count > MAX_UINT8) ||
+ (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_IO_WRITE))) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // save script data
+ //
+ ScriptIoWrite.OpCode = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;
+ ScriptIoWrite.Length = Length;
+ ScriptIoWrite.Width = Width;
+ ScriptIoWrite.Address = Address;
+ ScriptIoWrite.Count = (UINT32) Count;
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Adds a record for an I/O modify operation into a S3 boot script table
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the I/O operations.
+ @param Data A pointer to the data to be OR-ed.
+ @param DataMask A pointer to the data mask to be AND-ed with the data read from the register
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;
+ ScriptIoReadWrite.Length = Length;
+ ScriptIoReadWrite.Width = Width;
+ ScriptIoReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a memory write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the memory operations
+ @param Count The number of memory operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ //
+ // Truncation check
+ //
+ if ((Count > MAX_UINT8) ||
+ (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_MEM_WRITE))) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemWrite.OpCode = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;
+ ScriptMemWrite.Length = Length;
+ ScriptMemWrite.Width = Width;
+ ScriptMemWrite.Address = Address;
+ ScriptMemWrite.Count = (UINT32) Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a memory modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the memory operations. Address needs alignment if required
+ @param Data A pointer to the data to be OR-ed.
+ @param DataMask A pointer to the data mask to be AND-ed with the data read from the register.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;
+ ScriptMemReadWrite.Length = Length;
+ ScriptMemReadWrite.Width = Width;
+ ScriptMemReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration space write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The address within the PCI configuration space.
+ @param Count The number of PCI operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfgWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ //
+ // Truncation check
+ //
+ if ((Count > MAX_UINT8) ||
+ (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE))) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;
+ ScriptPciWrite.Length = Length;
+ ScriptPciWrite.Width = Width;
+ ScriptPciWrite.Address = Address;
+ ScriptPciWrite.Count = (UINT32) Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration space modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The address within the PCI configuration space.
+ @param Data A pointer to the data to be OR-ed.The size depends on Width.
+ @param DataMask A pointer to the data mask to be AND-ed.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN__SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfgReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;
+ ScriptPciReadWrite.Length = Length;
+ ScriptPciReadWrite.Width = Width;
+ ScriptPciReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),
+ DataMask,
+ WidthInByte
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration 2 space write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Count The number of PCI operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfg2Write (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ //
+ // Truncation check
+ //
+ if ((Count > MAX_UINT8) ||
+ (WidthInByte * Count > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE))) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;
+ ScriptPciWrite2.Length = Length;
+ ScriptPciWrite2.Width = Width;
+ ScriptPciWrite2.Address = Address;
+ ScriptPciWrite2.Segment = Segment;
+ ScriptPciWrite2.Count = (UINT32)Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Data A pointer to the data to be OR-ed. The size depends on Width.
+ @param DataMask A pointer to the data mask to be AND-ed.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfg2ReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;
+ ScriptPciReadWrite2.Length = Length;
+ ScriptPciReadWrite2.Width = Width;
+ ScriptPciReadWrite2.Segment = Segment;
+ ScriptPciReadWrite2.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),
+ DataMask,
+ WidthInByte
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Checks the parameter of S3BootScriptSaveSmbusExecute().
+
+ This function checks the input parameters of SmbusExecute(). If the input parameters are valid
+ for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
+ error code based on the input SMBus bus protocol.
+
+ @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
+ and PEC.
+ @param Operation Signifies which particular SMBus hardware protocol instance that
+ it will use to execute the SMBus transactions. This SMBus
+ hardware protocol is defined by the SMBus Specification and is
+ not related to EFI.
+ @param Length Signifies the number of bytes that this operation will do. The
+ maximum number of bytes can be revision specific and operation
+ specific. This field will contain the actual number of bytes that
+ are executed for this operation. Not all operations require this
+ argument.
+ @param Buffer Contains the value of data to execute to the SMBus slave device.
+ Not all operations require this argument. The length of this
+ buffer is identified by Length.
+
+ @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus
+ protocol.
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+ and EfiSmbusQuickWrite. Length is outside the range of valid
+ values.
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+CheckParameters (
+ IN UINTN SmBusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN OUT UINTN *Length,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN RequiredLen;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ BOOLEAN PecCheck;
+
+ Command = SMBUS_LIB_COMMAND (SmBusAddress);
+ PecCheck = SMBUS_LIB_PEC (SmBusAddress);
+ //
+ // Set default value to be 2:
+ // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
+ //
+ RequiredLen = 2;
+ Status = EFI_SUCCESS;
+ switch (Operation) {
+ case EfiSmbusQuickRead:
+ case EfiSmbusQuickWrite:
+ if (PecCheck || Command != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ break;
+ case EfiSmbusReceiveByte:
+ case EfiSmbusSendByte:
+ if (Command != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Cascade to check length parameter.
+ //
+ case EfiSmbusReadByte:
+ case EfiSmbusWriteByte:
+ RequiredLen = 1;
+ //
+ // Cascade to check length parameter.
+ //
+ case EfiSmbusReadWord:
+ case EfiSmbusWriteWord:
+ case EfiSmbusProcessCall:
+ if (Buffer == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else if (*Length < RequiredLen) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = RequiredLen;
+ break;
+ case EfiSmbusReadBlock:
+ case EfiSmbusWriteBlock:
+ case EfiSmbusBWBRProcessCall:
+ if ((Buffer == NULL) ||
+ (Length == NULL) ||
+ (*Length < MIN_SMBUS_BLOCK_LEN) ||
+ (*Length > MAX_SMBUS_BLOCK_LEN)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ return Status;
+}
+
+/**
+ Adds a record for an SMBus command execution into a specified boot script table.
+
+ @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.
+ @param Operation Indicates which particular SMBus protocol it will use to execute the SMBus
+ transactions.
+ @param Length A pointer to signify the number of bytes that this operation will do.
+ @param Buffer Contains the value of data to execute to the SMBUS slave device.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveSmbusExecute (
+ IN UINTN SmBusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN UINTN *Length,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferLength;
+ UINT8 DataSize;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;
+
+ if (Length == NULL) {
+ BufferLength = 0;
+ } else {
+ BufferLength = *Length;
+ }
+
+ Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Truncation check
+ //
+ if (BufferLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);
+
+ Script = S3BootScriptGetEntryAddAddress (DataSize);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptSmbusExecute.OpCode = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;
+ ScriptSmbusExecute.Length = DataSize;
+ ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;
+ ScriptSmbusExecute.Operation = Operation;
+ ScriptSmbusExecute.DataSize = (UINT32) BufferLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),
+ Buffer,
+ BufferLength
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for an execution stall on the processor into a specified boot script table.
+
+ @param Duration Duration in microseconds of the stall
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveStall (
+ IN UINTN Duration
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_STALL ScriptStall;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE;
+ ScriptStall.Length = Length;
+ ScriptStall.Duration = Duration;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for dispatching specified arbitrary code into a specified boot script table.
+
+ @param EntryPoint Entry point of the code to be dispatched.
+ @param Context Argument to be passed into the EntryPoint of the code to be dispatched.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveDispatch2 (
+ IN VOID *EntryPoint,
+ IN VOID *Context
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;
+ ScriptDispatch2.Length = Length;
+ ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+ ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Adds a record for memory reads of the memory location and continues when the exit criteria is
+ satisfied or after a defined duration.
+
+ Please aware, below interface is different with PI specification, Vol 5:
+ EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.
+ "Duration" below is microseconds, while "Delay" in PI specification means
+ the number of 100ns units to poll.
+
+ @param Width The width of the memory operations.
+ @param Address The base address of the memory operations.
+ @param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.
+ @param BitValue A pointer to the data value after to be Masked.
+ @param Duration Duration in microseconds of the stall.
+ @param LoopTimes The times of the register polling.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *BitMask,
+ IN VOID *BitValue,
+ IN UINTN Duration,
+ IN UINT64 LoopTimes
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;
+ ScriptMemPoll.Length = Length;
+ ScriptMemPoll.Width = Width;
+ ScriptMemPoll.Address = Address;
+ ScriptMemPoll.Duration = Duration;
+ ScriptMemPoll.LoopTimes = LoopTimes;
+
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only
+ used for debugging script issues.
+
+ @param InformationLength Length of the data in bytes
+ @param Information Information to be logged in the boot scrpit
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveInformation (
+ IN UINT32 InformationLength,
+ IN VOID *Information
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
+
+ //
+ // Truncation check
+ //
+ if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptInformation.OpCode = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;
+ ScriptInformation.Length = Length;
+
+
+ ScriptInformation.InformationLength = InformationLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Store a string in the boot script table. This opcode is a no-op on dispatch and is only
+ used for debugging script issues.
+
+ @param String The string to save to boot script table
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveInformationAsciiString (
+ IN CONST CHAR8 *String
+ )
+{
+ return S3BootScriptSaveInformation (
+ (UINT32) AsciiStrLen (String) + 1,
+ (VOID*) String
+ );
+}
+/**
+ Adds a record for dispatching specified arbitrary code into a specified boot script table.
+
+ @param EntryPoint Entry point of the code to be dispatched.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveDispatch (
+ IN VOID *EntryPoint
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;
+ ScriptDispatch.Length = Length;
+ ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a
+ defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Address The base address of the I/O operations.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address.
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+ )
+{
+ UINT8 WidthInByte;
+ UINT8 *Script;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll;
+
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;
+ ScriptIoPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
+ ScriptIoPoll.Width = Width;
+ ScriptIoPoll.Address = Address;
+ ScriptIoPoll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
+ after a defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Address The address within the PCI configuration space.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+)
+{
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;
+ ScriptPciPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
+ ScriptPciPoll.Width = Width;
+ ScriptPciPoll.Address = Address;
+ ScriptPciPoll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
+ after a defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePci2Poll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+)
+{
+ UINT8 WidthInByte;
+ UINT8 *Script;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPci2Poll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;
+ ScriptPci2Poll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
+ ScriptPci2Poll.Width = Width;
+ ScriptPci2Poll.Segment = Segment;
+ ScriptPci2Poll.Address = Address;
+ ScriptPci2Poll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Do the calculation of start address from which a new s3 boot script entry will write into.
+
+ @param EntryLength The new entry length.
+ @param Position specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter.
+ @param BeforeOrAfter The flag to indicate to insert the nod before or after the position.
+ This parameter is effective when InsertFlag is TRUE
+ @param Script return out the position from which the a new s3 boot script entry will write into
+**/
+VOID
+S3BootScriptCalculateInsertAddress (
+ IN UINT8 EntryLength,
+ IN VOID *Position OPTIONAL,
+ IN BOOLEAN BeforeOrAfter OPTIONAL,
+ OUT UINT8 **Script
+ )
+{
+ UINTN TableLength;
+ UINT8 *S3TableBase;
+ UINTN PositionOffset;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ //
+ // The entry inserting to table is already added to the end of the table
+ //
+ TableLength = mS3BootScriptTablePtr->TableLength - EntryLength;
+ S3TableBase = mS3BootScriptTablePtr->TableBase ;
+ //
+ // calculate the Position offset
+ //
+ if (Position != NULL) {
+ PositionOffset = (UINTN)Position - (UINTN)S3TableBase;
+
+ //
+ // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.
+ //
+ if (!BeforeOrAfter) {
+ CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ PositionOffset += (ScriptHeader.Length);
+ }
+ //
+ // Insert the node before the adjusted Position
+ //
+ CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
+ //
+ // calculate the the start address for the new entry.
+ //
+ *Script = S3TableBase + PositionOffset;
+
+ } else {
+ if (!BeforeOrAfter) {
+ //
+ // Insert the node to the end of the table
+ //
+ *Script = S3TableBase + TableLength;
+ } else {
+ //
+ // Insert the node to the beginning of the table
+ //
+ PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
+ CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
+ *Script = S3TableBase + PositionOffset;
+ }
+ }
+}
+/**
+ Move the last boot script entry to the position
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+
+ @retval RETURN_OUT_OF_RESOURCES The table is not available.
+ @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+ @retval RETURN_SUCCESS Opcode is inserted.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptMoveLastOpcode (
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT VOID **Position OPTIONAL
+)
+{
+ UINT8* Script;
+ VOID *TempPosition;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ BOOLEAN ValidatePosition;
+ UINT8* LastOpcode;
+ UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];
+
+ ValidatePosition = FALSE;
+ TempPosition = (Position == NULL) ? NULL:(*Position);
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Script = mS3BootScriptTablePtr->TableBase;
+
+ StartAddress = (UINTN) Script;
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ Script = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
+ LastOpcode = Script;
+ //
+ // Find the last boot Script Entry which is not the terminate node
+ //
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ if (TempPosition != NULL && TempPosition == Script) {
+ //
+ // If the position is specified, the position must be pointed to a boot script entry start address.
+ //
+ ValidatePosition = TRUE;
+ }
+ if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {
+ LastOpcode = Script;
+ }
+ Script = Script + ScriptHeader.Length;
+ }
+ //
+ // If the position is specified, but not the start of a boot script entry, it is a invalid input
+ //
+ if (TempPosition != NULL && !ValidatePosition) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+
+ CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);
+ //
+ // Find the right position to write the node in
+ //
+ S3BootScriptCalculateInsertAddress (
+ ScriptHeader.Length,
+ TempPosition,
+ BeforeOrAfter,
+ &Script
+ );
+ //
+ // Copy the node to Boot script table
+ //
+ CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);
+
+ SyncBootScript (Script);
+
+ //
+ // return out the Position
+ //
+ if (Position != NULL) {
+ *Position = Script;
+ }
+ return RETURN_SUCCESS;
+}
+/**
+ Create a Label node in the boot script table.
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param InformationLength Length of the label in bytes
+ @param Information Label to be logged in the boot scrpit
+
+ @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLabelInternal (
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT VOID **Position OPTIONAL,
+ IN UINT32 InformationLength,
+ IN CONST CHAR8 *Information
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
+
+ //
+ // Truncation check
+ //
+ if (InformationLength > MAX_UINT8 - sizeof (EFI_BOOT_SCRIPT_INFORMATION)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptInformation.OpCode = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;
+ ScriptInformation.Length = Length;
+
+
+ ScriptInformation.InformationLength = InformationLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
+
+ SyncBootScript (Script);
+
+ return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
+
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE)
+ or after (FALSE) the position in the boot script table
+ specified by Position.
+ @param CreateIfNotFound Specifies whether the label will be created if the label
+ does not exists (TRUE) or not (FALSE).
+ @param Position On entry, specifies the position in the boot script table
+ where the opcode will be inserted, either before or after,
+ depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted opcode in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLabel (
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT VOID **Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ UINT8* Script;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;
+ UINT32 LabelLength;
+ //
+ // Check NULL Label
+ //
+ if (Label == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check empty Label
+ //
+ if (Label[0] == '\0') {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ // The code must search for the label first before it knows if a new entry needs
+ // to be added.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check the header and search for existing label.
+ //
+ Script = mS3BootScriptTablePtr->TableBase;
+ CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
+ if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ StartAddress = (UINTN) Script;
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ Script = Script + TableHeader.Length;
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {
+ if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {
+ (*Position) = Script;
+ return EFI_SUCCESS;
+ }
+ }
+ Script = Script + ScriptHeader.Length;
+ }
+ if (CreateIfNotFound) {
+ LabelLength = (UINT32)AsciiStrSize(Label);
+ return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Compare two positions in the boot script table and return their relative position.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptCompare (
+ IN UINT8 *Position1,
+ IN UINT8 *Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ UINT8* Script;
+ UINT32 TableLength;
+
+ if (RelativePosition == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Script = mS3BootScriptTablePtr->TableBase;
+
+ //
+ // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up
+ //
+ TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ if (Position1 < Script || Position1 > Script+TableLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Position2 < Script || Position2 > Script+TableLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
new file mode 100644
index 000000000..2b894c99d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
@@ -0,0 +1,68 @@
+## @file
+# DXE S3 boot script Library.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeS3BootScriptLib
+ MODULE_UNI_FILE = DxeS3BootScriptLib.uni
+ FILE_GUID = 57F9967B-26CD-4262-837A-55B8AA158254
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = S3BootScriptLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+
+ CONSTRUCTOR = S3BootScriptLibInitialize
+ DESTRUCTOR = S3BootScriptLibDeinitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootScriptSave.c
+ BootScriptExecute.c
+ InternalBootScriptLib.h
+ BootScriptInternalFormat.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ TimerLib
+ DebugLib
+ PcdLib
+ UefiLib
+ SmbusLib
+ PciSegmentLib
+ IoLib
+ LockBoxLib
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid ## NOTIFY
+ gEfiSmmReadyToLockProtocolGuid ## NOTIFY
+ gEdkiiSmmExitBootServicesProtocolGuid ## NOTIFY
+ gEdkiiSmmLegacyBootProtocolGuid ## NOTIFY
+
+[Pcd]
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptRuntimeTableReservePageNumber ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni
new file mode 100644
index 000000000..4664943f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// DXE S3 boot script Library.
+//
+// S3 boot script Library that could be used for multiple phases.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "S3 boot script Library that could be used for multiple phases"
+
+#string STR_MODULE_DESCRIPTION #language en-US "S3 boot script Library that could be used for multiple phases."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h
new file mode 100644
index 000000000..948599408
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h
@@ -0,0 +1,105 @@
+/** @file
+ Support for S3 boot script lib. This file defined some internal macro and internal
+ data structure
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __INTERNAL_BOOT_SCRIPT_LIB__
+#define __INTERNAL_BOOT_SCRIPT_LIB__
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmExitBootServices.h>
+#include <Protocol/SmmLegacyBoot.h>
+
+#include <Library/S3BootScriptLib.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/LockBoxLib.h>
+
+#include "BootScriptInternalFormat.h"
+
+#define MAX_IO_ADDRESS 0xFFFF
+
+//
+// Macro to convert a UEFI PCI address + segment to a PCI Segment Library PCI address
+//
+#define PCI_ADDRESS_ENCODE(S, A) PCI_SEGMENT_LIB_ADDRESS( \
+ S, \
+ ((((UINTN)(A)) & 0xff000000) >> 24), \
+ ((((UINTN)(A)) & 0x00ff0000) >> 16), \
+ ((((UINTN)(A)) & 0xff00) >> 8), \
+ ((RShiftU64 ((A), 32) & 0xfff) | ((A) & 0xff)) \
+ )
+
+typedef union {
+ UINT8 volatile *Buf;
+ UINT8 volatile *Uint8;
+ UINT16 volatile *Uint16;
+ UINT32 volatile *Uint32;
+ UINT64 volatile *Uint64;
+ UINTN volatile Uint;
+} PTR;
+
+
+// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0.
+//
+#define MIN_SMBUS_BLOCK_LEN 1
+#define MAX_SMBUS_BLOCK_LEN 32
+
+//
+// The boot script private data.
+//
+typedef struct {
+ UINT8 *TableBase;
+ UINT32 TableLength; // Record the actual memory length
+ UINT16 TableMemoryPageNumber; // Record the page number Allocated for the table
+ BOOLEAN InSmm; // Record if this library is in SMM.
+ BOOLEAN AtRuntime; // Record if current state is after SmmExitBootServices or SmmLegacyBoot.
+ UINT32 BootTimeScriptLength; // Maintain boot time script length in LockBox after SmmReadyToLock in SMM.
+ BOOLEAN SmmLocked; // Record if current state is after SmmReadyToLock
+ BOOLEAN BackFromS3; // Indicate that the system is back from S3.
+} SCRIPT_TABLE_PRIVATE_DATA;
+
+typedef
+EFI_STATUS
+(EFIAPI *DISPATCH_ENTRYPOINT_FUNC) (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Context
+ );
+
+extern SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;
+
+//
+// Define Opcode for Label which is implementation specific and no standard spec define.
+//
+#define S3_BOOT_SCRIPT_LIB_LABEL_OPCODE 0xFE
+
+///
+/// The opcode indicate the start of the boot script table.
+///
+#define S3_BOOT_SCRIPT_LIB_TABLE_OPCODE 0xAA
+///
+/// The opcode indicate the end of the boot script table.
+///
+#define S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE 0xFF
+
+
+#endif //__INTERNAL_BOOT_SCRIPT_LIB__
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c
new file mode 100644
index 000000000..fd20a779c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c
@@ -0,0 +1,1105 @@
+/** @file
+ Support routines for memory allocation routines based on SMM Core internal functions,
+ with memory profile support.
+
+ The PI System Management Mode Core Interface Specification only allows the use
+ of EfiRuntimeServicesCode and EfiRuntimeServicesData memory types for memory
+ allocations as the SMRAM space should be reserved after BDS phase. The functions
+ in the Memory Allocation Library use EfiBootServicesData as the default memory
+ allocation type. For this SMM specific instance of the Memory Allocation Library,
+ EfiRuntimeServicesData is used as the default memory type for all allocations.
+ In addition, allocation for the Reserved memory types are not supported and will
+ always return NULL.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "PiSmmCoreMemoryAllocationServices.h"
+
+#include <Library/MemoryProfileLib.h>
+
+EFI_SMRAM_DESCRIPTOR *mSmmCoreMemoryAllocLibSmramRanges = NULL;
+UINTN mSmmCoreMemoryAllocLibSmramRangeCount = 0;
+
+/**
+ Check whether the start address of buffer is within any of the SMRAM ranges.
+
+ @param[in] Buffer The pointer to the buffer to be checked.
+
+ @retval TRUE The buffer is in SMRAM ranges.
+ @retval FALSE The buffer is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+BufferInSmram (
+ IN VOID *Buffer
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mSmmCoreMemoryAllocLibSmramRangeCount; Index ++) {
+ if (((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer >= mSmmCoreMemoryAllocLibSmramRanges[Index].CpuStart) &&
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer < (mSmmCoreMemoryAllocLibSmramRanges[Index].CpuStart + mSmmCoreMemoryAllocLibSmramRanges[Index].PhysicalSize))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.
+ // So, SmmFreePages() service is used to free it.
+ //
+ Status = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.
+ // So, SmmFreePages() service is used to free it.
+ //
+ Status = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = SmmAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePool() service.
+ // So, SmmFreePool() service is used to free it.
+ //
+ Status = SmmFreePool (Buffer);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePool() service.
+ // So, gBS->FreePool() service is used to free it.
+ //
+ Status = gBS->FreePool (Buffer);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ The constructor function calls SmmInitializeMemoryServices to initialize memory in SMRAM.
+
+ @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
+PiSmmCoreMemoryAllocationLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SMM_CORE_PRIVATE_DATA *SmmCorePrivate;
+ UINTN Size;
+ VOID *BootServicesData;
+
+ SmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;
+
+ //
+ // The FreePool()/FreePages() will need use SmramRanges data to know whether
+ // the buffer to free is in SMRAM range or not. And there may be FreePool()/
+ // FreePages() indrectly during calling SmmInitializeMemoryServices(), but
+ // no SMRAM could be allocated before calling SmmInitializeMemoryServices(),
+ // so temporarily use BootServicesData to hold the SmramRanges data.
+ //
+ mSmmCoreMemoryAllocLibSmramRangeCount = SmmCorePrivate->SmramRangeCount;
+ Size = mSmmCoreMemoryAllocLibSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR);
+ Status = gBS->AllocatePool (EfiBootServicesData, Size, (VOID **) &mSmmCoreMemoryAllocLibSmramRanges);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mSmmCoreMemoryAllocLibSmramRanges != NULL);
+ CopyMem (mSmmCoreMemoryAllocLibSmramRanges, SmmCorePrivate->SmramRanges, Size);
+
+ //
+ // Initialize memory service using free SMRAM
+ //
+ SmmInitializeMemoryServices (SmmCorePrivate->SmramRangeCount, SmmCorePrivate->SmramRanges);
+
+ //
+ // Move the SmramRanges data from BootServicesData to SMRAM.
+ //
+ BootServicesData = mSmmCoreMemoryAllocLibSmramRanges;
+ mSmmCoreMemoryAllocLibSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocateCopyPool (Size, (VOID *) BootServicesData);
+ ASSERT (mSmmCoreMemoryAllocLibSmramRanges != NULL);
+
+ //
+ // Free the temporarily used BootServicesData.
+ //
+ Status = gBS->FreePool (BootServicesData);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
new file mode 100644
index 000000000..5c51c48b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
@@ -0,0 +1,42 @@
+## @file
+# Memory Allocation Library instance dedicated to SMM Core.
+# The implementation borrows the SMM Core Memory Allocation services as the primitive
+# for memory allocation instead of using SMM System Table services in an indirect way.
+# It is assumed that this library instance must be linked with SMM Cre in this package.
+#
+# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCoreMemoryAllocationLib
+ MODULE_UNI_FILE = PiSmmCoreMemoryAllocationLib.uni
+ FILE_GUID = B618E089-9ABA-4d97-AE80-57B5BCCDA51D
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE
+ CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ PiSmmCoreMemoryAllocationServices.h
+ PiSmmCoreMemoryProfileLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni
new file mode 100644
index 000000000..9fe84a9bd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Memory Allocation Library instance dedicated to SMM Core.
+//
+// The implementation borrows the SMM Core Memory Allocation services as the primitive
+// for memory allocation instead of using SMM System Table services in an indirect way.
+// It is assumed that this library instance must be linked with SMM Cre in this package.
+//
+// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation Library instance dedicated to SMM Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the SMM Core Memory Allocation services as the primitive for memory allocation instead of using SMM System Table services in an indirect way. This library is only intended to be linked with the SMM Core that resides in this same package."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf
new file mode 100644
index 000000000..89658c0f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Memory Allocation/Profile Library instance dedicated to SMM Core.
+# The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive
+# for memory allocation/profile instead of using SMM System Table servces or SMM memory profile protocol in an indirect way.
+# It is assumed that this library instance must be linked with SMM Cre in this package.
+#
+# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCoreMemoryAllocationProfileLib
+ MODULE_UNI_FILE = PiSmmCoreMemoryAllocationProfileLib.uni
+ FILE_GUID = D55E42AD-3E63-4536-8281-82C0F1098C5E
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE
+ CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor
+ LIBRARY_CLASS = MemoryProfileLib|SMM_CORE
+ CONSTRUCTOR = PiSmmCoreMemoryProfileLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ PiSmmCoreMemoryAllocationServices.h
+ PiSmmCoreMemoryProfileLib.c
+ PiSmmCoreMemoryProfileServices.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.uni b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.uni
new file mode 100644
index 000000000..479c07941
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Memory Allocation/Profile Library instance dedicated to SMM Core.
+//
+// The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive
+// for memory allocation/profile instead of using SMM System Table servces or SMM memory profile protocol in an indirect way.
+// It is assumed that this library instance must be linked with SMM Cre in this package.
+//
+// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation/Profile Library instance dedicated to SMM Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive for memory allocation/profile instead of using SMM System Table services or SMM memory profile protocol in an indirect way. This library is only intended to be linked with the SMM Core that resides in this same package."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h
new file mode 100644
index 000000000..789fcf2c0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h
@@ -0,0 +1,185 @@
+/** @file
+ Contains function prototypes for Memory Services in the SMM Core.
+
+ This header file borrows the PiSmmCore Memory Allocation services as the primitive
+ for memory allocation.
+
+ Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_
+#define _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_
+
+//
+// It should be aligned with the definition in PiSmmCore.
+//
+typedef struct {
+ UINTN Signature;
+
+ ///
+ /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle
+ /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded
+ /// Image Protocol for each SMM Driver that is dispatched by the SMM Core.
+ ///
+ EFI_HANDLE SmmIplImageHandle;
+
+ ///
+ /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
+ ///
+ UINTN SmramRangeCount;
+
+ ///
+ /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
+ ///
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;
+
+ ///
+ /// The SMM Foundation Entry Point. The SMM Core fills in this field when the
+ /// SMM Core is initialized. The SMM IPL is responsbile for registering this entry
+ /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may
+ /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL
+ /// sets up a protocol notification on the SMM Configuration Protocol and registers
+ /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is
+ /// available.
+ ///
+ EFI_SMM_ENTRY_POINT SmmEntryPoint;
+
+ ///
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
+ ///
+ BOOLEAN SmmEntryPointRegistered;
+
+ ///
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
+ ///
+ BOOLEAN InSmm;
+
+ ///
+ /// This field is set by the SMM Core then the SMM Core is initialized. This field is
+ /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in
+ /// the SMM IPL.
+ ///
+ EFI_SMM_SYSTEM_TABLE2 *Smst;
+
+ ///
+ /// This field is used by the SMM Communicatioon Protocol to pass a buffer into
+ /// a software SMI handler and for the software SMI handler to pass a buffer back to
+ /// the caller of the SMM Communication Protocol.
+ ///
+ VOID *CommunicationBuffer;
+
+ ///
+ /// This field is used by the SMM Communicatioon Protocol to pass the size of a buffer,
+ /// in bytes, into a software SMI handler and for the software SMI handler to pass the
+ /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.
+ ///
+ UINTN BufferSize;
+
+ ///
+ /// This field is used by the SMM Communication Protocol to pass the return status from
+ /// a software SMI handler back to the caller of the SMM Communication Protocol.
+ ///
+ EFI_STATUS ReturnStatus;
+
+ EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase;
+ UINT64 PiSmmCoreImageSize;
+ EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint;
+} SMM_CORE_PRIVATE_DATA;
+
+/**
+ Called to initialize the memory service.
+
+ @param SmramRangeCount Number of SMRAM Regions
+ @param SmramRanges Pointer to SMRAM Descriptors
+
+**/
+VOID
+SmmInitializeMemoryServices (
+ IN UINTN SmramRangeCount,
+ IN EFI_SMRAM_DESCRIPTOR *SmramRanges
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFreePool (
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLib.c b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLib.c
new file mode 100644
index 000000000..32ef22256
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLib.c
@@ -0,0 +1,117 @@
+/** @file
+ Support routines for memory profile for PiSmmCore.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include <Guid/MemoryProfile.h>
+
+#include "PiSmmCoreMemoryProfileServices.h"
+
+EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
+
+/**
+ Check whether the start address of buffer is within any of the SMRAM ranges.
+
+ @param[in] Buffer The pointer to the buffer to be checked.
+
+ @retval TRUE The buffer is in SMRAM ranges.
+ @retval FALSE The buffer is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+BufferInSmram (
+ IN VOID *Buffer
+ );
+
+/**
+ The constructor function initializes memory profile for SMM phase.
+
+ @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
+PiSmmCoreMemoryProfileLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Profile Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEdkiiMemoryProfileGuid,
+ NULL,
+ (VOID **)&mLibProfileProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mLibProfileProtocol = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ if (BufferInSmram (Buffer)) {
+ return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ } else {
+ if (mLibProfileProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mLibProfileProtocol->Record (
+ mLibProfileProtocol,
+ CallerAddress,
+ Action,
+ MemoryType,
+ Buffer,
+ Size,
+ ActionString
+ );
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLibNull.c b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLibNull.c
new file mode 100644
index 000000000..b132024d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileLibNull.c
@@ -0,0 +1,48 @@
+/** @file
+ Null routines for memory profile for PiSmmCore.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Guid/MemoryProfile.h>
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileServices.h b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileServices.h
new file mode 100644
index 000000000..236a5ead2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryProfileServices.h
@@ -0,0 +1,48 @@
+/** @file
+ Contains function prototypes for Memory Profile Services in the SMM Core.
+
+ This header file borrows the PiSmmCore Memory Profile services as the primitive
+ for memory profile.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_SMM_CORE_MEMORY_PROFILE_SERVICES_H_
+#define _PI_SMM_CORE_MEMORY_PROFILE_SERVICES_H_
+
+/**
+ Update SMRAM profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c
new file mode 100644
index 000000000..b48372f62
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c
@@ -0,0 +1,54 @@
+/** @file
+ SMM Core SMM Services Table Library.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+EFI_SMM_SYSTEM_TABLE2 *gSmst = NULL;
+extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst;
+
+/**
+ The constructor function caches the pointer of SMM Services Table.
+
+ @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
+SmmCoreSmmServicesTableLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gSmst = &gSmmCoreSmst;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows the caller to determine if the driver is executing in
+ System Management Mode(SMM).
+
+ This function returns TRUE if the driver is executing in SMM and FALSE if the
+ driver is not executing in SMM.
+
+ @retval TRUE The driver is executing in System Management Mode (SMM).
+ @retval FALSE The driver is not executing in System Management Mode (SMM).
+
+**/
+BOOLEAN
+EFIAPI
+InSmm (
+ VOID
+ )
+{
+ return TRUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
new file mode 100644
index 000000000..f25e8fff1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
@@ -0,0 +1,31 @@
+## @file
+# SMM Core SMM Services Table Library.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCoreSmmServicesTableLib
+ MODULE_UNI_FILE = PiSmmCoreSmmServicesTableLib.uni
+ FILE_GUID = C427146A-2EF2-4af9-A85A-E09EA65EE47D
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmServicesTableLib|SMM_CORE
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ CONSTRUCTOR = SmmCoreSmmServicesTableLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmCoreSmmServicesTableLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
diff --git a/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni
new file mode 100644
index 000000000..3ef566708
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SMM Core SMM Services Table Library.
+//
+// SMM Core SMM Services Table Library.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM Core SMM Services Table Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "SMM Core SMM Services Table Library."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c
new file mode 100644
index 000000000..43560bf2a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c
@@ -0,0 +1,78 @@
+/** @file
+ This file include all platform action which can be customized
+ by IBV/OEM.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/PlatformBootManagerLib.h>
+
+
+/**
+ Do the platform specific action before the console is connected.
+
+ Such as:
+ Update console variable;
+ Register new Driver#### or Boot####;
+ Signal ReadyToLock event.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ Do the platform specific action after the console is connected.
+
+ Such as:
+ Dynamically switch output mode;
+ Signal console ready platform customized event;
+ Run diagnostics like memory testing;
+ Connect certain devices;
+ Dispatch aditional option roms.
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This function is called each second during the boot manager waits the timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ return;
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ )
+{
+ return;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
new file mode 100644
index 000000000..cf1beb2ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
@@ -0,0 +1,31 @@
+## @file
+# Include all platform action which can be customized by IBV/OEM.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBootManagerLib
+ MODULE_UNI_FILE = PlatformBootManagerLibNull.uni
+ FILE_GUID = 95C097CC-8943-4038-BB8A-1C70CF2E9F3C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PlatformBootManager.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni
new file mode 100644
index 000000000..a002ab8e5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni
@@ -0,0 +1,14 @@
+// /** @file
+// NULL implementation for PlatformBootManagerLib library class interfaces.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL implementation for PlatformBootManagerLib library class interfaces"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL implementation for PlatformBootManagerLib library class interfaces."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c
new file mode 100644
index 000000000..8cdfc846f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c
@@ -0,0 +1,30 @@
+/** @file
+ Null Platform Hook Library instance with dependency on gPeiSerialPortPpiGuid
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/PlatformHookLib.h>
+
+/**
+ Performs platform specific initialization required for the CPU to access
+ the hardware associated with a SerialPortLib instance. This function does
+ not initialize the serial port hardware itself. Instead, it initializes
+ hardware devices that are required for the CPU to access the serial port
+ hardware. This function may be called more than once.
+
+ @retval RETURN_SUCCESS The platform specific initialization succeeded.
+ @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf
new file mode 100644
index 000000000..6777bac88
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf
@@ -0,0 +1,33 @@
+## @file
+# Null Platform Hook Library instance with dependency on gPeiSerialPortPpiGuid
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformHookLibSerialPortPpi
+ FILE_GUID = 621734D8-8B5E-4c01-B330-9F89A1081710
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER SMM_CORE PEIM SEC PEI_CORE UEFI_APPLICATION UEFI_DRIVER
+ MODULE_UNI_FILE = PlatformHookLibSerialPortPpi.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PlatformHookLibSerialPortPpi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Depex.common.PEIM]
+ gPeiSerialPortPpiGuid
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni
new file mode 100644
index 000000000..75dba77fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Null Platform Hook Library instance with dependency on gPeiSerialPortPpiGuid
+//
+// Provides platform-specific implementations to support core functionality. Currently this provides a hook to initialize the serial port with dependency on gPeiSerialPortPpiGuid.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Platform Hook Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides platform-specific implementations to support core functionality. Currently this provides a hook to initialize the serial port with dependency on gPeiSerialPortPpiGuid."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
new file mode 100644
index 000000000..c809a7086
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
@@ -0,0 +1,102 @@
+/** @file
+ Include file for platform variable cleanup.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_
+#define _PLAT_VAR_CLEANUP_
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PlatformVarCleanupLib.h>
+
+#include <Protocol/Variable.h>
+#include <Protocol/VarCheck.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/VarErrorFlag.h>
+
+#include "PlatVarCleanupHii.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatVarCleanupBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatformVarCleanupLibStrings[];
+
+#define USER_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_GUID Guid;
+ CHAR16 *PromptString;
+ LIST_ENTRY NameLink;
+} USER_VARIABLE_NODE;
+
+#define USER_VARIABLE_FROM_LINK(a) CR (a, USER_VARIABLE_NODE, Link, USER_VARIABLE_NODE_SIGNATURE)
+
+#define USER_VARIABLE_NAME_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'N')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ UINTN DataSize;
+ UINT32 Attributes;
+ UINT16 Index;
+ EFI_QUESTION_ID QuestionId;
+ CHAR16 *PromptString;
+ CHAR16 *HelpString;
+ BOOLEAN Deleted;
+} USER_VARIABLE_NAME_NODE;
+
+#define USER_VARIABLE_NAME_FROM_LINK(a) CR (a, USER_VARIABLE_NAME_NODE, Link, USER_VARIABLE_NAME_NODE_SIGNATURE)
+
+#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()
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ VARIABLE_CLEANUP_DATA VariableCleanupData;
+} VARIABLE_CLEANUP_HII_PRIVATE_DATA;
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS(a) CR (a, VARIABLE_CLEANUP_HII_PRIVATE_DATA, ConfigAccess, VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE)
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
new file mode 100644
index 000000000..692faa3f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
@@ -0,0 +1,35 @@
+/** @file
+ Platform variable cleanup Formset.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlatVarCleanupHii.h"
+
+formset
+ guid = VARIABLE_CLEANUP_HII_GUID,
+ title = STRING_TOKEN(STR_ENTRY_TITLE),
+ help = STRING_TOKEN(STR_TITLE_HELP),
+
+ varstore VARIABLE_CLEANUP_DATA,
+ varid = VARIABLE_CLEANUP_VARSTORE_ID,
+ name = VariableCleanup,
+ guid = VARIABLE_CLEANUP_HII_GUID;
+
+ form formid = FORM_ID_VARIABLE_CLEANUP,
+ title = STRING_TOKEN(STR_TITLE);
+
+ checkbox varid = VARIABLE_CLEANUP_DATA.SelectAll,
+ prompt = STRING_TOKEN(STR_SELECT_ALL_PROMPT),
+ help = STRING_TOKEN(STR_SELECT_ALL_HELP),
+ flags = INTERACTIVE,
+ key = SELECT_ALL_QUESTION_ID,
+ endcheckbox;
+
+ label LABEL_START;
+ label LABEL_END;
+
+ endform;
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
new file mode 100644
index 000000000..74bcdb4b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
@@ -0,0 +1,53 @@
+/** @file
+ Include file for platform variable cleanup HII.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_HII_
+#define _PLAT_VAR_CLEANUP_HII_
+
+//
+// {24F14D8A-D7A8-4991-91E0-96C3B7DB8456}
+//
+#define VARIABLE_CLEANUP_HII_GUID \
+ { \
+ 0x24f14d8a, 0xd7a8, 0x4991, { 0x91, 0xe0, 0x96, 0xc3, 0xb7, 0xdb, 0x84, 0x56 } \
+ }
+
+#define MAX_USER_VARIABLE_COUNT 0x1000
+
+typedef struct {
+ UINT8 SelectAll;
+ //
+ // FALSE is to not delete, TRUE is to delete.
+ //
+ UINT8 UserVariable[MAX_USER_VARIABLE_COUNT];
+} VARIABLE_CLEANUP_DATA;
+
+#define VARIABLE_CLEANUP_VARSTORE_ID 0x8000
+
+//
+// Field offset of structure VARIABLE_CLEANUP_DATA
+//
+#define VAR_OFFSET(Field) ((UINTN) &(((VARIABLE_CLEANUP_DATA *) 0)->Field))
+#define USER_VARIABLE_VAR_OFFSET (VAR_OFFSET (UserVariable))
+
+#define FORM_ID_VARIABLE_CLEANUP 0x8000
+
+#define LABEL_START 0x0000
+#define LABEL_END 0xFFFF
+
+#define SELECT_ALL_QUESTION_ID 0x7FFD
+#define SAVE_AND_EXIT_QUESTION_ID 0x7FFE
+#define NO_SAVE_AND_EXIT_QUESTION_ID 0x7FFF
+
+//
+// Tool automatic generated Question Id start from 1.
+// In order to avoid to conflict them, the user variable QuestionID offset is defined from 0x8000.
+//
+#define USER_VARIABLE_QUESTION_ID 0x8000
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
new file mode 100644
index 000000000..3875d614b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
@@ -0,0 +1,1278 @@
+/** @file
+ Sample platform variable cleanup library implementation.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlatVarCleanup.h"
+
+VAR_ERROR_FLAG mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
+EDKII_VAR_CHECK_PROTOCOL *mVarCheck = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+EFI_EVENT mPlatVarCleanupLibEndOfDxeEvent = NULL;
+
+LIST_ENTRY mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
+UINT16 mUserVariableCount = 0;
+UINT16 mMarkedUserVariableCount = 0;
+
+EFI_GUID mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
+CHAR16 mVarStoreName[] = L"VariableCleanup";
+
+HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ VARIABLE_CLEANUP_HII_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+ (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+ }
+ }
+};
+
+/**
+ Internal get variable error flag.
+
+ @return Variable error flag.
+
+**/
+VAR_ERROR_FLAG
+InternalGetVarErrorFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ VAR_ERROR_FLAG ErrorFlag;
+
+ Size = sizeof (ErrorFlag);
+ Status = gRT->GetVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ NULL,
+ &Size,
+ &ErrorFlag
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));
+ return VAR_ERROR_FLAG_NO_ERROR;
+ }
+ return ErrorFlag;
+}
+
+/**
+ Is user variable?
+
+ @param[in] Name Pointer to variable name.
+ @param[in] Guid Pointer to vendor guid.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ if (mVarCheck == NULL) {
+ gBS->LocateProtocol (
+ &gEdkiiVarCheckProtocolGuid,
+ NULL,
+ (VOID **) &mVarCheck
+ );
+ }
+ ASSERT (mVarCheck != NULL);
+
+ ZeroMem (&Property, sizeof (Property));
+ Status = mVarCheck->VariablePropertyGet (
+ Name,
+ Guid,
+ &Property
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No property, it is user variable.
+ //
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
+ return TRUE;
+ }
+
+// DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
+// DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));
+// DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));
+// DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));
+// DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));
+// DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));
+
+ return FALSE;
+}
+
+/**
+ Find user variable node by variable GUID.
+
+ @param[in] Guid Pointer to vendor guid.
+
+ @return Pointer to user variable node.
+
+**/
+USER_VARIABLE_NODE *
+FindUserVariableNodeByGuid (
+ IN EFI_GUID *Guid
+ )
+{
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ if (CompareGuid (Guid, &UserVariableNode->Guid)) {
+ //
+ // Found it.
+ //
+ return UserVariableNode;
+ }
+ }
+
+ //
+ // Create new one if not found.
+ //
+ UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
+ ASSERT (UserVariableNode != NULL);
+ UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
+ CopyGuid (&UserVariableNode->Guid, Guid);
+ //
+ // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
+ //
+ UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
+ ASSERT (UserVariableNode->PromptString != NULL);
+ UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
+ InitializeListHead (&UserVariableNode->NameLink);
+ InsertTailList (&mUserVariableList, &UserVariableNode->Link);
+ return UserVariableNode;
+}
+
+/**
+ Create user variable node.
+
+**/
+VOID
+CreateUserVariableNode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS GetVariableStatus;
+ CHAR16 *VarName;
+ UINTN MaxVarNameSize;
+ UINTN VarNameSize;
+ UINTN MaxDataSize;
+ UINTN DataSize;
+ VOID *Data;
+ UINT32 Attributes;
+ EFI_GUID Guid;
+ USER_VARIABLE_NODE *UserVariableNode;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ UINT16 Index;
+ UINTN StringSize;
+
+ //
+ // Initialize 128 * sizeof (CHAR16) variable name size.
+ //
+ MaxVarNameSize = 128 * sizeof (CHAR16);
+ VarName = AllocateZeroPool (MaxVarNameSize);
+ ASSERT (VarName != NULL);
+
+ //
+ // Initialize 0x1000 variable data size.
+ //
+ MaxDataSize = 0x1000;
+ Data = AllocateZeroPool (MaxDataSize);
+ ASSERT (Data != NULL);
+
+ Index = 0;
+ do {
+ VarNameSize = MaxVarNameSize;
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
+ ASSERT (VarName != NULL);
+ MaxVarNameSize = VarNameSize;
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (IsUserVariable (VarName, &Guid)) {
+ DataSize = MaxDataSize;
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
+ if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
+ Data = ReallocatePool (MaxDataSize, DataSize, Data);
+ ASSERT (Data != NULL);
+ MaxDataSize = DataSize;
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
+ }
+ ASSERT_EFI_ERROR (GetVariableStatus);
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ UserVariableNode = FindUserVariableNodeByGuid (&Guid);
+ ASSERT (UserVariableNode != NULL);
+
+ //
+ // Different variables that have same variable GUID share same user variable node.
+ //
+ UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
+ ASSERT (UserVariableNameNode != NULL);
+ UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
+ UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
+ UserVariableNameNode->Attributes = Attributes;
+ UserVariableNameNode->DataSize = DataSize;
+ UserVariableNameNode->Index = Index;
+ UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
+ //
+ // 2 space * sizeof (CHAR16) + StrSize.
+ //
+ StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
+ UserVariableNameNode->PromptString = AllocatePool (StringSize);
+ ASSERT (UserVariableNameNode->PromptString != NULL);
+ UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L" %s", UserVariableNameNode->Name);
+ //
+ // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
+ //
+ StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
+ UserVariableNameNode->HelpString = AllocatePool (StringSize);
+ ASSERT (UserVariableNameNode->HelpString != NULL);
+ UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
+ UserVariableNameNode->Deleted = FALSE;
+ InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
+ Index++;
+ }
+ }
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ mUserVariableCount = Index;
+ ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
+
+ FreePool (VarName);
+ FreePool (Data);
+}
+
+/**
+ Destroy user variable nodes.
+
+**/
+VOID
+DestroyUserVariableNode (
+ VOID
+ )
+{
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+
+ while (mUserVariableList.ForwardLink != &mUserVariableList) {
+ Link = mUserVariableList.ForwardLink;
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ RemoveEntryList (&UserVariableNode->Link);
+
+ while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
+ NameLink = UserVariableNode->NameLink.ForwardLink;
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ RemoveEntryList (&UserVariableNameNode->Link);
+
+ FreePool (UserVariableNameNode->Name);
+ FreePool (UserVariableNameNode->PromptString);
+ FreePool (UserVariableNameNode->HelpString);
+ FreePool (UserVariableNameNode);
+ }
+
+ FreePool (UserVariableNode->PromptString);
+ FreePool (UserVariableNode);
+ }
+}
+
+/**
+ Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
+ descriptor with the input data. NO authentication is required in this function.
+
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.
+ On output, the size of data returned in Data
+ buffer in bytes.
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or
+ pointer to NULL to wrap an empty payload.
+ On output, Pointer to the new payload date buffer allocated from pool,
+ it's caller's responsibility to free the memory after using it.
+
+ @retval EFI_SUCCESS Create time based payload successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval Others Unexpected error happens.
+
+**/
+EFI_STATUS
+CreateTimeBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
+ UINTN DescriptorSize;
+ EFI_TIME Time;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At user physical presence, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
+
+ ZeroMem (&Time, sizeof (EFI_TIME));
+ Status = gRT->GetTime (&Time, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewData);
+ return Status;
+ }
+ Time.Pad1 = 0;
+ Time.Nanosecond = 0;
+ Time.TimeZone = 0;
+ Time.Daylight = 0;
+ Time.Pad2 = 0;
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
+
+ if (Payload != NULL) {
+ FreePool (Payload);
+ }
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
+ descriptor with the input data. NO authentication is required in this function.
+
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.
+ On output, the size of data returned in Data
+ buffer in bytes.
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or
+ pointer to NULL to wrap an empty payload.
+ On output, Pointer to the new payload date buffer allocated from pool,
+ it's caller's responsibility to free the memory after using it.
+
+ @retval EFI_SUCCESS Create counter based payload successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval Others Unexpected error happens.
+
+**/
+EFI_STATUS
+CreateCounterBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION *DescriptorData;
+ UINTN DescriptorSize;
+ UINT64 MonotonicCount;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At user physical presence, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
+ sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
+
+ Status = gBS->GetNextMonotonicCount (&MonotonicCount);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewData);
+ return Status;
+ }
+ DescriptorData->MonotonicCount = MonotonicCount;
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
+
+ if (Payload != NULL) {
+ FreePool (Payload);
+ }
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete user variable.
+
+ @param[in] DeleteAll Delete all user variables.
+ @param[in] VariableCleanupData Pointer to variable cleanup data.
+
+**/
+VOID
+DeleteUserVariable (
+ IN BOOLEAN DeleteAll,
+ IN VARIABLE_CLEANUP_DATA *VariableCleanupData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+ UINTN DataSize;
+ UINT8 *Data;
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ for (NameLink = UserVariableNode->NameLink.ForwardLink
+ ;NameLink != &UserVariableNode->NameLink
+ ;NameLink = NameLink->ForwardLink) {
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
+ if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ DataSize = 0;
+ Data = NULL;
+ Status = CreateTimeBasedPayload (&DataSize, &Data);
+ if (!EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
+ FreePool (Data);
+ }
+ } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ DataSize = 0;
+ Data = NULL;
+ Status = CreateCounterBasedPayload (&DataSize, &Data);
+ if (!EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
+ FreePool (Data);
+ }
+ } else {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
+ }
+ if (!EFI_ERROR (Status)) {
+ UserVariableNameNode->Deleted = TRUE;
+ } else {
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
+ }
+ }
+ }
+ }
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in <ConfigRequest> format.
+ @param[out] 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[out] 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
+VariableCleanupHiiExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+ 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, &mVariableCleanupHiiGuid, mVarStoreName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
+ //
+ BufferSize = sizeof (VARIABLE_CLEANUP_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 (
+ &mVariableCleanupHiiGuid,
+ mVarStoreName,
+ Private->DriverHandle
+ );
+ 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 = Private->ConfigRouting->BlockToConfig (
+ Private->ConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Private->VariableCleanupData,
+ BufferSize,
+ Results,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+ //
+ // Set Progress string to the original request string or the string's null terminator.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ Update user variable form.
+
+ @param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
+
+**/
+VOID
+UpdateUserVariableForm (
+ IN VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private
+ )
+{
+ EFI_STRING_ID PromptStringToken;
+ EFI_STRING_ID HelpStringToken;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+ BOOLEAN Created;
+
+ //
+ // Init OpCode Handle.
+ //
+ 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_START;
+
+ //
+ // 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;
+
+ HiiUpdateForm (
+ Private->HiiHandle,
+ &mVariableCleanupHiiGuid,
+ FORM_ID_VARIABLE_CLEANUP,
+ StartOpCodeHandle, // LABEL_START
+ EndOpCodeHandle // LABEL_END
+ );
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ //
+ // Create checkbox opcode for variables in the same variable GUID space.
+ //
+ Created = FALSE;
+ for (NameLink = UserVariableNode->NameLink.ForwardLink
+ ;NameLink != &UserVariableNode->NameLink
+ ;NameLink = NameLink->ForwardLink) {
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ if (!UserVariableNameNode->Deleted) {
+ if (!Created) {
+ //
+ // Create subtitle opcode for variable GUID.
+ //
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
+ Created = TRUE;
+ }
+
+ //
+ // Only create opcode for the non-deleted variables.
+ //
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
+ HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ UserVariableNameNode->QuestionId,
+ VARIABLE_CLEANUP_VARSTORE_ID,
+ (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
+ PromptStringToken,
+ HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
+ NULL
+ );
+ }
+ }
+ }
+
+ HiiCreateSubTitleOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 0
+ );
+
+ //
+ // Create the "Apply changes" and "Discard changes" tags.
+ //
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ SAVE_AND_EXIT_QUESTION_ID,
+ STRING_TOKEN (STR_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ NO_SAVE_AND_EXIT_QUESTION_ID,
+ STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+
+ HiiUpdateForm (
+ Private->HiiHandle,
+ &mVariableCleanupHiiGuid,
+ FORM_ID_VARIABLE_CLEANUP,
+ StartOpCodeHandle, // LABEL_START
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+/**
+ 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
+VariableCleanupHiiRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+
+ 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, &mVariableCleanupHiiGuid, mVarStoreName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+ //
+ // Get Buffer Storage data.
+ //
+ BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
+ //
+ Status = Private->ConfigRouting->ConfigToBlock (
+ Private->ConfigRouting,
+ Configuration,
+ (UINT8 *) &Private->VariableCleanupData,
+ &BufferSize,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DeleteUserVariable (FALSE, &Private->VariableCleanupData);
+ //
+ // For "F10" hotkey to refresh the form.
+ //
+// UpdateUserVariableForm (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called to provide results data to the driver.
+ This data consists of a unique key that is used to identify
+ which data is either being passed back or being asked for.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect. The format of the data tends to
+ vary based on the opcode that generated the callback.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] 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
+VariableCleanupHiiCallback (
+ 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
+ )
+{
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ VARIABLE_CLEANUP_DATA *VariableCleanupData;
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve uncommitted data from Form Browser.
+ //
+ VariableCleanupData = &Private->VariableCleanupData;
+ HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
+ if (Value->b){
+ //
+ // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
+ //
+ mMarkedUserVariableCount++;
+ ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
+ if (mMarkedUserVariableCount == mUserVariableCount) {
+ //
+ // All user variables have been marked, then also mark the SelectAll checkbox.
+ //
+ VariableCleanupData->SelectAll = TRUE;
+ }
+ } else {
+ //
+ // Means one user variable checkbox is unmarked.
+ //
+ mMarkedUserVariableCount--;
+ //
+ // Also unmark the SelectAll checkbox.
+ //
+ VariableCleanupData->SelectAll = FALSE;
+ }
+ } else {
+ switch (QuestionId) {
+ case SELECT_ALL_QUESTION_ID:
+ if (Value->b){
+ //
+ // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
+ //
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
+ mMarkedUserVariableCount = mUserVariableCount;
+ } else {
+ //
+ // Means the SelectAll checkbox is unmarked.
+ //
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
+ mMarkedUserVariableCount = 0;
+ }
+ break;
+ case SAVE_AND_EXIT_QUESTION_ID:
+ DeleteUserVariable (FALSE, VariableCleanupData);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ case NO_SAVE_AND_EXIT_QUESTION_ID:
+ //
+ // Restore local maintain data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser.
+ //
+ HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
+ return EFI_SUCCESS;
+}
+
+/**
+ Platform variable cleanup.
+
+ @param[in] Flag Variable error flag.
+ @param[in] Type Variable cleanup type.
+ If it is VarCleanupManually, the interface must be called after console connected.
+
+ @retval EFI_SUCCESS No error or error processed.
+ @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
+ For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
+ Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
+ @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanup (
+ IN VAR_ERROR_FLAG Flag,
+ IN VAR_CLEANUP_TYPE Type
+ )
+{
+ EFI_STATUS Status;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+
+ if (!mEndOfDxe) {
+ //
+ // This implementation must be called after EndOfDxe.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
+ //
+ // Just return success if no error.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
+ //
+ // This sample does not support system variables cleanup.
+ //
+ DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
+ DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Continue to process VAR_ERROR_FLAG_USER_ERROR.
+ //
+
+ //
+ // Create user variable nodes for the following processing.
+ //
+ CreateUserVariableNode ();
+
+ switch (Type) {
+ case VarCleanupAll:
+ DeleteUserVariable (TRUE, NULL);
+ //
+ // Destroyed the created user variable nodes
+ //
+ DestroyUserVariableNode ();
+ return EFI_SUCCESS;
+ break;
+
+ case VarCleanupManually:
+ //
+ // Locate FormBrowser2 protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
+ Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
+ Private->ConfigAccess.RouteConfig = VariableCleanupHiiRouteConfig;
+ Private->ConfigAccess.Callback = VariableCleanupHiiCallback;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **) &Private->ConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVarCleanupHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &Private->ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Publish our HII data.
+ //
+ Private->HiiHandle = HiiAddPackages (
+ &mVariableCleanupHiiGuid,
+ Private->DriverHandle,
+ PlatformVarCleanupLibStrings,
+ PlatVarCleanupBin,
+ NULL
+ );
+ if (Private->HiiHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ UpdateUserVariableForm (Private);
+
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ &Private->HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+Done:
+ if (Private->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Private->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVarCleanupHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &Private->ConfigAccess,
+ NULL
+ );
+ }
+ if (Private->HiiHandle != NULL) {
+ HiiRemovePackages (Private->HiiHandle);
+ }
+
+ FreePool (Private);
+
+ //
+ // Destroyed the created user variable nodes
+ //
+ DestroyUserVariableNode ();
+ return Status;
+}
+
+/**
+ Get last boot variable error flag.
+
+ @return Last boot variable error flag.
+
+**/
+VAR_ERROR_FLAG
+EFIAPI
+GetLastBootVarErrorFlag (
+ VOID
+ )
+{
+ return mLastVarErrorFlag;
+}
+
+/**
+ Notification function of END_OF_DXE.
+
+ This is a notification function registered on END_OF_DXE event.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+PlatformVarCleanupEndOfDxeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
+
+/**
+ The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
+
+ The constructor function locates VarCheck protocol from protocol database.
+ 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 always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanupLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mLastVarErrorFlag = InternalGetVarErrorFlag ();
+ DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
+
+ //
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PlatformVarCleanupEndOfDxeEvent,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &mPlatVarCleanupLibEndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the End of DXE event.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanupLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the End of DXE event.
+ //
+ Status = gBS->CloseEvent (mPlatVarCleanupLibEndOfDxeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
new file mode 100644
index 000000000..8d5db826a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
@@ -0,0 +1,65 @@
+## @file
+# Sample platform variable cleanup library instance.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformVarCleanupLib
+ MODULE_UNI_FILE = PlatformVarCleanupLib.uni
+ FILE_GUID = 9C9623EB-4EF3-44e0-A931-F3A340D1A0F9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformVarCleanupLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = PlatformVarCleanupLibConstructor
+ DESTRUCTOR = PlatformVarCleanupLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ PlatVarCleanupLib.c
+ PlatVarCleanup.h
+ PlatVarCleanupHii.h
+ PlatVarCleanup.vfr
+ VfrStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PrintLib
+ MemoryAllocationLib
+ HiiLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## GUID
+ gEdkiiVarErrorFlagGuid ## CONSUMES ## Variable:L"VarErrorFlag"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID
+ gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEdkiiVarCheckProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiHiiConfigRoutingProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiVariableArchProtocolGuid
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
new file mode 100644
index 000000000..a7563e9b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL class library to register var check HII handler.
+//
+// NULL class library to register var check HII handler.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL class library to register var check HII handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL class library to register var check HII handler."
+
diff --git a/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
new file mode 100644
index 000000000..b98788d7f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
@@ -0,0 +1,29 @@
+///** @file
+// String definitions for platform variable cleanup.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_ENTRY_TITLE #language en-US "Platform Variable Cleanup Form"
+ #language fr-FR "fr-FR: Platform Variable Cleanup Form"
+#string STR_TITLE #language en-US "Platform Variable Cleanup"
+ #language fr-FR "fr-FR: Platform Variable Cleanup"
+#string STR_TITLE_HELP #language en-US "Select and cleanup variables"
+ #language fr-FR "fr-FR: Select and cleanup variables"
+#string STR_SELECT_ALL_PROMPT #language en-US "Select all"
+ #language fr-FR "fr-FR: Select all"
+#string STR_SELECT_ALL_HELP #language en-US "Select all, then all the listed user variables below will be deleted when Commit or Save."
+ #language fr-FR "fr-FR: Select all, then all the listed user variables below will be deleted when Commit or Save."
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_SAVE_AND_EXIT #language en-US "Commit Changes and Exit"
+ #language fr-FR "fr-FR: Commit Changes and Exit"
+#string STR_NO_SAVE_AND_EXIT #language en-US "Discard Changes and Exit"
+ #language fr-FR "fr-FR: Discard Changes and Exit"
diff --git a/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtility.c b/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtility.c
new file mode 100644
index 000000000..bb151d033
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtility.c
@@ -0,0 +1,252 @@
+/** @file
+ This contains the business logic for the module-specific Reset Helper functions.
+
+ Copyright (c) 2017 - 2019 Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 Microsoft Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ResetSystemLib.h>
+
+#pragma pack(1)
+typedef struct {
+ CHAR16 NullTerminator;
+ GUID ResetSubtype;
+} RESET_UTILITY_GUID_SPECIFIC_RESET_DATA;
+#pragma pack()
+
+STATIC_ASSERT (
+ sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) == 18,
+ "sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) is expected to be 18 bytes"
+ );
+
+/**
+ This is a shorthand helper function to reset with reset type and a subtype
+ so that the caller doesn't have to bother with a function that has half
+ a dozen parameters.
+
+ This will generate a reset with status EFI_SUCCESS, a NULL string, and
+ no custom data. The subtype will be formatted in such a way that it can be
+ picked up by notification registrations and custom handlers.
+
+ NOTE: This call will fail if the architectural ResetSystem underpinnings
+ are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
+ to your DEPEX.
+
+ @param[in] ResetType The default EFI_RESET_TYPE of the reset.
+ @param[in] ResetSubtype GUID pointer for the reset subtype to be used.
+
+**/
+VOID
+EFIAPI
+ResetSystemWithSubtype (
+ IN EFI_RESET_TYPE ResetType,
+ IN CONST GUID *ResetSubtype
+ )
+{
+ RESET_UTILITY_GUID_SPECIFIC_RESET_DATA ResetData;
+
+ ResetData.NullTerminator = CHAR_NULL;
+ CopyGuid (
+ (GUID *)((UINT8 *)&ResetData + OFFSET_OF (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA, ResetSubtype)),
+ ResetSubtype
+ );
+
+ ResetSystem (ResetType, EFI_SUCCESS, sizeof (ResetData), &ResetData);
+}
+
+/**
+ This is a shorthand helper function to reset with the reset type
+ 'EfiResetPlatformSpecific' and a subtype so that the caller doesn't
+ have to bother with a function that has half a dozen parameters.
+
+ This will generate a reset with status EFI_SUCCESS, a NULL string, and
+ no custom data. The subtype will be formatted in such a way that it can be
+ picked up by notification registrations and custom handlers.
+
+ NOTE: This call will fail if the architectural ResetSystem underpinnings
+ are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
+ to your DEPEX.
+
+ @param[in] ResetSubtype GUID pointer for the reset subtype to be used.
+
+**/
+VOID
+EFIAPI
+ResetPlatformSpecificGuid (
+ IN CONST GUID *ResetSubtype
+ )
+{
+ ResetSystemWithSubtype (EfiResetPlatformSpecific, ResetSubtype);
+}
+
+/**
+ This function examines the DataSize and ResetData parameters passed to
+ to ResetSystem() and detemrines if the ResetData contains a Null-terminated
+ Unicode string followed by a GUID specific subtype. If the GUID specific
+ subtype is present, then a pointer to the GUID value in ResetData is returned.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData Pointer to the data buffer passed into ResetSystem().
+
+ @retval Pointer Pointer to the GUID value in ResetData.
+ @retval NULL ResetData is NULL.
+ @retval NULL ResetData does not start with a Null-terminated
+ Unicode string.
+ @retval NULL A Null-terminated Unicode string is present, but there
+ are less than sizeof (GUID) bytes after the string.
+ @retval NULL No subtype is found.
+
+**/
+GUID *
+EFIAPI
+GetResetPlatformSpecificGuid (
+ IN UINTN DataSize,
+ IN CONST VOID *ResetData
+ )
+{
+ UINTN ResetDataStringSize;
+ GUID *ResetSubtypeGuid;
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((ResetData == NULL) || (DataSize < sizeof (GUID))) {
+ return NULL;
+ }
+
+ //
+ // Determine the number of bytes in the Null-terminated Unicode string
+ // at the beginning of ResetData including the Null terminator.
+ //
+ ResetDataStringSize = StrnSizeS (ResetData, (DataSize / sizeof (CHAR16)));
+
+ //
+ // Now, assuming that we have enough data for a GUID after the string, the
+ // GUID should be immediately after the string itself.
+ //
+ if ((ResetDataStringSize < DataSize) && (DataSize - ResetDataStringSize) >= sizeof (GUID)) {
+ ResetSubtypeGuid = (GUID *)((UINT8 *)ResetData + ResetDataStringSize);
+ DEBUG ((DEBUG_VERBOSE, "%a - Detected reset subtype %g...\n", __FUNCTION__, ResetSubtypeGuid));
+ return ResetSubtypeGuid;
+ }
+ return NULL;
+}
+
+/**
+ This is a helper function that creates the reset data buffer that can be
+ passed into ResetSystem().
+
+ The reset data buffer is returned in ResetData and contains ResetString
+ followed by the ResetSubtype GUID followed by the ExtraData.
+
+ NOTE: Strings are internally limited by MAX_UINT16.
+
+ @param[in, out] ResetDataSize On input, the size of the ResetData buffer. On
+ output, either the total number of bytes
+ copied, or the required buffer size.
+ @param[in, out] ResetData A pointer to the buffer in which to place the
+ final structure.
+ @param[in] ResetSubtype Pointer to the GUID specific subtype. This
+ parameter is optional and may be NULL.
+ @param[in] ResetString Pointer to a Null-terminated Unicode string
+ that describes the reset. This parameter is
+ optional and may be NULL.
+ @param[in] ExtraDataSize The size, in bytes, of ExtraData buffer.
+ @param[in] ExtraData Pointer to a buffer of extra data. This
+ parameter is optional and may be NULL.
+
+ @retval RETURN_SUCCESS ResetDataSize and ResetData are updated.
+ @retval RETURN_INVALID_PARAMETER ResetDataSize is NULL.
+ @retval RETURN_INVALID_PARAMETER ResetData is NULL.
+ @retval RETURN_INVALID_PARAMETER ExtraData was provided without a
+ ResetSubtype. This is not supported by the
+ UEFI spec.
+ @retval RETURN_BUFFER_TOO_SMALL An insufficient buffer was provided.
+ ResetDataSize is updated with minimum size
+ required.
+**/
+RETURN_STATUS
+EFIAPI
+BuildResetData (
+ IN OUT UINTN *ResetDataSize,
+ IN OUT VOID *ResetData,
+ IN CONST GUID *ResetSubtype OPTIONAL,
+ IN CONST CHAR16 *ResetString OPTIONAL,
+ IN UINTN ExtraDataSize OPTIONAL,
+ IN CONST VOID *ExtraData OPTIONAL
+ )
+{
+ UINTN ResetStringSize;
+ UINTN ResetDataBufferSize;
+ UINT8 *Data;
+
+ //
+ // If the size return pointer is NULL.
+ //
+ if (ResetDataSize == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // If extra data is indicated, but pointer is NULL.
+ //
+ if (ExtraDataSize > 0 && ExtraData == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // If extra data is indicated, but no subtype GUID is supplied.
+ //
+ if (ResetSubtype == NULL && ExtraDataSize > 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Determine the final string.
+ //
+ if (ResetString == NULL) {
+ ResetString = L""; // Use an empty string.
+ }
+
+ //
+ // Calculate the total buffer required for ResetData.
+ //
+ ResetStringSize = StrnSizeS (ResetString, MAX_UINT16);
+ ResetDataBufferSize = ResetStringSize + ExtraDataSize;
+ if (ResetSubtype != NULL) {
+ ResetDataBufferSize += sizeof (GUID);
+ }
+
+ //
+ // At this point, if the buffer isn't large enough (or if
+ // the buffer is NULL) we cannot proceed.
+ //
+ if (*ResetDataSize < ResetDataBufferSize) {
+ *ResetDataSize = ResetDataBufferSize;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *ResetDataSize = ResetDataBufferSize;
+ if (ResetData == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Fill in ResetData with ResetString, the ResetSubtype GUID, and extra data
+ //
+ Data = (UINT8 *)ResetData;
+ CopyMem (Data, ResetString, ResetStringSize);
+ Data += ResetStringSize;
+ if (ResetSubtype != NULL) {
+ CopyMem (Data, ResetSubtype, sizeof (GUID));
+ Data += sizeof (GUID);
+ }
+ if (ExtraDataSize > 0) {
+ CopyMem (Data, ExtraData, ExtraDataSize);
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtilityLib.inf b/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtilityLib.inf
new file mode 100644
index 000000000..4e17a0f1e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/ResetUtilityLib/ResetUtilityLib.inf
@@ -0,0 +1,34 @@
+## @file
+# This file contains the Reset Utility functions.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = ResetUtilityLib
+ FILE_GUID = CAFC3CA1-3E32-449F-9B0E-40BA3CB73A12
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = ResetUtilityLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ResetUtility.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ResetSystemLib
diff --git a/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 000000000..dc7fcf7a2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,752 @@
+/** @file
+ API implementation for instance of Report Status Code Library.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/StatusCode.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/EventGroup.h>
+
+
+//
+// Define the maximum extended data size that is supported when a status code is reported.
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+EFI_STATUS_CODE_PROTOCOL *mReportStatusCodeLibStatusCodeProtocol = NULL;
+EFI_EVENT mReportStatusCodeLibVirtualAddressChangeEvent;
+EFI_EVENT mReportStatusCodeLibExitBootServicesEvent;
+BOOLEAN mHaveExitedBootServices = FALSE;
+
+/**
+ Locate the report status code service.
+
+ Retrieve ReportStatusCode() API of Report Status Code Protocol.
+
+**/
+VOID
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mReportStatusCodeLibStatusCodeProtocol != NULL) {
+ return;
+ }
+
+ if (mHaveExitedBootServices) {
+ return;
+ }
+
+ //
+ // Check gBS just in case ReportStatusCode is called before gBS is initialized.
+ //
+ if (gBS != NULL && gBS->LocateProtocol != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**) &mReportStatusCodeLibStatusCodeProtocol);
+ if (EFI_ERROR (Status)) {
+ mReportStatusCodeLibStatusCodeProtocol = NULL;
+ }
+ }
+}
+
+/**
+ 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 (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return;
+ }
+ EfiConvertPointer (0, (VOID **) &mReportStatusCodeLibStatusCodeProtocol);
+}
+
+/**
+ 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
+ )
+{
+ //
+ // Locate the report status code service before enter runtime.
+ //
+ InternalGetReportStatusCode ();
+
+ mHaveExitedBootServices = TRUE;
+}
+
+/**
+ The constructor function of 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
+ReportStatusCodeLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Cache the report status code service
+ //
+ InternalGetReportStatusCode ();
+
+ //
+ // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibVirtualAddressChange,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mReportStatusCodeLibVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function for EVT_SIGNAL_EXIT_BOOT_SERVICES
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mReportStatusCodeLibExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function of 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
+ReportStatusCodeLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (gBS != NULL);
+ Status = gBS->CloseEvent (mReportStatusCodeLibVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseEvent (mReportStatusCodeLibExitBootServicesEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal worker function that reports a status code through the Report Status Code Protocol.
+
+ If status code service is not cached, then this function checks if Report Status Code
+ Protocol is available in system. If Report Status Code Protocol is not available, then
+ EFI_UNSUPPORTED is returned. If Report Status Code Protocol is present, then it is
+ cached in mReportStatusCodeLibStatusCodeProtocol. Finally this function reports status
+ code through the Report Status Code Protocol.
+
+ @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 Report Status Code Protocol 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 mReportStatusCodeLibStatusCodeProtocol is NULL, then check if Report Status Code Protocol is available in system.
+ //
+ InternalGetReportStatusCode ();
+ if (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // A Report Status Code Protocol is present in system, so pass in all the parameters to the service.
+ //
+ return mReportStatusCodeLibStatusCodeProtocol->ReportStatusCode (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;
+ UINT64 StatusCodeBuffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (ExtendedDataSize <= (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {
+ //
+ // Use Buffer instead of allocating if possible.
+ //
+ StatusCodeData = (EFI_STATUS_CODE_DATA *) StatusCodeBuffer;
+ } else {
+ if (mHaveExitedBootServices) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gBS == NULL || gBS->AllocatePool == NULL || gBS->FreePool == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ StatusCodeData = NULL;
+ gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize, (VOID **)&StatusCodeData);
+ if (StatusCodeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // 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 *) StatusCodeBuffer) {
+ 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/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
new file mode 100644
index 000000000..b99747aad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
@@ -0,0 +1,54 @@
+## @file
+# Report status code library instance which supports logging message in DXE & runtime phase.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RuntimeDxeReportStatusCodeLib
+ MODULE_UNI_FILE = RuntimeDxeReportStatusCodeLib.uni
+ FILE_GUID = 07D25BBB-F832-41bb-BBA0-612E9F033067
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_RUNTIME_DRIVER
+ CONSTRUCTOR = ReportStatusCodeLibConstructor
+ DESTRUCTOR = ReportStatusCodeLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ PcdLib
+ DevicePathLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni
new file mode 100644
index 000000000..dafa97b45
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Report status code library instance which supports logging message in DXE & runtime phase.
+//
+// Report status code library instance that supports logging message in DXE & runtime phase.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Supports logging message in DXE & runtime phases"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Report status code library instance that supports logging message in DXE & runtime phase."
+
diff --git a/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c
new file mode 100644
index 000000000..f4490180c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c
@@ -0,0 +1,195 @@
+/** @file
+ DXE Reset System Library instance that calls gRT->ResetSystem().
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+EFI_EVENT mRuntimeResetSystemLibVirtualAddressChangeEvent;
+EFI_RUNTIME_SERVICES *mInternalRT;
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ )
+{
+ mInternalRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ )
+{
+ mInternalRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ )
+{
+ mInternalRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+}
+
+/**
+ This function causes a systemwide reset. The exact type of the reset is
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+ the platform must pick a supported reset type to perform.The platform may
+ optionally log the parameters from any non-normal reset that occurs.
+
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData The data buffer starts with a Null-terminated string,
+ followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+ IN UINTN DataSize,
+ IN VOID *ResetData
+ )
+{
+ mInternalRT->ResetSystem (EfiResetPlatformSpecific, EFI_SUCCESS, DataSize, ResetData);
+}
+
+/**
+ The ResetSystem function resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+ the data buffer starts with a Null-terminated string, optionally
+ followed by additional binary data. The string is a description
+ that the caller may use to further indicate the reason for the
+ system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ mInternalRT->ResetSystem (ResetType, ResetStatus, DataSize, ResetData);
+}
+
+/**
+ 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
+RuntimeResetSystemLibVirtualAddressChange (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mInternalRT->ConvertPointer (0, (VOID **) &mInternalRT);
+}
+
+/**
+ The constructor function of Runtime Reset System 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
+RuntimeResetSystemLibConstruct (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Library should not use the gRT directly, for it may be converted by other library instance.
+ //
+ mInternalRT = gRT;
+
+ //
+ // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ RuntimeResetSystemLibVirtualAddressChange,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mRuntimeResetSystemLibVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The Deconstructor function of Runtime Reset System 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
+RuntimeResetSystemLibDeconstruct (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (gBS != NULL);
+ Status = gBS->CloseEvent (mRuntimeResetSystemLibVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.inf b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.inf
new file mode 100644
index 000000000..9d94a8016
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.inf
@@ -0,0 +1,45 @@
+## @file
+# Runtime Reset System Library instance that calls gRT->ResetSystem().
+#
+# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RuntimeResetSystemLib
+ MODULE_UNI_FILE = RuntimeResetSystemLib.uni
+ FILE_GUID = DD5D0821-F343-4C85-9CD9-54B3C1A19CEA
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ResetSystemLib|DXE_RUNTIME_DRIVER
+
+ CONSTRUCTOR = RuntimeResetSystemLibConstruct
+ DESTRUCTOR = RuntimeResetSystemLibDeconstruct
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ RuntimeResetSystemLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+
+[Depex]
+ gEfiResetArchProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.uni b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.uni
new file mode 100644
index 000000000..41b3da0d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Runtime Reset System Library instance that calls gRT->ResetSystem().
+//
+// Runtime Reset System Library instance that calls gRT->ResetSystem().
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Runtime Reset System Library instance that calls gRT->ResetSystem()"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Runtime Reset System Library instance that calls gRT->ResetSystem()."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
new file mode 100644
index 000000000..b4f22c14a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
@@ -0,0 +1,1326 @@
+/** @file
+ Performance library instance used by SMM Core.
+
+ This library provides the performance measurement interfaces and initializes performance
+ logging for the SMM phase.
+ It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
+ which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
+
+ This library is mainly used by SMM Core to start performance logging to ensure that
+ SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - performance data and communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "SmmCorePerformanceLibInternal.h"
+
+#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
+#define FIRMWARE_RECORD_BUFFER 0x1000
+#define CACHE_HANDLE_GUID_COUNT 0x100
+
+SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ EFI_GUID ModuleGuid;
+} HANDLE_GUID_MAP;
+
+HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
+UINTN mCachePairCount = 0;
+
+UINT32 mPerformanceLength = sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+UINT32 mMaxPerformanceLength = 0;
+UINT32 mLoadImageCount = 0;
+BOOLEAN mFpdtDataIsReported = FALSE;
+BOOLEAN mLackSpaceIsReport = FALSE;
+CHAR8 *mPlatformLanguage = NULL;
+SPIN_LOCK mSmmFpdtLock;
+PERFORMANCE_PROPERTY mPerformanceProperty;
+UINT32 mCachedLength = 0;
+
+//
+// Interfaces for SMM PerformanceMeasurement Protocol.
+//
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
+ CreatePerformanceMeasurement,
+};
+
+/**
+ Return the pointer to the FPDT record in the allocated memory.
+
+ @param RecordSize The size of FPDT record.
+ @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
+
+ @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
+ @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+ IN UINT8 RecordSize,
+ IN OUT FPDT_RECORD_PTR *FpdtRecordPtr
+)
+{
+ if (mFpdtDataIsReported) {
+ //
+ // Append Boot records after Smm boot performance records have been reported.
+ //
+ if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+ if (!mLackSpaceIsReport) {
+ DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));
+ mLackSpaceIsReport = TRUE;
+ }
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Covert buffer to FPDT Ptr Union type.
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+ }
+ } else {
+ //
+ // Check if pre-allocated buffer is full
+ //
+ if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+ mSmmBootPerformanceTable = ReallocatePool (
+ mPerformanceLength,
+ mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
+ mSmmBootPerformanceTable
+ );
+
+ if (mSmmBootPerformanceTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mSmmBootPerformanceTable->Header.Length = mPerformanceLength;
+ mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
+ }
+ //
+ // Covert buffer to FPDT Ptr Union type.
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+ }
+ FpdtRecordPtr->RecordHeader->Length = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+Check whether the Token is a known one which is uesed by core.
+
+@param Token Pointer to a Null-terminated ASCII string
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownTokens (
+ IN CONST CHAR8 *Token
+ )
+{
+ if (Token == NULL) {
+ return FALSE;
+ }
+
+ if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
+ AsciiStrCmp (Token, PEI_TOK) == 0 ||
+ AsciiStrCmp (Token, DXE_TOK) == 0 ||
+ AsciiStrCmp (Token, BDS_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
+ AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
+ AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
+ AsciiStrCmp (Token, PEIM_TOK) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+Check whether the ID is a known one which map to the known Token.
+
+@param Identifier 32-bit identifier.
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownID (
+ IN UINT32 Identifier
+ )
+{
+ if (Identifier == MODULE_START_ID ||
+ Identifier == MODULE_END_ID ||
+ Identifier == MODULE_LOADIMAGE_START_ID ||
+ Identifier == MODULE_LOADIMAGE_END_ID ||
+ Identifier == MODULE_DB_START_ID ||
+ Identifier == MODULE_DB_END_ID ||
+ Identifier == MODULE_DB_SUPPORT_START_ID ||
+ Identifier == MODULE_DB_SUPPORT_END_ID ||
+ Identifier == MODULE_DB_STOP_START_ID ||
+ Identifier == MODULE_DB_STOP_END_ID) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get the FPDT record identifier.
+
+ @param Attribute The attribute of the Record.
+ PerfStartEntry: Start Record.
+ PerfEndEntry: End Record.
+ @param Handle Pointer to environment specific context used to identify the component being measured.
+ @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
+ @param ProgressID On return, pointer to the ProgressID.
+
+ @retval EFI_SUCCESS Get record info successfully.
+ @retval EFI_INVALID_PARAMETER No matched FPDT record.
+
+**/
+EFI_STATUS
+GetFpdtRecordId (
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute,
+ IN CONST VOID *Handle,
+ IN CONST CHAR8 *String,
+ OUT UINT16 *ProgressID
+ )
+{
+ //
+ // Token to Id.
+ //
+ if (String != NULL) {
+ if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_START_ID;
+ } else {
+ *ProgressID = MODULE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_LOADIMAGE_START_ID;
+ } else {
+ *ProgressID = MODULE_LOADIMAGE_END_ID;
+ }
+ } else { // Pref used in Modules
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ }
+ } else if (Handle != NULL) { // Pref used in Modules
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a human readable module name and module guid for the given image handle.
+ If module name can't be found, "" string will return.
+ If module guid can't be found, Zero Guid will return.
+
+ @param Handle Image handle or Controller handle.
+ @param NameString The ascii string will be filled into it. If not found, null string will return.
+ @param BufferSize Size of the input NameString buffer.
+ @param ModuleGuid Point to the guid buffer to store the got module guid value.
+
+ @retval EFI_SUCCESS Successfully get module name and guid.
+ @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
+ @retval other value Module Name can't be got.
+**/
+EFI_STATUS
+EFIAPI
+GetModuleInfoFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize,
+ OUT EFI_GUID *ModuleGuid OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ CHAR8 *PdbFileName;
+ EFI_GUID *TempGuid;
+ UINTN StartIndex;
+ UINTN Index;
+ INTN Count;
+ BOOLEAN ModuleGuidIsGet;
+ UINTN StringSize;
+ CHAR16 *StringPtr;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
+
+ if (NameString == NULL || BufferSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to get the ModuleGuid and name string form the caached array.
+ //
+ if (mCachePairCount > 0) {
+ for (Count = mCachePairCount - 1; Count >= 0; Count--) {
+ if (Handle == mCacheHandleGuidTable[Count].Handle) {
+ CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
+ AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ LoadedImage = NULL;
+ ModuleGuidIsGet = FALSE;
+
+ //
+ // Initialize GUID as zero value.
+ //
+ TempGuid = &gZeroGuid;
+ //
+ // Initialize it as "" string.
+ //
+ NameString[0] = 0;
+
+ if (Handle != NULL) {
+ //
+ // Try Handle as ImageHandle.
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**) &LoadedImage
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Try Handle as Controller Handle
+ //
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get Image protocol from ImageHandle
+ //
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**) &LoadedImage
+ );
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status) && LoadedImage != NULL) {
+ //
+ // Get Module Guid from DevicePath.
+ //
+ if (LoadedImage->FilePath != NULL &&
+ LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
+ LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
+ ) {
+ //
+ // Determine GUID associated with module logging performance
+ //
+ ModuleGuidIsGet = TRUE;
+ FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
+ TempGuid = &FvFilePath->FvFileName;
+ }
+
+ //
+ // Method 1 Get Module Name from PDB string.
+ //
+ PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
+ if (PdbFileName != NULL && BufferSize > 0) {
+ StartIndex = 0;
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string.
+ // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < BufferSize - 1; Index++) {
+ NameString[Index] = PdbFileName[Index + StartIndex];
+ if (NameString[Index] == 0 || NameString[Index] == '.') {
+ NameString[Index] = 0;
+ break;
+ }
+ }
+
+ if (Index == BufferSize - 1) {
+ NameString[Index] = 0;
+ }
+ //
+ // Module Name is got.
+ //
+ goto Done;
+ }
+ }
+
+ if (ModuleGuidIsGet) {
+ //
+ // Method 2 Try to get the image's FFS UI section by image GUID
+ //
+ StringPtr = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ TempGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &StringPtr,
+ &StringSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Method 3. Get the name string from FFS UI section
+ //
+ for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
+ NameString[Index] = (CHAR8) StringPtr[Index];
+ }
+ NameString[Index] = 0;
+ FreePool (StringPtr);
+ }
+ }
+
+Done:
+ //
+ // Copy Module Guid
+ //
+ if (ModuleGuid != NULL) {
+ CopyGuid (ModuleGuid, TempGuid);
+ if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
+ // Handle is GUID
+ CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
+ }
+ }
+
+ //
+ // Cache the Handle and Guid pairs.
+ //
+ if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
+ mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
+ CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
+ AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
+ mCachePairCount ++;
+ }
+
+ return Status;
+}
+
+/**
+ Copies the string from Source into Destination and updates Length with the
+ size of the string.
+
+ @param Destination - destination of the string copy
+ @param Source - pointer to the source string which will get copied
+ @param Length - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+ IN OUT CHAR8 *Destination,
+ IN CONST CHAR8 *Source,
+ IN OUT UINT8 *Length
+ )
+{
+ UINTN StringLen;
+ UINTN DestMax;
+
+ ASSERT (Source != NULL);
+
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ DestMax = STRING_SIZE;
+ } else {
+ DestMax = AsciiStrSize (Source);
+ if (DestMax > STRING_SIZE) {
+ DestMax = STRING_SIZE;
+ }
+ }
+ StringLen = AsciiStrLen (Source);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+ *Length += (UINT8)DestMax;
+
+ return;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param Ticker - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param PerfId - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+
+ @retval EFI_SUCCESS - Successfully created performance record
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+EFI_STATUS
+InsertFpdtRecord (
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Ticker,
+ IN UINT64 Address, OPTIONAL
+ IN UINT16 PerfId,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_GUID ModuleGuid;
+ CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ FPDT_RECORD_PTR FpdtRecordPtr;
+ FPDT_RECORD_PTR CachedFpdtRecordPtr;
+ UINT64 TimeStamp;
+ CONST CHAR8 *StringPtr;
+ UINTN DestMax;
+ UINTN StringLen;
+ UINT16 ProgressId;
+
+ StringPtr = NULL;
+ ZeroMem (ModuleName, sizeof (ModuleName));
+
+ //
+ // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
+ // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
+ //
+ if (Attribute != PerfEntry) {
+ //
+ // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
+ // !!! Note: If the Perf is not the known Token used in the core but have same
+ // ID with the core Token, this case will not be supported.
+ // And in currtnt usage mode, for the unkown ID, there is a general rule:
+ // If it is start pref: the lower 4 bits of the ID should be 0.
+ // If it is end pref: the lower 4 bits of the ID should not be 0.
+ // If input ID doesn't follow the rule, we will adjust it.
+ //
+ if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
+ PerfId &= 0xFFF0;
+ } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+ PerfId += 1;
+ }
+ }
+ if (PerfId == 0) {
+ //
+ // Get ProgressID form the String Token.
+ //
+ Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PerfId = ProgressId;
+ }
+ }
+
+ //
+ // 2. Get the buffer to store the FPDT record.
+ //
+ Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 3. Get the TimeStamp.
+ //
+ if (Ticker == 0) {
+ Ticker = GetPerformanceCounter ();
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ } else if (Ticker == 1) {
+ TimeStamp = 0;
+ } else {
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ }
+
+ //
+ // 4. Fill in the FPDT record according to different Performance Identifier.
+ //
+ switch (PerfId) {
+ case MODULE_START_ID:
+ case MODULE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ //
+ // Cache the offset of start image start record and use to update the start image end record if needed.
+ //
+ if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {
+ mCachedLength = mSmmBootPerformanceTable->Header.Length;
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
+ FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
+ FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+ break;
+
+ case MODULE_LOADIMAGE_START_ID:
+ case MODULE_LOADIMAGE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ if (PerfId == MODULE_LOADIMAGE_START_ID) {
+ mLoadImageCount++;
+ //
+ // Cache the offset of load image start record and use to be updated by the load image end record if needed.
+ //
+ if (CallerIdentifier == NULL && Attribute == PerfEntry) {
+ mCachedLength = mSmmBootPerformanceTable->Header.Length;
+ }
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+ FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
+ FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
+ CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
+ if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+ CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+ break;
+
+ case PERF_EVENTSIGNAL_START_ID:
+ case PERF_EVENTSIGNAL_END_ID:
+ case PERF_CALLBACK_START_ID:
+ case PERF_CALLBACK_END_ID:
+ if (String == NULL || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ StringPtr = String;
+ if (AsciiStrLen (String) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+ }
+ break;
+
+ case PERF_EVENT_ID:
+ case PERF_FUNCTION_START_ID:
+ case PERF_FUNCTION_END_ID:
+ case PERF_INMODULE_START_ID:
+ case PERF_INMODULE_END_ID:
+ case PERF_CROSSMODULE_START_ID:
+ case PERF_CROSSMODULE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (String != NULL) {
+ StringPtr = String;
+ } else {
+ StringPtr = ModuleName;
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ break;
+
+ default:
+ if (Attribute != PerfEntry) {
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (String != NULL) {
+ StringPtr = String;
+ } else {
+ StringPtr = ModuleName;
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ //
+ // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
+ //
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ if (StringPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ if (Guid != NULL) {
+ //
+ // Cache the event guid in string event record.
+ //
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ } else {
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ }
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+
+ if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
+ }
+ if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+ if (PerfId == MODULE_LOADIMAGE_END_ID) {
+ DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (StringPtr);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+ CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
+ } else if (PerfId == MODULE_END_ID) {
+ DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
+ }
+ mCachedLength = 0;
+ }
+ }
+
+ //
+ // 5. Update the length of the used buffer after fill in the record.
+ //
+ mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+ mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SmmReadyToBoot protocol notification event handler.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmReadyToBootCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReportFpdtRecordData (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ UINT64 SmmBPDTddr;
+
+ if (!mFpdtDataIsReported && mSmmBootPerformanceTable != NULL) {
+ SmmBPDTddr = (UINT64)(UINTN)mSmmBootPerformanceTable;
+ REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_SOFTWARE_SMM_DRIVER,
+ 0,
+ NULL,
+ &gEdkiiFpdtExtendedFirmwarePerformanceGuid,
+ &SmmBPDTddr,
+ sizeof (UINT64)
+ );
+ //
+ // Set FPDT report state to TRUE.
+ //
+ mFpdtDataIsReported = TRUE;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
+ this function is callbacked to initialize the Smm Performance Lib
+
+ @param Event The event of notify protocol.
+ @param Context Notify event context.
+
+**/
+VOID
+EFIAPI
+InitializeSmmCorePerformanceLib (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ VOID *SmmReadyToBootRegistration;
+ PERFORMANCE_PROPERTY *PerformanceProperty;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mSmmFpdtLock);
+
+ //
+ // Install the protocol interfaces for SMM performance library instance.
+ //
+ Handle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEdkiiSmmPerformanceMeasurementProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPerformanceMeasurementInterface
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmReadyToBootProtocolGuid,
+ SmmReportFpdtRecordData,
+ &SmmReadyToBootRegistration
+ );
+ Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
+ if (EFI_ERROR (Status)) {
+ //
+ // Install configuration table for performance property.
+ //
+ mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;
+ mPerformanceProperty.Reserved = 0;
+ mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
+ &mPerformanceProperty.TimerStartValue,
+ &mPerformanceProperty.TimerEndValue
+ );
+ Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ The constructor function initializes the Performance Measurement Enable flag and
+ registers SmmBase2 protocol notify callback.
+ It will ASSERT() if one of these operations 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
+SmmCorePerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ VOID *Registration;
+
+ if (!PerformanceMeasurementEnabled ()) {
+ //
+ // Do not initialize performance infrastructure if not required.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Create the events to do the library init.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InitializeSmmCorePerformanceLib,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiSmmBase2ProtocolGuid,
+ Event,
+ &Registration
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+**/
+EFI_STATUS
+EFIAPI
+CreatePerformanceMeasurement(
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 TimeStamp, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ AcquireSpinLock (&mSmmFpdtLock);
+ Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
+ ReleaseSpinLock (&mSmmFpdtLock);
+ return Status;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ !!! Not Support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ !!! Not Support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
new file mode 100644
index 000000000..6b013b855
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
@@ -0,0 +1,72 @@
+## @file
+# Performance library instance used by SMM Core.
+#
+# This library provides the performance measurement interfaces and initializes performance
+# logging for the SMM phase.
+# It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
+# which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
+# This library is mainly used by SMM Core to start performance logging to ensure that
+# SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCorePerformanceLib
+ MODULE_UNI_FILE = SmmCorePerformanceLib.uni
+ FILE_GUID = 36290D10-0F47-42c1-BBCE-E191C7928DCF
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = PerformanceLib|SMM_CORE
+
+ CONSTRUCTOR = SmmCorePerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCorePerformanceLib.c
+ SmmCorePerformanceLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ PcdLib
+ TimerLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ SynchronizationLib
+ SmmServicesTableLib
+ SmmMemLib
+ UefiLib
+ ReportStatusCodeLib
+ PeCoffGetEntryPointLib
+ DxeServicesLib
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## CONSUMES
+ gEdkiiSmmReadyToBootProtocolGuid ## NOTIFY
+
+[Guids]
+ ## PRODUCES ## SystemTable
+ gPerformanceProtocolGuid
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # StatusCode Data
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+ gEdkiiSmmPerformanceMeasurementProtocolGuid ## PRODUCES ## UNDEFINED # Install protocol
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni
new file mode 100644
index 000000000..bafefece4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Performance library instance used by SMM Core.
+//
+// This library provides the performance measurement interfaces and initializes performance
+// logging for the SMM phase.
+// It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
+// which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
+// This library is mainly used by SMM Core to start performance logging to ensure that
+// SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Performance library instance used by SMM Core"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides the performance measurement interfaces and initializes performance logging for the SMM phase. It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol, which is consumed by SmmPerformanceLib to logging performance data in the SMM phase. This library is mainly used by SMM Core to start performance logging to ensure that SMM Performance and PerformanceEx Protocol are installed at the very beginning of the SMM phase."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
new file mode 100644
index 000000000..120ba506a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
@@ -0,0 +1,76 @@
+/** @file
+ Master header files for SmmCorePerformanceLib instance.
+
+ This header file holds the prototypes of the SMM Performance and PerformanceEx Protocol published by this
+ library instance at its constructor.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
+#define _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
+
+
+#include <Guid/Performance.h>
+#include <Guid/PerformanceMeasurement.h>
+#include <Guid/ExtendedFirmwarePerformance.h>
+#include <Guid/FirmwarePerformance.h>
+#include <Guid/ZeroGuid.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/SmmMemLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+
+#include <Protocol/SmmBase2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePathToText.h>
+
+//
+// Interface declarations for SMM PerformanceMeasurement Protocol.
+//
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+**/
+EFI_STATUS
+EFIAPI
+CreatePerformanceMeasurement(
+ IN CONST VOID *CallerIdentifier, OPTIONAL
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 TimeStamp, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c
new file mode 100644
index 000000000..8046b0fa5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c
@@ -0,0 +1,46 @@
+/** @file
+ Null instance of SmmCorePlatformHookLibNull.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/SmmCorePlatformHookLib.h>
+
+/**
+ Performs platform specific tasks before invoking registered SMI handlers.
+
+ This function performs platform specific tasks before invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookBeforeSmmDispatch (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Performs platform specific tasks after invoking registered SMI handlers.
+
+ This function performs platform specific tasks after invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookAfterSmmDispatch (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
new file mode 100644
index 000000000..db707b6b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
@@ -0,0 +1,31 @@
+## @file
+# SMM Core Platform Hook Null Library instance
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCorePlatformHookLibNull
+ MODULE_UNI_FILE = SmmCorePlatformHookLibNull.uni
+ FILE_GUID = FED6583D-2418-4760-AC96-B5E18F0A6326
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = SmmCorePlatformHookLib|SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCorePlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni
new file mode 100644
index 000000000..ccc1f8124
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SMM Core Platform Hook Null Library instance
+//
+// SMM Core Platform Hook Null Library instance
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM Core Platform Hook Null Library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "SMM Core Platform Hook Null Library instance"
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c
new file mode 100644
index 000000000..0af2fab29
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c
@@ -0,0 +1,76 @@
+/** @file
+ Implementation of Ipmi Library for SMM.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Protocol/IpmiProtocol.h>
+#include <Library/IpmiLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+IPMI_PROTOCOL *mIpmiProtocol = NULL;
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIpmiProtocol == NULL) {
+ Status = gSmst->SmmLocateProtocol (
+ &gSmmIpmiProtocolGuid,
+ NULL,
+ (VOID **) &mIpmiProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Smm Ipmi Protocol is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand for SMM Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = mIpmiProtocol->IpmiSubmitCommand (
+ mIpmiProtocol,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf
new file mode 100644
index 000000000..827969f2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf
@@ -0,0 +1,36 @@
+## @file
+# Instance of SMM IPMI Library.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmIpmiLibSmmIpmiProtocol
+ MODULE_UNI_FILE = SmmIpmiLibSmmIpmiProtocol.uni
+ FILE_GUID = B422FB70-E835-448D-A921-EBA460E105B6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|DXE_SMM_DRIVER SMM_CORE
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmIpmiLibSmmIpmiProtocol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ SmmServicesTableLib
+
+[Protocols]
+ gSmmIpmiProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.uni b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.uni
new file mode 100644
index 000000000..d49cf0c3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Instance of SMM IPMI Library.
+//
+// Instance of SMM IPMI Library.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Instance of SMM IPMI Library."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Instance of SMM IPMI Library."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
new file mode 100644
index 000000000..2cbffe889
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
@@ -0,0 +1,538 @@
+/** @file
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Guid/SmmLockBox.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+EFI_SMM_COMMUNICATION_PROTOCOL *mLockBoxSmmCommProtocol = NULL;
+UINT8 *mLockBoxSmmCommBuffer = NULL;
+
+/**
+ Get smm communication protocol for lockbox.
+
+ @return Pointer to smm communication protocol, NULL if not found.
+
+**/
+EFI_SMM_COMMUNICATION_PROTOCOL *
+LockBoxGetSmmCommProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If the protocol has been got previously, return it.
+ //
+ if (mLockBoxSmmCommProtocol != NULL) {
+ return mLockBoxSmmCommProtocol;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&mLockBoxSmmCommProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mLockBoxSmmCommProtocol = NULL;
+ }
+ return mLockBoxSmmCommProtocol;
+}
+
+/**
+ Get smm communication buffer for lockbox.
+
+ @return Pointer to smm communication buffer, NULL if not found.
+
+**/
+UINT8 *
+LockBoxGetSmmCommBuffer (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN MinimalSizeNeeded;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ UINTN Size;
+
+ //
+ // If the buffer has been got previously, return it.
+ //
+ if (mLockBoxSmmCommBuffer != NULL) {
+ return mLockBoxSmmCommBuffer;
+ }
+
+ MinimalSizeNeeded = sizeof (EFI_GUID) +
+ sizeof (UINTN) +
+ MAX (sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE),
+ MAX (sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES),
+ MAX (sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE),
+ MAX (sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE),
+ sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)))));
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ mLockBoxSmmCommBuffer = NULL;
+ return mLockBoxSmmCommBuffer;
+ }
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
+ if (Size >= MinimalSizeNeeded) {
+ break;
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ if (Index >= PiSmmCommunicationRegionTable->NumberOfEntries) {
+ mLockBoxSmmCommBuffer = NULL;
+ } else {
+ mLockBoxSmmCommBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
+ }
+ return mLockBoxSmmCommBuffer;
+}
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 TempCommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)];
+ UINT8 *CommBuffer;
+ UINTN CommSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunication = LockBoxGetSmmCommProtocol ();
+ if (SmmCommunication == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommBuffer = LockBoxGetSmmCommBuffer ();
+ if (CommBuffer == NULL) {
+ CommBuffer = &TempCommBuffer[0];
+ }
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterSave);
+
+ LockBoxParameterSave = (EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterSave->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_SAVE;
+ LockBoxParameterSave->Header.DataLength = sizeof(*LockBoxParameterSave);
+ LockBoxParameterSave->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterSave->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterSave->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBoxParameterSave->Length = (UINT64)Length;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterSave->Header.ReturnStatus;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 TempCommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)];
+ UINT8 *CommBuffer;
+ UINTN CommSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Attributes & ~(LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE | LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunication = LockBoxGetSmmCommProtocol ();
+ if (SmmCommunication == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommBuffer = LockBoxGetSmmCommBuffer ();
+ if (CommBuffer == NULL) {
+ CommBuffer = &TempCommBuffer[0];
+ }
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterSetAttributes);
+
+ LockBoxParameterSetAttributes = (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterSetAttributes->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES;
+ LockBoxParameterSetAttributes->Header.DataLength = sizeof(*LockBoxParameterSetAttributes);
+ LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterSetAttributes->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterSetAttributes->Attributes = (UINT64)Attributes;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterSetAttributes->Header.ReturnStatus;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ the original buffer to too small to hold new information.
+ @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 TempCommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)];
+ UINT8 *CommBuffer;
+ UINTN CommSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib UpdateLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunication = LockBoxGetSmmCommProtocol ();
+ if (SmmCommunication == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommBuffer = LockBoxGetSmmCommBuffer ();
+ if (CommBuffer == NULL) {
+ CommBuffer = &TempCommBuffer[0];
+ }
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterUpdate);
+
+ LockBoxParameterUpdate = (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterUpdate->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_UPDATE;
+ LockBoxParameterUpdate->Header.DataLength = sizeof(*LockBoxParameterUpdate);
+ LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterUpdate->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterUpdate->Offset = (UINT64)Offset;
+ LockBoxParameterUpdate->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBoxParameterUpdate->Length = (UINT64)Length;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterUpdate->Header.ReturnStatus;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib UpdateLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 TempCommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)];
+ UINT8 *CommBuffer;
+ UINTN CommSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunication = LockBoxGetSmmCommProtocol ();
+ if (SmmCommunication == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommBuffer = LockBoxGetSmmCommBuffer ();
+ if (CommBuffer == NULL) {
+ CommBuffer = &TempCommBuffer[0];
+ }
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestore);
+
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterRestore->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE;
+ LockBoxParameterRestore->Header.DataLength = sizeof(*LockBoxParameterRestore);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterRestore->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterRestore->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (EFI_PHYSICAL_ADDRESS)*Length;
+ } else {
+ LockBoxParameterRestore->Length = 0;
+ }
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (Length != NULL) {
+ *Length = (UINTN)LockBoxParameterRestore->Length;
+ }
+
+ Status = (EFI_STATUS)LockBoxParameterRestore->Header.ReturnStatus;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 TempCommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)];
+ UINT8 *CommBuffer;
+ UINTN CommSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ SmmCommunication = LockBoxGetSmmCommProtocol ();
+ if (SmmCommunication == NULL) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommBuffer = LockBoxGetSmmCommBuffer ();
+ if (CommBuffer == NULL) {
+ CommBuffer = &TempCommBuffer[0];
+ }
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterRestoreAllInPlace->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE;
+ LockBoxParameterRestoreAllInPlace->Header.DataLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)-1;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterRestoreAllInPlace->Header.ReturnStatus;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
new file mode 100644
index 000000000..93c10772b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
@@ -0,0 +1,45 @@
+## @file
+# DXE LockBox library instance.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxDxeLib
+ MODULE_UNI_FILE = SmmLockBoxDxeLib.uni
+ FILE_GUID = 4A0054B4-3CA8-4e1b-9339-9B58D5FBB7D2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxDxeLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+
+[Guids]
+ gEfiSmmLockBoxCommunicationGuid ## SOMETIMES_CONSUMES ## GUID # Used to do smm communication
+ gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni
new file mode 100644
index 000000000..fc87e3504
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// DXE LockBox library instance.
+//
+// DXE LockBox library instance.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "DXE LockBox library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "DXE LockBox library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h
new file mode 100644
index 000000000..35311cb85
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h
@@ -0,0 +1,47 @@
+/** @file
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_LOCK_BOX_LIB_PRIVATE_H_
+#define _SMM_LOCK_BOX_LIB_PRIVATE_H_
+
+#include <Uefi.h>
+
+#pragma pack(1)
+
+//
+// Below data structure is used for lockbox registration in SMST
+//
+
+#define SMM_LOCK_BOX_SIGNATURE_32 SIGNATURE_64 ('L','O','C','K','B','_','3','2')
+#define SMM_LOCK_BOX_SIGNATURE_64 SIGNATURE_64 ('L','O','C','K','B','_','6','4')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_PHYSICAL_ADDRESS LockBoxDataAddress;
+} SMM_LOCK_BOX_CONTEXT;
+
+//
+// Below data structure is used for lockbox management
+//
+
+#define SMM_LOCK_BOX_DATA_SIGNATURE SIGNATURE_64 ('L','O','C','K','B','O','X','D')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_GUID Guid;
+ EFI_PHYSICAL_ADDRESS Buffer;
+ UINT64 Length;
+ UINT64 Attributes;
+ EFI_PHYSICAL_ADDRESS SmramBuffer;
+ LIST_ENTRY Link;
+} SMM_LOCK_BOX_DATA;
+
+#pragma pack()
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
new file mode 100644
index 000000000..fe1059d8f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
@@ -0,0 +1,742 @@
+/** @file
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <PiDxe.h>
+#include <PiSmm.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Ppi/SmmCommunication.h>
+#include <Ppi/SmmAccess.h>
+#include <Guid/AcpiS3Context.h>
+#include <Guid/SmmLockBox.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+#if defined (MDE_CPU_IA32)
+typedef struct _LIST_ENTRY64 LIST_ENTRY64;
+struct _LIST_ENTRY64 {
+ LIST_ENTRY64 *ForwardLink;
+ UINT32 Reserved1;
+ LIST_ENTRY64 *BackLink;
+ UINT32 Reserved2;
+};
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ UINT64 SmmFirmwareVendor;
+ UINT64 SmmFirmwareRevision;
+ UINT64 SmmInstallConfigurationTable;
+ UINT64 SmmIoMemRead;
+ UINT64 SmmIoMemWrite;
+ UINT64 SmmIoIoRead;
+ UINT64 SmmIoIoWrite;
+ UINT64 SmmAllocatePool;
+ UINT64 SmmFreePool;
+ UINT64 SmmAllocatePages;
+ UINT64 SmmFreePages;
+ UINT64 SmmStartupThisAp;
+ UINT64 CurrentlyExecutingCpu;
+ UINT64 NumberOfCpus;
+ UINT64 CpuSaveStateSize;
+ UINT64 CpuSaveState;
+ UINT64 NumberOfTableEntries;
+ UINT64 SmmConfigurationTable;
+} EFI_SMM_SYSTEM_TABLE2_64;
+
+typedef struct {
+ EFI_GUID VendorGuid;
+ UINT64 VendorTable;
+} EFI_CONFIGURATION_TABLE64;
+#endif
+
+#if defined (MDE_CPU_X64)
+typedef LIST_ENTRY LIST_ENTRY64;
+typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
+typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
+#endif
+
+/**
+ This function return first node of LinkList queue.
+
+ @param LockBoxQueue LinkList queue
+
+ @return first node of LinkList queue
+**/
+LIST_ENTRY *
+InternalInitLinkDxe (
+ IN LIST_ENTRY *LinkList
+ )
+{
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ return (LIST_ENTRY *)(((LIST_ENTRY64 *)LinkList)->ForwardLink);
+ } else {
+ return LinkList->ForwardLink;
+ }
+}
+
+/**
+ This function return next node of LinkList.
+
+ @param Link LinkList node
+
+ @return next node of LinkList
+**/
+LIST_ENTRY *
+InternalNextLinkDxe (
+ IN LIST_ENTRY *Link
+ )
+{
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ return (LIST_ENTRY *)(((LIST_ENTRY64 *)Link)->ForwardLink);
+ } else {
+ return Link->ForwardLink;
+ }
+}
+
+/**
+ This function find LockBox by GUID from SMRAM.
+
+ @param LockBoxQueue The LockBox queue in SMRAM
+ @param Guid The guid to indentify the LockBox
+
+ @return LockBoxData
+**/
+SMM_LOCK_BOX_DATA *
+InternalFindLockBoxByGuidFromSmram (
+ IN LIST_ENTRY *LockBoxQueue,
+ IN EFI_GUID *Guid
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_LOCK_BOX_DATA *LockBox;
+
+ for (Link = InternalInitLinkDxe (LockBoxQueue);
+ Link != LockBoxQueue;
+ Link = InternalNextLinkDxe (Link)) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if (CompareGuid (&LockBox->Guid, Guid)) {
+ return LockBox;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Get VendorTable by VendorGuid in Smst.
+
+ @param Signature Signature of SMM_S3_RESUME_STATE
+ @param Smst SMM system table
+ @param VendorGuid vendor guid
+
+ @return vendor table.
+**/
+VOID *
+InternalSmstGetVendorTableByGuid (
+ IN UINT64 Signature,
+ IN EFI_SMM_SYSTEM_TABLE2 *Smst,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_CONFIGURATION_TABLE *SmmConfigurationTable;
+ UINTN NumberOfTableEntries;
+ UINTN Index;
+ EFI_SMM_SYSTEM_TABLE2_64 *Smst64;
+ EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64;
+
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
+ SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
+ NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
+ }
+ }
+ return NULL;
+ } else {
+ SmmConfigurationTable = Smst->SmmConfigurationTable;
+ NumberOfTableEntries = Smst->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)SmmConfigurationTable[Index].VendorTable;
+ }
+ }
+ return NULL;
+ }
+}
+
+/**
+ Get SMM LockBox context.
+
+ @return SMM LockBox context.
+**/
+SMM_LOCK_BOX_CONTEXT *
+InternalGetSmmLockBoxContext (
+ VOID
+ )
+{
+ EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
+ SMM_S3_RESUME_STATE *SmmS3ResumeState;
+ VOID *GuidHob;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
+ ASSERT (GuidHob != NULL);
+ SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
+ SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
+
+ SmmLockBoxContext = (SMM_LOCK_BOX_CONTEXT *)InternalSmstGetVendorTableByGuid (
+ SmmS3ResumeState->Signature,
+ (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
+ &gEfiSmmLockBoxCommunicationGuid
+ );
+ ASSERT (SmmLockBoxContext != NULL);
+
+ return SmmLockBoxContext;
+}
+
+/**
+ This function will restore confidential information from lockbox in SMRAM directly.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+**/
+EFI_STATUS
+InternalRestoreLockBoxFromSmram (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ UINTN Index;
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+ LIST_ENTRY *LockBoxQueue;
+ SMM_LOCK_BOX_DATA *LockBox;
+ VOID *RestoreBuffer;
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; !EFI_ERROR (Status); Index++) {
+ Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
+ }
+ }
+
+ //
+ // Get LockBox context
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ LockBoxQueue = (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+
+ //
+ // We do NOT check Buffer address in SMRAM, because if SMRAM not locked, we trust the caller.
+ //
+
+ //
+ // Restore this, Buffer and Length MUST be both NULL or both non-NULL
+ //
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuidFromSmram (LockBoxQueue, Guid);
+ if (LockBox == NULL) {
+ //
+ // Not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set RestoreBuffer
+ //
+ if (Buffer != NULL) {
+ //
+ // restore to new buffer
+ //
+ RestoreBuffer = Buffer;
+ } else {
+ //
+ // restore to original buffer
+ //
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+ RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
+ }
+
+ //
+ // Set RestoreLength
+ //
+ if (Length != NULL) {
+ if (*Length < (UINTN)LockBox->Length) {
+ //
+ // Input buffer is too small to hold all data.
+ //
+ *Length = (UINTN)LockBox->Length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = (UINTN)LockBox->Length;
+ }
+
+ //
+ // Restore data
+ //
+ CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+**/
+EFI_STATUS
+InternalRestoreAllLockBoxInPlaceFromSmram (
+ VOID
+ )
+{
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ UINTN Index;
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+ LIST_ENTRY *LockBoxQueue;
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *Link;
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; !EFI_ERROR (Status); Index++) {
+ Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
+ }
+ }
+
+ //
+ // Get LockBox context
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ LockBoxQueue = (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+
+ //
+ // We do NOT check Buffer address in SMRAM, because if SMRAM not locked, we trust the caller.
+ //
+
+ //
+ // Restore all, Buffer and Length MUST be NULL
+ //
+ for (Link = InternalInitLinkDxe (LockBoxQueue);
+ Link != LockBoxQueue;
+ Link = InternalNextLinkDxe (Link)) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
+ //
+ // Restore data
+ //
+ CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ }
+ }
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to save at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to save at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ the original buffer to too small to hold new information.
+ @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to update at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_SMM_COMMUNICATION_PPI *SmmCommunicationPpi;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINT64) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)];
+ UINTN CommSize;
+ UINT64 MessageLength;
+
+ //
+ // Please aware that there is UINTN in EFI_SMM_COMMUNICATE_HEADER. It might be UINT64 in DXE, while it is UINT32 in PEI.
+ // typedef struct {
+ // EFI_GUID HeaderGuid;
+ // UINTN MessageLength;
+ // UINT8 Data[1];
+ // } EFI_SMM_COMMUNICATE_HEADER;
+ //
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiSmmCommunicationPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmCommunicationPpi
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
+ Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ MessageLength = sizeof(*LockBoxParameterRestore);
+ CopyMem (&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength)], &MessageLength, sizeof(MessageLength));
+ } else {
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestore);
+ }
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib CommBuffer - %x\n", &CommBuffer[0]));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINT64)];
+ } else {
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINTN)];
+ }
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LockBoxParameterRestore - %x\n", LockBoxParameterRestore));
+ LockBoxParameterRestore->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE;
+ LockBoxParameterRestore->Header.DataLength = sizeof(*LockBoxParameterRestore);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)-1;
+ if (Guid != 0) {
+ CopyMem (&LockBoxParameterRestore->Guid, Guid, sizeof(*Guid));
+ } else {
+ ZeroMem (&LockBoxParameterRestore->Guid, sizeof(*Guid));
+ }
+ LockBoxParameterRestore->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (EFI_PHYSICAL_ADDRESS)*Length;
+ } else {
+ LockBoxParameterRestore->Length = 0;
+ }
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunicationPpi->Communicate (
+ SmmCommunicationPpi,
+ &CommBuffer[0],
+ &CommSize
+ );
+ if (Status == EFI_NOT_STARTED) {
+ //
+ // Pei SMM communication not ready yet, so we access SMRAM directly
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+ Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (UINT64)*Length;
+ }
+ }
+
+ if (Length != NULL) {
+ *Length = (UINTN)LockBoxParameterRestore->Length;
+ }
+
+ Status = (EFI_STATUS)LockBoxParameterRestore->Header.ReturnStatus;
+ if (Status != EFI_SUCCESS) {
+ // Need or MAX_BIT, because there might be case that SMM is X64 while PEI is IA32.
+ Status |= MAX_BIT;
+ }
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_SMM_COMMUNICATION_PPI *SmmCommunicationPpi;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINT64) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)];
+ UINTN CommSize;
+ UINT64 MessageLength;
+
+ //
+ // Please aware that there is UINTN in EFI_SMM_COMMUNICATE_HEADER. It might be UINT64 in DXE, while it is UINT32 in PEI.
+ // typedef struct {
+ // EFI_GUID HeaderGuid;
+ // UINTN MessageLength;
+ // UINT8 Data[1];
+ // } EFI_SMM_COMMUNICATE_HEADER;
+ //
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiSmmCommunicationPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmCommunicationPpi
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
+ Status = InternalRestoreAllLockBoxInPlaceFromSmram ();
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ CopyMem (&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength)], &MessageLength, sizeof(MessageLength));
+ } else {
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ }
+
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINT64)];
+ } else {
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINTN)];
+ }
+ LockBoxParameterRestoreAllInPlace->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE;
+ LockBoxParameterRestoreAllInPlace->Header.DataLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)-1;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunicationPpi->Communicate (
+ SmmCommunicationPpi,
+ &CommBuffer[0],
+ &CommSize
+ );
+ if (Status == EFI_NOT_STARTED) {
+ //
+ // Pei SMM communication not ready yet, so we access SMRAM directly
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+ Status = InternalRestoreAllLockBoxInPlaceFromSmram ();
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterRestoreAllInPlace->Header.ReturnStatus;
+ if (Status != EFI_SUCCESS) {
+ // Need or MAX_BIT, because there might be case that SMM is X64 while PEI is IA32.
+ Status |= MAX_BIT;
+ }
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
new file mode 100644
index 000000000..5d57a08a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
@@ -0,0 +1,52 @@
+## @file
+# PEI LockBox library instance.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxPeiLib
+ MODULE_UNI_FILE = SmmLockBoxPeiLib.uni
+ FILE_GUID = 5F5E6140-E7BA-4bd6-B85F-236B5BCD8E1E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxPeiLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ BaseLib
+ BaseMemoryLib
+ HobLib
+ DebugLib
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # Used to do smm communication
+ ## SOMETIMES_CONSUMES ## UNDEFINED # SmmSystemTable
+ gEfiSmmLockBoxCommunicationGuid
+ gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Ppis]
+ gEfiPeiSmmCommunicationPpiGuid ## CONSUMES
+ gPeiSmmAccessPpiGuid ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni
new file mode 100644
index 000000000..ee6d577a2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// PEI LockBox library instance.
+//
+// PEI LockBox library instance.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PEI LockBox library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "PEI LockBox library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
new file mode 100644
index 000000000..4cc0e8b78
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
@@ -0,0 +1,871 @@
+/** @file
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/DebugLib.h>
+#include <Guid/SmmLockBox.h>
+#include <Guid/EndOfS3Resume.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmEndOfDxe.h>
+#include <Protocol/SmmSxDispatch2.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+/**
+ We need handle this library carefully. Only one library instance will construct the environment.
+ Below 2 global variable can only be used in constructor. They should NOT be used in any other library functions.
+**/
+SMM_LOCK_BOX_CONTEXT mSmmLockBoxContext;
+LIST_ENTRY mLockBoxQueue = INITIALIZE_LIST_HEAD_VARIABLE (mLockBoxQueue);
+
+BOOLEAN mSmmConfigurationTableInstalled = FALSE;
+VOID *mSmmLockBoxRegistrationSmmEndOfDxe = NULL;
+VOID *mSmmLockBoxRegistrationSmmReadyToLock = NULL;
+VOID *mSmmLockBoxRegistrationEndOfS3Resume = NULL;
+BOOLEAN mSmmLockBoxSmmReadyToLock = FALSE;
+BOOLEAN mSmmLockBoxDuringS3Resume = FALSE;
+
+/**
+ This function return SmmLockBox context from SMST.
+
+ @return SmmLockBox context from SMST.
+**/
+SMM_LOCK_BOX_CONTEXT *
+InternalGetSmmLockBoxContext (
+ VOID
+ )
+{
+ UINTN Index;
+
+ //
+ // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
+ //
+ for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gSmst->SmmConfigurationTable[Index].VendorGuid, &gEfiSmmLockBoxCommunicationGuid)) {
+ //
+ // Found. That means some other library instance is already run.
+ // No need to install again, just return.
+ //
+ return (SMM_LOCK_BOX_CONTEXT *)gSmst->SmmConfigurationTable[Index].VendorTable;
+ }
+ }
+
+ //
+ // Not found.
+ //
+ return NULL;
+}
+
+/**
+ Notification for SMM ReadyToLock protocol.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmReadyToLockNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ mSmmLockBoxSmmReadyToLock = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry point for an SMM handler dispatch or communicate-based callback.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in,out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in,out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxS3EntryCallBack (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ mSmmLockBoxDuringS3Resume = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification for SMM EndOfDxe protocol.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmEndOfDxeNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
+ EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
+ EFI_HANDLE S3EntryHandle;
+
+ //
+ // Locate SmmSxDispatch2 protocol.
+ //
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ NULL,
+ (VOID **)&SxDispatch
+ );
+ if (!EFI_ERROR (Status) && (SxDispatch != NULL)) {
+ //
+ // Register a S3 entry callback function to
+ // determine if it will be during S3 resume.
+ //
+ EntryRegisterContext.Type = SxS3;
+ EntryRegisterContext.Phase = SxEntry;
+ Status = SxDispatch->Register (
+ SxDispatch,
+ SmmLockBoxS3EntryCallBack,
+ &EntryRegisterContext,
+ &S3EntryHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification for SMM EndOfS3Resume protocol.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxEndOfS3ResumeNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ mSmmLockBoxDuringS3Resume = FALSE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Constructor for SmmLockBox library.
+ This is used to set SmmLockBox context, which will be used in PEI phase in S3 boot path later.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
+
+ //
+ // Register SmmReadyToLock notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ SmmLockBoxSmmReadyToLockNotify,
+ &mSmmLockBoxRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SmmEndOfDxe notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmLockBoxSmmEndOfDxeNotify,
+ &mSmmLockBoxRegistrationSmmEndOfDxe
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register EndOfS3Resume notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEdkiiEndOfS3ResumeGuid,
+ SmmLockBoxEndOfS3ResumeNotify,
+ &mSmmLockBoxRegistrationEndOfS3Resume
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ if (SmmLockBoxContext != NULL) {
+ //
+ // Find it. That means some other library instance is already run.
+ // No need to install again, just return.
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If no one install this, it means this is first instance. Install it.
+ //
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_64;
+ } else {
+ mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_32;
+ }
+ mSmmLockBoxContext.LockBoxDataAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)&mLockBoxQueue;
+
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiSmmLockBoxCommunicationGuid,
+ &mSmmLockBoxContext,
+ sizeof(mSmmLockBoxContext)
+ );
+ ASSERT_EFI_ERROR (Status);
+ mSmmConfigurationTableInstalled = TRUE;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext));
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue));
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+
+ return Status;
+}
+
+/**
+ Destructor for SmmLockBox library.
+ This is used to uninstall SmmLockBoxCommunication configuration table
+ if it has been installed in Constructor.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName));
+
+ if (mSmmConfigurationTableInstalled) {
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiSmmLockBoxCommunicationGuid,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
+ }
+
+ if (mSmmLockBoxRegistrationSmmReadyToLock != NULL) {
+ //
+ // Unregister SmmReadyToLock notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ NULL,
+ &mSmmLockBoxRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mSmmLockBoxRegistrationSmmEndOfDxe != NULL) {
+ //
+ // Unregister SmmEndOfDxe notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ NULL,
+ &mSmmLockBoxRegistrationSmmEndOfDxe
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mSmmLockBoxRegistrationEndOfS3Resume != NULL) {
+ //
+ // Unregister EndOfS3Resume notification.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEdkiiEndOfS3ResumeGuid,
+ NULL,
+ &mSmmLockBoxRegistrationEndOfS3Resume
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function return SmmLockBox queue address.
+
+ @return SmmLockBox queue address.
+**/
+LIST_ENTRY *
+InternalGetLockBoxQueue (
+ VOID
+ )
+{
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ ASSERT (SmmLockBoxContext != NULL);
+ if (SmmLockBoxContext == NULL) {
+ return NULL;
+ }
+ return (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+}
+
+/**
+ This function find LockBox by GUID.
+
+ @param Guid The guid to indentify the LockBox
+
+ @return LockBoxData
+**/
+SMM_LOCK_BOX_DATA *
+InternalFindLockBoxByGuid (
+ IN EFI_GUID *Guid
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *LockBoxQueue;
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+
+ for (Link = LockBoxQueue->ForwardLink;
+ Link != LockBoxQueue;
+ Link = Link->ForwardLink) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if (CompareGuid (&LockBox->Guid, Guid)) {
+ return LockBox;
+ }
+ }
+ return NULL;
+}
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ EFI_PHYSICAL_ADDRESS SmramBuffer;
+ EFI_STATUS Status;
+ LIST_ENTRY *LockBoxQueue;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox != NULL) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Allocate SMRAM buffer
+ //
+ Status = gSmst->SmmAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Length),
+ &SmramBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate LockBox
+ //
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof(*LockBox),
+ (VOID **)&LockBox
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ gSmst->SmmFreePages (SmramBuffer, EFI_SIZE_TO_PAGES (Length));
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save data
+ //
+ CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)Buffer, Length);
+
+ //
+ // Insert LockBox to queue
+ //
+ LockBox->Signature = SMM_LOCK_BOX_DATA_SIGNATURE;
+ CopyMem (&LockBox->Guid, Guid, sizeof(EFI_GUID));
+ LockBox->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBox->Length = (UINT64)Length;
+ LockBox->Attributes = 0;
+ LockBox->SmramBuffer = SmramBuffer;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n",
+ &LockBox->Guid,
+ LockBox->SmramBuffer,
+ LockBox->Length
+ ));
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+ InsertTailList (LockBoxQueue, &LockBox->Link);
+
+ //
+ // Done
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Attributes & ~(LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE | LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY)) != 0)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) &&
+ ((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ DEBUG ((DEBUG_INFO, " LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
+ DEBUG ((DEBUG_INFO, " can not be set together\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ if ((((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) &&
+ ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0)) ||
+ (((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) &&
+ ((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0))) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes 0x%lx 0x%lx - Exit (%r)\n", LockBox->Attributes, Attributes, EFI_INVALID_PARAMETER));
+ DEBUG ((DEBUG_INFO, " LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
+ DEBUG ((DEBUG_INFO, " can not be set together\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update data
+ //
+ LockBox->Attributes = Attributes;
+
+ //
+ // Done
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL for lockbox without attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ the original buffer to too small to hold new information.
+ @retval RETURN_OUT_OF_RESOURCES for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ EFI_PHYSICAL_ADDRESS SmramBuffer;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0) ||
+ (Length > MAX_UINTN - Offset)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update data
+ //
+ if (LockBox->Length < Offset + Length) {
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0) {
+ //
+ // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is set, enlarge the
+ // LockBox.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "SmmLockBoxSmmLib UpdateLockBox - Origin LockBox too small, enlarge.\n"
+ ));
+
+ if (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES ((UINTN)LockBox->Length)) < Offset + Length) {
+ //
+ // In SaveLockBox(), the SMRAM buffer allocated for LockBox is of page
+ // granularity. Here, if the required size is larger than the origin size
+ // of the pages, allocate new buffer from SMRAM to enlarge the LockBox.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "SmmLockBoxSmmLib UpdateLockBox - Allocate new buffer to enlarge.\n"
+ ));
+ Status = gSmst->SmmAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Offset + Length),
+ &SmramBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy origin data to the new SMRAM buffer and wipe the content in the
+ // origin SMRAM buffer.
+ //
+ CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ ZeroMem ((VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ gSmst->SmmFreePages (LockBox->SmramBuffer, EFI_SIZE_TO_PAGES ((UINTN)LockBox->Length));
+
+ LockBox->SmramBuffer = SmramBuffer;
+ }
+
+ //
+ // Handle uninitialized content in the LockBox.
+ //
+ if (Offset > LockBox->Length) {
+ ZeroMem (
+ (VOID *)((UINTN)LockBox->SmramBuffer + (UINTN)LockBox->Length),
+ Offset - (UINTN)LockBox->Length
+ );
+ }
+ LockBox->Length = Offset + Length;
+ } else {
+ //
+ // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is NOT set, return
+ // EFI_BUFFER_TOO_SMALL directly.
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+ ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
+ CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length);
+
+ //
+ // Done
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ VOID *RestoreBuffer;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
+
+ //
+ // Restore this, Buffer and Length MUST be both NULL or both non-NULL
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ //
+ // Not found
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ if (((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0) &&
+ mSmmLockBoxSmmReadyToLock &&
+ !mSmmLockBoxDuringS3Resume) {
+ //
+ // With LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+ // this LockBox can be restored in S3 resume only.
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Set RestoreBuffer
+ //
+ if (Buffer != NULL) {
+ //
+ // restore to new buffer
+ //
+ RestoreBuffer = Buffer;
+ } else {
+ //
+ // restore to original buffer
+ //
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED));
+ return EFI_WRITE_PROTECTED;
+ }
+ RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
+ }
+
+ //
+ // Set RestoreLength
+ //
+ if (Length != NULL) {
+ if (*Length < (UINTN)LockBox->Length) {
+ //
+ // Input buffer is too small to hold all data.
+ //
+ *Length = (UINTN)LockBox->Length;
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = (UINTN)LockBox->Length;
+ }
+
+ //
+ // Restore data
+ //
+ CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+
+ //
+ // Done
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *LockBoxQueue;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+
+ //
+ // Restore all, Buffer and Length MUST be NULL
+ //
+ for (Link = LockBoxQueue->ForwardLink;
+ Link != LockBoxQueue;
+ Link = Link->ForwardLink) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
+ //
+ // Restore data
+ //
+ CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ }
+ }
+ //
+ // Done
+ //
+ DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
new file mode 100644
index 000000000..2b6cc983b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
@@ -0,0 +1,51 @@
+## @file
+# SMM LockBox library instance.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxSmmLib
+ MODULE_UNI_FILE = SmmLockBoxSmmLib.uni
+ FILE_GUID = E04894D6-290D-4171-A362-0ACFD939F3C8
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmLockBoxSmmConstructor
+ DESTRUCTOR = SmmLockBoxSmmDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxSmmLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+ BaseLib
+ DebugLib
+
+[Protocols]
+ gEfiSmmReadyToLockProtocolGuid ## NOTIFY
+ gEfiSmmEndOfDxeProtocolGuid ## NOTIFY
+ gEfiSmmSxDispatch2ProtocolGuid ## NOTIFY
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # SmmSystemTable
+ ## SOMETIMES_PRODUCES ## UNDEFINED # SmmSystemTable
+ gEfiSmmLockBoxCommunicationGuid
+ ## CONSUMES ## UNDEFINED # Protocol notify
+ gEdkiiEndOfS3ResumeGuid
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni
new file mode 100644
index 000000000..eb654d79e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SMM LockBox library instance.
+//
+// SMM LockBox library instance.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM LockBox library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "SMM LockBox library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/MemoryAllocationLib.c b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/MemoryAllocationLib.c
new file mode 100644
index 000000000..27a6748f5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/MemoryAllocationLib.c
@@ -0,0 +1,1134 @@
+/** @file
+ Support routines for memory allocation routines based
+ on SMM Services Table services for SMM phase drivers, with memory profile support.
+
+ The PI System Management Mode Core Interface Specification only allows the use
+ of EfiRuntimeServicesCode and EfiRuntimeServicesData memory types for memory
+ allocations through the SMM Services Table as the SMRAM space should be
+ reserved after BDS phase. The functions in the Memory Allocation Library use
+ EfiBootServicesData as the default memory allocation type. For this SMM
+ specific instance of the Memory Allocation Library, EfiRuntimeServicesData
+ is used as the default memory type for all allocations. In addition,
+ allocation for the Reserved memory types are not supported and will always
+ return NULL.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Protocol/SmmAccess2.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include <Library/MemoryProfileLib.h>
+
+EFI_SMRAM_DESCRIPTOR *mSmramRanges;
+UINTN mSmramRangeCount;
+
+/**
+ The constructor function caches SMRAM ranges that are present in the system.
+
+ It will ASSERT() if SMM Access2 Protocol doesn't exist.
+ It will ASSERT() if SMRAM ranges can't be got.
+ It will ASSERT() if Resource can't be allocated for cache SMRAM range.
+ 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
+SmmMemoryAllocationLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+ UINTN Size;
+
+ //
+ // Locate SMM Access2 Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmAccess2ProtocolGuid,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get SMRAM range information
+ //
+ Size = 0;
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ mSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
+ ASSERT (mSmramRanges != NULL);
+
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);
+ ASSERT_EFI_ERROR (Status);
+
+ mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ If SMM driver exits with an error, it must call this routine
+ to free the allocated resource before the exiting.
+
+ @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 deconstructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+SmmMemoryAllocationLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ FreePool (mSmramRanges);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the start address of buffer is within any of the SMRAM ranges.
+
+ @param[in] Buffer The pointer to the buffer to be checked.
+
+ @retval TRUE The buffer is in SMRAM ranges.
+ @retval FALSE The buffer is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+BufferInSmram (
+ IN VOID *Buffer
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mSmramRangeCount; Index ++) {
+ if (((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer >= mSmramRanges[Index].CpuStart) &&
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer < (mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer
+ to the allocated buffer. The buffer returned is aligned on a 4KB boundary. If
+ Pages is 0, then NULL is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = gSmst->SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer
+ to the allocated buffer. The buffer returned is aligned on a 4KB boundary. If
+ Pages is 0, then NULL is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a
+ pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
+ If Pages is 0, then NULL is returned. If there is not enough memory remaining
+ to satisfy the request, then NULL is returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a
+ pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
+ If Pages is 0, then NULL is returned. If there is not enough memory remaining
+ to satisfy the request, then NULL is returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer.
+ Buffer must have been allocated on a previous call to the page allocation services
+ of the Memory Allocation Library. If it is not possible to free allocated pages,
+ then this function will perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePages() service.
+ // So, gSmst->SmmFreePages() service is used to free it.
+ //
+ Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type
+ with an alignment specified by Alignment. The allocated buffer is returned.
+ If Pages is 0, then NULL is returned. If there is not enough memory at the
+ specified alignment remaining to satisfy the request, then NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = gSmst->SmmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = gSmst->SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = gSmst->SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = gSmst->SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData
+ with an alignment specified by Alignment. The allocated buffer is returned.
+ If Pages is 0, then NULL is returned. If there is not enough memory at the
+ specified alignment remaining to satisfy the request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData
+ with an alignment specified by Alignment. The allocated buffer is returned.
+ If Pages is 0, then NULL is returned. If there is not enough memory at the
+ specified alignment remaining to satisfy the request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE(Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType
+ with an alignment specified by Alignment. The allocated buffer is returned.
+ If Pages is 0, then NULL is returned. If there is not enough memory at the
+ specified alignment remaining to satisfy the request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation.
+ Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by
+ Buffer. Buffer must have been allocated on a previous call to the aligned page
+ allocation services of the Memory Allocation Library. If it is not possible to
+ free allocated pages, then this function will perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the
+ Memory Allocation Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePages() service.
+ // So, gSmst->SmmFreePages() service is used to free it.
+ //
+ Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type
+ and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Status = gSmst->SmmAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData
+ and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData
+ and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType
+ and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to
+ satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type,
+ clears the buffer with zeros, and returns a pointer to the allocated buffer.
+ If AllocationSize is 0, then a valid buffer of 0 size is returned. If there is
+ not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData,
+ clears the buffer with zeros, and returns a pointer to the allocated buffer.
+ If AllocationSize is 0, then a valid buffer of 0 size is returned. If there is
+ not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData,
+ clears the buffer with zeros, and returns a pointer to the allocated buffer.
+ If AllocationSize is 0, then a valid buffer of 0 size is returned. If there is
+ not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType,
+ clears the buffer with zeros, and returns a pointer to the allocated buffer.
+ If AllocationSize is 0, then a valid buffer of 0 size is returned. If there is
+ not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type,
+ copies AllocationSize bytes from Buffer to the newly allocated buffer, and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer
+ of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned. If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData,
+ copies AllocationSize bytes from Buffer to the newly allocated buffer, and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer
+ of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData,
+ copies AllocationSize bytes from Buffer to the newly allocated buffer, and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer
+ of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType,
+ copies AllocationSize bytes from Buffer to the newly allocated buffer, and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer
+ of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize
+ and OldSize is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize
+ and OldSize is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize
+ and NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize
+ and OldSize is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize
+ and NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize
+ and OldSize is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an
+ optional parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation
+ functions in the Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a
+ previous call to the pool allocation services of the Memory Allocation Library.
+ If it is not possible to free pool resources, then this function will perform
+ no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory
+ Allocation Library, then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePool() service.
+ // So, gSmst->SmmFreePool() service is used to free it.
+ //
+ Status = gSmst->SmmFreePool (Buffer);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePool() service.
+ // So, gBS->FreePool() service is used to free it.
+ //
+ Status = gBS->FreePool (Buffer);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.inf b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.inf
new file mode 100644
index 000000000..3e29a8caf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Instance of Memory Allocation Library using SMM Services Table,
+# with memory profile support.
+#
+# Memory Allocation Library that uses services from the SMM Services Table to
+# allocate and free memory, with memory profile support.
+#
+# The implementation of this instance is copied from UefiMemoryAllocationLib
+# in MdePkg and updated to support both MemoryAllocationLib and MemoryProfileLib.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmMemoryAllocationProfileLib
+ MODULE_UNI_FILE = SmmMemoryAllocationProfileLib.uni
+ FILE_GUID = DC50729F-8633-47ab-8FD3-6939688CEE4C
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = MemoryAllocationLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmMemoryAllocationLibConstructor
+ DESTRUCTOR = SmmMemoryAllocationLibDestructor
+ LIBRARY_CLASS = MemoryProfileLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmMemoryProfileLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ SmmMemoryProfileLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiSmmAccess2ProtocolGuid ## CONSUMES
+
+[Guids]
+ gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+ gEdkiiSmmMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+
+[Depex]
+ gEfiSmmAccess2ProtocolGuid
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.uni b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.uni
new file mode 100644
index 000000000..3fae26372
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Instance of Memory Allocation Library using SMM Services Table,
+// with memory profile support.
+//
+// Memory Allocation Library that uses services from the SMM Services Table to
+// allocate and free memory, with memory profile support.
+//
+// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library using SMM Services Table, with memory profile support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This Memory Allocation Library uses services from the SMM Services Table to allocate and free memory, with memory profile support."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryProfileLib.c b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryProfileLib.c
new file mode 100644
index 000000000..83ffcf510
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryProfileLib.c
@@ -0,0 +1,137 @@
+/** @file
+ Support routines for memory profile for Smm phase drivers.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include <Guid/MemoryProfile.h>
+
+EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
+EDKII_SMM_MEMORY_PROFILE_PROTOCOL *mLibSmmProfileProtocol;
+
+/**
+ Check whether the start address of buffer is within any of the SMRAM ranges.
+
+ @param[in] Buffer The pointer to the buffer to be checked.
+
+ @retval TRUE The buffer is in SMRAM ranges.
+ @retval FALSE The buffer is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+BufferInSmram (
+ IN VOID *Buffer
+ );
+
+/**
+ The constructor function initializes memory profile for SMM phase.
+
+ @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
+SmmMemoryProfileLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Profile Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEdkiiMemoryProfileGuid,
+ NULL,
+ (VOID **)&mLibProfileProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mLibProfileProtocol = NULL;
+ }
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEdkiiSmmMemoryProfileGuid,
+ NULL,
+ (VOID **)&mLibSmmProfileProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mLibSmmProfileProtocol = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ if (BufferInSmram (Buffer)) {
+ if (mLibSmmProfileProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mLibSmmProfileProtocol->Record (
+ mLibSmmProfileProtocol,
+ CallerAddress,
+ Action,
+ MemoryType,
+ Buffer,
+ Size,
+ ActionString
+ );
+ } else {
+ if (mLibProfileProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mLibProfileProtocol->Record (
+ mLibProfileProtocol,
+ CallerAddress,
+ Action,
+ MemoryType,
+ Buffer,
+ Size,
+ ActionString
+ );
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
new file mode 100644
index 000000000..797d72f67
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
@@ -0,0 +1,461 @@
+/** @file
+ Performance Library used in SMM phase.
+
+ This library instance provides infrastructure for SMM drivers to log performance
+ data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
+ to log performance data. If both SMM PerformanceEx and Performance Protocol are not available, it does not log any
+ performance information.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Guid/PerformanceMeasurement.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+
+//
+// The cached SMM Performance Protocol and SMM PerformanceEx Protocol interface.
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL *mPerformanceMeasurement = NULL;
+BOOLEAN mPerformanceMeasurementEnabled;
+
+/**
+ The constructor function initializes the Performance Measurement Enable flag
+
+ @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
+SmmPerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ mPerformanceMeasurementEnabled = (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The function caches the pointers to SMM PerformanceEx protocol and Performance Protocol.
+
+ The function locates SMM PerformanceEx protocol and Performance Protocol from protocol database.
+
+ @retval EFI_SUCCESS SMM PerformanceEx protocol or Performance Protocol is successfully located.
+ @retval EFI_NOT_FOUND Both SMM PerformanceEx protocol and Performance Protocol are not located to log performance.
+
+**/
+EFI_STATUS
+GetPerformanceMeasurementProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL *PerformanceMeasurement;
+
+ if (mPerformanceMeasurement != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gSmst->SmmLocateProtocol (&gEdkiiSmmPerformanceMeasurementProtocolGuid, NULL, (VOID **) &PerformanceMeasurement);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PerformanceMeasurement != NULL);
+ //
+ // Cache PerformanceMeasurement Protocol.
+ //
+ mPerformanceMeasurement = PerformanceMeasurement;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+ CONST CHAR8* String;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+ CONST CHAR8* String;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return mPerformanceMeasurementEnabled;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid, OPTIONAL
+ IN CONST CHAR8 *String, OPTIONAL
+ IN UINT64 Address, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceMeasurementProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ if (mPerformanceMeasurement != NULL) {
+ Status = mPerformanceMeasurement->CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
new file mode 100644
index 000000000..d79cd5c8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Performance library instance used in SMM phase.
+#
+# This library instance provides infrastructure for SMM drivers to log performance
+# data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
+# to log performance data. If both SMM PerformanceEx and Performance Protocol are not available,
+# it does not log any performance information.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmPerformanceLib
+ MODULE_UNI_FILE = SmmPerformanceLib.uni
+ FILE_GUID = 1EDD13E6-D0CD-4432-A692-FF65C9B4F039
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_SMM_DRIVER
+
+ CONSTRUCTOR = SmmPerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmPerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ PcdLib
+ SmmServicesTableLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gEdkiiSmmPerformanceMeasurementProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni
new file mode 100644
index 000000000..34c9c9982
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Performance library instance used in SMM phase.
+//
+// This library instance provides infrastructure for SMM drivers to log performance
+// data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
+// to log performance data. If both SMM PerformanceEx and Performance Protocol are not available,
+// it does not log any performance information.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Performance library instance used in the SMM phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance provides infrastructure for SMM drivers to log performance data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib to log performance data. If both SMM PerformanceEx and Performance Protocol are not available, it does not log any performance information."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 000000000..3a1772538
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,539 @@
+/** @file
+ Report Status Code Library for SMM Phase.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Protocol/SmmStatusCode.h>
+
+EFI_SMM_REPORT_STATUS_CODE mReportStatusCode = NULL;
+EFI_SMM_STATUS_CODE_PROTOCOL *mStatusCodeProtocol = 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_SMM_REPORT_STATUS_CODE
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID**)&mStatusCodeProtocol);
+ if (!EFI_ERROR (Status) && mStatusCodeProtocol != NULL) {
+ return mStatusCodeProtocol->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) (mStatusCodeProtocol, 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 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;
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ StatusCodeData = AllocatePool (sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize);
+ if (StatusCodeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // 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
+ //
+ 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/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
new file mode 100644
index 000000000..72496bfab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
@@ -0,0 +1,51 @@
+## @file
+# SMM report status code library.
+#
+# Retrieve status code and report status code in SMM phase.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmReportStatusCodeLib
+ MODULE_UNI_FILE = SmmReportStatusCodeLib.uni
+ FILE_GUID = 67089D19-B3D6-4d9e-A0EB-FEDC1F83A1EE
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_SMM_DRIVER SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ SmmServicesTableLib
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiSmmStatusCodeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni
new file mode 100644
index 000000000..2dadb0efd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SMM report status code library.
+//
+// Retrieve status code and report status code in SMM phase.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM report status code library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Retrieves status code and report status code in the SMM phase."
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.c b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.c
new file mode 100644
index 000000000..b76e8f0dc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.c
@@ -0,0 +1,106 @@
+/** @file
+ SMM driver instance of SmiHandlerProfile Library.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmiHandlerProfileLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Guid/SmiHandlerProfile.h>
+
+SMI_HANDLER_PROFILE_PROTOCOL *mSmiHandlerProfile;
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ a new SMI handler is registered, to SmmCore.
+
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param CallerAddress The address of the module who registers the SMI handler.
+ @param Context The context of the SMI handler.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+ @param ContextSize The size of the context in bytes.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+
+ @retval EFI_SUCCESS The information is recorded.
+ @retval EFI_UNSUPPORTED The feature is unsupported.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileRegisterHandler (
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ if (mSmiHandlerProfile != NULL) {
+ return mSmiHandlerProfile->RegisterHandler (mSmiHandlerProfile, HandlerGuid, Handler, CallerAddress, Context, ContextSize);
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ an existing SMI handler is unregistered, to SmmCore.
+
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param Context The context of the SMI handler.
+ If it is NOT NULL, it will be used to check what is registered.
+ @param ContextSize The size of the context in bytes.
+ If Context is NOT NULL, it will be used to check what is registered.
+
+ @retval EFI_SUCCESS The original record is removed.
+ @retval EFI_UNSUPPORTED The feature is unsupported.
+ @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileUnregisterHandler (
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ if (mSmiHandlerProfile != NULL) {
+ return mSmiHandlerProfile->UnregisterHandler (mSmiHandlerProfile, HandlerGuid, Handler, Context, ContextSize);
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The constructor function for SMI handler profile.
+
+ @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
+SmmSmiHandlerProfileLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gSmst->SmmLocateProtocol (
+ &gSmiHandlerProfileGuid,
+ NULL,
+ (VOID **) &mSmiHandlerProfile
+ );
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.inf b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.inf
new file mode 100644
index 000000000..1d738c708
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.inf
@@ -0,0 +1,41 @@
+## @file
+# SMM driver instance of SmiHandlerProfile Library.
+#
+# This library instance provides real functionality for SmmChildDispatcher module.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmSmiHandlerProfileLib
+ MODULE_UNI_FILE = SmmSmiHandlerProfileLib.uni
+ FILE_GUID = FC38CEAE-FB74-4049-A51C-68F0BA69DA7D
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmiHandlerProfileLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmSmiHandlerProfileLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmSmiHandlerProfileLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+
+[Guids]
+ gSmiHandlerProfileGuid ## CONSUMES ## GUID # Locate protocol
+
diff --git a/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.uni b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.uni
new file mode 100644
index 000000000..e90799f53
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// SMM driver instance of SmiHandlerProfile Library.
+//
+// This library instance provides real functionality for SmmChildDispatcher module.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM driver instance of SmiHandlerProfile Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance provides real functionality for SmmChildDispatcher module."
+
diff --git a/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c
new file mode 100644
index 000000000..b9c5b68de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c
@@ -0,0 +1,39 @@
+/** @file
+ This library is used by other modules to measure data to TPM.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/**
+ Tpm measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+TpmMeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ )
+{
+ //
+ // Do nothing, just return EFI_SUCCESS.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
new file mode 100644
index 000000000..c3be447d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
@@ -0,0 +1,29 @@
+## @file
+# Provides NULL TPM measurement function.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TpmMeasurementLibNull
+ FILE_GUID = 6DFD6E9F-9278-48D8-8F45-B6CFF2C2B69C
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TpmMeasurementLib|SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ MODULE_UNI_FILE = TpmMeasurementLibNull.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ TpmMeasurementLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni
new file mode 100644
index 000000000..0e3552973
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Provides NULL TPM measurement function.
+//
+// Provides NULL TPM measurement function.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides NULL TPM measurement function"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides NULL TPM measurement function."
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
new file mode 100644
index 000000000..aff620ad5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
@@ -0,0 +1,2587 @@
+/** @file
+ Library functions which relates with booting.
+
+Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+EFI_RAM_DISK_PROTOCOL *mRamDisk = NULL;
+
+EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
+EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;
+
+///
+/// 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.
+///
+EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
+EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
+
+/**
+
+ End Perf entry of BDS
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+BmEndOfBdsPerfCode (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Record the performance data for End of BDS
+ //
+ PERF_CROSSMODULE_END("BDS");
+
+ return ;
+}
+
+/**
+ The function registers the legacy boot support capabilities.
+
+ @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
+ @param LegacyBoot The function pointer to boot the legacy boot option.
+**/
+VOID
+EFIAPI
+EfiBootManagerRegisterLegacyBootSupport (
+ EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
+ EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
+ )
+{
+ mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
+ mBmLegacyBoot = LegacyBoot;
+}
+
+/**
+ Return TRUE when the boot option is auto-created instead of manually added.
+
+ @param BootOption Pointer to the boot option to check.
+
+ @retval TRUE The boot option is auto-created.
+ @retval FALSE The boot option is manually added.
+**/
+BOOLEAN
+BmIsAutoCreateBootOption (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
+ CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Find the boot option in the NV storage and return the option number.
+
+ @param OptionToFind Boot option to be checked.
+
+ @return The option number of the found boot option.
+
+**/
+UINTN
+BmFindBootOptionInVariable (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+ UINTN OptionNumber;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ OptionNumber = LoadOptionNumberUnassigned;
+
+ //
+ // Try to match the variable exactly if the option number is assigned
+ //
+ if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
+ UnicodeSPrint (
+ OptionName, sizeof (OptionName), L"%s%04x",
+ mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
+ );
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
+ if ((OptionToFind->Attributes == BootOption.Attributes) &&
+ (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
+ (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
+ (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
+ (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
+ ) {
+ OptionNumber = OptionToFind->OptionNumber;
+ }
+ EfiBootManagerFreeLoadOption (&BootOption);
+ }
+ }
+
+ //
+ // The option number assigned is either incorrect or unassigned.
+ //
+ if (OptionNumber == LoadOptionNumberUnassigned) {
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
+ if (Index != -1) {
+ OptionNumber = BootOptions[Index].OptionNumber;
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ }
+
+ return OptionNumber;
+}
+
+/**
+ Return the correct FV file path.
+ FV address may change across reboot. This routine promises the FV file device path is right.
+
+ @param FilePath The Memory Mapped Device Path to get the file buffer.
+
+ @return The updated FV Device Path pointint to the file.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmAdjustFvFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
+ EFI_HANDLE FvHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandles;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+
+ //
+ // Get the file buffer by using the exactly FilePath.
+ //
+ FvFileNode = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
+ if (!EFI_ERROR (Status)) {
+ return DuplicateDevicePath (FilePath);
+ }
+
+ //
+ // Only wide match other FVs if it's a memory mapped FV file path.
+ //
+ if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {
+ return NULL;
+ }
+
+ FvFileNode = NextDevicePathNode (FilePath);
+
+ //
+ // Firstly find the FV file in current FV
+ //
+ gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
+ FreePool (NewDevicePath);
+ if (FullPath != NULL) {
+ return FullPath;
+ }
+
+ //
+ // Secondly find the FV file in all other FVs
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandles
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ if (FvHandles[Index] == LoadedImage->DeviceHandle) {
+ //
+ // Skip current FV, it was handed in first step.
+ //
+ continue;
+ }
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
+ FullPath = BmAdjustFvFilePath (NewDevicePath);
+ FreePool (NewDevicePath);
+ if (FullPath != NULL) {
+ break;
+ }
+ }
+
+ if (FvHandles != NULL) {
+ FreePool (FvHandles);
+ }
+ return FullPath;
+}
+
+/**
+ Check if it's a Device Path pointing to FV file.
+
+ The function doesn't garentee the device path points to existing FV file.
+
+ @param DevicePath Input device path.
+
+ @retval TRUE The device path is a FV File Device Path.
+ @retval FALSE The device path is NOT a FV File Device Path.
+**/
+BOOLEAN
+BmIsFvFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ Node = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
+ return IsDevicePathEnd (NextDevicePathNode (DevicePath));
+ }
+ }
+ return FALSE;
+}
+
+/**
+ 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
+BmMatchUsbClass (
+ 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
+BmMatchUsbWwid (
+ 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 which match the specified short-form device path start with
+ USB Class or USB WWID device path. 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 DevicePath The device path that contains USB Class or USB WWID device path.
+ @param ParentDevicePathSize The length of the device path before the USB Class or
+ USB WWID device path.
+ @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
+
+ @retval NULL The matched USB IO handles cannot be found.
+ @retval other The matched USB IO handles.
+
+**/
+EFI_HANDLE *
+BmFindUsbDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN ParentDevicePathSize,
+ OUT UINTN *UsbIoHandleCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *UsbIoHandles;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINTN Index;
+ BOOLEAN Matched;
+
+ ASSERT (UsbIoHandleCount != NULL);
+
+ //
+ // Get all UsbIo Handles.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ UsbIoHandleCount,
+ &UsbIoHandles
+ );
+ if (EFI_ERROR (Status)) {
+ *UsbIoHandleCount = 0;
+ UsbIoHandles = NULL;
+ }
+
+ for (Index = 0; Index < *UsbIoHandleCount; ) {
+ //
+ // Get the Usb IO interface.
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoHandles[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
+ Matched = FALSE;
+ if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
+
+ //
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
+ //
+ if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
+ if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
+ BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
+ Matched = TRUE;
+ }
+ }
+ }
+
+ if (!Matched) {
+ (*UsbIoHandleCount) --;
+ CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
+ } else {
+ Index++;
+ }
+ }
+
+ return UsbIoHandles;
+}
+
+/**
+ Expand USB Class or USB WWID device path node to be full device path of a USB
+ device in platform.
+
+ 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 FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+ @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandUsbDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
+ )
+{
+ UINTN ParentDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ BOOLEAN GetNext;
+
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
+ RemainingDevicePath = NextDevicePathNode (ShortformNode);
+ Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ if (FilePath == NULL) {
+ //
+ // Out of memory.
+ //
+ continue;
+ }
+ NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);
+ FreePool (FilePath);
+ if (NextFullPath == NULL) {
+ //
+ // No BlockIo or SimpleFileSystem under FilePath.
+ //
+ continue;
+ }
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Expand File-path device path node to be full device path in platform.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandFileDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINTN MediaType;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ BOOLEAN GetNext;
+
+ EfiBootManagerConnectAll ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status)) {
+ HandleCount = 0;
+ Handles = NULL;
+ }
+
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ NextFullPath = NULL;
+ //
+ // Enumerate all removable media devices followed by all fixed media devices,
+ // followed by media devices which don't layer on block io.
+ //
+ for (MediaType = 0; MediaType < 3; MediaType++) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);
+ if (EFI_ERROR (Status)) {
+ BlockIo = NULL;
+ }
+ if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||
+ (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
+ (MediaType == 2 && BlockIo == NULL)
+ ) {
+ NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+ }
+ if (NextFullPath != NULL) {
+ break;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Expand URI device path node to be full device path in platform.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandUriDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+ BOOLEAN GetNext;
+
+ EfiBootManagerConnectAll ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status)) {
+ HandleCount = 0;
+ Handles = NULL;
+ }
+
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ for (Index = 0; Index < HandleCount; Index++) {
+ NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
+
+ if (NextFullPath == NULL) {
+ continue;
+ }
+
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ //
+ // Free the resource occupied by the RAM disk.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Save the partition DevicePath to the CachedDevicePath as the first instance.
+
+ @param CachedDevicePath The device path cache.
+ @param DevicePath The partition device path to be cached.
+**/
+VOID
+BmCachePartitionDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Count;
+
+ if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
+ FreePool (TempDevicePath);
+ }
+
+ if (*CachedDevicePath == NULL) {
+ *CachedDevicePath = DuplicateDevicePath (DevicePath);
+ return;
+ }
+
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ //
+ // 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 'HDDP' variable maybe become larger and larger.
+ //
+ Count = 0;
+ TempDevicePath = *CachedDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ //
+ // Parse one instance
+ //
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ Count++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+ //
+ if (Count == 12) {
+ SetDevicePathEndNode (TempDevicePath);
+ break;
+ }
+ }
+}
+
+/**
+ 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 FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+
+ @return The full device path pointing to the load option.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandPartitionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+ UINTN CachedDevicePathSize;
+ BOOLEAN NeedAdjust;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+
+ //
+ // Check if there is prestore 'HDDP' variable.
+ // If exist, search the front path which point to partition node in the variable instants.
+ // If fail to find or 'HDDP' not exist, reconnect all and search in all system
+ //
+ GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
+
+ //
+ // Delete the invalid 'HDDP' variable.
+ //
+ if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
+ FreePool (CachedDevicePath);
+ CachedDevicePath = NULL;
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ FullPath = NULL;
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ 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 (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
+ //
+ // Connect the device path instance, the device path point to hard drive media device path node
+ // e.g. ACPI() /PCI()/ATA()/Partition()
+ //
+ Status = EfiBootManagerConnectDevicePath (Instance, NULL);
+ if (!EFI_ERROR (Status)) {
+ TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
+ //
+ // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
+ // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
+ //
+ // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
+ // it may expand to two potienal full paths (nested partition, rarely happen):
+ // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
+ // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
+ // For simplicity, only #1 is returned.
+ //
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
+ FreePool (TempDevicePath);
+
+ if (FullPath != NULL) {
+ //
+ // Adjust the 'HDDP' instances sequence if the matched one is not first one.
+ //
+ if (NeedAdjust) {
+ BmCachePartitionDevicePath (&CachedDevicePath, Instance);
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
+ //
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+ }
+
+ FreePool (Instance);
+ FreePool (CachedDevicePath);
+ return FullPath;
+ }
+ }
+ }
+ //
+ // Come here means the first instance is not matched
+ //
+ NeedAdjust = TRUE;
+ FreePool(Instance);
+ } while (TempNewDevicePath != NULL);
+ }
+
+ //
+ // If we get here we fail to find or 'HDDP' not exist, and now we need
+ // to search all devices in the system for a matched partition
+ //
+ EfiBootManagerConnectAll ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+ if (EFI_ERROR (Status)) {
+ BlockIoHandleCount = 0;
+ BlockIoBuffer = NULL;
+ }
+ //
+ // Loop through all the device handles that support the BLOCK_IO Protocol
+ //
+ for (Index = 0; Index < BlockIoHandleCount; Index++) {
+ BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
+ if (BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
+ //
+ // Find the matched partition device path
+ //
+ TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
+ FreePool (TempDevicePath);
+
+ if (FullPath != NULL) {
+ BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
+
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
+ //
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+
+ break;
+ }
+ }
+ }
+
+ if (CachedDevicePath != NULL) {
+ FreePool (CachedDevicePath);
+ }
+ if (BlockIoBuffer != NULL) {
+ FreePool (BlockIoBuffer);
+ }
+ return FullPath;
+}
+
+/**
+ Expand the media device path which points to a BlockIo or SimpleFileSystem instance
+ by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
+
+ @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandMediaDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ BOOLEAN GetNext;
+
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ //
+ // Check whether the device is connected
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (IsDevicePathEnd (TempDevicePath));
+
+ NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ //
+ // For device path pointing to simple file system, it only expands to one full path.
+ //
+ if (GetNext) {
+ return NextFullPath;
+ } else {
+ FreePool (NextFullPath);
+ return NULL;
+ }
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // For device boot option only pointing 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);
+
+ //
+ // 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.
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ 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
+ //
+ NextFullPath = NULL;
+ Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
+ 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) - END_DEVICE_PATH_LENGTH;
+ //
+ // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
+ //
+ if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
+ NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+ }
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool (SimpleFileSystemHandles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Check whether Left and Right are the same without matching the specific
+ device path data in IP device path and URI device path node.
+
+ @retval TRUE Left and Right are the same.
+ @retval FALSE Left and Right are the different.
+**/
+BOOLEAN
+BmMatchHttpBootDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *Left,
+ IN EFI_DEVICE_PATH_PROTOCOL *Right
+ )
+{
+ for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
+ ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
+ ) {
+ if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
+ if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
+ return FALSE;
+ }
+
+ if (DevicePathSubType (Left) == MSG_DNS_DP) {
+ Left = NextDevicePathNode (Left);
+ }
+
+ if (DevicePathSubType (Right) == MSG_DNS_DP) {
+ Right = NextDevicePathNode (Right);
+ }
+
+ if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
+ ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
+ ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
+ ) {
+ return FALSE;
+ }
+ }
+ }
+ return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
+}
+
+/**
+ Get the file buffer from the file system produced by Load File instance.
+
+ @param LoadFileHandle The handle of LoadFile instance.
+ @param RamDiskHandle Return the RAM Disk handle.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandNetworkFileSystem (
+ IN EFI_HANDLE LoadFileHandle,
+ OUT EFI_HANDLE *RamDiskHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ Handles = NULL;
+ HandleCount = 0;
+ }
+
+ Handle = NULL;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Node = DevicePathFromHandle (Handles[Index]);
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status) &&
+ (Handle == LoadFileHandle) &&
+ (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
+ //
+ // Find the BlockIo instance populated from the LoadFile.
+ //
+ Handle = Handles[Index];
+ break;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ if (Index == HandleCount) {
+ Handle = NULL;
+ }
+
+ *RamDiskHandle = Handle;
+
+ if (Handle != NULL) {
+ //
+ // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
+ // But assume only one SimpleFileSystem can be found under the BlockIo.
+ //
+ return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ Return the RAM Disk device path created by LoadFile.
+
+ @param FilePath The source file path.
+
+ @return Callee-to-free RAM Disk device path
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetRamDiskDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_HANDLE Handle;
+
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status) &&
+ (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)
+ ) {
+
+ //
+ // Construct the device path pointing to RAM Disk
+ //
+ Node = NextDevicePathNode (Node);
+ RamDiskDevicePath = DuplicateDevicePath (FilePath);
+ ASSERT (RamDiskDevicePath != NULL);
+ SetDevicePathEndNode ((VOID *) ((UINTN) RamDiskDevicePath + ((UINTN) Node - (UINTN) FilePath)));
+ return RamDiskDevicePath;
+ }
+
+ return NULL;
+}
+
+/**
+ Return the buffer and buffer size occupied by the RAM Disk.
+
+ @param RamDiskDevicePath RAM Disk device path.
+ @param RamDiskSizeInPages Return RAM Disk size in pages.
+
+ @retval RAM Disk buffer.
+**/
+VOID *
+BmGetRamDiskMemoryInfo (
+ IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
+ OUT UINTN *RamDiskSizeInPages
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ UINT64 StartingAddr;
+ UINT64 EndingAddr;
+
+ ASSERT (RamDiskDevicePath != NULL);
+
+ *RamDiskSizeInPages = 0;
+
+ //
+ // Get the buffer occupied by RAM Disk.
+ //
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT ((DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP));
+ StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);
+ EndingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);
+ *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));
+ return (VOID *) (UINTN) StartingAddr;
+}
+
+/**
+ Destroy the RAM Disk.
+
+ The destroy operation includes to call RamDisk.Unregister to
+ unregister the RAM DISK from RAM DISK driver, free the memory
+ allocated for the RAM Disk.
+
+ @param RamDiskDevicePath RAM Disk device path.
+**/
+VOID
+BmDestroyRamDisk (
+ IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VOID *RamDiskBuffer;
+ UINTN RamDiskSizeInPages;
+
+ ASSERT (RamDiskDevicePath != NULL);
+
+ RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
+
+ //
+ // Destroy RAM Disk.
+ //
+ if (mRamDisk == NULL) {
+ Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *) &mRamDisk);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Status = mRamDisk->Unregister (RamDiskDevicePath);
+ ASSERT_EFI_ERROR (Status);
+ FreePages (RamDiskBuffer, RamDiskSizeInPages);
+}
+
+/**
+ Get the file buffer from the specified Load File instance.
+
+ @param LoadFileHandle The specified Load File instance.
+ @param FilePath The file path which will pass to LoadFile().
+
+ @return The full device path pointing to the load option buffer.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
+ IN EFI_HANDLE LoadFileHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+ VOID *FileBuffer;
+ EFI_HANDLE RamDiskHandle;
+ UINTN BufferSize;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+
+ Status = gBS->OpenProtocol (
+ LoadFileHandle,
+ &gEfiLoadFileProtocolGuid,
+ (VOID **) &LoadFile,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FileBuffer = NULL;
+ BufferSize = 0;
+ Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
+ if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ return NULL;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // The load option buffer is directly returned by LoadFile.
+ //
+ return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ }
+
+ //
+ // The load option resides in a RAM disk.
+ //
+ FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
+ if (FileBuffer == NULL) {
+ DEBUG_CODE (
+ EFI_DEVICE_PATH *LoadFilePath;
+ CHAR16 *LoadFileText;
+ CHAR16 *FileText;
+
+ LoadFilePath = DevicePathFromHandle (LoadFileHandle);
+ if (LoadFilePath == NULL) {
+ LoadFileText = NULL;
+ } else {
+ LoadFileText = ConvertDevicePathToText (LoadFilePath, FALSE, FALSE);
+ }
+ FileText = ConvertDevicePathToText (FilePath, FALSE, FALSE);
+
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: failed to allocate reserved pages: "
+ "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ (UINT64)BufferSize,
+ LoadFileText,
+ FileText
+ ));
+
+ if (FileText != NULL) {
+ FreePool (FileText);
+ }
+ if (LoadFileText != NULL) {
+ FreePool (LoadFileText);
+ }
+ );
+ return NULL;
+ }
+
+ Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
+ return NULL;
+ }
+
+ FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);
+ if (FullPath == NULL) {
+ //
+ // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
+ //
+ BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
+ }
+
+ return FullPath;
+}
+
+/**
+ Return the full device path pointing to the load option.
+
+ FilePath may:
+ 1. Exactly matches to a LoadFile instance.
+ 2. Cannot match to any LoadFile instance. Wide match is required.
+ In either case, the routine may return:
+ 1. A copy of FilePath when FilePath matches to a LoadFile instance and
+ the LoadFile returns a load option buffer.
+ 2. A new device path with IP and URI information updated when wide match
+ happens.
+ 3. A new device path pointing to a load option in RAM disk.
+ In either case, only one full device path is returned for a specified
+ FilePath.
+
+ @param FilePath The media device path pointing to a LoadFile instance.
+
+ @return The load option buffer.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFiles (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ //
+ // Get file buffer from load file instance.
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ //
+ // When wide match happens, pass full device path to LoadFile (),
+ // otherwise, pass remaining device path to LoadFile ().
+ //
+ FilePath = Node;
+ } else {
+ Handle = NULL;
+ //
+ // Use wide match algorithm to find one when
+ // cannot find a LoadFile instance to exactly match the FilePath
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ Handles = NULL;
+ HandleCount = 0;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
+ Handle = Handles[Index];
+ break;
+ }
+ }
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ }
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ return BmExpandLoadFile (Handle, FilePath);
+}
+
+/**
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+EFIAPI
+EfiBootManagerGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ *FullPath = NULL;
+
+ EfiBootManagerConnectDevicePath (FilePath, NULL);
+ return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);
+}
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+ BmGetNextLoadOptionBuffer() guarantees.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_STATUS Status;
+
+ ASSERT (FilePath != NULL);
+
+ //
+ // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
+ }
+
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ return BmExpandMediaDevicePath (FilePath, FullPath);
+ }
+
+ //
+ // Expand the short-form device path to full device path
+ //
+ if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
+ //
+ // Expand the Harddrive device path
+ //
+ if (FullPath == NULL) {
+ return BmExpandPartitionDevicePath (FilePath);
+ } else {
+ return NULL;
+ }
+ } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
+ //
+ // Expand the File-path device path
+ //
+ return BmExpandFileDevicePath (FilePath, FullPath);
+ } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MSG_URI_DP)) {
+ //
+ // Expand the URI device path
+ //
+ return BmExpandUriDevicePath (FilePath, FullPath);
+ } else {
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Only expand the USB WWID/Class device path
+ // when FilePath doesn't point to a physical UsbIo controller.
+ // Otherwise, infinite recursion will happen.
+ //
+ for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
+ break;
+ }
+ }
+
+ //
+ // Expand the USB WWID/Class device path
+ //
+ if (!IsDevicePathEnd (Node)) {
+ if (FilePath == Node) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ // For Boot Option device path which doesn't begin with the USB Class or
+ // USB WWID device path, it's not needed to connect again here.
+ //
+ BmConnectUsbShortFormDevicePath (FilePath);
+ }
+ return BmExpandUsbDevicePath (FilePath, FullPath, Node);
+ }
+ }
+ }
+
+ //
+ // For the below cases, FilePath only expands to one Full path.
+ // So just handle the case when FullPath == NULL.
+ //
+ if (FullPath != NULL) {
+ return NULL;
+ }
+
+ //
+ // Load option resides in FV.
+ //
+ if (BmIsFvFilePath (FilePath)) {
+ return BmAdjustFvFilePath (FilePath);
+ }
+
+ //
+ // Load option resides in Simple File System.
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status)) {
+ return DuplicateDevicePath (FilePath);
+ }
+
+ //
+ // Last chance to try: Load option may be loaded through LoadFile.
+ //
+ return BmExpandLoadFiles (FilePath);
+}
+
+/**
+ Check if it's a Device Path pointing to BootManagerMenu.
+
+ @param DevicePath Input device path.
+
+ @retval TRUE The device path is BootManagerMenu File Device Path.
+ @retval FALSE The device path is NOT BootManagerMenu File Device Path.
+**/
+BOOLEAN
+BmIsBootManagerMenuFilePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+)
+{
+ EFI_HANDLE FvHandle;
+ VOID *NameGuid;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
+ if (!EFI_ERROR (Status)) {
+ NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
+ if (NameGuid != NULL) {
+ return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
+ StartImage() failure.
+
+ @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
+ Service Driver Subclass. ErrorCode will be used to
+ compose the Value parameter for status code
+ reporting. Must be one of
+ EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
+ EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
+
+ @param[in] FailureStatus The failure status returned by the boot service
+ that should be reported.
+**/
+VOID
+BmReportLoadFailure (
+ IN UINT32 ErrorCode,
+ IN EFI_STATUS FailureStatus
+ )
+{
+ EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;
+
+ if (!ReportErrorCodeEnabled ()) {
+ return;
+ }
+
+ ASSERT (
+ (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||
+ (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
+ );
+
+ ZeroMem (&ExtendedData, sizeof (ExtendedData));
+ ExtendedData.ReturnStatus = FailureStatus;
+
+ REPORT_STATUS_CODE_EX (
+ (EFI_ERROR_CODE | EFI_ERROR_MINOR),
+ (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),
+ 0,
+ NULL,
+ NULL,
+ &ExtendedData.DataHeader + 1,
+ sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)
+ );
+}
+
+/**
+ Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
+ also signals the EFI ready to boot event. If the device path for the option
+ starts with a BBS device path a legacy boot is attempted via the registered
+ gLegacyBoot function. Short form device paths are also supported via this
+ rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
+ MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
+ If the BootOption Device Path fails the removable media boot algorithm
+ is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
+ is tried per processor type)
+
+ @param BootOption Boot Option to try and boot.
+ On return, BootOption->Status contains the boot status.
+ EFI_SUCCESS BootOption was booted
+ EFI_UNSUPPORTED A BBS device path was found with no valid callback
+ registered via EfiBootManagerInitialize().
+ EFI_NOT_FOUND The BootOption was not found on the system
+ !EFI_SUCCESS BootOption failed with this error status
+
+**/
+VOID
+EFIAPI
+EfiBootManagerBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ UINT16 Uint16;
+ UINTN OptionNumber;
+ UINTN OriginalOptionNumber;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+ VOID *FileBuffer;
+ UINTN FileSize;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ EFI_EVENT LegacyBootEvent;
+
+ if (BootOption == NULL) {
+ return;
+ }
+
+ if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
+ BootOption->Status = EFI_INVALID_PARAMETER;
+ return;
+ }
+
+ //
+ // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
+ //
+ OptionNumber = BmFindBootOptionInVariable (BootOption);
+ if (OptionNumber == LoadOptionNumberUnassigned) {
+ Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Save the BootOption->OptionNumber to restore later
+ //
+ OptionNumber = Uint16;
+ OriginalOptionNumber = BootOption->OptionNumber;
+ BootOption->OptionNumber = OptionNumber;
+ Status = EfiBootManagerLoadOptionToVariable (BootOption);
+ BootOption->OptionNumber = OriginalOptionNumber;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
+ BootOption->Status = Status;
+ return ;
+ }
+ }
+
+ //
+ // 2. Set BootCurrent
+ //
+ Uint16 = (UINT16) OptionNumber;
+ BmSetVariableAndReportStatusCodeOnError (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT16),
+ &Uint16
+ );
+
+ //
+ // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
+ // the boot option.
+ //
+ if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {
+ DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
+ BmStopHotkeyService (NULL, NULL);
+ } else {
+ EfiSignalEventReadyToBoot();
+ //
+ // Report Status Code to indicate ReadyToBoot was signalled
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+ //
+ // 4. Repair system through DriverHealth protocol
+ //
+ BmRepairAllControllers (0);
+ }
+
+ PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+
+ //
+ // 5. Adjust the different type memory page number just before booting
+ // and save the updated info into the variable for next boot to use
+ //
+ BmSetMemoryTypeInformationVariable (
+ (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
+ );
+
+ //
+ // 6. Load EFI boot option to ImageHandle
+ //
+ DEBUG_CODE_BEGIN ();
+ if (BootOption->Description == NULL) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
+ } else {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
+ }
+ DEBUG_CODE_END ();
+
+ ImageHandle = NULL;
+ RamDiskDevicePath = NULL;
+ if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
+ Status = EFI_NOT_FOUND;
+ FilePath = NULL;
+ EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);
+ if (FileBuffer != NULL) {
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
+
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FilePath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ }
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+ if (FilePath != NULL) {
+ FreePool (FilePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ //
+ // Destroy the RAM disk
+ //
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+ //
+ // Report Status Code with the failure status to indicate that the failure to load boot option
+ //
+ BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);
+ BootOption->Status = Status;
+ return;
+ }
+ }
+
+ //
+ // Check to see if we should legacy BOOT. If yes then do the legacy boot
+ // Write boot to OS performance data for Legacy boot
+ //
+ if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
+ if (mBmLegacyBoot != NULL) {
+ //
+ // 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,
+ BmEndOfBdsPerfCode,
+ NULL,
+ &LegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ );
+
+ mBmLegacyBoot (BootOption);
+ } else {
+ BootOption->Status = EFI_UNSUPPORTED;
+ }
+
+ PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+ return;
+ }
+
+ //
+ // Provide the image with its load options
+ //
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (!BmIsAutoCreateBootOption (BootOption)) {
+ ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
+ ImageInfo->LoadOptions = BootOption->OptionalData;
+ }
+
+ //
+ // 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 5 minutes period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ //
+ // Write boot to OS performance data for UEFI boot
+ //
+ PERF_CODE (
+ BmEndOfBdsPerfCode (NULL, NULL);
+ );
+
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
+
+ Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
+ BootOption->Status = Status;
+
+ //
+ // Destroy the RAM disk
+ //
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status Code with the failure status to indicate that boot failure
+ //
+ BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);
+ }
+ PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+ //
+ // Set Logo status invalid after trying one boot option
+ //
+ BootLogo = NULL;
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
+ Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Clear Boot Current
+ //
+ Status = gRT->SetVariable (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
+ // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
+ //
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+}
+
+/**
+ 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
+BmMatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ HARDDRIVE_DEVICE_PATH *Node;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Match all the partition device path nodes including the nested partition nodes
+ //
+ while (!IsDevicePathEnd (BlockIoDevicePath)) {
+ if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node
+ //
+ Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
+
+ //
+ // Match Signature and PartitionNumber.
+ // Unused bytes in Signature are initiaized with zeros.
+ //
+ if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
+ (Node->MBRType == HardDriveDevicePath->MBRType) &&
+ (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
+ (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
+ return TRUE;
+ }
+ }
+
+ BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
+ }
+
+ return FALSE;
+}
+
+/**
+ Emuerate all possible bootable medias in the following order:
+ 1. Removable BlockIo - The boot option only points to the removable media
+ device, like USB key, DVD, Floppy etc.
+ 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
+ like HardDisk.
+ 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
+ SimpleFileSystem Protocol, but not supporting BlockIo
+ protocol.
+ 4. LoadFile - The boot option points to the media supporting
+ LoadFile protocol.
+ Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
+
+ @param BootOptionCount Return the boot option count which has been found.
+
+ @retval Pointer to the boot option array.
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+BmEnumerateBootOptions (
+ UINTN *BootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Removable;
+ UINTN Index;
+ CHAR16 *Description;
+
+ ASSERT (BootOptionCount != NULL);
+
+ *BootOptionCount = 0;
+ BootOptions = NULL;
+
+ //
+ // Parse removable block io followed by fixed block io
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+
+ for (Removable = 0; Removable < 2; Removable++) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Skip the logical partitions
+ //
+ if (BlkIo->Media->LogicalPartition) {
+ continue;
+ }
+
+ //
+ // Skip the fixed block io then the removable block io
+ //
+ if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
+ continue;
+ }
+
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Description);
+ }
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ //
+ // Parse simple file system not based on block io
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
+ //
+ continue;
+ }
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Description);
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ //
+ // Parse load file protocol
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
+ //
+ if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
+ continue;
+ }
+
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Description);
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
+ return BootOptions;
+}
+
+/**
+ The function enumerates all boot options, creates them and registers them in the BootOrder variable.
+**/
+VOID
+EFIAPI
+EfiBootManagerRefreshAllBootOption (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
+ UINTN NvBootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *UpdatedBootOptions;
+ UINTN UpdatedBootOptionCount;
+ UINTN Index;
+ EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;
+
+ //
+ // Optionally refresh the legacy boot option
+ //
+ if (mBmRefreshLegacyBootOption != NULL) {
+ mBmRefreshLegacyBootOption ();
+ }
+
+ BootOptions = BmEnumerateBootOptions (&BootOptionCount);
+
+ //
+ // Mark the boot option as added by BDS by setting OptionalData to a special GUID
+ //
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
+ BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
+ }
+
+ //
+ // Locate Platform Boot Options Protocol
+ //
+ Status = gBS->LocateProtocol (&gEdkiiPlatformBootManagerProtocolGuid,
+ NULL,
+ (VOID **)&PlatformBootManager);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If found, call platform specific refresh to all auto enumerated and NV
+ // boot options.
+ //
+ Status = PlatformBootManager->RefreshAllBootOptions ((CONST EFI_BOOT_MANAGER_LOAD_OPTION *)BootOptions,
+ (CONST UINTN)BootOptionCount,
+ &UpdatedBootOptions,
+ &UpdatedBootOptionCount);
+ if (!EFI_ERROR (Status)) {
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ BootOptions = UpdatedBootOptions;
+ BootOptionCount = UpdatedBootOptionCount;
+ }
+ }
+
+ NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
+
+ //
+ // Remove invalid EFI boot options from NV
+ //
+ for (Index = 0; Index < NvBootOptionCount; Index++) {
+ if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
+ ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
+ ) {
+ //
+ // Only check those added by BDS
+ // so that the boot options added by end-user or OS installer won't be deleted
+ //
+ if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {
+ Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+
+ //
+ // Add new EFI boot options to NV
+ //
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {
+ EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
+ //
+ // Try best to add the boot options so continue upon failure.
+ //
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
+}
+
+/**
+ This function is called to get or create the boot option for the Boot Manager Menu.
+
+ The Boot Manager Menu is shown after successfully booting a boot option.
+ Assume the BootManagerMenuFile is in the same FV as the module links to this library.
+
+ @param BootOption Return the boot option of the Boot Manager Menu
+
+ @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
+ @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
+ @retval others Return status of gRT->SetVariable (). BootOption still points
+ to the Boot Manager Menu even the Status is not EFI_SUCCESS
+ and EFI_NOT_FOUND.
+**/
+EFI_STATUS
+BmRegisterBootManagerMenu (
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Description;
+ UINTN DescriptionLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+ VOID *Data;
+ UINTN DataSize;
+
+ DevicePath = NULL;
+ Description = NULL;
+ //
+ // Try to find BootManagerMenu from LoadFile protocol
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
+ DevicePath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
+ Description = BmGetBootDescription (Handles[Index]);
+ break;
+ }
+ }
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ if (DevicePath == NULL) {
+ Data = NULL;
+ Status = GetSectionFromFv (
+ PcdGetPtr (PcdBootManagerMenuFile),
+ EFI_SECTION_PE32,
+ 0,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get BootManagerMenu application's description from EFI User Interface Section.
+ //
+ Status = GetSectionFromFv (
+ PcdGetPtr (PcdBootManagerMenuFile),
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &Description,
+ &DescriptionLength
+ );
+ if (EFI_ERROR (Status)) {
+ Description = NULL;
+ }
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (LoadedImage->DeviceHandle),
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
+ (Description != NULL) ? Description : L"Boot Manager Menu",
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+ if (Description != NULL) {
+ FreePool (Description);
+ }
+
+ DEBUG_CODE (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ );
+
+ return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
+}
+
+/**
+ Return the boot option corresponding to the Boot Manager Menu.
+ It may automatically create one if the boot option hasn't been created yet.
+
+ @param BootOption Return the Boot Manager Menu.
+
+ @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
+ @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
+ @retval others Return status of gRT->SetVariable (). BootOption still points
+ to the Boot Manager Menu even the Status is not EFI_SUCCESS
+ and EFI_NOT_FOUND.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerGetBootManagerMenu (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN Index;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ BootOptions[Index].OptionNumber,
+ BootOptions[Index].OptionType,
+ BootOptions[Index].Attributes,
+ BootOptions[Index].Description,
+ BootOptions[Index].FilePath,
+ BootOptions[Index].OptionalData,
+ BootOptions[Index].OptionalDataSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ break;
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+
+ //
+ // Automatically create the Boot#### for Boot Manager Menu when not found.
+ //
+ if (Index == BootOptionCount) {
+ return BmRegisterBootManagerMenu (BootOption);
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+ BmGetNextLoadOptionBuffer() guarantees.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+EfiBootManagerGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ return BmGetNextLoadOptionDevicePath(FilePath, FullPath);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
new file mode 100644
index 000000000..aa891feb1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
@@ -0,0 +1,875 @@
+/** @file
+ Library functions which relate with boot option description.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+#define VENDOR_IDENTIFICATION_OFFSET 3
+#define VENDOR_IDENTIFICATION_LENGTH 8
+#define PRODUCT_IDENTIFICATION_OFFSET 11
+#define PRODUCT_IDENTIFICATION_LENGTH 16
+
+CONST UINT16 mBmUsbLangId = 0x0409; // English
+CHAR16 mBmUefiPrefix[] = L"UEFI ";
+
+LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval MessageAtapiBoot 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 MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SATA_DP.
+ @retval MessageScsiBoot 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 MessageUsbBoot 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 BmMiscBoot If tiven device path doesn't match the above condition.
+
+**/
+BM_BOOT_TYPE
+BmDevicePathType (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+
+ ASSERT (DevicePath != NULL);
+
+ for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
+ switch (DevicePathType (Node)) {
+
+ case ACPI_DEVICE_PATH:
+ if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
+ return BmAcpiFloppyBoot;
+ }
+ break;
+
+ case HARDWARE_DEVICE_PATH:
+ if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
+ return BmHardwareDeviceBoot;
+ }
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+ //
+ // Skip LUN device node
+ //
+ NextNode = Node;
+ do {
+ NextNode = NextDevicePathNode (NextNode);
+ } while (
+ (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
+ );
+
+ //
+ // If the device path not only point to driver device, it is not a messaging device path,
+ //
+ if (!IsDevicePathEndType (NextNode)) {
+ continue;
+ }
+
+ switch (DevicePathSubType (Node)) {
+ case MSG_ATAPI_DP:
+ return BmMessageAtapiBoot;
+ break;
+
+ case MSG_SATA_DP:
+ return BmMessageSataBoot;
+ break;
+
+ case MSG_USB_DP:
+ return BmMessageUsbBoot;
+ break;
+
+ case MSG_SCSI_DP:
+ return BmMessageScsiBoot;
+ break;
+ }
+ }
+ }
+
+ return BmMiscBoot;
+}
+
+/**
+ Eliminate the extra spaces in the Str to one space.
+
+ @param Str Input string info.
+**/
+VOID
+BmEliminateExtraSpaces (
+ IN CHAR16 *Str
+ )
+{
+ UINTN Index;
+ UINTN ActualIndex;
+
+ for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
+ if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
+ Str[ActualIndex++] = Str[Index];
+ }
+ }
+ Str[ActualIndex] = L'\0';
+}
+
+/**
+ Try to get the controller's ATA/ATAPI description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetDescriptionFromDiskInfo (
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 BufferSize;
+ EFI_ATAPI_IDENTIFY_DATA IdentifyData;
+ EFI_SCSI_INQUIRY_DATA InquiryData;
+ CHAR16 *Description;
+ UINTN Length;
+ CONST UINTN ModelNameLength = 40;
+ CONST UINTN SerialNumberLength = 20;
+ CHAR8 *StrPtr;
+ UINT8 Temp;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Description = NULL;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
+ CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
+ Status = DiskInfo->Identify (
+ DiskInfo,
+ &IdentifyData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+ for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
+ Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];
+ Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
+ }
+
+ Length = Index;
+ Description[Length++] = L' ';
+
+ for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
+ Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];
+ Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
+ }
+ Length += Index;
+ Description[Length++] = L'\0';
+ ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
+ BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ &InquiryData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+
+ //
+ // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
+ // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
+ // Here combine the vendor identification and product identification to the description.
+ //
+ StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
+ Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
+
+ //
+ // Add one space at the middle of vendor information and product information.
+ //
+ Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
+
+ StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
+ StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+
+ while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+ if (IsDevicePathEnd (DevicePath)) {
+ return NULL;
+ }
+
+ if (DevicePathSubType (DevicePath) == MSG_SD_DP) {
+ Description = L"SD Device";
+ } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {
+ Description = L"eMMC Device";
+ } else {
+ return NULL;
+ }
+
+ Description = AllocateCopyPool (StrSize (Description), Description);
+ }
+
+ return Description;
+}
+
+/**
+ Try to get the controller's USB description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetUsbDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ CHAR16 NullChar;
+ CHAR16 *Manufacturer;
+ CHAR16 *Product;
+ CHAR16 *SerialNumber;
+ CHAR16 *Description;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ UINTN DescMaxSize;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ NullChar = L'\0';
+
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrManufacturer,
+ &Manufacturer
+ );
+ if (EFI_ERROR (Status)) {
+ Manufacturer = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrProduct,
+ &Product
+ );
+ if (EFI_ERROR (Status)) {
+ Product = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrSerialNumber,
+ &SerialNumber
+ );
+ if (EFI_ERROR (Status)) {
+ SerialNumber = &NullChar;
+ }
+
+ if ((Manufacturer == &NullChar) &&
+ (Product == &NullChar) &&
+ (SerialNumber == &NullChar)
+ ) {
+ return NULL;
+ }
+
+ DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
+ Description = AllocateZeroPool (DescMaxSize);
+ ASSERT (Description != NULL);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);
+
+ if (Manufacturer != &NullChar) {
+ FreePool (Manufacturer);
+ }
+ if (Product != &NullChar) {
+ FreePool (Product);
+ }
+ if (SerialNumber != &NullChar) {
+ FreePool (SerialNumber);
+ }
+
+ BmEliminateExtraSpaces (Description);
+
+ return Description;
+}
+
+/**
+ Return the description for network boot device.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetNetworkDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ MAC_ADDR_DEVICE_PATH *Mac;
+ VLAN_DEVICE_PATH *Vlan;
+ EFI_DEVICE_PATH_PROTOCOL *Ip;
+ EFI_DEVICE_PATH_PROTOCOL *Uri;
+ CHAR16 *Description;
+ UINTN DescriptionSize;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ gImageHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ gImageHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status) || (DevicePath == NULL)) {
+ return NULL;
+ }
+
+ //
+ // The PXE device path is like:
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
+ //
+ // The HTTP device path is like:
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
+ //
+ while (!IsDevicePathEnd (DevicePath) &&
+ ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))
+ ) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (IsDevicePathEnd (DevicePath)) {
+ return NULL;
+ }
+
+ Mac = (MAC_ADDR_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+
+ //
+ // Locate the optional Vlan node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_VLAN_DP)
+ ) {
+ Vlan = (VLAN_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Vlan = NULL;
+ }
+
+ //
+ // Skip the optional Wi-Fi node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_WIFI_DP)
+ ) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // Locate the IP node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||
+ (DevicePathSubType (DevicePath) == MSG_IPv6_DP))
+ ) {
+ Ip = DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Ip = NULL;
+ }
+
+ //
+ // Skip the optional DNS node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_DNS_DP)
+ ) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // Locate the URI node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_URI_DP)
+ ) {
+ Uri = DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Uri = NULL;
+ }
+
+ //
+ // Build description like below:
+ // "PXEv6 (MAC:112233445566 VLAN1)"
+ // "HTTPv4 (MAC:112233445566)"
+ //
+ DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");
+ Description = AllocatePool (DescriptionSize);
+ ASSERT (Description != NULL);
+ UnicodeSPrint (
+ Description, DescriptionSize,
+ (Vlan == NULL) ?
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
+ (Uri == NULL) ? L"PXE" : L"HTTP",
+ ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,
+ Mac->MacAddress.Addr[0], Mac->MacAddress.Addr[1], Mac->MacAddress.Addr[2],
+ Mac->MacAddress.Addr[3], Mac->MacAddress.Addr[4], Mac->MacAddress.Addr[5],
+ (Vlan == NULL) ? 0 : Vlan->VlanId
+ );
+ return Description;
+}
+
+/**
+ Return the boot description for LoadFile
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetLoadFileDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ CHAR16 *Description;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get the file name
+ //
+ Description = NULL;
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);
+ if (!EFI_ERROR (Status)) {
+ DevicePathNode = FilePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ if (DevicePathNode->Type == MEDIA_DEVICE_PATH && DevicePathNode->SubType == MEDIA_FILEPATH_DP) {
+ Description = (CHAR16 *)(DevicePathNode + 1);
+ break;
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ }
+
+ if (Description != NULL) {
+ return AllocateCopyPool (StrSize (Description), Description);
+ }
+
+ return NULL;
+}
+
+/**
+ Return the boot description for NVME boot device.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetNvmeDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;
+ EFI_DEV_PATH_PTR DevicePath;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ NVME_ADMIN_CONTROLLER_DATA ControllerData;
+ CHAR16 *Description;
+ CHAR16 *Char;
+ UINTN Index;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath.DevPath);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);
+ if (EFI_ERROR (Status) ||
+ (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP)) {
+ //
+ // Do not return description when the Handle is not a child of NVME controller.
+ //
+ return NULL;
+ }
+
+ //
+ // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **) &NvmePassthru);
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
+ //
+ Command.Nsid = 0;
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = &ControllerData;
+ CommandPacket.TransferLength = sizeof (ControllerData);
+ CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a controller
+ //
+ Command.Cdw10 = 1;
+ Command.Flags = CDW10_VALID;
+
+ Status = NvmePassthru->PassThru (
+ NvmePassthru,
+ 0,
+ &CommandPacket,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Description = AllocateZeroPool (
+ (ARRAY_SIZE (ControllerData.Mn) + 1
+ + ARRAY_SIZE (ControllerData.Sn) + 1
+ + MAXIMUM_VALUE_CHARACTERS + 1
+ ) * sizeof (CHAR16));
+ if (Description != NULL) {
+ Char = Description;
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {
+ *(Char++) = (CHAR16) ControllerData.Mn[Index];
+ }
+ *(Char++) = L' ';
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {
+ *(Char++) = (CHAR16) ControllerData.Sn[Index];
+ }
+ *(Char++) = L' ';
+ UnicodeValueToStringS (
+ Char, sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),
+ 0, DevicePath.NvmeNamespace->NamespaceId, 0
+ );
+ BmEliminateExtraSpaces (Description);
+ }
+
+ return Description;
+}
+
+/**
+ Return the boot description for the controller based on the type.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetMiscDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Description;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+
+ switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
+ case BmAcpiFloppyBoot:
+ Description = L"Floppy";
+ break;
+
+ case BmMessageAtapiBoot:
+ case BmMessageSataBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Assume a removable SATA device should be the DVD/CD device
+ //
+ Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
+ break;
+
+ case BmMessageUsbBoot:
+ Description = L"USB Device";
+ break;
+
+ case BmMessageScsiBoot:
+ Description = L"SCSI Device";
+ break;
+
+ case BmHardwareDeviceBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
+ } else {
+ Description = L"Misc Device";
+ }
+ break;
+
+ default:
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);
+ if (!EFI_ERROR (Status)) {
+ Description = L"Non-Block Boot Device";
+ } else {
+ Description = L"Misc Device";
+ }
+ break;
+ }
+
+ return AllocateCopyPool (StrSize (Description), Description);
+}
+
+/**
+ Register the platform provided boot description handler.
+
+ @param Handler The platform provided boot description handler
+
+ @retval EFI_SUCCESS The handler was registered successfully.
+ @retval EFI_ALREADY_STARTED The handler was already registered.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterBootDescriptionHandler (
+ IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ ) {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ if (Entry->Handler == Handler) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
+ Entry->Handler = Handler;
+ InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
+ return EFI_SUCCESS;
+}
+
+BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
+ BmGetUsbDescription,
+ BmGetDescriptionFromDiskInfo,
+ BmGetNetworkDescription,
+ BmGetLoadFileDescription,
+ BmGetNvmeDescription,
+ BmGetMiscDescription
+};
+
+/**
+ Return the boot description for the controller.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetBootDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+ CHAR16 *Description;
+ CHAR16 *DefaultDescription;
+ CHAR16 *Temp;
+ UINTN Index;
+
+ //
+ // Firstly get the default boot description
+ //
+ DefaultDescription = NULL;
+ for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {
+ DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);
+ if (DefaultDescription != NULL) {
+ //
+ // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
+ // ONLY for core provided boot description handler.
+ //
+ Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
+ ASSERT (Temp != NULL);
+ StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);
+ StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);
+ FreePool (DefaultDescription);
+ DefaultDescription = Temp;
+ break;
+ }
+ }
+ ASSERT (DefaultDescription != NULL);
+
+ //
+ // Secondly query platform for the better boot description
+ //
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ ) {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ Description = Entry->Handler (Handle, DefaultDescription);
+ if (Description != NULL) {
+ FreePool (DefaultDescription);
+ return Description;
+ }
+ }
+
+ return DefaultDescription;
+}
+
+/**
+ Enumerate all boot option descriptions and append " 2"/" 3"/... to make
+ unique description.
+
+ @param BootOptions Array of boot options.
+ @param BootOptionCount Count of boot options.
+**/
+VOID
+BmMakeBootOptionDescriptionUnique (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ UINTN BootOptionCount
+ )
+{
+ UINTN Base;
+ UINTN Index;
+ UINTN DescriptionSize;
+ UINTN MaxSuffixSize;
+ BOOLEAN *Visited;
+ UINTN MatchCount;
+
+ if (BootOptionCount == 0) {
+ return;
+ }
+
+ //
+ // Calculate the maximum buffer size for the number suffix.
+ // The initial sizeof (CHAR16) is for the blank space before the number.
+ //
+ MaxSuffixSize = sizeof (CHAR16);
+ for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
+ MaxSuffixSize += sizeof (CHAR16);
+ }
+
+ Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
+ ASSERT (Visited != NULL);
+
+ for (Base = 0; Base < BootOptionCount; Base++) {
+ if (!Visited[Base]) {
+ MatchCount = 1;
+ Visited[Base] = TRUE;
+ DescriptionSize = StrSize (BootOptions[Base].Description);
+ for (Index = Base + 1; Index < BootOptionCount; Index++) {
+ if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {
+ Visited[Index] = TRUE;
+ MatchCount++;
+ FreePool (BootOptions[Index].Description);
+ BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
+ UnicodeSPrint (
+ BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,
+ L"%s %d",
+ BootOptions[Base].Description, MatchCount
+ );
+ }
+ }
+ }
+ }
+
+ FreePool (Visited);
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
new file mode 100644
index 000000000..d4a263b8f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
@@ -0,0 +1,315 @@
+/** @file
+ Library functions which relate with connecting the device.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+/**
+ Connect all the drivers to all the controllers.
+
+ This function makes sure all the current system drivers manage the correspoinding
+ controllers if have. And at the same time, makes sure all the system controllers
+ have driver to manage it if have.
+**/
+VOID
+BmConnectAllDriversToAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ do {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The above code may have made new DXE drivers show up.
+ // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch ();
+
+ } while (!EFI_ERROR (Status));
+}
+
+/**
+ 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
+EfiBootManagerConnectAll (
+ VOID
+ )
+{
+ //
+ // Connect the platform console first
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+
+ //
+ // Generic way to connect all the drivers
+ //
+ BmConnectAllDriversToAllControllers ();
+
+ //
+ // Here we have the assumption that we have already had
+ // platform default console
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+}
+
+/**
+ 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
+ @param MatchingHandle Return the controller handle closest to the DevicePathToConnect
+
+ @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.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect,
+ OUT EFI_HANDLE *MatchingHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ EFI_TPL CurrentTpl;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrentTpl = EfiGetCurrentTpl ();
+ //
+ // 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 = DevicePathToConnect;
+ 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) {
+ 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.
+ //
+ // If ConnectController fails to find a driver, 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
+ //
+ Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+ if (MatchingHandle != NULL) {
+ *MatchingHandle = Handle;
+ }
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));
+
+ return Status;
+}
+
+/**
+ 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().
+**/
+VOID
+EFIAPI
+EfiBootManagerDisconnectAll (
+ VOID
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Disconnect all
+ //
+ gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+}
+
+/**
+ Connect the specific Usb device which match the short form device path,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param DevicePath 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 DevicePath is NULL pointer.
+ DevicePath is not a USB device path.
+
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+BmConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
+ ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
+ ) {
+ 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,
+ &HandleCount,
+ &Handles
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[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) &&
+ ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
+ ) {
+ Status = gBS->ConnectController (
+ Handles[Index],
+ NULL,
+ DevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR(Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ }
+
+ return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
new file mode 100644
index 000000000..d89331784
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
@@ -0,0 +1,761 @@
+/** @file
+ Library functions which contain all the code to connect console device.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+CHAR16 *mConVarName[] = {
+ L"ConIn",
+ L"ConOut",
+ L"ErrOut",
+ L"ConInDev",
+ L"ConOutDev",
+ L"ErrOutDev"
+};
+
+/**
+ Search out the video controller.
+
+ @return PCI device path of the video controller.
+**/
+EFI_HANDLE
+BmGetVideoController (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN RootBridgeHandleCount;
+ EFI_HANDLE *RootBridgeHandleBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN RootBridgeIndex;
+ UINTN Index;
+ EFI_HANDLE VideoController;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ //
+ // Make all the PCI_IO protocols show up
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &RootBridgeHandleCount,
+ &RootBridgeHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {
+ return NULL;
+ }
+
+ VideoController = NULL;
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
+
+ //
+ // Start to check all the pci io to find the first video controller
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check for all video controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {
+ // TODO: use IS_PCI_DISPLAY??
+ VideoController = HandleBuffer[Index];
+ break;
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+
+ if (VideoController != NULL) {
+ break;
+ }
+ }
+ FreePool (RootBridgeHandleBuffer);
+
+ return VideoController;
+}
+
+/**
+ Query all the children of VideoController and return the device paths of all the
+ children that support GraphicsOutput protocol.
+
+ @param VideoController PCI handle of video controller.
+
+ @return Device paths of all the children that support GraphicsOutput protocol.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+EfiBootManagerGetGopDevicePath (
+ IN EFI_HANDLE VideoController
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_GUID **ProtocolBuffer;
+ UINTN ProtocolBufferCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *Previous;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *GopPool;
+ EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath;
+
+
+ Status = gBS->ProtocolsPerHandle (
+ VideoController,
+ &ProtocolBuffer,
+ &ProtocolBufferCount
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ GopPool = NULL;
+
+ for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
+ Status = gBS->OpenProtocolInformation (
+ VideoController,
+ ProtocolBuffer[ProtocolIndex],
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ //
+ // Query all the children
+ //
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Previous = NULL;
+ for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
+ Previous = Next;
+ }
+ ASSERT (Previous != NULL);
+
+ if (DevicePathType (Previous) == ACPI_DEVICE_PATH && DevicePathSubType (Previous) == ACPI_ADR_DP) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Append the device path to GOP pool when there is GOP protocol installed.
+ //
+ TempDevicePath = GopPool;
+ GopPool = AppendDevicePathInstance (GopPool, DevicePath);
+ gBS->FreePool (TempDevicePath);
+ }
+ }
+
+ if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {
+ //
+ // Recursively look for GOP child in this frame buffer handle
+ //
+ DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));
+ TempDevicePath = GopPool;
+ ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
+ GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
+ gBS->FreePool (ReturnDevicePath);
+ gBS->FreePool (TempDevicePath);
+ }
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+
+ FreePool (ProtocolBuffer);
+
+ return GopPool;
+}
+
+/**
+ Connect the platform active active video controller.
+
+ @param VideoController PCI handle of video controller.
+
+ @retval EFI_NOT_FOUND There is no active video controller.
+ @retval EFI_SUCCESS The video controller is connected.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectVideoController (
+ EFI_HANDLE VideoController OPTIONAL
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Gop;
+
+ if (VideoController == NULL) {
+ //
+ // Get the platform vga device
+ //
+ VideoController = BmGetVideoController ();
+ }
+
+ if (VideoController == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try to connect the PCI device path, so that GOP driver could start on this
+ // device and create child handles with GraphicsOutput Protocol installed
+ // on them, then we get device paths of these child handles and select
+ // them as possible console device.
+ //
+ gBS->ConnectController (VideoController, NULL, NULL, FALSE);
+
+ Gop = EfiBootManagerGetGopDevicePath (VideoController);
+ if (Gop == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);
+ FreePool (Gop);
+
+ //
+ // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.
+ //
+ return gBS->ConnectController (VideoController, NULL, NULL, 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
+BmUpdateSystemTableConsole (
+ 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;
+ EFI_DEVICE_PATH_PROTOCOL *FullInstance;
+ 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
+ //
+ GetEfiGlobalVariable2 (VarName, (VOID **) &VarConsole, NULL);
+ 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) {
+ DEBUG ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
+ // We should not ASSERT when all the console devices are removed.
+ // ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ FreePool (FullDevicePath);
+ return FALSE;
+ }
+
+ //
+ // Find console device handle by device path instance
+ //
+ FullInstance = Instance;
+ Status = gBS->LocateDevicePath (
+ ConsoleGuid,
+ &Instance,
+ &NewHandle
+ );
+ FreePool (FullInstance);
+ 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);
+ }
+ }
+ FreePool (FullDevicePath);
+ return TRUE;
+ }
+ }
+
+ } while (Instance != NULL);
+
+ //
+ // No any available console devcie found.
+ //
+ FreePool (FullDevicePath);
+ return FALSE;
+}
+
+/**
+ This function updates the console variable based on ConVarName. It can
+ add or remove one specific console device path from the variable
+
+ @param ConsoleType ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
+ @param CustomizedConDevicePath The console device path to be added to
+ the console variable. Cannot be multi-instance.
+ @param ExclusiveDevicePath The console device path to be removed
+ from the console variable. 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.
+ @retval others Return status of RT->SetVariable().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerUpdateConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+
+ if (ConsoleType >= ARRAY_SIZE (mConVarName)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 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
+ //
+ GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &VarConsole, NULL);
+ //
+ // 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 = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
+ }
+ //
+ // Try to append customized device path to NewDevicePath.
+ //
+ if (CustomizedConDevicePath != NULL) {
+ if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
+ //
+ // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
+ //
+ NewDevicePath = BmDelPartMatchInstance (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);
+ }
+ }
+ }
+
+ //
+ // Finally, Update the variable of the default console by NewDevicePath
+ //
+ Status = gRT->SetVariable (
+ mConVarName[ConsoleType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+ | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),
+ GetDevicePathSize (NewDevicePath),
+ NewDevicePath
+ );
+
+ 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 ConsoleType.
+
+ @param ConsoleType ConIn, ConOut or 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
+EfiBootManagerConnectConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ UINTN Size;
+ BOOLEAN DeviceExist;
+ EFI_HANDLE Handle;
+
+ if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ DeviceExist = FALSE;
+ Handle = NULL;
+
+ //
+ // Check if the console variable exist
+ //
+ GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &StartDevicePath, NULL);
+ 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 = BmConnectUsbShortFormDevicePath (Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ }
+ } else {
+ for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
+ if (DevicePathType (Next) == ACPI_DEVICE_PATH && DevicePathSubType (Next) == ACPI_ADR_DP) {
+ break;
+ } else if (DevicePathType (Next) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (Next) == HW_CONTROLLER_DP &&
+ DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH &&
+ DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP
+ ) {
+ break;
+ }
+ }
+ if (!IsDevicePathEnd (Next)) {
+ //
+ // For GOP device path, start the video driver with NULL remaining device path
+ //
+ SetDevicePathEndNode (Next);
+ Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ Status = EfiBootManagerConnectDevicePath (Instance, NULL);
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Delete the instance from the console varialbe
+ //
+ EfiBootManagerUpdateConsoleVariable (ConsoleType, 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 input/output device in current system,
+ and make every input/output device as potential console device.
+**/
+VOID
+EFIAPI
+EfiBootManagerConnectAllConsoles (
+ 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
+ );
+ EfiBootManagerUpdateConsoleVariable (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
+ );
+ EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ //
+ // Connect all console variables
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+}
+
+
+/**
+ This function will connect all the console devices base on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectAllDefaultConsoles (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN OneConnected;
+ BOOLEAN SystemTableUpdated;
+
+ OneConnected = FALSE;
+
+ Status = EfiBootManagerConnectConsoleVariable (ConOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_EVENT ("ConOutReady");
+
+
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_EVENT ("ConInReady");
+
+ Status = EfiBootManagerConnectConsoleVariable (ErrOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_EVENT ("ErrOutReady");
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (BmUpdateSystemTableConsole (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 OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
new file mode 100644
index 000000000..52e35e451
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
@@ -0,0 +1,585 @@
+/** @file
+ Library functions which relates with driver health.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmHealthStatusText[] = {
+ L"Healthy",
+ L"Repair Required",
+ L"Configuration Required",
+ L"Failed",
+ L"Reconnect Required",
+ L"Reboot Required"
+ };
+
+/**
+ Return the controller name.
+
+ @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by DriverBindingHandle 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.
+
+ @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
+ specified by ControllerHandle and ChildHandle.
+**/
+CHAR16 *
+BmGetControllerName (
+ IN EFI_HANDLE DriverHealthHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ControllerName;
+ CHAR8 *LanguageVariable;
+ CHAR8 *BestLanguage;
+ BOOLEAN Iso639Language;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+
+ ControllerName = NULL;
+
+ //
+ // Locate Component Name (2) protocol on the driver binging handle.
+ //
+ Iso639Language = FALSE;
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ Iso639Language = TRUE;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
+ BestLanguage = GetBestLanguage(
+ ComponentName->SupportedLanguages,
+ Iso639Language,
+ (LanguageVariable != NULL) ? LanguageVariable : "",
+ Iso639Language ? "eng" : "en-US",
+ NULL
+ );
+ if (LanguageVariable != NULL) {
+ FreePool (LanguageVariable);
+ }
+
+ Status = ComponentName->GetControllerName (
+ ComponentName,
+ ControllerHandle,
+ ChildHandle,
+ BestLanguage,
+ &ControllerName
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return AllocateCopyPool (StrSize (ControllerName), ControllerName);
+ } else {
+ return ConvertDevicePathToText (
+ DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),
+ FALSE,
+ FALSE
+ );
+ }
+}
+
+/**
+ Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol
+
+ @param DriverHealthInfo Pointer to the Driver Health information entry.
+**/
+VOID
+BmDisplayMessages (
+ IN EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo
+ )
+{
+ UINTN Index;
+ EFI_STRING String;
+ CHAR16 *ControllerName;
+
+ if (DriverHealthInfo->MessageList == NULL ||
+ DriverHealthInfo->MessageList[0].HiiHandle == NULL) {
+ return;
+ }
+
+ ControllerName = BmGetControllerName (
+ DriverHealthInfo->DriverHealthHandle,
+ DriverHealthInfo->ControllerHandle,
+ DriverHealthInfo->ChildHandle
+ );
+
+ DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));
+ Print (L"Controller: %s\n", ControllerName);
+ for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {
+ String = HiiGetString (
+ DriverHealthInfo->MessageList[Index].HiiHandle,
+ DriverHealthInfo->MessageList[Index].StringId,
+ NULL
+ );
+ if (String != NULL) {
+ Print (L" %s\n", String);
+ DEBUG ((EFI_D_INFO, " %s\n", String));
+ FreePool (String);
+ }
+ }
+
+ if (ControllerName != NULL) {
+ FreePool (ControllerName);
+ }
+}
+
+/**
+ The repair notify function.
+ @param Value A value between 0 and Limit that identifies the current progress
+ of the repair operation.
+ @param Limit The maximum value of Value for the current repair operation.
+ If Limit is 0, then the completion progress is indeterminate.
+ For example, a driver that wants to specify progress in percent
+ would use a Limit value of 100.
+
+ @retval EFI_SUCCESS Successfully return from the notify function.
+**/
+EFI_STATUS
+EFIAPI
+BmRepairNotify (
+ IN UINTN Value,
+ IN UINTN Limit
+ )
+{
+ DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));
+ Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Collect the Driver Health status of a single controller.
+
+ @param DriverHealthInfo A pointer to the array containing all of the platform driver health information.
+ @param Count Return the updated array count.
+ @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.
+ @param ControllerHandle The handle of the controller..
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+
+ @retval Status The status returned from GetHealthStatus.
+ @retval EFI_ABORTED The health status is healthy so no further query is needed.
+
+**/
+EFI_STATUS
+BmGetSingleControllerHealthStatus (
+ IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,
+ IN OUT UINTN *Count,
+ IN EFI_HANDLE DriverHealthHandle,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+ EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
+ EFI_HII_HANDLE FormHiiHandle;
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+
+ ASSERT (DriverHealthHandle != NULL);
+ //
+ // Retrieve the Driver Health Protocol from DriverHandle
+ //
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiDriverHealthProtocolGuid,
+ (VOID **) &DriverHealth
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ 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 (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {
+ *DriverHealthInfo = ReallocatePool (
+ (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ *DriverHealthInfo
+ );
+ ASSERT (*DriverHealthInfo != NULL);
+
+ (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
+ (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;
+ (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;
+
+ *Count = *Count + 1;
+
+ Status = EFI_ABORTED;
+ }
+ 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)) {
+ *DriverHealthInfo = ReallocatePool (
+ (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ *DriverHealthInfo
+ );
+ ASSERT (*DriverHealthInfo != NULL);
+ (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;
+ (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
+ (*DriverHealthInfo)[*Count].ControllerHandle = ControllerHandle;
+ (*DriverHealthInfo)[*Count].ChildHandle = ChildHandle;
+ (*DriverHealthInfo)[*Count].HiiHandle = FormHiiHandle;
+ (*DriverHealthInfo)[*Count].MessageList = MessageList;
+ (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;
+
+ *Count = *Count + 1;
+ }
+
+ return Status;
+}
+
+/**
+ Return all the Driver Health information.
+
+ When the cumulative health status of all the controllers managed by the
+ driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
+ EFI_DRIVER_HEALTH_PROTOCOL instance.
+ Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
+ entry. Additionally every child controller creates one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
+
+ @param Count Return the count of the Driver Health information.
+
+ @retval NULL No Driver Health information is returned.
+ @retval !NULL Pointer to the Driver Health information array.
+**/
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
+EFIAPI
+EfiBootManagerGetDriverHealthInfo (
+ UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles;
+ EFI_HANDLE *DriverHealthHandles;
+ UINTN DriverHealthIndex;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN ControllerIndex;
+ UINTN ChildIndex;
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
+
+ //
+ // Initialize local variables
+ //
+ *Count = 0;
+ DriverHealthInfo = NULL;
+ Handles = NULL;
+ DriverHealthHandles = NULL;
+ NumHandles = 0;
+ HandleCount = 0;
+
+ 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 NULL;
+ }
+
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DriverHealthHandles != NULL);
+
+ //
+ // 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++) {
+ //
+ // Get the cumulative health status of the driver
+ //
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ 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
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Loop through all the controller handles in the handle database
+ //
+ for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Loop through all the child handles in the handle database
+ //
+ for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ if (DriverHealthHandles != NULL) {
+ FreePool (DriverHealthHandles);
+ }
+
+ return DriverHealthInfo;
+}
+
+/**
+ Free the Driver Health information array.
+
+ @param DriverHealthInfo Pointer to array of the Driver Health information.
+ @param Count Count of the array.
+
+ @retval EFI_SUCCESS The array is freed.
+ @retval EFI_INVALID_PARAMETER The array is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeDriverHealthInfo (
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,
+ UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if (DriverHealthInfo[Index].MessageList != NULL) {
+ FreePool (DriverHealthInfo[Index].MessageList);
+ }
+ }
+ return gBS->FreePool (DriverHealthInfo);
+}
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+
+ @param ReconnectRepairCount To record the number of recursive call of
+ this function itself.
+**/
+VOID
+BmRepairAllControllers (
+ UINTN ReconnectRepairCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+ UINTN Count;
+ UINTN Index;
+ BOOLEAN RepairRequired;
+ BOOLEAN ConfigurationRequired;
+ BOOLEAN ReconnectRequired;
+ BOOLEAN RebootRequired;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ UINT32 MaxRepairCount;
+ UINT32 RepairCount;
+
+ //
+ // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.
+ //
+ if (IsZeroGuid (PcdGetPtr (PcdDriverHealthConfigureForm))) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ ASSERT_EFI_ERROR (Status);
+
+ MaxRepairCount = PcdGet32 (PcdMaxRepairCount);
+ RepairCount = 0;
+
+ do {
+ RepairRequired = FALSE;
+ ConfigurationRequired = FALSE;
+
+ //
+ // Deal with Repair Required
+ //
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {
+ ConfigurationRequired = TRUE;
+ }
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {
+ RepairRequired = TRUE;
+
+ BmDisplayMessages (&DriverHealthInfo[Index]);
+
+ Status = DriverHealthInfo[Index].DriverHealth->Repair (
+ DriverHealthInfo[Index].DriverHealth,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle,
+ BmRepairNotify
+ );
+ if (!EFI_ERROR (Status) && !ConfigurationRequired) {
+ Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (
+ DriverHealthInfo[Index].DriverHealth,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle,
+ &HealthStatus,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {
+ ConfigurationRequired = TRUE;
+ }
+ }
+ }
+ }
+
+ if (ConfigurationRequired) {
+ HiiHandles = HiiGetHiiHandles (NULL);
+ if (HiiHandles != NULL) {
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ &HiiHandles[Index],
+ 1,
+ PcdGetPtr (PcdDriverHealthConfigureForm),
+ 0,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ FreePool (HiiHandles);
+ }
+ }
+
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+ RepairCount++;
+ } while ((RepairRequired || ConfigurationRequired) && ((MaxRepairCount == 0) || (RepairCount < MaxRepairCount)));
+
+ RebootRequired = FALSE;
+ ReconnectRequired = FALSE;
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+
+ BmDisplayMessages (&DriverHealthInfo[Index]);
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {
+ Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ //
+ // Disconnect failed. Need to promote reconnect to a reboot.
+ //
+ RebootRequired = TRUE;
+ } else {
+ gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);
+ ReconnectRequired = TRUE;
+ }
+ }
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {
+ RebootRequired = TRUE;
+ }
+ }
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+
+
+ DEBUG_CODE (
+ CHAR16 *ControllerName;
+
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+ ControllerName = BmGetControllerName (
+ DriverHealthInfo[Index].DriverHealthHandle,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle
+ );
+ DEBUG ((
+ EFI_D_INFO,
+ "%02d: %s - %s\n",
+ Index,
+ ControllerName,
+ mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]
+ ));
+ if (ControllerName != NULL) {
+ FreePool (ControllerName);
+ }
+ }
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+ );
+
+ if (ReconnectRequired) {
+ if (ReconnectRepairCount < MAX_RECONNECT_REPAIR) {
+ BmRepairAllControllers (ReconnectRepairCount + 1);
+ } else {
+ DEBUG ((DEBUG_ERROR, "[%a:%d] Repair failed after %d retries.\n",
+ __FUNCTION__, __LINE__, ReconnectRepairCount));
+ }
+ }
+
+ if (RebootRequired) {
+ DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
new file mode 100644
index 000000000..c2d1447f5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
@@ -0,0 +1,1151 @@
+/** @file
+ Hotkey library functions.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+//
+// Lock for linked list
+//
+EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
+EFI_EVENT mBmHotkeyTriggered = NULL;
+BOOLEAN mBmHotkeyServiceStarted = FALSE;
+UINTN mBmHotkeySupportCount = 0;
+
+//
+// Set OptionNumber as unassigned value to indicate the option isn't initialized
+//
+EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };
+
+EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;
+VOID *mBmTxtInExRegistration = NULL;
+
+
+/**
+ Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
+
+ @param KeyOption The input key option info.
+
+ @retval The buffer size of the key option data.
+**/
+UINTN
+BmSizeOfKeyOption (
+ IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)
+ + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
+}
+
+/**
+
+ Check whether the input key option is valid.
+
+ @param KeyOption Key option.
+ @param KeyOptionSize Size of the key option.
+
+ @retval TRUE Input key option is valid.
+ @retval FALSE Input key option is not valid.
+**/
+BOOLEAN
+BmIsKeyOptionValid (
+ IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,
+ IN UINTN KeyOptionSize
+)
+{
+ UINT16 OptionName[BM_OPTION_NAME_LEN];
+ UINT8 *BootOption;
+ UINTN BootOptionSize;
+ UINT32 Crc;
+
+ if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {
+ return FALSE;
+ }
+
+ //
+ // Check whether corresponding Boot Option exist
+ //
+ UnicodeSPrint (
+ OptionName, sizeof (OptionName), L"%s%04x",
+ mBmLoadOptionName[LoadOptionTypeBoot], KeyOption->BootOption
+ );
+ GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);
+
+ if (BootOption == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Check CRC for Boot Option
+ //
+ gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
+ FreePool (BootOption);
+
+ return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);
+}
+
+/**
+
+ Check whether the input variable is an key option variable.
+
+ @param Name Input variable name.
+ @param Guid Input variable guid.
+ @param OptionNumber The option number of this key option variable.
+
+ @retval TRUE Input variable is a key option variable.
+ @retval FALSE Input variable is not a key option variable.
+**/
+BOOLEAN
+BmIsKeyOptionVariable (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ UINT16 *OptionNumber
+ )
+{
+ UINTN Index;
+ UINTN Uint;
+
+ 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++) {
+ Uint = BmCharToUint (Name[Index]);
+ if (Uint == -1) {
+ return FALSE;
+ } else {
+ *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
+ }
+ }
+
+ return TRUE;
+}
+
+typedef struct {
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+} BM_COLLECT_KEY_OPTIONS_PARAM;
+
+/**
+ Visitor function to collect the key options from NV storage.
+
+ @param Name Variable name.
+ @param Guid Variable GUID.
+ @param Context The same context passed to BmForEachVariable.
+**/
+VOID
+BmCollectKeyOptions (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ VOID *Context
+ )
+{
+ UINTN Index;
+ BM_COLLECT_KEY_OPTIONS_PARAM *Param;
+ VOID *KeyOption;
+ UINT16 OptionNumber;
+ UINTN KeyOptionSize;
+
+ Param = (BM_COLLECT_KEY_OPTIONS_PARAM *) Context;
+
+ if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {
+ GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);
+ ASSERT (KeyOption != NULL);
+ if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {
+ Param->KeyOptions = ReallocatePool (
+ Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
+ (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
+ Param->KeyOptions
+ );
+ ASSERT (Param->KeyOptions != NULL);
+ //
+ // Insert the key option in order
+ //
+ for (Index = 0; Index < Param->KeyOptionCount; Index++) {
+ if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {
+ break;
+ }
+ }
+ CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);
+ Param->KeyOptions[Index].OptionNumber = OptionNumber;
+ Param->KeyOptionCount++;
+ }
+ FreePool (KeyOption);
+ }
+}
+
+/**
+ Return the array of key options.
+
+ @param Count Return the number of key options.
+
+ @retval NULL No key option.
+ @retval Other Pointer to the key options.
+**/
+EFI_BOOT_MANAGER_KEY_OPTION *
+BmGetKeyOptions (
+ OUT UINTN *Count
+ )
+{
+ BM_COLLECT_KEY_OPTIONS_PARAM Param;
+
+ if (Count == NULL) {
+ return NULL;
+ }
+
+ Param.KeyOptions = NULL;
+ Param.KeyOptionCount = 0;
+
+ BmForEachVariable (BmCollectKeyOptions, (VOID *) &Param);
+
+ *Count = Param.KeyOptionCount;
+
+ return Param.KeyOptions;
+}
+
+/**
+ Check whether the bit is set in the value.
+
+ @param Value The value need to be check.
+ @param Bit The bit filed need to be check.
+
+ @retval TRUE The bit is set.
+ @retval FALSE The bit is not set.
+**/
+BOOLEAN
+BmBitSet (
+ IN UINT32 Value,
+ IN UINT32 Bit
+ )
+{
+ return (BOOLEAN) ((Value & Bit) != 0);
+}
+
+/**
+ Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
+
+ @param Modifier Input key info.
+ @param Args Va_list info.
+ @param KeyOption Key info which need to update.
+
+ @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
+ @return EFI_INVALID_PARAMETER Input parameter error.
+**/
+EFI_STATUS
+BmInitializeKeyFields (
+ IN UINT32 Modifier,
+ IN VA_LIST Args,
+ OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ EFI_INPUT_KEY *Key;
+
+ if (KeyOption == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Key = NULL;
+ while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
+ Key = VA_ARG (Args, EFI_INPUT_KEY *);
+ if (Key == NULL) {
+ break;
+ }
+ CopyMem (
+ &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
+ Key,
+ sizeof (EFI_INPUT_KEY)
+ );
+ KeyOption->KeyData.Options.InputKeyCount++;
+ }
+
+ if (Key != NULL) {
+ //
+ // Too many keys
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
+ | EFI_BOOT_MANAGER_CONTROL_PRESSED
+ | EFI_BOOT_MANAGER_ALT_PRESSED
+ | EFI_BOOT_MANAGER_LOGO_PRESSED
+ | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
+ | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
+ )) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
+ KeyOption->KeyData.Options.ShiftPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
+ KeyOption->KeyData.Options.ControlPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
+ KeyOption->KeyData.Options.AltPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
+ KeyOption->KeyData.Options.LogoPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
+ KeyOption->KeyData.Options.MenuPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
+ KeyOption->KeyData.Options.SysReqPressed = 1;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Try to boot the boot option triggered by hot key.
+**/
+VOID
+EFIAPI
+EfiBootManagerHotkeyBoot (
+ VOID
+ )
+{
+ if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
+ EfiBootManagerBoot (&mBmHotkeyBootOption);
+ EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
+ mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
+ }
+}
+
+/**
+ 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
+BmHotkeyCallback (
+ IN EFI_KEY_DATA *KeyData
+)
+{
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ EFI_STATUS Status;
+ EFI_KEY_DATA *HotkeyData;
+
+ if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
+ //
+ // Do not process sequential hotkey stroke until the current boot option returns
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ for ( Link = GetFirstNode (&mBmHotkeyList)
+ ; !IsNull (&mBmHotkeyList, Link)
+ ; Link = GetNextNode (&mBmHotkeyList, Link)
+ ) {
+ Hotkey = BM_HOTKEY_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
+ )
+ ) {
+
+ //
+ // Receive an expecting key stroke, transit to next waiting state
+ //
+ Hotkey->WaitingKey++;
+
+ if (Hotkey->WaitingKey == Hotkey->CodeCount) {
+ //
+ // Reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ //
+ // Received the whole key stroke sequence
+ //
+ Status = gBS->SignalEvent (mBmHotkeyTriggered);
+ ASSERT_EFI_ERROR (Status);
+
+ if (!Hotkey->IsContinue) {
+ //
+ // Launch its BootOption
+ //
+ UnicodeSPrint (
+ OptionName, sizeof (OptionName), L"%s%04x",
+ mBmLoadOptionName[LoadOptionTypeBoot], Hotkey->BootOption
+ );
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
+ DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
+ if (EFI_ERROR (Status)) {
+ mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));
+ }
+ }
+ } else {
+ //
+ // Receive an unexpected key stroke, reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ }
+
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the active Simple Text Input Ex handle array.
+ If the SystemTable.ConsoleInHandle is NULL, the function returns all
+ founded Simple Text Input Ex handles.
+ Otherwise, it just returns the ConsoleInHandle.
+
+ @param Count Return the handle count.
+
+ @retval The active console handles.
+**/
+EFI_HANDLE *
+BmGetActiveConsoleIn (
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+
+ Handles = NULL;
+ *Count = 0;
+
+ if (gST->ConsoleInHandle != NULL) {
+ Status = gBS->OpenProtocol (
+ gST->ConsoleInHandle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);
+ if (Handles != NULL) {
+ *Count = 1;
+ }
+ }
+ } else {
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ Count,
+ &Handles
+ );
+ }
+
+ return Handles;
+}
+
+/**
+ Unregister hotkey notify list.
+
+ @param Hotkey Hotkey list.
+
+ @retval EFI_SUCCESS Unregister hotkey notify success.
+ @retval Others Unregister hotkey notify failed.
+**/
+EFI_STATUS
+BmUnregisterHotkeyNotify (
+ IN BM_HOTKEY *Hotkey
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN KeyIndex;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ VOID *NotifyHandle;
+
+ Handles = BmGetActiveConsoleIn (&HandleCount);
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
+ ASSERT_EFI_ERROR (Status);
+ for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
+ Status = TxtInEx->RegisterKeyNotify (
+ TxtInEx,
+ &Hotkey->KeyData[KeyIndex],
+ BmHotkeyCallback,
+ &NotifyHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
+ DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
+ }
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register hotkey notify list.
+
+ @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
+ @param Hotkey Hotkey list.
+
+ @retval EFI_SUCCESS Register hotkey notify success.
+ @retval Others Register hotkey notify failed.
+**/
+EFI_STATUS
+BmRegisterHotkeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx,
+ IN BM_HOTKEY *Hotkey
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VOID *NotifyHandle;
+
+ for (Index = 0; Index < Hotkey->CodeCount; Index++) {
+ Status = TxtInEx->RegisterKeyNotify (
+ TxtInEx,
+ &Hotkey->KeyData[Index],
+ BmHotkeyCallback,
+ &NotifyHandle
+ );
+ DEBUG ((
+ EFI_D_INFO,
+ "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
+ Hotkey->KeyData[Index].Key.ScanCode,
+ Hotkey->KeyData[Index].Key.UnicodeChar,
+ Hotkey->KeyData[Index].KeyState.KeyShiftState,
+ Hotkey->KeyData[Index].KeyState.KeyToggleState,
+ Status
+ ));
+ if (EFI_ERROR (Status)) {
+ //
+ // some of the hotkey registry failed
+ // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
+ //
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate key shift state base on the input key option info.
+
+ @param Depth Which key is checked.
+ @param KeyOption Input key option info.
+ @param KeyShiftState Input key shift state.
+ @param KeyShiftStates Return possible key shift state array.
+ @param KeyShiftStateCount Possible key shift state count.
+**/
+VOID
+BmGenerateKeyShiftState (
+ IN UINTN Depth,
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,
+ IN UINT32 KeyShiftState,
+ IN UINT32 *KeyShiftStates,
+ IN UINTN *KeyShiftStateCount
+ )
+{
+ switch (Depth) {
+ case 0:
+ if (KeyOption->KeyData.Options.ShiftPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+
+ case 1:
+ if (KeyOption->KeyData.Options.ControlPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+
+ case 2:
+ if (KeyOption->KeyData.Options.AltPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+ case 3:
+ if (KeyOption->KeyData.Options.LogoPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+ case 4:
+ if (KeyOption->KeyData.Options.MenuPressed) {
+ KeyShiftState |= EFI_MENU_KEY_PRESSED;
+ }
+ if (KeyOption->KeyData.Options.SysReqPressed) {
+ KeyShiftState |= EFI_SYS_REQ_PRESSED;
+ }
+ KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
+ (*KeyShiftStateCount)++;
+ break;
+ }
+}
+
+/**
+ Add it to hot key database, register it to existing TxtInEx.
+ New TxtInEx will be automatically registered with all the hot key in dababase
+
+ @param KeyOption Input key option info.
+**/
+EFI_STATUS
+BmProcessKeyOption (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN HandleIndex;
+ UINTN Index;
+ BM_HOTKEY *Hotkey;
+ UINTN KeyIndex;
+ //
+ // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
+ //
+ UINT32 KeyShiftStates[16];
+ UINTN KeyShiftStateCount;
+
+ if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ KeyShiftStateCount = 0;
+ BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
+ ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));
+
+ EfiAcquireLock (&mBmHotkeyLock);
+
+ Handles = BmGetActiveConsoleIn (&HandleCount);
+
+ for (Index = 0; Index < KeyShiftStateCount; Index++) {
+ Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
+ ASSERT (Hotkey != NULL);
+
+ Hotkey->Signature = BM_HOTKEY_SIGNATURE;
+ Hotkey->BootOption = KeyOption->BootOption;
+ Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);
+ Hotkey->CodeCount = (UINT8) KeyOption->KeyData.Options.InputKeyCount;
+
+ for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
+ CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
+ Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
+ }
+ InsertTailList (&mBmHotkeyList, &Hotkey->Link);
+
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
+ ASSERT_EFI_ERROR (Status);
+ BmRegisterHotkeyNotify (TxtInEx, Hotkey);
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function for SimpleTextInEx protocol install events
+
+ @param Event the event that is signaled.
+ @param Context not used here.
+
+**/
+VOID
+EFIAPI
+BmTxtInExCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ LIST_ENTRY *Link;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mBmTxtInExRegistration,
+ &BufferSize,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exist
+ //
+ return ;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &TxtInEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the hot key notification for the existing items in the list
+ //
+ EfiAcquireLock (&mBmHotkeyLock);
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
+ BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+ }
+}
+
+/**
+ Free the key options returned from BmGetKeyOptions.
+
+ @param KeyOptions Pointer to the key options.
+ @param KeyOptionCount Number of the key options.
+
+ @retval EFI_SUCCESS The key options are freed.
+ @retval EFI_NOT_FOUND KeyOptions is NULL.
+**/
+EFI_STATUS
+BmFreeKeyOptions (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions,
+ IN UINTN KeyOptionCount
+ )
+{
+ if (KeyOptions != NULL) {
+ FreePool (KeyOptions);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Register the key option to exit the waiting of the Boot Manager timeout.
+ Platform should ensure that the continue key option isn't conflict with
+ other boot key options.
+
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS Successfully register the continue key option.
+ @retval EFI_ALREADY_STARTED The continue key option is already registered.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterContinueKeyOption (
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ VA_LIST Args;
+
+ if (mBmContinueKeyOption != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+
+ if (!EFI_ERROR (Status)) {
+ mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
+ ASSERT (mBmContinueKeyOption != NULL);
+ if (mBmHotkeyServiceStarted) {
+ BmProcessKeyOption (mBmContinueKeyOption);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stop the hotkey processing.
+
+ @param Event Event pointer related to hotkey service.
+ @param Context Context pass to this function.
+**/
+VOID
+EFIAPI
+BmStopHotkeyService (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+
+ DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));
+ gBS->CloseEvent (Event);
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
+ Hotkey = BM_HOTKEY_FROM_LINK (Link);
+ BmUnregisterHotkeyNotify (Hotkey);
+ Link = RemoveEntryList (Link);
+ FreePool (Hotkey);
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+}
+
+/**
+ Start the hot key service so that the key press can trigger the boot option.
+
+ @param HotkeyTriggered Return the waitable event and it will be signaled
+ when a valid hot key is pressed.
+
+ @retval EFI_SUCCESS The hot key service is started.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerStartHotkeyService (
+ IN EFI_EVENT *HotkeyTriggered
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ UINTN Index;
+ EFI_EVENT Event;
+ UINT32 *BootOptionSupport;
+
+ GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);
+ if (BootOptionSupport != NULL) {
+ if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {
+ mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
+ }
+ FreePool (BootOptionSupport);
+ }
+
+ if (mBmHotkeySupportCount == 0) {
+ DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_CALLBACK,
+ EfiEventEmptyFunction,
+ NULL,
+ &mBmHotkeyTriggered
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (HotkeyTriggered != NULL) {
+ *HotkeyTriggered = mBmHotkeyTriggered;
+ }
+
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index ++) {
+ BmProcessKeyOption (&KeyOptions[Index]);
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ if (mBmContinueKeyOption != NULL) {
+ BmProcessKeyOption (mBmContinueKeyOption);
+ }
+
+ //
+ // Hook hotkey on every future SimpleTextInputEx instance when
+ // SystemTable.ConsoleInHandle == NULL, which means the console
+ // manager (ConSplitter) is absent.
+ //
+ if (gST->ConsoleInHandle == NULL) {
+ EfiCreateProtocolNotifyEvent (
+ &gEfiSimpleTextInputExProtocolGuid,
+ TPL_CALLBACK,
+ BmTxtInExCallback,
+ NULL,
+ &mBmTxtInExRegistration
+ );
+ }
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ BmStopHotkeyService,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mBmHotkeyServiceStarted = TRUE;
+ return Status;
+}
+
+/**
+ Add the key option.
+ It adds the key option variable and the key option takes affect immediately.
+
+ @param AddedOption Return the added key option.
+ @param BootOptionNumber The boot option number for the key option.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is added.
+ @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddKeyOptionVariable (
+ OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption, OPTIONAL
+ IN UINT16 BootOptionNumber,
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ VOID *BootOption;
+ UINTN BootOptionSize;
+ CHAR16 BootOptionName[BM_OPTION_NAME_LEN];
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ UINTN Index;
+ UINTN KeyOptionNumber;
+ CHAR16 KeyOptionName[sizeof ("Key####")];
+
+ UnicodeSPrint (
+ BootOptionName, sizeof (BootOptionName), L"%s%04x",
+ mBmLoadOptionName[LoadOptionTypeBoot], BootOptionNumber
+ );
+ GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
+
+ if (BootOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ KeyOption.BootOption = BootOptionNumber;
+ Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOption);
+
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyOptionNumber = LoadOptionNumberUnassigned;
+ //
+ // Check if the hot key sequence was defined already
+ //
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index++) {
+ if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
+ (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {
+ break;
+ }
+
+ if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
+ (KeyOptions[Index].OptionNumber > Index)
+ ){
+ KeyOptionNumber = Index;
+ }
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ if (Index < KeyOptionCount) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (KeyOptionNumber == LoadOptionNumberUnassigned) {
+ KeyOptionNumber = KeyOptionCount;
+ }
+
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
+
+ Status = gRT->SetVariable (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BmSizeOfKeyOption (&KeyOption),
+ &KeyOption
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the Key Option in case needed by caller
+ //
+ if (AddedOption != NULL) {
+ CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ }
+
+ //
+ // Register the newly added hot key
+ // Calling this function before EfiBootManagerStartHotkeyService doesn't
+ // need to call BmProcessKeyOption
+ //
+ if (mBmHotkeyServiceStarted) {
+ BmProcessKeyOption (&KeyOption);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Delete the Key Option variable and unregister the hot key
+
+ @param DeletedOption Return the deleted key options.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is deleted.
+ @retval EFI_NOT_FOUND The key option cannot be found.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteKeyOptionVariable (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VA_LIST Args;
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+ UINT32 ShiftState;
+ BOOLEAN Match;
+ CHAR16 KeyOptionName[sizeof ("Key####")];
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ //
+ // Delete the key option from active hot key list
+ // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
+ //
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
+ Hotkey = BM_HOTKEY_FROM_LINK (Link);
+ Match = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
+
+ for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
+ ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
+ if (
+ (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
+ (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
+ (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
+ (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
+ ) {
+ //
+ // Break when any field doesn't match
+ //
+ Match = FALSE;
+ break;
+ }
+ }
+
+ if (Match) {
+ Link = RemoveEntryList (Link);
+ FreePool (Hotkey);
+ } else {
+ Link = GetNextNode (&mBmHotkeyList, Link);
+ }
+ }
+
+ //
+ // Delete the key option from the variable
+ //
+ Status = EFI_NOT_FOUND;
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index++) {
+ if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
+ (CompareMem (
+ KeyOptions[Index].Keys, KeyOption.Keys,
+ KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)
+ ) {
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
+ Status = gRT->SetVariable (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Return the deleted key option in case needed by caller
+ //
+ if (DeletedOption != NULL) {
+ CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ }
+ break;
+ }
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
new file mode 100644
index 000000000..89372b3b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
@@ -0,0 +1,1457 @@
+/** @file
+ Load option library functions which relate with creating and processing load options.
+
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionName[] = {
+ L"Driver",
+ L"SysPrep",
+ L"Boot",
+ L"PlatformRecovery"
+ };
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionOrderName[] = {
+ EFI_DRIVER_ORDER_VARIABLE_NAME,
+ EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+ EFI_BOOT_ORDER_VARIABLE_NAME,
+ NULL // PlatformRecovery#### doesn't have associated *Order variable
+ };
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+BmForEachVariable (
+ BM_VARIABLE_VISITOR Visitor,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Name;
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN NewNameSize;
+
+ 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);
+
+ Visitor (Name, &Guid, Context);
+ }
+
+ FreePool (Name);
+}
+
+/**
+ Get the Option Number that wasn't used.
+
+ @param LoadOptionType The load option type.
+ @param FreeOptionNumber Return the minimal free option number.
+
+ @retval EFI_SUCCESS The option number is found and will be returned.
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
+ @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
+
+**/
+EFI_STATUS
+BmGetFreeOptionNumber (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
+ )
+{
+
+ UINTN OptionNumber;
+ UINTN Index;
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINT16 *BootNext;
+
+ ASSERT (FreeOptionNumber != NULL);
+ ASSERT (LoadOptionType == LoadOptionTypeDriver ||
+ LoadOptionType == LoadOptionTypeBoot ||
+ LoadOptionType == LoadOptionTypeSysPrep);
+
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ BootNext = NULL;
+ if (LoadOptionType == LoadOptionTypeBoot) {
+ GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
+ }
+
+ for (OptionNumber = 0;
+ OptionNumber < OptionOrderSize / sizeof (UINT16)
+ + ((BootNext != NULL) ? 1 : 0);
+ OptionNumber++
+ ) {
+ //
+ // Search in OptionOrder whether the OptionNumber exists
+ //
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionNumber == OptionOrder[Index]) {
+ break;
+ }
+ }
+
+ //
+ // We didn't find it in the ****Order array and it doesn't equal to BootNext
+ // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
+ //
+ if ((Index == OptionOrderSize / sizeof (UINT16)) &&
+ ((BootNext == NULL) || (OptionNumber != *BootNext))
+ ) {
+ break;
+ }
+ }
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ if (BootNext != NULL) {
+ FreePool (BootNext);
+ }
+
+ //
+ // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
+ // OptionNumber equals to 0x10000 which is not valid.
+ //
+ ASSERT (OptionNumber <= 0x10000);
+ if (OptionNumber == 0x10000) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ *FreeOptionNumber = (UINT16) OptionNumber;
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable
+ from the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_SUCCESS The variable was created.
+ @retval Others Error status returned by RT->SetVariable.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerLoadOptionToVariable (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableSize;
+ UINT8 *Variable;
+ UINT8 *Ptr;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ CHAR16 *Description;
+ CHAR16 NullChar;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ UINT32 VariableAttributes;
+
+ if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
+ (Option->FilePath == NULL) ||
+ ((UINT32) Option->OptionType >= LoadOptionTypeMax)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert NULL description to empty description
+ //
+ NullChar = L'\0';
+ Description = Option->Description;
+ if (Description == NULL) {
+ Description = &NullChar;
+ }
+
+ /*
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ CHAR16 Description[];
+ EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ UINT8 OptionalData[];
+TODO: FilePathList[] IS:
+A packed array of UEFI device paths. The first element of the
+array is a device path that describes the device and location of the
+Image for this load option. The FilePathList[0] is specific
+to the device type. Other device paths may optionally exist in the
+FilePathList, but their usage is OSV specific. Each element
+in the array is variable length, and ends at the device path end
+structure.
+ */
+ VariableSize = sizeof (Option->Attributes)
+ + sizeof (UINT16)
+ + StrSize (Description)
+ + GetDevicePathSize (Option->FilePath)
+ + Option->OptionalDataSize;
+
+ Variable = AllocatePool (VariableSize);
+ ASSERT (Variable != NULL);
+
+ Ptr = Variable;
+ WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
+ Ptr += sizeof (Option->Attributes);
+
+ WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
+ Ptr += sizeof (UINT16);
+
+ CopyMem (Ptr, Description, StrSize (Description));
+ Ptr += StrSize (Description);
+
+ CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
+ Ptr += GetDevicePathSize (Option->FilePath);
+
+ CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
+
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
+
+ VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+ if (Option->OptionType == LoadOptionTypePlatformRecovery) {
+ //
+ // Lock the PlatformRecovery####
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ Status = gRT->SetVariable (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ VariableAttributes,
+ VariableSize,
+ Variable
+ );
+ FreePool (Variable);
+
+ return Status;
+}
+
+/**
+ Update order variable .
+
+ @param OptionOrderName Order variable name which need to be updated.
+ @param OptionNumber Option number for the new option.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+BmAddOptionNumberToOrderVariable (
+ IN CHAR16 *OptionOrderName,
+ IN UINT16 OptionNumber,
+ IN UINTN Position
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 *OptionOrder;
+ UINT16 *NewOptionOrder;
+ UINTN OptionOrderSize;
+ //
+ // Update the option order variable
+ //
+ GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ Status = EFI_ALREADY_STARTED;
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
+
+ NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
+ ASSERT (NewOptionOrder != NULL);
+ if (OptionOrderSize != 0) {
+ CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
+ CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
+ }
+ NewOptionOrder[Position] = OptionNumber;
+
+ Status = gRT->SetVariable (
+ OptionOrderName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize + sizeof (UINT16),
+ NewOptionOrder
+ );
+ FreePool (NewOptionOrder);
+ }
+
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ return Status;
+}
+
+/**
+ This function will register the new Boot####, Driver#### or SysPrep#### option.
+ After the *#### is updated, the *Order will also be updated.
+
+ @param Option Pointer to load option to add. If on input
+ Option->OptionNumber is LoadOptionNumberUnassigned,
+ then on output Option->OptionNumber is updated to
+ the number of the new Boot####,
+ Driver#### or SysPrep#### option.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The *#### have been successfully registered.
+ @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ Note: this API only adds new load option, no replacement support.
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
+ option number specified in the Option is LoadOptionNumberUnassigned.
+ @return Status codes of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddLoadOptionVariable (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN Position
+ )
+{
+ EFI_STATUS Status;
+ UINT16 OptionNumber;
+
+ if (Option == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Option->OptionType != LoadOptionTypeDriver &&
+ Option->OptionType != LoadOptionTypeSysPrep &&
+ Option->OptionType != LoadOptionTypeBoot
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the free option number if the option number is unassigned
+ //
+ if (Option->OptionNumber == LoadOptionNumberUnassigned) {
+ Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Option->OptionNumber = OptionNumber;
+ }
+
+ if (Option->OptionNumber >= LoadOptionNumberMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Save the Boot#### or Driver#### variable
+ //
+ Status = EfiBootManagerLoadOptionToVariable (Option);
+ if (EFI_ERROR (Status)) {
+ //
+ // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
+ //
+ EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Sort the load option. The DriverOrder or BootOrder will be re-created to
+ reflect the new order.
+
+ @param OptionType Load option type
+ @param CompareFunction The comparator
+**/
+VOID
+EFIAPI
+EfiBootManagerSortLoadOptionVariable (
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ SORT_COMPARE CompareFunction
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;
+ UINTN LoadOptionCount;
+ UINTN Index;
+ UINT16 *OptionOrder;
+
+ LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
+
+ //
+ // Insertion sort algorithm
+ //
+ PerformQuickSort (
+ LoadOption,
+ LoadOptionCount,
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
+ CompareFunction
+ );
+
+ //
+ // Create new ****Order variable
+ //
+ OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
+ ASSERT (OptionOrder != NULL);
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
+ }
+
+ Status = gRT->SetVariable (
+ mBmLoadOptionOrderName[OptionType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ LoadOptionCount * sizeof (UINT16),
+ OptionOrder
+ );
+ //
+ // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (OptionOrder);
+ EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
+}
+
+/**
+ Initialize a load option.
+
+ @param Option Pointer to the load option to be initialized.
+ @param OptionNumber Option number of the load option.
+ @param OptionType Type of the load option.
+ @param Attributes Attributes of the load option.
+ @param Description Description of the load option.
+ @param FilePath Device path of the load option.
+ @param OptionalData Optional data of the load option.
+ @param OptionalDataSize Size of the optional data of the load option.
+
+ @retval EFI_SUCCESS The load option was initialized successfully.
+ @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerInitializeLoadOption (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ IN UINT32 Attributes,
+ IN CHAR16 *Description,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN UINT8 *OptionalData, OPTIONAL
+ IN UINT32 OptionalDataSize
+ )
+{
+ if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
+ ((OptionalData == NULL) && (OptionalDataSize != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32) OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Option->OptionNumber = OptionNumber;
+ Option->OptionType = OptionType;
+ Option->Attributes = Attributes;
+ Option->Description = AllocateCopyPool (StrSize (Description), Description);
+ Option->FilePath = DuplicateDevicePath (FilePath);
+ if (OptionalData != NULL) {
+ Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
+ Option->OptionalDataSize = OptionalDataSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param Key Pointer to the load option to be found.
+ @param Array Pointer to the array of load options to be found.
+ @param Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+EFIAPI
+EfiBootManagerFindLoadOption (
+ 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 ((Key->OptionType == Array[Index].OptionType) &&
+ (Key->Attributes == Array[Index].Attributes) &&
+ (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;
+}
+
+/**
+ Delete the load option.
+
+ @param OptionNumber Indicate the option number of load option
+ @param OptionType Indicate the type of load option
+
+ @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
+ @retval EFI_NOT_FOUND The load option cannot be found
+ @retval EFI_SUCCESS The load option was deleted
+ @retval others Status of RT->SetVariable()
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteLoadOptionVariable (
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
+ )
+{
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINTN Index;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+
+ if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
+ //
+ // If the associated *Order exists, firstly remove the reference in *Order for
+ // Driver####, SysPrep#### and Boot####.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ OptionOrderSize -= sizeof (UINT16);
+ CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
+ gRT->SetVariable (
+ mBmLoadOptionOrderName[OptionType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize,
+ OptionOrder
+ );
+ break;
+ }
+ }
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+ }
+
+ //
+ // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
+ //
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);
+ return gRT->SetVariable (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+}
+
+/**
+ 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
+BmGetDevicePathSizeEx (
+ 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 == 0) {
+ 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 number 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
+BmStrSizeEx (
+ 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 Boot####, Driver####, SysPrep#### and PlatformRecovery####
+ variable (VendorGuid/Name)
+
+ @param Variable The variable data.
+ @param VariableSize The variable size.
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+BmValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ )
+{
+ UINT16 FilePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DescriptionSize;
+
+ if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
+ return FALSE;
+ }
+
+ //
+ // Skip the option attribute
+ //
+ Variable += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
+ Variable += sizeof (UINT16);
+
+ //
+ // Get the option's description string size
+ //
+ DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
+ Variable += DescriptionSize;
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
+
+ //
+ // Validation boot option variable.
+ //
+ if ((FilePathSize == 0) || (DescriptionSize == 0)) {
+ return FALSE;
+ }
+
+ if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
+ return FALSE;
+ }
+
+ return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
+}
+
+/**
+ Check whether the VariableName is a valid load option variable name
+ and return the load option type and option number.
+
+ @param VariableName The name of the load option variable.
+ @param OptionType Return the load option type.
+ @param OptionNumber Return the load option number.
+
+ @retval TRUE The variable name is valid; The load option type and
+ load option number is returned.
+ @retval FALSE The variable name is NOT valid.
+**/
+BOOLEAN
+EFIAPI
+EfiBootManagerIsValidLoadOptionVariableName (
+ IN CHAR16 *VariableName,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL,
+ OUT UINT16 *OptionNumber OPTIONAL
+ )
+{
+ UINTN VariableNameLen;
+ UINTN Index;
+ UINTN Uint;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType;
+ UINT16 LocalOptionNumber;
+
+ if (VariableName == NULL) {
+ return FALSE;
+ }
+
+ VariableNameLen = StrLen (VariableName);
+
+ //
+ // Return FALSE when the variable name length is too small.
+ //
+ if (VariableNameLen <= 4) {
+ return FALSE;
+ }
+
+ //
+ // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.
+ //
+ for (LocalOptionType = 0; LocalOptionType < ARRAY_SIZE (mBmLoadOptionName); LocalOptionType++) {
+ if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[LocalOptionType])) &&
+ (StrnCmp (VariableName, mBmLoadOptionName[LocalOptionType], VariableNameLen - 4) == 0)
+ ) {
+ break;
+ }
+ }
+ if (LocalOptionType == ARRAY_SIZE (mBmLoadOptionName)) {
+ return FALSE;
+ }
+
+ //
+ // Return FALSE when the last four characters are not hex digits.
+ //
+ LocalOptionNumber = 0;
+ for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
+ Uint = BmCharToUint (VariableName[Index]);
+ if (Uint == -1) {
+ break;
+ } else {
+ LocalOptionNumber = (UINT16) Uint + LocalOptionNumber * 0x10;
+ }
+ }
+ if (Index != VariableNameLen) {
+ return FALSE;
+ }
+
+ if (OptionType != NULL) {
+ *OptionType = LocalOptionType;
+ }
+
+ if (OptionNumber != NULL) {
+ *OptionNumber = LocalOptionNumber;
+ }
+
+ return TRUE;
+}
+
+/**
+ Build the Boot#### or Driver#### option from the VariableName.
+
+ @param VariableName Variable name of the load option
+ @param VendorGuid Variable GUID of the load option
+ @param Option Return the load option.
+
+ @retval EFI_SUCCESS Get the option just been created
+ @retval EFI_NOT_FOUND Failed to get the new option
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOptionEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Attribute;
+ UINT16 FilePathSize;
+ UINT8 *Variable;
+ UINT8 *VariablePtr;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ UINT8 *OptionalData;
+ UINT32 OptionalDataSize;
+ CHAR16 *Description;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
+ UINT16 OptionNumber;
+
+ if ((VariableName == NULL) || (Option == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the variable
+ //
+ GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
+ if (Variable == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Validate *#### variable data.
+ //
+ if (!BmValidateOption(Variable, VariableSize)) {
+ FreePool (Variable);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the option attribute
+ //
+ VariablePtr = Variable;
+ Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
+ VariablePtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
+ VariablePtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string
+ //
+ Description = (CHAR16 *) VariablePtr;
+
+ //
+ // Get the option's description string size
+ //
+ VariablePtr += StrSize ((CHAR16 *) VariablePtr);
+
+ //
+ // Get the option's device path
+ //
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
+ VariablePtr += FilePathSize;
+
+ OptionalDataSize = (UINT32) (VariableSize - ((UINTN) VariablePtr - (UINTN) Variable));
+ if (OptionalDataSize == 0) {
+ OptionalData = NULL;
+ } else {
+ OptionalData = VariablePtr;
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ Option,
+ OptionNumber,
+ OptionType,
+ Attribute,
+ Description,
+ FilePath,
+ OptionalData,
+ OptionalDataSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ CopyGuid (&Option->VendorGuid, VendorGuid);
+
+ FreePool (Variable);
+ return Status;
+}
+
+/**
+Build the Boot#### or Driver#### option from the VariableName.
+
+@param VariableName EFI Variable name indicate if it is Boot#### or Driver####
+@param Option Return the Boot#### or Driver#### option.
+
+@retval EFI_SUCCESS Get the option just been created
+@retval EFI_NOT_FOUND Failed to get the new option
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOption (
+ IN CHAR16 *VariableName,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
+}
+
+typedef struct {
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
+ EFI_GUID *Guid;
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;
+ UINTN OptionCount;
+} BM_COLLECT_LOAD_OPTIONS_PARAM;
+
+/**
+ Visitor function to collect the Platform Recovery load options or OS Recovery
+ load options from NV storage.
+
+ @param Name Variable name.
+ @param Guid Variable GUID.
+ @param Context The same context passed to BmForEachVariable.
+**/
+VOID
+BmCollectLoadOptions (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
+ UINT16 OptionNumber;
+ EFI_BOOT_MANAGER_LOAD_OPTION Option;
+ UINTN Index;
+ BM_COLLECT_LOAD_OPTIONS_PARAM *Param;
+
+ Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
+
+ if (CompareGuid (Guid, Param->Guid) && (
+ Param->OptionType == LoadOptionTypePlatformRecovery &&
+ EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
+ OptionType == LoadOptionTypePlatformRecovery
+ )) {
+ Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < Param->OptionCount; Index++) {
+ if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
+ break;
+ }
+ }
+ Param->Options = ReallocatePool (
+ Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
+ (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
+ Param->Options
+ );
+ ASSERT (Param->Options != NULL);
+ CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Param->OptionCount++;
+ }
+ }
+}
+
+/**
+ Returns an array of load options based on the EFI variable
+ L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
+ #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
+
+ @param LoadOptionCount Returns number of entries in the array.
+ @param LoadOptionType The type of the load option.
+
+ @retval NULL No load options exist.
+ @retval !NULL Array of load option entries.
+
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+EFIAPI
+EfiBootManagerGetLoadOptions (
+ OUT UINTN *OptionCount,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINTN Index;
+ UINTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ UINT16 OptionNumber;
+ BM_COLLECT_LOAD_OPTIONS_PARAM Param;
+
+ *OptionCount = 0;
+ Options = NULL;
+
+ if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
+ //
+ // Read the BootOrder, or DriverOrder variable.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ if (OptionOrder == NULL) {
+ return NULL;
+ }
+
+ *OptionCount = OptionOrderSize / sizeof (UINT16);
+
+ Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ ASSERT (Options != NULL);
+
+ OptionIndex = 0;
+ for (Index = 0; Index < *OptionCount; Index++) {
+ OptionNumber = OptionOrder[Index];
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
+
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
+ EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
+ } else {
+ ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
+ OptionIndex++;
+ }
+ }
+
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ if (OptionIndex < *OptionCount) {
+ Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
+ ASSERT (Options != NULL);
+ *OptionCount = OptionIndex;
+ }
+
+ } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
+ Param.OptionType = LoadOptionTypePlatformRecovery;
+ Param.Options = NULL;
+ Param.OptionCount = 0;
+ Param.Guid = &gEfiGlobalVariableGuid;
+
+ BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
+
+ *OptionCount = Param.OptionCount;
+ Options = Param.Options;
+ }
+
+ return Options;
+}
+
+/**
+ Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
+
+ @param LoadOption Pointer to boot option to Free.
+
+ @return EFI_SUCCESS BootOption was freed
+ @return EFI_NOT_FOUND BootOption == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ )
+{
+ if (LoadOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (LoadOption->Description != NULL) {
+ FreePool (LoadOption->Description);
+ }
+ if (LoadOption->FilePath != NULL) {
+ FreePool (LoadOption->FilePath);
+ }
+ if (LoadOption->OptionalData != NULL) {
+ FreePool (LoadOption->OptionalData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
+ EfiBootManagerGetLoadOptions().
+
+ @param Option Pointer to boot option array to free.
+ @param OptionCount Number of array entries in BootOption
+
+ @return EFI_SUCCESS BootOption was freed
+ @return EFI_NOT_FOUND BootOption == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN OptionCount
+ )
+{
+ UINTN Index;
+
+ if (Option == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0;Index < OptionCount; Index++) {
+ EfiBootManagerFreeLoadOption (&Option[Index]);
+ }
+
+ FreePool (Option);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return whether the PE header of the load option is valid or not.
+
+ @param[in] Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param[in] FileBuffer The PE file buffer of the load option.
+ @param[in] FileSize The size of the load option file.
+
+ @retval TRUE The PE header of the load option is valid.
+ @retval FALSE The PE header of the load option is not valid.
+**/
+BOOLEAN
+BmIsLoadOptionPeHeaderValid (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;
+ EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;
+ UINT16 Subsystem;
+
+ if (FileBuffer == NULL || FileSize == 0) {
+ return FALSE;
+ }
+
+ //
+ // Read dos header
+ //
+ DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
+ if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
+ FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
+ ) {
+ //
+ // Read and check PE signature
+ //
+ PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
+ if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
+ PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
+ ) {
+ //
+ // Check PE32 or PE32+ magic, and machine type
+ //
+ OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
+ if (OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
+ OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Check the Subsystem:
+ // Driver#### must be of type BootServiceDriver or RuntimeDriver
+ // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
+ //
+ Subsystem = OptionalHeader->Subsystem;
+ if ((Type == LoadOptionTypeMax) ||
+ (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
+ (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
+ (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
+ (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ ) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
+ load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ UINTN LocalFileSize;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
+
+ LocalFileSize = 0;
+ FileBuffer = NULL;
+ CurFullPath = *FullPath;
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);
+ //
+ // Only free the full path created *inside* this routine
+ //
+ if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {
+ FreePool (PreFullPath);
+ }
+ if (CurFullPath == NULL) {
+ break;
+ }
+ FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);
+ if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {
+ //
+ // Free the RAM disk file system if the load option is invalid.
+ //
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
+ if (RamDiskDevicePath != NULL) {
+ BmDestroyRamDisk (RamDiskDevicePath);
+ FreePool (RamDiskDevicePath);
+ }
+
+ //
+ // Free the invalid load option buffer.
+ //
+ FreePool (FileBuffer);
+ FileBuffer = NULL;
+ }
+ } while (FileBuffer == NULL);
+
+ if (FileBuffer == NULL) {
+ CurFullPath = NULL;
+ LocalFileSize = 0;
+ }
+
+ DEBUG ((DEBUG_INFO, "[Bds] Expand "));
+ BmPrintDp (FilePath);
+ DEBUG ((DEBUG_INFO, " -> "));
+ BmPrintDp (CurFullPath);
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ *FullPath = CurFullPath;
+ *FileSize = LocalFileSize;
+ return FileBuffer;
+}
+
+/**
+ Process (load and execute) the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,
+ or the load option file path doesn't point to a valid file.
+ @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
+ @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ VOID *FileBuffer;
+ UINTN FileSize;
+
+ if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (LoadOption->OptionType == LoadOptionTypeBoot) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,
+ // the boot manager will not automatically load the option.
+ //
+ if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Load and start the load option.
+ //
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,
+ LoadOption->Description
+ ));
+ ImageHandle = NULL;
+ CurFullPath = NULL;
+ EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);
+
+ //
+ // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
+ //
+ while (TRUE) {
+ Status = EFI_INVALID_PARAMETER;
+ PreFullPath = CurFullPath;
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+ if (FileBuffer == NULL) {
+ break;
+ }
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ CurFullPath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ FreePool (FileBuffer);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ } else {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+ ImageInfo->LoadOptions = LoadOption->OptionalData;
+ //
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
+ ));
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+
+ if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {
+ break;
+ }
+ }
+ }
+
+ if (CurFullPath != NULL) {
+ FreePool (CurFullPath);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
new file mode 100644
index 000000000..89595747a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
@@ -0,0 +1,535 @@
+/** @file
+ Misc library functions.
+
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+/**
+ 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 *
+BmDelPartMatchInstance (
+ 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;
+
+ 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) {
+
+ if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 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
+BmMatchDevicePaths (
+ 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 routine adjust the memory information for different memory type and
+ save them into the variables for next boot. It resets the system when
+ memory information is updated and the current boot option belongs to
+ boot category instead of application category. It doesn't count the
+ reserved memory occupied by RAM Disk.
+
+ @param Boot TRUE if current boot option belongs to boot
+ category instead of application category.
+**/
+VOID
+BmSetMemoryTypeInformationVariable (
+ IN BOOLEAN Boot
+ )
+{
+ 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;
+ }
+ VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+ PreviousMemoryTypeInformation = AllocateCopyPool (VariableSize, GET_GUID_HOB_DATA (GuidHob));
+ if (PreviousMemoryTypeInformation == NULL) {
+ return;
+ }
+
+ //
+ // 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 = BmSetVariableAndReportStatusCodeOnError (
+ 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 and the boot option belongs to boot category,
+ // 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) {
+ DEBUG ((EFI_D_INFO, "Memory Type Information settings change.\n"));
+ if (Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
+ DEBUG ((EFI_D_INFO, "...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"));
+ }
+ }
+ FreePool (PreviousMemoryTypeInformation);
+}
+
+/**
+ 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,
+ 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_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
+BmSetVariableAndReportStatusCodeOnError (
+ 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;
+}
+
+
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *Str;
+
+ Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ DEBUG ((EFI_D_INFO, "%s", Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+}
+
+/**
+ 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 convert to int.
+
+ @return The converted 8-bit number or (UINTN) -1 if conversion failed.
+**/
+UINTN
+BmCharToUint (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'0') && (Char <= L'9')) {
+ return (Char - L'0');
+ }
+
+ if ((Char >= L'A') && (Char <= L'F')) {
+ return (Char - L'A' + 0xA);
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Dispatch the deferred images that are returned from all DeferredImageLoad instances.
+
+ @retval EFI_SUCCESS At least one deferred image is loaded successfully and started.
+ @retval EFI_NOT_FOUND There is no deferred image.
+ @retval EFI_ACCESS_DENIED There are deferred images but all of them are failed to load.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDispatchDeferredImages (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+ UINTN ImageIndex;
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ VOID *Image;
+ UINTN ImageSize;
+ BOOLEAN BootOption;
+ EFI_HANDLE ImageHandle;
+ UINTN ImageCount;
+ UINTN LoadCount;
+
+ //
+ // Find all the deferred image load protocols.
+ //
+ HandleCount = 0;
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDeferredImageLoadProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ImageCount = 0;
+ LoadCount = 0;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (ImageIndex = 0; ;ImageIndex++) {
+ //
+ // Load all the deferred images in this protocol instance.
+ //
+ Status = DeferredImage->GetImageInfo (
+ DeferredImage,
+ ImageIndex,
+ &ImageDevicePath,
+ (VOID **) &Image,
+ &ImageSize,
+ &BootOption
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ ImageCount++;
+ //
+ // Load and start the image.
+ //
+ Status = gBS->LoadImage (
+ BootOption,
+ gImageHandle,
+ ImageDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ } else {
+ LoadCount++;
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // a 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+ gBS->StartImage (ImageHandle, NULL, NULL);
+
+ //
+ // Clear the Watchdog Timer after the image returns.
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ }
+ }
+ }
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ if (ImageCount == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ if (LoadCount == 0) {
+ return EFI_ACCESS_DENIED;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
new file mode 100644
index 000000000..ac866ac25
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
@@ -0,0 +1,468 @@
+/** @file
+ BDS library definition, include the file and data structure
+
+Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _INTERNAL_BM_H_
+#define _INTERNAL_BM_H_
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/Atapi.h>
+#include <IndustryStandard/Scsi.h>
+#include <IndustryStandard/Nvme.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/NvmExpressPassthru.h>
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/BootLogo.h>
+#include <Protocol/DriverHealth.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/RamDisk.h>
+#include <Protocol/DeferredImageLoad.h>
+#include <Protocol/PlatformBootManager.h>
+
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.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/UefiBootManagerLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/HiiLib.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
+
+typedef enum {
+ BmAcpiFloppyBoot,
+ BmHardwareDeviceBoot,
+ BmMessageAtapiBoot,
+ BmMessageSataBoot,
+ BmMessageUsbBoot,
+ BmMessageScsiBoot,
+ BmMiscBoot
+} BM_BOOT_TYPE;
+
+typedef
+CHAR16 *
+(* BM_GET_BOOT_DESCRIPTION) (
+ IN EFI_HANDLE Handle
+ );
+
+//
+// PlatformRecovery#### is the load option with the longest name
+//
+#define BM_OPTION_NAME_LEN sizeof ("PlatformRecovery####")
+extern CHAR16 *mBmLoadOptionName[];
+
+//
+// Maximum number of reconnect retry to repair controller; it is to limit the
+// number of recursive call of BmRepairAllControllers.
+//
+#define MAX_RECONNECT_REPAIR 10
+
+/**
+ Visitor function to be called by BmForEachVariable for each variable
+ in variable storage.
+
+ @param Name Variable name.
+ @param Guid Variable GUID.
+ @param Context The same context passed to BmForEachVariable.
+**/
+typedef
+VOID
+(*BM_VARIABLE_VISITOR) (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ VOID *Context
+ );
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+BmForEachVariable (
+ BM_VARIABLE_VISITOR Visitor,
+ VOID *Context
+ );
+
+#define BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE SIGNATURE_32 ('b', 'm', 'd', 'h')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler;
+} BM_BOOT_DESCRIPTION_ENTRY;
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+
+ @param ReconnectRepairCount To record the number of recursive call of
+ this function itself.
+**/
+VOID
+BmRepairAllControllers (
+ UINTN ReconnectRepairCount
+ );
+
+#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ BOOLEAN IsContinue;
+ UINT16 BootOption;
+ UINT8 CodeCount;
+ UINT8 WaitingKey;
+ EFI_KEY_DATA KeyData[3];
+} BM_HOTKEY;
+
+#define BM_HOTKEY_FROM_LINK(a) CR (a, BM_HOTKEY, Link, BM_HOTKEY_SIGNATURE)
+
+/**
+ Get the Option Number that wasn't used.
+
+ @param LoadOptionType Load option type.
+ @param FreeOptionNumber To receive the minimal free option number.
+
+ @retval EFI_SUCCESS The option number is found
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
+ @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
+
+**/
+EFI_STATUS
+BmGetFreeOptionNumber (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
+ );
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot. It resets the system when
+ memory information is updated and the current boot option belongs to
+ boot category instead of application category. It doesn't count the
+ reserved memory occupied by RAM Disk.
+
+ @param Boot TRUE if current boot option belongs to boot
+ category instead of application category.
+**/
+VOID
+BmSetMemoryTypeInformationVariable (
+ IN BOOLEAN Boot
+ );
+
+/**
+ 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
+BmMatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+/**
+ Connect the specific Usb device which match the short form device path.
+
+ @param DevicePath 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 DevicePath is NULL pointer.
+ DevicePath is not a USB device path.
+
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+BmConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Stop the hotkey processing.
+
+ @param Event Event pointer related to hotkey service.
+ @param Context Context pass to this function.
+**/
+VOID
+EFIAPI
+BmStopHotkeyService (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ 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,
+ 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_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
+BmSetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ 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
+BmMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+/**
+ 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 *
+BmDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ 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 convert to int.
+
+ @return The converted 8-bit number or (UINTN) -1 if conversion failed.
+**/
+UINTN
+BmCharToUint (
+ IN CHAR16 Char
+ );
+
+/**
+ Return the boot description for the controller.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetBootDescription (
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Enumerate all boot option descriptions and append " 2"/" 3"/... to make
+ unique description.
+
+ @param BootOptions Array of boot options.
+ @param BootOptionCount Count of boot options.
+**/
+VOID
+BmMakeBootOptionDescriptionUnique (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ UINTN BootOptionCount
+ );
+
+/**
+ Get the file buffer from the specified Load File instance.
+
+ @param LoadFileHandle The specified Load File instance.
+ @param FilePath The file path which will pass to LoadFile().
+
+ @return The full device path pointing to the load option buffer.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
+ IN EFI_HANDLE LoadFileHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Return the RAM Disk device path created by LoadFile.
+
+ @param FilePath The source file path.
+
+ @return Callee-to-free RAM Disk device path
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetRamDiskDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Destroy the RAM Disk.
+
+ The destroy operation includes to call RamDisk.Unregister to
+ unregister the RAM DISK from RAM DISK driver, free the memory
+ allocated for the RAM Disk.
+
+ @param RamDiskDevicePath RAM Disk device path.
+**/
+VOID
+BmDestroyRamDisk (
+ IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
+ );
+
+/**
+ Get the next possible full path pointing to the load option.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ );
+
+/**
+ Return the next matched load option buffer.
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
+ load option is read.
+
+ @param Type The load option type.
+ It's used to check whether the load option is valid.
+ When it's LoadOptionTypeMax, the routine only guarantees
+ the load option is a valid PE image but doesn't guarantee
+ the PE's subsystem type is valid.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the next full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ NULL to return the first matched full device path.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetNextLoadOptionBuffer (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ );
+#endif // _INTERNAL_BM_H_
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
new file mode 100644
index 000000000..cf5908692
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
@@ -0,0 +1,120 @@
+## @file
+# Define and produce general Boot Manager related interfaces.
+#
+# The implementation provides richful library functions supporting load option
+# manipulation, hotkey registration, UEFI boot, connect/disconnect, console
+# manipulation, driver health checking and etc.
+#
+# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiBootManagerLib
+ MODULE_UNI_FILE = UefiBootManagerLib.uni
+ FILE_GUID = 8D4752BC-595E-49a2-B4AF-F3F57B601DE9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiBootManagerLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BmConnect.c
+ BmMisc.c
+ BmConsole.c
+ BmBoot.c
+ BmBootDescription.c
+ BmLoadOption.c
+ BmHotkey.c
+ BmDriverHealth.c
+ InternalBm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HobLib
+ PcdLib
+ BaseLib
+ UefiLib
+ DebugLib
+ PrintLib
+ BaseMemoryLib
+ DevicePathLib
+ PerformanceLib
+ PeCoffGetEntryPointLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ DxeServicesLib
+ ReportStatusCodeLib
+ PerformanceLib
+ HiiLib
+ SortLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## SystemTable (The identifier of memory type information type in system table)
+ ## SOMETIMES_CONSUMES ## HOB (The hob holding memory type information)
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryTypeInformation."
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryTypeInformation."
+ gEfiMemoryTypeInformationGuid
+
+ ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable)
+ ## SOMETIMES_CONSUMES ## 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_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
+ gEfiGlobalVariableGuid
+
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoAhciInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoScsiInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoSdMmcInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiNvmExpressPassThruProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDiskInfoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverHealthProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiRamDiskProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDeferredImageLoadProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPlatformBootManagerProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxRepairCount ## CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni
new file mode 100644
index 000000000..9471f81bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Define and produce general Boot Manager related interfaces.
+//
+// The implementation provides richful library functions supporting load option
+// manipulation, hotkey registration, UEFI boot, connect/disconnect, console
+// manipulation, driver health checking and etc.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Define and produce general Boot Manager related interfaces"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The implementation provides richful library functions supporting load option manipulation, hotkey registration, UEFI boot, connect/disconnect, console manipulation, driver health checking and etc."
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c
new file mode 100644
index 000000000..b2f372324
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c
@@ -0,0 +1,90 @@
+/** @file
+ Language related HII Library implementation.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "InternalHiiLib.h"
+
+/**
+ Retrieves a pointer to the a Null-terminated ASCII string containing the list
+ of languages that an HII handle in the HII Database supports. The returned
+ string is allocated using AllocatePool(). The caller is responsible for freeing
+ the returned string using FreePool(). The format of the returned string follows
+ the language format assumed the HII Database.
+
+ If HiiHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+
+ @retval NULL HiiHandle is not registered in the HII database
+ @retval NULL There are not enough resources available to retrieve the supported
+ languages.
+ @retval NULL The list of supported languages could not be retrieved.
+ @retval Other A pointer to the Null-terminated ASCII string of supported languages.
+
+**/
+CHAR8 *
+EFIAPI
+HiiGetSupportedLanguages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN LanguageSize;
+ CHAR8 TempSupportedLanguages;
+ CHAR8 *SupportedLanguages;
+
+ ASSERT (HiiHandle != NULL);
+
+ //
+ // Retrieve the size required for the supported languages buffer.
+ //
+ LanguageSize = 0;
+ Status = gHiiString->GetLanguages (gHiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
+
+ //
+ // If GetLanguages() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetLanguages()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ //
+ // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
+ //
+ return NULL;
+ }
+
+ //
+ // Allocate the supported languages buffer.
+ //
+ SupportedLanguages = AllocateZeroPool (LanguageSize);
+ if (SupportedLanguages == NULL) {
+ //
+ // Return NULL if allocation fails.
+ //
+ return NULL;
+ }
+
+ //
+ // Retrieve the supported languages string
+ //
+ Status = gHiiString->GetLanguages (gHiiString, HiiHandle, SupportedLanguages, &LanguageSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (SupportedLanguages);
+ return NULL;
+ }
+
+ //
+ // Return the Null-terminated ASCII string of supported languages
+ //
+ return SupportedLanguages;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLib.c b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
new file mode 100644
index 000000000..564169bc1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
@@ -0,0 +1,4481 @@
+/** @file
+ HII Library implementation that uses DXE protocols and services.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalHiiLib.h"
+
+#define GUID_CONFIG_STRING_TYPE 0x00
+#define NAME_CONFIG_STRING_TYPE 0x01
+#define PATH_CONFIG_STRING_TYPE 0x02
+
+#define ACTION_SET_DEFAUTL_VALUE 0x01
+#define ACTION_VALIDATE_SETTING 0x02
+
+#define HII_LIB_DEFAULT_VARSTORE_SIZE 0x200
+
+typedef struct {
+ LIST_ENTRY Entry; // Link to Block array
+ UINT16 Offset;
+ UINT16 Width;
+ UINT8 OpCode;
+ UINT8 Scope;
+} IFR_BLOCK_DATA;
+
+typedef struct {
+ EFI_VARSTORE_ID VarStoreId;
+ UINT16 Size;
+} IFR_VARSTORAGE_DATA;
+
+//
+// <ConfigHdr> Template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00";
+
+EFI_FORM_BROWSER2_PROTOCOL *mUefiFormBrowser2 = NULL;
+
+//
+// Template used to mark the end of a list of packages
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER mEndOfPakageList = {
+ sizeof (EFI_HII_PACKAGE_HEADER),
+ EFI_HII_PACKAGE_END
+};
+
+/**
+ Extract Hii package list GUID for given HII handle.
+
+ If HiiHandle could not be found in the HII database, then ASSERT.
+ If Guid is NULL, then ASSERT.
+
+ @param Handle Hii handle
+ @param Guid Package list GUID
+
+ @retval EFI_SUCCESS Successfully extract GUID from Hii database.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiExtractGuidFromHiiHandle (
+ IN EFI_HII_HANDLE Handle,
+ OUT EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+
+ ASSERT (Guid != NULL);
+ ASSERT (Handle != NULL);
+
+ //
+ // Get HII PackageList
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ ASSERT (Status != EFI_NOT_FOUND);
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (HiiPackageList);
+ return Status;
+ }
+
+ //
+ // Extract GUID
+ //
+ CopyGuid (Guid, &HiiPackageList->PackageListGuid);
+
+ FreePool (HiiPackageList);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a list of packages in the HII Database and returns the HII Handle
+ associated with that registration. If an HII Handle has already been registered
+ with the same PackageListGuid and DeviceHandle, then NULL is returned. If there
+ are not enough resources to perform the registration, then NULL is returned.
+ If an empty list of packages is passed in, then NULL is returned. If the size of
+ the list of package is 0, then NULL is returned.
+
+ The variable arguments are pointers which point to package header that defined
+ by UEFI VFR compiler and StringGather tool.
+
+ #pragma pack (push, 1)
+ typedef struct {
+ UINT32 BinaryLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ } EDKII_AUTOGEN_PACKAGES_HEADER;
+ #pragma pack (pop)
+
+ @param[in] PackageListGuid The GUID of the package list.
+ @param[in] DeviceHandle If not NULL, the Device Handle on which
+ an instance of DEVICE_PATH_PROTOCOL is installed.
+ This Device Handle uniquely defines the device that
+ the added packages are associated with.
+ @param[in] ... The variable argument list that contains pointers
+ to packages terminated by a NULL.
+
+ @retval NULL A HII Handle has already been registered in the HII Database with
+ the same PackageListGuid and DeviceHandle.
+ @retval NULL The HII Handle could not be created.
+ @retval NULL An empty list of packages was passed in.
+ @retval NULL All packages are empty.
+ @retval Other The HII Handle associated with the newly registered package list.
+
+**/
+EFI_HII_HANDLE
+EFIAPI
+HiiAddPackages (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_HANDLE DeviceHandle OPTIONAL,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ UINT32 *Package;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
+ EFI_HII_HANDLE HiiHandle;
+ UINT32 Length;
+ UINT8 *Data;
+
+ ASSERT (PackageListGuid != NULL);
+
+ //
+ // Calculate the length of all the packages in the variable argument list
+ //
+ for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
+ Length += (ReadUnaligned32 (Package) - sizeof (UINT32));
+ }
+ VA_END (Args);
+
+ //
+ // If there are no packages in the variable argument list or all the packages
+ // are empty, then return a NULL HII Handle
+ //
+ if (Length == 0) {
+ return NULL;
+ }
+
+ //
+ // 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 NULL;
+ }
+
+ //
+ // Fill in the GUID and Length of the Package List Header
+ //
+ CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid);
+ PackageListHeader->PackageLength = Length;
+
+ //
+ // Initialize a pointer to the beginning if the Package List data
+ //
+ Data = (UINT8 *)(PackageListHeader + 1);
+
+ //
+ // Copy the data from each package in the variable argument list
+ //
+ for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
+ Length = ReadUnaligned32 (Package) - sizeof (UINT32);
+ CopyMem (Data, Package + 1, Length);
+ Data += Length;
+ }
+ VA_END (Args);
+
+ //
+ // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list
+ //
+ CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList));
+
+ //
+ // Register the package list with the HII Database
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageListHeader,
+ DeviceHandle,
+ &HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ HiiHandle = NULL;
+ }
+
+ //
+ // Free the allocated package list
+ //
+ FreePool (PackageListHeader);
+
+ //
+ // Return the new HII Handle
+ //
+ return HiiHandle;
+}
+
+/**
+ Removes a package list from the HII database.
+
+ If HiiHandle is NULL, then ASSERT.
+ If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT.
+
+ @param[in] HiiHandle The handle that was previously registered in the HII database
+
+**/
+VOID
+EFIAPI
+HiiRemovePackages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (HiiHandle != NULL);
+ Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Retrieves the array of all the HII Handles or the HII handles of a specific
+ package list GUID in the HII Database.
+ This array is terminated with a NULL HII Handle.
+ This function allocates the returned array using AllocatePool().
+ The caller is responsible for freeing the array with FreePool().
+
+ @param[in] PackageListGuid An optional parameter that is used to request
+ HII Handles associated with a specific
+ Package List GUID. If this parameter is NULL,
+ then all the HII Handles in the HII Database
+ are returned. If this parameter is not NULL,
+ then zero or more HII Handles associated with
+ PackageListGuid are returned.
+
+ @retval NULL No HII handles were found in the HII database
+ @retval NULL The array of HII Handles could not be retrieved
+ @retval Other A pointer to the NULL terminated array of HII Handles
+
+**/
+EFI_HII_HANDLE *
+EFIAPI
+HiiGetHiiHandles (
+ IN CONST EFI_GUID *PackageListGuid OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleBufferLength;
+ EFI_HII_HANDLE TempHiiHandleBuffer;
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ EFI_GUID Guid;
+ UINTN Index1;
+ UINTN Index2;
+
+ //
+ // Retrieve the size required for the buffer of all HII handles.
+ //
+ HandleBufferLength = 0;
+ Status = gHiiDatabase->ListPackageLists (
+ gHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &HandleBufferLength,
+ &TempHiiHandleBuffer
+ );
+
+ //
+ // If ListPackageLists() returns EFI_SUCCESS for a zero size,
+ // then there are no HII handles in the HII database. If ListPackageLists()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII
+ // handles in the HII database.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ //
+ // Return NULL if the size can not be retrieved, or if there are no HII
+ // handles in the HII Database
+ //
+ return NULL;
+ }
+
+ //
+ // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator
+ //
+ HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE));
+ if (HiiHandleBuffer == NULL) {
+ //
+ // Return NULL if allocation fails.
+ //
+ return NULL;
+ }
+
+ //
+ // Retrieve the array of HII Handles in the HII Database
+ //
+ Status = gHiiDatabase->ListPackageLists (
+ gHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &HandleBufferLength,
+ HiiHandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the HII handles can not be retrieved.
+ //
+ FreePool (HiiHandleBuffer);
+ return NULL;
+ }
+
+ if (PackageListGuid == NULL) {
+ //
+ // Return the NULL terminated array of HII handles in the HII Database
+ //
+ return HiiHandleBuffer;
+ } else {
+ for (Index1 = 0, Index2 = 0; HiiHandleBuffer[Index1] != NULL; Index1++) {
+ Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index1], &Guid);
+ ASSERT_EFI_ERROR (Status);
+ if (CompareGuid (&Guid, PackageListGuid)) {
+ HiiHandleBuffer[Index2++] = HiiHandleBuffer[Index1];
+ }
+ }
+ if (Index2 > 0) {
+ HiiHandleBuffer[Index2] = NULL;
+ return HiiHandleBuffer;
+ } else {
+ FreePool (HiiHandleBuffer);
+ return NULL;
+ }
+ }
+}
+
+/**
+ This function allows a caller to extract the form set opcode form the Hii Handle.
+ The returned buffer is allocated using AllocatePool().The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ @param Handle The HII handle.
+ @param Buffer On return, points to a pointer which point to the buffer that contain the formset opcode.
+ @param BufferSize On return, points to the length of the buffer.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
+ @retval EFI_NOT_FOUND Can't find the package data for the input Handle.
+ @retval EFI_INVALID_PARAMETER The input parameters are not correct.
+ @retval EFI_SUCCESS Get the formset opcode from the hii handle successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetFormSetFromHiiHandle(
+ IN EFI_HII_HANDLE Handle,
+ OUT EFI_IFR_FORM_SET **Buffer,
+ OUT UINTN *BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN PackageListSize;
+ UINTN TempSize;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ UINT8 *FormSetBuffer;
+ UINT8 *TempBuffer;
+ UINT32 Offset;
+ UINT32 Offset2;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ TempSize = 0;
+ FormSetBuffer = NULL;
+ TempBuffer = NULL;
+
+ //
+ // Get HII PackageList
+ //
+ PackageListSize = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
+ if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ return Status;
+ }
+
+ HiiPackageList = AllocatePool (PackageListSize);
+ if (HiiPackageList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get Form package from this HII package List
+ //
+ Status = EFI_NOT_FOUND;
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
+
+ while (Offset < PackageListLength) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset += PackageHeader.Length;
+
+ if (PackageHeader.Type != EFI_HII_PACKAGE_FORMS) {
+ continue;
+ }
+
+ //
+ // 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) {
+ continue;
+ }
+
+ if (FormSetBuffer != NULL){
+ TempBuffer = ReallocatePool (
+ TempSize,
+ TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length,
+ FormSetBuffer
+ );
+ if (TempBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CopyMem (TempBuffer + TempSize, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
+ FormSetBuffer = NULL;
+ } else {
+ TempBuffer = AllocatePool (TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
+ if (TempBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CopyMem (TempBuffer, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
+ }
+ TempSize += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ FormSetBuffer = TempBuffer;
+
+ Status = EFI_SUCCESS;
+ //
+ //One form package has one formset, exit current form package to search other form package in the packagelist.
+ //
+ break;
+ }
+ }
+Done:
+ FreePool (HiiPackageList);
+
+ *BufferSize = TempSize;
+ *Buffer = (EFI_IFR_FORM_SET *)FormSetBuffer;
+
+ return Status;
+}
+
+/**
+ Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
+ hex digits that appear between a '=' and a '&' in a config string.
+
+ If ConfigString is NULL, then ASSERT().
+
+ @param[in] ConfigString Pointer to a Null-terminated Unicode string.
+
+ @return Pointer to the Null-terminated Unicode result string.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiLowerConfigString (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+
+ return ConfigString;
+}
+
+/**
+ Uses the BlockToConfig() service of the Config Routing Protocol to
+ convert <ConfigRequest> and a buffer to a <ConfigResp>
+
+ If ConfigRequest is NULL, then ASSERT().
+ If Block is NULL, then ASSERT().
+
+ @param[in] ConfigRequest Pointer to a Null-terminated Unicode string.
+ @param[in] Block Pointer to a block of data.
+ @param[in] BlockSize The zie, in bytes, of Block.
+
+ @retval NULL The <ConfigResp> string could not be generated.
+ @retval Other Pointer to the Null-terminated Unicode <ConfigResp> string.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiBlockToConfig (
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN UINTN BlockSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING ConfigResp;
+ CHAR16 *Progress;
+
+ ASSERT (ConfigRequest != NULL);
+ ASSERT (Block != NULL);
+
+ //
+ // Convert <ConfigRequest> to <ConfigResp>
+ //
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ Block,
+ BlockSize,
+ &ConfigResp,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return ConfigResp;
+}
+
+/**
+ Uses the BrowserCallback() service of the Form Browser Protocol to retrieve
+ or set uncommitted data. If sata i being retrieved, then the buffer is
+ allocated using AllocatePool(). The caller is then responsible for freeing
+ the buffer using FreePool().
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] SetResultsData If not NULL, then this parameter specified the buffer
+ of uncommited data to set. If this parameter is NULL,
+ then the caller is requesting to get the uncommited data
+ from the Form Browser.
+
+ @retval NULL The uncommitted data could not be retrieved.
+ @retval Other A pointer to a buffer containing the uncommitted data.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiBrowserCallback (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN CONST EFI_STRING SetResultsData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN ResultsDataSize;
+ EFI_STRING ResultsData;
+ CHAR16 TempResultsData;
+
+ //
+ // Locate protocols
+ //
+ if (mUefiFormBrowser2 == NULL) {
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2);
+ if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) {
+ return NULL;
+ }
+ }
+
+ ResultsDataSize = 0;
+
+ if (SetResultsData != NULL) {
+ //
+ // Request to to set data in the uncommitted browser state information
+ //
+ ResultsData = SetResultsData;
+ } else {
+ //
+ // Retrieve the length of the buffer required ResultsData from the Browser Callback
+ //
+ Status = mUefiFormBrowser2->BrowserCallback (
+ mUefiFormBrowser2,
+ &ResultsDataSize,
+ &TempResultsData,
+ TRUE,
+ VariableGuid,
+ VariableName
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // No Resluts Data, only allocate one char for '\0'
+ //
+ ResultsData = AllocateZeroPool (sizeof (CHAR16));
+ return ResultsData;
+ }
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return NULL;
+ }
+
+ //
+ // Allocate the ResultsData buffer
+ //
+ ResultsData = AllocateZeroPool (ResultsDataSize);
+ if (ResultsData == NULL) {
+ return NULL;
+ }
+ }
+
+ //
+ // Retrieve or set the ResultsData from the Browser Callback
+ //
+ Status = mUefiFormBrowser2->BrowserCallback (
+ mUefiFormBrowser2,
+ &ResultsDataSize,
+ ResultsData,
+ (BOOLEAN)(SetResultsData == NULL),
+ VariableGuid,
+ VariableName
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return ResultsData;
+}
+
+/**
+ Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
+ information that includes a GUID, an optional Unicode string name, and a device
+ path. The string returned is allocated with AllocatePool(). The caller is
+ responsible for freeing the allocated string with FreePool().
+
+ The format of a <ConfigHdr> is as follows:
+
+ GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
+
+ @param[in] Guid Pointer to an EFI_GUID that is the routing information
+ GUID. Each of the 16 bytes in Guid is converted to
+ a 2 Unicode character hexadecimal string. This is
+ an optional parameter that may be NULL.
+ @param[in] Name Pointer to a Null-terminated Unicode string that is
+ the routing information NAME. This is an optional
+ parameter that may be NULL. Each 16-bit Unicode
+ character in Name is converted to a 4 character Unicode
+ hexadecimal string.
+ @param[in] DriverHandle The driver handle which supports a Device Path Protocol
+ that is the routing information PATH. Each byte of
+ the Device Path associated with DriverHandle is converted
+ to a 2 Unicode character hexadecimal string.
+
+ @retval NULL DriverHandle does not support the Device Path Protocol.
+ @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
+
+**/
+EFI_STRING
+EFIAPI
+HiiConstructConfigHdr (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name, OPTIONAL
+ IN EFI_HANDLE DriverHandle
+ )
+{
+ UINTN NameLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DevicePathSize;
+ CHAR16 *String;
+ CHAR16 *ReturnString;
+ UINTN Index;
+ UINT8 *Buffer;
+ UINTN MaxLen;
+
+ //
+ // Compute the length of Name in Unicode characters.
+ // If Name is NULL, then the length is 0.
+ //
+ NameLength = 0;
+ if (Name != NULL) {
+ NameLength = StrLen (Name);
+ }
+
+ DevicePath = NULL;
+ DevicePathSize = 0;
+ //
+ // Retrieve DevicePath Protocol associated with DriverHandle
+ //
+ if (DriverHandle != NULL) {
+ DevicePath = DevicePathFromHandle (DriverHandle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+ //
+ // Compute the size of the device path in bytes
+ //
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ }
+
+ //
+ // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
+ // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
+ //
+ MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
+ String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ if (String == NULL) {
+ return NULL;
+ }
+
+ //
+ // Start with L"GUID="
+ //
+ StrCpyS (String, MaxLen, L"GUID=");
+ ReturnString = String;
+ String += StrLen (String);
+
+ if (Guid != NULL) {
+ //
+ // Append Guid converted to <HexCh>32
+ //
+ for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
+ UnicodeValueToStringS (
+ String,
+ MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *(Buffer++),
+ 2
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+ }
+
+ //
+ // Append L"&NAME="
+ //
+ StrCatS (ReturnString, MaxLen, L"&NAME=");
+ String += StrLen (String);
+
+ if (Name != NULL) {
+ //
+ // Append Name converted to <Char>NameLength
+ //
+ for (; *Name != L'\0'; Name++) {
+ UnicodeValueToStringS (
+ String,
+ sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *Name,
+ 4
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+ }
+
+ //
+ // Append L"&PATH="
+ //
+ StrCatS (ReturnString, MaxLen, L"&PATH=");
+ String += StrLen (String);
+
+ //
+ // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
+ //
+ for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
+ UnicodeValueToStringS (
+ String,
+ sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *(Buffer++),
+ 2
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+
+ //
+ // Null terminate the Unicode string
+ //
+ *String = L'\0';
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ return InternalHiiLowerConfigString (ReturnString);
+}
+
+/**
+ Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
+ to binary buffer from <ConfigHdr>.
+
+ This is a internal function.
+
+ @param String UEFI configuration string.
+ @param Flag Flag specifies what type buffer will be retrieved.
+ @param Buffer Binary of Guid, Name or Device path.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
+ @retval EFI_SUCCESS The buffer data is retrieved and translated to
+ binary format.
+
+**/
+EFI_STATUS
+InternalHiiGetBufferFromString (
+ IN EFI_STRING String,
+ IN UINT8 Flag,
+ OUT UINT8 **Buffer
+ )
+{
+ UINTN Length;
+ EFI_STRING ConfigHdr;
+ CHAR16 *StringPtr;
+ UINT8 *DataBuffer;
+ CHAR16 TemStr[5];
+ UINTN Index;
+ UINT8 DigitUint8;
+
+ if (String == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DataBuffer = NULL;
+ StringPtr = NULL;
+ ConfigHdr = String;
+ //
+ // The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
+ // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
+ //
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+
+ switch (Flag) {
+ case GUID_CONFIG_STRING_TYPE:
+ case PATH_CONFIG_STRING_TYPE:
+ //
+ // The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
+ // as the device path and Guid resides in RAM memory.
+ // Translate the data into binary.
+ //
+ DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Convert binary byte one by one
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = ConfigHdr[Index];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DataBuffer [Index/2] = DigitUint8;
+ } else {
+ DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
+ }
+ }
+
+ *Buffer = DataBuffer;
+ break;
+
+ case NAME_CONFIG_STRING_TYPE:
+ //
+ // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
+ //
+
+ //
+ // Add the tailling char L'\0'
+ //
+ DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Convert character one by one
+ //
+ StringPtr = (CHAR16 *) DataBuffer;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index += 4) {
+ StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), ConfigHdr + Index, 4);
+ StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
+ }
+ //
+ // Add tailing L'\0' character
+ //
+ StringPtr[Index/4] = L'\0';
+
+ *Buffer = DataBuffer;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function checks VarOffset and VarWidth is in the block range.
+
+ @param BlockArray The block array is to be checked.
+ @param VarOffset Offset of var to the structure
+ @param VarWidth Width of var.
+
+ @retval TRUE This Var is in the block range.
+ @retval FALSE This Var is not in the block range.
+**/
+BOOLEAN
+BlockArrayCheck (
+ IN IFR_BLOCK_DATA *BlockArray,
+ IN UINT16 VarOffset,
+ IN UINT16 VarWidth
+ )
+{
+ LIST_ENTRY *Link;
+ IFR_BLOCK_DATA *BlockData;
+
+ //
+ // No Request Block array, all vars are got.
+ //
+ if (BlockArray == NULL) {
+ return TRUE;
+ }
+
+ //
+ // Check the input var is in the request block range.
+ //
+ for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ @param ValueString String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param ValueData The output value. Caller takes the responsibility
+ to free memory.
+ @param ValueLength Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiGetValueOfNumber (
+ IN EFI_STRING ValueString,
+ OUT UINT8 **ValueData,
+ OUT UINTN *ValueLength
+ )
+{
+ EFI_STRING StringPtr;
+ UINTN Length;
+ UINT8 *Buf;
+ UINT8 DigitUint8;
+ UINTN Index;
+ CHAR16 TemStr[2];
+
+ ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
+ ASSERT (*ValueString != L'\0');
+
+ //
+ // Get the length of value string
+ //
+ StringPtr = ValueString;
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ Length = StringPtr - ValueString;
+
+ //
+ // Allocate buffer to store the value
+ //
+ Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (Buf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Convert character one by one to the value buffer
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = ValueString[Length - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ Buf [Index/2] = DigitUint8;
+ } else {
+ Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
+ }
+ }
+
+ //
+ // Set the converted value and string length.
+ //
+ *ValueData = Buf;
+ *ValueLength = Length;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get value from config request resp string.
+
+ @param ConfigElement ConfigResp string contains the current setting.
+ @param VarName The variable name which need to get value.
+ @param VarValue The return value.
+
+ @retval EFI_SUCCESS Get the value for the VarName
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+**/
+EFI_STATUS
+GetValueFromRequest (
+ IN CHAR16 *ConfigElement,
+ IN CHAR16 *VarName,
+ OUT UINT64 *VarValue
+ )
+{
+ UINT8 *TmpBuffer;
+ CHAR16 *StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ //
+ // Find VarName related string.
+ //
+ StringPtr = StrStr (ConfigElement, VarName);
+ ASSERT (StringPtr != NULL);
+
+ //
+ // Skip the "VarName=" string
+ //
+ StringPtr += StrLen (VarName) + 1;
+
+ //
+ // Get Offset
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *VarValue = 0;
+ CopyMem (VarValue, TmpBuffer, (((Length + 1) / 2) < sizeof (UINT64)) ? ((Length + 1) / 2) : sizeof (UINT64));
+
+ FreePool (TmpBuffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ Base on the NameValueType, if it is TRUE, RequestElement and HiiHandle is valid;
+ else the VarBuffer and CurrentBlockArray is valid.
+
+ @param HiiPackageList Point to Hii package list.
+ @param PackageListLength The length of the pacakge.
+ @param VarGuid Guid of the buffer storage.
+ @param VarName Name of the buffer storage.
+ @param VarBuffer The data buffer for the storage.
+ @param CurrentBlockArray The block array from the config Requst string.
+ @param RequestElement The config string for this storage.
+ @param HiiHandle The HiiHandle for this formset.
+ @param NameValueType Whether current storage is name/value varstore or not.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+ValidateQuestionFromVfr (
+ IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
+ IN UINTN PackageListLength,
+ IN EFI_GUID *VarGuid,
+ IN CHAR16 *VarName,
+ IN UINT8 *VarBuffer,
+ IN IFR_BLOCK_DATA *CurrentBlockArray,
+ IN CHAR16 *RequestElement,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BOOLEAN NameValueType
+ )
+{
+ IFR_BLOCK_DATA VarBlockData;
+ UINT16 Offset;
+ UINT16 Width;
+ UINT64 VarValue;
+ EFI_IFR_TYPE_VALUE TmpValue;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT32 PackageOffset;
+ UINT8 *PackageData;
+ UINTN IfrOffset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueStore;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ IFR_VARSTORAGE_DATA VarStoreData;
+ EFI_IFR_ONE_OF *IfrOneOf;
+ EFI_IFR_NUMERIC *IfrNumeric;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_STRING *IfrString;
+ CHAR8 *VarStoreName;
+ UINTN Index;
+ CHAR16 *QuestionName;
+ CHAR16 *StringPtr;
+ UINT16 BitOffset;
+ UINT16 BitWidth;
+ UINT16 TotalBits;
+ UINTN StartBit;
+ UINTN EndBit;
+ BOOLEAN QuestionReferBitField;
+ UINT32 BufferValue;
+
+ //
+ // Initialize the local variables.
+ //
+ Index = 0;
+ VarStoreName = NULL;
+ Status = EFI_SUCCESS;
+ VarValue = 0;
+ IfrVarStore = NULL;
+ IfrNameValueStore = NULL;
+ IfrEfiVarStore = NULL;
+ ZeroMem (&VarStoreData, sizeof (IFR_VARSTORAGE_DATA));
+ ZeroMem (&VarBlockData, sizeof (VarBlockData));
+ BitOffset = 0;
+ BitWidth = 0;
+ QuestionReferBitField = FALSE;
+
+ //
+ // Check IFR value is in block data, then Validate Value
+ //
+ PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ while (PackageOffset < PackageListLength) {
+ CopyMem (&PackageHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PackageHeader));
+
+ //
+ // Parse IFR opcode from the form package.
+ //
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ IfrOffset = sizeof (PackageHeader);
+ PackageData = (UINT8 *) HiiPackageList + PackageOffset;
+ while (IfrOffset < PackageHeader.Length) {
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
+ //
+ // Validate current setting to the value built in IFR opcode
+ //
+ switch (IfrOpHdr->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // VarStoreId has been found. No further found.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+ //
+ // Find the matched VarStoreId to the input VarGuid and VarName
+ //
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
+ if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) {
+ VarStoreName = (CHAR8 *) IfrVarStore->Name;
+ for (Index = 0; VarStoreName[Index] != 0; Index ++) {
+ if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
+ break;
+ }
+ }
+ //
+ // The matched VarStore is found.
+ //
+ if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
+ IfrVarStore = NULL;
+ }
+ } else {
+ IfrVarStore = NULL;
+ }
+
+ if (IfrVarStore != NULL) {
+ VarStoreData.VarStoreId = IfrVarStore->VarStoreId;
+ VarStoreData.Size = IfrVarStore->Size;
+ }
+ break;
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // VarStoreId has been found. No further found.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+ //
+ // Find the matched VarStoreId to the input VarGuid
+ //
+ IfrNameValueStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
+ if (!CompareGuid ((EFI_GUID *) (VOID *) &IfrNameValueStore->Guid, VarGuid)) {
+ IfrNameValueStore = NULL;
+ }
+
+ if (IfrNameValueStore != NULL) {
+ VarStoreData.VarStoreId = IfrNameValueStore->VarStoreId;
+ }
+ break;
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // VarStore is found. Don't need to search any more.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+
+ //
+ // If the length is small than the structure, this is from old efi
+ // varstore definition. Old efi varstore get config directly from
+ // GetVariable function.
+ //
+ if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
+ break;
+ }
+
+ if (CompareGuid ((EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid, VarGuid)) {
+ VarStoreName = (CHAR8 *) IfrEfiVarStore->Name;
+ for (Index = 0; VarStoreName[Index] != 0; Index ++) {
+ if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
+ break;
+ }
+ }
+ //
+ // The matched VarStore is found.
+ //
+ if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
+ IfrEfiVarStore = NULL;
+ }
+ } else {
+ IfrEfiVarStore = NULL;
+ }
+
+ if (IfrEfiVarStore != NULL) {
+ //
+ // Find the matched VarStore
+ //
+ VarStoreData.VarStoreId = IfrEfiVarStore->VarStoreId;
+ VarStoreData.Size = IfrEfiVarStore->Size;
+ }
+ break;
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // Check the matched VarStoreId is found.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_SUCCESS;
+ }
+ break;
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Check whether current value is the one of option.
+ //
+
+ //
+ // OneOf question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
+ if (IfrOneOf->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrOneOf->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header and Width by DataType Flags
+ //
+ if (QuestionReferBitField) {
+ //
+ // Get the byte offset/width for bit field.
+ //
+ BitOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
+ BitWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ Offset = BitOffset / 8;
+ TotalBits = BitOffset % 8 + BitWidth;
+ Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
+ } else {
+ Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the current value for oneof opcode
+ //
+ VarValue = 0;
+ if (QuestionReferBitField) {
+ //
+ // Get the value in bit fields.
+ //
+ StartBit = BitOffset % 8;
+ EndBit = StartBit + BitWidth - 1;
+ CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
+ VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
+ } else {
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ }
+ //
+ // Set Block Data, to be checked in the following Oneof option opcode.
+ //
+ VarBlockData.OpCode = IfrOpHdr->OpCode;
+ VarBlockData.Scope = IfrOpHdr->Scope;
+ break;
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Check the current value is in the numeric range.
+ //
+
+ //
+ // Numeric question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
+ if (IfrNumeric->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrNumeric->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header and Width by DataType Flags
+ //
+ if (QuestionReferBitField) {
+ //
+ // Get the byte offset/width for bit field.
+ //
+ BitOffset = IfrNumeric->Question.VarStoreInfo.VarOffset;
+ BitWidth = IfrNumeric->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ Offset = BitOffset / 8;
+ TotalBits = BitOffset % 8 + BitWidth;
+ Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
+ } else {
+ Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the current value is in the numeric range.
+ //
+ VarValue = 0;
+ if (QuestionReferBitField) {
+ //
+ // Get the value in the bit fields.
+ //
+ StartBit = BitOffset % 8;
+ EndBit = StartBit + BitWidth - 1;
+ CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
+ VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
+ } else {
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ }
+ if ( QuestionReferBitField) {
+ //
+ // Value in bit fields was stored as UINt32 type.
+ //
+ if ((IfrNumeric->Flags & EDKII_IFR_DISPLAY_BIT) == 0) {
+ if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (VarValue < IfrNumeric->data.u32.MinValue || VarValue > IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ } else {
+ if ((IfrNumeric->Flags & EFI_IFR_DISPLAY) == 0) {
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if ((INT8) VarValue < (INT8) IfrNumeric->data.u8.MinValue || (INT8) VarValue > (INT8) IfrNumeric->data.u8.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if ((INT16) VarValue < (INT16) IfrNumeric->data.u16.MinValue || (INT16) VarValue > (INT16) IfrNumeric->data.u16.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if ((INT64) VarValue < (INT64) IfrNumeric->data.u64.MinValue || (INT64) VarValue > (INT64) IfrNumeric->data.u64.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ } else {
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ //
+ // Check value is BOOLEAN type, only 0 and 1 is valid.
+ //
+
+ //
+ // CheckBox question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
+ if (IfrCheckBox->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrCheckBox->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header
+ //
+ if (QuestionReferBitField) {
+ //
+ // Get the byte offset/width for bit field.
+ //
+ BitOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+ BitWidth = 1;
+ Offset = BitOffset / 8;
+ TotalBits = BitOffset % 8 + BitWidth;
+ Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
+ } else {
+ Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) sizeof (BOOLEAN);
+ }
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check the current value is in the numeric range.
+ //
+ VarValue = 0;
+ if (QuestionReferBitField) {
+ //
+ // Get the value in bit fields.
+ //
+ StartBit = BitOffset % 8;
+ EndBit = StartBit + BitWidth - 1;
+ CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
+ VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
+ } else {
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ }
+ //
+ // Boolean type, only 1 and 0 is valid.
+ //
+ if (VarValue > 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_STRING_OP:
+ //
+ // Check current string length is less than maxsize
+ //
+
+ //
+ // CheckBox question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrString = (EFI_IFR_STRING *) IfrOpHdr;
+ if (IfrString->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+ //
+ // Get the Max size of the string.
+ //
+ Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrString->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ StringPtr = StrStr (RequestElement, QuestionName);
+ if (StringPtr == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Skip the VarName.
+ //
+ StringPtr += StrLen (QuestionName);
+
+ //
+ // Skip the "=".
+ //
+ StringPtr += 1;
+
+ //
+ // Check current string length is less than maxsize
+ // e.g Config String: "0041004200430044", Unicode String: "ABCD". Unicode String length = Config String length / 4.
+ // Config string format in UEFI spec.
+ // <NvConfig> ::= <Label>'='<String>
+ // <String> ::= [<Char>]+
+ // <Char> ::= <HexCh>4
+ //
+ if (StrLen (StringPtr) / 4 > IfrString->MaxSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // Get Offset/Width by Question header and OneOf Flags
+ //
+ Offset = IfrString->Question.VarStoreInfo.VarOffset;
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check current string length is less than maxsize
+ //
+ if (StrLen ((CHAR16 *) (VarBuffer + Offset)) > IfrString->MaxSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ break;
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // Opcode Scope is zero. This one of option is not to be checked.
+ //
+ if (VarBlockData.Scope == 0) {
+ break;
+ }
+
+ //
+ // Only check for OneOf and OrderList opcode
+ //
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
+ if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
+ //
+ // Check current value is the value of one of option.
+ //
+ ASSERT (IfrOneOfOption->Type <= EFI_IFR_TYPE_NUM_SIZE_64);
+ ZeroMem (&TmpValue, sizeof (EFI_IFR_TYPE_VALUE));
+ CopyMem (&TmpValue, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ if (VarValue == TmpValue.u64) {
+ //
+ // The value is one of option value.
+ // Set OpCode to Zero, don't need check again.
+ //
+ VarBlockData.OpCode = 0;
+ }
+ }
+ break;
+ case EFI_IFR_END_OP:
+ QuestionReferBitField = FALSE;
+ //
+ // Decrease opcode scope for the validated opcode
+ //
+ if (VarBlockData.Scope > 0) {
+ VarBlockData.Scope --;
+ }
+
+ //
+ // OneOf value doesn't belong to one of option value.
+ //
+ if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)((UINT8*)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ QuestionReferBitField = TRUE;
+ }
+ break;
+ default:
+ //
+ // Increase Scope for the validated opcode
+ //
+ if (VarBlockData.Scope > 0) {
+ VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
+ }
+ break;
+ }
+ //
+ // Go to the next opcode
+ //
+ IfrOffset += IfrOpHdr->Length;
+ }
+ //
+ // Only one form is in a package list.
+ //
+ break;
+ }
+
+ //
+ // Go to next package.
+ //
+ PackageOffset += PackageHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ @param ConfigElement ConfigResp element string contains the current setting.
+ @param CurrentBlockArray Current block array.
+ @param VarBuffer Data buffer for this varstore.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+GetBlockDataInfo (
+ IN CHAR16 *ConfigElement,
+ OUT IFR_BLOCK_DATA **CurrentBlockArray,
+ OUT UINT8 **VarBuffer
+ )
+{
+ IFR_BLOCK_DATA *BlockData;
+ IFR_BLOCK_DATA *NewBlockData;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ UINT8 *TmpBuffer;
+ UINT16 Offset;
+ UINT16 Width;
+ LIST_ENTRY *Link;
+ UINTN MaxBufferSize;
+ EFI_STATUS Status;
+ IFR_BLOCK_DATA *BlockArray;
+ UINT8 *DataBuffer;
+
+ //
+ // Initialize the local variables.
+ //
+ Status = EFI_SUCCESS;
+ BlockData = NULL;
+ NewBlockData = NULL;
+ TmpBuffer = NULL;
+ BlockArray = NULL;
+ MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
+ DataBuffer = AllocateZeroPool (MaxBufferSize);
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init BlockArray
+ //
+ BlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (BlockArray == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ InitializeListHead (&BlockArray->Entry);
+
+ StringPtr = StrStr (ConfigElement, L"&OFFSET=");
+ ASSERT (StringPtr != NULL);
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
+ //
+ // Skip the &OFFSET= string
+ //
+ StringPtr += StrLen (L"&OFFSET=");
+
+ //
+ // Get Offset
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Check whether VarBuffer is enough
+ //
+ if ((UINT32)Offset + Width > MaxBufferSize) {
+ DataBuffer = ReallocatePool (
+ MaxBufferSize,
+ Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
+ DataBuffer
+ );
+ if (DataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
+ }
+
+ //
+ // Update the Block with configuration info
+ //
+ CopyMem (DataBuffer + Offset, TmpBuffer, Width);
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ //
+ // Set new Block Data
+ //
+ NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (NewBlockData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ NewBlockData->Offset = Offset;
+ NewBlockData->Width = Width;
+
+ //
+ // Insert the new block data into the block data array.
+ //
+ for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (NewBlockData->Offset == BlockData->Offset) {
+ if (NewBlockData->Width > BlockData->Width) {
+ BlockData->Width = NewBlockData->Width;
+ }
+ FreePool (NewBlockData);
+ break;
+ } else if (NewBlockData->Offset < BlockData->Offset) {
+ //
+ // Insert new block data as the previous one of this link.
+ //
+ InsertTailList (Link, &NewBlockData->Entry);
+ break;
+ }
+ }
+
+ //
+ // Insert new block data into the array tail.
+ //
+ if (Link == &BlockArray->Entry) {
+ InsertTailList (Link, &NewBlockData->Entry);
+ }
+
+ //
+ // If '\0', parsing is finished.
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ //
+ // Go to next ConfigBlock
+ //
+ }
+
+ //
+ // Merge the aligned block data into the single block data.
+ //
+ Link = BlockArray->Entry.ForwardLink;
+ while ((Link != &BlockArray->Entry) && (Link->ForwardLink != &BlockArray->Entry)) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
+ if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
+ if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
+ BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset);
+ }
+ RemoveEntryList (Link->ForwardLink);
+ FreePool (NewBlockData);
+ continue;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ *VarBuffer = DataBuffer;
+ *CurrentBlockArray = BlockArray;
+ return EFI_SUCCESS;
+
+Done:
+ if (DataBuffer != NULL) {
+ FreePool (DataBuffer);
+ }
+
+ if (BlockArray != NULL) {
+ //
+ // Free Link Array CurrentBlockArray
+ //
+ while (!IsListEmpty (&BlockArray->Entry)) {
+ BlockData = BASE_CR (BlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ FreePool (BlockData);
+ }
+ FreePool (BlockArray);
+ }
+
+ return Status;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ @param ConfigResp ConfigResp string contains the current setting.
+ @param HiiPackageList Point to Hii package list.
+ @param PackageListLength The length of the pacakge.
+ @param VarGuid Guid of the buffer storage.
+ @param VarName Name of the buffer storage.
+ @param HiiHandle The HiiHandle for this package.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiValidateCurrentSetting (
+ IN EFI_STRING ConfigResp,
+ IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
+ IN UINTN PackageListLength,
+ IN EFI_GUID *VarGuid,
+ IN CHAR16 *VarName,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ CHAR16 *StringPtr;
+ EFI_STATUS Status;
+ IFR_BLOCK_DATA *CurrentBlockArray;
+ IFR_BLOCK_DATA *BlockData;
+ UINT8 *VarBuffer;
+ BOOLEAN NameValueType;
+
+ CurrentBlockArray = NULL;
+ VarBuffer = NULL;
+ StringPtr = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // If StringPtr != NULL, get the request elements.
+ //
+ if (StrStr (ConfigResp, L"&OFFSET=") != NULL) {
+ Status = GetBlockDataInfo(ConfigResp, &CurrentBlockArray, &VarBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ NameValueType = FALSE;
+ } else {
+ //
+ // Skip header part.
+ //
+ StringPtr = StrStr (ConfigResp, L"PATH=");
+ ASSERT (StringPtr != NULL);
+
+ if (StrStr (StringPtr, L"&") != NULL) {
+ NameValueType = TRUE;
+ } else {
+ //
+ // Not found Request element, return success.
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = ValidateQuestionFromVfr(
+ HiiPackageList,
+ PackageListLength,
+ VarGuid,
+ VarName,
+ VarBuffer,
+ CurrentBlockArray,
+ ConfigResp,
+ HiiHandle,
+ NameValueType
+ );
+
+ if (VarBuffer != NULL) {
+ FreePool (VarBuffer);
+ }
+
+ if (CurrentBlockArray != NULL) {
+ //
+ // Free Link Array CurrentBlockArray
+ //
+ while (!IsListEmpty (&CurrentBlockArray->Entry)) {
+ BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ FreePool (BlockData);
+ }
+ FreePool (CurrentBlockArray);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the ConfigRequest string has the request elements.
+ For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
+ For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
+
+ @param ConfigRequest The input config request string.
+
+ @retval TRUE The input include config request elements.
+ @retval FALSE The input string not includes.
+
+**/
+BOOLEAN
+GetElementsFromRequest (
+ IN EFI_STRING ConfigRequest
+ )
+{
+ EFI_STRING TmpRequest;
+
+ TmpRequest = StrStr (ConfigRequest, L"PATH=");
+ ASSERT (TmpRequest != NULL);
+
+ if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function parses the input ConfigRequest string and its matched IFR code
+ string for setting default value and validating current setting.
+
+ 1. For setting default action, Reset the default value specified by DefaultId
+ to the driver configuration got by Request string.
+ 2. For validating current setting, Validate the current configuration
+ by parsing HII form IFR opcode.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all current configuration for the
+ entirety of the current HII database will be validated.
+ If it is NULL, all configuration for the
+ entirety of the current HII database will be reset.
+ @param DefaultId Specifies the type of defaults to retrieve only for setting default action.
+ @param ActionType Action supports setting defaults and validate current setting.
+
+ @retval TRUE Action runs successfully.
+ @retval FALSE Action is not valid or Action can't be executed successfully..
+**/
+BOOLEAN
+EFIAPI
+InternalHiiIfrValueAction (
+ IN CONST EFI_STRING Request, OPTIONAL
+ IN UINT16 DefaultId,
+ IN UINT8 ActionType
+ )
+{
+ EFI_STRING ConfigAltResp;
+ EFI_STRING ConfigAltHdr;
+ EFI_STRING ConfigResp;
+ EFI_STRING Progress;
+ EFI_STRING StringPtr;
+ EFI_STRING StringHdr;
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+ EFI_HANDLE TempDriverHandle;
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ EFI_HII_HANDLE HiiHandle;
+ UINT32 Index;
+ EFI_GUID *VarGuid;
+ EFI_STRING VarName;
+
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN PackageListLength;
+ UINTN MaxLen;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ ConfigAltResp = NULL;
+ ConfigResp = NULL;
+ VarGuid = NULL;
+ VarName = NULL;
+ DevicePath = NULL;
+ ConfigAltHdr = NULL;
+ HiiHandleBuffer = NULL;
+ Index = 0;
+ TempDriverHandle = NULL;
+ HiiHandle = NULL;
+ HiiPackageList = NULL;
+
+ //
+ // Only support set default and validate setting action.
+ //
+ if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
+ return FALSE;
+ }
+
+ //
+ // Get the full requested value and deault value string.
+ //
+ if (Request != NULL) {
+ Status = gHiiConfigRouting->ExtractConfig (
+ gHiiConfigRouting,
+ Request,
+ &Progress,
+ &ConfigAltResp
+ );
+ } else {
+ Status = gHiiConfigRouting->ExportConfig (
+ gHiiConfigRouting,
+ &ConfigAltResp
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ StringPtr = ConfigAltResp;
+ ASSERT (StringPtr != NULL);
+
+ while (*StringPtr != L'\0') {
+ //
+ // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
+ //
+ StringHdr = StringPtr;
+
+ //
+ // Get Guid value
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"GUID=");
+ Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get Name value VarName
+ //
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&NAME=");
+ Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get Path value DevicePath
+ //
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&PATH=");
+ Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get the Driver handle by the got device path.
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find the matched Hii Handle for the found Driver handle
+ //
+ HiiHandleBuffer = HiiGetHiiHandles (NULL);
+ if (HiiHandleBuffer == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
+ gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
+ if (TempDriverHandle == DriverHandle) {
+ break;
+ }
+ }
+
+ HiiHandle = HiiHandleBuffer[Index];
+ FreePool (HiiHandleBuffer);
+
+ if (HiiHandle == NULL) {
+ //
+ // This request string has no its Hii package.
+ // Its default value and validating can't execute by parsing IFR data.
+ // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
+ //
+ Status = EFI_SUCCESS;
+ goto NextConfigAltResp;
+ }
+
+ //
+ // 2. Get HiiPackage by HiiHandle
+ //
+ PackageListLength = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
+
+ //
+ // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ HiiPackageList = AllocatePool (PackageListLength);
+ if (HiiPackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Get PackageList on HiiHandle
+ //
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
+ // Get the default configuration string according to the default ID.
+ //
+ Status = gHiiConfigRouting->GetAltConfig (
+ gHiiConfigRouting,
+ ConfigAltResp,
+ VarGuid,
+ VarName,
+ DevicePath,
+ (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL, // it can be NULL to get the current setting.
+ &ConfigResp
+ );
+
+ //
+ // The required setting can't be found. So, it is not required to be validated and set.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = EFI_SUCCESS;
+ goto NextConfigAltResp;
+ }
+ //
+ // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
+ //
+ if (!GetElementsFromRequest (ConfigResp)) {
+ goto NextConfigAltResp;
+ }
+
+ //
+ // 4. Set the default configuration information or Validate current setting by parse IFR code.
+ // Current Setting is in ConfigResp, will be set into buffer, then check it again.
+ //
+ if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
+ //
+ // Set the default configuration information.
+ //
+ Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
+ } else {
+ //
+ // Current Setting is in ConfigResp, will be set into buffer, then check it again.
+ //
+ Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName, HiiHandle);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+NextConfigAltResp:
+ //
+ // Free the allocated pacakge buffer and the got ConfigResp string.
+ //
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ HiiPackageList = NULL;
+ }
+
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ ConfigResp = NULL;
+ }
+
+ //
+ // Free the allocated buffer.
+ //
+ FreePool (VarGuid);
+ VarGuid = NULL;
+
+ FreePool (VarName);
+ VarName = NULL;
+
+ FreePool (DevicePath);
+ DevicePath = NULL;
+
+ //
+ // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
+ //
+
+ //
+ // Get and Skip ConfigHdr
+ //
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ break;
+ }
+
+ //
+ // Construct ConfigAltHdr string "&<ConfigHdr>&ALTCFG=\0"
+ // | 1 | StrLen (ConfigHdr) | 8 | 1 |
+ //
+ MaxLen = 1 + StringPtr - StringHdr + 8 + 1;
+ ConfigAltHdr = AllocateZeroPool ( MaxLen * sizeof (CHAR16));
+ if (ConfigAltHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ StrCpyS (ConfigAltHdr, MaxLen, L"&");
+ StrnCatS (ConfigAltHdr, MaxLen, StringHdr, StringPtr - StringHdr);
+ StrCatS (ConfigAltHdr, MaxLen, L"&ALTCFG=");
+
+ //
+ // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
+ //
+ while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
+ StringPtr = StringHdr + StrLen (ConfigAltHdr);
+ if (*StringPtr == L'\0') {
+ break;
+ }
+ }
+
+ //
+ // Free the allocated ConfigAltHdr string
+ //
+ FreePool (ConfigAltHdr);
+ if (*StringPtr == L'\0') {
+ break;
+ }
+
+ //
+ // Find &GUID as the next ConfigHdr
+ //
+ StringPtr = StrStr (StringPtr, L"&GUID");
+ if (StringPtr == NULL) {
+ break;
+ }
+
+ //
+ // Skip char '&'
+ //
+ StringPtr ++;
+ }
+
+Done:
+ if (VarGuid != NULL) {
+ FreePool (VarGuid);
+ }
+
+ if (VarName != NULL) {
+ FreePool (VarName);
+ }
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ }
+
+ if (ConfigAltResp != NULL) {
+ FreePool (ConfigAltResp);
+ }
+
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Validate the current configuration by parsing HII form IFR opcode.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all current configuration for the
+ entirety of the current HII database will be validated.
+
+ @retval TRUE Current configuration is valid.
+ @retval FALSE Current configuration is invalid.
+**/
+BOOLEAN
+EFIAPI
+HiiValidateSettings (
+ IN CONST EFI_STRING Request OPTIONAL
+ )
+{
+ return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
+}
+
+/**
+ Reset the default value specified by DefaultId to the driver
+ configuration got by Request string.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all configuration for the
+ entirety of the current HII database will be reset.
+ @param DefaultId Specifies the type of defaults to retrieve.
+
+ @retval TRUE The default value is set successfully.
+ @retval FALSE The default value can't be found and set.
+**/
+BOOLEAN
+EFIAPI
+HiiSetToDefaults (
+ IN CONST EFI_STRING Request, OPTIONAL
+ IN UINT16 DefaultId
+ )
+{
+ return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
+}
+
+/**
+ Determines if two values in config strings match.
+
+ Compares the substring between StartSearchString and StopSearchString in
+ FirstString to the substring between StartSearchString and StopSearchString
+ in SecondString. If the two substrings match, then TRUE is returned. If the
+ two substrings do not match, then FALSE is returned.
+
+ If FirstString is NULL, then ASSERT().
+ If SecondString is NULL, then ASSERT().
+ If StartSearchString is NULL, then ASSERT().
+ If StopSearchString is NULL, then ASSERT().
+
+ @param FirstString Pointer to the first Null-terminated Unicode string.
+ @param SecondString Pointer to the second Null-terminated Unicode string.
+ @param StartSearchString Pointer to the Null-terminated Unicode string that
+ marks the start of the value string to compare.
+ @param StopSearchString Pointer to the Null-terminated Unicode string that
+ marks the end of the value string to compare.
+
+ @retval FALSE StartSearchString is not present in FirstString.
+ @retval FALSE StartSearchString is not present in SecondString.
+ @retval FALSE StopSearchString is not present in FirstString.
+ @retval FALSE StopSearchString is not present in SecondString.
+ @retval FALSE The length of the substring in FirstString is not the
+ same length as the substring in SecondString.
+ @retval FALSE The value string in FirstString does not matche the
+ value string in SecondString.
+ @retval TRUE The value string in FirstString matches the value
+ string in SecondString.
+
+**/
+BOOLEAN
+EFIAPI
+InternalHiiCompareSubString (
+ IN CHAR16 *FirstString,
+ IN CHAR16 *SecondString,
+ IN CHAR16 *StartSearchString,
+ IN CHAR16 *StopSearchString
+ )
+{
+ CHAR16 *EndFirstString;
+ CHAR16 *EndSecondString;
+
+ ASSERT (FirstString != NULL);
+ ASSERT (SecondString != NULL);
+ ASSERT (StartSearchString != NULL);
+ ASSERT (StopSearchString != NULL);
+
+ FirstString = StrStr (FirstString, StartSearchString);
+ if (FirstString == NULL) {
+ return FALSE;
+ }
+
+ SecondString = StrStr (SecondString, StartSearchString);
+ if (SecondString == NULL) {
+ return FALSE;
+ }
+
+ EndFirstString = StrStr (FirstString, StopSearchString);
+ if (EndFirstString == NULL) {
+ return FALSE;
+ }
+
+ EndSecondString = StrStr (SecondString, StopSearchString);
+ if (EndSecondString == NULL) {
+ return FALSE;
+ }
+
+ if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
+ return FALSE;
+ }
+
+ return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
+}
+
+/**
+ Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
+
+ If ConfigHdr is NULL, then ASSERT().
+
+ @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
+ @param[in] Guid GUID of the storage.
+ @param[in] Name NAME of the storage.
+
+ @retval TRUE Routing information matches <ConfigHdr>.
+ @retval FALSE Routing information does not match <ConfigHdr>.
+
+**/
+BOOLEAN
+EFIAPI
+HiiIsConfigHdrMatch (
+ IN CONST EFI_STRING ConfigHdr,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name OPTIONAL
+ )
+{
+ EFI_STRING CompareConfigHdr;
+ BOOLEAN Result;
+
+ ASSERT (ConfigHdr != NULL);
+
+ //
+ // Use Guid and Name to generate a <ConfigHdr> string
+ //
+ CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
+ if (CompareConfigHdr == NULL) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ if (Guid != NULL) {
+ //
+ // Compare GUID value strings
+ //
+ Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
+ }
+
+ if (Result && Name != NULL) {
+ //
+ // Compare NAME value strings
+ //
+ Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
+ }
+
+ //
+ // Free the <ConfigHdr> string
+ //
+ FreePool (CompareConfigHdr);
+
+ return Result;
+}
+
+/**
+ Retrieves uncommitted data from the Form Browser and converts it to a binary
+ buffer.
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize Length in bytes of buffer to hold retrieved data.
+ @param[out] Buffer Buffer of data to be updated.
+
+ @retval FALSE The uncommitted data could not be retrieved.
+ @retval TRUE The uncommitted data was retrieved.
+
+**/
+BOOLEAN
+EFIAPI
+HiiGetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STRING ResultsData;
+ UINTN Size;
+ EFI_STRING ConfigResp;
+ EFI_STATUS Status;
+ CHAR16 *Progress;
+
+ //
+ // Retrieve the results data from the Browser Callback
+ //
+ ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
+ if (ResultsData == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
+ //
+ Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
+ Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
+ ConfigResp = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
+
+ //
+ // Free the allocated buffer
+ //
+ FreePool (ResultsData);
+ if (ConfigResp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Convert <ConfigResp> to a buffer
+ //
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ ConfigResp,
+ Buffer,
+ &BufferSize,
+ &Progress
+ );
+ //
+ // Free the allocated buffer
+ //
+ FreePool (ConfigResp);
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Updates uncommitted data in the Form Browser.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize Length, in bytes, of Buffer.
+ @param[in] Buffer Buffer of data to commit.
+ @param[in] RequestElement An optional field to specify which part of the
+ buffer data will be send back to Browser. If NULL,
+ the whole buffer of data will be committed to
+ Browser.
+ <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
+
+ @retval FALSE The uncommitted data could not be updated.
+ @retval TRUE The uncommitted data was updated.
+
+**/
+BOOLEAN
+EFIAPI
+HiiSetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ IN CONST UINT8 *Buffer,
+ IN CONST CHAR16 *RequestElement OPTIONAL
+ )
+{
+ UINTN Size;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigResp;
+ EFI_STRING ResultsData;
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Construct <ConfigRequest>
+ //
+ if (RequestElement == NULL) {
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
+ } else {
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by <RequestElement> followed by a Null-terminator
+ //
+ Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
+ Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
+ }
+ if (ConfigRequest == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Convert <ConfigRequest> to <ConfigResp>
+ //
+ ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
+ FreePool (ConfigRequest);
+ if (ConfigResp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Set data in the uncommitted browser state information
+ //
+ ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
+ FreePool (ConfigResp);
+
+ return (BOOLEAN)(ResultsData != NULL);
+}
+
+/////////////////////////////////////////
+/////////////////////////////////////////
+/// IFR Functions
+/////////////////////////////////////////
+/////////////////////////////////////////
+
+#define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200
+
+typedef struct {
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ UINTN Position;
+} HII_LIB_OPCODE_BUFFER;
+
+///
+/// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
+ 1, // EFI_IFR_TYPE_NUM_SIZE_8
+ 2, // EFI_IFR_TYPE_NUM_SIZE_16
+ 4, // EFI_IFR_TYPE_NUM_SIZE_32
+ 8, // EFI_IFR_TYPE_NUM_SIZE_64
+ 1, // EFI_IFR_TYPE_BOOLEAN
+ 3, // EFI_IFR_TYPE_TIME
+ 4, // EFI_IFR_TYPE_DATE
+ 2 // EFI_IFR_TYPE_STRING
+};
+
+/**
+ Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
+ HiiFreeOpCodeHandle().
+
+ @retval NULL There are not enough resources to allocate a new OpCode Handle.
+ @retval Other A new OpCode handle.
+
+**/
+VOID *
+EFIAPI
+HiiAllocateOpCodeHandle (
+ VOID
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
+ if (OpCodeBuffer == NULL) {
+ return NULL;
+ }
+ OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
+ if (OpCodeBuffer->Buffer == NULL) {
+ FreePool (OpCodeBuffer);
+ return NULL;
+ }
+ OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
+ OpCodeBuffer->Position = 0;
+ return (VOID *)OpCodeBuffer;
+}
+
+/**
+ Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
+ When an OpCode Handle is freed, all of the opcodes associated with the OpCode
+ Handle are also freed.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+**/
+VOID
+EFIAPI
+HiiFreeOpCodeHandle (
+ VOID *OpCodeHandle
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+
+ ASSERT (OpCodeHandle != NULL);
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
+ if (OpCodeBuffer->Buffer != NULL) {
+ FreePool (OpCodeBuffer->Buffer);
+ }
+ FreePool (OpCodeBuffer);
+}
+
+/**
+ Internal function gets the current position of opcode buffer.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @return Current position of opcode buffer.
+**/
+UINTN
+EFIAPI
+InternalHiiOpCodeHandlePosition (
+ IN VOID *OpCodeHandle
+ )
+{
+ return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position;
+}
+
+/**
+ Internal function gets the start pointer of opcode buffer.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @return Pointer to the opcode buffer base.
+**/
+UINT8 *
+EFIAPI
+InternalHiiOpCodeHandleBuffer (
+ IN VOID *OpCodeHandle
+ )
+{
+ return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer;
+}
+
+/**
+ Internal function reserves the enough buffer for current opcode.
+ When the buffer is not enough, Opcode buffer will be extended.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Size Size of current opcode.
+
+ @return Pointer to the current opcode.
+**/
+UINT8 *
+EFIAPI
+InternalHiiGrowOpCodeHandle (
+ IN VOID *OpCodeHandle,
+ IN UINTN Size
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+ UINT8 *Buffer;
+
+ ASSERT (OpCodeHandle != NULL);
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
+ if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
+ Buffer = ReallocatePool (
+ OpCodeBuffer->BufferSize,
+ OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
+ OpCodeBuffer->Buffer
+ );
+ ASSERT (Buffer != NULL);
+ OpCodeBuffer->Buffer = Buffer;
+ OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
+ }
+ Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
+ OpCodeBuffer->Position += Size;
+ return Buffer;
+}
+
+/**
+ Internal function creates opcode based on the template opcode.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
+ @param[in] OpCode OpCode IFR value.
+ @param[in] OpCodeSize Size of opcode.
+ @param[in] ExtensionSize Size of extended opcode.
+ @param[in] Scope Scope bit of opcode.
+
+ @return Pointer to the current opcode with opcode data.
+**/
+UINT8 *
+EFIAPI
+InternalHiiCreateOpCodeExtended (
+ IN VOID *OpCodeHandle,
+ IN VOID *OpCodeTemplate,
+ IN UINT8 OpCode,
+ IN UINTN OpCodeSize,
+ IN UINTN ExtensionSize,
+ IN UINT8 Scope
+ )
+{
+ EFI_IFR_OP_HEADER *Header;
+ UINT8 *Buffer;
+
+ ASSERT (OpCodeTemplate != NULL);
+ ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
+
+ Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
+ Header->OpCode = OpCode;
+ Header->Scope = Scope;
+ Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
+ Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
+ return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
+}
+
+/**
+ Internal function creates opcode based on the template opcode for the normal opcode.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
+ @param[in] OpCode OpCode IFR value.
+ @param[in] OpCodeSize Size of opcode.
+
+ @return Pointer to the current opcode with opcode data.
+**/
+UINT8 *
+EFIAPI
+InternalHiiCreateOpCode (
+ IN VOID *OpCodeHandle,
+ IN VOID *OpCodeTemplate,
+ IN UINT8 OpCode,
+ IN UINTN OpCodeSize
+ )
+{
+ return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
+}
+
+/**
+ Append raw opcodes to an OpCodeHandle.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If RawBuffer is NULL, then ASSERT();
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] RawBuffer Buffer of opcodes to append.
+ @param[in] RawBufferSize The size, in bytes, of Buffer.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the appended opcodes.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateRawOpCodes (
+ IN VOID *OpCodeHandle,
+ IN UINT8 *RawBuffer,
+ IN UINTN RawBufferSize
+ )
+{
+ UINT8 *Buffer;
+
+ ASSERT (RawBuffer != NULL);
+
+ Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
+ return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
+}
+
+/**
+ Append opcodes from one OpCode Handle to another OpCode handle.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If RawOpCodeHandle is NULL, then ASSERT();
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] RawOpCodeHandle Handle to the buffer of opcodes.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the appended opcodes.
+
+**/
+UINT8 *
+EFIAPI
+InternalHiiAppendOpCodes (
+ IN VOID *OpCodeHandle,
+ IN VOID *RawOpCodeHandle
+ )
+{
+ HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer;
+
+ ASSERT (RawOpCodeHandle != NULL);
+
+ RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
+ return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
+}
+
+/**
+ Create EFI_IFR_END_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateEndOpCode (
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_IFR_END OpCode;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_ONE_OF_OPTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+ If Flags is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] StringId StringId for the option
+ @param[in] Flags Flags for the option
+ @param[in] Type Type for the option
+ @param[in] Value Value for the option
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOptionOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 StringId,
+ IN UINT8 Flags,
+ IN UINT8 Type,
+ IN UINT64 Value
+ )
+{
+ EFI_IFR_ONE_OF_OPTION OpCode;
+
+ ASSERT (Type < EFI_IFR_TYPE_OTHER);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Option = StringId;
+ OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
+ OpCode.Type = Type;
+ CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
+}
+
+/**
+ Create EFI_IFR_DEFAULT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] DefaultId DefaultId for the default
+ @param[in] Type Type for the default
+ @param[in] Value Value for the default
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDefaultOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 DefaultId,
+ IN UINT8 Type,
+ IN UINT64 Value
+ )
+{
+ EFI_IFR_DEFAULT OpCode;
+
+ ASSERT (Type < EFI_IFR_TYPE_OTHER);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Type = Type;
+ OpCode.DefaultId = DefaultId;
+ CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
+}
+
+/**
+ Create EFI_IFR_GUID opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+ If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Guid Pointer to EFI_GUID of this guided opcode.
+ @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an
+ optional parameter that may be NULL. If this
+ parameter is NULL, then the GUID extension
+ region of the created opcode is filled with zeros.
+ If this parameter is not NULL, then the GUID
+ extension region of GuidData will be copied to
+ the GUID extension region of the created opcode.
+ @param[in] OpCodeSize The size, in bytes, of created opcode. This value
+ must be >= sizeof(EFI_IFR_GUID).
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGuidOpCode (
+ IN VOID *OpCodeHandle,
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *GuidOpCode, OPTIONAL
+ IN UINTN OpCodeSize
+ )
+{
+ EFI_IFR_GUID OpCode;
+ EFI_IFR_GUID *OpCodePointer;
+
+ ASSERT (Guid != NULL);
+ ASSERT (OpCodeSize >= sizeof (OpCode));
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
+
+ OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
+ OpCodeHandle,
+ &OpCode,
+ EFI_IFR_GUID_OP,
+ sizeof (OpCode),
+ OpCodeSize - sizeof (OpCode),
+ 0
+ );
+ if (OpCodePointer != NULL && GuidOpCode != NULL) {
+ CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
+ }
+ return (UINT8 *)OpCodePointer;
+}
+
+/**
+ Create EFI_IFR_ACTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] QuestionConfig String ID for configuration
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateActionOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_STRING_ID QuestionConfig
+ )
+{
+ EFI_IFR_ACTION OpCode;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.QuestionConfig = QuestionConfig;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_SUBTITLE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in Flags, then ASSERT().
+ If Scope > 1, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] Flags Subtitle opcode flags
+ @param[in] Scope 1 if this opcpde is the beginning of a new scope.
+ 0 if this opcode is within the current scope.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateSubTitleOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 Flags,
+ IN UINT8 Scope
+ )
+{
+ EFI_IFR_SUBTITLE OpCode;
+
+ ASSERT (Scope <= 1);
+ ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Statement.Prompt = Prompt;
+ OpCode.Statement.Help = Help;
+ OpCode.Flags = Flags;
+
+ return InternalHiiCreateOpCodeExtended (
+ OpCodeHandle,
+ &OpCode,
+ EFI_IFR_SUBTITLE_OP,
+ sizeof (OpCode),
+ 0,
+ Scope
+ );
+}
+
+/**
+ Create EFI_IFR_REF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] FormId Destination Form ID
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] QuestionId Question ID
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID FormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId
+ )
+{
+ EFI_IFR_REF OpCode;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.FormId = FormId;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
+
+ When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
+ When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] RefFormId The Destination Form ID.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header
+ @param[in] QuestionId Question ID.
+ @param[in] RefQuestionId The question on the form to which this link is referring.
+ If its value is zero, then the link refers to the top of the form.
+ @param[in] RefFormSetId The form set to which this link is referring. If its value is NULL, and RefDevicePath is
+ zero, then the link is to the current form set.
+ @param[in] RefDevicePath The string identifier that specifies the string containing the text representation of
+ the device path to which the form set containing the form specified by FormId.
+ If its value is zero, then the link refers to the current page.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoExOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID RefFormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_QUESTION_ID RefQuestionId,
+ IN EFI_GUID *RefFormSetId, OPTIONAL
+ IN EFI_STRING_ID RefDevicePath
+ )
+{
+ EFI_IFR_REF4 OpCode;
+ UINTN OpCodeSize;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.FormId = RefFormId;
+ OpCode.QuestionId = RefQuestionId;
+ OpCode.DevicePath = RefDevicePath;
+ if (RefFormSetId != NULL) {
+ CopyMem (&OpCode.FormSetId, RefFormSetId, sizeof (OpCode.FormSetId));
+ }
+
+ //
+ // Cacluate OpCodeSize based on the input Ref value.
+ // Try to use the small OpCode to save size.
+ //
+ OpCodeSize = sizeof (EFI_IFR_REF);
+ if (RefDevicePath != 0) {
+ OpCodeSize = sizeof (EFI_IFR_REF4);
+ } else if (RefFormSetId != NULL) {
+ OpCodeSize = sizeof (EFI_IFR_REF3);
+ } else if (RefQuestionId != 0) {
+ OpCodeSize = sizeof (EFI_IFR_REF2);
+ }
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, OpCodeSize);
+}
+
+/**
+ Create EFI_IFR_CHECKBOX_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in CheckBoxFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] CheckBoxFlags Flags for checkbox opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateCheckBoxOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 CheckBoxFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_CHECKBOX OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = CheckBoxFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_NUMERIC_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in NumericFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] NumericFlags Flags for numeric opcode
+ @param[in] Minimum Numeric minimum value
+ @param[in] Maximum Numeric maximum value
+ @param[in] Step Numeric step for edit
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateNumericOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 NumericFlags,
+ IN UINT64 Minimum,
+ IN UINT64 Maximum,
+ IN UINT64 Step,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_NUMERIC OpCode;
+ UINTN Position;
+ UINTN Length;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ Length = 0;
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = NumericFlags;
+
+ switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ OpCode.data.u8.MinValue = (UINT8)Minimum;
+ OpCode.data.u8.MaxValue = (UINT8)Maximum;
+ OpCode.data.u8.Step = (UINT8)Step;
+ Length = 3;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ OpCode.data.u16.MinValue = (UINT16)Minimum;
+ OpCode.data.u16.MaxValue = (UINT16)Maximum;
+ OpCode.data.u16.Step = (UINT16)Step;
+ Length = 6;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ OpCode.data.u32.MinValue = (UINT32)Minimum;
+ OpCode.data.u32.MaxValue = (UINT32)Maximum;
+ OpCode.data.u32.Step = (UINT32)Step;
+ Length = 12;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ OpCode.data.u64.MinValue = Minimum;
+ OpCode.data.u64.MaxValue = Maximum;
+ OpCode.data.u64.Step = Step;
+ Length = 24;
+ break;
+ }
+
+ Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_STRING_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in StringFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] StringFlags Flags for string opcode
+ @param[in] MinSize String minimum length
+ @param[in] MaxSize String maximum length
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateStringOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 StringFlags,
+ IN UINT8 MinSize,
+ IN UINT8 MaxSize,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_STRING OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.MinSize = MinSize;
+ OpCode.MaxSize = MaxSize;
+ OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_ONE_OF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OneOfFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] OneOfFlags Flags for oneof opcode
+ @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OneOfFlags,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_ONE_OF OpCode;
+ UINTN Position;
+ UINTN Length;
+
+ ASSERT (OptionsOpCodeHandle != NULL);
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = OneOfFlags;
+
+ Length = OFFSET_OF (EFI_IFR_ONE_OF, data);
+ Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
+ if (DefaultsOpCodeHandle != NULL) {
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ }
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_ORDERED_LIST_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OrderedListFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] OrderedListFlags Flags for ordered list opcode
+ @param[in] DataType Type for option value
+ @param[in] MaxContainers Maximum count for options in this ordered list
+ @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOrderedListOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OrderedListFlags,
+ IN UINT8 DataType,
+ IN UINT8 MaxContainers,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_ORDERED_LIST OpCode;
+ UINTN Position;
+
+ ASSERT (OptionsOpCodeHandle != NULL);
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.MaxContainers = MaxContainers;
+ OpCode.Flags = OrderedListFlags;
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
+ if (DefaultsOpCodeHandle != NULL) {
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ }
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_TEXT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Prompt String ID for Prompt.
+ @param[in] Help String ID for Help.
+ @param[in] TextTwo String ID for TextTwo.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTextOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN EFI_STRING_ID TextTwo
+ )
+{
+ EFI_IFR_TEXT OpCode;
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Statement.Prompt = Prompt;
+ OpCode.Statement.Help = Help;
+ OpCode.TextTwo = TextTwo;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_DATE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in DateFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] DateFlags Flags for date opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDateOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 DateFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_DATE OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+ ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = DateFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_TIME_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in TimeFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] TimeFlags Flags for time opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTimeOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 TimeFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_TIME OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+ ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = TimeFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ This is the internal worker function to update the data in
+ a form specified by FormSetGuid, FormId and Label.
+
+ @param[in] FormSetGuid The optional Formset GUID.
+ @param[in] FormId The Form ID.
+ @param[in] Package The package header.
+ @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
+ opcodes to be inserted or replaced in the form.
+ @param[in] OpCodeBufferEnd An OpCcode buffer that contains the IFR opcode
+ that marks the end of a replace operation in the form.
+ @param[out] TempPackage The resultant package.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND The updated opcode or endopcode is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiUpdateFormPackageData (
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN EFI_FORM_ID FormId,
+ IN EFI_HII_PACKAGE_HEADER *Package,
+ IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart,
+ IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL
+ OUT EFI_HII_PACKAGE_HEADER *TempPackage
+ )
+{
+ UINTN AddSize;
+ UINT8 *BufferPos;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINTN Offset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_OP_HEADER *UpdateIfrOpHdr;
+ BOOLEAN GetFormSet;
+ BOOLEAN GetForm;
+ BOOLEAN Updated;
+ UINTN UpdatePackageLength;
+
+ CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
+ BufferPos = (UINT8 *) (TempPackage + 1);
+
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset = sizeof (EFI_HII_PACKAGE_HEADER);
+ GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
+ GetForm = FALSE;
+ Updated = FALSE;
+
+ while (Offset < PackageHeader.Length) {
+ CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
+ BufferPos += IfrOpHdr->Length;
+ UpdatePackageLength += IfrOpHdr->Length;
+
+ //
+ // Find the matched FormSet and Form
+ //
+ if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
+ if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
+ GetFormSet = TRUE;
+ } else {
+ GetFormSet = FALSE;
+ }
+ } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
+ if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
+ GetForm = TRUE;
+ } else {
+ GetForm = FALSE;
+ }
+ }
+
+ //
+ // The matched Form is found, and Update data in this form
+ //
+ if (GetFormSet && GetForm) {
+ UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
+ if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
+ (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
+ //
+ // Remove the original data when End OpCode buffer exist.
+ //
+ if (OpCodeBufferEnd != NULL) {
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
+ while (Offset < PackageHeader.Length) {
+ //
+ // Search the matched end opcode
+ //
+ if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
+ (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
+ break;
+ }
+ //
+ // Go to the next Op-Code
+ //
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ }
+
+ if (Offset >= PackageHeader.Length) {
+ //
+ // The end opcode is not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Insert the updated data
+ //
+ AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
+ CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
+ BufferPos += OpCodeBufferStart->Position - AddSize;
+ UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
+
+ if (OpCodeBufferEnd != NULL) {
+ //
+ // Add the end opcode
+ //
+ CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
+ BufferPos += IfrOpHdr->Length;
+ UpdatePackageLength += IfrOpHdr->Length;
+ }
+
+ //
+ // Copy the left package data.
+ //
+ Offset += IfrOpHdr->Length;
+ CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
+ UpdatePackageLength += PackageHeader.Length - Offset;
+
+ //
+ // Set update flag
+ //
+ Updated = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Go to the next Op-Code
+ //
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ }
+
+ if (!Updated) {
+ //
+ // The updated opcode buffer is not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Update the package length.
+ //
+ PackageHeader.Length = (UINT32) UpdatePackageLength;
+ CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function updates a form that has previously been registered with the HII
+ Database. This function will perform at most one update operation.
+
+ The form to update is specified by Handle, FormSetGuid, and FormId. Binary
+ comparisons of IFR opcodes are performed from the beginning of the form being
+ updated until an IFR opcode is found that exactly matches the first IFR opcode
+ specified by StartOpCodeHandle. The following rules are used to determine if
+ an insert, replace, or delete operation is performed.
+
+ 1) If no matches are found, then NULL is returned.
+ 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching IFR opcode in the form to be updated.
+ 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
+ from the matching IFR opcode until an IFR opcode exactly matches the first
+ IFR opcode specified by EndOpCodeHandle. If no match is found for the first
+ IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
+ is found, then all of the IFR opcodes between the start match and the end
+ match are deleted from the form being updated and all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching start IFR opcode. If StartOpCcodeHandle only contains one
+ IFR instruction, then the result of this operation will delete all of the IFR
+ opcodes between the start end matches.
+
+ If HiiHandle is NULL, then ASSERT().
+ If StartOpCodeHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] FormSetGuid The Formset GUID of the form to update. This
+ is an optional parameter that may be NULL.
+ If it is NULL, all FormSet will be updated.
+ @param[in] FormId The ID of the form to update.
+ @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
+ opcodes to be inserted or replaced in the form.
+ The first IFR instruction in StartOpCodeHandle
+ is used to find matching IFR opcode in the
+ form.
+ @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
+ that marks the end of a replace operation in
+ the form. This is an optional parameter that
+ may be NULL. If it is NULL, then an the IFR
+ opcodes specified by StartOpCodeHandle are
+ inserted into the form.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
+ @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND.
+ 1) The form specified by HiiHandle, FormSetGuid,
+ and FormId could not be found in the HII Database.
+ 2) No IFR opcodes in the target form match the first
+ IFR opcode in StartOpCodeHandle.
+ 3) EndOpCOde is not NULL, and no IFR opcodes in the
+ target form following a matching start opcode match
+ the first IFR opcode in EndOpCodeHandle.
+ @retval EFI_SUCCESS The matched form is updated by StartOpcode.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdateForm (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN EFI_FORM_ID FormId,
+ IN VOID *StartOpCodeHandle,
+ IN VOID *EndOpCodeHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINT32 PackageListLength;
+ UINT32 Offset;
+ EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList;
+ UINTN BufferSize;
+ UINT8 *UpdateBufferPos;
+ EFI_HII_PACKAGE_HEADER *Package;
+ EFI_HII_PACKAGE_HEADER *TempPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ BOOLEAN Updated;
+ HII_LIB_OPCODE_BUFFER *OpCodeBufferStart;
+ HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd;
+
+ //
+ // Input update data can't be NULL.
+ //
+ ASSERT (HiiHandle != NULL);
+ ASSERT (StartOpCodeHandle != NULL);
+ UpdatePackageList = NULL;
+ TempPackage = NULL;
+ HiiPackageList = NULL;
+
+ //
+ // Retrieve buffer data from Opcode Handle
+ //
+ OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
+ OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
+
+ //
+ // Get the original package list
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ //
+ // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ HiiPackageList = AllocatePool (BufferSize);
+ if (HiiPackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Calculate and allocate space for retrieval of IFR data
+ //
+ BufferSize += OpCodeBufferStart->Position;
+ UpdatePackageList = AllocateZeroPool (BufferSize);
+ if (UpdatePackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ //
+ // Allocate temp buffer to store the temp updated package buffer
+ //
+ TempPackage = AllocateZeroPool (BufferSize);
+ if (TempPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ UpdateBufferPos = (UINT8 *) UpdatePackageList;
+
+ //
+ // Copy the package list header
+ //
+ CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+ UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+
+ //
+ // Go through each package to find the matched package and update one by one
+ //
+ Updated = FALSE;
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
+ while (Offset < PackageListLength) {
+ Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset += Package->Length;
+
+ if (Package->Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Check this package is the matched package.
+ //
+ Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPackage);
+ //
+ // The matched package is found. Its package buffer will be updated by the input new data.
+ //
+ if (!EFI_ERROR(Status)) {
+ //
+ // Set Update Flag
+ //
+ Updated = TRUE;
+ //
+ // Add updated package buffer
+ //
+ Package = TempPackage;
+ }
+ }
+
+ //
+ // Add pacakge buffer
+ //
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
+ UpdateBufferPos += PackageHeader.Length;
+ }
+
+ if (Updated) {
+ //
+ // Update package list length
+ //
+ BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
+ WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
+
+ //
+ // Update Package to show form
+ //
+ Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
+ } else {
+ //
+ // Not matched form is found and updated.
+ //
+ Status = EFI_NOT_FOUND;
+ }
+
+Finish:
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ }
+
+ if (UpdatePackageList != NULL) {
+ FreePool (UpdatePackageList);
+ }
+
+ if (TempPackage != NULL) {
+ FreePool (TempPackage);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiString.c b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiString.c
new file mode 100644
index 000000000..95229f8a8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/HiiString.c
@@ -0,0 +1,349 @@
+/** @file
+ HII Library implementation that uses DXE protocols and services.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "InternalHiiLib.h"
+
+/**
+ This function create a new string in String Package or updates an existing
+ string in a String Package. If StringId is 0, then a new string is added to
+ a String Package. If StringId is not zero, then a string in String Package is
+ updated. If SupportedLanguages is NULL, then the string is added or updated
+ for all the languages that the String Package supports. If SupportedLanguages
+ is not NULL, then the string is added or updated for the set of languages
+ specified by SupportedLanguages.
+
+ If HiiHandle is NULL, then ASSERT().
+ If String is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the
+ HII Database.
+ @param[in] StringId If zero, then a new string is created in the
+ String Package associated with HiiHandle. If
+ non-zero, then the string specified by StringId
+ is updated in the String Package associated
+ with HiiHandle.
+ @param[in] String A pointer to the Null-terminated Unicode string
+ to add or update in the String Package associated
+ with HiiHandle.
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string of
+ language codes. If this parameter is NULL, then
+ String is added or updated in the String Package
+ associated with HiiHandle for all the languages
+ that the String Package supports. If this
+ parameter is not NULL, then then String is added
+ or updated in the String Package associated with
+ HiiHandle for the set oflanguages specified by
+ SupportedLanguages. The format of
+ SupportedLanguages must follow the language
+ format assumed the HII Database.
+
+ @retval 0 The string could not be added or updated in the String Package.
+ @retval Other The EFI_STRING_ID of the newly added or updated string.
+
+**/
+EFI_STRING_ID
+EFIAPI
+HiiSetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST CHAR8 *SupportedLanguages OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *AllocatedLanguages;
+ CHAR8 *Supported;
+ CHAR8 *Language;
+
+ ASSERT (HiiHandle != NULL);
+ ASSERT (String != NULL);
+
+ if (SupportedLanguages == NULL) {
+ //
+ // Retrieve the languages that the package specified by HiiHandle supports
+ //
+ AllocatedLanguages = HiiGetSupportedLanguages (HiiHandle);
+ } else {
+ //
+ // Allocate a copy of the SupportLanguages string that passed in
+ //
+ AllocatedLanguages = AllocateCopyPool (AsciiStrSize (SupportedLanguages), SupportedLanguages);
+ }
+
+ //
+ // If there are not enough resources for the supported languages string, then return a StringId of 0
+ //
+ if (AllocatedLanguages == NULL) {
+ return (EFI_STRING_ID)(0);
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ //
+ // Loop through each language that the string supports
+ //
+ for (Supported = AllocatedLanguages; *Supported != '\0'; ) {
+ //
+ // Cache a pointer to the beginning of the current language in the list of languages
+ //
+ Language = Supported;
+
+ //
+ // Search for the next language separator and replace it with a Null-terminator
+ //
+ for (; *Supported != 0 && *Supported != ';'; Supported++);
+ if (*Supported != 0) {
+ *(Supported++) = '\0';
+ }
+
+ if ((SupportedLanguages == NULL) && AsciiStrnCmp (Language, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) == 0) {
+ //
+ // Skip string package used for keyword protocol.
+ //
+ continue;
+ }
+
+ //
+ // If StringId is 0, then call NewString(). Otherwise, call SetString()
+ //
+ if (StringId == (EFI_STRING_ID)(0)) {
+ Status = gHiiString->NewString (gHiiString, HiiHandle, &StringId, Language, NULL, String, NULL);
+ } else {
+ Status = gHiiString->SetString (gHiiString, HiiHandle, StringId, Language, String, NULL);
+ }
+
+ //
+ // If there was an error, then break out of the loop and return a StringId of 0
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Free the buffer of supported languages
+ //
+ FreePool (AllocatedLanguages);
+
+ if (EFI_ERROR (Status)) {
+ return (EFI_STRING_ID)(0);
+ } else {
+ return StringId;
+ }
+}
+
+
+/**
+ Retrieves a string from a string package names by GUID in a specific language.
+ If the language is not specified, then a string from a string package in the
+ current platform language is retrieved. If the string can not be retrieved
+ using the specified language or the current platform language, then the string
+ is retrieved from the string package in the first language the string package
+ supports. The returned string is allocated using AllocatePool(). The caller
+ is responsible for freeing the allocated buffer using FreePool().
+
+ If PackageListGuid is NULL, then ASSERT().
+ If StringId is 0, then ASSERT.
+
+ @param[in] PackageListGuid The GUID of a package list that was previously
+ registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the
+ string package associated with PackageListGuid.
+ @param[in] Language The language of the string to retrieve. If this
+ parameter is NULL, then the current platform
+ language is used. The format of Language must
+ follow the language format assumed the HII Database.
+
+ @retval NULL The package list specified by PackageListGuid is not present in the
+ HII Database.
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetPackageString (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+{
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ EFI_HII_HANDLE HiiHandle;
+
+ ASSERT (PackageListGuid != NULL);
+
+ HiiHandleBuffer = HiiGetHiiHandles (PackageListGuid);
+ if (HiiHandleBuffer == NULL) {
+ return NULL;
+ }
+
+ HiiHandle = HiiHandleBuffer[0];
+ FreePool (HiiHandleBuffer);
+
+ return HiiGetString (HiiHandle, StringId, Language);
+}
+
+/**
+ Retrieves a string from a string package in a specific language. If the language
+ is not specified, then a string from a string package in the current platform
+ language is retrieved. If the string can not be retrieved using the specified
+ language or the current platform language, then the string is retrieved from
+ the string package in the first language the string package supports. The
+ returned string is allocated using AllocatePool(). The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSET.
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+ @param[in] Language The language of the string to retrieve. If this parameter
+ is NULL, then the current platform language is used. The
+ format of Language must follow the language format assumed
+ the HII Database.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN StringSize;
+ CHAR16 TempString;
+ EFI_STRING String;
+ CHAR8 *SupportedLanguages;
+ CHAR8 *PlatformLanguage;
+ CHAR8 *BestLanguage;
+
+ ASSERT (HiiHandle != NULL);
+ ASSERT (StringId != 0);
+
+ //
+ // Initialize all allocated buffers to NULL
+ //
+ SupportedLanguages = NULL;
+ PlatformLanguage = NULL;
+ BestLanguage = NULL;
+ String = NULL;
+
+ //
+ // Get the languages that the package specified by HiiHandle supports
+ //
+ SupportedLanguages = HiiGetSupportedLanguages (HiiHandle);
+ if (SupportedLanguages == NULL) {
+ goto Error;
+ }
+
+ //
+ // Get the current platform language setting
+ //
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
+
+ //
+ // If Languag is NULL, then set it to an empty string, so it will be
+ // skipped by GetBestLanguage()
+ //
+ if (Language == NULL) {
+ Language = "";
+ }
+
+ //
+ // Get the best matching language from SupportedLanguages
+ //
+ BestLanguage = GetBestLanguage (
+ SupportedLanguages,
+ FALSE, // RFC 4646 mode
+ Language, // Highest priority
+ PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority
+ SupportedLanguages, // Lowest priority
+ NULL
+ );
+ if (BestLanguage == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the size of the string in the string package for the BestLanguage
+ //
+ StringSize = 0;
+ Status = gHiiString->GetString (
+ gHiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ &TempString,
+ &StringSize,
+ NULL
+ );
+ //
+ // If GetString() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetString()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Error;
+ }
+
+ //
+ // Allocate a buffer for the return string
+ //
+ String = AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the string from the string package
+ //
+ Status = gHiiString->GetString (
+ gHiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (String);
+ String = NULL;
+ }
+
+Error:
+ //
+ // Free allocated buffers
+ //
+ if (SupportedLanguages != NULL) {
+ FreePool (SupportedLanguages);
+ }
+ if (PlatformLanguage != NULL) {
+ FreePool (PlatformLanguage);
+ }
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ }
+
+ //
+ // Return the Null-terminated Unicode string
+ //
+ return String;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h
new file mode 100644
index 000000000..9378f9d6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h
@@ -0,0 +1,30 @@
+/** @file
+ Internal include file for the HII Library instance.
+
+ Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTERNAL_HII_LIB_H__
+#define __INTERNAL_HII_LIB_H__
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/FormBrowser2.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
new file mode 100644
index 000000000..d432b439b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
@@ -0,0 +1,50 @@
+## @file
+# HII Library implementation using UEFI HII protocols and services.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiHiiLib
+ MODULE_UNI_FILE = UefiHiiLib.uni
+ FILE_GUID = 3143687A-7C80-404e-B5FE-2D88980E1B1C
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HiiLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ HiiLib.c
+ HiiString.c
+ HiiLanguage.c
+ InternalHiiLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ UefiLib
+ UefiHiiServicesLib
+ PrintLib
+
+[Protocols]
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni
new file mode 100644
index 000000000..76ee89232
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// HII Library implementation using UEFI HII protocols and services.
+//
+// HII Library implementation using UEFI HII protocols and services.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "HII Library implementation using UEFI HII protocols and services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "HII Library implementation using UEFI HII protocols and services."
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c
new file mode 100644
index 000000000..179559bb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c
@@ -0,0 +1,107 @@
+/** @file
+ This library retrieves pointers to the UEFI HII Protocol instances in the
+ library's constructor. All of the UEFI HII related protocols are optional,
+ so the consumers of this library class must verify that the global variable
+ pointers are not NULL before use.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiConfigRouting.h>
+
+///
+/// Pointer to the UEFI HII Font Protocol
+///
+EFI_HII_FONT_PROTOCOL *gHiiFont = NULL;
+
+///
+/// Pointer to the UEFI HII String Protocol
+///
+EFI_HII_STRING_PROTOCOL *gHiiString = NULL;
+
+///
+/// Pointer to the UEFI HII Image Protocol
+///
+EFI_HII_IMAGE_PROTOCOL *gHiiImage = NULL;
+
+///
+/// Pointer to the UEFI HII Database Protocol
+///
+EFI_HII_DATABASE_PROTOCOL *gHiiDatabase = NULL;
+
+///
+/// Pointer to the UEFI HII Config Rounting Protocol
+///
+EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting = NULL;
+
+/**
+ The constructor function retrieves pointers to the UEFI HII protocol instances
+
+ The constructor function retrieves pointers to the four UEFI HII protocols from the
+ handle database. These include the UEFI HII Font Protocol, the UEFI HII String
+ Protocol, the UEFI HII Image Protocol, the UEFI HII Database Protocol, and the
+ UEFI HII Config Routing Protocol. This function always return EFI_SUCCESS.
+ All of these protocols are optional if the platform does not support configuration
+ and the UEFI HII Image Protocol and the UEFI HII Font Protocol are optional if
+ the platform does not support a graphical console. As a result, the consumers
+ of this library much check the protocol pointers againt NULL before using them,
+ or use dependency expressions to guarantee that some of them are present before
+ assuming they are not NULL.
+
+ @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
+UefiHiiServicesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Retrieve the pointer to the UEFI HII String Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &gHiiString);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the UEFI HII Database Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gHiiDatabase);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the UEFI HII Config Routing Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &gHiiConfigRouting);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the optional UEFI HII Font Protocol
+ //
+ gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &gHiiFont);
+
+ //
+ // Retrieve the pointer to the optional UEFI HII Image Protocol
+ //
+ gBS->LocateProtocol (&gEfiHiiImageProtocolGuid, NULL, (VOID **) &gHiiImage);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
new file mode 100644
index 000000000..005e8c9af
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
@@ -0,0 +1,62 @@
+## @file
+# UEFI HII Services Library implementation.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiHiiServicesLib
+ MODULE_UNI_FILE = UefiHiiServicesLib.uni
+ FILE_GUID = 894DC1B6-07A3-4a9d-8CDD-333580B3D4B1
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiHiiServicesLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = UefiHiiServicesLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UefiHiiServicesLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ DebugLib
+
+[Protocols]
+ gEfiHiiFontProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+
+[Depex.common.DXE_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_RUNTIME_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_SAL_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_SMM_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni
new file mode 100644
index 000000000..5b2a73412
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// UEFI HII Services Library implementation.
+//
+// UEFI HII Services Library implementation.
+//
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "UEFI HII Services Library implementation."
+
+#string STR_MODULE_DESCRIPTION #language en-US "UEFI HII Services Library implementation."
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/DxeMemoryProfileLib.c b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/DxeMemoryProfileLib.c
new file mode 100644
index 000000000..fadf0b7f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/DxeMemoryProfileLib.c
@@ -0,0 +1,96 @@
+/** @file
+ Support routines for memory profile for Dxe phase drivers.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi.h>
+
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include <Guid/MemoryProfile.h>
+
+EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
+
+/**
+ The constructor function initializes memory profile for DXE phase.
+
+ @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
+MemoryProfileLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gEdkiiMemoryProfileGuid,
+ NULL,
+ (VOID **) &mLibProfileProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mLibProfileProtocol = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryProfileLibRecord (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ if (mLibProfileProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mLibProfileProtocol->Record (
+ mLibProfileProtocol,
+ CallerAddress,
+ Action,
+ MemoryType,
+ Buffer,
+ Size,
+ ActionString
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/MemoryAllocationLib.c b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/MemoryAllocationLib.c
new file mode 100644
index 000000000..ca63df00a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/MemoryAllocationLib.c
@@ -0,0 +1,1051 @@
+/** @file
+ Support routines for memory allocation routines based
+ on boot services for Dxe phase drivers, with memory profile support.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi.h>
+
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include <Library/MemoryProfileLib.h>
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiBootServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
+ EfiBootServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePages (EfiReservedMemoryType, Pages);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,
+ EfiReservedMemoryType,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = gBS->FreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = gBS->FreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,
+ EfiBootServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,
+ EfiRuntimeServicesData,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES,
+ EfiReservedMemoryType,
+ Buffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer The pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiBootServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,
+ EfiBootServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocatePool (EfiReservedMemoryType, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiBootServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,
+ EfiBootServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,
+ EfiBootServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);
+ if (NewBuffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL,
+ EfiRuntimeServicesData,
+ NewBuffer,
+ AllocationSize,
+ NULL
+ );
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiBootServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,
+ EfiBootServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,
+ EfiRuntimeServicesData,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *Buffer;
+
+ Buffer = InternalReallocatePool (EfiReservedMemoryType, OldSize, NewSize, OldBuffer);
+ if (Buffer != NULL) {
+ MemoryProfileLibRecord (
+ (PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
+ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL,
+ EfiReservedMemoryType,
+ Buffer,
+ NewSize,
+ NULL
+ );
+ }
+ return Buffer;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->FreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.inf b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.inf
new file mode 100644
index 000000000..553e876e4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.inf
@@ -0,0 +1,48 @@
+## @file
+# Instance of Memory Allocation Library using EFI Boot Services,
+# with memory profile support.
+#
+# Memory Allocation Library that uses EFI Boot Services to allocate
+# and free memory, with memory profile support.
+#
+# The implementation of this instance is copied from UefiMemoryAllocationLib
+# in MdePkg and updated to support both MemoryAllocationLib and MemoryProfileLib.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiMemoryAllocationProfileLib
+ MODULE_UNI_FILE = UefiMemoryAllocationProfileLib.uni
+ FILE_GUID = 9E8A380A-231E-41E4-AD40-5E706196B853
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ LIBRARY_CLASS = MemoryProfileLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = MemoryProfileLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ DxeMemoryProfileLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.uni b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.uni
new file mode 100644
index 000000000..e0f369de3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Instance of Memory Allocation Library using EFI Boot Services,
+// with memory profile support.
+//
+// Memory Allocation Library that uses EFI Boot Services to allocate
+// and free memory, with memory profile support.
+//
+// Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library using EFI Boot Services, with memory profile support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This Memory Allocation Library uses EFI Boot Services to allocate and free memory, with memory profile support."
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c
new file mode 100644
index 000000000..46dc44363
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c
@@ -0,0 +1,316 @@
+/** @file
+ Library used for sorting routines.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SortLib.h>
+#include <Library/DevicePathLib.h>
+
+STATIC EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+
+#define USL_FREE_NON_NULL(Pointer) \
+{ \
+ if ((Pointer) != NULL) { \
+ FreePool((Pointer)); \
+ (Pointer) = NULL; \
+ } \
+}
+
+/**
+ Worker function for QuickSorting. This function is identical to PerformQuickSort,
+ except that is uses the pre-allocated buffer so the in place sorting does not need to
+ allocate and free buffers constantly.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+ if Buffer is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+ @param[in] Buffer Buffer of size ElementSize for use in swapping
+**/
+VOID
+EFIAPI
+QuickSortWorker (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction,
+ IN VOID *Buffer
+ )
+{
+ VOID *Pivot;
+ UINTN LoopCount;
+ UINTN NextSwapLocation;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+ ASSERT(Buffer != NULL);
+
+ if ( Count < 2
+ || ElementSize < 1
+ ){
+ return;
+ }
+
+ NextSwapLocation = 0;
+
+ //
+ // pick a pivot (we choose last element)
+ //
+ Pivot = ((UINT8*)BufferToSort+((Count-1)*ElementSize));
+
+ //
+ // Now get the pivot such that all on "left" are below it
+ // and everything "right" are above it
+ //
+ for ( LoopCount = 0
+ ; LoopCount < Count -1
+ ; LoopCount++
+ ){
+ //
+ // if the element is less than the pivot
+ //
+ if (CompareFunction((VOID*)((UINT8*)BufferToSort+((LoopCount)*ElementSize)),Pivot) <= 0){
+ //
+ // swap
+ //
+ CopyMem (Buffer, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), (UINT8*)BufferToSort+((LoopCount)*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+((LoopCount)*ElementSize), Buffer, ElementSize);
+
+ //
+ // increment NextSwapLocation
+ //
+ NextSwapLocation++;
+ }
+ }
+ //
+ // swap pivot to it's final position (NextSwapLocaiton)
+ //
+ CopyMem (Buffer, Pivot, ElementSize);
+ CopyMem (Pivot, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), Buffer, ElementSize);
+
+ //
+ // Now recurse on 2 paritial lists. neither of these will have the 'pivot' element
+ // IE list is sorted left half, pivot element, sorted right half...
+ //
+ if (NextSwapLocation >= 2) {
+ QuickSortWorker(
+ BufferToSort,
+ NextSwapLocation,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ if ((Count - NextSwapLocation - 1) >= 2) {
+ QuickSortWorker(
+ (UINT8 *)BufferToSort + (NextSwapLocation+1) * ElementSize,
+ Count - NextSwapLocation - 1,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ return;
+}
+/**
+ Function to perform a Quick Sort alogrithm on a buffer of comparable elements.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+**/
+VOID
+EFIAPI
+PerformQuickSort (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction
+ )
+{
+ VOID *Buffer;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+
+ Buffer = AllocateZeroPool(ElementSize);
+ ASSERT(Buffer != NULL);
+
+ QuickSortWorker(
+ BufferToSort,
+ Count,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+
+ FreePool(Buffer);
+ return;
+}
+
+/**
+ Function to compare 2 device paths for use in QuickSort.
+
+ @param[in] Buffer1 pointer to Device Path poiner to compare
+ @param[in] Buffer2 pointer to second DevicePath pointer to compare
+
+ @retval 0 Buffer1 equal to Buffer2
+ @retval <0 Buffer1 is less than Buffer2
+ @retval >0 Buffer1 is greater than Buffer2
+**/
+INTN
+EFIAPI
+DevicePathCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath1;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
+ CHAR16 *TextPath1;
+ CHAR16 *TextPath2;
+ EFI_STATUS Status;
+ INTN RetVal;
+
+ DevicePath1 = *(EFI_DEVICE_PATH_PROTOCOL**)Buffer1;
+ DevicePath2 = *(EFI_DEVICE_PATH_PROTOCOL**)Buffer2;
+
+ if (DevicePath1 == NULL) {
+ if (DevicePath2 == NULL) {
+ return 0;
+ }
+
+ return -1;
+ }
+
+ if (DevicePath2 == NULL) {
+ return 1;
+ }
+
+ if (mUnicodeCollation == NULL) {
+ Status = gBS->LocateProtocol(
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID**)&mUnicodeCollation);
+
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ TextPath1 = ConvertDevicePathToText(
+ DevicePath1,
+ FALSE,
+ FALSE);
+
+ TextPath2 = ConvertDevicePathToText(
+ DevicePath2,
+ FALSE,
+ FALSE);
+
+ if (TextPath1 == NULL) {
+ RetVal = -1;
+ } else if (TextPath2 == NULL) {
+ RetVal = 1;
+ } else {
+ RetVal = mUnicodeCollation->StriColl(
+ mUnicodeCollation,
+ TextPath1,
+ TextPath2);
+ }
+
+ USL_FREE_NON_NULL(TextPath1);
+ USL_FREE_NON_NULL(TextPath2);
+
+ return (RetVal);
+}
+
+/**
+ Function to compare 2 strings without regard to case of the characters.
+
+ @param[in] Buffer1 Pointer to String to compare.
+ @param[in] Buffer2 Pointer to second String to compare.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @retval <0 Buffer1 is less than Buffer2.
+ @retval >0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringNoCaseCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ EFI_STATUS Status;
+ if (mUnicodeCollation == NULL) {
+ Status = gBS->LocateProtocol(
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID**)&mUnicodeCollation);
+
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ return (mUnicodeCollation->StriColl(
+ mUnicodeCollation,
+ *(CHAR16**)Buffer1,
+ *(CHAR16**)Buffer2));
+}
+
+
+/**
+ Function to compare 2 strings.
+
+ @param[in] Buffer1 Pointer to String to compare (CHAR16**).
+ @param[in] Buffer2 Pointer to second String to compare (CHAR16**).
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @retval <0 Buffer1 is less than Buffer2.
+ @retval >0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ return (StrCmp(
+ *(CHAR16**)Buffer1,
+ *(CHAR16**)Buffer2));
+}
diff --git a/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
new file mode 100644
index 000000000..2ac6bfacf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
@@ -0,0 +1,42 @@
+## @file
+# Library used for sorting routines.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiSortLib
+ MODULE_UNI_FILE = UefiSortLib.uni
+ FILE_GUID = 4264A823-45A3-42db-B92C-AA078555CBD3
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SortLib|UEFI_APPLICATION UEFI_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER DXE_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ UefiSortLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+ DevicePathLib
+
+[Protocols]
+ gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+
diff --git a/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni
new file mode 100644
index 000000000..42bc43a1c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Library used for sorting routines.
+//
+// Library used for sorting routines.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Library used for sorting routines."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Library used for sorting routines."
+
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
new file mode 100644
index 000000000..a78d09905
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
@@ -0,0 +1,81 @@
+/** @file
+ Internal structure for Var Check Hii.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VAR_CHECK_STRUCTURE_H_
+#define _VAR_CHECK_STRUCTURE_H_
+
+//
+// Alignment for Hii Variable and Question header.
+//
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+#pragma pack (1)
+
+#define VAR_CHECK_HII_REVISION 0x0002
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 HeaderLength;
+ UINT32 Length; // Length include this header
+ UINT8 OpCode;
+ UINT8 Reserved;
+ UINT16 Size;
+ UINT32 Attributes;
+ EFI_GUID Guid;
+//CHAR16 Name[];
+} VAR_CHECK_HII_VARIABLE_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ BOOLEAN BitFieldStore; // Whether the Question is stored in bit field, if TRUE, the VarOffset/StorageWidth will be saved as bit level, otherwise in byte level.
+} VAR_CHECK_HII_QUESTION_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ BOOLEAN BitFieldStore; // Whether the Question is stored in bit field, if TRUE, the VarOffset/StorageWidth will be saved as bit level, otherwise in byte level.
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ONEOF;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ BOOLEAN BitFieldStore; // Whether the Question is stored in bit field, if TRUE, the VarOffset/StorageWidth will be saved as bit level, otherwise in byte level.
+} VAR_CHECK_HII_QUESTION_CHECKBOX;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ BOOLEAN BitFieldStore; // Whether the Question is stored in bit field, if TRUE, the VarOffset/StorageWidth will be saved as bit level, otherwise in byte level.
+//UINTx Minimum; // x = UINT8/UINT16/UINT32/UINT64;
+//UINTx Maximum; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_NUMERIC;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ BOOLEAN BitFieldStore; // Whether the Question is stored in bit field, if TRUE, the VarOffset/StorageWidth will be saved as bit level, otherwise in byte level.
+ UINT8 MaxContainers;
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ORDEREDLIST;
+
+#pragma pack ()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
new file mode 100644
index 000000000..fe0863922
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
@@ -0,0 +1,57 @@
+/** @file
+ Include file for Var Check Hii handler and bin.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VAR_CHECK_HII_H_
+#define _VAR_CHECK_HII_H_
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include "InternalVarCheckStructure.h"
+#include "VarCheckHiiGen.h"
+
+//#define DUMP_VAR_CHECK_HII
+//#define DUMP_HII_DATA
+
+typedef struct {
+ UINT8 HiiOpCode;
+ CHAR8 *HiiOpCodeStr;
+} VAR_CHECK_HII_OPCODE_STRING;
+
+typedef struct {
+ UINT8 PackageType;
+ CHAR8 *PackageTypeStr;
+} VAR_CHECK_HII_PACKAGE_TYPE_STRING;
+
+/**
+ Dump Var Check HII.
+
+ @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
+ @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+ IN VOID *VarCheckHiiBin,
+ IN UINTN VarCheckHiiBinSize
+ );
+
+extern VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin;
+extern UINTN mVarCheckHiiBinSize;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
new file mode 100644
index 000000000..3d787b8f7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
@@ -0,0 +1,1583 @@
+/** @file
+ Var Check Hii bin generation.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
+
+#define VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'V')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ EFI_VARSTORE_ID VarStoreId;
+
+ VAR_CHECK_HII_QUESTION_HEADER **HiiQuestionArray;
+} VAR_CHECK_HII_VARIABLE_NODE;
+
+#define VAR_CHECK_HII_VARIABLE_FROM_LINK(a) CR (a, VAR_CHECK_HII_VARIABLE_NODE, Link, VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE)
+
+CHAR16 *mVarName = NULL;
+UINTN mMaxVarNameSize = 0;
+
+#ifdef DUMP_HII_DATA
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mIfrOpCodeStringTable[] = {
+ {EFI_IFR_VARSTORE_OP, "EFI_IFR_VARSTORE_OP"},
+ {EFI_IFR_VARSTORE_EFI_OP, "EFI_IFR_VARSTORE_EFI_OP"},
+ {EFI_IFR_ONE_OF_OP, "EFI_IFR_ONE_OF_OP"},
+ {EFI_IFR_CHECKBOX_OP, "EFI_IFR_CHECKBOX_OP"},
+ {EFI_IFR_NUMERIC_OP, "EFI_IFR_NUMERIC_OP"},
+ {EFI_IFR_ORDERED_LIST_OP, "EFI_IFR_ORDERED_LIST_OP"},
+ {EFI_IFR_ONE_OF_OPTION_OP, "EFI_IFR_ONE_OF_OPTION_OP"},
+};
+
+/**
+ Ifr opcode to string.
+
+ @param[in] IfrOpCode Ifr OpCode.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+IfrOpCodeToStr (
+ IN UINT8 IfrOpCode
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < ARRAY_SIZE (mIfrOpCodeStringTable); Index++) {
+ if (mIfrOpCodeStringTable[Index].HiiOpCode == IfrOpCode) {
+ return mIfrOpCodeStringTable[Index].HiiOpCodeStr;
+ }
+ }
+
+ return "<UnknownIfrOpCode>";
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_PACKAGE_TYPE_STRING mPackageTypeStringTable[] = {
+ {EFI_HII_PACKAGE_TYPE_ALL, "EFI_HII_PACKAGE_TYPE_ALL"},
+ {EFI_HII_PACKAGE_TYPE_GUID, "EFI_HII_PACKAGE_TYPE_GUID"},
+ {EFI_HII_PACKAGE_FORMS, "EFI_HII_PACKAGE_FORMS"},
+ {EFI_HII_PACKAGE_STRINGS, "EFI_HII_PACKAGE_STRINGS"},
+ {EFI_HII_PACKAGE_FONTS, "EFI_HII_PACKAGE_FONTS"},
+ {EFI_HII_PACKAGE_IMAGES, "EFI_HII_PACKAGE_IMAGES"},
+ {EFI_HII_PACKAGE_SIMPLE_FONTS, "EFI_HII_PACKAGE_SIMPLE_FONTS"},
+ {EFI_HII_PACKAGE_DEVICE_PATH, "EFI_HII_PACKAGE_DEVICE_PATH"},
+ {EFI_HII_PACKAGE_KEYBOARD_LAYOUT, "EFI_HII_PACKAGE_KEYBOARD_LAYOUT"},
+ {EFI_HII_PACKAGE_ANIMATIONS, "EFI_HII_PACKAGE_ANIMATIONS"},
+ {EFI_HII_PACKAGE_END, "EFI_HII_PACKAGE_END"},
+ {EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN, "EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN"},
+ {EFI_HII_PACKAGE_TYPE_SYSTEM_END, "EFI_HII_PACKAGE_TYPE_SYSTEM_END"},
+};
+
+/**
+ Hii Package type to string.
+
+ @param[in] PackageType Package Type
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+HiiPackageTypeToStr (
+ IN UINT8 PackageType
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < ARRAY_SIZE (mPackageTypeStringTable); Index++) {
+ if (mPackageTypeStringTable[Index].PackageType == PackageType) {
+ return mPackageTypeStringTable[Index].PackageTypeStr;
+ }
+ }
+
+ return "<UnknownPackageType>";
+}
+
+/**
+ Dump Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+ IN VOID *HiiPackage
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ BOOLEAN QuestionStoredInBitField;
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+ QuestionStoredInBitField = FALSE;
+
+ DEBUG ((DEBUG_INFO, " HiiPackageHeader->Type - 0x%02x (%a)\n", HiiPackageHeader->Type, HiiPackageTypeToStr ((UINT8) HiiPackageHeader->Type)));
+ DEBUG ((DEBUG_INFO, " HiiPackageHeader->Length - 0x%06x\n", HiiPackageHeader->Length));
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < ((UINTN) HiiPackageHeader + HiiPackageHeader->Length)) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((DEBUG_INFO, " Guid - %g\n", &IfrVarStore->Guid));
+ DEBUG ((DEBUG_INFO, " VarStoreId - 0x%04x\n", IfrVarStore->VarStoreId));
+ DEBUG ((DEBUG_INFO, " Size - 0x%04x\n", IfrVarStore->Size));
+ DEBUG ((DEBUG_INFO, " Name - %a\n", IfrVarStore->Name));
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+ if (IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) {
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((DEBUG_INFO, " Guid - %g\n", &IfrEfiVarStore->Guid));
+ DEBUG ((DEBUG_INFO, " VarStoreId - 0x%04x\n", IfrEfiVarStore->VarStoreId));
+ DEBUG ((DEBUG_INFO, " Size - 0x%04x\n", IfrEfiVarStore->Size));
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%08x\n", IfrEfiVarStore->Attributes));
+ DEBUG ((DEBUG_INFO, " Name - %a\n", IfrEfiVarStore->Name));
+ }
+ break;
+
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)((UINTN)IfrOpCodeHeader + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ QuestionStoredInBitField = TRUE;
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a) (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode), (QuestionStoredInBitField? "bit level": "byte level")));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
+ DEBUG ((DEBUG_INFO, " IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((DEBUG_INFO, " Prompt - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt));
+ DEBUG ((DEBUG_INFO, " Help - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help));
+ DEBUG ((DEBUG_INFO, " QuestionId - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.QuestionId));
+ DEBUG ((DEBUG_INFO, " VarStoreId - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId));
+ DEBUG ((DEBUG_INFO, " VarStoreInfo - 0x%04x (%a)\n", ((EFI_IFR_ONE_OF * )IfrOpCodeHeader)->Question.VarStoreInfo.VarOffset, (QuestionStoredInBitField? "bit level": "byte level")));
+ {
+ EFI_IFR_ONE_OF *IfrOneOf;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_NUMERIC *IfrNumeric;
+ EFI_IFR_ORDERED_LIST *IfrOrderedList;
+
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, " Flags - 0x%02x\n", IfrOneOf->Flags));
+ if (QuestionStoredInBitField) {
+ //
+ // For OneOf stored in bit field, the option value are saved as UINT32 type.
+ //
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%08x\n", IfrOneOf->data.u32.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%08x\n", IfrOneOf->data.u32.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%08x\n", IfrOneOf->data.u32.Step));
+ } else {
+ switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%02x\n", IfrOneOf->data.u8.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%02x\n", IfrOneOf->data.u8.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%02x\n", IfrOneOf->data.u8.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%04x\n", IfrOneOf->data.u16.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%04x\n", IfrOneOf->data.u16.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%04x\n", IfrOneOf->data.u16.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%08x\n", IfrOneOf->data.u32.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%08x\n", IfrOneOf->data.u32.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%08x\n", IfrOneOf->data.u32.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%016lx\n", IfrOneOf->data.u64.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%016lx\n", IfrOneOf->data.u64.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%016lx\n", IfrOneOf->data.u64.Step));
+ break;
+ }
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, " Flags - 0x%02x\n", IfrCheckBox->Flags));
+ break;
+ case EFI_IFR_NUMERIC_OP:
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, " Flags - 0x%02x\n", IfrNumeric->Flags));
+ if (QuestionStoredInBitField) {
+ //
+ // For Numeric stored in bit field, the MinValue,MaxValue and Step are saved as UINT32 type.
+ //
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%08x\n", IfrNumeric->data.u32.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%08x\n", IfrNumeric->data.u32.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%08x\n", IfrNumeric->data.u32.Step));
+ } else {
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%02x\n", IfrNumeric->data.u8.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%02x\n", IfrNumeric->data.u8.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%02x\n", IfrNumeric->data.u8.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%04x\n", IfrNumeric->data.u16.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%04x\n", IfrNumeric->data.u16.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%04x\n", IfrNumeric->data.u16.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%08x\n", IfrNumeric->data.u32.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%08x\n", IfrNumeric->data.u32.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%08x\n", IfrNumeric->data.u32.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ DEBUG ((DEBUG_INFO, " MinValue - 0x%016lx\n", IfrNumeric->data.u64.MinValue));
+ DEBUG ((DEBUG_INFO, " MaxValue - 0x%016lx\n", IfrNumeric->data.u64.MaxValue));
+ DEBUG ((DEBUG_INFO, " Step - 0x%016lx\n", IfrNumeric->data.u64.Step));
+ break;
+ }
+ }
+ break;
+ case EFI_IFR_ORDERED_LIST_OP:
+ IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, " MaxContainers - 0x%02x\n", IfrOrderedList->MaxContainers));
+ DEBUG ((DEBUG_INFO, " Flags - 0x%02x\n", IfrOrderedList->Flags));
+ break;
+ default:
+ break;
+ }
+
+ if (IfrOpCodeHeader->Scope != 0) {
+ UINTN Scope;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ Scope = 1;
+ while (Scope != 0) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *)IfrOpCodeHeader;
+ DEBUG ((DEBUG_INFO, "!!!! IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", (UINTN)IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((DEBUG_INFO, "!!!! IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((DEBUG_INFO, "!!!! Option - 0x%04x\n", IfrOneOfOption->Option));
+ DEBUG ((DEBUG_INFO, "!!!! Flags - 0x%02x\n", IfrOneOfOption->Flags));
+ DEBUG ((DEBUG_INFO, "!!!! Type - 0x%02x\n", IfrOneOfOption->Type));
+ switch (IfrOneOfOption->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ DEBUG ((DEBUG_INFO, "!!!! Value - 0x%02x\n", IfrOneOfOption->Value.u8));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ DEBUG ((DEBUG_INFO, "!!!! Value - 0x%04x\n", IfrOneOfOption->Value.u16));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ DEBUG ((DEBUG_INFO, "!!!! Value - 0x%08x\n", IfrOneOfOption->Value.u32));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ DEBUG ((DEBUG_INFO, "!!!! Value - 0x%016lx\n", IfrOneOfOption->Value.u64));
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ DEBUG ((DEBUG_INFO, "!!!! Value - 0x%02x\n", IfrOneOfOption->Value.b));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+ QuestionStoredInBitField = FALSE;
+ ASSERT (Scope > 0);
+ Scope--;
+ if (Scope == 0) {
+ break;
+ }
+ } else if (IfrOpCodeHeader->Scope != 0) {
+ Scope++;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ }
+ }
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ Dump Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ )
+{
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageListHeader;
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+
+ DEBUG ((DEBUG_INFO, "HiiDatabaseSize - 0x%x\n", HiiDatabaseSize));
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+ while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
+ DEBUG ((DEBUG_INFO, "HiiPackageListHeader->PackageListGuid - %g\n", &HiiPackageListHeader->PackageListGuid));
+ DEBUG ((DEBUG_INFO, "HiiPackageListHeader->PackageLength - 0x%x\n", (UINTN)HiiPackageListHeader->PackageLength));
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiPackageListHeader + 1);
+
+ while ((UINTN) HiiPackageHeader < (UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength) {
+
+ DumpHiiPackage (HiiPackageHeader);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
+ }
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+ }
+
+ return ;
+}
+#endif
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalVarCheckAllocatePool (EfiBootServicesData, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->FreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalVarCheckAllocateZeroPool (NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ InternalVarCheckFreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Merge Hii Question.
+
+ @param[in, out] HiiVariableNode Pointer to Hii Variable node.
+ @param[in] HiiQuestion Pointer to Hii Question.
+ @param[in] FromFv Hii Question from FV.
+
+**/
+VOID
+MergeHiiQuestion (
+ IN OUT VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode,
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
+ IN BOOLEAN FromFv
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion1;
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion2;
+ VAR_CHECK_HII_QUESTION_HEADER *NewHiiQuestion;
+ UINT8 NewLength;
+ UINT64 Minimum1;
+ UINT64 Maximum1;
+ UINT64 OneValue1;
+ UINT64 Minimum2;
+ UINT64 Maximum2;
+ UINT64 OneValue2;
+ UINT8 *Ptr;
+ UINT8 *Ptr1;
+ UINT8 *Ptr2;
+ UINTN ArrayIndex;
+
+ //
+ // Hii Question from Hii Database has high priority.
+ // Do not to merge Hii Question from Fv to Hii Question from Hii Database.
+ //
+ if (FromFv) {
+ InternalVarCheckFreePool (HiiQuestion);
+ return;
+ }
+
+ if (HiiQuestion->BitFieldStore) {
+ ArrayIndex = HiiQuestion->VarOffset;
+ } else {
+ ArrayIndex = HiiQuestion->VarOffset * 8;
+ }
+
+ HiiQuestion1 = HiiVariableNode->HiiQuestionArray[ArrayIndex];
+ HiiQuestion2 = HiiQuestion;
+
+ ASSERT ((HiiQuestion1->OpCode == HiiQuestion2->OpCode) && (HiiQuestion1->StorageWidth == HiiQuestion2->StorageWidth));
+
+ switch (HiiQuestion1->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_ONE_OF_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
+ //
+ // Get the length of Hii Question 1.
+ //
+ NewLength = HiiQuestion1->Length;
+
+ //
+ // Check if the one of options in Hii Question 2 have been in Hii Question 1.
+ //
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ if (NewLength > HiiQuestion1->Length) {
+ //
+ // Merge the one of options of Hii Question 2 and Hii Question 1.
+ //
+ NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+ ASSERT (NewHiiQuestion != NULL);
+ CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+ //
+ // Use the new length.
+ //
+ NewHiiQuestion->Length = NewLength;
+ Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ HiiVariableNode->HiiQuestionArray[ArrayIndex] = NewHiiQuestion;
+ InternalVarCheckFreePool (HiiQuestion1);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_CHECKBOX_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_NUMERIC_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
+ //
+ // Get minimum and maximum of Hii Question 1.
+ //
+ Minimum1 = 0;
+ Maximum1 = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+ CopyMem (&Minimum1, Ptr, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ CopyMem (&Maximum1, Ptr, HiiQuestion1->StorageWidth);
+
+ //
+ // Get minimum and maximum of Hii Question 2.
+ //
+ Minimum2 = 0;
+ Maximum2 = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion2 + 1);
+ CopyMem (&Minimum2, Ptr, HiiQuestion2->StorageWidth);
+ Ptr += HiiQuestion2->StorageWidth;
+ CopyMem (&Maximum2, Ptr, HiiQuestion2->StorageWidth);
+
+ //
+ // Update minimum.
+ //
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+ if (Minimum2 < Minimum1) {
+ Minimum1 = Minimum2;
+ CopyMem (Ptr, &Minimum1, HiiQuestion1->StorageWidth);
+ }
+ //
+ // Update maximum.
+ //
+ Ptr += HiiQuestion1->StorageWidth;
+ if (Maximum2 > Maximum1) {
+ Maximum1 = Maximum2;
+ CopyMem (Ptr, &Maximum1, HiiQuestion1->StorageWidth);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_ORDERED_LIST_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+ //
+ // Get the length of Hii Question 1.
+ //
+ NewLength = HiiQuestion1->Length;
+
+ //
+ // Check if the one of options in Hii Question 2 have been in Hii Question 1.
+ //
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ if (NewLength > HiiQuestion1->Length) {
+ //
+ // Merge the one of options of Hii Question 2 and Hii Question 1.
+ //
+ NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+ ASSERT (NewHiiQuestion != NULL);
+ CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+ //
+ // Use the new length.
+ //
+ NewHiiQuestion->Length = NewLength;
+ Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ HiiVariableNode->HiiQuestionArray[ArrayIndex] = NewHiiQuestion;
+ InternalVarCheckFreePool (HiiQuestion1);
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return;
+ break;
+ }
+
+ //
+ //
+ // Hii Question 2 has been merged with Hii Question 1.
+ //
+ InternalVarCheckFreePool (HiiQuestion2);
+}
+
+/**
+ Get OneOf option data.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[out] Count Pointer to option count.
+ @param[out] Width Pointer to option width.
+ @param[out] OptionBuffer Pointer to option buffer.
+
+**/
+VOID
+GetOneOfOption (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ OUT UINTN *Count,
+ OUT UINT8 *Width,
+ OUT VOID *OptionBuffer OPTIONAL
+ )
+{
+ UINTN Scope;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+
+ //
+ // Assume all OPTION has same Width.
+ //
+ *Count = 0;
+
+ if (IfrOpCodeHeader->Scope != 0) {
+ //
+ // Nested OpCode.
+ //
+ Scope = 1;
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ while (Scope != 0) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpCodeHeader;
+ switch (IfrOneOfOption->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT8);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u8, sizeof (UINT8));
+ OptionBuffer = (UINT8 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT16);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u16, sizeof (UINT16));
+ OptionBuffer = (UINT16 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT32);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u32, sizeof (UINT32));
+ OptionBuffer = (UINT32 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT64);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u64, sizeof (UINT64));
+ OptionBuffer = (UINT64 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ *Count = *Count + 1;
+ *Width = sizeof (BOOLEAN);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.b, sizeof (BOOLEAN));
+ OptionBuffer = (BOOLEAN *) OptionBuffer + 1;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ //
+ // Until End OpCode.
+ //
+ if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+ ASSERT (Scope > 0);
+ Scope--;
+ if (Scope == 0) {
+ break;
+ }
+ } else if (IfrOpCodeHeader->Scope != 0) {
+ //
+ // Nested OpCode.
+ //
+ Scope++;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ }
+
+ return ;
+}
+
+/**
+ Parse Hii Question Oneof.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[in] StoredInBitField Whether the OneOf is stored in bit field Storage.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOneOf (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ IN BOOLEAN StoredInBitField
+ )
+{
+ EFI_IFR_ONE_OF *IfrOneOf;
+ VAR_CHECK_HII_QUESTION_ONEOF *OneOf;
+ UINTN Length;
+ UINT8 Width;
+ UINTN OptionCount;
+ UINT8 OptionWidth;
+ UINT8 BitWidth;
+
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+ BitWidth = 0;
+
+ if (StoredInBitField) {
+ //
+ // When OneOf stored in bit field, the bit width is saved in the lower six bits of the flag.
+ // And the options in the OneOf is saved as UINT32 type.
+ //
+ BitWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ Width = sizeof (UINT32);
+ } else {
+ Width = (UINT8) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+ ASSERT (Width == OptionWidth);
+
+ Length = sizeof (*OneOf) + OptionCount * Width;
+
+ OneOf = InternalVarCheckAllocateZeroPool (Length);
+ ASSERT (OneOf != NULL);
+ OneOf->OpCode = EFI_IFR_ONE_OF_OP;
+ OneOf->Length = (UINT8) Length;
+ OneOf->VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
+ OneOf->BitFieldStore = StoredInBitField;
+ if (StoredInBitField) {
+ OneOf->StorageWidth = BitWidth;
+ } else {
+ OneOf->StorageWidth = Width;
+ }
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OneOf + 1);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) OneOf;
+}
+
+/**
+ Parse Hii Question CheckBox.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[in] StoredInBitField Whether the CheckBox is stored in bit field Storage.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionCheckBox (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ IN BOOLEAN StoredInBitField
+ )
+{
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ VAR_CHECK_HII_QUESTION_CHECKBOX *CheckBox;
+
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+
+ CheckBox = InternalVarCheckAllocateZeroPool (sizeof (*CheckBox));
+ ASSERT (CheckBox != NULL);
+ CheckBox->OpCode = EFI_IFR_CHECKBOX_OP;
+ CheckBox->Length = (UINT8) sizeof (*CheckBox);;
+ CheckBox->VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+ CheckBox->BitFieldStore = StoredInBitField;
+ if (StoredInBitField) {
+ CheckBox->StorageWidth = 1;
+ } else {
+ CheckBox->StorageWidth = (UINT8) sizeof (BOOLEAN);
+ }
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) CheckBox;
+}
+
+/**
+ Parse Hii Question Numeric.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[in] StoredInBitField Whether the Numeric is stored in bit field Storage.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionNumeric (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ IN BOOLEAN StoredInBitField
+ )
+{
+ EFI_IFR_NUMERIC *IfrNumeric;
+ VAR_CHECK_HII_QUESTION_NUMERIC *Numeric;
+ UINT8 Width;
+ UINT8 BitWidth;
+
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+ BitWidth = 0;
+
+ Numeric = InternalVarCheckAllocateZeroPool (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * sizeof (UINT64));
+ ASSERT (Numeric != NULL);
+
+ if (StoredInBitField) {
+ //
+ // When Numeric stored in bit field, the bit field width is saved in the lower six bits of the flag.
+ // And the Minimum Maximum of Numeric is saved as UINT32 type.
+ //
+ BitWidth = IfrNumeric->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ Width = sizeof (UINT32);
+ } else {
+ Width = (UINT8) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+
+ Numeric->OpCode = EFI_IFR_NUMERIC_OP;
+ Numeric->Length = (UINT8) (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * Width);
+ Numeric->VarOffset = IfrNumeric->Question.VarStoreInfo.VarOffset;
+ Numeric->BitFieldStore = StoredInBitField;
+ if (StoredInBitField) {
+ Numeric->StorageWidth = BitWidth;
+ } else {
+ Numeric->StorageWidth = Width;
+ }
+
+ CopyMem (Numeric + 1, &IfrNumeric->data, Width * 2);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) Numeric;
+}
+
+/**
+ Parse Hii Question OrderedList.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOrderedList (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader
+ )
+{
+ EFI_IFR_ORDERED_LIST *IfrOrderedList;
+ VAR_CHECK_HII_QUESTION_ORDEREDLIST *OrderedList;
+ UINTN Length;
+ UINTN OptionCount;
+ UINT8 OptionWidth;
+
+ IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+
+ Length = sizeof (*OrderedList) + OptionCount * OptionWidth;
+
+ OrderedList = InternalVarCheckAllocateZeroPool (Length);
+ ASSERT (OrderedList != NULL);
+ OrderedList->OpCode = EFI_IFR_ORDERED_LIST_OP;
+ OrderedList->Length = (UINT8) Length;
+ OrderedList->VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;
+ OrderedList->StorageWidth = OptionWidth;
+ OrderedList->MaxContainers = IfrOrderedList->MaxContainers;
+ OrderedList->BitFieldStore = FALSE;
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OrderedList + 1);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) OrderedList;
+}
+
+/**
+ Parse and create Hii Question node.
+
+ @param[in] HiiVariableNode Pointer to Hii Variable node.
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[in] FromFv Hii Question from FV.
+ @param[in] StoredInBitField Whether the Question is stored in bit field Storage.
+
+**/
+VOID
+ParseHiiQuestion (
+ IN VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode,
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ IN BOOLEAN FromFv,
+ IN BOOLEAN StoredInBitField
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+ UINTN ArrayIndex;
+
+ //
+ // Currently only OneOf, CheckBox and Numeric can be stored in bit field.
+ //
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ HiiQuestion = ParseHiiQuestionOneOf (IfrOpCodeHeader, StoredInBitField);
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ HiiQuestion = ParseHiiQuestionCheckBox (IfrOpCodeHeader, StoredInBitField);
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ HiiQuestion = ParseHiiQuestionNumeric (IfrOpCodeHeader, StoredInBitField);
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ HiiQuestion = ParseHiiQuestionOrderedList (IfrOpCodeHeader);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return;
+ break;
+ }
+
+ if (StoredInBitField) {
+ ArrayIndex = HiiQuestion->VarOffset;
+ } else {
+ ArrayIndex = HiiQuestion->VarOffset * 8;
+ }
+ if (HiiVariableNode->HiiQuestionArray[ArrayIndex] != NULL) {
+ MergeHiiQuestion (HiiVariableNode, HiiQuestion, FromFv);
+ } else {
+ HiiVariableNode->HiiQuestionArray[ArrayIndex] = HiiQuestion;
+ }
+}
+
+/**
+ Find Hii variable node by name and GUID.
+
+ @param[in] Name Pointer to variable name.
+ @param[in] Guid Pointer to vendor GUID.
+
+ @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNode (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+
+ if ((StrCmp (Name, (CHAR16 *) (HiiVariableNode->HiiVariable + 1)) == 0) &&
+ CompareGuid (Guid, &HiiVariableNode->HiiVariable->Guid)) {
+ return HiiVariableNode;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Find Hii variable node by var store id.
+
+ @param[in] VarStoreId Var store id.
+
+ @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNodeByVarStoreId (
+ IN EFI_VARSTORE_ID VarStoreId
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ if (VarStoreId == 0) {
+ //
+ // The variable store identifier, which is unique within the current form set.
+ // A value of zero is invalid.
+ //
+ return NULL;
+ }
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+ //
+ // The variable store identifier, which is unique within the current form set.
+ //
+ if (VarStoreId == HiiVariableNode->VarStoreId) {
+ return HiiVariableNode;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Destroy var store id in the Hii Variable node after parsing one Hii Package.
+
+**/
+VOID
+DestroyVarStoreId (
+ VOID
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+ //
+ // The variable store identifier, which is unique within the current form set.
+ // A value of zero is invalid.
+ //
+ HiiVariableNode->VarStoreId = 0;
+ }
+}
+
+/**
+ Create Hii Variable node.
+
+ @param[in] IfrEfiVarStore Pointer to EFI VARSTORE.
+
+**/
+VOID
+CreateHiiVariableNode (
+ IN EFI_IFR_VARSTORE_EFI *IfrEfiVarStore
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ UINTN HeaderLength;
+ CHAR16 *VarName;
+ UINTN VarNameSize;
+
+ //
+ // Get variable name.
+ //
+ VarNameSize = AsciiStrSize ((CHAR8 *) IfrEfiVarStore->Name) * sizeof (CHAR16);
+ if (VarNameSize > mMaxVarNameSize) {
+ mVarName = InternalVarCheckReallocatePool (mMaxVarNameSize, VarNameSize, mVarName);
+ ASSERT (mVarName != NULL);
+ mMaxVarNameSize = VarNameSize;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) IfrEfiVarStore->Name, mVarName, mMaxVarNameSize / sizeof (CHAR16));
+ VarName = mVarName;
+
+ HiiVariableNode = FindHiiVariableNode (
+ VarName,
+ &IfrEfiVarStore->Guid
+ );
+ if (HiiVariableNode == NULL) {
+ //
+ // Not found, then create new.
+ //
+ HeaderLength = sizeof (*HiiVariable) + VarNameSize;
+ HiiVariable = InternalVarCheckAllocateZeroPool (HeaderLength);
+ ASSERT (HiiVariable != NULL);
+ HiiVariable->Revision = VAR_CHECK_HII_REVISION;
+ HiiVariable->OpCode = EFI_IFR_VARSTORE_EFI_OP;
+ HiiVariable->HeaderLength = (UINT16) HeaderLength;
+ HiiVariable->Size = IfrEfiVarStore->Size;
+ HiiVariable->Attributes = IfrEfiVarStore->Attributes;
+ CopyGuid (&HiiVariable->Guid, &IfrEfiVarStore->Guid);
+ StrCpyS ((CHAR16 *) (HiiVariable + 1), VarNameSize / sizeof (CHAR16), VarName);
+
+ HiiVariableNode = InternalVarCheckAllocateZeroPool (sizeof (*HiiVariableNode));
+ ASSERT (HiiVariableNode != NULL);
+ HiiVariableNode->Signature = VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE;
+ HiiVariableNode->HiiVariable = HiiVariable;
+ //
+ // The variable store identifier, which is unique within the current form set.
+ //
+ HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+ HiiVariableNode->HiiQuestionArray = InternalVarCheckAllocateZeroPool (IfrEfiVarStore->Size * 8 * sizeof (VAR_CHECK_HII_QUESTION_HEADER *));
+
+ InsertTailList (&mVarCheckHiiList, &HiiVariableNode->Link);
+ } else {
+ HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+ }
+}
+
+/**
+ Parse and create Hii Variable node list.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+ParseHiiVariable (
+ IN VOID *HiiPackage
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Come to EFI VARSTORE in Form Package.
+ //
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+ if ((IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) &&
+ ((IfrEfiVarStore->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
+ //
+ // Only create node list for Hii Variable with NV attribute.
+ //
+ CreateHiiVariableNode (IfrEfiVarStore);
+ }
+ break;
+
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Var Check Parse Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+ @param[in] FromFv Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+ IN VOID *HiiPackage,
+ IN BOOLEAN FromFv
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ BOOLEAN QuestionStoredInBitField;
+
+ //
+ // Parse and create Hii Variable node list for this Hii Package.
+ //
+ ParseHiiVariable (HiiPackage);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+ QuestionStoredInBitField = FALSE;
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)((UINTN)IfrOpCodeHeader + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ QuestionStoredInBitField = TRUE;
+ }
+ break;
+
+ case EFI_IFR_END_OP:
+ QuestionStoredInBitField = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ HiiVariableNode = FindHiiVariableNodeByVarStoreId (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId);
+ if ((HiiVariableNode == NULL) ||
+ //
+ // No related Hii Variable node found.
+ //
+ ((((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt == 0) && (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help == 0))) {
+ //
+ // meanless IFR item introduced by ECP.
+ //
+ } else {
+ //
+ // Normal IFR
+ //
+ ParseHiiQuestion (HiiVariableNode, IfrOpCodeHeader, FromFv, QuestionStoredInBitField);
+ }
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+
+ default:
+ break;
+ }
+ DestroyVarStoreId ();
+}
+
+/**
+ Var Check Parse Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ )
+{
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageListHeader;
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+ while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageListHeader + 1);
+
+ while ((UINTN) HiiPackageHeader < ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength)) {
+ //
+ // Parse Hii Package.
+ //
+ VarCheckParseHiiPackage (HiiPackageHeader, FALSE);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
+ }
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+ }
+}
+
+/**
+ Destroy Hii Variable node.
+
+**/
+VOID
+DestroyHiiVariableNode (
+ VOID
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *HiiVariableLink;
+ UINTN Index;
+
+ while (mVarCheckHiiList.ForwardLink != &mVarCheckHiiList) {
+ HiiVariableLink = mVarCheckHiiList.ForwardLink;
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+
+ RemoveEntryList (&HiiVariableNode->Link);
+
+ //
+ // Free the allocated buffer.
+ //
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray[Index]);
+ }
+ }
+ InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray);
+ InternalVarCheckFreePool (HiiVariableNode->HiiVariable);
+ InternalVarCheckFreePool (HiiVariableNode);
+ }
+}
+
+/**
+ Build VarCheckHiiBin.
+
+ @param[out] Size Pointer to VarCheckHii size.
+
+ @return Pointer to VarCheckHiiBin.
+
+**/
+VOID *
+BuildVarCheckHiiBin (
+ OUT UINTN *Size
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *HiiVariableLink;
+ UINTN Index;
+ VOID *Data;
+ UINT8 *Ptr;
+ UINT32 BinSize;
+ UINT32 HiiVariableLength;
+
+ //
+ // Get Size
+ //
+ BinSize = 0;
+
+ for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+ ;HiiVariableLink != &mVarCheckHiiList
+ ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+ //
+ // For Hii Variable header align.
+ //
+ BinSize = (UINT32) HEADER_ALIGN (BinSize);
+
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+ HiiVariableLength = HiiVariableNode->HiiVariable->HeaderLength;
+
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ //
+ // For Hii Question header align.
+ //
+ HiiVariableLength = (UINT32) HEADER_ALIGN (HiiVariableLength);
+ HiiVariableLength += HiiVariableNode->HiiQuestionArray[Index]->Length;
+ }
+ }
+
+ HiiVariableNode->HiiVariable->Length = HiiVariableLength;
+ BinSize += HiiVariableLength;
+ }
+
+ DEBUG ((DEBUG_INFO, "VarCheckHiiBin - size = 0x%x\n", BinSize));
+ if (BinSize == 0) {
+ *Size = BinSize;
+ return NULL;
+ }
+
+ //
+ // AllocatePages () and AllocatePool () from gBS are used for the process of VarCheckHiiBin generation.
+ // Only here AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
+ // in SetVariable check handler.
+ //
+ Data = AllocateRuntimeZeroPool (BinSize);
+ ASSERT (Data != NULL);
+ //
+ // Make sure the allocated buffer for VarCheckHiiBin at required alignment.
+ //
+ ASSERT ((((UINTN) Data) & (HEADER_ALIGNMENT - 1)) == 0);
+ DEBUG ((DEBUG_INFO, "VarCheckHiiBin - built at 0x%x\n", Data));
+
+ //
+ // Gen Data
+ //
+ Ptr = Data;
+ for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+ ;HiiVariableLink != &mVarCheckHiiList
+ ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+ //
+ // For Hii Variable header align.
+ //
+ Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+ CopyMem (Ptr, HiiVariableNode->HiiVariable, HiiVariableNode->HiiVariable->HeaderLength);
+ Ptr += HiiVariableNode->HiiVariable->HeaderLength;
+
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ //
+ // For Hii Question header align.
+ //
+ Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+ CopyMem (Ptr, HiiVariableNode->HiiQuestionArray[Index], HiiVariableNode->HiiQuestionArray[Index]->Length);
+ Ptr += HiiVariableNode->HiiQuestionArray[Index]->Length;
+ }
+ }
+ }
+
+ *Size = BinSize;
+ return Data;
+}
+
+/**
+ Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+ VOID
+ )
+{
+ VarCheckHiiGenFromHiiDatabase ();
+ VarCheckHiiGenFromFv ();
+
+ mVarCheckHiiBin = BuildVarCheckHiiBin (&mVarCheckHiiBinSize);
+ if (mVarCheckHiiBin == NULL) {
+ DEBUG ((DEBUG_INFO, "[VarCheckHii] This driver could be removed from *.dsc and *.fdf\n"));
+ return;
+ }
+
+ DestroyHiiVariableNode ();
+ if (mVarName != NULL) {
+ InternalVarCheckFreePool (mVarName);
+ }
+
+#ifdef DUMP_VAR_CHECK_HII
+ DEBUG_CODE (
+ DumpVarCheckHii (mVarCheckHiiBin, mVarCheckHiiBinSize);
+ );
+#endif
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
new file mode 100644
index 000000000..02783c431
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
@@ -0,0 +1,130 @@
+/** @file
+ Include file for Var Check Hii bin generation.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VAR_CHECK_HII_GEN_H_
+#define _VAR_CHECK_HII_GEN_H_
+
+#include "VarCheckHii.h"
+
+/**
+ Dump Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+ IN VOID *HiiPackage
+ );
+
+/**
+ Dump Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ );
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+ IN UINTN AllocationSize
+ );
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Var Check Parse Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+ @param[in] FromFv Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+ IN VOID *HiiPackage,
+ IN BOOLEAN FromFv
+ );
+
+/**
+ Var Check Parse Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ );
+
+/**
+ Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+ VOID
+ );
+
+/**
+ Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+ VOID
+ );
+
+/**
+ Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
new file mode 100644
index 000000000..f32499e34
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
@@ -0,0 +1,437 @@
+/** @file
+ Var Check Hii generation from FV.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
+
+EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
+
+#define ALL_FF_GUID \
+{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }
+
+EFI_GUID mAllFfGuid = ALL_FF_GUID;
+
+#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('V', 'D', 'R', 'I')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_GUID *DriverGuid;
+} VAR_CHECK_VFR_DRIVER_INFO;
+
+LIST_ENTRY mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE (mVfrDriverList);
+
+#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a) CR (a, VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)
+
+#define MAX_MATCH_GUID_NUM 100
+
+/**
+ Get the address by Guid.
+
+ Parse the FFS and find the GUID address.
+ There may be multiple Guids matching the searched Guid.
+
+ @param Ffs Pointer to the FFS.
+ @param Guid Guid to find.
+ @param Length The length of FFS.
+ @param Offset Pointer to pointer to the offset.
+ @param NumOfMatchingGuid The number of matching Guid.
+
+ @retval EFI_SUCCESS One or multiple Guids matching the searched Guid.
+ @retval EFI_NOT_FOUND No Guid matching the searched Guid.
+
+**/
+EFI_STATUS
+GetAddressByGuid (
+ IN VOID *Ffs,
+ IN EFI_GUID *Guid,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchingGuid
+ )
+{
+ UINTN LoopControl;
+ BOOLEAN Found;
+
+ if((Ffs == NULL) || (Guid == NULL) || (Length == 0)){
+ return EFI_NOT_FOUND;
+ }
+
+ if (NumOfMatchingGuid != NULL) {
+ *NumOfMatchingGuid = 0;
+ }
+
+ Found = FALSE;
+ for (LoopControl = 0; LoopControl < Length; LoopControl++) {
+ if (CompareGuid (Guid, (EFI_GUID *) ((UINT8 *) Ffs + LoopControl))) {
+ Found = TRUE;
+ //
+ // If NumOfMatchGuid or Offset are NULL, means user only want
+ // to check whether current FFS includes this Guid or not.
+ //
+ if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {
+ if (*NumOfMatchingGuid == 0) {
+ *Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ ASSERT (*Offset != NULL);
+ }
+ *(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);
+ (*NumOfMatchingGuid)++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+ Search the VfrBin Base address.
+
+ According to the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Ffs Pointer to the FFS.
+ @param EfiAddr Pointer to the EFI in FFS
+ @param Length The length of FFS.
+ @param Offset Pointer to pointer to the Addr (Offset).
+ @param NumOfMatchingOffset The number of Addr (Offset).
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_NOT_FOUND No VfrBin found.
+
+**/
+EFI_STATUS
+SearchVfrBinInFfs (
+ IN VOID *Ffs,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchingOffset
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ if ((Ffs == NULL) || (Offset == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+ Status = GetAddressByGuid (
+ Ffs,
+ &gVfrArrayAttractGuid,
+ Length,
+ Offset,
+ NumOfMatchingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ for (Index = 0; Index < *NumOfMatchingOffset; Index++) {
+ //
+ // Got the virOffset after the GUID
+ //
+ VirOffValue = *(UINTN *) ((UINTN) Ffs + *(*Offset + Index));
+ //
+ // Transfer the offset to the VA address. One modules may own multiple VfrBin address.
+ //
+ *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+ }
+
+ return Status;
+}
+
+/**
+ Parse FFS.
+
+ @param[in] Fv2 Pointer to Fv2 protocol.
+ @param[in] DriverGuid Pointer to driver GUID.
+
+ @return Found the driver in the FV or not.
+
+**/
+BOOLEAN
+ParseFfs (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2,
+ IN EFI_GUID *DriverGuid
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+ UINTN Size;
+ VOID *Buffer;
+ UINTN SectionSize;
+ VOID *SectionBuffer;
+ UINTN VfrBinIndex;
+ UINT8 NumberofMatchingVfrBin;
+ UINTN *VfrBinBaseAddress;
+
+ Status = Fv2->ReadFile (
+ Fv2,
+ DriverGuid,
+ NULL,
+ &Size,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ Buffer = NULL;
+ Status = Fv2->ReadSection (
+ Fv2,
+ DriverGuid,
+ EFI_SECTION_RAW,
+ 0, // Instance
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, &NumberofMatchingVfrBin);
+ if (!EFI_ERROR (Status)) {
+ SectionBuffer = NULL;
+ Status = Fv2->ReadSection (
+ Fv2,
+ DriverGuid,
+ EFI_SECTION_PE32,
+ 0, // Instance
+ &SectionBuffer,
+ &SectionSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO , "FfsNameGuid - %g\n", DriverGuid));
+ DEBUG ((DEBUG_INFO , "NumberofMatchingVfrBin - 0x%02x\n", NumberofMatchingVfrBin));
+
+ for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; VfrBinIndex++) {
+#ifdef DUMP_HII_DATA
+ DEBUG_CODE (
+ DumpHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));
+ );
+#endif
+ VarCheckParseHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);
+ }
+
+ FreePool (SectionBuffer);
+ }
+
+ InternalVarCheckFreePool (VfrBinBaseAddress);
+ }
+
+ FreePool (Buffer);
+ }
+
+ return TRUE;
+}
+
+/**
+ Parse FVs.
+
+ @param[in] ScanAll Scan all modules in all FVs or not.
+
+**/
+VOID
+ParseFv (
+ IN BOOLEAN ScanAll
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
+ VOID *Key;
+ EFI_FV_FILETYPE FileType;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN Size;
+ UINTN FfsIndex;
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+ LIST_ENTRY *VfrDriverLink;
+
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Search all FVs
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ DEBUG ((DEBUG_INFO , "FvIndex - %x\n", Index));
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *Fvb2;
+ EFI_PHYSICAL_ADDRESS FvAddress;
+ UINT64 FvSize;
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlock2ProtocolGuid,
+ (VOID **) &Fvb2
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO , "FvAddress - 0x%08x\n", FvAddress));
+ FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength;
+ DEBUG ((DEBUG_INFO , "FvSize - 0x%08x\n", FvSize));
+ }
+ );
+
+ if (ScanAll) {
+ //
+ // Need to parse all modules in all FVs.
+ //
+ Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);
+ ASSERT (Key != NULL);
+
+ for (FfsIndex = 0; ; FfsIndex++) {
+ FileType = EFI_FV_FILETYPE_ALL;
+ Status = Fv2->GetNextFile (
+ Fv2,
+ Key,
+ &FileType,
+ &NameGuid,
+ &FileAttributes,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ParseFfs (Fv2, &NameGuid);
+ }
+
+ InternalVarCheckFreePool (Key);
+ } else {
+ //
+ // Only parse drivers in the VFR drivers list.
+ //
+ VfrDriverLink = mVfrDriverList.ForwardLink;
+ while (VfrDriverLink != &mVfrDriverList) {
+ VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+ VfrDriverLink = VfrDriverLink->ForwardLink;
+ if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {
+ //
+ // Found the driver in the FV.
+ //
+ RemoveEntryList (&VfrDriverInfo->Link);
+ InternalVarCheckFreePool (VfrDriverInfo);
+ }
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+}
+
+/**
+ Create Vfr Driver List.
+
+ @param[in] DriverGuidArray Driver Guid Array
+
+**/
+VOID
+CreateVfrDriverList (
+ IN EFI_GUID *DriverGuidArray
+ )
+{
+ UINTN Index;
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+
+ for (Index = 0; !IsZeroGuid (&DriverGuidArray[Index]); Index++) {
+ DEBUG ((DEBUG_INFO , "CreateVfrDriverList: %g\n", &DriverGuidArray[Index]));
+ VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof (*VfrDriverInfo));
+ ASSERT (VfrDriverInfo != NULL);
+ VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;
+ VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];
+ InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);
+ }
+}
+
+/**
+ Destroy Vfr Driver List.
+
+**/
+VOID
+DestroyVfrDriverList (
+ VOID
+ )
+{
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+ LIST_ENTRY *VfrDriverLink;
+
+ while (mVfrDriverList.ForwardLink != &mVfrDriverList) {
+ VfrDriverLink = mVfrDriverList.ForwardLink;
+ VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+ RemoveEntryList (&VfrDriverInfo->Link);
+ InternalVarCheckFreePool (VfrDriverInfo);
+ }
+}
+
+/**
+ Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+ VOID
+ )
+{
+ EFI_GUID *DriverGuidArray;
+ BOOLEAN ScanAll;
+
+ DEBUG ((DEBUG_INFO , "VarCheckHiiGenDxeFromFv\n"));
+
+ //
+ // Get vfr driver guid array from PCD.
+ //
+ DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray);
+
+ if (IsZeroGuid (&DriverGuidArray[0])) {
+ //
+ // No VFR driver will be parsed from FVs.
+ //
+ return;
+ }
+
+ if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {
+ ScanAll = TRUE;
+ } else {
+ ScanAll = FALSE;
+ CreateVfrDriverList (DriverGuidArray);
+ }
+
+ ParseFv (ScanAll);
+
+ if (!ScanAll) {
+ DestroyVfrDriverList ();
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
new file mode 100644
index 000000000..b113ff8fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
@@ -0,0 +1,67 @@
+/** @file
+ Var Check Hii generation from Hii Database.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+/**
+ Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_PHYSICAL_ADDRESS BufferAddress;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+
+ //
+ // Locate HII Database protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Call first time with zero buffer length.
+ // Should fail with EFI_BUFFER_TOO_SMALL.
+ //
+ BufferSize = 0;
+ Buffer = NULL;
+ Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate buffer to hold the HII Database.
+ //
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (BufferSize), &BufferAddress);
+ ASSERT_EFI_ERROR (Status);
+ Buffer = (VOID *) (UINTN) BufferAddress;
+
+ //
+ // Export HII Database into the buffer.
+ //
+ Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO , "VarCheckHiiGenDxeFromHii - HII Database exported at 0x%x, size = 0x%x\n", Buffer, BufferSize));
+
+#ifdef DUMP_HII_DATA
+ DEBUG_CODE (
+ DumpHiiDatabase (Buffer, BufferSize);
+ );
+#endif
+
+ VarCheckParseHiiDatabase (Buffer, BufferSize);
+
+ gBS->FreePages (BufferAddress, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
new file mode 100644
index 000000000..9e55d20f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
@@ -0,0 +1,51 @@
+## @file
+# NULL class library to register var check HII handler.
+#
+# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckHiiLib
+ MODULE_UNI_FILE = VarCheckHiiLib.uni
+ FILE_GUID = A34FBDD0-05D3-4AF7-A720-560E91AC8CDF
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+ CONSTRUCTOR = VarCheckHiiLibNullClassConstructor
+
+[Sources]
+ VarCheckHiiLibNullClass.c
+ VarCheckHii.h
+ VarCheckHiiGenFromFv.c
+ VarCheckHiiGenFromHii.c
+ VarCheckHiiGen.c
+ VarCheckHiiGen.h
+ InternalVarCheckStructure.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ PcdLib
+ VarCheckLib
+
+[Guids]
+ gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolumeBlock2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray ## SOMETIMES_CONSUMES
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
new file mode 100644
index 000000000..a7563e9b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL class library to register var check HII handler.
+//
+// NULL class library to register var check HII handler.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL class library to register var check HII handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL class library to register var check HII handler."
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
new file mode 100644
index 000000000..0f3c0f531
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
@@ -0,0 +1,601 @@
+/** @file
+ Var Check Hii handler.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VarCheckHii.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+/**
+ Dump some hexadecimal data.
+
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the dump.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to dump.
+
+**/
+VOID
+VarCheckHiiInternalDumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mVarCheckHiiHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mVarCheckHiiHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ DEBUG ((DEBUG_INFO , "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+/**
+ Var Check Hii Question.
+
+ @param[in] HiiQuestion Pointer to Hii Question
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data to set.
+
+ @retval TRUE Check pass
+ @retval FALSE Check fail.
+
+**/
+BOOLEAN
+VarCheckHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ UINT64 OneData;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+ UINT8 Index;
+ UINT8 MaxContainers;
+ UINT8 StartBit;
+ UINT8 EndBit;
+ UINT8 TotalBits;
+ UINT16 VarOffsetByteLevel;
+ UINT8 StorageWidthByteLevel;
+
+ if (HiiQuestion->BitFieldStore) {
+ VarOffsetByteLevel = HiiQuestion->VarOffset / 8;
+ TotalBits = HiiQuestion->VarOffset % 8 + HiiQuestion->StorageWidth;
+ StorageWidthByteLevel = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
+ } else {
+ VarOffsetByteLevel = HiiQuestion->VarOffset;
+ StorageWidthByteLevel = HiiQuestion->StorageWidth;
+ }
+
+ if (((UINT32) VarOffsetByteLevel + StorageWidthByteLevel) > DataSize) {
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x)) > Size(0x%x)\n", VarOffsetByteLevel, StorageWidthByteLevel, DataSize));
+ return FALSE;
+ }
+
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + VarOffsetByteLevel, StorageWidthByteLevel);
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // Get the value from the bit field.
+ //
+ StartBit = HiiQuestion->VarOffset % 8;
+ EndBit = StartBit + HiiQuestion->StorageWidth - 1;
+ OneData = BitFieldRead64 (OneData, StartBit, EndBit);
+ }
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+ while ((UINTN) Ptr < (UINTN) HiiQuestion + HiiQuestion->Length) {
+ OneValue = 0;
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For OneOf stored in bit field, the value of options are saved as UINT32 type.
+ //
+ CopyMem (&OneValue, Ptr, sizeof (UINT32));
+ } else {
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ }
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ if (HiiQuestion->BitFieldStore) {
+ Ptr += sizeof (UINT32);
+ } else {
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ }
+ if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: OneOf mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ if ((OneData != 0) && (OneData != 1)) {
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: CheckBox mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
+ //
+ CopyMem (&Minimum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ CopyMem (&Maximum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ } else {
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ }
+
+ //
+ // No need to check Step, because it is ONLY for UI.
+ //
+ if ((OneData < Minimum) || (OneData > Maximum)) {
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: Numeric mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers;
+ if (((UINT32) HiiQuestion->VarOffset + HiiQuestion->StorageWidth * MaxContainers) > DataSize) {
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize));
+ return FALSE;
+ }
+ for (Index = 0; Index < MaxContainers; Index++) {
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset + HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth);
+ if (OneData == 0) {
+ //
+ // The value of 0 is used to determine if a particular "slot" in the array is empty.
+ //
+ continue;
+ }
+
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((DEBUG_INFO , "VarCheckHiiQuestion fail: OrderedList mismatch\n"));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->StorageWidth * MaxContainers, (UINT8 *) Data + HiiQuestion->VarOffset););
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return TRUE;
+}
+
+VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin = NULL;
+UINTN mVarCheckHiiBinSize = 0;
+
+/**
+ SetVariable check handler HII.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerHii (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ if (mVarCheckHiiBin == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckHiiBin);
+ while ((UINTN) HiiVariable < ((UINTN) mVarCheckHiiBin + mVarCheckHiiBinSize)) {
+ if ((StrCmp ((CHAR16 *) (HiiVariable + 1), VariableName) == 0) &&
+ (CompareGuid (&HiiVariable->Guid, VendorGuid))) {
+ //
+ // Found the Hii Variable that could be used to do check.
+ //
+ DEBUG ((DEBUG_INFO , "VarCheckHiiVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+ if (HiiVariable->Attributes != Attributes) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Attributes - 0x%08x\n", HiiVariable->Attributes));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (DataSize == 0) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 0 !\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (HiiVariable->Size != DataSize) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", HiiVariable->Size));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Do the check.
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) {
+ if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length));
+ }
+
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length));
+ }
+
+ // Not found, so pass.
+ return EFI_SUCCESS;
+}
+
+#ifdef DUMP_VAR_CHECK_HII
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mHiiOpCodeStringTable[] = {
+ {EFI_IFR_VARSTORE_EFI_OP, "EfiVarStore"},
+ {EFI_IFR_ONE_OF_OP, "OneOf"},
+ {EFI_IFR_CHECKBOX_OP, "CheckBox"},
+ {EFI_IFR_NUMERIC_OP, "Numeric"},
+ {EFI_IFR_ORDERED_LIST_OP, "OrderedList"},
+};
+
+/**
+ HII opcode to string.
+
+ @param[in] HiiOpCode Hii OpCode.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+HiiOpCodeToStr (
+ IN UINT8 HiiOpCode
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < ARRAY_SIZE (mHiiOpCodeStringTable); Index++) {
+ if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) {
+ return mHiiOpCodeStringTable[Index].HiiOpCodeStr;
+ }
+ }
+
+ return "<UnknownHiiOpCode>";
+}
+
+/**
+ Dump Hii Question.
+
+ @param[in] HiiQuestion Pointer to Hii Question.
+
+**/
+VOID
+DumpHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion
+ )
+{
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ DEBUG ((DEBUG_INFO, " VAR_CHECK_HII_QUESTION_HEADER\n"));
+ DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a) (%a)\n", HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode), (HiiQuestion->BitFieldStore? "bit level": "byte level")));
+ DEBUG ((DEBUG_INFO, " Length - 0x%02x\n", HiiQuestion->Length));
+ DEBUG ((DEBUG_INFO, " VarOffset - 0x%04x (%a)\n", HiiQuestion->VarOffset, (HiiQuestion->BitFieldStore? "bit level": "byte level")));
+ DEBUG ((DEBUG_INFO, " StorageWidth - 0x%02x (%a)\n", HiiQuestion->StorageWidth, (HiiQuestion->BitFieldStore? "bit level": "byte level")));
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For OneOf stored in bit field, the value of options are saved as UINT32 type.
+ //
+ CopyMem (&OneValue, Ptr, sizeof (UINT32));
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ } else {
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ if (HiiQuestion->BitFieldStore) {
+ Ptr += sizeof (UINT32);
+ } else {
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+ if(HiiQuestion->BitFieldStore) {
+ //
+ // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
+ //
+ CopyMem (&Minimum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ CopyMem (&Maximum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
+ } else {
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%02x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%02x\n", Maximum));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%04x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%04x\n", Maximum));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%016lx\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%016lx\n", Maximum));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((DEBUG_INFO, " MaxContainers - 0x%02x\n", ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers));
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Dump Hii Variable.
+
+ @param[in] HiiVariable Pointer to Hii Variable.
+
+**/
+VOID
+DumpHiiVariable (
+ IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ DEBUG ((DEBUG_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n"));
+ DEBUG ((DEBUG_INFO, " Revision - 0x%04x\n", HiiVariable->Revision));
+ DEBUG ((DEBUG_INFO, " HeaderLength - 0x%04x\n", HiiVariable->HeaderLength));
+ DEBUG ((DEBUG_INFO, " Length - 0x%08x\n", HiiVariable->Length));
+ DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a)\n", HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode)));
+ DEBUG ((DEBUG_INFO, " Size - 0x%04x\n", HiiVariable->Size));
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%08x\n", HiiVariable->Attributes));
+ DEBUG ((DEBUG_INFO, " Guid - %g\n", &HiiVariable->Guid));
+ DEBUG ((DEBUG_INFO, " Name - %s\n", HiiVariable + 1));
+
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) {
+ //
+ // Dump Hii Question related to the Hii Variable.
+ //
+ DumpHiiQuestion (HiiQuestion);
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length));
+ }
+}
+
+/**
+ Dump Var Check HII.
+
+ @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
+ @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+ IN VOID *VarCheckHiiBin,
+ IN UINTN VarCheckHiiBinSize
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+
+ DEBUG ((DEBUG_INFO, "DumpVarCheckHii\n"));
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckHiiBin);
+ while ((UINTN) HiiVariable < ((UINTN) VarCheckHiiBin + VarCheckHiiBinSize)) {
+ DumpHiiVariable (HiiVariable);
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length));
+ }
+}
+#endif
+
+/**
+ Constructor function of VarCheckHiiLib to register var check HII handler.
+
+ @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 constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibNullClassConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen);
+ VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckHiiBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c
new file mode 100644
index 000000000..470d78244
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c
@@ -0,0 +1,664 @@
+/** @file
+ Implementation functions and structures for var check services.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HardwareErrorVariable.h>
+
+BOOLEAN mVarCheckLibEndOfDxe = FALSE;
+
+#define VAR_CHECK_TABLE_SIZE 0x8
+
+UINTN mVarCheckLibEndOfDxeCallbackCount = 0;
+UINTN mVarCheckLibEndOfDxeCallbackMaxCount = 0;
+VAR_CHECK_END_OF_DXE_CALLBACK *mVarCheckLibEndOfDxeCallback = NULL;
+
+UINTN mVarCheckLibAddressPointerCount = 0;
+UINTN mVarCheckLibAddressPointerMaxCount = 0;
+VOID ***mVarCheckLibAddressPointer = NULL;
+
+UINTN mNumberOfVarCheckHandler = 0;
+UINTN mMaxNumberOfVarCheckHandler = 0;
+VAR_CHECK_SET_VARIABLE_CHECK_HANDLER *mVarCheckHandlerTable = NULL;
+
+typedef struct {
+ EFI_GUID Guid;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+ //CHAR16 *Name;
+} VAR_CHECK_VARIABLE_ENTRY;
+
+UINTN mNumberOfVarCheckVariable = 0;
+UINTN mMaxNumberOfVarCheckVariable = 0;
+VARIABLE_ENTRY_PROPERTY **mVarCheckVariableTable = NULL;
+
+//
+// Handle variables with wildcard name specially.
+//
+VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = {
+ {
+ &gEfiGlobalVariableGuid,
+ L"Boot####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"Driver####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"SysPrep####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"Key####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"PlatformRecovery####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiHardwareErrorVariableGuid,
+ L"HwErrRec####",
+ {
+ 0
+ },
+ },
+};
+
+/**
+ Check if a Unicode character is an upper case hexadecimal character.
+
+ This function checks if a Unicode character is an upper case
+ hexadecimal character. The valid upper case hexadecimal character is
+ L'0' to L'9', or L'A' to L'F'.
+
+
+ @param[in] Char The character to check against.
+
+ @retval TRUE If the Char is an upper case hexadecmial character.
+ @retval FALSE If the Char is not an upper case hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+VarCheckInternalIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F'));
+}
+
+/**
+ Variable property get with wildcard name.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable vendor GUID.
+ @param[in] WildcardMatch Try wildcard match or not.
+
+ @return Pointer to variable property.
+
+**/
+VAR_CHECK_VARIABLE_PROPERTY *
+VariablePropertyGetWithWildcardName (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN WildcardMatch
+ )
+{
+ UINTN Index;
+ UINTN NameLength;
+
+ NameLength = StrLen (VariableName) - 4;
+ for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) {
+ if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)){
+ if (WildcardMatch) {
+ if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) &&
+ (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
+ return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
+ }
+ }
+ if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) {
+ return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Variable property get function.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] WildcardMatch Try wildcard match or not.
+
+ @return Pointer to the property of variable specified by the Name and Guid.
+
+**/
+VAR_CHECK_VARIABLE_PROPERTY *
+VariablePropertyGetFunction (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN BOOLEAN WildcardMatch
+ )
+{
+ UINTN Index;
+ VAR_CHECK_VARIABLE_ENTRY *Entry;
+ CHAR16 *VariableName;
+
+ for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
+ Entry = (VAR_CHECK_VARIABLE_ENTRY *) mVarCheckVariableTable[Index];
+ VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
+ if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) {
+ return &Entry->VariableProperty;
+ }
+ }
+
+ return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch);
+}
+
+/**
+ Var check add table entry.
+
+ @param[in, out] Table Pointer to table buffer.
+ @param[in, out] MaxNumber Pointer to maximum number of entry in the table.
+ @param[in, out] CurrentNumber Pointer to current number of entry in the table.
+ @param[in] Entry Entry will be added to the table.
+
+ @retval EFI_SUCCESS Reallocate memory successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
+
+**/
+EFI_STATUS
+VarCheckAddTableEntry (
+ IN OUT UINTN **Table,
+ IN OUT UINTN *MaxNumber,
+ IN OUT UINTN *CurrentNumber,
+ IN UINTN Entry
+ )
+{
+ UINTN *TempTable;
+
+ //
+ // Check whether the table is enough to store new entry.
+ //
+ if (*CurrentNumber == *MaxNumber) {
+ //
+ // Reallocate memory for the table.
+ //
+ TempTable = ReallocateRuntimePool (
+ *MaxNumber * sizeof (UINTN),
+ (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN),
+ *Table
+ );
+
+ //
+ // No enough resource to allocate.
+ //
+ if (TempTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Table = TempTable;
+ //
+ // Increase max number.
+ //
+ *MaxNumber += VAR_CHECK_TABLE_SIZE;
+ }
+
+ //
+ // Add entry to the table.
+ //
+ (*Table)[*CurrentNumber] = Entry;
+ (*CurrentNumber)++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register END_OF_DXE callback.
+ The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] Callback END_OF_DXE callback.
+
+ @retval EFI_SUCCESS The callback was registered successfully.
+ @retval EFI_INVALID_PARAMETER Callback is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterEndOfDxeCallback (
+ IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
+ )
+{
+ EFI_STATUS Status;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry (
+ (UINTN **) &mVarCheckLibEndOfDxeCallback,
+ &mVarCheckLibEndOfDxeCallbackMaxCount,
+ &mVarCheckLibEndOfDxeCallbackCount,
+ (UINTN) Callback
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status));
+
+ return Status;
+}
+
+/**
+ Var check initialize at END_OF_DXE.
+
+ This function needs to be called at END_OF_DXE.
+ Address pointers may be returned,
+ and caller needs to ConvertPointer() for the pointers.
+
+ @param[in, out] AddressPointerCount Output pointer to address pointer count.
+
+ @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
+
+**/
+VOID ***
+EFIAPI
+VarCheckLibInitializeAtEndOfDxe (
+ IN OUT UINTN *AddressPointerCount OPTIONAL
+ )
+{
+ VOID *TempTable;
+ UINTN TotalCount;
+ UINTN Index;
+
+ for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) {
+ //
+ // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
+ //
+ mVarCheckLibEndOfDxeCallback[Index] ();
+ }
+ if (mVarCheckLibEndOfDxeCallback != NULL) {
+ //
+ // Free the callback buffer.
+ //
+ mVarCheckLibEndOfDxeCallbackCount = 0;
+ mVarCheckLibEndOfDxeCallbackMaxCount = 0;
+ FreePool ((VOID *) mVarCheckLibEndOfDxeCallback);
+ mVarCheckLibEndOfDxeCallback = NULL;
+ }
+
+ mVarCheckLibEndOfDxe = TRUE;
+
+ if (AddressPointerCount == NULL) {
+ if (mVarCheckLibAddressPointer != NULL) {
+ //
+ // Free the address pointer buffer.
+ //
+ mVarCheckLibAddressPointerCount = 0;
+ mVarCheckLibAddressPointerMaxCount = 0;
+ FreePool ((VOID *) mVarCheckLibAddressPointer);
+ mVarCheckLibAddressPointer = NULL;
+ }
+ return NULL;
+ }
+
+ //
+ // Get the total count needed.
+ // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
+ //
+ TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1);
+ TempTable = ReallocateRuntimePool (
+ mVarCheckLibAddressPointerMaxCount * sizeof (VOID **),
+ TotalCount * sizeof (VOID **),
+ (VOID *) mVarCheckLibAddressPointer
+ );
+
+ if (TempTable != NULL) {
+ mVarCheckLibAddressPointer = (VOID ***) TempTable;
+
+ //
+ // Cover VarCheckHandler and the entries.
+ //
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable;
+ for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable[Index];
+ }
+
+ //
+ // Cover VarCheckVariable and the entries.
+ //
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable;
+ for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable[Index];
+ }
+
+ ASSERT (mVarCheckLibAddressPointerCount == TotalCount);
+ mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount;
+ }
+
+ *AddressPointerCount = mVarCheckLibAddressPointerCount;
+ return mVarCheckLibAddressPointer;
+}
+
+/**
+ Register address pointer.
+ The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] AddressPointer Address pointer.
+
+ @retval EFI_SUCCESS The address pointer was registered successfully.
+ @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterAddressPointer (
+ IN VOID **AddressPointer
+ )
+{
+ EFI_STATUS Status;
+
+ if (AddressPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckLibAddressPointer,
+ &mVarCheckLibAddressPointerMaxCount,
+ &mVarCheckLibAddressPointerCount,
+ (UINTN) AddressPointer
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status));
+
+ return Status;
+}
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ EFI_STATUS Status;
+
+ if (Handler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckHandlerTable,
+ &mMaxNumberOfVarCheckHandler,
+ &mNumberOfVarCheckHandler,
+ (UINTN) Handler
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status));
+
+ return Status;
+}
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_ENTRY *Entry;
+ CHAR16 *VariableName;
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the pointer of property data for set.
+ //
+ Property = VariablePropertyGetFunction (Name, Guid, FALSE);
+ if (Property != NULL) {
+ CopyMem (Property, VariableProperty, sizeof (*VariableProperty));
+ } else {
+ Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
+ StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name);
+ CopyGuid (&Entry->Guid, Guid);
+ CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty));
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckVariableTable,
+ &mMaxNumberOfVarCheckVariable,
+ &mNumberOfVarCheckVariable,
+ (UINTN) Entry
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Entry);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Property = VariablePropertyGetFunction (Name, Guid, TRUE);
+ //
+ // Also check the property revision before using the property data.
+ // There is no property set to this variable(wildcard name)
+ // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
+ //
+ if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
+ CopyMem (VariableProperty, Property, sizeof (*VariableProperty));
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ SetVariable check.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @param[in] RequestSource Request source.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
+ DataSize and Data value was supplied.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval Others The other return status from check handler.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibSetVariableCheck (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data,
+ IN VAR_CHECK_REQUEST_SOURCE RequestSource
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (!mVarCheckLibEndOfDxe) {
+ //
+ // Only do check after End Of Dxe.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE);
+ //
+ // Also check the property revision before using the property data.
+ // There is no property set to this variable(wildcard name)
+ // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
+ //
+ if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
+ if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) {
+ DEBUG ((EFI_D_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName));
+ return EFI_WRITE_PROTECTED;
+ }
+ if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) {
+ //
+ // Not to delete variable.
+ //
+ if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) {
+ DEBUG ((EFI_D_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataSize != 0) {
+ if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) {
+ DEBUG ((EFI_D_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ }
+
+ for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
+ Status = mVarCheckHandlerTable[Index] (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName));
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
new file mode 100644
index 000000000..c95c983f5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Provides variable check services and database management.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckLib
+ MODULE_UNI_FILE = VarCheckLib.uni
+ FILE_GUID = 63E12D08-0C5D-47F8-95E4-09F89D7506C5
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VarCheckLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER MM_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ VarCheckLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"Boot####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Driver####"
+ ## SOMETIMES_CONSUMES ## Variable:L"SysPrep####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Key####"
+ gEfiGlobalVariableGuid
+ gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####"
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni
new file mode 100644
index 000000000..9744867a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Provides variable check services and database management.
+//
+// Provides variable check services and database management.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides variable check services and database management"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides variable check services and database management."
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
new file mode 100644
index 000000000..9f2d1abad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
@@ -0,0 +1,58 @@
+## @file
+# NULL class library to register var check PCD handler.
+#
+# In platform *.fdf, the example build rule for the driver this library linked to.
+# [Rule.Common.DXE_RUNTIME_DRIVER.VARCHECKPCD]
+# FILE DRIVER = $(NAMED_GUID) {
+# RAW BIN $(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/PcdVarCheck.bin
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+#
+# or
+#
+# [Rule.Common.DXE_SMM_DRIVER.VARCHECKPCD]
+# FILE SMM = $(NAMED_GUID) {
+# RAW BIN $(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/PcdVarCheck.bin
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+#
+# In platform *.dsc, also need add one line below to enable PcdVarCheck.bin generation by BaseTools.
+# PCD_VAR_CHECK_GENERATION = TRUE
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckPcdLib
+ MODULE_UNI_FILE = VarCheckPcdLib.uni
+ FILE_GUID = D4FA5311-5F1F-4B1E-9AC3-90C4DFC029F1
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+ CONSTRUCTOR = VarCheckPcdLibNullClassConstructor
+
+[Sources]
+ VarCheckPcdLibNullClass.c
+ VarCheckPcdStructure.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ DxeServicesLib
+ MemoryAllocationLib
+ VarCheckLib
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni
new file mode 100644
index 000000000..a2cdd8dac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL class library to register var check PCD handler.
+//
+// NULL class library to register var check PCD handler.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL class library to register var check PCD handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL class library to register var check PCD handler."
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c
new file mode 100644
index 000000000..9a3f9187c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c
@@ -0,0 +1,472 @@
+/** @file
+ Var Check PCD handler.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesLib.h>
+
+#include "VarCheckPcdStructure.h"
+
+//#define DUMP_VAR_CHECK_PCD
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckPcdHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+/**
+ Dump some hexadecimal data.
+
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the dump.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to dump.
+
+**/
+VOID
+VarCheckPcdInternalDumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mVarCheckPcdHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mVarCheckPcdHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+/**
+ Var Check Pcd ValidData.
+
+ @param[in] PcdValidData Pointer to Pcd ValidData
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data to set.
+
+ @retval TRUE Check pass
+ @retval FALSE Check fail.
+
+**/
+BOOLEAN
+VarCheckPcdValidData (
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ UINT64 OneData;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + PcdValidData->VarOffset, PcdValidData->StorageWidth);
+
+ switch (PcdValidData->Type) {
+ case VarCheckPcdValidList:
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr += PcdValidData->StorageWidth;
+ }
+ if ((UINTN) Ptr >= ((UINTN) PcdValidData + PcdValidData->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidList mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
+ return FALSE;
+ }
+ break;
+
+ case VarCheckPcdValidRange:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+
+ if ((OneData >= Minimum) && (OneData <= Maximum)) {
+ return TRUE;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidRange mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
+ return FALSE;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return TRUE;
+}
+
+VAR_CHECK_PCD_VARIABLE_HEADER *mVarCheckPcdBin = NULL;
+UINTN mVarCheckPcdBinSize = 0;
+
+/**
+ SetVariable check handler PCD.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerPcd (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
+
+ if (mVarCheckPcdBin == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckPcdBin);
+ while ((UINTN) PcdVariable < ((UINTN) mVarCheckPcdBin + mVarCheckPcdBinSize)) {
+ if ((StrCmp ((CHAR16 *) (PcdVariable + 1), VariableName) == 0) &&
+ (CompareGuid (&PcdVariable->Guid, VendorGuid))) {
+ //
+ // Found the Pcd Variable that could be used to do check.
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+ if ((PcdVariable->Attributes != 0) && PcdVariable->Attributes != Attributes) {
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable fail for Attributes - 0x%08x\n", PcdVariable->Attributes));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (DataSize == 0) {
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - CHECK PASS with DataSize == 0 !\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do the check.
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
+ if (((UINTN) PcdValidData->VarOffset + PcdValidData->StorageWidth) <= DataSize) {
+ if (!VarCheckPcdValidData (PcdValidData, Data, DataSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
+ }
+
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - ALL CHECK PASS!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
+ }
+
+ // Not found, so pass.
+ return EFI_SUCCESS;
+}
+
+#ifdef DUMP_VAR_CHECK_PCD
+/**
+ Dump Pcd ValidData.
+
+ @param[in] PcdValidData Pointer to Pcd ValidData.
+
+**/
+VOID
+DumpPcdValidData (
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData
+ )
+{
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ DEBUG ((EFI_D_INFO, " VAR_CHECK_PCD_VALID_DATA_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdValidData->Type));
+ DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", PcdValidData->Length));
+ DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", PcdValidData->VarOffset));
+ DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", PcdValidData->StorageWidth));
+
+ switch (PcdValidData->Type) {
+ case VarCheckPcdValidList:
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
+ while ((UINTN) Ptr < ((UINTN) PcdValidData + PcdValidData->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
+ switch (PcdValidData->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Ptr += PcdValidData->StorageWidth;
+ }
+ break;
+
+ case VarCheckPcdValidRange:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+
+ switch (PcdValidData->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Dump Pcd Variable.
+
+ @param[in] PcdVariable Pointer to Pcd Variable.
+
+**/
+VOID
+DumpPcdVariable (
+ IN VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable
+ )
+{
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
+
+ DEBUG ((EFI_D_INFO, "VAR_CHECK_PCD_VARIABLE_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", PcdVariable->Revision));
+ DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", PcdVariable->HeaderLength));
+ DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", PcdVariable->Length));
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdVariable->Type));
+ DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", PcdVariable->Attributes));
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &PcdVariable->Guid));
+ DEBUG ((EFI_D_INFO, " Name - %s\n", PcdVariable + 1));
+
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
+ //
+ // Dump Pcd ValidData related to the Pcd Variable.
+ //
+ DumpPcdValidData (PcdValidData);
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
+ }
+}
+
+/**
+ Dump Var Check PCD.
+
+ @param[in] VarCheckPcdBin Pointer to VarCheckPcdBin.
+ @param[in] VarCheckPcdBinSize VarCheckPcdBin size.
+
+**/
+VOID
+DumpVarCheckPcd (
+ IN VOID *VarCheckPcdBin,
+ IN UINTN VarCheckPcdBinSize
+ )
+{
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
+
+ DEBUG ((EFI_D_INFO, "DumpVarCheckPcd\n"));
+
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckPcdBin);
+ while ((UINTN) PcdVariable < ((UINTN) VarCheckPcdBin + VarCheckPcdBinSize)) {
+ DumpPcdVariable (PcdVariable);
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
+ }
+}
+#endif
+
+/**
+ Locate VarCheckPcdBin.
+
+**/
+VOID
+EFIAPI
+LocateVarCheckPcdBin (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_PCD_VARIABLE_HEADER *VarCheckPcdBin;
+ UINTN VarCheckPcdBinSize;
+
+ //
+ // Search the VarCheckPcdBin from the first RAW section of current FFS.
+ //
+ Status = GetSectionFromFfs (
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **) &VarCheckPcdBin,
+ &VarCheckPcdBinSize
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
+ // in SetVariable check handler.
+ //
+ mVarCheckPcdBin = AllocateRuntimeCopyPool (VarCheckPcdBinSize, VarCheckPcdBin);
+ ASSERT (mVarCheckPcdBin != NULL);
+ //
+ // Make sure the allocated buffer for VarCheckPcdBin at required alignment.
+ //
+ ASSERT ((((UINTN) mVarCheckPcdBin) & (HEADER_ALIGNMENT - 1)) == 0);
+ mVarCheckPcdBinSize = VarCheckPcdBinSize;
+ FreePool (VarCheckPcdBin);
+
+ DEBUG ((EFI_D_INFO, "VarCheckPcdBin - at 0x%x size = 0x%x\n", mVarCheckPcdBin, mVarCheckPcdBinSize));
+
+#ifdef DUMP_VAR_CHECK_PCD
+ DEBUG_CODE (
+ DumpVarCheckPcd (mVarCheckPcdBin, mVarCheckPcdBinSize);
+ );
+#endif
+ } else {
+ DEBUG ((EFI_D_INFO, "[VarCheckPcd] No VarCheckPcdBin found at the first RAW section\n"));
+ }
+}
+
+/**
+ Constructor function of VarCheckPcdLib to register var check PCD handler.
+
+ @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 constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckPcdLibNullClassConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ LocateVarCheckPcdBin ();
+ VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckPcdBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerPcd);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h
new file mode 100644
index 000000000..324dcd8f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h
@@ -0,0 +1,70 @@
+/** @file
+ Internal structure for Var Check Pcd.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VAR_CHECK_STRUCTURE_H_
+#define _VAR_CHECK_STRUCTURE_H_
+
+//
+// Alignment for PCD Variable and check data header.
+//
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+#pragma pack (1)
+
+#define VAR_CHECK_PCD_REVISION 0x0001
+
+typedef enum {
+ VarCheckPcdVariableHeader,
+ VarCheckPcdValidList,
+ VarCheckPcdValidRange,
+ VarCheckPcdCheckTypeMax,
+} VAR_CHECK_PCD_CHECK_TYPE;
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 HeaderLength;
+ UINT32 Length; // Length include this header
+ UINT8 Type;
+ UINT8 Reserved[3];
+ UINT32 Attributes;
+ EFI_GUID Guid;
+//CHAR16 Name[];
+} VAR_CHECK_PCD_VARIABLE_HEADER;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+} VAR_CHECK_PCD_VALID_DATA_HEADER;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_PCD_VALID_LIST;
+
+//typedef struct {
+// UINTx Minimum; // x = UINT8/UINT16/UINT32/UINT64
+// UINTx Maximum; // x = UINT8/UINT16/UINT32/UINT64
+//} VAR_CHECK_PCD_VALID_RANGE_DATA;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+// VAR_CHECK_PCD_VALID_RANGE_DATA ValidRange[];
+} VAR_CHECK_PCD_VALID_RANGE;
+
+#pragma pack ()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
new file mode 100644
index 000000000..47add89e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
@@ -0,0 +1,81 @@
+## @file
+# NULL class library to register var check handler and variable property set for UEFI defined variables.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckUefiLib
+ MODULE_UNI_FILE = VarCheckUefiLib.uni
+ FILE_GUID = AC24A4C7-F845-4665-90E5-6431D6E28DC0
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER MM_STANDALONE
+ CONSTRUCTOR = VarCheckUefiLibNullClassConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ VarCheckUefiLibNullClass.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ VarCheckLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"LangCodes"
+ ## SOMETIMES_CONSUMES ## Variable:L"Lang"
+ ## SOMETIMES_CONSUMES ## Variable:L"Timeout"
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLangCodes"
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut"
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConInDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootNext"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootCurrent"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOptionSupport"
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"SysPrepOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"HwErrRecSupport"
+ ## SOMETIMES_CONSUMES ## Variable:L"SetupMode"
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"SignatureSupport"
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEKDefault"
+ ## SOMETIMES_CONSUMES ## Variable:L"PKDefault"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbDefault"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbxDefault"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbtDefault"
+ ## SOMETIMES_CONSUMES ## Variable:L"OsIndicationsSupported"
+ ## SOMETIMES_CONSUMES ## Variable:L"OsIndications"
+ ## SOMETIMES_CONSUMES ## Variable:L"VendorKeys"
+ ## SOMETIMES_CONSUMES ## Variable:L"Boot####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Driver####"
+ ## SOMETIMES_CONSUMES ## Variable:L"SysPrep####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Key####"
+ gEfiGlobalVariableGuid
+ ## SOMETIMES_CONSUMES ## Variable:L"DB"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBX"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBT"
+ gEfiImageSecurityDatabaseGuid
+ gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####"
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni
new file mode 100644
index 000000000..d67790582
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// NULL library class to register var check handler and variable property set for UEFI defined variables.
+//
+// NULL library class to register var check handler and variable property set for UEFI defined variables.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL library class to register var check handler and variable property set for UEFI defined variables"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL library class to register var check handler and variable property set for UEFI defined variables."
+
diff --git a/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c
new file mode 100644
index 000000000..e3bf04a54
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c
@@ -0,0 +1,933 @@
+/** @file
+ Implementation functions and structures for var check uefi library.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/HardwareErrorVariable.h>
+#include <Guid/ImageAuthentication.h>
+
+typedef
+EFI_STATUS
+(EFIAPI *INTERNAL_VAR_CHECK_FUNCTION) (
+ IN VAR_CHECK_VARIABLE_PROPERTY *Propery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+typedef struct {
+ CHAR16 *Name;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+ INTERNAL_VAR_CHECK_FUNCTION CheckFunction;
+} UEFI_DEFINED_VARIABLE_ENTRY;
+
+/**
+ Internal check for load option.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid load option.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckLoadOption (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ UINT16 FilePathListLength;
+ CHAR16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathList;
+
+ FilePathListLength = *((UINT16 *) ((UINTN) Data + sizeof (UINT32)));
+
+ //
+ // Check Description
+ //
+ Description = (CHAR16 *) ((UINTN) Data + sizeof (UINT32) + sizeof (UINT16));
+ while (Description < (CHAR16 *) ((UINTN) Data + DataSize)) {
+ if (*Description == L'\0') {
+ break;
+ }
+ Description++;
+ }
+ if ((UINTN) Description >= ((UINTN) Data + DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Description++;
+
+ //
+ // Check FilePathList
+ //
+ FilePathList = (EFI_DEVICE_PATH_PROTOCOL *) Description;
+ if ((UINTN) FilePathList > (MAX_ADDRESS - FilePathListLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (((UINTN) FilePathList + FilePathListLength) > ((UINTN) Data + DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FilePathListLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsDevicePathValid (FilePathList, FilePathListLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for key option.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid key option.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckKeyOption (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if (((DataSize - sizeof (EFI_KEY_OPTION)) % sizeof (EFI_INPUT_KEY)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for device path.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid device path.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckDevicePath (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if (!IsDevicePathValid ((EFI_DEVICE_PATH_PROTOCOL *) Data, DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for ASCII string.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a Null-terminated ASCII string.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckAsciiString (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ CHAR8 *String;
+ UINTN Index;
+
+ String = (CHAR8 *) Data;
+ if (String[DataSize - 1] == '\0') {
+ return EFI_SUCCESS;
+ } else {
+ for (Index = 1; Index < DataSize && (String[DataSize - 1 - Index] != '\0'); Index++);
+ if (Index == DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for size array.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The DataSize is not size array.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckSizeArray (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if ((DataSize % VariablePropery->MinSize) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+//
+// To prevent name collisions with possible future globally defined variables,
+// other internal firmware data variables that are not defined here must be
+// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
+// any other GUID defined by the UEFI Specification. Implementations must
+// only permit the creation of variables with a UEFI Specification-defined
+// VendorGuid when these variables are documented in the UEFI Specification.
+//
+UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList[] = {
+ {
+ EFI_LANG_CODES_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_LANG_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_TIME_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_PLATFORM_LANG_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_CON_IN_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_ERR_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_IN_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_OUT_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_ERR_OUT_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_BOOT_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_BOOT_CURRENT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT32),
+ sizeof (UINT32)
+ },
+ NULL
+ },
+ {
+ EFI_DRIVER_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_SETUP_MODE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+ {
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_PLATFORM_KEY_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_SIGNATURE_SUPPORT_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_GUID),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_SECURE_BOOT_MODE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+ {
+ EFI_KEK_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_PK_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DB_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DBX_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DBT_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT64),
+ sizeof (UINT64)
+ },
+ NULL
+ },
+ {
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT64),
+ sizeof (UINT64)
+ },
+ NULL
+ },
+ {
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+};
+
+UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList2[] = {
+ {
+ L"Boot####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"Driver####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"SysPrep####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"Key####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_KEY_OPTION),
+ sizeof (EFI_KEY_OPTION) + 3 * sizeof (EFI_INPUT_KEY)
+ },
+ InternalVarCheckKeyOption
+ },
+ {
+ L"PlatformRecovery####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+};
+
+//
+// EFI_IMAGE_SECURITY_DATABASE_GUID
+//
+UEFI_DEFINED_VARIABLE_ENTRY mImageSecurityVariableList[] = {
+ {
+ EFI_IMAGE_SECURITY_DATABASE,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_IMAGE_SECURITY_DATABASE1,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_IMAGE_SECURITY_DATABASE2,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+};
+
+//
+// EFI_HARDWARE_ERROR_VARIABLE
+//
+UEFI_DEFINED_VARIABLE_ENTRY mHwErrRecVariable = {
+ L"HwErrRec####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_HR,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+};
+
+EFI_GUID *mUefiDefinedGuid[] = {
+ &gEfiGlobalVariableGuid,
+ &gEfiImageSecurityDatabaseGuid,
+ &gEfiHardwareErrorVariableGuid
+};
+
+/**
+ Check if a Unicode character is an upper case hexadecimal character.
+
+ This function checks if a Unicode character is an upper case
+ hexadecimal character. The valid upper case hexadecimal character is
+ L'0' to L'9', or L'A' to L'F'.
+
+
+ @param[in] Char The character to check against.
+
+ @retval TRUE If the Char is an upper case hexadecmial character.
+ @retval FALSE If the Char is not an upper case hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+VarCheckUefiIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F'));
+}
+
+/**
+
+ This code checks if variable is hardware error record variable or not.
+
+ According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
+ and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+
+ @retval TRUE Variable is hardware error record variable.
+ @retval FALSE Variable is not hardware error record variable.
+
+**/
+BOOLEAN
+EFIAPI
+IsHwErrRecVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||
+ (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||
+ (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0x8]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0x9]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0xA]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0xB])) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get UEFI defined var check function.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable vendor GUID.
+ @param[out] VariableProperty Pointer to variable property.
+
+ @return Internal var check function, NULL if no specific check function.
+
+**/
+INTERNAL_VAR_CHECK_FUNCTION
+GetUefiDefinedVarCheckFunction (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY **VariableProperty
+ )
+{
+ UINTN Index;
+ UINTN NameLength;
+
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
+ //
+ // Try list 1, exactly match.
+ //
+ for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {
+ if (StrCmp (mGlobalVariableList[Index].Name, VariableName) == 0) {
+ *VariableProperty = &(mGlobalVariableList[Index].VariableProperty);
+ return mGlobalVariableList[Index].CheckFunction;
+ }
+ }
+
+ //
+ // Try list 2.
+ //
+ NameLength = StrLen (VariableName) - 4;
+ for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {
+ if ((StrLen (VariableName) == StrLen (mGlobalVariableList2[Index].Name)) &&
+ (StrnCmp (VariableName, mGlobalVariableList2[Index].Name, NameLength) == 0) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
+ *VariableProperty = &(mGlobalVariableList2[Index].VariableProperty);
+ return mGlobalVariableList2[Index].CheckFunction;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ SetVariable check handler UEFI defined.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
+ DataSize and Data value was supplied.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerUefiDefined (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+ VAR_CHECK_VARIABLE_PROPERTY *VarCheckProperty;
+ INTERNAL_VAR_CHECK_FUNCTION VarCheckFunction;
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (!IsHwErrRecVariable (VariableName, VendorGuid)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ for (Index = 0; Index < sizeof (mUefiDefinedGuid)/sizeof (mUefiDefinedGuid[0]); Index++) {
+ if (CompareGuid (VendorGuid, mUefiDefinedGuid[Index])) {
+ if (VarCheckLibVariablePropertyGet (VariableName, VendorGuid, &Property) == EFI_NOT_FOUND) {
+ //
+ // To prevent name collisions with possible future globally defined variables,
+ // other internal firmware data variables that are not defined here must be
+ // saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
+ // any other GUID defined by the UEFI Specification. Implementations must
+ // only permit the creation of variables with a UEFI Specification-defined
+ // VendorGuid when these variables are documented in the UEFI Specification.
+ //
+ DEBUG ((EFI_D_INFO, "UEFI Variable Check fail %r - %s not in %g namespace\n", EFI_INVALID_PARAMETER, VariableName, VendorGuid));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ VarCheckProperty = NULL;
+ VarCheckFunction = GetUefiDefinedVarCheckFunction (VariableName, VendorGuid, &VarCheckProperty);
+ if (VarCheckFunction != NULL) {
+ Status = VarCheckFunction (
+ VarCheckProperty,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "UEFI Variable Check function fail %r - %g:%s\n", Status, VendorGuid, VariableName));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Variable property set for UEFI defined variables.
+
+**/
+VOID
+VariablePropertySetUefiDefined (
+ VOID
+ )
+{
+ UINTN Index;
+
+ //
+ // EFI_GLOBAL_VARIABLE
+ //
+ for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mGlobalVariableList[Index].Name,
+ &gEfiGlobalVariableGuid,
+ &mGlobalVariableList[Index].VariableProperty
+ );
+ }
+ for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mGlobalVariableList2[Index].Name,
+ &gEfiGlobalVariableGuid,
+ &mGlobalVariableList2[Index].VariableProperty
+ );
+ }
+
+ //
+ // EFI_IMAGE_SECURITY_DATABASE_GUID
+ //
+ for (Index = 0; Index < sizeof (mImageSecurityVariableList)/sizeof (mImageSecurityVariableList[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mImageSecurityVariableList[Index].Name,
+ &gEfiImageSecurityDatabaseGuid,
+ &mImageSecurityVariableList[Index].VariableProperty
+ );
+ }
+
+ //
+ // EFI_HARDWARE_ERROR_VARIABLE
+ //
+ VarCheckLibVariablePropertySet (
+ mHwErrRecVariable.Name,
+ &gEfiHardwareErrorVariableGuid,
+ &mHwErrRecVariable.VariableProperty
+ );
+}
+
+/**
+ Constructor function of VarCheckUefiLib to set property and
+ register SetVariable check handler for UEFI defined variables.
+
+ @retval EFI_SUCCESS The constructor executed correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+VarCheckUefiLibNullClassConstructor (
+ VOID
+ )
+{
+ VariablePropertySetUefiDefined ();
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerUefiDefined);
+
+ return RETURN_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Logo/Logo.bmp b/roms/edk2/MdeModulePkg/Logo/Logo.bmp
new file mode 100644
index 000000000..3e85229e1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/Logo.bmp
Binary files differ
diff --git a/roms/edk2/MdeModulePkg/Logo/Logo.c b/roms/edk2/MdeModulePkg/Logo/Logo.c
new file mode 100644
index 000000000..c647253ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/Logo.c
@@ -0,0 +1,153 @@
+/** @file
+ Logo DXE Driver, install Edkii Platform Logo protocol.
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/HiiImageEx.h>
+#include <Protocol/PlatformLogo.h>
+#include <Protocol/HiiPackageList.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+typedef struct {
+ EFI_IMAGE_ID ImageId;
+ EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute;
+ INTN OffsetX;
+ INTN OffsetY;
+} LOGO_ENTRY;
+
+EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx;
+EFI_HII_HANDLE mHiiHandle;
+LOGO_ENTRY mLogos[] = {
+ {
+ IMAGE_TOKEN (IMG_LOGO),
+ EdkiiPlatformLogoDisplayAttributeCenter,
+ 0,
+ 0
+ }
+};
+
+/**
+ Load a platform logo image and return its data and attributes.
+
+ @param This The pointer to this protocol instance.
+ @param Instance The visible image instance is found.
+ @param Image Points to the image.
+ @param Attribute The display attributes of the image returned.
+ @param OffsetX The X offset of the image regarding the Attribute.
+ @param OffsetY The Y offset of the image regarding the Attribute.
+
+ @retval EFI_SUCCESS The image was fetched successfully.
+ @retval EFI_NOT_FOUND The specified image could not be found.
+**/
+EFI_STATUS
+EFIAPI
+GetImage (
+ IN EDKII_PLATFORM_LOGO_PROTOCOL *This,
+ IN OUT UINT32 *Instance,
+ OUT EFI_IMAGE_INPUT *Image,
+ OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute,
+ OUT INTN *OffsetX,
+ OUT INTN *OffsetY
+ )
+{
+ UINT32 Current;
+ if (Instance == NULL || Image == NULL ||
+ Attribute == NULL || OffsetX == NULL || OffsetY == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Current = *Instance;
+ if (Current >= ARRAY_SIZE (mLogos)) {
+ return EFI_NOT_FOUND;
+ }
+
+ (*Instance)++;
+ *Attribute = mLogos[Current].Attribute;
+ *OffsetX = mLogos[Current].OffsetX;
+ *OffsetY = mLogos[Current].OffsetY;
+ return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, mLogos[Current].ImageId, Image);
+}
+
+EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = {
+ GetImage
+};
+
+/**
+ Entrypoint of this module.
+
+ This function is the entrypoint of this module. It installs the Edkii
+ Platform Logo protocol.
+
+ @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
+InitializeLogo (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HANDLE Handle;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiImageExProtocolGuid,
+ NULL,
+ (VOID **) &mHiiImageEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **) &PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "HII Image Package with logo not found in PE/COFF resource section\n"));
+ return Status;
+ }
+
+ //
+ // Publish HII package list to HII Database.
+ //
+ Status = HiiDatabase->NewPackageList (
+ HiiDatabase,
+ PackageList,
+ NULL,
+ &mHiiHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo,
+ NULL
+ );
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Logo/Logo.idf b/roms/edk2/MdeModulePkg/Logo/Logo.idf
new file mode 100644
index 000000000..1f7933202
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/Logo.idf
@@ -0,0 +1,10 @@
+// /** @file
+// Platform Logo image definition file.
+//
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#image IMG_LOGO Logo.bmp
diff --git a/roms/edk2/MdeModulePkg/Logo/Logo.inf b/roms/edk2/MdeModulePkg/Logo/Logo.inf
new file mode 100644
index 000000000..70a66cae9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/Logo.inf
@@ -0,0 +1,31 @@
+## @file
+# The default logo bitmap picture shown on setup screen, which is corresponding to gEfiDefaultBmpLogoGuid.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Logo
+ MODULE_UNI_FILE = Logo.uni
+ FILE_GUID = 7BB28B99-61BB-11D5-9A5D-0090273FC14D
+ MODULE_TYPE = USER_DEFINED
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64 RISCV64
+#
+
+[Binaries]
+ BIN|Logo.bmp|*
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LogoExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Logo/Logo.uni b/roms/edk2/MdeModulePkg/Logo/Logo.uni
new file mode 100644
index 000000000..9d1bbaffa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/Logo.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The default logo bitmap picture shown on setup screen, which is corresponding to gEfiDefaultBmpLogoGuid.
+//
+// This module provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid."
+
diff --git a/roms/edk2/MdeModulePkg/Logo/LogoDxe.inf b/roms/edk2/MdeModulePkg/Logo/LogoDxe.inf
new file mode 100644
index 000000000..41215d25d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/LogoDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# The default logo bitmap picture shown on setup screen.
+#
+# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LogoDxe
+ MODULE_UNI_FILE = LogoDxe.uni
+ FILE_GUID = F74D20EE-37E7-48FC-97F7-9B1047749C69
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeLogo
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ Logo.bmp
+ Logo.c
+ Logo.idf
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiHiiImageExProtocolGuid ## CONSUMES
+ gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES
+ gEdkiiPlatformLogoProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiImageExProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LogoDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Logo/LogoDxe.uni b/roms/edk2/MdeModulePkg/Logo/LogoDxe.uni
new file mode 100644
index 000000000..9635701b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/LogoDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The default logo bitmap picture shown on setup screen.
+//
+// This module provides the default logo bitmap picture shown on setup screen, through EDKII Platform Logo protocol.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the default logo bitmap picture shown on setup screen."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides the default logo bitmap picture shown on setup screen, through EDKII Platform Logo protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Logo/LogoDxeExtra.uni b/roms/edk2/MdeModulePkg/Logo/LogoDxeExtra.uni
new file mode 100644
index 000000000..c6ea34b81
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/LogoDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Logo Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Logo Image File"
+
+
diff --git a/roms/edk2/MdeModulePkg/Logo/LogoExtra.uni b/roms/edk2/MdeModulePkg/Logo/LogoExtra.uni
new file mode 100644
index 000000000..041179fb7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Logo/LogoExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Logo Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Logo Image File"
+
+
diff --git a/roms/edk2/MdeModulePkg/MdeModulePkg.ci.yaml b/roms/edk2/MdeModulePkg/MdeModulePkg.ci.yaml
new file mode 100644
index 000000000..1a7e95518
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/MdeModulePkg.ci.yaml
@@ -0,0 +1,111 @@
+## @file
+# CI configuration for MdeModulePkg
+#
+# Copyright (c) Microsoft Corporation
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+{
+ ## options defined .pytool/Plugin/LicenseCheck
+ "LicenseCheck": {
+ "IgnoreFiles": []
+ },
+ "EccCheck": {
+ ## Exception sample looks like below:
+ ## "ExceptionList": [
+ ## "<ErrorID>", "<KeyWord>"
+ ## ]
+ "ExceptionList": [
+ ],
+ ## Both file path and directory path are accepted.
+ "IgnoreFiles": [
+ "Library/BrotliCustomDecompressLib/brotli",
+ "Universal/RegularExpressionDxe/oniguruma"
+ ]
+ },
+ ## options defined ci/Plugin/CompilerPlugin
+ "CompilerPlugin": {
+ "DscPath": "MdeModulePkg.dsc"
+ },
+ ## options defined ci/Plugin/HostUnitTestCompilerPlugin
+ "HostUnitTestCompilerPlugin": {
+ "DscPath": "Test/MdeModulePkgHostTest.dsc"
+ },
+
+ ## options defined ci/Plugin/CharEncodingCheck
+ "CharEncodingCheck": {
+ "IgnoreFiles": [
+ "MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testc.c",
+ "MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/windows/testc.c"
+ ]
+ },
+
+ ## options defined ci/Plugin/DependencyCheck
+ "DependencyCheck": {
+ "AcceptableDependencies": [
+ "MdePkg/MdePkg.dec",
+ "MdeModulePkg/MdeModulePkg.dec",
+ "StandaloneMmPkg/StandaloneMmPkg.dec",
+ "ArmPkg/ArmPkg.dec" # this should be fixed by promoting an abstraction
+ ],
+ # For host based unit tests
+ "AcceptableDependencies-HOST_APPLICATION":[
+ "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec"
+ ],
+ # For UEFI shell based apps
+ "AcceptableDependencies-UEFI_APPLICATION":[],
+ "IgnoreInf": []
+ },
+
+ ## options defined ci/Plugin/DscCompleteCheck
+ "DscCompleteCheck": {
+ "IgnoreInf": [],
+ "DscPath": "MdeModulePkg.dsc"
+ },
+ ## options defined ci/Plugin/HostUnitTestDscCompleteCheck
+ "HostUnitTestDscCompleteCheck": {
+ "IgnoreInf": [""],
+ "DscPath": "Test/MdeModulePkgHostTest.dsc"
+ },
+
+ ## options defined ci/Plugin/GuidCheck
+ "GuidCheck": {
+ "IgnoreGuidName": [],
+ "IgnoreGuidValue": ["00000000-0000-0000-0000-000000000000"],
+ "IgnoreFoldersAndFiles": [],
+ "IgnoreDuplicates": [
+ "gEfiPeiMmAccessPpiGuid=gPeiSmmAccessPpiGuid",
+ "gPeiSmmControlPpiGuid=gEfiPeiMmControlPpiGuid",
+ ]
+ },
+
+ ## options defined ci/Plugin/LibraryClassCheck
+ "LibraryClassCheck": {
+ "IgnoreHeaderFile": []
+ },
+
+ ## options defined ci/Plugin/SpellCheck
+ "SpellCheck": {
+ "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log
+ "IgnoreStandardPaths": [ # Standard Plugin defined paths that should be ignore
+ "*.c", "*.asm", "*.h", "*.nasm", "*.s", "*.asl", "*.inf"
+ ],
+ "IgnoreFiles": [ # use gitignore syntax to ignore errors in matching files
+ "Library/LzmaCustomDecompressLib/Sdk/DOC/*"
+ ],
+ "ExtendWords": [ # words to extend to the dictionary for this package
+ "LIGHTGRAY",
+ "DARKGRAY",
+ "LIGHTBLUE",
+ "LIGHTGREEN",
+ "LIGHTCYAN",
+ "LIGHTRED",
+ "LIGHTMAGENTA",
+ "FVMAIN",
+ "VARCHECKPCD",
+ "Getxx",
+ "lzturbo"
+ ],
+ "AdditionalIncludePaths": [] # Additional paths to spell check relative to package root (wildcards supported)
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/MdeModulePkg.dec b/roms/edk2/MdeModulePkg/MdeModulePkg.dec
new file mode 100644
index 000000000..cb30a7975
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/MdeModulePkg.dec
@@ -0,0 +1,2095 @@
+## @file MdeModulePkg.dec
+# This package provides the modules that conform to UEFI/PI Industry standards.
+# It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
+# and libraries instances, which are used for those modules.
+#
+# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+# (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+# Copyright (c) 2016, Microsoft Corporation<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = MdeModulePkg
+ PACKAGE_UNI_FILE = MdeModulePkg.uni
+ PACKAGE_GUID = BA0D78D6-2CAF-414b-BD4D-B6762A894288
+ PACKAGE_VERSION = 0.98
+
+[Includes]
+ Include
+
+[Includes.Common.Private]
+ Library/BrotliCustomDecompressLib/brotli/c/include
+
+[LibraryClasses]
+ ## @libraryclass Defines a set of methods to reset whole system.
+ ResetSystemLib|Include/Library/ResetSystemLib.h
+
+ ## @libraryclass Defines a set of helper functions for resetting the system.
+ ResetUtilityLib|Include/Library/ResetUtilityLib.h
+
+ ## @libraryclass Provides HII related functions.
+ HiiLib|Include/Library/HiiLib.h
+
+ ## @libraryclass Defines a set of interfaces on how to process capusle image update.
+ CapsuleLib|Include/Library/CapsuleLib.h
+
+ ## @libraryclass Provides global variables that are pointers
+ # to the UEFI HII related protocols.
+ #
+ UefiHiiServicesLib|Include/Library/UefiHiiServicesLib.h
+
+ ## @libraryclass Provides a set of interfaces to abstract the policy of security measurement.
+ #
+ SecurityManagementLib|Include/Library/SecurityManagementLib.h
+
+ ## @libraryclass OEM status code libary is used to report status code to OEM device.
+ #
+ OemHookStatusCodeLib|Include/Library/OemHookStatusCodeLib.h
+
+ ## @libraryclass Debug Agent is used to provide soft debug capability.
+ #
+ DebugAgentLib|Include/Library/DebugAgentLib.h
+
+ ## @libraryclass Provide platform specific hooks.
+ #
+ PlatformHookLib|Include/Library/PlatformHookLib.h
+
+ ## @libraryclass Provide platform specific hooks for SMM core.
+ #
+ SmmCorePlatformHookLib|Include/Library/SmmCorePlatformHookLib.h
+
+ ## @libraryclass Provide capability to maintain the data integrity cross S3 phase.
+ #
+ LockBoxLib|Include/Library/LockBoxLib.h
+
+ ## @libraryclass Provide the CPU exception handler.
+ #
+ CpuExceptionHandlerLib|Include/Library/CpuExceptionHandlerLib.h
+
+ ## @libraryclass Provides platform specific display interface.
+ #
+ CustomizedDisplayLib|Include/Library/CustomizedDisplayLib.h
+
+ ## @libraryclass Provides sorting functions
+ SortLib|Include/Library/SortLib.h
+
+ ## @libraryclass Provides core boot manager functions
+ UefiBootManagerLib|Include/Library/UefiBootManagerLib.h
+
+ ## @libraryclass Provides core boot manager functions
+ PlatformBootManagerLib|Include/Library/PlatformBootManagerLib.h
+
+ ## @libraryclass Provides common interfaces about TPM measurement for other modules.
+ #
+ TpmMeasurementLib|Include/Library/TpmMeasurementLib.h
+
+ ## @libraryclass Provides authenticated variable services.
+ #
+ AuthVariableLib|Include/Library/AuthVariableLib.h
+
+ ## @libraryclass Provides variable check services and database management.
+ #
+ VarCheckLib|Include/Library/VarCheckLib.h
+
+ ## @libraryclass Provides services to get variable error flag and do platform variable cleanup.
+ #
+ PlatformVarCleanupLib|Include/Library/PlatformVarCleanupLib.h
+
+ ## @libraryclass Provides services to get do the file explorer.
+ #
+ FileExplorerLib|Include/Library/FileExplorerLib.h
+
+ ## @libraryclass Provides interfaces about logo display.
+ #
+ BootLogoLib|Include/Library/BootLogoLib.h
+
+ ## @libraryclass Provides interfaces about Ipmi submit generic commond.
+ #
+ IpmiLib|Include/Library/IpmiLib.h
+
+ ## @libraryclass Provides interfaces for platform to return root bridge information to PciHostBridgeDxe driver.
+ #
+ PciHostBridgeLib|Include/Library/PciHostBridgeLib.h
+
+ ## @libraryclass Provides services to record memory profile of multilevel caller.
+ #
+ MemoryProfileLib|Include/Library/MemoryProfileLib.h
+
+ ## @libraryclass Provides an interface for performing UEFI Graphics Output Protocol Video blt operations.
+ ##
+ FrameBufferBltLib|Include/Library/FrameBufferBltLib.h
+
+ ## @libraryclass Provides services to authenticate a UEFI defined FMP Capsule.
+ #
+ FmpAuthenticationLib|Include/Library/FmpAuthenticationLib.h
+
+ ## @libraryclass Provides a service to register non-discoverable device
+ ##
+ NonDiscoverableDeviceRegistrationLib|Include/Library/NonDiscoverableDeviceRegistrationLib.h
+
+ ## @libraryclass Provides services to convert a BMP graphics image to a GOP BLT buffer
+ # and to convert a GOP BLT buffer to a BMP graphics image.
+ #
+ BmpSupportLib|Include/Library/BmpSupportLib.h
+
+ ## @libraryclass Provides services to display completion progress when
+ # processing a firmware update that updates the firmware image in a firmware
+ # device. A platform may provide its own instance of this library class to
+ # customize how a user is informed of completion progress.
+ #
+ DisplayUpdateProgressLib|Include/Library/DisplayUpdateProgressLib.h
+
+[Guids]
+ ## MdeModule package token space guid
+ # Include/Guid/MdeModulePkgTokenSpace.h
+ gEfiMdeModulePkgTokenSpaceGuid = { 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }}
+
+ ## Hob guid for Pcd DataBase
+ # Include/Guid/PcdDataBaseHobGuid.h
+ gPcdDataBaseHobGuid = { 0xEA296D92, 0x0B69, 0x423C, { 0x8C, 0x28, 0x33, 0xB4, 0xE0, 0xA9, 0x12, 0x68 }}
+
+ ## Guid for PCD DataBase signature.
+ # Include/Guid/PcdDataBaseSignatureGuid.h
+ gPcdDataBaseSignatureGuid = { 0x3c7d193c, 0x682c, 0x4c14, { 0xa6, 0x8f, 0x55, 0x2d, 0xea, 0x4f, 0x43, 0x7e }}
+
+ ## Guid for EDKII implementation GUIDed opcodes
+ # Include/Guid/MdeModuleHii.h
+ gEfiIfrTianoGuid = { 0xf0b1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce }}
+
+ ## Guid for EDKII implementation extension, used to indaicate there are bit fields in the varstore.
+ # Include/Guid/MdeModuleHii.h
+ gEdkiiIfrBitVarstoreGuid = {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60,0xA7, 0x1D}}
+
+ ## Guid for Framework vfr GUIDed opcodes.
+ # Include/Guid/MdeModuleHii.h
+ gEfiIfrFrameworkGuid = { 0x31ca5d1a, 0xd511, 0x4931, { 0xb7, 0x82, 0xae, 0x6b, 0x2b, 0x17, 0x8c, 0xd7 }}
+
+ ## Guid to specify the System Non Volatile FV
+ # Include/Guid/SystemNvDataGuid.h
+ gEfiSystemNvDataFvGuid = { 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+
+ ## GUID used as the signature of FTW working block header.
+ # Include/Guid/SystemNvDataGuid.h
+ gEdkiiWorkingBlockSignatureGuid = { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
+
+ ## GUID used to build FTW last write data hob and install PPI to inform the check for FTW last write data has been done.
+ # Include/Guid/FaultTolerantWrite.h
+ gEdkiiFaultTolerantWriteGuid = { 0x1d3e9cb8, 0x43af, 0x490b, { 0x83, 0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 }}
+
+ ## Guid specify the device is the console out device.
+ # Include/Guid/ConsoleOutDevice.h
+ gEfiConsoleOutDeviceGuid = { 0xD3B36F2C, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}
+
+ ## Guid specify the device is the console in device.
+ # Include/Guid/ConsoleInDevice.h
+ gEfiConsoleInDeviceGuid = { 0xD3B36F2B, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}
+
+ ## Hob and Variable guid specify the platform memory type information.
+ # Include/Guid/MemoryTypeInformation.h
+ gEfiMemoryTypeInformationGuid = { 0x4C19049F, 0x4137, 0x4DD3, { 0x9C, 0x10, 0x8B, 0x97, 0xA8, 0x3F, 0xFD, 0xFA }}
+
+ ## Capsule update hob and variable guid
+ # Include/Guid/CapsuleVendor.h
+ gEfiCapsuleVendorGuid = { 0x711C703F, 0xC285, 0x4B10, { 0xA3, 0xB0, 0x36, 0xEC, 0xBD, 0x3C, 0x8B, 0xE2 }}
+
+ ## Guid specifiy the device is the StdErr device.
+ # Include/Guid/StandardErrorDevice.h
+ gEfiStandardErrorDeviceGuid = { 0xD3B36F2D, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}
+
+ ## Guid acted as variable store header's signature and to specify the variable list entries put in the EFI system table.
+ # Include/Guid/VariableFormat.h
+ gEfiVariableGuid = { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }}
+
+ ## Guid acted as the authenticated variable store header's signature, and to specify the variable list entries put in the EFI system table.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiAuthenticatedVariableGuid = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+ # Include/Guid/VariableIndexTable.h
+ gEfiVariableIndexTableGuid = { 0x8cfdb8c8, 0xd6b2, 0x40f3, { 0x8e, 0x97, 0x02, 0x30, 0x7c, 0xc9, 0x8b, 0x7c }}
+
+ ## Guid is defined for SMM variable module to notify SMM variable wrapper module when variable write service was ready.
+ # Include/Guid/SmmVariableCommon.h
+ gSmmVariableWriteGuid = { 0x93ba1826, 0xdffb, 0x45dd, { 0x82, 0xa7, 0xe7, 0xdc, 0xaa, 0x3b, 0xbd, 0xf3 }}
+
+ ## Performance protocol guid that also acts as the performance HOB guid and performance variable GUID
+ # Include/Guid/Performance.h
+ gPerformanceProtocolGuid = { 0x76B6BDFA, 0x2ACD, 0x4462, { 0x9E, 0x3F, 0xCB, 0x58, 0xC9, 0x69, 0xD9, 0x37 } }
+ gSmmPerformanceProtocolGuid = { 0xf866226a, 0xeaa5, 0x4f5a, { 0xa9, 0xa, 0x6c, 0xfb, 0xa5, 0x7c, 0x58, 0x8e } }
+ gPerformanceExProtocolGuid = { 0x1ea81bec, 0xf01a, 0x4d98, { 0xa2, 0x1, 0x4a, 0x61, 0xce, 0x2f, 0xc0, 0x22 } }
+ gSmmPerformanceExProtocolGuid = { 0x931fc048, 0xc71d, 0x4455, { 0x89, 0x30, 0x47, 0x6, 0x30, 0xe3, 0xe, 0xe5 } }
+ # Include/Guid/PerformanceMeasurement.h
+ gEdkiiPerformanceMeasurementProtocolGuid = { 0xc85d06be, 0x5f75, 0x48ce, { 0xa8, 0x0f, 0x12, 0x36, 0xba, 0x3b, 0x87, 0xb1 } }
+ gEdkiiSmmPerformanceMeasurementProtocolGuid = { 0xd56b6d73, 0x1a7b, 0x4015, { 0x9b, 0xb4, 0x7b, 0x07, 0x17, 0x29, 0xed, 0x24 } }
+
+ ## Guid is defined for CRC32 encapsulation scheme.
+ # Include/Guid/Crc32GuidedSectionExtraction.h
+ gEfiCrc32GuidedSectionExtractionGuid = { 0xFC1BCDB0, 0x7D31, 0x49aa, {0x93, 0x6A, 0xA4, 0x60, 0x0D, 0x9D, 0xD0, 0x83 } }
+
+ ## Include/Guid/StatusCodeCallbackGuid.h
+ gStatusCodeCallbackGuid = {0xe701458c, 0x4900, 0x4ca5, {0xb7, 0x72, 0x3d, 0x37, 0x94, 0x9f, 0x79, 0x27}}
+
+ ## GUID identifies status code records HOB that originate from the PEI status code
+ # Include/Guid/MemoryStatusCodeRecord.h
+ gMemoryStatusCodeRecordGuid = { 0x060CC026, 0x4C0D, 0x4DDA, { 0x8F, 0x41, 0x59, 0x5F, 0xEF, 0x00, 0xA5, 0x02 }}
+
+ ## GUID used to pass DEBUG() macro information through the Status Code Protocol and Status Code PPI
+ # Include/Guid/StatusCodeDataTypeDebug.h
+ gEfiStatusCodeDataTypeDebugGuid = { 0x9A4E9246, 0xD553, 0x11D5, { 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9 }}
+
+ ## A configuration Table Guid for Load module at fixed address
+ # Include/Guid/LoadModuleAtFixedAddress.h
+ gLoadFixedAddressConfigurationTableGuid = { 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9 } }
+
+ ## GUID used to store the global debug mask value into an EFI Variable
+ # Include/Guid/DebugMask.h
+ gEfiGenericVariableGuid = { 0x59d1c24f, 0x50f1, 0x401a, {0xb1, 0x01, 0xf3, 0x3e, 0x0d, 0xae, 0xd4, 0x43} }
+
+ ## Event for the DXE Core to signal idle events
+ # Include/Guid/EventIdle.h
+ gIdleLoopEventGuid = { 0x3c8d294c, 0x5fc3, 0x4451, { 0xbb, 0x31, 0xc4, 0xc0, 0x32, 0x29, 0x5e, 0x6c } }
+
+ ## Include/Guid/RecoveryDevice.h
+ gRecoveryOnFatUsbDiskGuid = { 0x0FFBCE19, 0x324C, 0x4690, { 0xA0, 0x09, 0x98, 0xC6, 0xAE, 0x2E, 0xB1, 0x86 }}
+
+ ## Include/Guid/RecoveryDevice.h
+ gRecoveryOnFatIdeDiskGuid = { 0xB38573B6, 0x6200, 0x4AC5, { 0xB5, 0x1D, 0x82, 0xE6, 0x59, 0x38, 0xD7, 0x83 }}
+
+ ## Include/Guid/RecoveryDevice.h
+ gRecoveryOnFatFloppyDiskGuid = { 0x2E3D2E75, 0x9B2E, 0x412D, { 0xB4, 0xB1, 0x70, 0x41, 0x6B, 0x87, 0x00, 0xFF }}
+
+ ## Include/Guid/RecoveryDevice.h
+ gRecoveryOnDataCdGuid = { 0x5CAC0099, 0x0DC9, 0x48E5, { 0x80, 0x68, 0xBB, 0x95, 0xF5, 0x40, 0x0A, 0x9F }}
+
+ ## Include/Guid/RecoveryDevice.h
+ gRecoveryOnFatNvmeDiskGuid = { 0xC770A27F, 0x956A, 0x497A, { 0x85, 0x48, 0xE0, 0x61, 0x97, 0x58, 0x8B, 0xF6 }}
+
+ ## Include/Guid/SmmLockBox.h
+ gEfiSmmLockBoxCommunicationGuid = { 0x2a3cfebd, 0x27e8, 0x4d0a, { 0x8b, 0x79, 0xd6, 0x88, 0xc2, 0xa3, 0xe1, 0xc0 }}
+
+ ## Include/Guid/AcpiS3Context.h
+ gEfiAcpiVariableGuid = { 0xAF9FFD67, 0xEC10, 0x488A, { 0x9D, 0xFC, 0x6C, 0xBF, 0x5E, 0xE2, 0x2C, 0x2E }}
+
+ ## Include/Guid/AcpiS3Context.h
+ gEfiAcpiS3ContextGuid = { 0xef98d3a, 0x3e33, 0x497a, { 0xa4, 0x1, 0x77, 0xbe, 0x3e, 0xb7, 0x4f, 0x38 }}
+
+ ## Include/Guid/BootScriptExecutorVariable.h
+ gEfiBootScriptExecutorVariableGuid = { 0x3079818c, 0x46d4, 0x4a73, { 0xae, 0xf3, 0xe3, 0xe4, 0x6c, 0xf1, 0xee, 0xdb }}
+ gEfiBootScriptExecutorContextGuid = { 0x79cb58c4, 0xac51, 0x442f, { 0xaf, 0xd7, 0x98, 0xe4, 0x7d, 0x2e, 0x99, 0x8 }}
+
+ ## Include/Guid/UsbKeyBoardLayout.h
+ gUsbKeyboardLayoutPackageGuid = { 0xc0f3b43, 0x44de, 0x4907, { 0xb4, 0x78, 0x22, 0x5f, 0x6f, 0x62, 0x89, 0xdc }}
+ gUsbKeyboardLayoutKeyGuid = { 0x3a4d7a7c, 0x18a, 0x4b42, { 0x81, 0xb3, 0xdc, 0x10, 0xe3, 0xb5, 0x91, 0xbd }}
+
+ ## Include/Guid/HiiResourceSampleHii.h
+ gHiiResourceSamleFormSetGuid = { 0x4f4ef7f0, 0xaa29, 0x4ce9, { 0xba, 0x41, 0x64, 0x3e, 0x1, 0x23, 0xa9, 0x9f }}
+
+ ## Include/Guid/DriverSampleHii.h
+ gDriverSampleFormSetGuid = { 0xA04A27f4, 0xDF00, 0x4D42, { 0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D }}
+ gDriverSampleInventoryGuid = { 0xb3f56470, 0x6141, 0x4621, { 0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8 }}
+ gEfiIfrRefreshIdOpGuid = { 0xF5E655D9, 0x02A6, 0x46f2, { 0x9E, 0x76, 0xB8, 0xBE, 0x8E, 0x60, 0xAB, 0x22 }}
+
+ ## Include/Guid/PlatDriOverrideHii.h
+ gPlatformOverridesManagerGuid = { 0x8614567d, 0x35be, 0x4415, { 0x8d, 0x88, 0xbd, 0x7d, 0xc, 0x9c, 0x70, 0xc0 }}
+
+ ## Include/Guid/ZeroGuid.h
+ gZeroGuid = { 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+
+ ## Include/Guid/MtcVendor.h
+ gMtcVendorGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b }}
+
+ ## Guid for Firmware Performance Data Table (FPDT) implementation.
+ # Include/Guid/FirmwarePerformance.h
+ gEfiFirmwarePerformanceGuid = { 0xc095791a, 0x3001, 0x47b2, { 0x80, 0xc9, 0xea, 0xc7, 0x31, 0x9f, 0x2f, 0xa4 }}
+ gFirmwarePerformanceS3PointerGuid = { 0xdc65adc, 0xa973, 0x4130, { 0x8d, 0xf0, 0x2a, 0xdb, 0xeb, 0x9e, 0x4a, 0x31 }}
+
+ ## Include/Guid/ExitBootServiceFailed.h
+ gEventExitBootServicesFailedGuid = { 0x4f6c5507, 0x232f, 0x4787, { 0xb9, 0x5e, 0x72, 0xf8, 0x62, 0x49, 0xc, 0xb1 } }
+
+ ## Include/Guid/ConnectConInEvent.h
+ gConnectConInEventGuid = { 0xdb4e8151, 0x57ed, 0x4bed, { 0x88, 0x33, 0x67, 0x51, 0xb5, 0xd1, 0xa8, 0xd7 }}
+
+ ## Include/Guid/StatusCodeDataTypeVariable.h
+ gEdkiiStatusCodeDataTypeVariableGuid = { 0xf6ee6dbb, 0xd67f, 0x4ea0, { 0x8b, 0x96, 0x6a, 0x71, 0xb1, 0x9d, 0x84, 0xad }}
+
+ ## Include/Guid/MemoryProfile.h
+ gEdkiiMemoryProfileGuid = { 0x821c9a09, 0x541a, 0x40f6, { 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe }}
+ gEdkiiSmmMemoryProfileGuid = { 0xe22bbcca, 0x516a, 0x46a8, { 0x80, 0xe2, 0x67, 0x45, 0xe8, 0x36, 0x93, 0xbd }}
+
+ ## Include/Protocol/VarErrorFlag.h
+ gEdkiiVarErrorFlagGuid = { 0x4b37fe8, 0xf6ae, 0x480b, { 0xbd, 0xd5, 0x37, 0xd9, 0x8c, 0x5e, 0x89, 0xaa } }
+
+ ## GUID indicates the BROTLI custom compress/decompress algorithm.
+ gBrotliCustomDecompressGuid = { 0x3D532050, 0x5CDA, 0x4FD0, { 0x87, 0x9E, 0x0F, 0x7F, 0x63, 0x0D, 0x5A, 0xFB }}
+
+ ## GUID indicates the LZMA custom compress/decompress algorithm.
+ # Include/Guid/LzmaDecompress.h
+ gLzmaCustomDecompressGuid = { 0xEE4E5898, 0x3914, 0x4259, { 0x9D, 0x6E, 0xDC, 0x7B, 0xD7, 0x94, 0x03, 0xCF }}
+ gLzmaF86CustomDecompressGuid = { 0xD42AE6BD, 0x1352, 0x4bfb, { 0x90, 0x9A, 0xCA, 0x72, 0xA6, 0xEA, 0xE8, 0x89 }}
+
+ ## Include/Guid/TtyTerm.h
+ gEfiTtyTermGuid = { 0x7d916d80, 0x5bb1, 0x458c, {0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94 }}
+ gEdkiiLinuxTermGuid = { 0xe4364a7f, 0xf825, 0x430e, {0x9d, 0x3a, 0x9c, 0x9b, 0xe6, 0x81, 0x7c, 0xa5 }}
+ gEdkiiXtermR6Guid = { 0xfbfca56b, 0xbb36, 0x4b78, {0xaa, 0xab, 0xbe, 0x1b, 0x97, 0xec, 0x7c, 0xcb }}
+ gEdkiiVT400Guid = { 0x8e46dddd, 0x3d49, 0x4a9d, {0xb8, 0x75, 0x3c, 0x08, 0x6f, 0x6a, 0xa2, 0xbd }}
+ gEdkiiSCOTermGuid = { 0xfc7dd6e0, 0x813c, 0x434d, {0xb4, 0xda, 0x3b, 0xd6, 0x49, 0xe9, 0xe1, 0x5a }}
+
+ ## Include/Guid/HiiBootMaintenanceFormset.h
+ gEfiIfrBootMaintenanceGuid = { 0xb2dedc91, 0xd59f, 0x48d2, { 0x89, 0x8a, 0x12, 0x49, 0xc, 0x74, 0xa4, 0xe0 }}
+
+ gEfiIfrFrontPageGuid = { 0xe58809f8, 0xfbc1, 0x48e2, { 0x88, 0x3a, 0xa3, 0x0f, 0xdc, 0x4b, 0x44, 0x1e } }
+
+ ## Include/Guid/RamDiskHii.h
+ gRamDiskFormSetGuid = { 0x2a46715f, 0x3581, 0x4a55, { 0x8e, 0x73, 0x2b, 0x76, 0x9a, 0xaa, 0x30, 0xc5 }}
+
+ ## Include/Guid/PiSmmCommunicationRegionTable.h
+ gEdkiiPiSmmCommunicationRegionTableGuid = { 0x4e28ca50, 0xd582, 0x44ac, {0xa1, 0x1f, 0xe3, 0xd5, 0x65, 0x26, 0xdb, 0x34}}
+
+ ## Include/Guid/PiSmmMemoryAttributesTable.h
+ gEdkiiPiSmmMemoryAttributesTableGuid = { 0x6b9fd3f7, 0x16df, 0x45e8, {0xbd, 0x39, 0xb9, 0x4a, 0x66, 0x54, 0x1a, 0x5d}}
+
+ ## Include/Guid/SmiHandlerProfile.h
+ gSmiHandlerProfileGuid = {0x49174342, 0x7108, 0x409b, {0x8b, 0xbe, 0x65, 0xfd, 0xa8, 0x53, 0x89, 0xf5}}
+
+ ## Include/Guid/NonDiscoverableDevice.h
+ gEdkiiNonDiscoverableAhciDeviceGuid = { 0xC7D35798, 0xE4D2, 0x4A93, {0xB1, 0x45, 0x54, 0x88, 0x9F, 0x02, 0x58, 0x4B } }
+ gEdkiiNonDiscoverableAmbaDeviceGuid = { 0x94440339, 0xCC93, 0x4506, {0xB4, 0xC6, 0xEE, 0x8D, 0x0F, 0x4C, 0xA1, 0x91 } }
+ gEdkiiNonDiscoverableEhciDeviceGuid = { 0xEAEE5615, 0x0CFD, 0x45FC, {0x87, 0x69, 0xA0, 0xD8, 0x56, 0x95, 0xAF, 0x85 } }
+ gEdkiiNonDiscoverableNvmeDeviceGuid = { 0xC5F25542, 0x2A79, 0x4A26, {0x81, 0xBB, 0x4E, 0xA6, 0x32, 0x33, 0xB3, 0x09 } }
+ gEdkiiNonDiscoverableOhciDeviceGuid = { 0xB20005B0, 0xBB2D, 0x496F, {0x86, 0x9C, 0x23, 0x0B, 0x44, 0x79, 0xE7, 0xD1 } }
+ gEdkiiNonDiscoverableSdhciDeviceGuid = { 0x1DD1D619, 0xF9B8, 0x463E, {0x86, 0x81, 0xD1, 0xDC, 0x7C, 0x07, 0xB7, 0x2C } }
+ gEdkiiNonDiscoverableUfsDeviceGuid = { 0x2EA77912, 0x80A8, 0x4947, {0xBE, 0x69, 0xCD, 0xD0, 0x0A, 0xFB, 0xE5, 0x56 } }
+ gEdkiiNonDiscoverableUhciDeviceGuid = { 0xA8CDA0A2, 0x4F37, 0x4A1B, {0x8E, 0x10, 0x8E, 0xF3, 0xCC, 0x3B, 0xF3, 0xA8 } }
+ gEdkiiNonDiscoverableXhciDeviceGuid = { 0xB1BE0BC5, 0x6C28, 0x442D, {0xAA, 0x37, 0x15, 0x1B, 0x42, 0x57, 0xBD, 0x78 } }
+
+ ## Include/Guid/PlatformHasAcpi.h
+ gEdkiiPlatformHasAcpiGuid = { 0xf0966b41, 0xc23f, 0x41b9, { 0x96, 0x04, 0x0f, 0xf7, 0xe1, 0x11, 0x96, 0x5a } }
+
+ ## Include/Guid/ExtendedFirmwarePerformance.h
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid = { 0x3b387bfd, 0x7abc, 0x4cf2, { 0xa0, 0xca, 0xb6, 0xa1, 0x6c, 0x1b, 0x1b, 0x25 } }
+
+ ## Include/Guid/EndofS3Resume.h
+ gEdkiiEndOfS3ResumeGuid = { 0x96f5296d, 0x05f7, 0x4f3c, {0x84, 0x67, 0xe4, 0x56, 0x89, 0x0e, 0x0c, 0xb5 } }
+
+ ## Include/Guid/S3SmmInitDone.h
+ gEdkiiS3SmmInitDoneGuid = { 0x8f9d4825, 0x797d, 0x48fc, { 0x84, 0x71, 0x84, 0x50, 0x25, 0x79, 0x2e, 0xf6 } }
+
+ ## Include/Guid/S3StorageDeviceInitList.h
+ gS3StorageDeviceInitListGuid = { 0x310e9b8c, 0xcf90, 0x421e, { 0x8e, 0x9b, 0x9e, 0xef, 0xb6, 0x17, 0xc8, 0xef } }
+
+ ## Include/Guid/SerialPortLibVendor.h
+ gEdkiiSerialPortLibVendorGuid = { 0xD3987D4B, 0x971A, 0x435F, { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } }
+
+ ## GUID indicates the capsule is to store Capsule On Disk file names.
+ gEdkiiCapsuleOnDiskNameGuid = { 0x98c80a4f, 0xe16b, 0x4d11, { 0x93, 0x9a, 0xab, 0xe5, 0x61, 0x26, 0x3, 0x30 } }
+
+ ## Include/Guid/MigratedFvInfo.h
+ gEdkiiMigratedFvInfoGuid = { 0xc1ab12f7, 0x74aa, 0x408d, { 0xa2, 0xf4, 0xc6, 0xce, 0xfd, 0x17, 0x98, 0x71 } }
+
+[Ppis]
+ ## Include/Ppi/AtaController.h
+ gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }}
+
+ ## Include/Ppi/UsbHostController.h
+ gPeiUsbHostControllerPpiGuid = { 0x652B38A9, 0x77F4, 0x453F, { 0x89, 0xD5, 0xE7, 0xBD, 0xC3, 0x52, 0xFC, 0x53 }}
+
+ ## Include/Ppi/Usb2HostController.h
+ gPeiUsb2HostControllerPpiGuid = { 0xfedd6305, 0xe2d7, 0x4ed5, { 0x9f, 0xaa, 0xda, 0x8, 0xe, 0x33, 0x6c, 0x22 }}
+
+ ## Include/Ppi/UsbController.h
+ gPeiUsbControllerPpiGuid = { 0x3BC1F6DE, 0x693E, 0x4547, { 0xA3, 0x00, 0x21, 0x82, 0x3C, 0xA4, 0x20, 0xB2 }}
+
+ ## Include/Ppi/UsbIo.h
+ gPeiUsbIoPpiGuid = { 0x7C29785C, 0x66B9, 0x49FC, { 0xB7, 0x97, 0x1C, 0xA5, 0x55, 0x0E, 0xF2, 0x83 }}
+
+ ## Include/Ppi/SecPerformance.h
+ gPeiSecPerformancePpiGuid = { 0x0ecc666b, 0x4662, 0x47f9, { 0x9d, 0xd5, 0xd0, 0x96, 0xff, 0x7d, 0xa4, 0x9e }}
+
+ ## Include/Ppi/SmmCommunication.h
+ gEfiPeiSmmCommunicationPpiGuid = { 0xae933e1c, 0xcc47, 0x4e38, { 0x8f, 0xe, 0xe2, 0xf6, 0x1d, 0x26, 0x5, 0xdf }}
+
+ ## Include/Ppi/SmmAccess.h
+ gPeiSmmAccessPpiGuid = { 0x268f33a9, 0xcccd, 0x48be, { 0x88, 0x17, 0x86, 0x5, 0x3a, 0xc3, 0x2e, 0xd6 }}
+
+ ## Include/Ppi/SmmControl.h
+ gPeiSmmControlPpiGuid = { 0x61c68702, 0x4d7e, 0x4f43, { 0x8d, 0xef, 0xa7, 0x43, 0x5, 0xce, 0x74, 0xc5 }}
+
+ ## Include/Ppi/PostBootScriptTable.h
+ gPeiPostScriptTablePpiGuid = { 0x88c9d306, 0x900, 0x4eb5, { 0x82, 0x60, 0x3e, 0x2d, 0xbe, 0xda, 0x1f, 0x89}}
+
+ ## Include/Ppi/SerialPortPei.h
+ gPeiSerialPortPpiGuid = { 0x490e9d85, 0x8aef, 0x4193, { 0x8e, 0x56, 0xf7, 0x34, 0xa9, 0xff, 0xac, 0x8b}}
+
+ ## Include/Ppi/UfsHostController.h
+ gEdkiiPeiUfsHostControllerPpiGuid = { 0xdc54b283, 0x1a77, 0x4cd6, { 0x83, 0xbb, 0xfd, 0xda, 0x46, 0x9a, 0x2e, 0xc6 }}
+
+ ## Include/Ppi/IpmiPpi.h
+ gPeiIpmiPpiGuid = { 0xa9731431, 0xd968, 0x4277, { 0xb7, 0x52, 0xa3, 0xa9, 0xa6, 0xae, 0x18, 0x98 }}
+
+ ## Include/Ppi/SdMmcHostController.h
+ gEdkiiPeiSdMmcHostControllerPpiGuid = { 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 }}
+
+ ## Include/Ppi/IoMmu.h
+ gEdkiiIoMmuPpiGuid = { 0x70b0af26, 0xf847, 0x4bb6, { 0xaa, 0xb9, 0xcd, 0xe8, 0x4f, 0xc6, 0x14, 0x31 } }
+
+ ## Include/Ppi/PlatformSpecificResetFilter.h
+ gEdkiiPlatformSpecificResetFilterPpiGuid = { 0x8c9f4de3, 0x7b90, 0x47ef, { 0x93, 0x8, 0x28, 0x7c, 0xec, 0xd6, 0x6d, 0xe8 } }
+
+ ## Include/Ppi/PlatformSpecificResetNotification.h
+ gEdkiiPlatformSpecificResetNotificationPpiGuid = { 0xe09f355d, 0xdae8, 0x4910, { 0xb1, 0x4a, 0x92, 0x78, 0xf, 0xdc, 0xf7, 0xcb } }
+
+ ## Include/Ppi/PlatformSpecificResetHandler.h
+ gEdkiiPlatformSpecificResetHandlerPpiGuid = { 0x75cf14ae, 0x3441, 0x49dc, { 0xaa, 0x10, 0xbb, 0x35, 0xa7, 0xba, 0x8b, 0xab } }
+
+ ## Include/Ppi/NvmExpressHostController.h
+ gEdkiiPeiNvmExpressHostControllerPpiGuid = { 0xcae3aa63, 0x676f, 0x4da3, { 0xbd, 0x50, 0x6c, 0xc5, 0xed, 0xde, 0x9a, 0xad } }
+
+ ## Include/Ppi/AtaAhciController.h
+ gEdkiiPeiAtaAhciHostControllerPpiGuid = { 0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } }
+
+ ## Include/Ppi/StorageSecurityCommand.h
+ gEdkiiPeiStorageSecurityCommandPpiGuid = { 0x35de0b4e, 0x30fb, 0x46c3, { 0xbd, 0x84, 0x1f, 0xdb, 0xa1, 0x58, 0xbb, 0x56 } }
+
+ ## Include/Ppi/AtaPassThru.h
+ gEdkiiPeiAtaPassThruPpiGuid = { 0xa16473fd, 0xd474, 0x4c89, { 0xae, 0xc7, 0x90, 0xb8, 0x3c, 0x73, 0x86, 0x9 } }
+
+ ## Include/Ppi/Debug.h
+ gEdkiiDebugPpiGuid = { 0x999e699c, 0xb013, 0x475e, { 0xb1, 0x7b, 0xf3, 0xa8, 0xae, 0x5c, 0x48, 0x75 } }
+
+ ## Include/Ppi/NvmExpressPassThru.h
+ gEdkiiPeiNvmExpressPassThruPpiGuid = { 0x6af31b2c, 0x3be, 0x46c1, { 0xb1, 0x2d, 0xea, 0x4a, 0x36, 0xdf, 0xa7, 0x4c } }
+
+ ## Include/Ppi/CapsuleOnDisk.h
+ gEdkiiPeiCapsuleOnDiskPpiGuid = { 0x71a9ea61, 0x5a35, 0x4a5d, { 0xac, 0xef, 0x9c, 0xf8, 0x6d, 0x6d, 0x67, 0xe0 } }
+ gEdkiiPeiBootInCapsuleOnDiskModePpiGuid = { 0xb08a11e4, 0xe2b7, 0x4b75, { 0xb5, 0x15, 0xaf, 0x61, 0x6, 0x68, 0xbf, 0xd1 } }
+
+[Protocols]
+ ## Load File protocol provides capability to load and unload EFI image into memory and execute it.
+ # Include/Protocol/LoadPe32Image.h
+ # This protocol is deprecated. Native EDKII module should NOT use this protocol to load/unload image.
+ # If developer need implement such functionality, they should use BasePeCoffLib.
+ gEfiLoadPeImageProtocolGuid = { 0x5CB5C776, 0x60D5, 0x45EE, { 0x88, 0x3C, 0x45, 0x27, 0x08, 0xCD, 0x74, 0x3F }}
+
+ ## Print protocols define basic print functions to print the format unicode and ascii string.
+ # Include/Protocol/Print2.h
+ gEfiPrint2ProtocolGuid = { 0xf05976ef, 0x83f1, 0x4f3d, { 0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38 } }
+ gEfiPrint2SProtocolGuid = { 0xcc252d2, 0xc106, 0x4661, { 0xb5, 0xbd, 0x31, 0x47, 0xa4, 0xf8, 0x1f, 0x92 } }
+
+ ## This protocol defines the generic memory test interfaces in Dxe phase.
+ # Include/Protocol/GenericMemoryTest.h
+ gEfiGenericMemTestProtocolGuid = { 0x309DE7F1, 0x7F5E, 0x4ACE, { 0xB4, 0x9C, 0x53, 0x1B, 0xE5, 0xAA, 0x95, 0xEF }}
+
+ ## This protocol defines the Debugger Configuration interface.
+ # Include/Protocol/DebuggerConfiguration.h
+ gEfiDebuggerConfigurationProtocolGuid = { 0x577d959c, 0xe967, 0x4546, { 0x86, 0x20, 0xc7, 0x78, 0xfa, 0xe5, 0xda, 0x05 }}
+
+ ## Fault Tolerant Write protocol provides boot-time service to do fault tolerant write capability for block devices.
+ # Include/Protocol/FaultTolerantWrite.h
+ gEfiFaultTolerantWriteProtocolGuid = { 0x3EBD9E82, 0x2C78, 0x4DE6, { 0x97, 0x86, 0x8D, 0x4B, 0xFC, 0xB7, 0xC8, 0x81 }}
+
+ ## This protocol provides boot-time service to do fault tolerant write capability for block devices in SMM environment.
+ # Include/Protocol/SmmFaultTolerantWrite.h
+ gEfiSmmFaultTolerantWriteProtocolGuid = { 0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d }}
+
+ ## This protocol is used to abstract the swap operation of boot block and backup block of boot FV.
+ # Include/Protocol/SwapAddressRange.h
+ gEfiSwapAddressRangeProtocolGuid = { 0x1259F60D, 0xB754, 0x468E, { 0xA7, 0x89, 0x4D, 0xB8, 0x5D, 0x55, 0xE8, 0x7E }}
+
+ ## This protocol is used to abstract the swap operation of boot block and backup block of boot FV in SMM environment.
+ # Include/Protocol/SmmSwapAddressRange.h
+ gEfiSmmSwapAddressRangeProtocolGuid = { 0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 }}
+
+ ## This protocol is intended for use as a means to store data in the EFI SMM environment.
+ # Include/Protocol/SmmVariableProtocol.h
+ gEfiSmmVariableProtocolGuid = { 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}
+
+ ## This protocol is intended for use as a means to mark a variable read-only after the event EFI_END_OF_DXE_EVENT_GUID is signaled.
+ # Include/Protocol/VariableLock.h
+ gEdkiiVariableLockProtocolGuid = { 0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 }}
+
+ ## Include/Protocol/VarCheck.h
+ gEdkiiVarCheckProtocolGuid = { 0xaf23b340, 0x97b4, 0x4685, { 0x8d, 0x4f, 0xa3, 0xf2, 0x81, 0x69, 0xb2, 0x1d } }
+
+ ## Include/Protocol/SmmVarCheck.h
+ gEdkiiSmmVarCheckProtocolGuid = { 0xb0d8f3c1, 0xb7de, 0x4c11, { 0xbc, 0x89, 0x2f, 0xb5, 0x62, 0xc8, 0xc4, 0x11 } }
+
+ ## This protocol is similar with DXE FVB protocol and used in the UEFI SMM evvironment.
+ # Include/Protocol/SmmFirmwareVolumeBlock.h
+ gEfiSmmFirmwareVolumeBlockProtocolGuid = { 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 }}
+
+ ## This protocol allows the error level mask for DEBUG() macros to be adjusted for DXE Phase modules
+ # Include/Guid/DebugMask.h
+ gEfiDebugMaskProtocolGuid = { 0x4c8a2451, 0xc207, 0x405b, {0x96, 0x94, 0x99, 0xea, 0x13, 0x25, 0x13, 0x41} }
+
+ ## Include/Protocol/LockBox.h
+ gEfiLockBoxProtocolGuid = { 0xbd445d79, 0xb7ad, 0x4f04, { 0x9a, 0xd8, 0x29, 0xbd, 0x20, 0x40, 0xeb, 0x3c }}
+
+ ## Include/Protocol/FormBrowserEx.h
+ gEdkiiFormBrowserExProtocolGuid = { 0x1f73b18d, 0x4630, 0x43c1, { 0xa1, 0xde, 0x6f, 0x80, 0x85, 0x5d, 0x7d, 0xa4 } }
+
+ ## Include/Protocol/EbcVmTest.h
+ gEfiEbcVmTestProtocolGuid = { 0xAAEACCFD, 0xF27B, 0x4C17, { 0xB6, 0x10, 0x75, 0xCA, 0x1F, 0x2D, 0xFB, 0x52 } }
+
+ ## Include/Protocol/EbcSimpleDebugger.h
+ gEfiEbcSimpleDebuggerProtocolGuid = { 0x2a72d11e, 0x7376, 0x40f6, { 0x9c, 0x68, 0x23, 0xfa, 0x2f, 0xe3, 0x63, 0xf1 } }
+
+ ## Include/Protocol/BootLogo.h
+ gEfiBootLogoProtocolGuid = { 0xcdea2bd3, 0xfc25, 0x4c1c, { 0xb9, 0x7c, 0xb3, 0x11, 0x86, 0x6, 0x49, 0x90 } }
+
+ # Include/Protocol/BootLogo2.h
+ gEdkiiBootLogo2ProtocolGuid = { 0x4b5dc1df, 0x1eaa, 0x48b2, { 0xa7, 0xe9, 0xea, 0xc4, 0x89, 0xa0, 0xb, 0x5c } }
+
+ ## Include/Protocol/DisplayProtocol.h
+ gEdkiiFormDisplayEngineProtocolGuid = { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } }
+
+ ## Include/Protocol/FormBrowserEx2.h
+ gEdkiiFormBrowserEx2ProtocolGuid = { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb } }
+
+ ## Include/Protocol/UfsHostController.h
+ gEdkiiUfsHostControllerProtocolGuid = { 0xebc01af5, 0x7a9, 0x489e, { 0xb7, 0xce, 0xdc, 0x8, 0x9e, 0x45, 0x9b, 0x2f } }
+
+ ## Include/Protocol/UfsHostControllerPlatform.h
+ gEdkiiUfsHcPlatformProtocolGuid = { 0x3d18ba13, 0xd9b1, 0x4dd4, {0xb9, 0x16, 0xd3, 0x07, 0x96, 0x53, 0x9e, 0xd8}}
+
+ ## Include/Protocol/EsrtManagement.h
+ gEsrtManagementProtocolGuid = { 0xa340c064, 0x723c, 0x4a9c, { 0xa4, 0xdd, 0xd5, 0xb4, 0x7a, 0x26, 0xfb, 0xb0 }}
+
+ ## Include/Protocol/SmmExitBootServices.h
+ gEdkiiSmmExitBootServicesProtocolGuid = { 0x296eb418, 0xc4c8, 0x4e05, { 0xab, 0x59, 0x39, 0xe8, 0xaf, 0x56, 0xf0, 0xa } }
+
+ ## Include/Protocol/SmmLegacyBoot.h
+ gEdkiiSmmLegacyBootProtocolGuid = { 0x85a8ab57, 0x644, 0x4110, { 0x85, 0xf, 0x98, 0x13, 0x22, 0x4, 0x70, 0x70 } }
+
+ ## Include/Protocol/SmmReadyToBoot.h
+ gEdkiiSmmReadyToBootProtocolGuid = { 0x6e057ecf, 0xfa99, 0x4f39, { 0x95, 0xbc, 0x59, 0xf9, 0x92, 0x1d, 0x17, 0xe4 } }
+
+ ## Include/Protocol/PlatformLogo.h
+ gEdkiiPlatformLogoProtocolGuid = { 0x53cd299f, 0x2bc1, 0x40c0, { 0x8c, 0x07, 0x23, 0xf6, 0x4f, 0xdb, 0x30, 0xe0 } }
+
+ ## Include/Protocol/FileExplorer.h
+ gEfiFileExplorerProtocolGuid = { 0x2C03C536, 0x4594, 0x4515, { 0x9E, 0x7A, 0xD3, 0xD2, 0x04, 0xFE, 0x13, 0x63 } }
+
+ ## Include/Protocol/IpmiProtocol.h
+ gIpmiProtocolGuid = { 0xdbc6381f, 0x5554, 0x4d14, { 0x8f, 0xfd, 0x76, 0xd7, 0x87, 0xb8, 0xac, 0xbf } }
+ gSmmIpmiProtocolGuid = { 0x5169af60, 0x8c5a, 0x4243, { 0xb3, 0xe9, 0x56, 0xc5, 0x6d, 0x18, 0xee, 0x26 } }
+
+ ## 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 } }
+
+ ## Include/Protocol/NonDiscoverableDevice.h
+ gEdkiiNonDiscoverableDeviceProtocolGuid = { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a } }
+
+ ## Include/Protocol/IoMmu.h
+ gEdkiiIoMmuProtocolGuid = { 0x4e939de9, 0xd948, 0x4b0f, { 0x88, 0xed, 0xe6, 0xe1, 0xce, 0x51, 0x7c, 0x1e } }
+
+ ## Include/Protocol/DeviceSecurity.h
+ gEdkiiDeviceSecurityProtocolGuid = { 0x5d6b38c8, 0x5510, 0x4458, { 0xb4, 0x8d, 0x95, 0x81, 0xcf, 0xa7, 0xb0, 0xd } }
+ gEdkiiDeviceIdentifierTypePciGuid = { 0x2509b2f1, 0xa022, 0x4cca, { 0xaf, 0x70, 0xf9, 0xd3, 0x21, 0xfb, 0x66, 0x49 } }
+ gEdkiiDeviceIdentifierTypeUsbGuid = { 0x7394f350, 0x394d, 0x488c, { 0xbb, 0x75, 0xc, 0xab, 0x7b, 0x12, 0xa, 0xc5 } }
+
+ ## Include/Protocol/SmmMemoryAttribute.h
+ gEdkiiSmmMemoryAttributeProtocolGuid = { 0x69b792ea, 0x39ce, 0x402d, { 0xa2, 0xa6, 0xf7, 0x21, 0xde, 0x35, 0x1d, 0xfe } }
+
+ ## Include/Protocol/SdMmcOverride.h
+ gEdkiiSdMmcOverrideProtocolGuid = { 0xeaf9e3c1, 0xc9cd, 0x46db, { 0xa5, 0xe5, 0x5a, 0x12, 0x4c, 0x83, 0x23, 0x23 } }
+
+ ## Include/Protocol/PlatformSpecificResetFilter.h
+ gEdkiiPlatformSpecificResetFilterProtocolGuid = { 0x695d7835, 0x8d47, 0x4c11, { 0xab, 0x22, 0xfa, 0x8a, 0xcc, 0xe7, 0xae, 0x7a } }
+ ## Include/Protocol/PlatformSpecificResetHandler.h
+ gEdkiiPlatformSpecificResetHandlerProtocolGuid = { 0x2df6ba0b, 0x7092, 0x440d, { 0xbd, 0x4, 0xfb, 0x9, 0x1e, 0xc3, 0xf3, 0xc1 } }
+
+ ## Include/Protocol/FirmwareManagementProgress.h
+ gEdkiiFirmwareManagementProgressProtocolGuid = { 0x1849bda2, 0x6952, 0x4e86, { 0xa1, 0xdb, 0x55, 0x9a, 0x3c, 0x47, 0x9d, 0xf1 } }
+
+ ## Include/Protocol/AtaAtapiPolicy.h
+ gEdkiiAtaAtapiPolicyProtocolGuid = { 0xe59cd769, 0x5083, 0x4f26,{ 0x90, 0x94, 0x6c, 0x91, 0x9f, 0x91, 0x6c, 0x4e } }
+
+ ## Include/Protocol/PeCoffImageEmulator.h
+ gEdkiiPeCoffImageEmulatorProtocolGuid = { 0x96f46153, 0x97a7, 0x4793, { 0xac, 0xc1, 0xfa, 0x19, 0xbf, 0x78, 0xea, 0x97 } }
+
+ ## Include/Protocol/PlatformBootManager.h
+ gEdkiiPlatformBootManagerProtocolGuid = { 0xaa17add4, 0x756c, 0x460d, { 0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } }
+
+#
+# [Error.gEfiMdeModulePkgTokenSpaceGuid]
+# 0x80000001 | Invalid value provided.
+# 0x80000002 | Reserved bits must be set to zero.
+# 0x80000003 | Incorrect progress code provided.
+# 0x80000004 | Invalid foreground color specified.
+# 0x80000005 | Invalid background color specified.
+# 0x80000006 | Incorrect error code provided.
+#
+
+[PcdsFeatureFlag]
+ ## Indicates if the platform can support update capsule across a system reset.<BR><BR>
+ # TRUE - Supports update capsule across a system reset.<BR>
+ # FALSE - Does not support update capsule across a system reset.<BR>
+ # @Prompt Enable update capsule across a system reset.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE|BOOLEAN|0x0001001d
+
+ ## Indicates if all PCD PPI services will be enabled.<BR><BR>
+ # TRUE - All PCD PPI services will be produced.<BR>
+ # FALSE - Minimal PCD PPI services (only GetService) will be produced.<BR>
+ # @Prompt Enable full PEI PCD services.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiFullPcdDatabaseEnable|TRUE|BOOLEAN|0x00010020
+
+ ## Indicates if the Device Path To Text Protocol should be produced by the platform.
+ # It can be disabled to save size.<BR><BR>
+ # TRUE - Device Path To Text Protocol will be produced.<BR>
+ # FALSE - Device Path To Text Protocol will not be produced.<BR>
+ # @Prompt Enable Device Path to Text support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathToText|TRUE|BOOLEAN|0x00010037
+
+ ## Indicates if the Device Path From Text Protocol should be produced by the platform.
+ # It can be disabled to save size.<BR><BR>
+ # TRUE - Device Path From Text Protocol will be produced.<BR>
+ # FALSE - Device Path From Text Protocol will not be produced.<BR>
+ # @Prompt Enable Device Path From Text support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|TRUE|BOOLEAN|0x00010038
+
+ ## Indicates if the UEFI variable runtime cache should be enabled.
+ # This setting only applies if SMM variables are enabled. When enabled, all variable
+ # data for Runtime Service GetVariable () and GetNextVariableName () calls is retrieved
+ # from a runtime data buffer referred to as the "runtime cache". An SMI is not triggered
+ # at all for these requests. Variables writes still trigger an SMI. This can greatly
+ # reduce overall system SMM usage as most boots tend to issue far more variable reads
+ # than writes.<BR><BR>
+ # TRUE - The UEFI variable runtime cache is enabled.<BR>
+ # FALSE - The UEFI variable runtime cache is disabled.<BR>
+ # @Prompt Enable the UEFI variable runtime cache.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|TRUE|BOOLEAN|0x00010039
+
+ ## Indicates if the statistics about variable usage will be collected. This information is
+ # stored as a vendor configuration table into the EFI system table.
+ # Set this PCD to TRUE to use VariableInfo application in MdeModulePkg\Application directory to get
+ # variable usage info. VariableInfo application will not output information if not set to TRUE.<BR><BR>
+ # TRUE - Statistics about variable usage will be collected.<BR>
+ # FALSE - Statistics about variable usage will not be collected.<BR>
+ # @Prompt Enable variable statistics collection.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics|FALSE|BOOLEAN|0x0001003f
+
+ ## Indicates if Unicode Collation Protocol will be installed.<BR><BR>
+ # TRUE - Installs Unicode Collation Protocol.<BR>
+ # FALSE - Does not install Unicode Collation Protocol.<BR>
+ # @Prompt Enable Unicode Collation support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollationSupport|TRUE|BOOLEAN|0x00010040
+
+ ## Indicates if Unicode Collation 2 Protocol will be installed.<BR><BR>
+ # TRUE - Installs Unicode Collation 2 Protocol.<BR>
+ # FALSE - Does not install Unicode Collation 2 Protocol.<BR>
+ # @Prompt Enable Unicode Collation 2 support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollation2Support|TRUE|BOOLEAN|0x00010041
+
+ ## Indicates if Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe.
+ # It could be set FALSE to save size.<BR><BR>
+ # TRUE - Installs Graphics Output Protocol on virtual handle created by ConsplitterDxe.<BR>
+ # FALSE - Does not install Graphics Output Protocol on virtual handle created by ConsplitterDxe.<BR>
+ # @Prompt Enable ConOut GOP support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE|BOOLEAN|0x00010042
+
+ ## Indicates if UGA Draw Protocol will be installed on virtual handle created by ConsplitterDxe.
+ # It could be set FALSE to save size.<BR><BR>
+ # TRUE - Installs UGA Draw Protocol on virtual handle created by ConsplitterDxe.<BR>
+ # FALSE - Does not install UGA Draw Protocol on virtual handle created by ConsplitterDxe.<BR>
+ # @Prompt Enable ConOut UGA support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|TRUE|BOOLEAN|0x00010043
+
+ ## Indicates PeiCore will first search TE section from the PEIM to load the image, or PE32 section, when PeiCore dispatches a PEI module.
+ # This PCD is used to tune PEI phase performance to reduce the search image time.
+ # It can be set according to the generated image section type.<BR><BR>
+ # TRUE - PeiCore will first search TE section from PEIM to load the image, if TE section is not found, then PeiCore will search PE section.<BR>
+ # FALSE - PeiCore will first search PE section from PEIM to load the image.<BR>
+ # @Prompt PeiCore search TE section first.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|TRUE|BOOLEAN|0x00010044
+
+ ## Indicates if to turn off the support of legacy usb. So legacy usb device driver can not make use of SMI
+ # interrupt to access usb device in the case of absence of usb stack.
+ # DUET platform requires the token to be TRUE.<BR><BR>
+ # TRUE - Turn off usb legacy support.<BR>
+ # FALSE - Does not turn off usb legacy support.<BR>
+ # @Prompt Turn off USB legacy support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|FALSE|BOOLEAN|0x00010047
+
+ ## Indicates if HiiImageProtocol will be installed.
+ # FALSE is for size reduction.<BR><BR>
+ # TRUE - Installs HiiImageProtocol.<BR>
+ # FALSE - Does not install HiiImageProtocol.<BR>
+ # @Prompt Enable HII image support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol|TRUE|BOOLEAN|0x00010100
+
+ ## Indicates if USB KeyBoard Driver disables the default keyboard layout.
+ # The default keyboard layout serves as the backup when no keyboard layout can be retrieved
+ # from HII database.<BR><BR>
+ # TRUE - USB KeyBoard Driver will disable the default keyboard layout.<BR>
+ # FALSE - USB KeyBoard Driver will not disable the default keyboard layout.<BR>
+ # @Prompt Disable default keyboard layout in USB KeyBoard Driver.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDisableDefaultKeyboardLayoutInUsbKbDriver|FALSE|BOOLEAN|0x00010200
+
+ ## Indicates if HelloWorld Application will print the verbose information.
+ # This PCD is a sample to explain FeatureFlag PCD usage.<BR><BR>
+ # TRUE - HelloWorld Application will print the verbose information.<BR>
+ # FALSE - HelloWorld Application will not print the verbose information.<BR>
+ # @Prompt Enable HelloWorld print.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable|TRUE|BOOLEAN|0x0001200a
+
+ ## Indicates if FULL FTW protocol services (total six APIs) will be produced.<BR><BR>
+ # TRUE - Produces FULL FTW protocol services (total six APIs).<BR>
+ # FALSE - Only FTW Write service is available.<BR>
+ # @Prompt Enable FULL FTW services.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable|TRUE|BOOLEAN|0x0001200b
+
+ ## Indicates if DXE IPL supports the UEFI decompression algorithm.<BR><BR>
+ # TRUE - DXE IPL will support UEFI decompression.<BR>
+ # FALSE - DXE IPL will not support UEFI decompression to save space.<BR>
+ # @Prompt Enable UEFI decompression support in DXE IPL.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress|TRUE|BOOLEAN|0x0001200c
+
+ ## Indicates if PciBus driver supports the hot plug device.<BR><BR>
+ # TRUE - PciBus driver supports the hot plug device.<BR>
+ # FALSE - PciBus driver doesn't support the hot plug device.<BR>
+ # @Prompt Enable PciBus hot plug device support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport|TRUE|BOOLEAN|0x0001003d
+
+ ## Indicates if the PciBus driver probes non-standard, such as 2K/1K/512, granularity for PCI to PCI bridge I/O window.<BR><BR>
+ # TRUE - PciBus driver probes non-standard granularity for PCI to PCI bridge I/O window.<BR>
+ # FALSE - PciBus driver doesn't probe non-standard granularity for PCI to PCI bridge I/O window.<BR>
+ # @Prompt Enable PCI bridge IO alignment probe.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBridgeIoAlignmentProbe|FALSE|BOOLEAN|0x0001004e
+
+ ## Indicates if PEI phase StatusCode will be replayed in DXE phase.<BR><BR>
+ # TRUE - Replays PEI phase StatusCode in DXE phased.<BR>
+ # FALSE - Does not replay PEI phase StatusCode in DXE phase.<BR>
+ # @Prompt Enable PEI StatusCode replay in DXE phase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeReplayIn|FALSE|BOOLEAN|0x0001002d
+
+ ## Indicates if ACPI SDT protocol will be installed.<BR><BR>
+ # TRUE - Installs ACPI SDT protocol.<BR>
+ # FALSE - Does not install ACPI SDT protocol.<BR>
+ # @Prompt Enable ACPI SDT support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|FALSE|BOOLEAN|0x0001004d
+
+ ## Indicates if the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol are enabled.
+ # The default value for this PCD is false to disable support for unaligned PCI I/O Protocol requests.<BR><BR>
+ # TRUE - Enables the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol.<BR>
+ # FALSE - Disables the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol.<BR>
+ # @Prompt Enable unaligned PCI I/O support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnalignedPciIoEnable|FALSE|BOOLEAN|0x0001003e
+
+ ## Indicates if TEXT statement is always set to GrayOut statement in HII Form Browser.<BR><BR>
+ # TRUE - TEXT statement will always be set to GrayOut.<BR>
+ # FALSE - TEXT statement will be set to GrayOut only when GrayOut condition is TRUE.<BR>
+ # @Prompt Always GrayOut TEXT statement.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement|FALSE|BOOLEAN|0x0001004f
+
+ ## Indicates if unselectable menu should be gray out in HII Form Browser.<BR><BR>
+ # TRUE - The unselectable menu will be set to GrayOut.<BR>
+ # FALSE - The menu will be show as normal menu entry even if it is not selectable.<BR>
+ # @Prompt GrayOut read only menu.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu|FALSE|BOOLEAN|0x00010070
+
+ ## Indicates if recovery from IDE disk will be supported.<BR><BR>
+ # TRUE - Supports recovery from IDE disk.<BR>
+ # FALSE - Does not support recovery from IDE disk.<BR>
+ # @Prompt Enable recovery on IDE disk.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryOnIdeDisk|TRUE|BOOLEAN|0x00010060
+
+ ## Indicates if recovery from FAT floppy disk will be supported.<BR><BR>
+ # TRUE - Supports recovery from FAT floppy disk.<BR>
+ # FALSE - Does not support recovery from FAT floppy disk.<BR>
+ # @Prompt Enable recovery on FAT floppy disk.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryOnFatFloppyDisk|TRUE|BOOLEAN|0x00010061
+
+ ## Indicates if recovery from data CD will be supported.<BR><BR>
+ # TRUE - Supports recovery from data CD.<BR>
+ # FALSE - Does not support recovery from data CD.<BR>
+ # @Prompt Enable recovery on data CD.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryOnDataCD|TRUE|BOOLEAN|0x00010062
+
+ ## Indicates if recovery from FAT USB disk will be supported.<BR><BR>
+ # TRUE - Supports recovery from USB disk.<BR>
+ # FALSE - Does not support recovery from USB disk.<BR>
+ # @Prompt Enable recovery on FAT USB disk.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryOnFatUsbDisk|TRUE|BOOLEAN|0x00010063
+
+ ## Indicates if S3 performance data will be supported in ACPI FPDT table.<BR><BR>
+ # TRUE - S3 performance data will be supported in ACPI FPDT table.<BR>
+ # FALSE - S3 performance data will not be supported in ACPI FPDT table.<BR>
+ # @Prompt Enable S3 performance data support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support|TRUE|BOOLEAN|0x00010064
+
+ ## Indicates if PS2 keyboard does a extended verification during start.
+ # Add this PCD mainly consider the use case of simulator. This PCD maybe set to FALSE for
+ # 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
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPs2KbdExtendedVerification|TRUE|BOOLEAN|0x00010072
+
+ ## 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
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010073
+
+ ## Indicates if HII data and configuration has been exported.<BR><BR>
+ # Add this PCD mainly consider the use case of simulator. This PCD maybe set to FALSE for
+ # simulator platform because the performance cost for this feature.
+ # TRUE - Export HII data and configuration data.<BR>
+ # FALSE - Does not export HII data and configuration.<BR>
+ # @Prompt Enable export HII data and configuration to be used in OS runtime.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|TRUE|BOOLEAN|0x00010074
+
+ ## 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
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPs2MouseExtendedVerification|TRUE|BOOLEAN|0x00010075
+
+ ## Indicates whether 64-bit PCI MMIO BARs should degrade to 32-bit in the presence of an option ROM
+ # On X64 platforms, Option ROMs may contain code that executes in the context of a legacy BIOS (CSM),
+ # which requires that all PCI MMIO BARs are located below 4 GB
+ # TRUE - All PCI MMIO BARs of a device will be located below 4 GB if it has an option ROM
+ # FALSE - PCI MMIO BARs of a device may be located above 4 GB even if it has an option ROM
+ # @Prompt Degrade 64-bit PCI MMIO BARs for legacy BIOS option ROMs
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom|TRUE|BOOLEAN|0x0001003a
+
+ ## Indicates if the platform can support process non-reset capsule image at runtime.<BR><BR>
+ # TRUE - Supports process non-reset capsule image at runtime.<BR>
+ # FALSE - Does not support process non-reset capsule image at runtime.<BR>
+ # @Prompt Enable process non-reset capsule image at runtime.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportProcessCapsuleAtRuntime|FALSE|BOOLEAN|0x00010079
+
+[PcdsFeatureFlag.IA32, PcdsFeatureFlag.ARM, PcdsFeatureFlag.AARCH64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom|FALSE|BOOLEAN|0x0001003a
+
+[PcdsFeatureFlag.IA32, PcdsFeatureFlag.X64]
+ ## Indicates if DxeIpl should switch to long mode to enter DXE phase.
+ # It is assumed that 64-bit DxeCore is built in firmware if it is true; otherwise 32-bit DxeCore
+ # is built in firmware.<BR><BR>
+ # TRUE - DxeIpl will load a 64-bit DxeCore and switch to long mode to hand over to DxeCore.<BR>
+ # FALSE - DxeIpl will load a 32-bit DxeCore and perform stack switch to hand over to DxeCore.<BR>
+ # @Prompt DxeIpl switch to long mode.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE|BOOLEAN|0x0001003b
+
+ ## Indicates if DxeIpl should rebuild page tables. This flag only
+ # makes sense in the case where the DxeIpl and the DxeCore are both X64.<BR><BR>
+ # TRUE - DxeIpl will rebuild page tables.<BR>
+ # FALSE - DxeIpl will not rebuild page tables.<BR>
+ # @Prompt DxeIpl rebuild page tables.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables|TRUE|BOOLEAN|0x0001003c
+
+[PcdsFixedAtBuild]
+ ## Flag of enabling/disabling the feature of Loading Module at Fixed Address.<BR><BR>
+ # 0xFFFFFFFFFFFFFFFF: Enable the feature as fixed offset to TOLM.<BR>
+ # 0: Disable the feature.<BR>
+ # Other Value: Enable the feature as fixed absolute address, and the value is the top memory address.<BR>
+ # @Prompt Enable LMFA feature.
+ # @Expression 0x80000001 | (gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable == 0xFFFFFFFFFFFFFFFF || gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable <= 0x0FFFFFFFFFFFFFFF)
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable|0|UINT64|0x30001015
+
+ ## Progress Code for OS Loader LoadImage start.<BR><BR>
+ # PROGRESS_CODE_OS_LOADER_LOAD = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03058000<BR>
+ # @Prompt Progress Code for OS Loader LoadImage start.
+ # @ValidList 0x80000003 | 0x03058000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad|0x03058000|UINT32|0x30001030
+
+ ## Progress Code for OS Loader StartImage start.<BR><BR>
+ # PROGRESS_CODE_OS_LOADER_START = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03058001<BR>
+ # @Prompt Progress Code for OS Loader StartImage start.
+ # @ValidList 0x80000003 | 0x03058001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart|0x03058001|UINT32|0x30001031
+
+ ## Progress Code for S3 Suspend start.<BR><BR>
+ # PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03078000<BR>
+ # @Prompt Progress Code for S3 Suspend start.
+ # @ValidList 0x80000003 | 0x03078000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart|0x03078000|UINT32|0x30001032
+
+ ## Progress Code for S3 Suspend end.<BR><BR>
+ # PROGRESS_CODE_S3_SUSPEND_END = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03078001<BR>
+ # @Prompt Progress Code for S3 Suspend end.
+ # @ValidList 0x80000003 | 0x03078001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd|0x03078001|UINT32|0x30001033
+
+ ## Error Code for SetVariable failure.<BR><BR>
+ # EDKII_ERROR_CODE_SET_VARIABLE = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000002)) = 0x03058002<BR>
+ # @Prompt Error Code for SetVariable failure.
+ # @ValidList 0x80000006 | 0x03058002
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|UINT32|0x30001040
+
+ ## Mask to control the NULL address detection in code for different phases.
+ # If enabled, accessing NULL address in UEFI or SMM code can be caught.<BR><BR>
+ # BIT0 - Enable NULL pointer detection for UEFI.<BR>
+ # BIT1 - Enable NULL pointer detection for SMM.<BR>
+ # BIT2..5 - Reserved for future uses.<BR>
+ # BIT6 - Enable non-stop mode.<BR>
+ # BIT7 - Disable NULL pointer detection just after EndOfDxe. <BR>
+ # This is a workaround for those unsolvable NULL access issues in
+ # OptionROM, boot loader, etc. It can also help to avoid unnecessary
+ # exception caused by legacy memory (0-4095) access after EndOfDxe,
+ # such as Windows 7 boot on Qemu.<BR>
+ # @Prompt Enable NULL address detection.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask|0x0|UINT8|0x30001050
+
+ ## Init Value in Temp Stack to be shared between SEC and PEI_CORE
+ # SEC fills the full temp stack with this values. When switch stack, PeiCore can check
+ # this value in the temp stack to know how many stack has been used.
+ # @Prompt Init Value in Temp Stack
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack|0x5AA55AA5|UINT32|0x30001051
+
+ ## Indicates which type allocation need guard page.
+ #
+ # If a bit is set, a head guard page and a tail guard page will be added just
+ # before and after corresponding type of pages allocated if there's enough
+ # free pages for all of them. The page allocation for the type related to
+ # cleared bits keeps the same as ususal.
+ #
+ # This PCD is only valid if BIT0 and/or BIT2 are set in PcdHeapGuardPropertyMask.
+ #
+ # Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>
+ # EfiReservedMemoryType 0x0000000000000001<BR>
+ # EfiLoaderCode 0x0000000000000002<BR>
+ # EfiLoaderData 0x0000000000000004<BR>
+ # EfiBootServicesCode 0x0000000000000008<BR>
+ # EfiBootServicesData 0x0000000000000010<BR>
+ # EfiRuntimeServicesCode 0x0000000000000020<BR>
+ # EfiRuntimeServicesData 0x0000000000000040<BR>
+ # EfiConventionalMemory 0x0000000000000080<BR>
+ # EfiUnusableMemory 0x0000000000000100<BR>
+ # EfiACPIReclaimMemory 0x0000000000000200<BR>
+ # EfiACPIMemoryNVS 0x0000000000000400<BR>
+ # EfiMemoryMappedIO 0x0000000000000800<BR>
+ # EfiMemoryMappedIOPortSpace 0x0000000000001000<BR>
+ # EfiPalCode 0x0000000000002000<BR>
+ # EfiPersistentMemory 0x0000000000004000<BR>
+ # OEM Reserved 0x4000000000000000<BR>
+ # OS Reserved 0x8000000000000000<BR>
+ # e.g. LoaderCode+LoaderData+BootServicesCode+BootServicesData are needed, 0x1E should be used.<BR>
+ # @Prompt The memory type mask for Page Guard.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType|0x0|UINT64|0x30001052
+
+ ## Indicates which type allocation need guard page.
+ #
+ # If a bit is set, a head guard page and a tail guard page will be added just
+ # before and after corresponding type of pages which the allocated pool occupies,
+ # if there's enough free memory for all of them. The pool allocation for the
+ # type related to cleared bits keeps the same as ususal.
+ #
+ # This PCD is only valid if BIT1 and/or BIT3 are set in PcdHeapGuardPropertyMask.
+ #
+ # Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>
+ # EfiReservedMemoryType 0x0000000000000001<BR>
+ # EfiLoaderCode 0x0000000000000002<BR>
+ # EfiLoaderData 0x0000000000000004<BR>
+ # EfiBootServicesCode 0x0000000000000008<BR>
+ # EfiBootServicesData 0x0000000000000010<BR>
+ # EfiRuntimeServicesCode 0x0000000000000020<BR>
+ # EfiRuntimeServicesData 0x0000000000000040<BR>
+ # EfiConventionalMemory 0x0000000000000080<BR>
+ # EfiUnusableMemory 0x0000000000000100<BR>
+ # EfiACPIReclaimMemory 0x0000000000000200<BR>
+ # EfiACPIMemoryNVS 0x0000000000000400<BR>
+ # EfiMemoryMappedIO 0x0000000000000800<BR>
+ # EfiMemoryMappedIOPortSpace 0x0000000000001000<BR>
+ # EfiPalCode 0x0000000000002000<BR>
+ # EfiPersistentMemory 0x0000000000004000<BR>
+ # OEM Reserved 0x4000000000000000<BR>
+ # OS Reserved 0x8000000000000000<BR>
+ # e.g. LoaderCode+LoaderData+BootServicesCode+BootServicesData are needed, 0x1E should be used.<BR>
+ # @Prompt The memory type mask for Pool Guard.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType|0x0|UINT64|0x30001053
+
+ ## This mask is to control Heap Guard behavior.
+ #
+ # Note:
+ # a) Heap Guard is for debug purpose and should not be enabled in product
+ # BIOS.
+ # b) Due to the limit of pool memory implementation and the alignment
+ # requirement of UEFI spec, BIT7 is a try-best setting which cannot
+ # guarantee that the returned pool is exactly adjacent to head guard
+ # page or tail guard page.
+ # c) UEFI freed-memory guard and UEFI pool/page guard cannot be enabled
+ # at the same time.
+ #
+ # BIT0 - Enable UEFI page guard.<BR>
+ # BIT1 - Enable UEFI pool guard.<BR>
+ # BIT2 - Enable SMM page guard.<BR>
+ # BIT3 - Enable SMM pool guard.<BR>
+ # BIT4 - Enable UEFI freed-memory guard (Use-After-Free memory detection).<BR>
+ # BIT6 - Enable non-stop mode.<BR>
+ # BIT7 - The direction of Guard Page for Pool Guard.
+ # 0 - The returned pool is near the tail guard page.<BR>
+ # 1 - The returned pool is near the head guard page.<BR>
+ # @Prompt The Heap Guard feature mask
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask|0x0|UINT8|0x30001054
+
+ ## Indicates if UEFI Stack Guard will be enabled.
+ # If enabled, stack overflow in UEFI can be caught, preventing chaotic consequences.<BR><BR>
+ # TRUE - UEFI Stack Guard will be enabled.<BR>
+ # FALSE - UEFI Stack Guard will be disabled.<BR>
+ # @Prompt Enable UEFI Stack Guard.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|FALSE|BOOLEAN|0x30001055
+
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+ ## Dynamic type PCD can be registered callback function for Pcd setting action.
+ # PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
+ # for a dynamic PCD used in PEI phase.
+ # @Prompt Max PEI PCD callback number per PCD entry.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry|0x08|UINT32|0x0001000f
+
+ ## VPD type PCD allows a developer to point to an absolute physical address PcdVpdBaseAddress
+ # to store PCD value.
+ # @Prompt VPD base address.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0|UINT32|0x00010010
+
+ ## Maximum stack size for PeiCore.
+ # @Prompt Maximum stack size for PeiCore.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize|0x20000|UINT32|0x00010032
+
+ ## The maximum size of a single non-HwErr type variable.
+ # @Prompt Maximum variable size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x400|UINT32|0x30000003
+
+ ## The maximum size of a single authenticated variable.
+ # The value is 0 as default for compatibility that maximum authenticated variable size is specified by PcdMaxVariableSize.
+ # @Prompt Maximum authenticated variable size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x00|UINT32|0x30000009
+
+ ## The maximum size of a single non-authenticated volatile variable.
+ # The default value is 0 for compatibility: in that case, the maximum
+ # non-authenticated volatile variable size remains specified by
+ # PcdMaxVariableSize. Only the MdeModulePkg/Universal/Variable/RuntimeDxe
+ # driver supports this PCD.
+ # @Prompt Maximum non-authenticated volatile variable size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize|0x00|UINT32|0x3000000a
+
+ ## The maximum size of single hardware error record variable.<BR><BR>
+ # In IA32/X64 platforms, this value should be larger than 1KB.<BR>
+ # In IA64 platforms, this value should be larger than 128KB.<BR>
+ # @Prompt Maximum HwErr variable size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize|0x8000|UINT32|0x30000004
+
+ ## The size of reserved HwErr variable space. Note that this value must be less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER)).
+ # In EdkII implementation, HwErr type variable is stored with common non-volatile variables in the same NV region.
+ # so the platform integrator should ensure this value is less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER)).
+ # this value is used to guarantee the space of HwErr type variable and not populated by common variable.
+ # @Prompt HwErr variable storage size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize|0x0000|UINT32|0x30000006
+
+ ## The size of maximum user NV variable space.<BR><BR>
+ # Note that this value must be less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize).<BR>
+ # If the value is 0, it means user variable share the same NV storage with system variable,
+ # this is designed to keep the compatibility for the platform that does not allocate special region for user variable.<BR>
+ # If the value is non-0, the below 4 types of variables will be regarded as System Variable after EndOfDxe, their property could be got by VarCheck protocol,
+ # otherwise the variable will be regarded as user variable.<BR>
+ # 1) UEFI defined variables (gEfiGlobalVariableGuid and gEfiImageSecurityDatabaseGuid(auth variable) variables at least).<BR>
+ # 2) Variables managed by Variable driver internally.<BR>
+ # 3) Variables need to be locked, they MUST be set by VariableLock protocol.<BR>
+ # 4) Important variables during platform boot, their property SHOULD be set by VarCheck protocol.<BR>
+ # The PCD is used to guarantee the space of system variable and not populated by user variable.<BR>
+ # @Prompt Maximum user NV variable space size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize|0x00|UINT32|0x00000009
+
+ ## The size of NV variable space reserved at UEFI boottime.<BR><BR>
+ # Note that this value must be less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize).<BR>
+ # In EdkII implementation, variable driver can reserved some NV storage region for boottime settings.
+ # So at UEFI runtime, the variable service consumer can not exhaust full NV storage region.<BR>
+ # Then the common NV variable space size at boottime will be
+ # (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize),<BR>
+ # and the common NV variable space size at runtime will be
+ # (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize) - PcdBoottimeReservedNvVariableSpaceSize.<BR>
+ # @Prompt Boottime reserved NV variable space size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize|0x00|UINT32|0x30000007
+
+ ## Reclaim variable space at EndOfDxe.<BR><BR>
+ # The value is FALSE as default for compatibility that variable driver tries to reclaim variable space at ReadyToBoot event.<BR>
+ # If the value is set to TRUE, variable driver tries to reclaim variable space at EndOfDxe event.<BR>
+ # @Prompt Reclaim variable space at EndOfDxe.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe|FALSE|BOOLEAN|0x30000008
+
+ ## The size of volatile buffer. This buffer is used to store VOLATILE attribute variables.
+ # @Prompt Variable storage size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005
+
+ ## FFS filename to find the ACPI tables.
+ # @Prompt FFS name of ACPI tables storage.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile|{ 0x25, 0x4e, 0x37, 0x7e, 0x01, 0x8e, 0xee, 0x4f, 0x87, 0xf2, 0x39, 0xc, 0x23, 0xc6, 0x6, 0xcd }|VOID*|0x30000016
+
+ ## FFS filename to find the capsule coalesce image.
+ # @Prompt FFS name of capsule coalesce image.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleCoalesceFile|{ 0xA6, 0xE4, 0xFD, 0xF7, 0x4C, 0x29, 0x3c, 0x49, 0xB5, 0x0F, 0x97, 0x34, 0x55, 0x3B, 0xB7, 0x57 }|VOID*|0x30000017
+
+ ## Maximum number of performance log entries during PEI phase.
+ # Use PcdMaxPeiPerformanceLogEntries16 if the number of entries required is
+ # more than 255.
+ # @Prompt Maximum number of PEI performance log entries.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries|40|UINT8|0x0001002f
+
+ ## Maximum number of performance log entries during PEI phase.
+ # If set to 0, then PcdMaxPeiPerformanceLogEntries determines the number of
+ # entries. If greater than 0, then this PCD determines the number of entries,
+ # and PcdMaxPeiPerformanceLogEntries is ignored.
+ # @Prompt Maximum number of PEI performance log entries.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries16|0|UINT16|0x00010035
+
+ ## Indicates the 16550 serial port registers are in MMIO space, or in I/O space. Default is I/O space.<BR><BR>
+ # TRUE - 16550 serial port registers are in MMIO space.<BR>
+ # FALSE - 16550 serial port registers are in I/O space.<BR>
+ # @Prompt Serial port registers use MMIO.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|FALSE|BOOLEAN|0x00020000
+
+ ## Indicates the access width for 16550 serial port registers.
+ # Default is 8-bit access mode.<BR><BR>
+ # 8 - 16550 serial port registers are accessed in 8-bit width.<BR>
+ # 32 - 16550 serial port registers are accessed in 32-bit width.<BR>
+ # @Prompt Serial port register access width.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterAccessWidth|8|UINT8|0x00020007
+
+ ## Indicates if the 16550 serial port hardware flow control will be enabled. Default is FALSE.<BR><BR>
+ # TRUE - 16550 serial port hardware flow control will be enabled.<BR>
+ # FALSE - 16550 serial port hardware flow control will be disabled.<BR>
+ # @Prompt Enable serial port hardware flow control.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE|BOOLEAN|0x00020001
+
+ ## Indicates if the 16550 serial Tx operations will be blocked if DSR is not asserted (no cable). Default is FALSE.
+ # This PCD is ignored if PcdSerialUseHardwareFlowControl is FALSE.<BR><BR>
+ # TRUE - 16550 serial Tx operations will be blocked if DSR is not asserted.<BR>
+ # FALSE - 16550 serial Tx operations will not be blocked if DSR is not asserted.<BR>
+ # @Prompt Enable serial port cable detetion.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable|FALSE|BOOLEAN|0x00020006
+
+ ## Base address of 16550 serial port registers in MMIO or I/O space. Default is 0x3F8.
+ # @Prompt Base address of serial port registers.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x03F8|UINT64|0x00020002
+
+ ## Baud rate for the 16550 serial port. Default is 115200 baud.
+ # @Prompt Baud rate for serial port.
+ # @ValidList 0x80000001 | 921600, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 7200, 4800, 3600, 2400, 2000, 1800, 1200, 600, 300, 150, 134, 110, 75, 50
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate|115200|UINT32|0x00020003
+
+ ## Line Control Register (LCR) for the 16550 serial port. This encodes data bits, parity, and stop bits.<BR><BR>
+ # BIT1..BIT0 - Data bits. 00b = 5 bits, 01b = 6 bits, 10b = 7 bits, 11b = 8 bits<BR>
+ # BIT2 - Stop Bits. 0 = 1 stop bit. 1 = 1.5 stop bits if 5 data bits selected, otherwise 2 stop bits.<BR>
+ # BIT5..BIT3 - Parity. xx0b = No Parity, 001b = Odd Parity, 011b = Even Parity, 101b = Mark Parity, 111b=Stick Parity<BR>
+ # BIT7..BIT6 - Reserved. Must be 0.<BR>
+ #
+ # Default is No Parity, 8 Data Bits, 1 Stop Bit.<BR>
+ # @Prompt Serial port Line Control settings.
+ # @Expression 0x80000002 | (gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl & 0xC0) == 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03|UINT8|0x00020004
+
+ ## FIFO Control Register (FCR) for the 16550 serial port.<BR><BR>
+ # BIT0 - FIFO Enable. 0 = Disable FIFOs. 1 = Enable FIFOs.<BR>
+ # BIT1 - Clear receive FIFO. 1 = Clear FIFO.<BR>
+ # BIT2 - Clear transmit FIFO. 1 = Clear FIFO.<BR>
+ # BIT4..BIT3 - Reserved. Must be 0.<BR>
+ # BIT5 - Enable 64-byte FIFO. 0 = Disable 64-byte FIFO. 1 = Enable 64-byte FIFO<BR>
+ # BIT7..BIT6 - Reserved. Must be 0.<BR>
+ #
+ # Default is to enable and clear all FIFOs.<BR>
+ # @Prompt Serial port FIFO Control settings.
+ # @Expression 0x80000002 | (gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl & 0xD8) == 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07|UINT8|0x00020005
+
+ ## Maximum address that the DXE Core will allocate the EFI_SYSTEM_TABLE_POINTER
+ # structure. The default value for this PCD is 0, which means that the DXE Core
+ # will allocate the buffer from the EFI_SYSTEM_TABLE_POINTER structure on a 4MB
+ # boundary as close to the top of memory as feasible. If this PCD is set to a
+ # value other than 0, then the DXE Core will first attempt to allocate the
+ # EFI_SYSTEM_TABLE_POINTER structure on a 4MB boundary below the address specified
+ # by this PCD, and if that allocation fails, retry the allocation on a 4MB
+ # boundary as close to the top of memory as feasible.
+ # @Prompt Maximum Efi System Table Pointer address.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress|0x0|UINT64|0x30001027
+
+ ## Indicates if to shadow PEIM on S3 boot path after memory is ready.<BR><BR>
+ # TRUE - Shadow PEIM on S3 boot path after memory is ready.<BR>
+ # FALSE - Not shadow PEIM on S3 boot path after memory is ready.<BR>
+ # @Prompt Shadow Peim On S3 Boot.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnS3Boot|FALSE|BOOLEAN|0x30001028
+
+ ## Indicates if to shadow PEIM and PeiCore after memory is ready.<BR><BR>
+ # This PCD is used on other boot path except for S3 boot.
+ # TRUE - Shadow PEIM and PeiCore after memory is ready.<BR>
+ # FALSE - Not shadow PEIM after memory is ready.<BR>
+ # @Prompt Shadow Peim and PeiCore on boot
+ gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot|TRUE|BOOLEAN|0x30001029
+
+ ## Enable the feature that evacuate temporary memory to permanent memory or not<BR><BR>
+ # Set FALSE as default, if the developer need this feature to avoid this vulnerability, please
+ # enable it to shadow all PEIMs no matter the behavior controled by PcdShadowPeimOnBoot or
+ # PcdShadowPeimOnS3Boot<BR>
+ # TRUE - Evacuate temporary memory, the actions include copy memory, convert PPI pointers and so on.<BR>
+ # FALSE - Do nothing, for example, no copy memory, no convert PPI pointers and so on.<BR>
+ # @Prompt Evacuate temporary memory to permanent memory
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolumes|FALSE|BOOLEAN|0x3000102A
+
+ ## The mask is used to control memory profile behavior.<BR><BR>
+ # BIT0 - Enable UEFI memory profile.<BR>
+ # BIT1 - Enable SMRAM profile.<BR>
+ # BIT7 - Disable recording at the start.<BR>
+ # @Prompt Memory Profile Property.
+ # @Expression 0x80000002 | (gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask & 0x7C) == 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask|0x0|UINT8|0x30001041
+
+ ## The mask is used to control SmiHandlerProfile behavior.<BR><BR>
+ # BIT0 - Enable SmiHandlerProfile.<BR>
+ # @Prompt SmiHandlerProfile Property.
+ # @Expression 0x80000002 | (gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask & 0xFE) == 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask|0|UINT8|0x00000108
+
+ ## This flag is to control which memory types of alloc info will be recorded by DxeCore & SmmCore.<BR><BR>
+ # For SmmCore, only EfiRuntimeServicesCode and EfiRuntimeServicesData are valid.<BR>
+ #
+ # Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>
+ # EfiReservedMemoryType 0x0001<BR>
+ # EfiLoaderCode 0x0002<BR>
+ # EfiLoaderData 0x0004<BR>
+ # EfiBootServicesCode 0x0008<BR>
+ # EfiBootServicesData 0x0010<BR>
+ # EfiRuntimeServicesCode 0x0020<BR>
+ # EfiRuntimeServicesData 0x0040<BR>
+ # EfiConventionalMemory 0x0080<BR>
+ # EfiUnusableMemory 0x0100<BR>
+ # EfiACPIReclaimMemory 0x0200<BR>
+ # EfiACPIMemoryNVS 0x0400<BR>
+ # EfiMemoryMappedIO 0x0800<BR>
+ # EfiMemoryMappedIOPortSpace 0x1000<BR>
+ # EfiPalCode 0x2000<BR>
+ # EfiPersistentMemory 0x4000<BR>
+ # OEM Reserved 0x4000000000000000<BR>
+ # OS Reserved 0x8000000000000000<BR>
+ #
+ # e.g. Reserved+ACPINvs+ACPIReclaim+RuntimeCode+RuntimeData are needed, 0x661 should be used.<BR>
+ #
+ # @Prompt Memory profile memory type.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType|0x0|UINT64|0x30001042
+
+ ## This PCD is to control which drivers need memory profile data.<BR><BR>
+ # For example:<BR>
+ # One image only (Shell):<BR>
+ # Header GUID<BR>
+ # {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,<BR>
+ # 0x7F, 0xFF, 0x04, 0x00}<BR>
+ # Two or more images (Shell + WinNtSimpleFileSystem):<BR>
+ # {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,<BR>
+ # 0x7F, 0x01, 0x04, 0x00,<BR>
+ # 0x04, 0x06, 0x14, 0x00, 0x8B, 0xE1, 0x25, 0x9C, 0xBA, 0x76, 0xDA, 0x43, 0xA1, 0x32, 0xDB, 0xB0, 0x99, 0x7C, 0xEF, 0xEF,<BR>
+ # 0x7F, 0xFF, 0x04, 0x00}<BR>
+ # @Prompt Memory profile driver path.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath|{0x0}|VOID*|0x00001043
+
+ ## Set image protection policy. The policy is bitwise.
+ # If a bit is set, the image will be protected by DxeCore if it is aligned.
+ # The code section becomes read-only, and the data section becomes non-executable.
+ # If a bit is clear, nothing will be done to image code/data sections.<BR><BR>
+ # BIT0 - Image from unknown device. <BR>
+ # BIT1 - Image from firmware volume.<BR>
+ # <BR>
+ # Note: If a bit is cleared, the data section could be still non-executable if
+ # PcdDxeNxMemoryProtectionPolicy is enabled for EfiLoaderData, EfiBootServicesData
+ # and/or EfiRuntimeServicesData.<BR>
+ # <BR>
+ # @Prompt Set image protection policy.
+ # @ValidRange 0x80000002 | 0x00000000 - 0x0000001F
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy|0x00000002|UINT32|0x00001047
+
+ ## Set DXE memory protection policy. The policy is bitwise.
+ # If a bit is set, memory regions of the associated type will be mapped
+ # non-executable.<BR>
+ # If a bit is cleared, nothing will be done to associated type of memory.<BR>
+ # <BR>
+ # Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>
+ # EfiReservedMemoryType 0x0001<BR>
+ # EfiLoaderCode 0x0002<BR>
+ # EfiLoaderData 0x0004<BR>
+ # EfiBootServicesCode 0x0008<BR>
+ # EfiBootServicesData 0x0010<BR>
+ # EfiRuntimeServicesCode 0x0020<BR>
+ # EfiRuntimeServicesData 0x0040<BR>
+ # EfiConventionalMemory 0x0080<BR>
+ # EfiUnusableMemory 0x0100<BR>
+ # EfiACPIReclaimMemory 0x0200<BR>
+ # EfiACPIMemoryNVS 0x0400<BR>
+ # EfiMemoryMappedIO 0x0800<BR>
+ # EfiMemoryMappedIOPortSpace 0x1000<BR>
+ # EfiPalCode 0x2000<BR>
+ # EfiPersistentMemory 0x4000<BR>
+ # OEM Reserved 0x4000000000000000<BR>
+ # OS Reserved 0x8000000000000000<BR>
+ #
+ # NOTE: User must NOT set NX protection for EfiLoaderCode / EfiBootServicesCode / EfiRuntimeServicesCode. <BR>
+ # User MUST set the same NX protection for EfiBootServicesData and EfiConventionalMemory. <BR>
+ #
+ # e.g. 0x7FD5 can be used for all memory except Code. <BR>
+ # e.g. 0x7BD4 can be used for all memory except Code and ACPINVS/Reserved. <BR>
+ #
+ # @Prompt Set DXE memory protection policy.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x0000000|UINT64|0x00001048
+
+ ## PCI Serial Device Info. It is an array of Device, Function, and Power Management
+ # information that describes the path that contains zero or more PCI to PCI briges
+ # followed by a PCI serial device. Each array entry is 4-bytes in length. The
+ # first byte is the PCI Device Number, then second byte is the PCI Function Number,
+ # and the last two bytes are the offset to the PCI power management capabilities
+ # register used to manage the D0-D3 states. If a PCI power management capabilities
+ # register is not present, then the last two bytes in the offset is set to 0. The
+ # array is terminated by an array entry with a PCI Device Number of 0xFF. For a
+ # non-PCI fixed address serial device, such as an ISA serial device, the value is 0xFF.
+ # @Prompt Pci Serial Device Info
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067
+
+ ## PCI Serial Parameters. It is an array of VendorID, DeviceID, ClockRate, Offset,
+ # BarIndex, RegisterStride, ReceiveFifoDepth, TransmitFifoDepth information that
+ # describes the parameters of special PCI serial devices.
+ # Each array entry is 24-byte in length. The array is terminated
+ # by an array entry with a PCI Vendor ID of 0xFFFF. If a platform only contains a
+ # standard 16550 PCI serial device whose class code is 7/0/2, the value is 0xFFFF.
+ # The C style structure is defined as below:<BR>
+ # typedef struct {<BR>
+ # UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries.<BR>
+ # UINT16 DeviceId; ///< Device ID to match the PCI device.<BR>
+ # UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz.<BR>
+ # UINT64 Offset; ///< The byte offset into to the BAR.<BR>
+ # UINT8 BarIndex; ///< Which BAR to get the UART base address.<BR>
+ # UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte.<BR>
+ # UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.<BR>
+ # UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.<BR>
+ # UINT8 Reserved[2];<BR>
+ # } PCI_SERIAL_PARAMETER;<BR>
+ # It contains zero or more instances of the above structure.<BR>
+ # For example, if a PCI device contains two UARTs, PcdPciSerialParameters needs
+ # to contain two instances of the above structure, with the VendorId and DeviceId
+ # equals to the Device ID and Vendor ID of the device; If the PCI device uses the
+ # first two BARs to support two UARTs, BarIndex of first instance equals to 0 and
+ # BarIndex of second one equals to 1; If the PCI device uses the first BAR to
+ # support both UARTs, BarIndex of both instance equals to 0, Offset of first
+ # instance equals to 0 and Offset of second one equals to a value bigger than or
+ # equal to 8.<BR>
+ # For certain UART whose register needs to be accessed in DWORD aligned address,
+ # RegisterStride equals to 4.
+ # @Prompt Pci Serial Parameters
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters|{0xFF, 0xFF}|VOID*|0x00010071
+
+ ## Serial Port Extended Transmit FIFO Size. The default is 64 bytes.
+ # @Prompt Serial Port Extended Transmit FIFO Size in Bytes
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|64|UINT32|0x00010068
+
+ ## This PCD points to the file name GUID of the BootManagerMenuApp
+ # Platform can customize the PCD to point to different application for Boot Manager Menu
+ # @Prompt Boot Manager Menu File
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0xdc, 0x5b, 0xc2, 0xee, 0xf2, 0x67, 0x95, 0x4d, 0xb1, 0xd5, 0xf8, 0x1b, 0x20, 0x39, 0xd1, 0x1d }|VOID*|0x0001006b
+
+ ## This PCD points to the formset GUID of the driver health management form
+ # The form will be popped up by BDS core when there are Configuration Required driver health intances.
+ # Platform can customize the PCD to point to different formset.
+ # @Prompt Driver Health Management Form
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm|{ 0xf4, 0xd9, 0x96, 0x42, 0xfc, 0xf6, 0xde, 0x4d, 0x86, 0x85, 0x8c, 0xe2, 0xd7, 0x9d, 0x90, 0xf0 }|VOID*|0x0001006c
+
+ ## The number of bytes between registers in serial device. The default is 1 byte.
+ # @Prompt Serial Port Register Stride in Bytes
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|1|UINT32|0x0001006d
+
+ ## This PCD to include the driver guid of VFR drivers for VarCheckHiiBin generation.<BR><BR>
+ # Default is gZeroGuid that means no VFR driver will be parsed for VarCheckHiiBin generation.<BR>
+ # If it is set to an all FFs GUID, it means all modules in all FVs will be parsed for VarCheckHiiBin generation.<BR>
+ # @Prompt Driver guid array of VFR drivers for VarCheckHiiBin generation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray|{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }|VOID*|0x3000103A
+
+ ## Indicates which ACPI versions are targeted by the ACPI tables exposed to the OS
+ # These values are aligned with the definitions in MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h
+ # BIT 1 - EFI_ACPI_TABLE_VERSION_1_0B.<BR>
+ # BIT 2 - EFI_ACPI_TABLE_VERSION_2_0.<BR>
+ # BIT 3 - EFI_ACPI_TABLE_VERSION_3_0.<BR>
+ # BIT 4 - EFI_ACPI_TABLE_VERSION_4_0.<BR>
+ # BIT 5 - EFI_ACPI_TABLE_VERSION_5_0.<BR>
+ # @Prompt Exposed ACPI table versions.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x3E|UINT32|0x0001004c
+
+ ## This PCD defines the MAX repair count.
+ # The default value is 0 that means infinite.
+ # @Prompt MAX repair count
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxRepairCount|0x00|UINT32|0x00010076
+
+ ## Status Code for Capsule subclass definitions.<BR><BR>
+ # EFI_OEM_SPECIFIC_SUBCLASS_CAPSULE = 0x00810000<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule subclass definitions
+ # @ValidList 0x80000003 | 0x00810000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule|0x00810000|UINT32|0x00000100
+
+ ## Status Code for Capsule Process Begin.<BR><BR>
+ # EFI_CAPSULE_PROCESS_CAPSULES_BEGIN = (EFI_OEM_SPECIFIC | 0x00000001) = 0x00008001<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Process Begin
+ # @ValidList 0x80000003 | 0x00008001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin|0x00008001|UINT32|0x00000101
+
+ ## Status Code for Capsule Process End.<BR><BR>
+ # EFI_CAPSULE_PROCESS_CAPSULES_END = (EFI_OEM_SPECIFIC | 0x00000002) = 0x00008002<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Process End
+ # @ValidList 0x80000003 | 0x00008002
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd|0x00008002|UINT32|0x00000102
+
+ ## Status Code for Capsule Process Updating Firmware.<BR><BR>
+ # EFI_CAPSULE_UPDATING_FIRMWARE = (EFI_OEM_SPECIFIC | 0x00000003) = 0x00008003<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Process Updating Firmware
+ # @ValidList 0x80000003 | 0x00008003
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware|0x00008003|UINT32|0x00000103
+
+ ## Status Code for Capsule Process Update Firmware Success.<BR><BR>
+ # EFI_CAPSULE_UPDATE_FIRMWARE_SUCCESS = (EFI_OEM_SPECIFIC | 0x00000004) = 0x00008004<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Process Update Firmware Success
+ # @ValidList 0x80000003 | 0x00008004
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess|0x00008004|UINT32|0x00000104
+
+ ## Status Code for Capsule Process Update Firmware Failed.<BR><BR>
+ # EFI_CAPSULE_UPDATE_FIRMWARE_FAILED = (EFI_OEM_SPECIFIC | 0x00000005) = 0x00008005<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Process Update Firmware Failed
+ # @ValidList 0x80000003 | 0x00008005
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed|0x00008005|UINT32|0x00000105
+
+ ## Status Code for Capsule Resetting System.<BR><BR>
+ # EFI_CAPSULE_RESETTING_SYSTEM = (EFI_OEM_SPECIFIC | 0x00000006) = 0x00008006<BR>
+ # NOTE: The default value of this PCD may collide with other OEM specific status codes.
+ # Override the value of this PCD in the platform DSC file as needed.
+ # @Prompt Status Code for Capsule Resetting System
+ # @ValidList 0x80000003 | 0x00008006
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem|0x00008006|UINT32|0x00000106
+
+ ## CapsuleMax value in capsule report variable.
+ # @Prompt CapsuleMax value in capsule report variable.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax|0xFFFF|UINT16|0x00000107
+
+ ## Control which FPDT record format will be used to store the performance entry.
+ # On TRUE, the string FPDT record will be used to store every performance entry.
+ # On FALSE, the different FPDT record will be used to store the different performance entries.
+ # @Prompt String FPDT Record Enable Only
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly|FALSE|BOOLEAN|0x00000109
+
+ ## Indicates the allowable maximum number of Reset Filters, Reset Notifications or Reset Handlers in PEI phase.
+ # @Prompt Maximum Number of PEI Reset Filters, Reset Notifications or Reset Handlers.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaximumPeiResetNotifies|0x10|UINT32|0x0000010A
+
+ ## Capsule On Disk is to deliver capsules via files on Mass Storage device.<BR><BR>
+ # This PCD indicates if the Capsule On Disk is supported.<BR>
+ # TRUE - Capsule On Disk is supported.<BR>
+ # FALSE - Capsule On Disk is not supported.<BR>
+ # If platform does not use this feature, this PCD should be set to FALSE.<BR><BR>
+ # Two sulotions to deliver Capsule On Disk:<BR>
+ # a) If PcdCapsuleInRamSupport = TRUE, Load Capsule On Disk image out of TCB, and reuse
+ # Capsule In Ram to deliver capsule.<BR>
+ # b) If PcdCapsuleInRamSupport = FALSE, Relocate Capsule On Disk image to RootDir out
+ # of TCB, and reuse FatPei to load capsules from external storage.<BR>
+ # Note:<BR>
+ # If Both Capsule In Ram and Capsule On Disk are provisioned at the same time, the Capsule
+ # On Disk will be bypassed.
+ # @Prompt Enable Capsule On Disk support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport|FALSE|BOOLEAN|0x0000002d
+
+[PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## This PCD defines the Console output row. The default value is 25 according to UEFI spec.
+ # This PCD could be set to 0 then console output would be at max column and max row.
+ # @Prompt Console output row.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow|25|UINT32|0x40000006
+
+ ## This PCD defines the Console output column. The default value is 80 according to UEFI spec.
+ # This PCD could be set to 0 then console output would be at max column and max row.
+ # @Prompt Console output column.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn|80|UINT32|0x40000007
+
+ ## This PCD defines the video horizontal resolution.
+ # If this PCD is set to 0 then video resolution would be at highest resolution.
+ # @Prompt Video horizontal resolution.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|800|UINT32|0x40000009
+
+ ## This PCD defines the video vertical resolution.
+ # If this PCD is set to 0 then video resolution would be at highest resolution.
+ # @Prompt Video vertical resolution.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|600|UINT32|0x4000000a
+
+ # The 4 PCDs below are used to specify the video resolution and text mode of text setup.
+ # To make text setup work in this resolution, PcdVideoHorizontalResolution, PcdVideoVerticalResolution,
+ # PcdConOutColumn and PcdConOutRow should be created as PcdsDynamic or PcdsDynamicEx in platform DSC file.
+ # Then BDS setup will update these PCDs defined in MdeModulePkg.dec and reconnect console drivers
+ # (GraphicsConsole, Terminal, Consplitter) to make the video resolution and text mode work
+ # for text setup.
+
+ ## Specify the video horizontal resolution of text setup.
+ # @Prompt Video Horizontal Resolution of Text Setup
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|800|UINT32|0x4000000b
+
+ ## Specify the video vertical resolution of text setup.
+ # @Prompt Video Vertical Resolution of Text Setup
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|600|UINT32|0x4000000c
+
+ ## Specify the console output column of text setup.
+ # @Prompt Console Output Column of Text Setup
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn|80|UINT32|0x4000000d
+
+ ## Specify the console output row of text setup.
+ # @Prompt Console Output Row of Text Setup
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow|25|UINT32|0x4000000e
+
+[PcdsFixedAtBuild.AARCH64, PcdsPatchableInModule.AARCH64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20|UINT32|0x0001004c
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## UART clock frequency is for the baud rate configuration.
+ # @Prompt Serial Port Clock Rate.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200|UINT32|0x00010066
+
+ ## This PCD points to the front page formset GUID
+ # Compare the FormsetGuid or ClassGuid with this PCD value can detect whether in front page
+ # @Prompt Front Page Formset.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrontPageFormSetGuid|{ 0xbc, 0x30, 0x0c, 0x9e,0x06, 0x3f, 0xa6, 0x4b, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe }|VOID*|0x0001006e
+
+ ## Base address of the NV variable range in flash device.
+ # @Prompt Base address of flash NV variable range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0|UINT32|0x30000001
+
+ ## Size of the NV variable range. Note that this value should less than or equal to PcdFlashNvStorageFtwSpareSize.
+ # The root cause is that variable driver will use FTW protocol to reclaim variable region.
+ # If the length of variable region is larger than FTW spare size, it means the whole variable region can not
+ # be reflushed through the manner of fault tolerant write.
+ # @Prompt Size of flash NV variable range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x0|UINT32|0x30000002
+
+ ## Base address of the FTW spare block range in flash device. Note that this value should be block size aligned.
+ # @Prompt Base address of flash FTW spare block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x0|UINT32|0x30000013
+
+ ## Size of the FTW spare block range. Note that this value should larger than PcdFlashNvStorageVariableSize and block size aligned.
+ # The root cause is that variable driver will use FTW protocol to reclaim variable region.
+ # If the length of variable region is larger than FTW spare size, it means the whole variable region can not
+ # be reflushed through the manner of fault tolerant write.
+ # @Prompt Size of flash FTW spare block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x0|UINT32|0x30000014
+
+ ## Base address of the FTW working block range in flash device.
+ # If PcdFlashNvStorageFtwWorkingSize is larger than one block size, this value should be block size aligned.
+ # @Prompt Base address of flash FTW working block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x0|UINT32|0x30000010
+
+ ## Size of the FTW working block range.
+ # If the value is less than one block size, the work space range should not span blocks.
+ # If the value is larger than one block size, it should be block size aligned.
+ # @Prompt Size of flash FTW working block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x0|UINT32|0x30000011
+
+ ## 64-bit Base address of the NV variable range in flash device.
+ # @Prompt 64-bit Base address of flash NV variable range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0x0|UINT64|0x80000001
+
+ ## 64-bit Base address of the FTW spare block range in flash device. Note that this value should be block size aligned.
+ # @Prompt 64-bit Base address of flash FTW spare block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0|UINT64|0x80000013
+
+ ## 64-bit Base address of the FTW working block range in flash device.
+ # If PcdFlashNvStorageFtwWorkingSize is larger than one block size, this value should be block size aligned.
+ # @Prompt 64-bit Base address of flash FTW working block range.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0|UINT64|0x80000010
+
+ ## Indicates if Variable driver will enable emulated variable NV mode.<BR><BR>
+ # If this PCD is configured to dynamic, its value should be set before Variable driver starts to work,<BR>
+ # otherwise default value will take effect.<BR>
+ # TRUE - An EMU variable NV storage will be allocated or reserved for NV variables.<BR>
+ # FALSE - No EMU variable NV storage will be allocated or reserved for NV variables.<BR>
+ # @Prompt EMU variable NV mode enable.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE|BOOLEAN|0x01100001
+
+ ## This PCD defines the base address of reserved memory range for EMU variable NV storage.
+ # A non-ZERO value indicates a valid range reserved with size given by PcdVariableStoreSize.
+ # @Prompt Base of reserved memory range for EMU variable NV storage.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved|0|UINT64|0x40000008
+
+ ## This PCD defines the times to print hello world string.
+ # This PCD is a sample to explain UINT32 PCD usage.
+ # @Prompt HellowWorld print times.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes|1|UINT32|0x40000005
+
+ ## This PCD defines the HelloWorld print string.
+ # This PCD is a sample to explain String typed PCD usage.
+ # @Prompt HelloWorld print string.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString|L"UEFI Hello World!\n"|VOID*|0x40000004
+
+ ## Indicates the maximum size of the capsule image with a reset flag that the platform can support.
+ # The default max size is 100MB (0x6400000) for more than one large capsule images.
+ # @Prompt Max size of populated capsule.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule|0x6400000|UINT32|0x0001001e
+
+ ## Indicates the maximum size of the capsule image without a reset flag that the platform can support.
+ # The default max size is 10MB (0xa00000) for the casule image without reset flag setting.
+ # @Prompt Max size of non-populated capsule.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule|0xa00000|UINT32|0x0001001f
+
+ ## Null-terminated Unicode string of the firmware vendor name that is the default name filled into the EFI System Table.
+ # @Prompt Firmware vendor.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor|L"EDK II"|VOID*|0x00010050
+
+ ## Firmware revision that is the default revision filled into the EFI System Table.
+ # @Prompt Firmware revision.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareRevision|0x00010000|UINT32|0x00010051
+
+ ## Null-terminated Unicode string that describes the firmware version.
+ # @Prompt Firmware version string.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString|L""|VOID*|0x00010052
+
+ ## Null-terminated Unicode string that contains the date the firmware was released
+ # @Prompt Firmware release data string.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareReleaseDateString|L""|VOID*|0x00010053
+
+ ## PcdStatusCodeMemorySize is used when PcdStatusCodeUseMemory is set to true.
+ # (PcdStatusCodeMemorySize * KBytes) is the total taken memory size.<BR><BR>
+ # The default value in PeiPhase is 1 KBytes.<BR>
+ # The default value in DxePhase is 128 KBytes.<BR>
+ # @Prompt StatusCode memory size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|UINT16|0x00010054
+
+ ## Indicates if to reset system when memory type information changes.<BR><BR>
+ # TRUE - Resets system when memory type information changes.<BR>
+ # FALSE - Does not reset system when memory type information changes.<BR>
+ # @Prompt Reset on memory type information change.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|TRUE|BOOLEAN|0x00010056
+
+ ## Indicates if the BDS supports Platform Recovery.<BR><BR>
+ # TRUE - BDS supports Platform Recovery.<BR>
+ # FALSE - BDS does not support Platform Recovery.<BR>
+ # @Prompt Support Platform Recovery.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformRecoverySupport|TRUE|BOOLEAN|0x00010078
+
+ ## Specify the foreground color for Subtile text in HII Form Browser. The default value is EFI_BLUE.
+ # Only following values defined in UEFI specification are valid:<BR><BR>
+ # 0x00 (EFI_BLACK)<BR>
+ # 0x01 (EFI_BLUE)<BR>
+ # 0x02 (EFI_GREEN)<BR>
+ # 0x03 (EFI_CYAN)<BR>
+ # 0x04 (EFI_RED)<BR>
+ # 0x05 (EFI_MAGENTA)<BR>
+ # 0x06 (EFI_BROWN)<BR>
+ # 0x07 (EFI_LIGHTGRAY)<BR>
+ # 0x08 (EFI_DARKGRAY)<BR>
+ # 0x09 (EFI_LIGHTBLUE)<BR>
+ # 0x0A (EFI_LIGHTGREEN)<BR>
+ # 0x0B (EFI_LIGHTCYAN)<BR>
+ # 0x0C (EFI_LIGHTRED)<BR>
+ # 0x0D (EFI_LIGHTMAGENTA)<BR>
+ # 0x0E (EFI_YELLOW)<BR>
+ # 0x0F (EFI_WHITE)<BR>
+ # @Prompt Foreground color for browser subtile.
+ # @ValidRange 0x80000004 | 0x00 - 0x0F
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor|0x01|UINT8|0x00010057
+
+ ## Specify the foreground color for prompt and Question value text in HII Form Browser. The default value is EFI_BLACK.
+ # Only following values defined in UEFI specification are valid:<BR><BR>
+ # 0x00 (EFI_BLACK)<BR>
+ # 0x01 (EFI_BLUE)<BR>
+ # 0x02 (EFI_GREEN)<BR>
+ # 0x03 (EFI_CYAN)<BR>
+ # 0x04 (EFI_RED)<BR>
+ # 0x05 (EFI_MAGENTA)<BR>
+ # 0x06 (EFI_BROWN)<BR>
+ # 0x07 (EFI_LIGHTGRAY)<BR>
+ # 0x08 (EFI_DARKGRAY)<BR>
+ # 0x09 (EFI_LIGHTBLUE)<BR>
+ # 0x0A (EFI_LIGHTGREEN)<BR>
+ # 0x0B (EFI_LIGHTCYAN)<BR>
+ # 0x0C (EFI_LIGHTRED)<BR>
+ # 0x0D (EFI_LIGHTMAGENTA)<BR>
+ # 0x0E (EFI_YELLOW)<BR>
+ # 0x0F (EFI_WHITE)<BR>
+ # @Prompt Foreground color for browser field.
+ # @ValidRange 0x80000004 | 0x00 - 0x0F
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor|0x00|UINT8|0x00010058
+
+ ## Specify the foreground color for highlighted prompt and Question value text in HII Form Browser.
+ # The default value is EFI_LIGHTGRAY. Only following values defined in UEFI specification are valid:<BR><BR>
+ # 0x00 (EFI_BLACK)<BR>
+ # 0x01 (EFI_BLUE)<BR>
+ # 0x02 (EFI_GREEN)<BR>
+ # 0x03 (EFI_CYAN)<BR>
+ # 0x04 (EFI_RED)<BR>
+ # 0x05 (EFI_MAGENTA)<BR>
+ # 0x06 (EFI_BROWN)<BR>
+ # 0x07 (EFI_LIGHTGRAY)<BR>
+ # 0x08 (EFI_DARKGRAY)<BR>
+ # 0x09 (EFI_LIGHTBLUE)<BR>
+ # 0x0A (EFI_LIGHTGREEN)<BR>
+ # 0x0B (EFI_LIGHTCYAN)<BR>
+ # 0x0C (EFI_LIGHTRED)<BR>
+ # 0x0D (EFI_LIGHTMAGENTA)<BR>
+ # 0x0E (EFI_YELLOW)<BR>
+ # 0x0F (EFI_WHITE)<BR>
+ # @Prompt Foreground color for highlighted browser field.
+ # @ValidRange 0x80000004 | 0x00 - 0x0F
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor|0x07|UINT8|0x00010059
+
+ ## Specify the background color for highlighted prompt and Question value text in HII Form Browser.
+ # The default value is EFI_BACKGROUND_BLACK. Only following values defined in UEFI specification are valid:<BR><BR>
+ # 0x00 (EFI_BACKGROUND_BLACK)<BR>
+ # 0x10 (EFI_BACKGROUND_BLUE)<BR>
+ # 0x20 (EFI_BACKGROUND_GREEN)<BR>
+ # 0x30 (EFI_BACKGROUND_CYAN)<BR>
+ # 0x40 (EFI_BACKGROUND_RED)<BR>
+ # 0x50 (EFI_BACKGROUND_MAGENTA)<BR>
+ # 0x60 (EFI_BACKGROUND_BROWN)<BR>
+ # 0x70 (EFI_BACKGROUND_LIGHTGRAY)<BR>
+ # @Prompt Background color for highlighted browser field.
+ # @ValidList 0x80000005 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor|0x00|UINT8|0x0001005A
+
+ ## Time in second to delay for SATA devices to spin-up for recovery.
+ # @Prompt SATA spin-up delay time in second for recovery path.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSataSpinUpDelayInSecForRecoveryPath|15|UINT16|0x0001005B
+
+ ## This PCD is used to specify memory size with page number for a pre-allocated ACPI reserved memory
+ # to hold runtime(after SmmReadyToLock) created S3 boot script entries. The default page number is 2.
+ # When changing the value of this PCD, the platform developer should make sure the memory size is
+ # large enough to hold the S3 boot script node created in runtime(after SmmReadyToLock) phase.
+ # @Prompt Reserved page number for S3 Boot Script Runtime Table.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptRuntimeTableReservePageNumber|0x2|UINT16|0x0001005C
+
+ ## The PCD is used to specify the stack size when capsule IA32 PEI transfers to long mode in PEI phase.
+ # The default size is 32K. When changing the value of this PCD, the platform developer should
+ # make sure the memory size is large enough to meet capsule PEI requirement in capsule update path.
+ # @Prompt Stack size for CapsulePei transfer to long mode.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize|0x8000|UINT32|0x0001005D
+
+ ## Indicates if 1G page table will be enabled.<BR><BR>
+ # TRUE - 1G page table will be enabled.<BR>
+ # FALSE - 1G page table will not be enabled.<BR>
+ # @Prompt Enable 1G page table support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|FALSE|BOOLEAN|0x0001005E
+
+ ## Indicates if the Single Root I/O virtualization is supported.<BR><BR>
+ # TRUE - Single Root I/O virtualization is supported.<BR>
+ # FALSE - Single Root I/O virtualization is not supported.<BR>
+ # @Prompt Enable SRIOV support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport|TRUE|BOOLEAN|0x10000044
+
+ ## Indicates if the Alternative Routing-ID is supported.<BR><BR>
+ # TRUE - Alternative Routing-ID is supported.<BR>
+ # FALSE - Alternative Routing-ID is not supported.<BR>
+ # @Prompt Enable ARI support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport|TRUE|BOOLEAN|0x10000045
+
+ ## Indicates if the Multi Root I/O virtualization is supported.<BR><BR>
+ # TRUE - Multi Root I/O virtualization is supported.<BR>
+ # FALSE - Multi Root I/O virtualization is not supported.<BR>
+ # @Prompt Enable MRIOV support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport|FALSE|BOOLEAN|0x10000046
+
+ ## Single root I/O virtualization virtual function memory BAR alignment.<BR><BR>
+ # BITN set indicates 2 of n+12 power<BR>
+ # BIT0 set indicates 4KB alignment<BR>
+ # BIT1 set indicates 8KB alignment<BR>
+ # @Prompt SRIOV system page size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize|0x1|UINT32|0x10000047
+
+ ## SMBIOS version.
+ # @Prompt SMBIOS version.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0303|UINT16|0x00010055
+
+ ## SMBIOS Docrev field in SMBIOS 3.0 (64-bit) Entry Point Structure.
+ # @Prompt SMBIOS Docrev field in SMBIOS 3.0 (64-bit) Entry Point Structure.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev|0x0|UINT8|0x0001006A
+
+ ## SMBIOS produce method.
+ # BIT0 set indicates 32-bit entry point and table are produced.<BR>
+ # BIT1 set indicates 64-bit entry point and table are produced.<BR>
+ # @Prompt The policy to produce SMBIOS entry point and table.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosEntryPointProvideMethod|0x3|UINT32|0x00010069
+
+ ## This PCD specifies the additional pad size in FPDT Basic Boot Performance Table for
+ # the extension FPDT boot records received after ReadyToBoot and before ExitBootService.
+ # @Prompt Pad size for extension FPDT boot records.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdExtFpdtBootRecordPadSize|0x20000|UINT32|0x0001005F
+
+ ## Indicates if ConIn device are connected on demand.<BR><BR>
+ # TRUE - ConIn device are not connected during BDS and ReadKeyStroke/ReadKeyStrokeEx produced
+ # by Consplitter should be called before any real key read operation.<BR>
+ # FALSE - ConIn device may be connected normally during BDS.<BR>
+ # @Prompt ConIn connect on demand.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand|FALSE|BOOLEAN|0x10000060
+
+ ## Indicates if the S.M.A.R.T feature of attached ATA hard disks will be enabled.<BR><BR>
+ # TRUE - S.M.A.R.T feature of attached ATA hard disks will be enabled.<BR>
+ # FALSE - S.M.A.R.T feature of attached ATA hard disks will be default status.<BR>
+ # @Prompt Enable ATA S.M.A.R.T feature.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAtaSmartEnable|TRUE|BOOLEAN|0x00010065
+
+ ## Indicates if full PCI enumeration is disabled.<BR><BR>
+ # TRUE - Full PCI enumeration is disabled.<BR>
+ # FALSE - Full PCI enumeration is not disabled.<BR>
+ # @Prompt Disable full PCI enumeration.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|FALSE|BOOLEAN|0x10000048
+
+ ## Disk I/O - Number of Data Buffer block.
+ # Define the size in block of the pre-allocated buffer. It provide better
+ # performance for large Disk I/O requests.
+ # @Prompt Disk I/O - Number of Data Buffer block.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum|64|UINT32|0x30001039
+
+ ## This PCD specifies the PCI-based UFS host controller mmio base address.
+ # Define the mmio base address of the pci-based UFS host controller. If there are multiple UFS
+ # host controllers, their mmio base addresses are calculated one by one from this base address.
+ # @Prompt Mmio base address of pci-based UFS host controller.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUfsPciHostControllerMmioBase|0xd0000000|UINT32|0x10000061
+
+ ## Specify Max ESRT cache entry number supported for FMP instances
+ #
+ # @Prompt Max FMP ESRT entry number to be synced & cached in repository.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxFmpEsrtCacheNum|32|UINT32|0x0000006b
+
+ ## Specify Max ESRT cache entry number supported for Non FMP instances
+ #
+ # @Prompt Max Non-FMP ESRT entry number to be cached in repository.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxNonFmpEsrtCacheNum|32|UINT32|0x0000006c
+
+ ## Specify of Capsule Flag defined by CapsuleGuid to request system reboot after capsule process
+ #
+ # @Prompt Flag to request system reboot after processing capsule.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag|0x0001|UINT16|0x0000006d
+
+ ## Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification.
+ # @Prompt Default OEM ID for ACPI table creation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034
+
+ ## Default OEM Table ID for ACPI table creation, it is "EDK2 ".
+ # According to ACPI specification, this field is particularly useful when
+ # defining a definition block to distinguish definition block functions.
+ # The OEM assigns each dissimilar table a new OEM Table ID.
+ # This PCD is ignored for definition block.
+ # @Prompt Default OEM Table ID for ACPI table creation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId|0x20202020324B4445|UINT64|0x30001035
+
+ ## Default OEM Revision for ACPI table creation.
+ # According to ACPI specification, for LoadTable() opcode, the OS can also
+ # check the OEM Table ID and Revision ID against a database for a newer
+ # revision Definition Block of the same OEM Table ID and load it instead.
+ # This PCD is ignored for definition block.
+ # @Prompt Default OEM Revision for ACPI table creation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision|0x00000002|UINT32|0x30001036
+
+ ## Default Creator ID for ACPI table creation.
+ # According to ACPI specification, for tables containing Definition Blocks,
+ # this is the ID for the ASL Compiler.
+ # This PCD is ignored for definition block.
+ # @Prompt Default Creator ID for ACPI table creation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId|0x20202020|UINT32|0x30001037
+
+ ## Default Creator Revision for ACPI table creation.
+ # According to ACPI specification, for tables containing Definition Blocks,
+ # this is the revision for the ASL Compiler.
+ # This PCD is ignored for definition block.
+ # @Prompt Default Creator Revision for ACPI table creation.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038
+
+ ## Indicates if to set NX for stack.<BR><BR>
+ # For the DxeIpl and the DxeCore are both X64, set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE.<BR>
+ # For the DxeIpl and the DxeCore are both IA32 (PcdDxeIplSwitchToLongMode is FALSE), set NX for stack feature also require
+ # IA32 PAE is supported and Execute Disable Bit is available.<BR>
+ # <BR>
+ # TRUE - Set NX for stack.<BR>
+ # FALSE - Do nothing for stack.<BR>
+ # <BR>
+ # Note: If this PCD is set to FALSE, NX could be still applied to stack due to PcdDxeNxMemoryProtectionPolicy enabled for
+ # EfiBootServicesData.<BR>
+ # <BR>
+ # @Prompt Set NX for stack.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f
+
+ ## This PCD specifies the PCI-based SD/MMC host controller mmio base address.
+ # Define the mmio base address of the pci-based SD/MMC host controller. If there are multiple SD/MMC
+ # host controllers, their mmio base addresses are calculated one by one from this base address.
+ # @Prompt Mmio base address of pci-based SD/MMC host controller.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase|0xd0000000|UINT32|0x30001043
+
+ ## Indicates if ACPI S3 will be enabled.<BR><BR>
+ # TRUE - ACPI S3 will be enabled.<BR>
+ # FALSE - ACPI S3 will be disabled.<BR>
+ # @Prompt ACPI S3 Enable.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable|TRUE|BOOLEAN|0x01100000
+
+ ## 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
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize|0x8000|UINT32|0x02000000
+
+ ## 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
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFastPS2Detection|FALSE|BOOLEAN|0x30001044
+
+ ## This is recover file name in PEI phase.
+ # The file must be in the root directory.
+ # The file name must be the 8.3 format.
+ # The PCD data must be in UNICODE format.
+ # @Prompt Recover file name in PEI phase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"|VOID*|0x30001045
+
+ ## This is Capsule Temp Relocation file name in PEI phase.
+ # The file must be in the root directory.
+ # The file name must be the 8.3 format.
+ # The PCD data must be in UNICODE format.
+ # CapsuleOnDiskLoadPei PEI module will set value of this PCD to PcdRecoveryFileName, then
+ # leverage recovery to get Capsule On Disk Temp Relocation file.
+ # Note: The file name must be shorter than PcdRecoveryFileName, otherwise CapsuleOnDiskLoadPei
+ # PEI module will fail to get Capsule On Disk Temp Relocation file.
+ # @Prompt Capsule On Disk Temp Relocation file name in PEI phase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName|L"Cod.tmp"|VOID*|0x30001048
+
+ ## This PCD hold a list GUIDs for the ImageTypeId to indicate the
+ # FMP capsule is a system FMP.
+ # @Prompt A list of system FMP ImageTypeId GUIDs
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid|{0x0}|VOID*|0x30001046
+
+ ## This PCD holds the address mask for page table entries when memory encryption is
+ # enabled on AMD processors supporting the Secure Encrypted Virtualization (SEV) feature.
+ # This mask should be applied when creating 1:1 virtual to physical mapping tables.
+ # @Prompt The address mask when memory encryption is enabled.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0|UINT64|0x30001047
+
+ ## Indicates if 5-Level Paging will be enabled in long mode. 5-Level Paging will not be enabled
+ # when the PCD is TRUE but CPU doesn't support 5-Level Paging.
+ # TRUE - 5-Level Paging will be enabled.<BR>
+ # FALSE - 5-Level Paging will not be enabled.<BR>
+ # @Prompt Enable 5-Level Paging support in long mode.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable|FALSE|BOOLEAN|0x0001105F
+
+ ## Capsule In Ram is to use memory to deliver the capsules that will be processed after system
+ # reset.<BR><BR>
+ # This PCD indicates if the Capsule In Ram is supported.<BR>
+ # TRUE - Capsule In Ram is supported.<BR>
+ # FALSE - Capsule In Ram is not supported.
+ # @Prompt Enable Capsule In Ram support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport|TRUE|BOOLEAN|0x0000002e
+
+ ## Full device path of plaform specific device to store Capsule On Disk temp relocation file.<BR>
+ # If this PCD is set, Capsule On Disk temp relocation file will be stored in the device specified
+ # by this PCD, instead of the EFI System Partition that stores capsule image file.
+ # @Prompt Capsule On Disk relocation device path.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath|{0xFF}|VOID*|0x0000002f
+
+ ## Indicates which TCG Platform Firmware Profile revision the EDKII firmware follows.
+ # The revision number is defined in MdePkg/Include/IndustryStandard/UefiTcgPlatform.h
+ # 0: This is for compatiblity support.
+ # 105: This is the first revision to support 800-155 is related event, such as
+ # EV_EFI_PLATFORM_FIRMWARE_BLOB2 and EV_EFI_HANDOFF_TABLES2.
+ # @Prompt TCG Platform Firmware Profile revision.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision|0|UINT32|0x00010077
+
+ ## Indicates if StatusCode is reported via Serial port.<BR><BR>
+ # TRUE - Reports StatusCode via Serial port.<BR>
+ # FALSE - Does not report StatusCode via Serial port.<BR>
+ # @Prompt Enable StatusCode via Serial port.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|TRUE|BOOLEAN|0x00010022
+
+ ## Indicates if StatusCode is stored in memory.
+ # The memory is boot time memory in PEI Phase and is runtime memory in DXE Phase.<BR><BR>
+ # TRUE - Stores StatusCode in memory.<BR>
+ # FALSE - Does not store StatusCode in memory.<BR>
+ # @Prompt Enable StatusCode via memory.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE|BOOLEAN|0x00010023
+
+[PcdsPatchableInModule]
+ ## Specify memory size with page number for PEI code when
+ # Loading Module at Fixed Address feature is enabled.
+ # The value will be set by the build tool.
+ # @Prompt LMFA PEI code page number.
+ # @ValidList 0x80000001 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber|0|UINT32|0x00000029
+
+ ## Specify memory size with page number for DXE boot time code when
+ # Loading Module at Fixed Address feature is enabled.
+ # The value will be set by the build tool.
+ # @Prompt LMFA DXE boot code page number.
+ # @ValidList 0x80000001 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber|0|UINT32|0x0000002a
+
+ ## Specify memory size with page number for DXE runtime code when
+ # Loading Module at Fixed Address feature is enabled.
+ # The value will be set by the build tool.
+ # @Prompt LMFA DXE runtime code page number.
+ # @ValidList 0x80000001 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber|0|UINT32|0x0000002b
+
+ ## Specify memory size with page number for SMM code when
+ # Loading Module at Fixed Address feature is enabled.
+ # The value will be set by the build tool.
+ # @Prompt LMFA SMM code page number.
+ # @ValidList 0x80000001 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber|0|UINT32|0x0000002c
+
+[PcdsDynamic, PcdsDynamicEx]
+ ## This dynamic PCD hold an address to point to private data structure used in DxeS3BootScriptLib library
+ # instance which records the S3 boot script table start address, length, etc. To introduce this PCD is
+ # only for DxeS3BootScriptLib instance implementation purpose. The platform developer should make sure the
+ # default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library.
+ # @Prompt S3 Boot Script Table Private Data pointer.
+ # @ValidList 0x80000001 | 0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr|0x0|UINT64|0x00030000
+
+ ## This dynamic PCD hold an address to point to private data structure SMM copy used in DxeS3BootScriptLib library
+ # instance which records the S3 boot script table start address, length, etc. To introduce this PCD is
+ # only for DxeS3BootScriptLib instance implementation purpose. The platform developer should make sure the
+ # default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library.
+ # @Prompt S3 Boot Script Table Private Smm Data pointer.
+ # @ValidList 0x80000001 | 0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr|0x0|UINT64|0x00030001
+
+ ## This dynamic PCD holds the information if there is any test key used by the platform.
+ # @Prompt If there is any test key used by the platform.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed|FALSE|BOOLEAN|0x00030003
+
+ ## This dynamic PCD holds the base address of the Guest-Hypervisor Communication Block (GHCB) pool allocation.
+ # @Prompt GHCB Pool Base Address
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0|UINT64|0x00030007
+
+ ## This dynamic PCD holds the total size of the Guest-Hypervisor Communication Block (GHCB) pool allocation.
+ # The amount of memory allocated for GHCBs is dependent on the number of APs.
+ # @Prompt GHCB Pool Size
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030008
+
+[PcdsDynamicEx]
+ ## This dynamic PCD enables the default variable setting.
+ # Its value is the default store ID value. The default value is zero as Standard default.
+ # When its value is set in PEI, it will trig the default setting to be applied as the default EFI variable.
+ # @Prompt NV Storage DefaultId
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId|0x0|UINT16|0x00030004
+
+ ## This dynamic PCD holds the DynamicHii PCD value. Its value is the auto generated.
+ # @Prompt NV Storage Default Value Buffer
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer|{0x0}|VOID*|0x00030005
+
+ ## VPD type PCD allows a developer to point to an absolute physical address PcdVpdBaseAddress64
+ # to store PCD value. It will be DynamicExDefault only.
+ # It is used to set VPD region base address. So, it can't be DynamicExVpd PCD. Its value is
+ # required to be accessed in PcdDxe driver entry point. So, its value must be set in PEI phase.
+ # It can't depend on EFI variable service, and can't be DynamicExHii PCD.
+ # @Prompt 64bit VPD base address.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress64|0x0|UINT64|0x00030006
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MdeModulePkgExtra.uni
diff --git a/roms/edk2/MdeModulePkg/MdeModulePkg.dsc b/roms/edk2/MdeModulePkg/MdeModulePkg.dsc
new file mode 100644
index 000000000..25aea3e2a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/MdeModulePkg.dsc
@@ -0,0 +1,495 @@
+## @file
+# EFI/PI Reference Module Package for All Architectures
+#
+# (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ PLATFORM_NAME = MdeModule
+ PLATFORM_GUID = 587CE499-6CBE-43cd-94E2-186218569478
+ PLATFORM_VERSION = 0.98
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/MdeModule
+ SUPPORTED_ARCHITECTURES = IA32|X64|EBC|ARM|AARCH64|RISCV64
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+
+[LibraryClasses]
+ #
+ # Entry point
+ #
+ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ #
+ # Basic
+ #
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+ PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
+ #
+ # UEFI & PI
+ #
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+ #
+ # Generic Modules
+ #
+ UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
+ UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+ FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ #
+ # Misc
+ #
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+ ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+ SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf
+ S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+ CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
+ PlatformBootManagerLib|MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
+ PciHostBridgeLib|MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
+ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+ VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+ NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
+
+ FmpAuthenticationLib|MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+ SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+ DisplayUpdateProgressLib|MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf
+
+[LibraryClasses.EBC.PEIM]
+ IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
+
+[LibraryClasses.common.PEI_CORE]
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+
+[LibraryClasses.common.PEIM]
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
+
+[LibraryClasses.common.DXE_CORE]
+ HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
+ MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
+
+[LibraryClasses.common.SMM_CORE]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
+ SmmServicesTableLib|MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
+ SmmCorePlatformHookLib|MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
+ SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf
+
+[LibraryClasses.common.DXE_SMM_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+ MmServicesTableLib|MdePkg/Library/MmServicesTableLib/MmServicesTableLib.inf
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
+ SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+
+[LibraryClasses.common.UEFI_APPLICATION]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+
+[LibraryClasses.common.MM_STANDALONE]
+ HobLib|MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
+ MemoryAllocationLib|MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf
+ StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
+ MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
+
+[LibraryClasses.ARM, LibraryClasses.AARCH64]
+ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+ ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
+ LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+
+ #
+ # It is not possible to prevent ARM compiler calls to generic intrinsic functions.
+ # This library provides the instrinsic functions generated by a given compiler.
+ # [LibraryClasses.ARM] and NULL mean link this library into all ARM images.
+ #
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+
+ #
+ # Since software stack checking may be heuristically enabled by the compiler
+ # include BaseStackCheckLib unconditionally.
+ #
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+[LibraryClasses.EBC, LibraryClasses.RISCV64]
+ LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+
+[PcdsFeatureFlag]
+ gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathToText|FALSE
+
+[PcdsFixedAtBuild]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0f
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule|0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule|0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries|28
+
+[PcdsDynamicExDefault]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
+
+[Components]
+ MdeModulePkg/Application/HelloWorld/HelloWorld.inf
+ MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
+ MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
+
+ MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+ MdeModulePkg/Logo/Logo.inf
+ MdeModulePkg/Logo/LogoDxe.inf
+ MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
+ MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+ MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+ MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+ MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+ MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+ MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
+ MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
+ MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
+ MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf
+
+ MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+ MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
+ MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+ MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
+ MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+ MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
+ MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
+ MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf
+ MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf
+ MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
+ MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
+ MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+ MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
+ MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
+ MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf
+ MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
+ MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+ MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
+ MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
+ MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf
+ MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf
+ MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
+ MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf
+ MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf
+ MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf
+ MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
+ MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+ MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+ MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
+ MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+ MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+ MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+ MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+ MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf
+ MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf
+ MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf
+ MdeModulePkg/Bus/I2c/I2cDxe/I2cHostDxe.inf
+ MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
+ MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
+ MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
+ MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
+ MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+
+ MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+ MdeModulePkg/Core/Pei/PeiMain.inf
+ MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+
+ MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ MdeModulePkg/Library/UefiMemoryAllocationProfileLib/UefiMemoryAllocationProfileLib.inf
+ MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+ MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationProfileLib.inf
+ MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
+ MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf
+ MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf
+ MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
+ MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
+ MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf
+ MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ MdeModulePkg/Library/ResetUtilityLib/ResetUtilityLib.inf
+ MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+ MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+ MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+ MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+ MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+ MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.inf
+ MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+ MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+ MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
+ MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+ MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf
+ MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
+ MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf
+ MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
+ MdeModulePkg/Library/PeiDebugLibDebugPpi/PeiDebugLibDebugPpi.inf
+ MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+ MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
+ MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+ MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+ MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+ MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+ MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+ MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
+ MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+ MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf
+ MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
+ MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf
+ MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf
+ MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf
+ MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
+ MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+ MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf
+ MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf
+
+ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+ MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
+ MdeModulePkg/Application/UiApp/UiApp.inf{
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+ }
+ MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
+ MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.inf
+ MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
+ MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.inf
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+ MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutputDxe.inf
+ MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.inf
+ MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
+ MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
+ MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+ MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf
+ MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
+ MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+ MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf
+ MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
+ MdeModulePkg/Universal/Metronome/Metronome.inf
+ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+ MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf {
+ <LibraryClasses>
+ ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+ }
+ MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf {
+ <LibraryClasses>
+ ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+ }
+ MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+ MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf
+
+ MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.inf
+ MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+ MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+ MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatformDriOverrideDxe.inf
+
+ MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
+ MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
+
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+ MdeModulePkg/Application/VariableInfo/VariableInfo.inf
+ MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
+ MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
+ MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+ MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+
+ MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
+ MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+ MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleDxe.inf
+ MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.inf
+
+ MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
+ MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
+
+ MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf {
+ <LibraryClasses>
+ LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+ }
+ MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf
+ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
+ MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ }
+ MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
+ }
+
+ MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf
+ MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf
+ MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf
+
+ MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.inf {
+ <LibraryClasses>
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+ }
+
+ MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+ MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf
+
+ MdeModulePkg/Universal/DebugServicePei/DebugServicePei.inf
+
+ MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
+ MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf
+ MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
+ MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
+
+[Components.IA32, Components.X64, Components.AARCH64]
+ MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+ MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
+ MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf
+
+[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
+ MdeModulePkg/Library/BrotliCustomDecompressLib/BrotliCustomDecompressLib.inf
+ MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ MdeModulePkg/Core/Dxe/DxeMain.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ }
+
+!if $(TOOL_CHAIN_TAG) != "XCODE5"
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+!endif
+
+[Components.IA32, Components.X64]
+ MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf
+ MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.inf
+ MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
+ MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+ NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+ }
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+ NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+ }
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+ MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+ MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
+ MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf
+ MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
+ MdeModulePkg/Library/SmmMemoryAllocationProfileLib/SmmMemoryAllocationProfileLib.inf
+ MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf
+ MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
+ MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
+ MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
+ MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
+ MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+ MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
+ MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
+ MdeModulePkg/Library/SmmSmiHandlerProfileLib/SmmSmiHandlerProfileLib.inf
+ MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
+ MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
+ MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
+ MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf
+ MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf
+ MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
+ MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
+ MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
+
+[Components.X64]
+ MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
+
+[BuildOptions]
+ *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
diff --git a/roms/edk2/MdeModulePkg/MdeModulePkg.uni b/roms/edk2/MdeModulePkg/MdeModulePkg.uni
new file mode 100644
index 000000000..b8c867379
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/MdeModulePkg.uni
@@ -0,0 +1,1313 @@
+// /** @file
+// This package provides the modules that conform to UEFI/PI Industry standards.
+//
+// It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
+// and libraries instances, which are used for those modules.
+//
+// Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_PACKAGE_ABSTRACT #language en-US "Provides the modules that conform to UEFI/PI Industry standards"
+
+#string STR_PACKAGE_DESCRIPTION #language en-US "It also provides the definitions (including PPIs/PROTOCOLs/GUIDs and library classes) and libraries instances, which are used for those modules."
+
+
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadModuleAtFixAddressEnable_PROMPT #language en-US "Enable LMFA feature"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadModuleAtFixAddressEnable_HELP #language en-US "Flag of enabling/disabling the feature of Loading Module at Fixed Address.<BR><BR>\n"
+ "0xFFFFFFFFFFFFFFFF: Enable the feature as fixed offset to TOLM.<BR>\n"
+ "0: Disable the feature.<BR>\n"
+ "Other Value: Enable the feature as fixed absolute address, and the value is the top memory address.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000001 #language en-US "Invalid value provided."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeOsLoaderLoad_PROMPT #language en-US "Progress Code for OS Loader LoadImage start."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeOsLoaderLoad_HELP #language en-US "Progress Code for OS Loader LoadImage start.<BR><BR>\n"
+ "PROGRESS_CODE_OS_LOADER_LOAD = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03058000<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000003 #language en-US "Incorrect progress code provided."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeOsLoaderStart_PROMPT #language en-US "Progress Code for OS Loader StartImage start"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeOsLoaderStart_HELP #language en-US "Progress Code for OS Loader StartImage start.<BR><BR>\n"
+ "PROGRESS_CODE_OS_LOADER_START = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03058001<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeS3SuspendStart_PROMPT #language en-US "Progress Code for S3 Suspend start"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeS3SuspendStart_HELP #language en-US "Progress Code for S3 Suspend start.<BR><BR>\n"
+ "PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03078000<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeS3SuspendEnd_PROMPT #language en-US "Progress Code for S3 Suspend end"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdProgressCodeS3SuspendEnd_HELP #language en-US "Progress Code for S3 Suspend end.<BR><BR>\n"
+ "PROGRESS_CODE_S3_SUSPEND_END = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03078001<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdErrorCodeSetVariable_PROMPT #language en-US "Error Code for SetVariable failure"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdErrorCodeSetVariable_HELP #language en-US "Error Code for SetVariable failure.<BR><BR>\n"
+ "EDKII_ERROR_CODE_SET_VARIABLE = (EFI_SOFTWARE_DXE_BS_DRIVER | (EFI_OEM_SPECIFIC | 0x00000002)) = 0x03058002<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000006 #language en-US "Incorrect error code provided."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPcdCallBackNumberPerPcdEntry_PROMPT #language en-US "Max PEI PCD callback number per PCD entry"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPcdCallBackNumberPerPcdEntry_HELP #language en-US "Dynamic type PCD can be registered callback function for Pcd setting action. PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function for a dynamic PCD used in PEI phase."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVpdBaseAddress_PROMPT #language en-US "VPD base address"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVpdBaseAddress_HELP #language en-US "VPD type PCD allows a developer to point to an absolute physical address PCDVPDBASEADDRESS to store PCD value."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiCoreMaxPeiStackSize_PROMPT #language en-US "Maximum stack size for PeiCore"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiCoreMaxPeiStackSize_HELP #language en-US "Maximum stack size for PeiCore."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxVariableSize_PROMPT #language en-US "Maximum variable size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxVariableSize_HELP #language en-US "The maximum size of a single non-HwErr type variable."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxAuthVariableSize_PROMPT #language en-US "Maximum authenticated variable size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxAuthVariableSize_HELP #language en-US "The maximum size of a single authenticated variable."
+ "The value is 0 as default for compatibility that maximum authenticated variable size is specified by PcdMaxVariableSize."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxVolatileVariableSize_PROMPT #language en-US "The maximum size of a single non-authenticated volatile variable."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxVolatileVariableSize_HELP #language en-US "The maximum size of a single non-authenticated volatile variable.<BR><BR>\n"
+ "The default value is 0 for compatibility: in that case, the maximum "
+ "non-authenticated volatile variable size remains specified by "
+ "PcdMaxVariableSize.<BR>\n"
+ "Only the MdeModulePkg/Universal/Variable/RuntimeDxe driver supports this PCD.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxHardwareErrorVariableSize_PROMPT #language en-US "Maximum HwErr variable size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxHardwareErrorVariableSize_HELP #language en-US "The maximum size of single hardware error record variable.<BR><BR>\n"
+ "In IA32/X64 platforms, this value should be larger than 1KB.<BR>\n"
+ "In IA64 platforms, this value should be larger than 128KB.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHwErrStorageSize_PROMPT #language en-US "HwErr variable storage size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHwErrStorageSize_HELP #language en-US "The size of reserved HwErr variable space. Note that this value must be less than or equal to PcdFlashNvStorageVariableSize. In EdkII implementation, HwErr type variable is stored with common non-volatile variables in the same NV region. so the platform integrator should ensure this value is less than or equal to PcdFlashNvStorageVariableSize. this value is used to guarantee the space of HwErr type variable and not populated by common variable."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxUserNvVariableSpaceSize_PROMPT #language en-US "Maximum user NV variable space size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxUserNvVariableSpaceSize_HELP #language en-US "The size of maximum user NV variable space.<BR><BR>\n"
+ "Note that this value must be less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize).<BR>\n"
+ "If the value is 0, it means user variable share the same NV storage with system variable, "
+ "this is designed to keep the compatibility for the platform that does not allocate special region for user variable.<BR>\n"
+ "If the value is non-0, the below 4 types of variables will be regarded as System Variable after EndOfDxe, their property could be got by VarCheck protocol, "
+ "otherwise the variable will be regarded as user variable.<BR>\n"
+ " 1) UEFI defined variables (gEfiGlobalVariableGuid and gEfiImageSecurityDatabaseGuid(auth variable) variables at least).<BR>\n"
+ " 2) Variables managed by Variable driver internally.<BR>\n"
+ " 3) Variables need to be locked, they MUST be set by VariableLock protocol.<BR>\n"
+ " 4) Important variables during platform boot, their property SHOULD be set by VarCheck protocol.<BR>\n"
+ "The PCD is used to guarantee the space of system variable and not populated by user variable.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBoottimeReservedNvVariableSpaceSize_PROMPT #language en-US "Boottime reserved NV variable space size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBoottimeReservedNvVariableSpaceSize_HELP #language en-US "The size of NV variable space reserved at UEFI boottime.<BR><BR>\n"
+ "Note that this value must be less than (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize).<BR>\n"
+ "In EdkII implementation, variable driver can reserved some NV storage region for boottime settings. "
+ "So at UEFI runtime, the variable service consumer can not exhaust full NV storage region.<BR>\n"
+ "Then the common NV variable space size at boottime will be "
+ " (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize),<BR>\n"
+ "and the common NV variable space size at runtime will be "
+ " (PcdFlashNvStorageVariableSize - EFI_FIRMWARE_VOLUME_HEADER.HeaderLength - sizeof (VARIABLE_STORE_HEADER) - PcdHwErrStorageSize) - PcdBoottimeReservedNvVariableSpaceSize.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdReclaimVariableSpaceAtEndOfDxe_PROMPT #language en-US "Reclaim variable space at EndOfDxe"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdReclaimVariableSpaceAtEndOfDxe_HELP #language en-US "Reclaim variable space at EndOfDxe.<BR><BR>\n"
+ "The value is FALSE as default for compatibility that variable driver tries to reclaim variable space at ReadyToBoot event.<BR>\n"
+ "If the value is set to TRUE, variable driver tries to reclaim variable space at EndOfDxe event.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableStoreSize_PROMPT #language en-US "Variable storage size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableStoreSize_HELP #language en-US "The size of volatile buffer. This buffer is used to store VOLATILE attribute variables."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiTableStorageFile_PROMPT #language en-US "FFS name of ACPI tables storage"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiTableStorageFile_HELP #language en-US "FFS filename to find the ACPI tables."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleCoalesceFile_PROMPT #language en-US "FFS name of capsule coalesce image"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleCoalesceFile_HELP #language en-US "FFS filename to find the capsule coalesce image."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPerformanceLogEntries_PROMPT #language en-US "Maximum number of PEI performance log entries"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPerformanceLogEntries_HELP #language en-US "Maximum number of performance log entries during PEI phase.\n"
+ "Use PcdMaxPeiPerformanceLogEntries16 if the number of entries required is\n"
+ "more than 255."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPerformanceLogEntries16_PROMPT #language en-US "Maximum number of PEI performance log entries"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxPeiPerformanceLogEntries16_HELP #language en-US "Maximum number of performance log entries during PEI phase.\n"
+ "If set to 0, then PcdMaxPeiPerformanceLogEntries determines the number of\n"
+ "entries. If greater than 0, then this PCD determines the number of entries,\n"
+ "and PcdMaxPeiPerformanceLogEntries is ignored."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseMmio_PROMPT #language en-US "Serial port registers use MMIO"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseMmio_HELP #language en-US "Indicates the 16550 serial port registers are in MMIO space, or in I/O space. Default is I/O space.<BR><BR>\n"
+ "TRUE - 16550 serial port registers are in MMIO space.<BR>\n"
+ "FALSE - 16550 serial port registers are in I/O space.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterAccessWidth_PROMPT #language en-US "Serial port registers access width"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterAccessWidth_HELP #language en-US "Sets the 16550 serial port registers access width in MMIO space. Default is 8 bits access.<BR><BR>\n"
+ "8 - 16550 serial port MMIO register access are in 8 bits mode.<BR>\n"
+ "32 - 16550 serial port MMIO registers acess are in 32 bits mode.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseHardwareFlowControl_PROMPT #language en-US "Enable serial port hardware flow control"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseHardwareFlowControl_HELP #language en-US "Indicates if the 16550 serial port hardware flow control will be enabled. Default is FALSE.<BR><BR>\n"
+ "TRUE - 16550 serial port hardware flow control will be enabled.<BR>\n"
+ "FALSE - 16550 serial port hardware flow control will be disabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialDetectCable_PROMPT #language en-US "Enable serial port cable detection"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialDetectCable_HELP #language en-US "Indicates if the 16550 serial Tx operations will be blocked if DSR is not asserted (no cable). Default is FALSE. This PCD is ignored if PcdSerialUseHardwareFlowControl is FALSE.<BR><BR>\n"
+ "TRUE - 16550 serial Tx operations will be blocked if DSR is not asserted.<BR>\n"
+ "FALSE - 16550 serial Tx operations will not be blocked if DSR is not asserted.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterBase_PROMPT #language en-US "Base address of serial port registers"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterBase_HELP #language en-US "Base address of 16550 serial port registers in MMIO or I/O space. Default is 0x3F8."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialBaudRate_PROMPT #language en-US "Baud rate for serial port"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialBaudRate_HELP #language en-US "Baud rate for the 16550 serial port. Default is 115200 baud."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialLineControl_PROMPT #language en-US "Serial port Line Control settings"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialLineControl_HELP #language en-US "Line Control Register (LCR) for the 16550 serial port. This encodes data bits, parity, and stop bits.<BR><BR>\n"
+ "BIT1..BIT0 - Data bits. 00b = 5 bits, 01b = 6 bits, 10b = 7 bits, 11b = 8 bits<BR>\n"
+ "BIT2 - Stop Bits. 0 = 1 stop bit. 1 = 1.5 stop bits if 5 data bits selected, otherwise 2 stop bits.<BR>\n"
+ "BIT5..BIT3 - Parity. xx0b = No Parity, 001b = Odd Parity, 011b = Even Parity, 101b = Mark Parity, 111b=Stick Parity<BR>\n"
+ "BIT7..BIT6 - Reserved. Must be 0.<BR>\n"
+ "Default is No Parity, 8 Data Bits, 1 Stop Bit.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000002 #language en-US "Reserved bits must be set to zero."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialFifoControl_PROMPT #language en-US "Serial port FIFO Control settings"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialFifoControl_HELP #language en-US "FIFO Control Register (FCR) for the 16550 serial port.<BR><BR>\n"
+ "BIT0 - FIFO Enable. 0 = Disable FIFOs. 1 = Enable FIFOs.<BR>\n"
+ "BIT1 - Clear receive FIFO. 1 = Clear FIFO.<BR>\n"
+ "BIT2 - Clear transmit FIFO. 1 = Clear FIFO.<BR>\n"
+ "BIT4..BIT3 - Reserved. Must be 0.<BR>\n"
+ "BIT5 - Enable 64-byte FIFO. 0 = Disable 64-byte FIFO. 1 = Enable 64-byte FIFO<BR>\n"
+ "BIT7..BIT6 - Reserved. Must be 0.<BR>\n"
+ "Default is to enable and clear all FIFOs.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxEfiSystemTablePointerAddress_PROMPT #language en-US "Maximum Efi System Table Pointer address"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxEfiSystemTablePointerAddress_HELP #language en-US "Maximum address that the DXE Core will allocate the EFI_SYSTEM_TABLE_POINTER structure. The default value for this PCD is 0, which means that the DXE Core will allocate the buffer from the EFI_SYSTEM_TABLE_POINTER structure on a 4MB boundary as close to the top of memory as feasible. If this PCD is set to a value other than 0, then the DXE Core will first attempt to allocate the EFI_SYSTEM_TABLE_POINTER structure on a 4MB boundary below the address specified by this PCD, and if that allocation fails, retry the allocation on a 4MB boundary as close to the top of memory as feasible."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdShadowPeimOnS3Boot_PROMPT #language en-US "Shadow Peim On S3 Boot"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdShadowPeimOnS3Boot_HELP #language en-US "Indicates if to shadow PEIM on S3 boot path after memory is ready.<BR><BR>\n"
+ "TRUE - Shadow PEIM on S3 boot path after memory is ready.<BR>\n"
+ "FALSE - Not shadow PEIM on S3 boot path after memory is ready.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMigrateTemporaryRamFirmwareVolumes_HELP #language en-US "Enable the feature that evacuate temporary memory to permanent memory or not.<BR><BR>\n"
+ "It will allocate page to save the temporary PEIMs resided in NEM(or CAR) to the permanent memory and change all pointers pointed to the NEM(or CAR) to permanent memory.<BR><BR>\n"
+ "After then, there are no pointer pointed to NEM(or CAR) and TOCTOU volnerability can be avoid.<BR><BR>\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMigrateTemporaryRamFirmwareVolumes_PROMPT #language en-US "Enable the feature that evacuate temporary memory to permanent memory or not"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemId_PROMPT #language en-US "Default OEM ID for ACPI table creation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemId_HELP #language en-US "Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemTableId_PROMPT #language en-US "Default OEM Table ID for ACPI table creation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemTableId_HELP #language en-US "Default OEM Table ID for ACPI table creation.<BR><BR>\n"
+ "According to ACPI specification, this field is particularly useful when\n"
+ "defining a definition block to distinguish definition block functions.<BR>\n"
+ "The OEM assigns each dissimilar table a new OEM Table ID.<BR>\n"
+ "This PCD is ignored for definition block.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemRevision_PROMPT #language en-US "Default OEM Revision for ACPI table creation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultOemRevision_HELP #language en-US "Default OEM Revision for ACPI table creation.<BR><BR>\n"
+ "According to ACPI specification, for LoadTable() opcode, the OS can also\n"
+ "check the OEM Table ID and Revision ID against a database for a newer\n"
+ "revision Definition Block of the same OEM Table ID and load it instead.<BR>\n"
+ "This PCD is ignored for definition block.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultCreatorId_PROMPT #language en-US "Default Creator ID for ACPI table creation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultCreatorId_HELP #language en-US "Default Creator ID for ACPI table creation.<BR><BR>\n"
+ "According to ACPI specification, for tables containing Definition Blocks,\n"
+ "this is the ID for the ASL Compiler.<BR>\n"
+ "This PCD is ignored for definition block.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultCreatorRevision_PROMPT #language en-US "Default Creator Revision for ACPI table creation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiDefaultCreatorRevision_HELP #language en-US "Default Creator Revision for ACPI table creation.<BR><BR>\n"
+ "According to ACPI specification, for tables containing Definition Blocks,\n"
+ "this is the revision for the ASL Compiler.<BR>\n"
+ "This PCD is ignored for definition block.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfilePropertyMask_PROMPT #language en-US "Memory Profile Property"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfilePropertyMask_HELP #language en-US "The mask is used to control memory profile behavior.<BR><BR>\n"
+ "BIT0 - Enable UEFI memory profile.<BR>\n"
+ "BIT1 - Enable SMRAM profile.<BR>\n"
+ "BIT7 - Disable recording at the start.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileMemoryType_PROMPT #language en-US "Memory profile memory type"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileMemoryType_HELP #language en-US "This flag is to control which memory types of alloc info will be recorded by DxeCore & SmmCore.<BR><BR>\n"
+ "For SmmCore, only EfiRuntimeServicesCode and EfiRuntimeServicesData are valid.<BR>\n"
+ "Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>\n"
+ " EfiReservedMemoryType 0x0001<BR>\n"
+ " EfiLoaderCode 0x0002<BR>\n"
+ " EfiLoaderData 0x0004<BR>\n"
+ " EfiBootServicesCode 0x0008<BR>\n"
+ " EfiBootServicesData 0x0010<BR>\n"
+ " EfiRuntimeServicesCode 0x0020<BR>\n"
+ " EfiRuntimeServicesData 0x0040<BR>\n"
+ " EfiConventionalMemory 0x0080<BR>\n"
+ " EfiUnusableMemory 0x0100<BR>\n"
+ " EfiACPIReclaimMemory 0x0200<BR>\n"
+ " EfiACPIMemoryNVS 0x0400<BR>\n"
+ " EfiMemoryMappedIO 0x0800<BR>\n"
+ " EfiMemoryMappedIOPortSpace 0x1000<BR>\n"
+ " EfiPalCode 0x2000<BR>\n"
+ " EfiPersistentMemory 0x4000<BR>\n"
+ " OEM Reserved 0x40000000<BR>\n"
+ " OS Reserved 0x80000000<BR>\n"
+ "e.g. Reserved+ACPINvs+ACPIReclaim+RuntimeCode+RuntimeData are needed, 0x661 should be used.<BR>\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileDriverPath_PROMPT #language en-US "Memory profile driver path"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileDriverPath_HELP #language en-US "This PCD is to control which drivers need memory profile data.<BR><BR>\n"
+ "For example:<BR>\n"
+ "One image only (Shell):<BR>\n"
+ " Header GUID<BR>\n"
+ " {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,<BR>\n"
+ " 0x7F, 0xFF, 0x04, 0x00}<BR>\n"
+ "Two or more images (Shell + WinNtSimpleFileSystem):<BR>\n"
+ " {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,<BR>\n"
+ " 0x7F, 0x01, 0x04, 0x00,<BR>\n"
+ " 0x04, 0x06, 0x14, 0x00, 0x8B, 0xE1, 0x25, 0x9C, 0xBA, 0x76, 0xDA, 0x43, 0xA1, 0x32, 0xDB, 0xB0, 0x99, 0x7C, 0xEF, 0xEF,<BR>\n"
+ " 0x7F, 0xFF, 0x04, 0x00}<BR>\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialClockRate_PROMPT #language en-US "Serial Port Clock Rate"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialClockRate_HELP #language en-US "UART clock frequency is for the baud rate configuration."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialPciDeviceInfo_PROMPT #language en-US "PCI Serial Device Info"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialPciDeviceInfo_HELP #language en-US "PCI Serial Device Info. It is an array of Device, Function, and Power Management\n"
+ "information that describes the path that contains zero or more PCI to PCI briges\n"
+ "followed by a PCI serial device. Each array entry is 4-bytes in length. The\n"
+ "first byte is the PCI Device Number, then second byte is the PCI Function Number,\n"
+ "and the last two bytes are the offset to the PCI power management capabilities\n"
+ "register used to manage the D0-D3 states. If a PCI power management capabilities\n"
+ "register is not present, then the last two bytes in the offset is set to 0. The\n"
+ "array is terminated by an array entry with a PCI Device Number of 0xFF. For a\n"
+ "non-PCI fixed address serial device, such as an ISA serial device, the value is 0xFF."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialExtendedTxFifoSize_PROMPT #language en-US "Serial Port Extended Transmit FIFO Size in Bytes"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialExtendedTxFifoSize_HELP #language en-US "Serial Port Extended Transmit FIFO Size. The default is 64 bytes."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterStride_PROMPT #language en-US "Serial Port Register Stride in Bytes"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialRegisterStride_HELP #language en-US "The number of bytes between registers in serial device. The default is 1 byte."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetNxForStack_PROMPT #language en-US "Set NX for stack"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetNxForStack_HELP #language en-US "Indicates if to set NX for stack.<BR><BR>"
+ "For the DxeIpl and the DxeCore are both X64, set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE.<BR>"
+ "For the DxeIpl and the DxeCore are both IA32 (PcdDxeIplSwitchToLongMode is FALSE), set NX for stack feature also require"
+ "IA32 PAE is supported and Execute Disable Bit is available.<BR>"
+ "TRUE - Set NX for stack.<BR>"
+ "FALSE - Do nothing for stack.<BR>"
+ "Note: If this PCD is set to FALSE, NX could be still applied to stack due to PcdDxeNxMemoryProtectionPolicy enabled for EfiBootServicesData.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiS3Enable_PROMPT #language en-US "ACPI S3 Enable"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiS3Enable_HELP #language en-US "Indicates if ACPI S3 will be enabled.<BR><BR>"
+ "TRUE - ACPI S3 will be enabled.<BR>"
+ "FALSE - ACPI S3 will be disabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptStackSize_PROMPT #language en-US "Reserved S3 Boot Script Stack ACPI Memory Size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptStackSize_HELP #language en-US "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."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVarCheckVfrDriverGuidArray_PROMPT #language en-US "Driver guid array of VFR drivers for VarCheckHiiBin generation"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVarCheckVfrDriverGuidArray_HELP #language en-US "This PCD to include the driver guid of VFR drivers for VarCheckHiiBin generation.<BR><BR>"
+ "Default is gZeroGuid that means no VFR driver will be parsed for VarCheckHiiBin generation.<BR>"
+ "If it is set to an all FFs GUID, it means all modules in all FVs will be parsed for VarCheckHiiBin generation.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableBase_PROMPT #language en-US "Base address of flash NV variable range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableBase_HELP #language en-US "Base address of the NV variable range in flash device."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableSize_PROMPT #language en-US "Size of flash NV variable range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableSize_HELP #language en-US "Size of the NV variable range. Note that this value should less than or equal to PcdFlashNvStorageFtwSpareSize. The root cause is that variable driver will use FTW protocol to reclaim variable region. If the length of variable region is larger than FTW spare size, it means the whole variable region cannot be reflushed through the manner of fault tolerant write."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareBase_PROMPT #language en-US "Base address of flash FTW spare block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareBase_HELP #language en-US "Base address of the FTW spare block range in flash device. Note that this value should be block size aligned."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareSize_PROMPT #language en-US "Size of flash FTW spare block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareSize_HELP #language en-US "Size of the FTW spare block range. Note that this value should larger than PcdFlashNvStorageVariableSize and block size aligned. The root cause is that variable driver will use FTW protocol to reclaim variable region. If the length of variable region is larger than FTW spare size, it means the whole variable region cannot be reflushed through the manner of fault tolerant write."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingBase_PROMPT #language en-US "Base address of flash FTW working block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingBase_HELP #language en-US "Base address of the FTW working block range in flash device. If PcdFlashNvStorageFtwWorkingSize is larger than one block size, this value should be block size aligned."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingSize_PROMPT #language en-US "Size of flash FTW working block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingSize_HELP #language en-US "Size of the FTW working block range. If the value is less than one block size, the work space range should not span blocks. If the value is larger than one block size, it should be block size aligned."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableBase64_PROMPT #language en-US "64-bit Base address of flash NV variable range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageVariableBase64_HELP #language en-US "64-bit Base address of the NV variable range in flash device."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareBase64_PROMPT #language en-US "64-bit Base address of flash FTW spare block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwSpareBase64_HELP #language en-US "64-bit Base address of the FTW spare block range in flash device. Note that this value should be block size aligned."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingBase64_PROMPT #language en-US "64-bit Base address of flash FTW working block range"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFlashNvStorageFtwWorkingBase64_HELP #language en-US "64-bit Base address of the FTW working block range in flash device. If PcdFlashNvStorageFtwWorkingSize is larger than one block size, this value should be block size aligned."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEmuVariableNvModeEnable_PROMPT #language en-US "EMU variable NV mode enable"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEmuVariableNvModeEnable_HELP #language en-US "Indicates if Variable driver will enable emulated variable NV mode.<BR><BR>"
+ "If this PCD is configured to dynamic, its value should be set before Variable driver starts to work,<BR>"
+ "otherwise default value will take effect.<BR>"
+ "TRUE - An EMU variable NV storage will be allocated or reserved for NV variables.<BR>"
+ "FALSE - No EMU variable NV storage will be allocated or reserved for NV variables.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEmuVariableNvStoreReserved_PROMPT #language en-US "Base of reserved memory range for EMU variable NV storage"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEmuVariableNvStoreReserved_HELP #language en-US "This PCD defines the base address of reserved memory range for EMU variable NV storage. A non-ZERO value indicates a valid range reserved with size given by PcdVariableStoreSize."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintTimes_PROMPT #language en-US "HelloWorld print times"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintTimes_HELP #language en-US "This PCD defines the times to print hello world string. This PCD is a sample to explain UINT32 PCD usage."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintString_PROMPT #language en-US "HelloWorld print string"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintString_HELP #language en-US "This PCD defines the HelloWorld print string. This PCD is a sample to explain String typed PCD usage."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxSizePopulateCapsule_PROMPT #language en-US "Max size of populated capsule"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxSizePopulateCapsule_HELP #language en-US "Indicates the maximum size of the capsule image with a reset flag that the platform can support. The default max size is 100MB (0x6400000) for more than one large capsule images."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxSizeNonPopulateCapsule_PROMPT #language en-US "Max size of non-populated capsule"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxSizeNonPopulateCapsule_HELP #language en-US "Indicates the maximum size of the capsule image without a reset flag that the platform can support. The default max size is 10MB (0xa00000) for the capsule image without reset flag setting."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareVendor_PROMPT #language en-US "Firmware vendor"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareVendor_HELP #language en-US "Null-terminated Unicode string of the firmware vendor name that is the default name filled into the EFI System Table."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareRevision_PROMPT #language en-US "Firmware revision"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareRevision_HELP #language en-US "Firmware revision that is the default revision filled into the EFI System Table."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareVersionString_PROMPT #language en-US "Firmware version string"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareVersionString_HELP #language en-US "Null-terminated Unicode string that describes the firmware version."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareReleaseDateString_PROMPT #language en-US "Firmware release data string"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwareReleaseDateString_HELP #language en-US "Null-terminated Unicode string that contains the date the firmware was released"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeMemorySize_PROMPT #language en-US "StatusCode memory size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeMemorySize_HELP #language en-US "PcdStatusCodeMemorySize is used when PcdStatusCodeUseMemory is set to true. (PcdStatusCodeMemorySize * KBytes) is the total taken memory size.<BR><BR>\n"
+ "The default value in PeiPhase is 1 KBytes.<BR>\n"
+ "The default value in DxePhase is 128 KBytes.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdResetOnMemoryTypeInformationChange_PROMPT #language en-US "Reset on memory type information change"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdResetOnMemoryTypeInformationChange_HELP #language en-US "Indicates if to reset system when memory type information changes.<BR><BR>\n"
+ "TRUE - Resets system when memory type information changes.<BR>\n"
+ "FALSE - Does not reset system when memory type information changes.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPlatformRecoverySupport_PROMPT #language en-US "Support Platform Recovery"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPlatformRecoverySupport_HELP #language en-US "Indicates if the BDS supports Platform Recovery.<BR><BR>\n"
+ "TRUE - BDS supports Platform Recovery.<BR>\n"
+ "FALSE - BDS does not support Platform Recovery.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserSubtitleTextColor_PROMPT #language en-US "Foreground color for browser subtitle"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserSubtitleTextColor_HELP #language en-US "Specify the foreground color for Subtitle text in HII Form Browser. The default value is EFI_BLUE. Only following values defined in UEFI specification are valid:<BR><BR>\n"
+ "0x00 (EFI_BLACK)<BR>\n"
+ "0x01 (EFI_BLUE)<BR>\n"
+ "0x02 (EFI_GREEN)<BR>\n"
+ "0x03 (EFI_CYAN)<BR>\n"
+ "0x04 (EFI_RED)<BR>\n"
+ "0x05 (EFI_MAGENTA)<BR>\n"
+ "0x06 (EFI_BROWN)<BR>\n"
+ "0x07 (EFI_LIGHTGRAY)<BR>\n"
+ "0x08 (EFI_DARKGRAY)<BR>\n"
+ "0x09 (EFI_LIGHTBLUE)<BR>\n"
+ "0x0A (EFI_LIGHTGREEN)<BR>\n"
+ "0x0B (EFI_LIGHTCYAN)<BR>\n"
+ "0x0C (EFI_LIGHTRED)<BR>\n"
+ "0x0D (EFI_LIGHTMAGENTA)<BR>\n"
+ "0x0E (EFI_YELLOW)<BR>\n"
+ "0x0F (EFI_WHITE)<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000004 #language en-US "Invalid foreground color specified."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldTextColor_PROMPT #language en-US "Foreground color for browser field"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldTextColor_HELP #language en-US "Specify the foreground color for prompt and Question value text in HII Form Browser. The default value is EFI_BLACK. Only following values defined in UEFI specification are valid:<BR><BR>\n"
+ "0x00 (EFI_BLACK)<BR>\n"
+ "0x01 (EFI_BLUE)<BR>\n"
+ "0x02 (EFI_GREEN)<BR>\n"
+ "0x03 (EFI_CYAN)<BR>\n"
+ "0x04 (EFI_RED)<BR>\n"
+ "0x05 (EFI_MAGENTA)<BR>\n"
+ "0x06 (EFI_BROWN)<BR>\n"
+ "0x07 (EFI_LIGHTGRAY)<BR>\n"
+ "0x08 (EFI_DARKGRAY)<BR>\n"
+ "0x09 (EFI_LIGHTBLUE)<BR>\n"
+ "0x0A (EFI_LIGHTGREEN)<BR>\n"
+ "0x0B (EFI_LIGHTCYAN)<BR>\n"
+ "0x0C (EFI_LIGHTRED)<BR>\n"
+ "0x0D (EFI_LIGHTMAGENTA)<BR>\n"
+ "0x0E (EFI_YELLOW)<BR>\n"
+ "0x0F (EFI_WHITE)<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldTextHighlightColor_PROMPT #language en-US "Foreground color for highlighted browser field"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldTextHighlightColor_HELP #language en-US "Specify the foreground color for highlighted prompt and Question value text in HII Form Browser. The default value is EFI_LIGHTGRAY. Only following values defined in UEFI specification are valid:<BR><BR>\n"
+ "0x00 (EFI_BLACK)<BR>\n"
+ "0x01 (EFI_BLUE)<BR>\n"
+ "0x02 (EFI_GREEN)<BR>\n"
+ "0x03 (EFI_CYAN)<BR>\n"
+ "0x04 (EFI_RED)<BR>\n"
+ "0x05 (EFI_MAGENTA)<BR>\n"
+ "0x06 (EFI_BROWN)<BR>\n"
+ "0x07 (EFI_LIGHTGRAY)<BR>\n"
+ "0x08 (EFI_DARKGRAY)<BR>\n"
+ "0x09 (EFI_LIGHTBLUE)<BR>\n"
+ "0x0A (EFI_LIGHTGREEN)<BR>\n"
+ "0x0B (EFI_LIGHTCYAN)<BR>\n"
+ "0x0C (EFI_LIGHTRED)<BR>\n"
+ "0x0D (EFI_LIGHTMAGENTA)<BR>\n"
+ "0x0E (EFI_YELLOW)<BR>\n"
+ "0x0F (EFI_WHITE)<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldBackgroundHighlightColor_PROMPT #language en-US "Background color for highlighted browser field"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserFieldBackgroundHighlightColor_HELP #language en-US "Specify the background color for highlighted prompt and Question value text in HII Form Browser. The default value is EFI_BACKGROUND_BLACK. Only following values defined in UEFI specification are valid:<BR><BR>\n"
+ "0x00 (EFI_BACKGROUND_BLACK)<BR>\n"
+ "0x10 (EFI_BACKGROUND_BLUE)<BR>\n"
+ "0x20 (EFI_BACKGROUND_GREEN)<BR>\n"
+ "0x30 (EFI_BACKGROUND_CYAN)<BR>\n"
+ "0x40 (EFI_BACKGROUND_RED)<BR>\n"
+ "0x50 (EFI_BACKGROUND_MAGENTA)<BR>\n"
+ "0x60 (EFI_BACKGROUND_BROWN)<BR>\n"
+ "0x70 (EFI_BACKGROUND_LIGHTGRAY)<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_ERR_80000005 #language en-US "Invalid background color specified."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSataSpinUpDelayInSecForRecoveryPath_PROMPT #language en-US "SATA spin-up delay time in second for recovery path"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSataSpinUpDelayInSecForRecoveryPath_HELP #language en-US "Time in second to delay for SATA devices to spin-up for recovery."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptRuntimeTableReservePageNumber_PROMPT #language en-US "Reserved page number for S3 Boot Script Runtime Table"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptRuntimeTableReservePageNumber_HELP #language en-US "This PCD is used to specify memory size with page number for a pre-allocated ACPI reserved memory to hold runtime(after SmmReadyToLock) created S3 boot script entries. The default page number is 2. When changing the value of this PCD, the platform developer should make sure the memory size is large enough to hold the S3 boot script node created in runtime(after SmmReadyToLock) phase."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsulePeiLongModeStackSize_PROMPT #language en-US "Stack size for CapsulePei transfer to long mode"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsulePeiLongModeStackSize_HELP #language en-US "The PCD is used to specify the stack size when capsule IA32 PEI transfers to long mode in PEI phase. The default size is 32K. When changing the value of this PCD, the platform developer should make sure the memory size is large enough to meet capsule PEI requirement in capsule update path."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUse1GPageTable_PROMPT #language en-US "Enable 1G page table support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUse1GPageTable_HELP #language en-US "Indicates if 1G page table will be enabled.<BR><BR>\n"
+ "TRUE - 1G page table will be enabled.<BR>\n"
+ "FALSE - 1G page table will not be enabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSrIovSupport_PROMPT #language en-US "Enable SRIOV support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSrIovSupport_HELP #language en-US "Indicates if the Single Root I/O virtualization is supported.<BR><BR>\n"
+ "TRUE - Single Root I/O virtualization is supported.<BR>\n"
+ "FALSE - Single Root I/O virtualization is not supported.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAriSupport_PROMPT #language en-US "Enable ARI support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAriSupport_HELP #language en-US "Indicates if the Alternative Routing-ID is supported.<BR><BR>\n"
+ "TRUE - Alternative Routing-ID is supported.<BR>\n"
+ "FALSE - Alternative Routing-ID is not supported.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMrIovSupport_PROMPT #language en-US "Enable MRIOV support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMrIovSupport_HELP #language en-US "Indicates if the Multi Root I/O virtualization is supported.<BR><BR>\n"
+ "TRUE - Multi Root I/O virtualization is supported.<BR>\n"
+ "FALSE - Multi Root I/O virtualization is not supported.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSrIovSystemPageSize_PROMPT #language en-US "SRIOV system page size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSrIovSystemPageSize_HELP #language en-US "Single root I/O virtualization virtual function memory BAR alignment.<BR><BR>\n"
+ "BITN set indicates 2 of n+12 power<BR>\n"
+ "BIT0 set indicates 4KB alignment<BR>\n"
+ "BIT1 set indicates 8KB alignment<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosVersion_PROMPT #language en-US "SMBIOS version"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosVersion_HELP #language en-US "SMBIOS version."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosDocRev_PROMPT #language en-US "SMBIOS Docrev field in SMBIOS 3.0 (64-bit) Entry Point Structure"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosDocRev_HELP #language en-US "SMBIOS Docrev field in SMBIOS 3.0 (64-bit) Entry Point Structure"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosEntryPointProvideMethod_PROMPT #language en-US "SMBIOS produce method"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmbiosEntryPointProvideMethod_HELP #language en-US "The policy to produce SMBIOS entry point and table.<BR><BR>\n"
+ "BIT0 set indicates 32-bit entry point and table are produced.<BR>\n"
+ "BIT1 set indicates 64-bit entry point and table are produced.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdExtFpdtBootRecordPadSize_PROMPT #language en-US "Pad size for extension FPDT boot records"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdExtFpdtBootRecordPadSize_HELP #language en-US "This PCD specifies the additional pad size in FPDT Basic Boot Performance Table for the extension FPDT boot records received after ReadyToBoot and before ExitBootService."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConInConnectOnDemand_PROMPT #language en-US "ConIn connect on demand"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConInConnectOnDemand_HELP #language en-US "Indicates if ConIn device are connected on demand.<BR><BR>\n"
+ "TRUE - ConIn device are not connected during BDS and ReadKeyStroke/ReadKeyStrokeEx produced by Consplitter should be called before any real key read operation.<BR>\n"
+ "FALSE - ConIn device may be connected normally during BDS.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAtaSmartEnable_PROMPT #language en-US "Enable ATA S.M.A.R.T feature"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAtaSmartEnable_HELP #language en-US "Indicates if the S.M.A.R.T feature of attached ATA hard disks will be enabled.<BR><BR>\n"
+ "TRUE - S.M.A.R.T feature of attached ATA hard disks will be enabled.<BR>\n"
+ "FALSE - S.M.A.R.T feature of attached ATA hard disks will be default status.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciDisableBusEnumeration_PROMPT #language en-US "Disable full PCI enumeration"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciDisableBusEnumeration_HELP #language en-US "Indicates if full PCI enumeration is disabled.<BR><BR>\n"
+ "TRUE - Full PCI enumeration is disabled.<BR>\n"
+ "FALSE - Full PCI enumeration is not disabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDiskIoDataBufferBlockNum_PROMPT #language en-US "Disk I/O - Number of Data Buffer block"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDiskIoDataBufferBlockNum_HELP #language en-US "Disk I/O - Number of Data Buffer block. Define the size in block of the pre-allocated buffer. It provide better performance for large Disk I/O requests."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUfsPciHostControllerMmioBase_PROMPT #language en-US "Mmio base address of pci-based UFS host controller"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUfsPciHostControllerMmioBase_HELP #language en-US "This PCD specifies the pci-based UFS host controller mmio base address. Define the mmio base address of the pci-based UFS host controller. If there are multiple UFS host controllers, their mmio base addresses are calculated one by one from this base address."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutRow_PROMPT #language en-US "Console output row"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutRow_HELP #language en-US "This PCD defines the Console output row. The default value is 25 according to UEFI spec. This PCD could be set to 0 then console output would be at max column and max row."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutColumn_PROMPT #language en-US "Console output column"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutColumn_HELP #language en-US "This PCD defines the Console output column. The default value is 80 according to UEFI spec. This PCD could be set to 0 then console output would be at max column and max row."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVideoHorizontalResolution_PROMPT #language en-US "Video horizontal resolution"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVideoHorizontalResolution_HELP #language en-US "This PCD defines the video horizontal resolution. If this PCD is set to 0 then video resolution would be at highest resolution."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVideoVerticalResolution_PROMPT #language en-US "Video vertical resolution"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVideoVerticalResolution_HELP #language en-US "This PCD defines the video vertical resolution. If this PCD is set to 0 then video resolution would be at highest resolution."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressPeiCodePageNumber_PROMPT #language en-US "LMFA PEI code page number"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressPeiCodePageNumber_HELP #language en-US "Specify memory size with page number for PEI code when Loading Module at Fixed Address feature is enabled. The value will be set by the build tool."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressBootTimeCodePageNumber_PROMPT #language en-US "LMFA DXE boot code page number"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressBootTimeCodePageNumber_HELP #language en-US "Specify memory size with page number for DXE boot time code when Loading Module at Fixed Address feature is enabled. The value will be set by the build tool."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressRuntimeCodePageNumber_PROMPT #language en-US "LMFA DXE runtime code page number"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressRuntimeCodePageNumber_HELP #language en-US "Specify memory size with page number for DXE runtime code when Loading Module at Fixed Address feature is enabled. The value will be set by the build tool."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressSmmCodePageNumber_PROMPT #language en-US "LMFA SMM code page number"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdLoadFixAddressSmmCodePageNumber_HELP #language en-US "Specify memory size with page number for SMM code when Loading Module at Fixed Address feature is enabled. The value will be set by the build tool."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportUpdateCapsuleReset_PROMPT #language en-US "Enable update capsule across a system reset"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportUpdateCapsuleReset_HELP #language en-US "Indicates if the platform can support update capsule across a system reset.<BR><BR>\n"
+ "TRUE - Supports update capsule across a system reset.<BR>\n"
+ "FALSE - Does not support update capsule across a system reset.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiFullPcdDatabaseEnable_PROMPT #language en-US "Enable full PEI PCD services"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiFullPcdDatabaseEnable_HELP #language en-US "Indicates if all PCD PPI services will be enabled.<BR><BR>\n"
+ "TRUE - All PCD PPI services will be produced.<BR>\n"
+ "FALSE - Minimal PCD PPI services (only GetService) will be produced.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDevicePathSupportDevicePathToText_PROMPT #language en-US "Enable Device Path to Text support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDevicePathSupportDevicePathToText_HELP #language en-US "Indicates if the Device Path To Text Protocol should be produced by the platform. It can be disabled to save size.<BR><BR>\n"
+ "TRUE - Device Path To Text Protocol will be produced.<BR>\n"
+ "FALSE - Device Path To Text Protocol will not be produced.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDevicePathSupportDevicePathFromText_PROMPT #language en-US "Enable Device Path From Text support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDevicePathSupportDevicePathFromText_HELP #language en-US "Indicates if the Device Path From Text Protocol should be produced by the platform. It can be disabled to save size.<BR><BR>\n"
+ "TRUE - Device Path From Text Protocol will be produced.<BR>\n"
+ "FALSE - Device Path From Text Protocol will not be produced.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEnableVariableRuntimeCache_PROMPT #language en-US "Enable the UEFI variable runtime cache."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEnableVariableRuntimeCache_HELP #language en-US "Indicates if the UEFI variable runtime cache should be enabled.<BR><BR>\n"
+ "This setting only applies if SMM variables are enabled. When enabled, all variable<BR>\n"
+ "data for Runtime Service GetVariable () and GetNextVariableName () calls is retrieved<BR>\n"
+ "from a runtime data buffer referred to as the "runtime cache". An SMI is not triggered<BR>\n"
+ "at all for these requests. Variables writes still trigger an SMI. This can greatly<BR>\n"
+ "reduce overall system SMM usage as most boots tend to issue far more variable reads<BR>\n"
+ "than writes.<BR>\n"
+ "TRUE - The UEFI variable runtime cache is enabled.<BR>\n"
+ "FALSE - The UEFI variable runtime cache is disabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableCollectStatistics_PROMPT #language en-US "Enable variable statistics collection"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableCollectStatistics_HELP #language en-US "Indicates if the statistics about variable usage will be collected. This information is stored as a vendor configuration table into the EFI system table. Set this PCD to TRUE to use VariableInfo application in MdeModulePkg\Application directory to get variable usage info. VariableInfo application will not output information if not set to TRUE.<BR><BR>\n"
+ "TRUE - Statistics about variable usage will be collected.<BR>\n"
+ "FALSE - Statistics about variable usage will not be collected.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnicodeCollationSupport_PROMPT #language en-US "Enable Unicode Collation support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnicodeCollationSupport_HELP #language en-US "Indicates if Unicode Collation Protocol will be installed.<BR><BR>\n"
+ "TRUE - Installs Unicode Collation Protocol.<BR>\n"
+ "FALSE - Does not install Unicode Collation Protocol.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnicodeCollation2Support_PROMPT #language en-US "Enable Unicode Collation 2 support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnicodeCollation2Support_HELP #language en-US "Indicates if Unicode Collation 2 Protocol will be installed.<BR><BR>\n"
+ "TRUE - Installs Unicode Collation 2 Protocol.<BR>\n"
+ "FALSE - Does not install Unicode Collation 2 Protocol.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutGopSupport_PROMPT #language en-US "Enable ConOut GOP support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutGopSupport_HELP #language en-US "Indicates if Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe. It could be set FALSE to save size.<BR><BR>\n"
+ "TRUE - Installs Graphics Output Protocol on virtual handle created by ConsplitterDxe.<BR>\n"
+ "FALSE - Does not install Graphics Output Protocol on virtual handle created by ConsplitterDxe.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutUgaSupport_PROMPT #language en-US "Enable ConOut UGA support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdConOutUgaSupport_HELP #language en-US "Indicates if UGA Draw Protocol will be installed on virtual handle created by ConsplitterDxe. It could be set FALSE to save size.<BR><BR>\n"
+ "TRUE - Installs UGA Draw Protocol on virtual handle created by ConsplitterDxe.<BR>\n"
+ "FALSE - Does not install UGA Draw Protocol on virtual handle created by ConsplitterDxe.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiCoreImageLoaderSearchTeSectionFirst_PROMPT #language en-US "PeiCore search TE section first"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPeiCoreImageLoaderSearchTeSectionFirst_HELP #language en-US "Indicates PeiCore will first search TE section from the PEIM to load the image, or PE32 section, when PeiCore dispatches a PEI module. This PCD is used to tune PEI phase performance to reduce the search image time. It can be set according to the generated image section type.<BR><BR>\n"
+ "TRUE - PeiCore will first search TE section from PEIM to load the image, if TE section is not found, then PeiCore will search PE section.<BR>\n"
+ "FALSE - PeiCore will first search PE section from PEIM to load the image.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTurnOffUsbLegacySupport_PROMPT #language en-US "Turn off USB legacy support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTurnOffUsbLegacySupport_HELP #language en-US "Disable legacy USB? If disabled, legacy USB device driver cannot make use of SMI interrupt to access USB device in the case of absence of a USB stack. TRUE - disable<BR>\n"
+ "FALSE - enable<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportHiiImageProtocol_PROMPT #language en-US "Enable HII image support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportHiiImageProtocol_HELP #language en-US "Indicates if HiiImageProtocol will be installed. FALSE is for size reduction.<BR><BR>\n"
+ "TRUE - Installs HiiImageProtocol.<BR>\n"
+ "FALSE - Does not install HiiImageProtocol.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDisableDefaultKeyboardLayoutInUsbKbDriver_PROMPT #language en-US "Disable default keyboard layout in USB Keyboard Driver"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDisableDefaultKeyboardLayoutInUsbKbDriver_HELP #language en-US "Disable default USB keyboard layout? The default keyboard layout serves as the backup when no keyboard layout can be retrieved from HII database.<BR><BR>\n"
+ "TRUE - disable<BR>\n"
+ "FALSE - enable<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintEnable_PROMPT #language en-US "Enable HelloWorld print"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHelloWorldPrintEnable_HELP #language en-US "Indicates if HelloWorld Application will print the verbose information. This PCD is a sample to explain FeatureFlag PCD usage.<BR><BR>\n"
+ "TRUE - HelloWorld Application will print the verbose information.<BR>\n"
+ "FALSE - HelloWorld Application will not print the verbose information.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFullFtwServiceEnable_PROMPT #language en-US "Enable FULL FTW services"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFullFtwServiceEnable_HELP #language en-US "Indicates if FULL FTW protocol services (total six APIs) will be produced.<BR><BR>\n"
+ "TRUE - Produces FULL FTW protocol services (total six APIs).<BR>\n"
+ "FALSE - Only FTW Write service is available.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplSupportUefiDecompress_PROMPT #language en-US "Enable UEFI decompression support in DXE IPL"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplSupportUefiDecompress_HELP #language en-US "Indicates if DXE IPL supports the UEFI decompression algorithm.<BR><BR>\n"
+ "TRUE - DXE IPL will support UEFI decompression.<BR>\n"
+ "FALSE - DXE IPL will not support UEFI decompression to save space.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciBusHotplugDeviceSupport_PROMPT #language en-US "Enable PciBus hot plug device support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciBusHotplugDeviceSupport_HELP #language en-US "Indicates if PciBus driver supports the hot plug device.<BR><BR>\n"
+ "TRUE - PciBus driver supports the hot plug device.<BR>\n"
+ "FALSE - PciBus driver doesn't support the hot plug device.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciBridgeIoAlignmentProbe_PROMPT #language en-US "Enable PCI bridge IO alignment prob."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciBridgeIoAlignmentProbe_HELP #language en-US "Indicates if the PciBus driver probes non-standard, such as 2K/1K/512, granularity for PCI to PCI bridge I/O window.<BR><BR>\n"
+ "TRUE - PciBus driver probes non-standard granularity for PCI to PCI bridge I/O window.<BR>\n"
+ "FALSE - PciBus driver doesn't probe non-standard granularity for PCI to PCI bridge I/O window.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeUseSerial_PROMPT #language en-US "Enable StatusCode via Serial port"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeUseSerial_HELP #language en-US "Indicates if StatusCode is reported via Serial port.<BR><BR>\n"
+ "TRUE - Reports StatusCode via Serial port.<BR>\n"
+ "FALSE - Does not report StatusCode via Serial port.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeUseMemory_PROMPT #language en-US "Enable StatusCode via memory"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeUseMemory_HELP #language en-US "Indicates if StatusCode is stored in memory. The memory is boot time memory in PEI Phase and is runtime memory in DXE Phase.<BR><BR>\n"
+ "TRUE - Stores StatusCode in memory.<BR>\n"
+ "FALSE - Does not store StatusCode in memory.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeReplayIn_PROMPT #language en-US "Enable PEI StatusCode replay in DXE phase"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeReplayIn_HELP #language en-US "Indicates if PEI phase StatusCode will be replayed in DXE phase.<BR><BR>\n"
+ "TRUE - Replays PEI phase StatusCode in DXE phased.<BR>\n"
+ "FALSE - Does not replay PEI phase StatusCode in DXE phase.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdInstallAcpiSdtProtocol_PROMPT #language en-US "Enable ACPI SDT support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdInstallAcpiSdtProtocol_HELP #language en-US "Indicates if ACPI SDT protocol will be installed.<BR><BR>\n"
+ "TRUE - Installs ACPI SDT protocol.<BR>\n"
+ "FALSE - Does not install ACPI SDT protocol.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnalignedPciIoEnable_PROMPT #language en-US "Enable unaligned PCI I/O support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUnalignedPciIoEnable_HELP #language en-US "Indicates if the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol are enabled. The default value for this PCD is false to disable support for unaligned PCI I/O Protocol requests.<BR><BR>\n"
+ "TRUE - Enables the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol.<BR>\n"
+ "FALSE - Disables the unaligned I/O, MMIO, and PCI Configuration cycles through the PCI I/O Protocol.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserGrayOutTextStatement_PROMPT #language en-US "Always GrayOut TEXT statement"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowserGrayOutTextStatement_HELP #language en-US "Indicates if TEXT statement is always set to GrayOut statement in HII Form Browser.<BR><BR>\n"
+ "TRUE - TEXT statement will always be set to GrayOut.<BR>\n"
+ "FALSE - TEXT statement will be set to GrayOut only when GrayOut condition is TRUE.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowerGrayOutReadOnlyMenu_PROMPT #language en-US "GrayOut read only menu"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBrowerGrayOutReadOnlyMenu_HELP #language en-US "Indicates if unselectable menu should be gray out in HII Form Browser.<BR><BR>\n"
+ "TRUE - The unselectable menu will be set to GrayOut.<BR>\n"
+ "FALSE - The menu will be show as normal menu entry even if it is not selectable.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnIdeDisk_PROMPT #language en-US "Enable recovery on IDE disk"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnIdeDisk_HELP #language en-US "Indicates if recovery from IDE disk will be supported.<BR><BR>\n"
+ "TRUE - Supports recovery from IDE disk.<BR>\n"
+ "FALSE - Does not support recovery from IDE disk.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnFatFloppyDisk_PROMPT #language en-US "Enable recovery on FAT floppy disk"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnFatFloppyDisk_HELP #language en-US "Indicates if recovery from FAT floppy disk will be supported.<BR><BR>\n"
+ "TRUE - Supports recovery from FAT floppy disk.<BR>\n"
+ "FALSE - Does not support recovery from FAT floppy disk.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnDataCD_PROMPT #language en-US "Enable recovery on data CD"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnDataCD_HELP #language en-US "Indicates if recovery from data CD will be supported.<BR><BR>\n"
+ "TRUE - Supports recovery from data CD.<BR>\n"
+ "FALSE - Does not support recovery from data CD.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnFatUsbDisk_PROMPT #language en-US "Enable recovery on FAT USB disk"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryOnFatUsbDisk_HELP #language en-US "Indicates if recovery from FAT USB disk will be supported.<BR><BR>\n"
+ "TRUE - Supports recovery from USB disk.<BR>\n"
+ "FALSE - Does not support recovery from USB disk.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwarePerformanceDataTableS3Support_PROMPT #language en-US "Enable S3 performance data support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFirmwarePerformanceDataTableS3Support_HELP #language en-US "Indicates if S3 performance data will be supported in ACPI FPDT table.<BR><BR>\n"
+ "TRUE - S3 performance data will be supported in ACPI FPDT table.<BR>\n"
+ "FALSE - S3 performance data will not be supported in ACPI FPDT table.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplSwitchToLongMode_PROMPT #language en-US "DxeIpl switch to long mode"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplSwitchToLongMode_HELP #language en-US "Indicates if DxeIpl should switch to long mode to enter DXE phase. It is assumed that 64-bit DxeCore is built in firmware if it is true; otherwise 32-bit DxeCore is built in firmware.<BR><BR>\n"
+ "TRUE - DxeIpl will load a 64-bit DxeCore and switch to long mode to hand over to DxeCore.<BR>\n"
+ "FALSE - DxeIpl will load a 32-bit DxeCore and perform stack switch to hand over to DxeCore.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplBuildPageTables_PROMPT #language en-US "DxeIpl rebuild page tables"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeIplBuildPageTables_HELP #language en-US "Indicates if DxeIpl should rebuild page tables. This flag only makes sense in the case where the DxeIpl and the DxeCore are both X64.<BR><BR>\n"
+ "TRUE - DxeIpl will rebuild page tables.<BR>\n"
+ "FALSE - DxeIpl will not rebuild page tables.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptTablePrivateDataPtr_PROMPT #language en-US "S3 Boot Script Table Private Data pointer"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptTablePrivateDataPtr_HELP #language en-US "This dynamic PCD hold an address to point to private data structure used in DxeS3BootScriptLib library instance which records the S3 boot script table start address, length, etc. To introduce this PCD is only for DxeS3BootScriptLib instance implementation purpose. The platform developer should make sure the default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptTablePrivateSmmDataPtr_PROMPT #language en-US "S3 Boot Script Table Private Smm Data pointer"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdS3BootScriptTablePrivateSmmDataPtr_HELP #language en-US "This dynamic PCD hold an address to point to private data structure SMM copy used in DxeS3BootScriptLib library instance which records the S3 boot script table start address, length, etc. To introduce this PCD is only for DxeS3BootScriptLib instance implementation purpose. The platform developer should make sure the default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxFmpEsrtCacheNum_PROMPT #language en-US "Max FMP ESRT entry number to be synced & cached in repository"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxFmpEsrtCacheNum_HELP #language en-US "Max FMP ESRT entry number to be synced & cached in repository"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxNonFmpEsrtCacheNum_PROMPT #language en-US " Max Non-FMP ESRT entry number to be cached in repository"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxNonFmpEsrtCacheNum_HELP #language en-US " Max Non-FMP ESRT entry number to be cached in repository"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSystemRebootAfterCapsuleProcessFlag_PROMPT #language en-US "Flag to request system reboot after processing capsule"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSystemRebootAfterCapsuleProcessFlag_HELP #language en-US "Flag to request system reboot after processing capsule"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBootManagerMenuFile_PROMPT #language en-US "Boot Manager Menu File"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdBootManagerMenuFile_HELP #language en-US "This PCD points to the file name GUID of the BootManagerMenuApp\n"
+ "Platform can customize the PCD to point to different application for Boot Manager Menu"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDriverHealthConfigureForm_PROMPT #language en-US "Driver Health Management Form"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDriverHealthConfigureForm_HELP #language en-US "This PCD points to the formset GUID of the driver health management form\n"
+ "The form will be popped up by BDS core when there are Configuration Required driver health intances.\n"
+ "Platform can customize the PCD to point to different formset."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupVideoHorizontalResolution_PROMPT #language en-US "Video Horizontal Resolution of Text Setup"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupVideoHorizontalResolution_HELP #language en-US "Specify the video horizontal resolution of text setup."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupVideoVerticalResolution_PROMPT #language en-US "Video Vertical Resolution of Text Setup"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupVideoVerticalResolution_HELP #language en-US "Specify the video vertical resolution of text setup."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupConOutColumn_PROMPT #language en-US "Console Output Column of Text Setup"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupConOutColumn_HELP #language en-US "Specify the console output column of text setup."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupConOutRow_PROMPT #language en-US "Console Output Row of Text Setup"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetupConOutRow_HELP #language en-US "Specify the console output row of text setup."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFrontPageFormSetGuid_PROMPT #language en-US "Front Page Formset."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFrontPageFormSetGuid_HELP #language en-US "This PCD points to the front page formset GUID\n"
+ "Compare the FormsetGuid or ClassGuid with this PCD value can detect whether in front page"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdShadowPeimOnBoot_HELP #language en-US "Indicates if to shadow PEIM and PeiCore after memory is ready.<BR><BR>\n"
+ "This PCD is used on other boot path except for S3 boot.\n"
+ "TRUE - Shadow PEIM and PeiCore after memory is ready.<BR>\n"
+ "FALSE - Not shadow PEIM after memory is ready.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdShadowPeimOnBoot_PROMPT #language en-US "Shadow Peim on boot"
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseHalfHandshake_PROMPT #language en-US "Enable Serial device Half Hand Shake"
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialUseHalfHandshake_HELP #language en-US "Indicates if Serial device uses half hand shake.<BR><BR>\n"
+ "TRUE - Serial device uses half hand shake.<BR>\n"
+ "FALSE - Serial device doesn't use half hand shake.<BR>"
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciSerialParameters_PROMPT #language en-US "Pci Serial Parameters"
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciSerialParameters_HELP #language en-US "PCI Serial Parameters. It is an array of VendorID, DeviceID, ClockRate, Offset,\n"
+ "BarIndex, RegisterStride, ReceiveFifoDepth, TransmitFifoDepth information that \n"
+ "describes the parameters of special PCI serial devices.\n"
+ "Each array entry is 24-byte in length. The array is terminated\n"
+ "by an array entry with a PCI Vendor ID of 0xFFFF. If a platform only contains a\n"
+ "standard 16550 PCI serial device whose class code is 7/0/2, the value is 0xFFFF.\n"
+ "The C style structure is defined as below:<BR>\n"
+ "typedef struct {<BR>\n"
+ " UINT16 VendorId; ///< Vendor ID to match the PCI device. The value 0xFFFF terminates the list of entries.<BR>\n"
+ " UINT16 DeviceId; ///< Device ID to match the PCI device<BR>\n"
+ " UINT32 ClockRate; ///< UART clock rate. Set to 0 for default clock rate of 1843200 Hz<BR>\n"
+ " UINT64 Offset; ///< The byte offset into to the BAR<BR>\n"
+ " UINT8 BarIndex; ///< Which BAR to get the UART base address<BR>\n"
+ " UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 for default register stride of 1 byte.<BR>\n"
+ " UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.<BR>\n"
+ " UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to 0 for a default FIFO depth of 16 bytes.<BR>\n"
+ " UINT8 Reserved[2];<BR>\n"
+ "} PCI_SERIAL_PARAMETER;<BR>\n"
+ "It contains zero or more instances of the above structure.<BR>\n"
+ "For example, if a PCI device contains two UARTs, PcdPciSerialParameters needs\n"
+ "to contain two instances of the above structure, with the VendorId and DeviceId\n"
+ "equals to the Device ID and Vendor ID of the device; If the PCI device uses the\n"
+ "first two BARs to support two UARTs, BarIndex of first instance equals to 0 and\n"
+ "BarIndex of second one equals to 1; If the PCI device uses the first BAR to\n"
+ "support both UARTs, BarIndex of both instance equals to 0, Offset of first\n"
+ "instance equals to 0 and Offset of second one equals to a value bigger than or\n"
+ "equal to 8.<BR>\n"
+ "For certain UART whose register needs to be accessed in DWORD aligned address,\n"
+ "RegisterStride equals to 4.\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiExposedTableVersions_PROMPT #language en-US "Exposed ACPI table versions."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiExposedTableVersions_HELP #language en-US "Indicates which ACPI versions are targeted by the ACPI tables exposed to the OS\n"
+ "These values are aligned with the definitions in MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h\n"
+ "BIT 1 - EFI_ACPI_TABLE_VERSION_1_0B.<BR>\n"
+ "BIT 2 - EFI_ACPI_TABLE_VERSION_2_0.<BR>\n"
+ "BIT 3 - EFI_ACPI_TABLE_VERSION_3_0.<BR>\n"
+ "BIT 4 - EFI_ACPI_TABLE_VERSION_4_0.<BR>\n"
+ "BIT 5 - EFI_ACPI_TABLE_VERSION_5_0.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHiiOsRuntimeSupport_PROMPT #language en-US "Enable export HII data and configuration to be used in OS runtime."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHiiOsRuntimeSupport_HELP #language en-US "Indicates if HII data and configuration has been exported.<BR><BR>\n"
+ "Add this PCD mainly consider the use case of simulator. This PCD maybe set to FALSE for\n"
+ "simulator platform because the performance cost for this feature.\n"
+ "TRUE - Export HII data and configuration data.<BR>\n"
+ "FALSE - Does not export HII data and configuration.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPs2KbdExtendedVerification_PROMPT #language en-US "Turn on PS2 Keyboard Extended Verification"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPs2KbdExtendedVerification_HELP #language en-US "Indicates if PS2 keyboard does a extended verification during start.\n"
+ "Add this PCD mainly consider the use case of simulator. This PCD maybe set to FALSE for\n"
+ "Extended verification will take some performance. It can be set to FALSE for boot performance.<BR><BR>\n"
+ "TRUE - Turn on PS2 keyboard extended verification.<BR>\n"
+ "FALSE - Turn off PS2 keyboard extended verification.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPs2MouseExtendedVerification_PROMPT #language en-US "Turn on PS2 Mouse Extended Verification"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPs2MouseExtendedVerification_HELP #language en-US "Indicates if PS2 mouse does a extended verification during start.\n"
+ "Extended verification will take some performance. It can be set to FALSE for boot performance.<BR><BR>\n"
+ "TRUE - Turn on PS2 mouse extended verification. <BR>\n"
+ "FALSE - Turn off PS2 mouse extended verification. <BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFastPS2Detection_PROMPT #language en-US "Enable fast PS2 detection"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdFastPS2Detection_HELP #language en-US "Indicates if to use the optimized timing for best PS2 detection performance.\n"
+ "Note this PCD could be set to TRUE for best boot performance and set to FALSE for best device compatibility.<BR><BR>\n"
+ "TRUE - Use the optimized timing for best PS2 detection performance.<BR>\n"
+ "FALSE - Use the normal timing to detect PS2.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSdMmcPciHostControllerMmioBase_PROMPT #language en-US "Mmio base address of pci-based SD/MMC host controller"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSdMmcPciHostControllerMmioBase_HELP #language en-US "This PCD specifies the PCI-based SD/MMC host controller mmio base address. Define the mmio base address of the pci-based SD/MMC host controller. If there are multiple SD/MMC host controllers, their mmio base addresses are calculated one by one from this base address.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxRepairCount_PROMPT #language en-US "MAX repair count"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaxRepairCount_HELP #language en-US "This PCD defines the MAX repair count. The default value is 0 that means infinite.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciDegradeResourceForOptionRom_PROMPT #language en-US "Degrade 64-bit PCI MMIO BARs for legacy BIOS option ROMs"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPciDegradeResourceForOptionRom_HELP #language en-US "Indicates whether 64-bit PCI MMIO BARs should degrade to 32-bit in the presence of an option ROM.<BR>"
+ "On X64 platforms, Option ROMs may contain code that executes in the context of a legacy BIOS (CSM),"
+ "which requires that all PCI MMIO BARs are located below 4 GB.<BR>"
+ "TRUE - All PCI MMIO BARs of a device will be located below 4 GB if it has an option ROM.<BR>"
+ "FALSE - PCI MMIO BARs of a device may be located above 4 GB even if it has an option ROM.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportProcessCapsuleAtRuntime_PROMPT #language en-US "Enable process non-reset capsule image at runtime."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSupportProcessCapsuleAtRuntime_HELP #language en-US "Indicates if the platform can support process non-reset capsule image at runtime.<BR><BR>\n"
+ "TRUE - Supports process non-reset capsule image at runtime.<BR>\n"
+ "FALSE - Does not support process non-reset capsule image at runtime.<BR>"
+
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeSubClassCapsule_PROMPT #language en-US "Status Code for Capsule subclass definitions"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdStatusCodeSubClassCapsule_HELP #language en-US "Status Code for Capsule subclass definitions.<BR><BR>\n"
+ "EFI_OEM_SPECIFIC_SUBCLASS_CAPSULE = 0x00810000<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeProcessCapsulesBegin_PROMPT #language en-US "Status Code for Capsule Process Begin"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeProcessCapsulesBegin_HELP #language en-US "Status Code for Capsule Process Begin.<BR><BR>\n"
+ "EFI_CAPSULE_PROCESS_CAPSULES_BEGIN = (EFI_OEM_SPECIFIC | 0x00000001) = 0x00008001<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeProcessCapsulesEnd_PROMPT #language en-US "Status Code for Capsule Process End"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeProcessCapsulesEnd_HELP #language en-US "Status Code for Capsule Process End.<BR><BR>\n"
+ "EFI_CAPSULE_PROCESS_CAPSULES_END = (EFI_OEM_SPECIFIC | 0x00000002) = 0x00008002<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdatingFirmware_PROMPT #language en-US "Status Code for Capsule Process Updating Firmware"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdatingFirmware_HELP #language en-US "Status Code for Capsule Process Updating Firmware.<BR><BR>\n"
+ "EFI_CAPSULE_UPDATING_FIRMWARE = (EFI_OEM_SPECIFIC | 0x00000003) = 0x00008003<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdateFirmwareSuccess_PROMPT #language en-US "Status Code for Capsule Process Update Firmware Success"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdateFirmwareSuccess_HELP #language en-US "Status Code for Capsule Process Update Firmware Success.<BR><BR>\n"
+ "EFI_CAPSULE_UPDATE_FIRMWARE_SUCCESS = (EFI_OEM_SPECIFIC | 0x00000004) = 0x00008004<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdateFirmwareFailed_PROMPT #language en-US "Status Code for Capsule Process Update Firmware Failed"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeUpdateFirmwareFailed_HELP #language en-US "Status Code for Capsule Process Update Firmware Failed.<BR><BR>\n"
+ "EFI_CAPSULE_UPDATE_FIRMWARE_FAILED = (EFI_OEM_SPECIFIC | 0x00000005) = 0x00008005<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeResettingSystem_PROMPT #language en-US "Status Code for Capsule Resetting System"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleStatusCodeResettingSystem_HELP #language en-US "Status Code for Capsule Resetting System.<BR><BR>\n"
+ "EFI_CAPSULE_RESETTING_SYSTEM = (EFI_OEM_SPECIFIC | 0x00000006) = 0x00008006<BR>\n"
+ "NOTE: The default value of this PCD may collide with other OEM specific status codes.\n"
+ "Override the value of this PCD in the platform DSC file as needed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleMax_PROMPT #language en-US "CapsuleMax value in capsule report variable."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleMax_HELP #language en-US "CapsuleMax value in capsule report variable."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaximumPeiResetNotifies_PROMPT #language en-US "Maximum Number of PEI Reset Filters, Reset Notifications or Reset Handlers."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMaximumPeiResetNotifies_HELP #language en-US "Indicates the allowable maximum number of Reset Filters, <BR>\n"
+ "Reset Notifications or Reset Handlers in PEI phase."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryFileName_PROMPT #language en-US "Recover file name in PEI phase"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdRecoveryFileName_HELP #language en-US "This is recover file name in PEI phase.\n"
+ "The file must be in the root directory.\n"
+ "The file name must be the 8.3 format.\n"
+ "The PCD data must be in UNICODE format."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCoDRelocationFileName_PROMPT #language en-US "Capsule On Disk Temp Relocation file name in PEI phase"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCoDRelocationFileName_HELP #language en-US "This is Capsule Temp Relocation file name in PEI phase.<BR>"
+ "The file must be in the root directory.<BR>"
+ "The file name must be the 8.3 format.<BR>"
+ "The PCD data must be in UNICODE format.<BR>"
+ "CapsuleOnDiskLoadPei PEI module will set value of this PCD to PcdRecoveryFileName, then leverage recovery to get Capsule On Disk Temp Relocation file.<BR>"
+ "Note: The file name must be shorter than PcdRecoveryFileName, otherwise CapsuleOnDiskLoadPei PEI module will fail to get Capsule On Disk Temp Relocation file.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSystemFmpCapsuleImageTypeIdGuid_PROMPT #language en-US "A list of system FMP ImageTypeId GUIDs"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSystemFmpCapsuleImageTypeIdGuid_HELP #language en-US "This PCD hold a list GUIDs for the ImageTypeId to indicate the\n"
+ "FMP capsule is a system FMP."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTestKeyUsed_PROMPT #language en-US "If there is any test key used by the platform."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTestKeyUsed_HELP #language en-US "This dynamic PCD holds the information if there is any test key used by the platform."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmiHandlerProfilePropertyMask_PROMPT #language en-US "SmiHandlerProfile Property."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSmiHandlerProfilePropertyMask_HELP #language en-US "The mask is used to control SmiHandlerProfile behavior.<BR><BR>\n"
+ "BIT0 - Enable SmiHandlerProfile.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdImageProtectionPolicy_PROMPT #language en-US "Set image protection policy."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdImageProtectionPolicy_HELP #language en-US "Set image protection policy. The policy is bitwise.\n"
+ "If a bit is set, the image will be protected by DxeCore if it is aligned.\n"
+ "The code section becomes read-only, and the data section becomes non-executable.\n"
+ "If a bit is clear, nothing will be done to image code/data sections.<BR><BR>\n"
+ "BIT0 - Image from unknown device. <BR>\n"
+ "BIT1 - Image from firmware volume.<BR>"
+ "Note: If a bit is cleared, the data section could be still non-executable if\n"
+ "PcdDxeNxMemoryProtectionPolicy is enabled for EfiLoaderData, EfiBootServicesData\n"
+ "and/or EfiRuntimeServicesData.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeNxMemoryProtectionPolicy_PROMPT #language en-US "Set DXE memory protection policy."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdDxeNxMemoryProtectionPolicy_HELP #language en-US "Set DXE memory protection policy. The policy is bitwise.\n"
+ "If a bit is set, memory regions of the associated type will be mapped\n"
+ "non-executable.<BR>\n"
+ "If a bit is cleared, nothing will be done to associated type of memory.<BR><BR>\n"
+ "\n"
+ "Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>\n"
+ "EfiReservedMemoryType 0x0001<BR>\n"
+ "EfiLoaderCode 0x0002<BR>\n"
+ "EfiLoaderData 0x0004<BR>\n"
+ "EfiBootServicesCode 0x0008<BR>\n"
+ "EfiBootServicesData 0x0010<BR>\n"
+ "EfiRuntimeServicesCode 0x0020<BR>\n"
+ "EfiRuntimeServicesData 0x0040<BR>\n"
+ "EfiConventionalMemory 0x0080<BR>\n"
+ "EfiUnusableMemory 0x0100<BR>\n"
+ "EfiACPIReclaimMemory 0x0200<BR>\n"
+ "EfiACPIMemoryNVS 0x0400<BR>\n"
+ "EfiMemoryMappedIO 0x0800<BR>\n"
+ "EfiMemoryMappedIOPortSpace 0x1000<BR>\n"
+ "EfiPalCode 0x2000<BR>\n"
+ "EfiPersistentMemory 0x4000<BR>\n"
+ "OEM Reserved 0x4000000000000000<BR>\n"
+ "OS Reserved 0x8000000000000000<BR>\n"
+ "\n"
+ "NOTE: User must NOT set NX protection for EfiLoaderCode / EfiBootServicesCode / EfiRuntimeServicesCode. <BR>\n"
+ "User MUST set the same NX protection for EfiBootServicesData and EfiConventionalMemory. <BR>\n"
+ "\n"
+ "e.g. 0x7FD5 can be used for all memory except Code. <BR>\n"
+ "e.g. 0x7BD4 can be used for all memory except Code and ACPINVS/Reserved. <BR>\n"
+ ""
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPteMemoryEncryptionAddressOrMask_PROMPT #language en-US "The address mask when memory encryption is enabled."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdPteMemoryEncryptionAddressOrMask_HELP #language en-US "This PCD holds the address mask for page table entries when memory encryption is\n"
+ "enabled on AMD processors supporting the Secure Encrypted Virtualization (SEV) feature.\n"
+ "This mask should be applied when creating 1:1 virtual to physical mapping tables."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleOnDiskSupport_PROMPT #language en-US "Enable Capsule On Disk support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleOnDiskSupport_HELP #language en-US "Capsule On Disk is to deliver capsules via files on Mass Storage device.<BR><BR>"
+ "This PCD indicates if the Capsule On Disk is supported.<BR>"
+ " TRUE - Capsule On Disk is supported.<BR>"
+ " FALSE - Capsule On Disk is not supported.<BR>"
+ "If platform does not use this feature, this PCD should be set to FALSE.<BR><BR>"
+ "Two sulotions to deliver Capsule On Disk:<BR>"
+ " a) If PcdCapsuleInRamSupport = TRUE, Load Capsule On Disk image out of TCB, and reuse Capsule In Ram to deliver capsule.<BR>"
+ " b) If PcdCapsuleInRamSupport = FALSE, Relocate Capsule On Disk image to RootDir out of TCB, and reuse FatPei to load capsules from external storage.<BR>"
+ "Note:<BR>"
+ "If Both Capsule In Ram and Capsule On Disk are provisioned at the same time, the Capsule On Disk will be bypassed."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleInRamSupport_PROMPT #language en-US "Enable Capsule In Ram support"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCapsuleInRamSupport_HELP #language en-US "Capsule In Ram is to use memory to deliver the capsules that will be processed after system reset.<BR><BR>"
+ "This PCD indicates if the Capsule In Ram is supported.<BR>"
+ " TRUE - Capsule In Ram is supported.<BR>"
+ " FALSE - Capsule In Ram is not supported."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCodRelocationDevPath_PROMPT #language en-US "Capsule On Disk relacation device path."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCodRelocationDevPath_HELP #language en-US "Full device path of plaform specific device to store Capsule On Disk temp relocation file.<BR>"
+ "If this PCD is set, Capsule On Disk temp relocation file will be stored in the device specified by this PCD, instead of the EFI System Partition that stores capsule image file."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdNullPointerDetectionPropertyMask_PROMPT #language en-US "Enable NULL pointer detection"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdNullPointerDetectionPropertyMask_HELP #language en-US "Mask to control the NULL address detection in code for different phases.\n"
+ " If enabled, accessing NULL address in UEFI or SMM code can be caught.\n\n"
+ " BIT0 - Enable NULL pointer detection for UEFI.\n"
+ " BIT1 - Enable NULL pointer detection for SMM.\n"
+ " BIT2..6 - Reserved for future uses.\n"
+ " BIT7 - Disable NULL pointer detection just after EndOfDxe."
+ " This is a workaround for those unsolvable NULL access issues in"
+ " OptionROM, boot loader, etc. It can also help to avoid unnecessary"
+ " exception caused by legacy memory (0-4095) access after EndOfDxe,"
+ " such as Windows 7 boot on Qemu.\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdInitValueInTempStack_PROMPT #language en-US "Init Value in Temp Stack"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdInitValueInTempStack_HELP #language en-US "Init Value in Temp Stack to be shared between SEC and PEI_CORE\n"
+ "SEC fills the full temp stack with this values. When switch stack, PeiCore can check\n"
+ "this value in the temp stack to know how many stack has been used.\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPageType_PROMPT #language en-US "The memory type mask for Page Guard"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPageType_HELP #language en-US "Indicates which type allocation need guard page.\n\n"
+ " If a bit is set, a head guard page and a tail guard page will be added just\n"
+ " before and after corresponding type of pages allocated if there's enough\n"
+ " free pages for all of them. The page allocation for the type related to\n"
+ " cleared bits keeps the same as ususal.\n\n"
+ " This PCD is only valid if BIT0 and/or BIT2 are set in PcdHeapGuardPropertyMask.\n\n"
+ " Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>\n"
+ " EfiReservedMemoryType 0x0000000000000001\n"
+ " EfiLoaderCode 0x0000000000000002\n"
+ " EfiLoaderData 0x0000000000000004\n"
+ " EfiBootServicesCode 0x0000000000000008\n"
+ " EfiBootServicesData 0x0000000000000010\n"
+ " EfiRuntimeServicesCode 0x0000000000000020\n"
+ " EfiRuntimeServicesData 0x0000000000000040\n"
+ " EfiConventionalMemory 0x0000000000000080\n"
+ " EfiUnusableMemory 0x0000000000000100\n"
+ " EfiACPIReclaimMemory 0x0000000000000200\n"
+ " EfiACPIMemoryNVS 0x0000000000000400\n"
+ " EfiMemoryMappedIO 0x0000000000000800\n"
+ " EfiMemoryMappedIOPortSpace 0x0000000000001000\n"
+ " EfiPalCode 0x0000000000002000\n"
+ " EfiPersistentMemory 0x0000000000004000\n"
+ " OEM Reserved 0x4000000000000000\n"
+ " OS Reserved 0x8000000000000000\n"
+ " e.g. LoaderCode+LoaderData+BootServicesCode+BootServicesData are needed, 0x1E should be used.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPoolType_PROMPT #language en-US "The memory type mask for Pool Guard"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPoolType_HELP #language en-US "Indicates which type allocation need guard page.\n\n"
+ " If a bit is set, a head guard page and a tail guard page will be added just\n"
+ " before and after corresponding type of pages which the allocated pool occupies,\n"
+ " if there's enough free memory for all of them. The pool allocation for the\n"
+ " type related to cleared bits keeps the same as ususal.\n\n"
+ " This PCD is only valid if BIT1 and/or BIT3 are set in PcdHeapGuardPropertyMask.\n\n"
+ " Below is bit mask for this PCD: (Order is same as UEFI spec)<BR>\n"
+ " EfiReservedMemoryType 0x0000000000000001\n"
+ " EfiLoaderCode 0x0000000000000002\n"
+ " EfiLoaderData 0x0000000000000004\n"
+ " EfiBootServicesCode 0x0000000000000008\n"
+ " EfiBootServicesData 0x0000000000000010\n"
+ " EfiRuntimeServicesCode 0x0000000000000020\n"
+ " EfiRuntimeServicesData 0x0000000000000040\n"
+ " EfiConventionalMemory 0x0000000000000080\n"
+ " EfiUnusableMemory 0x0000000000000100\n"
+ " EfiACPIReclaimMemory 0x0000000000000200\n"
+ " EfiACPIMemoryNVS 0x0000000000000400\n"
+ " EfiMemoryMappedIO 0x0000000000000800\n"
+ " EfiMemoryMappedIOPortSpace 0x0000000000001000\n"
+ " EfiPalCode 0x0000000000002000\n"
+ " EfiPersistentMemory 0x0000000000004000\n"
+ " OEM Reserved 0x4000000000000000\n"
+ " OS Reserved 0x8000000000000000\n"
+ " e.g. LoaderCode+LoaderData+BootServicesCode+BootServicesData are needed, 0x1E should be used.<BR>"
+
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPropertyMask_PROMPT #language en-US "The Heap Guard feature mask"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdHeapGuardPropertyMask_HELP #language en-US "This mask is to control Heap Guard behavior.\n"
+ " Note:\n"
+ " a) Heap Guard is for debug purpose and should not be enabled in product"
+ " BIOS.\n"
+ " b) Due to the limit of pool memory implementation and the alignment"
+ " requirement of UEFI spec, BIT7 is a try-best setting which cannot"
+ " guarantee that the returned pool is exactly adjacent to head guard"
+ " page or tail guard page.\n"
+ " c) UEFI freed-memory guard and UEFI pool/page guard cannot be enabled"
+ " at the same time.\n"
+ " BIT0 - Enable UEFI page guard.<BR>\n"
+ " BIT1 - Enable UEFI pool guard.<BR>\n"
+ " BIT2 - Enable SMM page guard.<BR>\n"
+ " BIT3 - Enable SMM pool guard.<BR>\n"
+ " BIT4 - Enable UEFI freed-memory guard (Use-After-Free memory detection).<BR>\n"
+ " BIT7 - The direction of Guard Page for Pool Guard.\n"
+ " 0 - The returned pool is near the tail guard page.<BR>\n"
+ " 1 - The returned pool is near the head guard page.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCpuStackGuard_PROMPT #language en-US "Enable UEFI Stack Guard"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdCpuStackGuard_HELP #language en-US "Indicates if UEFI Stack Guard will be enabled.\n"
+ " If enabled, stack overflow in UEFI can be caught, preventing chaotic consequences.<BR><BR>\n"
+ " TRUE - UEFI Stack Guard will be enabled.<BR>\n"
+ " FALSE - UEFI Stack Guard will be disabled.<BR>"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetNvStoreDefaultId_PROMPT #language en-US "NV Storage DefaultId"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSetNvStoreDefaultId_HELP #language en-US "This dynamic PCD enables the default variable setting.\n"
+ " Its value is the default store ID value. The default value is zero as Standard default.\n"
+ " When its value is set in PEI, it will trig the default setting to be applied as the default EFI variable.\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdNvStoreDefaultValueBuffer_PROMPT #language en-US "NV Storage Default Value Buffer"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdNvStoreDefaultValueBuffer_HELP #language en-US "This dynamic PCD holds the DynamicHii PCD value. Its value is the auto generated.\n"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEdkiiFpdtStringRecordEnableOnly_PROMPT #language en-US "String FPDT Record Enable Only"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdEdkiiFpdtStringRecordEnableOnly_HELP #language en-US "Control which FPDT record format will be used to store the performance entry.\n"
+ "On TRUE, the string FPDT record will be used to store every performance entry.\n"
+ "On FALSE, the different FPDT record will be used to store the different performance entries."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVpdBaseAddress64_PROMPT #language en-US "64bit VPD base address"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVpdBaseAddress64_HELP #language en-US "VPD type PCD allows a developer to point to an absolute physical address PcdVpdBaseAddress64"
+ "to store PCD value. It will be DynamicExDefault only."
+ "It is used to set VPD region base address. So, it can't be DynamicExVpd PCD. Its value is"
+ "required to be accessed in PcdDxe driver entry point. So, its value must be set in PEI phase."
+ "It can't depend on EFI variable service, and can't be DynamicExHii PCD."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUse5LevelPageTable_PROMPT #language en-US "Enable 5-Level Paging support in long mode"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdUse5LevelPageTable_HELP #language en-US "Indicates if 5-Level Paging will be enabled in long mode. 5-Level Paging will not be enabled"
+ "when the PCD is TRUE but CPU doesn't support 5-Level Paging."
+ " TRUE - 5-Level Paging will be enabled."
+ " FALSE - 5-Level Paging will not be enabled."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTcgPfpMeasurementRevision_PROMPT #language en-US "TCG Platform Firmware Profile revision"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdTcgPfpMeasurementRevision_HELP #language en-US "Indicates which TCG Platform Firmware Profile revision the EDKII firmware follows."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdGhcbBase_PROMPT #language en-US "Guest-Hypervisor Communication Block (GHCB) Pool Base Address"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdGhcbBase_HELP #language en-US "Used with SEV-ES support to identify an address range that is not to be encrypted."
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdGhcbSize_PROMPT #language en-US "Guest-Hypervisor Communication Block (GHCB) Pool Base Size"
+
+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdGhcbSize_HELP #language en-US "Used with SEV-ES support to identify the size of the address range that is not to be encrypted."
diff --git a/roms/edk2/MdeModulePkg/MdeModulePkgExtra.uni b/roms/edk2/MdeModulePkg/MdeModulePkgExtra.uni
new file mode 100644
index 000000000..b9410a8d2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/MdeModulePkgExtra.uni
@@ -0,0 +1,13 @@
+// /** @file
+// MdeModule Package Localized Strings and Content.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_PACKAGE_NAME
+#language en-US
+"MdeModule package"
+
diff --git a/roms/edk2/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/roms/edk2/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
new file mode 100644
index 000000000..72a119db4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -0,0 +1,32 @@
+## @file
+# MdeModulePkg DSC file used to build host-based unit tests.
+#
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ PLATFORM_NAME = MdeModulePkgHostTest
+ PLATFORM_GUID = F74AF7C6-698C-4EBA-BA49-FF6816916354
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/MdeModulePkg/HostTest
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+
+!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
+
+[Components]
+ MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf
+
+ #
+ # Build MdeModulePkg HOST_APPLICATION Tests
+ #
+ MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf {
+ <LibraryClasses>
+ ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf
+ UefiRuntimeServicesTableLib|MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf
+ }
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c
new file mode 100644
index 000000000..8d376af41
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c
@@ -0,0 +1,257 @@
+/** @file
+ Sample ACPI Platform Driver
+
+ Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/FirmwareVolume2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Acpi.h>
+
+/**
+ Locate the first instance of a protocol. If the protocol requested is an
+ FV protocol, then it will return the first FV that contains the ACPI table
+ storage file.
+
+ @param Instance Return pointer to the first instance of the protocol
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_NOT_FOUND The protocol could not be located.
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
+
+**/
+EFI_STATUS
+LocateFvInstanceWithTables (
+ OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+
+ FvStatus = 0;
+
+ //
+ // Locate protocol.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Defined errors at this time are not found and out of resources.
+ //
+ return Status;
+ }
+
+
+
+ //
+ // Looking for FV with ACPI storage file
+ //
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ //
+ // Get the protocol on this handle
+ // This should not fail because of LocateHandleBuffer
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID**) &FvInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // See if it has the ACPI storage file
+ //
+ Status = FvInstance->ReadFile (
+ FvInstance,
+ (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ //
+ // If we found it, then we are done
+ //
+ if (Status == EFI_SUCCESS) {
+ *Instance = FvInstance;
+ break;
+ }
+ }
+
+ //
+ // Our exit status is determined by the success of the previous operations
+ // If the protocol was found, Instance already points to it.
+ //
+
+ //
+ // Free any allocated buffers
+ //
+ gBS->FreePool (HandleBuffer);
+
+ return Status;
+}
+
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+
+**/
+VOID
+AcpiPlatformChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
+
+ //
+ // Set checksum to 0 first
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
+}
+
+
+/**
+ Entrypoint of Acpi Platform driver.
+
+ @param ImageHandle
+ @param SystemTable
+
+ @return EFI_SUCCESS
+ @return EFI_LOAD_ERROR
+ @return EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+EFIAPI
+AcpiPlatformEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ UINTN TableHandle;
+ UINT32 FvStatus;
+ UINTN TableSize;
+ UINTN Size;
+
+ Instance = 0;
+ CurrentTable = NULL;
+ TableHandle = 0;
+
+ //
+ // Find the AcpiTable protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Locate the firmware volume protocol
+ //
+ Status = LocateFvInstanceWithTables (&FwVol);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read tables from the storage file.
+ //
+ while (Status == EFI_SUCCESS) {
+
+ Status = FwVol->ReadSection (
+ FwVol,
+ (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID**) &CurrentTable,
+ &Size,
+ &FvStatus
+ );
+ if (!EFI_ERROR(Status)) {
+ //
+ // Add the table
+ //
+ TableHandle = 0;
+
+ TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
+ ASSERT (Size >= TableSize);
+
+ //
+ // Checksum ACPI table
+ //
+ AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize);
+
+ //
+ // Install ACPI table
+ //
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ CurrentTable,
+ TableSize,
+ &TableHandle
+ );
+
+ //
+ // Free memory allocated by ReadSection
+ //
+ gBS->FreePool (CurrentTable);
+
+ if (EFI_ERROR(Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Increment the instance
+ //
+ Instance++;
+ CurrentTable = NULL;
+ }
+ }
+
+ //
+ // The driver does not require to be kept loaded.
+ //
+ return EFI_REQUEST_UNLOAD_IMAGE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni
new file mode 100644
index 000000000..4b8d33dbc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Sample ACPI Platform Driver
+//
+// Sample ACPI Platform Driver
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Sample ACPI Platform Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Sample ACPI Platform Driver"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
new file mode 100644
index 000000000..ca29de430
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -0,0 +1,49 @@
+## @file
+# Sample ACPI Platform Driver
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AcpiPlatform
+ MODULE_UNI_FILE = AcpiPlatform.uni
+ FILE_GUID = cb933912-df8f-4305-b1f9-7b44fa11395c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = AcpiPlatformEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ AcpiPlatform.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ PcdLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile ## CONSUMES
+
+[Depex]
+ gEfiAcpiTableProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiPlatformExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni
new file mode 100644
index 000000000..7e7728ef9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// AcpiPlatform Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Platform Sample DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
new file mode 100644
index 000000000..b1cba20c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
@@ -0,0 +1,1053 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = {
+ EFI_ACPI_TABLE_VERSION_NONE,
+ GetAcpiTable2,
+ RegisterNotify,
+ Open,
+ OpenSdt,
+ Close,
+ GetChild,
+ GetOption,
+ SetOption,
+ FindPath
+};
+
+/**
+ This function returns ACPI Table instance.
+
+ @return AcpiTableInstance
+**/
+EFI_ACPI_TABLE_INSTANCE *
+SdtGetAcpiTableInstance (
+ VOID
+ )
+{
+ return mPrivateData;
+}
+
+/**
+ This function finds the table specified by the buffer.
+
+ @param[in] Buffer Table buffer to find.
+
+ @return ACPI table list.
+**/
+EFI_ACPI_TABLE_LIST *
+FindTableByBuffer (
+ IN VOID *Buffer
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ LIST_ENTRY *CurrentLink;
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->TableList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) &&
+ ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) {
+ //
+ // Good! Found Table.
+ //
+ return CurrentTableList;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ This function updates AML table checksum.
+ It will search the ACPI table installed by ACPI_TABLE protocol.
+
+ @param[in] Buffer A piece of AML code buffer pointer.
+
+ @retval EFI_SUCCESS The table holds the AML buffer is found, and checksum is updated.
+ @retval EFI_NOT_FOUND The table holds the AML buffer is not found.
+**/
+EFI_STATUS
+SdtUpdateAmlChecksum (
+ IN VOID *Buffer
+ )
+{
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+
+ CurrentTableList = FindTableByBuffer (Buffer);
+ if (CurrentTableList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ AcpiPlatformChecksum (
+ (VOID *)CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ This function finds MAX AML buffer size.
+ It will search the ACPI table installed by ACPI_TABLE protocol.
+
+ @param[in] Buffer A piece of AML code buffer pointer.
+ @param[out] MaxSize On return it holds the MAX size of buffer.
+
+ @retval EFI_SUCCESS The table holds the AML buffer is found, and MAX size if returned.
+ @retval EFI_NOT_FOUND The table holds the AML buffer is not found.
+**/
+EFI_STATUS
+SdtGetMaxAmlBufferSize (
+ IN VOID *Buffer,
+ OUT UINTN *MaxSize
+ )
+{
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+
+ CurrentTableList = FindTableByBuffer (Buffer);
+ if (CurrentTableList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function invokes ACPI notification.
+
+ @param[in] AcpiTableInstance Instance to AcpiTable
+ @param[in] Version Version(s) to set.
+ @param[in] Handle Handle of the table.
+**/
+VOID
+SdtNotifyAcpiList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ )
+{
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_STATUS Status;
+
+ //
+ // We should not use Table buffer, because it is user input buffer.
+ //
+ Status = FindTableByHandle (
+ Handle,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->NotifyList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
+
+ //
+ // Inovke notification
+ //
+ CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle);
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return ;
+}
+
+/**
+ Returns a requested ACPI table.
+
+ The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated
+ with the Index that was input. The following structures are not considered elements in the list of
+ ACPI tables:
+ - Root System Description Pointer (RSD_PTR)
+ - Root System Description Table (RSDT)
+ - Extended System Description Table (XSDT)
+ Version is updated with a bit map containing all the versions of ACPI of which the table is a
+ member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,
+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.
+
+ @param[in] Index The zero-based index of the table to retrieve.
+ @param[out] Table Pointer for returning the table buffer.
+ @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type
+ EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the
+ EFI_ACPI_SDT_PROTOCOL.
+ @param[out] TableKey On return, points to the table key for the specified ACPI system definition table.
+ This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.
+ The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()
+ to uninstall the table.
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The requested index is too large and a table was not found.
+**/
+EFI_STATUS
+EFIAPI
+GetAcpiTable2 (
+ IN UINTN Index,
+ OUT EFI_ACPI_SDT_HEADER **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *TableKey
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ UINTN TableIndex;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_ACPI_TABLE_LIST *CurrentTable;
+
+ ASSERT (Table != NULL);
+ ASSERT (Version != NULL);
+ ASSERT (TableKey != NULL);
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the table
+ //
+ StartLink = &AcpiTableInstance->TableList;
+ CurrentLink = StartLink->ForwardLink;
+ TableIndex = 0;
+
+ while (CurrentLink != StartLink) {
+ if (TableIndex == Index) {
+ break;
+ }
+ //
+ // Next one
+ //
+ CurrentLink = CurrentLink->ForwardLink;
+ TableIndex ++;
+ }
+
+ if ((TableIndex != Index) || (CurrentLink == StartLink)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get handle and version
+ //
+ CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ *TableKey = CurrentTable->Handle;
+ *Version = CurrentTable->Version;
+ *Table = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register a callback when an ACPI table is installed.
+
+ This function registers a function which will be called whenever a new ACPI table is installed.
+
+ @param[in] Notification Points to the callback function to be registered
+**/
+VOID
+SdtRegisterNotify (
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Create a new list entry
+ //
+ CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST));
+ ASSERT (CurrentNotifyList != NULL);
+
+ //
+ // Initialize the table contents
+ //
+ CurrentNotifyList->Signature = EFI_ACPI_NOTIFY_LIST_SIGNATURE;
+ CurrentNotifyList->Notification = Notification;
+
+ //
+ // Add the table to the current list of tables
+ //
+ InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link);
+
+ return ;
+}
+
+/**
+ Unregister a callback when an ACPI table is installed.
+
+ This function unregisters a function which will be called whenever a new ACPI table is installed.
+
+ @param[in] Notification Points to the callback function to be unregistered.
+
+ @retval EFI_SUCCESS Callback successfully unregistered.
+ @retval EFI_INVALID_PARAMETER Notification does not match a known registration function.
+**/
+EFI_STATUS
+SdtUnregisterNotify (
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->NotifyList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
+ if (CurrentNotifyList->Notification == Notification) {
+ //
+ // Good! Found notification.
+ //
+ // Remove it from list and free the node.
+ //
+ RemoveEntryList (&(CurrentNotifyList->Link));
+ FreePool (CurrentNotifyList);
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Not found!
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Register or unregister a callback when an ACPI table is installed.
+
+ This function registers or unregisters a function which will be called whenever a new ACPI table is
+ installed.
+
+ @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified
+ function will be unregistered.
+ @param[in] Notification Points to the callback function to be registered or unregistered.
+
+ @retval EFI_SUCCESS Callback successfully registered or unregistered.
+ @retval EFI_INVALID_PARAMETER Notification is NULL
+ @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterNotify (
+ IN BOOLEAN Register,
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ //
+ // Check for invalid input parameters
+ //
+ if (Notification == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Register) {
+ //
+ // Register a new notify
+ //
+ SdtRegisterNotify (Notification);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Unregister an old notify
+ //
+ return SdtUnregisterNotify (Notification);
+ }
+}
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+SdtOpenSdtTable (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_AML_HANDLE *AmlHandle;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the table
+ //
+ Status = FindTableByHandle (
+ TableKey,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ AmlHandle = AllocatePool (sizeof(*AmlHandle));
+ ASSERT (AmlHandle != NULL);
+ AmlHandle->Signature = EFI_AML_ROOT_HANDLE_SIGNATURE;
+ AmlHandle->Buffer = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER));
+ AmlHandle->Size = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER);
+ AmlHandle->AmlByteEncoding = NULL;
+ AmlHandle->Modified = FALSE;
+
+ //
+ // return the ACPI handle
+ //
+ *Handle = (EFI_ACPI_HANDLE)AmlHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+EFIAPI
+OpenSdt (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SdtOpenSdtTable (TableKey, Handle);
+}
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[in] BufferSize Max buffer size.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+SdtOpenEx (
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_AML_HANDLE *AmlHandle;
+
+ AmlByteEncoding = AmlSearchByOpByte (Buffer);
+ if (AmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Do not open NameString as handle
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Good, find it
+ //
+ AmlHandle = AllocatePool (sizeof(*AmlHandle));
+ ASSERT (AmlHandle != NULL);
+
+ AmlHandle->Signature = EFI_AML_HANDLE_SIGNATURE;
+ AmlHandle->Buffer = Buffer;
+ AmlHandle->AmlByteEncoding = AmlByteEncoding;
+ AmlHandle->Modified = FALSE;
+
+ AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize);
+ if (AmlHandle->Size == 0) {
+ FreePool (AmlHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Handle = (EFI_ACPI_HANDLE)AmlHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+EFIAPI
+Open (
+ IN VOID *Buffer,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxSize;
+
+ MaxSize = 0;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Buffer == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SdtOpenEx (Buffer, MaxSize, Handle);
+}
+
+/**
+ Close an ACPI handle.
+
+ @param[in] Handle Returns the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_ACPI_HANDLE Handle
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) &&
+ (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update Checksum only if modified
+ //
+ if (AmlHandle->Modified) {
+ Status = SdtUpdateAmlChecksum (AmlHandle->Buffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ FreePool (AmlHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT CONST VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_STATUS Status;
+
+ ASSERT (DataType != NULL);
+ ASSERT (Data != NULL);
+ ASSERT (DataSize != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ //
+ // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
+ //
+ if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+ if (Index > AmlByteEncoding->MaxIndex) {
+ *DataType = EFI_ACPI_DATA_TYPE_NONE;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse option
+ //
+ Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Change information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[in] Data Points to the data.
+ @param[in] DataSize The size of the Data.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+ @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by
+ the option.
+
+**/
+EFI_STATUS
+EFIAPI
+SetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_STATUS Status;
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *OrgData;
+ UINTN OrgDataSize;
+
+ ASSERT (Data != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ //
+ // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
+ //
+ if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+
+ if (Index > AmlByteEncoding->MaxIndex) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Parse option
+ //
+ Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataType == EFI_ACPI_DATA_TYPE_NONE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize > OrgDataSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // Update
+ //
+ CopyMem (OrgData, Data, DataSize);
+ AmlHandle->Modified = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child ACPI objects.
+
+ @param[in] ParentHandle Parent handle.
+ @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first
+ handle. On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetChild (
+ IN EFI_ACPI_HANDLE ParentHandle,
+ IN OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_AML_HANDLE *AmlParentHandle;
+ EFI_AML_HANDLE *AmlHandle;
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ ASSERT (Handle != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (ParentHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = *Handle;
+ if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle;
+ if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
+ //
+ // Root handle
+ //
+ Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer);
+ } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
+ //
+ // Non-root handle
+ //
+ Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer);
+ } else {
+ //
+ // Invalid
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Buffer == NULL) {
+ *Handle = NULL;
+ return EFI_SUCCESS;
+ }
+ return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle);
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the AML path.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+SdtFindPathFromNonRoot (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN UINT8 *AmlPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Buffer = NULL;
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // For non-root handle, we need search from THIS node instead of ROOT.
+ //
+ Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Buffer == NULL) {
+ *HandleOut = NULL;
+ return EFI_SUCCESS;
+ }
+ return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
+}
+
+/**
+ Duplicate AML handle.
+
+ @param[in] AmlHandle Handle to be duplicated.
+
+ @return Duplicated AML handle.
+**/
+EFI_AML_HANDLE *
+SdtDuplicateHandle (
+ IN EFI_AML_HANDLE *AmlHandle
+ )
+{
+ EFI_AML_HANDLE *DstAmlHandle;
+
+ DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle));
+ ASSERT (DstAmlHandle != NULL);
+ CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle));
+
+ return DstAmlHandle;
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the AML path.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+SdtFindPathFromRoot (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN UINT8 *AmlPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_ACPI_HANDLE ChildHandle;
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+ VOID *Buffer;
+
+ Buffer = NULL;
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // Handle case that AcpiPath is Root
+ //
+ if (AmlIsRootPath (AmlPath)) {
+ //
+ // Duplicate RootHandle
+ //
+ *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Let children find it.
+ //
+ ChildHandle = NULL;
+ while (TRUE) {
+ Status = GetChild (HandleIn, &ChildHandle);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChildHandle == NULL) {
+ //
+ // Not found
+ //
+ *HandleOut = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // More child
+ //
+ AmlHandle = (EFI_AML_HANDLE *)ChildHandle;
+ Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer != NULL) {
+ //
+ // Great! Find it, open
+ //
+ Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Not success, try next one
+ //
+ }
+ }
+
+ //
+ // Should not run here
+ //
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+FindPath (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN VOID *AcpiPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+ UINT8 *AmlPath;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (HandleIn == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // Convert ASL path to AML path
+ //
+ AmlPath = AmlNameFromAslName (AcpiPath);
+ if (AmlPath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - "));
+ AmlPrintNameString (AmlPath);
+ DEBUG ((EFI_D_ERROR, "\n"));
+ DEBUG_CODE_END ();
+
+ if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
+ //
+ // Root Handle
+ //
+ Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut);
+ } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
+ //
+ // Non-Root handle
+ //
+ Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut);
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (AmlPath);
+
+ return Status;
+}
+
+/**
+ This function initializes AcpiSdt protocol in ACPI table instance.
+
+ @param[in] AcpiTableInstance Instance to construct
+**/
+VOID
+SdtAcpiTableAcpiSdtConstructor (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+
+ InitializeListHead (&AcpiTableInstance->NotifyList);
+ CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));
+ AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions);
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h
new file mode 100644
index 000000000..50d4c96ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h
@@ -0,0 +1,580 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ACPI_SDT_H_
+#define _ACPI_SDT_H_
+
+//
+// Privacy data structure
+//
+
+//
+// ACPI Notify Linked List Signature.
+//
+#define EFI_ACPI_NOTIFY_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'N', 'L')
+
+//
+// ACPI Notify List Entry definition.
+//
+// Signature must be set to EFI_ACPI_NOTIFY_LIST_SIGNATURE
+// Link is the linked list data.
+// Notification is the callback function.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_ACPI_NOTIFICATION_FN Notification;
+} EFI_ACPI_NOTIFY_LIST;
+
+//
+// Containment record for ACPI Notify linked list.
+//
+#define EFI_ACPI_NOTIFY_LIST_FROM_LINK(_link) CR (_link, EFI_ACPI_NOTIFY_LIST, Link, EFI_ACPI_NOTIFY_LIST_SIGNATURE)
+
+typedef struct _AML_BYTE_ENCODING AML_BYTE_ENCODING;
+typedef struct _EFI_AML_NODE_LIST EFI_AML_NODE_LIST;
+
+//
+// AML Node Linked List Signature.
+//
+#define EFI_AML_NODE_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'M', 'L')
+
+//
+// AML Node Linked List Entry definition.
+//
+// Signature must be set to EFI_AML_NODE_LIST_SIGNATURE
+// Link is the linked list data.
+// Name is the ACPI node name.
+// This is listed for PATH finding.
+// Buffer is the ACPI node buffer pointer, the first/second bytes are opcode.
+// This buffer should not be freed.
+// Size is the total size of this ACPI node buffer.
+// Children is the children linked list of this node.
+//
+#define AML_NAME_SEG_SIZE 4
+
+struct _EFI_AML_NODE_LIST {
+ UINT32 Signature;
+ UINT8 Name[AML_NAME_SEG_SIZE];
+ UINT8 *Buffer;
+ UINTN Size;
+ LIST_ENTRY Link;
+ LIST_ENTRY Children;
+ EFI_AML_NODE_LIST *Parent;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+};
+
+//
+// Containment record for AML Node linked list.
+//
+#define EFI_AML_NODE_LIST_FROM_LINK(_link) CR (_link, EFI_AML_NODE_LIST, Link, EFI_AML_NODE_LIST_SIGNATURE)
+
+//
+// AML Handle Signature.
+//
+#define EFI_AML_HANDLE_SIGNATURE SIGNATURE_32 ('E', 'A', 'H', 'S')
+#define EFI_AML_ROOT_HANDLE_SIGNATURE SIGNATURE_32 ('E', 'A', 'R', 'H')
+
+//
+// AML Handle Entry definition.
+//
+// Signature must be set to EFI_AML_HANDLE_SIGNATURE or EFI_AML_ROOT_HANDLE_SIGNATURE
+// Buffer is the ACPI node buffer pointer, the first/second bytes are opcode.
+// This buffer should not be freed.
+// Size is the total size of this ACPI node buffer.
+//
+typedef struct {
+ UINT32 Signature;
+ UINT8 *Buffer;
+ UINTN Size;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ BOOLEAN Modified;
+} EFI_AML_HANDLE;
+
+typedef UINT32 AML_OP_PARSE_INDEX;
+
+#define AML_OP_PARSE_INDEX_GET_OPCODE 0
+#define AML_OP_PARSE_INDEX_GET_TERM1 1
+#define AML_OP_PARSE_INDEX_GET_TERM2 2
+#define AML_OP_PARSE_INDEX_GET_TERM3 3
+#define AML_OP_PARSE_INDEX_GET_TERM4 4
+#define AML_OP_PARSE_INDEX_GET_TERM5 5
+#define AML_OP_PARSE_INDEX_GET_TERM6 6
+#define AML_OP_PARSE_INDEX_GET_SIZE (AML_OP_PARSE_INDEX)-1
+
+typedef UINT32 AML_OP_PARSE_FORMAT;
+#define AML_NONE 0
+#define AML_OPCODE 1
+#define AML_UINT8 2
+#define AML_UINT16 3
+#define AML_UINT32 4
+#define AML_UINT64 5
+#define AML_NAME 6
+#define AML_STRING 7
+#define AML_OBJECT 8
+
+typedef UINT32 AML_OP_ATTRIBUTE;
+#define AML_HAS_PKG_LENGTH 0x1 // It is ACPI attribute - if OpCode has PkgLength
+#define AML_IS_NAME_CHAR 0x2 // It is ACPI attribute - if this is NameChar
+#define AML_HAS_CHILD_OBJ 0x4 // it is ACPI attribute - if OpCode has Child Object.
+#define AML_IN_NAMESPACE 0x10000 // It is UEFI SDT attribute - if OpCode will be in NameSpace
+ // NOTE; Not all OBJECT will be in NameSpace
+ // For example, BankField | CreateBitField | CreateByteField | CreateDWordField |
+ // CreateField | CreateQWordField | CreateWordField | Field | IndexField.
+
+struct _AML_BYTE_ENCODING {
+ UINT8 OpCode;
+ UINT8 SubOpCode;
+ AML_OP_PARSE_INDEX MaxIndex;
+ AML_OP_PARSE_FORMAT Format[6];
+ AML_OP_ATTRIBUTE Attribute;
+};
+
+//
+// AcpiSdt protocol declaration
+//
+
+/**
+ Returns a requested ACPI table.
+
+ The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated
+ with the Index that was input. The following structures are not considered elements in the list of
+ ACPI tables:
+ - Root System Description Pointer (RSD_PTR)
+ - Root System Description Table (RSDT)
+ - Extended System Description Table (XSDT)
+ Version is updated with a bit map containing all the versions of ACPI of which the table is a
+ member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,
+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.
+
+ @param[in] Index The zero-based index of the table to retrieve.
+ @param[out] Table Pointer for returning the table buffer.
+ @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type
+ EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the
+ EFI_ACPI_SDT_PROTOCOL.
+ @param[out] TableKey On return, points to the table key for the specified ACPI system definition table.
+ This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.
+ The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()
+ to uninstall the table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The requested index is too large and a table was not found.
+**/
+EFI_STATUS
+EFIAPI
+GetAcpiTable2 (
+ IN UINTN Index,
+ OUT EFI_ACPI_SDT_HEADER **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *TableKey
+ );
+
+/**
+ Register or unregister a callback when an ACPI table is installed.
+
+ This function registers or unregisters a function which will be called whenever a new ACPI table is
+ installed.
+
+ @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified
+ function will be unregistered.
+ @param[in] Notification Points to the callback function to be registered or unregistered.
+
+ @retval EFI_SUCCESS Callback successfully registered or unregistered.
+ @retval EFI_INVALID_PARAMETER Notification is NULL
+ @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterNotify (
+ IN BOOLEAN Register,
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ );
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+EFIAPI
+OpenSdt (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+EFIAPI
+Open (
+ IN VOID *Buffer,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Close an ACPI handle.
+
+ @param[in] Handle Returns the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_ACPI_HANDLE Handle
+ );
+
+/**
+ Retrieve information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT CONST VOID **Data,
+ OUT UINTN *DataSize
+ );
+
+/**
+ Change information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[in] Data Points to the data.
+ @param[in] DataSize The size of the Data.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+ @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by
+ the option.
+
+**/
+EFI_STATUS
+EFIAPI
+SetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ );
+
+/**
+ Return the child ACPI objects.
+
+ @param[in] ParentHandle Parent handle.
+ @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first
+ handle. On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetChild (
+ IN EFI_ACPI_HANDLE ParentHandle,
+ IN OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+FindPath (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN VOID *AcpiPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ );
+
+//
+// ACPI SDT function
+//
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[in] BufferSize Max buffer size.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+SdtOpenEx (
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+//
+// AML support function
+//
+
+/**
+ Get AML NameString size.
+
+ @param[in] Buffer AML NameString.
+ @param[out] BufferSize AML NameString size
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
+**/
+EFI_STATUS
+AmlGetNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *BufferSize
+ );
+
+/**
+ This function retuns package length from the buffer.
+
+ @param[in] Buffer AML buffer
+ @param[out] PkgLength The total length of package.
+
+ @return The byte data count to present the package length.
+**/
+UINTN
+AmlGetPkgLength (
+ IN UINT8 *Buffer,
+ OUT UINTN *PkgLength
+ );
+
+/**
+ This function returns AcpiDataType according to AmlType.
+
+ @param[in] AmlType AML Type.
+
+ @return AcpiDataType
+**/
+EFI_ACPI_DATA_TYPE
+AmlTypeToAcpiType (
+ IN AML_OP_PARSE_FORMAT AmlType
+ );
+
+/**
+ This function returns AmlByteEncoding according to OpCode Byte.
+
+ @param[in] OpByteBuffer OpCode byte buffer.
+
+ @return AmlByteEncoding
+**/
+AML_BYTE_ENCODING *
+AmlSearchByOpByte (
+ IN UINT8 *OpByteBuffer
+ );
+
+/**
+ Return object size.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML object buffer.
+ @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
+
+ @return Size of the object.
+**/
+UINTN
+AmlGetObjectSize (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize
+ );
+
+/**
+ Return object name.
+
+ @param[in] AmlHandle AML handle.
+
+ @return Name of the object.
+**/
+CHAR8 *
+AmlGetObjectName (
+ IN EFI_AML_HANDLE *AmlHandle
+ );
+
+/**
+ Retrieve information according to AmlHandle
+
+ @param[in] AmlHandle AML handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionHandleCommon (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ );
+
+/**
+ Return offset of last option.
+
+ @param[in] AmlHandle AML Handle.
+ @param[out] Buffer Upon return, points to the offset after last option.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetOffsetAfterLastOption (
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT UINT8 **Buffer
+ );
+
+/**
+ Return the child ACPI objects from Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ );
+
+/**
+ Return the child ACPI objects from Non-Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Non-Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromNonRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ );
+
+/**
+ Return AML name according to ASL name.
+ The caller need free the AmlName returned.
+
+ @param[in] AslPath ASL name.
+
+ @return AmlName
+**/
+UINT8 *
+AmlNameFromAslName (
+ IN UINT8 *AslPath
+ );
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI AML path
+
+ @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the ACPI AML path.
+ @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+ @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
+ FALSE means to find AML path from this Node (The HandleIn).
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlFindPath (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN UINT8 *AmlPath,
+ OUT VOID **Buffer,
+ IN BOOLEAN FromRoot
+ );
+
+/**
+ Print AML NameString.
+
+ @param[in] Buffer AML NameString.
+**/
+VOID
+AmlPrintNameString (
+ IN UINT8 *Buffer
+ );
+
+/**
+ Print AML NameSeg.
+
+ @param[in] Buffer AML NameSeg.
+**/
+VOID
+AmlPrintNameSeg (
+ IN UINT8 *Buffer
+ );
+
+/**
+ Check if it is AML Root name
+
+ @param[in] Buffer AML path.
+
+ @retval TRUE AML path is root.
+ @retval FALSE AML path is not root.
+**/
+BOOLEAN
+AmlIsRootPath (
+ IN UINT8 *Buffer
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c
new file mode 100644
index 000000000..1d91737cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c
@@ -0,0 +1,84 @@
+/** @file
+ ACPI Table Protocol Driver
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+
+//
+// Handle to install ACPI Table Protocol
+//
+EFI_HANDLE mHandle = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_TABLE_INSTANCE *mPrivateData = NULL;
+
+/**
+ Entry point of the ACPI table driver.
+ Creates and initializes an instance of the ACPI Table
+ 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.
+
+ @return EFI_SUCCESS Driver initialized successfully.
+ @return EFI_LOAD_ERROR Failed to Initialize or has been loaded.
+ @return EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeAcpiTableDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_INSTANCE *PrivateData;
+
+ //
+ // Initialize our protocol
+ //
+ PrivateData = AllocateZeroPool (sizeof (EFI_ACPI_TABLE_INSTANCE));
+ ASSERT (PrivateData);
+ PrivateData->Signature = EFI_ACPI_TABLE_SIGNATURE;
+
+ //
+ // Call all constructors per produced protocols
+ //
+ Status = AcpiTableAcpiTableConstructor (PrivateData);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrivateData);
+ return EFI_LOAD_ERROR;
+ }
+
+ //
+ // Install ACPI Table protocol
+ //
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ mPrivateData = PrivateData;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ &gEfiAcpiSdtProtocolGuid,
+ &mPrivateData->AcpiSdtProtocol,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ NULL
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
new file mode 100644
index 000000000..425a462fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
@@ -0,0 +1,234 @@
+/** @file
+ ACPI Table Protocol Driver
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ACPI_TABLE_H_
+#define _ACPI_TABLE_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Guid/Acpi.h>
+#include <Protocol/AcpiSystemDescriptionTable.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>
+
+#include "AcpiSdt.h"
+
+//
+// Great than or equal to 2.0.
+//
+#define ACPI_TABLE_VERSION_GTE_2_0 (EFI_ACPI_TABLE_VERSION_2_0 | \
+ EFI_ACPI_TABLE_VERSION_3_0 | \
+ EFI_ACPI_TABLE_VERSION_4_0 | \
+ EFI_ACPI_TABLE_VERSION_5_0)
+
+//
+// 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 ACPI Table 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_TABLE_SIGNATURE SIGNATURE_32 ('S', 'T', '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;
+ EFI_ACPI_TABLE_PROTOCOL AcpiTableProtocol;
+ EFI_ACPI_SDT_PROTOCOL AcpiSdtProtocol;
+ LIST_ENTRY NotifyList;
+} EFI_ACPI_TABLE_INSTANCE;
+
+//
+// ACPI table protocol instance containing record macro
+//
+#define EFI_ACPI_TABLE_INSTANCE_FROM_THIS(a) \
+ CR (a, \
+ EFI_ACPI_TABLE_INSTANCE, \
+ AcpiTableProtocol, \
+ EFI_ACPI_TABLE_SIGNATURE \
+ )
+
+//
+// Protocol Constructor functions
+//
+
+/**
+ Constructor for the ACPI support protocol. Initializes instance
+ data.
+
+ @param AcpiTableInstance Instance to construct
+
+ @return EFI_SUCCESS Instance initialized.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+AcpiTableAcpiTableConstructor (
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+
+/**
+ Entry point of the ACPI table driver.
+ Creates and initializes an instance of the ACPI Table
+ 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
+
+ @return EFI_SUCCESS Driver initialized successfully
+ @return EFI_LOAD_ERROR Failed to Initialize or has been loaded
+ @return EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeAcpiTableDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ 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[in] Handle Table to find.
+ @param[in] TableList Table list to search
+ @param[out] Table Pointer to table found.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval 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
+ );
+
+/**
+
+ This function calculates and updates an UINT8 checksum.
+
+ @param[in] Buffer Pointer to buffer to checksum
+ @param[in] Size Number of bytes to checksum
+ @param[in] ChecksumOffset Offset to place the checksum result in
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ );
+
+/**
+ This function invokes ACPI notification.
+
+ @param[in] AcpiTableInstance Instance to AcpiTable
+ @param[in] Version Version(s) to set.
+ @param[in] Handle Handle of the table.
+**/
+VOID
+SdtNotifyAcpiList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ );
+
+/**
+ This function initializes AcpiSdt protocol in ACPI table instance.
+
+ @param[in] AcpiTableInstance Instance to construct
+**/
+VOID
+SdtAcpiTableAcpiSdtConstructor (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+//
+// export PrivateData symbol, because we need that in AcpiSdtProtol implementation
+//
+extern EFI_HANDLE mHandle;
+extern EFI_ACPI_TABLE_INSTANCE *mPrivateData;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
new file mode 100644
index 000000000..d341df439
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@@ -0,0 +1,78 @@
+## @file
+# ACPI Table Protocol Driver
+#
+# This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces UEFI/PI
+# services to install/uninstall/manage ACPI tables.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AcpiTableDxe
+ MODULE_UNI_FILE = AcpiTableDxe.uni
+ FILE_GUID = 9622E42C-8E38-4a08-9E8F-54F784652F6B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeAcpiTableDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ AcpiTableProtocol.c
+ AcpiTable.h
+ AcpiTable.c
+ AcpiSdt.h
+ AcpiSdt.c
+ Aml.c
+ AmlString.c
+ AmlOption.c
+ AmlChild.c
+ AmlNamespace.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ BaseLib
+ PcdLib
+
+[Guids]
+ gEfiAcpi10TableGuid ## PRODUCES ## SystemTable
+ gEfiAcpiTableGuid ## PRODUCES ## SystemTable
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions ## CONSUMES
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## PRODUCES
+ gEfiAcpiSdtProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiTableDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni
new file mode 100644
index 000000000..7afe9bd4d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// AcpiTableDxe Module Localized Abstract and Description Content
+//
+// Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ACPI Table Protocol Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces UEFI/PI services to install/uninstall/manage ACPI tables."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni
new file mode 100644
index 000000000..b64bc2b25
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// AcpiTableDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Table DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
new file mode 100644
index 000000000..ad7baf820
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
@@ -0,0 +1,1850 @@
+/** @file
+ ACPI Table Protocol Implementation
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+//
+// The maximum number of tables that pre-allocated.
+//
+UINTN mEfiAcpiMaxNumTables = EFI_ACPI_MAX_NUM_TABLES;
+
+//
+// Allocation strategy to use for AllocatePages ().
+// Runtime value depends on PcdExposedAcpiTableVersions.
+//
+STATIC EFI_ALLOCATE_TYPE mAcpiTableAllocType;
+
+/**
+ 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 AcpiTableInstance 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_TABLE_INSTANCE *AcpiTableInstance,
+ 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 AcpiTableInstance 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_TABLE_INSTANCE *AcpiTableInstance,
+ 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 AcpiTableInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+//
+// Protocol function implementations.
+//
+
+/**
+ 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 AcpiTableInstance Instance 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_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 Buffer64;
+
+ //
+ // 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 *) AcpiTableInstance->Rsdt1 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiTableInstance->Fadt1;
+
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) AcpiTableInstance->Rsdt3 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiTableInstance->Fadt3;
+ }
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ CurrentXsdtEntry = (VOID *) ((UINT8 *) AcpiTableInstance->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) AcpiTableInstance->Fadt3;
+ CopyMem (
+ CurrentXsdtEntry,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ }
+
+ //
+ // Do checksum again because Dsdt/Xsdt is updated.
+ //
+ ChecksumCommonTables (AcpiTableInstance);
+
+ //
+ // 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) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpi10TableGuid, AcpiTableInstance->Rsdp1);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpiTableGuid, AcpiTableInstance->Rsdp3);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ 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_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ VOID *AcpiTableBufferConst;
+ EFI_ACPI_TABLE_VERSION Version;
+
+ //
+ // Check for invalid input parameters
+ //
+ if ((AcpiTableBuffer == NULL) || (TableKey == NULL)
+ || (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer)->Length != AcpiTableBufferSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Version = PcdGet32 (PcdAcpiExposedTableVersions);
+
+ //
+ // Get the instance of the ACPI table protocol
+ //
+ AcpiTableInstance = EFI_ACPI_TABLE_INSTANCE_FROM_THIS (This);
+
+ //
+ // Install the ACPI table
+ //
+ AcpiTableBufferConst = AllocateCopyPool (AcpiTableBufferSize,AcpiTableBuffer);
+ *TableKey = 0;
+ Status = AddTableToList (
+ AcpiTableInstance,
+ AcpiTableBufferConst,
+ TRUE,
+ Version,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PublishTables (
+ AcpiTableInstance,
+ Version
+ );
+ }
+ FreePool (AcpiTableBufferConst);
+
+ //
+ // Add a new table successfully, notify registed callback
+ //
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ if (!EFI_ERROR (Status)) {
+ SdtNotifyAcpiList (
+ AcpiTableInstance,
+ Version,
+ *TableKey
+ );
+ }
+ }
+
+ 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_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_VERSION Version;
+
+ //
+ // Get the instance of the ACPI table protocol
+ //
+ AcpiTableInstance = EFI_ACPI_TABLE_INSTANCE_FROM_THIS (This);
+
+ Version = PcdGet32 (PcdAcpiExposedTableVersions);
+
+ //
+ // Uninstall the ACPI table
+ //
+ Status = RemoveTableFromList (
+ AcpiTableInstance,
+ Version,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PublishTables (
+ AcpiTableInstance,
+ Version
+ );
+ }
+
+ 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 AcpiTableInstance ACPI table 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_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ UINTN NewMaxTableNumber;
+ UINTN TotalSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ EFI_ACPI_TABLE_INSTANCE TempPrivateData;
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+
+ CopyMem (&TempPrivateData, AcpiTableInstance, sizeof (EFI_ACPI_TABLE_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 2.0/3.0 XSDT
+ NewMaxTableNumber * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ 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);
+ }
+
+ //
+ // 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 (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiTableInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ AcpiTableInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ }
+ AcpiTableInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Update RSDP to point to the new Rsdt and Xsdt address.
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt1;
+ AcpiTableInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt3;
+ }
+ CurrentData = (UINT64) (UINTN) AcpiTableInstance->Xsdt;
+ CopyMem (&AcpiTableInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+
+ //
+ // copy the original Rsdt1, Rsdt3 and Xsdt structure to new buffer
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CopyMem (AcpiTableInstance->Rsdt1, TempPrivateData.Rsdt1, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ CopyMem (AcpiTableInstance->Rsdt3, TempPrivateData.Rsdt3, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ }
+ CopyMem (AcpiTableInstance->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 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ 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);
+ }
+
+ 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 AcpiTableInstance 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_TABLE_INSTANCE *AcpiTableInstance,
+ 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 (AcpiTableInstance);
+ 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 (
+ mAcpiTableAllocType,
+ 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 = AcpiTableInstance->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 && AcpiTableInstance->Fadt1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->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
+ //
+ AcpiTableInstance->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.
+ //
+ AcpiTableInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs1;
+ AcpiTableInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt1;
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdp1->OemId,
+ &AcpiTableInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ //
+ // RSDT OEM information is updated to match the FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdt1->OemId,
+ &AcpiTableInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ CopyMem (
+ &AcpiTableInstance->Rsdt1->OemTableId,
+ &AcpiTableInstance->Fadt1->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Rsdt1->OemRevision = AcpiTableInstance->Fadt1->Header.OemRevision;
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->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)AcpiTableInstance->Facs3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs3;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+ } else {
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Facs3;
+ CopyMem (
+ &AcpiTableInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ }
+ if ((UINT64)(UINTN)AcpiTableInstance->Dsdt3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt3;
+ //
+ // Comment block "the caller installs the tables in "DSDT, FADT" order"
+ // The below comments are also in "the caller installs the tables in "FADT, DSDT" order" comment block.
+ //
+ // The ACPI specification, up to and including revision 5.1 Errata A,
+ // allows the DSDT and X_DSDT fields to be both set in the FADT.
+ // (Obviously, this only makes sense if the DSDT address is representable in 4 bytes.)
+ // Starting with 5.1 Errata B, specifically for Mantis 1393 <https://mantis.uefi.org/mantis/view.php?id=1393>,
+ // the spec requires at most one of DSDT and X_DSDT fields to be set to a nonzero value,
+ // but strangely an exception is 6.0 that has no this requirement.
+ //
+ // Here we do not make the DSDT and X_DSDT fields mutual exclusion conditionally
+ // by checking FADT revision, but always set both DSDT and X_DSDT fields in the FADT
+ // to have better compatibility as some OS may have assumption to only consume X_DSDT
+ // field even the DSDT address is < 4G.
+ //
+ Buffer64 = AcpiTableInstance->Fadt3->Dsdt;
+ } else {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Dsdt3;
+ }
+ CopyMem (&AcpiTableInstance->Fadt3->XDsdt, &Buffer64, sizeof (UINT64));
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdp3->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // RSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdt3->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiTableInstance->Rsdt3->OemTableId,
+ &AcpiTableInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Rsdt3->OemRevision = AcpiTableInstance->Fadt3->Header.OemRevision;
+ }
+
+ //
+ // XSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Xsdt->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiTableInstance->Xsdt->OemTableId,
+ &AcpiTableInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Xsdt->OemRevision = AcpiTableInstance->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 && AcpiTableInstance->Facs1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->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
+ //
+ AcpiTableInstance->Facs1 = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Facs3 = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ //
+ // Note: If the FIRMWARE_CTRL is non-zero, then X_FIRMWARE_CTRL must be zero, and
+ // vice-versa.
+ //
+ if ((UINT64)(UINTN)AcpiTableInstance->Facs3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs3;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+ } else {
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Facs3;
+ CopyMem (
+ &AcpiTableInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ }
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->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 && AcpiTableInstance->Dsdt1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->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
+ //
+ AcpiTableInstance->Dsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Dsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ if ((UINT64)(UINTN)AcpiTableInstance->Dsdt3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt3;
+ //
+ // Comment block "the caller installs the tables in "FADT, DSDT" order"
+ // The below comments are also in "the caller installs the tables in "DSDT, FADT" order" comment block.
+ //
+ // The ACPI specification, up to and including revision 5.1 Errata A,
+ // allows the DSDT and X_DSDT fields to be both set in the FADT.
+ // (Obviously, this only makes sense if the DSDT address is representable in 4 bytes.)
+ // Starting with 5.1 Errata B, specifically for Mantis 1393 <https://mantis.uefi.org/mantis/view.php?id=1393>,
+ // the spec requires at most one of DSDT and X_DSDT fields to be set to a nonzero value,
+ // but strangely an exception is 6.0 that has no this requirement.
+ //
+ // Here we do not make the DSDT and X_DSDT fields mutual exclusion conditionally
+ // by checking FADT revision, but always set both DSDT and X_DSDT fields in the FADT
+ // to have better compatibility as some OS may have assumption to only consume X_DSDT
+ // field even the DSDT address is < 4G.
+ //
+ Buffer64 = AcpiTableInstance->Fadt3->Dsdt;
+ } else {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Dsdt3;
+ }
+ CopyMem (&AcpiTableInstance->Fadt3->XDsdt, &Buffer64, sizeof (UINT64));
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->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 (&AcpiTableInstance->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 (AcpiTableInstance->NumberOfTableEntries1 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiTableInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+ CurrentRsdtEntry = (UINT32 *)
+ (
+ (UINT8 *) AcpiTableInstance->Rsdt1 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries1 *
+ sizeof (UINT32)
+ );
+
+ //
+ // Add entry to the RSDT unless its the FACS or DSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiTableInstance->Rsdt1->Length = AcpiTableInstance->Rsdt1->Length + sizeof (UINT32);
+
+ AcpiTableInstance->NumberOfTableEntries1++;
+ }
+ }
+ //
+ // Add to ACPI 2.0/3.0 table tree
+ //
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ if (AddToRsdt) {
+ //
+ // If the table number exceed the gEfiAcpiMaxNumTables, enlarge the table buffer
+ //
+ if (AcpiTableInstance->NumberOfTableEntries3 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiTableInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // 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 *) AcpiTableInstance->Rsdt3 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries3 *
+ sizeof (UINT32)
+ );
+
+ //
+ // Add entry to the RSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiTableInstance->Rsdt3->Length = AcpiTableInstance->Rsdt3->Length + 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 *) AcpiTableInstance->Xsdt +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries3 *
+ sizeof (UINT64)
+ );
+
+ //
+ // 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
+ //
+ AcpiTableInstance->Xsdt->Length = AcpiTableInstance->Xsdt->Length + sizeof (UINT64);
+
+ AcpiTableInstance->NumberOfTableEntries3++;
+ }
+ }
+
+ ChecksumCommonTables (AcpiTableInstance);
+ 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 OPTIONAL,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER * Xsdt OPTIONAL
+ )
+{
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 CurrentTablePointer64;
+ UINTN Index;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (Table);
+ ASSERT (NumberOfTableEntries);
+ ASSERT (Rsdt || Xsdt);
+
+ //
+ // Find the table entry in the RSDT and XSDT
+ //
+ for (Index = 0; Index < *NumberOfTableEntries; Index++) {
+ //
+ // 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.
+ //
+ if (Rsdt != NULL) {
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER) + Index * sizeof (UINT32));
+ } else {
+ CurrentRsdtEntry = NULL;
+ }
+ 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) + Index * 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 (((Rsdt == NULL) || *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.
+ //
+ if (Rsdt != NULL) {
+ CopyMem (CurrentRsdtEntry, CurrentRsdtEntry + 1, (*NumberOfTableEntries - Index) * sizeof (UINT32));
+ Rsdt->Length = Rsdt->Length - sizeof (UINT32);
+ }
+ if (Xsdt != NULL) {
+ CopyMem (CurrentXsdtEntry, ((UINT64 *) CurrentXsdtEntry) + 1, (*NumberOfTableEntries - Index) * sizeof (UINT64));
+ Xsdt->Length = Xsdt->Length - sizeof (UINT64);
+ }
+ break;
+ } else if (Index + 1 == *NumberOfTableEntries) {
+ //
+ // At the last entry, and table not found
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Checksum the tables
+ //
+ if (Rsdt != NULL) {
+ 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 AcpiTableInstance 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_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN OUT EFI_ACPI_TABLE_LIST *Table
+ )
+{
+ UINT32 CurrentTableSignature;
+ BOOLEAN RemoveFromRsdt;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+ ASSERT (Table);
+
+ //
+ // Init locals
+ //
+ RemoveFromRsdt = TRUE;
+ //
+ // Check for Table->Table
+ //
+ ASSERT (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
+ //
+ if (Table->Table != NULL) {
+ //
+ // 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,
+ &AcpiTableInstance->NumberOfTableEntries1,
+ AcpiTableInstance->Rsdt1,
+ NULL
+ );
+ }
+ }
+
+ if (Version & ACPI_TABLE_VERSION_GTE_2_0 & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~(Version & ACPI_TABLE_VERSION_GTE_2_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,
+ &AcpiTableInstance->NumberOfTableEntries3,
+ AcpiTableInstance->Rsdt3,
+ AcpiTableInstance->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) {
+ AcpiTableInstance->Fadt1 = NULL;
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Fadt3 = NULL;
+ }
+ break;
+
+ case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Facs1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->FirmwareCtrl = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Facs3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->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) {
+ AcpiTableInstance->Dsdt1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->Dsdt = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Dsdt3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ ZeroMem (&AcpiTableInstance->Fadt3->XDsdt, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->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 AcpiTableInstance 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_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ )
+{
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_STATUS Status;
+
+ Table = (EFI_ACPI_TABLE_LIST*) NULL;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+
+ //
+ // Find the table
+ //
+ Status = FindTableByHandle (
+ Handle,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Remove the table
+ //
+ Status = DeleteTable (AcpiTableInstance, 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 AcpiTableInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ //
+ // RSDP ACPI 1.0 checksum for 1.0 table. This is only the first 20 bytes of the structure
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiPlatformChecksum (
+ AcpiTableInstance->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 (
+ AcpiTableInstance->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 (
+ AcpiTableInstance->Rsdp3,
+ sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ ExtendedChecksum)
+ );
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // RSDT checksums
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdt1,
+ AcpiTableInstance->Rsdt1->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdt3,
+ AcpiTableInstance->Rsdt3->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+
+ //
+ // XSDT checksum
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Xsdt,
+ AcpiTableInstance->Xsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Constructor for the ACPI table protocol. Initializes instance
+ data.
+
+ @param AcpiTableInstance Instance to construct
+
+ @return EFI_SUCCESS Instance initialized.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+AcpiTableAcpiTableConstructor (
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+ UINTN TotalSize;
+ UINTN RsdpTableSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+
+ //
+ // If ACPI v1.0b is among the ACPI versions we aim to support, we have to
+ // ensure that all memory allocations are below 4 GB.
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ mAcpiTableAllocType = AllocateMaxAddress;
+ } else {
+ mAcpiTableAllocType = AllocateAnyPages;
+ }
+
+ InitializeListHead (&AcpiTableInstance->TableList);
+ AcpiTableInstance->CurrentHandle = 1;
+
+ AcpiTableInstance->AcpiTableProtocol.InstallAcpiTable = InstallAcpiTable;
+ AcpiTableInstance->AcpiTableProtocol.UninstallAcpiTable = UninstallAcpiTable;
+
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ SdtAcpiTableAcpiSdtConstructor (AcpiTableInstance);
+ }
+
+ //
+ // Create RSDP table
+ //
+ RsdpTableSize = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ RsdpTableSize += sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ }
+
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (RsdpTableSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, RsdpTableSize);
+
+ AcpiTableInstance->Rsdp1 = (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ }
+ AcpiTableInstance->Rsdp3 = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+
+ //
+ // Create RSDT, XSDT structures
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ 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);
+ }
+
+ //
+ // 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 (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)AcpiTableInstance->Rsdp1, EFI_SIZE_TO_PAGES (RsdpTableSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiTableInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ AcpiTableInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ }
+ AcpiTableInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Initialize RSDP
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CurrentData = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiTableInstance->Rsdp1->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiTableInstance->Rsdp1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdp1->OemId));
+ AcpiTableInstance->Rsdp1->Reserved = EFI_ACPI_RESERVED_BYTE;
+ AcpiTableInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt1;
+ }
+
+ CurrentData = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiTableInstance->Rsdp3->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiTableInstance->Rsdp3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdp3->OemId));
+ AcpiTableInstance->Rsdp3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION;
+ AcpiTableInstance->Rsdp3->Length = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt3;
+ }
+ CurrentData = (UINT64) (UINTN) AcpiTableInstance->Xsdt;
+ CopyMem (&AcpiTableInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+ SetMem (AcpiTableInstance->Rsdp3->Reserved, 3, EFI_ACPI_RESERVED_BYTE);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // 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.
+ //
+ AcpiTableInstance->Rsdt1->Signature = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Rsdt1->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Rsdt1->Revision = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Rsdt1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdt1->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Rsdt1->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Rsdt1->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Rsdt1->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Rsdt1->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->NumberOfTableEntries1 = 1;
+ AcpiTableInstance->Rsdt1->Length = AcpiTableInstance->Rsdt1->Length + sizeof(UINT32);
+
+ AcpiTableInstance->Rsdt3->Signature = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Rsdt3->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Rsdt3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Rsdt3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdt3->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Rsdt3->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Rsdt3->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Rsdt3->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Rsdt3->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->Rsdt3->Length = AcpiTableInstance->Rsdt3->Length + sizeof(UINT32);
+ }
+ AcpiTableInstance->NumberOfTableEntries3 = 1;
+
+ //
+ // Initialize Xsdt
+ //
+ AcpiTableInstance->Xsdt->Signature = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Xsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Xsdt->Revision = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Xsdt->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Xsdt->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Xsdt->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Xsdt->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Xsdt->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Xsdt->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->Xsdt->Length = AcpiTableInstance->Xsdt->Length + sizeof(UINT64);
+
+ ChecksumCommonTables (AcpiTableInstance);
+
+ //
+ // Completed successfully
+ //
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c
new file mode 100644
index 000000000..368805674
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c
@@ -0,0 +1,296 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiTable.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+AML_BYTE_ENCODING mAmlByteEncoding[] = {
+ // OpCode SubOpCode Num 1 2 3 4 5 6 Attribute
+/* ZeroOp - 0x00 */ {AML_ZERO_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OneOp - 0x01 */ {AML_ONE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AliasOp - 0x06 */ {AML_ALIAS_OP, 0, 2, {AML_NAME, AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* NameOp - 0x08 */ {AML_NAME_OP, 0, 2, {AML_NAME, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* BytePrefix - 0x0A */ {AML_BYTE_PREFIX, 0, 1, {AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* WordPrefix - 0x0B */ {AML_WORD_PREFIX, 0, 1, {AML_UINT16, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DWordPrefix - 0x0C */ {AML_DWORD_PREFIX, 0, 1, {AML_UINT32, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StringPrefix - 0x0D */ {AML_STRING_PREFIX, 0, 1, {AML_STRING, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* QWordPrefix - 0x0E */ {AML_QWORD_PREFIX, 0, 1, {AML_UINT64, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ScopeOp - 0x10 */ {AML_SCOPE_OP, 0, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* BufferOp - 0x11 */ {AML_BUFFER_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* PackageOp - 0x12 */ {AML_PACKAGE_OP, 0, 1, {AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* VarPackageOp - 0x13 */ {AML_VAR_PACKAGE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* MethodOp - 0x14 */ {AML_METHOD_OP, 0, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* DualNamePrefix - 0x2F */ {AML_DUAL_NAME_PREFIX, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* MultiNamePrefix - 0x2F */ {AML_MULTI_NAME_PREFIX, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x41 */ {'A', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x42 */ {'B', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x43 */ {'C', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x44 */ {'D', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x45 */ {'E', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x46 */ {'F', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x47 */ {'G', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x48 */ {'H', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x49 */ {'I', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4A */ {'J', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4B */ {'K', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4C */ {'L', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4D */ {'M', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4E */ {'N', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4F */ {'O', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x50 */ {'P', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x51 */ {'Q', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x52 */ {'R', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x53 */ {'S', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x54 */ {'T', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x55 */ {'U', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x56 */ {'V', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x57 */ {'W', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x58 */ {'X', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x59 */ {'Y', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x5A */ {'Z', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* MutexOp - 0x5B 0x01 */ {AML_EXT_OP, AML_EXT_MUTEX_OP, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* EventOp - 0x5B 0x02 */ {AML_EXT_OP, AML_EXT_EVENT_OP, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* CondRefOfOp - 0x5B 0x12 */ {AML_EXT_OP, AML_EXT_COND_REF_OF_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateFieldOp - 0x5B 0x13 */ {AML_EXT_OP, AML_EXT_CREATE_FIELD_OP,4, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE}, 0},
+/* LoadTableOp - 0x5B 0x1F */ {AML_EXT_OP, AML_EXT_LOAD_TABLE_OP, 6, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT}, 0},
+/* LoadOp - 0x5B 0x20 */ {AML_EXT_OP, AML_EXT_LOAD_OP, 2, {AML_NAME, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StallOp - 0x5B 0x21 */ {AML_EXT_OP, AML_EXT_STALL_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SleepOp - 0x5B 0x22 */ {AML_EXT_OP, AML_EXT_SLEEP_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AcquireOp - 0x5B 0x23 */ {AML_EXT_OP, AML_EXT_ACQUIRE_OP, 2, {AML_OBJECT, AML_UINT16, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SignalOp - 0x5B 0x24 */ {AML_EXT_OP, AML_EXT_SIGNAL_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* WaitOp - 0x5B 0x25 */ {AML_EXT_OP, AML_EXT_WAIT_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ResetOp - 0x5B 0x26 */ {AML_EXT_OP, AML_EXT_RESET_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ReleaseOp - 0x5B 0x27 */ {AML_EXT_OP, AML_EXT_RELEASE_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FromBCDOp - 0x5B 0x28 */ {AML_EXT_OP, AML_EXT_FROM_BCD_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToBCDOp - 0x5B 0x29 */ {AML_EXT_OP, AML_EXT_TO_BCD_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* UnloadOp - 0x5B 0x2A */ {AML_EXT_OP, AML_EXT_UNLOAD_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* RevisionOp - 0x5B 0x30 */ {AML_EXT_OP, AML_EXT_REVISION_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DebugOp - 0x5B 0x31 */ {AML_EXT_OP, AML_EXT_DEBUG_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FatalOp - 0x5B 0x32 */ {AML_EXT_OP, AML_EXT_FATAL_OP, 3, {AML_UINT8, AML_UINT32, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* TimerOp - 0x5B 0x33 */ {AML_EXT_OP, AML_EXT_TIMER_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OpRegionOp - 0x5B 0x80 */ {AML_EXT_OP, AML_EXT_REGION_OP, 4, {AML_NAME, AML_UINT8, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* FieldOp - 0x5B 0x81 */ {AML_EXT_OP, AML_EXT_FIELD_OP, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* DeviceOp - 0x5B 0x82 */ {AML_EXT_OP, AML_EXT_DEVICE_OP, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* ProcessorOp - 0x5B 0x83 */ {AML_EXT_OP, AML_EXT_PROCESSOR_OP, 4, {AML_NAME, AML_UINT8, AML_UINT32, AML_UINT8, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* PowerResOp - 0x5B 0x84 */ {AML_EXT_OP, AML_EXT_POWER_RES_OP, 3, {AML_NAME, AML_UINT8, AML_UINT16, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* ThermalZoneOp - 0x5B 0x85 */ {AML_EXT_OP, AML_EXT_THERMAL_ZONE_OP,1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* IndexFieldOp - 0x5B 0x86 */ {AML_EXT_OP, AML_EXT_INDEX_FIELD_OP, 3, {AML_NAME, AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* BankFieldOp - 0x5B 0x87 */ {AML_EXT_OP, AML_EXT_BANK_FIELD_OP, 4, {AML_NAME, AML_NAME, AML_OBJECT, AML_UINT8, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* DataRegionOp - 0x5B 0x88 */ {AML_EXT_OP, AML_EXT_DATA_REGION_OP, 4, {AML_NAME, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* RootChar - 0x5C */ {AML_ROOT_CHAR, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* ParentPrefixChar - 0x5E */ {AML_PARENT_PREFIX_CHAR, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x5F */ {'_', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* Local0Op - 0x60 */ {AML_LOCAL0, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local1Op - 0x61 */ {AML_LOCAL1, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local2Op - 0x62 */ {AML_LOCAL2, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local3Op - 0x63 */ {AML_LOCAL3, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local4Op - 0x64 */ {AML_LOCAL4, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local5Op - 0x65 */ {AML_LOCAL5, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local6Op - 0x66 */ {AML_LOCAL6, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local7Op - 0x67 */ {AML_LOCAL7, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg0Op - 0x68 */ {AML_ARG0, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg1Op - 0x69 */ {AML_ARG1, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg2Op - 0x6A */ {AML_ARG2, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg3Op - 0x6B */ {AML_ARG3, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg4Op - 0x6C */ {AML_ARG4, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg5Op - 0x6D */ {AML_ARG5, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg6Op - 0x6E */ {AML_ARG6, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StoreOp - 0x70 */ {AML_STORE_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* RefOfOp - 0x71 */ {AML_REF_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AddOp - 0x72 */ {AML_ADD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ConcatOp - 0x73 */ {AML_CONCAT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SubtractOp - 0x74 */ {AML_SUBTRACT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IncrementOp - 0x75 */ {AML_INCREMENT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DecrementOp - 0x76 */ {AML_DECREMENT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MultiplyOp - 0x77 */ {AML_MULTIPLY_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DivideOp - 0x78 */ {AML_DIVIDE_OP, 0, 4, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, 0},
+/* ShiftLeftOp - 0x79 */ {AML_SHIFT_LEFT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ShiftRightOp - 0x7A */ {AML_SHIFT_RIGHT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AndOp - 0x7B */ {AML_AND_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NAndOp - 0x7C */ {AML_NAND_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OrOp - 0x7D */ {AML_OR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NorOp - 0x7E */ {AML_NOR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* XOrOp - 0x7F */ {AML_XOR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NotOp - 0x80 */ {AML_NOT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FindSetLeftBitOp - 0x81 */ {AML_FIND_SET_LEFT_BIT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FindSetRightBitOp - 0x82 */ {AML_FIND_SET_RIGHT_BIT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DerefOfOp - 0x83 */ {AML_DEREF_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ConcatResOp - 0x84 */ {AML_CONCAT_RES_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ModOp - 0x85 */ {AML_MOD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NotifyOp - 0x86 */ {AML_NOTIFY_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SizeOfOp - 0x87 */ {AML_SIZE_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IndexOp - 0x88 */ {AML_INDEX_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MatchOp - 0x89 */ {AML_MATCH_OP, 0, 6, {AML_OBJECT, AML_UINT8, AML_OBJECT, AML_UINT8, AML_OBJECT, AML_OBJECT}, 0},
+/* CreateDWordFieldOp - 0x8A */ {AML_CREATE_DWORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateWordFieldOp - 0x8B */ {AML_CREATE_WORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateByteFieldOp - 0x8C */ {AML_CREATE_BYTE_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateBitFieldOp - 0x8D */ {AML_CREATE_BIT_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ObjectTypeOp - 0x8E */ {AML_OBJECT_TYPE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateQWordFieldOp - 0x8F */ {AML_CREATE_QWORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LAndOp - 0x90 */ {AML_LAND_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LOrOp - 0x91 */ {AML_LOR_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LNotOp - 0x92 */ {AML_LNOT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LEqualOp - 0x93 */ {AML_LEQUAL_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LGreaterOp - 0x94 */ {AML_LGREATER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LLessOp - 0x95 */ {AML_LLESS_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToBufferOp - 0x96 */ {AML_TO_BUFFER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToDecimalStringOp - 0x97 */ {AML_TO_DEC_STRING_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToHexStringOp - 0x98 */ {AML_TO_HEX_STRING_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToIntegerOp - 0x99 */ {AML_TO_INTEGER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToStringOp - 0x9C */ {AML_TO_STRING_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CopyObjectOp - 0x9D */ {AML_COPY_OBJECT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MidOp - 0x9E */ {AML_MID_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ContinueOp - 0x9F */ {AML_CONTINUE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IfOp - 0xA0 */ {AML_IF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* ElseOp - 0xA1 */ {AML_ELSE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* WhileOp - 0xA2 */ {AML_WHILE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* NoopOp - 0xA3 */ {AML_NOOP_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ReturnOp - 0xA4 */ {AML_RETURN_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* BreakOp - 0xA5 */ {AML_BREAK_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* BreakPointOp - 0xCC */ {AML_BREAK_POINT_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OnesOp - 0xFF */ {AML_ONES_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_ACPI_DATA_TYPE mAmlTypeToAcpiType[] = {
+ EFI_ACPI_DATA_TYPE_NONE, // AML_NONE
+ EFI_ACPI_DATA_TYPE_OPCODE, // AML_OPCODE
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT8
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT16
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT32
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT64
+ EFI_ACPI_DATA_TYPE_NAME_STRING, // AML_NAME
+ EFI_ACPI_DATA_TYPE_STRING, // AML_STRING
+ EFI_ACPI_DATA_TYPE_CHILD // AML_OBJECT
+};
+
+/**
+ This function returns AmlByteEncoding according to OpCode Byte.
+
+ @param[in] OpByteBuffer OpCode byte buffer.
+
+ @return AmlByteEncoding
+**/
+AML_BYTE_ENCODING *
+AmlSearchByOpByte (
+ IN UINT8 *OpByteBuffer
+ )
+{
+ UINT8 OpCode;
+ UINT8 SubOpCode;
+ UINTN Index;
+
+ //
+ // Get OpCode and SubOpCode
+ //
+ OpCode = OpByteBuffer[0];
+ if (OpCode == AML_EXT_OP) {
+ SubOpCode = OpByteBuffer[1];
+ } else {
+ SubOpCode = 0;
+ }
+
+ //
+ // Search the table
+ //
+ for (Index = 0; Index < sizeof(mAmlByteEncoding)/sizeof(mAmlByteEncoding[0]); Index++) {
+ if ((mAmlByteEncoding[Index].OpCode == OpCode) && (mAmlByteEncoding[Index].SubOpCode == SubOpCode)) {
+ return &mAmlByteEncoding[Index];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ This function returns AcpiDataType according to AmlType.
+
+ @param[in] AmlType AML Type.
+
+ @return AcpiDataType
+**/
+EFI_ACPI_DATA_TYPE
+AmlTypeToAcpiType (
+ IN AML_OP_PARSE_FORMAT AmlType
+ )
+{
+ if (AmlType >= sizeof(mAmlTypeToAcpiType)/sizeof(mAmlTypeToAcpiType[0])) {
+ ASSERT(FALSE);
+ return EFI_ACPI_DATA_TYPE_NONE;
+ }
+ return mAmlTypeToAcpiType [AmlType];
+}
+
+/**
+ This function retuns package length from the buffer.
+
+ @param[in] Buffer AML buffer
+ @param[out] PkgLength The total length of package.
+
+ @return The byte data count to present the package length.
+**/
+UINTN
+AmlGetPkgLength (
+ IN UINT8 *Buffer,
+ OUT UINTN *PkgLength
+ )
+{
+ UINT8 LeadByte;
+ UINT8 ByteCount;
+ UINTN RealLength;
+ UINTN Offset;
+
+ //
+ // <bit 7-6: ByteData count that follows (0-3)>
+ // <bit 5-4: Only used if PkgLength < 63>
+ // <bit 3-0: Least significant package length nybble>
+ //
+ // Note: The high 2 bits of the first byte reveal how many follow bytes are in the
+ // If the PkgLength has only one byte, bit 0 through 5 are used to encode the
+ // package length (in other words, values 0-63). If the package length value is more than
+ // 63, more than one byte must be used for the encoding in which case bit 4 and 5 of the
+ // PkgLeadByte are reserved and must be zero. If the multiple bytes encoding is used,
+ // bits 0-3 of the PkgLeadByte become the least significant 4 bits of the resulting
+ // package length value. The next ByteData will become the next least significant 8 bits
+ // of the resulting value and so on, up to 3 ByteData bytes. Thus, the maximum package
+ // length is 2**28.
+ //
+
+ LeadByte = *Buffer;
+ ByteCount = (UINT8)((LeadByte >> 6) & 0x03);
+ Offset = ByteCount + 1;
+ RealLength = 0;
+
+ switch (ByteCount) {
+ case 0:
+ RealLength = (UINT32)LeadByte;
+ break;
+ case 1:
+ RealLength = *(Buffer + 1);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ case 2:
+ RealLength = *(Buffer + 1);
+ RealLength |= (UINTN)((*(Buffer + 2)) << 8);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ case 3:
+ RealLength = *(Buffer + 1);
+ RealLength |= (UINTN)((*(Buffer + 2)) << 8);
+ RealLength |= (UINTN)((*(Buffer + 3)) << 16);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ default:
+ ASSERT (0);
+ break;
+ }
+
+ *PkgLength = RealLength;
+ return Offset;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c
new file mode 100644
index 000000000..562271807
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c
@@ -0,0 +1,274 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiTable.h"
+
+/**
+ Return the child objects buffer from AML Handle's buffer.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] CurrentBuffer The current child buffer.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromObjectBuffer (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN UINT8 *CurrentBuffer,
+ OUT VOID **Buffer
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ UINTN DataSize;
+
+ //
+ // Root is considered as SCOPE, which has TermList.
+ // We need return only Object in TermList.
+ //
+ while ((UINTN)CurrentBuffer < (UINTN)(AmlParentHandle->Buffer + AmlParentHandle->Size)) {
+ AmlByteEncoding = AmlSearchByOpByte (CurrentBuffer);
+ if (AmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // NOTE: We need return everything, because user might need parse the returned object.
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0) {
+ *Buffer = CurrentBuffer;
+ return EFI_SUCCESS;
+ }
+
+ DataSize = AmlGetObjectSize (
+ AmlByteEncoding,
+ CurrentBuffer,
+ (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)CurrentBuffer
+ );
+ if (DataSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBuffer += DataSize;
+ }
+
+ //
+ // No more
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child ACPI objects from Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ UINT8 *CurrentBuffer;
+
+ if (AmlHandle == NULL) {
+ //
+ // First One
+ //
+ CurrentBuffer = (VOID *)AmlParentHandle->Buffer;
+ } else {
+ CurrentBuffer = (VOID *)(AmlHandle->Buffer + AmlHandle->Size);
+ }
+
+ return AmlGetChildFromObjectBuffer (AmlParentHandle, CurrentBuffer, Buffer);
+}
+
+/**
+ Return the child objects buffer from AML Handle's option list.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] AmlHandle The current child handle.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromOptionList (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *Data;
+ UINTN DataSize;
+ AML_OP_PARSE_INDEX Index;
+ EFI_STATUS Status;
+ AML_OP_PARSE_INDEX MaxTerm;
+
+ Index = AML_OP_PARSE_INDEX_GET_TERM1;
+ MaxTerm = AmlParentHandle->AmlByteEncoding->MaxIndex;
+ while (Index <= MaxTerm) {
+ Status = AmlParseOptionHandleCommon (
+ AmlParentHandle,
+ (AML_OP_PARSE_INDEX)Index,
+ &DataType,
+ (VOID **)&Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataType == EFI_ACPI_DATA_TYPE_NONE) {
+ //
+ // Not found
+ //
+ break;
+ }
+
+ //
+ // Find it, and Check Data
+ //
+ if ((DataType == EFI_ACPI_DATA_TYPE_CHILD) &&
+ ((UINTN)AmlHandle->Buffer < (UINTN)Data)) {
+ //
+ // Buffer < Data means current node is next one
+ //
+ *Buffer = Data;
+ return EFI_SUCCESS;
+ }
+ //
+ // Not Child
+ //
+ Index ++;
+ }
+
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child objects buffer from AML Handle's object child list.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] AmlHandle The current child handle.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromObjectChildList (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *CurrentBuffer;
+
+ CurrentBuffer = NULL;
+
+ if ((AmlParentHandle->AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
+ //
+ // No ObjectList
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do we need add node within METHOD?
+ // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
+ //
+
+ //
+ // Now, we get the last node.
+ //
+ Status = AmlGetOffsetAfterLastOption (AmlParentHandle, &CurrentBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Go through all the reset buffer.
+ //
+ if ((UINTN)AmlHandle->Buffer < (UINTN)CurrentBuffer) {
+ //
+ // Buffer < Data means next node is first object
+ //
+ } else if ((UINTN)AmlHandle->Buffer + AmlHandle->Size < (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size) {
+ //
+ // There is still more node
+ //
+ CurrentBuffer = AmlHandle->Buffer + AmlHandle->Size;
+ } else {
+ //
+ // No more data
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+ }
+
+ return AmlGetChildFromObjectBuffer (AmlParentHandle, CurrentBuffer, Buffer);
+}
+
+/**
+ Return the child ACPI objects from Non-Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Non-Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromNonRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (AmlHandle == NULL) {
+ //
+ // NULL means first one
+ //
+ AmlHandle = AmlParentHandle;
+ }
+
+ //
+ // 1. Get Option
+ //
+ Status = AmlGetChildFromOptionList (AmlParentHandle, AmlHandle, Buffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*Buffer != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 2. search ObjectList
+ //
+ return AmlGetChildFromObjectChildList (AmlParentHandle, AmlHandle, Buffer);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
new file mode 100644
index 000000000..8139f3ab4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
@@ -0,0 +1,608 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiTable.h"
+
+/**
+ Construct node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeList (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ );
+
+/**
+ Create AML Node.
+
+ @param[in] NameSeg AML NameSeg.
+ @param[in] Parent AML parent node list.
+ @param[in] AmlByteEncoding AML Byte Encoding.
+
+ @return AML Node.
+**/
+EFI_AML_NODE_LIST *
+AmlCreateNode (
+ IN UINT8 *NameSeg,
+ IN EFI_AML_NODE_LIST *Parent,
+ IN AML_BYTE_ENCODING *AmlByteEncoding
+ )
+{
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ AmlNodeList = AllocatePool (sizeof(*AmlNodeList));
+ ASSERT (AmlNodeList != NULL);
+
+ AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE;
+ CopyMem (AmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE);
+ AmlNodeList->Buffer = NULL;
+ AmlNodeList->Size = 0;
+ InitializeListHead (&AmlNodeList->Link);
+ InitializeListHead (&AmlNodeList->Children);
+ AmlNodeList->Parent = Parent;
+ AmlNodeList->AmlByteEncoding = AmlByteEncoding;
+
+ return AmlNodeList;
+}
+
+/**
+ Find the AML NameSeg in the children of AmlParentNodeList.
+
+ @param[in] NameSeg AML NameSeg.
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Create TRUE means to create node if not found.
+
+ @return AmlChildNode whoes name is same as NameSeg.
+**/
+EFI_AML_NODE_LIST *
+AmlFindNodeInThis (
+ IN UINT8 *NameSeg,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN BOOLEAN Create
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ StartLink = &AmlParentNodeList->Children;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ //
+ // AML name is same as the one stored
+ //
+ if (CompareMem (CurrentAmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE) == 0) {
+ //
+ // Good! Found it
+ //
+ return CurrentAmlNodeList;
+ }
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Not found
+ //
+ if (!Create) {
+ return NULL;
+ }
+
+ //
+ // Create new node with NULL buffer - it means namespace not be returned.
+ //
+ AmlNodeList = AmlCreateNode (NameSeg, AmlParentNodeList, NULL);
+ InsertTailList (&AmlParentNodeList->Children, &AmlNodeList->Link);
+
+ return AmlNodeList;
+}
+
+/**
+ Find the AML NameString in the children of AmlParentNodeList or AmlRootNodeList.
+
+ @param[in] NameString AML NameString.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Create TRUE means to create node if not found.
+
+ @return AmlChildNode whoes name is same as NameSeg.
+**/
+EFI_AML_NODE_LIST *
+AmlFindNodeInTheTree (
+ IN UINT8 *NameString,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN BOOLEAN Create
+ )
+{
+ UINT8 *Buffer;
+ EFI_AML_NODE_LIST *AmlNodeList;
+ EFI_AML_NODE_LIST *AmlCurrentNodeList;
+ UINT8 Index;
+ UINT8 SegCount;
+
+ Buffer = NameString;
+
+ //
+ // Handle root or parent prefix
+ //
+ if (*Buffer == AML_ROOT_CHAR) {
+ AmlCurrentNodeList = AmlRootNodeList;
+ Buffer += 1;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ AmlCurrentNodeList = AmlParentNodeList;
+ do {
+ if (AmlCurrentNodeList->Parent != NULL) {
+ AmlCurrentNodeList = AmlCurrentNodeList->Parent;
+ } else {
+ //
+ // Only root has no parent
+ //
+ ASSERT (AmlCurrentNodeList == AmlRootNodeList);
+ }
+ Buffer += 1;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ } else {
+ AmlCurrentNodeList = AmlParentNodeList;
+ }
+
+ //
+ // Handle name segment
+ //
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ Buffer += 1;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ Buffer += 1;
+ SegCount = *Buffer;
+ Buffer += 1;
+ } else if (*Buffer == 0) {
+ //
+ // NULL name, only for Root
+ //
+ ASSERT (AmlCurrentNodeList == AmlRootNodeList);
+ return AmlCurrentNodeList;
+ } else {
+ SegCount = 1;
+ }
+
+ //
+ // Handle NamePath
+ //
+ Index = 0;
+ do {
+ AmlNodeList = AmlFindNodeInThis (Buffer, AmlCurrentNodeList, Create);
+ if (AmlNodeList == NULL) {
+ return NULL;
+ }
+ AmlCurrentNodeList = AmlNodeList;
+ Buffer += AML_NAME_SEG_SIZE;
+ Index ++;
+ } while (Index < SegCount);
+
+ return AmlNodeList;
+}
+
+/**
+ Insert the NameString to the AmlNodeList.
+
+ @param[in] NameString AML NameString.
+ @param[in] Buffer Buffer for the Node.
+ @param[in] Size Size for the Node.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @return AmlChildNode whoes name is NameString.
+**/
+EFI_AML_NODE_LIST *
+AmlInsertNodeToTree (
+ IN UINT8 *NameString,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ AmlNodeList = AmlFindNodeInTheTree (
+ NameString,
+ AmlRootNodeList,
+ AmlParentNodeList,
+ TRUE // Find and Create
+ );
+ ASSERT (AmlNodeList != NULL);
+ if (AmlNodeList == NULL) {
+ return NULL;
+ }
+
+ //
+ // Check buffer
+ //
+ if (AmlNodeList->Buffer == NULL) {
+ //
+ // NULL means new added one or SCOPE_OP
+ //
+ if (*(UINT8 *)Buffer != AML_SCOPE_OP) {
+ //
+ // We need check if new one is SCOPE_OP, because SCOPE_OP just means namespace, not a real device.
+ // We should not return SCOPE_OP.
+ //
+ AmlNodeList->Buffer = Buffer;
+ AmlNodeList->Size = Size;
+ AmlNodeList->AmlByteEncoding = AmlSearchByOpByte (Buffer);
+ }
+ return AmlNodeList;
+ }
+
+ //
+ // Already added
+ //
+ if (*(UINT8 *)Buffer == AML_SCOPE_OP) {
+ //
+ // The new one is SCOPE_OP, OK just return;
+ //
+ return AmlNodeList;
+ }
+
+ //
+ // Oops!!!, There must be something wrong.
+ //
+ DEBUG ((EFI_D_ERROR, "AML: Override Happen - %a!\n", NameString));
+ DEBUG ((EFI_D_ERROR, "AML: Existing Node - %x\n", AmlNodeList->Buffer));
+ DEBUG ((EFI_D_ERROR, "AML: New Buffer - %x\n", Buffer));
+
+ return NULL;
+}
+
+/**
+ Construct child node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeListForChild (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ UINT8 *CurrentBuffer;
+ EFI_AML_HANDLE *AmlChildHandle;
+ EFI_STATUS Status;
+
+ CurrentBuffer = NULL;
+ AmlChildHandle = NULL;
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+ Buffer = AmlHandle->Buffer;
+ BufferSize = AmlHandle->Size;
+
+ //
+ // Check if we need recursively add node
+ //
+ if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
+ //
+ // No more node need to be added
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do we need add node within METHOD?
+ // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
+ //
+
+ //
+ // Now, we get the last node.
+ //
+ Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Go through all the reset buffer.
+ //
+ while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {
+ //
+ // Find the child node.
+ //
+ Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // No child found, break now.
+ //
+ break;
+ }
+
+ //
+ // Good, find the child. Construct node recursively
+ //
+ Status = AmlConstructNodeList (
+ AmlChildHandle,
+ AmlRootNodeList,
+ AmlParentNodeList
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Parse next one
+ //
+ CurrentBuffer += AmlChildHandle->Size;
+
+ Close ((EFI_ACPI_HANDLE)AmlChildHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeList (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ VOID *NameString;
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ //
+ // 1. Check if there is need to construct node for this OpCode.
+ //
+ if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {
+ //
+ // No need to construct node, so we just skip this OpCode.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 2. Now, we need construct node for this OpCode.
+ //
+ NameString = AmlGetObjectName (AmlHandle);
+ if (NameString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Now, we need to insert node to the node list.
+ // NOTE: The name here could be AML NameString. So the callee need parse it.
+ //
+ AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);
+ ASSERT (AmlNodeList != NULL);
+
+ //
+ // 3. Ok, we need to parse the object list to see if there are more node to be added.
+ //
+ return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);
+}
+
+/**
+ Destruct node list
+
+ @param[in] AmlParentNodeList AML parent node list.
+**/
+VOID
+AmlDestructNodeList (
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the children link
+ //
+ StartLink = &AmlParentNodeList->Children;
+ CurrentLink = StartLink->ForwardLink;
+
+ //
+ // Go through all the children
+ //
+ while (CurrentLink != StartLink) {
+ //
+ // Destruct the child's list recursively
+ //
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ CurrentLink = CurrentLink->ForwardLink;
+
+ //
+ // Remove this child from list and free the node
+ //
+ RemoveEntryList (&(CurrentAmlNodeList->Link));
+
+ AmlDestructNodeList (CurrentAmlNodeList);
+ }
+
+ //
+ // Done.
+ //
+ FreePool (AmlParentNodeList);
+ return ;
+}
+
+/**
+ Dump node list
+
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Level Output debug level.
+**/
+VOID
+AmlDumpNodeInfo (
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN UINTN Level
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ volatile LIST_ENTRY *CurrentLink;
+ UINTN Index;
+
+ CurrentLink = AmlParentNodeList->Children.ForwardLink;
+
+ if (Level == 0) {
+ DEBUG ((EFI_D_ERROR, "\\"));
+ } else {
+ for (Index = 0; Index < Level; Index++) {
+ DEBUG ((EFI_D_ERROR, " "));
+ }
+ AmlPrintNameSeg (AmlParentNodeList->Name);
+ }
+ DEBUG ((EFI_D_ERROR, "\n"));
+
+ while (CurrentLink != &AmlParentNodeList->Children) {
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return ;
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI AML path
+
+ @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the ACPI AML path.
+ @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+ @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
+ FALSE means to find AML path from this Node (The HandleIn).
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlFindPath (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN UINT8 *AmlPath,
+ OUT VOID **Buffer,
+ IN BOOLEAN FromRoot
+ )
+{
+ EFI_AML_NODE_LIST *AmlRootNodeList;
+ EFI_STATUS Status;
+ EFI_AML_NODE_LIST *AmlNodeList;
+ UINT8 RootNameSeg[AML_NAME_SEG_SIZE];
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // 1. create tree
+ //
+
+ //
+ // Create root handle
+ //
+ RootNameSeg[0] = AML_ROOT_CHAR;
+ RootNameSeg[1] = 0;
+ AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);
+
+ Status = AmlConstructNodeList (
+ AmlHandle,
+ AmlRootNodeList, // Root
+ AmlRootNodeList // Parent
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));
+ AmlDumpNodeInfo (AmlRootNodeList, 0);
+ DEBUG_CODE_END ();
+
+ //
+ // 2. Search the node in the tree
+ //
+ if (FromRoot) {
+ //
+ // Search from Root
+ //
+ CurrentAmlNodeList = AmlRootNodeList;
+ } else {
+ //
+ // Search from this node, NOT ROOT.
+ // Since we insert node to ROOT one by one, we just get the first node and search from it.
+ //
+ CurrentLink = AmlRootNodeList->Children.ForwardLink;
+ if (CurrentLink != &AmlRootNodeList->Children) {
+ //
+ // First node
+ //
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ } else {
+ //
+ // No child
+ //
+ CurrentAmlNodeList = NULL;
+ }
+ }
+
+ //
+ // Search
+ //
+ if (CurrentAmlNodeList != NULL) {
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));
+ AmlPrintNameSeg (CurrentAmlNodeList->Name);
+ DEBUG ((EFI_D_ERROR, "\n"));
+ DEBUG_CODE_END ();
+ AmlNodeList = AmlFindNodeInTheTree (
+ AmlPath,
+ AmlRootNodeList, // Root
+ CurrentAmlNodeList, // Parent
+ FALSE
+ );
+ } else {
+ AmlNodeList = NULL;
+ }
+
+ *Buffer = NULL;
+ Status = EFI_SUCCESS;
+ if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {
+ *Buffer = AmlNodeList->Buffer;
+ }
+
+ //
+ // 3. free the tree
+ //
+ AmlDestructNodeList (AmlRootNodeList);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c
new file mode 100644
index 000000000..d0374c5de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c
@@ -0,0 +1,446 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiTable.h"
+
+/**
+ Retrieve option term according to AmlByteEncoding and Buffer.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML buffer.
+ @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
+ @param[in] TermIndex Index of the data to retrieve from the object.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionTerm (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize,
+ IN AML_OP_PARSE_INDEX TermIndex,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ AML_BYTE_ENCODING *ChildAmlByteEncoding;
+ EFI_STATUS Status;
+
+ if (DataType != NULL) {
+ *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
+ }
+ if (Data != NULL) {
+ *Data = Buffer;
+ }
+ //
+ // Parse term according to AML type
+ //
+ switch (AmlByteEncoding->Format[TermIndex - 1]) {
+ case AML_UINT8:
+ *DataSize = sizeof(UINT8);
+ break;
+ case AML_UINT16:
+ *DataSize = sizeof(UINT16);
+ break;
+ case AML_UINT32:
+ *DataSize = sizeof(UINT32);
+ break;
+ case AML_UINT64:
+ *DataSize = sizeof(UINT64);
+ break;
+ case AML_STRING:
+ *DataSize = AsciiStrSize((CHAR8 *)Buffer);
+ break;
+ case AML_NAME:
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case AML_OBJECT:
+ ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
+ if (ChildAmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
+ // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
+ // We should not return CHILD because there is NO OpCode for NameString.
+ //
+ if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ if (DataType != NULL) {
+ *DataType = AmlTypeToAcpiType (AML_NAME);
+ }
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ //
+ // It is real AML_OBJECT
+ //
+ *DataSize = AmlGetObjectSize (
+ ChildAmlByteEncoding,
+ Buffer,
+ MaxBufferSize
+ );
+ if (*DataSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case AML_NONE:
+ //
+ // No term
+ //
+ case AML_OPCODE:
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*DataSize > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information according to AmlByteEncoding and Buffer.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML buffer.
+ @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionCommon (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ UINT8 *CurrentBuffer;
+ UINTN PkgLength;
+ UINTN OpLength;
+ UINTN PkgOffset;
+ AML_OP_PARSE_INDEX TermIndex;
+ EFI_STATUS Status;
+
+ ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
+
+ //
+ // 0. Check if this is NAME string.
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ //
+ // Only allow GET_SIZE
+ //
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // return NameString size
+ //
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*DataSize > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Not NAME string, start parsing
+ //
+ CurrentBuffer = Buffer;
+
+ //
+ // 1. Get OpCode
+ //
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ *DataType = EFI_ACPI_DATA_TYPE_OPCODE;
+ *Data = (VOID *)CurrentBuffer;
+ }
+ if (*CurrentBuffer == AML_EXT_OP) {
+ OpLength = 2;
+ } else {
+ OpLength = 1;
+ }
+ *DataSize = OpLength;
+ if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
+ return EFI_SUCCESS;
+ }
+ if (OpLength > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBuffer += OpLength;
+
+ //
+ // 2. Skip PkgLength field, if have
+ //
+ if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
+ PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength);
+ //
+ // Override MaxBufferSize if it is valid PkgLength
+ //
+ if (OpLength + PkgLength > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ MaxBufferSize = OpLength + PkgLength;
+ }
+ } else {
+ PkgOffset = 0;
+ PkgLength = 0;
+ }
+ CurrentBuffer += PkgOffset;
+
+ //
+ // 3. Get Term one by one.
+ //
+ TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
+ while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
+ Status = AmlParseOptionTerm (
+ AmlByteEncoding,
+ CurrentBuffer,
+ (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
+ TermIndex,
+ DataType,
+ Data,
+ DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Index == TermIndex) {
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse next one
+ //
+ CurrentBuffer += *DataSize;
+ TermIndex ++;
+ }
+
+ //
+ // Finish all options, but no option found.
+ //
+ if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 4. Finish parsing all node, return size
+ //
+ ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
+ if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
+ *DataSize = OpLength + PkgLength;
+ } else {
+ *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return object size.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML object buffer.
+ @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
+
+ @return Size of the object.
+**/
+UINTN
+AmlGetObjectSize (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+
+ Status = AmlParseOptionCommon (
+ AmlByteEncoding,
+ Buffer,
+ MaxBufferSize,
+ AML_OP_PARSE_INDEX_GET_SIZE,
+ NULL,
+ NULL,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ } else {
+ return DataSize;
+ }
+}
+
+/**
+ Return object name.
+
+ @param[in] AmlHandle AML handle.
+
+ @return Name of the object.
+**/
+CHAR8 *
+AmlGetObjectName (
+ IN EFI_AML_HANDLE *AmlHandle
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ VOID *NameString;
+ UINTN NameSize;
+ AML_OP_PARSE_INDEX TermIndex;
+ EFI_STATUS Status;
+ EFI_ACPI_DATA_TYPE DataType;
+
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+
+ ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
+
+ //
+ // Find out Last Name index, according to OpCode table.
+ // The last name will be the node name by design.
+ //
+ TermIndex = AmlByteEncoding->MaxIndex;
+ for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
+ if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
+ break;
+ }
+ }
+ ASSERT (TermIndex != 0);
+
+ //
+ // Get Name for this node.
+ //
+ Status = AmlParseOptionHandleCommon (
+ AmlHandle,
+ TermIndex,
+ &DataType,
+ &NameString,
+ &NameSize
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
+
+ return NameString;
+}
+
+/**
+ Return offset of last option.
+
+ @param[in] AmlHandle AML Handle.
+ @param[out] Buffer Upon return, points to the offset after last option.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetOffsetAfterLastOption (
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT UINT8 **Buffer
+ )
+{
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *Data;
+ UINTN DataSize;
+ EFI_STATUS Status;
+
+ Status = AmlParseOptionHandleCommon (
+ AmlHandle,
+ AmlHandle->AmlByteEncoding->MaxIndex,
+ &DataType,
+ &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We need to parse the rest buffer after last node.
+ //
+ *Buffer = (UINT8 *)((UINTN)Data + DataSize);
+
+ //
+ // We need skip PkgLength if no Option
+ //
+ if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
+ *Buffer += AmlGetPkgLength (*Buffer, &DataSize);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information according to AmlHandle
+
+ @param[in] AmlHandle AML handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionHandleCommon (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ return AmlParseOptionCommon (
+ AmlHandle->AmlByteEncoding,
+ AmlHandle->Buffer,
+ AmlHandle->Size,
+ Index,
+ DataType,
+ Data,
+ DataSize
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c
new file mode 100644
index 000000000..d0b8b0d0f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c
@@ -0,0 +1,539 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiTable.h"
+
+/**
+ Check if it is AML Root name
+
+ @param[in] Buffer AML path.
+
+ @retval TRUE AML path is root.
+ @retval FALSE AML path is not root.
+**/
+BOOLEAN
+AmlIsRootPath (
+ IN UINT8 *Buffer
+ )
+{
+ if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is AML LeadName.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is AML LeadName.
+ @retval FALSE Char is not AML LeadName.
+**/
+BOOLEAN
+AmlIsLeadName (
+ IN CHAR8 Ch
+ )
+{
+ if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is AML Name.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is AML Name.
+ @retval FALSE Char is not AML Name.
+**/
+BOOLEAN
+AmlIsName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Return is buffer is AML NameSeg.
+
+ @param[in] Buffer AML NameSement.
+
+ @retval TRUE It is AML NameSegment.
+ @retval FALSE It is not AML NameSegment.
+**/
+BOOLEAN
+AmlIsNameSeg (
+ IN UINT8 *Buffer
+ )
+{
+ UINTN Index;
+ if (!AmlIsLeadName (Buffer[0])) {
+ return FALSE;
+ }
+ for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
+ if (!AmlIsName (Buffer[Index])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Get AML NameString size.
+
+ @param[in] Buffer AML NameString.
+ @param[out] BufferSize AML NameString size
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
+**/
+EFI_STATUS
+AmlGetNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *BufferSize
+ )
+{
+ UINTN SegCount;
+ UINTN Length;
+ UINTN Index;
+
+ Length = 0;
+
+ //
+ // Parse root or parent prefix
+ //
+ if (*Buffer == AML_ROOT_CHAR) {
+ Buffer ++;
+ Length ++;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ do {
+ Buffer ++;
+ Length ++;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ //
+ // Parse name segment
+ //
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ Buffer ++;
+ Length ++;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ Buffer ++;
+ Length ++;
+ SegCount = *Buffer;
+ Buffer ++;
+ Length ++;
+ } else if (*Buffer == 0) {
+ //
+ // NULL Name, only for Root
+ //
+ SegCount = 0;
+ Buffer --;
+ if ((Length == 1) && (*Buffer == AML_ROOT_CHAR)) {
+ *BufferSize = 2;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // NameSeg
+ //
+ SegCount = 1;
+ }
+
+ Index = 0;
+ do {
+ if (!AmlIsNameSeg (Buffer)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Buffer += AML_NAME_SEG_SIZE;
+ Length += AML_NAME_SEG_SIZE;
+ Index ++;
+ } while (Index < SegCount);
+
+ *BufferSize = Length;
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if it is ASL LeadName.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is ASL LeadName.
+ @retval FALSE Char is not ASL LeadName.
+**/
+BOOLEAN
+AmlIsAslLeadName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsLeadName (Ch) || (Ch >= 'a' && Ch <= 'z')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is ASL Name.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is ASL Name.
+ @retval FALSE Char is not ASL Name.
+**/
+BOOLEAN
+AmlIsAslName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsAslLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get ASL NameString size.
+
+ @param[in] Buffer ASL NameString.
+
+ @return ASL NameString size.
+**/
+UINTN
+AmlGetAslNameSegLength (
+ IN UINT8 *Buffer
+ )
+{
+ UINTN Length;
+ UINTN Index;
+
+ if (*Buffer == 0) {
+ return 0;
+ }
+
+ Length = 0;
+ //
+ // 1st
+ //
+ if (AmlIsAslLeadName (*Buffer)) {
+ Length ++;
+ Buffer ++;
+ }
+ if ((*Buffer == 0) || (*Buffer == '.')) {
+ return Length;
+ }
+ //
+ // 2, 3, 4 name char
+ //
+ for (Index = 0; Index < 3; Index++) {
+ if (AmlIsAslName (*Buffer)) {
+ Length ++;
+ Buffer ++;
+ }
+ if ((*Buffer == 0) || (*Buffer == '.')) {
+ return Length;
+ }
+ }
+
+ //
+ // Invalid ASL name
+ //
+ return 0;
+}
+
+/**
+ Get ASL NameString size.
+
+ @param[in] Buffer ASL NameString.
+ @param[out] Root On return, points to Root char number.
+ @param[out] Parent On return, points to Parent char number.
+ @param[out] SegCount On return, points to Segment count.
+
+ @return ASL NameString size.
+**/
+UINTN
+AmlGetAslNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *Root,
+ OUT UINTN *Parent,
+ OUT UINTN *SegCount
+ )
+{
+ UINTN NameLength;
+ UINTN TotalLength;
+
+ *Root = 0;
+ *Parent = 0;
+ *SegCount = 0;
+ TotalLength = 0;
+ NameLength = 0;
+ if (*Buffer == AML_ROOT_CHAR) {
+ *Root = 1;
+ Buffer ++;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ do {
+ Buffer ++;
+ (*Parent) ++;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ //
+ // Now parse name
+ //
+ while (*Buffer != 0) {
+ NameLength = AmlGetAslNameSegLength (Buffer);
+ if ((NameLength == 0) || (NameLength > AML_NAME_SEG_SIZE)) {
+ return 0;
+ }
+ (*SegCount) ++;
+ Buffer += NameLength;
+ if (*Buffer == 0) {
+ break;
+ }
+ Buffer ++;
+ }
+
+ //
+ // Check SegCoount
+ //
+ if (*SegCount > 0xFF) {
+ return 0;
+ }
+
+ //
+ // Calculate total length
+ //
+ TotalLength = *Root + *Parent + (*SegCount) * AML_NAME_SEG_SIZE;
+ if (*SegCount > 2) {
+ TotalLength += 2;
+ } else if (*SegCount == 2) {
+ TotalLength += 1;
+ }
+
+ //
+ // Add NULL char
+ //
+ TotalLength ++;
+
+ return TotalLength;
+}
+
+/**
+ Copy mem, and cast all the char in dest to be upper case.
+
+ @param[in] DstBuffer Destination buffer.
+ @param[in] SrcBuffer Source buffer.
+ @param[in] Length Buffer length.
+**/
+VOID
+AmlUpperCaseCopyMem (
+ IN UINT8 *DstBuffer,
+ IN UINT8 *SrcBuffer,
+ IN UINTN Length
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Length; Index++) {
+ if (SrcBuffer[Index] >= 'a' && SrcBuffer[Index] <= 'z') {
+ DstBuffer[Index] = (UINT8)(SrcBuffer[Index] - 'a' + 'A');
+ } else {
+ DstBuffer[Index] = SrcBuffer[Index];
+ }
+ }
+}
+
+/**
+ Return AML name according to ASL name.
+ The caller need free the AmlName returned.
+
+ @param[in] AslPath ASL name.
+
+ @return AmlName
+**/
+UINT8 *
+AmlNameFromAslName (
+ IN UINT8 *AslPath
+ )
+{
+ UINTN Root;
+ UINTN Parent;
+ UINTN SegCount;
+ UINTN TotalLength;
+ UINTN NameLength;
+ UINT8 *Buffer;
+ UINT8 *AmlPath;
+ UINT8 *AmlBuffer;
+
+ TotalLength = AmlGetAslNameStringSize (AslPath, &Root, &Parent, &SegCount);
+ if (TotalLength == 0) {
+ return NULL;
+ }
+
+ AmlPath = AllocatePool (TotalLength);
+ ASSERT (AmlPath != NULL);
+
+ AmlBuffer = AmlPath;
+ Buffer = AslPath;
+
+ //
+ // Handle Root and Parent
+ //
+ if (Root == 1) {
+ *AmlBuffer = AML_ROOT_CHAR;
+ AmlBuffer ++;
+ Buffer ++;
+ } else if (Parent > 0) {
+ SetMem (AmlBuffer, Parent, AML_PARENT_PREFIX_CHAR);
+ AmlBuffer += Parent;
+ Buffer += Parent;
+ }
+
+ //
+ // Handle SegCount
+ //
+ if (SegCount > 2) {
+ *AmlBuffer = AML_MULTI_NAME_PREFIX;
+ AmlBuffer ++;
+ *AmlBuffer = (UINT8)SegCount;
+ AmlBuffer ++;
+ } else if (SegCount == 2) {
+ *AmlBuffer = AML_DUAL_NAME_PREFIX;
+ AmlBuffer ++;
+ }
+
+ //
+ // Now to name
+ //
+ while (*Buffer != 0) {
+ NameLength = AmlGetAslNameSegLength (Buffer);
+ ASSERT ((NameLength != 0) && (NameLength <= AML_NAME_SEG_SIZE));
+ AmlUpperCaseCopyMem (AmlBuffer, Buffer, NameLength);
+ SetMem (AmlBuffer + NameLength, AML_NAME_SEG_SIZE - NameLength, AML_NAME_CHAR__);
+ Buffer += NameLength;
+ AmlBuffer += AML_NAME_SEG_SIZE;
+ if (*Buffer == 0) {
+ break;
+ }
+ Buffer ++;
+ }
+
+ //
+ // Add NULL
+ //
+ AmlPath[TotalLength - 1] = 0;
+
+ return AmlPath;
+}
+
+/**
+ Print AML NameSeg.
+
+ @param[in] Buffer AML NameSeg.
+**/
+VOID
+AmlPrintNameSeg (
+ IN UINT8 *Buffer
+ )
+{
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[0]));
+ if ((Buffer[1] == '_') && (Buffer[2] == '_') && (Buffer[3] == '_')) {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[1]));
+ if ((Buffer[2] == '_') && (Buffer[3] == '_')) {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[2]));
+ if (Buffer[3] == '_') {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[3]));
+ return ;
+}
+
+/**
+ Print AML NameString.
+
+ @param[in] Buffer AML NameString.
+**/
+VOID
+AmlPrintNameString (
+ IN UINT8 *Buffer
+ )
+{
+ UINT8 SegCount;
+ UINT8 Index;
+
+ if (*Buffer == AML_ROOT_CHAR) {
+ //
+ // RootChar
+ //
+ Buffer ++;
+ DEBUG ((EFI_D_ERROR, "\\"));
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ //
+ // ParentPrefixChar
+ //
+ do {
+ Buffer ++;
+ DEBUG ((EFI_D_ERROR, "^"));
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ //
+ // DualName
+ //
+ Buffer ++;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ //
+ // MultiName
+ //
+ Buffer ++;
+ SegCount = *Buffer;
+ Buffer ++;
+ } else if (*Buffer == 0) {
+ //
+ // NULL Name
+ //
+ return ;
+ } else {
+ //
+ // NameSeg
+ //
+ SegCount = 1;
+ }
+
+ AmlPrintNameSeg (Buffer);
+ Buffer += AML_NAME_SEG_SIZE;
+ for (Index = 0; Index < SegCount - 1; Index++) {
+ DEBUG ((EFI_D_ERROR, "."));
+ AmlPrintNameSeg (Buffer);
+ Buffer += AML_NAME_SEG_SIZE;
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c
new file mode 100644
index 000000000..d16872e14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c
@@ -0,0 +1,602 @@
+/** @file
+ This module install ACPI Boot Graphics Resource Table (BGRT).
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016, Microsoft Corporation<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Acpi.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/BootLogo.h>
+#include <Protocol/BootLogo2.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/BmpSupportLib.h>
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param[in] This The pointer to the Boot Logo protocol 2 instance.
+ @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param[in] DestinationX X coordinate of destination for the BltBuffer.
+ @param[in] DestinationY Y coordinate of destination for the BltBuffer.
+ @param[in] Width Width of rectangle in BltBuffer in pixels.
+ @param[in] Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo (
+ IN EFI_BOOT_LOGO_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ );
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param[in] This The pointer to the Boot Logo protocol 2 instance.
+ @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param[in] DestinationX X coordinate of destination for the BltBuffer.
+ @param[in] DestinationY Y coordinate of destination for the BltBuffer.
+ @param[in] Width Width of rectangle in BltBuffer in pixels.
+ @param[in] Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo2 (
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ );
+
+/**
+ Get the location of the boot logo on the screen.
+
+ @param[in] This The pointer to the Boot Logo Protocol 2 instance
+ @param[out] BltBuffer Returns pointer to the GOP BLT buffer that was
+ previously registered with SetBootLogo2(). The
+ buffer returned must not be modified or freed.
+ @param[out] DestinationX Returns the X start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] DestinationY Returns the Y start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Width Returns the width of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Height Returns the height of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+
+ @retval EFI_SUCCESS The location of the boot logo was returned.
+ @retval EFI_NOT_READY The boot logo has not been set.
+ @retval EFI_INVALID_PARAMETER BltBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationX is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationY is NULL.
+ @retval EFI_INVALID_PARAMETER Width is NULL.
+ @retval EFI_INVALID_PARAMETER Height is NULL.
+**/
+EFI_STATUS
+EFIAPI
+GetBootLogo2 (
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
+ OUT UINTN *DestinationX,
+ OUT UINTN *DestinationY,
+ OUT UINTN *Width,
+ OUT UINTN *Height
+ );
+
+//
+// Boot Logo Protocol Handle
+//
+EFI_HANDLE mBootLogoHandle = NULL;
+
+//
+// Boot Logo Protocol Instance
+//
+EFI_BOOT_LOGO_PROTOCOL mBootLogoProtocolTemplate = {
+ SetBootLogo
+};
+
+///
+/// Boot Logo 2 Protocol instance
+///
+EDKII_BOOT_LOGO2_PROTOCOL mBootLogo2ProtocolTemplate = {
+ SetBootLogo2,
+ GetBootLogo2
+};
+
+EFI_EVENT mBootGraphicsReadyToBootEvent;
+UINTN mBootGraphicsResourceTableKey = 0;
+BOOLEAN mIsLogoValid = FALSE;
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mLogoBltBuffer = NULL;
+UINTN mLogoDestX = 0;
+UINTN mLogoDestY = 0;
+UINTN mLogoWidth = 0;
+UINTN mLogoHeight = 0;
+BOOLEAN mAcpiBgrtInstalled = FALSE;
+BOOLEAN mAcpiBgrtStatusChanged = FALSE;
+BOOLEAN mAcpiBgrtBufferChanged = FALSE;
+
+//
+// ACPI Boot Graphics Resource Table template
+//
+EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = {
+ {
+ EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE,
+ sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
+ EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION, // Revision
+ 0x00, // Checksum will be updated at runtime
+ //
+ // It is expected that these values will be updated at EntryPoint.
+ //
+ {0x00}, // OEM ID is a 6 bytes long field
+ 0x00, // OEM Table ID(8 bytes long)
+ 0x00, // OEM Revision
+ 0x00, // Creator ID
+ 0x00, // Creator Revision
+ },
+ EFI_ACPI_5_0_BGRT_VERSION, // Version
+ EFI_ACPI_5_0_BGRT_STATUS_VALID, // Status
+ EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP, // Image Type
+ 0, // Image Address
+ 0, // Image Offset X
+ 0 // Image Offset Y
+};
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param This The pointer to the Boot Logo protocol instance.
+ @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo (
+ IN EFI_BOOT_LOGO_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ //
+ // Call same service in Boot Logo 2 Protocol
+ //
+ return SetBootLogo2 (
+ &mBootLogo2ProtocolTemplate,
+ BltBuffer,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height
+ );
+}
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param[in] This The pointer to the Boot Logo protocol 2 instance.
+ @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param[in] DestinationX X coordinate of destination for the BltBuffer.
+ @param[in] DestinationY Y coordinate of destination for the BltBuffer.
+ @param[in] Width Width of rectangle in BltBuffer in pixels.
+ @param[in] Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo2 (
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT32 Result32;
+
+ if (BltBuffer == NULL) {
+ mIsLogoValid = FALSE;
+ mAcpiBgrtStatusChanged = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Width and height are not allowed to be zero.
+ //
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Verify destination, width, and height do not overflow 32-bit values.
+ // The Boot Graphics Resource Table only has 32-bit fields for these values.
+ //
+ Status = SafeUintnToUint32 (DestinationX, &Result32);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = SafeUintnToUint32 (DestinationY, &Result32);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = SafeUintnToUint32 (Width, &Result32);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = SafeUintnToUint32 (Height, &Result32);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Ensure the Height * Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) does
+ // not overflow UINTN
+ //
+ Status = SafeUintnMult (
+ Width,
+ Height,
+ &BufferSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ Status = SafeUintnMult (
+ BufferSize,
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
+ &BufferSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update state
+ //
+ mAcpiBgrtBufferChanged = TRUE;
+
+ //
+ // Free old logo buffer
+ //
+ if (mLogoBltBuffer != NULL) {
+ FreePool (mLogoBltBuffer);
+ mLogoBltBuffer = NULL;
+ }
+
+ //
+ // Allocate new logo buffer
+ //
+ mLogoBltBuffer = AllocateCopyPool (BufferSize, BltBuffer);
+ if (mLogoBltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mLogoDestX = DestinationX;
+ mLogoDestY = DestinationY;
+ mLogoWidth = Width;
+ mLogoHeight = Height;
+ mIsLogoValid = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the location of the boot logo on the screen.
+
+ @param[in] This The pointer to the Boot Logo Protocol 2 instance
+ @param[out] BltBuffer Returns pointer to the GOP BLT buffer that was
+ previously registered with SetBootLogo2(). The
+ buffer returned must not be modified or freed.
+ @param[out] DestinationX Returns the X start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] DestinationY Returns the Y start position of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Width Returns the width of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+ @param[out] Height Returns the height of the GOP BLT buffer
+ that was previously registered with SetBootLogo2().
+
+ @retval EFI_SUCCESS The location of the boot logo was returned.
+ @retval EFI_NOT_READY The boot logo has not been set.
+ @retval EFI_INVALID_PARAMETER BltBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationX is NULL.
+ @retval EFI_INVALID_PARAMETER DestinationY is NULL.
+ @retval EFI_INVALID_PARAMETER Width is NULL.
+ @retval EFI_INVALID_PARAMETER Height is NULL.
+**/
+EFI_STATUS
+EFIAPI
+GetBootLogo2 (
+ IN EDKII_BOOT_LOGO2_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer,
+ OUT UINTN *DestinationX,
+ OUT UINTN *DestinationY,
+ OUT UINTN *Width,
+ OUT UINTN *Height
+ )
+{
+ //
+ // If the boot logo has not been set with SetBootLogo() or SetBootLogo() was
+ // called with a NULL BltBuffer then the boot logo is not valid and
+ // EFI_NOT_READY is returned.
+ //
+ if (mLogoBltBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Request to get boot logo location before boot logo has been set.\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Make sure none of the boot logo location parameters are NULL.
+ //
+ if (BltBuffer == NULL || DestinationX == NULL || DestinationY == NULL ||
+ Width == NULL || Height == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Boot logo is valid. Return values from module globals.
+ //
+ *BltBuffer = mLogoBltBuffer;
+ *DestinationX = mLogoDestX;
+ *DestinationY = mLogoDestY;
+ *Width = mLogoWidth;
+ *Height = mLogoHeight;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ install the Boot Graphics Resource Table.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+BgrtReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ VOID *ImageBuffer;
+ UINT32 BmpSize;
+
+ //
+ // Get ACPI Table protocol.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **) &AcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Check whether Boot Graphics Resource Table is already installed.
+ //
+ if (mAcpiBgrtInstalled) {
+ if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) {
+ //
+ // Nothing has changed
+ //
+ return;
+ } else {
+ //
+ // If BGRT data change happens, then uninstall orignal AcpiTable first
+ //
+ Status = AcpiTableProtocol->UninstallAcpiTable (
+ AcpiTableProtocol,
+ mBootGraphicsResourceTableKey
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+ } else {
+ //
+ // Check whether Logo exists
+ //
+ if (mLogoBltBuffer == NULL) {
+ return;
+ }
+ }
+
+ if (mAcpiBgrtBufferChanged) {
+ //
+ // Free the old BMP image buffer
+ //
+ ImageBuffer = (UINT8 *)(UINTN)mBootGraphicsResourceTableTemplate.ImageAddress;
+ if (ImageBuffer != NULL) {
+ FreePool (ImageBuffer);
+ }
+
+ //
+ // Convert GOP Blt buffer to BMP image. Pass in ImageBuffer set to NULL
+ // so the BMP image is allocated by TranslateGopBltToBmp().
+ //
+ ImageBuffer = NULL;
+ Status = TranslateGopBltToBmp (
+ mLogoBltBuffer,
+ (UINT32)mLogoHeight,
+ (UINT32)mLogoWidth,
+ &ImageBuffer,
+ &BmpSize
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Free the logo buffer
+ //
+ FreePool (mLogoBltBuffer);
+ mLogoBltBuffer = NULL;
+
+ //
+ // Update BMP image fields of the Boot Graphics Resource Table
+ //
+ mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64)(UINTN)ImageBuffer;
+ mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32)mLogoDestX;
+ mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32)mLogoDestY;
+ }
+
+ //
+ // Update Status field of Boot Graphics Resource Table
+ //
+ if (mIsLogoValid) {
+ mBootGraphicsResourceTableTemplate.Status = EFI_ACPI_5_0_BGRT_STATUS_VALID;
+ } else {
+ mBootGraphicsResourceTableTemplate.Status = EFI_ACPI_5_0_BGRT_STATUS_INVALID;
+ }
+
+ //
+ // Update Checksum of Boot Graphics Resource Table
+ //
+ mBootGraphicsResourceTableTemplate.Header.Checksum = 0;
+ mBootGraphicsResourceTableTemplate.Header.Checksum =
+ CalculateCheckSum8 (
+ (UINT8 *)&mBootGraphicsResourceTableTemplate,
+ sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE)
+ );
+
+ //
+ // Publish Boot Graphics Resource Table.
+ //
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ &mBootGraphicsResourceTableTemplate,
+ sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
+ &mBootGraphicsResourceTableKey
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ mAcpiBgrtInstalled = TRUE;
+ mAcpiBgrtStatusChanged = FALSE;
+ mAcpiBgrtBufferChanged = FALSE;
+}
+
+/**
+ The module Entry Point of the Boot Graphics Resource Table DXE 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
+BootGraphicsDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Header;
+
+ //
+ // Update Header fields of Boot Graphics Resource Table from PCDs
+ //
+ Header = &mBootGraphicsResourceTableTemplate.Header;
+ ZeroMem (Header->OemId, sizeof (Header->OemId));
+ CopyMem (
+ Header->OemId,
+ PcdGetPtr (PcdAcpiDefaultOemId),
+ MIN (PcdGetSize (PcdAcpiDefaultOemId), sizeof (Header->OemId))
+ );
+ WriteUnaligned64 (&Header->OemTableId, PcdGet64 (PcdAcpiDefaultOemTableId));
+ Header->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ Header->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ Header->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Install Boot Logo and Boot Logo 2 Protocols.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mBootLogoHandle,
+ &gEfiBootLogoProtocolGuid,
+ &mBootLogoProtocolTemplate,
+ &gEdkiiBootLogo2ProtocolGuid,
+ &mBootLogo2ProtocolTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function to install BGRT on ReadyToBoot Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ BgrtReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mBootGraphicsReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
new file mode 100644
index 000000000..911092fc9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# This module install ACPI Boot Graphics Resource Table (BGRT).
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Microsoft Corporation<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootGraphicsResourceTableDxe
+ MODULE_UNI_FILE = BootGraphicsResourceTableDxe.uni
+ FILE_GUID = B8E62775-BB0A-43f0-A843-5BE8B14F8CCD
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BootGraphicsDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootGraphicsResourceTableDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ DebugLib
+ PcdLib
+ SafeIntLib
+ BmpSupportLib
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gEfiBootLogoProtocolGuid ## PRODUCES
+ gEdkiiBootLogo2ProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[Guids]
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootGraphicsResourceTableDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni
new file mode 100644
index 000000000..0a94edae4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This module install ACPI Boot Graphics Resource Table (BGRT).
+//
+// This module installs the ACPI Boot Graphics Resource Table (BGRT).
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs ACPI Boot Graphics Resource Table (BGRT)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs the ACPI Boot Graphics Resource Table (BGRT)."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni
new file mode 100644
index 000000000..e4956d4a0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// BootGraphicsResourceTableDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Boot Graphics Resource Table DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
new file mode 100644
index 000000000..fb149c2f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
@@ -0,0 +1,86 @@
+## @file
+# Boot Script Executor Module
+#
+# This is a standalone Boot Script Executor. Standalone means it does not
+# depends on any PEI or DXE service.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootScriptExecutorDxe
+ MODULE_UNI_FILE = BootScriptExecutorDxe.uni
+ FILE_GUID = FA20568B-548B-4b2b-81EF-1BA08D4A3CEC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BootScriptExecutorEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ScriptExecute.h
+ ScriptExecute.c
+
+[Sources.X64]
+ X64/SetIdtEntry.c
+ X64/S3Asm.nasm
+
+[Sources.Ia32]
+ IA32/SetIdtEntry.c
+ IA32/S3Asm.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ BaseLib
+ S3BootScriptLib
+ PeCoffLib
+ DxeServicesLib
+ UefiBootServicesTableLib
+ CacheMaintenanceLib
+ UefiLib
+ DebugAgentLib
+ LockBoxLib
+ CpuExceptionHandlerLib
+ DevicePathLib
+ DxeServicesTableLib
+
+[Guids]
+ gEfiBootScriptExecutorVariableGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+ gEfiBootScriptExecutorContextGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+ gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+
+[Protocols]
+ ## NOTIFY
+ ## CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
+
+[Depex]
+ gEfiLockBoxProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootScriptExecutorDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni
new file mode 100644
index 000000000..44aaf1e4c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Boot Script Executor Module
+//
+// This is a standalone Boot Script Executor. Standalone means it does not
+// depends on any PEI or DXE service.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Boot Script Executor Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is a standalone Boot Script Executor. Standalone means it does not depends on any PEI or DXE service."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni
new file mode 100644
index 000000000..05b472b44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// BootScriptExecutorDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Script Execution DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm
new file mode 100644
index 000000000..e121cc937
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm
@@ -0,0 +1,62 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for IA32 platform
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;;
+ SECTION .text
+
+global ASM_PFX(AsmFixAddress16)
+global ASM_PFX(AsmJmpAddr32)
+
+;-----------------------------------------
+;VOID
+;AsmTransferControl (
+; IN UINT32 S3WakingVector,
+; IN UINT32 AcpiLowMemoryBase
+; );
+;-----------------------------------------
+
+global ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ lea eax, [.0]
+ push 0x28 ; CS
+ push eax
+ mov ecx, [ebp + 8]
+ shrd ebx, ecx, 20
+ and ecx, 0xf
+ mov bx, cx
+ mov [@jmp_addr + 1], ebx
+ retf
+
+BITS 16
+.0:
+ mov ax, 0x30
+o32 mov ds, eax
+o32 mov es, eax
+o32 mov fs, eax
+o32 mov gs, eax
+o32 mov ss, eax
+ mov eax, cr0 ; Get control register 0
+ and eax, 0x0fffffffe ; Clear PE bit (bit #0)
+ mov cr0, eax ; Activate real mode
+@jmp_addr:
+ jmp 0x0:0x0
+
+global ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+ jmp ASM_PFX(AsmTransferControl)
+
+; dummy
+global ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+ASM_PFX(AsmFixAddress16): DD 0
+ASM_PFX(AsmJmpAddr32): DD 0
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c
new file mode 100644
index 000000000..1e3c5b849
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c
@@ -0,0 +1,56 @@
+/** @file
+ Set a IDT entry for debug purpose
+
+ Set a IDT entry for interrupt vector 3 for debug purpose for IA32 platform
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "ScriptExecute.h"
+
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR *IdtDescriptor;
+ UINTN S3DebugBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Restore IDT for debug
+ //
+ IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
+ AsmWriteIdtr (IdtDescriptor);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ //
+ // Update IDT entry INT3 if the instruction is valid in it
+ //
+ S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
+ if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
+ }
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
new file mode 100644
index 000000000..b2ae9ec3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
@@ -0,0 +1,497 @@
+/** @file
+ This is the code for Boot Script Executer module.
+
+ This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory
+ in the entry point. The functionality is to interpret and restore the S3 boot script
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ScriptExecute.h"
+
+EFI_GUID mBootScriptExecutorImageGuid = {
+ 0x9a8d3433, 0x9fe8, 0x42b6, { 0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b }
+};
+
+BOOLEAN mPage1GSupport = FALSE;
+UINT64 mAddressEncMask = 0;
+
+/**
+ Entry function of Boot script exector. This function will be executed in
+ S3 boot path.
+ This function should not return, because it is invoked by switch stack.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+ @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE
+
+ @retval EFI_INVALID_PARAMETER - OS waking vector not found
+ @retval EFI_UNSUPPORTED - something wrong when we resume to OS
+**/
+EFI_STATUS
+EFIAPI
+S3BootScriptExecutorEntryFunction (
+ IN ACPI_S3_CONTEXT *AcpiS3Context,
+ IN PEI_S3_RESUME_STATE *PeiS3ResumeState
+ )
+{
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ EFI_STATUS Status;
+ UINTN TempStackTop;
+ UINTN TempStack[0x10];
+ UINTN AsmTransferControl16Address;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ //
+ // Disable interrupt of Debug timer, since new IDT table cannot handle it.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ AsmReadIdtr (&IdtDescriptor);
+ //
+ // Restore IDT for debug
+ //
+ SetIdtEntry (AcpiS3Context);
+
+ //
+ // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer.
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL);
+
+ //
+ // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
+ // for that parameter.
+ //
+ Status = S3BootScriptExecute ();
+
+ //
+ // If invalid script table or opcode in S3 boot script table.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ CpuDeadLoop ();
+ return Status;
+ }
+
+ AsmWbinvd ();
+
+ //
+ // Get ACPI Table Address
+ //
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+
+ //
+ // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
+ //
+ if (PeiS3ResumeState != 0) {
+ //
+ // Need report status back to S3ResumePeim.
+ // If boot script execution is failed, S3ResumePeim wil report the error status code.
+ //
+ PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ //
+ // X64 S3 Resume
+ //
+ DEBUG ((DEBUG_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
+ PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32;
+
+ if ((Facs != NULL) &&
+ (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) &&
+ (Facs->FirmwareWakingVector != 0) ) {
+ //
+ // more step needed - because relative address is handled differently between X64 and IA32.
+ //
+ AsmTransferControl16Address = (UINTN)AsmTransferControl16;
+ AsmFixAddress16 = (UINT32)AsmTransferControl16Address;
+ AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12));
+ }
+
+ AsmDisablePaging64 (
+ PeiS3ResumeState->ReturnCs,
+ (UINT32)PeiS3ResumeState->ReturnEntryPoint,
+ (UINT32)(UINTN)AcpiS3Context,
+ (UINT32)(UINTN)PeiS3ResumeState,
+ (UINT32)PeiS3ResumeState->ReturnStackPointer
+ );
+ } else {
+ //
+ // IA32 S3 Resume
+ //
+ DEBUG ((DEBUG_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
+ PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl;
+
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
+ (VOID *)(UINTN)AcpiS3Context,
+ (VOID *)(UINTN)PeiS3ResumeState,
+ (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
+ );
+ }
+
+ //
+ // Never run to here
+ //
+ CpuDeadLoop();
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly
+ //
+ if (Facs->XFirmwareWakingVector != 0) {
+ //
+ // Switch to native waking vector
+ //
+ TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
+ ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+ //
+ // X64 long mode waking vector
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+ NULL,
+ NULL,
+ (VOID *)(UINTN)TempStackTop
+ );
+ } else {
+ // Unsupported for 32bit DXE, 64bit OS vector
+ DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ //
+ // IA32 protected mode waking vector (Page disabled)
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ AsmDisablePaging64 (
+ 0x10,
+ (UINT32)Facs->XFirmwareWakingVector,
+ 0,
+ 0,
+ (UINT32)TempStackTop
+ );
+ } else {
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+ NULL,
+ NULL,
+ (VOID *)(UINTN)TempStackTop
+ );
+ }
+ }
+ } else {
+ //
+ // 16bit Realmode waking vector
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
+ AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
+ }
+
+ //
+ // Never run to here
+ //
+ CpuDeadLoop();
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Register image to memory profile.
+
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param FileType File type of the image.
+
+**/
+VOID
+RegisterMemoryProfileImage (
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) {
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
+ if (!EFI_ERROR (Status)) {
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ Status = ProfileProtocol->RegisterImage (
+ ProfileProtocol,
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
+ ImageBase,
+ ImageSize,
+ FileType
+ );
+ }
+ }
+}
+
+/**
+ This is the Event notification function to reload BootScriptExecutor image
+ to RESERVED mem and save it to LockBox.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+ **/
+VOID
+EFIAPI
+ReadyToLockEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ EFI_HANDLE NewImageHandle;
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS FfsBuffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
+
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // A workaround: Here we install a dummy handle
+ //
+ NewImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Reload BootScriptExecutor image itself to RESERVED mem
+ //
+ Status = GetSectionFromAnyFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_PE32,
+ 0,
+ (VOID **) &Buffer,
+ &BufferSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ ImageContext.Handle = Buffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
+ } else {
+ Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
+ }
+ FfsBuffer = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ Pages,
+ &FfsBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure that the buffer can be used to store code.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (FfsBuffer, &MemDesc);
+ if (!EFI_ERROR (Status) && (MemDesc.Attributes & EFI_MEMORY_XP) != 0) {
+ gDS->SetMemorySpaceAttributes (
+ FfsBuffer,
+ EFI_PAGES_TO_SIZE (Pages),
+ MemDesc.Attributes & (~EFI_MEMORY_XP)
+ );
+ }
+
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
+ //
+ gBS->FreePool (Buffer);
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ RegisterMemoryProfileImage (
+ &gEfiCallerIdGuid,
+ ImageContext.ImageAddress,
+ ImageContext.ImageSize,
+ EFI_FV_FILETYPE_DRIVER
+ );
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Additional step for BootScript integrity
+ // Save BootScriptExecutor image
+ //
+ Status = SaveLockBox (
+ &mBootScriptExecutorImageGuid,
+ (VOID *)(UINTN)ImageContext.ImageAddress,
+ (UINTN)ImageContext.ImageSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Entrypoint of Boot script exector driver, this function will be executed in
+ normal boot phase and invoked by DXE dispatch.
+
+ @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
+BootScriptExecutorEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN BufferSize;
+ UINTN Pages;
+ BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;
+ EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer;
+ EFI_STATUS Status;
+ VOID *DevicePath;
+ EFI_EVENT ReadyToLockEvent;
+ VOID *Registration;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field.
+ //
+ mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ //
+ // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
+ // point is loaded by DXE code which is the first time loaded. or else, it is already
+ // be reloaded be itself.This is a work-around
+ //
+ Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // Create ReadyToLock event to reload BootScriptExecutor image
+ // to RESERVED mem and save it to LockBox.
+ //
+ ReadyToLockEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ ReadyToLockEventNotify,
+ NULL,
+ &Registration
+ );
+ ASSERT (ReadyToLockEvent != NULL);
+ } else {
+ //
+ // the entry point is invoked after reloading. following code only run in RESERVED mem
+ //
+ if (PcdGetBool(PcdUse1GPageTable)) {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ mPage1GSupport = TRUE;
+ }
+ }
+ }
+
+ BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);
+
+ BootScriptExecutorBuffer = 0xFFFFFFFF;
+ Pages = EFI_SIZE_TO_PAGES(BufferSize);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ Pages,
+ &BootScriptExecutorBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;
+ EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;
+
+ Status = SaveLockBox (
+ &gEfiBootScriptExecutorVariableGuid,
+ &BootScriptExecutorBuffer,
+ sizeof(BootScriptExecutorBuffer)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Additional step for BootScript integrity
+ // Save BootScriptExecutor context
+ //
+ Status = SaveLockBox (
+ &gEfiBootScriptExecutorContextGuid,
+ EfiBootScriptExecutorVariable,
+ sizeof(*EfiBootScriptExecutorVariable)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h
new file mode 100644
index 000000000..14bb63f60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h
@@ -0,0 +1,91 @@
+/** @file
+ The header file for Boot Script Executer module.
+
+ This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory
+ in the entry point. The functionality is to interpret and restore the S3 boot script
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _BOOT_SCRIPT_EXECUTOR_H_
+#define _BOOT_SCRIPT_EXECUTOR_H_
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+
+#include <Guid/AcpiS3Context.h>
+#include <Guid/BootScriptExecutorVariable.h>
+#include <Guid/MemoryProfile.h>
+
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <IndustryStandard/Acpi.h>
+
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+/**
+ a ASM function to transfer control to OS.
+
+ @param S3WakingVector The S3 waking up vector saved in ACPI Facs table
+ @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer
+**/
+VOID
+AsmTransferControl (
+ IN UINT32 S3WakingVector,
+ IN UINT32 AcpiLowMemoryBase
+ );
+/**
+ a 32bit ASM function to transfer control to OS.
+
+ @param S3WakingVector The S3 waking up vector saved in ACPI Facs table
+ @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer
+**/
+VOID
+AsmTransferControl32 (
+ IN UINT32 S3WakingVector,
+ IN UINT32 AcpiLowMemoryBase
+ );
+/**
+ a 16bit ASM function to transfer control to OS.
+**/
+VOID
+AsmTransferControl16 (
+ VOID
+ );
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ );
+
+extern UINT32 AsmFixAddress16;
+extern UINT32 AsmJmpAddr32;
+extern BOOLEAN mPage1GSupport;
+extern UINT64 mAddressEncMask;
+
+#endif //_BOOT_SCRIPT_EXECUTOR_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
new file mode 100644
index 000000000..713fd7b2e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
@@ -0,0 +1,130 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for X64 platform
+;
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;;
+
+extern ASM_PFX(mOriginalHandler)
+extern ASM_PFX(PageFaultHandler)
+
+ DEFAULT REL
+ SECTION .text
+
+global ASM_PFX(AsmFixAddress16)
+global ASM_PFX(AsmJmpAddr32)
+
+global ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ ; rcx S3WakingVector :DWORD
+ ; rdx AcpiLowMemoryBase :DWORD
+ lea eax, [.0]
+ mov r8, 0x2800000000
+ or rax, r8
+ push rax
+ shrd ebx, ecx, 20
+ and ecx, 0xf
+ mov bx, cx
+ mov [@jmp_addr + 1], ebx
+ retf
+BITS 16
+.0:
+ mov ax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov eax, cr0
+ mov ebx, cr4
+ and eax, ((~ 0x80000001) & 0xffffffff)
+ and bl, ~ (1 << 5)
+ mov cr0, eax
+ mov ecx, 0xc0000080
+ rdmsr
+ and ah, ~ 1
+ wrmsr
+ mov cr4, ebx
+@jmp_addr:
+ jmp 0x0:0x0
+
+global ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+BITS 32
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ DB 0x8d, 0x5 ; lea eax, AsmTransferControl16
+ASM_PFX(AsmFixAddress16): DD 0
+ push 0x28 ; CS
+ push eax
+ retf
+
+global ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+BITS 16
+ mov ax, 0x30
+o32 mov ds, eax
+o32 mov es, eax
+o32 mov fs, eax
+o32 mov gs, eax
+o32 mov ss, eax
+ mov eax, cr0 ; Get control register 0
+ and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ mov cr0, eax ; Activate real mode
+ DB 0xea ; jmp far AsmJmpAddr32
+ASM_PFX(AsmJmpAddr32): DD 0
+
+global ASM_PFX(PageFaultHandlerHook)
+ASM_PFX(PageFaultHandlerHook):
+BITS 64
+ push rax ; save all volatile registers
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ ; save volatile fp registers
+ add rsp, -0x68
+ stmxcsr [rsp + 0x60]
+ movdqa [rsp + 0x0], xmm0
+ movdqa [rsp + 0x10], xmm1
+ movdqa [rsp + 0x20], xmm2
+ movdqa [rsp + 0x30], xmm3
+ movdqa [rsp + 0x40], xmm4
+ movdqa [rsp + 0x50], xmm5
+
+ add rsp, -0x20
+ call ASM_PFX(PageFaultHandler)
+ add rsp, 0x20
+
+ ; load volatile fp registers
+ ldmxcsr [rsp + 0x60]
+ movdqa xmm0, [rsp + 0x0]
+ movdqa xmm1, [rsp + 0x10]
+ movdqa xmm2, [rsp + 0x20]
+ movdqa xmm3, [rsp + 0x30]
+ movdqa xmm4, [rsp + 0x40]
+ movdqa xmm5, [rsp + 0x50]
+ add rsp, 0x68
+
+ test al, al
+
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax ; restore all volatile registers
+ jnz .1
+ jmp qword [ASM_PFX(mOriginalHandler)]
+.1:
+ add rsp, 0x8 ; skip error code for PF
+ iretq
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
new file mode 100644
index 000000000..0d448cc60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
@@ -0,0 +1,261 @@
+/** @file
+ Set a IDT entry for debug purpose
+
+ Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "ScriptExecute.h"
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+UINT64 mPhyMask;
+VOID *mOriginalHandler;
+UINTN mPageFaultBuffer;
+UINTN mPageFaultIndex = 0;
+//
+// Store the uplink information for each page being used.
+//
+UINT64 *mPageFaultUplink[EXTRA_PAGE_TABLE_PAGES];
+
+/**
+ Page fault handler.
+
+**/
+VOID
+EFIAPI
+PageFaultHandlerHook (
+ VOID
+ );
+
+/**
+ Hook IDT with our page fault handler so that the on-demand paging works on page fault.
+
+ @param IdtEntry a pointer to IDT entry
+
+**/
+VOID
+HookPageFaultHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+ UINTN PageFaultHandlerHookAddress;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
+ mPhyMask &= (1ull << 48) - SIZE_4KB;
+
+ //
+ // Set Page Fault entry to catch >4G access
+ //
+ PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
+ mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
+ IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+
+ if (mPage1GSupport) {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
+ }else {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
+ }
+ ZeroMem (mPageFaultUplink, sizeof (mPageFaultUplink));
+}
+
+/**
+ The function will check if current waking vector is long mode.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+ @retval TRUE Current context need long mode waking vector.
+ @retval FALSE Current context need not long mode waking vector.
+**/
+BOOLEAN
+IsLongModeWakingVector (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+ if ((Facs == NULL) ||
+ (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
+ // 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) &&
+ ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+ // Both BIOS and OS wants 64bit vector
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR *IdtDescriptor;
+ UINTN S3DebugBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Restore IDT for debug
+ //
+ IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
+ AsmWriteIdtr (IdtDescriptor);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ //
+ // Update IDT entry INT3 if the instruction is valid in it
+ //
+ S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
+ if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+ }
+ );
+
+ //
+ // If both BIOS and OS wants long mode waking vector,
+ // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,
+ // no need to hook page fault handler.
+ //
+ if (!IsLongModeWakingVector (AcpiS3Context)) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ HookPageFaultHandler (IdtEntry);
+ }
+}
+
+/**
+ Acquire page for page fault.
+
+ @param[in, out] Uplink Pointer to up page table entry.
+
+**/
+VOID
+AcquirePage (
+ IN OUT UINT64 *Uplink
+ )
+{
+ UINTN Address;
+
+ Address = mPageFaultBuffer + EFI_PAGES_TO_SIZE (mPageFaultIndex);
+ ZeroMem ((VOID *) Address, EFI_PAGES_TO_SIZE (1));
+
+ //
+ // Cut the previous uplink if it exists and wasn't overwritten.
+ //
+ if ((mPageFaultUplink[mPageFaultIndex] != NULL) &&
+ ((*mPageFaultUplink[mPageFaultIndex] & ~mAddressEncMask & mPhyMask) == Address)) {
+ *mPageFaultUplink[mPageFaultIndex] = 0;
+ }
+
+ //
+ // Link & Record the current uplink.
+ //
+ *Uplink = Address | mAddressEncMask | IA32_PG_P | IA32_PG_RW;
+ mPageFaultUplink[mPageFaultIndex] = Uplink;
+
+ mPageFaultIndex = (mPageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;
+}
+
+/**
+ The page fault handler that on-demand read >4G memory/MMIO.
+
+ @retval TRUE The page fault is correctly handled.
+ @retval FALSE The page fault is not handled and is passed through to original handler.
+
+**/
+BOOLEAN
+EFIAPI
+PageFaultHandler (
+ VOID
+ )
+{
+ UINT64 *PageTable;
+ UINT64 PFAddress;
+ UINTN PTIndex;
+
+ PFAddress = AsmReadCr2 ();
+ DEBUG ((DEBUG_INFO, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
+
+ if (PFAddress >= mPhyMask + SIZE_4KB) {
+ return FALSE;
+ }
+ PFAddress &= mPhyMask;
+
+ PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
+
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ // PML4E
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ // PDPTE
+ if (mPage1GSupport) {
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ } else {
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ // PD
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ }
+
+ return TRUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
new file mode 100644
index 000000000..61a7704b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
@@ -0,0 +1,677 @@
+/** @file
+ This module install ACPI Firmware Performance Data Table (FPDT).
+
+ This module register report status code listener to collect performance data
+ for Firmware Basic Boot Performance Record and other boot performance records,
+ and install FPDT to ACPI table.
+
+ Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/ReportStatusCodeHandler.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/LockBox.h>
+#include <Protocol/Variable.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/FirmwarePerformance.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/UefiLib.h>
+
+#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
+
+EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+
+BOOLEAN mLockBoxReady = FALSE;
+EFI_EVENT mReadyToBootEvent;
+EFI_EVENT mLegacyBootEvent;
+static EFI_EVENT mExitBootServicesEvent;
+UINTN mFirmwarePerformanceTableTemplateKey = 0;
+BOOLEAN mDxeCoreReportStatusCodeEnable = FALSE;
+
+BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;
+BOOT_PERFORMANCE_TABLE *mReceivedAcpiBootPerformanceTable = NULL;
+S3_PERFORMANCE_TABLE *mAcpiS3PerformanceTable = NULL;
+
+FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE,
+ sizeof (FIRMWARE_PERFORMANCE_TABLE),
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION, // Revision
+ 0x00, // Checksum will be updated at runtime
+ //
+ // It is expected that these values will be updated at EntryPoint.
+ //
+ {0x00}, // OEM ID is a 6 bytes long field
+ 0x00, // OEM Table ID(8 bytes long)
+ 0x00, // OEM Revision
+ 0x00, // Creator ID
+ 0x00, // Creator Revision
+ },
+ //
+ // Firmware Basic Boot Performance Table Pointer Record.
+ //
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER , // Type
+ sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER // Revision
+ },
+ 0, // Reserved
+ 0 // BootPerformanceTablePointer will be updated at runtime.
+ },
+ //
+ // S3 Performance Table Pointer Record.
+ //
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER // Revision
+ },
+ 0, // Reserved
+ 0 // S3PerformanceTablePointer will be updated at runtime.
+ }
+};
+
+BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
+ sizeof (BOOT_PERFORMANCE_TABLE)
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
+ },
+ 0, // Reserved
+ //
+ // These values will be updated at runtime.
+ //
+ 0, // ResetEnd
+ 0, // OsLoaderLoadImageStart
+ 0, // OsLoaderStartImageStart
+ 0, // ExitBootServicesEntry
+ 0 // ExitBootServicesExit
+ }
+};
+
+S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE,
+ sizeof (S3_PERFORMANCE_TABLE)
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME // Revision
+ },
+ //
+ // These values will be updated by Firmware Performance PEIM.
+ //
+ 0, // ResumeCount
+ 0, // FullResume
+ 0 // AverageResume
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND // Revision
+ },
+ //
+ // These values will be updated bye Firmware Performance SMM driver.
+ //
+ 0, // SuspendStart
+ 0 // SuspendEnd
+ }
+};
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param[in] Buffer Pointer to buffer to checksum
+ @param[in] Size Number of bytes to checksum
+
+**/
+VOID
+FpdtAcpiTableChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
+
+ //
+ // Set checksum to 0 first.
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value.
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
+}
+
+/**
+ Callback function upon VariableArchProtocol and LockBoxProtocol
+ to allocate S3 performance table memory and save the pointer to LockBox.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+FpdtAllocateS3PerformanceTableMemory (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;
+
+ if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
+ //
+ // The memory for S3 performance table should have been ready,
+ // and the pointer should have been saved to LockBox, just return.
+ //
+ return;
+ }
+
+ if (!mLockBoxReady) {
+ Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // LockBox services has been ready.
+ //
+ mLockBoxReady = TRUE;
+ }
+ }
+
+ if (mAcpiS3PerformanceTable == NULL) {
+ Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to allocate the same runtime buffer as last time boot.
+ //
+ ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
+ Size = sizeof (PerformanceVariable);
+ Status = gRT->GetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &Size,
+ &PerformanceVariable
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),
+ &PerformanceVariable.S3PerformanceTablePointer
+ );
+ if (!EFI_ERROR (Status)) {
+ mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;
+ }
+ }
+ if (mAcpiS3PerformanceTable == NULL) {
+ //
+ // Fail to allocate at specified address, continue to allocate at any address.
+ //
+ mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages (
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE))
+ );
+ }
+ DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));
+ if (mAcpiS3PerformanceTable != NULL) {
+ CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));
+ }
+ }
+ }
+
+ if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
+ //
+ // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,
+ // save the pointer to LockBox for use in S3 resume.
+ //
+ S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
+ Status = SaveLockBox (
+ &gFirmwarePerformanceS3PointerGuid,
+ &S3PerformanceTablePointer,
+ sizeof (EFI_PHYSICAL_ADDRESS)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Install ACPI Firmware Performance Data Table (FPDT).
+
+ @return Status code.
+
+**/
+EFI_STATUS
+InstallFirmwarePerformanceDataTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ UINTN BootPerformanceDataSize;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ UINTN Size;
+
+ //
+ // Get AcpiTable Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mReceivedAcpiBootPerformanceTable != NULL) {
+ mAcpiBootPerformanceTable = mReceivedAcpiBootPerformanceTable;
+ mAcpiBootPerformanceTable->BasicBoot.ResetEnd = mBootPerformanceTableTemplate.BasicBoot.ResetEnd;
+ } else {
+ //
+ // Try to allocate the same runtime buffer as last time boot.
+ //
+ BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE);
+ ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
+ Size = sizeof (PerformanceVariable);
+ Status = gRT->GetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &Size,
+ &PerformanceVariable
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
+ &PerformanceVariable.BootPerformanceTablePointer
+ );
+ if (!EFI_ERROR (Status)) {
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
+ }
+ }
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Fail to allocate at specified address, continue to allocate at any address.
+ //
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages (
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (BootPerformanceDataSize)
+ );
+ }
+ DEBUG ((DEBUG_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
+ if (mAcpiBootPerformanceTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Fill Basic Boot record to Boot Performance Table.
+ //
+ CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
+ }
+ BootPerformanceDataSize = mAcpiBootPerformanceTable->Header.Length;
+
+ //
+ // Save Boot Performance Table address to Variable for use in S4 resume.
+ //
+ PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;
+ //
+ // Update Boot Performance Table Pointer in template.
+ //
+ mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;
+
+ //
+ // Save S3 Performance Table address to Variable for use in S4 resume.
+ //
+ PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
+ //
+ // Update S3 Performance Table Pointer in template.
+ //
+ mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;
+ //
+ // Save Runtime Performance Table pointers to Variable.
+ // Don't check SetVariable return status. It doesn't impact FPDT table generation.
+ //
+ gRT->SetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (PerformanceVariable),
+ &PerformanceVariable
+ );
+
+ //
+ // Publish Firmware Performance Data Table.
+ //
+ FpdtAcpiTableChecksum ((UINT8 *) &mFirmwarePerformanceTableTemplate, mFirmwarePerformanceTableTemplate.Header.Length);
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ &mFirmwarePerformanceTableTemplate,
+ mFirmwarePerformanceTableTemplate.Header.Length,
+ &mFirmwarePerformanceTableTemplateKey
+ );
+ if (EFI_ERROR (Status)) {
+ if (mAcpiBootPerformanceTable != NULL) {
+ FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));
+ }
+ if (mAcpiS3PerformanceTable != NULL) {
+ FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));
+ }
+ mAcpiBootPerformanceTable = NULL;
+ mAcpiS3PerformanceTable = NULL;
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Report status code listener of FPDT. This is used to collect performance data
+ for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.
+
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] 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[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] 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[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerDxe (
+ 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
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)) {
+ //
+ // DxeCore ReportStatusCode Enable so that the capability can be supported.
+ //
+ mDxeCoreReportStatusCodeEnable = TRUE;
+ }
+
+ Status = EFI_SUCCESS;
+ if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {
+ //
+ // Progress code for OS Loader LoadImage.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update OS Loader LoadImage Start for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) {
+ //
+ // Progress code for OS Loader StartImage.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update OS Loader StartImage Start for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {
+ //
+ // Unregister boot time report status code listener.
+ //
+ mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
+
+ //
+ // Progress code for ExitBootServices.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update ExitBootServicesExit for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)) {
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Firmware Performance Data Table not installed, do nothing.
+ //
+ return Status;
+ }
+
+ //
+ // Update Firmware Basic Boot Performance Record for legacy boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Dump FPDT Boot Performance record.
+ //
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));
+ } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)) {
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // ACPI Firmware Performance Data Table not installed yet, install it now.
+ //
+ InstallFirmwarePerformanceDataTable ();
+ }
+ } else if (Data != NULL && CompareGuid (&Data->Type, &gEdkiiFpdtExtendedFirmwarePerformanceGuid)) {
+ //
+ // Get the Boot performance table and then install it to ACPI table.
+ //
+ CopyMem (&mReceivedAcpiBootPerformanceTable, Data + 1, Data->Size);
+ } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {
+ DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerDxe: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableDxe\n"));
+ Status = EFI_UNSUPPORTED;
+ } else {
+ //
+ // Ignore else progress code.
+ //
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+
+/**
+ Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record
+ performance data for ExitBootServicesEntry in FPDT.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+FpdtExitBootServicesEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (!mDxeCoreReportStatusCodeEnable) {
+ //
+ // When DxeCore Report Status Code is disabled,
+ // Unregister boot time report status code listener at ExitBootService Event.
+ //
+ mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
+ }
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Firmware Performance Data Table not installed, do nothing.
+ //
+ return ;
+ }
+
+ //
+ // Update Firmware Basic Boot Performance Record for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Dump FPDT Boot Performance record.
+ //
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry));
+ //
+ // ExitBootServicesExit will be updated later, so don't dump it here.
+ //
+}
+
+/**
+ The module Entry Point of the Firmware Performance Data Table DXE 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
+FirmwarePerformanceDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ FIRMWARE_SEC_PERFORMANCE *Performance;
+ VOID *Registration;
+ UINT64 OemTableId;
+
+ CopyMem (
+ mFirmwarePerformanceTableTemplate.Header.OemId,
+ PcdGetPtr (PcdAcpiDefaultOemId),
+ sizeof (mFirmwarePerformanceTableTemplate.Header.OemId)
+ );
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mFirmwarePerformanceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mFirmwarePerformanceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mFirmwarePerformanceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mFirmwarePerformanceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Get Report Status Code Handler Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register report status code listener for OS Loader load and start.
+ //
+ Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerDxe, TPL_HIGH_LEVEL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the notify function to update FPDT on ExitBootServices Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FpdtExitBootServicesEventNotify,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve GUID HOB data that contains the ResetEnd.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiFirmwarePerformanceGuid);
+ if (GuidHob != NULL) {
+ Performance = (FIRMWARE_SEC_PERFORMANCE *) GET_GUID_HOB_DATA (GuidHob);
+ mBootPerformanceTableTemplate.BasicBoot.ResetEnd = Performance->ResetEnd;
+ } else {
+ //
+ // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.
+ //
+ DEBUG ((DEBUG_WARN, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));
+ }
+
+ if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {
+ //
+ // Register callback function upon VariableArchProtocol and LockBoxProtocol
+ // to allocate S3 performance table memory and save the pointer to LockBox.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiVariableArchProtocolGuid,
+ TPL_CALLBACK,
+ FpdtAllocateS3PerformanceTableMemory,
+ NULL,
+ &Registration
+ );
+ EfiCreateProtocolNotifyEvent (
+ &gEfiLockBoxProtocolGuid,
+ TPL_CALLBACK,
+ FpdtAllocateS3PerformanceTableMemory,
+ NULL,
+ &Registration
+ );
+ } else {
+ //
+ // Exclude S3 Performance Table Pointer from FPDT table template.
+ //
+ mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf
new file mode 100644
index 000000000..1debb0193
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf
@@ -0,0 +1,83 @@
+## @file
+# This module installs ACPI Firmware Performance Data Table (FPDT).
+#
+# This module registers report status code listener to collect performance data
+# for Firmware Basic Boot Performance Record and other boot performance records,
+# and install FPDT to ACPI table.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FirmwarePerformanceDxe
+ MODULE_UNI_FILE = FirmwarePerformanceDxe.uni
+ FILE_GUID = 00160F8D-2B35-4df2-BBE0-B272A8D631F0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FirmwarePerformanceDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FirmwarePerformanceDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+ DebugLib
+ DxeServicesLib
+ TimerLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PcdLib
+ HobLib
+ LockBoxLib
+ UefiLib
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gEfiRscHandlerProtocolGuid ## CONSUMES
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEfiLockBoxProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_CONSUMES ## Variable:L"FirmwarePerformance"
+ ## PRODUCES ## Variable:L"FirmwarePerformance"
+ ## SOMETIMES_CONSUMES ## UNDEFINED # Used to do smm communication
+ ## SOMETIMES_CONSUMES ## UNDEFINED # StatusCode Data
+ gEfiFirmwarePerformanceGuid
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid ## SOMETIMES_CONSUMES ## UNDEFINED # StatusCode Data
+ gFirmwarePerformanceS3PointerGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support ## CONSUMES
+
+[Depex]
+ gEfiRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformanceDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni
new file mode 100644
index 000000000..a27b2cefa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// This module installs ACPI Firmware Performance Data Table (FPDT).
+//
+// This module registers report status code listener to collect performance data
+// for Firmware Basic Boot Performance Record and other boot performance records,
+// and install FPDT to ACPI table.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs ACPI Firmware Performance Data Table (FPDT)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module registers report status code listener to collect performance data for Firmware Basic Boot Performance Record and other boot performance records, and installs FPDT to the ACPI table."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni
new file mode 100644
index 000000000..02e307e1f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FirmwarePerformanceDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Firmware Performance DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
new file mode 100644
index 000000000..493d09c78
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
@@ -0,0 +1,225 @@
+/** @file
+ This module updates S3 Resume Performance Record in ACPI Firmware Performance
+ Data Table in S3 resume boot mode.
+
+ This module register report status code listener to collect performance data
+ for S3 Resume Performance Record on S3 resume boot path.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Ppi/ReportStatusCodeHandler.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Guid/FirmwarePerformance.h>
+#include <Guid/Performance.h>
+#include <Guid/ExtendedFirmwarePerformance.h>
+
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+
+/**
+ Report status code listener for PEI. This is used to record the performance
+ data for S3 FullResume in FPDT.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] 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[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] 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[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerPei (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentTime;
+ UINTN VarSize;
+ EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;
+ S3_PERFORMANCE_TABLE *AcpiS3PerformanceTable;
+ EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD *AcpiS3ResumeRecord;
+ UINT64 S3ResumeTotal;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD *AcpiS3SuspendRecord;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices;
+ UINT8 *BootPerformanceTable;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader;
+ UINT8 *FirmwarePerformanceData;
+ UINT8 *FirmwarePerformanceTablePtr;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) ||
+ (Value != (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve current time as early as possible.
+ //
+ CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Update S3 Resume Performance Record.
+ //
+ S3PerformanceTablePointer = 0;
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = RestoreLockBox (&gFirmwarePerformanceS3PointerGuid, &S3PerformanceTablePointer, &VarSize);
+ ASSERT_EFI_ERROR (Status);
+
+ AcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) S3PerformanceTablePointer;
+ ASSERT (AcpiS3PerformanceTable != NULL);
+ if (AcpiS3PerformanceTable->Header.Signature != EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE) {
+ DEBUG ((EFI_D_ERROR, "FPDT S3 performance data in ACPI memory get corrupted\n"));
+ return EFI_ABORTED;
+ }
+ AcpiS3ResumeRecord = &AcpiS3PerformanceTable->S3Resume;
+ AcpiS3ResumeRecord->FullResume = CurrentTime;
+ //
+ // Calculate average S3 resume time.
+ //
+ S3ResumeTotal = MultU64x32 (AcpiS3ResumeRecord->AverageResume, AcpiS3ResumeRecord->ResumeCount);
+ AcpiS3ResumeRecord->ResumeCount++;
+ AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);
+
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - ResumeCount = %d\n", AcpiS3ResumeRecord->ResumeCount));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - FullResume = %ld\n", AcpiS3ResumeRecord->FullResume));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - AverageResume = %ld\n", AcpiS3ResumeRecord->AverageResume));
+
+ //
+ // Update S3 Suspend Performance Record.
+ //
+ AcpiS3SuspendRecord = &AcpiS3PerformanceTable->S3Suspend;
+ VarSize = sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD);
+ ZeroMem (&S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD));
+ Status = RestoreLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ &S3SuspendRecord,
+ &VarSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ AcpiS3SuspendRecord->SuspendStart = S3SuspendRecord.SuspendStart;
+ AcpiS3SuspendRecord->SuspendEnd = S3SuspendRecord.SuspendEnd;
+
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendStart = %ld\n", AcpiS3SuspendRecord->SuspendStart));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendEnd = %ld\n", AcpiS3SuspendRecord->SuspendEnd));
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &VariableServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update S3 boot records into the basic boot performance table.
+ //
+ VarSize = sizeof (PerformanceVariable);
+ Status = VariableServices->GetVariable (
+ VariableServices,
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &VarSize,
+ &PerformanceVariable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ BootPerformanceTable = (UINT8*) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
+
+ //
+ // Dump PEI boot records
+ //
+ FirmwarePerformanceTablePtr = (BootPerformanceTable + sizeof (BOOT_PERFORMANCE_TABLE));
+ GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);
+ while (GuidHob != NULL) {
+ FirmwarePerformanceData = GET_GUID_HOB_DATA (GuidHob);
+ PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *) FirmwarePerformanceData;
+
+ CopyMem (FirmwarePerformanceTablePtr, FirmwarePerformanceData + sizeof (FPDT_PEI_EXT_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries));
+
+ GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
+
+ FirmwarePerformanceTablePtr += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries);
+ }
+
+ //
+ // Update Table length.
+ //
+ ((BOOT_PERFORMANCE_TABLE *) BootPerformanceTable)->Header.Length = (UINT32)((UINTN)FirmwarePerformanceTablePtr - (UINTN)BootPerformanceTable);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry for Firmware Performance Data Table PEIM.
+
+ This routine is to register report status code listener for FPDT.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Pointer to PEI Services table.
+
+ @retval EFI_SUCCESS Report status code listener is registered successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwarePerformancePeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RSC_HANDLER_PPI *RscHandler;
+
+ if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {
+ //
+ // S3 resume - register status code listener for OS wake vector.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiRscHandlerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &RscHandler
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RscHandler->Register (FpdtStatusCodeListenerPei);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf
new file mode 100644
index 000000000..e4d4f89d0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf
@@ -0,0 +1,67 @@
+## @file
+# Firmware Performance Pei Module.
+#
+# In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table.
+#
+# This module register report status code listener to collect performance data
+# for S3 Resume Performance Record on S3 resume boot path.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FirmwarePerformancePei
+ MODULE_UNI_FILE = FirmwarePerformancePei.uni
+ FILE_GUID = ADF01BF6-47D6-495d-B95B-687777807214
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FirmwarePerformancePeiEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FirmwarePerformancePei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ BaseLib
+ DebugLib
+ TimerLib
+ BaseMemoryLib
+ LockBoxLib
+ PcdLib
+ HobLib
+
+[Ppis]
+ gEfiPeiRscHandlerPpiGuid ## CONSUMES
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # RestoreLockBox
+ gEfiFirmwarePerformanceGuid
+ gFirmwarePerformanceS3PointerGuid ## SOMETIMES_CONSUMES ## UNDEFINED # RestoreLockBox
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid ## SOMETIMES_CONSUMES ## HOB
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support ## CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND gEfiPeiRscHandlerPpiGuid
+
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformancePeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni
new file mode 100644
index 000000000..2e9e717b2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Firmware Performance Pei Module.
+//
+// In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table.
+//
+// This module register report status code listener to collect performance data
+// for S3 Resume Performance Record on S3 resume boot path.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Firmware Performance Pei Module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table. This module register report status code listener to collect performance data for S3 Resume Performance Record on S3 resume boot path."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni
new file mode 100644
index 000000000..18d653156
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FirmwarePerformancePei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Performance PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c
new file mode 100644
index 000000000..d6c6e7693
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c
@@ -0,0 +1,318 @@
+/** @file
+ This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+
+ This module registers report status code listener to collect performance data
+ for SMM driver boot records and S3 Suspend Performance Record.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FpdtSmiHandler() will receive untrusted input and do basic validation.
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+
+#include <Protocol/SmmReportStatusCodeHandler.h>
+
+#include <Guid/FirmwarePerformance.h>
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/SmmMemLib.h>
+
+SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
+
+EFI_SMM_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+UINT64 mSuspendStartTime = 0;
+BOOLEAN mS3SuspendLockBoxSaved = FALSE;
+UINT32 mBootRecordSize = 0;
+UINT8 *mBootRecordBuffer = NULL;
+
+SPIN_LOCK mSmmFpdtLock;
+BOOLEAN mSmramIsOutOfResource = FALSE;
+
+/**
+ Report status code listener for SMM. This is used to record the performance
+ data for S3 Suspend Start and S3 Suspend End in FPDT.
+
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] 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[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] 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[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerSmm (
+ 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
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentTime;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Collect one or more Boot records in boot time
+ //
+ if (Data != NULL && CompareGuid (&Data->Type, &gEdkiiFpdtExtendedFirmwarePerformanceGuid)) {
+ AcquireSpinLock (&mSmmFpdtLock);
+ //
+ // Get the boot performance data.
+ //
+ CopyMem (&mSmmBootPerformanceTable, Data + 1, Data->Size);
+ mBootRecordBuffer = ((UINT8 *) (mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+
+ ReleaseSpinLock (&mSmmFpdtLock);
+ return EFI_SUCCESS;
+ }
+
+ if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {
+ DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerSmm: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableSmm\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) &&
+ (Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve current time.
+ //
+ CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ if (Value == PcdGet32 (PcdProgressCodeS3SuspendStart)) {
+ //
+ // S3 Suspend started, record the performance data and return.
+ //
+ mSuspendStartTime = CurrentTime;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // We are going to S3 sleep, record S3 Suspend End performance data.
+ //
+ S3SuspendRecord.SuspendStart = mSuspendStartTime;
+ S3SuspendRecord.SuspendEnd = CurrentTime;
+
+ //
+ // Save S3 suspend performance data to lock box, it will be used by Firmware Performance PEIM.
+ //
+ if (!mS3SuspendLockBoxSaved) {
+ Status = SaveLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ &S3SuspendRecord,
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mS3SuspendLockBoxSaved = TRUE;
+ } else {
+ Status = UpdateLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ 0,
+ &S3SuspendRecord,
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for report SMM boot records.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtSmiHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
+ UINTN BootRecordOffset;
+ UINTN BootRecordSize;
+ VOID *BootRecordData;
+ UINTN TempCommBufferSize;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if(TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM communication data buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)CommBuffer;
+
+ Status = EFI_SUCCESS;
+
+ switch (SmmCommData->Function) {
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE :
+ if (mSmmBootPerformanceTable != NULL) {
+ mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+ }
+ SmmCommData->BootRecordSize = mBootRecordSize;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET :
+ BootRecordOffset = SmmCommData->BootRecordOffset;
+ BootRecordData = SmmCommData->BootRecordData;
+ BootRecordSize = SmmCommData->BootRecordSize;
+ if (BootRecordData == NULL || BootRecordOffset >= mBootRecordSize) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Sanity check
+ //
+ if (BootRecordSize > mBootRecordSize - BootRecordOffset) {
+ BootRecordSize = mBootRecordSize - BootRecordOffset;
+ }
+ SmmCommData->BootRecordSize = BootRecordSize;
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM Data buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ CopyMem (
+ (UINT8*)BootRecordData,
+ mBootRecordBuffer + BootRecordOffset,
+ BootRecordSize
+ );
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+ SmmCommData->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The module Entry Point of the Firmware Performance Data Table SMM 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
+FirmwarePerformanceSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mSmmFpdtLock);
+
+ //
+ // Get SMM Report Status Code Handler Protocol.
+ //
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmRscHandlerProtocolGuid,
+ NULL,
+ (VOID **) &mRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register report status code listener for BootRecords and S3 Suspend Start and End.
+ //
+ Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerSmm);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMI handler.
+ //
+ Handle = NULL;
+ Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf
new file mode 100644
index 000000000..618cbd56c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf
@@ -0,0 +1,67 @@
+## @file
+# This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+#
+# This module registers report status code listener to collect performance data
+# for SMM boot performance records and S3 Suspend Performance Record.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FirmwarePerformanceSmm
+ MODULE_UNI_FILE = FirmwarePerformanceSmm.uni
+ FILE_GUID = 044310AB-77FD-402a-AF1A-87D4120E7329
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = FirmwarePerformanceSmmEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FirmwarePerformanceSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ BaseLib
+ DebugLib
+ TimerLib
+ LockBoxLib
+ PcdLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ SynchronizationLib
+ SmmMemLib
+
+[Protocols]
+ gEfiSmmRscHandlerProtocolGuid ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## UNDEFINED # SaveLockBox
+ ## PRODUCES ## UNDEFINED # SmiHandlerRegister
+ ## SOMETIMES_CONSUMES ## UNDEFINED # StatusCode Data
+ gEfiFirmwarePerformanceGuid
+ gEdkiiFpdtExtendedFirmwarePerformanceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # StatusCode Data
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd ## CONSUMES
+
+[Depex]
+ gEfiSmmRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformanceSmmExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni
new file mode 100644
index 000000000..dc940a78f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni
@@ -0,0 +1,17 @@
+// /** @file
+// This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+//
+// This module registers report status code listener to collect performance data
+// for SMM boot performance records and S3 Suspend Performance Record.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Collects performance data for SMM driver boot records and S3 Suspend Performance Record"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module registers report status code listener to collect performance data for SMM boot performance records and S3 Suspend Performance Record."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni
new file mode 100644
index 000000000..edb57b528
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FirmwarePerformanceSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM Firmware Performance Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
new file mode 100644
index 000000000..e7cd2a12a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
@@ -0,0 +1,325 @@
+/** @file
+ This is the implementation to save ACPI S3 Context.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/AcpiS3Context.h>
+#include <IndustryStandard/Acpi.h>
+#include <Protocol/LockBox.h>
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+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;
+}
+
+/**
+ 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->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 = 1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded;
+ } else {
+ TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded;
+ }
+
+ TotalPageTableSize += ExtraPageTablePages;
+ DEBUG ((DEBUG_INFO, "AcpiS3ContextSave 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;
+ }
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+AcpiS3ContextSaveOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
+ ACPI_S3_CONTEXT *AcpiS3Context;
+ IA32_DESCRIPTOR *Idtr;
+ IA32_IDT_GATE_DESCRIPTOR *IdtGate;
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ VOID *Interface;
+
+ DEBUG ((EFI_D_INFO, "AcpiS3ContextSave!\n"));
+
+ Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO | EFI_D_WARN, "ACPI S3 context can't be saved without LockBox!\n"));
+ goto Done;
+ }
+
+ 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 *) EfiLocateFirstAcpiTable (
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE
+ );
+ 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);
+
+Done:
+ //
+ // Close the event, deregistering the callback and freeing resources.
+ //
+ Status = gBS->CloseEvent (Event);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h
new file mode 100644
index 000000000..a8dece428
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h
@@ -0,0 +1,171 @@
+/** @file
+ Internal header file for S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _INTERNAL_S3_SAVE_STATE_H_
+#define _INTERNAL_S3_SAVE_STATE_H_
+#include <PiDxe.h>
+
+#include <Protocol/S3SaveState.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/SmBus.h>
+#include <Guid/EventGroup.h>
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+AcpiS3ContextSaveOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINTN OpCode,
+ ...
+ );
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINTN OpCode,
+ ...
+ );
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ );
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ );
+
+#endif //_INTERNAL_S3_SAVE_STATE_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c
new file mode 100644
index 000000000..e342f7348
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c
@@ -0,0 +1,928 @@
+/** @file
+ Implementation for S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "InternalS3SaveState.h"
+
+EFI_HANDLE mHandle = NULL;
+EFI_S3_SAVE_STATE_PROTOCOL mS3SaveState = {
+ BootScriptWrite,
+ BootScriptInsert,
+ BootScriptLabel,
+ BootScriptCompare
+ };
+/**
+ Internal function to add IO write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoWrite (Width, Address, Count, Buffer);
+}
+/**
+ Internal function to add IO read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add memory write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to add memory read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add PciCfg write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgReadWrite (Width, Address, Data, DataMask);
+}
+/**
+ Internal function to add PciCfg2 write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2Write (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+ UINT16 Segment;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg2 read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2ReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2ReadWrite (Width, Segment, Address, Data, DataMask);
+}
+/**
+ Internal function to add smbus execute opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteSmbusExecute (
+ IN VA_LIST Marker
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ EFI_SMBUS_OPERATION Operation;
+ BOOLEAN PecCheck;
+ VOID *Buffer;
+ UINTN *DataSize;
+ UINTN SmBusAddress;
+
+ SlaveAddress.SmbusDeviceAddress = VA_ARG (Marker, UINTN);
+ Command = VA_ARG (Marker, EFI_SMBUS_DEVICE_COMMAND);
+ Operation = VA_ARG (Marker, EFI_SMBUS_OPERATION);
+ PecCheck = VA_ARG (Marker, BOOLEAN);
+ SmBusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress,Command,0,PecCheck);
+ DataSize = VA_ARG (Marker, UINTN *);
+ Buffer = VA_ARG (Marker, VOID *);
+
+ return S3BootScriptSaveSmbusExecute (SmBusAddress, Operation, DataSize, Buffer);
+}
+/**
+ Internal function to add stall opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteStall (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 Duration;
+
+ Duration = VA_ARG (Marker, UINT32);
+
+ return S3BootScriptSaveStall (Duration);
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE.
+ We ignore "Context" parameter
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveDispatch (EntryPoint);
+}
+
+/**
+ Internal function to add memory pool operation to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+ UINT64 LoopTimes;
+ UINT32 Remainder;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = VA_ARG (Marker, UINT64);
+ //
+ // According to the spec, the interval between 2 polls is 100ns,
+ // but the unit of Duration for S3BootScriptSaveMemPoll() is microsecond(1000ns).
+ // Duration * 1000ns * LoopTimes = Delay * 100ns
+ // Duration will be minimum 1(microsecond) to be minimum deviation,
+ // so LoopTimes = Delay / 10.
+ //
+ LoopTimes = DivU64x32Remainder (
+ Delay,
+ 10,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, LoopTimes will be rounded up by 1.
+ //
+ LoopTimes +=1;
+ }
+ return S3BootScriptSaveMemPoll (Width, Address, DataMask, Data, 1, LoopTimes);
+
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE2.
+ The "Context" parameter is not ignored.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch2 (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+ VOID *Context;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ Context = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+
+ return S3BootScriptSaveDispatch2 (EntryPoint, Context);
+}
+/**
+ Internal function to add INFORAMTION opcode node to the table
+ list.
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteInformation (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 InformationLength;
+ EFI_PHYSICAL_ADDRESS Information;
+
+ InformationLength = VA_ARG (Marker, UINT32);
+ Information = VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveInformation (InformationLength, (VOID*)(UINTN)Information);
+}
+/**
+ Internal function to add IO poll opcode node to the table
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteIoPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSaveIoPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfigPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePciPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config 2 poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfig2Poll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePci2Poll (Width, Segment, Address, Data, DataMask, Delay);
+}
+
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINTN OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINTN OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = S3BootScriptMoveLastOpcode (BeforeOrAfter, (VOID **)Position);
+ }
+ return Status;
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Label is NULL or points to an empty string.
+ @retval EFI_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ return S3BootScriptLabel (BeforeOrAfter, CreateIfNotFound, (VOID **)Position, Label);
+}
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+ @retval EFI_INVALID_PARAMETER The RelativePosition is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ return S3BootScriptCompare (Position1, Position2, RelativePosition);
+}
+/**
+ This routine is entry point of ScriptSave driver.
+
+ @param ImageHandle Handle for this drivers loaded image protocol.
+ @param SystemTable EFI system table.
+
+ @retval EFI_OUT_OF_RESOURCES No enough resource
+ @retval EFI_SUCCESS Succesfully installed the ScriptSave driver.
+ @retval other Errors occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeS3SaveState (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT EndOfDxeEvent;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ AcpiS3ContextSaveOnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiS3SaveStateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mS3SaveState
+ );
+
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
new file mode 100644
index 000000000..2dc1ab822
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
@@ -0,0 +1,69 @@
+## @file
+# S3 Boot Script Save State driver.
+#
+# It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = S3SaveStateDxe
+ MODULE_UNI_FILE = S3SaveStateDxe.uni
+ FILE_GUID = BDCE85BB-FBAA-4f4e-9264-501A2C249581
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeS3SaveState
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ S3SaveState.c
+ InternalS3SaveState.h
+ AcpiS3ContextSave.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ BaseLib
+ S3BootScriptLib
+ PcdLib
+ HobLib
+ LockBoxLib
+ UefiLib
+
+[Guids]
+ gEfiAcpiVariableGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiAcpiS3ContextGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiS3SaveStateProtocolGuid ## PRODUCES
+ gEfiLockBoxProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ S3SaveStateDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni
new file mode 100644
index 000000000..2e7299461
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// S3 Boot Script Save State driver.
+//
+// It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "S3 Boot Script Save State driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni
new file mode 100644
index 000000000..d21c906c5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// S3SaveStateDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"S3 Save State DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h
new file mode 100644
index 000000000..afc41ed3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h
@@ -0,0 +1,154 @@
+/** @file
+ Internal header file for SMM S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _INTERNAL_SMM_S3_SAVE_STATE_H_
+#define _INTERNAL_SMM_S3_SAVE_STATE_H_
+#include <PiDxe.h>
+
+#include <Protocol/S3SmmSaveState.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmbusLib.h>
+#include <IndustryStandard/SmBus.h>
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINTN OpCode,
+ ...
+ );
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINTN OpCode,
+ ...
+ );
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ );
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ );
+
+#endif //_INTERNAL_SMM_S3_SAVE_STATE_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c
new file mode 100644
index 000000000..601c8218d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c
@@ -0,0 +1,913 @@
+/** @file
+ Implementation for S3 SMM Boot Script Saver state driver.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "InternalSmmSaveState.h"
+
+EFI_S3_SMM_SAVE_STATE_PROTOCOL mS3SmmSaveState = {
+ BootScriptWrite,
+ BootScriptInsert,
+ BootScriptLabel,
+ BootScriptCompare
+ };
+/**
+ Internal function to add IO write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoWrite (Width, Address, Count, Buffer);
+}
+/**
+ Internal function to add IO read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add memory write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to add memory read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add PciCfg write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgReadWrite (Width, Address, Data, DataMask);
+}
+/**
+ Internal function to add PciCfg2 write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2Write (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+ UINT16 Segment;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg2 read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2ReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2ReadWrite (Width, Segment, Address, Data, DataMask);
+}
+/**
+ Internal function to add smbus execute opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteSmbusExecute (
+ IN VA_LIST Marker
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ EFI_SMBUS_OPERATION Operation;
+ BOOLEAN PecCheck;
+ VOID *Buffer;
+ UINTN *DataSize;
+ UINTN SmBusAddress;
+
+ SlaveAddress.SmbusDeviceAddress = VA_ARG (Marker, UINTN);
+ Command = VA_ARG (Marker, EFI_SMBUS_DEVICE_COMMAND);
+ Operation = VA_ARG (Marker, EFI_SMBUS_OPERATION);
+ PecCheck = VA_ARG (Marker, BOOLEAN);
+ SmBusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress,Command,0,PecCheck);
+ DataSize = VA_ARG (Marker, UINTN *);
+ Buffer = VA_ARG (Marker, VOID *);
+
+ return S3BootScriptSaveSmbusExecute (SmBusAddress, Operation, DataSize, Buffer);
+}
+/**
+ Internal function to add stall opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteStall (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 Duration;
+
+ Duration = VA_ARG (Marker, UINT32);
+
+ return S3BootScriptSaveStall (Duration);
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE.
+ We ignore "Context" parameter
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveDispatch (EntryPoint);
+}
+
+/**
+ Internal function to add memory pool operation to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+ UINT64 LoopTimes;
+ UINT32 Remainder;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = VA_ARG (Marker, UINT64);
+ //
+ // According to the spec, the interval between 2 polls is 100ns,
+ // but the unit of Duration for S3BootScriptSaveMemPoll() is microsecond(1000ns).
+ // Duration * 1000ns * LoopTimes = Delay * 100ns
+ // Duration will be minimum 1(microsecond) to be minimum deviation,
+ // so LoopTimes = Delay / 10.
+ //
+ LoopTimes = DivU64x32Remainder (
+ Delay,
+ 10,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, LoopTimes will be rounded up by 1.
+ //
+ LoopTimes +=1;
+ }
+ return S3BootScriptSaveMemPoll (Width, Address, DataMask, Data, 1, LoopTimes);
+
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE2.
+ The "Context" parameter is not ignored.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch2 (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+ VOID *Context;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ Context = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+
+ return S3BootScriptSaveDispatch2 (EntryPoint, Context);
+}
+/**
+ Internal function to add INFORAMTION opcode node to the table
+ list.
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteInformation (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 InformationLength;
+ EFI_PHYSICAL_ADDRESS Information;
+
+ InformationLength = VA_ARG (Marker, UINT32);
+ Information = VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveInformation (InformationLength, (VOID*)(UINTN)Information);
+}
+/**
+ Internal function to add IO poll opcode node to the table
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteIoPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSaveIoPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfigPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePciPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config 2 poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfig2Poll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePci2Poll (Width, Segment, Address, Data, DataMask, Delay);
+}
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINTN OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINTN OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = S3BootScriptMoveLastOpcode (BeforeOrAfter, (VOID **)Position);
+ }
+ return Status;
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Label is NULL or points to an empty string.
+ @retval EFI_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ return S3BootScriptLabel (BeforeOrAfter, CreateIfNotFound, (VOID **)Position, Label);
+}
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+ @retval EFI_INVALID_PARAMETER The RelativePosition is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ return S3BootScriptCompare (Position1, Position2, RelativePosition);
+}
+/**
+ This routine is entry point of ScriptSave driver.
+
+ @param ImageHandle Handle for this drivers loaded image protocol.
+ @param SystemTable EFI system table.
+
+ @retval EFI_OUT_OF_RESOURCES No enough resource
+ @retval EFI_SUCCESS Succesfully installed the ScriptSave driver.
+ @retval other Errors occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSmmS3SaveState (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE Handle;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Handle = NULL;
+ return gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEfiS3SmmSaveStateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mS3SmmSaveState
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf
new file mode 100644
index 000000000..91d99545e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf
@@ -0,0 +1,56 @@
+## @file
+# S3 SMM Boot Script Save State driver.
+#
+# It will install S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmS3SaveState
+ MODULE_UNI_FILE = SmmS3SaveState.uni
+ FILE_GUID = 2D59F041-53A4-40d0-A6CD-844DC0DFEF17
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+
+ ENTRY_POINT = InitializeSmmS3SaveState
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ SmmS3SaveState.c
+ InternalSmmSaveState.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ BaseLib
+ S3BootScriptLib
+ PcdLib
+
+[Protocols]
+ gEfiS3SmmSaveStateProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmmS3SaveStateExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni
new file mode 100644
index 000000000..7cdb7e551
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni
@@ -0,0 +1,16 @@
+// /** @file
+// S3 SMM Boot Script Save State driver.
+//
+// It will install S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "S3 SMM Boot Script Save State driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It will install the S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni
new file mode 100644
index 000000000..a63907fd0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmmS3SaveState Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM S3 Save State Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/BdsDxe/Bds.h b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Bds.h
new file mode 100644
index 000000000..e7a9b5b4b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Bds.h
@@ -0,0 +1,108 @@
+/** @file
+ Head file for BDS Architectural Protocol implementation
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BDS_MODULE_H_
+#define _BDS_MODULE_H_
+
+#include <Uefi.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/ConnectConInEvent.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+#include <Guid/EventGroup.h>
+
+#include <Protocol/Bds.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/DeferredImageLoad.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+#include <Library/UefiBootManagerLib.h>
+#include <Library/PlatformBootManagerLib.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
+
+/**
+
+ 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
+ );
+
+/**
+ 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,
+ 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_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/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
new file mode 100644
index 000000000..9310b4dcc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
@@ -0,0 +1,105 @@
+## @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.
+#
+# Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BdsDxe
+ MODULE_UNI_FILE = BdsDxe.uni
+ FILE_GUID = 6D33944A-EC75-4855-A54D-809C75241F6C
+ 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 EBC
+#
+
+[Sources]
+ Language.h
+ Bds.h
+ HwErrRecSupport.c
+ HwErrRecSupport.h
+ Language.c
+ BdsEntry.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ UefiLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootManagerLib
+ PlatformBootManagerLib
+ PcdLib
+ PrintLib
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"BootNext" (The number of next boot option)
+ ## SOMETIMES_PRODUCES ## Variable:L"Boot####" (Boot option variable)
+ ## 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"Key####" (Hotkey option variable)
+ ## PRODUCES ## Variable:L"HwErrRecSupport" (The level of platform supported hardware Error Record Persistence)
+ ## 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 (not PcdUefiVariableDefaultLangDeprecate) ## Variable:L"LangCodes" (Value of PcdUefiVariableDefaultLangCodes)
+ ## PRODUCES ## Variable:L"PlatformLangCodes" (Value of PcdUefiVariableDefaultPlatformLangCodes)
+ ## PRODUCES ## Variable:L"Timeout" (The time out value in second of showing progress bar)
+ ## 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_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
+ gConnectConInEventGuid ## SOMETIMES_CONSUMES ## Event
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiBdsArchProtocolGuid ## PRODUCES
+ gEfiSimpleTextInputExProtocolGuid ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDeferredImageLoadProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangCodes ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformRecoverySupport ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BdsDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.uni b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.uni
new file mode 100644
index 000000000..8609352a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxe.uni
@@ -0,0 +1,17 @@
+// /** @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.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "BdsDxe module is core driver for BDS phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "When DxeCore dispatching all DXE driver, this module will produce architecture protocol gEfiBdsArchProtocolGuid. After DxeCore finishes dispatching, DxeCore will invoke the Entry interface of protocol gEfiBdsArchProtocolGuid. Then BDS phase is entered."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxeExtra.uni
new file mode 100644
index 000000000..cd561a723
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// BdsDxe Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Device Selection Core DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c
new file mode 100644
index 000000000..83b773a2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c
@@ -0,0 +1,1170 @@
+/** @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 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP<BR>
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Bds.h"
+#include "Language.h"
+#include "HwErrRecSupport.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); \
+ }
+
+///
+/// BDS arch protocol instance initial value.
+///
+EFI_BDS_ARCH_PROTOCOL gBds = {
+ BdsEntry
+};
+
+//
+// gConnectConInEvent - Event which is signaled when ConIn connection is required
+//
+EFI_EVENT gConnectConInEvent = NULL;
+
+///
+/// The read-only variables defined in UEFI Spec.
+///
+CHAR16 *mReadOnlyVariables[] = {
+ EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,
+ EFI_LANG_CODES_VARIABLE_NAME,
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
+ EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
+ };
+
+CHAR16 *mBdsLoadOptionName[] = {
+ L"Driver",
+ L"SysPrep",
+ L"Boot",
+ L"PlatformRecovery"
+};
+
+/**
+ Event to Connect ConIn.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+BdsDxeOnConnectConInCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // When Osloader call ReadKeyStroke to signal this event
+ // no driver dependency is assumed existing. So use a non-dispatch version
+ //
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);
+ if (EFI_ERROR (Status)) {
+ //
+ // Should not enter this case, if enter, the keyboard will not work.
+ // May need platfrom policy to connect keyboard.
+ //
+ DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));
+ }
+}
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ check whether there is remaining deferred load images.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+CheckDeferredLoadImageOnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+ UINTN ImageIndex;
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ VOID *Image;
+ UINTN ImageSize;
+ BOOLEAN BootOption;
+ CHAR16 *DevicePathStr;
+
+ //
+ // Find all the deferred image load protocols.
+ //
+ HandleCount = 0;
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDeferredImageLoadProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (ImageIndex = 0; ; ImageIndex++) {
+ //
+ // Load all the deferred images in this protocol instance.
+ //
+ Status = DeferredImage->GetImageInfo (
+ DeferredImage,
+ ImageIndex,
+ &ImageDevicePath,
+ (VOID **) &Image,
+ &ImageSize,
+ &BootOption
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ DevicePathStr = ConvertDevicePathToText (ImageDevicePath, FALSE, FALSE);
+ DEBUG ((DEBUG_LOAD, "[Bds] Image was deferred but not loaded: %s.\n", DevicePathStr));
+ if (DevicePathStr != NULL) {
+ FreePool (DevicePathStr);
+ }
+ }
+ }
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+}
+
+/**
+
+ 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;
+ EFI_HANDLE Handle;
+ //
+ // Install protocol interface
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiBdsArchProtocolGuid, &gBds,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ EFI_EVENT Event;
+ //
+ // Register notify function to check deferred images on ReadyToBoot Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ CheckDeferredLoadImageOnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+ );
+ return Status;
+}
+
+/**
+ 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
+BdsWaitForSingleEvent (
+ 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);
+ ASSERT_EFI_ERROR (Status);
+ gBS->CloseEvent (TimerEvent);
+
+ //
+ // If the timer expired, change the return to timed out
+ //
+ if (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;
+}
+
+/**
+ The function reads user inputs.
+
+**/
+VOID
+BdsReadKeys (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ return;
+ }
+
+ while (gST->ConIn != NULL) {
+
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No more keys.
+ //
+ break;
+ }
+ }
+}
+
+/**
+ The function waits for the boot manager timeout expires or hotkey is pressed.
+
+ It calls PlatformBootManagerWaitCallback each second.
+
+ @param HotkeyTriggered Input hotkey event.
+**/
+VOID
+BdsWait (
+ IN EFI_EVENT HotkeyTriggered
+ )
+{
+ EFI_STATUS Status;
+ UINT16 TimeoutRemain;
+
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));
+
+ TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);
+ while (TimeoutRemain != 0) {
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));
+ PlatformBootManagerWaitCallback (TimeoutRemain);
+
+ BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered
+ // Can be removed after all keyboard drivers invoke callback in timer callback.
+
+ if (HotkeyTriggered != NULL) {
+ Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ gBS->Stall (1000000);
+ }
+
+ //
+ // 0xffff means waiting forever
+ // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop
+ //
+ if (TimeoutRemain != 0xffff) {
+ TimeoutRemain--;
+ }
+ }
+
+ //
+ // If the platform configured a nonzero and finite time-out, and we have
+ // actually reached that, report 100% completion to the platform.
+ //
+ // Note that the (TimeoutRemain == 0) condition excludes
+ // PcdPlatformBootTimeOut=0xFFFF, and that's deliberate.
+ //
+ if (PcdGet16 (PcdPlatformBootTimeOut) != 0 && TimeoutRemain == 0) {
+ PlatformBootManagerWaitCallback (0);
+ }
+ DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));
+}
+
+/**
+ Attempt to boot each boot option in the BootOptions array.
+
+ @param BootOptions Input boot option array.
+ @param BootOptionCount Input boot option count.
+ @param BootManagerMenu Input boot manager menu.
+
+ @retval TRUE Successfully boot one of the boot options.
+ @retval FALSE Failed boot any of the boot options.
+**/
+BOOLEAN
+BootBootOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ IN UINTN BootOptionCount,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu OPTIONAL
+ )
+{
+ UINTN Index;
+
+ //
+ // Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));
+
+ //
+ // Attempt boot each boot option
+ //
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // 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 ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
+ continue;
+ }
+
+ //
+ // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not
+ // part of the normal boot processing. Boot options with reserved category values will be
+ // ignored by the boot manager.
+ //
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {
+ continue;
+ }
+
+ //
+ // All the driver options should have been processed since
+ // now boot will be performed.
+ //
+ EfiBootManagerBoot (&BootOptions[Index]);
+
+ //
+ // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware
+ // supports boot manager menu, and if firmware is configured to boot in an
+ // interactive mode, the boot manager will stop processing the BootOrder variable and
+ // present a boot manager menu to the user.
+ //
+ if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {
+ EfiBootManagerBoot (BootManagerMenu);
+ break;
+ }
+ }
+
+ return (BOOLEAN) (Index < BootOptionCount);
+}
+
+/**
+ The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.
+
+ @param LoadOptions Load option array.
+ @param LoadOptionCount Load option count.
+**/
+VOID
+ProcessLoadOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,
+ IN UINTN LoadOptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN ReconnectAll;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
+
+ ReconnectAll = FALSE;
+ LoadOptionType = LoadOptionTypeMax;
+
+ //
+ // Process the driver option
+ //
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ //
+ // All the load options in the array should be of the same type.
+ //
+ if (Index == 0) {
+ LoadOptionType = LoadOptions[Index].OptionType;
+ }
+ ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
+ ASSERT (LoadOptionType != LoadOptionTypeBoot);
+
+ Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
+
+ //
+ // Status indicates whether the load option is loaded and executed
+ // LoadOptions[Index].Status is what the load option returns
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Stop processing if any PlatformRecovery#### returns success.
+ //
+ if ((LoadOptions[Index].Status == EFI_SUCCESS) &&
+ (LoadOptionType == LoadOptionTypePlatformRecovery)) {
+ break;
+ }
+
+ //
+ // Only set ReconnectAll flag when the load option executes successfully.
+ //
+ if (!EFI_ERROR (LoadOptions[Index].Status) &&
+ (LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
+ ReconnectAll = TRUE;
+ }
+ }
+ }
+
+ //
+ // 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 (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {
+ EfiBootManagerDisconnectAll ();
+ EfiBootManagerConnectAll ();
+ }
+}
+
+/**
+
+ 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;
+
+ GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &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);
+ }
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+}
+
+/**
+ Formalize OsIndication related variables.
+
+ For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
+ 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.
+
+ Create a boot option for BootManagerMenu if it hasn't been created yet
+
+**/
+VOID
+BdsFormalizeOSIndicationVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndicationSupport;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ UINT32 Attributes;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+
+ //
+ // OS indicater support variable
+ //
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ if (Status != EFI_NOT_FOUND) {
+ OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);
+ } else {
+ OsIndicationSupport = 0;
+ }
+
+ if (PcdGetBool (PcdPlatformRecoverySupport)) {
+ OsIndicationSupport |= EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;
+ }
+
+ if (PcdGetBool(PcdCapsuleOnDiskSupport)) {
+ OsIndicationSupport |= EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
+ }
+
+ Status = gRT->SetVariable (
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(UINT64),
+ &OsIndicationSupport
+ );
+ //
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // 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 (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Attributes,
+ &DataSize,
+ &OsIndication
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return;
+ }
+
+ if ((DataSize != sizeof (OsIndication)) ||
+ ((OsIndication & ~OsIndicationSupport) != 0) ||
+ (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))
+ ){
+
+ DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));
+ Status = gRT->SetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR(Status);
+ }
+}
+
+/**
+
+ Validate variables.
+
+**/
+VOID
+BdsFormalizeEfiGlobalVariable (
+ VOID
+ )
+{
+ //
+ // Validate Console variable.
+ //
+ BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);
+ BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);
+ BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);
+
+ //
+ // Validate OSIndication related variable.
+ //
+ BdsFormalizeOSIndicationVariable ();
+}
+
+/**
+
+ 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
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;
+ UINTN LoadOptionCount;
+ CHAR16 *FirmwareVendor;
+ EFI_EVENT HotkeyTriggered;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ EFI_STATUS Status;
+ UINT32 BootOptionSupport;
+ UINT16 BootTimeOut;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;
+ UINT16 *BootNext;
+ CHAR16 BootNextVariableName[sizeof ("Boot####")];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ BOOLEAN BootFwUi;
+ BOOLEAN PlatformRecovery;
+ BOOLEAN BootSuccess;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_STATUS BootManagerMenuStatus;
+ EFI_BOOT_MANAGER_LOAD_OPTION PlatformDefaultBootOption;
+
+ HotkeyTriggered = NULL;
+ Status = EFI_SUCCESS;
+ BootSuccess = FALSE;
+
+ //
+ // Insert the performance probe
+ //
+ PERF_CROSSMODULE_END("DXE");
+ PERF_CROSSMODULE_BEGIN("BDS");
+ DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));
+
+ //
+ // 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 < ARRAY_SIZE (mReadOnlyVariables); Index++) {
+ Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ 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 (
+ EFI_TIME_OUT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &BootTimeOut
+ );
+ }
+
+ //
+ // Initialize L"BootOptionSupport" EFI global variable.
+ // Lazy-ConIn implictly disables BDS hotkey.
+ //
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {
+ BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
+ SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
+ }
+ Status = gRT->SetVariable (
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (BootOptionSupport),
+ &BootOptionSupport
+ );
+ //
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Cache the "BootNext" NV variable before calling any PlatformBootManagerLib APIs
+ // This could avoid the "BootNext" set by PlatformBootManagerLib be consumed in this boot.
+ //
+ GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);
+ if (DataSize != sizeof (UINT16)) {
+ if (BootNext != NULL) {
+ FreePool (BootNext);
+ }
+ BootNext = NULL;
+ }
+
+ //
+ // Initialize the platform language variables
+ //
+ InitializeLanguage (TRUE);
+
+ FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (FilePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));
+ CpuDeadLoop ();
+ }
+ Status = EfiBootManagerInitializeLoadOption (
+ &PlatformDefaultBootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypePlatformRecovery,
+ LOAD_OPTION_ACTIVE,
+ L"Default PlatformRecovery",
+ FilePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // System firmware must include a PlatformRecovery#### variable specifying
+ // a short-form File Path Media Device Path containing the platform default
+ // file path for removable media if the platform supports Platform Recovery.
+ //
+ if (PcdGetBool (PcdPlatformRecoverySupport)) {
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
+ if (EfiBootManagerFindLoadOption (&PlatformDefaultBootOption, LoadOptions, LoadOptionCount) == -1) {
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ //
+ // The PlatformRecovery#### options are sorted by OptionNumber.
+ // Find the the smallest unused number as the new OptionNumber.
+ //
+ if (LoadOptions[Index].OptionNumber != Index) {
+ break;
+ }
+ }
+ PlatformDefaultBootOption.OptionNumber = Index;
+ Status = EfiBootManagerLoadOptionToVariable (&PlatformDefaultBootOption);
+ ASSERT_EFI_ERROR (Status);
+ }
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+ }
+ FreePool (FilePath);
+
+ //
+ // 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)
+ );
+
+ //
+ // Initialize ConnectConIn event before calling platform code.
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ BdsDxeOnConnectConInCallBack,
+ NULL,
+ &gConnectConInEventGuid,
+ &gConnectConInEvent
+ );
+ if (EFI_ERROR (Status)) {
+ gConnectConInEvent = NULL;
+ }
+ }
+
+ //
+ // Do the platform init, can be customized by OEM/IBV
+ // Possible things that can be done in PlatformBootManagerBeforeConsole:
+ // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
+ // > Register new Driver#### or Boot####
+ // > Register new Key####: e.g.: F12
+ // > Signal ReadyToLock event
+ // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
+ //
+ PERF_INMODULE_BEGIN("PlatformBootManagerBeforeConsole");
+ PlatformBootManagerBeforeConsole ();
+ PERF_INMODULE_END("PlatformBootManagerBeforeConsole");
+
+ //
+ // Initialize hotkey service
+ //
+ EfiBootManagerStartHotkeyService (&HotkeyTriggered);
+
+ //
+ // Execute Driver Options
+ //
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+
+ //
+ // Connect consoles
+ //
+ PERF_INMODULE_BEGIN("EfiBootManagerConnectAllDefaultConsoles");
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ EfiBootManagerConnectConsoleVariable (ConOut);
+ EfiBootManagerConnectConsoleVariable (ErrOut);
+ //
+ // Do not connect ConIn devices when lazy ConIn feature is ON.
+ //
+ } else {
+ EfiBootManagerConnectAllDefaultConsoles ();
+ }
+ PERF_INMODULE_END("EfiBootManagerConnectAllDefaultConsoles");
+
+ //
+ // Do the platform specific action after the console is ready
+ // Possible things that can be done in PlatformBootManagerAfterConsole:
+ // > Console post action:
+ // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+ // > Signal console ready platform customized event
+ // > Run diagnostics like memory testing
+ // > Connect certain devices
+ // > Dispatch aditional option roms
+ // > Special boot: e.g.: USB boot, enter UI
+ //
+ PERF_INMODULE_BEGIN("PlatformBootManagerAfterConsole");
+ PlatformBootManagerAfterConsole ();
+ PERF_INMODULE_END("PlatformBootManagerAfterConsole");
+
+ //
+ // If any component set PcdTestKeyUsed to TRUE because use of a test key
+ // was detected, then display a warning message on the debug log and the console
+ //
+ if (PcdGetBool (PcdTestKeyUsed)) {
+ DEBUG ((DEBUG_ERROR, "**********************************\n"));
+ DEBUG ((DEBUG_ERROR, "** WARNING: Test Key is used. **\n"));
+ DEBUG ((DEBUG_ERROR, "**********************************\n"));
+ Print (L"** WARNING: Test Key is used. **\n");
+ }
+
+ //
+ // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
+ //
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR (Status)) {
+ OsIndication = 0;
+ }
+
+ DEBUG_CODE (
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
+ DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));
+ DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
+ for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
+ DEBUG ((
+ EFI_D_INFO, " %s Options:\n",
+ mBdsLoadOptionName[LoadOptionType]
+ ));
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ DEBUG ((
+ EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",
+ mBdsLoadOptionName[LoadOptionType],
+ LoadOptions[Index].OptionNumber,
+ LoadOptions[Index].Description,
+ LoadOptions[Index].Attributes
+ ));
+ }
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+ }
+ DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));
+ );
+
+ //
+ // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.
+ //
+ BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+
+ BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
+ PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);
+ //
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
+ //
+ if (BootFwUi || PlatformRecovery) {
+ OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));
+ Status = gRT->SetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &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);
+ }
+
+ //
+ // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
+ //
+ if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {
+ //
+ // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ BdsDxeOnConnectConInCallBack (NULL, NULL);
+ }
+
+ //
+ // Directly enter the setup page.
+ //
+ EfiBootManagerBoot (&BootManagerMenu);
+ }
+
+ if (!PlatformRecovery) {
+ //
+ // Execute SysPrep####
+ //
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+
+ //
+ // Execute Key####
+ //
+ PERF_INMODULE_BEGIN ("BdsWait");
+ BdsWait (HotkeyTriggered);
+ PERF_INMODULE_END ("BdsWait");
+ //
+ // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.
+ //
+ BdsReadKeys ();
+
+ EfiBootManagerHotkeyBoot ();
+
+ if (BootNext != NULL) {
+ //
+ // Delete "BootNext" NV variable before transferring control to it to prevent loops.
+ //
+ Status = gRT->SetVariable (
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting NV variable shouldn't fail unless it doesn't exist.
+ //
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+ //
+ // Boot to "BootNext"
+ //
+ UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
+ Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);
+ if (!EFI_ERROR (Status)) {
+ EfiBootManagerBoot (&LoadOption);
+ EfiBootManagerFreeLoadOption (&LoadOption);
+ if ((LoadOption.Status == EFI_SUCCESS) &&
+ (BootManagerMenuStatus != EFI_NOT_FOUND) &&
+ (LoadOption.OptionNumber != BootManagerMenu.OptionNumber)) {
+ //
+ // Boot to Boot Manager Menu upon EFI_SUCCESS
+ // Exception: Do not boot again when the BootNext points to Boot Manager Menu.
+ //
+ EfiBootManagerBoot (&BootManagerMenu);
+ }
+ }
+ }
+
+ do {
+ //
+ // Retry to boot if any of the boot succeeds
+ //
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);
+ BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+ } while (BootSuccess);
+ }
+
+ if (BootManagerMenuStatus != EFI_NOT_FOUND) {
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);
+ }
+
+ if (!BootSuccess) {
+ if (PcdGetBool (PcdPlatformRecoverySupport)) {
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+ } else {
+ //
+ // When platform recovery is not enabled, still boot to platform default file path.
+ //
+ EfiBootManagerProcessLoadOption (&PlatformDefaultBootOption);
+ }
+ }
+ EfiBootManagerFreeLoadOption (&PlatformDefaultBootOption);
+
+ DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));
+ PlatformBootManagerUnableToBoot ();
+ CpuDeadLoop ();
+}
+
+/**
+ 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,
+ 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_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/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c b/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c
new file mode 100644
index 000000000..6e7411977
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c
@@ -0,0 +1,42 @@
+/** @file
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h b/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h
new file mode 100644
index 000000000..82c0fd38c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h
@@ -0,0 +1,26 @@
+/** @file
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.c b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.c
new file mode 100644
index 000000000..03aa055bd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.c
@@ -0,0 +1,196 @@
+/** @file
+ Language settings
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Bds.h"
+#define ISO_639_2_ENTRY_SIZE 3
+
+/**
+ 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;
+
+ LangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes);
+ PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes);
+ if (LangCodesSettingRequired) {
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+ //
+ // UEFI 2.1 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.1 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/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.h b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.h
new file mode 100644
index 000000000..647730ff3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BdsDxe/Language.h
@@ -0,0 +1,24 @@
+/** @file
+ Language setting
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LANGUAGE_H_
+#define _LANGUAGE_H_
+
+/**
+ 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/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c
new file mode 100644
index 000000000..ff45e4f8e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.c
@@ -0,0 +1,281 @@
+/** @file
+ This module produces Boot Manager Policy protocol.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Protocol/BootManagerPolicy.h>
+#include <Protocol/ManagedNetwork.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootManagerLib.h>
+
+CHAR16 mNetworkDeviceList[] = L"_NDL";
+
+/**
+ Connect all the system drivers to controllers and create the network device list in NV storage.
+
+ @retval EFI_SUCCESS Network devices are connected.
+ @retval EFI_DEVICE_ERROR No network device is connected.
+
+**/
+EFI_STATUS
+ConnectAllAndCreateNetworkDeviceList (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ EFI_DEVICE_PATH_PROTOCOL *SingleDevice;
+ EFI_DEVICE_PATH_PROTOCOL *Devices;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ EfiBootManagerConnectAll ();
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiManagedNetworkServiceBindingProtocolGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status)) {
+ Handles = NULL;
+ HandleCount = 0;
+ }
+
+ Devices = NULL;
+ while (HandleCount-- != 0) {
+ Status = gBS->HandleProtocol (Handles[HandleCount], &gEfiDevicePathProtocolGuid, (VOID **) &SingleDevice);
+ if (EFI_ERROR (Status) || (SingleDevice == NULL)) {
+ continue;
+ }
+ TempDevicePath = Devices;
+ Devices = AppendDevicePathInstance (Devices, SingleDevice);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+ }
+
+ if (Devices != NULL) {
+ Status = gRT->SetVariable (
+ mNetworkDeviceList,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (Devices),
+ Devices
+ );
+ //
+ // Fails to save the network device list to NV storage is not a fatal error.
+ // Only impact is performance.
+ //
+ FreePool (Devices);
+ }
+
+ return (Devices == NULL) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+}
+
+/**
+ Connect the network devices.
+
+ @retval EFI_SUCCESS At least one network device was connected.
+ @retval EFI_DEVICE_ERROR Network devices were not connected due to an error.
+**/
+EFI_STATUS
+ConnectNetwork (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN OneConnected;
+ EFI_DEVICE_PATH_PROTOCOL *Devices;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *SingleDevice;
+ UINTN Size;
+
+ OneConnected = FALSE;
+ GetVariable2 (mNetworkDeviceList, &gEfiCallerIdGuid, (VOID **) &Devices, NULL);
+ TempDevicePath = Devices;
+ while (TempDevicePath != NULL) {
+ SingleDevice = GetNextDevicePathInstance (&TempDevicePath, &Size);
+ Status = EfiBootManagerConnectDevicePath (SingleDevice, NULL);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ FreePool (SingleDevice);
+ }
+ if (Devices != NULL) {
+ FreePool (Devices);
+ }
+
+ if (OneConnected) {
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Cached network devices list doesn't exist or is NOT valid.
+ //
+ return ConnectAllAndCreateNetworkDeviceList ();
+ }
+}
+
+/**
+ Connect a device path following the platforms EFI Boot Manager policy.
+
+ The ConnectDevicePath() function allows the caller to connect a DevicePath using the
+ same policy as the EFI Boot Manger.
+
+ @param[in] This A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
+ @param[in] DevicePath Points to the start of the EFI device path to connect.
+ If DevicePath is NULL then all the controllers in the
+ system will be connected using the platforms EFI Boot
+ Manager policy.
+ @param[in] Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the
+ controller specified by DevicePath have been created.
+ If FALSE, then the tree of controllers is only expanded
+ one level. If DevicePath is NULL then Recursive is ignored.
+
+ @retval EFI_SUCCESS The DevicePath was connected.
+ @retval EFI_NOT_FOUND The DevicePath was not found.
+ @retval EFI_NOT_FOUND No driver was connected to DevicePath.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION.
+**/
+EFI_STATUS
+EFIAPI
+BootManagerPolicyConnectDevicePath (
+ IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN BOOLEAN Recursive
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Controller;
+
+ if (EfiGetCurrentTpl () != TPL_APPLICATION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (DevicePath == NULL) {
+ EfiBootManagerConnectAll ();
+ return EFI_SUCCESS;
+ }
+
+ if (Recursive) {
+ Status = EfiBootManagerConnectDevicePath (DevicePath, NULL);
+ } else {
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Controller);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->ConnectController (Controller, NULL, DevicePath, FALSE);
+ }
+ }
+ return Status;
+}
+/**
+ Connect a class of devices using the platform Boot Manager policy.
+
+ The ConnectDeviceClass() function allows the caller to request that the Boot
+ Manager connect a class of devices.
+
+ If Class is EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID then the Boot Manager will
+ use platform policy to connect consoles. Some platforms may restrict the
+ number of consoles connected as they attempt to fast boot, and calling
+ ConnectDeviceClass() with a Class value of EFI_BOOT_MANAGER_POLICY_CONSOLE_GUID
+ must connect the set of consoles that follow the Boot Manager platform policy,
+ and the EFI_SIMPLE_TEXT_INPUT_PROTOCOL, EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL, and
+ the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL are produced on the connected handles.
+ The Boot Manager may restrict which consoles get connect due to platform policy,
+ for example a security policy may require that a given console is not connected.
+
+ If Class is EFI_BOOT_MANAGER_POLICY_NETWORK_GUID then the Boot Manager will
+ connect the protocols the platforms supports for UEFI general purpose network
+ applications on one or more handles. If more than one network controller is
+ available a platform will connect, one, many, or all of the networks based
+ on platform policy. Connecting UEFI networking protocols, like EFI_DHCP4_PROTOCOL,
+ does not establish connections on the network. The UEFI general purpose network
+ application that called ConnectDeviceClass() may need to use the published
+ protocols to establish the network connection. The Boot Manager can optionally
+ have a policy to establish a network connection.
+
+ If Class is EFI_BOOT_MANAGER_POLICY_CONNECT_ALL_GUID then the Boot Manager
+ will connect all UEFI drivers using the UEFI Boot Service
+ EFI_BOOT_SERVICES.ConnectController(). If the Boot Manager has policy
+ associated with connect all UEFI drivers this policy will be used.
+
+ A platform can also define platform specific Class values as a properly generated
+ EFI_GUID would never conflict with this specification.
+
+ @param[in] This A pointer to the EFI_BOOT_MANAGER_POLICY_PROTOCOL instance.
+ @param[in] Class A pointer to an EFI_GUID that represents a class of devices
+ that will be connected using the Boot Mangers platform policy.
+
+ @retval EFI_SUCCESS At least one devices of the Class was connected.
+ @retval EFI_DEVICE_ERROR Devices were not connected due to an error.
+ @retval EFI_NOT_FOUND The Class is not supported by the platform.
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION.
+**/
+EFI_STATUS
+EFIAPI
+BootManagerPolicyConnectDeviceClass (
+ IN EFI_BOOT_MANAGER_POLICY_PROTOCOL *This,
+ IN EFI_GUID *Class
+ )
+{
+ if (EfiGetCurrentTpl () != TPL_APPLICATION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CompareGuid (Class, &gEfiBootManagerPolicyConnectAllGuid)) {
+ ConnectAllAndCreateNetworkDeviceList ();
+ return EFI_SUCCESS;
+ }
+
+ if (CompareGuid (Class, &gEfiBootManagerPolicyConsoleGuid)) {
+ return EfiBootManagerConnectAllDefaultConsoles ();
+ }
+
+ if (CompareGuid (Class, &gEfiBootManagerPolicyNetworkGuid)) {
+ return ConnectNetwork ();
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_BOOT_MANAGER_POLICY_PROTOCOL mBootManagerPolicy = {
+ EFI_BOOT_MANAGER_POLICY_PROTOCOL_REVISION,
+ BootManagerPolicyConnectDevicePath,
+ BootManagerPolicyConnectDeviceClass
+};
+
+/**
+ Install Boot Manager Policy Protocol.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS The Boot Manager Policy protocol is successfully installed.
+ @retval Other Return status from gBS->InstallMultipleProtocolInterfaces().
+
+**/
+EFI_STATUS
+EFIAPI
+BootManagerPolicyInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE Handle;
+
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiBootManagerPolicyProtocolGuid);
+
+ Handle = NULL;
+ return gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiBootManagerPolicyProtocolGuid, &mBootManagerPolicy,
+ NULL
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.inf b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.inf
new file mode 100644
index 000000000..3e4f60764
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# This module produces Boot Manager Policy protocol.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootManagerPolicyDxe
+ MODULE_UNI_FILE = BootManagerPolicyDxe.uni
+ FILE_GUID = E622443C-284E-4b47-A984-FD66B482DAC0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BootManagerPolicyInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ BootManagerPolicyDxe.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ DevicePathLib
+ DebugLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiBootManagerLib
+
+[Guids]
+ gEfiBootManagerPolicyConnectAllGuid ## CONSUMES ## GUID
+ gEfiBootManagerPolicyNetworkGuid ## CONSUMES ## GUID
+ gEfiBootManagerPolicyConsoleGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES
+ gEfiBootManagerPolicyProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootManagerPolicyDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.uni b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.uni
new file mode 100644
index 000000000..8949cd349
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// This module produces Boot Manager Policy protocol.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This module produces Boot Manager Policy protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces Boot Manager Policy protocol, which is used by EFI Applications to request the UEFI Boot Manager to connect devices using platform policy."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxeExtra.uni
new file mode 100644
index 000000000..fba87555f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/BootManagerPolicyDxe/BootManagerPolicyDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// This module produces Boot Manager Policy protocol.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Manager Policy DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.c b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.c
new file mode 100644
index 000000000..e9b125008
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.c
@@ -0,0 +1,437 @@
+/** @file
+ Recovery module.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - Capsule-on-Disk Temp Relocation image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ RetrieveRelocatedCapsule() will receive untrusted input and do basic validation.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <Uefi.h>
+#include <PiPei.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Ppi/MasterBootMode.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/Capsule.h>
+#include <Ppi/CapsuleOnDisk.h>
+#include <Ppi/DeviceRecoveryModule.h>
+
+#include <Guid/FirmwareFileSystem2.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+/**
+ Loads a DXE capsule from some media into memory and updates the HOB table
+ with the DXE firmware volume information.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadCapsuleOnDisk (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This
+ );
+
+static EDKII_PEI_CAPSULE_ON_DISK_PPI mCapsuleOnDiskPpi = {
+ LoadCapsuleOnDisk
+};
+
+static EFI_PEI_PPI_DESCRIPTOR mCapsuleOnDiskPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiPeiCapsuleOnDiskPpiGuid,
+ &mCapsuleOnDiskPpi
+};
+
+/**
+ Determine if capsule comes from memory by checking Capsule PPI.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval TRUE Capsule comes from memory.
+ @retval FALSE No capsule comes from memory.
+
+**/
+static
+BOOLEAN
+CheckCapsuleFromRam (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_CAPSULE_PPI *Capsule;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiCapsulePpiGuid,
+ 0,
+ NULL,
+ (VOID **) &Capsule
+ );
+ if (!EFI_ERROR(Status)) {
+ Status = Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES **)PeiServices);
+ if (!EFI_ERROR(Status)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Determine if it is a Capsule On Disk mode.
+
+ @retval TRUE Capsule On Disk mode.
+ @retval FALSE Not capsule On Disk mode.
+
+**/
+static
+BOOLEAN
+IsCapsuleOnDiskMode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
+ BOOLEAN CodRelocInfo;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PPIVariableServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof (BOOLEAN);
+ Status = PPIVariableServices->GetVariable (
+ PPIVariableServices,
+ COD_RELOCATION_INFO_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ &CodRelocInfo
+ );
+
+ if (EFI_ERROR (Status) || Size != sizeof(BOOLEAN) || !CodRelocInfo) {
+ DEBUG (( DEBUG_ERROR, "Error Get CodRelocationInfo variable %r!\n", Status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Gets capsule images from relocated capsule buffer.
+ Create Capsule hob for each Capsule.
+
+ Caution: This function may receive untrusted input.
+ Capsule-on-Disk Temp Relocation image is external input, so this function
+ will validate Capsule-on-Disk Temp Relocation image to make sure the content
+ is read within the buffer.
+
+ @param[in] RelocCapsuleBuf Buffer pointer to the relocated capsule.
+ @param[in] RelocCapsuleTotalSize Total size of the relocated capsule.
+
+ @retval EFI_SUCCESS Succeed to get capsules and create hob.
+ @retval Others Fail to get capsules and create hob.
+
+**/
+static
+EFI_STATUS
+RetrieveRelocatedCapsule (
+ IN UINT8 *RelocCapsuleBuf,
+ IN UINTN RelocCapsuleTotalSize
+ )
+{
+ UINTN Index;
+ UINT8 *CapsuleDataBufEnd;
+ UINT8 *CapsulePtr;
+ UINT32 CapsuleSize;
+ UINT64 TotalImageSize;
+ UINTN CapsuleNum;
+
+ //
+ // Temp file contains at least 2 capsule (including 1 capsule name capsule) & 1 UINT64
+ //
+ if (RelocCapsuleTotalSize < sizeof(UINT64) + sizeof(EFI_CAPSULE_HEADER) * 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem(&TotalImageSize, RelocCapsuleBuf, sizeof(UINT64));
+
+ DEBUG ((DEBUG_INFO, "ProcessRelocatedCapsule CapsuleBuf %x TotalCapSize %lx\n",
+ RelocCapsuleBuf, TotalImageSize));
+
+ RelocCapsuleBuf += sizeof(UINT64);
+
+ //
+ // TempCaspule file length check
+ //
+ if (MAX_ADDRESS - TotalImageSize <= sizeof(UINT64) ||
+ (UINT64)RelocCapsuleTotalSize != TotalImageSize + sizeof(UINT64) ||
+ (UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)RelocCapsuleBuf) <= TotalImageSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CapsuleDataBufEnd = RelocCapsuleBuf + TotalImageSize;
+
+ //
+ // TempCapsule file integrity check over Capsule Header to ensure no data corruption in NV Var & Relocation storage
+ //
+ CapsulePtr = RelocCapsuleBuf;
+ CapsuleNum = 0;
+
+ while (CapsulePtr < CapsuleDataBufEnd) {
+ if ((CapsuleDataBufEnd - CapsulePtr) < sizeof(EFI_CAPSULE_HEADER) ||
+ ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize < sizeof(EFI_CAPSULE_HEADER) ||
+ (UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)CapsulePtr) < ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize
+ ) {
+ break;
+ }
+ CapsulePtr += ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;
+ CapsuleNum ++;
+ }
+
+ if (CapsulePtr != CapsuleDataBufEnd) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Capsule count must be less than PcdCapsuleMax, avoid building too many CvHobs to occupy all the free space in HobList.
+ //
+ if (CapsuleNum > PcdGet16 (PcdCapsuleMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Re-iterate the capsule buffer to create Capsule hob & Capsule Name Str Hob for each Capsule saved in relocated capsule file
+ //
+ CapsulePtr = RelocCapsuleBuf;
+ Index = 0;
+ while (CapsulePtr < CapsuleDataBufEnd) {
+ CapsuleSize = ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;
+ BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsulePtr, CapsuleSize);
+
+ DEBUG((DEBUG_INFO, "Capsule saved in address %x size %x\n", CapsulePtr, CapsuleSize));
+
+ CapsulePtr += CapsuleSize;
+ Index++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Recovery module entrypoint
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS Recovery module is initialized.
+**/
+EFI_STATUS
+EFIAPI
+InitializeCapsuleOnDiskLoad (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN BootMode;
+ UINTN FileNameSize;
+
+ BootMode = GetBootModeHob();
+ ASSERT(BootMode == BOOT_ON_FLASH_UPDATE);
+
+ //
+ // If there are capsules provisioned in memory, quit.
+ // Only one capsule resource is accept, CapsuleOnRam's priority is higher than CapsuleOnDisk.
+ //
+ if (CheckCapsuleFromRam(PeiServices)) {
+ DEBUG((DEBUG_ERROR, "Capsule On Memory Detected! Quit.\n"));
+ return EFI_ABORTED;
+ }
+
+ DEBUG_CODE (
+ VOID *CapsuleOnDiskModePpi;
+
+ if (!IsCapsuleOnDiskMode()){
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check Capsule On Disk Relocation flag. If exists, load capsule & create Capsule Hob
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiBootInCapsuleOnDiskModePpiGuid,
+ 0,
+ NULL,
+ (VOID **)&CapsuleOnDiskModePpi
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Locate CapsuleOnDiskModePpi error %x\n", Status));
+ return Status;
+ }
+ );
+
+ Status = PeiServicesInstallPpi (&mCapsuleOnDiskPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ FileNameSize = PcdGetSize (PcdCoDRelocationFileName);
+ Status = PcdSetPtrS (PcdRecoveryFileName, &FileNameSize, (VOID *) PcdGetPtr(PcdCoDRelocationFileName));
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Loads a DXE capsule from some media into memory and updates the HOB table
+ with the DXE firmware volume information.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadCapsuleOnDisk (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
+ UINTN NumberRecoveryCapsules;
+ UINTN Instance;
+ UINTN CapsuleInstance;
+ UINTN CapsuleSize;
+ EFI_GUID CapsuleType;
+ VOID *CapsuleBuffer;
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Load Capsule On Disk Entry\n"));
+
+ for (Instance = 0; ; Instance++) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiDeviceRecoveryModulePpiGuid,
+ Instance,
+ NULL,
+ (VOID **)&DeviceRecoveryPpi
+ );
+ DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
+ if (EFI_ERROR (Status)) {
+ if (Instance == 0) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)
+ );
+ }
+ break;
+ }
+ NumberRecoveryCapsules = 0;
+ Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ &NumberRecoveryCapsules
+ );
+ DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
+ CapsuleSize = 0;
+ Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ CapsuleInstance,
+ &CapsuleSize,
+ &CapsuleType
+ );
+ DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Allocate the memory so that it gets preserved into DXE.
+ // Capsule is special because it may need to populate to system table
+ //
+ CapsuleBuffer = AllocateRuntimePages (EFI_SIZE_TO_PAGES (CapsuleSize));
+
+ if (CapsuleBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "LoadCapsuleOnDisk - AllocateRuntimePages fail\n"));
+ continue;
+ }
+
+ Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
+ (EFI_PEI_SERVICES **)PeiServices,
+ DeviceRecoveryPpi,
+ CapsuleInstance,
+ CapsuleBuffer
+ );
+ DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
+ if (EFI_ERROR (Status)) {
+ FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize));
+ break;
+ }
+
+ //
+ // Capsule Update Mode, Split relocated Capsule buffer into different capsule vehical hobs.
+ //
+ Status = RetrieveRelocatedCapsule(CapsuleBuffer, CapsuleSize);
+
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)
+ );
+ }
+
+ return Status;
+ }
+
+ //
+ // Any attack against GPT, Relocation Info Variable or temp relocation file will result in no Capsule HOB and return EFI_NOT_FOUND.
+ // After flow to DXE phase. since no capsule hob is detected. Platform will clear Info flag and force restart.
+ // No volunerability will be exposed
+ //
+
+ return EFI_NOT_FOUND;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.inf b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.inf
new file mode 100644
index 000000000..b1f562058
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.inf
@@ -0,0 +1,64 @@
+## @file
+# Load Capsule on Disk module.
+#
+# Load Capsule On Disk from Root Directory file system. Create CV hob
+# based on temporary Capsule On Disk file.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleOnDiskLoadPei
+ MODULE_UNI_FILE = CapsuleOnDiskLoadPei.uni
+ FILE_GUID = 8ADEDF9E-2EC8-40fb-AE56-B76D90225D2D
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeCapsuleOnDiskLoad
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ CapsuleOnDiskLoadPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ DebugLib
+ HobLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+
+[Ppis]
+ gEdkiiPeiCapsuleOnDiskPpiGuid ## PRODUCES
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+ gEdkiiPeiBootInCapsuleOnDiskModePpiGuid ## SOMETIMES_CONSUMES
+ gEfiPeiDeviceRecoveryModulePpiGuid ## CONSUMES
+ gEfiPeiCapsulePpiGuid ## CONSUMES
+
+[Guids]
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable L"CodRelocationInfo"
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
+
+[PcdEx]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName ## PRODUCES
+
+[Depex]
+ gEdkiiPeiBootInCapsuleOnDiskModePpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsuleOnDiskLoadPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.uni
new file mode 100644
index 000000000..c3eae6a5c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Caspule On Disk Load module.
+//
+// Load Capsule On Disk and build CV hob.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Caspule On Disk Load module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Load Capsule On Disk and build CV hob."
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPeiExtra.uni
new file mode 100644
index 000000000..81034f629
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CapsuleOnDiskLoadPei Localized Strings and Content
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"CapsuleOnDiskLoad PEI Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/Capsule.h b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Capsule.h
new file mode 100644
index 000000000..3d9cab02c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Capsule.h
@@ -0,0 +1,123 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CAPSULE_PEIM_H_
+#define _CAPSULE_PEIM_H_
+
+#include <PiPei.h>
+#include <Uefi/UefiSpec.h>
+
+#include <Ppi/Capsule.h>
+#include <Ppi/LoadFile.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/PeImage.h>
+#include "Common/CommonHeader.h"
+
+#ifdef MDE_CPU_IA32
+
+#pragma pack(1)
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:17; // Must be zero;
+ UINT64 PageTableBaseAddress:22; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+typedef
+EFI_STATUS
+(*COALESCE_ENTRY) (
+ SWITCH_32_TO_64_CONTEXT *EntrypointContext,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+ );
+
+#endif
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
new file mode 100644
index 000000000..e5078c798
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf
@@ -0,0 +1,94 @@
+## @file
+# Capsule update PEIM supports EFI and UEFI.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - capsule image.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsulePei
+ MODULE_UNI_FILE = CapsulePei.uni
+ FILE_GUID = C779F6D8-7113-4AA1-9648-EB1633C7D53B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CapsuleMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UefiCapsule.c
+ Capsule.h
+ Common/CapsuleCoalesce.c
+ Common/CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ HobLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PrintLib
+ ReportStatusCodeLib
+
+[LibraryClasses.IA32]
+ PeCoffGetEntryPointLib
+ PcdLib
+ DebugAgentLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleLongModeBuffer"
+ gEfiCapsuleVendorGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+ gEfiPeiCapsulePpiGuid ## PRODUCES
+
+[Ppis.IA32]
+ gEfiPeiLoadFilePpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd.IA32]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleCoalesceFile ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
+
+[FeaturePcd.IA32]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Depex]
+ gEfiPeiReadOnlyVariable2PpiGuid
+
+# [BootMode]
+# FLASH_UPDATE ## SOMETIMES_CONSUMES
+
+# [Hob.IA32]
+# UNDEFINED ## SOMETIMES_CONSUMES # CPU
+
+# [Hob]
+# UNDEFINED ## SOMETIMES_PRODUCES # UEFI_CAPSULE
+
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsulePeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.uni b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.uni
new file mode 100644
index 000000000..528946a95
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePei.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Capsule update PEIM supports EFI and UEFI.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - capsule image.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Capsule update PEIM supporting EFI and UEFI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule update PEIM supporting EFI and UEFI"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePeiExtra.uni
new file mode 100644
index 000000000..40539cfd5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsulePeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CapsulePei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Update PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
new file mode 100644
index 000000000..35d2535a5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
@@ -0,0 +1,52 @@
+## @file
+# CapsuleX64 module handles >4GB capsule blocks.
+#
+# The X64 entrypoint to process capsule in long mode.
+# This module is built as X64.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - capsule image.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleX64
+ MODULE_UNI_FILE = CapsuleX64.uni
+ FILE_GUID = F7FDE4A6-294C-493c-B50F-9734553BB757
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ X64/X64Entry.c
+ X64/PageFaultHandler.nasm
+ Common/CapsuleCoalesce.c
+ Common/CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ CpuExceptionHandlerLib
+ DebugAgentLib
+
+[Depex]
+ FALSE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsuleX64Extra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.uni b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.uni
new file mode 100644
index 000000000..8b1400880
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64.uni
@@ -0,0 +1,23 @@
+// /** @file
+// CapsuleX64 module handles >4GB capsule blocks.
+//
+// The X64 entrypoint to process capsule in long mode.
+// This module is built as X64.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - capsule image.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Handles >4GB capsule blocks"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The X64 entry point to process capsule in long mode. This module is built as X64.<BR><BR>\n"
+ "This driver will have external input - capsule image. This external input must be validated carefully to avoid security issues like buffer overflow or integer overflow.<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64Extra.uni b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64Extra.uni
new file mode 100644
index 000000000..a6dffdd6a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/CapsuleX64Extra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CapsuleX64 Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Update PEI Module over 4GB"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c
new file mode 100644
index 000000000..468eea5d3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CapsuleCoalesce.c
@@ -0,0 +1,1291 @@
+/** @file
+ The logic to process capsule.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ CapsuleDataCoalesce() will do basic validation before coalesce capsule data
+ into memory.
+
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseLib.h>
+
+#include "CommonHeader.h"
+
+#define MIN_COALESCE_ADDR (1024 * 1024)
+
+/**
+ Given a pointer to the capsule block list, info on the available system
+ memory, and the size of a buffer, find a free block of memory where a
+ buffer of the given size can be copied to safely.
+
+ @param BlockList Pointer to head of capsule block descriptors
+ @param MemBase Pointer to the base of memory in which we want to find free space
+ @param MemSize The size of the block of memory pointed to by MemBase
+ @param DataSize How big a free block we want to find
+
+ @return A pointer to a memory block of at least DataSize that lies somewhere
+ between MemBase and (MemBase + MemSize). The memory pointed to does not
+ contain any of the capsule block descriptors or capsule blocks pointed to
+ by the BlockList.
+
+**/
+UINT8 *
+FindFreeMem (
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ UINT8 *MemBase,
+ UINTN MemSize,
+ UINTN DataSize
+ );
+
+/**
+ The capsule block descriptors may be fragmented and spread all over memory.
+ To simplify the coalescing of capsule blocks, first coalesce all the
+ capsule block descriptors low in memory.
+
+ The descriptors passed in can be fragmented throughout memory. Here
+ they are relocated into memory to turn them into a contiguous (null
+ terminated) array.
+
+ @param PeiServices pointer to PEI services table
+ @param BlockList pointer to the capsule block descriptors
+ @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.
+ @param MemBase base of system memory in which we can work
+ @param MemSize size of the system memory pointed to by MemBase
+
+ @retval NULL could not relocate the descriptors
+ @retval Pointer to the base of the successfully-relocated block descriptors.
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+RelocateBlockDescriptors (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN UINTN NumDescriptors,
+ IN UINT8 *MemBase,
+ IN UINTN MemSize
+ );
+
+/**
+ Check every capsule header.
+
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
+
+ @retval FALSE Capsule is OK
+ @retval TRUE Capsule is corrupted
+
+**/
+BOOLEAN
+IsCapsuleCorrupted (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ );
+
+/**
+ Determine if two buffers overlap in memory.
+
+ @param Buff1 pointer to first buffer
+ @param Size1 size of Buff1
+ @param Buff2 pointer to second buffer
+ @param Size2 size of Buff2
+
+ @retval TRUE Buffers overlap in memory.
+ @retval FALSE Buffer doesn't overlap.
+
+**/
+BOOLEAN
+IsOverlapped (
+ UINT8 *Buff1,
+ UINTN Size1,
+ UINT8 *Buff2,
+ UINTN Size2
+ );
+
+/**
+ Given a pointer to a capsule block descriptor, traverse the list to figure
+ out how many legitimate descriptors there are, and how big the capsule it
+ refers to is.
+
+ @param Desc Pointer to the capsule block descriptors
+ @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.
+ @param CapsuleSize Optional pointer to where to return the capsule image size
+ @param CapsuleNumber Optional pointer to where to return the number of capsule
+
+ @retval EFI_NOT_FOUND No descriptors containing data in the list
+ @retval EFI_SUCCESS Return data is valid
+
+**/
+EFI_STATUS
+GetCapsuleInfo (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,
+ IN OUT UINTN *NumDescriptors OPTIONAL,
+ IN OUT UINTN *CapsuleSize OPTIONAL,
+ IN OUT UINTN *CapsuleNumber OPTIONAL
+ );
+
+/**
+ Given a pointer to the capsule block list, info on the available system
+ memory, and the size of a buffer, find a free block of memory where a
+ buffer of the given size can be copied to safely.
+
+ @param BlockList Pointer to head of capsule block descriptors
+ @param MemBase Pointer to the base of memory in which we want to find free space
+ @param MemSize The size of the block of memory pointed to by MemBase
+ @param DataSize How big a free block we want to find
+
+ @return A pointer to a memory block of at least DataSize that lies somewhere
+ between MemBase and (MemBase + MemSize). The memory pointed to does not
+ contain any of the capsule block descriptors or capsule blocks pointed to
+ by the BlockList.
+
+**/
+UINT8 *
+FindFreeMem (
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ UINT8 *MemBase,
+ UINTN MemSize,
+ UINTN DataSize
+ )
+{
+ UINTN Size;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempDesc;
+ UINT8 *MemEnd;
+ BOOLEAN Failed;
+
+ //
+ // Need at least enough to copy the data to at the end of the buffer, so
+ // say the end is less the data size for easy comparisons here.
+ //
+ MemEnd = MemBase + MemSize - DataSize;
+ CurrDesc = BlockList;
+ //
+ // Go through all the descriptor blocks and see if any obstruct the range
+ //
+ while (CurrDesc != NULL) {
+ //
+ // Get the size of this block list and see if it's in the way
+ //
+ Failed = FALSE;
+ TempDesc = CurrDesc;
+ Size = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ while (TempDesc->Length != 0) {
+ Size += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ TempDesc++;
+ }
+
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) CurrDesc, Size)) {
+ //
+ // Set our new base to the end of this block list and start all over
+ //
+ MemBase = (UINT8 *) CurrDesc + Size;
+ CurrDesc = BlockList;
+ if (MemBase > MemEnd) {
+ return NULL;
+ }
+
+ Failed = TRUE;
+ }
+ //
+ // Now go through all the blocks and make sure none are in the way
+ //
+ while ((CurrDesc->Length != 0) && (!Failed)) {
+ if (IsOverlapped (MemBase, DataSize, (UINT8 *) (UINTN) CurrDesc->Union.DataBlock, (UINTN) CurrDesc->Length)) {
+ //
+ // Set our new base to the end of this block and start all over
+ //
+ Failed = TRUE;
+ MemBase = (UINT8 *) ((UINTN) CurrDesc->Union.DataBlock) + CurrDesc->Length;
+ CurrDesc = BlockList;
+ if (MemBase > MemEnd) {
+ return NULL;
+ }
+ }
+ CurrDesc++;
+ }
+ //
+ // Normal continuation -- jump to next block descriptor list
+ //
+ if (!Failed) {
+ CurrDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) CurrDesc->Union.ContinuationPointer;
+ }
+ }
+ return MemBase;
+}
+
+/**
+ Validate capsule by MemoryResource.
+
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+ @param Address Address to be validated.
+ @param Size Size to be validated.
+
+ @retval TRUE No memory resource descriptor reported in HOB list before capsule Coalesce,
+ or it is valid in one MemoryResource.
+ FALSE It is not in any MemoryResource.
+
+**/
+BOOLEAN
+ValidateCapsuleByMemoryResource (
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT64 Size
+ )
+{
+ UINTN Index;
+
+ //
+ // Sanity Check
+ //
+ if (Size > MAX_ADDRESS) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Size(0x%lx) > MAX_ADDRESS\n", Size));
+ return FALSE;
+ }
+
+ //
+ // Sanity Check
+ //
+ if (Address > (MAX_ADDRESS - Size)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) > (MAX_ADDRESS - Size(0x%lx))\n", Address, Size));
+ return FALSE;
+ }
+
+ if (MemoryResource == NULL) {
+ //
+ // No memory resource descriptor reported in HOB list before capsule Coalesce.
+ //
+ return TRUE;
+ }
+
+ for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) {
+ if ((Address >= MemoryResource[Index].PhysicalStart) &&
+ ((Address + Size) <= (MemoryResource[Index].PhysicalStart + MemoryResource[Index].ResourceLength))) {
+ DEBUG ((DEBUG_INFO, "Address(0x%lx) Size(0x%lx) in MemoryResource[0x%x] - Start(0x%lx) Length(0x%lx)\n",
+ Address, Size,
+ Index, MemoryResource[Index].PhysicalStart, MemoryResource[Index].ResourceLength));
+ return TRUE;
+ }
+ }
+
+ DEBUG ((DEBUG_ERROR, "ERROR: Address(0x%lx) Size(0x%lx) not in any MemoryResource\n", Address, Size));
+ return FALSE;
+}
+
+/**
+ Check the integrity of the capsule descriptors.
+
+ @param BlockList Pointer to the capsule descriptors
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+
+ @retval NULL BlockList is not valid.
+ @retval LastBlockDesc Last one Block in BlockList
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+ValidateCapsuleIntegrity (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource
+ )
+{
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT64 CapsuleSize;
+ UINTN CapsuleCount;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr;
+
+ DEBUG ((DEBUG_INFO, "ValidateCapsuleIntegrity\n"));
+
+ //
+ // Go through the list to look for inconsistencies. Check for:
+ // * misaligned block descriptors.
+ // * The first capsule header guid
+ // * The first capsule header flag
+ // * The first capsule header HeaderSize
+ // * Below check will be done in ValidateCapsuleByMemoryResource()
+ // Length > MAX_ADDRESS
+ // Ptr + sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR) > MAX_ADDRESS
+ // DataBlock + Length > MAX_ADDRESS
+ //
+ CapsuleSize = 0;
+ CapsuleCount = 0;
+ Ptr = BlockList;
+
+ if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {
+ return NULL;
+ }
+
+ DEBUG ((DEBUG_INFO, "Ptr - 0x%p\n", Ptr));
+ DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));
+ DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));
+ while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ //
+ // Make sure the descriptor is aligned at UINT64 in memory
+ //
+ if ((UINTN) Ptr & (sizeof(UINT64) - 1)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: BlockList address failed alignment check\n"));
+ return NULL;
+ }
+
+ if (Ptr->Length == 0) {
+ //
+ // Descriptor points to another list of block descriptors somewhere
+ // else.
+ //
+ Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer;
+ if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {
+ return NULL;
+ }
+ DEBUG ((DEBUG_INFO, "Ptr(C) - 0x%p\n", Ptr));
+ DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));
+ DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));
+ } else {
+ if (!ValidateCapsuleByMemoryResource (MemoryResource, Ptr->Union.DataBlock, Ptr->Length)) {
+ return NULL;
+ }
+
+ //
+ //To enhance the reliability of check-up, the first capsule's header is checked here.
+ //More reliabilities check-up will do later.
+ //
+ if (CapsuleSize == 0) {
+ //
+ //Move to the first capsule to check its header.
+ //
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock);
+ //
+ // Sanity check
+ //
+ if (Ptr->Length < sizeof(EFI_CAPSULE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length));
+ return NULL;
+ }
+ //
+ // Make sure HeaderSize field is valid
+ //
+ if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
+ return NULL;
+ }
+ if (IsCapsuleCorrupted (CapsuleHeader)) {
+ return NULL;
+ }
+ CapsuleCount ++;
+ CapsuleSize = CapsuleHeader->CapsuleImageSize;
+ }
+
+ if (CapsuleSize >= Ptr->Length) {
+ CapsuleSize = CapsuleSize - Ptr->Length;
+ } else {
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length));
+ //
+ // Sanity check
+ //
+ return NULL;
+ }
+
+ //
+ // Move to next BLOCK descriptor
+ //
+ Ptr++;
+ if (!ValidateCapsuleByMemoryResource (MemoryResource, (EFI_PHYSICAL_ADDRESS) (UINTN) Ptr, sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR))) {
+ return NULL;
+ }
+ DEBUG ((DEBUG_INFO, "Ptr(B) - 0x%p\n", Ptr));
+ DEBUG ((DEBUG_INFO, "Ptr->Length - 0x%lx\n", Ptr->Length));
+ DEBUG ((DEBUG_INFO, "Ptr->Union - 0x%lx\n", Ptr->Union.ContinuationPointer));
+ }
+ }
+
+ if (CapsuleCount == 0) {
+ //
+ // No any capsule is found in BlockList
+ //
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount));
+ return NULL;
+ }
+
+ if (CapsuleSize != 0) {
+ //
+ // Capsule data is incomplete.
+ //
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize));
+ return NULL;
+ }
+
+ return Ptr;
+}
+
+/**
+ The capsule block descriptors may be fragmented and spread all over memory.
+ To simplify the coalescing of capsule blocks, first coalesce all the
+ capsule block descriptors low in memory.
+
+ The descriptors passed in can be fragmented throughout memory. Here
+ they are relocated into memory to turn them into a contiguous (null
+ terminated) array.
+
+ @param PeiServices pointer to PEI services table
+ @param BlockList pointer to the capsule block descriptors
+ @param NumDescriptors number of capsule data block descriptors, whose Length is non-zero.
+ @param MemBase base of system memory in which we can work
+ @param MemSize size of the system memory pointed to by MemBase
+
+ @retval NULL could not relocate the descriptors
+ @retval Pointer to the base of the successfully-relocated block descriptors.
+
+**/
+EFI_CAPSULE_BLOCK_DESCRIPTOR *
+RelocateBlockDescriptors (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList,
+ IN UINTN NumDescriptors,
+ IN UINT8 *MemBase,
+ IN UINTN MemSize
+ )
+{
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *NewBlockList;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrBlockDescHead;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *PrevBlockDescTail;
+ UINTN BufferSize;
+ UINT8 *RelocBuffer;
+ UINTN BlockListSize;
+
+ //
+ // Get the info on the blocks and descriptors. Since we're going to move
+ // the descriptors low in memory, adjust the base/size values accordingly here.
+ // NumDescriptors is the number of legit data descriptors, so add one for
+ // a terminator. (Already done by caller, no check is needed.)
+ //
+
+ BufferSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ NewBlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) MemBase;
+ if (MemSize < BufferSize) {
+ return NULL;
+ }
+
+ MemSize -= BufferSize;
+ MemBase += BufferSize;
+ //
+ // Go through all the blocks and make sure none are in the way
+ //
+ TempBlockDesc = BlockList;
+ while (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ if (TempBlockDesc->Length == 0) {
+ //
+ // Next block of descriptors
+ //
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ } else {
+ //
+ // If the capsule data pointed to by this descriptor is in the way,
+ // move it.
+ //
+ if (IsOverlapped (
+ (UINT8 *) NewBlockList,
+ BufferSize,
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
+ (UINTN) TempBlockDesc->Length
+ )) {
+ //
+ // Relocate the block
+ //
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, (UINTN) TempBlockDesc->Length);
+ if (RelocBuffer == NULL) {
+ return NULL;
+ }
+
+ CopyMem ((VOID *) RelocBuffer, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
+ DEBUG ((DEBUG_INFO, "Capsule relocate descriptors from/to/size 0x%lX 0x%lX 0x%lX\n", TempBlockDesc->Union.DataBlock, (UINT64)(UINTN)RelocBuffer, TempBlockDesc->Length));
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
+ }
+ TempBlockDesc++;
+ }
+ }
+ //
+ // Now go through all the block descriptors to make sure that they're not
+ // in the memory region we want to copy them to.
+ //
+ CurrBlockDescHead = BlockList;
+ PrevBlockDescTail = NULL;
+ while ((CurrBlockDescHead != NULL) && (CurrBlockDescHead->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ //
+ // Get the size of this list then see if it overlaps our low region
+ //
+ TempBlockDesc = CurrBlockDescHead;
+ BlockListSize = sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ while (TempBlockDesc->Length != 0) {
+ BlockListSize += sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ TempBlockDesc++;
+ }
+
+ if (IsOverlapped (
+ (UINT8 *) NewBlockList,
+ BufferSize,
+ (UINT8 *) CurrBlockDescHead,
+ BlockListSize
+ )) {
+ //
+ // Overlaps, so move it out of the way
+ //
+ RelocBuffer = FindFreeMem (BlockList, MemBase, MemSize, BlockListSize);
+ if (RelocBuffer == NULL) {
+ return NULL;
+ }
+ CopyMem ((VOID *) RelocBuffer, (VOID *) CurrBlockDescHead, BlockListSize);
+ DEBUG ((DEBUG_INFO, "Capsule reloc descriptor block #2\n"));
+ //
+ // Point the previous block's next point to this copied version. If
+ // the tail pointer is null, then this is the first descriptor block.
+ //
+ if (PrevBlockDescTail == NULL) {
+ BlockList = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) RelocBuffer;
+ } else {
+ PrevBlockDescTail->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocBuffer;
+ }
+ }
+ //
+ // Save our new tail and jump to the next block list
+ //
+ PrevBlockDescTail = TempBlockDesc;
+ CurrBlockDescHead = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ }
+ //
+ // Cleared out low memory. Now copy the descriptors down there.
+ //
+ TempBlockDesc = BlockList;
+ CurrBlockDescHead = NewBlockList;
+ while ((TempBlockDesc != NULL) && (TempBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ if (TempBlockDesc->Length != 0) {
+ CurrBlockDescHead->Union.DataBlock = TempBlockDesc->Union.DataBlock;
+ CurrBlockDescHead->Length = TempBlockDesc->Length;
+ CurrBlockDescHead++;
+ TempBlockDesc++;
+ } else {
+ TempBlockDesc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockDesc->Union.ContinuationPointer;
+ }
+ }
+ //
+ // Null terminate
+ //
+ CurrBlockDescHead->Union.ContinuationPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
+ CurrBlockDescHead->Length = 0;
+ return NewBlockList;
+}
+
+/**
+ Determine if two buffers overlap in memory.
+
+ @param Buff1 pointer to first buffer
+ @param Size1 size of Buff1
+ @param Buff2 pointer to second buffer
+ @param Size2 size of Buff2
+
+ @retval TRUE Buffers overlap in memory.
+ @retval FALSE Buffer doesn't overlap.
+
+**/
+BOOLEAN
+IsOverlapped (
+ UINT8 *Buff1,
+ UINTN Size1,
+ UINT8 *Buff2,
+ UINTN Size2
+ )
+{
+ //
+ // If buff1's end is less than the start of buff2, then it's ok.
+ // Also, if buff1's start is beyond buff2's end, then it's ok.
+ //
+ if (((Buff1 + Size1) <= Buff2) || (Buff1 >= (Buff2 + Size2))) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Given a pointer to a capsule block descriptor, traverse the list to figure
+ out how many legitimate descriptors there are, and how big the capsule it
+ refers to is.
+
+ @param Desc Pointer to the capsule block descriptors
+ @param NumDescriptors Optional pointer to where to return the number of capsule data descriptors, whose Length is non-zero.
+ @param CapsuleSize Optional pointer to where to return the capsule image size
+ @param CapsuleNumber Optional pointer to where to return the number of capsule
+
+ @retval EFI_NOT_FOUND No descriptors containing data in the list
+ @retval EFI_SUCCESS Return data is valid
+
+**/
+EFI_STATUS
+GetCapsuleInfo (
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc,
+ IN OUT UINTN *NumDescriptors OPTIONAL,
+ IN OUT UINTN *CapsuleSize OPTIONAL,
+ IN OUT UINTN *CapsuleNumber OPTIONAL
+ )
+{
+ UINTN Count;
+ UINTN Size;
+ UINTN Number;
+ UINTN ThisCapsuleImageSize;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+
+ DEBUG ((DEBUG_INFO, "GetCapsuleInfo enter\n"));
+
+ ASSERT (Desc != NULL);
+
+ Count = 0;
+ Size = 0;
+ Number = 0;
+ ThisCapsuleImageSize = 0;
+
+ while (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ if (Desc->Length == 0) {
+ //
+ // Descriptor points to another list of block descriptors somewhere
+ //
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ } else {
+ //
+ // Sanity Check
+ // It is needed, because ValidateCapsuleIntegrity() only validate one individual capsule Size.
+ // While here we need check all capsules size.
+ //
+ if (Desc->Length >= (MAX_ADDRESS - Size)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Desc->Length(0x%lx) >= (MAX_ADDRESS - Size(0x%x))\n", Desc->Length, Size));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Size += (UINTN) Desc->Length;
+ Count++;
+
+ //
+ // See if this is first capsule's header
+ //
+ if (ThisCapsuleImageSize == 0) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Desc->Union.DataBlock);
+ //
+ // This has been checked in ValidateCapsuleIntegrity()
+ //
+ Number ++;
+ ThisCapsuleImageSize = CapsuleHeader->CapsuleImageSize;
+ }
+
+ //
+ // This has been checked in ValidateCapsuleIntegrity()
+ //
+ ASSERT (ThisCapsuleImageSize >= Desc->Length);
+ ThisCapsuleImageSize = (UINTN)(ThisCapsuleImageSize - Desc->Length);
+
+ //
+ // Move to next
+ //
+ Desc++;
+ }
+ }
+ //
+ // If no descriptors, then fail
+ //
+ if (Count == 0) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Count == 0\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // checked in ValidateCapsuleIntegrity()
+ //
+ ASSERT (ThisCapsuleImageSize == 0);
+
+ if (NumDescriptors != NULL) {
+ *NumDescriptors = Count;
+ }
+
+ if (CapsuleSize != NULL) {
+ *CapsuleSize = Size;
+ }
+
+ if (CapsuleNumber != NULL) {
+ *CapsuleNumber = Number;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check every capsule header.
+
+ @param CapsuleHeader The pointer to EFI_CAPSULE_HEADER
+
+ @retval FALSE Capsule is OK
+ @retval TRUE Capsule is corrupted
+
+**/
+BOOLEAN
+IsCapsuleCorrupted (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ //
+ //A capsule to be updated across a system reset should contain CAPSULE_FLAGS_PERSIST_ACROSS_RESET.
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+ return TRUE;
+ }
+ //
+ //Make sure the flags combination is supported by the platform.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return TRUE;
+ }
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Try to verify the integrity of a capsule test pattern before the
+ capsule gets coalesced. This can be useful in narrowing down
+ where capsule data corruption occurs.
+
+ The test pattern mode fills in memory with a counting UINT32 value.
+ If the capsule is not divided up in a multiple of 4-byte blocks, then
+ things get messy doing the check. Therefore there are some cases
+ here where we just give up and skip the pre-coalesce check.
+
+ @param PeiServices PEI services table
+ @param Desc Pointer to capsule descriptors
+**/
+VOID
+CapsuleTestPatternPreCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc
+ )
+{
+ UINT32 *TestPtr;
+ UINT32 TestCounter;
+ UINT32 TestSize;
+
+ DEBUG ((DEBUG_INFO, "CapsuleTestPatternPreCoalesce\n"));
+
+ //
+ // Find first data descriptor
+ //
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ }
+
+ if (Desc->Union.ContinuationPointer == 0) {
+ return ;
+ }
+ //
+ // First one better be long enough to at least hold the test signature
+ //
+ if (Desc->Length < sizeof (UINT32)) {
+ DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #1\n"));
+ return ;
+ }
+
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
+ //
+ // 0x54534554 "TEST"
+ //
+ if (*TestPtr != 0x54534554) {
+ return ;
+ }
+
+ TestCounter = 0;
+ TestSize = (UINT32) Desc->Length - 2 * sizeof (UINT32);
+ //
+ // Skip over the signature and the size fields in the pattern data header
+ //
+ TestPtr += 2;
+ while (1) {
+ if ((TestSize & 0x03) != 0) {
+ DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce punted #2\n"));
+ return ;
+ }
+
+ while (TestSize > 0) {
+ if (*TestPtr != TestCounter) {
+ DEBUG ((DEBUG_INFO, "Capsule test pattern pre-coalesce failed data corruption check\n"));
+ return ;
+ }
+
+ TestSize -= sizeof (UINT32);
+ TestCounter++;
+ TestPtr++;
+ }
+ Desc++;
+ while ((Desc->Length == 0) && (Desc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Desc->Union.ContinuationPointer;
+ }
+
+ if (Desc->Union.ContinuationPointer == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ return ;
+ }
+ TestSize = (UINT32) Desc->Length;
+ TestPtr = (UINT32 *) (UINTN) Desc->Union.DataBlock;
+ }
+}
+
+/**
+ Checks for the presence of capsule descriptors.
+ Get capsule descriptors from variable CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+
+ @param BlockListBuffer Pointer to the buffer of capsule descriptors variables
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+ @param BlockDescriptorList Pointer to the capsule descriptors list
+
+ @retval EFI_SUCCESS a valid capsule is present
+ @retval EFI_NOT_FOUND if a valid capsule is not present
+**/
+EFI_STATUS
+BuildCapsuleDescriptors (
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptorList
+ )
+{
+ UINTN Index;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *LastBlock;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlock;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *HeadBlock;
+
+ DEBUG ((DEBUG_INFO, "BuildCapsuleDescriptors enter\n"));
+
+ LastBlock = NULL;
+ HeadBlock = NULL;
+ TempBlock = NULL;
+ Index = 0;
+
+ while (BlockListBuffer[Index] != 0) {
+ //
+ // Test integrity of descriptors.
+ //
+ if (BlockListBuffer[Index] < MAX_ADDRESS) {
+ TempBlock = ValidateCapsuleIntegrity ((EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index], MemoryResource);
+ if (TempBlock != NULL) {
+ if (LastBlock == NULL) {
+ LastBlock = TempBlock;
+
+ //
+ // Return the base of the block descriptors
+ //
+ HeadBlock = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)BlockListBuffer[Index];
+ } else {
+ //
+ // Combine the different BlockList into single BlockList.
+ //
+ LastBlock->Union.DataBlock = (EFI_PHYSICAL_ADDRESS)(UINTN)BlockListBuffer[Index];
+ LastBlock->Length = 0;
+ LastBlock = TempBlock;
+ }
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "ERROR: BlockListBuffer[Index](0x%lx) < MAX_ADDRESS\n", BlockListBuffer[Index]));
+ }
+ Index ++;
+ }
+
+ if (HeadBlock != NULL) {
+ *BlockDescriptorList = HeadBlock;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ The function to coalesce a fragmented capsule in memory.
+
+ Memory Map for coalesced capsule:
+ MemBase + ---->+---------------------------+<-----------+
+ MemSize | ------------------------- | |
+ | | Capsule [Num-1] | | |
+ | ------------------------- | |
+ | | ................ | | |
+ | ------------------------- | |
+ | | Capsule [1] | | |
+ | ------------------------- | |
+ | | Capsule [0] | | |
+ | ------------------------- | |
+ | Capsule Image | |
+CapsuleImageBase-->+---------------------------+
+ | ------------------------- | |
+ | | CapsuleOffset[Num-1] | | |
+ | ------------------------- | |
+ | | ................ | | CapsuleSize
+ | ------------------------- | |
+ | | CapsuleOffset[1] | | |
+ | ------------------------- | |
+ | | CapsuleOffset[0] | | |
+ |---------------------------| |
+ | | CapsuleNumber | | |
+ | ------------------------- | |
+ | | CapsuleAllImageSize | | |
+ | ------------------------- | |
+ | PrivateData | |
+ DestPtr ---->+---------------------------+<-----------+
+ | | |
+ | FreeMem | FreeMemSize
+ | | |
+ FreeMemBase --->+---------------------------+<-----------+
+ | Terminator |
+ +---------------------------+
+ | BlockDescriptor n |
+ +---------------------------+
+ | ................. |
+ +---------------------------+
+ | BlockDescriptor 1 |
+ +---------------------------+
+ | BlockDescriptor 0 |
+ +---------------------------+
+ | PrivateDataDesc 0 |
+ MemBase ---->+---------------------------+<----- BlockList
+
+ Caution: This function may receive untrusted input.
+ The capsule data is external input, so this routine will do basic validation before
+ coalesce capsule data into memory.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param BlockListBuffer Pointer to the buffer of Capsule Descriptor Variables.
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+ @param MemoryBase Pointer to the base of a block of memory that we can walk
+ all over while trying to coalesce our buffers.
+ On output, this variable will hold the base address of
+ a coalesced capsule.
+ @param MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND If we could not find the capsule descriptors.
+
+ @retval EFI_BUFFER_TOO_SMALL
+ If we could not coalesce the capsule in the memory
+ region provided to us.
+
+ @retval EFI_SUCCESS Processed the capsule successfully.
+**/
+EFI_STATUS
+EFIAPI
+CapsuleDataCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ )
+{
+ VOID *NewCapsuleBase;
+ VOID *CapsuleImageBase;
+ UINTN CapsuleIndex;
+ UINT8 *FreeMemBase;
+ UINT8 *DestPtr;
+ UINTN DestLength;
+ UINT8 *RelocPtr;
+ UINTN CapsuleTimes;
+ UINT64 SizeLeft;
+ UINT64 CapsuleImageSize;
+ UINTN CapsuleSize;
+ UINTN CapsuleNumber;
+ UINTN DescriptorsSize;
+ UINTN FreeMemSize;
+ UINTN NumDescriptors;
+ BOOLEAN CapsuleBeginFlag;
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ EFI_CAPSULE_PEIM_PRIVATE_DATA PrivateData;
+ EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateDataPtr;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *CurrentBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockDesc;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR PrivateDataDesc[2];
+
+ DEBUG ((DEBUG_INFO, "CapsuleDataCoalesce enter\n"));
+
+ CapsuleIndex = 0;
+ SizeLeft = 0;
+ CapsuleTimes = 0;
+ CapsuleImageSize = 0;
+ PrivateDataPtr = NULL;
+ CapsuleHeader = NULL;
+ CapsuleBeginFlag = TRUE;
+ CapsuleSize = 0;
+ NumDescriptors = 0;
+
+ //
+ // Build capsule descriptors list
+ //
+ Status = BuildCapsuleDescriptors (BlockListBuffer, MemoryResource, &BlockList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG_CODE (
+ CapsuleTestPatternPreCoalesce (PeiServices, BlockList);
+ );
+
+ //
+ // Get the size of our descriptors and the capsule size. GetCapsuleInfo()
+ // returns the number of descriptors that actually point to data, so add
+ // one for a terminator. Do that below.
+ //
+ Status = GetCapsuleInfo (BlockList, &NumDescriptors, &CapsuleSize, &CapsuleNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "CapsuleSize - 0x%x\n", CapsuleSize));
+ DEBUG ((DEBUG_INFO, "CapsuleNumber - 0x%x\n", CapsuleNumber));
+ DEBUG ((DEBUG_INFO, "NumDescriptors - 0x%x\n", NumDescriptors));
+ if ((CapsuleSize == 0) || (NumDescriptors == 0) || (CapsuleNumber == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (CapsuleNumber - 1 >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + sizeof(UINT64))) / sizeof(UINT64)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleNumber - 0x%x\n", CapsuleNumber));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Initialize our local copy of private data. When we're done, we'll create a
+ // descriptor for it as well so that it can be put into free memory without
+ // trashing anything.
+ //
+ PrivateData.Signature = EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE;
+ PrivateData.CapsuleAllImageSize = (UINT64) CapsuleSize;
+ PrivateData.CapsuleNumber = (UINT64) CapsuleNumber;
+ PrivateData.CapsuleOffset[0] = 0;
+ //
+ // NOTE: Only data in sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) is valid, CapsuleOffset field is uninitialized at this moment.
+ // The code sets partial length here for Descriptor.Length check, but later it will use full length to reserve those PrivateData region.
+ //
+ PrivateDataDesc[0].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) &PrivateData;
+ PrivateDataDesc[0].Length = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA);
+ PrivateDataDesc[1].Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) BlockList;
+ PrivateDataDesc[1].Length = 0;
+ //
+ // Add PrivateDataDesc[0] in beginning, as it is new descriptor. PrivateDataDesc[1] is NOT needed.
+ // In addition, one NULL terminator is added in the end. See RelocateBlockDescriptors().
+ //
+ NumDescriptors += 2;
+ //
+ // Sanity check
+ //
+ if (CapsuleSize >= (MAX_ADDRESS - (sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64)))) {
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize - 0x%x\n", CapsuleSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Need add sizeof(UINT64) for PrivateData alignment
+ //
+ CapsuleSize += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64) + sizeof(UINT64);
+ BlockList = PrivateDataDesc;
+ //
+ // Sanity check
+ //
+ if (NumDescriptors >= (MAX_ADDRESS / sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR))) {
+ DEBUG ((DEBUG_ERROR, "ERROR: NumDescriptors - 0x%x\n", NumDescriptors));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ DescriptorsSize = NumDescriptors * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+ //
+ // Sanity check
+ //
+ if (DescriptorsSize >= (MAX_ADDRESS - CapsuleSize)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: DescriptorsSize - 0x%lx, CapsuleSize - 0x%lx\n", (UINT64)DescriptorsSize, (UINT64)CapsuleSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Don't go below some min address. If the base is below it,
+ // then move it up and adjust the size accordingly.
+ //
+ DEBUG ((DEBUG_INFO, "Capsule Memory range from 0x%8X to 0x%8X\n", (UINTN) *MemoryBase, (UINTN)*MemoryBase + *MemorySize));
+ if ((UINTN)*MemoryBase < (UINTN) MIN_COALESCE_ADDR) {
+ if (((UINTN)*MemoryBase + *MemorySize) < (UINTN) MIN_COALESCE_ADDR) {
+ DEBUG ((DEBUG_ERROR, "ERROR: *MemoryBase + *MemorySize - 0x%x\n", (UINTN)*MemoryBase + *MemorySize));
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ *MemorySize = *MemorySize - ((UINTN) MIN_COALESCE_ADDR - (UINTN) *MemoryBase);
+ *MemoryBase = (VOID *) (UINTN) MIN_COALESCE_ADDR;
+ }
+ }
+
+ if (*MemorySize <= (CapsuleSize + DescriptorsSize)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: CapsuleSize + DescriptorsSize - 0x%x\n", CapsuleSize + DescriptorsSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FreeMemBase = *MemoryBase;
+ FreeMemSize = *MemorySize;
+ DEBUG ((DEBUG_INFO, "Capsule Free Memory from 0x%8X to 0x%8X\n", (UINTN) FreeMemBase, (UINTN) FreeMemBase + FreeMemSize));
+
+ //
+ // Relocate all the block descriptors to low memory to make further
+ // processing easier.
+ //
+ BlockList = RelocateBlockDescriptors (PeiServices, BlockList, NumDescriptors, FreeMemBase, FreeMemSize);
+ if (BlockList == NULL) {
+ //
+ // Not enough room to relocate the descriptors
+ //
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Take the top of memory for the capsule. UINT64 align up.
+ //
+ DestPtr = FreeMemBase + FreeMemSize - CapsuleSize;
+ DestPtr = (UINT8 *) (((UINTN)DestPtr + sizeof (UINT64) - 1) & ~(sizeof (UINT64) - 1));
+ FreeMemBase = (UINT8 *) BlockList + DescriptorsSize;
+ FreeMemSize = (UINTN) DestPtr - (UINTN) FreeMemBase;
+ NewCapsuleBase = (VOID *) DestPtr;
+ CapsuleImageBase = (UINT8 *)NewCapsuleBase + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);
+
+ PrivateDataPtr = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) NewCapsuleBase;
+
+ //
+ // Move all the blocks to the top (high) of memory.
+ // Relocate all the obstructing blocks. Note that the block descriptors
+ // were coalesced when they were relocated, so we can just ++ the pointer.
+ //
+ CurrentBlockDesc = BlockList;
+ while ((CurrentBlockDesc->Length != 0) || (CurrentBlockDesc->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) {
+ if (CapsuleTimes == 0) {
+ //
+ // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
+ // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.
+ //
+ ASSERT (CurrentBlockDesc->Union.DataBlock == (UINT64)(UINTN)&PrivateData);
+ DestLength = sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);
+ } else {
+ DestLength = (UINTN)CurrentBlockDesc->Length;
+ }
+ //
+ // See if any of the remaining capsule blocks are in the way
+ //
+ TempBlockDesc = CurrentBlockDesc;
+ while (TempBlockDesc->Length != 0) {
+ //
+ // Is this block in the way of where we want to copy the current descriptor to?
+ //
+ if (IsOverlapped (
+ (UINT8 *) DestPtr,
+ (UINTN) DestLength,
+ (UINT8 *) (UINTN) TempBlockDesc->Union.DataBlock,
+ (UINTN) TempBlockDesc->Length
+ )) {
+ //
+ // Relocate the block
+ //
+ RelocPtr = FindFreeMem (BlockList, FreeMemBase, FreeMemSize, (UINTN) TempBlockDesc->Length);
+ if (RelocPtr == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem ((VOID *) RelocPtr, (VOID *) (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) TempBlockDesc->Length);
+ DEBUG ((DEBUG_INFO, "Capsule reloc data block from 0x%8X to 0x%8X with size 0x%8X\n",
+ (UINTN) TempBlockDesc->Union.DataBlock, (UINTN) RelocPtr, (UINTN) TempBlockDesc->Length));
+
+ TempBlockDesc->Union.DataBlock = (EFI_PHYSICAL_ADDRESS) (UINTN) RelocPtr;
+ }
+ //
+ // Next descriptor
+ //
+ TempBlockDesc++;
+ }
+ //
+ // Ok, we made it through. Copy the block.
+ // we just support greping one capsule from the lists of block descs list.
+ //
+ CapsuleTimes ++;
+ //
+ //Skip the first block descriptor that filled with EFI_CAPSULE_PEIM_PRIVATE_DATA
+ //
+ if (CapsuleTimes > 1) {
+ //
+ //For every capsule entry point, check its header to determine whether to relocate it.
+ //If it is invalid, skip it and move on to the next capsule. If it is valid, relocate it.
+ //
+ if (CapsuleBeginFlag) {
+ CapsuleBeginFlag = FALSE;
+ CapsuleHeader = (EFI_CAPSULE_HEADER*)(UINTN)CurrentBlockDesc->Union.DataBlock;
+ SizeLeft = CapsuleHeader->CapsuleImageSize;
+
+ //
+ // No more check here is needed, because IsCapsuleCorrupted() already in ValidateCapsuleIntegrity()
+ //
+ ASSERT (CapsuleIndex < CapsuleNumber);
+
+ //
+ // Relocate this capsule
+ //
+ CapsuleImageSize += SizeLeft;
+ //
+ // Cache the begin offset of this capsule
+ //
+ ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);
+ ASSERT ((UINTN)DestPtr >= (UINTN)CapsuleImageBase);
+ PrivateDataPtr->CapsuleOffset[CapsuleIndex++] = (UINTN)DestPtr - (UINTN)CapsuleImageBase;
+ }
+
+ //
+ // Below ASSERT is checked in ValidateCapsuleIntegrity()
+ //
+ ASSERT (CurrentBlockDesc->Length <= SizeLeft);
+
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) (CurrentBlockDesc->Union.DataBlock), (UINTN)CurrentBlockDesc->Length);
+ DEBUG ((DEBUG_INFO, "Capsule coalesce block no.0x%lX from 0x%lX to 0x%lX with size 0x%lX\n",(UINT64)CapsuleTimes,
+ CurrentBlockDesc->Union.DataBlock, (UINT64)(UINTN)DestPtr, CurrentBlockDesc->Length));
+ DestPtr += CurrentBlockDesc->Length;
+ SizeLeft -= CurrentBlockDesc->Length;
+
+ if (SizeLeft == 0) {
+ //
+ //Here is the end of the current capsule image.
+ //
+ CapsuleBeginFlag = TRUE;
+ }
+ } else {
+ //
+ // The first entry is the block descriptor for EFI_CAPSULE_PEIM_PRIVATE_DATA.
+ // CapsuleOffset field is uninitialized at this time. No need copy it, but need to reserve for future use.
+ //
+ ASSERT (CurrentBlockDesc->Length == sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA));
+ ASSERT ((UINTN)DestPtr == (UINTN)NewCapsuleBase);
+ CopyMem ((VOID *) DestPtr, (VOID *) (UINTN) CurrentBlockDesc->Union.DataBlock, (UINTN) CurrentBlockDesc->Length);
+ DestPtr += sizeof (EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64);
+ }
+ //
+ //Walk through the block descriptor list.
+ //
+ CurrentBlockDesc++;
+ }
+ //
+ // We return the base of memory we want reserved, and the size.
+ // The memory peim should handle it appropriately from there.
+ //
+ *MemorySize = (UINTN) CapsuleSize;
+ *MemoryBase = (VOID *) NewCapsuleBase;
+
+ ASSERT (PrivateDataPtr->Signature == EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE);
+ ASSERT (PrivateDataPtr->CapsuleAllImageSize == CapsuleImageSize);
+ ASSERT (PrivateDataPtr->CapsuleNumber == CapsuleIndex);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h
new file mode 100644
index 000000000..695520aa2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/Common/CommonHeader.h
@@ -0,0 +1,115 @@
+/** @file
+ Common header file.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CAPSULE_COMMON_HEADER_
+#define _CAPSULE_COMMON_HEADER_
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+//
+// This capsule PEIM puts its private data at the start of the
+// coalesced capsule. Here's the structure definition.
+//
+#define EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('C', 'a', 'p', 'P')
+
+#pragma pack(1)
+typedef struct {
+ UINT64 Signature;
+ UINT64 CapsuleAllImageSize;
+ UINT64 CapsuleNumber;
+ UINT64 CapsuleOffset[1];
+} EFI_CAPSULE_PEIM_PRIVATE_DATA;
+#pragma pack()
+
+typedef struct {
+ ///
+ /// The physical start address of the resource region.
+ ///
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ ///
+ /// The number of bytes of the resource region.
+ ///
+ UINT64 ResourceLength;
+} MEMORY_RESOURCE_DESCRIPTOR;
+
+#define CAPSULE_TEST_SIGNATURE SIGNATURE_32('T', 'E', 'S', 'T')
+
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+#pragma pack(1)
+typedef struct {
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PHYSICAL_ADDRESS StackBufferBase;
+ UINT64 StackBufferLength;
+ EFI_PHYSICAL_ADDRESS JumpBuffer;
+ EFI_PHYSICAL_ADDRESS BlockListAddr;
+ EFI_PHYSICAL_ADDRESS MemoryResource;
+ EFI_PHYSICAL_ADDRESS MemoryBase64Ptr;
+ EFI_PHYSICAL_ADDRESS MemorySize64Ptr;
+ BOOLEAN Page1GSupport;
+ UINT64 AddressEncMask;
+} SWITCH_32_TO_64_CONTEXT;
+
+typedef struct {
+ UINT16 ReturnCs;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ UINT64 ReturnStatus;
+ //
+ // NOTICE:
+ // Be careful about the Base field of IA32_DESCRIPTOR
+ // that is UINTN type.
+ // To extend new field for this structure, add it to
+ // right before this Gdtr field.
+ //
+ IA32_DESCRIPTOR Gdtr;
+} SWITCH_64_TO_32_CONTEXT;
+#pragma pack()
+#endif
+
+/**
+ The function to coalesce a fragmented capsule in memory.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param BlockListBuffer Point to the buffer of Capsule Descriptor Variables.
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+ @param MemoryBase Pointer to the base of a block of memory that we can walk
+ all over while trying to coalesce our buffers.
+ On output, this variable will hold the base address of
+ a coalesced capsule.
+ @param MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND if we can't determine the boot mode
+ if the boot mode is not flash-update
+ if we could not find the capsule descriptors
+
+ @retval EFI_BUFFER_TOO_SMALL
+ if we could not coalesce the capsule in the memory
+ region provided to us
+
+ @retval EFI_SUCCESS if there's no capsule, or if we processed the
+ capsule successfully.
+**/
+EFI_STATUS
+EFIAPI
+CapsuleDataCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS *BlockListBuffer,
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c b/roms/edk2/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
new file mode 100644
index 000000000..51afab7b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c
@@ -0,0 +1,1332 @@
+/** @file
+ Capsule update PEIM for UEFI2.0
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Capsule.h"
+
+#define DEFAULT_SG_LIST_HEADS (20)
+
+#ifdef MDE_CPU_IA32
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR mGdtEntries[] = {
+/* selector { Global Segment Descriptor } */
+/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
+/* 0x08 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
+/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
+/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x20 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
+/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x30 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x38 */ {{0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
+/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+
+
+/**
+ The function will check if 1G page is supported.
+
+ @retval TRUE 1G page is supported.
+ @retval FALSE 1G page is not supported.
+
+**/
+BOOLEAN
+IsPage1GSupport (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ 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;
+ }
+ }
+ }
+
+ return Page1GSupport;
+}
+
+/**
+ Calculate the total size of page table.
+
+ @param[in] Page1GSupport 1G page support or not.
+
+ @return The size of page table.
+
+**/
+UINTN
+CalculatePageTableSize (
+ IN BOOLEAN Page1GSupport
+ )
+{
+ UINTN ExtraPageTablePages;
+ UINTN TotalPagesNum;
+ UINT8 PhysicalAddressBits;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+
+ //
+ // Create 4G page table by default,
+ // 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;
+ }
+
+ if (!Page1GSupport) {
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+ } else {
+ TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
+ }
+ TotalPagesNum += ExtraPageTablePages;
+
+ return EFI_PAGES_TO_SIZE (TotalPagesNum);
+}
+
+/**
+ Allocates and fills in the Page Directory and Page Table Entries to
+ establish a 4G page table.
+
+ @param[in] PageTablesAddress The base address of page table.
+ @param[in] Page1GSupport 1G page support or not.
+
+**/
+VOID
+Create4GPageTables (
+ IN EFI_PHYSICAL_ADDRESS PageTablesAddress,
+ IN BOOLEAN Page1GSupport
+ )
+{
+ UINT8 PhysicalAddressBits;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ UINTN IndexOfPml4Entries;
+ UINTN IndexOfPdpEntries;
+ UINTN IndexOfPageDirectoryEntries;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINTN BigPageAddress;
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
+ UINT64 AddressEncMask;
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field.
+ //
+ AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ //
+ // Create 4G page table by default,
+ // and let PF handler to handle > 4G request.
+ //
+ PhysicalAddressBits = 32;
+
+ //
+ // 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;
+ }
+
+ //
+ // Pre-allocate big pages to avoid later allocations.
+ //
+ BigPageAddress = (UINTN) PageTablesAddress;
+
+ //
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+ //
+ PageMap = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ PageMapLevel4Entry = PageMap;
+ PageAddress = 0;
+ for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+ //
+ // Each PML4 entry points to a page of Page Directory Pointer entires.
+ // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
+ //
+ PageDirectoryPointerEntry = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ //
+ // Make a PML4 Entry
+ //
+ PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;
+ PageMapLevel4Entry->Bits.ReadWrite = 1;
+ PageMapLevel4Entry->Bits.Present = 1;
+
+ if (Page1GSupport) {
+ PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
+ PageDirectory1GEntry->Bits.ReadWrite = 1;
+ PageDirectory1GEntry->Bits.Present = 1;
+ PageDirectory1GEntry->Bits.MustBe1 = 1;
+ }
+ } else {
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+ //
+ // Each Directory Pointer entries points to a page of Page Directory entires.
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
+ //
+ PageDirectoryEntry = (VOID *) BigPageAddress;
+ BigPageAddress += SIZE_4KB;
+
+ //
+ // Fill in a Page Directory Pointer Entries
+ //
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;
+ PageDirectoryPointerEntry->Bits.ReadWrite = 1;
+ PageDirectoryPointerEntry->Bits.Present = 1;
+
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+
+ for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+ ZeroMem (
+ PageDirectoryPointerEntry,
+ sizeof(PAGE_MAP_AND_DIRECTORY_POINTER)
+ );
+ }
+ }
+ }
+
+ //
+ // For the PML4 entries we are not using fill in a null entry.
+ //
+ for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+ ZeroMem (
+ PageMapLevel4Entry,
+ sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
+ );
+ }
+}
+
+/**
+ Return function from long mode to 32-bit mode.
+
+ @param EntrypointContext Context for mode switching
+ @param ReturnContext Context for mode switching
+
+**/
+VOID
+ReturnFunction (
+ SWITCH_32_TO_64_CONTEXT *EntrypointContext,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+ )
+{
+ //
+ // Restore original GDT
+ //
+ AsmWriteGdtr (&ReturnContext->Gdtr);
+
+ //
+ // return to original caller
+ //
+ LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)EntrypointContext->JumpBuffer, 1);
+
+ //
+ // never be here
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Thunk function from 32-bit protection mode to long mode.
+
+ @param PageTableAddress Page table base address
+ @param Context Context for mode switching
+ @param ReturnContext Context for mode switching
+
+ @retval EFI_SUCCESS Function successfully executed.
+
+**/
+EFI_STATUS
+Thunk32To64 (
+ EFI_PHYSICAL_ADDRESS PageTableAddress,
+ SWITCH_32_TO_64_CONTEXT *Context,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+ )
+{
+ UINTN SetJumpFlag;
+ EFI_STATUS Status;
+
+ //
+ // Save return address, LongJump will return here then
+ //
+ SetJumpFlag = SetJump ((BASE_LIBRARY_JUMP_BUFFER *) (UINTN) Context->JumpBuffer);
+
+ if (SetJumpFlag == 0) {
+
+ //
+ // Build 4G Page Tables.
+ //
+ Create4GPageTables (PageTableAddress, Context->Page1GSupport);
+
+ //
+ // Create 64-bit GDT
+ //
+ AsmWriteGdtr (&mGdt);
+
+ //
+ // Write CR3
+ //
+ AsmWriteCr3 ((UINTN) PageTableAddress);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n",
+ __FUNCTION__,
+ Context->StackBufferBase,
+ Context->StackBufferLength
+ ));
+
+ //
+ // Disable interrupt of Debug timer, since the IDT table cannot work in long mode
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+ //
+ // Transfer to long mode
+ //
+ AsmEnablePaging64 (
+ 0x38,
+ (UINT64) Context->EntryPoint,
+ (UINT64)(UINTN) Context,
+ (UINT64)(UINTN) ReturnContext,
+ Context->StackBufferBase + Context->StackBufferLength
+ );
+ }
+
+ //
+ // Convert to 32-bit Status and return
+ //
+ Status = EFI_SUCCESS;
+ if ((UINTN) ReturnContext->ReturnStatus != 0) {
+ Status = ENCODE_ERROR ((UINTN) ReturnContext->ReturnStatus);
+ }
+
+ return Status;
+}
+
+/**
+ If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
+
+ @param LongModeBuffer The context of long mode.
+ @param CoalesceEntry Entry of coalesce image.
+ @param BlockListAddr Address of block list.
+ @param MemoryResource Pointer to the buffer of memory resource descriptor.
+ @param MemoryBase Base of memory range.
+ @param MemorySize Size of memory range.
+
+ @retval EFI_SUCCESS Successfully switched to long mode and execute coalesce.
+ @retval Others Failed to execute coalesce in long mode.
+
+**/
+EFI_STATUS
+ModeSwitch (
+ IN EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer,
+ IN COALESCE_ENTRY CoalesceEntry,
+ IN EFI_PHYSICAL_ADDRESS BlockListAddr,
+ IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryBase64;
+ UINT64 MemorySize64;
+ EFI_PHYSICAL_ADDRESS MemoryEnd64;
+ SWITCH_32_TO_64_CONTEXT Context;
+ SWITCH_64_TO_32_CONTEXT ReturnContext;
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+ EFI_PHYSICAL_ADDRESS ReservedRangeBase;
+ EFI_PHYSICAL_ADDRESS ReservedRangeEnd;
+ BOOLEAN Page1GSupport;
+
+ ZeroMem (&Context, sizeof (SWITCH_32_TO_64_CONTEXT));
+ ZeroMem (&ReturnContext, sizeof (SWITCH_64_TO_32_CONTEXT));
+
+ MemoryBase64 = (UINT64) (UINTN) *MemoryBase;
+ MemorySize64 = (UINT64) (UINTN) *MemorySize;
+ MemoryEnd64 = MemoryBase64 + MemorySize64;
+
+ Page1GSupport = IsPage1GSupport ();
+
+ //
+ // Merge memory range reserved for stack and page table
+ //
+ if (LongModeBuffer->StackBaseAddress < LongModeBuffer->PageTableAddress) {
+ ReservedRangeBase = LongModeBuffer->StackBaseAddress;
+ ReservedRangeEnd = LongModeBuffer->PageTableAddress + CalculatePageTableSize (Page1GSupport);
+ } else {
+ ReservedRangeBase = LongModeBuffer->PageTableAddress;
+ ReservedRangeEnd = LongModeBuffer->StackBaseAddress + LongModeBuffer->StackSize;
+ }
+
+ //
+ // Check if memory range reserved is overlap with MemoryBase ~ MemoryBase + MemorySize.
+ // If they are overlapped, get a larger range to process capsule data.
+ //
+ if (ReservedRangeBase <= MemoryBase64) {
+ if (ReservedRangeEnd < MemoryEnd64) {
+ MemoryBase64 = ReservedRangeEnd;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Memory is not enough to process capsule!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (ReservedRangeBase < MemoryEnd64) {
+ if (ReservedRangeEnd < MemoryEnd64 &&
+ ReservedRangeBase - MemoryBase64 < MemoryEnd64 - ReservedRangeEnd) {
+ MemoryBase64 = ReservedRangeEnd;
+ } else {
+ MemorySize64 = (UINT64)(UINTN)(ReservedRangeBase - MemoryBase64);
+ }
+ }
+
+ //
+ // Initialize context jumping to 64-bit enviroment
+ //
+ Context.JumpBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)&JumpBuffer;
+ Context.StackBufferBase = LongModeBuffer->StackBaseAddress;
+ Context.StackBufferLength = LongModeBuffer->StackSize;
+ Context.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)CoalesceEntry;
+ Context.BlockListAddr = BlockListAddr;
+ Context.MemoryResource = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryResource;
+ Context.MemoryBase64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemoryBase64;
+ Context.MemorySize64Ptr = (EFI_PHYSICAL_ADDRESS)(UINTN)&MemorySize64;
+ Context.Page1GSupport = Page1GSupport;
+ Context.AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ //
+ // Prepare data for return back
+ //
+ ReturnContext.ReturnCs = 0x10;
+ ReturnContext.ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)ReturnFunction;
+ //
+ // Will save the return status of processing capsule
+ //
+ ReturnContext.ReturnStatus = 0;
+
+ //
+ // Save original GDT
+ //
+ AsmReadGdtr ((IA32_DESCRIPTOR *)&ReturnContext.Gdtr);
+
+ Status = Thunk32To64 (LongModeBuffer->PageTableAddress, &Context, &ReturnContext);
+
+ if (!EFI_ERROR (Status)) {
+ *MemoryBase = (VOID *) (UINTN) MemoryBase64;
+ *MemorySize = (UINTN) MemorySize64;
+ }
+
+ return Status;
+
+}
+
+/**
+ Locates the coalesce image entry point, and detects its machine type.
+
+ @param CoalesceImageEntryPoint Pointer to coalesce image entry point for output.
+ @param CoalesceImageMachineType Pointer to machine type of coalesce image.
+
+ @retval EFI_SUCCESS Coalesce image successfully located.
+ @retval Others Failed to locate the coalesce image.
+
+**/
+EFI_STATUS
+FindCapsuleCoalesceImage (
+ OUT EFI_PHYSICAL_ADDRESS *CoalesceImageEntryPoint,
+ OUT UINT16 *CoalesceImageMachineType
+ )
+{
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ EFI_PHYSICAL_ADDRESS CoalesceImageAddress;
+ UINT64 CoalesceImageSize;
+ UINT32 AuthenticationState;
+
+ Instance = 0;
+
+ while (TRUE) {
+ Status = PeiServicesFfsFindNextVolume (Instance++, &VolumeHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = PeiServicesFfsFindFileByName (PcdGetPtr(PcdCapsuleCoalesceFile), VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, 0, NULL, (VOID **) &LoadFile);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &CoalesceImageAddress,
+ &CoalesceImageSize,
+ CoalesceImageEntryPoint,
+ &AuthenticationState
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to find PE32 section in CapsuleX64 image ffs %r!\n", Status));
+ return Status;
+ }
+ *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *) (UINTN) CoalesceImageAddress);
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Gets the reserved long mode buffer.
+
+ @param LongModeBuffer Pointer to the long mode buffer for output.
+
+ @retval EFI_SUCCESS Long mode buffer successfully retrieved.
+ @retval Others Variable storing long mode buffer not found.
+
+**/
+EFI_STATUS
+GetLongModeContext (
+ OUT EFI_CAPSULE_LONG_MODE_BUFFER *LongModeBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PPIVariableServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof (EFI_CAPSULE_LONG_MODE_BUFFER);
+ Status = PPIVariableServices->GetVariable (
+ PPIVariableServices,
+ EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ LongModeBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG (( DEBUG_ERROR, "Error Get LongModeBuffer variable %r!\n", Status));
+ }
+ return Status;
+}
+#endif
+
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+/**
+ Get physical address bits.
+
+ @return Physical address bits.
+
+**/
+UINT8
+GetPhysicalAddressBits (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+ VOID *Hob;
+
+ //
+ // 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;
+ }
+
+ return PhysicalAddressBits;
+}
+#endif
+
+/**
+ Sort memory resource entries based upon PhysicalStart, from low to high.
+
+ @param[in, out] MemoryResource A pointer to the memory resource entry buffer.
+
+**/
+VOID
+SortMemoryResourceDescriptor (
+ IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource
+ )
+{
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry;
+ MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry;
+ MEMORY_RESOURCE_DESCRIPTOR TempMemoryResource;
+
+ MemoryResourceEntry = MemoryResource;
+ NextMemoryResourceEntry = MemoryResource + 1;
+ while (MemoryResourceEntry->ResourceLength != 0) {
+ while (NextMemoryResourceEntry->ResourceLength != 0) {
+ if (MemoryResourceEntry->PhysicalStart > NextMemoryResourceEntry->PhysicalStart) {
+ CopyMem (&TempMemoryResource, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+ CopyMem (MemoryResourceEntry, NextMemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+ CopyMem (NextMemoryResourceEntry, &TempMemoryResource, sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+ }
+
+ NextMemoryResourceEntry = NextMemoryResourceEntry + 1;
+ }
+
+ MemoryResourceEntry = MemoryResourceEntry + 1;
+ NextMemoryResourceEntry = MemoryResourceEntry + 1;
+ }
+}
+
+/**
+ Merge continous memory resource entries.
+
+ @param[in, out] MemoryResource A pointer to the memory resource entry buffer.
+
+**/
+VOID
+MergeMemoryResourceDescriptor (
+ IN OUT MEMORY_RESOURCE_DESCRIPTOR *MemoryResource
+ )
+{
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEntry;
+ MEMORY_RESOURCE_DESCRIPTOR *NewMemoryResourceEntry;
+ MEMORY_RESOURCE_DESCRIPTOR *NextMemoryResourceEntry;
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResourceEnd;
+
+ MemoryResourceEntry = MemoryResource;
+ NewMemoryResourceEntry = MemoryResource;
+ while (MemoryResourceEntry->ResourceLength != 0) {
+ CopyMem (NewMemoryResourceEntry, MemoryResourceEntry, sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+ NextMemoryResourceEntry = MemoryResourceEntry + 1;
+
+ while ((NextMemoryResourceEntry->ResourceLength != 0) &&
+ (NextMemoryResourceEntry->PhysicalStart == (MemoryResourceEntry->PhysicalStart + MemoryResourceEntry->ResourceLength))) {
+ MemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength;
+ if (NewMemoryResourceEntry != MemoryResourceEntry) {
+ NewMemoryResourceEntry->ResourceLength += NextMemoryResourceEntry->ResourceLength;
+ }
+
+ NextMemoryResourceEntry = NextMemoryResourceEntry + 1;
+ }
+
+ MemoryResourceEntry = NextMemoryResourceEntry;
+ NewMemoryResourceEntry = NewMemoryResourceEntry + 1;
+ }
+
+ //
+ // Set NULL terminate memory resource descriptor after merging.
+ //
+ MemoryResourceEnd = NewMemoryResourceEntry;
+ ZeroMem (MemoryResourceEnd, sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+}
+
+/**
+ Build memory resource descriptor from resource descriptor in HOB list.
+
+ @return Pointer to the buffer of memory resource descriptor.
+ NULL if no memory resource descriptor reported in HOB list
+ before capsule Coalesce.
+
+**/
+MEMORY_RESOURCE_DESCRIPTOR *
+BuildMemoryResourceDescriptor (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN Index;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;
+ EFI_STATUS Status;
+
+ //
+ // Get the count of memory resource descriptor.
+ //
+ Index = 0;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ while (Hob.Raw != NULL) {
+ ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;
+ if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+ Index++;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+ }
+
+ if (Index == 0) {
+ DEBUG ((DEBUG_INFO | DEBUG_WARN, "No memory resource descriptor reported in HOB list before capsule Coalesce\n"));
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+ //
+ // Allocate memory to hold memory resource descriptor,
+ // include extra one NULL terminate memory resource descriptor.
+ //
+ Status = PeiServicesAllocatePool ((1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (MemoryResource, (1 + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+
+ MemoryResource[0].PhysicalStart = 0;
+ MemoryResource[0].ResourceLength = LShiftU64 (1, GetPhysicalAddressBits ());
+ DEBUG ((DEBUG_INFO, "MemoryResource[0x0] - Start(0x%0lx) Length(0x%0lx)\n",
+ MemoryResource[0x0].PhysicalStart, MemoryResource[0x0].ResourceLength));
+ return MemoryResource;
+#else
+ return NULL;
+#endif
+ }
+
+ //
+ // Allocate memory to hold memory resource descriptor,
+ // include extra one NULL terminate memory resource descriptor.
+ //
+ Status = PeiServicesAllocatePool ((Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR), (VOID **) &MemoryResource);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (MemoryResource, (Index + 1) * sizeof (MEMORY_RESOURCE_DESCRIPTOR));
+
+ //
+ // Get the content of memory resource descriptor.
+ //
+ Index = 0;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ while (Hob.Raw != NULL) {
+ ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *) Hob.Raw;
+ if (ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+ DEBUG ((DEBUG_INFO, "MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n",
+ Index, ResourceDescriptor->PhysicalStart, ResourceDescriptor->ResourceLength));
+ MemoryResource[Index].PhysicalStart = ResourceDescriptor->PhysicalStart;
+ MemoryResource[Index].ResourceLength = ResourceDescriptor->ResourceLength;
+ Index++;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+ }
+
+ SortMemoryResourceDescriptor (MemoryResource);
+ MergeMemoryResourceDescriptor (MemoryResource);
+
+ DEBUG ((DEBUG_INFO, "Dump MemoryResource[] after sorted and merged\n"));
+ for (Index = 0; MemoryResource[Index].ResourceLength != 0; Index++) {
+ DEBUG ((
+ DEBUG_INFO,
+ " MemoryResource[0x%x] - Start(0x%0lx) Length(0x%0lx)\n",
+ Index,
+ MemoryResource[Index].PhysicalStart,
+ MemoryResource[Index].ResourceLength
+ ));
+ }
+
+ return MemoryResource;
+}
+
+/**
+ Check if the capsules are staged.
+
+ @retval TRUE The capsules are staged.
+ @retval FALSE The capsules are not staged.
+
+**/
+BOOLEAN
+AreCapsulesStaged (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
+ EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;
+
+ CapsuleDataPtr64 = 0;
+
+ Status = PeiServicesLocatePpi(
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&PPIVariableServices
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to find ReadOnlyVariable2PPI\n"));
+ return FALSE;
+ }
+
+ //
+ // Check for Update capsule
+ //
+ Size = sizeof (CapsuleDataPtr64);
+ Status = PPIVariableServices->GetVariable (
+ PPIVariableServices,
+ EFI_CAPSULE_VARIABLE_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ (VOID *)&CapsuleDataPtr64
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check all the variables for SG list heads and get the count and addresses.
+
+ @param ListLength A pointer would return the SG list length.
+ @param HeadList A ponter to the capsule SG list.
+
+ @retval EFI_SUCCESS a valid capsule is present
+ @retval EFI_NOT_FOUND if a valid capsule is not present
+ @retval EFI_INVALID_PARAMETER the input parameter is invalid
+ @retval EFI_OUT_OF_RESOURCES fail to allocate memory
+
+**/
+EFI_STATUS
+GetScatterGatherHeadEntries (
+ OUT UINTN *ListLength,
+ OUT EFI_PHYSICAL_ADDRESS **HeadList
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN Index;
+ UINTN TempIndex;
+ UINTN ValidIndex;
+ BOOLEAN Flag;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+ EFI_PHYSICAL_ADDRESS CapsuleDataPtr64;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
+ EFI_PHYSICAL_ADDRESS *TempList;
+ EFI_PHYSICAL_ADDRESS *EnlargedTempList;
+ UINTN TempListLength;
+
+ Index = 0;
+ TempVarName = NULL;
+ CapsuleVarName[0] = 0;
+ ValidIndex = 0;
+ CapsuleDataPtr64 = 0;
+
+ if ((ListLength == NULL) || (HeadList == NULL)) {
+ DEBUG ((DEBUG_ERROR, "%a Invalid parameters. Inputs can't be NULL\n", __FUNCTION__));
+ ASSERT (ListLength != NULL);
+ ASSERT (HeadList != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ListLength = 0;
+ *HeadList = NULL;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&PPIVariableServices
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to find ReadOnlyVariable2PPI\n"));
+ return Status;
+ }
+
+ //
+ // Allocate memory for sg list head
+ //
+ TempListLength = DEFAULT_SG_LIST_HEADS * sizeof (EFI_PHYSICAL_ADDRESS);
+ TempList = AllocateZeroPool (TempListLength);
+ if (TempList == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // setup var name buffer for update capsules
+ //
+ StrCpyS (CapsuleVarName, sizeof (CapsuleVarName) / sizeof (CHAR16), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ while (TRUE) {
+ if (Index != 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ (sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName)),
+ 0,
+ Index,
+ 0
+ );
+ }
+ Size = sizeof (CapsuleDataPtr64);
+ Status = PPIVariableServices->GetVariable (
+ PPIVariableServices,
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ (VOID *)&CapsuleDataPtr64
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_ERROR, "Unexpected error getting Capsule Update variable. Status = %r\n"));
+ }
+ break;
+ }
+
+ //
+ // If this BlockList has been linked before, skip this variable
+ //
+ Flag = FALSE;
+ for (TempIndex = 0; TempIndex < ValidIndex; TempIndex++) {
+ if (TempList[TempIndex] == CapsuleDataPtr64) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ if (Flag) {
+ Index++;
+ continue;
+ }
+
+ //
+ // The TempList is full, enlarge it
+ //
+ if ((ValidIndex + 1) >= TempListLength) {
+ EnlargedTempList = AllocateZeroPool (TempListLength * 2);
+ if (EnlargedTempList == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (EnlargedTempList, TempList, TempListLength);
+ FreePool (TempList);
+ TempList = EnlargedTempList;
+ TempListLength *= 2;
+ }
+
+ //
+ // add it to the cached list
+ //
+ TempList[ValidIndex++] = CapsuleDataPtr64;
+ Index++;
+ }
+
+ if (ValidIndex == 0) {
+ DEBUG ((DEBUG_ERROR, "%a didn't find any SG lists in variables\n", __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ *HeadList = AllocateZeroPool ((ValidIndex + 1) * sizeof (EFI_PHYSICAL_ADDRESS));
+ if (*HeadList == NULL) {
+ DEBUG ((DEBUG_ERROR, "Failed to allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (*HeadList, TempList, (ValidIndex) * sizeof (EFI_PHYSICAL_ADDRESS));
+ *ListLength = ValidIndex;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Capsule PPI service to coalesce a fragmented capsule in memory.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param MemoryBase Pointer to the base of a block of memory that we can walk
+ all over while trying to coalesce our buffers.
+ On output, this variable will hold the base address of
+ a coalesced capsule.
+ @param MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND if we can't determine the boot mode
+ if the boot mode is not flash-update
+ if we could not find the capsule descriptors
+
+ @retval EFI_BUFFER_TOO_SMALL
+ if we could not coalesce the capsule in the memory
+ region provided to us
+
+ @retval EFI_SUCCESS if there's no capsule, or if we processed the
+ capsule successfully.
+**/
+EFI_STATUS
+EFIAPI
+CapsuleCoalesce (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemorySize
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ UINTN ListLength;
+ EFI_PHYSICAL_ADDRESS *VariableArrayAddress;
+ MEMORY_RESOURCE_DESCRIPTOR *MemoryResource;
+#ifdef MDE_CPU_IA32
+ UINT16 CoalesceImageMachineType;
+ EFI_PHYSICAL_ADDRESS CoalesceImageEntryPoint;
+ COALESCE_ENTRY CoalesceEntry;
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
+#endif
+
+ ListLength = 0;
+ VariableArrayAddress = NULL;
+
+ //
+ // Someone should have already ascertained the boot mode. If it's not
+ // capsule update, then return normally.
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ if (EFI_ERROR (Status) || (BootMode != BOOT_ON_FLASH_UPDATE)) {
+ DEBUG ((DEBUG_ERROR, "Boot mode is not correct for capsule update path.\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Get SG list entries
+ //
+ Status = GetScatterGatherHeadEntries (&ListLength, &VariableArrayAddress);
+ if (EFI_ERROR (Status) || VariableArrayAddress == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a failed to get Scatter Gather List Head Entries. Status = %r\n", __FUNCTION__, Status));
+ goto Done;
+ }
+
+ MemoryResource = BuildMemoryResourceDescriptor ();
+
+#ifdef MDE_CPU_IA32
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ //
+ // Switch to 64-bit mode to process capsule data when:
+ // 1. When DXE phase is 64-bit
+ // 2. When the buffer for 64-bit transition exists
+ // 3. When Capsule X64 image is built in BIOS image
+ // In 64-bit mode, we can process capsule data above 4GB.
+ //
+ CoalesceImageEntryPoint = 0;
+ Status = GetLongModeContext (&LongModeBuffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to find the variable for long mode context!\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Status = FindCapsuleCoalesceImage (&CoalesceImageEntryPoint, &CoalesceImageMachineType);
+ if ((EFI_ERROR (Status)) || (CoalesceImageMachineType != EFI_IMAGE_MACHINE_X64)) {
+ DEBUG ((DEBUG_ERROR, "Fail to find CapsuleX64 module in FV!\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ ASSERT (CoalesceImageEntryPoint != 0);
+ CoalesceEntry = (COALESCE_ENTRY) (UINTN) CoalesceImageEntryPoint;
+ Status = ModeSwitch (&LongModeBuffer, CoalesceEntry, (EFI_PHYSICAL_ADDRESS)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);
+ } else {
+ //
+ // Capsule is processed in IA32 mode.
+ //
+ Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);
+ }
+#else
+ //
+ // Process capsule directly.
+ //
+ Status = CapsuleDataCoalesce (PeiServices, (EFI_PHYSICAL_ADDRESS *)(UINTN)VariableArrayAddress, MemoryResource, MemoryBase, MemorySize);
+#endif
+
+ DEBUG ((DEBUG_INFO, "Capsule Coalesce Status = %r!\n", Status));
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((DEBUG_ERROR, "There is not enough memory to process capsule!\n"));
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_ERROR, "Fail to parse capsule descriptor in memory!\n"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR)
+ );
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ Determine if we're in capsule update boot mode.
+
+ @param PeiServices PEI services table
+
+ @retval EFI_SUCCESS if we have a capsule available
+ @retval EFI_NOT_FOUND no capsule detected
+
+**/
+EFI_STATUS
+EFIAPI
+CheckCapsuleUpdate (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ if (AreCapsulesStaged ()) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+/**
+ This function will look at a capsule and determine if it's a test pattern.
+ If it is, then it will verify it and emit an error message if corruption is detected.
+
+ @param PeiServices Standard pei services pointer
+ @param CapsuleBase Base address of coalesced capsule, which is preceeded
+ by private data. Very implementation specific.
+
+ @retval TRUE Capsule image is the test image
+ @retval FALSE Capsule image is not the test image.
+
+**/
+BOOLEAN
+CapsuleTestPattern (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *CapsuleBase
+ )
+{
+ UINT32 *TestPtr;
+ UINT32 TestCounter;
+ UINT32 TestSize;
+ BOOLEAN RetValue;
+
+ RetValue = FALSE;
+
+ //
+ // Look at the capsule data and determine if it's a test pattern. If it
+ // is, then test it now.
+ //
+ TestPtr = (UINT32 *) CapsuleBase;
+ //
+ // 0x54534554 "TEST"
+ //
+ if (*TestPtr == 0x54534554) {
+ RetValue = TRUE;
+ DEBUG ((DEBUG_INFO, "Capsule test pattern mode activated...\n"));
+ TestSize = TestPtr[1] / sizeof (UINT32);
+ //
+ // Skip over the signature and the size fields in the pattern data header
+ //
+ TestPtr += 2;
+ TestCounter = 0;
+ while (TestSize > 0) {
+ if (*TestPtr != TestCounter) {
+ DEBUG ((DEBUG_INFO, "Capsule test pattern mode FAILED: BaseAddr/FailAddr 0x%X 0x%X\n", (UINT32)(UINTN)(EFI_CAPSULE_PEIM_PRIVATE_DATA *)CapsuleBase, (UINT32)(UINTN)TestPtr));
+ return TRUE;
+ }
+
+ TestPtr++;
+ TestCounter++;
+ TestSize--;
+ }
+
+ DEBUG ((DEBUG_INFO, "Capsule test pattern mode SUCCESS\n"));
+ }
+
+ return RetValue;
+}
+
+/**
+ Capsule PPI service that gets called after memory is available. The
+ capsule coalesce function, which must be called first, returns a base
+ address and size, which can be anything actually. Once the memory init
+ PEIM has discovered memory, then it should call this function and pass in
+ the base address and size returned by the coalesce function. Then this
+ function can create a capsule HOB and return.
+
+ @param PeiServices standard pei services pointer
+ @param CapsuleBase address returned by the capsule coalesce function. Most
+ likely this will actually be a pointer to private data.
+ @param CapsuleSize value returned by the capsule coalesce function.
+
+ @retval EFI_VOLUME_CORRUPTED CapsuleBase does not appear to point to a
+ coalesced capsule
+ @retval EFI_SUCCESS if all goes well.
+**/
+EFI_STATUS
+EFIAPI
+CreateState (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *CapsuleBase,
+ IN UINTN CapsuleSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_CAPSULE_PEIM_PRIVATE_DATA *PrivateData;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS NewBuffer;
+ UINTN CapsuleNumber;
+ UINT32 Index;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+
+ PrivateData = (EFI_CAPSULE_PEIM_PRIVATE_DATA *) CapsuleBase;
+ if (PrivateData->Signature != EFI_CAPSULE_PEIM_PRIVATE_DATA_SIGNATURE) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ if (PrivateData->CapsuleAllImageSize >= MAX_ADDRESS) {
+ DEBUG ((DEBUG_ERROR, "CapsuleAllImageSize too big - 0x%lx\n", PrivateData->CapsuleAllImageSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (PrivateData->CapsuleNumber >= MAX_ADDRESS) {
+ DEBUG ((DEBUG_ERROR, "CapsuleNumber too big - 0x%lx\n", PrivateData->CapsuleNumber));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Capsule Number and Capsule Offset is in the tail of Capsule data.
+ //
+ Size = (UINTN)PrivateData->CapsuleAllImageSize;
+ CapsuleNumber = (UINTN)PrivateData->CapsuleNumber;
+ //
+ // Allocate the memory so that it gets preserved into DXE
+ //
+ Status = PeiServicesAllocatePages (
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &NewBuffer
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "AllocatePages Failed!\n"));
+ return Status;
+ }
+ //
+ // Copy to our new buffer for DXE
+ //
+ DEBUG ((DEBUG_INFO, "Capsule copy from 0x%8X to 0x%8X with size 0x%8X\n", (UINTN)((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), (UINTN) NewBuffer, Size));
+ CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) ((UINT8 *)PrivateData + sizeof(EFI_CAPSULE_PEIM_PRIVATE_DATA) + (CapsuleNumber - 1) * sizeof(UINT64)), Size);
+ //
+ // Check for test data pattern. If it is the test pattern, then we'll
+ // test it and still create the HOB so that it can be used to verify
+ // that capsules don't get corrupted all the way into BDS. BDS will
+ // still try to turn it into a firmware volume, but will think it's
+ // corrupted so nothing will happen.
+ //
+ DEBUG_CODE (
+ CapsuleTestPattern (PeiServices, (VOID *) (UINTN) NewBuffer);
+ );
+
+ //
+ // Build the UEFI Capsule Hob for each capsule image.
+ //
+ for (Index = 0; Index < CapsuleNumber; Index ++) {
+ BaseAddress = NewBuffer + PrivateData->CapsuleOffset[Index];
+ Length = ((EFI_CAPSULE_HEADER *)((UINTN) BaseAddress))->CapsuleImageSize;
+
+ BuildCvHob (BaseAddress, Length);
+ }
+
+ return EFI_SUCCESS;
+}
+
+CONST EFI_PEI_CAPSULE_PPI mCapsulePpi = {
+ CapsuleCoalesce,
+ CheckCapsuleUpdate,
+ CreateState
+};
+
+CONST EFI_PEI_PPI_DESCRIPTOR mUefiPpiListCapsule = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiCapsulePpiGuid,
+ (EFI_PEI_CAPSULE_PPI *) &mCapsulePpi
+};
+
+/**
+ Entry point function for the PEIM
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS If we installed our PPI
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleMain (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ //
+ // Just produce our PPI
+ //
+ return PeiServicesInstallPpi (&mUefiPpiListCapsule);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/PageFaultHandler.nasm b/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/PageFaultHandler.nasm
new file mode 100644
index 000000000..6adcc4c37
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/PageFaultHandler.nasm
@@ -0,0 +1,81 @@
+;; @file
+; This is the assembly code for page fault handler hook.
+;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;;
+
+extern ASM_PFX(PageFaultHandler)
+
+ DEFAULT REL
+ SECTION .text
+
+global ASM_PFX(PageFaultHandlerHook)
+ASM_PFX(PageFaultHandlerHook):
+ add rsp, -0x10
+ ; save rax
+ mov [rsp + 0x8], rax
+
+ ;push rax ; save all volatile registers
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ ; save volatile fp registers
+ ; 68h + 08h(for alignment)
+ add rsp, -0x70
+ stmxcsr [rsp + 0x60]
+ movdqa [rsp + 0x0], xmm0
+ movdqa [rsp + 0x10], xmm1
+ movdqa [rsp + 0x20], xmm2
+ movdqa [rsp + 0x30], xmm3
+ movdqa [rsp + 0x40], xmm4
+ movdqa [rsp + 0x50], xmm5
+
+ add rsp, -0x20
+ call ASM_PFX(PageFaultHandler)
+ add rsp, 0x20
+
+ ; load volatile fp registers
+ ldmxcsr [rsp + 0x60]
+ movdqa xmm0, [rsp + 0x0]
+ movdqa xmm1, [rsp + 0x10]
+ movdqa xmm2, [rsp + 0x20]
+ movdqa xmm3, [rsp + 0x30]
+ movdqa xmm4, [rsp + 0x40]
+ movdqa xmm5, [rsp + 0x50]
+ add rsp, 0x70
+
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ ;pop rax ; restore all volatile registers
+
+ add rsp, 0x10
+
+ ; rax returned from PageFaultHandler is NULL or OriginalHandler address
+ ; NULL if the page fault is handled by PageFaultHandler
+ ; OriginalHandler address if the page fault is not handled by PageFaultHandler
+ test rax, rax
+
+ ; save OriginalHandler address
+ mov [rsp - 0x10], rax
+ ; restore rax
+ mov rax, [rsp - 0x8]
+
+ jz .0
+
+ ; jump to OriginalHandler
+ jmp qword [rsp - 0x10]
+
+.0:
+ add rsp, 0x8 ; skip error code for PF
+ iretq
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c b/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c
new file mode 100644
index 000000000..4a0567fa7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsulePei/X64/X64Entry.c
@@ -0,0 +1,305 @@
+/** @file
+ The X64 entrypoint is used to process capsule in long mode.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/DebugAgentLib.h>
+#include "CommonHeader.h"
+
+#define EXCEPTION_VECTOR_NUMBER 0x22
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+typedef struct _PAGE_FAULT_CONTEXT {
+ BOOLEAN Page1GSupport;
+ UINT64 PhyMask;
+ UINTN PageFaultBuffer;
+ UINTN PageFaultIndex;
+ UINT64 AddressEncMask;
+ //
+ // Store the uplink information for each page being used.
+ //
+ UINT64 *PageFaultUplink[EXTRA_PAGE_TABLE_PAGES];
+ VOID *OriginalHandler;
+} PAGE_FAULT_CONTEXT;
+
+typedef struct _PAGE_FAULT_IDT_TABLE {
+ PAGE_FAULT_CONTEXT PageFaultContext;
+ IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
+} PAGE_FAULT_IDT_TABLE;
+
+/**
+ Page fault handler.
+
+**/
+VOID
+EFIAPI
+PageFaultHandlerHook (
+ VOID
+ );
+
+/**
+ Hook IDT with our page fault handler so that the on-demand paging works on page fault.
+
+ @param[in, out] IdtEntry Pointer to IDT entry.
+ @param[in, out] PageFaultContext Pointer to page fault context.
+
+**/
+VOID
+HookPageFaultHandler (
+ IN OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN OUT PAGE_FAULT_CONTEXT *PageFaultContext
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+ UINTN PageFaultHandlerHookAddress;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ PageFaultContext->PhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
+ PageFaultContext->PhyMask &= (1ull << 48) - SIZE_4KB;
+
+ //
+ // Set Page Fault entry to catch >4G access
+ //
+ PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
+ PageFaultContext->OriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
+ IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+
+ if (PageFaultContext->Page1GSupport) {
+ PageFaultContext->PageFaultBuffer = (UINTN)(AsmReadCr3 () & PageFaultContext->PhyMask) + EFI_PAGES_TO_SIZE(2);
+ }else {
+ PageFaultContext->PageFaultBuffer = (UINTN)(AsmReadCr3 () & PageFaultContext->PhyMask) + EFI_PAGES_TO_SIZE(6);
+ }
+ PageFaultContext->PageFaultIndex = 0;
+ ZeroMem (PageFaultContext->PageFaultUplink, sizeof (PageFaultContext->PageFaultUplink));
+}
+
+/**
+ Acquire page for page fault.
+
+ @param[in, out] PageFaultContext Pointer to page fault context.
+ @param[in, out] Uplink Pointer to up page table entry.
+
+**/
+VOID
+AcquirePage (
+ IN OUT PAGE_FAULT_CONTEXT *PageFaultContext,
+ IN OUT UINT64 *Uplink
+ )
+{
+ UINTN Address;
+ UINT64 AddressEncMask;
+
+ Address = PageFaultContext->PageFaultBuffer + EFI_PAGES_TO_SIZE (PageFaultContext->PageFaultIndex);
+ ZeroMem ((VOID *) Address, EFI_PAGES_TO_SIZE (1));
+
+ AddressEncMask = PageFaultContext->AddressEncMask;
+
+ //
+ // Cut the previous uplink if it exists and wasn't overwritten.
+ //
+ if ((PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] != NULL) &&
+ ((*PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] & ~AddressEncMask & PageFaultContext->PhyMask) == Address)) {
+ *PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] = 0;
+ }
+
+ //
+ // Link & Record the current uplink.
+ //
+ *Uplink = Address | AddressEncMask | IA32_PG_P | IA32_PG_RW;
+ PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] = Uplink;
+
+ PageFaultContext->PageFaultIndex = (PageFaultContext->PageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;
+}
+
+/**
+ The page fault handler that on-demand read >4G memory/MMIO.
+
+ @retval NULL The page fault is correctly handled.
+ @retval OriginalHandler The page fault is not handled and is passed through to original handler.
+
+**/
+VOID *
+EFIAPI
+PageFaultHandler (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR Idtr;
+ PAGE_FAULT_CONTEXT *PageFaultContext;
+ UINT64 PhyMask;
+ UINT64 *PageTable;
+ UINT64 PFAddress;
+ UINTN PTIndex;
+ UINT64 AddressEncMask;
+
+ //
+ // Get the IDT Descriptor.
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
+ //
+ // Then get page fault context by IDT Descriptor.
+ //
+ PageFaultContext = (PAGE_FAULT_CONTEXT *) (UINTN) (Idtr.Base - sizeof (PAGE_FAULT_CONTEXT));
+ PhyMask = PageFaultContext->PhyMask;
+ AddressEncMask = PageFaultContext->AddressEncMask;
+
+ PFAddress = AsmReadCr2 ();
+ DEBUG ((EFI_D_ERROR, "CapsuleX64 - PageFaultHandler: Cr2 - %lx\n", PFAddress));
+
+ if (PFAddress >= PhyMask + SIZE_4KB) {
+ return PageFaultContext->OriginalHandler;
+ }
+ PFAddress &= PhyMask;
+
+ PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & PhyMask);
+
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ // PML4E
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (PageFaultContext, &PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~AddressEncMask & PhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ // PDPTE
+ if (PageFaultContext->Page1GSupport) {
+ PageTable[PTIndex] = ((PFAddress | AddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ } else {
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (PageFaultContext, &PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~AddressEncMask & PhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ // PD
+ PageTable[PTIndex] = ((PFAddress | AddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ }
+
+ return NULL;
+}
+
+
+/**
+ The X64 entrypoint is used to process capsule in long mode then
+ return to 32-bit protected mode.
+
+ @param EntrypointContext Pointer to the context of long mode.
+ @param ReturnContext Pointer to the context of 32-bit protected mode.
+
+ @retval This function should never return actually.
+
+**/
+EFI_STATUS
+EFIAPI
+_ModuleEntryPoint (
+ SWITCH_32_TO_64_CONTEXT *EntrypointContext,
+ SWITCH_64_TO_32_CONTEXT *ReturnContext
+)
+{
+ EFI_STATUS Status;
+ IA32_DESCRIPTOR Ia32Idtr;
+ IA32_DESCRIPTOR X64Idtr;
+ PAGE_FAULT_IDT_TABLE PageFaultIdtTable;
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+
+ //
+ // Save the IA32 IDT Descriptor
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
+
+ //
+ // Setup X64 IDT table
+ //
+ ZeroMem (PageFaultIdtTable.IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER);
+ X64Idtr.Base = (UINTN) PageFaultIdtTable.IdtEntryTable;
+ X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Hook page fault handler to handle >4G request.
+ //
+ PageFaultIdtTable.PageFaultContext.Page1GSupport = EntrypointContext->Page1GSupport;
+ PageFaultIdtTable.PageFaultContext.AddressEncMask = EntrypointContext->AddressEncMask;
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) (X64Idtr.Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ HookPageFaultHandler (IdtEntry, &(PageFaultIdtTable.PageFaultContext));
+
+ //
+ // Initialize Debug Agent to support source level debug
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *) &Ia32Idtr, NULL);
+
+ //
+ // Call CapsuleDataCoalesce to process capsule.
+ //
+ Status = CapsuleDataCoalesce (
+ NULL,
+ (EFI_PHYSICAL_ADDRESS *) (UINTN) EntrypointContext->BlockListAddr,
+ (MEMORY_RESOURCE_DESCRIPTOR *) (UINTN) EntrypointContext->MemoryResource,
+ (VOID **) (UINTN) EntrypointContext->MemoryBase64Ptr,
+ (UINTN *) (UINTN) EntrypointContext->MemorySize64Ptr
+ );
+
+ ReturnContext->ReturnStatus = Status;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n",
+ __FUNCTION__,
+ EntrypointContext->StackBufferBase,
+ EntrypointContext->StackBufferLength
+ ));
+
+ //
+ // Disable interrupt of Debug timer, since the new IDT table cannot work in long mode
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+ //
+ // Restore IA32 IDT table
+ //
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
+
+ //
+ // Finish to coalesce capsule, and return to 32-bit mode.
+ //
+ AsmDisablePaging64 (
+ ReturnContext->ReturnCs,
+ (UINT32) ReturnContext->ReturnEntryPoint,
+ (UINT32) (UINTN) EntrypointContext,
+ (UINT32) (UINTN) ReturnContext,
+ (UINT32) (EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength)
+ );
+
+ //
+ // Should never be here.
+ //
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c
new file mode 100644
index 000000000..e05f14de6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/Arm/CapsuleReset.c
@@ -0,0 +1,36 @@
+/** @file
+ ARM implementation of architecture specific routines related to
+ PersistAcrossReset capsules
+
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+/**
+ Whether the platform supports capsules that persist across reset. Note that
+ some platforms only support such capsules at boot time.
+
+ @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule()
+ at this time
+ FALSE otherwise
+**/
+BOOLEAN
+IsPersistAcrossResetCapsuleSupported (
+ VOID
+ )
+{
+ //
+ // ARM requires the capsule payload to be cleaned to the point of coherency
+ // (PoC), but only permits doing so using cache maintenance instructions that
+ // operate on virtual addresses. Since at runtime, we don't know the virtual
+ // addresses of the data structures that make up the scatter/gather list, we
+ // cannot perform the maintenance, and all we can do is give up.
+ //
+ return FeaturePcdGet (PcdSupportUpdateCapsuleReset) && !EfiAtRuntime ();
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c
new file mode 100644
index 000000000..3c96851e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCache.c
@@ -0,0 +1,57 @@
+/** @file
+ Flush the cache is required for most architectures while do capsule
+ update. It is not support at Runtime.
+
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+#include <Library/CacheMaintenanceLib.h>
+
+/**
+ Writes Back a range of data cache lines covering a set of capsules in memory.
+
+ Writes Back the data cache lines specified by ScatterGatherList.
+
+ @param ScatterGatherList Physical address of the data structure that
+ describes a set of capsules in memory
+
+**/
+VOID
+CapsuleCacheWriteBack (
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList
+ )
+{
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc;
+
+ if (!EfiAtRuntime ()) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)ScatterGatherList;
+ do {
+ WriteBackDataCacheRange (
+ (VOID *)(UINTN)Desc,
+ (UINTN)sizeof (*Desc)
+ );
+
+ if (Desc->Length > 0) {
+ WriteBackDataCacheRange (
+ (VOID *)(UINTN)Desc->Union.DataBlock,
+ (UINTN)Desc->Length
+ );
+ Desc++;
+ } else if (Desc->Union.ContinuationPointer > 0) {
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer;
+ }
+ } while (Desc->Length > 0 || Desc->Union.ContinuationPointer > 0);
+
+ WriteBackDataCacheRange (
+ (VOID *)(UINTN)Desc,
+ (UINTN)sizeof (*Desc)
+ );
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c
new file mode 100644
index 000000000..edff7573b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleCacheNull.c
@@ -0,0 +1,32 @@
+/** @file
+ Null function version of cache function.
+
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+#include <Library/CacheMaintenanceLib.h>
+
+/**
+ Writes Back a range of data cache lines covering a set of capsules in memory.
+
+ Writes Back the data cache lines specified by ScatterGatherList.
+
+ Null version, do nothing.
+
+ @param ScatterGatherList Physical address of the data structure that
+ describes a set of capsules in memory
+
+**/
+VOID
+CapsuleCacheWriteBack (
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList
+ )
+{
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c
new file mode 100644
index 000000000..732a3c9ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleReset.c
@@ -0,0 +1,29 @@
+/** @file
+ Default implementation of architecture specific routines related to
+ PersistAcrossReset capsules
+
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+/**
+ Whether the platform supports capsules that persist across reset. Note that
+ some platforms only support such capsules at boot time.
+
+ @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule()
+ at this time
+ FALSE otherwise
+**/
+BOOLEAN
+IsPersistAcrossResetCapsuleSupported (
+ VOID
+ )
+{
+ return FeaturePcdGet (PcdSupportUpdateCapsuleReset);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
new file mode 100644
index 000000000..8bf5035a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
@@ -0,0 +1,108 @@
+## @file
+# Capsule Runtime Driver produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities).
+#
+# It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+# the capsule runtime services are ready.
+#
+# Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleRuntimeDxe
+ MODULE_UNI_FILE = CapsuleRuntimeDxe.uni
+ FILE_GUID = 42857F0A-13F2-4B21-8A23-53D3F714B840
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CapsuleServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64 RISCV64
+#
+
+[Sources]
+ CapsuleService.c
+ CapsuleService.h
+
+[Sources.Ia32, Sources.EBC, Sources.ARM, Sources.AARCH64, Sources.RISCV64]
+ SaveLongModeContext.c
+
+[Sources.Ia32, Sources.X64, Sources.ARM, Sources.AARCH64, Sources.RISCV64]
+ CapsuleCache.c
+
+[Sources.Ia32, Sources.X64, Sources.EBC, Sources.RISCV64]
+ CapsuleReset.c
+
+[Sources.ARM, Sources.AARCH64]
+ Arm/CapsuleReset.c
+
+[Sources.EBC]
+ CapsuleCacheNull.c
+
+[Sources.X64]
+ X64/SaveLongModeContext.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ PcdLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ CapsuleLib
+ UefiRuntimeLib
+ BaseLib
+ PrintLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+
+[LibraryClasses.X64]
+ UefiLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleUpdateData" # (Process across reset capsule image) for capsule updated data
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleLongModeBuffer" # The long mode buffer used by IA32 Capsule PEIM to call X64 CapsuleCoalesce code to handle >4GB capsule blocks
+ gEfiCapsuleVendorGuid
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID # FMP capsule GUID
+
+[Protocols]
+ gEfiCapsuleArchProtocolGuid ## PRODUCES
+
+[Protocols.X64]
+ ## UNDEFINED ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportProcessCapsuleAtRuntime ## CONSUMES
+
+[FeaturePcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule ## SOMETIMES_CONSUMES # Populate Image requires reset support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES
+
+[Pcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid # Depends on variable write functionality to produce capsule data variable
+
+# [Hob.X64]
+# UNDEFINED ## SOMETIMES_CONSUMES # CPU
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsuleRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni
new file mode 100644
index 000000000..b161af45c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Capsule Runtime Driver produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities).
+//
+// It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+// the capsule runtime services are ready.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It installs the Capsule Architectural Protocol defined in PI1.0a to signify the capsule runtime services are ready."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni
new file mode 100644
index 000000000..f97bfd64a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CapsuleRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Runtime Firmware Update DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
new file mode 100644
index 000000000..2fba22dec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
@@ -0,0 +1,397 @@
+/** @file
+ Capsule Runtime Driver produces two UEFI capsule runtime services.
+ (UpdateCapsule, QueryCapsuleCapabilities)
+ It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+ the capsule runtime services are ready.
+
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+//
+// Handle for the installation of Capsule Architecture Protocol.
+//
+EFI_HANDLE mNewHandle = NULL;
+
+//
+// The times of calling UpdateCapsule ()
+//
+UINTN mTimes = 0;
+
+UINT32 mMaxSizePopulateCapsule = 0;
+UINT32 mMaxSizeNonPopulateCapsule = 0;
+
+/**
+ Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
+ consumption, the firmware may process the capsule immediately. If the payload should persist
+ across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
+ be passed into ResetSystem() and will cause the capsule to be processed by the firmware as
+ part of the reset process.
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param ScatterGatherList Physical pointer to a set of
+ EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the
+ location in physical memory of a set of capsules.
+
+ @retval EFI_SUCCESS Valid capsule was passed. If
+ CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the
+ capsule has been successfully processed by the firmware.
+ @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error.
+ @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were
+ set in the capsule header.
+ @retval EFI_INVALID_PARAMETER CapsuleCount is Zero.
+ @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL.
+ @retval EFI_UNSUPPORTED CapsuleImage is not recognized by the firmware.
+ @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule
+ is compatible with this platform but is not capable of being submitted or processed
+ in runtime. The caller may resubmit the capsule prior to ExitBootServices().
+ @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates
+ the capsule is compatible with this platform but there are insufficient resources to process.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateCapsule (
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
+ )
+{
+ UINTN ArrayNumber;
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ BOOLEAN NeedReset;
+ BOOLEAN InitiateReset;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+
+ //
+ // Check if platform support Capsule In RAM or not.
+ // Platform could choose to drop CapsulePei/CapsuleX64 and do not support Capsule In RAM.
+ //
+ if (!PcdGetBool(PcdCapsuleInRamSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Capsule Count can't be less than one.
+ //
+ if (CapsuleCount < 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NeedReset = FALSE;
+ InitiateReset = FALSE;
+ CapsuleHeader = NULL;
+ CapsuleVarName[0] = 0;
+
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ //
+ // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check FMP capsule flag
+ //
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
+ && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check Capsule image without populate flag by firmware support capsule function
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ Status = SupportCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Walk through all capsules, record whether there is a capsule needs reset
+ // or initiate reset. And then process capsules which has no reset flag directly.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ //
+ // Here should be in the boot-time for non-reset capsule image
+ // Platform specific update for the non-reset capsule image.
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+ if (EfiAtRuntime () && !FeaturePcdGet (PcdSupportProcessCapsuleAtRuntime)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = ProcessCapsuleImage(CapsuleHeader);
+ }
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ NeedReset = TRUE;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) {
+ InitiateReset = TRUE;
+ }
+ }
+ }
+
+ //
+ // After launching all capsules who has no reset flag, if no more capsules claims
+ // for a system reset just return.
+ //
+ if (!NeedReset) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ScatterGatherList is only referenced if the capsules are defined to persist across
+ // system reset.
+ //
+ if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the platform supports update capsule across a system reset
+ //
+ if (!IsPersistAcrossResetCapsuleSupported ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CapsuleCacheWriteBack (ScatterGatherList);
+
+ //
+ // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+ // if user calls UpdateCapsule multiple times.
+ //
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ if (mTimes > 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
+ 0,
+ mTimes,
+ 0
+ );
+ }
+
+ //
+ // ScatterGatherList is only referenced if the capsules are defined to persist across
+ // system reset. Set its value into NV storage to let pre-boot driver to pick it up
+ // after coming through a system reset.
+ //
+ Status = EfiSetVariable (
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINTN),
+ (VOID *) &ScatterGatherList
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Variable has been set successfully, increase variable index.
+ //
+ mTimes++;
+ if(InitiateReset) {
+ //
+ // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header
+ // will initiate a reset of the platform which is compatible with the passed-in capsule request and will
+ // not return back to the caller.
+ //
+ EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ }
+ return Status;
+}
+
+/**
+ Returns if the capsule can be supported via UpdateCapsule().
+ Notice: When PcdCapsuleInRamSupport is unsupported, even this routine returns a valid answer,
+ the capsule still is unsupported via UpdateCapsule().
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can
+ support as an argument to UpdateCapsule() via
+ CapsuleHeaderArray and ScatterGatherList.
+ @param ResetType Returns the type of reset required for the capsule update.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_UNSUPPORTED The capsule image is not supported on this platform, and
+ MaximumCapsuleSize and ResetType are undefined.
+ @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL, or ResetTyep is NULL,
+ Or CapsuleCount is Zero, or CapsuleImage is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+QueryCapsuleCapabilities (
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ OUT UINT64 *MaxiumCapsuleSize,
+ OUT EFI_RESET_TYPE *ResetType
+ )
+{
+ EFI_STATUS Status;
+ UINTN ArrayNumber;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ BOOLEAN NeedReset;
+
+ //
+ // Capsule Count can't be less than one.
+ //
+ if (CapsuleCount < 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether input parameter is valid
+ //
+ if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CapsuleHeader = NULL;
+ NeedReset = FALSE;
+
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ //
+ // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check FMP capsule flag
+ //
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
+ && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check Capsule image without populate flag is supported by firmware
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ Status = SupportCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Find out whether there is any capsule defined to persist across system reset.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ NeedReset = TRUE;
+ break;
+ }
+ }
+
+ if (NeedReset) {
+ //
+ //Check if the platform supports update capsule across a system reset
+ //
+ if (!IsPersistAcrossResetCapsuleSupported ()) {
+ return EFI_UNSUPPORTED;
+ }
+ *ResetType = EfiResetWarm;
+ *MaxiumCapsuleSize = (UINT64) mMaxSizePopulateCapsule;
+ } else {
+ //
+ // For non-reset capsule image.
+ //
+ *ResetType = EfiResetCold;
+ *MaxiumCapsuleSize = (UINT64) mMaxSizeNonPopulateCapsule;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ This code installs UEFI capsule runtime service.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS UEFI Capsule Runtime Services are installed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mMaxSizePopulateCapsule = PcdGet32(PcdMaxSizePopulateCapsule);
+ mMaxSizeNonPopulateCapsule = PcdGet32(PcdMaxSizeNonPopulateCapsule);
+
+ //
+ // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are
+ // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.
+ // The page table and stack is used to transfer processor mode from IA32 to long mode.
+ // Create the base address of page table and stack, and save them into variable.
+ // This is not needed when capsule with reset type is not supported.
+ //
+ SaveLongModeContext ();
+
+ //
+ // Install capsule runtime services into UEFI runtime service tables.
+ //
+ gRT->UpdateCapsule = UpdateCapsule;
+ gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities;
+
+ //
+ // Install the Capsule Architectural Protocol on a new handle
+ // to signify the capsule runtime services are ready.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mNewHandle,
+ &gEfiCapsuleArchProtocolGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h
new file mode 100644
index 000000000..069df3c75
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h
@@ -0,0 +1,70 @@
+/** @file
+ Capsule Runtime Driver produces two UEFI capsule runtime services.
+ (UpdateCapsule, QueryCapsuleCapabilities)
+ It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+ the capsule runtime services are ready.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CAPSULE_SERVICE_H_
+#define _CAPSULE_SERVICE_H_
+
+#include <Uefi.h>
+
+#include <Protocol/Capsule.h>
+#include <Guid/CapsuleVendor.h>
+#include <Guid/FmpCapsule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+
+/**
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 PEI.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ );
+
+/**
+ Whether the platform supports capsules that persist across reset. Note that
+ some platforms only support such capsules at boot time.
+
+ @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule()
+ at this time
+ FALSE otherwise
+**/
+BOOLEAN
+IsPersistAcrossResetCapsuleSupported (
+ VOID
+ );
+
+/**
+ Writes Back a range of data cache lines covering a set of capsules in memory.
+
+ Writes Back the data cache lines specified by ScatterGatherList.
+
+ @param ScatterGatherList Physical address of the data structure that
+ describes a set of capsules in memory
+
+**/
+VOID
+CapsuleCacheWriteBack (
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c
new file mode 100644
index 000000000..37b388902
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/SaveLongModeContext.c
@@ -0,0 +1,21 @@
+/** @file
+ Create the NULL function to pass build in IA32/IPF/ARM/EBC.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+/**
+ Only when PEI is IA32 and DXE is X64, we need transfer to long mode in PEI
+ in order to process capsule data above 4GB. So create a NULL function here for
+ other cases.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ )
+{
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
new file mode 100644
index 000000000..d80d4ed3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
@@ -0,0 +1,209 @@
+/** @file
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 capsule PEI.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/Capsule.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/VariableLock.h>
+
+#include <Guid/CapsuleVendor.h>
+#include <Guid/AcpiS3Context.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+/**
+ Allocate EfiReservedMemoryType below 4G memory address.
+
+ This function allocates EfiReservedMemoryType below 4G memory address.
+
+ @param Size Size of memory to allocate.
+
+ @return Allocated Address for output.
+
+**/
+VOID*
+AllocateReservedMemoryBelow4G (
+ 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,
+ EfiReservedMemoryType,
+ Pages,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Buffer = (VOID *) (UINTN) Address;
+ ZeroMem (Buffer, Size);
+
+ return Buffer;
+}
+
+/**
+ Register callback function upon VariableLockProtocol
+ to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME 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
+VariableLockCapsuleLongModeBufferVariable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ //
+ // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME 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, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.
+ 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.
+
+**/
+VOID
+EFIAPI
+PrepareContextForCapsulePei (
+ VOID
+ )
+{
+ UINTN ExtraPageTablePages;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINTN TotalPagesNum;
+ UINT8 PhysicalAddressBits;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ BOOLEAN Page1GSupport;
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ //
+ // Calculate the size of page table, allocate the memory.
+ //
+ 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;
+ }
+ }
+ }
+
+ //
+ // Create 4G page table by default,
+ // 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;
+ }
+
+ if (!Page1GSupport) {
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+ } else {
+ TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
+ }
+ TotalPagesNum += ExtraPageTablePages;
+ DEBUG ((DEBUG_INFO, "CapsuleRuntimeDxe X64 TotalPagesNum - 0x%x pages\n", TotalPagesNum));
+
+ LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));
+ ASSERT (LongModeBuffer.PageTableAddress != 0);
+
+ //
+ // Allocate stack
+ //
+ LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);
+ LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));
+ ASSERT (LongModeBuffer.StackBaseAddress != 0);
+
+ Status = gRT->SetVariable (
+ EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),
+ &LongModeBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Register callback function upon VariableLockProtocol
+ // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiVariableLockProtocolGuid,
+ TPL_CALLBACK,
+ VariableLockCapsuleLongModeBufferVariable,
+ NULL,
+ &Registration
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));
+ gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));
+ }
+}
+
+/**
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 capsule PEI.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ )
+{
+ if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
+ //
+ // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.
+ //
+ PrepareContextForCapsulePei ();
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ComponentName.c
new file mode 100644
index 000000000..6930fae65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ComponentName.c
@@ -0,0 +1,161 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for ConPlatform driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ConPlatform.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConPlatformComponentName = {
+ ConPlatformComponentNameGetDriverName,
+ ConPlatformComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConPlatformComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConPlatformComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConPlatformComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConPlatformDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Platform Console Management 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
+ConPlatformComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConPlatformDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gConPlatformComponentName)
+ );
+}
+
+/**
+ 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
+ConPlatformComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c
new file mode 100644
index 000000000..46e7688f7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c
@@ -0,0 +1,1271 @@
+/** @file
+ Console Platform DXE Driver, install Console Device Guids and update Console
+ Environment Variables.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ConPlatform.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = {
+ ConPlatformTextInDriverBindingSupported,
+ ConPlatformTextInDriverBindingStart,
+ ConPlatformTextInDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
+ ConPlatformTextOutDriverBindingSupported,
+ ConPlatformTextOutDriverBindingStart,
+ ConPlatformTextOutDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of this module.
+
+ This function is the entrypoint of this module. 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
+InitializeConPlatform(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConPlatformTextInDriverBinding,
+ ImageHandle,
+ &gConPlatformComponentName,
+ &gConPlatformComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConPlatformTextOutDriverBinding,
+ NULL,
+ &gConPlatformComponentName,
+ &gConPlatformComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test to see if EFI_SIMPLE_TEXT_INPUT_PROTOCOL is supported on ControllerHandle.
+
+ @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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConPlatformTextInDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return ConPlatformDriverBindingSupported (
+ This,
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid
+ );
+}
+
+
+/**
+ Test to see if EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL is supported on ControllerHandle.
+
+ @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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConPlatformTextOutDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return ConPlatformDriverBindingSupported (
+ This,
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid
+ );
+}
+
+
+/**
+ Test to see if the specified protocol is supported on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param ProtocolGuid The specfic protocol.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+ConPlatformDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_GUID *ProtocolGuid
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ //
+ // Test to see if this is a physical device by checking if
+ // it has a Device Path Protocol.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Test to see if this device supports the specified Protocol.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ ProtocolGuid,
+ (VOID **) &Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on the device for console input.
+
+ Start this driver on ControllerHandle by opening Simple Text Input Protocol,
+ reading Device Path, and installing Console In Devcice GUID on ControllerHandle.
+
+ Append its device path into the console environment variables ConInDev.
+
+ @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
+ConPlatformTextInDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
+ BOOLEAN IsInConInVariable;
+
+ //
+ // Get the Device Path Protocol so the environment variables can be updated
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the Simple Text Input Protocol BY_DRIVER
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &TextIn,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check if the device path is in ConIn Variable
+ //
+ IsInConInVariable = FALSE;
+ Status = ConPlatformUpdateDeviceVariable (
+ L"ConIn",
+ DevicePath,
+ Check
+ );
+ if (!EFI_ERROR (Status)) {
+ IsInConInVariable = TRUE;
+ }
+
+ //
+ // Append the device path to the ConInDev environment variable
+ //
+ ConPlatformUpdateDeviceVariable (
+ L"ConInDev",
+ DevicePath,
+ Append
+ );
+
+ //
+ // If the device path is an instance in the ConIn environment variable,
+ // then install EfiConsoleInDeviceGuid onto ControllerHandle
+ //
+ if (IsInConInVariable) {
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleInDeviceGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on the device for console output and standard error output.
+
+ Start this driver on ControllerHandle by opening Simple Text Output Protocol,
+ reading Device Path, and installing Console Out Devcic GUID, Standard Error
+ Device GUID on ControllerHandle.
+
+ Append its device path into the console environment variables ConOutDev, ErrOutDev.
+
+ @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
+ConPlatformTextOutDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+ BOOLEAN NeedClose;
+ BOOLEAN IsInConOutVariable;
+ BOOLEAN IsInErrOutVariable;
+
+ NeedClose = TRUE;
+
+ //
+ // Get the Device Path Protocol so the environment variables can be updated
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the Simple Text Output Protocol BY_DRIVER
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check if the device path is in ConOut & ErrOut Variable
+ //
+ IsInConOutVariable = FALSE;
+ Status = ConPlatformUpdateDeviceVariable (
+ L"ConOut",
+ DevicePath,
+ Check
+ );
+ if (!EFI_ERROR (Status)) {
+ IsInConOutVariable = TRUE;
+ }
+
+ IsInErrOutVariable = FALSE;
+ Status = ConPlatformUpdateDeviceVariable (
+ L"ErrOut",
+ DevicePath,
+ Check
+ );
+ if (!EFI_ERROR (Status)) {
+ IsInErrOutVariable = TRUE;
+ }
+
+ //
+ // Append the device path to the ConOutDev and ErrOutDev environment variable.
+ // For GOP device path, append the sibling device path as well.
+ //
+ if (!ConPlatformUpdateGopCandidate (DevicePath)) {
+ ConPlatformUpdateDeviceVariable (
+ L"ConOutDev",
+ DevicePath,
+ Append
+ );
+ //
+ // Then append the device path to the ErrOutDev environment variable
+ //
+ ConPlatformUpdateDeviceVariable (
+ L"ErrOutDev",
+ DevicePath,
+ Append
+ );
+ }
+
+ //
+ // If the device path is an instance in the ConOut environment variable,
+ // then install EfiConsoleOutDeviceGuid onto ControllerHandle
+ //
+ if (IsInConOutVariable) {
+ NeedClose = FALSE;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiConsoleOutDeviceGuid,
+ NULL,
+ NULL
+ );
+ }
+ //
+ // If the device path is an instance in the ErrOut environment variable,
+ // then install EfiStandardErrorDeviceGuid onto ControllerHandle
+ //
+ if (IsInErrOutVariable) {
+ NeedClose = FALSE;
+ gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiStandardErrorDeviceGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (NeedClose) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle by removing Console In Devcice GUID
+ and closing the Simple Text Input protocol on ControllerHandle.
+
+ @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
+ConPlatformTextInDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Get the Device Path Protocol firstly
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // If there is device path on ControllerHandle
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Remove DevicePath from ConInDev if exists.
+ //
+ ConPlatformUpdateDeviceVariable (
+ L"ConInDev",
+ DevicePath,
+ Delete
+ );
+ }
+
+ //
+ // Uninstall the Console Device GUIDs from Controller Handle
+ //
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiConsoleInDeviceGuid
+ );
+
+ //
+ // Close the Simple Text Input Protocol
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Stop this driver on ControllerHandle by removing Console Out Devcice GUID
+ and closing the Simple Text Output protocol on ControllerHandle.
+
+ @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
+ConPlatformTextOutDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Get the Device Path Protocol firstly
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Remove DevicePath from ConOutDev and ErrOutDev if exists.
+ //
+ ConPlatformUpdateDeviceVariable (
+ L"ConOutDev",
+ DevicePath,
+ Delete
+ );
+ ConPlatformUpdateDeviceVariable (
+ L"ErrOutDev",
+ DevicePath,
+ Delete
+ );
+ }
+
+ //
+ // Uninstall the Console Device GUIDs from Controller Handle
+ //
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiConsoleOutDeviceGuid
+ );
+
+ ConPlatformUnInstallProtocol (
+ This,
+ ControllerHandle,
+ &gEfiStandardErrorDeviceGuid
+ );
+
+ //
+ // Close the Simple Text Output Protocol
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Uninstall the specified protocol.
+
+ @param This Protocol instance pointer.
+ @param Handle Handle of device to uninstall protocol on.
+ @param ProtocolGuid The specified protocol need to be uninstalled.
+
+**/
+VOID
+ConPlatformUnInstallProtocol (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *ProtocolGuid
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ ProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ ProtocolGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ return ;
+}
+
+/**
+ Get the necessary size of buffer and read the variable.
+
+ First get the necessary size of buffer. Then read the
+ EFI variable (Name) and return a dynamically allocated
+ buffer. On failure return NULL.
+
+ @param Name String part of EFI variable name
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable.
+ Caller is repsoncible freeing the buffer. Return NULL means Variable
+ was not read.
+
+**/
+VOID *
+ConPlatformGetVariable (
+ IN CHAR16 *Name
+ )
+{
+ EFI_STATUS Status;
+ VOID *Buffer;
+ UINTN BufferSize;
+
+ BufferSize = 0;
+ Buffer = NULL;
+
+ //
+ // Test to see if the variable exists. If it doesn't, return NULL.
+ //
+ Status = gRT->GetVariable (
+ Name,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Buffer = AllocatePool (BufferSize);
+ if (Buffer == NULL) {
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (
+ Name,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ //
+ // To make sure Buffer is NULL if any error occurs.
+ //
+ Buffer = NULL;
+ }
+ }
+
+ return Buffer;
+}
+
+/**
+ Function returns TRUE when the two input device paths point to the two
+ GOP child handles that have the same parent.
+
+ @param Left A pointer to a device path data structure.
+ @param Right A pointer to a device path data structure.
+
+ @retval TRUE Left and Right share the same parent.
+ @retval FALSE Left and Right don't share the same parent or either of them is not
+ a GOP device path.
+**/
+BOOLEAN
+IsGopSibling (
+ IN EFI_DEVICE_PATH_PROTOCOL *Left,
+ IN EFI_DEVICE_PATH_PROTOCOL *Right
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *NodeLeft;
+ EFI_DEVICE_PATH_PROTOCOL *NodeRight;
+
+ for (NodeLeft = Left; !IsDevicePathEndType (NodeLeft); NodeLeft = NextDevicePathNode (NodeLeft)) {
+ if ((DevicePathType (NodeLeft) == ACPI_DEVICE_PATH && DevicePathSubType (NodeLeft) == ACPI_ADR_DP) ||
+ (DevicePathType (NodeLeft) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeLeft) == HW_CONTROLLER_DP &&
+ DevicePathType (NextDevicePathNode (NodeLeft)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeLeft)) == ACPI_ADR_DP)) {
+ break;
+ }
+ }
+
+ if (IsDevicePathEndType (NodeLeft)) {
+ return FALSE;
+ }
+
+ for (NodeRight = Right; !IsDevicePathEndType (NodeRight); NodeRight = NextDevicePathNode (NodeRight)) {
+ if ((DevicePathType (NodeRight) == ACPI_DEVICE_PATH && DevicePathSubType (NodeRight) == ACPI_ADR_DP) ||
+ (DevicePathType (NodeRight) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeRight) == HW_CONTROLLER_DP &&
+ DevicePathType (NextDevicePathNode (NodeRight)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeRight)) == ACPI_ADR_DP)) {
+ break;
+ }
+ }
+
+ if (IsDevicePathEndType (NodeRight)) {
+ return FALSE;
+ }
+
+ if (((UINTN) NodeLeft - (UINTN) Left) != ((UINTN) NodeRight - (UINTN) Right)) {
+ return FALSE;
+ }
+
+ return (BOOLEAN) (CompareMem (Left, Right, (UINTN) NodeLeft - (UINTN) Left) == 0);
+}
+
+/**
+ 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
+MatchUsbClass (
+ 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
+MatchUsbWwid (
+ 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;
+}
+
+/**
+ Compare whether a full console device path matches a USB shortform device path.
+
+ @param[in] FullPath Full console device path.
+ @param[in] ShortformPath Short-form device path. Short-form device node may in the beginning or in the middle.
+
+ @retval TRUE The full console device path matches the short-form device path.
+ @retval FALSE The full console device path doesn't match the short-form device path.
+**/
+BOOLEAN
+MatchUsbShortformDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformPath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ShortformNode;
+ UINTN ParentDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_HANDLE Handle;
+
+ for ( ShortformNode = ShortformPath
+ ; !IsDevicePathEnd (ShortformNode)
+ ; ShortformNode = NextDevicePathNode (ShortformNode)
+ ) {
+ if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP))
+ ) {
+ break;
+ }
+ }
+
+ //
+ // Skip further compare when it's not a shortform device path.
+ //
+ if (IsDevicePathEnd (ShortformNode)) {
+ return FALSE;
+ }
+
+ //
+ // Compare the parent device path when the ShortformPath doesn't start with short-form node.
+ //
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) ShortformPath;
+ RemainingDevicePath = FullPath;
+ Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &RemainingDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (ParentDevicePathSize != 0) {
+ if ((ParentDevicePathSize > (UINTN) RemainingDevicePath - (UINTN) FullPath) ||
+ (CompareMem (FullPath, ShortformPath, ParentDevicePathSize) != 0)) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Compar the USB layer.
+ //
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return MatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *)ShortformNode) ||
+ MatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *)ShortformNode);
+}
+
+/**
+ 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.
+ @param NewDevicePath If Delete is TRUE, this parameter must not be null, and it
+ points to the remaining device path data structure.
+ (remaining device path = Multi - Single.)
+ @param Delete If TRUE, means removing Single from Multi.
+ If FALSE, the routine just check whether Single matches
+ with any instance in Multi.
+
+ @retval EFI_SUCCESS If the Single is contained within Multi.
+ @retval EFI_NOT_FOUND If the Single is not contained within Multi.
+ @retval EFI_INVALID_PARAMETER Multi is NULL.
+ @retval EFI_INVALID_PARAMETER Single is NULL.
+ @retval EFI_INVALID_PARAMETER NewDevicePath is NULL when Delete is TRUE.
+
+**/
+EFI_STATUS
+ConPlatformMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single,
+ OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL,
+ IN BOOLEAN Delete
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath1;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath2;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ //
+ // The passed in DevicePath should not be NULL
+ //
+ if ((Multi == NULL) || (Single == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If performing Delete operation, the NewDevicePath must not be NULL.
+ //
+ if (Delete) {
+ if (NewDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ TempDevicePath1 = NULL;
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ if ((CompareMem (Single, DevicePathInst, Size) == 0) ||
+ IsGopSibling (Single, DevicePathInst) || MatchUsbShortformDevicePath (Single, DevicePathInst)) {
+ if (!Delete) {
+ //
+ // If Delete is FALSE, return EFI_SUCCESS if Single is found in Multi.
+ //
+ FreePool (DevicePathInst);
+ return EFI_SUCCESS;
+ }
+ } else {
+ if (Delete) {
+ //
+ // If the node of Multi does not match Single, then added it back to the result.
+ // That is, the node matching Single will be dropped and deleted from result.
+ //
+ TempDevicePath2 = AppendDevicePathInstance (
+ TempDevicePath1,
+ DevicePathInst
+ );
+ if (TempDevicePath1 != NULL) {
+ FreePool (TempDevicePath1);
+ }
+ TempDevicePath1 = TempDevicePath2;
+ }
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ if (Delete) {
+ //
+ // Return the new device path data structure with specified node deleted.
+ //
+ *NewDevicePath = TempDevicePath1;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Update console environment variables.
+
+ @param VariableName Console environment variables, ConOutDev, ConInDev
+ ErrOutDev, ConIn ,ConOut or ErrOut.
+ @param DevicePath Console devcie's device path.
+ @param Operation Variable operations, including APPEND, CHECK and DELETE.
+
+ @retval EFI_SUCCESS Variable operates successfully.
+ @retval EFI_OUT_OF_RESOURCES If variable cannot be appended.
+ @retval other Variable updating failed.
+
+**/
+EFI_STATUS
+ConPlatformUpdateDeviceVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONPLATFORM_VAR_OPERATION Operation
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VariableDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariableDevicePath;
+
+ VariableDevicePath = NULL;
+ NewVariableDevicePath = NULL;
+
+ //
+ // Get Variable according to variable name.
+ // The memory for Variable is allocated within ConPlatformGetVarible(),
+ // it is the caller's responsibility to free the memory before return.
+ //
+ VariableDevicePath = ConPlatformGetVariable (VariableName);
+
+ if (Operation != Delete) {
+ //
+ // Match specified DevicePath in Console Variable.
+ //
+ Status = ConPlatformMatchDevicePaths (
+ VariableDevicePath,
+ DevicePath,
+ NULL,
+ FALSE
+ );
+
+ if ((Operation == Check) || (!EFI_ERROR (Status))) {
+ //
+ // Branch here includes 2 cases:
+ // 1. Operation is CHECK, simply return Status.
+ // 2. Operation is APPEND, and device path already exists in variable, also return.
+ //
+ if (VariableDevicePath != NULL) {
+ FreePool (VariableDevicePath);
+ }
+
+ return Status;
+ }
+ //
+ // We reach here to append a device path that does not exist in variable.
+ //
+ Status = EFI_SUCCESS;
+ NewVariableDevicePath = AppendDevicePathInstance (
+ VariableDevicePath,
+ DevicePath
+ );
+ if (NewVariableDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ } else {
+ //
+ // We reach here to remove DevicePath from the environment variable that
+ // is a multi-instance device path.
+ //
+ Status = ConPlatformMatchDevicePaths (
+ VariableDevicePath,
+ DevicePath,
+ &NewVariableDevicePath,
+ TRUE
+ );
+ }
+
+ if (VariableDevicePath != NULL) {
+ FreePool (VariableDevicePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (NewVariableDevicePath != NULL) {
+ //
+ // Update Console Environment Variable.
+ //
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ GetDevicePathSize (NewVariableDevicePath),
+ NewVariableDevicePath
+ );
+
+ FreePool (NewVariableDevicePath);
+ }
+
+ return Status;
+}
+
+/**
+ Update ConOutDev and ErrOutDev variables to add the device path of
+ GOP controller itself and the sibling controllers.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a GOP device.
+ @retval FALSE The devcie is not a GOP device.
+
+**/
+BOOLEAN
+ConPlatformUpdateGopCandidate (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE PciHandle;
+ EFI_HANDLE GopHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ //
+ // Check whether it's a GOP device.
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiGraphicsOutputProtocolGuid, &TempDevicePath, &GopHandle);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // Get the parent PciIo handle in order to find all the children
+ //
+ Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath, &PciHandle);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ TempDevicePath = EfiBootManagerGetGopDevicePath (PciHandle);
+ if (TempDevicePath != NULL) {
+ ConPlatformUpdateDeviceVariable (L"ConOutDev", TempDevicePath, Append);
+ ConPlatformUpdateDeviceVariable (L"ErrOutDev", TempDevicePath, Append);
+ }
+ return TRUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h
new file mode 100644
index 000000000..f11af2192
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h
@@ -0,0 +1,419 @@
+/** @file
+ Header file for Console Platfrom DXE Driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CON_PLATFORM_H_
+#define _CON_PLATFORM_H_
+
+#include <Uefi.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/GraphicsOutput.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/ConsoleInDevice.h>
+#include <Guid/StandardErrorDevice.h>
+#include <Guid/ConsoleOutDevice.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootManagerLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConPlatformComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConPlatformComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConPlatformComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConPlatformComponentName2;
+
+
+typedef enum {
+ Check,
+ Append,
+ Delete
+} CONPLATFORM_VAR_OPERATION;
+
+/**
+ Test to see if specific protocol could be supported on the ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test.
+ @param ProtocolGuid The specfic protocol.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+ConPlatformDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_GUID *ProtocolGuid
+ );
+
+/**
+ Test to see if EFI_SIMPLE_TEXT_INPUT_PROTOCOL is supported on ControllerHandle.
+
+ @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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConPlatformTextInDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Test to see if EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL is supported on ControllerHandle.
+
+ @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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConPlatformTextOutDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on the device for console input.
+
+ Start this driver on ControllerHandle by opening Simple Text Input Protocol,
+ reading Device Path, and installing Console In Devcice GUID on ControllerHandle.
+
+ Append its device path into the console environment variables ConInDev.
+
+ @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
+ConPlatformTextInDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on the device for console output and standard error output.
+
+ Start this driver on ControllerHandle by opening Simple Text Output Protocol,
+ reading Device Path, and installing Console Out Devcic GUID, Standard Error
+ Device GUID on ControllerHandle.
+
+ Append its device path into the console environment variables ConOutDev, ErrOutDev.
+
+ @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
+ConPlatformTextOutDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing Console In Devcice GUID
+ and closing the Simple Text Input protocol on ControllerHandle.
+
+ @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
+ConPlatformTextInDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing Console Out Devcice GUID
+ and closing the Simple Text Output protocol on ControllerHandle.
+
+ @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
+ConPlatformTextOutDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Uninstall the specified protocol.
+
+ @param This Protocol instance pointer.
+ @param Handle Handle of device to uninstall protocol on.
+ @param ProtocolGuid The specified protocol need to be uninstalled.
+
+**/
+VOID
+ConPlatformUnInstallProtocol (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *ProtocolGuid
+ );
+
+/**
+ Read the EFI variable (Name) and return a dynamically allocated
+ buffer, and the size of the buffer. On failure return NULL.
+
+ @param Name String part of EFI variable name
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable.
+ Caller is repsoncible freeing the buffer. Return NULL means Variable
+ was not read.
+
+**/
+VOID *
+ConPlatformGetVariable (
+ IN CHAR16 *Name
+ );
+
+/**
+ 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.
+ @param NewDevicePath If Delete is TRUE, this parameter must not be null, and it
+ points to the remaining device path data structure.
+ (remaining device path = Multi - Single.)
+ @param Delete If TRUE, means removing Single from Multi.
+ If FALSE, the routine just check whether Single matches
+ with any instance in Multi.
+
+ @retval EFI_SUCCESS If the Single is contained within Multi.
+ @retval EFI_NOT_FOUND If the Single is not contained within Multi.
+ @retval EFI_INVALID_PARAMETER Multi is NULL.
+ @retval EFI_INVALID_PARAMETER Single is NULL.
+ @retval EFI_INVALID_PARAMETER NewDevicePath is NULL when Delete is TRUE.
+
+**/
+EFI_STATUS
+ConPlatformMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single,
+ OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL,
+ IN BOOLEAN Delete
+ );
+
+/**
+ Update console environment variables.
+
+ @param VariableName Console environment variables, ConOutDev, ConInDev
+ StdErrDev, ConIn or ConOut.
+ @param DevicePath Console devcie's device path.
+ @param Operation Variable operations, including APPEND, CHECK and DELETE.
+
+ @retval EFI_SUCCESS Variable operates successfully.
+ @retval EFI_OUT_OF_RESOURCES If variable cannot be appended.
+ @retval other Variable updating failed.
+
+**/
+EFI_STATUS
+ConPlatformUpdateDeviceVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONPLATFORM_VAR_OPERATION Operation
+ );
+
+//
+// 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
+ConPlatformComponentNameGetDriverName (
+ 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
+ConPlatformComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Update ConOutDev and ErrOutDev variables to add the device path of
+ GOP controller itself and the sibling controllers.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a GOP device.
+ @retval FALSE The devcie is not a GOP device.
+
+**/
+BOOLEAN
+ConPlatformUpdateGopCandidate (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
new file mode 100644
index 000000000..ad11c09c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
@@ -0,0 +1,95 @@
+## @file
+# Platform console driver manages console devices.
+#
+# Console Platfrom DXE Driver that specifies whether device can be used as console
+# input/output device or error output device and update global variables accordingly.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ConPlatformDxe
+ MODULE_UNI_FILE = ConPlatformDxe.uni
+ FILE_GUID = 51ccf399-4fdf-4e55-a45b-e123f84d456a
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeConPlatform
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gConPlatformTextInDriverBinding
+# COMPONENT_NAME = gConPlatformComponentName
+# COMPONENT_NAME2 = gConPlatformComponentName2
+# DRIVER_BINDING = gConPlatformTextOutDriverBinding
+# COMPONENT_NAME = gConPlatformComponentName
+# COMPONENT_NAME2 = gConPlatformComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ ConPlatform.h
+ ConPlatform.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootManagerLib
+
+[Guids]
+ #
+ # This is the VendorGuid of all architecturally defined variables in UEFI spec.
+ #
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut"
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut"
+ ## SOMETIMES_PRODUCES ## Variable:L"ConInDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOutDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOutDev"
+ gEfiGlobalVariableGuid
+ #
+ # This GUID is used to specify the device is the standard error device.
+ # If the device is a standard error device, this GUID as the protocol GUID will be installed
+ # onto this device handle.
+ #
+ gEfiStandardErrorDeviceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # protocol GUID installed on device handle
+ #
+ # This GUID is used to specify the device is the console output device.
+ # If the device is a console output device, this GUID as the protocol GUID will be installed
+ # onto this device handle.
+ #
+ gEfiConsoleOutDeviceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # protocol GUID installed on device handle
+ #
+ # This GUID is used to specify the device is the console input device.
+ # If the device is a console input device, this GUID as the protocol GUID will be installed
+ # onto this device handle.
+ #
+ gEfiConsoleInDeviceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # protocol GUID installed on device handle
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiSimpleTextInProtocolGuid ## TO_START
+ gEfiSimpleTextOutProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ConPlatformDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.uni b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.uni
new file mode 100644
index 000000000..40c54790f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Platform console driver manages console devices.
+//
+// Console Platfrom DXE Driver that specifies whether device can be used as console
+// input/output device or error output device and update global variables accordingly.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages console devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Console Platform DXE Driver that specifies whether a device can be used as console input/output device or error output device and updates global variables accordingly."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxeExtra.uni
new file mode 100644
index 000000000..797a143be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ConPlatformDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Console Platform DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c
new file mode 100644
index 000000000..72c01ece5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ComponentName.c
@@ -0,0 +1,770 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for ConSplitter driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ConSplitter.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConSplitterConInComponentName = {
+ ConSplitterComponentNameGetDriverName,
+ ConSplitterConInComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConSplitterConInComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConSplitterComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConSplitterConInComponentNameGetControllerName,
+ "en"
+};
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConSplitterSimplePointerComponentName = {
+ ConSplitterComponentNameGetDriverName,
+ ConSplitterSimplePointerComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConSplitterSimplePointerComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConSplitterComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConSplitterSimplePointerComponentNameGetControllerName,
+ "en"
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConSplitterAbsolutePointerComponentName = {
+ ConSplitterComponentNameGetDriverName,
+ ConSplitterAbsolutePointerComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConSplitterAbsolutePointerComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConSplitterComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConSplitterAbsolutePointerComponentNameGetControllerName,
+ "en"
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConSplitterConOutComponentName = {
+ ConSplitterComponentNameGetDriverName,
+ ConSplitterConOutComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConSplitterConOutComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConSplitterComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConSplitterConOutComponentNameGetControllerName,
+ "en"
+};
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName = {
+ ConSplitterComponentNameGetDriverName,
+ ConSplitterStdErrComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gConSplitterStdErrComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ConSplitterComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ConSplitterStdErrComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Console Splitter Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterConInControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Primary Console Input Device"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterSimplePointerControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Primary Simple Pointer Device"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterAbsolutePointerControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Primary Absolute Pointer Device"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterConOutControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Primary Console Output Device"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mConSplitterStdErrControllerNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Primary Standard Error Device"
+ },
+ {
+ 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
+ConSplitterComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterDriverNameTable,
+ DriverName,
+ (BOOLEAN)((This == &gConSplitterConInComponentName) ||
+ (This == &gConSplitterSimplePointerComponentName) ||
+ (This == &gConSplitterAbsolutePointerComponentName) ||
+ (This == &gConSplitterConOutComponentName) ||
+ (This == &gConSplitterStdErrComponentName))
+ );
+}
+
+/**
+ Tests whether a controller handle is being managed by a specific driver and
+ the child handle is a child device of the controller.
+
+ @param ControllerHandle A handle for a controller to test.
+ @param DriverBindingHandle Specifies the driver binding handle for the
+ driver.
+ @param ProtocolGuid Specifies the protocol that the driver specified
+ by DriverBindingHandle opens in its Start()
+ function.
+ @param ChildHandle A child handle to test.
+ @param ConsumsedGuid Supplies the protocol that the child controller
+ opens on its parent controller.
+
+ @retval EFI_SUCCESS ControllerHandle is managed by the driver
+ specifed by DriverBindingHandle and ChildHandle
+ is a child of the ControllerHandle.
+ @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
+ specifed by DriverBindingHandle.
+ @retval EFI_UNSUPPORTED ChildHandle is not a child of the
+ ControllerHandle.
+
+**/
+EFI_STATUS
+ConSplitterTestControllerHandles (
+ IN CONST EFI_HANDLE ControllerHandle,
+ IN CONST EFI_HANDLE DriverBindingHandle,
+ IN CONST EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST EFI_GUID *ConsumsedGuid
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // here ChildHandle is not an Optional parameter.
+ //
+ if (ChildHandle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Tests whether a controller handle is being managed by a specific driver.
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ DriverBindingHandle,
+ ProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Tests whether a child handle is a child device of the controller.
+ //
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ ConsumsedGuid
+ );
+
+ return Status;
+}
+
+/**
+ 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
+ConSplitterConInComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ConSplitterTestControllerHandles (
+ ControllerHandle,
+ gConSplitterConInDriverBinding.DriverBindingHandle,
+ &gEfiConsoleInDeviceGuid,
+ ChildHandle,
+ &gEfiConsoleInDeviceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterConInControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gConSplitterConInComponentName)
+ );
+}
+
+/**
+ 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
+ConSplitterSimplePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ConSplitterTestControllerHandles (
+ ControllerHandle,
+ gConSplitterSimplePointerDriverBinding.DriverBindingHandle,
+ &gEfiSimplePointerProtocolGuid,
+ ChildHandle,
+ &gEfiSimplePointerProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterSimplePointerControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gConSplitterSimplePointerComponentName)
+ );
+}
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the 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 RFC4646 language identifier. This is
+ the language of the controller name that 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.
+ @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
+ConSplitterAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ConSplitterTestControllerHandles (
+ ControllerHandle,
+ gConSplitterAbsolutePointerDriverBinding.DriverBindingHandle,
+ &gEfiAbsolutePointerProtocolGuid,
+ ChildHandle,
+ &gEfiAbsolutePointerProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterAbsolutePointerControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gConSplitterAbsolutePointerComponentName)
+ );
+}
+
+/**
+ 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
+ConSplitterConOutComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ConSplitterTestControllerHandles (
+ ControllerHandle,
+ gConSplitterConOutDriverBinding.DriverBindingHandle,
+ &gEfiConsoleOutDeviceGuid,
+ ChildHandle,
+ &gEfiConsoleOutDeviceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterConOutControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gConSplitterConOutComponentName)
+ );
+}
+
+/**
+ 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
+ConSplitterStdErrComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ConSplitterTestControllerHandles (
+ ControllerHandle,
+ gConSplitterStdErrDriverBinding.DriverBindingHandle,
+ &gEfiStandardErrorDeviceGuid,
+ ChildHandle,
+ &gEfiStandardErrorDeviceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mConSplitterStdErrControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gConSplitterStdErrComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
new file mode 100644
index 000000000..9c38271b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
@@ -0,0 +1,5113 @@
+/** @file
+ Console Splitter Driver. Any Handle that attatched console I/O protocols
+ (Console In device, Console Out device, Console Error device, Simple Pointer
+ protocol, Absolute Pointer protocol) can be bound by this driver.
+
+ So far it works like any other driver by opening a SimpleTextIn and/or
+ SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big
+ difference is this driver does not layer a protocol on the passed in
+ handle, or construct a child handle like a standard device or bus driver.
+ This driver produces three virtual handles as children, one for console input
+ splitter, one for console output splitter and one for error output splitter.
+ These 3 virtual handles would be installed on gST.
+
+ Each virtual handle, that supports the Console I/O protocol, will be produced
+ in the driver entry point. The virtual handle are added on driver entry and
+ never removed. Such design ensures sytem function well during none console
+ device situation.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ConSplitter.h"
+
+//
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.
+// default not connect
+//
+BOOLEAN mConInIsConnect = FALSE;
+
+//
+// Text In Splitter Private Data template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = {
+ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE,
+ (EFI_HANDLE) NULL,
+
+ {
+ ConSplitterTextInReset,
+ ConSplitterTextInReadKeyStroke,
+ (EFI_EVENT) NULL
+ },
+ 0,
+ (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL,
+ 0,
+
+ {
+ ConSplitterTextInResetEx,
+ ConSplitterTextInReadKeyStrokeEx,
+ (EFI_EVENT) NULL,
+ ConSplitterTextInSetState,
+ ConSplitterTextInRegisterKeyNotify,
+ ConSplitterTextInUnregisterKeyNotify
+ },
+ 0,
+ (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL,
+ 0,
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ (EFI_KEY_DATA *) NULL,
+ 0,
+ 0,
+ FALSE,
+
+ {
+ ConSplitterSimplePointerReset,
+ ConSplitterSimplePointerGetState,
+ (EFI_EVENT) NULL,
+ (EFI_SIMPLE_POINTER_MODE *) NULL
+ },
+ {
+ 0x10000,
+ 0x10000,
+ 0x10000,
+ TRUE,
+ TRUE
+ },
+ 0,
+ (EFI_SIMPLE_POINTER_PROTOCOL **) NULL,
+ 0,
+
+ {
+ ConSplitterAbsolutePointerReset,
+ ConSplitterAbsolutePointerGetState,
+ (EFI_EVENT) NULL,
+ (EFI_ABSOLUTE_POINTER_MODE *) NULL
+ },
+ {
+ 0, // AbsoluteMinX
+ 0, // AbsoluteMinY
+ 0, // AbsoluteMinZ
+ 0x10000, // AbsoluteMaxX
+ 0x10000, // AbsoluteMaxY
+ 0x10000, // AbsoluteMaxZ
+ 0 // Attributes
+ },
+ 0,
+ (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL,
+ 0,
+ FALSE,
+
+ FALSE,
+ FALSE
+};
+
+
+//
+// Uga Draw Protocol Private Data template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL mUgaDrawProtocolTemplate = {
+ ConSplitterUgaDrawGetMode,
+ ConSplitterUgaDrawSetMode,
+ ConSplitterUgaDrawBlt
+};
+
+//
+// Graphics Output Protocol Private Data template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL mGraphicsOutputProtocolTemplate = {
+ ConSplitterGraphicsOutputQueryMode,
+ ConSplitterGraphicsOutputSetMode,
+ ConSplitterGraphicsOutputBlt,
+ NULL
+};
+
+
+//
+// Text Out Splitter Private Data template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
+ (EFI_HANDLE) NULL,
+ {
+ ConSplitterTextOutReset,
+ ConSplitterTextOutOutputString,
+ ConSplitterTextOutTestString,
+ ConSplitterTextOutQueryMode,
+ ConSplitterTextOutSetMode,
+ ConSplitterTextOutSetAttribute,
+ ConSplitterTextOutClearScreen,
+ ConSplitterTextOutSetCursorPosition,
+ ConSplitterTextOutEnableCursor,
+ (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
+ },
+ {
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ FALSE,
+ },
+
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
+ 0,
+ 0,
+
+ 0,
+ (TEXT_OUT_AND_GOP_DATA *) NULL,
+ 0,
+ (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
+ 0,
+ (INT32 *) NULL,
+ FALSE
+};
+
+//
+// Standard Error Text Out Splitter Data Template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,
+ (EFI_HANDLE) NULL,
+ {
+ ConSplitterTextOutReset,
+ ConSplitterTextOutOutputString,
+ ConSplitterTextOutTestString,
+ ConSplitterTextOutQueryMode,
+ ConSplitterTextOutSetMode,
+ ConSplitterTextOutSetAttribute,
+ ConSplitterTextOutClearScreen,
+ ConSplitterTextOutSetCursorPosition,
+ ConSplitterTextOutEnableCursor,
+ (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
+ },
+ {
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ FALSE,
+ },
+
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+ (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL,
+ 0,
+ 0,
+
+ 0,
+ (TEXT_OUT_AND_GOP_DATA *) NULL,
+ 0,
+ (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
+ 0,
+ (INT32 *) NULL,
+ FALSE
+};
+
+//
+// Driver binding instance for Console Input Device
+//
+EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding = {
+ ConSplitterConInDriverBindingSupported,
+ ConSplitterConInDriverBindingStart,
+ ConSplitterConInDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Driver binding instance for Console Out device
+//
+EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding = {
+ ConSplitterConOutDriverBindingSupported,
+ ConSplitterConOutDriverBindingStart,
+ ConSplitterConOutDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Driver binding instance for Standard Error device
+//
+EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding = {
+ ConSplitterStdErrDriverBindingSupported,
+ ConSplitterStdErrDriverBindingStart,
+ ConSplitterStdErrDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Driver binding instance for Simple Pointer protocol
+//
+EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding = {
+ ConSplitterSimplePointerDriverBindingSupported,
+ ConSplitterSimplePointerDriverBindingStart,
+ ConSplitterSimplePointerDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Driver binding instance for Absolute Pointer protocol
+//
+EFI_DRIVER_BINDING_PROTOCOL gConSplitterAbsolutePointerDriverBinding = {
+ ConSplitterAbsolutePointerDriverBindingSupported,
+ ConSplitterAbsolutePointerDriverBindingStart,
+ ConSplitterAbsolutePointerDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Key notify for toggle state sync.
+
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information for the key that was
+ pressed.
+
+ @retval EFI_SUCCESS Toggle state sync successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ToggleStateSyncKeyNotify (
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ UINTN Index;
+
+ if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&
+ (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {
+ //
+ // There is toggle state change, sync to other console input devices.
+ //
+ for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {
+ mConIn.TextInExList[Index]->SetState (
+ mConIn.TextInExList[Index],
+ &KeyData->KeyState.KeyToggleState
+ );
+ }
+ mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;
+ DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for toggle state sync.
+
+ @param Private Text In Splitter pointer.
+
+**/
+VOID
+ToggleStateSyncInitialization (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ EFI_KEY_DATA KeyData;
+ VOID *NotifyHandle;
+
+ //
+ // Initialize PhysicalKeyToggleState that will be synced to new console
+ // input device to turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
+
+ //
+ // Initialize VirtualKeyStateExported to let the virtual TextInEx not report
+ // the partial key even though the physical TextInEx turns on the partial
+ // key report. The virtual TextInEx will report the partial key after it is
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
+ //
+ Private->VirtualKeyStateExported = FALSE;
+
+ //
+ // Register key notify for toggle state sync.
+ //
+ KeyData.Key.ScanCode = SCAN_NULL;
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ KeyData.KeyState.KeyShiftState = 0;
+ KeyData.KeyState.KeyToggleState = 0;
+ Private->TextInEx.RegisterKeyNotify (
+ &Private->TextInEx,
+ &KeyData,
+ ToggleStateSyncKeyNotify,
+ &NotifyHandle
+ );
+}
+
+/**
+ Reinitialization for toggle state sync.
+
+ @param Private Text In Splitter pointer.
+
+**/
+VOID
+ToggleStateSyncReInitialization (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ UINTN Index;
+
+ //
+ // Reinitialize PhysicalKeyToggleState that will be synced to new console
+ // input device to turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
+
+ //
+ // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report
+ // the partial key even though the physical TextInEx turns on the partial
+ // key report. The virtual TextInEx will report the partial key after it is
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
+ //
+ Private->VirtualKeyStateExported = FALSE;
+
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Private->TextInExList[Index]->SetState (
+ Private->TextInExList[Index],
+ &Private->PhysicalKeyToggleState
+ );
+ }
+}
+
+/**
+ The Entry Point for module ConSplitter. The user code starts with this function.
+
+ Installs driver module protocols and. Creates virtual device handles for ConIn,
+ ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
+ Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
+ Installs Graphics Output protocol and/or UGA Draw protocol if needed.
+
+ @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
+ConSplitterDriverEntry(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConSplitterConInDriverBinding,
+ ImageHandle,
+ &gConSplitterConInComponentName,
+ &gConSplitterConInComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConSplitterSimplePointerDriverBinding,
+ NULL,
+ &gConSplitterSimplePointerComponentName,
+ &gConSplitterSimplePointerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConSplitterAbsolutePointerDriverBinding,
+ NULL,
+ &gConSplitterAbsolutePointerComponentName,
+ &gConSplitterAbsolutePointerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConSplitterConOutDriverBinding,
+ NULL,
+ &gConSplitterConOutComponentName,
+ &gConSplitterConOutComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gConSplitterStdErrDriverBinding,
+ NULL,
+ &gConSplitterStdErrComponentName,
+ &gConSplitterStdErrComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Either Graphics Output protocol or UGA Draw protocol must be supported.
+ //
+ ASSERT (FeaturePcdGet (PcdConOutGopSupport) ||
+ FeaturePcdGet (PcdConOutUgaSupport));
+
+ //
+ // The driver creates virtual handles for ConIn, ConOut, StdErr.
+ // The virtual handles will always exist even if no console exist in the
+ // system. This is need to support hotplug devices like USB.
+ //
+ //
+ // Create virtual device handle for ConIn Splitter
+ //
+ Status = ConSplitterTextInConstructor (&mConIn);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConIn.VirtualHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ &mConIn.TextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &mConIn.TextInEx,
+ &gEfiSimplePointerProtocolGuid,
+ &mConIn.SimplePointer,
+ &gEfiAbsolutePointerProtocolGuid,
+ &mConIn.AbsolutePointer,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update the EFI System Table with new virtual console
+ // and update the pointer to Simple Text Input protocol.
+ //
+ gST->ConsoleInHandle = mConIn.VirtualHandle;
+ gST->ConIn = &mConIn.TextIn;
+ }
+ }
+ //
+ // Create virtual device handle for ConOut Splitter
+ //
+ Status = ConSplitterTextOutConstructor (&mConOut);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ &mConOut.TextOut,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update the EFI System Table with new virtual console
+ // and Update the pointer to Text Output protocol.
+ //
+ gST->ConsoleOutHandle = mConOut.VirtualHandle;
+ gST->ConOut = &mConOut.TextOut;
+ }
+
+ }
+
+ //
+ // Create virtual device handle for StdErr Splitter
+ //
+ Status = ConSplitterTextOutConstructor (&mStdErr);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mStdErr.VirtualHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ &mStdErr.TextOut,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update the EFI System Table with new virtual console
+ // and update the pointer to Text Output protocol.
+ //
+ gST->StandardErrorHandle = mStdErr.VirtualHandle;
+ gST->StdErr = &mStdErr.TextOut;
+ }
+ }
+
+ //
+ // 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;
+
+}
+
+/**
+ Construct console input devices' private data.
+
+ @param ConInPrivate A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA
+ structure.
+
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_SUCCESS Text Input Devcie's private data has been constructed.
+ @retval other Failed to construct private data.
+
+**/
+EFI_STATUS
+ConSplitterTextInConstructor (
+ TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate
+ )
+{
+ EFI_STATUS Status;
+ UINTN TextInExListCount;
+
+ //
+ // Allocate buffer for Simple Text Input device
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
+ &ConInPrivate->TextInListCount,
+ (VOID **) &ConInPrivate->TextInList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create Event to wait for a key
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ ConSplitterTextInWaitForKey,
+ ConInPrivate,
+ &ConInPrivate->TextIn.WaitForKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate buffer for KeyQueue
+ //
+ TextInExListCount = ConInPrivate->TextInExListCount;
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_KEY_DATA),
+ &TextInExListCount,
+ (VOID **) &ConInPrivate->KeyQueue
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate buffer for Simple Text Input Ex device
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
+ &ConInPrivate->TextInExListCount,
+ (VOID **) &ConInPrivate->TextInExList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create Event to wait for a key Ex
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ ConSplitterTextInWaitForKey,
+ ConInPrivate,
+ &ConInPrivate->TextInEx.WaitForKeyEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeListHead (&ConInPrivate->NotifyList);
+
+ ToggleStateSyncInitialization (ConInPrivate);
+
+ ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;
+ //
+ // Allocate buffer for Absolute Pointer device
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
+ &ConInPrivate->AbsolutePointerListCount,
+ (VOID **) &ConInPrivate->AbsolutePointerList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create Event to wait for device input for Absolute pointer device
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ ConSplitterAbsolutePointerWaitForInput,
+ ConInPrivate,
+ &ConInPrivate->AbsolutePointer.WaitForInput
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;
+ //
+ // Allocate buffer for Simple Pointer device
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
+ &ConInPrivate->PointerListCount,
+ (VOID **) &ConInPrivate->PointerList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create Event to wait for device input for Simple pointer device
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ ConSplitterSimplePointerWaitForInput,
+ ConInPrivate,
+ &ConInPrivate->SimplePointer.WaitForInput
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Create Event to signal ConIn connection request
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EfiEventEmptyFunction,
+ NULL,
+ &gConnectConInEventGuid,
+ &ConInPrivate->ConnectConInEvent
+ );
+
+ return Status;
+}
+
+/**
+ Construct console output devices' private data.
+
+ @param ConOutPrivate A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA
+ structure.
+
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_SUCCESS Text Input Devcie's private data has been constructed.
+
+**/
+EFI_STATUS
+ConSplitterTextOutConstructor (
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+
+ //
+ // Copy protocols template
+ //
+ if (FeaturePcdGet (PcdConOutUgaSupport)) {
+ CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL));
+ }
+ if (FeaturePcdGet (PcdConOutGopSupport)) {
+ CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL));
+ }
+
+ //
+ // Initilize console output splitter's private data.
+ //
+ ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;
+
+ //
+ // When new console device is added, the new mode will be set later,
+ // so put current mode back to init state.
+ //
+ ConOutPrivate->TextOutMode.Mode = 0xFF;
+ //
+ // Allocate buffer for Console Out device
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (TEXT_OUT_AND_GOP_DATA),
+ &ConOutPrivate->TextOutListCount,
+ (VOID **) &ConOutPrivate->TextOutList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocate buffer for Text Out query data
+ //
+ Status = ConSplitterGrowBuffer (
+ sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
+ &ConOutPrivate->TextOutQueryDataCount,
+ (VOID **) &ConOutPrivate->TextOutQueryData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Setup the default console to 80 x 25 and mode to 0
+ //
+ ConOutPrivate->TextOutQueryData[0].Columns = 80;
+ ConOutPrivate->TextOutQueryData[0].Rows = 25;
+ TextOutSetMode (ConOutPrivate, 0);
+
+
+ if (FeaturePcdGet (PcdConOutUgaSupport)) {
+ //
+ // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz.
+ //
+ ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60);
+ }
+ if (FeaturePcdGet (PcdConOutGopSupport)) {
+ //
+ // Setup resource for mode information in Graphics Output Protocol interface
+ //
+ if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel
+ // DevNull will be updated to user-defined mode after driver has started.
+ //
+ if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Info = &ConOutPrivate->GraphicsOutputModeBuffer[0];
+ Info->Version = 0;
+ Info->HorizontalResolution = 800;
+ Info->VerticalResolution = 600;
+ Info->PixelFormat = PixelBltOnly;
+ Info->PixelsPerScanLine = 800;
+ CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ //
+ // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()
+ // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize
+ //
+ ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
+ ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;
+
+ ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;
+ //
+ // Initial current mode to unknown state, and then set to mode 0
+ //
+ ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;
+ ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test to see if the specified protocol could be supported on the specified device.
+
+ @param This Driver Binding protocol pointer.
+ @param ControllerHandle Handle of device to test.
+ @param Guid The specified protocol.
+
+ @retval EFI_SUCCESS The specified protocol is supported on this device.
+ @retval EFI_UNSUPPORTED The specified protocol attempts to be installed on virtul handle.
+ @retval other Failed to open specified protocol on this device.
+
+**/
+EFI_STATUS
+ConSplitterSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ VOID *Instance;
+
+ //
+ // Make sure the Console Splitter does not attempt to attach to itself
+ //
+ if (ControllerHandle == mConIn.VirtualHandle ||
+ ControllerHandle == mConOut.VirtualHandle ||
+ ControllerHandle == mStdErr.VirtualHandle
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check to see whether the specific protocol could be opened BY_DRIVER
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ Guid,
+ &Instance,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ Guid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test to see if Console In Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConInDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return ConSplitterSupported (
+ This,
+ ControllerHandle,
+ &gEfiConsoleInDeviceGuid
+ );
+}
+
+/**
+ Test to see if Simple Pointer protocol could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return ConSplitterSupported (
+ This,
+ ControllerHandle,
+ &gEfiSimplePointerProtocolGuid
+ );
+}
+
+/**
+ Test to see if Absolute Pointer protocol could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return ConSplitterSupported (
+ This,
+ ControllerHandle,
+ &gEfiAbsolutePointerProtocolGuid
+ );
+}
+
+
+/**
+ Test to see if Console Out Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConOutDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return ConSplitterSupported (
+ This,
+ ControllerHandle,
+ &gEfiConsoleOutDeviceGuid
+ );
+}
+
+/**
+ Test to see if Standard Error Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterStdErrDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ return ConSplitterSupported (
+ This,
+ ControllerHandle,
+ &gEfiStandardErrorDeviceGuid
+ );
+}
+
+
+/**
+ Start ConSplitter on devcie handle by opening Console Device Guid on device handle
+ and the console virtual handle. And Get the console interface on controller handle.
+
+ @param This Driver Binding protocol instance pointer.
+ @param ControllerHandle Handle of device.
+ @param ConSplitterVirtualHandle Console virtual Handle.
+ @param DeviceGuid The specified Console Device, such as ConInDev,
+ ConOutDev.
+ @param InterfaceGuid The specified protocol to be opened.
+ @param Interface Protocol interface returned.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other Failed to open the specified Console Device Guid
+ or specified protocol.
+
+**/
+EFI_STATUS
+ConSplitterStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ConSplitterVirtualHandle,
+ IN EFI_GUID *DeviceGuid,
+ IN EFI_GUID *InterfaceGuid,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ VOID *Instance;
+
+ //
+ // Check to see whether the ControllerHandle has the DeviceGuid on it.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ &Instance,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the Parent Handle for the child.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ &Instance,
+ This->DriverBindingHandle,
+ ConSplitterVirtualHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Err;
+ }
+
+ //
+ // Open InterfaceGuid on the virtul handle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ InterfaceGuid,
+ Interface,
+ This->DriverBindingHandle,
+ ConSplitterVirtualHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // close the DeviceGuid on ConSplitter VirtualHandle.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ This->DriverBindingHandle,
+ ConSplitterVirtualHandle
+ );
+
+Err:
+ //
+ // close the DeviceGuid on ControllerHandle.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+
+/**
+ Start Console In Consplitter on device handle.
+
+ @param This Driver Binding 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 Console In Consplitter is added to ControllerHandle.
+ @retval other Console In Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConInDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
+
+ //
+ // Start ConSplitter on ControllerHandle, and create the virtual
+ // agrogated console device on first call Start for a SimpleTextIn handle.
+ //
+ Status = ConSplitterStart (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiConsoleInDeviceGuid,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &TextIn
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Add this device into Text In devices list.
+ //
+ Status = ConSplitterTextInAddDevice (&mConIn, TextIn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &TextInEx,
+ This->DriverBindingHandle,
+ mConIn.VirtualHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If Simple Text Input Ex protocol exists,
+ // add this device into Text In Ex devices list.
+ //
+ Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx);
+ }
+
+ return Status;
+}
+
+
+/**
+ Start Simple Pointer Consplitter on device handle.
+
+ @param This Driver Binding 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 Simple Pointer Consplitter is added to ControllerHandle.
+ @retval other Simple Pointer Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
+
+ //
+ // Start ConSplitter on ControllerHandle, and create the virtual
+ // agrogated console device on first call Start for a SimplePointer handle.
+ //
+ Status = ConSplitterStart (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiSimplePointerProtocolGuid,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Add this devcie into Simple Pointer devices list.
+ //
+ return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);
+}
+
+
+/**
+ Start Absolute Pointer Consplitter on device handle.
+
+ @param This Driver Binding 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 Absolute Pointer Consplitter is added to ControllerHandle.
+ @retval other Absolute Pointer Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
+
+ //
+ // Start ConSplitter on ControllerHandle, and create the virtual
+ // agrogated console device on first call Start for a AbsolutePointer handle.
+ //
+ Status = ConSplitterStart (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiAbsolutePointerProtocolGuid,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Add this devcie into Absolute Pointer devices list.
+ //
+ return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer);
+}
+
+
+/**
+ Start Console Out Consplitter on device handle.
+
+ @param This Driver Binding 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 Console Out Consplitter is added to ControllerHandle.
+ @retval other Console Out Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConOutDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+
+ //
+ // Start ConSplitter on ControllerHandle, and create the virtual
+ // agrogated console device on first call Start for a ConsoleOut handle.
+ //
+ Status = ConSplitterStart (
+ This,
+ ControllerHandle,
+ mConOut.VirtualHandle,
+ &gEfiConsoleOutDeviceGuid,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GraphicsOutput = NULL;
+ UgaDraw = NULL;
+ //
+ // Try to Open Graphics Output protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ mConOut.VirtualHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // Open UGA DRAW protocol
+ //
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw,
+ This->DriverBindingHandle,
+ mConOut.VirtualHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ }
+
+ //
+ // When new console device is added, the new mode will be set later,
+ // so put current mode back to init state.
+ //
+ mConOut.TextOutMode.Mode = 0xFF;
+
+ //
+ // If both ConOut and StdErr incorporate the same Text Out device,
+ // their MaxMode and QueryData should be the intersection of both.
+ //
+ Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);
+ ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+
+ if (FeaturePcdGet (PcdConOutUgaSupport)) {
+ //
+ // Get the UGA mode data of ConOut from the current mode
+ //
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+
+ mConOut.UgaHorizontalResolution = Info->HorizontalResolution;
+ mConOut.UgaVerticalResolution = Info->VerticalResolution;
+ mConOut.UgaColorDepth = 32;
+ mConOut.UgaRefreshRate = 60;
+
+ FreePool (Info);
+
+ } else if (UgaDraw != NULL) {
+ Status = UgaDraw->GetMode (
+ UgaDraw,
+ &mConOut.UgaHorizontalResolution,
+ &mConOut.UgaVerticalResolution,
+ &mConOut.UgaColorDepth,
+ &mConOut.UgaRefreshRate
+ );
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Start Standard Error Consplitter on device handle.
+
+ @param This Driver Binding 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 Standard Error Consplitter is added to ControllerHandle.
+ @retval other Standard Error Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterStdErrDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ //
+ // Start ConSplitter on ControllerHandle, and create the virtual
+ // agrogated console device on first call Start for a StandardError handle.
+ //
+ Status = ConSplitterStart (
+ This,
+ ControllerHandle,
+ mStdErr.VirtualHandle,
+ &gEfiStandardErrorDeviceGuid,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // When new console device is added, the new mode will be set later,
+ // so put current mode back to init state.
+ //
+ mStdErr.TextOutMode.Mode = 0xFF;
+
+ //
+ // If both ConOut and StdErr incorporate the same Text Out device,
+ // their MaxMode and QueryData should be the intersection of both.
+ //
+ Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);
+ ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));
+
+ return Status;
+}
+
+
+/**
+ Stop ConSplitter on device handle by closing Console Device Guid on device handle
+ and the console virtual handle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device.
+ @param ConSplitterVirtualHandle Console virtual Handle.
+ @param DeviceGuid The specified Console Device, such as ConInDev,
+ ConOutDev.
+ @param InterfaceGuid The specified protocol to be opened.
+ @param Interface Protocol interface returned.
+
+ @retval EFI_SUCCESS Stop ConSplitter on ControllerHandle successfully.
+ @retval other Failed to Stop ConSplitter on ControllerHandle.
+
+**/
+EFI_STATUS
+ConSplitterStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ConSplitterVirtualHandle,
+ IN EFI_GUID *DeviceGuid,
+ IN EFI_GUID *InterfaceGuid,
+ IN VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ InterfaceGuid,
+ Interface,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // close the protocol refered.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ This->DriverBindingHandle,
+ ConSplitterVirtualHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ DeviceGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID.
+
+ @param This Driver Binding 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
+ConSplitterConInDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
+
+ if (NumberOfChildren == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &TextInEx,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If Simple Text Input Ex protocol exists,
+ // remove device from Text Input Ex devices list.
+ //
+ Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Close Simple Text In protocol on controller handle and virtual handle.
+ //
+ Status = ConSplitterStop (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiConsoleInDeviceGuid,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &TextIn
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove device from Text Input devices list.
+ //
+ return ConSplitterTextInDeleteDevice (&mConIn, TextIn);
+}
+
+
+/**
+ Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing
+ Simple Pointer protocol.
+
+ @param This Driver Binding 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
+ConSplitterSimplePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
+
+ if (NumberOfChildren == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Close Simple Pointer protocol on controller handle and virtual handle.
+ //
+ Status = ConSplitterStop (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiSimplePointerProtocolGuid,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove this device from Simple Pointer device list.
+ //
+ return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer);
+}
+
+
+/**
+ Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing
+ Absolute Pointer protocol.
+
+ @param This Driver Binding 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
+ConSplitterAbsolutePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
+
+ if (NumberOfChildren == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Close Absolute Pointer protocol on controller handle and virtual handle.
+ //
+ Status = ConSplitterStop (
+ This,
+ ControllerHandle,
+ mConIn.VirtualHandle,
+ &gEfiAbsolutePointerProtocolGuid,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove this device from Absolute Pointer device list.
+ //
+ return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer);
+}
+
+
+/**
+ Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID.
+
+ @param This Driver Binding 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
+ConSplitterConOutDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ if (NumberOfChildren == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Close Absolute Pointer protocol on controller handle and virtual handle.
+ //
+ Status = ConSplitterStop (
+ This,
+ ControllerHandle,
+ mConOut.VirtualHandle,
+ &gEfiConsoleOutDeviceGuid,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove this device from Text Out device list.
+ //
+ return ConSplitterTextOutDeleteDevice (&mConOut, TextOut);
+}
+
+
+/**
+ Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID.
+
+ @param This Driver Binding 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
+ConSplitterStdErrDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ if (NumberOfChildren == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Close Standard Error Device on controller handle and virtual handle.
+ //
+ Status = ConSplitterStop (
+ This,
+ ControllerHandle,
+ mStdErr.VirtualHandle,
+ &gEfiStandardErrorDeviceGuid,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &TextOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Delete this console error out device's data structures.
+ //
+ return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);
+}
+
+
+/**
+ Take the passed in Buffer of size ElementSize and grow the buffer
+ by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes.
+ Copy the current data in Buffer to the new version of Buffer and
+ free the old version of buffer.
+
+ @param ElementSize Size of element in array.
+ @param Count Current number of elements in array.
+ @param Buffer Bigger version of passed in Buffer with all the
+ data.
+
+ @retval EFI_SUCCESS Buffer size has grown.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterGrowBuffer (
+ IN UINTN ElementSize,
+ IN OUT UINTN *Count,
+ IN OUT VOID **Buffer
+ )
+{
+ VOID *Ptr;
+
+ //
+ // grow the buffer to new buffer size,
+ // copy the old buffer's content to the new-size buffer,
+ // then free the old buffer.
+ //
+ Ptr = ReallocatePool (
+ ElementSize * (*Count),
+ ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT),
+ *Buffer
+ );
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *Count += CONSOLE_SPLITTER_ALLOC_UNIT;
+ *Buffer = Ptr;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add Text Input Device in Consplitter Text Input list.
+
+ @param Private Text In Splitter pointer.
+ @param TextIn Simple Text Input protocol pointer.
+
+ @retval EFI_SUCCESS Text Input Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextInAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer().
+ //
+ if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) {
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),
+ &Private->TextInListCount,
+ (VOID **) &Private->TextInList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // Add the new text-in device data structure into the Text In List.
+ //
+ Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn;
+ Private->CurrentNumberOfConsoles++;
+
+ //
+ // Extra CheckEvent added to reduce the double CheckEvent().
+ //
+ gBS->CheckEvent (TextIn->WaitForKey);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Remove Text Input Device from Consplitter Text Input list.
+
+ @param Private Text In Splitter pointer.
+ @param TextIn Simple Text protocol pointer.
+
+ @retval EFI_SUCCESS Simple Text Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Text Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextInDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn
+ )
+{
+ UINTN Index;
+ //
+ // Remove the specified text-in device data structure from the Text In List,
+ // and rearrange the remaining data structures in the Text In List.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ if (Private->TextInList[Index] == TextIn) {
+ for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) {
+ Private->TextInList[Index] = Private->TextInList[Index + 1];
+ }
+
+ Private->CurrentNumberOfConsoles--;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Add Text Input Ex Device in Consplitter Text Input Ex list.
+
+ @param Private Text In Splitter pointer.
+ @param TextInEx Simple Text Input Ex Input protocol pointer.
+
+ @retval EFI_SUCCESS Text Input Ex Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextInExAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify;
+ UINTN TextInExListCount;
+
+ //
+ // Enlarge the NotifyHandleList and the TextInExList
+ //
+ if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) {
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
+ TextInExListCount = Private->TextInExListCount;
+
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_HANDLE),
+ &TextInExListCount,
+ (VOID **) &CurrentNotify->NotifyHandleList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ TextInExListCount = Private->TextInExListCount;
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_KEY_DATA),
+ &TextInExListCount,
+ (VOID **) &Private->KeyQueue
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
+ &Private->TextInExListCount,
+ (VOID **) &Private->TextInExList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Register the key notify in the new text-in device
+ //
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
+ Status = TextInEx->RegisterKeyNotify (
+ TextInEx,
+ &CurrentNotify->KeyData,
+ CurrentNotify->KeyNotificationFn,
+ &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
+ );
+ if (EFI_ERROR (Status)) {
+ for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) {
+ CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
+ TextInEx->UnregisterKeyNotify (
+ TextInEx,
+ CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]
+ );
+ }
+ return Status;
+ }
+ }
+
+ //
+ // Add the new text-in device data structure into the Text Input Ex List.
+ //
+ Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;
+ Private->CurrentNumberOfExConsoles++;
+
+ //
+ // Sync current toggle state to this new console input device.
+ //
+ TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);
+
+ //
+ // Extra CheckEvent added to reduce the double CheckEvent().
+ //
+ gBS->CheckEvent (TextInEx->WaitForKeyEx);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove Text Ex Device from Consplitter Text Input Ex list.
+
+ @param Private Text In Splitter pointer.
+ @param TextInEx Simple Text Ex protocol pointer.
+
+ @retval EFI_SUCCESS Simple Text Input Ex Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Text Input Ex Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextInExDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx
+ )
+{
+ UINTN Index;
+ //
+ // Remove the specified text-in device data structure from the Text Input Ex List,
+ // and rearrange the remaining data structures in the Text In List.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ if (Private->TextInExList[Index] == TextInEx) {
+ for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) {
+ Private->TextInExList[Index] = Private->TextInExList[Index + 1];
+ }
+
+ Private->CurrentNumberOfExConsoles--;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Add Simple Pointer Device in Consplitter Simple Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param SimplePointer Simple Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Simple Pointer Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterSimplePointerAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
+ //
+ if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),
+ &Private->PointerListCount,
+ (VOID **) &Private->PointerList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // Add the new text-in device data structure into the Simple Pointer List.
+ //
+ Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;
+ Private->CurrentNumberOfPointers++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Remove Simple Pointer Device from Consplitter Simple Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param SimplePointer Simple Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Simple Pointer Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Pointer Device found.
+
+**/
+EFI_STATUS
+ConSplitterSimplePointerDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
+ )
+{
+ UINTN Index;
+ //
+ // Remove the specified text-in device data structure from the Simple Pointer List,
+ // and rearrange the remaining data structures in the Text In List.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
+ if (Private->PointerList[Index] == SimplePointer) {
+ for (; Index < Private->CurrentNumberOfPointers - 1; Index++) {
+ Private->PointerList[Index] = Private->PointerList[Index + 1];
+ }
+
+ Private->CurrentNumberOfPointers--;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Add Absolute Pointer Device in Consplitter Absolute Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param AbsolutePointer Absolute Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Absolute Pointer Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterAbsolutePointerAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().
+ //
+ if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) {
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),
+ &Private->AbsolutePointerListCount,
+ (VOID **) &Private->AbsolutePointerList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // Add the new text-in device data structure into the Absolute Pointer List.
+ //
+ Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer;
+ Private->CurrentNumberOfAbsolutePointers++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Remove Absolute Pointer Device from Consplitter Absolute Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param AbsolutePointer Absolute Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Absolute Pointer Device removed successfully.
+ @retval EFI_NOT_FOUND No Absolute Pointer Device found.
+
+**/
+EFI_STATUS
+ConSplitterAbsolutePointerDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer
+ )
+{
+ UINTN Index;
+ //
+ // Remove the specified text-in device data structure from the Absolute Pointer List,
+ // and rearrange the remaining data structures from the Absolute Pointer List.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
+ if (Private->AbsolutePointerList[Index] == AbsolutePointer) {
+ for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) {
+ Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1];
+ }
+
+ Private->CurrentNumberOfAbsolutePointers--;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Reallocate Text Out mode map.
+
+ Allocate new buffer and copy original buffer into the new buffer.
+
+ @param Private Consplitter Text Out pointer.
+
+ @retval EFI_SUCCESS Buffer size has grown
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterGrowMapTable (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ UINTN Size;
+ UINTN NewSize;
+ UINTN TotalSize;
+ INT32 *TextOutModeMap;
+ INT32 *OldTextOutModeMap;
+ INT32 *SrcAddress;
+ INT32 Index;
+ UINTN OldStepSize;
+ UINTN NewStepSize;
+
+ NewSize = Private->TextOutListCount * sizeof (INT32);
+ OldTextOutModeMap = Private->TextOutModeMap;
+ TotalSize = NewSize * (Private->TextOutQueryDataCount);
+
+ //
+ // Allocate new buffer for Text Out List.
+ //
+ TextOutModeMap = AllocatePool (TotalSize);
+ if (TextOutModeMap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (TextOutModeMap, TotalSize, 0xFF);
+ Private->TextOutModeMap = TextOutModeMap;
+
+ //
+ // If TextOutList has been enlarged, need to realloc the mode map table
+ // The mode map table is regarded as a two dimension array.
+ //
+ // Old New
+ // 0 ---------> TextOutListCount ----> TextOutListCount
+ // | -------------------------------------------
+ // | | | |
+ // | | | |
+ // | | | |
+ // | | | |
+ // | | | |
+ // \/ | | |
+ // -------------------------------------------
+ // QueryDataCount
+ //
+ if (OldTextOutModeMap != NULL) {
+
+ Size = Private->CurrentNumberOfConsoles * sizeof (INT32);
+ Index = 0;
+ SrcAddress = OldTextOutModeMap;
+ NewStepSize = NewSize / sizeof(INT32);
+ // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap
+ // is not NULL, it indicates that the original TextOutModeMap is not enough
+ // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.
+ //
+ OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT;
+
+ //
+ // Copy the old data to the new one
+ //
+ while (Index < Private->TextOutMode.MaxMode) {
+ CopyMem (TextOutModeMap, SrcAddress, Size);
+ //
+ // Go to next row of new TextOutModeMap.
+ //
+ TextOutModeMap += NewStepSize;
+ //
+ // Go to next row of old TextOutModeMap.
+ //
+ SrcAddress += OldStepSize;
+ Index++;
+ }
+ //
+ // Free the old buffer
+ //
+ FreePool (OldTextOutModeMap);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add new device's output mode to console splitter's mode list.
+
+ @param Private Text Out Splitter pointer
+ @param TextOut Simple Text Output protocol pointer.
+
+ @retval EFI_SUCCESS Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterAddOutputMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut
+ )
+{
+ EFI_STATUS Status;
+ INT32 MaxMode;
+ INT32 Mode;
+ UINTN Index;
+
+ MaxMode = TextOut->Mode->MaxMode;
+ Private->TextOutMode.MaxMode = MaxMode;
+
+ //
+ // Grow the buffer if query data buffer is not large enough to
+ // hold all the mode supported by the first console.
+ //
+ while (MaxMode > (INT32) Private->TextOutQueryDataCount) {
+ Status = ConSplitterGrowBuffer (
+ sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
+ &Private->TextOutQueryDataCount,
+ (VOID **) &Private->TextOutQueryData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // Allocate buffer for the output mode map
+ //
+ Status = ConSplitterGrowMapTable (Private);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // As the first textout device, directly add the mode in to QueryData
+ // and at the same time record the mapping between QueryData and TextOut.
+ //
+ Mode = 0;
+ Index = 0;
+ while (Mode < MaxMode) {
+ Status = TextOut->QueryMode (
+ TextOut,
+ Mode,
+ &Private->TextOutQueryData[Mode].Columns,
+ &Private->TextOutQueryData[Mode].Rows
+ );
+ //
+ // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
+ // is clear to 0x0.
+ //
+ if ((EFI_ERROR(Status)) && (Mode == 1)) {
+ Private->TextOutQueryData[Mode].Columns = 0;
+ Private->TextOutQueryData[Mode].Rows = 0;
+ }
+ Private->TextOutModeMap[Index] = Mode;
+ Mode++;
+ Index += Private->TextOutListCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reconstruct TextOutModeMap to get intersection of modes.
+
+ This routine reconstruct TextOutModeMap to get the intersection
+ of modes for all console out devices. Because EFI/UEFI spec require
+ mode 0 is 80x25, mode 1 is 80x50, this routine will not check the
+ intersection for mode 0 and mode 1.
+
+ @param TextOutModeMap Current text out mode map, begin with the mode 80x25
+ @param NewlyAddedMap New text out mode map, begin with the mode 80x25
+ @param MapStepSize Mode step size for one console device
+ @param NewMapStepSize New Mode step size for one console device
+ @param MaxMode IN: Current max text mode, OUT: Updated max text mode.
+ @param CurrentMode IN: Current text mode, OUT: Updated current text mode.
+
+**/
+VOID
+ConSplitterGetIntersection (
+ IN INT32 *TextOutModeMap,
+ IN INT32 *NewlyAddedMap,
+ IN UINTN MapStepSize,
+ IN UINTN NewMapStepSize,
+ IN OUT INT32 *MaxMode,
+ IN OUT INT32 *CurrentMode
+ )
+{
+ INT32 Index;
+ INT32 *CurrentMapEntry;
+ INT32 *NextMapEntry;
+ INT32 *NewMapEntry;
+ INT32 CurrentMaxMode;
+ INT32 Mode;
+
+ //
+ // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved
+ // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection
+ // for mode 0 and mode 1, mode number starts from 2.
+ //
+ Index = 2;
+ CurrentMapEntry = &TextOutModeMap[MapStepSize * 2];
+ NextMapEntry = CurrentMapEntry;
+ NewMapEntry = &NewlyAddedMap[NewMapStepSize * 2];
+
+ CurrentMaxMode = *MaxMode;
+ Mode = *CurrentMode;
+
+ while (Index < CurrentMaxMode) {
+ if (*NewMapEntry == -1) {
+ //
+ // This mode is not supported any more. Remove it. Special care
+ // must be taken as this remove will also affect current mode;
+ //
+ if (Index == *CurrentMode) {
+ Mode = -1;
+ } else if (Index < *CurrentMode) {
+ Mode--;
+ }
+ (*MaxMode)--;
+ } else {
+ if (CurrentMapEntry != NextMapEntry) {
+ CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32));
+ }
+
+ NextMapEntry += MapStepSize;
+ }
+
+ CurrentMapEntry += MapStepSize;
+ NewMapEntry += NewMapStepSize;
+ Index++;
+ }
+
+ *CurrentMode = Mode;
+
+ return ;
+}
+
+/**
+ Sync the device's output mode to console splitter's mode list.
+
+ @param Private Text Out Splitter pointer.
+ @param TextOut Simple Text Output protocol pointer.
+
+**/
+VOID
+ConSplitterSyncOutputMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut
+ )
+{
+ INT32 CurrentMaxMode;
+ INT32 Mode;
+ INT32 Index;
+ INT32 *TextOutModeMap;
+ INT32 *MapTable;
+ INT32 QueryMode;
+ TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData;
+ UINTN Rows;
+ UINTN Columns;
+ UINTN StepSize;
+ EFI_STATUS Status;
+
+ //
+ // Must make sure that current mode won't change even if mode number changes
+ //
+ CurrentMaxMode = Private->TextOutMode.MaxMode;
+ TextOutModeMap = Private->TextOutModeMap;
+ StepSize = Private->TextOutListCount;
+ TextOutQueryData = Private->TextOutQueryData;
+
+ //
+ // Query all the mode that the newly added TextOut supports
+ //
+ Mode = 0;
+ MapTable = TextOutModeMap + Private->CurrentNumberOfConsoles;
+ while (Mode < TextOut->Mode->MaxMode) {
+ Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);
+
+ if (EFI_ERROR(Status)) {
+ if (Mode == 1) {
+ //
+ // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData
+ // is clear to 0x0.
+ //
+ MapTable[StepSize] = Mode;
+ TextOutQueryData[Mode].Columns = 0;
+ TextOutQueryData[Mode].Rows = 0;
+ }
+ Mode++;
+ continue;
+ }
+ //
+ // Search the intersection map and QueryData database to see if they intersects
+ //
+ Index = 0;
+ while (Index < CurrentMaxMode) {
+ QueryMode = *(TextOutModeMap + Index * StepSize);
+ if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) {
+ MapTable[Index * StepSize] = Mode;
+ break;
+ }
+ Index++;
+ }
+ Mode++;
+ }
+ //
+ // Now search the TextOutModeMap table to find the intersection of supported
+ // mode between ConSplitter and the newly added device.
+ //
+ ConSplitterGetIntersection (
+ TextOutModeMap,
+ MapTable,
+ StepSize,
+ StepSize,
+ &Private->TextOutMode.MaxMode,
+ &Private->TextOutMode.Mode
+ );
+
+ return ;
+}
+
+
+/**
+ Sync output device between ConOut and StdErr output.
+
+ @retval EFI_SUCCESS Sync implemented successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterGetIntersectionBetweenConOutAndStrErr (
+ VOID
+ )
+{
+ UINTN ConOutNumOfConsoles;
+ UINTN StdErrNumOfConsoles;
+ TEXT_OUT_AND_GOP_DATA *ConOutTextOutList;
+ TEXT_OUT_AND_GOP_DATA *StdErrTextOutList;
+ UINTN Indexi;
+ UINTN Indexj;
+ UINTN ConOutRows;
+ UINTN ConOutColumns;
+ UINTN StdErrRows;
+ UINTN StdErrColumns;
+ INT32 ConOutMaxMode;
+ INT32 StdErrMaxMode;
+ INT32 ConOutMode;
+ INT32 StdErrMode;
+ INT32 Mode;
+ INT32 Index;
+ INT32 *ConOutModeMap;
+ INT32 *StdErrModeMap;
+ INT32 *ConOutMapTable;
+ INT32 *StdErrMapTable;
+ TEXT_OUT_SPLITTER_QUERY_DATA *ConOutQueryData;
+ TEXT_OUT_SPLITTER_QUERY_DATA *StdErrQueryData;
+ UINTN ConOutStepSize;
+ UINTN StdErrStepSize;
+ BOOLEAN FoundTheSameTextOut;
+ UINTN ConOutMapTableSize;
+ UINTN StdErrMapTableSize;
+
+ ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles;
+ StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles;
+ ConOutTextOutList = mConOut.TextOutList;
+ StdErrTextOutList = mStdErr.TextOutList;
+
+ Indexi = 0;
+ FoundTheSameTextOut = FALSE;
+ while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) {
+ Indexj = 0;
+ while (Indexj < StdErrNumOfConsoles) {
+ if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) {
+ FoundTheSameTextOut = TRUE;
+ break;
+ }
+
+ Indexj++;
+ StdErrTextOutList++;
+ }
+
+ Indexi++;
+ ConOutTextOutList++;
+ }
+
+ if (!FoundTheSameTextOut) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Must make sure that current mode won't change even if mode number changes
+ //
+ ConOutMaxMode = mConOut.TextOutMode.MaxMode;
+ ConOutModeMap = mConOut.TextOutModeMap;
+ ConOutStepSize = mConOut.TextOutListCount;
+ ConOutQueryData = mConOut.TextOutQueryData;
+
+ StdErrMaxMode = mStdErr.TextOutMode.MaxMode;
+ StdErrModeMap = mStdErr.TextOutModeMap;
+ StdErrStepSize = mStdErr.TextOutListCount;
+ StdErrQueryData = mStdErr.TextOutQueryData;
+
+ //
+ // Allocate the map table and set the map table's index to -1.
+ //
+ ConOutMapTableSize = ConOutMaxMode * sizeof (INT32);
+ ConOutMapTable = AllocateZeroPool (ConOutMapTableSize);
+ if (ConOutMapTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);
+
+ StdErrMapTableSize = StdErrMaxMode * sizeof (INT32);
+ StdErrMapTable = AllocateZeroPool (StdErrMapTableSize);
+ if (StdErrMapTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF);
+
+ //
+ // Find the intersection of the two set of modes. If they actually intersect, the
+ // corresponding entry in the map table is set to 1.
+ //
+ Mode = 0;
+ while (Mode < ConOutMaxMode) {
+ //
+ // Search the intersection map and QueryData database to see if they intersect
+ //
+ Index = 0;
+ ConOutMode = *(ConOutModeMap + Mode * ConOutStepSize);
+ ConOutRows = ConOutQueryData[ConOutMode].Rows;
+ ConOutColumns = ConOutQueryData[ConOutMode].Columns;
+ while (Index < StdErrMaxMode) {
+ StdErrMode = *(StdErrModeMap + Index * StdErrStepSize);
+ StdErrRows = StdErrQueryData[StdErrMode].Rows;
+ StdErrColumns = StdErrQueryData[StdErrMode].Columns;
+ if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) {
+ ConOutMapTable[Mode] = 1;
+ StdErrMapTable[Index] = 1;
+ break;
+ }
+
+ Index++;
+ }
+
+ Mode++;
+ }
+ //
+ // Now search the TextOutModeMap table to find the intersection of supported
+ // mode between ConSplitter and the newly added device.
+ //
+ ConSplitterGetIntersection (
+ ConOutModeMap,
+ ConOutMapTable,
+ mConOut.TextOutListCount,
+ 1,
+ &(mConOut.TextOutMode.MaxMode),
+ &(mConOut.TextOutMode.Mode)
+ );
+
+ if (mConOut.TextOutMode.Mode < 0) {
+ mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);
+ }
+
+ ConSplitterGetIntersection (
+ StdErrModeMap,
+ StdErrMapTable,
+ mStdErr.TextOutListCount,
+ 1,
+ &(mStdErr.TextOutMode.MaxMode),
+ &(mStdErr.TextOutMode.Mode)
+ );
+
+ if (mStdErr.TextOutMode.Mode < 0) {
+ mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);
+ }
+
+ FreePool (ConOutMapTable);
+ FreePool (StdErrMapTable);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add Grahpics Output modes into Consplitter Text Out list.
+
+ @param Private Text Out Splitter pointer.
+ @param GraphicsOutput Graphics Output protocol pointer.
+ @param UgaDraw UGA Draw protocol pointer.
+
+ @retval EFI_SUCCESS Output mode added successfully.
+ @retval other Failed to add output mode.
+
+**/
+EFI_STATUS
+ConSplitterAddGraphicsOutputMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN CurrentIndex;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *CurrentGraphicsOutputMode;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeBuffer;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *MatchedMode;
+ UINTN NumberIndex;
+ BOOLEAN Match;
+ BOOLEAN AlreadyExist;
+ UINT32 UgaHorizontalResolution;
+ UINT32 UgaVerticalResolution;
+ UINT32 UgaColorDepth;
+ UINT32 UgaRefreshRate;
+
+ ASSERT (GraphicsOutput != NULL || UgaDraw != NULL);
+
+ CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;
+
+ Index = 0;
+ CurrentIndex = 0;
+ Status = EFI_SUCCESS;
+
+ if (Private->CurrentNumberOfUgaDraw != 0) {
+ //
+ // If any UGA device has already been added, then there is no need to
+ // calculate intersection of display mode of different GOP/UGA device,
+ // since only one display mode will be exported (i.e. user-defined mode)
+ //
+ goto Done;
+ }
+
+ if (GraphicsOutput != NULL) {
+ if (Private->CurrentNumberOfGraphicsOutput == 0) {
+ //
+ // This is the first Graphics Output device added
+ //
+ CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;
+ CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode;
+ CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);
+ CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo;
+ CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;
+ CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;
+
+ //
+ // Allocate resource for the private mode buffer
+ //
+ ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode);
+ if (ModeBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FreePool (Private->GraphicsOutputModeBuffer);
+ Private->GraphicsOutputModeBuffer = ModeBuffer;
+
+ //
+ // Store all supported display modes to the private mode buffer
+ //
+ Mode = ModeBuffer;
+ for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {
+ //
+ // The Info buffer would be allocated by callee
+ //
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ CopyMem (Mode, Info, SizeOfInfo);
+ Mode++;
+ FreePool (Info);
+ }
+ } else {
+ //
+ // Check intersection of display mode
+ //
+ ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode);
+ if (ModeBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MatchedMode = ModeBuffer;
+ Mode = &Private->GraphicsOutputModeBuffer[0];
+ for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
+ Match = FALSE;
+
+ for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {
+ //
+ // The Info buffer would be allocated by callee
+ //
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
+ (Info->VerticalResolution == Mode->VerticalResolution)) {
+ //
+ // If GOP device supports one mode in current mode buffer,
+ // it will be added into matched mode buffer
+ //
+ Match = TRUE;
+ FreePool (Info);
+ break;
+ }
+ FreePool (Info);
+ }
+
+ if (Match) {
+ AlreadyExist = FALSE;
+
+ //
+ // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin.
+ //
+ for (Info = ModeBuffer; Info < MatchedMode; Info++) {
+ if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&
+ (Info->VerticalResolution == Mode->VerticalResolution)) {
+ AlreadyExist = TRUE;
+ break;
+ }
+ }
+
+ if (!AlreadyExist) {
+ CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+
+ //
+ // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly
+ //
+ MatchedMode->Version = 0;
+ MatchedMode->PixelFormat = PixelBltOnly;
+ ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
+
+ MatchedMode++;
+ }
+ }
+
+ Mode++;
+ }
+
+ //
+ // Drop the old mode buffer, assign it to a new one
+ //
+ FreePool (Private->GraphicsOutputModeBuffer);
+ Private->GraphicsOutputModeBuffer = ModeBuffer;
+
+ //
+ // Physical frame buffer is no longer available when there are more than one physical GOP devices
+ //
+ CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;
+ ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK));
+ CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+ CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
+ CurrentGraphicsOutputMode->FrameBufferSize = 0;
+ }
+
+ //
+ // Graphics console driver can ensure the same mode for all GOP devices
+ //
+ for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
+ Mode = &Private->GraphicsOutputModeBuffer[Index];
+ if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) &&
+ (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution)) {
+ CurrentIndex = Index;
+ break;
+ }
+ }
+ if (Index >= CurrentGraphicsOutputMode->MaxMode) {
+ //
+ // if user defined mode is not found, set to default mode 800x600
+ //
+ for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {
+ Mode = &Private->GraphicsOutputModeBuffer[Index];
+ if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {
+ CurrentIndex = Index;
+ break;
+ }
+ }
+ }
+ } else if (UgaDraw != NULL) {
+ //
+ // Graphics console driver can ensure the same mode for all GOP devices
+ // so we can get the current mode from this video device
+ //
+ UgaDraw->GetMode (
+ UgaDraw,
+ &UgaHorizontalResolution,
+ &UgaVerticalResolution,
+ &UgaColorDepth,
+ &UgaRefreshRate
+ );
+
+ CurrentGraphicsOutputMode->MaxMode = 1;
+ Info = CurrentGraphicsOutputMode->Info;
+ Info->Version = 0;
+ Info->HorizontalResolution = UgaHorizontalResolution;
+ Info->VerticalResolution = UgaVerticalResolution;
+ Info->PixelFormat = PixelBltOnly;
+ Info->PixelsPerScanLine = UgaHorizontalResolution;
+ CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+ CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
+ CurrentGraphicsOutputMode->FrameBufferSize = 0;
+
+ //
+ // Update the private mode buffer
+ //
+ CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+
+ //
+ // Only mode 0 is available to be set
+ //
+ CurrentIndex = 0;
+ }
+
+Done:
+
+ if (GraphicsOutput != NULL) {
+ Private->CurrentNumberOfGraphicsOutput++;
+ }
+ if (UgaDraw != NULL) {
+ Private->CurrentNumberOfUgaDraw++;
+ }
+
+ //
+ // Force GraphicsOutput mode to be set,
+ //
+
+ Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];
+ if ((GraphicsOutput != NULL) &&
+ (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&
+ (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution)) {
+ CurrentGraphicsOutputMode->Mode = (UINT32) CurrentIndex;
+ if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) ||
+ (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution)) {
+ //
+ // If all existing video device has been set to common mode, only set new GOP device to
+ // the common mode
+ //
+ for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {
+ FreePool (Info);
+ break;
+ }
+ FreePool (Info);
+ }
+ Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
+ }
+ } else {
+ //
+ // Current mode number may need update now, so set it to an invalid mode number
+ //
+ CurrentGraphicsOutputMode->Mode = 0xffff;
+ //
+ // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode.
+ //
+ Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) CurrentIndex);
+ if (EFI_ERROR(Status)) {
+ //
+ // If user defined mode is not valid for display device, set to the default mode 800x600.
+ //
+ (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800;
+ (Private->GraphicsOutputModeBuffer[0]).VerticalResolution = 600;
+ Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the current console out mode.
+
+ This routine will get the current console mode information (column, row)
+ from ConsoleOutMode variable and set it; if the variable does not exist,
+ set to user defined console mode.
+
+ @param Private Consplitter Text Out pointer.
+
+**/
+VOID
+ConsplitterSetConsoleOutMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ UINTN Col;
+ UINTN Row;
+ UINTN Mode;
+ UINTN PreferMode;
+ UINTN BaseMode;
+ UINTN MaxMode;
+ EFI_STATUS Status;
+ CONSOLE_OUT_MODE ModeInfo;
+ CONSOLE_OUT_MODE MaxModeInfo;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ PreferMode = 0xFF;
+ BaseMode = 0xFF;
+ TextOut = &Private->TextOut;
+ MaxMode = (UINTN) (TextOut->Mode->MaxMode);
+
+ MaxModeInfo.Column = 0;
+ MaxModeInfo.Row = 0;
+ ModeInfo.Column = PcdGet32 (PcdConOutColumn);
+ ModeInfo.Row = PcdGet32 (PcdConOutRow);
+
+ //
+ // To find the prefer mode and basic mode from Text Out mode list
+ //
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row);
+ if (!EFI_ERROR(Status)) {
+ if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) {
+ //
+ // Use user defined column and row
+ //
+ if (Col == ModeInfo.Column && Row == ModeInfo.Row) {
+ PreferMode = Mode;
+ }
+ } else {
+ //
+ // If user sets PcdConOutColumn or PcdConOutRow to 0,
+ // find and set the highest text mode.
+ //
+ if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) {
+ MaxModeInfo.Column = Col;
+ MaxModeInfo.Row = Row;
+ PreferMode = Mode;
+ }
+ }
+ if (Col == 80 && Row == 25) {
+ BaseMode = Mode;
+ }
+ }
+ }
+
+ //
+ // Set prefer mode to Text Out devices.
+ //
+ Status = TextOut->SetMode (TextOut, PreferMode);
+ if (EFI_ERROR(Status)) {
+ //
+ // if current mode setting is failed, default 80x25 mode will be set.
+ //
+ Status = TextOut->SetMode (TextOut, BaseMode);
+ ASSERT(!EFI_ERROR(Status));
+
+ Status = PcdSet32S (PcdConOutColumn, 80);
+ ASSERT(!EFI_ERROR(Status));
+ Status = PcdSet32S (PcdConOutRow, 25);
+ ASSERT(!EFI_ERROR(Status));
+ }
+
+ return ;
+}
+
+
+/**
+ Add Text Output Device in Consplitter Text Output list.
+
+ @param Private Text Out Splitter pointer.
+ @param TextOut Simple Text Output protocol pointer.
+ @param GraphicsOutput Graphics Output protocol pointer.
+ @param UgaDraw UGA Draw protocol pointer.
+
+ @retval EFI_SUCCESS Text Output Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextOutAddDevice (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut,
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurrentNumOfConsoles;
+ INT32 MaxMode;
+ UINT32 UgaHorizontalResolution;
+ UINT32 UgaVerticalResolution;
+ UINT32 UgaColorDepth;
+ UINT32 UgaRefreshRate;
+ TEXT_OUT_AND_GOP_DATA *TextAndGop;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_STATUS DeviceStatus;
+
+ Status = EFI_SUCCESS;
+ CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
+ Private->AddingConOutDevice = TRUE;
+
+ //
+ // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().
+ //
+ while (CurrentNumOfConsoles >= Private->TextOutListCount) {
+ Status = ConSplitterGrowBuffer (
+ sizeof (TEXT_OUT_AND_GOP_DATA),
+ &Private->TextOutListCount,
+ (VOID **) &Private->TextOutList
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Also need to reallocate the TextOutModeMap table
+ //
+ Status = ConSplitterGrowMapTable (Private);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ TextAndGop = &Private->TextOutList[CurrentNumOfConsoles];
+
+ TextAndGop->TextOut = TextOut;
+ TextAndGop->GraphicsOutput = GraphicsOutput;
+ TextAndGop->UgaDraw = UgaDraw;
+
+ if (CurrentNumOfConsoles == 0) {
+ //
+ // Add the first device's output mode to console splitter's mode list
+ //
+ Status = ConSplitterAddOutputMode (Private, TextOut);
+ } else {
+ ConSplitterSyncOutputMode (Private, TextOut);
+ }
+
+ Private->CurrentNumberOfConsoles++;
+
+ //
+ // Scan both TextOutList, for the intersection TextOut device
+ // maybe both ConOut and StdErr incorporate the same Text Out
+ // device in them, thus the output of both should be synced.
+ //
+ ConSplitterGetIntersectionBetweenConOutAndStrErr ();
+
+ MaxMode = Private->TextOutMode.MaxMode;
+ ASSERT (MaxMode >= 1);
+
+ DeviceStatus = EFI_DEVICE_ERROR;
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // This device display mode will be added into Graphics Ouput modes.
+ //
+ if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {
+ DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);
+ }
+
+ if (FeaturePcdGet (PcdConOutUgaSupport)) {
+ //
+ // If UGA is produced by Consplitter
+ //
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+
+ UgaHorizontalResolution = Info->HorizontalResolution;
+ UgaVerticalResolution = Info->VerticalResolution;
+
+ FreePool (Info);
+
+ } else if (UgaDraw != NULL) {
+ Status = UgaDraw->GetMode (
+ UgaDraw,
+ &UgaHorizontalResolution,
+ &UgaVerticalResolution,
+ &UgaColorDepth,
+ &UgaRefreshRate
+ );
+ if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) {
+ //
+ // if GetMode is successfully and UGA device hasn't been set, set it
+ //
+ Status = ConSplitterUgaDrawSetMode (
+ &Private->UgaDraw,
+ UgaHorizontalResolution,
+ UgaVerticalResolution,
+ UgaColorDepth,
+ UgaRefreshRate
+ );
+ }
+ //
+ // If GetMode/SetMode is failed, set to 800x600 mode
+ //
+ if(EFI_ERROR (Status)) {
+ Status = ConSplitterUgaDrawSetMode (
+ &Private->UgaDraw,
+ 800,
+ 600,
+ 32,
+ 60
+ );
+ }
+ }
+ }
+
+ if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&
+ ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) {
+ if (!FeaturePcdGet (PcdConOutGopSupport)) {
+ //
+ // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed
+ // on the virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &mConOut.UgaDraw,
+ NULL
+ );
+ } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
+ //
+ // If UGA Draw protocol not supported, Graphics Output Protocol is installed
+ // on virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &mConOut.GraphicsOutput,
+ NULL
+ );
+ } else {
+ //
+ // Boot Graphics Output protocol and UGA Draw protocol are supported,
+ // both they will be installed on virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &mConOut.GraphicsOutput,
+ &gEfiUgaDrawProtocolGuid,
+ &mConOut.UgaDraw,
+ NULL
+ );
+ }
+ }
+
+ //
+ // After adding new console device, all existing console devices should be
+ // synced to the current shared mode.
+ //
+ ConsplitterSetConsoleOutMode (Private);
+
+ Private->AddingConOutDevice = FALSE;
+
+ return Status;
+}
+
+
+/**
+ Remove Text Out Device in Consplitter Text Out list.
+
+ @param Private Text Out Splitter pointer.
+ @param TextOut Simple Text Output Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Text Out Device removed successfully.
+ @retval EFI_NOT_FOUND No Text Out Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextOutDeleteDevice (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut
+ )
+{
+ INT32 Index;
+ UINTN CurrentNumOfConsoles;
+ TEXT_OUT_AND_GOP_DATA *TextOutList;
+ EFI_STATUS Status;
+
+ //
+ // Remove the specified text-out device data structure from the Text out List,
+ // and rearrange the remaining data structures in the Text out List.
+ //
+ CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
+ Index = (INT32) CurrentNumOfConsoles - 1;
+ TextOutList = Private->TextOutList;
+ while (Index >= 0) {
+ if (TextOutList->TextOut == TextOut) {
+ if (TextOutList->UgaDraw != NULL) {
+ Private->CurrentNumberOfUgaDraw--;
+ }
+ if (TextOutList->GraphicsOutput != NULL) {
+ Private->CurrentNumberOfGraphicsOutput--;
+ }
+ CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index);
+ CurrentNumOfConsoles--;
+ break;
+ }
+
+ Index--;
+ TextOutList++;
+ }
+ //
+ // The specified TextOut is not managed by the ConSplitter driver
+ //
+ if (Index < 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) {
+ //
+ // If there is not any physical GOP and UGA device in system,
+ // Consplitter GOP or UGA protocol will be uninstalled
+ //
+ if (!FeaturePcdGet (PcdConOutGopSupport)) {
+ Status = gBS->UninstallProtocolInterface (
+ Private->VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw
+ );
+ } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
+ Status = gBS->UninstallProtocolInterface (
+ Private->VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ }
+ }
+
+ if (CurrentNumOfConsoles == 0) {
+ //
+ // If the number of consoles is zero, reset all parameters
+ //
+ Private->CurrentNumberOfConsoles = 0;
+ Private->TextOutMode.MaxMode = 1;
+ Private->TextOutQueryData[0].Columns = 80;
+ Private->TextOutQueryData[0].Rows = 25;
+ TextOutSetMode (Private, 0);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Max Mode is realy an intersection of the QueryMode command to all
+ // devices. So we must copy the QueryMode of the first device to
+ // QueryData.
+ //
+ ZeroMem (
+ Private->TextOutQueryData,
+ Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA)
+ );
+
+ FreePool (Private->TextOutModeMap);
+ Private->TextOutModeMap = NULL;
+ TextOutList = Private->TextOutList;
+
+ //
+ // Add the first TextOut to the QueryData array and ModeMap table
+ //
+ Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut);
+
+ //
+ // Now add one by one
+ //
+ Index = 1;
+ Private->CurrentNumberOfConsoles = 1;
+ TextOutList++;
+ while ((UINTN) Index < CurrentNumOfConsoles) {
+ ConSplitterSyncOutputMode (Private, TextOutList->TextOut);
+ Index++;
+ Private->CurrentNumberOfConsoles++;
+ TextOutList++;
+ }
+
+ ConSplitterGetIntersectionBetweenConOutAndStrErr ();
+
+ return Status;
+}
+
+
+/**
+ 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
+ConSplitterTextInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ Private->KeyEventSignalState = FALSE;
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextInList[Index]->Reset (
+ Private->TextInList[Index],
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ if (!EFI_ERROR (ReturnStatus)) {
+ ToggleStateSyncReInitialization (Private);
+ //
+ // Empty the key queue.
+ //
+ Private->CurrentNumberOfKeys = 0;
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Dequeue the saved key from internal key queue.
+
+ @param Private 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_NOT_FOUND Queue is empty.
+ @retval EFI_SUCCESS First key is dequeued and returned.
+**/
+EFI_STATUS
+ConSplitterTextInExDequeueKey (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ if (Private->CurrentNumberOfKeys == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Return the first saved key.
+ //
+ CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));
+ Private->CurrentNumberOfKeys--;
+ CopyMem (
+ &Private->KeyQueue[0],
+ &Private->KeyQueue[1],
+ Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)
+ );
+ 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 Private Protocol instance pointer.
+ @param Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInPrivateReadKeyStroke (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_KEY_DATA KeyData;
+
+ //
+ // Return the first saved non-NULL key.
+ //
+ while (TRUE) {
+ Status = ConSplitterTextInExDequeueKey (Private, &KeyData);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+ return Status;
+ }
+ }
+
+ Key->UnicodeChar = 0;
+ Key->ScanCode = SCAN_NULL;
+
+ //
+ // if no physical console input device exists, return EFI_NOT_READY;
+ // if any physical console input device has key input,
+ // return the key and EFI_SUCCESS.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {
+ Status = Private->TextInList[Index]->ReadKeyStroke (
+ Private->TextInList[Index],
+ &KeyData.Key
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If it is not partial keystorke, return the key. Otherwise, continue
+ // to read key from THIS physical console input device.
+ //
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+ return Status;
+ }
+ } else {
+ //
+ // Continue to read key from NEXT physical console input device.
+ //
+ Index++;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+
+
+/**
+ 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 Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ Private->KeyEventSignalState = FALSE;
+
+ //
+ // Signal ConnectConIn event on first call in Lazy ConIn mode
+ //
+ if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
+ gBS->SignalEvent (Private->ConnectConInEvent);
+ mConInIsConnect = TRUE;
+ }
+
+ return ConSplitterTextInPrivateReadKeyStroke (Private, Key);
+}
+
+
+/**
+ This event aggregates all the events of the ConIn devices in the spliter.
+
+ If any events of physical ConIn devices are signaled, signal the ConIn
+ spliter event. This will cause the calling code to call
+ ConSplitterTextInReadKeyStroke ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterTextInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
+
+ if (Private->KeyEventSignalState) {
+ //
+ // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
+ //
+ gBS->SignalEvent (Event);
+ return ;
+ }
+
+ //
+ // If any physical console input device has key input, signal the event.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);
+ if (!EFI_ERROR (Status)) {
+ gBS->SignalEvent (Event);
+ Private->KeyEventSignalState = TRUE;
+ }
+ }
+}
+
+
+
+/**
+ Test if the key has been registered on input device.
+
+ @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;
+
+}
+
+
+/**
+ 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
+ConSplitterTextInResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ Private->KeyEventSignalState = FALSE;
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Status = Private->TextInExList[Index]->Reset (
+ Private->TextInExList[Index],
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ if (!EFI_ERROR (ReturnStatus)) {
+ ToggleStateSyncReInitialization (Private);
+ //
+ // Empty the key queue.
+ //
+ Private->CurrentNumberOfKeys = 0;
+ }
+
+ return ReturnStatus;
+
+}
+
+
+/**
+ 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
+ConSplitterTextInReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_KEY_STATE KeyState;
+ EFI_KEY_DATA CurrentKeyData;
+
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ Private->KeyEventSignalState = FALSE;
+
+ //
+ // Signal ConnectConIn event on first call in Lazy ConIn mode
+ //
+ if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
+ gBS->SignalEvent (Private->ConnectConInEvent);
+ mConInIsConnect = TRUE;
+ }
+
+ //
+ // Return the first saved key.
+ //
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (Private->CurrentNumberOfKeys == 0);
+
+ ZeroMem (&KeyState, sizeof (KeyState));
+
+ //
+ // Iterate through all physical consoles to get key state.
+ // Some physical consoles may return valid key.
+ // Queue the valid keys.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));
+ Status = Private->TextInExList[Index]->ReadKeyStrokeEx (
+ Private->TextInExList[Index],
+ &CurrentKeyData
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
+ continue;
+ }
+
+ //
+ // Consolidate the key state from all physical consoles.
+ //
+ if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {
+ KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;
+ }
+ if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {
+ KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // If virtual KeyState has been required to be exposed, or it is not
+ // partial keystorke, queue the key.
+ // It's possible that user presses at multiple keyboards at the same moment,
+ // Private->KeyQueue[] are the storage to save all the keys.
+ //
+ if ((Private->VirtualKeyStateExported) ||
+ (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||
+ (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (
+ &Private->KeyQueue[Private->CurrentNumberOfKeys],
+ &CurrentKeyData,
+ sizeof (EFI_KEY_DATA)
+ );
+ Private->CurrentNumberOfKeys++;
+ }
+ }
+ }
+
+ //
+ // Consolidate the key state for all keys in Private->KeyQueue[]
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {
+ CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));
+ }
+
+ //
+ // Return the first saved key.
+ //
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Always return the key state even there is no key pressed.
+ //
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));
+ return EFI_NOT_READY;
+}
+
+
+/**
+ 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
+ConSplitterTextInSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_KEY_TOGGLE_STATE PhysicalKeyToggleState;
+
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Always turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;
+
+ //
+ // if no physical console input device exists, return EFI_SUCCESS;
+ // otherwise return the status of setting state of physical console input device
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Status = Private->TextInExList[Index]->SetState (
+ Private->TextInExList[Index],
+ &PhysicalKeyToggleState
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Record the physical KeyToggleState.
+ //
+ Private->PhysicalKeyToggleState = PhysicalKeyToggleState;
+ //
+ // Get if virtual KeyState has been required to be exposed.
+ //
+ Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ 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 for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 KeyNotificationFunction or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINTN Index;
+ TEXT_IN_EX_SPLITTER_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify;
+
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+ NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY));
+ if (NewNotify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewNotify->NotifyHandleList = (VOID **) AllocateZeroPool (sizeof (VOID *) * Private->TextInExListCount);
+ if (NewNotify->NotifyHandleList == NULL) {
+ gBS->FreePool (NewNotify);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewNotify->Signature = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+
+ //
+ // Return the wrong status of registering key notify of
+ // physical console input device if meet problems
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Status = Private->TextInExList[Index]->RegisterKeyNotify (
+ Private->TextInExList[Index],
+ KeyData,
+ KeyNotificationFunction,
+ &NewNotify->NotifyHandleList[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Un-register the key notify on all physical console input devices
+ //
+ while (Index-- != 0) {
+ Private->TextInExList[Index]->UnregisterKeyNotify (
+ Private->TextInExList[Index],
+ NewNotify->NotifyHandleList[Index]
+ );
+ }
+ gBS->FreePool (NewNotify->NotifyHandleList);
+ gBS->FreePool (NewNotify);
+ return Status;
+ }
+ }
+
+ InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ 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
+ConSplitterTextInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify;
+ LIST_ENTRY *Link;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);
+ if (CurrentNotify == NotificationHandle) {
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Private->TextInExList[Index]->UnregisterKeyNotify (
+ Private->TextInExList[Index],
+ CurrentNotify->NotifyHandleList[Index]
+ );
+ }
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ gBS->FreePool (CurrentNotify->NotifyHandleList);
+ gBS->FreePool (CurrentNotify);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // NotificationHandle is not found in database
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+
+/**
+ 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
+ConSplitterSimplePointerReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
+
+ Private->InputEventSignalState = FALSE;
+
+ if (Private->CurrentNumberOfPointers == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfPointers; Index++) {
+ Status = Private->PointerList[Index]->Reset (
+ Private->PointerList[Index],
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ 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 Private Protocol instance pointer.
+ @param State The state information of simple pointer device.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerPrivateGetState (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN OUT EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINTN Index;
+ EFI_SIMPLE_POINTER_STATE CurrentState;
+
+ State->RelativeMovementX = 0;
+ State->RelativeMovementY = 0;
+ State->RelativeMovementZ = 0;
+ State->LeftButton = FALSE;
+ State->RightButton = FALSE;
+
+ //
+ // if no physical console input device exists, return EFI_NOT_READY;
+ // if any physical console input device has key input,
+ // return the key and EFI_SUCCESS.
+ //
+ ReturnStatus = EFI_NOT_READY;
+ for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
+
+ Status = Private->PointerList[Index]->GetState (
+ Private->PointerList[Index],
+ &CurrentState
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ReturnStatus == EFI_NOT_READY) {
+ ReturnStatus = EFI_SUCCESS;
+ }
+
+ if (CurrentState.LeftButton) {
+ State->LeftButton = TRUE;
+ }
+
+ if (CurrentState.RightButton) {
+ State->RightButton = TRUE;
+ }
+
+ if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) {
+ State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX;
+ }
+
+ if (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) {
+ State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY;
+ }
+
+ if (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) {
+ State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ;
+ }
+ } else if (Status == EFI_DEVICE_ERROR) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ 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 A pointer to protocol instance.
+ @param State A pointer to state information on the pointer device
+
+ @retval EFI_SUCCESS The keystroke information was returned in State.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerGetState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN OUT EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);
+
+ Private->InputEventSignalState = FALSE;
+
+ return ConSplitterSimplePointerPrivateGetState (Private, State);
+}
+
+
+/**
+ This event agregates all the events of the ConIn devices in the spliter.
+ If any events of physical ConIn devices are signaled, signal the ConIn
+ spliter event. This will cause the calling code to call
+ ConSplitterTextInReadKeyStroke ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterSimplePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
+
+ //
+ // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()
+ //
+ if (Private->InputEventSignalState) {
+ gBS->SignalEvent (Event);
+ return ;
+ }
+ //
+ // if any physical console input device has key input, signal the event.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {
+ Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput);
+ if (!EFI_ERROR (Status)) {
+ gBS->SignalEvent (Event);
+ Private->InputEventSignalState = TRUE;
+ }
+ }
+}
+
+/**
+ Resets the pointer device hardware.
+
+ @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 correctly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
+
+ Private->AbsoluteInputEventSignalState = FALSE;
+
+ if (Private->CurrentNumberOfAbsolutePointers == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
+ Status = Private->AbsolutePointerList[Index]->Reset (
+ Private->AbsolutePointerList[Index],
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This Protocol instance pointer.
+ @param State A pointer to the state information on the
+ pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in
+ State..
+ @retval EFI_NOT_READY The state of the pointer device has not changed
+ since the last call to GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ retrieve the pointer device's current state.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerGetState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN OUT EFI_ABSOLUTE_POINTER_STATE *State
+ )
+{
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ UINTN Index;
+ EFI_ABSOLUTE_POINTER_STATE CurrentState;
+ UINT64 MinX;
+ UINT64 MinY;
+ UINT64 MinZ;
+ UINT64 MaxX;
+ UINT64 MaxY;
+ UINT64 MaxZ;
+ UINT64 VirtualMinX;
+ UINT64 VirtualMinY;
+ UINT64 VirtualMinZ;
+ UINT64 VirtualMaxX;
+ UINT64 VirtualMaxY;
+ UINT64 VirtualMaxZ;
+
+ Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
+
+ Private->AbsoluteInputEventSignalState = FALSE;
+
+ State->CurrentX = 0;
+ State->CurrentY = 0;
+ State->CurrentZ = 0;
+ State->ActiveButtons = 0;
+
+ VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX;
+ VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY;
+ VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ;
+ VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX;
+ VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY;
+ VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ;
+
+ //
+ // if no physical pointer device exists, return EFI_NOT_READY;
+ // if any physical pointer device has changed state,
+ // return the state and EFI_SUCCESS.
+ //
+ ReturnStatus = EFI_NOT_READY;
+ for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
+
+ Status = Private->AbsolutePointerList[Index]->GetState (
+ Private->AbsolutePointerList[Index],
+ &CurrentState
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ReturnStatus == EFI_NOT_READY) {
+ ReturnStatus = EFI_SUCCESS;
+ }
+
+ MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX;
+ MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY;
+ MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ;
+ MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX;
+ MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY;
+ MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ;
+
+ State->ActiveButtons = CurrentState.ActiveButtons;
+
+ //
+ // Rescale to Con Splitter virtual Absolute Pointer's resolution.
+ //
+ if (!(MinX == 0 && MaxX == 0)) {
+ State->CurrentX = VirtualMinX + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentX,
+ VirtualMaxX - VirtualMinX
+ ),
+ MaxX - MinX,
+ NULL
+ );
+ }
+ if (!(MinY == 0 && MaxY == 0)) {
+ State->CurrentY = VirtualMinY + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentY,
+ VirtualMaxY - VirtualMinY
+ ),
+ MaxY - MinY,
+ NULL
+ );
+ }
+ if (!(MinZ == 0 && MaxZ == 0)) {
+ State->CurrentZ = VirtualMinZ + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentZ,
+ VirtualMaxZ - VirtualMinZ
+ ),
+ MaxZ - MinZ,
+ NULL
+ );
+ }
+
+ } else if (Status == EFI_DEVICE_ERROR) {
+ ReturnStatus = EFI_DEVICE_ERROR;
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ This event agregates all the events of the pointer devices in the splitter.
+ If any events of physical pointer devices are signaled, signal the pointer
+ splitter event. This will cause the calling code to call
+ ConSplitterAbsolutePointerGetState ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;
+
+ //
+ // if AbsoluteInputEventSignalState is flagged before,
+ // and not cleared by Reset() or GetState(), signal it
+ //
+ if (Private->AbsoluteInputEventSignalState) {
+ gBS->SignalEvent (Event);
+ return ;
+ }
+ //
+ // if any physical console input device has key input, signal the event.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {
+ Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput);
+ if (!EFI_ERROR (Status)) {
+ gBS->SignalEvent (Event);
+ Private->AbsoluteInputEventSignalState = TRUE;
+ }
+ }
+}
+
+
+/**
+ Reset the text output device hardware and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform more exhaustive verfication
+ 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
+ConSplitterTextOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->Reset (
+ Private->TextOutList[Index].TextOut,
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
+
+ //
+ // reset all mode parameters
+ //
+ TextOutSetMode (Private, 0);
+
+ return ReturnStatus;
+}
+
+
+/**
+ Write a Unicode string to the output device.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be
+ displayed on the output device(s). All output
+ devices must also support the Unicode drawing
+ defined in this file.
+
+ @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
+ConSplitterTextOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+
+ This->SetAttribute (This, This->Mode->Attribute);
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->OutputString (
+ Private->TextOutList[Index].TextOut,
+ WString
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ if (Private->CurrentNumberOfConsoles > 0) {
+ Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn;
+ Private->TextOutMode.CursorRow = Private->TextOutList[0].TextOut->Mode->CursorRow;
+ } else {
+ //
+ // When there is no real console devices in system,
+ // update cursor position for the virtual device in consplitter.
+ //
+ Private->TextOut.QueryMode (
+ &Private->TextOut,
+ Private->TextOutMode.Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ for (; *WString != CHAR_NULL; WString++) {
+ switch (*WString) {
+ case CHAR_BACKSPACE:
+ if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {
+ Private->TextOutMode.CursorRow--;
+ Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);
+ } else if (Private->TextOutMode.CursorColumn > 0) {
+ Private->TextOutMode.CursorColumn--;
+ }
+ break;
+
+ case CHAR_LINEFEED:
+ if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
+ Private->TextOutMode.CursorRow++;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ Private->TextOutMode.CursorColumn = 0;
+ break;
+
+ default:
+ if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {
+ Private->TextOutMode.CursorColumn++;
+ } else {
+ Private->TextOutMode.CursorColumn = 0;
+ if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
+ Private->TextOutMode.CursorRow++;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ @param This Protocol instance pointer.
+ @param WString 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
+ConSplitterTextOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->TestString (
+ Private->TextOutList[Index].TextOut,
+ WString
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+ //
+ // There is no DevNullTextOutTestString () since a Unicode buffer would
+ // always return EFI_SUCCESS.
+ // ReturnStatus will be EFI_SUCCESS if no consoles are present
+ //
+ return ReturnStatus;
+}
+
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Returns the columns of the text output device
+ for the requested ModeNumber.
+ @param Rows Returns the rows of the text output device
+ for the requested ModeNumber.
+
+ @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
+ConSplitterTextOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN CurrentMode;
+ INT32 *TextOutModeMap;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Check whether param ModeNumber is valid.
+ // ModeNumber should be within range 0 ~ MaxMode - 1.
+ //
+ if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((INT32) ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // We get the available mode from mode intersection map if it's available
+ //
+ if (Private->TextOutModeMap != NULL) {
+ TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
+ CurrentMode = (UINTN)(*TextOutModeMap);
+ *Columns = Private->TextOutQueryData[CurrentMode].Columns;
+ *Rows = Private->TextOutQueryData[CurrentMode].Rows;
+ } else {
+ *Columns = Private->TextOutQueryData[ModeNumber].Columns;
+ *Rows = Private->TextOutQueryData[ModeNumber].Rows;
+ }
+
+ if (*Columns <= 0 && *Rows <= 0) {
+ return EFI_UNSUPPORTED;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number 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
+ConSplitterTextOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ INT32 *TextOutModeMap;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Check whether param ModeNumber is valid.
+ // ModeNumber should be within range 0 ~ MaxMode - 1.
+ //
+ if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((INT32) ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // If the mode is being set to the curent mode, then just clear the screen and return.
+ //
+ if (Private->TextOutMode.Mode == (INT32) ModeNumber) {
+ return ConSplitterTextOutClearScreen (This);
+ }
+ //
+ // return the worst status met
+ //
+ TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ //
+ // While adding a console out device do not set same mode again for the same device.
+ //
+ if ((!Private->AddingConOutDevice) ||
+ (TextOutModeMap[Index] != Private->TextOutList[Index].TextOut->Mode->Mode)) {
+ Status = Private->TextOutList[Index].TextOut->SetMode (
+ Private->TextOutList[Index].TextOut,
+ TextOutModeMap[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+ }
+
+ //
+ // Set mode parameter to specified mode number
+ //
+ TextOutSetMode (Private, ModeNumber);
+
+ return ReturnStatus;
+}
+
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the
+ foreground color, and bits 4..6 are the
+ background color. All other bits are undefined
+ and must be zero. The valid Attributes are
+ defined in this file.
+
+ @retval EFI_SUCCESS The attribute was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete
+ the request.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Check whether param Attribute is valid.
+ //
+ if ((Attribute | 0x7F) != 0x7F) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->SetAttribute (
+ Private->TextOutList[Index].TextOut,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ Private->TextOutMode.Attribute = (INT32) Attribute;
+
+ return ReturnStatus;
+}
+
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ @param This Protocol instance pointer.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ //
+ // No need to do extra check here as whether (Column, Row) is valid has
+ // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
+ // always be supported.
+ //
+ Private->TextOutMode.CursorColumn = 0;
+ Private->TextOutMode.CursorRow = 0;
+ Private->TextOutMode.CursorVisible = TRUE;
+
+ return ReturnStatus;
+}
+
+
+/**
+ Sets the current coordinates of the cursor position
+
+ @param This Protocol instance pointer.
+ @param Column The column position to set the cursor to. Must be
+ greater than or equal to zero and less than the
+ number of columns by QueryMode ().
+ @param Row The row position to set the cursor to. Must be
+ greater than or equal to zero and less than the
+ number of rows by QueryMode ().
+
+ @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
+ConSplitterTextOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ INT32 *TextOutModeMap;
+ INT32 ModeNumber;
+ INT32 CurrentMode;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+ TextOutModeMap = NULL;
+ ModeNumber = Private->TextOutMode.Mode;
+
+ //
+ // Get current MaxColumn and MaxRow from intersection map
+ //
+ if (Private->TextOutModeMap != NULL) {
+ TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
+ CurrentMode = *TextOutModeMap;
+ } else {
+ CurrentMode = ModeNumber;
+ }
+
+ MaxColumn = Private->TextOutQueryData[CurrentMode].Columns;
+ MaxRow = Private->TextOutQueryData[CurrentMode].Rows;
+
+ if (Column >= MaxColumn || Row >= MaxRow) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->SetCursorPosition (
+ Private->TextOutList[Index].TextOut,
+ Column,
+ Row
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ //
+ // No need to do extra check here as whether (Column, Row) is valid has
+ // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
+ // always be supported.
+ //
+ Private->TextOutMode.CursorColumn = (INT32) Column;
+ Private->TextOutMode.CursorRow = (INT32) Row;
+
+ return ReturnStatus;
+}
+
+
+/**
+ Makes the cursor visible or invisible
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible. If
+ FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS 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 is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+
+ Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
+ Status = Private->TextOutList[Index].TextOut->EnableCursor (
+ Private->TextOutList[Index].TextOut,
+ Visible
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+
+ Private->TextOutMode.CursorVisible = Visible;
+
+ return ReturnStatus;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h
new file mode 100644
index 000000000..f26d2adb8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h
@@ -0,0 +1,2000 @@
+/** @file
+ Private data structures for the Console Splitter driver
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CON_SPLITTER_H_
+#define _CON_SPLITTER_H_
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SimplePointer.h>
+#include <Protocol/AbsolutePointer.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+
+#include <Guid/ConsoleInDevice.h>
+#include <Guid/StandardErrorDevice.h>
+#include <Guid/ConsoleOutDevice.h>
+#include <Guid/ConnectConInEvent.h>
+
+#include <Library/PcdLib.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>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterConInComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterConInComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterSimplePointerComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterSimplePointerComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterAbsolutePointerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterAbsolutePointerComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterAbsolutePointerComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterConOutComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterConOutComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gConSplitterStdErrComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gConSplitterStdErrComponentName2;
+
+
+//
+// These definitions were in the old Hii protocol, but are not in the new UEFI
+// version. So they are defined locally.
+//
+#define UNICODE_NARROW_CHAR 0xFFF0
+#define UNICODE_WIDE_CHAR 0xFFF1
+
+
+//
+// Private Data Structures
+//
+#define CONSOLE_SPLITTER_ALLOC_UNIT 32
+
+
+typedef struct {
+ UINTN Column;
+ UINTN Row;
+} CONSOLE_OUT_MODE;
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+} TEXT_OUT_SPLITTER_QUERY_DATA;
+
+#define KEY_STATE_VALID_EXPOSED (EFI_TOGGLE_STATE_VALID | EFI_KEY_STATE_EXPOSED)
+
+#define TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE SIGNATURE_32 ('T', 'i', 'S', 'n')
+
+//
+// Private data for Text In Ex Splitter Notify
+//
+typedef struct _TEXT_IN_EX_SPLITTER_NOTIFY {
+ UINTN Signature;
+ VOID **NotifyHandleList;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} TEXT_IN_EX_SPLITTER_NOTIFY;
+
+#define TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_IN_EX_SPLITTER_NOTIFY, \
+ NotifyEntry, \
+ TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE \
+ )
+
+#define TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'i', 'S', 'p')
+
+//
+// Private data for the Console In splitter
+//
+typedef struct {
+ UINT64 Signature;
+ EFI_HANDLE VirtualHandle;
+
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL TextIn;
+ UINTN CurrentNumberOfConsoles;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL **TextInList;
+ UINTN TextInListCount;
+
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL TextInEx;
+ UINTN CurrentNumberOfExConsoles;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **TextInExList;
+ UINTN TextInExListCount;
+ LIST_ENTRY NotifyList;
+ EFI_KEY_DATA *KeyQueue;
+ UINTN CurrentNumberOfKeys;
+ //
+ // It will be initialized and synced between console input devices
+ // for toggle state sync.
+ //
+ EFI_KEY_TOGGLE_STATE PhysicalKeyToggleState;
+ //
+ // It will be initialized and used to record if virtual KeyState
+ // has been required to be exposed.
+ //
+ BOOLEAN VirtualKeyStateExported;
+
+
+ EFI_SIMPLE_POINTER_PROTOCOL SimplePointer;
+ EFI_SIMPLE_POINTER_MODE SimplePointerMode;
+ UINTN CurrentNumberOfPointers;
+ EFI_SIMPLE_POINTER_PROTOCOL **PointerList;
+ UINTN PointerListCount;
+
+ EFI_ABSOLUTE_POINTER_PROTOCOL AbsolutePointer;
+ EFI_ABSOLUTE_POINTER_MODE AbsolutePointerMode;
+ UINTN CurrentNumberOfAbsolutePointers;
+ EFI_ABSOLUTE_POINTER_PROTOCOL **AbsolutePointerList;
+ UINTN AbsolutePointerListCount;
+ BOOLEAN AbsoluteInputEventSignalState;
+
+ BOOLEAN KeyEventSignalState;
+ BOOLEAN InputEventSignalState;
+ EFI_EVENT ConnectConInEvent;
+} TEXT_IN_SPLITTER_PRIVATE_DATA;
+
+#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_IN_SPLITTER_PRIVATE_DATA, \
+ TextIn, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS(a) \
+ CR ((a), \
+ TEXT_IN_SPLITTER_PRIVATE_DATA, \
+ SimplePointer, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+#define TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA, \
+ TextInEx, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS(a) \
+ CR (a, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA, \
+ AbsolutePointer, \
+ TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+
+#define TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'o', 'S', 'p')
+
+typedef struct {
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+} TEXT_OUT_AND_GOP_DATA;
+
+//
+// Private data for the Console Out splitter
+//
+typedef struct {
+ UINT64 Signature;
+ EFI_HANDLE VirtualHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL TextOut;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE TextOutMode;
+
+ EFI_UGA_DRAW_PROTOCOL UgaDraw;
+ UINT32 UgaHorizontalResolution;
+ UINT32 UgaVerticalResolution;
+ UINT32 UgaColorDepth;
+ UINT32 UgaRefreshRate;
+
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GraphicsOutputModeBuffer;
+ UINTN CurrentNumberOfGraphicsOutput;
+ UINTN CurrentNumberOfUgaDraw;
+
+ UINTN CurrentNumberOfConsoles;
+ TEXT_OUT_AND_GOP_DATA *TextOutList;
+ UINTN TextOutListCount;
+ TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData;
+ UINTN TextOutQueryDataCount;
+ INT32 *TextOutModeMap;
+
+ BOOLEAN AddingConOutDevice;
+
+} TEXT_OUT_SPLITTER_PRIVATE_DATA;
+
+#define TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA, \
+ TextOut, \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA, \
+ GraphicsOutput, \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA, \
+ UgaDraw, \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define CONSOLE_CONTROL_SPLITTER_PRIVATE_DATA_FROM_THIS(a) \
+ CR ((a), \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA, \
+ ConsoleControl, \
+ TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE \
+ )
+
+//
+// Function Prototypes
+//
+
+/**
+ The user Entry Point for module ConSplitter. The user code starts with this function.
+
+ Installs driver module protocols and. Creates virtual device handles for ConIn,
+ ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,
+ Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.
+ Installs Graphics Output protocol and/or UGA Draw protocol if needed.
+
+ @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
+ConSplitterDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Construct console input devices' private data.
+
+ @param ConInPrivate A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA
+ structure.
+
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_SUCCESS Text Input Devcie's private data has been constructed.
+ @retval other Failed to construct private data.
+
+**/
+EFI_STATUS
+ConSplitterTextInConstructor (
+ TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate
+ );
+
+/**
+ Construct console output devices' private data.
+
+ @param ConOutPrivate A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA
+ structure.
+
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_SUCCESS Text Input Devcie's private data has been constructed.
+
+**/
+EFI_STATUS
+ConSplitterTextOutConstructor (
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate
+ );
+
+
+/**
+ Test to see if Console In Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConInDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Test to see if Simple Pointer protocol could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Test to see if Console Out Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConOutDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Test to see if Standard Error Device could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterStdErrDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start Console In Consplitter on device handle.
+
+ @param This Driver Binding 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 Console In Consplitter is added to ControllerHandle.
+ @retval other Console In Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConInDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start Simple Pointer Consplitter on device handle.
+
+ @param This Driver Binding 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 Simple Pointer Consplitter is added to ControllerHandle.
+ @retval other Simple Pointer Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start Console Out Consplitter on device handle.
+
+ @param This Driver Binding 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 Console Out Consplitter is added to ControllerHandle.
+ @retval other Console Out Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterConOutDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start Standard Error Consplitter on device handle.
+
+ @param This Driver Binding 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 Standard Error Consplitter is added to ControllerHandle.
+ @retval other Standard Error Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterStdErrDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID.
+
+ @param This Driver Binding 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
+ConSplitterConInDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing
+ Simple Pointer protocol.
+
+ @param This Driver Binding 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
+ConSplitterSimplePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID.
+
+ @param This Driver Binding 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
+ConSplitterConOutDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID.
+
+ @param This Driver Binding 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
+ConSplitterStdErrDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+
+/**
+ Test to see if Absolute Pointer protocol could be supported on the Controller.
+
+ @param This Driver Binding 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start Absolute Pointer Consplitter on device handle.
+
+ @param This Driver Binding 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 Absolute Pointer Consplitter is added to ControllerHandle.
+ @retval other Absolute Pointer Consplitter does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing
+ Absolute Pointer protocol.
+
+ @param This Driver Binding 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
+ConSplitterAbsolutePointerDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Add Absolute Pointer Device in Consplitter Absolute Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param AbsolutePointer Absolute Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Absolute Pointer Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterAbsolutePointerAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer
+ );
+
+/**
+ Remove Absolute Pointer Device from Consplitter Absolute Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param AbsolutePointer Absolute Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Absolute Pointer Device removed successfully.
+ @retval EFI_NOT_FOUND No Absolute Pointer Device found.
+
+**/
+EFI_STATUS
+ConSplitterAbsolutePointerDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer
+ );
+
+//
+// Absolute Pointer protocol interfaces
+//
+
+
+/**
+ Resets the pointer device hardware.
+
+ @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 correctly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ Retrieves the current state of a pointer device.
+
+ @param This Protocol instance pointer.
+ @param State A pointer to the state information on the
+ pointer device.
+
+ @retval EFI_SUCCESS The state of the pointer device was returned in
+ State..
+ @retval EFI_NOT_READY The state of the pointer device has not changed
+ since the last call to GetState().
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to
+ retrieve the pointer device's current state.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterAbsolutePointerGetState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN OUT EFI_ABSOLUTE_POINTER_STATE *State
+ );
+
+/**
+ This event agregates all the events of the pointer devices in the splitter.
+
+ If any events of physical pointer devices are signaled, signal the pointer
+ splitter event. This will cause the calling code to call
+ ConSplitterAbsolutePointerGetState ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ 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
+ConSplitterComponentNameGetDriverName (
+ 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
+ConSplitterConInComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ 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
+ConSplitterSimplePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the 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 RFC4646 language identifier. This is
+ the language of the controller name that 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.
+ @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
+ConSplitterAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ 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
+ConSplitterConOutComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ 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
+ConSplitterStdErrComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// TextIn Constructor/Destructor functions
+//
+
+/**
+ Add Text Input Device in Consplitter Text Input list.
+
+ @param Private Text In Splitter pointer.
+ @param TextIn Simple Text Input protocol pointer.
+
+ @retval EFI_SUCCESS Text Input Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextInAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn
+ );
+
+/**
+ Remove Text Input Device from Consplitter Text Input list.
+
+ @param Private Text In Splitter pointer.
+ @param TextIn Simple Text protocol pointer.
+
+ @retval EFI_SUCCESS Simple Text Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Text Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextInDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn
+ );
+
+//
+// SimplePointer Constuctor/Destructor functions
+//
+
+/**
+ Add Simple Pointer Device in Consplitter Simple Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param SimplePointer Simple Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Simple Pointer Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterSimplePointerAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
+ );
+
+/**
+ Remove Simple Pointer Device from Consplitter Simple Pointer list.
+
+ @param Private Text In Splitter pointer.
+ @param SimplePointer Simple Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Simple Pointer Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Pointer Device found.
+
+**/
+EFI_STATUS
+ConSplitterSimplePointerDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
+ );
+
+//
+// TextOut Constuctor/Destructor functions
+//
+
+/**
+ Add Text Output Device in Consplitter Text Output list.
+
+ @param Private Text Out Splitter pointer.
+ @param TextOut Simple Text Output protocol pointer.
+ @param GraphicsOutput Graphics Output protocol pointer.
+ @param UgaDraw UGA Draw protocol pointer.
+
+ @retval EFI_SUCCESS Text Output Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextOutAddDevice (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut,
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
+ );
+
+/**
+ Remove Text Out Device in Consplitter Text Out list.
+
+ @param Private Text Out Splitter pointer.
+ @param TextOut Simple Text Output Pointer protocol pointer.
+
+ @retval EFI_SUCCESS Text Out Device removed successfully.
+ @retval EFI_NOT_FOUND No Text Out Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextOutDeleteDevice (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut
+ );
+
+//
+// TextIn I/O Functions
+//
+
+/**
+ 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
+ConSplitterTextInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_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 Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Add Text Input Ex Device in Consplitter Text Input Ex list.
+
+ @param Private Text In Splitter pointer.
+ @param TextInEx Simple Text Input Ex Input protocol pointer.
+
+ @retval EFI_SUCCESS Text Input Ex Device added successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterTextInExAddDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx
+ );
+
+/**
+ Remove Text Ex Device from Consplitter Text Input Ex list.
+
+ @param Private Text In Splitter pointer.
+ @param TextInEx Simple Text Ex protocol pointer.
+
+ @retval EFI_SUCCESS Simple Text Input Ex Device removed successfully.
+ @retval EFI_NOT_FOUND No Simple Text Input Ex Device found.
+
+**/
+EFI_STATUS
+ConSplitterTextInExDeleteDevice (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx
+ );
+
+//
+// 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
+ConSplitterTextInResetEx (
+ 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
+ConSplitterTextInReadKeyStrokeEx (
+ 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
+ConSplitterTextInSetState (
+ 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 for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 KeyNotificationFunction or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInRegisterKeyNotify (
+ 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
+ConSplitterTextInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ This event aggregates all the events of the ConIn devices in the spliter.
+
+ If any events of physical ConIn devices are signaled, signal the ConIn
+ spliter event. This will cause the calling code to call
+ ConSplitterTextInReadKeyStroke ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterTextInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+/**
+ 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 Private Protocol instance pointer.
+ @param Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextInPrivateReadKeyStroke (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ 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
+ConSplitterSimplePointerReset (
+ IN EFI_SIMPLE_POINTER_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 A pointer to protocol instance.
+ @param State A pointer to state information on the pointer device
+
+ @retval EFI_SUCCESS The keystroke information was returned in State.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due
+ to hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterSimplePointerGetState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN OUT EFI_SIMPLE_POINTER_STATE *State
+ );
+
+/**
+ This event agregates all the events of the ConIn devices in the spliter.
+ If any events of physical ConIn devices are signaled, signal the ConIn
+ spliter event. This will cause the calling code to call
+ ConSplitterTextInReadKeyStroke ().
+
+ @param Event The Event assoicated with callback.
+ @param Context Context registered when Event was created.
+
+**/
+VOID
+EFIAPI
+ConSplitterSimplePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// TextOut I/O Functions
+//
+
+/**
+ Reset the text output device hardware and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform more exhaustive verfication
+ 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
+ConSplitterTextOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Write a Unicode string to the output device.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be
+ displayed on the output device(s). All output
+ devices must also support the Unicode drawing
+ defined in this file.
+
+ @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
+ConSplitterTextOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ @param This Protocol instance pointer.
+ @param WString 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
+ConSplitterTextOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Returns the columns of the text output device
+ for the requested ModeNumber.
+ @param Rows Returns the rows of the text output device
+ for the requested ModeNumber.
+
+ @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
+ConSplitterTextOutQueryMode (
+ 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.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number 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
+ConSplitterTextOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the
+ foreground color, and bits 4..6 are the
+ background color. All other bits are undefined
+ and must be zero. The valid Attributes are
+ defined in this file.
+
+ @retval EFI_SUCCESS The attribute was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete
+ the request.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ @param This Protocol instance pointer.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the current coordinates of the cursor position
+
+ @param This Protocol instance pointer.
+ @param Column The column position to set the cursor to. Must be
+ greater than or equal to zero and less than the
+ number of columns by QueryMode ().
+ @param Row The row position to set the cursor to. Must be
+ greater than or equal to zero and less than the
+ number of rows by QueryMode ().
+
+ @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
+ConSplitterTextOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+
+/**
+ Makes the cursor visible or invisible
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible. If
+ FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS 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 is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterTextOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Take the passed in Buffer of size ElementSize and grow the buffer
+ by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes.
+ Copy the current data in Buffer to the new version of Buffer and
+ free the old version of buffer.
+
+ @param ElementSize Size of element in array.
+ @param Count Current number of elements in array.
+ @param Buffer Bigger version of passed in Buffer with all the
+ data.
+
+ @retval EFI_SUCCESS Buffer size has grown.
+ @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size.
+
+**/
+EFI_STATUS
+ConSplitterGrowBuffer (
+ IN UINTN ElementSize,
+ IN OUT UINTN *Count,
+ IN OUT VOID **Buffer
+ );
+
+/**
+ Returns information for an available graphics mode that the graphics device
+ and the set of active video output devices supports.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info buffer.
+ @param Info A pointer to callee 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_INVALID_PARAMETER One of the input args was NULL.
+ @retval EFI_OUT_OF_RESOURCES No resource available.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ );
+
+/**
+ Set the video device into the specified mode and clears the visible portions of
+ the output display to black.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber Abstraction that defines the current video mode.
+
+ @retval EFI_SUCCESS The graphics mode specified by ModeNumber was selected.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES No resource available.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ );
+
+/**
+ The following table defines actions for BltOperations.
+
+ EfiBltVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY)
+ directly to every pixel of the video display rectangle
+ (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ Only one pixel will be used from the BltBuffer. Delta is NOT used.
+ EfiBltVideoToBltBuffer - Read data from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
+ the BltBuffer rectangle (DestinationX, DestinationY )
+ (DestinationX + Width, DestinationY + Height). If DestinationX or
+ DestinationY is not zero then Delta must be set to the length in bytes
+ of a row in the BltBuffer.
+ EfiBltBufferToVideo - Write data from the BltBuffer rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
+ video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
+ not zero then Delta must be set to the length in bytes of a row in the
+ BltBuffer.
+ EfiBltVideoToVideo - Copy from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
+ to the video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ The BltBuffer and Delta are not used in this mode.
+
+ @param This Protocol instance pointer.
+ @param BltBuffer Buffer containing data to blit into video buffer.
+ This buffer has a size of
+ Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ @param BltOperation Operation to perform on BlitBuffer and video
+ memory
+ @param SourceX X coordinate of source for the BltBuffer.
+ @param SourceY Y coordinate of source for the BltBuffer.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+ @param Delta OPTIONAL.
+
+ @retval EFI_SUCCESS The Blt operation completed.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occurred writting to the video
+ buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputBlt (
+ 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 OPTIONAL
+ );
+
+
+/**
+ Return the current video mode information.
+
+ @param This The EFI_UGA_DRAW_PROTOCOL instance.
+ @param HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param ColorDepth Number of bits per pixel, currently defined to be 32.
+ @param RefreshRate The refresh rate of the monitor in Hertz.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @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
+ConSplitterUgaDrawGetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ OUT UINT32 *HorizontalResolution,
+ OUT UINT32 *VerticalResolution,
+ OUT UINT32 *ColorDepth,
+ OUT UINT32 *RefreshRate
+ );
+
+/**
+ Set the current video mode information.
+
+ @param This The EFI_UGA_DRAW_PROTOCOL instance.
+ @param HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param ColorDepth Number of bits per pixel, currently defined to be 32.
+ @param RefreshRate The refresh rate of the monitor in Hertz.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterUgaDrawSetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 ColorDepth,
+ IN UINT32 RefreshRate
+ );
+
+/**
+ Blt a rectangle of pixels on the graphics screen.
+
+ The following table defines actions for BltOperations.
+
+ EfiUgaVideoFill:
+ Write data from the BltBuffer pixel (SourceX, SourceY)
+ directly to every pixel of the video display rectangle
+ (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ Only one pixel will be used from the BltBuffer. Delta is NOT used.
+ EfiUgaVideoToBltBuffer:
+ Read data from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
+ the BltBuffer rectangle (DestinationX, DestinationY )
+ (DestinationX + Width, DestinationY + Height). If DestinationX or
+ DestinationY is not zero then Delta must be set to the length in bytes
+ of a row in the BltBuffer.
+ EfiUgaBltBufferToVideo:
+ Write data from the BltBuffer rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
+ video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
+ not zero then Delta must be set to the length in bytes of a row in the
+ BltBuffer.
+ EfiUgaVideoToVideo:
+ Copy from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
+ to the video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ The BltBuffer and Delta are not used in this mode.
+
+ @param This Protocol instance pointer.
+ @param BltBuffer Buffer containing data to blit into video buffer. This
+ buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)
+ @param BltOperation Operation to perform on BlitBuffer and video memory
+ @param SourceX X coordinate of source for the BltBuffer.
+ @param SourceY Y coordinate of source for the BltBuffer.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+ @param Delta OPTIONAL
+
+ @retval EFI_SUCCESS The Blt operation completed.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occurred writting to the video buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterUgaDrawBlt (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta OPTIONAL
+ );
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ @param Private Text Out Splitter pointer.
+ @param ModeNumber The mode number to set.
+
+**/
+VOID
+TextOutSetMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN UINTN ModeNumber
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
new file mode 100644
index 000000000..9aa1dade7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
@@ -0,0 +1,114 @@
+## @file
+# This driver provides multi console supports.
+#
+# This driver acts as a virtual console, takes over the console I/O control from selected
+# standard console devices, and transmits console I/O to related console device drivers.
+# Consplitter could install Graphics Output protocol and/or UGA Draw protocol in system
+# table according PCD settings(PcdConOutGopSupport, and PcdConOutUgaSupport). It always
+# consumes Graphics Output protocol which is produced by display device, and consumes UGA Draw
+# protocol which is produced by display device according to PcdUgaConsumeSupport value.
+# Note: If only UGA Draw protocol is installed in system, PcdUgaConsumeSupport should be
+# set to TRUE.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ConSplitterDxe
+ MODULE_UNI_FILE = ConSplitterDxe.uni
+ FILE_GUID = 408edcec-cf6d-477c-a5a8-b4844e3de281
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ConSplitterDriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gConSplitterConInDriverBinding
+# COMPONENT_NAME = gConSplitterConInComponentName
+# COMPONENT_NAME2 = gConSplitterConInComponentName2
+# DRIVER_BINDING = gConSplitterSimplePointerDriverBinding
+# COMPONENT_NAME = gConSplitterSimplePointerComponentName
+# COMPONENT_NAME2 = gConSplitterSimplePointerComponentName2
+# DRIVER_BINDING = gConSplitterConOutDriverBinding
+# COMPONENT_NAME = gConSplitterConOutComponentName
+# COMPONENT_NAME2 = gConSplitterConOutComponentName2
+# DRIVER_BINDING = gConSplitterStdErrDriverBinding
+# COMPONENT_NAME = gConSplitterStdErrComponentName
+# COMPONENT_NAME2 = gConSplitterStdErrComponentName2
+#
+
+[Sources]
+ ConSplitterGraphics.c
+ ComponentName.c
+ ConSplitter.h
+ ConSplitter.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Guids]
+ gEfiConsoleInDeviceGuid ## SOMETIMES_CONSUMES ## UNDEFINED # protocol GUID installed on device handle
+ gEfiStandardErrorDeviceGuid ## SOMETIMES_CONSUMES ## UNDEFINED # protocol GUID installed on device handle
+ gEfiConsoleOutDeviceGuid ## SOMETIMES_CONSUMES ## UNDEFINED # protocol GUID installed on device handle
+ ## SOMETIMES_PRODUCES ## Event
+ ## SOMETIMES_CONSUMES ## Event
+ gConnectConInEventGuid
+
+[Protocols]
+ ## PRODUCES
+ ## TO_START
+ gEfiSimplePointerProtocolGuid
+ ## PRODUCES
+ ## TO_START
+ gEfiAbsolutePointerProtocolGuid
+ ## PRODUCES
+ ## TO_START
+ gEfiSimpleTextInProtocolGuid
+ ## PRODUCES
+ ## TO_START
+ gEfiSimpleTextInputExProtocolGuid
+ ## PRODUCES
+ ## TO_START
+ gEfiSimpleTextOutProtocolGuid
+ ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiGraphicsOutputProtocolGuid
+ ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiUgaDrawProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
+
+[Pcd]
+ ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
+ ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ConSplitterDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.uni b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.uni
new file mode 100644
index 000000000..13c25b2a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// This driver provides multi console supports.
+//
+// This driver acts as a virtual console, takes over the console I/O control from selected
+// standard console devices, and transmits console I/O to related console device drivers.
+// Consplitter could install Graphics Output protocol and/or UGA Draw protocol in system
+// table according PCD settings(PcdConOutGopSupport, and PcdConOutUgaSupport). It always
+// consumes Graphics Output protocol which is produced by display device, and consumes UGA Draw
+// protocol which is produced by display device according to PcdUgaConsumeSupport value.
+// Note: If only UGA Draw protocol is installed in system, PcdUgaConsumeSupport should be
+// set to TRUE.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides multi console support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver acts as a virtual console, takes over the console I/O control from selected standard console devices, and transmits console I/O to related console device drivers. Consplitter could install Graphics Output protocol and/or UGA Draw protocol in system table according PCD settings(PcdConOutGopSupport, and PcdConOutUgaSupport). It always consumes Graphics Output protocol, which is produced by display device, and consumes UGA Draw protocol, which is produced by display device according to PcdUgaConsumeSupport value. Note: If only UGA Draw protocol is installed in system, PcdUgaConsumeSupport should be set to TRUE."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxeExtra.uni
new file mode 100644
index 000000000..1ec405734
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ConSplitterDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Console Splitter DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c
new file mode 100644
index 000000000..9323f31b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterGraphics.c
@@ -0,0 +1,622 @@
+/** @file
+ Support for Graphics output spliter.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "ConSplitter.h"
+
+
+CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
+
+/**
+ Returns information for an available graphics mode that the graphics device
+ and the set of active video output devices supports.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info buffer.
+ @param Info A pointer to callee 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_INVALID_PARAMETER One of the input args was NULL.
+ @retval EFI_OUT_OF_RESOURCES No resource available.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // retrieve private data
+ //
+ Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ GraphicsOutput = NULL;
+
+ if (Private->CurrentNumberOfGraphicsOutput == 1) {
+ //
+ // Find the only one GraphicsOutput.
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
+ if (GraphicsOutput != NULL) {
+ break;
+ }
+ }
+ }
+
+ if (GraphicsOutput != NULL) {
+ //
+ // If only one physical GOP device exist, return its information.
+ //
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) ModeNumber, SizeOfInfo, Info);
+ return Status;
+ } else {
+ //
+ // If 2 more phyiscal GOP device exist or GOP protocol does not exist,
+ // return GOP information (PixelFormat is PixelBltOnly) created in ConSplitterAddGraphicsOutputMode ().
+ //
+ *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ if (*Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+ CopyMem (*Info, &Private->GraphicsOutputModeBuffer[ModeNumber], *SizeOfInfo);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Set the video device into the specified mode and clears the visible portions of
+ the output display to black.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber Abstraction that defines the current video mode.
+
+ @retval EFI_SUCCESS The graphics mode specified by ModeNumber was selected.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES No resource available.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *PhysicalGraphicsOutput;
+ UINTN NumberIndex;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+ Mode = &Private->GraphicsOutputModeBuffer[ModeNumber];
+
+ ReturnStatus = EFI_SUCCESS;
+ GraphicsOutput = NULL;
+ PhysicalGraphicsOutput = NULL;
+ //
+ // return the worst status met
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
+ if (GraphicsOutput != NULL) {
+ PhysicalGraphicsOutput = GraphicsOutput;
+ //
+ // Find corresponding ModeNumber of this GraphicsOutput instance
+ //
+ for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {
+ FreePool (Info);
+ break;
+ }
+ FreePool (Info);
+ }
+
+ Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ UgaDraw = Private->TextOutList[Index].UgaDraw;
+ if (UgaDraw != NULL) {
+ Status = UgaDraw->SetMode (
+ UgaDraw,
+ Mode->HorizontalResolution,
+ Mode->VerticalResolution,
+ 32,
+ 60
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+ }
+ }
+
+ This->Mode->Mode = ModeNumber;
+
+ if ((Private->CurrentNumberOfGraphicsOutput == 1) && (PhysicalGraphicsOutput != NULL)) {
+ //
+ // If only one physical GOP device exist, copy physical information to consplitter.
+ //
+ CopyMem (This->Mode->Info, PhysicalGraphicsOutput->Mode->Info, PhysicalGraphicsOutput->Mode->SizeOfInfo);
+ This->Mode->SizeOfInfo = PhysicalGraphicsOutput->Mode->SizeOfInfo;
+ This->Mode->FrameBufferBase = PhysicalGraphicsOutput->Mode->FrameBufferBase;
+ This->Mode->FrameBufferSize = PhysicalGraphicsOutput->Mode->FrameBufferSize;
+ } else {
+ //
+ // If 2 more phyiscal GOP device exist or GOP protocol does not exist,
+ // return GOP information (PixelFormat is PixelBltOnly) created in ConSplitterAddGraphicsOutputMode ().
+ //
+ CopyMem (This->Mode->Info, &Private->GraphicsOutputModeBuffer[ModeNumber], This->Mode->SizeOfInfo);
+ }
+
+ return ReturnStatus;
+}
+
+
+
+/**
+ The following table defines actions for BltOperations.
+
+ EfiBltVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY)
+ directly to every pixel of the video display rectangle
+ (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ Only one pixel will be used from the BltBuffer. Delta is NOT used.
+ EfiBltVideoToBltBuffer - Read data from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
+ the BltBuffer rectangle (DestinationX, DestinationY )
+ (DestinationX + Width, DestinationY + Height). If DestinationX or
+ DestinationY is not zero then Delta must be set to the length in bytes
+ of a row in the BltBuffer.
+ EfiBltBufferToVideo - Write data from the BltBuffer rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
+ video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
+ not zero then Delta must be set to the length in bytes of a row in the
+ BltBuffer.
+ EfiBltVideoToVideo - Copy from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
+ to the video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ The BltBuffer and Delta are not used in this mode.
+
+ @param This Protocol instance pointer.
+ @param BltBuffer Buffer containing data to blit into video buffer.
+ This buffer has a size of
+ Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ @param BltOperation Operation to perform on BlitBuffer and video
+ memory
+ @param SourceX X coordinate of source for the BltBuffer.
+ @param SourceY Y coordinate of source for the BltBuffer.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+ @param Delta OPTIONAL.
+
+ @retval EFI_SUCCESS The Blt operation completed.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occurred writting to the video
+ buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterGraphicsOutputBlt (
+ 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 OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+
+ if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GRAPHICS_OUTPUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ BltBuffer,
+ BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ } else if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Only need to read the data into buffer one time
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ UgaDraw = Private->TextOutList[Index].UgaDraw;
+ if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) BltBuffer,
+ (EFI_UGA_BLT_OPERATION) BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ } else if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Only need to read the data into buffer one time
+ //
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Return the current video mode information.
+
+ @param This The EFI_UGA_DRAW_PROTOCOL instance.
+ @param HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param ColorDepth Number of bits per pixel, currently defined to be 32.
+ @param RefreshRate The refresh rate of the monitor in Hertz.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @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
+ConSplitterUgaDrawGetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ OUT UINT32 *HorizontalResolution,
+ OUT UINT32 *VerticalResolution,
+ OUT UINT32 *ColorDepth,
+ OUT UINT32 *RefreshRate
+ )
+{
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+
+ if ((HorizontalResolution == NULL) ||
+ (VerticalResolution == NULL) ||
+ (RefreshRate == NULL) ||
+ (ColorDepth == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // retrieve private data
+ //
+ Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ *HorizontalResolution = Private->UgaHorizontalResolution;
+ *VerticalResolution = Private->UgaVerticalResolution;
+ *ColorDepth = Private->UgaColorDepth;
+ *RefreshRate = Private->UgaRefreshRate;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Set the current video mode information.
+
+ @param This The EFI_UGA_DRAW_PROTOCOL instance.
+ @param HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param ColorDepth Number of bits per pixel, currently defined to be 32.
+ @param RefreshRate The refresh rate of the monitor in Hertz.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterUgaDrawSetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 ColorDepth,
+ IN UINT32 RefreshRate
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ UINTN NumberIndex;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+
+ Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Update the Mode data
+ //
+ Private->UgaHorizontalResolution = HorizontalResolution;
+ Private->UgaVerticalResolution = VerticalResolution;
+ Private->UgaColorDepth = ColorDepth;
+ Private->UgaRefreshRate = RefreshRate;
+
+ //
+ // return the worst status met
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+
+ GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
+ if (GraphicsOutput != NULL) {
+ //
+ // Find corresponding ModeNumber of this GraphicsOutput instance
+ //
+ for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) {
+ Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((Info->HorizontalResolution == HorizontalResolution) && (Info->VerticalResolution == VerticalResolution)) {
+ FreePool (Info);
+ break;
+ }
+ FreePool (Info);
+ }
+
+ Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)){
+ UgaDraw = Private->TextOutList[Index].UgaDraw;
+ if (UgaDraw != NULL) {
+ Status = UgaDraw->SetMode (
+ UgaDraw,
+ HorizontalResolution,
+ VerticalResolution,
+ ColorDepth,
+ RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ }
+ }
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Blt a rectangle of pixels on the graphics screen.
+
+ The following table defines actions for BltOperations.
+
+ EfiUgaVideoFill:
+ Write data from the BltBuffer pixel (SourceX, SourceY)
+ directly to every pixel of the video display rectangle
+ (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ Only one pixel will be used from the BltBuffer. Delta is NOT used.
+ EfiUgaVideoToBltBuffer:
+ Read data from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
+ the BltBuffer rectangle (DestinationX, DestinationY )
+ (DestinationX + Width, DestinationY + Height). If DestinationX or
+ DestinationY is not zero then Delta must be set to the length in bytes
+ of a row in the BltBuffer.
+ EfiUgaBltBufferToVideo:
+ Write data from the BltBuffer rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
+ video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
+ not zero then Delta must be set to the length in bytes of a row in the
+ BltBuffer.
+ EfiUgaVideoToVideo:
+ Copy from the video display rectangle
+ (SourceX, SourceY) (SourceX + Width, SourceY + Height) .
+ to the video display rectangle (DestinationX, DestinationY)
+ (DestinationX + Width, DestinationY + Height).
+ The BltBuffer and Delta are not used in this mode.
+
+ @param This Protocol instance pointer.
+ @param BltBuffer Buffer containing data to blit into video buffer. This
+ buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL)
+ @param BltOperation Operation to perform on BlitBuffer and video memory
+ @param SourceX X coordinate of source for the BltBuffer.
+ @param SourceY Y coordinate of source for the BltBuffer.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+ @param Delta OPTIONAL
+
+ @retval EFI_SUCCESS The Blt operation completed.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occurred writting to the video buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+ConSplitterUgaDrawBlt (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TEXT_OUT_SPLITTER_PRIVATE_DATA *Private;
+ UINTN Index;
+ EFI_STATUS ReturnStatus;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ Private = UGA_DRAW_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+
+ ReturnStatus = EFI_SUCCESS;
+ //
+ // return the worst status met
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ GraphicsOutput = Private->TextOutList[Index].GraphicsOutput;
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltBuffer,
+ (EFI_GRAPHICS_OUTPUT_BLT_OPERATION) BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ } else if (BltOperation == EfiUgaVideoToBltBuffer) {
+ //
+ // Only need to read the data into buffer one time
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Private->TextOutList[Index].UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = Private->TextOutList[Index].UgaDraw->Blt (
+ Private->TextOutList[Index].UgaDraw,
+ BltBuffer,
+ BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ } else if (BltOperation == EfiUgaVideoToBltBuffer) {
+ //
+ // Only need to read the data into buffer one time
+ //
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ @param Private Text Out Splitter pointer.
+ @param ModeNumber The mode number to set.
+
+**/
+VOID
+TextOutSetMode (
+ IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
+ IN UINTN ModeNumber
+ )
+{
+ //
+ // No need to do extra check here as whether (Column, Row) is valid has
+ // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should
+ // always be supported.
+ //
+ Private->TextOutMode.Mode = (INT32) ModeNumber;
+ Private->TextOutMode.CursorColumn = 0;
+ Private->TextOutMode.CursorRow = 0;
+ Private->TextOutMode.CursorVisible = TRUE;
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/ComponentName.c
new file mode 100644
index 000000000..0e6304087
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/ComponentName.c
@@ -0,0 +1,176 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for GraphicsConsole driver.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GraphicsConsole.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName = {
+ GraphicsConsoleComponentNameGetDriverName,
+ GraphicsConsoleComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gGraphicsConsoleComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GraphicsConsoleComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GraphicsConsoleComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mGraphicsConsoleDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Graphics Console 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
+GraphicsConsoleComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mGraphicsConsoleDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gGraphicsConsoleComponentName)
+ );
+}
+
+/**
+ 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
+GraphicsConsoleComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c
new file mode 100644
index 000000000..c042451a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c
@@ -0,0 +1,2136 @@
+/** @file
+ This is the main routine for initializing the Graphics Console support routines.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GraphicsConsole.h"
+
+//
+// Graphics Console Device Private Data template
+//
+GRAPHICS_CONSOLE_DEV mGraphicsConsoleDevTemplate = {
+ GRAPHICS_CONSOLE_DEV_SIGNATURE,
+ (EFI_GRAPHICS_OUTPUT_PROTOCOL *) NULL,
+ (EFI_UGA_DRAW_PROTOCOL *) NULL,
+ {
+ GraphicsConsoleConOutReset,
+ GraphicsConsoleConOutOutputString,
+ GraphicsConsoleConOutTestString,
+ GraphicsConsoleConOutQueryMode,
+ GraphicsConsoleConOutSetMode,
+ GraphicsConsoleConOutSetAttribute,
+ GraphicsConsoleConOutClearScreen,
+ GraphicsConsoleConOutSetCursorPosition,
+ GraphicsConsoleConOutEnableCursor,
+ (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
+ },
+ {
+ 0,
+ -1,
+ EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK),
+ 0,
+ 0,
+ TRUE
+ },
+ (GRAPHICS_CONSOLE_MODE_DATA *) NULL,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL
+};
+
+GRAPHICS_CONSOLE_MODE_DATA mGraphicsConsoleModeData[] = {
+ {100, 31},
+ //
+ // New modes can be added here.
+ // The last entry is specific for full screen mode.
+ //
+ {0, 0}
+};
+
+EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
+EFI_HII_FONT_PROTOCOL *mHiiFont;
+EFI_HII_HANDLE mHiiHandle;
+VOID *mHiiRegistration;
+
+EFI_GUID mFontPackageListGuid = {0xf5f219d3, 0x7006, 0x4648, {0xac, 0x8d, 0xd6, 0x1d, 0xfb, 0x7b, 0xc6, 0xad}};
+
+CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
+
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL mGraphicsEfiColors[16] = {
+ //
+ // B G R reserved
+ //
+ {0x00, 0x00, 0x00, 0x00}, // BLACK
+ {0x98, 0x00, 0x00, 0x00}, // LIGHTBLUE
+ {0x00, 0x98, 0x00, 0x00}, // LIGHGREEN
+ {0x98, 0x98, 0x00, 0x00}, // LIGHCYAN
+ {0x00, 0x00, 0x98, 0x00}, // LIGHRED
+ {0x98, 0x00, 0x98, 0x00}, // MAGENTA
+ {0x00, 0x98, 0x98, 0x00}, // BROWN
+ {0x98, 0x98, 0x98, 0x00}, // LIGHTGRAY
+ {0x30, 0x30, 0x30, 0x00}, // DARKGRAY - BRIGHT BLACK
+ {0xff, 0x00, 0x00, 0x00}, // BLUE
+ {0x00, 0xff, 0x00, 0x00}, // LIME
+ {0xff, 0xff, 0x00, 0x00}, // CYAN
+ {0x00, 0x00, 0xff, 0x00}, // RED
+ {0xff, 0x00, 0xff, 0x00}, // FUCHSIA
+ {0x00, 0xff, 0xff, 0x00}, // YELLOW
+ {0xff, 0xff, 0xff, 0x00} // WHITE
+};
+
+EFI_NARROW_GLYPH mCursorGlyph = {
+ 0x0000,
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF }
+};
+
+CHAR16 SpaceStr[] = { NARROW_CHAR, ' ', 0 };
+
+EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding = {
+ GraphicsConsoleControllerDriverSupported,
+ GraphicsConsoleControllerDriverStart,
+ GraphicsConsoleControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Test to see if Graphics Console could be supported on the Controller.
+
+ Graphics Console could be supported if Graphics Output Protocol or UGA Draw
+ Protocol exists on the Controller. (UGA Draw Protocol could be skipped
+ if PcdUgaConsumeSupport is set to FALSE.)
+
+ @param This Protocol instance pointer.
+ @param Controller 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ GraphicsOutput = NULL;
+ UgaDraw = NULL;
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // Open Graphics Output Protocol failed, try to open UGA Draw Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // We need to ensure that we do not layer on top of a virtual handle.
+ // We need to ensure that the handles produced by the conspliter do not
+ // get used.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ goto Error;
+ }
+
+ //
+ // Does Hii Exist? If not, we aren't ready to run
+ //
+ Status = EfiLocateHiiProtocol ();
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+Error:
+ if (GraphicsOutput != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+/**
+ Initialize all the text modes which the graphics console supports.
+
+ It returns information for available text modes that the graphics can support.
+
+ @param[in] HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param[in] VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param[in] GopModeNumber The graphics mode number which graphis console is based on.
+ @param[out] TextModeCount The total number of text modes that graphics console supports.
+ @param[out] TextModeData The buffer to the text modes column and row information.
+ Caller is responsible to free it when it's non-NULL.
+
+ @retval EFI_SUCCESS The supporting mode information is returned.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+InitializeGraphicsConsoleTextMode (
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 GopModeNumber,
+ OUT UINTN *TextModeCount,
+ OUT GRAPHICS_CONSOLE_MODE_DATA **TextModeData
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeBuffer;
+ GRAPHICS_CONSOLE_MODE_DATA *NewModeBuffer;
+ UINTN ValidCount;
+ UINTN ValidIndex;
+ UINTN MaxColumns;
+ UINTN MaxRows;
+
+ if ((TextModeCount == NULL) || (TextModeData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count = sizeof (mGraphicsConsoleModeData) / sizeof (GRAPHICS_CONSOLE_MODE_DATA);
+
+ //
+ // Compute the maximum number of text Rows and Columns that this current graphics mode can support.
+ // To make graphics console work well, MaxColumns and MaxRows should not be zero.
+ //
+ MaxColumns = HorizontalResolution / EFI_GLYPH_WIDTH;
+ MaxRows = VerticalResolution / EFI_GLYPH_HEIGHT;
+
+ //
+ // According to UEFI spec, all output devices support at least 80x25 text mode.
+ //
+ ASSERT ((MaxColumns >= 80) && (MaxRows >= 25));
+
+ //
+ // Add full screen mode to the last entry.
+ //
+ mGraphicsConsoleModeData[Count - 1].Columns = MaxColumns;
+ mGraphicsConsoleModeData[Count - 1].Rows = MaxRows;
+
+ //
+ // Get defined mode buffer pointer.
+ //
+ ModeBuffer = mGraphicsConsoleModeData;
+
+ //
+ // Here we make sure that the final mode exposed does not include the duplicated modes,
+ // and does not include the invalid modes which exceed the max column and row.
+ // Reserve 2 modes for 80x25, 80x50 of graphics console.
+ //
+ NewModeBuffer = AllocateZeroPool (sizeof (GRAPHICS_CONSOLE_MODE_DATA) * (Count + 2));
+ ASSERT (NewModeBuffer != NULL);
+
+ //
+ // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
+ //
+ ValidCount = 0;
+
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 25;
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (NewModeBuffer[ValidCount].Columns * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (NewModeBuffer[ValidCount].Rows * EFI_GLYPH_HEIGHT)) >> 1;
+ ValidCount++;
+
+ if ((MaxColumns >= 80) && (MaxRows >= 50)) {
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 50;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (80 * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (50 * EFI_GLYPH_HEIGHT)) >> 1;
+ }
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ ValidCount++;
+
+ //
+ // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
+ //
+ for (Index = 0; Index < Count; Index++) {
+ if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0) ||
+ (ModeBuffer[Index].Columns > MaxColumns) || (ModeBuffer[Index].Rows > MaxRows)) {
+ //
+ // Skip the pre-defined mode which is invalid or exceeds the max column and row.
+ //
+ continue;
+ }
+ for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
+ if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
+ (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
+ //
+ // Skip the duplicated mode.
+ //
+ break;
+ }
+ }
+ if (ValidIndex == ValidCount) {
+ NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
+ NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (NewModeBuffer[ValidCount].Columns * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (NewModeBuffer[ValidCount].Rows * EFI_GLYPH_HEIGHT)) >> 1;
+ ValidCount++;
+ }
+ }
+
+ DEBUG_CODE (
+ for (Index = 0; Index < ValidCount; Index++) {
+ DEBUG ((EFI_D_INFO, "Graphics - Mode %d, Column = %d, Row = %d\n",
+ Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
+ }
+ );
+
+ //
+ // Return valid mode count and mode information buffer.
+ //
+ *TextModeCount = ValidCount;
+ *TextModeData = NewModeBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on Controller by opening Graphics Output protocol or
+ UGA Draw protocol, and installing Simple Text Out protocol on Controller.
+ (UGA Draw protocol could be skipped if PcdUgaConsumeSupport is set to FALSE.)
+
+ @param This Protocol instance pointer.
+ @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 This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ UINT32 ModeIndex;
+ UINTN MaxMode;
+ UINT32 ModeNumber;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ INT32 PreferMode;
+ INT32 Index;
+ UINTN Column;
+ UINTN Row;
+ UINTN DefaultColumn;
+ UINTN DefaultRow;
+
+ ModeNumber = 0;
+
+ //
+ // Initialize the Graphics Console device instance
+ //
+ Private = AllocateCopyPool (
+ sizeof (GRAPHICS_CONSOLE_DEV),
+ &mGraphicsConsoleDevTemplate
+ );
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->SimpleTextOutput.Mode = &(Private->SimpleTextOutputMode);
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &Private->GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR(Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &Private->UgaDraw,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution);
+ VerticalResolution = PcdGet32 (PcdVideoVerticalResolution);
+
+ if (Private->GraphicsOutput != NULL) {
+ //
+ // The console is build on top of Graphics Output Protocol, find the mode number
+ // for the user-defined mode; if there are multiple video devices,
+ // graphic console driver will set all the video devices to the same mode.
+ //
+ if ((HorizontalResolution == 0x0) || (VerticalResolution == 0x0)) {
+ //
+ // Find the highest resolution which GOP supports.
+ //
+ MaxMode = Private->GraphicsOutput->Mode->MaxMode;
+
+ for (ModeIndex = 0; ModeIndex < MaxMode; ModeIndex++) {
+ Status = Private->GraphicsOutput->QueryMode (
+ Private->GraphicsOutput,
+ ModeIndex,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution > HorizontalResolution) ||
+ ((Info->HorizontalResolution == HorizontalResolution) && (Info->VerticalResolution > VerticalResolution))) {
+ HorizontalResolution = Info->HorizontalResolution;
+ VerticalResolution = Info->VerticalResolution;
+ ModeNumber = ModeIndex;
+ }
+ FreePool (Info);
+ }
+ }
+ if ((HorizontalResolution == 0x0) || (VerticalResolution == 0x0)) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+ } else {
+ //
+ // Use user-defined resolution
+ //
+ Status = CheckModeSupported (
+ Private->GraphicsOutput,
+ HorizontalResolution,
+ VerticalResolution,
+ &ModeNumber
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if not supporting current mode, try 800x600 which is required by UEFI/EFI spec
+ //
+ HorizontalResolution = 800;
+ VerticalResolution = 600;
+ Status = CheckModeSupported (
+ Private->GraphicsOutput,
+ HorizontalResolution,
+ VerticalResolution,
+ &ModeNumber
+ );
+ Mode = Private->GraphicsOutput->Mode;
+ if (EFI_ERROR (Status) && Mode->MaxMode != 0) {
+ //
+ // Set default mode failed or device don't support default mode, then get the current mode information
+ //
+ HorizontalResolution = Mode->Info->HorizontalResolution;
+ VerticalResolution = Mode->Info->VerticalResolution;
+ ModeNumber = Mode->Mode;
+ }
+ }
+ }
+ if (ModeNumber != Private->GraphicsOutput->Mode->Mode) {
+ //
+ // Current graphics mode is not set or is not set to the mode which we has found,
+ // set the new graphic mode.
+ //
+ Status = Private->GraphicsOutput->SetMode (Private->GraphicsOutput, ModeNumber);
+ if (EFI_ERROR (Status)) {
+ //
+ // The mode set operation failed
+ //
+ goto Error;
+ }
+ }
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // At first try to set user-defined resolution
+ //
+ ColorDepth = 32;
+ RefreshRate = 60;
+ Status = Private->UgaDraw->SetMode (
+ Private->UgaDraw,
+ HorizontalResolution,
+ VerticalResolution,
+ ColorDepth,
+ RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Try to set 800*600 which is required by UEFI/EFI spec
+ //
+ Status = Private->UgaDraw->SetMode (
+ Private->UgaDraw,
+ 800,
+ 600,
+ ColorDepth,
+ RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ Status = Private->UgaDraw->GetMode (
+ Private->UgaDraw,
+ &HorizontalResolution,
+ &VerticalResolution,
+ &ColorDepth,
+ &RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "GraphicsConsole video resolution %d x %d\n", HorizontalResolution, VerticalResolution));
+
+ //
+ // Initialize the mode which GraphicsConsole supports.
+ //
+ Status = InitializeGraphicsConsoleTextMode (
+ HorizontalResolution,
+ VerticalResolution,
+ ModeNumber,
+ &MaxMode,
+ &Private->ModeData
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Update the maximum number of modes
+ //
+ Private->SimpleTextOutputMode.MaxMode = (INT32) MaxMode;
+
+ //
+ // Initialize the Mode of graphics console devices
+ //
+ PreferMode = -1;
+ DefaultColumn = PcdGet32 (PcdConOutColumn);
+ DefaultRow = PcdGet32 (PcdConOutRow);
+ Column = 0;
+ Row = 0;
+ for (Index = 0; Index < (INT32)MaxMode; Index++) {
+ if (DefaultColumn != 0 && DefaultRow != 0) {
+ if ((Private->ModeData[Index].Columns == DefaultColumn) &&
+ (Private->ModeData[Index].Rows == DefaultRow)) {
+ PreferMode = Index;
+ break;
+ }
+ } else {
+ if ((Private->ModeData[Index].Columns > Column) &&
+ (Private->ModeData[Index].Rows > Row)) {
+ Column = Private->ModeData[Index].Columns;
+ Row = Private->ModeData[Index].Rows;
+ PreferMode = Index;
+ }
+ }
+ }
+ Private->SimpleTextOutput.Mode->Mode = (INT32)PreferMode;
+ DEBUG ((DEBUG_INFO, "Graphics Console Started, Mode: %d\n", PreferMode));
+
+ //
+ // Install protocol interfaces for the Graphics Console device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &Private->SimpleTextOutput,
+ NULL
+ );
+
+Error:
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the GOP and UGA Draw Protocol
+ //
+ if (Private->GraphicsOutput != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (Private->LineBuffer != NULL) {
+ FreePool (Private->LineBuffer);
+ }
+
+ if (Private->ModeData != NULL) {
+ FreePool (Private->ModeData);
+ }
+
+ //
+ // Free private data
+ //
+ FreePool (Private);
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on Controller by removing Simple Text Out protocol
+ and closing the Graphics Output Protocol or UGA Draw protocol on Controller.
+ (UGA Draw protocol could be skipped if PcdUgaConsumeSupport is set to FALSE.)
+
+
+ @param This Protocol instance pointer.
+ @param Controller 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 Controller.
+ @retval EFI_NOT_STARTED Simple Text Out protocol could not be found the
+ Controller.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ GRAPHICS_CONSOLE_DEV *Private;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &Private->SimpleTextOutput
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close the GOP or UGA IO Protocol
+ //
+ if (Private->GraphicsOutput != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (Private->LineBuffer != NULL) {
+ FreePool (Private->LineBuffer);
+ }
+
+ if (Private->ModeData != NULL) {
+ FreePool (Private->ModeData);
+ }
+
+ //
+ // Free our instance data
+ //
+ FreePool (Private);
+ }
+
+ return Status;
+}
+
+/**
+ Check if the current specific mode supported the user defined resolution
+ for the Graphics Console device based on Graphics Output Protocol.
+
+ If yes, set the graphic devcice's current mode to this specific mode.
+
+ @param GraphicsOutput Graphics Output Protocol instance pointer.
+ @param HorizontalResolution User defined horizontal resolution
+ @param VerticalResolution User defined vertical resolution.
+ @param CurrentModeNumber Current specific mode to be check.
+
+ @retval EFI_SUCCESS The mode is supported.
+ @retval EFI_UNSUPPORTED The specific mode is out of range of graphics
+ device supported.
+ @retval other The specific mode does not support user defined
+ resolution or failed to set the current mode to the
+ specific mode on graphics device.
+
+**/
+EFI_STATUS
+CheckModeSupported (
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ OUT UINT32 *CurrentModeNumber
+ )
+{
+ UINT32 ModeNumber;
+ EFI_STATUS Status;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINT32 MaxMode;
+
+ Status = EFI_SUCCESS;
+ MaxMode = GraphicsOutput->Mode->MaxMode;
+
+ for (ModeNumber = 0; ModeNumber < MaxMode; ModeNumber++) {
+ Status = GraphicsOutput->QueryMode (
+ GraphicsOutput,
+ ModeNumber,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution == HorizontalResolution) &&
+ (Info->VerticalResolution == VerticalResolution)) {
+ if ((GraphicsOutput->Mode->Info->HorizontalResolution == HorizontalResolution) &&
+ (GraphicsOutput->Mode->Info->VerticalResolution == VerticalResolution)) {
+ //
+ // If video device has been set to this mode, we do not need to SetMode again
+ //
+ FreePool (Info);
+ break;
+ } else {
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
+ if (!EFI_ERROR (Status)) {
+ FreePool (Info);
+ break;
+ }
+ }
+ }
+ FreePool (Info);
+ }
+ }
+
+ if (ModeNumber == GraphicsOutput->Mode->MaxMode) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ *CurrentModeNumber = ModeNumber;
+ return Status;
+}
+
+
+/**
+ Locate HII Database protocol and HII Font protocol.
+
+ @retval EFI_SUCCESS HII Database protocol and HII Font protocol
+ are located successfully.
+ @return other Failed to locate HII Database protocol or
+ HII Font protocol.
+
+**/
+EFI_STATUS
+EfiLocateHiiProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &mHiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &mHiiFont);
+ return Status;
+}
+
+//
+// Body of the STO functions
+//
+
+/**
+ Reset the text output device hardware and optionally run diagnostics.
+
+ Implements SIMPLE_TEXT_OUTPUT.Reset().
+ If ExtendeVerification is TRUE, then perform dependent Graphics Console
+ device reset, and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Protocol instance pointer.
+ @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
+GraphicsConsoleConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ Status = This->SetMode (This, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));
+ return Status;
+}
+
+
+/**
+ Write a Unicode string to the output device.
+
+ Implements SIMPLE_TEXT_OUTPUT.OutputString().
+ The Unicode string will be converted to Glyphs and will be
+ sent to the Graphics Console.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be displayed
+ on the output device(s). All output devices must
+ also support the Unicode drawing defined in this file.
+
+ @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
+GraphicsConsoleConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ INTN Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ UINTN Width;
+ UINTN Height;
+ UINTN Delta;
+ EFI_STATUS Status;
+ BOOLEAN Warning;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ UINTN DeltaX;
+ UINTN DeltaY;
+ UINTN Count;
+ UINTN Index;
+ INT32 OriginAttribute;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ //
+ // Current mode
+ //
+ Mode = This->Mode->Mode;
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+ UgaDraw = Private->UgaDraw;
+
+ MaxColumn = Private->ModeData[Mode].Columns;
+ MaxRow = Private->ModeData[Mode].Rows;
+ DeltaX = (UINTN) Private->ModeData[Mode].DeltaX;
+ DeltaY = (UINTN) Private->ModeData[Mode].DeltaY;
+ Width = MaxColumn * EFI_GLYPH_WIDTH;
+ Height = (MaxRow - 1) * EFI_GLYPH_HEIGHT;
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ //
+ // The Attributes won't change when during the time OutputString is called
+ //
+ GetTextColors (This, &Foreground, &Background);
+
+ FlushCursor (This);
+
+ Warning = FALSE;
+
+ //
+ // Backup attribute
+ //
+ OriginAttribute = This->Mode->Attribute;
+
+ while (*WString != L'\0') {
+
+ if (*WString == CHAR_BACKSPACE) {
+ //
+ // If the cursor is at the left edge of the display, then move the cursor
+ // one row up.
+ //
+ if (This->Mode->CursorColumn == 0 && This->Mode->CursorRow > 0) {
+ This->Mode->CursorRow--;
+ This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
+ This->OutputString (This, SpaceStr);
+ FlushCursor (This);
+ This->Mode->CursorRow--;
+ This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
+ } else if (This->Mode->CursorColumn > 0) {
+ //
+ // If the cursor is not at the left edge of the display, then move the cursor
+ // left one column.
+ //
+ This->Mode->CursorColumn--;
+ This->OutputString (This, SpaceStr);
+ FlushCursor (This);
+ This->Mode->CursorColumn--;
+ }
+
+ WString++;
+
+ } else if (*WString == CHAR_LINEFEED) {
+ //
+ // If the cursor is at the bottom of the display, then scroll the display one
+ // row, and do not update the cursor position. Otherwise, move the cursor
+ // down one row.
+ //
+ if (This->Mode->CursorRow == (INT32) (MaxRow - 1)) {
+ if (GraphicsOutput != NULL) {
+ //
+ // Scroll Screen Up One Row
+ //
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ NULL,
+ EfiBltVideoToVideo,
+ DeltaX,
+ DeltaY + EFI_GLYPH_HEIGHT,
+ DeltaX,
+ DeltaY,
+ Width,
+ Height,
+ Delta
+ );
+
+ //
+ // Print Blank Line at last line
+ //
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ DeltaX,
+ DeltaY + Height,
+ Width,
+ EFI_GLYPH_HEIGHT,
+ Delta
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // Scroll Screen Up One Row
+ //
+ UgaDraw->Blt (
+ UgaDraw,
+ NULL,
+ EfiUgaVideoToVideo,
+ DeltaX,
+ DeltaY + EFI_GLYPH_HEIGHT,
+ DeltaX,
+ DeltaY,
+ Width,
+ Height,
+ Delta
+ );
+
+ //
+ // Print Blank Line at last line
+ //
+ UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) (UINTN) &Background,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ DeltaX,
+ DeltaY + Height,
+ Width,
+ EFI_GLYPH_HEIGHT,
+ Delta
+ );
+ }
+ } else {
+ This->Mode->CursorRow++;
+ }
+
+ WString++;
+
+ } else if (*WString == CHAR_CARRIAGE_RETURN) {
+ //
+ // Move the cursor to the beginning of the current row.
+ //
+ This->Mode->CursorColumn = 0;
+ WString++;
+
+ } else if (*WString == WIDE_CHAR) {
+
+ This->Mode->Attribute |= EFI_WIDE_ATTRIBUTE;
+ WString++;
+
+ } else if (*WString == NARROW_CHAR) {
+
+ This->Mode->Attribute &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
+ WString++;
+
+ } else {
+ //
+ // Print the character at the current cursor position and move the cursor
+ // right one column. If this moves the cursor past the right edge of the
+ // display, then the line should wrap to the beginning of the next line. This
+ // is equivalent to inserting a CR and an LF. Note that if the cursor is at the
+ // bottom of the display, and the line wraps, then the display will be scrolled
+ // one line.
+ // If wide char is going to be displayed, need to display one character at a time
+ // Or, need to know the display length of a certain string.
+ //
+ // Index is used to determine how many character width units (wide = 2, narrow = 1)
+ // Count is used to determine how many characters are used regardless of their attributes
+ //
+ for (Count = 0, Index = 0; (This->Mode->CursorColumn + Index) < MaxColumn; Count++, Index++) {
+ if (WString[Count] == CHAR_NULL ||
+ WString[Count] == CHAR_BACKSPACE ||
+ WString[Count] == CHAR_LINEFEED ||
+ WString[Count] == CHAR_CARRIAGE_RETURN ||
+ WString[Count] == WIDE_CHAR ||
+ WString[Count] == NARROW_CHAR) {
+ break;
+ }
+ //
+ // Is the wide attribute on?
+ //
+ if ((This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) != 0) {
+ //
+ // If wide, add one more width unit than normal since we are going to increment at the end of the for loop
+ //
+ Index++;
+ //
+ // This is the end-case where if we are at column 79 and about to print a wide character
+ // We should prevent this from happening because we will wrap inappropriately. We should
+ // not print this character until the next line.
+ //
+ if ((This->Mode->CursorColumn + Index + 1) > MaxColumn) {
+ Index++;
+ break;
+ }
+ }
+ }
+
+ Status = DrawUnicodeWeightAtCursorN (This, WString, Count);
+ if (EFI_ERROR (Status)) {
+ Warning = TRUE;
+ }
+ //
+ // At the end of line, output carriage return and line feed
+ //
+ WString += Count;
+ This->Mode->CursorColumn += (INT32) Index;
+ if (This->Mode->CursorColumn > (INT32) MaxColumn) {
+ This->Mode->CursorColumn -= 2;
+ This->OutputString (This, SpaceStr);
+ }
+
+ if (This->Mode->CursorColumn >= (INT32) MaxColumn) {
+ FlushCursor (This);
+ This->OutputString (This, mCrLfString);
+ FlushCursor (This);
+ }
+ }
+ }
+
+ This->Mode->Attribute = OriginAttribute;
+
+ FlushCursor (This);
+
+ if (Warning) {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+}
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ Implements SIMPLE_TEXT_OUTPUT.TestString().
+ If one of the characters in the *Wstring is neither valid valid Unicode
+ drawing characters, not ASCII code, then this function will return
+ EFI_UNSUPPORTED
+
+ @param This Protocol instance pointer.
+ @param WString 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
+GraphicsConsoleConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Count;
+
+ EFI_IMAGE_OUTPUT *Blt;
+
+ Blt = NULL;
+ Count = 0;
+
+ while (WString[Count] != 0) {
+ Status = mHiiFont->GetGlyph (
+ mHiiFont,
+ WString[Count],
+ NULL,
+ &Blt,
+ NULL
+ );
+ if (Blt != NULL) {
+ FreePool (Blt);
+ Blt = NULL;
+ }
+ Count++;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports
+
+ Implements SIMPLE_TEXT_OUTPUT.QueryMode().
+ It returnes information for an available text mode that the Graphics Console supports.
+ In this driver,we only support text mode 80x25, which is defined as mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = EFI_SUCCESS;
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+
+ *Columns = Private->ModeData[ModeNumber].Columns;
+ *Rows = Private->ModeData[ModeNumber].Rows;
+
+ if (*Columns <= 0 || *Rows <= 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetMode().
+ Set the Graphics Console to a specified mode. In this driver, we only support mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set because of
+ Graphics Console device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewLineBuffer;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+ UgaDraw = Private->UgaDraw;
+
+ //
+ // Make sure the requested mode number is supported
+ //
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ ModeData = &(Private->ModeData[ModeNumber]);
+
+ if (ModeData->Columns <= 0 && ModeData->Rows <= 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ //
+ // If the mode has been set at least one other time, then LineBuffer will not be NULL
+ //
+ if (Private->LineBuffer != NULL) {
+ //
+ // If the new mode is the same as the old mode, then just return EFI_SUCCESS
+ //
+ if ((INT32) ModeNumber == This->Mode->Mode) {
+ //
+ // Clear the current text window on the current graphics console
+ //
+ This->ClearScreen (This);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Otherwise, the size of the text console and/or the GOP/UGA mode will be changed,
+ // so erase the cursor, and free the LineBuffer for the current mode
+ //
+ FlushCursor (This);
+
+ FreePool (Private->LineBuffer);
+ }
+
+ //
+ // Attempt to allocate a line buffer for the requested mode number
+ //
+ NewLineBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->Columns * EFI_GLYPH_WIDTH * EFI_GLYPH_HEIGHT);
+
+ if (NewLineBuffer == NULL) {
+ //
+ // The new line buffer could not be allocated, so return an error.
+ // No changes to the state of the current console have been made, so the current console is still valid
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Assign the current line buffer to the newly allocated line buffer
+ //
+ Private->LineBuffer = NewLineBuffer;
+
+ if (GraphicsOutput != NULL) {
+ if (ModeData->GopModeNumber != GraphicsOutput->Mode->Mode) {
+ //
+ // Either no graphics mode is currently set, or it is set to the wrong resolution, so set the new graphics mode
+ //
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeData->GopModeNumber);
+ if (EFI_ERROR (Status)) {
+ //
+ // The mode set operation failed
+ //
+ goto Done;
+ }
+ } else {
+ //
+ // The current graphics mode is correct, so simply clear the entire display
+ //
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &mGraphicsEfiColors[0],
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+ }
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // Get the current UGA Draw mode information
+ //
+ Status = UgaDraw->GetMode (
+ UgaDraw,
+ &HorizontalResolution,
+ &VerticalResolution,
+ &ColorDepth,
+ &RefreshRate
+ );
+ if (EFI_ERROR (Status) || HorizontalResolution != ModeData->GopWidth || VerticalResolution != ModeData->GopHeight) {
+ //
+ // Either no graphics mode is currently set, or it is set to the wrong resolution, so set the new graphics mode
+ //
+ Status = UgaDraw->SetMode (
+ UgaDraw,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 32,
+ 60
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The mode set operation failed
+ //
+ goto Done;
+ }
+ } else {
+ //
+ // The current graphics mode is correct, so simply clear the entire display
+ //
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) (UINTN) &mGraphicsEfiColors[0],
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+ }
+ }
+
+ //
+ // The new mode is valid, so commit the mode change
+ //
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ //
+ // Move the text cursor to the upper left hand corner of the display and flush it
+ //
+ This->Mode->CursorColumn = 0;
+ This->Mode->CursorRow = 0;
+
+ FlushCursor (This);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetAttribute().
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground
+ color, and bits 4..6 are the background color.
+ All other bits are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to Graphics Console port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ EFI_TPL OldTpl;
+
+ if ((Attribute | 0x7F) != 0x7F) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((INT32) Attribute == This->Mode->Attribute) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ FlushCursor (This);
+
+ This->Mode->Attribute = (INT32) Attribute;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ Implements SIMPLE_TEXT_OUTPUT.ClearScreen().
+
+ @param This Protocol instance pointer.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+ UgaDraw = Private->UgaDraw;
+ ModeData = &(Private->ModeData[This->Mode->Mode]);
+
+ GetTextColors (This, &Foreground, &Background);
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) (UINTN) &Background,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ This->Mode->CursorColumn = 0;
+ This->Mode->CursorRow = 0;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition().
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @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
+GraphicsConsoleConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ ModeData = &(Private->ModeData[This->Mode->Mode]);
+
+ if ((Column >= ModeData->Columns) || (Row >= ModeData->Rows)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if ((This->Mode->CursorColumn == (INT32) Column) && (This->Mode->CursorRow == (INT32) Row)) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ FlushCursor (This);
+
+ This->Mode->CursorColumn = (INT32) Column;
+ This->Mode->CursorRow = (INT32) Row;
+
+ FlushCursor (This);
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Makes the cursor visible or invisible.
+
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible, If FALSE,
+ the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ FlushCursor (This);
+
+ This->Mode->CursorVisible = Visible;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets Graphics Console devcie's foreground color and background color.
+
+ @param This Protocol instance pointer.
+ @param Foreground Returned text foreground color.
+ @param Background Returned text background color.
+
+ @retval EFI_SUCCESS It returned always.
+
+**/
+EFI_STATUS
+GetTextColors (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Foreground,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background
+ )
+{
+ INTN Attribute;
+
+ Attribute = This->Mode->Attribute & 0x7F;
+
+ *Foreground = mGraphicsEfiColors[Attribute & 0x0f];
+ *Background = mGraphicsEfiColors[Attribute >> 4];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Draw Unicode string on the Graphics Console device's screen.
+
+ @param This Protocol instance pointer.
+ @param UnicodeWeight One Unicode string to be displayed.
+ @param Count The count of Unicode string.
+
+ @retval EFI_OUT_OF_RESOURCES If no memory resource to use.
+ @retval EFI_UNSUPPORTED If no Graphics Output protocol and UGA Draw
+ protocol exist.
+ @retval EFI_SUCCESS Drawing Unicode string implemented successfully.
+
+**/
+EFI_STATUS
+DrawUnicodeWeightAtCursorN (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *UnicodeWeight,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_IMAGE_OUTPUT *Blt;
+ EFI_STRING String;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_HII_ROW_INFO *RowInfoArray;
+ UINTN RowInfoArraySize;
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ Blt = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Blt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Blt->Width = (UINT16) (Private->ModeData[This->Mode->Mode].GopWidth);
+ Blt->Height = (UINT16) (Private->ModeData[This->Mode->Mode].GopHeight);
+
+ String = AllocateCopyPool ((Count + 1) * sizeof (CHAR16), UnicodeWeight);
+ if (String == NULL) {
+ FreePool (Blt);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set the end character
+ //
+ *(String + Count) = L'\0';
+
+ FontInfo = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (sizeof (EFI_FONT_DISPLAY_INFO));
+ if (FontInfo == NULL) {
+ FreePool (Blt);
+ FreePool (String);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get current foreground and background colors.
+ //
+ GetTextColors (This, &FontInfo->ForegroundColor, &FontInfo->BackgroundColor);
+
+ if (Private->GraphicsOutput != NULL) {
+ //
+ // If Graphics Output protocol exists, using HII Font protocol to draw.
+ //
+ Blt->Image.Screen = Private->GraphicsOutput;
+
+ Status = mHiiFont->StringToImage (
+ mHiiFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_DIRECT_TO_SCREEN | EFI_HII_IGNORE_LINE_BREAK,
+ String,
+ FontInfo,
+ &Blt,
+ This->Mode->CursorColumn * EFI_GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ This->Mode->CursorRow * EFI_GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ //
+ // If Graphics Output protocol cannot be found and PcdUgaConsumeSupport enabled,
+ // using UGA Draw protocol to draw.
+ //
+ ASSERT (Private->UgaDraw!= NULL);
+
+ UgaDraw = Private->UgaDraw;
+
+ Blt->Image.Bitmap = AllocateZeroPool (Blt->Width * Blt->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Blt->Image.Bitmap == NULL) {
+ FreePool (Blt);
+ FreePool (String);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RowInfoArray = NULL;
+ //
+ // StringToImage only support blt'ing image to device using GOP protocol. If GOP is not supported in this platform,
+ // we ask StringToImage to print the string to blt buffer, then blt to device using UgaDraw.
+ //
+ Status = mHiiFont->StringToImage (
+ mHiiFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_IGNORE_LINE_BREAK,
+ String,
+ FontInfo,
+ &Blt,
+ This->Mode->CursorColumn * EFI_GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ This->Mode->CursorRow * EFI_GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ &RowInfoArray,
+ &RowInfoArraySize,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Line breaks are handled by caller of DrawUnicodeWeightAtCursorN, so the updated parameter RowInfoArraySize by StringToImage will
+ // always be 1 or 0 (if there is no valid Unicode Char can be printed). ASSERT here to make sure.
+ //
+ ASSERT (RowInfoArraySize <= 1);
+
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) Blt->Image.Bitmap,
+ EfiUgaBltBufferToVideo,
+ This->Mode->CursorColumn * EFI_GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ (This->Mode->CursorRow) * EFI_GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ This->Mode->CursorColumn * EFI_GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ (This->Mode->CursorRow) * EFI_GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ RowInfoArray[0].LineWidth,
+ RowInfoArray[0].LineHeight,
+ Blt->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ }
+
+ FreePool (RowInfoArray);
+ FreePool (Blt->Image.Bitmap);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+ if (String != NULL) {
+ FreePool (String);
+ }
+ if (FontInfo != NULL) {
+ FreePool (FontInfo);
+ }
+ return Status;
+}
+
+/**
+ Flush the cursor on the screen.
+
+ If CursorVisible is FALSE, nothing to do and return directly.
+ If CursorVisible is TRUE,
+ i) If the cursor shows on screen, it will be erased.
+ ii) If the cursor does not show on screen, it will be shown.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The cursor is erased successfully.
+
+**/
+EFI_STATUS
+FlushCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *CurrentMode;
+ INTN GlyphX;
+ INTN GlyphY;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltChar[EFI_GLYPH_HEIGHT][EFI_GLYPH_WIDTH];
+ UINTN PosX;
+ UINTN PosY;
+
+ CurrentMode = This->Mode;
+
+ if (!CurrentMode->CursorVisible) {
+ return EFI_SUCCESS;
+ }
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+ UgaDraw = Private->UgaDraw;
+
+ //
+ // In this driver, only narrow character was supported.
+ //
+ //
+ // Blt a character to the screen
+ //
+ GlyphX = (CurrentMode->CursorColumn * EFI_GLYPH_WIDTH) + Private->ModeData[CurrentMode->Mode].DeltaX;
+ GlyphY = (CurrentMode->CursorRow * EFI_GLYPH_HEIGHT) + Private->ModeData[CurrentMode->Mode].DeltaY;
+ if (GraphicsOutput != NULL) {
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltChar,
+ EfiBltVideoToBltBuffer,
+ GlyphX,
+ GlyphY,
+ 0,
+ 0,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) (UINTN) BltChar,
+ EfiUgaVideoToBltBuffer,
+ GlyphX,
+ GlyphY,
+ 0,
+ 0,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+
+ GetTextColors (This, &Foreground.Pixel, &Background.Pixel);
+
+ //
+ // Convert Monochrome bitmap of the Glyph to BltBuffer structure
+ //
+ for (PosY = 0; PosY < EFI_GLYPH_HEIGHT; PosY++) {
+ for (PosX = 0; PosX < EFI_GLYPH_WIDTH; PosX++) {
+ if ((mCursorGlyph.GlyphCol1[PosY] & (BIT0 << PosX)) != 0) {
+ BltChar[PosY][EFI_GLYPH_WIDTH - PosX - 1].Raw ^= Foreground.Raw;
+ }
+ }
+ }
+
+ if (GraphicsOutput != NULL) {
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltChar,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ GlyphX,
+ GlyphY,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) (UINTN) BltChar,
+ EfiUgaBltBufferToVideo,
+ 0,
+ 0,
+ GlyphX,
+ GlyphY,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ HII Database Protocol notification event handler.
+
+ Register font package when HII Database Protocol has been installed.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+RegisterFontPackage (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimplifiedFont;
+ UINT32 PackageLength;
+ UINT8 *Package;
+ UINT8 *Location;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+
+ //
+ // Locate HII Database Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Add 4 bytes to the header for entire length for HiiAddPackages use only.
+ //
+ // +--------------------------------+ <-- Package
+ // | |
+ // | PackageLength(4 bytes) |
+ // | |
+ // |--------------------------------| <-- SimplifiedFont
+ // | |
+ // |EFI_HII_SIMPLE_FONT_PACKAGE_HDR |
+ // | |
+ // |--------------------------------| <-- Location
+ // | |
+ // | gUsStdNarrowGlyphData |
+ // | |
+ // +--------------------------------+
+
+ PackageLength = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + mNarrowFontSize + 4;
+ Package = AllocateZeroPool (PackageLength);
+ ASSERT (Package != NULL);
+
+ WriteUnaligned32((UINT32 *) Package,PackageLength);
+ SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR *) (Package + 4);
+ SimplifiedFont->Header.Length = (UINT32) (PackageLength - 4);
+ SimplifiedFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
+ SimplifiedFont->NumberOfNarrowGlyphs = (UINT16) (mNarrowFontSize / sizeof (EFI_NARROW_GLYPH));
+
+ Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);
+ CopyMem (Location, gUsStdNarrowGlyphData, mNarrowFontSize);
+
+ //
+ // Add this simplified font package to a package list then install it.
+ //
+ mHiiHandle = HiiAddPackages (
+ &mFontPackageListGuid,
+ NULL,
+ Package,
+ NULL
+ );
+ ASSERT (mHiiHandle != NULL);
+ FreePool (Package);
+}
+
+/**
+ The user Entry Point for module GraphicsConsole. 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.
+ @return other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeGraphicsConsole (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Register notify function on HII Database Protocol to add font package.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiHiiDatabaseProtocolGuid,
+ TPL_CALLBACK,
+ RegisterFontPackage,
+ NULL,
+ &mHiiRegistration
+ );
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gGraphicsConsoleDriverBinding,
+ ImageHandle,
+ &gGraphicsConsoleComponentName,
+ &gGraphicsConsoleComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h
new file mode 100644
index 000000000..28d47ac7c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h
@@ -0,0 +1,594 @@
+/** @file
+ Header file for GraphicsConsole driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GRAPHICS_CONSOLE_H_
+#define _GRAPHICS_CONSOLE_H_
+
+#include <Uefi.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.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/HiiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiDatabase.h>
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gGraphicsConsoleComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding;
+extern EFI_NARROW_GLYPH gUsStdNarrowGlyphData[];
+
+extern UINT32 mNarrowFontSize;
+
+typedef union {
+ EFI_NARROW_GLYPH NarrowGlyph;
+ EFI_WIDE_GLYPH WideGlyph;
+} GLYPH_UNION;
+
+//
+// Device Structure
+//
+#define GRAPHICS_CONSOLE_DEV_SIGNATURE SIGNATURE_32 ('g', 's', 't', 'o')
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+ INTN DeltaX;
+ INTN DeltaY;
+ UINT32 GopWidth;
+ UINT32 GopHeight;
+ UINT32 GopModeNumber;
+} GRAPHICS_CONSOLE_MODE_DATA;
+
+typedef struct {
+ UINTN Signature;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LineBuffer;
+} GRAPHICS_CONSOLE_DEV;
+
+#define GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS(a) \
+ CR (a, GRAPHICS_CONSOLE_DEV, SimpleTextOutput, GRAPHICS_CONSOLE_DEV_SIGNATURE)
+
+
+//
+// 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
+GraphicsConsoleComponentNameGetDriverName (
+ 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
+GraphicsConsoleComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Reset the text output device hardware and optionally run diagnostics.
+
+ Implements SIMPLE_TEXT_OUTPUT.Reset().
+ If ExtendeVerification is TRUE, then perform dependent Graphics Console
+ device reset, and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Protocol instance pointer.
+ @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
+GraphicsConsoleConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Write a Unicode string to the output device.
+
+ Implements SIMPLE_TEXT_OUTPUT.OutputString().
+ The Unicode string will be converted to Glyphs and will be
+ sent to the Graphics Console.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be displayed
+ on the output device(s). All output devices must
+ also support the Unicode drawing defined in this file.
+
+ @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
+GraphicsConsoleConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ Implements SIMPLE_TEXT_OUTPUT.TestString().
+ If one of the characters in the *Wstring is neither valid valid Unicode
+ drawing characters, not ASCII code, then this function will return
+ EFI_UNSUPPORTED
+
+ @param This Protocol instance pointer.
+ @param WString 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
+GraphicsConsoleConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports
+
+ Implements SIMPLE_TEXT_OUTPUT.QueryMode().
+ It returnes information for an available text mode that the Graphics Console supports.
+ In this driver,we only support text mode 80x25, which is defined as mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutQueryMode (
+ 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.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetMode().
+ Set the Graphics Console to a specified mode. In this driver, we only support mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set because of
+ Graphics Console device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetAttribute().
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground
+ color, and bits 4..6 are the background color.
+ All other bits are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to Graphics Console port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ Implements SIMPLE_TEXT_OUTPUT.ClearScreen().
+
+ @param This Protocol instance pointer.
+
+ @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.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition().
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @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
+GraphicsConsoleConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+
+/**
+ Makes the cursor visible or invisible.
+
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible, If FALSE,
+ the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Test to see if Graphics Console could be supported on the Controller.
+
+ Graphics Console could be supported if Graphics Output Protocol or UGA Draw
+ Protocol exists on the Controller. (UGA Draw Protocol could be skipped
+ if PcdUgaConsumeSupport is set to FALSE.)
+
+ @param This Protocol instance pointer.
+ @param Controller 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 other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Start this driver on Controller by opening Graphics Output protocol or
+ UGA Draw protocol, and installing Simple Text Out protocol on Controller.
+ (UGA Draw protocol could be skipped if PcdUgaConsumeSupport is set to FALSE.)
+
+ @param This Protocol instance pointer.
+ @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 This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on Controller by removing Simple Text Out protocol
+ and closing the Graphics Output Protocol or UGA Draw protocol on Controller.
+ (UGA Draw protocol could be skipped if PcdUgaConsumeSupport is set to FALSE.)
+
+
+ @param This Protocol instance pointer.
+ @param Controller 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 Controller.
+ @retval EFI_NOT_STARTED Simple Text Out protocol could not be found the
+ Controller.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+
+/**
+ Locate HII Database protocol and HII Font protocol.
+
+ @retval EFI_SUCCESS HII Database protocol and HII Font protocol
+ are located successfully.
+ @return other Failed to locate HII Database protocol or
+ HII Font protocol.
+
+**/
+EFI_STATUS
+EfiLocateHiiProtocol (
+ VOID
+ );
+
+
+/**
+ Gets Graphics Console devcie's foreground color and background color.
+
+ @param This Protocol instance pointer.
+ @param Foreground Returned text foreground color.
+ @param Background Returned text background color.
+
+ @retval EFI_SUCCESS It returned always.
+
+**/
+EFI_STATUS
+GetTextColors (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Foreground,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background
+ );
+
+/**
+ Draw Unicode string on the Graphics Console device's screen.
+
+ @param This Protocol instance pointer.
+ @param UnicodeWeight One Unicode string to be displayed.
+ @param Count The count of Unicode string.
+
+ @retval EFI_OUT_OF_RESOURCES If no memory resource to use.
+ @retval EFI_UNSUPPORTED If no Graphics Output protocol and UGA Draw
+ protocol exist.
+ @retval EFI_SUCCESS Drawing Unicode string implemented successfully.
+
+**/
+EFI_STATUS
+DrawUnicodeWeightAtCursorN (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *UnicodeWeight,
+ IN UINTN Count
+ );
+
+/**
+ Flush the cursor on the screen.
+
+ If CursorVisible is FALSE, nothing to do and return directly.
+ If CursorVisible is TRUE,
+ i) If the cursor shows on screen, it will be erased.
+ ii) If the cursor does not show on screen, it will be shown.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The cursor is erased successfully.
+
+**/
+EFI_STATUS
+FlushCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Check if the current specific mode supported the user defined resolution
+ for the Graphics Console device based on Graphics Output Protocol.
+
+ If yes, set the graphic device's current mode to this specific mode.
+
+ @param GraphicsOutput Graphics Output Protocol instance pointer.
+ @param HorizontalResolution User defined horizontal resolution
+ @param VerticalResolution User defined vertical resolution.
+ @param CurrentModeNumber Current specific mode to be check.
+
+ @retval EFI_SUCCESS The mode is supported.
+ @retval EFI_UNSUPPORTED The specific mode is out of range of graphics
+ device supported.
+ @retval other The specific mode does not support user defined
+ resolution or failed to set the current mode to the
+ specific mode on graphics device.
+
+**/
+EFI_STATUS
+CheckModeSupported (
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ OUT UINT32 *CurrentModeNumber
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
new file mode 100644
index 000000000..bcfd306ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
@@ -0,0 +1,72 @@
+## @file
+# Console support on graphic devices.
+#
+# This driver will install Simple Text Output protocol by consuming Graphices Output
+# protocol or UGA Draw protocol on graphic devices.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GraphicsConsoleDxe
+ MODULE_UNI_FILE = GraphicsConsoleDxe.uni
+ FILE_GUID = CCCB0C28-4B24-11d5-9A5A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeGraphicsConsole
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gGraphicsConsoleDriverBinding
+# COMPONENT_NAME = gGraphicsConsoleComponentName
+# COMPONENT_NAME2 = gGraphicsConsoleComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ LaffStd.c
+ GraphicsConsole.c
+ GraphicsConsole.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ HiiLib
+ PcdLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiSimpleTextOutProtocolGuid ## BY_START
+ gEfiGraphicsOutputProtocolGuid ## TO_START
+ gEfiUgaDrawProtocolGuid ## TO_START
+ gEfiHiiFontProtocolGuid ## TO_START
+ ## TO_START
+ ## NOTIFY
+ gEfiHiiDatabaseProtocolGuid
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ GraphicsConsoleDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.uni b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.uni
new file mode 100644
index 000000000..aec5d57f9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Console support on graphic devices.
+//
+// This driver will install Simple Text Output protocol by consuming Graphices Output
+// protocol or UGA Draw protocol on graphic devices.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Console support on graphic devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver will install SimpleTextOutputProtocol by consuming GraphicesOutput\n"
+ "Protocol or UgaDrawProtocol on graphics devices."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni
new file mode 100644
index 000000000..4b97b6938
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// GraphicsConsoleDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Graphics Console DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/LaffStd.c b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/LaffStd.c
new file mode 100644
index 000000000..70715527a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/LaffStd.c
@@ -0,0 +1,271 @@
+/** @file
+ Narrow font Data definition for GraphicsConsole driver.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GraphicsConsole.h"
+
+
+
+EFI_NARROW_GLYPH gUsStdNarrowGlyphData[] = {
+ //
+ // Unicode glyphs from 0x20 to 0x7e are the same as ASCII characters 0x20 to 0x7e
+ //
+ { 0x0020, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0021, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x0022, 0x00, {0x00,0x00,0x00,0x6C,0x6C,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0023, 0x00, {0x00,0x00,0x00,0x00,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00}},
+ { 0x0024, 0x00, {0x00,0x00,0x18,0x18,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00}},
+ { 0x0025, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x0C,0x0C,0x18,0x18,0x30,0x30,0x60,0x60,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x0026, 0x00, {0x00,0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x76,0xDC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x0027, 0x00, {0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0028, 0x00, {0x00,0x00,0x00,0x06,0x0C,0x0C,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x0C,0x06,0x00,0x00,0x00,0x00}},
+ { 0x0029, 0x00, {0x00,0x00,0x00,0xC0,0x60,0x60,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0x60,0xC0,0x00,0x00,0x00,0x00}},
+ { 0x002a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x38,0xFE,0x38,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00}},
+ { 0x002d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002f, 0x00, {0x00,0x00,0x00,0x06,0x06,0x0C,0x0C,0x18,0x18,0x30,0x30,0x60,0x60,0xC0,0xC0,0x00,0x00,0x00,0x00}},
+ { 0x0030, 0x00, {0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00}},
+ { 0x0031, 0x00, {0x00,0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00}},
+ { 0x0032, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0x06,0x06,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC2,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x0033, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0x06,0x06,0x06,0x3C,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0034, 0x00, {0x00,0x00,0x00,0x1C,0x1C,0x3C,0x3C,0x6C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}},
+ { 0x0035, 0x00, {0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0036, 0x00, {0x00,0x00,0x00,0x3C,0x60,0xC0,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0037, 0x00, {0x00,0x00,0x00,0xFE,0xC6,0x06,0x06,0x06,0x0C,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x0038, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0039, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00}},
+ { 0x003a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00}},
+ { 0x003c, 0x00, {0x00,0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}},
+ { 0x003d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003e, 0x00, {0x00,0x00,0x00,0x00,0xC0,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00,0x00,0x00,0x00}},
+ { 0x003f, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x0040, 0x00, {0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0xC0,0x7E,0x00,0x00,0x00,0x00}},
+
+ { 0x0041, 0x00, {0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+
+ { 0x0042, 0x00, {0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00}},
+ { 0x0043, 0x00, {0x00,0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x0044, 0x00, {0x00,0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00}},
+ { 0x0045, 0x00, {0x00,0x00,0x00,0xFE,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x0046, 0x00, {0x00,0x00,0x00,0xFE,0x66,0x62,0x60,0x64,0x7C,0x64,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}},
+ { 0x0047, 0x00, {0x00,0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xDE,0xC6,0xC6,0xC6,0x66,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x0048, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x0049, 0x00, {0x00,0x00,0x00,0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xFC,0x00,0x00,0x00,0x00}},
+ { 0x004a, 0x00, {0x00,0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00}},
+ { 0x004b, 0x00, {0x00,0x00,0x00,0xE6,0x66,0x6C,0x6C,0x78,0x70,0x78,0x6C,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}},
+ { 0x004c, 0x00, {0x00,0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x004d, 0x00, {0x00,0x00,0x00,0xC6,0xEE,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x004e, 0x00, {0x00,0x00,0x00,0xC6,0xE6,0xF6,0xF6,0xF6,0xDE,0xCE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x004f, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0050, 0x00, {0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}},
+ { 0x0051, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0x7C,0x1C,0x0E,0x00,0x00}},
+ { 0x0052, 0x00, {0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x7C,0x78,0x6C,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}},
+ { 0x0053, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x60,0x38,0x0C,0x06,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0054, 0x00, {0x00,0x00,0x00,0xFC,0xFC,0xB4,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}},
+ { 0x0055, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0056, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00}},
+ { 0x0057, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00}},
+ { 0x0058, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0xC6,0x6C,0x6C,0x38,0x6C,0x6C,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x0059, 0x00, {0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}},
+ { 0x005a, 0x00, {0x00,0x00,0x00,0xFE,0xC6,0x86,0x0C,0x0C,0x18,0x30,0x60,0xC0,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x005b, 0x00, {0x00,0x00,0x00,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1E,0x00,0x00,0x00,0x00}},
+ { 0x005c, 0x00, {0x00,0x00,0x00,0xC0,0xC0,0x60,0x60,0x30,0x30,0x18,0x18,0x0C,0x0C,0x06,0x06,0x00,0x00,0x00,0x00}},
+ { 0x005d, 0x00, {0x00,0x00,0x00,0xF0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0x00,0x00,0x00,0x00}},
+ { 0x005e, 0x00, {0x00,0x00,0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x0060, 0x00, {0x00,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0061, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x0062, 0x00, {0x00,0x00,0x00,0xE0,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0063, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0064, 0x00, {0x00,0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0xCC,0x7E,0x00,0x00,0x00,0x00}},
+ { 0x0065, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0066, 0x00, {0x00,0x00,0x00,0x1E,0x33,0x30,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}},
+ { 0x0067, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00}},
+ { 0x0068, 0x00, {0x00,0x00,0x00,0xE0,0x60,0x60,0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}},
+ { 0x0069, 0x00, {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x006a, 0x00, {0x00,0x00,0x00,0x0C,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}},
+ { 0x006b, 0x00, {0x00,0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x70,0x78,0x6C,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00}},
+ { 0x006c, 0x00, {0x00,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x006d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEC,0xEE,0xFE,0xD6,0xD6,0xD6,0xD6,0xD6,0x00,0x00,0x00,0x00}},
+ { 0x006e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00}},
+ { 0x006f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0070, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00}},
+ { 0x0071, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00}},
+ { 0x0072, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x60,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}},
+ { 0x0073, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0x7C,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x0074, 0x00, {0x00,0x00,0x00,0x10,0x30,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00}},
+ { 0x0075, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x0076, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0x00}},
+ { 0x0077, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00}},
+ { 0x0078, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x6C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x0079, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00}},
+ { 0x007a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x86,0x0C,0x18,0x30,0x60,0xC0,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x007b, 0x00, {0x00,0x00,0x00,0x0E,0x18,0x18,0x18,0x18,0x30,0x18,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}},
+ { 0x007c, 0x00, {0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x007d, 0x00, {0x00,0x00,0x00,0xE0,0x30,0x30,0x30,0x30,0x18,0x30,0x30,0x30,0x30,0x30,0xE0,0x00,0x00,0x00,0x00}},
+ { 0x007e, 0x00, {0x00,0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+
+ { 0x00a0, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a1, 0x00, {0x00,0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00}},
+ { 0x00a2, 0x00, {0x00,0x00,0x00,0x00,0x18,0x18,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x00a3, 0x00, {0x00,0x00,0x00,0x38,0x6C,0x64,0x60,0x60,0xF0,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00}},
+ { 0x00a4, 0x00, {0x00,0x00,0x18,0x00,0x00,0x00,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a5, 0x00, {0x00,0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x00a6, 0x00, {0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}},
+ { 0x00a7, 0x00, {0x00,0x00,0x18,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00a8, 0x00, {0x00,0x00,0x00,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a9, 0x00, {0x00,0x00,0x00,0x00,0x7C,0x82,0x9A,0xA2,0xA2,0xA2,0x9A,0x82,0x7C,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00aa, 0x00, {0x00,0x00,0x00,0x00,0x3C,0x6C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ab, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ac, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ad, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ae, 0x00, {0x00,0x00,0x00,0x00,0x7C,0x82,0xB2,0xAA,0xAA,0xB2,0xAA,0xAA,0x82,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00af, 0x00, {0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b0, 0x00, {0x00,0x00,0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b1, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b2, 0x00, {0x00,0x00,0x00,0x3C,0x66,0x0C,0x18,0x32,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b3, 0x00, {0x00,0x00,0x00,0x7C,0x06,0x3C,0x06,0x06,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b4, 0x00, {0x00,0x00,0x00,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b5, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00}},
+ { 0x00b6, 0x00, {0x00,0x00,0x00,0x7F,0xDB,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00}},
+ { 0x00b7, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b8, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0x78,0x00,0x00,0x00}},
+ { 0x00b9, 0x00, {0x00,0x00,0x00,0x18,0x38,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ba, 0x00, {0x00,0x00,0x00,0x00,0x38,0x6C,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00bb, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00bc, 0x00, {0x00,0x00,0x00,0x60,0xE0,0x62,0x66,0x6C,0x18,0x30,0x66,0xCE,0x9A,0x3F,0x06,0x06,0x00,0x00,0x00}},
+ { 0x00bd, 0x00, {0x00,0x00,0x00,0x60,0xE0,0x62,0x66,0x6C,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00,0x00}},
+ { 0x00be, 0x00, {0x00,0x00,0x00,0xE0,0x30,0x62,0x36,0xEC,0x18,0x30,0x66,0xCE,0x9A,0x3F,0x06,0x06,0x00,0x00,0x00}},
+ { 0x00bf, 0x00, {0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00c0, 0x00, {0x60,0x30,0x18,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c1, 0x00, {0x18,0x30,0x60,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c2, 0x00, {0x10,0x38,0x6C,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c3, 0x00, {0x76,0xDC,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c4, 0x00, {0xCC,0xCC,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c5, 0x00, {0x38,0x6C,0x38,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00c6, 0x00, {0x00,0x00,0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00}},
+ { 0x00c7, 0x00, {0x00,0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x18,0x70,0x00,0x00}},
+ { 0x00c8, 0x00, {0x60,0x30,0x18,0x00,0xFE,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x00c9, 0x00, {0x18,0x30,0x60,0x00,0xFE,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x00ca, 0x00, {0x10,0x38,0x6C,0x00,0xFE,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x00cb, 0x00, {0xCC,0xCC,0x00,0x00,0xFE,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}},
+ { 0x00cc, 0x00, {0x60,0x30,0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00cd, 0x00, {0x18,0x30,0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00ce, 0x00, {0x10,0x38,0x6C,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00cf, 0x00, {0xCC,0xCC,0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00d0, 0x00, {0x00,0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0xF6,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00}},
+ { 0x00d1, 0x00, {0x76,0xDC,0x00,0x00,0xC6,0xE6,0xE6,0xF6,0xF6,0xDE,0xDE,0xCE,0xCE,0xC6,0xC6,0x00,0x00,0x00,0x00}},
+ { 0x00d2, 0x00, {0x60,0x30,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00d3, 0x00, {0x18,0x30,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00d4, 0x00, {0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00d5, 0x00, {0x76,0xDC,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00d6, 0x00, {0xCC,0xCC,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00d7, 0x00, {0x10,0x28,0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x6C,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00d8, 0x00, {0x00,0x00,0x00,0x7C,0xCE,0xCE,0xDE,0xD6,0xD6,0xD6,0xD6,0xF6,0xE6,0xE6,0x7C,0x40,0x00,0x00,0x00}},
+ { 0x00d9, 0x00, {0x60,0x30,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00da, 0x00, {0x18,0x30,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00db, 0x00, {0x10,0x38,0x6C,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00dc, 0x00, {0xCC,0xCC,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00dd, 0x00, {0x18,0x30,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00de, 0x00, {0x00,0x00,0x10,0x00,0xF0,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x00,0x00}},
+ { 0x00df, 0x00, {0x00,0x00,0x00,0x78,0xCC,0xCC,0xCC,0xCC,0xD8,0xCC,0xC6,0xC6,0xC6,0xC6,0xCC,0x00,0x00,0x00,0x00}},
+ { 0x00e0, 0x00, {0x00,0x30,0x30,0x60,0x30,0x18,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e1, 0x00, {0x00,0x00,0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e2, 0x00, {0x00,0x00,0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e3, 0x00, {0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e4, 0x00, {0x00,0x00,0x00,0xCC,0xCC,0x00,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e5, 0x00, {0x00,0x00,0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00e6, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEC,0x36,0x36,0x7E,0xD8,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00}},
+ { 0x00e7, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC0,0xC6,0x7C,0x18,0x70,0x00,0x00}},
+ { 0x00e8, 0x00, {0x00,0x00,0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00e9, 0x00, {0x00,0x00,0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00ea, 0x00, {0x00,0x00,0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00eb, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00ec, 0x00, {0x00,0x00,0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00ed, 0x00, {0x00,0x00,0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00ee, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00ef, 0x00, {0x00,0x00,0x00,0x66,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00f0, 0x00, {0x00,0x00,0x00,0x34,0x18,0x2C,0x0C,0x06,0x3E,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00f1, 0x00, {0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00}},
+ { 0x00f2, 0x00, {0x00,0x00,0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f3, 0x00, {0x00,0x00,0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f4, 0x00, {0x00,0x00,0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f5, 0x00, {0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f6, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f7, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x7E,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f8, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xCE,0xDE,0xD6,0xF6,0xE6,0xC6,0x7C,0x00,0x00,0x00,0x00}},
+ { 0x00f9, 0x00, {0x00,0x00,0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00fa, 0x00, {0x00,0x00,0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00fb, 0x00, {0x00,0x00,0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00fc, 0x00, {0x00,0x00,0x00,0xCC,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}},
+ { 0x00fd, 0x00, {0x00,0x00,0x00,0x0C,0x18,0x30,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00}},
+ { 0x00fe, 0x00, {0x00,0x00,0x00,0xE0,0x60,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00}},
+ { 0x00ff, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00}},
+
+ { (CHAR16)BOXDRAW_HORIZONTAL, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_VERTICAL, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_RIGHT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_LEFT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_UP_RIGHT, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_UP_LEFT, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_VERTICAL_RIGHT, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_VERTICAL_LEFT, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_HORIZONTAL, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_UP_HORIZONTAL, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_VERTICAL_HORIZONTAL, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOUBLE_HORIZONTAL, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_DOUBLE_VERTICAL, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOWN_RIGHT_DOUBLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_DOUBLE_RIGHT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_DOWN_RIGHT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOWN_LEFT_DOUBLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_DOUBLE_LEFT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_DOWN_LEFT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_UP_RIGHT_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_UP_DOUBLE_RIGHT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_DOUBLE_UP_RIGHT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_UP_LEFT_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_UP_DOUBLE_LEFT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_DOUBLE_UP_LEFT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_VERTICAL_LEFT_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_VERTICAL_DOUBLE_LEFT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_VERTICAL_LEFT, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_UP_HORIZONTAL_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_UP_DOUBLE_HORIZONTAL, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_DOUBLE_UP_HORIZONTAL, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { (CHAR16)BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { (CHAR16)BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+
+ { (CHAR16)BLOCKELEMENT_FULL_BLOCK, 0x00, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
+ { (CHAR16)BLOCKELEMENT_LIGHT_SHADE, 0x00, {0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22}},
+
+ { (CHAR16)GEOMETRICSHAPE_RIGHT_TRIANGLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)GEOMETRICSHAPE_LEFT_TRIANGLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)GEOMETRICSHAPE_UP_TRIANGLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)GEOMETRICSHAPE_DOWN_TRIANGLE, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00}},
+
+ { (CHAR16)ARROW_UP, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)ARROW_DOWN, 0x00, {0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)ARROW_LEFT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x20,0x60,0x60,0xFE,0xFE,0x60,0x60,0x20,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { (CHAR16)ARROW_RIGHT, 0x00, {0x00,0x00,0x00,0x00,0x00,0x08,0x0C,0x0C,0xFE,0xFE,0x0C,0x0C,0x08,0x00,0x00,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}} //EOL
+};
+
+// Get available Unicode glyphs narrow fonts(8*19 pixels) size.
+UINT32 mNarrowFontSize = sizeof (gUsStdNarrowGlyphData);
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/ComponentName.c
new file mode 100644
index 000000000..7b7f5683a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/ComponentName.c
@@ -0,0 +1,184 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for the generic GOP driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include <PiDxe.h>
+#include <Library/UefiLib.h>
+
+extern EFI_COMPONENT_NAME_PROTOCOL mGraphicsOutputComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL mGraphicsOutputComponentName2;
+
+//
+// Driver name table for GraphicsOutput module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mGraphicsOutputDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Generic Graphics Output 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
+GraphicsOutputComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mGraphicsOutputDriverNameTable,
+ DriverName,
+ (BOOLEAN) (This == &mGraphicsOutputComponentName)
+ );
+}
+
+/**
+ 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
+GraphicsOutputComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mGraphicsOutputComponentName = {
+ GraphicsOutputComponentNameGetDriverName,
+ GraphicsOutputComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mGraphicsOutputComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GraphicsOutputComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GraphicsOutputComponentNameGetControllerName,
+ "en"
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.c b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.c
new file mode 100644
index 000000000..99a76aa55
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.c
@@ -0,0 +1,729 @@
+/** @file
+ Implementation for a generic GOP driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "GraphicsOutput.h"
+CONST ACPI_ADR_DEVICE_PATH mGraphicsOutputAdrNode = {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_ADR_DP,
+ { sizeof (ACPI_ADR_DEVICE_PATH), 0 },
+ },
+ ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0)
+};
+
+EFI_PEI_GRAPHICS_DEVICE_INFO_HOB mDefaultGraphicsDeviceInfo = {
+ MAX_UINT16, MAX_UINT16, MAX_UINT16, MAX_UINT16, MAX_UINT8, MAX_UINT8
+};
+
+//
+// The driver should only start on one graphics controller.
+// So a global flag is used to remember that the driver is already started.
+//
+BOOLEAN mDriverStarted = FALSE;
+
+/**
+ Returns information for an available graphics mode that the graphics device
+ and the set of active video output devices supports.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info buffer.
+ @param Info A pointer to callee allocated buffer that returns information about ModeNumber.
+
+ @retval EFI_SUCCESS Valid mode information was returned.
+ @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the video mode.
+ @retval EFI_INVALID_PARAMETER ModeNumber is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *SizeOfInfo = This->Mode->SizeOfInfo;
+ *Info = AllocateCopyPool (*SizeOfInfo, This->Mode->Info);
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the video device into the specified mode and clears the visible portions of
+ the output display to black.
+
+ @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
+ @param ModeNumber Abstraction that defines the current video mode.
+
+ @retval EFI_SUCCESS The graphics mode specified by ModeNumber was selected.
+ @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
+GraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber
+)
+{
+ RETURN_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;
+ GRAPHICS_OUTPUT_PRIVATE_DATA *Private;
+
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (This);
+
+ Black.Blue = 0;
+ Black.Green = 0;
+ Black.Red = 0;
+ Black.Reserved = 0;
+
+ Status = FrameBufferBlt (
+ Private->FrameBufferBltLibConfigure,
+ &Black,
+ EfiBltVideoFill,
+ 0, 0,
+ 0, 0,
+ This->Mode->Info->HorizontalResolution,
+ This->Mode->Info->VerticalResolution,
+ 0
+ );
+ return RETURN_ERROR (Status) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+}
+
+/**
+ Blt a rectangle of pixels on the graphics screen. Blt stands for BLock Transfer.
+
+ @param This Protocol instance pointer.
+ @param BltBuffer The data to transfer to the graphics screen.
+ Size is at least Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL).
+ @param BltOperation The operation to perform when copying BltBuffer on to the graphics screen.
+ @param SourceX The X coordinate of source for the BltOperation.
+ @param SourceY The Y coordinate of source for the BltOperation.
+ @param DestinationX The X coordinate of destination for the BltOperation.
+ @param DestinationY The Y coordinate of destination for the 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 or the EfiBltVideoToVideo operation.
+ If a Delta of zero is used, the entire BltBuffer is being operated on.
+ If a subrectangle of the BltBuffer is being used then Delta
+ represents the number of bytes in a row of the BltBuffer.
+
+ @retval EFI_SUCCESS BltBuffer was drawn to the graphics screen.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsOutputBlt (
+ 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 OPTIONAL
+ )
+{
+ RETURN_STATUS Status;
+ EFI_TPL Tpl;
+ GRAPHICS_OUTPUT_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (This);
+ //
+ // We have to raise to TPL_NOTIFY, so we make an atomic write to the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = FrameBufferBlt (
+ Private->FrameBufferBltLibConfigure,
+ BltBuffer,
+ BltOperation,
+ SourceX, SourceY,
+ DestinationX, DestinationY, Width, Height,
+ Delta
+ );
+ gBS->RestoreTPL (Tpl);
+
+ return RETURN_ERROR (Status) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
+}
+
+CONST GRAPHICS_OUTPUT_PRIVATE_DATA mGraphicsOutputInstanceTemplate = {
+ GRAPHICS_OUTPUT_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // GraphicsOutputHandle
+ {
+ GraphicsOutputQueryMode,
+ GraphicsOutputSetMode,
+ GraphicsOutputBlt,
+ NULL // Mode
+ },
+ {
+ 1, // MaxMode
+ 0, // Mode
+ NULL, // Info
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), // SizeOfInfo
+ 0, // FrameBufferBase
+ 0 // FrameBufferSize
+ },
+ NULL, // DevicePath
+ NULL, // PciIo
+ 0, // PciAttributes
+ NULL, // FrameBufferBltLibConfigure
+ 0 // FrameBufferBltLibConfigureSize
+};
+
+/**
+ Test whether the Controller can be managed by the driver.
+
+ @param This Driver Binding protocol instance pointer.
+ @param Controller The PCI controller.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The driver can manage the video device.
+ @retval other The driver cannot manage the video device.
+**/
+EFI_STATUS
+EFIAPI
+GraphicsOutputDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Since there is only one GraphicsInfo HOB, the driver only manages one video device.
+ //
+ if (mDriverStarted) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Test the PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Test the DevicePath protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if ((RemainingDevicePath == NULL) ||
+ IsDevicePathEnd (RemainingDevicePath) ||
+ CompareMem (RemainingDevicePath, &mGraphicsOutputAdrNode, sizeof (mGraphicsOutputAdrNode)) == 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Start the video controller.
+
+ @param This Driver Binding protocol instance pointer.
+ @param ControllerHandle The PCI controller.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The driver starts to manage the video device.
+ @retval other The driver cannot manage the video device.
+**/
+EFI_STATUS
+EFIAPI
+GraphicsOutputDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ RETURN_STATUS ReturnStatus;
+ GRAPHICS_OUTPUT_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH *PciDevicePath;
+ PCI_TYPE00 Pci;
+ UINT8 Index;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
+ VOID *HobStart;
+ EFI_PEI_GRAPHICS_INFO_HOB *GraphicsInfo;
+ EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *DeviceInfo;
+ EFI_PHYSICAL_ADDRESS FrameBufferBase;
+
+ FrameBufferBase = 0;
+
+ HobStart = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid);
+ ASSERT ((HobStart != NULL) && (GET_GUID_HOB_DATA_SIZE (HobStart) == sizeof (EFI_PEI_GRAPHICS_INFO_HOB)));
+ GraphicsInfo = (EFI_PEI_GRAPHICS_INFO_HOB *) (GET_GUID_HOB_DATA (HobStart));
+
+ HobStart = GetFirstGuidHob (&gEfiGraphicsDeviceInfoHobGuid);
+ if ((HobStart == NULL) || (GET_GUID_HOB_DATA_SIZE (HobStart) < sizeof (*DeviceInfo))) {
+ //
+ // Use default device infomation when the device info HOB doesn't exist
+ //
+ DeviceInfo = &mDefaultGraphicsDeviceInfo;
+ DEBUG ((EFI_D_INFO, "[%a]: GraphicsDeviceInfo HOB doesn't exist!\n", gEfiCallerBaseName));
+ } else {
+ DeviceInfo = (EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *) (GET_GUID_HOB_DATA (HobStart));
+ DEBUG ((EFI_D_INFO, "[%a]: GraphicsDeviceInfo HOB:\n"
+ " VendorId = %04x, DeviceId = %04x,\n"
+ " RevisionId = %02x, BarIndex = %x,\n"
+ " SubsystemVendorId = %04x, SubsystemId = %04x\n",
+ gEfiCallerBaseName,
+ DeviceInfo->VendorId, DeviceInfo->DeviceId,
+ DeviceInfo->RevisionId, DeviceInfo->BarIndex,
+ DeviceInfo->SubsystemVendorId, DeviceInfo->SubsystemId));
+ }
+
+ //
+ // Open the PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &PciDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Read the PCI Class Code from the PCI Device
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
+ if (!EFI_ERROR (Status)) {
+ if (!IS_PCI_DISPLAY (&Pci) || (
+ ((DeviceInfo->VendorId != MAX_UINT16) && (DeviceInfo->VendorId != Pci.Hdr.VendorId)) ||
+ ((DeviceInfo->DeviceId != MAX_UINT16) && (DeviceInfo->DeviceId != Pci.Hdr.DeviceId)) ||
+ ((DeviceInfo->RevisionId != MAX_UINT8) && (DeviceInfo->RevisionId != Pci.Hdr.RevisionID)) ||
+ ((DeviceInfo->SubsystemVendorId != MAX_UINT16) && (DeviceInfo->SubsystemVendorId != Pci.Device.SubsystemVendorID)) ||
+ ((DeviceInfo->SubsystemId != MAX_UINT16) && (DeviceInfo->SubsystemId != Pci.Device.SubsystemID))
+ )
+ ) {
+ //
+ // It's not a video device, or device infomation doesn't match.
+ //
+ Status = EFI_UNSUPPORTED;
+ } else {
+ //
+ // If it's a video device and device information matches, use the BarIndex
+ // from device information, or any BAR if BarIndex is not specified
+ // whose size >= the frame buffer size from GraphicsInfo HOB.
+ // Store the new frame buffer base.
+ //
+ for (Index = 0; Index < MAX_PCI_BAR; Index++) {
+ if ((DeviceInfo->BarIndex != MAX_UINT8) && (DeviceInfo->BarIndex != Index)) {
+ continue;
+ }
+ Status = PciIo->GetBarAttributes (PciIo, Index, NULL, (VOID**) &Resources);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "[%a]: BAR[%d]: Base = %lx, Length = %lx\n",
+ gEfiCallerBaseName, Index, Resources->AddrRangeMin, Resources->AddrLen));
+ if ((Resources->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) &&
+ (Resources->Len == (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3)) &&
+ (Resources->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
+ (Resources->AddrLen >= GraphicsInfo->FrameBufferSize)
+ ) {
+ FrameBufferBase = Resources->AddrRangeMin;
+ DEBUG ((EFI_D_INFO, "[%a]: ... matched!\n", gEfiCallerBaseName));
+ break;
+ }
+ }
+ }
+ if (Index == MAX_PCI_BAR) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocols;
+ }
+
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ Private = AllocateCopyPool (sizeof (mGraphicsOutputInstanceTemplate), &mGraphicsOutputInstanceTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CloseProtocols;
+ }
+
+ Private->GraphicsOutputMode.FrameBufferBase = FrameBufferBase;
+ Private->GraphicsOutputMode.FrameBufferSize = GraphicsInfo->FrameBufferSize;
+ Private->GraphicsOutputMode.Info = &GraphicsInfo->GraphicsMode;
+
+ //
+ // Fix up Mode pointer in GraphicsOutput
+ //
+ Private->GraphicsOutput.Mode = &Private->GraphicsOutputMode;
+
+ //
+ // Set attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->PciAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto FreeMemory;
+ }
+
+ //
+ // Create the FrameBufferBltLib configuration.
+ //
+ ReturnStatus = FrameBufferBltConfigure (
+ (VOID *) (UINTN) Private->GraphicsOutput.Mode->FrameBufferBase,
+ Private->GraphicsOutput.Mode->Info,
+ Private->FrameBufferBltLibConfigure,
+ &Private->FrameBufferBltLibConfigureSize
+ );
+ if (ReturnStatus == RETURN_BUFFER_TOO_SMALL) {
+ Private->FrameBufferBltLibConfigure = AllocatePool (Private->FrameBufferBltLibConfigureSize);
+ if (Private->FrameBufferBltLibConfigure != NULL) {
+ ReturnStatus = FrameBufferBltConfigure (
+ (VOID *) (UINTN) Private->GraphicsOutput.Mode->FrameBufferBase,
+ Private->GraphicsOutput.Mode->Info,
+ Private->FrameBufferBltLibConfigure,
+ &Private->FrameBufferBltLibConfigureSize
+ );
+ }
+ }
+ if (RETURN_ERROR (ReturnStatus)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto RestorePciAttributes;
+ }
+
+ Private->DevicePath = AppendDevicePathNode (PciDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &mGraphicsOutputAdrNode);
+ if (Private->DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto RestorePciAttributes;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->GraphicsOutputHandle,
+ &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &Private->PciIo,
+ This->DriverBindingHandle,
+ Private->GraphicsOutputHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (!EFI_ERROR (Status)) {
+ mDriverStarted = TRUE;
+ } else {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Private->GraphicsOutputHandle,
+ &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ NULL
+ );
+ }
+ }
+
+RestorePciAttributes:
+ if (EFI_ERROR (Status)) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ }
+
+FreeMemory:
+ if (EFI_ERROR (Status)) {
+ if (Private != NULL) {
+ if (Private->DevicePath != NULL) {
+ FreePool (Private->DevicePath);
+ }
+ if (Private->FrameBufferBltLibConfigure != NULL) {
+ FreePool (Private->FrameBufferBltLibConfigure);
+ }
+ FreePool (Private);
+ }
+ }
+
+CloseProtocols:
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+/**
+ Stop the video controller.
+
+ @param This Driver Binding protocol instance pointer.
+ @param Controller The PCI controller.
+ @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
+GraphicsOutputDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+ GRAPHICS_OUTPUT_PRIVATE_DATA *Private;
+
+ if (NumberOfChildren == 0) {
+
+ //
+ // Close the PCI I/O Protocol
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (NumberOfChildren == 1);
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[0],
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &Gop,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[0],
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (Gop);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Private->GraphicsOutputHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Remove the GOP protocol interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->GraphicsOutputHandle,
+ &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Restore original PCI attributes
+ //
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Private->DevicePath);
+ FreePool (Private->FrameBufferBltLibConfigure);
+ mDriverStarted = FALSE;
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &Private->PciIo,
+ This->DriverBindingHandle,
+ Private->GraphicsOutputHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ return Status;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL mGraphicsOutputDriverBinding = {
+ GraphicsOutputDriverBindingSupported,
+ GraphicsOutputDriverBindingStart,
+ GraphicsOutputDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ The Entry Point for GraphicsOutput driver.
+
+ It installs DriverBinding, ComponentName and ComponentName2 protocol if there is
+ GraphicsInfo HOB passed from Graphics PEIM.
+
+ @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
+InitializeGraphicsOutput (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobStart;
+
+ HobStart = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid);
+
+ if ((HobStart == NULL) || (GET_GUID_HOB_DATA_SIZE (HobStart) < sizeof (EFI_PEI_GRAPHICS_INFO_HOB))) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mGraphicsOutputDriverBinding,
+ ImageHandle,
+ &mGraphicsOutputComponentName,
+ &mGraphicsOutputComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.h b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.h
new file mode 100644
index 000000000..a40768b1e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutput.h
@@ -0,0 +1,53 @@
+/** @file
+ Header file for a generic GOP driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _GRAPHICS_OUTPUT_DXE_H_
+#define _GRAPHICS_OUTPUT_DXE_H_
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+#include <Guid/GraphicsInfoHob.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/FrameBufferBltLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+
+#define MAX_PCI_BAR 6
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE GraphicsOutputHandle;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GraphicsOutputMode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 PciAttributes;
+ FRAME_BUFFER_CONFIGURE *FrameBufferBltLibConfigure;
+ UINTN FrameBufferBltLibConfigureSize;
+} GRAPHICS_OUTPUT_PRIVATE_DATA;
+
+#define GRAPHICS_OUTPUT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('g', 'g', 'o', 'p')
+#define GRAPHICS_OUTPUT_PRIVATE_FROM_THIS(a) \
+ CR(a, GRAPHICS_OUTPUT_PRIVATE_DATA, GraphicsOutput, GRAPHICS_OUTPUT_PRIVATE_DATA_SIGNATURE)
+
+extern EFI_COMPONENT_NAME_PROTOCOL mGraphicsOutputComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL mGraphicsOutputComponentName2;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutputDxe.inf b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutputDxe.inf
new file mode 100644
index 000000000..abc3de594
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/GraphicsOutputDxe/GraphicsOutputDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# This driver produces GraphicsOutput protocol based on the GraphicsInfo HOB information.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GraphicsOutputDxe
+ FILE_GUID = 20830080-CC28-4169-9836-7F42B8D0C8C9
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeGraphicsOutput
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ GraphicsOutput.h
+ GraphicsOutput.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ DebugLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+ FrameBufferBltLib
+ UefiLib
+ HobLib
+
+[Guids]
+ gEfiGraphicsInfoHobGuid ## CONSUMES ## HOB
+ gEfiGraphicsDeviceInfoHobGuid ## CONSUMES ## HOB
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiPciIoProtocolGuid ## TO_START
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c
new file mode 100644
index 000000000..f117d90b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Ansi.c
@@ -0,0 +1,73 @@
+/** @file
+ Implementation of translation upon PC ANSI.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Terminal.h"
+
+/**
+ Translate all raw data in the Raw FIFO into unicode, and insert
+ them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+AnsiRawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 RawData;
+
+ //
+ // pop the raw data out from the raw fifo,
+ // and translate it into unicode, then push
+ // the unicode into unicode fifo, until the raw fifo is empty.
+ //
+ while (!IsRawFiFoEmpty (TerminalDevice) && !IsUnicodeFiFoFull (TerminalDevice)) {
+
+ RawFiFoRemoveOneKey (TerminalDevice, &RawData);
+
+ UnicodeFiFoInsertOneKey (TerminalDevice, (UINT16) RawData);
+ }
+}
+
+/**
+ Check if input string is valid Ascii string, valid EFI control characters
+ or valid text graphics.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_UNSUPPORTED If not all input characters are valid.
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+AnsiTestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ )
+{
+ CHAR8 GraphicChar;
+
+ //
+ // support three kind of character:
+ // valid ascii, valid efi control char, valid text graphics.
+ //
+ for (; *WString != CHAR_NULL; WString++) {
+
+ if ( !(TerminalIsValidAscii (*WString) ||
+ TerminalIsValidEfiCntlChar (*WString) ||
+ TerminalIsValidTextGraphics (*WString, &GraphicChar, NULL) )) {
+
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c
new file mode 100644
index 000000000..c06d21bfd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/ComponentName.c
@@ -0,0 +1,231 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Terminal driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Terminal.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName = {
+ TerminalComponentNameGetDriverName,
+ TerminalComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gTerminalComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) TerminalComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) TerminalComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mTerminalDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"Serial Terminal 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
+TerminalComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mTerminalDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gTerminalComponentName)
+ );
+}
+
+/**
+ 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
+TerminalComponentNameGetControllerName (
+ 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_OUTPUT_PROTOCOL *SimpleTextOutput;
+ TERMINAL_DEV *TerminalDevice;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gTerminalDriverBinding.DriverBindingHandle,
+ &gEfiSerialIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // This is a bus driver, so ChildHandle can not be NULL.
+ //
+ if (ChildHandle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiSerialIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our context back
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ gTerminalDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ TerminalDevice->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gTerminalComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
new file mode 100644
index 000000000..a98b690c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -0,0 +1,1383 @@
+/** @file
+ Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
+ Simple Text Output Protocol upon Serial IO Protocol.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Terminal.h"
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
+ TerminalDriverBindingSupported,
+ TerminalDriverBindingStart,
+ TerminalDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+EFI_GUID *mTerminalType[] = {
+ &gEfiPcAnsiGuid,
+ &gEfiVT100Guid,
+ &gEfiVT100PlusGuid,
+ &gEfiVTUTF8Guid,
+ &gEfiTtyTermGuid,
+ &gEdkiiLinuxTermGuid,
+ &gEdkiiXtermR6Guid,
+ &gEdkiiVT400Guid,
+ &gEdkiiSCOTermGuid
+};
+
+
+CHAR16 *mSerialConsoleNames[] = {
+ L"PC-ANSI Serial Console",
+ L"VT-100 Serial Console",
+ L"VT-100+ Serial Console",
+ L"VT-UTF8 Serial Console",
+ L"Tty Terminal Serial Console",
+ L"Linux Terminal Serial Console",
+ L"Xterm R6 Serial Console",
+ L"VT-400 Serial Console",
+ L"SCO Terminal Serial Console"
+};
+
+TERMINAL_DEV mTerminalDevTemplate = {
+ TERMINAL_DEV_SIGNATURE,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ { // SimpleTextInput
+ TerminalConInReset,
+ TerminalConInReadKeyStroke,
+ NULL
+ },
+ { // SimpleTextOutput
+ TerminalConOutReset,
+ TerminalConOutOutputString,
+ TerminalConOutTestString,
+ TerminalConOutQueryMode,
+ TerminalConOutSetMode,
+ TerminalConOutSetAttribute,
+ TerminalConOutClearScreen,
+ TerminalConOutSetCursorPosition,
+ TerminalConOutEnableCursor,
+ NULL
+ },
+ { // SimpleTextOutputMode
+ 1, // MaxMode
+ 0, // Mode
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute
+ 0, // CursorColumn
+ 0, // CursorRow
+ TRUE // CursorVisible
+ },
+ NULL, // TerminalConsoleModeData
+ 0, // SerialInTimeOut
+
+ NULL, // RawFifo
+ NULL, // UnicodeFiFo
+ NULL, // EfiKeyFiFo
+ NULL, // EfiKeyFiFoForNotify
+
+ NULL, // ControllerNameTable
+ NULL, // TimerEvent
+ NULL, // TwoSecondTimeOut
+ INPUT_STATE_DEFAULT,
+ RESET_STATE_DEFAULT,
+ {
+ 0,
+ 0,
+ 0
+ },
+ 0,
+ FALSE,
+ { // SimpleTextInputEx
+ TerminalConInResetEx,
+ TerminalConInReadKeyStrokeEx,
+ NULL,
+ TerminalConInSetState,
+ TerminalConInRegisterKeyNotify,
+ TerminalConInUnregisterKeyNotify,
+ },
+ { // NotifyList
+ NULL,
+ NULL,
+ },
+ NULL // KeyNotifyProcessEvent
+};
+
+TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
+ {80, 25},
+ {80, 50},
+ {100, 31},
+ //
+ // New modes can be added here.
+ //
+};
+
+/**
+ Convert the GUID representation of terminal type to enum type.
+
+ @param Guid The GUID representation of terminal type.
+
+ @return The terminal type in enum type.
+**/
+TERMINAL_TYPE
+TerminalTypeFromGuid (
+ IN EFI_GUID *Guid
+)
+{
+ TERMINAL_TYPE Type;
+
+ for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {
+ if (CompareGuid (Guid, mTerminalType[Type])) {
+ break;
+ }
+ }
+ return Type;
+}
+
+/**
+ Test to see if this driver supports Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller 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
+TerminalDriverBindingSupported (
+ 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_SERIAL_IO_PROTOCOL *SerialIo;
+ VENDOR_DEVICE_PATH *Node;
+
+ //
+ // If remaining device path is not NULL, then make sure it is a
+ // device path that describes a terminal communications protocol.
+ //
+ 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
+ //
+ Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
+
+ if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
+ Node->Header.SubType != MSG_VENDOR_DP ||
+ DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
+
+ return EFI_UNSUPPORTED;
+
+ }
+ //
+ // only supports PC ANSI, VT100, VT100+, VT-UTF8, TtyTerm
+ // Linux, XtermR6, VT400 and SCO terminal types
+ //
+ if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ // The Controller must support the Serial I/O Protocol.
+ // This driver is a bus driver with at most 1 child device, so it is
+ // ok for it to be already started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ 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,
+ &gEfiSerialIoProtocolGuid,
+ 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;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Free notify functions list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.
+
+**/
+EFI_STATUS
+TerminalFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize all the text modes which the terminal console supports.
+
+ It returns information for available text modes that the terminal can support.
+
+ @param[out] TextModeCount The total number of text modes that terminal console supports.
+
+ @return The buffer to the text modes column and row information.
+ Caller is responsible to free it when it's non-NULL.
+
+**/
+TERMINAL_CONSOLE_MODE_DATA *
+InitializeTerminalConsoleTextMode (
+ OUT INT32 *TextModeCount
+)
+{
+ TERMINAL_CONSOLE_MODE_DATA *TextModeData;
+
+ ASSERT (TextModeCount != NULL);
+
+ TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);
+ if (TextModeData == NULL) {
+ return NULL;
+ }
+ *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);
+
+ DEBUG_CODE (
+ INT32 Index;
+ for (Index = 0; Index < *TextModeCount; Index++) {
+ DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
+ Index, TextModeData[Index].Columns, TextModeData[Index].Rows));
+ }
+ );
+ return TextModeData;
+}
+
+/**
+ Stop the terminal state machine.
+
+ @param TerminalDevice The terminal device.
+**/
+VOID
+StopTerminalStateMachine (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_TPL OriginalTpl;
+
+ OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ gBS->CloseEvent (TerminalDevice->TimerEvent);
+ gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
+
+ gBS->RestoreTPL (OriginalTpl);
+}
+
+/**
+ Start the terminal state machine.
+
+ @param TerminalDevice The terminal device.
+**/
+VOID
+StartTerminalStateMachine (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TerminalConInTimerHandler,
+ TerminalDevice,
+ &TerminalDevice->TimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer (
+ TerminalDevice->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TerminalDevice->TwoSecondTimeOut
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Initialize the controller name table.
+
+ @param TerminalType The terminal type.
+ @param ControllerNameTable The controller name table.
+
+ @retval EFI_SUCCESS The controller name table is initialized successfully.
+ @retval others Return status of AddUnicodeString2 ().
+**/
+EFI_STATUS
+InitializeControllerNameTable (
+ TERMINAL_TYPE TerminalType,
+ EFI_UNICODE_STRING_TABLE **ControllerNameTable
+)
+{
+ EFI_STATUS Status;
+ EFI_UNICODE_STRING_TABLE *Table;
+
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ Table = NULL;
+ Status = AddUnicodeString2 (
+ "eng",
+ gTerminalComponentName.SupportedLanguages,
+ &Table,
+ mSerialConsoleNames[TerminalType],
+ TRUE
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AddUnicodeString2 (
+ "en",
+ gTerminalComponentName2.SupportedLanguages,
+ &Table,
+ mSerialConsoleNames[TerminalType],
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ FreeUnicodeStringTable (Table);
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ *ControllerNameTable = Table;
+ }
+ return Status;
+}
+
+/**
+ Start this driver on Controller by opening a Serial IO protocol,
+ reading Device Path, and creating a child handle with a Simple Text In,
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.
+ And store Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @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 This driver is added to Controller.
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Vendor;
+ EFI_HANDLE SerialIoHandle;
+ EFI_SERIAL_IO_MODE *Mode;
+ UINTN SerialInTimeOut;
+ TERMINAL_DEV *TerminalDevice;
+ UINT8 TerminalType;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Get the Device Path Protocol to build the device path of the child device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Open the Serial I/O Protocol BY_DRIVER. It might already be started.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ if (!IsHotPlugDevice (ParentDevicePath)) {
+ //
+ // if the serial device is a hot plug device, do not update the
+ // ConInDev, ConOutDev, and StdErrDev variables.
+ //
+ TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ }
+
+ //
+ // Do not create any child for END remaining device path.
+ //
+ if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is NULL or is the End of Device Path Node
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This driver can only produce one child per serial port.
+ // Change its terminal type as remaining device path requests.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTextInput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
+ TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ if (TerminalDevice->TerminalType != TerminalType) {
+ Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);
+ if (!EFI_ERROR (Status)) {
+ StopTerminalStateMachine (TerminalDevice);
+ //
+ // Update the device path
+ //
+ Vendor = TerminalDevice->DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);
+ ASSERT_EFI_ERROR (Status);
+ CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalType]);
+ Status = gBS->ReinstallProtocolInterface (
+ TerminalDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ TerminalDevice->DevicePath,
+ TerminalDevice->DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ TerminalDevice->TerminalType = TerminalType;
+ StartTerminalStateMachine (TerminalDevice);
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ TerminalDevice->ControllerNameTable = ControllerNameTable;
+ } else {
+ //
+ // Restore the device path on failure
+ //
+ CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);
+ FreeUnicodeStringTable (ControllerNameTable);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+ }
+ return Status;
+ }
+
+ //
+ // Initialize the Terminal Dev
+ //
+ TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
+ if (TerminalDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CloseProtocols;
+ }
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is NULL, use default terminal type
+ //
+ TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);
+ } else {
+ //
+ // End of Device Path Node is handled in above.
+ //
+ ASSERT (!IsDevicePathEnd (RemainingDevicePath));
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // Use the RemainingDevicePath to determine the terminal type
+ //
+ TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);
+ }
+ ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));
+ TerminalDevice->SerialIo = SerialIo;
+
+ //
+ // Build the component name for the child device
+ //
+ Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);
+ if (EFI_ERROR (Status)) {
+ goto FreeResources;
+ }
+
+ //
+ // Build the device path for the child device
+ //
+ Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);
+ if (EFI_ERROR (Status)) {
+ goto FreeResources;
+ }
+
+ InitializeListHead (&TerminalDevice->NotifyList);
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKeyEx,
+ TerminalDevice,
+ &TerminalDevice->SimpleInputEx.WaitForKeyEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ TerminalConInWaitForKey,
+ TerminalDevice,
+ &TerminalDevice->SimpleInput.WaitForKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ KeyNotifyProcessHandler,
+ TerminalDevice,
+ &TerminalDevice->KeyNotifyProcessEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocates and initializes the FIFO buffer to be zero, used for accommodating
+ // the pre-read pending characters.
+ //
+ TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
+ if (TerminalDevice->RawFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
+ if (TerminalDevice->UnicodeFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
+ if (TerminalDevice->EfiKeyFiFo == NULL) {
+ goto FreeResources;
+ }
+ TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
+ if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {
+ goto FreeResources;
+ }
+
+ //
+ // Set the timeout value of serial buffer for keystroke response performance issue
+ //
+ Mode = TerminalDevice->SerialIo->Mode;
+
+ SerialInTimeOut = 0;
+ if (Mode->BaudRate != 0) {
+ SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
+ }
+
+ Status = TerminalDevice->SerialIo->SetAttributes (
+ TerminalDevice->SerialIo,
+ Mode->BaudRate,
+ Mode->ReceiveFifoDepth,
+ (UINT32) SerialInTimeOut,
+ (EFI_PARITY_TYPE) (Mode->Parity),
+ (UINT8) Mode->DataBits,
+ (EFI_STOP_BITS_TYPE) (Mode->StopBits)
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if set attributes operation fails, invalidate
+ // the value of SerialInTimeOut,thus make it
+ // inconsistent with the default timeout value
+ // of serial buffer. This will invoke the recalculation
+ // in the readkeystroke routine.
+ //
+ TerminalDevice->SerialInTimeOut = 0;
+ } else {
+ TerminalDevice->SerialInTimeOut = SerialInTimeOut;
+ }
+
+ SimpleTextOutput = &TerminalDevice->SimpleTextOutput;
+ SimpleTextInput = &TerminalDevice->SimpleInput;
+
+ //
+ // Initialize SimpleTextOut instance
+ //
+ SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
+ TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (
+ &SimpleTextOutput->Mode->MaxMode
+ );
+ if (TerminalDevice->TerminalConsoleModeData == NULL) {
+ goto FreeResources;
+ }
+ //
+ // For terminal devices, cursor is always visible
+ //
+ SimpleTextOutput->Mode->CursorVisible = TRUE;
+ Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ if (!EFI_ERROR (Status)) {
+ Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ //
+ // Initialize SimpleTextInput instance
+ //
+ Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto ReportError;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &TerminalDevice->Handle,
+ &gEfiSimpleTextInProtocolGuid, &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid, &TerminalDevice->SimpleInputEx,
+ &gEfiSimpleTextOutProtocolGuid, &TerminalDevice->SimpleTextOutput,
+ &gEfiDevicePathProtocolGuid, TerminalDevice->DevicePath,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &TerminalDevice->SerialIo,
+ This->DriverBindingHandle,
+ TerminalDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ ASSERT_EFI_ERROR (Status);
+ StartTerminalStateMachine (TerminalDevice);
+ return Status;
+ }
+
+ReportError:
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
+ ParentDevicePath
+ );
+
+FreeResources:
+ ASSERT (TerminalDevice != NULL);
+
+ if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ }
+ if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ }
+ if (TerminalDevice->KeyNotifyProcessEvent != NULL) {
+ gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
+ }
+
+ if (TerminalDevice->RawFiFo != NULL) {
+ FreePool (TerminalDevice->RawFiFo);
+ }
+ if (TerminalDevice->UnicodeFiFo != NULL) {
+ FreePool (TerminalDevice->UnicodeFiFo);
+ }
+ if (TerminalDevice->EfiKeyFiFo != NULL) {
+ FreePool (TerminalDevice->EfiKeyFiFo);
+ }
+ if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
+ FreePool (TerminalDevice->EfiKeyFiFoForNotify);
+ }
+
+ if (TerminalDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ }
+
+ if (TerminalDevice->DevicePath != NULL) {
+ FreePool (TerminalDevice->DevicePath);
+ }
+
+ if (TerminalDevice->TerminalConsoleModeData != NULL) {
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ }
+
+ FreePool (TerminalDevice);
+
+CloseProtocols:
+
+ //
+ // Remove Parent Device Path from
+ // the Console Device Environment Variables
+ //
+ TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Stop this driver on Controller by closing Simple Text In, Simple Text
+ In Ex, Simple Text Out protocol, and removing parent device path from
+ Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller 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 Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStop (
+ 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_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ TERMINAL_DEV *TerminalDevice;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+
+ //
+ // 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,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Remove Parent Device Path from
+ // the Console Device Environment Variables
+ //
+ TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+ TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleTextInProtocolGuid,
+ &TerminalDevice->SimpleInput,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &TerminalDevice->SimpleInputEx,
+ &gEfiSimpleTextOutProtocolGuid,
+ &TerminalDevice->SimpleTextOutput,
+ &gEfiDevicePathProtocolGuid,
+ TerminalDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+
+ FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
+ StopTerminalStateMachine (TerminalDevice);
+ gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
+ gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
+ gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
+ TerminalFreeNotifyList (&TerminalDevice->NotifyList);
+ FreePool (TerminalDevice->DevicePath);
+ FreePool (TerminalDevice->TerminalConsoleModeData);
+ FreePool (TerminalDevice);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare 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 is contained within Multi.
+ @retval FALSE The Single is not match within Multi.
+
+**/
+BOOLEAN
+MatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ 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;
+}
+
+/**
+ Update terminal device path in Console Device Environment Variables.
+
+ @param VariableName The Console Device Environment Variable.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalUpdateConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN NameSize;
+ UINTN VariableSize;
+ TERMINAL_TYPE TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ Status = GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ Variable = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Append terminal device path onto the variable.
+ //
+ for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+
+ if (TempDevicePath != NULL) {
+ if (!MatchDevicePaths (Variable, TempDevicePath)) {
+ NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
+ if (NewVariable != NULL) {
+ if (Variable != NULL) {
+ FreePool (Variable);
+ }
+ Variable = NewVariable;
+ }
+ }
+
+ FreePool (TempDevicePath);
+ }
+
+ }
+
+ VariableSize = GetDevicePathSize (Variable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ Variable
+ );
+
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = VariableSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable, VariableSize);
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ FreePool (Variable);
+
+ return ;
+}
+
+
+/**
+ Remove terminal device path from Console Device Environment Variables.
+
+ @param VariableName Console Device Environment Variables.
+ @param ParentDevicePath The terminal device path to be updated.
+
+**/
+VOID
+TerminalRemoveConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN FoundOne;
+ BOOLEAN Match;
+ UINTN VariableSize;
+ UINTN InstanceSize;
+ TERMINAL_TYPE TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Variable;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;
+ EFI_DEVICE_PATH_PROTOCOL *NewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ Instance = NULL;
+
+ //
+ // Get global variable and its size according to the name given.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
+ if (Variable == NULL) {
+ return ;
+ }
+
+ FoundOne = FALSE;
+ OriginalVariable = Variable;
+ NewVariable = NULL;
+
+ //
+ // Get first device path instance from Variable
+ //
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ if (Instance == NULL) {
+ FreePool (OriginalVariable);
+ return ;
+ }
+ //
+ // Loop through all the device path instances of Variable
+ //
+ do {
+ //
+ // Loop through all the terminal types that this driver supports
+ //
+ Match = FALSE;
+ for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
+
+ SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
+
+ //
+ // Compare the generated device path to the current device path instance
+ //
+ if (TempDevicePath != NULL) {
+ if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
+ Match = TRUE;
+ FoundOne = TRUE;
+ }
+
+ FreePool (TempDevicePath);
+ }
+ }
+ //
+ // If a match was not found, then keep the current device path instance
+ //
+ if (!Match) {
+ SavedNewVariable = NewVariable;
+ NewVariable = AppendDevicePathInstance (NewVariable, Instance);
+ if (SavedNewVariable != NULL) {
+ FreePool (SavedNewVariable);
+ }
+ }
+ //
+ // Get next device path instance from Variable
+ //
+ FreePool (Instance);
+ Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
+ } while (Instance != NULL);
+
+ FreePool (OriginalVariable);
+
+ if (FoundOne) {
+ VariableSize = GetDevicePathSize (NewVariable);
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize,
+ NewVariable
+ );
+ //
+ // Shrinking variable with existing variable driver implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (NewVariable != NULL) {
+ FreePool (NewVariable);
+ }
+
+ return ;
+}
+
+/**
+ Build terminal device path according to terminal type.
+
+ @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
+ @param ParentDevicePath Parent device path.
+ @param TerminalDevicePath Returned terminal device path, if building successfully.
+
+ @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
+ @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
+ @retval EFI_SUCCESS Build terminal device path successfully.
+
+**/
+EFI_STATUS
+SetTerminalDevicePath (
+ IN TERMINAL_TYPE TerminalType,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
+ )
+{
+ VENDOR_DEVICE_PATH Node;
+
+ ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
+ Node.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Header.SubType = MSG_VENDOR_DP;
+ SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));
+ CopyGuid (&Node.Guid, mTerminalType[TerminalType]);
+
+ //
+ // Append the terminal node onto parent device path
+ // to generate a complete terminal device path.
+ //
+ *TerminalDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Node
+ );
+ if (*TerminalDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module Terminal. The user code starts with this function.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeTerminal(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gTerminalDriverBinding,
+ ImageHandle,
+ &gTerminalComponentName,
+ &gTerminalComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Check if the device supports hot-plug through its device path.
+
+ This function could be updated to check more types of Hot Plug devices.
+ Currently, it checks USB and PCCard device.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a hot-plug device
+ @retval FALSE The devcie is not a hot-plug device.
+
+**/
+BOOLEAN
+IsHotPlugDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;
+
+ CheckDevicePath = DevicePath;
+ while (!IsDevicePathEnd (CheckDevicePath)) {
+ //
+ // Check device whether is hot plug device or not throught Device Path
+ //
+ if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
+ DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
+ //
+ // If Device is USB device
+ //
+ return TRUE;
+ }
+ if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
+ //
+ // If Device is PCCard
+ //
+ return TRUE;
+ }
+
+ CheckDevicePath = NextDevicePathNode (CheckDevicePath);
+ }
+
+ return FALSE;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
new file mode 100644
index 000000000..378ace13c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
@@ -0,0 +1,1458 @@
+/** @file
+ Header file for Terminal driver.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TERMINAL_H_
+#define _TERMINAL_H_
+
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/PcAnsi.h>
+#include <Guid/TtyTerm.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+
+
+#define RAW_FIFO_MAX_NUMBER 256
+#define FIFO_MAX_NUMBER 128
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ UINT8 Data[RAW_FIFO_MAX_NUMBER + 1];
+} RAW_DATA_FIFO;
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ UINT16 Data[FIFO_MAX_NUMBER + 1];
+} UNICODE_FIFO;
+
+typedef struct {
+ UINT8 Head;
+ UINT8 Tail;
+ EFI_INPUT_KEY Data[FIFO_MAX_NUMBER + 1];
+} EFI_KEY_FIFO;
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+} TERMINAL_CONSOLE_MODE_DATA;
+
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+
+#define TERMINAL_DEV_SIGNATURE SIGNATURE_32 ('t', 'm', 'n', 'l')
+
+#define TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('t', 'm', 'e', 'n')
+
+typedef struct _TERMINAL_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} TERMINAL_CONSOLE_IN_EX_NOTIFY;
+
+typedef enum {
+ TerminalTypePcAnsi,
+ TerminalTypeVt100,
+ TerminalTypeVt100Plus,
+ TerminalTypeVtUtf8,
+ TerminalTypeTtyTerm,
+ TerminalTypeLinux,
+ TerminalTypeXtermR6,
+ TerminalTypeVt400,
+ TerminalTypeSCO
+} TERMINAL_TYPE;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ TERMINAL_TYPE TerminalType;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleInput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode;
+ TERMINAL_CONSOLE_MODE_DATA *TerminalConsoleModeData;
+ UINTN SerialInTimeOut;
+ RAW_DATA_FIFO *RawFiFo;
+ UNICODE_FIFO *UnicodeFiFo;
+ EFI_KEY_FIFO *EfiKeyFiFo;
+ EFI_KEY_FIFO *EfiKeyFiFoForNotify;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT TwoSecondTimeOut;
+ UINT32 InputState;
+ UINT32 ResetState;
+ UINT16 TtyEscapeStr[3];
+ INTN TtyEscapeIndex;
+
+ //
+ // Esc could not be output to the screen by user,
+ // but the terminal driver need to output it to
+ // the terminal emulation software to send control sequence.
+ // This boolean is used by the terminal driver only
+ // to indicate whether the Esc could be sent or not.
+ //
+ BOOLEAN OutputEscChar;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleInputEx;
+ LIST_ENTRY NotifyList;
+ EFI_EVENT KeyNotifyProcessEvent;
+} TERMINAL_DEV;
+
+#define INPUT_STATE_DEFAULT 0x00
+#define INPUT_STATE_ESC 0x01
+#define INPUT_STATE_CSI 0x02
+#define INPUT_STATE_LEFTOPENBRACKET 0x04
+#define INPUT_STATE_O 0x08
+#define INPUT_STATE_2 0x10
+#define INPUT_STATE_LEFTOPENBRACKET_TTY 0x20
+#define INPUT_STATE_1 0x40
+#define INPUT_STATE_LEFTOPENBRACKET_2ND 0x80
+
+#define RESET_STATE_DEFAULT 0x00
+#define RESET_STATE_ESC_R 0x01
+#define RESET_STATE_ESC_R_ESC_R 0x02
+
+#define TERMINAL_CON_IN_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInput, TERMINAL_DEV_SIGNATURE)
+#define TERMINAL_CON_OUT_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleTextOutput, TERMINAL_DEV_SIGNATURE)
+#define TERMINAL_CON_IN_EX_DEV_FROM_THIS(a) CR (a, TERMINAL_DEV, SimpleInputEx, TERMINAL_DEV_SIGNATURE)
+
+typedef union {
+ UINT8 Utf8_1;
+ UINT8 Utf8_2[2];
+ UINT8 Utf8_3[3];
+} UTF8_CHAR;
+
+#define LEFTOPENBRACKET 0x5b // '['
+#define ACAP 0x41
+#define BCAP 0x42
+#define CCAP 0x43
+#define DCAP 0x44
+
+#define BACKSPACE 8
+#define ESC 27
+#define CSI 0x9B
+#define DEL 127
+#define BRIGHT_CONTROL_OFFSET 2
+#define FOREGROUND_CONTROL_OFFSET 6
+#define BACKGROUND_CONTROL_OFFSET 11
+#define ROW_OFFSET 2
+#define COLUMN_OFFSET 5
+#define FW_BACK_OFFSET 2
+
+typedef struct {
+ UINT16 Unicode;
+ CHAR8 PcAnsi;
+ CHAR8 Ascii;
+} UNICODE_TO_CHAR;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gTerminalComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gTerminalComponentName2;
+
+/**
+ The user Entry Point for module Terminal. 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
+InitializeTerminal (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
+ This driver only perform dependent serial device reset regardless of
+ the value of ExtendeVerification
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Skip by this driver.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
+
+ @param This Indicates the calling context.
+ @param Key A pointer to a buffer that is filled in with the
+ keystroke information for the key that was sent
+ from terminal.
+
+ @retval EFI_SUCCESS The keystroke information is returned successfully.
+ @retval EFI_NOT_READY There is no keystroke data available.
+ @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Check if the key already has been 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 FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Simple Text Input Ex protocol prototypes
+//
+
+/**
+ Reset the input device and optionally 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
+TerminalConInResetEx (
+ 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 existence 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 available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due
+ to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStrokeEx (
+ 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
+TerminalConInSetState (
+ 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. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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
+TerminalConInRegisterKeyNotify (
+ 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
+TerminalConInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+ If ExtendeVerification is TRUE, then perform dependent serial device reset,
+ and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+ The Unicode string will be converted to terminal expressible data stream
+ and send to terminal via serial port.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be displayed
+ on the terminal screen.
+
+ @retval EFI_SUCCESS The string is output successfully.
+ @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
+ @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
+ be rendered and are skipped.
+ @retval EFI_UNSUPPORTED If current display mode is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+ If one of the characters in the *Wstring is
+ neither valid Unicode drawing characters,
+ not ASCII code, then this function will return
+ EFI_UNSUPPORTED.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be tested.
+
+ @retval EFI_SUCCESS The terminal is capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It returns information for an available text mode
+ that the terminal supports.
+ In this driver, we support text mode 80x25 (mode 0),
+ 80x50 (mode 1), 100x31 (mode 2).
+
+ @param This Indicates the calling context.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUT.SetMode().
+ Set the terminal to a specified display mode.
+ In this driver, we only support mode 0.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set
+ because of serial device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+
+ @param This Indicates the calling context.
+ @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
+ are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ It clears the ANSI terminal's display to the
+ currently selected background color.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+
+ @param This Indicates the calling context.
+ @param Column The row to set cursor to.
+ @param Row The column to set cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The request fails due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
+ is invalid for current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+/**
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+ In this driver, the cursor cannot be hidden.
+
+ @param This Indicates the calling context.
+ @param Visible If TRUE, the cursor is set to be visible,
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The request is valid.
+ @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Test to see if this driver supports Controller.
+
+ @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
+TerminalDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on Controller by opening a Serial IO protocol,
+ reading Device Path, and creating a child handle with a Simple Text In,
+ Simple Text In Ex and Simple Text Out protocol, and device path protocol.
+ And store Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @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 This driver is added to Controller.
+ @retval EFI_ALREADY_STARTED This driver is already running on Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Stop this driver on Controller by closing Simple Text In, Simple Text
+ In Ex, Simple Text Out protocol, and removing parent device path from
+ Console Device Environment Variables.
+
+ @param This Protocol instance pointer.
+ @param Controller 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 Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Free notify functions list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully.
+ @retval EFI_INVALID_PARAMETER ListHead is NULL.
+
+**/
+EFI_STATUS
+TerminalFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ 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
+TerminalComponentNameGetDriverName (
+ 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
+TerminalComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// internal functions
+//
+
+/**
+ Check for a pending key in the Efi Key FIFO or Serial device buffer.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS There is key pending.
+ @retval EFI_NOT_READY There is no key pending.
+ @retval EFI_DEVICE_ERROR If Serial IO is not attached to serial device.
+
+**/
+EFI_STATUS
+TerminalConInCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ );
+
+/**
+ Update terminal device path in Console Device Environment Variables.
+
+ @param VariableName The Console Device Environment Variable.
+ @param ParentDevicePath The terminal device path to be updated.
+
+ @return None.
+
+**/
+VOID
+TerminalUpdateConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ );
+
+/**
+ Remove console device variable.
+
+ @param VariableName A pointer to the variable name.
+ @param ParentDevicePath A pointer to the parent device path.
+
+**/
+VOID
+TerminalRemoveConsoleDevVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ );
+
+/**
+ Build termial device path according to terminal type.
+
+ @param TerminalType The terminal type is PC ANSI, VT100, VT100+, VT-UTF8, TTY-Term,
+ Linux, XtermR6, VT400 and SCO.
+ @param ParentDevicePath Parent device path.
+ @param TerminalDevicePath Returned terminal device path, if building successfully.
+
+ @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.
+ @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.
+ @retval EFI_SUCCESS Build terminal device path successfully.
+
+**/
+EFI_STATUS
+SetTerminalDevicePath (
+ IN TERMINAL_TYPE TerminalType,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath
+ );
+
+/**
+ Get one key out of serial buffer.
+
+ @param SerialIo Serial I/O protocl attached to the serial device.
+ @param Input The fetched key.
+
+ @retval EFI_NOT_READY If serial buffer is empty.
+ @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
+ @retval EFI_SUCCESS If reading serial buffer successfully, put
+ the fetched key to the parameter output.
+
+**/
+EFI_STATUS
+GetOneKeyFromSerial (
+ EFI_SERIAL_IO_PROTOCOL *SerialIo,
+ UINT8 *Input
+ );
+
+/**
+ Insert one byte raw data into the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+RawFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 Input
+ );
+
+/**
+ Remove one pre-fetched key out of the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+RawFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 *Output
+ );
+
+/**
+ Clarify whether Raw Data FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is empty.
+ @retval FALSE If Raw Data FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsRawFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether Raw Data FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is full.
+ @retval FALSE If Raw Data FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsRawFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoForNotifyInsertOneKey (
+ EFI_KEY_FIFO *EfiKeyFiFo,
+ EFI_INPUT_KEY *Input
+ );
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoForNotifyRemoveOneKey (
+ EFI_KEY_FIFO *EfiKeyFiFo,
+ EFI_INPUT_KEY *Output
+ );
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoForNotifyEmpty (
+ IN EFI_KEY_FIFO *EfiKeyFiFo
+ );
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoForNotifyFull (
+ EFI_KEY_FIFO *EfiKeyFiFo
+ );
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Key The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Key
+ );
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Output
+ );
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Insert one pre-fetched key into the Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Unicode FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+UnicodeFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 Input
+ );
+
+/**
+ Remove one pre-fetched key out of the Unicode FIFO buffer.
+ The caller should guarantee that Unicode FIFO buffer is not empty
+ by IsUnicodeFiFoEmpty ().
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+**/
+VOID
+UnicodeFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 *Output
+ );
+
+/**
+ Clarify whether Unicode FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is empty.
+ @retval FALSE If Unicode FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsUnicodeFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Clarify whether Unicode FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is full.
+ @retval FALSE If Unicode FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsUnicodeFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ );
+
+
+/**
+ Translate raw data into Unicode (according to different encode), and
+ translate Unicode into key information. (according to different standard).
+
+ @param TerminalDevice Terminal driver private structure.
+
+**/
+VOID
+TranslateRawDataToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+//
+// internal functions for PC ANSI
+//
+
+/**
+ Translate all raw data in the Raw FIFI into unicode, and insert
+ them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+AnsiRawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Converts a stream of Unicode characters from a terminal input device into EFI Keys that
+ can be read through the Simple Input Protocol.
+
+ The table below shows the keyboard input mappings that this function supports.
+ If the ESC sequence listed in one of the columns is presented, then it is translated
+ into the coorespoding EFI Scan Code. If a matching sequence is not found, then the raw
+ key strokes are converted into EFI Keys.
+
+ 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
+ completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
+ converted into EFI Keys.
+ There is one special input sequence that will force the system to reset.
+ This is ESC R ESC r ESC R.
+
+ Symbols used in table below
+ ===========================
+ ESC = 0x1B
+ CSI = 0x9B
+ DEL = 0x7f
+ ^ = CTRL
+ +=========+======+===========+==========+==========+
+ | | EFI | UEFI 2.0 | | |
+ | | Scan | | VT100+ | |
+ | KEY | Code | PC ANSI | VTUTF8 | VT100 |
+ +=========+======+===========+==========+==========+
+ | NULL | 0x00 | | | |
+ | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
+ | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
+ | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
+ | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
+ | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
+ | END | 0x06 | ESC [ F | ESC k | ESC [ K |
+ | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
+ | | | ESC [ L | | ESC [ L |
+ | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
+ | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
+ | | | | | ESC [ ? |
+ | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
+ | | | | | ESC [ / |
+ | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
+ | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
+ | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
+ | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
+ | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
+ | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
+ | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
+ | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
+ | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
+ | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
+ | Escape | 0x17 | ESC | ESC | ESC |
+ | F11 | 0x15 | | ESC ! | |
+ | F12 | 0x16 | | ESC @ | |
+ +=========+======+===========+==========+==========+
+
+Putty function key map:
+ +=========+======+===========+=============+=============+=============+=========+
+ | | EFI | | | | | |
+ | | Scan | | | Normal | | |
+ | KEY | Code | VT100+ | Xterm R6 | VT400 | Linux | SCO |
+ +=========+======+===========+=============+=============+=============+=========+
+ | F1 | 0x0B | ESC O P | ESC O P | ESC [ 1 1 ~ | ESC [ [ A | ESC [ M |
+ | F2 | 0x0C | ESC O Q | ESC O Q | ESC [ 1 2 ~ | ESC [ [ B | ESC [ N |
+ | F3 | 0x0D | ESC O R | ESC O R | ESC [ 1 3 ~ | ESC [ [ C | ESC [ O |
+ | F4 | 0x0E | ESC O S | ESC O S | ESC [ 1 4 ~ | ESC [ [ D | ESC [ P |
+ | F5 | 0x0F | ESC O T | ESC [ 1 5 ~ | ESC [ 1 5 ~ | ESC [ [ E | ESC [ Q |
+ | F6 | 0x10 | ESC O U | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ R |
+ | F7 | 0x11 | ESC O V | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ S |
+ | F8 | 0x12 | ESC O W | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ T |
+ | F9 | 0x13 | ESC O X | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ U |
+ | F10 | 0x14 | ESC O Y | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ V |
+ | Escape | 0x17 | ESC | ESC | ESC | ESC | ESC |
+ | F11 | 0x15 | ESC O Z | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ W |
+ | F12 | 0x16 | ESC O [ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ X |
+ +=========+======+===========+=============+=============+=============+=========+
+
+
+ Special Mappings
+ ================
+ ESC R ESC r ESC R = Reset System
+
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ );
+
+/**
+ Check if input string is valid Ascii string, valid EFI control characters
+ or valid text graphics.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_UNSUPPORTED If not all input characters are valid.
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+AnsiTestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ );
+
+//
+// internal functions for VTUTF8
+//
+
+/**
+ Translate all VT-UTF8 characters in the Raw FIFI into unicode characters,
+ and insert them into Unicode FIFO.
+
+ @param VtUtf8Device The terminal device.
+
+**/
+VOID
+VTUTF8RawDataToUnicode (
+ IN TERMINAL_DEV *VtUtf8Device
+ );
+
+/**
+ Check if input string is valid VT-UTF8 string.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+VTUTF8TestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ );
+
+/**
+ Translate one Unicode character into VT-UTF8 characters.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Unicode Unicode character need translating.
+ @param Utf8Char Return VT-UTF8 character set.
+ @param ValidBytes The count of valid VT-UTF8 characters. If
+ ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+UnicodeToUtf8 (
+ IN CHAR16 Unicode,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ );
+
+/**
+ Get one valid VT-UTF8 characters set from Raw Data FIFO.
+
+ @param Utf8Device The terminal device.
+ @param Utf8Char Returned valid VT-UTF8 characters set.
+ @param ValidBytes The count of returned VT-VTF8 characters.
+ If ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+GetOneValidUtf8Char (
+ IN TERMINAL_DEV *Utf8Device,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ );
+
+/**
+ Translate VT-UTF8 characters into one Unicode character.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Utf8Char VT-UTF8 character set needs translating.
+ @param ValidBytes The count of valid VT-UTF8 characters.
+ @param UnicodeChar Returned unicode character.
+
+**/
+VOID
+Utf8ToUnicode (
+ IN UTF8_CHAR Utf8Char,
+ IN UINT8 ValidBytes,
+ OUT CHAR16 *UnicodeChar
+ );
+
+//
+// functions for boxdraw unicode
+//
+
+/**
+ Detects if a Unicode char is for Box Drawing text graphics.
+
+ @param Graphic Unicode char to test.
+ @param PcAnsi Optional pointer to return PCANSI equivalent of
+ Graphic.
+ @param Ascii Optional pointer to return ASCII equivalent of
+ Graphic.
+
+ @retval TRUE If Graphic is a supported Unicode Box Drawing character.
+
+**/
+BOOLEAN
+TerminalIsValidTextGraphics (
+ IN CHAR16 Graphic,
+ OUT CHAR8 *PcAnsi, OPTIONAL
+ OUT CHAR8 *Ascii OPTIONAL
+ );
+
+/**
+ Detects if a valid ASCII char.
+
+ @param Ascii An ASCII character.
+
+ @retval TRUE If it is a valid ASCII character.
+ @retval FALSE If it is not a valid ASCII character.
+
+**/
+BOOLEAN
+TerminalIsValidAscii (
+ IN CHAR16 Ascii
+ );
+
+/**
+ Detects if a valid EFI control character.
+
+ @param CharC An input EFI Control character.
+
+ @retval TRUE If it is a valid EFI control character.
+ @retval FALSE If it is not a valid EFI control character.
+
+**/
+BOOLEAN
+TerminalIsValidEfiCntlChar (
+ IN CHAR16 CharC
+ );
+
+/**
+ Check if the device supports hot-plug through its device path.
+
+ This function could be updated to check more types of Hot Plug devices.
+ Currently, it checks USB and PCCard device.
+
+ @param DevicePath Pointer to device's device path.
+
+ @retval TRUE The devcie is a hot-plug device
+ @retval FALSE The devcie is not a hot-plug device.
+
+**/
+BOOLEAN
+IsHotPlugDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Timer handler to poll the key from serial.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+TerminalConInTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
new file mode 100644
index 000000000..f8c71f95c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -0,0 +1,2093 @@
+/** @file
+ Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
+
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Terminal.h"
+
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param TerminalDevice Terminal 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 available.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+ReadKeyStrokeWorker (
+ IN TERMINAL_DEV *TerminalDevice,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ KeyData->KeyState.KeyShiftState = 0;
+ KeyData->KeyState.KeyToggleState = 0;
+
+ if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
+ This driver only perform dependent serial device reset regardless of
+ the value of ExtendeVerification
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Skip by this driver.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
+
+ //
+ // Report progress code here
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
+ TerminalDevice->DevicePath
+ );
+
+ Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
+
+ //
+ // Make all the internal buffer empty for keys
+ //
+ TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail;
+ TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;
+ TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail;
+ TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail;
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
+ TerminalDevice->DevicePath
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
+
+ @param This Indicates the calling context.
+ @param Key A pointer to a buffer that is filled in with the
+ keystroke information for the key that was sent
+ from terminal.
+
+ @retval EFI_SUCCESS The keystroke information is returned successfully.
+ @retval EFI_NOT_READY There is no keystroke data available.
+ @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ //
+ // get TERMINAL_DEV from "This" parameter.
+ //
+ TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
+
+ Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Check if the key already has been registered.
+
+ If both RegsiteredData and InputData is NULL, then ASSERT().
+
+ @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 FALSE 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;
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ TerminalConInWaitForKey (Event, Context);
+}
+
+//
+// Simple Text Input Ex protocol functions
+//
+
+/**
+ Reset the input device and optionally 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
+TerminalConInResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence 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 available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due
+ to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ return ReadKeyStrokeWorker (TerminalDevice, 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
+TerminalConInSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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 for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
+ @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 necessary data
+ structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConInRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+ NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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
+TerminalConInUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ LIST_ENTRY *Link;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ LIST_ENTRY *NotifyList;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
+
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ gBS->FreePool (CurrentNotify);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Can not find the matching entry in database.
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Translate raw data into Unicode (according to different encode), and
+ translate Unicode into key information. (according to different standard).
+
+ @param TerminalDevice Terminal driver private structure.
+
+**/
+VOID
+TranslateRawDataToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ switch (TerminalDevice->TerminalType) {
+
+ case TerminalTypePcAnsi:
+ case TerminalTypeVt100:
+ case TerminalTypeVt100Plus:
+ case TerminalTypeTtyTerm:
+ case TerminalTypeLinux:
+ case TerminalTypeXtermR6:
+ case TerminalTypeVt400:
+ case TerminalTypeSCO:
+ AnsiRawDataToUnicode (TerminalDevice);
+ UnicodeToEfiKey (TerminalDevice);
+ break;
+
+ case TerminalTypeVtUtf8:
+ //
+ // Process all the raw data in the RawFIFO,
+ // put the processed key into UnicodeFIFO.
+ //
+ VTUTF8RawDataToUnicode (TerminalDevice);
+
+ //
+ // Translate all the Unicode data in the UnicodeFIFO to Efi key,
+ // then put into EfiKeyFIFO.
+ //
+ UnicodeToEfiKey (TerminalDevice);
+
+ break;
+ }
+}
+
+/**
+ Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+TerminalConInWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Someone is waiting on the keystroke event, if there's
+ // a key pending, signal the event
+ //
+ if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {
+
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Timer handler to poll the key from serial.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+TerminalConInTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+ UINT32 Control;
+ UINT8 Input;
+ EFI_SERIAL_IO_MODE *Mode;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ UINTN SerialInTimeOut;
+
+ TerminalDevice = (TERMINAL_DEV *) Context;
+
+ SerialIo = TerminalDevice->SerialIo;
+ if (SerialIo == NULL) {
+ return ;
+ }
+ //
+ // if current timeout value for serial device is not identical with
+ // the value saved in TERMINAL_DEV structure, then recalculate the
+ // timeout value again and set serial attribute according to this value.
+ //
+ Mode = SerialIo->Mode;
+ if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
+
+ SerialInTimeOut = 0;
+ if (Mode->BaudRate != 0) {
+ //
+ // According to BAUD rate to calculate the timeout value.
+ //
+ SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
+ }
+
+ Status = SerialIo->SetAttributes (
+ SerialIo,
+ Mode->BaudRate,
+ Mode->ReceiveFifoDepth,
+ (UINT32) SerialInTimeOut,
+ (EFI_PARITY_TYPE) (Mode->Parity),
+ (UINT8) Mode->DataBits,
+ (EFI_STOP_BITS_TYPE) (Mode->StopBits)
+ );
+
+ if (EFI_ERROR (Status)) {
+ TerminalDevice->SerialInTimeOut = 0;
+ } else {
+ TerminalDevice->SerialInTimeOut = SerialInTimeOut;
+ }
+ }
+ //
+ // Check whether serial buffer is empty.
+ // Skip the key transfer loop only if the SerialIo protocol instance
+ // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
+ //
+ Status = SerialIo->GetControl (SerialIo, &Control);
+ if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) {
+ //
+ // Fetch all the keys in the serial buffer,
+ // and insert the byte stream into RawFIFO.
+ //
+ while (!IsRawFiFoFull (TerminalDevice)) {
+
+ Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
+ TerminalDevice->DevicePath
+ );
+ }
+ break;
+ }
+
+ RawFiFoInsertOneKey (TerminalDevice, Input);
+ }
+ }
+
+ //
+ // Translate all the raw data in RawFIFO into EFI Key,
+ // according to different terminal type supported.
+ //
+ TranslateRawDataToEfiKey (TerminalDevice);
+}
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BOOLEAN HasKey;
+ TERMINAL_DEV *TerminalDevice;
+ EFI_INPUT_KEY Key;
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_TPL OldTpl;
+
+ TerminalDevice = (TERMINAL_DEV *) Context;
+
+ //
+ // Invoke notification functions.
+ //
+ NotifyList = &TerminalDevice->NotifyList;
+ while (TRUE) {
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key);
+ CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));
+ KeyData.KeyState.KeyShiftState = 0;
+ KeyData.KeyState.KeyToggleState = 0;
+ //
+ // Leave critical section
+ //
+ gBS->RestoreTPL (OldTpl);
+ if (!HasKey) {
+ break;
+ }
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+ }
+}
+
+/**
+ Get one key out of serial buffer.
+
+ @param SerialIo Serial I/O protocol attached to the serial device.
+ @param Output The fetched key.
+
+ @retval EFI_NOT_READY If serial buffer is empty.
+ @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
+ @retval EFI_SUCCESS If reading serial buffer successfully, put
+ the fetched key to the parameter output.
+
+**/
+EFI_STATUS
+GetOneKeyFromSerial (
+ EFI_SERIAL_IO_PROTOCOL *SerialIo,
+ UINT8 *Output
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Size = 1;
+ *Output = 0;
+
+ //
+ // Read one key from serial I/O device.
+ //
+ Status = SerialIo->Read (SerialIo, &Size, Output);
+
+ if (EFI_ERROR (Status)) {
+
+ if (Status == EFI_TIMEOUT) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ }
+
+ if (*Output == 0) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert one byte raw data into the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+RawFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 Input
+ )
+{
+ UINT8 Tail;
+
+ Tail = TerminalDevice->RawFiFo->Tail;
+
+ if (IsRawFiFoFull (TerminalDevice)) {
+ //
+ // Raw FIFO is full
+ //
+ return FALSE;
+ }
+
+ TerminalDevice->RawFiFo->Data[Tail] = Input;
+
+ TerminalDevice->RawFiFo->Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the Raw Data FIFO.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+RawFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT8 *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->RawFiFo->Head;
+
+ if (IsRawFiFoEmpty (TerminalDevice)) {
+ //
+ // FIFO is empty
+ //
+ *Output = 0;
+ return FALSE;
+ }
+
+ *Output = TerminalDevice->RawFiFo->Data[Head];
+
+ TerminalDevice->RawFiFo->Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Clarify whether Raw Data FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is empty.
+ @retval FALSE If Raw Data FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsRawFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether Raw Data FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Raw Data FIFO buffer is full.
+ @retval FALSE If Raw Data FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsRawFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->RawFiFo->Tail;
+ Head = TerminalDevice->RawFiFo->Head;
+
+ if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoForNotifyInsertOneKey (
+ EFI_KEY_FIFO *EfiKeyFiFo,
+ EFI_INPUT_KEY *Input
+ )
+{
+ UINT8 Tail;
+
+ Tail = EfiKeyFiFo->Tail;
+
+ if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) {
+ //
+ // FIFO is full
+ //
+ return FALSE;
+ }
+
+ CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY));
+
+ EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+ @param Output The key will be removed.
+
+ @retval TRUE If remove successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoForNotifyRemoveOneKey (
+ EFI_KEY_FIFO *EfiKeyFiFo,
+ EFI_INPUT_KEY *Output
+ )
+{
+ UINT8 Head;
+
+ Head = EfiKeyFiFo->Head;
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);
+
+ if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) {
+ //
+ // FIFO is empty
+ //
+ Output->ScanCode = SCAN_NULL;
+ Output->UnicodeChar = 0;
+ return FALSE;
+ }
+
+ CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
+
+ EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoForNotifyEmpty (
+ EFI_KEY_FIFO *EfiKeyFiFo
+ )
+{
+ if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoForNotifyFull (
+ EFI_KEY_FIFO *EfiKeyFiFo
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = EfiKeyFiFo->Tail;
+ Head = EfiKeyFiFo->Head;
+
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Insert one pre-fetched key into the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Key The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+EfiKeyFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Key
+ )
+{
+ UINT8 Tail;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_KEY_DATA KeyData;
+
+ Tail = TerminalDevice->EfiKeyFiFo->Tail;
+
+ CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
+ KeyData.KeyState.KeyShiftState = 0;
+ KeyData.KeyState.KeyToggleState = 0;
+
+ //
+ // Signal KeyNotify process event if this key pressed matches any key registered.
+ //
+ NotifyList = &TerminalDevice->NotifyList;
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
+ CurrentNotify = CR (
+ Link,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ //
+ // The key notification function needs to run at TPL_CALLBACK
+ // while current TPL is TPL_NOTIFY. It will be invoked in
+ // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+ //
+ EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key);
+ gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent);
+ break;
+ }
+ }
+ if (IsEfiKeyFiFoFull (TerminalDevice)) {
+ //
+ // Efi Key FIFO is full
+ //
+ return FALSE;
+ }
+
+ CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
+
+ TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If FIFO buffer is empty before remove operation.
+
+**/
+BOOLEAN
+EfiKeyFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ EFI_INPUT_KEY *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->EfiKeyFiFo->Head;
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);
+
+ if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
+ //
+ // FIFO is empty
+ //
+ Output->ScanCode = SCAN_NULL;
+ Output->UnicodeChar = 0;
+ return FALSE;
+ }
+
+ CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
+
+ TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Clarify whether FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is empty.
+ @retval FALSE If FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If FIFO buffer is full.
+ @retval FALSE If FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsEfiKeyFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->EfiKeyFiFo->Tail;
+ Head = TerminalDevice->EfiKeyFiFo->Head;
+
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Insert one pre-fetched key into the Unicode FIFO buffer.
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Input The key will be input.
+
+ @retval TRUE If insert successfully.
+ @retval FALSE If Unicode FIFO buffer is full before key insertion,
+ and the key is lost.
+
+**/
+BOOLEAN
+UnicodeFiFoInsertOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 Input
+ )
+{
+ UINT8 Tail;
+
+ Tail = TerminalDevice->UnicodeFiFo->Tail;
+ ASSERT (Tail < FIFO_MAX_NUMBER + 1);
+
+
+ if (IsUnicodeFiFoFull (TerminalDevice)) {
+ //
+ // Unicode FIFO is full
+ //
+ return FALSE;
+ }
+
+ TerminalDevice->UnicodeFiFo->Data[Tail] = Input;
+
+ TerminalDevice->UnicodeFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
+
+ return TRUE;
+}
+
+/**
+ Remove one pre-fetched key out of the Unicode FIFO buffer.
+ The caller should guarantee that Unicode FIFO buffer is not empty
+ by IsUnicodeFiFoEmpty ().
+
+ @param TerminalDevice Terminal driver private structure.
+ @param Output The key will be removed.
+
+**/
+VOID
+UnicodeFiFoRemoveOneKey (
+ TERMINAL_DEV *TerminalDevice,
+ UINT16 *Output
+ )
+{
+ UINT8 Head;
+
+ Head = TerminalDevice->UnicodeFiFo->Head;
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);
+
+ *Output = TerminalDevice->UnicodeFiFo->Data[Head];
+
+ TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
+}
+
+/**
+ Clarify whether Unicode FIFO buffer is empty.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is empty.
+ @retval FALSE If Unicode FIFO buffer is not empty.
+
+**/
+BOOLEAN
+IsUnicodeFiFoEmpty (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Clarify whether Unicode FIFO buffer is full.
+
+ @param TerminalDevice Terminal driver private structure
+
+ @retval TRUE If Unicode FIFO buffer is full.
+ @retval FALSE If Unicode FIFO buffer is not full.
+
+**/
+BOOLEAN
+IsUnicodeFiFoFull (
+ TERMINAL_DEV *TerminalDevice
+ )
+{
+ UINT8 Tail;
+ UINT8 Head;
+
+ Tail = TerminalDevice->UnicodeFiFo->Tail;
+ Head = TerminalDevice->UnicodeFiFo->Head;
+
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Update the Unicode characters from a terminal input device into EFI Keys FIFO.
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKeyFlushState (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_INPUT_KEY Key;
+ UINT32 InputState;
+
+ InputState = TerminalDevice->InputState;
+
+ if (IsEfiKeyFiFoFull (TerminalDevice)) {
+ return;
+ }
+
+ if ((InputState & INPUT_STATE_ESC) != 0) {
+ Key.ScanCode = SCAN_ESC;
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_CSI) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = CSI;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = LEFTOPENBRACKET;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_O) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = 'O';
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ if ((InputState & INPUT_STATE_2) != 0) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = '2';
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+
+ //
+ // Cancel the timer.
+ //
+ gBS->SetTimer (
+ TerminalDevice->TwoSecondTimeOut,
+ TimerCancel,
+ 0
+ );
+
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+}
+
+
+/**
+ Converts a stream of Unicode characters from a terminal input device into EFI Keys that
+ can be read through the Simple Input Protocol.
+
+ The table below shows the keyboard input mappings that this function supports.
+ If the ESC sequence listed in one of the columns is presented, then it is translated
+ into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
+ key strokes are converted into EFI Keys.
+
+ 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
+ completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
+ converted into EFI Keys.
+ There is one special input sequence that will force the system to reset.
+ This is ESC R ESC r ESC R.
+
+ Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
+ The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
+ DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
+
+ Symbols used in table below
+ ===========================
+ ESC = 0x1B
+ CSI = 0x9B
+ DEL = 0x7f
+ ^ = CTRL
+
+ +=========+======+===========+==========+==========+
+ | | EFI | UEFI 2.0 | | |
+ | | Scan | | VT100+ | |
+ | KEY | Code | PC ANSI | VTUTF8 | VT100 |
+ +=========+======+===========+==========+==========+
+ | NULL | 0x00 | | | |
+ | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
+ | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
+ | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
+ | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
+ | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
+ | END | 0x06 | ESC [ F | ESC k | ESC [ K |
+ | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
+ | | | ESC [ L | | ESC [ L |
+ | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
+ | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
+ | | | | | ESC [ ? |
+ | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
+ | | | | | ESC [ / |
+ | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
+ | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
+ | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
+ | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
+ | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
+ | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
+ | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
+ | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
+ | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
+ | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
+ | Escape | 0x17 | ESC | ESC | ESC |
+ | F11 | 0x15 | | ESC ! | |
+ | F12 | 0x16 | | ESC @ | |
+ +=========+======+===========+==========+==========+
+
+Putty function key map:
+ +=========+======+===========+=============+=============+=============+=========+
+ | | EFI | | | | | |
+ | | Scan | | | Normal | | |
+ | KEY | Code | VT100+ | Xterm R6 | VT400 | Linux | SCO |
+ +=========+======+===========+=============+=============+=============+=========+
+ | F1 | 0x0B | ESC O P | ESC O P | ESC [ 1 1 ~ | ESC [ [ A | ESC [ M |
+ | F2 | 0x0C | ESC O Q | ESC O Q | ESC [ 1 2 ~ | ESC [ [ B | ESC [ N |
+ | F3 | 0x0D | ESC O R | ESC O R | ESC [ 1 3 ~ | ESC [ [ C | ESC [ O |
+ | F4 | 0x0E | ESC O S | ESC O S | ESC [ 1 4 ~ | ESC [ [ D | ESC [ P |
+ | F5 | 0x0F | ESC O T | ESC [ 1 5 ~ | ESC [ 1 5 ~ | ESC [ [ E | ESC [ Q |
+ | F6 | 0x10 | ESC O U | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ R |
+ | F7 | 0x11 | ESC O V | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ S |
+ | F8 | 0x12 | ESC O W | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ T |
+ | F9 | 0x13 | ESC O X | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ U |
+ | F10 | 0x14 | ESC O Y | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ V |
+ | Escape | 0x17 | ESC | ESC | ESC | ESC | ESC |
+ | F11 | 0x15 | ESC O Z | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ W |
+ | F12 | 0x16 | ESC O [ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ X |
+ +=========+======+===========+=============+=============+=============+=========+
+
+ Special Mappings
+ ================
+ ESC R ESC r ESC R = Reset System
+
+ @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
+
+**/
+VOID
+UnicodeToEfiKey (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS TimerStatus;
+ UINT16 UnicodeChar;
+ EFI_INPUT_KEY Key;
+ BOOLEAN SetDefaultResetState;
+
+ TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
+
+ if (!EFI_ERROR (TimerStatus)) {
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
+
+ if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
+ //
+ // Check to see if the 2 seconds timer has expired
+ //
+ TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
+ if (!EFI_ERROR (TimerStatus)) {
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+ }
+
+ //
+ // Fetch one Unicode character from the Unicode FIFO
+ //
+ UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
+
+ SetDefaultResetState = TRUE;
+
+ switch (TerminalDevice->InputState) {
+ case INPUT_STATE_DEFAULT:
+
+ break;
+
+ case INPUT_STATE_ESC:
+
+ if (UnicodeChar == LEFTOPENBRACKET) {
+ TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ continue;
+ }
+
+ if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == TerminalTypeVt100 ||
+ TerminalDevice->TerminalType == TerminalTypeTtyTerm ||
+ TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt100Plus)) {
+ TerminalDevice->InputState |= INPUT_STATE_O;
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ continue;
+ }
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == TerminalTypeVt100Plus ||
+ TerminalDevice->TerminalType == TerminalTypeVtUtf8) {
+ switch (UnicodeChar) {
+ case '1':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case '2':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case '3':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case '4':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case '5':
+ Key.ScanCode = SCAN_F5;
+ break;
+ case '6':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case '7':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case '8':
+ Key.ScanCode = SCAN_F8;
+ break;
+ case '9':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case '0':
+ Key.ScanCode = SCAN_F10;
+ break;
+ case '!':
+ Key.ScanCode = SCAN_F11;
+ break;
+ case '@':
+ Key.ScanCode = SCAN_F12;
+ break;
+ case 'h':
+ Key.ScanCode = SCAN_HOME;
+ break;
+ case 'k':
+ Key.ScanCode = SCAN_END;
+ break;
+ case '+':
+ Key.ScanCode = SCAN_INSERT;
+ break;
+ case '-':
+ Key.ScanCode = SCAN_DELETE;
+ break;
+ case '/':
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ break;
+ case '?':
+ Key.ScanCode = SCAN_PAGE_UP;
+ break;
+ default :
+ break;
+ }
+ }
+
+ switch (UnicodeChar) {
+ case 'R':
+ if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
+ TerminalDevice->ResetState = RESET_STATE_ESC_R;
+ SetDefaultResetState = FALSE;
+ } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ Key.ScanCode = SCAN_NULL;
+ break;
+ case 'r':
+ if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
+ TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
+ SetDefaultResetState = FALSE;
+ }
+ Key.ScanCode = SCAN_NULL;
+ break;
+ default :
+ break;
+ }
+
+ if (SetDefaultResetState) {
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_O:
+
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == TerminalTypeVt100) {
+ switch (UnicodeChar) {
+ case 'P':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'Q':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'w':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'x':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case 't':
+ Key.ScanCode = SCAN_F5;
+ break;
+ case 'u':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case 'q':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case 'r':
+ Key.ScanCode = SCAN_F8;
+ break;
+ case 'p':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case 'M':
+ Key.ScanCode = SCAN_F10;
+ break;
+ default :
+ break;
+ }
+ } else if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
+ /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */
+ switch (UnicodeChar) {
+ case 'P':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'Q':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'R':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'S':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case 'H':
+ Key.ScanCode = SCAN_HOME;
+ break;
+ case 'F':
+ Key.ScanCode = SCAN_END;
+ break;
+ }
+ } else if (TerminalDevice->TerminalType == TerminalTypeVt100Plus) {
+ switch (UnicodeChar) {
+ case 'P':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'Q':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'R':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'S':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case 'T':
+ Key.ScanCode = SCAN_F5;
+ break;
+ case 'U':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case 'V':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case 'W':
+ Key.ScanCode = SCAN_F8;
+ break;
+ case 'X':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case 'Y':
+ Key.ScanCode = SCAN_F10;
+ break;
+ case 'Z':
+ Key.ScanCode = SCAN_F11;
+ break;
+ case '[':
+ Key.ScanCode = SCAN_F12;
+ break;
+ }
+ } else if (TerminalDevice->TerminalType == TerminalTypeXtermR6) {
+ switch (UnicodeChar) {
+ case 'P':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'Q':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'R':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'S':
+ Key.ScanCode = SCAN_F4;
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
+
+ if (UnicodeChar == '1' && (TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400 ||
+ TerminalDevice->TerminalType == TerminalTypeLinux)) {
+ TerminalDevice->InputState |= INPUT_STATE_1;
+ continue;
+ }
+
+ if (UnicodeChar == '2' && (TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400 ||
+ TerminalDevice->TerminalType == TerminalTypeLinux)) {
+ TerminalDevice->InputState |= INPUT_STATE_2;
+ continue;
+ }
+
+ if (UnicodeChar == LEFTOPENBRACKET && TerminalDevice->TerminalType == TerminalTypeLinux) {
+ TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2ND;
+ continue;
+ }
+
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeVt100 ||
+ TerminalDevice->TerminalType == TerminalTypeVt100Plus ||
+ TerminalDevice->TerminalType == TerminalTypeVtUtf8 ||
+ TerminalDevice->TerminalType == TerminalTypeTtyTerm ||
+ TerminalDevice->TerminalType == TerminalTypeLinux ||
+ TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400 ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ switch (UnicodeChar) {
+ case 'A':
+ Key.ScanCode = SCAN_UP;
+ break;
+ case 'B':
+ Key.ScanCode = SCAN_DOWN;
+ break;
+ case 'C':
+ Key.ScanCode = SCAN_RIGHT;
+ break;
+ case 'D':
+ Key.ScanCode = SCAN_LEFT;
+ break;
+ case 'H':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeVt100 ||
+ TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
+ Key.ScanCode = SCAN_HOME;
+ }
+ break;
+ case 'F':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
+ Key.ScanCode = SCAN_END;
+ }
+ break;
+ case 'K':
+ if (TerminalDevice->TerminalType == TerminalTypeVt100) {
+ Key.ScanCode = SCAN_END;
+ }
+ break;
+ case 'L':
+ case '@':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeVt100) {
+ Key.ScanCode = SCAN_INSERT;
+ }
+ break;
+ case 'X':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
+ Key.ScanCode = SCAN_DELETE;
+ } else if (TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F12;
+ }
+ break;
+ case 'P':
+ if (TerminalDevice->TerminalType == TerminalTypeVt100) {
+ Key.ScanCode = SCAN_DELETE;
+ } else if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F4;
+ }
+ break;
+ case 'I':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
+ Key.ScanCode = SCAN_PAGE_UP;
+ }
+ break;
+ case 'V':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F10;
+ }
+ break;
+ case '?':
+ if (TerminalDevice->TerminalType == TerminalTypeVt100) {
+ Key.ScanCode = SCAN_PAGE_UP;
+ }
+ break;
+ case 'G':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ }
+ break;
+ case 'U':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F9;
+ }
+ break;
+ case '/':
+ if (TerminalDevice->TerminalType == TerminalTypeVt100) {
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ }
+ break;
+ case 'M':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F1;
+ }
+ break;
+ case 'N':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F2;
+ }
+ break;
+ case 'O':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F3;
+ }
+ break;
+ case 'Q':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F5;
+ }
+ break;
+ case 'R':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F6;
+ }
+ break;
+ case 'S':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F7;
+ }
+ break;
+ case 'T':
+ if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||
+ TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F8;
+ }
+ break;
+ case 'W':
+ if (TerminalDevice->TerminalType == TerminalTypeSCO) {
+ Key.ScanCode = SCAN_F11;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ /*
+ * The VT220 escape codes that the TTY terminal accepts all have
+ * numeric codes, and there are no ambiguous prefixes shared with
+ * other terminal types.
+ */
+ if (TerminalDevice->TerminalType == TerminalTypeTtyTerm &&
+ Key.ScanCode == SCAN_NULL &&
+ UnicodeChar >= '0' &&
+ UnicodeChar <= '9') {
+ TerminalDevice->TtyEscapeStr[0] = UnicodeChar;
+ TerminalDevice->TtyEscapeIndex = 1;
+ TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_TTY;
+ continue;
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_1:
+
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400 ||
+ TerminalDevice->TerminalType == TerminalTypeLinux) {
+ switch (UnicodeChar) {
+ case '1':
+ if (TerminalDevice->TerminalType == TerminalTypeVt400) {
+ Key.ScanCode = SCAN_F1;
+ }
+ break;
+ case '2':
+ if (TerminalDevice->TerminalType == TerminalTypeVt400) {
+ Key.ScanCode = SCAN_F2;
+ }
+ break;
+ case '3':
+ if (TerminalDevice->TerminalType == TerminalTypeVt400) {
+ Key.ScanCode = SCAN_F3;
+ }
+ break;
+ case '4':
+ if (TerminalDevice->TerminalType == TerminalTypeVt400) {
+ Key.ScanCode = SCAN_F4;
+ }
+ break;
+ case '5':
+ if (TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400) {
+ Key.ScanCode = SCAN_F5;
+ }
+ break;
+ case '7':
+ Key.ScanCode = SCAN_F6;
+ break;
+ case '8':
+ Key.ScanCode = SCAN_F7;
+ break;
+ case '9':
+ Key.ScanCode = SCAN_F8;
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_2:
+
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ Key.ScanCode = SCAN_NULL;
+ if (TerminalDevice->TerminalType == TerminalTypeXtermR6 ||
+ TerminalDevice->TerminalType == TerminalTypeVt400 ||
+ TerminalDevice->TerminalType == TerminalTypeLinux) {
+ switch (UnicodeChar) {
+ case '0':
+ Key.ScanCode = SCAN_F9;
+ break;
+ case '1':
+ Key.ScanCode = SCAN_F10;
+ break;
+ case '3':
+ Key.ScanCode = SCAN_F11;
+ break;
+ case '4':
+ Key.ScanCode = SCAN_F12;
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2ND:
+
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ Key.ScanCode = SCAN_NULL;
+
+ if (TerminalDevice->TerminalType == TerminalTypeLinux) {
+ switch (UnicodeChar) {
+ case 'A':
+ Key.ScanCode = SCAN_F1;
+ break;
+ case 'B':
+ Key.ScanCode = SCAN_F2;
+ break;
+ case 'C':
+ Key.ScanCode = SCAN_F3;
+ break;
+ case 'D':
+ Key.ScanCode = SCAN_F4;
+ break;
+ case 'E':
+ Key.ScanCode = SCAN_F5;
+ break;
+ }
+ }
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+
+ case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_TTY:
+ /*
+ * Here we handle the VT220 escape codes that we accept. This
+ * state is only used by the TTY terminal type.
+ */
+ Key.ScanCode = SCAN_NULL;
+ if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
+
+ if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) {
+ UINT16 EscCode;
+ TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */
+ EscCode = (UINT16) StrDecimalToUintn(TerminalDevice->TtyEscapeStr);
+ switch (EscCode) {
+ case 2:
+ Key.ScanCode = SCAN_INSERT;
+ break;
+ case 3:
+ Key.ScanCode = SCAN_DELETE;
+ break;
+ case 5:
+ Key.ScanCode = SCAN_PAGE_UP;
+ break;
+ case 6:
+ Key.ScanCode = SCAN_PAGE_DOWN;
+ break;
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ Key.ScanCode = SCAN_F1 + EscCode - 11;
+ break;
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ Key.ScanCode = SCAN_F6 + EscCode - 17;
+ break;
+ case 23:
+ case 24:
+ Key.ScanCode = SCAN_F11 + EscCode - 23;
+ break;
+ default:
+ break;
+ }
+ } else if (TerminalDevice->TtyEscapeIndex == 1){
+ /* 2 character escape code */
+ TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar;
+ continue;
+ }
+ else {
+ DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n"));
+ }
+ }
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+ if (Key.ScanCode != SCAN_NULL) {
+ Key.UnicodeChar = 0;
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ continue;
+ }
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+ break;
+
+ default:
+ //
+ // Invalid state. This should never happen.
+ //
+ ASSERT (FALSE);
+
+ UnicodeToEfiKeyFlushState (TerminalDevice);
+
+ break;
+ }
+
+ if (UnicodeChar == ESC) {
+ TerminalDevice->InputState = INPUT_STATE_ESC;
+ }
+
+ if (UnicodeChar == CSI) {
+ TerminalDevice->InputState = INPUT_STATE_CSI;
+ }
+
+ if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
+ Status = gBS->SetTimer(
+ TerminalDevice->TwoSecondTimeOut,
+ TimerRelative,
+ (UINT64)20000000
+ );
+ ASSERT_EFI_ERROR (Status);
+ continue;
+ }
+
+ if (SetDefaultResetState) {
+ TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+ }
+
+ if (UnicodeChar == DEL) {
+ if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = CHAR_BACKSPACE;
+ }
+ else {
+ Key.ScanCode = SCAN_DELETE;
+ Key.UnicodeChar = 0;
+ }
+ } else {
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = UnicodeChar;
+ }
+
+ EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
new file mode 100644
index 000000000..aae470e95
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
@@ -0,0 +1,959 @@
+/** @file
+ Implementation for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Terminal.h"
+
+//
+// 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, '^', L'^' },
+ { GEOMETRICSHAPE_RIGHT_TRIANGLE, '>', L'>' },
+ { GEOMETRICSHAPE_DOWN_TRIANGLE, 'v', L'v' },
+ { GEOMETRICSHAPE_LEFT_TRIANGLE, '<', L'<' },
+
+ { ARROW_LEFT, '<', L'<' },
+ { ARROW_UP, '^', L'^' },
+ { ARROW_RIGHT, '>', L'>' },
+ { ARROW_DOWN, 'v', L'v' },
+
+ { 0x0000, 0x00, L'\0' }
+};
+
+CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 };
+CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 };
+CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 };
+CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 };
+CHAR16 mCursorForwardString[] = { ESC, '[', '0', '0', 'C', 0 };
+CHAR16 mCursorBackwardString[] = { ESC, '[', '0', '0', 'D', 0 };
+
+//
+// Body of the ConOut functions
+//
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+
+ If ExtendeVerification is TRUE, then perform dependent serial device reset,
+ and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Indicates the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The reset operation succeeds.
+ @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // Perform a more exhaustive reset by resetting the serial port.
+ //
+ if (ExtendedVerification) {
+ //
+ // Report progress code here
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
+ TerminalDevice->DevicePath
+ );
+
+ Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
+ if (EFI_ERROR (Status)) {
+ //
+ // Report error code here
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
+ TerminalDevice->DevicePath
+ );
+
+ return Status;
+ }
+ }
+
+ This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
+
+ Status = This->SetMode (This, 0);
+
+ return Status;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+
+ The Unicode string will be converted to terminal expressible data stream
+ and send to terminal via serial port.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be displayed
+ on the terminal screen.
+
+ @retval EFI_SUCCESS The string is output successfully.
+ @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
+ @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
+ be rendered and are skipped.
+ @retval EFI_UNSUPPORTED If current display mode is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ UINTN Length;
+ UTF8_CHAR Utf8Char;
+ CHAR8 GraphicChar;
+ CHAR8 AsciiChar;
+ EFI_STATUS Status;
+ UINT8 ValidBytes;
+ CHAR8 CrLfStr[2];
+ //
+ // flag used to indicate whether condition happens which will cause
+ // return EFI_WARN_UNKNOWN_GLYPH
+ //
+ BOOLEAN Warning;
+
+ ValidBytes = 0;
+ Warning = FALSE;
+ AsciiChar = 0;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // Get current display mode
+ //
+ Mode = This->Mode;
+
+ if (Mode->Mode >= Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ This->QueryMode (
+ This,
+ Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+
+ for (; *WString != CHAR_NULL; WString++) {
+
+ switch (TerminalDevice->TerminalType) {
+
+ case TerminalTypePcAnsi:
+ case TerminalTypeVt100:
+ case TerminalTypeVt100Plus:
+ case TerminalTypeTtyTerm:
+ case TerminalTypeLinux:
+ case TerminalTypeXtermR6:
+ case TerminalTypeVt400:
+ case TerminalTypeSCO:
+
+ if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) {
+ //
+ // If it's not a graphic character convert Unicode to ASCII.
+ //
+ GraphicChar = (CHAR8) *WString;
+
+ if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) {
+ //
+ // when this driver use the OutputString to output control string,
+ // TerminalDevice->OutputEscChar is set to let the Esc char
+ // to be output to the terminal emulation software.
+ //
+ if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) {
+ GraphicChar = 27;
+ } else {
+ GraphicChar = '?';
+ Warning = TRUE;
+ }
+ }
+
+ AsciiChar = GraphicChar;
+
+ }
+
+ if (TerminalDevice->TerminalType != TerminalTypePcAnsi) {
+ GraphicChar = AsciiChar;
+ }
+
+ Length = 1;
+
+ Status = TerminalDevice->SerialIo->Write (
+ TerminalDevice->SerialIo,
+ &Length,
+ &GraphicChar
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto OutputError;
+ }
+
+ break;
+
+ case TerminalTypeVtUtf8:
+ UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
+ Length = ValidBytes;
+ Status = TerminalDevice->SerialIo->Write (
+ TerminalDevice->SerialIo,
+ &Length,
+ (UINT8 *) &Utf8Char
+ );
+ if (EFI_ERROR (Status)) {
+ goto OutputError;
+ }
+ break;
+ }
+ //
+ // Update cursor position.
+ //
+ switch (*WString) {
+
+ case CHAR_BACKSPACE:
+ if (Mode->CursorColumn > 0) {
+ Mode->CursorColumn--;
+ }
+ break;
+
+ case CHAR_LINEFEED:
+ if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
+ Mode->CursorRow++;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ Mode->CursorColumn = 0;
+ break;
+
+ default:
+ if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) {
+
+ Mode->CursorColumn++;
+
+ } else {
+
+ Mode->CursorColumn = 0;
+ if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
+ Mode->CursorRow++;
+ }
+
+ if (TerminalDevice->TerminalType == TerminalTypeTtyTerm &&
+ !TerminalDevice->OutputEscChar) {
+ //
+ // We've written the last character on the line. The
+ // terminal doesn't actually wrap its cursor until we print
+ // the next character, but the driver thinks it has wrapped
+ // already. Print CR LF to synchronize the terminal with
+ // the driver, but only if we're not in the middle of
+ // printing an escape sequence.
+ //
+ CrLfStr[0] = '\r';
+ CrLfStr[1] = '\n';
+
+ Length = sizeof(CrLfStr);
+
+ Status = TerminalDevice->SerialIo->Write (
+ TerminalDevice->SerialIo,
+ &Length,
+ CrLfStr
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto OutputError;
+ }
+ }
+ }
+ break;
+
+ };
+
+ }
+
+ if (Warning) {
+ return EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ return EFI_SUCCESS;
+
+OutputError:
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_OUTPUT_ERROR),
+ TerminalDevice->DevicePath
+ );
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+
+ If one of the characters in the *Wstring is
+ neither valid Unicode drawing characters,
+ not ASCII code, then this function will return
+ EFI_UNSUPPORTED.
+
+ @param This Indicates the calling context.
+ @param WString The Null-terminated Unicode string to be tested.
+
+ @retval EFI_SUCCESS The terminal is capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+ EFI_STATUS Status;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ switch (TerminalDevice->TerminalType) {
+
+ case TerminalTypePcAnsi:
+ case TerminalTypeVt100:
+ case TerminalTypeVt100Plus:
+ case TerminalTypeTtyTerm:
+ Status = AnsiTestString (TerminalDevice, WString);
+ break;
+
+ case TerminalTypeVtUtf8:
+ Status = VTUTF8TestString (TerminalDevice, WString);
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+
+ It returns information for an available text mode
+ that the terminal supports.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ TERMINAL_DEV *TerminalDevice;
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+ *Columns = TerminalDevice->TerminalConsoleModeData[ModeNumber].Columns;
+ *Rows = TerminalDevice->TerminalConsoleModeData[ModeNumber].Rows;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUT.SetMode().
+
+ Set the terminal to a specified display mode.
+ In this driver, we only support mode 0.
+
+ @param This Indicates the calling context.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set
+ because of serial device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set the current mode
+ //
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ This->ClearScreen (This);
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mSetModeString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ Status = This->ClearScreen (This);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+
+ @param This Indicates the calling context.
+ @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
+ are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ UINT8 ForegroundControl;
+ UINT8 BackgroundControl;
+ UINT8 BrightControl;
+ INT32 SavedColumn;
+ INT32 SavedRow;
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ SavedColumn = 0;
+ SavedRow = 0;
+
+ //
+ // get Terminal device data structure pointer.
+ //
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // only the bit0..6 of the Attribute is valid
+ //
+ if ((Attribute | 0x7f) != 0x7f) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Skip outputting the command string for the same attribute
+ // It improves the terminal performance significantly
+ //
+ if (This->Mode->Attribute == (INT32) Attribute) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // convert Attribute value to terminal emulator
+ // understandable foreground color
+ //
+ switch (Attribute & 0x07) {
+
+ case EFI_BLACK:
+ ForegroundControl = 30;
+ break;
+
+ case EFI_BLUE:
+ ForegroundControl = 34;
+ break;
+
+ case EFI_GREEN:
+ ForegroundControl = 32;
+ break;
+
+ case EFI_CYAN:
+ ForegroundControl = 36;
+ break;
+
+ case EFI_RED:
+ ForegroundControl = 31;
+ break;
+
+ case EFI_MAGENTA:
+ ForegroundControl = 35;
+ break;
+
+ case EFI_BROWN:
+ ForegroundControl = 33;
+ break;
+
+ default:
+
+ case EFI_LIGHTGRAY:
+ ForegroundControl = 37;
+ break;
+
+ }
+ //
+ // bit4 of the Attribute indicates bright control
+ // of terminal emulator.
+ //
+ BrightControl = (UINT8) ((Attribute >> 3) & 1);
+
+ //
+ // convert Attribute value to terminal emulator
+ // understandable background color.
+ //
+ switch ((Attribute >> 4) & 0x07) {
+
+ case EFI_BLACK:
+ BackgroundControl = 40;
+ break;
+
+ case EFI_BLUE:
+ BackgroundControl = 44;
+ break;
+
+ case EFI_GREEN:
+ BackgroundControl = 42;
+ break;
+
+ case EFI_CYAN:
+ BackgroundControl = 46;
+ break;
+
+ case EFI_RED:
+ BackgroundControl = 41;
+ break;
+
+ case EFI_MAGENTA:
+ BackgroundControl = 45;
+ break;
+
+ case EFI_BROWN:
+ BackgroundControl = 43;
+ break;
+
+ default:
+
+ case EFI_LIGHTGRAY:
+ BackgroundControl = 47;
+ break;
+ }
+ //
+ // terminal emulator's control sequence to set attributes
+ //
+ mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16) ('0' + BrightControl);
+ mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (ForegroundControl / 10));
+ mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (ForegroundControl % 10));
+ mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (BackgroundControl / 10));
+ mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (BackgroundControl % 10));
+
+ //
+ // save current column and row
+ // for future scrolling back use.
+ //
+ SavedColumn = This->Mode->CursorColumn;
+ SavedRow = This->Mode->CursorRow;
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mSetAttributeString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // scroll back to saved cursor position.
+ //
+ This->Mode->CursorColumn = SavedColumn;
+ This->Mode->CursorRow = SavedRow;
+
+ This->Mode->Attribute = (INT32) Attribute;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ It clears the ANSI terminal's display to the
+ currently selected background color.
+
+ @param This Indicates the calling context.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // control sequence for clear screen request
+ //
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, mClearScreenString);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = This->SetCursorPosition (This, 0, 0);
+
+ return Status;
+}
+
+
+/**
+ Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+
+ @param This Indicates the calling context.
+ @param Column The row to set cursor to.
+ @param Row The column to set cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The request fails due to serial port error.
+ @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
+ is invalid for current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ EFI_STATUS Status;
+ TERMINAL_DEV *TerminalDevice;
+ CHAR16 *String;
+
+ TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
+
+ //
+ // get current mode
+ //
+ Mode = This->Mode;
+
+ //
+ // get geometry of current mode
+ //
+ Status = This->QueryMode (
+ This,
+ Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Column >= MaxColumn || Row >= MaxRow) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // control sequence to move the cursor
+ //
+ // Optimize cursor motion control sequences for TtyTerm. Move
+ // within the current line if possible, and don't output anyting if
+ // it isn't necessary.
+ //
+ if (TerminalDevice->TerminalType == TerminalTypeTtyTerm &&
+ (UINTN)Mode->CursorRow == Row) {
+ if ((UINTN)Mode->CursorColumn > Column) {
+ mCursorBackwardString[FW_BACK_OFFSET + 0] = (CHAR16) ('0' + ((Mode->CursorColumn - Column) / 10));
+ mCursorBackwardString[FW_BACK_OFFSET + 1] = (CHAR16) ('0' + ((Mode->CursorColumn - Column) % 10));
+ String = mCursorBackwardString;
+ }
+ else if (Column > (UINTN)Mode->CursorColumn) {
+ mCursorForwardString[FW_BACK_OFFSET + 0] = (CHAR16) ('0' + ((Column - Mode->CursorColumn) / 10));
+ mCursorForwardString[FW_BACK_OFFSET + 1] = (CHAR16) ('0' + ((Column - Mode->CursorColumn) % 10));
+ String = mCursorForwardString;
+ }
+ else {
+ String = L""; // No cursor motion necessary
+ }
+ }
+ else {
+ mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16) ('0' + ((Row + 1) / 10));
+ mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16) ('0' + ((Row + 1) % 10));
+ mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16) ('0' + ((Column + 1) / 10));
+ mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16) ('0' + ((Column + 1) % 10));
+ String = mSetCursorPositionString;
+ }
+
+ TerminalDevice->OutputEscChar = TRUE;
+ Status = This->OutputString (This, String);
+ TerminalDevice->OutputEscChar = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // update current cursor position
+ // in the Mode data structure.
+ //
+ Mode->CursorColumn = (INT32) Column;
+ Mode->CursorRow = (INT32) Row;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ In this driver, the cursor cannot be hidden.
+
+ @param This Indicates the calling context.
+ @param Visible If TRUE, the cursor is set to be visible,
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The request is valid.
+ @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
+
+**/
+EFI_STATUS
+EFIAPI
+TerminalConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ if (!Visible) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Detects if a Unicode char is for Box Drawing text graphics.
+
+ @param Graphic Unicode char to test.
+ @param PcAnsi Optional pointer to return PCANSI equivalent of
+ Graphic.
+ @param Ascii Optional pointer to return ASCII equivalent of
+ Graphic.
+
+ @retval TRUE If Graphic is a supported Unicode Box Drawing character.
+
+**/
+BOOLEAN
+TerminalIsValidTextGraphics (
+ IN CHAR16 Graphic,
+ OUT CHAR8 *PcAnsi, OPTIONAL
+ OUT CHAR8 *Ascii OPTIONAL
+ )
+{
+ UNICODE_TO_CHAR *Table;
+
+ if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
+ //
+ // Unicode drawing code charts are all in the 0x25xx range,
+ // arrows are 0x21xx
+ //
+ return FALSE;
+ }
+
+ 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;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Detects if a valid ASCII char.
+
+ @param Ascii An ASCII character.
+
+ @retval TRUE If it is a valid ASCII character.
+ @retval FALSE If it is not a valid ASCII character.
+
+**/
+BOOLEAN
+TerminalIsValidAscii (
+ IN CHAR16 Ascii
+ )
+{
+ //
+ // valid ascii code lies in the extent of 0x20 ~ 0x7f
+ //
+ if ((Ascii >= 0x20) && (Ascii <= 0x7f)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Detects if a valid EFI control character.
+
+ @param CharC An input EFI Control character.
+
+ @retval TRUE If it is a valid EFI control character.
+ @retval FALSE If it is not a valid EFI control character.
+
+**/
+BOOLEAN
+TerminalIsValidEfiCntlChar (
+ IN CHAR16 CharC
+ )
+{
+ //
+ // only support four control characters.
+ //
+ if (CharC == CHAR_NULL ||
+ CharC == CHAR_BACKSPACE ||
+ CharC == CHAR_LINEFEED ||
+ CharC == CHAR_CARRIAGE_RETURN ||
+ CharC == CHAR_TAB
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
new file mode 100644
index 000000000..b2a8aeba8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
@@ -0,0 +1,98 @@
+## @file
+# Terminal module installs Simple Text Input(ex)/Out protocols for serial devices.
+#
+# This module will install Simple Text Input (Ex) protocol and Simple Test Output
+# protocols based on Serial I/O protocol for serial devices including hotplug serial
+# devices.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TerminalDxe
+ MODULE_UNI_FILE = TerminalDxe.uni
+ FILE_GUID = 9E863906-A40F-4875-977F-5B93FF237FC6
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeTerminal
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gTerminalDriverBinding
+# COMPONENT_NAME = gTerminalComponentName
+# COMPONENT_NAME2 = gTerminalComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Vtutf8.c
+ Ansi.c
+ TerminalConOut.c
+ TerminalConIn.c
+ Terminal.c
+ Terminal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ ReportStatusCodeLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ BaseLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"ConInDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConInDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOutDev"
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOutDev"
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOutDev"
+ gEfiGlobalVariableGuid
+ gEfiVTUTF8Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiVT100Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiVT100PlusGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiPcAnsiGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEfiTtyTermGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiLinuxTermGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiXtermR6Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiVT400Guid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiSCOTermGuid ## SOMETIMES_CONSUMES ## GUID # used with a Vendor-Defined Messaging Device Path
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiSerialIoProtocolGuid ## TO_START
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ gEfiSimpleTextOutProtocolGuid ## BY_START
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## CONSUMES
+
+# [Event]
+# # Relative timer event set by UnicodeToEfiKey(), used to be one 2 seconds input timeout.
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+# # Period timer event to invoke TerminalConInTimerHandler(), period value is KEYBOARD_TIMER_INTERVAL and used to poll the key from serial
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TerminalDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.uni b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.uni
new file mode 100644
index 000000000..0048229a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Terminal module installs Simple Text Input(ex)/Out protocols for serial devices.
+//
+// This module will install Simple Text Input (Ex) protocol and Simple Test Output
+// protocols based on Serial I/O protocol for serial devices including hotplug serial
+// devices.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Terminal module installs Simple Text Input(ex)/Out protocols for serial devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will install Simple Text Input (Ex) protocol and Simple Test Output protocols based on Serial I/O protocol for serial devices including hotplug serial devices."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxeExtra.uni
new file mode 100644
index 000000000..018a9c817
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// TerminalDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Terminal DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c
new file mode 100644
index 000000000..9cf52d90b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Console/TerminalDxe/Vtutf8.c
@@ -0,0 +1,322 @@
+/** @file
+ Implementation of translation upon VT-UTF8.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Terminal.h"
+
+/**
+ Translate all VT-UTF8 characters in the Raw FIFI into unicode characters,
+ and insert them into Unicode FIFO.
+
+ @param TerminalDevice The terminal device.
+
+**/
+VOID
+VTUTF8RawDataToUnicode (
+ IN TERMINAL_DEV *TerminalDevice
+ )
+{
+ UTF8_CHAR Utf8Char;
+ UINT8 ValidBytes;
+ UINT16 UnicodeChar;
+
+ ValidBytes = 0;
+ //
+ // pop the raw data out from the raw fifo,
+ // and translate it into unicode, then push
+ // the unicode into unicode fifo, until the raw fifo is empty.
+ //
+ while (!IsRawFiFoEmpty (TerminalDevice) && !IsUnicodeFiFoFull (TerminalDevice)) {
+
+ GetOneValidUtf8Char (TerminalDevice, &Utf8Char, &ValidBytes);
+
+ if (ValidBytes < 1 || ValidBytes > 3) {
+ continue;
+ }
+
+ Utf8ToUnicode (Utf8Char, ValidBytes, (CHAR16 *) &UnicodeChar);
+
+ UnicodeFiFoInsertOneKey (TerminalDevice, UnicodeChar);
+ }
+}
+
+/**
+ Get one valid VT-UTF8 characters set from Raw Data FIFO.
+
+ @param Utf8Device The terminal device.
+ @param Utf8Char Returned valid VT-UTF8 characters set.
+ @param ValidBytes The count of returned VT-VTF8 characters.
+ If ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+GetOneValidUtf8Char (
+ IN TERMINAL_DEV *Utf8Device,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ )
+{
+ UINT8 Temp;
+ UINT8 Index;
+ BOOLEAN FetchFlag;
+
+ Temp = 0;
+ Index = 0;
+ FetchFlag = TRUE;
+
+ //
+ // if no valid Utf8 char is found in the RawFiFo,
+ // then *ValidBytes will be zero.
+ //
+ *ValidBytes = 0;
+
+ while (!IsRawFiFoEmpty (Utf8Device)) {
+
+ RawFiFoRemoveOneKey (Utf8Device, &Temp);
+
+ switch (*ValidBytes) {
+
+ case 0:
+ if ((Temp & 0x80) == 0) {
+ //
+ // one-byte utf8 char
+ //
+ *ValidBytes = 1;
+
+ Utf8Char->Utf8_1 = Temp;
+
+ FetchFlag = FALSE;
+
+ } else if ((Temp & 0xe0) == 0xc0) {
+ //
+ // two-byte utf8 char
+ //
+ *ValidBytes = 2;
+
+ Utf8Char->Utf8_2[1] = Temp;
+
+ } else if ((Temp & 0xf0) == 0xe0) {
+ //
+ // three-byte utf8 char
+ //
+ *ValidBytes = 3;
+
+ Utf8Char->Utf8_3[2] = Temp;
+
+ Index++;
+
+ } else {
+ //
+ // reset *ValidBytes to zero, let valid utf8 char search restart
+ //
+ *ValidBytes = 0;
+ }
+
+ break;
+
+ case 2:
+ //
+ // two-byte utf8 char go on
+ //
+ if ((Temp & 0xc0) == 0x80) {
+
+ Utf8Char->Utf8_2[0] = Temp;
+
+ FetchFlag = FALSE;
+
+ } else {
+
+ *ValidBytes = 0;
+ }
+ break;
+
+ case 3:
+ //
+ // three-byte utf8 char go on
+ //
+ if ((Temp & 0xc0) == 0x80) {
+ if (Index == 1) {
+ Utf8Char->Utf8_3[1] = Temp;
+ Index++;
+ } else {
+ Utf8Char->Utf8_3[0] = Temp;
+ FetchFlag = FALSE;
+ }
+ } else {
+ //
+ // reset *ValidBytes and Index to zero, let valid utf8 char search restart
+ //
+ *ValidBytes = 0;
+ Index = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!FetchFlag) {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Translate VT-UTF8 characters into one Unicode character.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Utf8Char VT-UTF8 character set needs translating.
+ @param ValidBytes The count of valid VT-UTF8 characters.
+ @param UnicodeChar Returned unicode character.
+
+**/
+VOID
+Utf8ToUnicode (
+ IN UTF8_CHAR Utf8Char,
+ IN UINT8 ValidBytes,
+ OUT CHAR16 *UnicodeChar
+ )
+{
+ UINT8 UnicodeByte0;
+ UINT8 UnicodeByte1;
+ UINT8 Byte0;
+ UINT8 Byte1;
+ UINT8 Byte2;
+
+ *UnicodeChar = 0;
+
+ //
+ // translate utf8 code to unicode, in terminal standard,
+ // up to 3 bytes utf8 code is supported.
+ //
+ switch (ValidBytes) {
+ case 1:
+ //
+ // one-byte utf8 code
+ //
+ *UnicodeChar = (UINT16) Utf8Char.Utf8_1;
+ break;
+
+ case 2:
+ //
+ // two-byte utf8 code
+ //
+ Byte0 = Utf8Char.Utf8_2[0];
+ Byte1 = Utf8Char.Utf8_2[1];
+
+ UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f));
+ UnicodeByte1 = (UINT8) ((Byte1 >> 2) & 0x07);
+ *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8));
+ break;
+
+ case 3:
+ //
+ // three-byte utf8 code
+ //
+ Byte0 = Utf8Char.Utf8_3[0];
+ Byte1 = Utf8Char.Utf8_3[1];
+ Byte2 = Utf8Char.Utf8_3[2];
+
+ UnicodeByte0 = (UINT8) ((Byte1 << 6) | (Byte0 & 0x3f));
+ UnicodeByte1 = (UINT8) ((Byte2 << 4) | ((Byte1 >> 2) & 0x0f));
+ *UnicodeChar = (UINT16) (UnicodeByte0 | (UnicodeByte1 << 8));
+
+ default:
+ break;
+ }
+
+ return ;
+}
+
+/**
+ Translate one Unicode character into VT-UTF8 characters.
+
+ UTF8 Encoding Table
+ Bits per Character | Unicode Character Range | Unicode Binary Encoding | UTF8 Binary Encoding
+ 0-7 | 0x0000 - 0x007F | 00000000 0xxxxxxx | 0xxxxxxx
+ 8-11 | 0x0080 - 0x07FF | 00000xxx xxxxxxxx | 110xxxxx 10xxxxxx
+ 12-16 | 0x0800 - 0xFFFF | xxxxxxxx xxxxxxxx | 1110xxxx 10xxxxxx 10xxxxxx
+
+
+ @param Unicode Unicode character need translating.
+ @param Utf8Char Return VT-UTF8 character set.
+ @param ValidBytes The count of valid VT-UTF8 characters. If
+ ValidBytes is zero, no valid VT-UTF8 returned.
+
+**/
+VOID
+UnicodeToUtf8 (
+ IN CHAR16 Unicode,
+ OUT UTF8_CHAR *Utf8Char,
+ OUT UINT8 *ValidBytes
+ )
+{
+ UINT8 UnicodeByte0;
+ UINT8 UnicodeByte1;
+ //
+ // translate unicode to utf8 code
+ //
+ UnicodeByte0 = (UINT8) Unicode;
+ UnicodeByte1 = (UINT8) (Unicode >> 8);
+
+ if (Unicode < 0x0080) {
+
+ Utf8Char->Utf8_1 = (UINT8) (UnicodeByte0 & 0x7f);
+ *ValidBytes = 1;
+
+ } else if (Unicode < 0x0800) {
+ //
+ // byte sequence: high -> low
+ // Utf8_2[0], Utf8_2[1]
+ //
+ Utf8Char->Utf8_2[1] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80);
+ Utf8Char->Utf8_2[0] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x1f) + 0xc0);
+
+ *ValidBytes = 2;
+
+ } else {
+ //
+ // byte sequence: high -> low
+ // Utf8_3[0], Utf8_3[1], Utf8_3[2]
+ //
+ Utf8Char->Utf8_3[2] = (UINT8) ((UnicodeByte0 & 0x3f) + 0x80);
+ Utf8Char->Utf8_3[1] = (UINT8) ((((UnicodeByte1 << 2) + (UnicodeByte0 >> 6)) & 0x3f) + 0x80);
+ Utf8Char->Utf8_3[0] = (UINT8) (((UnicodeByte1 >> 4) & 0x0f) + 0xe0);
+
+ *ValidBytes = 3;
+ }
+}
+
+
+/**
+ Check if input string is valid VT-UTF8 string.
+
+ @param TerminalDevice The terminal device.
+ @param WString The input string.
+
+ @retval EFI_SUCCESS If all input characters are valid.
+
+**/
+EFI_STATUS
+VTUTF8TestString (
+ IN TERMINAL_DEV *TerminalDevice,
+ IN CHAR16 *WString
+ )
+{
+ //
+ // to utf8, all kind of characters are supported.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/ComponentName.c
new file mode 100644
index 000000000..69915b842
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/ComponentName.c
@@ -0,0 +1,176 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for DebugPort driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugPort.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDebugPortComponentName = {
+ DebugPortComponentNameGetDriverName,
+ DebugPortComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDebugPortComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DebugPortComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DebugPortComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDebugPortDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *) L"DebugPort 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
+DebugPortComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDebugPortDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gDebugPortComponentName)
+ );
+}
+
+/**
+ 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
+DebugPortComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c
new file mode 100644
index 000000000..172c1cbca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c
@@ -0,0 +1,739 @@
+/** @file
+ Top level C file for debugport driver. Contains initialization function.
+ This driver layers on top of SerialIo.
+ ALL CODE IN THE SERIALIO STACK MUST BE RE-ENTRANT AND CALLABLE FROM
+ INTERRUPT CONTEXT
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugPort.h"
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = {
+ DebugPortSupported,
+ DebugPortStart,
+ DebugPortStop,
+ DEBUGPORT_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+DEBUGPORT_DEVICE mDebugPortDevice = {
+ DEBUGPORT_DEVICE_SIGNATURE,
+ (EFI_HANDLE) 0,
+ (EFI_HANDLE) 0,
+ (EFI_DEVICE_PATH_PROTOCOL *) NULL,
+ {
+ DebugPortReset,
+ DebugPortWrite,
+ DebugPortRead,
+ DebugPortPoll
+ },
+ (EFI_HANDLE) 0,
+ (EFI_SERIAL_IO_PROTOCOL *) NULL,
+ DEBUGPORT_UART_DEFAULT_BAUDRATE,
+ DEBUGPORT_UART_DEFAULT_FIFO_DEPTH,
+ DEBUGPORT_UART_DEFAULT_TIMEOUT,
+ (EFI_PARITY_TYPE) DEBUGPORT_UART_DEFAULT_PARITY,
+ DEBUGPORT_UART_DEFAULT_DATA_BITS,
+ (EFI_STOP_BITS_TYPE) DEBUGPORT_UART_DEFAULT_STOP_BITS
+};
+
+/**
+ Local worker function to obtain device path information from DebugPort variable.
+
+ Records requested settings in DebugPort device structure.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+GetDebugPortVariable (
+ VOID
+ )
+{
+ UINTN DataSize;
+ EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ GetVariable2 (EFI_DEBUGPORT_VARIABLE_NAME, &gEfiDebugPortVariableGuid, (VOID **) &DebugPortVariable, &DataSize);
+ if (DebugPortVariable == NULL) {
+ return NULL;
+ }
+
+ DevicePath = DebugPortVariable;
+ while (!IsDevicePathEnd (DevicePath) && !IS_UART_DEVICEPATH (DevicePath)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (IsDevicePathEnd (DevicePath)) {
+ FreePool (DebugPortVariable);
+ return NULL;
+ } else {
+ CopyMem (
+ &mDebugPortDevice.BaudRate,
+ &((UART_DEVICE_PATH *) DevicePath)->BaudRate,
+ sizeof (((UART_DEVICE_PATH *) DevicePath)->BaudRate)
+ );
+ mDebugPortDevice.ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH;
+ mDebugPortDevice.Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT;
+ CopyMem (
+ &mDebugPortDevice.Parity,
+ &((UART_DEVICE_PATH *) DevicePath)->Parity,
+ sizeof (((UART_DEVICE_PATH *) DevicePath)->Parity)
+ );
+ CopyMem (
+ &mDebugPortDevice.DataBits,
+ &((UART_DEVICE_PATH *) DevicePath)->DataBits,
+ sizeof (((UART_DEVICE_PATH *) DevicePath)->DataBits)
+ );
+ CopyMem (
+ &mDebugPortDevice.StopBits,
+ &((UART_DEVICE_PATH *) DevicePath)->StopBits,
+ sizeof (((UART_DEVICE_PATH *) DevicePath)->StopBits)
+ );
+ return DebugPortVariable;
+ }
+}
+
+/**
+ Debug Port Driver entry point.
+
+ Reads DebugPort variable to determine what device and settings to use as the
+ debug port. Binds exclusively to SerialIo. Reverts to defaults if no variable
+ is found.
+
+ @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 Fails to allocate memory for device.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDebugPortDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDebugPortDriverBinding,
+ ImageHandle,
+ &gDebugPortComponentName,
+ &gDebugPortComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Checks to see if there's not already a DebugPort interface somewhere.
+
+ If there's a DEBUGPORT variable, the device path must match exactly. If there's
+ no DEBUGPORT variable, then device path is not checked and does not matter.
+ Checks to see that there's a serial io interface on the controller handle
+ that can be bound BY_DRIVER | EXCLUSIVE.
+ If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED
+ or other error returned by OpenProtocol.
+
+ @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_UNSUPPORTED Debug Port device is not supported.
+ @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
+ @retval others Some error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEBUGPORT_PROTOCOL *DebugPortInterface;
+ EFI_HANDLE TempHandle;
+
+ //
+ // Check to see that there's not a debugport protocol already published,
+ // since only one standard UART serial port could be supported by this driver.
+ //
+ if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **) &DebugPortInterface) != EFI_NOT_FOUND) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Read DebugPort variable to determine debug port selection and parameters
+ //
+ DebugPortVariable = GetDebugPortVariable ();
+
+ if (DebugPortVariable != NULL) {
+ //
+ // There's a DEBUGPORT variable, so do LocateDevicePath and check to see if
+ // the closest matching handle matches the controller handle, and if it does,
+ // check to see that the remaining device path has the DebugPort GUIDed messaging
+ // device path only. Otherwise, it's a mismatch and EFI_UNSUPPORTED is returned.
+ //
+ DevicePath = DebugPortVariable;
+ Status = gBS->LocateDevicePath (
+ &gEfiSerialIoProtocolGuid,
+ &DevicePath,
+ &TempHandle
+ );
+
+ if (Status == EFI_SUCCESS && TempHandle != ControllerHandle) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (Status == EFI_SUCCESS &&
+ (DevicePath->Type != MESSAGING_DEVICE_PATH ||
+ DevicePath->SubType != MSG_VENDOR_DP ||
+ *((UINT16 *) DevicePath->Length) != sizeof (DEBUGPORT_DEVICE_PATH))) {
+
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (Status == EFI_SUCCESS && !CompareGuid (&gEfiDebugPortDevicePathGuid, (GUID *) (DevicePath + 1))) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ FreePool (DebugPortVariable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+/**
+ Binds exclusively to serial io on the controller handle, Produces DebugPort
+ protocol and DevicePath on new handle.
+
+ @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_OUT_OF_RESOURCES Fails to allocate memory for device.
+ @retval others Some error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ DEBUGPORT_DEVICE_PATH DebugPortDP;
+ EFI_DEVICE_PATH_PROTOCOL EndDP;
+ EFI_DEVICE_PATH_PROTOCOL *Dp1;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &mDebugPortDevice.SerialIoBinding,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mDebugPortDevice.SerialIoDeviceHandle = ControllerHandle;
+
+ //
+ // Initialize the Serial Io interface...
+ //
+ Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
+ mDebugPortDevice.SerialIoBinding,
+ mDebugPortDevice.BaudRate,
+ mDebugPortDevice.ReceiveFifoDepth,
+ mDebugPortDevice.Timeout,
+ mDebugPortDevice.Parity,
+ mDebugPortDevice.DataBits,
+ mDebugPortDevice.StopBits
+ );
+ if (EFI_ERROR (Status)) {
+ mDebugPortDevice.BaudRate = 0;
+ mDebugPortDevice.Parity = DefaultParity;
+ mDebugPortDevice.DataBits = 0;
+ mDebugPortDevice.StopBits = DefaultStopBits;
+ mDebugPortDevice.ReceiveFifoDepth = 0;
+ Status = mDebugPortDevice.SerialIoBinding->SetAttributes (
+ mDebugPortDevice.SerialIoBinding,
+ mDebugPortDevice.BaudRate,
+ mDebugPortDevice.ReceiveFifoDepth,
+ mDebugPortDevice.Timeout,
+ mDebugPortDevice.Parity,
+ mDebugPortDevice.DataBits,
+ mDebugPortDevice.StopBits
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+ }
+ }
+
+ mDebugPortDevice.SerialIoBinding->Reset (mDebugPortDevice.SerialIoBinding);
+
+ //
+ // Create device path instance for DebugPort
+ //
+ DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH;
+ DebugPortDP.Header.SubType = MSG_VENDOR_DP;
+ SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP));
+ CopyGuid (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid);
+
+ Dp1 = DevicePathFromHandle (ControllerHandle);
+ if (Dp1 == NULL) {
+ Dp1 = &EndDP;
+ SetDevicePathEndNode (Dp1);
+ }
+
+ mDebugPortDevice.DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *) &DebugPortDP);
+ if (mDebugPortDevice.DebugPortDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Publish DebugPort and Device Path protocols
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDebugPortDevice.DebugPortDeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ mDebugPortDevice.DebugPortDevicePath,
+ &gEfiDebugPortProtocolGuid,
+ &mDebugPortDevice.DebugPortInterface,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+ }
+ //
+ // Connect debugport child to serial io
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &mDebugPortDevice.SerialIoBinding,
+ This->DriverBindingHandle,
+ mDebugPortDevice.DebugPortDeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle by removing Serial IO protocol on
+ the ControllerHandle.
+
+ @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
+DebugPortStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ mDebugPortDevice.SerialIoBinding = NULL;
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ FreePool (mDebugPortDevice.DebugPortDevicePath);
+
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Disconnect SerialIo child handle
+ //
+ Status = gBS->CloseProtocol (
+ mDebugPortDevice.SerialIoDeviceHandle,
+ &gEfiSerialIoProtocolGuid,
+ This->DriverBindingHandle,
+ mDebugPortDevice.DebugPortDeviceHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Unpublish our protocols (DevicePath, DebugPort)
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ mDebugPortDevice.DebugPortDeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ mDebugPortDevice.DebugPortDevicePath,
+ &gEfiDebugPortProtocolGuid,
+ &mDebugPortDevice.DebugPortInterface,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &mDebugPortDevice.SerialIoBinding,
+ This->DriverBindingHandle,
+ mDebugPortDevice.DebugPortDeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ mDebugPortDevice.DebugPortDeviceHandle = NULL;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ DebugPort protocol member function. Calls SerialIo:GetControl to flush buffer.
+ We cannot call SerialIo:SetAttributes because it uses pool services, which use
+ locks, which affect TPL, so it's not interrupt context safe or re-entrant.
+ SerialIo:Reset() calls SetAttributes, so it can't be used either.
+
+ The port itself should be fine since it was set up during initialization.
+
+ @param This Protocol instance pointer.
+
+ @return EFI_SUCCESS Always.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortReset (
+ IN EFI_DEBUGPORT_PROTOCOL *This
+ )
+{
+ UINTN BufferSize;
+ UINTN BitBucket;
+
+ while (This->Poll (This) == EFI_SUCCESS) {
+ BufferSize = 1;
+ This->Read (This, 0, &BufferSize, &BitBucket);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Read() after setting
+ if it's different than the last SerialIo access.
+
+ @param This Pointer to DebugPort protocol.
+ @param Timeout Timeout value.
+ @param BufferSize On input, the size of Buffer.
+ On output, the amount of data actually written.
+ @param Buffer Pointer to buffer to read.
+
+ @retval EFI_SUCCESS
+ @retval others
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortRead (
+ IN EFI_DEBUGPORT_PROTOCOL *This,
+ IN UINT32 Timeout,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ DEBUGPORT_DEVICE *DebugPortDevice;
+ UINTN LocalBufferSize;
+ EFI_STATUS Status;
+ UINT8 *BufferPtr;
+
+ DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
+ BufferPtr = Buffer;
+ LocalBufferSize = *BufferSize;
+
+ do {
+ Status = DebugPortDevice->SerialIoBinding->Read (
+ DebugPortDevice->SerialIoBinding,
+ &LocalBufferSize,
+ BufferPtr
+ );
+ if (Status == EFI_TIMEOUT) {
+ if (Timeout > DEBUGPORT_UART_DEFAULT_TIMEOUT) {
+ Timeout -= DEBUGPORT_UART_DEFAULT_TIMEOUT;
+ } else {
+ Timeout = 0;
+ }
+ } else if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ BufferPtr += LocalBufferSize;
+ LocalBufferSize = *BufferSize - (BufferPtr - (UINT8 *) Buffer);
+ } while (LocalBufferSize != 0 && Timeout > 0);
+
+ *BufferSize = (UINTN) BufferPtr - (UINTN) Buffer;
+
+ return Status;
+}
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Write() Writes 8 bytes at
+ a time and does a GetControl between 8 byte writes to help insure reads are
+ interspersed This is poor-man's flow control.
+
+ @param This Pointer to DebugPort protocol.
+ @param Timeout Timeout value.
+ @param BufferSize On input, the size of Buffer.
+ On output, the amount of data actually written.
+ @param Buffer Pointer to buffer to read.
+
+ @retval EFI_SUCCESS The data was written.
+ @retval others Fails when writting datas to debug port device.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortWrite (
+ IN EFI_DEBUGPORT_PROTOCOL *This,
+ IN UINT32 Timeout,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ DEBUGPORT_DEVICE *DebugPortDevice;
+ UINTN Position;
+ UINTN WriteSize;
+ EFI_STATUS Status;
+ UINT32 SerialControl;
+
+ Status = EFI_SUCCESS;
+ DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
+
+ WriteSize = 8;
+ for (Position = 0; Position < *BufferSize && !EFI_ERROR (Status); Position += WriteSize) {
+ DebugPortDevice->SerialIoBinding->GetControl (
+ DebugPortDevice->SerialIoBinding,
+ &SerialControl
+ );
+ if (*BufferSize - Position < 8) {
+ WriteSize = *BufferSize - Position;
+ }
+
+ Status = DebugPortDevice->SerialIoBinding->Write (
+ DebugPortDevice->SerialIoBinding,
+ &WriteSize,
+ &((UINT8 *) Buffer)[Position]
+ );
+ }
+
+ *BufferSize = Position;
+ return Status;
+}
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Write() after setting
+ if it's different than the last SerialIo access.
+
+ @param This Pointer to DebugPort protocol.
+
+ @retval EFI_SUCCESS At least 1 character is ready to be read from
+ the DebugPort interface.
+ @retval EFI_NOT_READY There are no characters ready to read from the
+ DebugPort interface
+ @retval EFI_DEVICE_ERROR A hardware failure occurred... (from SerialIo)
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortPoll (
+ IN EFI_DEBUGPORT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SerialControl;
+ DEBUGPORT_DEVICE *DebugPortDevice;
+
+ DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This);
+
+ Status = DebugPortDevice->SerialIoBinding->GetControl (
+ DebugPortDevice->SerialIoBinding,
+ &SerialControl
+ );
+
+ if (!EFI_ERROR (Status)) {
+ if ((SerialControl & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) {
+ Status = EFI_NOT_READY;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Unload function that is registered in the LoadImage protocol. It un-installs
+ protocols produced and deallocates pool used by the driver. Called by the core
+ when unloading the driver.
+
+ @param ImageHandle
+
+ @retval EFI_SUCCESS Unload Debug Port driver successfully.
+ @retval EFI_ABORTED Serial IO is still binding.
+
+**/
+EFI_STATUS
+EFIAPI
+ImageUnloadHandler (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ VOID *ComponentName;
+ VOID *ComponentName2;
+
+ if (mDebugPortDevice.SerialIoBinding != NULL) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Driver is stopped already.
+ //
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName);
+ if (EFI_ERROR (Status)) {
+ ComponentName = NULL;
+ }
+
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2);
+ if (EFI_ERROR (Status)) {
+ ComponentName2 = NULL;
+ }
+
+ if (ComponentName == NULL) {
+ if (ComponentName2 == NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding,
+ &gEfiComponentName2ProtocolGuid, ComponentName2,
+ NULL
+ );
+ }
+ } else {
+ if (ComponentName2 == NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding,
+ &gEfiComponentNameProtocolGuid, ComponentName,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding,
+ &gEfiComponentNameProtocolGuid, ComponentName,
+ &gEfiComponentName2ProtocolGuid, ComponentName2,
+ NULL
+ );
+ }
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.h b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.h
new file mode 100644
index 000000000..12fca8e27
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.h
@@ -0,0 +1,390 @@
+/** @file
+ Definitions and prototypes for DebugPort driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DEBUGPORT_H__
+#define __DEBUGPORT_H__
+
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DebugPort.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/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gDebugPortComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gDebugPortComponentName2;
+
+//
+// local type definitions
+//
+#define DEBUGPORT_DEVICE_SIGNATURE SIGNATURE_32 ('D', 'B', 'G', 'P')
+
+//
+// Device structure used by driver
+//
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE DriverBindingHandle;
+ EFI_HANDLE DebugPortDeviceHandle;
+
+ EFI_DEVICE_PATH_PROTOCOL *DebugPortDevicePath;
+ EFI_DEBUGPORT_PROTOCOL DebugPortInterface;
+
+ EFI_HANDLE SerialIoDeviceHandle;
+ EFI_SERIAL_IO_PROTOCOL *SerialIoBinding;
+ UINT64 BaudRate;
+ UINT32 ReceiveFifoDepth;
+ UINT32 Timeout;
+ EFI_PARITY_TYPE Parity;
+ UINT8 DataBits;
+ EFI_STOP_BITS_TYPE StopBits;
+} DEBUGPORT_DEVICE;
+
+#define DEBUGPORT_DEVICE_FROM_THIS(a) CR (a, DEBUGPORT_DEVICE, DebugPortInterface, DEBUGPORT_DEVICE_SIGNATURE)
+
+#define EFI_ACPI_PC_COMPORT_HID EISA_PNP_ID (0x0500)
+#define EFI_ACPI_16550UART_HID EISA_PNP_ID (0x0501)
+
+#define DEBUGPORT_UART_DEFAULT_BAUDRATE 115200
+#define DEBUGPORT_UART_DEFAULT_PARITY 0
+#define DEBUGPORT_UART_DEFAULT_FIFO_DEPTH 16
+#define DEBUGPORT_UART_DEFAULT_TIMEOUT 50000 ///< 5 ms
+#define DEBUGPORT_UART_DEFAULT_DATA_BITS 8
+#define DEBUGPORT_UART_DEFAULT_STOP_BITS 1
+
+#define DEBUGPORT_DRIVER_VERSION 1
+
+#define IS_UART_DEVICEPATH(dp) (DevicePathType (dp) == MESSAGING_DEVICE_PATH && DevicePathSubType (dp) == MSG_UART_DP)
+
+/**
+ Debug Port Driver entry point.
+
+ Reads DebugPort variable to determine what device and settings to use as the
+ debug port. Binds exclusively to SerialIo. Reverts to defaults if no variable
+ is found.
+
+ @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 Fails to allocate memory for device.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDebugPortDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Checks to see if there's not already a DebugPort interface somewhere.
+
+ If there's a DEBUGPORT variable, the device path must match exactly. If there's
+ no DEBUGPORT variable, then device path is not checked and does not matter.
+ Checks to see that there's a serial io interface on the controller handle
+ that can be bound BY_DRIVER | EXCLUSIVE.
+ If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED
+ or other error returned by OpenProtocol.
+
+ @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_UNSUPPORTED Debug Port device is not supported.
+ @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device.
+ @retval others Some error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Binds exclusively to serial io on the controller handle, Produces DebugPort
+ protocol and DevicePath on new handle.
+
+ @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_OUT_OF_RESOURCES Fails to allocate memory for device.
+ @retval others Some error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing Serial IO protocol on
+ the ControllerHandle.
+
+ @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
+DebugPortStop (
+ 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
+DebugPortComponentNameGetDriverName (
+ 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
+DebugPortComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ DebugPort protocol member function. Calls SerialIo:GetControl to flush buffer.
+ We cannot call SerialIo:SetAttributes because it uses pool services, which use
+ locks, which affect TPL, so it's not interrupt context safe or re-entrant.
+ SerialIo:Reset() calls SetAttributes, so it can't be used either.
+
+ The port itself should be fine since it was set up during initialization.
+
+ @param This Protocol instance pointer.
+
+ @return EFI_SUCCESS Always.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortReset (
+ IN EFI_DEBUGPORT_PROTOCOL *This
+ );
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Read() after setting
+ if it's different than the last SerialIo access.
+
+ @param This Pointer to DebugPort protocol.
+ @param Timeout Timeout value.
+ @param BufferSize On input, the size of Buffer.
+ On output, the amount of data actually written.
+ @param Buffer Pointer to buffer to read.
+
+ @retval EFI_SUCCESS
+ @retval others
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortRead (
+ IN EFI_DEBUGPORT_PROTOCOL *This,
+ IN UINT32 Timeout,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Write() Writes 8 bytes at
+ a time and does a GetControl between 8 byte writes to help insure reads are
+ interspersed This is poor-man's flow control.
+
+ @param This Pointer to DebugPort protocol.
+ @param Timeout Timeout value.
+ @param BufferSize On input, the size of Buffer.
+ On output, the amount of data actually written.
+ @param Buffer Pointer to buffer to read.
+
+ @retval EFI_SUCCESS The data was written.
+ @retval others Fails when writting datas to debug port device.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortWrite (
+ IN EFI_DEBUGPORT_PROTOCOL *This,
+ IN UINT32 Timeout,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ DebugPort protocol member function. Calls SerialIo:Write() after setting
+ if it's different than the last SerialIo access.
+
+ @param This Pointer to DebugPort protocol.
+
+ @retval EFI_SUCCESS At least 1 character is ready to be read from
+ the DebugPort interface.
+ @retval EFI_NOT_READY There are no characters ready to read from the
+ DebugPort interface
+ @retval EFI_DEVICE_ERROR A hardware failure occurred... (from SerialIo)
+
+**/
+EFI_STATUS
+EFIAPI
+DebugPortPoll (
+ IN EFI_DEBUGPORT_PROTOCOL *This
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.inf b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.inf
new file mode 100644
index 000000000..66da0dea9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.inf
@@ -0,0 +1,66 @@
+## @file
+# This driver produces Debug Port protocol to be used by debug agent to communicate with the remote debug host.
+#
+# This driver binds exclusively to a standard UART serial port on the controller handle,
+# and initializes serial Io interface, publishs Debug Port and Device Path Protocol.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugPortDxe
+ MODULE_UNI_FILE = DebugPortDxe.uni
+ FILE_GUID = 73E9457A-CEA1-4917-9A9C-9F1F0F0FD322
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDebugPortDriver
+ UNLOAD_IMAGE = ImageUnloadHandler
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gDebugPortDriverBinding
+# COMPONENT_NAME = gDebugPortComponentName
+# COMPONENT_NAME2 = gDebugPortComponentName2
+# Variable Guid C Name: gEfiDebugPortProtocolGuid Variable Name: L"DEBUGPORT"
+#
+#
+
+[Sources]
+ ComponentName.c
+ DebugPort.c
+ DebugPort.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Guids]
+ gEfiDebugPortVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"DEBUGPORT"
+ gEfiDebugPortDevicePathGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Device path
+
+[Protocols]
+ gEfiSerialIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiDebugPortProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DebugPortDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.uni b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.uni
new file mode 100644
index 000000000..2f631eada
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// This driver produces Debug Port protocol to be used by debug agent to communicate with the remote debug host.
+//
+// This driver binds exclusively to a standard UART serial port on the controller handle,
+// and initializes serial Io interface, publishs Debug Port and Device Path Protocol.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces Debug Port protocol to be used by debug agent to communicate with the remote debug host and initializes serial Io interface, publishes Debug Port and Device Path Protocol."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver binds exclusively to a standard UART serial port on the controller handle, and initializes serial Io interface, publishes Debug Port and Device Path Protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxeExtra.uni
new file mode 100644
index 000000000..3450ab45b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPortDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DebugPortDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Debug Port DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugService.h b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugService.h
new file mode 100644
index 000000000..e81b9cdb6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugService.h
@@ -0,0 +1,50 @@
+/** @file
+ Header file of Debug services instances.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __DEBUG_SERVICE_H__
+#define __DEBUG_SERVICE_H__
+
+#include <Ppi/Debug.h>
+
+/**
+ Print a debug message to debug output device if the specified error level
+ is enabled.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] Marker BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+PeiDebugBPrint(
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN BASE_LIST Marker
+ );
+
+/**
+ Prints an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ @param[in] FileName The pointer to the name of the source file that
+ generated the assert condition.
+ @param[in] LineNumber The line number in the source file that generated
+ the assert condition
+ @param[in] Description The pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+PeiDebugAssert(
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.c b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.c
new file mode 100644
index 000000000..6d08f5158
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.c
@@ -0,0 +1,94 @@
+/** @file
+ This driver installs gEdkiiDebugPpiGuid PPI to provide
+ debug services for PEIMs.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+
+#include <Ppi/Debug.h>
+
+#include "DebugService.h"
+
+EDKII_DEBUG_PPI mDebugPpi = {
+ PeiDebugBPrint,
+ PeiDebugAssert
+};
+
+EFI_PEI_PPI_DESCRIPTOR mDebugServicePpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiDebugPpiGuid,
+ (VOID *)&mDebugPpi
+};
+
+/**
+ Print a debug message to debug output device if the specified error level
+ is enabled.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] Marker BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+PeiDebugBPrint(
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ IN BASE_LIST Marker
+ )
+{
+ DebugBPrint(ErrorLevel, Format, Marker);
+}
+
+/**
+ Print an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ @param[in] FileName The pointer to the name of the source file that
+ generated the assert condition.
+ @param[in] LineNumber The line number in the source file that generated
+ the assert condition
+ @param[in] Description The pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+PeiDebugAssert(
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ )
+{
+ DebugAssert(FileName, LineNumber, Description);
+}
+
+/**
+ Entry point of Debug Service PEIM
+
+ This funciton installs EDKII DEBUG 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 Debug Service PEIM executes successfully.
+ @retval Others Some error occurs during the execution of this function.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugSerivceInitialize (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return PeiServicesInstallPpi (&mDebugServicePpi);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.inf b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.inf
new file mode 100644
index 000000000..eb76af034
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.inf
@@ -0,0 +1,46 @@
+## @file
+# Debug services for PEI phase
+#
+# This module installs gEdkiiDebugPpiGuid PPI to provide
+# debug services for PEIMs.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugServicePei
+ MODULE_UNI_FILE = DebugServicePei.uni
+ FILE_GUID = B73F81B9-1DFC-487C-824C-0509EE2B0128
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = DebugSerivceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DebugServicePei.c
+ DebugService.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEdkiiDebugPpiGuid ## PRODUCE
+
+[Depex]
+ TRUE
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.uni b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.uni
new file mode 100644
index 000000000..8fbd4069e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugServicePei/DebugServicePei.uni
@@ -0,0 +1,14 @@
+///** @file
+// This driver installs gEdkiiDebugPpiGuid PPI to provide
+// debug services for PEIMs.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#string STR_MODULE_ABSTRACT #language en-US "Provide debug services at PEI phase."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It produces gEdkiiDebugPpiGuid to print message to debug output device"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupport.c b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupport.c
new file mode 100644
index 000000000..1a03ba465
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupport.c
@@ -0,0 +1,127 @@
+/** @file
+ Top level C file for debug support driver. Contains initialization function.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlDebugSupport.h"
+
+EFI_DEBUG_SUPPORT_PROTOCOL mDebugSupportProtocolInterface = {
+ EFI_ISA,
+ GetMaximumProcessorIndex,
+ RegisterPeriodicCallback,
+ RegisterExceptionCallback,
+ InvalidateInstructionCache
+};
+
+
+/**
+ Debug Support Driver entry point.
+
+ Checks to see if there's not already a Debug Support protocol installed for
+ the selected processor before installing it.
+
+ @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_ALREADY_STARTED Debug Support protocol is installed already.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDebugSupportDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocolPtr;
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE *HandlePtr;
+ UINTN NumHandles;
+ EFI_DEBUG_SUPPORT_PROTOCOL *DebugSupportProtocolPtr;
+
+ //
+ // First check to see that the debug support protocol for this processor
+ // type is not already installed
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDebugSupportProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandlePtr
+ );
+
+ if (Status != EFI_NOT_FOUND) {
+ do {
+ NumHandles--;
+ Status = gBS->OpenProtocol (
+ HandlePtr[NumHandles],
+ &gEfiDebugSupportProtocolGuid,
+ (VOID **) &DebugSupportProtocolPtr,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if ((Status == EFI_SUCCESS) && (DebugSupportProtocolPtr->Isa == EFI_ISA)) {
+ //
+ // a Debug Support protocol has been installed for this processor
+ //
+ FreePool (HandlePtr);
+ Status = EFI_ALREADY_STARTED;
+ goto ErrExit;
+ }
+ } while (NumHandles > 0);
+ FreePool (HandlePtr);
+ }
+
+ //
+ // Get our image information and install platform specific unload handler
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImageProtocolPtr,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ if (Status != EFI_SUCCESS) {
+ goto ErrExit;
+ }
+
+ LoadedImageProtocolPtr->Unload = PlUnloadDebugSupportDriver;
+
+ //
+ // Call hook for processor specific initialization
+ //
+ Status = PlInitializeDebugSupportDriver ();
+ ASSERT (!EFI_ERROR (Status));
+ if (Status != EFI_SUCCESS) {
+ goto ErrExit;
+ }
+
+ //
+ // Install Debug Support protocol to new handle
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiDebugSupportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mDebugSupportProtocolInterface
+ );
+ ASSERT (!EFI_ERROR (Status));
+ if (Status != EFI_SUCCESS) {
+ goto ErrExit;
+ }
+
+ErrExit:
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf
new file mode 100644
index 000000000..1bb8635bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf
@@ -0,0 +1,72 @@
+## @file
+# This driver installs Debug Support protocol for the selected processor.
+#
+# This driver provides the capabilities for debug-agent to gain control of the machine
+# when certain types of events occur, i.e. breakpoint, processor execptions, etc. It also
+# provides debug-agent to periodically gain control during operation of the machine to
+# check for asynchronous commands form the host.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugSupportDxe
+ MODULE_UNI_FILE = DebugSupportDxe.uni
+ FILE_GUID = 911D584C-35F7-4955-BEF9-B452769DDC3A
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDebugSupportDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugSupport.c
+
+[Sources.Ia32]
+ Ia32/DebugSupport.h
+ Ia32/PlDebugSupport.c
+ Ia32/PlDebugSupport.h
+ Ia32/PlDebugSupportIa32.c
+ Ia32/AsmFuncs.nasm
+
+[Sources.X64]
+ Ia32/DebugSupport.h
+ Ia32/PlDebugSupport.c
+ X64/PlDebugSupport.h
+ X64/PlDebugSupportX64.c
+ X64/AsmFuncs.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[LibraryClasses.IA32, LibraryClasses.X64]
+ BaseLib
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiDebugSupportProtocolGuid ## PRODUCES
+
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DebugSupportDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.uni b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.uni
new file mode 100644
index 000000000..1403d41ef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.uni
@@ -0,0 +1,19 @@
+// /** @file
+// This driver installs Debug Support protocol for the selected processor.
+//
+// This driver provides the capabilities for debug-agent to gain control of the machine
+// when certain types of events occur, i.e. breakpoint, processor execptions, etc. It also
+// provides debug-agent to periodically gain control during operation of the machine to
+// check for asynchronous commands form the host.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs Debug Support protocol for the selected processor"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides the capabilities for debug-agent to gain control of the machine when certain types of events occur, i.e. breakpoint, processor exceptions, etc. It also provides debug-agent to periodically gain control during operation of the machine to check for asynchronous commands from the host."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxeExtra.uni
new file mode 100644
index 000000000..7ceb95d3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DebugSupportDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Debug Support DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/AsmFuncs.nasm b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/AsmFuncs.nasm
new file mode 100644
index 000000000..cfb418748
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/AsmFuncs.nasm
@@ -0,0 +1,493 @@
+;/** @file
+; Low leve IA32 specific debug support functions.
+;
+; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+%define EXCPT32_DIVIDE_ERROR 0
+%define EXCPT32_DEBUG 1
+%define EXCPT32_NMI 2
+%define EXCPT32_BREAKPOINT 3
+%define EXCPT32_OVERFLOW 4
+%define EXCPT32_BOUND 5
+%define EXCPT32_INVALID_OPCODE 6
+%define EXCPT32_DOUBLE_FAULT 8
+%define EXCPT32_INVALID_TSS 10
+%define EXCPT32_SEG_NOT_PRESENT 11
+%define EXCPT32_STACK_FAULT 12
+%define EXCPT32_GP_FAULT 13
+%define EXCPT32_PAGE_FAULT 14
+%define EXCPT32_FP_ERROR 16
+%define EXCPT32_ALIGNMENT_CHECK 17
+%define EXCPT32_MACHINE_CHECK 18
+%define EXCPT32_SIMD 19
+
+%define FXSTOR_FLAG 0x1000000 ; bit cpuid 24 of feature flags
+
+;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
+;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver
+;; MUST check the CPUID feature flags to see that these instructions are available
+;; and fail to init if they are not.
+
+;; fxstor [edi]
+%macro FXSTOR_EDI 0
+ db 0xf, 0xae, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi]
+%endmacro
+
+;; fxrstor [esi]
+%macro FXRSTOR_ESI 0
+ db 0xf, 0xae, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi]
+%endmacro
+SECTION .data
+
+global ASM_PFX(OrigVector)
+global ASM_PFX(InterruptEntryStub)
+global ASM_PFX(StubSize)
+global ASM_PFX(CommonIdtEntry)
+global ASM_PFX(FxStorSupport)
+extern ASM_PFX(InterruptDistrubutionHub)
+
+ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
+AppEsp: dd 0x11111111 ; ?
+DebugEsp: dd 0x22222222 ; ?
+ExtraPush: dd 0x33333333 ; ?
+ExceptData: dd 0x44444444 ; ?
+Eflags: dd 0x55555555 ; ?
+ASM_PFX(OrigVector): dd 0x66666666 ; ?
+
+;; The declarations below define the memory region that will be used for the debug stack.
+;; The context record will be built by pushing register values onto this stack.
+;; It is imparitive that alignment be carefully managed, since the FXSTOR and
+;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
+;;
+;; The stub will switch stacks from the application stack to the debuger stack
+;; and pushes the exception number.
+;;
+;; Then we building the context record on the stack. Since the stack grows down,
+;; we push the fields of the context record from the back to the front. There
+;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
+;; used as the memory buffer for the fxstor instruction. Therefore address of
+;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
+;; must be 16 byte aligned.
+;;
+;; We carefully locate the stack to make this happen.
+;;
+;; For reference, the context structure looks like this:
+;; struct {
+;; UINT32 ExceptionData;
+;; FX_SAVE_STATE_IA32 FxSaveState; // 512 bytes, must be 16 byte aligned
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+;; UINT32 EFlags;
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; UINT32 Eip;
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
+
+align 16
+DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
+ times 0x1ffc dd 0x0 ;; 32K should be enough stack
+ ;; This allocation is coocked to insure
+ ;; that the the buffer for the FXSTORE instruction
+ ;; will be 16 byte aligned also.
+ ;;
+ExceptionNumber: dd 0 ;; first entry will be the vector number pushed by the stub
+
+DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
+
+SECTION .text
+
+;------------------------------------------------------------------------------
+; BOOLEAN
+; FxStorSupport (
+; void
+; )
+;
+; Abstract: Returns TRUE if FxStor instructions are supported
+;
+global ASM_PFX(FxStorSupport)
+ASM_PFX(FxStorSupport):
+
+;
+; cpuid corrupts ebx which must be preserved per the C calling convention
+;
+ push ebx
+ mov eax, 1
+ cpuid
+ mov eax, edx
+ and eax, FXSTOR_FLAG
+ shr eax, 24
+ pop ebx
+ ret
+
+;------------------------------------------------------------------------------
+; void
+; Vect2Desc (
+; DESCRIPTOR * DestDesc,
+; void (*Vector) (void)
+; )
+;
+; Abstract: Encodes an IDT descriptor with the given physical address
+;
+global ASM_PFX(Vect2Desc)
+ASM_PFX(Vect2Desc):
+ push ebp
+ mov ebp, esp
+ mov eax, [ebp + 0xC]
+ mov ecx, [ebp + 0x8]
+ mov word [ecx], ax ; write bits 15..0 of offset
+ mov dx, cs
+ mov word [ecx+2], dx ; SYS_CODE_SEL from GDT
+ mov word [ecx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
+ shr eax, 16
+ mov word [ecx+6], ax ; write bits 31..16 of offset
+ leave
+ ret
+
+;------------------------------------------------------------------------------
+; InterruptEntryStub
+;
+; Abstract: This code is not a function, but is a small piece of code that is
+; copied and fixed up once for each IDT entry that is hooked.
+;
+ASM_PFX(InterruptEntryStub):
+ mov [AppEsp], esp ; save stack top
+ mov esp, DebugStackBegin ; switch to debugger stack
+ push 0 ; push vector number - will be modified before installed
+ db 0xe9 ; jump rel32
+ dd 0 ; fixed up to relative address of CommonIdtEntry
+InterruptEntryStubEnd:
+
+;------------------------------------------------------------------------------
+; CommonIdtEntry
+;
+; Abstract: This code is not a function, but is the common part for all IDT
+; vectors.
+;
+ASM_PFX(CommonIdtEntry):
+;;
+;; At this point, the stub has saved the current application stack esp into AppEsp
+;; and switched stacks to the debug stack, where it pushed the vector number
+;;
+;; The application stack looks like this:
+;;
+;; ...
+;; (last application stack entry)
+;; eflags from interrupted task
+;; CS from interrupted task
+;; EIP from interrupted task
+;; Error code <-------------------- Only present for some exeption types
+;;
+;;
+
+;; The stub switched us to the debug stack and pushed the interrupt number.
+;;
+;; Next, construct the context record. It will be build on the debug stack by
+;; pushing the registers in the correct order so as to create the context structure
+;; on the debug stack. The context record must be built from the end back to the
+;; beginning because the stack grows down...
+;
+;; For reference, the context record looks like this:
+;;
+;; typedef
+;; struct {
+;; UINT32 ExceptionData;
+;; FX_SAVE_STATE_IA32 FxSaveState;
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; UINT32 Cr0, Cr2, Cr3, Cr4;
+;; UINT32 EFlags;
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; UINT32 Eip;
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+;; } SYSTEM_CONTEXT_IA32; // 32 bit system context record
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pushad
+
+;; Save interrupt state eflags register...
+ pushfd
+ pop eax
+ mov [Eflags], eax
+
+;; We need to determine if any extra data was pushed by the exception, and if so, save it
+;; To do this, we check the exception number pushed by the stub, and cache the
+;; result in a variable since we'll need this again.
+ cmp dword [ExceptionNumber], EXCPT32_DOUBLE_FAULT
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_INVALID_TSS
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_SEG_NOT_PRESENT
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_STACK_FAULT
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_GP_FAULT
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_PAGE_FAULT
+ jz ExtraPushOne
+ cmp dword [ExceptionNumber], EXCPT32_ALIGNMENT_CHECK
+ jz ExtraPushOne
+ mov dword [ExtraPush], 0
+ mov dword [ExceptData], 0
+ jmp ExtraPushDone
+
+ExtraPushOne:
+ mov dword [ExtraPush], 1
+
+;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
+;; pop this value off the application's stack.
+ mov eax, [AppEsp]
+ mov ebx, [eax]
+ mov [ExceptData], ebx
+ add eax, 4
+ mov [AppEsp], eax
+
+ExtraPushDone:
+
+;; The "pushad" above pushed the debug stack esp. Since what we're actually doing
+;; is building the context record on the debug stack, we need to save the pushed
+;; debug ESP, and replace it with the application's last stack entry...
+ mov eax, [esp + 12]
+ mov [DebugEsp], eax
+ mov eax, [AppEsp]
+ add eax, 12
+ ; application stack has eflags, cs, & eip, so
+ ; last actual application stack entry is
+ ; 12 bytes into the application stack.
+ mov [esp + 12], eax
+
+;; continue building context record
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ mov eax, ss
+ push eax
+
+ ; CS from application is one entry back in application stack
+ mov eax, [AppEsp]
+ movzx eax, word [eax + 4]
+ push eax
+
+ mov eax, ds
+ push eax
+ mov eax, es
+ push eax
+ mov eax, fs
+ push eax
+ mov eax, gs
+ push eax
+
+;; UINT32 Eip;
+ ; Eip from application is on top of application stack
+ mov eax, [AppEsp]
+ push dword [eax]
+
+;; UINT32 Gdtr[2], Idtr[2];
+ push 0
+ push 0
+ sidt [esp]
+ push 0
+ push 0
+ sgdt [esp]
+
+;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+;; UINT32 EFlags;
+;; Eflags from application is two entries back in application stack
+ mov eax, [AppEsp]
+ push dword [eax + 8]
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+;; insure FXSAVE/FXRSTOR is enabled in CR4...
+;; ... while we're at it, make sure DE is also enabled...
+ mov eax, cr4
+ or eax, 0x208
+ mov cr4, eax
+ push eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ push 0
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+;; clear Dr7 while executing debugger itself
+ xor eax, eax
+ mov dr7, eax
+
+ mov eax, dr6
+ push eax
+;; insure all status bits in dr6 are clear...
+ xor eax, eax
+ mov dr6, eax
+
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ ; IMPORTANT!! The debug stack has been carefully constructed to
+ ; insure that esp and edi are 16 byte aligned when we get here.
+ ; They MUST be. If they are not, a GP fault will occur.
+ FXSTOR_EDI
+
+;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ mov eax, [ExceptData]
+ push eax
+
+; call to C code which will in turn call registered handler
+; pass in the vector number
+ mov eax, esp
+ push eax
+ mov eax, [ExceptionNumber]
+ push eax
+ call ASM_PFX(InterruptDistrubutionHub)
+ add esp, 8
+
+; restore context...
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ FXRSTOR_ESI
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop eax
+ mov dr0, eax
+ pop eax
+ mov dr1, eax
+ pop eax
+ mov dr2, eax
+ pop eax
+ mov dr3, eax
+;; skip restore of dr6. We cleared dr6 during the context save.
+ add esp, 4
+ pop eax
+ mov dr7, eax
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ mov eax, [AppEsp]
+ pop dword [eax + 8]
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop dword [eax]
+
+;; UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword [eax + 4]
+ pop ss
+
+;; The next stuff to restore is the general purpose registers that were pushed
+;; using the "pushad" instruction.
+;;
+;; The value of ESP as stored in the context record is the application ESP
+;; including the 3 entries on the application stack caused by the exception
+;; itself. It may have been modified by the debug agent, so we need to
+;; determine if we need to relocate the application stack.
+
+ mov ebx, [esp + 12] ; move the potentially modified AppEsp into ebx
+ mov eax, [AppEsp]
+ add eax, 12
+ cmp ebx, eax
+ je NoAppStackMove
+
+ mov eax, [AppEsp]
+ mov ecx, [eax] ; EIP
+ mov [ebx], ecx
+
+ mov ecx, [eax + 4] ; CS
+ mov [ebx + 4], ecx
+
+ mov ecx, [eax + 8] ; EFLAGS
+ mov [ebx + 8], ecx
+
+ mov eax, ebx ; modify the saved AppEsp to the new AppEsp
+ mov [AppEsp], eax
+NoAppStackMove:
+ mov eax, [DebugEsp] ; restore the DebugEsp on the debug stack
+ ; so our "popad" will not cause a stack switch
+ mov [esp + 12], eax
+
+ cmp dword [ExceptionNumber], 0x68
+ jne NoChain
+
+Chain:
+
+;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
+;; We gin up the stack to do an iretd so we can get ALL the flags.
+ mov eax, [AppEsp]
+ mov ebx, [eax + 8]
+ and ebx, ~ 0x300 ; special handling for IF and TF
+ push ebx
+ push cs
+ push PhonyIretd
+ iretd
+PhonyIretd:
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ popad
+
+;; Switch back to application stack
+ mov esp, [AppEsp]
+
+;; Jump to original handler
+ jmp [ASM_PFX(OrigVector)]
+
+NoChain:
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ popad
+
+;; Switch back to application stack
+ mov esp, [AppEsp]
+
+;; We're outa here...
+ iretd
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/DebugSupport.h b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/DebugSupport.h
new file mode 100644
index 000000000..9f88fab71
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/DebugSupport.h
@@ -0,0 +1,292 @@
+/** @file
+ Generic debug support macros, typedefs and prototypes for IA32/x64.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_SUPPORT_H_
+#define _DEBUG_SUPPORT_H_
+
+#include <Uefi.h>
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+
+#define NUM_IDT_ENTRIES 0x78
+#define SYSTEM_TIMER_VECTOR 0x68
+
+typedef
+VOID
+(*DEBUG_PROC) (
+ VOID
+ );
+
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNC) (
+ );
+
+typedef struct {
+ IA32_IDT_GATE_DESCRIPTOR OrigDesc;
+ DEBUG_PROC OrigVector;
+ IA32_IDT_GATE_DESCRIPTOR NewDesc;
+ DEBUG_PROC StubEntry;
+ CALLBACK_FUNC RegisteredCallback;
+} IDT_ENTRY;
+
+extern UINT8 InterruptEntryStub[];
+extern UINT32 StubSize;
+extern VOID (*OrigVector) (VOID);
+extern IDT_ENTRY *IdtEntryTable;
+extern IA32_IDT_GATE_DESCRIPTOR NullDesc;
+
+/**
+ Generic IDT entry.
+
+**/
+VOID
+CommonIdtEntry (
+ VOID
+ );
+
+/**
+ Check whether FXSTOR is supported
+
+ @retval TRUE FXSTOR is supported.
+ @retval FALSE FXSTOR is not supported.
+
+**/
+BOOLEAN
+FxStorSupport (
+ VOID
+ );
+
+/**
+ Encodes an IDT descriptor with the given physical address.
+
+ @param DestDesc The IDT descriptor address.
+ @param Vecotr The interrupt vector entry.
+
+**/
+VOID
+Vect2Desc (
+ IA32_IDT_GATE_DESCRIPTOR * DestDesc,
+ VOID (*Vector) (VOID)
+ );
+
+/**
+ Initializes driver's handler registration database.
+
+ This code executes in boot services context
+ Must be public because it's referenced from DebugSupport.c
+
+ @retval EFI_UNSUPPORTED If IA32 processor does not support FXSTOR/FXRSTOR instructions,
+ the context save will fail, so these processor's are not supported.
+ @retval EFI_OUT_OF_RESOURCES Fails to allocate memory.
+ @retval EFI_SUCCESS Initializes successfully.
+
+**/
+EFI_STATUS
+PlInitializeDebugSupportDriver (
+ VOID
+ );
+
+/**
+ This is the callback that is written to the LoadedImage protocol instance
+ on the image handle. It uninstalls all registered handlers and frees all entry
+ stub memory.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+
+ @retval EFI_SUCCESS Always.
+
+**/
+EFI_STATUS
+EFIAPI
+PlUnloadDebugSupportDriver (
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Returns the maximum value that may be used for the ProcessorIndex parameter in
+ RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+ Hard coded to support only 1 processor for now.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
+ processor index is returned. Always 0 returned.
+
+ @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ Registers a function to be called back periodically in interrupt context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
+ periodic entry point of the debug agent.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ Registers a function to be called when a given processor exception occurs.
+
+ This code executes in boot services context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
+ when the processor exception specified by ExceptionType occurs.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+ causes a fresh memory fetch to retrieve code to be executed.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
+ @param Start Specifies the physical base of the memory range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the processor's instruction
+ cache to invalidate.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+EFIAPI
+InvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+/**
+ Allocate pool for a new IDT entry stub.
+
+ Copy the generic stub into the new buffer and fixup the vector number
+ and jump target address.
+
+ @param ExceptionType This is the exception type that the new stub will be created
+ for.
+ @param Stub On successful exit, *Stub contains the newly allocated entry stub.
+
+**/
+VOID
+CreateEntryStub (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ OUT VOID **Stub
+ );
+
+/**
+ Get Interrupt Handle from IDT Gate Descriptor.
+
+ @param IdtGateDecriptor IDT Gate Descriptor.
+
+ @return Interrupt Handle stored in IDT Gate Descriptor.
+
+**/
+UINTN
+GetInterruptHandleFromIdt (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtGateDecriptor
+ );
+
+/**
+ This is the main worker function that manages the state of the interrupt
+ handlers. It both installs and uninstalls interrupt handlers based on the
+ value of NewCallback. If NewCallback is NULL, then uninstall is indicated.
+ If NewCallback is non-NULL, then install is indicated.
+
+ @param NewCallback If non-NULL, NewCallback specifies the new handler to register.
+ If NULL, specifies that the previously registered handler should
+ be uninstalled.
+ @param ExceptionType Indicates which entry to manage.
+
+ @retval EFI_SUCCESS Process is ok.
+ @retval EFI_INVALID_PARAMETER Requested uninstalling a handler from a vector that has
+ no handler registered for it
+ @retval EFI_ALREADY_STARTED Requested install to a vector that already has a handler registered.
+ @retval others Possible return values are passed through from UnHookEntry and HookEntry.
+
+**/
+EFI_STATUS
+ManageIdtEntryTable (
+ CALLBACK_FUNC NewCallback,
+ EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Creates a nes entry stub. Then saves the current IDT entry and replaces it
+ with an interrupt gate for the new entry point. The IdtEntryTable is updated
+ with the new registered function.
+
+ This code executes in boot services context. The stub entry executes in interrupt
+ context.
+
+ @param ExceptionType Specifies which vector to hook.
+ @param NewCallback A pointer to the new function to be registered.
+
+**/
+VOID
+HookEntry (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN CALLBACK_FUNC NewCallback
+ );
+
+/**
+ Undoes HookEntry. This code executes in boot services context.
+
+ @param ExceptionType Specifies which entry to unhook
+
+**/
+VOID
+UnhookEntry (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c
new file mode 100644
index 000000000..afea3a218
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c
@@ -0,0 +1,367 @@
+/** @file
+ IA32/x64 generic functions to support Debug Support protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugSupport.h"
+
+//
+// This the global main table to keep track of the interrupts
+//
+IDT_ENTRY *IdtEntryTable = NULL;
+
+/**
+ Read IDT Gate Descriptor from IDT Table.
+
+ @param Vector Specifies vector number.
+ @param IdtGateDescriptor Pointer to IDT Gate Descriptor read from IDT Table.
+
+**/
+VOID
+ReadIdtGateDescriptor (
+ IN EFI_EXCEPTION_TYPE Vector,
+ OUT IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor
+ )
+{
+ IA32_DESCRIPTOR IdtrValue;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+
+ AsmReadIdtr (&IdtrValue);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base;
+
+ CopyMem ((VOID *) IdtGateDescriptor, (VOID *) &(IdtTable)[Vector], sizeof (IA32_IDT_GATE_DESCRIPTOR));
+}
+
+/**
+ Write IDT Gate Descriptor into IDT Table.
+
+ @param Vector Specifies vector number.
+ @param IdtGateDescriptor Pointer to IDT Gate Descriptor written into IDT Table.
+
+**/
+VOID
+WriteIdtGateDescriptor (
+ EFI_EXCEPTION_TYPE Vector,
+ IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor
+ )
+{
+ IA32_DESCRIPTOR IdtrValue;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+
+ AsmReadIdtr (&IdtrValue);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base;
+
+ CopyMem ((VOID *) &(IdtTable)[Vector], (VOID *) IdtGateDescriptor, sizeof (IA32_IDT_GATE_DESCRIPTOR));
+}
+
+/**
+ Creates a nes entry stub. Then saves the current IDT entry and replaces it
+ with an interrupt gate for the new entry point. The IdtEntryTable is updated
+ with the new registered function.
+
+ This code executes in boot services context. The stub entry executes in interrupt
+ context.
+
+ @param ExceptionType Specifies which vector to hook.
+ @param NewCallback A pointer to the new function to be registered.
+
+**/
+VOID
+HookEntry (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN CALLBACK_FUNC NewCallback
+ )
+{
+ BOOLEAN OldIntFlagState;
+
+ CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry);
+
+ //
+ // Disables CPU interrupts and returns the previous interrupt state
+ //
+ OldIntFlagState = SaveAndDisableInterrupts ();
+
+ //
+ // gets IDT Gate descriptor by index
+ //
+ ReadIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
+ //
+ // stores orignal interrupt handle
+ //
+ IdtEntryTable[ExceptionType].OrigVector = (DEBUG_PROC) GetInterruptHandleFromIdt (&(IdtEntryTable[ExceptionType].OrigDesc));
+
+ //
+ // encodes new IDT Gate descriptor by stub entry
+ //
+ Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);
+ //
+ // stores NewCallback
+ //
+ IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;
+
+ //
+ // writes back new IDT Gate descriptor
+ //
+ WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));
+
+ //
+ // restore interrupt state
+ //
+ SetInterruptState (OldIntFlagState);
+
+ return ;
+}
+
+/**
+ Undoes HookEntry. This code executes in boot services context.
+
+ @param ExceptionType Specifies which entry to unhook
+
+**/
+VOID
+UnhookEntry (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ BOOLEAN OldIntFlagState;
+
+ //
+ // Disables CPU interrupts and returns the previous interrupt state
+ //
+ OldIntFlagState = SaveAndDisableInterrupts ();
+
+ //
+ // restore the default IDT Date Descriptor
+ //
+ WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
+
+ //
+ // restore interrupt state
+ //
+ SetInterruptState (OldIntFlagState);
+
+ return ;
+}
+
+/**
+ Returns the maximum value that may be used for the ProcessorIndex parameter in
+ RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+ Hard coded to support only 1 processor for now.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
+ processor index is returned. Always 0 returned.
+
+ @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.
+
+**/
+EFI_STATUS
+EFIAPI
+GetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ )
+{
+ *MaxProcessorIndex = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called back periodically in interrupt context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
+ periodic entry point of the debug agent.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ )
+{
+ return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);
+}
+
+/**
+ Registers a function to be called when a given processor exception occurs.
+
+ This code executes in boot services context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
+ when the processor exception specified by ExceptionType occurs.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ return ManageIdtEntryTable (ExceptionCallback, ExceptionType);
+}
+
+
+/**
+ Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+ causes a fresh memory fetch to retrieve code to be executed.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
+ @param Start Specifies the physical base of the memory range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the processor's instruction
+ cache to invalidate.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+EFIAPI
+InvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ )
+{
+ AsmWbinvd ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Common piece of code that invokes the registered handlers.
+
+ This code executes in exception context so no efi calls are allowed.
+ This code is called from assembly file.
+
+ @param ExceptionType Exception type
+ @param ContextRecord System context
+
+**/
+VOID
+InterruptDistrubutionHub (
+ EFI_EXCEPTION_TYPE ExceptionType,
+ EFI_SYSTEM_CONTEXT_IA32 *ContextRecord
+ )
+{
+ if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {
+ if (ExceptionType != SYSTEM_TIMER_VECTOR) {
+ IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);
+ } else {
+ OrigVector = IdtEntryTable[ExceptionType].OrigVector;
+ IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);
+ }
+ }
+}
+
+/**
+ This is the callback that is written to the Loaded Image protocol instance
+ on the image handle. It uninstalls all registered handlers and frees all entry
+ stub memory.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+
+ @retval EFI_SUCCESS Always.
+
+**/
+EFI_STATUS
+EFIAPI
+PlUnloadDebugSupportDriver (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_EXCEPTION_TYPE ExceptionType;
+
+ for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
+ ManageIdtEntryTable (NULL, ExceptionType);
+ //
+ // Free space for each Interrupt Stub precedure.
+ //
+ if (IdtEntryTable[ExceptionType].StubEntry != NULL) {
+ FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);
+ }
+ }
+
+ FreePool (IdtEntryTable);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes driver's handler registration database.
+
+ This code executes in boot services context.
+ Must be public because it's referenced from DebugSupport.c
+
+ @retval EFI_UNSUPPORTED If IA32/x64 processor does not support FXSTOR/FXRSTOR instructions,
+ the context save will fail, so these processors are not supported.
+ @retval EFI_OUT_OF_RESOURCES Fails to allocate memory.
+ @retval EFI_SUCCESS Initializes successfully.
+
+**/
+EFI_STATUS
+PlInitializeDebugSupportDriver (
+ VOID
+ )
+{
+ EFI_EXCEPTION_TYPE ExceptionType;
+
+ //
+ // Check whether FxStor instructions are supported.
+ //
+ if (!FxStorSupport ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES);
+ if (IdtEntryTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType ++) {
+ IdtEntryTable[ExceptionType].StubEntry = (DEBUG_PROC) (UINTN) AllocatePool (StubSize);
+ if (IdtEntryTable[ExceptionType].StubEntry == NULL) {
+ goto ErrorCleanup;
+ }
+
+ //
+ // Copy Interrupt stub code.
+ //
+ CopyMem ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry, InterruptEntryStub, StubSize);
+ }
+ return EFI_SUCCESS;
+
+ErrorCleanup:
+
+ for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
+ if (IdtEntryTable[ExceptionType].StubEntry != NULL) {
+ FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);
+ }
+ }
+ FreePool (IdtEntryTable);
+
+ return EFI_OUT_OF_RESOURCES;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.h b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.h
new file mode 100644
index 000000000..ed7d98ce2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.h
@@ -0,0 +1,16 @@
+/** @file
+ IA32 specific debug support macros, typedefs and prototypes.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLDEBUG_SUPPORT_H_
+#define _PLDEBUG_SUPPORT_H_
+
+#include "Ia32/DebugSupport.h"
+
+#define EFI_ISA IsaIa32
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupportIa32.c b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupportIa32.c
new file mode 100644
index 000000000..37c330626
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupportIa32.c
@@ -0,0 +1,139 @@
+/** @file
+ IA32 specific functions to support Debug Support protocol.
+
+Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlDebugSupport.h"
+
+IA32_IDT_GATE_DESCRIPTOR NullDesc = {{0}};
+
+/**
+ Get Interrupt Handle from IDT Gate Descriptor.
+
+ @param IdtGateDescriptor IDT Gate Descriptor.
+
+ @return Interrupt Handle stored in IDT Gate Descriptor.
+
+**/
+UINTN
+GetInterruptHandleFromIdt (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor
+ )
+{
+ UINTN InterruptHandle;
+
+ //
+ // InterruptHandle 0-15 : OffsetLow
+ // InterruptHandle 16-31 : OffsetHigh
+ //
+ ((UINT16 *) &InterruptHandle)[0] = (UINT16) IdtGateDescriptor->Bits.OffsetLow;
+ ((UINT16 *) &InterruptHandle)[1] = (UINT16) IdtGateDescriptor->Bits.OffsetHigh;
+
+ return InterruptHandle;
+}
+
+/**
+ Allocate pool for a new IDT entry stub.
+
+ Copy the generic stub into the new buffer and fixup the vector number
+ and jump target address.
+
+ @param ExceptionType This is the exception type that the new stub will be created
+ for.
+ @param Stub On successful exit, *Stub contains the newly allocated entry stub.
+
+**/
+VOID
+CreateEntryStub (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ OUT VOID **Stub
+ )
+{
+ UINT8 *StubCopy;
+
+ StubCopy = *Stub;
+
+ //
+ // Fixup the stub code for this vector
+ //
+
+ // The stub code looks like this:
+ //
+ // 00000000 89 25 00000004 R mov AppEsp, esp ; save stack top
+ // 00000006 BC 00008014 R mov esp, offset DbgStkBot ; switch to debugger stack
+ // 0000000B 6A 00 push 0 ; push vector number - will be modified before installed
+ // 0000000D E9 db 0e9h ; jump rel32
+ // 0000000E 00000000 dd 0 ; fixed up to relative address of CommonIdtEntry
+ //
+
+ //
+ // poke in the exception type so the second push pushes the exception type
+ //
+ StubCopy[0x0c] = (UINT8) ExceptionType;
+
+ //
+ // fixup the jump target to point to the common entry
+ //
+ *(UINT32 *) &StubCopy[0x0e] = (UINT32) CommonIdtEntry - (UINT32) &StubCopy[StubSize];
+
+ return ;
+}
+
+/**
+ This is the main worker function that manages the state of the interrupt
+ handlers. It both installs and uninstalls interrupt handlers based on the
+ value of NewCallback. If NewCallback is NULL, then uninstall is indicated.
+ If NewCallback is non-NULL, then install is indicated.
+
+ @param NewCallback If non-NULL, NewCallback specifies the new handler to register.
+ If NULL, specifies that the previously registered handler should
+ be uninstalled.
+ @param ExceptionType Indicates which entry to manage.
+
+ @retval EFI_SUCCESS Installing or Uninstalling operation is ok.
+ @retval EFI_INVALID_PARAMETER Requested uninstalling a handler from a vector that has
+ no handler registered for it
+ @retval EFI_ALREADY_STARTED Requested install to a vector that already has a handler registered.
+
+**/
+EFI_STATUS
+ManageIdtEntryTable (
+ CALLBACK_FUNC NewCallback,
+ EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (CompareMem (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc, sizeof (IA32_IDT_GATE_DESCRIPTOR)) != 0) {
+ //
+ // we've already installed to this vector
+ //
+ if (NewCallback != NULL) {
+ //
+ // if the input handler is non-null, error
+ //
+ Status = EFI_ALREADY_STARTED;
+ } else {
+ UnhookEntry (ExceptionType);
+ }
+ } else {
+ //
+ // no user handler installed on this vector
+ //
+ if (NewCallback == NULL) {
+ //
+ // if the input handler is null, error
+ //
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ HookEntry (ExceptionType, NewCallback);
+ }
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.nasm b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.nasm
new file mode 100644
index 000000000..9cc38a312
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/AsmFuncs.nasm
@@ -0,0 +1,581 @@
+;/** @file
+; Low level x64 routines used by the debug support driver.
+;
+; Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+%define EXCPT64_DIVIDE_ERROR 0
+%define EXCPT64_DEBUG 1
+%define EXCPT64_NMI 2
+%define EXCPT64_BREAKPOINT 3
+%define EXCPT64_OVERFLOW 4
+%define EXCPT64_BOUND 5
+%define EXCPT64_INVALID_OPCODE 6
+%define EXCPT64_DOUBLE_FAULT 8
+%define EXCPT64_INVALID_TSS 10
+%define EXCPT64_SEG_NOT_PRESENT 11
+%define EXCPT64_STACK_FAULT 12
+%define EXCPT64_GP_FAULT 13
+%define EXCPT64_PAGE_FAULT 14
+%define EXCPT64_FP_ERROR 16
+%define EXCPT64_ALIGNMENT_CHECK 17
+%define EXCPT64_MACHINE_CHECK 18
+%define EXCPT64_SIMD 19
+
+%define FXSTOR_FLAG 0x1000000 ; bit cpuid 24 of feature flags
+
+;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
+;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver
+;; MUST check the CPUID feature flags to see that these instructions are available
+;; and fail to init if they are not.
+
+;; fxstor [rdi]
+%macro FXSTOR_RDI 0
+ db 0xf, 0xae, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [rdi]
+%endmacro
+
+;; fxrstor [rsi]
+%macro FXRSTOR_RSI 0
+ db 0xf, 0xae, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [rsi]
+%endmacro
+
+SECTION .data
+
+global ASM_PFX(OrigVector)
+global ASM_PFX(InterruptEntryStub)
+global ASM_PFX(StubSize)
+global ASM_PFX(CommonIdtEntry)
+global ASM_PFX(FxStorSupport)
+extern ASM_PFX(InterruptDistrubutionHub)
+
+ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub)
+AppRsp: dq 0x1111111111111111 ; ?
+DebugRsp: dq 0x2222222222222222 ; ?
+ExtraPush: dq 0x3333333333333333 ; ?
+ExceptData: dq 0x4444444444444444 ; ?
+Rflags: dq 0x5555555555555555 ; ?
+ASM_PFX(OrigVector): dq 0x6666666666666666 ; ?
+
+;; The declarations below define the memory region that will be used for the debug stack.
+;; The context record will be built by pushing register values onto this stack.
+;; It is imparitive that alignment be carefully managed, since the FXSTOR and
+;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
+;;
+;; The stub will switch stacks from the application stack to the debuger stack
+;; and pushes the exception number.
+;;
+;; Then we building the context record on the stack. Since the stack grows down,
+;; we push the fields of the context record from the back to the front. There
+;; are 336 bytes of stack used prior allocating the 512 bytes of stack to be
+;; used as the memory buffer for the fxstor instruction. Therefore address of
+;; the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which
+;; must be 16 byte aligned.
+;;
+;; We carefully locate the stack to make this happen.
+;;
+;; For reference, the context structure looks like this:
+;; struct {
+;; UINT64 ExceptionData;
+;; FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+;; UINT64 RFlags;
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; UINT64 Rip;
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
+
+align 16
+DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment
+ times 0x1ffc dd 0x0 ;; 32K should be enough stack
+ ;; This allocation is coocked to insure
+ ;; that the the buffer for the FXSTORE instruction
+ ;; will be 16 byte aligned also.
+ ;;
+ExceptionNumber: dq 0 ;; first entry will be the vector number pushed by the stub
+
+DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub
+
+DEFAULT REL
+SECTION .text
+
+;------------------------------------------------------------------------------
+; BOOLEAN
+; FxStorSupport (
+; void
+; )
+;
+; Abstract: Returns TRUE if FxStor instructions are supported
+;
+global ASM_PFX(FxStorSupport)
+ASM_PFX(FxStorSupport):
+
+;
+; cpuid corrupts rbx which must be preserved per the C calling convention
+;
+ push rbx
+ mov rax, dword 1
+ cpuid
+ mov eax, edx
+ and rax, FXSTOR_FLAG
+ shr rax, 24
+ pop rbx
+ ret
+
+;------------------------------------------------------------------------------
+; void
+; Vect2Desc (
+; IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
+; void (*Vector) (void) // rdx
+; )
+;
+; Abstract: Encodes an IDT descriptor with the given physical address
+;
+global ASM_PFX(Vect2Desc)
+ASM_PFX(Vect2Desc):
+
+ mov rax, rdx
+ mov word [rcx], ax ; write bits 15..0 of offset
+ mov dx, cs
+ mov word [rcx+2], dx ; SYS_CODE_SEL from GDT
+ mov word [rcx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present
+ shr rax, 16
+ mov word [rcx+6], ax ; write bits 31..16 of offset
+ shr rax, 16
+ mov dword [rcx+8], eax ; write bits 63..32 of offset
+
+ ret
+
+;------------------------------------------------------------------------------
+; InterruptEntryStub
+;
+; Abstract: This code is not a function, but is a small piece of code that is
+; copied and fixed up once for each IDT entry that is hooked.
+;
+ASM_PFX(InterruptEntryStub):
+ push 0 ; push vector number - will be modified before installed
+ db 0xe9 ; jump rel32
+ dd 0 ; fixed up to relative address of CommonIdtEntry
+InterruptEntryStubEnd:
+
+;------------------------------------------------------------------------------
+; CommonIdtEntry
+;
+; Abstract: This code is not a function, but is the common part for all IDT
+; vectors.
+;
+ASM_PFX(CommonIdtEntry):
+;;
+;; At this point, the stub has saved the current application stack esp into AppRsp
+;; and switched stacks to the debug stack, where it pushed the vector number
+;;
+;; The application stack looks like this:
+;;
+;; ...
+;; (last application stack entry)
+;; [16 bytes alignment, do not care it]
+;; SS from interrupted task
+;; RSP from interrupted task
+;; rflags from interrupted task
+;; CS from interrupted task
+;; RIP from interrupted task
+;; Error code <-------------------- Only present for some exeption types
+;;
+;; Vector Number <----------------- pushed in our IDT Entry
+;;
+
+;; The stub switched us to the debug stack and pushed the interrupt number.
+;;
+;; Next, construct the context record. It will be build on the debug stack by
+;; pushing the registers in the correct order so as to create the context structure
+;; on the debug stack. The context record must be built from the end back to the
+;; beginning because the stack grows down...
+;
+;; For reference, the context record looks like this:
+;;
+;; typedef
+;; struct {
+;; UINT64 ExceptionData;
+;; FX_SAVE_STATE_X64 FxSaveState;
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
+;; UINT64 RFlags;
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; UINT64 Rip;
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+;; } SYSTEM_CONTEXT_X64; // 64 bit system context record
+
+;; NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
+ push rax
+ mov rax, qword [rsp+8] ; save vector number
+ mov [ExceptionNumber], rax ; save vector number
+ pop rax
+ add rsp, 8 ; pop vector number
+ mov [AppRsp], rsp ; save stack top
+ lea rsp, [DebugStackBegin] ; switch to debugger stack
+ sub rsp, 8 ; leave space for vector number
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push rcx
+ push rdx
+ push rbx
+ push rsp
+ push rbp
+ push rsi
+ push rdi
+
+;; Save interrupt state rflags register...
+ pushfq
+ pop rax
+ mov [Rflags], rax
+
+;; We need to determine if any extra data was pushed by the exception, and if so, save it
+;; To do this, we check the exception number pushed by the stub, and cache the
+;; result in a variable since we'll need this again.
+ cmp qword [ExceptionNumber], EXCPT64_DOUBLE_FAULT
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_INVALID_TSS
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_SEG_NOT_PRESENT
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_STACK_FAULT
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_GP_FAULT
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_PAGE_FAULT
+ jz ExtraPushOne
+ cmp qword [ExceptionNumber], EXCPT64_ALIGNMENT_CHECK
+ jz ExtraPushOne
+ mov qword [ExtraPush], 0
+ mov qword [ExceptData], 0
+ jmp ExtraPushDone
+ExtraPushOne:
+ mov qword [ExtraPush], 1
+
+;; If there's some extra data, save it also, and modify the saved AppRsp to effectively
+;; pop this value off the application's stack.
+ mov rax, [AppRsp]
+ mov rbx, [rax]
+ mov qword [ExceptData], rbx
+ add rax, 8
+ mov [AppRsp], rax
+
+ExtraPushDone:
+
+;; The "push" above pushed the debug stack rsp. Since what we're actually doing
+;; is building the context record on the debug stack, we need to save the pushed
+;; debug RSP, and replace it with the application's last stack entry...
+ mov rax, [rsp + 24]
+ mov [DebugRsp], rax
+ mov rax, [AppRsp]
+ mov rax, QWORD [rax + 24]
+ ; application stack has ss, rsp, rflags, cs, & rip, so
+ ; last actual application stack entry is saved at offset
+ ; 24 bytes from stack top.
+ mov [rsp + 24], rax
+
+;; continue building context record
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ mov rax, ss
+ push rax
+
+ ; CS from application is one entry back in application stack
+ mov rax, [AppRsp]
+ movzx rax, word [rax + 8]
+ push rax
+
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+;; UINT64 Rip;
+ ; Rip from application is on top of application stack
+ mov rax, [AppRsp]
+ push qword [rax]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ push 0
+ push 0
+ sidt [rsp]
+ push 0
+ push 0
+ sgdt [rsp]
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+;; Rflags from application is two entries back in application stack
+ mov rax, [AppRsp]
+ push qword [rax + 16]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+;; insure FXSAVE/FXRSTOR is enabled in CR4...
+;; ... while we're at it, make sure DE is also enabled...
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 0x208
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ push 0
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+;; clear Dr7 while executing debugger itself
+ xor rax, rax
+ mov dr7, rax
+
+ mov rax, dr6
+ push rax
+;; insure all status bits in dr6 are clear...
+ xor rax, rax
+ mov dr6, rax
+
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+ sub rsp, 512
+ mov rdi, rsp
+ ; IMPORTANT!! The debug stack has been carefully constructed to
+ ; insure that rsp and rdi are 16 byte aligned when we get here.
+ ; They MUST be. If they are not, a GP fault will occur.
+ FXSTOR_RDI
+
+;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT64 ExceptionData;
+ mov rax, [ExceptData]
+ push rax
+
+; call to C code which will in turn call registered handler
+; pass in the vector number
+ mov rdx, rsp
+ mov rcx, [ExceptionNumber]
+ sub rsp, 40
+ call ASM_PFX(InterruptDistrubutionHub)
+ add rsp, 40
+
+; restore context...
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+ mov rsi, rsp
+ FXRSTOR_RSI
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop rax
+ mov dr0, rax
+ pop rax
+ mov dr1, rax
+ pop rax
+ mov dr2, rax
+ pop rax
+ mov dr3, rax
+;; skip restore of dr6. We cleared dr6 during the context save.
+ add rsp, 8
+ pop rax
+ mov dr7, rax
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ mov rax, [AppRsp]
+ pop qword [rax + 16]
+
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add rsp, 48
+
+;; UINT64 Rip;
+ pop qword [rax]
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+
+ pop rax
+ ; mov gs, rax
+ pop rax
+ ; mov fs, rax
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ mov rax, [AppRsp]
+ pop qword [rax + 8]
+ pop rax
+ mov ss, rax
+
+;; The next stuff to restore is the general purpose registers that were pushed
+;; using the "push" instruction.
+;;
+;; The value of RSP as stored in the context record is the application RSP
+;; including the 5 entries on the application stack caused by the exception
+;; itself. It may have been modified by the debug agent, so we need to
+;; determine if we need to relocate the application stack.
+
+ mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx
+ mov rax, [AppRsp]
+ mov rax, QWORD [rax + 24]
+ cmp rbx, rax
+ je NoAppStackMove
+
+ mov rax, [AppRsp]
+ mov rcx, [rax] ; RIP
+ mov [rbx], rcx
+
+ mov rcx, [rax + 8] ; CS
+ mov [rbx + 8], rcx
+
+ mov rcx, [rax + 16] ; RFLAGS
+ mov [rbx + 16], rcx
+
+ mov rcx, [rax + 24] ; RSP
+ mov [rbx + 24], rcx
+
+ mov rcx, [rax + 32] ; SS
+ mov [rbx + 32], rcx
+
+ mov rax, rbx ; modify the saved AppRsp to the new AppRsp
+ mov [AppRsp], rax
+NoAppStackMove:
+ mov rax, [DebugRsp] ; restore the DebugRsp on the debug stack
+ ; so our "pop" will not cause a stack switch
+ mov [rsp + 24], rax
+
+ cmp qword [ExceptionNumber], 0x68
+ jne NoChain
+
+Chain:
+
+;; Restore rflags so when we chain, the flags will be exactly as if we were never here.
+;; We gin up the stack to do an iretq so we can get ALL the flags.
+ mov rax, [AppRsp]
+ mov rbx, [rax + 40]
+ push rbx
+ mov rax, ss
+ push rax
+ mov rax, rsp
+ add rax, 16
+ push rax
+ mov rax, [AppRsp]
+ mov rbx, [rax + 16]
+ and rbx, ~ 0x300 ; special handling for IF and TF
+ push rbx
+ mov rax, cs
+ push rax
+ lea rax, [PhonyIretq]
+ push rax
+ iretq
+PhonyIretq:
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ pop rbp
+ pop rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+;; Switch back to application stack
+ mov rsp, [AppRsp]
+
+;; Jump to original handler
+ jmp [ASM_PFX(OrigVector)]
+
+NoChain:
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ pop rbp
+ pop rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+;; Switch back to application stack
+ mov rsp, [AppRsp]
+
+;; We're outa here...
+ iretq
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupport.h b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupport.h
new file mode 100644
index 000000000..b3743fcdb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupport.h
@@ -0,0 +1,16 @@
+/** @file
+ X64 specific debug support macros.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLDEBUG_SUPPORT_H_
+#define _PLDEBUG_SUPPORT_H_
+
+#include "Ia32/DebugSupport.h"
+
+#define EFI_ISA IsaX64
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupportX64.c b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupportX64.c
new file mode 100644
index 000000000..1e40873bc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DebugSupportDxe/X64/PlDebugSupportX64.c
@@ -0,0 +1,140 @@
+/** @file
+ X64 specific functions to support Debug Support protocol.
+
+Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlDebugSupport.h"
+
+IA32_IDT_GATE_DESCRIPTOR NullDesc = {{0,0}};
+
+/**
+ Get Interrupt Handle from IDT Gate Descriptor.
+
+ @param IdtGateDecriptor IDT Gate Descriptor.
+
+ @return Interrupt Handle stored in IDT Gate Descriptor.
+
+**/
+UINTN
+GetInterruptHandleFromIdt (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtGateDecriptor
+ )
+{
+ UINTN InterruptHandle;
+
+ //
+ // InterruptHandle 0-15 : OffsetLow
+ // InterruptHandle 16-31 : OffsetHigh
+ // InterruptHandle 32-63 : OffsetUpper
+ //
+ InterruptHandle = ((UINTN) IdtGateDecriptor->Bits.OffsetLow) |
+ (((UINTN) IdtGateDecriptor->Bits.OffsetHigh) << 16) |
+ (((UINTN) IdtGateDecriptor->Bits.OffsetUpper) << 32) ;
+
+ return InterruptHandle;
+}
+
+/**
+ Allocate pool for a new IDT entry stub.
+
+ Copy the generic stub into the new buffer and fixup the vector number
+ and jump target address.
+
+ @param ExceptionType This is the exception type that the new stub will be created
+ for.
+ @param Stub On successful exit, *Stub contains the newly allocated entry stub.
+
+**/
+VOID
+CreateEntryStub (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ OUT VOID **Stub
+ )
+{
+ UINT8 *StubCopy;
+
+ StubCopy = *Stub;
+
+ //
+ // Fixup the stub code for this vector
+ //
+
+ // The stub code looks like this:
+ //
+ // 00000000 6A 00 push 0 ; push vector number - will be modified before installed
+ // 00000002 E9 db 0e9h ; jump rel32
+ // 00000003 00000000 dd 0 ; fixed up to relative address of CommonIdtEntry
+ //
+
+ //
+ // poke in the exception type so the second push pushes the exception type
+ //
+ StubCopy[0x1] = (UINT8) ExceptionType;
+
+ //
+ // fixup the jump target to point to the common entry
+ //
+ *(UINT32 *) &StubCopy[0x3] = (UINT32)((UINTN) CommonIdtEntry - (UINTN) &StubCopy[StubSize]);
+
+ return;
+}
+
+/**
+ This is the main worker function that manages the state of the interrupt
+ handlers. It both installs and uninstalls interrupt handlers based on the
+ value of NewCallback. If NewCallback is NULL, then uninstall is indicated.
+ If NewCallback is non-NULL, then install is indicated.
+
+ @param NewCallback If non-NULL, NewCallback specifies the new handler to register.
+ If NULL, specifies that the previously registered handler should
+ be uninstalled.
+ @param ExceptionType Indicates which entry to manage.
+
+ @retval EFI_SUCCESS Process is ok.
+ @retval EFI_INVALID_PARAMETER Requested uninstalling a handler from a vector that has
+ no handler registered for it
+ @retval EFI_ALREADY_STARTED Requested install to a vector that already has a handler registered.
+ @retval others Possible return values are passed through from UnHookEntry and HookEntry.
+
+**/
+EFI_STATUS
+ManageIdtEntryTable (
+ CALLBACK_FUNC NewCallback,
+ EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (CompareMem (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc, sizeof (IA32_IDT_GATE_DESCRIPTOR)) != 0) {
+ //
+ // we've already installed to this vector
+ //
+ if (NewCallback != NULL) {
+ //
+ // if the input handler is non-null, error
+ //
+ Status = EFI_ALREADY_STARTED;
+ } else {
+ UnhookEntry (ExceptionType);
+ }
+ } else {
+ //
+ // no user handler installed on this vector
+ //
+ if (NewCallback == NULL) {
+ //
+ // if the input handler is null, error
+ //
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ HookEntry (ExceptionType, NewCallback);
+ }
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePath.c b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePath.c
new file mode 100644
index 000000000..cba214987
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePath.c
@@ -0,0 +1,99 @@
+/** @file
+ Device Path Driver to produce DevPathUtilities Protocol, DevPathFromText Protocol
+ and DevPathToText Protocol.
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Protocol/DevicePathUtilities.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_DEVICE_PATH_UTILITIES_PROTOCOL mDevicePathUtilities = {
+ GetDevicePathSize,
+ DuplicateDevicePath,
+ AppendDevicePath,
+ AppendDevicePathNode,
+ AppendDevicePathInstance,
+ GetNextDevicePathInstance,
+ IsDevicePathMultiInstance,
+ CreateDeviceNode
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_DEVICE_PATH_TO_TEXT_PROTOCOL mDevicePathToText = {
+ ConvertDeviceNodeToText,
+ ConvertDevicePathToText
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL mDevicePathFromText = {
+ ConvertTextToDeviceNode,
+ ConvertTextToDevicePath
+};
+
+/**
+ The user Entry Point for DevicePath module.
+
+ This is the entry point for DevicePath module. It installs the UEFI Device Path Utility Protocol and
+ optionally the Device Path to Text and Device Path from Text protocols based on feature flags.
+
+ @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 Others Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+DevicePathEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = EFI_UNSUPPORTED;
+ if (FeaturePcdGet (PcdDevicePathSupportDevicePathToText)) {
+ if (FeaturePcdGet (PcdDevicePathSupportDevicePathFromText)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDevicePathUtilitiesProtocolGuid, &mDevicePathUtilities,
+ &gEfiDevicePathToTextProtocolGuid, &mDevicePathToText,
+ &gEfiDevicePathFromTextProtocolGuid, &mDevicePathFromText,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDevicePathUtilitiesProtocolGuid, &mDevicePathUtilities,
+ &gEfiDevicePathToTextProtocolGuid, &mDevicePathToText,
+ NULL
+ );
+ }
+ } else {
+ if (FeaturePcdGet (PcdDevicePathSupportDevicePathFromText)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDevicePathUtilitiesProtocolGuid, &mDevicePathUtilities,
+ &gEfiDevicePathFromTextProtocolGuid, &mDevicePathFromText,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDevicePathUtilitiesProtocolGuid, &mDevicePathUtilities,
+ NULL
+ );
+ }
+ }
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
new file mode 100644
index 000000000..0b8ea7267
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# Device path driver that produces three UEFI device path protocols.
+#
+# This driver produces Device Path Utilities protocol and optionally
+# DevicePahtToText and DevicePathFromText protocols based on feature flags
+# PcdDevicePathSupportDevicePathToText & PcdDevicePathSupportDevicePathFromText
+# respectively.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DevicePathDxe
+ MODULE_UNI_FILE = DevicePathDxe.uni
+ FILE_GUID = 9B680FCE-AD6B-4F3A-B60B-F59899003443
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DevicePathEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DevicePath.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiDevicePathToTextProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText ## SOMETIMES_PRODUCES
+ gEfiDevicePathFromTextProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathToText ## SOMETIMES_PRODUCES
+ gEfiDevicePathUtilitiesProtocolGuid ## PRODUCES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathToText ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DevicePathDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.uni b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.uni
new file mode 100644
index 000000000..05337a7b2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Device path driver that produces three UEFI device path protocols.
+//
+// This driver produces Device Path Utilities protocol and optionally
+// DevicePahtToText and DevicePathFromText protocols based on feature flags
+// PcdDevicePathSupportDevicePathToText & PcdDevicePathSupportDevicePathFromText
+// respectively.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces three UEFI device path protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces Device Path Utilities protocol and optionally DevicePahtToText and DevicePathFromText protocols based on feature flags PcdDevicePathSupportDevicePathToText & PcdDevicePathSupportDevicePathFromText respectively."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxeExtra.uni
new file mode 100644
index 000000000..d4beebcd6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DevicePathDxe/DevicePathDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DevicePathDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI Device Path DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf
new file mode 100644
index 000000000..691203816
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf
@@ -0,0 +1,68 @@
+## @file
+# PeiCdExpress recovery module.
+#
+# This module reads data from CDROM device by all installed block IO ppi and
+# finds whether there is Recovery data in the device. If it finds recovery
+# data, it will install Device Recovery Module PPI.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CdExpressPei
+ MODULE_UNI_FILE = CdExpressPei.uni
+ FILE_GUID = 31e147a6-d39a-4147-9da3-befd4d523243
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CdExpressPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PeiCdExpress.c
+ PeiCdExpress.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ MemoryAllocationLib
+ PcdLib
+
+[Guids]
+ gRecoveryOnDataCdGuid ## CONSUMES ## UNDEFINED # Indicate the recovery device type
+
+
+[Ppis]
+ ## NOTIFY
+ ## CONSUMES
+ gEfiPeiVirtualBlockIoPpiGuid
+ ## NOTIFY
+ ## CONSUMES
+ gEfiPeiVirtualBlockIo2PpiGuid
+ gEfiPeiDeviceRecoveryModulePpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CdExpressPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni
new file mode 100644
index 000000000..89f77e2a9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni
@@ -0,0 +1,18 @@
+// /** @file
+// PeiCdExpress recovery module.
+//
+// This module reads data from CDROM device by all installed block IO ppi and
+// finds whether there is Recovery data in the device. If it finds recovery
+// data, it will install Device Recovery Module PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PeiCdExpress recovery module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module reads data from CDROM device by all installed block IO ppi and finds whether there is Recovery data in the device. If it finds recovery data, it will install Device Recovery Module PPI."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni
new file mode 100644
index 000000000..d05fff83e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CdExpressPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"CD PEI Module for Recovery"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c
new file mode 100644
index 000000000..fd34f07ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c
@@ -0,0 +1,715 @@
+/** @file
+ Source file for CD recovery PEIM
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiCdExpress.h"
+
+PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL;
+CHAR8 *mRecoveryFileName;
+UINTN mRecoveryFileNameSize;
+
+/**
+ Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
+ installation notification
+
+ @param FileHandle The file handle of the image.
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory.
+
+**/
+EFI_STATUS
+EFIAPI
+CdExpressPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData)));
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mRecoveryFileNameSize = PcdGetSize(PcdRecoveryFileName) / sizeof(CHAR16);
+ mRecoveryFileName = AllocatePool(mRecoveryFileNameSize);
+ if (mRecoveryFileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName), mRecoveryFileName, mRecoveryFileNameSize);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize Private Data (to zero, as is required by subsequent operations)
+ //
+ ZeroMem (PrivateData, sizeof (*PrivateData));
+ PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE;
+
+ PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE));
+ if (PrivateData->BlockBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->CapsuleCount = 0;
+ Status = UpdateBlocksAndVolumes (PrivateData, TRUE);
+ Status = UpdateBlocksAndVolumes (PrivateData, FALSE);
+
+ //
+ // Installs Ppi
+ //
+ PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;
+ PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;
+ PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;
+
+ PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
+ PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;
+
+ Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // PrivateData is allocated now, set it to the module variable
+ //
+ mPrivateData = PrivateData;
+
+ //
+ // Installs Block Io Ppi notification function
+ //
+ PrivateData->NotifyDescriptor.Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
+ );
+ PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
+ PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;
+
+ PrivateData->NotifyDescriptor2.Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
+ );
+ PrivateData->NotifyDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid;
+ PrivateData->NotifyDescriptor2.Notify = BlockIoNotifyEntry;
+
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
+
+}
+
+/**
+ BlockIo installation notification function.
+
+ This function finds out all the current Block IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoNotifyEntry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
+ UpdateBlocksAndVolumes (mPrivateData, TRUE);
+ } else {
+ UpdateBlocksAndVolumes (mPrivateData, FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds out all the current Block IO PPIs in the system and add them into private data.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
+
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.
+
+**/
+EFI_STATUS
+UpdateBlocksAndVolumes (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN BOOLEAN BlockIo2
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
+ UINTN BlockIoPpiInstance;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN NumberBlockDevices;
+ UINTN IndexBlockDevice;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ EFI_PEI_BLOCK_IO2_MEDIA Media2;
+ EFI_PEI_SERVICES **PeiServices;
+
+ IndexBlockDevice = 0;
+ BlockIo2Ppi = NULL;
+ BlockIoPpi = NULL;
+ //
+ // Find out all Block Io Ppi instances within the system
+ // Assuming all device Block Io Peims are dispatched already
+ //
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
+ if (BlockIo2) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIo2Ppi
+ );
+ } else {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIoPpi
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Done with all Block Io Ppis
+ //
+ break;
+ }
+
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIo2Ppi,
+ &NumberBlockDevices
+ );
+ } else {
+ Status = BlockIoPpi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIoPpi,
+ &NumberBlockDevices
+ );
+ }
+ if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
+ continue;
+ }
+ //
+ // Just retrieve the first block, should emulate all blocks.
+ //
+ for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ &Media2
+ );
+ if (EFI_ERROR (Status) ||
+ !Media2.MediaPresent ||
+ ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) ||
+ (Media2.BlockSize != PEI_CD_BLOCK_SIZE)
+ ) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize));
+ } else {
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIoPpi,
+ IndexBlockDevice,
+ &Media
+ );
+ if (EFI_ERROR (Status) ||
+ !Media.MediaPresent ||
+ ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||
+ (Media.BlockSize != PEI_CD_BLOCK_SIZE)
+ ) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize));
+ }
+
+ DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));
+
+ DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice;
+ if (BlockIo2) {
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi;
+ } else {
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi;
+ }
+ Status = FindRecoveryCapsules (PrivateData);
+ DEBUG ((EFI_D_INFO, "Status is %d\n", Status));
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PrivateData->CapsuleCount++;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds out the recovery capsule in the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FindRecoveryCapsules (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Lba;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN BufferSize;
+ UINT8 *Buffer;
+ UINT8 Type;
+ UINT8 *StandardID;
+ UINT32 RootDirLBA;
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord;
+ UINTN VolumeSpaceSize;
+ BOOLEAN StartOfVolume;
+ UINTN OriginalLBA;
+ UINTN IndexBlockDevice;
+
+ Buffer = PrivateData->BlockBuffer;
+ BufferSize = PEI_CD_BLOCK_SIZE;
+
+ Lba = 16;
+ //
+ // The volume descriptor starts on Lba 16
+ //
+ IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;
+ BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;
+ BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2;
+
+ VolumeSpaceSize = 0;
+ StartOfVolume = TRUE;
+ OriginalLBA = 16;
+
+ while (TRUE) {
+ SetMem (Buffer, BufferSize, 0);
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIoPpi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);
+ if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {
+ break;
+ }
+
+ if (StartOfVolume) {
+ OriginalLBA = Lba;
+ StartOfVolume = FALSE;
+ }
+
+ Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);
+ if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {
+ if (VolumeSpaceSize == 0) {
+ break;
+ } else {
+ Lba = (OriginalLBA + VolumeSpaceSize);
+ VolumeSpaceSize = 0;
+ StartOfVolume = TRUE;
+ continue;
+ }
+ }
+
+ if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {
+ Lba++;
+ continue;
+ }
+
+ VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);
+
+ RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);
+ RootDirLBA = RoorDirRecord->LocationOfExtent[0];
+
+ Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Just look for the first primary descriptor
+ //
+ return EFI_SUCCESS;
+ }
+
+ Lba++;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieves the recovery capsule in root directory of the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIoPpi The Block IO PPI used to access the volume.
+ @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
+ @param IndexBlockDevice The index of current block device.
+ @param Lba The starting logic block address to retrieve capsule.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+ @retval Others
+
+**/
+EFI_STATUS
+EFIAPI
+RetrieveCapsuleFileFromRoot (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
+ IN UINTN IndexBlockDevice,
+ IN UINT32 Lba
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT8 *Buffer;
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord;
+ UINTN Index;
+
+ Buffer = PrivateData->BlockBuffer;
+ BufferSize = PEI_CD_BLOCK_SIZE;
+
+ SetMem (Buffer, BufferSize, 0);
+
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIoPpi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (1) {
+ FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;
+
+ if (FileRecord->Length == 0) {
+ break;
+ }
+ //
+ // Not intend to check other flag now
+ //
+ if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ for (Index = 0; Index < FileRecord->FileIDLength; Index++) {
+ if (FileRecord->FileID[Index] == ';') {
+ break;
+ }
+ }
+
+ if (Index != mRecoveryFileNameSize - 1) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ if (!StringCmp (FileRecord->FileID, (UINT8 *)mRecoveryFileName, mRecoveryFileNameSize - 1, FALSE)) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleBlockAlignedSize =
+ (
+ FileRecord->DataLength[0] /
+ PEI_CD_BLOCK_SIZE +
+ 1
+ ) *
+ PEI_CD_BLOCK_SIZE;
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = FileRecord->DataLength[0];
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Returns the number of DXE capsules residing on the device.
+
+ This function searches for DXE capsules from the associated device and returns
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is
+ assumed to be the highest load priority and entry N is assumed to be the lowest
+ priority.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
+ output, *NumberRecoveryCapsules contains
+ the number of recovery capsule images
+ available for retrieval from this PEIM
+ instance.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberRecoveryCapsules (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ OUT UINTN *NumberRecoveryCapsules
+ )
+{
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+ UpdateBlocksAndVolumes (PrivateData, TRUE);
+ UpdateBlocksAndVolumes (PrivateData, FALSE);
+ *NumberRecoveryCapsules = PrivateData->CapsuleCount;
+
+ if (*NumberRecoveryCapsules == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the size and type of the requested recovery capsule.
+
+ This function gets the size and type of the capsule specified by CapsuleInstance.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
+ the information. This parameter must be between
+ one and the value returned by GetNumberRecoveryCapsules()
+ in NumberRecoveryCapsules.
+ @param[out] Size A pointer to a caller-allocated UINTN in which
+ the size of the requested recovery module is
+ returned.
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
+ the type of the requested recovery capsule is
+ returned. The semantic meaning of the value
+ returned is defined by the implementation.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetRecoveryCapsuleInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT UINTN *Size,
+ OUT EFI_GUID *CapsuleType
+ )
+{
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+ UINTN NumberRecoveryCapsules;
+ EFI_STATUS Status;
+
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+
+ *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;
+ CopyMem (
+ CapsuleType,
+ &gRecoveryOnDataCdGuid,
+ sizeof (EFI_GUID)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Loads a DXE capsule from some media into memory.
+
+ This function, by whatever mechanism, retrieves a DXE capsule from some device
+ and loads it into memory. Note that the published interface is device neutral.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
+ @param[out] Buffer Specifies a caller-allocated buffer in which
+ the requested recovery capsule will be returned.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN NumberRecoveryCapsules;
+
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+ BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;
+ BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2;
+
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ PeiServices,
+ BlockIo2Ppi,
+ PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ PeiServices,
+ BlockIoPpi,
+ PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
+ Buffer
+ );
+ }
+ return Status;
+}
+
+/**
+ This function compares two ASCII strings in case sensitive/insensitive way.
+
+ @param Source1 The first string.
+ @param Source2 The second string.
+ @param Size The maximum comparison length.
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
+
+ @retval TRUE The two strings are the same.
+ @retval FALSE The two string are not the same.
+
+**/
+BOOLEAN
+StringCmp (
+ IN UINT8 *Source1,
+ IN UINT8 *Source2,
+ IN UINTN Size,
+ IN BOOLEAN CaseSensitive
+ )
+{
+ UINTN Index;
+ UINT8 Dif;
+
+ for (Index = 0; Index < Size; Index++) {
+ if (Source1[Index] == Source2[Index]) {
+ continue;
+ }
+
+ if (!CaseSensitive) {
+ Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));
+ if (Dif == ('a' - 'A')) {
+ continue;
+ }
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h
new file mode 100644
index 000000000..513f0709b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h
@@ -0,0 +1,292 @@
+/** @file
+ Header file for CD recovery PEIM
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_CD_EXPRESS_H_
+#define _PEI_CD_EXPRESS_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Guid/RecoveryDevice.h>
+#include <Ppi/DeviceRecoveryModule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+#pragma pack(1)
+
+#define PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI 8
+#define PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER 16
+
+#define PEI_CD_BLOCK_SIZE 0x800
+#define PEI_MEMMORY_PAGE_SIZE 0x1000
+
+//
+// Following are defined according to ISO-9660 specification
+//
+#define PEI_CD_STANDARD_ID "CD001"
+#define PEI_CD_EXPRESS_STANDARD_ID_SIZE 5
+
+#define PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET 0
+#define PEI_CD_EXPRESS_STANDARD_ID_OFFSET 1
+#define PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET 80
+#define PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET 156
+
+#define PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY 1
+#define PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR 255
+
+#define PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR 0x02
+
+typedef struct {
+ UINTN CapsuleStartLBA;
+ UINTN CapsuleSize;
+ UINTN CapsuleBlockAlignedSize;
+ UINTN IndexBlock;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2;
+} PEI_CD_EXPRESS_CAPSULE_DATA;
+
+#define PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'c', 'd', 'e')
+
+typedef struct {
+
+ UINTN Signature;
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor2;
+
+ UINT8 *BlockBuffer;
+ UINTN CapsuleCount;
+ PEI_CD_EXPRESS_CAPSULE_DATA CapsuleData[PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER];
+
+} PEI_CD_EXPRESS_PRIVATE_DATA;
+
+#define PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ PEI_CD_EXPRESS_PRIVATE_DATA, \
+ DeviceRecoveryPpi, \
+ PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINT8 Length;
+ UINT8 ExtendedAttributeRecordLength;
+ UINT32 LocationOfExtent[2];
+ UINT32 DataLength[2];
+ UINT8 DateTime[7];
+ UINT8 Flag;
+ UINT8 FileUnitSize;
+ UINT8 InterleaveGapSize;
+ UINT32 VolumeSequenceNumber;
+ UINT8 FileIDLength;
+ UINT8 FileID[1];
+} PEI_CD_EXPRESS_DIR_FILE_RECORD;
+
+/**
+ BlockIo installation notification function.
+
+ This function finds out all the current Block IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoNotifyEntry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Finds out all the current Block IO PPIs in the system and add them into private data.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
+
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.
+
+**/
+EFI_STATUS
+UpdateBlocksAndVolumes (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN BOOLEAN BlockIo2
+ );
+
+/**
+ Returns the number of DXE capsules residing on the device.
+
+ This function searches for DXE capsules from the associated device and returns
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is
+ assumed to be the highest load priority and entry N is assumed to be the lowest
+ priority.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
+ output, *NumberRecoveryCapsules contains
+ the number of recovery capsule images
+ available for retrieval from this PEIM
+ instance.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberRecoveryCapsules (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ OUT UINTN *NumberRecoveryCapsules
+ );
+
+/**
+ Returns the size and type of the requested recovery capsule.
+
+ This function gets the size and type of the capsule specified by CapsuleInstance.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
+ the information. This parameter must be between
+ one and the value returned by GetNumberRecoveryCapsules()
+ in NumberRecoveryCapsules.
+ @param[out] Size A pointer to a caller-allocated UINTN in which
+ the size of the requested recovery module is
+ returned.
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
+ the type of the requested recovery capsule is
+ returned. The semantic meaning of the value
+ returned is defined by the implementation.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetRecoveryCapsuleInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT UINTN *Size,
+ OUT EFI_GUID *CapsuleType
+ );
+
+/**
+ Loads a DXE capsule from some media into memory.
+
+ This function, by whatever mechanism, retrieves a DXE capsule from some device
+ and loads it into memory. Note that the published interface is device neutral.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
+ @param[out] Buffer Specifies a caller-allocated buffer in which
+ the requested recovery capsule will be returned.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT VOID *Buffer
+ );
+
+/**
+ Finds out the recovery capsule in the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FindRecoveryCapsules (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ Retrieves the recovery capsule in root directory of the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIoPpi The Block IO PPI used to access the volume.
+ @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
+ @param IndexBlockDevice The index of current block device.
+ @param Lba The starting logic block address to retrieve capsule.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+ @retval Others
+
+**/
+EFI_STATUS
+EFIAPI
+RetrieveCapsuleFileFromRoot (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
+ IN UINTN IndexBlockDevice,
+ IN UINT32 Lba
+ );
+
+
+/**
+ This function compares two ASCII strings in case sensitive/insensitive way.
+
+ @param Source1 The first string.
+ @param Source2 The second string.
+ @param Size The maximum comparison length.
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
+
+ @retval TRUE The two strings are the same.
+ @retval FALSE The two string are not the same.
+
+**/
+BOOLEAN
+StringCmp (
+ IN UINT8 *Source1,
+ IN UINT8 *Source2,
+ IN UINTN Size,
+ IN BOOLEAN CaseSensitive
+ );
+
+#pragma pack()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c
new file mode 100644
index 000000000..ba6e427cd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c
@@ -0,0 +1,183 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for DiskIo driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DiskIo.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName = {
+ DiskIoComponentNameGetDriverName,
+ DiskIoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDiskIoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DiskIoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DiskIoComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for DiskIo module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDiskIoDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Generic Disk I/O 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
+DiskIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDiskIoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gDiskIoComponentName)
+ );
+}
+
+
+
+/**
+ 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
+DiskIoComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
new file mode 100644
index 000000000..e19466bd2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
@@ -0,0 +1,1262 @@
+/** @file
+ DiskIo driver that lays on every BlockIo protocol in the system.
+ DiskIo converts a block oriented device to a byte oriented device.
+
+ Disk access may have to handle unaligned request about sector boundaries.
+ There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DiskIo.h"
+
+//
+// Driver binding protocol implementation for DiskIo driver.
+//
+EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
+ DiskIoDriverBindingSupported,
+ DiskIoDriverBindingStart,
+ DiskIoDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Template for DiskIo private data structure.
+// The pointer to BlockIo protocol interface is assigned dynamically.
+//
+DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
+ DISK_IO_PRIVATE_DATA_SIGNATURE,
+ {
+ EFI_DISK_IO_PROTOCOL_REVISION,
+ DiskIoReadDisk,
+ DiskIoWriteDisk
+ },
+ {
+ EFI_DISK_IO2_PROTOCOL_REVISION,
+ DiskIo2Cancel,
+ DiskIo2ReadDiskEx,
+ DiskIo2WriteDiskEx,
+ DiskIo2FlushDiskEx
+ }
+};
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @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
+DiskIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO protocol and
+ installing a Disk IO protocol on ControllerHandle.
+
+ @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
+DiskIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ DISK_IO_PRIVATE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ Instance = NULL;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Connect to the Block IO and Block IO2 interface on ControllerHandle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
+ }
+
+ //
+ // Initialize the Disk IO device instance.
+ //
+ Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
+ if (Instance == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
+ //
+ ASSERT ((Instance->BlockIo2 == NULL) ||
+ ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
+ (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
+ ));
+
+ InitializeListHead (&Instance->TaskQueue);
+ EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
+ Instance->SharedWorkingBuffer = AllocateAlignedPages (
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
+ Instance->BlockIo->Media->IoAlign
+ );
+ if (Instance->SharedWorkingBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // Install protocol interfaces for the Disk IO device.
+ //
+ if (Instance->BlockIo2 != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ NULL
+ );
+ }
+
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
+ FreeAlignedPages (
+ Instance->SharedWorkingBuffer,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+ );
+ }
+
+ if (Instance != NULL) {
+ FreePool (Instance);
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle by removing Disk IO protocol and closing
+ the Block IO protocol on ControllerHandle.
+
+ @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
+DiskIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ DISK_IO_PRIVATE_DATA *Instance;
+ BOOLEAN AllTaskDone;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ (VOID **) &DiskIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DiskIo2 = NULL;
+ }
+
+ Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
+
+ if (DiskIo2 != NULL) {
+ //
+ // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
+ //
+ ASSERT (Instance->BlockIo2 != NULL);
+ Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ NULL
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+
+ do {
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ AllTaskDone = IsListEmpty (&Instance->TaskQueue);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+ } while (!AllTaskDone);
+
+ FreeAlignedPages (
+ Instance->SharedWorkingBuffer,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+ );
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (DiskIo2 != NULL) {
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ FreePool (Instance);
+ }
+
+ return Status;
+}
+
+
+/**
+ Destroy the sub task.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Subtask Subtask.
+
+ @return LIST_ENTRY * Pointer to the next link of subtask.
+**/
+LIST_ENTRY *
+DiskIoDestroySubtask (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN DISK_IO_SUBTASK *Subtask
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (Subtask->Task != NULL) {
+ EfiAcquireLock (&Subtask->Task->SubtasksLock);
+ }
+ Link = RemoveEntryList (&Subtask->Link);
+ if (Subtask->Task != NULL) {
+ EfiReleaseLock (&Subtask->Task->SubtasksLock);
+ }
+
+ if (!Subtask->Blocking) {
+ if (Subtask->WorkingBuffer != NULL) {
+ FreeAlignedPages (
+ Subtask->WorkingBuffer,
+ Subtask->Length < Instance->BlockIo->Media->BlockSize
+ ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
+ : EFI_SIZE_TO_PAGES (Subtask->Length)
+ );
+ }
+ if (Subtask->BlockIo2Token.Event != NULL) {
+ gBS->CloseEvent (Subtask->BlockIo2Token.Event);
+ }
+ }
+ FreePool (Subtask);
+
+ return Link;
+}
+
+/**
+ The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the DISK_IO_SUBTASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnReadWriteComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DISK_IO_SUBTASK *Subtask;
+ DISK_IO2_TASK *Task;
+ EFI_STATUS TransactionStatus;
+ DISK_IO_PRIVATE_DATA *Instance;
+
+ Subtask = (DISK_IO_SUBTASK *) Context;
+ TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
+ Task = Subtask->Task;
+ Instance = Task->Instance;
+
+ ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE);
+ ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
+ ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);
+
+ if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
+ (Task->Token != NULL) && !Subtask->Write
+ ) {
+ CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+ }
+
+ DiskIoDestroySubtask (Instance, Subtask);
+
+ if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
+ if (Task->Token != NULL) {
+ //
+ // Signal error status once the subtask is failed.
+ // Or signal the last status once the last subtask is finished.
+ //
+ Task->Token->TransactionStatus = TransactionStatus;
+ gBS->SignalEvent (Task->Token->Event);
+
+ //
+ // Mark token to NULL indicating the Task is a dead task.
+ //
+ Task->Token = NULL;
+ }
+ }
+}
+
+/**
+ Create the subtask.
+
+ @param Write TRUE: Write request; FALSE: Read request.
+ @param Lba The starting logical block address to read from on the device.
+ @param Offset The starting byte offset to read from the LBA.
+ @param Length The number of bytes to read from the device.
+ @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
+ @param Buffer The buffer to hold the data for reading or writing.
+ @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
+
+ @return A pointer to the created subtask.
+**/
+DISK_IO_SUBTASK *
+DiskIoCreateSubtask (
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *WorkingBuffer, OPTIONAL
+ IN VOID *Buffer,
+ IN BOOLEAN Blocking
+ )
+{
+ DISK_IO_SUBTASK *Subtask;
+ EFI_STATUS Status;
+
+ Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
+ if (Subtask == NULL) {
+ return NULL;
+ }
+ Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;
+ Subtask->Write = Write;
+ Subtask->Lba = Lba;
+ Subtask->Offset = Offset;
+ Subtask->Length = Length;
+ Subtask->WorkingBuffer = WorkingBuffer;
+ Subtask->Buffer = Buffer;
+ Subtask->Blocking = Blocking;
+ if (!Blocking) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DiskIo2OnReadWriteComplete,
+ Subtask,
+ &Subtask->BlockIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Subtask);
+ return NULL;
+ }
+ }
+ DEBUG ((
+ EFI_D_BLKIO,
+ " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
+ Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
+ ));
+
+ return Subtask;
+}
+
+/**
+ Create the subtask list.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Write TRUE: Write request; FALSE: Read request.
+ @param Offset The starting byte offset to read from the device.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the buffer for the data.
+ @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
+ @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
+ @param Subtasks The subtask list header.
+
+ @retval TRUE The subtask list is created successfully.
+ @retval FALSE The subtask list is not created.
+**/
+BOOLEAN
+DiskIoCreateSubtaskList (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN BOOLEAN Write,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN BOOLEAN Blocking,
+ IN VOID *SharedWorkingBuffer,
+ IN OUT LIST_ENTRY *Subtasks
+ )
+{
+ UINT32 BlockSize;
+ UINT32 IoAlign;
+ UINT64 Lba;
+ UINT64 OverRunLba;
+ UINT32 UnderRun;
+ UINT32 OverRun;
+ UINT8 *BufferPtr;
+ UINTN Length;
+ UINTN DataBufferSize;
+ DISK_IO_SUBTASK *Subtask;
+ VOID *WorkingBuffer;
+ LIST_ENTRY *Link;
+
+ DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
+
+ BlockSize = Instance->BlockIo->Media->BlockSize;
+ IoAlign = Instance->BlockIo->Media->IoAlign;
+ if (IoAlign == 0) {
+ IoAlign = 1;
+ }
+
+ Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
+ BufferPtr = (UINT8 *) Buffer;
+
+ //
+ // Special handling for zero BufferSize
+ //
+ if (BufferSize == 0) {
+ Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ return TRUE;
+ }
+
+ if (UnderRun != 0) {
+ Length = MIN (BlockSize - UnderRun, BufferSize);
+ if (Blocking) {
+ WorkingBuffer = SharedWorkingBuffer;
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ goto Done;
+ }
+ }
+ if (Write) {
+ //
+ // A half write operation can be splitted to a blocking block-read and half write operation
+ // This can simplify the sub task processing logic
+ //
+ Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += Length;
+ Offset += Length;
+ BufferSize -= Length;
+ Lba ++;
+ }
+
+ OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
+ BufferSize -= OverRun;
+
+ if (OverRun != 0) {
+ if (Blocking) {
+ WorkingBuffer = SharedWorkingBuffer;
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ goto Done;
+ }
+ }
+ if (Write) {
+ //
+ // A half write operation can be splitted to a blocking block-read and half write operation
+ // This can simplify the sub task processing logic
+ //
+ Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ if (OverRunLba > Lba) {
+ //
+ // If the DiskIo maps directly to a BlockIo device do the read.
+ //
+ if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += BufferSize;
+ Offset += BufferSize;
+ BufferSize -= BufferSize;
+
+ } else {
+ if (Blocking) {
+ //
+ // Use the allocated buffer instead of the original buffer
+ // to avoid alignment issue.
+ //
+ for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
+ DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
+
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += DataBufferSize;
+ Offset += DataBufferSize;
+ BufferSize -= DataBufferSize;
+ }
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ //
+ // If there is not enough memory, downgrade to blocking access
+ //
+ DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
+ if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
+ goto Done;
+ }
+ } else {
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ BufferPtr += BufferSize;
+ Offset += BufferSize;
+ BufferSize -= BufferSize;
+ }
+ }
+ }
+
+ ASSERT (BufferSize == 0);
+
+ return TRUE;
+
+Done:
+ //
+ // Remove all the subtasks.
+ //
+ for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ Link = DiskIoDestroySubtask (Instance, Subtask);
+ }
+ return FALSE;
+}
+
+/**
+ Terminate outstanding asynchronous requests to a device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding requests were successfully terminated.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
+ operation.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2Cancel (
+ IN EFI_DISK_IO2_PROTOCOL *This
+ )
+{
+ DISK_IO_PRIVATE_DATA *Instance;
+ DISK_IO2_TASK *Task;
+ LIST_ENTRY *Link;
+
+ Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+
+ for (Link = GetFirstNode (&Instance->TaskQueue)
+ ; !IsNull (&Instance->TaskQueue, Link)
+ ; Link = GetNextNode (&Instance->TaskQueue, Link)
+ ) {
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+
+ if (Task->Token != NULL) {
+ Task->Token->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Task->Token->Event);
+ //
+ // Set Token to NULL so that the further BlockIo2 responses will be ignored
+ //
+ Task->Token = NULL;
+ }
+ }
+
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+
+ @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
+ @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
+**/
+BOOLEAN
+DiskIo2RemoveCompletedTask (
+ IN DISK_IO_PRIVATE_DATA *Instance
+ )
+{
+ BOOLEAN QueueEmpty;
+ LIST_ENTRY *Link;
+ DISK_IO2_TASK *Task;
+
+ QueueEmpty = TRUE;
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+ if (IsListEmpty (&Task->Subtasks)) {
+ Link = RemoveEntryList (&Task->Link);
+ ASSERT (Task->Token == NULL);
+ FreePool (Task);
+ } else {
+ Link = GetNextNode (&Instance->TaskQueue, Link);
+ QueueEmpty = FALSE;
+ }
+ }
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ return QueueEmpty;
+}
+
+/**
+ Common routine to access the disk.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Write TRUE: Write operation; FALSE: Read operation.
+ @param MediaId ID of the medium to access.
+ @param Offset The starting byte offset on the logical block I/O device to access.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+**/
+EFI_STATUS
+DiskIo2ReadWriteDisk (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN BOOLEAN Write,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_MEDIA *Media;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ LIST_ENTRY Subtasks;
+ DISK_IO_SUBTASK *Subtask;
+ DISK_IO2_TASK *Task;
+ EFI_TPL OldTpl;
+ BOOLEAN Blocking;
+ BOOLEAN SubtaskBlocking;
+ LIST_ENTRY *SubtasksPtr;
+
+ Task = NULL;
+ BlockIo = Instance->BlockIo;
+ BlockIo2 = Instance->BlockIo2;
+ Media = BlockIo->Media;
+ Status = EFI_SUCCESS;
+ Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
+
+ if (Blocking) {
+ //
+ // Wait till pending async task is completed.
+ //
+ while (!DiskIo2RemoveCompletedTask (Instance));
+
+ SubtasksPtr = &Subtasks;
+ } else {
+ DiskIo2RemoveCompletedTask (Instance);
+ Task = AllocatePool (sizeof (DISK_IO2_TASK));
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ InsertTailList (&Instance->TaskQueue, &Task->Link);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ Task->Signature = DISK_IO2_TASK_SIGNATURE;
+ Task->Instance = Instance;
+ Task->Token = Token;
+ EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
+
+ SubtasksPtr = &Task->Subtasks;
+ }
+
+ InitializeListHead (SubtasksPtr);
+ if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
+ if (Task != NULL) {
+ FreePool (Task);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (!IsListEmpty (SubtasksPtr));
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
+ ; !IsNull (SubtasksPtr, Link)
+ ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
+ ) {
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ Subtask->Task = Task;
+ SubtaskBlocking = Subtask->Blocking;
+
+ ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
+
+ if (Subtask->Write) {
+ //
+ // Write
+ //
+ if (Subtask->WorkingBuffer != NULL) {
+ //
+ // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
+ //
+ CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
+ }
+
+ if (SubtaskBlocking) {
+ Status = BlockIo->WriteBlocks (
+ BlockIo,
+ MediaId,
+ Subtask->Lba,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ } else {
+ Status = BlockIo2->WriteBlocksEx (
+ BlockIo2,
+ MediaId,
+ Subtask->Lba,
+ &Subtask->BlockIo2Token,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ }
+
+ } else {
+ //
+ // Read
+ //
+ if (SubtaskBlocking) {
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ MediaId,
+ Subtask->Lba,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
+ CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+ }
+ } else {
+ Status = BlockIo2->ReadBlocksEx (
+ BlockIo2,
+ MediaId,
+ Subtask->Lba,
+ &Subtask->BlockIo2Token,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ }
+ }
+
+ if (SubtaskBlocking || EFI_ERROR (Status)) {
+ //
+ // Make sure the subtask list only contains non-blocking subtasks.
+ // Remove failed non-blocking subtasks as well because the callback won't be called.
+ //
+ DiskIoDestroySubtask (Instance, Subtask);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Remove all the remaining subtasks when failure.
+ // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
+ //
+ if (EFI_ERROR (Status)) {
+ while (!IsNull (SubtasksPtr, NextLink)) {
+ Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ NextLink = DiskIoDestroySubtask (Instance, Subtask);
+ }
+ }
+
+ //
+ // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
+ // so the subtasks list might be empty at this point.
+ //
+ if (!Blocking && IsListEmpty (SubtasksPtr)) {
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ RemoveEntryList (&Task->Link);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
+ //
+ // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
+ // It it's not, that means the non-blocking request was downgraded to blocking request.
+ //
+ DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
+ Task->Token->TransactionStatus = Status;
+ gBS->SignalEvent (Task->Token->Event);
+ }
+
+ FreePool (Task);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reads a specified number of bytes from a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be read.
+ @param Offset The starting byte offset on the logical block I/O device to read from.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2ReadDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+ FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ Writes a specified number of bytes to a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be written.
+ @param Offset The starting byte offset on the logical block I/O device to write to.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
+ @param Buffer A pointer to the buffer containing the data to be written.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2WriteDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+ TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ The callback for the BlockIo2 FlushBlocksEx.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the DISK_IO2_FLUSH_TASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnFlushComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DISK_IO2_FLUSH_TASK *Task;
+
+ gBS->CloseEvent (Event);
+
+ Task = (DISK_IO2_FLUSH_TASK *) Context;
+ ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
+ Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
+ gBS->SignalEvent (Task->Token->Event);
+
+ FreePool (Task);
+}
+
+/**
+ Flushes all modified data to the physical device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2FlushDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN OUT EFI_DISK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ DISK_IO2_FLUSH_TASK *Task;
+ DISK_IO_PRIVATE_DATA *Private;
+
+ Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DiskIo2OnFlushComplete,
+ Task,
+ &Task->BlockIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Task);
+ return Status;
+ }
+ Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
+ Task->Token = Token;
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->BlockIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
+ }
+
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Offset into Buffer.
+ Reads may support reads that are not aligned on
+ sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @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_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoReadDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+ FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+
+/**
+ Writes BufferSize bytes from Buffer into Offset.
+ Writes may require a read modify write to support writes that are not
+ aligned on sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the write request
+ is less than a sector in length. Read modify write is required.
+ Aligned - A write of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary. Read modified write
+ required.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read 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_INVALID_PARAMETER The write request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoWriteDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+ TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ The user Entry Point for module DiskIo. 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
+InitializeDiskIo (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDiskIoDriverBinding,
+ ImageHandle,
+ &gDiskIoComponentName,
+ &gDiskIoComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h
new file mode 100644
index 000000000..3207b9fa2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h
@@ -0,0 +1,467 @@
+/** @file
+ Master header file for DiskIo driver. It includes the module private defininitions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DISK_IO_H_
+#define _DISK_IO_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.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 DISK_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('d', 's', 'k', 'I')
+typedef struct {
+ UINT32 Signature;
+
+ EFI_DISK_IO_PROTOCOL DiskIo;
+ EFI_DISK_IO2_PROTOCOL DiskIo2;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+
+ UINT8 *SharedWorkingBuffer;
+
+ EFI_LOCK TaskQueueLock;
+ LIST_ENTRY TaskQueue;
+} DISK_IO_PRIVATE_DATA;
+#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE)
+#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO2(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo2, DISK_IO_PRIVATE_DATA_SIGNATURE)
+
+#define DISK_IO2_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'a', 't')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link; /// < link to other task
+ EFI_LOCK SubtasksLock;
+ LIST_ENTRY Subtasks; /// < header of subtasks
+ EFI_DISK_IO2_TOKEN *Token;
+ DISK_IO_PRIVATE_DATA *Instance;
+} DISK_IO2_TASK;
+
+#define DISK_IO2_FLUSH_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'f', 't')
+typedef struct {
+ UINT32 Signature;
+ EFI_BLOCK_IO2_TOKEN BlockIo2Token;
+ EFI_DISK_IO2_TOKEN *Token;
+} DISK_IO2_FLUSH_TASK;
+
+#define DISK_IO_SUBTASK_SIGNATURE SIGNATURE_32 ('d', 'i', 's', 't')
+typedef struct {
+ //
+ // UnderRun: Offset != 0, Length < BlockSize
+ // OverRun: Offset == 0, Length < BlockSize
+ // Middle: Offset is block aligned, Length is multiple of block size
+ //
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BOOLEAN Write;
+ UINT64 Lba;
+ UINT32 Offset;
+ UINTN Length;
+ UINT8 *WorkingBuffer; /// < NULL indicates using "Buffer" directly
+ UINT8 *Buffer;
+ BOOLEAN Blocking;
+
+ //
+ // Following fields are for DiskIo2
+ //
+ DISK_IO2_TASK *Task;
+ EFI_BLOCK_IO2_TOKEN BlockIo2Token;
+} DISK_IO_SUBTASK;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gDiskIoComponentName2;
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @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
+DiskIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO protocol and
+ installing a Disk IO protocol on ControllerHandle.
+
+ @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
+DiskIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing Disk IO protocol and closing
+ the Block IO protocol on ControllerHandle.
+
+ @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
+DiskIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Disk I/O Protocol Interface
+//
+/**
+ Read BufferSize bytes from Offset into Buffer.
+ Reads may support reads that are not aligned on
+ sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @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_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoReadDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes BufferSize bytes from Buffer into Offset.
+ Writes may require a read modify write to support writes that are not
+ aligned on sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the write request
+ is less than a sector in length. Read modify write is required.
+ Aligned - A write of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary. Read modified write
+ required.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read 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_INVALID_PARAMETER The write request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoWriteDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Terminate outstanding asynchronous requests to a device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding requests were successfully terminated.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
+ operation.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2Cancel (
+ IN EFI_DISK_IO2_PROTOCOL *This
+ );
+
+/**
+ Reads a specified number of bytes from a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be read.
+ @param Offset The starting byte offset on the logical block I/O device to read from.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2ReadDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of bytes to a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be written.
+ @param Offset The starting byte offset on the logical block I/O device to write to.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
+ @param Buffer A pointer to the buffer containing the data to be written.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2WriteDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to the physical device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2FlushDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN OUT EFI_DISK_IO2_TOKEN *Token
+ );
+
+//
+// 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
+DiskIoComponentNameGetDriverName (
+ 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
+DiskIoComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
new file mode 100644
index 000000000..9ea371b3b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
@@ -0,0 +1,65 @@
+## @file
+# Module that lays Disk I/O protocol on every Block I/O protocol.
+#
+# This module produces Disk I/O protocol to abstract the block accesses
+# of the Block I/O protocol to a more general offset-length protocol
+# to provide byte-oriented access to block media. It adds this protocol
+# to any Block I/O interface that appears in the system that does not
+# already have a Disk I/O protocol. File systems and other disk access
+# code utilize the Disk I/O protocol.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DiskIoDxe
+ MODULE_UNI_FILE = DiskIoDxe.uni
+ FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDiskIo
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gDiskIoDriverBinding
+# COMPONENT_NAME = gDiskIoComponentName
+# COMPONENT_NAME2 = gDiskIoComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ DiskIo.h
+ DiskIo.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiDiskIoProtocolGuid ## BY_START
+ gEfiDiskIo2ProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## TO_START
+ gEfiBlockIo2ProtocolGuid ## TO_START
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DiskIoDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni
new file mode 100644
index 000000000..3bdf78d44
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Module that lays Disk I/O protocol on every Block I/O protocol.
+//
+// This module produces Disk I/O protocol to abstract the block accesses
+// of the Block I/O protocol to a more general offset-length protocol
+// to provide byte-oriented access to block media. It adds this protocol
+// to any Block I/O interface that appears in the system that does not
+// already have a Disk I/O protocol. File systems and other disk access
+// code utilize the Disk I/O protocol.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Lays Disk I/O protocol on every Block I/O protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces Disk I/O protocol to abstract the block accesses of the Block I/O protocol to a more general offset-length protocol to provide byte-oriented access to block media. It adds this protocol to any Block I/O interface that appears in the system that does not already have a Disk I/O protocol. File systems and other disk access code utilize the Disk I/O protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni
new file mode 100644
index 000000000..a63822cc6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DiskIoDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Disk I/O DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
new file mode 100644
index 000000000..7d1031f35
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
@@ -0,0 +1,182 @@
+/** @file
+ UEFI Component Name protocol for Partition driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName = {
+ PartitionComponentNameGetDriverName,
+ PartitionComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PartitionComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PartitionComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for Partition module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Partition Driver(MBR/GPT/El Torito)"
+ },
+ {
+ 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
+PartitionComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPartitionDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPartitionComponentName)
+ );
+}
+
+
+/**
+ 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
+PartitionComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
new file mode 100644
index 000000000..3d2ff3bc2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
@@ -0,0 +1,275 @@
+/** @file
+ Decode an El Torito formatted CD-ROM
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT64 VolDescriptorOffset;
+ UINT32 Lba2KB;
+ EFI_BLOCK_IO_MEDIA *Media;
+ CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
+ ELTORITO_CATALOG *Catalog;
+ UINTN Check;
+ UINTN Index;
+ UINTN BootEntry;
+ UINTN MaxIndex;
+ UINT16 *CheckBuffer;
+ CDROM_DEVICE_PATH CdDev;
+ UINT32 SubBlockSize;
+ UINT32 SectorCount;
+ EFI_STATUS Found;
+ UINT32 VolSpaceSize;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+ Media = BlockIo->Media;
+
+ VolSpaceSize = 0;
+
+ //
+ // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
+ //
+
+ // If the ISO image has been copied onto a different storage media
+ // then the block size might be different (eg: USB).
+ // Ensure 2048 (SIZE_2KB) is a multiple of block size
+ if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
+
+ if (VolDescriptor == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Catalog = (ELTORITO_CATALOG *) VolDescriptor;
+
+ //
+ // Loop: handle one volume descriptor per time
+ // The ISO-9660 volume descriptor starts at 32k on the media
+ //
+ for (VolDescriptorOffset = SIZE_32KB;
+ VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
+ VolDescriptorOffset += SIZE_2KB) {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ VolDescriptorOffset,
+ SIZE_2KB,
+ VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ break;
+ }
+ //
+ // Check for valid volume descriptor signature
+ //
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
+ CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
+ ) {
+ //
+ // end of Volume descriptor list
+ //
+ break;
+ }
+ //
+ // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
+ // the 32-bit numerical values is stored in Both-byte orders
+ //
+ if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
+ VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
+ }
+ //
+ // Is it an El Torito volume descriptor?
+ //
+ if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
+ continue;
+ }
+ //
+ // Read in the boot El Torito boot catalog
+ // The LBA unit used by El Torito boot catalog is 2KB unit
+ //
+ Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
+ // Ensure the LBA (in 2KB unit) fits into our media
+ if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
+ continue;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ MultU64x32 (Lba2KB, SIZE_2KB),
+ SIZE_2KB,
+ Catalog
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
+ continue;
+ }
+ //
+ // We don't care too much about the Catalog header's contents, but we do want
+ // to make sure it looks like a Catalog header
+ //
+ if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
+ DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
+ continue;
+ }
+
+ Check = 0;
+ CheckBuffer = (UINT16 *) Catalog;
+ for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
+ Check += CheckBuffer[Index];
+ }
+
+ if ((Check & 0xFFFF) != 0) {
+ DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
+ continue;
+ }
+
+ MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
+ for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
+ //
+ // Next entry
+ //
+ Catalog += 1;
+
+ //
+ // Check this entry
+ //
+ if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
+ continue;
+ }
+
+ SubBlockSize = 512;
+ SectorCount = Catalog->Boot.SectorCount;
+
+ switch (Catalog->Boot.MediaType) {
+
+ case ELTORITO_NO_EMULATION:
+ SubBlockSize = Media->BlockSize;
+ break;
+
+ case ELTORITO_HARD_DISK:
+ break;
+
+ case ELTORITO_12_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x0F;
+ break;
+
+ case ELTORITO_14_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x12;
+ break;
+
+ case ELTORITO_28_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x24;
+ break;
+
+ default:
+ DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
+ SectorCount = 0;
+ SubBlockSize = Media->BlockSize;
+ break;
+ }
+ //
+ // Create child device handle
+ //
+ CdDev.Header.Type = MEDIA_DEVICE_PATH;
+ CdDev.Header.SubType = MEDIA_CDROM_DP;
+ SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+ if (Index == 1) {
+ //
+ // This is the initial/default entry
+ //
+ BootEntry = 0;
+ }
+
+ CdDev.BootEntry = (UINT32) BootEntry;
+ BootEntry++;
+ CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
+ if (SectorCount < 2) {
+ //
+ // When the SectorCount < 2, set the Partition as the whole CD.
+ //
+ if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) {
+ CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1);
+ } else {
+ CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize);
+ }
+ } else {
+ CdDev.PartitionSize = DivU64x32 (
+ MultU64x32 (
+ SectorCount * (SIZE_2KB / Media->BlockSize),
+ SubBlockSize
+ ) + Media->BlockSize - 1,
+ Media->BlockSize
+ );
+ }
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
+ &PartitionInfo,
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1,
+ SubBlockSize,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ }
+
+ FreePool (VolDescriptor);
+
+ return Found;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
new file mode 100644
index 000000000..aefb2d6ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
@@ -0,0 +1,883 @@
+/** @file
+ Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
+ specification.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - disk partition.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ PartitionInstallGptChildHandles() routine will read disk partition content and
+ do basic validation before PartitionInstallChildHandle().
+
+ PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
+ partition content and validate the GPT table and GPT entry.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this routine
+ will do basic validation for GPT partition table before install
+ child handle for each GPT partition.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA LastBlock;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+ EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
+ EFI_PARTITION_TABLE_HEADER *BackupHeader;
+ EFI_PARTITION_ENTRY *PartEntry;
+ EFI_PARTITION_ENTRY *Entry;
+ EFI_PARTITION_ENTRY_STATUS *PEntryStatus;
+ UINTN Index;
+ EFI_STATUS GptValidStatus;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ UINT32 MediaId;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ ProtectiveMbr = NULL;
+ PrimaryHeader = NULL;
+ BackupHeader = NULL;
+ PartEntry = NULL;
+ PEntryStatus = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ LastBlock = BlockIo->Media->LastBlock;
+ MediaId = BlockIo->Media->MediaId;
+
+ DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));
+ DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));
+
+ GptValidStatus = EFI_NOT_FOUND;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a buffer for the Protective MBR
+ //
+ ProtectiveMbr = AllocatePool (BlockSize);
+ if (ProtectiveMbr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read the Protective MBR from LBA #0
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ ProtectiveMbr
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ goto Done;
+ }
+
+ //
+ // Verify that the Protective MBR is valid
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
+ ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&
+ UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
+ ) {
+ break;
+ }
+ }
+ if (Index == MAX_MBR_PARTITIONS) {
+ goto Done;
+ }
+
+ //
+ // Allocate the GPT structures
+ //
+ PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (PrimaryHeader == NULL) {
+ goto Done;
+ }
+
+ BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (BackupHeader == NULL) {
+ goto Done;
+ }
+
+ //
+ // Check primary and backup partition tables
+ //
+ if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
+
+ if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
+ goto Done;
+ } else {
+ DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+ }
+ } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+
+ }
+
+ DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));
+
+ //
+ // Read the EFI Partition Entries
+ //
+ PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+ if (PartEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
+ PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
+ PartEntry
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));
+
+ DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
+
+ PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
+ if (PEntryStatus == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ //
+ // Check the integrity of partition entries
+ //
+ PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
+
+ //
+ // If we got this far the GPT layout of the disk is valid and we should return true
+ //
+ GptValidStatus = EFI_SUCCESS;
+
+ //
+ // Create child device handles
+ //
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
+ PEntryStatus[Index].OutOfRange ||
+ PEntryStatus[Index].Overlap ||
+ PEntryStatus[Index].OsSpecific
+ ) {
+ //
+ // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
+ // partition Entries
+ //
+ continue;
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+
+ HdDev.PartitionNumber = (UINT32) Index + 1;
+ HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ HdDev.SignatureType = SIGNATURE_TYPE_GUID;
+ HdDev.PartitionStart = Entry->StartingLBA;
+ HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
+ CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_GPT;
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
+
+ DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));
+ DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));
+ DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));
+ DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));
+ DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
+ DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ Entry->StartingLBA,
+ Entry->EndingLBA,
+ BlockSize,
+ &Entry->PartitionTypeGUID
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
+
+Done:
+ if (ProtectiveMbr != NULL) {
+ FreePool (ProtectiveMbr);
+ }
+ if (PrimaryHeader != NULL) {
+ FreePool (PrimaryHeader);
+ }
+ if (BackupHeader != NULL) {
+ FreePool (BackupHeader);
+ }
+ if (PartEntry != NULL) {
+ FreePool (PartEntry);
+ }
+ if (PEntryStatus != NULL) {
+ FreePool (PEntryStatus);
+ }
+
+ return GptValidStatus;
+}
+
+/**
+ This routine will read GPT partition table header and return it.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ UINT32 MediaId;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+ //
+ // Read the EFI Partition Table Header
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (Lba, BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+ !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
+ PartHdr->MyLBA != Lba ||
+ (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
+ ) {
+ DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ //
+ // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
+ //
+ if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));
+ FreePool (PartHdr);
+ return TRUE;
+}
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT32 Crc;
+ UINTN Size;
+
+ //
+ // Read the EFI Partition Entries
+ //
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ return FALSE;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
+
+ Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ FreePool (Ptr);
+
+ return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ EFI_LBA PEntryLBA;
+ UINT8 *Ptr;
+ UINT32 MediaId;
+
+ PartHdr = NULL;
+ Ptr = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+
+ PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
+ (PartHeader->LastUsableLBA + 1) : \
+ (PRIMARY_PART_HEADER_LBA + 1);
+
+ CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
+
+ PartHdr->MyLBA = PartHeader->AlternateLBA;
+ PartHdr->AlternateLBA = PartHeader->MyLBA;
+ PartHdr->PartitionEntryLBA = PEntryLBA;
+ PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PEntryLBA, (UINT32) BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+
+Done:
+ FreePool (PartHdr);
+
+ if (Ptr != NULL) {
+ FreePool (Ptr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ )
+{
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ EFI_PARTITION_ENTRY *Entry;
+ UINTN Index1;
+ UINTN Index2;
+
+ DEBUG ((EFI_D_INFO, " start check partition entries\n"));
+ for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ if (StartingLBA > EndingLBA ||
+ StartingLBA < PartHeader->FirstUsableLBA ||
+ StartingLBA > PartHeader->LastUsableLBA ||
+ EndingLBA < PartHeader->FirstUsableLBA ||
+ EndingLBA > PartHeader->LastUsableLBA
+ ) {
+ PEntryStatus[Index1].OutOfRange = TRUE;
+ continue;
+ }
+
+ if ((Entry->Attributes & BIT1) != 0) {
+ //
+ // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+ //
+ PEntryStatus[Index1].OsSpecific = TRUE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ PEntryStatus[Index1].Overlap = TRUE;
+ PEntryStatus[Index2].Overlap = TRUE;
+ continue;
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, " End check partition entries\n"));
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+ gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+ UINT32 OrgCrc;
+ EFI_STATUS Status;
+
+ Crc = 0;
+
+ if (Size == 0) {
+ //
+ // If header size is 0 CRC will pass so return FALSE here
+ //
+ return FALSE;
+ }
+
+ if ((MaxSize != 0) && (Size > MaxSize)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
+ return FALSE;
+ }
+ //
+ // clear old crc from header
+ //
+ OrgCrc = Hdr->CRC32;
+ Hdr->CRC32 = 0;
+
+ Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
+ return FALSE;
+ }
+ //
+ // set results
+ //
+ Hdr->CRC32 = Crc;
+
+ //
+ // return status
+ //
+ DEBUG_CODE_BEGIN ();
+ if (OrgCrc != Crc) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
+ }
+ DEBUG_CODE_END ();
+
+ return (BOOLEAN) (OrgCrc == Crc);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
new file mode 100644
index 000000000..f0c92aa09
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
@@ -0,0 +1,353 @@
+/** @file
+ Decode a hard disk partitioned with the legacy MBR found on most PC's
+
+ MBR - Master Boot Record is in the first sector of a partitioned hard disk.
+ The MBR supports four partitions per disk. The MBR also contains legacy
+ code that is not run on an EFI system. The legacy code reads the
+ first sector of the active partition into memory and
+
+ BPB - BIOS Parameter Block is in the first sector of a FAT file system.
+ The BPB contains information about the FAT file system. The BPB is
+ always on the first sector of a media. The first sector also contains
+ the legacy boot strap code.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+/**
+ Test to see if the Mbr buffer is a valid MBR.
+
+ @param Mbr Parent Handle.
+ @param LastLba Last Lba address on the device.
+
+ @retval TRUE Mbr is a Valid MBR.
+ @retval FALSE Mbr is not a Valid MBR.
+
+**/
+BOOLEAN
+PartitionValidMbr (
+ IN MASTER_BOOT_RECORD *Mbr,
+ IN EFI_LBA LastLba
+ )
+{
+ UINT32 StartingLBA;
+ UINT32 EndingLBA;
+ UINT32 NewEndingLBA;
+ INTN Index1;
+ INTN Index2;
+ BOOLEAN MbrValid;
+
+ if (Mbr->Signature != MBR_SIGNATURE) {
+ return FALSE;
+ }
+ //
+ // The BPB also has this signature, so it can not be used alone.
+ //
+ MbrValid = FALSE;
+ for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
+ if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
+ continue;
+ }
+
+ MbrValid = TRUE;
+ StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
+ EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
+ if (EndingLBA > LastLba) {
+ //
+ // Compatibility Errata:
+ // Some systems try to hide drive space with their INT 13h driver
+ // This does not hide space from the OS driver. This means the MBR
+ // that gets created from DOS is smaller than the MBR created from
+ // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
+ // wrong on some systems FDISKed by the OS.
+ //
+ // return FALSE since no block devices on a system are implemented
+ // with INT 13h
+ //
+
+ DEBUG((EFI_D_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
+
+ return FALSE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
+ if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
+ continue;
+ }
+
+ NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
+ if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ return FALSE;
+ }
+ }
+ }
+ //
+ // None of the regions overlapped so MBR is O.K.
+ //
+ return MbrValid;
+}
+
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ MASTER_BOOT_RECORD *Mbr;
+ UINT32 ExtMbrStartingLba;
+ UINT32 Index;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ HARDDRIVE_DEVICE_PATH ParentHdDev;
+ EFI_STATUS Found;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
+ UINT32 BlockSize;
+ UINT32 MediaId;
+ EFI_LBA LastSector;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ LastSector = DivU64x32 (
+ MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
+ MBR_SIZE
+ ) - 1;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Mbr = AllocatePool (BlockSize);
+ if (Mbr == NULL) {
+ return Found;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+ if (!PartitionValidMbr (Mbr, LastSector)) {
+ goto Done;
+ }
+ //
+ // We have a valid mbr - add each partition
+ //
+ //
+ // Get starting and ending LBA of the parent block device.
+ //
+ LastDevicePathNode = NULL;
+ ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ LastDevicePathNode = DevicePathNode;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (LastDevicePathNode != NULL) {
+ if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
+ ) {
+ CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
+ } else {
+ LastDevicePathNode = NULL;
+ }
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+ HdDev.MBRType = MBR_TYPE_PCAT;
+ HdDev.SignatureType = SIGNATURE_TYPE_MBR;
+
+ if (LastDevicePathNode == NULL) {
+ //
+ // This is a MBR, add each partition
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
+ //
+ // Don't use null MBR entries
+ //
+ continue;
+ }
+
+ if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
+ //
+ // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
+ // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
+ // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
+ // that corrupted the GPT partition.
+ //
+ continue;
+ }
+
+ HdDev.PartitionNumber = Index + 1;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
+ CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart,
+ HdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ } else {
+ //
+ // It's an extended partition. Follow the extended partition
+ // chain to get all the logical drives
+ //
+ Index = 0;
+ ExtMbrStartingLba = 0;
+
+ do {
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (ExtMbrStartingLba, BlockSize),
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+
+ if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
+ break;
+ }
+
+ if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
+ (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
+ continue;
+ }
+ HdDev.PartitionNumber = ++Index;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
+ if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
+ (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
+ break;
+ }
+
+ //
+ // The signature in EBR(Extended Boot Record) should always be 0.
+ //
+ *((UINT32 *) &HdDev.Signature[0]) = 0;
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+
+ if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
+ (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
+ ) {
+ break;
+ }
+
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
+ //
+ // Don't allow partition to be self referencing
+ //
+ if (ExtMbrStartingLba == 0) {
+ break;
+ }
+ } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
+ }
+
+Done:
+ FreePool (Mbr);
+
+ return Found;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
new file mode 100644
index 000000000..f10ce7c65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -0,0 +1,1369 @@
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+//
+// Partition Driver Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
+ PartitionDriverBindingSupported,
+ PartitionDriverBindingStart,
+ PartitionDriverBindingStop,
+ //
+ // Grub4Dos copies the BPB of the first partition to the MBR. If the
+ // DriverBindingStart() of the Fat driver gets run before that of Partition
+ // driver only the first partition can be recognized.
+ // Let the driver binding version of Partition driver be higher than that of
+ // Fat driver to make sure the DriverBindingStart() of the Partition driver
+ // gets run before that of Fat driver so that all the partitions can be recognized.
+ //
+ 0xb,
+ NULL,
+ NULL
+};
+
+//
+// Prioritized function list to detect partition table.
+// Refer to UEFI Spec 13.3.2 Partition Discovery, the block device
+// should be scanned in below order:
+// 1. GPT
+// 2. ISO 9660 (El Torito) (or UDF)
+// 3. MBR
+// 4. no partiton found
+// Note: UDF is using a same method as booting from CD-ROM, so put it along
+// with CD-ROM check.
+//
+PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
+ PartitionInstallGptChildHandles,
+ PartitionInstallUdfChildHandles,
+ PartitionInstallMbrChildHandles,
+ NULL
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] 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
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DEV_PATH *Node;
+
+ //
+ // 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
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
+ Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
+ DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ 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 (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] 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
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS OpenStatus;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ PARTITION_DETECT_ROUTINE *Routine;
+ BOOLEAN MediaPresent;
+ EFI_TPL OldTpl;
+
+ BlockIo2 = NULL;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
+ // otherwise, return error.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ BlockIo2 = NULL;
+ }
+
+ //
+ // Get the Device Path Protocol on ControllerHandle's handle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ goto Exit;
+ }
+
+ //
+ // Get the DiskIo and DiskIo2.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ goto Exit;
+ }
+
+ OpenStatus = Status;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ (VOID **) &DiskIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ DiskIo2 = NULL;
+ }
+
+ //
+ // Try to read blocks when there's media or it is removable physical partition.
+ //
+ Status = EFI_UNSUPPORTED;
+ MediaPresent = BlockIo->Media->MediaPresent;
+ if (BlockIo->Media->MediaPresent ||
+ (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
+ //
+ // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
+ // If the media supports a given partition type install child handles to
+ // represent the partitions described by the media.
+ //
+ Routine = &mPartitionDetectRoutineTable[0];
+ while (*Routine != NULL) {
+ Status = (*Routine) (
+ This,
+ ControllerHandle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ ParentDevicePath
+ );
+ if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
+ break;
+ }
+ Routine++;
+ }
+ }
+ //
+ // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
+ // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
+ // driver. So don't try to close them. Otherwise, we will break the dependency
+ // between the controller and the driver set up before.
+ //
+ // In the case that when the media changes on a device it will Reinstall the
+ // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
+ // reentrant call to our Start() successfully. We should leave the device open
+ // when this happen. The "media change" case includes either the status is
+ // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
+ //
+ if (EFI_ERROR (Status) &&
+ !EFI_ERROR (OpenStatus) &&
+ Status != EFI_MEDIA_CHANGED &&
+ !(MediaPresent && Status == EFI_NO_MEDIA)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent DiskIo2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ BOOLEAN AllChildrenStopped;
+ PARTITION_PRIVATE_DATA *Private;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_GUID *TypeGuid;
+
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ Private = NULL;
+
+ if (NumberOfChildren == 0) {
+ //
+ // In the case of re-entry of the PartitionDriverBindingStop, the
+ // NumberOfChildren may not reflect the actual number of children on the
+ // bus driver. Hence, additional check is needed here.
+ //
+ if (HasChildren (ControllerHandle)) {
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent BlockIO2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // Try to locate BlockIo2.
+ //
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+ if (Private->InStop) {
+ //
+ // If the child handle is going to be stopped again during the re-entry
+ // of DriverBindingStop, just do nothing.
+ //
+ break;
+ }
+ Private->InStop = TRUE;
+
+ BlockIo->FlushBlocks (BlockIo);
+
+ if (BlockIo2 != NULL) {
+ Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ if (IsZeroGuid (&Private->TypeGuid)) {
+ TypeGuid = NULL;
+ } else {
+ TypeGuid = &Private->TypeGuid;
+ }
+
+ //
+ // All Software protocols have be freed from the handle so remove it.
+ // Remove the BlockIo Protocol if has.
+ // Remove the BlockIo2 Protocol if has.
+ //
+ if (BlockIo2 != NULL) {
+ //
+ // Some device drivers might re-install the BlockIO(2) protocols for a
+ // media change condition. Therefore, if the FlushBlocksEx returned with
+ // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
+ // reference of already stopped child handle.
+ //
+ if (Status != EFI_MEDIA_CHANGED) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Private->InStop = FALSE;
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ if (Status == EFI_MEDIA_CHANGED) {
+ break;
+ }
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the Block Device.
+
+ @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
+PartitionReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->Reset (
+ Private->ParentBlockIo,
+ ExtendedVerification
+ );
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo Pointer to the DiskIo instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatus (
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+ return DefaultStatus;
+}
+
+/**
+ Read by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param This Protocol instance pointer.
+ @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 Buffer containing read data
+
+ @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 device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+/**
+ Write by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer Buffer containing data to be written to device.
+
+ @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 a LBA that is not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+
+/**
+ Flush the parent Block Device.
+
+ @param This Protocol instance pointer.
+
+ @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
+PartitionFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo2 Pointer to the DiskIo2 instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatusEx (
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+ return DefaultStatus;
+}
+
+/**
+ Reset the Block Device throught Block I/O2 protocol.
+
+ @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
+PartitionResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ return Private->ParentBlockIo2->Reset (
+ Private->ParentBlockIo2,
+ ExtendedVerification
+ );
+}
+
+/**
+ The general callback for the DiskIo2 interfaces.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the PARTITION_ACCESS_TASK instance.
+**/
+VOID
+EFIAPI
+PartitionOnAccessComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = (PARTITION_ACCESS_TASK *) Context;
+
+ gBS->CloseEvent (Event);
+
+ Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
+ gBS->SignalEvent (Task->BlockIo2Token->Event);
+
+ FreePool (Task);
+}
+
+/**
+ Create a new PARTITION_ACCESS_TASK instance.
+
+ @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
+
+ @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
+**/
+PARTITION_ACCESS_TASK *
+PartitionCreateAccessTask (
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = AllocatePool (sizeof (*Task));
+ if (Task == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PartitionOnAccessComplete,
+ Task,
+ &Task->DiskIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Task);
+ return NULL;
+ }
+
+ Task->BlockIo2Token = Token;
+
+ return Task;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] 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 read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @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 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @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_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
+ All outstanding data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
+ }
+ return Status;
+}
+
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Partition GUID Type.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
+
+ Private->Start = MultU64x32 (Start, BlockSize);
+ Private->End = MultU64x32 (End + 1, BlockSize);
+
+ Private->BlockSize = BlockSize;
+ Private->ParentBlockIo = ParentBlockIo;
+ Private->ParentBlockIo2 = ParentBlockIo2;
+ Private->DiskIo = ParentDiskIo;
+ Private->DiskIo2 = ParentDiskIo2;
+
+ //
+ // Set the BlockIO into Private Data.
+ //
+ Private->BlockIo.Revision = ParentBlockIo->Revision;
+
+ Private->BlockIo.Media = &Private->Media;
+ CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo.Reset = PartitionReset;
+ Private->BlockIo.ReadBlocks = PartitionReadBlocks;
+ Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
+ Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
+
+ //
+ // Set the BlockIO2 into Private Data.
+ //
+ if (Private->DiskIo2 != NULL) {
+ ASSERT (Private->ParentBlockIo2 != NULL);
+ Private->BlockIo2.Media = &Private->Media2;
+ CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo2.Reset = PartitionResetEx;
+ Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
+ Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
+ Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
+ }
+
+ Private->Media.IoAlign = 0;
+ Private->Media.LogicalPartition = TRUE;
+ Private->Media.LastBlock = End - Start;
+
+ Private->Media.BlockSize = (UINT32) BlockSize;
+
+ Private->Media2.IoAlign = 0;
+ Private->Media2.LogicalPartition = TRUE;
+ Private->Media2.LastBlock = Private->Media.LastBlock;
+ Private->Media2.BlockSize = (UINT32) BlockSize;
+
+ //
+ // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
+ // for logical partitions.
+ //
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
+ Private->Media.LowestAlignedLba = 0;
+ Private->Media.LogicalBlocksPerPhysicalBlock = 0;
+ Private->Media2.LowestAlignedLba = 0;
+ Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
+ Private->Media.OptimalTransferLengthGranularity = 0;
+ Private->Media2.OptimalTransferLengthGranularity = 0;
+ }
+ }
+
+ Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
+
+ if (Private->DevicePath == NULL) {
+ FreePool (Private);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the PartitionInfo into Private Data.
+ //
+ CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+
+ if (TypeGuid != NULL) {
+ CopyGuid(&(Private->TypeGuid), TypeGuid);
+ } else {
+ ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));
+ }
+
+ //
+ // Create the new handle.
+ //
+ Private->Handle = NULL;
+ if (Private->DiskIo2 != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Parent Handle for the child
+ //
+ Status = gBS->OpenProtocol (
+ ParentHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &ParentDiskIo,
+ This->DriverBindingHandle,
+ Private->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+
+ //
+ // if the Status == EFI_ALREADY_STARTED, it means the child handles
+ // are already installed. So return EFI_SUCCESS to avoid do the next
+ // partition type check.
+ //
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ The user Entry Point for module Partition. 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
+InitializePartition (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPartitionDriverBinding,
+ ImageHandle,
+ &gPartitionComponentName,
+ &gPartitionComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocolInformation (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+
+ return (BOOLEAN) (Index < EntryCount);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
new file mode 100644
index 000000000..a633950be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
@@ -0,0 +1,485 @@
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Guid/Gpt.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/PartitionInfo.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/DevicePathLib.h>
+
+#include <IndustryStandard/Mbr.h>
+#include <IndustryStandard/ElTorito.h>
+#include <IndustryStandard/Udf.h>
+
+//
+// Partition private data
+//
+#define PARTITION_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'a', 'r', 't')
+typedef struct {
+ UINT64 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_BLOCK_IO_MEDIA Media2;//For BlockIO2
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_BLOCK_IO_PROTOCOL *ParentBlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2;
+ UINT64 Start;
+ UINT64 End;
+ UINT32 BlockSize;
+ BOOLEAN InStop;
+
+ EFI_GUID TypeGuid;
+
+} PARTITION_PRIVATE_DATA;
+
+typedef struct {
+ EFI_DISK_IO2_TOKEN DiskIo2Token;
+ EFI_BLOCK_IO2_TOKEN *BlockIo2Token;
+} PARTITION_ACCESS_TASK;
+
+#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE)
+#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2;
+
+//
+// Extract INT32 from char array
+//
+#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+//
+// Extract UINT32 from char array
+//
+#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+ BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+//
+// Function Prototypes
+//
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo 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
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path, and creating a child handle with a
+ Disk IO and device path protocol.
+
+ @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
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ 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
+PartitionComponentNameGetDriverName (
+ 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 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 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
+PartitionComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Parition Type Guid.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ );
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+typedef
+EFI_STATUS
+(*PARTITION_DETECT_ROUTINE) (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
new file mode 100644
index 000000000..14ab6ae19
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
@@ -0,0 +1,85 @@
+## @file
+# Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+#
+# This module produces the logical Block I/O device that represents
+# the bytes from Start to End of the Parent Block I/O device.
+# The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+# UDF and "El Torito" partitions.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - disk partition.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PartitionDxe
+ MODULE_UNI_FILE = PartitionDxe.uni
+ FILE_GUID = 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePartition
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gPartitionDriverBinding
+# COMPONENT_NAME = gPartitionComponentName
+# COMPONENT_NAME2 = gPartitionComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Mbr.c
+ Gpt.c
+ ElTorito.c
+ Udf.c
+ Partition.c
+ Partition.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID # Install protocol
+ gEfiPartTypeSystemPartGuid
+
+
+[Protocols]
+ ## BY_START
+ ## TO_START
+ gEfiBlockIoProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiBlockIo2ProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiPartitionInfoProtocolGuid ## BY_START
+ gEfiDiskIoProtocolGuid ## TO_START
+ gEfiDiskIo2ProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PartitionDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
new file mode 100644
index 000000000..e22c47bbc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
@@ -0,0 +1,24 @@
+// /** @file
+// Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+//
+// This module produces the logical Block I/O device that represents
+// the bytes from Start to End of the Parent Block I/O device.
+// The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+// and "El Torito" partitions.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - disk partition.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the logic Block I/O protocol for every partition via the physical Block I/O."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces the logical Block I/O device that represents the bytes from Start to End of the Parent Block I/O device. The partition of physical BlockIO device supported is one of legacy MBR, GPT, and \"El Torito\" partitions.<BR><BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
new file mode 100644
index 000000000..f92d2e53c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PartitionDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Partition DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
new file mode 100644
index 000000000..3bf89a187
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -0,0 +1,788 @@
+/** @file
+ Scan for an UDF file system on a formatted media.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - CD/DVD media.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FindUdfFileSystem() routine will consume the media properties and do basic
+ validation.
+
+ Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Partition.h"
+
+#define MAX_CORRECTION_BLOCKS_NUM 512u
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID \
+ { 0xC5BD4D42, 0x1A76, 0x4996, \
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
+ }
+
+typedef struct {
+ VENDOR_DEVICE_PATH DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} UDF_DEVICE_PATH;
+
+//
+// Vendor-Defined Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+//
+// Vendor-Defined Media Device Path for UDF file system
+//
+UDF_DEVICE_PATH gUdfDevicePath = {
+ { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+ { sizeof (VENDOR_DEVICE_PATH), 0 } },
+ EFI_UDF_DEVICE_PATH_GUID
+ },
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+};
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] LastRecordedBlock Last recorded block.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT EFI_LBA *LastRecordedBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN AvdpsCount;
+ UINTN Size;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;
+ INTN Index;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;
+ EFI_LBA LastAvdpBlockNum;
+
+ //
+ // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
+ //
+ // An Anchor Volume Descriptor Pointer structure shall be recorded in at
+ // least 2 of the following 3 locations on the media: Logical Sector 256,
+ // N - 256 or N, where N is the last *addressable* sector of a volume.
+ //
+ // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
+ // READ TRACK INFORMATION are used, however many drives or medias report their
+ // "last recorded block" wrongly. Although, READ CAPACITY returns the last
+ // readable data block but there might be unwritten blocks, which are located
+ // outside any track and therefore AVDP will not be found at block N.
+ //
+ // That said, we define a magic number of 512 blocks to be used as correction
+ // when attempting to find AVDP and define last block number.
+ //
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ *LastRecordedBlock = EndLBA;
+ AvdpsCount = 0;
+
+ //
+ // Check if the block size of the underlying media can hold the data of an
+ // Anchor Volume Descriptor Pointer
+ //
+ if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Media block size 0x%x unable to hold an AVDP.\n",
+ __FUNCTION__,
+ BlockSize
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Find AVDP at block 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));
+ AvdpsCount++;
+ }
+
+ //
+ // Find AVDP at block N - 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&
+ ++AvdpsCount == 2) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ EndLBA - 256));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if at least one AVDP was found in previous locations
+ //
+ if (AvdpsCount == 0) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Find AVDP at block N
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No AVDP found at block N. Possibly drive/media returned bad last recorded
+ // block, or it is part of unwritten data blocks and outside any track.
+ //
+ // Search backwards for an AVDP from block N-1 through
+ // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
+ // number for the new UDF partition child handle.
+ //
+ Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
+
+ AnchorPoints = AllocateZeroPool (Size);
+ if (AnchorPoints == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
+ Size,
+ AnchorPoints
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ //
+ // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
+ //
+ for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
+ AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
+
+ DescriptorTag = &AnchorPointPtr->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ //
+ // Calculate last recorded block number
+ //
+ LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
+ DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ LastAvdpBlockNum));
+ DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",
+ __FUNCTION__, EndLBA, LastAvdpBlockNum));
+ //
+ // Save read AVDP from last block
+ //
+ CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
+ //
+ // Set last recorded block number
+ //
+ *LastRecordedBlock = LastAvdpBlockNum;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+Out_Free:
+ FreePool (AnchorPoints);
+ return Status;
+}
+
+/**
+ Find UDF volume identifiers in a Volume Recognition Sequence.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+
+ @retval EFI_SUCCESS UDF volume identifiers were found.
+ @retval EFI_NOT_FOUND UDF volume identifiers were not found.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindUdfVolumeIdentifiers (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Offset;
+ UINT64 EndDiskOffset;
+ CDROM_VOLUME_DESCRIPTOR VolDescriptor;
+ CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
+
+ ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
+
+ //
+ // Start Volume Recognition Sequence
+ //
+ EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
+ BlockIo->Media->BlockSize);
+
+ for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
+ Offset += UDF_LOGICAL_SECTOR_SIZE) {
+ //
+ // Check if block device has a Volume Structure Descriptor and an Extended
+ // Area.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_BEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) == 0) {
+ break;
+ }
+
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)CDVOL_ID,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) ||
+ (CompareMem ((VOID *)&VolDescriptor,
+ (VOID *)&TerminatingVolDescriptor,
+ sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Look for "NSR0{2,3}" identifiers in the Extended Area.
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR2_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) &&
+ (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR3_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Look for "TEA01" identifier in the Extended Area
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_TEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if Logical Volume Descriptor is supported by current EDK2 UDF file
+ system implementation.
+
+ @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
+
+ @retval TRUE Logical Volume Descriptor is supported.
+ @retval FALSE Logical Volume Descriptor is not supported.
+
+**/
+BOOLEAN
+IsLogicalVolumeDescriptorSupported (
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
+ )
+{
+ //
+ // Check for a valid UDF revision range
+ //
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ break;
+ default:
+ return FALSE;
+ }
+
+ //
+ // Check for a single Partition Map
+ //
+ if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
+ return FALSE;
+ }
+ //
+ // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
+ // let's check it any way.
+ //
+ // PartitionMap[0] -> type
+ // PartitionMap[1] -> length (in bytes)
+ //
+ if (LogicalVolDesc->PartitionMaps[0] != 1 ||
+ LogicalVolDesc->PartitionMaps[1] != 6) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Find UDF logical volume location and whether it is supported by current EDK2
+ UDF file system implementation.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[in] LastRecordedBlock Last recorded block in media.
+ @param[out] MainVdsStartBlock Main VDS starting block number.
+ @param[out] MainVdsEndBlock Main VDS ending block number.
+
+ @retval EFI_SUCCESS UDF logical volume was found.
+ @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
+ @retval EFI_UNSUPPORTED UDF logical volume is not supported.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindLogicalVolumeLocation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ IN EFI_LBA LastRecordedBlock,
+ OUT UINT64 *MainVdsStartBlock,
+ OUT UINT64 *MainVdsEndBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 SeqBlocksNum;
+ UINT64 SeqStartBlock;
+ UINT64 GuardMainVdsStartBlock;
+ VOID *Buffer;
+ UINT64 SeqEndBlock;
+ BOOLEAN StopSequence;
+ UINTN LvdsCount;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
+ //
+ // The Main Volume Descriptor Sequence Extent shall have a minimum length of
+ // 16 logical sectors.
+ //
+ // Also make sure it does not exceed maximum number of blocks in the disk.
+ //
+ SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
+ if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Check for valid Volume Descriptor Sequence starting block number
+ //
+ SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
+ if (SeqStartBlock > LastRecordedBlock ||
+ SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ GuardMainVdsStartBlock = SeqStartBlock;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SeqEndBlock = SeqStartBlock + SeqBlocksNum;
+ StopSequence = FALSE;
+ LvdsCount = 0;
+ Status = EFI_VOLUME_CORRUPTED;
+ //
+ // Start Main Volume Descriptor Sequence
+ //
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ //
+ // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
+ //
+ // - A Volume Descriptor Sequence shall contain one or more Primary Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Implementation
+ // Use Volume Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Partition
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Unallocated
+ // Space Descriptors.
+ //
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPrimaryVolumeDescriptor:
+ case UdfImplemenationUseVolumeDescriptor:
+ case UdfPartitionDescriptor:
+ case UdfUnallocatedSpaceDescriptor:
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ LogicalVolDesc = Buffer;
+
+ //
+ // Check for existence of a single LVD and whether it is supported by
+ // current EDK2 UDF file system implementation.
+ //
+ if (++LvdsCount > 1 ||
+ !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {
+ Status = EFI_UNSUPPORTED;
+ StopSequence = TRUE;
+ }
+
+ break;
+
+ case UdfTerminatingDescriptor:
+ //
+ // Stop the sequence when we find a Terminating Descriptor
+ // (aka Unallocated Sector), se we don't have to walk all the unallocated
+ // area unnecessarily.
+ //
+ StopSequence = TRUE;
+ break;
+
+ default:
+ //
+ // An invalid Volume Descriptor has been found in the sequece. Volume is
+ // corrupted.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+ }
+
+ //
+ // Check if LVD was found
+ //
+ if (!EFI_ERROR (Status) && LvdsCount == 1) {
+ *MainVdsStartBlock = GuardMainVdsStartBlock;
+ //
+ // We do not need to read either LVD or PD descriptors to know the last
+ // valid block in the found UDF file system. It's already
+ // LastRecordedBlock.
+ //
+ *MainVdsEndBlock = LastRecordedBlock;
+
+ Status = EFI_SUCCESS;
+ }
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Find a supported UDF file system in block device.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from Partition.
+
+ The CD/DVD media is the external input, so this routine will do basic
+ validation for the media.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] StartingLBA UDF file system starting LBA.
+ @param[out] EndingLBA UDF file system starting LBA.
+
+ @retval EFI_SUCCESS UDF file system was found.
+ @retval other UDF file system was not found.
+
+**/
+EFI_STATUS
+FindUdfFileSystem (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT EFI_LBA *StartingLBA,
+ OUT EFI_LBA *EndingLBA
+ )
+{
+ EFI_STATUS Status;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
+ EFI_LBA LastRecordedBlock;
+
+ //
+ // Find UDF volume identifiers
+ //
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ &LastRecordedBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Logical Volume location
+ //
+ Status = FindLogicalVolumeLocation (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ LastRecordedBlock,
+ (UINT64 *)StartingLBA,
+ (UINT64 *)EndingLBA
+ );
+
+ return Status;
+}
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINT32 RemainderByMediaBlockSize;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ BOOLEAN ChildCreated;
+
+ Media = BlockIo->Media;
+ ChildCreated = FALSE;
+
+ //
+ // Check if UDF logical block size is multiple of underlying device block size
+ //
+ DivU64x32Remainder (
+ UDF_LOGICAL_SECTOR_SIZE, // Dividend
+ Media->BlockSize, // Divisor
+ &RemainderByMediaBlockSize // Remainder
+ );
+ if (RemainderByMediaBlockSize != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Detect El Torito feature first.
+ // And always continue to search for UDF.
+ //
+ Status = PartitionInstallElToritoChildHandles (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
+ ChildCreated = TRUE;
+ }
+
+ //
+ // Search for an UDF file system on block device
+ //
+ Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+
+ //
+ // Create Partition Info protocol for UDF file system
+ //
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ //
+ // Install partition child handle for UDF file system
+ //
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
+ &PartitionInfo,
+ StartingLBA,
+ EndingLBA,
+ Media->BlockSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl
new file mode 100644
index 000000000..9615aaa66
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl
@@ -0,0 +1,38 @@
+/** @file
+ The definition block in ACPI table for NVDIMM root device.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+DefinitionBlock (
+ "RamDisk.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "RamDisk ",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (NVDR)
+ {
+ //
+ // Define _HID, "ACPI0012" NVDIMM Root Device
+ //
+ Name (_HID, "ACPI0012")
+
+ //
+ // Readable name of this device
+ //
+ Name (_STR, Unicode ("NVDIMM Root Device"))
+
+ Method (_STA, 0)
+ {
+ Return (0x0f)
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c
new file mode 100644
index 000000000..13f81bae1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c
@@ -0,0 +1,487 @@
+/** @file
+ Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+//
+// The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle
+// for newly registered RAM disks
+//
+EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = {
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ (EFI_BLOCK_IO_MEDIA *) 0,
+ RamDiskBlkIoReset,
+ RamDiskBlkIoReadBlocks,
+ RamDiskBlkIoWriteBlocks,
+ RamDiskBlkIoFlushBlocks
+};
+
+//
+// The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle
+// for newly registered RAM disks
+//
+EFI_BLOCK_IO2_PROTOCOL mRamDiskBlockIo2Template = {
+ (EFI_BLOCK_IO_MEDIA *) 0,
+ RamDiskBlkIo2Reset,
+ RamDiskBlkIo2ReadBlocksEx,
+ RamDiskBlkIo2WriteBlocksEx,
+ RamDiskBlkIo2FlushBlocksEx
+};
+
+
+/**
+ Initialize the BlockIO & BlockIO2 protocol of a RAM disk device.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+**/
+VOID
+RamDiskInitBlockIo (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINT32 Remainder;
+
+ BlockIo = &PrivateData->BlockIo;
+ BlockIo2 = &PrivateData->BlockIo2;
+ Media = &PrivateData->Media;
+
+ CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL));
+ CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL));
+
+ BlockIo->Media = Media;
+ BlockIo2->Media = Media;
+ Media->RemovableMedia = FALSE;
+ Media->MediaPresent = TRUE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = FALSE;
+ Media->WriteCaching = FALSE;
+
+ for (Media->BlockSize = RAM_DISK_DEFAULT_BLOCK_SIZE;
+ Media->BlockSize >= 1;
+ Media->BlockSize = Media->BlockSize >> 1) {
+ Media->LastBlock = DivU64x32Remainder (PrivateData->Size, Media->BlockSize, &Remainder) - 1;
+ if (Remainder == 0) {
+ break;
+ }
+ }
+ ASSERT (Media->BlockSize != 0);
+
+ return;
+}
+
+
+/**
+ 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
+RamDiskBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[out] 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
+RamDiskBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ UINTN NumberOfBlocks;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
+
+ if (MediaId != PrivateData->Media.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ Buffer,
+ (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
+ BufferSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[in] 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
+RamDiskBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ UINTN NumberOfBlocks;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
+
+ if (MediaId != PrivateData->Media.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (TRUE == PrivateData->Media.ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
+ Buffer,
+ BufferSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Flush the Block Device.
+
+ @param[in] 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
+RamDiskBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets the block device hardware.
+
+ @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param[in] ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2Reset (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reads the requested number of blocks from the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the read request is for.
+ @param[in] Lba The starting logical block address to read
+ from on the device.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size of the Buffer in bytes. This 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 either
+ having implicit or explicit ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event
+ is not NULL. The data was read correctly from
+ the device if the Token->Event is NULL.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2ReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ Status = RamDiskBlkIoReadBlocks (
+ &PrivateData->BlockIo,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If caller's event is given, signal it after the memory read completes.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes a specified number of blocks to the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be
+ written. The caller is responsible for
+ writing to only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size in bytes of Buffer. This must be a
+ multiple of the intrinsic block size of the
+ device.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL. The data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device cannot 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2WriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ Status = RamDiskBlkIoWriteBlocks (
+ &PrivateData->BlockIo,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If caller's event is given, signal it after the memory write completes.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL. All outstanding data was written
+ correctly to the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to write data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2FlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ if (TRUE == PrivateData->Media.ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // If caller's event is given, signal it directly.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c
new file mode 100644
index 000000000..fcbf4f117
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c
@@ -0,0 +1,244 @@
+/** @file
+ The driver entry point for RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+//
+// Handle for the EFI_RAM_DISK_PROTOCOL instance
+//
+EFI_HANDLE mRamDiskHandle = NULL;
+
+//
+// The EFI_RAM_DISK_PROTOCOL instances that is installed onto the driver
+// handle
+//
+EFI_RAM_DISK_PROTOCOL mRamDiskProtocol = {
+ RamDiskRegister,
+ RamDiskUnregister
+};
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+//
+LIST_ENTRY RegisteredRamDisks;
+
+//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL;
+EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol = NULL;
+
+
+/**
+ Check whether EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL are produced.
+ If both protocols are produced, publish all the reserved memory type RAM
+ disks to the NVDIMM Firmware Interface Table (NFIT).
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+RamDiskAcpiCheck (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ gBS->CloseEvent (Event);
+
+ //
+ // Locate the EFI_ACPI_TABLE_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Table Protocol, "
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ return;
+ }
+
+ //
+ // Locate the EFI_ACPI_SDT_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Sdt Protocol, "
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ mAcpiTableProtocol = NULL;
+ return;
+ }
+
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ RamDiskPublishNfit (PrivateData);
+ }
+}
+
+
+/**
+ The entry point for RamDiskDxe driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
+ resources.
+ @retval EFI_SUCCES All the related protocols are installed on
+ the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+ VOID *DummyInterface;
+ EFI_EVENT Event;
+
+ //
+ // If already started, return.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiRamDiskProtocolGuid,
+ NULL,
+ &DummyInterface
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Driver already started!\n"));
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate);
+ if (ConfigPrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Install RAM disk configuration form
+ //
+ Status = InstallRamDiskConfigForm (ConfigPrivate);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install the EFI_RAM_DISK_PROTOCOL and RAM disk private data onto a
+ // new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mRamDiskHandle,
+ &gEfiRamDiskProtocolGuid,
+ &mRamDiskProtocol,
+ &gEfiCallerIdGuid,
+ ConfigPrivate,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize the list of registered RAM disks maintained by the driver
+ //
+ InitializeListHead (&RegisteredRamDisks);
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ RamDiskAcpiCheck,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (ConfigPrivate != NULL) {
+ UninstallRamDiskConfigForm (ConfigPrivate);
+ }
+
+ return Status;
+}
+
+
+/**
+ Unload the RamDiskDxe driver and its configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The RamDiskDxe driver and its configuration
+ form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskDxeUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+
+ Status = gBS->HandleProtocol (
+ mRamDiskHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &ConfigPrivate
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (ConfigPrivate->Signature == RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ //
+ // Unregister all registered RAM disks
+ //
+ UnregisterAllRamDisks ();
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ mRamDiskHandle,
+ &gEfiRamDiskProtocolGuid,
+ &mRamDiskProtocol,
+ &gEfiCallerIdGuid,
+ ConfigPrivate,
+ NULL
+ );
+
+ UninstallRamDiskConfigForm (ConfigPrivate);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
new file mode 100644
index 000000000..bc2e642cf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
@@ -0,0 +1,84 @@
+## @file
+# Produces EFI_RAM_DISK_PROTOCOL and provides the capability to
+# create/remove RAM disks in a setup browser.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RamDiskDxe
+ MODULE_UNI_FILE = RamDiskDxe.uni
+ FILE_GUID = 28A03FF4-12B3-4305-A417-BB1A4F94081E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RamDiskDxeEntryPoint
+ UNLOAD_IMAGE = RamDiskDxeUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ RamDiskDriver.c
+ RamDiskImpl.c
+ RamDiskBlockIo.c
+ RamDiskProtocol.c
+ RamDiskFileExplorer.c
+ RamDiskImpl.h
+ RamDiskHii.vfr
+ RamDiskHiiStrings.uni
+ RamDiskNVData.h
+ RamDisk.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiHiiServicesLib
+ MemoryAllocationLib
+ HiiLib
+ FileExplorerLib
+ DevicePathLib
+ PrintLib
+ PcdLib
+ DxeServicesLib
+
+[Guids]
+ gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode
+ ## PRODUCES ## HII
+ ## CONSUMES ## HII
+ gRamDiskFormSetGuid
+ gEfiVirtualDiskGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type
+
+[Protocols]
+ gEfiRamDiskProtocolGuid ## PRODUCES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiBlockIoProtocolGuid ## PRODUCES
+ gEfiBlockIo2ProtocolGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni
new file mode 100644
index 000000000..edf35ea18
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Produces EFI_RAM_DISK_PROTOCOL and provides the capability to
+// create/remove RAM disks in a setup browser.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c
new file mode 100644
index 000000000..3a000389f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c
@@ -0,0 +1,107 @@
+/** @file
+ Internal file explorer helper functions for RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+
+/**
+ Helper function called as part of the code needed to allocate the proper
+ sized buffer for various EFI interfaces.
+
+ @param[in, out] Status Current status.
+ @param[in, out] Buffer Current allocated buffer, or NULL.
+ @param[in] 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
+GrowBuffer (
+ 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;
+}
+
+
+/**
+ This function gets the file information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned.
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ 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 (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr
new file mode 100644
index 000000000..3964d2f5b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr
@@ -0,0 +1,94 @@
+///** @file
+// VFR file used by the RamDiskDxe driver.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+// (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#include "RamDiskNVData.h"
+
+formset
+ guid = RAM_DISK_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ //
+ // Form #1 "Main Form - Add/Remove/Show RAM Disks"
+ //
+ form formid = MAIN_FORM_ID,
+ title = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+ oneof
+ questionid = CREATE_RAW_MEMORY_TYPE_QUESTION_ID,
+ prompt = STRING_TOKEN(STR_MEMORY_TYPE_PROMPT),
+ help = STRING_TOKEN(STR_MEMORY_TYPE_HELP),
+ flags = NUMERIC_SIZE_1 | INTERACTIVE,
+ option text = STRING_TOKEN(STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY), value = RAM_DISK_BOOT_SERVICE_DATA_MEMORY, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_RAM_DISK_RESERVED_MEMORY), value = RAM_DISK_RESERVED_MEMORY, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ goto CREATE_RAW_RAM_DISK_FORM_ID,
+ prompt = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM),
+ help = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM_HELP);
+
+ goto MAIN_FORM_ID,
+ prompt = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM),
+ help = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM_HELP),
+ flags = INTERACTIVE,
+ key = MAIN_GOTO_FILE_EXPLORER_ID;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_LIST_TEXT);
+
+ label MAIN_LABEL_LIST_START;
+ label MAIN_LABEL_LIST_END;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_REMOVE_SEL_HELP),
+ text = STRING_TOKEN(STR_REMOVE_SEL_TEXT),
+ flags = INTERACTIVE,
+ key = MAIN_REMOVE_RD_QUESTION_ID;
+
+ endform;
+
+ //
+ // Form #2 "Add New Raw RAM Disk"
+ //
+ form formid = CREATE_RAW_RAM_DISK_FORM_ID,
+ title = STRING_TOKEN(STR_ADD_RAW_FORM_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ numeric
+ questionid = CREATE_RAW_SIZE_QUESTION_ID,
+ prompt = STRING_TOKEN(STR_SIZE_PROMPT),
+ help = STRING_TOKEN(STR_SIZE_HELP),
+ flags = NUMERIC_SIZE_8 | DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 1,
+ maximum = 0xFFFFFFFFFFFFFFFF,
+ endnumeric;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_CREATE_AND_EXIT_HELP),
+ text = STRING_TOKEN(STR_CREATE_AND_EXIT_PROMPT),
+ flags = INTERACTIVE,
+ key = CREATE_RAW_SUBMIT_QUESTION_ID;
+
+ text
+ help = STRING_TOKEN(STR_DISCARD_AND_EXIT_HELP),
+ text = STRING_TOKEN(STR_DISCARD_AND_EXIT_PROMPT),
+ flags = INTERACTIVE,
+ key = CREATE_RAW_DISCARD_QUESTION_ID;
+
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni
new file mode 100644
index 000000000..5ee1172c4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni
@@ -0,0 +1,41 @@
+// /** @file
+// String definitions for RamDiskDxe driver form.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+// (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#langdef en-US "English"
+
+#string STR_FORM_SET_TITLE #language en-US "RAM Disk Configuration"
+#string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to add/remove RAM disks."
+
+#string STR_MAIN_FORM_TITLE #language en-US "RAM Disk HII Main Screen"
+#string STR_RAM_DISK_NULL_STRING #language en-US ""
+
+#string STR_RAM_DISK_LIST_TEXT #language en-US "Created RAM disk list:"
+#string STR_RAM_DISK_LIST_HELP #language en-US "Select for remove"
+#string STR_GOTO_ADD_RAW_FORM #language en-US "Create raw"
+#string STR_GOTO_ADD_RAW_FORM_HELP #language en-US "Create a raw RAM disk."
+#string STR_GOTO_ADD_FROM_FILE_FORM #language en-US "Create from file"
+#string STR_GOTO_ADD_FROM_FILE_FORM_HELP #language en-US "Create a RAM disk from a given file."
+#string STR_REMOVE_SEL_HELP #language en-US "Remove selected RAM disk(s)"
+#string STR_REMOVE_SEL_TEXT #language en-US "Remove selected RAM disk(s)."
+
+#string STR_ADD_RAW_FORM_TITLE #language en-US "Add A Raw RAM Disk"
+#string STR_ADD_RAW_FORM_SUBTITLE_TEXT #language en-US " "
+
+#string STR_SIZE_PROMPT #language en-US "Size (Hex):"
+#string STR_SIZE_HELP #language en-US "The valid RAM disk size should be multiples of the RAM disk block size."
+
+#string STR_MEMORY_TYPE_PROMPT #language en-US "Disk Memory Type:"
+#string STR_MEMORY_TYPE_HELP #language en-US "Specifies type of memory to use from available memory pool in system to create a disk."
+#string STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY #language en-US "Boot Service Data"
+#string STR_RAM_DISK_RESERVED_MEMORY #language en-US "Reserved"
+
+#string STR_CREATE_AND_EXIT_HELP #language en-US "Create a new RAM disk with the given starting and ending address."
+#string STR_CREATE_AND_EXIT_PROMPT #language en-US "Create & Exit"
+#string STR_DISCARD_AND_EXIT_HELP #language en-US "Discard and exit."
+#string STR_DISCARD_AND_EXIT_PROMPT #language en-US "Discard & Exit"
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
new file mode 100644
index 000000000..e35b8fa22
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
@@ -0,0 +1,758 @@
+/** @file
+ HII Config Access protocol implementation of RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016-2018 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+CHAR16 mRamDiskStorageName[] = L"RAM_DISK_CONFIGURATION";
+
+RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate = {
+ RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ EFI_PAGE_SIZE,
+ RAM_DISK_BOOT_SERVICE_DATA_MEMORY
+ },
+ {
+ RamDiskExtractConfig,
+ RamDiskRouteConfig,
+ RamDiskCallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mRamDiskHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ RAM_DISK_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+/**
+ This function publish the RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &ConfigPrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ConfigPrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gRamDiskFormSetGuid,
+ DriverHandle,
+ RamDiskDxeStrings,
+ RamDiskHiiBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ConfigPrivateData->HiiHandle = HiiHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+**/
+VOID
+UninstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ )
+{
+ //
+ // Uninstall HII package list
+ //
+ if (ConfigPrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (ConfigPrivateData->HiiHandle);
+ ConfigPrivateData->HiiHandle = NULL;
+ }
+
+ //
+ // Uninstall HII Config Access Protocol
+ //
+ if (ConfigPrivateData->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ ConfigPrivateData->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &ConfigPrivateData->ConfigAccess,
+ NULL
+ );
+ ConfigPrivateData->DriverHandle = NULL;
+ }
+
+ FreePool (ConfigPrivateData);
+}
+
+
+/**
+ Unregister all registered RAM disks.
+
+**/
+VOID
+UnregisterAllRamDisks (
+ VOID
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
+ NULL
+ );
+
+ RemoveEntryList (&PrivateData->ThisInstance);
+
+ if (RamDiskCreateHii == PrivateData->CreateMethod) {
+ //
+ // If a RAM disk is created within HII, then the RamDiskDxe driver
+ // driver is responsible for freeing the allocated memory for the
+ // RAM disk.
+ //
+ FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
+ }
+
+ FreePool (PrivateData->DevicePath);
+ FreePool (PrivateData);
+ }
+ }
+}
+
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] 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[out] 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
+RamDiskExtractConfig (
+ 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[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ 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 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
+RamDiskRouteConfig (
+ 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;
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Allocate memory and register the RAM disk created within RamDiskDxe
+ driver HII.
+
+ @param[in] Size If creating raw, size of the RAM disk to create.
+ If creating from file, zero.
+ @param[in] FileHandle If creating raw, NULL. If creating from file, the
+ file handle.
+ @param[in] MemoryType Type of memory to be used to create RAM Disk.
+
+ @retval EFI_SUCCESS RAM disk is created and registered.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to match the
+ size required.
+
+**/
+EFI_STATUS
+HiiCreateRamDisk (
+ IN UINT64 Size,
+ IN EFI_FILE_HANDLE FileHandle,
+ IN UINT8 MemoryType
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT64 *StartingAddr;
+ EFI_INPUT_KEY Key;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_FILE_INFO *FileInformation;
+
+ FileInformation = NULL;
+ StartingAddr = NULL;
+
+ if (FileHandle != NULL) {
+ //
+ // Create from file.
+ //
+ FileInformation = FileInfo (FileHandle);
+ if (NULL == FileInformation) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Not enough memory to get the file information!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update the size of RAM disk according to the file size.
+ //
+ Size = FileInformation->FileSize;
+ }
+
+ if (Size > (UINTN) -1) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"The given RAM disk size is too large!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (MemoryType == RAM_DISK_BOOT_SERVICE_DATA_MEMORY) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN)Size,
+ (VOID**)&StartingAddr
+ );
+ } else if (MemoryType == RAM_DISK_RESERVED_MEMORY) {
+ Status = gBS->AllocatePool (
+ EfiReservedMemoryType,
+ (UINTN)Size,
+ (VOID**)&StartingAddr
+ );
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if ((StartingAddr == NULL) || EFI_ERROR(Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Not enough memory to create the RAM disk!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (FileHandle != NULL) {
+ //
+ // Copy the file content to the RAM disk.
+ //
+ BufferSize = (UINTN) Size;
+ FileHandle->Read (
+ FileHandle,
+ &BufferSize,
+ (VOID *)(UINTN) StartingAddr
+ );
+ if (BufferSize != FileInformation->FileSize) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"File content read error!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Register the newly created RAM disk.
+ //
+ Status = RamDiskRegister (
+ ((UINT64)(UINTN) StartingAddr),
+ Size,
+ &gEfiVirtualDiskGuid,
+ NULL,
+ &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Fail to register the newly created RAM disk!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return Status;
+ }
+
+ //
+ // If RAM disk is created within HII, memory should be freed when the
+ // RAM disk is unregisterd.
+ //
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (RegisteredRamDisks.BackLink);
+ PrivateData->CreateMethod = RamDiskCreateHii;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function updates the registered RAM disks list on the main form.
+
+ @param[in, out] ConfigPrivate
+ Private data for configurating hii data for RAM
+ disks.
+
+**/
+VOID
+UpdateMainForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate
+ )
+{
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ LIST_ENTRY *Entry;
+ UINTN Index;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ CHAR16 *String;
+ CHAR16 RamDiskStr[128];
+ EFI_STRING_ID StringId;
+
+ //
+ // Init OpCode Handle
+ //
+ 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 = MAIN_LABEL_LIST_START;
+
+ //
+ // 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 = MAIN_LABEL_LIST_END;
+
+ Index = 0;
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ PrivateData->CheckBoxId = (EFI_QUESTION_ID)
+ (MAIN_CHECKBOX_QUESTION_ID_START + Index);
+ //
+ // CheckBox is unchecked by default.
+ //
+ PrivateData->CheckBoxChecked = FALSE;
+ String = RamDiskStr;
+
+ UnicodeSPrint (
+ String,
+ sizeof (RamDiskStr),
+ L" RAM Disk %d: [0x%lx, 0x%lx]\n",
+ Index,
+ PrivateData->StartingAddr,
+ PrivateData->StartingAddr + PrivateData->Size - 1
+ );
+
+ StringId = HiiSetString (ConfigPrivate->HiiHandle, 0, RamDiskStr, NULL);
+ ASSERT (StringId != 0);
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ PrivateData->CheckBoxId,
+ 0,
+ 0,
+ StringId,
+ STRING_TOKEN (STR_RAM_DISK_LIST_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ NULL
+ );
+
+ Index++;
+ }
+
+ HiiUpdateForm (
+ ConfigPrivate->HiiHandle,
+ &gRamDiskFormSetGuid,
+ MAIN_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] 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
+RamDiskCallback (
+ 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
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *FileDevPath;
+ EFI_FILE_HANDLE FileHandle;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This);
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == CREATE_RAW_SIZE_QUESTION_ID) {
+ Value->u64 = EFI_PAGE_SIZE;
+ ConfigPrivate->ConfigStore.Size = EFI_PAGE_SIZE;
+ Status = EFI_SUCCESS;
+ } else if (QuestionId == CREATE_RAW_MEMORY_TYPE_QUESTION_ID) {
+ Value->u8 = RAM_DISK_BOOT_SERVICE_DATA_MEMORY;
+ ConfigPrivate->ConfigStore.MemType = RAM_DISK_BOOT_SERVICE_DATA_MEMORY;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
+ (Action != EFI_BROWSER_ACTION_CHANGING) &&
+ (Action != EFI_BROWSER_ACTION_FORM_OPEN)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update the RAM disk list show at the main form first.
+ //
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == MAIN_GOTO_FILE_EXPLORER_ID) {
+ UpdateMainForm (ConfigPrivate);
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ switch (QuestionId) {
+ case MAIN_GOTO_FILE_EXPLORER_ID:
+ Status = ChooseFile (NULL, NULL, NULL, &FileDevPath);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (FileDevPath != NULL) {
+ //
+ // Open the file.
+ //
+ Status = EfiOpenFileByDevicePath (
+ &FileDevPath,
+ &FileHandle,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Create from file, RAM disk size is zero. It will be updated
+ // according to the file size.
+ //
+ Status = HiiCreateRamDisk (
+ 0,
+ FileHandle,
+ ConfigPrivate->ConfigStore.MemType
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Refresh the registered RAM disks list.
+ //
+ UpdateMainForm (ConfigPrivate);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (QuestionId) {
+ case MAIN_REMOVE_RD_QUESTION_ID:
+ //
+ // Remove the selected RAM disks
+ //
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (PrivateData->CheckBoxChecked) {
+ RamDiskUnregister (
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath
+ );
+ }
+ }
+
+ UpdateMainForm (ConfigPrivate);
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ break;
+
+ case CREATE_RAW_SIZE_QUESTION_ID:
+ ConfigPrivate->ConfigStore.Size = Value->u64;
+ break;
+
+ case CREATE_RAW_MEMORY_TYPE_QUESTION_ID:
+ ConfigPrivate->ConfigStore.MemType = Value->u8;
+ break;
+
+ case CREATE_RAW_SUBMIT_QUESTION_ID:
+ //
+ // Create raw, FileHandle is NULL.
+ //
+ Status = HiiCreateRamDisk (
+ ConfigPrivate->ConfigStore.Size,
+ NULL,
+ ConfigPrivate->ConfigStore.MemType
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Refresh the registered RAM disks list.
+ //
+ UpdateMainForm (ConfigPrivate);
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ case CREATE_RAW_DISCARD_QUESTION_ID:
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ default:
+ //
+ // QuestionIds for checkboxes
+ //
+ if ((QuestionId >= MAIN_CHECKBOX_QUESTION_ID_START) &&
+ (QuestionId < CREATE_RAW_RAM_DISK_FORM_ID)) {
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (PrivateData->CheckBoxId == QuestionId) {
+ PrivateData->CheckBoxChecked = (BOOLEAN) (Value->u8 != 0);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h
new file mode 100644
index 000000000..ed80b47cc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h
@@ -0,0 +1,604 @@
+/** @file
+ The header file of RamDiskDxe driver.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RAM_DISK_IMPL_H_
+#define _RAM_DISK_IMPL_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Protocol/RamDisk.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/RamDiskHii.h>
+#include <Guid/FileInfo.h>
+#include <IndustryStandard/Acpi61.h>
+
+#include "RamDiskNVData.h"
+
+///
+/// RAM disk general definitions and declarations
+///
+
+//
+// Default block size for RAM disk
+//
+#define RAM_DISK_DEFAULT_BLOCK_SIZE 512
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+//
+extern LIST_ENTRY RegisteredRamDisks;
+
+//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol;
+extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol;
+
+//
+// RAM Disk create method.
+//
+typedef enum _RAM_DISK_CREATE_METHOD {
+ RamDiskCreateOthers = 0,
+ RamDiskCreateHii
+} RAM_DISK_CREATE_METHOD;
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+// The struct contains the list entry and the information of each RAM
+// disk
+//
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ UINT64 StartingAddr;
+ UINT64 Size;
+ EFI_GUID TypeGuid;
+ UINT16 InstanceNumber;
+ RAM_DISK_CREATE_METHOD CreateMethod;
+ BOOLEAN InNfit;
+ EFI_QUESTION_ID CheckBoxId;
+ BOOLEAN CheckBoxChecked;
+
+ LIST_ENTRY ThisInstance;
+} RAM_DISK_PRIVATE_DATA;
+
+#define RAM_DISK_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'D', 'S', 'K')
+#define RAM_DISK_PRIVATE_FROM_BLKIO(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+#define RAM_DISK_PRIVATE_FROM_BLKIO2(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo2, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+#define RAM_DISK_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_PRIVATE_DATA, ThisInstance, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+
+///
+/// RAM disk HII-related definitions and declarations
+///
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 RamDiskHiiBin[];
+extern UINT8 RamDiskDxeStrings[];
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+
+ RAM_DISK_CONFIGURATION ConfigStore;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+} RAM_DISK_CONFIG_PRIVATE_DATA;
+
+extern RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate;
+
+#define RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'C', 'F', 'G')
+#define RAM_DISK_CONFIG_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_CONFIG_PRIVATE_DATA, ConfigAccess, RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+/**
+ Register a RAM disk with specified address, size and type.
+
+ @param[in] RamDiskBase The base address of registered RAM disk.
+ @param[in] RamDiskSize The size of registered RAM disk.
+ @param[in] RamDiskType The type of registered RAM disk. The GUID can be
+ any of the values defined in section 9.3.6.9, or a
+ vendor defined GUID.
+ @param[in] ParentDevicePath
+ Pointer to the parent device path. If there is no
+ parent device path then ParentDevicePath is NULL.
+ @param[out] DevicePath On return, points to a pointer to the device path
+ of the RAM disk device.
+ If ParentDevicePath is not NULL, the returned
+ DevicePath is created by appending a RAM disk node
+ to the parent device path. If ParentDevicePath is
+ NULL, the returned DevicePath is a RAM disk device
+ path without appending. This function is
+ responsible for allocating the buffer DevicePath
+ with the boot service AllocatePool().
+
+ @retval EFI_SUCCESS The RAM disk is registered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
+ RamDiskSize is 0.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
+ is already present in the handle database.
+ @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
+ resource limitation.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRegister (
+ IN UINT64 RamDiskBase,
+ IN UINT64 RamDiskSize,
+ IN EFI_GUID *RamDiskType,
+ IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Unregister a RAM disk specified by DevicePath.
+
+ @param[in] DevicePath A pointer to the device path that describes a RAM
+ Disk device.
+
+ @retval EFI_SUCCESS The RAM disk is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
+ valid ramdisk device path and not supported
+ by the driver.
+ @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
+ exist.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskUnregister (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Initialize the BlockIO protocol of a RAM disk device.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+**/
+VOID
+RamDiskInitBlockIo (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] 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
+RamDiskBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[out] 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
+RamDiskBlkIoReadBlocks (
+ 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[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[in] 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
+RamDiskBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] 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
+RamDiskBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Resets the block device hardware.
+
+ @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param[in] ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2Reset (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the read request is for.
+ @param[in] Lba The starting logical block address to read
+ from on the device.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size of the Buffer in bytes. This 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 either
+ having implicit or explicit ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event
+ is not NULL. The data was read correctly from
+ the device if the Token->Event is NULL.
+ @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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2ReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be
+ written. The caller is responsible for
+ writing to only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size in bytes of Buffer. This must be a
+ multiple of the intrinsic block size of the
+ device.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL. The data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device cannot 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.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2WriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL. All outstanding data was written
+ correctly to the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to write data.
+ @retval EFI_WRITE_PROTECTED The device cannot 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_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2FlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ This function publish the RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ );
+
+/**
+ This function removes RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+**/
+VOID
+UninstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ );
+
+/**
+ Unregister all registered RAM disks.
+
+**/
+VOID
+UnregisterAllRamDisks (
+ VOID
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] 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[out] 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
+RamDiskExtractConfig (
+ 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[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ 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 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
+RamDiskRouteConfig (
+ 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[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] 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
+RamDiskCallback (
+ 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 gets the file information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned.
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+
+/**
+ Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
+ table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been published.
+ @retval others The RAM disk NFIT has not been published.
+
+**/
+EFI_STATUS
+RamDiskPublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h
new file mode 100644
index 000000000..3293ec1d5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h
@@ -0,0 +1,44 @@
+/** @file
+ Header file for NV data structure definition.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RAM_DISK_NVDATA_H_
+#define _RAM_DISK_NVDATA_H_
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/RamDiskHii.h>
+
+#define MAIN_FORM_ID 0x1000
+#define MAIN_GOTO_FILE_EXPLORER_ID 0x1001
+#define MAIN_REMOVE_RD_QUESTION_ID 0x1002
+#define MAIN_LABEL_LIST_START 0x1003
+#define MAIN_LABEL_LIST_END 0x1004
+#define MAIN_CHECKBOX_QUESTION_ID_START 0x1100
+
+#define CREATE_RAW_RAM_DISK_FORM_ID 0x2000
+#define CREATE_RAW_SIZE_QUESTION_ID 0x2001
+#define CREATE_RAW_SUBMIT_QUESTION_ID 0x2002
+#define CREATE_RAW_DISCARD_QUESTION_ID 0x2003
+#define CREATE_RAW_MEMORY_TYPE_QUESTION_ID 0x2004
+
+#define RAM_DISK_BOOT_SERVICE_DATA_MEMORY 0x00
+#define RAM_DISK_RESERVED_MEMORY 0x01
+#define RAM_DISK_MEMORY_TYPE_MAX 0x02
+
+typedef struct {
+ //
+ // The size of the RAM disk to be created.
+ //
+ UINT64 Size;
+ //
+ // Selected RAM Disk Memory Type
+ //
+ UINT8 MemType;
+} RAM_DISK_CONFIGURATION;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
new file mode 100644
index 000000000..4333e0005
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
@@ -0,0 +1,857 @@
+/** @file
+ The realization of EFI_RAM_DISK_PROTOCOL.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {
+ RAM_DISK_PRIVATE_DATA_SIGNATURE,
+ NULL
+};
+
+MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_RAM_DISK_DP,
+ {
+ (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),
+ (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)
+ }
+ }
+};
+
+BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;
+UINTN mRamDiskSsdtTableKey;
+
+
+/**
+ Initialize the RAM disk device node.
+
+ @param[in] PrivateData Points to RAM disk private data.
+ @param[in, out] RamDiskDevNode Points to the RAM disk device node.
+
+**/
+VOID
+RamDiskInitDeviceNode (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData,
+ IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode
+ )
+{
+ WriteUnaligned64 (
+ (UINT64 *) &(RamDiskDevNode->StartingAddr[0]),
+ (UINT64) PrivateData->StartingAddr
+ );
+ WriteUnaligned64 (
+ (UINT64 *) &(RamDiskDevNode->EndingAddr[0]),
+ (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1
+ );
+ CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);
+ RamDiskDevNode->Instance = PrivateData->InstanceNumber;
+}
+
+
+/**
+ Initialize and publish NVDIMM root device SSDT in ACPI table.
+
+ @retval EFI_SUCCESS The NVDIMM root device SSDT is published.
+ @retval Others The NVDIMM root device SSDT is not published.
+
+**/
+EFI_STATUS
+RamDiskPublishSsdt (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN SectionInstance;
+ UINTN TableSize;
+
+ Status = EFI_SUCCESS;
+ SectionInstance = 0;
+
+ //
+ // Scan all the EFI raw section instances in FV to find the NVDIMM root
+ // device SSDT.
+ //
+ while (TRUE) {
+ Status = GetSectionFromFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_RAW,
+ SectionInstance,
+ (VOID **) &Table,
+ &TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) {
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ Table,
+ TableSize,
+ &mRamDiskSsdtTableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ mRamDiskSsdtTableKeyValid = TRUE;
+ }
+
+ FreePool (Table);
+ return Status;
+ } else {
+ FreePool (Table);
+ SectionInstance++;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
+ table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been published.
+ @retval others The RAM disk NFIT has not been published.
+
+**/
+EFI_STATUS
+RamDiskPublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINTN TableIndex;
+ VOID *TableHeader;
+ EFI_ACPI_TABLE_VERSION TableVersion;
+ UINTN TableKey;
+ EFI_ACPI_DESCRIPTION_HEADER *NfitHeader;
+ EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
+ *SpaRange;
+ VOID *Nfit;
+ UINT32 NfitLen;
+ UINTN MemoryMapSize;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINT64 CurrentData;
+ UINT8 Checksum;
+ BOOLEAN MemoryFound;
+
+ //
+ // Get the EFI memory map.
+ //
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ MemoryFound = FALSE;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ do {
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+ ASSERT_EFI_ERROR (Status);
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
+ if ((MemoryMapEntry->Type == EfiReservedMemoryType) &&
+ (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) &&
+ (MemoryMapEntry->PhysicalStart +
+ MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE)
+ >= PrivateData->StartingAddr + PrivateData->Size)) {
+ MemoryFound = TRUE;
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n"
+ ));
+ break;
+ }
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+ FreePool (MemoryMap);
+
+ if (!MemoryFound) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Determine whether there is a NFIT already in the ACPI table.
+ //
+ Status = EFI_SUCCESS;
+ TableIndex = 0;
+ TableKey = 0;
+ TableHeader = NULL;
+
+ while (!EFI_ERROR (Status)) {
+ Status = mAcpiSdtProtocol->GetAcpiTable (
+ TableIndex,
+ (EFI_ACPI_SDT_HEADER **)&TableHeader,
+ &TableVersion,
+ &TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ TableIndex++;
+
+ if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
+ EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
+ break;
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // A NFIT is already in the ACPI table.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n"
+ ));
+
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader;
+ NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ Nfit = AllocateZeroPool (NfitLen);
+ if (Nfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (Nfit, TableHeader, NfitHeader->Length);
+
+ //
+ // Update the NFIT head pointer.
+ //
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
+
+ //
+ // Uninstall the origin NFIT from the ACPI table.
+ //
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Nfit);
+ return Status;
+ }
+
+ //
+ // Append the System Physical Address (SPA) Range Structure at the end
+ // of the origin NFIT.
+ //
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
+ ((UINT8 *)Nfit + NfitHeader->Length);
+
+ //
+ // Update the length field of the NFIT
+ //
+ NfitHeader->Length = NfitLen;
+
+ //
+ // The checksum will be updated after the new contents are appended.
+ //
+ NfitHeader->Checksum = 0;
+ } else {
+ //
+ // Assumption is made that if no NFIT is in the ACPI table, there is no
+ // NVDIMM root device in the \SB scope.
+ // Therefore, a NVDIMM root device will be reported via Secondary System
+ // Description Table (SSDT).
+ //
+ Status = RamDiskPublishSsdt ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // No NFIT is in the ACPI table, we will create one here.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n"
+ ));
+
+ NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) +
+ sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ Nfit = AllocateZeroPool (NfitLen);
+ if (Nfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
+ ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
+ NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE;
+ NfitHeader->Length = NfitLen;
+ NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION;
+ NfitHeader->Checksum = 0;
+ NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId));
+ CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64));
+ }
+
+ //
+ // Fill in the content of the SPA Range Structure.
+ //
+ SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE;
+ SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr;
+ SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size;
+ CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid);
+
+ Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length);
+ NfitHeader->Checksum = Checksum;
+
+ //
+ // Publish the NFIT to the ACPI table.
+ // Note, since the NFIT might be modified by other driver, therefore, we
+ // do not track the returning TableKey from the InstallAcpiTable().
+ //
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ Nfit,
+ NfitHeader->Length,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Nfit);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->InNfit = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the
+ ACPI table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been unpublished.
+ @retval others The RAM disk NFIT has not been unpublished.
+
+**/
+EFI_STATUS
+RamDiskUnpublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN TableIndex;
+ VOID *TableHeader;
+ EFI_ACPI_TABLE_VERSION TableVersion;
+ UINTN TableKey;
+ EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader;
+ EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
+ *SpaRange;
+ VOID *NewNfit;
+ VOID *NewNfitPtr;
+ EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader;
+ UINT32 NewNfitLen;
+ UINT32 RemainLen;
+ UINT8 Checksum;
+
+ //
+ // Find the NFIT in the ACPI table.
+ //
+ Status = EFI_SUCCESS;
+ TableIndex = 0;
+ TableKey = 0;
+ TableHeader = NULL;
+
+ while (!EFI_ERROR (Status)) {
+ Status = mAcpiSdtProtocol->GetAcpiTable (
+ TableIndex,
+ (EFI_ACPI_SDT_HEADER **)&TableHeader,
+ &TableVersion,
+ &TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ TableIndex++;
+
+ if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
+ EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
+ break;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No NFIT is found in the ACPI table.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length -
+ sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+
+ //
+ // After removing this RAM disk from the NFIT, if no other structure is in
+ // the NFIT, we just remove the NFIT and the SSDT which is used to report
+ // the NVDIMM root device.
+ //
+ if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) {
+ //
+ // Remove the NFIT.
+ //
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM
+ // root device.
+ // We do not care the return status since this SSDT might already be
+ // uninstalled by other drivers to update the information of the NVDIMM
+ // root device.
+ //
+ if (mRamDiskSsdtTableKeyValid) {
+ mRamDiskSsdtTableKeyValid = FALSE;
+
+ mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ mRamDiskSsdtTableKey
+ );
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ NewNfit = AllocateZeroPool (NewNfitLen);
+ if (NewNfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get a copy of the old NFIT header content.
+ //
+ CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+ NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit;
+ NewNfitHeader->Length = NewNfitLen;
+ NewNfitHeader->Checksum = 0;
+
+ //
+ // Copy the content of required NFIT structures.
+ //
+ NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
+ RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+ while (RemainLen > 0) {
+ if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) &&
+ (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) {
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader;
+
+ if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) &&
+ (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) &&
+ (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) {
+ //
+ // Skip the SPA Range Structure for the RAM disk to be unpublished
+ // from NFIT.
+ //
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
+ continue;
+ }
+ }
+
+ //
+ // Copy the content of origin NFIT.
+ //
+ CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length);
+ NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length;
+
+ //
+ // Move to the header of next NFIT structure.
+ //
+ RemainLen -= NfitStructHeader->Length;
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
+ }
+
+ Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length);
+ NewNfitHeader->Checksum = Checksum;
+
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (NewNfit);
+ return Status;
+ }
+
+ //
+ // Publish the NFIT to the ACPI table.
+ // Note, since the NFIT might be modified by other driver, therefore, we
+ // do not track the returning TableKey from the InstallAcpiTable().
+ //
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ NewNfit,
+ NewNfitLen,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (NewNfit);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Register a RAM disk with specified address, size and type.
+
+ @param[in] RamDiskBase The base address of registered RAM disk.
+ @param[in] RamDiskSize The size of registered RAM disk.
+ @param[in] RamDiskType The type of registered RAM disk. The GUID can be
+ any of the values defined in section 9.3.6.9, or a
+ vendor defined GUID.
+ @param[in] ParentDevicePath
+ Pointer to the parent device path. If there is no
+ parent device path then ParentDevicePath is NULL.
+ @param[out] DevicePath On return, points to a pointer to the device path
+ of the RAM disk device.
+ If ParentDevicePath is not NULL, the returned
+ DevicePath is created by appending a RAM disk node
+ to the parent device path. If ParentDevicePath is
+ NULL, the returned DevicePath is a RAM disk device
+ path without appending. This function is
+ responsible for allocating the buffer DevicePath
+ with the boot service AllocatePool().
+
+ @retval EFI_SUCCESS The RAM disk is registered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
+ RamDiskSize is 0.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
+ is already present in the handle database.
+ @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
+ resource limitation.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRegister (
+ IN UINT64 RamDiskBase,
+ IN UINT64 RamDiskSize,
+ IN EFI_GUID *RamDiskType,
+ IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ RAM_DISK_PRIVATE_DATA *RegisteredPrivateData;
+ MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
+ UINTN DevicePathSize;
+ LIST_ENTRY *Entry;
+
+ if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Add check to prevent data read across the memory boundary
+ //
+ if ((RamDiskSize > MAX_UINTN) ||
+ (RamDiskBase > MAX_UINTN - RamDiskSize + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RamDiskDevNode = NULL;
+
+ //
+ // Create a new RAM disk instance and initialize its private data
+ //
+ PrivateData = AllocateCopyPool (
+ sizeof (RAM_DISK_PRIVATE_DATA),
+ &mRamDiskPrivateDataTemplate
+ );
+ if (NULL == PrivateData) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->StartingAddr = RamDiskBase;
+ PrivateData->Size = RamDiskSize;
+ CopyGuid (&PrivateData->TypeGuid, RamDiskType);
+ InitializeListHead (&PrivateData->ThisInstance);
+
+ //
+ // Generate device path information for the registered RAM disk
+ //
+ RamDiskDevNode = AllocateCopyPool (
+ sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
+ &mRamDiskDeviceNodeTemplate
+ );
+ if (NULL == RamDiskDevNode) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
+
+ *DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
+ );
+ if (NULL == *DevicePath) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ PrivateData->DevicePath = *DevicePath;
+
+ //
+ // Check whether the created device path is already present in the handle
+ // database
+ //
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);
+
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {
+ //
+ // Compare device path
+ //
+ if ((CompareMem (
+ PrivateData->DevicePath,
+ RegisteredPrivateData->DevicePath,
+ DevicePathSize)) == 0) {
+ *DevicePath = NULL;
+ Status = EFI_ALREADY_STARTED;
+ goto ErrorExit;
+ }
+ }
+ }
+ }
+
+ //
+ // Fill Block IO protocol informations for the RAM disk
+ //
+ RamDiskInitBlockIo (PrivateData);
+
+ //
+ // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
+ // handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ PrivateData->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Insert the newly created one to the registered RAM disk list
+ //
+ InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);
+
+ gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);
+
+ FreePool (RamDiskDevNode);
+
+ if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
+ RamDiskPublishNfit (PrivateData);
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (RamDiskDevNode != NULL) {
+ FreePool (RamDiskDevNode);
+ }
+
+ if (PrivateData != NULL) {
+ if (PrivateData->DevicePath) {
+ FreePool (PrivateData->DevicePath);
+ }
+
+ FreePool (PrivateData);
+ }
+
+ return Status;
+}
+
+
+/**
+ Unregister a RAM disk specified by DevicePath.
+
+ @param[in] DevicePath A pointer to the device path that describes a RAM
+ Disk device.
+
+ @retval EFI_SUCCESS The RAM disk is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
+ valid ramdisk device path and not supported
+ by the driver.
+ @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
+ exist.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskUnregister (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ BOOLEAN Found;
+ UINT64 StartingAddr;
+ UINT64 EndingAddr;
+ EFI_DEVICE_PATH_PROTOCOL *Header;
+ MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ if (NULL == DevicePath) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Locate the RAM disk device node.
+ //
+ RamDiskDevNode = NULL;
+ Header = DevicePath;
+ do {
+ //
+ // Test if the current device node is a RAM disk.
+ //
+ if ((MEDIA_DEVICE_PATH == Header->Type) &&
+ (MEDIA_RAM_DISK_DP == Header->SubType)) {
+ RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
+
+ break;
+ }
+
+ Header = NextDevicePathNode (Header);
+ } while ((Header->Type != END_DEVICE_PATH_TYPE));
+
+ if (NULL == RamDiskDevNode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Found = FALSE;
+ StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
+ EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
+
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+
+ //
+ // Unregister the RAM disk given by its starting address, ending address
+ // and type guid.
+ //
+ if ((StartingAddr == PrivateData->StartingAddr) &&
+ (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
+ (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
+ //
+ // Remove the content for this RAM disk in NFIT.
+ //
+ if (PrivateData->InNfit) {
+ RamDiskUnpublishNfit (PrivateData);
+ }
+
+ //
+ // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
+ //
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
+ NULL
+ );
+
+ RemoveEntryList (&PrivateData->ThisInstance);
+
+ if (RamDiskCreateHii == PrivateData->CreateMethod) {
+ //
+ // If a RAM disk is created within HII, then the RamDiskDxe driver
+ // driver is responsible for freeing the allocated memory for the
+ // RAM disk.
+ //
+ FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
+ }
+
+ FreePool (PrivateData->DevicePath);
+ FreePool (PrivateData);
+ Found = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (TRUE == Found) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c
new file mode 100644
index 000000000..abbd4f768
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c
@@ -0,0 +1,179 @@
+/** @file
+ UEFI Component Name protocol for UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName = {
+ UdfComponentNameGetDriverName,
+ UdfComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdfComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdfComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for Udf module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdfDriverNameTable[] = {
+ {
+ "eng;en",
+ L"UDF File System 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
+UdfComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUdfDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUdfComponentName)
+ );
+}
+
+/**
+ 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
+UdfComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/File.c
new file mode 100644
index 000000000..4ad7bb93d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/File.c
@@ -0,0 +1,904 @@
+/** @file
+ Handle operations in files and directories from UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+EFI_FILE_PROTOCOL gUdfFileIoOps = {
+ EFI_FILE_PROTOCOL_REVISION,
+ UdfOpen,
+ UdfClose,
+ UdfDelete,
+ UdfRead,
+ UdfWrite,
+ UdfGetPosition,
+ UdfSetPosition,
+ UdfGetInfo,
+ UdfSetInfo,
+ UdfFlush,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+#define _ROOT_FILE(_PrivData) (_PrivData)->Root
+#define _PARENT_FILE(_PrivData) \
+ ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File)
+#define _FILE(_PrivData) _PARENT_FILE(_PrivData)
+
+/**
+ Open the root directory on a volume.
+
+ @param This Protocol instance pointer.
+ @param Root Returns an Open file handle for the root directory
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the file system.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
+ resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || Root == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);
+
+ if (PrivFsData->OpenFiles == 0) {
+ //
+ // There is no more open files. Read volume information again since it was
+ // cleaned up on the last UdfClose() call.
+ //
+ Status = ReadUdfVolumeInformation (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Udf_Volume;
+ }
+ }
+
+ CleanupFileInformation (&PrivFsData->Root);
+
+ //
+ // Find root directory file.
+ //
+ Status = FindRootDirectory (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &PrivFsData->Root
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Root_Dir;
+ }
+
+ PrivFileData =
+ (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
+ if (PrivFileData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Alloc_Priv_File_Data;
+ }
+
+ PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE;
+ PrivFileData->SimpleFs = This;
+ PrivFileData->Root = &PrivFsData->Root;
+ PrivFileData->IsRootDirectory = TRUE;
+
+ CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
+ sizeof (EFI_FILE_PROTOCOL));
+
+ *Root = &PrivFileData->FileIo;
+
+ PrivFsData->OpenFiles++;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+Error_Alloc_Priv_File_Data:
+ CleanupFileInformation (&PrivFsData->Root);
+
+Error_Find_Root_Dir:
+
+Error_Read_Udf_Volume:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This The protocol instance pointer.
+ @param NewHandle Returns File Handle for FileName.
+ @param FileName Null terminated string. "\", ".", and ".." are supported.
+ @param OpenMode Open mode for file.
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
+ resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ CHAR16 FilePath[UDF_PATH_LENGTH];
+ UDF_FILE_INFO File;
+ PRIVATE_UDF_FILE_DATA *NewPrivFileData;
+ CHAR16 *TempFileName;
+
+ ZeroMem (FilePath, sizeof FilePath);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || NewHandle == NULL || FileName == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ if (OpenMode != EFI_FILE_MODE_READ) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ //
+ // Build full path
+ //
+ if (*FileName == L'\\') {
+ StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);
+ } else {
+ StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);
+ StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");
+ StrCatS (FilePath, UDF_PATH_LENGTH, FileName);
+ }
+
+ MangleFileName (FilePath);
+ if (FilePath[0] == L'\0') {
+ Status = EFI_NOT_FOUND;
+ goto Error_Bad_FileName;
+ }
+
+ Status = FindFile (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ FilePath,
+ _ROOT_FILE (PrivFileData),
+ _PARENT_FILE (PrivFileData),
+ &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,
+ &File
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_File;
+ }
+
+ NewPrivFileData =
+ (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
+ if (NewPrivFileData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Alloc_New_Priv_File_Data;
+ }
+
+ CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,
+ sizeof (PRIVATE_UDF_FILE_DATA));
+ CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));
+
+ NewPrivFileData->IsRootDirectory = FALSE;
+
+ StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);
+ FileName = NewPrivFileData->AbsoluteFileName;
+
+ while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {
+ FileName = TempFileName + 1;
+ }
+
+ StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName);
+
+ Status = GetFileSize (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &NewPrivFileData->File,
+ &NewPrivFileData->FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: GetFileSize() fails with status - %r.\n",
+ __FUNCTION__, Status
+ ));
+ goto Error_Get_File_Size;
+ }
+
+ NewPrivFileData->FilePosition = 0;
+ ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,
+ sizeof (UDF_READ_DIRECTORY_INFO));
+
+ *NewHandle = &NewPrivFileData->FileIo;
+
+ PrivFsData->OpenFiles++;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+Error_Get_File_Size:
+ FreePool ((VOID *)NewPrivFileData);
+
+Error_Alloc_New_Priv_File_Data:
+ CleanupFileInformation (&File);
+
+Error_Find_File:
+Error_Bad_FileName:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains
+ required size.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ UDF_VOLUME_INFO *Volume;
+ UDF_FILE_INFO *Parent;
+ UDF_READ_DIRECTORY_INFO *ReadDirInfo;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ UDF_FILE_INFO FoundFile;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc;
+ VOID *NewFileEntryData;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ UINT64 FileSize;
+ UINT64 BufferSizeUint64;
+
+ ZeroMem (FileName, sizeof FileName);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&
+ Buffer == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ BlockIo = PrivFsData->BlockIo;
+ DiskIo = PrivFsData->DiskIo;
+ Volume = &PrivFsData->Volume;
+ ReadDirInfo = &PrivFileData->ReadDirInfo;
+ NewFileIdentifierDesc = NULL;
+ NewFileEntryData = NULL;
+
+ Parent = _PARENT_FILE (PrivFileData);
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {
+ if (PrivFileData->FilePosition > PrivFileData->FileSize) {
+ //
+ // File's position is beyond the EOF
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Error_File_Beyond_The_Eof;
+ }
+
+ if (PrivFileData->FilePosition == PrivFileData->FileSize) {
+ *BufferSize = 0;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ BufferSizeUint64 = *BufferSize;
+
+ Status = ReadFileData (
+ BlockIo,
+ DiskIo,
+ Volume,
+ Parent,
+ PrivFileData->FileSize,
+ &PrivFileData->FilePosition,
+ Buffer,
+ &BufferSizeUint64
+ );
+ ASSERT (BufferSizeUint64 <= MAX_UINTN);
+ *BufferSize = (UINTN)BufferSizeUint64;
+ } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {
+ if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {
+ Status = EFI_DEVICE_ERROR;
+ *BufferSize = 0;
+ goto Done;
+ }
+
+ for (;;) {
+ Status = ReadDirectoryEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Parent->FileIdentifierDesc->Icb,
+ Parent->FileEntry,
+ ReadDirInfo,
+ &NewFileIdentifierDesc
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ FreePool (ReadDirInfo->DirectoryData);
+ ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
+
+ *BufferSize = 0;
+ Status = EFI_SUCCESS;
+ }
+
+ goto Done;
+ }
+ //
+ // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc'
+ // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the
+ // code reaches here, 'NewFileIdentifierDesc' must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (NewFileIdentifierDesc != NULL);
+
+ if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
+ break;
+ }
+
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ }
+
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &NewFileIdentifierDesc->Icb,
+ &NewFileEntryData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Fe;
+ }
+ ASSERT (NewFileEntryData != NULL);
+
+ if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) {
+ Status = ResolveSymlink (
+ BlockIo,
+ DiskIo,
+ Volume,
+ Parent,
+ NewFileEntryData,
+ &FoundFile
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Resolve_Symlink;
+ }
+
+ FreePool ((VOID *)NewFileEntryData);
+ NewFileEntryData = FoundFile.FileEntry;
+
+ Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
+ if (EFI_ERROR (Status)) {
+ FreePool ((VOID *)FoundFile.FileIdentifierDesc);
+ goto Error_Get_FileName;
+ }
+
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
+ } else {
+ FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
+ FoundFile.FileEntry = NewFileEntryData;
+
+ Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_FileName;
+ }
+ }
+
+ Status = GetFileSize (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &FoundFile,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_File_Size;
+ }
+
+ Status = SetFileInfo (
+ &FoundFile,
+ FileSize,
+ FileName,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Set_File_Info;
+ }
+
+ PrivFileData->FilePosition++;
+ Status = EFI_SUCCESS;
+ } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Error_Set_File_Info:
+Error_Get_File_Size:
+Error_Get_FileName:
+Error_Resolve_Symlink:
+ if (NewFileEntryData != NULL) {
+ FreePool (NewFileEntryData);
+ }
+
+Error_Find_Fe:
+ if (NewFileIdentifierDesc != NULL) {
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ }
+
+Done:
+Error_File_Beyond_The_Eof:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Close the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfClose (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Status = EFI_SUCCESS;
+
+ if (This == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ if (!PrivFileData->IsRootDirectory) {
+ CleanupFileInformation (&PrivFileData->File);
+
+ if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
+ FreePool (PrivFileData->ReadDirInfo.DirectoryData);
+ }
+ }
+
+ FreePool ((VOID *)PrivFileData);
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
+ deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDelete (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ (VOID)PrivFileData->FileIo.Close(This);
+
+ return EFI_WARN_DELETE_FAILURE;
+}
+
+/**
+ Write data to a file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer in which data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Get file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for directories is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ if (This == NULL || Position == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ //
+ // As per UEFI spec, if the file handle is a directory, then the current file
+ // position has no meaning and the operation is not supported.
+ //
+ if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The file is not a directory. So, return its position.
+ //
+ *Position = PrivFileData->FilePosition;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;
+ ASSERT (FileIdentifierDesc != NULL);
+ if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
+ //
+ // If the file handle is a directory, the _only_ position that may be set is
+ // zero. This has no effect of starting the read proccess of the directory
+ // entries over.
+ //
+ if (Position == 0) {
+ PrivFileData->FilePosition = Position;
+ PrivFileData->ReadDirInfo.FidOffset = 0;
+ Status = EFI_SUCCESS;
+ }
+ } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
+ //
+ // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
+ // set to the EOF.
+ //
+ if (Position == 0xFFFFFFFFFFFFFFFF) {
+ PrivFileData->FilePosition = PrivFileData->FileSize;
+ } else {
+ PrivFileData->FilePosition = Position;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Get information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
+ BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ EFI_FILE_SYSTEM_INFO *FileSystemInfo;
+ UINTN FileSystemInfoLength;
+ UINT64 VolumeSize;
+ UINT64 FreeSpaceSize;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
+ UINTN FileSystemVolumeLabelLength;
+ CHAR16 VolumeLabel[64];
+
+ if (This == NULL || InformationType == NULL || BufferSize == NULL ||
+ (*BufferSize != 0 && Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ Status = EFI_UNSUPPORTED;
+
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ Status = SetFileInfo (
+ _FILE (PrivFileData),
+ PrivFileData->FileSize,
+ PrivFileData->FileName,
+ BufferSize,
+ Buffer
+ );
+ } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemInfoLength = StrSize (VolumeLabel) +
+ sizeof (EFI_FILE_SYSTEM_INFO);
+ if (*BufferSize < FileSystemInfoLength) {
+ *BufferSize = FileSystemInfoLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ StrCpyS (
+ FileSystemInfo->VolumeLabel,
+ (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16),
+ VolumeLabel
+ );
+ Status = GetVolumeSize (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &VolumeSize,
+ &FreeSpaceSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemInfo->Size = FileSystemInfoLength;
+ FileSystemInfo->ReadOnly = TRUE;
+ FileSystemInfo->BlockSize =
+ PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;
+ FileSystemInfo->VolumeSize = VolumeSize;
+ FileSystemInfo->FreeSpace = FreeSpaceSize;
+
+ *BufferSize = FileSystemInfoLength;
+ Status = EFI_SUCCESS;
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemVolumeLabelLength = StrSize (VolumeLabel) +
+ sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL);
+ if (*BufferSize < FileSystemVolumeLabelLength) {
+ *BufferSize = FileSystemVolumeLabelLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
+ StrCpyS (
+ FileSystemVolumeLabel->VolumeLabel,
+ (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16),
+ VolumeLabel
+ );
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Set information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was set.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was flushed.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfFlush (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return EFI_WRITE_PROTECTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c
new file mode 100644
index 000000000..ee236ccde
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c
@@ -0,0 +1,214 @@
+/** @file
+ Helper functions for mangling file names in UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+/**
+ Trim the leading and trailing spaces for a give Unicode string.
+
+ @param[in] String The Unicode string to trim.
+
+ @return A pointer to the trimmed string.
+
+**/
+CHAR16 *
+TrimString (
+ IN CHAR16 *String
+ )
+{
+ CHAR16 *TempString;
+
+ for ( ; *String != L'\0' && *String == L' '; String++) {
+ ;
+ }
+
+ TempString = String + StrLen (String) - 1;
+ while ((TempString >= String) && (*TempString == L' ')) {
+ TempString--;
+ }
+
+ *(TempString + 1) = L'\0';
+
+ return String;
+}
+
+/**
+ Replace the content of a Unicode string with the content of another Unicode
+ string.
+
+ @param[in] Destination A pointer to a Unicode string.
+ @param[in] Source A pointer to a Unicode string.
+
+**/
+VOID
+ReplaceLeft (
+ IN CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ CONST CHAR16 *EndString;
+
+ EndString = Source + StrLen (Source);
+ while (Source <= EndString) {
+ *Destination++ = *Source++;
+ }
+}
+
+/**
+ Remove one or more consecutive backslashes starting from the second character
+ of a given Unicode string.
+
+ @param[in] String A pointer to a Unicode string.
+
+ @return A pointer to the modified string.
+
+**/
+CHAR16 *
+ExcludeTrailingBackslashes (
+ IN CHAR16 *String
+ )
+{
+ CHAR16 *TempString;
+
+ switch (*(String + 1)) {
+ case L'\\':
+ break;
+ case L'\0':
+ default:
+ String++;
+ goto Exit;
+ }
+
+ TempString = String;
+ while (*TempString != L'\0' && *TempString == L'\\') {
+ TempString++;
+ }
+
+ if (TempString - 1 > String) {
+ ReplaceLeft (String + 1, TempString);
+ }
+
+ String++;
+
+Exit:
+ return String;
+}
+
+/**
+ Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
+
+ @param[in] FileName Filename.
+
+ @retval The mangled Filename.
+
+**/
+CHAR16 *
+MangleFileName (
+ IN CHAR16 *FileName
+ )
+{
+ CHAR16 *FileNameSavedPointer;
+ CHAR16 *TempFileName;
+ UINTN BackslashesNo;
+
+ if (FileName == NULL || *FileName == L'\0') {
+ FileName = NULL;
+ goto Exit;
+ }
+
+ FileName = TrimString (FileName);
+ if (*FileName == L'\0') {
+ goto Exit;
+ }
+
+ if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
+ FileName[StrLen (FileName) - 1] = L'\0';
+ }
+
+ FileNameSavedPointer = FileName;
+
+ if (FileName[0] == L'.') {
+ if (FileName[1] == L'.') {
+ if (FileName[2] == L'\0') {
+ goto Exit;
+ } else {
+ FileName += 2;
+ }
+ } else if (FileName[1] == L'\0') {
+ goto Exit;
+ }
+ }
+
+ while (*FileName != L'\0') {
+ if (*FileName == L'\\') {
+ FileName = ExcludeTrailingBackslashes (FileName);
+ } else if (*FileName == L'.') {
+ switch (*(FileName + 1)) {
+ case L'\0':
+ *FileName = L'\0';
+ break;
+ case L'\\':
+ TempFileName = FileName + 1;
+ TempFileName = ExcludeTrailingBackslashes (TempFileName);
+ ReplaceLeft (FileName, TempFileName);
+ break;
+ case '.':
+ if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||
+ (*(FileName + 2) != L'\0'))) {
+ FileName++;
+ continue;
+ }
+
+ BackslashesNo = 0;
+ TempFileName = FileName - 1;
+ while (TempFileName >= FileNameSavedPointer) {
+ if (*TempFileName == L'\\') {
+ if (++BackslashesNo == 2) {
+ break;
+ }
+ }
+
+ TempFileName--;
+ }
+
+ TempFileName++;
+
+ if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {
+ FileName += 2;
+ } else {
+ if (*(FileName + 2) != L'\0') {
+ ReplaceLeft (TempFileName, FileName + 3);
+ if (*(TempFileName - 1) == L'\\') {
+ FileName = TempFileName;
+ ExcludeTrailingBackslashes (TempFileName - 1);
+ TempFileName = FileName;
+ }
+ } else {
+ *TempFileName = L'\0';
+ }
+
+ FileName = TempFileName;
+ }
+
+ break;
+ default:
+ FileName++;
+ }
+ } else {
+ FileName++;
+ }
+ }
+
+ FileName = FileNameSavedPointer;
+ if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] == L'\\')) {
+ FileName [StrLen (FileName) - 1] = L'\0';
+ }
+
+Exit:
+ return FileName;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
new file mode 100644
index 000000000..e9e55cb2b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
@@ -0,0 +1,2924 @@
+/** @file
+ Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// Vendor-Defined Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ EFI_LBA DescriptorLBAs[4];
+ UINTN Index;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ DescriptorLBAs[0] = 256;
+ DescriptorLBAs[1] = EndLBA - 256;
+ DescriptorLBAs[2] = EndLBA;
+ DescriptorLBAs[3] = 512;
+
+ for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (DescriptorLBAs[Index], BlockSize),
+ sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
+ (VOID *)AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read LBA has a valid AVDP descriptor.
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // No AVDP found.
+ //
+ return EFI_VOLUME_CORRUPTED;
+}
+
+/**
+ Save the content of Logical Volume Descriptors and Partitions Descriptors in
+ memory.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS The descriptors were saved.
+ @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
+ resources.
+ @retval other The descriptors were not saved due to
+ ReadDisk error.
+
+**/
+EFI_STATUS
+StartMainVolumeDescriptorSequence (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ EFI_LBA SeqStartBlock;
+ EFI_LBA SeqEndBlock;
+ BOOLEAN StopSequence;
+ VOID *Buffer;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINT32 LogicalBlockSize;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // The logical partition created by Partition driver is relative to the main
+ // VDS extent location, so we start the Main Volume Descriptor Sequence at
+ // LBA 0.
+ //
+ // We don't need to check again if we have valid Volume Descriptors here since
+ // Partition driver already did.
+ //
+ SeqStartBlock = 0;
+ SeqEndBlock = SeqStartBlock + DivU64x32 ((UINT64)ExtentAd->ExtentLength,
+ BlockSize);
+ StopSequence = FALSE;
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPartitionDescriptor:
+ //
+ // Save Partition Descriptor
+ //
+ CopyMem (&Volume->PartitionDesc, Buffer, sizeof (Volume->PartitionDesc));
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ //
+ // Save Logical Volume Descriptor
+ //
+ CopyMem (&Volume->LogicalVolDesc, Buffer, sizeof (Volume->LogicalVolDesc));
+ break;
+
+ case UdfTerminatingDescriptor:
+ StopSequence = TRUE;
+ break;
+
+ default:
+ ;
+ }
+ }
+
+ //
+ // Determine FE (File Entry) size
+ //
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+ if (LogicalBlockSize >= UDF_LOGICAL_SECTOR_SIZE) {
+ Volume->FileEntrySize = (UINTN)LogicalBlockSize;
+ } else {
+ Volume->FileEntrySize = UDF_LOGICAL_SECTOR_SIZE;
+ }
+
+ Status = EFI_SUCCESS;
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Return a Partition Descriptor given a Long Allocation Descriptor. This is
+ necessary to calculate the right extent (LongAd) offset which is added up
+ with partition's starting location.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] LongAd Long Allocation Descriptor pointer.
+
+ @return A pointer to a Partition Descriptor.
+
+**/
+UDF_PARTITION_DESCRIPTOR *
+GetPdFromLongAd (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd
+ )
+{
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UINT16 PartitionNum;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ //
+ // UDF 1.02 specification:
+ //
+ // There shall be exactly one prevailing Logical Volume Descriptor recorded
+ // per Volume Set. The Partition Maps field shall contain only Type 1
+ // Partition Maps.
+ //
+ // UDF 1.50 through 2.60 specs say:
+ //
+ // For the purpose of interchange partition maps shall be limited to
+ // Partition Map type 1, except type 2 maps as described in the document.
+ //
+ // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
+ // checked already in Partition driver for existence of a single Type 1
+ // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
+ // used to access Partition Maps data within the Logical Volume Descriptor)
+ // in the Long Allocation Descriptor should be 0 to indicate there is only
+ // one partition.
+ //
+ if (LongAd->ExtentLocation.PartitionReferenceNumber != 0) {
+ return NULL;
+ }
+ //
+ // Since only one partition, get the first one directly.
+ //
+ PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
+ break;
+
+ default:
+ //
+ // Unsupported UDF revision
+ //
+ return NULL;
+ }
+
+ //
+ // Check if partition number matches Partition Descriptor found in Main Volume
+ // Descriptor Sequence.
+ //
+ if (Volume->PartitionDesc.PartitionNumber == PartitionNum) {
+ return &Volume->PartitionDesc;
+ }
+
+ return NULL;
+}
+
+/**
+ Return logical sector number of a given Long Allocation Descriptor.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] LongAd Long Allocation Descriptor pointer.
+ @param[out] Lsn Logical sector number pointer.
+
+ @retval EFI_SUCCESS Logical sector number successfully returned.
+ @retval EFI_UNSUPPORTED Logical sector number is not returned due to
+ unrecognized format.
+
+**/
+EFI_STATUS
+GetLongAdLsn (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd,
+ OUT UINT64 *Lsn
+ )
+{
+ UDF_PARTITION_DESCRIPTOR *PartitionDesc;
+
+ PartitionDesc = GetPdFromLongAd (Volume, LongAd);
+ if (PartitionDesc == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
+ __FUNCTION__
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ *Lsn = (UINT64)PartitionDesc->PartitionStartingLocation -
+ Volume->MainVdsStartLocation +
+ LongAd->ExtentLocation.LogicalBlockNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return logical sector number of a given Short Allocation Descriptor.
+
+ @param[in] Volume Volume pointer.
+ @param[in] PartitionDesc Partition Descriptor pointer.
+ @param[in] ShortAd Short Allocation Descriptor pointer.
+
+ @return The logical sector number of a given Short Allocation Descriptor.
+
+**/
+UINT64
+GetShortAdLsn (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_PARTITION_DESCRIPTOR *PartitionDesc,
+ IN UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd
+ )
+{
+ return (UINT64)PartitionDesc->PartitionStartingLocation -
+ Volume->MainVdsStartLocation + ShortAd->ExtentPosition;
+}
+
+/**
+ Find File Set Descriptor of a given Logical Volume Descriptor.
+
+ The found FSD will contain the extent (LogicalVolumeContentsUse) where our
+ root directory is.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+
+ @retval EFI_SUCCESS File Set Descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other File Set Descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindFileSetDescriptor (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Lsn;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+ Status = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse, &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // As per UDF 2.60 specification:
+ //
+ // There shall be exactly one File Set Descriptor recorded per Logical
+ // Volume.
+ //
+ // Read disk block
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize),
+ sizeof (Volume->FileSetDesc),
+ &Volume->FileSetDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &Volume->FileSetDesc.DescriptorTag;
+
+ //
+ // Check if read block is a File Set Descriptor
+ //
+ if (DescriptorTag->TagIdentifier != UdfFileSetDescriptor) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Volume and File Structure on an UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume Volume information pointer.
+
+ @retval EFI_SUCCESS Volume and File Structure were read.
+ @retval other Volume and File Structure were not read.
+
+**/
+EFI_STATUS
+ReadVolumeFileStructure (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
+ UDF_EXTENT_AD *ExtentAd;
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Save Main VDS start block number
+ //
+ ExtentAd = &AnchorPoint.MainVolumeDescriptorSequenceExtent;
+
+ Volume->MainVdsStartLocation = (UINT64)ExtentAd->ExtentLocation;
+
+ //
+ // Start Main Volume Descriptor Sequence.
+ //
+ Status = StartMainVolumeDescriptorSequence (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ Volume
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Calculate length of a given File Identifier Descriptor.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+
+ @return The length of a given File Identifier Descriptor.
+
+**/
+UINT64
+GetFidDescriptorLength (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc
+ )
+{
+ return (UINT64)(
+ (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) + 3 +
+ FileIdentifierDesc->LengthOfFileIdentifier +
+ FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2
+ );
+}
+
+/**
+ Duplicate a given File Identifier Descriptor.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
+
+**/
+VOID
+DuplicateFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **NewFileIdentifierDesc
+ )
+{
+ *NewFileIdentifierDesc =
+ (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (
+ (UINTN) GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc);
+}
+
+/**
+ Duplicate either a given File Entry or a given Extended File Entry.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] FileEntry (Extended) File Entry pointer.
+ @param[out] NewFileEntry The duplicated (Extended) File Entry.
+
+**/
+VOID
+DuplicateFe (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN VOID *FileEntry,
+ OUT VOID **NewFileEntry
+ )
+{
+ *NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);
+}
+
+/**
+ Get raw data + length of a given File Entry or Extended File Entry.
+
+ The file's recorded data can contain either real file content (inline) or
+ a sequence of extents (or Allocation Descriptors) which tells where file's
+ content is stored in.
+
+ NOTE: The FE/EFE can be thought it was an inode.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The (Extended) File Entry is external input, so this routine will do basic
+ validation for (Extended) File Entry and report status.
+
+ @param[in] FileEntryData (Extended) File Entry pointer.
+ @param[in] FileEntrySize Size of the (Extended) File Entry specified
+ by FileEntryData.
+ @param[out] Data Buffer contains the raw data of a given
+ (Extended) File Entry.
+ @param[out] Length Length of the data in Buffer.
+
+ @retval EFI_SUCCESS Raw data and size of the FE/EFE was read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+
+**/
+EFI_STATUS
+GetFileEntryData (
+ IN VOID *FileEntryData,
+ IN UINTN FileEntrySize,
+ OUT VOID **Data,
+ OUT UINT64 *Length
+ )
+{
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_FILE_ENTRY *FileEntry;
+
+ DescriptorTag = FileEntryData;
+
+ if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
+
+ *Length = ExtendedFileEntry->InformationLength;
+ *Data = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
+ ExtendedFileEntry->LengthOfExtendedAttributes);
+ } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
+
+ *Length = FileEntry->InformationLength;
+ *Data = (VOID *)((UINT8 *)FileEntry->Data +
+ FileEntry->LengthOfExtendedAttributes);
+ }
+
+ if ((*Length > FileEntrySize) ||
+ ((UINTN)FileEntryData > (UINTN)(*Data)) ||
+ ((UINTN)(*Data) - (UINTN)FileEntryData > FileEntrySize - *Length)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Allocation Descriptors' data information from a given FE/EFE.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The (Extended) File Entry is external input, so this routine will do basic
+ validation for (Extended) File Entry and report status.
+
+ @param[in] FileEntryData (Extended) File Entry pointer.
+ @param[in] FileEntrySize Size of the (Extended) File Entry specified
+ by FileEntryData.
+ @param[out] AdsData Buffer contains the Allocation Descriptors'
+ data from a given FE/EFE.
+ @param[out] Length Length of the data in AdsData.
+
+ @retval EFI_SUCCESS The data and size of Allocation Descriptors
+ were read from the FE/EFE.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+
+**/
+EFI_STATUS
+GetAdsInformation (
+ IN VOID *FileEntryData,
+ IN UINTN FileEntrySize,
+ OUT VOID **AdsData,
+ OUT UINT64 *Length
+ )
+{
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_FILE_ENTRY *FileEntry;
+
+ DescriptorTag = FileEntryData;
+
+ if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
+
+ *Length = ExtendedFileEntry->LengthOfAllocationDescriptors;
+ *AdsData = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
+ ExtendedFileEntry->LengthOfExtendedAttributes);
+ } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
+
+ *Length = FileEntry->LengthOfAllocationDescriptors;
+ *AdsData = (VOID *)((UINT8 *)FileEntry->Data +
+ FileEntry->LengthOfExtendedAttributes);
+ }
+
+ if ((*Length > FileEntrySize) ||
+ ((UINTN)FileEntryData > (UINTN)(*AdsData)) ||
+ ((UINTN)(*AdsData) - (UINTN)FileEntryData > FileEntrySize - *Length)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read next Long Allocation Descriptor from a given file's data.
+
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundLongAd Long Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Long Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
+
+**/
+EFI_STATUS
+GetLongAdFromAds (
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT UDF_LONG_ALLOCATION_DESCRIPTOR **FoundLongAd
+ )
+{
+ UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd;
+ UDF_EXTENT_FLAGS ExtentFlags;
+
+ for (;;) {
+ if (*Offset >= Length) {
+ //
+ // No more Long Allocation Descriptors.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ LongAd =
+ (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
+
+ //
+ // If it's either an indirect AD (Extended Alllocation Descriptor) or an
+ // allocated AD, then return it.
+ //
+ ExtentFlags = GET_EXTENT_FLAGS (LongAdsSequence, LongAd);
+ if (ExtentFlags == ExtentIsNextExtent ||
+ ExtentFlags == ExtentRecordedAndAllocated) {
+ break;
+ }
+
+ //
+ // This AD is either not recorded but allocated, or not recorded and not
+ // allocated. Skip it.
+ //
+ *Offset += AD_LENGTH (LongAdsSequence);
+ }
+
+ *FoundLongAd = LongAd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read next Short Allocation Descriptor from a given file's data.
+
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundShortAd Short Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Short Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
+
+**/
+EFI_STATUS
+GetShortAdFromAds (
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT UDF_SHORT_ALLOCATION_DESCRIPTOR **FoundShortAd
+ )
+{
+ UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd;
+ UDF_EXTENT_FLAGS ExtentFlags;
+
+ for (;;) {
+ if (*Offset >= Length) {
+ //
+ // No more Short Allocation Descriptors.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ ShortAd =
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
+
+ //
+ // If it's either an indirect AD (Extended Alllocation Descriptor) or an
+ // allocated AD, then return it.
+ //
+ ExtentFlags = GET_EXTENT_FLAGS (ShortAdsSequence, ShortAd);
+ if (ExtentFlags == ExtentIsNextExtent ||
+ ExtentFlags == ExtentRecordedAndAllocated) {
+ break;
+ }
+
+ //
+ // This AD is either not recorded but allocated, or not recorded and not
+ // allocated. Skip it.
+ //
+ *Offset += AD_LENGTH (ShortAdsSequence);
+ }
+
+ *FoundShortAd = ShortAd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
+ file's data.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundAd Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Short Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
+ Invalid type of descriptor was given.
+
+**/
+EFI_STATUS
+GetAllocationDescriptor (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT VOID **FoundAd
+ )
+{
+ if (RecordingFlags == LongAdsSequence) {
+ return GetLongAdFromAds (
+ Data,
+ Offset,
+ Length,
+ (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd
+ );
+ } else if (RecordingFlags == ShortAdsSequence) {
+ return GetShortAdFromAds (
+ Data,
+ Offset,
+ Length,
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd
+ );
+ }
+
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Return logical sector number of either Short or Long Allocation Descriptor.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Lsn Logical sector number pointer.
+
+ @retval EFI_SUCCESS Logical sector number of the given Allocation
+ Descriptor successfully returned.
+ @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
+ Descriptor is not returned due to unrecognized
+ format.
+
+**/
+EFI_STATUS
+GetAllocationDescriptorLsn (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *Ad,
+ OUT UINT64 *Lsn
+ )
+{
+ UDF_PARTITION_DESCRIPTOR *PartitionDesc;
+
+ if (RecordingFlags == LongAdsSequence) {
+ return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);
+ } else if (RecordingFlags == ShortAdsSequence) {
+ PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);
+ if (PartitionDesc == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Lsn = GetShortAdLsn (
+ Volume,
+ PartitionDesc,
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
+ );
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Return offset + length of a given indirect Allocation Descriptor (AED).
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Offset Offset of a given indirect Allocation
+ Descriptor.
+ @param[out] Length Length of a given indirect Allocation
+ Descriptor.
+
+ @retval EFI_SUCCESS The offset and length were returned.
+ @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
+ to lack of resources.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other The offset and length were not returned.
+
+**/
+EFI_STATUS
+GetAedAdsOffset (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ OUT UINT64 *Offset,
+ OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ExtentLength;
+ UINT64 Lsn;
+ VOID *Data;
+ UINT32 LogicalBlockSize;
+ UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+ Status = GetAllocationDescriptorLsn (RecordingFlags,
+ Volume,
+ ParentIcb,
+ Ad,
+ &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = AllocatePool (ExtentLength);
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+
+ //
+ // Read extent.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentLength,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;
+
+ DescriptorTag = &AllocExtDesc->DescriptorTag;
+
+ //
+ // Check if read extent contains a valid tag identifier for AED.
+ //
+ if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Exit;
+ }
+
+ //
+ // Get AED's block offset and its length.
+ //
+ *Offset = MultU64x32 (Lsn, LogicalBlockSize) +
+ sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);
+ *Length = AllocExtDesc->LengthOfAllocationDescriptors;
+
+Exit:
+ FreePool (Data);
+
+ return Status;
+}
+
+/**
+ Read Allocation Extent Descriptor into memory.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Data Buffer that contains the Allocation Extent
+ Descriptor.
+ @param[out] Length Length of Data.
+
+ @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
+ @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
+ due to lack of resources.
+ @retval other Fail to read the disk.
+
+**/
+EFI_STATUS
+GetAedAdsData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ OUT VOID **Data,
+ OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Offset;
+
+ //
+ // Get AED's offset + length.
+ //
+ Status = GetAedAdsOffset (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ RecordingFlags,
+ Ad,
+ &Offset,
+ Length
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer to read in AED's data.
+ //
+ *Data = AllocatePool ((UINTN) (*Length));
+ if (*Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ (UINTN) (*Length),
+ *Data
+ );
+}
+
+/**
+ Function used to serialise reads of Allocation Descriptors.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
+ @param[in] Length Length of Buffer.
+
+ @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
+ Descriptor.
+ @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
+
+**/
+EFI_STATUS
+GrowUpBufferToNextAd (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ IN OUT VOID **Buffer,
+ IN UINT64 Length
+ )
+{
+ UINT32 ExtentLength;
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+
+ if (*Buffer == NULL) {
+ *Buffer = AllocatePool (ExtentLength);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read data or size of either a File Entry or an Extended File Entry.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[in, out] ReadFileInfo Read file information pointer.
+
+ @retval EFI_SUCCESS Data or size of a FE/EFE was read.
+ @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
+ lack of resources.
+ @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
+ invalid.
+ @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
+ is not supported.
+ @retval other Data or size of a FE/EFE was not read.
+
+**/
+EFI_STATUS
+ReadFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_FILE_INFO *ReadFileInfo
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LogicalBlockSize;
+ VOID *Data;
+ VOID *DataBak;
+ UINT64 Length;
+ VOID *Ad;
+ UINT64 AdOffset;
+ UINT64 Lsn;
+ BOOLEAN DoFreeAed;
+ UINT64 FilePosition;
+ UINT64 Offset;
+ UINT64 DataOffset;
+ UINT64 BytesLeft;
+ UINT64 DataLength;
+ BOOLEAN FinishedSeeking;
+ UINT32 ExtentLength;
+ UDF_FE_RECORDING_FLAGS RecordingFlags;
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+ DoFreeAed = FALSE;
+
+ //
+ // set BytesLeft to suppress incorrect compiler/analyzer warnings
+ //
+ BytesLeft = 0;
+ DataOffset = 0;
+ FilePosition = 0;
+ FinishedSeeking = FALSE;
+ Data = NULL;
+
+ switch (ReadFileInfo->Flags) {
+ case ReadFileGetFileSize:
+ case ReadFileAllocateAndRead:
+ //
+ // Initialise ReadFileInfo structure for either getting file size, or
+ // reading file's recorded data.
+ //
+ ReadFileInfo->ReadLength = 0;
+ ReadFileInfo->FileData = NULL;
+ break;
+ case ReadFileSeekAndRead:
+ //
+ // About to seek a file and/or read its data.
+ //
+ Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
+ if (ReadFileInfo->FileDataSize > Length) {
+ //
+ // About to read beyond the EOF -- truncate it.
+ //
+ ReadFileInfo->FileDataSize = Length;
+ }
+
+ //
+ // Initialise data to start seeking and/or reading a file.
+ //
+ BytesLeft = ReadFileInfo->FileDataSize;
+ DataOffset = 0;
+ FilePosition = 0;
+ FinishedSeeking = FALSE;
+
+ break;
+ }
+
+ RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
+ switch (RecordingFlags) {
+ case InlineData:
+ //
+ // There are no extents for this FE/EFE. All data is inline.
+ //
+ Status = GetFileEntryData (FileEntryData, Volume->FileEntrySize, &Data, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ReadFileInfo->Flags == ReadFileGetFileSize) {
+ ReadFileInfo->ReadLength = Length;
+ } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
+ //
+ // Allocate buffer for starting read data.
+ //
+ ReadFileInfo->FileData = AllocatePool ((UINTN) Length);
+ if (ReadFileInfo->FileData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read all inline data into ReadFileInfo->FileData
+ //
+ CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);
+ ReadFileInfo->ReadLength = Length;
+ } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
+ //
+ // If FilePosition is non-zero, seek file to FilePosition, read
+ // FileDataSize bytes and then updates FilePosition.
+ //
+ CopyMem (
+ ReadFileInfo->FileData,
+ (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
+ (UINTN) ReadFileInfo->FileDataSize
+ );
+
+ ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ break;
+
+ case LongAdsSequence:
+ case ShortAdsSequence:
+ //
+ // This FE/EFE contains a run of Allocation Descriptors. Get data + size
+ // for start reading them out.
+ //
+ Status = GetAdsInformation (FileEntryData, Volume->FileEntrySize, &Data, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AdOffset = 0;
+
+ for (;;) {
+ //
+ // Read AD.
+ //
+ Status = GetAllocationDescriptor (
+ RecordingFlags,
+ Data,
+ &AdOffset,
+ Length,
+ &Ad
+ );
+ if (Status == EFI_DEVICE_ERROR) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Check if AD is an indirect AD. If so, read Allocation Extent
+ // Descriptor and its extents (ADs).
+ //
+ if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
+ DataBak = Data;
+ Status = GetAedAdsData (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ RecordingFlags,
+ Ad,
+ &Data,
+ &Length
+ );
+
+ if (!DoFreeAed) {
+ DoFreeAed = TRUE;
+ } else {
+ FreePool (DataBak);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_Aed;
+ }
+ ASSERT (Data != NULL);
+
+ AdOffset = 0;
+ continue;
+ }
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+
+ Status = GetAllocationDescriptorLsn (RecordingFlags,
+ Volume,
+ ParentIcb,
+ Ad,
+ &Lsn);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ switch (ReadFileInfo->Flags) {
+ case ReadFileGetFileSize:
+ ReadFileInfo->ReadLength += ExtentLength;
+ break;
+ case ReadFileAllocateAndRead:
+ //
+ // Increase FileData (if necessary) to read next extent.
+ //
+ Status = GrowUpBufferToNextAd (
+ RecordingFlags,
+ Ad,
+ &ReadFileInfo->FileData,
+ ReadFileInfo->ReadLength
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Alloc_Buffer_To_Next_Ad;
+ }
+
+ //
+ // Read extent's data into FileData.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentLength,
+ (VOID *)((UINT8 *)ReadFileInfo->FileData +
+ ReadFileInfo->ReadLength)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ ReadFileInfo->ReadLength += ExtentLength;
+ break;
+ case ReadFileSeekAndRead:
+ //
+ // Seek file first before reading in its data.
+ //
+ if (FinishedSeeking) {
+ Offset = 0;
+ goto Skip_File_Seek;
+ }
+
+ if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
+ FilePosition += ExtentLength;
+ goto Skip_Ad;
+ }
+
+ if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
+ Offset = ReadFileInfo->FilePosition - FilePosition;
+ } else {
+ Offset = 0;
+ }
+
+ //
+ // Done with seeking file. Start reading its data.
+ //
+ FinishedSeeking = TRUE;
+
+ Skip_File_Seek:
+ //
+ // Make sure we don't read more data than really wanted.
+ //
+ if (ExtentLength - Offset > BytesLeft) {
+ DataLength = BytesLeft;
+ } else {
+ DataLength = ExtentLength - Offset;
+ }
+
+ //
+ // Read extent's data into FileData.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset + MultU64x32 (Lsn, LogicalBlockSize),
+ (UINTN) DataLength,
+ (VOID *)((UINT8 *)ReadFileInfo->FileData +
+ DataOffset)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ //
+ // Update current file's position.
+ //
+ DataOffset += DataLength;
+ ReadFileInfo->FilePosition += DataLength;
+
+ BytesLeft -= DataLength;
+ if (BytesLeft == 0) {
+ //
+ // There is no more file data to read.
+ //
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ break;
+ }
+
+ Skip_Ad:
+ //
+ // Point to the next AD (extent).
+ //
+ AdOffset += AD_LENGTH (RecordingFlags);
+ }
+
+ break;
+ case ExtendedAdsSequence:
+ // FIXME: Not supported. Got no volume with it, yet.
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ //
+ // A flag value reserved by the ECMA-167 standard (3rd Edition - June
+ // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
+ //
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+Done:
+ if (DoFreeAed) {
+ FreePool (Data);
+ }
+
+ return Status;
+
+Error_Read_Disk_Blk:
+Error_Alloc_Buffer_To_Next_Ad:
+ if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
+ FreePool (ReadFileInfo->FileData);
+ }
+
+ if (DoFreeAed) {
+ FreePool (Data);
+ }
+
+Error_Get_Aed:
+ return Status;
+}
+
+/**
+ Find a file by its filename from a given Parent file.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] FileName File name string.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb Long Allocation Descriptor pointer.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
+ @retval EFI_NOT_FOUND The file was not found.
+
+**/
+EFI_STATUS
+InternalFindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FileName,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+ UDF_READ_DIRECTORY_INFO ReadDirInfo;
+ BOOLEAN Found;
+ CHAR16 FoundFileName[UDF_FILENAME_LENGTH];
+ VOID *CompareFileEntry;
+
+ //
+ // Check if both Parent->FileIdentifierDesc and Icb are NULL.
+ //
+ if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if parent file is really directory.
+ //
+ if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If FileName is current file or working directory, just duplicate Parent's
+ // FE/EFE and FID descriptors.
+ //
+ if (StrCmp (FileName, L".") == 0) {
+ if (Parent->FileIdentifierDesc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Start directory listing.
+ //
+ ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
+ Found = FALSE;
+
+ for (;;) {
+ Status = ReadDirectoryEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ (Parent->FileIdentifierDesc != NULL) ?
+ &Parent->FileIdentifierDesc->Icb :
+ Icb,
+ Parent->FileEntry,
+ &ReadDirInfo,
+ &FileIdentifierDesc
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ break;
+ }
+ //
+ // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
+ // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
+ // reaches here, 'FileIdentifierDesc' must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (FileIdentifierDesc != NULL);
+
+ if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
+ //
+ // This FID contains the location (FE/EFE) of the parent directory of this
+ // directory (Parent), and if FileName is either ".." or "\\", then it's
+ // the expected FID.
+ //
+ if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {
+ Found = TRUE;
+ break;
+ }
+ } else {
+ Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (StrCmp (FileName, FoundFileName) == 0) {
+ //
+ // FID has been found. Prepare to find its respective FE/EFE.
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+
+ FreePool ((VOID *)FileIdentifierDesc);
+ }
+
+ if (ReadDirInfo.DirectoryData != NULL) {
+ //
+ // Free all allocated resources for the directory listing.
+ //
+ FreePool (ReadDirInfo.DirectoryData);
+ }
+
+ if (Found) {
+ Status = EFI_SUCCESS;
+
+ File->FileIdentifierDesc = FileIdentifierDesc;
+
+ //
+ // If the requested file is root directory, then the FE/EFE was already
+ // retrieved in UdfOpenVolume() function, thus no need to find it again.
+ //
+ // Otherwise, find FE/EFE from the respective FID.
+ //
+ if (StrCmp (FileName, L"\\") != 0) {
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &FileIdentifierDesc->Icb,
+ &CompareFileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Fe;
+ }
+
+ //
+ // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
+ //
+ if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,
+ Volume->FileEntrySize) != 0) {
+ File->FileEntry = CompareFileEntry;
+ } else {
+ FreePool ((VOID *)FileIdentifierDesc);
+ FreePool ((VOID *)CompareFileEntry);
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ return Status;
+
+Error_Find_Fe:
+ FreePool ((VOID *)FileIdentifierDesc);
+
+ return Status;
+}
+
+/**
+ Read volume information on a medium which contains a valid UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS Volume information read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
+
+**/
+EFI_STATUS
+ReadUdfVolumeInformation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Read all necessary UDF volume information and keep it private to the driver
+ //
+ Status = ReadVolumeFileStructure (
+ BlockIo,
+ DiskIo,
+ Volume
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find File Set Descriptor
+ //
+ Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Find the root directory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] File Root directory file.
+
+ @retval EFI_SUCCESS Root directory found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindRootDirectory (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_FILE_INFO Parent;
+
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Volume->FileSetDesc.RootDirectoryIcb,
+ &File->FileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Parent.FileEntry = File->FileEntry;
+ Parent.FileIdentifierDesc = NULL;
+
+ Status = FindFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ L"\\",
+ NULL,
+ &Parent,
+ &Volume->FileSetDesc.RootDirectoryIcb,
+ File
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (File->FileEntry);
+ }
+
+ return Status;
+}
+
+/**
+ Find either a File Entry or a Extended File Entry from a given ICB.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Icb ICB of the FID.
+ @param[out] FileEntry File Entry or Extended File Entry.
+
+ @retval EFI_SUCCESS File Entry or Extended File Entry found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFileEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT VOID **FileEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Lsn;
+ UINT32 LogicalBlockSize;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ VOID *ReadBuffer;
+
+ Status = GetLongAdLsn (Volume, Icb, &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+
+ ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);
+ if (ReadBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read extent.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ Volume->FileEntrySize,
+ ReadBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ DescriptorTag = ReadBuffer;
+
+ //
+ // Check if the read extent contains a valid Tag Identifier for the expected
+ // FE/EFE.
+ //
+ if (DescriptorTag->TagIdentifier != UdfFileEntry &&
+ DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Invalid_Fe;
+ }
+
+ *FileEntry = ReadBuffer;
+ return EFI_SUCCESS;
+
+Error_Invalid_Fe:
+Error_Read_Disk_Blk:
+ FreePool (ReadBuffer);
+
+ return Status;
+}
+
+/**
+ Find a file given its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] FilePath File's absolute path.
+ @param[in] Root Root directory file.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb ICB of Parent.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS FilePath was found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FilePath,
+ IN UDF_FILE_INFO *Root,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ CHAR16 *FileNamePointer;
+ UDF_FILE_INFO PreviousFile;
+ VOID *FileEntry;
+
+ Status = EFI_NOT_FOUND;
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
+ while (*FilePath != L'\0') {
+ FileNamePointer = FileName;
+ while (*FilePath != L'\0' && *FilePath != L'\\') {
+ if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
+ (ARRAY_SIZE (FileName) - 1)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *FileNamePointer++ = *FilePath++;
+ }
+
+ *FileNamePointer = L'\0';
+ if (FileName[0] == L'\0') {
+ //
+ // Open root directory.
+ //
+ if (Root == NULL) {
+ //
+ // There is no file found for the root directory yet. So, find only its
+ // FID by now.
+ //
+ // See UdfOpenVolume() function.
+ //
+ Status = InternalFindFile (BlockIo,
+ DiskIo,
+ Volume,
+ L"\\",
+ &PreviousFile,
+ Icb,
+ File);
+ } else {
+ //
+ // We've already a file pointer (Root) for the root directory. Duplicate
+ // its FE/EFE and FID descriptors.
+ //
+ Status = EFI_SUCCESS;
+ DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // File->FileEntry is not NULL.
+ //
+ DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ } else {
+ //
+ // No root directory. Find filename from the current directory.
+ //
+ Status = InternalFindFile (BlockIo,
+ DiskIo,
+ Volume,
+ FileName,
+ &PreviousFile,
+ Icb,
+ File);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If the found file is a symlink, then find its respective FE/EFE and
+ // FID descriptors.
+ //
+ if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
+ FreePool ((VOID *)File->FileIdentifierDesc);
+
+ FileEntry = File->FileEntry;
+
+ Status = ResolveSymlink (BlockIo,
+ DiskIo,
+ Volume,
+ &PreviousFile,
+ FileEntry,
+ File);
+
+ FreePool (FileEntry);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
+ if (*FilePath != L'\0' && *FilePath == L'\\') {
+ FilePath++;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read a directory entry at a time on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] ParentIcb ICB of the parent file.
+ @param[in] FileEntryData FE/EFE of the parent file.
+ @param[in, out] ReadDirInfo Next read directory listing structure
+ information.
+ @param[out] FoundFid File Identifier Descriptor pointer.
+
+ @retval EFI_SUCCESS Directory entry read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ReadDirectoryEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+
+ if (ReadDirInfo->DirectoryData == NULL) {
+ //
+ // The directory's recorded data has not been read yet. So let's cache it
+ // into memory and the next calls won't need to read it again.
+ //
+ ReadFileInfo.Flags = ReadFileAllocateAndRead;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ FileEntryData,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill in ReadDirInfo structure with the read directory's data information.
+ //
+ ReadDirInfo->DirectoryData = ReadFileInfo.FileData;
+ ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
+ }
+
+ do {
+ if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
+ //
+ // There are no longer FIDs for this directory. By returning
+ // EFI_DEVICE_ERROR to the callee will indicate end of directory
+ // listening.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get FID for this entry.
+ //
+ FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,
+ ReadDirInfo->FidOffset);
+ //
+ // Update FidOffset to point to next FID.
+ //
+ ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
+ } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
+
+ DuplicateFid (FileIdentifierDesc, FoundFid);
+ if (*FoundFid == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a filename (encoded in OSTA-compressed format) from a File Identifier
+ Descriptor on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Identifier Descriptor is external input, so this routine will do
+ basic validation for File Identifier Descriptor and report status.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[in] CharMax The maximum number of FileName Unicode char,
+ including terminating null char.
+ @param[out] FileName Decoded filename.
+
+ @retval EFI_SUCCESS Filename decoded and read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
+ decoded filename.
+**/
+EFI_STATUS
+GetFileNameFromFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ IN UINTN CharMax,
+ OUT CHAR16 *FileName
+ )
+{
+ UINT8 *OstaCompressed;
+ UINT8 CompressionId;
+ UINT8 Length;
+ UINTN Index;
+ CHAR16 *FileNameBak;
+
+ if (CharMax == 0) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ OstaCompressed =
+ (UINT8 *)(
+ (UINT8 *)FileIdentifierDesc->Data +
+ FileIdentifierDesc->LengthOfImplementationUse
+ );
+
+ CompressionId = OstaCompressed[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ FileNameBak = FileName;
+
+ //
+ // Decode filename.
+ //
+ Length = FileIdentifierDesc->LengthOfFileIdentifier;
+ if (CompressionId == 16) {
+ if (((UINTN)Length >> 1) > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ for (Index = 1; Index < Length; Index++) {
+ if (CompressionId == 16) {
+ *FileName = OstaCompressed[Index++] << 8;
+ } else {
+ *FileName = 0;
+ }
+
+ if (Index < Length) {
+ *FileName |= (CHAR16)(OstaCompressed[Index]);
+ }
+
+ FileName++;
+ }
+
+ Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
+ if (Index > CharMax - 1) {
+ Index = CharMax - 1;
+ }
+ FileNameBak[Index] = L'\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resolve a symlink file on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Path Component is external input, so this routine will do basic
+ validation for Path Component and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Parent Parent file.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[out] File Resolved file.
+
+ @retval EFI_SUCCESS Symlink file resolved.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ResolveSymlink (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *Parent,
+ IN VOID *FileEntryData,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+ UINT8 *Data;
+ UINT64 Length;
+ UINT8 *EndData;
+ UDF_PATH_COMPONENT *PathComp;
+ UINT8 PathCompLength;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ CHAR16 *Char;
+ UINTN Index;
+ UINT8 CompressionId;
+ UDF_FILE_INFO PreviousFile;
+ BOOLEAN NotParent;
+ BOOLEAN NotFile;
+
+ ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
+
+ //
+ // Symlink files on UDF volumes do not contain so much data other than
+ // Path Components which resolves to real filenames, so it's OK to read in
+ // all its data here -- usually the data will be inline with the FE/EFE for
+ // lower filenames.
+ //
+ ReadFileInfo.Flags = ReadFileAllocateAndRead;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Parent->FileIdentifierDesc->Icb,
+ FileEntryData,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Length = ReadFileInfo.ReadLength;
+
+ Data = (UINT8 *)ReadFileInfo.FileData;
+ EndData = Data + Length;
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
+
+ for (;;) {
+ PathComp = (UDF_PATH_COMPONENT *)Data;
+
+ PathCompLength = PathComp->LengthOfComponentIdentifier;
+
+ switch (PathComp->ComponentType) {
+ case 1:
+ //
+ // This Path Component specifies the root directory hierarchy subject to
+ // agreement between the originator and recipient of the medium. Skip it.
+ //
+ // Fall through.
+ //
+ case 2:
+ //
+ // "\\." of the current directory. Read next Path Component.
+ //
+ goto Next_Path_Component;
+ case 3:
+ //
+ // ".." (parent directory). Go to it.
+ //
+ CopyMem ((VOID *)FileName, L"..", 6);
+ break;
+ case 4:
+ //
+ // "." (current file). Duplicate both FE/EFE and FID of this file.
+ //
+ DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Find_File;
+ }
+
+ DuplicateFid (PreviousFile.FileIdentifierDesc,
+ &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Find_File;
+ }
+ goto Next_Path_Component;
+ case 5:
+ //
+ // This Path Component identifies an object, either a file or a
+ // directory or an alias.
+ //
+ // Decode it from the compressed data in ComponentIdentifier and find
+ // respective path.
+ //
+ CompressionId = PathComp->ComponentIdentifier[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ if ((UINTN)PathComp->ComponentIdentifier + PathCompLength > (UINTN)EndData) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ Char = FileName;
+ for (Index = 1; Index < PathCompLength; Index++) {
+ if (CompressionId == 16) {
+ *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
+ Index) << 8;
+ Index++;
+ } else {
+ if (Index > ARRAY_SIZE (FileName)) {
+ return EFI_UNSUPPORTED;
+ }
+ *Char = 0;
+ }
+
+ if (Index < Length) {
+ *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
+ }
+
+ Char++;
+ }
+
+ Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
+ if (Index > ARRAY_SIZE (FileName) - 1) {
+ Index = ARRAY_SIZE (FileName) - 1;
+ }
+ FileName[Index] = L'\0';
+ break;
+ default:
+ //
+ // According to the ECMA-167 standard (3rd Edition - June 1997), Section
+ // 14.16.1.1, all other values are reserved.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Find_File;
+ }
+
+ //
+ // Find file from the read filename in symlink's file data.
+ //
+ Status = InternalFindFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ FileName,
+ &PreviousFile,
+ NULL,
+ File
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_File;
+ }
+
+ Next_Path_Component:
+ Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
+ if (Data >= EndData) {
+ break;
+ }
+
+ //
+ // Check the content in the file info pointed by File.
+ //
+ if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Find_File;
+ }
+
+ NotParent = (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0);
+ NotFile = (CompareMem ((VOID *)&PreviousFile, (VOID *)File,
+ sizeof (UDF_FILE_INFO)) != 0);
+
+ if (NotParent && NotFile) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ if (NotFile) {
+ CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
+ }
+ }
+
+ //
+ // Unmap the symlink file.
+ //
+ FreePool (ReadFileInfo.FileData);
+
+ //
+ // Check the content in the resolved file info.
+ //
+ if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+
+Error_Find_File:
+ if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ FreePool (ReadFileInfo.FileData);
+
+ return Status;
+}
+
+/**
+ Clean up in-memory UDF file information.
+
+ @param[in] File File information pointer.
+
+**/
+VOID
+CleanupFileInformation (
+ IN UDF_FILE_INFO *File
+ )
+{
+ if (File->FileEntry != NULL) {
+ FreePool (File->FileEntry);
+ }
+ if (File->FileIdentifierDesc != NULL) {
+ FreePool ((VOID *)File->FileIdentifierDesc);
+ }
+
+ ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
+}
+
+/**
+ Find a file from its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[out] Size Size of the file.
+
+ @retval EFI_SUCCESS File size calculated and set in Size.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
+ resources.
+
+**/
+EFI_STATUS
+GetFileSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ OUT UINT64 *Size
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+
+ ReadFileInfo.Flags = ReadFileGetFileSize;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &File->FileIdentifierDesc->Icb,
+ File->FileEntry,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Size = ReadFileInfo.ReadLength;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set information about a file on an UDF volume.
+
+ @param[in] File File pointer.
+ @param[in] FileSize Size of the file.
+ @param[in] FileName Filename of the file.
+ @param[in, out] BufferSize Size of the returned file infomation.
+ @param[out] Buffer Data of the returned file information.
+
+ @retval EFI_SUCCESS File information set.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
+ resources.
+
+**/
+EFI_STATUS
+SetFileInfo (
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN FileInfoLength;
+ EFI_FILE_INFO *FileInfo;
+ UDF_FILE_ENTRY *FileEntry;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ //
+ // Calculate the needed size for the EFI_FILE_INFO structure.
+ //
+ FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
+ StrSize (FileName) :
+ sizeof (CHAR16));
+ if (*BufferSize < FileInfoLength) {
+ //
+ // The given Buffer has no size enough for EFI_FILE_INFO structure.
+ //
+ *BufferSize = FileInfoLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Buffer now contains room enough to store EFI_FILE_INFO structure.
+ // Now, fill it in with all necessary information about the file.
+ //
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = FileInfoLength;
+ FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+
+ if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_ARCHIVE;
+ }
+
+ if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_HIDDEN;
+ }
+
+ DescriptorTag = File->FileEntry;
+
+ if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
+
+ //
+ // Check if FE has the system attribute set.
+ //
+ if (FileEntry->IcbTag.Flags & (1 << 10)) {
+ FileInfo->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ FileInfo->FileSize = FileSize;
+ FileInfo->PhysicalSize = FileSize;
+
+ FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;
+ FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;
+ FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;
+ FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;
+ FileInfo->CreateTime.Minute = FileEntry->AccessTime.Minute;
+ FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;
+ FileInfo->CreateTime.Nanosecond =
+ FileEntry->AccessTime.HundredsOfMicroseconds;
+
+ FileInfo->LastAccessTime.Year =
+ FileEntry->AccessTime.Year;
+ FileInfo->LastAccessTime.Month =
+ FileEntry->AccessTime.Month;
+ FileInfo->LastAccessTime.Day =
+ FileEntry->AccessTime.Day;
+ FileInfo->LastAccessTime.Hour =
+ FileEntry->AccessTime.Hour;
+ FileInfo->LastAccessTime.Minute =
+ FileEntry->AccessTime.Minute;
+ FileInfo->LastAccessTime.Second =
+ FileEntry->AccessTime.Second;
+ FileInfo->LastAccessTime.Nanosecond =
+ FileEntry->AccessTime.HundredsOfMicroseconds;
+ } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
+
+ //
+ // Check if EFE has the system attribute set.
+ //
+ if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
+ FileInfo->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ FileInfo->FileSize = FileSize;
+ FileInfo->PhysicalSize = FileSize;
+
+ FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;
+ FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;
+ FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;
+ FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;
+ FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;
+ FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;
+ FileInfo->CreateTime.Nanosecond =
+ ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
+
+ FileInfo->LastAccessTime.Year =
+ ExtendedFileEntry->AccessTime.Year;
+ FileInfo->LastAccessTime.Month =
+ ExtendedFileEntry->AccessTime.Month;
+ FileInfo->LastAccessTime.Day =
+ ExtendedFileEntry->AccessTime.Day;
+ FileInfo->LastAccessTime.Hour =
+ ExtendedFileEntry->AccessTime.Hour;
+ FileInfo->LastAccessTime.Minute =
+ ExtendedFileEntry->AccessTime.Minute;
+ FileInfo->LastAccessTime.Second =
+ ExtendedFileEntry->AccessTime.Second;
+ FileInfo->LastAccessTime.Nanosecond =
+ ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
+ }
+
+ FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+ FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+
+ CopyMem ((VOID *)&FileInfo->ModificationTime,
+ (VOID *)&FileInfo->LastAccessTime,
+ sizeof (EFI_TIME));
+
+ if (FileName != NULL) {
+ StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
+ } else {
+ FileInfo->FileName[0] = '\0';
+ }
+
+ *BufferSize = FileInfoLength;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get volume label of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] CharMax The maximum number of Unicode char in String,
+ including terminating null char.
+ @param[out] String String buffer pointer to store the volume label.
+
+ @retval EFI_SUCCESS Volume label is returned.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
+ volume label.
+
+**/
+EFI_STATUS
+GetVolumeLabel (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UINTN CharMax,
+ OUT CHAR16 *String
+ )
+{
+ UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
+ UINTN Index;
+ UINT8 *OstaCompressed;
+ UINT8 CompressionId;
+ CHAR16 *StringBak;
+
+ FileSetDesc = &Volume->FileSetDesc;
+
+ OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
+
+ CompressionId = OstaCompressed[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ StringBak = String;
+ for (Index = 1; Index < 128; Index++) {
+ if (CompressionId == 16) {
+ if ((Index >> 1) > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *String = *(UINT8 *)(OstaCompressed + Index) << 8;
+ Index++;
+ } else {
+ if (Index > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *String = 0;
+ }
+
+ if (Index < 128) {
+ *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
+ }
+
+ //
+ // Unlike FID Identifiers, Logical Volume Identifier is stored in a
+ // NULL-terminated OSTA compressed format, so we must check for the NULL
+ // character.
+ //
+ if (*String == L'\0') {
+ break;
+ }
+
+ String++;
+ }
+
+ Index = ((UINTN)String - (UINTN)StringBak) / sizeof (CHAR16);
+ if (Index > CharMax - 1) {
+ Index = CharMax - 1;
+ }
+ StringBak[Index] = L'\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get volume and free space size information of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
+ external inputs, so this routine will do basic validation for both descriptors
+ and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] VolumeSize Volume size.
+ @param[out] FreeSpaceSize Free space size.
+
+ @retval EFI_SUCCESS Volume and free space size calculated.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
+ calculated due to lack of resources.
+
+**/
+EFI_STATUS
+GetVolumeSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UINT64 *VolumeSize,
+ OUT UINT64 *FreeSpaceSize
+ )
+{
+ EFI_STATUS Status;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 Lsn;
+ UINT32 LogicalBlockSize;
+ UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN Index;
+ UINTN Length;
+ UINT32 LsnsNo;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+
+ ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
+
+ if ((ExtentAd->ExtentLength == 0) ||
+ (ExtentAd->ExtentLength < sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
+ if (LogicalVolInt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get location of Logical Volume Integrity Descriptor
+ //
+ Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
+
+ LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
+
+ //
+ // Read disk block
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentAd->ExtentLength,
+ LogicalVolInt
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = &LogicalVolInt->DescriptorTag;
+
+ //
+ // Check if read block is a Logical Volume Integrity Descriptor
+ //
+ if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+
+ if ((LogicalVolInt->NumberOfPartitions > MAX_UINT32 / sizeof (UINT32) / 2) ||
+ (LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2 >
+ ExtentAd->ExtentLength - sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+
+ *VolumeSize = 0;
+ *FreeSpaceSize = 0;
+
+ Length = LogicalVolInt->NumberOfPartitions;
+ for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
+ LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
+ //
+ // Check if size is not specified
+ //
+ if (LsnsNo == 0xFFFFFFFFUL) {
+ continue;
+ }
+ //
+ // Accumulate free space size
+ //
+ *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
+ }
+
+ Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
+ for (; Index < Length; Index += sizeof (UINT32)) {
+ LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
+ //
+ // Check if size is not specified
+ //
+ if (LsnsNo == 0xFFFFFFFFUL) {
+ continue;
+ }
+ //
+ // Accumulate used volume space
+ //
+ *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
+ }
+
+ Status = EFI_SUCCESS;
+
+Out_Free:
+ //
+ // Free Logical Volume Integrity Descriptor
+ //
+ FreePool (LogicalVolInt);
+
+ return Status;
+}
+
+/**
+ Seek a file and read its data into memory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[in] FileSize Size of the file.
+ @param[in, out] FilePosition File position.
+ @param[in, out] Buffer File data.
+ @param[in, out] BufferSize Read size.
+
+ @retval EFI_SUCCESS File seeked and read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
+ of resources.
+
+**/
+EFI_STATUS
+ReadFileData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN OUT UINT64 *FilePosition,
+ IN OUT VOID *Buffer,
+ IN OUT UINT64 *BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+
+ ReadFileInfo.Flags = ReadFileSeekAndRead;
+ ReadFileInfo.FilePosition = *FilePosition;
+ ReadFileInfo.FileData = Buffer;
+ ReadFileInfo.FileDataSize = *BufferSize;
+ ReadFileInfo.FileSize = FileSize;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &File->FileIdentifierDesc->Icb,
+ File->FileEntry,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *BufferSize = ReadFileInfo.FileDataSize;
+ *FilePosition = ReadFileInfo.FilePosition;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if ControllerHandle supports an UDF file system.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval EFI_SUCCESS UDF file system found.
+ @retval EFI_UNSUPPORTED UDF file system not found.
+
+**/
+EFI_STATUS
+SupportUdfFileSystem (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
+ EFI_GUID *VendorDefinedGuid;
+
+ //
+ // Open Device Path protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Get last Device Path node
+ //
+ LastDevicePathNode = NULL;
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ LastDevicePathNode = DevicePathNode;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ //
+ // Check if last Device Path node contains a Vendor-Defined Media Device Path
+ // of an UDF file system.
+ //
+ if (LastDevicePathNode != NULL &&
+ DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {
+ VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
+ OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
+ if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Close Device Path protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c
new file mode 100644
index 000000000..d15f44971
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c
@@ -0,0 +1,331 @@
+/** @file
+ UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// UDF filesystem driver's Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding = {
+ UdfDriverBindingSupported,
+ UdfDriverBindingStart,
+ UdfDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gUdfSimpleFsTemplate = {
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+ UdfOpenVolume
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] 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
+UdfDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+
+ //
+ // Open DiskIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Test whether ControllerHandle supports BlockIo protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] 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
+UdfDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Open BlockIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open DiskIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check if ControllerHandle supports an UDF file system
+ //
+ Status = SupportUdfFileSystem (This, ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Initialize private file system structure
+ //
+ PrivFsData =
+ (PRIVATE_UDF_SIMPLE_FS_DATA *)
+ AllocateZeroPool (sizeof (PRIVATE_UDF_SIMPLE_FS_DATA));
+ if (PrivFsData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Create new child handle
+ //
+ PrivFsData->Signature = PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE;
+ PrivFsData->BlockIo = BlockIo;
+ PrivFsData->DiskIo = DiskIo;
+ PrivFsData->Handle = ControllerHandle;
+
+ //
+ // Set up SimpleFs protocol
+ //
+ CopyMem ((VOID *)&PrivFsData->SimpleFs, (VOID *)&gUdfSimpleFsTemplate,
+ sizeof (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL));
+
+ //
+ // Install child handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PrivFsData->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &PrivFsData->SimpleFs,
+ NULL
+ );
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close BlockIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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
+UdfDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+
+ //
+ // Open SimpleFs protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **)&SimpleFs,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (SimpleFs);
+
+ //
+ // Uninstall child handle
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ PrivFsData->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &PrivFsData->SimpleFs,
+ NULL
+ );
+
+ FreePool ((VOID *)PrivFsData);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close BlockIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ return Status;
+}
+
+/**
+ The user Entry Point for UDF file system driver. 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
+InitializeUdf (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUdfDriverBinding,
+ ImageHandle,
+ &gUdfComponentName,
+ &gUdfComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
new file mode 100644
index 000000000..6c623a904
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
@@ -0,0 +1,1215 @@
+/** @file
+ UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _UDF_H_
+#define _UDF_H_
+
+#include <Uefi.h>
+#include <Base.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.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/DevicePathLib.h>
+
+#include <IndustryStandard/ElTorito.h>
+#include <IndustryStandard/Udf.h>
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID \
+ { 0xC5BD4D42, 0x1A76, 0x4996, \
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
+ }
+
+#define FE_ICB_FILE_TYPE(_Ptr) \
+ (UDF_FILE_ENTRY_TYPE)( \
+ ((UDF_DESCRIPTOR_TAG *)(_Ptr))->TagIdentifier == UdfFileEntry ? \
+ ((UDF_FILE_ENTRY *)(_Ptr))->IcbTag.FileType : \
+ ((UDF_EXTENDED_FILE_ENTRY *)(_Ptr))->IcbTag.FileType)
+
+typedef enum {
+ UdfFileEntryDirectory = 4,
+ UdfFileEntryStandardFile = 5,
+ UdfFileEntrySymlink = 12,
+} UDF_FILE_ENTRY_TYPE;
+
+#define HIDDEN_FILE (1 << 0)
+#define DIRECTORY_FILE (1 << 1)
+#define DELETED_FILE (1 << 2)
+#define PARENT_FILE (1 << 3)
+
+#define IS_FID_HIDDEN_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & HIDDEN_FILE)
+#define IS_FID_DIRECTORY_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & DIRECTORY_FILE)
+#define IS_FID_DELETED_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & DELETED_FILE)
+#define IS_FID_PARENT_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & PARENT_FILE)
+#define IS_FID_NORMAL_FILE(_Fid) \
+ (BOOLEAN)(!IS_FID_DIRECTORY_FILE (_Fid) && \
+ !IS_FID_PARENT_FILE (_Fid))
+
+typedef enum {
+ ShortAdsSequence,
+ LongAdsSequence,
+ ExtendedAdsSequence,
+ InlineData
+} UDF_FE_RECORDING_FLAGS;
+
+#define GET_FE_RECORDING_FLAGS(_Fe) \
+ ((UDF_FE_RECORDING_FLAGS)((UDF_ICB_TAG *)( \
+ (UINT8 *)(_Fe) + \
+ sizeof (UDF_DESCRIPTOR_TAG)))->Flags & 0x07)
+
+typedef enum {
+ ExtentRecordedAndAllocated,
+ ExtentNotRecordedButAllocated,
+ ExtentNotRecordedNotAllocated,
+ ExtentIsNextExtent,
+} UDF_EXTENT_FLAGS;
+
+#define AD_LENGTH(_RecFlags) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UINT64)(sizeof (UDF_SHORT_ALLOCATION_DESCRIPTOR))) : \
+ ((UINT64)(sizeof (UDF_LONG_ALLOCATION_DESCRIPTOR))))
+
+#define GET_EXTENT_FLAGS(_RecFlags, _Ad) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UDF_EXTENT_FLAGS)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \
+ 30) & 0x3)) : \
+ ((UDF_EXTENT_FLAGS)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \
+ 30) & 0x3)))
+
+#define GET_EXTENT_LENGTH(_RecFlags, _Ad) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UINT32)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \
+ ~0xC0000000UL))) : \
+ ((UINT32)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \
+ ~0xC0000000UL))))
+
+#define UDF_FILENAME_LENGTH 128
+#define UDF_PATH_LENGTH 512
+
+#define GET_FID_FROM_ADS(_Data, _Offs) \
+ ((UDF_FILE_IDENTIFIER_DESCRIPTOR *)((UINT8 *)(_Data) + (_Offs)))
+
+#define IS_VALID_COMPRESSION_ID(_CompId) \
+ ((BOOLEAN)((_CompId) == 8 || (_CompId) == 16))
+
+#define UDF_STANDARD_IDENTIFIER_LENGTH 5
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];
+} UDF_STANDARD_IDENTIFIER;
+
+#pragma pack()
+
+typedef enum {
+ ReadFileGetFileSize,
+ ReadFileAllocateAndRead,
+ ReadFileSeekAndRead,
+} UDF_READ_FILE_FLAGS;
+
+typedef struct {
+ VOID *FileData;
+ UDF_READ_FILE_FLAGS Flags;
+ UINT64 FileDataSize;
+ UINT64 FilePosition;
+ UINT64 FileSize;
+ UINT64 ReadLength;
+} UDF_READ_FILE_INFO;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 TypeAndTimezone;
+ INT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Centiseconds;
+ UINT8 HundredsOfMicroseconds;
+ UINT8 Microseconds;
+} UDF_TIMESTAMP;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT32 PrevAllocationExtentDescriptor;
+ UINT32 LengthOfAllocationDescriptors;
+} UDF_ALLOCATION_EXTENT_DESCRIPTOR;
+
+typedef struct {
+ UINT8 StructureType;
+ UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];
+ UINT8 StructureVersion;
+ UINT8 Reserved;
+ UINT8 StructureData[2040];
+} UDF_VOLUME_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_TIMESTAMP RecordingDateTime;
+ UINT32 IntegrityType;
+ UDF_EXTENT_AD NextIntegrityExtent;
+ UINT8 LogicalVolumeContentsUse[32];
+ UINT32 NumberOfPartitions;
+ UINT32 LengthOfImplementationUse;
+ UINT8 Data[0];
+} UDF_LOGICAL_VOLUME_INTEGRITY;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT32 VolumeDescriptorSequenceNumber;
+ UINT16 PartitionFlags;
+ UINT16 PartitionNumber;
+ UDF_ENTITY_ID PartitionContents;
+ UINT8 PartitionContentsUse[128];
+ UINT32 AccessType;
+ UINT32 PartitionStartingLocation;
+ UINT32 PartitionLength;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT8 ImplementationUse[128];
+ UINT8 Reserved[156];
+} UDF_PARTITION_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_TIMESTAMP RecordingDateAndTime;
+ UINT16 InterchangeLevel;
+ UINT16 MaximumInterchangeLevel;
+ UINT32 CharacterSetList;
+ UINT32 MaximumCharacterSetList;
+ UINT32 FileSetNumber;
+ UINT32 FileSetDescriptorNumber;
+ UDF_CHAR_SPEC LogicalVolumeIdentifierCharacterSet;
+ UINT8 LogicalVolumeIdentifier[128];
+ UDF_CHAR_SPEC FileSetCharacterSet;
+ UINT8 FileSetIdentifier[32];
+ UINT8 CopyrightFileIdentifier[32];
+ UINT8 AbstractFileIdentifier[32];
+ UDF_LONG_ALLOCATION_DESCRIPTOR RootDirectoryIcb;
+ UDF_ENTITY_ID DomainIdentifier;
+ UDF_LONG_ALLOCATION_DESCRIPTOR NextExtent;
+ UDF_LONG_ALLOCATION_DESCRIPTOR SystemStreamDirectoryIcb;
+ UINT8 Reserved[32];
+} UDF_FILE_SET_DESCRIPTOR;
+
+typedef struct {
+ UINT32 ExtentLength;
+ UINT32 ExtentPosition;
+} UDF_SHORT_ALLOCATION_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT16 FileVersionNumber;
+ UINT8 FileCharacteristics;
+ UINT8 LengthOfFileIdentifier;
+ UDF_LONG_ALLOCATION_DESCRIPTOR Icb;
+ UINT16 LengthOfImplementationUse;
+ UINT8 Data[0];
+} UDF_FILE_IDENTIFIER_DESCRIPTOR;
+
+typedef struct {
+ UINT32 PriorRecordNumberOfDirectEntries;
+ UINT16 StrategyType;
+ UINT16 StrategyParameter;
+ UINT16 MaximumNumberOfEntries;
+ UINT8 Reserved;
+ UINT8 FileType;
+ UDF_LB_ADDR ParentIcbLocation;
+ UINT16 Flags;
+} UDF_ICB_TAG;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_ICB_TAG IcbTag;
+ UINT32 Uid;
+ UINT32 Gid;
+ UINT32 Permissions;
+ UINT16 FileLinkCount;
+ UINT8 RecordFormat;
+ UINT8 RecordDisplayAttributes;
+ UINT32 RecordLength;
+ UINT64 InformationLength;
+ UINT64 LogicalBlocksRecorded;
+ UDF_TIMESTAMP AccessTime;
+ UDF_TIMESTAMP ModificationTime;
+ UDF_TIMESTAMP AttributeTime;
+ UINT32 CheckPoint;
+ UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT64 UniqueId;
+ UINT32 LengthOfExtendedAttributes;
+ UINT32 LengthOfAllocationDescriptors;
+ UINT8 Data[0]; // L_EA + L_AD
+} UDF_FILE_ENTRY;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_ICB_TAG IcbTag;
+ UINT32 Uid;
+ UINT32 Gid;
+ UINT32 Permissions;
+ UINT16 FileLinkCount;
+ UINT8 RecordFormat;
+ UINT8 RecordDisplayAttributes;
+ UINT32 RecordLength;
+ UINT64 InformationLength;
+ UINT64 ObjectSize;
+ UINT64 LogicalBlocksRecorded;
+ UDF_TIMESTAMP AccessTime;
+ UDF_TIMESTAMP ModificationTime;
+ UDF_TIMESTAMP CreationTime;
+ UDF_TIMESTAMP AttributeTime;
+ UINT32 CheckPoint;
+ UINT32 Reserved;
+ UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb;
+ UDF_LONG_ALLOCATION_DESCRIPTOR StreamDirectoryIcb;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT64 UniqueId;
+ UINT32 LengthOfExtendedAttributes;
+ UINT32 LengthOfAllocationDescriptors;
+ UINT8 Data[0]; // L_EA + L_AD
+} UDF_EXTENDED_FILE_ENTRY;
+
+typedef struct {
+ UINT8 ComponentType;
+ UINT8 LengthOfComponentIdentifier;
+ UINT16 ComponentFileVersionNumber;
+ UINT8 ComponentIdentifier[0];
+} UDF_PATH_COMPONENT;
+
+#pragma pack()
+
+//
+// UDF filesystem driver's private data
+//
+typedef struct {
+ UINT64 MainVdsStartLocation;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR LogicalVolDesc;
+ UDF_PARTITION_DESCRIPTOR PartitionDesc;
+ UDF_FILE_SET_DESCRIPTOR FileSetDesc;
+ UINTN FileEntrySize;
+} UDF_VOLUME_INFO;
+
+typedef struct {
+ VOID *FileEntry;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+} UDF_FILE_INFO;
+
+typedef struct {
+ VOID *DirectoryData;
+ UINT64 DirectoryLength;
+ UINT64 FidOffset;
+} UDF_READ_DIRECTORY_INFO;
+
+#define PRIVATE_UDF_FILE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 'f')
+
+#define PRIVATE_UDF_FILE_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ PRIVATE_UDF_FILE_DATA, \
+ FileIo, \
+ PRIVATE_UDF_FILE_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINTN Signature;
+ BOOLEAN IsRootDirectory;
+ UDF_FILE_INFO *Root;
+ UDF_FILE_INFO File;
+ UDF_READ_DIRECTORY_INFO ReadDirInfo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+ EFI_FILE_PROTOCOL FileIo;
+ CHAR16 AbsoluteFileName[UDF_PATH_LENGTH];
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ UINT64 FileSize;
+ UINT64 FilePosition;
+} PRIVATE_UDF_FILE_DATA;
+
+#define PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 's')
+
+#define PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ PRIVATE_UDF_SIMPLE_FS_DATA, \
+ SimpleFs, \
+ PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINTN Signature;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs;
+ UDF_VOLUME_INFO Volume;
+ UDF_FILE_INFO Root;
+ UINTN OpenFiles;
+ EFI_HANDLE Handle;
+} PRIVATE_UDF_SIMPLE_FS_DATA;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2;
+
+//
+// Function Prototypes
+//
+
+/**
+ Open the root directory on a volume.
+
+ @param This Protocol instance pointer.
+ @param Root Returns an Open file handle for the root directory
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the file system.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ );
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This The protocol instance pointer.
+ @param NewHandle Returns File Handle for FileName.
+ @param FileName Null terminated string. "\", ".", and ".." are supported.
+ @param OpenMode Open mode for file.
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Close the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfClose (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
+ deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDelete (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Write data to a file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Get file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for directories is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ );
+
+/**
+ Set file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ );
+
+/**
+ Get information about a file.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
+ BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Set information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was set.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was flushed.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfFlush (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Read volume information on a medium which contains a valid UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS Volume information read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
+
+**/
+EFI_STATUS
+ReadUdfVolumeInformation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ );
+
+/**
+ Find the root directory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] File Root directory file.
+
+ @retval EFI_SUCCESS Root directory found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindRootDirectory (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Find either a File Entry or a Extended File Entry from a given ICB.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Icb ICB of the FID.
+ @param[out] FileEntry File Entry or Extended File Entry.
+
+ @retval EFI_SUCCESS File Entry or Extended File Entry found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFileEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT VOID **FileEntry
+ );
+
+/**
+ Find a file given its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] FilePath File's absolute path.
+ @param[in] Root Root directory file.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb ICB of Parent.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS FilePath was found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FilePath,
+ IN UDF_FILE_INFO *Root,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Read a directory entry at a time on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] ParentIcb ICB of the parent file.
+ @param[in] FileEntryData FE/EFE of the parent file.
+ @param[in, out] ReadDirInfo Next read directory listing structure
+ information.
+ @param[out] FoundFid File Identifier Descriptor pointer.
+
+ @retval EFI_SUCCESS Directory entry read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ReadDirectoryEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
+ );
+
+/**
+ Get a filename (encoded in OSTA-compressed format) from a File Identifier
+ Descriptor on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Identifier Descriptor is external input, so this routine will do
+ basic validation for File Identifier Descriptor and report status.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[in] CharMax The maximum number of FileName Unicode char,
+ including terminating null char.
+ @param[out] FileName Decoded filename.
+
+ @retval EFI_SUCCESS Filename decoded and read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
+ decoded filename.
+**/
+EFI_STATUS
+GetFileNameFromFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ IN UINTN CharMax,
+ OUT CHAR16 *FileName
+ );
+
+/**
+ Resolve a symlink file on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Path Component is external input, so this routine will do basic
+ validation for Path Component and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Parent Parent file.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[out] File Resolved file.
+
+ @retval EFI_SUCCESS Symlink file resolved.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ResolveSymlink (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *Parent,
+ IN VOID *FileEntryData,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Clean up in-memory UDF file information.
+
+ @param[in] File File information pointer.
+
+**/
+VOID
+CleanupFileInformation (
+ IN UDF_FILE_INFO *File
+ );
+
+/**
+ Find a file from its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[out] Size Size of the file.
+
+ @retval EFI_SUCCESS File size calculated and set in Size.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
+ resources.
+
+**/
+EFI_STATUS
+GetFileSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ OUT UINT64 *Size
+ );
+
+/**
+ Set information about a file on an UDF volume.
+
+ @param[in] File File pointer.
+ @param[in] FileSize Size of the file.
+ @param[in] FileName Filename of the file.
+ @param[in, out] BufferSize Size of the returned file infomation.
+ @param[out] Buffer Data of the returned file information.
+
+ @retval EFI_SUCCESS File information set.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
+ resources.
+
+**/
+EFI_STATUS
+SetFileInfo (
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Get volume label of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] CharMax The maximum number of Unicode char in String,
+ including terminating null char.
+ @param[out] String String buffer pointer to store the volume label.
+
+ @retval EFI_SUCCESS Volume label is returned.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
+ volume label.
+
+**/
+EFI_STATUS
+GetVolumeLabel (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UINTN CharMax,
+ OUT CHAR16 *String
+ );
+
+/**
+ Get volume and free space size information of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
+ external inputs, so this routine will do basic validation for both descriptors
+ and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] VolumeSize Volume size.
+ @param[out] FreeSpaceSize Free space size.
+
+ @retval EFI_SUCCESS Volume and free space size calculated.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
+ calculated due to lack of resources.
+
+**/
+EFI_STATUS
+GetVolumeSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UINT64 *VolumeSize,
+ OUT UINT64 *FreeSpaceSize
+ );
+
+/**
+ Seek a file and read its data into memory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[in] FileSize Size of the file.
+ @param[in, out] FilePosition File position.
+ @param[in, out] Buffer File data.
+ @param[in, out] BufferSize Read size.
+
+ @retval EFI_SUCCESS File seeked and read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
+ of resources.
+
+**/
+EFI_STATUS
+ReadFileData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN OUT UINT64 *FilePosition,
+ IN OUT VOID *Buffer,
+ IN OUT UINT64 *BufferSize
+ );
+
+/**
+ Check if ControllerHandle supports an UDF file system.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval EFI_SUCCESS UDF file system found.
+ @retval EFI_UNSUPPORTED UDF file system not found.
+
+**/
+EFI_STATUS
+SupportUdfFileSystem (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
+
+ @param[in] FileName Filename.
+
+ @retval The mangled Filename.
+
+**/
+CHAR16 *
+MangleFileName (
+ IN CHAR16 *FileName
+ );
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo 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
+UdfDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path, and creating a child handle with a
+ Disk IO and device path protocol.
+
+ @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
+UdfDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping 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
+UdfDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ 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
+UdfComponentNameGetDriverName (
+ 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 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 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
+UdfComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif // _UDF_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
new file mode 100644
index 000000000..16c411b6b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# UDF/ECMA-167 file system driver.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UdfDxe
+ FILE_GUID = 905f13b0-8f91-4b0a-bd76-e1e78f9422e4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUdf
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUdfDriverBinding
+# COMPONENT_NAME = gUdfComponentName
+# COMPONENT_NAME2 = gUdfComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ FileSystemOperations.c
+ FileName.c
+ File.c
+ Udf.c
+ Udf.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## Protocol
+ gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## Protocol
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## Protocol
+
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## TO_START
+ gEfiDiskIoProtocolGuid ## TO_START
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
new file mode 100644
index 000000000..f97ffdbcd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# English module that provides Unicode Collation supports.
+#
+# This driver installs Unicode ISO 639-2 Collation and
+# RFC 4646 Unicode Collation 2 protocols based on feature flags
+# PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively.
+# It allows code running in the boot services environment to perform lexical
+# comparison functions on Unicode strings for English languages.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EnglishDxe
+ MODULE_UNI_FILE = EnglishDxe.uni
+ FILE_GUID = CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUnicodeCollationEng
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UnicodeCollationEng.c
+ UnicodeCollationEng.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollationSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollation2Support ## CONSUMES
+
+[Protocols]
+ gEfiUnicodeCollationProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollationSupport ## SOMETIMES_PRODUCES
+ gEfiUnicodeCollation2ProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollation2Support ## PRODUCES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EnglishDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni
new file mode 100644
index 000000000..400d5185b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// English module that provides Unicode Collation supports.
+//
+// This driver installs Unicode ISO 639-2 Collation and
+// RFC 4646 Unicode Collation 2 protocols based on feature flags
+// PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively.
+// It allows code running in the boot services environment to perform lexical
+// comparison functions on Unicode strings for English languages.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides Unicode Collation support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver installs Unicode ISO 639-2 Collation and RFC 4646 Unicode Collation 2 protocols based on feature flags PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively. It allows code running in the boot services environment to perform lexical comparison functions on Unicode strings for English languages."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni
new file mode 100644
index 000000000..ec4e8f586
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EnglishDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"English Language Support"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c
new file mode 100644
index 000000000..b959cb1e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c
@@ -0,0 +1,467 @@
+/** @file
+ Driver to implement English version of Unicode Collation Protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "UnicodeCollationEng.h"
+
+CHAR8 mEngUpperMap[MAP_TABLE_SIZE];
+CHAR8 mEngLowerMap[MAP_TABLE_SIZE];
+CHAR8 mEngInfoMap[MAP_TABLE_SIZE];
+
+CHAR8 mOtherChars[] = {
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '\\',
+ '.',
+ '_',
+ '^',
+ '$',
+ '~',
+ '!',
+ '#',
+ '%',
+ '&',
+ '-',
+ '{',
+ '}',
+ '(',
+ ')',
+ '@',
+ '`',
+ '\'',
+ '\0'
+};
+
+EFI_HANDLE mHandle = NULL;
+
+//
+// EFI Unicode Collation Protocol supporting ISO 639-2 language code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL UnicodeEng = {
+ EngStriColl,
+ EngMetaiMatch,
+ EngStrLwr,
+ EngStrUpr,
+ EngFatToStr,
+ EngStrToFat,
+ "eng"
+};
+
+//
+// EFI Unicode Collation2 Protocol supporting RFC 4646 language code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL Unicode2Eng = {
+ EngStriColl,
+ EngMetaiMatch,
+ EngStrLwr,
+ EngStrUpr,
+ EngFatToStr,
+ EngStrToFat,
+ "en"
+};
+
+/**
+ The user Entry Point for English module.
+
+ This function initializes unicode character mapping and then installs Unicode
+ Collation & Unicode Collation 2 Protocols based on the feature flags.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUnicodeCollationEng (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ //
+ // Initialize mapping tables for the supported languages
+ //
+ for (Index = 0; Index < MAP_TABLE_SIZE; Index++) {
+ mEngUpperMap[Index] = (CHAR8) Index;
+ mEngLowerMap[Index] = (CHAR8) Index;
+ mEngInfoMap[Index] = 0;
+
+ if ((Index >= 'a' && Index <= 'z') || (Index >= 0xe0 && Index <= 0xf6) || (Index >= 0xf8 && Index <= 0xfe)) {
+
+ Index2 = Index - 0x20;
+ mEngUpperMap[Index] = (CHAR8) Index2;
+ mEngLowerMap[Index2] = (CHAR8) Index;
+
+ mEngInfoMap[Index] |= CHAR_FAT_VALID;
+ mEngInfoMap[Index2] |= CHAR_FAT_VALID;
+ }
+ }
+
+ for (Index = 0; mOtherChars[Index] != 0; Index++) {
+ Index2 = mOtherChars[Index];
+ mEngInfoMap[Index2] |= CHAR_FAT_VALID;
+ }
+
+ if (FeaturePcdGet (PcdUnicodeCollation2Support)) {
+ if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollationProtocolGuid,
+ &UnicodeEng,
+ &gEfiUnicodeCollation2ProtocolGuid,
+ &Unicode2Eng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollation2ProtocolGuid,
+ &Unicode2Eng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollationProtocolGuid,
+ &UnicodeEng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // This module must support to produce at least one of Unicode Collation Protocol
+ // and Unicode Collation 2 Protocol.
+ //
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Performs a case-insensitive comparison of two Null-terminated strings.
+
+ @param This Protocol instance pointer.
+ @param Str1 A pointer to a Null-terminated string.
+ @param Str2 A pointer to a Null-terminated string.
+
+ @retval 0 Str1 is equivalent to Str2
+ @retval > 0 Str1 is lexically greater than Str2
+ @retval < 0 Str1 is lexically less than Str2
+
+**/
+INTN
+EFIAPI
+EngStriColl (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+{
+ while (*Str1 != 0) {
+ if (TO_UPPER (*Str1) != TO_UPPER (*Str2)) {
+ break;
+ }
+
+ Str1 += 1;
+ Str2 += 1;
+ }
+
+ return TO_UPPER (*Str1) - TO_UPPER (*Str2);
+}
+
+
+/**
+ Converts all the characters in a Null-terminated string to
+ lower case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrLwr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ )
+{
+ while (*Str != 0) {
+ *Str = TO_LOWER (*Str);
+ Str += 1;
+ }
+}
+
+
+/**
+ Converts all the characters in a Null-terminated string to upper
+ case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrUpr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ )
+{
+ while (*Str != 0) {
+ *Str = TO_UPPER (*Str);
+ Str += 1;
+ }
+}
+
+/**
+ Performs a case-insensitive comparison of a Null-terminated
+ pattern string and a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string.
+ @param Pattern A pointer to a Null-terminated pattern string.
+
+ @retval TRUE Pattern was found in String.
+ @retval FALSE Pattern was not found in String.
+
+**/
+BOOLEAN
+EFIAPI
+EngMetaiMatch (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ )
+{
+ CHAR16 CharC;
+ CHAR16 CharP;
+ CHAR16 Index3;
+
+ for (;;) {
+ CharP = *Pattern;
+ Pattern += 1;
+
+ switch (CharP) {
+ case 0:
+ //
+ // End of pattern. If end of string, TRUE match
+ //
+ if (*String != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+ case '*':
+ //
+ // Match zero or more chars
+ //
+ while (*String != 0) {
+ if (EngMetaiMatch (This, String, Pattern)) {
+ return TRUE;
+ }
+
+ String += 1;
+ }
+
+ return EngMetaiMatch (This, String, Pattern);
+
+ case '?':
+ //
+ // Match any one char
+ //
+ if (*String == 0) {
+ return FALSE;
+ }
+
+ String += 1;
+ break;
+
+ case '[':
+ //
+ // Match char set
+ //
+ CharC = *String;
+ if (CharC == 0) {
+ //
+ // syntax problem
+ //
+ return FALSE;
+ }
+
+ Index3 = 0;
+ CharP = *Pattern++;
+ while (CharP != 0) {
+ if (CharP == ']') {
+ return FALSE;
+ }
+
+ if (CharP == '-') {
+ //
+ // if range of chars, get high range
+ //
+ CharP = *Pattern;
+ if (CharP == 0 || CharP == ']') {
+ //
+ // syntax problem
+ //
+ return FALSE;
+ }
+
+ if (TO_UPPER (CharC) >= TO_UPPER (Index3) && TO_UPPER (CharC) <= TO_UPPER (CharP)) {
+ //
+ // if in range, it's a match
+ //
+ break;
+ }
+ }
+
+ Index3 = CharP;
+ if (TO_UPPER (CharC) == TO_UPPER (CharP)) {
+ //
+ // if char matches
+ //
+ break;
+ }
+
+ CharP = *Pattern++;
+ }
+ //
+ // skip to end of match char set
+ //
+ while ((CharP != 0) && (CharP != ']')) {
+ CharP = *Pattern;
+ Pattern += 1;
+ }
+
+ String += 1;
+ break;
+
+ default:
+ CharC = *String;
+ if (TO_UPPER (CharC) != TO_UPPER (CharP)) {
+ return FALSE;
+ }
+
+ String += 1;
+ break;
+ }
+ }
+}
+
+
+/**
+ Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an 8-bit OEM character set.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+
+**/
+VOID
+EFIAPI
+EngFatToStr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ )
+{
+ //
+ // No DBCS issues, just expand and add null terminate to end of string
+ //
+ while ((*Fat != 0) && (FatSize != 0)) {
+ *String = *Fat;
+ String += 1;
+ Fat += 1;
+ FatSize -= 1;
+ }
+
+ *String = 0;
+}
+
+
+/**
+ Converts a Null-terminated string to legal characters in a FAT
+ filename using an OEM character set.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an OEM character set.
+
+ @retval TRUE Fat is a Long File Name
+ @retval FALSE Fat is an 8.3 file name
+
+**/
+BOOLEAN
+EFIAPI
+EngStrToFat (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ )
+{
+ BOOLEAN SpecialCharExist;
+
+ SpecialCharExist = FALSE;
+ while ((*String != 0) && (FatSize != 0)) {
+ //
+ // Skip '.' or ' ' when making a fat name
+ //
+ if (*String != '.' && *String != ' ') {
+ //
+ // If this is a valid fat char, move it.
+ // Otherwise, move a '_' and flag the fact that the name needs a long file name.
+ //
+ if (*String < MAP_TABLE_SIZE && ((mEngInfoMap[*String] & CHAR_FAT_VALID) != 0)) {
+ *Fat = mEngUpperMap[*String];
+ } else {
+ *Fat = '_';
+ SpecialCharExist = TRUE;
+ }
+
+ Fat += 1;
+ FatSize -= 1;
+ }
+
+ String += 1;
+ }
+ //
+ // Do not terminate that fat string
+ //
+ return SpecialCharExist;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h
new file mode 100644
index 000000000..8a38909e6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h
@@ -0,0 +1,181 @@
+/** @file
+ Head file for Unicode Collation Protocol (English)
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UNICODE_COLLATION_ENG_H_
+#define _UNICODE_COLLATION_ENG_H_
+
+
+
+#include <Uefi.h>
+
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Bit mask to indicate the validity of character in FAT file name.
+//
+#define CHAR_FAT_VALID 0x01
+
+//
+// Maximum FAT table size.
+//
+#define MAP_TABLE_SIZE 0x100
+
+//
+// Macro to map character a to upper case.
+//
+#define TO_UPPER(a) (CHAR16) ((a) <= 0xFF ? mEngUpperMap[a] : (a))
+
+//
+// Macro to map character a to lower case.
+//
+#define TO_LOWER(a) (CHAR16) ((a) <= 0xFF ? mEngLowerMap[a] : (a))
+
+//
+// Prototypes
+//
+/**
+ Performs a case-insensitive comparison of two Null-terminated strings.
+
+ @param This Protocol instance pointer.
+ @param Str1 A pointer to a Null-terminated string.
+ @param Str2 A pointer to a Null-terminated string.
+
+ @retval 0 Str1 is equivalent to Str2
+ @retval > 0 Str1 is lexically greater than Str2
+ @retval < 0 Str1 is lexically less than Str2
+
+**/
+INTN
+EFIAPI
+EngStriColl (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ );
+
+/**
+ Performs a case-insensitive comparison of a Null-terminated
+ pattern string and a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string.
+ @param Pattern A pointer to a Null-terminated pattern string.
+
+ @retval TRUE Pattern was found in String.
+ @retval FALSE Pattern was not found in String.
+
+**/
+BOOLEAN
+EFIAPI
+EngMetaiMatch (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ );
+
+/**
+ Converts all the characters in a Null-terminated string to
+ lower case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrLwr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ );
+
+/**
+ Converts all the characters in a Null-terminated string to upper
+ case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrUpr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ );
+
+/**
+ Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an 8-bit OEM character set.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+
+**/
+VOID
+EFIAPI
+EngFatToStr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ );
+
+/**
+ Converts a Null-terminated string to legal characters in a FAT
+ filename using an OEM character set.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an OEM character set.
+
+ @retval TRUE Fat is a Long File Name
+ @retval FALSE Fat is an 8.3 file name
+
+**/
+BOOLEAN
+EFIAPI
+EngStrToFat (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ );
+
+/**
+ The user Entry Point for English module.
+
+ This function initializes unicode character mapping and then installs Unicode
+ Collation & Unicode Collation 2 Protocols based on the feature flags.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUnicodeCollationEng (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni
new file mode 100644
index 000000000..abf00de1d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngine.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The DXE driver produces FORM DISPLAY ENGIEN protocol.
+//
+// A generic Timestamp driver producing Timestamp Protocol using UEFI APIs.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
+
+#string STR_MODULE_DESCRIPTION #language en-US "A generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
new file mode 100644
index 000000000..07e19140b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# The DXE driver produces FORM DISPLAY ENGIEN protocol.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DisplayEngine
+ MODULE_UNI_FILE = DisplayEngine.uni
+ FILE_GUID = E660EA85-058E-4b55-A54B-F02F83A24707
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDisplayEngine
+ UNLOAD_IMAGE = UnloadDisplayEngine
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FormDisplayStr.uni
+ FormDisplay.c
+ FormDisplay.h
+ ProcessOptions.c
+ InputHandler.c
+ Popup.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+ BaseLib
+ PrintLib
+ HiiLib
+ MemoryAllocationLib
+ CustomizedDisplayLib
+
+[Protocols]
+ gEdkiiFormDisplayEngineProtocolGuid ## PRODUCES
+ gEdkiiFormBrowserEx2ProtocolGuid ## CONSUMES
+ gEfiHiiPopupProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DisplayEngineExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni
new file mode 100644
index 000000000..a6cc8306b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DisplayEngine Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"DisplayEngine DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
new file mode 100644
index 000000000..3b034a1c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
@@ -0,0 +1,4259 @@
+/** @file
+Entry and initialization module for the browser.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FormDisplay.h"
+
+//
+// Search table for UiDisplayMenu()
+//
+SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
+ {
+ SCAN_UP,
+ UiUp,
+ },
+ {
+ SCAN_DOWN,
+ UiDown,
+ },
+ {
+ SCAN_PAGE_UP,
+ UiPageUp,
+ },
+ {
+ SCAN_PAGE_DOWN,
+ UiPageDown,
+ },
+ {
+ SCAN_ESC,
+ UiReset,
+ },
+ {
+ SCAN_LEFT,
+ UiLeft,
+ },
+ {
+ SCAN_RIGHT,
+ UiRight,
+ }
+};
+
+UINTN mScanCodeNumber = ARRAY_SIZE (gScanCodeToOperation);
+
+SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
+ {
+ UiNoOperation,
+ CfUiNoOperation,
+ },
+ {
+ UiSelect,
+ CfUiSelect,
+ },
+ {
+ UiUp,
+ CfUiUp,
+ },
+ {
+ UiDown,
+ CfUiDown,
+ },
+ {
+ UiLeft,
+ CfUiLeft,
+ },
+ {
+ UiRight,
+ CfUiRight,
+ },
+ {
+ UiReset,
+ CfUiReset,
+ },
+ {
+ UiPageUp,
+ CfUiPageUp,
+ },
+ {
+ UiPageDown,
+ CfUiPageDown
+ },
+ {
+ UiHotKey,
+ CfUiHotKey
+ }
+};
+
+EFI_GUID gDisplayEngineGuid = {
+ 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
+};
+
+BOOLEAN gMisMatch;
+EFI_SCREEN_DESCRIPTOR gStatementDimensions;
+BOOLEAN mStatementLayoutIsChanged = TRUE;
+USER_INPUT *gUserInput;
+FORM_DISPLAY_ENGINE_FORM *gFormData;
+EFI_HII_HANDLE gHiiHandle;
+UINT16 gDirection;
+LIST_ENTRY gMenuOption;
+DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = {0};
+BOOLEAN mIsFirstForm = TRUE;
+FORM_ENTRY_INFO gOldFormEntry = {0};
+
+//
+// Browser Global Strings
+//
+CHAR16 *gReconnectConfirmChanges;
+CHAR16 *gReconnectFail;
+CHAR16 *gReconnectRequired;
+CHAR16 *gChangesOpt;
+CHAR16 *gFormNotFound;
+CHAR16 *gNoSubmitIf;
+CHAR16 *gBrowserError;
+CHAR16 *gSaveFailed;
+CHAR16 *gNoSubmitIfFailed;
+CHAR16 *gSaveProcess;
+CHAR16 *gSaveNoSubmitProcess;
+CHAR16 *gDiscardChange;
+CHAR16 *gJumpToFormSet;
+CHAR16 *gCheckError;
+CHAR16 *gPromptForData;
+CHAR16 *gPromptForPassword;
+CHAR16 *gPromptForNewPassword;
+CHAR16 *gConfirmPassword;
+CHAR16 *gConfirmError;
+CHAR16 *gPassowordInvalid;
+CHAR16 *gPressEnter;
+CHAR16 *gEmptyString;
+CHAR16 *gMiniString;
+CHAR16 *gOptionMismatch;
+CHAR16 *gFormSuppress;
+CHAR16 *gProtocolNotFound;
+CHAR16 *gConfirmDefaultMsg;
+CHAR16 *gConfirmSubmitMsg;
+CHAR16 *gConfirmDiscardMsg;
+CHAR16 *gConfirmResetMsg;
+CHAR16 *gConfirmExitMsg;
+CHAR16 *gConfirmSubmitMsg2nd;
+CHAR16 *gConfirmDefaultMsg2nd;
+CHAR16 *gConfirmResetMsg2nd;
+CHAR16 *gConfirmExitMsg2nd;
+CHAR16 *gConfirmOpt;
+CHAR16 *gConfirmOptYes;
+CHAR16 *gConfirmOptNo;
+CHAR16 *gConfirmOptOk;
+CHAR16 *gConfirmOptCancel;
+CHAR16 *gYesOption;
+CHAR16 *gNoOption;
+CHAR16 *gOkOption;
+CHAR16 *gCancelOption;
+CHAR16 *gErrorPopup;
+CHAR16 *gWarningPopup;
+CHAR16 *gInfoPopup;
+CHAR16 *gConfirmMsgConnect;
+CHAR16 *gConfirmMsgEnd;
+CHAR16 *gPasswordUnsupported;
+CHAR16 gModalSkipColumn;
+CHAR16 gPromptBlockWidth;
+CHAR16 gOptionBlockWidth;
+CHAR16 gHelpBlockWidth;
+CHAR16 *mUnknownString;
+
+FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {
+ FORM_DISPLAY_DRIVER_SIGNATURE,
+ NULL,
+ {
+ FormDisplay,
+ DriverClearDisplayPage,
+ ConfirmDataChange
+ },
+ {
+ EFI_HII_POPUP_PROTOCOL_REVISION,
+ CreatePopup
+ }
+};
+
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING String;
+
+ String = HiiGetString (HiiHandle, Token, NULL);
+ if (String == NULL) {
+ String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
+ ASSERT (String != NULL);
+ }
+
+ return (CHAR16 *) String;
+}
+
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeDisplayStrings (
+ VOID
+ )
+{
+ gReconnectConfirmChanges = GetToken (STRING_TOKEN (RECONNECT_CONFIRM_CHANGES), gHiiHandle);
+ mUnknownString = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);
+ gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
+ gNoSubmitIfFailed = GetToken (STRING_TOKEN (NO_SUBMIT_IF_CHECK_FAILED), gHiiHandle);
+ gReconnectFail = GetToken (STRING_TOKEN (RECONNECT_FAILED), gHiiHandle);
+ gReconnectRequired = GetToken (STRING_TOKEN (RECONNECT_REQUIRED), gHiiHandle);
+ gChangesOpt = GetToken (STRING_TOKEN (RECONNECT_CHANGES_OPTIONS), gHiiHandle);
+ gSaveProcess = GetToken (STRING_TOKEN (DISCARD_OR_JUMP), gHiiHandle);
+ gSaveNoSubmitProcess = GetToken (STRING_TOKEN (DISCARD_OR_CHECK), gHiiHandle);
+ gDiscardChange = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_DISCARD), gHiiHandle);
+ gJumpToFormSet = GetToken (STRING_TOKEN (DISCARD_OR_JUMP_JUMP), gHiiHandle);
+ gCheckError = GetToken (STRING_TOKEN (DISCARD_OR_CHECK_CHECK), gHiiHandle);
+ gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);
+ gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);
+ gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);
+ gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);
+ gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);
+ gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);
+ gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);
+ gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);
+ gOptionMismatch = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);
+ gFormSuppress = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);
+ gProtocolNotFound = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);
+ gFormNotFound = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle);
+ gNoSubmitIf = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle);
+ gBrowserError = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);
+ gConfirmDefaultMsg = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE), gHiiHandle);
+ gConfirmDiscardMsg = GetToken (STRING_TOKEN (CONFIRM_DISCARD_MESSAGE), gHiiHandle);
+ gConfirmSubmitMsg = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE), gHiiHandle);
+ gConfirmResetMsg = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE), gHiiHandle);
+ gConfirmExitMsg = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE), gHiiHandle);
+ gConfirmDefaultMsg2nd = GetToken (STRING_TOKEN (CONFIRM_DEFAULT_MESSAGE_2ND), gHiiHandle);
+ gConfirmSubmitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_SUBMIT_MESSAGE_2ND), gHiiHandle);
+ gConfirmResetMsg2nd = GetToken (STRING_TOKEN (CONFIRM_RESET_MESSAGE_2ND), gHiiHandle);
+ gConfirmExitMsg2nd = GetToken (STRING_TOKEN (CONFIRM_EXIT_MESSAGE_2ND), gHiiHandle);
+ gConfirmOpt = GetToken (STRING_TOKEN (CONFIRM_OPTION), gHiiHandle);
+ gConfirmOptYes = GetToken (STRING_TOKEN (CONFIRM_OPTION_YES), gHiiHandle);
+ gConfirmOptNo = GetToken (STRING_TOKEN (CONFIRM_OPTION_NO), gHiiHandle);
+ gConfirmOptOk = GetToken (STRING_TOKEN (CONFIRM_OPTION_OK), gHiiHandle);
+ gConfirmOptCancel = GetToken (STRING_TOKEN (CONFIRM_OPTION_CANCEL), gHiiHandle);
+ gYesOption = GetToken (STRING_TOKEN (YES_SELECTABLE_OPTION), gHiiHandle);
+ gNoOption = GetToken (STRING_TOKEN (NO_SELECTABLE_OPTION), gHiiHandle);
+ gOkOption = GetToken (STRING_TOKEN (OK_SELECTABLE_OPTION), gHiiHandle);
+ gCancelOption = GetToken (STRING_TOKEN (CANCEL_SELECTABLE_OPTION), gHiiHandle);
+ gErrorPopup = GetToken (STRING_TOKEN (ERROR_POPUP_STRING), gHiiHandle);
+ gWarningPopup = GetToken (STRING_TOKEN (WARNING_POPUP_STRING), gHiiHandle);
+ gInfoPopup = GetToken (STRING_TOKEN (INFO_POPUP_STRING), gHiiHandle);
+ gConfirmMsgConnect = GetToken (STRING_TOKEN (CONFIRM_OPTION_CONNECT), gHiiHandle);
+ gConfirmMsgEnd = GetToken (STRING_TOKEN (CONFIRM_OPTION_END), gHiiHandle);
+ gPasswordUnsupported = GetToken (STRING_TOKEN (PASSWORD_NOT_SUPPORTED ), gHiiHandle);
+}
+
+/**
+ Free up the resource allocated for all strings required
+ by Setup Browser.
+
+**/
+VOID
+FreeDisplayStrings (
+ VOID
+ )
+{
+ FreePool (mUnknownString);
+ FreePool (gEmptyString);
+ FreePool (gSaveFailed);
+ FreePool (gNoSubmitIfFailed);
+ FreePool (gReconnectFail);
+ FreePool (gReconnectRequired);
+ FreePool (gChangesOpt);
+ FreePool (gReconnectConfirmChanges);
+ FreePool (gSaveProcess);
+ FreePool (gSaveNoSubmitProcess);
+ FreePool (gDiscardChange);
+ FreePool (gJumpToFormSet);
+ FreePool (gCheckError);
+ FreePool (gPromptForData);
+ FreePool (gPromptForPassword);
+ FreePool (gPromptForNewPassword);
+ FreePool (gConfirmPassword);
+ FreePool (gConfirmError);
+ FreePool (gPassowordInvalid);
+ FreePool (gPressEnter);
+ FreePool (gMiniString);
+ FreePool (gOptionMismatch);
+ FreePool (gFormSuppress);
+ FreePool (gProtocolNotFound);
+ FreePool (gBrowserError);
+ FreePool (gNoSubmitIf);
+ FreePool (gFormNotFound);
+ FreePool (gConfirmDefaultMsg);
+ FreePool (gConfirmSubmitMsg);
+ FreePool (gConfirmDiscardMsg);
+ FreePool (gConfirmResetMsg);
+ FreePool (gConfirmExitMsg);
+ FreePool (gConfirmDefaultMsg2nd);
+ FreePool (gConfirmSubmitMsg2nd);
+ FreePool (gConfirmResetMsg2nd);
+ FreePool (gConfirmExitMsg2nd);
+ FreePool (gConfirmOpt);
+ FreePool (gConfirmOptYes);
+ FreePool (gConfirmOptNo);
+ FreePool (gConfirmOptOk);
+ FreePool (gConfirmOptCancel);
+ FreePool (gYesOption);
+ FreePool (gNoOption);
+ FreePool (gOkOption);
+ FreePool (gCancelOption);
+ FreePool (gErrorPopup);
+ FreePool (gWarningPopup);
+ FreePool (gInfoPopup);
+ FreePool (gConfirmMsgConnect);
+ FreePool (gConfirmMsgEnd);
+ FreePool (gPasswordUnsupported);
+}
+
+/**
+ Get prompt string id from the opcode data buffer.
+
+ @param OpCode The input opcode buffer.
+
+ @return The prompt string id.
+
+**/
+EFI_STRING_ID
+GetPrompt (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_STATEMENT_HEADER *Header;
+
+ if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {
+ return 0;
+ }
+
+ Header = (EFI_IFR_STATEMENT_HEADER *) (OpCode + 1);
+
+ return Header->Prompt;
+}
+
+/**
+ Get the supported width for a particular op-code
+
+ @param MenuOption The menu option.
+ @param AdjustWidth The width which is saved for the space.
+
+ @return Returns the number of CHAR16 characters that is support.
+
+**/
+UINT16
+GetWidth (
+ IN UI_MENU_OPTION *MenuOption,
+ OUT UINT16 *AdjustWidth
+ )
+{
+ CHAR16 *String;
+ UINTN Size;
+ EFI_IFR_TEXT *TestOp;
+ UINT16 ReturnWidth;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ Statement = MenuOption->ThisTag;
+
+ //
+ // For modal form, clean the entire row.
+ //
+ if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = LEFT_SKIPPED_COLUMNS;
+ }
+ return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gModalSkipColumn + LEFT_SKIPPED_COLUMNS));
+ }
+
+ Size = 0;
+
+ //
+ // See if the second text parameter is really NULL
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ TestOp = (EFI_IFR_TEXT *) Statement->OpCode;
+ if (TestOp->TextTwo != 0) {
+ String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);
+ Size = StrLen (String);
+ FreePool (String);
+ }
+ }
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
+ //
+ // Allow a wide display if text op-code and no secondary text op-code
+ //
+ ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
+ ) {
+
+ //
+ // Return the space width.
+ //
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = 2;
+ }
+ //
+ // Keep consistent with current behavior.
+ //
+ ReturnWidth = (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);
+ } else {
+ if (AdjustWidth != NULL) {
+ *AdjustWidth = 1;
+ }
+
+ ReturnWidth = (UINT16) (gPromptBlockWidth - 1);
+ }
+
+ //
+ // For nest in statement, should the subtitle indent.
+ //
+ if (MenuOption->NestInStatement) {
+ ReturnWidth -= SUBTITLE_INDENT;
+ }
+
+ return ReturnWidth;
+}
+
+/**
+ Will copy LineWidth amount of a string in the OutputString buffer and return the
+ number of CHAR16 characters that were copied into the OutputString buffer.
+ The output string format is:
+ Glyph Info + String info + '\0'.
+
+ In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
+
+ @param InputString String description for this option.
+ @param LineWidth Width of the desired string to extract in CHAR16
+ characters
+ @param GlyphWidth The glyph width of the begin of the char in the string.
+ @param Index Where in InputString to start the copy process
+ @param OutputString Buffer to copy the string into
+
+ @return Returns the number of CHAR16 characters that were copied into the OutputString
+ buffer, include extra glyph info and '\0' info.
+
+**/
+UINT16
+GetLineByWidth (
+ IN CHAR16 *InputString,
+ IN UINT16 LineWidth,
+ IN OUT UINT16 *GlyphWidth,
+ IN OUT UINTN *Index,
+ OUT CHAR16 **OutputString
+ )
+{
+ UINT16 StrOffset;
+ UINT16 GlyphOffset;
+ UINT16 OriginalGlyphWidth;
+ BOOLEAN ReturnFlag;
+ UINT16 LastSpaceOffset;
+ UINT16 LastGlyphWidth;
+
+ if (InputString == NULL || Index == NULL || OutputString == NULL) {
+ return 0;
+ }
+
+ if (LineWidth == 0 || *GlyphWidth == 0) {
+ return 0;
+ }
+
+ //
+ // Save original glyph width.
+ //
+ OriginalGlyphWidth = *GlyphWidth;
+ LastGlyphWidth = OriginalGlyphWidth;
+ ReturnFlag = FALSE;
+ LastSpaceOffset = 0;
+
+ //
+ // NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.
+ // To avoid displaying this empty line in screen, just skip the two CHARs here.
+ //
+ if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
+ *Index = *Index + 2;
+ }
+
+ //
+ // Fast-forward the string and see if there is a carriage-return in the string
+ //
+ for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {
+ switch (InputString[*Index + StrOffset]) {
+ case NARROW_CHAR:
+ *GlyphWidth = 1;
+ break;
+
+ case WIDE_CHAR:
+ *GlyphWidth = 2;
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ case CHAR_LINEFEED:
+ case CHAR_NULL:
+ ReturnFlag = TRUE;
+ break;
+
+ default:
+ GlyphOffset = GlyphOffset + *GlyphWidth;
+
+ //
+ // Record the last space info in this line. Will be used in rewind.
+ //
+ if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {
+ LastSpaceOffset = StrOffset;
+ LastGlyphWidth = *GlyphWidth;
+ }
+ break;
+ }
+
+ if (ReturnFlag) {
+ break;
+ }
+ }
+
+ //
+ // Rewind the string from the maximum size until we see a space to break the line
+ //
+ if (GlyphOffset > LineWidth) {
+ //
+ // Rewind the string to last space char in this line.
+ //
+ if (LastSpaceOffset != 0) {
+ StrOffset = LastSpaceOffset;
+ *GlyphWidth = LastGlyphWidth;
+ } else {
+ //
+ // Roll back to last char in the line width.
+ //
+ StrOffset--;
+ }
+ }
+
+ //
+ // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
+ //
+ if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {
+ return 0;
+ }
+
+ //
+ // Need extra glyph info and '\0' info, so +2.
+ //
+ *OutputString = AllocateZeroPool ((StrOffset + 2) * sizeof(CHAR16));
+ if (*OutputString == NULL) {
+ return 0;
+ }
+
+ //
+ // Save the glyph info at the begin of the string, will used by Print function.
+ //
+ if (OriginalGlyphWidth == 1) {
+ *(*OutputString) = NARROW_CHAR;
+ } else {
+ *(*OutputString) = WIDE_CHAR;
+ }
+
+ CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));
+
+ if (InputString[*Index + StrOffset] == CHAR_SPACE) {
+ //
+ // Skip the space info at the begin of next line.
+ //
+ *Index = (UINT16) (*Index + StrOffset + 1);
+ } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
+ //
+ // Skip the /n or /n/r info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
+ *Index = (UINT16) (*Index + StrOffset + 2);
+ } else {
+ *Index = (UINT16) (*Index + StrOffset + 1);
+ }
+ } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {
+ //
+ // Skip the /r or /r/n info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {
+ *Index = (UINT16) (*Index + StrOffset + 2);
+ } else {
+ *Index = (UINT16) (*Index + StrOffset + 1);
+ }
+ } else {
+ *Index = (UINT16) (*Index + StrOffset);
+ }
+
+ //
+ // Include extra glyph info and '\0' info, so +2.
+ //
+ return StrOffset + 2;
+}
+
+/**
+ Add one menu option by specified description and context.
+
+ @param Statement Statement of this Menu Option.
+ @param MenuItemCount The index for this Option in the Menu.
+ @param NestIn Whether this statement is nest in another statement.
+
+**/
+VOID
+UiAddMenuOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN UINT16 *MenuItemCount,
+ IN BOOLEAN NestIn
+ )
+{
+ UI_MENU_OPTION *MenuOption;
+ UINTN Index;
+ UINTN Count;
+ UINT16 NumberOfLines;
+ UINT16 GlyphWidth;
+ UINT16 Width;
+ UINTN ArrayEntry;
+ CHAR16 *OutputString;
+ EFI_STRING_ID PromptId;
+
+ NumberOfLines = 1;
+ ArrayEntry = 0;
+ GlyphWidth = 1;
+ Count = 1;
+ MenuOption = NULL;
+
+ PromptId = GetPrompt (Statement->OpCode);
+ ASSERT (PromptId != 0);
+
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ Count = 3;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
+ ASSERT (MenuOption);
+
+ MenuOption->Signature = UI_MENU_OPTION_SIGNATURE;
+ MenuOption->Description = GetToken (PromptId, gFormData->HiiHandle);
+ MenuOption->Handle = gFormData->HiiHandle;
+ MenuOption->ThisTag = Statement;
+ MenuOption->NestInStatement = NestIn;
+ MenuOption->EntryNumber = *MenuItemCount;
+
+ MenuOption->Sequence = Index;
+
+ if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {
+ MenuOption->GrayOut = TRUE;
+ } else {
+ MenuOption->GrayOut = FALSE;
+ }
+
+ if ((Statement->Attribute & HII_DISPLAY_LOCK) != 0 || (gFormData->Attribute & HII_DISPLAY_LOCK) != 0) {
+ MenuOption->GrayOut = TRUE;
+ }
+
+ //
+ // If the form or the question has the lock attribute, deal same as grayout.
+ //
+ if ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0 || (Statement->Attribute & HII_DISPLAY_LOCK) != 0) {
+ MenuOption->GrayOut = TRUE;
+ }
+
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_TIME_OP:
+ case EFI_IFR_DATE_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_PASSWORD_OP:
+ case EFI_IFR_STRING_OP:
+ //
+ // User could change the value of these items
+ //
+ MenuOption->IsQuestion = TRUE;
+ break;
+ case EFI_IFR_TEXT_OP:
+ if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {
+ //
+ // Initializing GrayOut option as TRUE for Text setup options
+ // so that those options will be Gray in colour and un selectable.
+ //
+ MenuOption->GrayOut = TRUE;
+ }
+ break;
+ default:
+ MenuOption->IsQuestion = FALSE;
+ break;
+ }
+
+ if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {
+ MenuOption->ReadOnly = TRUE;
+ if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {
+ MenuOption->GrayOut = TRUE;
+ }
+ }
+
+ if (Index == 0 &&
+ (Statement->OpCode->OpCode != EFI_IFR_DATE_OP) &&
+ (Statement->OpCode->OpCode != EFI_IFR_TIME_OP)) {
+ Width = GetWidth (MenuOption, NULL);
+ for (; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&MenuOption->Description[ArrayEntry]) != 0) {
+ NumberOfLines++;
+ }
+ FreePool (OutputString);
+ }
+ } else {
+ //
+ // Add three MenuOptions for Date/Time
+ // Data format : [01/02/2004] [11:22:33]
+ // Line number : 0 0 1 0 0 1
+ //
+ NumberOfLines = 0;
+ }
+
+ if (Index == 2) {
+ //
+ // Override LineNumber for the MenuOption in Date/Time sequence
+ //
+ MenuOption->Skip = 1;
+ } else {
+ MenuOption->Skip = NumberOfLines;
+ }
+
+ InsertTailList (&gMenuOption, &MenuOption->Link);
+ }
+
+ (*MenuItemCount)++;
+}
+
+/**
+ Create the menu list base on the form data info.
+
+**/
+VOID
+ConvertStatementToMenu (
+ VOID
+ )
+{
+ UINT16 MenuItemCount;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NestLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
+
+ MenuItemCount = 0;
+ InitializeListHead (&gMenuOption);
+
+ Link = GetFirstNode (&gFormData->StatementListHead);
+ while (!IsNull (&gFormData->StatementListHead, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gFormData->StatementListHead, Link);
+
+ //
+ // Skip the opcode not recognized by Display core.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {
+ continue;
+ }
+
+ UiAddMenuOption (Statement, &MenuItemCount, FALSE);
+
+ //
+ // Check the statement nest in this host statement.
+ //
+ NestLink = GetFirstNode (&Statement->NestStatementList);
+ while (!IsNull (&Statement->NestStatementList, NestLink)) {
+ NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
+ NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
+
+ //
+ // Skip the opcode not recognized by Display core.
+ //
+ if (NestStatement->OpCode->OpCode == EFI_IFR_GUID_OP) {
+ continue;
+ }
+
+ UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);
+ }
+ }
+}
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+GetStringWidth (
+ IN CHAR16 *String
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN IncrementValue;
+
+ ASSERT (String != NULL);
+ if (String == NULL) {
+ return 0;
+ }
+
+ Index = 0;
+ Count = 0;
+ IncrementValue = 1;
+
+ do {
+ //
+ // Advance to the null-terminator or to the first width directive
+ //
+ for (;
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
+ Index++, Count = Count + IncrementValue
+ )
+ ;
+
+ //
+ // We hit the null-terminator, we now have a count
+ //
+ if (String[Index] == 0) {
+ break;
+ }
+ //
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
+ //
+ if (String[Index] == NARROW_CHAR) {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 1;
+ } else {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 2;
+ }
+ } while (String[Index] != 0);
+
+ //
+ // Increment by one to include the null-terminator in the size
+ //
+ Count++;
+
+ return Count * sizeof (CHAR16);
+}
+
+/**
+ Base on the input option string to update the skip value for a menu option.
+
+ @param MenuOption The MenuOption to be checked.
+ @param OptionString The input option string.
+
+**/
+VOID
+UpdateSkipInfoForMenu (
+ IN UI_MENU_OPTION *MenuOption,
+ IN CHAR16 *OptionString
+ )
+{
+ UINTN Index;
+ UINT16 Width;
+ UINTN Row;
+ CHAR16 *OutputString;
+ UINT16 GlyphWidth;
+
+ Width = (UINT16) gOptionBlockWidth - 1;
+ GlyphWidth = 1;
+ Row = 1;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if (StrLen (&OptionString[Index]) != 0) {
+ Row++;
+ }
+
+ FreePool (OutputString);
+ }
+
+ if ((Row > MenuOption->Skip) &&
+ (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) &&
+ (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP)) {
+ MenuOption->Skip = Row;
+ }
+}
+
+/**
+ Update display lines for a Menu Option.
+
+ @param MenuOption The MenuOption to be checked.
+
+**/
+VOID
+UpdateOptionSkipLines (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ CHAR16 *OptionString;
+
+ OptionString = NULL;
+
+ ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
+ if (OptionString != NULL) {
+ UpdateSkipInfoForMenu (MenuOption, OptionString);
+
+ FreePool (OptionString);
+ }
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
+ OptionString = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
+
+ if (OptionString != NULL) {
+ UpdateSkipInfoForMenu (MenuOption, OptionString);
+
+ FreePool (OptionString);
+ }
+ }
+}
+
+/**
+ Check whether this Menu Option could be print.
+
+ Check Prompt string, option string or text two string not NULL.
+
+ This is an internal function.
+
+ @param MenuOption The MenuOption to be checked.
+
+ @retval TRUE This Menu Option is printable.
+ @retval FALSE This Menu Option could not be printable.
+
+**/
+BOOLEAN
+PrintableMenu (
+ UI_MENU_OPTION *MenuOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING OptionString;
+
+ OptionString = NULL;
+
+ if (MenuOption->Description[0] != '\0') {
+ return TRUE;
+ }
+
+ Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (OptionString != NULL && OptionString[0] != '\0') {
+ FreePool (OptionString);
+ return TRUE;
+ }
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {
+ OptionString = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);
+ ASSERT (OptionString != NULL);
+ if (OptionString[0] != '\0'){
+ FreePool (OptionString);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether this Menu Option could be highlighted.
+
+ This is an internal function.
+
+ @param MenuOption The MenuOption to be checked.
+
+ @retval TRUE This Menu Option is selectable.
+ @retval FALSE This Menu Option could not be selected.
+
+**/
+BOOLEAN
+IsSelectable (
+ UI_MENU_OPTION *MenuOption
+ )
+{
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ MenuOption->GrayOut || MenuOption->ReadOnly || !PrintableMenu (MenuOption)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Move to next selectable statement.
+
+ This is an internal function.
+
+ @param GoUp The navigation direction. TRUE: up, FALSE: down.
+ @param CurrentPosition Current position.
+ @param GapToTop Gap position to top or bottom.
+ @param FindInForm Whether find menu in current form or beyond.
+
+ @return The row distance from current MenuOption to next selectable MenuOption.
+
+ @retval -1 Reach the begin of the menu, still can't find the selectable menu.
+ @retval Value Find the selectable menu, maybe the truly selectable, maybe the
+ first menu showing beyond current form or last menu showing in
+ current form.
+ The value is the line number between the new selected menu and the
+ current select menu, not include the new selected menu.
+
+**/
+INTN
+MoveToNextStatement (
+ IN BOOLEAN GoUp,
+ IN OUT LIST_ENTRY **CurrentPosition,
+ IN UINTN GapToTop,
+ IN BOOLEAN FindInForm
+ )
+{
+ INTN Distance;
+ LIST_ENTRY *Pos;
+ UI_MENU_OPTION *NextMenuOption;
+ UI_MENU_OPTION *PreMenuOption;
+
+ Distance = 0;
+ Pos = *CurrentPosition;
+
+ if (Pos == &gMenuOption) {
+ return -1;
+ }
+
+ PreMenuOption = MENU_OPTION_FROM_LINK (Pos);
+
+ while (TRUE) {
+ NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
+ //
+ // NextMenuOption->Row == 0 means this menu has not calculate
+ // the NextMenuOption->Skip value yet, just calculate here.
+ //
+ if (NextMenuOption->Row == 0) {
+ UpdateOptionSkipLines (NextMenuOption);
+ }
+
+ //
+ // Check whether the menu is beyond current showing form,
+ // return the first one beyond the showing form.
+ //
+ if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {
+ if (FindInForm) {
+ NextMenuOption = PreMenuOption;
+ }
+ break;
+ }
+
+ //
+ // return the selectable menu in the showing form.
+ //
+ if (IsSelectable (NextMenuOption)) {
+ break;
+ }
+
+ Distance += NextMenuOption->Skip;
+
+ //
+ // Arrive at begin of the menu list.
+ //
+ if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {
+ Distance = -1;
+ break;
+ }
+
+ Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
+ PreMenuOption = NextMenuOption;
+ }
+
+ *CurrentPosition = &NextMenuOption->Link;
+ return Distance;
+}
+
+
+/**
+ Process option string for date/time opcode.
+
+ @param MenuOption Menu option point to date/time.
+ @param OptionString Option string input for process.
+ @param AddOptCol Whether need to update MenuOption->OptCol.
+
+**/
+VOID
+ProcessStringForDateTime (
+ UI_MENU_OPTION *MenuOption,
+ CHAR16 *OptionString,
+ BOOLEAN AddOptCol
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ EFI_IFR_DATE *Date;
+ EFI_IFR_TIME *Time;
+
+ ASSERT (MenuOption != NULL && OptionString != NULL);
+
+ Statement = MenuOption->ThisTag;
+ Date = NULL;
+ Time = NULL;
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ Date = (EFI_IFR_DATE *) Statement->OpCode;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ Time = (EFI_IFR_TIME *) Statement->OpCode;
+ }
+
+ //
+ // If leading spaces on OptionString - remove the spaces
+ //
+ for (Index = 0; OptionString[Index] == L' '; Index++) {
+ //
+ // Base on the blockspace to get the option column info.
+ //
+ if (AddOptCol) {
+ MenuOption->OptCol++;
+ }
+ }
+
+ for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
+ OptionString[Count] = OptionString[Index];
+ Count++;
+ }
+ OptionString[Count] = CHAR_NULL;
+
+ //
+ // Enable to suppress field in the opcode base on the flag.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ //
+ // OptionString format is: <**: **: ****>
+ // |month|day|year|
+ // 4 3 5
+ //
+ if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {
+ //
+ // At this point, only "<**:" in the optionstring.
+ // Clean the day's ** field, after clean, the format is "< :"
+ //
+ SetUnicodeMem (&OptionString[1], 2, L' ');
+ } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {
+ //
+ // At this point, only "**:" in the optionstring.
+ // Clean the month's "**" field, after clean, the format is " :"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {
+ //
+ // At this point, only "****>" in the optionstring.
+ // Clean the year's "****" field, after clean, the format is " >"
+ //
+ SetUnicodeMem (&OptionString[0], 4, L' ');
+ }
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ //
+ // OptionString format is: <**: **: **>
+ // |hour|minute|second|
+ // 4 3 3
+ //
+ if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {
+ //
+ // At this point, only "<**:" in the optionstring.
+ // Clean the hour's ** field, after clean, the format is "< :"
+ //
+ SetUnicodeMem (&OptionString[1], 2, L' ');
+ } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {
+ //
+ // At this point, only "**:" in the optionstring.
+ // Clean the minute's "**" field, after clean, the format is " :"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {
+ //
+ // At this point, only "**>" in the optionstring.
+ // Clean the second's "**" field, after clean, the format is " >"
+ //
+ SetUnicodeMem (&OptionString[0], 2, L' ');
+ }
+ }
+}
+
+
+/**
+ Adjust Data and Time position accordingly.
+ Data format : [01/02/2004] [11:22:33]
+ Line number : 0 0 1 0 0 1
+
+ This is an internal function.
+
+ @param DirectionUp the up or down direction. False is down. True is
+ up.
+ @param CurrentPosition Current position. On return: Point to the last
+ Option (Year or Second) if up; Point to the first
+ Option (Month or Hour) if down.
+
+ @return Return line number to pad. It is possible that we stand on a zero-advance
+ @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
+
+**/
+UINTN
+AdjustDateAndTimePosition (
+ IN BOOLEAN DirectionUp,
+ IN OUT LIST_ENTRY **CurrentPosition
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *NewPosition;
+ UI_MENU_OPTION *MenuOption;
+ UINTN PadLineNumber;
+
+ PadLineNumber = 0;
+ NewPosition = *CurrentPosition;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
+
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ //
+ // Calculate the distance from current position to the last Date/Time MenuOption
+ //
+ Count = 0;
+ while (MenuOption->Skip == 0) {
+ Count++;
+ NewPosition = NewPosition->ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
+ PadLineNumber = 1;
+ }
+
+ NewPosition = *CurrentPosition;
+ if (DirectionUp) {
+ //
+ // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
+ // to be one that back to the previous set of MenuOptions, we need to advance to the first
+ // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
+ // checking can be done.
+ //
+ while (Count++ < 2) {
+ NewPosition = NewPosition->BackLink;
+ }
+ } else {
+ //
+ // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
+ // to be one that progresses to the next set of MenuOptions, we need to advance to the last
+ // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
+ // checking can be done.
+ //
+ while (Count-- > 0) {
+ NewPosition = NewPosition->ForwardLink;
+ }
+ }
+
+ *CurrentPosition = NewPosition;
+ }
+
+ return PadLineNumber;
+}
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+GetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_NUMERIC *NumericOp;
+ UINT64 Step;
+
+ NumericOp = (EFI_IFR_NUMERIC *) OpCode;
+
+ switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ Step = NumericOp->data.u8.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ Step = NumericOp->data.u16.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ Step = NumericOp->data.u32.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ Step = NumericOp->data.u64.Step;
+ break;
+
+ default:
+ Step = 0;
+ break;
+ }
+
+ return Step;
+}
+
+/**
+ Find the registered HotKey based on KeyData.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key.
+
+ @return The registered HotKey context. If no found, NULL will return.
+**/
+BROWSER_HOT_KEY *
+GetHotKeyFromRegisterList (
+ IN EFI_INPUT_KEY *KeyData
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_HOT_KEY *HotKey;
+
+ Link = GetFirstNode (&gFormData->HotKeyListHead);
+ while (!IsNull (&gFormData->HotKeyListHead, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+
+ if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
+ return HotKey;
+ }
+
+ Link = GetNextNode (&gFormData->HotKeyListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Determine if the menu is the last menu that can be selected.
+
+ This is an internal function.
+
+ @param Direction The scroll direction. False is down. True is up.
+ @param CurrentPos The current focus.
+
+ @return FALSE -- the menu isn't the last menu that can be selected.
+ @return TRUE -- the menu is the last menu that can be selected.
+
+**/
+BOOLEAN
+ValueIsScroll (
+ IN BOOLEAN Direction,
+ IN LIST_ENTRY *CurrentPos
+ )
+{
+ LIST_ENTRY *Temp;
+
+ Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
+
+ if (Temp == &gMenuOption) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Wait for a given event to fire, or for an optional timeout to expire.
+
+ @param Event The event to wait for
+
+ @retval UI_EVENT_TYPE The type of the event which is trigged.
+
+**/
+UI_EVENT_TYPE
+UiWaitForEvent (
+ IN EFI_EVENT Event
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN EventNum;
+ UINT64 Timeout;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[3];
+ UI_EVENT_TYPE EventType;
+
+ TimerEvent = NULL;
+ Timeout = FormExitTimeout(gFormData);
+
+ if (Timeout != 0) {
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+
+ //
+ // Set the timer event
+ //
+ gBS->SetTimer (
+ TimerEvent,
+ TimerRelative,
+ Timeout
+ );
+ }
+
+ WaitList[0] = Event;
+ EventNum = 1;
+ if (gFormData->FormRefreshEvent != NULL) {
+ WaitList[EventNum] = gFormData->FormRefreshEvent;
+ EventNum ++;
+ }
+
+ if (Timeout != 0) {
+ WaitList[EventNum] = TimerEvent;
+ EventNum ++;
+ }
+
+ Status = gBS->WaitForEvent (EventNum, WaitList, &Index);
+ ASSERT_EFI_ERROR (Status);
+
+ switch (Index) {
+ case 0:
+ EventType = UIEventKey;
+ break;
+
+ case 1:
+ if (gFormData->FormRefreshEvent != NULL) {
+ EventType = UIEventDriver;
+ } else {
+ ASSERT (Timeout != 0 && EventNum == 2);
+ EventType = UIEventTimeOut;
+ }
+ break;
+
+ default:
+ ASSERT (Index == 2 && EventNum == 3);
+ EventType = UIEventTimeOut;
+ break;
+ }
+
+ if (Timeout != 0) {
+ gBS->CloseEvent (TimerEvent);
+ }
+
+ return EventType;
+}
+
+/**
+ Get question id info from the input opcode header.
+
+ @param OpCode The input opcode header pointer.
+
+ @retval The question id for this opcode.
+
+**/
+EFI_QUESTION_ID
+GetQuestionIdInfo (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_QUESTION_HEADER *QuestionHeader;
+
+ if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {
+ return 0;
+ }
+
+ QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *) OpCode + sizeof(EFI_IFR_OP_HEADER));
+
+ return QuestionHeader->QuestionId;
+}
+
+
+/**
+ Find the top of screen menu base on the current menu.
+
+ @param CurPos Current input menu.
+ @param Rows Totol screen rows.
+ @param SkipValue SkipValue for this new form.
+
+ @retval TopOfScreen Top of screen menu for the new form.
+
+**/
+LIST_ENTRY *
+FindTopOfScreenMenu (
+ IN LIST_ENTRY *CurPos,
+ IN UINTN Rows,
+ OUT UINTN *SkipValue
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *TopOfScreen;
+ UI_MENU_OPTION *PreviousMenuOption;
+
+ Link = CurPos;
+ PreviousMenuOption = NULL;
+
+ while (Link->BackLink != &gMenuOption) {
+ Link = Link->BackLink;
+ PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
+ if (PreviousMenuOption->Row == 0) {
+ UpdateOptionSkipLines (PreviousMenuOption);
+ }
+ if (Rows <= PreviousMenuOption->Skip) {
+ break;
+ }
+ Rows = Rows - PreviousMenuOption->Skip;
+ }
+
+ if (Link->BackLink == &gMenuOption) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ if (PreviousMenuOption != NULL && Rows < PreviousMenuOption->Skip) {
+ *SkipValue = PreviousMenuOption->Skip - Rows;
+ } else {
+ *SkipValue = 0;
+ }
+ } else {
+ TopOfScreen = Link;
+ *SkipValue = PreviousMenuOption->Skip - Rows;
+ }
+
+ return TopOfScreen;
+}
+
+/**
+ Get the index info for this opcode.
+
+ @param OpCode The input opcode for the statement.
+
+ @retval The index of this statement.
+
+**/
+UINTN
+GetIndexInfoForOpcode (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+ UINTN Index;
+
+ NewPos = gMenuOption.ForwardLink;
+ Index = 0;
+
+ for (NewPos = gMenuOption.ForwardLink; NewPos != &gMenuOption; NewPos = NewPos->ForwardLink){
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (CompareMem (MenuOption->ThisTag->OpCode, OpCode, OpCode->Length) == 0) {
+ if (MenuOption->ThisTag->OpCode == OpCode) {
+ return Index;
+ }
+
+ Index ++;
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Is this the saved highlight statement.
+
+ @param HighLightedStatement The input highlight statement.
+
+ @retval TRUE This is the highlight statement.
+ @retval FALSE This is not the highlight statement.
+
+**/
+BOOLEAN
+IsSavedHighlightStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
+ )
+{
+ if ((gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle) &&
+ (gFormData->FormId == gHighligthMenuInfo.FormId)) {
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {
+ return (BOOLEAN) (gHighligthMenuInfo.HLTQuestionId == GetQuestionIdInfo (HighLightedStatement->OpCode));
+ } else {
+ if (CompareMem (gHighligthMenuInfo.HLTOpCode, HighLightedStatement->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
+ if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(HighLightedStatement->OpCode)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Is this the highlight menu.
+
+ @param MenuOption The input Menu option.
+
+ @retval TRUE This is the highlight menu option.
+ @retval FALSE This is not the highlight menu option.
+
+**/
+BOOLEAN
+IsHighLightMenuOption (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ if (gHighligthMenuInfo.HLTQuestionId != 0) {
+ if (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.HLTQuestionId) {
+ return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
+ }
+ } else {
+ if(CompareMem (gHighligthMenuInfo.HLTOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.HLTOpCode->Length) == 0) {
+ if (gHighligthMenuInfo.HLTIndex == 0 || gHighligthMenuInfo.HLTIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {
+ return (BOOLEAN) (MenuOption->Sequence == gHighligthMenuInfo.HLTSequence);
+ } else {
+ return FALSE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Find the highlight menu.
+
+ If the input is NULL, base on the record highlight info in
+ gHighligthMenuInfo to find the last highlight menu.
+
+ @param HighLightedStatement The input highlight statement.
+
+ @retval The highlight menu index.
+
+**/
+LIST_ENTRY *
+FindHighLightMenuOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+
+ NewPos = gMenuOption.ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (HighLightedStatement != NULL) {
+ while (MenuOption->ThisTag != HighLightedStatement) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Must find the highlight statement.
+ //
+ ASSERT (NewPos != &gMenuOption);
+
+ } else {
+ while (!IsHighLightMenuOption (MenuOption)) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Highlight statement has disappear (suppressed/disableed)
+ //
+ if (NewPos == &gMenuOption) {
+ NewPos = NULL;
+ }
+ }
+
+ return NewPos;
+}
+
+/**
+ Is this the Top of screen menu.
+
+ @param MenuOption The input Menu option.
+
+ @retval TRUE This is the Top of screen menu option.
+ @retval FALSE This is not the Top of screen menu option.
+
+**/
+BOOLEAN
+IsTopOfScreeMenuOption (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ if (gHighligthMenuInfo.TOSQuestionId != 0) {
+ return (BOOLEAN) (GetQuestionIdInfo(MenuOption->ThisTag->OpCode) == gHighligthMenuInfo.TOSQuestionId);
+ }
+
+ if(CompareMem (gHighligthMenuInfo.TOSOpCode, MenuOption->ThisTag->OpCode, gHighligthMenuInfo.TOSOpCode->Length) == 0) {
+ if (gHighligthMenuInfo.TOSIndex == 0 || gHighligthMenuInfo.TOSIndex == GetIndexInfoForOpcode(MenuOption->ThisTag->OpCode)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Calculate the distance between two menus and include the skip value of StartMenu.
+
+ @param StartMenu The link_entry pointer to start menu.
+ @param EndMenu The link_entry pointer to end menu.
+
+**/
+UINTN
+GetDistanceBetweenMenus(
+ IN LIST_ENTRY *StartMenu,
+ IN LIST_ENTRY *EndMenu
+)
+{
+ LIST_ENTRY *Link;
+ UI_MENU_OPTION *MenuOption;
+ UINTN Distance;
+
+ Distance = 0;
+
+ Link = StartMenu;
+ while (Link != EndMenu) {
+ MenuOption = MENU_OPTION_FROM_LINK (Link);
+ if (MenuOption->Row == 0) {
+ UpdateOptionSkipLines (MenuOption);
+ }
+ Distance += MenuOption->Skip;
+ Link = Link->BackLink;
+ }
+ return Distance;
+}
+
+/**
+ Find the top of screen menu base on the previous record menu info.
+
+ @param HighLightMenu The link_entry pointer to highlight menu.
+
+ @retval Return the the link_entry pointer top of screen menu.
+
+**/
+LIST_ENTRY *
+FindTopOfScreenMenuOption (
+ IN LIST_ENTRY *HighLightMenu
+ )
+{
+ LIST_ENTRY *NewPos;
+ UI_MENU_OPTION *MenuOption;
+ UINTN TopRow;
+ UINTN BottomRow;
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
+
+ NewPos = gMenuOption.ForwardLink;
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ while (!IsTopOfScreeMenuOption(MenuOption)) {
+ NewPos = NewPos->ForwardLink;
+ if (NewPos == &gMenuOption) {
+ //
+ // Not Found it, break
+ //
+ break;
+ }
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ }
+
+ //
+ // Last time top of screen menu has disappeared.
+ //
+ if (NewPos == &gMenuOption) {
+ return NULL;
+ }
+ //
+ // Check whether highlight menu and top of screen menu can be shown within one page,
+ // if can't, return NULL to re-calcaulate the top of scrren menu. Because some new menus
+ // may be dynamically inserted between highlightmenu and previous top of screen menu,
+ // So previous record top of screen menu is not appropriate for current display.
+ //
+ if (GetDistanceBetweenMenus (HighLightMenu, NewPos) + 1 > BottomRow - TopRow) {
+ return NULL;
+ }
+
+ return NewPos;
+}
+
+/**
+ Find the first menu which will be show at the top.
+
+ @param FormData The data info for this form.
+ @param TopOfScreen The link_entry pointer to top menu.
+ @param HighlightMenu The menu which will be highlight.
+ @param SkipValue The skip value for the top menu.
+
+**/
+VOID
+FindTopMenu (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT LIST_ENTRY **TopOfScreen,
+ OUT LIST_ENTRY **HighlightMenu,
+ OUT UINTN *SkipValue
+ )
+{
+ UINTN TopRow;
+ UINTN BottomRow;
+ UI_MENU_OPTION *MenuOption;
+ UINTN TmpValue;
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
+ //
+ // When option mismatch happens,there exist two cases,one is reenter the form, just like the if case below,
+ // and the other is exit current form and enter last form, it can be covered by the else case.
+ //
+ if (gMisMatch && gFormData->HiiHandle == gHighligthMenuInfo.HiiHandle && gFormData->FormId == gHighligthMenuInfo.FormId) {
+ //
+ // Reenter caused by option mismatch or auto exit caused by refresh form(refresh interval/guid),
+ // base on the record highlight info to find the highlight menu.
+ //
+
+ *HighlightMenu = FindHighLightMenuOption(NULL);
+ if (*HighlightMenu != NULL) {
+ //
+ // Update skip info for this highlight menu.
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ //
+ // Found the last time highlight menu.
+ //
+ *TopOfScreen = FindTopOfScreenMenuOption(*HighlightMenu);
+ if (*TopOfScreen != NULL) {
+ //
+ // Found the last time selectable top of screen menu.
+ //
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
+ UpdateOptionSkipLines (MenuOption);
+
+ *SkipValue = gHighligthMenuInfo.SkipValue;
+ } else {
+ //
+ // Not found last time top of screen menu, so base on current highlight menu
+ // to find the new top of screen menu.
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ }
+ } else {
+ //
+ // Last time highlight menu has disappear, find the first highlightable menu as the default one.
+ //
+ *HighlightMenu = gMenuOption.ForwardLink;
+ if (!IsListEmpty (&gMenuOption)) {
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
+ }
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *SkipValue = 0;
+ }
+
+ } else if (FormData->HighLightedStatement != NULL) {
+ if (IsSavedHighlightStatement (FormData->HighLightedStatement)) {
+ //
+ // Input highlight menu is same as last time highlight menu.
+ // Base on last time highlight menu to set the top of screen menu and highlight menu.
+ //
+ *HighlightMenu = FindHighLightMenuOption(NULL);
+ ASSERT (*HighlightMenu != NULL);
+
+ //
+ // Update skip info for this highlight menu.
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ *TopOfScreen = FindTopOfScreenMenuOption(*HighlightMenu);
+ if (*TopOfScreen == NULL) {
+ //
+ // Not found last time top of screen menu, so base on current highlight menu
+ // to find the new top of screen menu.
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ } else {
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);
+ MenuOption = MENU_OPTION_FROM_LINK (*TopOfScreen);
+ UpdateOptionSkipLines (MenuOption);
+
+ *SkipValue = gHighligthMenuInfo.SkipValue;
+ }
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);
+ } else {
+ //
+ // Input highlight menu is not save as last time highlight menu.
+ //
+ *HighlightMenu = FindHighLightMenuOption(FormData->HighLightedStatement);
+ MenuOption = MENU_OPTION_FROM_LINK (*HighlightMenu);
+ UpdateOptionSkipLines (MenuOption);
+
+ //
+ // Make the current highlight menu at the bottom of the form to calculate the
+ // top of screen menu.
+ //
+ if (MenuOption->Skip >= BottomRow - TopRow) {
+ *TopOfScreen = *HighlightMenu;
+ TmpValue = 0;
+ } else {
+ *TopOfScreen = FindTopOfScreenMenu(*HighlightMenu, BottomRow - TopRow - MenuOption->Skip, &TmpValue);
+ }
+
+ *SkipValue = TmpValue;
+ }
+ AdjustDateAndTimePosition(TRUE, TopOfScreen);
+ } else {
+ //
+ // If not has input highlight statement, just return the first one in this form.
+ //
+ *TopOfScreen = gMenuOption.ForwardLink;
+ *HighlightMenu = gMenuOption.ForwardLink;
+ if (!IsListEmpty (&gMenuOption)) {
+ MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow, TRUE);
+ }
+ *SkipValue = 0;
+ }
+
+ gMisMatch = FALSE;
+
+ //
+ // First enter to show the menu, update highlight info.
+ //
+ UpdateHighlightMenuInfo (*HighlightMenu, *TopOfScreen, *SkipValue);
+}
+
+/**
+ Record the highlight menu and top of screen menu info.
+
+ @param Highlight The menu opton which is highlight.
+ @param TopOfScreen The menu opton which is at the top of the form.
+ @param SkipValue The skip line info for the top of screen menu.
+
+**/
+VOID
+UpdateHighlightMenuInfo (
+ IN LIST_ENTRY *Highlight,
+ IN LIST_ENTRY *TopOfScreen,
+ IN UINTN SkipValue
+ )
+{
+ UI_MENU_OPTION *MenuOption;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ gHighligthMenuInfo.HiiHandle = gFormData->HiiHandle;
+ gHighligthMenuInfo.FormId = gFormData->FormId;
+ gHighligthMenuInfo.SkipValue = (UINT16)SkipValue;
+
+ if (!IsListEmpty (&gMenuOption)) {
+ MenuOption = MENU_OPTION_FROM_LINK (Highlight);
+ Statement = MenuOption->ThisTag;
+
+ gUserInput->SelectedStatement = Statement;
+
+ gHighligthMenuInfo.HLTSequence = MenuOption->Sequence;
+ gHighligthMenuInfo.HLTQuestionId = GetQuestionIdInfo(Statement->OpCode);
+ if (gHighligthMenuInfo.HLTQuestionId == 0) {
+ //
+ // if question id == 0, save the opcode buffer..
+ //
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+ gHighligthMenuInfo.HLTOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
+ ASSERT (gHighligthMenuInfo.HLTOpCode != NULL);
+
+ gHighligthMenuInfo.HLTIndex = GetIndexInfoForOpcode(Statement->OpCode);
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+ Statement = MenuOption->ThisTag;
+
+ gHighligthMenuInfo.TOSQuestionId = GetQuestionIdInfo(Statement->OpCode);
+ if (gHighligthMenuInfo.TOSQuestionId == 0) {
+ //
+ // if question id == 0, save the opcode buffer..
+ //
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+ gHighligthMenuInfo.TOSOpCode = AllocateCopyPool (Statement->OpCode->Length, Statement->OpCode);
+ ASSERT (gHighligthMenuInfo.TOSOpCode != NULL);
+
+ gHighligthMenuInfo.TOSIndex = GetIndexInfoForOpcode(Statement->OpCode);
+ }
+ } else {
+ gUserInput->SelectedStatement = NULL;
+
+ gHighligthMenuInfo.HLTSequence = 0;
+ gHighligthMenuInfo.HLTQuestionId = 0;
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+ gHighligthMenuInfo.HLTOpCode = NULL;
+ gHighligthMenuInfo.HLTIndex = 0;
+
+ gHighligthMenuInfo.TOSQuestionId = 0;
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+ gHighligthMenuInfo.TOSOpCode = NULL;
+ gHighligthMenuInfo.TOSIndex = 0;
+ }
+}
+
+/**
+ Update attribut for this menu.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param Highlight Whether this menu will be highlight.
+
+**/
+VOID
+SetDisplayAttribute (
+ IN UI_MENU_OPTION *MenuOption,
+ IN BOOLEAN Highlight
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+
+ Statement = MenuOption->ThisTag;
+
+ if (Highlight) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+ return;
+ }
+
+ if (MenuOption->GrayOut) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
+ } else {
+ if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+ }
+}
+
+/**
+ Print string for this menu option.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param Col The column that this string will be print at.
+ @param Row The row that this string will be print at.
+ @param String The string which need to print.
+ @param Width The width need to print, if string is less than the
+ width, the block space will be used.
+ @param Highlight Whether this menu will be highlight.
+
+**/
+VOID
+DisplayMenuString (
+ IN UI_MENU_OPTION *MenuOption,
+ IN UINTN Col,
+ IN UINTN Row,
+ IN CHAR16 *String,
+ IN UINTN Width,
+ IN BOOLEAN Highlight
+ )
+{
+ UINTN Length;
+
+ //
+ // Print string with normal color.
+ //
+ if (!Highlight) {
+ PrintStringAtWithWidth (Col, Row, String, Width);
+ return;
+ }
+
+ //
+ // Print the highlight menu string.
+ // First print the highlight string.
+ //
+ SetDisplayAttribute(MenuOption, TRUE);
+ Length = PrintStringAt (Col, Row, String);
+
+ //
+ // Second, clean the empty after the string.
+ //
+ SetDisplayAttribute(MenuOption, FALSE);
+ PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);
+}
+
+/**
+ Check whether this menu can has option string.
+
+ @param MenuOption The menu opton which this attribut used to.
+
+ @retval TRUE This menu option can have option string.
+ @retval FALSE This menu option can't have option string.
+
+**/
+BOOLEAN
+HasOptionString (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ CHAR16 *String;
+ UINTN Size;
+ EFI_IFR_TEXT *TestOp;
+
+ Size = 0;
+ Statement = MenuOption->ThisTag;
+
+ //
+ // See if the second text parameter is really NULL
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ TestOp = (EFI_IFR_TEXT *) Statement->OpCode;
+ if (TestOp->TextTwo != 0) {
+ String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);
+ Size = StrLen (String);
+ FreePool (String);
+ }
+ }
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||
+ //
+ // Allow a wide display if text op-code and no secondary text op-code
+ //
+ ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
+ ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Double confirm with user about the action.
+
+ @param Action The user input action.
+
+ @retval TRUE User confirm with the input or not need user confirm.
+ @retval FALSE User want ignore this input.
+
+**/
+BOOLEAN
+FxConfirmPopup (
+ IN UINT32 Action
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *CfmStr;
+ UINTN CfmStrLen;
+ UINT32 CheckFlags;
+ BOOLEAN RetVal;
+ UINTN CatLen;
+ UINTN MaxLen;
+
+ CfmStrLen = 0;
+ CatLen = StrLen (gConfirmMsgConnect);
+
+ //
+ // Below action need extra popup dialog to confirm.
+ //
+ CheckFlags = BROWSER_ACTION_DISCARD |
+ BROWSER_ACTION_DEFAULT |
+ BROWSER_ACTION_SUBMIT |
+ BROWSER_ACTION_RESET |
+ BROWSER_ACTION_EXIT;
+
+ //
+ // Not need to confirm with user, just return TRUE.
+ //
+ if ((Action & CheckFlags) == 0) {
+ return TRUE;
+ }
+
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ CfmStrLen += StrLen (gConfirmDiscardMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmDefaultMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmSubmitMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmResetMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ if (CfmStrLen != 0) {
+ CfmStrLen += CatLen;
+ }
+
+ CfmStrLen += StrLen (gConfirmExitMsg);
+ }
+
+ //
+ // Allocate buffer to save the string.
+ // String + "?" + "\0"
+ //
+ MaxLen = CfmStrLen + 1 + 1;
+ CfmStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (CfmStr != NULL);
+
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ StrCpyS (CfmStr, MaxLen, gConfirmDiscardMsg);
+ }
+
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmDefaultMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmDefaultMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmSubmitMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmSubmitMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmResetMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmResetMsg);
+ }
+ }
+
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ if (CfmStr[0] != 0) {
+ StrCatS (CfmStr, MaxLen, gConfirmMsgConnect);
+ StrCatS (CfmStr, MaxLen, gConfirmExitMsg2nd);
+ } else {
+ StrCpyS (CfmStr, MaxLen, gConfirmExitMsg);
+ }
+ }
+
+ StrCatS (CfmStr, MaxLen, gConfirmMsgEnd);
+
+ do {
+ CreateDialog (&Key, gEmptyString, CfmStr, gConfirmOpt, gEmptyString, NULL);
+ } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (gConfirmOptNo[0] | UPPER_LOWER_CASE_OFFSET)) &&
+ (Key.ScanCode != SCAN_ESC));
+
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (gConfirmOptYes[0] | UPPER_LOWER_CASE_OFFSET)) {
+ RetVal = TRUE;
+ } else {
+ RetVal = FALSE;
+ }
+
+ FreePool (CfmStr);
+
+ return RetVal;
+}
+
+/**
+ Print string for this menu option.
+
+ @param MenuOption The menu opton which this attribut used to.
+ @param SkipWidth The skip width between the left to the start of the prompt.
+ @param BeginCol The begin column for one menu.
+ @param SkipLine The skip line for this menu.
+ @param BottomRow The bottom row for this form.
+ @param Highlight Whether this menu will be highlight.
+ @param UpdateCol Whether need to update the column info for Date/Time.
+
+ @retval EFI_SUCESSS Process the user selection success.
+
+**/
+EFI_STATUS
+DisplayOneMenu (
+ IN UI_MENU_OPTION *MenuOption,
+ IN UINTN SkipWidth,
+ IN UINTN BeginCol,
+ IN UINTN SkipLine,
+ IN UINTN BottomRow,
+ IN BOOLEAN Highlight,
+ IN BOOLEAN UpdateCol
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ UINTN Index;
+ UINT16 Width;
+ UINT16 PromptWidth;
+ CHAR16 *StringPtr;
+ CHAR16 *OptionString;
+ CHAR16 *OutputString;
+ UINT16 GlyphWidth;
+ UINTN Temp;
+ UINTN Temp2;
+ UINTN Temp3;
+ EFI_STATUS Status;
+ UINTN Row;
+ BOOLEAN IsProcessingFirstRow;
+ UINTN Col;
+ UINTN PromptLineNum;
+ UINTN OptionLineNum;
+ CHAR16 AdjustValue;
+ UINTN MaxRow;
+
+ Statement = MenuOption->ThisTag;
+ Temp = SkipLine;
+ Temp2 = SkipLine;
+ Temp3 = SkipLine;
+ AdjustValue = 0;
+ PromptLineNum = 0;
+ OptionLineNum = 0;
+ MaxRow = 0;
+ IsProcessingFirstRow = TRUE;
+
+ //
+ // Set default color.
+ //
+ SetDisplayAttribute (MenuOption, FALSE);
+
+ //
+ // 1. Paint the option string.
+ //
+ Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (OptionString != NULL) {
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ //
+ // Adjust option string for date/time opcode.
+ //
+ ProcessStringForDateTime(MenuOption, OptionString, UpdateCol);
+ }
+
+ Width = (UINT16) gOptionBlockWidth - 1;
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ OptionLineNum = 0;
+
+ for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if (((Temp2 == 0)) && (Row <= BottomRow)) {
+ if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ //
+ // For date/time question, it has three menu options for this qustion.
+ // The first/second menu options with the skip value is 0. the last one
+ // with skip value is 1.
+ //
+ if (MenuOption->Skip != 0) {
+ //
+ // For date/ time, print the last past (year for date and second for time)
+ // - 7 means skip [##/##/ for date and [##:##: for time.
+ //
+ DisplayMenuString (MenuOption,MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);
+ } else {
+ //
+ // For date/ time, print the first and second past (year for date and second for time)
+ // The OutputString has a NARROW_CHAR or WIDE_CHAR at the begin of the string,
+ // so need to - 1 to remove it, otherwise, it will clean 1 extr char follow it.
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString) - 1, Highlight);
+ }
+ } else {
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
+ }
+ OptionLineNum++;
+ }
+
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&OptionString[Index]) != 0) {
+ if (Temp2 == 0) {
+ Row++;
+ //
+ // Since the Number of lines for this menu entry may or may not be reflected accurately
+ // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
+ // some testing to ensure we are keeping this in-sync.
+ //
+ // If the difference in rows is greater than or equal to the skip value, increase the skip value
+ //
+ if ((Row - MenuOption->Row) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp2 != 0) {
+ Temp2--;
+ }
+ }
+
+ Highlight = FALSE;
+
+ FreePool (OptionString);
+ }
+
+ //
+ // 2. Paint the description.
+ //
+ PromptWidth = GetWidth (MenuOption, &AdjustValue);
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ PromptLineNum = 0;
+
+ if (MenuOption->Description == NULL || MenuOption->Description[0] == '\0') {
+ PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);
+ PromptLineNum++;
+ } else {
+ for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp == 0) && (Row <= BottomRow)) {
+ //
+ // 1.Clean the start LEFT_SKIPPED_COLUMNS
+ //
+ PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);
+
+ if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2 && IsProcessingFirstRow) {
+ //
+ // Print Arrow for Goto button.
+ //
+ PrintCharAt (
+ MenuOption->Col - 2,
+ Row,
+ GEOMETRICSHAPE_RIGHT_TRIANGLE
+ );
+ IsProcessingFirstRow = FALSE;
+ }
+ DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);
+ PromptLineNum ++;
+ }
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&MenuOption->Description[Index]) != 0) {
+ if (Temp == 0) {
+ Row++;
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp != 0) {
+ Temp--;
+ }
+ }
+
+ Highlight = FALSE;
+ }
+
+
+ //
+ // 3. If this is a text op with secondary text information
+ //
+ if ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) {
+ StringPtr = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle);
+
+ Width = (UINT16) gOptionBlockWidth - 1;
+ Row = MenuOption->Row;
+ GlyphWidth = 1;
+ OptionLineNum = 0;
+
+ for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
+ if ((Temp3 == 0) && (Row <= BottomRow)) {
+ DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
+ OptionLineNum++;
+ }
+ //
+ // If there is more string to process print on the next row and increment the Skip value
+ //
+ if (StrLen (&StringPtr[Index]) != 0) {
+ if (Temp3 == 0) {
+ Row++;
+ //
+ // If the rows for text two is greater than or equal to the skip value, increase the skip value
+ //
+ if ((Row - MenuOption->Row) >= MenuOption->Skip) {
+ MenuOption->Skip++;
+ }
+ }
+ }
+
+ FreePool (OutputString);
+ if (Temp3 != 0) {
+ Temp3--;
+ }
+ }
+
+ FreePool (StringPtr);
+ }
+
+ //
+ // 4.Line number for Option string and prompt string are not equal.
+ // Clean the column whose line number is less.
+ //
+ if (HasOptionString(MenuOption) && (OptionLineNum != PromptLineNum)) {
+ Col = OptionLineNum < PromptLineNum ? MenuOption->OptCol : BeginCol;
+ Row = (OptionLineNum < PromptLineNum ? OptionLineNum : PromptLineNum) + MenuOption->Row;
+ Width = (UINT16) (OptionLineNum < PromptLineNum ? gOptionBlockWidth : PromptWidth + AdjustValue + SkipWidth);
+ MaxRow = (OptionLineNum < PromptLineNum ? PromptLineNum : OptionLineNum) + MenuOption->Row - 1;
+
+ while (Row <= MaxRow) {
+ DisplayMenuString (MenuOption, Col, Row++, L"", Width, FALSE);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Display menu and wait for user to select one menu option, then return it.
+ If AutoBoot is enabled, then if user doesn't select any option,
+ after period of time, it will automatically return the first menu option.
+
+ @param FormData The current form data info.
+
+ @retval EFI_SUCESSS Process the user selection success.
+ @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
+
+**/
+EFI_STATUS
+UiDisplayMenu (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINTN SkipValue;
+ INTN Difference;
+ UINTN DistanceValue;
+ UINTN Row;
+ UINTN Col;
+ UINTN Temp;
+ UINTN Temp2;
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ CHAR16 *StringRightPtr;
+ CHAR16 *StringErrorPtr;
+ CHAR16 *OptionString;
+ CHAR16 *HelpString;
+ CHAR16 *HelpHeaderString;
+ CHAR16 *HelpBottomString;
+ BOOLEAN NewLine;
+ BOOLEAN Repaint;
+ BOOLEAN UpArrow;
+ BOOLEAN DownArrow;
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NewPos;
+ LIST_ENTRY *TopOfScreen;
+ LIST_ENTRY *SavedListEntry;
+ UI_MENU_OPTION *MenuOption;
+ UI_MENU_OPTION *NextMenuOption;
+ UI_MENU_OPTION *SavedMenuOption;
+ UI_CONTROL_FLAG ControlFlag;
+ UI_SCREEN_OPERATION ScreenOperation;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ BROWSER_HOT_KEY *HotKey;
+ UINTN HelpPageIndex;
+ UINTN HelpPageCount;
+ UINTN RowCount;
+ UINTN HelpLine;
+ UINTN HelpHeaderLine;
+ UINTN HelpBottomLine;
+ BOOLEAN MultiHelpPage;
+ UINT16 EachLineWidth;
+ UINT16 HeaderLineWidth;
+ UINT16 BottomLineWidth;
+ EFI_STRING_ID HelpInfo;
+ UI_EVENT_TYPE EventType;
+ BOOLEAN SkipHighLight;
+ EFI_HII_VALUE *StatementValue;
+
+ EventType = UIEventNone;
+ Status = EFI_SUCCESS;
+ HelpString = NULL;
+ HelpHeaderString = NULL;
+ HelpBottomString = NULL;
+ OptionString = NULL;
+ ScreenOperation = UiNoOperation;
+ NewLine = TRUE;
+ HelpPageCount = 0;
+ HelpLine = 0;
+ RowCount = 0;
+ HelpBottomLine = 0;
+ HelpHeaderLine = 0;
+ HelpPageIndex = 0;
+ MultiHelpPage = FALSE;
+ EachLineWidth = 0;
+ HeaderLineWidth = 0;
+ BottomLineWidth = 0;
+ UpArrow = FALSE;
+ DownArrow = FALSE;
+ SkipValue = 0;
+ SkipHighLight = FALSE;
+
+ NextMenuOption = NULL;
+ SavedMenuOption = NULL;
+ HotKey = NULL;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ gModalSkipColumn = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;
+
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
+
+ TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
+ BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;
+
+ Row = TopRow;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;
+ } else {
+ Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;
+ }
+
+ FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue);
+ if (!IsListEmpty (&gMenuOption)) {
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ gUserInput->SelectedStatement = NextMenuOption->ThisTag;
+ }
+
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ ControlFlag = CfInitialization;
+ while (TRUE) {
+ switch (ControlFlag) {
+ case CfInitialization:
+ if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) ||
+ (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))) {
+ //
+ // Clear Statement range if different formset is painted.
+ //
+ ClearLines (
+ gStatementDimensions.LeftColumn,
+ gStatementDimensions.RightColumn,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ GetFieldTextColor ()
+ );
+
+ }
+ ControlFlag = CfRepaint;
+ break;
+
+ case CfRepaint:
+ ControlFlag = CfRefreshHighLight;
+
+ if (Repaint) {
+ //
+ // Display menu
+ //
+ DownArrow = FALSE;
+ UpArrow = FALSE;
+ Row = TopRow;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+
+ //
+ // 1. Check whether need to print the arrow up.
+ //
+ if (!ValueIsScroll (TRUE, TopOfScreen)) {
+ UpArrow = TRUE;
+ }
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
+ }
+ if (UpArrow) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
+ PrintCharAt (
+ gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
+ TopRow - SCROLL_ARROW_HEIGHT,
+ ARROW_UP
+ );
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+
+ //
+ // 2.Paint the menu.
+ //
+ for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {
+ MenuOption = MENU_OPTION_FROM_LINK (Link);
+ MenuOption->Row = Row;
+ MenuOption->Col = Col;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth + gModalSkipColumn;
+ } else {
+ MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;
+ }
+
+ if (MenuOption->NestInStatement) {
+ MenuOption->Col += SUBTITLE_INDENT;
+ }
+
+ //
+ // Save the highlight menu, will be used in CfRefreshHighLight case.
+ //
+ if (Link == NewPos) {
+ SavedMenuOption = MenuOption;
+ SkipHighLight = TRUE;
+ }
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ Status = DisplayOneMenu (MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn + gModalSkipColumn,
+ Link == TopOfScreen ? SkipValue : 0,
+ BottomRow,
+ (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),
+ TRUE
+ );
+ } else {
+ Status = DisplayOneMenu (MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Link == TopOfScreen ? SkipValue : 0,
+ BottomRow,
+ (BOOLEAN) ((Link == NewPos) && IsSelectable(MenuOption)),
+ TRUE
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (gMisMatch) {
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+ }
+ //
+ // 3. Update the row info which will be used by next menu.
+ //
+ if (Link == TopOfScreen) {
+ Row += MenuOption->Skip - SkipValue;
+ } else {
+ Row += MenuOption->Skip;
+ }
+
+ if (Row > BottomRow) {
+ if (!ValueIsScroll (FALSE, Link)) {
+ DownArrow = TRUE;
+ }
+
+ Row = BottomRow + 1;
+ break;
+ }
+ }
+
+ //
+ // 3. Menus in this form may not cover all form, clean the remain field.
+ //
+ while (Row <= BottomRow) {
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);
+ }
+ }
+
+ //
+ // 4. Print the down arrow row.
+ //
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn + gModalSkipColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * + gModalSkipColumn);
+ } else {
+ PrintStringAtWithWidth(gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
+ }
+ if (DownArrow) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
+ PrintCharAt (
+ gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
+ BottomRow + SCROLL_ARROW_HEIGHT,
+ ARROW_DOWN
+ );
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ }
+
+ MenuOption = NULL;
+ }
+ break;
+
+ case CfRefreshHighLight:
+
+ //
+ // MenuOption: Last menu option that need to remove hilight
+ // MenuOption is set to NULL in Repaint
+ // NewPos: Current menu option that need to hilight
+ //
+ ControlFlag = CfUpdateHelpString;
+
+ ASSERT (NewPos != NULL);
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+
+ if (SkipHighLight) {
+ SkipHighLight = FALSE;
+ MenuOption = SavedMenuOption;
+ RefreshKeyHelp(gFormData, SavedMenuOption->ThisTag, FALSE);
+ break;
+ }
+
+ if (IsListEmpty (&gMenuOption)) {
+ //
+ // No menu option, just update the hotkey filed.
+ //
+ RefreshKeyHelp(gFormData, NULL, FALSE);
+ break;
+ }
+
+ if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {
+ Temp = SkipValue;
+ } else {
+ Temp = 0;
+ }
+ if (NewPos == TopOfScreen) {
+ Temp2 = SkipValue;
+ } else {
+ Temp2 = 0;
+ }
+
+ if (MenuOption == NULL || NewPos != &MenuOption->Link) {
+ if (MenuOption != NULL) {
+ //
+ // Remove the old highlight menu.
+ //
+ Status = DisplayOneMenu (MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Temp,
+ BottomRow,
+ FALSE,
+ FALSE
+ );
+ }
+
+ //
+ // This is the current selected statement
+ //
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE);
+
+ if (!IsSelectable (MenuOption)) {
+ break;
+ }
+
+ Status = DisplayOneMenu (MenuOption,
+ MenuOption->Col - gStatementDimensions.LeftColumn,
+ gStatementDimensions.LeftColumn,
+ Temp2,
+ BottomRow,
+ TRUE,
+ FALSE
+ );
+ }
+ break;
+
+ case CfUpdateHelpString:
+ ControlFlag = CfPrepareToReadKey;
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ break;
+ }
+
+ //
+ // NewLine means only update highlight menu (remove old highlight and highlith
+ // the new one), not need to full repain the form.
+ //
+ if (Repaint || NewLine) {
+ if (IsListEmpty (&gMenuOption)) {
+ //
+ // Don't print anything if no mwnu option.
+ //
+ StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ } else {
+ //
+ // Don't print anything if it is a NULL help token
+ //
+ ASSERT(MenuOption != NULL);
+ HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;
+ Statement = MenuOption->ThisTag;
+ StatementValue = &Statement->CurrentValue;
+ if (HelpInfo == 0 || !IsSelectable (MenuOption)) {
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP && StatementValue->Value.date.Month== 0xff)||(Statement->OpCode->OpCode == EFI_IFR_TIME_OP && StatementValue->Value.time.Hour == 0xff)){
+ StringPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
+ } else {
+ StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
+ }
+ } else {
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP && StatementValue->Value.date.Month== 0xff)||(Statement->OpCode->OpCode == EFI_IFR_TIME_OP && StatementValue->Value.time.Hour == 0xff)){
+ StringRightPtr = GetToken (HelpInfo, gFormData->HiiHandle);
+ StringErrorPtr = GetToken (STRING_TOKEN (GET_TIME_FAIL), gHiiHandle);
+ StringPtr = AllocateZeroPool ((StrLen (StringRightPtr) + StrLen (StringErrorPtr)+ 1 ) * sizeof (CHAR16));
+ StrCpyS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringRightPtr);
+ StrCatS (StringPtr, StrLen (StringRightPtr) + StrLen (StringErrorPtr) + 1, StringErrorPtr);
+ FreePool (StringRightPtr);
+ FreePool (StringErrorPtr);
+ } else {
+ StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);
+ }
+ }
+ }
+
+ RowCount = BottomRow - TopRow + 1;
+ HelpPageIndex = 0;
+ //
+ // 1.Calculate how many line the help string need to print.
+ //
+ if (HelpString != NULL) {
+ FreePool (HelpString);
+ HelpString = NULL;
+ }
+ HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);
+ FreePool (StringPtr);
+
+ if (HelpLine > RowCount) {
+ MultiHelpPage = TRUE;
+ StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);
+ if (HelpHeaderString != NULL) {
+ FreePool (HelpHeaderString);
+ HelpHeaderString = NULL;
+ }
+ HelpHeaderLine = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0);
+ FreePool (StringPtr);
+ StringPtr = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);
+ if (HelpBottomString != NULL) {
+ FreePool (HelpBottomString);
+ HelpBottomString = NULL;
+ }
+ HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);
+ FreePool (StringPtr);
+ //
+ // Calculate the help page count.
+ //
+ if (HelpLine > 2 * RowCount - 2) {
+ HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;
+ if ((HelpLine - RowCount + 1) % (RowCount - 2) != 0) {
+ HelpPageCount += 1;
+ }
+ } else {
+ HelpPageCount = 2;
+ }
+ } else {
+ MultiHelpPage = FALSE;
+ }
+ }
+
+ //
+ // Check whether need to show the 'More(U/u)' at the begin.
+ // Base on current direct info, here shows aligned to the right side of the column.
+ // If the direction is multi line and aligned to right side may have problem, so
+ // add ASSERT code here.
+ //
+ if (HelpPageIndex > 0) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
+ for (Index = 0; Index < HelpHeaderLine; Index++) {
+ ASSERT (HelpHeaderLine == 1);
+ ASSERT (GetStringWidth (HelpHeaderString) / 2 < ((UINT32) gHelpBlockWidth - 1));
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ PrintStringAt (
+ gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,
+ Index + TopRow,
+ &HelpHeaderString[Index * HeaderLineWidth]
+ );
+ }
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());
+ //
+ // Print the help string info.
+ //
+ if (!MultiHelpPage) {
+ for (Index = 0; Index < HelpLine; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ &HelpString[Index * EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+ for (; Index < RowCount; Index ++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ }
+ gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
+ } else {
+ if (HelpPageIndex == 0) {
+ for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow,
+ &HelpString[Index * EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+ } else {
+ for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) &&
+ (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow + HelpHeaderLine,
+ &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth],
+ gHelpBlockWidth
+ );
+ }
+ if (HelpPageIndex == HelpPageCount - 1) {
+ for (; Index < RowCount - HelpHeaderLine; Index ++) {
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ Index + TopRow + HelpHeaderLine,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ }
+ gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
+ }
+ }
+ }
+
+ //
+ // Check whether need to print the 'More(D/d)' at the bottom.
+ // Base on current direct info, here shows aligned to the right side of the column.
+ // If the direction is multi line and aligned to right side may have problem, so
+ // add ASSERT code here.
+ //
+ if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());
+ for (Index = 0; Index < HelpBottomLine; Index++) {
+ ASSERT (HelpBottomLine == 1);
+ ASSERT (GetStringWidth (HelpBottomString) / 2 < ((UINT32) gHelpBlockWidth - 1));
+ PrintStringAtWithWidth (
+ gStatementDimensions.RightColumn - gHelpBlockWidth,
+ BottomRow + Index - HelpBottomLine + 1,
+ gEmptyString,
+ gHelpBlockWidth
+ );
+ PrintStringAt (
+ gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,
+ BottomRow + Index - HelpBottomLine + 1,
+ &HelpBottomString[Index * BottomLineWidth]
+ );
+ }
+ }
+ //
+ // Reset this flag every time we finish using it.
+ //
+ Repaint = FALSE;
+ NewLine = FALSE;
+ break;
+
+ case CfPrepareToReadKey:
+ ControlFlag = CfReadKey;
+ ScreenOperation = UiNoOperation;
+ break;
+
+ case CfReadKey:
+ ControlFlag = CfScreenOperation;
+
+ //
+ // Wait for user's selection
+ //
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status)) {
+ EventType = UIEventKey;
+ break;
+ }
+
+ //
+ // If we encounter error, continue to read another key in.
+ //
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ EventType = UiWaitForEvent(gST->ConIn->WaitForKey);
+ if (EventType == UIEventKey) {
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ }
+ break;
+ }
+
+ if (EventType == UIEventDriver) {
+ gMisMatch = TRUE;
+ gUserInput->Action = BROWSER_ACTION_NONE;
+ ControlFlag = CfExit;
+ break;
+ }
+
+ if (EventType == UIEventTimeOut) {
+ gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
+ ControlFlag = CfExit;
+ break;
+ }
+
+ switch (Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ if(MenuOption == NULL || MenuOption->GrayOut || MenuOption->ReadOnly) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ScreenOperation = UiSelect;
+ gDirection = 0;
+ break;
+
+ //
+ // We will push the adjustment of these numeric values directly to the input handler
+ // NOTE: we won't handle manual input numeric
+ //
+ case '+':
+ case '-':
+ //
+ // If the screen has no menu items, and the user didn't select UiReset
+ // ignore the selection and go back to reading keys.
+ //
+ ASSERT(MenuOption != NULL);
+ if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ Statement = MenuOption->ThisTag;
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP)
+ || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)
+ || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum(Statement->OpCode) != 0))
+ ){
+ if (Key.UnicodeChar == '+') {
+ gDirection = SCAN_RIGHT;
+ } else {
+ gDirection = SCAN_LEFT;
+ }
+
+ Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
+ if (OptionString != NULL) {
+ FreePool (OptionString);
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Repaint to clear possible error prompt pop-up
+ //
+ Repaint = TRUE;
+ NewLine = TRUE;
+ } else {
+ ControlFlag = CfExit;
+ }
+ }
+ break;
+
+ case '^':
+ ScreenOperation = UiUp;
+ break;
+
+ case 'V':
+ case 'v':
+ ScreenOperation = UiDown;
+ break;
+
+ case ' ':
+ if(IsListEmpty (&gMenuOption)) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+
+ ASSERT(MenuOption != NULL);
+ if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {
+ ScreenOperation = UiSelect;
+ }
+ break;
+
+ case 'D':
+ case 'd':
+ if (!MultiHelpPage) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+ ControlFlag = CfUpdateHelpString;
+ HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;
+ break;
+
+ case 'U':
+ case 'u':
+ if (!MultiHelpPage) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+ ControlFlag = CfUpdateHelpString;
+ HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;
+ break;
+
+ case CHAR_NULL:
+ for (Index = 0; Index < mScanCodeNumber; Index++) {
+ if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
+ ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
+ break;
+ }
+ }
+
+ if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {
+ //
+ // ModalForm has no ESC key and Hot Key.
+ //
+ ControlFlag = CfReadKey;
+ } else if (Index == mScanCodeNumber) {
+ //
+ // Check whether Key matches the registered hot key.
+ //
+ HotKey = NULL;
+ HotKey = GetHotKeyFromRegisterList (&Key);
+ if (HotKey != NULL) {
+ ScreenOperation = UiHotKey;
+ }
+ }
+ break;
+ }
+ break;
+
+ case CfScreenOperation:
+ if ((ScreenOperation != UiReset) && (ScreenOperation != UiHotKey)) {
+ //
+ // If the screen has no menu items, and the user didn't select UiReset or UiHotKey
+ // ignore the selection and go back to reading keys.
+ //
+ if (IsListEmpty (&gMenuOption)) {
+ ControlFlag = CfReadKey;
+ break;
+ }
+ }
+
+ for (Index = 0;
+ Index < ARRAY_SIZE (gScreenOperationToControlFlag);
+ Index++
+ ) {
+ if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
+ ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
+ break;
+ }
+ }
+ break;
+
+ case CfUiSelect:
+ ControlFlag = CfRepaint;
+
+ ASSERT(MenuOption != NULL);
+ Statement = MenuOption->ThisTag;
+ if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
+ break;
+ }
+
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_REF_OP:
+ case EFI_IFR_ACTION_OP:
+ case EFI_IFR_RESET_BUTTON_OP:
+ ControlFlag = CfExit;
+ break;
+
+ default:
+ //
+ // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
+ //
+ RefreshKeyHelp (gFormData, Statement, TRUE);
+ Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
+
+ if (OptionString != NULL) {
+ FreePool (OptionString);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ RefreshKeyHelp (gFormData, Statement, FALSE);
+ break;
+ } else {
+ ControlFlag = CfExit;
+ break;
+ }
+ }
+ break;
+
+ case CfUiReset:
+ //
+ // We come here when someone press ESC
+ // If the policy is not exit front page when user press ESC, process here.
+ //
+ if (!FormExitPolicy()) {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ ControlFlag = CfRepaint;
+ break;
+ }
+
+ gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
+ ControlFlag = CfExit;
+ break;
+
+ case CfUiHotKey:
+ ControlFlag = CfRepaint;
+
+ ASSERT (HotKey != NULL);
+
+ if (FxConfirmPopup(HotKey->Action)) {
+ gUserInput->Action = HotKey->Action;
+ if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ gUserInput->DefaultId = HotKey->DefaultId;
+ }
+ ControlFlag = CfExit;
+ } else {
+ Repaint = TRUE;
+ NewLine = TRUE;
+ ControlFlag = CfRepaint;
+ }
+
+ break;
+
+ case CfUiLeft:
+ ControlFlag = CfRepaint;
+ ASSERT(MenuOption != NULL);
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ if (MenuOption->Sequence != 0) {
+ //
+ // In the middle or tail of the Date/Time op-code set, go left.
+ //
+ ASSERT(NewPos != NULL);
+ NewPos = NewPos->BackLink;
+ }
+ }
+ break;
+
+ case CfUiRight:
+ ControlFlag = CfRepaint;
+ ASSERT(MenuOption != NULL);
+ if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ if (MenuOption->Sequence != 2) {
+ //
+ // In the middle or tail of the Date/Time op-code set, go left.
+ //
+ ASSERT(NewPos != NULL);
+ NewPos = NewPos->ForwardLink;
+ }
+ }
+ break;
+
+ case CfUiUp:
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+
+ SavedListEntry = NewPos;
+ ASSERT(NewPos != NULL);
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ ASSERT (MenuOption != NULL);
+
+ //
+ // Adjust Date/Time position before we advance forward.
+ //
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ NewPos = NewPos->BackLink;
+ //
+ // Find next selectable menu or the first menu beyond current form.
+ //
+ Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow, FALSE);
+ if (Difference < 0) {
+ //
+ // We hit the begining MenuOption that can be focused
+ // so we simply scroll to the top.
+ //
+ Repaint = TRUE;
+ if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ NewPos = SavedListEntry;
+ SkipValue = 0;
+ } else {
+ //
+ // Scroll up to the last page when we have arrived at top page.
+ //
+ TopOfScreen = FindTopOfScreenMenu (gMenuOption.BackLink, BottomRow - TopRow, &SkipValue);
+ NewPos = gMenuOption.BackLink;
+ MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow, TRUE);
+ }
+ } else {
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+
+ if (MenuOption->Row < TopRow + Difference + NextMenuOption->Skip) {
+ //
+ // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
+ //
+ TopOfScreen = NewPos;
+ Repaint = TRUE;
+ SkipValue = 0;
+ }
+
+ //
+ // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
+ //
+ // BottomRow - TopRow + 1 means the total rows current forms supported.
+ // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
+ // and new top menu. New top menu will all shows in next form, but last highlight menu
+ // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
+ // last highlight menu.
+ //
+ if (!IsSelectable(NextMenuOption) && IsSelectable(MenuOption) &&
+ (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {
+ NewPos = SavedListEntry;
+ }
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiPageUp:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+ Repaint = TRUE;
+
+ Link = TopOfScreen;
+ //
+ // First minus the menu of the top screen, it's value is SkipValue.
+ //
+ if (SkipValue >= BottomRow - TopRow + 1) {
+ //
+ // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
+ // form of options to be show, so just update the SkipValue to show the next
+ // parts of options.
+ //
+ SkipValue -= BottomRow - TopRow + 1;
+ NewPos = TopOfScreen;
+ break;
+ } else {
+ Index = (BottomRow + 1) - SkipValue - TopRow;
+ }
+
+ TopOfScreen = FindTopOfScreenMenu(TopOfScreen, Index, &SkipValue);
+ NewPos = TopOfScreen;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, FALSE);
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ // Don't do this when we are already in the first page.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiPageDown:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+ Repaint = TRUE;
+
+ Link = TopOfScreen;
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);
+ Index = TopRow + NextMenuOption->Skip - SkipValue;
+ //
+ // Count to the menu option which will show at the top of the next form.
+ //
+ while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {
+ Link = Link->ForwardLink;
+ NextMenuOption = MENU_OPTION_FROM_LINK (Link);
+ Index = Index + NextMenuOption->Skip;
+ }
+
+ if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {
+ //
+ // Highlight on the last menu which can be highlight.
+ //
+ Repaint = FALSE;
+ MoveToNextStatement (TRUE, &Link, Index - TopRow, TRUE);
+ } else {
+ //
+ // Calculate the skip line for top of screen menu.
+ //
+ if (Link == TopOfScreen) {
+ //
+ // The top of screen menu option occupies the entire form.
+ //
+ SkipValue += BottomRow - TopRow + 1;
+ } else {
+ SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));
+ }
+ TopOfScreen = Link;
+ MenuOption = NULL;
+ //
+ // Move to the Next selectable menu.
+ //
+ MoveToNextStatement (FALSE, &Link, BottomRow - TopRow, TRUE);
+ }
+
+ //
+ // Save the menu as the next highlight menu.
+ //
+ NewPos = Link;
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
+ // Don't do this when we are already in the last page.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiDown:
+ //
+ // SkipValue means lines is skipped when show the top menu option.
+ // NewPos points to the menu which is highlighted now.
+ //
+ ControlFlag = CfRepaint;
+ NewLine = TRUE;
+
+ if (NewPos == TopOfScreen) {
+ Temp2 = SkipValue;
+ } else {
+ Temp2 = 0;
+ }
+
+ SavedListEntry = NewPos;
+ //
+ // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
+ // to be one that progresses to the next set of op-codes, we need to advance to the last
+ // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
+ // checking can be done. The only other logic we need to introduce is that if a Date/Time
+ // op-code is the last entry in the menu, we need to rewind back to the first op-code of
+ // the Date/Time op-code.
+ //
+ AdjustDateAndTimePosition (FALSE, &NewPos);
+
+ MenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ NewPos = NewPos->ForwardLink;
+ //
+ // Find the next selectable menu.
+ //
+ if (MenuOption->Row + MenuOption->Skip - Temp2 > BottomRow + 1) {
+ if (gMenuOption.ForwardLink == NewPos || &gMenuOption == NewPos) {
+ Difference = -1;
+ } else {
+ Difference = 0;
+ }
+ } else {
+ Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow + 1 - (MenuOption->Row + MenuOption->Skip - Temp2), FALSE);
+ }
+ if (Difference < 0) {
+ //
+ // Scroll to the first page.
+ //
+ if (TopOfScreen != gMenuOption.ForwardLink || SkipValue != 0) {
+ TopOfScreen = gMenuOption.ForwardLink;
+ Repaint = TRUE;
+ MenuOption = NULL;
+ } else {
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+ }
+ NewPos = gMenuOption.ForwardLink;
+ MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow, TRUE);
+
+ SkipValue = 0;
+ //
+ // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+ break;
+ }
+
+ //
+ // Get next selected menu info.
+ //
+ AdjustDateAndTimePosition (FALSE, &NewPos);
+ NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
+ if (NextMenuOption->Row == 0) {
+ UpdateOptionSkipLines (NextMenuOption);
+ }
+
+ //
+ // Calculate new highlight menu end row.
+ //
+ Temp = (MenuOption->Row + MenuOption->Skip - Temp2) + Difference + NextMenuOption->Skip - 1;
+ if (Temp > BottomRow) {
+ //
+ // Get the top screen menu info.
+ //
+ AdjustDateAndTimePosition (FALSE, &TopOfScreen);
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+
+ //
+ // Current Top screen menu occupy (SavedMenuOption->Skip - SkipValue) rows.
+ // Full shows the new selected menu need to skip (Temp - BottomRow - 1) rows.
+ //
+ if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {
+ //
+ // Skip the top op-code
+ //
+ TopOfScreen = TopOfScreen->ForwardLink;
+ DistanceValue = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);
+
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+
+ //
+ // If we have a remainder, skip that many more op-codes until we drain the remainder
+ // Special case is the selected highlight menu has more than one form of menus.
+ //
+ while (DistanceValue >= SavedMenuOption->Skip && TopOfScreen != NewPos) {
+ //
+ // Since the Difference is greater than or equal to this op-code's skip value, skip it
+ //
+ DistanceValue = DistanceValue - (INTN) SavedMenuOption->Skip;
+ TopOfScreen = TopOfScreen->ForwardLink;
+ SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
+ }
+ //
+ // Since we will act on this op-code in the next routine, and increment the
+ // SkipValue, set the skips to one less than what is required.
+ //
+ if (TopOfScreen != NewPos) {
+ SkipValue = DistanceValue;
+ } else {
+ SkipValue = 0;
+ }
+ } else {
+ //
+ // Since we will act on this op-code in the next routine, and increment the
+ // SkipValue, set the skips to one less than what is required.
+ //
+ SkipValue += Temp - BottomRow;
+ }
+ Repaint = TRUE;
+ } else if (!IsSelectable (NextMenuOption)) {
+ //
+ // Continue to go down until scroll to next page or the selectable option is found.
+ //
+ ScreenOperation = UiDown;
+ ControlFlag = CfScreenOperation;
+ break;
+ }
+
+ MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
+
+ //
+ // Check whether new highlight menu is selectable, if not, keep highlight on the old one.
+ //
+ // BottomRow - TopRow + 1 means the total rows current forms supported.
+ // Difference + NextMenuOption->Skip + 1 means the distance between last highlight menu
+ // and new top menu. New top menu will all shows in next form, but last highlight menu
+ // may only shows 1 line. + 1 at right part means at least need to keep 1 line for the
+ // last highlight menu.
+ //
+ if (!IsSelectable (NextMenuOption) && IsSelectable (MenuOption) &&
+ (BottomRow - TopRow + 1 >= Difference + NextMenuOption->Skip + 1)) {
+ NewPos = SavedListEntry;
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ //
+ // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
+ //
+ AdjustDateAndTimePosition (TRUE, &TopOfScreen);
+ AdjustDateAndTimePosition (TRUE, &NewPos);
+
+ UpdateHighlightMenuInfo(NewPos, TopOfScreen, SkipValue);
+ break;
+
+ case CfUiNoOperation:
+ ControlFlag = CfRepaint;
+ break;
+
+ case CfExit:
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ if (HelpString != NULL) {
+ FreePool (HelpString);
+ }
+ if (HelpHeaderString != NULL) {
+ FreePool (HelpHeaderString);
+ }
+ if (HelpBottomString != NULL) {
+ FreePool (HelpBottomString);
+ }
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ Free the UI Menu Option structure data.
+
+ @param MenuOptionList Point to the menu option list which need to be free.
+
+**/
+VOID
+FreeMenuOptionData(
+ LIST_ENTRY *MenuOptionList
+ )
+{
+ LIST_ENTRY *Link;
+ UI_MENU_OPTION *Option;
+
+ //
+ // Free menu option list
+ //
+ while (!IsListEmpty (MenuOptionList)) {
+ Link = GetFirstNode (MenuOptionList);
+ Option = MENU_OPTION_FROM_LINK (Link);
+ if (Option->Description != NULL){
+ FreePool(Option->Description);
+ }
+ RemoveEntryList (&Option->Link);
+ FreePool (Option);
+ }
+}
+
+/**
+
+ Base on the browser status info to show an pop up message.
+
+**/
+VOID
+BrowserStatusProcess (
+ VOID
+ )
+{
+ CHAR16 *ErrorInfo;
+ EFI_INPUT_KEY Key;
+ EFI_EVENT WaitList[2];
+ EFI_EVENT RefreshIntervalEvent;
+ EFI_EVENT TimeOutEvent;
+ UINT8 TimeOut;
+ EFI_STATUS Status;
+ UINTN Index;
+ WARNING_IF_CONTEXT EventContext;
+ EFI_IFR_OP_HEADER *OpCodeBuf;
+ EFI_STRING_ID StringToken;
+ CHAR16 DiscardChange;
+ CHAR16 JumpToFormSet;
+ CHAR16 *PrintString;
+
+ if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
+ return;
+ }
+
+ StringToken = 0;
+ TimeOutEvent = NULL;
+ RefreshIntervalEvent = NULL;
+ OpCodeBuf = NULL;
+ if (gFormData->HighLightedStatement != NULL) {
+ OpCodeBuf = gFormData->HighLightedStatement->OpCode;
+ }
+
+ if (gFormData->BrowserStatus == (BROWSER_WARNING_IF)) {
+ ASSERT (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_WARNING_IF_OP);
+
+ TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->TimeOut;
+ StringToken = ((EFI_IFR_WARNING_IF *) OpCodeBuf)->Warning;
+ } else {
+ TimeOut = 0;
+ if ((gFormData->BrowserStatus == (BROWSER_NO_SUBMIT_IF)) &&
+ (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_NO_SUBMIT_IF_OP)) {
+ StringToken = ((EFI_IFR_NO_SUBMIT_IF *) OpCodeBuf)->Error;
+ } else if ((gFormData->BrowserStatus == (BROWSER_INCONSISTENT_IF)) &&
+ (OpCodeBuf != NULL && OpCodeBuf->OpCode == EFI_IFR_INCONSISTENT_IF_OP)) {
+ StringToken = ((EFI_IFR_INCONSISTENT_IF *) OpCodeBuf)->Error;
+ }
+ }
+
+ if (StringToken != 0) {
+ ErrorInfo = GetToken (StringToken, gFormData->HiiHandle);
+ } else if (gFormData->ErrorString != NULL) {
+ //
+ // Only used to compatible with old setup browser.
+ // Not use this field in new browser core.
+ //
+ ErrorInfo = gFormData->ErrorString;
+ } else {
+ switch (gFormData->BrowserStatus) {
+ case BROWSER_SUBMIT_FAIL:
+ ErrorInfo = gSaveFailed;
+ break;
+
+ case BROWSER_FORM_NOT_FOUND:
+ ErrorInfo = gFormNotFound;
+ break;
+
+ case BROWSER_FORM_SUPPRESS:
+ ErrorInfo = gFormSuppress;
+ break;
+
+ case BROWSER_PROTOCOL_NOT_FOUND:
+ ErrorInfo = gProtocolNotFound;
+ break;
+
+ case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
+ ErrorInfo = gNoSubmitIfFailed;
+ break;
+
+ case BROWSER_RECONNECT_FAIL:
+ ErrorInfo = gReconnectFail;
+ break;
+
+ case BROWSER_RECONNECT_SAVE_CHANGES:
+ ErrorInfo = gReconnectConfirmChanges;
+ break;
+
+ case BROWSER_RECONNECT_REQUIRED:
+ ErrorInfo = gReconnectRequired;
+ break;
+
+ default:
+ ErrorInfo = gBrowserError;
+ break;
+ }
+ }
+
+ switch (gFormData->BrowserStatus) {
+ case BROWSER_SUBMIT_FAIL:
+ case BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF:
+ case BROWSER_RECONNECT_SAVE_CHANGES:
+ ASSERT (gUserInput != NULL);
+ if (gFormData->BrowserStatus == (BROWSER_SUBMIT_FAIL)) {
+ PrintString = gSaveProcess;
+ JumpToFormSet = gJumpToFormSet[0];
+ DiscardChange = gDiscardChange[0];
+ } else if (gFormData->BrowserStatus == (BROWSER_RECONNECT_SAVE_CHANGES)){
+ PrintString = gChangesOpt;
+ JumpToFormSet = gConfirmOptYes[0];
+ DiscardChange = gConfirmOptNo[0];
+ } else {
+ PrintString = gSaveNoSubmitProcess;
+ JumpToFormSet = gCheckError[0];
+ DiscardChange = gDiscardChange[0];
+ }
+
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, PrintString, gEmptyString, NULL);
+ } while (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (DiscardChange | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (JumpToFormSet | UPPER_LOWER_CASE_OFFSET)));
+
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (DiscardChange | UPPER_LOWER_CASE_OFFSET)) {
+ gUserInput->Action = BROWSER_ACTION_DISCARD;
+ } else {
+ gUserInput->Action = BROWSER_ACTION_GOTO;
+ }
+ break;
+
+ default:
+ if (TimeOut == 0) {
+ do {
+ CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ } else {
+ Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK, EmptyEventProcess, NULL, &TimeOutEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ EventContext.SyncEvent = TimeOutEvent;
+ EventContext.TimeOut = &TimeOut;
+ EventContext.ErrorInfo = ErrorInfo;
+
+ Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshTimeOutProcess, &EventContext, &RefreshIntervalEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Show the dialog first to avoid long time not reaction.
+ //
+ gBS->SignalEvent (RefreshIntervalEvent);
+
+ Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, ONE_SECOND);
+ ASSERT_EFI_ERROR (Status);
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status) && Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ break;
+ }
+
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ WaitList[0] = TimeOutEvent;
+ WaitList[1] = gST->ConIn->WaitForKey;
+
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Index == 0) {
+ //
+ // Timeout occur, close the hoot time out event.
+ //
+ break;
+ }
+ }
+
+ gBS->CloseEvent (TimeOutEvent);
+ gBS->CloseEvent (RefreshIntervalEvent);
+ }
+ break;
+ }
+
+ if (StringToken != 0) {
+ FreePool (ErrorInfo);
+ }
+}
+
+/**
+ Display one form, and return user input.
+
+ @param FormData Form Data to be shown.
+ @param UserInputData User input data.
+
+ @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
+ 2.Error info has show and return.
+ @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
+ @retval EFI_NOT_FOUND New form data has some error.
+**/
+EFI_STATUS
+EFIAPI
+FormDisplay (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FormData != NULL);
+ if (FormData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gUserInput = UserInputData;
+ gFormData = FormData;
+
+ //
+ // Process the status info first.
+ //
+ BrowserStatusProcess();
+ if (gFormData->BrowserStatus != BROWSER_SUCCESS) {
+ //
+ // gFormData->BrowserStatus != BROWSER_SUCCESS, means only need to print the error info, return here.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = DisplayPageFrame (FormData, &gStatementDimensions);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Global Widths should be initialized before any MenuOption creation
+ // or the GetWidth() used in UiAddMenuOption() will return incorrect value.
+ //
+ //
+ // Left right
+ // |<-.->|<-.........->|<- .........->|<-...........->|
+ // Skip Prompt Option Help
+ //
+ gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3) + 1;
+ gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - 1 - LEFT_SKIPPED_COLUMNS);
+ gPromptBlockWidth = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * (gOptionBlockWidth - 1) - 1);
+
+ ConvertStatementToMenu();
+
+ //
+ // Check whether layout is changed.
+ //
+ if (mIsFirstForm
+ || (gOldFormEntry.HiiHandle != FormData->HiiHandle)
+ || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))
+ || (gOldFormEntry.FormId != FormData->FormId)) {
+ mStatementLayoutIsChanged = TRUE;
+ } else {
+ mStatementLayoutIsChanged = FALSE;
+ }
+
+ Status = UiDisplayMenu(FormData);
+
+ //
+ // Backup last form info.
+ //
+ mIsFirstForm = FALSE;
+ gOldFormEntry.HiiHandle = FormData->HiiHandle;
+ CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid);
+ gOldFormEntry.FormId = FormData->FormId;
+
+ //
+ //Free the Ui menu option list.
+ //
+ FreeMenuOptionData(&gMenuOption);
+
+ return Status;
+}
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+DriverClearDisplayPage (
+ VOID
+ )
+{
+ ClearDisplayPage ();
+ mIsFirstForm = TRUE;
+}
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+SetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ )
+{
+ CHAR16 *Ptr;
+
+ Ptr = Buffer;
+ while ((Size--) != 0) {
+ *(Ptr++) = Value;
+ }
+}
+
+/**
+ Initialize Setup Browser driver.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
+ @return Other value if failed to initialize the Setup Browser module.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDisplayEngine (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY HotKey;
+ EFI_STRING NewString;
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
+
+ //
+ // Publish our HII data
+ //
+ gHiiHandle = HiiAddPackages (
+ &gDisplayEngineGuid,
+ ImageHandle,
+ DisplayEngineStrings,
+ NULL
+ );
+ ASSERT (gHiiHandle != NULL);
+
+ //
+ // Install Form Display protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FromDisplayProt
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install HII Popup Protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEfiHiiPopupProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.HiiPopup
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeDisplayStrings();
+
+ ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo));
+ ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry));
+
+ //
+ // Use BrowserEx2 protocol to register HotKey.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Register the default HotKey F9 and F10 again.
+ //
+ HotKey.UnicodeChar = CHAR_NULL;
+ HotKey.ScanCode = SCAN_F10;
+ NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);
+ FreePool (NewString);
+
+ HotKey.ScanCode = SCAN_F9;
+ NewString = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);
+ FreePool (NewString);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the default unload handle for display core drivers.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+UnloadDisplayEngine (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ HiiRemovePackages(gHiiHandle);
+
+ FreeDisplayStrings ();
+
+ if (gHighligthMenuInfo.HLTOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.HLTOpCode);
+ }
+
+ if (gHighligthMenuInfo.TOSOpCode != NULL) {
+ FreePool (gHighligthMenuInfo.TOSOpCode);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h
new file mode 100644
index 000000000..e6d3ae417
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h
@@ -0,0 +1,741 @@
+/** @file
+ FormDiplay protocol to show Form
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FORM_DISPLAY_H__
+#define __FORM_DISPLAY_H__
+
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/CustomizedDisplayLib.h>
+
+#include <Protocol/FormBrowserEx2.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/DisplayProtocol.h>
+#include <Protocol/HiiPopup.h>
+
+#include <Guid/MdeModuleHii.h>
+
+//
+// This is the generated header file which includes whatever needs to be exported (strings + IFR)
+//
+extern UINT8 DisplayEngineStrings[];
+extern EFI_SCREEN_DESCRIPTOR gStatementDimensions;
+extern USER_INPUT *gUserInput;
+extern FORM_DISPLAY_ENGINE_FORM *gFormData;
+extern EFI_HII_HANDLE gHiiHandle;
+extern UINT16 gDirection;
+extern LIST_ENTRY gMenuOption;
+extern CHAR16 *gConfirmOptYes;
+extern CHAR16 *gConfirmOptNo;
+extern CHAR16 *gConfirmOptOk;
+extern CHAR16 *gConfirmOptCancel;
+extern CHAR16 *gYesOption;
+extern CHAR16 *gNoOption;
+extern CHAR16 *gOkOption;
+extern CHAR16 *gCancelOption;
+extern CHAR16 *gErrorPopup;
+extern CHAR16 *gWarningPopup;
+extern CHAR16 *gInfoPopup;
+
+//
+// Browser Global Strings
+//
+extern CHAR16 *gSaveFailed;
+extern CHAR16 *gPromptForData;
+extern CHAR16 *gPromptForPassword;
+extern CHAR16 *gPromptForNewPassword;
+extern CHAR16 *gConfirmPassword;
+extern CHAR16 *gConfirmError;
+extern CHAR16 *gPassowordInvalid;
+extern CHAR16 *gPressEnter;
+extern CHAR16 *gEmptyString;
+extern CHAR16 *gMiniString;
+extern CHAR16 *gOptionMismatch;
+extern CHAR16 *gFormSuppress;
+extern CHAR16 *gProtocolNotFound;
+extern CHAR16 *gPasswordUnsupported;
+
+extern CHAR16 gPromptBlockWidth;
+extern CHAR16 gOptionBlockWidth;
+extern CHAR16 gHelpBlockWidth;
+extern CHAR16 *mUnknownString;
+extern BOOLEAN gMisMatch;
+
+//
+// Screen definitions
+//
+
+#define LEFT_SKIPPED_COLUMNS 3
+#define SCROLL_ARROW_HEIGHT 1
+#define POPUP_PAD_SPACE_COUNT 5
+#define POPUP_FRAME_WIDTH 2
+
+#define UPPER_LOWER_CASE_OFFSET 0x20
+
+//
+// Display definitions
+//
+#define LEFT_ONEOF_DELIMITER L'<'
+#define RIGHT_ONEOF_DELIMITER L'>'
+
+#define LEFT_NUMERIC_DELIMITER L'['
+#define RIGHT_NUMERIC_DELIMITER L']'
+
+#define LEFT_CHECKBOX_DELIMITER L'['
+#define RIGHT_CHECKBOX_DELIMITER L']'
+
+#define CHECK_ON L'X'
+#define CHECK_OFF L' '
+
+#define TIME_SEPARATOR L':'
+#define DATE_SEPARATOR L'/'
+
+#define SUBTITLE_INDENT 2
+
+//
+// This is the Input Error Message
+//
+#define INPUT_ERROR 1
+
+//
+// This is the NV RAM update required Message
+//
+#define NV_UPDATE_REQUIRED 2
+//
+// Time definitions
+//
+#define ONE_SECOND 10000000
+
+//
+// It take 23 characters including the NULL to print a 64 bits number with "[" and "]".
+// pow(2, 64) = [18446744073709551616]
+// with extra '-' flat, set the width to 24.
+//
+#define MAX_NUMERIC_INPUT_WIDTH 24
+
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
+#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
+#define EFI_HII_EXPRESSION_DISABLE_IF 4
+
+//
+// Character definitions
+//
+#define CHAR_SPACE 0x0020
+
+#define FORM_DISPLAY_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'D', 'D', 'V')
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ //
+ // Produced protocol
+ //
+ EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FromDisplayProt;
+ EFI_HII_POPUP_PROTOCOL HiiPopup;
+} FORM_DISPLAY_DRIVER_PRIVATE_DATA;
+
+
+typedef enum {
+ UiNoOperation,
+ UiSelect,
+ UiUp,
+ UiDown,
+ UiLeft,
+ UiRight,
+ UiReset,
+ UiPrevious,
+ UiPageUp,
+ UiPageDown,
+ UiHotKey,
+ UiMaxOperation
+} UI_SCREEN_OPERATION;
+
+typedef enum {
+ CfInitialization,
+ CfCheckSelection,
+ CfRepaint,
+ CfRefreshHighLight,
+ CfUpdateHelpString,
+ CfPrepareToReadKey,
+ CfReadKey,
+ CfScreenOperation,
+ CfUiSelect,
+ CfUiReset,
+ CfUiLeft,
+ CfUiRight,
+ CfUiUp,
+ CfUiPageUp,
+ CfUiPageDown,
+ CfUiDown,
+ CfUiNoOperation,
+ CfExit,
+ CfUiHotKey,
+ CfMaxControlFlag
+} UI_CONTROL_FLAG;
+
+typedef enum {
+ UIEventNone,
+ UIEventKey,
+ UIEventTimeOut,
+ UIEventDriver
+} UI_EVENT_TYPE;
+
+typedef struct {
+ UINT16 ScanCode;
+ UI_SCREEN_OPERATION ScreenOperation;
+} SCAN_CODE_TO_SCREEN_OPERATION;
+
+typedef struct {
+ UI_SCREEN_OPERATION ScreenOperation;
+ UI_CONTROL_FLAG ControlFlag;
+} SCREEN_OPERATION_T0_CONTROL_FLAG;
+
+typedef struct {
+ EFI_HII_HANDLE HiiHandle;
+ UINT16 FormId;
+
+ //
+ // Info for the highlight question.
+ // HLT means highlight
+ //
+ // If one statement has questionid, save questionid info to find the question.
+ // If one statement not has questionid info, save the opcode info to find the
+ // statement. If more than one statement has same opcode in one form(just like
+ // empty subtitle info may has more than one info one form), also use Index
+ // info to find the statement.
+ //
+ EFI_QUESTION_ID HLTQuestionId;
+ EFI_IFR_OP_HEADER *HLTOpCode;
+ UINTN HLTIndex;
+ UINTN HLTSequence;
+
+ //
+ // Info for the top of screen question.
+ // TOS means Top Of Screen
+ //
+ EFI_QUESTION_ID TOSQuestionId;
+ EFI_IFR_OP_HEADER *TOSOpCode;
+ UINTN TOSIndex;
+
+ UINT16 SkipValue;
+} DISPLAY_HIGHLIGHT_MENU_INFO;
+
+typedef struct {
+ EFI_EVENT SyncEvent;
+ UINT8 *TimeOut;
+ CHAR16 *ErrorInfo;
+} WARNING_IF_CONTEXT;
+
+#define UI_MENU_OPTION_SIGNATURE SIGNATURE_32 ('u', 'i', 'm', 'm')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_HII_HANDLE Handle;
+ FORM_DISPLAY_ENGINE_STATEMENT *ThisTag;
+ UINT16 EntryNumber;
+
+ UINTN Row;
+ UINTN Col;
+ UINTN OptCol;
+ CHAR16 *Description;
+ UINTN Skip; // Number of lines
+
+ //
+ // Display item sequence for date/time
+ // Date: Month/Day/Year
+ // Sequence: 0 1 2
+ //
+ // Time: Hour : Minute : Second
+ // Sequence: 0 1 2
+ //
+ //
+ UINTN Sequence;
+
+ BOOLEAN GrayOut;
+ BOOLEAN ReadOnly;
+
+ //
+ // Whether user could change value of this item
+ //
+ BOOLEAN IsQuestion;
+ BOOLEAN NestInStatement;
+} UI_MENU_OPTION;
+
+#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE)
+
+#define USER_SELECTABLE_OPTION_OK_WIDTH StrLen (gOkOption)
+#define USER_SELECTABLE_OPTION_OK_CAL_WIDTH (StrLen (gOkOption) + StrLen (gCancelOption))
+#define USER_SELECTABLE_OPTION_YES_NO_WIDTH (StrLen (gYesOption) + StrLen (gNoOption))
+#define USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH (StrLen (gYesOption) + StrLen (gNoOption) + StrLen (gCancelOption))
+
+#define USER_SELECTABLE_OPTION_SKIP_WIDTH 2
+
+//
+// +-------------------------------------------+ // POPUP_BORDER }
+// | ERROR/WARNING/INFO | // POPUP_STYLE_STRING_HEIGHT } POPUP_HEADER_HEIGHT
+// |-------------------------------------------| // POPUP_EMPTY_LINE_HEIGHT }
+// | popup messages |
+// | | // POPUP_EMPTY_LINE_HEIGHT }
+// | user selectable options | // POPUP_USER_SELECTABLE_OPTION_HEIGHT } POPUP_FOOTER_HEIGHT
+// +-------------------------------------------+ // POPUP_BORDER }
+//
+#define POPUP_BORDER 1
+#define POPUP_EMPTY_LINE_HEIGHT 1
+#define POPUP_STYLE_STRING_HEIGHT 1
+#define POPUP_USER_SELECTABLE_OPTION_HEIGHT 1
+
+#define POPUP_HEADER_HEIGHT (POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT + POPUP_EMPTY_LINE_HEIGHT)
+#define POPUP_FOOTER_HEIGHT (POPUP_EMPTY_LINE_HEIGHT + POPUP_USER_SELECTABLE_OPTION_HEIGHT + POPUP_BORDER)
+
+#define USER_SELECTABLE_OPTION_SIGNATURE SIGNATURE_32 ('u', 's', 's', 'o')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HII_POPUP_SELECTION OptionType;
+ CHAR16 *OptionString;
+ //
+ // Display item sequence for user select options
+ // Ok: Ok
+ // Sequence: 0
+ //
+ // Ok/Cancel: Ok : Cancel
+ // Sequence: 0 1
+ //
+ // Yes/No: Yes : No
+ // Sequence: 0 1
+ //
+ // Yes/No/Cancel: Yes : No: Cancel
+ // Sequence: 0 1 2
+ //
+ UINTN Sequence;
+ UINTN OptionRow;
+ UINTN OptionCol;
+ UINTN MaxSequence;
+ UINTN MinSequence;
+} USER_SELECTABLE_OPTION;
+
+#define SELECTABLE_OPTION_FROM_LINK(a) CR (a, USER_SELECTABLE_OPTION, Link, USER_SELECTABLE_OPTION_SIGNATURE)
+
+/**
+ Print Question Value according to it's storage width and display attributes.
+
+ @param Question The Question to be printed.
+ @param FormattedNumber Buffer for output string.
+ @param BufferSize The FormattedNumber buffer size in bytes.
+
+ @retval EFI_SUCCESS Print success.
+ @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
+
+**/
+EFI_STATUS
+PrintFormattedNumber (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
+ IN OUT CHAR16 *FormattedNumber,
+ IN UINTN BufferSize
+ );
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ );
+
+/**
+ Return data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+
+ @retval Value The data to be returned
+
+**/
+UINT64
+GetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index
+ );
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+DISPLAY_QUESTION_OPTION *
+ValueToOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ );
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param Result Return value after compare.
+ retval 0 Two operators equal.
+ return Positive value if Value1 is greater than Value2.
+ retval Negative value if Value1 is less than Value2.
+ @param HiiHandle Only required for string compare.
+
+ @retval other Could not perform compare on two values.
+ @retval EFI_SUCCESS Compare the value success.
+
+**/
+EFI_STATUS
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ OUT INTN *Result,
+ IN EFI_HII_HANDLE HiiHandle OPTIONAL
+ );
+
+/**
+ Draw a pop up windows based on the dimension, number of lines and
+ strings specified.
+
+ @param RequestedWidth The width of the pop-up.
+ @param NumberOfLines The number of lines.
+ @param ... A series of text strings that displayed in the pop-up.
+
+**/
+VOID
+EFIAPI
+CreateMultiStringPopUp (
+ IN UINTN RequestedWidth,
+ IN UINTN NumberOfLines,
+ ...
+ );
+
+/**
+ Will copy LineWidth amount of a string in the OutputString buffer and return the
+ number of CHAR16 characters that were copied into the OutputString buffer.
+ The output string format is:
+ Glyph Info + String info + '\0'.
+
+ In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
+
+ @param InputString String description for this option.
+ @param LineWidth Width of the desired string to extract in CHAR16
+ characters
+ @param GlyphWidth The glyph width of the begin of the char in the string.
+ @param Index Where in InputString to start the copy process
+ @param OutputString Buffer to copy the string into
+
+ @return Returns the number of CHAR16 characters that were copied into the OutputString
+ buffer, include extra glyph info and '\0' info.
+
+**/
+UINT16
+GetLineByWidth (
+ IN CHAR16 *InputString,
+ IN UINT16 LineWidth,
+ IN OUT UINT16 *GlyphWidth,
+ IN OUT UINTN *Index,
+ OUT CHAR16 **OutputString
+ );
+
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The Hii handle for this string package.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+GetStringWidth (
+ IN CHAR16 *String
+ );
+
+/**
+ This routine reads a numeric value from the user input.
+
+ @param MenuOption Pointer to the current input menu.
+
+ @retval EFI_SUCCESS If numerical input is read successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+GetNumericInput (
+ IN UI_MENU_OPTION *MenuOption
+ );
+
+/**
+ Get string or password input from user.
+
+ @param MenuOption Pointer to the current input menu.
+ @param Prompt The prompt string shown on popup window.
+ @param StringPtr Old user input and destination for use input string.
+
+ @retval EFI_SUCCESS If string input is read successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+ReadString (
+ IN UI_MENU_OPTION *MenuOption,
+ IN CHAR16 *Prompt,
+ IN OUT CHAR16 *StringPtr
+ );
+
+/**
+ Draw a pop up windows based on the dimension, number of lines and
+ strings specified.
+
+ @param RequestedWidth The width of the pop-up.
+ @param NumberOfLines The number of lines.
+ @param Marker The variable argument list for the list of string to be printed.
+
+**/
+VOID
+CreateSharedPopUp (
+ IN UINTN RequestedWidth,
+ IN UINTN NumberOfLines,
+ IN VA_LIST Marker
+ );
+
+/**
+ Wait for a key to be pressed by user.
+
+ @param Key The key which is pressed by user.
+
+ @retval EFI_SUCCESS The function always completed successfully.
+
+**/
+EFI_STATUS
+WaitForKeyStroke (
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Get selection for OneOf and OrderedList (Left/Right will be ignored).
+
+ @param MenuOption Pointer to the current input menu.
+
+ @retval EFI_SUCCESS If Option input is processed successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+GetSelectionInputPopUp (
+ IN UI_MENU_OPTION *MenuOption
+ );
+
+/**
+ Process the help string: Split StringPtr to several lines of strings stored in
+ FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
+
+ @param StringPtr The entire help string.
+ @param FormattedString The oupput formatted string.
+ @param EachLineWidth The max string length of each line in the formatted string.
+ @param RowCount TRUE: if Question is selected.
+
+**/
+UINTN
+ProcessHelpString (
+ IN CHAR16 *StringPtr,
+ OUT CHAR16 **FormattedString,
+ OUT UINT16 *EachLineWidth,
+ IN UINTN RowCount
+ );
+
+/**
+ Process a Question's Option (whether selected or un-selected).
+
+ @param MenuOption The MenuOption for this Question.
+ @param Selected TRUE: if Question is selected.
+ @param OptionString Pointer of the Option String to be displayed.
+ @param SkipErrorValue Whether need to return when value without option for it.
+
+ @retval EFI_SUCCESS Question Option process success.
+ @retval Other Question Option process fail.
+
+**/
+EFI_STATUS
+ProcessOptions (
+ IN UI_MENU_OPTION *MenuOption,
+ IN BOOLEAN Selected,
+ OUT CHAR16 **OptionString,
+ IN BOOLEAN SkipErrorValue
+ );
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+SetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ );
+
+/**
+ Display one form, and return user input.
+
+ @param FormData Form Data to be shown.
+ @param UserInputData User input data.
+
+ @retval EFI_SUCCESS Form Data is shown, and user input is got.
+**/
+EFI_STATUS
+EFIAPI
+FormDisplay (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+ );
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+DriverClearDisplayPage (
+ VOID
+ );
+
+/**
+ Exit Display and Clear Screen to the original state.
+
+**/
+VOID
+EFIAPI
+ExitDisplay (
+ VOID
+ );
+
+/**
+ Process nothing.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
+
+**/
+VOID
+EFIAPI
+EmptyEventProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Process for the refresh interval statement.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
+
+**/
+VOID
+EFIAPI
+RefreshTimeOutProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Record the highlight menu and top of screen menu info.
+
+ @param Highlight The menu opton which is highlight.
+ @param TopOfScreen The menu opton which is at the top of the form.
+ @param SkipValue The skip line info for the top of screen menu.
+
+**/
+VOID
+UpdateHighlightMenuInfo (
+ IN LIST_ENTRY *Highlight,
+ IN LIST_ENTRY *TopOfScreen,
+ IN UINTN SkipValue
+ );
+
+/**
+ Displays a popup window.
+
+ @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance.
+ @param PopupStyle Popup style to use.
+ @param PopupType Type of the popup to display.
+ @param HiiHandle HII handle of the string pack containing Message
+ @param Message A message to display in the popup box.
+ @param UserSelection User selection.
+
+ @retval EFI_SUCCESS The popup box was successfully displayed.
+ @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string.
+ @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box.
+
+**/
+EFI_STATUS
+EFIAPI
+CreatePopup (
+ IN EFI_HII_POPUP_PROTOCOL *This,
+ IN EFI_HII_POPUP_STYLE PopupStyle,
+ IN EFI_HII_POPUP_TYPE PopupType,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID Message,
+ OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni
new file mode 100644
index 000000000..5e3c35a2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni
@@ -0,0 +1,134 @@
+// *++
+//
+// Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// SetupBrowserStr.uni
+//
+// Abstract:
+//
+// String definitions for Browser.
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string UNKNOWN_STRING #language en-US "!"
+ #language fr-FR "!"
+#string STATUS_BROWSER_ERROR #language en-US "Browser met some error, return!"
+ #language fr-FR "Browser met some error, return!"
+#string STATUS_BROWSER_FORM_NOT_FOUND #language en-US "Form not found, return!"
+ #language fr-FR "Form not found, return!"
+#string STATUS_BROWSER_NO_SUBMIT_IF #language en-US "Not allowed to submit, return!"
+ #language fr-FR "Not allowed to submit, return!"
+#string FUNCTION_NINE_STRING #language en-US "F9=Reset to Defaults"
+ #language fr-FR "F9=Reset à Défauts"
+#string FUNCTION_TEN_STRING #language en-US "F10=Save"
+ #language fr-FR "F10=Économiser"
+#string SAVE_FAILED #language en-US "Failed to Save"
+ #language fr-FR "Échouer à économiser"
+#string NO_SUBMIT_IF_CHECK_FAILED #language en-US "NO_SUBMIT_IF check fail."
+ #language fr-FR "NO_SUBMIT_IF check fail."
+#string ADJUST_HELP_PAGE_DOWN #language en-US "More (D/d)"
+ #language fr-FR "More (D/d)"
+#string ADJUST_HELP_PAGE_UP #language en-US "More (U/u)"
+ #language fr-FR "More (U/u)"
+#string PROMPT_FOR_PASSWORD #language en-US "Please type in your password"
+ #language fr-FR "S'il vous plaît tape votre mot de passe"
+#string PROMPT_FOR_NEW_PASSWORD #language en-US "Please type in your new password"
+ #language fr-FR "S'il vous plaît tape votre nouveau mot de passe"
+#string CONFIRM_PASSWORD #language en-US "Please confirm your new password"
+ #language fr-FR "S'il vous plaît confirmer votre nouveau mot de passe"
+#string CONFIRM_ERROR #language en-US "Passwords are not the same"
+ #language fr-FR "Les mots de passe ne sont pas pareils"
+#string PASSWORD_INVALID #language en-US "Incorrect password"
+ #language fr-FR "Mauvais mot de passe"
+#string PRESS_ENTER #language en-US "Press ENTER to continue"
+ #language fr-FR "La presse ENTRE continuer"
+#string PROMPT_FOR_DATA #language en-US "Please type in your data"
+ #language fr-FR "S'il vous plaît tape vos données"
+#string EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+#string MINI_STRING #language en-US "Please enter enough characters"
+ #language fr-FR "Veuillez écrire assez de caractères"
+#string OPTION_MISMATCH #language en-US "Question value mismatch with Option value!"
+ #language fr-FR "Question valeur décalage avec l'option valeur!"
+#string FORM_SUPPRESSED #language en-US "Form is suppressed. Nothing is displayed."
+ #language fr-FR "Form is suppressed. Nothing is displayed."
+#string PROTOCOL_NOT_FOUND #language en-US "Convert string to device path fail. Can't goto the destination."
+ #language fr-FR "Convert string to device path fail. Can't goto the destination."
+#string DISCARD_OR_JUMP #language en-US "Press D(d) to discard changes for this form, Press G(g) to go to this form"
+ #language fr-FR "Press D(d) to discard changes for this form, Press G(g) to go to this form"
+#string DISCARD_OR_JUMP_DISCARD #language en-US "D (d)"
+ #language fr-FR "D (d)"
+#string DISCARD_OR_JUMP_JUMP #language en-US "G (g)"
+ #language fr-FR "G (g)"
+#string DISCARD_OR_CHECK #language en-US "Press D(d) to discard changes for this form, Press C(c) to check the error"
+ #language fr-FR "Press D(d) to discard changes for this form, Press C(c) to check the error"
+#string DISCARD_OR_CHECK_CHECK #language en-US "C (c)"
+ #language fr-FR "C (c)"
+#string CONFIRM_DISCARD_MESSAGE #language en-US "Discard configuration changes"
+ #language fr-FR "Discard configuration changes"
+#string CONFIRM_DEFAULT_MESSAGE #language en-US "Load default configuration"
+ #language fr-FR "Load default configuration"
+#string CONFIRM_DEFAULT_MESSAGE_2ND #language en-US "load default configuration"
+ #language fr-FR "load default configuration"
+#string CONFIRM_SUBMIT_MESSAGE #language en-US "Save configuration changes"
+ #language fr-FR "Save configuration changes"
+#string CONFIRM_SUBMIT_MESSAGE_2ND #language en-US "save configuration changes"
+ #language fr-FR "save configuration changes"
+#string CONFIRM_RESET_MESSAGE #language en-US "Reset"
+ #language fr-FR "Reset"
+#string CONFIRM_RESET_MESSAGE_2ND #language en-US "reset"
+ #language fr-FR "reset"
+#string CONFIRM_EXIT_MESSAGE #language en-US "Exit"
+ #language fr-FR "Exit"
+#string CONFIRM_EXIT_MESSAGE_2ND #language en-US "exit"
+ #language fr-FR "exit"
+#string CONFIRM_OPTION #language en-US "Press 'Y' to confirm, 'N'/'ESC' to ignore."
+ #language fr-FR "Press 'Y' to confirm, 'N'/'ESC' to ignore."
+#string CONFIRM_OPTION_YES #language en-US "Y (y)"
+ #language fr-FR "Y (y)"
+#string CONFIRM_OPTION_NO #language en-US "N (n)"
+ #language fr-FR "N (n)"
+#string CONFIRM_OPTION_OK #language en-US "O (o)"
+ #language fr-FR "O (o)"
+#string CONFIRM_OPTION_CANCEL #language en-US "C (c)"
+ #language fr-FR "C (c)"
+#string CONFIRM_OPTION_CONNECT #language en-US " and "
+ #language fr-FR " and "
+#string CONFIRM_OPTION_END #language en-US "?"
+ #language fr-FR "?"
+#string RECONNECT_FAILED #language en-US "Reconnect the controller failed!"
+ #language fr-FR "Reconnect the controller failed!"
+#string RECONNECT_CONFIRM_CHANGES #language en-US "Reconnect is required, confirm the changes then exit and reconnect"
+ #language fr-FR "Reconnect is required, confirm the changes then exit and reconnect"
+#string RECONNECT_CHANGES_OPTIONS #language en-US "Press 'Y' to save, 'N' to discard"
+ #language fr-FR "Press 'Y' to save, 'N' to discard"
+#string RECONNECT_REQUIRED #language en-US "Reconnect is required, exit and reconnect"
+ #language fr-FR "Reconnect is required, exit and reconnect"
+#string GET_TIME_FAIL #language en-US " Get date/time fail, display ??."
+ #language fr-FR " Get data/time fail, display ??."
+#string PASSWORD_NOT_SUPPORTED #language en-US "Unsupported! Because no interactieve flag or no ConfigAccess protocol!"
+ #language fr-FR "Unsupported! Because no interactieve flag or no ConfigAccess protocol!"
+#string OK_SELECTABLE_OPTION #language en-US "[ Ok ]"
+ #language fr-FR "[ Ok ]"
+#string CANCEL_SELECTABLE_OPTION #language en-US "[Cancel]"
+ #language fr-FR "[Cancel]"
+#string YES_SELECTABLE_OPTION #language en-US "[ Yes ]"
+ #language fr-FR "[ Yes ]"
+#string NO_SELECTABLE_OPTION #language en-US "[ No ]"
+ #language fr-FR "[ No ]"
+#string ERROR_POPUP_STRING #language en-US "ERROR"
+ #language fr-FR "ERROR"
+#string WARNING_POPUP_STRING #language en-US "WARNING"
+ #language fr-FR "WARNING"
+#string INFO_POPUP_STRING #language en-US "INFO"
+ #language fr-FR "INFO"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c
new file mode 100644
index 000000000..722c56aa2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c
@@ -0,0 +1,1664 @@
+/** @file
+Implementation for handling user input from the User Interfaces.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FormDisplay.h"
+
+/**
+ Get maximum and minimum info from this opcode.
+
+ @param OpCode Pointer to the current input opcode.
+ @param Minimum The minimum size info for this opcode.
+ @param Maximum The maximum size info for this opcode.
+
+**/
+VOID
+GetFieldFromOp (
+ IN EFI_IFR_OP_HEADER *OpCode,
+ OUT UINTN *Minimum,
+ OUT UINTN *Maximum
+ )
+{
+ EFI_IFR_STRING *StringOp;
+ EFI_IFR_PASSWORD *PasswordOp;
+ if (OpCode->OpCode == EFI_IFR_STRING_OP) {
+ StringOp = (EFI_IFR_STRING *) OpCode;
+ *Minimum = StringOp->MinSize;
+ *Maximum = StringOp->MaxSize;
+ } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
+ PasswordOp = (EFI_IFR_PASSWORD *) OpCode;
+ *Minimum = PasswordOp->MinSize;
+ *Maximum = PasswordOp->MaxSize;
+ } else {
+ *Minimum = 0;
+ *Maximum = 0;
+ }
+}
+
+/**
+ Get string or password input from user.
+
+ @param MenuOption Pointer to the current input menu.
+ @param Prompt The prompt string shown on popup window.
+ @param StringPtr Old user input and destination for use input string.
+
+ @retval EFI_SUCCESS If string input is read successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+ReadString (
+ IN UI_MENU_OPTION *MenuOption,
+ IN CHAR16 *Prompt,
+ IN OUT CHAR16 *StringPtr
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ CHAR16 NullCharacter;
+ UINTN ScreenSize;
+ CHAR16 Space[2];
+ CHAR16 KeyPad[2];
+ CHAR16 *TempString;
+ CHAR16 *BufferedString;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Count;
+ UINTN Start;
+ UINTN Top;
+ UINTN DimensionsWidth;
+ UINTN DimensionsHeight;
+ UINTN CurrentCursor;
+ BOOLEAN CursorVisible;
+ UINTN Minimum;
+ UINTN Maximum;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ BOOLEAN IsPassword;
+ UINTN MaxLen;
+
+ DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
+ DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
+
+ NullCharacter = CHAR_NULL;
+ ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);
+ Space[0] = L' ';
+ Space[1] = CHAR_NULL;
+
+ Question = MenuOption->ThisTag;
+ GetFieldFromOp(Question->OpCode, &Minimum, &Maximum);
+
+ if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
+ IsPassword = TRUE;
+ } else {
+ IsPassword = FALSE;
+ }
+
+ MaxLen = Maximum + 1;
+ TempString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (TempString);
+
+ if (ScreenSize < (Maximum + 1)) {
+ ScreenSize = Maximum + 1;
+ }
+
+ if ((ScreenSize + 2) > DimensionsWidth) {
+ ScreenSize = DimensionsWidth - 2;
+ }
+
+ BufferedString = AllocateZeroPool (ScreenSize * 2);
+ ASSERT (BufferedString);
+
+ Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;
+ Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;
+
+ //
+ // Display prompt for string
+ //
+ // CreateDialog (NULL, "", Prompt, Space, "", NULL);
+ CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
+
+ CursorVisible = gST->ConOut->Mode->CursorVisible;
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+
+ CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
+ if (CurrentCursor != 0) {
+ //
+ // Show the string which has beed saved before.
+ //
+ SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
+ PrintStringAt (Start + 1, Top + 3, BufferedString);
+
+ if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
+ Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
+ } else {
+ Index = 0;
+ }
+
+ if (IsPassword) {
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
+ }
+
+ for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
+ BufferedString[Count] = StringPtr[Index];
+
+ if (IsPassword) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
+ }
+ }
+
+ if (!IsPassword) {
+ PrintStringAt (Start + 1, Top + 3, BufferedString);
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
+ }
+
+ do {
+ Status = WaitForKeyStroke (&Key);
+ ASSERT_EFI_ERROR (Status);
+
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
+ switch (Key.UnicodeChar) {
+ case CHAR_NULL:
+ switch (Key.ScanCode) {
+ case SCAN_LEFT:
+ if (CurrentCursor > 0) {
+ CurrentCursor--;
+ }
+ break;
+
+ case SCAN_RIGHT:
+ if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
+ CurrentCursor++;
+ }
+ break;
+
+ case SCAN_ESC:
+ FreePool (TempString);
+ FreePool (BufferedString);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
+ return EFI_DEVICE_ERROR;
+
+ case SCAN_DELETE:
+ for (Index = CurrentCursor; StringPtr[Index] != CHAR_NULL; Index++) {
+ StringPtr[Index] = StringPtr[Index + 1];
+ PrintCharAt (Start + Index + 1, Top + 3, IsPassword && StringPtr[Index] != CHAR_NULL? L'*' : StringPtr[Index]);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
+
+ FreePool (TempString);
+ FreePool (BufferedString);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Simply create a popup to tell the user that they had typed in too few characters.
+ // To save code space, we can then treat this as an error and return back to the menu.
+ //
+ do {
+ CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ FreePool (TempString);
+ FreePool (BufferedString);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
+ return EFI_DEVICE_ERROR;
+ }
+
+
+ case CHAR_BACKSPACE:
+ if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {
+ for (Index = 0; Index < CurrentCursor - 1; Index++) {
+ TempString[Index] = StringPtr[Index];
+ }
+ Count = GetStringWidth (StringPtr) / 2 - 1;
+ if (Count >= CurrentCursor) {
+ for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {
+ TempString[Index] = StringPtr[Index2];
+ }
+ TempString[Index] = CHAR_NULL;
+ }
+ //
+ // Effectively truncate string by 1 character
+ //
+ StrCpyS (StringPtr, MaxLen, TempString);
+ CurrentCursor --;
+ }
+
+ default:
+ //
+ // If it is the beginning of the string, don't worry about checking maximum limits
+ //
+ if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
+ StrnCpyS (StringPtr, MaxLen, &Key.UnicodeChar, 1);
+ CurrentCursor++;
+ } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
+ KeyPad[0] = Key.UnicodeChar;
+ KeyPad[1] = CHAR_NULL;
+ Count = GetStringWidth (StringPtr) / 2 - 1;
+ if (CurrentCursor < Count) {
+ for (Index = 0; Index < CurrentCursor; Index++) {
+ TempString[Index] = StringPtr[Index];
+ }
+ TempString[Index] = CHAR_NULL;
+ StrCatS (TempString, MaxLen, KeyPad);
+ StrCatS (TempString, MaxLen, StringPtr + CurrentCursor);
+ StrCpyS (StringPtr, MaxLen, TempString);
+ } else {
+ StrCatS (StringPtr, MaxLen, KeyPad);
+ }
+ CurrentCursor++;
+ }
+
+ //
+ // If the width of the input string is now larger than the screen, we nee to
+ // adjust the index to start printing portions of the string
+ //
+ SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
+ PrintStringAt (Start + 1, Top + 3, BufferedString);
+
+ if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
+ Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
+ } else {
+ Index = 0;
+ }
+
+ if (IsPassword) {
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
+ }
+
+ for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
+ BufferedString[Count] = StringPtr[Index];
+
+ if (IsPassword) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
+ }
+ }
+
+ if (!IsPassword) {
+ PrintStringAt (Start + 1, Top + 3, BufferedString);
+ }
+ break;
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
+ } while (TRUE);
+
+}
+
+/**
+ Adjust the value to the correct one. Rules follow the sample:
+ like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
+ Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
+
+ @param QuestionValue Pointer to current question.
+ @param Sequence The sequence of the field in the question.
+**/
+VOID
+AdjustQuestionValue (
+ IN EFI_HII_VALUE *QuestionValue,
+ IN UINT8 Sequence
+ )
+{
+ UINT8 Month;
+ UINT16 Year;
+ UINT8 Maximum;
+ UINT8 Minimum;
+
+ Month = QuestionValue->Value.date.Month;
+ Year = QuestionValue->Value.date.Year;
+ Minimum = 1;
+
+ switch (Month) {
+ case 2:
+ if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {
+ Maximum = 29;
+ } else {
+ Maximum = 28;
+ }
+ break;
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ Maximum = 30;
+ break;
+ default:
+ Maximum = 31;
+ break;
+ }
+
+ //
+ // Change the month area.
+ //
+ if (Sequence == 0) {
+ if (QuestionValue->Value.date.Day > Maximum) {
+ QuestionValue->Value.date.Day = Maximum;
+ }
+ }
+
+ //
+ // Change the Year area.
+ //
+ if (Sequence == 2) {
+ if (QuestionValue->Value.date.Day > Maximum) {
+ QuestionValue->Value.date.Day = Minimum;
+ }
+ }
+}
+
+/**
+ Get field info from numeric opcode.
+
+ @param OpCode Pointer to the current input opcode.
+ @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
+ @param QuestionValue Input question value, with EFI_HII_VALUE type.
+ @param Value Return question value, always return UINT64 type.
+ @param Minimum The minimum size info for this opcode.
+ @param Maximum The maximum size info for this opcode.
+ @param Step The step size info for this opcode.
+ @param StorageWidth The storage width info for this opcode.
+
+**/
+VOID
+GetValueFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode,
+ IN BOOLEAN IntInput,
+ IN EFI_HII_VALUE *QuestionValue,
+ OUT UINT64 *Value,
+ OUT UINT64 *Minimum,
+ OUT UINT64 *Maximum,
+ OUT UINT64 *Step,
+ OUT UINT16 *StorageWidth
+)
+{
+ EFI_IFR_NUMERIC *NumericOp;
+
+ NumericOp = (EFI_IFR_NUMERIC *) OpCode;
+
+ switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if (IntInput) {
+ *Minimum = (INT64) (INT8) NumericOp->data.u8.MinValue;
+ *Maximum = (INT64) (INT8) NumericOp->data.u8.MaxValue;
+ *Value = (INT64) (INT8) QuestionValue->Value.u8;
+ } else {
+ *Minimum = NumericOp->data.u8.MinValue;
+ *Maximum = NumericOp->data.u8.MaxValue;
+ *Value = QuestionValue->Value.u8;
+ }
+ *Step = NumericOp->data.u8.Step;
+ *StorageWidth = (UINT16) sizeof (UINT8);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if (IntInput) {
+ *Minimum = (INT64) (INT16) NumericOp->data.u16.MinValue;
+ *Maximum = (INT64) (INT16) NumericOp->data.u16.MaxValue;
+ *Value = (INT64) (INT16) QuestionValue->Value.u16;
+ } else {
+ *Minimum = NumericOp->data.u16.MinValue;
+ *Maximum = NumericOp->data.u16.MaxValue;
+ *Value = QuestionValue->Value.u16;
+ }
+ *Step = NumericOp->data.u16.Step;
+ *StorageWidth = (UINT16) sizeof (UINT16);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if (IntInput) {
+ *Minimum = (INT64) (INT32) NumericOp->data.u32.MinValue;
+ *Maximum = (INT64) (INT32) NumericOp->data.u32.MaxValue;
+ *Value = (INT64) (INT32) QuestionValue->Value.u32;
+ } else {
+ *Minimum = NumericOp->data.u32.MinValue;
+ *Maximum = NumericOp->data.u32.MaxValue;
+ *Value = QuestionValue->Value.u32;
+ }
+ *Step = NumericOp->data.u32.Step;
+ *StorageWidth = (UINT16) sizeof (UINT32);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if (IntInput) {
+ *Minimum = (INT64) NumericOp->data.u64.MinValue;
+ *Maximum = (INT64) NumericOp->data.u64.MaxValue;
+ *Value = (INT64) QuestionValue->Value.u64;
+ } else {
+ *Minimum = NumericOp->data.u64.MinValue;
+ *Maximum = NumericOp->data.u64.MaxValue;
+ *Value = QuestionValue->Value.u64;
+ }
+ *Step = NumericOp->data.u64.Step;
+ *StorageWidth = (UINT16) sizeof (UINT64);
+ break;
+
+ default:
+ break;
+ }
+
+ if (*Maximum == 0) {
+ *Maximum = (UINT64) -1;
+ }
+}
+
+/**
+ This routine reads a numeric value from the user input.
+
+ @param MenuOption Pointer to the current input menu.
+
+ @retval EFI_SUCCESS If numerical input is read successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+GetNumericInput (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ UINTN Column;
+ UINTN Row;
+ CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];
+ CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
+ UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
+ UINTN Count;
+ UINTN Loop;
+ BOOLEAN ManualInput;
+ BOOLEAN HexInput;
+ BOOLEAN IntInput;
+ BOOLEAN Negative;
+ BOOLEAN ValidateFail;
+ BOOLEAN DateOrTime;
+ UINTN InputWidth;
+ UINT64 EditValue;
+ UINT64 Step;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINTN EraseLen;
+ UINT8 Digital;
+ EFI_INPUT_KEY Key;
+ EFI_HII_VALUE *QuestionValue;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ EFI_IFR_NUMERIC *NumericOp;
+ UINT16 StorageWidth;
+
+ Column = MenuOption->OptCol;
+ Row = MenuOption->Row;
+ PreviousNumber[0] = 0;
+ Count = 0;
+ InputWidth = 0;
+ Digital = 0;
+ StorageWidth = 0;
+ Minimum = 0;
+ Maximum = 0;
+ NumericOp = NULL;
+ IntInput = FALSE;
+ HexInput = FALSE;
+ Negative = FALSE;
+ ValidateFail = FALSE;
+
+ Question = MenuOption->ThisTag;
+ QuestionValue = &Question->CurrentValue;
+ ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16));
+
+ //
+ // Only two case, user can enter to this function: Enter and +/- case.
+ // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
+ //
+ ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
+
+ if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ DateOrTime = TRUE;
+ } else {
+ DateOrTime = FALSE;
+ }
+
+ //
+ // Prepare Value to be edit
+ //
+ EraseLen = 0;
+ EditValue = 0;
+ if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ Step = 1;
+ Minimum = 1;
+
+ switch (MenuOption->Sequence) {
+ case 0:
+ Maximum = 12;
+ EraseLen = 4;
+ EditValue = QuestionValue->Value.date.Month;
+ break;
+
+ case 1:
+ switch (QuestionValue->Value.date.Month) {
+ case 2:
+ if ((QuestionValue->Value.date.Year % 4) == 0 &&
+ ((QuestionValue->Value.date.Year % 100) != 0 ||
+ (QuestionValue->Value.date.Year % 400) == 0)) {
+ Maximum = 29;
+ } else {
+ Maximum = 28;
+ }
+ break;
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ Maximum = 30;
+ break;
+ default:
+ Maximum = 31;
+ break;
+ }
+
+ EraseLen = 3;
+ EditValue = QuestionValue->Value.date.Day;
+ break;
+
+ case 2:
+ Maximum = 0xffff;
+ EraseLen = 5;
+ EditValue = QuestionValue->Value.date.Year;
+ break;
+
+ default:
+ break;
+ }
+ } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ Step = 1;
+ Minimum = 0;
+
+ switch (MenuOption->Sequence) {
+ case 0:
+ Maximum = 23;
+ EraseLen = 4;
+ EditValue = QuestionValue->Value.time.Hour;
+ break;
+
+ case 1:
+ Maximum = 59;
+ EraseLen = 3;
+ EditValue = QuestionValue->Value.time.Minute;
+ break;
+
+ case 2:
+ Maximum = 59;
+ EraseLen = 3;
+ EditValue = QuestionValue->Value.time.Second;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);
+ NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
+ GetValueFromNum(Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);
+ EraseLen = gOptionBlockWidth;
+ }
+
+ if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {
+ if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX){
+ HexInput = TRUE;
+ } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0){
+ //
+ // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
+ //
+ IntInput = TRUE;
+ }
+ }
+
+ //
+ // Enter from "Enter" input, clear the old word showing.
+ //
+ if (ManualInput) {
+ if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
+ if (HexInput) {
+ InputWidth = StorageWidth * 2;
+ } else {
+ switch (StorageWidth) {
+ case 1:
+ InputWidth = 3;
+ break;
+
+ case 2:
+ InputWidth = 5;
+ break;
+
+ case 4:
+ InputWidth = 10;
+ break;
+
+ case 8:
+ InputWidth = 20;
+ break;
+
+ default:
+ InputWidth = 0;
+ break;
+ }
+
+ if (IntInput) {
+ //
+ // Support an extra '-' for negative number.
+ //
+ InputWidth += 1;
+ }
+ }
+
+ InputText[0] = LEFT_NUMERIC_DELIMITER;
+ SetUnicodeMem (InputText + 1, InputWidth, L' ');
+ ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
+ InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
+ InputText[InputWidth + 2] = L'\0';
+
+ PrintStringAt (Column, Row, InputText);
+ Column++;
+ }
+
+ if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ if (MenuOption->Sequence == 2) {
+ InputWidth = 4;
+ } else {
+ InputWidth = 2;
+ }
+
+ if (MenuOption->Sequence == 0) {
+ InputText[0] = LEFT_NUMERIC_DELIMITER;
+ SetUnicodeMem (InputText + 1, InputWidth, L' ');
+ InputText[InputWidth + 1] = DATE_SEPARATOR;
+ InputText[InputWidth + 2] = L'\0';
+ } else if (MenuOption->Sequence == 1){
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ InputText[InputWidth] = DATE_SEPARATOR;
+ InputText[InputWidth + 1] = L'\0';
+ } else {
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
+ InputText[InputWidth + 1] = L'\0';
+ }
+
+ PrintStringAt (Column, Row, InputText);
+ if (MenuOption->Sequence == 0) {
+ Column++;
+ }
+ }
+
+ if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ InputWidth = 2;
+
+ if (MenuOption->Sequence == 0) {
+ InputText[0] = LEFT_NUMERIC_DELIMITER;
+ SetUnicodeMem (InputText + 1, InputWidth, L' ');
+ InputText[InputWidth + 1] = TIME_SEPARATOR;
+ InputText[InputWidth + 2] = L'\0';
+ } else if (MenuOption->Sequence == 1){
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ InputText[InputWidth] = TIME_SEPARATOR;
+ InputText[InputWidth + 1] = L'\0';
+ } else {
+ SetUnicodeMem (InputText, InputWidth, L' ');
+ InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
+ InputText[InputWidth + 1] = L'\0';
+ }
+
+ PrintStringAt (Column, Row, InputText);
+ if (MenuOption->Sequence == 0) {
+ Column++;
+ }
+ }
+ }
+
+ //
+ // First time we enter this handler, we need to check to see if
+ // we were passed an increment or decrement directive
+ //
+ do {
+ Key.UnicodeChar = CHAR_NULL;
+ if (gDirection != 0) {
+ Key.ScanCode = gDirection;
+ gDirection = 0;
+ goto TheKey2;
+ }
+
+ WaitForKeyStroke (&Key);
+
+TheKey2:
+ switch (Key.UnicodeChar) {
+
+ case '+':
+ case '-':
+ if (ManualInput && IntInput) {
+ //
+ // In Manual input mode, check whether input the negative flag.
+ //
+ if (Key.UnicodeChar == '-') {
+ if (Negative) {
+ break;
+ }
+ Negative = TRUE;
+ PrintCharAt (Column++, Row, Key.UnicodeChar);
+ }
+ } else {
+ if (Key.UnicodeChar == '+') {
+ Key.ScanCode = SCAN_RIGHT;
+ } else {
+ Key.ScanCode = SCAN_LEFT;
+ }
+ Key.UnicodeChar = CHAR_NULL;
+ goto TheKey2;
+ }
+ break;
+
+ case CHAR_NULL:
+ switch (Key.ScanCode) {
+ case SCAN_LEFT:
+ case SCAN_RIGHT:
+ if (DateOrTime && !ManualInput) {
+ //
+ // By setting this value, we will return back to the caller.
+ // We need to do this since an auto-refresh will destroy the adjustment
+ // based on what the real-time-clock is showing. So we always commit
+ // upon changing the value.
+ //
+ gDirection = SCAN_DOWN;
+ }
+
+ if ((Step != 0) && !ManualInput) {
+ if (Key.ScanCode == SCAN_LEFT) {
+ if (IntInput) {
+ if ((INT64) EditValue >= (INT64) Minimum + (INT64) Step) {
+ EditValue = EditValue - Step;
+ } else if ((INT64) EditValue > (INT64) Minimum){
+ EditValue = Minimum;
+ } else {
+ EditValue = Maximum;
+ }
+ } else {
+ if (EditValue >= Minimum + Step) {
+ EditValue = EditValue - Step;
+ } else if (EditValue > Minimum){
+ EditValue = Minimum;
+ } else {
+ EditValue = Maximum;
+ }
+ }
+ } else if (Key.ScanCode == SCAN_RIGHT) {
+ if (IntInput) {
+ if ((INT64) EditValue + (INT64) Step <= (INT64) Maximum) {
+ EditValue = EditValue + Step;
+ } else if ((INT64) EditValue < (INT64) Maximum) {
+ EditValue = Maximum;
+ } else {
+ EditValue = Minimum;
+ }
+ } else {
+ if (EditValue + Step <= Maximum) {
+ EditValue = EditValue + Step;
+ } else if (EditValue < Maximum) {
+ EditValue = Maximum;
+ } else {
+ EditValue = Minimum;
+ }
+ }
+ }
+
+ ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
+ if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ if (MenuOption->Sequence == 2) {
+ //
+ // Year
+ //
+ UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
+ } else {
+ //
+ // Month/Day
+ //
+ UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
+ }
+
+ if (MenuOption->Sequence == 0) {
+ ASSERT (EraseLen >= 2);
+ FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
+ } else if (MenuOption->Sequence == 1) {
+ ASSERT (EraseLen >= 1);
+ FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
+ }
+ } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
+
+ if (MenuOption->Sequence == 0) {
+ ASSERT (EraseLen >= 2);
+ FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
+ } else if (MenuOption->Sequence == 1) {
+ ASSERT (EraseLen >= 1);
+ FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
+ }
+ } else {
+ QuestionValue->Value.u64 = EditValue;
+ PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
+ for (Loop = 0; Loop < EraseLen; Loop++) {
+ PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
+ }
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+
+ if (MenuOption->Sequence == 0) {
+ PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
+ Column = MenuOption->OptCol + 1;
+ }
+
+ PrintStringAt (Column, Row, FormattedNumber);
+
+ if (!DateOrTime || MenuOption->Sequence == 2) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
+ }
+ }
+
+ goto EnterCarriageReturn;
+
+ case SCAN_UP:
+ case SCAN_DOWN:
+ goto EnterCarriageReturn;
+
+ case SCAN_ESC:
+ return EFI_DEVICE_ERROR;
+
+ default:
+ break;
+ }
+
+ break;
+
+EnterCarriageReturn:
+
+ case CHAR_CARRIAGE_RETURN:
+ //
+ // Validate input value with Minimum value.
+ //
+ ValidateFail = FALSE;
+ if (IntInput) {
+ //
+ // After user input Enter, need to check whether the input value.
+ // If input a negative value, should compare with maximum value.
+ // else compare with the minimum value.
+ //
+ if (Negative) {
+ ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;
+ } else {
+ ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;
+ }
+
+ if (ValidateFail) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ break;
+ }
+ } else if (EditValue < Minimum) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ break;
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+ CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
+ QuestionValue = &gUserInput->InputValue;
+ //
+ // Store Edit value back to Question
+ //
+ if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ switch (MenuOption->Sequence) {
+ case 0:
+ QuestionValue->Value.date.Month = (UINT8) EditValue;
+ break;
+
+ case 1:
+ QuestionValue->Value.date.Day = (UINT8) EditValue;
+ break;
+
+ case 2:
+ QuestionValue->Value.date.Year = (UINT16) EditValue;
+ break;
+
+ default:
+ break;
+ }
+ } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ switch (MenuOption->Sequence) {
+ case 0:
+ QuestionValue->Value.time.Hour = (UINT8) EditValue;
+ break;
+
+ case 1:
+ QuestionValue->Value.time.Minute = (UINT8) EditValue;
+ break;
+
+ case 2:
+ QuestionValue->Value.time.Second = (UINT8) EditValue;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ //
+ // Numeric
+ //
+ QuestionValue->Value.u64 = EditValue;
+ }
+
+ //
+ // Adjust the value to the correct one.
+ // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
+ // 2013.03.29 -> 2013.02.29 -> 2013.02.28
+ //
+ if (Question->OpCode->OpCode == EFI_IFR_DATE_OP &&
+ (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {
+ AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
+ }
+
+ return EFI_SUCCESS;
+
+ case CHAR_BACKSPACE:
+ if (ManualInput) {
+ if (Count == 0) {
+ if (Negative) {
+ Negative = FALSE;
+ Column--;
+ PrintStringAt (Column, Row, L" ");
+ }
+ break;
+ }
+ //
+ // Remove a character
+ //
+ EditValue = PreviousNumber[Count - 1];
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+ Count--;
+ Column--;
+ PrintStringAt (Column, Row, L" ");
+ }
+ break;
+
+ default:
+ if (ManualInput) {
+ if (HexInput) {
+ if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
+ Digital = (UINT8) (Key.UnicodeChar - L'0');
+ } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
+ Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);
+ } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
+ Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);
+ } else {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ break;
+ }
+ } else {
+ if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ break;
+ }
+ }
+
+ //
+ // If Count exceed input width, there is no way more is valid
+ //
+ if (Count >= InputWidth) {
+ break;
+ }
+ //
+ // Someone typed something valid!
+ //
+ if (Count != 0) {
+ if (HexInput) {
+ EditValue = LShiftU64 (EditValue, 4) + Digital;
+ } else if (IntInput && Negative) {
+ //
+ // Save the negative number.
+ //
+ EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;
+ } else {
+ EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
+ }
+ } else {
+ if (HexInput) {
+ EditValue = Digital;
+ } else if (IntInput && Negative) {
+ //
+ // Save the negative number.
+ //
+ EditValue = ~(Key.UnicodeChar - L'0') + 1;
+ } else {
+ EditValue = Key.UnicodeChar - L'0';
+ }
+ }
+
+ if (IntInput) {
+ ValidateFail = FALSE;
+ //
+ // When user input a new value, should check the current value.
+ // If user input a negative value, should compare it with minimum
+ // value, else compare it with maximum value.
+ //
+ if (Negative) {
+ ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;
+ } else {
+ ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;
+ }
+
+ if (ValidateFail) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ ASSERT (Count < ARRAY_SIZE (PreviousNumber));
+ EditValue = PreviousNumber[Count];
+ break;
+ }
+ } else {
+ if (EditValue > Maximum) {
+ UpdateStatusBar (INPUT_ERROR, TRUE);
+ ASSERT (Count < ARRAY_SIZE (PreviousNumber));
+ EditValue = PreviousNumber[Count];
+ break;
+ }
+ }
+
+ UpdateStatusBar (INPUT_ERROR, FALSE);
+
+ Count++;
+ ASSERT (Count < (ARRAY_SIZE (PreviousNumber)));
+ PreviousNumber[Count] = EditValue;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+ PrintCharAt (Column, Row, Key.UnicodeChar);
+ Column++;
+ }
+ break;
+ }
+ } while (TRUE);
+}
+
+/**
+ Adjust option order base on the question value.
+
+ @param Question Pointer to current question.
+ @param PopUpMenuLines The line number of the pop up menu.
+
+ @retval EFI_SUCCESS If Option input is processed successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+AdjustOptionOrder (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
+ OUT UINTN *PopUpMenuLines
+ )
+{
+ UINTN Index;
+ EFI_IFR_ORDERED_LIST *OrderList;
+ UINT8 *ValueArray;
+ UINT8 ValueType;
+ LIST_ENTRY *Link;
+ DISPLAY_QUESTION_OPTION *OneOfOption;
+ EFI_HII_VALUE *HiiValueArray;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ ValueArray = Question->CurrentValue.Buffer;
+ ValueType = OneOfOption->OptionOpCode->Type;
+ OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
+
+ for (Index = 0; Index < OrderList->MaxContainers; Index++) {
+ if (GetArrayData (ValueArray, ValueType, Index) == 0) {
+ break;
+ }
+ }
+
+ *PopUpMenuLines = Index;
+
+ //
+ // Prepare HiiValue array
+ //
+ HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));
+ ASSERT (HiiValueArray != NULL);
+
+ for (Index = 0; Index < *PopUpMenuLines; Index++) {
+ HiiValueArray[Index].Type = ValueType;
+ HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
+ }
+
+ for (Index = 0; Index < *PopUpMenuLines; Index++) {
+ OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);
+ if (OneOfOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ RemoveEntryList (&OneOfOption->Link);
+
+ //
+ // Insert to head.
+ //
+ InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
+ }
+
+ FreePool (HiiValueArray);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Base on the type to compare the value.
+
+ @param Value1 The first value need to compare.
+ @param Value2 The second value need to compare.
+ @param Type The value type for above two values.
+
+ @retval TRUE The two value are same.
+ @retval FALSE The two value are different.
+
+**/
+BOOLEAN
+IsValuesEqual (
+ IN EFI_IFR_TYPE_VALUE *Value1,
+ IN EFI_IFR_TYPE_VALUE *Value2,
+ IN UINT8 Type
+ )
+{
+ switch (Type) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ return (BOOLEAN) (Value1->u8 == Value2->u8);
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ return (BOOLEAN) (Value1->u16 == Value2->u16);
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ return (BOOLEAN) (Value1->u32 == Value2->u32);
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ return (BOOLEAN) (Value1->u64 == Value2->u64);
+
+ default:
+ ASSERT (FALSE);
+ return FALSE;
+ }
+}
+
+/**
+ Base on the type to set the value.
+
+ @param Dest The dest value.
+ @param Source The source value.
+ @param Type The value type for above two values.
+
+**/
+VOID
+SetValuesByType (
+ OUT EFI_IFR_TYPE_VALUE *Dest,
+ IN EFI_IFR_TYPE_VALUE *Source,
+ IN UINT8 Type
+ )
+{
+ switch (Type) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ Dest->b = Source->b;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Dest->u8 = Source->u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Dest->u16 = Source->u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Dest->u32 = Source->u32;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Dest->u64 = Source->u64;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Get selection for OneOf and OrderedList (Left/Right will be ignored).
+
+ @param MenuOption Pointer to the current input menu.
+
+ @retval EFI_SUCCESS If Option input is processed successfully
+ @retval EFI_DEVICE_ERROR If operation fails
+
+**/
+EFI_STATUS
+GetSelectionInputPopUp (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ EFI_INPUT_KEY Key;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ CHAR16 *TempStringPtr;
+ UINTN Index2;
+ UINTN TopOptionIndex;
+ UINTN HighlightOptionIndex;
+ UINTN Start;
+ UINTN End;
+ UINTN Top;
+ UINTN Bottom;
+ UINTN PopUpMenuLines;
+ UINTN MenuLinesInView;
+ UINTN PopUpWidth;
+ CHAR16 Character;
+ INT32 SavedAttribute;
+ BOOLEAN ShowDownArrow;
+ BOOLEAN ShowUpArrow;
+ UINTN DimensionsWidth;
+ LIST_ENTRY *Link;
+ BOOLEAN OrderedList;
+ UINT8 *ValueArray;
+ UINT8 *ReturnValue;
+ UINT8 ValueType;
+ EFI_HII_VALUE HiiValue;
+ DISPLAY_QUESTION_OPTION *OneOfOption;
+ DISPLAY_QUESTION_OPTION *CurrentOption;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ INTN Result;
+ EFI_IFR_ORDERED_LIST *OrderList;
+
+ DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
+
+ ValueArray = NULL;
+ ValueType = 0;
+ CurrentOption = NULL;
+ ShowDownArrow = FALSE;
+ ShowUpArrow = FALSE;
+
+ ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));
+
+ Question = MenuOption->ThisTag;
+ if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
+ Link = GetFirstNode (&Question->OptionListHead);
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ ValueArray = Question->CurrentValue.Buffer;
+ ValueType = OneOfOption->OptionOpCode->Type;
+ OrderedList = TRUE;
+ OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
+ } else {
+ OrderedList = FALSE;
+ OrderList = NULL;
+ }
+
+ //
+ // Calculate Option count
+ //
+ PopUpMenuLines = 0;
+ if (OrderedList) {
+ AdjustOptionOrder(Question, &PopUpMenuLines);
+ } else {
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ PopUpMenuLines++;
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ }
+
+ //
+ // Get the number of one of options present and its size
+ //
+ PopUpWidth = 0;
+ HighlightOptionIndex = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ for (Index = 0; Index < PopUpMenuLines; Index++) {
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ if (StrLen (StringPtr) > PopUpWidth) {
+ PopUpWidth = StrLen (StringPtr);
+ }
+ FreePool (StringPtr);
+ HiiValue.Type = OneOfOption->OptionOpCode->Type;
+ SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
+ if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+ //
+ // Find current selected Option for OneOf
+ //
+ HighlightOptionIndex = Index;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ //
+ // Perform popup menu initialization.
+ //
+ PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
+
+ SavedAttribute = gST->ConOut->Mode->Attribute;
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+
+ if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
+ PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
+ }
+
+ Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
+ End = Start + PopUpWidth + POPUP_FRAME_WIDTH;
+ Top = gStatementDimensions.TopRow;
+ Bottom = gStatementDimensions.BottomRow - 1;
+
+ MenuLinesInView = Bottom - Top - 1;
+ if (MenuLinesInView >= PopUpMenuLines) {
+ Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
+ Bottom = Top + PopUpMenuLines + 1;
+ } else {
+ ShowDownArrow = TRUE;
+ }
+
+ if (HighlightOptionIndex > (MenuLinesInView - 1)) {
+ TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
+ } else {
+ TopOptionIndex = 0;
+ }
+
+ do {
+ //
+ // Clear that portion of the screen
+ //
+ ClearLines (Start, End, Top, Bottom, GetPopupColor ());
+
+ //
+ // Draw "One of" pop-up menu
+ //
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (Start, Top, Character);
+ for (Index = Start; Index + 2 < End; Index++) {
+ if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
+ Character = GEOMETRICSHAPE_UP_TRIANGLE;
+ } else {
+ Character = BOXDRAW_HORIZONTAL;
+ }
+
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ Character = BOXDRAW_VERTICAL;
+ for (Index = Top + 1; Index < Bottom; Index++) {
+ PrintCharAt (Start, Index, Character);
+ PrintCharAt (End - 1, Index, Character);
+ }
+
+ //
+ // Move to top Option
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ for (Index = 0; Index < TopOptionIndex; Index++) {
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ //
+ // Display the One of options
+ //
+ Index2 = Top + 1;
+ for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ //
+ // If the string occupies multiple lines, truncate it to fit in one line,
+ // and append a "..." for indication.
+ //
+ if (StrLen (StringPtr) > (PopUpWidth - 1)) {
+ TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
+ ASSERT ( TempStringPtr != NULL );
+ CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
+ FreePool (StringPtr);
+ StringPtr = TempStringPtr;
+ StrCatS (StringPtr, PopUpWidth - 1, L"...");
+ }
+
+ if (Index == HighlightOptionIndex) {
+ //
+ // Highlight the selected one
+ //
+ CurrentOption = OneOfOption;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
+ PrintStringAt (Start + 2, Index2, StringPtr);
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+ PrintStringAt (Start + 2, Index2, StringPtr);
+ }
+
+ Index2++;
+ FreePool (StringPtr);
+ }
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (Start, Bottom, Character);
+ for (Index = Start; Index + 2 < End; Index++) {
+ if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
+ Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
+ } else {
+ Character = BOXDRAW_HORIZONTAL;
+ }
+
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+
+ //
+ // Get User selection
+ //
+ Key.UnicodeChar = CHAR_NULL;
+ if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
+ Key.ScanCode = gDirection;
+ gDirection = 0;
+ goto TheKey;
+ }
+
+ WaitForKeyStroke (&Key);
+
+TheKey:
+ switch (Key.UnicodeChar) {
+ case '+':
+ if (OrderedList) {
+ if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
+ //
+ // Highlight reaches the top of the popup window, scroll one menu item.
+ //
+ TopOptionIndex--;
+ ShowDownArrow = TRUE;
+ }
+
+ if (TopOptionIndex == 0) {
+ ShowUpArrow = FALSE;
+ }
+
+ if (HighlightOptionIndex > 0) {
+ HighlightOptionIndex--;
+
+ ASSERT (CurrentOption != NULL);
+ SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
+ }
+ }
+ break;
+
+ case '-':
+ //
+ // If an ordered list op-code, we will allow for a popup of +/- keys
+ // to create an ordered list of items
+ //
+ if (OrderedList) {
+ if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
+ (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
+ //
+ // Highlight reaches the bottom of the popup window, scroll one menu item.
+ //
+ TopOptionIndex++;
+ ShowUpArrow = TRUE;
+ }
+
+ if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
+ ShowDownArrow = FALSE;
+ }
+
+ if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
+ HighlightOptionIndex++;
+
+ ASSERT (CurrentOption != NULL);
+ SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
+ }
+ }
+ break;
+
+ case CHAR_NULL:
+ switch (Key.ScanCode) {
+ case SCAN_UP:
+ case SCAN_DOWN:
+ if (Key.ScanCode == SCAN_UP) {
+ if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
+ //
+ // Highlight reaches the top of the popup window, scroll one menu item.
+ //
+ TopOptionIndex--;
+ ShowDownArrow = TRUE;
+ }
+
+ if (TopOptionIndex == 0) {
+ ShowUpArrow = FALSE;
+ }
+
+ if (HighlightOptionIndex > 0) {
+ HighlightOptionIndex--;
+ }
+ } else {
+ if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
+ (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
+ //
+ // Highlight reaches the bottom of the popup window, scroll one menu item.
+ //
+ TopOptionIndex++;
+ ShowUpArrow = TRUE;
+ }
+
+ if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
+ ShowDownArrow = FALSE;
+ }
+
+ if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
+ HighlightOptionIndex++;
+ }
+ }
+ break;
+
+ case SCAN_ESC:
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
+
+ //
+ // Restore link list order for orderedlist
+ //
+ if (OrderedList) {
+ HiiValue.Type = ValueType;
+ HiiValue.Value.u64 = 0;
+ for (Index = 0; Index < OrderList->MaxContainers; Index++) {
+ HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
+ if (HiiValue.Value.u64 == 0) {
+ break;
+ }
+
+ OneOfOption = ValueToOption (Question, &HiiValue);
+ if (OneOfOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ RemoveEntryList (&OneOfOption->Link);
+ InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ //
+ // return the current selection
+ //
+ if (OrderedList) {
+ ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
+ ASSERT (ReturnValue != NULL);
+ Index = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);
+
+ Index++;
+ if (Index > OrderList->MaxContainers) {
+ break;
+ }
+ }
+ if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
+ FreePool (ReturnValue);
+ return EFI_DEVICE_ERROR;
+ } else {
+ gUserInput->InputValue.Buffer = ReturnValue;
+ gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
+ }
+ } else {
+ ASSERT (CurrentOption != NULL);
+ gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
+ if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
+ }
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
+
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ } while (TRUE);
+
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c
new file mode 100644
index 000000000..a597a5d8a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/Popup.c
@@ -0,0 +1,724 @@
+/** @file
+Implementation for Hii Popup Protocol.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FormDisplay.h"
+
+EFI_SCREEN_DESCRIPTOR gPopupDimensions;
+LIST_ENTRY gUserSelectableOptions;
+EFI_STRING gMessageString;
+UINTN gMesStrLineNum;
+UINTN gMaxRowWidth;
+
+/**
+ Free the user selectable option structure data.
+
+ @param OptionList Point to the selectable option list which need to be freed.
+
+**/
+VOID
+FreeSelectableOptions(
+ LIST_ENTRY *OptionList
+ )
+{
+ LIST_ENTRY *Link;
+ USER_SELECTABLE_OPTION *SelectableOption;
+
+ while (!IsListEmpty (OptionList)) {
+ Link = GetFirstNode (OptionList);
+ SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);
+ RemoveEntryList (&SelectableOption->Link);
+ FreePool (SelectableOption);
+ }
+}
+
+/**
+ Display one selectable option.
+
+ @param SelectableOption The selectable option need to be drew.
+ @param Highlight Whether the option need to be highlighted.
+
+**/
+VOID
+DisplayOneSelectableOption(
+ IN USER_SELECTABLE_OPTION *SelectableOption,
+ IN BOOLEAN Highlight
+ )
+{
+ if (Highlight) {
+ gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
+ }
+ PrintStringAt (SelectableOption->OptionCol, SelectableOption->OptionRow, SelectableOption->OptionString);
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+}
+
+/**
+ Add one selectable option to option list. This is the work function for AddUserSelectableOptions.
+
+ @param PopupType The option need to be drew.
+ @param OptionType The type of this selection option.
+ @param OptionString Point to the option string that to be shown.
+ @param OptionCol The column that the option need to be drew at.
+ @param OptionRow The row that the option need to be drew at.
+
+ @retval EFI_SUCCESS This function implement successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available.
+
+**/
+EFI_STATUS
+AddOneSelectableOption (
+ IN EFI_HII_POPUP_TYPE PopupType,
+ IN EFI_HII_POPUP_SELECTION OptionType,
+ IN CHAR16 *OptionString,
+ IN UINTN OptionCol,
+ IN UINTN OptionRow
+ )
+{
+ USER_SELECTABLE_OPTION *UserSelectableOption;
+
+ UserSelectableOption = AllocateZeroPool (sizeof (USER_SELECTABLE_OPTION));
+ if (UserSelectableOption == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize the user selectable option based on the PopupType and OptionType.
+ // And then add the option to the option list gUserSelectableOptions.
+ //
+ UserSelectableOption->Signature = USER_SELECTABLE_OPTION_SIGNATURE;
+ UserSelectableOption->OptionString = OptionString;
+ UserSelectableOption->OptionType = OptionType;
+ UserSelectableOption->OptionCol = OptionCol;
+ UserSelectableOption->OptionRow = OptionRow;
+ UserSelectableOption->MinSequence = 0;
+
+ switch (PopupType) {
+ case EfiHiiPopupTypeOk:
+ UserSelectableOption->MaxSequence = 0;
+ UserSelectableOption->Sequence= 0;
+ break;
+ case EfiHiiPopupTypeOkCancel:
+ UserSelectableOption->MaxSequence = 1;
+ if (OptionType == EfiHiiPopupSelectionOk) {
+ UserSelectableOption->Sequence= 0;
+ } else {
+ UserSelectableOption->Sequence= 1;
+ }
+ break;
+ case EfiHiiPopupTypeYesNo:
+ UserSelectableOption->MaxSequence = 1;
+ if (OptionType == EfiHiiPopupSelectionYes) {
+ UserSelectableOption->Sequence = 0;
+ } else {
+ UserSelectableOption->Sequence = 1;
+ }
+ break;
+ case EfiHiiPopupTypeYesNoCancel:
+ UserSelectableOption->MaxSequence = 2;
+ if (OptionType == EfiHiiPopupSelectionYes) {
+ UserSelectableOption->Sequence = 0;
+ } else if (OptionType == EfiHiiPopupSelectionNo){
+ UserSelectableOption->Sequence = 1;
+ } else {
+ UserSelectableOption->Sequence = 2;
+ }
+ break;
+ default:
+ break;
+ }
+ InsertTailList (&gUserSelectableOptions, &UserSelectableOption->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add user selectable options to option list for different types of Popup.
+
+ @param PopupType Type of the popup to display.
+
+ @retval EFI_SUCCESS This function implement successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available.
+
+**/
+EFI_STATUS
+AddUserSelectableOptions (
+ IN EFI_HII_POPUP_TYPE PopupType
+ )
+{
+ EFI_STATUS Status;
+ UINTN EndCol;
+ UINTN StartCol;
+ UINTN OptionCol;
+ UINTN OptionRow;
+ UINTN ColDimension;
+
+ Status = EFI_SUCCESS;
+ EndCol = gPopupDimensions.RightColumn;
+ StartCol = gPopupDimensions.LeftColumn;
+ OptionRow = gPopupDimensions.BottomRow - POPUP_BORDER;
+ ColDimension = EndCol - StartCol + 1;
+
+ InitializeListHead (&gUserSelectableOptions);
+
+ switch (PopupType) {
+ case EfiHiiPopupTypeOk:
+ //
+ // Add [Ok] option to the option list.
+ //
+ OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_WIDTH) / 2;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);
+ break;
+ case EfiHiiPopupTypeOkCancel:
+ //
+ // Add [Ok] and [Cancel] options to the option list.
+ //
+ OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionOk, gOkOption, OptionCol, OptionRow);
+ OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_OK_CAL_WIDTH) / 3 - (GetStringWidth (gCancelOption) -2) / 2 + 1;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);
+ break;
+ case EfiHiiPopupTypeYesNo:
+ //
+ // Add [Yes] and [No] options to the option list.
+ //
+ OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);
+ OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_WIDTH) / 3 - (GetStringWidth (gNoOption)- 2) / 2 + 1;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);
+ break;
+ case EfiHiiPopupTypeYesNoCancel:
+ //
+ // Add [Yes], [No] and [Cancel] options to the option list.
+ //
+ OptionCol = StartCol + (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionYes, gYesOption, OptionCol, OptionRow);
+ OptionCol = StartCol + (ColDimension - (GetStringWidth (gNoOption) -2) / 2) / 2;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionNo, gNoOption, OptionCol, OptionRow);
+ OptionCol = EndCol - (ColDimension - USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH) / 4 - (GetStringWidth (gCancelOption) - 2) / 2 + 1;
+ Status = AddOneSelectableOption (PopupType, EfiHiiPopupSelectionCancel, gCancelOption, OptionCol, OptionRow);
+ break;
+ default:
+ break;
+ }
+ return Status;
+}
+
+/**
+ Show selectable options to user and get the one that user select.
+
+ @param PopupType Type of the popup to display.
+ @param UserSelection User selection.
+
+**/
+VOID
+GetUserSelection (
+ IN EFI_HII_POPUP_TYPE PopupType,
+ OUT EFI_HII_POPUP_SELECTION *UserSelection
+ )
+{
+ LIST_ENTRY *HighlightPos;
+ LIST_ENTRY *Link;
+ USER_SELECTABLE_OPTION *SelectableOption;
+ USER_SELECTABLE_OPTION *HighlightOption;
+ EFI_INPUT_KEY KeyValue;
+ EFI_STATUS Status;
+
+ //
+ // Display user selectable options in gUserSelectableOptions and get the option which user selects.
+ //
+ HighlightPos = gUserSelectableOptions.ForwardLink;
+ do {
+ for (Link = gUserSelectableOptions.ForwardLink; Link != &gUserSelectableOptions; Link = Link->ForwardLink) {
+ SelectableOption = SELECTABLE_OPTION_FROM_LINK (Link);
+ DisplayOneSelectableOption (SelectableOption, (BOOLEAN)(Link == HighlightPos));
+ }
+ //
+ //If UserSelection is NULL, there is no need to handle the key user input, just return.
+ //
+ if (UserSelection == NULL) {
+ return;
+ }
+
+ Status = WaitForKeyStroke (&KeyValue);
+ ASSERT_EFI_ERROR (Status);
+
+ HighlightOption = SELECTABLE_OPTION_FROM_LINK (HighlightPos);
+ switch (KeyValue.UnicodeChar) {
+ case CHAR_NULL:
+ switch (KeyValue.ScanCode) {
+ case SCAN_RIGHT:
+ if (HighlightOption->Sequence < HighlightOption->MaxSequence) {
+ HighlightPos = HighlightPos->ForwardLink;
+ } else {
+ HighlightPos = gUserSelectableOptions.ForwardLink;
+ }
+ break;
+ case SCAN_LEFT:
+ if (HighlightOption->Sequence > HighlightOption->MinSequence) {
+ HighlightPos = HighlightPos->BackLink;
+ } else {
+ HighlightPos = gUserSelectableOptions.BackLink;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ *UserSelection = HighlightOption->OptionType;
+ return;
+ default:
+ if (((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptYes | UPPER_LOWER_CASE_OFFSET)) &&
+ (PopupType == EfiHiiPopupTypeYesNo || PopupType == EfiHiiPopupTypeYesNoCancel)) {
+ *UserSelection = EfiHiiPopupSelectionYes;
+ return;
+ } else if ((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptNo| UPPER_LOWER_CASE_OFFSET) &&
+ (PopupType == EfiHiiPopupTypeYesNo || PopupType == EfiHiiPopupTypeYesNoCancel)){
+ *UserSelection = EfiHiiPopupSelectionNo;
+ return;
+ } else if ((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptOk | UPPER_LOWER_CASE_OFFSET) &&
+ (PopupType == EfiHiiPopupTypeOk || PopupType == EfiHiiPopupTypeOkCancel)){
+ *UserSelection = EfiHiiPopupSelectionOk;
+ return;
+ } else if ((KeyValue.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (*gConfirmOptCancel| UPPER_LOWER_CASE_OFFSET) &&
+ (PopupType == EfiHiiPopupTypeOkCancel || PopupType == EfiHiiPopupTypeYesNoCancel)){
+ *UserSelection = EfiHiiPopupSelectionCancel;
+ return;
+ }
+ break;
+ }
+ } while (TRUE);
+}
+
+/**
+ Get the offset in the input string when the width reaches to a fixed one.
+
+ The input string may contain NARROW_CHAR and WIDE_CHAR.
+ Notice: the input string doesn't contain line break characters.
+
+ @param String The input string to be counted.
+ @param MaxWidth The max length this function supported.
+ @param Offset The max index of the string can be show out. If string's width less than MaxWidth, offset will point to the "\0" of the string.
+
+**/
+VOID
+GetStringOffsetWithWidth (
+ IN CHAR16 *String,
+ IN UINTN MaxWidth,
+ OUT UINTN *Offset
+ )
+{
+ UINTN StringWidth;
+ UINTN CharWidth;
+ UINTN StrOffset;
+
+ StringWidth = 0;
+ CharWidth = 1;
+
+ for (StrOffset = 0; String[StrOffset] != CHAR_NULL; StrOffset++) {
+ switch (String[StrOffset]) {
+ case NARROW_CHAR:
+ CharWidth = 1;
+ break;
+ case WIDE_CHAR:
+ CharWidth = 2;
+ break;
+ default:
+ StringWidth += CharWidth;
+ if (StringWidth >= MaxWidth) {
+ *Offset = StrOffset;
+ return;
+ }
+ }
+ }
+ *Offset = StrOffset;
+}
+
+/**
+ Parse the message to check if it contains line break characters.
+ For once call, caller can get the string for one line and the width of the string.
+ This function call be called recursively to parse the whole InputString.
+
+ (Notice: current implementation, it only checks \r, \n characters, it deals \r,\n,\n\r same as \r\n.)
+
+ @param InputString String description for this option.
+ @param OutputString Buffer to copy the string into, caller is responsible for freeing the buffer.
+ @param OutputStrWidth The width of OutputString.
+ @param Index Where in InputString to start the copy process
+
+ @return Returns the number of CHAR16 characters that were copied into the OutputString buffer, include the '\0' info.
+
+**/
+UINTN
+ParseMessageString (
+ IN CHAR16 *InputString,
+ OUT CHAR16 **OutputString,
+ OUT UINTN *OutputStrWidth,
+ IN OUT UINTN *Index
+ )
+{
+ UINTN StrOffset;
+
+ if (InputString == NULL || Index == NULL || OutputString == NULL) {
+ return 0;
+ }
+
+ *OutputStrWidth = 0;
+
+ //
+ //Check the string to see if there are line break characters in the string
+ //
+ for (StrOffset = 0;
+ InputString[*Index + StrOffset] != CHAR_CARRIAGE_RETURN && InputString[*Index + StrOffset] != CHAR_LINEFEED && InputString[*Index + StrOffset] != CHAR_NULL;
+ StrOffset++
+ );
+
+ //
+ // The CHAR_NULL has process last time, this time just return 0 to stand for finishing parsing the InputString.
+ //
+ if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {
+ return 0;
+ }
+
+ //
+ // Copy the string to OutputString buffer and calculate the width of OutputString.
+ //
+ *OutputString = AllocateZeroPool ((StrOffset + 1) * sizeof(CHAR16));
+ if (*OutputString == NULL) {
+ return 0;
+ }
+ CopyMem ((*OutputString), &InputString[*Index], StrOffset * sizeof(CHAR16));
+ *OutputStrWidth = (GetStringWidth (*OutputString) -2) / 2;
+
+ //
+ // Update the value of Index, can be used for marking where to check the input string for next call.
+ //
+ if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
+ //
+ // Skip the /n or /n/r info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
+ *Index = (*Index + StrOffset + 2);
+ } else {
+ *Index = (*Index + StrOffset + 1);
+ }
+ } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {
+ //
+ // Skip the /r or /r/n info.
+ //
+ if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {
+ *Index = (*Index + StrOffset + 2);
+ } else {
+ *Index = (*Index + StrOffset + 1);
+ }
+ } else {
+ *Index = (*Index + StrOffset);
+ }
+
+ return StrOffset + 1;
+}
+
+/**
+ Calculate the position of the popup.
+
+ @param PopupType Type of the popup to display.
+ @param ScreenForPopup The screen dimensions for the popup.
+
+**/
+VOID
+CalculatePopupPosition (
+ IN EFI_HII_POPUP_TYPE PopupType,
+ OUT EFI_SCREEN_DESCRIPTOR *ScreenForPopup
+ )
+{
+ CHAR16 *OutputString;
+ UINTN StringIndex;
+ UINTN OutputStrWidth;
+ UINTN OptionRowWidth;
+ UINTN Columns;
+ UINTN Rows;
+
+ OptionRowWidth = 0;
+
+ //
+ // Calculate the row number which is needed to show the message string and the max width of the string in one row.
+ //
+ for (StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0;) {
+ gMesStrLineNum ++;
+ if (gMaxRowWidth < OutputStrWidth) {
+ gMaxRowWidth = OutputStrWidth;
+ }
+ FreePool (OutputString);
+ }
+
+ //
+ // Calculate the row width for the selectable options.(OptionRowWidth = Number * SkipWidth + OptionWidth)
+ //
+ if (PopupType == EfiHiiPopupTypeOk) {
+ OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *2 + USER_SELECTABLE_OPTION_OK_WIDTH;
+ } else if (PopupType == EfiHiiPopupTypeOkCancel) {
+ OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_OK_CAL_WIDTH;
+ } else if (PopupType == EfiHiiPopupTypeYesNo) {
+ OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *3 + USER_SELECTABLE_OPTION_YES_NO_WIDTH;
+ } else if (PopupType == EfiHiiPopupTypeYesNoCancel) {
+ OptionRowWidth = USER_SELECTABLE_OPTION_SKIP_WIDTH *4 + USER_SELECTABLE_OPTION_YES_NO_CAL_WIDTH;
+ }
+ if (OptionRowWidth > gMaxRowWidth) {
+ gMaxRowWidth = OptionRowWidth;
+ }
+
+ //
+ // Avialble row width for message string = screen width - left popup border width - right popup border width.
+ // Avialble line number for message string = screen height - 1 - popup header height - popup footer height.
+ // (Notice: screen height - 1 because in current UI page, the bottom row of srceen is usded to show Status Bar,not for form itself.
+ // So we don't use the bottom row for popup either. If macro STATUS_BAR_HEIGHT changed, we also need to update the height here.)
+ //
+ // Select the smaller one between actual dimension of message string and the avialble dimension for message string.
+ //
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Columns, &Rows);
+ gMaxRowWidth = MIN (gMaxRowWidth, Columns - 2 * POPUP_BORDER);
+ gMesStrLineNum = MIN (gMesStrLineNum, Rows -1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT);
+
+ //
+ // Calculate the start column, end column, top row and bottom row for the popup.
+ //
+ ScreenForPopup->LeftColumn = (Columns -2 * POPUP_BORDER - gMaxRowWidth) / 2;
+ ScreenForPopup->RightColumn = ScreenForPopup->LeftColumn + gMaxRowWidth + 2 * POPUP_BORDER - 1;
+ ScreenForPopup->TopRow = (Rows - 1 - POPUP_FOOTER_HEIGHT - POPUP_HEADER_HEIGHT - gMesStrLineNum) / 2;
+ ScreenForPopup->BottomRow = ScreenForPopup->TopRow + gMesStrLineNum + POPUP_FOOTER_HEIGHT + POPUP_HEADER_HEIGHT - 1;
+}
+
+/**
+ Draw the Message box.
+ +-------------------------------------------+
+ | ERROR/WARNING/INFO |
+ |-------------------------------------------|
+ | popup messages |
+ | |
+ | user selectable options |
+ +-------------------------------------------+
+
+ @param PopupStyle Popup style to use.
+
+**/
+EFI_STATUS
+DrawMessageBox (
+ IN EFI_HII_POPUP_STYLE PopupStyle
+ )
+{
+ UINTN Index;
+ UINTN Length;
+ UINTN EndCol;
+ UINTN TopRow;
+ UINTN StartCol;
+ UINTN BottomRow;
+ CHAR16 Character;
+ UINTN DisplayRow;
+ UINTN StringIndex;
+ CHAR16 *TempString;
+ CHAR16 *OutputString;
+ UINTN ColDimension;
+ UINTN OutputStrWidth;
+ UINTN DrawMesStrRowNum;
+
+ EndCol = gPopupDimensions.RightColumn;
+ TopRow = gPopupDimensions.TopRow;
+ StartCol = gPopupDimensions.LeftColumn;
+ BottomRow = gPopupDimensions.BottomRow;
+ ColDimension = EndCol - StartCol + 1;
+ DrawMesStrRowNum = 0;
+
+ //
+ // 1. Draw the top of the message box.
+ //
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (StartCol, TopRow, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = StartCol; Index + 1 < EndCol; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+
+ //
+ // 2. Draw the prompt string for different popup styles.
+ //
+ Character = BOXDRAW_VERTICAL;
+ DisplayRow = TopRow + POPUP_BORDER;
+ ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
+ PrintCharAt (StartCol, DisplayRow, Character);
+ PrintCharAt (EndCol, DisplayRow, Character);
+ if (PopupStyle == EfiHiiPopupStyleError) {
+ PrintStringAt ((ColDimension - (GetStringWidth (gErrorPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gErrorPopup);
+ } else if (PopupStyle == EfiHiiPopupStyleWarning) {
+ PrintStringAt ((ColDimension - (GetStringWidth (gWarningPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gWarningPopup);
+ } else {
+ PrintStringAt ((ColDimension - (GetStringWidth (gInfoPopup) - 2) / 2) / 2 + StartCol, DisplayRow, gInfoPopup);
+ }
+
+ //
+ // 3. Draw the horizontal line below the prompt string for different popup styles.
+ //
+ DisplayRow = TopRow + POPUP_BORDER + POPUP_STYLE_STRING_HEIGHT;
+ ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = StartCol + 1; Index < EndCol; Index++) {
+ PrintCharAt (Index, DisplayRow, Character);
+ }
+ Character = BOXDRAW_VERTICAL;
+ PrintCharAt (StartCol, DisplayRow, Character);
+ PrintCharAt (EndCol, DisplayRow, Character);
+
+ //
+ // 4. Draw the mesage string.
+ //
+ DisplayRow = TopRow + POPUP_HEADER_HEIGHT;
+ for (Index = DisplayRow ,StringIndex = 0; ParseMessageString (gMessageString, &OutputString, &OutputStrWidth, &StringIndex) != 0 && DrawMesStrRowNum < gMesStrLineNum;) {
+ ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());
+ PrintCharAt (StartCol, Index, Character);
+ PrintCharAt (EndCol, Index, Character);
+ if (OutputStrWidth > gMaxRowWidth) {
+ //
+ //OutputStrWidth > MaxMesStrWidth, cut off the string and print print ... instead.
+ //
+ GetStringOffsetWithWidth (OutputString, gMaxRowWidth, &Length);
+ TempString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
+ if (TempString == NULL) {
+ FreePool (OutputString);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrnCpyS (TempString, Length + 1, OutputString, Length - 3);
+ StrCatS (TempString, Length + 1, L"...");
+ PrintStringAt ((ColDimension - gMaxRowWidth) / 2 + StartCol, Index, TempString);
+ FreePool (TempString);
+ } else {
+ PrintStringAt ((ColDimension - OutputStrWidth) / 2 + StartCol, Index, OutputString);
+ }
+ Index ++;
+ DrawMesStrRowNum ++;
+ FreePool (OutputString);
+ }
+
+ //
+ // 5. Draw an empty line after message string.
+ //
+ ClearLines (StartCol, EndCol, Index, Index, GetPopupColor ());
+ PrintCharAt (StartCol, Index, Character);
+ PrintCharAt (EndCol, Index, Character);
+ //
+ // Check whether the actual string row number beyond the MesStrRowNum, if yes, print the ...... in the row.
+ //
+ if (OutputStrWidth > 0 && DrawMesStrRowNum >= gMesStrLineNum) {
+ PrintStringAt ((ColDimension - StrLen (L"......")) / 2 + StartCol, Index, L"......");
+ }
+
+ //
+ // 6. Draw an empty line which is used to show user selectable options, will draw concrete option strings in function GetUserSelection().
+ //
+ Character = BOXDRAW_VERTICAL;
+ DisplayRow = BottomRow - POPUP_BORDER;
+ ClearLines (StartCol, EndCol, DisplayRow, DisplayRow, GetPopupColor ());
+ PrintCharAt (StartCol, DisplayRow, Character);
+ PrintCharAt (EndCol, DisplayRow, Character);
+
+ //
+ // 7. Draw the bottom of the message box.
+ //
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (StartCol, BottomRow, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = StartCol; Index + 1 < EndCol; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+ }
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Displays a popup window.
+
+ @param This A pointer to the EFI_HII_POPUP_PROTOCOL instance.
+ @param PopupStyle Popup style to use.
+ @param PopupType Type of the popup to display.
+ @param HiiHandle HII handle of the string pack containing Message
+ @param Message A message to display in the popup box.
+ @param UserSelection User selection.
+
+ @retval EFI_SUCCESS The popup box was successfully displayed.
+ @retval EFI_INVALID_PARAMETER HiiHandle and Message do not define a valid HII string.
+ @retval EFI_INVALID_PARAMETER PopupType is not one of the values defined by this specification.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to display the popup box.
+
+**/
+EFI_STATUS
+EFIAPI
+CreatePopup (
+ IN EFI_HII_POPUP_PROTOCOL *This,
+ IN EFI_HII_POPUP_STYLE PopupStyle,
+ IN EFI_HII_POPUP_TYPE PopupType,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID Message,
+ OUT EFI_HII_POPUP_SELECTION *UserSelection OPTIONAL
+ )
+{
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
+ EFI_STATUS Status;
+
+ if ((PopupType < EfiHiiPopupTypeOk) || (PopupType > EfiHiiPopupTypeYesNoCancel)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if((HiiHandle == NULL) || (Message == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gMessageString = HiiGetString (HiiHandle, Message, NULL);
+ if(gMessageString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConOut = gST->ConOut;
+ gMaxRowWidth = 0;
+ gMesStrLineNum = 0;
+
+ CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));
+ ConOut->EnableCursor (ConOut, FALSE);
+ ConOut->SetAttribute (ConOut, GetPopupColor ());
+
+ CalculatePopupPosition (PopupType, &gPopupDimensions);
+
+ Status = DrawMessageBox (PopupStyle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Add user selectable options to option list: gUserSelectableOptions
+ //
+ Status = AddUserSelectableOptions (PopupType);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ GetUserSelection (PopupType, UserSelection);
+
+Done:
+ //
+ // Restore Conout attributes and free the resources allocate before.
+ //
+ ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible);
+ ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
+ ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute);
+ FreeSelectableOptions (&gUserSelectableOptions);
+ FreePool (gMessageString);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
new file mode 100644
index 000000000..c02e36a63
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
@@ -0,0 +1,1593 @@
+/** @file
+Implementation for handling the User Interface option processing.
+
+
+Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FormDisplay.h"
+
+#define MAX_TIME_OUT_LEN 0x10
+
+/**
+ Concatenate a narrow string to another string.
+
+ @param Destination The destination string.
+ @param DestMax The Max length of destination string.
+ @param Source The source string. The string to be concatenated.
+ to the end of Destination.
+
+**/
+VOID
+NewStrCat (
+ IN OUT CHAR16 *Destination,
+ IN UINTN DestMax,
+ IN CHAR16 *Source
+ )
+{
+ UINTN Length;
+
+ for (Length = 0; Destination[Length] != 0; Length++)
+ ;
+
+ //
+ // We now have the length of the original string
+ // We can safely assume for now that we are concatenating a narrow value to this string.
+ // For instance, the string is "XYZ" and cat'ing ">"
+ // If this assumption changes, we need to make this routine a bit more complex
+ //
+ Destination[Length] = NARROW_CHAR;
+ Length++;
+
+ StrCpyS (Destination + Length, DestMax - Length, Source);
+}
+
+/**
+ Get UINT64 type value.
+
+ @param Value Input Hii value.
+
+ @retval UINT64 Return the UINT64 type value.
+
+**/
+UINT64
+HiiValueToUINT64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ UINT64 RetVal;
+
+ RetVal = 0;
+
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ RetVal = Value->Value.u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ RetVal = Value->Value.u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ RetVal = Value->Value.u32;
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ RetVal = Value->Value.b;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ RetVal = *(UINT64*) &Value->Value.date;
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
+ break;
+
+ default:
+ RetVal = Value->Value.u64;
+ break;
+ }
+
+ return RetVal;
+}
+
+/**
+ Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
+
+ EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
+ EFI_IFR_TYPE_BUFFER when do the value compare.
+
+ @param Value Expression value to compare on.
+
+ @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
+ @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
+
+**/
+BOOLEAN
+IsTypeInBuffer (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_BUFFER:
+ case EFI_IFR_TYPE_DATE:
+ case EFI_IFR_TYPE_TIME:
+ case EFI_IFR_TYPE_REF:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
+
+ @param Value Expression value to compare on.
+
+ @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
+ @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
+
+**/
+BOOLEAN
+IsTypeInUINT64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ case EFI_IFR_TYPE_BOOLEAN:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Return the buffer length and buffer pointer for this value.
+
+ EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
+ EFI_IFR_TYPE_BUFFER when do the value compare.
+
+ @param Value Expression value to compare on.
+ @param Buf Return the buffer pointer.
+ @param BufLen Return the buffer length.
+
+**/
+VOID
+GetBufAndLenForValue (
+ IN EFI_HII_VALUE *Value,
+ OUT UINT8 **Buf,
+ OUT UINT16 *BufLen
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_BUFFER:
+ *Buf = Value->Buffer;
+ *BufLen = Value->BufferLen;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ *Buf = (UINT8 *) (&Value->Value.date);
+ *BufLen = (UINT16) sizeof (EFI_HII_DATE);
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ *Buf = (UINT8 *) (&Value->Value.time);
+ *BufLen = (UINT16) sizeof (EFI_HII_TIME);
+ break;
+
+ case EFI_IFR_TYPE_REF:
+ *Buf = (UINT8 *) (&Value->Value.ref);
+ *BufLen = (UINT16) sizeof (EFI_HII_REF);
+ break;
+
+ default:
+ *Buf = NULL;
+ *BufLen = 0;
+ }
+}
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param Result Return value after compare.
+ retval 0 Two operators equal.
+ return Positive value if Value1 is greater than Value2.
+ retval Negative value if Value1 is less than Value2.
+ @param HiiHandle Only required for string compare.
+
+ @retval other Could not perform compare on two values.
+ @retval EFI_SUCCESS Compare the value success.
+
+**/
+EFI_STATUS
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ OUT INTN *Result,
+ IN EFI_HII_HANDLE HiiHandle OPTIONAL
+ )
+{
+ INT64 Temp64;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+ UINTN Len;
+ UINT8 *Buf1;
+ UINT16 Buf1Len;
+ UINT8 *Buf2;
+ UINT16 Buf2Len;
+
+ if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
+ if (Value1->Value.string == 0 || Value2->Value.string == 0) {
+ //
+ // StringId 0 is reserved
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Value1->Value.string == Value2->Value.string) {
+ *Result = 0;
+ return EFI_SUCCESS;
+ }
+
+ Str1 = GetToken (Value1->Value.string, HiiHandle);
+ if (Str1 == NULL) {
+ //
+ // String not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ Str2 = GetToken (Value2->Value.string, HiiHandle);
+ if (Str2 == NULL) {
+ FreePool (Str1);
+ return EFI_NOT_FOUND;
+ }
+
+ *Result = StrCmp (Str1, Str2);
+
+ FreePool (Str1);
+ FreePool (Str2);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Take types(date, time, ref, buffer) as buffer
+ //
+ if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
+ GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);
+ GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);
+
+ Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
+ *Result = CompareMem (Buf1, Buf2, Len);
+ if ((*Result == 0) && (Buf1Len != Buf2Len)) {
+ //
+ // In this case, means base on samll number buffer, the data is same
+ // So which value has more data, which value is bigger.
+ //
+ *Result = Buf1Len > Buf2Len ? 1 : -1;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Take remain types(integer, boolean, date/time) as integer
+ //
+ if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
+ Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
+ if (Temp64 > 0) {
+ *Result = 1;
+ } else if (Temp64 < 0) {
+ *Result = -1;
+ } else {
+ *Result = 0;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+DISPLAY_QUESTION_OPTION *
+ValueToOption (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ )
+{
+ LIST_ENTRY *Link;
+ DISPLAY_QUESTION_OPTION *Option;
+ INTN Result;
+ EFI_HII_VALUE Value;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+
+ ZeroMem (&Value, sizeof (EFI_HII_VALUE));
+ Value.Type = Option->OptionOpCode->Type;
+ CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+
+ if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+ return Option;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Return data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+
+ @retval Value The data to be returned
+
+**/
+UINT64
+GetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index
+ )
+{
+ UINT64 Data;
+
+ ASSERT (Array != NULL);
+
+ Data = 0;
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Data = (UINT64) *(((UINT8 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Data = (UINT64) *(((UINT16 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Data = (UINT64) *(((UINT32 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Data = (UINT64) *(((UINT64 *) Array) + Index);
+ break;
+
+ default:
+ break;
+ }
+
+ return Data;
+}
+
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+
+ ASSERT (Array != NULL);
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *(((UINT8 *) Array) + Index) = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *(((UINT16 *) Array) + Index) = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *(((UINT32 *) Array) + Index) = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *(((UINT64 *) Array) + Index) = (UINT64) Value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Check whether this value already in the array, if yes, return the index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Value The value to be find.
+ @param Index The index in the array which has same value with Value.
+
+ @retval TRUE Found the value in the array.
+ @retval FALSE Not found the value.
+
+**/
+BOOLEAN
+FindArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINT64 Value,
+ OUT UINTN *Index OPTIONAL
+ )
+{
+ UINTN Count;
+ UINT64 TmpValue;
+ UINT64 ValueComp;
+
+ ASSERT (Array != NULL);
+
+ Count = 0;
+ TmpValue = 0;
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ ValueComp = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ ValueComp = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ ValueComp = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ ValueComp = (UINT64) Value;
+ break;
+
+ default:
+ ValueComp = 0;
+ break;
+ }
+
+ while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
+ if (ValueComp == TmpValue) {
+ if (Index != NULL) {
+ *Index = Count;
+ }
+ return TRUE;
+ }
+
+ Count ++;
+ }
+
+ return FALSE;
+}
+
+/**
+ Print Question Value according to it's storage width and display attributes.
+
+ @param Question The Question to be printed.
+ @param FormattedNumber Buffer for output string.
+ @param BufferSize The FormattedNumber buffer size in bytes.
+
+ @retval EFI_SUCCESS Print success.
+ @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
+
+**/
+EFI_STATUS
+PrintFormattedNumber (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
+ IN OUT CHAR16 *FormattedNumber,
+ IN UINTN BufferSize
+ )
+{
+ INT64 Value;
+ CHAR16 *Format;
+ EFI_HII_VALUE *QuestionValue;
+ EFI_IFR_NUMERIC *NumericOp;
+
+ if (BufferSize < (21 * sizeof (CHAR16))) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ QuestionValue = &Question->CurrentValue;
+ NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
+
+ Value = (INT64) QuestionValue->Value.u64;
+ switch (NumericOp->Flags & EFI_IFR_DISPLAY) {
+ case EFI_IFR_DISPLAY_INT_DEC:
+ switch (QuestionValue->Type) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ Value = (INT64) ((INT8) QuestionValue->Value.u8);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ Value = (INT64) ((INT16) QuestionValue->Value.u16);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ Value = (INT64) ((INT32) QuestionValue->Value.u32);
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ default:
+ break;
+ }
+
+ if (Value < 0) {
+ Value = -Value;
+ Format = L"-%ld";
+ } else {
+ Format = L"%ld";
+ }
+ break;
+
+ case EFI_IFR_DISPLAY_UINT_DEC:
+ Format = L"%ld";
+ break;
+
+ case EFI_IFR_DISPLAY_UINT_HEX:
+ Format = L"%lx";
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Draw a pop up windows based on the dimension, number of lines and
+ strings specified.
+
+ @param RequestedWidth The width of the pop-up.
+ @param NumberOfLines The number of lines.
+ @param Marker The variable argument list for the list of string to be printed.
+
+**/
+VOID
+CreateSharedPopUp (
+ IN UINTN RequestedWidth,
+ IN UINTN NumberOfLines,
+ IN VA_LIST Marker
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ CHAR16 Character;
+ UINTN Start;
+ UINTN End;
+ UINTN Top;
+ UINTN Bottom;
+ CHAR16 *String;
+ UINTN DimensionsWidth;
+ UINTN DimensionsHeight;
+
+ DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
+ DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+
+ if ((RequestedWidth + 2) > DimensionsWidth) {
+ RequestedWidth = DimensionsWidth - 2;
+ }
+
+ //
+ // Subtract the PopUp width from total Columns, allow for one space extra on
+ // each end plus a border.
+ //
+ Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;
+ End = Start + RequestedWidth + 1;
+
+ Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;
+ Bottom = Top + NumberOfLines + 2;
+
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (Start, Top, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ Character = BOXDRAW_VERTICAL;
+
+ Count = 0;
+ for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
+ String = VA_ARG (Marker, CHAR16*);
+
+ //
+ // This will clear the background of the line - we never know who might have been
+ // here before us. This differs from the next clear in that it used the non-reverse
+ // video for normal printing.
+ //
+ if (GetStringWidth (String) / 2 > 1) {
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ }
+
+ //
+ // Passing in a space results in the assumption that this is where typing will occur
+ //
+ if (String[0] == L' ') {
+ ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());
+ }
+
+ //
+ // Passing in a NULL results in a blank space
+ //
+ if (String[0] == CHAR_NULL) {
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ }
+
+ PrintStringAt (
+ ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,
+ Index + 1,
+ String
+ );
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+ PrintCharAt (Start, Index + 1, Character);
+ PrintCharAt (End - 1, Index + 1, Character);
+ }
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (Start, Bottom - 1, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+}
+
+/**
+ Draw a pop up windows based on the dimension, number of lines and
+ strings specified.
+
+ @param RequestedWidth The width of the pop-up.
+ @param NumberOfLines The number of lines.
+ @param ... A series of text strings that displayed in the pop-up.
+
+**/
+VOID
+EFIAPI
+CreateMultiStringPopUp (
+ IN UINTN RequestedWidth,
+ IN UINTN NumberOfLines,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, NumberOfLines);
+
+ CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);
+
+ VA_END (Marker);
+}
+
+/**
+ Process nothing.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
+
+**/
+VOID
+EFIAPI
+EmptyEventProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+}
+
+/**
+ Process for the refresh interval statement.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
+
+**/
+VOID
+EFIAPI
+RefreshTimeOutProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ WARNING_IF_CONTEXT *EventInfo;
+ CHAR16 TimeOutString[MAX_TIME_OUT_LEN];
+
+ EventInfo = (WARNING_IF_CONTEXT *) Context;
+
+ if (*(EventInfo->TimeOut) == 0) {
+ gBS->CloseEvent (Event);
+
+ gBS->SignalEvent (EventInfo->SyncEvent);
+ return;
+ }
+
+ UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));
+
+ CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL);
+
+ *(EventInfo->TimeOut) -= 1;
+}
+
+/**
+ Display error message for invalid password.
+
+**/
+VOID
+PasswordInvalid (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+
+ //
+ // Invalid password, prompt error message
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+}
+
+/**
+ Process password op code.
+
+ @param MenuOption The menu for current password op code.
+
+ @retval EFI_SUCCESS Question Option process success.
+ @retval Other Question Option process fail.
+
+**/
+EFI_STATUS
+PasswordProcess (
+ IN UI_MENU_OPTION *MenuOption
+ )
+{
+ CHAR16 *StringPtr;
+ CHAR16 *TempString;
+ UINTN Maximum;
+ EFI_STATUS Status;
+ EFI_IFR_PASSWORD *PasswordInfo;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ EFI_INPUT_KEY Key;
+
+ Question = MenuOption->ThisTag;
+ PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;
+ Maximum = PasswordInfo->MaxSize;
+ Status = EFI_SUCCESS;
+
+ StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
+ ASSERT (StringPtr);
+
+ //
+ // Use a NULL password to test whether old password is required
+ //
+ *StringPtr = 0;
+ Status = Question->PasswordCheck (gFormData, Question, StringPtr);
+ if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
+ //
+ // Password can't be set now.
+ //
+ if (Status == EFI_UNSUPPORTED) {
+ do {
+ CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ }
+ FreePool (StringPtr);
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Old password exist, ask user for the old password
+ //
+ Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
+ if (EFI_ERROR (Status)) {
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ FreePool (StringPtr);
+ return Status;
+ }
+
+ //
+ // Check user input old password
+ //
+ Status = Question->PasswordCheck (gFormData, Question, StringPtr);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_READY) {
+ //
+ // Typed in old password incorrect
+ //
+ PasswordInvalid ();
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ FreePool (StringPtr);
+ return Status;
+ }
+ }
+
+ //
+ // Ask for new password
+ //
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset state machine for password
+ //
+ Question->PasswordCheck (gFormData, Question, NULL);
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ FreePool (StringPtr);
+ return Status;
+ }
+
+ //
+ // Confirm new password
+ //
+ TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
+ ASSERT (TempString);
+ Status = ReadString (MenuOption, gConfirmPassword, TempString);
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset state machine for password
+ //
+ Question->PasswordCheck (gFormData, Question, NULL);
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
+ FreePool (StringPtr);
+ FreePool (TempString);
+ return Status;
+ }
+
+ //
+ // Compare two typed-in new passwords
+ //
+ if (StrCmp (StringPtr, TempString) == 0) {
+ gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
+ gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
+ gUserInput->InputValue.Type = Question->CurrentValue.Type;
+ gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
+
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Reset state machine for password
+ //
+ Question->PasswordCheck (gFormData, Question, NULL);
+
+ //
+ // Two password mismatch, prompt error message
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ Status = EFI_INVALID_PARAMETER;
+ }
+ ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
+ ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
+ FreePool (TempString);
+ FreePool (StringPtr);
+
+ return Status;
+}
+
+/**
+ Print some debug message about mismatched menu info.
+
+ @param MenuOption The MenuOption for this Question.
+
+**/
+VOID
+PrintMismatchMenuInfo (
+ IN UI_MENU_OPTION *MenuOption
+)
+{
+ CHAR16 *FormTitleStr;
+ CHAR16 *FormSetTitleStr;
+ CHAR16 *OneOfOptionStr;
+ CHAR16 *QuestionName;
+ LIST_ENTRY *Link;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ EFI_IFR_ORDERED_LIST *OrderList;
+ UINT8 Index;
+ EFI_HII_VALUE HiiValue;
+ EFI_HII_VALUE *QuestionValue;
+ DISPLAY_QUESTION_OPTION *Option;
+ UINT8 *ValueArray;
+ UINT8 ValueType;
+ EFI_IFR_FORM_SET *FormsetBuffer;
+ UINTN FormsetBufferSize;
+
+ Question = MenuOption->ThisTag;
+ HiiGetFormSetFromHiiHandle (gFormData->HiiHandle, &FormsetBuffer, &FormsetBufferSize);
+
+ FormSetTitleStr = GetToken (FormsetBuffer->FormSetTitle, gFormData->HiiHandle);
+ FormTitleStr = GetToken (gFormData->FormTitle, gFormData->HiiHandle);
+
+ DEBUG ((DEBUG_ERROR, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName, &gFormData->FormSetGuid, FormSetTitleStr));
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName, gFormData->FormId, FormTitleStr));
+
+ if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
+ QuestionName = GetToken (((EFI_IFR_ORDERED_LIST*)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);
+ Link = GetFirstNode (&Question->OptionListHead);
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ ValueType = Option->OptionOpCode->Type;
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName));
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName, QuestionName));
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName));
+
+ OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
+ for (Index = 0; Index < OrderList->MaxContainers; Index++) {
+ ValueArray = Question->CurrentValue.Buffer;
+ HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
+ DEBUG ((DEBUG_ERROR, " Value[%d] =%ld.\n", Index, HiiValue.Value.u64));
+ }
+ } else if (Question->OpCode->OpCode == EFI_IFR_ONE_OF_OP) {
+ QuestionName = GetToken (((EFI_IFR_ONE_OF*)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);
+ QuestionValue = &Question->CurrentValue;
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName));
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName, QuestionName));
+ switch (QuestionValue->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %ld.\n",gEfiCallerBaseName, QuestionValue->Value.u64));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u32));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u16));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u8));
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ Index = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ OneOfOptionStr = GetToken (Option->OptionOpCode->Option, gFormData->HiiHandle);
+ switch (Option->OptionOpCode->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u64, OneOfOptionStr));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u32, OneOfOptionStr));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u16, OneOfOptionStr));
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u8, OneOfOptionStr));
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ Index++;
+ }
+}
+
+/**
+ Process a Question's Option (whether selected or un-selected).
+
+ @param MenuOption The MenuOption for this Question.
+ @param Selected TRUE: if Question is selected.
+ @param OptionString Pointer of the Option String to be displayed.
+ @param SkipErrorValue Whether need to return when value without option for it.
+
+ @retval EFI_SUCCESS Question Option process success.
+ @retval Other Question Option process fail.
+
+**/
+EFI_STATUS
+ProcessOptions (
+ IN UI_MENU_OPTION *MenuOption,
+ IN BOOLEAN Selected,
+ OUT CHAR16 **OptionString,
+ IN BOOLEAN SkipErrorValue
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *StringPtr;
+ UINTN Index;
+ FORM_DISPLAY_ENGINE_STATEMENT *Question;
+ CHAR16 FormattedNumber[21];
+ UINT16 Number;
+ CHAR16 Character[2];
+ EFI_INPUT_KEY Key;
+ UINTN BufferSize;
+ DISPLAY_QUESTION_OPTION *OneOfOption;
+ LIST_ENTRY *Link;
+ EFI_HII_VALUE HiiValue;
+ EFI_HII_VALUE *QuestionValue;
+ DISPLAY_QUESTION_OPTION *Option;
+ UINTN Index2;
+ UINT8 *ValueArray;
+ UINT8 ValueType;
+ EFI_IFR_ORDERED_LIST *OrderList;
+ BOOLEAN ValueInvalid;
+ UINTN MaxLen;
+
+ Status = EFI_SUCCESS;
+
+ StringPtr = NULL;
+ Character[1] = L'\0';
+ *OptionString = NULL;
+ ValueInvalid = FALSE;
+
+ ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
+ BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
+
+ Question = MenuOption->ThisTag;
+ QuestionValue = &Question->CurrentValue;
+
+ switch (Question->OpCode->OpCode) {
+ case EFI_IFR_ORDERED_LIST_OP:
+
+ //
+ // Check whether there are Options of this OrderedList
+ //
+ if (IsListEmpty (&Question->OptionListHead)) {
+ break;
+ }
+
+ OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+
+ ValueType = OneOfOption->OptionOpCode->Type;
+ ValueArray = Question->CurrentValue.Buffer;
+
+ if (Selected) {
+ //
+ // Go ask for input
+ //
+ Status = GetSelectionInputPopUp (MenuOption);
+ } else {
+ //
+ // We now know how many strings we will have, so we can allocate the
+ // space required for the array or strings.
+ //
+ MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
+ *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (*OptionString);
+
+ HiiValue.Type = ValueType;
+ HiiValue.Value.u64 = 0;
+ for (Index = 0; Index < OrderList->MaxContainers; Index++) {
+ HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
+ if (HiiValue.Value.u64 == 0) {
+ //
+ // Values for the options in ordered lists should never be a 0
+ //
+ break;
+ }
+
+ OneOfOption = ValueToOption (Question, &HiiValue);
+ if (OneOfOption == NULL) {
+ //
+ // Print debug msg for the mistach menu.
+ //
+ PrintMismatchMenuInfo (MenuOption);
+
+ if (SkipErrorValue) {
+ //
+ // Just try to get the option string, skip the value which not has option.
+ //
+ continue;
+ }
+
+ //
+ // Show error message
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ //
+ // The initial value of the orderedlist is invalid, force to be valid value
+ // Exit current DisplayForm with new value.
+ //
+ gUserInput->SelectedStatement = Question;
+ gMisMatch = TRUE;
+ ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
+ ASSERT (ValueArray != NULL);
+ gUserInput->InputValue.Buffer = ValueArray;
+ gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
+ gUserInput->InputValue.Type = Question->CurrentValue.Type;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ Index2 = 0;
+ while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
+ Index2++;
+ }
+ SetArrayData (ValueArray, ValueType, Index2, 0);
+
+ FreePool (*OptionString);
+ *OptionString = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ Character[0] = LEFT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], MaxLen, StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ Character[0] = CHAR_CARRIAGE_RETURN;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ FreePool (StringPtr);
+ }
+
+ //
+ // If valid option more than the max container, skip these options.
+ //
+ if (Index >= OrderList->MaxContainers) {
+ break;
+ }
+
+ //
+ // Search the other options, try to find the one not in the container.
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
+ continue;
+ }
+
+ //
+ // Print debug msg for the mistach menu.
+ //
+ PrintMismatchMenuInfo (MenuOption);
+
+ if (SkipErrorValue) {
+ //
+ // Not report error, just get the correct option string info.
+ //
+ Character[0] = LEFT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], MaxLen, StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ Character[0] = CHAR_CARRIAGE_RETURN;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ FreePool (StringPtr);
+
+ continue;
+ }
+
+ if (!ValueInvalid) {
+ ValueInvalid = TRUE;
+ //
+ // Show error message
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ //
+ // The initial value of the orderedlist is invalid, force to be valid value
+ // Exit current DisplayForm with new value.
+ //
+ gUserInput->SelectedStatement = Question;
+ gMisMatch = TRUE;
+ ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
+ ASSERT (ValueArray != NULL);
+ gUserInput->InputValue.Buffer = ValueArray;
+ gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
+ gUserInput->InputValue.Type = Question->CurrentValue.Type;
+ }
+
+ SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
+ }
+
+ if (ValueInvalid) {
+ FreePool (*OptionString);
+ *OptionString = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Check whether there are Options of this OneOf
+ //
+ if (IsListEmpty (&Question->OptionListHead)) {
+ break;
+ }
+ if (Selected) {
+ //
+ // Go ask for input
+ //
+ Status = GetSelectionInputPopUp (MenuOption);
+ } else {
+ MaxLen = BufferSize / sizeof(CHAR16);
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ OneOfOption = ValueToOption (Question, QuestionValue);
+ if (OneOfOption == NULL) {
+ //
+ // Print debug msg for the mistach menu.
+ //
+ PrintMismatchMenuInfo (MenuOption);
+
+ if (SkipErrorValue) {
+ //
+ // Not report error, just get the correct option string info.
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+ } else {
+ //
+ // Show error message
+ //
+ do {
+ CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ //
+ // Force the Question value to be valid
+ // Exit current DisplayForm with new value.
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
+
+ gUserInput->InputValue.Type = Option->OptionOpCode->Type;
+ switch (gUserInput->InputValue.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ gUserInput->SelectedStatement = Question;
+ gMisMatch = TRUE;
+ FreePool (*OptionString);
+ *OptionString = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Character[0] = LEFT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+ StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
+ ASSERT (StringPtr != NULL);
+ NewStrCat (OptionString[0], MaxLen, StringPtr);
+ Character[0] = RIGHT_ONEOF_DELIMITER;
+ NewStrCat (OptionString[0], MaxLen, Character);
+
+ FreePool (StringPtr);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ if (Selected) {
+ //
+ // Since this is a BOOLEAN operation, flip it upon selection
+ //
+ gUserInput->InputValue.Type = QuestionValue->Type;
+ gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
+
+ //
+ // Perform inconsistent check
+ //
+ return EFI_SUCCESS;
+ } else {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
+
+ if (QuestionValue->Value.b) {
+ *(OptionString[0] + 1) = CHECK_ON;
+ } else {
+ *(OptionString[0] + 1) = CHECK_OFF;
+ }
+ *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ if (Selected) {
+ //
+ // Go ask for input
+ //
+ Status = GetNumericInput (MenuOption);
+ } else {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ *OptionString[0] = LEFT_NUMERIC_DELIMITER;
+
+ //
+ // Formatted print
+ //
+ PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
+ Number = (UINT16) GetStringWidth (FormattedNumber);
+ CopyMem (OptionString[0] + 1, FormattedNumber, Number);
+
+ *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
+ }
+ break;
+
+ case EFI_IFR_DATE_OP:
+ if (Selected) {
+ //
+ // This is similar to numerics
+ //
+ Status = GetNumericInput (MenuOption);
+ } else {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ switch (MenuOption->Sequence) {
+ case 0:
+ *OptionString[0] = LEFT_NUMERIC_DELIMITER;
+ if (QuestionValue->Value.date.Month == 0xff){
+ UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
+ } else {
+ UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
+ }
+ *(OptionString[0] + 3) = DATE_SEPARATOR;
+ break;
+
+ case 1:
+ SetUnicodeMem (OptionString[0], 4, L' ');
+ if (QuestionValue->Value.date.Day == 0xff){
+ UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
+ } else {
+ UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
+ }
+ *(OptionString[0] + 6) = DATE_SEPARATOR;
+ break;
+
+ case 2:
+ SetUnicodeMem (OptionString[0], 7, L' ');
+ if (QuestionValue->Value.date.Year == 0xff){
+ UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
+ } else {
+ UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
+ }
+ *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_TIME_OP:
+ if (Selected) {
+ //
+ // This is similar to numerics
+ //
+ Status = GetNumericInput (MenuOption);
+ } else {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ switch (MenuOption->Sequence) {
+ case 0:
+ *OptionString[0] = LEFT_NUMERIC_DELIMITER;
+ if (QuestionValue->Value.time.Hour == 0xff){
+ UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
+ } else {
+ UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
+ }
+ *(OptionString[0] + 3) = TIME_SEPARATOR;
+ break;
+
+ case 1:
+ SetUnicodeMem (OptionString[0], 4, L' ');
+ if (QuestionValue->Value.time.Minute == 0xff){
+ UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
+ } else {
+ UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
+ }
+ *(OptionString[0] + 6) = TIME_SEPARATOR;
+ break;
+
+ case 2:
+ SetUnicodeMem (OptionString[0], 7, L' ');
+ if (QuestionValue->Value.time.Second == 0xff){
+ UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
+ } else {
+ UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
+ }
+ *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_STRING_OP:
+ if (Selected) {
+ StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
+ ASSERT (StringPtr);
+ CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
+
+ Status = ReadString (MenuOption, gPromptForData, StringPtr);
+ if (EFI_ERROR (Status)) {
+ FreePool (StringPtr);
+ return Status;
+ }
+
+ gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
+ gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
+ gUserInput->InputValue.Type = Question->CurrentValue.Type;
+ gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
+ FreePool (StringPtr);
+ return EFI_SUCCESS;
+ } else {
+ *OptionString = AllocateZeroPool (BufferSize);
+ ASSERT (*OptionString);
+
+ if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
+ *(OptionString[0]) = '_';
+ } else {
+ if (Question->CurrentValue.BufferLen < BufferSize) {
+ BufferSize = Question->CurrentValue.BufferLen;
+ }
+ CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
+ }
+ }
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ if (Selected) {
+ Status = PasswordProcess (MenuOption);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Process the help string: Split StringPtr to several lines of strings stored in
+ FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
+
+ @param StringPtr The entire help string.
+ @param FormattedString The oupput formatted string.
+ @param EachLineWidth The max string length of each line in the formatted string.
+ @param RowCount TRUE: if Question is selected.
+
+**/
+UINTN
+ProcessHelpString (
+ IN CHAR16 *StringPtr,
+ OUT CHAR16 **FormattedString,
+ OUT UINT16 *EachLineWidth,
+ IN UINTN RowCount
+ )
+{
+ UINTN Index;
+ CHAR16 *OutputString;
+ UINTN TotalRowNum;
+ UINTN CheckedNum;
+ UINT16 GlyphWidth;
+ UINT16 LineWidth;
+ UINT16 MaxStringLen;
+ UINT16 StringLen;
+
+ TotalRowNum = 0;
+ CheckedNum = 0;
+ GlyphWidth = 1;
+ Index = 0;
+ MaxStringLen = 0;
+ StringLen = 0;
+
+ //
+ // Set default help string width.
+ //
+ LineWidth = (UINT16) (gHelpBlockWidth - 1);
+
+ //
+ // Get row number of the String.
+ //
+ while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
+ if (StringLen > MaxStringLen) {
+ MaxStringLen = StringLen;
+ }
+
+ TotalRowNum ++;
+ FreePool (OutputString);
+ }
+ *EachLineWidth = MaxStringLen;
+
+ *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
+ ASSERT (*FormattedString != NULL);
+
+ //
+ // Generate formatted help string array.
+ //
+ GlyphWidth = 1;
+ Index = 0;
+ while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
+ CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
+ CheckedNum ++;
+ FreePool (OutputString);
+ }
+
+ return TotalRowNum;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthConfigureVfr.Vfr b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthConfigureVfr.Vfr
new file mode 100644
index 000000000..9fc7ed34e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthConfigureVfr.Vfr
@@ -0,0 +1,33 @@
+///** @file
+//
+// VFR to produce the formset used by BDS. This form only lists
+// the Configure Required driver health instances.
+//
+// Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+
+//**/
+#include "DriverHealthManagerVfr.h"
+
+formset
+ guid = DRIVER_HEALTH_CONFIGURE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_TITLE),
+ help = STRING_TOKEN(STR_FORM_HELP),
+ classguid = DRIVER_HEALTH_CONFIGURE_FORMSET_GUID,
+
+ form formid = DRIVER_HEALTH_FORM_ID,
+ title = STRING_TOKEN(STR_FORM_TITLE);
+
+ label LABEL_BEGIN;
+ label LABEL_END;
+
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = QUESTION_ID_REFRESH_CONFIGURE;
+ endif;
+
+ endform;
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c
new file mode 100644
index 000000000..92c738a3f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c
@@ -0,0 +1,987 @@
+/** @file
+ This module produces two driver health manager forms.
+ One will be used by BDS core to configure the Configured Required
+ driver health instances, the other will be automatically included by
+ firmware setup (UI).
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DriverHealthManagerDxe.h"
+#include "DriverHealthManagerVfr.h"
+
+EFI_HII_CONFIG_ACCESS_PROTOCOL mDriverHealthManagerConfigAccess = {
+ DriverHealthManagerFakeExtractConfig,
+ DriverHealthManagerFakeRouteConfig,
+ DriverHealthManagerCallback
+};
+
+EFI_GUID mDriverHealthManagerForm = DRIVER_HEALTH_MANAGER_FORMSET_GUID;
+
+FORM_DEVICE_PATH mDriverHealthManagerFormDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ EFI_CALLER_ID_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_HII_HANDLE mDriverHealthManagerHiiHandle;
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *mDriverHealthManagerHealthInfo = NULL;
+UINTN mDriverHealthManagerHealthInfoCount = 0;
+EFI_HII_DATABASE_PROTOCOL *mDriverHealthManagerDatabase;
+
+
+extern UINT8 DriverHealthManagerVfrBin[];
+extern UINT8 DriverHealthConfigureVfrBin[];
+
+/**
+ 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
+DriverHealthManagerFakeExtractConfig (
+ 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
+DriverHealthManagerFakeRouteConfig (
+ 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;
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ Install the health manager forms.
+ One will be used by BDS core to configure the Configured Required
+ driver health instances, the other will be automatically included by
+ firmware setup (UI).
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS The health manager forms are successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDriverHealthManager (
+ EFI_HANDLE ImageHandle,
+ EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &mDriverHealthManagerDatabase
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDevicePathProtocolGuid,
+ &mDriverHealthManagerFormDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mDriverHealthManagerConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ //
+ // Publish Driver Health HII data.
+ //
+ mDriverHealthManagerHiiHandle = HiiAddPackages (
+ &gEfiCallerIdGuid,
+ Handle,
+ DriverHealthManagerVfrBin,
+ DriverHealthConfigureVfrBin,
+ STRING_ARRAY_NAME,
+ NULL
+ );
+ ASSERT (mDriverHealthManagerHiiHandle != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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 *
+DriverHealthManagerSelectBestLanguage (
+ 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
+DriverHealthManagerGetComponentNameWorker (
+ 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 = DriverHealthManagerSelectBestLanguage (
+ (*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
+DriverHealthManagerGetDriverNameWorker (
+ 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 = DriverHealthManagerGetComponentNameWorker (
+ 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.
+
+ @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
+ specified by ControllerHandle and ChildHandle.
+
+
+**/
+CHAR16 *
+DriverHealthManagerGetDriverName (
+ IN EFI_HANDLE DriverBindingHandle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *DriverName;
+
+ //
+ // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
+ //
+ Status = DriverHealthManagerGetDriverNameWorker (&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 = DriverHealthManagerGetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, &DriverName);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return AllocateCopyPool (StrSize (DriverName), DriverName);
+ } else {
+ return ConvertDevicePathToText (DevicePathFromHandle (DriverBindingHandle), FALSE, TRUE);
+ }
+}
+
+
+
+/**
+ 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
+DriverHealthManagerGetControllerNameWorker (
+ 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 = DriverHealthManagerGetComponentNameWorker (
+ 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 DriverBindingHandle 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.
+
+ @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
+ specified by ControllerHandle and ChildHandle.
+**/
+CHAR16 *
+DriverHealthManagerGetControllerName (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ControllerName;
+
+ //
+ // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
+ //
+ Status = DriverHealthManagerGetControllerNameWorker (
+ &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 = DriverHealthManagerGetControllerNameWorker (
+ &gEfiComponentNameProtocolGuid,
+ DriverBindingHandle,
+ ControllerHandle,
+ ChildHandle,
+ &ControllerName
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return AllocateCopyPool (StrSize (ControllerName), ControllerName);
+ } else {
+ return ConvertDevicePathToText (DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle), FALSE, TRUE);
+ }
+}
+
+/**
+ The repair notify function.
+ @param Value A value between 0 and Limit that identifies the current progress
+ of the repair operation.
+ @param Limit The maximum value of Value for the current repair operation.
+ If Limit is 0, then the completion progress is indeterminate.
+ For example, a driver that wants to specify progress in percent
+ would use a Limit value of 100.
+
+ @retval EFI_SUCCESS Successfully return from the notify function.
+**/
+EFI_STATUS
+EFIAPI
+DriverHealthManagerRepairNotify (
+ IN UINTN Value,
+ IN UINTN Limit
+ )
+{
+ DEBUG ((EFI_D_INFO, "[DriverHealthManagement]RepairNotify: %d/%d\n", Value, Limit));
+ return EFI_SUCCESS;
+}
+
+/**
+ Look for the formset GUID which has the gEfiHiiDriverHealthFormsetGuid class GUID in the specified HII package list.
+
+ @param Handle Handle to the HII package list.
+ @param FormsetGuid Return the formset GUID.
+
+ @retval EFI_SUCCESS The formset is found successfully.
+ @retval EFI_NOT_FOUND The formset cannot be found.
+**/
+EFI_STATUS
+DriverHealthManagerGetFormsetId (
+ IN EFI_HII_HANDLE Handle,
+ OUT EFI_GUID *FormsetGuid
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN BufferSize;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ UINT32 Offset;
+ UINT32 Offset2;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT8 Index;
+ UINT8 NumberOfClassGuid;
+ EFI_GUID *ClassGuid;
+
+ //
+ // Get HII PackageList
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (HiiPackageList != NULL);
+
+ //
+ // Get Form package from this HII package List
+ //
+ for (Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); Offset < ReadUnaligned32 (&HiiPackageList->PackageLength); Offset += PackageHeader.Length) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Search FormSet in this Form Package
+ //
+
+ for (Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); Offset2 < PackageHeader.Length; Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length) {
+ OpCodeData = Package + Offset2;
+
+ if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) &&
+ (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags))) {
+ //
+ // Try to compare against formset class GUID
+ //
+ NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
+ for (Index = 0; Index < NumberOfClassGuid; Index++) {
+ if (CompareGuid (&gEfiHiiDriverHealthFormsetGuid, &ClassGuid[Index])) {
+ CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ FreePool (HiiPackageList);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Form package not found in this Package List
+ //
+ FreePool (HiiPackageList);
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Processes a single controller using the EFI Driver Health Protocol associated with
+ that controller.
+
+ @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.
+**/
+VOID
+DriverHealthManagerProcessSingleControllerHealth (
+ 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
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (HealthStatus != EfiDriverHealthStatusConfigurationRequired);
+ //
+ // 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).
+ //
+ switch (HealthStatus) {
+
+ case EfiDriverHealthStatusRepairRequired:
+ Status = DriverHealth->Repair (
+ DriverHealth,
+ ControllerHandle,
+ ChildHandle,
+ DriverHealthManagerRepairNotify
+ );
+ break;
+
+ case EfiDriverHealthStatusRebootRequired:
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ break;
+
+ case EfiDriverHealthStatusReconnectRequired:
+ Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ //
+ // Disconnect failed. Need to promote reconnect to a reboot.
+ //
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ } else {
+ gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Update the form to include the driver health instances.
+
+ @param ConfigureOnly Only include the configure required driver health instances
+ when TRUE, include all the driver health instances otherwise.
+**/
+VOID
+DriverHealthManagerUpdateForm (
+ BOOLEAN ConfigureOnly
+ )
+{
+ EFI_STATUS Status;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ UINTN Index;
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+ CHAR16 String[512];
+ UINTN StringCount;
+ EFI_STRING TmpString;
+ EFI_STRING DriverName;
+ EFI_STRING ControllerName;
+ UINTN MessageIndex;
+ EFI_HANDLE DriverHandle;
+ EFI_STRING_ID DevicePath;
+ EFI_GUID FormsetGuid;
+
+ EfiBootManagerFreeDriverHealthInfo (mDriverHealthManagerHealthInfo, mDriverHealthManagerHealthInfoCount);
+ mDriverHealthManagerHealthInfo = EfiBootManagerGetDriverHealthInfo (&mDriverHealthManagerHealthInfoCount);
+
+ //
+ // 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_BEGIN;
+
+ //
+ // 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;
+
+ for (Index = 0; Index < mDriverHealthManagerHealthInfoCount; Index++) {
+ if (ConfigureOnly && mDriverHealthManagerHealthInfo[Index].HealthStatus != EfiDriverHealthStatusConfigurationRequired) {
+ continue;
+ }
+ DriverName = DriverHealthManagerGetDriverName (mDriverHealthManagerHealthInfo[Index].DriverHealthHandle);
+ ASSERT (DriverName != NULL);
+
+ if (mDriverHealthManagerHealthInfo[Index].ControllerHandle == NULL) {
+ //
+ // The ControllerHandle is set to NULL and the HealthStatus is set to EfiDriverHealthStatusHealthy
+ // if all the controllers managed by the driver are in healthy state.
+ //
+ ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy);
+ UnicodeSPrint (String, sizeof (String), L"%s", DriverName);
+ } else {
+ ControllerName = DriverHealthManagerGetControllerName (
+ mDriverHealthManagerHealthInfo[Index].DriverHealthHandle,
+ mDriverHealthManagerHealthInfo[Index].ControllerHandle,
+ mDriverHealthManagerHealthInfo[Index].ChildHandle
+ );
+ ASSERT (ControllerName != NULL);
+ UnicodeSPrint (String, sizeof (String), L"%s %s", DriverName, ControllerName);
+ FreePool (ControllerName);
+ }
+ FreePool (DriverName);
+
+ Prompt = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL);
+
+ switch(mDriverHealthManagerHealthInfo[Index].HealthStatus) {
+ case EfiDriverHealthStatusRepairRequired:
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REPAIR_REQUIRED), NULL);
+ break;
+ case EfiDriverHealthStatusConfigurationRequired:
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_CONFIGURATION_REQUIRED), NULL);
+ break;
+ case EfiDriverHealthStatusFailed:
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_FAILED), NULL);
+ break;
+ case EfiDriverHealthStatusReconnectRequired:
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_RECONNECT_REQUIRED), NULL);
+ break;
+ case EfiDriverHealthStatusRebootRequired:
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REBOOT_REQUIRED), NULL);
+ break;
+ default:
+ ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy);
+ TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_HEALTHY), NULL);
+ break;
+ }
+ StringCount = UnicodeSPrint (String, sizeof (String), L"%s\n", TmpString);
+ FreePool (TmpString);
+
+ //
+ // Add the message of the Module itself provided as the help.
+ //
+ if (mDriverHealthManagerHealthInfo[Index].MessageList != NULL) {
+ for (MessageIndex = 0; mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle != NULL; MessageIndex++) {
+ TmpString = HiiGetString (
+ mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle,
+ mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].StringId,
+ NULL
+ );
+ StringCount += UnicodeSPrint (String + StringCount, sizeof (String) - sizeof (String[0]) * StringCount, L"\n%s", TmpString);
+ FreePool (TmpString);
+ }
+ }
+ Help = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL);
+
+ switch (mDriverHealthManagerHealthInfo[Index].HealthStatus) {
+ case EfiDriverHealthStatusConfigurationRequired:
+ Status = mDriverHealthManagerDatabase->GetPackageListHandle (
+ mDriverHealthManagerDatabase,
+ mDriverHealthManagerHealthInfo[Index].HiiHandle,
+ &DriverHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ TmpString = ConvertDevicePathToText (DevicePathFromHandle (DriverHandle), FALSE, TRUE);
+ DevicePath = HiiSetString (mDriverHealthManagerHiiHandle, 0, TmpString, NULL);
+ FreePool (TmpString);
+
+ Status = DriverHealthManagerGetFormsetId (mDriverHealthManagerHealthInfo[Index].HiiHandle, &FormsetGuid);
+ ASSERT_EFI_ERROR (Status);
+
+ HiiCreateGotoExOpCode (
+ StartOpCodeHandle,
+ 0,
+ Prompt,
+ Help,
+ 0,
+ 0,
+ 0,
+ &FormsetGuid,
+ DevicePath
+ );
+ break;
+
+ case EfiDriverHealthStatusRepairRequired:
+ case EfiDriverHealthStatusReconnectRequired:
+ case EfiDriverHealthStatusRebootRequired:
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ (EFI_QUESTION_ID) (Index + QUESTION_ID_DRIVER_HEALTH_BASE),
+ Prompt,
+ Help,
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ break;
+
+ default:
+ ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy ||
+ mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusFailed);
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ Prompt,
+ Help,
+ 0
+ );
+ break;
+ }
+ }
+
+ Status = HiiUpdateForm (
+ mDriverHealthManagerHiiHandle,
+ ConfigureOnly ? PcdGetPtr (PcdDriverHealthConfigureForm) : &mDriverHealthManagerForm,
+ DRIVER_HEALTH_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+/**
+ Called when the form is closing to remove the dynamicly added string from the HII package list.
+**/
+VOID
+DriverHealthManagerCleanDynamicString (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN BufferSize;
+ EFI_HII_PACKAGE_HEADER *PackageHeader;
+ UINT32 FixedStringSize;
+
+ FixedStringSize = *(UINT32 *) &STRING_ARRAY_NAME - sizeof (UINT32);
+ BufferSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER) + FixedStringSize + sizeof (EFI_HII_PACKAGE_HEADER);
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ HiiPackageList->PackageLength = (UINT32) BufferSize;
+ CopyMem (&HiiPackageList->PackageListGuid, &gEfiCallerIdGuid, sizeof (EFI_GUID));
+
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageList + 1);
+ CopyMem (PackageHeader, STRING_ARRAY_NAME + sizeof (UINT32), FixedStringSize);
+
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHeader + PackageHeader->Length);
+ PackageHeader->Type = EFI_HII_PACKAGE_END;
+ PackageHeader->Length = sizeof (EFI_HII_PACKAGE_HEADER);
+
+ Status = mDriverHealthManagerDatabase->UpdatePackageList (
+ mDriverHealthManagerDatabase,
+ mDriverHealthManagerHiiHandle,
+ HiiPackageList
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Form package not found in this Package List
+ //
+ FreePool (HiiPackageList);
+}
+
+/**
+ This function is invoked if user selected a interactive opcode from Driver Health's
+ Formset.
+
+ @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
+DriverHealthManagerCallback (
+ 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 Index;
+
+ if (QuestionId == QUESTION_ID_REFRESH_MANAGER || QuestionId == QUESTION_ID_REFRESH_CONFIGURE) {
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE));
+ } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
+ DriverHealthManagerCleanDynamicString ();
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // 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;
+ }
+
+ DEBUG ((EFI_D_ERROR, "QuestionId = %x\n", QuestionId));
+
+ //
+ // 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.
+ //
+ Index = QuestionId - QUESTION_ID_DRIVER_HEALTH_BASE;
+ ASSERT (Index < mDriverHealthManagerHealthInfoCount);
+ //
+ // Process the driver's healthy status for the specify module
+ //
+ DriverHealthManagerProcessSingleControllerHealth (
+ mDriverHealthManagerHealthInfo[Index].DriverHealth,
+ mDriverHealthManagerHealthInfo[Index].ControllerHandle,
+ mDriverHealthManagerHealthInfo[Index].ChildHandle,
+ mDriverHealthManagerHealthInfo[Index].HealthStatus,
+ &(mDriverHealthManagerHealthInfo[Index].MessageList),
+ mDriverHealthManagerHealthInfo[Index].HiiHandle
+ );
+
+ DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE));
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.h b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.h
new file mode 100644
index 000000000..f4a09d03a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.h
@@ -0,0 +1,127 @@
+/** @file
+ This module produces two driver health manager forms.
+ One will be used by BDS core to configure the Configured Required
+ driver health instances, the other will be automatically included by
+ firmware setup (UI).
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DRIVER_HEALTH_MANAGEMENT_DXE_H_
+#define _DRIVER_HEALTH_MANAGEMENT_DXE_H_
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverHealth.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiDatabase.h>
+#include <Guid/MdeModuleHii.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>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FORM_DEVICE_PATH;
+
+/**
+ 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
+DriverHealthManagerCallback (
+ 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 illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverHealthManagerFakeExtractConfig (
+ 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
+DriverHealthManagerFakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
new file mode 100644
index 000000000..f6310b234
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
@@ -0,0 +1,74 @@
+## @file
+# Driver Health Manager DXE driver.
+#
+# This module produces two driver health manager forms.
+# One will be used by BDS core to configure the Configured Required
+# driver health instances, the other will be automatically included by
+# firmware setup (UI).
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DriverHealthManagerDxe
+ MODULE_UNI_FILE = DriverHealthManagerDxe.uni
+ FILE_GUID = EBF8ED7C-0DD1-4787-84F1-F48D537DCACF
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDriverHealthManager
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+
+[Sources.common]
+ DriverHealthManagerDxe.h
+ DriverHealthManagerDxe.c
+ DriverHealthManagerStrings.uni
+ DriverHealthManagerVfr.Vfr
+ DriverHealthManagerVfr.h
+ DriverHealthConfigureVfr.Vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ HiiLib
+ UefiBootManagerLib
+ PcdLib
+ DevicePathLib
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiHiiDriverHealthFormsetGuid ## CONSUMES ## GUID
+ gEfiIfrTianoGuid ## CONSUMES ## HII
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm ## CONSUMES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiFormBrowser2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DriverHealthManagerDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.uni b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.uni
new file mode 100644
index 000000000..67677fcb4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Driver Health Manager DXE driver.
+//
+// This module produces two driver health manager forms.
+// One will be used by BDS core to configure the Configured Required
+// driver health instances, the other will be automatically included by
+// firmware setup (UI).
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Driver Health Manager DXE driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces two driver health manager forms. One will be used by BDS core to configure the Configured Required driver health instances, the other will be automatically included by firmware setup (UI)."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxeExtra.uni
new file mode 100644
index 000000000..d71e2722b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Driver Health Manager DXE driver.
+//
+// This module produces two driver health manager forms.
+// One will be used by BDS core to configure the Configured Required
+// driver health instances, the other will be automatically included by
+// firmware setup (UI).
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Driver Health Manager DXE driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerStrings.uni b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerStrings.uni
new file mode 100644
index 000000000..0bdf68095
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerStrings.uni
@@ -0,0 +1,34 @@
+///** @file
+//
+// String definitions for the DriverHealthManager.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_FORM_TITLE #language en-US "Driver Health Manager"
+ #language fr-FR "Driver Health Manager"
+#string STR_FORM_HELP #language en-US "List all the Driver Health instances to manage"
+ #language fr-FR "List all the Driver Health instances to manage"
+#string STR_NULL #language en-US ""
+ #lauguage fr-FR ""
+
+#string STR_REPAIR_REQUIRED #language en-US "Repair Required."
+ #language fr-FR "Repair Required."
+#string STR_CONFIGURATION_REQUIRED #language en-US "Configuration Required."
+ #language fr-FR "Configuration Required."
+#string STR_FAILED #language en-US "Failed."
+ #language fr-FR "Failed."
+#string STR_RECONNECT_REQUIRED #language en-US "Reconnect Required."
+ #language fr-FR "Reconnect Required."
+#string STR_REBOOT_REQUIRED #language en-US "Reboot Required."
+ #language fr-FR "Reboot Required."
+#string STR_HEALTHY #language en-US "Healthy."
+ #language fr-FR "Healthy."
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.Vfr b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.Vfr
new file mode 100644
index 000000000..4c19bfcba
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.Vfr
@@ -0,0 +1,32 @@
+///** @file
+//
+// VFR to produce the formset used by UI.
+//
+// Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//**/
+
+#include "DriverHealthManagerVfr.h"
+
+formset
+ guid = DRIVER_HEALTH_MANAGER_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_TITLE),
+ help = STRING_TOKEN(STR_FORM_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ form formid = DRIVER_HEALTH_FORM_ID,
+ title = STRING_TOKEN(STR_FORM_TITLE);
+
+ label LABEL_BEGIN;
+ label LABEL_END;
+
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = QUESTION_ID_REFRESH_MANAGER;
+ endif;
+
+ endform;
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.h b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.h
new file mode 100644
index 000000000..65255c57c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerVfr.h
@@ -0,0 +1,26 @@
+/** @file
+ Definition shared by VFR file and C file.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DRIVER_HEALTH_VFR_H_
+#define _DRIVER_HEALTH_VFR_H_
+#include <Guid/HiiPlatformSetupFormset.h>
+
+#define DRIVER_HEALTH_MANAGER_FORMSET_GUID { 0xcfb3b000, 0x0b63, 0x444b, { 0xb1, 0xd1, 0x12, 0xd5, 0xd9, 0x5d, 0xc4, 0xfc } }
+#define DRIVER_HEALTH_CONFIGURE_FORMSET_GUID { 0x4296d9f4, 0xf6fc, 0x4dde, { 0x86, 0x85, 0x8c, 0xe2, 0xd7, 0x9d, 0x90, 0xf0 } }
+
+#define LABEL_BEGIN 0x2000
+#define LABEL_END 0x2001
+
+#define DRIVER_HEALTH_FORM_ID 0x1001
+
+#define QUESTION_ID_REFRESH_MANAGER 0x0001
+#define QUESTION_ID_REFRESH_CONFIGURE 0x0002
+
+#define QUESTION_ID_DRIVER_HEALTH_BASE 0x0003
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c
new file mode 100644
index 000000000..f98797225
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c
@@ -0,0 +1,2239 @@
+/** @file
+This is an example of how a driver might export data to the HII protocol to be
+later utilized by the Setup Protocol
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DriverSample.h"
+
+#define DISPLAY_ONLY_MY_ITEM 0x0002
+
+CHAR16 VariableName[] = L"MyIfrNVData";
+CHAR16 MyEfiVar[] = L"MyEfiVar";
+CHAR16 MyEfiBitVar[] = L"MyEfiBitVar";
+CHAR16 MyEfiUnionVar[] = L"MyEfiUnionVar";
+
+EFI_HANDLE DriverHandle[2] = {NULL, NULL};
+DRIVER_SAMPLE_PRIVATE_DATA *mPrivateData = NULL;
+EFI_EVENT mEvent;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath0 = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ DRIVER_SAMPLE_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 mHiiVendorDevicePath1 = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ DRIVER_SAMPLE_INVENTORY_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+
+ ASSERT (Array != NULL);
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *(((UINT8 *) Array) + Index) = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *(((UINT16 *) Array) + Index) = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *(((UINT32 *) Array) + Index) = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *(((UINT64 *) Array) + Index) = (UINT64) Value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Notification function for keystrokes.
+
+ @param[in] KeyData The key that was pressed.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+NotificationFunction(
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ gBS->SignalEvent (mEvent);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to start monitoring for CTRL-C using SimpleTextInputEx.
+
+ @retval EFI_SUCCESS The feature is enabled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
+**/
+EFI_STATUS
+EFIAPI
+InternalStartMonitor(
+ VOID
+ )
+{
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
+ EFI_KEY_DATA KeyData;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN HandleIndex;
+ VOID *NotifyHandle;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx);
+ ASSERT_EFI_ERROR (Status);
+
+ KeyData.KeyState.KeyToggleState = 0;
+ KeyData.Key.ScanCode = 0;
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
+ KeyData.Key.UnicodeChar = L'c';
+
+ Status = SimpleEx->RegisterKeyNotify(
+ SimpleEx,
+ &KeyData,
+ NotificationFunction,
+ &NotifyHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
+ Status = SimpleEx->RegisterKeyNotify(
+ SimpleEx,
+ &KeyData,
+ NotificationFunction,
+ &NotifyHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to stop monitoring for CTRL-C using SimpleTextInputEx.
+
+ @retval EFI_SUCCESS The feature is enabled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
+**/
+EFI_STATUS
+EFIAPI
+InternalStopMonitor(
+ VOID
+ )
+{
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ EFI_KEY_DATA KeyData;
+ UINTN HandleCount;
+ UINTN HandleIndex;
+ VOID *NotifyHandle;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleEx);
+ ASSERT_EFI_ERROR (Status);
+
+ KeyData.KeyState.KeyToggleState = 0;
+ KeyData.Key.ScanCode = 0;
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
+ KeyData.Key.UnicodeChar = L'c';
+
+ Status = SimpleEx->RegisterKeyNotify(
+ SimpleEx,
+ &KeyData,
+ NotificationFunction,
+ &NotifyHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle);
+ }
+
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
+ Status = SimpleEx->RegisterKeyNotify(
+ SimpleEx,
+ &KeyData,
+ NotificationFunction,
+ &NotifyHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = SimpleEx->UnregisterKeyNotify (SimpleEx, NotifyHandle);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Update names of Name/Value storage to current language.
+
+ @param PrivateData Points to the driver private data.
+
+ @retval EFI_SUCCESS All names are successfully updated.
+ @retval EFI_NOT_FOUND Failed to get Name from HII database.
+
+**/
+EFI_STATUS
+LoadNameValueNames (
+ IN DRIVER_SAMPLE_PRIVATE_DATA *PrivateData
+ )
+{
+ UINTN Index;
+
+ //
+ // Get Name/Value name string of current language
+ //
+ for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) {
+ PrivateData->NameValueName[Index] = HiiGetString (
+ PrivateData->HiiHandle[0],
+ PrivateData->NameStringId[Index],
+ NULL
+ );
+ if (PrivateData->NameValueName[Index] == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ This is a internal function.
+
+ @param StringPtr String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param Number The output value. Caller takes the responsibility
+ to free memory.
+ @param Len Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+EFI_STATUS
+GetValueOfNumber (
+ IN EFI_STRING StringPtr,
+ OUT UINT8 **Number,
+ OUT UINTN *Len
+ )
+{
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING Str;
+ UINT8 *Buf;
+ EFI_STATUS Status;
+ UINT8 DigitUint8;
+ UINTN Index;
+ CHAR16 TemStr[2];
+
+ if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buf = NULL;
+
+ TmpPtr = StringPtr;
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ *Len = StringPtr - TmpPtr;
+ Length = *Len + 1;
+
+ Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (Str == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
+ *(Str + *Len) = L'\0';
+
+ Length = (Length + 1) / 2;
+ Buf = (UINT8 *) AllocateZeroPool (Length);
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Length = *Len;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = Str[Length - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ Buf [Index/2] = DigitUint8;
+ } else {
+ Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
+ }
+ }
+
+ *Number = Buf;
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+
+ return Status;
+}
+
+/**
+ Create altcfg string.
+
+ @param Result The request result string.
+ @param ConfigHdr The request head info. <ConfigHdr> format.
+ @param Offset The offset of the parameter int he structure.
+ @param Width The width of the parameter.
+
+
+ @retval The string with altcfg info append at the end.
+**/
+EFI_STRING
+CreateAltCfgString (
+ IN EFI_STRING Result,
+ IN EFI_STRING ConfigHdr,
+ IN UINTN Offset,
+ IN UINTN Width
+ )
+{
+ EFI_STRING StringPtr;
+ EFI_STRING TmpStr;
+ UINTN NewLen;
+
+ NewLen = StrLen (Result);
+ //
+ // String Len = ConfigResp + AltConfig + AltConfig + 1("\0")
+ //
+ NewLen = (NewLen + ((1 + StrLen (ConfigHdr) + 8 + 4) + (8 + 4 + 7 + 4 + 7 + 4)) * 2 + 1) * sizeof (CHAR16);
+ StringPtr = AllocateZeroPool (NewLen);
+ if (StringPtr == NULL) {
+ return NULL;
+ }
+
+ TmpStr = StringPtr;
+ if (Result != NULL) {
+ StrCpyS (StringPtr, NewLen / sizeof (CHAR16), Result);
+ StringPtr += StrLen (Result);
+ FreePool (Result);
+ }
+
+ UnicodeSPrint (
+ StringPtr,
+ (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
+ L"&%s&ALTCFG=%04x",
+ ConfigHdr,
+ EFI_HII_DEFAULT_CLASS_STANDARD
+ );
+ StringPtr += StrLen (StringPtr);
+
+ UnicodeSPrint (
+ StringPtr,
+ (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
+ L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x",
+ Offset,
+ Width,
+ DEFAULT_CLASS_STANDARD_VALUE
+ );
+ StringPtr += StrLen (StringPtr);
+
+ UnicodeSPrint (
+ StringPtr,
+ (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
+ L"&%s&ALTCFG=%04x",
+ ConfigHdr,
+ EFI_HII_DEFAULT_CLASS_MANUFACTURING
+ );
+ StringPtr += StrLen (StringPtr);
+
+ UnicodeSPrint (
+ StringPtr,
+ (8 + 4 + 7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
+ L"&OFFSET=%04x&WIDTH=%04x&VALUE=%04x",
+ Offset,
+ Width,
+ DEFAULT_CLASS_MANUFACTURING_VALUE
+ );
+ StringPtr += StrLen (StringPtr);
+
+ return TmpStr;
+}
+
+/**
+ Check whether need to add the altcfg string. if need to add, add the altcfg
+ string.
+
+ @param RequestResult The request result string.
+ @param ConfigRequestHdr The request head info. <ConfigHdr> format.
+
+**/
+VOID
+AppendAltCfgString (
+ IN OUT EFI_STRING *RequestResult,
+ IN EFI_STRING ConfigRequestHdr
+ )
+{
+ EFI_STRING StringPtr;
+ UINTN Length;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINTN BlockSize;
+ UINTN ValueOffset;
+ UINTN ValueWidth;
+ EFI_STATUS Status;
+
+ TmpBuffer = NULL;
+ StringPtr = *RequestResult;
+ StringPtr = StrStr (StringPtr, L"OFFSET");
+ BlockSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ ValueOffset = OFFSET_OF (DRIVER_SAMPLE_CONFIGURATION, GetDefaultValueFromAccess);
+ ValueWidth = sizeof (((DRIVER_SAMPLE_CONFIGURATION *)0)->GetDefaultValueFromAccess);
+
+ if (StringPtr == NULL) {
+ return;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ return;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ return;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ StringPtr += Length;
+
+ //
+ // Skip the character "&" before "OFFSET".
+ //
+ StringPtr ++;
+
+ //
+ // Calculate Value and convert it to hex string.
+ //
+ if (Offset + Width > BlockSize) {
+ return;
+ }
+
+ if (Offset <= ValueOffset && Offset + Width >= ValueOffset + ValueWidth) {
+ *RequestResult = CreateAltCfgString(*RequestResult, ConfigRequestHdr, ValueOffset, ValueWidth);
+ return;
+ }
+ }
+}
+
+/**
+ 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
+ExtractConfig (
+ 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;
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ UINTN Size;
+ EFI_STRING Value;
+ UINTN ValueStrLen;
+ CHAR16 BackupChar;
+ CHAR16 *StrPointer;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ *Progress = Request;
+ AllocatedRequest = FALSE;
+
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get Buffer Storage data from EFI variable.
+ // Try to get the current setting from variable.
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Request == NULL) {
+ //
+ // Request is set to NULL, 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 (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]);
+ 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);
+ ConfigRequestHdr = NULL;
+ } else {
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Request, &gDriverSampleFormSetGuid, NULL)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check whether request for EFI Varstore. EFI varstore get data
+ // through hii database, not support in this path.
+ //
+ if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiVar)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiBitVar)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (HiiIsConfigHdrMatch(Request, &gDriverSampleFormSetGuid, MyEfiUnionVar)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set Request to the unified request string.
+ //
+ ConfigRequest = Request;
+ //
+ // Check whether Request includes Request Element.
+ //
+ if (StrStr (Request, L"OFFSET") == NULL) {
+ //
+ // Check Request Element does exist in Reques String
+ //
+ StrPointer = StrStr (Request, L"PATH");
+ if (StrPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StrStr (StrPointer, L"&") == NULL) {
+ Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", Request, (UINT64)BufferSize);
+ }
+ }
+ }
+
+ //
+ // Check if requesting Name/Value storage
+ //
+ if (StrStr (ConfigRequest, L"OFFSET") == NULL) {
+ //
+ // Update Name/Value storage Names
+ //
+ Status = LoadNameValueNames (PrivateData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate memory for <ConfigResp>, e.g. Name0=0x11, Name1=0x1234, Name2="ABCD"
+ // <Request> ::=<ConfigHdr>&Name0&Name1&Name2
+ // <ConfigResp>::=<ConfigHdr>&Name0=11&Name1=1234&Name2=0041004200430044
+ //
+ BufferSize = (StrLen (ConfigRequest) +
+ 1 + sizeof (PrivateData->Configuration.NameValueVar0) * 2 +
+ 1 + sizeof (PrivateData->Configuration.NameValueVar1) * 2 +
+ 1 + sizeof (PrivateData->Configuration.NameValueVar2) * 2 + 1) * sizeof (CHAR16);
+ *Results = AllocateZeroPool (BufferSize);
+ ASSERT (*Results != NULL);
+ StrCpyS (*Results, BufferSize / sizeof (CHAR16), ConfigRequest);
+ Value = *Results;
+
+ //
+ // Append value of NameValueVar0, type is UINT8
+ //
+ if ((Value = StrStr (*Results, PrivateData->NameValueName[0])) != NULL) {
+ Value += StrLen (PrivateData->NameValueName[0]);
+ ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar0) * 2) + 1);
+ CopyMem (Value + ValueStrLen, Value, StrSize (Value));
+
+ BackupChar = Value[ValueStrLen];
+ *Value++ = L'=';
+ UnicodeValueToStringS (
+ Value,
+ BufferSize - ((UINTN)Value - (UINTN)*Results),
+ PREFIX_ZERO | RADIX_HEX,
+ PrivateData->Configuration.NameValueVar0,
+ sizeof (PrivateData->Configuration.NameValueVar0) * 2
+ );
+ Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
+ *Value = BackupChar;
+ }
+
+ //
+ // Append value of NameValueVar1, type is UINT16
+ //
+ if ((Value = StrStr (*Results, PrivateData->NameValueName[1])) != NULL) {
+ Value += StrLen (PrivateData->NameValueName[1]);
+ ValueStrLen = ((sizeof (PrivateData->Configuration.NameValueVar1) * 2) + 1);
+ CopyMem (Value + ValueStrLen, Value, StrSize (Value));
+
+ BackupChar = Value[ValueStrLen];
+ *Value++ = L'=';
+ UnicodeValueToStringS (
+ Value,
+ BufferSize - ((UINTN)Value - (UINTN)*Results),
+ PREFIX_ZERO | RADIX_HEX,
+ PrivateData->Configuration.NameValueVar1,
+ sizeof (PrivateData->Configuration.NameValueVar1) * 2
+ );
+ Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
+ *Value = BackupChar;
+ }
+
+ //
+ // Append value of NameValueVar2, type is CHAR16 *
+ //
+ if ((Value = StrStr (*Results, PrivateData->NameValueName[2])) != NULL) {
+ Value += StrLen (PrivateData->NameValueName[2]);
+ ValueStrLen = StrLen (PrivateData->Configuration.NameValueVar2) * 4 + 1;
+ CopyMem (Value + ValueStrLen, Value, StrSize (Value));
+
+ *Value++ = L'=';
+ //
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
+ //
+ StrPointer = (CHAR16 *) PrivateData->Configuration.NameValueVar2;
+ for (; *StrPointer != L'\0'; StrPointer++) {
+ UnicodeValueToStringS (
+ Value,
+ BufferSize - ((UINTN)Value - (UINTN)*Results),
+ PREFIX_ZERO | RADIX_HEX,
+ *StrPointer,
+ 4
+ );
+ Value += StrnLenS (Value, (BufferSize - ((UINTN)Value - (UINTN)*Results)) / sizeof (CHAR16));
+ }
+ }
+
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+ if (!EFI_ERROR (Status)) {
+ ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, PrivateData->DriverHandle[0]);
+ AppendAltCfgString(Results, ConfigRequestHdr);
+ }
+ }
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+
+ if (ConfigRequestHdr != NULL) {
+ FreePool (ConfigRequestHdr);
+ }
+ //
+ // 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 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
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ CHAR16 *Value;
+ CHAR16 *StrPtr;
+ CHAR16 TemStr[5];
+ UINT8 *DataBuffer;
+ UINT8 DigitUint8;
+ UINTN Index;
+ CHAR16 *StrBuffer;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+ *Progress = Configuration;
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: if only one Storage is used, then this checking could be skipped.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gDriverSampleFormSetGuid, NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether request for EFI Varstore. EFI varstore get data
+ // through hii database, not support in this path.
+ //
+ if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiVar)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiBitVar)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (HiiIsConfigHdrMatch(Configuration, &gDriverSampleFormSetGuid, MyEfiUnionVar)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if configuring Name/Value storage
+ //
+ if (StrStr (Configuration, L"OFFSET") == NULL) {
+ //
+ // Update Name/Value storage Names
+ //
+ Status = LoadNameValueNames (PrivateData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert value for NameValueVar0
+ //
+ if ((Value = StrStr (Configuration, PrivateData->NameValueName[0])) != NULL) {
+ //
+ // Skip "Name="
+ //
+ Value += StrLen (PrivateData->NameValueName[0]);
+ Value++;
+ //
+ // Get Value String
+ //
+ StrPtr = StrStr (Value, L"&");
+ if (StrPtr == NULL) {
+ StrPtr = Value + StrLen (Value);
+ }
+ //
+ // Convert Value to Buffer data
+ //
+ DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar0;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) {
+ TemStr[0] = *StrPtr;
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DataBuffer [Index/2] = DigitUint8;
+ } else {
+ DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]);
+ }
+ }
+ }
+
+ //
+ // Convert value for NameValueVar1
+ //
+ if ((Value = StrStr (Configuration, PrivateData->NameValueName[1])) != NULL) {
+ //
+ // Skip "Name="
+ //
+ Value += StrLen (PrivateData->NameValueName[1]);
+ Value++;
+ //
+ // Get Value String
+ //
+ StrPtr = StrStr (Value, L"&");
+ if (StrPtr == NULL) {
+ StrPtr = Value + StrLen (Value);
+ }
+ //
+ // Convert Value to Buffer data
+ //
+ DataBuffer = (UINT8 *) &PrivateData->Configuration.NameValueVar1;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0, StrPtr --; StrPtr >= Value; StrPtr --, Index ++) {
+ TemStr[0] = *StrPtr;
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DataBuffer [Index/2] = DigitUint8;
+ } else {
+ DataBuffer [Index/2] = (UINT8) ((UINT8) (DigitUint8 << 4) + DataBuffer [Index/2]);
+ }
+ }
+ }
+
+ //
+ // Convert value for NameValueVar2
+ //
+ if ((Value = StrStr (Configuration, PrivateData->NameValueName[2])) != NULL) {
+ //
+ // Skip "Name="
+ //
+ Value += StrLen (PrivateData->NameValueName[2]);
+ Value++;
+ //
+ // Get Value String
+ //
+ StrPtr = StrStr (Value, L"&");
+ if (StrPtr == NULL) {
+ StrPtr = Value + StrLen (Value);
+ }
+ //
+ // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
+ //
+ StrBuffer = (CHAR16 *) PrivateData->Configuration.NameValueVar2;
+ ZeroMem (TemStr, sizeof (TemStr));
+ while (Value < StrPtr) {
+ StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value, 4);
+ *(StrBuffer++) = (CHAR16) StrHexToUint64 (TemStr);
+ Value += 4;
+ }
+ *StrBuffer = L'\0';
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *) &PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+
+ return Status;
+}
+
+
+/**
+ 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
+DriverCallback (
+ 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
+ )
+{
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+ VOID *StartOpCodeHandle;
+ VOID *OptionsOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_INPUT_KEY Key;
+ DRIVER_SAMPLE_CONFIGURATION *Configuration;
+ MY_EFI_VARSTORE_DATA *EfiData;
+ EFI_FORM_ID FormId;
+ EFI_STRING Progress;
+ EFI_STRING Results;
+ UINT32 ProgressErr;
+ CHAR16 *TmpStr;
+ UINTN Index;
+ UINT64 BufferValue;
+ EFI_HII_POPUP_SELECTION UserSelection;
+
+ UserSelection = 0xFF;
+
+ if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
+ (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ FormId = 0;
+ ProgressErr = 0;
+ Status = EFI_SUCCESS;
+ BufferValue = 3;
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ {
+ if (QuestionId == 0x1234) {
+ //
+ // Sample CallBack for UEFI FORM_OPEN action:
+ // Add Save action into Form 3 when Form 1 is opened.
+ // This will be done only in FORM_OPEN CallBack of question with ID 0x1234 from Form 1.
+ //
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != 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_UPDATE2;
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x1238, // Question ID
+ STRING_TOKEN(STR_SAVE_TEXT), // Prompt text
+ STRING_TOKEN(STR_SAVE_TEXT), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle[0], // HII handle
+ &gDriverSampleFormSetGuid, // Formset GUID
+ 0x3, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ NULL // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ }
+
+ if (QuestionId == 0x1247) {
+ Status = InternalStartMonitor ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_FORM_CLOSE:
+ {
+ if (QuestionId == 0x5678) {
+ //
+ // Sample CallBack for UEFI FORM_CLOSE action:
+ // Show up a pop-up to specify Form 3 will be closed when exit Form 3.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"You are going to leave third Form!",
+ L"Press ESC or ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+ }
+
+ if (QuestionId == 0x1247) {
+ Status = InternalStopMonitor ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_RETRIEVE:
+ {
+ switch (QuestionId ) {
+ case 0x1248:
+ if (Type != EFI_IFR_TYPE_REF) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Value->ref.FormId = 0x3;
+ break;
+
+ case 0x5678:
+ case 0x1247:
+ //
+ // We will reach here once the Question is refreshed
+ //
+
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != 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;
+ if (QuestionId == 0x5678) {
+ StartLabel->Number = LABEL_UPDATE2;
+ FormId = 0x03;
+ PrivateData->Configuration.DynamicRefresh++;
+ } else if (QuestionId == 0x1247 ) {
+ StartLabel->Number = LABEL_UPDATE3;
+ FormId = 0x06;
+ PrivateData->Configuration.RefreshGuidCount++;
+ }
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x1237, // Question ID
+ STRING_TOKEN(STR_EXIT_TEXT), // Prompt text
+ STRING_TOKEN(STR_EXIT_TEXT), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle[0], // HII handle
+ &gDriverSampleFormSetGuid, // Formset GUID
+ FormId, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ NULL // Insert data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+
+ //
+ // Refresh the Question value
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+
+ if (QuestionId == 0x5678) {
+ //
+ // Update uncommitted data of Browser
+ //
+ EfiData = AllocateZeroPool (sizeof (MY_EFI_VARSTORE_DATA));
+ ASSERT (EfiData != NULL);
+ if (HiiGetBrowserData (&gDriverSampleFormSetGuid, MyEfiVar, sizeof (MY_EFI_VARSTORE_DATA), (UINT8 *) EfiData)) {
+ EfiData->Field8 = 111;
+ HiiSetBrowserData (
+ &gDriverSampleFormSetGuid,
+ MyEfiVar,
+ sizeof (MY_EFI_VARSTORE_DATA),
+ (UINT8 *) EfiData,
+ NULL
+ );
+ }
+ FreePool (EfiData);
+ }
+ break;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
+ {
+ switch (QuestionId) {
+ case 0x1240:
+ Value->u8 = DEFAULT_CLASS_STANDARD_VALUE;
+ break;
+
+ case 0x1252:
+ for (Index = 0; Index < 3; Index ++) {
+ SetArrayData (Value, EFI_IFR_TYPE_NUM_SIZE_8, Index, BufferValue--);
+ }
+ break;
+
+ case 0x6666:
+ Value->u8 = 12;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
+ {
+ switch (QuestionId) {
+ case 0x1240:
+ Value->u8 = DEFAULT_CLASS_MANUFACTURING_VALUE;
+ break;
+
+ case 0x6666:
+ Value->u8 = 13;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_CHANGING:
+ {
+ switch (QuestionId) {
+ case 0x1249:
+ {
+ if (Type != EFI_IFR_TYPE_REF) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Value->ref.FormId = 0x1234;
+ }
+ break;
+ case 0x1234:
+ //
+ // Initialize the container for dynamic opcodes
+ //
+ 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_UPDATE1;
+
+ //
+ // 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;
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x1237, // Question ID
+ STRING_TOKEN(STR_EXIT_TEXT), // Prompt text
+ STRING_TOKEN(STR_EXIT_TEXT), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+
+ //
+ // Create Option OpCode
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_BOOT_OPTION1),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_BOOT_OPTION2),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 2
+ );
+
+ //
+ // Prepare initial value for the dynamic created oneof Question
+ //
+ PrivateData->Configuration.DynamicOneof = 2;
+ Status = gRT->SetVariable(
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+
+ //
+ // Set initial vlaue of dynamic created oneof Question in Form Browser
+ //
+ Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION));
+ ASSERT (Configuration != NULL);
+ if (HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration)) {
+ Configuration->DynamicOneof = 2;
+
+ //
+ // Update uncommitted data of Browser
+ //
+ HiiSetBrowserData (
+ &gDriverSampleFormSetGuid,
+ VariableName,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ (UINT8 *) Configuration,
+ NULL
+ );
+ }
+ FreePool (Configuration);
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8001, // Question ID (or call it "key")
+ CONFIGURATION_VARSTORE_ID, // VarStore ID
+ (UINT16) DYNAMIC_ONE_OF_VAR_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_ONE_OF_PROMPT), // Question prompt text
+ STRING_TOKEN (STR_ONE_OF_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiCreateOrderedListOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 0x8002, // Question ID
+ CONFIGURATION_VARSTORE_ID, // VarStore ID
+ (UINT16) DYNAMIC_ORDERED_LIST_VAR_OFFSET, // Offset in Buffer Storage
+ STRING_TOKEN (STR_BOOT_OPTIONS), // Question prompt text
+ STRING_TOKEN (STR_BOOT_OPTIONS), // Question help text
+ EFI_IFR_FLAG_RESET_REQUIRED, // Question flag
+ 0, // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question value
+ 5, // Maximum container
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiCreateTextOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN(STR_TEXT_SAMPLE_HELP),
+ STRING_TOKEN(STR_TEXT_SAMPLE_HELP),
+ STRING_TOKEN(STR_TEXT_SAMPLE_STRING)
+ );
+
+ HiiCreateDateOpCode (
+ StartOpCodeHandle,
+ 0x8004,
+ 0x0,
+ 0x0,
+ STRING_TOKEN(STR_DATE_SAMPLE_HELP),
+ STRING_TOKEN(STR_DATE_SAMPLE_HELP),
+ 0,
+ QF_DATE_STORAGE_TIME,
+ NULL
+ );
+
+ HiiCreateTimeOpCode (
+ StartOpCodeHandle,
+ 0x8005,
+ 0x0,
+ 0x0,
+ STRING_TOKEN(STR_TIME_SAMPLE_HELP),
+ STRING_TOKEN(STR_TIME_SAMPLE_HELP),
+ 0,
+ QF_TIME_STORAGE_TIME,
+ NULL
+ );
+
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ 1, // Target Form ID
+ STRING_TOKEN (STR_GOTO_FORM1), // Prompt text
+ STRING_TOKEN (STR_GOTO_HELP), // Help text
+ 0, // Question flag
+ 0x8003 // Question ID
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle[0], // HII handle
+ &gDriverSampleFormSetGuid, // Formset GUID
+ 0x1234, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_CHANGED:
+ switch (QuestionId) {
+ case 0x1237:
+ //
+ // User press "Exit now", request Browser to exit
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case 0x1238:
+ //
+ // User press "Save now", request Browser to save the uncommitted data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ case 0x1241:
+ case 0x1246:
+ //
+ // User press "Submit current form and Exit now", request Browser to submit current form and exit
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ case 0x1242:
+ //
+ // User press "Discard current form now", request Browser to discard the uncommitted data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD;
+ break;
+
+ case 0x1243:
+ //
+ // User press "Submit current form now", request Browser to save the uncommitted data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ break;
+
+ case 0x1244:
+ case 0x1245:
+ //
+ // User press "Discard current form and Exit now", request Browser to discard the uncommitted data and exit.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ case 0x1231:
+ //
+ // 1. Check to see whether system support keyword.
+ //
+ Status = PrivateData->HiiKeywordHandler->GetData (PrivateData->HiiKeywordHandler,
+ L"NAMESPACE=x-UEFI-ns",
+ L"KEYWORD=iSCSIBootEnable",
+ &Progress,
+ &ProgressErr,
+ &Results
+ );
+ if (EFI_ERROR (Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"This system not support this keyword!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ //
+ // 2. If system support this keyword, just try to change value.
+ //
+
+ //
+ // Change value from '0' to '1' or from '1' to '0'
+ //
+ TmpStr = StrStr (Results, L"&VALUE=");
+ ASSERT (TmpStr != NULL);
+ TmpStr += StrLen (L"&VALUE=");
+ TmpStr++;
+ if (*TmpStr == L'0') {
+ *TmpStr = L'1';
+ } else {
+ *TmpStr = L'0';
+ }
+
+ //
+ // 3. Call the keyword handler protocol to change the value.
+ //
+ Status = PrivateData->HiiKeywordHandler->SetData (PrivateData->HiiKeywordHandler,
+ Results,
+ &Progress,
+ &ProgressErr
+ );
+ if (EFI_ERROR (Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Set keyword to the system failed!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ Status = EFI_SUCCESS;
+ break;
+ }
+ break;
+
+ case 0x1330:
+ Status = mPrivateData->HiiPopup->CreatePopup (
+ mPrivateData->HiiPopup,
+ EfiHiiPopupStyleInfo,
+ EfiHiiPopupTypeYesNo,
+ mPrivateData->HiiHandle[0],
+ STRING_TOKEN (STR_POPUP_STRING),
+ &UserSelection
+ );
+ if (!EFI_ERROR (Status)) {
+ if (UserSelection == EfiHiiPopupSelectionYes) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_SUBMITTED:
+ {
+ if (QuestionId == 0x1250) {
+ //
+ // Sample CallBack for EFI_BROWSER_ACTION_SUBMITTED action:
+ // Show up a pop-up to show SUBMITTED callback has been triggered.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"EfiVarstore value has been submitted!",
+ L"Press ESC or ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+ }
+ }
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Main entry for this driver.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverSampleInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle[2];
+ EFI_SCREEN_DESCRIPTOR Screen;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+ EFI_HII_POPUP_PROTOCOL *PopupHandler;
+ CHAR16 *NewString;
+ UINTN BufferSize;
+ DRIVER_SAMPLE_CONFIGURATION *Configuration;
+ BOOLEAN ActionFlag;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING NameRequestHdr;
+ MY_EFI_VARSTORE_DATA *VarStoreConfig;
+ MY_EFI_BITS_VARSTORE_DATA *BitsVarStoreConfig;
+ MY_EFI_UNION_DATA *UnionConfig;
+ EFI_INPUT_KEY HotKey;
+ EDKII_FORM_BROWSER_EXTENSION_PROTOCOL *FormBrowserEx;
+
+ //
+ // Initialize the local variables.
+ //
+ ConfigRequestHdr = NULL;
+ NewString = NULL;
+
+ //
+ // Initialize screen dimensions for SendForm().
+ // Remove 3 characters from top and bottom
+ //
+ ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
+
+ Screen.TopRow = 3;
+ Screen.BottomRow = Screen.BottomRow - 3;
+
+ //
+ // Initialize driver private data
+ //
+ mPrivateData = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA));
+ if (mPrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE;
+
+ mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ mPrivateData->ConfigAccess.Callback = DriverCallback;
+
+ //
+ // Locate Hii Database protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiDatabase = HiiDatabase;
+
+ //
+ // Locate HiiString protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiString = HiiString;
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->FormBrowser2 = FormBrowser2;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ //
+ // Locate keyword handler protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiConfigKeywordHandlerProtocolGuid, NULL, (VOID **) &HiiKeywordHandler);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiKeywordHandler = HiiKeywordHandler;
+
+ //
+ // Locate HiiPopup protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiPopupProtocolGuid, NULL, (VOID **) &PopupHandler);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mPrivateData->HiiPopup = PopupHandler;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle[0],
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath0,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle[0] = DriverHandle[0];
+
+ //
+ // Publish our HII data
+ //
+ HiiHandle[0] = HiiAddPackages (
+ &gDriverSampleFormSetGuid,
+ DriverHandle[0],
+ DriverSampleStrings,
+ VfrBin,
+ NULL
+ );
+ if (HiiHandle[0] == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle[0] = HiiHandle[0];
+
+ //
+ // Publish another Fromset
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle[1],
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath1,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPrivateData->DriverHandle[1] = DriverHandle[1];
+
+ HiiHandle[1] = HiiAddPackages (
+ &gDriverSampleInventoryGuid,
+ DriverHandle[1],
+ DriverSampleStrings,
+ InventoryBin,
+ NULL
+ );
+ if (HiiHandle[1] == NULL) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPrivateData->HiiHandle[1] = HiiHandle[1];
+
+ //
+ // Update the device path string.
+ //
+ NewString = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*)&mHiiVendorDevicePath0, FALSE, FALSE);
+ if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_DEVICE_PATH), NewString, NULL) == 0) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (NewString != NULL) {
+ FreePool (NewString);
+ }
+
+ //
+ // Very simple example of how one would update a string that is already
+ // in the HII database
+ //
+ NewString = L"700 Mhz";
+
+ if (HiiSetString (HiiHandle[0], STRING_TOKEN (STR_CPU_STRING2), NewString, NULL) == 0) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HiiSetString (HiiHandle[0], 0, NewString, NULL);
+
+ //
+ // Initialize Name/Value name String ID
+ //
+ mPrivateData->NameStringId[0] = STR_NAME_VALUE_VAR_NAME0;
+ mPrivateData->NameStringId[1] = STR_NAME_VALUE_VAR_NAME1;
+ mPrivateData->NameStringId[2] = STR_NAME_VALUE_VAR_NAME2;
+
+ //
+ // Initialize configuration data
+ //
+ Configuration = &mPrivateData->Configuration;
+ ZeroMem (Configuration, sizeof (DRIVER_SAMPLE_CONFIGURATION));
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, VariableName, DriverHandle[0]);
+ ASSERT (ConfigRequestHdr != NULL);
+
+ NameRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, NULL, DriverHandle[0]);
+ ASSERT (NameRequestHdr != NULL);
+
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (VariableName, &gDriverSampleFormSetGuid, NULL, &BufferSize, Configuration);
+ if (EFI_ERROR (Status)) {
+ //
+ // Store zero data Buffer Storage to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DriverSampleUnload (ImageHandle);
+ return Status;
+ }
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ ActionFlag = HiiSetToDefaults (NameRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // EFI variable does exist and Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (NameRequestHdr);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ //
+ // Initialize efi varstore configuration data
+ //
+ VarStoreConfig = &mPrivateData->VarStoreConfig;
+ ZeroMem (VarStoreConfig, sizeof (MY_EFI_VARSTORE_DATA));
+
+ ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiVar, DriverHandle[0]);
+ ASSERT (ConfigRequestHdr != NULL);
+
+ BufferSize = sizeof (MY_EFI_VARSTORE_DATA);
+ Status = gRT->GetVariable (MyEfiVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, VarStoreConfig);
+ if (EFI_ERROR (Status)) {
+ //
+ // Store zero data to EFI variable Storage.
+ //
+ Status = gRT->SetVariable(
+ MyEfiVar,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (MY_EFI_VARSTORE_DATA),
+ VarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DriverSampleUnload (ImageHandle);
+ return Status;
+ }
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // EFI variable does exist and Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ //
+ // Initialize Bits efi varstore configuration data
+ //
+ BitsVarStoreConfig = &mPrivateData->BitsVarStoreConfig;
+ ZeroMem (BitsVarStoreConfig, sizeof (MY_EFI_BITS_VARSTORE_DATA));
+
+ ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiBitVar, DriverHandle[0]);
+ ASSERT (ConfigRequestHdr != NULL);
+
+ BufferSize = sizeof (MY_EFI_BITS_VARSTORE_DATA);
+ Status = gRT->GetVariable (MyEfiBitVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, BitsVarStoreConfig);
+ if (EFI_ERROR (Status)) {
+ //
+ // Store zero data to EFI variable Storage.
+ //
+ Status = gRT->SetVariable(
+ MyEfiBitVar,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (MY_EFI_BITS_VARSTORE_DATA),
+ BitsVarStoreConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DriverSampleUnload (ImageHandle);
+ return Status;
+ }
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // EFI variable does exist and Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ //
+ // Initialize Union efi varstore configuration data
+ //
+ UnionConfig = &mPrivateData->UnionConfig;
+ ZeroMem (UnionConfig, sizeof (MY_EFI_UNION_DATA));
+
+ ConfigRequestHdr = HiiConstructConfigHdr (&gDriverSampleFormSetGuid, MyEfiUnionVar, DriverHandle[0]);
+ ASSERT (ConfigRequestHdr != NULL);
+
+ BufferSize = sizeof (MY_EFI_UNION_DATA);
+ Status = gRT->GetVariable (MyEfiUnionVar, &gDriverSampleFormSetGuid, NULL, &BufferSize, UnionConfig);
+ if (EFI_ERROR (Status)) {
+ //
+ // Store zero data to EFI variable Storage.
+ //
+ Status = gRT->SetVariable(
+ MyEfiUnionVar,
+ &gDriverSampleFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (MY_EFI_UNION_DATA),
+ UnionConfig
+ );
+ if (EFI_ERROR (Status)) {
+ DriverSampleUnload (ImageHandle);
+ return Status;
+ }
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // EFI variable does exist and Validate Current Setting
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ DriverSampleUnload (ImageHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gEfiIfrRefreshIdOpGuid,
+ &mEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Example of how to use BrowserEx protocol to register HotKey.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiFormBrowserExProtocolGuid, NULL, (VOID **) &FormBrowserEx);
+ if (!EFI_ERROR (Status)) {
+ //
+ // First unregister the default hot key F9 and F10.
+ //
+ HotKey.UnicodeChar = CHAR_NULL;
+ HotKey.ScanCode = SCAN_F9;
+ FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL);
+ HotKey.ScanCode = SCAN_F10;
+ FormBrowserEx->RegisterHotKey (&HotKey, 0, 0, NULL);
+
+ //
+ // Register the default HotKey F9 and F10 again.
+ //
+ HotKey.ScanCode = SCAN_F10;
+ NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_TEN_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);
+ HotKey.ScanCode = SCAN_F9;
+ NewString = HiiGetString (mPrivateData->HiiHandle[0], STRING_TOKEN (FUNCTION_NINE_STRING), NULL);
+ ASSERT (NewString != NULL);
+ FormBrowserEx->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);
+ }
+
+ //
+ // In default, this driver is built into Flash device image,
+ // the following code doesn't run.
+ //
+
+ //
+ // Example of how to display only the item we sent to HII
+ // When this driver is not built into Flash device image,
+ // it need to call SendForm to show front page by itself.
+ //
+ if (DISPLAY_ONLY_MY_ITEM <= 1) {
+ //
+ // Have the browser pull out our copy of the data, and only display our data
+ //
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ &(HiiHandle[DISPLAY_ONLY_MY_ITEM]),
+ 1,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+
+ HiiRemovePackages (HiiHandle[0]);
+
+ HiiRemovePackages (HiiHandle[1]);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+DriverSampleUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ UINTN Index;
+
+ ASSERT (mPrivateData != NULL);
+
+ if (DriverHandle[0] != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle[0],
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath0,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ DriverHandle[0] = NULL;
+ }
+
+ if (DriverHandle[1] != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle[1],
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath1,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mPrivateData->ConfigAccess,
+ NULL
+ );
+ DriverHandle[1] = NULL;
+ }
+
+ if (mPrivateData->HiiHandle[0] != NULL) {
+ HiiRemovePackages (mPrivateData->HiiHandle[0]);
+ }
+
+ if (mPrivateData->HiiHandle[1] != NULL) {
+ HiiRemovePackages (mPrivateData->HiiHandle[1]);
+ }
+
+ for (Index = 0; Index < NAME_VALUE_NAME_NUMBER; Index++) {
+ if (mPrivateData->NameValueName[Index] != NULL) {
+ FreePool (mPrivateData->NameValueName[Index]);
+ }
+ }
+ FreePool (mPrivateData);
+ mPrivateData = NULL;
+
+ gBS->CloseEvent (mEvent);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h
new file mode 100644
index 000000000..f4d2437d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h
@@ -0,0 +1,122 @@
+/** @file
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ DriverSample.h
+
+Abstract:
+
+
+Revision History
+
+
+**/
+
+#ifndef _DRIVER_SAMPLE_H_
+#define _DRIVER_SAMPLE_H_
+
+#include <Uefi.h>
+
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/FormBrowserEx.h>
+#include <Protocol/HiiConfigKeyword.h>
+#include <Protocol/HiiPopup.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+
+#include "NVDataStruc.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 VfrBin[];
+extern UINT8 InventoryBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 DriverSampleStrings[];
+
+#define DYNAMIC_ONE_OF_VAR_OFFSET OFFSET_OF (DRIVER_SAMPLE_CONFIGURATION, DynamicOneof)
+#define DYNAMIC_ORDERED_LIST_VAR_OFFSET OFFSET_OF (DRIVER_SAMPLE_CONFIGURATION, DynamicOrderedList)
+
+#define DEFAULT_CLASS_MANUFACTURING_VALUE 0xFF
+#define DEFAULT_CLASS_STANDARD_VALUE 0x0
+
+//
+// Number of name in Name/Value storage
+//
+#define NAME_VALUE_NAME_NUMBER 3
+
+#define DRIVER_SAMPLE_PRIVATE_SIGNATURE SIGNATURE_32 ('D', 'S', 'p', 's')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE DriverHandle[2];
+ EFI_HII_HANDLE HiiHandle[2];
+ DRIVER_SAMPLE_CONFIGURATION Configuration;
+ MY_EFI_VARSTORE_DATA VarStoreConfig;
+ MY_EFI_BITS_VARSTORE_DATA BitsVarStoreConfig;
+ MY_EFI_UNION_DATA UnionConfig;
+
+ //
+ // Name/Value storage Name list
+ //
+ EFI_STRING_ID NameStringId[NAME_VALUE_NAME_NUMBER];
+ EFI_STRING NameValueName[NAME_VALUE_NAME_NUMBER];
+
+ //
+ // Consumed protocol
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *HiiKeywordHandler;
+ EFI_HII_POPUP_PROTOCOL *HiiPopup;
+
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Produced protocol
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} DRIVER_SAMPLE_PRIVATE_DATA;
+
+#define DRIVER_SAMPLE_PRIVATE_FROM_THIS(a) CR (a, DRIVER_SAMPLE_PRIVATE_DATA, ConfigAccess, DRIVER_SAMPLE_PRIVATE_SIGNATURE)
+
+#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()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.uni b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.uni
new file mode 100644
index 000000000..e7f16c418
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.uni
@@ -0,0 +1,17 @@
+// /** @file
+// This is a sample HII driver.
+//
+// This driver shows how HII protocol, VFR and UNI files are used to create a HII
+// driver which can be dipslayed and configured by a UEFI HII Form Browser.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A sample HII driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver shows how HII protocol, VFR and UNI files are used to create a HII driver that can be displayed and configured by a UEFI HII Form Browser."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
new file mode 100644
index 000000000..a277f641d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
@@ -0,0 +1,96 @@
+## @file
+# This is a sample HII driver.
+#
+# This driver shows how HII protocol, VFR and UNI files are used to create a HII
+# driver which can be dipslayed and configured by a UEFI HII Form Browser.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DriverSample
+ MODULE_UNI_FILE = DriverSample.uni
+ FILE_GUID = FE3542FE-C1D3-4EF8-657C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DriverSampleInit
+ UNLOAD_IMAGE = DriverSampleUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DriverSample.c
+ InventoryStrings.uni
+ NVDataStruc.h
+ VfrStrings.uni
+ DriverSample.h
+ Inventory.vfr
+ Vfr.vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ PrintLib
+ UefiLib
+ DevicePathLib
+
+[Guids]
+ gEfiIfrTianoGuid ## PRODUCES ## UNDEFINED
+ gDriverSampleInventoryGuid ## CONSUMES ## HII
+ ## SOMETIMES_PRODUCES ## Event
+ ## CONSUMES ## Event
+ gEfiIfrRefreshIdOpGuid
+ ## CONSUMES ## HII
+ ## PRODUCES ## Variable:L"MyIfrNVData"
+ ## SOMETIMES_CONSUMES ## Variable:L"MyIfrNVData"
+ ## PRODUCES ## Variable:L"MyEfiVar"
+ ## SOMETIMES_CONSUMES ## Variable:L"MyEfiVar"
+ ## PRODUCES ## GUID # HiiConstructConfigHdr MyEfiVar
+ ## PRODUCES ## GUID # HiiConstructConfigHdr MyIfrNVData
+ ## SOMETIMES_CONSUMES ## GUID # HiiIsConfigHdrMatch MyEfiVar
+ ## SOMETIMES_CONSUMES ## GUID # HiiIsConfigHdrMatch MyIfrNVData
+ ## SOMETIMES_PRODUCES ## GUID # HiiGetBrowserData MyIfrNVData
+ ## SOMETIMES_CONSUMES ## GUID # HiiSetBrowserData MyIfrNVData
+ ## SOMETIMES_PRODUCES ## GUID # HiiGetBrowserData MyEfiVar
+ ## SOMETIMES_CONSUMES ## GUID # HiiSetBrowserData MyEfiVar
+ gDriverSampleFormSetGuid
+
+[Protocols]
+ ## PRODUCES # DriverSampleFormSet
+ ## PRODUCES # DriverSampleInventory
+ gEfiDevicePathProtocolGuid
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiFormBrowserExProtocolGuid ## CONSUMES
+ gEfiConfigKeywordHandlerProtocolGuid ## CONSUMES
+ gEfiHiiPopupProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiSimpleTextOutProtocolGuid AND gEfiHiiDatabaseProtocolGuid AND gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DriverSampleExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleExtra.uni b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleExtra.uni
new file mode 100644
index 000000000..15a8598e2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DriverSample Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"HII Sample DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Inventory.vfr b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Inventory.vfr
new file mode 100644
index 000000000..dd3578a62
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Inventory.vfr
@@ -0,0 +1,111 @@
+///** @file
+//
+// Sample Inventory Data
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#include "NVDataStruc.h"
+
+formset
+ guid = DRIVER_SAMPLE_INVENTORY_GUID,
+ title = STRING_TOKEN(STR_INV_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_INV_FORM_SET_HELP),
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_INV_FORM1_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ text
+ help = STRING_TOKEN(STR_INV_VERSION_HELP),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT2),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT3),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT4),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT5),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT6),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT7),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT8),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT9),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT10),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT11),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_CHECK_KEYWORD_SUPPORT),
+ text = STRING_TOKEN(STR_CHECK_KEYWORD_SUPPORT),
+ flags = INTERACTIVE,
+ key = 0x1231;
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_INV_VERSION_TEXT12);
+
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/InventoryStrings.uni b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/InventoryStrings.uni
new file mode 100644
index 000000000..836229699
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/InventoryStrings.uni
@@ -0,0 +1,60 @@
+// *++
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// InventoryStrings.uni
+//
+// Abstract:
+//
+// String definitions for Inventory file.
+//
+// Revision History:
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+
+#string STR_INV_FORM_SET_TITLE #language en-US "ABC Information Sample"
+ #language fr-FR "Mi motor Español de arreglo"
+#string STR_INV_FORM_SET_HELP #language en-US "The ABC Network Controller version information, which includes Firmware versions as well as supported characteristics"
+ #language fr-FR "The ABC Network Controller version information, which includes Firmware versions as well as supported characteristics"
+#string STR_INV_FORM1_TITLE #language en-US "ABC Network Controller Version Data"
+ #language fr-FR "Mi Primero Arreglo Página"
+#string STR_INV_VERSION_TEXT #language en-US "Firmware Revision Date: 02/03/2002"
+ #language fr-FR "Firmware Revision Date: 02/03/2002"
+#string STR_INV_VERSION_HELP #language en-US "The date of the revision of the Firmware being used."
+ #language fr-FR "The date of the revision of the Firmware being used."
+#string STR_INV_VERSION_TEXT2 #language en-US "Major Version: 6.32.5"
+ #language fr-FR "Major Version: 6.32.5"
+#string STR_INV_VERSION_TEXT3 #language en-US "Patch Version: 1.02.53"
+ #language fr-FR "Patch Version: 1.02.53"
+#string STR_INV_VERSION_TEXT4 #language en-US "Characteristics: 10/100 Mb/s"
+ #language fr-FR "Characteristics: 10/100 Mb/s"
+#string STR_INV_VERSION_TEXT5 #language en-US " 3.3 V power usage"
+ #language fr-FR " 3.3 V power usage"
+#string STR_INV_VERSION_TEXT6 #language en-US " 3K Transmit FIFO"
+ #language fr-FR " 3K Transmit FIFO"
+#string STR_INV_VERSION_TEXT7 #language en-US " 3K Receive FIFO"
+ #language fr-FR " 3K Receive FIFO"
+#string STR_INV_VERSION_TEXT8 #language en-US " TCP/UDP checksum offload"
+ #language fr-FR " TCP/UDP checksum offload"
+#string STR_INV_VERSION_TEXT9 #language en-US " 128K Flash"
+ #language fr-FR " 128K Flash"
+#string STR_INV_VERSION_TEXT10 #language en-US " 32-bit PCI"
+ #language fr-FR " 32-bit PCI"
+#string STR_INV_VERSION_TEXT11 #language en-US " Intel® 82540EM"
+ #language fr-FR " Intel® 82540EM"
+#string STR_INV_VERSION_TEXT12 #language en-US "Press ESC to exit."
+ #language fr-FR "Press ESC to exit."
+#string STR_INV_EMPTY_STRING #language en-US ""
+ #language fr-FR ""
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h
new file mode 100644
index 000000000..861761768
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h
@@ -0,0 +1,129 @@
+/** @file
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ NVDataStruc.h
+
+Abstract:
+
+ NVData structure used by the sample driver
+
+Revision History:
+
+
+**/
+
+#ifndef _NVDATASTRUC_H_
+#define _NVDATASTRUC_H_
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/HiiFormMapMethodGuid.h>
+#include <Guid/DriverSampleHii.h>
+#include <Guid/ZeroGuid.h>
+
+#define CONFIGURATION_VARSTORE_ID 0x1234
+#define BITS_VARSTORE_ID 0x2345
+
+#pragma pack(1)
+
+//
+// !!! For a structure with a series of bit fields and used as a storage in vfr file, and if the bit fields do not add up to the size of the defined type.
+// In the C code use sizeof() to get the size the strucure, the results may vary form the compiler(VS,GCC...).
+// But the size of the storage calculated by VfrCompiler is fixed (calculate with alignment).
+// To avoid above case, we need to make the total bit width in the structure aligned with the size of the defined type for these bit fields. We can:
+// 1. Add bit field (with/without name) with remianing with for padding.
+// 2. Add unnamed bit field with 0 for padding, the amount of padding is determined by the alignment characteristics of the members of the structure.
+//
+typedef struct {
+ UINT16 NestByteField;
+ UINT8 : 1; // unamed field can be used for padding
+ UINT8 NestBitCheckbox : 1;
+ UINT8 NestBitOneof : 2;
+ UINT8 : 0; // Special width 0 can be used to force alignment at the next word boundary
+ UINT8 NestBitNumeric : 4;
+} MY_BITS_DATA;
+
+typedef union {
+ UINT8 UnionNumeric;
+ UINT8 UnionNumericAlias;
+} MY_EFI_UNION_DATA;
+
+typedef struct {
+ UINT16 MyStringData[40];
+ UINT16 SomethingHiddenForHtml;
+ UINT8 HowOldAreYouInYearsManual;
+ UINT16 HowTallAreYouManual;
+ UINT8 HowOldAreYouInYears;
+ UINT16 HowTallAreYou;
+ UINT8 MyFavoriteNumber;
+ UINT8 TestLateCheck;
+ UINT8 TestLateCheck2;
+ UINT8 QuestionAboutTreeHugging;
+ UINT8 ChooseToActivateNuclearWeaponry;
+ UINT8 SuppressGrayOutSomething;
+ UINT8 OrderedList[8];
+ UINT16 BootOrder[8];
+ UINT8 BootOrderLarge;
+ UINT8 DynamicRefresh;
+ UINT8 DynamicOneof;
+ UINT8 DynamicOrderedList[5];
+ UINT8 Reserved;
+ EFI_HII_REF RefData;
+ UINT8 NameValueVar0;
+ UINT16 NameValueVar1;
+ UINT16 NameValueVar2[20];
+ UINT8 SerialPortNo;
+ UINT8 SerialPortStatus;
+ UINT16 SerialPortIo;
+ UINT8 SerialPortIrq;
+ UINT8 GetDefaultValueFromCallBack;
+ UINT8 GetDefaultValueFromAccess;
+ EFI_HII_TIME Time;
+ UINT8 RefreshGuidCount;
+ UINT8 Match2;
+ UINT8 GetDefaultValueFromCallBackForOrderedList[3];
+ UINT8 BitCheckbox : 1;
+ UINT8 ReservedBits: 7; // Reserved bit fields for padding.
+ UINT16 BitOneof : 6;
+ UINT16 : 0; // Width 0 used to force alignment.
+ UINT16 BitNumeric : 12;
+ MY_BITS_DATA MyBitData;
+ MY_EFI_UNION_DATA MyUnionData;
+} DRIVER_SAMPLE_CONFIGURATION;
+
+//
+// 2nd NV data structure definition
+//
+typedef struct {
+ UINT8 Field8;
+ UINT16 Field16;
+ UINT8 OrderedList[3];
+ UINT16 SubmittedCallback;
+} MY_EFI_VARSTORE_DATA;
+
+//
+// 3rd NV data structure definition
+//
+typedef struct {
+ MY_BITS_DATA BitsData;
+ UINT32 EfiBitGrayoutTest : 5;
+ UINT32 EfiBitNumeric : 4;
+ UINT32 EfiBitOneof : 10;
+ UINT32 EfiBitCheckbox : 1;
+ UINT32 : 0; // Width 0 used to force alignment.
+} MY_EFI_BITS_VARSTORE_DATA;
+
+//
+// Labels definition
+//
+#define LABEL_UPDATE1 0x1234
+#define LABEL_UPDATE2 0x2234
+#define LABEL_UPDATE3 0x3234
+#define LABEL_END 0x2223
+
+#pragma pack()
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr
new file mode 100644
index 000000000..65a65d4d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr
@@ -0,0 +1,932 @@
+///** @file
+//
+// Sample Setup formset.
+//
+// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+
+#include <Uefi/UefiMultiPhase.h>
+#include "NVDataStruc.h"
+
+//
+// Formset class used by Device Manager
+//
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+//
+// Formset subclass
+//
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+#define EFI_USER_INFO_ACCESS_SETUP_ADMIN_GUID \
+ { 0x85b75607, 0xf7ce, 0x471e, { 0xb7, 0xe4, 0x2a, 0xea, 0x5f, 0x72, 0x32, 0xee } }
+
+#define PERL_GUID \
+ { 0x63E60A51, 0x497D, 0xD427, {0xC4, 0xA5, 0xB8, 0xAB, 0xDC, 0x3A, 0xAE, 0xB6 }}
+
+//
+// Labels definition
+//
+#define LABEL_1_VALUE 0x01
+#define LABEL_2_VALUE 0x1000
+#define LABEL_UPDATE_BBS 0x2222
+
+formset
+ guid = DRIVER_SAMPLE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ //
+ // Notes: VfrCompiler will insert a Standard Default Storage declaration
+ // after the formset declaration. >00000040: 5C 06 00 00 00 00.
+ // So we don't need to declare the Standard Default.
+ // Please check the vfr.lst file for details.
+ // To enable list file for VFR, add "-l" to VfrCompile <Command> in [Build.Visual-Form-Representation-File] as follows:
+ // VfrCompile -l --no-pre-processing --output-directory ${d_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
+ //
+
+ //
+ // Define a Buffer Storage (EFI_IFR_VARSTORE)
+ //
+ varstore DRIVER_SAMPLE_CONFIGURATION, // This is the data structure type
+ varid = CONFIGURATION_VARSTORE_ID, // Optional VarStore ID
+ name = MyIfrNVData, // Define referenced name in vfr
+ guid = DRIVER_SAMPLE_FORMSET_GUID; // GUID of this buffer storage
+
+ //
+ // Define a EFI variable Storage (EFI_IFR_VARSTORE_EFI)
+ //
+ efivarstore MY_EFI_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attribures
+ name = MyEfiVar,
+ guid = DRIVER_SAMPLE_FORMSET_GUID;
+
+ //
+ // Define a Buffer Storage (EFI_IFR_VARSTORE)
+ //
+ efivarstore MY_EFI_BITS_VARSTORE_DATA, // This is the data structure type
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attribures
+ name = MyEfiBitVar, // Define referenced name in vfr
+ guid = DRIVER_SAMPLE_FORMSET_GUID; // GUID of this buffer storage
+
+ efivarstore MY_EFI_UNION_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attribures
+ name = MyEfiUnionVar,
+ guid = DRIVER_SAMPLE_FORMSET_GUID;
+
+ //
+ // Define a Name/Value Storage (EFI_IFR_VARSTORE_NAME_VALUE)
+ //
+ namevaluevarstore MyNameValueVar, // Define storage reference name in vfr
+ name = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME0), // Define Name list of this storage, refer it by MyNameValueVar[0]
+ name = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME1), // Define Name list of this storage, refer it by MyNameValueVar[1]
+ name = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME2), // Define Name list of this storage, refer it by MyNameValueVar[2]
+ guid = DRIVER_SAMPLE_FORMSET_GUID; // GUID of this Name/Value storage
+
+ defaultstore MyStandardDefault,
+ prompt = STRING_TOKEN(STR_STANDARD_DEFAULT_PROMPT),
+ attribute = 0x0000; // Default ID: 0000 standard default
+
+ defaultstore MyManufactureDefault,
+ prompt = STRING_TOKEN(STR_MANUFACTURE_DEFAULT_PROMPT),
+ attribute = 0x0001; // Default ID: 0001 manufacture default
+
+ //
+ // Define a Form (EFI_IFR_FORM)
+ //
+ form formid = 1, // Form ID
+ title = STRING_TOKEN(STR_FORM1_TITLE); // Form title
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT);
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+
+ //
+ // Define a display only text (EFI_IFR_TEXT)
+ //
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP), // Help string
+ text = STRING_TOKEN(STR_CPU_STRING), // Prompt string
+ text = STRING_TOKEN(STR_CPU_STRING2); // TextTwo
+
+ //
+ // Define action button (EFI_IFR_ACTION)
+ //
+ text
+ help = STRING_TOKEN(STR_EXIT_TEXT),
+ text = STRING_TOKEN(STR_EXIT_TEXT),
+ flags = INTERACTIVE, // VfrCompiler will generate opcode EFI_IFR_ACTION for Text marked as INTERACTIVE
+ key = 0x1237;
+
+ text
+ help = STRING_TOKEN(STR_SAVE_TEXT),
+ text = STRING_TOKEN(STR_SAVE_TEXT),
+ flags = INTERACTIVE,
+ key = 0x1238;
+
+ text
+ help = STRING_TOKEN(STR_SAVE_CURRENT),
+ text = STRING_TOKEN(STR_SAVE_CURRENT),
+ flags = INTERACTIVE,
+ key = 0x1243;
+
+ text
+ help = STRING_TOKEN(STR_DISCARD_CURRENT_AND_EXIT),
+ text = STRING_TOKEN(STR_DISCARD_CURRENT_AND_EXIT),
+ flags = INTERACTIVE,
+ key = 0x1244;
+ //
+ // Define oneof (EFI_IFR_ONE_OF)
+ //
+ oneof name = MyOneOf, // Define reference name for Question
+ varid = MyIfrNVData.SuppressGrayOutSomething, // Use "DataStructure.Member" to reference Buffer Storage
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ //
+ // Define an option (EFI_IFR_ONE_OF_OPTION)
+ //
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT4), value = 0x0, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT5), value = 0x1, flags = 0;
+ //
+ // DEFAULT indicate this option will be marked with EFI_IFR_OPTION_DEFAULT
+ //
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT6), value = 0x2, flags = DEFAULT;
+ endoneof;
+
+ oneof varid = MyIfrNVData.BootOrderLarge,
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ default value = cond (pushthis == 0 ? 0 : cond ((questionref(MyOneOf) >> 0x4 & 0xF00) == 0x0 + 0x2 ? 0 : 1)),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0x0, flags = 0;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 0x1, flags = 0;
+ endoneof;
+
+ grayoutif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
+ suppressif questionref(MyOneOf) == 0x0;
+
+ checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry,
+ prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_CHECK_BOX_HELP),
+ //
+ // CHECKBOX_DEFAULT indicate this checkbox is marked with EFI_IFR_CHECKBOX_DEFAULT
+ // CHECKBOX_DEFAULT_MFG indicate EFI_IFR_CHECKBOX_DEFAULT_MFG.
+ //
+ flags = CHECKBOX_DEFAULT | CHECKBOX_DEFAULT_MFG,
+ default = TRUE,
+ endcheckbox;
+ endif;
+ endif;
+
+ //
+ // Ordered list:
+ // sizeof(MyIfrNVData) storage must be UINT8 array, and
+ // size written for the variable must be size of the entire
+ // variable.
+ //
+ //
+ suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x0;
+
+ //
+ // label is defined as an anchor where you want to insert some dynamic
+ // opcodes created on-the-fly
+ //
+ label LABEL_UPDATE_BBS;
+
+ orderedlist
+ varid = MyIfrNVData.BootOrder,
+ prompt = STRING_TOKEN(STR_BOOT_OPTIONS),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_BOOT_OPTION2), value = 2, flags = 0;
+ option text = STRING_TOKEN(STR_BOOT_OPTION1), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_BOOT_OPTION3), value = 3, flags = 0;
+ suppressif ideqval MyIfrNVData.BootOrderLarge == 0;
+ option text = STRING_TOKEN(STR_BOOT_OPTION4), value = 4, flags = 0;
+ endif;
+ endlist;
+
+ //
+ // label should be paired with each other
+ //
+ label LABEL_END;
+
+ endif; // end suppressif
+
+ disableif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x2;
+ orderedlist
+ varid = MyIfrNVData.OrderedList,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE),
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 3, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 2, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 1, flags = 0;
+ default = {1,2,3},
+ endlist;
+ endif;
+
+ label 100;
+
+ //
+ // Define a hyperlink (EFI_IFR_REF)
+ //
+ goto 0x1234, // Destination Form ID
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC), // Prompt string
+ help = STRING_TOKEN(STR_GOTO_HELP), // Help string
+ flags = INTERACTIVE, // INTERACTIVE indicate it's marked with EFI_IFR_FLAG_CALLBACK
+ key = 0x1234; // Question ID which will be passed-in in COnfigAccess.Callback()
+
+ goto 0x1234,
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC2),
+ help = STRING_TOKEN(STR_GOTO_HELP),
+ flags = INTERACTIVE,
+ key = 0x1235;
+
+ oneof varid = MyIfrNVData.TestLateCheck,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT;
+ warningif prompt = STRING_TOKEN(STR_WARNING_POPUP), timeout = 5,
+ ideqval MyIfrNVData.TestLateCheck == 0
+ endif;
+
+ endoneof;
+
+ oneof varid = MyIfrNVData.TestLateCheck2,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE2),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = 0;
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqid MyIfrNVData.TestLateCheck == MyIfrNVData.TestLateCheck2
+ endif;
+
+ endoneof;
+
+ oneof varid = MyIfrNVData.QuestionAboutTreeHugging,
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT_KEYWORD),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ flags = RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 3, flags = 0;
+ endoneof;
+
+ //
+ // Define a string (EFI_IFR_STRING)
+ //
+ string varid = MyIfrNVData.MyStringData,
+ prompt = STRING_TOKEN(STR_MY_STRING_PROMPT2),
+ help = STRING_TOKEN(STR_MY_STRING_HELP2),
+ flags = INTERACTIVE,
+ key = 0x1236,
+ minsize = 6,
+ maxsize = 40,
+ inconsistentif prompt = STRING_TOKEN(STR_STRING_CHECK_ERROR_POPUP),
+ pushthis != stringref(STRING_TOKEN(STR_STRING_CHECK))
+ endif;
+ endstring;
+
+ //
+ // Define a numeric (EFI_IFR_NUMERIC)
+ //
+ numeric varid = MyIfrNVData.HowOldAreYouInYearsManual,
+ prompt = STRING_TOKEN(STR_NUMERIC_READONLY_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ flags = READ_ONLY, // READ_ONLY indicate it's marked with EFI_IFR_FLAG_READ_ONLY
+ minimum = 0,
+ maximum = 0xf0,
+ step = 0, // Stepping of 0 equates to a manual entering
+ // of a value, otherwise it will be adjusted by "+"/"-"
+ default = 21, // defaultstore could be used to specify the default type
+ // If no defaultstore is specified, it implies Standard Default
+
+ endnumeric;
+
+ numeric varid = MyIfrNVData.HowOldAreYouInYearsManual,
+ prompt = STRING_TOKEN(STR_NUMERIC_MANUAL_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ minimum = 0,
+ maximum = 0xf0,
+ step = 0,
+ default value = questionrefval(devicepath = STRING_TOKEN (STR_DEVICE_PATH), guid = DRIVER_SAMPLE_FORMSET_GUID, 0x1111),
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval MyIfrNVData.HowOldAreYouInYearsManual == 99
+ OR
+ ideqid MyIfrNVData.HowOldAreYouInYearsManual == MyEfiVar.Field8
+ OR
+ ideqvallist MyIfrNVData.HowOldAreYouInYearsManual == 1 3 5 7
+ endif;
+
+ endnumeric;
+
+ numeric varid = MyEfiVar.Field8, // Reference of EFI variable storage
+ questionid = 0x1111,
+ prompt = STRING_TOKEN(STR_TALL_HEX_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP1),
+ flags = DISPLAY_UINT_HEX | INTERACTIVE, // Display in HEX format (if not specified, default is in decimal format)
+ minimum = 0,
+ maximum = 250,
+ default = 18, defaultstore = MyStandardDefault, // This is standard default value
+ default = 19, defaultstore = MyManufactureDefault, // This is manufacture default value
+
+ endnumeric;
+
+ //
+ // Define numeric using Name/Value Storage
+ //
+ numeric varid = MyNameValueVar[0], // This numeric take NameValueVar0 as storage
+ prompt = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME0),
+ help = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME0_HELP),
+ //
+ // Size should be defined for numeric when use Name/Value storage
+ // Valid value for numerice size are: NUMERIC_SIZE_1, NUMERIC_SIZE_2, NUMERIC_SIZE_4 and NUMERIC_SIZE_8
+ //
+ flags = NUMERIC_SIZE_1, // Size of this numeric is 1 byte
+ minimum = 0,
+ maximum = 0xff,
+ step = 0,
+ locked,
+ default = 16, defaultstore = MyStandardDefault, // This is standard default value
+ default = 17, defaultstore = MyManufactureDefault, // This is manufacture default value
+ endnumeric;
+
+ numeric varid = MyNameValueVar[1], // This numeric take NameValueVar1 as storage
+ prompt = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME1),
+ help = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME1_HELP),
+ flags = NUMERIC_SIZE_2, // Size of this numeric is 2 bytes
+ minimum = 0,
+ maximum = 0xffff,
+ step = 0,
+ default = 18, defaultstore = MyStandardDefault, // This is standard default value
+ default = 19, defaultstore = MyManufactureDefault, // This is manufacture default value
+ endnumeric;
+
+ //
+ // Define string using Name/Value Storage
+ //
+ string varid = MyNameValueVar[2], // This string take NameValueVar2 as storage
+ prompt = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME2),
+ help = STRING_TOKEN(STR_NAME_VALUE_VAR_NAME2_HELP),
+ minsize = 2,
+ maxsize = 0x14,
+ endstring;
+
+ oneof varid = MyEfiVar.Field16,
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_NUM_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0x0, flags = 0;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 0x1, flags = DEFAULT;
+ endoneof;
+
+ label LABEL_1_VALUE;
+ label LABEL_2_VALUE;
+
+ grayoutif ideqval MyIfrNVData.HowOldAreYouInYearsManual == 23 AND ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
+ numeric varid = MyIfrNVData.HowOldAreYouInYears,
+ prompt = STRING_TOKEN(STR_NUMERIC_STEP_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP2),
+ minimum = 0,
+ maximum = 243,
+ step = 1,
+ default = 18, defaultstore = MyStandardDefault, // This is standard default value
+ default = 19, defaultstore = MyManufactureDefault, // This is manufacture default value
+
+ endnumeric;
+ endif;
+
+ numeric varid = MyIfrNVData.GetDefaultValueFromAccess,
+ questionid = 0x1239,
+ prompt = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_ACCESS_PROMPT),
+ help = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_ACCESS_HELP),
+ flags = DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 0,
+ maximum = 255,
+ step = 1,
+ default = 18,
+ endnumeric;
+
+ numeric varid = MyIfrNVData.GetDefaultValueFromCallBack,
+ questionid = 0x1240,
+ prompt = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_CALLBACK_PROMPT),
+ help = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_CALLBACK_HELP),
+ flags = DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 0,
+ maximum = 255,
+ step = 1,
+ default = 18,
+ endnumeric;
+
+ orderedlist
+ varid = MyIfrNVData.GetDefaultValueFromCallBackForOrderedList,
+ questionid = 0x1252,
+ prompt = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_CALLBACK_PROMPT),
+ help = STRING_TOKEN(STR_DEFAULT_VALUE_FROM_CALLBACK_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 2, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 3, flags = 0;
+ endlist;
+
+ resetbutton
+ defaultstore = MyStandardDefault,
+ prompt = STRING_TOKEN(STR_STANDARD_DEFAULT_PROMPT),
+ help = STRING_TOKEN(STR_STANDARD_DEFAULT_HELP),
+ endresetbutton;
+
+ resetbutton
+ defaultstore = MyManufactureDefault,
+ prompt = STRING_TOKEN(STR_MANUFACTURE_DEFAULT_PROMPT),
+ help = STRING_TOKEN(STR_MANUFACTURE_DEFAULT_HELP),
+ endresetbutton;
+
+ //
+ // Sample use case for IFR Security op-code
+ //
+ grayoutif NOT security (EFI_USER_INFO_ACCESS_SETUP_ADMIN_GUID);
+ text
+ help = STRING_TOKEN(STR_TEXT_SECRUITY_TEST_HELP),
+ text = STRING_TOKEN(STR_TEXT_SECRUITY_TEST_TEXT);
+ endif;
+
+ numeric varid = MyEfiVar.SubmittedCallback,
+ questionid = 0x1250,
+ prompt = STRING_TOKEN(STR_SUBMITTED_CALLBACK_TEST_PROMPT),
+ help = STRING_TOKEN(STR_SUBMITTED_CALLBACK_TEST_HELP),
+ flags = INTERACTIVE,
+ minimum = 0,
+ maximum = 255,
+ default = 18,
+ endnumeric;
+
+ text
+ help = STRING_TOKEN(STR_POPUP_TEST_HELP),
+ text = STRING_TOKEN(STR_POPUP_TEST_PROMPT),
+ flags = INTERACTIVE,
+ key = 0x1330;
+
+ goto 2,
+ prompt = STRING_TOKEN(STR_GOTO_FORM2), //SecondSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto 3,
+ prompt = STRING_TOKEN(STR_GOTO_FORM3), //ThirdSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto 4,
+ prompt = STRING_TOKEN(STR_GOTO_FORM4), //FourthSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto 5,
+ prompt = STRING_TOKEN(STR_GOTO_FORM5), //FifthSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_FORM5_HELP);
+
+ goto 6,
+ prompt = STRING_TOKEN(STR_GOTO_FORM6), //SixthSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto
+ formsetguid = DRIVER_SAMPLE_INVENTORY_GUID,
+ formid = 0x1,
+ question = 0x1,
+ prompt = STRING_TOKEN(STR_GOTO_ANOTHER_FORMSET),
+ help = STRING_TOKEN(STR_GOTO_ANOTHER_FORMSET_HELP);
+
+ guidop
+ guid = DRIVER_SAMPLE_FORMSET_GUID,
+ datatype = MY_EFI_VARSTORE_DATA,
+ data.Field8 = 0x21,
+ data.Field16 = 0x2121,
+ data.OrderedList[0] = 0x21,
+ endguidop;
+
+ goto 7,
+ prompt = STRING_TOKEN(STR_GOTO_FORM7),
+ help = STRING_TOKEN(STR_GOTO_FORM7_HELP);
+
+ endform;
+
+ suppressif ideqval MyIfrNVData.BootOrderLarge == 0;
+ form formid = 2, // SecondSetupPage,
+ title = STRING_TOKEN(STR_FORM2_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ date
+ name = Date,
+ prompt = STRING_TOKEN(STR_DATE_PROMPT),
+ help = STRING_TOKEN(STR_DATE_HELP),
+ flags = STORAGE_TIME,
+ default = 2004/1/1,
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 31
+ AND
+ ideqvallist Date.Month == 2 4 6 9 11
+ endif;
+
+ //
+ // If the day is 30 AND month is 2
+ //
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 30
+ AND
+ ideqval Date.Month == 2
+ endif;
+
+ //
+ // If the day is 29 AND month is 2 AND it year is NOT a leapyear
+ //
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 0x1D
+ AND
+ ideqval Date.Month == 2
+ AND
+ NOT
+ ideqvallist Date.Year == 2004 2008 20012 20016 2020 2024 2028 2032 2036
+ endif;
+
+ enddate;
+
+ text
+ help = STRING_TOKEN(STR_SAVE_CURRENT_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_CURRENT_AND_EXIT),
+ flags = INTERACTIVE,
+ key = 0x1241;
+
+ text
+ help = STRING_TOKEN(STR_DISCARD_CURRENT),
+ text = STRING_TOKEN(STR_DISCARD_CURRENT),
+ flags = INTERACTIVE,
+ key = 0x1242;
+
+ time
+ prompt = STRING_TOKEN(STR_TIME_PROMPT),
+ help = STRING_TOKEN(STR_TIME_HELP),
+ flags = STORAGE_TIME,
+ endtime;
+
+ time
+ name = MyTime,
+ varid = MyIfrNVData.Time,
+ prompt = STRING_TOKEN(STR_TIME_PROMPT),
+ help = STRING_TOKEN(STR_TIME_PROMPT),
+ flags = STORAGE_NORMAL | SECOND_SUPPRESS,
+ default = 15:33:33,
+ endtime;
+
+ checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry,
+ prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ endcheckbox;
+
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1);
+
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1),
+ text = STRING_TOKEN(STR_TEXT_TEXT_2);
+
+ goto 1,
+ prompt = STRING_TOKEN(STR_GOTO_FORM1), //MainSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto
+ varid = MyIfrNVData.RefData,
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC3),
+ help = STRING_TOKEN(STR_GOTO_DYNAMIC3_HELP),
+ flags = INTERACTIVE,
+ key = 0x1248,
+ //
+ // Set the defult value, format is QuestionId; FormId; FormsetGuid; Device Path String Token
+ //
+ default = 0;0;ZERO_GUID;STRING_TOKEN(STR_NULL_STRING),
+ ; // goto opcode end flag.
+
+ goto
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC4),
+ help = STRING_TOKEN(STR_GOTO_DYNAMIC4_HELP),
+ flags = INTERACTIVE,
+ key = 0x1249;
+
+ endform;
+ endif;
+
+ form formid = 3, title = STRING_TOKEN(STR_FORM3_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ suppressif ideqval MyEfiVar.Field8 == 111;
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1);
+ endif;
+
+ goto 1,
+ prompt = STRING_TOKEN(STR_GOTO_FORM1), //MainSetupPage
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ numeric varid = MyIfrNVData.DynamicRefresh,
+ prompt = STRING_TOKEN(STR_NUMERIC_MANUAL_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ flags = INTERACTIVE,
+ key = 0x5678,
+ minimum = 0,
+ maximum = 0xff,
+ step = 0,
+ default = 0,
+ refresh interval = 3 // Refresh interval in seconds
+ endnumeric;
+
+ grayoutif match2 (stringref(STRING_TOKEN(STR_PATTERN)), stringref(STRING_TOKEN(STR_STRING)), PERL_GUID);
+ numeric
+ varid = MyIfrNVData.Match2,
+ prompt = STRING_TOKEN(STR_MATCH2_PROMPT),
+ help = STRING_TOKEN(STR_MATCH2_HELP),
+ minimum = 0,
+ maximum = 243,
+ endnumeric;
+ endif;
+
+ label LABEL_UPDATE2;
+ label LABEL_END;
+
+ endform;
+
+ formmap formid = 4,
+ maptitle = STRING_TOKEN(STR_SAMPL_MAP_METHOD);
+ mapguid = DRIVER_SAMPLE_FORMSET_GUID;
+ maptitle = STRING_TOKEN(STR_STANDARD_MAP_METHOD);
+ mapguid = EFI_HII_STANDARD_FORM_GUID;
+
+ oneof varid = MyIfrNVData.SerialPortNo,
+ prompt = STRING_TOKEN(STR_SERIAL_PORT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+
+ read cond (get(MyIfrNVData.SerialPortStatus) != 0 ? 0 : cond ((get(MyIfrNVData.SerialPortIo) & 0xF00) >> 0x8 == get(MyIfrNVData.SerialPortIrq) - 1 ? UNDEFINED : map (get(MyIfrNVData.SerialPortIo) : 0x3f8,1; 0x2F8,2; 0x3E8,3; 0x2E8,4;)));
+ write set(MyIfrNVData.SerialPortStatus, pushthis != 0) AND set(MyIfrNVData.SerialPortIo, map (pushthis : 1,0x3F8; 2,0x2F8; 3,0x3E8; 4,0x2E8;)) AND set (MyIfrNVData.SerialPortIrq, map (pushthis: 1,4; 2,3; 3,4; 4,3;));
+
+ option text = STRING_TOKEN(STR_SERIAL_PORT_DISABLE), value = 0x0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_SERIAL_PORT1), value = 0x1, flags = 0;
+ option text = STRING_TOKEN(STR_SERIAL_PORT2), value = 0x2, flags = 0;
+ option text = STRING_TOKEN(STR_SERIAL_PORT3), value = 0x3, flags = 0;
+ option text = STRING_TOKEN(STR_SERIAL_PORT4), value = 0x4, flags = 0;
+ endoneof;
+
+ grayoutif TRUE;
+ checkbox varid = MyIfrNVData.SerialPortStatus,
+ prompt = STRING_TOKEN(STR_SERIAL_PORT_STATUS),
+ help = STRING_TOKEN(STR_CHECK_BOX_HELP),
+ endcheckbox;
+ endif;
+
+ grayoutif TRUE;
+ suppressif ideqval MyIfrNVData.SerialPortStatus == 0;
+ oneof varid = MyIfrNVData.SerialPortIo,
+ prompt = STRING_TOKEN(STR_SERIAL_PORT_IO_ADDRESS),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+
+ option text = STRING_TOKEN(STR_SERIAL_PORT1_IOADDR), value = 0x3F8, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_SERIAL_PORT2_IOADDR), value = 0x2F8, flags = 0;
+ option text = STRING_TOKEN(STR_SERIAL_PORT3_IOADDR), value = 0x3E8, flags = 0;
+ option text = STRING_TOKEN(STR_SERIAL_PORT4_IOADDR), value = 0x2E8, flags = 0;
+ endoneof;
+ endif;
+ endif;
+
+ grayoutif TRUE;
+ suppressif ideqval MyIfrNVData.SerialPortStatus == 0;
+ oneof varid = MyIfrNVData.SerialPortIrq,
+ prompt = STRING_TOKEN(STR_SERIAL_PORT_IRQ),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+
+ option text = STRING_TOKEN(STR_SERIAL_PORT13_IRQ), value = 0x4, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_SERIAL_PORT24_IRQ), value = 0x3, flags = 0;
+ endoneof;
+ endif;
+ endif;
+
+ goto 1,
+ prompt = STRING_TOKEN(STR_GOTO_FORM1), //MainSetupPage
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ endform;
+
+ form formid = 5, // Modal form
+ title = STRING_TOKEN(STR_MODAL_FORM_TITLE);
+ //
+ // This form is a modal form.
+ //
+ modal;
+ text
+ help = STRING_TOKEN(STR_EXIT_TEXT),
+ text = STRING_TOKEN(STR_EXIT_TEXT),
+ flags = INTERACTIVE, // VfrCompiler will generate opcode EFI_IFR_ACTION for Text marked as INTERACTIVE
+ key = 0x1245;
+
+ text
+ help = STRING_TOKEN(STR_SAVE_TEXT),
+ text = STRING_TOKEN(STR_SAVE_TEXT),
+ flags = INTERACTIVE, // VfrCompiler will generate opcode EFI_IFR_ACTION for Text marked as INTERACTIVE
+ key = 0x1246;
+ endform;
+
+ form formid = 6, // Form to show the refresh guid group op-code
+ title = STRING_TOKEN(STR_FORM6_TITLE);
+
+ text
+ help = STRING_TOKEN(STR_TEXT_REFRESH_GUID),
+ text = STRING_TOKEN(STR_TEXT_REFRESH_GUID);
+
+ numeric varid = MyIfrNVData.RefreshGuidCount,
+ prompt = STRING_TOKEN(STR_TEXT_REFRESH_GUID_COUNT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ flags = INTERACTIVE,
+ key = 0x1247,
+ minimum = 0,
+ maximum = 0xff,
+ step = 0,
+ default = 0,
+ refreshguid = EFI_IFR_REFRESH_ID_OP_GUID,
+ endnumeric;
+
+ label LABEL_UPDATE3;
+ label LABEL_END;
+
+ endform;
+
+ form formid = 0x1234, // Dynamically created page,
+ title = STRING_TOKEN(STR_DYNAMIC_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ label LABEL_UPDATE1;
+ //
+ // This is where we will insert dynamic created opcodes
+ //
+ label LABEL_END;
+
+ endform;
+
+
+ form formid = 7, // Form to show the question refer to union and bit Varstore
+ title = STRING_TOKEN(STR_FORM7_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NEST_BIT_EFI_VARSTORE);
+
+ checkbox varid = MyEfiBitVar.BitsData.NestBitCheckbox,
+ prompt = STRING_TOKEN(STR_BIT_NEST_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_BIT_NEST_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ endcheckbox;
+
+ oneof varid = MyEfiBitVar.BitsData.NestBitOneof,
+ prompt = STRING_TOKEN(STR_ONE_OF_BIT_NEST_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_BIT_NEST_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 1, flags = DEFAULT;
+ endoneof;
+
+ numeric varid = MyEfiBitVar.BitsData.NestBitNumeric,
+ questionid = 0x6666,
+ prompt = STRING_TOKEN(STR_BIT_NEST_NUMERIC_PROMPT),
+ help = STRING_TOKEN(STR_BIT_NEST_NUMERIC_DEFAULT_HELP),
+ flags = DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 2,
+ maximum = 15,
+ step = 1,
+ endnumeric;
+
+ oneof varid = MyEfiBitVar.BitsData.NestByteField,
+ prompt = STRING_TOKEN(BYTE_QUESTION_NEST_BIT_PROMPT),
+ help = STRING_TOKEN(BYTE_QUESTION_NEST_BIT_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 1, flags = DEFAULT;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+ subtitle text = STRING_TOKEN(STR_BIT_EFI_VARSTORE);
+
+ checkbox varid = MyEfiBitVar.EfiBitCheckbox,
+ prompt = STRING_TOKEN(STR_BIT_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_BIT_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ endcheckbox;
+
+ grayoutif ideqval MyEfiBitVar.EfiBitGrayoutTest == 0;
+ numeric varid = MyEfiBitVar.EfiBitNumeric,
+ prompt = STRING_TOKEN(STR_BIT_NUMERIC_PROMPT),
+ help = STRING_TOKEN(STR_BIT_NUMERIC_HELP),
+ minimum = 0,
+ maximum = 7,
+ step = 0,
+ default = 4, defaultstore = MyStandardDefault,
+ default = 5, defaultstore = MyManufactureDefault,
+ endnumeric;
+ endif;
+
+ oneof varid = MyEfiBitVar.EfiBitOneof,
+ questionid = 0x9999,
+ prompt = STRING_TOKEN(STR_ONE_OF_BIT_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_BIT_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0x0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 0x1, flags = DEFAULT;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+ subtitle text = STRING_TOKEN(STR_NEST_BIT_VARSTORE);
+ checkbox varid = MyIfrNVData.MyBitData.NestBitCheckbox,
+ prompt = STRING_TOKEN(STR_BIT_NEST_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_BIT_NEST_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ endcheckbox;
+
+ oneof varid = MyIfrNVData.MyBitData.NestBitOneof,
+ prompt = STRING_TOKEN(STR_ONE_OF_BIT_NEST_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_BIT_NEST_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 1, flags = DEFAULT;
+ endoneof;
+
+ numeric varid = MyIfrNVData.MyBitData.NestBitNumeric,
+ prompt = STRING_TOKEN(STR_BIT_NEST_NUMERIC_PROMPT),
+ help = STRING_TOKEN(STR_BIT_NEST_NUMERIC_HELP),
+ minimum = 0,
+ maximum = 7,
+ step = 0,
+ default = 6, defaultstore = MyStandardDefault,
+ default = 7, defaultstore = MyManufactureDefault,
+ endnumeric;
+
+ oneof varid = MyIfrNVData.MyBitData.NestByteField,
+ prompt = STRING_TOKEN(BYTE_QUESTION_NEST_BIT_PROMPT),
+ help = STRING_TOKEN(BYTE_QUESTION_NEST_BIT_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 1, flags = DEFAULT;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+ subtitle text = STRING_TOKEN(STR_BIT_VARSTORE);
+
+ oneof varid = MyIfrNVData.BitOneof,
+ prompt = STRING_TOKEN(STR_ONE_OF_BIT_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_BIT_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0, flags = MANUFACTURING;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 1, flags = DEFAULT;
+ endoneof;
+
+ checkbox varid = MyIfrNVData.BitCheckbox,
+ prompt = STRING_TOKEN(STR_BIT_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_BIT_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ endcheckbox;
+
+ numeric varid = MyIfrNVData.BitNumeric,
+ prompt = STRING_TOKEN(STR_BIT_NUMERIC_PROMPT),
+ help = STRING_TOKEN(STR_BUFFER_BIT_NUMERIC_HELP),
+ minimum = 0,
+ maximum = 20,
+ step = 0,
+ default = 16, defaultstore = MyStandardDefault,
+ default = 17, defaultstore = MyManufactureDefault,
+ endnumeric;
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+ subtitle text = STRING_TOKEN(STR_UNION_EFI_VARSTORE);
+
+ numeric varid = MyEfiUnionVar.UnionNumeric,
+ prompt = STRING_TOKEN(STR_UNION_BYTE_NUMERIC_PROMPT),
+ help = STRING_TOKEN(STR_UNION_BYTE_NUMERIC_HELP),
+ minimum = 0,
+ maximum = 20,
+ step = 0,
+ default = 7, defaultstore = MyStandardDefault,
+ default = 8, defaultstore = MyManufactureDefault,
+ endnumeric;
+
+ guidop
+ guid = DRIVER_SAMPLE_FORMSET_GUID,
+ datatype = MY_EFI_BITS_VARSTORE_DATA,
+ data.EfiBitNumeric = 1,
+ data.EfiBitOneof = 1,
+ data.EfiBitCheckbox = 1,
+ endguidop;
+
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni
new file mode 100644
index 000000000..bafa194c6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni
@@ -0,0 +1,428 @@
+// *++
+ //
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// VfrStrings.vfr
+//
+// Abstract:
+//
+// String definitions for Sample Setup formset.
+//
+// Revision History:
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+#langdef x-UEFI-ns "UefiNameSpace"
+
+
+#string STR_FORM_SET_TITLE #language en-US "Browser Testcase Engine"
+ #language fr-FR "Browser Testcase Engine"
+#string STR_FORM_SET_TITLE_HELP #language en-US "This is a sample driver which is used to test the browser op-code operations. This is for development purposes and not to be distributed in any form other than a test application. Here is a set of wide \wideAAAAAAAAA\narrow and narrow AAA!"
+ #language fr-FR "This is a sample driver which is used to test the browser op-code operations. This is for development purposes and not to be distributed in any form other than a test application. Here is a set of wide \wideAAAAAAAAA\narrow and narrow AAA!"
+#string STR_FORM1_TITLE #language en-US "My First Setup Page"
+ #language fr-FR "Mi Primero Arreglo Página"
+#string STR_FORM2_TITLE #language en-US "My Second Setup Page"
+ #language fr-FR "Mi Segunda Paginación De la Disposición"
+#string STR_FORM3_TITLE #language en-US "My Third Setup Page"
+ #language fr-FR "Mi Tercera Paginación De la Disposición"
+#string STR_FORM6_TITLE #language en-US "My Sixth Setup Page"
+ #language fr-FR "My Sixth Setup Page"
+#string STR_DYNAMIC_TITLE #language en-US "My Dynamic Page"
+ #language fr-FR "My Dynamic Page Spanish"
+#string STR_SUBTITLE_TEXT #language en-US "My subtitle text"
+ #language fr-FR "Mi texto del subtítulo"
+#string STR_SUBTITLE_TEXT2 #language en-US " "
+ #language fr-FR " "
+#string STR_CPU_STRING #language en-US "My CPU Speed is "
+ #language fr-FR "My CPU Speed is "
+#string STR_CPU_STRING2 #language en-US " "
+ #language fr-FR " "
+#string STR_NUMERIC_NUM_PROMPT #language en-US "Please select the number"
+ #language fr-FR "Please select the number"
+#string STR_NUMERIC_NUM_HELP #language en-US "Check the input number, test the efi buffer varstore"
+ #language fr-FR "Check the input number, test the efi buffer varstore"
+#string STR_ONE_OF_PROMPT #language en-US "My one-of prompt #1"
+ #language fr-FR "Mi uno- de guía # 1"
+#string STR_ONE_OF_PROMPT_KEYWORD #language en-US "My Keyword Namespace Test"
+ #language fr-FR "My Keyword Namespace Test"
+ #language x-UEFI-ns "iSCSIBootEnable"
+#string STR_CHECK_KEYWORD_SUPPORT #language en-US "Check iSCSI Boot Enable"
+ #language fr-FR "Check iSCSI Boot Enable"
+#string STR_ONE_OF_HELP #language en-US "My one-of help is going to be a long string to test out the efficiency of the ability of the I am tired of typing capabilities"
+ #language fr-FR "Mi uno- de ayuda va a ser una cadena larga a probar fuera de la eficacia de la capacidad del yo es cansada de capacidades el pulsar."
+#string STR_ONE_OF_TEXT1 #language en-US "My one-of text #1"
+ #language fr-FR "Mi uno- del texto # 1"
+#string STR_ONE_OF_TEXT2 #language en-US "My one-of text #2"
+ #language fr-FR "Mi uno- del texto # 2"
+#string STR_ONE_OF_TEXT3 #language en-US "My one-of text #3"
+ #language fr-FR "Mi uno- del texto # 3"
+#string STR_ONE_OF_TEXT4 #language en-US "Suppress the Checkbox"
+ #language fr-FR "Mi uno- del texto # 4"
+#string STR_ONE_OF_TEXT5 #language en-US "GrayOut the Checkbox"
+ #language fr-FR "Mi uno- del texto # 5"
+#string STR_ONE_OF_TEXT6 #language en-US "Enable Checkbox"
+ #language fr-FR "Mi uno- del texto # 6"
+#string STR_BOOT_ORDER1 #language en-US "SmallBootList"
+ #language fr-FR "Mi uno- del texto # 7"
+#string STR_BOOT_ORDER2 #language en-US "LargeBootList"
+ #language fr-FR "Mi uno- del texto # 8"
+#string STR_CHECK_BOX_PROMPT #language en-US "Activate this check box"
+ #language fr-FR "Active Las Armas Nucleares"
+#string STR_CHECK_BOX_HELP #language en-US "This is the help message for the activation of check boxes. This is not to be confused with activating Czech boxes, since one can never tell what the ramifications are of activating foreign controlled boxes are."
+ #language fr-FR "Éste es el mensaje de la ayuda para la activación del armamento nuclear. Cuál es exactamente resistente calcular fuera sobre de eso?"
+#string STR_CHECK_DYNAMIC_PROMPT #language en-US "Activate Dynamic check box"
+ #language fr-FR "Activate Dynamico check box"
+#string STR_CHECK_DYNAMIC_HELP #language en-US "This is the help message for the activation of check boxes. This is not to be confused with activating Czech boxes, since one can never tell what the ramifications are of activating foreign controlled boxes are."
+ #language fr-FR "Spanish - This is the help message for the activation of check boxes. This is not to be confused with activating Czech boxes, since one can never tell what the ramifications are of activating foreign controlled boxes are."
+#string STR_NUMERIC_PROMPT #language en-US "How old are you?"
+ #language fr-FR "Cómo viejo es usted?"
+#string STR_NUMERIC_STEP_PROMPT #language en-US "How old are you? (Step)"
+ #language fr-FR "Cómo viejo es usted?(Step)"
+#string STR_NUMERIC_PROMPT1 #language en-US "How tall are you?"
+ #language fr-FR "Cómo viejo es usted?"
+#string STR_NUMERIC_READONLY_PROMPT #language en-US "How old are you?(Readonly)"
+ #language fr-FR "Cómo viejo es usted?(Readonly)"
+#string STR_NUMERIC_MANUAL_PROMPT #language en-US "How old are you? (Manual)"
+ #language fr-FR "Cómo viejo es usted? (Manual)"
+#string STR_TALL_HEX_PROMPT #language en-US "How tall are you? (Hex)"
+ #language fr-FR "Cómo viejo es usted? (Hex)"
+#string STR_MYIFRNVDATA2_HEX_PROMPT #language en-US "MyIfrNVData2 Uint8? (Hex)"
+#string STR_MYIFRNVDATA2_HEX_HELP #language en-US "MyIfrNVData2 Uint8? (Hex) Help"
+#string STR_NUMERIC_HELP0 #language en-US "This is the help for those who are too old to understand the question. Type how old you are in a numeric value. The valid range in this case is from 0 to 240. Let's see if you actually read this help and figure that out."
+ #language fr-FR "This is the help for those who are too old to understand the question. Type how old you are in a numeric value. The valid range in this case is from 0 to 240. Let's see if you actually read this help and figure that out."
+#string STR_NUMERIC_HELP1 #language en-US "This is the help for those who are curious about body height. Type how tall you are in a numeric value. The valid range in this case is from 0 to 250. Let's see if you actually read this help and figure that out."
+ #language fr-FR "This is the help for those who are curious about body height. Type how tall you are in a numeric value. The valid range in this case is from 0 to 250. Let's see if you actually read this help and figure that out."
+#string STR_NUMERIC_HELP2 #language en-US "This is the help for those who are too old to understand the question. Adjust how old you are step by step. The valid range in this case is from 0 to 243 in step of 1. Let's see if you actually read this help and figure that out."
+ #language fr-FR "This is the help for those who are too old to understand the question. Adjust how old you are step by step. The valid range in this case is from 0 to 243 in step of 1. Let's see if you actually read this help and figure that out."
+#string STR_NUMERIC_HELP3 #language en-US "This is the help for those who are curious about body height. Type how tall you are in a numeric value. The valid range in this case is from 0 to 190. Let's see if you actually read this help and figure that out."
+ #language fr-FR "Ésta es la ayuda para los que sean demasiado viejos entender la pregunta. Pulse cómo es viejo usted está en años."
+
+#string STR_PASSWORD_PROMPT #language en-US "Set the system password"
+ #language fr-FR "Cuál es la palabra mágica?"
+#string STR_TEXT_SECRUITY_TEST_TEXT #language en-US "Access only permitted for Admin"
+ #language fr-FR "Access only permitted for Admin"
+#string STR_TEXT_SECRUITY_TEST_HELP #language en-US "If this label is not gray, then current user has admin access setup permission. If this label is gray, then current user has no admin access setup permission."
+ #language fr-FR "If this label is not gray, then current user has admin access setup permission. If this label is gray, then current user has no admin access setup permission."
+#string STR_GOTO_FORM1 #language en-US "Enter Page 1"
+ #language fr-FR "Vaya a paginar 1"
+#string STR_GOTO_FORM2 #language en-US "Enter Page 2"
+ #language fr-FR "Vaya a paginar 2"
+#string STR_GOTO_FORM3 #language en-US "Enter Page 3"
+ #language fr-FR "Vaya a paginar 3"
+#string STR_GOTO_FORM4 #language en-US "Enter Page 4 Formmap Page"
+ #language fr-FR "Vaya a paginar 4"
+#string STR_GOTO_FORM6 #language en-US "Enter Page 6"
+ #language fr-FR "Enter Page 6"
+#string STR_GOTO_FORM5 #language en-US "Enter Page 5 Modal Page"
+ #language fr-FR "Enter Page 5 Modal Page"
+#string STR_GOTO_FORM5_HELP #language en-US "Enter this form to double confirm the selection, must select on option before exit!"
+ #language fr-FR "Enter this form to double confirm the selection, must select on option before exit!"
+#string STR_GOTO_DYNAMIC #language en-US "Goto Dynamic Page +"
+ #language fr-FR "Vaya a página dynamico"
+#string STR_GOTO_DYNAMIC2 #language en-US "Goto Fresh Dynamic Page"
+ #language fr-FR "Vaya a página fresca dynamico"
+#string STR_GOTO_DYNAMIC3 #language en-US "Update dest through retrieve"
+ #language fr-FR "Update dest through retrieve"
+#string STR_GOTO_DYNAMIC4 #language en-US "Update dest through changing"
+ #language fr-FR "Update dest through changing"
+#string STR_GOTO_DYNAMIC3_HELP #language en-US "Update the destination through "retrieve" call back type before user select it."
+ #language fr-FR "Update the destination through "retrieve" call back type before user select it."
+#string STR_GOTO_DYNAMIC4_HELP #language en-US "Update the destination through "changing" call back type when user select it."
+ #language fr-FR "Update the destination through "changing" call back type when user select it."
+#string STR_ERROR_INCONSISTENT #language en-US "This is my inconsistent error message"
+ #language fr-FR "Éste es mi mensaje de error contrario."
+#string STR_ERROR_POPUP #language en-US "You typed in something bad!"
+ #language fr-FR "Esto es un mensaje de error del popup."
+#string STR_MY_STRING_DEFAULT #language en-US "my password"
+ #language fr-FR "my password"
+#string STR_MY_STRING_PROMPT2 #language en-US "String - Interactive"
+ #language fr-FR "String - interactive"
+#string STR_MY_STRING_HELP2 #language en-US "This is my string help - Interactive"
+ #language fr-FR "This is my string help - interactive"
+#string STR_TEXT_TEXT_1 #language en-US "This is my 1st text string"
+ #language fr-FR "This is my 1st text string"
+#string STR_TEXT_TEXT_2 #language en-US "This is my 2nd text string that I am testing"
+ #language fr-FR "This is my 2nd text string that I am testing"
+#string STR_DATE_PROMPT #language en-US "System Date"
+ #language fr-FR "Fecha del sistema"
+#string STR_DATE_HELP #language en-US "This is the help for the Date (month/day/year). (Error checking will be done against month/day/year combinations that are not supported.)"
+ #language fr-FR "Esto es la ayuda para el Fecha (mes/día/las). (Verificar de error se hará contra vez mes/día/las combinaciones de año que no se sostienen.)"
+#string STR_TIME_PROMPT #language en-US "System Time"
+ #language fr-FR "Tiempo del sistema"
+#string STR_TIME_HELP #language en-US "This is the help for the Time (hour/minute/second)."
+ #language fr-FR "Esto es la ayuda para el Tiempo (hora/minuto/segundo)."
+#string STR_RESTORE_DEFAULTS_PROMPT #language en-US "This is my restore defaults prompt"
+ #language fr-FR "This is my Spanish restore defaults prompt"
+#string STR_RESTORE_DEFAULTS_HELP #language en-US "This is my restore defaults help"
+ #language fr-FR "Ésta es mi ayuda española de los defectos del restore"
+#string STR_SAVE_DEFAULTS_PROMPT #language en-US "This is my save defaults prompt"
+ #language fr-FR "This is my Spanish save defaults prompt"
+#string STR_SAVE_DEFAULTS_HELP #language en-US "This is my save defaults help"
+ #language fr-FR "This is my Spanish save defaults help"
+#string STR_TEXT_HELP #language en-US "This is my text help"
+ #language fr-FR "This is my Spanish text help"
+#string STR_GOTO_HELP #language en-US "This is my goto help"
+ #language fr-FR "This is my Spanish goto help"
+#string STR_BANNER_TITLE #language en-US "This is my English banner title"
+ #language fr-FR "Éste es mi título español de la bandera"
+#string STR_SUPPRESS_IF_TEXT1 #language en-US "This is my English suppress-if text1"
+ #language fr-FR "This is my Spanish suppress-if text1"
+#string STR_SUPPRESS_IF_TEXT2 #language en-US "This is my English suppress-if text2"
+ #language fr-FR "This is my Spanish suppress-if text2"
+#string STR_GRAYOUT_IF_TEXT1 #language en-US "This is my English grayout-if text1"
+ #language fr-FR "This is my Spanish grayout-if text1"
+#string STR_GRAYOUT_IF_TEXT2 #language en-US "This is my English grayout-if text2"
+ #language fr-FR "This is my Spanish grayout-if text2"
+#string STR_INVENTORY_HELP #language en-US "This is my English inventory help string"
+ #language fr-FR "This is my Spanish inventory help string"
+#string STR_INVENTORY_TEXT1 #language en-US "This is my English inventory text1 string"
+ #language fr-FR "This is my Spanish inventory text1 string"
+#string STR_INVENTORY_TEXT2 #language en-US "This is my English inventory text2 string"
+ #language fr-FR "This is my Spanish inventory text2 string"
+#string STR_TEST_OPCODE #language en-US "Pick 1"
+ #language fr-FR "Pick 1"
+#string STR_TEST_OPCODE2 #language en-US "Pick 2"
+ #language fr-FR "Pick 2"
+#string STR_EXIT_TEXT #language en-US "Exit now!"
+ #language fr-FR "Salir ahora!"
+#string STR_SAVE_TEXT #language en-US "Save now!"
+ #language fr-FR "(French)Save now!"
+#string STR_RESET_TEXT #language en-US "Reset now!"
+ #language fr-FR "(French)Reset now!"
+#string STR_DISCARD_CURRENT #language en-US "Discard current form now!"
+ #language fr-FR "(French)Discard current form now!"
+#string STR_SAVE_CURRENT #language en-US "Save current form now!"
+ #language fr-FR "(French)Save current form now!"
+#string STR_DISCARD_CURRENT_AND_EXIT #language en-US "Discard current form and exit now!"
+ #language fr-FR "(French)Discard current form and exit now!"
+#string STR_SAVE_CURRENT_AND_EXIT #language en-US "Save current form and exit now!"
+ #language fr-FR "(French)Save current form and exit now!"
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_TEST_STRING #language en-US "This is a test string"
+ #language fr-FR "Esto es una secuencia de la prueba"
+#string STR_GRAYOUT_TEST #language en-US "Grayout VarEq test"
+ #language fr-FR "Grayout VarEq test"
+#string STR_SUPPRESS_TEST #language en-US "Suppress VarEq test"
+ #language fr-FR "Suppress VarEq test"
+#string STR_CLEAR_TEST #language en-US "Clear VarEq test"
+ #language fr-FR "Clear VarEq test"
+#string STR_STANDARD_DEFAULT_PROMPT #language en-US "Reset to Standard Default"
+ #language fr-FR "Reset to Standard Default"
+#string STR_STANDARD_DEFAULT_HELP #language en-US "This will reset all the Questions to their standard default value"
+ #language fr-FR "This will reset all the Questions to their standard default value"
+#string STR_MANUFACTURE_DEFAULT_PROMPT #language en-US "Reset to Manufacture Default"
+ #language fr-FR "Reset to Manufacture Default"
+#string STR_MANUFACTURE_DEFAULT_HELP #language en-US "This will reset all the Questions to their manufacture default value"
+ #language fr-FR "This will reset all the Questions to their manufacture default value"
+#string STR_NAME_VALUE_VAR_NAME0_HELP #language en-US "This numeric(UINT8) use Name/Value storage, Name is NameValueVar0"
+ #language fr-FR "This numeric(UINT8) use Name/Value storage, Name is NameValueVar0"
+#string STR_NAME_VALUE_VAR_NAME1_HELP #language en-US "This numeric(UINT16) use Name/Value storage, Name is NameValueVar1"
+ #language fr-FR "This numeric(UINT16) use Name/Value storage, Name is NameValueVar1"
+#string STR_NAME_VALUE_VAR_NAME2_HELP #language en-US "This string use Name/Value storage, Name is NameValueVar2"
+ #language fr-FR "This string use Name/Value storage, Name is NameValueVar2"
+#string STR_STRING_CHECK #language en-US "STRING"
+ #language fr-FR "STRING"
+#string STR_STRING_CHECK_ERROR_POPUP #language en-US "String you typed in is not correct!"
+ #language fr-FR "String you typed in is not correct!"
+#string STR_TEXT_REFRESH_GUID #language en-US "Add new menu by press "Ctrl + C""
+ #language fr-FR "Add new menu by press "Ctrl + C""
+#string STR_TEXT_REFRESH_GUID_COUNT #language en-US "Refresh guid event count"
+ #language fr-FR "Refresh guid event count"
+#string STR_MODAL_FORM_TITLE #language en-US "First Modal Form"
+ #language fr-FR "First Modal Form"
+#string STR_EXIT_THROUGH_FORM_DISCARD_EXIT #language en-US "Exit through form discard and exit"
+ #language fr-FR "Exit through form discard and exit"
+#string STR_EXIT_THROUGH_FORM_SUBMIT_EXIT #language en-US "Exit through form submit and exit"
+ #language fr-FR "Exit through form submit and exit"
+#string STR_DEFAULT_VALUE_FROM_CALLBACK_PROMPT #language en-US "Get Call Back default"
+ #language fr-FR "Get Call Back default"
+#string STR_DEFAULT_VALUE_FROM_CALLBACK_HELP #language en-US "This is the help for getting default value from call back function"
+ #language fr-FR "This is the help for getting default value from call back function"
+#string STR_DEFAULT_VALUE_FROM_ACCESS_PROMPT #language en-US "Get ExtractConfig default"
+ #language fr-FR "Get ExtractConfig default"
+#string STR_DEFAULT_VALUE_FROM_ACCESS_HELP #language en-US "This is the help for getting default value from ExtractConfig function"
+ #language fr-FR "This is the help for getting default value from ExtractConfig function"
+#string STR_GOTO_ANOTHER_FORMSET #language en-US "Goto ABC Information Sample FormSet"
+ #language fr-FR "Goto ABC Information Sample FormSet"
+#string STR_GOTO_ANOTHER_FORMSET_HELP #language en-US "When select this option, browser will go to another formset."
+ #language fr-FR "When select this option, browser will go to another formset."
+#string STR_DEVICE_PATH #language en-US ""
+ #language fr-FR ""
+#string STR_SUBMITTED_CALLBACK_TEST_PROMPT #language en-US "Submitted callback test"
+ #language fr-FR "Submitted callback test"
+#string STR_SUBMITTED_CALLBACK_TEST_HELP #language en-US "Change the value and press F10 to submmit will pop up a dialogue to show SUBMITTED Callback has been triggered"
+ #language fr-FR "Change the value and press F10 to submmit will pop up a dialogue to show SUBMITTED Callback has been triggered"
+#string STR_POPUP_TEST_PROMPT #language en-US "Select it to invoke Hii Popup Protocol"
+ #language fr-FR "Select it to invoke Hii Popup Protocol"
+#string STR_POPUP_TEST_HELP #language en-US "Select this question will pop up a message box, then user can decide whether exit curret form or not"
+ #language fr-FR "Select this question will pop up a message box, then user can decide whether exit curret form or not"
+#string STR_POPUP_STRING #language en-US "Are you sure to exit current form?"
+ #language fr-FR "Are you sure to exit current form?"
+//
+// Form 7 to show Questions which refer to Union Bit varstore
+//
+#string STR_FORM7_TITLE #language en-US "Form to Show Questions with union and bit VarStore"
+ #language fr-FR "Form to Show Questions with union and bit VarStore"
+#string STR_GOTO_FORM7 #language en-US "Enter Page 7"
+ #language fr-FR "Enter Page 7"
+#string STR_GOTO_FORM7_HELP #language en-US "This Form is to Show Questions with union and bit VarStore"
+ #language fr-FR "This Form is to Show Questions with union and bit VarStore"
+#string STR_NEST_BIT_EFI_VARSTORE #language en-US "Nested BIT fields in efivarstore"
+ #language fr-FR "Nested BIT fields in efivarstore"
+#string STR_BIT_EFI_VARSTORE #language en-US "BIT fields in efivarstore"
+ #language fr-FR "BIT fields in efivarstore"
+#string STR_NEST_BIT_VARSTORE #language en-US "Nested BIT fields in bufferstore"
+ #language fr-FR "Nested BIT fields in bufferstore"
+#string STR_BIT_VARSTORE #language en-US "BIT fields in bufferstore"
+ #language fr-FR "BIT fields in bufferstore"
+#string STR_UNION_EFI_VARSTORE #language en-US "Union efivarstore"
+ #language fr-FR "Union efivarstore"
+#string STR_BIT_NEST_CHECK_BOX_PROMPT #language en-US "NEST_BIT check box"
+ #language fr-FR "NEST_BIT check box"
+#string STR_BIT_NEST_CHECK_BOX_HELP #language en-US "The check box refer to nested bit field, the default is checked"
+ #language fr-FR "The check box refer to nested bit field, the default is checked"
+#string STR_ONE_OF_BIT_NEST_PROMPT #language en-US "NEST_BIT one-of"
+ #language fr-FR "NEST_BIT one-of"
+#string STR_ONE_OF_BIT_NEST_HELP #language en-US "The oneof refer to nested bit field"
+ #language fr-FR "The oneof refer to nested bit field"
+#string STR_BIT_NEST_NUMERIC_PROMPT #language en-US "NEST_BIT numeric"
+ #language fr-FR "NEST_BIT numeric"
+#string STR_BIT_NEST_NUMERIC_HELP #language en-US "The numeric refer to nested bit field, the Standard default is 6 Manufacture default is 7"
+ #language fr-FR "The numeric refer to nested bit field, the Standard default is 6 Manufacture default is 7"
+#string BYTE_QUESTION_NEST_BIT_PROMPT #language en-US "Use byte field in NEST_BIT structure"
+ #language fr-FR "Use byte field in NEST_BIT structure"
+#string BYTE_QUESTION_NEST_BIT_HELP #language en-US "The Question refer to byte field in NEST_BIT structure"
+ #language fr-FR "The Question refer to byte field in NEST_BIT structure"
+#string STR_BIT_NEST_NUMERIC_DEFAULT_HELP #language en-US "NEST_BIT numeric, default value form callback function, the Standard default is C Manufacture default is D"
+ #language fr-FR "NEST_BIT numeric, default value form callback function, the Standard default is C Manufacture default is D"
+#string STR_BIT_CHECK_BOX_PROMPT #language en-US "BIT check box"
+ #language fr-FR "BIT check box"
+#string STR_BIT_CHECK_BOX_HELP #language en-US "The check box refer to bit field, the default is checked"
+ #language fr-FR "The check box refer to bit field, the default is checked"
+#string STR_ONE_OF_BIT_PROMPT #language en-US "BIT one-of"
+ #language fr-FR "BIT one-of"
+#string STR_ONE_OF_BIT_HELP #language en-US "The one-of refer to bit field"
+ #language fr-FR "The one-of refer to bit field"
+#string STR_BIT_NUMERIC_PROMPT #language en-US "BIT numeric"
+ #language fr-FR "BIT numeric"
+#string STR_BIT_NUMERIC_HELP #language en-US "The numeric refer to bit field, the Standard default is 4 Manufacture default is 5"
+ #language fr-FR "The numeric refer to bit field the Standard default is 4 Manufacture default is 5"
+#string STR_BUFFER_BIT_NUMERIC_HELP #language en-US "The numeric refer to bit field, the Standard default is 16 Manufacture default is 17"
+ #language fr-FR "The numeric refer to bit field, the Standard default is 16 Manufacture default is 17"
+#string BYTE_QUESTION_BIT_PROMPT #language en-US "Use byte field in BIT structure"
+ #language fr-FR "Use byte field in BIT structure"
+#string BYTE_QUESTION_BIT_HELP #language en-US "The question refer to byte field in BIT structure"
+ #language fr-FR "The question refer to byte field in BIT structure"
+#string STR_UNION_BYTE_NUMERIC_PROMPT #language en-US "UNION EfiVarStore byte numeric"
+ #language fr-FR "UNION EfiVarStore byte numeric"
+#string STR_UNION_BYTE_NUMERIC_HELP #language en-US "Question refer to byte field in UNION type efivastore, the Standard default is 7 Manufacture default is 8"
+ #language fr-FR "Question refer to byte field in UNION type efivastore, the Standard default is 7 Manufacture default is 8"
+// Boot Order
+#string STR_BOOT_TITLE #language en-US "Boot"
+#string STR_BOOT_OPTIONS #language en-US "Boot Order"
+#string STR_BOOT_OPTION1 #language en-US "IDE HDD"
+#string STR_BOOT_OPTION2 #language en-US "ATAPI CD"
+#string STR_BOOT_OPTION3 #language en-US "PXE"
+#string STR_BOOT_OPTION4 #language en-US "USB"
+
+#string STR_VAR_NAME #language en-US "MyVar"
+
+#string STR_DEFAULTSTORE_MFG #language en-US "Manufacture Default"
+ #language fr-FR "Manufacture Default"
+
+#string STR_DEFAULTSTORE_SAFE #language en-US "Safe Default"
+ #language fr-FR "Safe Default"
+
+#string STR_STANDARD_DEFAULT_PROMPT #language en-US "Standard Default"
+ #language fr-FR "Standard Default"
+#string STR_MANUFACTURE_DEFAULT_PROMPT #language en-US "Manufacture Default"
+ #language fr-FR "Manufacture Default"
+
+//
+// Name list of Name/Value storage
+//
+#string STR_NAME_VALUE_VAR_NAME0 #language en-US "NameValueVar0"
+ #language fr-FR "NameValueVar0 (fr-FR)"
+#string STR_NAME_VALUE_VAR_NAME1 #language en-US "NameValueVar1"
+ #language fr-FR "NameValueVar1 (fr-FR)"
+#string STR_NAME_VALUE_VAR_NAME2 #language en-US "NameValueVar2"
+ #language fr-FR "NameValueVar2 (fr-FR)"
+//
+// Form Map method
+//
+#string STR_SAMPL_MAP_METHOD #language en-US "Sample Map Form"
+ #language fr-FR "Sample Map Form"
+#string STR_STANDARD_MAP_METHOD #language en-US "UEFI Standard Map Form"
+ #language fr-FR "UEFI Standard Map Form"
+//
+// Serial Port
+//
+#string STR_SERIAL_PORT #language en-US "Serial port number"
+ #language fr-FR "Serial port number"
+#string STR_SERIAL_PORT_DISABLE #language en-US "Serial port disable"
+ #language fr-FR "Serial port disable"
+#string STR_SERIAL_PORT1 #language en-US "Serial port 1"
+ #language fr-FR "Serial port 1"
+#string STR_SERIAL_PORT2 #language en-US "Serial port 2"
+ #language fr-FR "Serial port 2"
+#string STR_SERIAL_PORT3 #language en-US "Serial port 3"
+ #language fr-FR "Serial port 3"
+#string STR_SERIAL_PORT4 #language en-US "Serial port 4"
+ #language fr-FR "Serial port 4"
+
+#string STR_SERIAL_PORT_STATUS #language en-US "Serial port is enable"
+ #language fr-FR "Serial port is enable"
+#string STR_SERIAL_PORT_IO_ADDRESS #language en-US "Serial port IO address"
+ #language fr-FR "Serial port IO address"
+#string STR_SERIAL_PORT_IRQ #language en-US "Serial port IRQ value"
+ #language fr-FR "Serial port IRQ value"
+
+#string STR_SERIAL_PORT1_IOADDR #language en-US "3F8"
+ #language fr-FR "3F8"
+#string STR_SERIAL_PORT2_IOADDR #language en-US "2F8"
+ #language fr-FR "2F8"
+#string STR_SERIAL_PORT3_IOADDR #language en-US "3E8"
+ #language fr-FR "3E8"
+#string STR_SERIAL_PORT4_IOADDR #language en-US "2E8"
+ #language fr-FR "2E8"
+
+#string STR_SERIAL_PORT13_IRQ #language en-US "4"
+ #language fr-FR "4"
+#string STR_SERIAL_PORT24_IRQ #language en-US "3"
+ #language fr-FR "3"
+
+//
+// TEXT/DATE/TIME
+//
+#string STR_TEXT_SAMPLE_HELP #language en-US "Text Help"
+ #language fr-FR "Text Help"
+#string STR_TEXT_SAMPLE_STRING #language en-US "Text Sample"
+ #language fr-FR "Text Sample"
+#string STR_DATE_SAMPLE_HELP #language en-US "Date Sample"
+ #language fr-FR "Date Sample"
+#string STR_TIME_SAMPLE_HELP #language en-US "Time Sample"
+ #language fr-FR "Time Sample"
+
+#string FUNCTION_NINE_STRING #language en-US "F9=Reset to Defaults"
+ #language fr-FR "F9=Reset à Défauts"
+#string FUNCTION_TEN_STRING #language en-US "F10=Save"
+ #language fr-FR "F10=Économiser"
+#string STR_WARNING_POPUP #language en-US "Change value requires to reset the system."
+ #language fr-FR "Change value requires to reset the system."
+#string STR_MATCH2_PROMPT #language en-US "Match2 Test"
+ #language fr-FR "Match2 Test"
+#string STR_MATCH2_HELP #language en-US "This question used to test the match2 opcode."
+ #language fr-FR "This question used to test the match2 opcode."
+#string STR_STRING #language en-US "Match2 Test"
+ #language fr-FR "Match2 Test"
+#string STR_PATTERN #language en-US "Match2"
+ #language fr-FR "Match2"
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
new file mode 100644
index 000000000..a84d5b330
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
@@ -0,0 +1,156 @@
+///** @file
+//
+// This code provides low level routines that support the Virtual Machine
+// for option ROMs.
+//
+// Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+// Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative)
+ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret)
+ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+
+ASM_GLOBAL ASM_PFX(mEbcInstructionBufferTemplate)
+
+//****************************************************************************
+// EbcLLCALLEX
+//
+// This function is called to execute an EBC CALLEX instruction.
+// This instruction requires that we thunk out to external native
+// code. For AArch64, we copy the VM stack into the main stack and then pop
+// the first 8 arguments off according to the AArch64 Procedure Call Standard
+// On return, we restore the stack pointer to its original location.
+//
+//****************************************************************************
+// UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+ASM_PFX(EbcLLCALLEXNative):
+ mov x8, x0 // Preserve x0
+ mov x9, x1 // Preserve x1
+
+ //
+ // If the EBC stack frame is smaller than or equal to 64 bytes, we know there
+ // are no stacked arguments #9 and beyond that we need to copy to the native
+ // stack. In this case, we can perform a tail call which is much more
+ // efficient, since there is no need to touch the native stack at all.
+ //
+ sub x3, x2, x1 // Length = NewStackPointer - FramePtr
+ cmp x3, #64
+ b.gt 1f
+
+ //
+ // While probably harmless in practice, we should not access the VM stack
+ // outside of the interval [NewStackPointer, FramePtr), which means we
+ // should not blindly fill all 8 argument registers with VM stack data.
+ // So instead, calculate how many argument registers we can fill based on
+ // the size of the VM stack frame, and skip the remaining ones.
+ //
+ adr x0, 0f // Take address of 'br' instruction below
+ bic x3, x3, #7 // Ensure correct alignment
+ sub x0, x0, x3, lsr #1 // Subtract 4 bytes for each arg to unstack
+ br x0 // Skip remaining argument registers
+
+ ldr x7, [x9, #56] // Call with 8 arguments
+ ldr x6, [x9, #48] // |
+ ldr x5, [x9, #40] // |
+ ldr x4, [x9, #32] // |
+ ldr x3, [x9, #24] // |
+ ldr x2, [x9, #16] // |
+ ldr x1, [x9, #8] // V
+ ldr x0, [x9] // Call with 1 argument
+
+0: br x8 // Call with no arguments
+
+ //
+ // More than 64 bytes: we need to build the full native stack frame and copy
+ // the part of the VM stack exceeding 64 bytes (which may contain stacked
+ // arguments) to the native stack
+ //
+1: stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ //
+ // Ensure that the stack pointer remains 16 byte aligned,
+ // even if the size of the VM stack frame is not a multiple of 16
+ //
+ add x1, x1, #64 // Skip over [potential] reg params
+ tbz x3, #3, 2f // Multiple of 16?
+ ldr x4, [x2, #-8]! // No? Then push one word
+ str x4, [sp, #-16]! // ... but use two slots
+ b 3f
+
+2: ldp x4, x5, [x2, #-16]!
+ stp x4, x5, [sp, #-16]!
+3: cmp x2, x1
+ b.gt 2b
+
+ ldp x0, x1, [x9]
+ ldp x2, x3, [x9, #16]
+ ldp x4, x5, [x9, #32]
+ ldp x6, x7, [x9, #48]
+
+ blr x8
+
+ mov sp, x29
+ ldp x29, x30, [sp], #16
+ ret
+
+//****************************************************************************
+// EbcLLEbcInterpret
+//
+// This function is called by the thunk code to handle an Native to EBC call
+// This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack)
+// x16 contains the Entry point that will be the first stacked argument when
+// EBCInterpret is called.
+//
+//****************************************************************************
+ASM_PFX(EbcLLEbcInterpret):
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ // push the entry point and the address of args #9 - #16 onto the stack
+ add x17, sp, #16
+ stp x16, x17, [sp, #-16]!
+
+ // call C-code
+ bl ASM_PFX(EbcInterpret)
+
+ add sp, sp, #16
+ ldp x29, x30, [sp], #16
+ ret
+
+//****************************************************************************
+// EbcLLExecuteEbcImageEntryPoint
+//
+// This function is called by the thunk code to handle the image entry point
+// x16 contains the Entry point that will be the third argument when
+// ExecuteEbcImageEntryPoint is called.
+//
+//****************************************************************************
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ mov x2, x16
+
+ // tail call to C code
+ b ASM_PFX(ExecuteEbcImageEntryPoint)
+
+//****************************************************************************
+// mEbcInstructionBufferTemplate
+//****************************************************************************
+ .section ".rodata", "a"
+ .align 3
+ASM_PFX(mEbcInstructionBufferTemplate):
+ adr x17, 0f
+ ldp x16, x17, [x17]
+ br x17
+
+ //
+ // Add a magic code here to help the VM recognize the thunk.
+ //
+ hlt #0xEBC
+
+0: .quad 0 // EBC_ENTRYPOINT_SIGNATURE
+ .quad 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
new file mode 100644
index 000000000..a9512bd85
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
@@ -0,0 +1,475 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target AArch64 processor.
+
+Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// Amount of space that is not used in the stack
+//
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+#pragma pack(1)
+typedef struct {
+ UINT32 Instr[3];
+ UINT32 Magic;
+ UINT64 EbcEntryPoint;
+ UINT64 EbcLlEntryPoint;
+} EBC_INSTRUCTION_BUFFER;
+#pragma pack()
+
+extern CONST EBC_INSTRUCTION_BUFFER mEbcInstructionBufferTemplate;
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ Pushes a 64 bit unsigned value to the VM stack.
+
+ @param VmPtr The pointer to current VM context.
+ @param Arg The value to be pushed.
+
+**/
+VOID
+PushU64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Arg
+ )
+{
+ //
+ // Advance the VM stack down, and then copy the argument to the stack.
+ // Hope it's aligned.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ *(UINT64 *) VmPtr->Gpr[0] = Arg;
+ return;
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function.
+
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param EntryPoint The entrypoint of EBC code.
+ @param Args9_16[] Array containing arguments #9 to #16.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN EntryPoint,
+ IN CONST UINTN Args9_16[]
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Adjust the VM's stack pointer down.
+ //
+
+ Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Align the stack on a natural boundary.
+ //
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again.
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // The stack upper to LowStackTop is belong to the VM.
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For the worst case, assume there are 4 arguments passed in registers, store
+ // them to VM's stack.
+ //
+ PushU64 (&VmContext, (UINT64) Args9_16[7]);
+ PushU64 (&VmContext, (UINT64) Args9_16[6]);
+ PushU64 (&VmContext, (UINT64) Args9_16[5]);
+ PushU64 (&VmContext, (UINT64) Args9_16[4]);
+ PushU64 (&VmContext, (UINT64) Args9_16[3]);
+ PushU64 (&VmContext, (UINT64) Args9_16[2]);
+ PushU64 (&VmContext, (UINT64) Args9_16[1]);
+ PushU64 (&VmContext, (UINT64) Args9_16[0]);
+ PushU64 (&VmContext, (UINT64) Arg8);
+ PushU64 (&VmContext, (UINT64) Arg7);
+ PushU64 (&VmContext, (UINT64) Arg6);
+ PushU64 (&VmContext, (UINT64) Arg5);
+ PushU64 (&VmContext, (UINT64) Arg4);
+ PushU64 (&VmContext, (UINT64) Arg3);
+ PushU64 (&VmContext, (UINT64) Arg2);
+ PushU64 (&VmContext, (UINT64) Arg1);
+
+ //
+ // Interpreter assumes 64-bit return address is pushed on the stack.
+ // AArch64 does not do this so pad the stack accordingly.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For AArch64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in R[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+ @param EntryPoint The entrypoint of EBC code.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN UINTN EntryPoint
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // Simply copy the image handle and system table onto the EBC stack.
+ // Greatly simplifies things by not having to spill the args.
+ //
+ PushU64 (&VmContext, (UINT64) SystemTable);
+ PushU64 (&VmContext, (UINT64) ImageHandle);
+
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For AArch64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // Entry function needn't access high stack context, simply
+ // put the stack pointer here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in R[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ EBC_INSTRUCTION_BUFFER *InstructionBuffer;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ InstructionBuffer = EbcAllocatePoolForThunk (sizeof (EBC_INSTRUCTION_BUFFER));
+ if (InstructionBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = InstructionBuffer;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+ sizeof (EBC_INSTRUCTION_BUFFER));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ InstructionBuffer->EbcEntryPoint = (UINT64)EbcEntryPoint;
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLEbcInterpret;
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, InstructionBuffer,
+ sizeof (EBC_INSTRUCTION_BUFFER));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ CONST EBC_INSTRUCTION_BUFFER *InstructionBuffer;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ InstructionBuffer = (EBC_INSTRUCTION_BUFFER *)FuncAddr;
+
+ if (CompareMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+ sizeof(EBC_INSTRUCTION_BUFFER) - 2 * sizeof (UINT64)) == 0) {
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ VmPtr->Ip = (VMIP) InstructionBuffer->EbcEntryPoint;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
new file mode 100644
index 000000000..e94231760
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
@@ -0,0 +1,108 @@
+## @file
+# EFI Byte Code (EBC) Debugger.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EbcDebugger
+ MODULE_UNI_FILE = EbcDebugger.uni
+ FILE_GUID = 8296AF37-D183-4416-B3B6-19D2A80AD4A8
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebuggerHook.h
+ EbcInt.c
+ EbcInt.h
+ EbcExecute.c
+ EbcExecute.h
+ EbcDebugger/Edb.c
+ EbcDebugger/Edb.h
+ EbcDebugger/EdbCommon.h
+ EbcDebugger/EdbCmdBranch.c
+ EbcDebugger/EdbCmdBreak.c
+ EbcDebugger/EdbCmdBreakpoint.c
+ EbcDebugger/EdbCmdGo.c
+ EbcDebugger/EdbCmdHelp.c
+ EbcDebugger/EdbCmdMemory.c
+ EbcDebugger/EdbCmdRegister.c
+ EbcDebugger/EdbCmdQuit.c
+ EbcDebugger/EdbCmdScope.c
+ EbcDebugger/EdbCmdStep.c
+ EbcDebugger/EdbCmdSymbol.c
+ EbcDebugger/EdbCmdExtIo.c
+ EbcDebugger/EdbCmdExtPci.c
+ EbcDebugger/EdbCommand.c
+ EbcDebugger/EdbCommand.h
+ EbcDebugger/EdbDisasm.c
+ EbcDebugger/EdbDisasm.h
+ EbcDebugger/EdbDisasmSupport.c
+ EbcDebugger/EdbDisasmSupport.h
+ EbcDebugger/EdbSymbol.c
+ EbcDebugger/EdbSymbol.h
+ EbcDebugger/EdbHook.c
+ EbcDebugger/EdbHook.h
+ EbcDebugger/EdbSupport.h
+ EbcDebugger/EdbSupportUI.c
+ EbcDebugger/EdbSupportString.c
+ EbcDebugger/EdbSupportFile.c
+
+[Sources.Ia32]
+ Ia32/EbcSupport.c
+ Ia32/EbcLowLevel.nasm
+
+[Sources.X64]
+ X64/EbcSupport.c
+ X64/EbcLowLevel.nasm
+
+[Sources.AARCH64]
+ AArch64/EbcSupport.c
+ AArch64/EbcLowLevel.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ BaseLib
+ CacheMaintenanceLib
+ PeCoffLib
+
+[Protocols]
+ gEfiDebugSupportProtocolGuid ## PRODUCES
+ gEfiEbcProtocolGuid ## PRODUCES
+ gEfiDebuggerConfigurationProtocolGuid ## PRODUCES
+ gEfiEbcVmTestProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEbcSimpleDebuggerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciRootBridgeIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDebugImageInfoTableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDebuggerExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni
new file mode 100644
index 000000000..11776211d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni
@@ -0,0 +1,13 @@
+// /** @file
+// EFI Byte Code (EBC) Debugger.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EFI Byte Code (EBC) Debugger application"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application enables the debugging of EBC runtimes."
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c
new file mode 100644
index 000000000..966dfb717
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c
@@ -0,0 +1,247 @@
+/** @file
+ Configuration application for the EBC Debugger.
+
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Protocol/ShellParameters.h>
+
+#include "EdbCommon.h"
+#include "EdbSupport.h"
+
+/**
+
+ The function that displays the utility usage message.
+
+**/
+VOID
+PrintUsage (
+ VOID
+ )
+{
+ Print (
+ L"EbcDebuggerConfig Version 1.0\n"
+ L"Copyright (C) Intel Corp 2007-2016. All rights reserved.\n"
+ L"\n"
+ L"Configure EbcDebugger in EFI Shell Environment.\n"
+ L"\n"
+ L"usage: EdbCfg <Command>\n"
+ L" CommandList:\n"
+ L" BO[C|CX|R|E|T|K] <ON|OFF> - Enable/Disable BOC/BOCX/BOR/BOE/BOT/BOK.\n"
+// L" SHOWINFO - Show Debugger Information.\n"
+ L"\n"
+ );
+ return;
+}
+
+/**
+
+ The function is to show some information.
+
+ @param DebuggerConfiguration Point to the EFI_DEBUGGER_CONFIGURATION_PROTOCOL.
+
+**/
+VOID
+EdbShowInfo (
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration
+ )
+{
+ Print (L"Not supported!\n");
+ return ;
+}
+
+/**
+
+ EdbConfigBreak function.
+
+ @param DebuggerConfiguration Point to the EFI_DEBUGGER_CONFIGURATION_PROTOCOL.
+ @param Command Point to the command.
+ @param CommandArg The argument for this command.
+
+**/
+VOID
+EdbConfigBreak (
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration,
+ CHAR16 *Command,
+ CHAR16 *CommandArg
+ )
+{
+ EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate;
+
+ DebuggerPrivate = (EFI_DEBUGGER_PRIVATE_DATA *)DebuggerConfiguration->DebuggerPrivateData;
+
+ if (StriCmp (Command, L"BOC") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ Print (L"BOC on\n");
+ } else {
+ Print (L"BOC off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOC;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOC;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOCX") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ Print (L"BOCX on\n");
+ } else {
+ Print (L"BOCX off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOCX;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOCX;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOR") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ Print (L"BOR on\n");
+ } else {
+ Print (L"BOR off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOR;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOR;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOE") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ Print (L"BOE on\n");
+ } else {
+ Print (L"BOE off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOE;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOE;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOT") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ Print (L"BOT on\n");
+ } else {
+ Print (L"BOT off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOT;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOT;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOK") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ Print (L"BOK on\n");
+ } else {
+ Print (L"BOK off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOK;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ }
+ return ;
+}
+
+/**
+ Alter the EBC Debugger configuration.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Usage error.
+ @retval EFI_NOT_FOUND A running debugger cannot be located.
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcDebuggerConfig (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Argc;
+ CHAR16 **Argv;
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration;
+ EFI_STATUS Status;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID**)&ShellParameters
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"Please use UEFI Shell to run this application.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Argc = ShellParameters->Argc;
+ Argv = ShellParameters->Argv;
+
+ if (Argc < 2) {
+ PrintUsage ();
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Argc == 2) {
+ if ((StrCmp (Argv[1], L"/?") == 0) ||
+ (StrCmp (Argv[1], L"-?") == 0) ||
+ (StrCmp (Argv[1], L"-h") == 0) ||
+ (StrCmp (Argv[1], L"-H") == 0) ) {
+ PrintUsage ();
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiDebuggerConfigurationProtocolGuid,
+ NULL,
+ (VOID**)&DebuggerConfiguration
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"Error: DebuggerConfiguration protocol not found.\n");
+ return EFI_NOT_FOUND;
+ }
+
+ if (StriCmp (Argv[1], L"SHOWINFO") == 0) {
+ EdbShowInfo (DebuggerConfiguration);
+ return EFI_SUCCESS;
+ }
+
+ if (((Argc == 2) || (Argc == 3)) &&
+ ((StriCmp (Argv[1], L"BOC") == 0) ||
+ (StriCmp (Argv[1], L"BOCX") == 0) ||
+ (StriCmp (Argv[1], L"BOR") == 0) ||
+ (StriCmp (Argv[1], L"BOE") == 0) ||
+ (StriCmp (Argv[1], L"BOT") == 0) ||
+ (StriCmp (Argv[1], L"BOK") == 0))) {
+ if (Argc == 3) {
+ EdbConfigBreak (DebuggerConfiguration, Argv[1], Argv[2]);
+ } else {
+ EdbConfigBreak (DebuggerConfiguration, Argv[1], NULL);
+ }
+ return EFI_SUCCESS;
+ }
+
+ Print (L"Error: Invalid Command.\n");
+ return EFI_INVALID_PARAMETER;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
new file mode 100644
index 000000000..611b2de5d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
@@ -0,0 +1,585 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include "Edb.h"
+
+EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate = {
+ EFI_DEBUGGER_SIGNATURE, // Signature
+ IsaEbc, // Isa
+ (EBC_DEBUGGER_MAJOR_VERSION << 16) |
+ EBC_DEBUGGER_MINOR_VERSION, // EfiDebuggerRevision
+ (VM_MAJOR_VERSION << 16) |
+ VM_MINOR_VERSION, // EbcVmRevision
+ {
+ EFI_DEBUGGER_CONFIGURATION_VERSION,
+ &mDebuggerPrivate,
+ }, // DebuggerConfiguration
+ NULL, // DebugImageInfoTableHeader
+ NULL, // Vol
+ NULL, // PciRootBridgeIo
+ mDebuggerCommandSet, // DebuggerCommandSet
+ {0}, // DebuggerSymbolContext
+ 0, // DebuggerBreakpointCount
+ {{0}}, // DebuggerBreakpointContext
+ 0, // CallStackEntryCount
+ {{0}}, // CallStackEntry
+ 0, // TraceEntryCount
+ {{0}}, // TraceEntry
+ {0}, // StepContext
+ {0}, // GoTilContext
+ 0, // InstructionScope
+ EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER, // InstructionNumber
+ EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT, // FeatureFlags
+ 0, // StatusFlags
+ FALSE, // EnablePageBreak
+ NULL // BreakEvent
+};
+
+CHAR16 *mExceptionStr[] = {
+ L"EXCEPT_EBC_UNDEFINED",
+ L"EXCEPT_EBC_DIVIDE_ERROR",
+ L"EXCEPT_EBC_DEBUG",
+ L"EXCEPT_EBC_BREAKPOINT",
+ L"EXCEPT_EBC_OVERFLOW",
+ L"EXCEPT_EBC_INVALID_OPCODE",
+ L"EXCEPT_EBC_STACK_FAULT",
+ L"EXCEPT_EBC_ALIGNMENT_CHECK",
+ L"EXCEPT_EBC_INSTRUCTION_ENCODING",
+ L"EXCEPT_EBC_BAD_BREAK",
+ L"EXCEPT_EBC_SINGLE_STEP",
+};
+
+/**
+
+ Clear all the breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param NeedRemove Whether need to remove all the breakpoint
+
+**/
+VOID
+EdbClearAllBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN BOOLEAN NeedRemove
+ )
+{
+ UINTN Index;
+
+ //
+ // Patch all the breakpoint
+ //
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
+ &DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction,
+ sizeof(UINT16)
+ );
+ }
+ }
+
+ //
+ // Zero Breakpoint context, if need to remove all breakpoint
+ //
+ if (NeedRemove) {
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ Set all the breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+
+**/
+VOID
+EdbSetAllBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ UINTN Index;
+ UINT16 Data16;
+
+ //
+ // Set all the breakpoint (BREAK(3) : 0x0300)
+ //
+ Data16 = 0x0300;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
+ &Data16,
+ sizeof(UINT16)
+ );
+ }
+ }
+
+ //
+ // Check if current break is caused by breakpoint set.
+ // If so, we need to patch memory back to let user see the real memory.
+ //
+ if (DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress != 0) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress,
+ &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].OldInstruction,
+ sizeof(UINT16)
+ );
+ DebuggerPrivate->StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BP;
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ Check all the breakpoint, if match, then set status flag, and record current breakpoint.
+ Then clear all breakpoint to let user see a clean memory
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EdbCheckBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT64 Address;
+ UINTN Index;
+ BOOLEAN IsHitBreakpoint;
+
+ //
+ // Roll back IP for breakpoint instruction (BREAK(3) : 0x0300)
+ //
+ Address = SystemContext.SystemContextEbc->Ip - sizeof(UINT16);
+
+ //
+ // Check if the breakpoint is hit
+ //
+ IsHitBreakpoint = FALSE;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
+ (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
+ IsHitBreakpoint = TRUE;
+ break;
+ }
+ }
+
+ if (IsHitBreakpoint) {
+ //
+ // If hit, record current breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
+ //
+ // Update: IP and Instruction (NOTE: Since we not allow set breakpoint to BREAK 3, this update is safe)
+ //
+ SystemContext.SystemContextEbc->Ip = Address;
+ //
+ // Set Flags
+ //
+ DebuggerPrivate->StatusFlags |= EFI_DEBUG_FLAG_EBC_BP;
+ } else {
+ //
+ // If not hit, check whether current IP is in breakpoint list,
+ // because STEP will be triggered before execute the instruction.
+ // We should not patch it in de-init.
+ //
+ Address = SystemContext.SystemContextEbc->Ip;
+
+ //
+ // Check if the breakpoint is hit
+ //
+ IsHitBreakpoint = FALSE;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
+ (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
+ IsHitBreakpoint = TRUE;
+ break;
+ }
+ }
+
+ if (IsHitBreakpoint) {
+ //
+ // If hit, record current breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
+ //
+ // Do not set Breakpoint flag. We record the address here just let it not patch breakpoint address when de-init.
+ //
+ } else {
+ //
+ // Zero current breakpoint
+ //
+ ZeroMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX],
+ sizeof(DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX])
+ );
+ }
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+ clear all the symbol.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+
+**/
+VOID
+EdbClearSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ EFI_DEBUGGER_SYMBOL_CONTEXT *DebuggerSymbolContext;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN Index;
+
+ //
+ // Go throuth each object
+ //
+ DebuggerSymbolContext = &DebuggerPrivate->DebuggerSymbolContext;
+ for (ObjectIndex = 0; ObjectIndex < DebuggerSymbolContext->ObjectCount; ObjectIndex++) {
+ Object = &DebuggerSymbolContext->Object[ObjectIndex];
+ //
+ // Go throuth each entry
+ //
+ for (Index = 0; Index < Object->EntryCount; Index++) {
+ ZeroMem (&Object->Entry[Index], sizeof(Object->Entry[Index]));
+ }
+ ZeroMem (Object->Name, sizeof(Object->Name));
+ Object->EntryCount = 0;
+ Object->BaseAddress = 0;
+ Object->StartEntrypointRVA = 0;
+ Object->MainEntrypointRVA = 0;
+ //
+ // Free source buffer
+ //
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ gBS->FreePool (Object->SourceBuffer[Index]);
+ Object->SourceBuffer[Index] = NULL;
+ }
+ }
+ DebuggerSymbolContext->ObjectCount = 0;
+
+ return ;
+}
+
+/**
+
+ Initialize Debugger private data structure
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+EFI_STATUS
+InitDebuggerPrivateData (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ //
+ // clear STEP flag in any condition.
+ //
+ if (SystemContext.SystemContextEbc->Flags & ((UINT64) VMFLAGS_STEP)) {
+ SystemContext.SystemContextEbc->Flags &= ~((UINT64) VMFLAGS_STEP);
+ }
+
+ if (!Initialized) {
+ //
+ // Initialize everything
+ //
+ DebuggerPrivate->InstructionNumber = EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER;
+
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+
+// DebuggerPrivate->StatusFlags = 0;
+
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount = 0;
+ } else {
+ //
+ // Already initialized, just check Breakpoint here.
+ //
+ if (ExceptionType == EXCEPT_EBC_BREAKPOINT) {
+ EdbCheckBreakpoint (DebuggerPrivate, SystemContext);
+ }
+
+ //
+ // Clear all breakpoint
+ //
+ EdbClearAllBreakpoint (DebuggerPrivate, FALSE);
+ }
+
+ //
+ // Set Scope to currentl IP. (Note: Check Breakpoint may change Ip)
+ //
+ DebuggerPrivate->InstructionScope = SystemContext.SystemContextEbc->Ip;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ De-initialize Debugger private data structure.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+EFI_STATUS
+DeinitDebuggerPrivateData (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ if (!Initialized) {
+ //
+ // If it does not want initialized state, de-init everything
+ //
+ DebuggerPrivate->FeatureFlags = EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT;
+ DebuggerPrivate->CallStackEntryCount = 0;
+ DebuggerPrivate->TraceEntryCount = 0;
+ ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
+ ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
+
+ //
+ // Clear all breakpoint
+ //
+ EdbClearAllBreakpoint (DebuggerPrivate, TRUE);
+
+ //
+ // Clear symbol
+ //
+ EdbClearSymbol (DebuggerPrivate);
+ } else {
+ //
+ // If it wants to keep initialized state, just set breakpoint.
+ //
+ EdbSetAllBreakpoint (DebuggerPrivate);
+ }
+
+ //
+ // Clear Step context
+ //
+ ZeroMem (&mDebuggerPrivate.StepContext, sizeof(mDebuggerPrivate.StepContext));
+ DebuggerPrivate->StatusFlags = 0;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Print the reason of current break to EbcDebugger.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+VOID
+PrintExceptionReason (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ //
+ // Print break status
+ //
+ if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_GT) == EFI_DEBUG_FLAG_EBC_GT) {
+ EDBPrint (L"Break on GoTil\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ EDBPrint (L"Break on CALL\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ EDBPrint (L"Break on CALLEX\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ EDBPrint (L"Break on RET\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ EDBPrint (L"Break on Entrypoint\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ EDBPrint (L"Break on Thunk\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER) {
+ EDBPrint (L"Break on StepOver\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT) {
+ EDBPrint (L"Break on StepOut\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BP) == EFI_DEBUG_FLAG_EBC_BP) {
+ EDBPrint (L"Break on Breakpoint\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ EDBPrint (L"Break on Key\n");
+ } else {
+ EDBPrint (L"Exception Type - %x", (UINTN)ExceptionType);
+ if ((ExceptionType >= EXCEPT_EBC_UNDEFINED) && (ExceptionType <= EXCEPT_EBC_STEP)) {
+ EDBPrint (L" (%s)\n", mExceptionStr[ExceptionType]);
+ } else {
+ EDBPrint (L"\n");
+ }
+ }
+
+ return ;
+}
+
+/**
+
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+EdbExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 InputBuffer[EFI_DEBUG_INPUS_BUFFER_SIZE];
+ CHAR16 *CommandArg;
+ EFI_DEBUGGER_COMMAND DebuggerCommand;
+ EFI_DEBUG_STATUS DebugStatus;
+ STATIC BOOLEAN mInitialized;
+
+ mInitialized = FALSE;
+
+ DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n"));
+
+ if (!mInitialized) {
+ //
+ // Print version
+ //
+ EDBPrint (
+ L"EBC Interpreter Version - %d.%d\n",
+ (UINTN)VM_MAJOR_VERSION,
+ (UINTN)VM_MINOR_VERSION
+ );
+ EDBPrint (
+ L"EBC Debugger Version - %d.%d\n",
+ (UINTN)EBC_DEBUGGER_MAJOR_VERSION,
+ (UINTN)EBC_DEBUGGER_MINOR_VERSION
+ );
+ }
+ //
+ // Init Private Data
+ //
+ InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ //
+ // EDBPrint basic info
+ //
+ PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ EdbShowDisasm (&mDebuggerPrivate, SystemContext);
+ // EFI_BREAKPOINT ();
+
+ if (!mInitialized) {
+ //
+ // Interactive with user
+ //
+ EDBPrint (L"\nPlease enter command now, \'h\' for help.\n");
+ EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n");
+ }
+ mInitialized = TRUE;
+
+ //
+ // Dispatch each command
+ //
+ while (TRUE) {
+ //
+ // Get user input
+ //
+ Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE);
+ EDBPrint (L"\n");
+
+ //
+ // Get command
+ //
+ DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg);
+ if (DebuggerCommand == NULL) {
+ EDBPrint (L"ERROR: Command not found!\n");
+ continue;
+ }
+
+ //
+ // Check PageBreak;
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"-b") == 0) {
+ CommandArg = StrGetNextTokenLine (L" ");
+ mDebuggerPrivate.EnablePageBreak = TRUE;
+ }
+ }
+
+ //
+ // Dispatch command
+ //
+ DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext);
+ mDebuggerPrivate.EnablePageBreak = FALSE;
+
+ //
+ // Check command return status
+ //
+ if (DebugStatus == EFI_DEBUG_RETURN) {
+ mInitialized = FALSE;
+ break;
+ } else if (DebugStatus == EFI_DEBUG_BREAK) {
+ break;
+ } else if (DebugStatus == EFI_DEBUG_CONTINUE) {
+ continue;
+ } else {
+ ASSERT (FALSE);
+ }
+ }
+
+ //
+ // Deinit Private Data
+ //
+ DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n"));
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h
new file mode 100644
index 000000000..34253b3a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h
@@ -0,0 +1,60 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_H_
+#define _EFI_EDB_H_
+
+#include "EdbCommon.h"
+
+#define EBC_DEBUGGER_MAJOR_VERSION 1
+#define EBC_DEBUGGER_MINOR_VERSION 0
+
+#define EFI_DEBUG_RETURN 1
+#define EFI_DEBUG_BREAK 2
+#define EFI_DEBUG_CONTINUE 3
+
+/**
+ Driver Entry point.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+**/
+EFI_STATUS
+EfiDebuggerEntrypoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+EdbExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+extern EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate;
+
+#include "EdbSupport.h"
+#include "EdbCommand.h"
+#include "EdbDisasm.h"
+#include "EdbDisasmSupport.h"
+#include "EdbSymbol.h"
+#include "EdbHook.h"
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c
new file mode 100644
index 000000000..500bb41da
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c
@@ -0,0 +1,306 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+CHAR16 *mBranchTypeStr[] = {
+ L"(CALL)",
+ L"(CALLEX)",
+ L"(RET)",
+ L"(JMP)",
+ L"(JMP8)",
+};
+
+/**
+
+ Comvert Branch Type to string.
+
+ @param Type Branch Type
+
+ @retval String string of Branch Type.
+
+**/
+CHAR16 *
+EdbBranchTypeToStr (
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (Type < 0 || Type >= EfiDebuggerBranchTypeEbcMax) {
+ return L"(Unknown Type)";
+ }
+
+ return mBranchTypeStr [Type];
+}
+
+/**
+
+ DebuggerCommand - CallStack.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerCallStack (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ INTN Index;
+ UINTN SubIndex;
+ CHAR8 *FuncName;
+ EFI_DEBUGGER_CALLSTACK_CONTEXT *CallStackEntry;
+ BOOLEAN ShowParameter;
+ UINTN ParameterNumber;
+
+ ShowParameter = FALSE;
+ ParameterNumber = EFI_DEBUGGER_CALL_DEFAULT_PARAMETER;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"c") == 0) {
+ //
+ // Clear Call-Stack
+ //
+ DebuggerPrivate->CallStackEntryCount = 0;
+ ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
+ EDBPrint (L"Call-Stack is cleared\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (StriCmp (CommandArg, L"p") == 0) {
+ //
+ // Print Call-Stack with parameter
+ //
+ ShowParameter = TRUE;
+ CommandArg = StrGetNextTokenLine (L" ");
+ if (CommandArg != NULL) {
+ //
+ // Try to get the parameter number
+ //
+ ParameterNumber = Atoi (CommandArg);
+ if (ParameterNumber > 16) {
+ EDBPrint (L"Call-Stack argument Invalid\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ } else {
+ EDBPrint (L"Call-Stack argument Invalid\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Check CallStack Entry Count
+ //
+ if (DebuggerPrivate->CallStackEntryCount == 0) {
+ EDBPrint (L"No Call-Stack\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ EDBPrint (L"Call-Stack Crash, re-initialize!\n");
+ DebuggerPrivate->CallStackEntryCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each CallStack entry and print
+ //
+ EDBPrint (L"Call-Stack (TOP):\n");
+ EDBPrint (L" Caller Callee Name\n");
+ EDBPrint (L" ================== ================== ========\n");
+//EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 EfiMain\n");
+ for (Index = (INTN)(DebuggerPrivate->CallStackEntryCount - 1); Index >= 0; Index--) {
+ //
+ // Get CallStack and print
+ //
+ CallStackEntry = &DebuggerPrivate->CallStackEntry[Index];
+ EDBPrint (
+ L" 0x%016lx 0x%016lx",
+ CallStackEntry->SourceAddress,
+ CallStackEntry->DestAddress
+ );
+ FuncName = FindSymbolStr ((UINTN)CallStackEntry->DestAddress);
+ if (FuncName != NULL) {
+ EDBPrint (L" %a()", FuncName);
+ }
+ EDBPrint (L"\n");
+
+ if (ShowParameter) {
+ //
+ // Print parameter
+ //
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (
+ L" Parameter Address (0x%016lx) (\n",
+ CallStackEntry->ParameterAddr
+ );
+ if (ParameterNumber == 0) {
+ EDBPrint (L" )\n");
+ continue;
+ }
+ //
+ // Print each parameter
+ //
+ for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) {
+ if (SubIndex % 2 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%016lx, ",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ if (SubIndex % 2 == 1) {
+ EDBPrint (L"\n");
+ }
+ }
+ if (SubIndex % 2 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%016lx\n",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ EDBPrint (L" )\n");
+ //
+ // break only for parameter
+ //
+ if ((((DebuggerPrivate->CallStackEntryCount - Index) % (16 / ParameterNumber)) == 0) &&
+ (Index != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+ } else {
+ EDBPrint (
+ L" Parameter Address (0x%08x) (\n",
+ CallStackEntry->ParameterAddr
+ );
+ if (ParameterNumber == 0) {
+ EDBPrint (L" )\n");
+ continue;
+ }
+ //
+ // Print each parameter
+ //
+ for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) {
+ if (SubIndex % 4 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%08x, ",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ if (SubIndex % 4 == 3) {
+ EDBPrint (L"\n");
+ }
+ }
+ if (SubIndex % 4 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%08x\n",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ EDBPrint (L" )\n");
+ //
+ // break only for parameter
+ //
+ if ((((DebuggerPrivate->CallStackEntryCount - Index) % (32 / ParameterNumber)) == 0) &&
+ (Index != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - InstructionBranch.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerInstructionBranch (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"c") == 0) {
+ //
+ // Clear Trace
+ //
+ DebuggerPrivate->TraceEntryCount = 0;
+ ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
+ EDBPrint (L"Instruction Trace is cleared\n");
+ } else {
+ EDBPrint (L"Trace argument Invalid\n");
+ }
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Check Trace Entry Count
+ //
+ if (DebuggerPrivate->TraceEntryCount == 0) {
+ EDBPrint (L"No Instruction Trace\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
+ EDBPrint (L"Instruction Trace Crash, re-initialize!\n");
+ DebuggerPrivate->TraceEntryCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each Trace entry and print
+ //
+ EDBPrint (L"Instruction Trace (->Latest):\n");
+ EDBPrint (L" Source Addr Destination Addr Type\n");
+ EDBPrint (L" ================== ================== ========\n");
+//EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 (CALLEX)\n");
+ for (Index = 0; Index < DebuggerPrivate->TraceEntryCount; Index++) {
+ EDBPrint (
+ L" 0x%016lx 0x%016lx %s\n",
+ DebuggerPrivate->TraceEntry[Index].SourceAddress,
+ DebuggerPrivate->TraceEntry[Index].DestAddress,
+ EdbBranchTypeToStr (DebuggerPrivate->TraceEntry[Index].Type)
+ );
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c
new file mode 100644
index 000000000..696703c4b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c
@@ -0,0 +1,288 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+
+/**
+
+ DebuggerCommand - BreakOnCALL.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnCALL (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ EDBPrint (L"BOC on\n");
+ } else {
+ EDBPrint (L"BOC off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOC;
+ EDBPrint (L"BOC on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOC;
+ EDBPrint (L"BOC off\n");
+ } else {
+ EDBPrint (L"BOC - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand BreakOnCALLEX.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exceptiont type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnCALLEX (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ EDBPrint (L"BOCX on\n");
+ } else {
+ EDBPrint (L"BOCX off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOCX;
+ EDBPrint (L"BOCX on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOCX;
+ EDBPrint (L"BOCX off\n");
+ } else {
+ EDBPrint (L"BOCX - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnRET.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnRET (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ EDBPrint (L"BOR on\n");
+ } else {
+ EDBPrint (L"BOR off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOR;
+ EDBPrint (L"BOR on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOR;
+ EDBPrint (L"BOR off\n");
+ } else {
+ EDBPrint (L"BOR - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnEntrypoint.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnEntrypoint (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ EDBPrint (L"BOE on\n");
+ } else {
+ EDBPrint (L"BOE off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOE;
+ EDBPrint (L"BOE on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOE;
+ EDBPrint (L"BOE off\n");
+ } else {
+ EDBPrint (L"BOE - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+
+ DebuggerCommand - BreakOnThunk.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnThunk (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ EDBPrint (L"BOT on\n");
+ } else {
+ EDBPrint (L"BOT off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOT;
+ EDBPrint (L"BOT on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOT;
+ EDBPrint (L"BOT off\n");
+ } else {
+ EDBPrint (L"BOT - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnKey.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnKey (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ EDBPrint (L"BOK on\n");
+ } else {
+ EDBPrint (L"BOK off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOK;
+ EDBPrint (L"BOK on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ EDBPrint (L"BOK off\n");
+ } else {
+ EDBPrint (L"BOK - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
new file mode 100644
index 000000000..e0c797be2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
@@ -0,0 +1,542 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check whether current IP is EBC BREAK3 instruction.
+
+ @param Address EBC IP address.
+
+ @retval TRUE Current IP is EBC BREAK3 instruction
+ @retval FALSE Current IP is not EBC BREAK3 instruction
+
+**/
+BOOLEAN
+IsEBCBREAK3 (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_BREAK) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) != 3) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ Check whether the Address is already set in breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Address Breakpoint Address
+
+ @retval TRUE breakpoint is found
+ @retval FALSE breakpoint is not found
+
+**/
+BOOLEAN
+DebuggerBreakpointIsDuplicated (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Address
+ )
+{
+ UINTN Index;
+
+ //
+ // Go through each breakpoint context
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) {
+ //
+ // Found it
+ //
+ return TRUE;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return FALSE;
+}
+
+/**
+
+ Add this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Address Breakpoint Address
+
+ @retval EFI_SUCCESS breakpoint added successfully
+ @retval EFI_ALREADY_STARTED breakpoint is already added
+ @retval EFI_OUT_OF_RESOURCES all the breakpoint entries are used
+
+**/
+EFI_STATUS
+DebuggerBreakpointAdd (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Address
+ )
+{
+ //
+ // Check duplicated breakpoint
+ //
+ if (DebuggerBreakpointIsDuplicated (DebuggerPrivate, Address)) {
+ EDBPrint (L"Breakpoint duplicated!\n");
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Check whether the address is a breakpoint 3 instruction
+ //
+ if (IsEBCBREAK3 (Address)) {
+ EDBPrint (L"Breakpoint can not be set on BREAK 3 instruction!\n");
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (DebuggerPrivate->DebuggerBreakpointCount >= EFI_DEBUGGER_BREAKPOINT_MAX) {
+ EDBPrint (L"Breakpoint out of resource!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].BreakpointAddress = Address;
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].State = TRUE;
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].OldInstruction = 0;
+ CopyMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].OldInstruction,
+ (VOID *)Address,
+ sizeof(UINT16)
+ );
+
+ DebuggerPrivate->DebuggerBreakpointCount ++;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Delete this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Index Breakpoint Index
+
+ @retval EFI_SUCCESS breakpoint deleted successfully
+ @retval EFI_NOT_FOUND breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointDel (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ UINTN BpIndex;
+
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Delete this breakpoint
+ //
+ for (BpIndex = Index; BpIndex < DebuggerPrivate->DebuggerBreakpointCount - 1; BpIndex++) {
+ DebuggerPrivate->DebuggerBreakpointContext[BpIndex] = DebuggerPrivate->DebuggerBreakpointContext[BpIndex + 1];
+ }
+ ZeroMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[BpIndex],
+ sizeof(DebuggerPrivate->DebuggerBreakpointContext[BpIndex])
+ );
+
+ DebuggerPrivate->DebuggerBreakpointCount --;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Disable this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Index Breakpoint Index
+
+ @retval EFI_SUCCESS breakpoint disabled successfully
+ @retval EFI_NOT_FOUND breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointDis (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Disable this breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[Index].State = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Enable this breakpoint.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param Index - Breakpoint Index
+
+ @retval EFI_SUCCESS - breakpoint enabled successfully
+ @retval EFI_NOT_FOUND - breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointEn (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Enable this breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[Index].State = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ DebuggerCommand - BreakpointList.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointList (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // Check breakpoint cound
+ //
+ if (DebuggerPrivate->DebuggerBreakpointCount == 0) {
+ EDBPrint (L"No Breakpoint\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->DebuggerBreakpointCount > EFI_DEBUGGER_BREAKPOINT_MAX) {
+ EDBPrint (L"Breakpoint too many!\n");
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each breakpoint
+ //
+ EDBPrint (L"Breakpoint :\n");
+ EDBPrint (L" Index Address Status\n");
+ EDBPrint (L"======= ================== ========\n");
+//EDBPrint (L" 1 0xFFFFFFFF00000000 *\n");
+//EDBPrint (L" 12 0x00000000FFFFFFFF\n");
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ //
+ // Print the breakpoint
+ //
+ EDBPrint (L" %2d 0x%016lx", Index, DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress);
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ EDBPrint (L" *\n");
+ } else {
+ EDBPrint (L"\n");
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointSet.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointSet (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Address;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointSet Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint address
+ //
+ Status = Symboltoi (CommandArg, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandArg);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Add breakpoint
+ //
+ Status = DebuggerBreakpointAdd (DebuggerPrivate, Address);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointSet error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointClear
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointClear (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointClear Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // delete all breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+ EDBPrint (L"All the Breakpoint is cleared\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointClear Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ EDBPrint (L"BreakpointClear error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Delete breakpoint
+ //
+ Status = DebuggerBreakpointDel (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointClear error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointDisable
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointDisable (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointDisable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // disable all breakpoint
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ Status = DebuggerBreakpointDis (DebuggerPrivate, Index);
+ }
+ EDBPrint (L"All the Breakpoint is disabled\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointDisable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Disable breakpoint
+ //
+ Status = DebuggerBreakpointDis (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointDisable error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+ DebuggerCommand - BreakpointEnable.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointEnable (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointEnable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // enable all breakpoint
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ Status = DebuggerBreakpointEn (DebuggerPrivate, Index);
+ }
+ EDBPrint (L"All the Breakpoint is enabled\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointEnable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Enable breakpoint
+ //
+ Status = DebuggerBreakpointEn (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointEnable error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c
new file mode 100644
index 000000000..d5390d13a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c
@@ -0,0 +1,176 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - IB.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoIB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - IW.
+
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoIW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - ID.
+
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoID (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - OB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - OW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - OD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c
new file mode 100644
index 000000000..93e8b503e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c
@@ -0,0 +1,145 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - PCIL.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciPCIL (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - PCID.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciPCID (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - CFGB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - CFGW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - CFGD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c
new file mode 100644
index 000000000..e5cf857a2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c
@@ -0,0 +1,76 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Go.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_BREAK - formal return value
+ @retval EFI_DEBUG_CONTINUE - something wrong
+
+**/
+EFI_DEBUG_STATUS
+DebuggerGo (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Address;
+ CHAR16 *CommandStr;
+ EFI_STATUS Status;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"til") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr != NULL) {
+ //
+ // Enable GoTil break now
+ // set BreakAddress, and set feature flag.
+ //
+ Status = Symboltoi (CommandStr, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ DebuggerPrivate->GoTilContext.BreakAddress = Address;
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_GT;
+ } else {
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ } else {
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_BREAK;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c
new file mode 100644
index 000000000..74e1befee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c
@@ -0,0 +1,68 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Help.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerHelp (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // if no argument, print all the command title
+ //
+ if (CommandArg == NULL) {
+ for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].ClassName);
+ if (StrCmp (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle, L"") != 0) {
+ EDBPrint (L" ");
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle);
+ }
+ }
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // If there is argument, the argument should be command name.
+ // Find the command and print the detail information.
+ //
+ for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if (StriCmp (CommandArg, DebuggerPrivate->DebuggerCommandSet[Index].CommandName) == 0) {
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandHelp);
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandSyntax);
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Command not found.
+ //
+ EDBPrint (L"No help info for this command\n");
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c
new file mode 100644
index 000000000..42bd8093f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c
@@ -0,0 +1,578 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+
+/**
+
+ Display memory unit.
+
+ @param Address - Memory Address
+ @param Width - Memory Width
+
+ @return Length of the memory unit
+
+**/
+UINTN
+EdbDisplayMemoryUnit (
+ IN UINTN Address,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ UINT8 Data8;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ //
+ // Print according to width
+ //
+ switch (Width) {
+ case EdbWidthUint8:
+ CopyMem (&Data8, (VOID *)Address, sizeof(UINT8));
+ EDBPrint (L"%02x ", Data8);
+ return sizeof(UINT8);
+ case EdbWidthUint16:
+ CopyMem (&Data16, (VOID *)Address, sizeof(UINT16));
+ EDBPrint (L"%04x ", Data16);
+ return sizeof(UINT16);
+ case EdbWidthUint32:
+ CopyMem (&Data32, (VOID *)Address, sizeof(UINT32));
+ EDBPrint (L"%08x ", Data32);
+ return sizeof(UINT32);
+ case EdbWidthUint64:
+ CopyMem (&Data64, (VOID *)Address, sizeof(UINT64));
+ EDBPrint (L"%016lx ", Data64);
+ return sizeof(UINT64);
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // something wrong
+ //
+ return 0;
+}
+
+/**
+
+ Display memory.
+
+ @param Address - Memory Address
+ @param Count - Memory Count
+ @param Width - Memory Width
+
+**/
+VOID
+EdbDisplayMemory (
+ IN UINTN Address,
+ IN UINTN Count,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ UINTN LineNumber;
+ UINTN ByteNumber;
+ UINTN LineIndex;
+ UINTN ByteIndex;
+ UINTN NumberInLine;
+
+ if (Count == 0) {
+ return ;
+ }
+
+ //
+ // Get line number and byte number
+ //
+ switch (Width) {
+ case EdbWidthUint8:
+ NumberInLine = 16;
+ break;
+ case EdbWidthUint16:
+ NumberInLine = 8;
+ break;
+ case EdbWidthUint32:
+ NumberInLine = 4;
+ break;
+ case EdbWidthUint64:
+ NumberInLine = 2;
+ break;
+ default:
+ return;
+ }
+
+ LineNumber = Count / NumberInLine;
+ ByteNumber = Count % NumberInLine;
+ if (ByteNumber == 0) {
+ LineNumber -= 1;
+ ByteNumber = NumberInLine;
+ }
+
+ //
+ // Print each line
+ //
+ for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) {
+
+ //
+ // Break check
+ //
+ if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (LineIndex != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
+ for (ByteIndex = 0; ByteIndex < NumberInLine; ByteIndex++) {
+ Address += EdbDisplayMemoryUnit (Address, Width);
+ }
+ EDBPrint (L"\n");
+ }
+
+ //
+ // Break check
+ //
+ if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (LineIndex != 0)) {
+ if (SetPageBreak ()) {
+ return;
+ }
+ }
+
+ //
+ // Print last line
+ //
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
+ for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) {
+ Address += EdbDisplayMemoryUnit (Address, Width);
+ }
+
+ return ;
+}
+
+/**
+
+ Entry memory.
+
+ @param Address - Memory Address
+ @param Value - Memory Value
+ @param Width - Memory Width
+
+**/
+VOID
+EdbEnterMemory (
+ IN UINTN Address,
+ IN VOID *Value,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ switch (Width) {
+ case EdbWidthUint8:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT8));
+ break;
+ case EdbWidthUint16:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT16));
+ break;
+ case EdbWidthUint32:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT32));
+ break;
+ case EdbWidthUint64:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT64));
+ break;
+ default:
+ break;
+ }
+
+ return ;
+}
+
+/**
+
+ Get memory address and count.
+
+ @param CommandArg - The argument for this command
+ @param Address - Memory Address
+ @param Count - Memory Count
+
+ @retval EFI_SUCCESS - memory address and count are got
+ @retval EFI_INVALID_PARAMETER - something wrong
+
+**/
+EFI_STATUS
+EdbGetMemoryAddressCount (
+ IN CHAR16 *CommandArg,
+ IN UINTN *Address,
+ IN UINTN *Count
+ )
+{
+ CHAR16 *CommandStr;
+ UINTN MemAddress;
+ EFI_STATUS Status;
+
+ //
+ // Get Address
+ //
+ CommandStr = CommandArg;
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Address error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = Symboltoi (CommandStr, &MemAddress);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ MemAddress = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ *Address = MemAddress;
+
+ //
+ // Get Count
+ //
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ *Count = 1;
+ } else {
+ *Count = Xtoi(CommandStr);
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get memory address and value.
+
+ @param CommandArg - The argument for this command
+ @param Address - Memory Address
+ @param Value - Memory Value
+
+ @retval EFI_SUCCESS - memory address and value are got
+ @retval EFI_INVALID_PARAMETER - something wrong
+
+**/
+EFI_STATUS
+EdbGetMemoryAddressValue (
+ IN CHAR16 *CommandArg,
+ IN UINTN *Address,
+ IN UINT64 *Value
+ )
+{
+ CHAR16 *CommandStr;
+ UINTN MemAddress;
+ EFI_STATUS Status;
+
+ //
+ // Get Address
+ //
+ CommandStr = CommandArg;
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Address error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = Symboltoi (CommandStr, &MemAddress);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ MemAddress = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ *Address = MemAddress;
+
+ //
+ // Get Value
+ //
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Value error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *Value = LXtoi(CommandStr);
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Display memory.
+
+ @param CommandArg - The argument for this command
+ @param Width - Memory Width
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDisplay (
+ IN CHAR16 *CommandArg,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINTN Count;
+
+ //
+ // Get memory address and count
+ //
+ Status = EdbGetMemoryAddressCount (CommandArg, &Address, &Count);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Display memory
+ //
+ EdbDisplayMemory (Address, Count, Width);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ Enter memory.
+
+ @param CommandArg - The argument for this command
+ @param Width - Memory Width
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEnter (
+ IN CHAR16 *CommandArg,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINT64 Value;
+
+ //
+ // Get memory address and value
+ //
+ Status = EdbGetMemoryAddressValue (CommandArg, &Address, &Value);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Enter memory
+ //
+ EdbEnterMemory (Address, &Value, Width);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint8);
+}
+
+/**
+
+ DebuggerCommand - DW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint16);
+}
+
+/**
+
+ DebuggerCommand - DD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint32);
+}
+
+/**
+
+ DebuggerCommand - DQ.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDQ (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint64);
+}
+
+/**
+
+ DebuggerCommand - EB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint8);
+}
+
+/**
+
+ DebuggerCommand - EW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint16);
+}
+
+/**
+
+ DebuggerCommand - ED.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryED (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint32);
+}
+
+/**
+
+ DebuggerCommand - EQ.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEQ (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint64);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c
new file mode 100644
index 000000000..76daf8540
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c
@@ -0,0 +1,38 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ EdbCmdQuit.c
+
+Abstract:
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Quit
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerQuit (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return EFI_DEBUG_RETURN;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c
new file mode 100644
index 000000000..2ced0e4dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c
@@ -0,0 +1,118 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Register.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerRegister (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *RegName;
+ CHAR16 *RegValStr;
+ UINT64 RegVal;
+
+ //
+ // Check Argument, NULL means print all register
+ //
+ if (CommandArg == 0) {
+ EDBPrint (
+ L" R0 - 0x%016lx, R1 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R0,
+ SystemContext.SystemContextEbc->R1
+ );
+ EDBPrint (
+ L" R2 - 0x%016lx, R3 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R2,
+ SystemContext.SystemContextEbc->R3
+ );
+ EDBPrint (
+ L" R4 - 0x%016lx, R5 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R4,
+ SystemContext.SystemContextEbc->R5
+ );
+ EDBPrint (
+ L" R6 - 0x%016lx, R7 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R6,
+ SystemContext.SystemContextEbc->R7
+ );
+ EDBPrint (
+ L" Flags - 0x%016lx, ControlFlags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Flags,
+ SystemContext.SystemContextEbc->ControlFlags
+ );
+ EDBPrint (
+ L" Ip - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Ip
+ );
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get register name
+ //
+ RegName = CommandArg;
+ //
+ // Get register value
+ //
+ RegValStr = StrGetNextTokenLine (L" ");
+ if (RegValStr == NULL) {
+ EDBPrint (L"Invalid Register Value\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ RegVal = LXtoi (RegValStr);
+
+ //
+ // Assign register value
+ //
+ if (StriCmp (RegName, L"R0") == 0) {
+ SystemContext.SystemContextEbc->R0 = RegVal;
+ } else if (StriCmp (RegName, L"R1") == 0) {
+ SystemContext.SystemContextEbc->R1 = RegVal;
+ } else if (StriCmp (RegName, L"R2") == 0) {
+ SystemContext.SystemContextEbc->R2 = RegVal;
+ } else if (StriCmp (RegName, L"R3") == 0) {
+ SystemContext.SystemContextEbc->R3 = RegVal;
+ } else if (StriCmp (RegName, L"R4") == 0) {
+ SystemContext.SystemContextEbc->R4 = RegVal;
+ } else if (StriCmp (RegName, L"R5") == 0) {
+ SystemContext.SystemContextEbc->R5 = RegVal;
+ } else if (StriCmp (RegName, L"R6") == 0) {
+ SystemContext.SystemContextEbc->R6 = RegVal;
+ } else if (StriCmp (RegName, L"R7") == 0) {
+ SystemContext.SystemContextEbc->R7 = RegVal;
+ } else if (StriCmp (RegName, L"Flags") == 0) {
+ SystemContext.SystemContextEbc->Flags = RegVal;
+ } else if (StriCmp (RegName, L"ControlFlags") == 0) {
+ SystemContext.SystemContextEbc->ControlFlags = RegVal;
+ } else if (StriCmp (RegName, L"Ip") == 0) {
+ SystemContext.SystemContextEbc->Ip = RegVal;
+ } else {
+ EDBPrint (L"Invalid Register - %s\n", RegName);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c
new file mode 100644
index 000000000..8240ab624
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c
@@ -0,0 +1,99 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Scope.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerScope (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"Scope: invalid Address\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Load new scope
+ //
+ Status = Symboltoi (CommandArg, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandArg);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ DebuggerPrivate->InstructionScope = Address;
+ EDBPrint (L"Scope: 0x%x\n", DebuggerPrivate->InstructionScope);
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - List.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerList (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ //
+ // Load new list number
+ //
+ DebuggerPrivate->InstructionNumber = Atoi(CommandArg);
+ EDBPrint (L"List Number: %d\n", DebuggerPrivate->InstructionNumber);
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c
new file mode 100644
index 000000000..441f53676
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c
@@ -0,0 +1,156 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check whether current IP is EBC CALL instruction (NOTE: CALLEX is exclusive)
+
+ @param Address - EBC IP address.
+
+ @retval TRUE - Current IP is EBC CALL instruction
+ @retval FALSE - Current IP is not EBC CALL instruction
+
+**/
+BOOLEAN
+IsEBCCALL (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_CALL) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) & OPERAND_M_NATIVE_CALL) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ Check whether current IP is EBC RET instruction.
+
+ @param Address - EBC IP address.
+
+ @retval TRUE - Current IP is EBC RET instruction
+ @retval FALSE - Current IP is not EBC RET instruction
+
+**/
+BOOLEAN
+IsEBCRET (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_RET) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ DebuggerCommand - StepInto.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepInto (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+
+ return EFI_DEBUG_BREAK;
+}
+
+/**
+
+ DebuggerCommand - StepOver.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepOver (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (IsEBCCALL((UINTN)SystemContext.SystemContextEbc->Ip)) {
+ //
+ // Check CALL (NOTE: CALLEX is exclusive)
+ //
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_STEPOVER;
+ } else {
+ //
+ // Other instruction including CALLEX
+ //
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+ }
+
+ return EFI_DEBUG_BREAK;
+}
+
+/**
+
+ DebuggerCommand - StepOut.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepOut (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (IsEBCRET((UINTN)SystemContext.SystemContextEbc->Ip)) {
+ //
+ // Check RET
+ //
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+ } else {
+ //
+ // Other instruction
+ //
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_STEPOUT;
+ }
+
+ return EFI_DEBUG_BREAK;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c
new file mode 100644
index 000000000..7b453fa98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c
@@ -0,0 +1,862 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Get file name from full path.
+
+ @param FullPath - full file path
+
+ @return file name
+
+**/
+CHAR16 *
+GetFileNameFromFullPath (
+ IN CHAR16 *FullPath
+ )
+{
+ CHAR16 *FileName;
+ CHAR16 *TempFileName;
+
+ FileName = FullPath;
+ TempFileName = StrGetNewTokenLine (FullPath, L"\\");
+
+ while (TempFileName != NULL) {
+ FileName = TempFileName;
+ TempFileName = StrGetNextTokenLine (L"\\");
+ PatchForStrTokenBefore (TempFileName, L'\\');
+ }
+
+ return FileName;
+}
+
+/**
+
+ Get dir name from full path.
+
+ @param FullPath - full file path
+
+ @return dir name
+
+**/
+CHAR16 *
+GetDirNameFromFullPath (
+ IN CHAR16 *FullPath
+ )
+{
+ CHAR16 *FileName;
+
+ FileName = GetFileNameFromFullPath (FullPath);
+ if (FileName != FullPath) {
+ *(FileName - 1) = 0;
+ return FullPath;
+ }
+
+ return L"";
+}
+
+/**
+
+ Construct full path according to dir and file path.
+
+ @param DirPath - dir path
+ @param FilePath - file path
+ @param Size - dir max size
+
+ @return Full file name
+
+**/
+CHAR16 *
+ConstructFullPath (
+ IN CHAR16 *DirPath,
+ IN CHAR16 *FilePath,
+ IN UINTN Size
+ )
+{
+ UINTN DirPathSize;
+
+ DirPathSize = StrLen(DirPath);
+ *(DirPath + DirPathSize) = L'\\';
+ StrnCatS (DirPath, DirPathSize + Size + 1, FilePath, Size);
+
+ *(DirPath + DirPathSize + Size + 1) = 0;
+
+ return DirPath;
+}
+
+CHAR16 *mSymbolTypeStr[] = {
+ L"( F)",
+ L"(SF)",
+ L"(GV)",
+ L"(SV)",
+};
+
+/**
+
+ Comvert Symbol Type to string.
+
+ @param Type - Symbol Type
+
+ @return String
+
+**/
+CHAR16 *
+EdbSymbolTypeToStr (
+ IN EFI_DEBUGGER_SYMBOL_TYPE Type
+ )
+{
+ if (Type < 0 || Type >= EfiDebuggerSymbolTypeMax) {
+ return L"(?)";
+ }
+
+ return mSymbolTypeStr [Type];
+}
+
+/**
+
+ Find the symbol according to address and display symbol.
+
+ @param Address - SymbolAddress
+ @param DebuggerPrivate - EBC Debugger private data structure
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbolAccrodingToAddress (
+ IN UINTN Address,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ UINTN CandidateAddress;
+
+ //
+ // Find the nearest symbol address
+ //
+ CandidateAddress = EbdFindSymbolAddress (Address, EdbMatchSymbolTypeNearestAddress, &Object, &Entry);
+ if (CandidateAddress == 0 || CandidateAddress == (UINTN) -1 || Entry == NULL) {
+ EDBPrint (L"Symbole at Address not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (Address != CandidateAddress) {
+ EDBPrint (L"Symbole at Address not found, print nearest one!\n");
+ }
+
+ //
+ // Display symbol
+ //
+ EDBPrint (L"Symbol File Name: %s\n", Object->Name);
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ================== ==== ========\n");
+// EDBPrint (L" 0xFFFFFFFF00000000 ( F) TestMain\n");
+ EDBPrint (
+ L" 0x%016lx %s %a\n",
+ (UINT64)Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name
+ );
+ } else {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ========== ==== ========\n");
+// EDBPrint (L" 0xFFFF0000 ( F) TestMain\n");
+ EDBPrint (
+ L" 0x%08x %s %a\n",
+ Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name
+ );
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ Find the symbol according to name and display symbol.
+
+ @param SymbolFileName - The Symbol File Name, NULL means for all
+ @param SymbolName - The Symbol Name, NULL means for all
+ @param DebuggerPrivate - EBC Debugger private data structure
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbolAccrodingToName (
+ IN CHAR16 *SymbolFileName,
+ IN CHAR16 *SymbolName,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount == 0) {
+ EDBPrint (L"No Symbol File!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go throuth each symbol file
+ //
+ Object = DebuggerPrivate->DebuggerSymbolContext.Object;
+ for (Index = 0; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; Index++, Object++) {
+ if ((SymbolFileName != NULL) &&
+ (StriCmp (SymbolFileName, Object->Name) != 0)) {
+ continue;
+ }
+
+ //
+ // Break each symbol file
+ //
+ if (Index != 0) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ EDBPrint (L"Symbol File Name: %s\n", Object->Name);
+ if (Object->EntryCount == 0) {
+ EDBPrint (L"No Symbol!\n");
+ continue;
+ }
+ Entry = Object->Entry;
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ================== ==== ========\n");
+// EDBPrint (L" 0xFFFFFFFF00000000 ( F) TestMain (EbcTest.obj)\n");
+ } else {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ========== ==== ========\n");
+// EDBPrint (L" 0xFFFF0000 ( F) TestMain (EbcTest.obj)\n");
+ }
+
+ //
+ // Go through each symbol name
+ //
+ for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
+ if ((SymbolName != NULL) &&
+ (StrCmpUnicodeAndAscii (SymbolName, Entry->Name) != 0)) {
+ continue;
+ }
+
+ //
+ // Break symbol
+ //
+ if (((SubIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (SubIndex != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (
+ L" 0x%016lx %s %a (%a)\n",
+ (UINT64)Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name,
+ Entry->ObjName
+ );
+ } else {
+ EDBPrint (
+ L" 0x%08x %s %a (%a)\n",
+ Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name,
+ Entry->ObjName
+ );
+ }
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - ListSymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerListSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *SymbolFileName;
+ CHAR16 *SymbolName;
+ CHAR16 *CommandStr;
+ UINTN Address;
+
+ SymbolFileName = NULL;
+ SymbolName = NULL;
+ CommandStr = CommandArg;
+
+ //
+ // display symbol according to address
+ //
+ if (CommandStr != NULL) {
+ if ((StriCmp (CommandStr, L"F") != 0) &&
+ (StriCmp (CommandStr, L"S") != 0)) {
+ Address = Xtoi (CommandStr);
+ return DebuggerDisplaySymbolAccrodingToAddress (Address, DebuggerPrivate);
+ }
+ }
+
+ //
+ // Get SymbolFileName
+ //
+ if (CommandStr != NULL) {
+ if (StriCmp (CommandStr, L"F") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Symbol File Name missing!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else {
+ SymbolFileName = CommandStr;
+ CommandStr = StrGetNextTokenLine (L" ");
+ }
+ }
+ }
+ //
+ // Get SymbolName
+ //
+ if (CommandStr != NULL) {
+ if (StriCmp (CommandStr, L"S") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Symbol Name missing!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else {
+ SymbolName = CommandStr;
+ CommandStr = StrGetNextTokenLine (L" ");
+ }
+ }
+ }
+ if (CommandStr != NULL) {
+ EDBPrint (L"Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // display symbol according to name
+ //
+ return DebuggerDisplaySymbolAccrodingToName (SymbolFileName, SymbolName, DebuggerPrivate);
+}
+
+/**
+
+ DebuggerCommand - LoadSymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerLoadSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_STATUS Status;
+ CHAR16 *FileName;
+ CHAR16 *CommandArg2;
+ BOOLEAN IsLoadCode;
+ CHAR16 *DirName;
+ CHAR16 CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR16 *CodFileName;
+ UINTN Index;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ IsLoadCode = FALSE;
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 != NULL) {
+ if (StriCmp (CommandArg2, L"a") == 0) {
+ IsLoadCode = TRUE;
+ } else {
+ EDBPrint (L"Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ if (StrLen (CommandArg) <= 4) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".map") != 0) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Read MAP file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"SymbolFile read error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ //
+ // Load Symbol
+ //
+ Status = EdbLoadSymbol (DebuggerPrivate, FileName, BufferSize, Buffer);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"LoadSymbol error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+ gBS->FreePool (Buffer);
+
+ //
+ // Patch Symbol for RVA
+ //
+ Status = EdbPatchSymbolRVA (DebuggerPrivate, FileName, EdbEbcImageRvaSearchTypeLast);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"PatchSymbol RVA - %r! Using the RVA in symbol file.\n", Status);
+ } else {
+ DEBUG ((DEBUG_ERROR, "PatchSymbol RVA successfully!\n"));
+ }
+
+ if (!IsLoadCode) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // load each cod file
+ //
+ DirName = GetDirNameFromFullPath (CommandArg);
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ } else {
+ DirName = L"\\";
+ }
+
+ //
+ // Go throuth each file under this dir
+ //
+ Index = 0;
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ while (CodFileName != NULL) {
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"\\") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ }
+
+ //
+ // read cod file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, ConstructFullPath (CodFile, CodFileName, EFI_DEBUGGER_SYMBOL_NAME_MAX - StrLen (CodFile) - 2), &BufferSize, &Buffer, FALSE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"CodeFile read error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Load Code
+ //
+ Status = EdbLoadCode (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"LoadCode error!\n");
+ gBS->FreePool (Buffer);
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Record the buffer
+ //
+ Status = EdbAddCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"AddCodeBuffer error!\n");
+ gBS->FreePool (Buffer);
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Get next file
+ //
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - UnloadSymbol
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerUnloadSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *FileName;
+ CHAR16 *DirName;
+ CHAR16 CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR16 *CodFileName;
+ UINTN Index;
+ VOID *BufferPtr;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+
+ //
+ // Unload Code
+ //
+ DirName = GetDirNameFromFullPath (CommandArg);
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ } else {
+ DirName = L"\\";
+ }
+
+ //
+ // Go through each file under this dir
+ //
+ Index = 0;
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ while (CodFileName != NULL) {
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"\\") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ }
+
+ //
+ // Unload Code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, FileName, CodFileName, &BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"UnloadCode error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Delete the code buffer
+ //
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DeleteCodeBuffer error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Get next file
+ //
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ }
+
+ //
+ // Unload Symbol
+ //
+ Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"UnloadSymbol error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DisplaySymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = !DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = FALSE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ EDBPrint (L"DisplaySymbol - argument error\n");
+ }
+
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - LoadCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerLoadCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_STATUS Status;
+ CHAR16 *CommandArg2;
+ CHAR16 *FileName;
+ CHAR16 *MapFileName;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"CodeFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StrLen (CommandArg) <= 4) {
+ EDBPrint (L"CodeFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".cod") != 0) {
+ EDBPrint (L"CodeFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StrLen (CommandArg2) <= 4) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg2 + (StrLen (CommandArg2) - 4), L".map") != 0) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // read cod file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"CodeFile read error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ MapFileName = GetFileNameFromFullPath (CommandArg2);
+ //
+ // Load Code
+ //
+ Status = EdbLoadCode (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"LoadCode error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Record the buffer
+ //
+ Status = EdbAddCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"AddCodeBuffer error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - UnloadCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerUnloadCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *CommandArg2;
+ CHAR16 *FileName;
+ CHAR16 *MapFileName;
+ EFI_STATUS Status;
+ VOID *BufferPtr;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"CodeFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ MapFileName = GetFileNameFromFullPath (CommandArg2);
+
+ //
+ // Unload Code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"UnloadCode error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Delete Code buffer
+ //
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DeleteCodeBuffer error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DisplayCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplayCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = !DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = TRUE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ EDBPrint (L"DisplayCode - argument error\n");
+ }
+
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c
new file mode 100644
index 000000000..5597a7e15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c
@@ -0,0 +1,656 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+//
+// Debugger Command Table
+//
+EFI_DEBUGGER_COMMAND_SET mDebuggerCommandSet[] = {
+ //
+ // Execution
+ //
+ {
+ L"G",
+ L"G/[F5] - continue to run the program\n",
+ L"The go command is used to cause the debugger to not interrupt execution of the EBC image. The debugger will only break execution of the interpreter if an exception is encountered (including an EBC breakpoint).\n\n",
+ L"G [til <Address|Symbol>]\n"
+ L" (No Argument) - It means continue run the program.\n"
+ L" til - It means continuing run the program till IP is the Address.\n"
+ L" <Address> - The hexical address user want to break at.\n"
+ L" <Symbol> - The symbol name for target address user want to break at. It has following format [MapFileName:]SymbolName\n",
+ L"Execution:\n",
+ {SCAN_F5, CHAR_NULL},
+ DebuggerGo
+ },
+ {
+ L"T",
+ L"T/[F8] - step into\n",
+ L"The step into command will cause the EBC debugger to step a single instruction. If the instruction is a call to internal code (CALL), then the debugger will break at the new function CALL.\n\n",
+ L"T\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F8, CHAR_NULL},
+ DebuggerStepInto
+ },
+ {
+ L"P",
+ L"P/[F10] - step over\n",
+ L"The step over command will cause the EBC debugger to step a single instruction. If the instruction is a call to internal code (CALL), then the external call will be made and the debugger will break at the instruction following the CALL.\n\n",
+ L"P\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F10, CHAR_NULL},
+ DebuggerStepOver
+ },
+ {
+ L"O",
+ L"O/[F11] - step out\n",
+ L"The step out command causes the EBC debugger to step out function calls. The function will be executed, but the debugger will stop after the called function returns.\n\n",
+ L"O\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F11, CHAR_NULL},
+ DebuggerStepOut
+ },
+ {
+ L"Q",
+ L"Q - reset the debugger to default value and go\n",
+ L"The quit command will reset the debugger to default value and go.\n\n",
+ L"Q\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerQuit
+ },
+ //
+ // Break
+ //
+ {
+ L"BOC",
+ L"BO[C|CX|R|E|T|K] - break on CALL/CALLEX/RET/Entrypoint/Native Thunk/Key\n",
+ L"Enabling break-on-call will cause the debugger to halt execution and display the debugger prompt prior to executing any EBC CALL (to EBC) instructions.\n\n",
+ L"BOC [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-call\n"
+ L" off - disable break-on-call\n",
+ L"Break:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnCALL
+ },
+ {
+ L"BOCX",
+ L"",
+ L"Enabling break-on-callex will cause the debugger to halt execution and display the debugger prompt prior to executing EBC CALLEX (thunk out) instructions.\n\n",
+ L"BOCX [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-callex\n"
+ L" off - disable break-on-callex\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnCALLEX
+ },
+ {
+ L"BOR",
+ L"",
+ L"Enabling break-on-return will cause the debugger to halt execution and display the debugger prompt prior to executing EBC RET instructions.\n\n",
+ L"BOR [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-return\n"
+ L" off - disable break-on-return\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnRET
+ },
+ {
+ L"BOE",
+ L"",
+ L"Enabling break-on-entrypoint will cause the debugger to halt execution and display the debugger prompt prior to start a driver entry point. (Default is on)\n\n",
+ L"BOE [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-entrypoint\n"
+ L" off - disable break-on-entrypoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnEntrypoint
+ },
+ {
+ L"BOT",
+ L"",
+ L"Enabling break-on-thunk will cause the debugger to halt execution and display the debugger prompt prior to start native call EBC thunk. (Default is on)\n\n",
+ L"BOT [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-thunk\n"
+ L" off - disable break-on-thunk\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnThunk
+ },
+ {
+ L"BOK",
+ L"",
+ L"Enabling break-on-key will cause the debugger to halt execution and display the debugger prompt after press any key.\n\n",
+ L"BOK [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-key\n"
+ L" off - disable break-on-key\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnKey
+ },
+ {
+ L"BL",
+ L"B[L|P|C|D|E] - breakpoint list/set/clear/disable/enable\n",
+ L"List Breakpoint\n\n",
+ L"BL\n"
+ L" (No Argument) - show the state for current breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointList
+ },
+ {
+ L"BP",
+ L"",
+ L"Set Breakpoint\n\n",
+ L"BP <Address|Symbol>\n"
+ L" <Address> - Hexical breakpoint address\n"
+ L" <Symbol> - Symbol name for breakpoint address. It has following format [MapFileName:]SymbolName.\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointSet
+ },
+ {
+ L"BC",
+ L"",
+ L"Clear Breakpoint\n\n",
+ L"BC <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointClear
+ },
+ {
+ L"BD",
+ L"",
+ L"Disable Breakpoint\n\n",
+ L"BD <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointDisable
+ },
+ {
+ L"BE",
+ L"",
+ L"Enable Breakpoint\n\n",
+ L"BE <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointEnable
+ },
+ //
+ // Information
+ //
+ {
+ L"K",
+ L"K - show/clear call-stack\n",
+ L"The call-stack command will show or clear the current call-stack.\n\n",
+ L"K [p [<ParameterNum>]|c]\n"
+ L" (No Argument) - Show current call-stack\n"
+ L" p - Show current call-stack with parameters\n"
+ L" ParameterNum - Decimal call-stack parameters number, 8 by default, 16 as max\n"
+ L" c - Clear current call-stack\n",
+ L"Information:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerCallStack
+ },
+ {
+ L"TRACE",
+ L"TRACE - show/clear trace instruction branch\n",
+ L"The trace command will show or clear the latest instruction branch.\n\n",
+ L"TRACE [c]\n"
+ L" (No Argument) - Show current instruction branch\n"
+ L" c - Clear current instruction branch\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerInstructionBranch
+ },
+ {
+ L"R",
+ L"R/[F2] - display/modify register\n",
+ L"The register command is used to display or modify the contents of EBC VM registers. (R0~R7, Flags, IP)\n\n",
+ L"R [<Register> <Value>]\n"
+ L" (No Argument) - Display all registers\n"
+ L" <Register> - EBC VM register name (R0~R7, Flags, ControlFlags, and IP\n"
+ L" <Value> - The Hexical value of register\n",
+ L"",
+ {SCAN_F2, CHAR_NULL},
+ DebuggerRegister
+ },
+ {
+ L"L",
+ L"L/[F4] - show/load instruction assembly count\n",
+ L"The list assembly command will disassemble instructions starting with the current EBC VM instruction pointer. (by default 5 instructions)\n\n",
+ L"L [<Count>]\n"
+ L" (No Argument) - List current assembly code\n"
+ L" Count - The decimal instruction assembly count\n",
+ L"",
+ {SCAN_F4, CHAR_NULL},
+ DebuggerList
+ },
+ {
+ L"SCOPE",
+ L"SCOPE - load scope address\n",
+ L"The scope command will disassemble instructions starting with the Scope. (by default current EBC VM IP)\n\n",
+ L"SCOPE <Address|Symbol>\n"
+ L" <Address> - The Hexical address where user wants to see the assembly code\n"
+ L" <Symbol> - Symbol name for scope address. It has following format [MapFileName:]SymbolName.\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerScope
+ },
+ {
+ L"DB",
+ L"[D|E][B|W|D|Q] - display/modify memory\n",
+ L"Display BYTES Memory\n\n",
+ L"DB <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDB
+ },
+ {
+ L"DW",
+ L"",
+ L"Display WORDS Memory\n\n",
+ L"DW <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDW
+ },
+ {
+ L"DD",
+ L"",
+ L"Display DWORDS Memory\n\n",
+ L"DD <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDD
+ },
+ {
+ L"DQ",
+ L"",
+ L"Display QWORDS Memory\n\n",
+ L"DQ <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDQ
+ },
+ {
+ L"EB",
+ L"",
+ L"Enter BYTES Memory\n\n",
+ L"EB <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEB
+ },
+ {
+ L"EW",
+ L"",
+ L"Enter WORDS Memory\n\n",
+ L"EW <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEW
+ },
+ {
+ L"ED",
+ L"",
+ L"Enter DWORDS Memory\n\n",
+ L"ED <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryED
+ },
+ {
+ L"EQ",
+ L"",
+ L"Enter QWORDS Memory\n\n",
+ L"EQ <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEQ
+ },
+ //
+ // Symbol
+ //
+ {
+ L"LN",
+ L"LN - list the symbol\n",
+ L"The show symbol command will list all the current symbol. It can list the symbol in one symbol file, or list the same symbol in all the files. It can also list the symbol according to nearest address.\n\n",
+ L"LN [[F <SymbolFile>] [S <Symbol>]] | <Address>\n"
+ L" (No Argument) - List all the symbol\n"
+ L" F <SymbolFile> - List the symbol in this symbol file only\n"
+ L" S <Symbol> - List this symbol only\n"
+ L" <Address> - The hexical memory address, which user want to find the symbol for.\n",
+ L"Symbol:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerListSymbol
+ },
+ {
+ L"LOADSYMBOL",
+ L"[UN]LOADSYMBOL - load/unload the symbol file\n",
+ L"The load symbol command will load the ebc map file. Then it parses the function name and global variable, and the print real name when do the disassembly. (Symbol file name should be XXX.MAP)\n\n",
+ L"LOADSYMBOL <SymbolFile> [a]\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n"
+ L" a - Automatically load code files in the same dir\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerLoadSymbol
+ },
+ {
+ L"UNLOADSYMBOL",
+ L"",
+ L"The unload symbol command will unload the ebc map and cod file. After that the name will not be print.\n\n",
+ L"UNLOADSYMBOL <SymbolFile>\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerUnloadSymbol
+ },
+ {
+ L"LOADCODE",
+ L"[UN]LOADCODE - load/unload the code file\n",
+ L"The load code command will load the ebc cod file. Then it parses the cod file, and the print source code when do the disassembly. (Code file name should be XXX.COD)\n\n",
+ L"LOADCODE <CodeFile> <SymbolFile>\n"
+ L" CodeFile - The EBC code file (Its name should be XXX.COD)\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerLoadCode
+ },
+ {
+ L"UNLOADCODE",
+ L"",
+ L"The unload code command will unload the ebc cod file. After that the source code will not be print.\n\n",
+ L"UNLOADCODE <CodeFile> <SymbolFile>\n"
+ L" CodeFile - The EBC code file (Its name should be XXX.COD)\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerUnloadCode
+ },
+ {
+ L"DISPLAYSYMBOL",
+ L"DISPLAYSYMBOL/[F3] - disable/enable the symbol output\n",
+ L"",
+ L"The display symbol command will configure the symbol show or not-show when disassembly.\n\n"
+ L"DISPLAYSYMBOL [on|off]\n"
+ L" (No Argument) - swtich symbol output state to another one\n"
+ L" on - enable symbol output\n"
+ L" off - disable symbol output\n",
+ L"",
+ {SCAN_F3, CHAR_NULL},
+ DebuggerDisplaySymbol
+ },
+ {
+ L"DISPLAYCODE",
+ L"DISPLAYCODE/[F6] - disable/enable the source code only output\n",
+ L"",
+ L"The display code command will configure the source code only show or misc source code with assembly.\n\n"
+ L"DISPLAYCODE [on|off]\n"
+ L" (No Argument) - swtich source only output state to another one\n"
+ L" on - enable source only output\n"
+ L" off - disable source only output\n",
+ L"",
+ {SCAN_F6, CHAR_NULL},
+ DebuggerDisplayCode
+ },
+ //
+ // Other
+ //
+ {
+ L"H",
+ L"",
+ L"The help command will print help information for each command\n\n",
+ L"H [<Command>]\n",
+ L"",
+ {SCAN_F1, CHAR_NULL},
+ DebuggerHelp
+ },
+/*
+ //
+ // Extended
+ //
+ {
+ L"!IB",
+ L"![I|O][B|W|D] - display/modify IO\n",
+ L"",
+ L"!IB <Address>\n",
+ L"Extended:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoIB
+ },
+ {
+ L"!IW",
+ L"",
+ L"",
+ L"!IW <Address>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoIW
+ },
+ {
+ L"!ID",
+ L"",
+ L"",
+ L"!ID <Address>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoID
+ },
+ {
+ L"!OB",
+ L"",
+ L"",
+ L"!OB <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOB
+ },
+ {
+ L"!OW",
+ L"",
+ L"",
+ L"!OW <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOW
+ },
+ {
+ L"!OD",
+ L"",
+ L"",
+ L"!OD <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOD
+ },
+ {
+ L"!PCIL",
+ L"!PCIL - list PCI device, with BAR\n",
+ L"",
+ L"!PCIL [B]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciPCIL
+ },
+ {
+ L"!PCID",
+ L"!PCID - show PCI space\n",
+ L"",
+ L"!PCID Bus Device Function [H|B|E]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciPCID
+ },
+ {
+ L"!CFGB",
+ L"!CFG[B|W|D] - show/modify PCI space",
+ L"",
+ L"!CFGB <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGB
+ },
+ {
+ L"!CFGW",
+ L"",
+ L"",
+ L"!CFGW <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGW
+ },
+ {
+ L"!CFGD",
+ L"",
+ L"",
+ L"!CFGD <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGD
+ },
+*/
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ {SCAN_NULL, CHAR_NULL},
+ NULL
+ },
+};
+
+/**
+
+ Find the command according to name.
+
+ @param CommandName - Command Name
+ @param CommandArg - Command Argument
+
+ @return Not NULL - The DebuggerCommand is found successfully
+ @return NULL - not found
+
+**/
+EFI_DEBUGGER_COMMAND
+MatchDebuggerCommand (
+ IN CHAR16 *CommandName,
+ IN CHAR16 **CommandArg
+ )
+{
+ UINTN Index;
+ CHAR16 *Temp;
+
+ //
+ // Get Command Name
+ //
+ Temp = StrGetNewTokenLine (CommandName, L" ");
+ CommandName = Temp;
+ //
+ // Get Command Argument
+ //
+ Temp = StrGetNextTokenLine (L" ");
+ *CommandArg = Temp;
+
+ if (CommandName == NULL) {
+ return NULL;
+ }
+
+ //
+ // Go through each command, check the CommandName
+ //
+ for (Index = 0; mDebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if (StriCmp (CommandName, mDebuggerCommandSet[Index].CommandName) == 0) {
+ //
+ // Found
+ //
+ return mDebuggerCommandSet[Index].CommandFunc;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
+
+/**
+
+ Find the command name according to the function key.
+
+ @param CommandKey - Command Function Key
+
+ @return Not NULL - The DebuggerName is found successfully
+ @return NULL - not found
+
+**/
+CHAR16 *
+GetCommandNameByKey (
+ IN EFI_INPUT_KEY CommandKey
+ )
+{
+ UINTN Index;
+
+ //
+ // Go through each command, check the CommandKey
+ //
+ for (Index = 0; mDebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if ((mDebuggerCommandSet[Index].CommandKey.UnicodeChar == CommandKey.UnicodeChar) &&
+ (mDebuggerCommandSet[Index].CommandKey.ScanCode == CommandKey.ScanCode)) {
+ //
+ // Found
+ //
+ return mDebuggerCommandSet[Index].CommandName;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h
new file mode 100644
index 000000000..ac8c23adf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h
@@ -0,0 +1,115 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_COMMAND_H_
+#define _EFI_EDB_COMMAND_H_
+
+typedef enum {
+ EdbWidthUint8,
+ EdbWidthUint16,
+ EdbWidthUint32,
+ EdbWidthUint64,
+ EdbWidthMax
+} EDB_DATA_WIDTH;
+
+/**
+
+ Find the command according to name.
+
+ @param CommandName - Command Name
+ @param CommandArg - Command Argument
+
+ @return Not NULL - The DebuggerCommand is found successfully
+ @return NULL - not found
+
+**/
+EFI_DEBUGGER_COMMAND
+MatchDebuggerCommand (
+ IN CHAR16 *CommandName,
+ IN CHAR16 **CommandArg
+ );
+
+/**
+
+ Find the command name according to the function key.
+
+ @param CommandKey - Command Function Key
+
+ @return Not NULL - The DebuggerName is found successfully
+ @return NULL - not found
+
+**/
+CHAR16 *
+GetCommandNameByKey (
+ IN EFI_INPUT_KEY CommandKey
+ );
+
+//
+// Definition for Command Table
+//
+#define EDB_COMMAND_DEFINE(func) \
+EFI_DEBUG_STATUS \
+func ( \
+ IN CHAR16 *CommandArg, \
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, \
+ IN EFI_EXCEPTION_TYPE ExceptionType, \
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext \
+ )
+
+EDB_COMMAND_DEFINE (DebuggerCallStack);
+EDB_COMMAND_DEFINE (DebuggerInstructionBranch);
+EDB_COMMAND_DEFINE (DebuggerBreakOnCALL);
+EDB_COMMAND_DEFINE (DebuggerBreakOnCALLEX);
+EDB_COMMAND_DEFINE (DebuggerBreakOnRET);
+EDB_COMMAND_DEFINE (DebuggerBreakOnEntrypoint);
+EDB_COMMAND_DEFINE (DebuggerBreakOnThunk);
+EDB_COMMAND_DEFINE (DebuggerBreakOnKey);
+EDB_COMMAND_DEFINE (DebuggerBreakpointList);
+EDB_COMMAND_DEFINE (DebuggerBreakpointSet);
+EDB_COMMAND_DEFINE (DebuggerBreakpointClear);
+EDB_COMMAND_DEFINE (DebuggerBreakpointDisable);
+EDB_COMMAND_DEFINE (DebuggerBreakpointEnable);
+EDB_COMMAND_DEFINE (DebuggerGo);
+EDB_COMMAND_DEFINE (DebuggerHelp);
+EDB_COMMAND_DEFINE (DebuggerMemoryDB);
+EDB_COMMAND_DEFINE (DebuggerMemoryDW);
+EDB_COMMAND_DEFINE (DebuggerMemoryDD);
+EDB_COMMAND_DEFINE (DebuggerMemoryDQ);
+EDB_COMMAND_DEFINE (DebuggerMemoryEB);
+EDB_COMMAND_DEFINE (DebuggerMemoryEW);
+EDB_COMMAND_DEFINE (DebuggerMemoryED);
+EDB_COMMAND_DEFINE (DebuggerMemoryEQ);
+EDB_COMMAND_DEFINE (DebuggerQuit);
+EDB_COMMAND_DEFINE (DebuggerRegister);
+EDB_COMMAND_DEFINE (DebuggerScope);
+EDB_COMMAND_DEFINE (DebuggerList);
+EDB_COMMAND_DEFINE (DebuggerStepInto);
+EDB_COMMAND_DEFINE (DebuggerStepOver);
+EDB_COMMAND_DEFINE (DebuggerStepOut);
+EDB_COMMAND_DEFINE (DebuggerListSymbol);
+EDB_COMMAND_DEFINE (DebuggerLoadSymbol);
+EDB_COMMAND_DEFINE (DebuggerUnloadSymbol);
+EDB_COMMAND_DEFINE (DebuggerDisplaySymbol);
+EDB_COMMAND_DEFINE (DebuggerLoadCode);
+EDB_COMMAND_DEFINE (DebuggerUnloadCode);
+EDB_COMMAND_DEFINE (DebuggerDisplayCode);
+EDB_COMMAND_DEFINE (DebuggerExtIoIB);
+EDB_COMMAND_DEFINE (DebuggerExtIoIW);
+EDB_COMMAND_DEFINE (DebuggerExtIoID);
+EDB_COMMAND_DEFINE (DebuggerExtIoOB);
+EDB_COMMAND_DEFINE (DebuggerExtIoOW);
+EDB_COMMAND_DEFINE (DebuggerExtIoOD);
+EDB_COMMAND_DEFINE (DebuggerExtPciPCIL);
+EDB_COMMAND_DEFINE (DebuggerExtPciPCID);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGB);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGW);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGD);
+
+extern EFI_DEBUGGER_COMMAND_SET mDebuggerCommandSet[];
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h
new file mode 100644
index 000000000..924a2f755
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h
@@ -0,0 +1,239 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EDB_COMMON_H_
+#define _EFI_EDB_COMMON_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Ebc.h>
+#include <Protocol/EbcVmTest.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DebuggerConfiguration.h>
+#include <Guid/FileInfo.h>
+#include <Guid/DebugImageInfoTable.h>
+
+typedef UINTN EFI_DEBUG_STATUS;
+
+typedef struct _EFI_DEBUGGER_PRIVATE_DATA EFI_DEBUGGER_PRIVATE_DATA;
+
+//
+// Definition for Debugger Command
+//
+typedef
+EFI_DEBUG_STATUS
+(* EFI_DEBUGGER_COMMAND) (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+);
+
+typedef struct {
+ CHAR16 *CommandName;
+ CHAR16 *CommandTitle;
+ CHAR16 *CommandHelp;
+ CHAR16 *CommandSyntax;
+ CHAR16 *ClassName;
+ EFI_INPUT_KEY CommandKey;
+ EFI_DEBUGGER_COMMAND CommandFunc;
+} EFI_DEBUGGER_COMMAND_SET;
+
+//
+// Definition for Debugger Symbol
+//
+#define EFI_DEBUGGER_SYMBOL_NAME_MAX 256
+#define EFI_DEBUGGER_SYMBOL_ENTRY_MAX 512
+#define EFI_DEBUGGER_SYMBOL_OBJECT_MAX 32
+
+//
+// We have following SYMBOL data structure:
+//
+// SYMBOL_CONTEXT -> SYMBOL_OBJECT -> SYMBOL_ENTRY (FuncXXX, 0xXXX)
+// SYMBOL_ENTRY (VarYYY, 0xYYY)
+// SYMBOL_ENTRY
+//
+// SYMBOL_OBJECT -> SYMBOL_ENTRY
+// SYMBOL_ENTRY
+//
+// SYMBOL_OBJECT -> SYMBOL_ENTRY
+// SYMBOL_ENTRY
+//
+
+typedef enum {
+ EfiDebuggerSymbolFunction,
+ EfiDebuggerSymbolStaticFunction,
+ EfiDebuggerSymbolGlobalVariable,
+ EfiDebuggerSymbolStaticVariable,
+ EfiDebuggerSymbolTypeMax,
+} EFI_DEBUGGER_SYMBOL_TYPE;
+
+typedef struct {
+ CHAR8 Name[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ UINTN Rva;
+ EFI_DEBUGGER_SYMBOL_TYPE Type;
+ CHAR8 ObjName[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR8 *CodBuffer;
+ UINTN CodBufferSize;
+ UINTN FuncOffsetBase;
+ CHAR8 *SourceBuffer;
+} EFI_DEBUGGER_SYMBOL_ENTRY;
+
+typedef struct {
+ CHAR16 Name[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ UINTN EntryCount;
+ UINTN MaxEntryCount;
+ UINTN BaseAddress;
+ UINTN StartEntrypointRVA;
+ UINTN MainEntrypointRVA;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ VOID **SourceBuffer;
+} EFI_DEBUGGER_SYMBOL_OBJECT;
+
+typedef struct {
+ UINTN ObjectCount;
+ UINTN MaxObjectCount;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ BOOLEAN DisplaySymbol;
+ BOOLEAN DisplayCodeOnly;
+} EFI_DEBUGGER_SYMBOL_CONTEXT;
+
+//
+// Definition for Debugger Breakpoint
+//
+#define EFI_DEBUGGER_BREAKPOINT_MAX 0x10
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakpointAddress;
+ UINT64 OldInstruction; // UINT64 is enough for an instruction
+ BOOLEAN State;
+} EFI_DEBUGGER_BREAKPOINT_CONTEXT;
+
+//
+// Definition for Debugger Call-Stack
+//
+#define EFI_DEBUGGER_CALLSTACK_MAX 0x10
+
+typedef enum {
+ EfiDebuggerBranchTypeEbcCall,
+ EfiDebuggerBranchTypeEbcCallEx,
+ EfiDebuggerBranchTypeEbcRet,
+ EfiDebuggerBranchTypeEbcJmp,
+ EfiDebuggerBranchTypeEbcJmp8,
+ EfiDebuggerBranchTypeEbcMax,
+} EFI_DEBUGGER_BRANCH_TYPE;
+
+#define EFI_DEBUGGER_CALL_MAX_PARAMETER 0x16
+#define EFI_DEBUGGER_CALL_DEFAULT_PARAMETER 0x8
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS SourceAddress;
+ EFI_PHYSICAL_ADDRESS DestAddress;
+ //
+ // We save all parameter here, because code may update the parameter as local variable.
+ //
+ UINTN ParameterAddr;
+ UINTN Parameter[EFI_DEBUGGER_CALL_MAX_PARAMETER];
+ EFI_DEBUGGER_BRANCH_TYPE Type;
+} EFI_DEBUGGER_CALLSTACK_CONTEXT;
+
+//
+// Definition for Debugger Trace
+//
+#define EFI_DEBUGGER_TRACE_MAX 0x10
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS SourceAddress;
+ EFI_PHYSICAL_ADDRESS DestAddress;
+ EFI_DEBUGGER_BRANCH_TYPE Type;
+} EFI_DEBUGGER_TRACE_CONTEXT;
+
+//
+// Definition for Debugger Step
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakAddress;
+ EFI_PHYSICAL_ADDRESS FramePointer;
+} EFI_DEBUGGER_STEP_CONTEXT;
+
+//
+// Definition for Debugger GoTil
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakAddress;
+} EFI_DEBUGGER_GOTIL_CONTEXT;
+
+//
+// Definition for Debugger private data structure
+//
+#define EFI_DEBUGGER_SIGNATURE SIGNATURE_32 ('e', 'd', 'b', '!')
+
+#define EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER 5
+
+#define EFI_DEBUG_BREAK_TIMER_INTERVAL 10000000 // 1 second
+
+#define EFI_DEBUG_FLAG_EBC 0x80000000
+#define EFI_DEBUG_FLAG_EBC_B_BOC 0x1
+#define EFI_DEBUG_FLAG_EBC_B_BOCX 0x2
+#define EFI_DEBUG_FLAG_EBC_B_BOR 0x4
+#define EFI_DEBUG_FLAG_EBC_B_BOE 0x8
+#define EFI_DEBUG_FLAG_EBC_B_BOT 0x10
+#define EFI_DEBUG_FLAG_EBC_B_STEPOVER 0x20
+#define EFI_DEBUG_FLAG_EBC_B_STEPOUT 0x40
+#define EFI_DEBUG_FLAG_EBC_B_BP 0x80
+#define EFI_DEBUG_FLAG_EBC_B_GT 0x100
+#define EFI_DEBUG_FLAG_EBC_B_BOK 0x200
+#define EFI_DEBUG_FLAG_EBC_BOC (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOC)
+#define EFI_DEBUG_FLAG_EBC_BOCX (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOCX)
+#define EFI_DEBUG_FLAG_EBC_BOR (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOR)
+#define EFI_DEBUG_FLAG_EBC_BOE (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOE)
+#define EFI_DEBUG_FLAG_EBC_BOT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOT)
+#define EFI_DEBUG_FLAG_EBC_STEPOVER (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_STEPOVER)
+#define EFI_DEBUG_FLAG_EBC_STEPOUT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_STEPOUT)
+#define EFI_DEBUG_FLAG_EBC_BP (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BP)
+#define EFI_DEBUG_FLAG_EBC_GT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_GT)
+#define EFI_DEBUG_FLAG_EBC_BOK (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOK)
+
+//
+// Debugger private data structure
+//
+typedef struct _EFI_DEBUGGER_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_INSTRUCTION_SET_ARCHITECTURE Isa;
+ UINT32 EfiDebuggerRevision;
+ UINT32 EbcVmRevision;
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL DebuggerConfiguration;
+ EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageInfoTableHeader;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_DEBUGGER_COMMAND_SET *DebuggerCommandSet;
+ EFI_DEBUGGER_SYMBOL_CONTEXT DebuggerSymbolContext;
+ UINTN DebuggerBreakpointCount;
+ EFI_DEBUGGER_BREAKPOINT_CONTEXT DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX + 1];
+ UINTN CallStackEntryCount;
+ EFI_DEBUGGER_CALLSTACK_CONTEXT CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX + 1];
+ UINTN TraceEntryCount;
+ EFI_DEBUGGER_TRACE_CONTEXT TraceEntry[EFI_DEBUGGER_TRACE_MAX + 1];
+ EFI_DEBUGGER_STEP_CONTEXT StepContext;
+ EFI_DEBUGGER_GOTIL_CONTEXT GoTilContext;
+ EFI_PHYSICAL_ADDRESS InstructionScope;
+ UINTN InstructionNumber;
+ UINT32 FeatureFlags;
+ UINT32 StatusFlags;
+ BOOLEAN EnablePageBreak;
+ EFI_EVENT BreakEvent;
+} EFI_DEBUGGER_PRIVATE_DATA;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c
new file mode 100644
index 000000000..7d933cae7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c
@@ -0,0 +1,1770 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+//
+// Debugger Disasm definition
+//
+#define EDB_DISASM_DEFINE(func) \
+UINTN \
+func ( \
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress, \
+ IN EFI_SYSTEM_CONTEXT SystemContext, \
+ OUT CHAR16 **DisasmString \
+ )
+
+EDB_DISASM_DEFINE (EdbDisasmBREAK);
+EDB_DISASM_DEFINE (EdbDisasmJMP);
+EDB_DISASM_DEFINE (EdbDisasmJMP8);
+EDB_DISASM_DEFINE (EdbDisasmCALL);
+EDB_DISASM_DEFINE (EdbDisasmRET);
+EDB_DISASM_DEFINE (EdbDisasmCMP);
+EDB_DISASM_DEFINE (EdbDisasmUnsignedDataManip);
+EDB_DISASM_DEFINE (EdbDisasmSignedDataManip);
+EDB_DISASM_DEFINE (EdbDisasmMOVxx);
+EDB_DISASM_DEFINE (EdbDisasmMOVsnw);
+EDB_DISASM_DEFINE (EdbDisasmMOVsnd);
+EDB_DISASM_DEFINE (EdbDisasmLOADSP);
+EDB_DISASM_DEFINE (EdbDisasmSTORESP);
+EDB_DISASM_DEFINE (EdbDisasmPUSH);
+EDB_DISASM_DEFINE (EdbDisasmPOP);
+EDB_DISASM_DEFINE (EdbDisasmCMPI);
+EDB_DISASM_DEFINE (EdbDisasmPUSHn);
+EDB_DISASM_DEFINE (EdbDisasmPOPn);
+EDB_DISASM_DEFINE (EdbDisasmMOVI);
+EDB_DISASM_DEFINE (EdbDisasmMOVIn);
+EDB_DISASM_DEFINE (EdbDisasmMOVREL);
+
+//
+// Debugger Disasm Table
+//
+EDB_DISASM_INSTRUCTION mEdbDisasmInstructionTable[] = {
+ EdbDisasmBREAK, // opcode 0x00 BREAK
+ EdbDisasmJMP, // opcode 0x01 JMP
+ EdbDisasmJMP8, // opcode 0x02 JMP8
+ EdbDisasmCALL, // opcode 0x03 CALL
+ EdbDisasmRET, // opcode 0x04 RET
+ EdbDisasmCMP, // opcode 0x05 CMPEQ
+ EdbDisasmCMP, // opcode 0x06 CMPLTE
+ EdbDisasmCMP, // opcode 0x07 CMPGTE
+ EdbDisasmCMP, // opcode 0x08 CMPULTE
+ EdbDisasmCMP, // opcode 0x09 CMPUGTE
+ EdbDisasmUnsignedDataManip, // opcode 0x0A NOT
+ EdbDisasmSignedDataManip, // opcode 0x0B NEG
+ EdbDisasmSignedDataManip, // opcode 0x0C ADD
+ EdbDisasmSignedDataManip, // opcode 0x0D SUB
+ EdbDisasmSignedDataManip, // opcode 0x0E MUL
+ EdbDisasmUnsignedDataManip, // opcode 0x0F MULU
+ EdbDisasmSignedDataManip, // opcode 0x10 DIV
+ EdbDisasmUnsignedDataManip, // opcode 0x11 DIVU
+ EdbDisasmSignedDataManip, // opcode 0x12 MOD
+ EdbDisasmUnsignedDataManip, // opcode 0x13 MODU
+ EdbDisasmUnsignedDataManip, // opcode 0x14 AND
+ EdbDisasmUnsignedDataManip, // opcode 0x15 OR
+ EdbDisasmUnsignedDataManip, // opcode 0x16 XOR
+ EdbDisasmUnsignedDataManip, // opcode 0x17 SHL
+ EdbDisasmUnsignedDataManip, // opcode 0x18 SHR
+ EdbDisasmSignedDataManip, // opcode 0x19 ASHR
+ EdbDisasmUnsignedDataManip, // opcode 0x1A EXTNDB
+ EdbDisasmUnsignedDataManip, // opcode 0x1B EXTNDW
+ EdbDisasmUnsignedDataManip, // opcode 0x1C EXTNDD
+ EdbDisasmMOVxx, // opcode 0x1D MOVBW
+ EdbDisasmMOVxx, // opcode 0x1E MOVWW
+ EdbDisasmMOVxx, // opcode 0x1F MOVDW
+ EdbDisasmMOVxx, // opcode 0x20 MOVQW
+ EdbDisasmMOVxx, // opcode 0x21 MOVBD
+ EdbDisasmMOVxx, // opcode 0x22 MOVWD
+ EdbDisasmMOVxx, // opcode 0x23 MOVDD
+ EdbDisasmMOVxx, // opcode 0x24 MOVQD
+ EdbDisasmMOVsnw, // opcode 0x25 MOVSNW
+ EdbDisasmMOVsnd, // opcode 0x26 MOVSND
+ NULL, // opcode 0x27
+ EdbDisasmMOVxx, // opcode 0x28 MOVQQ
+ EdbDisasmLOADSP, // opcode 0x29 LOADSP
+ EdbDisasmSTORESP, // opcode 0x2A STORESP
+ EdbDisasmPUSH, // opcode 0x2B PUSH
+ EdbDisasmPOP, // opcode 0x2C POP
+ EdbDisasmCMPI, // opcode 0x2D CMPIEQ
+ EdbDisasmCMPI, // opcode 0x2E CMPILTE
+ EdbDisasmCMPI, // opcode 0x2F CMPIGTE
+ EdbDisasmCMPI, // opcode 0x30 CMPIULTE
+ EdbDisasmCMPI, // opcode 0x31 CMPIUGTE
+ EdbDisasmMOVxx, // opcode 0x32 MOVNW
+ EdbDisasmMOVxx, // opcode 0x33 MOVND
+ NULL, // opcode 0x34
+ EdbDisasmPUSHn, // opcode 0x35 PUSHN
+ EdbDisasmPOPn, // opcode 0x36 POPN
+ EdbDisasmMOVI, // opcode 0x37 MOVI
+ EdbDisasmMOVIn, // opcode 0x38 MOVIN
+ EdbDisasmMOVREL, // opcode 0x39 MOVREL
+};
+
+/**
+
+ Disasm instruction - BREAK.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmBREAK (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_BREAK);
+
+ if (*(UINT8 *)(UINTN)(InstructionAddress + 1) > 6) {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"BREAK");
+ EdbPrintDatan (*(UINT8 *)(UINTN)(InstructionAddress + 1));
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+extern CONST UINT8 mJMPLen[];
+
+/**
+
+ Disasm instruction - JMP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmJMP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_JMP);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"JMP");
+// if (Modifiers & OPCODE_M_IMMDATA64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
+ if ((Modifiers & JMP_M_CS) != 0) {
+ EdbPrintInstructionName (L"cs");
+ } else {
+ EdbPrintInstructionName (L"cc");
+ }
+ }
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintData64 (Data64);
+ } else {
+ return 0;
+ }
+ } else {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRegister1 (Operands);
+
+ if ((Operands & OPERAND_M_INDIRECT1) == 0) {
+ if ((Modifiers & OPCODE_M_IMMDATA) == 0) {
+ Data32 = 0;
+ }
+ EdbPrintImmDatan (Data32);
+ } else {
+ EdbPrintRawIndexData32 (Data32);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - JMP8.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmJMP8 (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_JMP8);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"JMP8");
+ if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
+ if ((Modifiers & JMP_M_CS) != 0) {
+ EdbPrintInstructionName (L"cs");
+ } else {
+ EdbPrintInstructionName (L"cc");
+ }
+ }
+
+ EdbPrintData8 (*(UINT8 *)(UINTN)(InstructionAddress + 1));
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - CALL.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCALL (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+ UINT64 Data64;
+ UINT64 Ip;
+ UINTN Result;
+ EFI_PHYSICAL_ADDRESS SavedInstructionAddress;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_CALL);
+ SavedInstructionAddress = InstructionAddress;
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CALL");
+// if (Modifiers & OPCODE_M_IMMDATA64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EdbPrintInstructionName (L"EX");
+ }
+// if ((Operands & OPERAND_M_RELATIVE_ADDR) == 0) {
+// EdbPrintInstructionName (L"a");
+// }
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ Ip = Data64;
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ Result = EdbFindAndPrintSymbol ((UINTN)Ip);
+ if (Result == 0) {
+ EdbPrintData64 (Data64);
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ } else {
+ Data32 = 0;
+ }
+
+ if ((Operands & OPERAND_M_OP1) == 0) {
+ Ip = (UINT64)Data32;
+ } else {
+ Ip = GetRegisterValue (SystemContext, (Operands & OPERAND_M_OP1));
+ }
+
+ if ((Operands & OPERAND_M_INDIRECT1) == 0) {
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Ip + Size));
+ } else {
+ Result = EdbFindAndPrintSymbol ((UINTN)Ip);
+ }
+ if (Result == 0) {
+ EdbPrintRegister1 (Operands);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintImmData32 (Data32);
+ }
+ }
+ } else {
+ EdbPrintRegister1 (Operands);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintRawIndexData32 (Data32);
+ }
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - RET.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmRET (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_RET);
+
+ if (*(UINT8 *)(UINTN)(InstructionAddress + 1) != 0) {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"RET");
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - CMP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCMP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Opcode;
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINT16 Data16;
+ UINTN Size;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPEQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPLTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPGTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPULTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPUGTE)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CMP");
+// if (Modifiers & OPCODE_M_64BIT) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ switch (Opcode) {
+ case OPCODE_CMPEQ:
+ EdbPrintInstructionName (L"eq");
+ break;
+ case OPCODE_CMPLTE:
+ EdbPrintInstructionName (L"lte");
+ break;
+ case OPCODE_CMPGTE:
+ EdbPrintInstructionName (L"gte");
+ break;
+ case OPCODE_CMPULTE:
+ EdbPrintInstructionName (L"ulte");
+ break;
+ case OPCODE_CMPUGTE:
+ EdbPrintInstructionName (L"ugte");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+ InstructionAddress += 2;
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - Unsigned Data Manipulate.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmUnsignedDataManip (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_NOT) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MULU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_DIVU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MODU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_AND) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_OR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_XOR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SHL) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SHR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDB) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDD)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ switch (Opcode) {
+ case OPCODE_NOT:
+ EdbPrintInstructionName (L"NOT");
+ break;
+ case OPCODE_MULU:
+ EdbPrintInstructionName (L"MULU");
+ break;
+ case OPCODE_DIVU:
+ EdbPrintInstructionName (L"DIVU");
+ break;
+ case OPCODE_MODU:
+ EdbPrintInstructionName (L"MODU");
+ break;
+ case OPCODE_AND:
+ EdbPrintInstructionName (L"AND");
+ break;
+ case OPCODE_OR:
+ EdbPrintInstructionName (L"OR");
+ break;
+ case OPCODE_XOR:
+ EdbPrintInstructionName (L"XOR");
+ break;
+ case OPCODE_SHL:
+ EdbPrintInstructionName (L"SHL");
+ break;
+ case OPCODE_SHR:
+ EdbPrintInstructionName (L"SHR");
+ break;
+ case OPCODE_EXTNDB:
+ EdbPrintInstructionName (L"EXTNDB");
+ break;
+ case OPCODE_EXTNDW:
+ EdbPrintInstructionName (L"EXTNDW");
+ break;
+ case OPCODE_EXTNDD:
+ EdbPrintInstructionName (L"EXTNDD");
+ break;
+ }
+// if (Modifiers & DATAMANIP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - Signed Data Manipulate,
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmSignedDataManip (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_NEG) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_ADD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SUB) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MUL) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_DIV) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_ASHR)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ switch (Opcode) {
+ case OPCODE_NEG:
+ EdbPrintInstructionName (L"NEG");
+ break;
+ case OPCODE_ADD:
+ EdbPrintInstructionName (L"ADD");
+ break;
+ case OPCODE_SUB:
+ EdbPrintInstructionName (L"SUB");
+ break;
+ case OPCODE_MUL:
+ EdbPrintInstructionName (L"MUL");
+ break;
+ case OPCODE_DIV:
+ EdbPrintInstructionName (L"DIV");
+ break;
+ case OPCODE_MOD:
+ EdbPrintInstructionName (L"MOD");
+ break;
+ case OPCODE_ASHR:
+ EdbPrintInstructionName (L"ASHR");
+ break;
+ }
+// if (Modifiers & DATAMANIP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVxx.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVxx (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVBW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVWW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVDW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVBD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVWD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVDD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVNW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVND)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 2;
+ }
+ } else if (((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) != 0) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 4;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 4;
+ }
+ } else if (Opcode == OPCODE_MOVQQ) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 8;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 8;
+ }
+ }
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOV");
+ switch (Opcode) {
+ case OPCODE_MOVBW:
+ EdbPrintInstructionName (L"bw");
+ break;
+ case OPCODE_MOVWW:
+ EdbPrintInstructionName (L"ww");
+ break;
+ case OPCODE_MOVDW:
+ EdbPrintInstructionName (L"dw");
+ break;
+ case OPCODE_MOVQW:
+ EdbPrintInstructionName (L"qw");
+ break;
+ case OPCODE_MOVBD:
+ EdbPrintInstructionName (L"bd");
+ break;
+ case OPCODE_MOVWD:
+ EdbPrintInstructionName (L"wd");
+ break;
+ case OPCODE_MOVDD:
+ EdbPrintInstructionName (L"dd");
+ break;
+ case OPCODE_MOVQD:
+ EdbPrintInstructionName (L"qd");
+ break;
+ case OPCODE_MOVQQ:
+ EdbPrintInstructionName (L"qq");
+ break;
+ case OPCODE_MOVNW:
+ EdbPrintInstructionName (L"nw");
+ break;
+ case OPCODE_MOVND:
+ EdbPrintInstructionName (L"nd");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ InstructionAddress += 4;
+ EdbPrintRawIndexData32 (Data32);
+ } else if (Opcode == OPCODE_MOVQQ) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ InstructionAddress += 8;
+ EdbPrintRawIndexData64 (Data64);
+ }
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintRawIndexData16 (Data16);
+ } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRawIndexData32 (Data32);
+ } else if (Opcode == OPCODE_MOVQQ) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintRawIndexData64 (Data64);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVsnw.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVsnw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVSNW);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVsnw");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVsnd.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVsnd (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVSND);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 4;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 4;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVsnd");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ InstructionAddress += 4;
+ EdbPrintRawIndexData32 (Data32);
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData32 (Data32);
+ } else {
+ EdbPrintImmDatan (Data32);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - LOADSP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmLOADSP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Operands;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_LOADSP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"LOADSP");
+
+ EdbPrintDedicatedRegister1 (Operands);
+
+ EdbPrintRegister2 (Operands);
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - STORESP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmSTORESP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Operands;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_STORESP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"STORESP");
+
+ EdbPrintRegister1 (Operands);
+
+ EdbPrintDedicatedRegister2 (Operands);
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+
+/**
+
+ Disasm instruction - PUSH.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPUSH (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_PUSH);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"PUSH");
+// if (Modifiers & PUSHPOP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - POP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPOP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_POP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"POP");
+// if (Modifiers & PUSHPOP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - CMPI.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCMPI (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINTN Size;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIEQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPILTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIGTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIULTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIUGTE)
+ );
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & 0xE0) != 0) {
+ return 0;
+ }
+
+ Size = 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ Size += 4;
+ } else {
+ Size += 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CMPI");
+// if (Modifiers & OPCODE_M_CMPI64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ EdbPrintInstructionName (L"d");
+ } else {
+ EdbPrintInstructionName (L"w");
+ }
+ switch (Opcode) {
+ case OPCODE_CMPIEQ:
+ EdbPrintInstructionName (L"eq");
+ break;
+ case OPCODE_CMPILTE:
+ EdbPrintInstructionName (L"lte");
+ break;
+ case OPCODE_CMPIGTE:
+ EdbPrintInstructionName (L"gte");
+ break;
+ case OPCODE_CMPIULTE:
+ EdbPrintInstructionName (L"ulte");
+ break;
+ case OPCODE_CMPIUGTE:
+ EdbPrintInstructionName (L"ugte");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintDatan (Data32);
+ } else {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintDatan (Data16);
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - PUSHn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPUSHn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_PUSHN);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"PUSHn");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - POPn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPOPn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_POPN);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"POPn");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVI.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVI (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVI);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVI");
+ switch (Operands & MOVI_M_MOVEWIDTH) {
+ case MOVI_MOVEWIDTH8:
+ EdbPrintInstructionName (L"b");
+ break;
+ case MOVI_MOVEWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_MOVEWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_MOVEWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintDatan (Data16);
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintDatan (Data32);
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintData64n (Data64);
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVIn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVIn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVIN);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVIn");
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintRawIndexData16 (Data16);
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRawIndexData32 (Data32);
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintRawIndexData64 (Data64);
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVREL.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVREL (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+ UINTN Result;
+ EFI_PHYSICAL_ADDRESS SavedInstructionAddress;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVREL);
+ SavedInstructionAddress = InstructionAddress;
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ } else {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVrel");
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT16)Data16));
+ if (Result == 0) {
+ EdbPrintData16 (Data16);
+ }
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT32)Data32));
+ if (Result == 0) {
+ EdbPrintData32 (Data32);
+ }
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT64)Data64));
+ } else {
+ Result = 0;
+ }
+ if (Result == 0) {
+ EdbPrintData64 (Data64);
+ }
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h
new file mode 100644
index 000000000..43fa5f4b8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h
@@ -0,0 +1,30 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_DISASM_H_
+#define _EFI_EDB_DISASM_H_
+
+#include <Uefi.h>
+
+//
+// Definition for instruction OPCODE, MODIFIER, and OPERAND
+//
+#define GET_OPCODE(Addr) (UINT8)((*(UINT8 *)(UINTN)(Addr)) & 0x3F)
+#define GET_MODIFIERS(Addr) (UINT8)((*(UINT8 *)(UINTN)(Addr)) & 0xC0)
+#define GET_OPCODE_BYTE(Addr) (UINT8)(*(UINT8 *)(UINTN)(Addr))
+#define GET_OPERANDS(Addr) (UINT8)(*(UINT8 *)(UINTN)((Addr) + 1))
+
+typedef
+UINTN
+(* EDB_DISASM_INSTRUCTION) (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisAsmString
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c
new file mode 100644
index 000000000..feb3fb121
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c
@@ -0,0 +1,1211 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+extern EDB_DISASM_INSTRUCTION mEdbDisasmInstructionTable[];
+
+typedef struct {
+ CHAR16 Name[EDB_INSTRUCTION_NAME_MAX_LENGTH];
+ CHAR16 Content[EDB_INSTRUCTION_CONTENT_MAX_LENGTH];
+ CHAR16 Tail;
+} EDB_INSTRUCTION_STRING;
+
+EDB_INSTRUCTION_STRING mInstructionString;
+UINTN mInstructionNameOffset;
+UINTN mInstructionContentOffset;
+
+/**
+
+ Set offset for Instruction name and content.
+
+ @param InstructionNameOffset - Instruction name offset
+ @param InstructionContentOffset - Instruction content offset
+
+**/
+VOID
+EdbSetOffset (
+ IN UINTN InstructionNameOffset,
+ IN UINTN InstructionContentOffset
+ )
+{
+ mInstructionNameOffset = InstructionNameOffset;
+ mInstructionContentOffset = InstructionContentOffset;
+
+ return ;
+}
+
+/**
+
+ Pre instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPreInstructionString (
+ VOID
+ )
+{
+ ZeroMem (&mInstructionString, sizeof(mInstructionString));
+ mInstructionNameOffset = 0;
+ mInstructionContentOffset = 0;
+
+ return (CHAR16 *)&mInstructionString;
+}
+
+/**
+
+ Post instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPostInstructionString (
+ VOID
+ )
+{
+ CHAR16 *Char;
+
+ for (Char = (CHAR16 *)&mInstructionString; Char < &mInstructionString.Tail; Char++) {
+ if (*Char == 0) {
+ *Char = L' ';
+ }
+ }
+ mInstructionString.Tail = 0;
+
+ mInstructionNameOffset = 0;
+ mInstructionContentOffset = 0;
+
+ return (CHAR16 *)&mInstructionString;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the WORD data.
+
+ @param Data16 - WORD data
+ @param NaturalUnits - Natural Units of the WORD
+ @param ConstantUnits - Constant Units of the WORD
+
+ @return Sign value of WORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex16 (
+ IN UINT16 Data16,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)(Data16 >> 15);
+ NaturalUnitBit = (UINTN)((Data16 >> 12) & 0x7);
+ NaturalUnitBit *= 2;
+ Data16 = Data16 & 0xFFF;
+ *NaturalUnits = (UINTN)(Data16 & ((1 << NaturalUnitBit) - 1));
+ *ConstantUnits = (UINTN)((Data16 >> NaturalUnitBit) & ((1 << (12 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the DWORD data.
+
+ @param Data32 - DWORD data
+ @param NaturalUnits - Natural Units of the DWORD
+ @param ConstantUnits - Constant Units of the DWORD
+
+ @return Sign value of DWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex32 (
+ IN UINT32 Data32,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)(Data32 >> 31);
+ NaturalUnitBit = (UINTN)((Data32 >> 28) & 0x7);
+ NaturalUnitBit *= 4;
+ Data32 = Data32 & 0xFFFFFFF;
+ *NaturalUnits = (UINTN)(Data32 & ((1 << NaturalUnitBit) - 1));
+ *ConstantUnits = (UINTN)((Data32 >> NaturalUnitBit) & ((1 << (28 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the QWORD data.
+
+ @param Data64 - QWORD data
+ @param NaturalUnits - Natural Units of the QWORD
+ @param ConstantUnits - Constant Units of the QWORD
+
+ @return Sign value of QWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex64 (
+ IN UINT64 Data64,
+ OUT UINT64 *NaturalUnits,
+ OUT UINT64 *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)RShiftU64 (Data64, 63);
+ NaturalUnitBit = (UINTN)(RShiftU64 (Data64, 60) & 0x7);
+ NaturalUnitBit *= 8;
+ Data64 = RShiftU64 (LShiftU64 (Data64, 4), 4);
+ *NaturalUnits = (UINT64)(Data64 & (LShiftU64 (1, NaturalUnitBit) - 1));
+ *ConstantUnits = (UINT64)(RShiftU64 (Data64, NaturalUnitBit) & (LShiftU64 (1, (60 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Bit Width of the value.
+
+ @param Value - data
+
+ @return Bit width
+
+**/
+UINT8
+EdbGetBitWidth (
+ IN UINT64 Value
+ )
+{
+ if (Value >= 10000000000000) {
+ return 14;
+ } else if (Value >= 1000000000000) {
+ return 13;
+ } else if (Value >= 100000000000) {
+ return 12;
+ } else if (Value >= 10000000000) {
+ return 11;
+ } else if (Value >= 1000000000) {
+ return 10;
+ } else if (Value >= 100000000) {
+ return 9;
+ } else if (Value >= 10000000) {
+ return 8;
+ } else if (Value >= 1000000) {
+ return 7;
+ } else if (Value >= 100000) {
+ return 6;
+ } else if (Value >= 10000) {
+ return 5;
+ } else if (Value >= 1000) {
+ return 4;
+ } else if (Value >= 100) {
+ return 3;
+ } else if (Value >= 10) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+/**
+
+ Print the instruction name.
+
+ @param Name - instruction name
+
+ @return Instruction name offset
+
+**/
+UINTN
+EdbPrintInstructionName (
+ IN CHAR16 *Name
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Name,
+ EDB_INSTRUCTION_NAME_MAX_SIZE,
+ mInstructionNameOffset,
+ L"%s",
+ Name
+ );
+ mInstructionNameOffset += StrLen (Name);
+
+ return mInstructionNameOffset;
+}
+
+/**
+
+ Print register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister1 (
+ IN UINT8 Operands
+ )
+{
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"@"
+ );
+ mInstructionContentOffset += 1;
+ }
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"R%d",
+ (UINTN)(Operands & OPERAND_M_OP1)
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister2 (
+ IN UINT8 Operands
+ )
+{
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"@"
+ );
+ mInstructionContentOffset += 1;
+ }
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"R%d",
+ (UINTN)((Operands & OPERAND_M_OP2) >> 4)
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print dedicated register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister1 (
+ IN UINT8 Operands
+ )
+{
+ switch (Operands & OPERAND_M_OP1) {
+ case 0:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[FLAGS]"
+ );
+ mInstructionContentOffset += 7;
+ break;
+ case 1:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[IP]"
+ );
+ mInstructionContentOffset += 4;
+ break;
+ }
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print dedicated register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister2 (
+ IN UINT8 Operands
+ )
+{
+ switch ((Operands & OPERAND_M_OP2) >> 4) {
+ case 0:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[FLAGS]"
+ );
+ mInstructionContentOffset += 7;
+ break;
+ case 1:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[IP]"
+ );
+ mInstructionContentOffset += 4;
+ break;
+ }
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical UINTN index data to instruction content.
+
+ @param Sign - Signed bit of UINTN data
+ @param NaturalUnits - natural units of UINTN data
+ @param ConstantUnits - natural units of UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData (
+ IN BOOLEAN Sign,
+ IN UINTN NaturalUnits,
+ IN UINTN ConstantUnits
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%s%d,%s%d)",
+ Sign ? L"-" : L"+",
+ NaturalUnits,
+ Sign ? L"-" : L"+",
+ ConstantUnits
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 5 + EdbGetBitWidth (NaturalUnits) + EdbGetBitWidth (ConstantUnits);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD index data to instruction content.
+
+ @param Sign - Signed bit of QWORD data
+ @param NaturalUnits - natural units of QWORD data
+ @param ConstantUnits - natural units of QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData64 (
+ IN BOOLEAN Sign,
+ IN UINT64 NaturalUnits,
+ IN UINT64 ConstantUnits
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%s%ld,%s%ld)",
+ Sign ? L"-" : L"+",
+ NaturalUnits,
+ Sign ? L"-" : L"+",
+ ConstantUnits
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 5 + EdbGetBitWidth (NaturalUnits) + EdbGetBitWidth (ConstantUnits);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD raw index data to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData16 (
+ IN UINT16 Data16
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnits;
+ UINTN ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex16 (Data16, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical DWORD raw index data to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData32 (
+ IN UINT32 Data32
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnits;
+ UINTN ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex32 (Data32, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical QWORD raw index data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData64 (
+ IN UINT64 Data64
+ )
+{
+ BOOLEAN Sign;
+ UINT64 NaturalUnits;
+ UINT64 ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex64 (Data64, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData64 (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical BYTE immediate data to instruction content.
+
+ @param Data - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData8 (
+ IN UINT8 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%02x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 6;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD immediate data to instruction content.
+
+ @param Data - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData16 (
+ IN UINT16 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%04x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 8;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical DWORD immediate data to instruction content.
+
+ @param Data - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData32 (
+ IN UINT32 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%08x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 12;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD immediate data to instruction content.
+
+ @param Data - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64 (
+ IN UINT64 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%016lx)",
+ Data
+ );
+ mInstructionContentOffset += 20;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal UINTN immediate data to instruction content.
+
+ @param Data - UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmDatan (
+ IN UINTN Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%d)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 2 + EdbGetBitWidth (Data);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal QWORD immediate data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64n (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%ld)",
+ Data64
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 2 + EdbGetBitWidth (Data64);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical BYTE to instruction content.
+
+ @param Data8 - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8 (
+ IN UINT8 Data8
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%02x",
+ (UINTN)Data8
+ );
+ mInstructionContentOffset += 4;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16 (
+ IN UINT16 Data16
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%04x",
+ (UINTN)Data16
+ );
+ mInstructionContentOffset += 6;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical DWORD to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32 (
+ IN UINT32 Data32
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%08x",
+ (UINTN)Data32
+ );
+ mInstructionContentOffset += 10;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64 (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%016lx",
+ (UINT64)Data64
+ );
+ mInstructionContentOffset += 18;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal unsigned UINTN to instruction content.
+
+ @param Data - unsigned UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDatan (
+ IN UINTN Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%d",
+ (UINTN)Data
+ );
+ mInstructionContentOffset = mInstructionContentOffset + EdbGetBitWidth (Data);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal unsigned QWORD to instruction content.
+
+ @param Data64 - unsigned QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64n (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%ld",
+ Data64
+ );
+ mInstructionContentOffset = mInstructionContentOffset + EdbGetBitWidth (Data64);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed BYTE to instruction content.
+
+ @param Data8 - signed BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8s (
+ IN UINT8 Data8
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data8 >> 7);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data8 & 0x7F)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data8 & 0x7F);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed WORD to instruction content.
+
+ @param Data16 - signed WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16s (
+ IN UINT16 Data16
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data16 >> 15);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data16 & 0x7FFF)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data16 & 0x7FFF);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed DWORD to instruction content.
+
+ @param Data32 - signed DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32s (
+ IN UINT32 Data32
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data32 >> 31);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data32 & 0x7FFFFFFF)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data32 & 0x7FFFFFFF);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed QWORD to instruction content.
+
+ @param Data64 - signed QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64s (
+ IN UINT64 Data64
+ )
+{
+ BOOLEAN Sign;
+ INT64 Data64s;
+
+ Sign = (BOOLEAN)RShiftU64 (Data64, 63);
+ Data64s = (INT64)RShiftU64 (LShiftU64 (Data64, 1), 1);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%ld",
+ Sign ? L"-" : L"+",
+ (UINT64)Data64s
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data64s);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the comma to instruction content.
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintComma (
+ VOID
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L", "
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Find the symbol string according to address, then print it.
+
+ @param Address - instruction address
+
+ @retval 1 - symbol string is found and printed
+ @retval 0 - symbol string not found
+
+**/
+UINTN
+EdbFindAndPrintSymbol (
+ IN UINTN Address
+ )
+{
+ CHAR8 *SymbolStr;
+
+ SymbolStr = FindSymbolStr (Address);
+ if (SymbolStr != NULL) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[%a]",
+ SymbolStr
+ );
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+
+ Print the EBC byte code.
+
+ @param InstructionAddress - instruction address
+ @param InstructionNumber - instruction number
+
+**/
+VOID
+EdbPrintRaw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN UINTN InstructionNumber
+ )
+{
+ UINTN LineNumber;
+ UINTN ByteNumber;
+ UINTN LineIndex;
+ UINTN ByteIndex;
+ CHAR8 *SymbolStr;
+
+ if (InstructionNumber == 0) {
+ return ;
+ }
+
+ LineNumber = InstructionNumber / EDB_BYTECODE_NUMBER_IN_LINE;
+ ByteNumber = InstructionNumber % EDB_BYTECODE_NUMBER_IN_LINE;
+ if (ByteNumber == 0) {
+ LineNumber -= 1;
+ ByteNumber = EDB_BYTECODE_NUMBER_IN_LINE;
+ }
+
+ //
+ // Print Symbol
+ //
+ SymbolStr = FindSymbolStr ((UINTN)InstructionAddress);
+ if (SymbolStr != NULL) {
+ EDBPrint (L"[%a]:\n", SymbolStr);
+ }
+
+ for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) {
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)InstructionAddress);
+ for (ByteIndex = 0; ByteIndex < EDB_BYTECODE_NUMBER_IN_LINE; ByteIndex++) {
+ EDBPrint (L"%02x ", *(UINT8 *)(UINTN)InstructionAddress);
+ InstructionAddress += 1;
+ }
+ EDBPrint (L"\n");
+ }
+
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)InstructionAddress);
+ for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) {
+ EDBPrint (L"%02x ", *(UINT8 *)(UINTN)InstructionAddress);
+ InstructionAddress += 1;
+ }
+ for (ByteIndex = 0; ByteIndex < EDB_BYTECODE_NUMBER_IN_LINE - ByteNumber; ByteIndex++) {
+ EDBPrint (L" ");
+ }
+
+ return ;
+}
+
+/**
+
+ Print the EBC asm code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param SystemContext - EBC system context.
+
+ @retval EFI_SUCCESS - show disasm successfully
+
+**/
+EFI_STATUS
+EdbShowDisasm (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_PHYSICAL_ADDRESS InstructionAddress;
+ UINTN InstructionNumber;
+ UINTN InstructionLength;
+ UINT8 Opcode;
+ CHAR16 *InstructionString;
+// UINTN Result;
+
+ InstructionAddress = DebuggerPrivate->InstructionScope;
+ for (InstructionNumber = 0; InstructionNumber < DebuggerPrivate->InstructionNumber; InstructionNumber++) {
+
+ //
+ // Break each 0x10 instruction
+ //
+ if (((InstructionNumber % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (InstructionNumber != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ Opcode = GET_OPCODE(InstructionAddress);
+ if ((Opcode < OPCODE_MAX) && (mEdbDisasmInstructionTable[Opcode] != NULL)) {
+ InstructionLength = mEdbDisasmInstructionTable [Opcode] (InstructionAddress, SystemContext, &InstructionString);
+ if (InstructionLength != 0) {
+
+ //
+ // Print Source
+ //
+// Result = EdbPrintSource ((UINTN)InstructionAddress, FALSE);
+
+ if (!DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly) {
+
+ EdbPrintRaw (InstructionAddress, InstructionLength);
+ if (InstructionString != NULL) {
+ EDBPrint (L"%s\n", InstructionString);
+ } else {
+ EDBPrint (L"%s\n", L"<Unknown Instruction>");
+ }
+ }
+
+ EdbPrintSource ((UINTN)InstructionAddress, TRUE);
+
+ InstructionAddress += InstructionLength;
+ } else {
+ //
+ // Something wrong with OPCODE
+ //
+ EdbPrintRaw (InstructionAddress, EDB_BYTECODE_NUMBER_IN_LINE);
+ EDBPrint (L"%s\n", L"<Bad Instruction>");
+ break;
+ }
+ } else {
+ //
+ // Something wrong with OPCODE
+ //
+ EdbPrintRaw (InstructionAddress, EDB_BYTECODE_NUMBER_IN_LINE);
+ EDBPrint (L"%s\n", L"<Bad Instruction>");
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get register value according to the system context, and register index.
+
+ @param SystemContext - EBC system context.
+ @param Index - EBC register index
+
+ @return register value
+
+**/
+UINT64
+GetRegisterValue (
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN UINT8 Index
+ )
+{
+ switch (Index) {
+ case 0:
+ return SystemContext.SystemContextEbc->R0;
+ case 1:
+ return SystemContext.SystemContextEbc->R1;
+ case 2:
+ return SystemContext.SystemContextEbc->R2;
+ case 3:
+ return SystemContext.SystemContextEbc->R3;
+ case 4:
+ return SystemContext.SystemContextEbc->R4;
+ case 5:
+ return SystemContext.SystemContextEbc->R5;
+ case 6:
+ return SystemContext.SystemContextEbc->R6;
+ case 7:
+ return SystemContext.SystemContextEbc->R7;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h
new file mode 100644
index 000000000..b1e7a468e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h
@@ -0,0 +1,567 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_DISASM_SUPPORT_H_
+#define _EFI_EDB_DISASM_SUPPORT_H_
+
+#include <Uefi.h>
+
+#define EDB_BYTECODE_NUMBER_IN_LINE 5
+
+#ifdef EFI32
+#define EDB_PRINT_ADDRESS_FORMAT L"%08x: "
+#else
+// To use 012l instead of 016l because space is not enough
+#define EDB_PRINT_ADDRESS_FORMAT L"%012lx: "
+#endif
+
+#define OPCODE_MAX 0x40
+
+#define EDB_INSTRUCTION_NAME_MAX_LENGTH 10
+#define EDB_INSTRUCTION_NAME_MAX_SIZE (EDB_INSTRUCTION_NAME_MAX_LENGTH * sizeof(CHAR16))
+#define EDB_INSTRUCTION_CONTENT_MAX_LENGTH 30
+#define EDB_INSTRUCTION_CONTENT_MAX_SIZE (EDB_INSTRUCTION_CONTENT_MAX_LENGTH * sizeof(CHAR16))
+
+/**
+
+ Set offset for Instruction name and content.
+
+ @param InstructionNameOffset - Instruction name offset
+ @param InstructionContentOffset - Instruction content offset
+
+**/
+VOID
+EdbSetOffset (
+ IN UINTN InstructionNameOffset,
+ IN UINTN InstructionContentOffset
+ );
+
+/**
+
+ Pre instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPreInstructionString (
+ VOID
+ );
+
+/**
+
+ Post instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPostInstructionString (
+ VOID
+ );
+
+/**
+
+ Print the instruction name.
+
+ @param Name - instruction name
+
+ @return Instruction name offset
+
+**/
+UINTN
+EdbPrintInstructionName (
+ IN CHAR16 *Name
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the WORD data.
+
+ @param Data16 - WORD data
+ @param NaturalUnits - Natural Units of the WORD
+ @param ConstantUnits - Constant Units of the WORD
+
+ @return Sign value of WORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex16 (
+ IN UINT16 Data16,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the DWORD data.
+
+ @param Data32 - DWORD data
+ @param NaturalUnits - Natural Units of the DWORD
+ @param ConstantUnits - Constant Units of the DWORD
+
+ @return Sign value of DWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex32 (
+ IN UINT32 Data32,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the QWORD data.
+
+ @param Data64 - QWORD data
+ @param NaturalUnits - Natural Units of the QWORD
+ @param ConstantUnits - Constant Units of the QWORD
+
+ @return Sign value of QWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex64 (
+ IN UINT64 Data64,
+ OUT UINT64 *NaturalUnits,
+ OUT UINT64 *ConstantUnits
+ );
+
+/**
+
+ Print the hexical WORD raw index data to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData16 (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the hexical DWORD raw index data to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData32 (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the hexical QWORD raw index data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData64 (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister1 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister2 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print dedicated register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister1 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print dedicated register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister2 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print the hexical UINTN index data to instruction content.
+
+ @param Sign - Signed bit of UINTN data
+ @param NaturalUnits - natural units of UINTN data
+ @param ConstantUnits - natural units of UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData (
+ IN BOOLEAN Sign,
+ IN UINTN NaturalUnits,
+ IN UINTN ConstantUnits
+ );
+
+/**
+
+ Print the hexical QWORD index data to instruction content.
+
+ @param Sign - Signed bit of QWORD data
+ @param NaturalUnits - natural units of QWORD data
+ @param ConstantUnits - natural units of QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData64 (
+ IN BOOLEAN Sign,
+ IN UINT64 NaturalUnits,
+ IN UINT64 ConstantUnits
+ );
+
+/**
+
+ Print the hexical BYTE immediate data to instruction content.
+
+ @param Data - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData8 (
+ IN UINT8 Data
+ );
+
+/**
+
+ Print the hexical WORD immediate data to instruction content.
+
+ @param Data - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData16 (
+ IN UINT16 Data
+ );
+
+/**
+
+ Print the hexical DWORD immediate data to instruction content.
+
+ @param Data - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData32 (
+ IN UINT32 Data
+ );
+
+/**
+
+ Print the hexical QWORD immediate data to instruction content.
+
+ @param Data - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64 (
+ IN UINT64 Data
+ );
+
+/**
+
+ Print the decimal UINTN immediate data to instruction content.
+
+ @param Data - UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmDatan (
+ IN UINTN Data
+ );
+
+/**
+
+ Print the decimal QWORD immediate data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64n (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the hexical BYTE to instruction content.
+
+ @param Data8 - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8 (
+ IN UINT8 Data8
+ );
+
+/**
+
+ Print the hexical WORD to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16 (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the hexical DWORD to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32 (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the hexical QWORD to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64 (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the decimal unsigned UINTN to instruction content.
+
+ @param Data - unsigned UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDatan (
+ IN UINTN Data
+ );
+
+/**
+
+ Print the decimal unsigned QWORD to instruction content.
+
+ @param Data64 - unsigned QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64n (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the decimal signed BYTE to instruction content.
+
+ @param Data8 - signed BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8s (
+ IN UINT8 Data8
+ );
+
+/**
+
+ Print the decimal signed WORD to instruction content.
+
+ @param Data16 - signed WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16s (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the decimal signed DWORD to instruction content.
+
+ @param Data32 - signed DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32s (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the decimal signed QWORD to instruction content.
+
+ @param Data64 - signed QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64s (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the comma to instruction content.
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintComma (
+ VOID
+ );
+
+/**
+
+ Find the symbol string according to address, then print it.
+
+ @param Address - instruction address
+
+ @retval 1 - symbol string is found and printed
+ @retval 0 - symbol string not found
+
+**/
+UINTN
+EdbFindAndPrintSymbol (
+ IN UINTN Address
+ );
+
+/**
+
+ Print the EBC byte code.
+
+ @param InstructionAddress - instruction address
+ @param InstructionNumber - instruction number
+
+**/
+VOID
+EdbPrintRaw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN UINTN InstructionNumber
+ );
+
+/**
+
+ Print the EBC asm code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param SystemContext - EBC system context.
+
+ @retval EFI_SUCCESS - show disasm successfully
+
+**/
+EFI_STATUS
+EdbShowDisasm (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+
+ Get register value according to the system context, and register index.
+
+ @param SystemContext - EBC system context.
+ @param Index - EBC register index
+
+ @return register value
+
+**/
+UINT64
+GetRegisterValue (
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN UINT8 Index
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
new file mode 100644
index 000000000..83257a2c2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
@@ -0,0 +1,833 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check the Hook flag, and trigger exception if match.
+
+ @param VmPtr - EbcDebuggerCheckHookFlag
+ @param Flag - Feature flag
+
+**/
+VOID
+EbcDebuggerCheckHookFlag (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Flag
+ )
+{
+ if ((mDebuggerPrivate.FeatureFlags & Flag) == Flag) {
+ mDebuggerPrivate.StatusFlags = Flag;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ }
+ return ;
+}
+
+/**
+
+ It will record soruce address for Callstack entry.
+
+ @param SourceEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackSource (
+ IN UINT64 SourceEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+ //
+ // Record the new callstack entry
+ //
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = SourceEntry;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type = Type;
+
+ //
+ // Do not change CallStackEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record parameter for Callstack entry.
+
+ @param ParameterAddress - The address for the parameter
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackParameter (
+ IN UINT64 ParameterAddress,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+ //
+ // Record the new callstack parameter
+ //
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].ParameterAddr = (UINTN)ParameterAddress;
+ CopyMem (
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter,
+ (VOID *)(UINTN)ParameterAddress,
+ sizeof(mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter)
+ );
+
+ //
+ // Do not change CallStackEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record source address for callstack entry.
+
+ @param DestEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackDest (
+ IN UINT64 DestEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ UINTN Index;
+
+ if (mDebuggerPrivate.CallStackEntryCount < EFI_DEBUGGER_CALLSTACK_MAX) {
+ //
+ // If there is empty entry for callstack, add it
+ //
+ ASSERT (mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type == Type);
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = DestEntry;
+ mDebuggerPrivate.CallStackEntryCount ++;
+ } else {
+ //
+ // If there is no empty entry for callstack, throw the oldest one
+ //
+ ASSERT (mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
+ for (Index = 0; Index < EFI_DEBUGGER_CALLSTACK_MAX; Index++) {
+ CopyMem (&mDebuggerPrivate.CallStackEntry[Index],
+ &mDebuggerPrivate.CallStackEntry[Index + 1],
+ sizeof (mDebuggerPrivate.CallStackEntry[Index])
+ );
+ }
+ mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+
+ return ;
+}
+
+/**
+
+ It will throw the newest Callstack entry.
+
+**/
+VOID
+EbcDebuggerPopCallstack (
+ VOID
+ )
+{
+ if ((mDebuggerPrivate.CallStackEntryCount > 0) &&
+ (mDebuggerPrivate.CallStackEntryCount <= EFI_DEBUGGER_CALLSTACK_MAX)) {
+ //
+ // Throw the newest one
+ //
+ mDebuggerPrivate.CallStackEntryCount --;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = 0;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = 0;
+ } else if (mDebuggerPrivate.CallStackEntryCount == 0) {
+ //
+ // NOT assert here because it is reasonable, because when we start to build
+ // callstack, we do not know how many function already called.
+ //
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return ;
+}
+
+/**
+
+ It will record source address for trace entry.
+
+ @param SourceEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushTraceSourceEntry (
+ IN UINT64 SourceEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
+ }
+ //
+ // Record the new trace entry
+ //
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].SourceAddress = SourceEntry;
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type = Type;
+
+ //
+ // Do not change TraceEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record destination address for trace entry.
+
+ @param DestEntry - Destination address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushTraceDestEntry (
+ IN UINT64 DestEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ UINTN Index;
+
+ if (mDebuggerPrivate.TraceEntryCount < EFI_DEBUGGER_TRACE_MAX) {
+ //
+ // If there is empty entry for trace, add it
+ //
+ ASSERT (mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type == Type);
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].DestAddress = DestEntry;
+ mDebuggerPrivate.TraceEntryCount ++;
+ } else {
+ //
+ // If there is no empty entry for trace, throw the oldest one
+ //
+ ASSERT (mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
+ for (Index = 0; Index < EFI_DEBUGGER_TRACE_MAX; Index++) {
+ mDebuggerPrivate.TraceEntry[Index] = mDebuggerPrivate.TraceEntry[Index + 1];
+ }
+ mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
+ mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
+ }
+
+ return ;
+}
+
+/**
+
+ It will record address for StepEntry, if STEPOVER or STEPOUT is enabled.
+
+ @param Entry - Break Address
+ @param FramePtr - Break Frame pointer
+ @param Flag - for STEPOVER or STEPOUT
+
+**/
+VOID
+EbcDebuggerPushStepEntry (
+ IN UINT64 Entry,
+ IN UINT64 FramePtr,
+ IN UINT32 Flag
+ )
+{
+ //
+ // Check StepOver
+ //
+ if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOVER) &&
+ ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER)) {
+ mDebuggerPrivate.StepContext.BreakAddress = Entry;
+ mDebuggerPrivate.StepContext.FramePointer = FramePtr;
+ mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
+ }
+ //
+ // Check StepOut
+ //
+ if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOUT) &&
+ ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT)) {
+ mDebuggerPrivate.StepContext.BreakAddress = Entry;
+ mDebuggerPrivate.StepContext.FramePointer = FramePtr;
+ mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
+ }
+}
+
+
+/**
+ Notify the callback function when an event is triggered.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+EbcDebuggerBreakEventFunc (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ if ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) != EFI_DEBUG_FLAG_EBC_BOK) {
+ return ;
+ }
+
+ Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
+ if (Status == EFI_SUCCESS) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_BOK;
+ }
+}
+
+/**
+
+ The hook in InitializeEbcDriver.
+ It will init the EbcDebuggerPrivate data structure.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+
+ //
+ // Register all exception handler
+ //
+ for (Index = EXCEPT_EBC_UNDEFINED; Index <= EXCEPT_EBC_STEP; Index++) {
+ EbcDebugProtocol->RegisterExceptionCallback (
+ EbcDebugProtocol,
+ 0,
+ NULL,
+ Index
+ );
+ EbcDebugProtocol->RegisterExceptionCallback (
+ EbcDebugProtocol,
+ 0,
+ EdbExceptionHandler,
+ Index
+ );
+ }
+
+ //
+ // Init Symbol
+ //
+ Object = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_OBJECT) * EFI_DEBUGGER_SYMBOL_OBJECT_MAX);
+ ASSERT (Object != NULL);
+ mDebuggerPrivate.DebuggerSymbolContext.Object = Object;
+ mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
+ mDebuggerPrivate.DebuggerSymbolContext.MaxObjectCount = EFI_DEBUGGER_SYMBOL_OBJECT_MAX;
+ for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
+ Entry = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_ENTRY) * EFI_DEBUGGER_SYMBOL_ENTRY_MAX);
+ ASSERT (Entry != NULL);
+ Object[Index].Entry = Entry;
+ Object[Index].MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
+ Object[Index].SourceBuffer = AllocateZeroPool (sizeof(VOID *) * (EFI_DEBUGGER_SYMBOL_ENTRY_MAX + 1));
+ ASSERT (Object[Index].SourceBuffer != NULL);
+ }
+
+ //
+ // locate PciRootBridgeIo
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ (VOID**) &mDebuggerPrivate.PciRootBridgeIo
+ );
+
+ //
+ // locate DebugImageInfoTable
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiDebugImageInfoTableGuid,
+ (VOID**) &mDebuggerPrivate.DebugImageInfoTableHeader
+ );
+
+ //
+ // Register Debugger Configuration Protocol, for config in shell
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiDebuggerConfigurationProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mDebuggerPrivate.DebuggerConfiguration
+ );
+
+ //
+ //
+ // Create break event
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EbcDebuggerBreakEventFunc,
+ NULL,
+ &mDebuggerPrivate.BreakEvent
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->SetTimer (
+ mDebuggerPrivate.BreakEvent,
+ TimerPeriodic,
+ EFI_DEBUG_BREAK_TIMER_INTERVAL
+ );
+ }
+
+ return ;
+}
+
+/**
+
+ The hook in UnloadImage for EBC Interpreter.
+ It clean up the environment.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Close the break event
+ //
+ if (mDebuggerPrivate.BreakEvent != NULL) {
+ gBS->CloseEvent (mDebuggerPrivate.BreakEvent);
+ }
+
+ //
+ // Clean up the symbol
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
+ //
+ // Clean up Entry
+ //
+ gBS->FreePool (Object[Index].Entry);
+ Object[Index].Entry = NULL;
+ Object[Index].EntryCount = 0;
+ //
+ // Clean up source buffer
+ //
+ for (SubIndex = 0; Object[Index].SourceBuffer[SubIndex] != NULL; SubIndex++) {
+ gBS->FreePool (Object[Index].SourceBuffer[SubIndex]);
+ Object[Index].SourceBuffer[SubIndex] = NULL;
+ }
+ gBS->FreePool (Object[Index].SourceBuffer);
+ Object[Index].SourceBuffer = NULL;
+ }
+
+ //
+ // Clean up Object
+ //
+ gBS->FreePool (Object);
+ mDebuggerPrivate.DebuggerSymbolContext.Object = NULL;
+ mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle - The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ )
+{
+ return ;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+ It will record the call-stack entry. (-1 means EbcImageEntryPoint call)
+ and trigger Exception if BOE enabled.
+
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-1, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOE);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+ It will record the call-stack entry. (-2 means EbcInterpret call)
+ and trigger Exception if BOT enabled.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-2, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOT);
+ return ;
+}
+
+/**
+
+ The hook in EbcExecute, before ExecuteFunction.
+ It will trigger Exception if GoTil, StepOver, or StepOut hit.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_TPL CurrentTpl;
+
+ //
+ // Check Ip for GoTil
+ //
+ if (mDebuggerPrivate.GoTilContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_GT;
+ mDebuggerPrivate.GoTilContext.BreakAddress = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_GT;
+ return ;
+ }
+ //
+ // Check ReturnAddress for StepOver
+ //
+ if ((mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) &&
+ (mDebuggerPrivate.StepContext.FramePointer == (UINT64)(UINTN)VmPtr->FramePtr)) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOVER;
+ mDebuggerPrivate.StepContext.BreakAddress = 0;
+ mDebuggerPrivate.StepContext.FramePointer = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
+ }
+ //
+ // Check FramePtr for StepOut
+ //
+ if (mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->FramePtr) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOUT;
+ mDebuggerPrivate.StepContext.BreakAddress = 0;
+ mDebuggerPrivate.StepContext.FramePointer = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
+ }
+ //
+ // Check Flags for BreakOnKey
+ //
+ if (mDebuggerPrivate.StatusFlags == EFI_DEBUG_FLAG_EBC_BOK) {
+ //
+ // Only break when the current TPL <= TPL_APPLICATION
+ //
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_APPLICATION) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ }
+ }
+ return ;
+}
+
+/**
+
+ The hook in EbcExecute, after ExecuteFunction.
+ It will record StepOut Entry if need.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINTN Address;
+
+ //
+ // Use FramePtr as checkpoint for StepOut
+ //
+ CopyMem (&Address, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(Address));
+ EbcDebuggerPushStepEntry (Address, (UINT64)(UINTN)VmPtr->FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
+
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, before move IP.
+ It will trigger Exception if BOC enabled,
+ and record Callstack, and trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOC);
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+ It will record Callstack, trace information
+ and record StepOver/StepOut Entry if need.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT64 Address;
+ UINTN FramePtr;
+
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+
+ //
+ // Get Old FramePtr
+ //
+ CopyMem (&FramePtr, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(FramePtr));
+
+ //
+ // Use ReturnAddress as checkpoint for StepOver
+ //
+ CopyMem (&Address, (VOID *)(UINTN)VmPtr->Gpr[0], sizeof(Address));
+ EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOVER);
+
+ //
+ // Use FramePtr as checkpoint for StepOut
+ //
+ Address = 0;
+ CopyMem (&Address, (VOID *)(FramePtr), sizeof(UINTN));
+ EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
+
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+ It will trigger Exception if BOCX enabled,
+ and record Callstack information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOCX);
+// EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+// EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->R[0], EfiDebuggerBranchTypeEbcCallEx);
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+// EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+ It will trigger Exception if BOR enabled,
+ and record Callstack, and trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOR);
+ EbcDebuggerPopCallstack ();
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP8, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h
new file mode 100644
index 000000000..6de50e0a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h
@@ -0,0 +1,14 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EDB_HOOKER_H_
+#define _EFI_EDB_HOOKER_H_
+
+#include <Uefi.h>
+#include "EbcDebuggerHook.h"
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h
new file mode 100644
index 000000000..ba8b936b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h
@@ -0,0 +1,477 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_SUPPORT_H_
+#define _EFI_EDB_SUPPORT_H_
+
+#include <Uefi.h>
+
+#define EFI_DEBUG_PROMPT_STRING L"EDB > "
+#define EFI_DEBUG_PROMPT_COLUMN 5
+#define EFI_DEBUG_INPUS_BUFFER_SIZE 64
+
+#define EFI_DEBUGGER_LINE_NUMBER_IN_PAGE 0x10
+
+#define EFI_DEBUG_MAX_PRINT_BUFFER (80 * 4)
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Xtoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINT64
+EFIAPI
+LXtoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Atoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiXtoi (
+ CHAR8 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiAtoi (
+ CHAR8 *Str
+ );
+
+/**
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexicall greater than String2; Zero if
+ the two strings are identical; and a negative interger if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StrCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ );
+
+/**
+
+ Compare the Unicode string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Unicode string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmp (
+ IN CHAR16 *String,
+ IN CHAR16 *String2
+ );
+
+/**
+
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ );
+
+/**
+
+ Verify if the string is end with the sub string.
+
+ @param Str - The string where to search the sub string
+ @param SubStr - The substring.
+
+**/
+BOOLEAN
+EFIAPI
+StrEndWith (
+ IN CHAR16 *Str,
+ IN CHAR16 *SubStr
+ );
+
+/**
+ Duplicate a string.
+
+ @param Src The string to be duplicated.
+
+**/
+CHAR16 *
+EFIAPI
+StrDuplicate (
+ IN CHAR16 *Src
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenLine (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenLine (
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenField (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenField (
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenAfter (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ );
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenBefore (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenLine (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenLine (
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenField (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenField (
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenAfter (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ );
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenBefore (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ );
+
+/**
+
+ Shell Library.
+ Get user input.
+
+ @param Prompt The prompt string.
+ @param InStr Point to the input string.
+ @param StrLen The max length of string user can input.
+
+**/
+VOID
+EFIAPI
+Input (
+ IN CHAR16 *Prompt OPTIONAL,
+ OUT CHAR16 *InStr,
+ IN UINTN StrLen
+ );
+
+/**
+
+ SetPageBreak.
+
+**/
+BOOLEAN
+EFIAPI
+SetPageBreak (
+ VOID
+ );
+
+/**
+ Print a Unicode string to the output device.
+
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBPrint (
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+ Print a Unicode string to the output buffer.
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrint (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+ Print a Unicode string to the output buffer with specified offset..
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Offset The offset of the buffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrintWithOffset (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN UINTN Offset,
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+
+ Read a file.
+ If ScanFs is FLASE, it will use DebuggerPrivate->Vol as default Fs.
+ If ScanFs is TRUE, it will scan all FS and check the file.
+ If there is only one file match the name, it will be read.
+ If there is more than one file match the name, it will return Error.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+ @param ScanFs - Need Scan all FS
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+ @retval EFI_NO_MAPPING - there is duplicated files found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileToBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer,
+ IN BOOLEAN ScanFs
+ );
+
+/**
+
+ Get file name under this dir with index
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param DirName - The dir to be read.
+ @param FileName - The file name pattern under this dir
+ @param Index - The file index under this dir
+
+ @return File Name which match the pattern and index.
+
+**/
+CHAR16 *
+EFIAPI
+GetFileNameUnderDir (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *DirName,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c
new file mode 100644
index 000000000..ee2f8fc2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c
@@ -0,0 +1,384 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+ Read a file.
+
+ @param Vol - File System Volume
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileFromVol (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE Handle;
+ UINTN FileInfoSize;
+ EFI_FILE_INFO *FileInfo;
+ UINTN TempBufferSize;
+ VOID *TempBuffer;
+
+ //
+ // Open the root directory
+ //
+ Status = Vol->OpenVolume (Vol, &RootDir);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the file
+ //
+ Status = RootDir->Open (
+ RootDir,
+ &Handle,
+ FileName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ RootDir->Close (RootDir);
+ return Status;
+ }
+
+ RootDir->Close (RootDir);
+
+ //
+ // Get the file information
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ FileInfo = AllocateZeroPool (FileInfoSize);
+ if (FileInfo == NULL) {
+ Handle->Close (Handle);
+ return Status;
+ }
+
+ Status = Handle->GetInfo (
+ Handle,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ gBS->FreePool (FileInfo);
+ return Status;
+ }
+
+ //
+ // Allocate buffer for the file data. The last CHAR16 is for L'\0'
+ //
+ TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer == NULL) {
+ Handle->Close (Handle);
+ gBS->FreePool (FileInfo);
+ return Status;
+ }
+
+ gBS->FreePool (FileInfo);
+
+ //
+ // Read the file data to the buffer
+ //
+ Status = Handle->Read (
+ Handle,
+ &TempBufferSize,
+ TempBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ gBS->FreePool (TempBuffer);
+ return Status;
+ }
+
+ Handle->Close (Handle);
+
+ *BufferSize = TempBufferSize;
+ *Buffer = TempBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Read a file.
+ If ScanFs is FLASE, it will use DebuggerPrivate->Vol as default Fs.
+ If ScanFs is TRUE, it will scan all FS and check the file.
+ If there is only one file match the name, it will be read.
+ If there is more than one file match the name, it will return Error.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+ @param ScanFs - Need Scan all FS
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+ @retval EFI_NO_MAPPING - there is duplicated files found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileToBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer,
+ IN BOOLEAN ScanFs
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ UINTN TempBufferSize;
+ VOID *TempBuffer;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Check parameters
+ //
+ if ((FileName == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // not scan fs
+ //
+ if (!ScanFs) {
+ if (DebuggerPrivate->Vol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Read file directly from Vol
+ //
+ return ReadFileFromVol (DebuggerPrivate->Vol, FileName, BufferSize, Buffer);
+ }
+
+ //
+ // need scan fs
+ //
+
+ //
+ // Get all Vol handle
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Walk through each Vol
+ //
+ DebuggerPrivate->Vol = NULL;
+ *BufferSize = 0;
+ *Buffer = NULL;
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**) &Vol
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Read file OK, check duplication
+ //
+ if (DebuggerPrivate->Vol != NULL) {
+ //
+ // Find the duplicated file
+ //
+ gBS->FreePool (TempBuffer);
+ gBS->FreePool (*Buffer);
+ EDBPrint (L"Duplicated FileName found!\n");
+ return EFI_NO_MAPPING;
+ } else {
+ //
+ // Record value
+ //
+ DebuggerPrivate->Vol = Vol;
+ *BufferSize = TempBufferSize;
+ *Buffer = TempBuffer;
+ }
+ }
+ }
+
+ //
+ // Scan Fs done
+ //
+ if (DebuggerPrivate->Vol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get file name under this dir with index
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param DirName - The dir to be read.
+ @param FileName - The file name pattern under this dir
+ @param Index - The file index under this dir
+
+ @return File Name which match the pattern and index.
+
+**/
+CHAR16 *
+EFIAPI
+GetFileNameUnderDir (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *DirName,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE Handle;
+ UINTN FileInfoSize;
+ EFI_FILE_INFO *FileInfo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ VOID *TempName;
+ UINTN FileIndex;
+
+ if (DebuggerPrivate->Vol == NULL) {
+ Status = gBS->LocateProtocol (
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ (VOID**) &DebuggerPrivate->Vol
+ );
+ if (EFI_ERROR(Status)) {
+ return NULL;
+ }
+ }
+ Vol = DebuggerPrivate->Vol;
+
+ //
+ // Open the root directory
+ //
+ Status = Vol->OpenVolume (Vol, &RootDir);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Open the file
+ //
+ Status = RootDir->Open (
+ RootDir,
+ &Handle,
+ DirName,
+ EFI_FILE_MODE_READ,
+ EFI_FILE_DIRECTORY
+ );
+ if (EFI_ERROR (Status)) {
+ RootDir->Close (RootDir);
+ return NULL;
+ }
+ RootDir->Close (RootDir);
+
+ //
+ // Set Dir Position
+ //
+ Status = Handle->SetPosition (Handle, 0);
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ return NULL;
+ }
+
+ //
+ // Get the file information
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ FileInfo = AllocateZeroPool (FileInfoSize);
+ if (FileInfo == NULL) {
+ Handle->Close (Handle);
+ return NULL;
+ }
+
+ //
+ // Walk through each file in the directory
+ //
+ FileIndex = 0;
+ TempName = NULL;
+ while (TRUE) {
+ //
+ // Read a file entry
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ Status = Handle->Read (
+ Handle,
+ &FileInfoSize,
+ FileInfo
+ );
+ if (EFI_ERROR (Status) || (FileInfoSize == 0)) {
+ break;
+ }
+
+ if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ //
+ // This is a file
+ //
+
+ //
+ // Only deal with the EFI key file
+ //
+ if (!StrEndWith (FileInfo->FileName, FileName)) {
+ continue;
+ }
+
+ if (FileIndex == *Index) {
+ TempName = StrDuplicate (FileInfo->FileName);
+ *Index = *Index + 1;
+ break;
+ }
+ FileIndex ++;
+ }
+ }
+
+ //
+ // Free resources
+ //
+ gBS->FreePool (FileInfo);
+ Handle->Close (Handle);
+
+ return TempName;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c
new file mode 100644
index 000000000..9679a2300
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c
@@ -0,0 +1,1020 @@
+/** @file
+
+Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Xtoi (
+ CHAR16 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR16 TempChar;
+ UINTN MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 >> 4;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINT64
+EFIAPI
+LXtoi (
+ CHAR16 *Str
+ )
+{
+ UINT64 RetVal;
+ CHAR16 TempChar;
+ UINT64 MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = RShiftU64 ((UINT64) -1, 4);
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINT64) -1;
+ }
+
+ RetVal = LShiftU64 (RetVal, 4);
+ RetVal = RetVal + (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Atoi (
+ CHAR16 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR16 TempChar;
+ UINTN MaxVal;
+ UINTN ResteVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 / 10;
+ ResteVal = (UINTN) -1 % 10;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // convert digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= '0' && TempChar <= '9') {
+ if (RetVal > MaxVal || (RetVal == MaxVal && TempChar - '0' > (INTN) ResteVal)) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal * 10) + TempChar - '0';
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiXtoi (
+ CHAR8 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR8 TempChar;
+ UINTN MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 >> 4;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiAtoi (
+ CHAR8 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR8 TempChar;
+ UINTN MaxVal;
+ UINTN ResteVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 / 10;
+ ResteVal = (UINTN) -1 % 10;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // convert digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= '0' && TempChar <= '9') {
+ if (RetVal > MaxVal || (RetVal == MaxVal && TempChar - '0' > (INTN) ResteVal)) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal * 10) + TempChar - '0';
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+
+/**
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexicall greater than String2; Zero if
+ the two strings are identical; and a negative interger if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StrCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ )
+{
+ while (*String != '\0') {
+ if (*String != (CHAR16)*String2) {
+ break;
+ }
+
+ String += 1;
+ String2 += 1;
+ }
+
+ return (*String - (CHAR16)*String2);
+}
+
+/**
+
+ Compare the Unicode string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Unicode string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmp (
+ IN CHAR16 *String,
+ IN CHAR16 *String2
+ )
+{
+ while ((*String != L'\0') &&
+ (CharToUpper (*String) == CharToUpper (*String2))) {
+ String++;
+ String2++;
+ }
+
+ return CharToUpper (*String) - CharToUpper (*String2);
+}
+
+/**
+
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ )
+{
+ while ((*String != L'\0') &&
+ (CharToUpper (*String) == (CHAR16)AsciiCharToUpper (*String2))) {
+ String++;
+ String2++;
+ }
+
+ return CharToUpper (*String) - (CHAR16)AsciiCharToUpper (*String2);
+}
+
+/**
+
+ Verify if the string is end with the sub string.
+
+ @param Str - The string where to search the sub string
+ @param SubStr - The substring.
+
+**/
+BOOLEAN
+EFIAPI
+StrEndWith (
+ IN CHAR16 *Str,
+ IN CHAR16 *SubStr
+ )
+{
+ CHAR16 *Temp;
+
+ if ((Str == NULL) || (SubStr == NULL) || (StrLen(Str) < StrLen(SubStr))) {
+ return FALSE;
+ }
+
+ Temp = Str + StrLen(Str) - StrLen(SubStr);
+
+ //
+ // Compare
+ //
+ if (StriCmp (Temp, SubStr) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Duplicate a string.
+
+ @param Src The string to be duplicated.
+
+**/
+CHAR16 *
+EFIAPI
+StrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = (StrLen(Src) + 1) * sizeof(CHAR16);
+ Dest = AllocateZeroPool (Size);
+ if (Dest != NULL) {
+ CopyMem (Dest, Src, Size);
+ }
+ return Dest;
+}
+
+
+CHAR16 *mLineBuffer = NULL;
+CHAR16 *mFieldBuffer = NULL;
+
+/**
+
+ Find the first substring.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+UINTN
+EFIAPI
+StrSpn (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ UINTN Count;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ Count = 0;
+
+ for (Str1 = String; *Str1 != L'\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != L'\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ break;
+ }
+ }
+
+ if (*Str2 == L'\0') {
+ return Count;
+ }
+
+ Count ++;
+ }
+
+ return Count;
+}
+
+/**
+
+ Searches a string for the first occurrence of a character contained in a
+ specified buffer.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrBrk (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ for (Str1 = String; *Str1 != L'\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != L'\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ return (CHAR16 *) Str1;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrTokenLine (
+ IN CHAR16 *String OPTIONAL,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Begin;
+ CHAR16 *End;
+
+ Begin = (String == NULL) ? mLineBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ Begin += StrSpn (Begin, CharSet);
+ if (*Begin == L'\0') {
+ mLineBuffer = NULL;
+ return NULL;
+ }
+
+ End = StrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != L'\0')) {
+ *End = L'\0';
+ End ++;
+ }
+
+ mLineBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrTokenField (
+ IN CHAR16 *String OPTIONAL,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Begin;
+ CHAR16 *End;
+
+
+ Begin = (String == NULL) ? mFieldBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ if (*Begin == L'\0') {
+ mFieldBuffer = NULL;
+ return NULL;
+ }
+
+ End = StrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != L'\0')) {
+ *End = L'\0';
+ End ++;
+ }
+
+ mFieldBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenLine (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenLine (String, CharSet);
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenLine (
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenLine (NULL, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenField (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenField (String, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenField (
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenField (NULL, CharSet);
+}
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenAfter (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ )
+{
+ CHAR16 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*Str != 0) {
+ Str ++;
+ }
+ *Str = Patch;
+
+ while (*(Str ++) != '\0') {
+ if (*Str == 0) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenBefore (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ )
+{
+ CHAR16 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*(Str --) != '\0') {
+ if ((*Str == 0) || (*Str == Patch)) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+CHAR8 *mAsciiLineBuffer = NULL;
+CHAR8 *mAsciiFieldBuffer = NULL;
+
+/**
+
+ Find the first substring.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+UINTN
+EFIAPI
+AsciiStrSpn (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ UINTN Count;
+ CHAR8 *Str1;
+ CHAR8 *Str2;
+
+ Count = 0;
+
+ for (Str1 = String; *Str1 != '\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != '\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ break;
+ }
+ }
+
+ if (*Str2 == '\0') {
+ return Count;
+ }
+
+ Count ++;
+ }
+
+ return Count;
+}
+
+/**
+ Searches a string for the first occurrence of a character contained in a
+ specified buffer.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrBrk (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Str1;
+ CHAR8 *Str2;
+
+ for (Str1 = String; *Str1 != '\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != '\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ return (CHAR8 *) Str1;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrTokenLine (
+ IN CHAR8 *String OPTIONAL,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Begin;
+ CHAR8 *End;
+
+ Begin = (String == NULL) ? mAsciiLineBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ Begin += AsciiStrSpn (Begin, CharSet);
+ if (*Begin == '\0') {
+ mAsciiLineBuffer = NULL;
+ return NULL;
+ }
+
+ End = AsciiStrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != '\0')) {
+ *End = '\0';
+ End ++;
+ }
+
+ mAsciiLineBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrTokenField (
+ IN CHAR8 *String OPTIONAL,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Begin;
+ CHAR8 *End;
+
+
+ Begin = (String == NULL) ? mAsciiFieldBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ if (*Begin == '\0') {
+ mAsciiFieldBuffer = NULL;
+ return NULL;
+ }
+
+ End = AsciiStrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != '\0')) {
+ *End = '\0';
+ End ++;
+ }
+
+ mAsciiFieldBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenLine (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenLine (String, CharSet);
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenLine (
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenLine (NULL, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenField (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenField (String, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenField (
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenField (NULL, CharSet);
+}
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenAfter (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ )
+{
+ CHAR8 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*Str != 0) {
+ Str ++;
+ }
+ *Str = Patch;
+
+ while (*(Str ++) != '\0') {
+ if (*Str == 0) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenBefore (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ )
+{
+ CHAR8 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*(Str --) != '\0') {
+ if ((*Str == 0) || (*Str == Patch)) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
new file mode 100644
index 000000000..dd881a021
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
@@ -0,0 +1,754 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+ Set the current coordinates of the cursor position.
+
+ @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+ @param Column The position to set the cursor to.
+ @param Row The position to set the cursor to.
+ @param LineLength Length of a line.
+ @param TotalRow Total row of a screen.
+ @param Str Point to the string.
+ @param StrPos The position of the string.
+ @param Len The length of the string.
+
+**/
+VOID
+EFIAPI
+SetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ IN UINTN Column,
+ IN INTN Row,
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN CHAR16 *Str,
+ IN UINTN StrPos,
+ IN UINTN Len
+ );
+
+/**
+
+ 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
+EFIAPI
+WaitForSingleEvent (
+ IN EFI_EVENT Event,
+ IN UINT64 Timeout OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ 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;
+}
+
+/**
+
+ Move the cursor position one character backward.
+
+ @param LineLength Length of a line. Get it by calling QueryMode
+ @param Column Current column of the cursor position
+ @param Row Current row of the cursor position
+
+**/
+VOID
+EFIAPI
+ConMoveCursorBackward (
+ IN UINTN LineLength,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ ASSERT (Column != NULL);
+ ASSERT (Row != NULL);
+ //
+ // If current column is 0, move to the last column of the previous line,
+ // otherwise, just decrement column.
+ //
+ if (*Column == 0) {
+ (*Column) = LineLength - 1;
+ //
+ // if (*Row > 0) {
+ //
+ (*Row)--;
+ //
+ // }
+ //
+ } else {
+ (*Column)--;
+ }
+}
+
+/**
+
+ Move the cursor position one character backward.
+
+ @param LineLength Length of a line. Get it by calling QueryMode
+ @param TotalRow Total row of a screen, get by calling QueryMode
+ @param Column Current column of the cursor position
+ @param Row Current row of the cursor position
+
+**/
+VOID
+EFIAPI
+ConMoveCursorForward (
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ ASSERT (Column != NULL);
+ ASSERT (Row != NULL);
+ //
+ // If current column is at line end, move to the first column of the nest
+ // line, otherwise, just increment column.
+ //
+ (*Column)++;
+ if (*Column >= LineLength) {
+ (*Column) = 0;
+ if ((*Row) < TotalRow - 1) {
+ (*Row)++;
+ }
+ }
+}
+
+CHAR16 mBackupSpace[EFI_DEBUG_INPUS_BUFFER_SIZE];
+CHAR16 mInputBufferHistory[EFI_DEBUG_INPUS_BUFFER_SIZE];
+
+/**
+
+ Get user input.
+
+ @param Prompt The prompt string.
+ @param InStr Point to the input string.
+ @param StrLength The max length of string user can input.
+
+**/
+VOID
+EFIAPI
+Input (
+ IN CHAR16 *Prompt OPTIONAL,
+ OUT CHAR16 *InStr,
+ IN UINTN StrLength
+ )
+{
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ BOOLEAN Done;
+ UINTN Column;
+ UINTN Row;
+ UINTN StartColumn;
+ UINTN Update;
+ UINTN Delete;
+ UINTN Len;
+ UINTN StrPos;
+ UINTN Index;
+ UINTN LineLength;
+ UINTN TotalRow;
+ UINTN SkipLength;
+ UINTN OutputLength;
+ UINTN TailRow;
+ UINTN TailColumn;
+ EFI_INPUT_KEY Key;
+ BOOLEAN InsertMode;
+ BOOLEAN NeedAdjust;
+ UINTN SubIndex;
+ CHAR16 *CommandStr;
+
+ ConOut = gST->ConOut;
+ ConIn = gST->ConIn;
+
+ ASSERT (ConOut != NULL);
+ ASSERT (ConIn != NULL);
+ ASSERT (InStr != NULL);
+
+ if (Prompt != NULL) {
+ ConOut->OutputString (ConOut, Prompt);
+ }
+ //
+ // Read a line from the console
+ //
+ Len = 0;
+ StrPos = 0;
+ OutputLength = 0;
+ Update = 0;
+ Delete = 0;
+ InsertMode = TRUE;
+ NeedAdjust = FALSE;
+
+ //
+ // If buffer is not large enough to hold a CHAR16, do nothing.
+ //
+ if (StrLength < 1) {
+ return ;
+ }
+ //
+ // Get the screen setting and the current cursor location
+ //
+ StartColumn = ConOut->Mode->CursorColumn;
+ Column = StartColumn;
+ Row = ConOut->Mode->CursorRow;
+ ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
+ if (LineLength == 0) {
+ return ;
+ }
+
+ SetMem (InStr, StrLength * sizeof (CHAR16), 0);
+ Done = FALSE;
+ do {
+ //
+ // Read a key
+ //
+ WaitForSingleEvent (ConIn->WaitForKey, 0);
+ ConIn->ReadKeyStroke (ConIn, &Key);
+
+ switch (Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ //
+ // All done, print a newline at the end of the string
+ //
+ TailRow = Row + (Len - StrPos + Column) / LineLength;
+ TailColumn = (Len - StrPos + Column) % LineLength;
+ Done = TRUE;
+ break;
+
+ case CHAR_BACKSPACE:
+ if (StrPos != 0) {
+ //
+ // If not move back beyond string beginning, move all characters behind
+ // the current position one character forward
+ //
+ StrPos -= 1;
+ Update = StrPos;
+ Delete = 1;
+ CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
+
+ //
+ // Adjust the current column and row
+ //
+ ConMoveCursorBackward (LineLength, &Column, &Row);
+
+ NeedAdjust = TRUE;
+ }
+ break;
+
+ default:
+ if (Key.UnicodeChar >= ' ') {
+ //
+ // If we are at the buffer's end, drop the key
+ //
+ if (Len == StrLength - 1 && (InsertMode || StrPos == Len)) {
+ break;
+ }
+ //
+ // If in insert mode, move all characters behind the current position
+ // one character backward to make space for this character. Then store
+ // the character.
+ //
+ if (InsertMode) {
+ for (Index = Len; Index > StrPos; Index -= 1) {
+ InStr[Index] = InStr[Index - 1];
+ }
+ }
+
+ InStr[StrPos] = Key.UnicodeChar;
+ Update = StrPos;
+
+ StrPos += 1;
+ OutputLength = 1;
+ }
+ break;
+
+ case 0:
+ switch (Key.ScanCode) {
+ case SCAN_DELETE:
+ //
+ // Move characters behind current position one character forward
+ //
+ if (Len != 0) {
+ Update = StrPos;
+ Delete = 1;
+ CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
+
+ NeedAdjust = TRUE;
+ }
+ break;
+
+ case SCAN_LEFT:
+ //
+ // Adjust current cursor position
+ //
+ if (StrPos != 0) {
+ StrPos -= 1;
+ ConMoveCursorBackward (LineLength, &Column, &Row);
+ }
+ break;
+
+ case SCAN_RIGHT:
+ //
+ // Adjust current cursor position
+ //
+ if (StrPos < Len) {
+ StrPos += 1;
+ ConMoveCursorForward (LineLength, TotalRow, &Column, &Row);
+ }
+ break;
+
+ case SCAN_HOME:
+ //
+ // Move current cursor position to the beginning of the command line
+ //
+ Row -= (StrPos + StartColumn) / LineLength;
+ Column = StartColumn;
+ StrPos = 0;
+ break;
+
+ case SCAN_END:
+ //
+ // Move current cursor position to the end of the command line
+ //
+ TailRow = Row + (Len - StrPos + Column) / LineLength;
+ TailColumn = (Len - StrPos + Column) % LineLength;
+ Row = TailRow;
+ Column = TailColumn;
+ StrPos = Len;
+ break;
+
+ case SCAN_ESC:
+ //
+ // Prepare to clear the current command line
+ //
+ InStr[0] = 0;
+ Update = 0;
+ Delete = Len;
+ Row -= (StrPos + StartColumn) / LineLength;
+ Column = StartColumn;
+ OutputLength = 0;
+
+ NeedAdjust = TRUE;
+ break;
+
+ case SCAN_INSERT:
+ //
+ // Toggle the SEnvInsertMode flag
+ //
+ InsertMode = (BOOLEAN)!InsertMode;
+ break;
+
+ case SCAN_UP:
+ case SCAN_DOWN:
+ //
+ // show history
+ //
+ CopyMem (InStr, mInputBufferHistory, StrLength * sizeof(CHAR16));
+ StrPos = StrLen (mInputBufferHistory);
+ Update = 0;
+ Delete = 0;
+ OutputLength = 0;
+
+ TailRow = Row + (StrPos + StartColumn) / LineLength;
+ TailColumn = (StrPos + StartColumn) % LineLength;
+ Row = TailRow;
+ Column = TailColumn;
+ NeedAdjust = FALSE;
+
+ ConOut->SetCursorPosition (ConOut, StartColumn, Row);
+ for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
+ mBackupSpace[SubIndex] = L' ';
+ }
+ EDBPrint (mBackupSpace);
+ SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
+
+ ConOut->SetCursorPosition (ConOut, StartColumn, Row);
+ Len = StrPos;
+
+ break;
+
+ case SCAN_F1:
+ case SCAN_F2:
+ case SCAN_F3:
+ case SCAN_F4:
+ case SCAN_F5:
+ case SCAN_F6:
+ case SCAN_F7:
+ case SCAN_F8:
+ case SCAN_F9:
+ case SCAN_F10:
+ case SCAN_F11:
+ case SCAN_F12:
+ CommandStr = GetCommandNameByKey (Key);
+ if (CommandStr != NULL) {
+ StrnCpyS (InStr, StrLength, CommandStr, StrLength - 1);
+ return ;
+ }
+ break;
+ }
+ }
+
+ if (Done) {
+ break;
+ }
+ //
+ // If we need to update the output do so now
+ //
+ if (Update != -1) {
+ if (NeedAdjust) {
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
+ mBackupSpace[SubIndex] = L' ';
+ }
+ EDBPrint (mBackupSpace);
+ SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ NeedAdjust = FALSE;
+ }
+ EDBPrint (InStr + Update);
+ Len = StrLen (InStr);
+
+ if (Delete != 0) {
+ SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
+ }
+
+ if (StrPos > Len) {
+ StrPos = Len;
+ }
+
+ Update = (UINTN) -1;
+
+ //
+ // After using print to reflect newly updates, if we're not using
+ // BACKSPACE and DELETE, we need to move the cursor position forward,
+ // so adjust row and column here.
+ //
+ if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
+ //
+ // Calulate row and column of the tail of current string
+ //
+ TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
+ TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
+
+ //
+ // If the tail of string reaches screen end, screen rolls up, so if
+ // Row does not equal TailRow, Row should be decremented
+ //
+ // (if we are recalling commands using UPPER and DOWN key, and if the
+ // old command is too long to fit the screen, TailColumn must be 79.
+ //
+ if (TailColumn == 0 && TailRow >= TotalRow && (UINTN) Row != TailRow) {
+ Row--;
+ }
+ //
+ // Calculate the cursor position after current operation. If cursor
+ // reaches line end, update both row and column, otherwise, only
+ // column will be changed.
+ //
+ if (Column + OutputLength >= LineLength) {
+ SkipLength = OutputLength - (LineLength - Column);
+
+ Row += SkipLength / LineLength + 1;
+ if ((UINTN) Row > TotalRow - 1) {
+ Row = TotalRow - 1;
+ }
+
+ Column = SkipLength % LineLength;
+ } else {
+ Column += OutputLength;
+ }
+ }
+
+ Delete = 0;
+ }
+ //
+ // Set the cursor position for this key
+ //
+ SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
+ } while (!Done);
+
+ CopyMem (mInputBufferHistory, InStr, StrLength * sizeof(CHAR16));
+
+ //
+ // Return the data to the caller
+ //
+ return ;
+}
+
+/**
+ Set the current coordinates of the cursor position.
+
+ @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+ @param Column The position to set the cursor to.
+ @param Row The position to set the cursor to.
+ @param LineLength Length of a line.
+ @param TotalRow Total row of a screen.
+ @param Str Point to the string.
+ @param StrPos The position of the string.
+ @param Len The length of the string.
+
+**/
+VOID
+EFIAPI
+SetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ IN UINTN Column,
+ IN INTN Row,
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN CHAR16 *Str,
+ IN UINTN StrPos,
+ IN UINTN Len
+ )
+{
+ CHAR16 Backup;
+
+ ASSERT (ConOut != NULL);
+ ASSERT (Str != NULL);
+
+ Backup = 0;
+ if (Row >= 0) {
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ return ;
+ }
+
+ if (Len - StrPos > Column * Row) {
+ Backup = *(Str + StrPos + Column * Row);
+ *(Str + StrPos + Column * Row) = 0;
+ }
+
+ EDBPrint (L"%s", Str + StrPos);
+ if (Len - StrPos > Column * Row) {
+ *(Str + StrPos + Column * Row) = Backup;
+ }
+
+ ConOut->SetCursorPosition (ConOut, 0, 0);
+}
+
+/**
+
+ SetPageBreak.
+
+**/
+BOOLEAN
+EFIAPI
+SetPageBreak (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 Str[3];
+ BOOLEAN OmitPrint;
+
+ //
+ // Check
+ //
+ if (!mDebuggerPrivate.EnablePageBreak) {
+ return FALSE;
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, L"Press ENTER to continue, 'q' to exit:");
+
+ OmitPrint = FALSE;
+ //
+ // Wait for user input
+ //
+ Str[0] = ' ';
+ Str[1] = 0;
+ Str[2] = 0;
+ for (;;) {
+ WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ //
+ // handle control keys
+ //
+ if (Key.UnicodeChar == CHAR_NULL) {
+ if (Key.ScanCode == SCAN_ESC) {
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+ OmitPrint = TRUE;
+ break;
+ }
+
+ continue;
+ }
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+ break;
+ }
+ //
+ // Echo input
+ //
+ Str[1] = Key.UnicodeChar;
+ if (Str[1] == CHAR_BACKSPACE) {
+ continue;
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, Str);
+
+ if ((Str[1] == L'q') || (Str[1] == L'Q')) {
+ OmitPrint = TRUE;
+ } else {
+ OmitPrint = FALSE;
+ }
+
+ Str[0] = CHAR_BACKSPACE;
+ }
+
+ return OmitPrint;
+}
+
+/**
+ Print a Unicode string to the output device.
+
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBPrint (
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+ CHAR16 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ if (gST->ConOut != NULL) {
+ //
+ // To be extra safe make sure ConOut has been initialized
+ //
+ gST->ConOut->OutputString (gST->ConOut, Buffer);
+ }
+
+ return Return;
+}
+
+/**
+ Print a Unicode string to the output buffer.
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrint (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+
+ ASSERT (BufferSize > 0);
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer, (UINTN)BufferSize, Format, Marker);
+ VA_END (Marker);
+
+ return Return;
+}
+
+/**
+ Print a Unicode string to the output buffer with specified offset..
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Offset The offset of the buffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrintWithOffset (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN UINTN Offset,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+
+ ASSERT (BufferSize - (Offset * sizeof(CHAR16)) > 0);
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer + Offset, (UINTN)(BufferSize - (Offset * sizeof(CHAR16))), Format, Marker);
+ VA_END (Marker);
+
+ return Return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c
new file mode 100644
index 000000000..90a9b9fbd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c
@@ -0,0 +1,2230 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Load single symbol entry.
+
+ @param Object - Symbol file object
+ @param Name - Symbol name
+ @param ObjName - Object name
+ @param Address - Symbol address
+ @param Type - Symbol type
+
+ @retval EFI_SUCCESS - add single symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolSingleEntry (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN CHAR8 *Name,
+ IN CHAR8 *ObjName,
+ IN UINTN Address,
+ IN EFI_DEBUGGER_SYMBOL_TYPE Type
+ )
+{
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ //
+ // Check Count VS MaxCount
+ //
+ if (Object->EntryCount >= Object->MaxEntryCount) {
+ //
+ // reallocate (for codebuffer too)
+ // TBD
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Entry = &Object->Entry[Object->EntryCount];
+
+ //
+ // Print Debug info
+ //
+ if (sizeof (UINTN) == sizeof(UINT64)) {
+ DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%016lx (%d)\n", Name, (UINT64)Address, (UINTN)Type));
+ } else {
+ DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%08x (%d)\n", Name, Address, (UINTN)Type));
+ }
+
+ //
+ // Fill the entry - name, RVA, type
+ //
+ AsciiStrnCpyS (Entry->Name, sizeof(Entry->Name), Name, sizeof(Entry->Name) - 1);
+ if (ObjName != NULL) {
+ AsciiStrnCpyS (Entry->ObjName, sizeof(Entry->ObjName), ObjName, sizeof(Entry->ObjName) - 1);
+ }
+ Entry->Rva = Address % EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE;
+ Entry->Type = Type;
+
+ //
+ // Increase Count
+ //
+ Object->EntryCount++;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+typedef enum {
+ EdbEbcMapParseStateUninitialized,
+ EdbEbcMapParseStateSymbolStart,
+ EdbEbcMapParseStateSeHandlerSymbol,
+ EdbEbcMapParseStateFunctionSymbol,
+ EdbEbcMapParseStateVarbssInitSymbol,
+ EdbEbcMapParseStateCrtSymbol,
+ EdbEbcMapParseStateVariableSymbol,
+ EdbEbcMapParseStateStaticFunctionSymbol,
+ EdbEbcMapParseStateMax,
+} EDB_EBC_MAP_PARSE_STATE;
+
+typedef enum {
+ EdbEbcSymbolParseStateUninitialized,
+ EdbEbcSymbolParseStateReadyForName,
+ EdbEbcSymbolParseStateReadyForRVA,
+ EdbEbcSymbolParseStateReadyForType,
+ EdbEbcSymbolParseStateReadyForObject,
+ EdbEbcSymbolParseStateMax,
+} EDB_EBC_SYMBOL_PARSE_STATE;
+
+/**
+
+ The following code depends on the MAP file generated by IEC compiler (actually Microsoft linker).
+
+ Sample as follows: EbcTest.map
+===============================================================================
+ EbcTest
+
+ Timestamp is 45b02718 (Fri Jan 19 10:04:08 2007)
+
+ Preferred load address is 10000000
+
+ Start Length Name Class
+ 0001:00000000 00000370H .text CODE
+ 0002:00000000 00000030H _VARBSS_INIT CODE
+ 0003:00000000 00000004H .CRT$TSA DATA
+ 0003:00000004 00000004H .CRT$TSC DATA
+ 0003:00000008 00000004H .CRT$X DATA
+ 0003:0000000c 00000008H .CRT$XCU DATA
+ 0003:00000014 00000004H .CRT$Z DATA
+ 0003:00000020 0000001cH .rdata DATA
+ 0003:0000003c 00000000H .edata DATA
+ 0003:0000003c 00000056H .rdata$debug DATA
+ 0004:00000000 00000070H .data DATA
+ 0004:00000070 00000020H .bss DATA
+
+ Address Publics by Value Rva+Base Lib:Object
+
+ 0000:00000000 ___safe_se_handler_table 00000000 <absolute>
+ 0000:00000000 ___safe_se_handler_count 00000000 <absolute>
+ 0001:00000042 TestSubRoutine 10000442 f EbcTest.obj
+ 0001:0000011a EfiMain 1000051a f EbcTest.obj
+ 0001:00000200 TestSubRoutineSub 10000600 f EbcTestSub.obj
+ 0001:00000220 EfiStart 10000620 f EbcLib:EbcLib.obj
+ 0002:00000000 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b02717 10000800 f EbcTest.obj
+ 0002:00000020 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTestSub$c45af77f3 10000820 f EbcTestSub.obj
+ 0003:00000000 CrtThunkBegin 10000a00 EbcLib:EbcLib.obj
+ 0003:00000004 CrtThunkEnd 10000a04 EbcLib:EbcLib.obj
+ 0003:00000008 CrtBegin 10000a08 EbcLib:EbcLib.obj
+ 0003:00000014 CrtEnd 10000a14 EbcLib:EbcLib.obj
+ 0004:00000070 TestStr 10000c70 EbcTest.obj
+ 0004:00000078 TestVariable1 10000c78 EbcTest.obj
+ 0004:00000080 TestSubVariableSub 10000c80 EbcTestSub.obj
+
+ entry point at 0001:00000220
+
+ Static symbols
+
+ 0001:00000000 TestSubRoutine2 10000400 f EbcTest.obj
+===============================================================================
+
+**/
+
+/**
+
+ Load symbol entry by Iec.
+
+ @param Object - Symbol file object
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - add symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolEntryByIec (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ EDB_EBC_MAP_PARSE_STATE MapParseState;
+ EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState;
+ CHAR8 *Name;
+ CHAR8 *ObjName;
+ UINTN Address;
+ EFI_DEBUGGER_SYMBOL_TYPE Type;
+
+
+ //
+ // Begin to parse the Buffer
+ //
+ LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
+ MapParseState = EdbEbcMapParseStateUninitialized;
+ //
+ // Check each line
+ //
+ while (LineBuffer != NULL) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, " ");
+ SymbolParseState = EdbEbcSymbolParseStateUninitialized;
+ //
+ // Init entry value
+ //
+ Name = NULL;
+ ObjName = NULL;
+ Address = 0;
+ Type = EfiDebuggerSymbolTypeMax;
+ //
+ // Check each field
+ //
+ while (FieldBuffer != NULL) {
+ if (AsciiStrCmp (FieldBuffer, "") == 0) {
+ FieldBuffer = AsciiStrGetNextTokenField (" ");
+ continue;
+ }
+ //
+ // check "Address"
+ //
+ if (AsciiStrCmp (FieldBuffer, "Address") == 0) {
+ MapParseState = EdbEbcMapParseStateSymbolStart;
+ break;
+ }
+ //
+ // check "Static"
+ //
+ if (AsciiStrCmp (FieldBuffer, "Static") == 0) {
+ MapParseState = EdbEbcMapParseStateStaticFunctionSymbol;
+ break;
+ }
+
+ if (MapParseState == EdbEbcMapParseStateUninitialized) {
+ //
+ // Do not parse anything until get "Address" or "Static"
+ //
+ break;
+ }
+ if (AsciiStrCmp (FieldBuffer, "entry") == 0) {
+ //
+ // Skip entry point
+ //
+ break;
+ }
+
+ //
+ // Now we start to parse this line for Name, Address, and Object
+ //
+ switch (SymbolParseState) {
+ case EdbEbcSymbolParseStateUninitialized:
+ //
+ // Get the Address
+ //
+ SymbolParseState = EdbEbcSymbolParseStateReadyForName;
+ break;
+ case EdbEbcSymbolParseStateReadyForName:
+ //
+ // Get the Name
+ //
+ if (AsciiStrnCmp (FieldBuffer, "___safe_se_handler", AsciiStrLen ("___safe_se_handler")) == 0) {
+ //
+ // skip SeHandler
+ //
+ MapParseState = EdbEbcMapParseStateSeHandlerSymbol;
+ goto ExitFieldParse;
+ } else if (AsciiStrnCmp (FieldBuffer, "varbss_init", AsciiStrLen ("varbss_init")) == 0) {
+ //
+ // check VarbssInit
+ //
+ MapParseState = EdbEbcMapParseStateVarbssInitSymbol;
+// goto ExitFieldParse;
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ } else if (AsciiStrnCmp (FieldBuffer, "Crt", AsciiStrLen ("Crt")) == 0) {
+ //
+ // check Crt
+ //
+ MapParseState = EdbEbcMapParseStateCrtSymbol;
+// goto ExitFieldParse;
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ } else {
+ //
+ // Now, it is normal function
+ //
+ switch (MapParseState) {
+ case EdbEbcMapParseStateSeHandlerSymbol:
+ MapParseState = EdbEbcMapParseStateFunctionSymbol;
+ break;
+ case EdbEbcMapParseStateCrtSymbol:
+ MapParseState = EdbEbcMapParseStateVariableSymbol;
+ break;
+ case EdbEbcMapParseStateFunctionSymbol:
+ case EdbEbcMapParseStateVariableSymbol:
+ case EdbEbcMapParseStateStaticFunctionSymbol:
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ }
+ break;
+ case EdbEbcSymbolParseStateReadyForRVA:
+ //
+ // Get the RVA
+ //
+ Address = AsciiXtoi (FieldBuffer);
+ SymbolParseState = EdbEbcSymbolParseStateReadyForType;
+ break;
+ case EdbEbcSymbolParseStateReadyForType:
+ //
+ // Get the Type. This is optional, only for "f".
+ //
+ if (AsciiStrCmp (FieldBuffer, "f") == 0) {
+ SymbolParseState = EdbEbcSymbolParseStateReadyForObject;
+ switch (MapParseState) {
+ case EdbEbcMapParseStateFunctionSymbol:
+ case EdbEbcMapParseStateVarbssInitSymbol:
+ Type = EfiDebuggerSymbolFunction;
+ break;
+ case EdbEbcMapParseStateStaticFunctionSymbol:
+ Type = EfiDebuggerSymbolStaticFunction;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+ }
+ //
+ // Else it should be Object.
+ // let it bypass here
+ //
+ case EdbEbcSymbolParseStateReadyForObject:
+ switch (Type) {
+ case EfiDebuggerSymbolTypeMax:
+ switch (MapParseState) {
+ case EdbEbcMapParseStateVariableSymbol:
+ case EdbEbcMapParseStateCrtSymbol:
+ Type = EfiDebuggerSymbolGlobalVariable;
+ break;
+ case EdbEbcMapParseStateSeHandlerSymbol:
+ //
+ // do nothing here
+ //
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+ case EfiDebuggerSymbolFunction:
+ case EfiDebuggerSymbolStaticFunction:
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ //
+ // Get the Object
+ //
+ ObjName = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateUninitialized;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Get the next field
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (" ");
+ }
+
+ //
+ // Add the entry if we get everything.
+ //
+ if ((Name != NULL) && (Type != EfiDebuggerSymbolTypeMax)) {
+ EdbLoadSymbolSingleEntry (Object, Name, ObjName, Address, Type);
+ }
+
+ExitFieldParse:
+ //
+ // Get the next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Load symbol entry.
+
+ @param Object - Symbol file object
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - add symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolEntry (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ //
+ // MAP file format depends on the compiler (actually linker).
+ //
+ // It is possible to check the different MAP file format in this routine.
+ // Now only IEC is supported.
+ //
+ return EdbLoadSymbolEntryByIec (Object, BufferSize, Buffer);
+}
+
+/**
+
+ Find symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param Index - Symbol file index
+
+ @return Object
+
+**/
+EFI_DEBUGGER_SYMBOL_OBJECT *
+EdbFindSymbolFile (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index OPTIONAL
+ )
+{
+ UINTN ObjectIndex;
+
+ //
+ // Check each Object
+ //
+ for (ObjectIndex = 0; ObjectIndex < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ if (StrCmp (FileName, DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex].Name) == 0) {
+ //
+ // Name match, found it
+ //
+ if (Index != NULL) {
+ *Index = ObjectIndex;
+ }
+ return &DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex];
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
+
+/**
+
+ Find symbol by address.
+
+ @param Address - Symbol address
+ @param Type - Search type
+ @param RetObject - Symbol object
+ @param RetEntry - Symbol entry
+
+ @return Nearest symbol address
+
+**/
+UINTN
+EbdFindSymbolAddress (
+ IN UINTN Address,
+ IN EDB_MATCH_SYMBOL_TYPE Type,
+ OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
+ OUT EFI_DEBUGGER_SYMBOL_ENTRY **RetEntry
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ UINTN CandidateLowerAddress;
+ UINTN CandidateUpperAddress;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ EFI_DEBUGGER_SYMBOL_ENTRY *LowEntry;
+ EFI_DEBUGGER_SYMBOL_ENTRY *UpperEntry;
+ EFI_DEBUGGER_SYMBOL_OBJECT *LowObject;
+ EFI_DEBUGGER_SYMBOL_OBJECT *UpperObject;
+
+ if ((Type < 0) || (Type >= EdbMatchSymbolTypeMax)) {
+ return 0;
+ }
+
+ //
+ // Init
+ //
+ CandidateLowerAddress = 0;
+ CandidateUpperAddress = (UINTN)-1;
+ LowEntry = NULL;
+ UpperEntry = NULL;
+ LowObject = NULL;
+ UpperObject = NULL;
+
+ //
+ // Go through each object
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (Index = 0; Index < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; Index++, Object++) {
+ if (Object->EntryCount == 0) {
+ continue;
+ }
+ //
+ // Go through each entry
+ //
+ Entry = Object->Entry;
+ for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
+ if (Address != Entry->Rva + Object->BaseAddress) {
+ //
+ // Check for nearest address
+ //
+ if (Address > Entry->Rva + Object->BaseAddress) {
+ //
+ // Record it if Current RVA < Address
+ //
+ if (CandidateLowerAddress < Entry->Rva + Object->BaseAddress) {
+ CandidateLowerAddress = Entry->Rva + Object->BaseAddress;
+ LowEntry = Entry;
+ LowObject = Object;
+ }
+ } else {
+ //
+ // Record it if Current RVA > Address
+ //
+ if (CandidateUpperAddress > Entry->Rva + Object->BaseAddress) {
+ CandidateUpperAddress = Entry->Rva + Object->BaseAddress;
+ UpperEntry = Entry;
+ UpperObject = Object;
+ }
+ }
+ continue;
+ }
+ //
+ // address match, return directly
+ //
+ *RetEntry = Entry;
+ *RetObject = Object;
+ return Address;
+ }
+ }
+
+ //
+ // No Match, provide latest symbol
+ //
+
+ if ((Address - CandidateLowerAddress) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
+ //
+ // Check for lower address
+ //
+ if (((Type == EdbMatchSymbolTypeNearestAddress) &&
+ ((CandidateUpperAddress - Address) > (Address - CandidateLowerAddress))) ||
+ (Type == EdbMatchSymbolTypeLowerAddress)) {
+ //
+ // return nearest lower address
+ //
+ *RetEntry = LowEntry;
+ *RetObject = LowObject;
+ return CandidateLowerAddress;
+ }
+ }
+
+ if ((CandidateUpperAddress - Address) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
+ //
+ // Check for upper address
+ //
+ if (((Type == EdbMatchSymbolTypeNearestAddress) &&
+ ((CandidateUpperAddress - Address) < (Address - CandidateLowerAddress))) ||
+ (Type == EdbMatchSymbolTypeUpperAddress)) {
+ //
+ // return nearest upper address
+ //
+ *RetEntry = UpperEntry;
+ *RetObject = UpperObject;
+ return CandidateUpperAddress;
+ }
+ }
+
+ //
+ // No match and nearest one, return NULL
+ //
+ return 0;
+}
+
+/**
+
+ Unload symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+
+ @retval EFI_SUCCESS - unload symbol successfully
+
+**/
+EFI_STATUS
+EdbUnloadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_ENTRY *OldEntry;
+ UINTN OldEntryCount;
+ UINTN MaxEntryCount;
+ VOID **OldSourceBuffer;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Record old data
+ //
+ Object = DebuggerPrivate->DebuggerSymbolContext.Object;
+ OldEntry = Object->Entry;
+ OldSourceBuffer = Object->SourceBuffer;
+ MaxEntryCount = Object->MaxEntryCount;
+ OldEntryCount = Object->EntryCount;
+
+ //
+ // Remove the matched Object
+ //
+ for (Index = ObjectIndex; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount - 1; Index++) {
+ CopyMem (&Object[Index], &Object[Index + 1], sizeof(EFI_DEBUGGER_SYMBOL_OBJECT));
+ }
+ ZeroMem (&Object[Index], sizeof(Object[Index]));
+
+ //
+ // Move old data to new place
+ //
+ Object[Index].Entry = OldEntry;
+ Object[Index].SourceBuffer = OldSourceBuffer;
+ Object[Index].MaxEntryCount = MaxEntryCount;
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount --;
+
+ //
+ // Clean old entry data
+ //
+ for (Index = 0; Index < OldEntryCount; Index++) {
+ ZeroMem (&OldEntry[Index], sizeof(OldEntry[Index]));
+ }
+
+ //
+ // Free OldSourceBuffer
+ //
+ for (Index = 0; OldSourceBuffer[Index] != NULL; Index++) {
+ gBS->FreePool (OldSourceBuffer[Index]);
+ OldSourceBuffer[Index] = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Load symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - load symbol successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_STATUS Status;
+
+ //
+ // Check duplicated File
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
+ if (Object != NULL) {
+ Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Unload Duplicated Symbol File Error!\n"));
+ return Status;
+ }
+ }
+
+ //
+ // Check Count VS MaxCount
+ //
+ if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount >= DebuggerPrivate->DebuggerSymbolContext.MaxObjectCount) {
+ //
+ // reallocate
+ // TBD
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Object = &DebuggerPrivate->DebuggerSymbolContext.Object[DebuggerPrivate->DebuggerSymbolContext.ObjectCount];
+
+ //
+ // Init Object
+ //
+ Object->EntryCount = 0;
+ Object->MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
+
+ //
+ // Load SymbolEntry
+ //
+ DEBUG ((DEBUG_ERROR, "Symbol File: %s\n", FileName));
+ Status = EdbLoadSymbolEntry (Object, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill Object value
+ //
+ StrnCpyS (Object->Name, sizeof(Object->Name) / sizeof(CHAR16),
+ FileName, (sizeof(Object->Name) / sizeof(CHAR16)) - 1);
+ Object->BaseAddress = 0;
+
+ //
+ // Increase the object count
+ //
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Located PDB path name in PE image.
+
+ @param ImageBase - base of PE to search
+
+ @return Pointer into image at offset of PDB file name if PDB file name is found,
+ Otherwise a pointer to an empty string.
+
+**/
+CHAR8 *
+GetPdbPath (
+ VOID *ImageBase
+ )
+{
+ CHAR8 *PdbPath;
+ UINT32 DirCount;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
+ EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHdr32;
+ EFI_IMAGE_OPTIONAL_HEADER64 *OptionalHdr64;
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
+ VOID *CodeViewEntryPointer;
+
+ //
+ // Init value
+ //
+ CodeViewEntryPointer = NULL;
+ PdbPath = NULL;
+ DosHdr = ImageBase;
+
+ //
+ // Check magic
+ //
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ return NULL;
+ }
+ NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
+ //
+ // Check Machine, filter for EBC
+ //
+ if (NtHdr->Pe32.FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) {
+ //
+ // If not EBC, return NULL
+ //
+ return NULL;
+ }
+
+ //
+ // Get DirectoryEntry
+ // EBC spec says PE32+, but implementation uses PE32. So check dynamically here.
+ //
+ if (NtHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ OptionalHdr32 = (VOID *) &NtHdr->Pe32.OptionalHeader;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else if (NtHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ OptionalHdr64 = (VOID *) &NtHdr->Pe32Plus.OptionalHeader;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else {
+ return NULL;
+ }
+ if (DirectoryEntry->VirtualAddress == 0) {
+ return NULL;
+ }
+ //
+ // Go through DirectoryEntry
+ //
+ for (DirCount = 0;
+ (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
+ DirCount++
+ ) {
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
+ if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+ //
+ // Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported.
+ //
+ CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
+ switch (*(UINT32 *) CodeViewEntryPointer) {
+ case CODEVIEW_SIGNATURE_NB10:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
+ break;
+ case CODEVIEW_SIGNATURE_RSDS:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Done successfully
+ //
+ return PdbPath;
+}
+
+/**
+
+ Check whether PDB file and MAP file have same name.
+
+ @param PdbFileName - PDB file name
+ @param MapFileName - MAP file name
+
+ @retval TRUE - PDB and MAP file name match
+ @retval FALSE - PDB and MAP file name not match
+
+**/
+BOOLEAN
+MatchPdbAndMap (
+ IN CHAR8 *PdbFileName,
+ IN CHAR16 *MapFileName
+ )
+{
+ UINTN PdbNameSize;
+ UINTN MapNameSize;
+ CHAR8 *PurePdbFileName;
+ UINTN Index;
+
+ //
+ // remove dir name
+ //
+ PurePdbFileName = PdbFileName;
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if (PdbFileName[Index] == '\\') {
+ PurePdbFileName = &PdbFileName[Index + 1];
+ }
+ }
+ PdbFileName = PurePdbFileName;
+
+ //
+ // get size
+ //
+ PdbNameSize = AsciiStrLen (PdbFileName);
+ MapNameSize = StrLen (MapFileName);
+
+ if (PdbNameSize != MapNameSize) {
+ return FALSE;
+ }
+
+ //
+ // check the name
+ //
+ for (Index = 0; Index < MapNameSize - 4; Index++) {
+ if ((PdbFileName[Index] | 0x20) != (MapFileName[Index] | 0x20)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//
+// BUGBUG: work-around start
+//
+typedef struct {
+ EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
+ volatile UINT32 UpdateStatus;
+ UINT32 TableSize;
+} EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD;
+
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugImageInfoTableHeader;
+
+/**
+For compatibility consideration, we handle 2 cases:
+
+1) IA32:
+ Old: New:
+ +------------------------+ +------------------------+
+ | EfiDebugImageInfoTable | | UpdateStatus |
+ +------------------------+ +------------------------+
+ | UpdateStatus | | TableSize |
+ +------------------------+ +------------------------+
+ | TableSize | | EfiDebugImageInfoTable |
+ +------------------------+ +------------------------+
+
+2) X64 and IPF:
+ Old: New:
+ +------------------------+ +------------------------+
+ | EfiDebugImageInfoTable | | UpdateStatus |
+ | | +------------------------+
+ | | | TableSize |
+ +------------------------+ +------------------------+
+ | UpdateStatus | | EfiDebugImageInfoTable |
+ +------------------------+ | |
+ | TableSize | | |
+ +------------------------+ +------------------------+
+
+ @param DebugImageInfoTableHeader Point to the EFI_DEBUG_IMAGE_INFO_TABLE_HEADER structure.
+
+**/
+VOID
+EdbFixDebugImageInfoTable (
+ IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
+ )
+{
+ mDebugImageInfoTableHeader.EfiDebugImageInfoTable = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->EfiDebugImageInfoTable;
+ mDebugImageInfoTableHeader.UpdateStatus = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->UpdateStatus;
+ mDebugImageInfoTableHeader.TableSize = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->TableSize;
+
+ if ((*DebugImageInfoTableHeader)->UpdateStatus > 3) {
+ *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
+ return ;
+ }
+
+ if ((*DebugImageInfoTableHeader)->TableSize % (EFI_PAGE_SIZE / (sizeof (VOID *))) != 0) {
+ *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
+ return ;
+ }
+
+ return ;
+}
+//
+// BUGBUG: work-around end
+//
+
+/**
+
+ Patch symbol RVA.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param SearchType - Search type for Object
+
+ @retval EFI_SUCCESS - Patch symbol RVA successfully
+ @retval EFI_NOT_FOUND - Symbol RVA base not found
+
+**/
+EFI_STATUS
+EdbPatchSymbolRVA (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
+ )
+{
+ EFI_STATUS Status;
+ UINTN ImageNumber;
+ EFI_DEBUG_IMAGE_INFO *ImageTable;
+ CHAR8 *PdbPath;
+ VOID *ImageBase;
+ VOID *CandidateImageBase;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ if (SearchType < 0 || SearchType >= EdbEbcImageRvaSearchTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the related object
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
+ if (Object == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try again to get DebugImageInfoTable
+ //
+ if (mDebuggerPrivate.DebugImageInfoTableHeader == NULL) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiDebugImageInfoTableGuid,
+ (VOID **) &mDebuggerPrivate.DebugImageInfoTableHeader
+ );
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DebugImageInfoTable not found!\n");
+ return Status;
+ }
+ }
+ DEBUG ((DEBUG_ERROR, "DebugImageInfoTableHeader: %x\n", mDebuggerPrivate.DebugImageInfoTableHeader));
+
+ //
+ // BUGBUG: work-around start
+ //
+ EdbFixDebugImageInfoTable (&mDebuggerPrivate.DebugImageInfoTableHeader);
+ //
+ // BUGBUG: work-around end
+ //
+
+ //
+ // Go through DebugImageInfoTable for each Image
+ //
+ CandidateImageBase = NULL;
+ ImageTable = mDebuggerPrivate.DebugImageInfoTableHeader->EfiDebugImageInfoTable;
+ for (ImageNumber = 0; ImageNumber < mDebuggerPrivate.DebugImageInfoTableHeader->TableSize; ImageNumber++) {
+ if (ImageTable[ImageNumber].NormalImage == NULL) {
+ continue;
+ }
+ ImageBase = ImageTable[ImageNumber].NormalImage->LoadedImageProtocolInstance->ImageBase;
+ //
+ // Get PDB path
+ //
+ PdbPath = GetPdbPath (ImageBase);
+ if (PdbPath == NULL) {
+ continue;
+ }
+ //
+ // Check PDB name
+ //
+ if (!MatchPdbAndMap (PdbPath, FileName)) {
+ continue;
+ }
+ DEBUG ((DEBUG_ERROR, "ImageBase: %x\n", ImageBase));
+
+ //
+ // Check SearchType
+ //
+ if (SearchType == EdbEbcImageRvaSearchTypeAny || SearchType == EdbEbcImageRvaSearchTypeFirst) {
+ //
+ // Assign base address and return
+ //
+ Object->BaseAddress = (UINTN)ImageBase;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get CandidateImageBase for EdbEbcImageRvaSearchTypeLast
+ //
+ CandidateImageBase = ImageBase;
+ }
+
+ //
+ // Check EdbEbcImageRvaSearchTypeLast
+ //
+ if (SearchType == EdbEbcImageRvaSearchTypeLast) {
+ if (CandidateImageBase == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Assign base address and return
+ //
+ Object->BaseAddress = (UINTN)CandidateImageBase;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No match
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ Check whether OBJ file and COD file have same name.
+
+ @param ObjFileName - OBJ file name
+ @param CodFileName - COD file name
+
+ @retval TRUE - OBJ and COD file name match
+ @retval FALSE - OBJ and COD file name not match
+
+**/
+BOOLEAN
+MatchObjAndCod (
+ IN CHAR8 *ObjFileName,
+ IN CHAR16 *CodFileName
+ )
+{
+ UINTN ObjNameSize;
+ UINTN CodNameSize;
+ CHAR8 *PureObjFileName;
+ UINTN Index;
+
+ //
+ // remove library name
+ //
+ PureObjFileName = ObjFileName;
+ for (Index = 0; ObjFileName[Index] != 0; Index++) {
+ if (ObjFileName[Index] == ':') {
+ PureObjFileName = &ObjFileName[Index + 1];
+ break;
+ }
+ }
+ ObjFileName = PureObjFileName;
+
+ //
+ // get size
+ //
+ ObjNameSize = AsciiStrLen (ObjFileName);
+ CodNameSize = StrLen (CodFileName);
+
+ if (ObjNameSize != CodNameSize) {
+ return FALSE;
+ }
+
+ //
+ // check the name
+ //
+ for (Index = 0; Index < CodNameSize - 4; Index++) {
+ if ((ObjFileName[Index] | 0x20) != (CodFileName[Index] | 0x20)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+typedef enum {
+ EdbEbcCodParseStateUninitialized,
+ EdbEbcCodParseStateSymbolInitialized,
+ EdbEbcCodParseStateSymbolStart,
+ EdbEbcCodParseStateSymbolEnd,
+ EdbEbcCodParseStateMax,
+} EDB_EBC_COD_PARSE_STATE;
+
+/**
+
+ The following code depends on the COD file generated by IEC compiler.
+
+**/
+
+/**
+
+ Load code by symbol by Iec.
+
+ @param Name - Symbol file name
+ @param Buffer - Symbol file buffer
+ @param BufferSize - Symbol file buffer size
+ @param CodeBufferSize - Code buffer size
+ @param FuncOffset - Code funcion offset
+
+ @return CodeBuffer
+
+**/
+CHAR8 *
+EdbLoadCodBySymbolByIec (
+ IN CHAR8 *Name,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT UINTN *CodeBufferSize,
+ OUT UINTN *FuncOffset
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ VOID *BufferStart;
+ VOID *BufferEnd;
+ UINTN Offset;
+ EDB_EBC_COD_PARSE_STATE CodParseState;
+ CHAR8 Char[2];
+
+ //
+ // Init
+ //
+ Char[0] = 9;
+ Char[1] = 0;
+ LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
+ Offset = (UINTN)-1;
+ BufferStart = NULL;
+ BufferEnd = NULL;
+ CodParseState = EdbEbcCodParseStateUninitialized;
+
+ //
+ // Check each line
+ //
+ while (LineBuffer != NULL) {
+ switch (CodParseState) {
+ case EdbEbcCodParseStateUninitialized:
+ //
+ // check mark_begin, begin to check line after this match
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_begin;") == 0) {
+ CodParseState = EdbEbcCodParseStateSymbolInitialized;
+ }
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolInitialized:
+ //
+ // check mark_end, not check line after this match
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
+ CodParseState = EdbEbcCodParseStateUninitialized;
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+ }
+
+ //
+ // not check this line if the first char is as follows
+ //
+ if ((*LineBuffer == 0) ||
+ (*LineBuffer == '$') ||
+ (*LineBuffer == ';') ||
+ (*LineBuffer == '_') ||
+ (*LineBuffer == ' ')) {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+ }
+
+ //
+ // get function name, function name is followed by char 0x09.
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, Char);
+ ASSERT (FieldBuffer != NULL);
+ if (AsciiStriCmp (FieldBuffer, Name) == 0) {
+ BufferStart = FieldBuffer;
+ CodParseState = EdbEbcCodParseStateSymbolStart;
+ }
+ PatchForAsciiStrTokenAfter (FieldBuffer, 0x9);
+
+ //
+ // Get next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolStart:
+ //
+ // check mark_end, if this match, means the function is found successfully.
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
+ CodParseState = EdbEbcCodParseStateSymbolEnd;
+ //
+ // prepare CodeBufferSize, FuncOffset, and FuncStart to return
+ //
+ BufferEnd = LineBuffer + sizeof("; mark_end;") - 1;
+ *CodeBufferSize = (UINTN)BufferEnd - (UINTN)BufferStart;
+ *FuncOffset = Offset;
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return BufferStart;
+ }
+
+ //
+ // Get function offset
+ //
+ if ((Offset == (UINTN)-1) &&
+ (*LineBuffer == ' ')) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
+ Offset = AsciiXtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ }
+
+ //
+ // Get next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolEnd:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // no function found
+ //
+ return NULL;
+}
+
+/**
+
+ Load code by symbol.
+
+ @param Name - Symbol file name
+ @param Buffer - Symbol file buffer
+ @param BufferSize - Symbol file buffer size
+ @param CodeBufferSize - Code buffer size
+ @param FuncOffset - Code funcion offset
+
+ @return CodeBuffer
+
+**/
+CHAR8 *
+EdbLoadCodBySymbol (
+ IN CHAR8 *Name,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT UINTN *CodeBufferSize,
+ OUT UINTN *FuncOffset
+ )
+{
+ //
+ // COD file format depends on the compiler.
+ //
+ // It is possible to check the different COD file format in this routine.
+ // Now only IEC is supported.
+ //
+ return EdbLoadCodBySymbolByIec (Name, Buffer, BufferSize, CodeBufferSize, FuncOffset);
+}
+
+/**
+
+ Find code from object.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Object - Symbol object
+ @param FileName - File name
+
+**/
+VOID *
+EdbFindCodeFromObject (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN CHAR16 *FileName
+ )
+{
+ UINTN EntryIndex;
+
+ //
+ // Go througn each Entry in this Object
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ //
+ // This check is for Function only
+ //
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ //
+ // Skip match varbss_init function, because they has no source code
+ //
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ //
+ // check the name
+ //
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // found it, return source buffer
+ //
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ return Object->Entry[EntryIndex].SourceBuffer;
+ }
+ }
+
+ //
+ // not found
+ //
+ return NULL;
+}
+
+/**
+
+ Load code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param BufferSize - Code file buffer size
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code loaded successfully
+
+**/
+EFI_STATUS
+EdbLoadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN EntryIndex;
+ VOID *SourceBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // Check duplicated File
+ //
+ SourceBuffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
+ if (SourceBuffer != NULL) {
+ //
+ // unnload duplicated code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &SourceBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Unload Duplicated Code File Error!\n"));
+ return Status;
+ }
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, SourceBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Delete Duplicated Code File Error!\n"));
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Go through each SymbolEntry
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ //
+ // load symbol for function only
+ //
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ //
+ // skip varbss_init
+ //
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ //
+ // Check the name
+ //
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // load code for this symbol
+ //
+ Object->Entry[EntryIndex].CodBuffer = EdbLoadCodBySymbol (
+ Object->Entry[EntryIndex].Name,
+ Buffer,
+ BufferSize,
+ &Object->Entry[EntryIndex].CodBufferSize,
+ &Object->Entry[EntryIndex].FuncOffsetBase
+ );
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ Object->Entry[EntryIndex].SourceBuffer = Buffer;
+ }
+ }
+
+ //
+ // patch end '\0' for each code buffer
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ *((UINT8 *)Object->Entry[EntryIndex].CodBuffer + Object->Entry[EntryIndex].CodBufferSize) = 0;
+ DEBUG ((DEBUG_ERROR, " CodeSymbol: %a, FuncOffset: 0x05%x\n", Object->Entry[EntryIndex].Name, Object->Entry[EntryIndex].FuncOffsetBase));
+// DEBUG ((DEBUG_ERROR, " [CODE]:\n%a\n", Object->Entry[EntryIndex].CodBuffer));
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Unload code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code unloaded successfully
+
+**/
+EFI_STATUS
+EdbUnloadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN EntryIndex;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find code
+ //
+ *Buffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
+ if (*Buffer == NULL) {
+ EDBPrint (L"CodeFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // go through each entry
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // clean up the buffer
+ //
+ Object->Entry[EntryIndex].CodBuffer = NULL;
+ Object->Entry[EntryIndex].CodBufferSize = 0;
+ Object->Entry[EntryIndex].FuncOffsetBase = 0;
+ Object->Entry[EntryIndex].SourceBuffer = NULL;
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Add code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBufferSize- Code buffer size
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer added successfully
+
+**/
+EFI_STATUS
+EdbAddCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN UINTN SourceBufferSize,
+ IN VOID *SourceBuffer
+ )
+{
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Add it to last entry
+ //
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ ;
+ }
+ Object->SourceBuffer[Index] = SourceBuffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Delete code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer deleted successfully
+
+**/
+EFI_STATUS
+EdbDeleteCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN VOID *SourceBuffer
+ )
+{
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ //
+ // free the buffer if match
+ //
+ if (Object->SourceBuffer[Index] == SourceBuffer) {
+ gBS->FreePool (SourceBuffer);
+ break;
+ }
+ }
+
+ if (Object->SourceBuffer[Index] == NULL) {
+ //
+ // not return NOT_FOUND
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // remove the entry
+ //
+ Object->SourceBuffer[Index] = NULL;
+ for (Index = Index + 1; Object->SourceBuffer[Index] != NULL; Index++) {
+ Object->SourceBuffer[Index - 1] = Object->SourceBuffer[Index];
+ }
+ Object->SourceBuffer[Index - 1] = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Find the symbol string according to address.
+
+ @param Address - Symbol address
+
+ @return Symbol string
+
+**/
+CHAR8 *
+FindSymbolStr (
+ IN UINTN Address
+ )
+{
+ UINTN ObjectIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN EntryIndex;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ //
+ // need we display symbol
+ //
+ if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
+ return NULL;
+ }
+
+ //
+ // Go through each object and entry
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ Entry = Object[ObjectIndex].Entry;
+ for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
+ //
+ // if Address match, return Name
+ //
+ if (Address == (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress)) {
+ return Entry[EntryIndex].Name;
+ }
+ }
+ }
+
+ //
+ // not found
+ //
+ return NULL;
+}
+
+/**
+
+ Get line number and offset from this line in code file.
+
+ @param Line - Line buffer in code file
+ @param Offset - Offset to functin entry
+
+ @return Line number
+
+**/
+UINTN
+EdbGetLineNumberAndOffsetFromThisLine (
+ IN VOID *Line,
+ OUT UINTN *Offset
+ )
+{
+ UINTN LineNumber;
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+
+ LineNumber = (UINTN)-1;
+ LineBuffer = Line;
+ *Offset = (UINTN)-1;
+
+ while (LineBuffer != NULL) {
+ //
+ // Check candidate
+ //
+ if (*LineBuffer != ' ') {
+ return (UINTN)-1;
+ }
+
+ //
+ // Get Offset
+ //
+ if (*(LineBuffer + 2) != ' ') {
+ if (*Offset == (UINTN)-1) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
+ *Offset = AsciiXtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ }
+ }
+
+ //
+ // 1. assembly instruction
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, ":");
+ //
+ // 2. file path
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (":");
+ PatchForAsciiStrTokenBefore (FieldBuffer, ':');
+ if (FieldBuffer == NULL) {
+ //
+ // candidate found
+ //
+ LineNumber = 0;
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+ //
+ // 3. line number
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (":");
+ PatchForAsciiStrTokenBefore (FieldBuffer, ':');
+ if (FieldBuffer == NULL) {
+ //
+ // impossible, TBD?
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ LineNumber = AsciiAtoi (FieldBuffer);
+ //
+ // Not patch after
+ //
+
+ return LineNumber;
+ }
+
+ return (UINTN)-1;
+}
+
+typedef enum {
+ EdbEbcLineSearchTypeAny,
+ EdbEbcLineSearchTypeFirst,
+ EdbEbcLineSearchTypeLast,
+ EdbEbcLineSearchTypeMax,
+} EDB_EBC_LINE_SEARCH_TYPE;
+
+/**
+
+ Get line number from this code file.
+
+ @param Entry - Symbol entry
+ @param FuncOffset - Offset to functin entry
+ @param SearchType - Search type for the code
+
+ @return Line number
+
+**/
+UINTN
+EdbGetLineNumberFromCode (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN FuncOffset,
+ IN EDB_EBC_LINE_SEARCH_TYPE SearchType
+ )
+{
+ CHAR8 *LineBuffer;
+ UINTN LineNumber;
+ UINTN Offset;
+ UINTN CandidateLineNumber;
+ UINTN CandidateOffset;
+
+ if (SearchType < 0 || SearchType >= EdbEbcLineSearchTypeMax) {
+ return (UINTN)-1;
+ }
+
+ LineNumber = (UINTN)-1;
+ CandidateLineNumber = (UINTN)-1;
+ CandidateOffset = (UINTN)-1;
+ LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
+ while (LineBuffer != NULL) {
+ if (*LineBuffer != ' ') {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Get Info
+ //
+ LineNumber = EdbGetLineNumberAndOffsetFromThisLine (LineBuffer, &Offset);
+
+ //
+ // Check offset
+ //
+ if (Offset != FuncOffset) {
+ //
+ // Check last offset match
+ //
+ if (CandidateOffset == FuncOffset) {
+ if (SearchType == EdbEbcLineSearchTypeLast) {
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ if (CandidateLineNumber != LineNumber) {
+ return CandidateLineNumber;
+ } else {
+ return (UINTN)-1;
+ }
+ } else {
+ //
+ // impossible, TBD?
+ //
+ }
+ }
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ CandidateLineNumber = LineNumber;
+ continue;
+ }
+
+ //
+ // Offset match, more check
+ //
+ if (SearchType == EdbEbcLineSearchTypeAny) {
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return LineNumber;
+ }
+
+ if (SearchType == EdbEbcLineSearchTypeFirst) {
+ //
+ // Check last line
+ //
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ if (CandidateLineNumber != LineNumber) {
+ return LineNumber;
+ } else {
+ return (UINTN)-1;
+ }
+ }
+
+ CandidateLineNumber = LineNumber;
+ CandidateOffset = Offset;
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ }
+
+ //
+ // Check last offset match
+ //
+ if (CandidateOffset == FuncOffset) {
+ if (SearchType == EdbEbcLineSearchTypeLast) {
+ return CandidateLineNumber;
+ }
+ }
+
+ return (UINTN)-1;
+}
+
+/**
+
+ Get the source string from this code file by line.
+
+ @param Entry - Symbol entry
+ @param LineNumber - line number
+ @param FuncEnd - Function end
+
+ @return Funtion start
+
+**/
+VOID *
+EdbGetSourceStrFromCodeByLine (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN LineNumber,
+ IN VOID **FuncEnd
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ VOID *FuncStart;
+ UINTN Number;
+
+ FuncStart = NULL;
+ LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
+ while (LineBuffer != NULL) {
+ if (*LineBuffer != ';') {
+ if (FuncStart != NULL) {
+ //
+ // Over
+ //
+ *FuncEnd = LineBuffer - 1;
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return FuncStart;
+ }
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Check LineNumber
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 1, " ");
+ Number = AsciiAtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ if (Number != LineNumber) {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Line match, get line number
+ //
+ if (FuncStart == NULL) {
+ FuncStart = LineBuffer;
+ }
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ }
+
+ return NULL;
+}
+
+/**
+
+ Get source string from this code file.
+
+ @param Entry - Symbol entry
+ @param FuncOffset - Offset to functin entry
+ @param FuncEnd - Function end
+
+ @retval Funtion start
+
+**/
+VOID *
+EdbGetSourceStrFromCode (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN FuncOffset,
+ IN VOID **FuncEnd
+ )
+{
+ UINTN LineNumber;
+
+ //
+ // Only search the last line, then display
+ //
+ LineNumber = EdbGetLineNumberFromCode (Entry, FuncOffset, EdbEbcLineSearchTypeLast);
+ if (LineNumber == (UINTN)-1) {
+ return NULL;
+ }
+
+ return EdbGetSourceStrFromCodeByLine (Entry, LineNumber, FuncEnd);
+}
+
+/**
+
+ Print source.
+
+ @param Address - Instruction address
+ @param IsPrint - Whether need to print
+
+ @retval 1 - find the source
+ @retval 0 - not find the source
+
+**/
+UINTN
+EdbPrintSource (
+ IN UINTN Address,
+ IN BOOLEAN IsPrint
+ )
+{
+ UINTN SymbolAddress;
+ EFI_DEBUGGER_SYMBOL_OBJECT *RetObject;
+ EFI_DEBUGGER_SYMBOL_ENTRY *RetEntry;
+ UINTN FuncOffset;
+ UINT8 *FuncStart;
+ UINT8 *FuncEnd;
+ UINT8 *FuncIndex;
+ CHAR8 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
+ UINTN BufferSize;
+
+ //
+ // need we display symbol
+ //
+ if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
+ return 0 ;
+ }
+
+ //
+ // find the symbol address
+ //
+ SymbolAddress = EbdFindSymbolAddress (
+ Address,
+ EdbMatchSymbolTypeLowerAddress,
+ &RetObject,
+ &RetEntry
+ );
+ if (SymbolAddress == 0 || RetEntry == NULL) {
+ return 0 ;
+ }
+
+ FuncOffset = Address - SymbolAddress + RetEntry->FuncOffsetBase;
+
+ //
+ // Get Func String
+ //
+ FuncStart = EdbGetSourceStrFromCode (RetEntry, FuncOffset, (VOID**) &FuncEnd);
+ if (FuncStart == NULL) {
+ return 0 ;
+ }
+
+ //
+ // check whether need to real print
+ //
+ if (!IsPrint) {
+ return 1;
+ }
+
+ *(UINT8 *)FuncEnd = 0;
+
+ //
+ // seperate buffer by \n, so that \r can be added.
+ //
+ FuncIndex = FuncStart;
+ while (*FuncIndex != 0) {
+ if (*FuncIndex == '\n') {
+ if ((FuncIndex - FuncStart) < (EFI_DEBUG_MAX_PRINT_BUFFER - 3)) {
+ BufferSize = FuncIndex - FuncStart;
+ } else {
+ BufferSize = EFI_DEBUG_MAX_PRINT_BUFFER - 3;
+ }
+ if (BufferSize != 0) {
+ CopyMem (Buffer, FuncStart, BufferSize);
+ }
+ Buffer[BufferSize] = 0;
+ EDBPrint (L"%a\n", Buffer);
+ FuncStart = FuncIndex + 1;
+ FuncIndex = FuncStart;
+ } else {
+ FuncIndex ++;
+ }
+ }
+
+ //
+ // Patch the end
+ //
+ *(UINT8 *)FuncEnd = '\n';
+
+ return 1 ;
+}
+
+/**
+
+ Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName.
+
+ @param Symbol - whole Symbol name
+ @param MapfileName - the mapfile name in the symbol
+ @param SymbolName - the symbol name in the symbol
+
+**/
+VOID
+GetMapfileAndSymbol (
+ IN CHAR16 *Symbol,
+ OUT CHAR16 **MapfileName,
+ OUT CHAR16 **SymbolName
+ )
+{
+ CHAR16 *Ch;
+
+ *MapfileName = NULL;
+ *SymbolName = Symbol;
+
+ for (Ch = Symbol; *Ch != 0; Ch++) {
+ //
+ // Find split char
+ //
+ if (*Ch == L':') {
+ *MapfileName = Symbol;
+ *Ch = 0;
+ *SymbolName = Ch + 1;
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+
+ Convert a symbol to an address.
+
+ @param Symbol - Symbol name
+ @param Address - Symbol address
+
+ @retval EFI_SUCCESS - symbol found and address returned.
+ @retval EFI_NOT_FOUND - symbol not found
+ @retval EFI_NO_MAPPING - duplicated symbol not found
+
+**/
+EFI_STATUS
+Symboltoi (
+ IN CHAR16 *Symbol,
+ OUT UINTN *Address
+ )
+{
+ UINTN ObjectIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN EntryIndex;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ CHAR16 *SymbolName;
+ CHAR16 *MapfileName;
+
+ //
+ // Split one symbol to mapfile name and symbol name
+ //
+ GetMapfileAndSymbol (Symbol, &MapfileName, &SymbolName);
+
+ *Address = 0;
+ //
+ // Go through each object
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ //
+ // Check MapfileName
+ //
+ if ((MapfileName != NULL) && (StriCmp (Object[ObjectIndex].Name, MapfileName) != 0)) {
+ continue;
+ }
+ //
+ // Go through each entry
+ //
+ Entry = Object[ObjectIndex].Entry;
+ for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
+ //
+ // Check SymbolName (case sensitive)
+ //
+ if (StrCmpUnicodeAndAscii (SymbolName, Entry[EntryIndex].Name) == 0) {
+ if ((*Address != 0) && (MapfileName == NULL)) {
+ //
+ // Find the duplicated symbol
+ //
+ EDBPrint (L"Duplicated Symbol found!\n");
+ return EFI_NO_MAPPING;
+ } else {
+ //
+ // record Address
+ //
+ *Address = (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress);
+ }
+ }
+ }
+ }
+
+ if (*Address == 0) {
+ //
+ // Not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h
new file mode 100644
index 000000000..f82e5b76c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h
@@ -0,0 +1,244 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_SYMBOL_H_
+#define _EFI_EDB_SYMBOL_H_
+
+#include <Uefi.h>
+
+//
+// The default base address is 0x10000000
+//
+#define EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE 0x10000000
+
+#define EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE 0x100000 // 1 M delta
+
+typedef enum {
+ EdbMatchSymbolTypeSameAdderss,
+ EdbMatchSymbolTypeNearestAddress,
+ EdbMatchSymbolTypeLowerAddress,
+ EdbMatchSymbolTypeUpperAddress,
+ EdbMatchSymbolTypeMax,
+} EDB_MATCH_SYMBOL_TYPE;
+
+typedef enum {
+ EdbEbcImageRvaSearchTypeAny,
+ EdbEbcImageRvaSearchTypeFirst,
+ EdbEbcImageRvaSearchTypeLast,
+ EdbEbcImageRvaSearchTypeMax,
+} EDB_EBC_IMAGE_RVA_SEARCH_TYPE;
+
+/**
+
+ Find symbol by address.
+
+ @param Address - Symbol address
+ @param Type - Search type
+ @param RetObject - Symbol object
+ @param RetEntry - Symbol entry
+
+ @return Nearest symbol address
+
+**/
+UINTN
+EbdFindSymbolAddress (
+ IN UINTN Address,
+ IN EDB_MATCH_SYMBOL_TYPE Type,
+ OUT EFI_DEBUGGER_SYMBOL_OBJECT **Object,
+ OUT EFI_DEBUGGER_SYMBOL_ENTRY **Entry
+ );
+
+/**
+
+ Load symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - load symbol successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+
+ Unload symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+
+ @retval EFI_SUCCESS - unload symbol successfully
+
+**/
+EFI_STATUS
+EdbUnloadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName
+ );
+
+/**
+
+ Patch symbol RVA.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param SearchType - Search type for Object
+
+ @retval EFI_SUCCESS - Patch symbol RVA successfully
+ @retval EFI_NOT_FOUND - Symbol RVA base not found
+
+**/
+EFI_STATUS
+EdbPatchSymbolRVA (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
+ );
+
+/**
+
+ Load code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param BufferSize - Code file buffer size
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code loaded successfully
+
+**/
+EFI_STATUS
+EdbLoadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+
+ Unload code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code unloaded successfully
+
+**/
+EFI_STATUS
+EdbUnloadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer
+ );
+
+/**
+
+ Add code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBufferSize- Code buffer size
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer added successfully
+
+**/
+EFI_STATUS
+EdbAddCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN UINTN SourceBufferSize,
+ IN VOID *SourceBuffer
+ );
+
+/**
+
+ Delete code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer deleted successfully
+
+**/
+EFI_STATUS
+EdbDeleteCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN VOID *SourceBuffer
+ );
+
+/**
+
+ Find the symbol string according to address.
+
+ @param Address - Symbol address
+
+ @return Symbol string
+
+**/
+CHAR8 *
+FindSymbolStr (
+ IN UINTN Address
+ );
+
+/**
+
+ Print source.
+
+ @param Address - Instruction address
+ @param IsPrint - Whether need to print
+
+ @retval 1 - find the source
+ @retval 0 - not find the source
+
+**/
+UINTN
+EdbPrintSource (
+ IN UINTN Address,
+ IN BOOLEAN IsPrint
+ );
+
+/**
+
+ Convert a symbol to an address.
+
+ @param Symbol - Symbol name
+ @param Address - Symbol address
+
+ @retval EFI_SUCCESS - symbol found and address returned.
+ @retval EFI_NOT_FOUND - symbol not found
+ @retval EFI_NO_MAPPING - duplicated symbol not found
+
+**/
+EFI_STATUS
+Symboltoi (
+ IN CHAR16 *Symbol,
+ OUT UINTN *Address
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf
new file mode 100644
index 000000000..22cf64d95
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf
@@ -0,0 +1,57 @@
+## @file
+# EBC Debugger configuration application.
+#
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EdbCfg
+ MODULE_UNI_FILE = EbcDebuggerConfig.uni
+ FILE_GUID = 8CFC5233-23C6-49e3-8A2D-7E581AB305BA
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDebuggerConfig
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebugger/EbcDebuggerConfig.c
+ EbcDebugger/EdbCommon.h
+ EbcDebugger/EdbSupportString.c
+ EbcDebugger/EdbSupport.h
+ EbcDebugger/EdbCommand.h
+ EbcDebugger/EdbHook.h
+ EbcDebugger/Edb.h
+ EbcDebugger/EdbDisasmSupport.h
+ EbcDebugger/EdbDisasm.h
+ EbcDebugger/EdbSymbol.h
+ EbcDebuggerHook.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ DebugLib
+ UefiApplicationEntryPoint
+
+[Protocols]
+ gEfiDebuggerConfigurationProtocolGuid ## CONSUMES
+ gEfiShellParametersProtocolGuid ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDebuggerConfigExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni
new file mode 100644
index 000000000..c8592407c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni
@@ -0,0 +1,13 @@
+// /** @file
+// EBC Debugger configuration application.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EBC Debugger configuration application"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application allows configuring the EBC Debugger."
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni
new file mode 100644
index 000000000..1d532c86a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// EBC Debugger configuration application.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EBC Debugger Config"
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni
new file mode 100644
index 000000000..944abae21
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// EFI Byte Code (EBC) Debugger
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EFI Byte Code (EBC) Debugger"
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c
new file mode 100644
index 000000000..b516147ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c
@@ -0,0 +1,267 @@
+/** @file
+ Contains the empty version of the EBC Debugger hooks, to be used when
+ compiling the regular EBC VM module.
+ As debugging is not needed for the standard EBC VM, all calls are left empty.
+
+ The EBC Debugger defines its own version for these calls in EbdHooks.c.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcDebuggerHook.h"
+
+/**
+
+ The hook in InitializeEbcDriver.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ )
+{
+ return;
+}
+
+/**
+
+The hook in UnloadImage for EBC Interpreter.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+ The hook in EbcExecute, before ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+ The hook in EbcExecute, after ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP8, after move IP..
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h
new file mode 100644
index 000000000..b166e505a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h
@@ -0,0 +1,241 @@
+/** @file
+ Prototypes for the EBC Debugger hooks.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EBC_DEBUGGER_HOOK_H_
+#define _EFI_EBC_DEBUGGER_HOOK_H_
+
+#include <Uefi.h>
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/EbcVmTest.h>
+
+/**
+ The VM interpreter calls this function when an exception is detected.
+
+ @param ExceptionType Specifies the processor exception detected.
+ @param ExceptionFlags Specifies the exception context.
+ @param VmPtr Pointer to a VM context for passing info to the
+ EFI debugger.
+
+ @retval EFI_SUCCESS This function completed successfully.
+
+**/
+EFI_STATUS
+EbcDebugSignalException (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EXCEPTION_FLAGS ExceptionFlags,
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in InitializeEbcDriver.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ );
+
+/**
+
+The hook in UnloadImage for EBC Interpreter.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ );
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ );
+
+
+/**
+
+ Hooks in EbcSupport.c
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+/**
+ The hook in EbcExecute, before ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ The hook in EbcExecute, after ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ The hook in ExecuteCALL, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP8, after move IP..
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
new file mode 100644
index 000000000..a38700df5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# Module that produces EBC Interprete and EBC Debug Support protocols.
+#
+# This module implements EFI Byte Code (EBC) Virtual Machine that can provide
+# platform and processor-independent mechanisms for loading and executing EFI
+# device drivers.
+#
+# Copyright (c) 2015, The Linux Foundation. All rights reserved.
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EbcDxe
+ MODULE_UNI_FILE = EbcDxe.uni
+ FILE_GUID = 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebuggerHook.h
+ EbcDebuggerHook.c
+ EbcExecute.h
+ EbcExecute.c
+ EbcInt.h
+ EbcInt.c
+
+[Sources.Ia32]
+ Ia32/EbcSupport.c
+ Ia32/EbcLowLevel.nasm
+
+[Sources.X64]
+ X64/EbcSupport.c
+ X64/EbcLowLevel.nasm
+
+[Sources.AARCH64]
+ AArch64/EbcSupport.c
+ AArch64/EbcLowLevel.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ CacheMaintenanceLib
+ MemoryAllocationLib
+ PeCoffLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseLib
+
+
+[Protocols]
+ gEfiDebugSupportProtocolGuid ## PRODUCES
+ gEfiEbcProtocolGuid ## PRODUCES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## PRODUCES
+ gEfiEbcVmTestProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEbcSimpleDebuggerProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+
+# [Event]
+#
+# Periodic timer event to support EFI debug support protocol for EBC image.
+#
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni
new file mode 100644
index 000000000..746d8b911
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Module that produces EBC Interprete and EBC Debug Support protocols.
+//
+// This module implements EFI Byte Code (EBC) Virtual Machine that can provide
+// platform and processor-independent mechanisms for loading and executing EFI
+// device drivers.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces EBC Interpreter and EBC Debug Support protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module implements EFI Byte Code (EBC) Virtual Machine that can provide platform and processor-independent mechanisms for loading and executing UEFI device drivers."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni
new file mode 100644
index 000000000..7b47f15a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EbcDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EFI Byte Code DXE Interpreter"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
new file mode 100644
index 000000000..1c4a4f515
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
@@ -0,0 +1,5383 @@
+/** @file
+ Contains code that implements the virtual machine.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+
+//
+// Define some useful data size constants to allow switch statements based on
+// size of operands or data.
+//
+#define DATA_SIZE_INVALID 0
+#define DATA_SIZE_8 1
+#define DATA_SIZE_16 2
+#define DATA_SIZE_32 4
+#define DATA_SIZE_64 8
+#define DATA_SIZE_N 48 // 4 or 8
+//
+// Structure we'll use to dispatch opcodes to execute functions.
+//
+typedef struct {
+ EFI_STATUS (*ExecuteFunction) (IN VM_CONTEXT * VmPtr);
+}
+VM_TABLE_ENTRY;
+
+typedef
+UINT64
+(*DATA_MANIP_EXEC_FUNCTION) (
+ IN VM_CONTEXT * VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Decode a 16-bit index to determine the offset. Given an index value:
+
+ b15 - sign bit
+ b14:12 - number of bits in this index assigned to natural units (=a)
+ ba:11 - constant units = ConstUnits
+ b0:a - natural units = NaturalUnits
+
+ Given this info, the offset can be computed by:
+ offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
+
+ Max offset is achieved with index = 0x7FFF giving an offset of
+ 0x27B (32-bit machine) or 0x477 (64-bit machine).
+ Min offset is achieved with index =
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 16-bit index
+ to decode.
+
+ @return The decoded offset.
+
+**/
+INT16
+VmReadIndex16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Decode a 32-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 32-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification.
+
+**/
+INT32
+VmReadIndex32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Decode a 64-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.s
+ @param CodeOffset Offset from IP of the location of the 64-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification
+
+**/
+INT64
+VmReadIndex64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Reads 8-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 8-bit value from the memory address.
+
+**/
+UINT8
+VmReadMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 16-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 16-bit value from the memory address.
+
+**/
+UINT16
+VmReadMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 32-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 32-bit value from the memory address.
+
+**/
+UINT32
+VmReadMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 64-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 64-bit value from the memory address.
+
+**/
+UINT64
+VmReadMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Read a natural value from memory. May or may not be aligned.
+
+ @param VmPtr current VM context
+ @param Addr the address to read from
+
+ @return The natural value at address Addr.
+
+**/
+UINTN
+VmReadMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Writes 8-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT8 Data
+ );
+
+/**
+ Writes 16-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT16 Data
+ );
+
+/**
+ Writes 32-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT32 Data
+ );
+
+/**
+ Reads 16-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 16-bit value from the code stream.
+
+**/
+UINT16
+VmReadCode16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 32-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 32-bit value from the code stream.
+
+**/
+UINT32
+VmReadCode32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 64-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 64-bit value from the code stream.
+
+**/
+UINT64
+VmReadCode64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 8-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT8
+VmReadImmed8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 16-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT16
+VmReadImmed16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 32-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT32
+VmReadImmed32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 64-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT64
+VmReadImmed64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Given an address that EBC is going to read from or write to, return
+ an appropriate address that accounts for a gap in the stack.
+ The stack for this application looks like this (high addr on top)
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+ The EBC assumes that its arguments are at the top of its stack, which
+ is where the VM stack is really. Therefore if the EBC does memory
+ accesses into the VM stack area, then we need to convert the address
+ to point to the EBC entry point arguments area. Do this here.
+
+ @param VmPtr A Pointer to VM context.
+ @param Addr Address of interest
+
+ @return The unchanged address if it's not in the VM stack region. Otherwise,
+ adjust for the stack gap and return the modified address.
+
+**/
+UINTN
+ConvertStackAddr (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Execute all the EBC data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+ @param IsSignedOp Indicates whether the operand is signed or not.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteDataManip (
+ IN VM_CONTEXT *VmPtr,
+ IN BOOLEAN IsSignedOp
+ );
+
+//
+// Functions that execute VM opcodes
+//
+/**
+ Execute the EBC BREAK instruction.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteBREAK (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the JMP instruction.
+
+ Instruction syntax:
+ JMP64{cs|cc} Immed64
+ JMP32{cs|cc} {@}R1 {Immed32|Index32}
+
+ Encoding:
+ b0.7 - immediate data present
+ b0.6 - 1 = 64 bit immediate data
+ 0 = 32 bit immediate data
+ b1.7 - 1 = conditional
+ b1.6 1 = CS (condition set)
+ 0 = CC (condition clear)
+ b1.4 1 = relative address
+ 0 = absolute address
+ b1.3 1 = operand1 indirect
+ b1.2-0 operand 1
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC JMP8 instruction.
+
+ Instruction syntax:
+ JMP8{cs|cc} Offset/2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP8 (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Implements the EBC CALL instruction.
+
+ Instruction format:
+ CALL64 Immed64
+ CALL32 {@}R1 {Immed32|Index32}
+ CALLEX64 Immed64
+ CALLEX16 {@}R1 {Immed32}
+
+ If Rx == R0, then it's a PC relative call to PC = PC + imm32.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCALL (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC RET instruction.
+
+ Instruction syntax:
+ RET
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteRET (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC CMP instruction.
+
+ Instruction syntax:
+ CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC CMPI instruction
+
+ Instruction syntax:
+ CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMPI (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the MOVxx instructions.
+
+ Instruction format:
+
+ MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
+ MOVqq {@}R1 {Index64}, {@}R2 {Index64}
+
+ Copies contents of [R2] -> [R1], zero extending where required.
+
+ First character indicates the size of the move.
+ Second character indicates the size of the index(s).
+
+ Invalid to have R1 direct with index.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVxx (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVI.
+
+ Instruction syntax:
+
+ MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ First variable character specifies the move size
+ Second variable character specifies size of the immediate data
+
+ Sign-extend the immediate data to the size of the operation, and zero-extend
+ if storing to a register.
+
+ Operand1 direct with index/immed is invalid.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVI (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOV immediate natural. This instruction moves an immediate
+ index value into a register or memory location.
+
+ Instruction syntax:
+
+ MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVIn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVREL instruction.
+ Dest <- Ip + ImmData
+
+ Instruction syntax:
+
+ MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVREL (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC PUSHn instruction
+
+ Instruction syntax:
+ PUSHn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSHn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC PUSH instruction.
+
+ Instruction syntax:
+ PUSH[32|64] {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSH (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC POPn instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOPn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC POP instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute all the EBC signed data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute all the EBC unsigned data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteUnsignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC LOADSP instruction.
+
+ Instruction syntax:
+ LOADSP SP1, R2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteLOADSP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC STORESP instruction.
+
+ Instruction syntax:
+ STORESP Rx, FLAGS|IP
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSTORESP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnw (
+ IN VM_CONTEXT *VmPtr
+ );
+
+//
+// Data manipulation subfunctions
+//
+/**
+ Execute the EBC NOT instruction.s
+
+ Instruction syntax:
+ NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return ~Op2
+
+**/
+UINT64
+ExecuteNOT (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC NEG instruction.
+
+ Instruction syntax:
+ NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op2 * -1
+
+**/
+UINT64
+ExecuteNEG (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC ADD instruction.
+
+ Instruction syntax:
+ ADD[32|64] {@}R1, {@}R2 {Index16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 + Op2
+
+**/
+UINT64
+ExecuteADD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SUB instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 - Op2
+
+**/
+UINT64
+ExecuteSUB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MUL instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 * Op2
+
+**/
+UINT64
+ExecuteMUL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MULU instruction
+
+ Instruction syntax:
+ MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 * (unsigned)Op2
+
+**/
+UINT64
+ExecuteMULU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC DIV instruction.
+
+ Instruction syntax:
+ DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 / Op2
+
+**/
+UINT64
+ExecuteDIV (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC DIVU instruction
+
+ Instruction syntax:
+ DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 / (unsigned)Op2
+
+**/
+UINT64
+ExecuteDIVU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MOD instruction.
+
+ Instruction syntax:
+ MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 MODULUS Op2
+
+**/
+UINT64
+ExecuteMOD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MODU instruction.
+
+ Instruction syntax:
+ MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 UNSIGNED_MODULUS Op2
+
+**/
+UINT64
+ExecuteMODU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC AND instruction.
+
+ Instruction syntax:
+ AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 AND Op2
+
+**/
+UINT64
+ExecuteAND (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC OR instruction.
+
+ Instruction syntax:
+ OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 OR Op2
+
+**/
+UINT64
+ExecuteOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC XOR instruction.
+
+ Instruction syntax:
+ XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 XOR Op2
+
+**/
+UINT64
+ExecuteXOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SHL shift left instruction.
+
+ Instruction syntax:
+ SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 << Op2
+
+**/
+UINT64
+ExecuteSHL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SHR instruction.
+
+ Instruction syntax:
+ SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (unsigned operands)
+
+**/
+UINT64
+ExecuteSHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC ASHR instruction.
+
+ Instruction syntax:
+ ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (signed)
+
+**/
+UINT64
+ExecuteASHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDB instruction to sign-extend a byte value.
+
+ Instruction syntax:
+ EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT8)Op2
+
+**/
+UINT64
+ExecuteEXTNDB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
+
+ Instruction syntax:
+ EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT16)Op2
+
+**/
+UINT64
+ExecuteEXTNDW (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
+
+ Instruction syntax:
+ EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT32)Op2
+
+**/
+UINT64
+ExecuteEXTNDD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+//
+// Once we retrieve the operands for the data manipulation instructions,
+// call these functions to perform the operation.
+//
+CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable[] = {
+ ExecuteNOT,
+ ExecuteNEG,
+ ExecuteADD,
+ ExecuteSUB,
+ ExecuteMUL,
+ ExecuteMULU,
+ ExecuteDIV,
+ ExecuteDIVU,
+ ExecuteMOD,
+ ExecuteMODU,
+ ExecuteAND,
+ ExecuteOR,
+ ExecuteXOR,
+ ExecuteSHL,
+ ExecuteSHR,
+ ExecuteASHR,
+ ExecuteEXTNDB,
+ ExecuteEXTNDW,
+ ExecuteEXTNDD,
+};
+
+CONST VM_TABLE_ENTRY mVmOpcodeTable[] = {
+ { ExecuteBREAK }, // opcode 0x00
+ { ExecuteJMP }, // opcode 0x01
+ { ExecuteJMP8 }, // opcode 0x02
+ { ExecuteCALL }, // opcode 0x03
+ { ExecuteRET }, // opcode 0x04
+ { ExecuteCMP }, // opcode 0x05 CMPeq
+ { ExecuteCMP }, // opcode 0x06 CMPlte
+ { ExecuteCMP }, // opcode 0x07 CMPgte
+ { ExecuteCMP }, // opcode 0x08 CMPulte
+ { ExecuteCMP }, // opcode 0x09 CMPugte
+ { ExecuteUnsignedDataManip }, // opcode 0x0A NOT
+ { ExecuteSignedDataManip }, // opcode 0x0B NEG
+ { ExecuteSignedDataManip }, // opcode 0x0C ADD
+ { ExecuteSignedDataManip }, // opcode 0x0D SUB
+ { ExecuteSignedDataManip }, // opcode 0x0E MUL
+ { ExecuteUnsignedDataManip }, // opcode 0x0F MULU
+ { ExecuteSignedDataManip }, // opcode 0x10 DIV
+ { ExecuteUnsignedDataManip }, // opcode 0x11 DIVU
+ { ExecuteSignedDataManip }, // opcode 0x12 MOD
+ { ExecuteUnsignedDataManip }, // opcode 0x13 MODU
+ { ExecuteUnsignedDataManip }, // opcode 0x14 AND
+ { ExecuteUnsignedDataManip }, // opcode 0x15 OR
+ { ExecuteUnsignedDataManip }, // opcode 0x16 XOR
+ { ExecuteUnsignedDataManip }, // opcode 0x17 SHL
+ { ExecuteUnsignedDataManip }, // opcode 0x18 SHR
+ { ExecuteSignedDataManip }, // opcode 0x19 ASHR
+ { ExecuteUnsignedDataManip }, // opcode 0x1A EXTNDB
+ { ExecuteUnsignedDataManip }, // opcode 0x1B EXTNDW
+ { ExecuteUnsignedDataManip }, // opcode 0x1C EXTNDD
+ { ExecuteMOVxx }, // opcode 0x1D MOVBW
+ { ExecuteMOVxx }, // opcode 0x1E MOVWW
+ { ExecuteMOVxx }, // opcode 0x1F MOVDW
+ { ExecuteMOVxx }, // opcode 0x20 MOVQW
+ { ExecuteMOVxx }, // opcode 0x21 MOVBD
+ { ExecuteMOVxx }, // opcode 0x22 MOVWD
+ { ExecuteMOVxx }, // opcode 0x23 MOVDD
+ { ExecuteMOVxx }, // opcode 0x24 MOVQD
+ { ExecuteMOVsnw }, // opcode 0x25 MOVsnw
+ { ExecuteMOVsnd }, // opcode 0x26 MOVsnd
+ { NULL }, // opcode 0x27
+ { ExecuteMOVxx }, // opcode 0x28 MOVqq
+ { ExecuteLOADSP }, // opcode 0x29 LOADSP SP1, R2
+ { ExecuteSTORESP }, // opcode 0x2A STORESP R1, SP2
+ { ExecutePUSH }, // opcode 0x2B PUSH {@}R1 [imm16]
+ { ExecutePOP }, // opcode 0x2C POP {@}R1 [imm16]
+ { ExecuteCMPI }, // opcode 0x2D CMPIEQ
+ { ExecuteCMPI }, // opcode 0x2E CMPILTE
+ { ExecuteCMPI }, // opcode 0x2F CMPIGTE
+ { ExecuteCMPI }, // opcode 0x30 CMPIULTE
+ { ExecuteCMPI }, // opcode 0x31 CMPIUGTE
+ { ExecuteMOVxx }, // opcode 0x32 MOVN
+ { ExecuteMOVxx }, // opcode 0x33 MOVND
+ { NULL }, // opcode 0x34
+ { ExecutePUSHn }, // opcode 0x35
+ { ExecutePOPn }, // opcode 0x36
+ { ExecuteMOVI }, // opcode 0x37 - mov immediate data
+ { ExecuteMOVIn }, // opcode 0x38 - mov immediate natural
+ { ExecuteMOVREL }, // opcode 0x39 - move data relative to PC
+ { NULL }, // opcode 0x3a
+ { NULL }, // opcode 0x3b
+ { NULL }, // opcode 0x3c
+ { NULL }, // opcode 0x3d
+ { NULL }, // opcode 0x3e
+ { NULL } // opcode 0x3f
+};
+
+//
+// Length of JMP instructions, depending on upper two bits of opcode.
+//
+CONST UINT8 mJMPLen[] = { 2, 2, 6, 10 };
+
+/**
+ Given a pointer to a new VM context, execute one or more instructions. This
+ function is only used for test purposes via the EBC VM test protocol.
+
+ @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param VmPtr A pointer to a VM context.
+ @param InstructionCount A pointer to a UINTN value holding the number of
+ instructions to execute. If it holds value of 0,
+ then the instruction to be executed is 1.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcExecuteInstructions (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN OUT UINTN *InstructionCount
+ )
+{
+ UINTN ExecFunc;
+ EFI_STATUS Status;
+ UINTN InstructionsLeft;
+ UINTN SavedInstructionCount;
+
+ Status = EFI_SUCCESS;
+
+ if (*InstructionCount == 0) {
+ InstructionsLeft = 1;
+ } else {
+ InstructionsLeft = *InstructionCount;
+ }
+
+ SavedInstructionCount = *InstructionCount;
+ *InstructionCount = 0;
+
+ //
+ // Index into the opcode table using the opcode byte for this instruction.
+ // This gives you the execute function, which we first test for null, then
+ // call it if it's not null.
+ //
+ while (InstructionsLeft != 0) {
+ ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
+ if (ExecFunc == (UINTN) NULL) {
+ EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
+ return EFI_UNSUPPORTED;
+ } else {
+ mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
+ *InstructionCount = *InstructionCount + 1;
+ }
+
+ //
+ // Decrement counter if applicable
+ //
+ if (SavedInstructionCount != 0) {
+ InstructionsLeft--;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute an EBC image from an entry point or from a published protocol.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EbcExecute (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINTN ExecFunc;
+ UINT8 StackCorrupted;
+ EFI_STATUS Status;
+ EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *EbcSimpleDebugger;
+
+ mVmPtr = VmPtr;
+ EbcSimpleDebugger = NULL;
+ Status = EFI_SUCCESS;
+ StackCorrupted = 0;
+
+ //
+ // Make sure the magic value has been put on the stack before we got here.
+ //
+ if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {
+ StackCorrupted = 1;
+ }
+
+ VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->Gpr[0] + 8);
+
+ //
+ // Try to get the debug support for EBC
+ //
+ DEBUG_CODE_BEGIN ();
+ Status = gBS->LocateProtocol (
+ &gEfiEbcSimpleDebuggerProtocolGuid,
+ NULL,
+ (VOID **) &EbcSimpleDebugger
+ );
+ if (EFI_ERROR (Status)) {
+ EbcSimpleDebugger = NULL;
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Save the start IP for debug. For example, if we take an exception we
+ // can print out the location of the exception relative to the entry point,
+ // which could then be used in a disassembly listing to find the problem.
+ //
+ VmPtr->EntryPoint = (VOID *) VmPtr->Ip;
+
+ //
+ // We'll wait for this flag to know when we're done. The RET
+ // instruction sets it if it runs out of stack.
+ //
+ VmPtr->StopFlags = 0;
+ while ((VmPtr->StopFlags & STOPFLAG_APP_DONE) == 0) {
+ //
+ // If we've found a simple debugger protocol, call it
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EbcSimpleDebugger != NULL) {
+ EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Use the opcode bits to index into the opcode dispatch table. If the
+ // function pointer is null then generate an exception.
+ //
+ ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
+ if (ExecFunc == (UINTN) NULL) {
+ EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ EbcDebuggerHookExecuteStart (VmPtr);
+
+ //
+ // The EBC VM is a strongly ordered processor, so perform a fence operation before
+ // and after each instruction is executed.
+ //
+ MemoryFence ();
+
+ mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
+
+ MemoryFence ();
+
+ EbcDebuggerHookExecuteEnd (VmPtr);
+
+ //
+ // If the step flag is set, signal an exception and continue. We don't
+ // clear it here. Assuming the debugger is responsible for clearing it.
+ //
+ if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {
+ EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);
+ }
+ //
+ // Make sure stack has not been corrupted. Only report it once though.
+ //
+ if ((StackCorrupted == 0) && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {
+ EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
+ StackCorrupted = 1;
+ }
+ if ((StackCorrupted == 0) && ((UINT64)VmPtr->Gpr[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {
+ EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
+ StackCorrupted = 1;
+ }
+ }
+
+Done:
+ mVmPtr = NULL;
+
+ return Status;
+}
+
+
+/**
+ Execute the MOVxx instructions.
+
+ Instruction format:
+
+ MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
+ MOVqq {@}R1 {Index64}, {@}R2 {Index64}
+
+ Copies contents of [R2] -> [R1], zero extending where required.
+
+ First character indicates the size of the move.
+ Second character indicates the size of the index(s).
+
+ Invalid to have R1 direct with index.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVxx (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 OpcMasked;
+ UINT8 Operands;
+ UINT8 Size;
+ UINT8 MoveSize;
+ INT16 Index16;
+ INT32 Index32;
+ INT64 Index64Op1;
+ INT64 Index64Op2;
+ UINT64 Data64;
+ UINT64 DataMask;
+ UINTN Source;
+
+ Opcode = GETOPCODE (VmPtr);
+ OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);
+
+ //
+ // Get the operands byte so we can get R1 and R2
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Assume no indexes
+ //
+ Index64Op1 = 0;
+ Index64Op2 = 0;
+ Data64 = 0;
+
+ //
+ // Determine if we have an index/immediate data. Base instruction size
+ // is 2 (opcode + operands). Add to this size each index specified.
+ //
+ Size = 2;
+ if ((Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
+ //
+ // Determine size of the index from the opcode. Then get it.
+ //
+ if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {
+ //
+ // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
+ // Get one or both index values.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Index64Op1 = (INT64) Index16;
+ Size += sizeof (UINT16);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, Size);
+ Index64Op2 = (INT64) Index16;
+ Size += sizeof (UINT16);
+ }
+ } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {
+ //
+ // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index32 = VmReadIndex32 (VmPtr, 2);
+ Index64Op1 = (INT64) Index32;
+ Size += sizeof (UINT32);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index32 = VmReadIndex32 (VmPtr, Size);
+ Index64Op2 = (INT64) Index32;
+ Size += sizeof (UINT32);
+ }
+ } else if (OpcMasked == OPCODE_MOVQQ) {
+ //
+ // MOVqq -- only form with a 64-bit index
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index64Op1 = VmReadIndex64 (VmPtr, 2);
+ Size += sizeof (UINT64);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index64Op2 = VmReadIndex64 (VmPtr, Size);
+ Size += sizeof (UINT64);
+ }
+ } else {
+ //
+ // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Determine the size of the move, and create a mask for it so we can
+ // clear unused bits.
+ //
+ if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {
+ MoveSize = DATA_SIZE_8;
+ DataMask = 0xFF;
+ } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {
+ MoveSize = DATA_SIZE_16;
+ DataMask = 0xFFFF;
+ } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {
+ MoveSize = DATA_SIZE_32;
+ DataMask = 0xFFFFFFFF;
+ } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {
+ MoveSize = DATA_SIZE_64;
+ DataMask = (UINT64)~0;
+ } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {
+ MoveSize = DATA_SIZE_N;
+ DataMask = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));
+ } else {
+ //
+ // We were dispatched to this function and we don't recognize the opcode
+ //
+ EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now get the source address
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ //
+ // Indirect form @R2. Compute address of operand2
+ //
+ Source = (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
+ //
+ // Now get the data from the source. Always 0-extend and let the compiler
+ // sign-extend where required.
+ //
+ switch (MoveSize) {
+ case DATA_SIZE_8:
+ Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_16:
+ Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_32:
+ Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_64:
+ Data64 = (UINT64) VmReadMem64 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_N:
+ Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);
+ break;
+
+ default:
+ //
+ // not reached
+ //
+ break;
+ }
+ } else {
+ //
+ // Not indirect source: MOVxx {@}Rx, Ry [Index]
+ //
+ Data64 = (UINT64) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
+ //
+ // Did Operand2 have an index? If so, treat as two signed values since
+ // indexes are signed values.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ //
+ // NOTE: need to find a way to fix this, most likely by changing the VM
+ // implementation to remove the stack gap. To do that, we'd need to
+ // allocate stack space for the VM and actually set the system
+ // stack pointer to the allocated buffer when the VM starts.
+ //
+ // Special case -- if someone took the address of a function parameter
+ // then we need to make sure it's not in the stack gap. We can identify
+ // this situation if (Operand2 register == 0) && (Operand2 is direct)
+ // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
+ // Situations that to be aware of:
+ // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
+ //
+ if ((OPERAND2_REGNUM (Operands) == 0) &&
+ (!OPERAND2_INDIRECT (Operands)) &&
+ (Index64Op2 > 0) &&
+ (OPERAND1_REGNUM (Operands) == 0) &&
+ (OPERAND1_INDIRECT (Operands))
+ ) {
+ Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);
+ }
+ }
+ }
+ //
+ // Now write it back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ //
+ // Reuse the Source variable to now be dest.
+ //
+ Source = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index64Op1);
+ //
+ // Do the write based on the size
+ //
+ switch (MoveSize) {
+ case DATA_SIZE_8:
+ VmWriteMem8 (VmPtr, Source, (UINT8) Data64);
+ break;
+
+ case DATA_SIZE_16:
+ VmWriteMem16 (VmPtr, Source, (UINT16) Data64);
+ break;
+
+ case DATA_SIZE_32:
+ VmWriteMem32 (VmPtr, Source, (UINT32) Data64);
+ break;
+
+ case DATA_SIZE_64:
+ VmWriteMem64 (VmPtr, Source, Data64);
+ break;
+
+ case DATA_SIZE_N:
+ VmWriteMemN (VmPtr, Source, (UINTN) Data64);
+ break;
+
+ default:
+ //
+ // not reached
+ //
+ break;
+ }
+ } else {
+ //
+ // Operand1 direct.
+ // Make sure we didn't have an index on operand1.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Direct storage in register. Clear unused bits and store back to
+ // register.
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC BREAK instruction.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteBREAK (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Operands;
+ VOID *EbcEntryPoint;
+ VOID *Thunk;
+ UINT64 U64EbcEntryPoint;
+ INT32 Offset;
+
+ Thunk = NULL;
+ Operands = GETOPERANDS (VmPtr);
+ switch (Operands) {
+ //
+ // Runaway program break. Generate an exception and terminate
+ //
+ case 0:
+ EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
+ break;
+
+ //
+ // Get VM version -- return VM revision number in R7
+ //
+ case 1:
+ //
+ // Bits:
+ // 63-17 = 0
+ // 16-8 = Major version
+ // 7-0 = Minor version
+ //
+ VmPtr->Gpr[7] = GetVmVersion ();
+ break;
+
+ //
+ // Debugger breakpoint
+ //
+ case 3:
+ VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;
+ //
+ // See if someone has registered a handler
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ break;
+
+ //
+ // System call, which there are none, so NOP it.
+ //
+ case 4:
+ break;
+
+ //
+ // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
+ // "offset from self" pointer to the EBC entry point.
+ // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
+ //
+ case 5:
+ Offset = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7]);
+ U64EbcEntryPoint = (UINT64) (VmPtr->Gpr[7] + Offset + 4);
+ EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint;
+
+ //
+ // Now create a new thunk
+ //
+ Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Finally replace the EBC entry point memory with the thunk address
+ //
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[7], (UINT64) (UINTN) Thunk);
+ break;
+
+ //
+ // Compiler setting version per value in R7
+ //
+ case 6:
+ VmPtr->CompilerVersion = (UINT32) VmPtr->Gpr[7];
+ //
+ // Check compiler version against VM version?
+ //
+ break;
+
+ //
+ // Unhandled break code. Signal exception.
+ //
+ default:
+ EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
+ break;
+ }
+ //
+ // Advance IP
+ //
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the JMP instruction.
+
+ Instruction syntax:
+ JMP64{cs|cc} Immed64
+ JMP32{cs|cc} {@}R1 {Immed32|Index32}
+
+ Encoding:
+ b0.7 - immediate data present
+ b0.6 - 1 = 64 bit immediate data
+ 0 = 32 bit immediate data
+ b1.7 - 1 = conditional
+ b1.6 1 = CS (condition set)
+ 0 = CC (condition clear)
+ b1.4 1 = relative address
+ 0 = absolute address
+ b1.3 1 = operand1 indirect
+ b1.2-0 operand 1
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 CompareSet;
+ UINT8 ConditionFlag;
+ UINT8 Size;
+ UINT8 Operand;
+ UINT64 Data64;
+ INT32 Index32;
+ UINTN Addr;
+
+ Operand = GETOPERANDS (VmPtr);
+ Opcode = GETOPCODE (VmPtr);
+
+ //
+ // Get instruction length from the opcode. The upper two bits are used here
+ // to index into the length array.
+ //
+ Size = mJMPLen[(Opcode >> 6) & 0x03];
+
+ //
+ // Decode instruction conditions
+ // If we haven't met the condition, then simply advance the IP and return.
+ //
+ CompareSet = (UINT8) (((Operand & JMP_M_CS) != 0) ? 1 : 0);
+ ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
+ if ((Operand & CONDITION_M_CONDITIONAL) != 0) {
+ if (CompareSet != ConditionFlag) {
+ EbcDebuggerHookJMPStart (VmPtr);
+ VmPtr->Ip += Size;
+ EbcDebuggerHookJMPEnd (VmPtr);
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Check for 64-bit form and do it right away since it's the most
+ // straight-forward form.
+ //
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ //
+ // Double check for immediate-data, which is required. If not there,
+ // then signal an exception
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 64-bit immediate data is full address. Read the immediate data,
+ // check for alignment, and jump absolute.
+ //
+ Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);
+ if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Take jump -- relative or absolute
+ //
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Data64 + Size;
+ } else {
+ VmPtr->Ip = (VMIP) (UINTN) Data64;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // 32-bit forms:
+ // Get the index if there is one. May be either an index, or an immediate
+ // offset depending on indirect operand.
+ // JMP32 @R1 Index32 -- immediate data is an index
+ // JMP32 R1 Immed32 -- immedate data is an offset
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operand)) {
+ Index32 = VmReadIndex32 (VmPtr, 2);
+ } else {
+ Index32 = VmReadImmed32 (VmPtr, 2);
+ }
+ } else {
+ Index32 = 0;
+ }
+ //
+ // Get the register data. If R == 0, then special case where it's ignored.
+ //
+ if (OPERAND1_REGNUM (Operand) == 0) {
+ Data64 = 0;
+ } else {
+ Data64 = (UINT64) OPERAND1_REGDATA (VmPtr, Operand);
+ }
+ //
+ // Decode the forms
+ //
+ if (OPERAND1_INDIRECT (Operand)) {
+ //
+ // Form: JMP32 @Rx {Index32}
+ //
+ Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
+ if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Addr + Size;
+ } else {
+ VmPtr->Ip = (VMIP) Addr;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ } else {
+ //
+ // Form: JMP32 Rx {Immed32}
+ //
+ Addr = (UINTN) (Data64 + Index32);
+ if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Addr + Size;
+ } else {
+ VmPtr->Ip = (VMIP) Addr;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC JMP8 instruction.
+
+ Instruction syntax:
+ JMP8{cs|cc} Offset/2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP8 (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 ConditionFlag;
+ UINT8 CompareSet;
+ INT8 Offset;
+
+ //
+ // Decode instruction.
+ //
+ Opcode = GETOPCODE (VmPtr);
+ CompareSet = (UINT8) (((Opcode & JMP_M_CS) != 0) ? 1 : 0);
+ ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
+
+ //
+ // If we haven't met the condition, then simply advance the IP and return
+ //
+ if ((Opcode & CONDITION_M_CONDITIONAL) != 0) {
+ if (CompareSet != ConditionFlag) {
+ EbcDebuggerHookJMP8Start (VmPtr);
+ VmPtr->Ip += 2;
+ EbcDebuggerHookJMP8End (VmPtr);
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Get the offset from the instruction stream. It's relative to the
+ // following instruction, and divided by 2.
+ //
+ Offset = VmReadImmed8 (VmPtr, 1);
+ //
+ // Want to check for offset == -2 and then raise an exception?
+ //
+ EbcDebuggerHookJMP8Start (VmPtr);
+ VmPtr->Ip += (Offset * 2) + 2;
+ EbcDebuggerHookJMP8End (VmPtr);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVI.
+
+ Instruction syntax:
+
+ MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ First variable character specifies the move size
+ Second variable character specifies size of the immediate data
+
+ Sign-extend the immediate data to the size of the operation, and zero-extend
+ if storing to a register.
+
+ Operand1 direct with index/immed is invalid.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVI (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT64 ImmData64;
+ UINT64 Op1;
+ UINT64 Mask64;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Extract the immediate data. Sign-extend always.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now write back the result
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Operand1 direct. Make sure it didn't have an index.
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Writing directly to a register. Clear unused bits.
+ //
+ if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
+ Mask64 = 0x000000FF;
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
+ Mask64 = 0x0000FFFF;
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
+ Mask64 = 0x00000000FFFFFFFF;
+ } else {
+ Mask64 = (UINT64)~0;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;
+ } else {
+ //
+ // Get the address then write back based on size of the move
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
+ VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
+ VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
+ VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);
+ } else {
+ VmWriteMem64 (VmPtr, (UINTN) Op1, (UINT64) ImmData64);
+ }
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOV immediate natural. This instruction moves an immediate
+ index value into a register or memory location.
+
+ Instruction syntax:
+
+ MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVIn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT16 ImmedIndex16;
+ INT32 ImmedIndex32;
+ INT64 ImmedIndex64;
+ UINT64 Op1;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the operand1 index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Extract the immediate data and convert to a 64-bit index.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmedIndex16 = VmReadIndex16 (VmPtr, Size);
+ ImmedIndex64 = (INT64) ImmedIndex16;
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmedIndex32 = VmReadIndex32 (VmPtr, Size);
+ ImmedIndex64 = (INT64) ImmedIndex32;
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmedIndex64 = VmReadIndex64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now write back the result
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
+ // is illegal
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmedIndex64;
+ } else {
+ //
+ // Get the address
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN)(INTN) ImmedIndex64);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVREL instruction.
+ Dest <- Ip + ImmData
+
+ Instruction syntax:
+
+ MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVREL (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT64 ImmData64;
+ UINT64 Op1;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the Operand 1 index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Get the immediate data.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmData64 = VmReadImmed64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Compute the value and write back the result
+ //
+ Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Check for illegal combination of operand1 direct with immediate data
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;
+ } else {
+ //
+ // Get the address = [Rx] + Index16
+ // Write back the result. Always a natural size write, since
+ // we're talking addresses here.
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnw (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Op1Index;
+ INT16 Op2Index;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operand bytes
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ Op1Index = Op2Index = 0;
+
+ //
+ // Get the indexes if present.
+ //
+ Size = 2;
+ if ((Opcode & OPCODE_M_IMMED_OP1) !=0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1Index = VmReadIndex16 (VmPtr, 2);
+ } else {
+ //
+ // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ Size += sizeof (UINT16);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2Index = VmReadIndex16 (VmPtr, Size);
+ } else {
+ Op2Index = VmReadImmed16 (VmPtr, Size);
+ }
+
+ Size += sizeof (UINT16);
+ }
+ //
+ // Get the data from the source.
+ //
+ Op2 = (UINT64)(INT64)(INTN)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2 = (UINT64)(INT64)(INTN)VmReadMemN (VmPtr, (UINTN) Op2);
+ }
+ //
+ // Now write back the result.
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ } else {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT32 Op1Index;
+ INT32 Op2Index;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operand bytes
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ Op1Index = Op2Index = 0;
+
+ //
+ // Get the indexes if present.
+ //
+ Size = 2;
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1Index = VmReadIndex32 (VmPtr, 2);
+ } else {
+ //
+ // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ Size += sizeof (UINT32);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2Index = VmReadIndex32 (VmPtr, Size);
+ } else {
+ Op2Index = VmReadImmed32 (VmPtr, Size);
+ }
+
+ Size += sizeof (UINT32);
+ }
+ //
+ // Get the data from the source.
+ //
+ Op2 = (UINT64)(INT64)(INTN)(INT64)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2 = (UINT64)(INT64)(INTN)(INT64)VmReadMemN (VmPtr, (UINTN) Op2);
+ }
+ //
+ // Now write back the result.
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ } else {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC PUSHn instruction
+
+ Instruction syntax:
+ PUSHn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSHn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ UINTN DataN;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get index if present
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data to push
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ DataN = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16);
+ }
+ //
+ // Adjust the stack down.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINTN);
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], DataN);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC PUSH instruction.
+
+ Instruction syntax:
+ PUSH[32|64] {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSH (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT32 Data32;
+ UINT64 Data64;
+ INT16 Index16;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate index if present, then advance the IP.
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data to push
+ //
+ if ((Opcode & PUSHPOP_M_64) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ Data64 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Adjust the stack down, then write back the data
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], Data64);
+ } else {
+ //
+ // 32-bit data
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ Data32 = (UINT32) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Adjust the stack down and write the data
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT32);
+ VmWriteMem32 (VmPtr, (UINTN) VmPtr->Gpr[0], Data32);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC POPn instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOPn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ UINTN DataN;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate data if present, and advance the IP
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Read the data off the stack, then adjust the stack pointer
+ //
+ DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINTN);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), DataN);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) (UINTN) (DataN + Index16);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC POP instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ INT32 Data32;
+ UINT64 Data64;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate data if present, and advance the IP.
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data off the stack, then write it to the appropriate location
+ //
+ if ((Opcode & PUSHPOP_M_64) != 0) {
+ //
+ // Read the data off the stack, then adjust the stack pointer
+ //
+ Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINT64);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data64);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 + Index16;
+ }
+ } else {
+ //
+ // 32-bit pop. Read it off the stack and adjust the stack pointer
+ //
+ Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINT32);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data32);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements the EBC CALL instruction.
+
+ Instruction format:
+ CALL64 Immed64
+ CALL32 {@}R1 {Immed32|Index32}
+ CALLEX64 Immed64
+ CALLEX16 {@}R1 {Immed32}
+
+ If Rx == R0, then it's a PC relative call to PC = PC + imm32.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCALL (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT32 Immed32;
+ UINT8 Size;
+ INT64 Immed64;
+ VOID *FramePtr;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EbcDebuggerHookCALLEXStart (VmPtr);
+ } else {
+ EbcDebuggerHookCALLStart (VmPtr);
+ }
+
+ //
+ // Assign these as well to avoid compiler warnings
+ //
+ Immed64 = 0;
+ Immed32 = 0;
+
+ FramePtr = VmPtr->FramePtr;
+ //
+ // Determine the instruction size, and get immediate data if present
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ Immed64 = VmReadImmed64 (VmPtr, 2);
+ Size = 10;
+ } else {
+ //
+ // If register operand is indirect, then the immediate data is an index
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Immed32 = VmReadIndex32 (VmPtr, 2);
+ } else {
+ Immed32 = VmReadImmed32 (VmPtr, 2);
+ }
+
+ Size = 6;
+ }
+ } else {
+ Size = 2;
+ }
+ //
+ // If it's a call to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+ }
+ //
+ // If 64-bit data, then absolute jump only
+ //
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ //
+ // Native or EBC call?
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ VmPtr->Ip = (VMIP) (UINTN) Immed64;
+ } else {
+ //
+ // Call external function, get the return value, and advance the IP
+ //
+ EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ }
+ } else {
+ //
+ // Get the register data. If operand1 == 0, then ignore register and
+ // take immediate data as relative or absolute address.
+ // Compiler should take care of upper bits if 32-bit machine.
+ //
+ if (OPERAND1_REGNUM (Operands) != 0) {
+ Immed64 = (UINT64) (UINTN) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ }
+ //
+ // Get final address
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));
+ } else {
+ Immed64 += Immed32;
+ }
+ //
+ // Now determine if external call, and then if relative or absolute
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ //
+ // EBC call. Relative or absolute? If relative, then it's relative to the
+ // start of the next instruction.
+ //
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ VmPtr->Ip += Immed64 + Size;
+ } else {
+ VmPtr->Ip = (VMIP) (UINTN) Immed64;
+ }
+ } else {
+ //
+ // Native call. Relative or absolute?
+ //
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ } else {
+ if ((VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) != 0) {
+ CpuBreakpoint ();
+ }
+
+ EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ }
+ }
+ }
+
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EbcDebuggerHookCALLEXEnd (VmPtr);
+ } else {
+ EbcDebuggerHookCALLEnd (VmPtr);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC RET instruction.
+
+ Instruction syntax:
+ RET
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteRET (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+
+ EbcDebuggerHookRETStart (VmPtr);
+
+ //
+ // If we're at the top of the stack, then simply set the done
+ // flag and return
+ //
+ if (VmPtr->StackRetAddr == (UINT64) VmPtr->Gpr[0]) {
+ VmPtr->StopFlags |= STOPFLAG_APP_DONE;
+ } else {
+ //
+ // Pull the return address off the VM app's stack and set the IP
+ // to it
+ //
+ if (!IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ }
+ //
+ // Restore the IP and frame pointer from the stack
+ //
+ VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += 8;
+ VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += 8;
+ }
+
+
+ EbcDebuggerHookRETEnd (VmPtr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC CMP instruction.
+
+ Instruction syntax:
+ CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ UINT32 Flag;
+ INT64 Op2;
+ INT64 Op1;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get the register data we're going to compare to
+ //
+ Op1 = VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ //
+ // Get immediate data
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Now get Op2
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ if ((Opcode & OPCODE_M_64BIT) != 0) {
+ Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16));
+ } else {
+ //
+ // 32-bit operations. 0-extend the values for all cases.
+ //
+ Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16)));
+ }
+ } else {
+ Op2 = VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Now do the compare
+ //
+ Flag = 0;
+ if ((Opcode & OPCODE_M_64BIT) != 0) {
+ //
+ // 64-bit compares
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPEQ:
+ if (Op1 == Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPLTE:
+ if (Op1 <= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPGTE:
+ if (Op1 >= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPULTE:
+ if ((UINT64) Op1 <= (UINT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPUGTE:
+ if ((UINT64) Op1 >= (UINT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ } else {
+ //
+ // 32-bit compares
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPEQ:
+ if ((INT32) Op1 == (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPLTE:
+ if ((INT32) Op1 <= (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPGTE:
+ if ((INT32) Op1 >= (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPULTE:
+ if ((UINT32) Op1 <= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPUGTE:
+ if ((UINT32) Op1 >= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ }
+ //
+ // Now set the flag accordingly for the comparison
+ //
+ if (Flag != 0) {
+ VMFLAG_SET (VmPtr, VMFLAGS_CC);
+ } else {
+ VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
+ }
+ //
+ // Advance the IP
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC CMPI instruction
+
+ Instruction syntax:
+ CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMPI (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT64 Op1;
+ INT64 Op2;
+ INT16 Index16;
+ UINT32 Flag;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get operand1 index if present
+ //
+ Size = 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size += 2;
+ } else {
+ Index16 = 0;
+ }
+ //
+ // Get operand1 data we're going to compare to
+ //
+ Op1 = (INT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if (OPERAND1_INDIRECT (Operands)) {
+ //
+ // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
+ //
+ if ((Opcode & OPCODE_M_CMPI64) != 0) {
+ Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);
+ } else {
+ Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);
+ }
+ } else {
+ //
+ // Better not have been an index with direct. That is, CMPI R1 Index,...
+ // is illegal.
+ //
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ VmPtr->Ip += Size;
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Get immediate data -- 16- or 32-bit sign extended
+ //
+ if ((Opcode & OPCODE_M_CMPI32_DATA) != 0) {
+ Op2 = (INT64) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else {
+ //
+ // 16-bit immediate data. Sign extend always.
+ //
+ Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));
+ Size += 2;
+ }
+ //
+ // Now do the compare
+ //
+ Flag = 0;
+ if ((Opcode & OPCODE_M_CMPI64) != 0) {
+ //
+ // 64 bit comparison
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPIEQ:
+ if (Op1 == (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPILTE:
+ if (Op1 <= (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIGTE:
+ if (Op1 >= (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIULTE:
+ if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIUGTE:
+ if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ } else {
+ //
+ // 32-bit comparisons
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPIEQ:
+ if ((INT32) Op1 == Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPILTE:
+ if ((INT32) Op1 <= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIGTE:
+ if ((INT32) Op1 >= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIULTE:
+ if ((UINT32) Op1 <= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIUGTE:
+ if ((UINT32) Op1 >= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ }
+ //
+ // Now set the flag accordingly for the comparison
+ //
+ if (Flag != 0) {
+ VMFLAG_SET (VmPtr, VMFLAGS_CC);
+ } else {
+ VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
+ }
+ //
+ // Advance the IP
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC NOT instruction.s
+
+ Instruction syntax:
+ NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return ~Op2
+
+**/
+UINT64
+ExecuteNOT (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return ~Op2;
+}
+
+
+/**
+ Execute the EBC NEG instruction.
+
+ Instruction syntax:
+ NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op2 * -1
+
+**/
+UINT64
+ExecuteNEG (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return ~Op2 + 1;
+}
+
+
+/**
+ Execute the EBC ADD instruction.
+
+ Instruction syntax:
+ ADD[32|64] {@}R1, {@}R2 {Index16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 + Op2
+
+**/
+UINT64
+ExecuteADD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 + Op2;
+}
+
+
+/**
+ Execute the EBC SUB instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 - Op2
+
+**/
+UINT64
+ExecuteSUB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));
+ } else {
+ return (UINT64) ((INT64) ((INT32) ((INT32) Op1 - (INT32) Op2)));
+ }
+}
+
+
+/**
+ Execute the EBC MUL instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 * Op2
+
+**/
+UINT64
+ExecuteMUL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return MultS64x64 ((INT64)Op1, (INT64)Op2);
+ } else {
+ return (UINT64) ((INT64) ((INT32) ((INT32) Op1 * (INT32) Op2)));
+ }
+}
+
+
+/**
+ Execute the EBC MULU instruction
+
+ Instruction syntax:
+ MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 * (unsigned)Op2
+
+**/
+UINT64
+ExecuteMULU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return MultU64x64 (Op1, Op2);
+ } else {
+ return (UINT64) ((UINT32) ((UINT32) Op1 * (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC DIV instruction.
+
+ Instruction syntax:
+ DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 / Op2
+
+**/
+UINT64
+ExecuteDIV (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return 0;
+ } else {
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));
+ } else {
+ return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));
+ }
+ }
+}
+
+
+/**
+ Execute the EBC DIVU instruction
+
+ Instruction syntax:
+ DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 / (unsigned)Op2
+
+**/
+UINT64
+ExecuteDIVU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ UINT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ //
+ // Get the destination register
+ //
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) (DivU64x64Remainder (Op1, Op2, &Remainder));
+ } else {
+ return (UINT64) ((UINT32) Op1 / (UINT32) Op2);
+ }
+ }
+}
+
+
+/**
+ Execute the EBC MOD instruction.
+
+ Instruction syntax:
+ MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 MODULUS Op2
+
+**/
+UINT64
+ExecuteMOD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);
+ return Remainder;
+ }
+}
+
+
+/**
+ Execute the EBC MODU instruction.
+
+ Instruction syntax:
+ MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 UNSIGNED_MODULUS Op2
+
+**/
+UINT64
+ExecuteMODU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ UINT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ DivU64x64Remainder (Op1, Op2, &Remainder);
+ return Remainder;
+ }
+}
+
+
+/**
+ Execute the EBC AND instruction.
+
+ Instruction syntax:
+ AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 AND Op2
+
+**/
+UINT64
+ExecuteAND (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 & Op2;
+}
+
+
+/**
+ Execute the EBC OR instruction.
+
+ Instruction syntax:
+ OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 OR Op2
+
+**/
+UINT64
+ExecuteOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 | Op2;
+}
+
+
+/**
+ Execute the EBC XOR instruction.
+
+ Instruction syntax:
+ XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 XOR Op2
+
+**/
+UINT64
+ExecuteXOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 ^ Op2;
+}
+
+
+/**
+ Execute the EBC SHL shift left instruction.
+
+ Instruction syntax:
+ SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 << Op2
+
+**/
+UINT64
+ExecuteSHL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return LShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC SHR instruction.
+
+ Instruction syntax:
+ SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (unsigned operands)
+
+**/
+UINT64
+ExecuteSHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return RShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);
+ }
+}
+
+
+/**
+ Execute the EBC ASHR instruction.
+
+ Instruction syntax:
+ ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (signed)
+
+**/
+UINT64
+ExecuteASHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return ARShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC EXTNDB instruction to sign-extend a byte value.
+
+ Instruction syntax:
+ EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT8)Op2
+
+**/
+UINT64
+ExecuteEXTNDB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT8 Data8;
+ INT64 Data64;
+ //
+ // Convert to byte, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data8 = (INT8) Op2;
+ Data64 = (INT64) Data8;
+
+ return (UINT64) Data64;
+}
+
+
+/**
+ Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
+
+ Instruction syntax:
+ EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT16)Op2
+
+**/
+UINT64
+ExecuteEXTNDW (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT16 Data16;
+ INT64 Data64;
+ //
+ // Convert to word, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data16 = (INT16) Op2;
+ Data64 = (INT64) Data16;
+
+ return (UINT64) Data64;
+}
+//
+// Execute the EBC EXTNDD instruction.
+//
+// Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
+// EXTNDD Dest, Source
+//
+// Operation: Dest <- SignExtended((DWORD)Source))
+//
+
+/**
+ Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
+
+ Instruction syntax:
+ EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT32)Op2
+
+**/
+UINT64
+ExecuteEXTNDD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT32 Data32;
+ INT64 Data64;
+ //
+ // Convert to 32-bit value, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data32 = (INT32) Op2;
+ Data64 = (INT64) Data32;
+
+ return (UINT64) Data64;
+}
+
+
+/**
+ Execute all the EBC signed data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ //
+ // Just call the data manipulation function with a flag indicating this
+ // is a signed operation.
+ //
+ return ExecuteDataManip (VmPtr, TRUE);
+}
+
+
+/**
+ Execute all the EBC unsigned data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteUnsignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ //
+ // Just call the data manipulation function with a flag indicating this
+ // is not a signed operation.
+ //
+ return ExecuteDataManip (VmPtr, FALSE);
+}
+
+
+/**
+ Execute all the EBC data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+ @param IsSignedOp Indicates whether the operand is signed or not.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteDataManip (
+ IN VM_CONTEXT *VmPtr,
+ IN BOOLEAN IsSignedOp
+ )
+{
+ UINT8 Opcode;
+ INT16 Index16;
+ UINT8 Operands;
+ UINT8 Size;
+ UINT64 Op1;
+ UINT64 Op2;
+ INTN DataManipDispatchTableIndex;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Determine if we have immediate data by the opcode
+ //
+ if ((Opcode & DATAMANIP_M_IMMDATA) != 0) {
+ //
+ // Index16 if Ry is indirect, or Immed16 if Ry direct.
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
+ //
+ Op2 = (UINT64) VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
+ if (OPERAND2_INDIRECT (Operands)) {
+ //
+ // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
+ //
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);
+ } else {
+ //
+ // Read as signed value where appropriate.
+ //
+ if (IsSignedOp) {
+ Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));
+ } else {
+ Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);
+ }
+ }
+ } else {
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ if (IsSignedOp) {
+ Op2 = (UINT64) (INT64) ((INT32) Op2);
+ } else {
+ Op2 = (UINT64) ((UINT32) Op2);
+ }
+ }
+ }
+ //
+ // Get operand1 (destination and sometimes also an actual operand)
+ // of form {@}R1
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if (OPERAND1_INDIRECT (Operands)) {
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);
+ } else {
+ if (IsSignedOp) {
+ Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));
+ } else {
+ Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);
+ }
+ }
+ } else {
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ if (IsSignedOp) {
+ Op1 = (UINT64) (INT64) ((INT32) Op1);
+ } else {
+ Op1 = (UINT64) ((UINT32) Op1);
+ }
+ }
+ }
+ //
+ // Dispatch to the computation function
+ //
+ DataManipDispatchTableIndex = (Opcode & OPCODE_M_OPCODE) - OPCODE_NOT;
+ if ((DataManipDispatchTableIndex < 0) ||
+ (DataManipDispatchTableIndex >= ARRAY_SIZE (mDataManipDispatchTable))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INVALID_OPCODE,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ //
+ // Advance and return
+ //
+ VmPtr->Ip += Size;
+ return EFI_UNSUPPORTED;
+ } else {
+ Op2 = mDataManipDispatchTable[DataManipDispatchTableIndex](VmPtr, Op1, Op2);
+ }
+ //
+ // Write back the result.
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ VmWriteMem64 (VmPtr, (UINTN) Op1, Op2);
+ } else {
+ VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) Op2);
+ }
+ } else {
+ //
+ // Storage back to a register. Write back, clearing upper bits (as per
+ // the specification) if 32-bit operation.
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF;
+ }
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC LOADSP instruction.
+
+ Instruction syntax:
+ LOADSP SP1, R2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteLOADSP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Operands;
+
+ //
+ // Get the operands
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Do the operation
+ //
+ switch (OPERAND1_REGNUM (Operands)) {
+ //
+ // Set flags
+ //
+ case 0:
+ //
+ // Spec states that this instruction will not modify reserved bits in
+ // the flags register.
+ //
+ VmPtr->Flags = (VmPtr->Flags &~VMFLAGS_ALL_VALID) | (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] & VMFLAGS_ALL_VALID);
+ break;
+
+ default:
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ VmPtr->Ip += 2;
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC STORESP instruction.
+
+ Instruction syntax:
+ STORESP Rx, FLAGS|IP
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSTORESP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Operands;
+
+ //
+ // Get the operands
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Do the operation
+ //
+ switch (OPERAND2_REGNUM (Operands)) {
+ //
+ // Get flags
+ //
+ case 0:
+ //
+ // Retrieve the value in the flags register, then clear reserved bits
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID);
+ break;
+
+ //
+ // Get IP -- address of following instruction
+ //
+ case 1:
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (UINTN) VmPtr->Ip + 2;
+ break;
+
+ default:
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ VmPtr->Ip += 2;
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Decode a 16-bit index to determine the offset. Given an index value:
+
+ b15 - sign bit
+ b14:12 - number of bits in this index assigned to natural units (=a)
+ ba:11 - constant units = ConstUnits
+ b0:a - natural units = NaturalUnits
+
+ Given this info, the offset can be computed by:
+ offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
+
+ Max offset is achieved with index = 0x7FFF giving an offset of
+ 0x27B (32-bit machine) or 0x477 (64-bit machine).
+ Min offset is achieved with index =
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 16-bit index
+ to decode.
+
+ @return The decoded offset.
+
+**/
+INT16
+VmReadIndex16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT16 Index;
+ INT16 Offset;
+ INT16 ConstUnits;
+ INT16 NaturalUnits;
+ INT16 NBits;
+ INT16 Mask;
+
+ //
+ // First read the index from the code stream
+ //
+ Index = VmReadCode16 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = (INT16) ((Index & 0x7000) >> 12);
+
+ //
+ // Scale it for 16-bit indexes
+ //
+ NBits *= 2;
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (INT16) ((INT16)~0 << NBits);
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = (INT16) (Index &~Mask);
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = (INT16) (((Index &~0xF000) & Mask) >> NBits);
+
+ Offset = (INT16) (NaturalUnits * sizeof (UINTN) + ConstUnits);
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x8000) != 0) {
+ //
+ // Do it the hard way to work around a bogus compiler warning
+ //
+ // Offset = -1 * Offset;
+ //
+ Offset = (INT16) ((INT32) Offset * -1);
+ }
+
+ return Offset;
+}
+
+
+/**
+ Decode a 32-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 32-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification.
+
+**/
+INT32
+VmReadIndex32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT32 Index;
+ INT32 Offset;
+ INT32 ConstUnits;
+ INT32 NaturalUnits;
+ INT32 NBits;
+ INT32 Mask;
+
+ Index = VmReadImmed32 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = (Index & 0x70000000) >> 28;
+
+ //
+ // Scale it for 32-bit indexes
+ //
+ NBits *= 4;
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (INT32)~0 << NBits;
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = Index &~Mask;
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = ((Index &~0xF0000000) & Mask) >> NBits;
+
+ Offset = NaturalUnits * sizeof (UINTN) + ConstUnits;
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x80000000) != 0) {
+ Offset = Offset * -1;
+ }
+
+ return Offset;
+}
+
+
+/**
+ Decode a 64-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.s
+ @param CodeOffset Offset from IP of the location of the 64-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification
+
+**/
+INT64
+VmReadIndex64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT64 Index;
+ INT64 Offset;
+ INT64 ConstUnits;
+ INT64 NaturalUnits;
+ INT64 NBits;
+ INT64 Mask;
+
+ Index = VmReadCode64 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = RShiftU64 ((Index & 0x7000000000000000ULL), 60);
+
+ //
+ // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
+ //
+ NBits = LShiftU64 ((UINT64)NBits, 3);
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (LShiftU64 ((UINT64)~0, (UINTN)NBits));
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = Index &~Mask;
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = ARShiftU64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN)NBits);
+
+ Offset = MultU64x64 ((UINT64) NaturalUnits, sizeof (UINTN)) + ConstUnits;
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x8000000000000000ULL) != 0) {
+ Offset = MultS64x64 (Offset, -1);
+ }
+
+ return Offset;
+}
+
+
+/**
+ Writes 8-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT8 Data
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ *(UINT8 *) Addr = Data;
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes 16-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT16 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ *(UINT16 *) Addr = Data;
+ } else {
+ //
+ // Write as two bytes
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem8 (VmPtr, Addr, (UINT8) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem8 (VmPtr, Addr + 1, (UINT8) (Data >> 8))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes 32-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ *(UINT32 *) Addr = Data;
+ } else {
+ //
+ // Write as two words
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem16 (VmPtr, Addr, (UINT16) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem16 (VmPtr, Addr + sizeof (UINT16), (UINT16) (Data >> 16))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes 64-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT64 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ *(UINT64 *) Addr = Data;
+ } else {
+ //
+ // Write as two 32-bit words
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem32 (VmPtr, Addr, (UINT32) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), (UINT32) RShiftU64(Data, 32))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes UINTN data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINTN Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ *(UINTN *) Addr = Data;
+ } else {
+ for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
+ MemoryFence ();
+ Status = VmWriteMem32 (VmPtr, Addr + Index * sizeof (UINT32), (UINT32) Data);
+ MemoryFence ();
+ Data = (UINTN) RShiftU64 ((UINT64)Data, 32);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Reads 8-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT8
+VmReadImmed8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Simply return the data in flat memory space
+ //
+ return * (INT8 *) (VmPtr->Ip + Offset);
+}
+
+/**
+ Reads 16-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT16
+VmReadImmed16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
+ return * (INT16 *) (VmPtr->Ip + Offset);
+ } else {
+ //
+ // All code word reads should be aligned
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ }
+ //
+ // Return unaligned data
+ //
+ return (INT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
+}
+
+
+/**
+ Reads 32-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT32
+VmReadImmed32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ return * (INT32 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadCode16 (VmPtr, Offset);
+ Data |= (UINT32)(VmReadCode16 (VmPtr, Offset + 2) << 16);
+ return Data;
+}
+
+
+/**
+ Reads 64-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT64
+VmReadImmed64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT64 Data64;
+ UINT32 Data32;
+ UINT8 *Ptr;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ return * (UINT64 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data.
+ //
+ Ptr = (UINT8 *) &Data64;
+ Data32 = VmReadCode32 (VmPtr, Offset);
+ *(UINT32 *) Ptr = Data32;
+ Ptr += sizeof (Data32);
+ Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
+ *(UINT32 *) Ptr = Data32;
+ return Data64;
+}
+
+
+/**
+ Reads 16-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 16-bit value from the code stream.
+
+**/
+UINT16
+VmReadCode16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
+ return * (UINT16 *) (VmPtr->Ip + Offset);
+ } else {
+ //
+ // All code word reads should be aligned
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ }
+ //
+ // Return unaligned data
+ //
+ return (UINT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
+}
+
+
+/**
+ Reads 32-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 32-bit value from the code stream.
+
+**/
+UINT32
+VmReadCode32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ return * (UINT32 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadCode16 (VmPtr, Offset);
+ Data |= (VmReadCode16 (VmPtr, Offset + 2) << 16);
+ return Data;
+}
+
+
+/**
+ Reads 64-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 64-bit value from the code stream.
+
+**/
+UINT64
+VmReadCode64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT64 Data64;
+ UINT32 Data32;
+ UINT8 *Ptr;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ return * (UINT64 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data.
+ //
+ Ptr = (UINT8 *) &Data64;
+ Data32 = VmReadCode32 (VmPtr, Offset);
+ *(UINT32 *) Ptr = Data32;
+ Ptr += sizeof (Data32);
+ Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
+ *(UINT32 *) Ptr = Data32;
+ return Data64;
+}
+
+
+/**
+ Reads 8-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 8-bit value from the memory address.
+
+**/
+UINT8
+VmReadMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Simply return the data in flat memory space
+ //
+ return * (UINT8 *) Addr;
+}
+
+/**
+ Reads 16-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 16-bit value from the memory address.
+
+**/
+UINT16
+VmReadMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ return * (UINT16 *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ return (UINT16) (*(UINT8 *) Addr + (*(UINT8 *) (Addr + 1) << 8));
+}
+
+/**
+ Reads 32-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 32-bit value from the memory address.
+
+**/
+UINT32
+VmReadMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINT32 Data;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ return * (UINT32 *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadMem16 (VmPtr, Addr);
+ Data |= (VmReadMem16 (VmPtr, Addr + 2) << 16);
+ return Data;
+}
+
+/**
+ Reads 64-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 64-bit value from the memory address.
+
+**/
+UINT64
+VmReadMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINT64 Data;
+ UINT32 Data32;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ return * (UINT64 *) Addr;
+ }
+ //
+ // Return unaligned data. Assume little endian.
+ //
+ Data32 = VmReadMem32 (VmPtr, Addr);
+ Data = (UINT64) VmReadMem32 (VmPtr, Addr + sizeof (UINT32));
+ Data = LShiftU64 (Data, 32) | Data32;
+ return Data;
+}
+
+
+/**
+ Given an address that EBC is going to read from or write to, return
+ an appropriate address that accounts for a gap in the stack.
+ The stack for this application looks like this (high addr on top)
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+ The EBC assumes that its arguments are at the top of its stack, which
+ is where the VM stack is really. Therefore if the EBC does memory
+ accesses into the VM stack area, then we need to convert the address
+ to point to the EBC entry point arguments area. Do this here.
+
+ @param VmPtr A Pointer to VM context.
+ @param Addr Address of interest
+
+ @return The unchanged address if it's not in the VM stack region. Otherwise,
+ adjust for the stack gap and return the modified address.
+
+**/
+UINTN
+ConvertStackAddr (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));
+ return Addr;
+}
+
+
+/**
+ Read a natural value from memory. May or may not be aligned.
+
+ @param VmPtr current VM context
+ @param Addr the address to read from
+
+ @return The natural value at address Addr.
+
+**/
+UINTN
+VmReadMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINTN Data;
+ volatile UINT32 Size;
+ UINT8 *FromPtr;
+ UINT8 *ToPtr;
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ return * (UINTN *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ Data = 0;
+ FromPtr = (UINT8 *) Addr;
+ ToPtr = (UINT8 *) &Data;
+
+ for (Size = 0; Size < sizeof (Data); Size++) {
+ *ToPtr = *FromPtr;
+ ToPtr++;
+ FromPtr++;
+ }
+
+ return Data;
+}
+
+/**
+ Returns the version of the EBC virtual machine.
+
+ @return The 64-bit version of EBC virtual machine.
+
+**/
+UINT64
+GetVmVersion (
+ VOID
+ )
+{
+ return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)));
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
new file mode 100644
index 000000000..1cb68bc53
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
@@ -0,0 +1,135 @@
+/** @file
+ Header file for Virtual Machine support. Contains EBC defines that can
+ be of use to a disassembler for the most part. Also provides function
+ prototypes for VM functions.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_EXECUTE_H_
+#define _EBC_EXECUTE_H_
+
+//
+// Macros to check and set alignment
+//
+#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
+#define IS_ALIGNED(addr, size) !((UINT32) (addr) & (size - 1))
+
+//
+// Debug macro
+//
+#define EBCMSG(s) gST->ConOut->OutputString (gST->ConOut, s)
+
+
+/**
+ Execute an EBC image from an entry point or from a published protocol.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EbcExecute (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+
+/**
+ Returns the version of the EBC virtual machine.
+
+ @return The 64-bit version of EBC virtual machine.
+
+**/
+UINT64
+GetVmVersion (
+ VOID
+ );
+
+/**
+ Writes UINTN data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINTN Data
+ );
+
+/**
+ Writes 64-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT64 Data
+ );
+
+/**
+ Given a pointer to a new VM context, execute one or more instructions. This
+ function is only used for test purposes via the EBC VM test protocol.
+
+ @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param VmPtr A pointer to a VM context.
+ @param InstructionCount A pointer to a UINTN value holding the number of
+ instructions to execute. If it holds value of 0,
+ then the instruction to be executed is 1.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcExecuteInstructions (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN OUT UINTN *InstructionCount
+ );
+
+#endif // ifndef _EBC_EXECUTE_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c
new file mode 100644
index 000000000..eced1d5c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c
@@ -0,0 +1,1542 @@
+/** @file
+ Top level module for the EBC virtual machine implementation.
+ Provides auxiliary support routines for the VM. That is, routines
+ that are not particularly related to VM execution of EBC instructions.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// We'll keep track of all thunks we create in a linked list. Each
+// thunk is tied to an image handle, so we have a linked list of
+// image handles, with each having a linked list of thunks allocated
+// to that image handle.
+//
+typedef struct _EBC_THUNK_LIST EBC_THUNK_LIST;
+struct _EBC_THUNK_LIST {
+ VOID *ThunkBuffer;
+ EBC_THUNK_LIST *Next;
+};
+
+typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
+struct _EBC_IMAGE_LIST {
+ EBC_IMAGE_LIST *Next;
+ EFI_HANDLE ImageHandle;
+ EBC_THUNK_LIST *ThunkList;
+};
+
+/**
+ This routine is called by the core when an image is being unloaded from
+ memory. Basically we now have the opportunity to do any necessary cleanup.
+ Typically this will include freeing any memory allocated for thunk-creation.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created.
+
+ @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
+ internal list of EBC image handles.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcUnloadImage (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ This is the top-level routine plugged into the EBC protocol. Since thunks
+ are very processor-specific, from here we dispatch directly to the very
+ processor-specific routine EbcCreateThunks().
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created. The EBC interpreter may use this to
+ keep track of any resource allocations
+ performed in loading and executing the image.
+ @param EbcEntryPoint Address of the actual EBC entry point or
+ protocol service the thunk should call.
+ @param Thunk Returned pointer to a thunk created.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
+ @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcCreateThunk (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk
+ );
+
+/**
+ Called to get the version of the interpreter.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Version Pointer to where to store the returned version
+ of the interpreter.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Version pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcGetVersion (
+ IN EFI_EBC_PROTOCOL *This,
+ IN OUT UINT64 *Version
+ );
+
+/**
+ To install default Callback function for the VM interpreter.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when creating periodic event.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This
+ );
+
+/**
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param InterruptType Interrupt type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+CommonEbcExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ The periodic callback function for EBC VM interpreter, which is used
+ to support the EFI debug support protocol.
+
+ @param Event The Periodic Callback Event.
+ @param Context It should be the address of VM_CONTEXT pointer.
+
+**/
+VOID
+EFIAPI
+EbcPeriodicNotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ The VM interpreter calls this function on a periodic basis to support
+ the EFI debug support protocol.
+
+ @param VmPtr Pointer to a VM context for passing info to the
+ debugger.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugPeriodic (
+ IN VM_CONTEXT *VmPtr
+ );
+
+//
+// These two functions and the GUID are used to produce an EBC test protocol.
+// This functionality is definitely not required for execution.
+//
+/**
+ Produces an EBC VM test protocol that can be used for regression tests.
+
+ @param IHandle Handle on which to install the protocol.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+InitEbcVmTestProtocol (
+ IN EFI_HANDLE *IHandle
+ );
+
+/**
+ Returns the EFI_UNSUPPORTED Status.
+
+ @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcVmTestUnsupported (
+ VOID
+ );
+
+/**
+ Registers a callback function that the EBC interpreter calls to flush the
+ processor instruction cache following creation of thunks.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterICacheFlush (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EBC_ICACHE_FLUSH Flush
+ );
+
+/**
+ This EBC debugger protocol service is called by the debug agent
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
+ maximum supported processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugGetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call on a periodic basis.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param PeriodicCallback A pointer to a function of type
+ PERIODIC_CALLBACK that is the main periodic
+ entry point of the debug agent. It receives as a
+ parameter a pointer to the full context of the
+ interrupted execution thread.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call when we detect an exception.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param ExceptionCallback A pointer to a function of type
+ EXCEPTION_CALLBACK that is called when the
+ processor exception specified by ExceptionType
+ occurs. Passing NULL unregisters any previously
+ registered function associated with
+ ExceptionType.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
+ MAX_EBC_EXCEPTION.
+ @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ This EBC debugger protocol service is called by the debug agent. Required
+ for DebugSupport compliance but is only stubbed out for EBC.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param Start StartSpecifies the physical base of the memory
+ range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the
+ processor's instruction cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugInvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+//
+// We have one linked list of image handles for the whole world. Since
+// there should only be one interpreter, make them global. They must
+// also be global since the execution of an EBC image does not provide
+// a This pointer.
+//
+EBC_IMAGE_LIST *mEbcImageList = NULL;
+
+//
+// Callback function to flush the icache after thunk creation
+//
+EBC_ICACHE_FLUSH mEbcICacheFlush;
+
+//
+// These get set via calls by the debug agent
+//
+EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
+EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
+
+VOID *mStackBuffer[MAX_STACK_NUM];
+EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
+UINTN mStackNum = 0;
+
+//
+// Event for Periodic callback
+//
+EFI_EVENT mEbcPeriodicEvent;
+VM_CONTEXT *mVmPtr = NULL;
+
+/**
+ Check whether the emulator supports executing a certain PE/COFF image
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageType Whether the image is an application, a boot time
+ driver or a runtime driver.
+ @param[in] DevicePath Path to device where the image originated
+ (e.g., a PCI option ROM)
+
+ @retval TRUE The image is supported by the emulator
+ @retval FALSE The image is not supported by the emulator.
+**/
+BOOLEAN
+EFIAPI
+EbcIsImageSupported (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN UINT16 ImageType,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
+ )
+{
+ if (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION &&
+ ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Register a supported PE/COFF image with the emulator. After this call
+ completes successfully, the PE/COFF image may be started as usual, and
+ it is the responsibility of the emulator implementation that any branch
+ into the code section of the image (including returns from functions called
+ from the foreign code) is executed as if it were running on the machine
+ type it was built for.
+
+ @param[in] This This pointer for
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+ @param[in] ImageSize The size in memory of the PE/COFF image
+ @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
+ reference so that the emulator may modify it.
+
+ @retval EFI_SUCCESS The image was registered with the emulator and
+ can be started as usual.
+ @retval other The image could not be registered.
+
+ If the PE/COFF machine type or image type are not supported by the emulator,
+ then ASSERT().
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterImage (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_STATUS Status;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+
+ ImageContext.Handle = (VOID *)(UINTN)ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC);
+ ASSERT (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ||
+ ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER);
+ DEBUG_CODE_END ();
+
+ EbcRegisterICacheFlush (NULL,
+ (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);
+
+ return EbcCreateThunk (NULL, (VOID *)(UINTN)ImageBase,
+ (VOID *)(UINTN)*EntryPoint, (VOID **)EntryPoint);
+}
+
+/**
+ Unregister a PE/COFF image that has been registered with the emulator.
+ This should be done before the image is unloaded from memory.
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+
+ @retval EFI_SUCCESS The image was unregistered with the emulator.
+ @retval other Image could not be unloaded.
+**/
+EFI_STATUS
+EFIAPI
+EbcUnregisterImage (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase
+ )
+{
+ return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase);
+}
+
+STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = {
+ EbcIsImageSupported,
+ EbcRegisterImage,
+ EbcUnregisterImage,
+ EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
+ EFI_IMAGE_MACHINE_EBC
+};
+
+/**
+ Initializes the VM EFI interface. Allocates memory for the VM interface
+ and registers the VM protocol.
+
+ @param ImageHandle EFI image handle.
+ @param SystemTable Pointer to the EFI system table.
+
+ @return Standard EFI status code.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_EBC_PROTOCOL *EbcProtocol;
+ EFI_EBC_PROTOCOL *OldEbcProtocol;
+ EFI_STATUS Status;
+ EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumHandles;
+ UINTN Index;
+ BOOLEAN Installed;
+
+ EbcProtocol = NULL;
+ EbcDebugProtocol = NULL;
+
+ //
+ // Allocate memory for our protocol. Then fill in the blanks.
+ //
+ EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
+
+ if (EbcProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EbcProtocol->CreateThunk = EbcCreateThunk;
+ EbcProtocol->UnloadImage = EbcUnloadImage;
+ EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
+ EbcProtocol->GetVersion = EbcGetVersion;
+ mEbcICacheFlush = NULL;
+
+ //
+ // Find any already-installed EBC protocols and uninstall them
+ //
+ Installed = FALSE;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiEbcProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Loop through the handles
+ //
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ (VOID **) &OldEbcProtocol
+ );
+ if (Status == EFI_SUCCESS) {
+ if (gBS->ReinstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ OldEbcProtocol,
+ EbcProtocol
+ ) == EFI_SUCCESS) {
+ Installed = TRUE;
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+ //
+ // Add the protocol so someone can locate us if we haven't already.
+ //
+ if (!Installed) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiEbcProtocolGuid, EbcProtocol,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid, &mPeCoffEmuProtocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcProtocol);
+ return Status;
+ }
+ }
+
+ Status = InitEBCStack();
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Allocate memory for our debug protocol. Then fill in the blanks.
+ //
+ EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
+
+ if (EbcDebugProtocol == NULL) {
+ goto ErrorExit;
+ }
+
+ EbcDebugProtocol->Isa = IsaEbc;
+ EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
+ EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
+ EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
+ EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
+
+ //
+ // Add the protocol so the debug agent can find us
+ //
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiDebugSupportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ EbcDebugProtocol
+ );
+ //
+ // This is recoverable, so free the memory and continue.
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcDebugProtocol);
+ goto ErrorExit;
+ }
+ //
+ // Install EbcDebugSupport Protocol Successfully
+ // Now we need to initialize the Ebc default Callback
+ //
+ Status = InitializeEbcCallback (EbcDebugProtocol);
+
+ //
+ // Produce a VM test interface protocol. Not required for execution.
+ //
+ DEBUG_CODE_BEGIN ();
+ InitEbcVmTestProtocol (&ImageHandle);
+ DEBUG_CODE_END ();
+
+ EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ FreeEBCStack();
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiEbcProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Loop through the handles
+ //
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ (VOID **) &OldEbcProtocol
+ );
+ if (Status == EFI_SUCCESS) {
+ gBS->UninstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ OldEbcProtocol
+ );
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ FreePool (EbcProtocol);
+
+ return Status;
+}
+
+
+/**
+ This is the top-level routine plugged into the EBC protocol. Since thunks
+ are very processor-specific, from here we dispatch directly to the very
+ processor-specific routine EbcCreateThunks().
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created. The EBC interpreter may use this to
+ keep track of any resource allocations
+ performed in loading and executing the image.
+ @param EbcEntryPoint Address of the actual EBC entry point or
+ protocol service the thunk should call.
+ @param Thunk Returned pointer to a thunk created.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
+ @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcCreateThunk (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EbcCreateThunks (
+ ImageHandle,
+ EbcEntryPoint,
+ Thunk,
+ FLAG_THUNK_ENTRY_POINT
+ );
+ return Status;
+}
+
+
+/**
+ This EBC debugger protocol service is called by the debug agent
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
+ maximum supported processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugGetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ )
+{
+ *MaxProcessorIndex = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call on a periodic basis.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param PeriodicCallback A pointer to a function of type
+ PERIODIC_CALLBACK that is the main periodic
+ entry point of the debug agent. It receives as a
+ parameter a pointer to the full context of the
+ interrupted execution thread.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ )
+{
+ if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mDebugPeriodicCallback = PeriodicCallback;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call when we detect an exception.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param ExceptionCallback A pointer to a function of type
+ EXCEPTION_CALLBACK that is called when the
+ processor exception specified by ExceptionType
+ occurs. Passing NULL unregisters any previously
+ registered function associated with
+ ExceptionType.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
+ MAX_EBC_EXCEPTION.
+ @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+ mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This EBC debugger protocol service is called by the debug agent. Required
+ for DebugSupport compliance but is only stubbed out for EBC.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param Start StartSpecifies the physical base of the memory
+ range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the
+ processor's instruction cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugInvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The VM interpreter calls this function when an exception is detected.
+
+ @param ExceptionType Specifies the processor exception detected.
+ @param ExceptionFlags Specifies the exception context.
+ @param VmPtr Pointer to a VM context for passing info to the
+ EFI debugger.
+
+ @retval EFI_SUCCESS This function completed successfully.
+
+**/
+EFI_STATUS
+EbcDebugSignalException (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EXCEPTION_FLAGS ExceptionFlags,
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_SYSTEM_CONTEXT_EBC EbcContext;
+ EFI_SYSTEM_CONTEXT SystemContext;
+
+ ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
+ //
+ // Save the exception in the context passed in
+ //
+ VmPtr->ExceptionFlags |= ExceptionFlags;
+ VmPtr->LastException = (UINTN) ExceptionType;
+ //
+ // If it's a fatal exception, then flag it in the VM context in case an
+ // attached debugger tries to return from it.
+ //
+ if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
+ VmPtr->StopFlags |= STOPFLAG_APP_DONE;
+ }
+
+ //
+ // If someone's registered for exception callbacks, then call them.
+ //
+ // EBC driver will register default exception callback to report the
+ // status code via the status code API
+ //
+ if (mDebugExceptionCallback[ExceptionType] != NULL) {
+
+ //
+ // Initialize the context structure
+ //
+ EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
+ EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
+ EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
+ EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
+ EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
+ EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
+ EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
+ EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
+ EbcContext.Flags = VmPtr->Flags;
+ EbcContext.ControlFlags = 0;
+ SystemContext.SystemContextEbc = &EbcContext;
+
+ mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
+ //
+ // Restore the context structure and continue to execute
+ //
+ VmPtr->Gpr[0] = EbcContext.R0;
+ VmPtr->Gpr[1] = EbcContext.R1;
+ VmPtr->Gpr[2] = EbcContext.R2;
+ VmPtr->Gpr[3] = EbcContext.R3;
+ VmPtr->Gpr[4] = EbcContext.R4;
+ VmPtr->Gpr[5] = EbcContext.R5;
+ VmPtr->Gpr[6] = EbcContext.R6;
+ VmPtr->Gpr[7] = EbcContext.R7;
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
+ VmPtr->Flags = EbcContext.Flags;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ To install default Callback function for the VM interpreter.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when creating periodic event.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This
+ )
+{
+ INTN Index;
+ EFI_STATUS Status;
+
+ //
+ // For ExceptionCallback
+ //
+ for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
+ EbcDebugRegisterExceptionCallback (
+ This,
+ 0,
+ CommonEbcExceptionHandler,
+ Index
+ );
+ }
+
+ //
+ // For PeriodicCallback
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EbcPeriodicNotifyFunction,
+ &mVmPtr,
+ &mEbcPeriodicEvent
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (
+ mEbcPeriodicEvent,
+ TimerPeriodic,
+ EBC_VM_PERIODIC_CALLBACK_RATE
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param InterruptType Interrupt type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+CommonEbcExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // We print debug information to let user know what happen.
+ //
+ DEBUG ((
+ EFI_D_ERROR,
+ "EBC Interrupter Version - 0x%016lx\n",
+ (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "Exception Type - 0x%016lx\n",
+ (UINT64)(UINTN)InterruptType
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R0 - 0x%016lx, R1 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R0,
+ SystemContext.SystemContextEbc->R1
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R2 - 0x%016lx, R3 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R2,
+ SystemContext.SystemContextEbc->R3
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R4 - 0x%016lx, R5 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R4,
+ SystemContext.SystemContextEbc->R5
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R6 - 0x%016lx, R7 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R6,
+ SystemContext.SystemContextEbc->R7
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " Flags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Flags
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " ControlFlags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->ControlFlags
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " Ip - 0x%016lx\n\n",
+ SystemContext.SystemContextEbc->Ip
+ ));
+
+ //
+ // We deadloop here to make it easy to debug this issue.
+ //
+ CpuDeadLoop ();
+
+ return ;
+}
+
+
+/**
+ The periodic callback function for EBC VM interpreter, which is used
+ to support the EFI debug support protocol.
+
+ @param Event The Periodic Callback Event.
+ @param Context It should be the address of VM_CONTEXT pointer.
+
+**/
+VOID
+EFIAPI
+EbcPeriodicNotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VM_CONTEXT *VmPtr;
+
+ VmPtr = *(VM_CONTEXT **)Context;
+
+ if (VmPtr != NULL) {
+ EbcDebugPeriodic (VmPtr);
+ }
+
+ return ;
+}
+
+
+/**
+ The VM interpreter calls this function on a periodic basis to support
+ the EFI debug support protocol.
+
+ @param VmPtr Pointer to a VM context for passing info to the
+ debugger.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugPeriodic (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_SYSTEM_CONTEXT_EBC EbcContext;
+ EFI_SYSTEM_CONTEXT SystemContext;
+
+ //
+ // If someone's registered for periodic callbacks, then call them.
+ //
+ if (mDebugPeriodicCallback != NULL) {
+
+ //
+ // Initialize the context structure
+ //
+ EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
+ EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
+ EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
+ EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
+ EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
+ EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
+ EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
+ EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
+ EbcContext.Flags = VmPtr->Flags;
+ EbcContext.ControlFlags = 0;
+ SystemContext.SystemContextEbc = &EbcContext;
+
+ mDebugPeriodicCallback (SystemContext);
+
+ //
+ // Restore the context structure and continue to execute
+ //
+ VmPtr->Gpr[0] = EbcContext.R0;
+ VmPtr->Gpr[1] = EbcContext.R1;
+ VmPtr->Gpr[2] = EbcContext.R2;
+ VmPtr->Gpr[3] = EbcContext.R3;
+ VmPtr->Gpr[4] = EbcContext.R4;
+ VmPtr->Gpr[5] = EbcContext.R5;
+ VmPtr->Gpr[6] = EbcContext.R6;
+ VmPtr->Gpr[7] = EbcContext.R7;
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
+ VmPtr->Flags = EbcContext.Flags;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This routine is called by the core when an image is being unloaded from
+ memory. Basically we now have the opportunity to do any necessary cleanup.
+ Typically this will include freeing any memory allocated for thunk-creation.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created.
+
+ @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
+ internal list of EBC image handles.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcUnloadImage (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EBC_THUNK_LIST *ThunkList;
+ EBC_THUNK_LIST *NextThunkList;
+ EBC_IMAGE_LIST *ImageList;
+ EBC_IMAGE_LIST *PrevImageList;
+ //
+ // First go through our list of known image handles and see if we've already
+ // created an image list element for this image handle.
+ //
+ ReturnEBCStackByHandle(ImageHandle);
+ PrevImageList = NULL;
+ for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
+ if (ImageList->ImageHandle == ImageHandle) {
+ break;
+ }
+ //
+ // Save the previous so we can connect the lists when we remove this one
+ //
+ PrevImageList = ImageList;
+ }
+
+ if (ImageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Free up all the thunk buffers and thunks list elements for this image
+ // handle.
+ //
+ ThunkList = ImageList->ThunkList;
+ while (ThunkList != NULL) {
+ NextThunkList = ThunkList->Next;
+ FreePool (ThunkList->ThunkBuffer);
+ FreePool (ThunkList);
+ ThunkList = NextThunkList;
+ }
+ //
+ // Now remove this image list element from the chain
+ //
+ if (PrevImageList == NULL) {
+ //
+ // Remove from head
+ //
+ mEbcImageList = ImageList->Next;
+ } else {
+ PrevImageList->Next = ImageList->Next;
+ }
+ //
+ // Now free up the image list element
+ //
+ FreePool (ImageList);
+
+ EbcDebuggerHookEbcUnloadImage (ImageHandle);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add a thunk to our list of thunks for a given image handle.
+ Also flush the instruction cache since we've written thunk code
+ to memory that will be executed eventually.
+
+ @param ImageHandle The image handle to which the thunk is tied.
+ @param ThunkBuffer The buffer that has been created/allocated.
+ @param ThunkSize The size of the thunk memory allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EbcAddImageThunk (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *ThunkBuffer,
+ IN UINT32 ThunkSize
+ )
+{
+ EBC_THUNK_LIST *ThunkList;
+ EBC_IMAGE_LIST *ImageList;
+ EFI_STATUS Status;
+
+ //
+ // It so far so good, then flush the instruction cache
+ //
+ if (mEbcICacheFlush != NULL) {
+ Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Go through our list of known image handles and see if we've already
+ // created a image list element for this image handle.
+ //
+ for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
+ if (ImageList->ImageHandle == ImageHandle) {
+ break;
+ }
+ }
+
+ if (ImageList == NULL) {
+ //
+ // Allocate a new one
+ //
+ ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
+
+ if (ImageList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ImageList->ThunkList = NULL;
+ ImageList->ImageHandle = ImageHandle;
+ ImageList->Next = mEbcImageList;
+ mEbcImageList = ImageList;
+ }
+ //
+ // Ok, now create a new thunk element to add to the list
+ //
+ ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
+
+ if (ThunkList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Add it to the head of the list
+ //
+ ThunkList->Next = ImageList->ThunkList;
+ ThunkList->ThunkBuffer = ThunkBuffer;
+ ImageList->ThunkList = ThunkList;
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a callback function that the EBC interpreter calls to flush the
+ processor instruction cache following creation of thunks.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterICacheFlush (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EBC_ICACHE_FLUSH Flush
+ )
+{
+ mEbcICacheFlush = Flush;
+ return EFI_SUCCESS;
+}
+
+/**
+ Called to get the version of the interpreter.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Version Pointer to where to store the returned version
+ of the interpreter.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Version pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcGetVersion (
+ IN EFI_EBC_PROTOCOL *This,
+ IN OUT UINT64 *Version
+ )
+{
+ if (Version == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Version = GetVmVersion ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the stack index and buffer assosicated with the Handle parameter.
+
+ @param Handle The EFI handle as the index to the EBC stack.
+ @param StackBuffer A pointer to hold the returned stack buffer.
+ @param BufferIndex A pointer to hold the returned stack index.
+
+ @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
+ existing EBC stack.
+ @retval EFI_SUCCESS The stack index and buffer were found and
+ returned to the caller.
+
+**/
+EFI_STATUS
+GetEBCStack(
+ IN EFI_HANDLE Handle,
+ OUT VOID **StackBuffer,
+ OUT UINTN *BufferIndex
+ )
+{
+ UINTN Index;
+ EFI_TPL OldTpl;
+ OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
+ for (Index = 0; Index < mStackNum; Index ++) {
+ if (mStackBufferIndex[Index] == NULL) {
+ mStackBufferIndex[Index] = Handle;
+ break;
+ }
+ }
+ gBS->RestoreTPL(OldTpl);
+ if (Index == mStackNum) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *BufferIndex = Index;
+ *StackBuffer = mStackBuffer[Index];
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns from the EBC stack by stack Index.
+
+ @param Index Specifies which EBC stack to return from.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStack(
+ IN UINTN Index
+ )
+{
+ mStackBufferIndex[Index] = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns from the EBC stack associated with the Handle parameter.
+
+ @param Handle Specifies the EFI handle to find the EBC stack with.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStackByHandle(
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < mStackNum; Index ++) {
+ if (mStackBufferIndex[Index] == Handle) {
+ break;
+ }
+ }
+ if (Index == mStackNum) {
+ return EFI_NOT_FOUND;
+ }
+ mStackBufferIndex[Index] = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates memory to hold all the EBC stacks.
+
+ @retval EFI_SUCCESS The EBC stacks were allocated successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
+
+**/
+EFI_STATUS
+InitEBCStack (
+ VOID
+ )
+{
+ for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
+ mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
+ mStackBufferIndex[mStackNum] = NULL;
+ if (mStackBuffer[mStackNum] == NULL) {
+ break;
+ }
+ }
+ if (mStackNum == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Free all EBC stacks allocated before.
+
+ @retval EFI_SUCCESS All the EBC stacks were freed.
+
+**/
+EFI_STATUS
+FreeEBCStack(
+ VOID
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < mStackNum; Index ++) {
+ FreePool(mStackBuffer[Index]);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Produces an EBC VM test protocol that can be used for regression tests.
+
+ @param IHandle Handle on which to install the protocol.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+InitEbcVmTestProtocol (
+ IN EFI_HANDLE *IHandle
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
+
+ //
+ // Allocate memory for the protocol, then fill in the fields
+ //
+ EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
+ if (EbcVmTestProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
+
+ DEBUG_CODE_BEGIN ();
+ EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
+ EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
+ DEBUG_CODE_END ();
+
+ //
+ // Publish the protocol
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (&Handle, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcVmTestProtocol);
+ }
+ return Status;
+}
+
+
+/**
+ Returns the EFI_UNSUPPORTED Status.
+
+ @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcVmTestUnsupported (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesCode.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+EbcAllocatePoolForThunk (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = gBS->AllocatePool (EfiBootServicesCode, AllocationSize, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return Buffer;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h
new file mode 100644
index 000000000..16f5ed4eb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h
@@ -0,0 +1,260 @@
+/** @file
+ Main routines for the EBC interpreter. Includes the initialization and
+ main interpreter routines.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_INT_H_
+#define _EBC_INT_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/Ebc.h>
+#include <Protocol/EbcVmTest.h>
+#include <Protocol/EbcSimpleDebugger.h>
+#include <Protocol/PeCoffImageEmulator.h>
+
+#include <Library/BaseLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+extern VM_CONTEXT *mVmPtr;
+
+//
+// Flags passed to the internal create-thunks function.
+//
+#define FLAG_THUNK_ENTRY_POINT 0x01 // thunk for an image entry point
+#define FLAG_THUNK_PROTOCOL 0x00 // thunk for an EBC protocol service
+//
+// Put this value at the bottom of the VM's stack gap so we can check it on
+// occasion to make sure the stack has not been corrupted.
+//
+#define VM_STACK_KEY_VALUE 0xDEADBEEF
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ );
+
+/**
+ Add a thunk to our list of thunks for a given image handle.
+ Also flush the instruction cache since we've written thunk code
+ to memory that will be executed eventually.
+
+ @param ImageHandle The image handle to which the thunk is tied.
+ @param ThunkBuffer The buffer that has been created/allocated.
+ @param ThunkSize The size of the thunk memory allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EbcAddImageThunk (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *ThunkBuffer,
+ IN UINT32 ThunkSize
+ );
+
+//
+// Define a constant of how often to call the debugger periodic callback
+// function.
+//
+#define EFI_TIMER_UNIT_1MS (1000 * 10)
+#define EBC_VM_PERIODIC_CALLBACK_RATE (1000 * EFI_TIMER_UNIT_1MS)
+#define STACK_POOL_SIZE (1024 * 1020)
+#define MAX_STACK_NUM 4
+
+//
+// External low level functions that are native-processor dependent
+//
+/**
+ The VM thunk code stuffs an EBC entry point into a processor
+ register. Since we can't use inline assembly to get it from
+ the interpreter C code, stuff it into the return value
+ register and return.
+
+ @return The contents of the register in which the entry point is passed.
+
+**/
+UINTN
+EFIAPI
+EbcLLGetEbcEntryPoint (
+ VOID
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ This instruction requires that we thunk out to external native
+ code. For x64, we switch stacks, copy the arguments to the stack
+ and jump to the specified function.
+ On return, we restore the stack pointer to its original location.
+ Destroys no working registers.
+
+ @param CallAddr The function address.
+ @param EbcSp The new EBC stack pointer.
+ @param FramePtr The frame pointer.
+
+ @return The unmodified value returned by the native code.
+
+**/
+INT64
+EFIAPI
+EbcLLCALLEXNative (
+ IN UINTN CallAddr,
+ IN UINTN EbcSp,
+ IN VOID *FramePtr
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ );
+
+/**
+ Returns the stack index and buffer assosicated with the Handle parameter.
+
+ @param Handle The EFI handle as the index to the EBC stack.
+ @param StackBuffer A pointer to hold the returned stack buffer.
+ @param BufferIndex A pointer to hold the returned stack index.
+
+ @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
+ existing EBC stack.
+ @retval EFI_SUCCESS The stack index and buffer were found and
+ returned to the caller.
+
+**/
+EFI_STATUS
+GetEBCStack(
+ IN EFI_HANDLE Handle,
+ OUT VOID **StackBuffer,
+ OUT UINTN *BufferIndex
+ );
+
+/**
+ Returns from the EBC stack by stack Index.
+
+ @param Index Specifies which EBC stack to return from.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStack(
+ IN UINTN Index
+ );
+
+/**
+ Allocates memory to hold all the EBC stacks.
+
+ @retval EFI_SUCCESS The EBC stacks were allocated successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
+
+**/
+EFI_STATUS
+InitEBCStack (
+ VOID
+ );
+
+/**
+ Free all EBC stacks allocated before.
+
+ @retval EFI_SUCCESS All the EBC stacks were freed.
+
+**/
+EFI_STATUS
+FreeEBCStack(
+ VOID
+ );
+
+/**
+ Returns from the EBC stack associated with the Handle parameter.
+
+ @param Handle Specifies the EFI handle to find the EBC stack with.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStackByHandle(
+ IN EFI_HANDLE Handle
+ );
+
+typedef struct {
+ EFI_EBC_PROTOCOL *This;
+ VOID *EntryPoint;
+ EFI_HANDLE ImageHandle;
+ VM_CONTEXT VmContext;
+} EFI_EBC_THUNK_DATA;
+
+#define EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('e', 'b', 'c', 'p')
+
+
+#define EBC_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, EBC_PROTOCOL_PRIVATE_DATA, EbcProtocol, EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE)
+
+
+/**
+ Allocates a buffer of type EfiBootServicesCode.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+EbcAllocatePoolForThunk (
+ IN UINTN AllocationSize
+ );
+
+#endif // #ifndef _EBC_INT_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm
new file mode 100644
index 000000000..60e41428b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm
@@ -0,0 +1,191 @@
+;/** @file
+;
+; This code provides low level routines that support the Virtual Machine
+; for option ROMs.
+;
+; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+;---------------------------------------------------------------------------
+; Equate files needed.
+;---------------------------------------------------------------------------
+
+;---------------------------------------------------------------------------
+; Assembler options
+;---------------------------------------------------------------------------
+
+SECTION .text
+extern ASM_PFX(CopyMem)
+extern ASM_PFX(EbcInterpret)
+extern ASM_PFX(ExecuteEbcImageEntryPoint)
+
+;****************************************************************************
+; EbcLLCALLEXNative
+;
+; This function is called to execute an EBC CALLEX instruction
+; to native code.
+; This instruction requires that we thunk out to external native
+; code. For IA32, we simply switch stacks and jump to the
+; specified function. On return, we restore the stack pointer
+; to its original location.
+;
+; Destroys no working registers.
+;****************************************************************************
+; INT64 EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+global ASM_PFX(EbcLLCALLEXNative)
+ASM_PFX(EbcLLCALLEXNative):
+ push ebp
+ push ebx
+ mov ebp, esp ; standard function prolog
+
+ ; Get function address in a register
+ ; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr]
+ mov ecx, dword [esp + 0xC]
+
+ ; Set stack pointer to new value
+ ; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
+ mov eax, dword [esp + 0x14]
+ mov edx, dword [esp + 0x10]
+ sub eax, edx
+ sub esp, eax
+ mov ebx, esp
+ push ecx
+ push eax
+ push edx
+ push ebx
+ call ASM_PFX(CopyMem)
+ pop eax
+ pop eax
+ pop eax
+ pop ecx
+
+ ; Now call the external routine
+ call ecx
+
+ ; ebp is preserved by the callee. In this function it
+ ; equals the original esp, so set them equal
+ mov esp, ebp
+
+ ; Standard function epilog
+ mov esp, ebp
+ pop ebx
+ pop ebp
+ ret
+
+;****************************************************************************
+; EbcLLEbcInterpret
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLEbcInterpret(VOID)
+global ASM_PFX(EbcLLEbcInterpret)
+ASM_PFX(EbcLLEbcInterpret):
+ ;
+ ;; mov eax, 0xca112ebc
+ ;; mov eax, EbcEntryPoint
+ ;; mov ecx, EbcLLEbcInterpret
+ ;; jmp ecx
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (EAX)
+ ; +-----------+
+ ; | Arg1 | <- EDI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ; | EDI |
+ ; +-----------+
+ ; | ESI |
+ ; +-----------+
+ ; | EBP | <- EBP
+ ; +-----------+
+ ; | RetAddr | <- ESP is here
+ ; +-----------+
+ ; | Arg1 | <- ESI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ;
+
+ ; Construct new stack
+ push ebp
+ mov ebp, esp
+ push esi
+ push edi
+ sub esp, 0x40
+ push eax
+ mov esi, ebp
+ add esi, 8
+ mov edi, esp
+ add edi, 4
+ mov ecx, 16
+ rep movsd
+
+ ; call C-code
+ call ASM_PFX(EbcInterpret)
+ add esp, 0x44
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+;****************************************************************************
+; EbcLLExecuteEbcImageEntryPoint
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLExecuteEbcImageEntryPoint(VOID)
+global ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ ;
+ ;; mov eax, 0xca112ebc
+ ;; mov eax, EbcEntryPoint
+ ;; mov ecx, EbcLLExecuteEbcImageEntryPoint
+ ;; jmp ecx
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (EAX)
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ; | RetAddr | <- ESP is here
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ;
+
+ ; Construct new stack
+ mov [esp - 0xC], eax
+ mov eax, [esp + 0x4]
+ mov [esp - 0x8], eax
+ mov eax, [esp + 0x8]
+ mov [esp - 0x4], eax
+
+ ; call C-code
+ sub esp, 0xC
+ call ASM_PFX(ExecuteEbcImageEntryPoint)
+ add esp, 0xC
+ ret
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c
new file mode 100644
index 000000000..a25139536
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c
@@ -0,0 +1,526 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target ia32 processor.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// NOTE: This is the stack size allocated for the interpreter
+// when it executes an EBC image. The requirements can change
+// based on whether or not a debugger is present, and other
+// platform-specific configurations.
+//
+#define VM_STACK_SIZE (1024 * 4)
+
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+//
+// This is instruction buffer used to create EBC thunk
+//
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAF
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFA
+UINT8 mInstructionBufferTemplate[] = {
+ //
+ // Add a magic code here to help the VM recognize the thunk..
+ // mov eax, 0xca112ebc => B8 BC 2E 11 CA
+ //
+ 0xB8, 0xBC, 0x2E, 0x11, 0xCA,
+ //
+ // Add code bytes to load up a processor register with the EBC entry point.
+ // mov eax, EbcEntryPoint => B8 XX XX XX XX (To be fixed at runtime)
+ // These 4 bytes of the thunk entry is the address of the EBC
+ // entry point.
+ //
+ 0xB8,
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ //
+ // Stick in a load of ecx with the address of appropriate VM function.
+ // mov ecx, EbcLLEbcInterpret => B9 XX XX XX XX (To be fixed at runtime)
+ //
+ 0xB9,
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ //
+ // Stick in jump opcode bytes
+ // jmp ecx => FF E1
+ //
+ 0xFF, 0xE1,
+};
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ UINTN IsThunk;
+ UINTN TargetEbcAddr;
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
+ UINTN Index;
+ UINTN IndexOfEbcEntrypoint;
+
+ IsThunk = 1;
+ TargetEbcAddr = 0;
+ IndexOfEbcEntrypoint = 0;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
+ //
+ // Fill the signature according to mInstructionBufferTemplate
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
+ IndexOfEbcEntrypoint = Index;
+ }
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
+ }
+ }
+ //
+ // Check if we need thunk to native
+ //
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
+ IsThunk = 0;
+ }
+
+ if (IsThunk == 1){
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
+ VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function. Microsoft x64 compiler only provide fast_call
+ calling convention, so the first four arguments are passed by rcx, rdx,
+ r8, and r9, while other arguments are passed in stack.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param Arg9 The 9th argument.
+ @param Arg10 The 10th argument.
+ @param Arg11 The 11th argument.
+ @param Arg12 The 12th argument.
+ @param Arg13 The 13th argument.
+ @param Arg14 The 14th argument.
+ @param Arg15 The 15th argument.
+ @param Arg16 The 16th argument.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN EntryPoint,
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN Arg9,
+ IN UINTN Arg10,
+ IN UINTN Arg11,
+ IN UINTN Arg12,
+ IN UINTN Arg13,
+ IN UINTN Arg14,
+ IN UINTN Arg15,
+ IN UINTN Arg16
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Align the stack on a natural boundary
+ //
+
+ //
+ // Allocate stack pool
+ //
+ Status = GetEBCStack((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
+ VmContext.Gpr[0] &= ~((VM_REGISTER)(sizeof (UINTN) - 1));
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For IA32, this is where we say our return address is
+ //
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg16;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg15;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg14;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg13;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg12;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg11;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg10;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg9;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg8;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg7;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg6;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg5;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg4;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg3;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg2;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg1;
+ VmContext.Gpr[0] -= 16;
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN UINTN EntryPoint,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Allocate stack pool
+ //
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ // VmContext.Gpr[0] &= ~(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) SystemTable;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) ImageHandle;
+
+ VmContext.Gpr[0] -= 16;
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ThunkBase;
+ UINT32 Index;
+ INT32 ThunkSize;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ThunkSize = sizeof(mInstructionBufferTemplate);
+
+ Ptr = EbcAllocatePoolForThunk (sizeof(mInstructionBufferTemplate));
+
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
+ //
+ // Save the start address so we can add a pointer to it to a list later.
+ //
+ ThunkBase = Ptr;
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = (VOID *) Ptr;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
+ }
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
+ }
+ }
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm
new file mode 100644
index 000000000..3a8707616
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm
@@ -0,0 +1,236 @@
+;/** @file
+;
+; This code provides low level routines that support the Virtual Machine.
+; for option ROMs.
+;
+; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+; Copyright (c) 2014 Hewlett-Packard Development Company, L.P.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+;---------------------------------------------------------------------------
+; Equate files needed.
+;---------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+extern ASM_PFX(CopyMem)
+extern ASM_PFX(EbcInterpret)
+extern ASM_PFX(ExecuteEbcImageEntryPoint)
+
+;****************************************************************************
+; EbcLLCALLEX
+;
+; This function is called to execute an EBC CALLEX instruction.
+; This instruction requires that we thunk out to external native
+; code. For x64, we switch stacks, copy the arguments to the stack
+; and jump to the specified function.
+; On return, we restore the stack pointer to its original location.
+;
+; Destroys no working registers.
+;****************************************************************************
+; INT64 EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+global ASM_PFX(EbcLLCALLEXNative)
+ASM_PFX(EbcLLCALLEXNative):
+ push rbp
+ push rbx
+ mov rbp, rsp
+ ; Function prolog
+
+ ; Copy FuncAddr to a preserved register.
+ mov rbx, rcx
+
+ ; Set stack pointer to new value
+ sub r8, rdx
+
+ ;
+ ; Fix X64 native function call prolog. Prepare space for at least 4 arguments,
+ ; even if the native function's arguments are less than 4.
+ ;
+ ; From MSDN x64 Software Conventions, Overview of x64 Calling Conventions:
+ ; "The caller is responsible for allocating space for parameters to the
+ ; callee, and must always allocate sufficient space for the 4 register
+ ; parameters, even if the callee doesn't have that many parameters.
+ ; This aids in the simplicity of supporting C unprototyped functions,
+ ; and vararg C/C++ functions."
+ ;
+ cmp r8, 0x20
+ jae skip_expansion
+ mov r8, dword 0x20
+skip_expansion:
+
+ sub rsp, r8
+
+ ;
+ ; Fix X64 native function call 16-byte alignment.
+ ;
+ ; From MSDN x64 Software Conventions, Stack Usage:
+ ; "The stack will always be maintained 16-byte aligned, except within
+ ; the prolog (for example, after the return address is pushed)."
+ ;
+ and rsp, ~ 0xf
+
+ mov rcx, rsp
+ sub rsp, 0x20
+ call ASM_PFX(CopyMem)
+ add rsp, 0x20
+
+ ; Considering the worst case, load 4 potiential arguments
+ ; into registers.
+ mov rcx, qword [rsp]
+ mov rdx, qword [rsp+0x8]
+ mov r8, qword [rsp+0x10]
+ mov r9, qword [rsp+0x18]
+
+ ; Now call the external routine
+ call rbx
+
+ ; Function epilog
+ mov rsp, rbp
+ pop rbx
+ pop rbp
+ ret
+
+;****************************************************************************
+; EbcLLEbcInterpret
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLEbcInterpret(VOID)
+global ASM_PFX(EbcLLEbcInterpret)
+ASM_PFX(EbcLLEbcInterpret):
+ ;
+ ;; mov rax, ca112ebccall2ebch
+ ;; mov r10, EbcEntryPoint
+ ;; mov r11, EbcLLEbcInterpret
+ ;; jmp r11
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (R10)
+ ; +-----------+
+ ; | Arg1 | <- RDI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | RDI |
+ ; +-----------+
+ ; | RSI |
+ ; +-----------+
+ ; | RBP | <- RBP
+ ; +-----------+
+ ; | RetAddr | <- RSP is here
+ ; +-----------+
+ ; | Scratch1 | (RCX) <- RSI
+ ; +-----------+
+ ; | Scratch2 | (RDX)
+ ; +-----------+
+ ; | Scratch3 | (R8)
+ ; +-----------+
+ ; | Scratch4 | (R9)
+ ; +-----------+
+ ; | Arg5 |
+ ; +-----------+
+ ; | Arg6 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ;
+
+ ; save old parameter to stack
+ mov [rsp + 0x8], rcx
+ mov [rsp + 0x10], rdx
+ mov [rsp + 0x18], r8
+ mov [rsp + 0x20], r9
+
+ ; Construct new stack
+ push rbp
+ mov rbp, rsp
+ push rsi
+ push rdi
+ push rbx
+ sub rsp, 0x80
+ push r10
+ mov rsi, rbp
+ add rsi, 0x10
+ mov rdi, rsp
+ add rdi, 8
+ mov rcx, dword 16
+ rep movsq
+
+ ; build new paramater calling convention
+ mov r9, [rsp + 0x18]
+ mov r8, [rsp + 0x10]
+ mov rdx, [rsp + 0x8]
+ mov rcx, r10
+
+ ; call C-code
+ call ASM_PFX(EbcInterpret)
+ add rsp, 0x88
+ pop rbx
+ pop rdi
+ pop rsi
+ pop rbp
+ ret
+
+;****************************************************************************
+; EbcLLExecuteEbcImageEntryPoint
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLExecuteEbcImageEntryPoint(VOID)
+global ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ ;
+ ;; mov rax, ca112ebccall2ebch
+ ;; mov r10, EbcEntryPoint
+ ;; mov r11, EbcLLExecuteEbcImageEntryPoint
+ ;; jmp r11
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (R10)
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | RetAddr | <- RSP is here
+ ; +-----------+
+ ; |ImageHandle| (RCX)
+ ; +-----------+
+ ; |SystemTable| (RDX)
+ ; +-----------+
+ ;
+
+ ; build new paramater calling convention
+ mov r8, rdx
+ mov rdx, rcx
+ mov rcx, r10
+
+ ; call C-code
+ sub rsp, 0x28
+ call ASM_PFX(ExecuteEbcImageEntryPoint)
+ add rsp, 0x28
+ ret
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c
new file mode 100644
index 000000000..25ca8dbc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c
@@ -0,0 +1,570 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target x64 processor.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// NOTE: This is the stack size allocated for the interpreter
+// when it executes an EBC image. The requirements can change
+// based on whether or not a debugger is present, and other
+// platform-specific configurations.
+//
+#define VM_STACK_SIZE (1024 * 8)
+
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+//
+// This is instruction buffer used to create EBC thunk
+//
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull
+UINT8 mInstructionBufferTemplate[] = {
+ //
+ // Add a magic code here to help the VM recognize the thunk..
+ // mov rax, 0xca112ebcca112ebc => 48 B8 BC 2E 11 CA BC 2E 11 CA
+ //
+ 0x48, 0xB8, 0xBC, 0x2E, 0x11, 0xCA, 0xBC, 0x2E, 0x11, 0xCA,
+ //
+ // Add code bytes to load up a processor register with the EBC entry point.
+ // mov r10, EbcEntryPoint => 49 BA XX XX XX XX XX XX XX XX (To be fixed at runtime)
+ // These 8 bytes of the thunk entry is the address of the EBC
+ // entry point.
+ //
+ 0x49, 0xBA,
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
+ //
+ // Stick in a load of r11 with the address of appropriate VM function.
+ // mov r11, EbcLLEbcInterpret => 49 BB XX XX XX XX XX XX XX XX (To be fixed at runtime)
+ //
+ 0x49, 0xBB,
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
+ //
+ // Stick in jump opcode bytes
+ // jmp r11 => 41 FF E3
+ //
+ 0x41, 0xFF, 0xE3,
+};
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ Pushes a 64 bit unsigned value to the VM stack.
+
+ @param VmPtr The pointer to current VM context.
+ @param Arg The value to be pushed.
+
+**/
+VOID
+PushU64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Arg
+ )
+{
+ //
+ // Advance the VM stack down, and then copy the argument to the stack.
+ // Hope it's aligned.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ *(UINT64 *) VmPtr->Gpr[0] = Arg;
+ return;
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function. Microsoft x64 compiler only provide fast_call
+ calling convention, so the first four arguments are passed by rcx, rdx,
+ r8, and r9, while other arguments are passed in stack.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param Arg9 The 9th argument.
+ @param Arg10 The 10th argument.
+ @param Arg11 The 11th argument.
+ @param Arg12 The 12th argument.
+ @param Arg13 The 13th argument.
+ @param Arg14 The 14th argument.
+ @param Arg15 The 15th argument.
+ @param Arg16 The 16th argument.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN EntryPoint,
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN Arg9,
+ IN UINTN Arg10,
+ IN UINTN Arg11,
+ IN UINTN Arg12,
+ IN UINTN Arg13,
+ IN UINTN Arg14,
+ IN UINTN Arg15,
+ IN UINTN Arg16
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Adjust the VM's stack pointer down.
+ //
+
+ Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Align the stack on a natural boundary.
+ //
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again.
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // The stack upper to LowStackTop is belong to the VM.
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For the worst case, assume there are 4 arguments passed in registers, store
+ // them to VM's stack.
+ //
+ PushU64 (&VmContext, (UINT64) Arg16);
+ PushU64 (&VmContext, (UINT64) Arg15);
+ PushU64 (&VmContext, (UINT64) Arg14);
+ PushU64 (&VmContext, (UINT64) Arg13);
+ PushU64 (&VmContext, (UINT64) Arg12);
+ PushU64 (&VmContext, (UINT64) Arg11);
+ PushU64 (&VmContext, (UINT64) Arg10);
+ PushU64 (&VmContext, (UINT64) Arg9);
+ PushU64 (&VmContext, (UINT64) Arg8);
+ PushU64 (&VmContext, (UINT64) Arg7);
+ PushU64 (&VmContext, (UINT64) Arg6);
+ PushU64 (&VmContext, (UINT64) Arg5);
+ PushU64 (&VmContext, (UINT64) Arg4);
+ PushU64 (&VmContext, (UINT64) Arg3);
+ PushU64 (&VmContext, (UINT64) Arg2);
+ PushU64 (&VmContext, (UINT64) Arg1);
+
+ //
+ // Interpreter assumes 64-bit return address is pushed on the stack.
+ // The x64 does not do this so pad the stack accordingly.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For x64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN UINTN EntryPoint,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // Simply copy the image handle and system table onto the EBC stack.
+ // Greatly simplifies things by not having to spill the args.
+ //
+ PushU64 (&VmContext, (UINT64) SystemTable);
+ PushU64 (&VmContext, (UINT64) ImageHandle);
+
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For x64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // Entry function needn't access high stack context, simply
+ // put the stack pointer here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ThunkBase;
+ UINT32 Index;
+ INT32 ThunkSize;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ThunkSize = sizeof(mInstructionBufferTemplate);
+
+ Ptr = EbcAllocatePoolForThunk (sizeof(mInstructionBufferTemplate));
+
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
+ //
+ // Save the start address so we can add a pointer to it to a list later.
+ //
+ ThunkBase = Ptr;
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = (VOID *) Ptr;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
+ }
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
+ }
+ }
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ UINTN IsThunk;
+ UINTN TargetEbcAddr;
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
+ UINTN Index;
+ UINTN IndexOfEbcEntrypoint;
+
+ IsThunk = 1;
+ TargetEbcAddr = 0;
+ IndexOfEbcEntrypoint = 0;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
+ //
+ // Fill the signature according to mInstructionBufferTemplate
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
+ IndexOfEbcEntrypoint = Index;
+ }
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
+ }
+ }
+ //
+ // Check if we need thunk to native
+ //
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
+ IsThunk = 0;
+ }
+
+ if (IsThunk == 1){
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
+ VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.c b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.c
new file mode 100644
index 000000000..a386a9770
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.c
@@ -0,0 +1,661 @@
+/** @file
+ Esrt management module.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "EsrtImpl.h"
+
+
+//
+// Module globals.
+//
+
+ESRT_PRIVATE_DATA mPrivate;
+
+ESRT_MANAGEMENT_PROTOCOL mEsrtManagementProtocolTemplate = {
+ EsrtDxeGetEsrtEntry,
+ EsrtDxeUpdateEsrtEntry,
+ EsrtDxeRegisterEsrtEntry,
+ EsrtDxeUnRegisterEsrtEntry,
+ EsrtDxeSyncFmp,
+ EsrtDxeLockEsrtRepository
+ };
+
+/**
+ Get ESRT entry from ESRT Cache by FwClass Guid
+
+ @param[in] FwClass FwClass of Esrt entry to get
+ @param[in, out] Entry Esrt entry returned
+
+ @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
+ @retval EF_NOT_FOUND No correct variable found.
+ @retval EFI_WRITE_PROTECTED ESRT Cache repository is locked
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeGetEsrtEntry(
+ IN EFI_GUID *FwClass,
+ IN OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+
+ if (FwClass == NULL || Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find in Non-FMP Cached Esrt Repository
+ //
+ Status = GetEsrtEntry(
+ FwClass,
+ ESRT_FROM_NONFMP,
+ Entry
+ );
+
+ EfiReleaseLock(&mPrivate.NonFmpLock);
+
+ if (EFI_ERROR(Status)) {
+ Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find in FMP Cached Esrt NV Variable
+ //
+ Status = GetEsrtEntry(
+ FwClass,
+ ESRT_FROM_FMP,
+ Entry
+ );
+
+ EfiReleaseLock(&mPrivate.FmpLock);
+ }
+
+ return Status;
+}
+
+/**
+ Update one ESRT entry in ESRT Cache.
+
+ @param[in] Entry Esrt entry to be updated
+
+ @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
+ @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
+ @retval EFI_WRITE_PROTECTED ESRT Cache repositoy is locked
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeUpdateEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+
+ if (Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UpdateEsrtEntry(Entry, ESRT_FROM_FMP);
+
+ if (!EFI_ERROR(Status)) {
+ EfiReleaseLock(&mPrivate.FmpLock);
+ return Status;
+ }
+ EfiReleaseLock(&mPrivate.FmpLock);
+
+
+ Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UpdateEsrtEntry(Entry, ESRT_FROM_NONFMP);
+
+ EfiReleaseLock(&mPrivate.NonFmpLock);
+
+ return Status;
+}
+
+/**
+ Non-FMP instance to unregister Esrt Entry from ESRT Cache.
+
+ @param[in] FwClass FwClass of Esrt entry to Unregister
+
+ @retval EFI_SUCCESS Insert all entries Successfully
+ @retval EFI_NOT_FOUND Entry of FwClass does not exsit
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeUnRegisterEsrtEntry(
+ IN EFI_GUID *FwClass
+ )
+{
+ EFI_STATUS Status;
+
+ if (FwClass == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DeleteEsrtEntry(FwClass, ESRT_FROM_NONFMP);
+
+ EfiReleaseLock(&mPrivate.NonFmpLock);
+
+ return Status;
+}
+
+/**
+ Non-FMP instance to register one ESRT entry into ESRT Cache.
+
+ @param[in] Entry Esrt entry to be set
+
+ @retval EFI_SUCCESS Successfully set a variable.
+ @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
+ @retval EFI_OUT_OF_RESOURCES Non-FMP ESRT repository is full
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeRegisterEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntryTmp;
+
+ if (Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetEsrtEntry(
+ &Entry->FwClass,
+ ESRT_FROM_NONFMP,
+ &EsrtEntryTmp
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ Status = InsertEsrtEntry(Entry, ESRT_FROM_NONFMP);
+ }
+
+ EfiReleaseLock(&mPrivate.NonFmpLock);
+
+ return Status;
+}
+
+/**
+ This function syn up Cached ESRT with data from FMP instances
+ Function should be called after Connect All in order to locate all FMP protocols
+ installed.
+
+ @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
+ @retval EFI_NOT_FOUND No FMP Instance are found
+ @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeSyncFmp(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ EFI_HANDLE *HandleBuffer;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL **FmpBuf;
+ UINTN NumberOfHandles;
+ UINTN *DescriptorSizeBuf;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR **FmpImageInfoBuf;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
+ UINT8 *FmpImageInfoCountBuf;
+ UINT32 *FmpImageInfoDescriptorVerBuf;
+ UINTN ImageInfoSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepositoryNew;
+ UINTN EntryNumNew;
+
+ NumberOfHandles = 0;
+ EntryNumNew = 0;
+ FmpBuf = NULL;
+ HandleBuffer = NULL;
+ FmpImageInfoBuf = NULL;
+ FmpImageInfoCountBuf = NULL;
+ PackageVersionName = NULL;
+ DescriptorSizeBuf = NULL;
+ FmpImageInfoDescriptorVerBuf = NULL;
+ EsrtRepositoryNew = NULL;
+
+ //
+ // Get image information from all FMP protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+
+
+ if (Status == EFI_NOT_FOUND) {
+ EntryNumNew = 0;
+ goto UPDATE_REPOSITORY;
+ } else if (EFI_ERROR(Status)){
+ goto END;
+ }
+
+ //
+ // Allocate buffer to hold new FMP ESRT Cache repository
+ //
+ EsrtRepositoryNew = AllocateZeroPool(PcdGet32(PcdMaxFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ if (EsrtRepositoryNew == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ FmpBuf = AllocatePool(sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) * NumberOfHandles);
+ if (FmpBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool(sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfHandles);
+ if (FmpImageInfoBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ FmpImageInfoCountBuf = AllocateZeroPool(sizeof(UINT8) * NumberOfHandles);
+ if (FmpImageInfoCountBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ DescriptorSizeBuf = AllocateZeroPool(sizeof(UINTN) * NumberOfHandles);
+ if (DescriptorSizeBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ FmpImageInfoDescriptorVerBuf = AllocateZeroPool(sizeof(UINT32) * NumberOfHandles);
+ if (FmpImageInfoDescriptorVerBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+
+ //
+ // Get all FmpImageInfo Descriptor into FmpImageInfoBuf
+ //
+ for (Index1 = 0; Index1 < NumberOfHandles; Index1++){
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index1],
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&FmpBuf[Index1]
+ );
+
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ ImageInfoSize = 0;
+ Status = FmpBuf[Index1]->GetImageInfo (
+ FmpBuf[Index1],
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FmpImageInfoBuf[Index1] = AllocateZeroPool(ImageInfoSize);
+ if (FmpImageInfoBuf[Index1] == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto END;
+ }
+ } else {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = FmpBuf[Index1]->GetImageInfo (
+ FmpBuf[Index1],
+ &ImageInfoSize,
+ FmpImageInfoBuf[Index1],
+ &FmpImageInfoDescriptorVerBuf[Index1],
+ &FmpImageInfoCountBuf[Index1],
+ &DescriptorSizeBuf[Index1],
+ &PackageVersion,
+ &PackageVersionName
+ );
+
+ //
+ // If FMP GetInformation interface failed, skip this resource
+ //
+ if (EFI_ERROR(Status)){
+ FmpImageInfoCountBuf[Index1] = 0;
+ continue;
+ }
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+ }
+
+ //
+ // Create new FMP cache repository based on FmpImageInfoBuf
+ //
+ for (Index2 = 0; Index2 < NumberOfHandles; Index2++){
+ TempFmpImageInfo = FmpImageInfoBuf[Index2];
+ for (Index3 = 0; Index3 < FmpImageInfoCountBuf[Index2]; Index3++){
+ if ((TempFmpImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) != 0
+ && (TempFmpImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0){
+ //
+ // Always put the first smallest version of Image info into ESRT cache
+ //
+ for(Index1 = 0; Index1 < EntryNumNew; Index1++) {
+ if (CompareGuid(&EsrtRepositoryNew[Index1].FwClass, &TempFmpImageInfo->ImageTypeId)) {
+ if(EsrtRepositoryNew[Index1].FwVersion > TempFmpImageInfo->Version) {
+ SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew[Index1], TempFmpImageInfo, FmpImageInfoDescriptorVerBuf[Index2]);
+ }
+ break;
+ }
+ }
+ //
+ // New ImageTypeId can't be found in EsrtRepositoryNew. Create a new one
+ //
+ if (Index1 == EntryNumNew){
+ SetEsrtEntryFromFmpInfo(&EsrtRepositoryNew[EntryNumNew], TempFmpImageInfo, FmpImageInfoDescriptorVerBuf[Index2]);
+ EntryNumNew++;
+ if (EntryNumNew >= PcdGet32(PcdMaxFmpEsrtCacheNum)) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+ //
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSizeBuf[Index2]);
+ }
+ }
+
+UPDATE_REPOSITORY:
+
+ Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gRT->SetVariable(
+ EFI_ESRT_FMP_VARIABLE_NAME,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ EntryNumNew * sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
+ EsrtRepositoryNew
+ );
+
+ EfiReleaseLock(&mPrivate.FmpLock);
+
+END:
+ if (EsrtRepositoryNew != NULL) {
+ FreePool(EsrtRepositoryNew);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ if (FmpBuf != NULL) {
+ FreePool(FmpBuf);
+ }
+
+ if (FmpImageInfoCountBuf != NULL) {
+ FreePool(FmpImageInfoCountBuf);
+ }
+
+ if (DescriptorSizeBuf != NULL) {
+ FreePool(DescriptorSizeBuf);
+ }
+
+ if (FmpImageInfoDescriptorVerBuf != NULL) {
+ FreePool(FmpImageInfoDescriptorVerBuf);
+ }
+
+ if (FmpImageInfoBuf != NULL) {
+ for (Index1 = 0; Index1 < NumberOfHandles; Index1++){
+ if (FmpImageInfoBuf[Index1] != NULL) {
+ FreePool(FmpImageInfoBuf[Index1]);
+ }
+ }
+ FreePool(FmpImageInfoBuf);
+ }
+
+ return Status;
+}
+
+/**
+ This function locks up Esrt repository to be readonly. It should be called
+ before gEfiEndOfDxeEventGroupGuid event signaled
+
+ @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeLockEsrtRepository(
+ VOID
+ )
+{
+ 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, EFI_ESRT_FMP_VARIABLE_NAME, &gEfiCallerIdGuid);
+ DEBUG((EFI_D_INFO, "EsrtDxe Lock EsrtFmp Variable Status 0x%x", Status));
+
+ Status = VariableLock->RequestToLock (VariableLock, EFI_ESRT_NONFMP_VARIABLE_NAME, &gEfiCallerIdGuid);
+ DEBUG((EFI_D_INFO, "EsrtDxe Lock EsrtNonFmp Variable Status 0x%x", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ install the Esrt Table into system configuration table
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+EsrtReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_TABLE *EsrtTable;
+ EFI_SYSTEM_RESOURCE_ENTRY *FmpEsrtRepository;
+ EFI_SYSTEM_RESOURCE_ENTRY *NonFmpEsrtRepository;
+ UINTN FmpRepositorySize;
+ UINTN NonFmpRepositorySize;
+
+
+ FmpEsrtRepository = NULL;
+ NonFmpEsrtRepository = NULL;
+ FmpRepositorySize = 0;
+ NonFmpRepositorySize = 0;
+
+ Status = EfiAcquireLockOrFail (&mPrivate.NonFmpLock);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = GetVariable2 (
+ EFI_ESRT_NONFMP_VARIABLE_NAME,
+ &gEfiCallerIdGuid,
+ (VOID **) &NonFmpEsrtRepository,
+ &NonFmpRepositorySize
+ );
+
+ if (EFI_ERROR(Status)) {
+ NonFmpRepositorySize = 0;
+ }
+
+ if (NonFmpRepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
+ DEBUG((EFI_D_ERROR, "NonFmp Repository Corrupt. Need to rebuild NonFmp Repository.\n"));
+ NonFmpRepositorySize = 0;
+ }
+
+ EfiReleaseLock(&mPrivate.NonFmpLock);
+
+ Status = EfiAcquireLockOrFail (&mPrivate.FmpLock);
+ Status = GetVariable2 (
+ EFI_ESRT_FMP_VARIABLE_NAME,
+ &gEfiCallerIdGuid,
+ (VOID **) &FmpEsrtRepository,
+ &FmpRepositorySize
+ );
+
+ if (EFI_ERROR(Status)) {
+ FmpRepositorySize = 0;
+ }
+
+ if (FmpRepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
+ DEBUG((EFI_D_ERROR, "Fmp Repository Corrupt. Need to rebuild Fmp Repository.\n"));
+ FmpRepositorySize = 0;
+ }
+
+ EfiReleaseLock(&mPrivate.FmpLock);
+
+ //
+ // Skip ESRT table publish if no ESRT entry exists
+ //
+ if (NonFmpRepositorySize + FmpRepositorySize == 0) {
+ goto EXIT;
+ }
+
+ EsrtTable = AllocatePool(sizeof(EFI_SYSTEM_RESOURCE_TABLE) + NonFmpRepositorySize + FmpRepositorySize);
+ if (EsrtTable == NULL) {
+ DEBUG ((EFI_D_ERROR, "Esrt table memory allocation failure\n"));
+ goto EXIT;
+ }
+
+ EsrtTable->FwResourceVersion = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
+ EsrtTable->FwResourceCount = (UINT32)((NonFmpRepositorySize + FmpRepositorySize) / sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ EsrtTable->FwResourceCountMax = PcdGet32(PcdMaxNonFmpEsrtCacheNum) + PcdGet32(PcdMaxFmpEsrtCacheNum);
+
+ if (NonFmpRepositorySize != 0 && NonFmpEsrtRepository != NULL) {
+ CopyMem(EsrtTable + 1, NonFmpEsrtRepository, NonFmpRepositorySize);
+ }
+
+ if (FmpRepositorySize != 0 && FmpEsrtRepository != NULL) {
+ CopyMem((UINT8 *)(EsrtTable + 1) + NonFmpRepositorySize, FmpEsrtRepository, FmpRepositorySize);
+ }
+
+ //
+ // Publish Esrt to system config table
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, EsrtTable);
+
+ //
+ // Only one successful install
+ //
+ gBS->CloseEvent(Event);
+
+EXIT:
+
+ if (FmpEsrtRepository != NULL) {
+ FreePool(FmpEsrtRepository);
+ }
+
+ if (NonFmpEsrtRepository != NULL) {
+ FreePool(NonFmpEsrtRepository);
+ }
+}
+
+/**
+ The module Entry Point of the Esrt DXE driver that manages cached ESRT repository
+ & publishes ESRT table
+
+ @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
+EsrtDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ EfiInitializeLock (&mPrivate.FmpLock, TPL_CALLBACK);
+ EfiInitializeLock (&mPrivate.NonFmpLock, TPL_CALLBACK);
+
+ //
+ // Install Esrt management Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPrivate.Handle,
+ &gEsrtManagementProtocolGuid,
+ &mEsrtManagementProtocolTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function to install Esrt Table on ReadyToBoot Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EsrtReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mPrivate.Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf
new file mode 100644
index 000000000..6b9eec95f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf
@@ -0,0 +1,66 @@
+## @file
+# Esrt DXE driver that manages cached ESRT repository & publishes ESRT table
+#
+# This driver produces EsrtManagement protocol to manage cache ESRT repository for FMP/Non-FMP instances.
+# ESRT table based on repository is published on gEfiEventReadyToBootGuid.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EsrtDxe
+ MODULE_UNI_FILE = EsrtDxe.uni
+ FILE_GUID = 999BD818-7DF7-4A9A-A502-9B75033E6A0F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = EsrtDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ EsrtImpl.h
+ EsrtImpl.c
+ EsrtDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ PcdLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gEfiSystemResourceTableGuid ## PRODUCES ## SystemTable
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES
+ gEsrtManagementProtocolGuid ## PRODUCES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxFmpEsrtCacheNum ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxNonFmpEsrtCacheNum ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid ## CONSUMES
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EsrtDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.uni b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.uni
new file mode 100644
index 000000000..35bb39a29
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Esrt DXE driver that manages cached ESRT repository & publishes ESRT table
+//
+// This driver produces EsrtManagement protocol to manage cache ESRT repository for FMP/Non-FMP instances.
+// ESRT table based on repository is published on gEfiEventReadyToBootGuid.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Esrt DXE driver that manages cached ESRT repository & publishes ESRT table"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces EsrtManagement protocol to manage cache ESRT repository for FMP/Non-FMP instances.<BR><BR>\n"
+ "ESRT table based on repository is published on EsrtReadyToBootEventNotify.<BR>"
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxeExtra.uni
new file mode 100644
index 000000000..629a6845a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EsrtDxe Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Esrt DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c
new file mode 100644
index 000000000..fff17b98f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.c
@@ -0,0 +1,475 @@
+/** @file
+ Esrt management implementation.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EsrtImpl.h"
+
+/**
+ Find Esrt Entry stored in ESRT repository.
+
+ @param[in] FwClass Firmware class guid in Esrt entry
+ @param[in] Attribute Esrt from Non FMP or FMP instance
+ @param[out] Entry Esrt entry returned
+
+ @retval EFI_SUCCESS Successfully find an Esrt entry
+ @retval EF_NOT_FOUND No Esrt entry found
+
+**/
+EFI_STATUS
+GetEsrtEntry (
+ IN EFI_GUID *FwClass,
+ IN UINTN Attribute,
+ OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableName;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
+ UINTN RepositorySize;
+ UINTN Index;
+ UINTN EsrtNum;
+
+ EsrtRepository = NULL;
+
+ //
+ // Get Esrt index buffer
+ //
+ if (Attribute == ESRT_FROM_FMP) {
+ VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
+ } else {
+ VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
+ }
+
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID **) &EsrtRepository,
+ &RepositorySize
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
+ DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
+ Status = EFI_ABORTED;
+ goto EXIT;
+ }
+
+ Status = EFI_NOT_FOUND;
+ EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
+ for (Index = 0; Index < EsrtNum; Index++) {
+ if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) {
+ CopyMem(Entry, &EsrtRepository[Index], sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+EXIT:
+ if (EsrtRepository != NULL) {
+ FreePool(EsrtRepository);
+ }
+
+ return Status;
+}
+
+/**
+ Insert a new ESRT entry into ESRT Cache repository.
+
+ @param[in] Entry Esrt entry to be set
+ @param[in] Attribute Esrt from Esrt private protocol or FMP instance
+
+ @retval EFI_SUCCESS Successfully set a variable.
+
+**/
+EFI_STATUS
+InsertEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
+ UINTN Attribute
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableName;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
+ UINTN RepositorySize;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepositoryNew;
+
+ EsrtRepository = NULL;
+ EsrtRepositoryNew = NULL;
+
+ //
+ // Get Esrt index buffer
+ //
+ if (Attribute == ESRT_FROM_FMP) {
+ VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
+ } else {
+ VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
+ }
+
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID **) &EsrtRepository,
+ &RepositorySize
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // If not exist, create new Esrt cache repository
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
+ Entry
+ );
+ return Status;
+
+ } else if (Status == EFI_SUCCESS) {
+ //
+ // if exist, update Esrt cache repository
+ //
+ if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
+ DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
+ //
+ // Repository is corrupt. Clear Repository before insert new entry
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ EsrtRepository
+ );
+ FreePool(EsrtRepository);
+ RepositorySize = 0;
+ EsrtRepository = NULL;
+ }
+
+ //
+ // Check Repository size constraint
+ //
+ if ((Attribute == ESRT_FROM_FMP && RepositorySize >= PcdGet32(PcdMaxFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY))
+ ||(Attribute == ESRT_FROM_NONFMP && RepositorySize >= PcdGet32(PcdMaxNonFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ EsrtRepositoryNew = AllocatePool(RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ if (EsrtRepositoryNew == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ if (RepositorySize != 0 && EsrtRepository != NULL) {
+ CopyMem(EsrtRepositoryNew, EsrtRepository, RepositorySize);
+ }
+ CopyMem((UINT8 *)EsrtRepositoryNew + RepositorySize, Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
+ EsrtRepositoryNew
+ );
+ }
+
+EXIT:
+ if (EsrtRepository != NULL) {
+ FreePool(EsrtRepository);
+ }
+
+ if (EsrtRepositoryNew != NULL) {
+ FreePool(EsrtRepositoryNew);
+ }
+
+ return Status;
+}
+
+/**
+ Delete ESRT Entry from ESRT repository.
+
+ @param[in] FwClass FwClass of Esrt entry to delete
+ @param[in] Attribute Esrt from Esrt private protocol or FMP instance
+
+ @retval EFI_SUCCESS Insert all entries Successfully
+ @retval EFI_NOT_FOUND ESRT entry with FwClass doesn't exsit
+
+**/
+EFI_STATUS
+DeleteEsrtEntry(
+ IN EFI_GUID *FwClass,
+ IN UINTN Attribute
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableName;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
+ UINTN RepositorySize;
+ UINTN Index;
+ UINTN EsrtNum;
+
+ EsrtRepository = NULL;
+
+ //
+ // Get Esrt index buffer
+ //
+ if (Attribute == ESRT_FROM_FMP) {
+ VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
+ } else {
+ VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
+ }
+
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID **) &EsrtRepository,
+ &RepositorySize
+ );
+
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ if (EsrtRepository == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ if ((RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) != 0) {
+ DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
+ //
+ // Repository is corrupt. Clear Repository before insert new entry
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ EsrtRepository
+ );
+ goto EXIT;
+ }
+
+ Status = EFI_NOT_FOUND;
+ EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
+ for (Index = 0; Index < EsrtNum; Index++) {
+ //
+ // Delete Esrt entry if it is found in repository
+ //
+ if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) {
+ //
+ // If delete Esrt entry is not at the rail
+ //
+ if (Index < EsrtNum - 1) {
+ CopyMem(&EsrtRepository[Index], &EsrtRepository[Index + 1], (EsrtNum - Index - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ }
+
+ //
+ // Update New Repository
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ (EsrtNum - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY),
+ EsrtRepository
+ );
+ break;
+ }
+ }
+
+EXIT:
+ if (EsrtRepository != NULL) {
+ FreePool(EsrtRepository);
+ }
+
+ return Status;
+
+}
+
+/**
+ Update one ESRT entry in ESRT repository
+
+ @param[in] Entry Esrt entry to be set
+ @param[in] Attribute Esrt from Non Esrt or FMP instance
+
+ @retval EFI_SUCCESS Successfully Update a variable.
+ @retval EFI_NOT_FOUND The Esrt enry doesn't exist
+
+**/
+EFI_STATUS
+UpdateEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
+ UINTN Attribute
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableName;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository;
+ UINTN RepositorySize;
+ UINTN Index;
+ UINTN EsrtNum;
+
+ EsrtRepository = NULL;
+
+ //
+ // Get Esrt index buffer
+ //
+ if (Attribute == ESRT_FROM_FMP) {
+ VariableName = EFI_ESRT_FMP_VARIABLE_NAME;
+ } else {
+ VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME;
+ }
+
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID **) &EsrtRepository,
+ &RepositorySize
+ );
+
+ if (EsrtRepository == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ if (!EFI_ERROR(Status)) {
+ //
+ // if exist, update Esrt cache repository
+ //
+ if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) {
+ DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n"));
+ //
+ // Repository is corrupt. Clear Repository before insert new entry
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ EsrtRepository
+ );
+ Status = EFI_NOT_FOUND;
+ goto EXIT;
+ }
+
+ Status = EFI_NOT_FOUND;
+ EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY);
+ for (Index = 0; Index < EsrtNum; Index++) {
+ //
+ // Update Esrt entry if it is found in repository
+ //
+ if (CompareGuid(&Entry->FwClass, &EsrtRepository[Index].FwClass)) {
+
+ CopyMem(&EsrtRepository[Index], Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY));
+ //
+ // Update New Repository
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ RepositorySize,
+ EsrtRepository
+ );
+ break;
+ }
+ }
+ }
+
+EXIT:
+ if (EsrtRepository != NULL) {
+ FreePool(EsrtRepository);
+ }
+
+ return Status;
+}
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
+
+ @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
+
+ @return TRUE It is a system FMP.
+ @return FALSE It is a device FMP.
+**/
+BOOLEAN
+IsSystemFmp (
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo
+ )
+{
+ GUID *Guid;
+ UINTN Count;
+ UINTN Index;
+
+ Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid);
+ Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid)/sizeof(GUID);
+
+ for (Index = 0; Index < Count; Index++, Guid++) {
+ if (CompareGuid(&FmpImageInfo->ImageTypeId, Guid)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Init one ESRT entry according to input FmpImageInfo (V1, V2, V3) .
+
+ @param[in, out] EsrtEntry Esrt entry to be Init
+ @param[in] FmpImageInfo FMP image info descriptor
+ @param[in] DescriptorVersion FMP Image info descriptor version
+
+**/
+VOID
+SetEsrtEntryFromFmpInfo (
+ IN OUT EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo,
+ IN UINT32 DescriptorVersion
+ )
+{
+ EsrtEntry->FwVersion = FmpImageInfo->Version;
+ EsrtEntry->FwClass = FmpImageInfo->ImageTypeId;
+ if (IsSystemFmp(FmpImageInfo)) {
+ EsrtEntry->FwType = ESRT_FW_TYPE_SYSTEMFIRMWARE;
+ } else {
+ EsrtEntry->FwType = ESRT_FW_TYPE_DEVICEFIRMWARE;
+ }
+ EsrtEntry->LowestSupportedFwVersion = 0;
+ EsrtEntry->CapsuleFlags = 0;
+ EsrtEntry->LastAttemptVersion = 0;
+ EsrtEntry->LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+
+ if (DescriptorVersion >= 2) {
+ //
+ // LowestSupportedImageVersion only available in FMP V2 or higher
+ //
+ EsrtEntry->LowestSupportedFwVersion = FmpImageInfo->LowestSupportedImageVersion;
+ }
+
+ if (DescriptorVersion >= 3) {
+ //
+ // LastAttemptVersion & LastAttemptStatus only available in FMP V3 or higher
+ //
+ EsrtEntry->LastAttemptVersion = FmpImageInfo->LastAttemptVersion;
+ EsrtEntry->LastAttemptStatus = FmpImageInfo->LastAttemptStatus;
+ }
+
+ //
+ // Set capsule customized flag
+ //
+ if ((FmpImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0
+ && (FmpImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) {
+ EsrtEntry->CapsuleFlags = PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag);
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.h b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.h
new file mode 100644
index 000000000..68d0d2ba5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtDxe/EsrtImpl.h
@@ -0,0 +1,238 @@
+/** @file
+ Esrt management implementation head file.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_ESRT_IMPL_H_
+#define _DXE_ESRT_IMPL_H_
+
+#include <Guid/EventGroup.h>
+#include <Guid/SystemResourceTable.h>
+
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CapsuleLib.h>
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/VariableLock.h>
+
+//
+// Name of Variable for Non-FMP ESRT Repository
+//
+#define EFI_ESRT_NONFMP_VARIABLE_NAME L"EsrtNonFmp"
+
+//
+// Name of Variable for FMP
+//
+#define EFI_ESRT_FMP_VARIABLE_NAME L"EsrtFmp"
+
+//
+// Attribute of Cached ESRT entry
+//
+#define ESRT_FROM_FMP 0x00000001
+#define ESRT_FROM_NONFMP 0x00000002
+
+typedef struct {
+ EFI_HANDLE Handle;
+ //
+ // Ready to boot event
+ //
+ EFI_EVENT Event;
+
+ //
+ // Updates to Fmp storage must be locked.
+ //
+ EFI_LOCK FmpLock;
+
+ //
+ // Update to Non-Fmp storage must be locked
+ //
+ EFI_LOCK NonFmpLock;
+} ESRT_PRIVATE_DATA;
+
+
+/**
+ Find Esrt Entry stored in ESRT repository.
+
+ @param[in] FwClass Firmware class guid in Esrt entry
+ @param[in] Attribute Esrt from Non FMP or FMP instance
+ @param[out] Entry Esrt entry returned
+
+ @retval EFI_SUCCESS Successfully find an Esrt entry
+ @retval EF_NOT_FOUND No Esrt entry found
+
+**/
+EFI_STATUS
+GetEsrtEntry (
+ IN EFI_GUID *FwClass,
+ IN UINTN Attribute,
+ OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+/**
+ Insert a new ESRT entry into ESRT Cache repository.
+
+ @param[in] Entry Esrt entry to be set
+ @param[in] Attribute Esrt from Esrt private protocol or FMP instance
+
+ @retval EFI_SUCCESS Successfully set a variable.
+
+**/
+EFI_STATUS
+InsertEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
+ UINTN Attribute
+ );
+
+/**
+ Delete ESRT Entry from ESRT repository.
+
+ @param[in] FwClass FwClass of Esrt entry to delete
+ @param[in] Attribute Esrt from Esrt private protocol or FMP instance
+
+ @retval EFI_SUCCESS Insert all entries Successfully
+ @retval EFI_NOT_FOUND ESRT entry with FwClass doesn't exsit
+
+**/
+EFI_STATUS
+DeleteEsrtEntry(
+ IN EFI_GUID *FwClass,
+ IN UINTN Attribute
+ );
+
+/**
+ Update one ESRT entry in ESRT repository
+
+ @param[in] Entry Esrt entry to be set
+ @param[in] Attribute Esrt from Non Esrt or FMP instance
+
+ @retval EFI_SUCCESS Successfully Update a variable.
+ @retval EFI_NOT_FOUND The Esrt enry doesn't exist
+
+**/
+EFI_STATUS
+UpdateEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry,
+ UINTN Attribute
+ );
+
+/**
+ Init one ESRT entry according to input FmpImageInfo (V1, V2, V3) .
+
+ @param[in, out] EsrtEntry Esrt entry to be Init
+ @param[in] FmpImageInfo FMP image info descriptor
+ @param[in] DescriptorVersion FMP Image info descriptor version
+
+**/
+VOID
+SetEsrtEntryFromFmpInfo (
+ IN OUT EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo,
+ IN UINT32 DescriptorVersion
+ );
+
+/**
+ Get ESRT entry from ESRT Cache by FwClass Guid
+
+ @param[in] FwClass FwClass of Esrt entry to get
+ @param[in, out] Entry Esrt entry returned
+
+ @retval EFI_SUCCESS The variable saving this Esrt Entry exists.
+ @retval EF_NOT_FOUND No correct variable found.
+ @retval EFI_WRITE_PROTECTED ESRT Cache repository is locked
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeGetEsrtEntry(
+ IN EFI_GUID *FwClass,
+ IN OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+/**
+ Update one ESRT entry in ESRT Cache.
+
+ @param[in] Entry Esrt entry to be updated
+
+ @retval EFI_SUCCESS Successfully update an ESRT entry in cache.
+ @retval EFI_INVALID_PARAMETER Entry does't exist in ESRT Cache
+ @retval EFI_WRITE_PROTECTED ESRT Cache is locked
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeUpdateEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+/**
+ Non-FMP instance to unregister Esrt Entry from ESRT Cache.
+
+ @param[in] FwClass FwClass of Esrt entry to Unregister
+
+ @retval EFI_SUCCESS Insert all entries Successfully
+ @retval EFI_NOT_FOUND Entry of FwClass does not exsit
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeUnRegisterEsrtEntry(
+ IN EFI_GUID *FwClass
+ );
+
+/**
+ Non-FMP instance to register one ESRT entry into ESRT Cache.
+
+ @param[in] Entry Esrt entry to be set
+
+ @retval EFI_SUCCESS Successfully set a variable.
+ @retval EFI_INVALID_PARAMETER ESRT Entry is already exist
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeRegisterEsrtEntry(
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ );
+
+/**
+ This function syn up Cached ESRT with data from FMP instances
+ Function should be called after Connect All in order to locate all FMP protocols
+ installed.
+
+ @retval EFI_SUCCESS Successfully sync cache repository from FMP instances
+ @retval EFI_NOT_FOUND No FMP Instance are found
+ @retval EFI_OUT_OF_RESOURCES Resource allocaton fail
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeSyncFmp(
+ VOID
+ );
+
+/**
+ This function locks up Esrt repository to be readonly. It should be called
+ before gEfiEndOfDxeEventGroupGuid event signaled
+
+ @retval EFI_SUCCESS Locks up FMP Non-FMP repository successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EsrtDxeLockEsrtRepository(
+ VOID
+ );
+
+#endif // #ifndef _EFI_ESRT_IMPL_H_
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmp.c b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmp.c
new file mode 100644
index 000000000..4670349f8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmp.c
@@ -0,0 +1,558 @@
+/** @file
+ Publishes ESRT table from Firmware Management Protocol instances
+
+ Copyright (c) 2016, Microsoft Corporation
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/EventGroup.h>
+#include <Guid/SystemResourceTable.h>
+
+///
+/// Structure for array of unique GUID/HardwareInstance pairs from the
+/// current set of EFI_FIRMWARE_IMAGE_DESCRIPTORs from all FMP Protocols.
+///
+typedef struct {
+ ///
+ /// A unique GUID identifying the firmware image type.
+ ///
+ EFI_GUID ImageTypeGuid;
+ ///
+ /// An optional number to identify the unique hardware instance within the
+ /// system for devices that may have multiple instances whenever possible.
+ ///
+ UINT64 HardwareInstance;
+} GUID_HARDWAREINSTANCE_PAIR;
+
+/**
+ Print ESRT to debug console.
+
+ @param[in] Table Pointer to the ESRT table.
+
+**/
+VOID
+EFIAPI
+PrintTable (
+ IN EFI_SYSTEM_RESOURCE_TABLE *Table
+ );
+
+/**
+ Install EFI System Resource Table into the UEFI Configuration Table
+
+ @param[in] Table Pointer to the ESRT.
+
+ @return Status code.
+
+**/
+EFI_STATUS
+InstallEfiSystemResourceTableInUefiConfigurationTable (
+ IN EFI_SYSTEM_RESOURCE_TABLE *Table
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ if (Table->FwResourceCount == 0) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
+ Status = EFI_UNSUPPORTED;
+ } else {
+ //
+ // Install the pointer into config table
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, Table);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table. Status: %r. \n", Status));
+ } else {
+ DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Installed ESRT table. \n"));
+ }
+ }
+ return Status;
+}
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
+
+ @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
+
+ @return TRUE It is a system FMP.
+ @return FALSE It is a device FMP.
+**/
+BOOLEAN
+IsSystemFmp (
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo
+ )
+{
+ GUID *Guid;
+ UINTN Count;
+ UINTN Index;
+
+ Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);
+ Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
+
+ for (Index = 0; Index < Count; Index++, Guid++) {
+ if (CompareGuid (&FmpImageInfo->ImageTypeId, Guid)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Function to create a single ESRT Entry and add it to the ESRT with
+ a given FMP descriptor. If the GUID is already in the ESRT, then the ESRT
+ entry is updated.
+
+ @param[in,out] Table Pointer to the ESRT Table.
+ @param[in,out] HardwareInstances Pointer to the GUID_HARDWAREINSTANCE_PAIR.
+ @param[in,out] NumberOfDescriptors The number of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+ @param[in] FmpImageInfoBuf Pointer to the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] FmpVersion FMP Version.
+
+ @retval EFI_SUCCESS FmpImageInfoBuf was use to fill in a new ESRT entry
+ in Table.
+ @retval EFI_SUCCESS The ImageTypeId GUID in FmpImageInfoBuf matches an
+ existing ESRT entry in Table, and the information
+ from FmpImageInfoBuf was merged into the the existing
+ ESRT entry.
+ @retval EFI_UNSPOORTED The GUID/HardareInstance in FmpImageInfoBuf has is a
+ duplicate.
+
+**/
+EFI_STATUS
+CreateEsrtEntry (
+ IN OUT EFI_SYSTEM_RESOURCE_TABLE *Table,
+ IN OUT GUID_HARDWAREINSTANCE_PAIR *HardwareInstances,
+ IN OUT UINT32 *NumberOfDescriptors,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf,
+ IN UINT32 FmpVersion
+ )
+{
+ UINTN Index;
+ EFI_SYSTEM_RESOURCE_ENTRY *Entry;
+ UINT64 FmpHardwareInstance;
+
+ FmpHardwareInstance = 0;
+ if (FmpVersion >= 3) {
+ FmpHardwareInstance = FmpImageInfoBuf->HardwareInstance;
+ }
+
+ //
+ // Check to see of FmpImageInfoBuf GUID/HardwareInstance is unique
+ //
+ for (Index = 0; Index < *NumberOfDescriptors; Index++) {
+ if (CompareGuid (&HardwareInstances[Index].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId)) {
+ if (HardwareInstances[Index].HardwareInstance == FmpHardwareInstance) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Duplicate firmware image descriptor with GUID %g HardwareInstance:0x%x\n", &FmpImageInfoBuf->ImageTypeId, FmpHardwareInstance));
+ ASSERT (
+ !CompareGuid (&HardwareInstances[Index].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId) ||
+ HardwareInstances[Index].HardwareInstance != FmpHardwareInstance
+ );
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Record new GUID/HardwareInstance pair
+ //
+ CopyGuid (&HardwareInstances[*NumberOfDescriptors].ImageTypeGuid, &FmpImageInfoBuf->ImageTypeId);
+ HardwareInstances[*NumberOfDescriptors].HardwareInstance = FmpHardwareInstance;
+ *NumberOfDescriptors = *NumberOfDescriptors + 1;
+
+ DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Add new image descriptor with GUID %g HardwareInstance:0x%x\n", &FmpImageInfoBuf->ImageTypeId, FmpHardwareInstance));
+
+ //
+ // Check to see if GUID is already in the ESRT table
+ //
+ Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(Table + 1);
+ for (Index = 0; Index < Table->FwResourceCount; Index++, Entry++) {
+ if (!CompareGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId)) {
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry->FwClass));
+
+ //
+ // Set ESRT FwVersion to the smaller of the two values
+ //
+ Entry->FwVersion = MIN (FmpImageInfoBuf->Version, Entry->FwVersion);
+
+ //
+ // VERSION 2 has Lowest Supported
+ //
+ if (FmpVersion >= 2) {
+ //
+ // Set ESRT LowestSupportedFwVersion to the smaller of the two values
+ //
+ Entry->LowestSupportedFwVersion =
+ MIN (
+ FmpImageInfoBuf->LowestSupportedImageVersion,
+ Entry->LowestSupportedFwVersion
+ );
+ }
+
+ //
+ // VERSION 3 supports last attempt values
+ //
+ if (FmpVersion >= 3) {
+ //
+ // Update the ESRT entry with the last attempt status and last attempt
+ // version from the first FMP instance whose last attempt status is not
+ // SUCCESS. If all FMP instances are SUCCESS, then set version to the
+ // smallest value from all FMP instances.
+ //
+ if (Entry->LastAttemptStatus == LAST_ATTEMPT_STATUS_SUCCESS) {
+ if (FmpImageInfoBuf->LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {
+ Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
+ Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
+ } else {
+ Entry->LastAttemptVersion =
+ MIN (
+ FmpImageInfoBuf->LastAttemptVersion,
+ Entry->LastAttemptVersion
+ );
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Add a new ESRT Table Entry
+ //
+ Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(Table + 1) + Table->FwResourceCount;
+
+ CopyGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId);
+
+ if (IsSystemFmp (FmpImageInfoBuf)) {
+ DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
+ Entry->FwType = (UINT32)(ESRT_FW_TYPE_SYSTEMFIRMWARE);
+ } else {
+ Entry->FwType = (UINT32)(ESRT_FW_TYPE_DEVICEFIRMWARE);
+ }
+
+ Entry->FwVersion = FmpImageInfoBuf->Version;
+ Entry->LowestSupportedFwVersion = 0;
+ Entry->CapsuleFlags = 0;
+ Entry->LastAttemptVersion = 0;
+ Entry->LastAttemptStatus = 0;
+
+ //
+ // VERSION 2 has Lowest Supported
+ //
+ if (FmpVersion >= 2) {
+ Entry->LowestSupportedFwVersion = FmpImageInfoBuf->LowestSupportedImageVersion;
+ }
+
+ //
+ // VERSION 3 supports last attempt values
+ //
+ if (FmpVersion >= 3) {
+ Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
+ Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
+ }
+
+ //
+ // Increment the number of active ESRT Table Entries
+ //
+ Table->FwResourceCount++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to retrieve the EFI_FIRMWARE_IMAGE_DESCRIPTOR from an FMP Instance.
+ The returned buffer is allocated using AllocatePool() and must be freed by the
+ caller using FreePool().
+
+ @param[in] Fmp Pointer to an EFI_FIRMWARE_MANAGEMENT_PROTOCOL.
+ @param[out] FmpImageInfoDescriptorVer Pointer to the version number associated
+ with the returned EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] FmpImageInfoCount Pointer to the number of the returned
+ EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+ @param[out] DescriptorSize Pointer to the size, in bytes, of each
+ returned EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ @return Pointer to the retrieved EFI_FIRMWARE_IMAGE_DESCRIPTOR. If the
+ descriptor can not be retrieved, then NULL is returned.
+
+**/
+EFI_FIRMWARE_IMAGE_DESCRIPTOR *
+FmpGetFirmwareImageDescriptor (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp,
+ OUT UINT32 *FmpImageInfoDescriptorVer,
+ OUT UINT8 *FmpImageInfoCount,
+ OUT UINTN *DescriptorSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN ImageInfoSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp, // FMP Pointer
+ &ImageInfoSize, // Buffer Size (in this case 0)
+ NULL, // NULL so we can get size
+ FmpImageInfoDescriptorVer, // DescriptorVersion
+ FmpImageInfoCount, // DescriptorCount
+ DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Unexpected Failure in GetImageInfo. Status = %r\n", Status));
+ return NULL;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to get memory for FMP descriptor.\n"));
+ return NULL;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp, // FMP Pointer
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ FmpImageInfoDescriptorVer, // DescriptorVersion
+ FmpImageInfoCount, // DescriptorCount
+ DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (PackageVersionName != NULL) {
+ FreePool (PackageVersionName);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failure in GetImageInfo. Status = %r\n", Status));
+ FreePool (FmpImageInfoBuf);
+ return NULL;
+ }
+
+ return FmpImageInfoBuf;
+}
+
+/**
+ Function to create ESRT based on FMP Instances.
+ Create ESRT table, get the descriptors from FMP Instance and
+ create ESRT entries (ESRE).
+
+ @return Pointer to the ESRT created.
+
+**/
+EFI_SYSTEM_RESOURCE_TABLE *
+CreateFmpBasedEsrt (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NoProtocols;
+ VOID **Buffer;
+ UINTN Index;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 NumberOfDescriptors;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *OrgFmpImageInfoBuf;
+ EFI_SYSTEM_RESOURCE_TABLE *Table;
+ GUID_HARDWAREINSTANCE_PAIR *HardwareInstances;
+
+ Status = EFI_SUCCESS;
+ NoProtocols = 0;
+ Buffer = NULL;
+ FmpImageInfoBuf = NULL;
+ OrgFmpImageInfoBuf = NULL;
+ Table = NULL;
+ HardwareInstances = NULL;
+
+ Status = EfiLocateProtocolBuffer (
+ &gEfiFirmwareManagementProtocolGuid,
+ &NoProtocols,
+ &Buffer
+ );
+ if (EFI_ERROR(Status) || (Buffer == NULL)) {
+ return NULL;
+ }
+
+ //
+ // Count the total number of EFI_FIRMWARE_IMAGE_DESCRIPTORs
+ //
+ for (Index = 0, NumberOfDescriptors = 0; Index < NoProtocols; Index++) {
+ FmpImageInfoBuf = FmpGetFirmwareImageDescriptor (
+ (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) Buffer[Index],
+ &FmpImageInfoDescriptorVer,
+ &FmpImageInfoCount,
+ &DescriptorSize
+ );
+ if (FmpImageInfoBuf != NULL) {
+ NumberOfDescriptors += FmpImageInfoCount;
+ FreePool (FmpImageInfoBuf);
+ }
+ }
+
+ //
+ // Allocate ESRT Table and GUID/HardwareInstance table
+ //
+ Table = AllocateZeroPool (
+ (NumberOfDescriptors * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
+ );
+ if (Table == NULL) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
+ FreePool (Buffer);
+ return NULL;
+ }
+
+ HardwareInstances = AllocateZeroPool (NumberOfDescriptors * sizeof (GUID_HARDWAREINSTANCE_PAIR));
+ if (HardwareInstances == NULL) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for HW Instance Table.\n"));
+ FreePool (Table);
+ FreePool (Buffer);
+ return NULL;
+ }
+
+ //
+ // Initialize ESRT Table
+ //
+ Table->FwResourceCount = 0;
+ Table->FwResourceCountMax = NumberOfDescriptors;
+ Table->FwResourceVersion = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
+
+ NumberOfDescriptors = 0;
+ for (Index = 0; Index < NoProtocols; Index++) {
+ FmpImageInfoBuf = FmpGetFirmwareImageDescriptor (
+ (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) Buffer[Index],
+ &FmpImageInfoDescriptorVer,
+ &FmpImageInfoCount,
+ &DescriptorSize
+ );
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ //
+ // Check each descriptor and read from the one specified
+ //
+ OrgFmpImageInfoBuf = FmpImageInfoBuf;
+ while (FmpImageInfoCount > 0) {
+ //
+ // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
+ //
+ if ((FmpImageInfoBuf->AttributesSetting & FmpImageInfoBuf->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) == IMAGE_ATTRIBUTE_IN_USE) {
+ //
+ // Create ESRT entry
+ //
+ CreateEsrtEntry (Table, HardwareInstances, &NumberOfDescriptors, FmpImageInfoBuf, FmpImageInfoDescriptorVer);
+ }
+ FmpImageInfoCount--;
+ //
+ // Increment the buffer pointer ahead by the size of the descriptor
+ //
+ FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);
+ }
+
+ FreePool (OrgFmpImageInfoBuf);
+ OrgFmpImageInfoBuf = NULL;
+ }
+
+ FreePool (Buffer);
+ FreePool (HardwareInstances);
+ return Table;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ install the Efi System Resource Table.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+EsrtReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_TABLE *Table;
+
+ Table = CreateFmpBasedEsrt ();
+ if (Table != NULL) {
+ //
+ // Print table on debug builds
+ //
+ DEBUG_CODE_BEGIN ();
+ PrintTable (Table);
+ DEBUG_CODE_END ();
+
+ Status = InstallEfiSystemResourceTableInUefiConfigurationTable (Table);
+ if (EFI_ERROR (Status)) {
+ FreePool (Table);
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
+ }
+
+ //
+ // Close the event to prevent it be signalled again.
+ //
+ gBS->CloseEvent (Event);
+}
+
+/**
+ The module Entry Point of the Efi System Resource Table DXE 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
+EsrtFmpEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT EsrtReadyToBootEvent;
+
+ //
+ // Register notify function to install ESRT on ReadyToBoot Event.
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ EsrtReadyToBootEventNotify,
+ NULL,
+ &EsrtReadyToBootEvent
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to register for ready to boot\n"));
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDebugPrint.c b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDebugPrint.c
new file mode 100644
index 000000000..e97279376
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDebugPrint.c
@@ -0,0 +1,144 @@
+/** @file
+ Publishes ESRT table from Firmware Management Protocol instances
+
+ Copyright (c) 2016, Microsoft Corporation
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/SystemResourceTable.h>
+
+/**
+ Function to print a single ESRT Entry (ESRE) to the debug console.
+
+ Print Format:
+ | 00000000-0000-0000-0000-000000000000 | SSSSSSSSSSSS | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+
+ @param[in] Entry - Pointer to an ESRE entry
+ @retval EFI_SUCCESS
+ EFI_INVALID_PARAMETER
+**/
+EFI_STATUS
+EFIAPI
+PrintOutEsrtEntry (
+ IN EFI_SYSTEM_RESOURCE_ENTRY *Entry
+ )
+{
+ if (Entry == NULL) {
+ DEBUG ((DEBUG_INFO, "| ERROR: Invalid resource entry pointer "));
+ DEBUG ((DEBUG_INFO, " |\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // GUID FW Class (36 chars plus table formatting)
+ //
+ DEBUG ((DEBUG_INFO, "| %g |", &Entry->FwClass));
+
+ //
+ // Entry Type (12 chars plus table formatting)
+ //
+ switch (Entry->FwType) {
+ case (ESRT_FW_TYPE_SYSTEMFIRMWARE) :
+ DEBUG ((DEBUG_INFO, " System FW |"));
+ break;
+ case (ESRT_FW_TYPE_DEVICEFIRMWARE) :
+ DEBUG ((DEBUG_INFO, " Device FW |"));
+ break;
+ case (ESRT_FW_TYPE_UEFIDRIVER) :
+ DEBUG ((DEBUG_INFO, " Uefi Driver |"));
+ break;
+ case (ESRT_FW_TYPE_UNKNOWN) :
+ DEBUG ((DEBUG_INFO, " Unknown Type |"));
+ break;
+ default:
+ DEBUG ((DEBUG_INFO, " ? 0x%8X |", Entry->FwType));
+ break;
+ }
+
+ //
+ // FW Version (10 char UINT32 string plus table formatting)
+ // Lowest Supported Version (10 char UINT32 string plus table formatting)
+ // Capsule Flags (10 char UINT32 string plus table formatting)
+ // Last Attempt Version (10 char UINT32 string plus table formatting)
+ // Last Attempt Status (10 char UINT32 string plus table formatting)
+ //
+ DEBUG ((DEBUG_INFO,
+ " 0x%8X | 0x%8X | 0x%8X | 0x%8X | 0x%8X |\n",
+ Entry->FwVersion,
+ Entry->LowestSupportedFwVersion,
+ Entry->CapsuleFlags,
+ Entry->LastAttemptVersion,
+ Entry->LastAttemptStatus
+ ));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to print the ESRT table to the debug console.
+
+ @param[in] Table - Pointer to the ESRT table
+**/
+VOID
+EFIAPI
+PrintTable (
+ IN EFI_SYSTEM_RESOURCE_TABLE *Table
+ )
+{
+ EFI_SYSTEM_RESOURCE_ENTRY *Entry;
+ UINTN Index;
+
+ Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(((UINT8 *)Table) + sizeof (EFI_SYSTEM_RESOURCE_TABLE));
+
+ //
+ // Print ESRT table information
+ //
+ DEBUG ((DEBUG_INFO, "ESRT Table Information:\n"));
+ if (Table == NULL) {
+ DEBUG ((DEBUG_INFO, "ERROR: Invalid table pointer\n"));
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "+--------------------------------------------------------+\n"));
+ DEBUG ((DEBUG_INFO, "| Firmware Resource Count : 0x%08x |\n", Table->FwResourceCount));
+ DEBUG ((DEBUG_INFO, "| Firmware Resource Count Max : 0x%08x |\n", Table->FwResourceCountMax));
+ DEBUG ((DEBUG_INFO, "| Firmware Resource Entry Version : 0x%016x |\n", Table->FwResourceVersion));
+ DEBUG ((DEBUG_INFO, "+--------------------------------------------------------+\n"));
+
+ //
+ // Print table entry information
+ //
+ DEBUG ((DEBUG_INFO, "ESRT Table Entries:\n"));
+ if (Table->FwResourceVersion != EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION) {
+ DEBUG ((DEBUG_INFO, "ERROR: Unsupported Resource Entry Version\n"));
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "+--------------------------------------+--------------+------------"));
+ DEBUG ((DEBUG_INFO, "+------------+------------+------------+------------+\n"));
+ DEBUG ((DEBUG_INFO, "| | | "));
+ DEBUG ((DEBUG_INFO, "| Lowest | | Last | Last |\n"));
+ DEBUG ((DEBUG_INFO, "| | Firmware | "));
+ DEBUG ((DEBUG_INFO, "| Supported | Capsule | Attempted | Attempted |\n"));
+ DEBUG ((DEBUG_INFO, "| CLASS GUID | Type | Version "));
+ DEBUG ((DEBUG_INFO, "| Version | Flags | Version | Status |\n"));
+ DEBUG ((DEBUG_INFO, "+--------------------------------------+--------------+------------"));
+ DEBUG ((DEBUG_INFO, "+------------+------------+------------+------------+\n"));
+
+ for (Index = 0; Index < Table->FwResourceCount; Index++) {
+ PrintOutEsrtEntry (&(Entry[Index]));
+ }
+
+ DEBUG ((DEBUG_INFO, "+--------------------------------------+--------------+------------"));
+ DEBUG ((DEBUG_INFO, "+------------+------------+------------+------------+\n"));
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf
new file mode 100644
index 000000000..89120c181
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf
@@ -0,0 +1,57 @@
+## @file
+# Publishes ESRT table from Firmware Management Protocol instances
+#
+# Copyright (c) 2016, Microsoft Corporation
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EsrtFmpDxe
+ MODULE_UNI_FILE = EsrtFmpDxe.uni
+ FILE_GUID = FF626DA9-17EE-4949-A8B8-B10FA0044E9F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = EsrtFmpEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ EsrtFmp.c
+ EsrtFmpDebugPrint.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid ## CONSUMES
+
+[Guids]
+ gEfiSystemResourceTableGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EsrtFmpDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.uni b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.uni
new file mode 100644
index 000000000..7d97bc204
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// Publishes ESRT table from Firmware Management Protocol instances
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Publishes ESRT table from Firmware Management Protocol instances"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver publishes the ESRT table from Firmware Management Protocol instances.<BR><BR>\n"
+ "The ESRT table is published when the Ready To Boot event is signaled.<BR>"
diff --git a/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxeExtra.uni
new file mode 100644
index 000000000..e6ad5d689
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxeExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// EsrtFmpDxe Localized Strings and Content
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ESRT FMP DXE Driver"
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
new file mode 100644
index 000000000..484763225
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
@@ -0,0 +1,887 @@
+/** @file
+
+ These are the common Fault Tolerant Write (FTW) functions that are shared
+ by DXE FTW driver and SMM FTW driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FaultTolerantWrite.h"
+
+//
+// Fault Tolerant Write Protocol API
+//
+/**
+ Query the largest block that may be updated in a fault tolerant manner.
+
+
+ @param This The pointer to this protocol instance.
+ @param BlockSize A pointer to a caller allocated UINTN that is updated to
+ indicate the size of the largest block that can be updated.
+
+ @return EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetMaxBlockSize (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT UINTN *BlockSize
+ )
+{
+ EFI_FTW_DEVICE *FtwDevice;
+
+ if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ *BlockSize = FtwDevice->SpareAreaLength;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates space for the protocol to maintain information about writes.
+ Since writes must be completed in a fault tolerant manner and multiple
+ updates will require more resources to be successful, this function
+ enables the protocol to ensure that enough space exists to track
+ information about the upcoming writes.
+
+ All writes must be completed or aborted before another fault tolerant write can occur.
+
+ @param This The pointer to this protocol instance.
+ @param CallerId The GUID identifying the write.
+ @param PrivateDataSize The size of the caller's private data
+ that must be recorded for each write.
+ @param NumberOfWrites The number of fault tolerant block writes
+ that will need to occur.
+
+ @return EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAllocate (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_GUID *CallerId,
+ IN UINTN PrivateDataSize,
+ IN UINTN NumberOfWrites
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ EFI_FTW_DEVICE *FtwDevice;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ Status = WorkSpaceRefresh (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Check if there is enough space for the coming allocation
+ //
+ if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Find the last write header and record.
+ // If the FtwHeader is complete, skip the completed last write header/records
+ //
+ FtwHeader = FtwDevice->FtwLastWriteHeader;
+
+ //
+ // Previous write has not completed, access denied.
+ //
+ if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // If workspace is not enough, then reclaim workspace
+ //
+ Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
+ if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
+ Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ FtwHeader = FtwDevice->FtwLastWriteHeader;
+ }
+ //
+ // Prepare FTW write header,
+ // overwrite the buffer and write to workspace.
+ //
+ FtwHeader->WritesAllocated = FTW_INVALID_STATE;
+ FtwHeader->Complete = FTW_INVALID_STATE;
+ CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
+ FtwHeader->NumberOfWrites = NumberOfWrites;
+ FtwHeader->PrivateDataSize = PrivateDataSize;
+ FtwHeader->HeaderAllocated = FTW_VALID_STATE;
+
+ Status = WriteWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + Offset,
+ sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER),
+ (UINT8 *) FtwHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Update Header->WriteAllocated as VALID
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + Offset,
+ WRITES_ALLOCATED
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG (
+ (EFI_D_INFO,
+ "Ftw: Allocate() success, Caller:%g, # %d\n",
+ CallerId,
+ NumberOfWrites)
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Write a record with fault tolerant manner.
+ Since the content has already backuped in spare block, the write is
+ guaranteed to be completed with fault tolerant manner.
+
+ @param This The pointer to this protocol instance.
+ @param Fvb The FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param BlockSize The size of the block.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FtwWriteRecord (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN UINTN BlockSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_FTW_DEVICE *FtwDevice;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
+ UINTN Offset;
+ UINTN NumberOfWriteBlocks;
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ //
+ // Spare Complete but Destination not complete,
+ // Recover the target block with the spare block.
+ //
+ Header = FtwDevice->FtwLastWriteHeader;
+ Record = FtwDevice->FtwLastWriteRecord;
+
+ //
+ // IF target block is working block, THEN Flush Spare Block To Working Block;
+ // ELSE flush spare block to target block, which may be boot block after all.
+ //
+ if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
+ //
+ // If target block is working block,
+ // it also need to set SPARE_COMPLETED to spare block.
+ //
+ Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->SpareBlockSize,
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
+ FtwDevice->FtwWorkSpaceBaseInSpare + Offset,
+ SPARE_COMPLETED
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Status = FlushSpareBlockToWorkingBlock (FtwDevice);
+ } else if (IsBootBlock (FtwDevice, Fvb)) {
+ //
+ // Update boot block
+ //
+ Status = FlushSpareBlockToBootBlock (FtwDevice);
+ } else {
+ //
+ // Update blocks other than working block or boot block
+ //
+ NumberOfWriteBlocks = FTW_BLOCKS ((UINTN) (Record->Offset + Record->Length), BlockSize);
+ Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba, BlockSize, NumberOfWriteBlocks);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Record the DestionationComplete in record
+ //
+ Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + Offset,
+ DEST_COMPLETED
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Record->DestinationComplete = FTW_VALID_STATE;
+
+ //
+ // If this is the last Write in these write sequence,
+ // set the complete flag of write header.
+ //
+ if (IsLastRecordOfWrites (Header, Record)) {
+ Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + Offset,
+ WRITES_COMPLETED
+ );
+ Header->Complete = FTW_VALID_STATE;
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a target block update. This function will record data about write
+ in fault tolerant storage and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param This The pointer to this protocol instance.
+ @param Lba The logical block address of the target block.
+ @param Offset The offset within the target block to place the data.
+ @param Length The number of bytes to write to the target block.
+ @param PrivateData A pointer to private data that the caller requires to
+ complete any pending writes in the event of a fault.
+ @param FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
+ Offset + *NumBytes > SpareAreaLength.
+ @retval EFI_ACCESS_DENIED No writes have been allocated.
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
+ @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN VOID *PrivateData,
+ IN EFI_HANDLE FvBlockHandle,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FTW_DEVICE *FtwDevice;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ UINTN MyLength;
+ UINTN MyOffset;
+ UINTN MyBufferSize;
+ UINT8 *MyBuffer;
+ UINTN SpareBufferSize;
+ UINT8 *SpareBuffer;
+ UINTN Index;
+ UINT8 *Ptr;
+ EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN NumberOfWriteBlocks;
+ UINTN WriteLength;
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ Status = WorkSpaceRefresh (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Header = FtwDevice->FtwLastWriteHeader;
+ Record = FtwDevice->FtwLastWriteRecord;
+
+ if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
+ if (PrivateData == NULL) {
+ //
+ // Ftw Write Header is not allocated.
+ // No additional private data, the private data size is zero. Number of record can be set to 1.
+ //
+ Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Ftw Write Header is not allocated
+ // Additional private data is not NULL, the private data size can't be determined.
+ //
+ DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
+ DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // If Record is out of the range of Header, return access denied.
+ //
+ if (((UINTN) Record - (UINTN) Header) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check the COMPLETE flag of last write header
+ //
+ if (Header->Complete == FTW_VALID_STATE) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (Record->DestinationComplete == FTW_VALID_STATE) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Get the FVB protocol by handle
+ //
+ Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get FVB physical address - %r\n", Status));
+ return EFI_ABORTED;
+ }
+
+ //
+ // Now, one FVB has one type of BlockSize.
+ //
+ Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get block size - %r\n", Status));
+ return EFI_ABORTED;
+ }
+
+ NumberOfWriteBlocks = FTW_BLOCKS (Offset + Length, BlockSize);
+ DEBUG ((EFI_D_INFO, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize, NumberOfWriteBlocks));
+ WriteLength = NumberOfWriteBlocks * BlockSize;
+
+ //
+ // Check if the input data can fit within the spare block.
+ //
+ if (WriteLength > FtwDevice->SpareAreaLength) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // Set BootBlockUpdate FLAG if it's updating boot block.
+ //
+ if (IsBootBlock (FtwDevice, Fvb)) {
+ Record->BootBlockUpdate = FTW_VALID_STATE;
+ //
+ // Boot Block and Spare Block should have same block size and block numbers.
+ //
+ ASSERT ((BlockSize == FtwDevice->SpareBlockSize) && (NumberOfWriteBlocks == FtwDevice->NumberOfSpareBlock));
+ }
+ //
+ // Write the record to the work space.
+ //
+ Record->Lba = Lba;
+ Record->Offset = Offset;
+ Record->Length = Length;
+ Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * BlockSize) - (INT64) FtwDevice->SpareAreaAddress;
+ if (PrivateData != NULL) {
+ CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);
+ }
+
+ MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
+ MyLength = FTW_RECORD_SIZE (Header->PrivateDataSize);
+
+ Status = WriteWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + MyOffset,
+ MyLength,
+ (UINT8 *) Record
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Record has written to working block, then do the data.
+ //
+ //
+ // Allocate a memory buffer
+ //
+ MyBufferSize = WriteLength;
+ MyBuffer = AllocatePool (MyBufferSize);
+ if (MyBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read all original data from target block to memory buffer
+ //
+ Ptr = MyBuffer;
+ for (Index = 0; Index < NumberOfWriteBlocks; Index += 1) {
+ MyLength = BlockSize;
+ Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
+ if (EFI_ERROR (Status)) {
+ FreePool (MyBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += MyLength;
+ }
+ //
+ // Overwrite the updating range data with
+ // the input buffer content
+ //
+ CopyMem (MyBuffer + Offset, Buffer, Length);
+
+ //
+ // Try to keep the content of spare block
+ // Save spare block into a spare backup memory buffer (Sparebuffer)
+ //
+ SpareBufferSize = FtwDevice->SpareAreaLength;
+ SpareBuffer = AllocatePool (SpareBufferSize);
+ if (SpareBuffer == NULL) {
+ FreePool (MyBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ MyLength = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MyBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += MyLength;
+ }
+ //
+ // Write the memory buffer to spare block
+ // Do not assume Spare Block and Target Block have same block size
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (MyBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ Ptr = MyBuffer;
+ for (Index = 0; MyBufferSize > 0; Index += 1) {
+ if (MyBufferSize > FtwDevice->SpareBlockSize) {
+ MyLength = FtwDevice->SpareBlockSize;
+ } else {
+ MyLength = MyBufferSize;
+ }
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MyBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += MyLength;
+ MyBufferSize -= MyLength;
+ }
+ //
+ // Free MyBuffer
+ //
+ FreePool (MyBuffer);
+
+ //
+ // Set the SpareComplete in the FTW record,
+ //
+ MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + MyOffset,
+ SPARE_COMPLETED
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Record->SpareComplete = FTW_VALID_STATE;
+
+ //
+ // Since the content has already backuped in spare block, the write is
+ // guaranteed to be completed with fault tolerant manner.
+ //
+ Status = FtwWriteRecord (This, Fvb, BlockSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ MyLength = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += MyLength;
+ }
+ //
+ // All success.
+ //
+ FreePool (SpareBuffer);
+
+ DEBUG (
+ (EFI_D_INFO,
+ "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
+ Lba,
+ Offset,
+ Length)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Restarts a previously interrupted write. The caller must provide the
+ block protocol needed to complete the interrupted write.
+
+ @param This The pointer to this protocol instance.
+ @param FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ACCESS_DENIED No pending writes exist
+ @retval EFI_NOT_FOUND FVB protocol not found by the handle
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FtwRestart (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_HANDLE FvBlockHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FTW_DEVICE *FtwDevice;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ Status = WorkSpaceRefresh (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Header = FtwDevice->FtwLastWriteHeader;
+ Record = FtwDevice->FtwLastWriteRecord;
+
+ //
+ // Spare Complete but Destination not complete,
+ // Recover the targt block with the spare block.
+ //
+ Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Now, one FVB has one type of BlockSize
+ //
+ Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Restart(), Get block size - %r\n", Status));
+ return EFI_ABORTED;
+ }
+
+ //
+ // Check the COMPLETE flag of last write header
+ //
+ if (Header->Complete == FTW_VALID_STATE) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check the flags of last write record
+ //
+ if (Record->DestinationComplete == FTW_VALID_STATE) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if ((Record->SpareComplete != FTW_VALID_STATE)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Since the content has already backuped in spare block, the write is
+ // guaranteed to be completed with fault tolerant manner.
+ //
+ Status = FtwWriteRecord (This, Fvb, BlockSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Erase Spare block
+ // This is restart, no need to keep spareblock content.
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
+ return EFI_SUCCESS;
+}
+
+/**
+ Aborts all previous allocated writes.
+
+ @param This The pointer to this protocol instance.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAbort (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ EFI_FTW_DEVICE *FtwDevice;
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ Status = WorkSpaceRefresh (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Update the complete state of the header as VALID and abort.
+ //
+ Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + Offset,
+ WRITES_COMPLETED
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
+
+ DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a target block update. This records information about the write
+ in fault tolerant storage and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param This The pointer to this protocol instance.
+ @param CallerId The GUID identifying the last write.
+ @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 PrivateDataSize bytes from the private data
+ stored for this write.
+ @param PrivateData A pointer to a buffer. The function will copy
+ @param Complete A Boolean value with TRUE indicating
+ that the write was completed.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully
+ @retval EFI_NOT_FOUND No allocated writes exist
+ @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetLastWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT EFI_GUID *CallerId,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset,
+ OUT UINTN *Length,
+ IN OUT UINTN *PrivateDataSize,
+ OUT VOID *PrivateData,
+ OUT BOOLEAN *Complete
+ )
+{
+ EFI_STATUS Status;
+ EFI_FTW_DEVICE *FtwDevice;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
+
+ if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FtwDevice = FTW_CONTEXT_FROM_THIS (This);
+
+ Status = WorkSpaceRefresh (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Header = FtwDevice->FtwLastWriteHeader;
+ Record = FtwDevice->FtwLastWriteRecord;
+
+ //
+ // If Header is incompleted and the last record has completed, then
+ // call Abort() to set the Header->Complete FLAG.
+ //
+ if ((Header->Complete != FTW_VALID_STATE) &&
+ (Record->DestinationComplete == FTW_VALID_STATE) &&
+ IsLastRecordOfWrites (Header, Record)
+ ) {
+
+ Status = FtwAbort (This);
+ *Complete = TRUE;
+ return EFI_NOT_FOUND;
+ }
+ //
+ // If there is no write header/record, return not found.
+ //
+ if (Header->HeaderAllocated != FTW_VALID_STATE) {
+ *Complete = TRUE;
+ return EFI_NOT_FOUND;
+ }
+ //
+ // If this record SpareComplete has not set, then it can not restart.
+ //
+ if (Record->SpareComplete != FTW_VALID_STATE) {
+ Status = GetPreviousRecordOfWrites (Header, &Record);
+ if (EFI_ERROR (Status)) {
+ FtwAbort (This);
+ *Complete = TRUE;
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (Record != NULL);
+ }
+
+ //
+ // Fill all the requested values
+ //
+ CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
+ *Lba = Record->Lba;
+ *Offset = (UINTN) Record->Offset;
+ *Length = (UINTN) Record->Length;
+ *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
+
+ if (*PrivateDataSize < Header->PrivateDataSize) {
+ *PrivateDataSize = (UINTN) Header->PrivateDataSize;
+ PrivateData = NULL;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ *PrivateDataSize = (UINTN) Header->PrivateDataSize;
+ CopyMem (PrivateData, Record + 1, *PrivateDataSize);
+ Status = EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
new file mode 100644
index 000000000..fe1c9f373
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
@@ -0,0 +1,784 @@
+/** @file
+
+ The internal header file includes the common header files, defines
+ internal structure and functions used by Ftw module.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_FAULT_TOLERANT_WRITE_H_
+#define _EFI_FAULT_TOLERANT_WRITE_H_
+
+#include <PiDxe.h>
+
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/ZeroGuid.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/SwapAddressRange.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+//
+// Flash erase polarity is 1
+//
+#define FTW_ERASE_POLARITY 1
+
+#define FTW_ERASED_BYTE ((UINT8) (255))
+#define FTW_POLARITY_REVERT ((UINT8) (255))
+
+#define HEADER_ALLOCATED 0x1
+#define WRITES_ALLOCATED 0x2
+#define WRITES_COMPLETED 0x4
+
+#define BOOT_BLOCK_UPDATE 0x1
+#define SPARE_COMPLETED 0x2
+#define DEST_COMPLETED 0x4
+
+#define FTW_BLOCKS(Length, BlockSize) ((UINTN) ((Length) / (BlockSize) + (((Length) & ((BlockSize) - 1)) ? 1 : 0)))
+
+#define FTW_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'T', 'W', 'D')
+
+//
+// EFI Fault tolerant protocol private data structure
+//
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL FtwInstance;
+ EFI_PHYSICAL_ADDRESS WorkSpaceAddress; // Base address of working space range in flash.
+ EFI_PHYSICAL_ADDRESS SpareAreaAddress; // Base address of spare range in flash.
+ UINTN WorkSpaceLength; // Size of working space range in flash.
+ UINTN NumberOfWorkSpaceBlock; // Number of the blocks in work block for work space.
+ UINTN WorkBlockSize; // Block size in bytes of the work blocks in flash
+ UINTN SpareAreaLength; // Size of spare range in flash.
+ UINTN NumberOfSpareBlock; // Number of the blocks in spare block.
+ UINTN SpareBlockSize; // Block size in bytes of the spare blocks in flash
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader;// Pointer to Working Space Header in memory buffer
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader;// Pointer to last record header in memory buffer
+ EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord;// Pointer to last record in memory buffer
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwFvBlock; // FVB of working block
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwBackupFvb; // FVB of spare block
+ EFI_LBA FtwSpareLba; // Start LBA of spare block
+ EFI_LBA FtwWorkBlockLba; // Start LBA of working block that contains working space in its last block.
+ UINTN NumberOfWorkBlock; // Number of the blocks in work block.
+ EFI_LBA FtwWorkSpaceLba; // Start LBA of working space
+ UINTN FtwWorkSpaceBase; // Offset into the FtwWorkSpaceLba block.
+ UINTN FtwWorkSpaceSize; // Size of working space range that stores write record.
+ EFI_LBA FtwWorkSpaceLbaInSpare; // Start LBA of working space in spare block.
+ UINTN FtwWorkSpaceBaseInSpare;// Offset into the FtwWorkSpaceLbaInSpare block.
+ UINT8 *FtwWorkSpace; // Point to Work Space in memory buffer
+ //
+ // Following a buffer of FtwWorkSpace[FTW_WORK_SPACE_SIZE],
+ // Allocated with EFI_FTW_DEVICE.
+ //
+} EFI_FTW_DEVICE;
+
+#define FTW_CONTEXT_FROM_THIS(a) CR (a, EFI_FTW_DEVICE, FtwInstance, FTW_DEVICE_SIGNATURE)
+
+//
+// Driver entry point
+//
+/**
+ This function is the entry point of the Fault Tolerant Write driver.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @return EFI_SUCCESS FTW has finished the initialization
+ @retval EFI_NOT_FOUND Locate FVB protocol error
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_VOLUME_CORRUPTED Firmware volume is error
+ @retval EFI_ABORTED FTW initialization error
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeFaultTolerantWrite (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+//
+// Fault Tolerant Write Protocol API
+//
+
+/**
+ Query the largest block that may be updated in a fault tolerant manner.
+
+
+ @param This Indicates a pointer to the calling context.
+ @param BlockSize A pointer to a caller allocated UINTN that is updated to
+ indicate the size of the largest block that can be updated.
+
+ @return EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetMaxBlockSize (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT UINTN *BlockSize
+ );
+
+/**
+ Allocates space for the protocol to maintain information about writes.
+ Since writes must be completed in a fault tolerant manner and multiple
+ updates will require more resources to be successful, this function
+ enables the protocol to ensure that enough space exists to track
+ information about the upcoming writes.
+
+ All writes must be completed or aborted before another fault tolerant write can occur.
+
+ @param This Indicates a pointer to the calling context.
+ @param CallerId The GUID identifying the write.
+ @param PrivateDataSize The size of the caller's private data
+ that must be recorded for each write.
+ @param NumberOfWrites The number of fault tolerant block writes
+ that will need to occur.
+
+ @return EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAllocate (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_GUID *CallerId,
+ IN UINTN PrivateDataSize,
+ IN UINTN NumberOfWrites
+ );
+
+/**
+ Starts a target block update. This function will record data about write
+ in fault tolerant storage and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+
+ @param This Calling context
+ @param Lba The logical block address of the target block.
+ @param Offset The offset within the target block to place the data.
+ @param Length The number of bytes to write to the target block.
+ @param PrivateData A pointer to private data that the caller requires to
+ complete any pending writes in the event of a fault.
+ @param FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
+ Offset + *NumBytes > SpareAreaLength.
+ @retval EFI_ACCESS_DENIED No writes have been allocated.
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
+ @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN VOID *PrivateData,
+ IN EFI_HANDLE FvBlockHandle,
+ IN VOID *Buffer
+ );
+
+/**
+ Restarts a previously interrupted write. The caller must provide the
+ block protocol needed to complete the interrupted write.
+
+ @param This Calling context.
+ @param FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ACCESS_DENIED No pending writes exist
+ @retval EFI_NOT_FOUND FVB protocol not found by the handle
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FtwRestart (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_HANDLE FvBlockHandle
+ );
+
+/**
+ Aborts all previous allocated writes.
+
+ @param This Calling context
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAbort (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
+ );
+
+/**
+ Starts a target block update. This records information about the write
+ in fault tolerant storage and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param This Indicates a pointer to the calling context.
+ @param CallerId The GUID identifying the last write.
+ @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 PrivateDataSize bytes from the private data
+ stored for this write.
+ @param PrivateData A pointer to a buffer. The function will copy
+ @param Complete A Boolean value with TRUE indicating
+ that the write was completed.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully
+ @retval EFI_NOT_FOUND No allocated writes exist
+ @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetLastWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT EFI_GUID *CallerId,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset,
+ OUT UINTN *Length,
+ IN OUT UINTN *PrivateDataSize,
+ OUT VOID *PrivateData,
+ OUT BOOLEAN *Complete
+ );
+
+/**
+ Erase spare block.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+
+**/
+EFI_STATUS
+FtwEraseSpareBlock (
+ IN EFI_FTW_DEVICE *FtwDevice
+ );
+
+/**
+ Retrieve the proper FVB protocol interface by HANDLE.
+
+
+ @param FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param FvBlock The interface of FVB protocol
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FtwGetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ );
+
+/**
+
+ Is it in working block?
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock Fvb protocol instance
+ @param Lba The block specified
+
+ @return A BOOLEAN value indicating in working block or not.
+
+**/
+BOOLEAN
+IsWorkingBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ EFI_LBA Lba
+ );
+
+/**
+
+ Is it in boot block?
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock Fvb protocol instance
+
+ @return A BOOLEAN value indicating in boot block or not.
+
+**/
+BOOLEAN
+IsBootBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock
+ );
+
+/**
+ Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
+ Spare block is accessed by FTW backup FVB protocol interface.
+ Target block is accessed by FvBlock protocol interface.
+
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock FVB Protocol interface to access target block
+ @param Lba Lba of the target block
+ @param BlockSize The size of the block
+ @param NumberOfBlocks The number of consecutive blocks starting with Lba
+
+ @retval EFI_SUCCESS Spare block content is copied to target block
+ @retval EFI_INVALID_PARAMETER Input parameter error
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToTargetBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ EFI_LBA Lba,
+ UINTN BlockSize,
+ UINTN NumberOfBlocks
+ );
+
+/**
+ Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
+ Spare block is accessed by FTW backup FVB protocol interface. LBA is
+ FtwDevice->FtwSpareLba.
+ Working block is accessed by FTW working FVB protocol interface. LBA is
+ FtwDevice->FtwWorkBlockLba.
+
+ Since the working block header is important when FTW initializes, the
+ state of the operation should be handled carefully. The Crc value is
+ calculated without STATE element.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS Spare block content is copied to target block
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToWorkingBlock (
+ EFI_FTW_DEVICE *FtwDevice
+ );
+
+/**
+ Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
+ Spare block is accessed by FTW working FVB protocol interface.
+ Target block is accessed by FvBlock protocol interface.
+
+ FTW will do extra work on boot block update.
+ FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
+ which is produced by a chipset driver.
+ FTW updating boot block steps may be:
+ 1. GetRangeLocation(), if the Range is inside the boot block, FTW know
+ that boot block will be update. It shall add a FLAG in the working block.
+ 2. When spare block is ready,
+ 3. SetSwapState(SWAPPED)
+ 4. erasing boot block,
+ 5. programming boot block until the boot block is ok.
+ 6. SetSwapState(UNSWAPPED)
+ FTW shall not allow to update boot block when battery state is error.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS Spare block content is copied to boot block
+ @retval EFI_INVALID_PARAMETER Input parameter error
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToBootBlock (
+ EFI_FTW_DEVICE *FtwDevice
+ );
+
+/**
+ Update a bit of state on a block device. The location of the bit is
+ calculated by the (Lba, Offset, bit). Here bit is determined by the
+ the name of a certain bit.
+
+
+ @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
+ @param BlockSize The size of the block
+ @param Lba Lba of a block
+ @param Offset Offset on the Lba
+ @param NewBit New value that will override the old value if it can be change
+
+ @retval EFI_SUCCESS A state bit has been updated successfully
+ @retval Others Access block device error.
+ Notes:
+ Assume all bits of State are inside the same BYTE.
+ @retval EFI_ABORTED Read block fail
+
+**/
+EFI_STATUS
+FtwUpdateFvState (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINT8 NewBit
+ );
+
+/**
+ Get the last Write Header pointer.
+ The last write header is the header whose 'complete' state hasn't been set.
+ After all, this header may be a EMPTY header entry for next Allocate.
+
+
+ @param FtwWorkSpaceHeader Pointer of the working block header
+ @param FtwWorkSpaceSize Size of the work space
+ @param FtwWriteHeader Pointer to retrieve the last write header
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
+ IN UINTN FtwWorkSpaceSize,
+ OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
+ );
+
+/**
+ Get the last Write Record pointer. The last write Record is the Record
+ whose DestinationCompleted state hasn't been set. After all, this Record
+ may be a EMPTY record entry for next write.
+
+
+ @param FtwWriteHeader Pointer to the write record header
+ @param FtwWriteRecord Pointer to retrieve the last write record
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteRecord (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
+ OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
+ );
+
+/**
+ To check if FtwRecord is the first record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to the write record
+
+ @retval TRUE FtwRecord is the first Record of the FtwHeader
+ @retval FALSE FtwRecord is not the first Record of the FtwHeader
+
+**/
+BOOLEAN
+IsFirstRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
+ );
+
+/**
+ To check if FtwRecord is the last record of FtwHeader. Because the
+ FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be
+ determined if it is the last record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to the write record
+
+ @retval TRUE FtwRecord is the last Record of the FtwHeader
+ @retval FALSE FtwRecord is not the last Record of the FtwHeader
+
+**/
+BOOLEAN
+IsLastRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
+ );
+
+/**
+ To check if FtwRecord is the first record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to retrieve the previous write record
+
+ @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.
+ @retval EFI_SUCCESS The previous write record is found.
+
+**/
+EFI_STATUS
+GetPreviousRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord
+ );
+
+/**
+
+ Check whether a flash buffer is erased.
+
+ @param Buffer Buffer to check
+ @param BufferSize Size of the buffer
+
+ @return A BOOLEAN value indicating erased or not.
+
+**/
+BOOLEAN
+IsErasedFlashBuffer (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ );
+/**
+ Initialize a work space when there is no work space.
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+InitWorkSpaceHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ );
+/**
+ Read from working block to refresh the work space in memory.
+
+ @param FtwDevice Point to private data of FTW driver
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WorkSpaceRefresh (
+ IN EFI_FTW_DEVICE *FtwDevice
+ );
+/**
+ Check to see if it is a valid work space.
+
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+BOOLEAN
+IsValidWorkSpace (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ );
+/**
+ Reclaim the work space on the working block.
+
+ @param FtwDevice Point to private data of FTW driver
+ @param PreserveRecord Whether to preserve the working record is needed
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FtwReclaimWorkSpace (
+ IN EFI_FTW_DEVICE *FtwDevice,
+ IN BOOLEAN PreserveRecord
+ );
+
+/**
+
+ Get firmware volume block by address.
+
+
+ @param Address Address specified the block
+ @param FvBlock The block caller wanted
+
+ @retval EFI_SUCCESS The protocol instance if found.
+ @retval EFI_NOT_FOUND Block not found
+
+**/
+EFI_HANDLE
+GetFvbByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ );
+
+/**
+ Retrieve the proper Swap Address Range protocol interface.
+
+ @param[out] SarProtocol The interface of SAR protocol
+
+ @retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol.
+ @retval EFI_NOT_FOUND The SAR protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+FtwGetSarProtocol (
+ OUT VOID **SarProtocol
+ );
+
+/**
+ Function returns an array of handles that support the FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+
+/**
+ Allocate private data for FTW driver and initialize it.
+
+ @param[out] FtwData Pointer to the FTW device structure
+
+ @retval EFI_SUCCESS Initialize the FTW device successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+InitFtwDevice (
+ OUT EFI_FTW_DEVICE **FtwData
+ );
+
+
+/**
+ Initialization for Fault Tolerant Write is done in this handler.
+
+ @param[in, out] FtwDevice Pointer to the FTW device structure
+
+ @retval EFI_SUCCESS Initialize the FTW protocol successfully.
+ @retval EFI_NOT_FOUND No proper FVB protocol was found.
+
+**/
+EFI_STATUS
+InitFtwProtocol (
+ IN OUT EFI_FTW_DEVICE *FtwDevice
+ );
+
+/**
+ Initialize a local work space header.
+
+ Since Signature and WriteQueueSize have been known, Crc can be calculated out,
+ then the work space header will be fixed.
+**/
+VOID
+InitializeLocalWorkSpaceHeader (
+ VOID
+ );
+
+/**
+ Read work space data from work block or spare block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block.
+ @param Length The number of bytes to read from the block.
+ @param Buffer The data is read.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+ReadWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Write data to work block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block to place the data.
+ @param Length The number of bytes to write to the block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WriteWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Internal implementation of CRC32. Depending on the execution context
+ (traditional SMM or DXE vs standalone MM), this function is implemented
+ via a call to the CalculateCrc32 () boot service, or via a library
+ call.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param[in] Buffer A pointer to the buffer on which the 32-bit CRC is
+ to be computed.
+ @param[in] Length The number of bytes in the buffer Data.
+
+ @retval Crc32 The 32-bit CRC was computed for the data buffer.
+
+**/
+UINT32
+FtwCalculateCrc32 (
+ IN VOID *Buffer,
+ IN UINTN Length
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c
new file mode 100644
index 000000000..de38ea028
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c
@@ -0,0 +1,277 @@
+/** @file
+
+ This is a simple fault tolerant write driver.
+
+ This boot service protocol only provides fault tolerant write capability for
+ block devices. The protocol has internal non-volatile intermediate storage
+ of the data and private information. It should be able to recover
+ automatically from a critical fault, such as power failure.
+
+ The implementation uses an FTW (Fault Tolerant Write) Work Space.
+ This work space is a memory copy of the work space on the Working Block,
+ the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
+
+ The work space stores each write record as EFI_FTW_RECORD structure.
+ The spare block stores the write buffer before write to the target block.
+
+ The write record has three states to specify the different phase of write operation.
+ 1) WRITE_ALLOCATED is that the record is allocated in write space.
+ The information of write operation is stored in write record structure.
+ 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
+ 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
+
+ This driver operates the data as the whole size of spare block.
+ It first read the SpareAreaLength data from the target block into the spare memory buffer.
+ Then copy the write buffer data into the spare memory buffer.
+ Then write the spare memory buffer into the spare block.
+ Final copy the data from the spare block to the target block.
+
+ To make this drive work well, the following conditions must be satisfied:
+ 1. The write NumBytes data must be fit within Spare area.
+ Offset + NumBytes <= SpareAreaLength
+ 2. The whole flash range has the same block size.
+ 3. Working block is an area which contains working space in its last block and has the same size as spare block.
+ 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 6. Any write data area (SpareAreaLength Area) which the data will be written into must be
+ in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
+ The spare area must be enough large to store the write data before write them into the target range.
+ If one of them is not satisfied, FtwWrite may fail.
+ Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include "FaultTolerantWrite.h"
+VOID *mFvbRegistration = NULL;
+
+
+/**
+ Retrieve the FVB protocol interface by HANDLE.
+
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param[out] FvBlock The interface of FVB protocol
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the FVB protocol.
+ @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+FtwGetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ )
+{
+ //
+ // To get the FVB protocol interface on the handle
+ //
+ return gBS->HandleProtocol (
+ FvBlockHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) FvBlock
+ );
+}
+
+/**
+ Retrieve the Swap Address Range protocol interface.
+
+ @param[out] SarProtocol The interface of SAR protocol
+
+ @retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol.
+ @retval EFI_NOT_FOUND The SAR protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+FtwGetSarProtocol (
+ OUT VOID **SarProtocol
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Swap Address Range protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSwapAddressRangeProtocolGuid,
+ NULL,
+ SarProtocol
+ );
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate all handles of Fvb protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ NumberHandles,
+ Buffer
+ );
+ return Status;
+}
+
+
+/**
+ Firmware Volume Block Protocol notification event handler.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+FvbNotificationEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ EFI_FTW_DEVICE *FtwDevice;
+
+ //
+ // Just return to avoid installing FaultTolerantWriteProtocol again
+ // if Fault Tolerant Write protocol has been installed.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ NULL,
+ (VOID **) &FtwProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Found proper FVB protocol and initialize FtwDevice for protocol installation
+ //
+ FtwDevice = (EFI_FTW_DEVICE *)Context;
+ Status = InitFtwProtocol (FtwDevice);
+ if (EFI_ERROR(Status)) {
+ return ;
+ }
+
+ //
+ // Install protocol interface
+ //
+ Status = gBS->InstallProtocolInterface (
+ &FtwDevice->Handle,
+ &gEfiFaultTolerantWriteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FtwDevice->FtwInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseEvent (Event);
+ ASSERT_EFI_ERROR (Status);
+
+ return;
+}
+
+
+/**
+ This function is the entry point of the Fault Tolerant Write driver.
+
+ @param[in] ImageHandle A handle for the image that is initializing this driver
+ @param[in] SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS The initialization finished successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+EFIAPI
+FaultTolerantWriteInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_FTW_DEVICE *FtwDevice;
+
+ FtwDevice = NULL;
+
+ //
+ // Allocate private data structure for FTW protocol and do some initialization
+ //
+ Status = InitFtwDevice (&FtwDevice);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Register FvbNotificationEvent () notify function.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ TPL_CALLBACK,
+ FvbNotificationEvent,
+ (VOID *)FtwDevice,
+ &mFvbRegistration
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal implementation of CRC32. Depending on the execution context
+ (traditional SMM or DXE vs standalone MM), this function is implemented
+ via a call to the CalculateCrc32 () boot service, or via a library
+ call.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param[in] Buffer A pointer to the buffer on which the 32-bit CRC is to be computed.
+ @param[in] Length The number of bytes in the buffer Data.
+
+ @retval Crc32 The 32-bit CRC was computed for the data buffer.
+
+**/
+UINT32
+FtwCalculateCrc32 (
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ReturnValue;
+
+ Status = gBS->CalculateCrc32 (Buffer, Length, &ReturnValue);
+ ASSERT_EFI_ERROR (Status);
+
+ return ReturnValue;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
new file mode 100644
index 000000000..96165614d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
@@ -0,0 +1,86 @@
+## @file
+# Fault Tolerant Write Dxe Driver.
+#
+# This driver installs Fault Tolerant Write (FTW) protocol,
+# which provides fault tolerant write capability for block devices.
+# Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FaultTolerantWriteDxe
+ MODULE_UNI_FILE = FaultTolerantWriteDxe.uni
+ FILE_GUID = FE5CEA76-4F72-49e8-986F-2CD899DFFE5D
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FaultTolerantWriteInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FtwMisc.c
+ UpdateWorkingBlock.c
+ FaultTolerantWrite.c
+ FaultTolerantWriteDxe.c
+ FaultTolerantWrite.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+ UefiLib
+ PcdLib
+ ReportStatusCodeLib
+
+[Guids]
+ #
+ # Signature in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
+ #
+ ## CONSUMES ## GUID
+ ## PRODUCES ## GUID
+ gEdkiiWorkingBlockSignatureGuid
+
+[Protocols]
+ gEfiSwapAddressRangeProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid
+ gEfiFaultTolerantWriteProtocolGuid ## PRODUCES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES
+
+#
+# gBS->CalculateCrc32() is consumed in EntryPoint.
+# PI spec said: When the DXE Foundation is notified that the EFI_RUNTIME_ARCH_PROTOCOL
+# has been installed, then the Boot Service CalculateCrc32() is available.
+# So add gEfiRuntimeArchProtocolGuid Depex here.
+#
+[Depex]
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiRuntimeArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FaultTolerantWriteDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.uni
new file mode 100644
index 000000000..274313558
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Fault Tolerant Write Dxe Driver.
+//
+// This driver installs Fault Tolerant Write (FTW) protocol,
+// which provides fault tolerant write capability for block devices.
+// Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Fault Tolerant Write Dxe Driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Installs Fault Tolerant Write (FTW) protocol, which provides fault tolerant write capability for block devices. Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxeExtra.uni
new file mode 100644
index 000000000..b05a88df0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FaultTolerantWriteDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Fault Tolerant Flash Write DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c
new file mode 100644
index 000000000..9612b3948
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c
@@ -0,0 +1,636 @@
+/** @file
+
+ This is a simple fault tolerant write driver that is intended to use in the SMM environment.
+
+ This boot service protocol only provides fault tolerant write capability for
+ block devices. The protocol has internal non-volatile intermediate storage
+ of the data and private information. It should be able to recover
+ automatically from a critical fault, such as power failure.
+
+ The implementation uses an FTW (Fault Tolerant Write) Work Space.
+ This work space is a memory copy of the work space on the Working Block,
+ the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
+
+ The work space stores each write record as EFI_FTW_RECORD structure.
+ The spare block stores the write buffer before write to the target block.
+
+ The write record has three states to specify the different phase of write operation.
+ 1) WRITE_ALLOCATED is that the record is allocated in write space.
+ The information of write operation is stored in write record structure.
+ 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
+ 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
+
+ This driver operates the data as the whole size of spare block.
+ It first read the SpareAreaLength data from the target block into the spare memory buffer.
+ Then copy the write buffer data into the spare memory buffer.
+ Then write the spare memory buffer into the spare block.
+ Final copy the data from the spare block to the target block.
+
+ To make this drive work well, the following conditions must be satisfied:
+ 1. The write NumBytes data must be fit within Spare area.
+ Offset + NumBytes <= SpareAreaLength
+ 2. The whole flash range has the same block size.
+ 3. Working block is an area which contains working space in its last block and has the same size as spare block.
+ 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 6. Any write data area (SpareAreaLength Area) which the data will be written into must be
+ in the single one Firmware Volume Block range which FVB protocol is produced on.
+ 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
+ The spare area must be enough large to store the write data before write them into the target range.
+ If one of them is not satisfied, FtwWrite may fail.
+ Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
+
+ Caution: This module requires additional review when modified.
+ This driver need to make sure the CommBuffer is not in the SMRAM range.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/MmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Protocol/SmmSwapAddressRange.h>
+#include "FaultTolerantWrite.h"
+#include "FaultTolerantWriteSmmCommon.h"
+#include <Protocol/MmEndOfDxe.h>
+
+VOID *mFvbRegistration = NULL;
+EFI_FTW_DEVICE *mFtwDevice = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+/**
+ Retrieve the SMM FVB protocol interface by HANDLE.
+
+ @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param[out] FvBlock The interface of SMM FVB protocol
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
+ @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+FtwGetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ )
+{
+ //
+ // To get the SMM FVB protocol interface on the handle
+ //
+ return gMmst->MmHandleProtocol (
+ FvBlockHandle,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ (VOID **) FvBlock
+ );
+}
+
+/**
+ Retrieve the SMM Swap Address Range protocol interface.
+
+ @param[out] SarProtocol The interface of SMM SAR protocol
+
+ @retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol.
+ @retval EFI_NOT_FOUND The SMM SAR protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+FtwGetSarProtocol (
+ OUT VOID **SarProtocol
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Smm Swap Address Range protocol
+ //
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSmmSwapAddressRangeProtocolGuid,
+ NULL,
+ SarProtocol
+ );
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the SMM FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support SMM FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No SMM FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if ((NumberHandles == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = gMmst->MmLocateHandle (
+ ByProtocol,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &BufferSize,
+ *Buffer
+ );
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gMmst->MmLocateHandle (
+ ByProtocol,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR(Status)) {
+ *NumberHandles = 0;
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the handle of the SMM FVB protocol by the FVB base address and attributes.
+
+ @param[in] Address The base address of SMM FVB protocol.
+ @param[in] Attributes The attributes of the SMM FVB protocol.
+ @param[out] SmmFvbHandle The handle of the SMM FVB protocol.
+
+ @retval EFI_SUCCESS The FVB handle is found.
+ @retval EFI_ABORTED The FVB protocol is not found.
+
+**/
+EFI_STATUS
+GetFvbByAddressAndAttribute (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN EFI_FVB_ATTRIBUTES_2 Attributes,
+ OUT EFI_HANDLE *SmmFvbHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+
+ HandleBuffer = NULL;
+
+ //
+ // Locate all handles of SMM Fvb protocol.
+ //
+ Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Find the proper SMM Fvb handle by the address and attributes.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Compare the address.
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (Address != FvbBaseAddress) {
+ continue;
+ }
+
+ //
+ // Compare the attribute.
+ //
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (Attributes != FvbAttributes) {
+ continue;
+ }
+
+ //
+ // Found the proper FVB handle.
+ //
+ *SmmFvbHandle = HandleBuffer[Index];
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_ABORTED;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the fault tolerant write wrapper driver.
+
+ Caution: This function requires additional review when modified.
+ This driver need to make sure the CommBuffer is not in the SMRAM range.
+ Also in FTW_FUNCTION_GET_LAST_WRITE case, check SmmFtwGetLastWriteHeader->Data +
+ SmmFtwGetLastWriteHeader->PrivateDataSize within communication buffer.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will be conveyed
+ from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFaultTolerantWriteHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_FTW_COMMUNICATE_FUNCTION_HEADER *SmmFtwFunctionHeader;
+ SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *SmmGetMaxBlockSizeHeader;
+ SMM_FTW_ALLOCATE_HEADER *SmmFtwAllocateHeader;
+ SMM_FTW_WRITE_HEADER *SmmFtwWriteHeader;
+ SMM_FTW_RESTART_HEADER *SmmFtwRestartHeader;
+ SMM_FTW_GET_LAST_WRITE_HEADER *SmmFtwGetLastWriteHeader;
+ VOID *PrivateData;
+ EFI_HANDLE SmmFvbHandle;
+ UINTN InfoSize;
+ UINTN CommBufferPayloadSize;
+ UINTN PrivateDataSize;
+ UINTN Length;
+ UINTN TempCommBufferSize;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {
+ DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;
+
+ if (!FtwSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer;
+
+ if (mEndOfDxe) {
+ //
+ // It will be not safe to expose the operations after End Of Dxe.
+ //
+ DEBUG ((EFI_D_ERROR, "SmmFtwHandler: Not safe to do the operation: %x after End Of Dxe, so access denied!\n", SmmFtwFunctionHeader->Function));
+ SmmFtwFunctionHeader->ReturnStatus = EFI_ACCESS_DENIED;
+ return EFI_SUCCESS;
+ }
+
+ switch (SmmFtwFunctionHeader->Function) {
+ case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:
+ if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;
+
+ Status = FtwGetMaxBlockSize (
+ &mFtwDevice->FtwInstance,
+ &SmmGetMaxBlockSizeHeader->BlockSize
+ );
+ break;
+
+ case FTW_FUNCTION_ALLOCATE:
+ if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Allocate: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data;
+ Status = FtwAllocate (
+ &mFtwDevice->FtwInstance,
+ &SmmFtwAllocateHeader->CallerId,
+ SmmFtwAllocateHeader->PrivateDataSize,
+ SmmFtwAllocateHeader->NumberOfWrites
+ );
+ break;
+
+ case FTW_FUNCTION_WRITE:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) {
+ DEBUG ((EFI_D_ERROR, "Write: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
+ Length = SmmFtwWriteHeader->Length;
+ PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize;
+ if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) ||
+ ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length)) {
+ //
+ // Prevent InfoSize overflow
+ //
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+ InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "Write: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ if (PrivateDataSize == 0) {
+ PrivateData = NULL;
+ } else {
+ PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length];
+ }
+ Status = GetFvbByAddressAndAttribute (
+ SmmFtwWriteHeader->FvbBaseAddress,
+ SmmFtwWriteHeader->FvbAttributes,
+ &SmmFvbHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The SpeculationBarrier() call here is to ensure the previous
+ // range/content checks for the CommBuffer have been completed before
+ // calling into FtwWrite().
+ //
+ SpeculationBarrier ();
+ Status = FtwWrite(
+ &mFtwDevice->FtwInstance,
+ SmmFtwWriteHeader->Lba,
+ SmmFtwWriteHeader->Offset,
+ Length,
+ PrivateData,
+ SmmFvbHandle,
+ SmmFtwWriteHeader->Data
+ );
+ }
+ break;
+
+ case FTW_FUNCTION_RESTART:
+ if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Restart: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data;
+ Status = GetFvbByAddressAndAttribute (
+ SmmFtwRestartHeader->FvbBaseAddress,
+ SmmFtwRestartHeader->FvbAttributes,
+ &SmmFvbHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FtwRestart (&mFtwDevice->FtwInstance, SmmFvbHandle);
+ }
+ break;
+
+ case FTW_FUNCTION_ABORT:
+ Status = FtwAbort (&mFtwDevice->FtwInstance);
+ break;
+
+ case FTW_FUNCTION_GET_LAST_WRITE:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {
+ DEBUG ((EFI_D_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
+ PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
+ if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){
+ //
+ // Prevent InfoSize overflow
+ //
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+ InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ Status = FtwGetLastWrite (
+ &mFtwDevice->FtwInstance,
+ &SmmFtwGetLastWriteHeader->CallerId,
+ &SmmFtwGetLastWriteHeader->Lba,
+ &SmmFtwGetLastWriteHeader->Offset,
+ &SmmFtwGetLastWriteHeader->Length,
+ &PrivateDataSize,
+ (VOID *)SmmFtwGetLastWriteHeader->Data,
+ &SmmFtwGetLastWriteHeader->Complete
+ );
+ SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+ SmmFtwFunctionHeader->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ SMM Firmware Volume Block Protocol notification event handler.
+
+ @param[in] Protocol Points to the protocol's unique identifier
+ @param[in] Interface Points to the interface instance
+ @param[in] Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEventCallback runs successfully
+
+ **/
+EFI_STATUS
+EFIAPI
+FvbNotificationEvent (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ EFI_HANDLE SmmFtwHandle;
+
+ //
+ // Just return to avoid install SMM FaultTolerantWriteProtocol again
+ // if SMM Fault Tolerant Write protocol had been installed.
+ //
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ NULL,
+ (VOID **) &FtwProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Found proper FVB protocol and initialize FtwDevice for protocol installation
+ //
+ Status = InitFtwProtocol (mFtwDevice);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Install protocol interface
+ //
+ Status = gMmst->MmInstallProtocolInterface (
+ &mFtwDevice->Handle,
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mFtwDevice->FtwInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Register SMM FTW SMI handler
+ ///
+ Status = gMmst->MmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Notify the Ftw wrapper driver SMM Ftw is ready
+ //
+ FtwNotifySmmReady ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SMM END_OF_DXE protocol notification event handler.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+MmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ mEndOfDxe = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Shared entry point of the module
+
+ @retval EFI_SUCCESS The initialization finished successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+**/
+EFI_STATUS
+MmFaultTolerantWriteInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *MmEndOfDxeRegistration;
+
+ //
+ // Allocate private data structure for SMM FTW protocol and do some initialization
+ //
+ Status = InitFtwDevice (&mFtwDevice);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gMmst->MmRegisterProtocolNotify (
+ &gEfiMmEndOfDxeProtocolGuid,
+ MmEndOfDxeCallback,
+ &MmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register FvbNotificationEvent () notify function.
+ //
+ Status = gMmst->MmRegisterProtocolNotify (
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ FvbNotificationEvent,
+ &mFvbRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FvbNotificationEvent (NULL, NULL, NULL);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
new file mode 100644
index 000000000..8cc602847
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
@@ -0,0 +1,95 @@
+## @file
+# Fault Tolerant Write Smm Driver.
+#
+# This driver installs SMM Fault Tolerant Write (FTW) protocol, which provides fault
+# tolerant write capability in SMM environment for block devices. Its implementation
+# depends on the full functionality SMM FVB protocol that support read, write/erase
+# flash access.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmFaultTolerantWriteDxe
+ MODULE_UNI_FILE = SmmFaultTolerantWriteDxe.uni
+ FILE_GUID = 470CB248-E8AC-473c-BB4F-81069A1FE6FD
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SmmFaultTolerantWriteInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FtwMisc.c
+ UpdateWorkingBlock.c
+ FaultTolerantWrite.c
+ FaultTolerantWriteTraditionalMm.c
+ FaultTolerantWriteSmm.c
+ FaultTolerantWrite.h
+ FaultTolerantWriteSmmCommon.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MmServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+ UefiLib
+ PcdLib
+ ReportStatusCodeLib
+ SmmMemLib
+ BaseLib
+
+[Guids]
+ #
+ # Signature in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
+ #
+ ## CONSUMES ## GUID
+ ## PRODUCES ## GUID
+ gEdkiiWorkingBlockSignatureGuid
+
+[Protocols]
+ gEfiSmmSwapAddressRangeProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## CONSUMES
+ gEfiSmmFirmwareVolumeBlockProtocolGuid
+ ## PRODUCES
+ ## UNDEFINED # SmiHandlerRegister
+ gEfiSmmFaultTolerantWriteProtocolGuid
+ gEfiMmEndOfDxeProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES
+
+#
+# gBS->CalculateCrc32() is consumed in EntryPoint.
+# PI spec said: When the DXE Foundation is notified that the EFI_RUNTIME_ARCH_PROTOCOL
+# has been installed, then the Boot Service CalculateCrc32() is available.
+# So add gEfiRuntimeArchProtocolGuid Depex here.
+#
+[Depex]
+ gEfiSmmFirmwareVolumeBlockProtocolGuid AND gEfiRuntimeArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmmFaultTolerantWriteDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmCommon.h b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmCommon.h
new file mode 100644
index 000000000..5f0eec050
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmCommon.h
@@ -0,0 +1,113 @@
+/** @file
+
+ The common header file for SMM FTW module and SMM FTW DXE Module.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_FTW_COMMON_H__
+#define __SMM_FTW_COMMON_H__
+
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Protocol/SmmFaultTolerantWrite.h>
+
+#define FTW_FUNCTION_GET_MAX_BLOCK_SIZE 1
+#define FTW_FUNCTION_ALLOCATE 2
+#define FTW_FUNCTION_WRITE 3
+#define FTW_FUNCTION_RESTART 4
+#define FTW_FUNCTION_ABORT 5
+#define FTW_FUNCTION_GET_LAST_WRITE 6
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINT8 Data[1];
+} SMM_FTW_COMMUNICATE_FUNCTION_HEADER;
+
+///
+/// Size of SMM communicate header, without including the payload.
+///
+#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data))
+
+///
+/// Size of SMM FTW communicate function header, without including the payload.
+///
+#define SMM_FTW_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_FTW_COMMUNICATE_FUNCTION_HEADER, Data))
+
+typedef struct {
+ UINTN BlockSize;
+} SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER;
+
+typedef struct {
+ EFI_GUID CallerId;
+ UINTN PrivateDataSize;
+ UINTN NumberOfWrites;
+} SMM_FTW_ALLOCATE_HEADER;
+
+typedef struct {
+ EFI_LBA Lba;
+ UINTN Offset;
+ UINTN PrivateDataSize;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN Length;
+ UINT8 Data[1];
+} SMM_FTW_WRITE_HEADER;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+} SMM_FTW_RESTART_HEADER;
+
+typedef struct {
+ EFI_GUID CallerId;
+ EFI_LBA Lba;
+ UINTN Offset;
+ UINTN Length;
+ UINTN PrivateDataSize;
+ BOOLEAN Complete;
+ UINT8 Data[1];
+} SMM_FTW_GET_LAST_WRITE_HEADER;
+
+/**
+ Shared entry point of the module.
+
+ @retval EFI_SUCCESS The initialization finished successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+MmFaultTolerantWriteInitialize (
+ VOID
+ );
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+FtwSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ );
+
+/**
+ Notify the system that the SMM FTW driver is ready.
+**/
+VOID
+FtwNotifySmmReady (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.c
new file mode 100644
index 000000000..24c209502
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.c
@@ -0,0 +1,559 @@
+/** @file
+
+ Implement the Fault Tolerant Write (FTW) protocol based on SMM FTW
+ module.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FaultTolerantWriteSmmDxe.h"
+
+EFI_HANDLE mHandle = NULL;
+EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 = NULL;
+UINTN mPrivateDataSize = 0;
+
+EFI_FAULT_TOLERANT_WRITE_PROTOCOL mFaultTolerantWriteDriver = {
+ FtwGetMaxBlockSize,
+ FtwAllocate,
+ FtwWrite,
+ FtwRestart,
+ FtwAbort,
+ FtwGetLastWrite
+};
+
+/**
+ Initialize the communicate buffer using DataSize and Function number.
+
+ @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use.
+ @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it.
+ @param[in] DataSize The payload size.
+ @param[in] Function The function number used to initialize the communicate header.
+
+**/
+VOID
+InitCommunicateBuffer (
+ OUT VOID **CommunicateBuffer,
+ OUT VOID **DataPtr,
+ IN UINTN DataSize,
+ IN UINTN Function
+ )
+{
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_COMMUNICATE_FUNCTION_HEADER *SmmFtwFunctionHeader;
+
+ //
+ // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE + DataSize.
+ //
+ SmmCommunicateHeader = AllocateZeroPool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE);
+ ASSERT (SmmCommunicateHeader != NULL);
+
+ //
+ // Prepare data buffer.
+ //
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFaultTolerantWriteProtocolGuid);
+ SmmCommunicateHeader->MessageLength = DataSize + SMM_FTW_COMMUNICATE_HEADER_SIZE;
+
+ SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
+ SmmFtwFunctionHeader->Function = Function;
+
+ *CommunicateBuffer = SmmCommunicateHeader;
+ if (DataPtr != NULL) {
+ *DataPtr = SmmFtwFunctionHeader->Data;
+ }
+}
+
+
+/**
+ Send the data in communicate buffer to SMI handler and get response.
+
+ @param[in, out] SmmCommunicateHeader The communicate buffer.
+ @param[in] DataSize The payload size.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+ IN OUT EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ SMM_FTW_COMMUNICATE_FUNCTION_HEADER *SmmFtwFunctionHeader;
+
+ CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE;
+ Status = mMmCommunication2->Communicate (mMmCommunication2,
+ SmmCommunicateHeader,
+ SmmCommunicateHeader,
+ &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
+ return SmmFtwFunctionHeader->ReturnStatus;
+}
+
+
+/**
+ Get the FvbBaseAddress and FvbAttributes from the FVB handle FvbHandle.
+
+ @param[in] FvbHandle The handle of FVB protocol that provides services.
+ @param[out] FvbBaseAddress The base address of the FVB attached with FvbHandle.
+ @param[out] FvbAttributes The attributes of the FVB attached with FvbHandle.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval Others The function could not complete successfully.
+
+**/
+EFI_STATUS
+ConvertFvbHandle (
+ IN EFI_HANDLE FvbHandle,
+ OUT EFI_PHYSICAL_ADDRESS *FvbBaseAddress,
+ OUT EFI_FVB_ATTRIBUTES_2 *FvbAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+
+ Status = gBS->HandleProtocol (FvbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Fvb->GetPhysicalAddress (Fvb, FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Fvb->GetAttributes (Fvb, FvbAttributes);
+ return Status;
+}
+
+
+/**
+ Get the size of the largest block that can be updated in a fault-tolerant manner.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] BlockSize A pointer to a caller-allocated UINTN that is
+ updated to indicate the size of the largest block
+ that can be updated.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetMaxBlockSize (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT UINTN *BlockSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *SmmFtwBlockSizeHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ PayloadSize = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER);
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwBlockSizeHeader, PayloadSize, FTW_FUNCTION_GET_MAX_BLOCK_SIZE);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
+
+ //
+ // Get data from SMM
+ //
+ *BlockSize = SmmFtwBlockSizeHeader->BlockSize;
+ FreePool (SmmCommunicateHeader);
+
+ return Status;
+}
+
+
+/**
+ Allocates space for the protocol to maintain information about writes.
+ Since writes must be completed in a fault-tolerant manner and multiple
+ writes require more resources to be successful, this function
+ enables the protocol to ensure that enough space exists to track
+ information about upcoming writes.
+
+ @param[in] This A pointer to the calling context.
+ @param[in] CallerId The GUID identifying the write.
+ @param[in] PrivateDataSize The size of the caller's private data that must be
+ recorded for each write.
+ @param[in] NumberOfWrites The number of fault tolerant block writes that will
+ need to occur.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED Not all allocated writes have been completed. All
+ writes must be completed or aborted before another
+ fault tolerant write can occur.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAllocate (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_GUID *CallerId,
+ IN UINTN PrivateDataSize,
+ IN UINTN NumberOfWrites
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_ALLOCATE_HEADER *SmmFtwAllocateHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ PayloadSize = sizeof (SMM_FTW_ALLOCATE_HEADER);
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwAllocateHeader, PayloadSize, FTW_FUNCTION_ALLOCATE);
+ CopyGuid (&SmmFtwAllocateHeader->CallerId, CallerId);
+ SmmFtwAllocateHeader->PrivateDataSize = PrivateDataSize;
+ SmmFtwAllocateHeader->NumberOfWrites = NumberOfWrites;
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
+ if (!EFI_ERROR( Status)) {
+ mPrivateDataSize = PrivateDataSize;
+ }
+
+ FreePool (SmmCommunicateHeader);
+ return Status;
+}
+
+
+/**
+ Starts a target block update. This records information about the write
+ in fault tolerant storage, and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param[in] This The calling context.
+ @param[in] Lba The logical block address of the target block.
+ @param[in] Offset The offset within the target block to place the
+ data.
+ @param[in] Length The number of bytes to write to the target block.
+ @param[in] PrivateData A pointer to private data that the caller requires
+ to complete any pending writes in the event of a
+ fault.
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services
+ for reading, writing, and erasing the target block.
+ @param[in] Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write would span a block boundary, which is not
+ a valid action.
+ @retval EFI_ACCESS_DENIED No writes have been allocated.
+ @retval EFI_NOT_READY The last write has not been completed. Restart()
+ must be called to complete it.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN VOID *PrivateData,
+ IN EFI_HANDLE FvBlockHandle,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_WRITE_HEADER *SmmFtwWriteHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ PayloadSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length;
+ if (PrivateData != NULL) {
+ //
+ // The private data buffer size should be the same one in FtwAllocate API.
+ //
+ PayloadSize += mPrivateDataSize;
+ }
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwWriteHeader, PayloadSize, FTW_FUNCTION_WRITE);
+
+ //
+ // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
+ // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
+ //
+ Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwWriteHeader->FvbBaseAddress, &SmmFtwWriteHeader->FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ FreePool (SmmCommunicateHeader);
+ return EFI_ABORTED;
+ }
+
+ SmmFtwWriteHeader->Lba = Lba;
+ SmmFtwWriteHeader->Offset = Offset;
+ SmmFtwWriteHeader->Length = Length;
+ CopyMem (SmmFtwWriteHeader->Data, Buffer, Length);
+ if (PrivateData == NULL) {
+ SmmFtwWriteHeader->PrivateDataSize = 0;
+ } else {
+ SmmFtwWriteHeader->PrivateDataSize = mPrivateDataSize;
+ CopyMem (&SmmFtwWriteHeader->Data[Length], PrivateData, mPrivateDataSize);
+ }
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
+ FreePool (SmmCommunicateHeader);
+ return Status;
+}
+
+
+/**
+ Restarts a previously interrupted write. The caller must provide the
+ block protocol needed to complete the interrupted write.
+
+ @param[in] This The calling context.
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED No pending writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwRestart (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_HANDLE FvBlockHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_RESTART_HEADER *SmmFtwRestartHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ PayloadSize = sizeof (SMM_FTW_RESTART_HEADER);
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwRestartHeader, PayloadSize, FTW_FUNCTION_RESTART);
+
+ //
+ // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
+ // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
+ //
+ Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwRestartHeader->FvbBaseAddress, &SmmFtwRestartHeader->FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ FreePool (SmmCommunicateHeader);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
+ FreePool (SmmCommunicateHeader);
+ return Status;
+}
+
+
+/**
+ Aborts all previously allocated writes.
+
+ @param[in] This The calling context.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAbort (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, NULL, 0, FTW_FUNCTION_ABORT);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, 0);
+
+ FreePool (SmmCommunicateHeader);
+ return Status;
+}
+
+
+/**
+ Starts a target block update. This function records information about the write
+ in fault-tolerant storage and completes the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] CallerId The GUID identifying the last write.
+ @param[out] Lba The logical block address of the last write.
+ @param[out] Offset The offset within the block of the last write.
+ @param[out] Length The length of the last write.
+ @param[in, out] PrivateDataSize On input, the size of the PrivateData buffer. On
+ output, the size of the private data stored for
+ this write.
+ @param[out] PrivateData A pointer to a buffer. The function will copy
+ PrivateDataSize bytes from the private data stored
+ for this write.
+ @param[out] Complete A Boolean value with TRUE indicating that the write
+ was completed.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetLastWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT EFI_GUID *CallerId,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset,
+ OUT UINTN *Length,
+ IN OUT UINTN *PrivateDataSize,
+ OUT VOID *PrivateData,
+ OUT BOOLEAN *Complete
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_FTW_GET_LAST_WRITE_HEADER *SmmFtwGetLastWriteHeader;
+
+ //
+ // Initialize the communicate buffer.
+ //
+ PayloadSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + *PrivateDataSize;
+ InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwGetLastWriteHeader, PayloadSize, FTW_FUNCTION_GET_LAST_WRITE);
+ SmmFtwGetLastWriteHeader->PrivateDataSize = *PrivateDataSize;
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
+
+ //
+ // Get data from SMM
+ //
+ *PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ *Lba = SmmFtwGetLastWriteHeader->Lba;
+ *Offset = SmmFtwGetLastWriteHeader->Offset;
+ *Length = SmmFtwGetLastWriteHeader->Length;
+ *Complete = SmmFtwGetLastWriteHeader->Complete;
+ CopyGuid (CallerId, &SmmFtwGetLastWriteHeader->CallerId);
+ if (Status == EFI_SUCCESS) {
+ CopyMem (PrivateData, SmmFtwGetLastWriteHeader->Data, *PrivateDataSize);
+ }
+ } else if (Status == EFI_NOT_FOUND) {
+ *Complete = SmmFtwGetLastWriteHeader->Complete;
+ }
+
+ FreePool (SmmCommunicateHeader);
+ return Status;
+}
+
+/**
+ SMM Fault Tolerant Write Protocol notification event handler.
+
+ Install Fault Tolerant Write Protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+SmmFtwReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+
+ //
+ // Just return to avoid install SMM FaultTolerantWriteProtocol again
+ // if Fault Tolerant Write protocol had been installed.
+ //
+ Status = gBS->LocateProtocol (&gEfiFaultTolerantWriteProtocolGuid, NULL, (VOID **)&FtwProtocol);
+ if (!EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **) &mMmCommunication2);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install protocol interface
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiFaultTolerantWriteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mFaultTolerantWriteDriver
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseEvent (Event);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ The driver entry point for Fault Tolerant Write driver.
+
+ The function does the necessary initialization work.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[in] SystemTable A pointer to the EFI system table.
+
+ @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+FaultTolerantWriteSmmInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *SmmFtwRegistration;
+
+ //
+ // Smm FTW driver is ready
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ TPL_CALLBACK,
+ SmmFtwReady,
+ NULL,
+ &SmmFtwRegistration
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.h b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.h
new file mode 100644
index 000000000..a15644abd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.h
@@ -0,0 +1,196 @@
+/** @file
+
+ The internal header file includes the common header files, defines
+ internal structure and functions used by FTW module.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SMM_FTW_DXE_H__
+#define __SMM_FTW_DXE_H__
+
+#include <PiDxe.h>
+
+#include <Protocol/MmCommunication2.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include "FaultTolerantWriteSmmCommon.h"
+
+/**
+ Get the size of the largest block that can be updated in a fault-tolerant manner.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] BlockSize A pointer to a caller-allocated UINTN that is
+ updated to indicate the size of the largest block
+ that can be updated.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetMaxBlockSize (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT UINTN *BlockSize
+ );
+
+
+/**
+ Allocates space for the protocol to maintain information about writes.
+ Since writes must be completed in a fault-tolerant manner and multiple
+ writes require more resources to be successful, this function
+ enables the protocol to ensure that enough space exists to track
+ information about upcoming writes.
+
+ @param[in] This A pointer to the calling context.
+ @param[in] CallerId The GUID identifying the write.
+ @param[in] PrivateDataSize The size of the caller's private data that must be
+ recorded for each write.
+ @param[in] NumberOfWrites The number of fault tolerant block writes that will
+ need to occur.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED Not all allocated writes have been completed. All
+ writes must be completed or aborted before another
+ fault tolerant write can occur.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAllocate (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_GUID *CallerId,
+ IN UINTN PrivateDataSize,
+ IN UINTN NumberOfWrites
+ );
+
+
+/**
+ Starts a target block update. This records information about the write
+ in fault tolerant storage, and will complete the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param[in] This The calling context.
+ @param[in] Lba The logical block address of the target block.
+ @param[in] Offset The offset within the target block to place the
+ data.
+ @param[in] Length The number of bytes to write to the target block.
+ @param[in] PrivateData A pointer to private data that the caller requires
+ to complete any pending writes in the event of a
+ fault.
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services
+ for reading, writing, and erasing the target block.
+ @param[in] Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write would span a block boundary, which is not
+ a valid action.
+ @retval EFI_ACCESS_DENIED No writes have been allocated.
+ @retval EFI_NOT_READY The last write has not been completed. Restart()
+ must be called to complete it.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN VOID *PrivateData,
+ IN EFI_HANDLE FvBlockHandle,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Restarts a previously interrupted write. The caller must provide the
+ block protocol needed to complete the interrupted write.
+
+ @param[in] This The calling context.
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_ACCESS_DENIED No pending writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwRestart (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ IN EFI_HANDLE FvBlockHandle
+ );
+
+
+/**
+ Aborts all previously allocated writes.
+
+ @param This The calling context.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwAbort (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
+ );
+
+
+/**
+ Starts a target block update. This function records information about the write
+ in fault-tolerant storage and completes the write in a recoverable
+ manner, ensuring at all times that either the original contents or
+ the modified contents are available.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] CallerId The GUID identifying the last write.
+ @param[out] Lba The logical block address of the last write.
+ @param[out] Offset The offset within the block of the last write.
+ @param[out] Length The length of the last write.
+ @param[in, out] PrivateDataSize On input, the size of the PrivateData buffer. On
+ output, the size of the private data stored for
+ this write.
+ @param[out] PrivateData A pointer to a buffer. The function will copy
+ PrivateDataSize bytes from the private data stored
+ for this write.
+ @param[out] Complete A Boolean value with TRUE indicating that the write
+ was completed.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+ @retval EFI_NOT_FOUND No allocated writes exist.
+
+**/
+EFI_STATUS
+EFIAPI
+FtwGetLastWrite (
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
+ OUT EFI_GUID *CallerId,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset,
+ OUT UINTN *Length,
+ IN OUT UINTN *PrivateDataSize,
+ OUT VOID *PrivateData,
+ OUT BOOLEAN *Complete
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf
new file mode 100644
index 000000000..f0dd82965
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.inf
@@ -0,0 +1,59 @@
+## @file
+# This module is the Runtime DXE part corresponding to SMM Fault Tolerant Write (FTW) module.
+#
+# It installs FTW protocol and works with SMM FTW module together.
+# The FTW protocol will not work after End Of Dxe because it will be not safe to expose
+# the related operations in SMM handler in SMM FTW module. You can use the FTW protocol
+# before End Of Dxe or use FaultTolerantWriteDxe module instead if you really want to.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FaultTolerantWriteSmmDxe
+ MODULE_UNI_FILE = FaultTolerantWriteSmmDxe.uni
+ FILE_GUID = 98948C4A-70F2-4035-8E9F-5927493CFC07
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FaultTolerantWriteSmmInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FaultTolerantWriteSmmDxe.c
+ FaultTolerantWriteSmmDxe.h
+ FaultTolerantWriteSmmCommon.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiFaultTolerantWriteProtocolGuid ## PRODUCES
+ gEfiMmCommunication2ProtocolGuid ## CONSUMES
+ ## NOTIFY
+ ## UNDEFINED # Used to do smm communication
+ ## CONSUMES
+ gEfiSmmFaultTolerantWriteProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiMmCommunication2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FaultTolerantWriteSmmDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.uni
new file mode 100644
index 000000000..84ee45ccb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxe.uni
@@ -0,0 +1,19 @@
+// /** @file
+// This module is the Runtime DXE part corresponding to SMM Fault Tolerant Write (FTW) module.
+//
+// It installs FTW protocol and works with SMM FTW module together.
+// The FTW protocol will not work after End Of Dxe because it will be not safe to expose
+// the related operations in SMM handler in SMM FTW module. You can use the FTW protocol
+// before End Of Dxe or use FaultTolerantWriteDxe module instead if you really want to.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The Runtime DXE part corresponding to the SMM Fault Tolerant Write (FTW) module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It installs FTW protocol and works with SMM FTW module together."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxeExtra.uni
new file mode 100644
index 000000000..5807b10f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmmDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FaultTolerantWriteSmmDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Fault Tolerant Flash Write SMM/DXE Bridge Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.c
new file mode 100644
index 000000000..5af49e040
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.c
@@ -0,0 +1,90 @@
+/** @file
+
+ Parts of the SMM/MM implementation that are specific to standalone MM
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/SmmMemLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "FaultTolerantWrite.h"
+#include "FaultTolerantWriteSmmCommon.h"
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+FtwSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return TRUE;
+}
+
+/**
+ Internal implementation of CRC32. Depending on the execution context
+ (standalone SMM or DXE vs standalone MM), this function is implemented
+ via a call to the CalculateCrc32 () boot service, or via a library
+ call.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param[in] Buffer A pointer to the buffer on which the 32-bit CRC is to be computed.
+ @param[in] Length The number of bytes in the buffer Data.
+
+ @retval Crc32 The 32-bit CRC was computed for the data buffer.
+
+**/
+UINT32
+FtwCalculateCrc32 (
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ return CalculateCrc32 (Buffer, Length);
+}
+
+/**
+ Notify the system that the SMM FTW driver is ready.
+**/
+VOID
+FtwNotifySmmReady (
+ VOID
+ )
+{
+}
+
+/**
+ This function is the entry point of the Fault Tolerant Write driver.
+
+ @param[in] ImageHandle A handle for the image that is initializing this driver
+ @param[in] MmSystemTable A pointer to the MM system table
+
+ @retval EFI_SUCCESS The initialization finished successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmFaultTolerantWriteInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ return MmFaultTolerantWriteInitialize ();
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf
new file mode 100644
index 000000000..d0fab7d94
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf
@@ -0,0 +1,85 @@
+ ## @file
+# Fault Tolerant Write Smm Driver.
+#
+# This driver installs SMM Fault Tolerant Write (FTW) protocol, which provides fault
+# tolerant write capability in SMM environment for block devices. Its implementation
+# depends on the full functionality SMM FVB protocol that support read, write/erase
+# flash access.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = FaultTolerantWriteStandaloneMm
+ FILE_GUID = 3aade4ec-63cc-4a48-a928-5a374dd463eb
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = StandaloneMmFaultTolerantWriteInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ FtwMisc.c
+ UpdateWorkingBlock.c
+ FaultTolerantWrite.c
+ FaultTolerantWriteStandaloneMm.c
+ FaultTolerantWriteSmm.c
+ FaultTolerantWrite.h
+ FaultTolerantWriteSmmCommon.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ PcdLib
+ ReportStatusCodeLib
+ StandaloneMmDriverEntryPoint
+
+[Guids]
+ #
+ # Signature in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
+ #
+ ## CONSUMES ## GUID
+ ## PRODUCES ## GUID
+ gEdkiiWorkingBlockSignatureGuid
+
+[Protocols]
+ gEfiSmmSwapAddressRangeProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## CONSUMES
+ gEfiSmmFirmwareVolumeBlockProtocolGuid
+ ## PRODUCES
+ ## UNDEFINED # SmiHandlerRegister
+ gEfiSmmFaultTolerantWriteProtocolGuid
+ gEfiMmEndOfDxeProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES
+
+[Depex]
+ TRUE
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteTraditionalMm.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteTraditionalMm.c
new file mode 100644
index 000000000..10e56e9a3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteTraditionalMm.c
@@ -0,0 +1,108 @@
+/** @file
+
+ Parts of the SMM/MM implementation that are specific to traditional MM
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/SmmMemLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "FaultTolerantWrite.h"
+#include "FaultTolerantWriteSmmCommon.h"
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+FtwSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return SmmIsBufferOutsideSmmValid (Buffer, Length);
+}
+
+/**
+ Internal implementation of CRC32. Depending on the execution context
+ (traditional SMM or DXE vs standalone MM), this function is implemented
+ via a call to the CalculateCrc32 () boot service, or via a library
+ call.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param[in] Buffer A pointer to the buffer on which the 32-bit CRC is
+ to be computed.
+ @param[in] Length The number of bytes in the buffer Data.
+
+ @retval Crc32 The 32-bit CRC was computed for the data buffer.
+
+**/
+UINT32
+FtwCalculateCrc32 (
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ReturnValue;
+
+ Status = gBS->CalculateCrc32 (Buffer, Length, &ReturnValue);
+ ASSERT_EFI_ERROR (Status);
+
+ return ReturnValue;
+}
+
+/**
+ Notify the system that the SMM FTW driver is ready.
+**/
+VOID
+FtwNotifySmmReady (
+ VOID
+ )
+{
+ EFI_HANDLE FtwHandle;
+ EFI_STATUS Status;
+
+ FtwHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &FtwHandle,
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This function is the entry point of the Fault Tolerant Write driver.
+
+ @param[in] ImageHandle A handle for the image that is initializing this driver
+ @param[in] SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS The initialization finished successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+EFIAPI
+SmmFaultTolerantWriteInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmFaultTolerantWriteInitialize ();
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
new file mode 100644
index 000000000..ed73f887a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
@@ -0,0 +1,1378 @@
+/** @file
+
+ Internal generic functions to operate flash block.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FaultTolerantWrite.h"
+
+/**
+
+ Check whether a flash buffer is erased.
+
+ @param Buffer Buffer to check
+ @param BufferSize Size of the buffer
+
+ @return A BOOLEAN value indicating erased or not.
+
+**/
+BOOLEAN
+IsErasedFlashBuffer (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ BOOLEAN IsEmpty;
+ UINT8 *Ptr;
+ UINTN Index;
+
+ Ptr = Buffer;
+ IsEmpty = TRUE;
+ for (Index = 0; Index < BufferSize; Index += 1) {
+ if (*Ptr++ != FTW_ERASED_BYTE) {
+ IsEmpty = FALSE;
+ break;
+ }
+ }
+
+ return IsEmpty;
+}
+
+/**
+ To erase the block with specified blocks.
+
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock FVB Protocol interface
+ @param Lba Lba of the firmware block
+ @param NumberOfBlocks The number of consecutive blocks starting with Lba
+
+ @retval EFI_SUCCESS Block LBA is Erased successfully
+ @retval Others Error occurs
+
+**/
+EFI_STATUS
+FtwEraseBlock (
+ IN EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ EFI_LBA Lba,
+ UINTN NumberOfBlocks
+ )
+{
+ return FvBlock->EraseBlocks (
+ FvBlock,
+ Lba,
+ NumberOfBlocks,
+ EFI_LBA_LIST_TERMINATOR
+ );
+}
+
+/**
+ Erase spare block.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+
+**/
+EFI_STATUS
+FtwEraseSpareBlock (
+ IN EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ return FtwDevice->FtwBackupFvb->EraseBlocks (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba,
+ FtwDevice->NumberOfSpareBlock,
+ EFI_LBA_LIST_TERMINATOR
+ );
+}
+
+/**
+
+ Is it in working block?
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock Fvb protocol instance
+ @param Lba The block specified
+
+ @return A BOOLEAN value indicating in working block or not.
+
+**/
+BOOLEAN
+IsWorkingBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ EFI_LBA Lba
+ )
+{
+ //
+ // If matching the following condition, the target block is in working block.
+ // 1. Target block is on the FV of working block (Using the same FVB protocol instance).
+ // 2. Lba falls into the range of working block.
+ //
+ return (BOOLEAN)
+ (
+ (FvBlock == FtwDevice->FtwFvBlock) &&
+ (Lba >= FtwDevice->FtwWorkBlockLba) &&
+ (Lba <= FtwDevice->FtwWorkSpaceLba)
+ );
+}
+
+/**
+
+ Get firmware volume block by address.
+
+
+ @param Address Address specified the block
+ @param FvBlock The block caller wanted
+
+ @retval EFI_SUCCESS The protocol instance if found.
+ @retval EFI_NOT_FOUND Block not found
+
+**/
+EFI_HANDLE
+GetFvbByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_HANDLE FvbHandle;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ *FvBlock = NULL;
+ FvbHandle = NULL;
+ HandleBuffer = NULL;
+ //
+ // Locate all handles of Fvb protocol
+ //
+ Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ //
+ // Get the FVB to access variable store
+ //
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Compare the address and select the right one
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Now, one FVB has one type of BlockSize
+ //
+ Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
+ *FvBlock = Fvb;
+ FvbHandle = HandleBuffer[Index];
+ break;
+ }
+ }
+
+ FreePool (HandleBuffer);
+ return FvbHandle;
+}
+
+/**
+
+ Is it in boot block?
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock Fvb protocol instance
+
+ @return A BOOLEAN value indicating in boot block or not.
+
+**/
+BOOLEAN
+IsBootBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
+ EFI_PHYSICAL_ADDRESS BootBlockBase;
+ UINTN BootBlockSize;
+ EFI_PHYSICAL_ADDRESS BackupBlockBase;
+ UINTN BackupBlockSize;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
+ BOOLEAN IsSwapped;
+ EFI_HANDLE FvbHandle;
+
+ if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
+ return FALSE;
+ }
+
+ Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // Get the boot block range
+ //
+ Status = SarProtocol->GetRangeLocation (
+ SarProtocol,
+ &BootBlockBase,
+ &BootBlockSize,
+ &BackupBlockBase,
+ &BackupBlockSize
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ Status = SarProtocol->GetSwapState (SarProtocol, &IsSwapped);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // Get FVB by address
+ //
+ if (!IsSwapped) {
+ FvbHandle = GetFvbByAddress (BootBlockBase, &BootFvb);
+ } else {
+ FvbHandle = GetFvbByAddress (BackupBlockBase, &BootFvb);
+ }
+
+ if (FvbHandle == NULL) {
+ return FALSE;
+ }
+ //
+ // Compare the Fvb
+ //
+ return (BOOLEAN) (FvBlock == BootFvb);
+}
+
+/**
+ Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
+ Spare block is accessed by FTW working FVB protocol interface.
+ Target block is accessed by FvBlock protocol interface.
+
+ FTW will do extra work on boot block update.
+ FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
+ which is produced by a chipset driver.
+ FTW updating boot block steps may be:
+ 1. GetRangeLocation(), if the Range is inside the boot block, FTW know
+ that boot block will be update. It shall add a FLAG in the working block.
+ 2. When spare block is ready,
+ 3. SetSwapState(SWAPPED)
+ 4. erasing boot block,
+ 5. programming boot block until the boot block is ok.
+ 6. SetSwapState(UNSWAPPED)
+ FTW shall not allow to update boot block when battery state is error.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS Spare block content is copied to boot block
+ @retval EFI_INVALID_PARAMETER Input parameter error
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToBootBlock (
+ EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 *Buffer;
+ UINTN Count;
+ UINT8 *Ptr;
+ UINTN Index;
+ BOOLEAN TopSwap;
+ EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
+ EFI_LBA BootLba;
+
+ if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Locate swap address range protocol
+ //
+ Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate a memory buffer
+ //
+ Length = FtwDevice->SpareAreaLength;
+ Buffer = AllocatePool (Length);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get TopSwap bit state
+ //
+ Status = SarProtocol->GetSwapState (SarProtocol, &TopSwap);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Get Top Swapped status - %r\n", Status));
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+
+ if (TopSwap) {
+ //
+ // Get FVB of current boot block
+ //
+ if (GetFvbByAddress (FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength, &BootFvb) == NULL) {
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Read data from current boot block
+ //
+ BootLba = 0;
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Count = FtwDevice->SpareBlockSize;
+ Status = BootFvb->Read (
+ BootFvb,
+ BootLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+ } else {
+ //
+ // Read data from spare block
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Count = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+ //
+ // Set TopSwap bit
+ //
+ Status = SarProtocol->SetSwapState (SarProtocol, TRUE);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+ }
+ //
+ // Erase current spare block
+ // Because TopSwap is set, this actually erase the top block (boot block)!
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Write memory buffer to current spare block. Still top block.
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Count = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: FVB Write boot block - %r\n", Status));
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+
+ FreePool (Buffer);
+
+ //
+ // Clear TopSwap bit
+ //
+ Status = SarProtocol->SetSwapState (SarProtocol, FALSE);
+
+ return Status;
+}
+
+/**
+ Copy the content of spare block to a target block.
+ Spare block is accessed by FTW backup FVB protocol interface.
+ Target block is accessed by FvBlock protocol interface.
+
+
+ @param FtwDevice The private data of FTW driver
+ @param FvBlock FVB Protocol interface to access target block
+ @param Lba Lba of the target block
+ @param BlockSize The size of the block
+ @param NumberOfBlocks The number of consecutive blocks starting with Lba
+
+ @retval EFI_SUCCESS Spare block content is copied to target block
+ @retval EFI_INVALID_PARAMETER Input parameter error
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToTargetBlock (
+ EFI_FTW_DEVICE *FtwDevice,
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ EFI_LBA Lba,
+ UINTN BlockSize,
+ UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 *Buffer;
+ UINTN Count;
+ UINT8 *Ptr;
+ UINTN Index;
+
+ if ((FtwDevice == NULL) || (FvBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Allocate a memory buffer
+ //
+ Length = FtwDevice->SpareAreaLength;
+ Buffer = AllocatePool (Length);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read all content of spare block to memory buffer
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Count = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+ //
+ // Erase the target block
+ //
+ Status = FtwEraseBlock (FtwDevice, FvBlock, Lba, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Write memory buffer to block, using the FvBlock protocol interface
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < NumberOfBlocks; Index += 1) {
+ Count = BlockSize;
+ Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
+ Spare block is accessed by FTW backup FVB protocol interface. LBA is
+ FtwDevice->FtwSpareLba.
+ Working block is accessed by FTW working FVB protocol interface. LBA is
+ FtwDevice->FtwWorkBlockLba.
+
+ Since the working block header is important when FTW initializes, the
+ state of the operation should be handled carefully. The Crc value is
+ calculated without STATE element.
+
+ @param FtwDevice The private data of FTW driver
+
+ @retval EFI_SUCCESS Spare block content is copied to target block
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FlushSpareBlockToWorkingBlock (
+ EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 *Buffer;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
+ UINTN Count;
+ UINT8 *Ptr;
+ UINTN Index;
+
+ //
+ // Allocate a memory buffer
+ //
+ Length = FtwDevice->SpareAreaLength;
+ Buffer = AllocatePool (Length);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // To guarantee that the WorkingBlockValid is set on spare block
+ //
+ // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
+ // WorkingBlockValid);
+ // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
+ //
+ FtwUpdateFvState (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->SpareBlockSize,
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
+ FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_VALID
+ );
+ //
+ // Read from spare block to memory buffer
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Count = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+ //
+ // Clear the CRC and STATE, copy data from spare to working block.
+ //
+ WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) FtwDevice->FtwWorkSpaceLbaInSpare * FtwDevice->SpareBlockSize + FtwDevice->FtwWorkSpaceBaseInSpare);
+ InitWorkSpaceHeader (WorkingBlockHeader);
+ WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
+ WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
+
+ //
+ // target block is working block, then
+ // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
+ // before erase the working block.
+ //
+ // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
+ // WorkingBlockInvalid);
+ // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to
+ // skip Signature and Crc.
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_INVALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+
+ FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
+
+ //
+ // Erase the working block
+ //
+ Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba, FtwDevice->NumberOfWorkBlock);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Write memory buffer to working block, using the FvBlock protocol interface
+ //
+ Ptr = Buffer;
+ for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
+ Count = FtwDevice->WorkBlockSize;
+ Status = FtwDevice->FtwFvBlock->Write (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->FtwWorkBlockLba + Index,
+ 0,
+ &Count,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr += Count;
+ }
+ //
+ // Since the memory buffer will not be used, free memory Buffer.
+ //
+ FreePool (Buffer);
+
+ //
+ // Update the VALID of the working block
+ //
+ // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid);
+ // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc.
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_VALID
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
+ FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update a bit of state on a block device. The location of the bit is
+ calculated by the (Lba, Offset, bit). Here bit is determined by the
+ the name of a certain bit.
+
+
+ @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
+ @param BlockSize The size of the block
+ @param Lba Lba of a block
+ @param Offset Offset on the Lba
+ @param NewBit New value that will override the old value if it can be change
+
+ @retval EFI_SUCCESS A state bit has been updated successfully
+ @retval Others Access block device error.
+ Notes:
+ Assume all bits of State are inside the same BYTE.
+ @retval EFI_ABORTED Read block fail
+
+**/
+EFI_STATUS
+FtwUpdateFvState (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINT8 NewBit
+ )
+{
+ EFI_STATUS Status;
+ UINT8 State;
+ UINTN Length;
+
+ //
+ // Calculate the real Offset and Lba to write.
+ //
+ while (Offset >= BlockSize) {
+ Offset -= BlockSize;
+ Lba++;
+ }
+
+ //
+ // Read state from device, assume State is only one byte.
+ //
+ Length = sizeof (UINT8);
+ Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ State ^= FTW_POLARITY_REVERT;
+ State = (UINT8) (State | NewBit);
+ State ^= FTW_POLARITY_REVERT;
+
+ //
+ // Write state back to device
+ //
+ Length = sizeof (UINT8);
+ Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
+
+ return Status;
+}
+
+/**
+ Get the last Write Header pointer.
+ The last write header is the header whose 'complete' state hasn't been set.
+ After all, this header may be a EMPTY header entry for next Allocate.
+
+
+ @param FtwWorkSpaceHeader Pointer of the working block header
+ @param FtwWorkSpaceSize Size of the work space
+ @param FtwWriteHeader Pointer to retrieve the last write header
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
+ IN UINTN FtwWorkSpaceSize,
+ OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
+ )
+{
+ UINTN Offset;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
+
+ *FtwWriteHeader = NULL;
+ FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);
+ Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
+
+ while (FtwHeader->Complete == FTW_VALID_STATE) {
+ Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
+ //
+ // If Offset exceed the FTW work space boudary, return error.
+ //
+ if (Offset >= FtwWorkSpaceSize) {
+ *FtwWriteHeader = FtwHeader;
+ return EFI_ABORTED;
+ }
+
+ FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);
+ }
+ //
+ // Last write header is found
+ //
+ *FtwWriteHeader = FtwHeader;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the last Write Record pointer. The last write Record is the Record
+ whose DestinationCompleted state hasn't been set. After all, this Record
+ may be a EMPTY record entry for next write.
+
+
+ @param FtwWriteHeader Pointer to the write record header
+ @param FtwWriteRecord Pointer to retrieve the last write record
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteRecord (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
+ OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
+ )
+{
+ UINTN Index;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
+
+ *FtwWriteRecord = NULL;
+ FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);
+
+ //
+ // Try to find the last write record "that has not completed"
+ //
+ for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
+ if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
+ //
+ // The last write record is found
+ //
+ *FtwWriteRecord = FtwRecord;
+ return EFI_SUCCESS;
+ }
+
+ FtwRecord++;
+
+ if (FtwWriteHeader->PrivateDataSize != 0) {
+ FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize);
+ }
+ }
+ //
+ // if Index == NumberOfWrites, then
+ // the last record has been written successfully,
+ // but the Header->Complete Flag has not been set.
+ // also return the last record.
+ //
+ if (Index == FtwWriteHeader->NumberOfWrites) {
+ *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
+ return EFI_SUCCESS;
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ To check if FtwRecord is the first record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to the write record
+
+ @retval TRUE FtwRecord is the first Record of the FtwHeader
+ @retval FALSE FtwRecord is not the first Record of the FtwHeader
+
+**/
+BOOLEAN
+IsFirstRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
+ )
+{
+ UINT8 *Head;
+ UINT8 *Ptr;
+
+ Head = (UINT8 *) FtwHeader;
+ Ptr = (UINT8 *) FtwRecord;
+
+ Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
+ return (BOOLEAN) (Head == Ptr);
+}
+
+/**
+ To check if FtwRecord is the last record of FtwHeader. Because the
+ FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be
+ determined if it is the last record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to the write record
+
+ @retval TRUE FtwRecord is the last Record of the FtwHeader
+ @retval FALSE FtwRecord is not the last Record of the FtwHeader
+
+**/
+BOOLEAN
+IsLastRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
+ )
+{
+ UINT8 *Head;
+ UINT8 *Ptr;
+
+ Head = (UINT8 *) FtwHeader;
+ Ptr = (UINT8 *) FtwRecord;
+
+ Head += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);
+ return (BOOLEAN) (Head == Ptr);
+}
+
+/**
+ To check if FtwRecord is the first record of FtwHeader.
+
+ @param FtwHeader Pointer to the write record header
+ @param FtwRecord Pointer to retrieve the previous write record
+
+ @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.
+ @retval EFI_SUCCESS The previous write record is found.
+
+**/
+EFI_STATUS
+GetPreviousRecordOfWrites (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
+ IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord
+ )
+{
+ UINT8 *Ptr;
+
+ if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) {
+ *FtwRecord = NULL;
+ return EFI_ACCESS_DENIED;
+ }
+
+ Ptr = (UINT8 *) (*FtwRecord);
+ Ptr -= FTW_RECORD_SIZE (FtwHeader->PrivateDataSize);
+ *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate private data for FTW driver and initialize it.
+
+ @param[out] FtwData Pointer to the FTW device structure
+
+ @retval EFI_SUCCESS Initialize the FTW device successfully.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
+
+**/
+EFI_STATUS
+InitFtwDevice (
+ OUT EFI_FTW_DEVICE **FtwData
+ )
+{
+ EFI_FTW_DEVICE *FtwDevice;
+
+ //
+ // Allocate private data of this driver,
+ // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
+ //
+ FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
+ if (FtwDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
+ //
+ FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+ FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+ if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
+ FreePool (FtwDevice);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
+ FtwDevice->FtwFvBlock = NULL;
+ FtwDevice->FtwBackupFvb = NULL;
+ FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
+ FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
+
+ FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
+ if (FtwDevice->WorkSpaceAddress == 0) {
+ FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
+ }
+
+ FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
+ if (FtwDevice->SpareAreaAddress == 0) {
+ FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
+ }
+
+ *FtwData = FtwDevice;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find the proper Firmware Volume Block protocol for FTW operation.
+
+ @param[in, out] FtwDevice Pointer to the FTW device structure
+
+ @retval EFI_SUCCESS Find the FVB protocol successfully.
+ @retval EFI_NOT_FOUND No proper FVB protocol was found.
+ @retval EFI_ABORTED Some data can not be got or be invalid.
+
+**/
+EFI_STATUS
+FindFvbForFtw (
+ IN OUT EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINT32 LbaIndex;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ HandleBuffer = NULL;
+
+ //
+ // Get all FVB handle.
+ //
+ Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the FVB to access variable store
+ //
+ Fvb = NULL;
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Ensure this FVB protocol support Write operation.
+ //
+ Status = Fvb->GetAttributes (Fvb, &Attributes);
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
+ continue;
+ }
+ //
+ // Compare the address and select the right one
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Now, one FVB has one type of BlockSize.
+ //
+ Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
+ ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
+ FtwDevice->FtwFvBlock = Fvb;
+ //
+ // To get the LBA of work space
+ //
+ for (LbaIndex = 1; LbaIndex <= NumberOfBlocks; LbaIndex += 1) {
+ if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + BlockSize * (LbaIndex - 1)))
+ && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + BlockSize * LbaIndex))) {
+ FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
+ //
+ // Get the Work space size and Base(Offset)
+ //
+ FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
+ FtwDevice->WorkBlockSize = BlockSize;
+ FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FtwDevice->WorkBlockSize * (LbaIndex - 1)));
+ FtwDevice->NumberOfWorkSpaceBlock = FTW_BLOCKS (FtwDevice->FtwWorkSpaceBase + FtwDevice->FtwWorkSpaceSize, FtwDevice->WorkBlockSize);
+ if (FtwDevice->FtwWorkSpaceSize >= FtwDevice->WorkBlockSize) {
+ //
+ // Check the alignment of work space address and length, they should be block size aligned when work space size is larger than one block size.
+ //
+ if (((FtwDevice->WorkSpaceAddress & (FtwDevice->WorkBlockSize - 1)) != 0) ||
+ ((FtwDevice->WorkSpaceLength & (FtwDevice->WorkBlockSize - 1)) != 0)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Work space address or length is not block size aligned when work space size is larger than one block size\n"));
+ FreePool (HandleBuffer);
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+ } else if ((FtwDevice->FtwWorkSpaceBase + FtwDevice->FtwWorkSpaceSize) > FtwDevice->WorkBlockSize) {
+ DEBUG ((EFI_D_ERROR, "Ftw: The work space range should not span blocks when work space size is less than one block size\n"));
+ FreePool (HandleBuffer);
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+ break;
+ }
+ }
+ }
+
+ if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
+ ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
+ FtwDevice->FtwBackupFvb = Fvb;
+ //
+ // To get the LBA of spare
+ //
+ for (LbaIndex = 1; LbaIndex <= NumberOfBlocks; LbaIndex += 1) {
+ if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + BlockSize * (LbaIndex - 1)))
+ && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + BlockSize * LbaIndex))) {
+ //
+ // Get the NumberOfSpareBlock and BlockSize
+ //
+ FtwDevice->FtwSpareLba = LbaIndex - 1;
+ FtwDevice->SpareBlockSize = BlockSize;
+ FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->SpareBlockSize;
+ //
+ // Check the range of spare area to make sure that it's in FV range
+ //
+ if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > NumberOfBlocks) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
+ FreePool (HandleBuffer);
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+ //
+ // Check the alignment of spare area address and length, they should be block size aligned
+ //
+ if (((FtwDevice->SpareAreaAddress & (FtwDevice->SpareBlockSize - 1)) != 0) ||
+ ((FtwDevice->SpareAreaLength & (FtwDevice->SpareBlockSize - 1)) != 0)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Spare area address or length is not block size aligned\n"));
+ FreePool (HandleBuffer);
+ //
+ // Report Status Code EFI_SW_EC_ABORTED.
+ //
+ REPORT_STATUS_CODE ((EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ABORTED));
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
+ break;
+ }
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+
+ if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
+ (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
+ return EFI_ABORTED;
+ }
+ DEBUG ((EFI_D_INFO, "Ftw: FtwWorkSpaceLba - 0x%lx, WorkBlockSize - 0x%x, FtwWorkSpaceBase - 0x%x\n", FtwDevice->FtwWorkSpaceLba, FtwDevice->WorkBlockSize, FtwDevice->FtwWorkSpaceBase));
+ DEBUG ((EFI_D_INFO, "Ftw: FtwSpareLba - 0x%lx, SpareBlockSize - 0x%x\n", FtwDevice->FtwSpareLba, FtwDevice->SpareBlockSize));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialization for Fault Tolerant Write protocol.
+
+ @param[in, out] FtwDevice Pointer to the FTW device structure
+
+ @retval EFI_SUCCESS Initialize the FTW protocol successfully.
+ @retval EFI_NOT_FOUND No proper FVB protocol was found.
+
+**/
+EFI_STATUS
+InitFtwProtocol (
+ IN OUT EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
+ UINTN Offset;
+ EFI_HANDLE FvbHandle;
+ EFI_LBA WorkSpaceLbaOffset;
+
+ //
+ // Find the right SMM Fvb protocol instance for FTW.
+ //
+ Status = FindFvbForFtw (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Calculate the start LBA of working block.
+ //
+ if (FtwDevice->FtwWorkSpaceSize >= FtwDevice->WorkBlockSize) {
+ //
+ // Working block is a standalone area which only contains working space.
+ //
+ FtwDevice->NumberOfWorkBlock = FtwDevice->NumberOfWorkSpaceBlock;
+ } else {
+ //
+ // Working block is an area which
+ // contains working space in its last block and has the same size as spare
+ // block, unless there are not enough blocks before the block that contains
+ // working space.
+ //
+ FtwDevice->NumberOfWorkBlock = (UINTN) (FtwDevice->FtwWorkSpaceLba + FtwDevice->NumberOfWorkSpaceBlock);
+ while (FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize > FtwDevice->SpareAreaLength) {
+ FtwDevice->NumberOfWorkBlock--;
+ }
+ }
+ FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba + FtwDevice->NumberOfWorkSpaceBlock - FtwDevice->NumberOfWorkBlock;
+ DEBUG ((EFI_D_INFO, "Ftw: NumberOfWorkBlock - 0x%x, FtwWorkBlockLba - 0x%lx\n", FtwDevice->NumberOfWorkBlock, FtwDevice->FtwWorkBlockLba));
+
+ //
+ // Calcualte the LBA and base of work space in spare block.
+ // Note: Do not assume Spare Block and Work Block have same block size.
+ //
+ WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
+ FtwDevice->FtwWorkSpaceLbaInSpare = (EFI_LBA) (((UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize + FtwDevice->FtwWorkSpaceBase) / FtwDevice->SpareBlockSize);
+ FtwDevice->FtwWorkSpaceBaseInSpare = ((UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize + FtwDevice->FtwWorkSpaceBase) % FtwDevice->SpareBlockSize;
+ DEBUG ((EFI_D_INFO, "Ftw: WorkSpaceLbaInSpare - 0x%lx, WorkSpaceBaseInSpare - 0x%x\n", FtwDevice->FtwWorkSpaceLbaInSpare, FtwDevice->FtwWorkSpaceBaseInSpare));
+
+ //
+ // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
+ //
+ FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
+ FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
+
+ FtwDevice->FtwLastWriteHeader = NULL;
+ FtwDevice->FtwLastWriteRecord = NULL;
+
+ InitializeLocalWorkSpaceHeader ();
+
+ //
+ // Refresh the working space data from working block
+ //
+ Status = WorkSpaceRefresh (FtwDevice);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // If the working block workspace is not valid, try the spare block
+ //
+ if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
+ //
+ // Read from spare block
+ //
+ Status = ReadWorkSpaceData (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->SpareBlockSize,
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
+ FtwDevice->FtwWorkSpaceBaseInSpare,
+ FtwDevice->FtwWorkSpaceSize,
+ FtwDevice->FtwWorkSpace
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If spare block is valid, then replace working block content.
+ //
+ if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
+ Status = FlushSpareBlockToWorkingBlock (FtwDevice);
+ DEBUG ((EFI_D_INFO, "Ftw: Restart working block update in %a() - %r\n",
+ __FUNCTION__, Status));
+ FtwAbort (&FtwDevice->FtwInstance);
+ //
+ // Refresh work space.
+ //
+ Status = WorkSpaceRefresh (FtwDevice);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((EFI_D_INFO,
+ "Ftw: Both working and spare blocks are invalid, init workspace\n"));
+ //
+ // If both are invalid, then initialize work space.
+ //
+ SetMem (
+ FtwDevice->FtwWorkSpace,
+ FtwDevice->FtwWorkSpaceSize,
+ FTW_ERASED_BYTE
+ );
+ InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
+ //
+ // Initialize the work space
+ //
+ Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ //
+ // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
+ // (! SpareComplete) THEN call Abort().
+ //
+ if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
+ (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
+ IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
+ ) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
+ FtwAbort (&FtwDevice->FtwInstance);
+ }
+ //
+ // If Header is incompleted and the last record has completed, then
+ // call Abort() to set the Header->Complete FLAG.
+ //
+ if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
+ (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
+ IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
+ ) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
+ FtwAbort (&FtwDevice->FtwInstance);
+ }
+ //
+ // To check the workspace buffer following last Write header/records is EMPTY or not.
+ // If it's not EMPTY, FTW also need to call reclaim().
+ //
+ FtwHeader = FtwDevice->FtwLastWriteHeader;
+ Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
+ if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
+ Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
+ }
+
+ if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
+ Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Restart if it's boot block
+ //
+ if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
+ (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
+ ) {
+ if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
+ Status = FlushSpareBlockToBootBlock (FtwDevice);
+ DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ FtwAbort (&FtwDevice->FtwInstance);
+ } else {
+ //
+ // if (SpareCompleted) THEN Restart to fault tolerant write.
+ //
+ FvbHandle = NULL;
+ FvbHandle = GetFvbByAddress ((EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) FtwDevice->SpareAreaAddress + FtwDevice->FtwLastWriteRecord->RelativeOffset), &Fvb);
+ if (FvbHandle != NULL) {
+ Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
+ DEBUG ((EFI_D_ERROR, "Ftw: Restart last write - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ FtwAbort (&FtwDevice->FtwInstance);
+ }
+ }
+ //
+ // Hook the protocol API
+ //
+ FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
+ FtwDevice->FtwInstance.Allocate = FtwAllocate;
+ FtwDevice->FtwInstance.Write = FtwWrite;
+ FtwDevice->FtwInstance.Restart = FtwRestart;
+ FtwDevice->FtwInstance.Abort = FtwAbort;
+ FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxe.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxe.uni
new file mode 100644
index 000000000..da8b40e6d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxe.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Fault Tolerant Write Smm Driver.
+//
+// This driver installs SMM Fault Tolerant Write (FTW) protocol, which provides fault
+// tolerant write capability in SMM environment for block devices. Its implementation
+// depends on the full functionality SMM FVB protocol that support read, write/erase
+// flash access.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Fault Tolerant Write Smm Driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Installs SMM Fault Tolerant Write (FTW) protocol, which provides fault tolerant write capability in SMM environment for block devices. Its implementation depends on the full functionality SMM FVB protocol that support read, write/erase flash access."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxeExtra.uni
new file mode 100644
index 000000000..29455445b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/SmmFaultTolerantWriteDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmmFaultTolerantWriteDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM Fault Tolerant Flash Write Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
new file mode 100644
index 000000000..04cb38afd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
@@ -0,0 +1,607 @@
+/** @file
+
+ Internal functions to operate Working Block Space.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "FaultTolerantWrite.h"
+
+EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = {ZERO_GUID, 0, 0, 0, 0, {0, 0, 0}, 0};
+
+/**
+ Initialize a local work space header.
+
+ Since Signature and WriteQueueSize have been known, Crc can be calculated out,
+ then the work space header will be fixed.
+**/
+VOID
+InitializeLocalWorkSpaceHeader (
+ VOID
+ )
+{
+ //
+ // Check signature with gEdkiiWorkingBlockSignatureGuid.
+ //
+ if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {
+ //
+ // The local work space header has been initialized.
+ //
+ return;
+ }
+
+ SetMem (
+ &mWorkingBlockHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ FTW_ERASED_BYTE
+ );
+
+ //
+ // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
+ //
+ CopyMem (
+ &mWorkingBlockHeader.Signature,
+ &gEdkiiWorkingBlockSignatureGuid,
+ sizeof (EFI_GUID)
+ );
+ mWorkingBlockHeader.WriteQueueSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
+
+ //
+ // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
+ //
+
+ //
+ // Calculate the Crc of woking block header
+ //
+ mWorkingBlockHeader.Crc = FtwCalculateCrc32 (&mWorkingBlockHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
+
+ mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;
+ mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;
+}
+
+/**
+ Check to see if it is a valid work space.
+
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval TRUE The work space is valid.
+ @retval FALSE The work space is invalid.
+
+**/
+BOOLEAN
+IsValidWorkSpace (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+{
+ if (WorkingHeader == NULL) {
+ return FALSE;
+ }
+
+ if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {
+ return TRUE;
+ }
+
+ DEBUG ((EFI_D_INFO, "Ftw: Work block header check mismatch\n"));
+ return FALSE;
+}
+
+/**
+ Initialize a work space when there is no work space.
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+InitWorkSpaceHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+{
+ if (WorkingHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read work space data from work block or spare block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block.
+ @param Length The number of bytes to read from the block.
+ @param Buffer The data is read.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+ReadWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINTN MyLength;
+
+ //
+ // Calculate the real Offset and Lba to write.
+ //
+ while (Offset >= BlockSize) {
+ Offset -= BlockSize;
+ Lba++;
+ }
+
+ Ptr = Buffer;
+ while (Length > 0) {
+ if ((Offset + Length) > BlockSize) {
+ MyLength = BlockSize - Offset;
+ } else {
+ MyLength = Length;
+ }
+
+ Status = FvBlock->Read (
+ FvBlock,
+ Lba,
+ Offset,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ Offset = 0;
+ Length -= MyLength;
+ Ptr += MyLength;
+ Lba++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write work space data to work block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block to place the data.
+ @param Length The number of bytes to write to the block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WriteWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINTN MyLength;
+
+ //
+ // Calculate the real Offset and Lba to write.
+ //
+ while (Offset >= BlockSize) {
+ Offset -= BlockSize;
+ Lba++;
+ }
+
+ Ptr = Buffer;
+ while (Length > 0) {
+ if ((Offset + Length) > BlockSize) {
+ MyLength = BlockSize - Offset;
+ } else {
+ MyLength = Length;
+ }
+
+ Status = FvBlock->Write (
+ FvBlock,
+ Lba,
+ Offset,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ Offset = 0;
+ Length -= MyLength;
+ Ptr += MyLength;
+ Lba++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read from working block to refresh the work space in memory.
+
+ @param FtwDevice Point to private data of FTW driver
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WorkSpaceRefresh (
+ IN EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN RemainingSpaceSize;
+
+ //
+ // Initialize WorkSpace as FTW_ERASED_BYTE
+ //
+ SetMem (
+ FtwDevice->FtwWorkSpace,
+ FtwDevice->FtwWorkSpaceSize,
+ FTW_ERASED_BYTE
+ );
+
+ //
+ // Read from working block
+ //
+ Status = ReadWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase,
+ FtwDevice->FtwWorkSpaceSize,
+ FtwDevice->FtwWorkSpace
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Refresh the FtwLastWriteHeader
+ //
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN) FtwDevice->FtwLastWriteHeader - (UINTN) FtwDevice->FtwWorkSpace);
+ DEBUG ((EFI_D_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
+ //
+ // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
+ // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
+ // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
+ // it needs to reclaim work space.
+ //
+ if (EFI_ERROR (Status) || RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD)) {
+ //
+ // reclaim work space in working block.
+ //
+ Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
+ return EFI_ABORTED;
+ }
+ //
+ // Read from working block again
+ //
+ Status = ReadWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase,
+ FtwDevice->FtwWorkSpaceSize,
+ FtwDevice->FtwWorkSpace
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Refresh the FtwLastWriteRecord
+ //
+ Status = FtwGetLastWriteRecord (
+ FtwDevice->FtwLastWriteHeader,
+ &FtwDevice->FtwLastWriteRecord
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reclaim the work space on the working block.
+
+ @param FtwDevice Point to private data of FTW driver
+ @param PreserveRecord Whether to preserve the working record is needed
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FtwReclaimWorkSpace (
+ IN EFI_FTW_DEVICE *FtwDevice,
+ IN BOOLEAN PreserveRecord
+ )
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ UINT8 *TempBuffer;
+ UINTN TempBufferSize;
+ UINTN SpareBufferSize;
+ UINT8 *SpareBuffer;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
+ UINTN Index;
+ UINT8 *Ptr;
+ EFI_LBA WorkSpaceLbaOffset;
+
+ DEBUG ((EFI_D_INFO, "Ftw: start to reclaim work space\n"));
+
+ WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
+
+ //
+ // Read all original data from working block to a memory buffer
+ //
+ TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = TempBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
+ Length = FtwDevice->WorkBlockSize;
+ Status = FtwDevice->FtwFvBlock->Read (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->FtwWorkBlockLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+ //
+ // Clean up the workspace, remove all the completed records.
+ //
+ Ptr = TempBuffer +
+ (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
+ FtwDevice->FtwWorkSpaceBase;
+
+ //
+ // Clear the content of buffer that will save the new work space data
+ //
+ SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
+
+ //
+ // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
+ //
+ CopyMem (
+ Ptr,
+ FtwDevice->FtwWorkSpaceHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
+ );
+ if (PreserveRecord) {
+ //
+ // Get the last record following the header,
+ //
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ Header = FtwDevice->FtwLastWriteHeader;
+ if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {
+ CopyMem (
+ Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ FtwDevice->FtwLastWriteHeader,
+ FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)
+ );
+ }
+ }
+
+ CopyMem (
+ FtwDevice->FtwWorkSpace,
+ Ptr,
+ FtwDevice->FtwWorkSpaceSize
+ );
+
+ FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+
+ FtwGetLastWriteRecord (
+ FtwDevice->FtwLastWriteHeader,
+ &FtwDevice->FtwLastWriteRecord
+ );
+
+ //
+ // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
+ //
+ WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +
+ (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
+ FtwDevice->FtwWorkSpaceBase);
+ WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
+ WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
+
+ //
+ // Try to keep the content of spare block
+ // Save spare block into a spare backup memory buffer (Sparebuffer)
+ //
+ SpareBufferSize = FtwDevice->SpareAreaLength;
+ SpareBuffer = AllocatePool (SpareBufferSize);
+ if (SpareBuffer == NULL) {
+ FreePool (TempBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+ //
+ // Write the memory buffer to spare block
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ Ptr = TempBuffer;
+ for (Index = 0; TempBufferSize > 0; Index += 1) {
+ if (TempBufferSize > FtwDevice->SpareBlockSize) {
+ Length = FtwDevice->SpareBlockSize;
+ } else {
+ Length = TempBufferSize;
+ }
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ TempBufferSize -= Length;
+ }
+ //
+ // Free TempBuffer
+ //
+ FreePool (TempBuffer);
+
+ //
+ // Set the WorkingBlockValid in spare block
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->SpareBlockSize,
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
+ FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_VALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ //
+ // Before erase the working block, set WorkingBlockInvalid in working block.
+ //
+ // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
+ // WorkingBlockInvalid);
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_INVALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
+
+ //
+ // Write the spare block to working block
+ //
+ Status = FlushSpareBlockToWorkingBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return Status;
+ }
+ //
+ // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+
+ FreePool (SpareBuffer);
+
+ DEBUG ((EFI_D_INFO, "Ftw: reclaim work space successfully\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c
new file mode 100644
index 000000000..439d5b01e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c
@@ -0,0 +1,315 @@
+/** @file
+ This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform
+ the check for FTW last write data has been done.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiFaultTolerantWriteGuid,
+ NULL
+};
+
+/**
+ Get the last Write Header pointer.
+ The last write header is the header whose 'complete' state hasn't been set.
+ After all, this header may be a EMPTY header entry for next Allocate.
+
+
+ @param FtwWorkSpaceHeader Pointer of the working block header
+ @param FtwWorkSpaceSize Size of the work space
+ @param FtwWriteHeader Pointer to retrieve the last write header
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
+ IN UINTN FtwWorkSpaceSize,
+ OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
+ )
+{
+ UINTN Offset;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
+
+ *FtwWriteHeader = NULL;
+ FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);
+ Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
+
+ while (FtwHeader->Complete == FTW_VALID_STATE) {
+ Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
+ //
+ // If Offset exceed the FTW work space boudary, return error.
+ //
+ if (Offset >= FtwWorkSpaceSize) {
+ *FtwWriteHeader = FtwHeader;
+ return EFI_ABORTED;
+ }
+
+ FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);
+ }
+ //
+ // Last write header is found
+ //
+ *FtwWriteHeader = FtwHeader;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the last Write Record pointer. The last write Record is the Record
+ whose DestinationCompleted state hasn't been set. After all, this Record
+ may be a EMPTY record entry for next write.
+
+
+ @param FtwWriteHeader Pointer to the write record header
+ @param FtwWriteRecord Pointer to retrieve the last write record
+
+ @retval EFI_SUCCESS Get the last write record successfully
+ @retval EFI_ABORTED The FTW work space is damaged
+
+**/
+EFI_STATUS
+FtwGetLastWriteRecord (
+ IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
+ OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
+ )
+{
+ UINTN Index;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
+
+ *FtwWriteRecord = NULL;
+ FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);
+
+ //
+ // Try to find the last write record "that has not completed"
+ //
+ for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
+ if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
+ //
+ // The last write record is found
+ //
+ *FtwWriteRecord = FtwRecord;
+ return EFI_SUCCESS;
+ }
+
+ FtwRecord++;
+
+ if (FtwWriteHeader->PrivateDataSize != 0) {
+ FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize);
+ }
+ }
+ //
+ // if Index == NumberOfWrites, then
+ // the last record has been written successfully,
+ // but the Header->Complete Flag has not been set.
+ // also return the last record.
+ //
+ if (Index == FtwWriteHeader->NumberOfWrites) {
+ *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
+ return EFI_SUCCESS;
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ Check to see if it is a valid work space.
+
+
+ @param WorkingHeader Pointer of working block header
+ @param WorkingLength Working block length
+
+ @retval TRUE The work space is valid.
+ @retval FALSE The work space is invalid.
+
+**/
+BOOLEAN
+IsValidWorkSpace (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader,
+ IN UINTN WorkingLength
+ )
+{
+ UINT8 Data;
+
+ if (WorkingHeader == NULL) {
+ return FALSE;
+ }
+
+ if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) {
+ DEBUG ((EFI_D_ERROR, "FtwPei: Work block header valid bit check error\n"));
+ return FALSE;
+ }
+
+ if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) {
+ DEBUG ((EFI_D_ERROR, "FtwPei: Work block header WriteQueueSize check error\n"));
+ return FALSE;
+ }
+
+ //
+ // Check signature with gEdkiiWorkingBlockSignatureGuid
+ //
+ if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) {
+ DEBUG ((EFI_D_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n"));
+ //
+ // To be compatible with old signature gEfiSystemNvDataFvGuid.
+ //
+ if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
+ return FALSE;
+ } else {
+ Data = *(UINT8 *) (WorkingHeader + 1);
+ if (Data != 0xff) {
+ DEBUG ((EFI_D_ERROR, "FtwPei: Old format FTW structure can't be handled\n"));
+ ASSERT (FALSE);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+/**
+ Main entry for Fault Tolerant Write PEIM.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Pointer to PEI Services table.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimFaultTolerantWriteInitialize (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkingBlockHeader;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader;
+ EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord;
+ EFI_PHYSICAL_ADDRESS WorkSpaceAddress;
+ UINTN WorkSpaceLength;
+ EFI_PHYSICAL_ADDRESS SpareAreaAddress;
+ UINTN SpareAreaLength;
+ EFI_PHYSICAL_ADDRESS WorkSpaceInSpareArea;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA FtwLastWrite;
+
+ FtwWorkingBlockHeader = NULL;
+ FtwLastWriteHeader = NULL;
+ FtwLastWriteRecord = NULL;
+
+ WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
+ if (WorkSpaceAddress == 0) {
+ WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
+ }
+ WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+
+ SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
+ if (SpareAreaAddress == 0) {
+ SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
+ }
+ SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+ //
+ // The address of FTW working base and spare base must not be 0.
+ //
+ ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0));
+
+ FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceAddress;
+ if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
+ Status = FtwGetLastWriteHeader (
+ FtwWorkingBlockHeader,
+ WorkSpaceLength,
+ &FtwLastWriteHeader
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = FtwGetLastWriteRecord (
+ FtwLastWriteHeader,
+ &FtwLastWriteRecord
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FtwLastWriteRecord != NULL);
+ if ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE)) {
+ //
+ // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set.
+ // It means the target buffer has been backed up in spare block, then target block has been erased,
+ // but the target buffer has not been writen in target block from spare block, we need to build
+ // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data.
+ //
+ FtwLastWrite.TargetAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) SpareAreaAddress + FtwLastWriteRecord->RelativeOffset);
+ FtwLastWrite.SpareAddress = SpareAreaAddress;
+ FtwLastWrite.Length = SpareAreaLength;
+ DEBUG ((
+ EFI_D_INFO,
+ "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
+ (UINTN) FtwLastWrite.TargetAddress,
+ (UINTN) FtwLastWrite.SpareAddress,
+ (UINTN) FtwLastWrite.Length));
+ BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
+ }
+ }
+ } else {
+ FtwWorkingBlockHeader = NULL;
+ //
+ // If the working block workspace is not valid, try to find workspace in the spare block.
+ //
+ WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength;
+ while (WorkSpaceInSpareArea >= SpareAreaAddress) {
+ if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *) (UINTN) WorkSpaceInSpareArea)) {
+ //
+ // Found the workspace.
+ //
+ DEBUG ((EFI_D_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN) WorkSpaceInSpareArea));
+ FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceInSpareArea;
+ break;
+ }
+ WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID);
+ }
+ if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
+ //
+ // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it.
+ //
+ FtwLastWrite.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress);
+ FtwLastWrite.SpareAddress = SpareAreaAddress;
+ FtwLastWrite.Length = SpareAreaLength;
+ DEBUG ((
+ EFI_D_INFO,
+ "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
+ (UINTN) FtwLastWrite.TargetAddress,
+ (UINTN) FtwLastWrite.SpareAddress,
+ (UINTN) FtwLastWrite.Length));
+ BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
+ } else {
+ //
+ // Both are invalid.
+ //
+ DEBUG ((EFI_D_ERROR, "FtwPei: Both working and spare block are invalid.\n"));
+ }
+ }
+
+ //
+ // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
+ //
+ return PeiServicesInstallPpi (&mPpiListVariable);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
new file mode 100644
index 000000000..f90892ad4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
@@ -0,0 +1,62 @@
+## @file
+# Fault Tolerant Write PEI Driver.
+#
+# This module installs gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FaultTolerantWritePei
+ MODULE_UNI_FILE = FaultTolerantWritePei.uni
+ FILE_GUID = AAC33064-9ED0-4b89-A5AD-3EA767960B22
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimFaultTolerantWriteInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FaultTolerantWritePei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ BaseLib
+ DebugLib
+ HobLib
+ BaseMemoryLib
+ PcdLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## HOB
+ ## PRODUCES ## GUID # Install ppi
+ gEdkiiFaultTolerantWriteGuid
+ gEdkiiWorkingBlockSignatureGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FaultTolerantWritePeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.uni
new file mode 100644
index 000000000..ee64d5afe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Fault Tolerant Write PEI Driver.
+//
+// This module installs gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This module installs gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePeiExtra.uni
new file mode 100644
index 000000000..5def161b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FaultTolerantWritePei Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"FaultTolerantWrite PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.c b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.c
new file mode 100644
index 000000000..19ab71b1e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.c
@@ -0,0 +1,52 @@
+/** @file
+ This driver produces file explorer protocol layered on top of the FileExplorerLib from the MdeModulePkg.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/FileExplorer.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+EFI_HANDLE mFileExplorerThunkHandle = NULL;
+
+CONST EFI_FILE_EXPLORER_PROTOCOL mFileExplorerProtocol = {
+ ChooseFile
+};
+
+/**
+ The user Entry Point for File explorer module.
+
+ This is the entry point for Print DXE Driver. It installs the file explorer Protocol.
+
+ @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 Others Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mFileExplorerThunkHandle,
+ &gEfiFileExplorerProtocolGuid, &mFileExplorerProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.inf b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.inf
new file mode 100644
index 000000000..e01ccb7eb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# File explorer DXE driver that produces File explorer Protocol.
+#
+# This driver produces File explorerprotocol layered on top of the FileExplorerLib
+# from the MdeModulePkg.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FileExplorerDxe
+ MODULE_UNI_FILE = FileExplorerDxe.uni
+ FILE_GUID = 405DA936-3737-4C0C-8E3F-E6172A568592
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FileExplorerEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ FileExplorerDxe.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ FileExplorerLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiFileExplorerProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FileExplorerDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.uni b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.uni
new file mode 100644
index 000000000..aa011c0c1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxe.uni
@@ -0,0 +1,17 @@
+// /** @file
+// File Explorer DXE driver that produces Print2 Protocol.
+//
+// This driver produces File Explorer protocol layered on top of the File Explorer library
+// from the MdeModulePkg.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "File Explorer DXE driver that produces File Explorer Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces file explorer protocol layered on top of the FileExplorerLib from the MdeModulePkg."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxeExtra.uni
new file mode 100644
index 000000000..42611d58c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FileExplorerDxe/FileExplorerDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FileExplorerDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"File Explorer DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/ComponentName.c
new file mode 100644
index 000000000..8ab660a0c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/ComponentName.c
@@ -0,0 +1,181 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for FvSimpleFileSystem driver.
+
+Copyright (c) 2014, ARM Limited. All rights reserved.
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FvSimpleFileSystemInternal.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gFvSimpleFileSystemComponentName = {
+ FvSimpleFileSystemComponentNameGetDriverName,
+ FvSimpleFileSystemComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gFvSimpleFileSystemComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FvSimpleFileSystemComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FvSimpleFileSystemComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for FvSimpleFileSystem module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFvSimpleFileSystemDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Fv Simple File System 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
+FvSimpleFileSystemComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mFvSimpleFileSystemDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gFvSimpleFileSystemComponentName)
+ );
+}
+
+/**
+ 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
+FvSimpleFileSystemComponentNameGetControllerName (
+ 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/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.c b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.c
new file mode 100644
index 000000000..f33f7f721
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.c
@@ -0,0 +1,1030 @@
+/** @file
+ This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
+ volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
+
+ It will expose a single directory, containing one file for each file in the firmware
+ volume. If a file has a UI section, its contents will be used as a filename.
+ Otherwise, a string representation of the GUID will be used.
+ Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
+ will have ".efi" added to their filename.
+
+ Its primary intended use is to be able to start EFI applications embedded in FVs
+ from the UEFI shell. It is entirely read-only.
+
+Copyright (c) 2014, ARM Limited. All rights reserved.
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FvSimpleFileSystemInternal.h"
+
+//
+// Template for EFI_FILE_SYSTEM_INFO data structure.
+//
+EFI_FILE_SYSTEM_INFO mFsInfoTemplate = {
+ 0, // Populate at runtime
+ TRUE, // Read-only
+ 0, // Don't know volume size
+ 0, // No free space
+ 0, // Don't know block size
+ L"" // Populate at runtime
+};
+
+//
+// Template for EFI_FILE_PROTOCOL data structure.
+//
+EFI_FILE_PROTOCOL mFileSystemTemplate = {
+ EFI_FILE_PROTOCOL_REVISION,
+ FvSimpleFileSystemOpen,
+ FvSimpleFileSystemClose,
+ FvSimpleFileSystemDelete,
+ FvSimpleFileSystemRead,
+ FvSimpleFileSystemWrite,
+ FvSimpleFileSystemGetPosition,
+ FvSimpleFileSystemSetPosition,
+ FvSimpleFileSystemGetInfo,
+ FvSimpleFileSystemSetInfo,
+ FvSimpleFileSystemFlush
+};
+
+/**
+ Find and call ReadSection on the first section found of an executable type.
+
+ @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
+ @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
+ representing a file's info.
+ @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of
+ the memory represented by *Buffer.
+ @param Buffer Pointer to a pointer to a data buffer to contain file content.
+
+ @retval EFI_SUCCESS The call completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output.
+ @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads.
+ @retval EFI_NOT_FOUND The requested file was not found in the firmware volume.
+ @retval EFI_DEVICE_ERROR A hardware error occurred when attempting toaccess the firmware volume.
+
+**/
+EFI_STATUS
+FvFsFindExecutableSection (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol,
+ IN FV_FILESYSTEM_FILE_INFO *FvFileInfo,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID **Buffer
+ )
+{
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_STATUS Status;
+
+ for (SectionType = EFI_SECTION_PE32; SectionType <= EFI_SECTION_TE; SectionType++) {
+ Status = FvProtocol->ReadSection (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ SectionType,
+ 0,
+ Buffer,
+ BufferSize,
+ &AuthenticationStatus
+ );
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get the size of the buffer that will be returned by FvFsReadFile.
+
+ @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
+ @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
+ representing a file's info.
+
+ @retval EFI_SUCCESS The file size was gotten correctly.
+ @retval Others The file size wasn't gotten correctly.
+
+**/
+EFI_STATUS
+FvFsGetFileSize (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol,
+ IN OUT FV_FILESYSTEM_FILE_INFO *FvFileInfo
+ )
+{
+ UINT32 AuthenticationStatus;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ EFI_STATUS Status;
+ UINT8 IgnoredByte;
+ VOID *IgnoredPtr;
+
+ //
+ // To get the size of a section, we pass 0 for BufferSize. But we can't pass
+ // NULL for Buffer, as that will cause a return of INVALID_PARAMETER, and we
+ // can't pass NULL for *Buffer, as that will cause the callee to allocate
+ // a buffer of the sections size.
+ //
+ IgnoredPtr = &IgnoredByte;
+ FvFileInfo->FileInfo.FileSize = 0;
+
+ if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
+ //
+ // Get the size of the first executable section out of the file.
+ //
+ Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, (UINTN*)&FvFileInfo->FileInfo.FileSize, &IgnoredPtr);
+ if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
+ return EFI_SUCCESS;
+ }
+ } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
+ //
+ // Try to get the size of a raw section out of the file
+ //
+ Status = FvProtocol->ReadSection (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ EFI_SECTION_RAW,
+ 0,
+ &IgnoredPtr,
+ (UINTN*)&FvFileInfo->FileInfo.FileSize,
+ &AuthenticationStatus
+ );
+ if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Didn't find a raw section, just return the whole file's size.
+ //
+ return FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ NULL,
+ (UINTN*)&FvFileInfo->FileInfo.FileSize,
+ &FoundType,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ }
+ } else {
+ //
+ // Get the size of the entire file
+ //
+ return FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ NULL,
+ (UINTN*)&FvFileInfo->FileInfo.FileSize,
+ &FoundType,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Helper function to read a file.
+
+ The data returned depends on the type of the underlying FV file:
+ - For executable types, the first section found that contains executable code is returned.
+ - For files of type FREEFORM, the driver attempts to return the first section of type RAW.
+ If none is found, the entire contents of the FV file are returned.
+ - On all other files the entire contents of the FV file is returned, as by
+ EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadFile.
+
+ @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
+ @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
+ representing a file's info.
+ @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of
+ the memory represented by *Buffer.
+ @param Buffer Pointer to a pointer to a data buffer to contain file content.
+
+ @retval EFI_SUCCESS The call completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output.
+ @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads.
+ @retval EFI_NOT_FOUND The requested file was not found in the firmware volume.
+ @retval EFI_DEVICE_ERROR A hardware error occurred when attempting toaccess the firmware volume.
+
+**/
+EFI_STATUS
+FvFsReadFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol,
+ IN FV_FILESYSTEM_FILE_INFO *FvFileInfo,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID **Buffer
+ )
+{
+ UINT32 AuthenticationStatus;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ EFI_STATUS Status;
+
+ if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
+ //
+ // Read the first executable section out of the file.
+ //
+ Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, BufferSize, Buffer);
+ } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
+ //
+ // Try to read a raw section out of the file
+ //
+ Status = FvProtocol->ReadSection (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ EFI_SECTION_RAW,
+ 0,
+ Buffer,
+ BufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Didn't find a raw section, just return the whole file.
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ Buffer,
+ BufferSize,
+ &FoundType,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ }
+ } else {
+ //
+ // Read the entire file
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileInfo->NameGuid,
+ Buffer,
+ BufferSize,
+ &FoundType,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Helper function for populating an EFI_FILE_INFO for a file.
+
+ Note the CreateTime, LastAccessTime and ModificationTime fields in EFI_FILE_INFO
+ are full zero as FV2 protocol has no corresponding info to fill.
+
+ @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
+ representing a file's info.
+ @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of
+ the memory represented by FileInfo.
+ @param FileInfo A pointer to EFI_FILE_INFO to contain the returned file info.
+
+ @retval EFI_SUCCESS The call completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to contain the requested output.
+
+**/
+EFI_STATUS
+FvFsGetFileInfo (
+ IN FV_FILESYSTEM_FILE_INFO *FvFileInfo,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FILE_INFO *FileInfo
+ )
+{
+ UINTN InfoSize;
+
+ InfoSize = (UINTN)FvFileInfo->FileInfo.Size;
+ if (*BufferSize < InfoSize) {
+ *BufferSize = InfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Initialize FileInfo
+ //
+ CopyMem (FileInfo, &FvFileInfo->FileInfo, InfoSize);
+
+ *BufferSize = InfoSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Removes the last directory or file entry in a path by changing the last
+ L'\' to a CHAR_NULL.
+
+ @param Path The pointer to the path to modify.
+
+ @retval FALSE Nothing was found to remove.
+ @retval TRUE A directory or file was removed.
+
+**/
+BOOLEAN
+EFIAPI
+RemoveLastItemFromPath (
+ IN OUT CHAR16 *Path
+ )
+{
+ CHAR16 *Walker;
+ CHAR16 *LastSlash;
+ //
+ // get directory name from path... ('chop' off extra)
+ //
+ for ( Walker = Path, LastSlash = NULL
+ ; Walker != NULL && *Walker != CHAR_NULL
+ ; Walker++
+ ){
+ if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) {
+ LastSlash = Walker + 1;
+ }
+ }
+
+ if (LastSlash != NULL) {
+ *LastSlash = CHAR_NULL;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/**
+ Function to clean up paths.
+
+ - Single periods in the path are removed.
+ - Double periods in the path are removed along with a single parent directory.
+ - Forward slashes L'/' are converted to backward slashes L'\'.
+
+ This will be done inline and the existing buffer may be larger than required
+ upon completion.
+
+ @param Path The pointer to the string containing the path.
+
+ @retval NULL An error occurred.
+ @return Path in all other instances.
+
+**/
+CHAR16*
+EFIAPI
+TrimFilePathToAbsolutePath (
+ IN CHAR16 *Path
+ )
+{
+ CHAR16 *TempString;
+ UINTN TempSize;
+
+ if (Path == NULL) {
+ return NULL;
+ }
+
+ //
+ // Fix up the '/' vs '\'
+ //
+ for (TempString = Path ; (TempString != NULL) && (*TempString != CHAR_NULL); TempString++) {
+ if (*TempString == L'/') {
+ *TempString = L'\\';
+ }
+ }
+
+ //
+ // Fix up the ..
+ //
+ while ((TempString = StrStr (Path, L"\\..\\")) != NULL) {
+ *TempString = CHAR_NULL;
+ TempString += 4;
+ RemoveLastItemFromPath (Path);
+ TempSize = StrSize (TempString);
+ CopyMem (Path + StrLen (Path), TempString, TempSize);
+ }
+
+ if (((TempString = StrStr (Path, L"\\..")) != NULL) && (*(TempString + 3) == CHAR_NULL)) {
+ *TempString = CHAR_NULL;
+ RemoveLastItemFromPath (Path);
+ }
+
+ //
+ // Fix up the .
+ //
+ while ((TempString = StrStr (Path, L"\\.\\")) != NULL) {
+ *TempString = CHAR_NULL;
+ TempString += 2;
+ TempSize = StrSize (TempString);
+ CopyMem(Path + StrLen (Path), TempString, TempSize);
+ }
+
+ if (((TempString = StrStr (Path, L"\\.")) != NULL) && (*(TempString + 2) == CHAR_NULL)) {
+ *(TempString + 1) = CHAR_NULL;
+ }
+
+ while ((TempString = StrStr (Path, L"\\\\")) != NULL) {
+ *TempString = CHAR_NULL;
+ TempString += 1;
+ TempSize = StrSize(TempString);
+ CopyMem(Path + StrLen(Path), TempString, TempSize);
+ }
+
+ if (((TempString = StrStr(Path, L"\\\\")) != NULL) && (*(TempString + 1) == CHAR_NULL)) {
+ *(TempString) = CHAR_NULL;
+ }
+
+ return Path;
+}
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to the source location. This would typically be an open
+ handle to a directory.
+ @param NewHandle A pointer to the location to return the opened handle for the new
+ file.
+ @param FileName The Null-terminated string of the name of the file to be opened.
+ The file name may contain the following path modifiers: "\", ".",
+ and "..".
+ @param OpenMode The mode to open the file. The only valid combinations that the
+ file may be opened with are: Read, Read/Write, or Create/Read/Write.
+ @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
+ attribute bits for the newly created file.
+
+ @retval EFI_SUCCESS The file was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
+ longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
+ when the media is write-protected.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+ FV_FILESYSTEM_FILE *NewFile;
+ FV_FILESYSTEM_FILE_INFO *FvFileInfo;
+ LIST_ENTRY *FvFileInfoLink;
+ EFI_STATUS Status;
+ UINTN FileNameLength;
+ UINTN NewFileNameLength;
+ CHAR16 *FileNameWithExtension;
+
+ //
+ // Check for a valid mode
+ //
+ switch (OpenMode) {
+ case EFI_FILE_MODE_READ:
+ break;
+
+ default:
+ return EFI_WRITE_PROTECTED;
+ }
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ FileName = TrimFilePathToAbsolutePath (FileName);
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FileName[0] == L'\\') {
+ FileName++;
+ }
+
+ //
+ // Check for opening root
+ //
+ if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) {
+ NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
+ if (NewFile == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewFile->Signature = FVFS_FILE_SIGNATURE;
+ NewFile->Instance = Instance;
+ NewFile->FvFileInfo = File->FvFileInfo;
+ CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
+ InitializeListHead (&NewFile->Link);
+ InsertHeadList (&Instance->FileHead, &NewFile->Link);
+
+ NewFile->DirReadNext = NULL;
+ if (!IsListEmpty (&Instance->FileInfoHead)) {
+ NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
+ }
+
+ *NewHandle = &NewFile->FileProtocol;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do a linear search for a file in the FV with a matching filename
+ //
+ Status = EFI_NOT_FOUND;
+ FvFileInfo = NULL;
+ for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
+ !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
+ FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
+ FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
+ if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ // If the file has not been found check if the filename exists with an extension
+ // in case there was no extension present.
+ // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers
+ // present in the Firmware Volume
+ if (Status == EFI_NOT_FOUND) {
+ FileNameLength = StrLen (FileName);
+
+ // Does the filename already contain the '.EFI' extension?
+ if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) {
+ // No, there was no extension. So add one and search again for the file
+ // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character)
+ NewFileNameLength = FileNameLength + 1 + 4;
+ FileNameWithExtension = AllocatePool (NewFileNameLength * 2);
+ StrCpyS (FileNameWithExtension, NewFileNameLength, FileName);
+ StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI");
+
+ for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
+ !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
+ FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
+ FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
+ if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
+ if (NewFile == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFile->Signature = FVFS_FILE_SIGNATURE;
+ NewFile->Instance = Instance;
+ NewFile->FvFileInfo = FvFileInfo;
+ CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
+ InitializeListHead (&NewFile->Link);
+ InsertHeadList (&Instance->FileHead, &NewFile->Link);
+
+ *NewHandle = &NewFile->FileProtocol;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Closes a specified file handle.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to close.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemClose (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ if (File != Instance->Root) {
+ RemoveEntryList (&File->Link);
+ FreePool (File);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads data from a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to read data from.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of data
+ returned in Buffer. In both cases, the size is measured in bytes.
+ @param Buffer The buffer into which the data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
+ @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
+ entry. BufferSize has been updated with the size
+ needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+ EFI_STATUS Status;
+ LIST_ENTRY *FvFileInfoLink;
+ VOID *FileBuffer;
+ UINTN FileSize;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ if (File->FvFileInfo == Instance->Root->FvFileInfo) {
+ if (File->DirReadNext) {
+ //
+ // Directory read: populate Buffer with an EFI_FILE_INFO
+ //
+ Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Successfully read a directory entry, now update the pointer to the
+ // next file, which will be read on the next call to this function
+ //
+ FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link);
+ if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) {
+ //
+ // No more files left
+ //
+ File->DirReadNext = NULL;
+ } else {
+ File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
+ }
+ }
+ return Status;
+ } else {
+ //
+ // Directory read. All entries have been read, so return a zero-size
+ // buffer.
+ //
+ *BufferSize = 0;
+ return EFI_SUCCESS;
+ }
+ } else {
+ FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize;
+
+ FileBuffer = AllocateZeroPool (FileSize);
+ if (FileBuffer == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (*BufferSize + File->Position > FileSize) {
+ *BufferSize = (UINTN)(FileSize - File->Position);
+ }
+
+ CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize);
+ File->Position += *BufferSize;
+
+ FreePool (FileBuffer);
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Writes data to a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to write data to.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of data
+ actually written. In both cases, the size is measured in bytes.
+ @param Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to open directory files are not supported.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ if (File->FvFileInfo == Instance->Root->FvFileInfo) {
+ return EFI_UNSUPPORTED;
+ } else {
+ return EFI_WRITE_PROTECTED;
+ }
+}
+
+/**
+ Returns a file's current position.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to get the current position on.
+ @param Position The address to return the file's current position value.
+
+ @retval EFI_SUCCESS The position was returned.
+ @retval EFI_UNSUPPORTED The request is not valid on open directories.
+ @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ if (File->FvFileInfo == Instance->Root->FvFileInfo) {
+ return EFI_UNSUPPORTED;
+ } else {
+ *Position = File->Position;
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Sets a file's current position.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ file handle to set the requested position on.
+ @param Position The byte position from the start of the file to set.
+
+ @retval EFI_SUCCESS The position was set.
+ @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
+ directories.
+ @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE *File;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+ Instance = File->Instance;
+
+ if (File->FvFileInfo == Instance->Root->FvFileInfo) {
+ if (Position != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Reset directory position to first entry
+ //
+ if (File->DirReadNext) {
+ File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
+ }
+ } else if (Position == 0xFFFFFFFFFFFFFFFFull) {
+ File->Position = File->FvFileInfo->FileInfo.FileSize;
+ } else {
+ File->Position = Position;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Flushes all modified data associated with a file to a device.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to flush.
+
+ @retval EFI_SUCCESS The data was flushed.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
+ @retval EFI_ACCESS_DENIED The file was opened read-only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemFlush (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ Close and delete the file handle.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ handle to the file to delete.
+
+ @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemDelete (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+
+ Status = FvSimpleFileSystemClose (This);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_WARN_DELETE_FAILURE;
+}
+
+/**
+ Returns information about a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle the requested information is for.
+ @param InformationType The type identifier for the information being requested.
+ @param BufferSize On input, the size of Buffer. On output, the amount of data
+ returned in Buffer. In both cases, the size is measured in bytes.
+ @param Buffer A pointer to the data buffer to return. The buffer's type is
+ indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was returned.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete
+ the request.
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ FV_FILESYSTEM_FILE *File;
+ EFI_FILE_SYSTEM_INFO *FsInfoOut;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel;
+ FV_FILESYSTEM_INSTANCE *Instance;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ File = FVFS_FILE_FROM_FILE_THIS (This);
+
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ //
+ // Return filesystem info
+ //
+ Instance = File->Instance;
+
+ Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);
+
+ if (*BufferSize < Size) {
+ *BufferSize = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Cast output buffer for convenience
+ //
+ FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer;
+
+ CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO));
+ Status = StrnCpyS ( FsInfoOut->VolumeLabel,
+ (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
+ Instance->VolumeLabel,
+ StrLen (Instance->VolumeLabel)
+ );
+ ASSERT_EFI_ERROR (Status);
+ FsInfoOut->Size = Size;
+ return Status;
+ } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ //
+ // Return file info
+ //
+ return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer);
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ //
+ // Return Volume Label
+ //
+ Instance = File->Instance;
+ Size = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);;
+ if (*BufferSize < Size) {
+ *BufferSize = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer;
+ Status = StrnCpyS (FsVolumeLabel->VolumeLabel,
+ (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16),
+ Instance->VolumeLabel,
+ StrLen (Instance->VolumeLabel)
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Sets information about a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle the information is for.
+ @param InformationType The type identifier for the information being set.
+ @param BufferSize The size, in bytes, of Buffer.
+ @param Buffer A pointer to the data buffer to write. The buffer's type is
+ indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the media is
+ read-only.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
+ and the media is read only.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
+ and the media is read-only.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file to a
+ file that is already present.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_FILE_DIRECTORY
+ Attribute.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the size of a directory.
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the file was opened
+ read-only and an attempt is being made to modify a field
+ other than Attribute.
+ @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type indicated
+ by InformationType.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) ||
+ CompareGuid (InformationType, &gEfiFileInfoGuid) ||
+ CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.uni b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.uni
new file mode 100644
index 000000000..ed148b8b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystem.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Module that lays Simple File System protocol on every FirmwareVolume2 protocol.
+//
+// This module produces Simple File System protocol to provide the accesses to the files in FVs.
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Lays Simple File System protocol on every FirmwareVolume2 protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces Simple File System protocol to provide the accesses to the files in FVs."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf
new file mode 100644
index 000000000..03797847d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf
@@ -0,0 +1,68 @@
+## @file
+# Support for Simple File System over Firmware Volume.
+#
+# This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
+# volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
+#
+# It will expose a single directory, containing one file for each file in the firmware
+# volume. If a file has a UI section, its contents will be used as a filename.
+# Otherwise, a string representation of the GUID will be used.
+# Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
+# will have ".efi" added to their filename.
+#
+# Its primary intended use is to be able to start EFI applications embedded in FVs
+# from the UEFI shell. It is entirely read-only.
+#
+# Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FvSimpleFileSystem
+ MODULE_UNI_FILE = FvSimpleFileSystem.uni
+ FILE_GUID = 907125c0-a5f1-11e3-a3fe-a3198b49350c
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FvSimpleFileSystemEntryPoint
+
+[Sources]
+
+ ComponentName.c
+ FvSimpleFileSystem.c
+ FvSimpleFileSystemEntryPoint.c
+ FvSimpleFileSystemInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DevicePathLib
+ MemoryAllocationLib
+ PrintLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiFirmwareVolume2ProtocolGuid ## TO_START
+ gEfiUnicodeCollationProtocolGuid ## TO_START
+ gEfiUnicodeCollation2ProtocolGuid ## TO_START
+ gEfiSimpleFileSystemProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FvSimpleFileSystemExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c
new file mode 100644
index 000000000..f5d6275d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemEntryPoint.c
@@ -0,0 +1,673 @@
+/** @file
+ This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
+ volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
+
+ It will expose a single directory, containing one file for each file in the firmware
+ volume. If a file has a UI section, its contents will be used as a filename.
+ Otherwise, a string representation of the GUID will be used.
+ Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
+ will have ".efi" added to their filename.
+
+ Its primary intended use is to be able to start EFI applications embedded in FVs
+ from the UEFI shell. It is entirely read-only.
+
+Copyright (c) 2014, ARM Limited. All rights reserved.
+Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FvSimpleFileSystemInternal.h"
+
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+
+//
+// A Guid string is 32 hex characters with 4 hyphens and a NULL-terminated char: 37 characters total
+//
+#define GUID_STRING_SIZE (37 * sizeof (CHAR16))
+
+#define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: "
+#define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE - sizeof (CHAR16))
+#define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume"
+
+//
+// Template for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL data structure.
+//
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate = {
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+ FvSimpleFileSystemOpenVolume
+};
+
+//
+// Template for EFI_DRIVER_BINDING_PROTOCOL data structure.
+//
+EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
+ FvSimpleFileSystemDriverSupported,
+ FvSimpleFileSystemDriverStart,
+ FvSimpleFileSystemDriverStop,
+ 0,
+ NULL,
+ NULL
+};
+
+/**
+ Open the root directory on a volume.
+
+ @param This A pointer to the volume to open the root directory.
+ @param RootFile A pointer to the location to return the opened file handle for the
+ root directory.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the requested file system type.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
+ longer supported. Any existing file handles for this volume are
+ no longer valid. To access the files on the new medium, the
+ volume must be reopened with OpenVolume().
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **RootFile
+ )
+{
+ EFI_STATUS Status;
+ FV_FILESYSTEM_FILE *Root;
+ CHAR16 *UiSection;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 Authentication;
+ UINTN Key;
+ EFI_FV_FILETYPE FileType;
+ UINTN Size;
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE_INFO *FvFileInfo;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ CHAR16 *Name;
+ UINTN NameLen;
+ UINTN NumChars;
+ UINTN DestMax;
+
+ Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This);
+ Status = EFI_SUCCESS;
+
+ if (Instance->Root == NULL) {
+ //
+ // Allocate file structure for root file
+ //
+ Root = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
+ if (Root == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Instance->Root = Root;
+ Root->Instance = Instance;
+ Root->Signature = FVFS_FILE_SIGNATURE;
+ CopyMem (&Root->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
+ Root->FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO));
+ if (Root->FvFileInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Root->FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO);
+ Root->FvFileInfo->FileInfo.Attribute = EFI_FILE_DIRECTORY | EFI_FILE_READ_ONLY;
+
+ //
+ // Populate the instance's list of files. We consider anything a file that
+ // has a UI_SECTION, which we consider to be its filename.
+ //
+ FvProtocol = Instance->FvProtocol;
+ //
+ // Allocate Key
+ //
+ Key = 0;
+
+ do {
+ FileType = EFI_FV_FILETYPE_ALL;
+
+ Status = FvProtocol->GetNextFile (
+ FvProtocol,
+ &Key,
+ &FileType,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (Status == EFI_NOT_FOUND);
+ break;
+ }
+
+ //
+ // Get a file's name: If it has a UI section, use that, otherwise use
+ // its NameGuid.
+ //
+ UiSection = NULL;
+ Status = FvProtocol->ReadSection (
+ FvProtocol,
+ &NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&UiSection,
+ &Size,
+ &Authentication
+ );
+ if (!EFI_ERROR (Status)) {
+ Name = UiSection;
+ } else {
+ Name = AllocateZeroPool (GUID_STRING_SIZE);
+ if (Name == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid);
+ ASSERT ((NumChars + 1) * sizeof (CHAR16) == GUID_STRING_SIZE);
+ }
+
+ //
+ // Found a file.
+ // Allocate a file structure and populate it.
+ //
+ NameLen = StrSize (Name);
+ if (FV_FILETYPE_IS_EXECUTABLE (FileType)) {
+ NameLen += StrSize (L".efi") - sizeof (CHAR16);
+ }
+
+ FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO) + NameLen - sizeof (CHAR16));
+ if (FvFileInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvFileInfo->Signature = FVFS_FILE_INFO_SIGNATURE;
+ InitializeListHead (&FvFileInfo->Link);
+ CopyMem (&FvFileInfo->NameGuid, &NameGuid, sizeof (EFI_GUID));
+ FvFileInfo->Type = FileType;
+
+ //
+ // Add ".efi" to filenames of drivers and applications.
+ //
+ DestMax = NameLen / sizeof (CHAR16);
+ Status = StrnCpyS (&FvFileInfo->FileInfo.FileName[0], DestMax, Name, StrLen (Name));
+ ASSERT_EFI_ERROR (Status);
+
+ if (FV_FILETYPE_IS_EXECUTABLE (FileType)) {
+ Status = StrnCatS (&FvFileInfo->FileInfo.FileName[0], DestMax, L".efi", StrLen (L".efi"));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO) + NameLen - sizeof (CHAR16);
+ Status = FvFsGetFileSize (FvProtocol, FvFileInfo);
+ ASSERT_EFI_ERROR (Status);
+ FvFileInfo->FileInfo.PhysicalSize = FvFileInfo->FileInfo.FileSize;
+ FvFileInfo->FileInfo.Attribute = EFI_FILE_READ_ONLY;
+
+ InsertHeadList (&Instance->FileInfoHead, &FvFileInfo->Link);
+
+ FreePool (Name);
+
+ } while (TRUE);
+
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ Instance->Root->DirReadNext = NULL;
+ if (!IsListEmpty (&Instance->FileInfoHead)) {
+ Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
+ }
+
+ *RootFile = &Instance->Root->FileProtocol;
+ return Status;
+}
+
+/**
+ Worker function to initialize Unicode Collation support.
+
+ It tries to locate Unicode Collation (2) protocol and matches it with current
+ platform language code.
+
+ @param AgentHandle The handle used to open Unicode Collation (2) protocol.
+ @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.
+ @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
+ @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.
+
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
+ @retval Others The Unicode Collation (2) protocol has not been located.
+
+**/
+EFI_STATUS
+InitializeUnicodeCollationSupportWorker (
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_GUID *ProtocolGuid,
+ IN CONST CHAR16 *VariableName,
+ IN CONST CHAR8 *DefaultLanguage
+ )
+{
+ EFI_STATUS ReturnStatus;
+ EFI_STATUS Status;
+ UINTN NumHandles;
+ UINTN Index;
+ EFI_HANDLE *Handles;
+ EFI_UNICODE_COLLATION_PROTOCOL *Uci;
+ BOOLEAN Iso639Language;
+ CHAR8 *Language;
+ CHAR8 *BestLanguage;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ ProtocolGuid,
+ NULL,
+ &NumHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Iso639Language = (BOOLEAN) (ProtocolGuid == &gEfiUnicodeCollationProtocolGuid);
+ GetEfiGlobalVariable2 (VariableName, (VOID**) &Language, NULL);
+
+ ReturnStatus = EFI_UNSUPPORTED;
+ for (Index = 0; Index < NumHandles; Index++) {
+ //
+ // Open Unicode Collation Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Handles[Index],
+ ProtocolGuid,
+ (VOID **) &Uci,
+ AgentHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Find the best matching matching language from the supported languages
+ // of Unicode Collation (2) protocol.
+ //
+ BestLanguage = GetBestLanguage (
+ Uci->SupportedLanguages,
+ Iso639Language,
+ (Language == NULL) ? "" : Language,
+ DefaultLanguage,
+ NULL
+ );
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ mUnicodeCollation = Uci;
+ ReturnStatus = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ if (Language != NULL) {
+ FreePool (Language);
+ }
+
+ FreePool (Handles);
+
+ return ReturnStatus;
+}
+
+/**
+ Initialize Unicode Collation support.
+
+ It tries to locate Unicode Collation 2 protocol and matches it with current
+ platform language code. If for any reason the first attempt fails, it then tries to
+ use Unicode Collation Protocol.
+
+ @param AgentHandle The handle used to open Unicode Collation (2) protocol.
+
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
+ @retval Others The Unicode Collation (2) protocol has not been located.
+
+**/
+EFI_STATUS
+InitializeUnicodeCollationSupport (
+ IN EFI_HANDLE AgentHandle
+ )
+{
+
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // First try to use RFC 4646 Unicode Collation 2 Protocol.
+ //
+ Status = InitializeUnicodeCollationSupportWorker (
+ AgentHandle,
+ &gEfiUnicodeCollation2ProtocolGuid,
+ L"PlatformLang",
+ (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang)
+ );
+ //
+ // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back
+ // on the ISO 639-2 Unicode Collation Protocol.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = InitializeUnicodeCollationSupportWorker (
+ AgentHandle,
+ &gEfiUnicodeCollationProtocolGuid,
+ L"Lang",
+ (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+}
+
+/**
+ Start this driver on ControllerHandle by opening a FV protocol and
+ installing a SimpleFileSystem protocol on ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ FV_FILESYSTEM_INSTANCE *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_GUID *FvGuid;
+ UINTN NumChars;
+
+ Status = InitializeUnicodeCollationSupport (DriverBinding->DriverBindingHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open FV protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &FvProtocol,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create an instance
+ //
+ Instance = AllocateZeroPool (sizeof (FV_FILESYSTEM_INSTANCE));
+ ASSERT (Instance != NULL);
+
+ Instance->Root = NULL;
+ Instance->FvProtocol = FvProtocol;
+ Instance->Signature = FVFS_INSTANCE_SIGNATURE;
+ InitializeListHead (&Instance->FileInfoHead);
+ InitializeListHead (&Instance->FileHead);
+ CopyMem (&Instance->SimpleFs, &mSimpleFsTemplate, sizeof (mSimpleFsTemplate));
+
+ Status = gBS->InstallProtocolInterface(
+ &ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Instance->SimpleFs
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Decide on a filesystem volume label, which will include the FV's guid.
+ // Get the device path to find the FV's GUID
+ //
+ Instance->VolumeLabel = NULL;
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &FvDevicePath,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Iterate over device path until we find a firmware volume node
+ //
+ while (!IsDevicePathEndType (FvDevicePath)) {
+ if (DevicePathType (FvDevicePath) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (FvDevicePath) == MEDIA_PIWG_FW_VOL_DP) {
+ //
+ // Allocate the volume label
+ //
+ Instance->VolumeLabel = AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE);
+ //
+ // Check the allocation was successful
+ //
+ if (Instance->VolumeLabel != NULL) {
+ //
+ // Extract the FV's guid
+ //
+ FvGuid = &((MEDIA_FW_VOL_DEVICE_PATH *) FvDevicePath)->FvName;
+ //
+ // Build the volume label string
+ //
+ NumChars = UnicodeSPrint (
+ Instance->VolumeLabel,
+ FVFS_VOLUME_LABEL_SIZE,
+ FVFS_VOLUME_LABEL_PREFIX L"%g",
+ FvGuid
+ );
+ ASSERT ((NumChars + 1) * sizeof (CHAR16) == FVFS_VOLUME_LABEL_SIZE);
+ }
+ break;
+ }
+ FvDevicePath = NextDevicePathNode (FvDevicePath);
+ }
+ }
+ //
+ // If we didn't decide on a volume label, set a fallback one
+ //
+ if (Instance->VolumeLabel == NULL) {
+ Instance->VolumeLabel = AllocateCopyPool (
+ sizeof (FVFS_FALLBACK_VOLUME_LABEL),
+ FVFS_FALLBACK_VOLUME_LABEL
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing
+ the FV protocol on ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ FV_FILESYSTEM_INSTANCE *Instance;
+ FV_FILESYSTEM_FILE_INFO *FvFileInfo;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *DelEntry;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFile;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &SimpleFile,
+ DriverBinding->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile);
+
+ if (IsListEmpty (&Instance->FileHead) == FALSE) {
+ //
+ // Not all opened files are closed
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close and uninstall protocols.
+ //
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->UninstallProtocolInterface (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Instance->SimpleFs
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free file structures
+ //
+ if (!IsListEmpty (&Instance->FileInfoHead)) {
+ //
+ // Free the Subtask list.
+ //
+ for(Entry = Instance->FileInfoHead.ForwardLink;
+ Entry != (&Instance->FileInfoHead);
+ ) {
+ DelEntry = Entry;
+ Entry = Entry->ForwardLink;
+ FvFileInfo = FVFS_FILE_INFO_FROM_LINK (DelEntry);
+
+ RemoveEntryList (DelEntry);
+ FreePool (FvFileInfo);
+ }
+ }
+
+ if (Instance->Root != NULL) {
+ //
+ // Root->Name is statically allocated, no need to free.
+ //
+ if (Instance->Root->FvFileInfo != NULL) {
+ FreePool (Instance->Root->FvFileInfo);
+ }
+ FreePool (Instance->Root);
+ }
+
+ //
+ // Free Instance
+ //
+ if (Instance->VolumeLabel != NULL) {
+ FreePool (Instance->VolumeLabel);
+ }
+ FreePool (Instance);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module FvSimpleFileSystem. 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
+FvSimpleFileSystemEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mDriverBinding,
+ ImageHandle,
+ &gFvSimpleFileSystemComponentName,
+ &gFvSimpleFileSystemComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemExtra.uni b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemExtra.uni
new file mode 100644
index 000000000..48d2b64b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// FvSimpleFileSystem Driver's Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"FvSimpleFileSystem UEFI Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemInternal.h b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemInternal.h
new file mode 100644
index 000000000..dea2b7a21
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemInternal.h
@@ -0,0 +1,616 @@
+/** @file
+ The internal header file of FvSimpleFileSystem driver.
+
+Copyright (c) 2014, ARM Limited. All rights reserved.
+Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FVFS_INTERNAL_H__
+#define __FVFS_INTERNAL_H__
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+
+typedef struct _FV_FILESYSTEM_FILE FV_FILESYSTEM_FILE;
+typedef struct _FV_FILESYSTEM_FILE_INFO FV_FILESYSTEM_FILE_INFO;
+typedef struct _FV_FILESYSTEM_INSTANCE FV_FILESYSTEM_INSTANCE;
+
+//
+// Struct representing an instance of the "filesystem". There will be one of
+// these structs per FV.
+//
+struct _FV_FILESYSTEM_INSTANCE {
+ UINT32 Signature;
+ LIST_ENTRY FileInfoHead;
+ LIST_ENTRY FileHead;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs;
+ FV_FILESYSTEM_FILE *Root;
+ CHAR16 *VolumeLabel;
+};
+
+//
+// Struct representing a opening file. Each opening operation on file will
+// create such an instance except for the "root directory", which will only
+// be created once for each FV.
+//
+struct _FV_FILESYSTEM_FILE {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ FV_FILESYSTEM_FILE_INFO *DirReadNext;
+ FV_FILESYSTEM_INSTANCE *Instance;
+ EFI_FILE_PROTOCOL FileProtocol;
+ FV_FILESYSTEM_FILE_INFO *FvFileInfo;
+ UINT64 Position;
+};
+
+//
+// Struct representing the info of a file.
+//
+struct _FV_FILESYSTEM_FILE_INFO {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_GUID NameGuid;
+ EFI_FV_FILETYPE Type;
+ EFI_FILE_INFO FileInfo;
+};
+
+#define FVFS_FILE_SIGNATURE SIGNATURE_32 ('f', 'v', 'f', 'i')
+#define FVFS_FILE_INFO_SIGNATURE SIGNATURE_32 ('f', 'v', 'i', 'n')
+#define FVFS_INSTANCE_SIGNATURE SIGNATURE_32 ('f', 'v', 'f', 's')
+
+#define FVFS_INSTANCE_FROM_SIMPLE_FS_THIS(This) CR ( \
+ This, \
+ FV_FILESYSTEM_INSTANCE, \
+ SimpleFs, \
+ FVFS_INSTANCE_SIGNATURE \
+ )
+
+#define FVFS_FILE_FROM_FILE_THIS(This) CR ( \
+ This, \
+ FV_FILESYSTEM_FILE, \
+ FileProtocol, \
+ FVFS_FILE_SIGNATURE \
+ )
+
+#define FVFS_FILE_INFO_FROM_LINK(This) CR ( \
+ This, \
+ FV_FILESYSTEM_FILE_INFO, \
+ Link, \
+ FVFS_FILE_INFO_SIGNATURE \
+ )
+
+#define FVFS_FILE_FROM_LINK(FileLink) CR (FileLink, FV_FILESYSTEM_FILE, Link, FVFS_FILE_SIGNATURE)
+
+#define FVFS_GET_FIRST_FILE(Instance) FVFS_FILE_FROM_LINK (GetFirstNode (&Instance->FileHead))
+
+#define FVFS_GET_FIRST_FILE_INFO(Instance) FVFS_FILE_INFO_FROM_LINK (GetFirstNode (&Instance->FileInfoHead))
+
+
+#define FV_FILETYPE_IS_EXECUTABLE(Type) ((Type) == EFI_FV_FILETYPE_PEIM || \
+ (Type) == EFI_FV_FILETYPE_DRIVER || \
+ (Type) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER || \
+ (Type) == EFI_FV_FILETYPE_APPLICATION)
+
+/**
+ Open the root directory on a volume.
+
+ @param This A pointer to the volume to open the root directory.
+ @param RootFile A pointer to the location to return the opened file handle for the
+ root directory.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the requested file system type.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
+ longer supported. Any existing file handles for this volume are
+ no longer valid. To access the files on the new medium, the
+ volume must be reopened with OpenVolume().
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **RootFile
+ );
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a FV protocol and
+ installing a SimpleFileSystem protocol on ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing
+ the FV protocol on ControllerHandle.
+
+ @param DriverBinding 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
+FvSimpleFileSystemDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to the source location. This would typically be an open
+ handle to a directory.
+ @param NewHandle A pointer to the location to return the opened handle for the new
+ file.
+ @param FileName The Null-terminated string of the name of the file to be opened.
+ The file name may contain the following path modifiers: "\", ".",
+ and "..".
+ @param OpenMode The mode to open the file. The only valid combinations that the
+ file may be opened with are: Read, Read/Write, or Create/Read/Write.
+ @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
+ attribute bits for the newly created file.
+
+ @retval EFI_SUCCESS The file was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
+ longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
+ when the media is write-protected.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+/**
+ Closes a specified file handle.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to close.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemClose (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Reads data from a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to read data from.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of data
+ returned in Buffer. In both cases, the size is measured in bytes.
+ @param Buffer The buffer into which the data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
+ @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
+ entry. BufferSize has been updated with the size
+ needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes data to a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to write data to.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of data
+ actually written. In both cases, the size is measured in bytes.
+ @param Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to open directory files are not supported.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Returns a file's current position.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to get the current position on.
+ @param Position The address to return the file's current position value.
+
+ @retval EFI_SUCCESS The position was returned.
+ @retval EFI_UNSUPPORTED The request is not valid on open directories.
+ @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ );
+
+/**
+ Sets a file's current position.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ file handle to set the requested position on.
+ @param Position The byte position from the start of the file to set.
+
+ @retval EFI_SUCCESS The position was set.
+ @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
+ directories.
+ @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ );
+
+/**
+ Flushes all modified data associated with a file to a device.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to flush.
+
+ @retval EFI_SUCCESS The data was flushed.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
+ @retval EFI_ACCESS_DENIED The file was opened read-only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemFlush (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Close and delete the file handle.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ handle to the file to delete.
+
+ @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemDelete (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Returns information about a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle the requested information is for.
+ @param InformationType The type identifier for the information being requested.
+ @param BufferSize On input, the size of Buffer. On output, the amount of data
+ returned in Buffer. In both cases, the size is measured in bytes.
+ @param Buffer A pointer to the data buffer to return. The buffer's type is
+ indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was returned.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+ BufferSize has been updated with the size needed to complete
+ the request.
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Sets information about a file.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle the information is for.
+ @param InformationType The type identifier for the information being set.
+ @param BufferSize The size, in bytes, of Buffer.
+ @param Buffer A pointer to the data buffer to write. The buffer's type is
+ indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the media is
+ read-only.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
+ and the media is read only.
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
+ and the media is read-only.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file to a
+ file that is already present.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_FILE_DIRECTORY
+ Attribute.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the size of a directory.
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the file was opened
+ read-only and an attempt is being made to modify a field
+ other than Attribute.
+ @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type indicated
+ by InformationType.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSimpleFileSystemSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Get the size of the buffer that will be returned by FvFsReadFile.
+
+ @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
+ @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
+ representing a file's info.
+
+ @retval EFI_SUCCESS The file size was gotten correctly.
+ @retval Others The file size wasn't gotten correctly.
+
+**/
+EFI_STATUS
+FvFsGetFileSize (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol,
+ IN OUT FV_FILESYSTEM_FILE_INFO *FvFileInfo
+ );
+
+/**
+ 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
+FvSimpleFileSystemComponentNameGetDriverName (
+ 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
+FvSimpleFileSystemComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+extern EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation;
+extern EFI_FILE_PROTOCOL mFileSystemTemplate;
+extern EFI_COMPONENT_NAME_PROTOCOL gFvSimpleFileSystemComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gFvSimpleFileSystemComponentName2;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
new file mode 100644
index 000000000..5ee866fb9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
@@ -0,0 +1,3329 @@
+/** @file
+Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+extern HII_DATABASE_PRIVATE_DATA mPrivate;
+
+/**
+ Convert the hex UNICODE %02x encoding of a UEFI device path to binary
+ from <PathHdr> of <MultiKeywordRequest>.
+
+ This is a internal function.
+
+ @param String MultiKeywordRequest string.
+ @param DevicePathData Binary of a UEFI device path.
+ @param NextString string follow the possible PathHdr string.
+
+ @retval EFI_INVALID_PARAMETER The device path is not valid or the incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store necessary structures.
+ @retval EFI_SUCCESS The device path is retrieved and translated to binary format.
+ The Input string not include PathHdr section.
+
+**/
+EFI_STATUS
+ExtractDevicePath (
+ IN EFI_STRING String,
+ OUT UINT8 **DevicePathData,
+ OUT EFI_STRING *NextString
+ )
+{
+ UINTN Length;
+ EFI_STRING PathHdr;
+ UINT8 *DevicePathBuffer;
+ CHAR16 TemStr[2];
+ UINTN Index;
+ UINT8 DigitUint8;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ ASSERT (NextString != NULL && DevicePathData != NULL);
+
+ //
+ // KeywordRequest == NULL case.
+ //
+ if (String == NULL) {
+ *DevicePathData = NULL;
+ *NextString = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip '&' if exist.
+ //
+ if (*String == L'&') {
+ String ++;
+ }
+
+ //
+ // Find the 'PATH=' of <PathHdr>.
+ //
+ if (StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0) {
+ if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Not include PathHdr, return success and DevicePath = NULL.
+ //
+ *DevicePathData = NULL;
+ *NextString = String;
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Check whether path data does exist.
+ //
+ String += StrLen (L"PATH=");
+ if (*String == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ PathHdr = String;
+
+ //
+ // The content between 'PATH=' of <ConfigHdr> and '&' of next element
+ // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
+ // of UEFI device path.
+ //
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+
+ //
+ // Save the return next keyword string value.
+ //
+ *NextString = String;
+
+ //
+ // Check DevicePath Length
+ //
+ if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
+ // as the device path resides in RAM memory.
+ // Translate the data into binary.
+ //
+ DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (DevicePathBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Convert DevicePath
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = PathHdr[Index];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DevicePathBuffer [Index/2] = DigitUint8;
+ } else {
+ DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
+ }
+ }
+
+ //
+ // Validate DevicePath
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
+ //
+ // Invalid device path
+ //
+ FreePool (DevicePathBuffer);
+ return EFI_INVALID_PARAMETER;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // return the device path
+ //
+ *DevicePathData = DevicePathBuffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get NameSpace from the input NameSpaceId string.
+
+ This is a internal function.
+
+ @param String <NameSpaceId> format string.
+ @param NameSpace Return the name space string.
+ @param NextString Return the next string follow namespace.
+
+ @retval EFI_SUCCESS Get the namespace string success.
+ @retval EFI_INVALID_PARAMETER The NameSpaceId string not follow spec definition.
+
+**/
+EFI_STATUS
+ExtractNameSpace (
+ IN EFI_STRING String,
+ OUT CHAR8 **NameSpace,
+ OUT EFI_STRING *NextString
+ )
+{
+ CHAR16 *TmpPtr;
+ UINTN NameSpaceSize;
+
+ ASSERT (NameSpace != NULL);
+
+ TmpPtr = NULL;
+
+ //
+ // Input NameSpaceId == NULL
+ //
+ if (String == NULL) {
+ *NameSpace = NULL;
+ if (NextString != NULL) {
+ *NextString = NULL;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip '&' if exist.
+ //
+ if (*String == L'&') {
+ String++;
+ }
+
+ if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ String += StrLen (L"NAMESPACE=");
+
+ TmpPtr = StrStr (String, L"&");
+ if (TmpPtr != NULL) {
+ *TmpPtr = 0;
+ }
+ if (NextString != NULL) {
+ *NextString = String + StrLen (String);
+ }
+
+ //
+ // Input NameSpace is unicode string. The language in String package is ascii string.
+ // Here will convert the unicode string to ascii and save it.
+ //
+ NameSpaceSize = StrLen (String) + 1;
+ *NameSpace = AllocatePool (NameSpaceSize);
+ if (*NameSpace == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UnicodeStrToAsciiStrS (String, *NameSpace, NameSpaceSize);
+
+ if (TmpPtr != NULL) {
+ *TmpPtr = L'&';
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Keyword from the input KeywordRequest string.
+
+ This is a internal function.
+
+ @param String KeywordRequestformat string.
+ @param Keyword return the extract keyword string.
+ @param NextString return the next string follow this keyword section.
+
+ @retval EFI_SUCCESS Success to get the keyword string.
+ @retval EFI_INVALID_PARAMETER Parse the input string return error.
+
+**/
+EFI_STATUS
+ExtractKeyword (
+ IN EFI_STRING String,
+ OUT EFI_STRING *Keyword,
+ OUT EFI_STRING *NextString
+ )
+{
+ EFI_STRING TmpPtr;
+
+ ASSERT ((Keyword != NULL) && (NextString != NULL));
+
+ TmpPtr = NULL;
+
+ //
+ // KeywordRequest == NULL case.
+ //
+ if (String == NULL) {
+ *Keyword = NULL;
+ *NextString = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip '&' if exist.
+ //
+ if (*String == L'&') {
+ String++;
+ }
+
+ if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ String += StrLen (L"KEYWORD=");
+
+ TmpPtr = StrStr (String, L"&");
+ if (TmpPtr != NULL) {
+ *TmpPtr = 0;
+ }
+ *NextString = String + StrLen (String);
+
+ *Keyword = AllocateCopyPool (StrSize (String), String);
+ if (*Keyword == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (TmpPtr != NULL) {
+ *TmpPtr = L'&';
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get value from the input KeywordRequest string.
+
+ This is a internal function.
+
+ @param String KeywordRequestformat string.
+ @param Value return the extract value string.
+ @param NextString return the next string follow this keyword section.
+
+ @retval EFI_SUCCESS Success to get the keyword string.
+ @retval EFI_INVALID_PARAMETER Parse the input string return error.
+
+**/
+EFI_STATUS
+ExtractValue (
+ IN EFI_STRING String,
+ OUT EFI_STRING *Value,
+ OUT EFI_STRING *NextString
+ )
+{
+ EFI_STRING TmpPtr;
+
+ ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL));
+
+ //
+ // Skip '&' if exist.
+ //
+ if (*String == L'&') {
+ String++;
+ }
+
+ if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ String += StrLen (L"VALUE=");
+
+ TmpPtr = StrStr (String, L"&");
+ if (TmpPtr != NULL) {
+ *TmpPtr = 0;
+ }
+ *NextString = String + StrLen (String);
+
+ *Value = AllocateCopyPool (StrSize (String), String);
+ if (*Value == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (TmpPtr != NULL) {
+ *TmpPtr = L'&';
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get filter from the input KeywordRequest string.
+
+ This is a internal function.
+
+ @param String KeywordRequestformat string.
+ @param FilterFlags return the filter condition.
+ @param NextString return the next string follow this keyword section.
+
+ @retval EFI_SUCCESS Success to get the keyword string.
+ @retval EFI_INVALID_PARAMETER Parse the input string return error.
+
+**/
+BOOLEAN
+ExtractFilter (
+ IN EFI_STRING String,
+ OUT UINT8 *FilterFlags,
+ OUT EFI_STRING *NextString
+ )
+{
+ CHAR16 *PathPtr;
+ CHAR16 *KeywordPtr;
+ BOOLEAN RetVal;
+
+ ASSERT ((FilterFlags != NULL) && (NextString != NULL));
+
+ //
+ // String end, no filter section.
+ //
+ if (String == NULL) {
+ *NextString = NULL;
+ return FALSE;
+ }
+
+ *FilterFlags = 0;
+ RetVal = TRUE;
+
+ //
+ // Skip '&' if exist.
+ //
+ if (*String == L'&') {
+ String++;
+ }
+
+ if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) {
+ //
+ // Find ReadOnly filter.
+ //
+ *FilterFlags |= EFI_KEYWORD_FILTER_READONY;
+ String += StrLen (L"ReadOnly");
+ } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) {
+ //
+ // Find ReadWrite filter.
+ //
+ *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE;
+ String += StrLen (L"ReadWrite");
+ } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) {
+ //
+ // Find Buffer Filter.
+ //
+ *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER;
+ String += StrLen (L"Buffer");
+ } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) {
+ //
+ // Find Numeric Filter
+ //
+ String += StrLen (L"Numeric");
+ if (*String != L':') {
+ *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC;
+ } else {
+ String++;
+ switch (*String) {
+ case L'1':
+ *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1;
+ break;
+ case L'2':
+ *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2;
+ break;
+ case L'4':
+ *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4;
+ break;
+ case L'8':
+ *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ String++;
+ }
+ } else {
+ //
+ // Check whether other filter item defined by Platform.
+ //
+ if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) ||
+ (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) {
+ //
+ // New KeywordRequest start, no platform defined filter.
+ //
+ } else {
+ //
+ // Platform defined filter rule.
+ // Just skip platform defined filter rule, return success.
+ //
+ PathPtr = StrStr(String, L"&PATH");
+ KeywordPtr = StrStr(String, L"&KEYWORD");
+ if (PathPtr != NULL && KeywordPtr != NULL) {
+ //
+ // If both sections exist, return the first follow string.
+ //
+ String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr;
+ } else if (PathPtr != NULL) {
+ //
+ // Should not exist PathPtr != NULL && KeywordPtr == NULL case.
+ //
+ ASSERT (FALSE);
+ } else if (KeywordPtr != NULL) {
+ //
+ // Just to the next keyword section.
+ //
+ String = KeywordPtr;
+ } else {
+ //
+ // Only has platform defined filter section, just skip it.
+ //
+ String += StrLen (String);
+ }
+ }
+ RetVal = FALSE;
+ }
+
+ *NextString = String;
+
+ return RetVal;
+}
+
+/**
+ Extract Readonly flag from opcode.
+
+ This is a internal function.
+
+ @param OpCodeData Input opcode for this question.
+
+ @retval TRUE This question is readonly.
+ @retval FALSE This question is not readonly.
+
+**/
+BOOLEAN
+ExtractReadOnlyFromOpCode (
+ IN UINT8 *OpCodeData
+ )
+{
+ EFI_IFR_QUESTION_HEADER *QuestionHdr;
+
+ ASSERT (OpCodeData != NULL);
+
+ QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+
+ return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0;
+}
+
+/**
+ Create a circuit to check the filter section.
+
+ This is a internal function.
+
+ @param OpCodeData The question binary ifr data.
+ @param KeywordRequest KeywordRequestformat string.
+ @param NextString return the next string follow this keyword section.
+ @param ReadOnly Return whether this question is read only.
+
+ @retval KEYWORD_HANDLER_NO_ERROR Success validate.
+ @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED Validate fail.
+
+**/
+UINT32
+ValidateFilter (
+ IN UINT8 *OpCodeData,
+ IN CHAR16 *KeywordRequest,
+ OUT CHAR16 **NextString,
+ OUT BOOLEAN *ReadOnly
+ )
+{
+ CHAR16 *NextFilter;
+ CHAR16 *StringPtr;
+ UINT8 FilterFlags;
+ EFI_IFR_QUESTION_HEADER *QuestionHdr;
+ EFI_IFR_OP_HEADER *OpCodeHdr;
+ UINT8 Flags;
+ UINT32 RetVal;
+
+ RetVal = KEYWORD_HANDLER_NO_ERROR;
+ StringPtr = KeywordRequest;
+
+ OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData;
+ QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
+ Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER));
+ } else {
+ Flags = 0;
+ }
+
+ //
+ // Get ReadOnly flag from Question.
+ //
+ *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData);
+
+ while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) {
+ switch (FilterFlags) {
+ case EFI_KEYWORD_FILTER_READONY:
+ if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_KEYWORD_FILTER_REAWRITE:
+ if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_KEYWORD_FILTER_BUFFER:
+ //
+ // Only these three opcode use numeric value type.
+ //
+ if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_KEYWORD_FILTER_NUMERIC:
+ if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_KEYWORD_FILTER_NUMERIC_1:
+ case EFI_KEYWORD_FILTER_NUMERIC_2:
+ case EFI_KEYWORD_FILTER_NUMERIC_4:
+ case EFI_KEYWORD_FILTER_NUMERIC_8:
+ if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+
+ //
+ // For numeric and oneof, it has flags field to specify the detail numeric type.
+ //
+ if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
+ switch (Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) {
+ RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ goto Done;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Jump to the next filter.
+ //
+ StringPtr = NextFilter;
+ }
+
+Done:
+ //
+ // The current filter which is processing.
+ //
+ *NextString = StringPtr;
+
+ return RetVal;
+}
+
+/**
+ Get HII_DATABASE_RECORD from the input device path info.
+
+ This is a internal function.
+
+ @param DevicePath UEFI device path protocol.
+
+ @retval Internal data base record.
+
+**/
+HII_DATABASE_RECORD *
+GetRecordFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ LIST_ENTRY *Link;
+ UINT8 *DevicePathPkg;
+ UINT8 *CurrentDevicePath;
+ UINTN DevicePathSize;
+ HII_DATABASE_RECORD *TempDatabase;
+
+ ASSERT (DevicePath != NULL);
+
+ for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
+ TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ DevicePathPkg = TempDatabase->PackageList->DevicePathPkg;
+ if (DevicePathPkg != NULL) {
+ CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
+ if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) {
+ return TempDatabase;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Calculate the size of StringSrc and output it. Also copy string text from src
+ to dest.
+
+ This is a internal function.
+
+ @param StringSrc Points to current null-terminated string.
+ @param BufferSize Length of the buffer.
+ @param StringDest Buffer to store the string text.
+
+ @retval EFI_SUCCESS The string text was outputted successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of resource.
+
+**/
+EFI_STATUS
+GetUnicodeStringTextAndSize (
+ IN UINT8 *StringSrc,
+ OUT UINTN *BufferSize,
+ OUT EFI_STRING *StringDest
+ )
+{
+ UINTN StringSize;
+ UINT8 *StringPtr;
+
+ ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL);
+
+ StringSize = sizeof (CHAR16);
+ StringPtr = StringSrc;
+ while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
+ StringSize += sizeof (CHAR16);
+ StringPtr += sizeof (CHAR16);
+ }
+
+ *StringDest = AllocatePool (StringSize);
+ if (*StringDest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (*StringDest, StringSrc, StringSize);
+
+ *BufferSize = StringSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the string id for the input keyword.
+
+ @param StringPackage Hii string package instance.
+ @param KeywordValue Input keyword value.
+ @param StringId The string's id, which is unique within PackageList.
+
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+**/
+EFI_STATUS
+GetStringIdFromString (
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN CHAR16 *KeywordValue,
+ OUT EFI_STRING_ID *StringId
+ )
+{
+ UINT8 *BlockHdr;
+ EFI_STRING_ID CurrentStringId;
+ UINTN BlockSize;
+ UINTN Index;
+ UINT8 *StringTextPtr;
+ UINTN Offset;
+ UINT16 StringCount;
+ UINT16 SkipCount;
+ UINT8 Length8;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINT32 Length32;
+ UINTN StringSize;
+ CHAR16 *String;
+ CHAR8 *AsciiKeywordValue;
+ UINTN KeywordValueSize;
+ EFI_STATUS Status;
+
+ ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL);
+ ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
+
+ CurrentStringId = 1;
+ Status = EFI_SUCCESS;
+ String = NULL;
+ BlockHdr = StringPackage->StringBlock;
+ BlockSize = 0;
+ Offset = 0;
+
+ //
+ // Make a ascii keyword value for later use.
+ //
+ KeywordValueSize = StrLen (KeywordValue) + 1;
+ AsciiKeywordValue = AllocatePool (KeywordValueSize);
+ if (AsciiKeywordValue == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UnicodeStrToAsciiStrS (KeywordValue, AsciiKeywordValue, KeywordValueSize);
+
+ while (*BlockHdr != EFI_HII_SIBT_END) {
+ switch (*BlockHdr) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
+ StringTextPtr = BlockHdr + Offset;
+ if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (String != NULL);
+ if (StrCmp(KeywordValue, String) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (String != NULL);
+ if (StrCmp(KeywordValue, String) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ for (Index = 0; Index < StringCount; Index++) {
+ Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (String != NULL);
+ BlockSize += StringSize;
+ if (StrCmp(KeywordValue, String) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < StringCount; Index++) {
+ Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (String != NULL);
+ BlockSize += StringSize;
+ if (StrCmp(KeywordValue, String) == 0) {
+ *StringId = CurrentStringId;
+ goto Done;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ CopyMem (
+ &Length8,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT8)
+ );
+ BlockSize += Length8;
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockSize += Ext2.Length;
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ CopyMem (
+ &Length32,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT32)
+ );
+
+ BlockSize += Length32;
+ break;
+
+ default:
+ break;
+ }
+
+ if (String != NULL) {
+ FreePool (String);
+ String = NULL;
+ }
+
+ BlockHdr = StringPackage->StringBlock + BlockSize;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Done:
+ if (AsciiKeywordValue != NULL) {
+ FreePool (AsciiKeywordValue);
+ }
+ if (String != NULL) {
+ FreePool (String);
+ }
+ return Status;
+}
+
+/**
+ Find the next valid string id for the input string id.
+
+ @param StringPackage Hii string package instance.
+ @param StringId The current string id which is already got.
+ 1 means just begin to get the string id.
+ @param KeywordValue Return the string for the next string id.
+
+
+ @retval EFI_STRING_ID Not 0 means a valid stringid found.
+ 0 means not found a valid string id.
+**/
+EFI_STRING_ID
+GetNextStringId (
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING *KeywordValue
+ )
+{
+ UINT8 *BlockHdr;
+ EFI_STRING_ID CurrentStringId;
+ UINTN BlockSize;
+ UINTN Index;
+ UINT8 *StringTextPtr;
+ UINTN Offset;
+ UINT16 StringCount;
+ UINT16 SkipCount;
+ UINT8 Length8;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINT32 Length32;
+ BOOLEAN FindString;
+ UINTN StringSize;
+ CHAR16 *String;
+
+ ASSERT (StringPackage != NULL);
+ ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
+
+ CurrentStringId = 1;
+ FindString = FALSE;
+ String = NULL;
+
+ //
+ // Parse the string blocks to get the string text and font.
+ //
+ BlockHdr = StringPackage->StringBlock;
+ BlockSize = 0;
+ Offset = 0;
+ while (*BlockHdr != EFI_HII_SIBT_END) {
+ switch (*BlockHdr) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+
+ if (FindString) {
+ StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
+ *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
+ if (*KeywordValue == NULL) {
+ return 0;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
+ StringTextPtr = BlockHdr + Offset;
+
+ if (FindString) {
+ StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
+ *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
+ if (*KeywordValue == NULL) {
+ return 0;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ if (FindString) {
+ StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
+ *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
+ if (*KeywordValue == NULL) {
+ return 0;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ if (FindString) {
+ StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
+ *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
+ if (*KeywordValue == NULL) {
+ return 0;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (FindString && (String != NULL) && (*String != L'\0')) {
+ //
+ // String protocol use this type for the string id which has value for other package.
+ // It will allocate an empty string block for this string id. so here we also check
+ // *String != L'\0' to prohibit this case.
+ //
+ *KeywordValue = String;
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (FindString) {
+ *KeywordValue = String;
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+
+ if (FindString) {
+ *KeywordValue = String;
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += StringSize;
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
+ if (FindString) {
+ *KeywordValue = String;
+ return CurrentStringId;
+ } else if (CurrentStringId == StringId) {
+ FindString = TRUE;
+ }
+
+ BlockSize += StringSize;
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ CopyMem (
+ &Length8,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT8)
+ );
+ BlockSize += Length8;
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockSize += Ext2.Length;
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ CopyMem (
+ &Length32,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT32)
+ );
+
+ BlockSize += Length32;
+ break;
+
+ default:
+ break;
+ }
+
+ if (String != NULL) {
+ FreePool (String);
+ String = NULL;
+ }
+
+ BlockHdr = StringPackage->StringBlock + BlockSize;
+ }
+
+ return 0;
+}
+
+/**
+ Get string package from the input NameSpace string.
+
+ This is a internal function.
+
+ @param DatabaseRecord HII_DATABASE_RECORD format string.
+ @param NameSpace NameSpace format string.
+ @param KeywordValue Keyword value.
+ @param StringId String Id for this keyword.
+
+ @retval KEYWORD_HANDLER_NO_ERROR Get String id successfully.
+ @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND Not found the string id in the string package.
+ @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND Not found the string package for this namespace.
+ @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR Out of resource error.
+
+**/
+UINT32
+GetStringIdFromRecord (
+ IN HII_DATABASE_RECORD *DatabaseRecord,
+ IN CHAR8 **NameSpace,
+ IN CHAR16 *KeywordValue,
+ OUT EFI_STRING_ID *StringId
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ EFI_STATUS Status;
+ CHAR8 *Name;
+ UINT32 RetVal;
+
+ ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL);
+
+ PackageListNode = DatabaseRecord->PackageList;
+ RetVal = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
+
+ if (*NameSpace != NULL) {
+ Name = *NameSpace;
+ } else {
+ Name = UEFI_CONFIG_LANG;
+ }
+
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+
+ if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) {
+ Status = GetStringIdFromString (StringPackage, KeywordValue, StringId);
+ if (EFI_ERROR (Status)) {
+ return KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
+ } else {
+ if (*NameSpace == NULL) {
+ *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
+ if (*NameSpace == NULL) {
+ return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
+ }
+ }
+ return KEYWORD_HANDLER_NO_ERROR;
+ }
+ }
+ }
+
+ return RetVal;
+}
+
+/**
+ Tell whether this Operand is an Statement OpCode.
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Statement OpCode.
+ @retval FALSE Not an Statement OpCode.
+
+**/
+BOOLEAN
+IsStatementOpCode (
+ IN UINT8 Operand
+ )
+{
+ if ((Operand == EFI_IFR_SUBTITLE_OP) ||
+ (Operand == EFI_IFR_TEXT_OP) ||
+ (Operand == EFI_IFR_RESET_BUTTON_OP) ||
+ (Operand == EFI_IFR_REF_OP) ||
+ (Operand == EFI_IFR_ACTION_OP) ||
+ (Operand == EFI_IFR_NUMERIC_OP) ||
+ (Operand == EFI_IFR_ORDERED_LIST_OP) ||
+ (Operand == EFI_IFR_CHECKBOX_OP) ||
+ (Operand == EFI_IFR_STRING_OP) ||
+ (Operand == EFI_IFR_PASSWORD_OP) ||
+ (Operand == EFI_IFR_DATE_OP) ||
+ (Operand == EFI_IFR_TIME_OP) ||
+ (Operand == EFI_IFR_GUID_OP) ||
+ (Operand == EFI_IFR_ONE_OF_OP)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Tell whether this Operand is an Statement OpCode.
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Statement OpCode.
+ @retval FALSE Not an Statement OpCode.
+
+**/
+BOOLEAN
+IsStorageOpCode (
+ IN UINT8 Operand
+ )
+{
+ if ((Operand == EFI_IFR_VARSTORE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Base on the prompt string id to find the question.
+
+ @param FormPackage The input form package.
+ @param KeywordStrId The input prompt string id for one question.
+
+ @retval the opcode for the question.
+
+**/
+UINT8 *
+FindQuestionFromStringId (
+ IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
+ IN EFI_STRING_ID KeywordStrId
+ )
+{
+ UINT8 *OpCodeData;
+ UINT32 Offset;
+ EFI_IFR_STATEMENT_HEADER *StatementHeader;
+ EFI_IFR_OP_HEADER *OpCodeHeader;
+ UINT32 FormDataLen;
+
+ ASSERT (FormPackage != NULL);
+
+ FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
+ Offset = 0;
+ while (Offset < FormDataLen) {
+ OpCodeData = FormPackage->IfrData + Offset;
+ OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
+
+ if (IsStatementOpCode(OpCodeHeader->OpCode)) {
+ StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ if (StatementHeader->Prompt == KeywordStrId) {
+ return OpCodeData;
+ }
+ }
+
+ Offset += OpCodeHeader->Length;
+ }
+
+ return NULL;
+}
+
+/**
+ Base on the varstore id to find the storage info.
+
+ @param FormPackage The input form package.
+ @param VarStoreId The input storage id.
+
+ @retval the opcode for the storage.
+
+**/
+UINT8 *
+FindStorageFromVarId (
+ IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
+ IN EFI_VARSTORE_ID VarStoreId
+ )
+{
+ UINT8 *OpCodeData;
+ UINT32 Offset;
+ EFI_IFR_OP_HEADER *OpCodeHeader;
+ UINT32 FormDataLen;
+
+ ASSERT (FormPackage != NULL);
+
+ FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
+ Offset = 0;
+ while (Offset < FormDataLen) {
+ OpCodeData = FormPackage->IfrData + Offset;
+ OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
+
+ if (IsStorageOpCode(OpCodeHeader->OpCode)) {
+ switch (OpCodeHeader->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) {
+ return OpCodeData;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) {
+ return OpCodeData;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) {
+ return OpCodeData;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ Offset += OpCodeHeader->Length;
+ }
+
+ return NULL;
+}
+
+/**
+ Get width info for one question.
+
+ @param OpCodeData The input opcode for one question.
+
+ @retval the width info for one question.
+
+**/
+UINT16
+GetWidth (
+ IN UINT8 *OpCodeData
+ )
+{
+ UINT8 *NextOpCodeData;
+
+ ASSERT (OpCodeData != NULL);
+
+ switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) {
+ case EFI_IFR_REF_OP:
+ return (UINT16) sizeof (EFI_HII_REF);
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ return (UINT16) sizeof (UINT8);
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ return (UINT16) sizeof (UINT16);
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ return (UINT16) sizeof (UINT32);
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ return (UINT16) sizeof (UINT64);
+
+ default:
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length;
+ //
+ // OneOfOption must follow the orderedlist opcode.
+ //
+ ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP);
+ switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ default:
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ case EFI_IFR_CHECKBOX_OP:
+ return (UINT16) sizeof (BOOLEAN);
+
+ case EFI_IFR_PASSWORD_OP:
+ return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16));
+
+ case EFI_IFR_STRING_OP:
+ return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16));
+
+ case EFI_IFR_DATE_OP:
+ return (UINT16) sizeof (EFI_HII_DATE);
+
+ case EFI_IFR_TIME_OP:
+ return (UINT16) sizeof (EFI_HII_TIME);
+
+ default:
+ ASSERT (FALSE);
+ return 0;
+ }
+}
+
+/**
+ Converts all hex string characters in range ['A'..'F'] to ['a'..'f'] for
+ hex digits that appear between a '=' and a '&' in a config string.
+
+ If ConfigString is NULL, then ASSERT().
+
+ @param[in] ConfigString Pointer to a Null-terminated Unicode string.
+
+ @return Pointer to the Null-terminated Unicode result string.
+
+**/
+EFI_STRING
+EFIAPI
+InternalLowerConfigString (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+
+ return ConfigString;
+}
+
+/**
+ Allocates and returns a Null-terminated Unicode <ConfigHdr> string.
+
+ The format of a <ConfigHdr> is as follows:
+
+ GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
+
+ @param[in] OpCodeData The opcode for the storage.
+ @param[in] DriverHandle The driver handle which supports a Device Path Protocol
+ that is the routing information PATH. Each byte of
+ the Device Path associated with DriverHandle is converted
+ to a 2 Unicode character hexadecimal string.
+
+ @retval NULL DriverHandle does not support the Device Path Protocol.
+ @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
+
+**/
+EFI_STRING
+ConstructConfigHdr (
+ IN UINT8 *OpCodeData,
+ IN EFI_HANDLE DriverHandle
+ )
+{
+ UINTN NameLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DevicePathSize;
+ CHAR16 *String;
+ CHAR16 *ReturnString;
+ UINTN Index;
+ UINT8 *Buffer;
+ CHAR16 *Name;
+ CHAR8 *AsciiName;
+ UINTN NameSize;
+ EFI_GUID *Guid;
+ UINTN MaxLen;
+
+ ASSERT (OpCodeData != NULL);
+
+ switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
+ AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
+ AsciiName = NULL;
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
+ AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ Guid = NULL;
+ AsciiName = NULL;
+ break;
+ }
+
+ if (AsciiName != NULL) {
+ NameSize = AsciiStrSize (AsciiName);
+ Name = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ ASSERT (Name != NULL);
+ AsciiStrToUnicodeStrS (AsciiName, Name, NameSize);
+ } else {
+ Name = NULL;
+ }
+
+ //
+ // Compute the length of Name in Unicode characters.
+ // If Name is NULL, then the length is 0.
+ //
+ NameLength = 0;
+ if (Name != NULL) {
+ NameLength = StrLen (Name);
+ }
+
+ DevicePath = NULL;
+ DevicePathSize = 0;
+ //
+ // Retrieve DevicePath Protocol associated with DriverHandle
+ //
+ if (DriverHandle != NULL) {
+ DevicePath = DevicePathFromHandle (DriverHandle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+ //
+ // Compute the size of the device path in bytes
+ //
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ }
+
+ //
+ // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
+ // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
+ //
+ MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
+ String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ if (String == NULL) {
+ return NULL;
+ }
+
+ //
+ // Start with L"GUID="
+ //
+ StrCpyS (String, MaxLen, L"GUID=");
+ ReturnString = String;
+ String += StrLen (String);
+
+ if (Guid != NULL) {
+ //
+ // Append Guid converted to <HexCh>32
+ //
+ for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
+ UnicodeValueToStringS (
+ String,
+ MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *(Buffer++),
+ 2
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+ }
+
+ //
+ // Append L"&NAME="
+ //
+ StrCatS (ReturnString, MaxLen, L"&NAME=");
+ String += StrLen (String);
+
+ if (Name != NULL) {
+ //
+ // Append Name converted to <Char>NameLength
+ //
+ for (; *Name != L'\0'; Name++) {
+ UnicodeValueToStringS (
+ String,
+ MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *Name,
+ 4
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+ }
+
+ //
+ // Append L"&PATH="
+ //
+ StrCatS (ReturnString, MaxLen, L"&PATH=");
+ String += StrLen (String);
+
+ //
+ // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
+ //
+ for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
+ UnicodeValueToStringS (
+ String,
+ MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
+ PREFIX_ZERO | RADIX_HEX,
+ *(Buffer++),
+ 2
+ );
+ String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
+ }
+
+ //
+ // Null terminate the Unicode string
+ //
+ *String = L'\0';
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ return InternalLowerConfigString (ReturnString);
+}
+
+/**
+ Generate the Config request element for one question.
+
+ @param Name The name info for one question.
+ @param Offset The offset info for one question.
+ @param Width The width info for one question.
+
+ @return Pointer to the Null-terminated Unicode request element string.
+
+**/
+EFI_STRING
+ConstructRequestElement (
+ IN CHAR16 *Name,
+ IN UINT16 Offset,
+ IN UINT16 Width
+ )
+{
+ CHAR16 *StringPtr;
+ UINTN Length;
+
+ if (Name != NULL) {
+ //
+ // Add <BlockName> length for each Name
+ //
+ // <BlockName> ::= Name + \0
+ // StrLen(Name) | 1
+ //
+ Length = StrLen (Name) + 1;
+ } else {
+ //
+ // Add <BlockName> length for each Offset/Width pair
+ //
+ // <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0
+ // | 7 | 4 | 7 | 4 | 1
+ //
+ Length = (7 + 4 + 7 + 4 + 1);
+ }
+
+ //
+ // Allocate buffer for the entire <ConfigRequest>
+ //
+ StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
+ ASSERT (StringPtr != NULL);
+
+ if (Name != NULL) {
+ //
+ // Append Name\0
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (StrLen (Name) + 1) * sizeof (CHAR16),
+ L"%s",
+ Name
+ );
+ } else {
+ //
+ // Append OFFSET=XXXX&WIDTH=YYYY\0
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
+ L"OFFSET=%04X&WIDTH=%04X",
+ Offset,
+ Width
+ );
+ }
+
+ return StringPtr;
+}
+
+/**
+ Get string value for question's name field.
+
+ @param DatabaseRecord HII_DATABASE_RECORD format string.
+ @param NameId The string id for the name field.
+
+ @retval Name string.
+
+**/
+CHAR16 *
+GetNameFromId (
+ IN HII_DATABASE_RECORD *DatabaseRecord,
+ IN EFI_STRING_ID NameId
+ )
+{
+ CHAR16 *Name;
+ CHAR8 *PlatformLanguage;
+ CHAR8 *SupportedLanguages;
+ CHAR8 *BestLanguage;
+ UINTN StringSize;
+ CHAR16 TempString;
+ EFI_STATUS Status;
+
+ Name = NULL;
+ BestLanguage = NULL;
+ PlatformLanguage = NULL;
+ SupportedLanguages = NULL;
+
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
+ SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle);
+
+ //
+ // Get the best matching language from SupportedLanguages
+ //
+ BestLanguage = GetBestLanguage (
+ SupportedLanguages,
+ FALSE, // RFC 4646 mode
+ PlatformLanguage != NULL ? PlatformLanguage : "", // Highest priority
+ SupportedLanguages, // Lowest priority
+ NULL
+ );
+ if (BestLanguage == NULL) {
+ BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US");
+ ASSERT (BestLanguage != NULL);
+ }
+
+ StringSize = 0;
+ Status = mPrivate.HiiString.GetString (
+ &mPrivate.HiiString,
+ BestLanguage,
+ DatabaseRecord->Handle,
+ NameId,
+ &TempString,
+ &StringSize,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Done;
+ }
+
+ Name = AllocateZeroPool (StringSize);
+ if (Name == NULL) {
+ goto Done;
+ }
+
+ Status = mPrivate.HiiString.GetString (
+ &mPrivate.HiiString,
+ BestLanguage,
+ DatabaseRecord->Handle,
+ NameId,
+ Name,
+ &StringSize,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Name);
+ Name = NULL;
+ goto Done;
+ }
+
+Done:
+ if (SupportedLanguages != NULL) {
+ FreePool(SupportedLanguages);
+ }
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ }
+ if (PlatformLanguage != NULL) {
+ FreePool (PlatformLanguage);
+ }
+
+ return Name;
+}
+
+/**
+ Base on the input parameter to generate the ConfigRequest string.
+
+ This is a internal function.
+
+ @param DatabaseRecord HII_DATABASE_RECORD format string.
+ @param KeywordStrId Keyword string id.
+ @param OpCodeData The IFR data for this question.
+ @param ConfigRequest Return the generate ConfigRequest string.
+
+ @retval EFI_SUCCESS Generate ConfigResp string success.
+ @retval EFI_OUT_OF_RESOURCES System out of memory resource error.
+ @retval EFI_NOT_FOUND Not found the question which use this string id
+ as the prompt string id.
+**/
+EFI_STATUS
+ExtractConfigRequest (
+ IN HII_DATABASE_RECORD *DatabaseRecord,
+ IN EFI_STRING_ID KeywordStrId,
+ OUT UINT8 **OpCodeData,
+ OUT EFI_STRING *ConfigRequest
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ EFI_IFR_QUESTION_HEADER *Header;
+ UINT8 *Storage;
+ UINT8 *OpCode;
+ CHAR16 *Name;
+ UINT16 Offset;
+ UINT16 Width;
+ CHAR16 *ConfigHdr;
+ CHAR16 *RequestElement;
+ UINTN MaxLen;
+ CHAR16 *StringPtr;
+
+ ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL);
+
+ OpCode = NULL;
+ Name = NULL;
+ Width = 0;
+ Offset = 0;
+
+ PackageListNode = DatabaseRecord->PackageList;
+
+ //
+ // Search the languages in the specified packagelist.
+ //
+ for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
+ FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
+
+ OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
+ if (OpCode != NULL) {
+ *OpCodeData = OpCode;
+ Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
+ //
+ // Header->VarStoreId == 0 means no storage for this question.
+ //
+ ASSERT (Header->VarStoreId != 0);
+ DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
+
+ Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
+ ASSERT (Storage != NULL);
+
+ if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
+ Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
+ } else {
+ Offset = Header->VarStoreInfo.VarOffset;
+ Width = GetWidth (OpCode);
+ }
+ RequestElement = ConstructRequestElement(Name, Offset, Width);
+ ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
+ ASSERT (ConfigHdr != NULL);
+
+ MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1;
+ *ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16));
+ if (*ConfigRequest == NULL) {
+ FreePool (ConfigHdr);
+ FreePool (RequestElement);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StringPtr = *ConfigRequest;
+
+ StrCpyS (StringPtr, MaxLen, ConfigHdr);
+
+ StrCatS (StringPtr, MaxLen, L"&");
+
+ StrCatS (StringPtr, MaxLen, RequestElement);
+
+ FreePool (ConfigHdr);
+ FreePool (RequestElement);
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Base on the input parameter to generate the ConfigResp string.
+
+ This is a internal function.
+
+ @param DatabaseRecord HII_DATABASE_RECORD format string.
+ @param KeywordStrId Keyword string id.
+ @param ValueElement The value for the question which use keyword string id
+ as the prompt string id.
+ @param OpCodeData The IFR data for this question.
+ @param ConfigResp Return the generate ConfigResp string.
+
+ @retval EFI_SUCCESS Generate ConfigResp string success.
+ @retval EFI_OUT_OF_RESOURCES System out of memory resource error.
+ @retval EFI_NOT_FOUND Not found the question which use this string id
+ as the prompt string id.
+**/
+EFI_STATUS
+ExtractConfigResp (
+ IN HII_DATABASE_RECORD *DatabaseRecord,
+ IN EFI_STRING_ID KeywordStrId,
+ IN EFI_STRING ValueElement,
+ OUT UINT8 **OpCodeData,
+ OUT EFI_STRING *ConfigResp
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ EFI_IFR_QUESTION_HEADER *Header;
+ UINT8 *Storage;
+ UINT8 *OpCode;
+ CHAR16 *Name;
+ UINT16 Offset;
+ UINT16 Width;
+ CHAR16 *ConfigHdr;
+ CHAR16 *RequestElement;
+ UINTN MaxLen;
+ CHAR16 *StringPtr;
+
+ ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL));
+
+ OpCode = NULL;
+ Name = NULL;
+ Width = 0;
+ Offset = 0;
+
+ PackageListNode = DatabaseRecord->PackageList;
+
+ //
+ // Search the languages in the specified packagelist.
+ //
+ for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
+ FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
+
+ OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
+ if (OpCode != NULL) {
+ *OpCodeData = OpCode;
+ Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
+ //
+ // Header->VarStoreId == 0 means no storage for this question.
+ //
+ ASSERT (Header->VarStoreId != 0);
+ DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
+
+ Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
+ ASSERT (Storage != NULL);
+
+ if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
+ Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
+ } else {
+ Offset = Header->VarStoreInfo.VarOffset;
+ Width = GetWidth (OpCode);
+ }
+ RequestElement = ConstructRequestElement(Name, Offset, Width);
+
+ ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
+ ASSERT (ConfigHdr != NULL);
+
+ MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1;
+ *ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16));
+ if (*ConfigResp == NULL) {
+ FreePool (ConfigHdr);
+ FreePool (RequestElement);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StringPtr = *ConfigResp;
+
+ StrCpyS (StringPtr, MaxLen, ConfigHdr);
+
+ StrCatS (StringPtr, MaxLen, L"&");
+
+
+ StrCatS (StringPtr, MaxLen, RequestElement);
+
+ StrCatS (StringPtr, MaxLen, L"&");
+
+ StrCatS (StringPtr, MaxLen, L"VALUE=");
+
+ StrCatS (StringPtr, MaxLen, ValueElement);
+
+ FreePool (ConfigHdr);
+ FreePool (RequestElement);
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get the Value section from the Hii driver.
+
+ This is a internal function.
+
+ @param ConfigRequest The input ConfigRequest string.
+ @param ValueElement The respond Value section from the hii driver.
+
+ @retval Misc value The error status return from ExtractConfig function.
+ @retval EFI_OUT_OF_RESOURCES The memory can't be allocated
+ @retval EFI_SUCCESS Get the value section success.
+
+**/
+EFI_STATUS
+ExtractValueFromDriver (
+ IN CHAR16 *ConfigRequest,
+ OUT CHAR16 **ValueElement
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Result;
+ EFI_STRING Progress;
+ CHAR16 *StringPtr;
+ CHAR16 *StringEnd;
+
+ ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL));
+
+ Status = mPrivate.ConfigRouting.ExtractConfig (
+ &mPrivate.ConfigRouting,
+ (EFI_STRING) ConfigRequest,
+ &Progress,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Value Section and return it.
+ //
+ StringPtr = StrStr (Result, L"&VALUE=");
+ ASSERT (StringPtr != NULL);
+ StringEnd = StrStr (StringPtr + 1, L"&");
+ if (StringEnd != NULL) {
+ *StringEnd = L'\0';
+ }
+
+ *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr);
+ if (*ValueElement == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (StringEnd != NULL) {
+ *StringEnd = L'&';
+ }
+ FreePool (Result);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get EFI_STRING_ID info from the input device path, namespace and keyword.
+
+ This is a internal function.
+
+ @param DevicePath Input device path info.
+ @param NameSpace NameSpace format string.
+ @param KeywordData Keyword used to get string id.
+ @param ProgressErr Return extra error type.
+ @param KeywordStringId Return EFI_STRING_ID.
+ @param DataBaseRecord DataBase record data for this driver.
+
+ @retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace.
+ @retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword.
+ @retval EFI_SUCCESS Find the EFI_STRING_ID.
+
+**/
+EFI_STATUS
+GetStringIdFromDatabase (
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ IN CHAR8 **NameSpace,
+ IN CHAR16 *KeywordData,
+ OUT UINT32 *ProgressErr,
+ OUT EFI_STRING_ID *KeywordStringId,
+ OUT HII_DATABASE_RECORD **DataBaseRecord
+ )
+{
+ HII_DATABASE_RECORD *Record;
+ LIST_ENTRY *Link;
+ BOOLEAN FindNameSpace;
+ EFI_DEVICE_PATH_PROTOCOL *DestDevicePath;
+ UINT8 *DevicePathPkg;
+ UINTN DevicePathSize;
+
+ ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL));
+
+ FindNameSpace = FALSE;
+
+ if (*DevicePath != NULL) {
+ //
+ // Get DataBaseRecord from device path protocol.
+ //
+ Record = GetRecordFromDevicePath(*DevicePath);
+ if (Record == NULL) {
+ //
+ // Can't find the DatabaseRecord base on the input device path info.
+ // NEED TO CONFIRM the return ProgressErr.
+ //
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get string id from the record.
+ //
+ *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
+ switch (*ProgressErr) {
+ case KEYWORD_HANDLER_NO_ERROR:
+ *DataBaseRecord = Record;
+ return EFI_SUCCESS;
+
+ case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND:
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND);
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ //
+ // Find driver which matches the routing data.
+ //
+ for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
+ Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+
+ *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
+ if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) {
+ *DataBaseRecord = Record;
+
+ if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) {
+ DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER));
+ DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath);
+ *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath);
+ if (*DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // Need to verify this ASSERT.
+ //
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+ } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) {
+ return EFI_OUT_OF_RESOURCES;
+ } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) {
+ FindNameSpace = TRUE;
+ }
+ }
+
+ //
+ // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND.
+ // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND.
+ //
+ if (FindNameSpace) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+}
+
+/**
+ Generate the KeywordResp String.
+
+ <KeywordResp> ::= <NameSpaceId><PathHdr>'&'<Keyword>'&VALUE='<Number>['&READONLY']
+
+ @param NameSpace NameSpace format string.
+ @param DevicePath Input device path info.
+ @param KeywordData Keyword used to get string id.
+ @param ValueStr The value section for the keyword.
+ @param ReadOnly Whether this value is readonly.
+ @param KeywordResp Return the point to the KeywordResp string.
+
+ @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
+ @retval EFI_SUCCESS Generate the KeywordResp string.
+
+**/
+EFI_STATUS
+GenerateKeywordResp (
+ IN CHAR8 *NameSpace,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_STRING KeywordData,
+ IN EFI_STRING ValueStr,
+ IN BOOLEAN ReadOnly,
+ OUT EFI_STRING *KeywordResp
+ )
+{
+ UINTN RespStrLen;
+ CHAR16 *RespStr;
+ CHAR16 *PathHdr;
+ CHAR16 *UnicodeNameSpace;
+ UINTN NameSpaceLength;
+
+ ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL));
+
+ //
+ // 1. Calculate the string length.
+ //
+ //
+ // 1.1 NameSpaceId size.
+ // 'NAMESPACE='<String>
+ //
+ NameSpaceLength = AsciiStrLen (NameSpace);
+ RespStrLen = 10 + NameSpaceLength;
+ UnicodeNameSpace = AllocatePool ((NameSpaceLength + 1) * sizeof (CHAR16));
+ if (UnicodeNameSpace == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AsciiStrToUnicodeStrS (NameSpace, UnicodeNameSpace, NameSpaceLength + 1);
+
+ //
+ // 1.2 PathHdr size.
+ // PATH=<UEFI binary Device Path represented as hex number>'&'
+ // Attention: The output include the '&' at the end.
+ //
+ GenerateSubStr (
+ L"&PATH=",
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
+ (VOID *) DevicePath,
+ 1,
+ &PathHdr
+ );
+ RespStrLen += StrLen (PathHdr);
+
+ //
+ // 1.3 Keyword section.
+ // 'KEYWORD='<String>[':'<DecCh>(1/4)]
+ //
+ RespStrLen += 8 + StrLen (KeywordData);
+
+ //
+ // 1.4 Value section.
+ // ValueStr = '&VALUE='<Number>
+ //
+ RespStrLen += StrLen (ValueStr);
+
+ //
+ // 1.5 ReadOnly Section.
+ // '&READONLY'
+ //
+ if (ReadOnly) {
+ RespStrLen += 9;
+ }
+
+ //
+ // 2. Allocate the buffer and create the KeywordResp string include '\0'.
+ //
+ RespStrLen += 1;
+ *KeywordResp = AllocatePool (RespStrLen * sizeof (CHAR16));
+ if (*KeywordResp == NULL) {
+ if (UnicodeNameSpace != NULL) {
+ FreePool (UnicodeNameSpace);
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+ RespStr = *KeywordResp;
+
+ //
+ // 2.1 Copy NameSpaceId section.
+ //
+ StrCpyS (RespStr, RespStrLen, L"NAMESPACE=");
+
+ StrCatS (RespStr, RespStrLen, UnicodeNameSpace);
+
+ //
+ // 2.2 Copy PathHdr section.
+ //
+ StrCatS (RespStr, RespStrLen, PathHdr);
+
+ //
+ // 2.3 Copy Keyword section.
+ //
+ StrCatS (RespStr, RespStrLen, L"KEYWORD=");
+
+ StrCatS (RespStr, RespStrLen, KeywordData);
+
+ //
+ // 2.4 Copy the Value section.
+ //
+ StrCatS (RespStr, RespStrLen, ValueStr);
+
+ //
+ // 2.5 Copy ReadOnly section if exist.
+ //
+ if (ReadOnly) {
+ StrCatS (RespStr, RespStrLen, L"&READONLY");
+ }
+
+ if (UnicodeNameSpace != NULL) {
+ FreePool (UnicodeNameSpace);
+ }
+ if (PathHdr != NULL) {
+ FreePool (PathHdr);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Merge the KeywordResp String to MultiKeywordResp string.
+
+ This is a internal function.
+
+ @param MultiKeywordResp The existed multikeywordresp string.
+ @param KeywordResp The input keywordResp string.
+
+ @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
+ @retval EFI_SUCCESS Generate the MultiKeywordResp string.
+
+**/
+EFI_STATUS
+MergeToMultiKeywordResp (
+ IN OUT EFI_STRING *MultiKeywordResp,
+ IN EFI_STRING *KeywordResp
+ )
+{
+ UINTN MultiKeywordRespLen;
+ EFI_STRING StringPtr;
+
+ if (*MultiKeywordResp == NULL) {
+ *MultiKeywordResp = *KeywordResp;
+ *KeywordResp = NULL;
+ return EFI_SUCCESS;
+ }
+
+ MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16);
+
+ StringPtr = ReallocatePool (
+ StrSize (*MultiKeywordResp),
+ MultiKeywordRespLen,
+ *MultiKeywordResp
+ );
+ if (StringPtr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *MultiKeywordResp = StringPtr;
+
+ StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&");
+
+ StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enumerate all keyword in the system.
+
+ If error occur when parse one keyword, just skip it and parse the next one.
+
+ This is a internal function.
+
+ @param NameSpace The namespace used to search the string.
+ @param MultiResp Return the MultiKeywordResp string for the system.
+ @param ProgressErr Return the error status.
+
+ @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
+ @retval EFI_SUCCESS Generate the MultiKeywordResp string.
+ @retval EFI_NOT_FOUND No keyword found.
+
+**/
+EFI_STATUS
+EnumerateAllKeywords (
+ IN CHAR8 *NameSpace,
+ OUT EFI_STRING *MultiResp,
+ OUT UINT32 *ProgressErr
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *StringLink;
+ UINT8 *DevicePathPkg;
+ UINT8 *DevicePath;
+ HII_DATABASE_RECORD *DataBaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ CHAR8 *LocalNameSpace;
+ EFI_STRING_ID NextStringId;
+ EFI_STATUS Status;
+ UINT8 *OpCode;
+ CHAR16 *ConfigRequest;
+ CHAR16 *ValueElement;
+ CHAR16 *KeywordResp;
+ CHAR16 *MultiKeywordResp;
+ CHAR16 *KeywordData;
+ BOOLEAN ReadOnly;
+ BOOLEAN FindKeywordPackages;
+
+ DataBaseRecord = NULL;
+ Status = EFI_SUCCESS;
+ MultiKeywordResp = NULL;
+ DevicePath = NULL;
+ LocalNameSpace = NULL;
+ ConfigRequest = NULL;
+ ValueElement = NULL;
+ KeywordResp = NULL;
+ FindKeywordPackages = FALSE;
+
+ if (NameSpace == NULL) {
+ NameSpace = UEFI_CONFIG_LANG;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
+ DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) {
+ DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ }
+ PackageListNode = DataBaseRecord->PackageList;
+
+ for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) {
+ StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+
+ //
+ // Check whether has keyword string package.
+ //
+ if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) {
+ FindKeywordPackages = TRUE;
+ //
+ // Keep the NameSpace string.
+ //
+ LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
+ if (LocalNameSpace == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // 1 means just begin the enumerate the valid string ids.
+ // StringId == 1 is always used to save the language for this string package.
+ // Any valid string start from 2. so here initial it to 1.
+ //
+ NextStringId = 1;
+
+ //
+ // Enumerate all valid stringid in the package.
+ //
+ while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) {
+ //
+ // 3.3 Construct the ConfigRequest string.
+ //
+ Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest);
+ if (EFI_ERROR (Status)) {
+ //
+ // If can't generate ConfigRequest for this question, skip it and start the next.
+ //
+ goto Error;
+ }
+
+ //
+ // 3.4 Extract Value for the input keyword.
+ //
+ Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ //
+ // If can't generate ConfigRequest for this question, skip it and start the next.
+ //
+ goto Error;
+ }
+ //
+ // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
+ //
+ goto Done;
+ }
+
+ //
+ // Extract readonly flag from opcode.
+ //
+ ReadOnly = ExtractReadOnlyFromOpCode(OpCode);
+
+ //
+ // 5. Generate KeywordResp string.
+ //
+ ASSERT (DevicePath != NULL);
+ Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
+ if (Status != EFI_SUCCESS) {
+ //
+ // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
+ //
+ goto Done;
+ }
+
+ //
+ // 6. Merge to the MultiKeywordResp string.
+ //
+ Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+Error:
+ //
+ // Clean the temp buffer to later use again.
+ //
+ if (ConfigRequest != NULL) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+ if (ValueElement != NULL) {
+ FreePool (ValueElement);
+ ValueElement = NULL;
+ }
+ if (KeywordResp != NULL) {
+ FreePool (KeywordResp);
+ KeywordResp = NULL;
+ }
+ }
+
+ if (LocalNameSpace != NULL) {
+ FreePool (LocalNameSpace);
+ LocalNameSpace = NULL;
+ }
+ }
+ }
+ }
+
+ //
+ // return the already get MultiKeywordString even error occurred.
+ //
+ if (MultiKeywordResp == NULL) {
+ Status = EFI_NOT_FOUND;
+ if (!FindKeywordPackages) {
+ *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
+ } else {
+ *ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
+ }
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ *MultiResp = MultiKeywordResp;
+
+Done:
+ if (LocalNameSpace != NULL) {
+ FreePool (LocalNameSpace);
+ }
+ if (ConfigRequest != NULL) {
+ FreePool (ConfigRequest);
+ }
+ if (ValueElement != NULL) {
+ FreePool (ValueElement);
+ }
+
+ return Status;
+}
+
+/**
+
+ This function accepts a <MultiKeywordResp> formatted string, finds the associated
+ keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
+ EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
+
+ If there is an issue in resolving the contents of the KeywordString, then the
+ function returns an error and also sets the Progress and ProgressErr with the
+ appropriate information about where the issue occurred and additional data about
+ the nature of the issue.
+
+ In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
+ error is generated during processing the second or later keyword element, the system
+ storage associated with earlier keywords is not modified. All elements of the
+ KeywordString must successfully pass all tests for format and access prior to making
+ any modifications to storage.
+
+ In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
+ containing multiple keywords, the state of storage associated with earlier keywords
+ is undefined.
+
+
+ @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
+
+ @param KeywordString A null-terminated string in <MultiKeywordResp> format.
+
+ @param Progress On return, points to a character in the KeywordString.
+ Points to the string's NULL terminator if the 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 ProgressErr If during the processing of the KeywordString there was
+ a failure, this parameter gives additional information
+ about the possible source of the problem. The various
+ errors are defined in "Related Definitions" below.
+
+
+ @retval EFI_SUCCESS The specified action was completed successfully.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ 1. KeywordString is NULL.
+ 2. Parsing of the KeywordString resulted in an
+ error. See Progress and ProgressErr for more data.
+
+ @retval EFI_NOT_FOUND An element of the KeywordString was not found.
+ See ProgressErr for more data.
+
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ See ProgressErr for more data.
+
+ @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr
+ for more data.
+
+ @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
+ for more data.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiConfigKeywordHandlerSetData (
+ IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
+ IN CONST EFI_STRING KeywordString,
+ OUT EFI_STRING *Progress,
+ OUT UINT32 *ProgressErr
+ )
+{
+ CHAR8 *NameSpace;
+ EFI_STATUS Status;
+ CHAR16 *StringPtr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 *NextStringPtr;
+ CHAR16 *KeywordData;
+ EFI_STRING_ID KeywordStringId;
+ UINT32 RetVal;
+ HII_DATABASE_RECORD *DataBaseRecord;
+ UINT8 *OpCode;
+ CHAR16 *ConfigResp;
+ CHAR16 *MultiConfigResp;
+ CHAR16 *ValueElement;
+ BOOLEAN ReadOnly;
+ EFI_STRING InternalProgress;
+ CHAR16 *TempString;
+ CHAR16 *KeywordStartPos;
+
+ if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = KeywordString;
+ *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
+ Status = EFI_SUCCESS;
+ MultiConfigResp = NULL;
+ NameSpace = NULL;
+ DevicePath = NULL;
+ KeywordData = NULL;
+ ValueElement = NULL;
+ ConfigResp = NULL;
+ KeywordStartPos = NULL;
+ KeywordStringId = 0;
+
+ //
+ // Use temp string to avoid changing input string buffer.
+ //
+ TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
+ ASSERT (TempString != NULL);
+ StringPtr = TempString;
+
+ while ((StringPtr != NULL) && (*StringPtr != L'\0')) {
+ //
+ // 1. Get NameSpace from NameSpaceId keyword.
+ //
+ Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ goto Done;
+ }
+ ASSERT (NameSpace != NULL);
+ //
+ // 1.1 Check whether the input namespace is valid.
+ //
+ if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ StringPtr = NextStringPtr;
+
+ //
+ // 2. Get possible Device Path info from KeywordString.
+ //
+ Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+ //
+ // 3. Extract keyword from the KeywordRequest string.
+ //
+ KeywordStartPos = StringPtr;
+ Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ //
+ // Can't find Keyword base on the input device path info.
+ //
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+ //
+ // 4. Extract Value from the KeywordRequest string.
+ //
+ Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ //
+ // Can't find Value base on the input device path info.
+ //
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+ //
+ // 5. Find READONLY tag.
+ //
+ if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&READONLY", StrLen (L"&READONLY")) == 0) {
+ ReadOnly = TRUE;
+ StringPtr += StrLen (L"&READONLY");
+ } else {
+ ReadOnly = FALSE;
+ }
+
+ //
+ // 6. Get EFI_STRING_ID for the input keyword.
+ //
+ Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = RetVal;
+ goto Done;
+ }
+
+ //
+ // 7. Construct the ConfigRequest string.
+ //
+ Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 8. Check the readonly flag.
+ //
+ if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) {
+ //
+ // Extracting readonly flag form opcode and extracting "READONLY" tag form KeywordString should have the same results.
+ // If not, the input KeywordString must be incorrect, return the error status to caller.
+ //
+ *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ if (ReadOnly) {
+ *ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED;
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ //
+ // 9. Merge to the MultiKeywordResp string.
+ //
+ Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 10. Clean the temp buffer point.
+ //
+ FreePool (NameSpace);
+ FreePool (DevicePath);
+ FreePool (KeywordData);
+ FreePool (ValueElement);
+ NameSpace = NULL;
+ DevicePath = NULL;
+ KeywordData = NULL;
+ ValueElement = NULL;
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ ConfigResp = NULL;
+ }
+ KeywordStartPos = NULL;
+ }
+
+ //
+ // 11. Set value to driver.
+ //
+ Status = mPrivate.ConfigRouting.RouteConfig(
+ &mPrivate.ConfigRouting,
+ (EFI_STRING) MultiConfigResp,
+ &InternalProgress
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
+
+Done:
+ if (KeywordStartPos != NULL) {
+ *Progress = KeywordString + (KeywordStartPos - TempString);
+ } else {
+ *Progress = KeywordString + (StringPtr - TempString);
+ }
+
+ ASSERT (TempString != NULL);
+ FreePool (TempString);
+ if (NameSpace != NULL) {
+ FreePool (NameSpace);
+ }
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+ if (KeywordData != NULL) {
+ FreePool (KeywordData);
+ }
+ if (ValueElement != NULL) {
+ FreePool (ValueElement);
+ }
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ }
+ if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) {
+ FreePool (MultiConfigResp);
+ }
+
+ return Status;
+}
+
+/**
+
+ This function accepts a <MultiKeywordRequest> formatted string, finds the underlying
+ keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
+ EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
+
+ If there is an issue in resolving the contents of the KeywordString, then the function
+ returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
+ appropriate information about where the issue occurred and additional data about the
+ nature of the issue.
+
+ In the case when KeywordString is NULL, or contains multiple keywords, or when
+ EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
+ contains values returned for all keywords processed prior to the keyword generating the
+ error but no values for the keyword with error or any following keywords.
+
+
+ @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
+
+ @param NameSpaceId A null-terminated string containing the platform configuration
+ language to search through in the system. If a NULL is passed
+ in, then it is assumed that any platform configuration language
+ with the prefix of "x-UEFI-" are searched.
+
+ @param KeywordString A null-terminated string in <MultiKeywordRequest> format. If a
+ NULL is passed in the KeywordString field, all of the known
+ keywords in the system for the NameSpaceId specified are
+ returned in the Results field.
+
+ @param Progress On return, points to a character in the KeywordString. Points
+ to the string's NULL terminator if the 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 ProgressErr If during the processing of the KeywordString there was a
+ failure, this parameter gives additional information about the
+ possible source of the problem. See the definitions in SetData()
+ for valid value definitions.
+
+ @param Results A null-terminated string in <MultiKeywordResp> format is returned
+ which has all the values filled in for the keywords in the
+ KeywordString. This is a callee-allocated field, and must be freed
+ by the caller after being used.
+
+ @retval EFI_SUCCESS The specified action was completed successfully.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ 1.Progress, ProgressErr, or Results is NULL.
+ 2.Parsing of the KeywordString resulted in an error. See
+ Progress and ProgressErr for more data.
+
+
+ @retval EFI_NOT_FOUND An element of the KeywordString was not found. See
+ ProgressErr for more data.
+
+ @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr
+ for more data.
+
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See
+ ProgressErr for more data.
+
+ @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for
+ more data.
+
+ @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
+ for more data.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiConfigKeywordHandlerGetData (
+ IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
+ IN CONST EFI_STRING NameSpaceId, OPTIONAL
+ IN CONST EFI_STRING KeywordString, OPTIONAL
+ OUT EFI_STRING *Progress,
+ OUT UINT32 *ProgressErr,
+ OUT EFI_STRING *Results
+ )
+{
+ CHAR8 *NameSpace;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ HII_DATABASE_RECORD *DataBaseRecord;
+ CHAR16 *StringPtr;
+ CHAR16 *NextStringPtr;
+ CHAR16 *KeywordData;
+ EFI_STRING_ID KeywordStringId;
+ UINT8 *OpCode;
+ CHAR16 *ConfigRequest;
+ CHAR16 *ValueElement;
+ UINT32 RetVal;
+ BOOLEAN ReadOnly;
+ CHAR16 *KeywordResp;
+ CHAR16 *MultiKeywordResp;
+ CHAR16 *TempString;
+
+ if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
+ Status = EFI_SUCCESS;
+ DevicePath = NULL;
+ NameSpace = NULL;
+ KeywordData = NULL;
+ ConfigRequest= NULL;
+ StringPtr = KeywordString;
+ ReadOnly = FALSE;
+ MultiKeywordResp = NULL;
+ KeywordStringId = 0;
+ TempString = NULL;
+
+ //
+ // Use temp string to avoid changing input string buffer.
+ //
+ if (NameSpaceId != NULL) {
+ TempString = AllocateCopyPool (StrSize (NameSpaceId), NameSpaceId);
+ ASSERT (TempString != NULL);
+ }
+ //
+ // 1. Get NameSpace from NameSpaceId keyword.
+ //
+ Status = ExtractNameSpace (TempString, &NameSpace, NULL);
+ if (TempString != NULL) {
+ FreePool (TempString);
+ TempString = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ return Status;
+ }
+ //
+ // 1.1 Check whether the input namespace is valid.
+ //
+ if (NameSpace != NULL){
+ if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (KeywordString != NULL) {
+ //
+ // Use temp string to avoid changing input string buffer.
+ //
+ TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
+ ASSERT (TempString != NULL);
+ StringPtr = TempString;
+
+ while (*StringPtr != L'\0') {
+ //
+ // 2. Get possible Device Path info from KeywordString.
+ //
+ Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+
+ //
+ // 3. Process Keyword section from the input keywordRequest string.
+ //
+ // 3.1 Extract keyword from the KeywordRequest string.
+ //
+ Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
+ if (EFI_ERROR (Status)) {
+ //
+ // Can't find Keyword base on the input device path info.
+ //
+ *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // 3.2 Get EFI_STRING_ID for the input keyword.
+ //
+ Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
+ if (EFI_ERROR (Status)) {
+ *ProgressErr = RetVal;
+ goto Done;
+ }
+
+ //
+ // 3.3 Construct the ConfigRequest string.
+ //
+ Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 3.4 Extract Value for the input keyword.
+ //
+ Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+ //
+ // 4. Process the possible filter section.
+ //
+ RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly);
+ if (RetVal != KEYWORD_HANDLER_NO_ERROR) {
+ *ProgressErr = RetVal;
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr = NextStringPtr;
+
+
+ //
+ // 5. Generate KeywordResp string.
+ //
+ Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
+ if (Status != EFI_SUCCESS) {
+ goto Done;
+ }
+
+ //
+ // 6. Merge to the MultiKeywordResp string.
+ //
+ Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 7. Update return value.
+ //
+ *Results = MultiKeywordResp;
+
+ //
+ // 8. Clean the temp buffer.
+ //
+ FreePool (DevicePath);
+ FreePool (KeywordData);
+ FreePool (ValueElement);
+ FreePool (ConfigRequest);
+ DevicePath = NULL;
+ KeywordData = NULL;
+ ValueElement = NULL;
+ ConfigRequest = NULL;
+ if (KeywordResp != NULL) {
+ FreePool (KeywordResp);
+ KeywordResp = NULL;
+ }
+ }
+ } else {
+ //
+ // Enumerate all keyword in the system.
+ //
+ Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ *Results = MultiKeywordResp;
+ }
+
+ *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
+
+Done:
+ *Progress = KeywordString + (StringPtr - TempString);
+
+ if (TempString != NULL) {
+ FreePool (TempString);
+ }
+ if (NameSpace != NULL) {
+ FreePool (NameSpace);
+ }
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+ if (KeywordData != NULL) {
+ FreePool (KeywordData);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
new file mode 100644
index 000000000..2cad6d29f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
@@ -0,0 +1,6231 @@
+/** @file
+Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+extern HII_DATABASE_PRIVATE_DATA mPrivate;
+
+/**
+ Calculate the number of Unicode characters of the incoming Configuration string,
+ not including NULL terminator.
+
+ This is a internal function.
+
+ @param String String in <MultiConfigRequest> or
+ <MultiConfigResp> format.
+
+ @return The number of Unicode characters.
+
+**/
+UINTN
+CalculateConfigStringLen (
+ IN EFI_STRING String
+ )
+{
+ EFI_STRING TmpPtr;
+
+ //
+ // "GUID=" should be the first element of incoming string.
+ //
+ ASSERT (String != NULL);
+ ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
+
+ //
+ // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
+ // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
+ //
+ TmpPtr = StrStr (String, L"&GUID=");
+ if (TmpPtr == NULL) {
+ return StrLen (String);
+ }
+
+ return (TmpPtr - String);
+}
+
+
+/**
+ Convert the hex UNICODE %02x encoding of a UEFI device path to binary
+ from <PathHdr> of <ConfigHdr>.
+
+ This is a internal function.
+
+ @param String UEFI configuration string
+ @param DevicePathData Binary of a UEFI device path.
+
+ @retval EFI_NOT_FOUND The device path is not invalid.
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store necessary structures.
+ @retval EFI_SUCCESS The device path is retrieved and translated to
+ binary format.
+
+**/
+EFI_STATUS
+GetDevicePath (
+ IN EFI_STRING String,
+ OUT UINT8 **DevicePathData
+ )
+{
+ UINTN Length;
+ EFI_STRING PathHdr;
+ UINT8 *DevicePathBuffer;
+ CHAR16 TemStr[2];
+ UINTN Index;
+ UINT8 DigitUint8;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+
+ if (String == NULL || DevicePathData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the 'PATH=' of <PathHdr> and skip it.
+ //
+ for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
+ if (*String == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether path data does exist.
+ //
+ String += StrLen (L"PATH=");
+ if (*String == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ PathHdr = String;
+
+ //
+ // The content between 'PATH=' of <ConfigHdr> and '&' of next element
+ // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
+ // of UEFI device path.
+ //
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+ //
+ // Check DevicePath Length
+ //
+ if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
+ // as the device path resides in RAM memory.
+ // Translate the data into binary.
+ //
+ DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (DevicePathBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Convert DevicePath
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = PathHdr[Index];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DevicePathBuffer [Index/2] = DigitUint8;
+ } else {
+ DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
+ }
+ }
+
+ //
+ // Validate DevicePath
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
+ //
+ // Invalid device path
+ //
+ FreePool (DevicePathBuffer);
+ return EFI_NOT_FOUND;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // return the device path
+ //
+ *DevicePathData = DevicePathBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Converts the unicode character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+EFIAPI
+HiiToLower (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+
+ return;
+}
+
+/**
+ Generate a sub string then output it.
+
+ This is a internal function.
+
+ @param String A constant string which is the prefix of the to be
+ generated string, e.g. GUID=
+
+ @param BufferLen The length of the Buffer in bytes.
+
+ @param Buffer Points to a buffer which will be converted to be the
+ content of the generated string.
+
+ @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
+ UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
+ if 3, the buffer contains other data.
+
+ @param SubStr Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+
+**/
+VOID
+GenerateSubStr (
+ IN CONST EFI_STRING String,
+ IN UINTN BufferLen,
+ IN VOID *Buffer,
+ IN UINT8 Flag,
+ OUT EFI_STRING *SubStr
+ )
+{
+ UINTN Length;
+ EFI_STRING Str;
+ EFI_STRING StringHeader;
+ CHAR16 *TemString;
+ CHAR16 *TemName;
+ UINT8 *TemBuffer;
+ UINTN Index;
+
+ ASSERT (String != NULL && SubStr != NULL);
+
+ if (Buffer == NULL) {
+ *SubStr = AllocateCopyPool (StrSize (String), String);
+ ASSERT (*SubStr != NULL);
+ return;
+ }
+
+ //
+ // Header + Data + '&' + '\0'
+ //
+ Length = StrLen (String) + BufferLen * 2 + 1 + 1;
+ Str = AllocateZeroPool (Length * sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ StrCpyS (Str, Length, String);
+
+ StringHeader = Str + StrLen (String);
+ TemString = (CHAR16 *) StringHeader;
+
+ switch (Flag) {
+ case 1:
+ //
+ // Convert Buffer to Hex String in reverse order
+ //
+ TemBuffer = ((UINT8 *) Buffer);
+ for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) {
+ UnicodeValueToStringS (
+ TemString,
+ sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemBuffer,
+ 2
+ );
+ TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
+ }
+ break;
+ case 2:
+ //
+ // Check buffer is enough
+ //
+ TemName = (CHAR16 *) Buffer;
+ ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));
+ //
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
+ //
+ for (; *TemName != L'\0'; TemName++) {
+ UnicodeValueToStringS (
+ TemString,
+ sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemName,
+ 4
+ );
+ TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
+ }
+ break;
+ case 3:
+ //
+ // Convert Buffer to Hex String
+ //
+ TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1;
+ for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) {
+ UnicodeValueToStringS (
+ TemString,
+ sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemBuffer,
+ 2
+ );
+ TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
+ }
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
+ //
+ StrCatS (Str, Length, L"&");
+ HiiToLower (Str);
+
+ *SubStr = Str;
+}
+
+
+/**
+ Retrieve the <ConfigBody> from String then output it.
+
+ This is a internal function.
+
+ @param String A sub string of a configuration string in
+ <MultiConfigAltResp> format.
+ @param ConfigBody Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+ @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
+ @retval EFI_SUCCESS All existing storage is exported.
+
+**/
+EFI_STATUS
+OutputConfigBody (
+ IN EFI_STRING String,
+ OUT EFI_STRING *ConfigBody
+ )
+{
+ EFI_STRING TmpPtr;
+ EFI_STRING Result;
+ UINTN Length;
+
+ if (String == NULL || ConfigBody == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The setting information should start OFFSET, not ALTCFG.
+ //
+ if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TmpPtr = StrStr (String, L"GUID=");
+ if (TmpPtr == NULL) {
+ //
+ // It is the last <ConfigResp> of the incoming configuration string.
+ //
+ Result = AllocateCopyPool (StrSize (String), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+ }
+ }
+
+ Length = TmpPtr - String;
+ if (Length == 0) {
+ return EFI_NOT_FOUND;
+ }
+ Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(Result + Length - 1) = 0;
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+}
+
+/**
+ Append a string to a multi-string format.
+
+ This is a internal function.
+
+ @param MultiString String in <MultiConfigRequest>,
+ <MultiConfigAltResp>, or <MultiConfigResp>. On
+ input, the buffer length of this string is
+ MAX_STRING_LENGTH. On output, the buffer length
+ might be updated.
+ @param AppendString NULL-terminated Unicode string.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_SUCCESS AppendString is append to the end of MultiString
+
+**/
+EFI_STATUS
+AppendToMultiString (
+ IN OUT EFI_STRING *MultiString,
+ IN EFI_STRING AppendString
+ )
+{
+ UINTN AppendStringSize;
+ UINTN MultiStringSize;
+ UINTN MaxLen;
+
+ if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AppendStringSize = StrSize (AppendString);
+ MultiStringSize = StrSize (*MultiString);
+ MaxLen = MAX_STRING_LENGTH / sizeof (CHAR16);
+
+ //
+ // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
+ //
+ if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
+ MultiStringSize > MAX_STRING_LENGTH) {
+ *MultiString = (EFI_STRING) ReallocatePool (
+ MultiStringSize,
+ MultiStringSize + AppendStringSize,
+ (VOID *) (*MultiString)
+ );
+ MaxLen = (MultiStringSize + AppendStringSize) / sizeof (CHAR16);
+ ASSERT (*MultiString != NULL);
+ }
+ //
+ // Append the incoming string
+ //
+ StrCatS (*MultiString, MaxLen, AppendString);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ This is a internal function.
+
+ @param StringPtr String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param Number The output value. Caller takes the responsibility
+ to free memory.
+ @param Len Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+EFI_STATUS
+GetValueOfNumber (
+ IN EFI_STRING StringPtr,
+ OUT UINT8 **Number,
+ OUT UINTN *Len
+ )
+{
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING Str;
+ UINT8 *Buf;
+ EFI_STATUS Status;
+ UINT8 DigitUint8;
+ UINTN Index;
+ CHAR16 TemStr[2];
+
+ if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buf = NULL;
+
+ TmpPtr = StringPtr;
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ *Len = StringPtr - TmpPtr;
+ Length = *Len + 1;
+
+ Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (Str == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
+ *(Str + *Len) = L'\0';
+
+ Length = (Length + 1) / 2;
+ Buf = (UINT8 *) AllocateZeroPool (Length);
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Length = *Len;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = Str[Length - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ Buf [Index/2] = DigitUint8;
+ } else {
+ Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
+ }
+ }
+
+ *Number = Buf;
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+
+ return Status;
+}
+
+/**
+ To find the BlockName in the string with same value.
+
+ @param String Pointer to a Null-terminated Unicode string.
+ @param BlockName Pointer to a Null-terminated Unicode string to search for.
+ @param Buffer Pointer to the value correspond to the BlockName.
+ @param Found The Block whether has been found.
+ @param BufferLen The length of the buffer.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
+ @retval EFI_SUCCESS The function finishes successfully.
+
+**/
+EFI_STATUS
+FindSameBlockElement(
+ IN EFI_STRING String,
+ IN EFI_STRING BlockName,
+ IN UINT8 *Buffer,
+ OUT BOOLEAN *Found,
+ IN UINTN BufferLen
+ )
+{
+ EFI_STRING BlockPtr;
+ UINTN Length;
+ UINT8 *TempBuffer;
+ EFI_STATUS Status;
+
+ TempBuffer = NULL;
+ *Found = FALSE;
+ BlockPtr = StrStr (String, BlockName);
+
+ while (BlockPtr != NULL) {
+ BlockPtr += StrLen (BlockName);
+ Status = GetValueOfNumber (BlockPtr, &TempBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (TempBuffer != NULL);
+ if ((BufferLen == Length) && (0 == CompareMem (Buffer, TempBuffer, Length))) {
+ *Found = TRUE;
+ FreePool (TempBuffer);
+ TempBuffer = NULL;
+ return EFI_SUCCESS;
+ } else {
+ FreePool (TempBuffer);
+ TempBuffer = NULL;
+ BlockPtr = StrStr (BlockPtr + 1, BlockName);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp>
+ in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp.
+
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
+ <MultiConfigAltResp> format. The default value
+ string may contain more than one ConfigAltResp
+ string for the different varstore buffer.
+ @param ConfigAltResp Pointer to a null-terminated Unicode string in
+ <ConfigAltResp> format.
+ @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
+ @param ConfigAltRespChanged Whether the ConfigAltResp has been changed.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
+ @retval EFI_SUCCESS The function finishes successfully.
+
+**/
+EFI_STATUS
+CompareBlockElementDefault (
+ IN EFI_STRING DefaultAltCfgResp,
+ IN OUT EFI_STRING *ConfigAltResp,
+ IN EFI_STRING AltConfigHdr,
+ IN OUT BOOLEAN *ConfigAltRespChanged
+)
+{
+ EFI_STATUS Status;
+ EFI_STRING BlockPtr;
+ EFI_STRING BlockPtrStart;
+ EFI_STRING StringPtr;
+ EFI_STRING AppendString;
+ EFI_STRING AltConfigHdrPtr;
+ UINT8 *TempBuffer;
+ UINTN OffsetLength;
+ UINTN AppendSize;
+ UINTN TotalSize;
+ BOOLEAN FoundOffset;
+
+ AppendString = NULL;
+ TempBuffer = NULL;
+ //
+ // Make BlockPtr point to the first <BlockConfig> with AltConfigHdr in DefaultAltCfgResp.
+ //
+ AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
+ ASSERT (AltConfigHdrPtr != NULL);
+ BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET=");
+ //
+ // Make StringPtr point to the AltConfigHdr in ConfigAltResp.
+ //
+ StringPtr = StrStr (*ConfigAltResp, AltConfigHdr);
+ ASSERT (StringPtr != NULL);
+
+ while (BlockPtr != NULL) {
+ //
+ // Find the "&OFFSET=<Number>" block and get the value of the Number with AltConfigHdr in DefaultAltCfgResp.
+ //
+ BlockPtrStart = BlockPtr;
+ BlockPtr += StrLen (L"&OFFSET=");
+ Status = GetValueOfNumber (BlockPtr, &TempBuffer, &OffsetLength);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ //
+ // To find the same "&OFFSET=<Number>" block in ConfigAltResp.
+ //
+ Status = FindSameBlockElement (StringPtr, L"&OFFSET=", TempBuffer, &FoundOffset, OffsetLength);
+ if (TempBuffer != NULL) {
+ FreePool (TempBuffer);
+ TempBuffer = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ if (!FoundOffset) {
+ //
+ // Don't find the same "&OFFSET=<Number>" block in ConfigAltResp.
+ // Calculate the size of <BlockConfig>.
+ // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number>.
+ //
+ BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET=");
+ if (BlockPtr != NULL) {
+ AppendSize = (BlockPtr - BlockPtrStart) * sizeof (CHAR16);
+ } else {
+ AppendSize = StrSize (BlockPtrStart);
+ }
+ //
+ // Copy the <BlockConfig> to AppendString.
+ //
+ if (AppendString == NULL) {
+ AppendString = (EFI_STRING) AllocateZeroPool (AppendSize + sizeof (CHAR16));
+ StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, BlockPtrStart, AppendSize / sizeof (CHAR16));
+ } else {
+ TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16);
+ AppendString = (EFI_STRING) ReallocatePool (
+ StrSize (AppendString),
+ TotalSize,
+ AppendString
+ );
+ if (AppendString == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrnCatS (AppendString, TotalSize / sizeof (CHAR16), BlockPtrStart, AppendSize / sizeof (CHAR16));
+ }
+ } else {
+ //
+ // To find next "&OFFSET=<Number>" block with AltConfigHdr in DefaultAltCfgResp.
+ //
+ BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET=");
+ }
+ }
+
+ if (AppendString != NULL) {
+ //
+ // Reallocate ConfigAltResp to copy the AppendString.
+ //
+ TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16);
+ *ConfigAltResp = (EFI_STRING) ReallocatePool (
+ StrSize (*ConfigAltResp),
+ TotalSize,
+ *ConfigAltResp
+ );
+ if (*ConfigAltResp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString);
+ *ConfigAltRespChanged = TRUE;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (AppendString != NULL) {
+ FreePool (AppendString);
+ }
+
+ return Status;
+}
+
+/**
+ Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp>
+ in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp.
+
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
+ <MultiConfigAltResp> format. The default value
+ string may contain more than one ConfigAltResp
+ string for the different varstore buffer.
+ @param ConfigAltResp Pointer to a null-terminated Unicode string in
+ <ConfigAltResp> format.
+ @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
+ @param ConfigAltRespChanged Whether the ConfigAltResp has been changed.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
+ @retval EFI_SUCCESS The function finishes successfully.
+
+**/
+EFI_STATUS
+CompareNameElementDefault (
+ IN EFI_STRING DefaultAltCfgResp,
+ IN OUT EFI_STRING *ConfigAltResp,
+ IN EFI_STRING AltConfigHdr,
+ IN OUT BOOLEAN *ConfigAltRespChanged
+)
+{
+ EFI_STATUS Status;
+ EFI_STRING NvConfigPtr;
+ EFI_STRING NvConfigStart;
+ EFI_STRING NvConfigValuePtr;
+ EFI_STRING StringPtr;
+ EFI_STRING NvConfigExist;
+ EFI_STRING AppendString;
+ CHAR16 TempChar;
+ UINTN AppendSize;
+ UINTN TotalSize;
+
+ AppendString = NULL;
+ NvConfigExist = NULL;
+ //
+ // Make NvConfigPtr point to the first <NvConfig> with AltConfigHdr in DefaultAltCfgResp.
+ //
+ NvConfigPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
+ ASSERT (NvConfigPtr != NULL);
+ NvConfigPtr = StrStr (NvConfigPtr + StrLen(AltConfigHdr),L"&");
+ //
+ // Make StringPtr point to the first <NvConfig> with AltConfigHdr in ConfigAltResp.
+ //
+ StringPtr = StrStr (*ConfigAltResp, AltConfigHdr);
+ ASSERT (StringPtr != NULL);
+ StringPtr = StrStr (StringPtr + StrLen (AltConfigHdr), L"&");
+ ASSERT (StringPtr != NULL);
+
+ while (NvConfigPtr != NULL) {
+ //
+ // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number>.
+ // Get the <Label> with AltConfigHdr in DefaultAltCfgResp.
+ //
+ NvConfigStart = NvConfigPtr;
+ NvConfigValuePtr = StrStr (NvConfigPtr + 1, L"=");
+ ASSERT (NvConfigValuePtr != NULL);
+ TempChar = *NvConfigValuePtr;
+ *NvConfigValuePtr = L'\0';
+ //
+ // Get the <Label> with AltConfigHdr in ConfigAltResp.
+ //
+ NvConfigExist = StrStr (StringPtr, NvConfigPtr);
+ if (NvConfigExist == NULL) {
+ //
+ // Don't find same <Label> in ConfigAltResp.
+ // Calculate the size of <NvConfig>.
+ //
+ *NvConfigValuePtr = TempChar;
+ NvConfigPtr = StrStr (NvConfigPtr + 1, L"&");
+ if (NvConfigPtr != NULL) {
+ AppendSize = (NvConfigPtr - NvConfigStart) * sizeof (CHAR16);
+ } else {
+ AppendSize = StrSize (NvConfigStart);
+ }
+ //
+ // Copy the <NvConfig> to AppendString.
+ //
+ if (AppendString == NULL) {
+ AppendString = (EFI_STRING) AllocateZeroPool (AppendSize + sizeof (CHAR16));
+ StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, NvConfigStart, AppendSize / sizeof (CHAR16));
+ } else {
+ TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16);
+ AppendString = (EFI_STRING) ReallocatePool (
+ StrSize (AppendString),
+ TotalSize,
+ AppendString
+ );
+ if (AppendString == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrnCatS (AppendString, TotalSize / sizeof (CHAR16), NvConfigStart, AppendSize / sizeof (CHAR16));
+ }
+ } else {
+ //
+ // To find next <Label> in DefaultAltCfgResp.
+ //
+ *NvConfigValuePtr = TempChar;
+ NvConfigPtr = StrStr (NvConfigPtr + 1, L"&");
+ }
+ }
+ if (AppendString != NULL) {
+ //
+ // Reallocate ConfigAltResp to copy the AppendString.
+ //
+ TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16);
+ *ConfigAltResp = (EFI_STRING) ReallocatePool (
+ StrSize (*ConfigAltResp),
+ StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16),
+ *ConfigAltResp
+ );
+ if (*ConfigAltResp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString);
+ *ConfigAltRespChanged = TRUE;
+ }
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (AppendString != NULL) {
+ FreePool (AppendString);
+ }
+ return Status;
+}
+
+/**
+ Compare the <AltResp> in AltCfgResp and DefaultAltCfgResp, if the <AltResp>
+ in DefaultAltCfgResp but not in AltCfgResp,add it to the AltCfgResp.
+
+ @param AltCfgResp Pointer to a null-terminated Unicode string in
+ <ConfigAltResp> format.
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
+ <MultiConfigAltResp> format. The default value
+ string may contain more than one ConfigAltResp
+ string for the different varstore buffer.
+ @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary
+ structures.
+ @retval EFI_SUCCESS The function finishes successfully.
+
+**/
+EFI_STATUS
+CompareAndMergeDefaultString (
+ IN OUT EFI_STRING *AltCfgResp,
+ IN EFI_STRING DefaultAltCfgResp,
+ IN EFI_STRING AltConfigHdr
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING AltCfgRespBackup;
+ EFI_STRING AltConfigHdrPtr;
+ EFI_STRING AltConfigHdrPtrNext;
+ EFI_STRING ConfigAltResp;
+ EFI_STRING StringPtr;
+ EFI_STRING StringPtrNext;
+ EFI_STRING BlockPtr;
+ UINTN ReallocateSize;
+ CHAR16 TempChar;
+ CHAR16 TempCharA;
+ BOOLEAN ConfigAltRespChanged;
+
+ Status = EFI_OUT_OF_RESOURCES;
+ BlockPtr = NULL;
+ AltConfigHdrPtrNext = NULL;
+ StringPtrNext = NULL;
+ ConfigAltResp = NULL;
+ AltCfgRespBackup = NULL;
+ TempChar = L'\0';
+ TempCharA = L'\0';
+ ConfigAltRespChanged = FALSE;
+
+ //
+ //To find the <AltResp> with AltConfigHdr in DefaultAltCfgResp, ignore other <AltResp> which follow it.
+ //
+ AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
+ ASSERT (AltConfigHdrPtr != NULL);
+ AltConfigHdrPtrNext = StrStr (AltConfigHdrPtr + 1, L"&GUID");
+ if (AltConfigHdrPtrNext != NULL) {
+ TempChar = *AltConfigHdrPtrNext;
+ *AltConfigHdrPtrNext = L'\0';
+ }
+ //
+ // To find the <AltResp> with AltConfigHdr in AltCfgResp, ignore other <AltResp> which follow it.
+ //
+ StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
+ ASSERT (StringPtr != NULL);
+ StringPtrNext = StrStr (StringPtr + 1, L"&GUID");
+ if (StringPtrNext != NULL) {
+ TempCharA = *StringPtrNext;
+ *StringPtrNext = L'\0';
+ }
+ //
+ // Copy the content of <ConfigAltResp> which contain current AltConfigHdr in AltCfgResp.
+ //
+ ConfigAltResp = AllocateCopyPool (StrSize (*AltCfgResp), *AltCfgResp);
+ if (ConfigAltResp == NULL) {
+ goto Exit;
+ }
+ //
+ // To find the <ConfigBody> with AltConfigHdr in DefaultAltCfgResp.
+ //
+ BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET=");
+ if (BlockPtr != NULL) {
+ //
+ // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number> style.
+ // Call function CompareBlockElementDefault to compare the <BlockConfig> in DefaultAltCfgResp and ConfigAltResp.
+ // The ConfigAltResp which may contain the new <BlockConfig> get from DefaultAltCfgResp.
+ //
+ Status = CompareBlockElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+ } else {
+ //
+ // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number> style.
+ // Call function CompareNameElementDefault to compare the <NvConfig> in DefaultAltCfgResp and ConfigAltResp.
+ // The ConfigAltResp which may contain the new <NvConfig> get from DefaultAltCfgResp.
+ //
+ Status = CompareNameElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+ }
+ //
+ // Restore the AltCfgResp.
+ //
+ if (StringPtrNext != NULL) {
+ *StringPtrNext = TempCharA;
+ }
+
+ //
+ // If the ConfigAltResp has no change,no need to update the content in AltCfgResp.
+ //
+ if (!ConfigAltRespChanged) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ //
+ // ConfigAltResp has been changed, need to update the content in AltCfgResp.
+ //
+ if (StringPtrNext != NULL) {
+ ReallocateSize = StrSize (ConfigAltResp) + StrSize (StringPtrNext) + sizeof (CHAR16);
+ } else {
+ ReallocateSize = StrSize (ConfigAltResp) + sizeof (CHAR16);
+ }
+
+ AltCfgRespBackup = (EFI_STRING) AllocateZeroPool (ReallocateSize);
+ if (AltCfgRespBackup == NULL) {
+ goto Exit;
+ }
+
+ StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), ConfigAltResp);
+ if (StringPtrNext != NULL) {
+ StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), StringPtrNext);
+ }
+
+ FreePool (*AltCfgResp);
+ *AltCfgResp = AltCfgRespBackup;
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (ConfigAltResp != NULL) {
+ FreePool(ConfigAltResp);
+ }
+ //
+ // Restore the DefaultAltCfgResp.
+ //
+ if ( AltConfigHdrPtrNext != NULL) {
+ *AltConfigHdrPtrNext = TempChar;
+ AltConfigHdrPtrNext = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ This function merges DefaultAltCfgResp string into AltCfgResp string for
+ the missing AltCfgId in AltCfgResq.
+
+ @param AltCfgResp Pointer to a null-terminated Unicode string in
+ <ConfigAltResp> format. The default value string
+ will be merged into it.
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
+ <MultiConfigAltResp> format. The default value
+ string may contain more than one ConfigAltResp
+ string for the different varstore buffer.
+
+ @retval EFI_SUCCESS The merged string returns.
+ @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
+**/
+EFI_STATUS
+EFIAPI
+MergeDefaultString (
+ IN OUT EFI_STRING *AltCfgResp,
+ IN EFI_STRING DefaultAltCfgResp
+ )
+{
+ EFI_STRING StringPtrDefault;
+ EFI_STRING StringPtrEnd;
+ CHAR16 TempChar;
+ EFI_STRING StringPtr;
+ EFI_STRING AltConfigHdr;
+ UINTN HeaderLength;
+ UINTN SizeAltCfgResp;
+ UINTN MaxLen;
+ UINTN TotalSize;
+
+ if (*AltCfgResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the request ConfigHdr
+ //
+ SizeAltCfgResp = 0;
+ StringPtr = *AltCfgResp;
+
+ //
+ // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
+ StringPtr++;
+ }
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ return EFI_INVALID_PARAMETER;
+ }
+ StringPtr += StrLen (L"&PATH=");
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr ++;
+ }
+ HeaderLength = StringPtr - *AltCfgResp;
+
+ //
+ // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
+ // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
+ //
+ MaxLen = 1 + HeaderLength + 8 + 4 + 1;
+ AltConfigHdr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ if (AltConfigHdr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrCpyS (AltConfigHdr, MaxLen, L"&");
+ StrnCatS (AltConfigHdr, MaxLen, *AltCfgResp, HeaderLength);
+ StrCatS (AltConfigHdr, MaxLen, L"&ALTCFG=");
+ HeaderLength = StrLen (AltConfigHdr);
+
+ StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
+ while (StringPtrDefault != NULL) {
+ //
+ // Get AltCfg Name
+ //
+ StrnCatS (AltConfigHdr, MaxLen, StringPtrDefault + HeaderLength, 4);
+ StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
+
+ //
+ // Append the found default value string to the input AltCfgResp
+ //
+ if (StringPtr == NULL) {
+ StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
+ SizeAltCfgResp = StrSize (*AltCfgResp);
+ if (StringPtrEnd == NULL) {
+ //
+ // No more default string is found.
+ //
+ TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);
+ *AltCfgResp = (EFI_STRING) ReallocatePool (
+ SizeAltCfgResp,
+ TotalSize,
+ (VOID *) (*AltCfgResp)
+ );
+ if (*AltCfgResp == NULL) {
+ FreePool (AltConfigHdr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
+ break;
+ } else {
+ TempChar = *StringPtrEnd;
+ *StringPtrEnd = L'\0';
+ TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);
+ *AltCfgResp = (EFI_STRING) ReallocatePool (
+ SizeAltCfgResp,
+ TotalSize,
+ (VOID *) (*AltCfgResp)
+ );
+ if (*AltCfgResp == NULL) {
+ FreePool (AltConfigHdr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
+ *StringPtrEnd = TempChar;
+ }
+ } else {
+ //
+ // The AltCfgResp contains <AltCfgResp>.
+ // If the <ConfigElement> in <AltCfgResp> in the DefaultAltCfgResp but not in the
+ // related <AltCfgResp> in AltCfgResp, merge it to AltCfgResp. else no need to merge.
+ //
+ CompareAndMergeDefaultString (AltCfgResp, DefaultAltCfgResp, AltConfigHdr);
+ }
+
+ //
+ // Find next AltCfg String
+ //
+ *(AltConfigHdr + HeaderLength) = L'\0';
+ StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
+ }
+
+ FreePool (AltConfigHdr);
+ return EFI_SUCCESS;
+}
+
+/**
+ This function inserts new DefaultValueData into the BlockData DefaultValue array.
+
+ @param BlockData The BlockData is updated to add new default value.
+ @param DefaultValueData The DefaultValue is added.
+
+**/
+VOID
+InsertDefaultValue (
+ IN IFR_BLOCK_DATA *BlockData,
+ IN IFR_DEFAULT_DATA *DefaultValueData
+ )
+{
+ LIST_ENTRY *Link;
+ IFR_DEFAULT_DATA *DefaultValueArray;
+ LIST_ENTRY *DefaultLink;
+
+ DefaultLink = &BlockData->DefaultValueEntry;
+
+ for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) {
+ DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
+ if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
+ //
+ // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority.
+ // When default types are DEFAULT_VALUE_FROM_OTHER_DEFAULT, the default value can be overrode.
+ //
+ if ((DefaultValueData->Type > DefaultValueArray->Type) || (DefaultValueData->Type == DefaultValueArray->Type && DefaultValueData->Type == DefaultValueFromOtherDefault)) {
+ //
+ // Update the default value array in BlockData.
+ //
+ CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE));
+ DefaultValueArray->Type = DefaultValueData->Type;
+ DefaultValueArray->Cleaned = DefaultValueData->Cleaned;
+ }
+ return;
+ }
+ }
+
+ //
+ // Insert new default value data in tail.
+ //
+ DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
+ ASSERT (DefaultValueArray != NULL);
+ CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA));
+ InsertTailList (Link, &DefaultValueArray->Entry);
+}
+
+/**
+ This function inserts new BlockData into the block link
+
+ @param BlockLink The list entry points to block array.
+ @param BlockData The point to BlockData is added.
+
+**/
+VOID
+InsertBlockData (
+ IN LIST_ENTRY *BlockLink,
+ IN IFR_BLOCK_DATA **BlockData
+ )
+{
+ LIST_ENTRY *Link;
+ IFR_BLOCK_DATA *BlockArray;
+ IFR_BLOCK_DATA *BlockSingleData;
+
+ BlockSingleData = *BlockData;
+
+ if (BlockSingleData->Name != NULL) {
+ InsertTailList (BlockLink, &BlockSingleData->Entry);
+ return;
+ }
+
+ //
+ // Insert block data in its Offset and Width order.
+ //
+ for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
+ BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (BlockArray->Offset == BlockSingleData->Offset) {
+ if ((BlockArray->Width > BlockSingleData->Width) || (BlockSingleData->IsBitVar && BlockArray->Width == BlockSingleData->Width)) {
+ //
+ // Insert this block data in the front of block array
+ //
+ InsertTailList (Link, &BlockSingleData->Entry);
+ return;
+ }
+
+ if ((!BlockSingleData->IsBitVar) && BlockArray->Width == BlockSingleData->Width) {
+ //
+ // The same block array has been added.
+ //
+ if (BlockSingleData != BlockArray) {
+ FreePool (BlockSingleData);
+ *BlockData = BlockArray;
+ }
+ return;
+ }
+ } else if (BlockArray->Offset > BlockSingleData->Offset) {
+ //
+ // Insert new block data in the front of block array
+ //
+ InsertTailList (Link, &BlockSingleData->Entry);
+ return;
+ }
+ }
+
+ //
+ // Add new block data into the tail.
+ //
+ InsertTailList (Link, &BlockSingleData->Entry);
+}
+
+/**
+ Retrieves a pointer to the a Null-terminated ASCII string containing the list
+ of languages that an HII handle in the HII Database supports. The returned
+ string is allocated using AllocatePool(). The caller is responsible for freeing
+ the returned string using FreePool(). The format of the returned string follows
+ the language format assumed the HII Database.
+
+ If HiiHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+
+ @retval NULL HiiHandle is not registered in the HII database
+ @retval NULL There are not enough resources available to retrieve the supported
+ languages.
+ @retval NULL The list of supported languages could not be retrieved.
+ @retval Other A pointer to the Null-terminated ASCII string of supported languages.
+
+**/
+CHAR8 *
+GetSupportedLanguages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN LanguageSize;
+ CHAR8 TempSupportedLanguages;
+ CHAR8 *SupportedLanguages;
+
+ ASSERT (HiiHandle != NULL);
+
+ //
+ // Retrieve the size required for the supported languages buffer.
+ //
+ LanguageSize = 0;
+ Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
+
+ //
+ // If GetLanguages() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetLanguages()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ //
+ // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
+ //
+ return NULL;
+ }
+
+ //
+ // Allocate the supported languages buffer.
+ //
+ SupportedLanguages = AllocateZeroPool (LanguageSize);
+ if (SupportedLanguages == NULL) {
+ //
+ // Return NULL if allocation fails.
+ //
+ return NULL;
+ }
+
+ //
+ // Retrieve the supported languages string
+ //
+ Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, SupportedLanguages, &LanguageSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (SupportedLanguages);
+ return NULL;
+ }
+
+ //
+ // Return the Null-terminated ASCII string of supported languages
+ //
+ return SupportedLanguages;
+}
+
+/**
+ Retrieves a string from a string package.
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSET.
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+InternalGetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId
+ )
+{
+ EFI_STATUS Status;
+ UINTN StringSize;
+ CHAR16 TempString;
+ EFI_STRING String;
+ CHAR8 *SupportedLanguages;
+ CHAR8 *PlatformLanguage;
+ CHAR8 *BestLanguage;
+ CHAR8 *Language;
+
+ ASSERT (HiiHandle != NULL);
+ ASSERT (StringId != 0);
+
+ //
+ // Initialize all allocated buffers to NULL
+ //
+ SupportedLanguages = NULL;
+ PlatformLanguage = NULL;
+ BestLanguage = NULL;
+ String = NULL;
+ Language = "";
+
+ //
+ // Get the languages that the package specified by HiiHandle supports
+ //
+ SupportedLanguages = GetSupportedLanguages (HiiHandle);
+ if (SupportedLanguages == NULL) {
+ goto Error;
+ }
+
+ //
+ // Get the current platform language setting
+ //
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
+
+ //
+ // Get the best matching language from SupportedLanguages
+ //
+ BestLanguage = GetBestLanguage (
+ SupportedLanguages,
+ FALSE, // RFC 4646 mode
+ Language, // Highest priority
+ PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority
+ SupportedLanguages, // Lowest priority
+ NULL
+ );
+ if (BestLanguage == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the size of the string in the string package for the BestLanguage
+ //
+ StringSize = 0;
+ Status = mPrivate.HiiString.GetString (
+ &mPrivate.HiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ &TempString,
+ &StringSize,
+ NULL
+ );
+ //
+ // If GetString() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetString()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Error;
+ }
+
+ //
+ // Allocate a buffer for the return string
+ //
+ String = AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the string from the string package
+ //
+ Status = mPrivate.HiiString.GetString (
+ &mPrivate.HiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (String);
+ String = NULL;
+ }
+
+Error:
+ //
+ // Free allocated buffers
+ //
+ if (SupportedLanguages != NULL) {
+ FreePool (SupportedLanguages);
+ }
+ if (PlatformLanguage != NULL) {
+ FreePool (PlatformLanguage);
+ }
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ }
+
+ //
+ // Return the Null-terminated Unicode string
+ //
+ return String;
+}
+
+/**
+ This function checks VarOffset and VarWidth is in the block range.
+
+ @param RequestBlockArray The block array is to be checked.
+ @param VarOffset Offset of var to the structure
+ @param VarWidth Width of var.
+ @param IsNameValueType Whether this varstore is name/value varstore or not.
+ @param HiiHandle Hii handle for this hii package.
+
+ @retval TRUE This Var is in the block range.
+ @retval FALSE This Var is not in the block range.
+**/
+BOOLEAN
+BlockArrayCheck (
+ IN IFR_BLOCK_DATA *RequestBlockArray,
+ IN UINT16 VarOffset,
+ IN UINT16 VarWidth,
+ IN BOOLEAN IsNameValueType,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ LIST_ENTRY *Link;
+ IFR_BLOCK_DATA *BlockData;
+ EFI_STRING Name;
+
+ //
+ // No Request Block array, all vars are got.
+ //
+ if (RequestBlockArray == NULL) {
+ return TRUE;
+ }
+
+ //
+ // Check the input var is in the request block range.
+ //
+ for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+
+ if (IsNameValueType) {
+ Name = InternalGetString (HiiHandle, VarOffset);
+ ASSERT (Name != NULL);
+
+ if (StrnCmp (BlockData->Name, Name, StrLen (Name)) == 0) {
+ FreePool (Name);
+ return TRUE;
+ }
+ FreePool (Name);
+ } else {
+ if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get form package data from data base.
+
+ @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
+ @param HiiFormPackage The buffer saves the package data.
+ @param PackageSize The buffer size of the package data.
+
+**/
+EFI_STATUS
+GetFormPackageData (
+ IN HII_DATABASE_RECORD *DataBaseRecord,
+ IN OUT UINT8 **HiiFormPackage,
+ OUT UINTN *PackageSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN ResultSize;
+
+ if (DataBaseRecord == NULL || HiiFormPackage == NULL || PackageSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size = 0;
+ ResultSize = 0;
+ //
+ // 0. Get Hii Form Package by HiiHandle
+ //
+ Status = ExportFormPackages (
+ &mPrivate,
+ DataBaseRecord->Handle,
+ DataBaseRecord->PackageList,
+ 0,
+ Size,
+ HiiFormPackage,
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ (*HiiFormPackage) = AllocatePool (ResultSize);
+ if (*HiiFormPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ //
+ // Get HiiFormPackage by HiiHandle
+ //
+ Size = ResultSize;
+ ResultSize = 0;
+ Status = ExportFormPackages (
+ &mPrivate,
+ DataBaseRecord->Handle,
+ DataBaseRecord->PackageList,
+ 0,
+ Size,
+ *HiiFormPackage,
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (*HiiFormPackage);
+ }
+
+ *PackageSize = Size;
+
+ return Status;
+}
+
+
+/**
+ This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
+
+ @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
+ @param ConfigHdr Request string ConfigHdr. If it is NULL,
+ the first found varstore will be as ConfigHdr.
+ @param IsEfiVarstore Whether the request storage type is efi varstore type.
+ @param EfiVarStore The efi varstore info which will return.
+**/
+EFI_STATUS
+GetVarStoreType (
+ IN HII_DATABASE_RECORD *DataBaseRecord,
+ IN EFI_STRING ConfigHdr,
+ OUT BOOLEAN *IsEfiVarstore,
+ OUT EFI_IFR_VARSTORE_EFI **EfiVarStore
+ )
+{
+ EFI_STATUS Status;
+ UINTN IfrOffset;
+ UINTN PackageOffset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ CHAR16 *VarStoreName;
+ UINTN NameSize;
+ EFI_STRING GuidStr;
+ EFI_STRING NameStr;
+ EFI_STRING TempStr;
+ UINTN LengthString;
+ UINT8 *HiiFormPackage;
+ UINTN PackageSize;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ EFI_HII_PACKAGE_HEADER *PackageHeader;
+
+ HiiFormPackage = NULL;
+ LengthString = 0;
+ Status = EFI_SUCCESS;
+ GuidStr = NULL;
+ NameStr = NULL;
+ TempStr = NULL;
+ *IsEfiVarstore = FALSE;
+
+ Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageOffset = IfrOffset;
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
+
+ while (IfrOffset < PackageSize) {
+ //
+ // More than one form packages exist.
+ //
+ if (PackageOffset >= PackageHeader->Length) {
+ //
+ // Process the new form package.
+ //
+ PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ IfrOffset += PackageOffset;
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
+ }
+
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
+ IfrOffset += IfrOpHdr->Length;
+ PackageOffset += IfrOpHdr->Length;
+
+ if (IfrOpHdr->OpCode == EFI_IFR_VARSTORE_EFI_OP ) {
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+ //
+ // If the length is small than the structure, this is from old efi
+ // varstore definition. Old efi varstore get config directly from
+ // GetVariable function.
+ //
+ if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
+ continue;
+ }
+
+ NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) IfrEfiVarStore->Name, VarStoreName, NameSize);
+
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrEfiVarStore->Guid, 1, &GuidStr);
+ GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
+ LengthString = StrLen (GuidStr);
+ LengthString = LengthString + StrLen (NameStr) + 1;
+ TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
+ if (TempStr == NULL) {
+ FreePool (GuidStr);
+ FreePool (NameStr);
+ FreePool (VarStoreName);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ StrCpyS (TempStr, LengthString, GuidStr);
+ StrCatS (TempStr, LengthString, NameStr);
+ if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
+ *EfiVarStore = (EFI_IFR_VARSTORE_EFI *) AllocateZeroPool (IfrOpHdr->Length);
+ if (*EfiVarStore == NULL) {
+ FreePool (VarStoreName);
+ FreePool (GuidStr);
+ FreePool (NameStr);
+ FreePool (TempStr);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ *IsEfiVarstore = TRUE;
+ CopyMem (*EfiVarStore, IfrEfiVarStore, IfrOpHdr->Length);
+ }
+
+ //
+ // Free allocated temp string.
+ //
+ FreePool (VarStoreName);
+ FreePool (GuidStr);
+ FreePool (NameStr);
+ FreePool (TempStr);
+
+ //
+ // Already found the varstore, break;
+ //
+ if (*IsEfiVarstore) {
+ break;
+ }
+ }
+ }
+Done:
+ if (HiiFormPackage != NULL) {
+ FreePool (HiiFormPackage);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the ConfigRequest string has the request elements.
+ For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
+ For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
+
+ @param ConfigRequest The input config request string.
+
+ @retval TRUE The input include config request elements.
+ @retval FALSE The input string not includes.
+
+**/
+BOOLEAN
+GetElementsFromRequest (
+ IN EFI_STRING ConfigRequest
+ )
+{
+ EFI_STRING TmpRequest;
+
+ TmpRequest = StrStr (ConfigRequest, L"PATH=");
+ ASSERT (TmpRequest != NULL);
+
+ if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether the this varstore is the request varstore.
+
+ @param VarstoreGuid Varstore guid.
+ @param Name Varstore name.
+ @param ConfigHdr Current configRequest info.
+
+ @retval TRUE This varstore is the request one.
+ @retval FALSE This varstore is not the request one.
+
+**/
+BOOLEAN
+IsThisVarstore (
+ IN EFI_GUID *VarstoreGuid,
+ IN CHAR16 *Name,
+ IN CHAR16 *ConfigHdr
+ )
+{
+ EFI_STRING GuidStr;
+ EFI_STRING NameStr;
+ EFI_STRING TempStr;
+ UINTN LengthString;
+ BOOLEAN RetVal;
+
+ RetVal = FALSE;
+ GuidStr = NULL;
+ TempStr = NULL;
+
+ //
+ // If ConfigHdr has name field and varstore not has name, return FALSE.
+ //
+ if (Name == NULL && ConfigHdr != NULL && StrStr (ConfigHdr, L"NAME=&") == NULL) {
+ return FALSE;
+ }
+
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)VarstoreGuid, 1, &GuidStr);
+ if (Name != NULL) {
+ GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
+ } else {
+ GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
+ }
+ LengthString = StrLen (GuidStr);
+ LengthString = LengthString + StrLen (NameStr) + 1;
+ TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
+ if (TempStr == NULL) {
+ goto Done;
+ }
+
+ StrCpyS (TempStr, LengthString, GuidStr);
+ StrCatS (TempStr, LengthString, NameStr);
+
+ if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
+ RetVal = TRUE;
+ }
+
+Done:
+ if (GuidStr != NULL) {
+ FreePool (GuidStr);
+ }
+
+ if (NameStr != NULL) {
+ FreePool (NameStr);
+ }
+
+ if (TempStr != NULL) {
+ FreePool (TempStr);
+ }
+
+ return RetVal;
+}
+
+/**
+ This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
+
+ @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
+ @param ConfigHdr Request string ConfigHdr. If it is NULL,
+ the first found varstore will be as ConfigHdr.
+ @retval TRUE This hii package is the request one.
+ @retval FALSE This hii package is not the request one.
+**/
+BOOLEAN
+IsThisPackageList (
+ IN HII_DATABASE_RECORD *DataBaseRecord,
+ IN EFI_STRING ConfigHdr
+ )
+{
+ EFI_STATUS Status;
+ UINTN IfrOffset;
+ UINTN PackageOffset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ CHAR16 *VarStoreName;
+ UINTN NameSize;
+ UINT8 *HiiFormPackage;
+ UINTN PackageSize;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ EFI_HII_PACKAGE_HEADER *PackageHeader;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
+ BOOLEAN FindVarstore;
+
+ HiiFormPackage = NULL;
+ VarStoreName = NULL;
+ Status = EFI_SUCCESS;
+ FindVarstore = FALSE;
+
+ Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageOffset = IfrOffset;
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
+
+ while (IfrOffset < PackageSize) {
+ //
+ // More than one form packages exist.
+ //
+ if (PackageOffset >= PackageHeader->Length) {
+ //
+ // Process the new form package.
+ //
+ PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ IfrOffset += PackageOffset;
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
+ }
+
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
+ IfrOffset += IfrOpHdr->Length;
+ PackageOffset += IfrOpHdr->Length;
+
+ switch (IfrOpHdr->OpCode) {
+
+ case EFI_IFR_VARSTORE_OP:
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
+
+ NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize);
+
+ if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
+ FindVarstore = TRUE;
+ goto Done;
+ } else {
+ FreePool (VarStoreName);
+ VarStoreName = NULL;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+ NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
+
+ if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
+ FindVarstore = TRUE;
+ goto Done;
+ } else {
+ FreePool (VarStoreName);
+ VarStoreName = NULL;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
+
+ if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
+ FindVarstore = TRUE;
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // No matched varstore is found and directly return.
+ //
+ goto Done;
+
+ default:
+ break;
+ }
+ }
+Done:
+ if (HiiFormPackage != NULL) {
+ FreePool (HiiFormPackage);
+ }
+
+ if (VarStoreName != NULL) {
+ FreePool (VarStoreName);
+ }
+
+ return FindVarstore;
+}
+
+/**
+ Check whether the this op code is required.
+
+ @param RequestBlockArray The array includes all the request info or NULL.
+ @param HiiHandle The hii handle for this form package.
+ @param VarStorageData The varstore data structure.
+ @param IfrOpHdr Ifr opcode header for this opcode.
+ @param VarWidth The buffer width for this opcode.
+ @param ReturnData The data block added for this opcode.
+ @param IsBitVar Whether the the opcode refers to bit storage.
+
+ @retval EFI_SUCCESS This opcode is required.
+ @retval EFI_NOT_FOUND This opcode is not required.
+ @retval Others Contain some error.
+
+**/
+EFI_STATUS
+IsThisOpcodeRequired (
+ IN IFR_BLOCK_DATA *RequestBlockArray,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
+ IN EFI_IFR_OP_HEADER *IfrOpHdr,
+ IN UINT16 VarWidth,
+ OUT IFR_BLOCK_DATA **ReturnData,
+ IN BOOLEAN IsBitVar
+ )
+{
+ IFR_BLOCK_DATA *BlockData;
+ UINT16 VarOffset;
+ EFI_STRING_ID NameId;
+ EFI_IFR_QUESTION_HEADER *IfrQuestionHdr;
+ UINT16 BitOffset;
+ UINT16 BitWidth;
+ UINT16 TotalBits;
+
+ NameId = 0;
+ VarOffset = 0;
+ BitOffset = 0;
+ BitWidth = 0;
+ IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *)((CHAR8 *) IfrOpHdr + sizeof (EFI_IFR_OP_HEADER));
+
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ NameId = IfrQuestionHdr->VarStoreInfo.VarName;
+
+ //
+ // Check whether this question is in requested block array.
+ //
+ if (!BlockArrayCheck (RequestBlockArray, NameId, 0, TRUE, HiiHandle)) {
+ //
+ // This question is not in the requested string. Skip it.
+ //
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ //
+ // Get the byte offset/with and bit offset/width
+ //
+ if (IsBitVar) {
+ BitOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
+ BitWidth = VarWidth;
+ VarOffset = BitOffset / 8;
+ //
+ // Use current bit width and the bit width before current bit (with same byte offset) to calculate the byte width.
+ //
+ TotalBits = BitOffset % 8 + BitWidth;
+ VarWidth = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
+ } else {
+ VarOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
+ BitWidth = VarWidth;
+ BitOffset = VarOffset * 8;
+ }
+
+ //
+ // Check whether this question is in requested block array.
+ //
+ if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth, FALSE, HiiHandle)) {
+ //
+ // This question is not in the requested string. Skip it.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check this var question is in the var storage
+ //
+ if (((VarOffset + VarWidth) > VarStorageData->Size)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (BlockData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ BlockData->Name = InternalGetString(HiiHandle, NameId);
+ } else {
+ BlockData->Offset = VarOffset;
+ }
+
+ BlockData->Width = VarWidth;
+ BlockData->QuestionId = IfrQuestionHdr->QuestionId;
+ BlockData->OpCode = IfrOpHdr->OpCode;
+ BlockData->Scope = IfrOpHdr->Scope;
+ BlockData->IsBitVar = IsBitVar;
+ BlockData->BitOffset = BitOffset;
+ BlockData->BitWidth = BitWidth;
+ InitializeListHead (&BlockData->DefaultValueEntry);
+ //
+ // Add Block Data into VarStorageData BlockEntry
+ //
+ InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
+ *ReturnData = BlockData;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function parses Form Package to get the block array and the default
+ value array according to the request ConfigHdr.
+
+ @param HiiHandle Hii Handle for this hii package.
+ @param Package Pointer to the form package data.
+ @param PackageLength Length of the package.
+ @param ConfigHdr Request string ConfigHdr. If it is NULL,
+ the first found varstore will be as ConfigHdr.
+ @param RequestBlockArray The block array is retrieved from the request string.
+ @param VarStorageData VarStorage structure contains the got block and default value.
+ @param DefaultIdArray Point to the got default id and default name array.
+
+ @retval EFI_SUCCESS The block array and the default value array are got.
+ @retval EFI_INVALID_PARAMETER The varstore definition in the different form packages
+ are conflicted.
+ @retval EFI_OUT_OF_RESOURCES No enough memory.
+**/
+EFI_STATUS
+EFIAPI
+ParseIfrData (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN UINT8 *Package,
+ IN UINT32 PackageLength,
+ IN EFI_STRING ConfigHdr,
+ IN IFR_BLOCK_DATA *RequestBlockArray,
+ IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
+ OUT IFR_DEFAULT_DATA *DefaultIdArray
+ )
+{
+ EFI_STATUS Status;
+ UINTN IfrOffset;
+ UINTN PackageOffset;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_ONE_OF *IfrOneOf;
+ EFI_IFR_REF4 *IfrRef;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+ EFI_IFR_DEFAULT *IfrDefault;
+ EFI_IFR_ORDERED_LIST *IfrOrderedList;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_PASSWORD *IfrPassword;
+ EFI_IFR_STRING *IfrString;
+ EFI_IFR_DATE *IfrDate;
+ EFI_IFR_TIME *IfrTime;
+ IFR_DEFAULT_DATA DefaultData;
+ IFR_DEFAULT_DATA *DefaultDataPtr;
+ IFR_BLOCK_DATA *BlockData;
+ CHAR16 *VarStoreName;
+ UINTN NameSize;
+ UINT16 VarWidth;
+ UINT16 VarDefaultId;
+ BOOLEAN FirstOneOfOption;
+ BOOLEAN FirstOrderedList;
+ LIST_ENTRY *LinkData;
+ LIST_ENTRY *LinkDefault;
+ EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
+ EFI_HII_PACKAGE_HEADER *PackageHeader;
+ EFI_VARSTORE_ID VarStoreId;
+ UINT16 SmallestDefaultId;
+ BOOLEAN SmallestIdFromFlag;
+ BOOLEAN FromOtherDefaultOpcode;
+ BOOLEAN QuestionReferBitField;
+
+ Status = EFI_SUCCESS;
+ BlockData = NULL;
+ DefaultDataPtr = NULL;
+ FirstOneOfOption = FALSE;
+ VarStoreId = 0;
+ FirstOrderedList = FALSE;
+ VarStoreName = NULL;
+ ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA));
+ SmallestDefaultId = 0xFFFF;
+ FromOtherDefaultOpcode = FALSE;
+ QuestionReferBitField = FALSE;
+
+ //
+ // Go through the form package to parse OpCode one by one.
+ //
+ PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) Package;
+ IfrOffset = PackageOffset;
+ while (IfrOffset < PackageLength) {
+
+ //
+ // More than one form package found.
+ //
+ if (PackageOffset >= PackageHeader->Length) {
+ //
+ // Already found varstore for this request, break;
+ //
+ if (VarStoreId != 0) {
+ VarStoreId = 0;
+ }
+
+ //
+ // Get next package header info.
+ //
+ IfrOffset += sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageHeader = (EFI_HII_PACKAGE_HEADER *) (Package + IfrOffset);
+ }
+
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
+ switch (IfrOpHdr->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // VarStore is found. Don't need to search any more.
+ //
+ if (VarStoreId != 0) {
+ break;
+ }
+
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
+
+ NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize);
+
+ if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
+ //
+ // Find the matched VarStore
+ //
+ CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
+ VarStorageData->Size = IfrVarStore->Size;
+ VarStorageData->Name = VarStoreName;
+ VarStorageData->Type = EFI_HII_VARSTORE_BUFFER;
+ VarStoreId = IfrVarStore->VarStoreId;
+ } else {
+ FreePool (VarStoreName);
+ VarStoreName = NULL;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // VarStore is found. Don't need to search any more.
+ //
+ if (VarStoreId != 0) {
+ break;
+ }
+
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+
+ //
+ // If the length is small than the structure, this is from old efi
+ // varstore definition. Old efi varstore get config directly from
+ // GetVariable function.
+ //
+ if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
+ break;
+ }
+
+ NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
+
+ if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
+ //
+ // Find the matched VarStore
+ //
+ CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid);
+ VarStorageData->Size = IfrEfiVarStore->Size;
+ VarStorageData->Name = VarStoreName;
+ VarStorageData->Type = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER;
+ VarStoreId = IfrEfiVarStore->VarStoreId;
+ } else {
+ FreePool (VarStoreName);
+ VarStoreName = NULL;
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // VarStore is found. Don't need to search any more.
+ //
+ if (VarStoreId != 0) {
+ break;
+ }
+
+ IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
+
+ if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
+ //
+ // Find the matched VarStore
+ //
+ CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrNameValueVarStore->Guid);
+ VarStorageData->Type = EFI_HII_VARSTORE_NAME_VALUE;
+ VarStoreId = IfrNameValueVarStore->VarStoreId;
+ }
+ break;
+
+ case EFI_IFR_DEFAULTSTORE_OP:
+ //
+ // Add new the map between default id and default name.
+ //
+ DefaultDataPtr = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
+ if (DefaultDataPtr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ DefaultDataPtr->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
+ InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry);
+ DefaultDataPtr = NULL;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // No matched varstore is found and directly return.
+ //
+ if ( VarStoreId == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_REF_OP:
+ //
+ // Ref question is not in IFR Form. This IFR form is not valid.
+ //
+ if ( VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrRef = (EFI_IFR_REF4 *) IfrOpHdr;
+ if (IfrRef->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+ VarWidth = (UINT16) (sizeof (EFI_HII_REF));
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Numeric and OneOf has the same opcode structure.
+ //
+
+ //
+ // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
+ if (IfrOneOf->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+
+ if (QuestionReferBitField) {
+ VarWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ } else {
+ VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+
+ //
+ //when go to there,BlockData can't be NULLL.
+ //
+ ASSERT (BlockData != NULL);
+
+ if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
+ //
+ // Set this flag to TRUE for the first oneof option.
+ //
+ FirstOneOfOption = TRUE;
+ } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
+ //
+ // Numeric minimum value will be used as default value when no default is specified.
+ //
+ DefaultData.Type = DefaultValueFromDefault;
+ if (QuestionReferBitField) {
+ //
+ // Since default value in bit field was stored as UINT32 type.
+ //
+ CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
+ } else {
+ switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ //
+ // Set default value base on the DefaultId list get from IFR data.
+ //
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ //
+ // offset by question header
+ // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
+ //
+
+ FirstOrderedList = TRUE;
+ //
+ // OrderedList question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
+ if (IfrOrderedList->Question.VarStoreId != VarStoreId) {
+ BlockData = NULL;
+ break;
+ }
+ VarWidth = IfrOrderedList->MaxContainers;
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ //
+ // EFI_IFR_DEFAULT_OP
+ // offset by question header
+ // width is 1 sizeof (BOOLEAN)
+ // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
+ // value by DefaultOption
+ // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
+ //
+
+ //
+ // CheckBox question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
+ if (IfrCheckBox->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+ VarWidth = (UINT16) sizeof (BOOLEAN);
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ if (QuestionReferBitField) {
+ VarWidth = 1;
+ }
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+
+ //
+ //when go to there,BlockData can't be NULLL.
+ //
+ ASSERT (BlockData != NULL);
+
+ SmallestIdFromFlag = FALSE;
+
+ //
+ // Add default value for standard ID by CheckBox Flag
+ //
+ VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ //
+ // Prepare new DefaultValue
+ //
+ DefaultData.DefaultId = VarDefaultId;
+ if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
+ //
+ // When flag is set, default value is TRUE.
+ //
+ DefaultData.Type = DefaultValueFromFlag;
+ if (QuestionReferBitField) {
+ DefaultData.Value.u32 = TRUE;
+ } else {
+ DefaultData.Value.b = TRUE;
+ }
+ InsertDefaultValue (BlockData, &DefaultData);
+
+ if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
+ //
+ // Record the SmallestDefaultId and update the SmallestIdFromFlag.
+ //
+ SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ SmallestIdFromFlag = TRUE;
+ }
+ }
+
+ //
+ // Add default value for Manufacture ID by CheckBox Flag
+ //
+ VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ //
+ // Prepare new DefaultValue
+ //
+ DefaultData.DefaultId = VarDefaultId;
+ if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
+ //
+ // When flag is set, default value is TRUE.
+ //
+ DefaultData.Type = DefaultValueFromFlag;
+ if (QuestionReferBitField) {
+ DefaultData.Value.u32 = TRUE;
+ } else {
+ DefaultData.Value.b = TRUE;
+ }
+ InsertDefaultValue (BlockData, &DefaultData);
+
+ if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // Record the SmallestDefaultId and update the SmallestIdFromFlag.
+ //
+ SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ SmallestIdFromFlag = TRUE;
+ }
+ }
+ if (SmallestIdFromFlag) {
+ //
+ // When smallest default Id is given by the flag of CheckBox, set default value with TRUE for other default Id in the DefaultId list.
+ //
+ DefaultData.Type = DefaultValueFromOtherDefault;
+ if (QuestionReferBitField) {
+ DefaultData.Value.u32 = TRUE;
+ } else {
+ DefaultData.Value.b = TRUE;
+ }
+ //
+ // Set default value for all the default id in the DefaultId list.
+ //
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ } else {
+ //
+ // When flag is not set, default value is FASLE.
+ //
+ DefaultData.Type = DefaultValueFromDefault;
+ if (QuestionReferBitField) {
+ DefaultData.Value.u32 = FALSE;
+ } else {
+ DefaultData.Value.b = FALSE;
+ }
+ //
+ // Set default value for all the default id in the DefaultId list.
+ //
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ }
+ break;
+
+ case EFI_IFR_DATE_OP:
+ //
+ // offset by question header
+ // width MaxSize * sizeof (CHAR16)
+ // no default value, only block array
+ //
+
+ //
+ // Date question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrDate = (EFI_IFR_DATE *) IfrOpHdr;
+ if (IfrDate->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ VarWidth = (UINT16) sizeof (EFI_HII_DATE);
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_TIME_OP:
+ //
+ // offset by question header
+ // width MaxSize * sizeof (CHAR16)
+ // no default value, only block array
+ //
+
+ //
+ // Time question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrTime = (EFI_IFR_TIME *) IfrOpHdr;
+ if (IfrTime->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ VarWidth = (UINT16) sizeof (EFI_HII_TIME);
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_STRING_OP:
+ //
+ // offset by question header
+ // width MaxSize * sizeof (CHAR16)
+ // no default value, only block array
+ //
+
+ //
+ // String question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrString = (EFI_IFR_STRING *) IfrOpHdr;
+ if (IfrString->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ //
+ // offset by question header
+ // width MaxSize * sizeof (CHAR16)
+ // no default value, only block array
+ //
+
+ //
+ // Password question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreId == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
+ if (IfrPassword->Question.VarStoreId != VarStoreId) {
+ break;
+ }
+
+ //
+ // The BlockData may allocate by other opcode,need to clean.
+ //
+ if (BlockData != NULL){
+ BlockData = NULL;
+ }
+
+ VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
+ Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND){
+ //
+ //The opcode is not required,exit and parse other opcode.
+ //
+ break;
+ }
+ goto Done;
+ }
+
+ //
+ // No default value for string.
+ //
+ BlockData = NULL;
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // No matched block data is ignored.
+ //
+ if (BlockData == NULL || BlockData->Scope == 0) {
+ break;
+ }
+
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
+ if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
+
+ if (!FirstOrderedList){
+ break;
+ }
+ //
+ // Get ordered list option data type.
+ //
+ if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
+ VarWidth = 1;
+ } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
+ VarWidth = 2;
+ } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
+ VarWidth = 4;
+ } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
+ VarWidth = 8;
+ } else {
+ //
+ // Invalid ordered list option data type.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ FreePool (BlockData);
+ goto Done;
+ }
+
+ //
+ // Calculate Ordered list QuestionId width.
+ //
+ BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
+ //
+ // Check whether this question is in requested block array.
+ //
+ if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) {
+ //
+ // This question is not in the requested string. Skip it.
+ //
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ FreePool (BlockData);
+ BlockData = NULL;
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) {
+ Status = EFI_INVALID_PARAMETER;
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ FreePool (BlockData);
+ goto Done;
+ }
+ //
+ // Add Block Data into VarStorageData BlockEntry
+ //
+ InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
+
+ FirstOrderedList = FALSE;
+
+ break;
+ }
+
+ //
+ // 1. Set default value for OneOf option when flag field has default attribute.
+ // And set the default value with the smallest default id for other default id in the DefaultId list.
+ //
+ if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
+ ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) {
+ //
+ // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
+ // The first oneof option value will be used as default value when no default value is specified.
+ //
+ FirstOneOfOption = FALSE;
+
+ SmallestIdFromFlag = FALSE;
+
+ // Prepare new DefaultValue
+ //
+ DefaultData.Type = DefaultValueFromFlag;
+ CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
+ DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ InsertDefaultValue (BlockData, &DefaultData);
+ if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
+ //
+ // Record the SmallestDefaultId and update the SmallestIdFromFlag.
+ //
+ SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ SmallestIdFromFlag = TRUE;
+ }
+ }
+ if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
+ DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ InsertDefaultValue (BlockData, &DefaultData);
+ if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // Record the SmallestDefaultId and update the SmallestIdFromFlag.
+ //
+ SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ SmallestIdFromFlag = TRUE;
+ }
+ }
+
+ if (SmallestIdFromFlag) {
+ //
+ // When smallest default Id is given by the flag of oneofOption, set this option value for other default Id in the DefaultId list.
+ //
+ DefaultData.Type = DefaultValueFromOtherDefault;
+ //
+ // Set default value for other default id in the DefaultId list.
+ //
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ }
+ }
+
+ //
+ // 2. Set as the default value when this is the first option.
+ // The first oneof option value will be used as default value when no default value is specified.
+ //
+ if (FirstOneOfOption) {
+ // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
+ FirstOneOfOption = FALSE;
+
+ //
+ // Prepare new DefaultValue
+ //
+ DefaultData.Type = DefaultValueFromDefault;
+ CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ }
+ break;
+
+ case EFI_IFR_DEFAULT_OP:
+ //
+ // Update Current BlockData to the default value.
+ //
+ if (BlockData == NULL || BlockData->Scope == 0) {
+ //
+ // No matched block data is ignored.
+ //
+ break;
+ }
+
+ //
+ // Get the DefaultId
+ //
+ IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
+ VarDefaultId = IfrDefault->DefaultId;
+ //
+ // Prepare new DefaultValue
+ //
+ DefaultData.Type = DefaultValueFromOpcode;
+ DefaultData.DefaultId = VarDefaultId;
+ if (QuestionReferBitField) {
+ CopyMem (&DefaultData.Value.u32, &IfrDefault->Value.u32, sizeof (UINT32));
+ } else {
+ CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value));
+ }
+
+ // If the value field is expression, set the cleaned flag.
+ if (IfrDefault->Type == EFI_IFR_TYPE_OTHER) {
+ DefaultData.Cleaned = TRUE;
+ }
+ //
+ // Add DefaultValue into current BlockData
+ //
+ InsertDefaultValue (BlockData, &DefaultData);
+
+ //
+ // Set default value for other default id in the DefaultId list.
+ // when SmallestDefaultId == VarDefaultId means there are two defaults with same default Id.
+ // If the two defaults are both from default opcode, use the first default as the default value of other default Id.
+ // If one from flag and the other form default opcode, use the default opcode value as the default value of other default Id.
+ //
+ if ((SmallestDefaultId > VarDefaultId) || (SmallestDefaultId == VarDefaultId && !FromOtherDefaultOpcode)) {
+ FromOtherDefaultOpcode = TRUE;
+ SmallestDefaultId = VarDefaultId;
+ for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
+ DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
+ if (DefaultDataPtr->DefaultId != DefaultData.DefaultId){
+ DefaultData.Type = DefaultValueFromOtherDefault;
+ DefaultData.DefaultId = DefaultDataPtr->DefaultId;
+ InsertDefaultValue (BlockData, &DefaultData);
+ }
+ }
+ }
+
+ //
+ // After insert the default value, reset the cleaned value for next
+ // time used. If not set here, need to set the value before every time.
+ // use it.
+ //
+ DefaultData.Cleaned = FALSE;
+ break;
+
+ case EFI_IFR_END_OP:
+ //
+ // End Opcode is for Var question.
+ //
+ QuestionReferBitField = FALSE;
+ if (BlockData != NULL) {
+ if (BlockData->Scope > 0) {
+ BlockData->Scope--;
+ }
+ if (BlockData->Scope == 0) {
+ BlockData = NULL;
+ //
+ // when finishing parsing a question, clean the SmallestDefaultId and GetDefaultFromDefaultOpcode.
+ //
+ SmallestDefaultId = 0xFFFF;
+ FromOtherDefaultOpcode = FALSE;
+ }
+ }
+
+ break;
+
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ QuestionReferBitField = TRUE;
+ }
+ break;
+
+ default:
+ if (BlockData != NULL) {
+ if (BlockData->Scope > 0) {
+ BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
+ }
+
+ if (BlockData->Scope == 0) {
+ BlockData = NULL;
+ }
+ }
+ break;
+ }
+
+ IfrOffset += IfrOpHdr->Length;
+ PackageOffset += IfrOpHdr->Length;
+ }
+
+ //
+ //if Status == EFI_NOT_FOUND, just means the opcode is not required,not contain any error,
+ //so set the Status to EFI_SUCCESS.
+ //
+ if (Status == EFI_NOT_FOUND){
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
+ BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
+ for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; ) {
+ DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
+ LinkDefault = LinkDefault->ForwardLink;
+ if (DefaultDataPtr->Cleaned == TRUE) {
+ RemoveEntryList (&DefaultDataPtr->Entry);
+ FreePool (DefaultDataPtr);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ parse the configrequest string, get the elements.
+
+ @param ConfigRequest The input configrequest string.
+ @param Progress Return the progress data.
+
+ @retval Block data pointer.
+**/
+IFR_BLOCK_DATA *
+GetBlockElement (
+ IN EFI_STRING ConfigRequest,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STRING StringPtr;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_BLOCK_DATA *RequestBlockArray;
+ EFI_STATUS Status;
+ UINT8 *TmpBuffer;
+ UINT16 Offset;
+ UINT16 Width;
+ LIST_ENTRY *Link;
+ IFR_BLOCK_DATA *NextBlockData;
+ UINTN Length;
+
+ TmpBuffer = NULL;
+
+ //
+ // Init RequestBlockArray
+ //
+ RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (RequestBlockArray == NULL) {
+ goto Done;
+ }
+ InitializeListHead (&RequestBlockArray->Entry);
+
+ //
+ // Get the request Block array from the request string
+ // Offset and Width
+ //
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ StringPtr = ConfigRequest;
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
+ //
+ // Skip the OFFSET string
+ //
+ *Progress = StringPtr;
+ StringPtr += StrLen (L"&OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ goto Done;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ goto Done;
+ }
+
+ //
+ // Set Block Data
+ //
+ BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (BlockData == NULL) {
+ goto Done;
+ }
+ BlockData->Offset = Offset;
+ BlockData->Width = Width;
+ InsertBlockData (&RequestBlockArray->Entry, &BlockData);
+
+ //
+ // Skip &VALUE string if &VALUE does exists.
+ //
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ FreePool (TmpBuffer);
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ goto Done;
+ }
+ }
+ //
+ // If '\0', parsing is finished.
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ }
+
+ //
+ // Merge the requested block data.
+ //
+ Link = RequestBlockArray->Entry.ForwardLink;
+ while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
+ if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
+ if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
+ BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
+ }
+ RemoveEntryList (Link->ForwardLink);
+ FreePool (NextBlockData);
+ continue;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ return RequestBlockArray;
+
+Done:
+ if (RequestBlockArray != NULL) {
+ //
+ // Free Link Array RequestBlockArray
+ //
+ while (!IsListEmpty (&RequestBlockArray->Entry)) {
+ BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ FreePool (BlockData);
+ }
+
+ FreePool (RequestBlockArray);
+ }
+
+ return NULL;
+}
+
+/**
+ parse the configrequest string, get the elements.
+
+ @param ConfigRequest The input config request string.
+ @param Progress Return the progress data.
+
+ @retval return data block array.
+**/
+IFR_BLOCK_DATA *
+GetNameElement (
+ IN EFI_STRING ConfigRequest,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STRING StringPtr;
+ EFI_STRING NextTag;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_BLOCK_DATA *RequestBlockArray;
+ BOOLEAN HasValue;
+
+ StringPtr = ConfigRequest;
+
+ //
+ // Init RequestBlockArray
+ //
+ RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (RequestBlockArray == NULL) {
+ goto Done;
+ }
+ InitializeListHead (&RequestBlockArray->Entry);
+
+ //
+ // Get the request Block array from the request string
+ //
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= &'Name***=***
+ //
+ while (StringPtr != NULL && *StringPtr == L'&') {
+
+ *Progress = StringPtr;
+ //
+ // Skip the L"&" string
+ //
+ StringPtr += 1;
+
+ HasValue = FALSE;
+ if ((NextTag = StrStr (StringPtr, L"=")) != NULL) {
+ *NextTag = L'\0';
+ HasValue = TRUE;
+ } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) {
+ *NextTag = L'\0';
+ }
+
+ //
+ // Set Block Data
+ //
+ BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (BlockData == NULL) {
+ goto Done;
+ }
+
+ //
+ // Get Name
+ //
+ BlockData->Name = AllocateCopyPool(StrSize (StringPtr), StringPtr);
+ InsertBlockData (&RequestBlockArray->Entry, &BlockData);
+
+ if (HasValue) {
+ //
+ // If has value, skip the value.
+ //
+ StringPtr = NextTag + 1;
+ *NextTag = L'=';
+ StringPtr = StrStr (StringPtr, L"&");
+ } else if (NextTag != NULL) {
+ //
+ // restore the '&' text.
+ //
+ StringPtr = NextTag;
+ *NextTag = L'&';
+ }
+ }
+
+ return RequestBlockArray;
+
+Done:
+ if (RequestBlockArray != NULL) {
+ //
+ // Free Link Array RequestBlockArray
+ //
+ while (!IsListEmpty (&RequestBlockArray->Entry)) {
+ BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ FreePool (BlockData);
+ }
+
+ FreePool (RequestBlockArray);
+ }
+
+ return NULL;
+}
+
+/**
+ Generate ConfigRequest string base on the varstore info.
+
+ @param ConfigHdr The config header for this varstore.
+ @param VarStorageData The varstore info.
+ @param Status Return Status.
+ @param ConfigRequest The ConfigRequest info may be return.
+
+ @retval TRUE Need to continue
+ @retval Others NO need to continue or error occur.
+**/
+BOOLEAN
+GenerateConfigRequest (
+ IN CHAR16 *ConfigHdr,
+ IN IFR_VARSTORAGE_DATA *VarStorageData,
+ OUT EFI_STATUS *Status,
+ IN OUT EFI_STRING *ConfigRequest
+ )
+{
+ BOOLEAN DataExist;
+ UINTN Length;
+ LIST_ENTRY *Link;
+ CHAR16 *FullConfigRequest;
+ CHAR16 *StringPtr;
+ IFR_BLOCK_DATA *BlockData;
+
+ //
+ // Append VarStorageData BlockEntry into *Request string
+ // Now support only one varstore in a form package.
+ //
+
+ //
+ // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
+ // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
+ //
+
+ //
+ // Compute the length of the entire request starting with <ConfigHdr> and a
+ // Null-terminator
+ //
+ DataExist = FALSE;
+ Length = StrLen (ConfigHdr) + 1;
+
+ for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
+ DataExist = TRUE;
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Add <BlockName> length for each Name
+ //
+ // <BlockName> ::= &Name1&Name2&...
+ // |1| StrLen(Name1)
+ //
+ Length = Length + (1 + StrLen (BlockData->Name));
+ } else {
+ //
+ // Add <BlockName> length for each Offset/Width pair
+ //
+ // <BlockName> ::= &OFFSET=1234&WIDTH=1234
+ // | 8 | 4 | 7 | 4 |
+ //
+ Length = Length + (8 + 4 + 7 + 4);
+ }
+ }
+ //
+ // No any request block data is found. The request string can't be constructed.
+ //
+ if (!DataExist) {
+ *Status = EFI_SUCCESS;
+ return FALSE;
+ }
+
+ //
+ // Allocate buffer for the entire <ConfigRequest>
+ //
+ FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (FullConfigRequest == NULL) {
+ *Status = EFI_OUT_OF_RESOURCES;
+ return FALSE;
+ }
+ StringPtr = FullConfigRequest;
+
+ //
+ // Start with <ConfigHdr>
+ //
+ StrCpyS (StringPtr, Length, ConfigHdr);
+ StringPtr += StrLen (StringPtr);
+
+ //
+ // Loop through all the Offset/Width pairs and append them to ConfigRequest
+ //
+ for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Append &Name1\0
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16),
+ L"&%s",
+ BlockData->Name
+ );
+ } else {
+ //
+ // Append &OFFSET=XXXX&WIDTH=YYYY\0
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
+ L"&OFFSET=%04X&WIDTH=%04X",
+ BlockData->Offset,
+ BlockData->Width
+ );
+ }
+ StringPtr += StrLen (StringPtr);
+ }
+ //
+ // Set to the got full request string.
+ //
+ HiiToLower (FullConfigRequest);
+
+ if (*ConfigRequest != NULL) {
+ FreePool (*ConfigRequest);
+ }
+ *ConfigRequest = FullConfigRequest;
+
+ return TRUE;
+}
+
+/**
+ Generate ConfigRequest Header base on the varstore info.
+
+ @param VarStorageData The varstore info.
+ @param DevicePath Device path for this varstore.
+ @param ConfigHdr The config header for this varstore.
+
+ @retval EFI_SUCCESS Generate the header success.
+ @retval EFI_OUT_OF_RESOURCES Allocate buffer fail.
+**/
+EFI_STATUS
+GenerateHdr (
+ IN IFR_VARSTORAGE_DATA *VarStorageData,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_STRING *ConfigHdr
+ )
+{
+ EFI_STRING GuidStr;
+ EFI_STRING NameStr;
+ EFI_STRING PathStr;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ NameStr = NULL;
+ GuidStr = NULL;
+ PathStr = NULL;
+
+ //
+ // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
+ //
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
+ if (VarStorageData->Name != NULL) {
+ GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
+ } else {
+ GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
+ }
+ GenerateSubStr (
+ L"PATH=",
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
+ (VOID *) DevicePath,
+ 1,
+ &PathStr
+ );
+ Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1;
+ if (VarStorageData->Name == NULL) {
+ Length += 1;
+ }
+
+ *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (*ConfigHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ StrCpyS (*ConfigHdr, Length, GuidStr);
+ StrCatS (*ConfigHdr, Length, NameStr);
+ if (VarStorageData->Name == NULL) {
+ StrCatS (*ConfigHdr, Length, L"&");
+ }
+ StrCatS (*ConfigHdr, Length, PathStr);
+
+ //
+ // Remove the last character L'&'
+ //
+ *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0';
+
+Done:
+ if (GuidStr != NULL) {
+ FreePool (GuidStr);
+ }
+
+ if (NameStr != NULL) {
+ FreePool (NameStr);
+ }
+
+ if (PathStr != NULL) {
+ FreePool (PathStr);
+ }
+
+ return Status;
+}
+
+
+/**
+ Update the default value in the block data which is used as bit var store.
+
+ For example:
+ A question value saved in a bit fied: bitoffset = 1; bitwidth = 2;default value = 1.
+ And corresponding block data info: offset==0; width==1;currently the default value
+ is saved as 1.Actually the default value 1 need to be set to bit field 1, so the
+ default value of this block data shuold be:2.
+
+ typedef struct {
+ UINT8 Bit1 : 1; //
+ UINT8 Bit2 : 2; // Question saved in Bit2,so originalBlock info: offset = 0; width = 1;(byte level) defaul = 1.
+ // (default value record for the bit field)
+ ......
+ }ExampleData;
+
+ After function UpdateDefaultValue,the Block info is: offset = 0; width = 1;(byte level) default = 2.
+ (default value record for the Block)
+
+ UpdateDefaultValue function update default value of bit var block based on the bit field info in the block.
+
+ @param BlockLink The Link of the block data.
+
+**/
+VOID
+UpdateDefaultValue (
+ IN LIST_ENTRY *BlockLink
+)
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ListEntry;
+ LIST_ENTRY *LinkDefault;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_DEFAULT_DATA *DefaultValueData;
+ UINTN StartBit;
+ UINTN EndBit;
+ UINT32 BitFieldDefaultValue;
+
+ for ( Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (!BlockData ->IsBitVar) {
+ continue;
+ }
+ ListEntry = &BlockData->DefaultValueEntry;
+ //
+ // Update the default value in the block data with all existing default id.
+ //
+ for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
+ //
+ // Get the default data, and the value of the default data is for some field in the block.
+ // Note: Default value for bit field question is stored as UINT32.
+ //
+ DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
+ BitFieldDefaultValue = DefaultValueData->Value.u32;
+
+ StartBit = BlockData->BitOffset % 8;
+ EndBit = StartBit + BlockData->BitWidth - 1;
+
+ //
+ // Set the bit field default value to related bit filed, then we will got the new default vaule for the block data.
+ //
+ DefaultValueData->Value.u32 = BitFieldWrite32 (0, StartBit, EndBit, BitFieldDefaultValue);
+ }
+ }
+}
+
+/**
+Merge the default value in two block datas which have overlap region.
+
+For bit fields, their related block data may have overlap region, such as:
+
+typedef struct {
+ UINT16 Bit1 : 6; // Question1 refer Bit1, Block1: offset = 0; width = 1;(byte level) default = 1
+ UINT16 Bit2 : 5; // Question2 refer Bit2, Block2: offset = 0; width = 2;(byte level) default = 5
+ // (default value record for the bit field)
+ ......
+}ExampleData;
+
+After function UpdateDefaultValue:
+Block1: offset = 0; width = 1;(byte level) default = 1
+Block2: offset = 0; width = 2;(byte level) default = 320 (5 * (2 << 6))
+(default value record for block)
+
+After function MergeBlockDefaultValue:
+Block1: offset = 0; width = 1;(byte level) default = 65
+Block2: offset = 0; width = 2;(byte level) default = 321
+(Block1 and Block2 has overlap region, merge the overlap value to Block1 and Blcok2)
+
+Block1 and Block2 have overlap byte region, but currntly the default value of Block1 only contains
+value of Bit1 (low 6 bits),the default value of Block2 only contains the value of Bit2 (middle 5 bits).
+
+This fuction merge the default value of these two blocks, and make the default value of block1
+also contain the value of lower 2 bits of the Bit2. And make the default value of Block2 also
+contain the default value of Bit1.
+
+We can get the total value of the whole block that just cover these two blocks(in this case is:
+block: offset =0; width =2;) then the value of block2 is same as block, the value of block1 is
+the first byte value of block.
+
+@param FirstBlock Point to the block date whose default value need to be merged.
+@param SecondBlock Point to the block date whose default value need to be merged.
+
+**/
+VOID
+MergeBlockDefaultValue (
+ IN OUT IFR_BLOCK_DATA *FirstBlock,
+ IN OUT IFR_BLOCK_DATA *SecondBlock
+)
+{
+ LIST_ENTRY *FirstListEntry;
+ LIST_ENTRY *SecondListEntry;
+ LIST_ENTRY *FirstDefaultLink;
+ LIST_ENTRY *SecondDefaultLink;
+ IFR_DEFAULT_DATA *FirstDefaultValueData;
+ IFR_DEFAULT_DATA *SecondDefaultValueData;
+ UINT32 *FirstDefaultValue;
+ UINT32 *SecondDefaultValue;
+ UINT64 TotalValue;
+ UINT64 ShiftedValue;
+ UINT16 OffsetShift;
+
+ FirstListEntry = &FirstBlock->DefaultValueEntry;
+ for (FirstDefaultLink = FirstListEntry->ForwardLink; FirstDefaultLink != FirstListEntry; FirstDefaultLink = FirstDefaultLink->ForwardLink) {
+ FirstDefaultValueData = BASE_CR (FirstDefaultLink, IFR_DEFAULT_DATA, Entry);
+ SecondListEntry = &SecondBlock->DefaultValueEntry;
+ for (SecondDefaultLink = SecondListEntry->ForwardLink; SecondDefaultLink != SecondListEntry; SecondDefaultLink = SecondDefaultLink->ForwardLink) {
+ SecondDefaultValueData = BASE_CR (SecondDefaultLink, IFR_DEFAULT_DATA, Entry);
+ if (FirstDefaultValueData->DefaultId != SecondDefaultValueData->DefaultId) {
+ continue;
+ }
+ //
+ // Find default value with same default id in the two blocks.
+ // Note: Default value for bit field question is stored as UINT32 type.
+ //
+ FirstDefaultValue = &FirstDefaultValueData->Value.u32;
+ SecondDefaultValue = &SecondDefaultValueData->Value.u32;
+ //
+ // 1. Get the default value of the whole blcok that can just cover FirstBlock and SecondBlock.
+ // 2. Get the default value of FirstBlock and SecondBlock form the value of whole block based
+ // on the offset and width of FirstBlock and SecondBlock.
+ //
+ if (FirstBlock->Offset > SecondBlock->Offset) {
+ OffsetShift = FirstBlock->Offset - SecondBlock->Offset;
+ ShiftedValue = LShiftU64 ((UINT64) (*FirstDefaultValue), OffsetShift * 8);
+ TotalValue = ShiftedValue | (UINT64) (*SecondDefaultValue);
+ *SecondDefaultValue = (UINT32) BitFieldRead64 (TotalValue, 0, SecondBlock->Width * 8 -1);
+ *FirstDefaultValue = (UINT32) BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + FirstBlock->Width *8 -1);
+ } else {
+ OffsetShift = SecondBlock->Offset -FirstBlock->Offset;
+ ShiftedValue = LShiftU64 ((UINT64) (*SecondDefaultValue), OffsetShift * 8);
+ TotalValue = ShiftedValue | (UINT64) (*FirstDefaultValue);
+ *FirstDefaultValue = (UINT32) BitFieldRead64 (TotalValue, 0, FirstBlock->Width * 8 -1);
+ *SecondDefaultValue = (UINT32) BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + SecondBlock->Width *8 -1);
+ }
+ }
+ }
+}
+
+/**
+
+Update the default value in the block data which used as Bit VarStore
+
+@param BlockLink The Link of the block data.
+
+**/
+VOID
+UpdateBlockDataArray (
+ IN LIST_ENTRY *BlockLink
+)
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *TempLink;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_BLOCK_DATA *NextBlockData;
+
+ //
+ // 1. Update default value in BitVar block data.
+ // Sine some block datas are used as BitVarStore, then the default value recored in the block
+ // is for related bit field in the block. so we need to set the default value to the related bit
+ // fields in the block data if the block data is used as bit varstore, then the default value of
+ // the block will be updated.
+ //
+ UpdateDefaultValue (BlockLink);
+
+ //
+ // 2.Update default value for overlap BitVar blcok datas.
+ // For block datas have overlap region, we need to merge the default value in different blocks.
+ //
+ for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (!BlockData ->IsBitVar) {
+ continue;
+ }
+ for (TempLink = Link->ForwardLink; TempLink != BlockLink; TempLink = TempLink->ForwardLink) {
+ NextBlockData = BASE_CR (TempLink, IFR_BLOCK_DATA, Entry);
+ if (!NextBlockData->IsBitVar || NextBlockData->Offset >= BlockData->Offset + BlockData->Width || BlockData->Offset >= NextBlockData->Offset + NextBlockData->Width) {
+ continue;
+ }
+ //
+ // Find two blocks are used as bit VarStore and have overlap region, so need to merge default value of these two blocks.
+ //
+ MergeBlockDefaultValue (BlockData, NextBlockData);
+ }
+ }
+}
+
+/**
+ Generate ConfigAltResp string base on the varstore info.
+
+ @param HiiHandle Hii Handle for this hii package.
+ @param ConfigHdr The config header for this varstore.
+ @param VarStorageData The varstore info.
+ @param DefaultIdArray The Default id array.
+ @param DefaultAltCfgResp The DefaultAltCfgResp info may be return.
+
+ @retval TRUE Need to continue
+ @retval Others NO need to continue or error occur.
+**/
+EFI_STATUS
+GenerateAltConfigResp (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN CHAR16 *ConfigHdr,
+ IN IFR_VARSTORAGE_DATA *VarStorageData,
+ IN IFR_DEFAULT_DATA *DefaultIdArray,
+ IN OUT EFI_STRING *DefaultAltCfgResp
+ )
+{
+ BOOLEAN DataExist;
+ UINTN Length;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *LinkData;
+ LIST_ENTRY *LinkDefault;
+ LIST_ENTRY *ListEntry;
+ CHAR16 *StringPtr;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_DEFAULT_DATA *DefaultId;
+ IFR_DEFAULT_DATA *DefaultValueData;
+ UINTN Width;
+ UINT8 *TmpBuffer;
+ CHAR16 *DefaultString;
+ UINTN StrSize;
+
+ BlockData = NULL;
+ DataExist = FALSE;
+ DefaultString = NULL;
+ //
+ // Add length for <ConfigHdr> + '\0'
+ //
+ Length = StrLen (ConfigHdr) + 1;
+
+ UpdateBlockDataArray (&VarStorageData->BlockEntry);
+
+ for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
+ DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
+ //
+ // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
+ // |1| StrLen (ConfigHdr) | 8 | 4 |
+ //
+ Length += (1 + StrLen (ConfigHdr) + 8 + 4);
+
+ for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
+ BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
+ ListEntry = &BlockData->DefaultValueEntry;
+ for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
+ DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
+ if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
+ continue;
+ }
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Add length for "&Name1=zzzzzzzzzzzz"
+ // |1|Name|1|Value|
+ //
+ Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2);
+ } else {
+ //
+ // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
+ // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
+ //
+ Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
+ }
+ DataExist = TRUE;
+ }
+ }
+ }
+
+ //
+ // No default value is found. The default string doesn't exist.
+ //
+ if (!DataExist) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Allocate buffer for the entire <DefaultAltCfgResp>
+ //
+ *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (*DefaultAltCfgResp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StringPtr = *DefaultAltCfgResp;
+
+ //
+ // Start with <ConfigHdr>
+ //
+ StrCpyS (StringPtr, Length, ConfigHdr);
+ StringPtr += StrLen (StringPtr);
+
+ for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
+ DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
+ //
+ // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
+ // |1| StrLen (ConfigHdr) | 8 | 4 |
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
+ L"&%s&ALTCFG=%04X",
+ ConfigHdr,
+ DefaultId->DefaultId
+ );
+ StringPtr += StrLen (StringPtr);
+
+ for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
+ BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
+ ListEntry = &BlockData->DefaultValueEntry;
+ for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
+ DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
+ if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
+ continue;
+ }
+ if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ UnicodeSPrint (
+ StringPtr,
+ (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16),
+ L"&%s=",
+ BlockData->Name
+ );
+ StringPtr += StrLen (StringPtr);
+ } else {
+ //
+ // Add <BlockConfig>
+ // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+ //
+ UnicodeSPrint (
+ StringPtr,
+ (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
+ L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
+ BlockData->Offset,
+ BlockData->Width
+ );
+ StringPtr += StrLen (StringPtr);
+ }
+ Width = BlockData->Width;
+ //
+ // Convert Value to a hex string in "%x" format
+ // NOTE: This is in the opposite byte that GUID and PATH use
+ //
+ if (BlockData->OpCode == EFI_IFR_STRING_OP){
+ DefaultString = InternalGetString(HiiHandle, DefaultValueData->Value.string);
+ TmpBuffer = AllocateZeroPool (Width);
+ ASSERT (TmpBuffer != NULL);
+ if (DefaultString != NULL) {
+ StrSize = StrLen(DefaultString)* sizeof (CHAR16);
+ if (StrSize > Width) {
+ StrSize = Width;
+ }
+ CopyMem (TmpBuffer, (UINT8 *) DefaultString, StrSize);
+ }
+ } else {
+ TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
+ }
+ for (; Width > 0 && (TmpBuffer != NULL); Width--) {
+ UnicodeValueToStringS (
+ StringPtr,
+ Length * sizeof (CHAR16) - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp),
+ PREFIX_ZERO | RADIX_HEX,
+ TmpBuffer[Width - 1],
+ 2
+ );
+ StringPtr += StrnLenS (StringPtr, Length - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp) / sizeof (CHAR16));
+ }
+ if (DefaultString != NULL){
+ FreePool(DefaultString);
+ DefaultString = NULL;
+ }
+ if (BlockData->OpCode == EFI_IFR_STRING_OP && TmpBuffer != NULL) {
+ FreePool(TmpBuffer);
+ TmpBuffer = NULL;
+ }
+ }
+ }
+ }
+
+ HiiToLower (*DefaultAltCfgResp);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function gets the full request string and full default value string by
+ parsing IFR data in HII form packages.
+
+ When Request points to NULL string, the request string and default value string
+ for each varstore in form package will return.
+
+ @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
+ @param DevicePath Device Path which Hii Config Access Protocol is registered.
+ @param Request Pointer to a null-terminated Unicode string in
+ <ConfigRequest> format. When it doesn't contain
+ any RequestElement, it will be updated to return
+ the full RequestElement retrieved from IFR data.
+ If it points to NULL, the request string for the first
+ varstore in form package will be merged into a
+ <MultiConfigRequest> format string and return.
+ @param AltCfgResp Pointer to a null-terminated Unicode string in
+ <ConfigAltResp> format. When the pointer is to NULL,
+ the full default value string retrieved from IFR data
+ will return. When the pinter is to a string, the
+ full default value string retrieved from IFR data
+ will be merged into the input string and return.
+ When Request points to NULL, the default value string
+ for each varstore in form package will be merged into
+ a <MultiConfigAltResp> format string and return.
+ @param PointerProgress Optional parameter, it can be NULL.
+ When it is not NULL, if Request is NULL, it returns NULL.
+ 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.
+ @retval EFI_SUCCESS The Results string is set to the full request string.
+ And AltCfgResp contains all default value string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
+ @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
+ can't be found in Form package.
+ @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
+ @retval EFI_INVALID_PARAMETER Request points to NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFullStringFromHiiFormPackages (
+ IN HII_DATABASE_RECORD *DataBaseRecord,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN OUT EFI_STRING *Request,
+ IN OUT EFI_STRING *AltCfgResp,
+ OUT EFI_STRING *PointerProgress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *HiiFormPackage;
+ UINTN PackageSize;
+ IFR_BLOCK_DATA *RequestBlockArray;
+ IFR_BLOCK_DATA *BlockData;
+ IFR_DEFAULT_DATA *DefaultValueData;
+ IFR_DEFAULT_DATA *DefaultId;
+ IFR_DEFAULT_DATA *DefaultIdArray;
+ IFR_VARSTORAGE_DATA *VarStorageData;
+ EFI_STRING DefaultAltCfgResp;
+ EFI_STRING ConfigHdr;
+ EFI_STRING StringPtr;
+ EFI_STRING Progress;
+
+ if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the local variables.
+ //
+ RequestBlockArray = NULL;
+ DefaultIdArray = NULL;
+ VarStorageData = NULL;
+ DefaultAltCfgResp = NULL;
+ ConfigHdr = NULL;
+ HiiFormPackage = NULL;
+ PackageSize = 0;
+ Progress = *Request;
+
+ Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 1. Get the request block array by Request String when Request string contains the block array.
+ //
+ StringPtr = NULL;
+ if (*Request != NULL) {
+ StringPtr = *Request;
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"GUID=");
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&NAME=");
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&PATH=");
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr ++;
+ }
+
+ if (*StringPtr == L'\0') {
+ //
+ // No request block is found.
+ //
+ StringPtr = NULL;
+ }
+ }
+
+ //
+ // If StringPtr != NULL, get the request elements.
+ //
+ if (StringPtr != NULL) {
+ if (StrStr (StringPtr, L"&OFFSET=") != NULL) {
+ RequestBlockArray = GetBlockElement(StringPtr, &Progress);
+ } else {
+ RequestBlockArray = GetNameElement(StringPtr, &Progress);
+ }
+
+ if (RequestBlockArray == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
+ //
+ DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
+ if (DefaultIdArray == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ InitializeListHead (&DefaultIdArray->Entry);
+
+ //
+ // Initialize VarStorageData to store the var store Block and Default value information.
+ //
+ VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
+ if (VarStorageData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ InitializeListHead (&VarStorageData->Entry);
+ InitializeListHead (&VarStorageData->BlockEntry);
+
+ //
+ // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
+ //
+
+ //
+ // Parse the opcode in form package to get the default setting.
+ //
+ Status = ParseIfrData (DataBaseRecord->Handle,
+ HiiFormPackage,
+ (UINT32) PackageSize,
+ *Request,
+ RequestBlockArray,
+ VarStorageData,
+ DefaultIdArray);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // No requested varstore in IFR data and directly return
+ //
+ if (VarStorageData->Type == 0 && VarStorageData->Name == NULL) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
+ //
+ Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RequestBlockArray == NULL) {
+ if (!GenerateConfigRequest(ConfigHdr, VarStorageData, &Status, Request)) {
+ goto Done;
+ }
+ }
+
+ //
+ // 4. Construct Default Value string in AltResp according to request element.
+ // Go through all VarStorageData Entry and get the DefaultId array for each one
+ // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
+ //
+ Status = GenerateAltConfigResp (DataBaseRecord->Handle,ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 5. Merge string into the input AltCfgResp if the input *AltCfgResp is not NULL.
+ //
+ if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
+ Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
+ FreePool (DefaultAltCfgResp);
+ } else if (*AltCfgResp == NULL) {
+ *AltCfgResp = DefaultAltCfgResp;
+ }
+
+Done:
+ if (RequestBlockArray != NULL) {
+ //
+ // Free Link Array RequestBlockArray
+ //
+ while (!IsListEmpty (&RequestBlockArray->Entry)) {
+ BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ FreePool (BlockData);
+ }
+
+ FreePool (RequestBlockArray);
+ }
+
+ if (VarStorageData != NULL) {
+ //
+ // Free link array VarStorageData
+ //
+ while (!IsListEmpty (&VarStorageData->BlockEntry)) {
+ BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ if (BlockData->Name != NULL) {
+ FreePool (BlockData->Name);
+ }
+ //
+ // Free default value link array
+ //
+ while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
+ DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
+ RemoveEntryList (&DefaultValueData->Entry);
+ FreePool (DefaultValueData);
+ }
+ FreePool (BlockData);
+ }
+ if (VarStorageData ->Name != NULL) {
+ FreePool (VarStorageData ->Name);
+ VarStorageData ->Name = NULL;
+ }
+ FreePool (VarStorageData);
+ }
+
+ if (DefaultIdArray != NULL) {
+ //
+ // Free DefaultId Array
+ //
+ while (!IsListEmpty (&DefaultIdArray->Entry)) {
+ DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
+ RemoveEntryList (&DefaultId->Entry);
+ FreePool (DefaultId);
+ }
+ FreePool (DefaultIdArray);
+ }
+
+ //
+ // Free the allocated string
+ //
+ if (ConfigHdr != NULL) {
+ FreePool (ConfigHdr);
+ }
+
+ //
+ // Free Package data
+ //
+ if (HiiFormPackage != NULL) {
+ FreePool (HiiFormPackage);
+ }
+
+ if (PointerProgress != NULL) {
+ if (*Request == NULL) {
+ *PointerProgress = NULL;
+ } else if (EFI_ERROR (Status)) {
+ *PointerProgress = *Request;
+ } else {
+ *PointerProgress = *Request + StrLen (*Request);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function gets the full request resp string by
+ parsing IFR data in HII form packages.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param EfiVarStoreInfo The efi varstore info which is save in the EFI
+ varstore data structure.
+ @param Request Pointer to a null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param RequestResp Pointer to a null-terminated Unicode string in
+ <ConfigResp> format.
+ @param AccessProgress 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.
+
+ @retval EFI_SUCCESS The Results string is set to the full request string.
+ And AltCfgResp contains all default value string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
+ @retval EFI_INVALID_PARAMETER Request points to NULL.
+
+**/
+EFI_STATUS
+GetConfigRespFromEfiVarStore (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
+ IN EFI_STRING Request,
+ OUT EFI_STRING *RequestResp,
+ OUT EFI_STRING *AccessProgress
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING VarStoreName;
+ UINTN NameSize;
+ UINT8 *VarStore;
+ UINTN BufferSize;
+
+ Status = EFI_SUCCESS;
+ BufferSize = 0;
+ VarStore = NULL;
+ VarStoreName = NULL;
+ *AccessProgress = Request;
+
+ NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName, NameSize);
+
+
+ Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Done;
+ }
+
+ VarStore = AllocateZeroPool (BufferSize);
+ ASSERT (VarStore != NULL);
+ Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = HiiBlockToConfig(This, Request, VarStore, BufferSize, RequestResp, AccessProgress);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ if (VarStoreName != NULL) {
+ FreePool (VarStoreName);
+ }
+
+ if (VarStore != NULL) {
+ FreePool (VarStore);
+ }
+
+ return Status;
+}
+
+
+/**
+ This function route the full request resp string for efi varstore.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param EfiVarStoreInfo The efi varstore info which is save in the EFI
+ varstore data structure.
+ @param RequestResp Pointer to a null-terminated Unicode string in
+ <ConfigResp> format.
+ @param Result Pointer to a null-terminated Unicode string in
+ <ConfigResp> format.
+
+ @retval EFI_SUCCESS The Results string is set to the full request string.
+ And AltCfgResp contains all default value string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
+ @retval EFI_INVALID_PARAMETER Request points to NULL.
+
+**/
+EFI_STATUS
+RouteConfigRespForEfiVarStore (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
+ IN EFI_STRING RequestResp,
+ OUT EFI_STRING *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING VarStoreName;
+ UINTN NameSize;
+ UINT8 *VarStore;
+ UINTN BufferSize;
+ UINTN BlockSize;
+
+ Status = EFI_SUCCESS;
+ BufferSize = 0;
+ VarStore = NULL;
+ VarStoreName = NULL;
+ *Result = RequestResp;
+
+ NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
+ VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
+ if (VarStoreName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName, NameSize);
+
+ Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((DEBUG_ERROR, "The variable does not exist!"));
+ goto Done;
+ }
+
+ BlockSize = BufferSize;
+ VarStore = AllocateZeroPool (BufferSize);
+ ASSERT (VarStore != NULL);
+ Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = HiiConfigToBlock(This, RequestResp, VarStore, &BlockSize, Result);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore);
+ if (EFI_ERROR (Status)) {
+ *Result = RequestResp;
+ goto Done;
+ }
+
+Done:
+ if (VarStoreName != NULL) {
+ FreePool (VarStoreName);
+ }
+
+ if (VarStore != NULL) {
+ FreePool (VarStore);
+ }
+
+ return Status;
+}
+
+/**
+ Validate the config request elements.
+
+ @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
+ without configHdr field.
+
+ @retval CHAR16 * THE first Name/value pair not correct.
+ @retval NULL Success parse the name/value pair
+**/
+CHAR16 *
+OffsetWidthValidate (
+ CHAR16 *ConfigElements
+ )
+{
+ CHAR16 *StringPtr;
+ CHAR16 *RetVal;
+
+ StringPtr = ConfigElements;
+
+ while (1) {
+ RetVal = StringPtr;
+ if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
+ return RetVal;
+ }
+
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ return RetVal;
+ }
+
+ StringPtr += StrLen (L"&WIDTH=");
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
+ StringPtr ++;
+ }
+
+ if (*StringPtr == L'\0') {
+ return NULL;
+ }
+ }
+}
+
+/**
+ Validate the config request elements.
+
+ @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
+ without configHdr field.
+
+ @retval CHAR16 * THE first Name/value pair not correct.
+ @retval NULL Success parse the name/value pair
+
+**/
+CHAR16 *
+NameValueValidate (
+ CHAR16 *ConfigElements
+ )
+{
+ CHAR16 *StringPtr;
+ CHAR16 *RetVal;
+
+ StringPtr = ConfigElements;
+
+ while (1) {
+ RetVal = StringPtr;
+ if (*StringPtr != L'&') {
+ return RetVal;
+ }
+ StringPtr += 1;
+
+ StringPtr = StrStr (StringPtr, L"&");
+
+ if (StringPtr == NULL) {
+ return NULL;
+ }
+ }
+}
+
+/**
+ Validate the config request string.
+
+ @param ConfigRequest A null-terminated Unicode string in <ConfigRequest> format.
+
+ @retval CHAR16 * THE first element not correct.
+ @retval NULL Success parse the name/value pair
+
+**/
+CHAR16 *
+ConfigRequestValidate (
+ CHAR16 *ConfigRequest
+ )
+{
+ BOOLEAN HasNameField;
+ CHAR16 *StringPtr;
+
+ HasNameField = TRUE;
+ StringPtr = ConfigRequest;
+
+ //
+ // Check <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return ConfigRequest;
+ }
+ StringPtr += StrLen (L"GUID=");
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ return ConfigRequest;
+ }
+ StringPtr += StrLen (L"&NAME=");
+ if (*StringPtr == L'&') {
+ HasNameField = FALSE;
+ }
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ return ConfigRequest;
+ }
+ StringPtr += StrLen (L"&PATH=");
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr ++;
+ }
+
+ if (*StringPtr == L'\0') {
+ return NULL;
+ }
+
+ if (HasNameField) {
+ //
+ // Should be Buffer varstore, config request should be "OFFSET/Width" pairs.
+ //
+ return OffsetWidthValidate(StringPtr);
+ } else {
+ //
+ // Should be Name/Value varstore, config request should be "&name1&name2..." pairs.
+ //
+ return NameValueValidate(StringPtr);
+ }
+}
+
+/**
+ This function allows a caller to extract the current configuration
+ for one or more named elements from one or more drivers.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> 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 Null-terminated Unicode string in
+ <MultiConfigAltResp> 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 string is filled with the values
+ corresponding to all requested names.
+ @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_NOT_FOUND Routing data doesn't match any known driver.
+ Progress set to the "G" in "GUID" of the routing
+ header that doesn't match. Note: There is no
+ requirement that all routing data be validated
+ before any configuration extraction.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
+ parameter would result in this type of error. The
+ Progress parameter is set to NULL.
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
+ before the error or the beginning of the string.
+ @retval EFI_INVALID_PARAMETER The ExtractConfig function of the underlying HII
+ Configuration Access Protocol returned
+ EFI_INVALID_PARAMETER. Progress set to most recent
+ & before the error or the beginning of the string.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExtractConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigRequest;
+ UINTN Length;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *DevicePathPkg;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_STRING AccessResults;
+ EFI_STRING AccessProgressBackup;
+ EFI_STRING AccessResultsBackup;
+ EFI_STRING DefaultResults;
+ BOOLEAN FirstElement;
+ BOOLEAN IfrDataParsedFlag;
+ BOOLEAN IsEfiVarStore;
+ EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
+ EFI_STRING ErrorPtr;
+ UINTN DevicePathSize;
+ UINTN ConigStringSize;
+ UINTN ConigStringSizeNewsize;
+ EFI_STRING ConfigStringPtr;
+
+ if (This == NULL || Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Request == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Request;
+ *Progress = StringPtr;
+ DefaultResults = NULL;
+ ConfigRequest = NULL;
+ Status = EFI_SUCCESS;
+ AccessResults = NULL;
+ AccessProgress = NULL;
+ AccessResultsBackup = NULL;
+ AccessProgressBackup = NULL;
+ DevicePath = NULL;
+ IfrDataParsedFlag = FALSE;
+ IsEfiVarStore = FALSE;
+ EfiVarStoreInfo = NULL;
+
+ //
+ // The first element of <MultiConfigRequest> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FirstElement = TRUE;
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Request) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigRequest> of <MultiConfigRequest>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigRequest == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ *(ConfigRequest + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ HiiHandle = NULL;
+ Database = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
+ CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
+ if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigRequest)) {
+ DriverHandle = Database->DriverHandle;
+ HiiHandle = Database->Handle;
+ break;
+ }
+ }
+ }
+
+ //
+ // Try to find driver handle by device path.
+ //
+ if (DriverHandle == NULL) {
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempDevicePath,
+ &DriverHandle
+ );
+ if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ *Progress = StringPtr;
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ //
+ // Validate ConfigRequest String.
+ //
+ ErrorPtr = ConfigRequestValidate(ConfigRequest);
+ if (ErrorPtr != NULL) {
+ *Progress = StrStr (StringPtr, ErrorPtr);
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Check whether ConfigRequest contains request string.
+ //
+ IfrDataParsedFlag = FALSE;
+ if ((HiiHandle != NULL) && !GetElementsFromRequest(ConfigRequest)) {
+ //
+ // Get the full request string from IFR when HiiPackage is registered to HiiHandle
+ //
+ IfrDataParsedFlag = TRUE;
+ Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigRequest>.
+ // Map it to the progress on <MultiConfigRequest> then return it.
+ //
+ ASSERT (AccessProgress != NULL);
+ *Progress = StrStr (StringPtr, AccessProgress);
+ goto Done;
+ }
+ //
+ // Not any request block is found.
+ //
+ if (!GetElementsFromRequest(ConfigRequest)) {
+ AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
+ goto NextConfigString;
+ }
+ }
+
+ //
+ // Check whether this ConfigRequest is search from Efi varstore type storage.
+ //
+ Status = GetVarStoreType(Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (IsEfiVarStore) {
+ //
+ // Call the GetVariable function to extract settings.
+ //
+ Status = GetConfigRespFromEfiVarStore(This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress);
+ FreePool (EfiVarStoreInfo);
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigRequest>.
+ // Map it to the progress on <MultiConfigRequest> then return it.
+ //
+ *Progress = StrStr (StringPtr, AccessProgress);
+ goto Done;
+ }
+
+ //
+ // For EfiVarstore, call corresponding ConfigAccess protocol to get the AltCfgResp from driver.
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The driver has EfiVarStore, may not install ConfigAccess protocol.
+ // So ignore the error status in this case.
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgressBackup,
+ &AccessResultsBackup
+ );
+ if (!EFI_ERROR(Status)) {
+ //
+ //Merge the AltCfgResp in AccessResultsBackup to AccessResults
+ //
+ if ((AccessResultsBackup != NULL) && (StrStr (AccessResultsBackup, L"&ALTCFG=") != NULL)) {
+ ConigStringSize = StrSize (AccessResults);
+ ConfigStringPtr = StrStr (AccessResultsBackup, L"&GUID=");
+ ConigStringSizeNewsize = StrSize (ConfigStringPtr) + ConigStringSize + sizeof (CHAR16);
+ AccessResults = (EFI_STRING) ReallocatePool (
+ ConigStringSize,
+ ConigStringSizeNewsize,
+ AccessResults);
+ StrCatS (AccessResults, ConigStringSizeNewsize / sizeof (CHAR16), ConfigStringPtr);
+ }
+ } else {
+ //
+ // In the ExtractConfig function of some driver may not support EfiVarStore,
+ // may return error status, just ignore the error status in this case.
+ //
+ Status = EFI_SUCCESS;
+ }
+ if (AccessResultsBackup != NULL) {
+ FreePool (AccessResultsBackup);
+ AccessResultsBackup = NULL;
+ }
+ }
+ } else {
+ //
+ // Call corresponding ConfigAccess protocol to extract settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgress,
+ &AccessResults
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigRequest>.
+ // Map it to the progress on <MultiConfigRequest> then return it.
+ //
+ *Progress = StrStr (StringPtr, AccessProgress);
+ goto Done;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
+ // which separates the first <ConfigAltResp> and the following ones.
+ //
+ ASSERT (*AccessProgress == 0);
+
+ //
+ // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
+ //
+ if (!IfrDataParsedFlag && HiiHandle != NULL) {
+ Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ FreePool (DevicePath);
+ DevicePath = NULL;
+
+ if (DefaultResults != NULL) {
+ Status = MergeDefaultString (&AccessResults, DefaultResults);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DefaultResults);
+ DefaultResults = NULL;
+ }
+
+NextConfigString:
+ if (!FirstElement) {
+ Status = AppendToMultiString (Results, L"&");
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+
+ FirstElement = FALSE;
+
+ FreePool (AccessResults);
+ AccessResults = NULL;
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+
+ //
+ // Go to next <ConfigRequest> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ FreePool (*Results);
+ *Results = NULL;
+ }
+
+ if (ConfigRequest != NULL) {
+ FreePool (ConfigRequest);
+ }
+
+ if (AccessResults != NULL) {
+ FreePool (AccessResults);
+ }
+
+ if (DefaultResults != NULL) {
+ FreePool (DefaultResults);
+ }
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+
+ return Status;
+}
+
+
+/**
+ This function allows the caller to request the current configuration for the
+ entirety of the current HII database and returns the data in a
+ null-terminated Unicode string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the entirety of the current HII
+ database. String to be allocated by the called
+ function. De-allocation is up to the caller.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @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_PARAMETER For example, passing in a NULL for the Results
+ parameter would result in this type of error.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExportConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessResults;
+ EFI_STRING Progress;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigRequest;
+ UINTN Index;
+ EFI_HANDLE *ConfigAccessHandles;
+ UINTN NumberConfigAccessHandles;
+ BOOLEAN FirstElement;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_STRING DefaultResults;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *DevicePathPkg;
+ UINT8 *CurrentDevicePath;
+ BOOLEAN IfrDataParsedFlag;
+
+ if (This == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberConfigAccessHandles = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiHiiConfigAccessProtocolGuid,
+ NULL,
+ &NumberConfigAccessHandles,
+ &ConfigAccessHandles
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FirstElement = TRUE;
+
+ for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ ConfigAccessHandles[Index],
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get DevicePath and HiiHandle for this ConfigAccess driver handle
+ //
+ IfrDataParsedFlag = FALSE;
+ Progress = NULL;
+ HiiHandle = NULL;
+ DefaultResults = NULL;
+ Database = NULL;
+ ConfigRequest = NULL;
+ DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
+ if (DevicePath != NULL) {
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
+ CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ if (CompareMem (
+ DevicePath,
+ CurrentDevicePath,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
+ ) == 0) {
+ HiiHandle = Database->Handle;
+ break;
+ }
+ }
+ }
+ }
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ NULL,
+ &Progress,
+ &AccessResults
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
+ //
+ if (HiiHandle != NULL && DevicePath != NULL) {
+ IfrDataParsedFlag = TRUE;
+ Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
+ //
+ // Get the full request string to get the Current setting again.
+ //
+ if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &Progress,
+ &AccessResults
+ );
+ FreePool (ConfigRequest);
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
+ //
+ if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
+ StringPtr = StrStr (AccessResults, L"&GUID=");
+ if (StringPtr != NULL) {
+ *StringPtr = 0;
+ }
+ if (GetElementsFromRequest (AccessResults)) {
+ Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (StringPtr != NULL) {
+ *StringPtr = L'&';
+ }
+ }
+ //
+ // Merge the default sting from IFR code into the got setting from driver.
+ //
+ if (DefaultResults != NULL) {
+ Status = MergeDefaultString (&AccessResults, DefaultResults);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DefaultResults);
+ DefaultResults = NULL;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
+ // which separates the first <ConfigAltResp> and the following ones.
+ //
+ if (!FirstElement) {
+ Status = AppendToMultiString (Results, L"&");
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+
+ FirstElement = FALSE;
+
+ FreePool (AccessResults);
+ AccessResults = NULL;
+ }
+ }
+ FreePool (ConfigAccessHandles);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function processes the results of processing forms and routes it to the
+ appropriate handlers or storage.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MulltiConfigResp> 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 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_PARAMETER Passing in a NULL for the Configuration parameter
+ would result in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingRouteConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigResp;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *DevicePathPkg;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
+ BOOLEAN IsEfiVarstore;
+ UINTN DevicePathSize;
+
+ if (This == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Configuration == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Configuration;
+ *Progress = StringPtr;
+ Database = NULL;
+ AccessProgress = NULL;
+ EfiVarStoreInfo= NULL;
+ IsEfiVarstore = FALSE;
+
+ //
+ // The first element of <MultiConfigResp> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigResp>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Configuration) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigResp> of <MultiConfigResp>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigResp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Append '\0' to the end of ConfigRequest
+ //
+ *(ConfigResp + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ FreePool (ConfigResp);
+ return Status;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+
+ if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
+ CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
+ if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigResp)) {
+ DriverHandle = Database->DriverHandle;
+ break;
+ }
+ }
+ }
+
+ //
+ // Try to find driver handle by device path.
+ //
+ if (DriverHandle == NULL) {
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempDevicePath,
+ &DriverHandle
+ );
+ if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ FreePool (DevicePath);
+ *Progress = StringPtr;
+ FreePool (ConfigResp);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ FreePool (DevicePath);
+
+ //
+ // Check whether this ConfigRequest is search from Efi varstore type storage.
+ //
+ Status = GetVarStoreType(Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsEfiVarstore) {
+ //
+ // Call the SetVariable function to route settings.
+ //
+ Status = RouteConfigRespForEfiVarStore(This, EfiVarStoreInfo, ConfigResp, &AccessProgress);
+ FreePool (EfiVarStoreInfo);
+ } else {
+ //
+ // Call corresponding ConfigAccess protocol to route settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ *Progress = StringPtr;
+ FreePool (ConfigResp);
+ return EFI_NOT_FOUND;
+ }
+
+ Status = ConfigAccess->RouteConfig (
+ ConfigAccess,
+ ConfigResp,
+ &AccessProgress
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ ASSERT (AccessProgress != NULL);
+ //
+ // AccessProgress indicates the parsing progress on <ConfigResp>.
+ // Map it to the progress on <MultiConfigResp> then return it.
+ //
+ *Progress = StrStr (StringPtr, AccessProgress);
+
+ FreePool (ConfigResp);
+ return Status;
+ }
+
+ FreePool (ConfigResp);
+ ConfigResp = NULL;
+
+ //
+ // Go to next <ConfigResp> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration data
+ stored in byte array ("block") formats such as UEFI Variables into current
+ configuration strings.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigRequest A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Block Array of bytes defining the block's configuration.
+ @param BlockSize Length in bytes of Block.
+ @param Config Filled-in configuration string. String allocated
+ by the function. Returned only if call is
+ successful. It is <ConfigResp> string 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 request succeeded. Progress points to the null
+ terminator at the end of the ConfigRequest
+ string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigRequest.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigRequest.
+ @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
+ Block is left updated and Progress points at
+ the "&" preceding the first non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiBlockToConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN CONST UINTN BlockSize,
+ OUT EFI_STRING *Config,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_STRING TmpPtr;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ EFI_STRING ValueStr;
+ EFI_STRING ConfigElement;
+ UINTN Index;
+ UINT8 *TemBuffer;
+ CHAR16 *TemString;
+ CHAR16 TemChar;
+
+ TmpBuffer = NULL;
+
+ if (This == NULL || Progress == NULL || Config == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Block == NULL || ConfigRequest == NULL) {
+ *Progress = ConfigRequest;
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigRequest;
+ ValueStr = NULL;
+ Value = NULL;
+ ConfigElement = NULL;
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Config == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ while (*StringPtr != L'&' && *StringPtr != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+
+ AppendToMultiString(Config, ConfigRequest);
+ HiiToLower (*Config);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Skip '&'
+ //
+ StringPtr++;
+
+ //
+ // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
+ //
+ TemChar = *StringPtr;
+ *StringPtr = '\0';
+ AppendToMultiString(Config, ConfigRequest);
+ *StringPtr = TemChar;
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ //
+ // Back up the header of one <BlockName>
+ //
+ TmpPtr = StringPtr;
+
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ *Progress = TmpPtr - 1;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = TmpPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ *Progress = TmpPtr - 1;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = TmpPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Calculate Value and convert it to hex string.
+ //
+ if (Offset + Width > BlockSize) {
+ *Progress = StringPtr;
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Value = (UINT8 *) AllocateZeroPool (Width);
+ if (Value == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (Value, (UINT8 *) Block + Offset, Width);
+
+ Length = Width * 2 + 1;
+ ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ValueStr == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ TemString = ValueStr;
+ TemBuffer = Value + Width - 1;
+ for (Index = 0; Index < Width; Index ++, TemBuffer --) {
+ UnicodeValueToStringS (
+ TemString,
+ Length * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ValueStr),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemBuffer,
+ 2
+ );
+ TemString += StrnLenS (TemString, Length - ((UINTN)TemString - (UINTN)ValueStr) / sizeof (CHAR16));
+ }
+
+ FreePool (Value);
+ Value = NULL;
+
+ //
+ // Build a ConfigElement
+ //
+ Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
+ ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ConfigElement == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
+ if (*StringPtr == 0) {
+ *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
+ }
+ *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
+ StrCatS (ConfigElement, Length, L"VALUE=");
+ StrCatS (ConfigElement, Length, ValueStr);
+
+ AppendToMultiString (Config, ConfigElement);
+
+ FreePool (ConfigElement);
+ FreePool (ValueStr);
+ ConfigElement = NULL;
+ ValueStr = NULL;
+
+ //
+ // If '\0', parsing is finished. Otherwise skip '&' to continue
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ AppendToMultiString (Config, L"&");
+ StringPtr++;
+
+ }
+
+ if (*StringPtr != 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ HiiToLower (*Config);
+ *Progress = StringPtr;
+ return EFI_SUCCESS;
+
+Exit:
+ if (*Config != NULL) {
+ FreePool (*Config);
+ *Config = NULL;
+ }
+ if (ValueStr != NULL) {
+ FreePool (ValueStr);
+ }
+ if (Value != NULL) {
+ FreePool (Value);
+ }
+ if (ConfigElement != NULL) {
+ FreePool (ConfigElement);
+ }
+
+ return Status;
+
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration strings
+ to configurations stored in byte array ("block") formats such as UEFI Variables.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigResp A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Block A possibly null array of bytes representing the
+ current block. Only bytes referenced in the
+ ConfigResp string in the block are modified. If
+ this parameter is null or if the *BlockSize
+ parameter is (on input) shorter than required by
+ the Configuration string, only the BlockSize
+ parameter is updated and an appropriate status
+ (see below) is returned.
+ @param BlockSize The length of the Block in units of UINT8. On
+ input, this is the size of the Block. On output,
+ if successful, contains the largest index of the
+ modified byte in the Block, or the required buffer
+ size if the Block is not large enough.
+ @param Progress On return, points to an element of the ConfigResp
+ 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 request succeeded. Progress points to the null
+ terminator at the end of the ConfigResp string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigResp.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigResp.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
+ value pair. Block is left updated and
+ Progress points at the '&' preceding the first
+ non-<BlockName>.
+ @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined.
+ BlockSize is updated with the required buffer size.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not found.
+ Progress points to the "G" in "GUID" of the errant
+ routing data.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigToBlock (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigResp,
+ IN OUT UINT8 *Block,
+ IN OUT UINTN *BlockSize,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ UINTN BufferSize;
+ UINTN MaxBlockSize;
+
+ TmpBuffer = NULL;
+
+ if (This == NULL || BlockSize == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = ConfigResp;
+ if (ConfigResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigResp;
+ BufferSize = *BlockSize;
+ Value = NULL;
+ MaxBlockSize = 0;
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ while (*StringPtr != L'&' && *StringPtr != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Parse each <ConfigElement> if exists
+ // Only '&'<BlockConfig> format is supported by this help function.
+ // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
+ TmpPtr = StringPtr;
+ StringPtr += StrLen (L"&OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ *Progress = TmpPtr;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = TmpPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ *Progress = TmpPtr;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ FreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ *Progress = TmpPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = GetValueOfNumber (StringPtr, &Value, &Length);
+ if (EFI_ERROR (Status)) {
+ *Progress = TmpPtr;
+ goto Exit;
+ }
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = TmpPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Update the Block with configuration info
+ //
+ if ((Block != NULL) && (Offset + Width <= BufferSize)) {
+ CopyMem (Block + Offset, Value, Width);
+ }
+ if (Offset + Width > MaxBlockSize) {
+ MaxBlockSize = Offset + Width;
+ }
+
+ FreePool (Value);
+ Value = NULL;
+
+ //
+ // If '\0', parsing is finished.
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ }
+
+ //
+ // The input string is not ConfigResp format, return error.
+ //
+ if (*StringPtr != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *Progress = StringPtr + StrLen (StringPtr);
+ *BlockSize = MaxBlockSize - 1;
+
+ if (MaxBlockSize > BufferSize) {
+ *BlockSize = MaxBlockSize;
+ if (Block != NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (Block == NULL) {
+ *Progress = ConfigResp;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+
+Exit:
+
+ if (Value != NULL) {
+ FreePool (Value);
+ }
+ return Status;
+}
+
+
+/**
+ This helper function is to be called by drivers to extract portions of
+ a larger configuration string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MultiConfigAltResp> format.
+ @param Guid A pointer to the GUID value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Guid is NULL,
+ then all GUID values will be searched for.
+ @param Name A pointer to the NAME value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Name is NULL,
+ then all Name values will be searched for.
+ @param DevicePath A pointer to the PATH value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If DevicePath is
+ NULL, then all DevicePath values will be searched
+ for.
+ @param AltCfgId A pointer to the ALTCFG value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If this parameter
+ is NULL, then the current setting will be
+ retrieved.
+ @param AltCfgResp A pointer to a buffer which will be allocated by
+ the function which contains the retrieved string
+ as requested. This buffer is only allocated if
+ the call was successful. It is <ConfigResp> format.
+
+ @retval EFI_SUCCESS The request succeeded. The requested data was
+ extracted and placed in the newly allocated
+ AltCfgResp buffer.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetAltCfg (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ IN CONST EFI_GUID *Guid,
+ IN CONST EFI_STRING Name,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONST UINT16 *AltCfgId,
+ OUT EFI_STRING *AltCfgResp
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING StringPtr;
+ EFI_STRING HdrStart;
+ EFI_STRING HdrEnd;
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING GuidStr;
+ EFI_STRING NameStr;
+ EFI_STRING PathStr;
+ EFI_STRING AltIdStr;
+ EFI_STRING Result;
+ BOOLEAN GuidFlag;
+ BOOLEAN NameFlag;
+ BOOLEAN PathFlag;
+
+ HdrStart = NULL;
+ HdrEnd = NULL;
+ GuidStr = NULL;
+ NameStr = NULL;
+ PathStr = NULL;
+ AltIdStr = NULL;
+ Result = NULL;
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ PathFlag = FALSE;
+
+ if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringPtr = Configuration;
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Generate the sub string for later matching.
+ //
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
+ GenerateSubStr (
+ L"PATH=",
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
+ (VOID *) DevicePath,
+ 1,
+ &PathStr
+ );
+ if (AltCfgId != NULL) {
+ GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
+ }
+ if (Name != NULL) {
+ GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
+ } else {
+ GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
+ }
+
+ while (*StringPtr != 0) {
+ //
+ // Try to match the GUID
+ //
+ if (!GuidFlag) {
+ TmpPtr = StrStr (StringPtr, GuidStr);
+ if (TmpPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ HdrStart = TmpPtr;
+
+ //
+ // Jump to <NameHdr>
+ //
+ if (Guid != NULL) {
+ StringPtr = TmpPtr + StrLen (GuidStr);
+ } else {
+ StringPtr = StrStr (TmpPtr, L"NAME=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ GuidFlag = TRUE;
+ }
+
+ //
+ // Try to match the NAME
+ //
+ if (GuidFlag && !NameFlag) {
+ if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
+ GuidFlag = FALSE;
+ } else {
+ //
+ // Jump to <PathHdr>
+ //
+ if (Name != NULL) {
+ StringPtr += StrLen (NameStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"PATH=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ NameFlag = TRUE;
+ }
+ }
+
+ //
+ // Try to match the DevicePath
+ //
+ if (GuidFlag && NameFlag && !PathFlag) {
+ if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ } else {
+ //
+ // Jump to '&' before <DescHdr> or <ConfigBody>
+ //
+ if (DevicePath != NULL) {
+ StringPtr += StrLen (PathStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"&");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ StringPtr ++;
+ }
+ PathFlag = TRUE;
+ HdrEnd = StringPtr;
+ }
+ }
+
+ //
+ // Try to match the AltCfgId
+ //
+ if (GuidFlag && NameFlag && PathFlag) {
+ if (AltCfgId == NULL) {
+ //
+ // Return Current Setting when AltCfgId is NULL.
+ //
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ //
+ // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
+ //
+ if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ PathFlag = FALSE;
+ } else {
+ //
+ // Skip AltIdStr and &
+ //
+ StringPtr = StringPtr + StrLen (AltIdStr);
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Exit:
+ *AltCfgResp = NULL;
+ if (!EFI_ERROR (Status) && (Result != NULL)) {
+ //
+ // Copy the <ConfigHdr> and <ConfigBody>
+ //
+ Length = HdrEnd - HdrStart + StrLen (Result) + 1;
+ *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (*AltCfgResp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ StrnCpyS (*AltCfgResp, Length, HdrStart, HdrEnd - HdrStart);
+ StrCatS (*AltCfgResp, Length, Result);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ if (GuidStr != NULL) {
+ FreePool (GuidStr);
+ }
+ if (NameStr != NULL) {
+ FreePool (NameStr);
+ }
+ if (PathStr != NULL) {
+ FreePool (PathStr);
+ }
+ if (AltIdStr != NULL) {
+ FreePool (AltIdStr);
+ }
+ if (Result != NULL) {
+ FreePool (Result);
+ }
+
+ return Status;
+
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c
new file mode 100644
index 000000000..174770bdb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c
@@ -0,0 +1,4632 @@
+/** @file
+Implementation for EFI_HII_DATABASE_PROTOCOL.
+
+Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+#define BASE_NUMBER 10
+
+EFI_HII_PACKAGE_LIST_HEADER *gRTDatabaseInfoBuffer = NULL;
+EFI_STRING gRTConfigRespBuffer = NULL;
+UINTN gDatabaseInfoSize = 0;
+UINTN gConfigRespSize = 0;
+BOOLEAN gExportConfigResp = FALSE;
+UINTN gNvDefaultStoreSize = 0;
+SKU_ID gSkuId = 0xFFFFFFFFFFFFFFFF;
+LIST_ENTRY gVarStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gVarStorageList);
+
+//
+// HII database lock.
+//
+EFI_LOCK mHiiDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_NOTIFY);
+
+/**
+ This function generates a HII_DATABASE_RECORD node and adds into hii database.
+ This is a internal function.
+
+ @param Private hii database private structure
+ @param DatabaseNode HII_DATABASE_RECORD node which is used to store a
+ package list
+
+ @retval EFI_SUCCESS A database record is generated successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ database contents.
+ @retval EFI_INVALID_PARAMETER Private is NULL or DatabaseRecord is NULL.
+
+**/
+EFI_STATUS
+GenerateHiiDatabaseRecord (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ OUT HII_DATABASE_RECORD **DatabaseNode
+ )
+{
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ HII_HANDLE *HiiHandle;
+
+ if (Private == NULL || DatabaseNode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DatabaseRecord = (HII_DATABASE_RECORD *) AllocateZeroPool (sizeof (HII_DATABASE_RECORD));
+ if (DatabaseRecord == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DatabaseRecord->Signature = HII_DATABASE_RECORD_SIGNATURE;
+
+ DatabaseRecord->PackageList = AllocateZeroPool (sizeof (HII_DATABASE_PACKAGE_LIST_INSTANCE));
+ if (DatabaseRecord->PackageList == NULL) {
+ FreePool (DatabaseRecord);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PackageList = DatabaseRecord->PackageList;
+
+ InitializeListHead (&PackageList->GuidPkgHdr);
+ InitializeListHead (&PackageList->FormPkgHdr);
+ InitializeListHead (&PackageList->KeyboardLayoutHdr);
+ InitializeListHead (&PackageList->StringPkgHdr);
+ InitializeListHead (&PackageList->FontPkgHdr);
+ InitializeListHead (&PackageList->SimpleFontPkgHdr);
+ PackageList->ImagePkg = NULL;
+ PackageList->DevicePathPkg = NULL;
+
+ //
+ // Create a new hii handle
+ //
+ HiiHandle = (HII_HANDLE *) AllocateZeroPool (sizeof (HII_HANDLE));
+ if (HiiHandle == NULL) {
+ FreePool (DatabaseRecord->PackageList);
+ FreePool (DatabaseRecord);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ HiiHandle->Signature = HII_HANDLE_SIGNATURE;
+ //
+ // Backup the number of Hii handles
+ //
+ Private->HiiHandleCount++;
+ HiiHandle->Key = (UINTN) Private->HiiHandleCount;
+ //
+ // Insert the handle to hii handle list of the whole database.
+ //
+ InsertTailList (&Private->HiiHandleList, &HiiHandle->Handle);
+
+ DatabaseRecord->Handle = (EFI_HII_HANDLE) HiiHandle;
+
+ //
+ // Insert the Package List node to Package List link of the whole database.
+ //
+ InsertTailList (&Private->DatabaseList, &DatabaseRecord->DatabaseEntry);
+
+ *DatabaseNode = DatabaseRecord;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function checks whether a handle is a valid EFI_HII_HANDLE
+ This is a internal function.
+
+ @param Handle Pointer to a EFI_HII_HANDLE
+
+ @retval TRUE Valid
+ @retval FALSE Invalid
+
+**/
+BOOLEAN
+IsHiiHandleValid (
+ EFI_HII_HANDLE Handle
+ )
+{
+ HII_HANDLE *HiiHandle;
+
+ HiiHandle = (HII_HANDLE *) Handle;
+
+ if (HiiHandle == NULL) {
+ return FALSE;
+ }
+
+ if (HiiHandle->Signature != HII_HANDLE_SIGNATURE) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ This function invokes the matching registered function.
+ This is a internal function.
+
+ @param Private HII Database driver private structure.
+ @param NotifyType The type of change concerning the database.
+ @param PackageInstance Points to the package referred to by the
+ notification.
+ @param PackageType Package type
+ @param Handle The handle of the package list which contains the
+ specified package.
+
+ @retval EFI_SUCCESS Already checked all registered function and
+ invoked if matched.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+InvokeRegisteredFunction (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN VOID *PackageInstance,
+ IN UINT8 PackageType,
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ HII_DATABASE_NOTIFY *Notify;
+ LIST_ENTRY *Link;
+ EFI_HII_PACKAGE_HEADER *Package;
+ UINT8 *Buffer;
+ UINT32 BufferSize;
+ UINT32 HeaderSize;
+ UINT32 ImageBlockSize;
+ UINT32 PaletteInfoSize;
+
+ if (Private == NULL || (NotifyType & 0xF) == 0 || PackageInstance == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buffer = NULL;
+ Package = NULL;
+
+ //
+ // Convert the incoming package from hii database storage format to UEFI
+ // storage format. e.g. HII_GUID_PACKAGE_INSTANCE to EFI_HII_GUID_PACKAGE_HDR.
+ //
+ switch (PackageType) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Package = (EFI_HII_PACKAGE_HEADER *) (((HII_GUID_PACKAGE_INSTANCE *) PackageInstance)->GuidPkg);
+ break;
+
+ case EFI_HII_PACKAGE_FORMS:
+ BufferSize = ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr.Length;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ &((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr,
+ sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER),
+ ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->IfrData,
+ BufferSize - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Package = (EFI_HII_PACKAGE_HEADER *) (((HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *) PackageInstance)->KeyboardPkg);
+ break;
+
+ case EFI_HII_PACKAGE_STRINGS:
+ BufferSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->Header.Length;
+ HeaderSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->HdrSize;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringBlock,
+ BufferSize - HeaderSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_FONTS:
+ BufferSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->Header.Length;
+ HeaderSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->HdrSize;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->GlyphBlock,
+ BufferSize - HeaderSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_IMAGES:
+ BufferSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr.Header.Length;
+ HeaderSize = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+
+ CopyMem (
+ Buffer,
+ &((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER),
+ &HeaderSize,
+ sizeof (UINT32)
+ );
+
+ ImageBlockSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlockSize;
+ if (ImageBlockSize != 0) {
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlock,
+ ImageBlockSize
+ );
+ }
+
+ PaletteInfoSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteInfoSize;
+ if (PaletteInfoSize != 0) {
+ CopyMem (
+ Buffer + HeaderSize + ImageBlockSize,
+ ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteBlock,
+ PaletteInfoSize
+ );
+ HeaderSize += ImageBlockSize;
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT32),
+ &HeaderSize,
+ sizeof (UINT32)
+ );
+ }
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ BufferSize = ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr->Header.Length;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr,
+ BufferSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Package = (EFI_HII_PACKAGE_HEADER *) PackageInstance;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = Private->DatabaseNotifyList.ForwardLink;
+ Link != &Private->DatabaseNotifyList;
+ Link = Link->ForwardLink
+ ) {
+ Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE);
+ if (Notify->NotifyType == NotifyType && Notify->PackageType == PackageType) {
+ //
+ // Check in case PackageGuid is not NULL when Package is GUID package
+ //
+ if (PackageType != EFI_HII_PACKAGE_TYPE_GUID) {
+ Notify->PackageGuid = NULL;
+ }
+ //
+ // Status of Registered Function is unknown so did not check it
+ //
+ Notify->PackageNotifyFn (
+ Notify->PackageType,
+ Notify->PackageGuid,
+ Package,
+ Handle,
+ NotifyType
+ );
+ }
+ }
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a GUID package to a package list node.
+ This is a internal function.
+
+ @param PackageHdr Pointer to a buffer stored with GUID package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created GUID package
+
+ @retval EFI_SUCCESS Guid Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Guid package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertGuidPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_GUID_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a GUID package node
+ //
+ GuidPackage = (HII_GUID_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_GUID_PACKAGE_INSTANCE));
+ if (GuidPackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ GuidPackage->GuidPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length);
+ if (GuidPackage->GuidPkg == NULL) {
+ FreePool (GuidPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ GuidPackage->Signature = HII_GUID_PACKAGE_SIGNATURE;
+ CopyMem (GuidPackage->GuidPkg, PackageHdr, PackageHeader.Length);
+ InsertTailList (&PackageList->GuidPkgHdr, &GuidPackage->GuidEntry);
+ *Package = GuidPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += PackageHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports GUID packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Guid Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportGuidPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ if (PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->GuidPkgHdr.ForwardLink; Link != &PackageList->GuidPkgHdr; Link = Link->ForwardLink) {
+ GuidPackage = CR (Link, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE);
+ CopyMem (&PackageHeader, GuidPackage->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageLength += PackageHeader.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) GuidPackage,
+ EFI_HII_PACKAGE_TYPE_GUID,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (Buffer, GuidPackage->GuidPkg, PackageHeader.Length);
+ Buffer = (UINT8 *) Buffer + PackageHeader.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all GUID packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed GUID packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS GUID Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveGuidPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_GUID_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ ListHead = &PackageList->GuidPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_GUID_PACKAGE_INSTANCE,
+ GuidEntry,
+ HII_GUID_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_TYPE_GUID,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->GuidEntry);
+ CopyMem (&PackageHeader, Package->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= PackageHeader.Length;
+ FreePool (Package->GuidPkg);
+ FreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the input question related to EFI variable
+
+ @param IfrQuestionHdr Point to Question header
+ @param EfiVarStoreList Point to EFI VarStore List
+ @param EfiVarStoreNumber The number of EFI VarStore
+
+ @retval Index The index of the found EFI varstore in EFI varstore list
+ EfiVarStoreNumber will return if no EFI varstore is found.
+**/
+UINTN
+IsEfiVarStoreQuestion (
+ EFI_IFR_QUESTION_HEADER *IfrQuestionHdr,
+ EFI_IFR_VARSTORE_EFI **EfiVarStoreList,
+ UINTN EfiVarStoreNumber
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < EfiVarStoreNumber; Index ++) {
+ if (IfrQuestionHdr->VarStoreId == EfiVarStoreList[Index]->VarStoreId) {
+ return Index;
+ }
+ }
+
+ return EfiVarStoreNumber;
+}
+
+/**
+ Find the matched variable from the input variable storage.
+
+ @param[in] VariableStorage Point to the variable storage header.
+ @param[in] VarGuid A unique identifier for the variable.
+ @param[in] VarAttribute The attributes bitmask for the variable.
+ @param[in] VarName A Null-terminated ascii string that is the name of the variable.
+
+ @return Pointer to the matched variable header or NULL if not found.
+**/
+VARIABLE_HEADER *
+FindVariableData (
+ IN VARIABLE_STORE_HEADER *VariableStorage,
+ IN EFI_GUID *VarGuid,
+ IN UINT32 VarAttribute,
+ IN CHAR16 *VarName
+ )
+{
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_HEADER *VariableEnd;
+
+ VariableEnd = (VARIABLE_HEADER *) ((UINT8 *) VariableStorage + VariableStorage->Size);
+ VariableHeader = (VARIABLE_HEADER *) (VariableStorage + 1);
+ VariableHeader = (VARIABLE_HEADER *) HEADER_ALIGN (VariableHeader);
+ while (VariableHeader < VariableEnd) {
+ if (CompareGuid (&VariableHeader->VendorGuid, VarGuid) &&
+ VariableHeader->Attributes == VarAttribute &&
+ StrCmp (VarName, (CHAR16 *) (VariableHeader + 1)) == 0) {
+ return VariableHeader;
+ }
+ VariableHeader = (VARIABLE_HEADER *) ((UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize);
+ VariableHeader = (VARIABLE_HEADER *) HEADER_ALIGN (VariableHeader);
+ }
+
+ return NULL;
+}
+
+/**
+ Find question default value from PcdNvStoreDefaultValueBuffer
+
+ @param DefaultId Default store ID
+ @param EfiVarStore Point to EFI VarStore header
+ @param IfrQuestionHdr Point to Question header
+ @param ValueBuffer Point to Buffer includes the found default setting
+ @param Width Width of the default value
+ @param BitFieldQuestion Whether the Question is stored in Bit field.
+
+ @retval EFI_SUCCESS Question default value is found.
+ @retval EFI_NOT_FOUND Question default value is not found.
+**/
+EFI_STATUS
+FindQuestionDefaultSetting (
+ IN UINT16 DefaultId,
+ IN EFI_IFR_VARSTORE_EFI *EfiVarStore,
+ IN EFI_IFR_QUESTION_HEADER *IfrQuestionHdr,
+ OUT VOID *ValueBuffer,
+ IN UINTN Width,
+ IN BOOLEAN BitFieldQuestion
+ )
+{
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStorage;
+ LIST_ENTRY *Link;
+ VARSTORAGE_DEFAULT_DATA *Entry;
+ VARIABLE_STORE_HEADER *NvStoreBuffer;
+ UINT8 *DataBuffer;
+ UINT8 *BufferEnd;
+ BOOLEAN IsFound;
+ UINTN Index;
+ UINT32 BufferValue;
+ UINT32 BitFieldVal;
+ UINTN BitOffset;
+ UINTN ByteOffset;
+ UINTN BitWidth;
+ UINTN StartBit;
+ UINTN EndBit;
+ PCD_DEFAULT_DATA *DataHeader;
+ PCD_DEFAULT_INFO *DefaultInfo;
+ PCD_DATA_DELTA *DeltaData;
+
+ if (gSkuId == 0xFFFFFFFFFFFFFFFF) {
+ gSkuId = LibPcdGetSku ();
+ }
+
+ //
+ // Find the DefaultId setting from the full DefaultSetting
+ //
+ VariableStorage = NULL;
+ Link = gVarStorageList.ForwardLink;
+ while (Link != &gVarStorageList) {
+ Entry = BASE_CR (Link, VARSTORAGE_DEFAULT_DATA, Entry);
+ if (Entry->DefaultId == DefaultId) {
+ VariableStorage = Entry->VariableStorage;
+ break;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ if (Link == &gVarStorageList) {
+ DataBuffer = (UINT8 *) PcdGetPtr (PcdNvStoreDefaultValueBuffer);
+ gNvDefaultStoreSize = ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)DataBuffer)->Length;
+ //
+ // The first section data includes NV storage default setting.
+ //
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER));
+ NvStoreBuffer = (VARIABLE_STORE_HEADER *) ((UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize);
+ VariableStorage = AllocatePool (NvStoreBuffer->Size);
+ ASSERT (VariableStorage != NULL);
+ CopyMem (VariableStorage, NvStoreBuffer, NvStoreBuffer->Size);
+
+ //
+ // Find the matched SkuId and DefaultId in the first section
+ //
+ IsFound = FALSE;
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == gSkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ //
+ // Find the matched SkuId and DefaultId in the remaining section
+ //
+ Index = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + ((DataHeader->DataSize + 7) & (~7));
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ while (!IsFound && Index < gNvDefaultStoreSize && DataHeader->DataSize != 0xFFFF) {
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == gSkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ if (IsFound) {
+ DeltaData = (PCD_DATA_DELTA *) BufferEnd;
+ BufferEnd = (UINT8 *) DataHeader + DataHeader->DataSize;
+ while ((UINT8 *) DeltaData < BufferEnd) {
+ *((UINT8 *) VariableStorage + DeltaData->Offset) = (UINT8) DeltaData->Value;
+ DeltaData ++;
+ }
+ break;
+ }
+ Index = (Index + DataHeader->DataSize + 7) & (~7);
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ }
+ //
+ // Cache the found result in VarStorageList
+ //
+ if (!IsFound) {
+ FreePool (VariableStorage);
+ VariableStorage = NULL;
+ }
+ Entry = AllocatePool (sizeof (VARSTORAGE_DEFAULT_DATA));
+ if (Entry != NULL) {
+ Entry->DefaultId = DefaultId;
+ Entry->VariableStorage = VariableStorage;
+ InsertTailList (&gVarStorageList, &Entry->Entry);
+ } else if (VariableStorage != NULL) {
+ FreePool (VariableStorage);
+ VariableStorage = NULL;
+ }
+ }
+ //
+ // The matched variable storage is not found.
+ //
+ if (VariableStorage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the question default value from the variable storage
+ //
+ VariableHeader = FindVariableData (VariableStorage, &EfiVarStore->Guid, EfiVarStore->Attributes, (CHAR16 *) EfiVarStore->Name);
+ if (VariableHeader == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ StartBit = 0;
+ EndBit = 0;
+ ByteOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
+ if (BitFieldQuestion) {
+ BitOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
+ ByteOffset = BitOffset / 8;
+ BitWidth = Width;
+ StartBit = BitOffset % 8;
+ EndBit = StartBit + BitWidth - 1;
+ Width = EndBit / 8 + 1;
+ }
+ if (VariableHeader->DataSize < ByteOffset + Width) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Copy the question value
+ //
+ if (ValueBuffer != NULL) {
+ if (BitFieldQuestion) {
+ CopyMem (&BufferValue, (UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + ByteOffset, Width);
+ BitFieldVal = BitFieldRead32 (BufferValue, StartBit, EndBit);
+ CopyMem (ValueBuffer, &BitFieldVal, Width);
+ } else {
+ CopyMem (ValueBuffer, (UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + IfrQuestionHdr->VarStoreInfo.VarOffset, Width);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update IFR default setting in Form Package.
+
+ @param FormPackage Form Package to be updated
+
+**/
+VOID
+UpdateDefaultSettingInFormPackage (
+ HII_IFR_PACKAGE_INSTANCE *FormPackage
+ )
+{
+ UINTN IfrOffset;
+ UINTN PackageLength;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+ UINT8 IfrQuestionType;
+ UINT8 IfrScope;
+ EFI_IFR_QUESTION_HEADER *IfrQuestionHdr;
+ EFI_IFR_VARSTORE_EFI **EfiVarStoreList;
+ UINTN EfiVarStoreMaxNum;
+ UINTN EfiVarStoreNumber;
+ UINT16 *DefaultIdList;
+ UINTN DefaultIdNumber;
+ UINTN DefaultIdMaxNum;
+ UINTN Index;
+ UINTN EfiVarStoreIndex;
+ EFI_IFR_TYPE_VALUE IfrValue;
+ EFI_IFR_TYPE_VALUE IfrManufactValue;
+ BOOLEAN StandardDefaultIsSet;
+ BOOLEAN ManufactDefaultIsSet;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_STATUS Status;
+ EFI_IFR_DEFAULT *IfrDefault;
+ UINTN Width;
+ EFI_IFR_QUESTION_HEADER VarStoreQuestionHeader;
+ BOOLEAN QuestionReferBitField;
+
+ //
+ // If no default setting, do nothing
+ //
+ if (gNvDefaultStoreSize == 0) {
+ gNvDefaultStoreSize = PcdGetSize (PcdNvStoreDefaultValueBuffer);
+ }
+ if (gNvDefaultStoreSize < sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+ return;
+ }
+
+ ZeroMem (&VarStoreQuestionHeader, sizeof (VarStoreQuestionHeader));
+ PackageLength = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
+ Width = 0;
+ IfrOffset = 0;
+ IfrScope = 0;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) FormPackage->IfrData;
+ IfrQuestionHdr = NULL;
+ IfrQuestionType = 0;
+ EfiVarStoreMaxNum = 0;
+ EfiVarStoreNumber = 0;
+ DefaultIdMaxNum = 0;
+ DefaultIdNumber = 0;
+ EfiVarStoreList = NULL;
+ DefaultIdList = NULL;
+ StandardDefaultIsSet = FALSE;
+ ManufactDefaultIsSet = FALSE;
+ QuestionReferBitField = FALSE;
+
+ while (IfrOffset < PackageLength) {
+ switch (IfrOpHdr->OpCode) {
+ case EFI_IFR_VARSTORE_EFI_OP:
+ if (EfiVarStoreNumber >= EfiVarStoreMaxNum) {
+ //
+ // Reallocate EFI VarStore Buffer
+ //
+ EfiVarStoreList = ReallocatePool (EfiVarStoreMaxNum * sizeof (UINTN), (EfiVarStoreMaxNum + BASE_NUMBER) * sizeof (UINTN), EfiVarStoreList);
+ if (EfiVarStoreList == NULL) {
+ goto Done;
+ }
+ EfiVarStoreMaxNum = EfiVarStoreMaxNum + BASE_NUMBER;
+ }
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+ //
+ // Convert VarStore Name from ASCII string to Unicode string.
+ //
+ EfiVarStoreList [EfiVarStoreNumber] = AllocatePool (IfrEfiVarStore->Header.Length + AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name));
+ if (EfiVarStoreList [EfiVarStoreNumber] == NULL) {
+ break;
+ }
+ CopyMem (EfiVarStoreList [EfiVarStoreNumber], IfrEfiVarStore, IfrEfiVarStore->Header.Length);
+ AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, (CHAR16 *) &(EfiVarStoreList [EfiVarStoreNumber]->Name[0]), AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
+ Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_STANDARD, EfiVarStoreList[EfiVarStoreNumber], &VarStoreQuestionHeader, NULL, IfrEfiVarStore->Size, FALSE);
+ if (!EFI_ERROR (Status)) {
+ EfiVarStoreNumber ++;
+ } else {
+ FreePool (EfiVarStoreList [EfiVarStoreNumber]);
+ EfiVarStoreList [EfiVarStoreNumber] = NULL;
+ }
+ break;
+ case EFI_IFR_DEFAULTSTORE_OP:
+ if (DefaultIdNumber >= DefaultIdMaxNum) {
+ //
+ // Reallocate DefaultIdNumber
+ //
+ DefaultIdList = ReallocatePool (DefaultIdMaxNum * sizeof (UINT16), (DefaultIdMaxNum + BASE_NUMBER) * sizeof (UINT16), DefaultIdList);
+ if (DefaultIdList == NULL) {
+ goto Done;
+ }
+ DefaultIdMaxNum = DefaultIdMaxNum + BASE_NUMBER;
+ }
+ DefaultIdList[DefaultIdNumber ++] = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
+ break;
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // No EFI varstore is found and directly return.
+ //
+ if (EfiVarStoreNumber == 0 || DefaultIdNumber == 0) {
+ goto Done;
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ IfrScope = IfrOpHdr->Scope;
+ IfrQuestionType = IfrOpHdr->OpCode;
+ IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1);
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
+ EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber);
+ Width = sizeof (BOOLEAN);
+ if (EfiVarStoreIndex < EfiVarStoreNumber) {
+ for (Index = 0; Index < DefaultIdNumber; Index ++) {
+ if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_STANDARD) {
+ Status = FindQuestionDefaultSetting (DefaultIdList[Index], EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, sizeof (BOOLEAN), QuestionReferBitField);
+ if (!EFI_ERROR (Status)) {
+ if (IfrValue.b) {
+ IfrCheckBox->Flags = IfrCheckBox->Flags | EFI_IFR_CHECKBOX_DEFAULT;
+ } else {
+ IfrCheckBox->Flags = IfrCheckBox->Flags & (~EFI_IFR_CHECKBOX_DEFAULT);
+ }
+ }
+ } else if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ Status = FindQuestionDefaultSetting (DefaultIdList[Index], EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, sizeof (BOOLEAN), QuestionReferBitField);
+ if (!EFI_ERROR (Status)) {
+ if (IfrValue.b) {
+ IfrCheckBox->Flags = IfrCheckBox->Flags | EFI_IFR_CHECKBOX_DEFAULT_MFG;
+ } else {
+ IfrCheckBox->Flags = IfrCheckBox->Flags & (~EFI_IFR_CHECKBOX_DEFAULT_MFG);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case EFI_IFR_NUMERIC_OP:
+ IfrScope = IfrOpHdr->Scope;
+ IfrQuestionType = IfrOpHdr->OpCode;
+ IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1);
+ if (QuestionReferBitField) {
+ Width = (UINTN) (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EDKII_IFR_NUMERIC_SIZE_BIT);
+ } else {
+ Width = (UINTN) ((UINT32) 1 << (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+ break;
+ case EFI_IFR_ONE_OF_OP:
+ IfrScope = IfrOpHdr->Scope;
+ IfrQuestionType = IfrOpHdr->OpCode;
+ IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1);
+ if (QuestionReferBitField) {
+ Width = (UINTN) (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EDKII_IFR_NUMERIC_SIZE_BIT);
+ } else {
+ Width = (UINTN) ((UINT32) 1 << (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EFI_IFR_NUMERIC_SIZE));
+ }
+ EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber);
+ StandardDefaultIsSet = FALSE;
+ ManufactDefaultIsSet = FALSE;
+ //
+ // Find Default and Manufacturing default for OneOf question
+ //
+ if (EfiVarStoreIndex < EfiVarStoreNumber) {
+ for (Index = 0; Index < DefaultIdNumber; Index ++) {
+ if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_STANDARD) {
+ Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_STANDARD, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, Width, QuestionReferBitField);
+ if (!EFI_ERROR (Status)) {
+ StandardDefaultIsSet = TRUE;
+ }
+ } else if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_MANUFACTURING, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrManufactValue, Width, QuestionReferBitField);
+ if (!EFI_ERROR (Status)) {
+ ManufactDefaultIsSet = TRUE;
+ }
+ }
+ }
+ }
+ break;
+ case EFI_IFR_ORDERED_LIST_OP:
+ IfrScope = IfrOpHdr->Scope;
+ IfrQuestionType = IfrOpHdr->OpCode;
+ IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1);
+ break;
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ if (IfrQuestionHdr != NULL && IfrScope > 0) {
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
+ if (IfrQuestionType == EFI_IFR_ONE_OF_OP) {
+ Width = (UINTN) ((UINT32) 1 << (IfrOneOfOption->Flags & EFI_IFR_NUMERIC_SIZE));
+ if (StandardDefaultIsSet) {
+ if (CompareMem (&IfrOneOfOption->Value, &IfrValue, Width) == 0) {
+ IfrOneOfOption->Flags |= EFI_IFR_OPTION_DEFAULT;
+ } else {
+ IfrOneOfOption->Flags &= ~EFI_IFR_OPTION_DEFAULT;
+ }
+ }
+ if (ManufactDefaultIsSet) {
+ if (CompareMem (&IfrOneOfOption->Value, &IfrManufactValue, Width) == 0) {
+ IfrOneOfOption->Flags |= EFI_IFR_OPTION_DEFAULT_MFG;
+ } else {
+ IfrOneOfOption->Flags &= ~EFI_IFR_OPTION_DEFAULT_MFG;
+ }
+ }
+ }
+ }
+ break;
+ case EFI_IFR_DEFAULT_OP:
+ if (IfrQuestionHdr != NULL && IfrScope > 0) {
+ IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
+ //
+ // Collect default value width
+ //
+ if (!QuestionReferBitField) {
+ Width = 0;
+ if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrDefault->Type == EFI_IFR_TYPE_BOOLEAN) {
+ Width = 1;
+ } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
+ Width = 2;
+ } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
+ Width = 4;
+ } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
+ Width = 8;
+ } else if (IfrDefault->Type == EFI_IFR_TYPE_BUFFER) {
+ Width = IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value);
+ }
+ }
+ //
+ // Update the default value
+ //
+ if (Width > 0) {
+ EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber);
+ if (EfiVarStoreIndex < EfiVarStoreNumber) {
+ Status = FindQuestionDefaultSetting (IfrDefault->DefaultId, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrDefault->Value, Width, QuestionReferBitField);
+ }
+ }
+ }
+ break;
+ case EFI_IFR_END_OP:
+ if (IfrQuestionHdr != NULL) {
+ if (IfrScope > 0) {
+ IfrScope --;
+ }
+ if (IfrScope == 0) {
+ IfrQuestionHdr = NULL;
+ QuestionReferBitField = FALSE;
+ }
+ }
+ break;
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ QuestionReferBitField = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ IfrOffset = IfrOffset + IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) IfrOpHdr + IfrOpHdr->Length);
+ if (IfrScope > 0) {
+ IfrScope += IfrOpHdr->Scope;
+ }
+ }
+
+Done:
+ if (EfiVarStoreList != NULL) {
+ for (Index = 0; Index < EfiVarStoreNumber; Index ++) {
+ FreePool (EfiVarStoreList [Index]);
+ }
+ }
+ return;
+}
+
+/**
+ This function insert a Form package to a package list node.
+ This is a internal function.
+
+ @param PackageHdr Pointer to a buffer stored with Form package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Form package
+
+ @retval EFI_SUCCESS Form Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Form package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertFormPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_IFR_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the length of the package, including package header itself
+ //
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a Form package node
+ //
+ FormPackage = (HII_IFR_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IFR_PACKAGE_INSTANCE));
+ if (FormPackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormPackage->IfrData = (UINT8 *) AllocateZeroPool (PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER));
+ if (FormPackage->IfrData == NULL) {
+ FreePool (FormPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormPackage->Signature = HII_IFR_PACKAGE_SIGNATURE;
+ //
+ // Copy Package Header
+ //
+ CopyMem (&FormPackage->FormPkgHdr, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Copy Ifr contents
+ //
+ CopyMem (
+ FormPackage->IfrData,
+ (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER),
+ PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+
+ InsertTailList (&PackageList->FormPkgHdr, &FormPackage->IfrEntry);
+ *Package = FormPackage;
+
+ //
+ // Update FormPackage with the default setting
+ //
+ UpdateDefaultSettingInFormPackage (FormPackage);
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += FormPackage->FormPkgHdr.Length;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports Form packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Form Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportFormPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ UINTN PackageLength;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Export Form packages.
+ //
+ for (Link = PackageList->FormPkgHdr.ForwardLink; Link != &PackageList->FormPkgHdr; Link = Link->ForwardLink) {
+ FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
+ PackageLength += FormPackage->FormPkgHdr.Length;
+ if ((Buffer != NULL) && (PackageLength + *ResultSize + UsedSize <= BufferSize)) {
+ //
+ // Invoke registered notification if exists
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) FormPackage,
+ EFI_HII_PACKAGE_FORMS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy the Form package content.
+ //
+ CopyMem (Buffer, (VOID *) (&FormPackage->FormPkgHdr), sizeof (EFI_HII_PACKAGE_HEADER));
+ Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_PACKAGE_HEADER);
+ CopyMem (
+ Buffer,
+ (VOID *) FormPackage->IfrData,
+ FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ Buffer = (UINT8 *) Buffer + FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
+ }
+ }
+
+ *ResultSize += PackageLength;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function deletes all Form packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Form packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Form Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveFormPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_IFR_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->FormPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_IFR_PACKAGE_INSTANCE,
+ IfrEntry,
+ HII_IFR_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FORMS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->IfrEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->FormPkgHdr.Length;
+ FreePool (Package->IfrData);
+ FreePool (Package);
+ //
+ // If Hii runtime support feature is enabled,
+ // will export Hii info for runtime use after ReadyToBoot event triggered.
+ // If some driver add/update/remove packages from HiiDatabase after ReadyToBoot,
+ // will need to export the content of HiiDatabase.
+ // But if form packages removed, also need to export the ConfigResp string
+ //
+ if (gExportAfterReadyToBoot) {
+ gExportConfigResp = TRUE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This function insert a String package to a package list node.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param PackageHdr Pointer to a buffer stored with String package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created String package
+
+ @retval EFI_SUCCESS String Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ String package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+ @retval EFI_UNSUPPORTED A string package with the same language already
+ exists in current package list.
+
+**/
+EFI_STATUS
+InsertStringPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_STRING_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 HeaderSize;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ CHAR8 *Language;
+ UINT32 LanguageSize;
+ LIST_ENTRY *Link;
+
+ if (Private == NULL || PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32));
+
+ //
+ // It is illegal to have two string packages with same language within one packagelist
+ // since the stringid will be duplicate if so. Check it to avoid this potential issue.
+ //
+ LanguageSize = HeaderSize - sizeof (EFI_HII_STRING_PACKAGE_HDR) + sizeof (CHAR8);
+ Language = (CHAR8 *) AllocateZeroPool (LanguageSize);
+ if (Language == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AsciiStrCpyS (Language, LanguageSize / sizeof (CHAR8), (CHAR8 *) PackageHdr + HeaderSize - LanguageSize);
+ for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (HiiCompareLanguage (Language, StringPackage->StringPkgHdr->Language)) {
+ FreePool (Language);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ FreePool (Language);
+
+ //
+ // Create a String package node
+ //
+ StringPackage = (HII_STRING_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE));
+ if (StringPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->StringPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) AllocateZeroPool (HeaderSize);
+ if (StringPackage->StringPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize);
+ if (StringPackage->StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE;
+ StringPackage->FontId = 0;
+ InitializeListHead (&StringPackage->FontInfoList);
+
+ //
+ // Copy the String package header.
+ //
+ CopyMem (StringPackage->StringPkgHdr, PackageHdr, HeaderSize);
+
+ //
+ // Copy the String blocks
+ //
+ CopyMem (
+ StringPackage->StringBlock,
+ (UINT8 *) PackageHdr + HeaderSize,
+ PackageHeader.Length - HeaderSize
+ );
+
+ //
+ // Collect all font block info
+ //
+ Status = FindStringBlock (Private, StringPackage, (EFI_STRING_ID) (-1), NULL, NULL, NULL, &StringPackage->MaxStringId, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert to String package array
+ //
+ InsertTailList (&PackageList->StringPkgHdr, &StringPackage->StringEntry);
+ *Package = StringPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ if (StringPackage != NULL) {
+ if (StringPackage->StringBlock != NULL) {
+ FreePool (StringPackage->StringBlock);
+ }
+ if (StringPackage->StringPkgHdr != NULL) {
+ FreePool (StringPackage->StringPkgHdr);
+ }
+ FreePool (StringPackage);
+ }
+ return Status;
+
+}
+
+/**
+ Adjust all string packages in a single package list to have the same max string ID.
+
+ @param PackageList Pointer to a package list which will be adjusted.
+
+ @retval EFI_SUCCESS Adjust all string packages successfully.
+ @retval others Can't adjust string packages.
+
+**/
+EFI_STATUS
+AdjustStringPackage (
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+)
+{
+ LIST_ENTRY *Link;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 Skip2BlockSize;
+ UINT32 OldBlockSize;
+ UINT8 *StringBlock;
+ UINT8 *BlockPtr;
+ EFI_STRING_ID MaxStringId;
+ UINT16 SkipCount;
+
+ MaxStringId = 0;
+ for (Link = PackageList->StringPkgHdr.ForwardLink;
+ Link != &PackageList->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (MaxStringId < StringPackage->MaxStringId) {
+ MaxStringId = StringPackage->MaxStringId;
+ }
+ }
+
+ for (Link = PackageList->StringPkgHdr.ForwardLink;
+ Link != &PackageList->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (StringPackage->MaxStringId < MaxStringId) {
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ //
+ // Create SKIP2 EFI_HII_SIBT_SKIP2_BLOCKs to reserve the missing string IDs.
+ //
+ SkipCount = (UINT16) (MaxStringId - StringPackage->MaxStringId);
+ Skip2BlockSize = (UINT32) sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Skip2BlockSize);
+ if (StringBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create SKIP2 EFI_HII_SIBT_SKIP2_BLOCK blocks
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_SKIP2;
+ CopyMem (BlockPtr + 1, &SkipCount, sizeof (UINT16));
+ BlockPtr += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Skip2BlockSize;
+ PackageList->PackageListHdr.PackageLength += Skip2BlockSize;
+ StringPackage->MaxStringId = MaxStringId;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function exports String packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS String Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportStringPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) StringPackage,
+ EFI_HII_PACKAGE_STRINGS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy String package header
+ //
+ CopyMem (Buffer, StringPackage->StringPkgHdr, StringPackage->StringPkgHdr->HdrSize);
+ Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->HdrSize;
+
+ //
+ // Copy String blocks information
+ //
+ CopyMem (
+ Buffer,
+ StringPackage->StringBlock,
+ StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize
+ );
+ Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all String packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed String packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS String Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveStringPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_STRING_PACKAGE_INSTANCE *Package;
+ HII_FONT_INFO *FontInfo;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->StringPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_STRING_PACKAGE_INSTANCE,
+ StringEntry,
+ HII_STRING_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_STRINGS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->StringEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->StringPkgHdr->Header.Length;
+ FreePool (Package->StringBlock);
+ FreePool (Package->StringPkgHdr);
+ //
+ // Delete font information
+ //
+ while (!IsListEmpty (&Package->FontInfoList)) {
+ FontInfo = CR (
+ Package->FontInfoList.ForwardLink,
+ HII_FONT_INFO,
+ Entry,
+ HII_FONT_INFO_SIGNATURE
+ );
+ RemoveEntryList (&FontInfo->Entry);
+ FreePool (FontInfo);
+ }
+
+ FreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Font package to a package list node.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param PackageHdr Pointer to a buffer stored with Font package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Font package
+
+ @retval EFI_SUCCESS Font Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Font package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+ @retval EFI_UNSUPPORTED A font package with same EFI_FONT_INFO already
+ exists in current hii database.
+
+**/
+EFI_STATUS
+InsertFontPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_FONT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_FONT_PACKAGE_INSTANCE *FontPackage;
+ EFI_HII_FONT_PACKAGE_HDR *FontPkgHdr;
+ UINT32 HeaderSize;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_FONT_INFO *FontInfo;
+ UINT32 FontInfoSize;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ if (Private == NULL || PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32));
+
+ FontInfo = NULL;
+ FontPackage = NULL;
+ GlobalFont = NULL;
+
+ //
+ // It is illegal to have two font packages with same EFI_FONT_INFO within hii
+ // database. EFI_FONT_INFO (FontName, FontSize, FontStyle) describes font's
+ // attributes and identify a font uniquely.
+ //
+ FontPkgHdr = (EFI_HII_FONT_PACKAGE_HDR *) AllocateZeroPool (HeaderSize);
+ if (FontPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ CopyMem (FontPkgHdr, PackageHdr, HeaderSize);
+
+ FontInfoSize = sizeof (EFI_FONT_INFO) + HeaderSize - sizeof (EFI_HII_FONT_PACKAGE_HDR);
+ FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize);
+ if (FontInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ FontInfo->FontStyle = FontPkgHdr->FontStyle;
+ FontInfo->FontSize = FontPkgHdr->Cell.Height;
+ StrCpyS (FontInfo->FontName, (FontInfoSize - OFFSET_OF(EFI_FONT_INFO,FontName)) / sizeof (CHAR16), FontPkgHdr->FontFamily);
+
+ if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+ //
+ // Create a Font package node
+ //
+ FontPackage = (HII_FONT_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_FONT_PACKAGE_INSTANCE));
+ if (FontPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ FontPackage->Signature = HII_FONT_PACKAGE_SIGNATURE;
+ FontPackage->FontPkgHdr = FontPkgHdr;
+ InitializeListHead (&FontPackage->GlyphInfoList);
+
+ FontPackage->GlyphBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize);
+ if (FontPackage->GlyphBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ CopyMem (FontPackage->GlyphBlock, (UINT8 *) PackageHdr + HeaderSize, PackageHeader.Length - HeaderSize);
+
+ //
+ // Collect all default character cell information and backup in GlyphInfoList.
+ //
+ Status = FindGlyphBlock (FontPackage, (CHAR16) (-1), NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // This font package describes an unique EFI_FONT_INFO. Backup it in global
+ // font info list.
+ //
+ GlobalFont = (HII_GLOBAL_FONT_INFO *) AllocateZeroPool (sizeof (HII_GLOBAL_FONT_INFO));
+ if (GlobalFont == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ GlobalFont->Signature = HII_GLOBAL_FONT_INFO_SIGNATURE;
+ GlobalFont->FontPackage = FontPackage;
+ GlobalFont->FontInfoSize = FontInfoSize;
+ GlobalFont->FontInfo = FontInfo;
+ InsertTailList (&Private->FontInfoList, &GlobalFont->Entry);
+
+ //
+ // Insert this font package to Font package array
+ //
+ InsertTailList (&PackageList->FontPkgHdr, &FontPackage->FontEntry);
+ *Package = FontPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += FontPackage->FontPkgHdr->Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ if (FontPkgHdr != NULL) {
+ FreePool (FontPkgHdr);
+ }
+ if (FontInfo != NULL) {
+ FreePool (FontInfo);
+ }
+ if (FontPackage != NULL) {
+ if (FontPackage->GlyphBlock != NULL) {
+ FreePool (FontPackage->GlyphBlock);
+ }
+ FreePool (FontPackage);
+ }
+ if (GlobalFont != NULL) {
+ FreePool (GlobalFont);
+ }
+
+ return Status;
+
+}
+
+
+/**
+ This function exports Font packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Font Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_FONT_PACKAGE_INSTANCE *Package;
+
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->FontPkgHdr.ForwardLink; Link != &PackageList->FontPkgHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_FONT_PACKAGE_INSTANCE, FontEntry, HII_FONT_PACKAGE_SIGNATURE);
+ PackageLength += Package->FontPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FONTS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy Font package header
+ //
+ CopyMem (Buffer, Package->FontPkgHdr, Package->FontPkgHdr->HdrSize);
+ Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->HdrSize;
+
+ //
+ // Copy Glyph blocks information
+ //
+ CopyMem (
+ Buffer,
+ Package->GlyphBlock,
+ Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize
+ );
+ Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Font packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Font packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Font Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_FONT_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+ HII_GLYPH_INFO *GlyphInfo;
+ LIST_ENTRY *Link;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ ListHead = &PackageList->FontPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_FONT_PACKAGE_INSTANCE,
+ FontEntry,
+ HII_FONT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FONTS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->FontEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->FontPkgHdr->Header.Length;
+
+ if (Package->GlyphBlock != NULL) {
+ FreePool (Package->GlyphBlock);
+ }
+ FreePool (Package->FontPkgHdr);
+ //
+ // Delete default character cell information
+ //
+ while (!IsListEmpty (&Package->GlyphInfoList)) {
+ GlyphInfo = CR (
+ Package->GlyphInfoList.ForwardLink,
+ HII_GLYPH_INFO,
+ Entry,
+ HII_GLYPH_INFO_SIGNATURE
+ );
+ RemoveEntryList (&GlyphInfo->Entry);
+ FreePool (GlyphInfo);
+ }
+
+ //
+ // Remove corresponding global font info
+ //
+ for (Link = Private->FontInfoList.ForwardLink; Link != &Private->FontInfoList; Link = Link->ForwardLink) {
+ GlobalFont = CR (Link, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ if (GlobalFont->FontPackage == Package) {
+ RemoveEntryList (&GlobalFont->Entry);
+ FreePool (GlobalFont->FontInfo);
+ FreePool (GlobalFont);
+ break;
+ }
+ }
+
+ FreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Image package to a package list node.
+ This is a internal function.
+
+ @param PackageHdr Pointer to a buffer stored with Image package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Image package
+
+ @retval EFI_SUCCESS Image Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Image package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertImagePackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_IMAGE_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ UINT32 PaletteSize;
+ UINT32 ImageSize;
+ UINT16 Index;
+ EFI_HII_IMAGE_PALETTE_INFO_HEADER *PaletteHdr;
+ EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo;
+ UINT32 PaletteInfoOffset;
+ UINT32 ImageInfoOffset;
+ UINT16 CurrentSize;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Less than one image package is allowed in one package list.
+ //
+ if (PackageList->ImagePkg != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a Image package node
+ //
+ ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
+ if (ImagePackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the Image package header.
+ //
+ CopyMem (&ImagePackage->ImagePkgHdr, PackageHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR));
+
+ PaletteInfoOffset = ImagePackage->ImagePkgHdr.PaletteInfoOffset;
+ ImageInfoOffset = ImagePackage->ImagePkgHdr.ImageInfoOffset;
+
+ //
+ // If PaletteInfoOffset is zero, there are no palettes in this image package.
+ //
+ PaletteSize = 0;
+ ImagePackage->PaletteBlock = NULL;
+ if (PaletteInfoOffset != 0) {
+ PaletteHdr = (EFI_HII_IMAGE_PALETTE_INFO_HEADER *) ((UINT8 *) PackageHdr + PaletteInfoOffset);
+ PaletteSize = sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
+ PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteHdr + PaletteSize);
+
+ for (Index = 0; Index < PaletteHdr->PaletteCount; Index++) {
+ CopyMem (&CurrentSize, PaletteInfo, sizeof (UINT16));
+ CurrentSize += sizeof (UINT16);
+ PaletteSize += (UINT32) CurrentSize;
+ PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteInfo + CurrentSize);
+ }
+
+ ImagePackage->PaletteBlock = (UINT8 *) AllocateZeroPool (PaletteSize);
+ if (ImagePackage->PaletteBlock == NULL) {
+ FreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ ImagePackage->PaletteBlock,
+ (UINT8 *) PackageHdr + PaletteInfoOffset,
+ PaletteSize
+ );
+ }
+
+ //
+ // If ImageInfoOffset is zero, there are no images in this package.
+ //
+ ImageSize = 0;
+ ImagePackage->ImageBlock = NULL;
+ if (ImageInfoOffset != 0) {
+ ImageSize = ImagePackage->ImagePkgHdr.Header.Length -
+ sizeof (EFI_HII_IMAGE_PACKAGE_HDR) - PaletteSize;
+ ImagePackage->ImageBlock = AllocateZeroPool (ImageSize);
+ if (ImagePackage->ImageBlock == NULL) {
+ FreePool (ImagePackage->PaletteBlock);
+ FreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ ImagePackage->ImageBlock,
+ (UINT8 *) PackageHdr + ImageInfoOffset,
+ ImageSize
+ );
+ }
+
+ ImagePackage->ImageBlockSize = ImageSize;
+ ImagePackage->PaletteInfoSize = PaletteSize;
+ PackageList->ImagePkg = ImagePackage;
+ *Package = ImagePackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports Image packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Image Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportImagePackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_IMAGE_PACKAGE_INSTANCE *Package;
+
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Package = PackageList->ImagePkg;
+
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ PackageLength = Package->ImagePkgHdr.Header.Length;
+
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_IMAGES,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Package->ImagePkgHdr.Header.Length ==
+ sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + Package->ImageBlockSize + Package->PaletteInfoSize);
+ //
+ // Copy Image package header,
+ // then justify the offset for image info and palette info in the header.
+ //
+ CopyMem (Buffer, &Package->ImagePkgHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR));
+ Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+
+ //
+ // Copy Image blocks information
+ //
+ if (Package->ImageBlockSize != 0) {
+ CopyMem (Buffer, Package->ImageBlock, Package->ImageBlockSize);
+ Buffer = (UINT8 *) Buffer + Package->ImageBlockSize;
+ }
+ //
+ // Copy Palette information
+ //
+ if (Package->PaletteInfoSize != 0) {
+ CopyMem (Buffer, Package->PaletteBlock, Package->PaletteInfoSize);
+ Buffer = (UINT8 *) Buffer + Package->PaletteInfoSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes Image package from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Image packages.
+ @param PackageList Package List which contains the to be removed
+ Image package.
+
+ @retval EFI_SUCCESS Image Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveImagePackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ HII_IMAGE_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ Package = PackageList->ImagePkg;
+
+ //
+ // Image package does not exist, return directly.
+ //
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_IMAGES,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PackageList->PackageListHdr.PackageLength -= Package->ImagePkgHdr.Header.Length;
+
+ FreePool (Package->ImageBlock);
+ if (Package->PaletteBlock != NULL) {
+ FreePool (Package->PaletteBlock);
+ }
+ FreePool (Package);
+
+ PackageList->ImagePkg = NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Simple Font package to a package list node.
+ This is a internal function.
+
+ @param PackageHdr Pointer to a buffer stored with Simple Font
+ package information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Simple Font package
+
+ @retval EFI_SUCCESS Simple Font Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Simple Font package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertSimpleFontPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_SIMPLE_FONT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a Simple Font package node
+ //
+ SimpleFontPackage = AllocateZeroPool (sizeof (HII_SIMPLE_FONT_PACKAGE_INSTANCE));
+ if (SimpleFontPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ SimpleFontPackage->Signature = HII_S_FONT_PACKAGE_SIGNATURE;
+
+ //
+ // Copy the Simple Font package.
+ //
+ CopyMem (&Header, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ SimpleFontPackage->SimpleFontPkgHdr = AllocateZeroPool (Header.Length);
+ if (SimpleFontPackage->SimpleFontPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (SimpleFontPackage->SimpleFontPkgHdr, PackageHdr, Header.Length);
+
+ //
+ // Insert to Simple Font package array
+ //
+ InsertTailList (&PackageList->SimpleFontPkgHdr, &SimpleFontPackage->SimpleFontEntry);
+ *Package = SimpleFontPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ if (SimpleFontPackage != NULL) {
+ if (SimpleFontPackage->SimpleFontPkgHdr != NULL) {
+ FreePool (SimpleFontPackage->SimpleFontPkgHdr);
+ }
+ FreePool (SimpleFontPackage);
+ }
+ return Status;
+}
+
+
+/**
+ This function exports SimpleFont packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS SimpleFont Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportSimpleFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->SimpleFontPkgHdr.ForwardLink; Link != &PackageList->SimpleFontPkgHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE);
+ PackageLength += Package->SimpleFontPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy SimpleFont package
+ //
+ CopyMem (Buffer, Package->SimpleFontPkgHdr, Package->SimpleFontPkgHdr->Header.Length);
+ Buffer = (UINT8 *) Buffer + Package->SimpleFontPkgHdr->Header.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Simple Font packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Simple Font packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Simple Font Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveSimpleFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->SimpleFontPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE,
+ SimpleFontEntry,
+ HII_S_FONT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->SimpleFontEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->SimpleFontPkgHdr->Header.Length;
+ FreePool (Package->SimpleFontPkgHdr);
+ FreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Device path package to a package list node.
+ This is a internal function.
+
+ @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol
+ instance
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+
+ @retval EFI_SUCCESS Device path Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertDevicePathPackage (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ UINT32 PackageLength;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (DevicePath == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Less than one device path package is allowed in one package list.
+ //
+ if (PackageList->DevicePathPkg != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = (UINT32) GetDevicePathSize (DevicePath) + sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageList->DevicePathPkg = (UINT8 *) AllocateZeroPool (PackageLength);
+ if (PackageList->DevicePathPkg == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Header.Length = PackageLength;
+ Header.Type = EFI_HII_PACKAGE_DEVICE_PATH;
+ CopyMem (PackageList->DevicePathPkg, &Header, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (
+ PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER),
+ DevicePath,
+ PackageLength - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+
+ //
+ // Since Device Path package is created by NewPackageList, either NEW_PACK
+ // or ADD_PACK should increase the length of package list.
+ //
+ PackageList->PackageListHdr.PackageLength += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports device path package to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Device path Package is exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Package;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Package = PackageList->DevicePathPkg;
+
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ if (Header.Length + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy Device path package
+ //
+ CopyMem (Buffer, Package, Header.Length);
+ }
+
+ *ResultSize += Header.Length;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes Device Path package from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list.
+ @param PackageList Package List which contains the to be removed
+ Device Path package.
+
+ @retval EFI_SUCCESS Device Path Package is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Package;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ Package = PackageList->DevicePathPkg;
+
+ //
+ // No device path, return directly.
+ //
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= Header.Length;
+
+ FreePool (Package);
+
+ PackageList->DevicePathPkg = NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will insert a device path package to package list firstly then
+ invoke notification functions if any.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param NotifyType The type of change concerning the database.
+ @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol
+ instance
+ @param DatabaseRecord Pointer to a database record contains a package
+ list which will be inserted to.
+
+ @retval EFI_SUCCESS Device path Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+AddDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN OUT HII_DATABASE_RECORD *DatabaseRecord
+ )
+{
+ EFI_STATUS Status;
+
+ if (DevicePath == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (Private != NULL);
+ ASSERT (DatabaseRecord != NULL);
+
+ //
+ // Create a device path package and insert to packagelist
+ //
+ Status = InsertDevicePathPackage (
+ DevicePath,
+ NotifyType,
+ DatabaseRecord->PackageList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) DatabaseRecord->PackageList->DevicePathPkg,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ DatabaseRecord->Handle
+ );
+}
+
+
+/**
+ This function insert a Keyboard Layout package to a package list node.
+ This is a internal function.
+
+ @param PackageHdr Pointer to a buffer stored with Keyboard Layout
+ package information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Keyboard Layout package
+
+ @retval EFI_SUCCESS Keyboard Layout Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Keyboard Layout package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+EFI_STATUS
+InsertKeyboardLayoutPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a Keyboard Layout package node
+ //
+ KeyboardLayoutPackage = AllocateZeroPool (sizeof (HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE));
+ if (KeyboardLayoutPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ KeyboardLayoutPackage->Signature = HII_KB_LAYOUT_PACKAGE_SIGNATURE;
+
+ KeyboardLayoutPackage->KeyboardPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length);
+ if (KeyboardLayoutPackage->KeyboardPkg == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (KeyboardLayoutPackage->KeyboardPkg, PackageHdr, PackageHeader.Length);
+ InsertTailList (&PackageList->KeyboardLayoutHdr, &KeyboardLayoutPackage->KeyboardEntry);
+
+ *Package = KeyboardLayoutPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += PackageHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+
+ if (KeyboardLayoutPackage != NULL) {
+ if (KeyboardLayoutPackage->KeyboardPkg != NULL) {
+ FreePool (KeyboardLayoutPackage->KeyboardPkg);
+ }
+ FreePool (KeyboardLayoutPackage);
+ }
+
+ return Status;
+}
+
+
+/**
+ This function exports Keyboard Layout packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Keyboard Layout Packages are exported
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportKeyboardLayoutPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->KeyboardLayoutHdr.ForwardLink; Link != &PackageList->KeyboardLayoutHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE);
+ CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageLength += PackageHeader.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (EFI_HII_PACKAGE_HEADER *) Package,
+ EFI_HII_PACKAGE_KEYBOARD_LAYOUT,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy Keyboard Layout package
+ //
+ CopyMem (Buffer, Package->KeyboardPkg, PackageHeader.Length);
+ Buffer = (UINT8 *) Buffer + PackageHeader.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Keyboard Layout packages from a package list node.
+ This is a internal function.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Keyboard Layout packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Keyboard Layout Package(s) is deleted
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+RemoveKeyboardLayoutPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->KeyboardLayoutHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_KEYBOARD_LAYOUT,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->KeyboardEntry);
+ CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= PackageHeader.Length;
+ FreePool (Package->KeyboardPkg);
+ FreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will insert a package list to hii database firstly then
+ invoke notification functions if any. It is the worker function of
+ HiiNewPackageList and HiiUpdatePackageList.
+
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list.
+ @param DatabaseRecord Pointer to a database record contains a package
+ list instance which will be inserted to.
+
+ @retval EFI_SUCCESS All incoming packages are inserted to current
+ database.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+AddPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+ IN OUT HII_DATABASE_RECORD *DatabaseRecord
+ )
+{
+ EFI_STATUS Status;
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ HII_FONT_PACKAGE_INSTANCE *FontPackage;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_PACKAGE_HEADER *PackageHdrPtr;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT32 OldPackageListLen;
+ BOOLEAN StringPkgIsAdd;
+
+ //
+ // Initialize Variables
+ //
+ StringPkgIsAdd = FALSE;
+ FontPackage = NULL;
+ StringPackage = NULL;
+ GuidPackage = NULL;
+ FormPackage = NULL;
+ ImagePackage = NULL;
+ SimpleFontPackage = NULL;
+ KeyboardLayoutPackage = NULL;
+
+ //
+ // Process the package list header
+ //
+ OldPackageListLen = DatabaseRecord->PackageList->PackageListHdr.PackageLength;
+ CopyMem (
+ &DatabaseRecord->PackageList->PackageListHdr,
+ (VOID *) PackageList,
+ sizeof (EFI_HII_PACKAGE_LIST_HEADER)
+ );
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ DatabaseRecord->PackageList->PackageListHdr.PackageLength = OldPackageListLen;
+ }
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ Status = EFI_SUCCESS;
+
+ while (PackageHeader.Type != EFI_HII_PACKAGE_END) {
+ switch (PackageHeader.Type) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Status = InsertGuidPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &GuidPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) GuidPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_FORMS:
+ Status = InsertFormPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &FormPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) FormPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ //
+ // If Hii runtime support feature is enabled,
+ // will export Hii info for runtime use after ReadyToBoot event triggered.
+ // If some driver add/update/remove packages from HiiDatabase after ReadyToBoot,
+ // will need to export the content of HiiDatabase.
+ // But if form packages added/updated, also need to export the ConfigResp string.
+ //
+ if (gExportAfterReadyToBoot) {
+ gExportConfigResp = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Status = InsertKeyboardLayoutPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &KeyboardLayoutPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) KeyboardLayoutPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ Status = InsertStringPackage (
+ Private,
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &StringPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (StringPackage != NULL);
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) StringPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ StringPkgIsAdd = TRUE;
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ Status = InsertFontPackage (
+ Private,
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &FontPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) FontPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ Status = InsertImagePackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &ImagePackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) ImagePackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ Status = InsertSimpleFontPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &SimpleFontPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) SimpleFontPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Status = AddDevicePathPackage (
+ Private,
+ NotifyType,
+ (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *) PackageHdrPtr + sizeof (EFI_HII_PACKAGE_HEADER)),
+ DatabaseRecord
+ );
+ break;
+ default:
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // goto header of next package
+ //
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length);
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ }
+
+ //
+ // Adjust String Package to make sure all string packages have the same max string ID.
+ //
+ if (!EFI_ERROR (Status) && StringPkgIsAdd) {
+ Status = AdjustStringPackage (DatabaseRecord->PackageList);
+ }
+
+ return Status;
+}
+
+
+/**
+ This function exports a package list to a buffer. It is the worker function
+ of HiiExportPackageList.
+
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer has been used by exporting
+ package lists when Handle is NULL.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+
+ @retval EFI_SUCCESS Keyboard Layout Packages are exported
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportPackageList (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN OUT UINTN *UsedSize,
+ IN UINTN BufferSize,
+ OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN ResultSize;
+ EFI_HII_PACKAGE_HEADER EndofPackageList;
+
+ ASSERT (Private != NULL && PackageList != NULL && UsedSize != NULL);
+ ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ ASSERT (IsHiiHandleValid (Handle));
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Copy the package list header
+ // ResultSize indicates the length of the exported bytes of this package list
+ //
+ ResultSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ if (ResultSize + *UsedSize <= BufferSize) {
+ CopyMem ((VOID *) Buffer, PackageList, ResultSize);
+ }
+ //
+ // Copy the packages and invoke EXPORT_PACK notify functions if exists.
+ //
+ Status = ExportGuidPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportFormPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportKeyboardLayoutPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportStringPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportFontPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportImagePackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportSimpleFontPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportDevicePathPackage (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Append the package list end.
+ //
+ EndofPackageList.Length = sizeof (EFI_HII_PACKAGE_HEADER);
+ EndofPackageList.Type = EFI_HII_PACKAGE_END;
+ if (ResultSize + *UsedSize + sizeof (EFI_HII_PACKAGE_HEADER) <= BufferSize) {
+ CopyMem (
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ (VOID *) &EndofPackageList,
+ sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ }
+
+ *UsedSize += ResultSize + sizeof (EFI_HII_PACKAGE_HEADER);
+
+ return EFI_SUCCESS;
+}
+
+/**
+This function mainly use to get and update ConfigResp string.
+
+@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+@retval EFI_SUCCESS Get the information successfully.
+@retval EFI_OUT_OF_RESOURCES Not enough memory to store the Configuration Setting data.
+
+**/
+EFI_STATUS
+HiiGetConfigRespInfo(
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING ConfigAltResp;
+ UINTN ConfigSize;
+
+ ConfigAltResp = NULL;
+ ConfigSize = 0;
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get ConfigResp string
+ //
+ Status = HiiConfigRoutingExportConfig(&Private->ConfigRouting,&ConfigAltResp);
+
+ if (!EFI_ERROR (Status)){
+ ConfigSize = StrSize(ConfigAltResp);
+ if (ConfigSize > gConfigRespSize){
+ //
+ // Do 25% overallocation to minimize the number of memory allocations after ReadyToBoot.
+ // Since lots of allocation after ReadyToBoot may change memory map and cause S4 resume issue.
+ //
+ gConfigRespSize = ConfigSize + (ConfigSize >> 2);
+ if (gRTConfigRespBuffer != NULL){
+ FreePool(gRTConfigRespBuffer);
+ DEBUG ((DEBUG_WARN, "[HiiDatabase]: Memory allocation is required after ReadyToBoot, which may change memory map and cause S4 resume issue.\n"));
+ }
+ gRTConfigRespBuffer = (EFI_STRING) AllocateRuntimeZeroPool (gConfigRespSize);
+ if (gRTConfigRespBuffer == NULL){
+ FreePool(ConfigAltResp);
+ DEBUG ((DEBUG_ERROR, "[HiiDatabase]: No enough memory resource to store the ConfigResp string.\n"));
+ //
+ // Remove from the System Table when the configuration runtime buffer is freed.
+ //
+ gBS->InstallConfigurationTable (&gEfiHiiConfigRoutingProtocolGuid, NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ ZeroMem(gRTConfigRespBuffer,gConfigRespSize);
+ }
+ CopyMem(gRTConfigRespBuffer,ConfigAltResp,ConfigSize);
+ gBS->InstallConfigurationTable (&gEfiHiiConfigRoutingProtocolGuid, gRTConfigRespBuffer);
+ FreePool(ConfigAltResp);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+This is an internal function,mainly use to get HiiDatabase information.
+
+@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+@retval EFI_SUCCESS Get the information successfully.
+@retval EFI_OUT_OF_RESOURCES Not enough memory to store the Hiidatabase data.
+
+**/
+EFI_STATUS
+HiiGetDatabaseInfo(
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *DatabaseInfo;
+ UINTN DatabaseInfoSize;
+
+ DatabaseInfo = NULL;
+ DatabaseInfoSize = 0;
+
+ //
+ // Get HiiDatabase information.
+ //
+ Status = HiiExportPackageLists(This, NULL, &DatabaseInfoSize, DatabaseInfo);
+
+ ASSERT(Status == EFI_BUFFER_TOO_SMALL);
+
+ if(DatabaseInfoSize > gDatabaseInfoSize ) {
+ //
+ // Do 25% overallocation to minimize the number of memory allocations after ReadyToBoot.
+ // Since lots of allocation after ReadyToBoot may change memory map and cause S4 resume issue.
+ //
+ gDatabaseInfoSize = DatabaseInfoSize + (DatabaseInfoSize >> 2);
+ if (gRTDatabaseInfoBuffer != NULL){
+ FreePool(gRTDatabaseInfoBuffer);
+ DEBUG ((DEBUG_WARN, "[HiiDatabase]: Memory allocation is required after ReadyToBoot, which may change memory map and cause S4 resume issue.\n"));
+ }
+ gRTDatabaseInfoBuffer = AllocateRuntimeZeroPool (gDatabaseInfoSize);
+ if (gRTDatabaseInfoBuffer == NULL){
+ DEBUG ((DEBUG_ERROR, "[HiiDatabase]: No enough memory resource to store the HiiDatabase info.\n"));
+ //
+ // Remove from the System Table when the configuration runtime buffer is freed.
+ //
+ gBS->InstallConfigurationTable (&gEfiHiiDatabaseProtocolGuid, NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ ZeroMem(gRTDatabaseInfoBuffer,gDatabaseInfoSize);
+ }
+ Status = HiiExportPackageLists(This, NULL, &DatabaseInfoSize, gRTDatabaseInfoBuffer);
+ ASSERT_EFI_ERROR (Status);
+ gBS->InstallConfigurationTable (&gEfiHiiDatabaseProtocolGuid, gRTDatabaseInfoBuffer);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This function adds the packages in the package list to the database and returns a handle. If there is a
+ EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will
+ create a package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ structure.
+ @param DriverHandle Associate the package list with this EFI handle.
+ If a NULL is specified, this data will not be associate
+ with any drivers and cannot have a callback induced.
+ @param Handle A pointer to the EFI_HII_HANDLE instance.
+
+ @retval EFI_SUCCESS The package list associated with the Handle was
+ added to the HII database.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ database contents.
+ @retval EFI_INVALID_PARAMETER PackageList is NULL or Handle is NULL.
+ @retval EFI_INVALID_PARAMETER PackageListGuid already exists in database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewPackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+ IN CONST EFI_HANDLE DriverHandle, OPTIONAL
+ OUT EFI_HII_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ LIST_ENTRY *Link;
+ EFI_GUID PackageListGuid;
+
+ if (This == NULL || PackageList == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ CopyMem (&PackageListGuid, (VOID *) PackageList, sizeof (EFI_GUID));
+
+ //
+ // Check the Package list GUID to guarantee this GUID is unique in database.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (CompareGuid (
+ &(DatabaseRecord->PackageList->PackageListHdr.PackageListGuid),
+ &PackageListGuid) &&
+ DatabaseRecord->DriverHandle == DriverHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ //
+ // Build a PackageList node
+ //
+ Status = GenerateHiiDatabaseRecord (Private, &DatabaseRecord);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+
+ //
+ // Fill in information of the created Package List node
+ // according to incoming package list.
+ //
+ Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, PackageList, DatabaseRecord);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+
+ DatabaseRecord->DriverHandle = DriverHandle;
+
+ //
+ // Create a Device path package and add into the package list if exists.
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AddDevicePathPackage (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, DevicePath, DatabaseRecord);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ *Handle = DatabaseRecord->Handle;
+
+ //
+ // Check whether need to get the Database info.
+ // Only after ReadyToBoot, need to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ HiiGetDatabaseInfo (This);
+ }
+ EfiReleaseLock (&mHiiDatabaseLock);
+
+ //
+ // Notes:
+ // HiiGetDatabaseInfo () will get the contents of HII data base,
+ // belong to the atomic behavior of Hii Database update.
+ // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers
+ // we can not think it belong to the atomic behavior of Hii Database update.
+ // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo ().
+ //
+
+ // Check whether need to get the configuration setting info from HII drivers.
+ // When after ReadyToBoot and need to do the export for form package add.
+ //
+ if (gExportAfterReadyToBoot && gExportConfigResp) {
+ HiiGetConfigRespInfo (This);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes the package list that is associated with Handle
+ from the HII database. Before removing the package, any registered functions
+ with the notification type REMOVE_PACK and the same package type will be called.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that is
+ requested for removal.
+
+ @retval EFI_SUCCESS The data associated with the Handle was removed
+ from the HII database.
+ @retval EFI_NOT_FOUND The specified handle is not in database.
+ @retval EFI_INVALID_PARAMETER The Handle was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRemovePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ HII_HANDLE *HiiHandle;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the packagelist to be removed.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == Handle) {
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ ASSERT (PackageList != NULL);
+
+ //
+ // Call registered functions with REMOVE_PACK before removing packages
+ // then remove them.
+ //
+ Status = RemoveGuidPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveFormPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveKeyboardLayoutPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveStringPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveFontPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveImagePackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveSimpleFontPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ Status = RemoveDevicePathPackage (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+
+ //
+ // Free resources of the package list
+ //
+ RemoveEntryList (&Node->DatabaseEntry);
+
+ HiiHandle = (HII_HANDLE *) Handle;
+ RemoveEntryList (&HiiHandle->Handle);
+ Private->HiiHandleCount--;
+ ASSERT (Private->HiiHandleCount >= 0);
+
+ HiiHandle->Signature = 0;
+ FreePool (HiiHandle);
+ FreePool (Node->PackageList);
+ FreePool (Node);
+
+ //
+ // Check whether need to get the Database info.
+ // Only after ReadyToBoot, need to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ HiiGetDatabaseInfo (This);
+ }
+ EfiReleaseLock (&mHiiDatabaseLock);
+
+ //
+ // Notes:
+ // HiiGetDatabaseInfo () will get the contents of HII data base,
+ // belong to the atomic behavior of Hii Database update.
+ // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers
+ // we can not think it belong to the atomic behavior of Hii Database update.
+ // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo ().
+ //
+
+ //
+ // Check whether need to get the configuration setting info from HII drivers.
+ // When after ReadyToBoot and need to do the export for form package remove.
+ //
+ if (gExportAfterReadyToBoot && gExportConfigResp) {
+ HiiGetConfigRespInfo (This);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function updates the existing package list (which has the specified Handle)
+ in the HII databases, using the new package list specified by PackageList.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that is
+ requested to be updated.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ package.
+
+ @retval EFI_SUCCESS The HII database was successfully updated.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate enough memory for the updated
+ database.
+ @retval EFI_INVALID_PARAMETER PackageList was NULL.
+ @retval EFI_NOT_FOUND The specified Handle is not in database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdatePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Node;
+ EFI_HII_PACKAGE_HEADER *PackageHdrPtr;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *OldPackageList;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (This == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+
+ Status = EFI_SUCCESS;
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+ //
+ // Get original packagelist to be updated
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == Handle) {
+ OldPackageList = Node->PackageList;
+ //
+ // Remove the package if its type matches one of the package types which is
+ // contained in the new package list.
+ //
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ while (PackageHeader.Type != EFI_HII_PACKAGE_END) {
+ switch (PackageHeader.Type) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Status = RemoveGuidPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_FORMS:
+ Status = RemoveFormPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Status = RemoveKeyboardLayoutPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ Status = RemoveStringPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ Status = RemoveFontPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ Status = RemoveImagePackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ Status = RemoveSimpleFontPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Status = RemoveDevicePathPackage (Private, Handle, OldPackageList);
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length);
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ }
+
+ //
+ // Add all of the packages within the new package list
+ //
+ Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_ADD_PACK, PackageList, Node);
+
+ //
+ // Check whether need to get the Database info.
+ // Only after ReadyToBoot, need to do the export.
+ //
+ if (gExportAfterReadyToBoot && Status == EFI_SUCCESS) {
+ HiiGetDatabaseInfo (This);
+ }
+ EfiReleaseLock (&mHiiDatabaseLock);
+
+ //
+ // Notes:
+ // HiiGetDatabaseInfo () will get the contents of HII data base,
+ // belong to the atomic behavior of Hii Database update.
+ // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers
+ // we can not think it belong to the atomic behavior of Hii Database update.
+ // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo ().
+ //
+
+ //
+ // Check whether need to get the configuration setting info from HII drivers.
+ // When after ReadyToBoot and need to do the export for form package update.
+ //
+ if (gExportAfterReadyToBoot && gExportConfigResp && Status == EFI_SUCCESS) {
+ HiiGetConfigRespInfo (This);
+ }
+
+ return Status;
+ }
+ }
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function returns a list of the package handles of the specified type
+ that are currently active in the database. The pseudo-type
+ EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to list
+ or EFI_HII_PACKAGE_TYPE_ALL for all packages to be
+ listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR.
+ Otherwise, it must be NULL.
+ @param HandleBufferLength On input, a pointer to the length of the handle
+ buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param Handle An array of EFI_HII_HANDLE instances returned.
+
+ @retval EFI_SUCCESS The matching handles are outputted successfully.
+ HandleBufferLength is updated with the actual length.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with a
+ value that will enable the data to fit.
+ @retval EFI_NOT_FOUND No matching handle could not be found in database.
+ @retval EFI_INVALID_PARAMETER HandleBufferLength was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by HandleBufferLength was not
+ zero and Handle was NULL.
+ @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but
+ PackageGuid is not NULL, PackageType is a EFI_HII_
+ PACKAGE_TYPE_GUID but PackageGuid is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiListPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN OUT UINTN *HandleBufferLength,
+ OUT EFI_HII_HANDLE *Handle
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+ BOOLEAN Matched;
+ HII_HANDLE **Result;
+ UINTN ResultSize;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link1;
+
+ //
+ // Check input parameters
+ //
+ if (This == NULL || HandleBufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*HandleBufferLength > 0 && Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) ||
+ (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ Matched = FALSE;
+ Result = (HII_HANDLE **) Handle;
+ ResultSize = 0;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ switch (PackageType) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ for (Link1 = PackageList->GuidPkgHdr.ForwardLink; Link1 != &PackageList->GuidPkgHdr; Link1 = Link1->ForwardLink) {
+ GuidPackage = CR (Link1, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE);
+ if (CompareGuid (
+ (EFI_GUID *) PackageGuid,
+ (EFI_GUID *) (GuidPackage->GuidPkg + sizeof (EFI_HII_PACKAGE_HEADER))
+ )) {
+ Matched = TRUE;
+ break;
+ }
+ }
+ break;
+ case EFI_HII_PACKAGE_FORMS:
+ if (!IsListEmpty (&PackageList->FormPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ if (!IsListEmpty (&PackageList->KeyboardLayoutHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ if (!IsListEmpty (&PackageList->StringPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ if (!IsListEmpty (&PackageList->FontPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ if (PackageList->ImagePkg != NULL) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ if (!IsListEmpty (&PackageList->SimpleFontPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ if (PackageList->DevicePathPkg != NULL) {
+ Matched = TRUE;
+ }
+ break;
+ //
+ // Pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package handles
+ // to be listed.
+ //
+ case EFI_HII_PACKAGE_TYPE_ALL:
+ Matched = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // This active package list has the specified package type, list it.
+ //
+ if (Matched) {
+ ResultSize += sizeof (EFI_HII_HANDLE);
+ if (ResultSize <= *HandleBufferLength) {
+ *Result++ = Node->Handle;
+ }
+ }
+ Matched = FALSE;
+ }
+
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*HandleBufferLength < ResultSize) {
+ *HandleBufferLength = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *HandleBufferLength = ResultSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will export one or all package lists in the database to a buffer.
+ For each package list exported, this function will call functions registered
+ with EXPORT_PACK and then copy the package list to the buffer.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HII database to export or NULL
+ to indicate all package lists should be exported.
+ @param BufferSize On input, a pointer to the length of the buffer.
+ On output, the length of the buffer that is
+ required for the exported data.
+ @param Buffer A pointer to a buffer that will contain the
+ results of the export function.
+
+ @retval EFI_SUCCESS Package exported.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with a
+ value that will enable the data to fit.
+ @retval EFI_NOT_FOUND The specified Handle could not be found in the
+ current database.
+ @retval EFI_INVALID_PARAMETER BufferSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by BufferSize was not zero
+ and Buffer was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiExportPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ UINTN UsedSize;
+
+ if (This == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*BufferSize > 0 && Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Handle != NULL) && (!IsHiiHandleValid (Handle))) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ UsedSize = 0;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Handle == NULL) {
+ //
+ // Export all package lists in current hii database.
+ //
+ Status = ExportPackageList (
+ Private,
+ Node->Handle,
+ (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList),
+ &UsedSize,
+ *BufferSize,
+ (EFI_HII_PACKAGE_LIST_HEADER *)((UINT8 *) Buffer + UsedSize)
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else if (Handle != NULL && Node->Handle == Handle) {
+ Status = ExportPackageList (
+ Private,
+ Handle,
+ (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList),
+ &UsedSize,
+ *BufferSize,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (*BufferSize < UsedSize) {
+ *BufferSize = UsedSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Handle == NULL && UsedSize != 0) {
+ if (*BufferSize < UsedSize) {
+ *BufferSize = UsedSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function registers a function which will be called when specified actions related to packages of
+ the specified type occur in the HII database. By registering a function, other HII-related drivers are
+ notified when specific package types are added, removed or updated in the HII database.
+ Each driver or application which registers a notification should use
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before exiting.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to list
+ or EFI_HII_PACKAGE_TYPE_ALL for all packages to be
+ listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of
+ EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must
+ be NULL.
+ @param PackageNotifyFn Points to the function to be called when the event
+ specified by
+ NotificationType occurs.
+ @param NotifyType Describes the types of notification which this
+ function will be receiving.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification. Can be used in
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify()
+ to stop notifications.
+
+ @retval EFI_SUCCESS Notification registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+ @retval EFI_INVALID_PARAMETER NotifyHandle is NULL.
+ @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when PackageType is not
+ EFI_HII_PACKAGE_TYPE_GUID.
+ @retval EFI_INVALID_PARAMETER PackageGuid is NULL when PackageType is
+ EFI_HII_PACKAGE_TYPE_GUID.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRegisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN CONST EFI_HII_DATABASE_NOTIFY PackageNotifyFn,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ OUT EFI_HANDLE *NotifyHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_NOTIFY *Notify;
+ EFI_STATUS Status;
+
+ if (This == NULL || NotifyHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) ||
+ (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Allocate a notification node
+ //
+ Notify = (HII_DATABASE_NOTIFY *) AllocateZeroPool (sizeof (HII_DATABASE_NOTIFY));
+ if (Notify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Generate a notify handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Notify->NotifyHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fill in the information to the notification node
+ //
+ Notify->Signature = HII_DATABASE_NOTIFY_SIGNATURE;
+ Notify->PackageType = PackageType;
+ Notify->PackageGuid = (EFI_GUID *) PackageGuid;
+ Notify->PackageNotifyFn = (EFI_HII_DATABASE_NOTIFY) PackageNotifyFn;
+ Notify->NotifyType = NotifyType;
+
+ InsertTailList (&Private->DatabaseNotifyList, &Notify->DatabaseNotifyEntry);
+ *NotifyHandle = Notify->NotifyHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Removes the specified HII database package-related notification.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param NotificationHandle The handle of the notification function being
+ unregistered.
+
+ @retval EFI_SUCCESS Notification is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The Handle is invalid.
+ @retval EFI_NOT_FOUND The incoming notification handle does not exist
+ in current hii database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUnregisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_NOTIFY *Notify;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NotificationHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = gBS->OpenProtocol (
+ NotificationHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ for (Link = Private->DatabaseNotifyList.ForwardLink; Link != &Private->DatabaseNotifyList; Link = Link->ForwardLink) {
+ Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE);
+ if (Notify->NotifyHandle == NotificationHandle) {
+ //
+ // Remove the matching notification node
+ //
+ RemoveEntryList (&Notify->DatabaseNotifyEntry);
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Notify->NotifyHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Notify);
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This routine retrieves an array of GUID values for each keyboard layout that
+ was previously registered in the system.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuidBufferLength On input, a pointer to the length of the keyboard
+ GUID buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param KeyGuidBuffer An array of keyboard layout GUID instances
+ returned.
+
+ @retval EFI_SUCCESS KeyGuidBuffer was updated successfully.
+ @retval EFI_BUFFER_TOO_SMALL The KeyGuidBufferLength parameter indicates
+ that KeyGuidBuffer is too small to support the
+ number of GUIDs. KeyGuidBufferLength is
+ updated with a value that will enable the data to
+ fit.
+ @retval EFI_INVALID_PARAMETER The KeyGuidBufferLength is NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by KeyGuidBufferLength is not
+ zero and KeyGuidBuffer is NULL.
+ @retval EFI_NOT_FOUND There was no keyboard layout.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiFindKeyboardLayouts (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN OUT UINT16 *KeyGuidBufferLength,
+ OUT EFI_GUID *KeyGuidBuffer
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ UINT16 ResultSize;
+ UINTN Index;
+ UINT16 LayoutCount;
+ UINT16 LayoutLength;
+ UINT8 *Layout;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+
+ if (This == NULL || KeyGuidBufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*KeyGuidBufferLength > 0 && KeyGuidBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ResultSize = 0;
+
+ //
+ // Search all package lists in whole database to retrieve keyboard layout.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = Node->PackageList;
+ for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink;
+ Link1 != &PackageList->KeyboardLayoutHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ //
+ // Find out all Keyboard Layout packages in this package list.
+ //
+ Package = CR (
+ Link1,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+ Layout = (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16);
+ CopyMem (
+ &LayoutCount,
+ (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < LayoutCount; Index++) {
+ ResultSize += sizeof (EFI_GUID);
+ if (ResultSize <= *KeyGuidBufferLength) {
+ CopyMem (KeyGuidBuffer + (ResultSize / sizeof (EFI_GUID) - 1), Layout + sizeof (UINT16), sizeof (EFI_GUID));
+ CopyMem (&LayoutLength, Layout, sizeof (UINT16));
+ Layout = Layout + LayoutLength;
+ }
+ }
+ }
+ }
+
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*KeyGuidBufferLength < ResultSize) {
+ *KeyGuidBufferLength = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *KeyGuidBufferLength = ResultSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This routine retrieves the requested keyboard layout. The layout is a physical description of the keys
+ on a keyboard and the character(s) that are associated with a particular set of key strokes.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a given
+ keyboard layout. If KeyGuid is NULL then the
+ current layout will be retrieved.
+ @param KeyboardLayoutLength On input, a pointer to the length of the
+ KeyboardLayout buffer. On output, the length of
+ the data placed into KeyboardLayout.
+ @param KeyboardLayout A pointer to a buffer containing the retrieved
+ keyboard layout.
+
+ @retval EFI_SUCCESS The keyboard layout was retrieved successfully.
+ @retval EFI_NOT_FOUND The requested keyboard layout was not found.
+ @retval EFI_INVALID_PARAMETER The KeyboardLayout or KeyboardLayoutLength was
+ NULL.
+ @retval EFI_BUFFER_TOO_SMALL The KeyboardLayoutLength parameter indicates
+ that KeyboardLayout is too small to support the
+ requested keyboard layout. KeyboardLayoutLength is
+ updated with a value that will enable the
+ data to fit.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid,
+ IN OUT UINT16 *KeyboardLayoutLength,
+ OUT EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ UINTN Index;
+ UINT8 *Layout;
+ UINT16 LayoutCount;
+ UINT16 LayoutLength;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+
+ if (This == NULL || KeyboardLayoutLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*KeyboardLayoutLength > 0 && KeyboardLayout == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ //
+ // Retrieve the current keyboard layout.
+ //
+ if (KeyGuid == NULL) {
+ if (Private->CurrentLayout == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ CopyMem (&LayoutLength, Private->CurrentLayout, sizeof (UINT16));
+ if (*KeyboardLayoutLength < LayoutLength) {
+ *KeyboardLayoutLength = LayoutLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (KeyboardLayout, Private->CurrentLayout, LayoutLength);
+ return EFI_SUCCESS;
+ }
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink;
+ Link1 != &PackageList->KeyboardLayoutHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ Package = CR (
+ Link1,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+
+ Layout = (UINT8 *) Package->KeyboardPkg +
+ sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16);
+ CopyMem (&LayoutCount, Layout - sizeof (UINT16), sizeof (UINT16));
+ for (Index = 0; Index < LayoutCount; Index++) {
+ CopyMem (&LayoutLength, Layout, sizeof (UINT16));
+ if (CompareMem (Layout + sizeof (UINT16), KeyGuid, sizeof (EFI_GUID)) == 0) {
+ if (LayoutLength <= *KeyboardLayoutLength) {
+ CopyMem (KeyboardLayout, Layout, LayoutLength);
+ return EFI_SUCCESS;
+ } else {
+ *KeyboardLayoutLength = LayoutLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+ Layout = Layout + LayoutLength;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This routine sets the default keyboard layout to the one referenced by KeyGuid. When this routine
+ is called, an event will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+ group type. This is so that agents which are sensitive to the current keyboard layout being changed
+ can be notified of this change.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a given
+ keyboard layout.
+
+ @retval EFI_SUCCESS The current keyboard layout was successfully set.
+ @retval EFI_NOT_FOUND The referenced keyboard layout was not found, so
+ action was taken.
+ @retval EFI_INVALID_PARAMETER The KeyGuid was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout;
+ UINT16 KeyboardLayoutLength;
+ EFI_STATUS Status;
+
+ if (This == NULL || KeyGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // The specified GUID equals the current keyboard layout GUID,
+ // return directly.
+ //
+ if (CompareGuid (&Private->CurrentLayoutGuid, KeyGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Try to find the incoming keyboard layout data in current database.
+ //
+ KeyboardLayoutLength = 0;
+ KeyboardLayout = NULL;
+ Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ KeyboardLayout = (EFI_HII_KEYBOARD_LAYOUT *) AllocateZeroPool (KeyboardLayoutLength);
+ ASSERT (KeyboardLayout != NULL);
+ Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Backup current keyboard layout.
+ //
+ CopyMem (&Private->CurrentLayoutGuid, KeyGuid, sizeof (EFI_GUID));
+ if (Private->CurrentLayout != NULL) {
+ FreePool(Private->CurrentLayout);
+ }
+ Private->CurrentLayout = KeyboardLayout;
+
+ //
+ // Signal EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group to notify
+ // current keyboard layout is changed.
+ //
+ Status = gBS->SignalEvent (gHiiKeyboardLayoutChanged);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the EFI handle associated with a package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageListHandle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HIIdatabase.
+ @param DriverHandle On return, contains the EFI_HANDLE which was
+ registered with the package list in
+ NewPackageList().
+
+ @retval EFI_SUCCESS The DriverHandle was returned successfully.
+ @retval EFI_INVALID_PARAMETER The PackageListHandle was not valid or
+ DriverHandle was NULL.
+ @retval EFI_NOT_FOUND This PackageList handle can not be found in
+ current database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetPackageListHandle (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageListHandle,
+ OUT EFI_HANDLE *DriverHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+
+ if (This == NULL || DriverHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageListHandle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == PackageListHandle) {
+ *DriverHandle = Node->DriverHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c
new file mode 100644
index 000000000..ee6c65287
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c
@@ -0,0 +1,2904 @@
+/** @file
+Implementation for EFI_HII_FONT_PROTOCOL.
+
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL mHiiEfiColors[16] = {
+ //
+ // B G R
+ //
+ {0x00, 0x00, 0x00, 0x00}, // BLACK
+ {0x98, 0x00, 0x00, 0x00}, // BLUE
+ {0x00, 0x98, 0x00, 0x00}, // GREEN
+ {0x98, 0x98, 0x00, 0x00}, // CYAN
+ {0x00, 0x00, 0x98, 0x00}, // RED
+ {0x98, 0x00, 0x98, 0x00}, // MAGENTA
+ {0x00, 0x98, 0x98, 0x00}, // BROWN
+ {0x98, 0x98, 0x98, 0x00}, // LIGHTGRAY
+ {0x30, 0x30, 0x30, 0x00}, // DARKGRAY - BRIGHT BLACK
+ {0xff, 0x00, 0x00, 0x00}, // LIGHTBLUE
+ {0x00, 0xff, 0x00, 0x00}, // LIGHTGREEN
+ {0xff, 0xff, 0x00, 0x00}, // LIGHTCYAN
+ {0x00, 0x00, 0xff, 0x00}, // LIGHTRED
+ {0xff, 0x00, 0xff, 0x00}, // LIGHTMAGENTA
+ {0x00, 0xff, 0xff, 0x00}, // YELLOW
+ {0xff, 0xff, 0xff, 0x00}, // WHITE
+};
+
+
+/**
+ Insert a character cell information to the list specified by GlyphInfoList.
+
+ This is a internal function.
+
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphInfoList HII_GLYPH_INFO list head.
+ @param Cell Incoming character cell information.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+NewCell (
+ IN CHAR16 CharValue,
+ IN LIST_ENTRY *GlyphInfoList,
+ IN EFI_HII_GLYPH_INFO *Cell
+ )
+{
+ HII_GLYPH_INFO *GlyphInfo;
+
+ ASSERT (Cell != NULL && GlyphInfoList != NULL);
+
+ GlyphInfo = (HII_GLYPH_INFO *) AllocateZeroPool (sizeof (HII_GLYPH_INFO));
+ if (GlyphInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // GlyphInfoList stores a list of default character cell information, each is
+ // identified by "CharId".
+ //
+ GlyphInfo->Signature = HII_GLYPH_INFO_SIGNATURE;
+ GlyphInfo->CharId = CharValue;
+ if (Cell->AdvanceX == 0) {
+ Cell->AdvanceX = Cell->Width;
+ }
+ CopyMem (&GlyphInfo->Cell, Cell, sizeof (EFI_HII_GLYPH_INFO));
+ InsertTailList (GlyphInfoList, &GlyphInfo->Entry);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get a character cell information from the list specified by GlyphInfoList.
+
+ This is a internal function.
+
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphInfoList HII_GLYPH_INFO list head.
+ @param Cell Buffer which stores output character cell
+ information.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_NOT_FOUND The character info specified by CharValue does
+ not exist.
+
+**/
+EFI_STATUS
+GetCell (
+ IN CHAR16 CharValue,
+ IN LIST_ENTRY *GlyphInfoList,
+ OUT EFI_HII_GLYPH_INFO *Cell
+ )
+{
+ HII_GLYPH_INFO *GlyphInfo;
+ LIST_ENTRY *Link;
+
+ ASSERT (Cell != NULL && GlyphInfoList != NULL);
+
+ //
+ // Since the EFI_HII_GIBT_DEFAULTS block won't increment CharValueCurrent,
+ // the value of "CharId" of a default character cell which is used for a
+ // EFI_HII_GIBT_GLYPH_DEFAULT or EFI_HII_GIBT_GLYPHS_DEFAULT should be
+ // less or equal to the value of "CharValueCurrent" of this default block.
+ //
+ // For instance, if the CharId of a GlyphInfoList is {1, 3, 7}, a default glyph
+ // with CharValue equals "7" uses the GlyphInfo with CharId = 7;
+ // a default glyph with CharValue equals "6" uses the GlyphInfo with CharId = 3.
+ //
+ for (Link = GlyphInfoList->BackLink; Link != GlyphInfoList; Link = Link->BackLink) {
+ GlyphInfo = CR (Link, HII_GLYPH_INFO, Entry, HII_GLYPH_INFO_SIGNATURE);
+ if (GlyphInfo->CharId <= CharValue) {
+ CopyMem (Cell, &GlyphInfo->Cell, sizeof (EFI_HII_GLYPH_INFO));
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Convert the glyph for a single character into a bitmap.
+
+ This is a internal function.
+
+ @param Private HII database driver private data.
+ @param Char Character to retrieve.
+ @param StringInfo Points to the string font and color information
+ or NULL if the string should use the default
+ system font and color.
+ @param GlyphBuffer Buffer to store the retrieved bitmap data.
+ @param Cell Points to EFI_HII_GLYPH_INFO structure.
+ @param Attributes If not NULL, output the glyph attributes if any.
+
+ @retval EFI_SUCCESS Glyph bitmap outputted.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer GlyphBuffer.
+ @retval EFI_NOT_FOUND The glyph was unknown can not be found.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+GetGlyphBuffer (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN CHAR16 Char,
+ IN EFI_FONT_INFO *StringInfo,
+ OUT UINT8 **GlyphBuffer,
+ OUT EFI_HII_GLYPH_INFO *Cell,
+ OUT UINT8 *Attributes OPTIONAL
+ )
+{
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFont;
+ LIST_ENTRY *Link1;
+ UINT16 Index;
+ EFI_NARROW_GLYPH Narrow;
+ EFI_WIDE_GLYPH Wide;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ UINTN HeaderSize;
+ EFI_NARROW_GLYPH *NarrowPtr;
+ EFI_WIDE_GLYPH *WidePtr;
+
+ if (GlyphBuffer == NULL || Cell == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private == NULL || Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Cell, sizeof (EFI_HII_GLYPH_INFO));
+
+ //
+ // If StringInfo is not NULL, it must point to an existing EFI_FONT_INFO rather
+ // than system default font and color.
+ // If NULL, try to find the character in simplified font packages since
+ // default system font is the fixed font (narrow or wide glyph).
+ //
+ if (StringInfo != NULL) {
+ if(!IsFontInfoExisted (Private, StringInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Attributes != NULL) {
+ *Attributes = PROPORTIONAL_GLYPH;
+ }
+ return FindGlyphBlock (GlobalFont->FontPackage, Char, GlyphBuffer, Cell, NULL);
+ } else {
+ HeaderSize = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR);
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ for (Link1 = Node->PackageList->SimpleFontPkgHdr.ForwardLink;
+ Link1 != &Node->PackageList->SimpleFontPkgHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ SimpleFont = CR (Link1, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE);
+ //
+ // Search the narrow glyph array
+ //
+ NarrowPtr = (EFI_NARROW_GLYPH *) ((UINT8 *) (SimpleFont->SimpleFontPkgHdr) + HeaderSize);
+ for (Index = 0; Index < SimpleFont->SimpleFontPkgHdr->NumberOfNarrowGlyphs; Index++) {
+ CopyMem (&Narrow, NarrowPtr + Index,sizeof (EFI_NARROW_GLYPH));
+ if (Narrow.UnicodeWeight == Char) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (EFI_GLYPH_HEIGHT);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Cell->Width = EFI_GLYPH_WIDTH;
+ Cell->Height = EFI_GLYPH_HEIGHT;
+ Cell->AdvanceX = Cell->Width;
+ CopyMem (*GlyphBuffer, Narrow.GlyphCol1, Cell->Height);
+ if (Attributes != NULL) {
+ *Attributes = (UINT8) (Narrow.Attributes | NARROW_GLYPH);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Search the wide glyph array
+ //
+ WidePtr = (EFI_WIDE_GLYPH *) (NarrowPtr + SimpleFont->SimpleFontPkgHdr->NumberOfNarrowGlyphs);
+ for (Index = 0; Index < SimpleFont->SimpleFontPkgHdr->NumberOfWideGlyphs; Index++) {
+ CopyMem (&Wide, WidePtr + Index, sizeof (EFI_WIDE_GLYPH));
+ if (Wide.UnicodeWeight == Char) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (EFI_GLYPH_HEIGHT * 2);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Cell->Width = EFI_GLYPH_WIDTH * 2;
+ Cell->Height = EFI_GLYPH_HEIGHT;
+ Cell->AdvanceX = Cell->Width;
+ CopyMem (*GlyphBuffer, Wide.GlyphCol1, EFI_GLYPH_HEIGHT);
+ CopyMem (*GlyphBuffer + EFI_GLYPH_HEIGHT, Wide.GlyphCol2, EFI_GLYPH_HEIGHT);
+ if (Attributes != NULL) {
+ *Attributes = (UINT8) (Wide.Attributes | EFI_GLYPH_WIDE);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Convert bitmap data of the glyph to blt structure.
+
+ This is a internal function.
+
+ @param GlyphBuffer Buffer points to bitmap data of glyph.
+ @param Foreground The color of the "on" pixels in the glyph in the
+ bitmap.
+ @param Background The color of the "off" pixels in the glyph in the
+ bitmap.
+ @param ImageWidth Width of the whole image in pixels.
+ @param RowWidth The width of the text on the line, in pixels.
+ @param RowHeight The height of the line, in pixels.
+ @param Transparent If TRUE, the Background color is ignored and all
+ "off" pixels in the character's drawn will use the
+ pixel value from BltBuffer.
+ @param Origin On input, points to the origin of the to be
+ displayed character, on output, points to the
+ next glyph's origin.
+
+**/
+VOID
+NarrowGlyphToBlt (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINT16 ImageWidth,
+ IN UINTN RowWidth,
+ IN UINTN RowHeight,
+ IN BOOLEAN Transparent,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ UINT8 Xpos;
+ UINT8 Ypos;
+ UINT8 Height;
+ UINT8 Width;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Buffer;
+
+ ASSERT (GlyphBuffer != NULL && Origin != NULL && *Origin != NULL);
+
+ Height = EFI_GLYPH_HEIGHT;
+ Width = EFI_GLYPH_WIDTH;
+
+ //
+ // Move position to the left-top corner of char.
+ //
+ Buffer = *Origin - EFI_GLYPH_HEIGHT * ImageWidth;
+
+ //
+ // Char may be partially displayed when CLIP_X or CLIP_Y is not set.
+ //
+ if (RowHeight < Height) {
+ Height = (UINT8) RowHeight;
+ }
+ if (RowWidth < Width) {
+ Width = (UINT8) RowWidth;
+ }
+
+ for (Ypos = 0; Ypos < Height; Ypos++) {
+ for (Xpos = 0; Xpos < Width; Xpos++) {
+ if ((GlyphBuffer[Ypos] & (1 << (EFI_GLYPH_WIDTH - Xpos - 1))) != 0) {
+ Buffer[Ypos * ImageWidth + Xpos] = Foreground;
+ } else {
+ if (!Transparent) {
+ Buffer[Ypos * ImageWidth + Xpos] = Background;
+ }
+ }
+ }
+ }
+
+ *Origin = *Origin + EFI_GLYPH_WIDTH;
+}
+
+
+/**
+ Convert bitmap data of the glyph to blt structure.
+
+ This is a internal function.
+
+ @param GlyphBuffer Buffer points to bitmap data of glyph.
+ @param Foreground The color of the "on" pixels in the glyph in the
+ bitmap.
+ @param Background The color of the "off" pixels in the glyph in the
+ bitmap.
+ @param ImageWidth Width of the whole image in pixels.
+ @param BaseLine BaseLine in the line.
+ @param RowWidth The width of the text on the line, in pixels.
+ @param RowHeight The height of the line, in pixels.
+ @param Transparent If TRUE, the Background color is ignored and all
+ "off" pixels in the character's drawn will use the
+ pixel value from BltBuffer.
+ @param Cell Points to EFI_HII_GLYPH_INFO structure.
+ @param Attributes The attribute of incoming glyph in GlyphBuffer.
+ @param Origin On input, points to the origin of the to be
+ displayed character, on output, points to the
+ next glyph's origin.
+
+
+**/
+VOID
+GlyphToBlt (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINT16 ImageWidth,
+ IN UINT16 BaseLine,
+ IN UINTN RowWidth,
+ IN UINTN RowHeight,
+ IN BOOLEAN Transparent,
+ IN CONST EFI_HII_GLYPH_INFO *Cell,
+ IN UINT8 Attributes,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ UINT16 Xpos;
+ UINT16 Ypos;
+ UINT8 Data;
+ UINT16 Index;
+ UINT16 YposOffset;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+
+ ASSERT (Origin != NULL && *Origin != NULL && Cell != NULL);
+
+ //
+ // Only adjust origin position if char has no bitmap.
+ //
+ if (GlyphBuffer == NULL) {
+ *Origin = *Origin + Cell->AdvanceX;
+ return;
+ }
+ //
+ // Move position to the left-top corner of char.
+ //
+ BltBuffer = *Origin + Cell->OffsetX - (Cell->OffsetY + Cell->Height) * ImageWidth;
+ YposOffset = (UINT16) (BaseLine - (Cell->OffsetY + Cell->Height));
+
+ //
+ // Since non-spacing key will be printed OR'd with the previous glyph, don't
+ // write 0.
+ //
+ if ((Attributes & EFI_GLYPH_NON_SPACING) == EFI_GLYPH_NON_SPACING) {
+ Transparent = TRUE;
+ }
+
+ //
+ // The glyph's upper left hand corner pixel is the most significant bit of the
+ // first bitmap byte.
+ //
+ for (Ypos = 0; Ypos < Cell->Height && (((UINT32) Ypos + YposOffset) < RowHeight); Ypos++) {
+ OffsetY = BITMAP_LEN_1_BIT (Cell->Width, Ypos);
+
+ //
+ // All bits in these bytes are meaningful.
+ //
+ for (Xpos = 0; Xpos < Cell->Width / 8; Xpos++) {
+ Data = *(GlyphBuffer + OffsetY + Xpos);
+ for (Index = 0; Index < 8 && (((UINT32) Xpos * 8 + Index + Cell->OffsetX) < RowWidth); Index++) {
+ if ((Data & (1 << (8 - Index - 1))) != 0) {
+ BltBuffer[Ypos * ImageWidth + Xpos * 8 + Index] = Foreground;
+ } else {
+ if (!Transparent) {
+ BltBuffer[Ypos * ImageWidth + Xpos * 8 + Index] = Background;
+ }
+ }
+ }
+ }
+
+ if (Cell->Width % 8 != 0) {
+ //
+ // There are some padding bits in this byte. Ignore them.
+ //
+ Data = *(GlyphBuffer + OffsetY + Xpos);
+ for (Index = 0; Index < Cell->Width % 8 && (((UINT32) Xpos * 8 + Index + Cell->OffsetX) < RowWidth); Index++) {
+ if ((Data & (1 << (8 - Index - 1))) != 0) {
+ BltBuffer[Ypos * ImageWidth + Xpos * 8 + Index] = Foreground;
+ } else {
+ if (!Transparent) {
+ BltBuffer[Ypos * ImageWidth + Xpos * 8 + Index] = Background;
+ }
+ }
+ }
+ } // end of if (Width % 8...)
+
+ } // end of for (Ypos=0...)
+
+ *Origin = *Origin + Cell->AdvanceX;
+}
+
+
+/**
+ Convert bitmap data of the glyph to blt structure.
+
+ This is a internal function.
+
+ @param GlyphBuffer Buffer points to bitmap data of glyph.
+ @param Foreground The color of the "on" pixels in the glyph in the
+ bitmap.
+ @param Background The color of the "off" pixels in the glyph in the
+ bitmap.
+ @param ImageWidth Width of the whole image in pixels.
+ @param BaseLine BaseLine in the line.
+ @param RowWidth The width of the text on the line, in pixels.
+ @param RowHeight The height of the line, in pixels.
+ @param Transparent If TRUE, the Background color is ignored and all
+ "off" pixels in the character's drawn will use the
+ pixel value from BltBuffer.
+ @param Cell Points to EFI_HII_GLYPH_INFO structure.
+ @param Attributes The attribute of incoming glyph in GlyphBuffer.
+ @param Origin On input, points to the origin of the to be
+ displayed character, on output, points to the
+ next glyph's origin.
+
+ @return Points to the address of next origin node in BltBuffer.
+
+**/
+VOID
+GlyphToImage (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINT16 ImageWidth,
+ IN UINT16 BaseLine,
+ IN UINTN RowWidth,
+ IN UINTN RowHeight,
+ IN BOOLEAN Transparent,
+ IN CONST EFI_HII_GLYPH_INFO *Cell,
+ IN UINT8 Attributes,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Buffer;
+
+ ASSERT (Origin != NULL && *Origin != NULL && Cell != NULL);
+
+ Buffer = *Origin;
+
+ if ((Attributes & EFI_GLYPH_NON_SPACING) == EFI_GLYPH_NON_SPACING) {
+ //
+ // This character is a non-spacing key, print it OR'd with the previous glyph.
+ // without advancing cursor.
+ //
+ Buffer -= Cell->AdvanceX;
+ GlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ BaseLine,
+ RowWidth,
+ RowHeight,
+ Transparent,
+ Cell,
+ Attributes,
+ &Buffer
+ );
+
+ } else if ((Attributes & EFI_GLYPH_WIDE) == EFI_GLYPH_WIDE) {
+ //
+ // This character is wide glyph, i.e. 16 pixels * 19 pixels.
+ // Draw it as two narrow glyphs.
+ //
+ NarrowGlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ RowWidth,
+ RowHeight,
+ Transparent,
+ Origin
+ );
+
+ NarrowGlyphToBlt (
+ GlyphBuffer + EFI_GLYPH_HEIGHT,
+ Foreground,
+ Background,
+ ImageWidth,
+ RowWidth,
+ RowHeight,
+ Transparent,
+ Origin
+ );
+
+ } else if ((Attributes & NARROW_GLYPH) == NARROW_GLYPH) {
+ //
+ // This character is narrow glyph, i.e. 8 pixels * 19 pixels.
+ //
+ NarrowGlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ RowWidth,
+ RowHeight,
+ Transparent,
+ Origin
+ );
+
+ } else if ((Attributes & PROPORTIONAL_GLYPH) == PROPORTIONAL_GLYPH) {
+ //
+ // This character is proportional glyph, i.e. Cell->Width * Cell->Height pixels.
+ //
+ GlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ BaseLine,
+ RowWidth,
+ RowHeight,
+ Transparent,
+ Cell,
+ Attributes,
+ Origin
+ );
+ }
+}
+
+
+/**
+ Write the output parameters of FindGlyphBlock().
+
+ This is a internal function.
+
+ @param BufferIn Buffer which stores the bitmap data of the found
+ block.
+ @param BufferLen Length of BufferIn.
+ @param InputCell Buffer which stores cell information of the
+ encoded bitmap.
+ @param GlyphBuffer Output the corresponding bitmap data of the found
+ block. It is the caller's responsibility to free
+ this buffer.
+ @param Cell Output cell information of the encoded bitmap.
+ @param GlyphBufferLen If not NULL, output the length of GlyphBuffer.
+
+ @retval EFI_SUCCESS The operation is performed successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+WriteOutputParam (
+ IN UINT8 *BufferIn,
+ IN UINTN BufferLen,
+ IN EFI_HII_GLYPH_INFO *InputCell,
+ OUT UINT8 **GlyphBuffer, OPTIONAL
+ OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL
+ OUT UINTN *GlyphBufferLen OPTIONAL
+ )
+{
+ if (BufferIn == NULL || InputCell == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Cell != NULL) {
+ CopyMem (Cell, InputCell, sizeof (EFI_HII_GLYPH_INFO));
+ }
+
+ if (GlyphBuffer != NULL && BufferLen > 0) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (BufferLen);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (*GlyphBuffer, BufferIn, BufferLen);
+ }
+
+ if (GlyphBufferLen != NULL) {
+ *GlyphBufferLen = BufferLen;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Parse all glyph blocks to find a glyph block specified by CharValue.
+ If CharValue = (CHAR16) (-1), collect all default character cell information
+ within this font package and backup its information.
+
+ @param FontPackage Hii string package instance.
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphBuffer Output the corresponding bitmap data of the found
+ block. It is the caller's responsibility to free
+ this buffer.
+ @param Cell Output cell information of the encoded bitmap.
+ @param GlyphBufferLen If not NULL, output the length of GlyphBuffer.
+
+ @retval EFI_SUCCESS The bitmap data is retrieved successfully.
+ @retval EFI_NOT_FOUND The specified CharValue does not exist in current
+ database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindGlyphBlock (
+ IN HII_FONT_PACKAGE_INSTANCE *FontPackage,
+ IN CHAR16 CharValue,
+ OUT UINT8 **GlyphBuffer, OPTIONAL
+ OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL
+ OUT UINTN *GlyphBufferLen OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *BlockPtr;
+ UINT16 CharCurrent;
+ UINT16 Length16;
+ UINT32 Length32;
+ EFI_HII_GIBT_GLYPHS_BLOCK Glyphs;
+ UINTN BufferLen;
+ UINT16 Index;
+ EFI_HII_GLYPH_INFO DefaultCell;
+ EFI_HII_GLYPH_INFO LocalCell;
+ INT16 MinOffsetY;
+ UINT16 BaseLine;
+
+ ASSERT (FontPackage != NULL);
+ ASSERT (FontPackage->Signature == HII_FONT_PACKAGE_SIGNATURE);
+ BaseLine = 0;
+ MinOffsetY = 0;
+
+ if (CharValue == (CHAR16) (-1)) {
+ //
+ // Collect the cell information specified in font package fixed header.
+ // Use CharValue =0 to represent this particular cell.
+ //
+ Status = NewCell (
+ 0,
+ &FontPackage->GlyphInfoList,
+ (EFI_HII_GLYPH_INFO *) ((UINT8 *) FontPackage->FontPkgHdr + 3 * sizeof (UINT32))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (
+ &LocalCell,
+ (UINT8 *) FontPackage->FontPkgHdr + 3 * sizeof (UINT32),
+ sizeof (EFI_HII_GLYPH_INFO)
+ );
+ }
+
+ BlockPtr = FontPackage->GlyphBlock;
+ CharCurrent = 1;
+ BufferLen = 0;
+
+ while (*BlockPtr != EFI_HII_GIBT_END) {
+ switch (*BlockPtr) {
+ case EFI_HII_GIBT_DEFAULTS:
+ //
+ // Collect all default character cell information specified by
+ // EFI_HII_GIBT_DEFAULTS.
+ //
+ if (CharValue == (CHAR16) (-1)) {
+ Status = NewCell (
+ CharCurrent,
+ &FontPackage->GlyphInfoList,
+ (EFI_HII_GLYPH_INFO *) (BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (
+ &LocalCell,
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK),
+ sizeof (EFI_HII_GLYPH_INFO)
+ );
+ if (BaseLine < LocalCell.Height + LocalCell.OffsetY) {
+ BaseLine = (UINT16) (LocalCell.Height + LocalCell.OffsetY);
+ }
+ if (MinOffsetY > LocalCell.OffsetY) {
+ MinOffsetY = LocalCell.OffsetY;
+ }
+ }
+ BlockPtr += sizeof (EFI_HII_GIBT_DEFAULTS_BLOCK);
+ break;
+
+ case EFI_HII_GIBT_DUPLICATE:
+ if (CharCurrent == CharValue) {
+ CopyMem (&CharValue, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (CHAR16));
+ CharCurrent = 1;
+ BlockPtr = FontPackage->GlyphBlock;
+ continue;
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GIBT_DUPLICATE_BLOCK);
+ break;
+
+ case EFI_HII_GIBT_EXT1:
+ BlockPtr += *(UINT8*)((UINTN)BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8));
+ break;
+ case EFI_HII_GIBT_EXT2:
+ CopyMem (
+ &Length16,
+ (UINT8*)((UINTN)BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ BlockPtr += Length16;
+ break;
+ case EFI_HII_GIBT_EXT4:
+ CopyMem (
+ &Length32,
+ (UINT8*)((UINTN)BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT32)
+ );
+ BlockPtr += Length32;
+ break;
+
+ case EFI_HII_GIBT_GLYPH:
+ CopyMem (
+ &LocalCell,
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK),
+ sizeof (EFI_HII_GLYPH_INFO)
+ );
+ if (CharValue == (CHAR16) (-1)) {
+ if (BaseLine < LocalCell.Height + LocalCell.OffsetY) {
+ BaseLine = (UINT16) (LocalCell.Height + LocalCell.OffsetY);
+ }
+ if (MinOffsetY > LocalCell.OffsetY) {
+ MinOffsetY = LocalCell.OffsetY;
+ }
+ }
+ BufferLen = BITMAP_LEN_1_BIT (LocalCell.Width, LocalCell.Height);
+ if (CharCurrent == CharValue) {
+ return WriteOutputParam (
+ (UINT8*)((UINTN)BlockPtr + sizeof (EFI_HII_GIBT_GLYPH_BLOCK) - sizeof (UINT8)),
+ BufferLen,
+ &LocalCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GIBT_GLYPH_BLOCK) - sizeof (UINT8) + BufferLen;
+ break;
+
+ case EFI_HII_GIBT_GLYPHS:
+ BlockPtr += sizeof (EFI_HII_GLYPH_BLOCK);
+ CopyMem (&Glyphs.Cell, BlockPtr, sizeof (EFI_HII_GLYPH_INFO));
+ BlockPtr += sizeof (EFI_HII_GLYPH_INFO);
+ CopyMem (&Glyphs.Count, BlockPtr, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+
+ if (CharValue == (CHAR16) (-1)) {
+ if (BaseLine < Glyphs.Cell.Height + Glyphs.Cell.OffsetY) {
+ BaseLine = (UINT16) (Glyphs.Cell.Height + Glyphs.Cell.OffsetY);
+ }
+ if (MinOffsetY > Glyphs.Cell.OffsetY) {
+ MinOffsetY = Glyphs.Cell.OffsetY;
+ }
+ }
+
+ BufferLen = BITMAP_LEN_1_BIT (Glyphs.Cell.Width, Glyphs.Cell.Height);
+ for (Index = 0; Index < Glyphs.Count; Index++) {
+ if (CharCurrent + Index == CharValue) {
+ return WriteOutputParam (
+ BlockPtr,
+ BufferLen,
+ &Glyphs.Cell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ BlockPtr += BufferLen;
+ }
+ CharCurrent = (UINT16) (CharCurrent + Glyphs.Count);
+ break;
+
+ case EFI_HII_GIBT_GLYPH_DEFAULT:
+ Status = GetCell (CharCurrent, &FontPackage->GlyphInfoList, &DefaultCell);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CharValue == (CHAR16) (-1)) {
+ if (BaseLine < DefaultCell.Height + DefaultCell.OffsetY) {
+ BaseLine = (UINT16) (DefaultCell.Height + DefaultCell.OffsetY);
+ }
+ if (MinOffsetY > DefaultCell.OffsetY) {
+ MinOffsetY = DefaultCell.OffsetY;
+ }
+ }
+ BufferLen = BITMAP_LEN_1_BIT (DefaultCell.Width, DefaultCell.Height);
+
+ if (CharCurrent == CharValue) {
+ return WriteOutputParam (
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK),
+ BufferLen,
+ &DefaultCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GLYPH_BLOCK) + BufferLen;
+ break;
+
+ case EFI_HII_GIBT_GLYPHS_DEFAULT:
+ CopyMem (&Length16, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (UINT16));
+ Status = GetCell (CharCurrent, &FontPackage->GlyphInfoList, &DefaultCell);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CharValue == (CHAR16) (-1)) {
+ if (BaseLine < DefaultCell.Height + DefaultCell.OffsetY) {
+ BaseLine = (UINT16) (DefaultCell.Height + DefaultCell.OffsetY);
+ }
+ if (MinOffsetY > DefaultCell.OffsetY) {
+ MinOffsetY = DefaultCell.OffsetY;
+ }
+ }
+ BufferLen = BITMAP_LEN_1_BIT (DefaultCell.Width, DefaultCell.Height);
+ BlockPtr += sizeof (EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK) - sizeof (UINT8);
+ for (Index = 0; Index < Length16; Index++) {
+ if (CharCurrent + Index == CharValue) {
+ return WriteOutputParam (
+ BlockPtr,
+ BufferLen,
+ &DefaultCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ BlockPtr += BufferLen;
+ }
+ CharCurrent = (UINT16) (CharCurrent + Length16);
+ break;
+
+ case EFI_HII_GIBT_SKIP1:
+ CharCurrent = (UINT16) (CharCurrent + (UINT16) (*(BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK))));
+ BlockPtr += sizeof (EFI_HII_GIBT_SKIP1_BLOCK);
+ break;
+ case EFI_HII_GIBT_SKIP2:
+ CopyMem (&Length16, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (UINT16));
+ CharCurrent = (UINT16) (CharCurrent + Length16);
+ BlockPtr += sizeof (EFI_HII_GIBT_SKIP2_BLOCK);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ if (CharValue < CharCurrent) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (CharValue == (CHAR16) (-1)) {
+ FontPackage->BaseLine = BaseLine;
+ FontPackage->Height = (UINT16) (BaseLine - MinOffsetY);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Copy a Font Name to a new created EFI_FONT_INFO structure.
+
+ This is a internal function.
+
+ @param FontName NULL-terminated string.
+ @param FontInfo a new EFI_FONT_INFO which stores the FontName.
+ It's caller's responsibility to free this buffer.
+
+ @retval EFI_SUCCESS FontInfo is allocated and copied with FontName.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+SaveFontName (
+ IN EFI_STRING FontName,
+ OUT EFI_FONT_INFO **FontInfo
+ )
+{
+ UINTN FontInfoLen;
+ UINTN NameSize;
+
+ ASSERT (FontName != NULL && FontInfo != NULL);
+
+ NameSize = StrSize (FontName);
+ FontInfoLen = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + NameSize;
+ *FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoLen);
+ if (*FontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StrCpyS ((*FontInfo)->FontName, NameSize / sizeof (CHAR16), FontName);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve system default font and color.
+
+ @param Private HII database driver private data.
+ @param FontInfo Points to system default font output-related
+ information. It's caller's responsibility to free
+ this buffer.
+ @param FontInfoSize If not NULL, output the size of buffer FontInfo.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+GetSystemFont (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ OUT EFI_FONT_DISPLAY_INFO **FontInfo,
+ OUT UINTN *FontInfoSize OPTIONAL
+ )
+{
+ EFI_FONT_DISPLAY_INFO *Info;
+ UINTN InfoSize;
+ UINTN NameSize;
+
+ if (Private == NULL || Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FontInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The standard font always has the name "sysdefault".
+ //
+ NameSize = StrSize (L"sysdefault");
+ InfoSize = sizeof (EFI_FONT_DISPLAY_INFO) - sizeof (CHAR16) + NameSize;
+ Info = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Info->ForegroundColor = mHiiEfiColors[Private->Attribute & 0x0f];
+ ASSERT ((Private->Attribute >> 4) < 8);
+ Info->BackgroundColor = mHiiEfiColors[Private->Attribute >> 4];
+ Info->FontInfoMask = EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_SYS_STYLE;
+ Info->FontInfo.FontStyle = 0;
+ Info->FontInfo.FontSize = EFI_GLYPH_HEIGHT;
+ StrCpyS (Info->FontInfo.FontName, NameSize / sizeof (CHAR16), L"sysdefault");
+
+ *FontInfo = Info;
+ if (FontInfoSize != NULL) {
+ *FontInfoSize = InfoSize;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether EFI_FONT_DISPLAY_INFO points to system default font and color or
+ returns the system default according to the optional inputs.
+
+ This is a internal function.
+
+ @param Private HII database driver private data.
+ @param StringInfo Points to the string output information,
+ including the color and font.
+ @param SystemInfo If not NULL, points to system default font and color.
+
+ @param SystemInfoLen If not NULL, output the length of default system
+ info.
+
+ @retval TRUE Yes, it points to system default.
+ @retval FALSE No.
+
+**/
+BOOLEAN
+IsSystemFontInfo (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_FONT_DISPLAY_INFO *StringInfo,
+ OUT EFI_FONT_DISPLAY_INFO **SystemInfo, OPTIONAL
+ OUT UINTN *SystemInfoLen OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ UINTN DefaultLen;
+ BOOLEAN Flag;
+
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+
+ if (StringInfo == NULL && SystemInfo == NULL) {
+ return TRUE;
+ }
+
+ SystemDefault = NULL;
+ DefaultLen = 0;
+
+ Status = GetSystemFont (Private, &SystemDefault, &DefaultLen);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT ((SystemDefault != NULL) && (DefaultLen != 0));
+
+ //
+ // Record the system default info.
+ //
+ if (SystemInfo != NULL) {
+ *SystemInfo = SystemDefault;
+ }
+
+ if (SystemInfoLen != NULL) {
+ *SystemInfoLen = DefaultLen;
+ }
+
+ if (StringInfo == NULL) {
+ return TRUE;
+ }
+
+ Flag = FALSE;
+ //
+ // Check the FontInfoMask to see whether it is retrieving system info.
+ //
+ if ((StringInfo->FontInfoMask & (EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_ANY_FONT)) == 0) {
+ if (StrCmp (StringInfo->FontInfo.FontName, SystemDefault->FontInfo.FontName) != 0) {
+ goto Exit;
+ }
+ }
+ if ((StringInfo->FontInfoMask & (EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_ANY_SIZE)) == 0) {
+ if (StringInfo->FontInfo.FontSize != SystemDefault->FontInfo.FontSize) {
+ goto Exit;
+ }
+ }
+ if ((StringInfo->FontInfoMask & (EFI_FONT_INFO_SYS_STYLE | EFI_FONT_INFO_ANY_STYLE)) == 0) {
+ if (StringInfo->FontInfo.FontStyle != SystemDefault->FontInfo.FontStyle) {
+ goto Exit;
+ }
+ }
+ if ((StringInfo->FontInfoMask & EFI_FONT_INFO_SYS_FORE_COLOR) == 0) {
+ if (CompareMem (
+ &StringInfo->ForegroundColor,
+ &SystemDefault->ForegroundColor,
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ ) != 0) {
+ goto Exit;
+ }
+ }
+ if ((StringInfo->FontInfoMask & EFI_FONT_INFO_SYS_BACK_COLOR) == 0) {
+ if (CompareMem (
+ &StringInfo->BackgroundColor,
+ &SystemDefault->BackgroundColor,
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ ) != 0) {
+ goto Exit;
+ }
+ }
+
+ Flag = TRUE;
+
+Exit:
+ if (SystemInfo == NULL) {
+ if (SystemDefault != NULL) {
+ FreePool (SystemDefault);
+ }
+ }
+ return Flag;
+}
+
+
+/**
+ This function checks whether EFI_FONT_INFO exists in current database. If
+ FontInfoMask is specified, check what options can be used to make a match.
+ Note that the masks relate to where the system default should be supplied
+ are ignored by this function.
+
+ @param Private Hii database private structure.
+ @param FontInfo Points to EFI_FONT_INFO structure.
+ @param FontInfoMask If not NULL, describes what options can be used
+ to make a match between the font requested and
+ the font available. The caller must guarantee
+ this mask is valid.
+ @param FontHandle On entry, Points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font.
+ @param GlobalFontInfo If not NULL, output the corresponding global font
+ info.
+
+ @retval TRUE Existed
+ @retval FALSE Not existed
+
+**/
+BOOLEAN
+IsFontInfoExisted (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_FONT_INFO *FontInfo,
+ IN EFI_FONT_INFO_MASK *FontInfoMask, OPTIONAL
+ IN EFI_FONT_HANDLE FontHandle, OPTIONAL
+ OUT HII_GLOBAL_FONT_INFO **GlobalFontInfo OPTIONAL
+ )
+{
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFontBackup1;
+ HII_GLOBAL_FONT_INFO *GlobalFontBackup2;
+ LIST_ENTRY *Link;
+ EFI_FONT_INFO_MASK Mask;
+ BOOLEAN Matched;
+ BOOLEAN VagueMatched1;
+ BOOLEAN VagueMatched2;
+
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ ASSERT (FontInfo != NULL);
+
+ //
+ // Matched flag represents an exactly match; VagueMatched1 represents a RESIZE
+ // or RESTYLE match; VagueMatched2 represents a RESIZE | RESTYLE match.
+ //
+ Matched = FALSE;
+ VagueMatched1 = FALSE;
+ VagueMatched2 = FALSE;
+
+ Mask = 0;
+ GlobalFontBackup1 = NULL;
+ GlobalFontBackup2 = NULL;
+
+ // The process of where the system default should be supplied instead of
+ // the specified font info beyonds this function's scope.
+ //
+ if (FontInfoMask != NULL) {
+ Mask = *FontInfoMask & (~SYS_FONT_INFO_MASK);
+ }
+
+ //
+ // If not NULL, FontHandle points to the next node of the last searched font
+ // node by previous call.
+ //
+ if (FontHandle == NULL) {
+ Link = Private->FontInfoList.ForwardLink;
+ } else {
+ Link = (LIST_ENTRY *) FontHandle;
+ }
+
+ for (; Link != &Private->FontInfoList; Link = Link->ForwardLink) {
+ GlobalFont = CR (Link, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ if (FontInfoMask == NULL) {
+ if (CompareMem (GlobalFont->FontInfo, FontInfo, GlobalFont->FontInfoSize) == 0) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFont;
+ }
+ return TRUE;
+ }
+ } else {
+ //
+ // Check which options could be used to make a match.
+ //
+ switch (Mask) {
+ case EFI_FONT_INFO_ANY_FONT:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_STYLE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_ANY_STYLE:
+ Matched = TRUE;
+ break;
+ //
+ // If EFI_FONT_INFO_RESTYLE is specified, then the system may attempt to
+ // remove some of the specified styles to meet the style requested.
+ //
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESTYLE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ //
+ // If EFI_FONT_INFO_RESIZE is specified, then the system may attempt to
+ // stretch or shrink a font to meet the size requested.
+ //
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ } else {
+ VagueMatched2 = TRUE;
+ GlobalFontBackup2 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_RESTYLE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_ANY_SIZE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_RESIZE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_SIZE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_RESTYLE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESTYLE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESIZE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_RESTYLE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ } else {
+ VagueMatched2 = TRUE;
+ GlobalFontBackup2 = GlobalFont;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (Matched) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFont;
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ if (VagueMatched1) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFontBackup1;
+ }
+ return TRUE;
+ } else if (VagueMatched2) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFontBackup2;
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Check whether the unicode represents a line break or not.
+
+ This is a internal function. Please see Section 27.2.6 of the UEFI Specification
+ for a description of the supported string format.
+
+ @param Char Unicode character
+
+ @retval 0 Yes, it forces a line break.
+ @retval 1 Yes, it presents a line break opportunity
+ @retval 2 Yes, it requires a line break happen before and after it.
+ @retval -1 No, it is not a link break.
+
+**/
+INT8
+IsLineBreak (
+ IN CHAR16 Char
+ )
+{
+ switch (Char) {
+ //
+ // Mandatory line break characters, which force a line-break
+ //
+ case 0x000A:
+ case 0x000C:
+ case 0x000D:
+ case 0x2028:
+ case 0x2029:
+ return 0;
+ //
+ // Space characters, which is taken as a line-break opportunity
+ //
+ case 0x0020:
+ case 0x1680:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2008:
+ case 0x2009:
+ case 0x200A:
+ case 0x205F:
+ //
+ // In-Word Break Opportunities
+ //
+ case 0x200B:
+ return 1;
+ //
+ // A space which is not a line-break opportunity
+ //
+ case 0x00A0:
+ case 0x202F:
+ //
+ // A hyphen which is not a line-break opportunity
+ //
+ case 0x2011:
+ return -1;
+ //
+ // Hyphen characters which describe line break opportunities after the character
+ //
+ case 0x058A:
+ case 0x2010:
+ case 0x2012:
+ case 0x2013:
+ case 0x0F0B:
+ case 0x1361:
+ case 0x17D5:
+ return 1;
+ //
+ // A hyphen which describes line break opportunities before and after them, but not between a pair of them
+ //
+ case 0x2014:
+ return 2;
+ }
+ return -1;
+}
+
+
+/**
+ Renders a string to a bitmap or to the display.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param String Points to the null-terminated string to be
+ displayed.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param BltY Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller's responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The String or Blt was NULL.
+ @retval EFI_INVALID_PARAMETER Flags were invalid combination..
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ UINT8 **GlyphBuf;
+ EFI_HII_GLYPH_INFO *Cell;
+ UINT8 *Attributes;
+ EFI_IMAGE_OUTPUT *Image;
+ EFI_STRING StringPtr;
+ EFI_STRING StringTmp;
+ EFI_HII_ROW_INFO *RowInfo;
+ UINTN LineWidth;
+ UINTN LineHeight;
+ UINTN LineOffset;
+ UINTN LastLineHeight;
+ UINTN BaseLineOffset;
+ UINT16 MaxRowNum;
+ UINT16 RowIndex;
+ UINTN Index;
+ UINTN NextIndex;
+ UINTN Index1;
+ EFI_FONT_DISPLAY_INFO *StringInfoOut;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_HANDLE FontHandle;
+ EFI_STRING StringIn;
+ EFI_STRING StringIn2;
+ UINT16 Height;
+ UINT16 BaseLine;
+ EFI_FONT_INFO *FontInfo;
+ BOOLEAN SysFontFlag;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ BOOLEAN Transparent;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BufferPtr;
+ UINTN RowInfoSize;
+ BOOLEAN LineBreak;
+ UINTN StrLength;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *RowBufferPtr;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ UINT32 PreInitBkgnd;
+
+ //
+ // Check incoming parameters.
+ //
+
+ if (This == NULL || String == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*Blt == NULL) {
+ //
+ // These two flag cannot be used if Blt is NULL upon entry.
+ //
+ if ((Flags & EFI_HII_OUT_FLAG_TRANSPARENT) == EFI_HII_OUT_FLAG_TRANSPARENT) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Flags & EFI_HII_OUT_FLAG_CLIP) == EFI_HII_OUT_FLAG_CLIP) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // These two flags require that EFI_HII_OUT_FLAG_CLIP be also set.
+ //
+ if ((Flags & (EFI_HII_OUT_FLAG_CLIP | EFI_HII_OUT_FLAG_CLIP_CLEAN_X)) == EFI_HII_OUT_FLAG_CLIP_CLEAN_X) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Flags & (EFI_HII_OUT_FLAG_CLIP | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y)) == EFI_HII_OUT_FLAG_CLIP_CLEAN_Y) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // This flag cannot be used with EFI_HII_OUT_FLAG_CLEAN_X.
+ //
+ if ((Flags & (EFI_HII_OUT_FLAG_WRAP | EFI_HII_OUT_FLAG_CLIP_CLEAN_X)) == (EFI_HII_OUT_FLAG_WRAP | EFI_HII_OUT_FLAG_CLIP_CLEAN_X)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Blt == NULL) {
+ //
+ // Create a new bitmap and draw the string onto this image.
+ //
+ Image = AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Image == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Image->Width = 800;
+ Image->Height = 600;
+ Image->Image.Bitmap = AllocateZeroPool (Image->Width * Image->Height *sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Image->Image.Bitmap == NULL) {
+ FreePool (Image);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Other flags are not permitted when Blt is NULL.
+ //
+ Flags &= EFI_HII_OUT_FLAG_WRAP | EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_IGNORE_LINE_BREAK;
+ *Blt = Image;
+ }
+
+ StrLength = StrLen(String);
+ GlyphBuf = (UINT8 **) AllocateZeroPool (StrLength * sizeof (UINT8 *));
+ ASSERT (GlyphBuf != NULL);
+ Cell = (EFI_HII_GLYPH_INFO *) AllocateZeroPool (StrLength * sizeof (EFI_HII_GLYPH_INFO));
+ ASSERT (Cell != NULL);
+ Attributes = (UINT8 *) AllocateZeroPool (StrLength * sizeof (UINT8));
+ ASSERT (Attributes != NULL);
+
+ RowInfo = NULL;
+ Status = EFI_SUCCESS;
+ StringIn2 = NULL;
+ SystemDefault = NULL;
+ StringIn = NULL;
+
+ //
+ // Calculate the string output information, including specified color and font .
+ // If StringInfo does not points to system font info, it must indicate an existing
+ // EFI_FONT_INFO.
+ //
+ StringInfoOut = NULL;
+ FontHandle = NULL;
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ SysFontFlag = IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfo, &SystemDefault, NULL);
+
+ if (SysFontFlag) {
+ ASSERT (SystemDefault != NULL);
+ FontInfo = NULL;
+ Height = SystemDefault->FontInfo.FontSize;
+ BaseLine = SystemDefault->FontInfo.FontSize;
+ Foreground = SystemDefault->ForegroundColor;
+ Background = SystemDefault->BackgroundColor;
+
+ } else {
+ //
+ // StringInfo must not be NULL if it is not system info.
+ //
+ ASSERT (StringInfo != NULL);
+ Status = HiiGetFontInfo (This, &FontHandle, (EFI_FONT_DISPLAY_INFO *) StringInfo, &StringInfoOut, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // The specified EFI_FONT_DISPLAY_INFO does not exist in current database.
+ // Use the system font instead. Still use the color specified by StringInfo.
+ //
+ SysFontFlag = TRUE;
+ FontInfo = NULL;
+ Height = SystemDefault->FontInfo.FontSize;
+ BaseLine = SystemDefault->FontInfo.FontSize;
+ Foreground = ((EFI_FONT_DISPLAY_INFO *) StringInfo)->ForegroundColor;
+ Background = ((EFI_FONT_DISPLAY_INFO *) StringInfo)->BackgroundColor;
+
+ } else if (Status == EFI_SUCCESS) {
+ FontInfo = &StringInfoOut->FontInfo;
+ IsFontInfoExisted (Private, FontInfo, NULL, NULL, &GlobalFont);
+ Height = GlobalFont->FontPackage->Height;
+ BaseLine = GlobalFont->FontPackage->BaseLine;
+ Foreground = StringInfoOut->ForegroundColor;
+ Background = StringInfoOut->BackgroundColor;
+ } else {
+ goto Exit;
+ }
+ }
+
+ //
+ // Use the maximum height of font as the base line.
+ // And, use the maximum height as line height.
+ //
+ LineHeight = Height;
+ LastLineHeight = Height;
+ BaseLineOffset = Height - BaseLine;
+
+ //
+ // Parse the string to be displayed to drop some ignored characters.
+ //
+
+ StringPtr = String;
+
+ //
+ // Ignore line-break characters only. Hyphens or dash character will be displayed
+ // without line-break opportunity.
+ //
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == EFI_HII_IGNORE_LINE_BREAK) {
+ StringIn = AllocateZeroPool (StrSize (StringPtr));
+ if (StringIn == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StringTmp = StringIn;
+ while (*StringPtr != 0) {
+ if (IsLineBreak (*StringPtr) == 0) {
+ StringPtr++;
+ } else {
+ *StringTmp++ = *StringPtr++;
+ }
+ }
+ *StringTmp = 0;
+ StringPtr = StringIn;
+ }
+ //
+ // If EFI_HII_IGNORE_IF_NO_GLYPH is set, then characters which have no glyphs
+ // are not drawn. Otherwise they are replaced with Unicode character 0xFFFD.
+ //
+ StringIn2 = AllocateZeroPool (StrSize (StringPtr));
+ if (StringIn2 == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Index = 0;
+ StringTmp = StringIn2;
+ StrLength = StrLen(StringPtr);
+ while (*StringPtr != 0 && Index < StrLength) {
+ if (IsLineBreak (*StringPtr) == 0) {
+ *StringTmp++ = *StringPtr++;
+ Index++;
+ continue;
+ }
+
+ Status = GetGlyphBuffer (Private, *StringPtr, FontInfo, &GlyphBuf[Index], &Cell[Index], &Attributes[Index]);
+ if (Status == EFI_NOT_FOUND) {
+ if ((Flags & EFI_HII_IGNORE_IF_NO_GLYPH) == EFI_HII_IGNORE_IF_NO_GLYPH) {
+ GlyphBuf[Index] = NULL;
+ ZeroMem (&Cell[Index], sizeof (Cell[Index]));
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Unicode 0xFFFD must exist in current hii database if this flag is not set.
+ //
+ Status = GetGlyphBuffer (
+ Private,
+ REPLACE_UNKNOWN_GLYPH,
+ FontInfo,
+ &GlyphBuf[Index],
+ &Cell[Index],
+ &Attributes[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ *StringTmp++ = *StringPtr++;
+ Index++;
+ }
+ *StringTmp = 0;
+ StringPtr = StringIn2;
+
+ //
+ // Draw the string according to the specified EFI_HII_OUT_FLAGS and Blt.
+ // If Blt is not NULL, then EFI_HII_OUT_FLAG_CLIP is implied, render this string
+ // to an existing image (bitmap or screen depending on flags) pointed by "*Blt".
+ // Otherwise render this string to a new allocated image and output it.
+ //
+ Image = *Blt;
+ BufferPtr = Image->Image.Bitmap + Image->Width * BltY + BltX;
+ if (Image->Height < BltY) {
+ //
+ // the top edge of the image should be in Image resolution scope.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ MaxRowNum = (UINT16) ((Image->Height - BltY) / Height);
+ if ((Image->Height - BltY) % Height != 0) {
+ LastLineHeight = (Image->Height - BltY) % Height;
+ MaxRowNum++;
+ }
+
+ RowInfo = (EFI_HII_ROW_INFO *) AllocateZeroPool (MaxRowNum * sizeof (EFI_HII_ROW_INFO));
+ if (RowInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Format the glyph buffer according to flags.
+ //
+ Transparent = (BOOLEAN) ((Flags & EFI_HII_OUT_FLAG_TRANSPARENT) == EFI_HII_OUT_FLAG_TRANSPARENT ? TRUE : FALSE);
+
+ for (RowIndex = 0, Index = 0; RowIndex < MaxRowNum && StringPtr[Index] != 0; ) {
+ LineWidth = 0;
+ LineBreak = FALSE;
+
+ //
+ // Clip the final row if the row's bottom-most on pixel cannot fit when
+ // EFI_HII_OUT_FLAG_CLEAN_Y is set.
+ //
+ if (RowIndex == MaxRowNum - 1) {
+ if ((Flags & EFI_HII_OUT_FLAG_CLIP_CLEAN_Y) == EFI_HII_OUT_FLAG_CLIP_CLEAN_Y && LastLineHeight < LineHeight ) {
+ //
+ // Don't draw at all if the row's bottom-most on pixel cannot fit.
+ //
+ break;
+ }
+ LineHeight = LastLineHeight;
+ }
+
+ //
+ // Calculate how many characters there are in a row.
+ //
+ RowInfo[RowIndex].StartIndex = Index;
+
+ while (LineWidth + BltX < Image->Width && StringPtr[Index] != 0) {
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == 0 &&
+ IsLineBreak (StringPtr[Index]) == 0) {
+ //
+ // It forces a line break that ends this row.
+ //
+ Index++;
+ LineBreak = TRUE;
+ break;
+ }
+
+ //
+ // If the glyph of the character is existing, then accumulate the actual printed width
+ //
+ LineWidth += (UINTN) Cell[Index].AdvanceX;
+
+ Index++;
+ }
+
+ //
+ // Record index of next char.
+ //
+ NextIndex = Index;
+ //
+ // Return to the previous char.
+ //
+ Index--;
+ if (LineBreak && Index > 0 ) {
+ //
+ // Return the previous non line break char.
+ //
+ Index --;
+ }
+
+ //
+ // If this character is the last character of a row, we need not
+ // draw its (AdvanceX - Width - OffsetX) for next character.
+ //
+ LineWidth -= (Cell[Index].AdvanceX - Cell[Index].Width - Cell[Index].OffsetX);
+
+ //
+ // Clip the right-most character if cannot fit when EFI_HII_OUT_FLAG_CLEAN_X is set.
+ //
+ if (LineWidth + BltX <= Image->Width ||
+ (LineWidth + BltX > Image->Width && (Flags & EFI_HII_OUT_FLAG_CLIP_CLEAN_X) == 0)) {
+ //
+ // Record right-most character in RowInfo even if it is partially displayed.
+ //
+ RowInfo[RowIndex].EndIndex = Index;
+ RowInfo[RowIndex].LineWidth = LineWidth;
+ RowInfo[RowIndex].LineHeight = LineHeight;
+ RowInfo[RowIndex].BaselineOffset = BaseLineOffset;
+ } else {
+ //
+ // When EFI_HII_OUT_FLAG_CLEAN_X is set, it will not draw a character
+ // if its right-most on pixel cannot fit.
+ //
+ if (Index > RowInfo[RowIndex].StartIndex) {
+ //
+ // Don't draw the last char on this row. And, don't draw the second last char (AdvanceX - Width - OffsetX).
+ //
+ LineWidth -= (Cell[Index].Width + Cell[Index].OffsetX);
+ LineWidth -= (Cell[Index - 1].AdvanceX - Cell[Index - 1].Width - Cell[Index - 1].OffsetX);
+ RowInfo[RowIndex].EndIndex = Index - 1;
+ RowInfo[RowIndex].LineWidth = LineWidth;
+ RowInfo[RowIndex].LineHeight = LineHeight;
+ RowInfo[RowIndex].BaselineOffset = BaseLineOffset;
+ } else {
+ //
+ // There is no enough column to draw any character, so set current line width to zero.
+ // And go to draw Next line if LineBreak is set.
+ //
+ RowInfo[RowIndex].LineWidth = 0;
+ goto NextLine;
+ }
+ }
+
+ //
+ // EFI_HII_OUT_FLAG_WRAP will wrap the text at the right-most line-break
+ // opportunity prior to a character whose right-most extent would exceed Width.
+ // Search the right-most line-break opportunity here.
+ //
+ if ((Flags & EFI_HII_OUT_FLAG_WRAP) == EFI_HII_OUT_FLAG_WRAP &&
+ (RowInfo[RowIndex].LineWidth + BltX > Image->Width || StringPtr[NextIndex] != 0) &&
+ !LineBreak) {
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == 0) {
+ LineWidth = RowInfo[RowIndex].LineWidth;
+ for (Index1 = RowInfo[RowIndex].EndIndex; Index1 >= RowInfo[RowIndex].StartIndex; Index1--) {
+ if (Index1 == RowInfo[RowIndex].EndIndex) {
+ LineWidth -= (Cell[Index1].Width + Cell[Index1].OffsetX);
+ } else {
+ LineWidth -= Cell[Index1].AdvanceX;
+ }
+ if (IsLineBreak (StringPtr[Index1]) > 0) {
+ LineBreak = TRUE;
+ if (Index1 > RowInfo[RowIndex].StartIndex) {
+ RowInfo[RowIndex].EndIndex = Index1 - 1;
+ }
+ //
+ // relocate to the character after the right-most line break opportunity of this line
+ //
+ NextIndex = Index1 + 1;
+ break;
+ }
+ //
+ // If don't find a line break opportunity from EndIndex to StartIndex,
+ // then jump out.
+ //
+ if (Index1 == RowInfo[RowIndex].StartIndex)
+ break;
+ }
+
+ //
+ // Update LineWidth to the real width
+ //
+ if (IsLineBreak (StringPtr[Index1]) > 0) {
+ if (Index1 == RowInfo[RowIndex].StartIndex) {
+ LineWidth = 0;
+ } else {
+ LineWidth -= (Cell[Index1 - 1].AdvanceX - Cell[Index1 - 1].Width - Cell[Index1 - 1].OffsetX);
+ }
+ RowInfo[RowIndex].LineWidth = LineWidth;
+ }
+ }
+ //
+ // If no line-break opportunity can be found, then the text will
+ // behave as if EFI_HII_OUT_FLAG_CLEAN_X is set.
+ //
+ if (!LineBreak) {
+ LineWidth = RowInfo[RowIndex].LineWidth;
+ Index1 = RowInfo[RowIndex].EndIndex;
+ if (LineWidth + BltX > Image->Width) {
+ if (Index1 > RowInfo[RowIndex].StartIndex) {
+ //
+ // Don't draw the last char on this row. And, don't draw the second last char (AdvanceX - Width - OffsetX).
+ //
+ LineWidth -= (Cell[Index1].Width + Cell[Index1].OffsetX);
+ LineWidth -= (Cell[Index1 - 1].AdvanceX - Cell[Index1 - 1].Width - Cell[Index1 - 1].OffsetX);
+ RowInfo[RowIndex].EndIndex = Index1 - 1;
+ RowInfo[RowIndex].LineWidth = LineWidth;
+ } else {
+ //
+ // There is no enough column to draw any character, so set current line width to zero.
+ // And go to draw Next line if LineBreak is set.
+ //
+ RowInfo[RowIndex].LineWidth = 0;
+ goto NextLine;
+ }
+ }
+ }
+ }
+
+ //
+ // LineWidth can't exceed Image width.
+ //
+ if (RowInfo[RowIndex].LineWidth + BltX > Image->Width) {
+ RowInfo[RowIndex].LineWidth = Image->Width - BltX;
+ }
+
+ //
+ // Draw it to screen or existing bitmap depending on whether
+ // EFI_HII_DIRECT_TO_SCREEN is set.
+ //
+ LineOffset = 0;
+ if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ BltBuffer = NULL;
+ if (RowInfo[RowIndex].LineWidth != 0) {
+ BltBuffer = AllocatePool (RowInfo[RowIndex].LineWidth * RowInfo[RowIndex].LineHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (BltBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ //
+ // Initialize the background color.
+ //
+ PreInitBkgnd = Background.Blue | Background.Green << 8 | Background.Red << 16;
+ SetMem32 (BltBuffer,RowInfo[RowIndex].LineWidth * RowInfo[RowIndex].LineHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),PreInitBkgnd);
+ //
+ // Set BufferPtr to Origin by adding baseline to the starting position.
+ //
+ BufferPtr = BltBuffer + BaseLine * RowInfo[RowIndex].LineWidth;
+ }
+ for (Index1 = RowInfo[RowIndex].StartIndex; Index1 <= RowInfo[RowIndex].EndIndex; Index1++) {
+ if (RowInfo[RowIndex].LineWidth > 0 && RowInfo[RowIndex].LineWidth > LineOffset) {
+ //
+ // Only BLT these character which have corresponding glyph in font database.
+ //
+ GlyphToImage (
+ GlyphBuf[Index1],
+ Foreground,
+ Background,
+ (UINT16) RowInfo[RowIndex].LineWidth,
+ BaseLine,
+ RowInfo[RowIndex].LineWidth - LineOffset,
+ RowInfo[RowIndex].LineHeight,
+ Transparent,
+ &Cell[Index1],
+ Attributes[Index1],
+ &BufferPtr
+ );
+ }
+ if (ColumnInfoArray != NULL) {
+ if ((GlyphBuf[Index1] == NULL && Cell[Index1].AdvanceX == 0)
+ || RowInfo[RowIndex].LineWidth == 0) {
+ *ColumnInfoArray = (UINTN) ~0;
+ } else {
+ *ColumnInfoArray = LineOffset + Cell[Index1].OffsetX + BltX;
+ }
+ ColumnInfoArray++;
+ }
+ LineOffset += Cell[Index1].AdvanceX;
+ }
+
+ if (BltBuffer != NULL) {
+ Status = Image->Image.Screen->Blt (
+ Image->Image.Screen,
+ BltBuffer,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ BltX,
+ BltY,
+ RowInfo[RowIndex].LineWidth,
+ RowInfo[RowIndex].LineHeight,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (BltBuffer);
+ goto Exit;
+ }
+
+ FreePool (BltBuffer);
+ }
+ } else {
+ //
+ // Save the starting position for calculate the starting position of next row.
+ //
+ RowBufferPtr = BufferPtr;
+ //
+ // Set BufferPtr to Origin by adding baseline to the starting position.
+ //
+ BufferPtr = BufferPtr + BaseLine * Image->Width;
+ for (Index1 = RowInfo[RowIndex].StartIndex; Index1 <= RowInfo[RowIndex].EndIndex; Index1++) {
+ if (RowInfo[RowIndex].LineWidth > 0 && RowInfo[RowIndex].LineWidth > LineOffset) {
+ //
+ // Only BLT these character which have corresponding glyph in font database.
+ //
+ GlyphToImage (
+ GlyphBuf[Index1],
+ Foreground,
+ Background,
+ Image->Width,
+ BaseLine,
+ RowInfo[RowIndex].LineWidth - LineOffset,
+ RowInfo[RowIndex].LineHeight,
+ Transparent,
+ &Cell[Index1],
+ Attributes[Index1],
+ &BufferPtr
+ );
+ }
+ if (ColumnInfoArray != NULL) {
+ if ((GlyphBuf[Index1] == NULL && Cell[Index1].AdvanceX == 0)
+ || RowInfo[RowIndex].LineWidth == 0) {
+ *ColumnInfoArray = (UINTN) ~0;
+ } else {
+ *ColumnInfoArray = LineOffset + Cell[Index1].OffsetX + BltX;
+ }
+ ColumnInfoArray++;
+ }
+ LineOffset += Cell[Index1].AdvanceX;
+ }
+
+ //
+ // Jump to starting position of next row.
+ //
+ if (RowIndex == 0) {
+ BufferPtr = RowBufferPtr - BltX + LineHeight * Image->Width;
+ } else {
+ BufferPtr = RowBufferPtr + LineHeight * Image->Width;
+ }
+ }
+
+NextLine:
+ //
+ // Recalculate the start point of Y axis to draw multi-lines with the order of top-to-down
+ //
+ BltY += RowInfo[RowIndex].LineHeight;
+
+ RowIndex++;
+ Index = NextIndex;
+
+ if (!LineBreak) {
+ //
+ // If there is not a mandatory line break or line break opportunity, only render one line to image
+ //
+ break;
+ }
+ }
+
+ //
+ // Write output parameters.
+ //
+ RowInfoSize = RowIndex * sizeof (EFI_HII_ROW_INFO);
+ if (RowInfoArray != NULL) {
+ if (RowInfoSize > 0) {
+ *RowInfoArray = AllocateZeroPool (RowInfoSize);
+ if (*RowInfoArray == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (*RowInfoArray, RowInfo, RowInfoSize);
+ } else {
+ *RowInfoArray = NULL;
+ }
+ }
+ if (RowInfoArraySize != NULL) {
+ *RowInfoArraySize = RowIndex;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+
+ for (Index = 0; Index < StrLength; Index++) {
+ if (GlyphBuf[Index] != NULL) {
+ FreePool (GlyphBuf[Index]);
+ }
+ }
+ if (StringIn != NULL) {
+ FreePool (StringIn);
+ }
+ if (StringIn2 != NULL) {
+ FreePool (StringIn2);
+ }
+ if (StringInfoOut != NULL) {
+ FreePool (StringInfoOut);
+ }
+ if (RowInfo != NULL) {
+ FreePool (RowInfo);
+ }
+ if (SystemDefault != NULL) {
+ FreePool (SystemDefault);
+ }
+ if (GlyphBuf != NULL) {
+ FreePool (GlyphBuf);
+ }
+ if (Cell != NULL) {
+ FreePool (Cell);
+ }
+ if (Attributes != NULL) {
+ FreePool (Attributes);
+ }
+
+ return Status;
+}
+
+
+/**
+ Render a string to a bitmap or the screen containing the contents of the specified string.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param PackageList The package list in the HII database to search
+ for the specified string.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param Language Points to the language for the retrieved string.
+ If NULL, then the current system language is
+ used.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param BltY Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller's responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The Blt or PackageList was NULL.
+ @retval EFI_INVALID_PARAMETER Flags were invalid combination.
+ @retval EFI_NOT_FOUND The specified PackageList is not in the Database or the string id is not
+ in the specified PackageList.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringIdToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8* Language,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_STRING String;
+ UINTN StringSize;
+ UINTN FontLen;
+ UINTN NameSize;
+ EFI_FONT_INFO *StringFontInfo;
+ EFI_FONT_DISPLAY_INFO *NewStringInfo;
+ CHAR8 TempSupportedLanguages;
+ CHAR8 *SupportedLanguages;
+ UINTN SupportedLanguagesSize;
+ CHAR8 *CurrentLanguage;
+ CHAR8 *BestLanguage;
+
+ if (This == NULL || PackageList == NULL || Blt == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Initialize string pointers to be NULL
+ //
+ SupportedLanguages = NULL;
+ CurrentLanguage = NULL;
+ BestLanguage = NULL;
+ String = NULL;
+ StringFontInfo = NULL;
+ NewStringInfo = NULL;
+
+ //
+ // Get the string to be displayed.
+ //
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ HiiString = &Private->HiiString;
+
+ //
+ // Get the size of supported language.
+ //
+ SupportedLanguagesSize = 0;
+ Status = HiiString->GetLanguages (
+ HiiString,
+ PackageList,
+ &TempSupportedLanguages,
+ &SupportedLanguagesSize
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ SupportedLanguages = AllocatePool (SupportedLanguagesSize);
+ if (SupportedLanguages == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = HiiString->GetLanguages (
+ HiiString,
+ PackageList,
+ SupportedLanguages,
+ &SupportedLanguagesSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (Language == NULL) {
+ Language = "";
+ }
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLanguage, NULL);
+ BestLanguage = GetBestLanguage (
+ SupportedLanguages,
+ FALSE,
+ Language,
+ (CurrentLanguage == NULL) ? CurrentLanguage : "",
+ (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang),
+ NULL
+ );
+ if (BestLanguage == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ StringSize = MAX_STRING_LENGTH;
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = HiiString->GetString (
+ HiiString,
+ BestLanguage,
+ PackageList,
+ StringId,
+ String,
+ &StringSize,
+ &StringFontInfo
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (String);
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Status = HiiString->GetString (
+ HiiString,
+ BestLanguage,
+ PackageList,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // When StringInfo specifies that string will be output in the system default font and color,
+ // use particular stringfontinfo described in string package instead if exists.
+ // StringFontInfo equals NULL means system default font attaches with the string block.
+ //
+ if (StringFontInfo != NULL && IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfo, NULL, NULL)) {
+ NameSize = StrSize (StringFontInfo->FontName);
+ FontLen = sizeof (EFI_FONT_DISPLAY_INFO) - sizeof (CHAR16) + NameSize;
+ NewStringInfo = AllocateZeroPool (FontLen);
+ if (NewStringInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ NewStringInfo->FontInfoMask = EFI_FONT_INFO_SYS_FORE_COLOR | EFI_FONT_INFO_SYS_BACK_COLOR;
+ NewStringInfo->FontInfo.FontStyle = StringFontInfo->FontStyle;
+ NewStringInfo->FontInfo.FontSize = StringFontInfo->FontSize;
+ StrCpyS (NewStringInfo->FontInfo.FontName, NameSize / sizeof (CHAR16), StringFontInfo->FontName);
+
+ Status = HiiStringToImage (
+ This,
+ Flags,
+ String,
+ NewStringInfo,
+ Blt,
+ BltX,
+ BltY,
+ RowInfoArray,
+ RowInfoArraySize,
+ ColumnInfoArray
+ );
+ goto Exit;
+ }
+
+ Status = HiiStringToImage (
+ This,
+ Flags,
+ String,
+ StringInfo,
+ Blt,
+ BltX,
+ BltY,
+ RowInfoArray,
+ RowInfoArraySize,
+ ColumnInfoArray
+ );
+
+Exit:
+ if (SupportedLanguages != NULL) {
+ FreePool (SupportedLanguages);
+ }
+ if (CurrentLanguage != NULL) {
+ FreePool (CurrentLanguage);
+ }
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ }
+ if (String != NULL) {
+ FreePool (String);
+ }
+ if (StringFontInfo != NULL) {
+ FreePool (StringFontInfo);
+ }
+ if (NewStringInfo != NULL) {
+ FreePool (NewStringInfo);
+ }
+
+ return Status;
+}
+
+
+/**
+ Convert the glyph for a single character into a bitmap.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Char Character to retrieve.
+ @param StringInfo Points to the string font and color information
+ or NULL if the string should use the default
+ system font and color.
+ @param Blt Thus must point to a NULL on entry. A buffer will
+ be allocated to hold the output and the pointer
+ updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param Baseline Number of pixels from the bottom of the bitmap to
+ the baseline.
+
+ @retval EFI_SUCCESS Glyph bitmap created.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer Blt.
+ @retval EFI_WARN_UNKNOWN_GLYPH The glyph was unknown and was replaced with the
+ glyph for Unicode character 0xFFFD.
+ @retval EFI_INVALID_PARAMETER Blt is NULL or *Blt is not NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetGlyph (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN CHAR16 Char,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo,
+ OUT EFI_IMAGE_OUTPUT **Blt,
+ OUT UINTN *Baseline OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_IMAGE_OUTPUT *Image;
+ UINT8 *GlyphBuffer;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_DISPLAY_INFO *StringInfoOut;
+ BOOLEAN Default;
+ EFI_FONT_HANDLE FontHandle;
+ EFI_STRING String;
+ EFI_HII_GLYPH_INFO Cell;
+ EFI_FONT_INFO *FontInfo;
+ UINT8 Attributes;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ UINT16 BaseLine;
+
+ if (This == NULL || Blt == NULL || *Blt != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ Default = FALSE;
+ Image = NULL;
+ SystemDefault = NULL;
+ FontHandle = NULL;
+ String = NULL;
+ GlyphBuffer = NULL;
+ StringInfoOut = NULL;
+ FontInfo = NULL;
+
+ ZeroMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ Default = IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfo, &SystemDefault, NULL);
+
+ if (!Default) {
+ //
+ // Find out a EFI_FONT_DISPLAY_INFO which could display the character in
+ // the specified color and font.
+ //
+ String = (EFI_STRING) AllocateZeroPool (sizeof (CHAR16) * 2);
+ if (String == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ *String = Char;
+ *(String + 1) = 0;
+
+ Status = HiiGetFontInfo (This, &FontHandle, StringInfo, &StringInfoOut, String);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ ASSERT (StringInfoOut != NULL);
+ FontInfo = &StringInfoOut->FontInfo;
+ Foreground = StringInfoOut->ForegroundColor;
+ Background = StringInfoOut->BackgroundColor;
+ } else {
+ ASSERT (SystemDefault != NULL);
+ Foreground = SystemDefault->ForegroundColor;
+ Background = SystemDefault->BackgroundColor;
+ }
+
+ Status = GetGlyphBuffer (Private, Char, FontInfo, &GlyphBuffer, &Cell, &Attributes);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Image = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Image->Width = Cell.Width;
+ Image->Height = Cell.Height;
+
+ if (Image->Width * Image->Height > 0) {
+ Image->Image.Bitmap = AllocateZeroPool (Image->Width * Image->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Image->Image.Bitmap == NULL) {
+ FreePool (Image);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Set BaseLine to the char height.
+ //
+ BaseLine = (UINT16) (Cell.Height + Cell.OffsetY);
+ //
+ // Set BltBuffer to the position of Origin.
+ //
+ BltBuffer = Image->Image.Bitmap + (Cell.Height + Cell.OffsetY) * Image->Width - Cell.OffsetX;
+ GlyphToImage (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ Image->Width,
+ BaseLine,
+ Cell.Width + Cell.OffsetX,
+ BaseLine - Cell.OffsetY,
+ FALSE,
+ &Cell,
+ Attributes,
+ &BltBuffer
+ );
+ }
+
+ *Blt = Image;
+ if (Baseline != NULL) {
+ *Baseline = Cell.OffsetY;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Glyph is unknown and replaced with the glyph for unicode character 0xFFFD
+ //
+ if (Char != REPLACE_UNKNOWN_GLYPH) {
+ Status = HiiGetGlyph (This, REPLACE_UNKNOWN_GLYPH, StringInfo, Blt, Baseline);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+ } else {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+ }
+
+ if (SystemDefault != NULL) {
+ FreePool (SystemDefault);
+ }
+ if (StringInfoOut != NULL) {
+ FreePool (StringInfoOut);
+ }
+ if (String != NULL) {
+ FreePool (String);
+ }
+ if (GlyphBuffer != NULL) {
+ FreePool (GlyphBuffer);
+ }
+
+ return Status;
+}
+
+
+/**
+ This function iterates through fonts which match the specified font, using
+ the specified criteria. If String is non-NULL, then all of the characters in
+ the string must exist in order for a candidate font to be returned.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param FontHandle On entry, points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font. On return, points to the
+ returned font handle or points to NULL if there
+ are no more matching fonts.
+ @param StringInfoIn Upon entry, points to the font to return information
+ about. If NULL, then the information about the system
+ default font will be returned.
+ @param StringInfoOut Upon return, contains the matching font's information.
+ If NULL, then no information is returned. This buffer
+ is allocated with a call to the Boot Service AllocatePool().
+ It is the caller's responsibility to call the Boot
+ Service FreePool() when the caller no longer requires
+ the contents of StringInfoOut.
+ @param String Points to the string which will be tested to
+ determine if all characters are available. If
+ NULL, then any font is acceptable.
+
+ @retval EFI_SUCCESS Matching font returned successfully.
+ @retval EFI_NOT_FOUND No matching font was found.
+ @retval EFI_INVALID_PARAMETER StringInfoIn->FontInfoMask is an invalid combination.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetFontInfo (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN OUT EFI_FONT_HANDLE *FontHandle,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfoIn, OPTIONAL
+ OUT EFI_FONT_DISPLAY_INFO **StringInfoOut,
+ IN CONST EFI_STRING String OPTIONAL
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_DISPLAY_INFO InfoOut;
+ UINTN StringInfoOutLen;
+ EFI_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ EFI_STRING StringIn;
+ EFI_FONT_HANDLE LocalFontHandle;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringInfoOutLen = 0;
+ FontInfo = NULL;
+ SystemDefault = NULL;
+ LocalFontHandle = NULL;
+ if (FontHandle != NULL) {
+ LocalFontHandle = *FontHandle;
+ }
+
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Already searched to the end of the whole list, return directly.
+ //
+ if (LocalFontHandle == &Private->FontInfoList) {
+ LocalFontHandle = NULL;
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ //
+ // Get default system display info, if StringInfoIn points to
+ // system display info, return it directly.
+ //
+ if (IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfoIn, &SystemDefault, &StringInfoOutLen)) {
+ //
+ // System font is the first node. When handle is not NULL, system font can not
+ // be found any more.
+ //
+ if (LocalFontHandle == NULL) {
+ if (StringInfoOut != NULL) {
+ *StringInfoOut = AllocateCopyPool (StringInfoOutLen, SystemDefault);
+ if (*StringInfoOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+ }
+
+ LocalFontHandle = Private->FontInfoList.ForwardLink;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ } else {
+ LocalFontHandle = NULL;
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+
+ //
+ // StringInfoIn must not be NULL if it is not system default font info.
+ //
+ ASSERT (StringInfoIn != NULL);
+ //
+ // Check the font information mask to make sure it is valid.
+ //
+ if (((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_ANY_FONT)) ==
+ (EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_ANY_FONT)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_ANY_SIZE)) ==
+ (EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_ANY_SIZE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_STYLE | EFI_FONT_INFO_ANY_STYLE)) ==
+ (EFI_FONT_INFO_SYS_STYLE | EFI_FONT_INFO_ANY_STYLE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_ANY_SIZE)) ==
+ (EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_ANY_SIZE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_ANY_STYLE)) ==
+ (EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_ANY_STYLE))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Parse the font information mask to find a matching font.
+ //
+
+ CopyMem (&InfoOut, (EFI_FONT_DISPLAY_INFO *) StringInfoIn, sizeof (EFI_FONT_DISPLAY_INFO));
+
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_FONT) == EFI_FONT_INFO_SYS_FONT) {
+ Status = SaveFontName (SystemDefault->FontInfo.FontName, &FontInfo);
+ } else {
+ Status = SaveFontName (((EFI_FONT_DISPLAY_INFO *) StringInfoIn)->FontInfo.FontName, &FontInfo);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_SIZE) == EFI_FONT_INFO_SYS_SIZE) {
+ InfoOut.FontInfo.FontSize = SystemDefault->FontInfo.FontSize;
+ }
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_STYLE) == EFI_FONT_INFO_SYS_STYLE) {
+ InfoOut.FontInfo.FontStyle = SystemDefault->FontInfo.FontStyle;
+ }
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_FORE_COLOR) == EFI_FONT_INFO_SYS_FORE_COLOR) {
+ InfoOut.ForegroundColor = SystemDefault->ForegroundColor;
+ }
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_BACK_COLOR) == EFI_FONT_INFO_SYS_BACK_COLOR) {
+ InfoOut.BackgroundColor = SystemDefault->BackgroundColor;
+ }
+
+ ASSERT (FontInfo != NULL);
+ FontInfo->FontSize = InfoOut.FontInfo.FontSize;
+ FontInfo->FontStyle = InfoOut.FontInfo.FontStyle;
+
+ if (IsFontInfoExisted (Private, FontInfo, &InfoOut.FontInfoMask, LocalFontHandle, &GlobalFont)) {
+ //
+ // Test to guarantee all characters are available in the found font.
+ //
+ if (String != NULL) {
+ StringIn = String;
+ while (*StringIn != 0) {
+ Status = FindGlyphBlock (GlobalFont->FontPackage, *StringIn, NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+ StringIn++;
+ }
+ }
+ //
+ // Write to output parameter
+ //
+ if (StringInfoOut != NULL) {
+ StringInfoOutLen = sizeof (EFI_FONT_DISPLAY_INFO) - sizeof (EFI_FONT_INFO) + GlobalFont->FontInfoSize;
+ *StringInfoOut = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (StringInfoOutLen);
+ if (*StringInfoOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+
+ CopyMem (*StringInfoOut, &InfoOut, sizeof (EFI_FONT_DISPLAY_INFO));
+ CopyMem (&(*StringInfoOut)->FontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize);
+ }
+
+ LocalFontHandle = GlobalFont->Entry.ForwardLink;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Exit:
+
+ if (FontHandle != NULL) {
+ *FontHandle = LocalFontHandle;
+ }
+
+ if (SystemDefault != NULL) {
+ FreePool (SystemDefault);
+ }
+ if (FontInfo != NULL) {
+ FreePool (FontInfo);
+ }
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h
new file mode 100644
index 000000000..4a3feab94
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h
@@ -0,0 +1,2352 @@
+/** @file
+Private structures definitions in HiiDatabase.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HII_DATABASE_PRIVATE_H__
+#define __HII_DATABASE_PRIVATE_H__
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/HiiImageEx.h>
+#include <Protocol/HiiImageDecoder.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigKeyword.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Guid/HiiKeyBoardLayout.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/VariableFormat.h>
+#include <Guid/PcdDataBaseSignatureGuid.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+
+#define MAX_STRING_LENGTH 1024
+#define MAX_FONT_NAME_LEN 256
+#define NARROW_BASELINE 15
+#define WIDE_BASELINE 14
+#define SYS_FONT_INFO_MASK 0x37
+#define REPLACE_UNKNOWN_GLYPH 0xFFFD
+#define PROPORTIONAL_GLYPH 0x80
+#define NARROW_GLYPH 0x40
+
+#define BITMAP_LEN_1_BIT(Width, Height) (((Width) + 7) / 8 * (Height))
+#define BITMAP_LEN_4_BIT(Width, Height) (((Width) + 1) / 2 * (Height))
+#define BITMAP_LEN_8_BIT(Width, Height) ((Width) * (Height))
+#define BITMAP_LEN_24_BIT(Width, Height) ((Width) * (Height) * 3)
+
+extern EFI_LOCK mHiiDatabaseLock;
+
+//
+// IFR data structure
+//
+// BASE_CR (a, IFR_DEFAULT_VALUE_DATA, Entry) to get the whole structure.
+
+typedef struct {
+ LIST_ENTRY Entry; // Link to VarStorage Default Data
+ UINT16 DefaultId;
+ VARIABLE_STORE_HEADER *VariableStorage;
+} VARSTORAGE_DEFAULT_DATA;
+
+typedef struct {
+ LIST_ENTRY Entry; // Link to VarStorage
+ EFI_GUID Guid;
+ CHAR16 *Name;
+ UINT16 Size;
+ UINT8 Type;
+ LIST_ENTRY BlockEntry; // Link to its Block array
+} IFR_VARSTORAGE_DATA;
+
+typedef struct {
+ LIST_ENTRY Entry; // Link to Block array
+ UINT16 Offset;
+ UINT16 Width;
+ UINT16 BitOffset;
+ UINT16 BitWidth;
+ EFI_QUESTION_ID QuestionId;
+ UINT8 OpCode;
+ UINT8 Scope;
+ LIST_ENTRY DefaultValueEntry; // Link to its default value array
+ CHAR16 *Name;
+ BOOLEAN IsBitVar;
+} IFR_BLOCK_DATA;
+
+//
+// Get default value from IFR data.
+//
+typedef enum {
+ DefaultValueFromDefault = 0, // Get from the minimum or first one when not set default value.
+ DefaultValueFromOtherDefault, // Get default vale from other default when no default(When other
+ // defaults are more than one, use the default with smallest default id).
+ DefaultValueFromFlag, // Get default value from the default flag.
+ DefaultValueFromOpcode // Get default value from default opcode, highest priority.
+} DEFAULT_VALUE_TYPE;
+
+typedef struct {
+ LIST_ENTRY Entry;
+ DEFAULT_VALUE_TYPE Type;
+ BOOLEAN Cleaned; // Whether this value is cleaned
+ // TRUE Cleaned, the value can't be used
+ // FALSE Not cleaned, the value can be used.
+ UINT16 DefaultId;
+ EFI_IFR_TYPE_VALUE Value;
+} IFR_DEFAULT_DATA;
+
+//
+// Storage types
+//
+#define EFI_HII_VARSTORE_BUFFER 0
+#define EFI_HII_VARSTORE_NAME_VALUE 1
+#define EFI_HII_VARSTORE_EFI_VARIABLE 2
+#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3
+
+//
+// Keyword handler protocol filter type.
+//
+#define EFI_KEYWORD_FILTER_READONY 0x01
+#define EFI_KEYWORD_FILTER_REAWRITE 0x02
+#define EFI_KEYWORD_FILTER_BUFFER 0x10
+#define EFI_KEYWORD_FILTER_NUMERIC 0x20
+#define EFI_KEYWORD_FILTER_NUMERIC_1 0x30
+#define EFI_KEYWORD_FILTER_NUMERIC_2 0x40
+#define EFI_KEYWORD_FILTER_NUMERIC_4 0x50
+#define EFI_KEYWORD_FILTER_NUMERIC_8 0x60
+
+
+#define HII_FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('H', 'S', 'T', 'G')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Entry;
+
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ UINT8 Type; // EFI_HII_VARSTORE_BUFFER, EFI_HII_VARSTORE_NAME_VALUE, EFI_HII_VARSTORE_EFI_VARIABLE
+ EFI_GUID Guid;
+ CHAR16 *Name;
+ UINT16 Size;
+} HII_FORMSET_STORAGE;
+
+
+//
+// String Package definitions
+//
+#define HII_STRING_PACKAGE_SIGNATURE SIGNATURE_32 ('h','i','s','p')
+typedef struct _HII_STRING_PACKAGE_INSTANCE {
+ UINTN Signature;
+ EFI_HII_STRING_PACKAGE_HDR *StringPkgHdr;
+ UINT8 *StringBlock;
+ LIST_ENTRY StringEntry;
+ LIST_ENTRY FontInfoList; // local font info list
+ UINT8 FontId;
+ EFI_STRING_ID MaxStringId; // record StringId
+} HII_STRING_PACKAGE_INSTANCE;
+
+//
+// Form Package definitions
+//
+#define HII_IFR_PACKAGE_SIGNATURE SIGNATURE_32 ('h','f','r','p')
+typedef struct _HII_IFR_PACKAGE_INSTANCE {
+ UINTN Signature;
+ EFI_HII_PACKAGE_HEADER FormPkgHdr;
+ UINT8 *IfrData;
+ LIST_ENTRY IfrEntry;
+} HII_IFR_PACKAGE_INSTANCE;
+
+//
+// Simple Font Package definitions
+//
+#define HII_S_FONT_PACKAGE_SIGNATURE SIGNATURE_32 ('h','s','f','p')
+typedef struct _HII_SIMPLE_FONT_PACKAGE_INSTANCE {
+ UINTN Signature;
+ EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimpleFontPkgHdr;
+ LIST_ENTRY SimpleFontEntry;
+} HII_SIMPLE_FONT_PACKAGE_INSTANCE;
+
+//
+// Font Package definitions
+//
+#define HII_FONT_PACKAGE_SIGNATURE SIGNATURE_32 ('h','i','f','p')
+typedef struct _HII_FONT_PACKAGE_INSTANCE {
+ UINTN Signature;
+ EFI_HII_FONT_PACKAGE_HDR *FontPkgHdr;
+ UINT16 Height;
+ UINT16 BaseLine;
+ UINT8 *GlyphBlock;
+ LIST_ENTRY FontEntry;
+ LIST_ENTRY GlyphInfoList;
+} HII_FONT_PACKAGE_INSTANCE;
+
+#define HII_GLYPH_INFO_SIGNATURE SIGNATURE_32 ('h','g','i','s')
+typedef struct _HII_GLYPH_INFO {
+ UINTN Signature;
+ LIST_ENTRY Entry;
+ CHAR16 CharId;
+ EFI_HII_GLYPH_INFO Cell;
+} HII_GLYPH_INFO;
+
+#define HII_FONT_INFO_SIGNATURE SIGNATURE_32 ('h','l','f','i')
+typedef struct _HII_FONT_INFO {
+ UINTN Signature;
+ LIST_ENTRY Entry;
+ LIST_ENTRY *GlobalEntry;
+ UINT8 FontId;
+} HII_FONT_INFO;
+
+#define HII_GLOBAL_FONT_INFO_SIGNATURE SIGNATURE_32 ('h','g','f','i')
+typedef struct _HII_GLOBAL_FONT_INFO {
+ UINTN Signature;
+ LIST_ENTRY Entry;
+ HII_FONT_PACKAGE_INSTANCE *FontPackage;
+ UINTN FontInfoSize;
+ EFI_FONT_INFO *FontInfo;
+} HII_GLOBAL_FONT_INFO;
+
+//
+// Image Package definitions
+//
+
+#define HII_PIXEL_MASK 0x80
+
+typedef struct _HII_IMAGE_PACKAGE_INSTANCE {
+ EFI_HII_IMAGE_PACKAGE_HDR ImagePkgHdr;
+ UINT32 ImageBlockSize;
+ UINT32 PaletteInfoSize;
+ EFI_HII_IMAGE_BLOCK *ImageBlock;
+ UINT8 *PaletteBlock;
+} HII_IMAGE_PACKAGE_INSTANCE;
+
+//
+// Keyboard Layout Package definitions
+//
+#define HII_KB_LAYOUT_PACKAGE_SIGNATURE SIGNATURE_32 ('h','k','l','p')
+typedef struct _HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE {
+ UINTN Signature;
+ UINT8 *KeyboardPkg;
+ LIST_ENTRY KeyboardEntry;
+} HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE;
+
+//
+// Guid Package definitions
+//
+#define HII_GUID_PACKAGE_SIGNATURE SIGNATURE_32 ('h','i','g','p')
+typedef struct _HII_GUID_PACKAGE_INSTANCE {
+ UINTN Signature;
+ UINT8 *GuidPkg;
+ LIST_ENTRY GuidEntry;
+} HII_GUID_PACKAGE_INSTANCE;
+
+//
+// A package list can contain only one or less than one device path package.
+// This rule also applies to image package since ImageId can not be duplicate.
+//
+typedef struct _HII_DATABASE_PACKAGE_LIST_INSTANCE {
+ EFI_HII_PACKAGE_LIST_HEADER PackageListHdr;
+ LIST_ENTRY GuidPkgHdr;
+ LIST_ENTRY FormPkgHdr;
+ LIST_ENTRY KeyboardLayoutHdr;
+ LIST_ENTRY StringPkgHdr;
+ LIST_ENTRY FontPkgHdr;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePkg;
+ LIST_ENTRY SimpleFontPkgHdr;
+ UINT8 *DevicePathPkg;
+} HII_DATABASE_PACKAGE_LIST_INSTANCE;
+
+#define HII_HANDLE_SIGNATURE SIGNATURE_32 ('h','i','h','l')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Handle;
+ UINTN Key;
+} HII_HANDLE;
+
+#define HII_DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('h','i','d','r')
+
+typedef struct _HII_DATABASE_RECORD {
+ UINTN Signature;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE Handle;
+ LIST_ENTRY DatabaseEntry;
+} HII_DATABASE_RECORD;
+
+#define HII_DATABASE_NOTIFY_SIGNATURE SIGNATURE_32 ('h','i','d','n')
+
+typedef struct _HII_DATABASE_NOTIFY {
+ UINTN Signature;
+ EFI_HANDLE NotifyHandle;
+ UINT8 PackageType;
+ EFI_GUID *PackageGuid;
+ EFI_HII_DATABASE_NOTIFY PackageNotifyFn;
+ EFI_HII_DATABASE_NOTIFY_TYPE NotifyType;
+ LIST_ENTRY DatabaseNotifyEntry;
+} HII_DATABASE_NOTIFY;
+
+#define HII_DATABASE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('H', 'i', 'D', 'p')
+
+typedef struct _HII_DATABASE_PRIVATE_DATA {
+ UINTN Signature;
+ LIST_ENTRY DatabaseList;
+ LIST_ENTRY DatabaseNotifyList;
+ EFI_HII_FONT_PROTOCOL HiiFont;
+ EFI_HII_IMAGE_PROTOCOL HiiImage;
+ EFI_HII_IMAGE_EX_PROTOCOL HiiImageEx;
+ EFI_HII_STRING_PROTOCOL HiiString;
+ EFI_HII_DATABASE_PROTOCOL HiiDatabase;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL ConfigRouting;
+ EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL ConfigKeywordHandler;
+ LIST_ENTRY HiiHandleList;
+ INTN HiiHandleCount;
+ LIST_ENTRY FontInfoList; // global font info list
+ UINTN Attribute; // default system color
+ EFI_GUID CurrentLayoutGuid;
+ EFI_HII_KEYBOARD_LAYOUT *CurrentLayout;
+} HII_DATABASE_PRIVATE_DATA;
+
+#define HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ HiiFont, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ HiiImage, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ HiiImageEx, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ HiiString, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ HiiDatabase, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ ConfigRouting, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define CONFIG_KEYWORD_HANDLER_DATABASE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ HII_DATABASE_PRIVATE_DATA, \
+ ConfigKeywordHandler, \
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE \
+ )
+
+//
+// Internal function prototypes.
+//
+
+/**
+ Generate a sub string then output it.
+
+ This is a internal function.
+
+ @param String A constant string which is the prefix of the to be
+ generated string, e.g. GUID=
+
+ @param BufferLen The length of the Buffer in bytes.
+
+ @param Buffer Points to a buffer which will be converted to be the
+ content of the generated string.
+
+ @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
+ UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
+ if 3, the buffer contains other data.
+
+ @param SubStr Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+
+**/
+VOID
+GenerateSubStr (
+ IN CONST EFI_STRING String,
+ IN UINTN BufferLen,
+ IN VOID *Buffer,
+ IN UINT8 Flag,
+ OUT EFI_STRING *SubStr
+ );
+
+/**
+ This function checks whether a handle is a valid EFI_HII_HANDLE.
+
+ @param Handle Pointer to a EFI_HII_HANDLE
+
+ @retval TRUE Valid
+ @retval FALSE Invalid
+
+**/
+BOOLEAN
+IsHiiHandleValid (
+ EFI_HII_HANDLE Handle
+ );
+
+
+/**
+ This function checks whether EFI_FONT_INFO exists in current database. If
+ FontInfoMask is specified, check what options can be used to make a match.
+ Note that the masks relate to where the system default should be supplied
+ are ignored by this function.
+
+ @param Private Hii database private structure.
+ @param FontInfo Points to EFI_FONT_INFO structure.
+ @param FontInfoMask If not NULL, describes what options can be used
+ to make a match between the font requested and
+ the font available. The caller must guarantee
+ this mask is valid.
+ @param FontHandle On entry, Points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font.
+ @param GlobalFontInfo If not NULL, output the corresponding global font
+ info.
+
+ @retval TRUE Existed
+ @retval FALSE Not existed
+
+**/
+BOOLEAN
+IsFontInfoExisted (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_FONT_INFO *FontInfo,
+ IN EFI_FONT_INFO_MASK *FontInfoMask, OPTIONAL
+ IN EFI_FONT_HANDLE FontHandle, OPTIONAL
+ OUT HII_GLOBAL_FONT_INFO **GlobalFontInfo OPTIONAL
+ );
+
+/**
+
+ This function invokes the matching registered function.
+
+ @param Private HII Database driver private structure.
+ @param NotifyType The type of change concerning the database.
+ @param PackageInstance Points to the package referred to by the notification.
+ @param PackageType Package type
+ @param Handle The handle of the package list which contains the specified package.
+
+ @retval EFI_SUCCESS Already checked all registered function and invoked
+ if matched.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+EFI_STATUS
+InvokeRegisteredFunction (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN VOID *PackageInstance,
+ IN UINT8 PackageType,
+ IN EFI_HII_HANDLE Handle
+ )
+;
+
+/**
+ Retrieve system default font and color.
+
+ @param Private HII database driver private data.
+ @param FontInfo Points to system default font output-related
+ information. It's caller's responsibility to free
+ this buffer.
+ @param FontInfoSize If not NULL, output the size of buffer FontInfo.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+GetSystemFont (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ OUT EFI_FONT_DISPLAY_INFO **FontInfo,
+ OUT UINTN *FontInfoSize OPTIONAL
+ );
+
+
+/**
+ Parse all string blocks to find a String block specified by StringId.
+ If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks
+ within this string package and backup its information. If LastStringId is
+ specified, the string id of last string block will also be output.
+ If StringId = 0, output the string id of last string block (EFI_HII_SIBT_STRING).
+
+ @param Private Hii database private structure.
+ @param StringPackage Hii string package instance.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param BlockType Output the block type of found string block.
+ @param StringBlockAddr Output the block address of found string block.
+ @param StringTextOffset Offset, relative to the found block address, of
+ the string text information.
+ @param LastStringId Output the last string id when StringId = 0 or StringId = -1.
+ @param StartStringId The first id in the skip block which StringId in the block.
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindStringBlock (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT UINT8 *BlockType, OPTIONAL
+ OUT UINT8 **StringBlockAddr, OPTIONAL
+ OUT UINTN *StringTextOffset, OPTIONAL
+ OUT EFI_STRING_ID *LastStringId, OPTIONAL
+ OUT EFI_STRING_ID *StartStringId OPTIONAL
+ );
+
+
+/**
+ Parse all glyph blocks to find a glyph block specified by CharValue.
+ If CharValue = (CHAR16) (-1), collect all default character cell information
+ within this font package and backup its information.
+
+ @param FontPackage Hii string package instance.
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphBuffer Output the corresponding bitmap data of the found
+ block. It is the caller's responsibility to free
+ this buffer.
+ @param Cell Output cell information of the encoded bitmap.
+ @param GlyphBufferLen If not NULL, output the length of GlyphBuffer.
+
+ @retval EFI_SUCCESS The bitmap data is retrieved successfully.
+ @retval EFI_NOT_FOUND The specified CharValue does not exist in current
+ database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindGlyphBlock (
+ IN HII_FONT_PACKAGE_INSTANCE *FontPackage,
+ IN CHAR16 CharValue,
+ OUT UINT8 **GlyphBuffer, OPTIONAL
+ OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL
+ OUT UINTN *GlyphBufferLen OPTIONAL
+ );
+
+/**
+ This function exports Form packages to a buffer.
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Form Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+ExportFormPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ );
+
+//
+// EFI_HII_FONT_PROTOCOL protocol interfaces
+//
+
+
+/**
+ Renders a string to a bitmap or to the display.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param String Points to the null-terminated string to be
+ displayed.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Together with BltX, Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param BltY Together with BltY, Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller's responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The String or Blt.
+ @retval EFI_INVALID_PARAMETER Flags were invalid combination..
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ );
+
+
+/**
+ Render a string to a bitmap or the screen containing the contents of the specified string.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param PackageList The package list in the HII database to search
+ for the specified string.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param Language Points to the language for the retrieved string.
+ If NULL, then the current system language is
+ used.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Together with BltX, Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param BltY Together with BltY, Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller's responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The Blt or PackageList was NULL.
+ @retval EFI_INVALID_PARAMETER Flags were invalid combination.
+ @retval EFI_NOT_FOUND The specified PackageList is not in the Database or the stringid is not
+ in the specified PackageList.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringIdToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8* Language,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ );
+
+
+/**
+ Convert the glyph for a single character into a bitmap.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Char Character to retrieve.
+ @param StringInfo Points to the string font and color information
+ or NULL if the string should use the default
+ system font and color.
+ @param Blt Thus must point to a NULL on entry. A buffer will
+ be allocated to hold the output and the pointer
+ updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param Baseline Number of pixels from the bottom of the bitmap to
+ the baseline.
+
+ @retval EFI_SUCCESS Glyph bitmap created.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer Blt.
+ @retval EFI_WARN_UNKNOWN_GLYPH The glyph was unknown and was replaced with the
+ glyph for Unicode character 0xFFFD.
+ @retval EFI_INVALID_PARAMETER Blt is NULL or *Blt is not NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetGlyph (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN CHAR16 Char,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo,
+ OUT EFI_IMAGE_OUTPUT **Blt,
+ OUT UINTN *Baseline OPTIONAL
+ );
+
+
+/**
+ This function iterates through fonts which match the specified font, using
+ the specified criteria. If String is non-NULL, then all of the characters in
+ the string must exist in order for a candidate font to be returned.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param FontHandle On entry, points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font. On return, points to the
+ returned font handle or points to NULL if there
+ are no more matching fonts.
+ @param StringInfoIn Upon entry, points to the font to return information
+ about. If NULL, then the information about the system
+ default font will be returned.
+ @param StringInfoOut Upon return, contains the matching font's information.
+ If NULL, then no information is returned. This buffer
+ is allocated with a call to the Boot Service AllocatePool().
+ It is the caller's responsibility to call the Boot
+ Service FreePool() when the caller no longer requires
+ the contents of StringInfoOut.
+ @param String Points to the string which will be tested to
+ determine if all characters are available. If
+ NULL, then any font is acceptable.
+
+ @retval EFI_SUCCESS Matching font returned successfully.
+ @retval EFI_NOT_FOUND No matching font was found.
+ @retval EFI_INVALID_PARAMETER StringInfoIn is NULL.
+ @retval EFI_INVALID_PARAMETER StringInfoIn->FontInfoMask is an invalid combination.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+**/
+EFI_STATUS
+EFIAPI
+HiiGetFontInfo (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN OUT EFI_FONT_HANDLE *FontHandle,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfoIn, OPTIONAL
+ OUT EFI_FONT_DISPLAY_INFO **StringInfoOut,
+ IN CONST EFI_STRING String OPTIONAL
+ );
+
+//
+// EFI_HII_IMAGE_PROTOCOL interfaces
+//
+
+/**
+ Get the image id of last image block: EFI_HII_IIBT_END_BLOCK when input
+ ImageId is zero, otherwise return the address of the
+ corresponding image block with identifier specified by ImageId.
+
+ This is a internal function.
+
+ @param ImageBlocks Points to the beginning of a series of image blocks stored in order.
+ @param ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
+ else use this id to find its corresponding image block address.
+
+ @return The image block address when input ImageId is not zero; otherwise return NULL.
+
+**/
+EFI_HII_IMAGE_BLOCK *
+GetImageIdOrAddress (
+ IN EFI_HII_IMAGE_BLOCK *ImageBlocks,
+ IN OUT EFI_IMAGE_ID *ImageId
+ );
+
+/**
+ Return the HII package list identified by PackageList HII handle.
+
+ @param Database Pointer to HII database list header.
+ @param PackageList HII handle of the package list to locate.
+
+ @retval The HII package list instance.
+**/
+HII_DATABASE_PACKAGE_LIST_INSTANCE *
+LocatePackageList (
+ IN LIST_ENTRY *Database,
+ IN EFI_HII_HANDLE PackageList
+ );
+
+/**
+ This function retrieves the image specified by ImageId which is associated with
+ the specified PackageList and copies it into the buffer specified by Image.
+
+ @param Database A pointer to the database list header.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+ @param BitmapOnly TRUE to only return the bitmap type image.
+ FALSE to locate image decoder instance to decode image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
+ enough memory.
+**/
+EFI_STATUS
+IGetImage (
+ IN LIST_ENTRY *Database,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image,
+ IN BOOLEAN BitmapOnly
+ );
+
+/**
+ Return the first HII image decoder instance which supports the DecoderName.
+
+ @param BlockType The image block type.
+
+ @retval Pointer to the HII image decoder instance.
+**/
+EFI_HII_IMAGE_DECODER_PROTOCOL *
+LocateHiiImageDecoder (
+ UINT8 BlockType
+ );
+
+/**
+ This function adds the image Image to the group of images owned by PackageList, and returns
+ a new image identifier (ImageId).
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be added.
+ @param ImageId On return, contains the new image id, which is
+ unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_IMAGE_ID *ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ );
+
+
+/**
+ This function retrieves the image specified by ImageId which is associated with
+ the specified PackageList and copies it into the buffer specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not available.
+ The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
+ enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image
+ );
+
+
+/**
+ This function updates the image specified by ImageId in the specified PackageListHandle to
+ the image specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList The package list containing the images.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was updated successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ );
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param Image Points to the image to be displayed.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The image will be drawn
+ onto this image and EFI_HII_DRAW_FLAG_CLIP is
+ implied. If this points to a NULL on entry, then
+ a buffer will be allocated to hold the generated
+ image and the pointer updated on exit. It is the
+ caller's responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge
+ of the output image of the first pixel in the
+ image.
+ @param BltY Specifies the offset from the left and top edge
+ of the output image of the first pixel in the
+ image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
+ @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN CONST EFI_IMAGE_INPUT *Image,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ );
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param PackageList The package list in the HII database to search
+ for the specified image.
+ @param ImageId The image's id, which is unique within
+ PackageList.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The image will be drawn
+ onto this image and
+ EFI_HII_DRAW_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer will be
+ allocated to hold the generated image and the
+ pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge
+ of the output image of the first pixel in the
+ image.
+ @param BltY Specifies the offset from the left and top edge
+ of the output image of the first pixel in the
+ image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Blt was NULL.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
+ The specified PackageList is not in the database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageId (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ );
+
+/**
+ The prototype of this extension function is the same with EFI_HII_IMAGE_PROTOCOL.NewImage().
+ This protocol invokes EFI_HII_IMAGE_PROTOCOL.NewImage() implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be added.
+ @param ImageId On return, contains the new image id, which is
+ unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was added successfully.
+ @retval EFI_NOT_FOUND The PackageList could not be found.
+ @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
+**/
+EFI_STATUS
+EFIAPI
+HiiNewImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_IMAGE_ID *ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ );
+
+/**
+ Return the information about the image, associated with the package list.
+ The prototype of this extension function is the same with EFI_HII_IMAGE_PROTOCOL.GetImage().
+
+ This function is similar to EFI_HII_IMAGE_PROTOCOL.GetImage(). The difference is that
+ this function will locate all EFI_HII_IMAGE_DECODER_PROTOCOL instances installed in the
+ system if the decoder of the certain image type is not supported by the
+ EFI_HII_IMAGE_EX_PROTOCOL. The function will attempt to decode the image to the
+ EFI_IMAGE_INPUT using the first EFI_HII_IMAGE_DECODER_PROTOCOL instance that
+ supports the requested image type.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList The package list in the HII database to search for the
+ specified image.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not available. The specified
+ PackageList is not in the Database.
+ @retval EFI_INVALID_PARAMETER Image was NULL or ImageId was 0.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there
+ was not enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image
+ );
+
+/**
+ Change the information about the image.
+
+ Same with EFI_HII_IMAGE_PROTOCOL.SetImage(), this protocol invokes
+ EFI_HII_IMAGE_PROTOCOL.SetImage()implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList The package list containing the images.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was successfully updated.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in
+ the database.
+ @retval EFI_INVALID_PARAMETER The Image was NULL, the ImageId was 0 or
+ the Image->Bitmap was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ );
+
+/**
+ Renders an image to a bitmap or to the display.
+
+ The prototype of this extension function is the same with
+ EFI_HII_IMAGE_PROTOCOL.DrawImage(). This protocol invokes
+ EFI_HII_IMAGE_PROTOCOL.DrawImage() implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param Image Points to the image to be displayed.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN CONST EFI_IMAGE_INPUT *Image,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ );
+
+/**
+ Renders an image to a bitmap or the screen containing the contents of the specified
+ image.
+
+ This function is similar to EFI_HII_IMAGE_PROTOCOL.DrawImageId(). The difference is that
+ this function will locate all EFI_HII_IMAGE_DECODER_PROTOCOL instances installed in the
+ system if the decoder of the certain image type is not supported by the
+ EFI_HII_IMAGE_EX_PROTOCOL. The function will attempt to decode the image to the
+ EFI_IMAGE_INPUT using the first EFI_HII_IMAGE_DECODER_PROTOCOL instance that
+ supports the requested image type.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param PackageList The package list in the HII database to search for
+ the specified image.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image
+ and the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Blt was NULL or ImageId was 0.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
+ The specified PackageList is not in the database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageIdEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ );
+
+/**
+ This function returns the image information to EFI_IMAGE_OUTPUT. Only the width
+ and height are returned to the EFI_IMAGE_OUTPUT instead of decoding the image
+ to the buffer. This function is used to get the geometry of the image. This function
+ will try to locate all of the EFI_HII_IMAGE_DECODER_PROTOCOL installed on the
+ system if the decoder of image type is not supported by the EFI_HII_IMAGE_EX_PROTOCOL.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image was NULL or the ImageId was 0.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there
+ was not enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImageInfo (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_OUTPUT *Image
+ );
+//
+// EFI_HII_STRING_PROTOCOL
+//
+
+
+/**
+ This function adds the string String to the group of strings owned by PackageList, with the
+ specified font information StringFontInfo and returns a new string id.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL
+ instance.
+ @param PackageList Handle of the package list where this string will
+ be added.
+ @param StringId On return, contains the new strings id, which is
+ unique within PackageList.
+ @param Language Points to the language for the new string.
+ @param LanguageName Points to the printable language name to
+ associate with the passed in Language field.If
+ LanguageName is not NULL and the string package
+ header's LanguageName associated with a given
+ Language is not zero, the LanguageName being
+ passed in will be ignored.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the new string's font information or
+ NULL if the string should have the default system
+ font, size and style.
+
+ @retval EFI_SUCCESS The new string was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of
+ resources.
+ @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL or Language is
+ NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_STRING_ID *StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST CHAR16 *LanguageName, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ );
+
+
+/**
+ This function retrieves the string specified by StringId which is associated
+ with the specified PackageList in the language Language and copies it into
+ the buffer specified by String.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL
+ instance.
+ @param Language Points to the language for the retrieved string.
+ @param PackageList The package list in the HII database to search
+ for the specified string.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param String Points to the new null-terminated string.
+ @param StringSize On entry, points to the size of the buffer
+ pointed to by String, in bytes. On return,
+ points to the length of the string, in bytes.
+ @param StringFontInfo If not NULL, points to the string's font
+ information. It's caller's responsibility to
+ free this buffer.
+
+ @retval EFI_SUCCESS The string was returned successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not
+ available.
+ The specified PackageList is not in the database.
+ @retval EFI_INVALID_LANGUAGE The string specified by StringId is available but
+ not in the specified language.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small
+ to hold the string.
+ @retval EFI_INVALID_PARAMETER The Language or StringSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by StringSize was not zero
+ and String was NULL.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN CONST CHAR8 *Language,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING String,
+ IN OUT UINTN *StringSize,
+ OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
+ );
+
+
+/**
+ This function updates the string specified by StringId in the specified PackageList to the text
+ specified by String and, optionally, the font information specified by StringFontInfo.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL
+ instance.
+ @param PackageList The package list containing the strings.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param Language Points to the language for the updated string.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the string's font information or NULL
+ if the string font information is not changed.
+
+ @retval EFI_SUCCESS The string was updated successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The String or Language was NULL.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ );
+
+
+/**
+ This function returns the list of supported languages, in the format specified
+ in Appendix M of UEFI 2.1 spec.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL
+ instance.
+ @param PackageList The package list to examine.
+ @param Languages Points to the buffer to hold the returned
+ null-terminated ASCII string.
+ @param LanguagesSize On entry, points to the size of the buffer
+ pointed to by Languages, in bytes. On return,
+ points to the length of Languages, in bytes.
+
+ @retval EFI_SUCCESS The languages were returned successfully.
+ @retval EFI_INVALID_PARAMETER The LanguagesSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by LanguagesSize is not zero and Languages is NULL.
+ @retval EFI_BUFFER_TOO_SMALL The LanguagesSize is too small to hold the list
+ of supported languages. LanguageSize is updated
+ to contain the required size.
+ @retval EFI_NOT_FOUND Could not find string package in specified
+ packagelist.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN OUT CHAR8 *Languages,
+ IN OUT UINTN *LanguagesSize
+ );
+
+
+/**
+ Each string package has associated with it a single primary language and zero
+ or more secondary languages. This routine returns the secondary languages
+ associated with a package list.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL
+ instance.
+ @param PackageList The package list to examine.
+ @param PrimaryLanguage Points to the null-terminated ASCII string that specifies
+ the primary language. Languages are specified in the
+ format specified in Appendix M of the UEFI 2.0 specification.
+ @param SecondaryLanguages Points to the buffer to hold the returned null-terminated
+ ASCII string that describes the list of
+ secondary languages for the specified
+ PrimaryLanguage. If there are no secondary
+ languages, the function returns successfully,
+ but this is set to NULL.
+ @param SecondaryLanguagesSize On entry, points to the size of the buffer
+ pointed to by SecondaryLanguages, in bytes. On
+ return, points to the length of SecondaryLanguages
+ in bytes.
+
+ @retval EFI_SUCCESS Secondary languages were correctly returned.
+ @retval EFI_INVALID_PARAMETER PrimaryLanguage or SecondaryLanguagesSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by SecondaryLanguagesSize is not
+ zero and SecondaryLanguages is NULL.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by SecondaryLanguagesSize is
+ too small to hold the returned information.
+ SecondaryLanguageSize is updated to hold the size of
+ the buffer required.
+ @retval EFI_INVALID_LANGUAGE The language specified by PrimaryLanguage is not
+ present in the specified package list.
+ @retval EFI_NOT_FOUND The specified PackageList is not in the Database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetSecondaryLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN CONST CHAR8 *PrimaryLanguage,
+ IN OUT CHAR8 *SecondaryLanguages,
+ IN OUT UINTN *SecondaryLanguagesSize
+ );
+
+//
+// EFI_HII_DATABASE_PROTOCOL protocol interfaces
+//
+
+
+/**
+ This function adds the packages in the package list to the database and returns a handle. If there is a
+ EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will
+ create a package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ structure.
+ @param DriverHandle Associate the package list with this EFI handle.
+ If a NULL is specified, this data will not be associate
+ with any drivers and cannot have a callback induced.
+ @param Handle A pointer to the EFI_HII_HANDLE instance.
+
+ @retval EFI_SUCCESS The package list associated with the Handle was
+ added to the HII database.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the
+ new database contents.
+ @retval EFI_INVALID_PARAMETER PackageList is NULL or Handle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewPackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+ IN CONST EFI_HANDLE DriverHandle, OPTIONAL
+ OUT EFI_HII_HANDLE *Handle
+ );
+
+
+/**
+ This function removes the package list that is associated with a handle Handle
+ from the HII database. Before removing the package, any registered functions
+ with the notification type REMOVE_PACK and the same package type will be called.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that
+ is requested for removal.
+
+ @retval EFI_SUCCESS The data associated with the Handle was removed
+ from the HII database.
+ @retval EFI_NOT_FOUND The specified Handle is not in database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRemovePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle
+ );
+
+
+/**
+ This function updates the existing package list (which has the specified Handle)
+ in the HII databases, using the new package list specified by PackageList.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that
+ is requested to be updated.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ package.
+
+ @retval EFI_SUCCESS The HII database was successfully updated.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate enough memory for the updated
+ database.
+ @retval EFI_INVALID_PARAMETER PackageList was NULL.
+ @retval EFI_NOT_FOUND The specified Handle is not in database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdatePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList
+ );
+
+
+/**
+ This function returns a list of the package handles of the specified type
+ that are currently active in the database. The pseudo-type
+ EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to
+ list or EFI_HII_PACKAGE_TYPE_ALL for all packages
+ to be listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR.
+ Otherwise, it must be NULL.
+ @param HandleBufferLength On input, a pointer to the length of the handle
+ buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param Handle An array of EFI_HII_HANDLE instances returned.
+
+ @retval EFI_SUCCESS The matching handles are outputted successfully.
+ HandleBufferLength is updated with the actual length.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with a
+ value that will enable the data to fit.
+ @retval EFI_NOT_FOUND No matching handle could not be found in
+ database.
+ @retval EFI_INVALID_PARAMETER HandleBufferLength was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by HandleBufferLength was not
+ zero and Handle was NULL.
+ @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but
+ PackageGuid is not NULL, PackageType is a EFI_HII_
+ PACKAGE_TYPE_GUID but PackageGuid is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiListPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN OUT UINTN *HandleBufferLength,
+ OUT EFI_HII_HANDLE *Handle
+ );
+
+
+/**
+ This function will export one or all package lists in the database to a buffer.
+ For each package list exported, this function will call functions registered
+ with EXPORT_PACK and then copy the package list to the buffer.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HII database to export or
+ NULL to indicate all package lists should be
+ exported.
+ @param BufferSize On input, a pointer to the length of the buffer.
+ On output, the length of the buffer that is
+ required for the exported data.
+ @param Buffer A pointer to a buffer that will contain the
+ results of the export function.
+
+ @retval EFI_SUCCESS Package exported.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with
+ a value that will enable the data to fit.
+ @retval EFI_NOT_FOUND The specified Handle could not be found in the
+ current database.
+ @retval EFI_INVALID_PARAMETER BufferSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by BufferSize was not zero
+ and Buffer was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiExportPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
+ );
+
+
+/**
+ This function registers a function which will be called when specified actions related to packages of
+ the specified type occur in the HII database. By registering a function, other HII-related drivers are
+ notified when specific package types are added, removed or updated in the HII database.
+ Each driver or application which registers a notification should use
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before exiting.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to
+ list or EFI_HII_PACKAGE_TYPE_ALL for all packages
+ to be listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of
+ EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must
+ be NULL.
+ @param PackageNotifyFn Points to the function to be called when the
+ event specified by
+ NotificationType occurs.
+ @param NotifyType Describes the types of notification which this
+ function will be receiving.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification. Can be used in
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify()
+ to stop notifications.
+
+ @retval EFI_SUCCESS Notification registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+ @retval EFI_INVALID_PARAMETER NotifyHandle is NULL.
+ @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when PackageType is not
+ EFI_HII_PACKAGE_TYPE_GUID.
+ @retval EFI_INVALID_PARAMETER PackageGuid is NULL when PackageType is
+ EFI_HII_PACKAGE_TYPE_GUID.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRegisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN CONST EFI_HII_DATABASE_NOTIFY PackageNotifyFn,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ OUT EFI_HANDLE *NotifyHandle
+ );
+
+
+/**
+ Removes the specified HII database package-related notification.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param NotificationHandle The handle of the notification function being
+ unregistered.
+
+ @retval EFI_SUCCESS Notification is unregistered successfully.
+ @retval EFI_NOT_FOUND The incoming notification handle does not exist
+ in current hii database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUnregisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ );
+
+
+/**
+ This routine retrieves an array of GUID values for each keyboard layout that
+ was previously registered in the system.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuidBufferLength On input, a pointer to the length of the keyboard
+ GUID buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param KeyGuidBuffer An array of keyboard layout GUID instances
+ returned.
+
+ @retval EFI_SUCCESS KeyGuidBuffer was updated successfully.
+ @retval EFI_BUFFER_TOO_SMALL The KeyGuidBufferLength parameter indicates
+ that KeyGuidBuffer is too small to support the
+ number of GUIDs. KeyGuidBufferLength is
+ updated with a value that will enable the data to
+ fit.
+ @retval EFI_INVALID_PARAMETER The KeyGuidBufferLength is NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by KeyGuidBufferLength is not
+ zero and KeyGuidBuffer is NULL.
+ @retval EFI_NOT_FOUND There was no keyboard layout.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiFindKeyboardLayouts (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN OUT UINT16 *KeyGuidBufferLength,
+ OUT EFI_GUID *KeyGuidBuffer
+ );
+
+
+/**
+ This routine retrieves the requested keyboard layout. The layout is a physical description of the keys
+ on a keyboard and the character(s) that are associated with a particular set of key strokes.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a
+ given keyboard layout. If KeyGuid is NULL then
+ the current layout will be retrieved.
+ @param KeyboardLayoutLength On input, a pointer to the length of the
+ KeyboardLayout buffer. On output, the length of
+ the data placed into KeyboardLayout.
+ @param KeyboardLayout A pointer to a buffer containing the retrieved
+ keyboard layout.
+
+ @retval EFI_SUCCESS The keyboard layout was retrieved successfully.
+ @retval EFI_NOT_FOUND The requested keyboard layout was not found.
+ @retval EFI_INVALID_PARAMETER The KeyboardLayout or KeyboardLayoutLength was
+ NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid,
+ IN OUT UINT16 *KeyboardLayoutLength,
+ OUT EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout
+ );
+
+
+/**
+ This routine sets the default keyboard layout to the one referenced by KeyGuid. When this routine
+ is called, an event will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+ group type. This is so that agents which are sensitive to the current keyboard layout being changed
+ can be notified of this change.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a
+ given keyboard layout.
+
+ @retval EFI_SUCCESS The current keyboard layout was successfully set.
+ @retval EFI_NOT_FOUND The referenced keyboard layout was not found, so
+ action was taken.
+ @retval EFI_INVALID_PARAMETER The KeyGuid was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid
+ );
+
+
+/**
+ Return the EFI handle associated with a package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageListHandle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HIIdatabase.
+ @param DriverHandle On return, contains the EFI_HANDLE which was
+ registered with the package list in
+ NewPackageList().
+
+ @retval EFI_SUCCESS The DriverHandle was returned successfully.
+ @retval EFI_INVALID_PARAMETER The PackageListHandle was not valid or
+ DriverHandle was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetPackageListHandle (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageListHandle,
+ OUT EFI_HANDLE *DriverHandle
+ );
+
+//
+// EFI_HII_CONFIG_ROUTING_PROTOCOL interfaces
+//
+
+
+/**
+ This function allows a caller to extract the current configuration
+ for one or more named elements from one or more drivers.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> 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 Null-terminated Unicode string in
+ <MultiConfigAltResp> 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 string is filled with the values
+ corresponding to all requested names.
+ @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_NOT_FOUND Routing data doesn't match any known driver.
+ Progress set to the "G" in "GUID" of the
+ routing header that doesn't match. Note: There
+ is no requirement that all routing data
+ be validated before any configuration extraction.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
+ parameter would result in this type of error. The
+ Progress parameter is set to NULL.
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
+ before the error or the beginning of the string.
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
+ name in question.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExtractConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+
+/**
+ This function allows the caller to request the current configuration for the
+ entirety of the current HII database and returns the data in a null-terminated Unicode string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the entirety of the current HII
+ database. String to be allocated by the called
+ function. De-allocation is up to the caller.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @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_PARAMETER For example, passing in a NULL for the Results
+ parameter would result in this type of error.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExportConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ OUT EFI_STRING *Results
+ );
+
+
+/**
+ This function processes the results of processing forms and routes it to the
+ appropriate handlers or storage.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MulltiConfigResp> 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 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_PARAMETER Passing in a NULL for the Configuration parameter
+ would result in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingRouteConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+
+
+/**
+ This helper function is to be called by drivers to map configuration data stored
+ in byte array ("block") formats such as UEFI Variables into current configuration strings.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigRequest A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Block Array of bytes defining the block's
+ configuration.
+ @param BlockSize Length in bytes of Block.
+ @param Config Filled-in configuration string. String allocated
+ by the function. Returned only if call is
+ successful.
+ @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 request succeeded. Progress points to the
+ null terminator at the end of the ConfigRequest
+ string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config.
+ Progress points to the first character of
+ ConfigRequest.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigRequest.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found. Progress points to the "G" in "GUID" of
+ the errant routing data.
+ @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
+ Block is left updated and Progress points at
+ the '&' preceding the first non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiBlockToConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN CONST UINTN BlockSize,
+ OUT EFI_STRING *Config,
+ OUT EFI_STRING *Progress
+ );
+
+
+/**
+ This helper function is to be called by drivers to map configuration strings
+ to configurations stored in byte array ("block") formats such as UEFI Variables.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigResp A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Block A possibly null array of bytes representing the
+ current block. Only bytes referenced in the
+ ConfigResp string in the block are modified. If
+ this parameter is null or if the *BlockSize
+ parameter is (on input) shorter than required by
+ the Configuration string, only the BlockSize
+ parameter is updated and an appropriate status
+ (see below) is returned.
+ @param BlockSize The length of the Block in units of UINT8. On
+ input, this is the size of the Block. On output,
+ if successful, contains the largest index of the
+ modified byte in the Block, or the required buffer
+ size if the Block is not large enough.
+ @param Progress On return, points to an element of the ConfigResp
+ 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 request succeeded. Progress points to the
+ null terminator at the end of the ConfigResp
+ string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config.
+ Progress points to the first character of
+ ConfigResp.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigResp.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found. Progress points to the "G" in "GUID" of
+ the errant routing data.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
+ value pair. Block is left updated and
+ Progress points at the '&' preceding the first
+ non-<BlockName>.
+ @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined.
+ BlockSize is updated with the required buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigToBlock (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigResp,
+ IN OUT UINT8 *Block,
+ IN OUT UINTN *BlockSize,
+ OUT EFI_STRING *Progress
+ );
+
+
+/**
+ This helper function is to be called by drivers to extract portions of
+ a larger configuration string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MultiConfigAltResp> format.
+ @param Guid A pointer to the GUID value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Guid is NULL,
+ then all GUID values will be searched for.
+ @param Name A pointer to the NAME value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Name is NULL,
+ then all Name values will be searched for.
+ @param DevicePath A pointer to the PATH value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If DevicePath is
+ NULL, then all DevicePath values will be
+ searched for.
+ @param AltCfgId A pointer to the ALTCFG value to search for in
+ the routing portion of the ConfigResp string
+ when retrieving the requested data. If this
+ parameter is NULL, then the current setting will
+ be retrieved.
+ @param AltCfgResp A pointer to a buffer which will be allocated by
+ the function which contains the retrieved string
+ as requested. This buffer is only allocated if
+ the call was successful.
+
+ @retval EFI_SUCCESS The request succeeded. The requested data was
+ extracted and placed in the newly allocated
+ AltCfgResp buffer.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetAltCfg (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ IN CONST EFI_GUID *Guid,
+ IN CONST EFI_STRING Name,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONST UINT16 *AltCfgId,
+ OUT EFI_STRING *AltCfgResp
+ );
+
+/**
+
+ This function accepts a <MultiKeywordResp> formatted string, finds the associated
+ keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
+ EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
+
+ If there is an issue in resolving the contents of the KeywordString, then the
+ function returns an error and also sets the Progress and ProgressErr with the
+ appropriate information about where the issue occurred and additional data about
+ the nature of the issue.
+
+ In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
+ error is generated during processing the second or later keyword element, the system
+ storage associated with earlier keywords is not modified. All elements of the
+ KeywordString must successfully pass all tests for format and access prior to making
+ any modifications to storage.
+
+ In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
+ containing multiple keywords, the state of storage associated with earlier keywords
+ is undefined.
+
+
+ @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
+
+ @param KeywordString A null-terminated string in <MultiKeywordResp> format.
+
+ @param Progress On return, points to a character in the KeywordString.
+ Points to the string's NULL terminator if the 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 ProgressErr If during the processing of the KeywordString there was
+ a failure, this parameter gives additional information
+ about the possible source of the problem. The various
+ errors are defined in "Related Definitions" below.
+
+
+ @retval EFI_SUCCESS The specified action was completed successfully.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ 1. KeywordString is NULL.
+ 2. Parsing of the KeywordString resulted in an
+ error. See Progress and ProgressErr for more data.
+
+ @retval EFI_NOT_FOUND An element of the KeywordString was not found.
+ See ProgressErr for more data.
+
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ See ProgressErr for more data.
+
+ @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr
+ for more data.
+
+ @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
+ for more data.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiConfigKeywordHandlerSetData (
+ IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
+ IN CONST EFI_STRING KeywordString,
+ OUT EFI_STRING *Progress,
+ OUT UINT32 *ProgressErr
+ );
+
+/**
+
+ This function accepts a <MultiKeywordRequest> formatted string, finds the underlying
+ keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
+ EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
+
+ If there is an issue in resolving the contents of the KeywordString, then the function
+ returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
+ appropriate information about where the issue occurred and additional data about the
+ nature of the issue.
+
+ In the case when KeywordString is NULL, or contains multiple keywords, or when
+ EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
+ contains values returned for all keywords processed prior to the keyword generating the
+ error but no values for the keyword with error or any following keywords.
+
+
+ @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
+
+ @param NameSpaceId A null-terminated string containing the platform configuration
+ language to search through in the system. If a NULL is passed
+ in, then it is assumed that any platform configuration language
+ with the prefix of "x-UEFI-" are searched.
+
+ @param KeywordString A null-terminated string in <MultiKeywordRequest> format. If a
+ NULL is passed in the KeywordString field, all of the known
+ keywords in the system for the NameSpaceId specified are
+ returned in the Results field.
+
+ @param Progress On return, points to a character in the KeywordString. Points
+ to the string's NULL terminator if the 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 ProgressErr If during the processing of the KeywordString there was a
+ failure, this parameter gives additional information about the
+ possible source of the problem. See the definitions in SetData()
+ for valid value definitions.
+
+ @param Results A null-terminated string in <MultiKeywordResp> format is returned
+ which has all the values filled in for the keywords in the
+ KeywordString. This is a callee-allocated field, and must be freed
+ by the caller after being used.
+
+ @retval EFI_SUCCESS The specified action was completed successfully.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ 1.Progress, ProgressErr, or Results is NULL.
+ 2.Parsing of the KeywordString resulted in an error. See
+ Progress and ProgressErr for more data.
+
+
+ @retval EFI_NOT_FOUND An element of the KeywordString was not found. See
+ ProgressErr for more data.
+
+ @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr
+ for more data.
+
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See
+ ProgressErr for more data.
+
+ @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for
+ more data.
+
+ @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
+ for more data.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiConfigKeywordHandlerGetData (
+ IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
+ IN CONST EFI_STRING NameSpaceId, OPTIONAL
+ IN CONST EFI_STRING KeywordString, OPTIONAL
+ OUT EFI_STRING *Progress,
+ OUT UINT32 *ProgressErr,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ Compare whether two names of languages are identical.
+
+ @param Language1 Name of language 1 from StringPackage
+ @param Language2 Name of language 2 to be compared with language 1.
+
+ @retval TRUE same
+ @retval FALSE not same
+
+**/
+BOOLEAN
+HiiCompareLanguage (
+ IN CHAR8 *Language1,
+ IN CHAR8 *Language2
+ )
+;
+
+/**
+ Retrieves a pointer to a Null-terminated ASCII string containing the list
+ of languages that an HII handle in the HII Database supports. The returned
+ string is allocated using AllocatePool(). The caller is responsible for freeing
+ the returned string using FreePool(). The format of the returned string follows
+ the language format assumed the HII Database.
+
+ If HiiHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+
+ @retval NULL HiiHandle is not registered in the HII database
+ @retval NULL There are not enough resources available to retrieve the supported
+ languages.
+ @retval NULL The list of supported languages could not be retrieved.
+ @retval Other A pointer to the Null-terminated ASCII string of supported languages.
+
+**/
+CHAR8 *
+GetSupportedLanguages (
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+This function mainly use to get HiiDatabase information.
+
+@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+@retval EFI_SUCCESS Get the information successfully.
+@retval EFI_OUT_OF_RESOURCES Not enough memory to store the Hiidatabase data.
+
+**/
+EFI_STATUS
+HiiGetDatabaseInfo (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This
+ );
+
+/**
+This function mainly use to get and update ConfigResp string.
+
+@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+@retval EFI_SUCCESS Get the information successfully.
+@retval EFI_OUT_OF_RESOURCES Not enough memory to store the Configuration Setting data.
+
+**/
+EFI_STATUS
+HiiGetConfigRespInfo (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This
+ );
+
+//
+// Global variables
+//
+extern EFI_EVENT gHiiKeyboardLayoutChanged;
+extern BOOLEAN gExportAfterReadyToBoot;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.uni b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.uni
new file mode 100644
index 000000000..c799672b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The DXE driver produces HII protocols defined in UEFI specification.
+//
+// This driver produces all required HII serivces that includes HiiDataBase, HiiString,
+// HiiFont, HiiConfigRouting. To support UEFI HII, this driver is required.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces HII protocols defined in the UEFI Specification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces all required HII services that includes HiiDataBase, HiiString, HiiFont, HiiConfigRouting. To support UEFI HII, this driver is required."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
new file mode 100644
index 000000000..0116fb6ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
@@ -0,0 +1,94 @@
+## @file
+# The DXE driver produces HII protocols defined in UEFI specification.
+#
+# This driver produces all required HII serivces that includes HiiDataBase, HiiString,
+# HiiFont, HiiConfigRouting. To support UEFI HII, this driver is required.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HiiDatabase
+ MODULE_UNI_FILE = HiiDatabase.uni
+ FILE_GUID = 348C4D62-BFBD-4882-9ECE-C80BB1C4783B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeHiiDatabase
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ HiiDatabaseEntry.c
+ Image.c
+ ImageEx.c
+ HiiDatabase.h
+ ConfigRouting.c
+ String.c
+ Database.c
+ Font.c
+ ConfigKeywordHandler.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ PcdLib
+ UefiRuntimeServicesTableLib
+ PrintLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiStringProtocolGuid ## PRODUCES
+ gEfiHiiImageProtocolGuid |gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## SOMETIMES_PRODUCES
+ gEfiHiiImageExProtocolGuid |gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## SOMETIMES_PRODUCES
+ gEfiHiiImageDecoderProtocolGuid |gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## SOMETIMES_CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## PRODUCES
+ gEfiHiiDatabaseProtocolGuid ## PRODUCES
+ gEfiHiiFontProtocolGuid ## PRODUCES
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiConfigKeywordHandlerProtocolGuid ## PRODUCES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer ## CONSUMES
+
+[Guids]
+ #
+ # Event registered to EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group,
+ # which will be triggered by EFI_HII_DATABASE_PROTOCOL.SetKeyboardLayout().
+ #
+ ## CONSUMES ## Event
+ ## PRODUCES ## Event
+ gEfiHiiKeyBoardLayoutGuid
+ gEfiHiiImageDecoderNameJpegGuid |gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## SOMETIMES_CONSUMES ## GUID
+ gEfiHiiImageDecoderNamePngGuid |gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## SOMETIMES_CONSUMES ## GUID
+ gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ HiiDatabaseExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c
new file mode 100644
index 000000000..bbf437bbb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c
@@ -0,0 +1,251 @@
+/** @file
+This file contains the entry code to the HII database, which is defined by
+UEFI 2.1 specification.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+//
+// Global variables
+//
+EFI_EVENT gHiiKeyboardLayoutChanged;
+BOOLEAN gExportAfterReadyToBoot = FALSE;
+
+HII_DATABASE_PRIVATE_DATA mPrivate = {
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE,
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ {
+ HiiStringToImage,
+ HiiStringIdToImage,
+ HiiGetGlyph,
+ HiiGetFontInfo
+ },
+ {
+ HiiNewImage,
+ HiiGetImage,
+ HiiSetImage,
+ HiiDrawImage,
+ HiiDrawImageId
+ },
+ {
+ HiiNewImageEx,
+ HiiGetImageEx,
+ HiiSetImageEx,
+ HiiDrawImageEx,
+ HiiDrawImageIdEx,
+ HiiGetImageInfo
+ },
+ {
+ HiiNewString,
+ HiiGetString,
+ HiiSetString,
+ HiiGetLanguages,
+ HiiGetSecondaryLanguages
+ },
+ {
+ HiiNewPackageList,
+ HiiRemovePackageList,
+ HiiUpdatePackageList,
+ HiiListPackageLists,
+ HiiExportPackageLists,
+ HiiRegisterPackageNotify,
+ HiiUnregisterPackageNotify,
+ HiiFindKeyboardLayouts,
+ HiiGetKeyboardLayout,
+ HiiSetKeyboardLayout,
+ HiiGetPackageListHandle
+ },
+ {
+ HiiConfigRoutingExtractConfig,
+ HiiConfigRoutingExportConfig,
+ HiiConfigRoutingRouteConfig,
+ HiiBlockToConfig,
+ HiiConfigToBlock,
+ HiiGetAltCfg
+ },
+ {
+ EfiConfigKeywordHandlerSetData,
+ EfiConfigKeywordHandlerGetData
+ },
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ 0,
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),
+ {
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ NULL
+};
+
+/**
+ The default event handler for gHiiKeyboardLayoutChanged
+ event group.
+
+ This is internal function.
+
+ @param Event The event that triggered this notification function.
+ @param Context Pointer to the notification functions context.
+
+**/
+VOID
+EFIAPI
+KeyboardLayoutChangeNullEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ return;
+}
+
+/**
+ On Ready To Boot Services Event notification handler.
+
+ To trigger the function that to export the Hii Configuration setting.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // When ready to boot, we begin to export the HiiDatabase date.
+ // And hook all the possible HiiDatabase change actions to export data.
+ //
+ HiiGetDatabaseInfo (&mPrivate.HiiDatabase);
+ HiiGetConfigRespInfo (&mPrivate.HiiDatabase);
+ gExportAfterReadyToBoot = TRUE;
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Initialize HII Database.
+
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The Hii database is setup correctly.
+ @return Other value if failed to create the default event for
+ gHiiKeyboardLayoutChanged. Check gBS->CreateEventEx for
+ details. Or failed to install the protocols.
+ Check gBS->InstallMultipleProtocolInterfaces for details.
+ Or failed to create Ready To Boot Event.
+ Check EfiCreateEventReadyToBootEx for details.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeHiiDatabase (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_EVENT ReadyToBootEvent;
+
+ //
+ // There will be only one HII Database in the system
+ // If there is another out there, someone is trying to install us
+ // again. Fail that scenario.
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiDatabaseProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiFontProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiImageProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiStringProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiConfigRoutingProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiConfigKeywordHandlerProtocolGuid);
+
+ InitializeListHead (&mPrivate.DatabaseList);
+ InitializeListHead (&mPrivate.DatabaseNotifyList);
+ InitializeListHead (&mPrivate.HiiHandleList);
+ InitializeListHead (&mPrivate.FontInfoList);
+
+ //
+ // Create a event with EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group type.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ KeyboardLayoutChangeNullEvent,
+ NULL,
+ &gEfiHiiKeyBoardLayoutGuid,
+ &gHiiKeyboardLayoutChanged
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiHiiFontProtocolGuid,
+ &mPrivate.HiiFont,
+ &gEfiHiiStringProtocolGuid,
+ &mPrivate.HiiString,
+ &gEfiHiiDatabaseProtocolGuid,
+ &mPrivate.HiiDatabase,
+ &gEfiHiiConfigRoutingProtocolGuid,
+ &mPrivate.ConfigRouting,
+ &gEfiConfigKeywordHandlerProtocolGuid,
+ &mPrivate.ConfigKeywordHandler,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FeaturePcdGet (PcdSupportHiiImageProtocol)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiHiiImageProtocolGuid, &mPrivate.HiiImage,
+ &gEfiHiiImageExProtocolGuid, &mPrivate.HiiImageEx,
+ NULL
+ );
+
+ }
+
+ if (FeaturePcdGet(PcdHiiOsRuntimeSupport)) {
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &ReadyToBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseExtra.uni b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseExtra.uni
new file mode 100644
index 000000000..81a33ecd5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// HiiDatabase Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"HII Database DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c
new file mode 100644
index 000000000..a108fc615
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c
@@ -0,0 +1,1563 @@
+/** @file
+Implementation for EFI_HII_IMAGE_PROTOCOL.
+
+
+Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+#define MAX_UINT24 0xFFFFFF
+
+/**
+ Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input
+ ImageId is zero, otherwise return the address of the
+ corresponding image block with identifier specified by ImageId.
+
+ This is a internal function.
+
+ @param ImageBlocks Points to the beginning of a series of image blocks stored in order.
+ @param ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
+ else use this id to find its corresponding image block address.
+
+ @return The image block address when input ImageId is not zero; otherwise return NULL.
+
+**/
+EFI_HII_IMAGE_BLOCK *
+GetImageIdOrAddress (
+ IN EFI_HII_IMAGE_BLOCK *ImageBlocks,
+ IN OUT EFI_IMAGE_ID *ImageId
+ )
+{
+ EFI_IMAGE_ID ImageIdCurrent;
+ EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
+ UINTN Length;
+
+ ASSERT (ImageBlocks != NULL && ImageId != NULL);
+ CurrentImageBlock = ImageBlocks;
+ ImageIdCurrent = 1;
+
+ while (CurrentImageBlock->BlockType != EFI_HII_IIBT_END) {
+ if (*ImageId != 0) {
+ if (*ImageId == ImageIdCurrent) {
+ //
+ // If the found image block is a duplicate block, update the ImageId to
+ // find the previous defined image block.
+ //
+ if (CurrentImageBlock->BlockType == EFI_HII_IIBT_DUPLICATE) {
+ *ImageId = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_DUPLICATE_BLOCK *) CurrentImageBlock)->ImageId);
+ ASSERT (*ImageId != ImageIdCurrent);
+ ASSERT (*ImageId != 0);
+ CurrentImageBlock = ImageBlocks;
+ ImageIdCurrent = 1;
+ continue;
+ }
+
+ return CurrentImageBlock;
+ }
+ if (*ImageId < ImageIdCurrent) {
+ //
+ // Can not find the specified image block in this image.
+ //
+ return NULL;
+ }
+ }
+ switch (CurrentImageBlock->BlockType) {
+ case EFI_HII_IIBT_EXT1:
+ Length = ((EFI_HII_IIBT_EXT1_BLOCK *) CurrentImageBlock)->Length;
+ break;
+ case EFI_HII_IIBT_EXT2:
+ Length = ReadUnaligned16 (&((EFI_HII_IIBT_EXT2_BLOCK *) CurrentImageBlock)->Length);
+ break;
+ case EFI_HII_IIBT_EXT4:
+ Length = ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_EXT4_BLOCK *) CurrentImageBlock)->Length);
+ break;
+
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ Length = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_1_BIT (
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ Length = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_4_BIT (
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ Length = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_8_BIT (
+ (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ Length = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (
+ (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_DUPLICATE:
+ Length = sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ Length = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_PNG:
+ Length = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_SKIP1:
+ Length = sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
+ ImageIdCurrent += ((EFI_HII_IIBT_SKIP1_BLOCK *) CurrentImageBlock)->SkipCount;
+ break;
+
+ case EFI_HII_IIBT_SKIP2:
+ Length = sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
+ ImageIdCurrent += ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_SKIP2_BLOCK *) CurrentImageBlock)->SkipCount);
+ break;
+
+ default:
+ //
+ // Unknown image blocks can not be skipped, processing halts.
+ //
+ ASSERT (FALSE);
+ Length = 0;
+ break;
+ }
+
+ CurrentImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) CurrentImageBlock + Length);
+
+ }
+
+ //
+ // When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK.
+ //
+ if (*ImageId == 0) {
+ *ImageId = ImageIdCurrent;
+ return CurrentImageBlock;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style.
+
+ This is a internal function.
+
+
+ @param BitMapOut Pixels in EFI_HII_RGB_PIXEL format.
+ @param BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
+ @param PixelNum The number of pixels to be converted.
+
+
+**/
+VOID
+CopyGopToRgbPixel (
+ OUT EFI_HII_RGB_PIXEL *BitMapOut,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn,
+ IN UINTN PixelNum
+ )
+{
+ UINTN Index;
+
+ ASSERT (BitMapOut != NULL && BitMapIn != NULL);
+
+ for (Index = 0; Index < PixelNum; Index++) {
+ CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
+ }
+}
+
+
+/**
+ Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style.
+
+ This is a internal function.
+
+
+ @param BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
+ @param BitMapIn Pixels in EFI_HII_RGB_PIXEL format.
+ @param PixelNum The number of pixels to be converted.
+
+
+**/
+VOID
+CopyRgbToGopPixel (
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut,
+ IN EFI_HII_RGB_PIXEL *BitMapIn,
+ IN UINTN PixelNum
+ )
+{
+ UINTN Index;
+
+ ASSERT (BitMapOut != NULL && BitMapIn != NULL);
+
+ for (Index = 0; Index < PixelNum; Index++) {
+ CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
+ }
+}
+
+
+/**
+ Output pixels in "1 bit per pixel" format to an image.
+
+ This is a internal function.
+
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 or 1.
+ @param PaletteInfo PaletteInfo which stores the color of the output
+ pixels. First entry corresponds to color 0 and
+ second one to color 1.
+
+
+**/
+VOID
+Output1bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 Xpos;
+ UINT16 Ypos;
+ UINTN OffsetY;
+ UINT8 Index;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINTN PaletteSize;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // First entry corresponds to color 0 and second entry corresponds to color 1.
+ //
+ PaletteSize = 0;
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ if (Palette == NULL) {
+ return;
+ }
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
+ CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
+ FreePool (Palette);
+
+ //
+ // Convert the pixel from one bit to corresponding color.
+ //
+ for (Ypos = 0; Ypos < Image->Height; Ypos++) {
+ OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos);
+ //
+ // All bits in these bytes are meaningful
+ //
+ for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) {
+ Byte = *(Data + OffsetY + Xpos);
+ for (Index = 0; Index < 8; Index++) {
+ if ((Byte & (1 << Index)) != 0) {
+ BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1];
+ } else {
+ BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0];
+ }
+ }
+ }
+
+ if (Image->Width % 8 != 0) {
+ //
+ // Padding bits in this byte should be ignored.
+ //
+ Byte = *(Data + OffsetY + Xpos);
+ for (Index = 0; Index < Image->Width % 8; Index++) {
+ if ((Byte & (1 << (8 - Index - 1))) != 0) {
+ BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1];
+ } else {
+ BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0];
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Output pixels in "4 bit per pixel" format to an image.
+
+ This is a internal function.
+
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 ~ 15.
+ @param[in] PaletteInfo PaletteInfo which stores the color of the output
+ pixels. Each entry corresponds to a color within
+ [0, 15].
+
+
+**/
+VOID
+Output4bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 Xpos;
+ UINT16 Ypos;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINTN PaletteSize;
+ UINT16 PaletteNum;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // The bitmap should allocate each color index starting from 0.
+ //
+ PaletteSize = 0;
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ if (Palette == NULL) {
+ return;
+ }
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+ PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
+
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
+ FreePool (Palette);
+
+ //
+ // Convert the pixel from 4 bit to corresponding color.
+ //
+ for (Ypos = 0; Ypos < Image->Height; Ypos++) {
+ OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos);
+ //
+ // All bits in these bytes are meaningful
+ //
+ for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) {
+ Byte = *(Data + OffsetY + Xpos);
+ BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
+ BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F];
+ }
+
+ if (Image->Width % 2 != 0) {
+ //
+ // Padding bits in this byte should be ignored.
+ //
+ Byte = *(Data + OffsetY + Xpos);
+ BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
+ }
+ }
+}
+
+
+/**
+ Output pixels in "8 bit per pixel" format to an image.
+
+ This is a internal function.
+
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 ~ 255.
+ @param[in] PaletteInfo PaletteInfo which stores the color of the output
+ pixels. Each entry corresponds to a color within
+ [0, 255].
+
+
+**/
+VOID
+Output8bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 Xpos;
+ UINT16 Ypos;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINTN PaletteSize;
+ UINT16 PaletteNum;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // The bitmap should allocate each color index starting from 0.
+ //
+ PaletteSize = 0;
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ if (Palette == NULL) {
+ return;
+ }
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+ PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
+ FreePool (Palette);
+
+ //
+ // Convert the pixel from 8 bits to corresponding color.
+ //
+ for (Ypos = 0; Ypos < Image->Height; Ypos++) {
+ OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
+ //
+ // All bits are meaningful since the bitmap is 8 bits per pixel.
+ //
+ for (Xpos = 0; Xpos < Image->Width; Xpos++) {
+ Byte = *(Data + OffsetY + Xpos);
+ BitMapPtr[OffsetY + Xpos] = PaletteValue[Byte];
+ }
+ }
+
+}
+
+
+/**
+ Output pixels in "24 bit per pixel" format to an image.
+
+ This is a internal function.
+
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the color of output pixels, allowing 16.8
+ millions colors.
+
+
+**/
+VOID
+Output24bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN EFI_HII_RGB_PIXEL *Data
+ )
+{
+ UINT16 Ypos;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+
+ ASSERT (Image != NULL && Data != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ for (Ypos = 0; Ypos < Image->Height; Ypos++) {
+ OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
+ CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width);
+ }
+
+}
+
+
+/**
+ Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format.
+
+ This is a internal function.
+
+
+ @param BltBuffer Buffer points to bitmap data of incoming image.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param Width Width of the incoming image, in pixels.
+ @param Height Height of the incoming image, in pixels.
+ @param Transparent If TRUE, all "off" pixels in the image will be
+ drawn using the pixel value from blt and all other
+ pixels will be copied.
+ @param Blt Buffer points to bitmap data of output image.
+
+ @retval EFI_SUCCESS The image was successfully converted.
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+
+**/
+EFI_STATUS
+ImageToBlt (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN BOOLEAN Transparent,
+ IN OUT EFI_IMAGE_OUTPUT **Blt
+ )
+{
+ EFI_IMAGE_OUTPUT *ImageOut;
+ UINTN Xpos;
+ UINTN Ypos;
+ UINTN OffsetY1; // src buffer
+ UINTN OffsetY2; // dest buffer
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel;
+
+ if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ImageOut = *Blt;
+
+ if (Width + BltX > ImageOut->Width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Height + BltY > ImageOut->Height) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ for (Ypos = 0; Ypos < Height; Ypos++) {
+ OffsetY1 = Width * Ypos;
+ OffsetY2 = ImageOut->Width * (BltY + Ypos);
+ for (Xpos = 0; Xpos < Width; Xpos++) {
+ SrcPixel = BltBuffer[OffsetY1 + Xpos];
+ if (Transparent) {
+ if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) {
+ ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
+ }
+ } else {
+ ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the HII package list identified by PackageList HII handle.
+
+ @param Database Pointer to HII database list header.
+ @param PackageList HII handle of the package list to locate.
+
+ @retval The HII package list instance.
+**/
+HII_DATABASE_PACKAGE_LIST_INSTANCE *
+LocatePackageList (
+ IN LIST_ENTRY *Database,
+ IN EFI_HII_HANDLE PackageList
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Record;
+
+ //
+ // Get the specified package list and image package.
+ //
+ for (Link = GetFirstNode (Database);
+ !IsNull (Database, Link);
+ Link = GetNextNode (Database, Link)
+ ) {
+ Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Record->Handle == PackageList) {
+ return Record->PackageList;
+ }
+ }
+ return NULL;
+}
+
+/**
+ This function adds the image Image to the group of images owned by PackageList, and returns
+ a new image identifier (ImageId).
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be added.
+ @param ImageId On return, contains the new image id, which is
+ unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_IMAGE_ID *ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_IMAGE_BLOCK *ImageBlocks;
+ UINT32 NewBlockSize;
+
+ if (This == NULL || ImageId == NULL || Image == NULL || Image->Bitmap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ //
+ // Calcuate the size of new image.
+ // Make sure the size doesn't overflow UINT32.
+ // Note: 24Bit BMP occpuies 3 bytes per pixel.
+ //
+ NewBlockSize = (UINT32)Image->Width * Image->Height;
+ if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
+
+ //
+ // Get the image package in the package list,
+ // or create a new image package if image package does not exist.
+ //
+ if (PackageListNode->ImagePkg != NULL) {
+ ImagePackage = PackageListNode->ImagePkg;
+
+ //
+ // Output the image id of the incoming image being inserted, which is the
+ // image id of the EFI_HII_IIBT_END block of old image package.
+ //
+ *ImageId = 0;
+ GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId);
+
+ //
+ // Update the package's image block by appending the new block to the end.
+ //
+
+ //
+ // Make sure the final package length doesn't overflow.
+ // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
+ //
+ if (NewBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Because ImagePackage->ImageBlockSize < ImagePackage->ImagePkgHdr.Header.Length,
+ // So (ImagePackage->ImageBlockSize + NewBlockSize) <= MAX_UINT24
+ //
+ ImageBlocks = AllocatePool (ImagePackage->ImageBlockSize + NewBlockSize);
+ if (ImageBlocks == NULL) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy the original content.
+ //
+ CopyMem (
+ ImageBlocks,
+ ImagePackage->ImageBlock,
+ ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
+ );
+ FreePool (ImagePackage->ImageBlock);
+ ImagePackage->ImageBlock = ImageBlocks;
+
+ //
+ // Point to the very last block.
+ //
+ ImageBlocks = (EFI_HII_IMAGE_BLOCK *) (
+ (UINT8 *) ImageBlocks + ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
+ );
+ //
+ // Update the length record.
+ //
+ ImagePackage->ImageBlockSize += NewBlockSize;
+ ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += NewBlockSize;
+
+ } else {
+ //
+ // Make sure the final package length doesn't overflow.
+ // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
+ //
+ if (NewBlockSize > MAX_UINT24 - (sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + sizeof (EFI_HII_IIBT_END_BLOCK))) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // The specified package list does not contain image package.
+ // Create one to add this image block.
+ //
+ ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
+ if (ImagePackage == NULL) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Output the image id of the incoming image being inserted, which is the
+ // first image block so that id is initially to one.
+ //
+ *ImageId = 1;
+ //
+ // Fill in image package header.
+ //
+ ImagePackage->ImagePkgHdr.Header.Length = sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
+ ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES;
+ ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+ ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0;
+
+ //
+ // Fill in palette info.
+ //
+ ImagePackage->PaletteBlock = NULL;
+ ImagePackage->PaletteInfoSize = 0;
+
+ //
+ // Fill in image blocks.
+ //
+ ImagePackage->ImageBlockSize = NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
+ ImagePackage->ImageBlock = AllocateZeroPool (NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK));
+ if (ImagePackage->ImageBlock == NULL) {
+ FreePool (ImagePackage);
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageBlocks = ImagePackage->ImageBlock;
+
+ //
+ // Insert this image package.
+ //
+ PackageListNode->ImagePkg = ImagePackage;
+ PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
+ }
+
+ //
+ // Append the new block here
+ //
+ if (Image->Flags == EFI_IMAGE_TRANSPARENT) {
+ ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
+ } else {
+ ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
+ }
+ WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Width, Image->Width);
+ WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Height, Image->Height);
+ CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Bitmap, Image->Bitmap, (UINT32) Image->Width * Image->Height);
+
+ //
+ // Append the block end
+ //
+ ImageBlocks = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + NewBlockSize);
+ ImageBlocks->BlockType = EFI_HII_IIBT_END;
+
+ //
+ // Check whether need to get the contents of HiiDataBase.
+ // Only after ReadyToBoot to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ HiiGetDatabaseInfo(&Private->HiiDatabase);
+ }
+
+ EfiReleaseLock (&mHiiDatabaseLock);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function retrieves the image specified by ImageId which is associated with
+ the specified PackageList and copies it into the buffer specified by Image.
+
+ @param Database A pointer to the database list header.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+ @param BitmapOnly TRUE to only return the bitmap type image.
+ FALSE to locate image decoder instance to decode image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
+ enough memory.
+**/
+EFI_STATUS
+IGetImage (
+ IN LIST_ENTRY *Database,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image,
+ IN BOOLEAN BitmapOnly
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
+ EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
+ UINT16 Width;
+ UINT16 Height;
+ UINTN ImageLength;
+ UINT8 *PaletteInfo;
+ UINT8 PaletteIndex;
+ UINT16 PaletteSize;
+ EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder;
+ EFI_IMAGE_OUTPUT *ImageOut;
+
+ if (Image == NULL || ImageId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageListNode = LocatePackageList (Database, PackageList);
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ImagePackage = PackageListNode->ImagePkg;
+ if (ImagePackage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the image block specified by ImageId
+ //
+ CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
+ if (CurrentImageBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Image->Flags = 0;
+ switch (CurrentImageBlock->BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ case EFI_HII_IIBT_IMAGE_PNG:
+ if (BitmapOnly) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ImageOut = NULL;
+ Decoder = LocateHiiImageDecoder (CurrentImageBlock->BlockType);
+ if (Decoder == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Use the common block code since the definition of two structures is the same.
+ //
+ ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data));
+ ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data) ==
+ sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Data));
+ ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Size) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Size));
+ ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size) ==
+ sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size));
+ Status = Decoder->DecodeImage (
+ Decoder,
+ ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data,
+ ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size,
+ &ImageOut,
+ FALSE
+ );
+
+ //
+ // Spec requires to use the first capable image decoder instance.
+ // The first image decoder instance may fail to decode the image.
+ //
+ if (!EFI_ERROR (Status)) {
+ Image->Bitmap = ImageOut->Image.Bitmap;
+ Image->Height = ImageOut->Height;
+ Image->Width = ImageOut->Width;
+ FreePool (ImageOut);
+ }
+ return Status;
+
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ Image->Flags = EFI_IMAGE_TRANSPARENT;
+ //
+ // fall through
+ //
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ //
+ // Use the common block code since the definition of these structures is the same.
+ //
+ CopyMem (&Iibt1bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
+ ImageLength = (UINTN) Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height;
+ if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ Image->Bitmap = AllocateZeroPool (ImageLength);
+ if (Image->Bitmap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Image->Width = Iibt1bit.Bitmap.Width;
+ Image->Height = Iibt1bit.Bitmap.Height;
+
+ PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
+ for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) {
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteInfo += PaletteSize + sizeof (UINT16);
+ }
+ ASSERT (PaletteIndex == Iibt1bit.PaletteIndex);
+
+ //
+ // Output bitmap data
+ //
+ if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT ||
+ CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) {
+ Output1bitPixel (
+ Image,
+ ((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ } else if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT ||
+ CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) {
+ Output4bitPixel (
+ Image,
+ ((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ } else {
+ Output8bitPixel (
+ Image,
+ ((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ }
+
+ return EFI_SUCCESS;
+
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ Image->Flags = EFI_IMAGE_TRANSPARENT;
+ //
+ // fall through
+ //
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ Width = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width);
+ Height = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height);
+ ImageLength = (UINTN)Width * Height;
+ if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ Image->Bitmap = AllocateZeroPool (ImageLength);
+ if (Image->Bitmap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Image->Width = Width;
+ Image->Height = Height;
+
+ //
+ // Output the bitmap data directly.
+ //
+ Output24bitPixel (
+ Image,
+ ((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Bitmap
+ );
+ return EFI_SUCCESS;
+
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ This function retrieves the image specified by ImageId which is associated with
+ the specified PackageList and copies it into the buffer specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
+ enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ return IGetImage (&Private->DatabaseList, PackageList, ImageId, Image, TRUE);
+}
+
+
+/**
+ This function updates the image specified by ImageId in the specified PackageListHandle to
+ the image specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList The package list containing the images.
+ @param ImageId The image's id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was updated successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
+ EFI_HII_IMAGE_BLOCK *ImageBlocks;
+ EFI_HII_IMAGE_BLOCK *NewImageBlock;
+ UINT32 NewBlockSize;
+ UINT32 OldBlockSize;
+ UINT32 Part1Size;
+ UINT32 Part2Size;
+
+ if (This == NULL || Image == NULL || ImageId == 0 || Image->Bitmap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ImagePackage = PackageListNode->ImagePkg;
+ if (ImagePackage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the image block specified by ImageId
+ //
+ CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
+ if (CurrentImageBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ //
+ // Get the size of original image block. Use some common block code here
+ // since the definition of some structures is the same.
+ //
+ switch (CurrentImageBlock->BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ OldBlockSize = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
+ break;
+ case EFI_HII_IIBT_IMAGE_PNG:
+ OldBlockSize = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
+ break;
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_1_BIT (
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ break;
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_4_BIT (
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ break;
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_8_BIT (
+ (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ break;
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (
+ (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
+ ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
+ );
+ break;
+ default:
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Create the new image block according to input image.
+ //
+
+ //
+ // Make sure the final package length doesn't overflow.
+ // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
+ // 24Bit BMP occpuies 3 bytes per pixel.
+ //
+ NewBlockSize = (UINT32)Image->Width * Image->Height;
+ if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
+ if ((NewBlockSize > OldBlockSize) &&
+ (NewBlockSize - OldBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length)
+ ) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Adjust the image package to remove the original block firstly then add the new block.
+ //
+ ImageBlocks = AllocateZeroPool (ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize);
+ if (ImageBlocks == NULL) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Part1Size = (UINT32) ((UINTN) CurrentImageBlock - (UINTN) ImagePackage->ImageBlock);
+ Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize;
+ CopyMem (ImageBlocks, ImagePackage->ImageBlock, Part1Size);
+
+ //
+ // Set the new image block
+ //
+ NewImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + Part1Size);
+ if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
+ NewImageBlock->BlockType= EFI_HII_IIBT_IMAGE_24BIT_TRANS;
+ } else {
+ NewImageBlock->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
+ }
+ WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Width, Image->Width);
+ WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Height, Image->Height);
+ CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Bitmap,
+ Image->Bitmap, (UINT32) Image->Width * Image->Height);
+
+ CopyMem ((UINT8 *) NewImageBlock + NewBlockSize, (UINT8 *) CurrentImageBlock + OldBlockSize, Part2Size);
+
+ FreePool (ImagePackage->ImageBlock);
+ ImagePackage->ImageBlock = ImageBlocks;
+ ImagePackage->ImageBlockSize += NewBlockSize - OldBlockSize;
+ ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize;
+
+ //
+ // Check whether need to get the contents of HiiDataBase.
+ // Only after ReadyToBoot to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ HiiGetDatabaseInfo(&Private->HiiDatabase);
+ }
+
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param Image Points to the image to be displayed.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
+ @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN CONST EFI_IMAGE_INPUT *Image,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ BOOLEAN Transparent;
+ EFI_IMAGE_OUTPUT *ImageOut;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ UINTN BufferLen;
+ UINT16 Width;
+ UINT16 Height;
+ UINTN Xpos;
+ UINTN Ypos;
+ UINTN OffsetY1;
+ UINTN OffsetY2;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+ UINTN Index;
+
+ if (This == NULL || Image == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FontInfo = NULL;
+
+ //
+ // Check whether the image will be drawn transparently or opaquely.
+ //
+ Transparent = FALSE;
+ if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) {
+ Transparent = TRUE;
+ } else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){
+ Transparent = FALSE;
+ } else {
+ //
+ // Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending
+ // on the image's transparency setting.
+ //
+ if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
+ Transparent = TRUE;
+ }
+ }
+
+ //
+ // Image cannot be drawn transparently if Blt points to NULL on entry.
+ // Currently output to Screen transparently is not supported, either.
+ //
+ if (Transparent) {
+ if (*Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // When Blt points to a non-NULL on entry, this image will be drawn onto
+ // this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied.
+ // Otherwise a new bitmap will be allocated to hold this image.
+ //
+ if (*Blt != NULL) {
+ //
+ // Make sure the BltX and BltY is inside the Blt area.
+ //
+ if ((BltX >= (*Blt)->Width) || (BltY >= (*Blt)->Height)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Clip the image by (Width, Height)
+ //
+
+ Width = Image->Width;
+ Height = Image->Height;
+
+ if (Width > (*Blt)->Width - (UINT16)BltX) {
+ Width = (*Blt)->Width - (UINT16)BltX;
+ }
+ if (Height > (*Blt)->Height - (UINT16)BltY) {
+ Height = (*Blt)->Height - (UINT16)BltY;
+ }
+
+ //
+ // Prepare the buffer for the temporary image.
+ // Make sure the buffer size doesn't overflow UINTN.
+ //
+ BufferLen = Width * Height;
+ if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ BltBuffer = AllocateZeroPool (BufferLen);
+ if (BltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Width == Image->Width && Height == Image->Height) {
+ CopyMem (BltBuffer, Image->Bitmap, BufferLen);
+ } else {
+ for (Ypos = 0; Ypos < Height; Ypos++) {
+ OffsetY1 = Image->Width * Ypos;
+ OffsetY2 = Width * Ypos;
+ for (Xpos = 0; Xpos < Width; Xpos++) {
+ BltBuffer[OffsetY2 + Xpos] = Image->Bitmap[OffsetY1 + Xpos];
+ }
+ }
+ }
+
+ //
+ // Draw the image to existing bitmap or screen depending on flag.
+ //
+ if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ //
+ // Caller should make sure the current UGA console is grarphic mode.
+ //
+
+ //
+ // Write the image directly to the output device specified by Screen.
+ //
+ Status = (*Blt)->Image.Screen->Blt (
+ (*Blt)->Image.Screen,
+ BltBuffer,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ BltX,
+ BltY,
+ Width,
+ Height,
+ 0
+ );
+ } else {
+ //
+ // Draw the image onto the existing bitmap specified by Bitmap.
+ //
+ Status = ImageToBlt (
+ BltBuffer,
+ BltX,
+ BltY,
+ Width,
+ Height,
+ Transparent,
+ Blt
+ );
+
+ }
+
+ FreePool (BltBuffer);
+ return Status;
+
+ } else {
+ //
+ // Allocate a new bitmap to hold the incoming image.
+ //
+
+ //
+ // Make sure the final width and height doesn't overflow UINT16.
+ //
+ if ((BltX > (UINTN)MAX_UINT16 - Image->Width) || (BltY > (UINTN)MAX_UINT16 - Image->Height)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Width = Image->Width + (UINT16)BltX;
+ Height = Image->Height + (UINT16)BltY;
+
+ //
+ // Make sure the output image size doesn't overflow UINTN.
+ //
+ BufferLen = Width * Height;
+ if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ BltBuffer = AllocateZeroPool (BufferLen);
+ if (BltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (ImageOut == NULL) {
+ FreePool (BltBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageOut->Width = Width;
+ ImageOut->Height = Height;
+ ImageOut->Image.Bitmap = BltBuffer;
+
+ //
+ // BUGBUG: Now all the "blank" pixels are filled with system default background
+ // color. Not sure if it need to be updated or not.
+ //
+ Status = GetSystemFont (Private, &FontInfo, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (BltBuffer);
+ FreePool (ImageOut);
+ return Status;
+ }
+ ASSERT (FontInfo != NULL);
+ for (Index = 0; Index < (UINTN)Width * Height; Index++) {
+ BltBuffer[Index] = FontInfo->BackgroundColor;
+ }
+ FreePool (FontInfo);
+
+ //
+ // Draw the incoming image to the new created image.
+ //
+ *Blt = ImageOut;
+ return ImageToBlt (
+ Image->Bitmap,
+ BltX,
+ BltY,
+ Image->Width,
+ Image->Height,
+ Transparent,
+ Blt
+ );
+
+ }
+}
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param PackageList The package list in the HII database to search for
+ the specified image.
+ @param ImageId The image's id, which is unique within
+ PackageList.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and
+ EFI_HII_DRAW_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer will be
+ allocated to hold the generated image and the
+ pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Blt was NULL.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
+ The specified PackageList is not in the database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageId (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_INPUT Image;
+
+ //
+ // Check input parameter.
+ //
+ if (This == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the specified Image.
+ //
+ Status = HiiGetImage (This, PackageList, ImageId, &Image);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Draw this image.
+ //
+ Status = HiiDrawImage (This, Flags, &Image, Blt, BltX, BltY);
+ if (Image.Bitmap != NULL) {
+ FreePool (Image.Bitmap);
+ }
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ImageEx.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ImageEx.c
new file mode 100644
index 000000000..07e8b3b56
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ImageEx.c
@@ -0,0 +1,421 @@
+/** @file
+Implementation for EFI_HII_IMAGE_EX_PROTOCOL.
+
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+/**
+ The prototype of this extension function is the same with EFI_HII_IMAGE_PROTOCOL.NewImage().
+ This protocol invokes EFI_HII_IMAGE_PROTOCOL.NewImage() implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be added.
+ @param ImageId On return, contains the new image id, which is
+ unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was added successfully.
+ @retval EFI_NOT_FOUND The PackageList could not be found.
+ @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
+**/
+EFI_STATUS
+EFIAPI
+HiiNewImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_IMAGE_ID *ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+
+ Private = HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ return HiiNewImage (&Private->HiiImage, PackageList, ImageId, Image);
+}
+
+/**
+ Return the information about the image, associated with the package list.
+ The prototype of this extension function is the same with EFI_HII_IMAGE_PROTOCOL.GetImage().
+
+ This function is similar to EFI_HII_IMAGE_PROTOCOL.GetImage().The difference is that
+ this function will locate all EFI_HII_IMAGE_DECODER_PROTOCOL instances installed in the
+ system if the decoder of the certain image type is not supported by the
+ EFI_HII_IMAGE_EX_PROTOCOL. The function will attempt to decode the image to the
+ EFI_IMAGE_INPUT using the first EFI_HII_IMAGE_DECODER_PROTOCOL instance that
+ supports the requested image type.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList The package list in the HII database to search for the
+ specified image.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not available. The specified
+ PackageList is not in the Database.
+ @retval EFI_INVALID_PARAMETER Image was NULL or ImageId was 0.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there
+ was not enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+
+ Private = HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ return IGetImage (&Private->DatabaseList, PackageList, ImageId, Image, FALSE);
+}
+
+
+/**
+ Change the information about the image.
+
+ Same with EFI_HII_IMAGE_PROTOCOL.SetImage(),this protocol invokes
+ EFI_HII_IMAGE_PROTOCOL.SetImage()implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList The package list containing the images.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was successfully updated.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in
+ the database.
+ @retval EFI_INVALID_PARAMETER The Image was NULL, the ImageId was 0 or
+ the Image->Bitmap was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ Private = HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ return HiiSetImage (&Private->HiiImage, PackageList, ImageId, Image);
+}
+
+
+/**
+ Renders an image to a bitmap or to the display.
+
+ The prototype of this extension function is the same with
+ EFI_HII_IMAGE_PROTOCOL.DrawImage(). This protocol invokes
+ EFI_HII_IMAGE_PROTOCOL.DrawImage() implicitly.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param Image Points to the image to be displayed.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN CONST EFI_IMAGE_INPUT *Image,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ Private = HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ return HiiDrawImage (&Private->HiiImage, Flags, Image, Blt, BltX, BltY);
+}
+
+
+/**
+ Renders an image to a bitmap or the screen containing the contents of the specified
+ image.
+
+ This function is similar to EFI_HII_IMAGE_PROTOCOL.DrawImageId(). The difference is that
+ this function will locate all EFI_HII_IMAGE_DECODER_PROTOCOL instances installed in the
+ system if the decoder of the certain image type is not supported by the
+ EFI_HII_IMAGE_EX_PROTOCOL. The function will attempt to decode the image to the
+ EFI_IMAGE_INPUT using the first EFI_HII_IMAGE_DECODER_PROTOCOL instance that
+ supports the requested image type.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param PackageList The package list in the HII database to search for
+ the specified image.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image
+ and the pointer updated on exit. It is the caller's
+ responsibility to free this buffer.
+ @param BltX Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Blt was NULL or ImageId was 0.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
+ The specified PackageList is not in the database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageIdEx (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_INPUT Image;
+
+ //
+ // Check input parameter.
+ //
+ if (This == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the specified Image.
+ //
+ Status = HiiGetImageEx (This, PackageList, ImageId, &Image);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Draw this image.
+ //
+ Status = HiiDrawImageEx (This, Flags, &Image, Blt, BltX, BltY);
+ if (Image.Bitmap != NULL) {
+ FreePool (Image.Bitmap);
+ }
+ return Status;
+}
+
+/**
+ Return the first HII image decoder instance which supports the DecoderName.
+
+ @param BlockType The image block type.
+
+ @retval Pointer to the HII image decoder instance.
+**/
+EFI_HII_IMAGE_DECODER_PROTOCOL *
+LocateHiiImageDecoder (
+ UINT8 BlockType
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder;
+ EFI_HANDLE *Handles;
+ UINTN HandleNum;
+ UINTN Index;
+ EFI_GUID *DecoderNames;
+ UINT16 NumberOfDecoderName;
+ UINT16 DecoderNameIndex;
+ EFI_GUID *DecoderName;
+
+ switch (BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ DecoderName = &gEfiHiiImageDecoderNameJpegGuid;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_PNG:
+ DecoderName = &gEfiHiiImageDecoderNamePngGuid;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return NULL;
+ }
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiHiiImageDecoderProtocolGuid, NULL, &HandleNum, &Handles);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ for (Index = 0; Index < HandleNum; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiHiiImageDecoderProtocolGuid, (VOID **) &Decoder);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = Decoder->GetImageDecoderName (Decoder, &DecoderNames, &NumberOfDecoderName);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ for (DecoderNameIndex = 0; DecoderNameIndex < NumberOfDecoderName; DecoderNameIndex++) {
+ if (CompareGuid (DecoderName, &DecoderNames[DecoderNameIndex])) {
+ return Decoder;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ This function returns the image information to EFI_IMAGE_OUTPUT. Only the width
+ and height are returned to the EFI_IMAGE_OUTPUT instead of decoding the image
+ to the buffer. This function is used to get the geometry of the image. This function
+ will try to locate all of the EFI_HII_IMAGE_DECODER_PROTOCOL installed on the
+ system if the decoder of image type is not supported by the EFI_HII_IMAGE_EX_PROTOCOL.
+
+ @param This A pointer to the EFI_HII_IMAGE_EX_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image's id, which is unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database. The specified PackageList is not in the database.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image was NULL or the ImageId was 0.
+ @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there
+ was not enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImageInfo (
+ IN CONST EFI_HII_IMAGE_EX_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_OUTPUT *Image
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
+ EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder;
+ EFI_HII_IMAGE_DECODER_IMAGE_INFO_HEADER *ImageInfo;
+
+ if (Image == NULL || ImageId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_IMAGE_EX_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ImagePackage = PackageListNode->ImagePkg;
+ if (ImagePackage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the image block specified by ImageId
+ //
+ CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
+ if (CurrentImageBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ switch (CurrentImageBlock->BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ case EFI_HII_IIBT_IMAGE_PNG:
+ Decoder = LocateHiiImageDecoder (CurrentImageBlock->BlockType);
+ if (Decoder == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Use the common block code since the definition of two structures is the same.
+ //
+ ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data));
+ ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data) ==
+ sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Data));
+ ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Size) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Size));
+ ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size) ==
+ sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size));
+ Status = Decoder->GetImageInfo (
+ Decoder,
+ ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data,
+ ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size,
+ &ImageInfo
+ );
+
+ //
+ // Spec requires to use the first capable image decoder instance.
+ // The first image decoder instance may fail to decode the image.
+ //
+ if (!EFI_ERROR (Status)) {
+ Image->Height = ImageInfo->ImageHeight;
+ Image->Width = ImageInfo->ImageWidth;
+ Image->Image.Bitmap = NULL;
+ FreePool (ImageInfo);
+ }
+ return Status;
+
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ //
+ // Use the common block code since the definition of these structures is the same.
+ //
+ Image->Width = ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width);
+ Image->Height = ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height);
+ Image->Image.Bitmap = NULL;
+ return EFI_SUCCESS;
+
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ Image->Width = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width);
+ Image->Height = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height);
+ Image->Image.Bitmap = NULL;
+ return EFI_SUCCESS;
+
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c
new file mode 100644
index 000000000..2c7ecfea4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c
@@ -0,0 +1,2085 @@
+/** @file
+Implementation for EFI_HII_STRING_PROTOCOL.
+
+
+Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "HiiDatabase.h"
+
+CHAR16 mLanguageWindow[16] = {
+ 0x0000, 0x0080, 0x0100, 0x0300,
+ 0x2000, 0x2080, 0x2100, 0x3000,
+ 0x0080, 0x00C0, 0x0400, 0x0600,
+ 0x0900, 0x3040, 0x30A0, 0xFF00
+};
+
+
+/**
+ This function checks whether a global font info is referred by local
+ font info list or not. (i.e. HII_FONT_INFO is generated.) If not, create
+ a HII_FONT_INFO to refer it locally.
+
+ This is a internal function.
+
+
+ @param Private Hii database private structure.
+ @param StringPackage HII string package instance.
+ @param FontId Font identifer, which must be unique within the string package.
+ @param DuplicateEnable If true, duplicate HII_FONT_INFO which refers to
+ the same EFI_FONT_INFO is permitted. Otherwise it
+ is not allowed.
+ @param GlobalFontInfo Input a global font info which specify a
+ EFI_FONT_INFO.
+ @param LocalFontInfo Output a local font info which refers to a
+ EFI_FONT_INFO.
+
+ @retval TRUE Already referred before calling this function.
+ @retval FALSE Not referred before calling this function.
+
+**/
+BOOLEAN
+ReferFontInfoLocally (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN UINT8 FontId,
+ IN BOOLEAN DuplicateEnable,
+ IN HII_GLOBAL_FONT_INFO *GlobalFontInfo,
+ OUT HII_FONT_INFO **LocalFontInfo
+ )
+{
+ HII_FONT_INFO *LocalFont;
+ LIST_ENTRY *Link;
+
+ ASSERT (Private != NULL && StringPackage != NULL && GlobalFontInfo != NULL && LocalFontInfo != NULL);
+
+ if (!DuplicateEnable) {
+ for (Link = StringPackage->FontInfoList.ForwardLink;
+ Link != &StringPackage->FontInfoList;
+ Link = Link->ForwardLink
+ ) {
+ LocalFont = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
+ if (LocalFont->GlobalEntry == &GlobalFontInfo->Entry) {
+ //
+ // Already referred by local font info list, return directly.
+ //
+ *LocalFontInfo = LocalFont;
+ return TRUE;
+ }
+ }
+ }
+ // FontId identifies EFI_FONT_INFO in local string package uniquely.
+ // GlobalEntry points to a HII_GLOBAL_FONT_INFO which identifies
+ // EFI_FONT_INFO uniquely in whole hii database.
+ //
+ LocalFont = (HII_FONT_INFO *) AllocateZeroPool (sizeof (HII_FONT_INFO));
+ ASSERT (LocalFont != NULL);
+
+ LocalFont->Signature = HII_FONT_INFO_SIGNATURE;
+ LocalFont->FontId = FontId;
+ LocalFont->GlobalEntry = &GlobalFontInfo->Entry;
+ InsertTailList (&StringPackage->FontInfoList, &LocalFont->Entry);
+
+ *LocalFontInfo = LocalFont;
+ return FALSE;
+}
+
+
+/**
+ Convert Ascii string text to unicode string test.
+
+ This is a internal function.
+
+
+ @param StringDest Buffer to store the string text. If it is NULL,
+ only the size will be returned.
+ @param StringSrc Points to current null-terminated string.
+ @param BufferSize Length of the buffer.
+
+ @retval EFI_SUCCESS The string text was outputted successfully.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string
+ text. BufferSize is updated to the required buffer
+ size.
+
+**/
+EFI_STATUS
+ConvertToUnicodeText (
+ OUT EFI_STRING StringDest,
+ IN CHAR8 *StringSrc,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN StringSize;
+ UINTN Index;
+
+ ASSERT (StringSrc != NULL && BufferSize != NULL);
+
+ StringSize = AsciiStrSize (StringSrc) * 2;
+ if (*BufferSize < StringSize || StringDest == NULL) {
+ *BufferSize = StringSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ for (Index = 0; Index < AsciiStrLen (StringSrc); Index++) {
+ StringDest[Index] = (CHAR16) StringSrc[Index];
+ }
+
+ StringDest[Index] = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Calculate the size of StringSrc and output it. If StringDest is not NULL,
+ copy string text from src to dest.
+
+ This is a internal function.
+
+ @param StringDest Buffer to store the string text. If it is NULL,
+ only the size will be returned.
+ @param StringSrc Points to current null-terminated string.
+ @param BufferSize Length of the buffer.
+
+ @retval EFI_SUCCESS The string text was outputted successfully.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string
+ text. BufferSize is updated to the required buffer
+ size.
+
+**/
+EFI_STATUS
+GetUnicodeStringTextOrSize (
+ OUT EFI_STRING StringDest, OPTIONAL
+ IN UINT8 *StringSrc,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN StringSize;
+ UINT8 *StringPtr;
+
+ ASSERT (StringSrc != NULL && BufferSize != NULL);
+
+ StringSize = sizeof (CHAR16);
+ StringPtr = StringSrc;
+ while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
+ StringSize += sizeof (CHAR16);
+ StringPtr += sizeof (CHAR16);
+ }
+
+ if (*BufferSize < StringSize) {
+ *BufferSize = StringSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ if (StringDest != NULL) {
+ CopyMem (StringDest, StringSrc, StringSize);
+ }
+
+ *BufferSize = StringSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Copy string font info to a buffer.
+
+ This is a internal function.
+
+ @param StringPackage Hii string package instance.
+ @param FontId Font identifier which is unique in a string
+ package.
+ @param StringFontInfo Buffer to record the output font info. It's
+ caller's responsibility to free this buffer.
+
+ @retval EFI_SUCCESS The string font is outputted successfully.
+ @retval EFI_NOT_FOUND The specified font id does not exist.
+
+**/
+EFI_STATUS
+GetStringFontInfo (
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN UINT8 FontId,
+ OUT EFI_FONT_INFO **StringFontInfo
+ )
+{
+ LIST_ENTRY *Link;
+ HII_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ ASSERT (StringFontInfo != NULL && StringPackage != NULL);
+
+ for (Link = StringPackage->FontInfoList.ForwardLink; Link != &StringPackage->FontInfoList; Link = Link->ForwardLink) {
+ FontInfo = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
+ if (FontInfo->FontId == FontId) {
+ GlobalFont = CR (FontInfo->GlobalEntry, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ *StringFontInfo = (EFI_FONT_INFO *) AllocateZeroPool (GlobalFont->FontInfoSize);
+ if (*StringFontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (*StringFontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Parse all string blocks to find a String block specified by StringId.
+ If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks
+ within this string package and backup its information. If LastStringId is
+ specified, the string id of last string block will also be output.
+ If StringId = 0, output the string id of last string block (EFI_HII_SIBT_STRING).
+
+ @param Private Hii database private structure.
+ @param StringPackage Hii string package instance.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param BlockType Output the block type of found string block.
+ @param StringBlockAddr Output the block address of found string block.
+ @param StringTextOffset Offset, relative to the found block address, of
+ the string text information.
+ @param LastStringId Output the last string id when StringId = 0 or StringId = -1.
+ @param StartStringId The first id in the skip block which StringId in the block.
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindStringBlock (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT UINT8 *BlockType, OPTIONAL
+ OUT UINT8 **StringBlockAddr, OPTIONAL
+ OUT UINTN *StringTextOffset, OPTIONAL
+ OUT EFI_STRING_ID *LastStringId, OPTIONAL
+ OUT EFI_STRING_ID *StartStringId OPTIONAL
+ )
+{
+ UINT8 *BlockHdr;
+ EFI_STRING_ID CurrentStringId;
+ UINTN BlockSize;
+ UINTN Index;
+ UINT8 *StringTextPtr;
+ UINTN Offset;
+ HII_FONT_INFO *LocalFont;
+ EFI_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ UINTN FontInfoSize;
+ UINT16 StringCount;
+ UINT16 SkipCount;
+ EFI_HII_FONT_STYLE FontStyle;
+ UINT16 FontSize;
+ UINT8 Length8;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINT8 FontId;
+ UINT32 Length32;
+ UINTN StringSize;
+ CHAR16 Zero;
+
+ ASSERT (StringPackage != NULL);
+ ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
+
+ CurrentStringId = 1;
+ StringSize = 0;
+
+ if (StringId != (EFI_STRING_ID) (-1) && StringId != 0) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ if (StringId > StringPackage->MaxStringId) {
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ if (StringId == 0 && LastStringId != NULL) {
+ *LastStringId = StringPackage->MaxStringId;
+ return EFI_SUCCESS;
+ }
+ }
+
+ ZeroMem (&Zero, sizeof (CHAR16));
+
+ //
+ // Parse the string blocks to get the string text and font.
+ //
+ BlockHdr = StringPackage->StringBlock;
+ BlockSize = 0;
+ Offset = 0;
+ while (*BlockHdr != EFI_HII_SIBT_END) {
+ switch (*BlockHdr) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (CurrentStringId == StringId) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (CurrentStringId == StringId) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StrSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += StringSize;
+ if (CurrentStringId == StringId) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (
+ &StringCount,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += StringSize;
+ if (CurrentStringId == StringId) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ if (CurrentStringId == StringId) {
+ //
+ // Incoming StringId is an id of a duplicate string block.
+ // Update the StringId to be the previous string block.
+ // Go back to the header of string block to search.
+ //
+ CopyMem (
+ &StringId,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK),
+ sizeof (EFI_STRING_ID)
+ );
+ ASSERT (StringId != CurrentStringId);
+ CurrentStringId = 1;
+ BlockSize = 0;
+ } else {
+ BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ CopyMem (
+ &Length8,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT8)
+ );
+ BlockSize += Length8;
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ if (Ext2.BlockType2 == EFI_HII_SIBT_FONT && StringId == (EFI_STRING_ID) (-1)) {
+ //
+ // Find the relationship between global font info and the font info of
+ // this EFI_HII_SIBT_FONT block then backup its information in local package.
+ //
+ BlockHdr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
+ CopyMem (&FontId, BlockHdr, sizeof (UINT8));
+ BlockHdr ++;
+ CopyMem (&FontSize, BlockHdr, sizeof (UINT16));
+ BlockHdr += sizeof (UINT16);
+ CopyMem (&FontStyle, BlockHdr, sizeof (EFI_HII_FONT_STYLE));
+ BlockHdr += sizeof (EFI_HII_FONT_STYLE);
+ GetUnicodeStringTextOrSize (NULL, BlockHdr, &StringSize);
+
+ FontInfoSize = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + StringSize;
+ FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize);
+ if (FontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FontInfo->FontStyle = FontStyle;
+ FontInfo->FontSize = FontSize;
+ CopyMem (FontInfo->FontName, BlockHdr, StringSize);
+
+ //
+ // If find the corresponding global font info, save the relationship.
+ // Otherwise ignore this EFI_HII_SIBT_FONT block.
+ //
+ if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, &GlobalFont)) {
+ ReferFontInfoLocally (Private, StringPackage, FontId, TRUE, GlobalFont, &LocalFont);
+ }
+
+ //
+ // Since string package tool set FontId initially to 0 and increases it
+ // progressively by one, StringPackage->FondId always represents an unique
+ // and available FontId.
+ //
+ StringPackage->FontId++;
+
+ FreePool (FontInfo);
+ }
+
+ BlockSize += Ext2.Length;
+
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ CopyMem (
+ &Length32,
+ (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
+ sizeof (UINT32)
+ );
+
+ BlockSize += Length32;
+ break;
+
+ default:
+ break;
+ }
+
+ if (StringId > 0 && StringId != (EFI_STRING_ID)(-1)) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = Offset;
+
+ if (StringId == CurrentStringId - 1) {
+ //
+ // if only one skip item, return EFI_NOT_FOUND.
+ //
+ if(*BlockType == EFI_HII_SIBT_SKIP2 || *BlockType == EFI_HII_SIBT_SKIP1) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (StringId < CurrentStringId - 1) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ BlockHdr = StringPackage->StringBlock + BlockSize;
+ if (StartStringId != NULL) {
+ *StartStringId = CurrentStringId;
+ }
+ }
+
+ //
+ // Get last string ID
+ //
+ if (StringId == (EFI_STRING_ID) (-1) && LastStringId != NULL) {
+ *LastStringId = (EFI_STRING_ID) (CurrentStringId - 1);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Parse all string blocks to get a string specified by StringId.
+
+ This is a internal function.
+
+ @param Private Hii database private structure.
+ @param StringPackage Hii string package instance.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param String Points to retrieved null-terminated string.
+ @param StringSize On entry, points to the size of the buffer pointed
+ to by String, in bytes. On return, points to the
+ length of the string, in bytes.
+ @param StringFontInfo If not NULL, allocate a buffer to record the
+ output font info. It's caller's responsibility to
+ free this buffer.
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to
+ hold the string.
+
+**/
+EFI_STATUS
+GetStringWorker (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING String,
+ IN OUT UINTN *StringSize, OPTIONAL
+ OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
+ )
+{
+ UINT8 *StringTextPtr;
+ UINT8 BlockType;
+ UINT8 *StringBlockAddr;
+ UINTN StringTextOffset;
+ EFI_STATUS Status;
+ UINT8 FontId;
+
+ ASSERT (StringPackage != NULL);
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+
+ //
+ // Find the specified string block
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ StringId,
+ &BlockType,
+ &StringBlockAddr,
+ &StringTextOffset,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (StringSize == NULL) {
+ //
+ // String text buffer is not requested
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the string text.
+ //
+ StringTextPtr = StringBlockAddr + StringTextOffset;
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ Status = ConvertToUnicodeText (String, (CHAR8 *) StringTextPtr, StringSize);
+ break;
+ case EFI_HII_SIBT_STRING_UCS2:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Status = GetUnicodeStringTextOrSize (String, StringTextPtr, StringSize);
+ break;
+ default:
+ return EFI_NOT_FOUND;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the string font. The FontId 0 is the default font for those string blocks which
+ // do not specify a font identifier. If default font is not specified, return NULL.
+ //
+ if (StringFontInfo != NULL) {
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ FontId = *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK));
+ break;
+ default:
+ FontId = 0;
+ }
+ Status = GetStringFontInfo (StringPackage, FontId, StringFontInfo);
+ if (Status == EFI_NOT_FOUND) {
+ *StringFontInfo = NULL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ If GetStringBlock find the StringId's string is not saved in the exist string block,
+ this function will create the UCS2 string block to save the string; also split the
+ skip block into two or one skip block.
+
+ This is a internal function.
+
+ @param StringPackage Hii string package instance.
+ @param StartStringId The first id in the skip block which StringId in the block.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param BlockType Output the block type of found string block.
+ @param StringBlockAddr Output the block address of found string block.
+ @param FontBlock whether this string block has font info.
+
+ @retval EFI_SUCCESS The string font is outputted successfully.
+ @retval EFI_OUT_OF_RESOURCES NO resource for the memory to save the new string block.
+
+**/
+EFI_STATUS
+InsertLackStringBlock (
+ IN OUT HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StartStringId,
+ IN EFI_STRING_ID StringId,
+ IN OUT UINT8 *BlockType,
+ IN OUT UINT8 **StringBlockAddr,
+ IN BOOLEAN FontBlock
+ )
+{
+ UINT8 *BlockPtr;
+ UINT8 *StringBlock;
+ UINT32 SkipLen;
+ UINT32 OldBlockSize;
+ UINT32 NewBlockSize;
+ UINT32 FrontSkipNum;
+ UINT32 NewUCSBlockLen;
+ UINT8 *OldStringAddr;
+ UINT32 IdCount;
+
+ FrontSkipNum = 0;
+ SkipLen = 0;
+ OldStringAddr = *StringBlockAddr;
+
+ ASSERT (*BlockType == EFI_HII_SIBT_SKIP1 || *BlockType == EFI_HII_SIBT_SKIP2);
+ //
+ // Old skip block size.
+ //
+ if (*BlockType == EFI_HII_SIBT_SKIP1) {
+ SkipLen = sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
+ IdCount = *(UINT8*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK));
+ } else {
+ SkipLen = sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+ IdCount = *(UINT16*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK));
+ }
+
+ //
+ // New create UCS or UCS2 block size.
+ //
+ if (FontBlock) {
+ NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK);
+ } else {
+ NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+
+ if (StartStringId == StringId) {
+ //
+ // New block + [Skip block]
+ //
+ if (IdCount > 1) {
+ NewBlockSize = OldBlockSize + NewUCSBlockLen;
+ } else {
+ NewBlockSize = OldBlockSize + NewUCSBlockLen - SkipLen;
+ }
+ } else if (StartStringId + IdCount - 1 == StringId){
+ //
+ // Skip block + New block
+ //
+ NewBlockSize = OldBlockSize + NewUCSBlockLen;
+ FrontSkipNum = StringId - StartStringId;
+ } else {
+ //
+ // Skip block + New block + [Skip block]
+ //
+ NewBlockSize = OldBlockSize + NewUCSBlockLen + SkipLen;
+ FrontSkipNum = StringId - StartStringId;
+ }
+
+ StringBlock = (UINT8 *) AllocateZeroPool (NewBlockSize);
+ if (StringBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy old block in front of skip block.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldStringAddr - StringPackage->StringBlock);
+ BlockPtr = StringBlock + (OldStringAddr - StringPackage->StringBlock);
+
+ if (FrontSkipNum > 0) {
+ *BlockPtr = *BlockType;
+ if (*BlockType == EFI_HII_SIBT_SKIP1) {
+ *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) FrontSkipNum;
+ } else {
+ *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) FrontSkipNum;
+ }
+ BlockPtr += SkipLen;
+ }
+
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
+ //
+ *StringBlockAddr = BlockPtr;
+ if (FontBlock) {
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
+ } else {
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ }
+ BlockPtr += NewUCSBlockLen;
+
+ if (IdCount > FrontSkipNum + 1) {
+ *BlockPtr = *BlockType;
+ if (*BlockType == EFI_HII_SIBT_SKIP1) {
+ *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) (IdCount - FrontSkipNum - 1);
+ } else {
+ *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) (IdCount - FrontSkipNum - 1);
+ }
+ BlockPtr += SkipLen;
+ }
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ CopyMem (BlockPtr, OldStringAddr + SkipLen, OldBlockSize - (OldStringAddr - StringPackage->StringBlock) - SkipLen);
+
+ if (FontBlock) {
+ *BlockType = EFI_HII_SIBT_STRING_UCS2_FONT;
+ } else {
+ *BlockType = EFI_HII_SIBT_STRING_UCS2;
+ }
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += NewBlockSize - OldBlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse all string blocks to set a String specified by StringId.
+
+ This is a internal function.
+
+ @param Private HII database driver private structure.
+ @param StringPackage HII string package instance.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the input font info.
+
+ @retval EFI_SUCCESS The string was updated successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The String or Language was NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+SetStringWorker (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN OUT HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ IN EFI_STRING String,
+ IN EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ UINT8 *StringTextPtr;
+ UINT8 BlockType;
+ UINT8 *StringBlockAddr;
+ UINTN StringTextOffset;
+ EFI_STATUS Status;
+ UINT8 *Block;
+ UINT8 *BlockPtr;
+ UINTN BlockSize;
+ UINTN OldBlockSize;
+ HII_FONT_INFO *LocalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ BOOLEAN Referred;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINTN StringSize;
+ UINTN TmpSize;
+ EFI_STRING_ID StartStringId;
+
+ StartStringId = 0;
+ StringSize = 0;
+ ASSERT (Private != NULL && StringPackage != NULL && String != NULL);
+ ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ //
+ // Find the specified string block
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ StringId,
+ &BlockType,
+ &StringBlockAddr,
+ &StringTextOffset,
+ NULL,
+ &StartStringId
+ );
+ if (EFI_ERROR (Status) && (BlockType == EFI_HII_SIBT_SKIP1 || BlockType == EFI_HII_SIBT_SKIP2)) {
+ Status = InsertLackStringBlock(StringPackage,
+ StartStringId,
+ StringId,
+ &BlockType,
+ &StringBlockAddr,
+ (BOOLEAN)(StringFontInfo != NULL)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (StringFontInfo != NULL) {
+ StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ } else {
+ StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16);
+ }
+ }
+
+ LocalFont = NULL;
+ GlobalFont = NULL;
+ Referred = FALSE;
+
+ //
+ // The input StringFontInfo should exist in current database if specified.
+ //
+ if (StringFontInfo != NULL) {
+ if (!IsFontInfoExisted (Private, StringFontInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ Referred = ReferFontInfoLocally (
+ Private,
+ StringPackage,
+ StringPackage->FontId,
+ FALSE,
+ GlobalFont,
+ &LocalFont
+ );
+ if (!Referred) {
+ StringPackage->FontId++;
+ }
+ }
+ //
+ // Update the FontId of the specified string block to input font info.
+ //
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK)) = LocalFont->FontId;
+ break;
+ default:
+ //
+ // When modify the font info of these blocks, the block type should be updated
+ // to contain font info thus the whole structure should be revised.
+ // It is recommended to use tool to modify the block type not in the code.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+
+ //
+ // Set the string text and font.
+ //
+ StringTextPtr = StringBlockAddr + StringTextOffset;
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ BlockSize = OldBlockSize + StrLen (String);
+ BlockSize -= AsciiStrSize ((CHAR8 *) StringTextPtr);
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
+ BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
+
+ while (*String != 0) {
+ *BlockPtr++ = (CHAR8) *String++;
+ }
+ *BlockPtr++ = 0;
+
+
+ TmpSize = OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CopyMem (
+ BlockPtr,
+ StringTextPtr + AsciiStrSize ((CHAR8 *)StringTextPtr),
+ TmpSize
+ );
+
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ //
+ // Use StrSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+
+ BlockSize = OldBlockSize + StrSize (String) - StringSize;
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
+ BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
+
+ CopyMem (BlockPtr, String, StrSize (String));
+ BlockPtr += StrSize (String);
+
+ CopyMem (
+ BlockPtr,
+ StringTextPtr + StringSize,
+ OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - StringSize
+ );
+
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
+ break;
+
+ default:
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Insert a new EFI_HII_SIBT_FONT_BLOCK to the header of string block, if incoming
+ // StringFontInfo does not exist in current string package.
+ //
+ // This new block does not impact on the value of StringId.
+ //
+ //
+ if (StringFontInfo == NULL || Referred) {
+ return EFI_SUCCESS;
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ BlockSize = OldBlockSize + sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16) +
+ StrSize (GlobalFont->FontInfo->FontName);
+
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockPtr = Block;
+ Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
+ Ext2.BlockType2 = EFI_HII_SIBT_FONT;
+ Ext2.Length = (UINT16) (BlockSize - OldBlockSize);
+ CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
+
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr ++;
+ CopyMem (BlockPtr, &GlobalFont->FontInfo->FontSize, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+ CopyMem (BlockPtr, &GlobalFont->FontInfo->FontStyle, sizeof (UINT32));
+ BlockPtr += sizeof (UINT32);
+ CopyMem (
+ BlockPtr,
+ GlobalFont->FontInfo->FontName,
+ StrSize (GlobalFont->FontInfo->FontName)
+ );
+ BlockPtr += StrSize (GlobalFont->FontInfo->FontName);
+
+ CopyMem (BlockPtr, StringPackage->StringBlock, OldBlockSize);
+
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += Ext2.Length;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function adds the string String to the group of strings owned by PackageList, with the
+ specified font information StringFontInfo and returns a new string id.
+ The new string identifier is guaranteed to be unique within the package list.
+ That new string identifier is reserved for all languages in the package list.
+
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList Handle of the package list where this string will
+ be added.
+ @param StringId On return, contains the new strings id, which is
+ unique within PackageList.
+ @param Language Points to the language for the new string.
+ @param LanguageName Points to the printable language name to associate
+ with the passed in Language field.If LanguageName
+ is not NULL and the string package header's
+ LanguageName associated with a given Language is
+ not zero, the LanguageName being passed in will
+ be ignored.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the new string's font information or
+ NULL if the string should have the default system
+ font, size and style.
+
+ @retval EFI_SUCCESS The new string was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of resources.
+ @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL or Language is
+ NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_STRING_ID *StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST CHAR16 *LanguageName, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 HeaderSize;
+ UINT32 BlockSize;
+ UINT32 OldBlockSize;
+ UINT8 *StringBlock;
+ UINT8 *BlockPtr;
+ UINT32 Ucs2BlockSize;
+ UINT32 FontBlockSize;
+ UINT32 Ucs2FontBlockSize;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ HII_FONT_INFO *LocalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ EFI_STRING_ID NewStringId;
+ EFI_STRING_ID NextStringId;
+ EFI_STRING_ID Index;
+ HII_STRING_PACKAGE_INSTANCE *MatchStringPackage;
+ BOOLEAN NewStringPackageCreated;
+
+
+ if (This == NULL || String == NULL || StringId == NULL || Language == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ GlobalFont = NULL;
+
+ //
+ // If StringFontInfo specify a paritcular font, it should exist in current database.
+ //
+ if (StringFontInfo != NULL) {
+ if (!IsFontInfoExisted (Private, (EFI_FONT_INFO *) StringFontInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Get the matching package list.
+ //
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ Status = EFI_SUCCESS;
+ NewStringPackageCreated = FALSE;
+ NewStringId = 0;
+ NextStringId = 0;
+ StringPackage = NULL;
+ MatchStringPackage = NULL;
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ //
+ // Create a string block and corresponding font block if exists, then append them
+ // to the end of the string package.
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ &NextStringId,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Make sure that new StringId is same in all String Packages for the different language.
+ //
+ if (NewStringId != 0 && NewStringId != NextStringId) {
+ ASSERT (FALSE);
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ NewStringId = NextStringId;
+ //
+ // Get the matched string package with language.
+ //
+ if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ MatchStringPackage = StringPackage;
+ } else {
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ //
+ // Create a blank EFI_HII_SIBT_STRING_UCS2_BLOCK to reserve new string ID.
+ //
+ Ucs2BlockSize = (UINT32) sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
+
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize);
+ if (StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create a blank EFI_HII_SIBT_STRING_UCS2 block
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize;
+ PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize;
+ }
+ }
+ if (NewStringId == 0) {
+ //
+ // No string package is found.
+ // Create new string package. StringId 1 is reserved for Language Name string.
+ //
+ *StringId = 2;
+ } else {
+ //
+ // Set new StringId
+ //
+ *StringId = (EFI_STRING_ID) (NewStringId + 1);
+ }
+
+ if (MatchStringPackage != NULL) {
+ StringPackage = MatchStringPackage;
+ } else {
+ //
+ // LanguageName is required to create a new string package.
+ //
+ if (LanguageName == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ StringPackage = AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE));
+ if (StringPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE;
+ StringPackage->MaxStringId = *StringId;
+ StringPackage->FontId = 0;
+ InitializeListHead (&StringPackage->FontInfoList);
+
+ //
+ // Fill in the string package header
+ //
+ HeaderSize = (UINT32) (AsciiStrSize ((CHAR8 *) Language) - 1 + sizeof (EFI_HII_STRING_PACKAGE_HDR));
+ StringPackage->StringPkgHdr = AllocateZeroPool (HeaderSize);
+ if (StringPackage->StringPkgHdr == NULL) {
+ FreePool (StringPackage);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ StringPackage->StringPkgHdr->Header.Type = EFI_HII_PACKAGE_STRINGS;
+ StringPackage->StringPkgHdr->HdrSize = HeaderSize;
+ StringPackage->StringPkgHdr->StringInfoOffset = HeaderSize;
+ CopyMem (StringPackage->StringPkgHdr->LanguageWindow, mLanguageWindow, 16 * sizeof (CHAR16));
+ StringPackage->StringPkgHdr->LanguageName = 1;
+ AsciiStrCpyS (StringPackage->StringPkgHdr->Language, (HeaderSize - OFFSET_OF(EFI_HII_STRING_PACKAGE_HDR,Language)) / sizeof (CHAR8), (CHAR8 *) Language);
+
+ //
+ // Calculate the length of the string blocks, including string block to record
+ // printable language full name and EFI_HII_SIBT_END_BLOCK.
+ //
+ Ucs2BlockSize = (UINT32) (StrSize ((CHAR16 *) LanguageName) +
+ (*StringId - 1) * sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16));
+
+ BlockSize = Ucs2BlockSize + sizeof (EFI_HII_SIBT_END_BLOCK);
+ StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (BlockSize);
+ if (StringPackage->StringBlock == NULL) {
+ FreePool (StringPackage->StringPkgHdr);
+ FreePool (StringPackage);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Insert the string block of printable language full name
+ //
+ BlockPtr = StringPackage->StringBlock;
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ CopyMem (BlockPtr, (EFI_STRING) LanguageName, StrSize ((EFI_STRING) LanguageName));
+ BlockPtr += StrSize ((EFI_STRING) LanguageName);
+ for (Index = 2; Index <= *StringId - 1; Index ++) {
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
+ }
+ //
+ // Insert the end block
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+
+ //
+ // Append this string package node to string package array in this package list.
+ //
+ StringPackage->StringPkgHdr->Header.Length = HeaderSize + BlockSize;
+ PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ InsertTailList (&PackageListNode->StringPkgHdr, &StringPackage->StringEntry);
+ NewStringPackageCreated = TRUE;
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+
+ if (StringFontInfo == NULL) {
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_BLOCK since font info is not specified.
+ //
+ Ucs2BlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK)
+ - sizeof (CHAR16));
+
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize);
+ if (StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2 block
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize;
+ PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize;
+
+ } else {
+ //
+ // StringFontInfo is specified here. If there is a EFI_HII_SIBT_FONT_BLOCK
+ // which refers to this font info, create a EFI_HII_SIBT_STRING_UCS2_FONT block
+ // only. Otherwise create a EFI_HII_SIBT_FONT block with a EFI_HII_SIBT_STRING
+ // _UCS2_FONT block.
+ //
+ Ucs2FontBlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) -
+ sizeof (CHAR16));
+ if (ReferFontInfoLocally (Private, StringPackage, StringPackage->FontId, FALSE, GlobalFont, &LocalFont)) {
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT block only.
+ //
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2FontBlockSize);
+ if (StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr ++;
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Ucs2FontBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += Ucs2FontBlockSize;
+
+ } else {
+ //
+ // EFI_HII_SIBT_FONT_BLOCK does not exist in current string package, so
+ // create a EFI_HII_SIBT_FONT block to record the font info, then generate
+ // a EFI_HII_SIBT_STRING_UCS2_FONT block to record the incoming string.
+ //
+ FontBlockSize = (UINT32) (StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName) +
+ sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16));
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + FontBlockSize + Ucs2FontBlockSize);
+ if (StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+
+ //
+ // Create a EFI_HII_SIBT_FONT block firstly and then backup its info in string
+ // package instance for future reference.
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+
+ Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
+ Ext2.BlockType2 = EFI_HII_SIBT_FONT;
+ Ext2.Length = (UINT16) FontBlockSize;
+ CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
+
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr ++;
+ CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontSize, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+ CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontStyle, sizeof (EFI_HII_FONT_STYLE));
+ BlockPtr += sizeof (EFI_HII_FONT_STYLE);
+ CopyMem (
+ BlockPtr,
+ &((EFI_FONT_INFO *) StringFontInfo)->FontName,
+ StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName)
+ );
+ BlockPtr += StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName);
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
+ //
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr ++;
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ ZeroMem (StringPackage->StringBlock, OldBlockSize);
+ FreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += FontBlockSize + Ucs2FontBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += FontBlockSize + Ucs2FontBlockSize;
+
+ //
+ // Increase the FontId to make it unique since we already add
+ // a EFI_HII_SIBT_FONT block to this string package.
+ //
+ StringPackage->FontId++;
+ }
+ }
+
+Done:
+ if (!EFI_ERROR (Status) && NewStringPackageCreated) {
+ //
+ // Trigger any registered notification function for new string package
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_NEW_PACK,
+ (VOID *) StringPackage,
+ EFI_HII_PACKAGE_STRINGS,
+ PackageList
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update MaxString Id to new StringId
+ //
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ StringPackage->MaxStringId = *StringId;
+ }
+ } else if (NewStringPackageCreated) {
+ //
+ // Free the allocated new string Package when new string can't be added.
+ //
+ RemoveEntryList (&StringPackage->StringEntry);
+ FreePool (StringPackage->StringBlock);
+ FreePool (StringPackage->StringPkgHdr);
+ FreePool (StringPackage);
+ }
+ //
+ // The contents of HiiDataBase may updated,need to check.
+ //
+ //
+ // Check whether need to get the contents of HiiDataBase.
+ // Only after ReadyToBoot to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ if (!EFI_ERROR (Status)) {
+ HiiGetDatabaseInfo(&Private->HiiDatabase);
+ }
+ }
+
+ EfiReleaseLock (&mHiiDatabaseLock);
+
+ return Status;
+}
+
+
+/**
+ This function retrieves the string specified by StringId which is associated
+ with the specified PackageList in the language Language and copies it into
+ the buffer specified by String.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param Language Points to the language for the retrieved string.
+ @param PackageList The package list in the HII database to search for
+ the specified string.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param String Points to the new null-terminated string.
+ @param StringSize On entry, points to the size of the buffer pointed
+ to by String, in bytes. On return, points to the
+ length of the string, in bytes.
+ @param StringFontInfo If not NULL, points to the string's font
+ information. It's caller's responsibility to free
+ this buffer.
+
+ @retval EFI_SUCCESS The string was returned successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not available.
+ @retval EFI_NOT_FOUND The string specified by StringId is available but
+ not in the specified language.
+ The specified PackageList is not in the database.
+ @retval EFI_INVALID_LANGUAGE - The string specified by StringId is available but
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to
+ hold the string.
+ @retval EFI_INVALID_PARAMETER The Language or StringSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by StringSize was not zero and String was NULL.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN CONST CHAR8 *Language,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING String,
+ IN OUT UINTN *StringSize,
+ OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+
+ if (This == NULL || Language == NULL || StringId < 1 || StringSize == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (String == NULL && *StringSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = NULL;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+
+ if (PackageListNode != NULL) {
+ //
+ // First search: to match the StringId in the specified language.
+ //
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ Status = GetStringWorker (Private, StringPackage, StringId, String, StringSize, StringFontInfo);
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ }
+ }
+ //
+ // Second search: to match the StringId in other available languages if exist.
+ //
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ Status = GetStringWorker (Private, StringPackage, StringId, NULL, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_LANGUAGE;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ This function updates the string specified by StringId in the specified PackageList to the text
+ specified by String and, optionally, the font information specified by StringFontInfo.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list containing the strings.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param Language Points to the language for the updated string.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the string's font information or NULL if
+ the string font information is not changed.
+
+ @retval EFI_SUCCESS The string was updated successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The String or Language was NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 OldPackageLen;
+
+ if (This == NULL || Language == NULL || StringId < 1 || String == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiAcquireLock (&mHiiDatabaseLock);
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = NULL;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
+ }
+ }
+
+ if (PackageListNode != NULL) {
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ OldPackageLen = StringPackage->StringPkgHdr->Header.Length;
+ Status = SetStringWorker (
+ Private,
+ StringPackage,
+ StringId,
+ (EFI_STRING) String,
+ (EFI_FONT_INFO *) StringFontInfo
+ );
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return Status;
+ }
+ PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length - OldPackageLen;
+ //
+ // Check whether need to get the contents of HiiDataBase.
+ // Only after ReadyToBoot to do the export.
+ //
+ if (gExportAfterReadyToBoot) {
+ HiiGetDatabaseInfo(&Private->HiiDatabase);
+ }
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ EfiReleaseLock (&mHiiDatabaseLock);
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ This function returns the list of supported languages, in the format specified
+ in Appendix M of UEFI 2.1 spec.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list to examine.
+ @param Languages Points to the buffer to hold the returned
+ null-terminated ASCII string.
+ @param LanguagesSize On entry, points to the size of the buffer pointed
+ to by Languages, in bytes. On return, points to
+ the length of Languages, in bytes.
+
+ @retval EFI_SUCCESS The languages were returned successfully.
+ @retval EFI_INVALID_PARAMETER The LanguagesSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by LanguagesSize is not zero and Languages is NULL.
+ @retval EFI_BUFFER_TOO_SMALL The LanguagesSize is too small to hold the list of
+ supported languages. LanguageSize is updated to
+ contain the required size.
+ @retval EFI_NOT_FOUND Could not find string package in specified
+ packagelist.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN OUT CHAR8 *Languages,
+ IN OUT UINTN *LanguagesSize
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINTN ResultSize;
+
+ if (This == NULL || LanguagesSize == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*LanguagesSize != 0 && Languages == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Search the languages in the specified packagelist.
+ //
+ ResultSize = 0;
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ ResultSize += AsciiStrSize (StringPackage->StringPkgHdr->Language);
+ if (ResultSize <= *LanguagesSize) {
+ AsciiStrCpyS (Languages, *LanguagesSize / sizeof (CHAR8), StringPackage->StringPkgHdr->Language);
+ Languages += AsciiStrSize (StringPackage->StringPkgHdr->Language);
+ *(Languages - 1) = L';';
+ }
+ }
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*LanguagesSize < ResultSize) {
+ *LanguagesSize = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *(Languages - 1) = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Each string package has associated with it a single primary language and zero
+ or more secondary languages. This routine returns the secondary languages
+ associated with a package list.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list to examine.
+ @param PrimaryLanguage Points to the null-terminated ASCII string that specifies
+ the primary language. Languages are specified in the
+ format specified in Appendix M of the UEFI 2.0 specification.
+ @param SecondaryLanguages Points to the buffer to hold the returned null-terminated
+ ASCII string that describes the list of
+ secondary languages for the specified
+ PrimaryLanguage. If there are no secondary
+ languages, the function returns successfully, but
+ this is set to NULL.
+ @param SecondaryLanguagesSize On entry, points to the size of the buffer pointed
+ to by SecondaryLanguages, in bytes. On return,
+ points to the length of SecondaryLanguages in bytes.
+
+ @retval EFI_SUCCESS Secondary languages were correctly returned.
+ @retval EFI_INVALID_PARAMETER PrimaryLanguage or SecondaryLanguagesSize was NULL.
+ @retval EFI_INVALID_PARAMETER The value referenced by SecondaryLanguagesSize is not
+ zero and SecondaryLanguages is NULL.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by SecondaryLanguagesSize is
+ too small to hold the returned information.
+ SecondaryLanguageSize is updated to hold the size of
+ the buffer required.
+ @retval EFI_INVALID_LANGUAGE The language specified by PrimaryLanguage is not
+ present in the specified package list.
+ @retval EFI_NOT_FOUND The specified PackageList is not in the Database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetSecondaryLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN CONST CHAR8 *PrimaryLanguage,
+ IN OUT CHAR8 *SecondaryLanguages,
+ IN OUT UINTN *SecondaryLanguagesSize
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ CHAR8 *Languages;
+ UINTN ResultSize;
+
+ if (This == NULL || PackageList == NULL || PrimaryLanguage == NULL || SecondaryLanguagesSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (SecondaryLanguages == NULL && *SecondaryLanguagesSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Languages = NULL;
+ ResultSize = 0;
+ for (Link1 = PackageListNode->StringPkgHdr.ForwardLink;
+ Link1 != &PackageListNode->StringPkgHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ StringPackage = CR (Link1, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) PrimaryLanguage)) {
+ Languages = StringPackage->StringPkgHdr->Language;
+ //
+ // Language is a series of ';' terminated strings, first one is primary
+ // language and following with other secondary languages or NULL if no
+ // secondary languages any more.
+ //
+ Languages = AsciiStrStr (Languages, ";");
+ if (Languages == NULL) {
+ break;
+ }
+ Languages++;
+
+ ResultSize = AsciiStrSize (Languages);
+ if (ResultSize <= *SecondaryLanguagesSize) {
+ AsciiStrCpyS (SecondaryLanguages, *SecondaryLanguagesSize / sizeof (CHAR8), Languages);
+ } else {
+ *SecondaryLanguagesSize = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_LANGUAGE;
+}
+
+/**
+ Converts the ascii character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+EFIAPI
+AsciiHiiToLower (
+ IN CHAR8 *ConfigString
+ )
+{
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (; *ConfigString != '\0'; ConfigString++) {
+ if ( *ConfigString >= 'A' && *ConfigString <= 'Z') {
+ *ConfigString = (CHAR8) (*ConfigString - 'A' + 'a');
+ }
+ }
+}
+
+/**
+ Compare whether two names of languages are identical.
+
+ @param Language1 Name of language 1 from StringPackage
+ @param Language2 Name of language 2 to be compared with language 1.
+
+ @retval TRUE same
+ @retval FALSE not same
+
+**/
+BOOLEAN
+HiiCompareLanguage (
+ IN CHAR8 *Language1,
+ IN CHAR8 *Language2
+ )
+{
+ UINTN Index;
+ UINTN StrLen;
+ CHAR8 *Lan1;
+ CHAR8 *Lan2;
+
+ //
+ // Convert to lower to compare.
+ //
+ StrLen = AsciiStrSize (Language1);
+ Lan1 = AllocateZeroPool (StrLen);
+ ASSERT (Lan1 != NULL);
+ AsciiStrCpyS(Lan1, StrLen / sizeof (CHAR8), Language1);
+ AsciiHiiToLower (Lan1);
+
+ StrLen = AsciiStrSize (Language2);
+ Lan2 = AllocateZeroPool (StrLen);
+ ASSERT (Lan2 != NULL);
+ AsciiStrCpyS(Lan2, StrLen / sizeof (CHAR8), Language2);
+ AsciiHiiToLower (Lan2);
+
+ //
+ // Compare the Primary Language in Language1 to Language2
+ //
+ for (Index = 0; Lan1[Index] != 0 && Lan1[Index] != ';'; Index++) {
+ if (Lan1[Index] != Lan2[Index]) {
+ //
+ // Return FALSE if any characters are different.
+ //
+ FreePool (Lan1);
+ FreePool (Lan2);
+ return FALSE;
+ }
+ }
+
+ FreePool (Lan1);
+ FreePool (Lan2);
+
+ //
+ // Only return TRUE if Language2[Index] is a Null-terminator which means
+ // the Primary Language in Language1 is the same length as Language2. If
+ // Language2[Index] is not a Null-terminator, then Language2 is longer than
+ // the Primary Language in Language1, and FALSE must be returned.
+ //
+ return (BOOLEAN) (Language2[Index] == 0);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.c b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.c
new file mode 100644
index 000000000..01cbf37fb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.c
@@ -0,0 +1,146 @@
+/** @file
+This is an example of how a driver retrieve HII data using HII Package List
+Protocol, and how to publish the HII data.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Guid/HiiResourceSampleHii.h>
+#include <Protocol/HiiPackageList.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/HiiLib.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()
+
+
+EFI_HII_HANDLE mHiiHandle = NULL;
+EFI_HANDLE mDriverHandle = NULL;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ HII_RESOURCE_SAMPLE_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Main entry for this driver.
+
+ @param[in] ImageHandle Image handle this driver.
+ @param[in] SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiResourcesSampleInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ //
+ // Retrieve HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **) &PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Publish sample Fromset
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mHiiVendorDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Publish HII package list to HII Database.
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ mDriverHandle,
+ &mHiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unloads the application and its installed protocol.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+HiiResourcesSampleUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ if (mDriverHandle != NULL) {
+ gBS->UninstallProtocolInterface (
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath
+ );
+ mDriverHandle = NULL;
+ }
+
+ if (mHiiHandle != NULL) {
+ HiiRemovePackages (mHiiHandle);
+ mHiiHandle = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.uni b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.uni
new file mode 100644
index 000000000..fb83d51fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSample.uni
@@ -0,0 +1,18 @@
+// /** @file
+// This is a sample HII resource driver.
+//
+// This driver show how a HII driver retrieve HII data using HII Package List protocol
+// and publish the HII data.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A sample HII resource driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver show how a HII driver retrieve HII data using HII Package List protocol\n"
+ "and publish the HII data."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleDxe.inf b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleDxe.inf
new file mode 100644
index 000000000..5ed9ee3ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# This is a sample HII resource driver.
+#
+# This driver show how a HII driver retrieve HII data using HII Package List protocol
+# and publish the HII data.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HiiResourcesSample
+ MODULE_UNI_FILE = HiiResourcesSample.uni
+ FILE_GUID = D49D2EB0-44D5-4621-9FD6-1A92C9109B99
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = HiiResourcesSampleInit
+ UNLOAD_IMAGE = HiiResourcesSampleUnload
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ HiiResourcesSample.c
+ SampleStrings.uni
+ Sample.vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ HiiLib
+
+[Protocols]
+ gEfiHiiPackageListProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ HiiResourcesSampleExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleExtra.uni b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleExtra.uni
new file mode 100644
index 000000000..f038951f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/HiiResourcesSampleExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// HiiResourcesSample Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"HII Resources Sample DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/Sample.vfr b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/Sample.vfr
new file mode 100644
index 000000000..da75455cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/Sample.vfr
@@ -0,0 +1,39 @@
+// *++
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// Sample.vfr
+//
+// Abstract:
+//
+// Sample Form.
+//
+// Revision History:
+//
+// --*/
+
+#include <Guid/HiiResourceSampleHii.h>
+
+formset
+ guid = HII_RESOURCE_SAMPLE_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_SAMPLE_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_SAMPLE_FORM_SET_HELP),
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_SAMPLE_FORM1_TITLE);
+
+ text
+ help = STRING_TOKEN(STR_SAMPLE_VERSION_HELP),
+ text = STRING_TOKEN(STR_SAMPLE_VERSION_TEXT),
+ text = STRING_TOKEN(STR_SAMPLE_EMPTY);
+
+ subtitle text = STRING_TOKEN(STR_SAMPLE_EMPTY);
+
+ subtitle text = STRING_TOKEN(STR_SAMPLE_ESC);
+
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/SampleStrings.uni b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/SampleStrings.uni
new file mode 100644
index 000000000..e91f99165
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/HiiResourcesSampleDxe/SampleStrings.uni
@@ -0,0 +1,38 @@
+// *++
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// SampleStrings.uni
+//
+// Abstract:
+//
+// String definitions for Sample.vfr
+//
+// Revision History:
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+
+#string STR_SAMPLE_FORM_SET_TITLE #language en-US "HII Resource Section Sample"
+ #language fr-FR "HII Resource Section Sample"
+#string STR_SAMPLE_FORM_SET_HELP #language en-US "This HII Package List is built in PE/COFF .rsrc section"
+ #language fr-FR "This HII Package List is built in PE/COFF .rsrc section"
+#string STR_SAMPLE_FORM1_TITLE #language en-US "Sample Form"
+ #language fr-FR "Sample Form"
+#string STR_SAMPLE_VERSION_TEXT #language en-US "Firmware Revision EDKII"
+ #language fr-FR "Firmware Revision EDKII"
+#string STR_SAMPLE_VERSION_HELP #language en-US "The date of the revision of the Firmware being used."
+ #language fr-FR "The date of the revision of the Firmware being used."
+#string STR_SAMPLE_ESC #language en-US "Press ESC to exit."
+ #language fr-FR "Press ESC to exit."
+#string STR_SAMPLE_EMPTY #language en-US ""
+ #language fr-FR ""
diff --git a/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.c b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.c
new file mode 100644
index 000000000..c1278157a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.c
@@ -0,0 +1,251 @@
+/** @file
+ Dummy implementation of Legacy Region 2 Protocol.
+
+ This generic implementation of the Legacy Region 2 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 2 Protocol on
+ a platform that does support HW locking of the legacy memory regions.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <LegacyRegion2.h>
+
+EFI_HANDLE mLegacyRegion2Handle = NULL;
+
+EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = {
+ LegacyRegion2Decode,
+ LegacyRegion2Lock,
+ LegacyRegion2BootLock,
+ LegacyRegion2Unlock,
+ LegacyRegionGetInfo
+};
+
+/**
+ Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
+
+ If the On parameter evaluates to TRUE, this function enables memory reads in the address range
+ Start to (Start + Length - 1).
+ If the On parameter evaluates to FALSE, this function disables memory reads in the address range
+ Start to (Start + Length - 1).
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose attributes
+ should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address
+ was not aligned to a region's starting address or if the length
+ was greater than the number of bytes in the first region.
+ @param On[in] Decode / Non-Decode flag.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Decode (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity,
+ IN BOOLEAN *On
+ )
+{
+ if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Granularity != NULL);
+ *Granularity = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Modify the hardware to disallow memory writes in a region.
+
+ This function changes the attributes of a memory range to not allow writes.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Lock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ )
+{
+ if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Granularity != NULL);
+ *Granularity = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Modify the hardware to disallow memory attribute changes in a region.
+
+ This function makes the attributes of a region read only. Once a region is boot-locked with this
+ function, the read and write attributes of that region cannot be changed until a power cycle has
+ reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+ @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
+ a way that will not affect memory regions outside the legacy memory
+ region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2BootLock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ )
+{
+ if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Modify the hardware to allow memory writes in a region.
+
+ This function changes the attributes of a memory range to allow writes.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Unlock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ )
+{
+ if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT (Granularity != NULL);
+ *Granularity = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get region information for the attributes of the Legacy Region.
+
+ This function is used to discover the granularity of the attributes for the memory in the legacy
+ region. Each attribute may have a different granularity and the granularity may not be the same
+ for all memory ranges in the legacy region.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION2_PROTOCOL instance.
+ @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
+ buffer.
+ @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
+ region information is deposited. This buffer will contain a list of
+ DescriptorCount number of region descriptors. This function will
+ provide the memory for the buffer.
+
+ @retval EFI_SUCCESS The information structure was returned.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionGetInfo (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ OUT UINT32 *DescriptorCount,
+ OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ 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.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Install (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure the Legacy Region 2 Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiLegacyRegion2ProtocolGuid);
+
+ //
+ // Install the protocol on a new handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mLegacyRegion2Handle,
+ &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.h b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.h
new file mode 100644
index 000000000..56108d8ef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2.h
@@ -0,0 +1,169 @@
+/** @file
+ Internal include file for the dummy Legacy Region 2 Protocol implementation.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DUMMY_LEGACY_REGION2_H__
+#define __DUMMY_LEGACY_REGION2_H__
+
+#include <Protocol/LegacyRegion2.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
+
+ If the On parameter evaluates to TRUE, this function enables memory reads in the address range
+ Start to (Start + Length - 1).
+ If the On parameter evaluates to FALSE, this function disables memory reads in the address range
+ Start to (Start + Length - 1).
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose attributes
+ should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address
+ was not aligned to a region's starting address or if the length
+ was greater than the number of bytes in the first region.
+ @param On[in] Decode / Non-Decode flag.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Decode (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity,
+ IN BOOLEAN *On
+ );
+
+/**
+ Modify the hardware to disallow memory writes in a region.
+
+ This function changes the attributes of a memory range to not allow writes.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Lock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ );
+
+/**
+ Modify the hardware to disallow memory attribute changes in a region.
+
+ This function makes the attributes of a region read only. Once a region is boot-locked with this
+ function, the read and write attributes of that region cannot be changed until a power cycle has
+ reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+ @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
+ a way that will not affect memory regions outside the legacy memory
+ region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2BootLock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ );
+
+/**
+ Modify the hardware to allow memory writes in a region.
+
+ This function changes the attributes of a memory range to allow writes.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param Start[in] The beginning of the physical address of the region whose
+ attributes should be modified.
+ @param Length[in] The number of bytes of memory whose attributes should be modified.
+ The actual number of bytes modified may be greater than the number
+ specified.
+ @param Granularity[out] The number of bytes in the last region affected. This may be less
+ than the total number of bytes affected if the starting address was
+ not aligned to a region's starting address or if the length was
+ greater than the number of bytes in the first region.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Unlock (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity
+ );
+
+/**
+ Get region information for the attributes of the Legacy Region.
+
+ This function is used to discover the granularity of the attributes for the memory in the legacy
+ region. Each attribute may have a different granularity and the granularity may not be the same
+ for all memory ranges in the legacy region.
+
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+ @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
+ buffer.
+ @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
+ region information is deposited. This buffer will contain a list of
+ DescriptorCount number of region descriptors. This function will
+ provide the memory for the buffer.
+
+ @retval EFI_SUCCESS The region's attributes were successfully modified.
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionGetInfo (
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,
+ OUT UINT32 *DescriptorCount,
+ OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.inf b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.inf
new file mode 100644
index 000000000..09b9f1c3c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.inf
@@ -0,0 +1,54 @@
+## @file
+# Produces the Legacy Region 2 Protocol.
+#
+# This generic implementation of the Legacy Region 2 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 2 Protocol on
+# a platform that does support HW locking of the legacy memory regions.
+#
+# Note: This module does not fully comply with PI Specification of Legacy Region 2
+# Protocol. For Lock/UnLock/Decode, EFI_SUCCESS is returned although the region's
+# attributes were not actually modified.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyRegion2Dxe
+ MODULE_UNI_FILE = LegacyRegion2Dxe.uni
+ FILE_GUID = EC2BEECA-E84A-445B-869B-F7A73C96F58A
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = LegacyRegion2Install
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ LegacyRegion2.c
+ LegacyRegion2.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiLegacyRegion2ProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LegacyRegion2DxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.uni b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.uni
new file mode 100644
index 000000000..997b742b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2Dxe.uni
@@ -0,0 +1,24 @@
+// /** @file
+// Produces the Legacy Region 2 Protocol.
+//
+// This generic implementation of the Legacy Region 2 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 2 Protocol on
+// a platform that does support HW locking of the legacy memory regions.
+//
+// Note: This module does not fully comply with PI Specification of Legacy Region 2
+// Protocol. For Lock/UnLock/Decode, EFI_SUCCESS is returned although the region's
+// attributes were not actually modified.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the Legacy Region 2 Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This generic implementation of the Legacy Region 2 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 2 Protocol on a platform that does support HW locking of the legacy memory regions. Note: This module does not fully comply with PI Specification of Legacy Region 2 Protocol. For Lock/UnLock/Decode, EFI_SUCCESS is returned although the region's attributes were not actually modified."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2DxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2DxeExtra.uni
new file mode 100644
index 000000000..42cfa6c02
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LegacyRegion2Dxe/LegacyRegion2DxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// LegacyRegion2Dxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Legacy Region DXE Driver v2"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
new file mode 100644
index 000000000..58e658ee0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.c
@@ -0,0 +1,421 @@
+/** @file
+ Produce Load File Protocol for UEFI Applications in Firmware Volumes
+
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/LzmaDecompress.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('l', 'f', 'f', 'v')
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOAD_FILE_PROTOCOL LoadFile;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_GUID NameGuid;
+ LIST_ENTRY Link;
+} LOAD_FILE_ON_FV2_PRIVATE_DATA;
+
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, LoadFile, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
+#define LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK(a) CR (a, LOAD_FILE_ON_FV2_PRIVATE_DATA, Link, LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE)
+
+VOID *mFvRegistration;
+LIST_ENTRY mPrivateDataList;
+
+/**
+ Causes the driver to load a specified file from firmware volume.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] FilePath The device specific path of the file to load.
+ @param[in] BootPolicy If TRUE, indicates that the request originates from the
+ boot manager is attempting to load FilePath as a boot
+ selection. If FALSE, then FilePath must match an exact file
+ to be loaded.
+ @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
+ code of EFI_SUCCESS, the amount of data transferred to
+ Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of Buffer required to retrieve the requested file.
+ @param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
+ then no the size of the requested file is returned in
+ BufferSize.
+
+ @retval EFI_SUCCESS The file was loaded.
+ @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy.
+ @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+ BufferSize is NULL.
+ @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
+ @retval EFI_NOT_FOUND The file was not found.
+ @retval EFI_OUT_OF_RESOURCES An allocation failure occurred.
+ @retval EFI_ACCESS_DENIED The firmware volume is configured to
+ disallow reads.
+**/
+EFI_STATUS
+EFIAPI
+LoadFileOnFv2LoadFile (
+ IN EFI_LOAD_FILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;
+ VOID *Pe32Buffer;
+ UINTN Pe32BufferSize;
+ UINT32 AuthenticationStatus;
+
+ if (This == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only support BootPolicy
+ //
+ if (!BootPolicy) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get private context data
+ //
+ Private = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Determine the size of the PE32 section
+ //
+ Pe32Buffer = NULL;
+ Pe32BufferSize = 0;
+ Status = Private->Fv->ReadSection (
+ Private->Fv,
+ &Private->NameGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Pe32Buffer,
+ &Pe32BufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If the buffer passed in is not large enough, return the size of the required
+ // buffer in BufferSize and return EFI_BUFFER_TOO_SMALL
+ //
+ if (*BufferSize < Pe32BufferSize || Buffer == NULL) {
+ *BufferSize = Pe32BufferSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // The buffer passed in is large enough, so read the PE32 section directly into
+ // the buffer, update BufferSize with the actual size read, and return the status
+ // from ReadSection()
+ //
+ return Private->Fv->ReadSection (
+ Private->Fv,
+ &Private->NameGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Buffer,
+ BufferSize,
+ &AuthenticationStatus
+ );
+}
+
+LOAD_FILE_ON_FV2_PRIVATE_DATA mLoadFileOnFv2PrivateDataTemplate = {
+ LOAD_FILE_ON_FV2_PRIVATE_DATA_SIGNATURE,
+ {
+ LoadFileOnFv2LoadFile
+ }
+};
+
+/**
+ Check if the FFS has been installed LoadFileProtocol for it.
+
+ @param[in] NameGuid Point to FFS File GUID to be checked.
+
+ @retval TRUE The FFS's FileLoadProtocol is in list.
+ @retval FALSE The FFS's FileLoadProtocol is not in list.
+
+**/
+BOOLEAN
+EFIAPI
+IsInPrivateList (
+ IN EFI_GUID *NameGuid
+)
+{
+ LIST_ENTRY *Entry;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *PrivateData;
+
+ if (IsListEmpty (&mPrivateDataList)) {
+ return FALSE;
+ }
+
+ for(Entry = (&mPrivateDataList)->ForwardLink; Entry != (&mPrivateDataList); Entry = Entry->ForwardLink) {
+ PrivateData = LOAD_FILE_ON_FV2_PRIVATE_DATA_FROM_LINK (Entry);
+ if (CompareGuid (NameGuid, &PrivateData->NameGuid)) {
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:FileLoadProtocol has been installed in:%g\n", NameGuid));
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Create file device path based on FFS file GUID and UI name.
+
+ @param Device Handle to Firmware Volume.
+ @param NameGuid Point to FFS file GUID.
+ @param FileName Point to FFS UI section name.
+
+ @return the combined device path
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+CreateFileDevicePath (
+ IN EFI_HANDLE Device,
+ IN EFI_GUID *NameGuid,
+ IN CONST CHAR16 *FileName
+ )
+{
+ UINTN Size;
+ FILEPATH_DEVICE_PATH *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, NameGuid);
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (Device),
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+
+ Size = StrSize (FileName);
+ FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
+ if (FileDevicePath != NULL) {
+ FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;
+ FilePath->Header.Type = MEDIA_DEVICE_PATH;
+ FilePath->Header.SubType = MEDIA_FILEPATH_DP;
+ CopyMem (&FilePath->PathName, FileName, Size);
+ SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
+ SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
+
+ DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
+ FreePool (FileDevicePath);
+ }
+
+ return DevicePath;
+}
+
+/**
+ Install LoadFile Protocol for Application FFS.
+
+ @param Handle FV Handle.
+
+**/
+VOID
+EFIAPI
+InstallFileLoadProtocol (
+ EFI_HANDLE Handle
+)
+{
+ EFI_STATUS Status;
+ LOAD_FILE_ON_FV2_PRIVATE_DATA *Private;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_FV_FILETYPE FileType;
+ UINTN Key;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_HANDLE LoadFileHandle;
+ UINT32 AuthenticationStatus;
+ CHAR16 *UiName;
+ UINTN UiNameSize;
+
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Find a FV!\n"));
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ Fvb->GetPhysicalAddress (Fvb, &Address);
+ DEBUG ((DEBUG_INFO, "LoadFileOnFv2:Fvb->Address=%x \n", Address));
+
+ //
+ // Use Firmware Volume 2 Protocol to search for a FFS files of type
+ // EFI_FV_FILETYPE_APPLICATION and produce a LoadFile protocol for
+ // each one found.
+ //
+ FileType = EFI_FV_FILETYPE_APPLICATION;
+ Key = 0;
+ while (TRUE) {
+ Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, &Size);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ UiName = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&UiName,
+ &UiNameSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (!IsInPrivateList (&NameGuid)) {
+ Private = (LOAD_FILE_ON_FV2_PRIVATE_DATA *)AllocateCopyPool (sizeof (mLoadFileOnFv2PrivateDataTemplate), &mLoadFileOnFv2PrivateDataTemplate);
+ ASSERT (Private != NULL);
+ Private->Fv = Fv;
+ Private->DevicePath = CreateFileDevicePath (Handle, &NameGuid, UiName);
+ CopyGuid (&Private->NameGuid, &NameGuid);
+ LoadFileHandle = NULL;
+ DEBUG ((DEBUG_INFO, "Find a APPLICATION in this FV!\n"));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &LoadFileHandle,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ &gEfiLoadFileProtocolGuid, &Private->LoadFile,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ InsertTailList (&mPrivateDataList, &Private->Link);
+ } else {
+ DEBUG ((DEBUG_ERROR, "Application with the same name %s has been installed.!\n", UiName));
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+ }
+ }
+ }
+}
+
+/**
+ This notification function is invoked when an instance of the
+ LzmaCustomDecompressGuid is produced. It installs another instance of the
+ EFI_FIRMWARE_VOLUME_PROTOCOL on the handle of the FFS. This notification function
+ also handles the situation when LZMA decoder driver loaded later than FirmwareVolume driver.
+
+ @param Event The event that occurred
+ @param Context Context of event. Not used in this nofication function.
+
+**/
+VOID
+EFIAPI
+FvNotificationEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE *Handle;
+ UINTN Index;
+ EFI_HANDLE *CurHandle;
+
+
+ Handle = NULL;
+ Index = 0;
+ BufferSize = sizeof (EFI_HANDLE);
+ Handle = AllocateZeroPool (BufferSize);
+ if (Handle == NULL) {
+ return;
+ }
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &BufferSize,
+ Handle
+ );
+ if (EFI_BUFFER_TOO_SMALL == Status) {
+ FreePool (Handle);
+ Handle = AllocateZeroPool (BufferSize);
+ if (Handle == NULL) {
+ return;
+ }
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &BufferSize,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ } else if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ CurHandle = Handle;
+ for (Index=0; Index < BufferSize/sizeof (EFI_HANDLE); Index++) {
+ CurHandle = Handle + Index;
+ //
+ // Install LoadFile Protocol
+ //
+ InstallFileLoadProtocol (*CurHandle);
+ }
+ if (Handle != NULL) {
+ FreePool (Handle);
+ }
+}
+
+/**
+ Entry point function initializes global variables and installs notifications.
+
+ @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
+LoadFileOnFv2Intialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ InitializeListHead (&mPrivateDataList);
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ TPL_CALLBACK,
+ FvNotificationEvent,
+ NULL,
+ &mFvRegistration
+ );
+
+ EfiCreateProtocolNotifyEvent (
+ &gLzmaCustomDecompressGuid,
+ TPL_CALLBACK,
+ FvNotificationEvent,
+ NULL,
+ &mFvRegistration
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf
new file mode 100644
index 000000000..7aad0aff4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf
@@ -0,0 +1,62 @@
+## @file
+# Load File Module
+#
+# Allows the system to load a file from a FV2 based firmware volume. This
+# version of the module only supports loading of files for the purpose of
+# booting from the file.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010018
+ BASE_NAME = LoadFileOnFv2
+ FILE_GUID = BD712601-082F-4c59-8677-2C8A3C297948
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = LoadFileOnFv2Intialize
+ MODULE_UNI_FILE = LoadFileOnFv2.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ LoadFileOnFv2.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ DevicePathLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # Notify gLzmaCustomDecompressGuid SectionExtraction.
+ gLzmaCustomDecompressGuid
+
+[Protocols]
+ ## NOTIFY
+ ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LoadFileOnFv2Extra.uni
+
diff --git a/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni
new file mode 100644
index 000000000..6b88064f9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.uni
@@ -0,0 +1,18 @@
+// /** @file
+// LoadFileOnFv2 Localized Abstract and Description Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Allows system to load files from an FV2-based firmware volume"
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"This module allows the system to load a file from an FV2-based firmware "
+"volume. This version of the module only supports loading of files for the "
+"purpose of booting from a file."
diff --git a/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni
new file mode 100644
index 000000000..5d5681c59
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2Extra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// LoadFileOnFv2 Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Volume Load File Module"
diff --git a/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
new file mode 100644
index 000000000..f11c3a17e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
@@ -0,0 +1,434 @@
+/** @file
+ LockBox SMM driver.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmLockBoxHandler(), SmmLockBoxRestore(), SmmLockBoxUpdate(), SmmLockBoxSave()
+ will receive untrusted input and do basic validation.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmMemLib.h>
+#include <Library/LockBoxLib.h>
+
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/LockBox.h>
+#include <Guid/SmmLockBox.h>
+
+BOOLEAN mLocked = FALSE;
+
+/**
+ Dispatch function for SMM lock box save.
+
+ Caution: This function may receive untrusted input.
+ Restore buffer and length are external input, so this function will validate
+ it is in SMRAM.
+
+ @param LockBoxParameterSave parameter of lock box save
+**/
+VOID
+SmmLockBoxSave (
+ IN EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_LOCK_BOX_PARAMETER_SAVE TempLockBoxParameterSave;
+
+ //
+ // Sanity check
+ //
+ if (mLocked) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
+ LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+
+ CopyMem (&TempLockBoxParameterSave, LockBoxParameterSave, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterSave.Buffer, (UINTN)TempLockBoxParameterSave.Length)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));
+ LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+ //
+ // The SpeculationBarrier() call here is to ensure the above range check for
+ // the CommBuffer have been completed before calling into SaveLockBox().
+ //
+ SpeculationBarrier ();
+
+ //
+ // Save data
+ //
+ Status = SaveLockBox (
+ &TempLockBoxParameterSave.Guid,
+ (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,
+ (UINTN)TempLockBoxParameterSave.Length
+ );
+ LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;
+ return ;
+}
+
+/**
+ Dispatch function for SMM lock box set attributes.
+
+ @param LockBoxParameterSetAttributes parameter of lock box set attributes
+**/
+VOID
+SmmLockBoxSetAttributes (
+ IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;
+
+ //
+ // Sanity check
+ //
+ if (mLocked) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
+ LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+
+ CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));
+
+ //
+ // Update data
+ //
+ Status = SetLockBoxAttributes (
+ &TempLockBoxParameterSetAttributes.Guid,
+ TempLockBoxParameterSetAttributes.Attributes
+ );
+ LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;
+ return ;
+}
+
+/**
+ Dispatch function for SMM lock box update.
+
+ Caution: This function may receive untrusted input.
+ Restore buffer and length are external input, so this function will validate
+ it is in SMRAM.
+
+ @param LockBoxParameterUpdate parameter of lock box update
+**/
+VOID
+SmmLockBoxUpdate (
+ IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;
+
+ //
+ // Sanity check
+ //
+ if (mLocked) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
+ LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+
+ CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
+ LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+ //
+ // The SpeculationBarrier() call here is to ensure the above range check for
+ // the CommBuffer have been completed before calling into UpdateLockBox().
+ //
+ SpeculationBarrier ();
+
+ //
+ // Update data
+ //
+ Status = UpdateLockBox (
+ &TempLockBoxParameterUpdate.Guid,
+ (UINTN)TempLockBoxParameterUpdate.Offset,
+ (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,
+ (UINTN)TempLockBoxParameterUpdate.Length
+ );
+ LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;
+ return ;
+}
+
+/**
+ Dispatch function for SMM lock box restore.
+
+ Caution: This function may receive untrusted input.
+ Restore buffer and length are external input, so this function will validate
+ it is in SMRAM.
+
+ @param LockBoxParameterRestore parameter of lock box restore
+**/
+VOID
+SmmLockBoxRestore (
+ IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;
+
+ CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
+ return ;
+ }
+
+ //
+ // Restore data
+ //
+ if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
+ Status = RestoreLockBox (
+ &TempLockBoxParameterRestore.Guid,
+ NULL,
+ NULL
+ );
+ } else {
+ Status = RestoreLockBox (
+ &TempLockBoxParameterRestore.Guid,
+ (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
+ (UINTN *)&TempLockBoxParameterRestore.Length
+ );
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)) {
+ //
+ // Return the actual Length value.
+ //
+ LockBoxParameterRestore->Length = TempLockBoxParameterRestore.Length;
+ }
+ }
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
+ return ;
+}
+
+/**
+ Dispatch function for SMM lock box restore all in place.
+
+ @param LockBoxParameterRestoreAllInPlace parameter of lock box restore all in place
+**/
+VOID
+SmmLockBoxRestoreAllInPlace (
+ IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RestoreAllLockBoxInPlace ();
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
+ return ;
+}
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS Command is handled successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;
+ UINTN TempCommBufferSize;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBox SmmLockBoxHandler Enter\n"));
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ //
+ // Sanity check
+ //
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);
+
+ LockBoxParameterHeader->ReturnStatus = (UINT64)-1;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));
+
+ DEBUG ((DEBUG_INFO, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));
+
+ switch (LockBoxParameterHeader->Command) {
+ case EFI_SMM_LOCK_BOX_COMMAND_SAVE:
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));
+ break;
+ }
+ SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);
+ break;
+ case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));
+ break;
+ }
+ SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);
+ break;
+ case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));
+ break;
+ }
+ SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);
+ break;
+ case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));
+ break;
+ }
+ SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);
+ break;
+ case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:
+ if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));
+ break;
+ }
+ SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);
+ break;
+ default:
+ DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));
+ break;
+ }
+
+ LockBoxParameterHeader->Command = (UINT32)-1;
+
+ DEBUG ((DEBUG_INFO, "SmmLockBox SmmLockBoxHandler Exit\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Smm Ready To Lock event notification handler.
+
+ It sets a flag indicating that SMRAM has been locked.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+ **/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockEventNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ mLocked = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry Point for LockBox SMM driver.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+ VOID *Registration;
+
+ //
+ // Register LockBox communication handler
+ //
+ Status = gSmst->SmiHandlerRegister (
+ SmmLockBoxHandler,
+ &gEfiSmmLockBoxCommunicationGuid,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMM Ready To Lock Protocol notification
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ SmmReadyToLockEventNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install NULL to DXE data base as notify
+ //
+ ImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiLockBoxProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
new file mode 100644
index 000000000..5081b2d7f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf
@@ -0,0 +1,59 @@
+## @file
+# LockBox SMM driver.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - communicate buffer in SMM mode.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBox
+ MODULE_UNI_FILE = SmmLockBox.uni
+ FILE_GUID = 33FB3535-F15E-4c17-B303-5EB94595ECB6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SmmLockBoxEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBox.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ SmmServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ LockBoxLib
+ SmmMemLib
+
+[Guids]
+ gEfiSmmLockBoxCommunicationGuid ## PRODUCES ## GUID # SmiHandlerRegister
+
+[Protocols]
+ gEfiSmmReadyToLockProtocolGuid ## NOTIFY
+ gEfiLockBoxProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmmLockBoxExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.uni b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.uni
new file mode 100644
index 000000000..40cf44cc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.uni
@@ -0,0 +1,19 @@
+// /** @file
+// LockBox SMM driver.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - communicate buffer in SMM mode.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "LockBox SMM driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "LockBox SMM driver."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBoxExtra.uni b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBoxExtra.uni
new file mode 100644
index 000000000..3d9811c02
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBoxExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmmLockBox Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM Lock Box Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf
new file mode 100644
index 000000000..ae1b5909b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# This driver first constructs the non-tested memory range, then performs the R/W/V memory test.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GenericMemoryTestDxe
+ MODULE_UNI_FILE = GenericMemoryTestDxe.uni
+ FILE_GUID = 9C1080EE-D02E-487f-9432-F3BF086EC180
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = GenericMemoryTestEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ LightMemoryTest.h
+ LightMemoryTest.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ ReportStatusCodeLib
+ DxeServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiGenericMemTestProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiCpuArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ GenericMemoryTestDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.uni b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.uni
new file mode 100644
index 000000000..3406f90f2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver first constructs the non-tested memory range, then performs the R/W/V memory test.
+//
+// This driver first constructs the non-tested memory range, then performs the R/W/V memory test.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Constructs the non-tested memory range, then performs the R/W/V memory test"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver first constructs the non-tested memory range, then performs the R/W/V memory test."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxeExtra.uni
new file mode 100644
index 000000000..f7818c961
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// GenericMemoryTestDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Generic Memory Test DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.c b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.c
new file mode 100644
index 000000000..7fd383ab7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.c
@@ -0,0 +1,926 @@
+/** @file
+
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LightMemoryTest.h"
+
+//
+// Global:
+// Since this driver will only ever produce one instance of the memory test
+// protocol, so we do not need to dynamically allocate the PrivateData.
+//
+EFI_PHYSICAL_ADDRESS mCurrentAddress;
+LIST_ENTRY *mCurrentLink;
+NONTESTED_MEMORY_RANGE *mCurrentRange;
+UINT64 mTestedSystemMemory;
+UINT64 mNonTestedSystemMemory;
+
+UINT32 GenericMemoryTestMonoPattern[GENERIC_CACHELINE_SIZE / 4] = {
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0x5a5a5a5a,
+ 0xa5a5a5a5
+};
+
+/**
+ Compares the contents of two buffers.
+
+ This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
+ If all Length bytes of the two buffers are identical, then 0 is returned. Otherwise, the
+ value returned is the first mismatched byte in SourceBuffer subtracted from the first
+ mismatched byte in DestinationBuffer.
+
+ If Length = 0, then ASSERT().
+
+ @param[in] DestinationBuffer The pointer to the destination buffer to compare.
+ @param[in] SourceBuffer The pointer to the source buffer to compare.
+ @param[in] Length The number of bytes to compare.
+
+ @return 0 All Length bytes of the two buffers are identical.
+ @retval Non-zero The first mismatched byte in SourceBuffer subtracted from the first
+ mismatched byte in DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+CompareMemWithoutCheckArgument (
+ IN CONST VOID *DestinationBuffer,
+ IN CONST VOID *SourceBuffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (Length > 0);
+ while ((--Length != 0) &&
+ (*(INT8*)DestinationBuffer == *(INT8*)SourceBuffer)) {
+ DestinationBuffer = (INT8*)DestinationBuffer + 1;
+ SourceBuffer = (INT8*)SourceBuffer + 1;
+ }
+ return (INTN)*(UINT8*)DestinationBuffer - (INTN)*(UINT8*)SourceBuffer;
+}
+
+/**
+ Construct the system base memory range through GCD service.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful construct the base memory range through GCD service.
+ @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
+ @retval Others Failed to construct base memory range through GCD service.
+
+**/
+EFI_STATUS
+ConstructBaseMemoryRange (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ )
+{
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ //
+ // Base memory will always below 4G
+ //
+ gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
+ Private->BaseMemorySize += MemorySpaceMap[Index].Length;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Destroy the link list base on the correspond link list type.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+**/
+VOID
+DestroyLinkList (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ )
+{
+ LIST_ENTRY *Link;
+ NONTESTED_MEMORY_RANGE *NontestedRange;
+
+ Link = Private->NonTestedMemRanList.BackLink;
+
+ while (Link != &Private->NonTestedMemRanList) {
+ RemoveEntryList (Link);
+ NontestedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
+ gBS->FreePool (NontestedRange);
+ Link = Private->NonTestedMemRanList.BackLink;;
+ }
+}
+
+/**
+ Convert the memory range to tested.
+
+ @param BaseAddress Base address of the memory range.
+ @param Length Length of the memory range.
+ @param Capabilities Capabilities of the memory range.
+
+ @retval EFI_SUCCESS The memory range is converted to tested.
+ @retval others Error happens.
+**/
+EFI_STATUS
+ConvertToTestedMemory (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ Status = gDS->RemoveMemorySpace (
+ BaseAddress,
+ Length
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gDS->AddMemorySpace (
+ ((Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) ?
+ EfiGcdMemoryTypeMoreReliable : EfiGcdMemoryTypeSystemMemory,
+ BaseAddress,
+ Length,
+ Capabilities &~
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ }
+ return Status;
+}
+
+/**
+ Add the extened memory to whole system memory map.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful add all the extended memory to system memory map.
+ @retval Others Failed to add the tested extended memory.
+
+**/
+EFI_STATUS
+UpdateMemoryMap (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ )
+{
+ LIST_ENTRY *Link;
+ NONTESTED_MEMORY_RANGE *Range;
+
+ Link = Private->NonTestedMemRanList.ForwardLink;
+
+ while (Link != &Private->NonTestedMemRanList) {
+ Range = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
+
+ ConvertToTestedMemory (
+ Range->StartAddress,
+ Range->Length,
+ Range->Capabilities &~
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ Link = Link->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test a range of the memory directly .
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] StartAddress Starting address of the memory range to be tested.
+ @param[in] Length Length in bytes of the memory range to be tested.
+ @param[in] Capabilities The bit mask of attributes that the memory range supports.
+
+ @retval EFI_SUCCESS Successful test the range of memory.
+ @retval Others Failed to test the range of memory.
+
+**/
+EFI_STATUS
+DirectRangeTest (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Perform a dummy memory test, so directly write the pattern to all range
+ //
+ WriteMemory (Private, StartAddress, Length);
+
+ //
+ // Verify the memory range
+ //
+ Status = VerifyMemory (Private, StartAddress, Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Add the tested compatible memory to system memory using GCD service
+ //
+ ConvertToTestedMemory (
+ StartAddress,
+ Length,
+ Capabilities &~
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct the system non-tested memory range through GCD service.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful construct the non-tested memory range through GCD service.
+ @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
+ @retval Others Failed to construct non-tested memory range through GCD service.
+
+**/
+EFI_STATUS
+ConstructNonTestedMemoryRange (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ )
+{
+ NONTESTED_MEMORY_RANGE *Range;
+ BOOLEAN NoFound;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ //
+ // Non tested memory range may be span 4G here
+ //
+ NoFound = TRUE;
+
+ gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ (MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
+ ) {
+ NoFound = FALSE;
+ //
+ // Light version do not need to process >4G memory range
+ //
+ gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (NONTESTED_MEMORY_RANGE),
+ (VOID **) &Range
+ );
+
+ Range->Signature = EFI_NONTESTED_MEMORY_RANGE_SIGNATURE;
+ Range->StartAddress = MemorySpaceMap[Index].BaseAddress;
+ Range->Length = MemorySpaceMap[Index].Length;
+ Range->Capabilities = MemorySpaceMap[Index].Capabilities;
+
+ mNonTestedSystemMemory += MemorySpaceMap[Index].Length;
+ InsertTailList (&Private->NonTestedMemRanList, &Range->Link);
+ }
+ }
+
+ if (NoFound) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write the memory test pattern into a range of physical memory.
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] Start The memory range's start address.
+ @param[in] Size The memory range's size.
+
+ @retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.
+ @retval Others The test pattern may not really write into the physical memory.
+
+**/
+EFI_STATUS
+WriteMemory (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Size
+ )
+{
+ EFI_PHYSICAL_ADDRESS Address;
+
+ Address = Start;
+
+ //
+ // Add 4G memory address check for IA32 platform
+ // NOTE: Without page table, there is no way to use memory above 4G.
+ //
+ if (Start + Size > MAX_ADDRESS) {
+ return EFI_SUCCESS;
+ }
+
+ while (Address < (Start + Size)) {
+ CopyMem ((VOID *) (UINTN) Address, Private->MonoPattern, Private->MonoTestSize);
+ Address += Private->CoverageSpan;
+ }
+ //
+ // bug bug: we may need GCD service to make the code cache and data uncache,
+ // if GCD do not support it or return fail, then just flush the whole cache.
+ //
+ if (Private->Cpu != NULL) {
+ Private->Cpu->FlushDataCache (Private->Cpu, Start, Size, EfiCpuFlushTypeWriteBackInvalidate);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verify the range of physical memory which covered by memory test pattern.
+
+ This function will also do not return any informatin just cause system reset,
+ because the handle error encount fatal error and disable the bad DIMMs.
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] Start The memory range's start address.
+ @param[in] Size The memory range's size.
+
+ @retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.
+ @retval Others The range of memory have errors contained.
+
+**/
+EFI_STATUS
+VerifyMemory (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Size
+ )
+{
+ EFI_PHYSICAL_ADDRESS Address;
+ INTN ErrorFound;
+ EFI_MEMORY_EXTENDED_ERROR_DATA *ExtendedErrorData;
+
+ Address = Start;
+ ExtendedErrorData = NULL;
+
+ //
+ // Add 4G memory address check for IA32 platform
+ // NOTE: Without page table, there is no way to use memory above 4G.
+ //
+ if (Start + Size > MAX_ADDRESS) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Use the software memory test to check whether have detected miscompare
+ // error here. If there is miscompare error here then check if generic
+ // memory test driver can disable the bad DIMM.
+ //
+ while (Address < (Start + Size)) {
+ ErrorFound = CompareMemWithoutCheckArgument (
+ (VOID *) (UINTN) (Address),
+ Private->MonoPattern,
+ Private->MonoTestSize
+ );
+ if (ErrorFound != 0) {
+ //
+ // Report uncorrectable errors
+ //
+ ExtendedErrorData = AllocateZeroPool (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA));
+ if (ExtendedErrorData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ExtendedErrorData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ ExtendedErrorData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA));
+ ExtendedErrorData->Granularity = EFI_MEMORY_ERROR_DEVICE;
+ ExtendedErrorData->Operation = EFI_MEMORY_OPERATION_READ;
+ ExtendedErrorData->Syndrome = 0x0;
+ ExtendedErrorData->Address = Address;
+ ExtendedErrorData->Resolution = 0x40;
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE,
+ 0,
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (UINT8 *) ExtendedErrorData + sizeof (EFI_STATUS_CODE_DATA),
+ ExtendedErrorData->DataHeader.Size
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Address += Private->CoverageSpan;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the generic memory test.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] Level The coverage level of the memory test.
+ @param[out] RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test is initialized correctly.
+ @retval EFI_NO_MEDIA The system had no memory to be tested.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ )
+{
+ EFI_STATUS Status;
+ GENERIC_MEMORY_TEST_PRIVATE *Private;
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+
+ Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
+ *RequireSoftECCInit = FALSE;
+
+ //
+ // This is initialize for default value, but some value may be reset base on
+ // platform memory test driver.
+ //
+ Private->CoverLevel = Level;
+ Private->BdsBlockSize = TEST_BLOCK_SIZE;
+ Private->MonoPattern = GenericMemoryTestMonoPattern;
+ Private->MonoTestSize = GENERIC_CACHELINE_SIZE;
+
+ //
+ // Initialize several internal link list
+ //
+ InitializeListHead (&Private->NonTestedMemRanList);
+
+ //
+ // Construct base memory range
+ //
+ ConstructBaseMemoryRange (Private);
+
+ //
+ // get the cpu arch protocol to support flash cache
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiCpuArchProtocolGuid,
+ NULL,
+ (VOID **) &Cpu
+ );
+ if (!EFI_ERROR (Status)) {
+ Private->Cpu = Cpu;
+ }
+ //
+ // Create the CoverageSpan of the memory test base on the coverage level
+ //
+ switch (Private->CoverLevel) {
+ case EXTENSIVE:
+ Private->CoverageSpan = GENERIC_CACHELINE_SIZE;
+ break;
+
+ case SPARSE:
+ Private->CoverageSpan = SPARSE_SPAN_SIZE;
+ break;
+
+ //
+ // Even the BDS do not need to test any memory, but in some case it
+ // still need to init ECC memory.
+ //
+ default:
+ Private->CoverageSpan = QUICK_SPAN_SIZE;
+ break;
+ }
+ //
+ // This is the first time we construct the non-tested memory range, if no
+ // extended memory found, we know the system have not any extended memory
+ // need to be test
+ //
+ Status = ConstructNonTestedMemoryRange (Private);
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_NO_MEDIA;
+ }
+ //
+ // ready to perform the R/W/V memory test
+ //
+ mTestedSystemMemory = Private->BaseMemorySize;
+ mCurrentLink = Private->NonTestedMemRanList.ForwardLink;
+ mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
+ mCurrentAddress = mCurrentRange->StartAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform the memory test.
+
+ @param[in] This The protocol instance pointer.
+ @param[out] TestedMemorySize Return the tested extended memory size.
+ @param[out] TotalMemorySize Return the whole system physical memory size.
+ The total memory size does not include memory in a slot with a disabled DIMM.
+ @param[out] ErrorOut TRUE if the memory error occurred.
+ @param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.
+
+ @retval EFI_SUCCESS One block of memory passed the test.
+ @retval EFI_NOT_FOUND All memory blocks have already been tested.
+ @retval EFI_DEVICE_ERROR Memory device error occurred, and no agent can handle it.
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ )
+{
+ EFI_STATUS Status;
+ GENERIC_MEMORY_TEST_PRIVATE *Private;
+ EFI_MEMORY_RANGE_EXTENDED_DATA *RangeData;
+ UINT64 BlockBoundary;
+
+ Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
+ *ErrorOut = FALSE;
+ RangeData = NULL;
+ BlockBoundary = 0;
+
+ //
+ // In extensive mode the boundary of "mCurrentRange->Length" may will lost
+ // some range that is not Private->BdsBlockSize size boundary, so need
+ // the software mechanism to confirm all memory location be covered.
+ //
+ if (mCurrentAddress < (mCurrentRange->StartAddress + mCurrentRange->Length)) {
+ if ((mCurrentAddress + Private->BdsBlockSize) <= (mCurrentRange->StartAddress + mCurrentRange->Length)) {
+ BlockBoundary = Private->BdsBlockSize;
+ } else {
+ BlockBoundary = mCurrentRange->StartAddress + mCurrentRange->Length - mCurrentAddress;
+ }
+ //
+ // If TestAbort is true, means user cancel the memory test
+ //
+ if (!TestAbort && Private->CoverLevel != IGNORE) {
+ //
+ // Report status code of every memory range
+ //
+ RangeData = AllocateZeroPool (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA));
+ if (RangeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ RangeData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ RangeData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA));
+ RangeData->Start = mCurrentAddress;
+ RangeData->Length = BlockBoundary;
+
+ REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST,
+ 0,
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (UINT8 *) RangeData + sizeof (EFI_STATUS_CODE_DATA),
+ RangeData->DataHeader.Size
+ );
+
+ //
+ // The software memory test (R/W/V) perform here. It will detect the
+ // memory mis-compare error.
+ //
+ WriteMemory (Private, mCurrentAddress, BlockBoundary);
+
+ Status = VerifyMemory (Private, mCurrentAddress, BlockBoundary);
+ if (EFI_ERROR (Status)) {
+ //
+ // If perform here, means there is mis-compare error, and no agent can
+ // handle it, so we return to BDS EFI_DEVICE_ERROR.
+ //
+ *ErrorOut = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ mTestedSystemMemory += BlockBoundary;
+ *TestedMemorySize = mTestedSystemMemory;
+
+ //
+ // If the memory test restart after the platform driver disable dimms,
+ // the NonTestSystemMemory may be changed, but the base memory size will
+ // not changed, so we can get the current total memory size.
+ //
+ *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;
+
+ //
+ // Update the current test address pointing to next BDS BLOCK
+ //
+ mCurrentAddress += Private->BdsBlockSize;
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Change to next non tested memory range
+ //
+ mCurrentLink = mCurrentLink->ForwardLink;
+ if (mCurrentLink != &Private->NonTestedMemRanList) {
+ mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
+ mCurrentAddress = mCurrentRange->StartAddress;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Here means all the memory test have finished
+ //
+ *TestedMemorySize = mTestedSystemMemory;
+ *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;
+ return EFI_NOT_FOUND;
+ }
+
+}
+
+/**
+ Finish the memory test.
+
+ @param[in] This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Success. All resources used in the memory test are freed.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ GENERIC_MEMORY_TEST_PRIVATE *Private;
+
+ Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
+
+ //
+ // Perform Data and Address line test only if not ignore memory test
+ //
+ if (Private->CoverLevel != IGNORE) {
+ Status = PerformAddressDataLineTest (Private);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Add the non tested memory range to system memory map through GCD service
+ //
+ UpdateMemoryMap (Private);
+
+ //
+ // we need to free all the memory allocate
+ //
+ DestroyLinkList (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Provides the capability to test the compatible range used by some special drivers.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] StartAddress The start address of the compatible memory range that
+ must be below 16M.
+ @param[in] Length The compatible memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_STATUS Status;
+ GENERIC_MEMORY_TEST_PRIVATE *Private;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ EFI_PHYSICAL_ADDRESS CurrentBase;
+ UINT64 CurrentLength;
+
+ Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
+
+ //
+ // Check if the parameter is below 16MB
+ //
+ if (StartAddress + Length > 0x1000000) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBase = StartAddress;
+ do {
+ //
+ // Check the required memory range status; if the required memory range span
+ // the different GCD memory descriptor, it may be cause different action.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (
+ CurrentBase,
+ &Descriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ (Descriptor.Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
+ ) {
+ CurrentLength = Descriptor.BaseAddress + Descriptor.Length - CurrentBase;
+ if (CurrentBase + CurrentLength > StartAddress + Length) {
+ CurrentLength = StartAddress + Length - CurrentBase;
+ }
+ Status = DirectRangeTest (
+ Private,
+ CurrentBase,
+ CurrentLength,
+ Descriptor.Capabilities
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ CurrentBase = Descriptor.BaseAddress + Descriptor.Length;
+ } while (CurrentBase < StartAddress + Length);
+ //
+ // Here means the required range already be tested, so just return success.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform the address line walking ones test.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful finished walking ones test.
+ @retval EFI_OUT_OF_RESOURCE Could not get resource in base memory.
+ @retval EFI_ACCESS_DENIED Code may can not run here because if walking one test
+ failed, system may be already halt.
+
+**/
+EFI_STATUS
+PerformAddressDataLineTest (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ )
+{
+ LIST_ENTRY *ExtendedLink;
+ NONTESTED_MEMORY_RANGE *ExtendedRange;
+ BOOLEAN InExtendedRange;
+ EFI_PHYSICAL_ADDRESS TestAddress;
+
+ //
+ // Light version no data line test, only perform the address line test
+ //
+ TestAddress = (EFI_PHYSICAL_ADDRESS) 0x1;
+ while (TestAddress < MAX_ADDRESS && TestAddress > 0) {
+ //
+ // only test if the address falls in the enabled range
+ //
+ InExtendedRange = FALSE;
+ ExtendedLink = Private->NonTestedMemRanList.BackLink;
+ while (ExtendedLink != &Private->NonTestedMemRanList) {
+ ExtendedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (ExtendedLink);
+ if ((TestAddress >= ExtendedRange->StartAddress) &&
+ (TestAddress < (ExtendedRange->StartAddress + ExtendedRange->Length))
+ ) {
+ InExtendedRange = TRUE;
+ }
+
+ ExtendedLink = ExtendedLink->BackLink;
+ }
+
+ if (InExtendedRange) {
+ *(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress = TestAddress;
+ Private->Cpu->FlushDataCache (Private->Cpu, TestAddress, 1, EfiCpuFlushTypeWriteBackInvalidate);
+ if (*(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress != TestAddress) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ TestAddress = LShiftU64 (TestAddress, 1);
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// Driver entry here
+//
+GENERIC_MEMORY_TEST_PRIVATE mGenericMemoryTestPrivate = {
+ EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ InitializeMemoryTest,
+ GenPerformMemoryTest,
+ GenMemoryTestFinished,
+ GenCompatibleRangeTest
+ },
+ (EXTENDMEM_COVERAGE_LEVEL) 0,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0,
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ The generic memory test driver's entry point.
+
+ It initializes private data to default value.
+
+ @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_NOT_FOUND Can't find HandOff Hob in HobList.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericMemoryTestEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobList;
+ EFI_BOOT_MODE BootMode;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ //
+ // Use the generic pattern to test compatible memory range
+ //
+ mGenericMemoryTestPrivate.MonoPattern = GenericMemoryTestMonoPattern;
+ mGenericMemoryTestPrivate.MonoTestSize = GENERIC_CACHELINE_SIZE;
+
+ //
+ // Get the platform boot mode
+ //
+ HobList = GetHobList ();
+
+ Hob.Raw = HobList;
+ if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) {
+ return EFI_NOT_FOUND;
+ }
+
+ BootMode = Hob.HandoffInformationTable->BootMode;
+
+ //
+ // Get the platform boot mode and create the default memory test coverage
+ // level and span size for compatible memory test using
+ //
+ switch (BootMode) {
+ case BOOT_WITH_FULL_CONFIGURATION:
+ case BOOT_WITH_DEFAULT_SETTINGS:
+ mGenericMemoryTestPrivate.CoverageSpan = SPARSE_SPAN_SIZE;
+ break;
+
+ case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
+ mGenericMemoryTestPrivate.CoverageSpan = GENERIC_CACHELINE_SIZE;
+ break;
+
+ default:
+ mGenericMemoryTestPrivate.CoverageSpan = QUICK_SPAN_SIZE;
+ break;
+ }
+ //
+ // Install the protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mGenericMemoryTestPrivate.Handle,
+ &gEfiGenericMemTestProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mGenericMemoryTestPrivate.GenericMemoryTest
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.h b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.h
new file mode 100644
index 000000000..72e58ae4a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/LightMemoryTest.h
@@ -0,0 +1,335 @@
+/** @file
+ The generic memory test driver definition
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GENERIC_MEMORY_TEST_H_
+#define _GENERIC_MEMORY_TEST_H_
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/Cpu.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+//
+// Some global define
+//
+#define GENERIC_CACHELINE_SIZE 0x40
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+//
+// The SPARSE_SPAN_SIZE size can not small then the MonoTestSize
+//
+#define TEST_BLOCK_SIZE 0x2000000
+#define QUICK_SPAN_SIZE (TEST_BLOCK_SIZE >> 2)
+#define SPARSE_SPAN_SIZE (TEST_BLOCK_SIZE >> 4)
+
+//
+// This structure records every nontested memory range parsed through GCD
+// service.
+//
+#define EFI_NONTESTED_MEMORY_RANGE_SIGNATURE SIGNATURE_32 ('N', 'T', 'M', 'E')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ UINT64 Length;
+ UINT64 Capabilities;
+ BOOLEAN Above4G;
+ BOOLEAN AlreadyMapped;
+} NONTESTED_MEMORY_RANGE;
+
+#define NONTESTED_MEMORY_RANGE_FROM_LINK(link) \
+ CR ( \
+ link, \
+ NONTESTED_MEMORY_RANGE, \
+ Link, \
+ EFI_NONTESTED_MEMORY_RANGE_SIGNATURE \
+ )
+
+//
+// This is the memory test driver's structure definition
+//
+#define EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE SIGNATURE_32 ('G', 'E', 'M', 'T')
+
+typedef struct {
+
+ UINTN Signature;
+ EFI_HANDLE Handle;
+
+ //
+ // Cpu arch protocol's pointer
+ //
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+
+ //
+ // generic memory test driver's protocol
+ //
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL GenericMemoryTest;
+
+ //
+ // memory test covered spans
+ //
+ EXTENDMEM_COVERAGE_LEVEL CoverLevel;
+ UINTN CoverageSpan;
+ UINT64 BdsBlockSize;
+
+ //
+ // the memory test pattern and size every time R/W/V memory
+ //
+ VOID *MonoPattern;
+ UINTN MonoTestSize;
+
+ //
+ // base memory's size which tested in PEI phase
+ //
+ UINT64 BaseMemorySize;
+
+ //
+ // memory range list
+ //
+ LIST_ENTRY NonTestedMemRanList;
+
+} GENERIC_MEMORY_TEST_PRIVATE;
+
+#define GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS(a) \
+ CR ( \
+ a, \
+ GENERIC_MEMORY_TEST_PRIVATE, \
+ GenericMemoryTest, \
+ EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE \
+ )
+
+//
+// Function Prototypes
+//
+
+/**
+ Construct the system base memory range through GCD service.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful construct the base memory range through GCD service.
+ @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
+ @retval Others Failed to construct base memory range through GCD service.
+
+**/
+EFI_STATUS
+ConstructBaseMemoryRange (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ );
+
+/**
+ Construct the system non-tested memory range through GCD service.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful construct the non-tested memory range through GCD service.
+ @retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
+ @retval Others Failed to construct non-tested memory range through GCD service.
+
+**/
+EFI_STATUS
+ConstructNonTestedMemoryRange (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ );
+
+/**
+ Perform the address line walking ones test.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful finished walking ones test.
+ @retval EFI_OUT_OF_RESOURCE Could not get resource in base memory.
+ @retval EFI_ACCESS_DENIED Code may can not run here because if walking one test
+ failed, system may be already halt.
+
+**/
+EFI_STATUS
+PerformAddressDataLineTest (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ );
+
+/**
+ Destroy the link list base on the correspond link list type.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+**/
+VOID
+DestroyLinkList (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ );
+
+/**
+ Add the extened memory to whole system memory map.
+
+ @param[in] Private Point to generic memory test driver's private data.
+
+ @retval EFI_SUCCESS Successful add all the extended memory to system memory map.
+ @retval Others Failed to add the tested extended memory.
+
+**/
+EFI_STATUS
+UpdateMemoryMap (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private
+ );
+
+/**
+ Write the memory test pattern into a range of physical memory.
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] Start The memory range's start address.
+ @param[in] Size The memory range's size.
+
+ @retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.
+ @retval Others The test pattern may not really write into the physical memory.
+
+**/
+EFI_STATUS
+WriteMemory (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Size
+ );
+
+/**
+ Verify the range of physical memory which covered by memory test pattern.
+
+ This function will also do not return any informatin just cause system reset,
+ because the handle error encount fatal error and disable the bad DIMMs.
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] Start The memory range's start address.
+ @param[in] Size The memory range's size.
+
+ @retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.
+ @retval Others The range of memory have errors contained.
+
+**/
+EFI_STATUS
+VerifyMemory (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Size
+ );
+
+/**
+ Test a range of the memory directly .
+
+ @param[in] Private Point to generic memory test driver's private data.
+ @param[in] StartAddress Starting address of the memory range to be tested.
+ @param[in] Length Length in bytes of the memory range to be tested.
+ @param[in] Capabilities The bit mask of attributes that the memory range supports.
+
+ @retval EFI_SUCCESS Successful test the range of memory.
+ @retval Others Failed to test the range of memory.
+
+**/
+EFI_STATUS
+DirectRangeTest (
+ IN GENERIC_MEMORY_TEST_PRIVATE *Private,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+/**
+ Initialize the generic memory test.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] Level The coverage level of the memory test.
+ @param[out] RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test is initialized correctly.
+ @retval EFI_NO_MEDIA The system had no memory to be tested.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ );
+
+/**
+ Perform the memory test.
+
+ @param[in] This The protocol instance pointer.
+ @param[out] TestedMemorySize Return the tested extended memory size.
+ @param[out] TotalMemorySize Return the whole system physical memory size.
+ The total memory size does not include memory in a slot with a disabled DIMM.
+ @param[out] ErrorOut TRUE if the memory error occurred.
+ @param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.
+
+ @retval EFI_SUCCESS One block of memory passed the test.
+ @retval EFI_NOT_FOUND All memory blocks have already been tested.
+ @retval EFI_DEVICE_ERROR Memory device error occurred, and no agent can handle it.
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ );
+
+/**
+ Finish the memory test.
+
+ @param[in] This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Success. All resources used in the memory test are freed.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ );
+
+/**
+ Provides the capability to test the compatible range used by some special drivers.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] StartAddress The start address of the compatible memory range that
+ must be below 16M.
+ @param[in] Length The compatible memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c
new file mode 100644
index 000000000..9c016106b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.c
@@ -0,0 +1,284 @@
+/** @file
+ Implementation of Generic Memory Test Protocol which does not perform real memory test.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "NullMemoryTest.h"
+
+UINT64 mTestedSystemMemory = 0;
+UINT64 mTotalSystemMemory = 0;
+EFI_HANDLE mGenericMemoryTestHandle;
+
+EFI_GENERIC_MEMORY_TEST_PROTOCOL mGenericMemoryTest = {
+ InitializeMemoryTest,
+ GenPerformMemoryTest,
+ GenMemoryTestFinished,
+ GenCompatibleRangeTest
+};
+
+/**
+ Entry point of the NULL memory test driver.
+
+ This function is the entry point of the NULL memory test driver.
+ It simply installs the Generic Memory Test Protocol.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Generic Memory Test Protocol is successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericMemoryTestEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallProtocolInterface (
+ &mGenericMemoryTestHandle,
+ &gEfiGenericMemTestProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mGenericMemoryTest
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert the memory range to tested.
+
+ @param BaseAddress Base address of the memory range.
+ @param Length Length of the memory range.
+ @param Capabilities Capabilities of the memory range.
+
+ @retval EFI_SUCCESS The memory range is converted to tested.
+ @retval others Error happens.
+**/
+EFI_STATUS
+ConvertToTestedMemory (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ Status = gDS->RemoveMemorySpace (
+ BaseAddress,
+ Length
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gDS->AddMemorySpace (
+ ((Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) ?
+ EfiGcdMemoryTypeMoreReliable : EfiGcdMemoryTypeSystemMemory,
+ BaseAddress,
+ Length,
+ Capabilities &~
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ }
+ return Status;
+}
+
+/**
+ Initialize the generic memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.MemoryTestInit.
+ It simply promotes untested reserved memory to system memory without real test.
+
+ @param This Protocol instance pointer.
+ @param Level The coverage level of the memory test.
+ @param RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test initialized correctly.
+ @retval EFI_NO_MEDIA There is not any non-tested memory found, in this
+ function if not any non-tesed memory found means
+ that the memory test driver have not detect any
+ non-tested extended memory of current system.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ (MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
+ ) {
+ //
+ // For those reserved memory that have not been tested, simply promote to system memory.
+ //
+ Status = ConvertToTestedMemory (
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].Length,
+ MemorySpaceMap[Index].Capabilities
+ );
+ ASSERT_EFI_ERROR (Status);
+ mTestedSystemMemory += MemorySpaceMap[Index].Length;
+ mTotalSystemMemory += MemorySpaceMap[Index].Length;
+ } else if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
+ mTotalSystemMemory += MemorySpaceMap[Index].Length;
+ }
+ }
+
+ FreePool (MemorySpaceMap);
+
+ *RequireSoftECCInit = FALSE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform the memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.PerformMemoryTest.
+ It simply returns EFI_NOT_FOUND.
+
+ @param This Protocol instance pointer.
+ @param TestedMemorySize Return the tested extended memory size.
+ @param TotalMemorySize Return the whole system physical memory size, this
+ value may be changed if in some case some error
+ DIMMs be disabled.
+ @param ErrorOut Any time the memory error occurs, this will be
+ TRUE.
+ @param IfTestAbort Indicate if the user press "ESC" to skip the memory
+ test.
+
+ @retval EFI_SUCCESS One block of memory test ok, the block size is hide
+ internally.
+ @retval EFI_NOT_FOUND Indicate all the non-tested memory blocks have
+ already go through.
+ @retval EFI_DEVICE_ERROR Mis-compare error, and no agent can handle it
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ )
+{
+ *ErrorOut = FALSE;
+ *TestedMemorySize = mTestedSystemMemory;
+ *TotalMemorySize = mTotalSystemMemory;
+
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ The memory test finished.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.Finished.
+ It simply returns EFI_SUCCESS.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Successful free all the generic memory test driver
+ allocated resource and notify to platform memory
+ test driver that memory test finished.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Provide capability to test compatible range which used by some special
+ driver required using memory range before BDS perform memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.CompatibleRangeTest.
+ It simply sets the memory range to system memory.
+
+ @param This Protocol instance pointer.
+ @param StartAddress The start address of the memory range.
+ @param Length The memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range must be below 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ EFI_PHYSICAL_ADDRESS CurrentBase;
+ UINT64 CurrentLength;
+
+ //
+ // Check if the parameter is below 16MB
+ //
+ if (StartAddress + Length > SIZE_16MB) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBase = StartAddress;
+ do {
+ //
+ // Check the required memory range status; if the required memory range span
+ // the different GCD memory descriptor, it may be cause different action.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (
+ CurrentBase,
+ &Descriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ (Descriptor.Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
+ ) {
+ CurrentLength = Descriptor.BaseAddress + Descriptor.Length - CurrentBase;
+ if (CurrentBase + CurrentLength > StartAddress + Length) {
+ CurrentLength = StartAddress + Length - CurrentBase;
+ }
+ Status = ConvertToTestedMemory (
+ CurrentBase,
+ CurrentLength,
+ Descriptor.Capabilities
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ CurrentBase = Descriptor.BaseAddress + Descriptor.Length;
+ } while (CurrentBase < StartAddress + Length);
+ //
+ // Here means the required range already be tested, so just return success.
+ //
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h
new file mode 100644
index 000000000..cee9b785b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTest.h
@@ -0,0 +1,131 @@
+/** @file
+ Include file of the NULL memory test driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _NULL_MEMORY_TEST_H_
+#define _NULL_MEMORY_TEST_H_
+
+
+#include <PiDxe.h>
+
+
+#include <Protocol/GenericMemoryTest.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Definition of memory status.
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+/**
+ Initialize the generic memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.MemoryTestInit.
+ It simply promotes untested reserved memory to system memory without real test.
+
+ @param This Protocol instance pointer.
+ @param Level The coverage level of the memory test.
+ @param RequireSoftECCInit Indicate if the memory need software ECC init.
+
+ @retval EFI_SUCCESS The generic memory test initialized correctly.
+ @retval EFI_NO_MEDIA There is not any non-tested memory found, in this
+ function if not any non-tesed memory found means
+ that the memory test driver have not detect any
+ non-tested extended memory of current system.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EXTENDMEM_COVERAGE_LEVEL Level,
+ OUT BOOLEAN *RequireSoftECCInit
+ );
+
+/**
+ Perform the memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.PerformMemoryTest.
+ It simply returns EFI_NOT_FOUND.
+
+ @param This Protocol instance pointer.
+ @param TestedMemorySize Return the tested extended memory size.
+ @param TotalMemorySize Return the whole system physical memory size, this
+ value may be changed if in some case some error
+ DIMMs be disabled.
+ @param ErrorOut Any time the memory error occurs, this will be
+ TRUE.
+ @param IfTestAbort Indicate if the user press "ESC" to skip the memory
+ test.
+
+ @retval EFI_SUCCESS One block of memory test ok, the block size is hide
+ internally.
+ @retval EFI_NOT_FOUND Indicate all the non-tested memory blocks have
+ already go through.
+ @retval EFI_DEVICE_ERROR Mis-compare error, and no agent can handle it
+
+**/
+EFI_STATUS
+EFIAPI
+GenPerformMemoryTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN OUT UINT64 *TestedMemorySize,
+ OUT UINT64 *TotalMemorySize,
+ OUT BOOLEAN *ErrorOut,
+ IN BOOLEAN TestAbort
+ );
+
+/**
+ The memory test finished.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.Finished.
+ It simply returns EFI_SUCCESS.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Successful free all the generic memory test driver
+ allocated resource and notify to platform memory
+ test driver that memory test finished.
+
+**/
+EFI_STATUS
+EFIAPI
+GenMemoryTestFinished (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
+ );
+
+/**
+ Provide capability to test compatible range which used by some special
+ driver required using memory range before BDS perform memory test.
+
+ This function implements EFI_GENERIC_MEMORY_TEST_PROTOCOL.CompatibleRangeTest.
+ It simply set the memory range to system memory.
+
+ @param This Protocol instance pointer.
+ @param StartAddress The start address of the memory range.
+ @param Length The memory range's length.
+
+ @retval EFI_SUCCESS The compatible memory range pass the memory test.
+ @retval EFI_INVALID_PARAMETER The compatible memory range must be below 16M.
+
+**/
+EFI_STATUS
+EFIAPI
+GenCompatibleRangeTest (
+ IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT64 Length
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
new file mode 100644
index 000000000..eac7ae119
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
@@ -0,0 +1,46 @@
+## @file
+# This driver installs Generic Memory Test Protocol which does not perform real memory test.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NullMemoryTestDxe
+ MODULE_UNI_FILE = NullMemoryTestDxe.uni
+ FILE_GUID = 96B5C032-DF4C-4b6e-8232-438DCF448D0E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GenericMemoryTestEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ NullMemoryTest.h
+ NullMemoryTest.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiGenericMemTestProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ NullMemoryTestDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni
new file mode 100644
index 000000000..63c6698c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver installs Generic Memory Test Protocol which does not perform real memory test.
+//
+// This driver installs Generic Memory Test Protocol, which does not perform a real memory test.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs Generic Memory Test Protocol, which does not perform real memory test"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver installs Generic Memory Test Protocol, which does not perform a real memory test."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni
new file mode 100644
index 000000000..e763f0685
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// NullMemoryTestDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"NULL Memory Test DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.c b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.c
new file mode 100644
index 000000000..fdee1e39a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.c
@@ -0,0 +1,119 @@
+/** @file
+ Produces the Metronome Architectural Protocol on top of Timer Library.
+
+ This is a generic implementation of the Metronome Architectural Protocol that
+ layers on top of an instance of the Timer Library. The Timer Library provides
+ functions for nanosecond and microsecond delays. This generic implementation
+ produces a fixed TickPeriod of 1 100ns unit, and when the WaitForTick() service
+ is called, the number of ticks passed in is converted to either nanosecond or
+ microsecond units. If the number of ticks is small, then nanoseconds are used.
+ If the number of ticks is large, then microseconds are used. This prevents
+ overflows that could occur for long delays if only nanoseconds were used and also
+ provides the greatest accuracy for small delays.
+
+Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Metronome.h"
+
+//
+// Handle for the Metronome Architectural Protocol instance produced by this driver
+//
+EFI_HANDLE mMetronomeHandle = NULL;
+
+//
+// The Metronome Architectural Protocol instance produced by this driver
+//
+EFI_METRONOME_ARCH_PROTOCOL mMetronome = {
+ WaitForTick,
+ 1 // TickPeriod = 1*100 ns units
+};
+
+/**
+ Waits for the specified number of ticks.
+
+ This function implements EFI_METRONOME_ARCH_PROTOCOL.WaitForTick().
+ The WaitForTick() function waits for the number of ticks specified by
+ TickNumber from a known time source in the platform. If TickNumber of
+ ticks are detected, then EFI_SUCCESS is returned. The actual time passed
+ between entry of this function and the first tick is between 0 and
+ TickPeriod 100 nS units. If you want to guarantee that at least TickPeriod
+ time has elapsed, wait for two ticks. This function waits for a hardware
+ event to determine when a tick occurs. It is possible for interrupt
+ processing, or exception processing to interrupt the execution of the
+ WaitForTick() function. Depending on the hardware source for the ticks, it
+ is possible for a tick to be missed. This function cannot guarantee that
+ ticks will not be missed. If a timeout occurs waiting for the specified
+ number of ticks, then EFI_TIMEOUT is returned.
+
+ @param This The EFI_METRONOME_ARCH_PROTOCOL instance.
+ @param TickNumber Number of ticks to wait.
+
+ @retval EFI_SUCCESS The wait for the number of ticks specified by TickNumber
+ succeeded.
+ @retval EFI_TIMEOUT A timeout occurred waiting for the specified number of ticks.
+
+**/
+EFI_STATUS
+EFIAPI
+WaitForTick (
+ IN EFI_METRONOME_ARCH_PROTOCOL *This,
+ IN UINT32 TickNumber
+ )
+{
+ //
+ // Check the value of TickNumber, so a 32-bit overflow can be avoided
+ // when TickNumber of converted to nanosecond units
+ //
+ if (TickNumber < 10000000) {
+ //
+ // If TickNumber is small, then use NanoSecondDelay()
+ //
+ NanoSecondDelay (TickNumber * 100);
+ } else {
+ //
+ // If TickNumber is large, then use MicroSecondDelay()
+ //
+ MicroSecondDelay (TickNumber / 10);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module Metronome. 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
+InstallMetronome (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure the Metronome Architectural Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMetronomeArchProtocolGuid);
+
+ //
+ // Install on a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mMetronomeHandle,
+ &gEfiMetronomeArchProtocolGuid, &mMetronome,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.h b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.h
new file mode 100644
index 000000000..7017e34ea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.h
@@ -0,0 +1,51 @@
+/** @file
+ Include file of Metronome driver.
+
+Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _METRONOME_H_
+#define _METRONOME_H_
+
+#include <PiDxe.h>
+#include <Protocol/Metronome.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+/**
+ Waits for the specified number of ticks.
+
+ This function implements EFI_METRONOME_ARCH_PROTOCOL.WaitForTick().
+ The WaitForTick() function waits for the number of ticks specified by
+ TickNumber from a known time source in the platform. If TickNumber of
+ ticks are detected, then EFI_SUCCESS is returned. The actual time passed
+ between entry of this function and the first tick is between 0 and
+ TickPeriod 100 nS units. If you want to guarantee that at least TickPeriod
+ time has elapsed, wait for two ticks. This function waits for a hardware
+ event to determine when a tick occurs. It is possible for interrupt
+ processing, or exception processing to interrupt the execution of the
+ WaitForTick() function. Depending on the hardware source for the ticks, it
+ is possible for a tick to be missed. This function cannot guarantee that
+ ticks will not be missed. If a timeout occurs waiting for the specified
+ number of ticks, then EFI_TIMEOUT is returned.
+
+ @param This The EFI_METRONOME_ARCH_PROTOCOL instance.
+ @param TickNumber Number of ticks to wait.
+
+ @retval EFI_SUCCESS The wait for the number of ticks specified by TickNumber
+ succeeded.
+ @retval EFI_TIMEOUT A timeout occurred waiting for the specified number of ticks.
+
+**/
+EFI_STATUS
+EFIAPI
+WaitForTick (
+ IN EFI_METRONOME_ARCH_PROTOCOL *This,
+ IN UINT32 TickNumber
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.inf b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.inf
new file mode 100644
index 000000000..6d5de0c2a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.inf
@@ -0,0 +1,54 @@
+## @file
+# This module produces the Metronome Architectural Protocol on top of Timer Library.
+#
+# This is a generic implementation of the Metronome Architectural Protocol that
+# layers on top of an instance of the Timer Library. The Timer Library provides
+# functions for nanosecond and microsecond delays. This generic implementation
+# produces a fixed TickPeriod of 100ns unit, and when the WaitForTick() service
+# is called, the number of ticks passed in is converted to either nanosecond or
+# microsecond units. If the number of ticks is small, then nanoseconds are used.
+# If the number of ticks is large, then microseconds are used. This prevents
+# overflows that could occur for long delays if only nanoseconds were used and also
+# provides the greatest accuracy for small delays.
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Metronome
+ MODULE_UNI_FILE = Metronome.uni
+ FILE_GUID = C8339973-A563-4561-B858-D8476F9DEFC4
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InstallMetronome
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ TimerLib
+ DebugLib
+
+[Sources]
+ Metronome.c
+ Metronome.h
+
+[Protocols]
+ gEfiMetronomeArchProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MetronomeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.uni b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.uni
new file mode 100644
index 000000000..6f23db2df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Metronome/Metronome.uni
@@ -0,0 +1,24 @@
+// /** @file
+// This module produces the Metronome Architectural Protocol on top of Timer Library.
+//
+// This is a generic implementation of the Metronome Architectural Protocol that
+// layers on top of an instance of the Timer Library. The Timer Library provides
+// functions for nanosecond and microsecond delays. This generic implementation
+// produces a fixed TickPeriod of 100ns unit, and when the WaitForTick() service
+// is called, the number of ticks passed in is converted to either nanosecond or
+// microsecond units. If the number of ticks is small, then nanoseconds are used.
+// If the number of ticks is large, then microseconds are used. This prevents
+// overflows that could occur for long delays if only nanoseconds were used and also
+// provides the greatest accuracy for small delays.
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the Metronome Architectural Protocol on top of Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is a generic implementation of the Metronome Architectural Protocol that layers on top of an instance of the Timer Library. The Timer Library provides functions for nanosecond and microsecond delays. This generic implementation produces a fixed TickPeriod of 100ns unit, and when the WaitForTick() service is called, the number of ticks passed in is converted to either nanosecond or microsecond units. If the number of ticks is small, then nanoseconds are used. If the number of ticks is large, then microseconds are used. This prevents overflows that could occur for long delays if only nanoseconds were used and also provides the greatest accuracy for small delays."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Metronome/MetronomeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Metronome/MetronomeExtra.uni
new file mode 100644
index 000000000..3d2b57dbc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Metronome/MetronomeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Metronome Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Metronome/Timer DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounter.c b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounter.c
new file mode 100644
index 000000000..f74b0b8a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounter.c
@@ -0,0 +1,269 @@
+/** @file
+ Produce the UEFI boot service GetNextMonotonicCount() and runtime service
+ GetNextHighMonotonicCount().
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/MonotonicCounter.h>
+#include <Guid/MtcVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// The handle to install Monotonic Counter Architctural Protocol
+//
+EFI_HANDLE mMonotonicCounterHandle = NULL;
+
+//
+// The current monotonic counter value
+//
+UINT64 mEfiMtc;
+
+//
+// Event to update the monotonic Counter's high part when low part overflows.
+//
+EFI_EVENT mEfiMtcEvent;
+
+/**
+ Returns a monotonically increasing count for the platform.
+
+ This function returns a 64-bit value that is numerically larger then the last
+ time the function was called.
+ The platform monotonic counter is comprised of two parts: the high 32 bits
+ and the low 32 bits. The low 32-bit value is volatile and is reset to zero on
+ every system reset. It is increased by 1 on every call to GetNextMonotonicCount().
+ The high 32-bit value is nonvolatile and is increased by one on whenever the
+ system resets or the low 32-bit counter overflows.
+
+ @param Count Pointer to returned value.
+
+ @retval EFI_SUCCESS The next monotonic count was returned.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+ @retval EFI_INVALID_PARAMETER Count is NULL.
+ @retval EFI_UNSUPPORTED This function is called at runtime.
+
+**/
+EFI_STATUS
+EFIAPI
+MonotonicCounterDriverGetNextMonotonicCount (
+ OUT UINT64 *Count
+ )
+{
+ EFI_TPL OldTpl;
+
+ //
+ // Cannot be called after ExitBootServices()
+ //
+ if (EfiAtRuntime ()) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check input parameters
+ //
+ if (Count == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Update the monotonic counter with a lock
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ *Count = mEfiMtc;
+ mEfiMtc++;
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // If the low 32-bit counter overflows (MSB bit toggled),
+ // then signal that the high part needs update now.
+ //
+ if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & BIT31) {
+ gBS->SignalEvent (mEfiMtcEvent);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the next high 32 bits of the platform's monotonic counter.
+
+ The GetNextHighMonotonicCount() function returns the next high 32 bits
+ of the platform's monotonic counter. The platform's monotonic counter is
+ comprised of two 32 bit quantities: the high 32 bits and the low 32 bits.
+ During boot service time the low 32 bit value is volatile: it is reset to
+ zero on every system reset and is increased by 1 on every call to GetNextMonotonicCount().
+ The high 32 bit value is non-volatile and is increased by 1 whenever the system resets,
+ whenever GetNextHighMonotonicCount() is called, or whenever the low 32 bit count
+ (returned by GetNextMonoticCount()) overflows.
+ The GetNextMonotonicCount() function is only available at boot services time.
+ If the operating system wishes to extend the platform monotonic counter to runtime,
+ it may do so by utilizing GetNextHighMonotonicCount(). To do this, before calling
+ ExitBootServices() the operating system would call GetNextMonotonicCount() to obtain
+ the current platform monotonic count. The operating system would then provide an
+ interface that returns the next count by:
+ Adding 1 to the last count.
+ Before the lower 32 bits of the count overflows, call GetNextHighMonotonicCount().
+ This will increase the high 32 bits of the platform's non-volatile portion of the monotonic
+ count by 1.
+
+ This function may only be called at Runtime.
+
+ @param HighCount Pointer to returned value.
+
+ @retval EFI_SUCCESS The next high monotonic count was returned.
+ @retval EFI_INVALID_PARAMETER HighCount is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
+ @retval EFI_OUT_OF_RESOURCES If variable service reports that not enough storage
+ is available to hold the variable and its data.
+
+**/
+EFI_STATUS
+EFIAPI
+MonotonicCounterDriverGetNextHighMonotonicCount (
+ OUT UINT32 *HighCount
+ )
+{
+ EFI_TPL OldTpl;
+
+ //
+ // Check input parameters
+ //
+ if (HighCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!EfiAtRuntime ()) {
+ //
+ // Use a lock if called before ExitBootServices()
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;
+ mEfiMtc = LShiftU64 (*HighCount, 32);
+ gBS->RestoreTPL (OldTpl);
+ } else {
+ *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1;
+ mEfiMtc = LShiftU64 (*HighCount, 32);
+ }
+ //
+ // Update the NV variable to match the new high part
+ //
+ return EfiSetVariable (
+ MTC_VARIABLE_NAME,
+ &gMtcVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT32),
+ HighCount
+ );
+
+}
+
+/**
+ Monotonic counter event handler. This handler updates the high part of monotonic counter.
+
+ @param Event The event to handle.
+ @param Context The event context.
+
+**/
+VOID
+EFIAPI
+EfiMtcEventHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINT32 HighCount;
+
+ MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount);
+}
+
+/**
+ Entry point of monotonic counter driver.
+
+ @param ImageHandle The image handle of this driver.
+ @param SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS The initialization is successful.
+
+**/
+EFI_STATUS
+EFIAPI
+MonotonicCounterDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 HighCount;
+ UINTN BufferSize;
+
+ //
+ // Make sure the Monotonic Counter Architectural Protocol has not been installed in the system yet.
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMonotonicCounterArchProtocolGuid);
+
+ //
+ // Initialize event to handle low-part overflow
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EfiMtcEventHandler,
+ NULL,
+ &mEfiMtcEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Read the last high part
+ //
+ BufferSize = sizeof (UINT32);
+ Status = EfiGetVariable (
+ MTC_VARIABLE_NAME,
+ &gMtcVendorGuid,
+ NULL,
+ &BufferSize,
+ &HighCount
+ );
+ if (EFI_ERROR (Status)) {
+ HighCount = 0;
+ }
+ //
+ // Set the current value
+ //
+ mEfiMtc = LShiftU64 (HighCount, 32);
+
+ //
+ // Increment the upper 32 bits for this boot
+ // Continue even if it fails. It will only fail if the variable services are
+ // not functional.
+ //
+ MonotonicCounterDriverGetNextHighMonotonicCount (&HighCount);
+
+ //
+ // Fill in the EFI Boot Services and EFI Runtime Services Monotonic Counter Fields
+ //
+ gBS->GetNextMonotonicCount = MonotonicCounterDriverGetNextMonotonicCount;
+ gRT->GetNextHighMonotonicCount = MonotonicCounterDriverGetNextHighMonotonicCount;
+
+ //
+ // Install the Monotonic Counter Architctural Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mMonotonicCounterHandle,
+ &gEfiMonotonicCounterArchProtocolGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
new file mode 100644
index 000000000..f08f17cfb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# This module produces the UEFI boot service GetNextMonotonicCount() and runtime service GetNextHighMonotonicCount().
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MonotonicCounterRuntimeDxe
+ MODULE_UNI_FILE = MonotonicCounterRuntimeDxe.uni
+ FILE_GUID = AD608272-D07F-4964-801E-7BD3B7888652
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MonotonicCounterDriverInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ MonotonicCounter.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ UefiRuntimeLib
+ UefiDriverEntryPoint
+ BaseLib
+
+[Guids]
+ ## PRODUCES ## Variable:L"MTC"
+ ## CONSUMES ## Variable:L"MTC"
+ gMtcVendorGuid
+
+[Protocols]
+ gEfiMonotonicCounterArchProtocolGuid ## PRODUCES
+
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ MonotonicCounterRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.uni
new file mode 100644
index 000000000..e00fc13e3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This module produces the UEFI boot service GetNextMonotonicCount() and runtime service GetNextHighMonotonicCount().
+//
+// This module produces the UEFI boot service GetNextMonotonicCount() and runtime service GetNextHighMonotonicCount().
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the UEFI boot service GetNextMonotonicCount() and runtime service GetNextHighMonotonicCount()"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces the UEFI boot service GetNextMonotonicCount() and runtime service GetNextHighMonotonicCount()."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxeExtra.uni
new file mode 100644
index 000000000..0b505cf05
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// MonotonicCounterRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Monotonic Counter DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.c b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.c
new file mode 100644
index 000000000..cdb9b4fac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.c
@@ -0,0 +1,1378 @@
+/** @file
+ PCD DXE driver manage all PCD entry initialized in PEI phase and DXE phase, and
+ produce the implementation of native PCD protocol and EFI_PCD_PROTOCOL defined in
+ PI 1.4a Vol3.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Service.h"
+
+///
+/// PCD database lock.
+///
+EFI_LOCK mPcdDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_NOTIFY);
+
+///
+/// PCD_PROTOCOL the EDKII native implementation which support dynamic
+/// type and dynamicEx type PCDs.
+///
+PCD_PROTOCOL mPcdInstance = {
+ DxePcdSetSku,
+
+ DxePcdGet8,
+ DxePcdGet16,
+ DxePcdGet32,
+ DxePcdGet64,
+ DxePcdGetPtr,
+ DxePcdGetBool,
+ DxePcdGetSize,
+
+ DxePcdGet8Ex,
+ DxePcdGet16Ex,
+ DxePcdGet32Ex,
+ DxePcdGet64Ex,
+ DxePcdGetPtrEx,
+ DxePcdGetBoolEx,
+ DxePcdGetSizeEx,
+
+ DxePcdSet8,
+ DxePcdSet16,
+ DxePcdSet32,
+ DxePcdSet64,
+ DxePcdSetPtr,
+ DxePcdSetBool,
+
+ DxePcdSet8Ex,
+ DxePcdSet16Ex,
+ DxePcdSet32Ex,
+ DxePcdSet64Ex,
+ DxePcdSetPtrEx,
+ DxePcdSetBoolEx,
+
+ DxeRegisterCallBackOnSet,
+ DxeUnRegisterCallBackOnSet,
+ DxePcdGetNextToken,
+ DxePcdGetNextTokenSpace
+};
+
+///
+/// EFI_PCD_PROTOCOL is defined in PI 1.2 Vol 3 which only support dynamicEx type
+/// PCD.
+///
+EFI_PCD_PROTOCOL mEfiPcdInstance = {
+ DxePcdSetSku,
+ DxePcdGet8Ex,
+ DxePcdGet16Ex,
+ DxePcdGet32Ex,
+ DxePcdGet64Ex,
+ DxePcdGetPtrEx,
+ DxePcdGetBoolEx,
+ DxePcdGetSizeEx,
+ DxePcdSet8Ex,
+ DxePcdSet16Ex,
+ DxePcdSet32Ex,
+ DxePcdSet64Ex,
+ DxePcdSetPtrEx,
+ DxePcdSetBoolEx,
+ (EFI_PCD_PROTOCOL_CALLBACK_ON_SET) DxeRegisterCallBackOnSet,
+ (EFI_PCD_PROTOCOL_CANCEL_CALLBACK) DxeUnRegisterCallBackOnSet,
+ DxePcdGetNextToken,
+ DxePcdGetNextTokenSpace
+};
+
+///
+/// Instance of GET_PCD_INFO_PROTOCOL protocol is EDKII native implementation.
+/// This protocol instance support dynamic and dynamicEx type PCDs.
+///
+GET_PCD_INFO_PROTOCOL mGetPcdInfoInstance = {
+ DxeGetPcdInfoGetInfo,
+ DxeGetPcdInfoGetInfoEx,
+ DxeGetPcdInfoGetSku
+};
+
+///
+/// Instance of EFI_GET_PCD_INFO_PROTOCOL which is defined in PI 1.2.1 Vol 3.
+/// This PPI instance only support dyanmicEx type PCD.
+///
+EFI_GET_PCD_INFO_PROTOCOL mEfiGetPcdInfoInstance = {
+ DxeGetPcdInfoGetInfoEx,
+ DxeGetPcdInfoGetSku
+};
+
+EFI_HANDLE mPcdHandle = NULL;
+UINTN mVpdBaseAddress = 0;
+
+/**
+ Main entry for PCD DXE driver.
+
+ This routine initialize the PCD database and install PCD_PROTOCOL.
+
+ @param ImageHandle Image handle for PCD DXE driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @return Status of gBS->InstallProtocolInterface()
+
+**/
+EFI_STATUS
+EFIAPI
+PcdDxeInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ //
+ // Make sure the Pcd Protocol is not already installed in the system
+ //
+
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gPcdProtocolGuid);
+
+ BuildPcdDxeDataBase ();
+
+ //
+ // Install PCD_PROTOCOL to handle dynamic type PCD
+ // Install EFI_PCD_PROTOCOL to handle dynamicEx type PCD
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPcdHandle,
+ &gPcdProtocolGuid, &mPcdInstance,
+ &gEfiPcdProtocolGuid, &mEfiPcdInstance,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install GET_PCD_INFO_PROTOCOL to handle dynamic type PCD
+ // Install EFI_GET_PCD_INFO_PROTOCOL to handle dynamicEx type PCD
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPcdHandle,
+ &gGetPcdInfoProtocolGuid, &mGetPcdInfoInstance,
+ &gEfiGetPcdInfoProtocolGuid, &mEfiGetPcdInfoInstance,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register callback function upon VariableLockProtocol
+ // to lock the variables referenced by DynamicHii PCDs with RO property set in *.dsc.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiVariableLockProtocolGuid,
+ TPL_CALLBACK,
+ VariableLockCallBack,
+ NULL,
+ &Registration
+ );
+
+ //
+ // Cache VpdBaseAddress in entry point for the following usage.
+ //
+
+ //
+ // PcdVpdBaseAddress64 is DynamicEx PCD only. So, DxePcdGet64Ex() is used to get its value.
+ //
+ mVpdBaseAddress = (UINTN) DxePcdGet64Ex (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdVpdBaseAddress64));
+ if (mVpdBaseAddress == 0) {
+ //
+ // PcdVpdBaseAddress64 is not set, get value from PcdVpdBaseAddress.
+ //
+ mVpdBaseAddress = (UINTN) PcdGet32 (PcdVpdBaseAddress);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+DxeGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return DxeGetPcdInfo (NULL, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+DxeGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return DxeGetPcdInfo (Guid, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+DxeGetPcdInfoGetSku (
+ VOID
+ )
+{
+ return (UINTN) mPcdDatabase.DxeDb->SystemSkuId;
+}
+
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+DxePcdSetSku (
+ IN UINTN SkuId
+ )
+{
+ SKU_ID *SkuIdTable;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "PcdDxe - SkuId 0x%lx is to be set.\n", (SKU_ID) SkuId));
+
+ if (SkuId == mPcdDatabase.DxeDb->SystemSkuId) {
+ //
+ // The input SKU Id is equal to current SKU Id, return directly.
+ //
+ DEBUG ((DEBUG_INFO, "PcdDxe - SkuId is same to current system Sku.\n"));
+ return;
+ }
+
+ if (mPcdDatabase.DxeDb->SystemSkuId != (SKU_ID) 0) {
+ DEBUG ((DEBUG_ERROR, "PcdDxe - The SKU Id could be changed only once."));
+ DEBUG ((
+ DEBUG_ERROR,
+ "PcdDxe - The SKU Id was set to 0x%lx already, it could not be set to 0x%lx any more.",
+ mPcdDatabase.DxeDb->SystemSkuId,
+ (SKU_ID) SkuId
+ ));
+ ASSERT (FALSE);
+ return;
+ }
+
+ SkuIdTable = (SKU_ID *) ((UINT8 *) mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SkuIdTableOffset);
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (SkuId == SkuIdTable[Index + 1]) {
+ DEBUG ((DEBUG_INFO, "PcdDxe - SkuId is found in SkuId table.\n"));
+ Status = UpdatePcdDatabase (SkuId, TRUE);
+ if (!EFI_ERROR (Status)) {
+ mPcdDatabase.DxeDb->SystemSkuId = (SKU_ID) SkuId;
+ DEBUG ((DEBUG_INFO, "PcdDxe - Set current SKU Id to 0x%lx.\n", (SKU_ID) SkuId));
+ return;
+ }
+ }
+ }
+
+ //
+ // Invalid input SkuId, the default SKU Id will be still used for the system.
+ //
+ DEBUG ((DEBUG_ERROR, "PcdDxe - Invalid input SkuId, the default SKU Id will be still used.\n"));
+ return;
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+DxePcdGet8 (
+ IN UINTN TokenNumber
+ )
+{
+ return *((UINT8 *) GetWorker (TokenNumber, sizeof (UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+DxePcdGet16 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned16 (GetWorker (TokenNumber, sizeof (UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+DxePcdGet32 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned32 (GetWorker (TokenNumber, sizeof (UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+DxePcdGet64 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned64(GetWorker (TokenNumber, sizeof (UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+DxePcdGetPtr (
+ IN UINTN TokenNumber
+ )
+{
+ return GetWorker (TokenNumber, 0);
+}
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+DxePcdGetBool (
+ IN UINTN TokenNumber
+ )
+{
+ return *((BOOLEAN *) GetWorker (TokenNumber, sizeof (BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+DxePcdGetSize (
+ IN UINTN TokenNumber
+ )
+{
+ UINTN Size;
+ UINT32 *LocalTokenNumberTable;
+ BOOLEAN IsPeiDb;
+ UINTN MaxSize;
+ UINTN TmpTokenNumber;
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ //
+ // Backup the TokenNumber passed in as GetPtrTypeSize need the original TokenNumber
+ //
+ TmpTokenNumber = TokenNumber;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ IsPeiDb = (BOOLEAN) (TokenNumber + 1 < mPeiLocalTokenCount + 1);
+
+ TokenNumber = IsPeiDb ? TokenNumber :
+ (TokenNumber - mPeiLocalTokenCount);
+
+ LocalTokenNumberTable = IsPeiDb ? (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset)
+ : (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
+
+ Size = (LocalTokenNumberTable[TokenNumber] & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
+
+ if (Size == 0) {
+ //
+ // For pointer type, we need to scan the SIZE_TABLE to get the current size.
+ //
+ return GetPtrTypeSize (TmpTokenNumber, &MaxSize);
+ } else {
+ return Size;
+ }
+
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+DxePcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((UINT8 *) ExGetWorker (Guid, ExTokenNumber, sizeof(UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+DxePcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned16 (ExGetWorker (Guid, ExTokenNumber, sizeof(UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+DxePcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned32 (ExGetWorker (Guid, ExTokenNumber, sizeof(UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+DxePcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned64 (ExGetWorker (Guid, ExTokenNumber, sizeof(UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+DxePcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ExGetWorker (Guid, ExTokenNumber, 0);
+}
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+DxePcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((BOOLEAN *) ExGetWorker (Guid, ExTokenNumber, sizeof(BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+DxePcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return DxePcdGetSize(GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ )
+{
+ return SetWorker (TokenNumber, Buffer, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT8 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT16 Value
+ )
+{
+ //
+ // PcdSetNvStoreDefaultId should be set in PEI phase to take effect.
+ //
+ ASSERT (!(CompareGuid (Guid, &gEfiMdeModulePkgTokenSpaceGuid) &&
+ (ExTokenNumber == PcdToken(PcdSetNvStoreDefaultId))));
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT32 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT64 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ )
+{
+ return ExSetWorker(ExTokenNumber, Guid, Buffer, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ )
+{
+ EFI_STATUS Status;
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Aquire lock to prevent reentrance from TPL_CALLBACK level
+ //
+ EfiAcquireLock (&mPcdDatabaseLock);
+
+ Status = DxeRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction);
+
+ EfiReleaseLock (&mPcdDatabaseLock);
+
+ return Status;
+}
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ )
+{
+ EFI_STATUS Status;
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Aquire lock to prevent reentrance from TPL_CALLBACK level
+ //
+ EfiAcquireLock (&mPcdDatabaseLock);
+
+ Status = DxeUnRegisterCallBackWorker (TokenNumber, Guid, CallBackFunction);
+
+ EfiReleaseLock (&mPcdDatabaseLock);
+
+ return Status;
+}
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to retrieve the next token.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request is
+ being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber
+ A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service has retrieved the next valid token number.
+ @retval EFI_NOT_FOUND The PCD service could not find data from the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN PeiExMapTableEmpty;
+ BOOLEAN DxeExMapTableEmpty;
+
+ Status = EFI_NOT_FOUND;
+ PeiExMapTableEmpty = mPeiExMapTableEmpty;
+ DxeExMapTableEmpty = mDxeExMapTableEmpty;
+
+ //
+ // Scan the local token space
+ //
+ if (Guid == NULL) {
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ if (((*TokenNumber + 1 > mPeiNexTokenCount + 1) && (*TokenNumber + 1 <= mPeiLocalTokenCount + 1)) ||
+ ((*TokenNumber + 1 > (mPeiLocalTokenCount + mDxeNexTokenCount + 1)))) {
+ return EFI_NOT_FOUND;
+ }
+
+ (*TokenNumber)++;
+ if ((*TokenNumber + 1 > mPeiNexTokenCount + 1) &&
+ (*TokenNumber + 1 <= mPeiLocalTokenCount + 1)) {
+ //
+ // The first Non-Ex type Token Number for DXE PCD
+ // database is mPeiLocalTokenCount + 1
+ //
+ if (mDxeNexTokenCount > 0) {
+ *TokenNumber = mPeiLocalTokenCount + 1;
+ } else {
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ }
+ } else if (*TokenNumber + 1 > mDxeNexTokenCount + mPeiLocalTokenCount + 1) {
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (PeiExMapTableEmpty && DxeExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!PeiExMapTableEmpty) {
+ Status = ExGetNextTokeNumber (
+ Guid,
+ TokenNumber,
+ (EFI_GUID *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset),
+ mPeiGuidTableSize,
+ (DYNAMICEX_MAPPING *)((UINT8 *) mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->ExMapTableOffset),
+ mPeiExMapppingTableSize
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (!DxeExMapTableEmpty) {
+ Status = ExGetNextTokeNumber (
+ Guid,
+ TokenNumber,
+ (EFI_GUID *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset),
+ mDxeGuidTableSize,
+ (DYNAMICEX_MAPPING *)((UINT8 *) mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->ExMapTableOffset),
+ mDxeExMapppingTableSize
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Get all token space guid table which is different with given token space guid.
+
+ @param ExMapTableSize The size of ExMapTable in item
+ @param ExMapTable Token space guid table that want to be scaned.
+ @param GuidTable Guid table
+
+ @return all token space guid table which is different with given token space guid.
+
+**/
+EFI_GUID **
+GetDistinctTokenSpace (
+ IN OUT UINTN *ExMapTableSize,
+ IN DYNAMICEX_MAPPING *ExMapTable,
+ IN EFI_GUID *GuidTable
+ )
+{
+ EFI_GUID **DistinctTokenSpace;
+ UINTN OldGuidIndex;
+ UINTN TsIdx;
+ UINTN TempTsIdx;
+ UINTN Idx;
+ BOOLEAN Match;
+
+ DistinctTokenSpace = AllocateZeroPool (*ExMapTableSize * sizeof (EFI_GUID *));
+ ASSERT (DistinctTokenSpace != NULL);
+
+ TsIdx = 0;
+ OldGuidIndex = ExMapTable[0].ExGuidIndex;
+ DistinctTokenSpace[TsIdx] = &GuidTable[OldGuidIndex];
+ for (Idx = 1; Idx < *ExMapTableSize; Idx++) {
+ Match = FALSE;
+ OldGuidIndex = ExMapTable[Idx].ExGuidIndex;
+ for (TempTsIdx = 0; TempTsIdx <= TsIdx; TempTsIdx++) {
+ if (&GuidTable[OldGuidIndex] == DistinctTokenSpace[TempTsIdx]) {
+ //
+ // Have recorded this GUID.
+ //
+ Match = TRUE;
+ break;
+ }
+ }
+ if (!Match) {
+ DistinctTokenSpace[++TsIdx] = &GuidTable[OldGuidIndex];
+ }
+ }
+
+ //
+ // The total number of Distinct Token Space
+ // is TsIdx + 1 because we use TsIdx as a index
+ // to the DistinctTokenSpace[]
+ //
+ *ExMapTableSize = TsIdx + 1;
+ return DistinctTokenSpace;
+
+}
+
+/**
+ Retrieves the next valid PCD token namespace for a given namespace.
+
+ Gets the next valid token namespace for a given namespace. This is useful to traverse the valid
+ token namespaces on a platform.
+
+ @param[in, out] Guid An indirect pointer to EFI_GUID. On input it designates a known token
+ namespace from which the search will start. On output, it designates the next valid
+ token namespace on the platform. If *Guid is NULL, then the GUID of the first token
+ space of the current platform is returned. If the search cannot locate the next valid
+ token namespace, an error is returned and the value of *Guid is undefined.
+
+ @retval EFI_SUCCESS The PCD service retrieved the value requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the next valid token namespace.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ )
+{
+ UINTN Idx;
+ UINTN Idx2;
+ UINTN Idx3;
+ UINTN PeiTokenSpaceTableSize;
+ UINTN DxeTokenSpaceTableSize;
+ EFI_GUID **PeiTokenSpaceTable;
+ EFI_GUID **DxeTokenSpaceTable;
+ BOOLEAN Match;
+ BOOLEAN PeiExMapTableEmpty;
+ BOOLEAN DxeExMapTableEmpty;
+
+ ASSERT (Guid != NULL);
+
+ PeiExMapTableEmpty = mPeiExMapTableEmpty;
+ DxeExMapTableEmpty = mDxeExMapTableEmpty;
+
+ if (PeiExMapTableEmpty && DxeExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (TmpTokenSpaceBuffer[0] == NULL) {
+ PeiTokenSpaceTableSize = 0;
+
+ if (!PeiExMapTableEmpty) {
+ PeiTokenSpaceTableSize = mPeiExMapppingTableSize / sizeof(DYNAMICEX_MAPPING);
+ PeiTokenSpaceTable = GetDistinctTokenSpace (&PeiTokenSpaceTableSize,
+ (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->ExMapTableOffset),
+ (EFI_GUID *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset)
+ );
+ CopyMem (TmpTokenSpaceBuffer, PeiTokenSpaceTable, sizeof (EFI_GUID*) * PeiTokenSpaceTableSize);
+ TmpTokenSpaceBufferCount = PeiTokenSpaceTableSize;
+ FreePool (PeiTokenSpaceTable);
+ }
+
+ if (!DxeExMapTableEmpty) {
+ DxeTokenSpaceTableSize = mDxeExMapppingTableSize / sizeof(DYNAMICEX_MAPPING);
+ DxeTokenSpaceTable = GetDistinctTokenSpace (&DxeTokenSpaceTableSize,
+ (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->ExMapTableOffset),
+ (EFI_GUID *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset)
+ );
+
+ //
+ // Make sure EFI_GUID in DxeTokenSpaceTable does not exist in PeiTokenSpaceTable
+ //
+ for (Idx2 = 0, Idx3 = PeiTokenSpaceTableSize; Idx2 < DxeTokenSpaceTableSize; Idx2++) {
+ Match = FALSE;
+ for (Idx = 0; Idx < PeiTokenSpaceTableSize; Idx++) {
+ if (CompareGuid (TmpTokenSpaceBuffer[Idx], DxeTokenSpaceTable[Idx2])) {
+ Match = TRUE;
+ break;
+ }
+ }
+ if (!Match) {
+ TmpTokenSpaceBuffer[Idx3++] = DxeTokenSpaceTable[Idx2];
+ }
+ }
+
+ TmpTokenSpaceBufferCount = Idx3;
+ FreePool (DxeTokenSpaceTable);
+ }
+ }
+
+ if (*Guid == NULL) {
+ *Guid = TmpTokenSpaceBuffer[0];
+ return EFI_SUCCESS;
+ }
+
+ for (Idx = 0; Idx < TmpTokenSpaceBufferCount; Idx++) {
+ if (CompareGuid (*Guid, TmpTokenSpaceBuffer[Idx])) {
+ if (Idx == TmpTokenSpaceBufferCount - 1) {
+ //
+ // It has been the last token namespace.
+ //
+ *Guid = NULL;
+ return EFI_NOT_FOUND;
+ } else {
+ Idx++;
+ *Guid = TmpTokenSpaceBuffer[Idx];
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.inf b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
new file mode 100644
index 000000000..eb9f757f1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
@@ -0,0 +1,349 @@
+## @file
+# PCD DXE driver manage database contains all dynamic PCD entries and produce the implementation of PCD protocol.
+#
+# This version PCD DXE depends on the external PCD database binary file, not built in PCD data base.
+# There are two PCD Protocols as follows:
+# 1) PCD_PROTOCOL
+# It is EDKII implementation which support Dynamic/DynamicEx type Pcds.
+# 2) EFI_PCD_PROTOCOL
+# It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+# type Pcd.
+#
+# For dynamicEx type PCD, it is compatible between PCD_PROTOCOL and EFI_PCD_PROTOCOL.
+# PCD DXE driver will produce above two protocols at same time.
+#
+# PCD database is generated as the separate binary image at build time. The binary image
+# will be intergrated into Firmware volume together with PCD driver.
+#
+# ////////////////////////////////////////////////////////////////////////////////
+# // //
+# // Introduction of PCD database //
+# // //
+# ////////////////////////////////////////////////////////////////////////////////
+#
+# 1, Introduction
+# PCD database hold all dynamic type PCD information. The structure of PEI PCD
+# database is generated by build tools according to dynamic PCD usage for
+# specified platform.
+#
+# 2, Dynamic Type PCD
+# Dynamic type PCD is used for the configuration/setting which value is determined
+# dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+# PatchablePcd) is fixed in final generated FD image in build time.
+#
+# 2.1 The "dynamic" determination means one of below cases:
+# a) The PCD setting value is produced by someone driver and consumed by
+# other driver in execution time.
+# b) The PCD setting value is set/get by user from FrontPage.
+# c) The PCD setting value is produced by platform OEM vendor in specified area.
+#
+# 2.2 According to module distribution way, dynamic PCD could be classfied as:
+# a) Dynamic:
+# If module is released in source code and will be built with platform
+# DSC, the dynamic PCD used by this module can be accessed as:
+# PcdGetxx(PcdSampleDynamicPcd);
+# In building platform, build tools will translate PcdSampleDynamicPcd to
+# pair of {Token Space Guid: Token Number} for this PCD.
+# b) DynamicEx:
+# If module is release as binary and will not pariticpate platform building,
+# the dynamic PCD used by this module need be accessed as:
+# PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+# Developer need explicity gives {Token Space Guid:Token Number} as parameter
+# in writting source code.
+#
+# 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+# a) Default Storage:
+# - The PCD value is stored in PCD database maintained by PCD driver in boot
+# time memory.
+# - This type is used for communication between PEIM/DXE driver, DXE/DXE
+# driver. But all set/get value will be losted after boot-time memory
+# is turn off.
+# - [PcdsDynamicDefault] is used as section name for this type PCD in
+# platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+#
+# b) Variable Storage:
+# - The PCD value is stored in variable area.
+# - As default storage type, this type PCD could be used for PEI/DXE driver
+# communication. But beside it, this type PCD could also be used to store
+# the value associate with a HII setting via variable interface.
+# - In PEI phase, the PCD value could only be got but can not be set due
+# to variable area is readonly.
+# - [PcdsDynamicHii] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+#
+# c) OEM specificed storage area:
+# - The PCD value is stored in OEM specified area which base address is
+# specified by PCD setting - PcdVpdBaseAddress64 or PcdVpdBaseAddress.
+# - The area is read only for PEI and DXE phase.
+# - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+#
+# 2.4 When and how to use dynamic PCD
+# Module developer do not care the used PCD is dynamic or static when writting
+# source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+# in platform DSC file. Please ref section 2.3 to get matching between dynamic
+# PCD type and section name in DSC file.
+#
+# 3, PCD database:
+# Although dynamic PCD could be in different storage type as above description,
+# but the basic information and default value for all dynamic PCD is hold
+# by PCD database maintained by PEI/DXE driver.
+#
+# As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+# also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+# To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+# PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+# database contains all PCDs used in PEI/DXE phase in memory.
+#
+# Build tool will generate PCD database into the separate binary file for
+# PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+#
+# 3.1 PcdPeim and PcdDxe
+# PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+# build guid hob in temporary memory and copy the binary data base from flash
+# to temporary memory for PEI PCD database.
+# DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+# a new PCD database is allocated in boot-time memory which including all
+# PEI PCD and DXE PCD entry.
+#
+# Pcd driver should run as early as possible before any other driver access
+# dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+# making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+#
+# 3.2 Token space Guid/Token number, Platform token, Local token number
+# Dynamic PCD
+# +-----------+ +---------+
+# |TokenSpace | |Platform |
+# | Guid | build tool | Token |
+# | + +-------------->| Number |
+# | Token | +---------+`._
+# | Number | `.
+# +-----------+ `. +------+
+# `-|Local |
+# |Token |
+# DynamicEx PCD ,-|Number|
+# +-----------+ ,-' +------+
+# |TokenSpace | ,-'
+# | Guid | _,-'
+# | + +.'
+# | Token |
+# | Number |
+# +-----------+
+#
+#
+# 3.2.1 Pair of Token space guid + Token number
+# Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+# is not easy maintained by PCD driver, and hashed token number will make
+# searching slowly.
+#
+# 3.2.2 Platform Token Number
+# "Platform token number" concept is introduced for mapping to a pair of
+# "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+# build tool in autogen.h and all of them are continual in a platform scope
+# started from 1.(0 meaning invalid internal token number)
+# With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+# in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+# in autogen.h.
+# Notes: The mapping between pair of "tokenspace guid + token number" and
+# "internal token number" need build tool establish, so "platform token number"
+# mechanism is not suitable for binary module which use DynamicEx type PCD.
+# To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+# to be specificed for PcdSet/PcdGet accessing macro.
+#
+# Platform Token Number is started from 1, and inceased continuous. From whole
+# platform scope, there are two zones: PEI Zone and DXE Zone
+# | Platform Token Number
+# ----------|----------------------------------------------------------------
+# PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+# DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+#
+# 3.2.3 Local Token Number
+# To fast searching a PCD entry in PCD database, PCD driver translate
+# platform token number to local token number via a mapping table.
+# For binary DynamicEx type PCD, there is a another mapping table to translate
+# "token space guid + token number" to local token number directly.
+# Local token number is identifier for all internal interface in PCD PEI/DXE
+# driver.
+#
+# A local token number is a 32-bit value in following meaning:
+# 32 ------------- 28 ---------- 24 -------- 0
+# | PCD type mask | Datum Type | Offset |
+# +-----------------------------------------+
+# where:
+# PCd type mask: indicate Pcd type from following macro:
+# PCD_TYPE_DATA
+# PCD_TYPE_HII
+# PCD_TYPE_VPD
+# PCD_TYPE_STRING
+# Datum Type : indicate PCD vaue type from following macro:
+# PCD_DATUM_TYPE_POINTER
+# PCD_DATUM_TYPE_UINT8
+# PCD_DATUM_TYPE_UINT16
+# PCD_DATUM_TYPE_UINT32
+# PCD_DATUM_TYPE_UINT64
+# Offset : indicate the related offset of PCD value in PCD database array.
+# Based on local token number, PCD driver could fast determine PCD type, value
+# type and get PCD entry from PCD database.
+#
+# 3.3 PCD Database binary file
+# PCD Database binary file will be created at build time as the standalone binary image.
+# To understand the binary image layout, PCD Database C structure is still generated
+# as comments by build tools in PCD driver's autogen.h/
+# autogen.c file. In generated C structure, following information is stored:
+# - ExMapTable: This table is used translate a binary dynamicex type PCD's
+# "tokenguid + token" to local token number.
+# - LocalTokenNumberTable:
+# This table stores all local token number in array, use "Internal
+# token number" as array index to get PCD entry's offset fastly.
+# - SizeTable: This table stores the size information for all PCD entry.
+# - GuidTable: This table stores guid value for DynamicEx's token space,
+# HII type PCD's variable GUID.
+# - SkuIdTable: TBD
+# - SystemSkuId: TBD
+# - PCD value structure:
+# Every PCD has a value record in PCD database. For different
+# datum type PCD has different record structure which will be
+# introduced in 3.3.1
+#
+# In a PCD database structure, there are two major area: Init and UnInit.
+# Init area is use stored above PCD internal structure such as ExMapTable,
+# LocalTokenNumberTable etc and the (default) value of PCD which has default
+# value specified in platform DSC file.
+# Unint area is used stored the value of PCD which has no default value in
+# platform DSC file, the value of NULL, 0 specified in platform DSC file can
+# be seemed as "no default value".
+#
+# 3.3.1 Simple Sample PCD Database C Structure
+# A general sample of PCD database structue is as follows:
+# typedef struct _PCD_DATABASE {
+# typedef struct _PCD_DATABASE_INIT {
+# //===== Following is PCD database internal maintain structures
+# DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+# UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+# GUID GuidTable[PEI_GUID_TABLE_SIZE];
+# SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+# UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+# SKU_ID SystemSkuId;
+#
+# //===== Following is value structure for PCD with default value
+# ....
+# ....
+# ....
+# } Init;
+# typedef struct _PCD_DATABSE_UNINIT {
+# //==== Following is value structure for PCD without default value
+# ....
+# ....
+# } UnInit;
+# }
+#
+# 3.3.2 PCD value structure in PCD database C structure
+# The value's structure is generated by build tool in PCD database C structure.
+# The PCDs in different datum type has different value structure.
+#
+# 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+# The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+# data member in PCD database, For example:
+# UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+# Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+# Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+# in DEC file.
+#
+# 3.3.2.2 VOID* datum type PCD
+# The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+#
+# 3.3.2.2.1 VOID* - string type
+# If the default value for VOID* datum type PCD like L"xxx", the PCD is
+# used for unicode string, and C structure of this datum type PCD is
+# UINT16 string array in PCD database, for example:
+# UINT16 StringTable[29];
+# The number of 29 in above sample is max size of a unicode string.
+#
+# If the default value for VOID* datum type PCD like "xxx", the PCD is
+# used for ascii string, and C structure of this datum type PCD is
+# UINT8 string array in PCD database, for example:
+# UINT8 StringTable[20];
+# The number of 20 in above sample is max size of a ascii string.
+#
+# 3.3.2.2.2 VOID* - byte array
+# If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+# the PCD is used for byte array. The generated structrue is same as
+# above ascii string table,
+# UINT8 StringTable[13];
+# The number of 13 in above sample is max size of byte array.
+#
+# 3.3.3 Some utility structures in PCD Database
+# 3.3.3.1 GuidTable
+# GuidTable array is used to store all related GUID value in PCD database:
+# - Variable GUID for HII type PCD
+# - Token space GUID for dynamicex type PCD
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PcdDxe
+ MODULE_UNI_FILE = PcdDxe.uni
+ FILE_GUID = 80CF7257-87AB-47f9-A3FE-D50B76D89541
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 4.0
+ PCD_IS_DRIVER = DXE_PCD_DRIVER
+ ENTRY_POINT = PcdDxeInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Pcd.c
+ Service.c
+ Service.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiLib
+ DebugLib
+ BaseLib
+ PcdLib
+ DxeServicesLib
+
+[Guids]
+ gPcdDataBaseHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gPcdDataBaseSignatureGuid ## CONSUMES ## GUID # PCD database signature GUID.
+ gEfiMdeModulePkgTokenSpaceGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gPcdProtocolGuid ## PRODUCES
+ gEfiPcdProtocolGuid ## PRODUCES
+ gGetPcdInfoProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiGetPcdInfoProtocolGuid ## SOMETIMES_PRODUCES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress64 ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PcdDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxe.uni b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxe.uni
new file mode 100644
index 000000000..6a3b3db4c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxe.uni
@@ -0,0 +1,291 @@
+// /** @file
+// PCD DXE driver manage database contains all dynamic PCD entries and produce the implementation of PCD protocol.
+//
+// This version PCD DXE depends on the external PCD database binary file, not built in PCD data base.
+// There are two PCD Protocols as follows:
+// 1) PCD_PROTOCOL
+// It is EDKII implementation which support Dynamic/DynamicEx type Pcds.
+// 2) EFI_PCD_PROTOCOL
+// It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+// type Pcd.
+//
+// For dynamicEx type PCD, it is compatible between PCD_PROTOCOL and EFI_PCD_PROTOCOL.
+// PCD DXE driver will produce above two protocols at same time.
+//
+// PCD database is generated as the separate binary image at build time. The binary image
+// will be intergrated into Firmware volume together with PCD driver.
+//
+// ////////////////////////////////////////////////////////////////////////////////
+// // //
+// // Introduction of PCD database //
+// // //
+// ////////////////////////////////////////////////////////////////////////////////
+//
+// 1, Introduction
+// PCD database hold all dynamic type PCD information. The structure of PEI PCD
+// database is generated by build tools according to dynamic PCD usage for
+// specified platform.
+//
+// 2, Dynamic Type PCD
+// Dynamic type PCD is used for the configuration/setting which value is determined
+// dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+// PatchablePcd) is fixed in final generated FD image in build time.
+//
+// 2.1 The "dynamic" determination means one of below cases:
+// a) The PCD setting value is produced by someone driver and consumed by
+// other driver in execution time.
+// b) The PCD setting value is set/get by user from FrontPage.
+// c) The PCD setting value is produced by platform OEM vendor in specified area.
+//
+// 2.2 According to module distribution way, dynamic PCD could be classfied as:
+// a) Dynamic:
+// If module is released in source code and will be built with platform
+// DSC, the dynamic PCD used by this module can be accessed as:
+// PcdGetxx(PcdSampleDynamicPcd);
+// In building platform, build tools will translate PcdSampleDynamicPcd to
+// pair of {Token Space Guid: Token Number} for this PCD.
+// b) DynamicEx:
+// If module is release as binary and will not pariticpate platform building,
+// the dynamic PCD used by this module need be accessed as:
+// PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+// Developer need explicity gives {Token Space Guid:Token Number} as parameter
+// in writting source code.
+//
+// 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+// a) Default Storage:
+// - The PCD value is stored in PCD database maintained by PCD driver in boot
+// time memory.
+// - This type is used for communication between PEIM/DXE driver, DXE/DXE
+// driver. But all set/get value will be losted after boot-time memory
+// is turn off.
+// - [PcdsDynamicDefault] is used as section name for this type PCD in
+// platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+//
+// b) Variable Storage:
+// - The PCD value is stored in variable area.
+// - As default storage type, this type PCD could be used for PEI/DXE driver
+// communication. But beside it, this type PCD could also be used to store
+// the value associate with a HII setting via variable interface.
+// - In PEI phase, the PCD value could only be got but can not be set due
+// to variable area is readonly.
+// - [PcdsDynamicHii] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+//
+// c) OEM specificed storage area:
+// - The PCD value is stored in OEM specified area which base address is
+// specified by a FixedAtBuild PCD setting - PcdVpdBaseAddress.
+// - The area is read only for PEI and DXE phase.
+// - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+//
+// 2.4 When and how to use dynamic PCD
+// Module developer do not care the used PCD is dynamic or static when writting
+// source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+// in platform DSC file. Please ref section 2.3 to get matching between dynamic
+// PCD type and section name in DSC file.
+//
+// 3, PCD database:
+// Although dynamic PCD could be in different storage type as above description,
+// but the basic information and default value for all dynamic PCD is hold
+// by PCD database maintained by PEI/DXE driver.
+//
+// As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+// also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+// To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+// PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+// database contains all PCDs used in PEI/DXE phase in memory.
+//
+// Build tool will generate PCD database into the separate binary file for
+// PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+//
+// 3.1 PcdPeim and PcdDxe
+// PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+// build guid hob in temporary memory and copy the binary data base from flash
+// to temporary memory for PEI PCD database.
+// DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+// a new PCD database is allocated in boot-time memory which including all
+// PEI PCD and DXE PCD entry.
+//
+// Pcd driver should run as early as possible before any other driver access
+// dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+// making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+//
+// 3.2 Token space Guid/Token number, Platform token, Local token number
+// Dynamic PCD
+// +-----------+ +---------+
+// |TokenSpace | |Platform |
+// | Guid | build tool | Token |
+// | + +-------------->| Number |
+// | Token | +---------+`._
+// | Number | `.
+// +-----------+ `. +------+
+// `-|Local |
+// |Token |
+// DynamicEx PCD ,-|Number|
+// +-----------+ ,-' +------+
+// |TokenSpace | ,-'
+// | Guid | _,-'
+// | + +.'
+// | Token |
+// | Number |
+// +-----------+
+//
+//
+// 3.2.1 Pair of Token space guid + Token number
+// Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+// is not easy maintained by PCD driver, and hashed token number will make
+// searching slowly.
+//
+// 3.2.2 Platform Token Number
+// "Platform token number" concept is introduced for mapping to a pair of
+// "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+// build tool in autogen.h and all of them are continual in a platform scope
+// started from 1.(0 meaning invalid internal token number)
+// With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+// in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+// in autogen.h.
+// Notes: The mapping between pair of "tokenspace guid + token number" and
+// "internal token number" need build tool establish, so "platform token number"
+// mechanism is not suitable for binary module which use DynamicEx type PCD.
+// To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+// to be specificed for PcdSet/PcdGet accessing macro.
+//
+// Platform Token Number is started from 1, and inceased continuous. From whole
+// platform scope, there are two zones: PEI Zone and DXE Zone
+// | Platform Token Number
+// ----------|----------------------------------------------------------------
+// PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+// DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+//
+// 3.2.3 Local Token Number
+// To fast searching a PCD entry in PCD database, PCD driver translate
+// platform token number to local token number via a mapping table.
+// For binary DynamicEx type PCD, there is a another mapping table to translate
+// "token space guid + token number" to local token number directly.
+// Local token number is identifier for all internal interface in PCD PEI/DXE
+// driver.
+//
+// A local token number is a 32-bit value in following meaning:
+// 32 ------------- 28 ---------- 24 -------- 0
+// | PCD type mask | Datum Type | Offset |
+// +-----------------------------------------+
+// where:
+// PCd type mask: indicate Pcd type from following macro:
+// PCD_TYPE_DATA
+// PCD_TYPE_HII
+// PCD_TYPE_VPD
+// PCD_TYPE_STRING
+// Datum Type : indicate PCD vaue type from following macro:
+// PCD_DATUM_TYPE_POINTER
+// PCD_DATUM_TYPE_UINT8
+// PCD_DATUM_TYPE_UINT16
+// PCD_DATUM_TYPE_UINT32
+// PCD_DATUM_TYPE_UINT64
+// Offset : indicate the related offset of PCD value in PCD database array.
+// Based on local token number, PCD driver could fast determine PCD type, value
+// type and get PCD entry from PCD database.
+//
+// 3.3 PCD Database binary file
+// PCD Database binary file will be created at build time as the standalone binary image.
+// To understand the binary image layout, PCD Database C structure is still generated
+// as comments by build tools in PCD driver's autogen.h/
+// autogen.c file. In generated C structure, following information is stored:
+// - ExMapTable: This table is used translate a binary dynamicex type PCD's
+// "tokenguid + token" to local token number.
+// - LocalTokenNumberTable:
+// This table stores all local token number in array, use "Internal
+// token number" as array index to get PCD entry's offset fastly.
+// - SizeTable: This table stores the size information for all PCD entry.
+// - GuidTable: This table stores guid value for DynamicEx's token space,
+// HII type PCD's variable GUID.
+// - SkuIdTable: TBD
+// - SystemSkuId: TBD
+// - PCD value structure:
+// Every PCD has a value record in PCD database. For different
+// datum type PCD has different record structure which will be
+// introduced in 3.3.1
+//
+// In a PCD database structure, there are two major area: Init and UnInit.
+// Init area is use stored above PCD internal structure such as ExMapTable,
+// LocalTokenNumberTable etc and the (default) value of PCD which has default
+// value specified in platform DSC file.
+// Unint area is used stored the value of PCD which has no default value in
+// platform DSC file, the value of NULL, 0 specified in platform DSC file can
+// be seemed as "no default value".
+//
+// 3.3.1 Simple Sample PCD Database C Structure
+// A general sample of PCD database structue is as follows:
+// typedef struct _PCD_DATABASE {
+// typedef struct _PCD_DATABASE_INIT {
+// //===== Following is PCD database internal maintain structures
+// DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+// UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+// GUID GuidTable[PEI_GUID_TABLE_SIZE];
+// SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+// UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+// SKU_ID SystemSkuId;
+//
+// //===== Following is value structure for PCD with default value
+// ....
+// ....
+// ....
+// } Init;
+// typedef struct _PCD_DATABSE_UNINIT {
+// //==== Following is value structure for PCD without default value
+// ....
+// ....
+// } UnInit;
+// }
+//
+// 3.3.2 PCD value structure in PCD database C structure
+// The value's structure is generated by build tool in PCD database C structure.
+// The PCDs in different datum type has different value structure.
+//
+// 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+// The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+// data member in PCD database, For example:
+// UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+// Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+// Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+// in DEC file.
+//
+// 3.3.2.2 VOID* datum type PCD
+// The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+//
+// 3.3.2.2.1 VOID* - string type
+// If the default value for VOID* datum type PCD like L"xxx", the PCD is
+// used for unicode string, and C structure of this datum type PCD is
+// UINT16 string array in PCD database, for example:
+// UINT16 StringTable[29];
+// The number of 29 in above sample is max size of a unicode string.
+//
+// If the default value for VOID* datum type PCD like "xxx", the PCD is
+// used for ascii string, and C structure of this datum type PCD is
+// UINT8 string array in PCD database, for example:
+// UINT8 StringTable[20];
+// The number of 20 in above sample is max size of a ascii string.
+//
+// 3.3.2.2.2 VOID* - byte array
+// If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+// the PCD is used for byte array. The generated structrue is same as
+// above ascii string table,
+// UINT8 StringTable[13];
+// The number of 13 in above sample is max size of byte array.
+//
+// 3.3.3 Some utility structures in PCD Database
+// 3.3.3.1 GuidTable
+// GuidTable array is used to store all related GUID value in PCD database:
+// - Variable GUID for HII type PCD
+// - Token space GUID for dynamicex type PCD
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PCD DXE driver manages the database that contains all dynamic PCD entries and produce the implementation of PCD protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "PCD DXE driver manages the database that contains all dynamic PCD entries and produces the implementation of PCD protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxeExtra.uni
new file mode 100644
index 000000000..b9d12be63
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/PcdDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PcdDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform Configuration Database DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.c b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.c
new file mode 100644
index 000000000..ea7edc3cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.c
@@ -0,0 +1,1901 @@
+/** @file
+ Help functions used by PCD DXE driver.
+
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Service.h"
+#include <Library/DxeServicesLib.h>
+
+PCD_DATABASE mPcdDatabase;
+
+UINT32 mPcdTotalTokenCount;
+UINT32 mPeiLocalTokenCount;
+UINT32 mDxeLocalTokenCount;
+UINT32 mPeiNexTokenCount;
+UINT32 mDxeNexTokenCount;
+UINT32 mPeiExMapppingTableSize;
+UINT32 mDxeExMapppingTableSize;
+UINT32 mPeiGuidTableSize;
+UINT32 mDxeGuidTableSize;
+
+BOOLEAN mPeiExMapTableEmpty;
+BOOLEAN mDxeExMapTableEmpty;
+BOOLEAN mPeiDatabaseEmpty;
+
+LIST_ENTRY *mCallbackFnTable;
+EFI_GUID **TmpTokenSpaceBuffer;
+UINTN TmpTokenSpaceBufferCount;
+
+UINTN mPeiPcdDbSize = 0;
+PEI_PCD_DATABASE *mPeiPcdDbBinary = NULL;
+UINTN mDxePcdDbSize = 0;
+DXE_PCD_DATABASE *mDxePcdDbBinary = NULL;
+
+/**
+ Get Local Token Number by Token Number.
+
+ @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
+ If FALSE, the pcd entry is initialized in DXE phase.
+ @param[in] TokenNumber The PCD token number.
+
+ @return Local Token Number.
+**/
+UINT32
+GetLocalTokenNumber (
+ IN BOOLEAN IsPeiDb,
+ IN UINTN TokenNumber
+ )
+{
+ UINT32 *LocalTokenNumberTable;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ LocalTokenNumberTable = IsPeiDb ? (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset) :
+ (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
+ TokenNumber = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
+
+ return LocalTokenNumberTable[TokenNumber];
+}
+
+/**
+ Get PCD type by Local Token Number.
+
+ @param[in] LocalTokenNumber The PCD local token number.
+
+ @return PCD type.
+**/
+EFI_PCD_TYPE
+GetPcdType (
+ IN UINT32 LocalTokenNumber
+ )
+{
+ switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
+ case PCD_DATUM_TYPE_POINTER:
+ return EFI_PCD_TYPE_PTR;
+ case PCD_DATUM_TYPE_UINT8:
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {
+ return EFI_PCD_TYPE_BOOL;
+ } else {
+ return EFI_PCD_TYPE_8;
+ }
+ case PCD_DATUM_TYPE_UINT16:
+ return EFI_PCD_TYPE_16;
+ case PCD_DATUM_TYPE_UINT32:
+ return EFI_PCD_TYPE_32;
+ case PCD_DATUM_TYPE_UINT64:
+ return EFI_PCD_TYPE_64;
+ default:
+ ASSERT (FALSE);
+ return EFI_PCD_TYPE_8;
+ }
+}
+
+/**
+ Get PCD name.
+
+ @param[in] OnlyTokenSpaceName If TRUE, only need to get the TokenSpaceCName.
+ If FALSE, need to get the full PCD name.
+ @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
+ If FALSE, the pcd entry is initialized in DXE phase.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The TokenSpaceCName or full PCD name.
+**/
+CHAR8 *
+GetPcdName (
+ IN BOOLEAN OnlyTokenSpaceName,
+ IN BOOLEAN IsPeiDb,
+ IN UINTN TokenNumber
+ )
+{
+ PCD_DATABASE_INIT *Database;
+ UINT8 *StringTable;
+ UINTN NameSize;
+ PCD_NAME_INDEX *PcdNameIndex;
+ CHAR8 *TokenSpaceName;
+ CHAR8 *PcdName;
+ CHAR8 *Name;
+
+ //
+ // Return NULL when PCD name table is absent.
+ //
+ if (IsPeiDb) {
+ if (mPcdDatabase.PeiDb->PcdNameTableOffset == 0) {
+ return NULL;
+ }
+ } else {
+ if (mPcdDatabase.DxeDb->PcdNameTableOffset == 0) {
+ return NULL;
+ }
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
+ TokenNumber = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
+
+ StringTable = (UINT8 *) Database + Database->StringTableOffset;
+
+ //
+ // Get the PCD name index.
+ //
+ PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
+ TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
+ PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
+
+ if (OnlyTokenSpaceName) {
+ //
+ // Only need to get the TokenSpaceCName.
+ //
+ Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
+ } else {
+ //
+ // Need to get the full PCD name.
+ //
+ NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ //
+ // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
+ //
+ AsciiStrCatS (Name, NameSize, TokenSpaceName);
+ Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
+ AsciiStrCatS (Name, NameSize, PcdName);
+ }
+
+ return Name;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
+ If FALSE, the pcd entry is initialized in DXE phase.
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+ExGetPcdInfo (
+ IN BOOLEAN IsPeiDb,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ PCD_DATABASE_INIT *Database;
+ UINTN GuidTableIdx;
+ EFI_GUID *MatchGuid;
+ EFI_GUID *GuidTable;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ UINT32 LocalTokenNumber;
+
+ Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
+
+ GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
+ MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
+
+ //
+ // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
+ //
+ for (Index = 0; Index < Database->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to the null-terminated ASCII string
+ // associated with the token's namespace Guid.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ //
+ // Here use one representative in the token space to get the TokenSpaceCName.
+ //
+ PcdInfo->PcdName = GetPcdName (TRUE, IsPeiDb, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
+ PcdInfo->PcdSize = DxePcdGetSize (ExMapTable[Index].TokenNumber);
+ LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, ExMapTable[Index].TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+DxeGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN PeiExMapTableEmpty;
+ BOOLEAN DxeExMapTableEmpty;
+ UINT32 LocalTokenNumber;
+ BOOLEAN IsPeiDb;
+
+ ASSERT (PcdInfo != NULL);
+
+ Status = EFI_NOT_FOUND;
+ PeiExMapTableEmpty = mPeiExMapTableEmpty;
+ DxeExMapTableEmpty = mDxeExMapTableEmpty;
+
+ if (Guid == NULL) {
+ if (((TokenNumber + 1 > mPeiNexTokenCount + 1) && (TokenNumber + 1 <= mPeiLocalTokenCount + 1)) ||
+ ((TokenNumber + 1 > (mPeiLocalTokenCount + mDxeNexTokenCount + 1)))) {
+ return EFI_NOT_FOUND;
+ } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to NULL for default Token Space.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ PcdInfo->PcdName = NULL;
+ } else {
+ PcdInfo->PcdSize = DxePcdGetSize (TokenNumber);
+ IsPeiDb = FALSE;
+ if ((TokenNumber + 1 <= mPeiNexTokenCount + 1)) {
+ IsPeiDb = TRUE;
+ }
+ LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, TokenNumber);
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (PeiExMapTableEmpty && DxeExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!PeiExMapTableEmpty) {
+ Status = ExGetPcdInfo (
+ TRUE,
+ Guid,
+ TokenNumber,
+ PcdInfo
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (!DxeExMapTableEmpty) {
+ Status = ExGetPcdInfo (
+ FALSE,
+ Guid,
+ TokenNumber,
+ PcdInfo
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ )
+{
+ EFI_GUID *GuidTable;
+ UINT8 *StringTable;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+ VARIABLE_HEAD *VariableHead;
+ UINT8 *VaraiableDefaultBuffer;
+ UINT8 *Data;
+ VPD_HEAD *VpdHead;
+ UINT8 *PcdDb;
+ VOID *RetPtr;
+ UINTN TmpTokenNumber;
+ UINTN DataSize;
+ EFI_STATUS Status;
+ UINT32 LocalTokenNumber;
+ UINT32 Offset;
+ STRING_HEAD StringTableIdx;
+ BOOLEAN IsPeiDb;
+
+ //
+ // Aquire lock to prevent reentrance from TPL_CALLBACK level
+ //
+ EfiAcquireLock (&mPcdDatabaseLock);
+
+ RetPtr = NULL;
+
+ ASSERT (TokenNumber > 0);
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ TmpTokenNumber = TokenNumber;
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
+
+ ASSERT ((GetSize == DxePcdGetSize (TokenNumber + 1)) || (GetSize == 0));
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
+
+ LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
+
+ PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
+
+ if (IsPeiDb) {
+ StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
+ } else {
+ StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
+ }
+
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ VpdHead = (VPD_HEAD *) ((UINT8 *) PcdDb + Offset);
+ ASSERT (mVpdBaseAddress != 0);
+ RetPtr = (VOID *) (mVpdBaseAddress + VpdHead->Offset);
+
+ break;
+
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ case PCD_TYPE_HII:
+ if (IsPeiDb) {
+ GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
+ } else {
+ GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
+ }
+
+ VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
+ Guid = GuidTable + VariableHead->GuidTableIndex;
+ Name = (UINT16*)(StringTable + VariableHead->StringIndex);
+
+ if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
+ //
+ // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
+ // string array in string table.
+ //
+ StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + VariableHead->DefaultValueOffset);
+ VaraiableDefaultBuffer = (UINT8 *) (StringTable + StringTableIdx);
+ } else {
+ VaraiableDefaultBuffer = (UINT8 *) PcdDb + VariableHead->DefaultValueOffset;
+ }
+ Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
+ if (Status == EFI_SUCCESS) {
+ if (DataSize >= (VariableHead->Offset + GetSize)) {
+ if (GetSize == 0) {
+ //
+ // It is a pointer type. So get the MaxSize reserved for
+ // this PCD entry.
+ //
+ GetPtrTypeSize (TmpTokenNumber, &GetSize);
+ if (GetSize > (DataSize - VariableHead->Offset)) {
+ //
+ // Use actual valid size.
+ //
+ GetSize = DataSize - VariableHead->Offset;
+ }
+ }
+ //
+ // If the operation is successful, we copy the data
+ // to the default value buffer in the PCD Database.
+ // So that we can free the Data allocated in GetHiiVariable.
+ //
+ CopyMem (VaraiableDefaultBuffer, Data + VariableHead->Offset, GetSize);
+ }
+ FreePool (Data);
+ }
+ RetPtr = (VOID *) VaraiableDefaultBuffer;
+ break;
+
+ case PCD_TYPE_STRING:
+ StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + Offset);
+ RetPtr = (VOID *) (StringTable + StringTableIdx);
+ break;
+
+ case PCD_TYPE_DATA:
+ RetPtr = (VOID *) ((UINT8 *) PcdDb + Offset);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+
+ }
+
+ EfiReleaseLock (&mPcdDatabaseLock);
+
+ return RetPtr;
+
+}
+
+/**
+ Register the callback function for a PCD entry.
+
+ This routine will register a callback function to a PCD entry by given token number
+ and token space guid.
+
+ @param TokenNumber PCD token's number, it is autogened by build tools.
+ @param Guid PCD token space's guid,
+ if not NULL, this PCD is dynamicEx type PCD.
+ @param CallBackFunction Callback function pointer
+
+ @return EFI_SUCCESS Always success for registering callback function.
+
+**/
+EFI_STATUS
+DxeRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+)
+{
+ CALLBACK_FN_ENTRY *FnTableEntry;
+ LIST_ENTRY *ListHead;
+ LIST_ENTRY *ListNode;
+
+ if (Guid != NULL) {
+ TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index of mCallbackFnTable[].
+ //
+ ListHead = &mCallbackFnTable[TokenNumber - 1];
+ ListNode = GetFirstNode (ListHead);
+
+ while (ListNode != ListHead) {
+ FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
+
+ if (FnTableEntry->CallbackFn == CallBackFunction) {
+ //
+ // We only allow a Callback function to be register once
+ // for a TokenNumber. So just return EFI_SUCCESS
+ //
+ return EFI_SUCCESS;
+ }
+ ListNode = GetNextNode (ListHead, ListNode);
+ }
+
+ FnTableEntry = AllocatePool (sizeof(CALLBACK_FN_ENTRY));
+ ASSERT (FnTableEntry != NULL);
+
+ FnTableEntry->CallbackFn = CallBackFunction;
+ InsertTailList (ListHead, &FnTableEntry->Node);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ UnRegister the callback function for a PCD entry.
+
+ This routine will unregister a callback function to a PCD entry by given token number
+ and token space guid.
+
+ @param TokenNumber PCD token's number, it is autogened by build tools.
+ @param Guid PCD token space's guid.
+ if not NULL, this PCD is dynamicEx type PCD.
+ @param CallBackFunction Callback function pointer
+
+ @retval EFI_SUCCESS Callback function is success to be unregister.
+ @retval EFI_INVALID_PARAMETER Can not find the PCD entry by given token number.
+**/
+EFI_STATUS
+DxeUnRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+)
+{
+ CALLBACK_FN_ENTRY *FnTableEntry;
+ LIST_ENTRY *ListHead;
+ LIST_ENTRY *ListNode;
+
+ if (Guid != NULL) {
+ TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index of mCallbackFnTable[].
+ //
+ ListHead = &mCallbackFnTable[TokenNumber - 1];
+ ListNode = GetFirstNode (ListHead);
+
+ while (ListNode != ListHead) {
+ FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
+
+ if (FnTableEntry->CallbackFn == CallBackFunction) {
+ //
+ // We only allow a Callback function to be register once
+ // for a TokenNumber. So we can safely remove the Node from
+ // the Link List and return EFI_SUCCESS.
+ //
+ RemoveEntryList (ListNode);
+ FreePool (FnTableEntry);
+
+ return EFI_SUCCESS;
+ }
+ ListNode = GetNextNode (ListHead, ListNode);
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Get next token number in given token space.
+
+ This routine is used for dynamicEx type PCD. It will firstly scan token space
+ table to get token space according to given token space guid. Then scan given
+ token number in found token space, if found, then return next token number in
+ this token space.
+
+ @param Guid Token space guid. Next token number will be scaned in
+ this token space.
+ @param TokenNumber Token number.
+ If PCD_INVALID_TOKEN_NUMBER, return first token number in
+ token space table.
+ If not PCD_INVALID_TOKEN_NUMBER, return next token number
+ in token space table.
+ @param GuidTable Token space guid table. It will be used for scan token space
+ by given token space guid.
+ @param SizeOfGuidTable The size of guid table.
+ @param ExMapTable DynamicEx token number mapping table.
+ @param SizeOfExMapTable The size of dynamicEx token number mapping table.
+
+ @retval EFI_NOT_FOUND Can not given token space or token number.
+ @retval EFI_SUCCESS Success to get next token number.
+
+**/
+EFI_STATUS
+ExGetNextTokeNumber (
+ IN CONST EFI_GUID *Guid,
+ IN OUT UINTN *TokenNumber,
+ IN EFI_GUID *GuidTable,
+ IN UINTN SizeOfGuidTable,
+ IN DYNAMICEX_MAPPING *ExMapTable,
+ IN UINTN SizeOfExMapTable
+ )
+{
+ EFI_GUID *MatchGuid;
+ UINTN Index;
+ UINTN GuidTableIdx;
+ BOOLEAN Found;
+ UINTN ExMapTableCount;
+
+ //
+ // Scan token space guid
+ //
+ MatchGuid = ScanGuid (GuidTable, SizeOfGuidTable, Guid);
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the token space table in dynamicEx mapping table.
+ //
+ Found = FALSE;
+ GuidTableIdx = MatchGuid - GuidTable;
+ ExMapTableCount = SizeOfExMapTable / sizeof(ExMapTable[0]);
+ for (Index = 0; Index < ExMapTableCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ //
+ // If given token number is PCD_INVALID_TOKEN_NUMBER, then return the first
+ // token number in found token space.
+ //
+ if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+
+ for ( ; Index < ExMapTableCount; Index++) {
+ if ((ExMapTable[Index].ExTokenNumber == *TokenNumber) && (ExMapTable[Index].ExGuidIndex == GuidTableIdx)) {
+ break;
+ }
+ }
+
+ while (Index < ExMapTableCount) {
+ Index++;
+ if (Index == ExMapTableCount) {
+ //
+ // Exceed the length of ExMap Table
+ //
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ } else if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ //
+ // Found the next match
+ //
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find the PCD database.
+
+ @retval The base address of external PCD database binary.
+ @retval NULL Return NULL if not find.
+**/
+DXE_PCD_DATABASE *
+LocateExPcdBinary (
+ VOID
+)
+{
+ EFI_STATUS Status;
+
+ //
+ // Search the External Pcd database from one section of current FFS,
+ // and read it to memory
+ //
+ Status = GetSectionFromFfs (
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **) &mDxePcdDbBinary,
+ &mDxePcdDbSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check the first bytes (Header Signature Guid) and build version.
+ //
+ if (!CompareGuid ((VOID *)mDxePcdDbBinary, &gPcdDataBaseSignatureGuid) ||
+ (mDxePcdDbBinary->BuildVersion != PCD_SERVICE_DXE_VERSION)) {
+ ASSERT (FALSE);
+ }
+
+ return mDxePcdDbBinary;
+}
+
+/**
+ Update PCD database base on current SkuId
+
+ @param SkuId Current SkuId
+ @param IsPeiDb Whether to update PEI PCD database.
+
+ @retval EFI_SUCCESS Update PCD database successfully.
+ @retval EFI_NOT_FOUND Not found PCD database for current SkuId.
+**/
+EFI_STATUS
+UpdatePcdDatabase (
+ IN SKU_ID SkuId,
+ IN BOOLEAN IsPeiDb
+ )
+{
+ UINTN Index;
+ PCD_DATABASE_SKU_DELTA *SkuDelta;
+ PCD_DATA_DELTA *SkuDeltaData;
+
+ if (IsPeiDb && mPeiPcdDbBinary != NULL) {
+ //
+ // Find the delta data for PEI DB
+ //
+ Index = (mPcdDatabase.PeiDb->Length + 7) & (~7);
+ SkuDelta = NULL;
+ while (Index < mPeiPcdDbSize) {
+ SkuDelta = (PCD_DATABASE_SKU_DELTA *) ((UINT8 *) mPeiPcdDbBinary + Index);
+ if (SkuDelta->SkuId == SkuId && SkuDelta->SkuIdCompared == 0) {
+ break;
+ }
+ Index = (Index + SkuDelta->Length + 7) & (~7);
+ }
+
+ //
+ // Patch the delta data into current PCD database
+ //
+ if (Index < mPeiPcdDbSize && SkuDelta != NULL) {
+ SkuDeltaData = (PCD_DATA_DELTA *) (SkuDelta + 1);
+ while ((UINT8 *) SkuDeltaData < (UINT8 *) SkuDelta + SkuDelta->Length) {
+ *((UINT8 *) mPcdDatabase.PeiDb + SkuDeltaData->Offset) = (UINT8) SkuDeltaData->Value;
+ SkuDeltaData ++;
+ }
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Find the delta data for DXE DB
+ //
+ Index = (mPcdDatabase.DxeDb->Length + 7) & (~7);
+ SkuDelta = NULL;
+ while (Index < mDxePcdDbSize) {
+ SkuDelta = (PCD_DATABASE_SKU_DELTA *) ((UINT8 *) mDxePcdDbBinary + Index);
+ if (SkuDelta->SkuId == SkuId && SkuDelta->SkuIdCompared == 0) {
+ break;
+ }
+ Index = (Index + SkuDelta->Length + 7) & (~7);
+ }
+
+ //
+ // Patch the delta data into current PCD database
+ //
+ if (Index < mDxePcdDbSize && SkuDelta != NULL) {
+ SkuDeltaData = (PCD_DATA_DELTA *) (SkuDelta + 1);
+ while ((UINT8 *) SkuDeltaData < (UINT8 *) SkuDelta + SkuDelta->Length) {
+ *((UINT8 *) mPcdDatabase.DxeDb + SkuDeltaData->Offset) = (UINT8) SkuDeltaData->Value;
+ SkuDeltaData ++;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Initialize the PCD database in DXE phase.
+
+ PCD database in DXE phase also contains PCD database in PEI phase which is copied
+ from GUID Hob.
+
+**/
+VOID
+BuildPcdDxeDataBase (
+ VOID
+ )
+{
+ PEI_PCD_DATABASE *PeiDatabase;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN Index;
+ UINT32 PcdDxeDbLen;
+ VOID *PcdDxeDb;
+ EFI_STATUS Status;
+
+ //
+ // Assign PCD Entries with default value to PCD DATABASE
+ //
+ mPcdDatabase.DxeDb = LocateExPcdBinary ();
+ ASSERT(mPcdDatabase.DxeDb != NULL);
+ PcdDxeDbLen = mPcdDatabase.DxeDb->Length + mPcdDatabase.DxeDb->UninitDataBaseSize;
+ PcdDxeDb = AllocateZeroPool (PcdDxeDbLen);
+ ASSERT (PcdDxeDb != NULL);
+ CopyMem (PcdDxeDb, mPcdDatabase.DxeDb, mPcdDatabase.DxeDb->Length);
+ mPcdDatabase.DxeDb = PcdDxeDb;
+
+ GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
+ if (GuidHob != NULL) {
+
+ //
+ // If no PEIMs use dynamic Pcd Entry, the Pcd Service PEIM
+ // should not be included at all. So the GuidHob could
+ // be NULL. If it is NULL, we just copy over the DXE Default
+ // Value to PCD Database.
+ //
+ PeiDatabase = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
+
+ //
+ // Get next one that stores full PEI data
+ //
+ GuidHob = GetNextGuidHob (&gPcdDataBaseHobGuid, GET_NEXT_HOB (GuidHob));
+ if (GuidHob != NULL) {
+ mPeiPcdDbBinary = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
+ mPeiPcdDbSize = (UINTN) GET_GUID_HOB_DATA_SIZE (GuidHob);
+ }
+
+ //
+ // Assign PCD Entries refereneced in PEI phase to PCD DATABASE
+ //
+ mPcdDatabase.PeiDb = PeiDatabase;
+ //
+ // Inherit the SystemSkuId from PEI phase.
+ //
+ if (mPcdDatabase.PeiDb->SystemSkuId != 0) {
+ Status = UpdatePcdDatabase (mPcdDatabase.PeiDb->SystemSkuId, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ }
+ mPcdDatabase.DxeDb->SystemSkuId = mPcdDatabase.PeiDb->SystemSkuId;
+ } else {
+ mPcdDatabase.PeiDb = AllocateZeroPool (sizeof (PEI_PCD_DATABASE));
+ ASSERT(mPcdDatabase.PeiDb != NULL);
+ }
+
+ //
+ // Initialized the external PCD database local variables
+ //
+ mPeiLocalTokenCount = mPcdDatabase.PeiDb->LocalTokenCount;
+ mDxeLocalTokenCount = mPcdDatabase.DxeDb->LocalTokenCount;
+
+ mPeiExMapppingTableSize = mPcdDatabase.PeiDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
+ mDxeExMapppingTableSize = mPcdDatabase.DxeDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
+ mPeiGuidTableSize = mPcdDatabase.PeiDb->GuidTableCount * sizeof(GUID);
+ mDxeGuidTableSize = mPcdDatabase.DxeDb->GuidTableCount * sizeof (GUID);
+
+ mPcdTotalTokenCount = mPeiLocalTokenCount + mDxeLocalTokenCount;
+ mPeiNexTokenCount = mPeiLocalTokenCount - mPcdDatabase.PeiDb->ExTokenCount;
+ mDxeNexTokenCount = mDxeLocalTokenCount - mPcdDatabase.DxeDb->ExTokenCount;
+
+ mPeiExMapTableEmpty = (mPcdDatabase.PeiDb->ExTokenCount == 0) ? TRUE : FALSE;
+ mDxeExMapTableEmpty = (mPcdDatabase.DxeDb->ExTokenCount == 0) ? TRUE : FALSE;
+ mPeiDatabaseEmpty = (mPeiLocalTokenCount == 0) ? TRUE : FALSE;
+
+ TmpTokenSpaceBufferCount = mPcdDatabase.PeiDb->ExTokenCount + mPcdDatabase.DxeDb->ExTokenCount;
+ TmpTokenSpaceBuffer = (EFI_GUID **)AllocateZeroPool(TmpTokenSpaceBufferCount * sizeof (EFI_GUID *));
+
+ //
+ // Initialized the Callback Function Table
+ //
+ mCallbackFnTable = AllocateZeroPool (mPcdTotalTokenCount * sizeof (LIST_ENTRY));
+ ASSERT(mCallbackFnTable != NULL);
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ for (Index = 0; Index + 1 < mPcdTotalTokenCount + 1; Index++) {
+ InitializeListHead (&mCallbackFnTable[Index]);
+ }
+}
+
+/**
+ Get Variable which contains HII type PCD entry.
+
+ @param VariableGuid Variable's guid
+ @param VariableName Variable's unicode name string
+ @param VariableData Variable's data pointer,
+ @param VariableSize Variable's size.
+
+ @return the status of gRT->GetVariable
+**/
+EFI_STATUS
+GetHiiVariable (
+ IN EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ OUT UINT8 **VariableData,
+ OUT UINTN *VariableSize
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+
+ Size = 0;
+ Buffer = NULL;
+
+ //
+ // Firstly get the real size of HII variable
+ //
+ Status = gRT->GetVariable (
+ (UINT16 *)VariableName,
+ VariableGuid,
+ NULL,
+ &Size,
+ Buffer
+ );
+
+ //
+ // Allocate buffer to hold whole variable data according to variable size.
+ //
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Buffer = (UINT8 *) AllocatePool (Size);
+
+ ASSERT (Buffer != NULL);
+
+ Status = gRT->GetVariable (
+ VariableName,
+ VariableGuid,
+ NULL,
+ &Size,
+ Buffer
+ );
+
+ ASSERT (Status == EFI_SUCCESS);
+ *VariableData = Buffer;
+ *VariableSize = Size;
+ } else {
+ //
+ // Use Default Data only when variable is not found.
+ // For other error status, correct data can't be got, and trig ASSERT().
+ //
+ ASSERT (Status == EFI_NOT_FOUND);
+ }
+
+ return Status;
+}
+
+/**
+ Invoke the callback function when dynamic PCD entry was set, if this PCD entry
+ has registered callback function.
+
+ @param ExTokenNumber DynamicEx PCD's token number, if this PCD entry is dyanmicEx
+ type PCD.
+ @param Guid DynamicEx PCD's guid, if this PCD entry is dynamicEx type
+ PCD.
+ @param TokenNumber PCD token number generated by build tools.
+ @param Data Value want to be set for this PCD entry
+ @param Size The size of value
+
+**/
+VOID
+InvokeCallbackOnSet (
+ UINT32 ExTokenNumber,
+ CONST EFI_GUID *Guid, OPTIONAL
+ UINTN TokenNumber,
+ VOID *Data,
+ UINTN Size
+ )
+{
+ CALLBACK_FN_ENTRY *FnTableEntry;
+ LIST_ENTRY *ListHead;
+ LIST_ENTRY *ListNode;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index of mCallbackFnTable[].
+ //
+ ListHead = &mCallbackFnTable[TokenNumber - 1];
+ ListNode = GetFirstNode (ListHead);
+
+ while (ListNode != ListHead) {
+ FnTableEntry = CR_FNENTRY_FROM_LISTNODE (ListNode, CALLBACK_FN_ENTRY, Node);
+
+ FnTableEntry->CallbackFn(Guid,
+ (Guid == NULL) ? TokenNumber : ExTokenNumber,
+ Data,
+ Size);
+
+ ListNode = GetNextNode (ListHead, ListNode);
+ }
+
+ return;
+}
+
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ return SetWorker (TokenNumber, Data, &Size, FALSE);
+}
+
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ )
+{
+ BOOLEAN IsPeiDb;
+ UINT32 LocalTokenNumber;
+ EFI_GUID *GuidTable;
+ UINT8 *StringTable;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+ UINTN VariableOffset;
+ UINT32 Attributes;
+ VOID *InternalData;
+ VARIABLE_HEAD *VariableHead;
+ UINTN Offset;
+ UINT8 *PcdDb;
+ EFI_STATUS Status;
+ UINTN MaxSize;
+ UINTN TmpTokenNumber;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ TmpTokenNumber = TokenNumber;
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
+
+ if (PtrType) {
+ //
+ // Get MaxSize first, then check new size with max buffer size.
+ //
+ GetPtrTypeSize (TokenNumber, &MaxSize);
+ if (*Size > MaxSize) {
+ *Size = MaxSize;
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (*Size != DxePcdGetSize (TokenNumber + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ if ((TokenNumber + 1 < mPeiNexTokenCount + 1) ||
+ (TokenNumber + 1 >= mPeiLocalTokenCount + 1 && TokenNumber + 1 < (mPeiLocalTokenCount + mDxeNexTokenCount + 1))) {
+ InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
+ }
+
+ //
+ // Aquire lock to prevent reentrance from TPL_CALLBACK level
+ //
+ EfiAcquireLock (&mPcdDatabaseLock);
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
+
+ LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+
+ PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
+
+ if (IsPeiDb) {
+ StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
+ } else {
+ StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
+ }
+
+
+ InternalData = PcdDb + Offset;
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ ASSERT (FALSE);
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case PCD_TYPE_STRING:
+ if (SetPtrTypeSize (TmpTokenNumber, Size)) {
+ CopyMem (StringTable + *((STRING_HEAD *)InternalData), Data, *Size);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ break;
+
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ case PCD_TYPE_HII:
+ if (PtrType) {
+ if (!SetPtrTypeSize (TmpTokenNumber, Size)) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ if (IsPeiDb) {
+ GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
+ } else {
+ GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
+ }
+
+ VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
+
+ Guid = GuidTable + VariableHead->GuidTableIndex;
+ Name = (UINT16*) (StringTable + VariableHead->StringIndex);
+ VariableOffset = VariableHead->Offset;
+ Attributes = VariableHead->Attributes;
+ Status = SetHiiVariable (Guid, Name, Attributes, Data, *Size, VariableOffset);
+ break;
+
+ case PCD_TYPE_DATA:
+ if (PtrType) {
+ if (SetPtrTypeSize (TmpTokenNumber, Size)) {
+ CopyMem (InternalData, Data, *Size);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ Status = EFI_SUCCESS;
+ switch (*Size) {
+ case sizeof(UINT8):
+ *((UINT8 *) InternalData) = *((UINT8 *) Data);
+ break;
+
+ case sizeof(UINT16):
+ *((UINT16 *) InternalData) = *((UINT16 *) Data);
+ break;
+
+ case sizeof(UINT32):
+ *((UINT32 *) InternalData) = *((UINT32 *) Data);
+ break;
+
+ case sizeof(UINT64):
+ *((UINT64 *) InternalData) = *((UINT64 *) Data);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ EfiReleaseLock (&mPcdDatabaseLock);
+
+ return Status;
+}
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ )
+{
+ return GetWorker(GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber), GetSize);
+}
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN SetSize
+ )
+{
+ return ExSetWorker (ExTokenNumber, Guid, Data, &SetSize, FALSE);
+}
+
+/**
+ Set value for a dynamic-ex PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *SetSize,
+ IN BOOLEAN PtrType
+ )
+{
+ UINTN TokenNumber;
+
+ TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber);
+
+ InvokeCallbackOnSet ((UINT32) ExTokenNumber, Guid, TokenNumber, Data, *SetSize);
+
+ return SetWorker (TokenNumber, Data, SetSize, PtrType);
+
+}
+
+/**
+ Get variable size and data from HII-type PCDs.
+
+ @param[in] VariableGuid Guid of variable which stored value of a HII-type PCD.
+ @param[in] VariableName Unicode name of variable which stored value of a HII-type PCD.
+ @param[out] VariableSize Pointer to variable size got from HII-type PCDs.
+ @param[out] VariableData Pointer to variable data got from HII-type PCDs.
+
+**/
+VOID
+GetVariableSizeAndDataFromHiiPcd (
+ IN EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ OUT UINTN *VariableSize,
+ OUT VOID *VariableData OPTIONAL
+ )
+{
+ BOOLEAN IsPeiDb;
+ PCD_DATABASE_INIT *Database;
+ UINTN TokenNumber;
+ UINT32 LocalTokenNumber;
+ UINTN Offset;
+ EFI_GUID *GuidTable;
+ UINT8 *StringTable;
+ VARIABLE_HEAD *VariableHead;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+ UINTN PcdDataSize;
+ UINTN Size;
+ UINT8 *VaraiableDefaultBuffer;
+ STRING_HEAD StringTableIdx;
+
+ *VariableSize = 0;
+
+ //
+ // Go through PCD database to find out DynamicHii PCDs.
+ //
+ for (TokenNumber = 1; TokenNumber <= mPcdTotalTokenCount; TokenNumber++) {
+ IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
+ Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
+ LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber);
+ if ((LocalTokenNumber & PCD_TYPE_HII) != 0) {
+ //
+ // Get the Variable Guid and Name pointer.
+ //
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ VariableHead = (VARIABLE_HEAD *) ((UINT8 *) Database + Offset);
+ StringTable = (UINT8 *) ((UINT8 *) Database + Database->StringTableOffset);
+ GuidTable = (EFI_GUID *) ((UINT8 *) Database + Database->GuidTableOffset);
+ Guid = GuidTable + VariableHead->GuidTableIndex;
+ Name = (UINT16*) (StringTable + VariableHead->StringIndex);
+ if (CompareGuid (VariableGuid, Guid) && (StrCmp (VariableName, Name) == 0)) {
+ //
+ // It is the matched DynamicHii PCD.
+ //
+ PcdDataSize = DxePcdGetSize (TokenNumber);
+ Size = VariableHead->Offset + PcdDataSize;
+ if (Size > *VariableSize) {
+ *VariableSize = Size;
+ }
+ if (VariableData != NULL) {
+ if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
+ //
+ // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
+ // string array in string table.
+ //
+ StringTableIdx = *(STRING_HEAD *) ((UINT8 *) Database + VariableHead->DefaultValueOffset);
+ VaraiableDefaultBuffer = (UINT8 *) (StringTable + StringTableIdx);
+ } else {
+ VaraiableDefaultBuffer = (UINT8 *) Database + VariableHead->DefaultValueOffset;
+ }
+ CopyMem ((UINT8 *) VariableData + VariableHead->Offset, VaraiableDefaultBuffer, PcdDataSize);
+ }
+ }
+ }
+ }
+}
+
+/**
+ Set value for HII-type PCD.
+
+ A HII-type PCD's value is stored in a variable. Setting/Getting the value of
+ HII-type PCD is to visit this variable.
+
+ @param VariableGuid Guid of variable which stored value of a HII-type PCD.
+ @param VariableName Unicode name of variable which stored value of a HII-type PCD.
+ @param SetAttributes Attributes bitmask to set for the variable.
+ @param Data Value want to be set.
+ @param DataSize Size of value
+ @param Offset Value offset of HII-type PCD in variable.
+
+ @return status of GetVariable()/SetVariable().
+
+**/
+EFI_STATUS
+SetHiiVariable (
+ IN EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ IN UINT32 SetAttributes,
+ IN CONST VOID *Data,
+ IN UINTN DataSize,
+ IN UINTN Offset
+ )
+{
+ UINTN Size;
+ VOID *Buffer;
+ EFI_STATUS Status;
+ UINT32 Attribute;
+ UINTN SetSize;
+
+ Size = 0;
+ SetSize = 0;
+
+ //
+ // Try to get original variable size information.
+ //
+ Status = gRT->GetVariable (
+ (UINT16 *)VariableName,
+ VariableGuid,
+ NULL,
+ &Size,
+ NULL
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Patch new PCD's value to offset in given HII variable.
+ //
+ if (Size >= (DataSize + Offset)) {
+ SetSize = Size;
+ } else {
+ SetSize = DataSize + Offset;
+ }
+ Buffer = AllocatePool (SetSize);
+ ASSERT (Buffer != NULL);
+
+ Status = gRT->GetVariable (
+ VariableName,
+ VariableGuid,
+ &Attribute,
+ &Size,
+ Buffer
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
+
+ if (SetAttributes == 0) {
+ SetAttributes = Attribute;
+ }
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VariableGuid,
+ SetAttributes,
+ SetSize,
+ Buffer
+ );
+
+ FreePool (Buffer);
+ return Status;
+ } else if (Status == EFI_NOT_FOUND) {
+ //
+ // If variable does not exist, a new variable need to be created.
+ //
+
+ //
+ // Get size, allocate buffer and get data.
+ //
+ GetVariableSizeAndDataFromHiiPcd (VariableGuid, VariableName, &Size, NULL);
+ Buffer = AllocateZeroPool (Size);
+ ASSERT (Buffer != NULL);
+ GetVariableSizeAndDataFromHiiPcd (VariableGuid, VariableName, &Size, Buffer);
+
+ //
+ // Update buffer.
+ //
+ CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
+
+ if (SetAttributes == 0) {
+ SetAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+ }
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VariableGuid,
+ SetAttributes,
+ Size,
+ Buffer
+ );
+
+ FreePool (Buffer);
+ return Status;
+ }
+
+ //
+ // If we drop to here, the value is failed to be written in to variable area.
+ //
+ return Status;
+}
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Dynamic-ex PCD token number.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINT32 ExTokenNumber
+ )
+{
+ UINT32 Index;
+ DYNAMICEX_MAPPING *ExMap;
+ EFI_GUID *GuidTable;
+ EFI_GUID *MatchGuid;
+ UINTN MatchGuidIdx;
+
+ if (!mPeiDatabaseEmpty) {
+ ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
+
+ MatchGuid = ScanGuid (GuidTable, mPeiGuidTableSize, Guid);
+
+ if (MatchGuid != NULL) {
+
+ MatchGuidIdx = MatchGuid - GuidTable;
+
+ for (Index = 0; Index < mPcdDatabase.PeiDb->ExTokenCount; Index++) {
+ if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
+ (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
+ return ExMap[Index].TokenNumber;
+ }
+ }
+ }
+ }
+
+ ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
+
+ MatchGuid = ScanGuid (GuidTable, mDxeGuidTableSize, Guid);
+ //
+ // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
+ // error in the BUILD system.
+ //
+ ASSERT (MatchGuid != NULL);
+
+ MatchGuidIdx = MatchGuid - GuidTable;
+
+ for (Index = 0; Index < mPcdDatabase.DxeDb->ExTokenCount; Index++) {
+ if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
+ (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
+ return ExMap[Index].TokenNumber;
+ }
+ }
+
+ ASSERT (FALSE);
+
+ return 0;
+}
+
+/**
+ Wrapper function of getting index of PCD entry in size table.
+
+ @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
+ @param IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
+ If FALSE, the pcd entry is initialized in DXE phase.
+
+ @return index of PCD entry in size table.
+**/
+UINTN
+GetSizeTableIndex (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN BOOLEAN IsPeiDb
+ )
+{
+ UINT32 *LocalTokenNumberTable;
+ UINTN LocalTokenNumber;
+ UINTN Index;
+ UINTN SizeTableIdx;
+
+ if (IsPeiDb) {
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
+ } else {
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
+ }
+
+ SizeTableIdx = 0;
+
+ for (Index = 0; Index < LocalTokenNumberTableIdx; Index ++) {
+ LocalTokenNumber = LocalTokenNumberTable[Index];
+
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // Current size is equal to MAX size.
+ //
+ SizeTableIdx += 2;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTableIdx += 2;
+ }
+ }
+
+ }
+
+ return SizeTableIdx;
+}
+
+/**
+ Get size of POINTER type PCD value.
+
+ @param LocalTokenNumberTableIdx Index of local token number in local token number table.
+ @param MaxSize Maxmium size of POINTER type PCD value.
+
+ @return size of POINTER type PCD value.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+ BOOLEAN IsPeiDb;
+ UINT32 *LocalTokenNumberTable;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
+
+
+ if (IsPeiDb) {
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
+ SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
+ } else {
+ LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
+ SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
+ }
+
+ LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
+
+ *MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // We consider current size is equal to MAX size.
+ //
+ return *MaxSize;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ return SizeTable[SizeTableIdx + 1];
+ }
+}
+
+/**
+ Set size of POINTER type PCD value. The size should not exceed the maximum size
+ of this PCD value.
+
+ @param LocalTokenNumberTableIdx Index of local token number in local token number table.
+ @param CurrentSize Size of POINTER type PCD value.
+
+ @retval TRUE Success to set size of PCD value.
+ @retval FALSE Fail to set size of PCD value.
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+ UINTN MaxSize;
+ BOOLEAN IsPeiDb;
+ UINT32 *LocalTokenNumberTable;
+
+ //
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ //
+ IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
+
+ if (IsPeiDb) {
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
+ SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
+ } else {
+ LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
+ LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
+ SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
+ }
+
+ LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
+
+ MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We shouldn't come here as we don't support SET for VPD
+ //
+ ASSERT (FALSE);
+ return FALSE;
+ } else {
+ if ((*CurrentSize > MaxSize) ||
+ (*CurrentSize == MAX_ADDRESS)) {
+ *CurrentSize = MaxSize;
+ return FALSE;
+ }
+
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
+ return TRUE;
+ }
+}
+
+/**
+ VariableLock DynamicHiiPcd.
+
+ @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
+ If FALSE, the pcd entry is initialized in DXE phase.
+ @param[in] VariableLock Pointer to VariableLockProtocol.
+
+**/
+VOID
+VariableLockDynamicHiiPcd (
+ IN BOOLEAN IsPeiDb,
+ IN EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock
+ )
+{
+ EFI_STATUS Status;
+ PCD_DATABASE_INIT *Database;
+ UINT32 LocalTokenCount;
+ UINTN TokenNumber;
+ UINT32 LocalTokenNumber;
+ UINTN Offset;
+ EFI_GUID *GuidTable;
+ UINT8 *StringTable;
+ VARIABLE_HEAD *VariableHead;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+
+ Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
+ LocalTokenCount = IsPeiDb ? mPeiLocalTokenCount: mDxeLocalTokenCount;
+
+ //
+ // Go through PCD database to find out DynamicHii PCDs.
+ //
+ for (TokenNumber = 1; TokenNumber <= LocalTokenCount; TokenNumber++) {
+ if (IsPeiDb) {
+ LocalTokenNumber = GetLocalTokenNumber (TRUE, TokenNumber);
+ } else {
+ LocalTokenNumber = GetLocalTokenNumber (FALSE, TokenNumber + mPeiLocalTokenCount);
+ }
+ if ((LocalTokenNumber & PCD_TYPE_HII) != 0) {
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ VariableHead = (VARIABLE_HEAD *) ((UINT8 *) Database + Offset);
+ //
+ // Why not to set property by VarCheckProtocol with Attributes and Property directly here?
+ // It is because that set property by VarCheckProtocol will indicate the variable to
+ // be a system variable, but the unknown max size of the variable is dangerous to
+ // the system variable region.
+ //
+ if ((VariableHead->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0) {
+ //
+ // DynamicHii PCD with RO property set in *.dsc.
+ //
+ StringTable = (UINT8 *) ((UINT8 *) Database + Database->StringTableOffset);
+ GuidTable = (EFI_GUID *) ((UINT8 *) Database + Database->GuidTableOffset);
+ Guid = GuidTable + VariableHead->GuidTableIndex;
+ Name = (UINT16*) (StringTable + VariableHead->StringIndex);
+ Status = VariableLock->RequestToLock (VariableLock, Name, Guid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
+
+/**
+ VariableLockProtocol callback
+ to lock the variables referenced by DynamicHii PCDs with RO property set in *.dsc.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableLockCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ if (!EFI_ERROR (Status)) {
+ VariableLockDynamicHiiPcd (TRUE, VariableLock);
+ VariableLockDynamicHiiPcd (FALSE, VariableLock);
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.h b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.h
new file mode 100644
index 000000000..6109458ca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Dxe/Service.h
@@ -0,0 +1,1195 @@
+/** @file
+Private functions used by PCD DXE driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCD_DXE_SERVICE_H_
+#define _PCD_DXE_SERVICE_H_
+
+#include <PiDxe.h>
+#include <Guid/PcdDataBaseHobGuid.h>
+#include <Guid/PcdDataBaseSignatureGuid.h>
+#include <Protocol/Pcd.h>
+#include <Protocol/PiPcd.h>
+#include <Protocol/PcdInfo.h>
+#include <Protocol/PiPcdInfo.h>
+#include <Protocol/VarCheck.h>
+#include <Protocol/VariableLock.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// Please make sure the PCD Serivce DXE Version is consistent with
+// the version of the generated DXE PCD Database by build tool.
+//
+#define PCD_SERVICE_DXE_VERSION 7
+
+//
+// PCD_DXE_SERVICE_DRIVER_VERSION is defined in Autogen.h.
+//
+#if (PCD_SERVICE_DXE_VERSION != PCD_DXE_SERVICE_DRIVER_VERSION)
+ #error "Please make sure the version of PCD DXE Service and the generated PCD DXE Database match."
+#endif
+
+extern UINTN mVpdBaseAddress;
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+DxeGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+DxeGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+DxeGetPcdInfoGetSku (
+ VOID
+ );
+
+//
+// Protocol Interface function declaration.
+//
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default. The valid SkuId range is 1 to 255.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+DxePcdSetSku (
+ IN UINTN SkuId
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+DxePcdGet8 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+DxePcdGet16 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+DxePcdGet32 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+DxePcdGet64 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+DxePcdGetPtr (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+DxePcdGetBool (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+DxePcdGetSize (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+DxePcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+DxePcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+DxePcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+DxePcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+DxePcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+DxePcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+DxePcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ );
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ );
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to retrieve the next token.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request is
+ being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber
+ A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service retrieved the next valid token number. Or the input token number
+ is already the last valid token number in the PCD database.
+ In the later case, *TokenNumber is updated with the value of 0.
+ @retval EFI_NOT_FOUND If this input token number and token namespace does not exist on the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+DxePcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ );
+
+/**
+ Get next token space in PCD database according to given token space guid.
+
+ @param Guid Given token space guid. If NULL, then Guid will be set to
+ the first PCD token space in PCD database, If not NULL, then
+ Guid will be set to next PCD token space.
+
+ @retval EFI_NOT_FOUND If PCD database has no token space table or can not find given
+ token space in PCD database.
+ @retval EFI_SUCCESS Success to get next token space guid.
+**/
+EFI_STATUS
+EFIAPI
+DxePcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ );
+
+typedef struct {
+ LIST_ENTRY Node;
+ PCD_PROTOCOL_CALLBACK CallbackFn;
+} CALLBACK_FN_ENTRY;
+
+#define CR_FNENTRY_FROM_LISTNODE(Record, Type, Field) BASE_CR(Record, Type, Field)
+
+//
+// Internal Functions
+//
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+DxeGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ );
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN SetSize
+ );
+
+/**
+ Set value for a dynamic PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ );
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ );
+
+/**
+ Get Variable which contains HII type PCD entry.
+
+ @param VariableGuid Variable's guid
+ @param VariableName Variable's unicode name string
+ @param VariableData Variable's data pointer,
+ @param VariableSize Variable's size.
+
+ @return the status of gRT->GetVariable
+**/
+EFI_STATUS
+GetHiiVariable (
+ IN EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ OUT UINT8 **VariableData,
+ OUT UINTN *VariableSize
+ );
+
+/**
+ Set value for HII-type PCD.
+
+ A HII-type PCD's value is stored in a variable. Setting/Getting the value of
+ HII-type PCD is to visit this variable.
+
+ @param VariableGuid Guid of variable which stored value of a HII-type PCD.
+ @param VariableName Unicode name of variable which stored value of a HII-type PCD.
+ @param SetAttributes Attributes bitmask to set for the variable.
+ @param Data Value want to be set.
+ @param DataSize Size of value
+ @param Offset Value offset of HII-type PCD in variable.
+
+ @return status of GetVariable()/SetVariable().
+
+**/
+EFI_STATUS
+SetHiiVariable (
+ IN EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ IN UINT32 SetAttributes,
+ IN CONST VOID *Data,
+ IN UINTN DataSize,
+ IN UINTN Offset
+ );
+
+/**
+ Register the callback function for a PCD entry.
+
+ This routine will register a callback function to a PCD entry by given token number
+ and token space guid.
+
+ @param TokenNumber PCD token's number, it is autogened by build tools.
+ @param Guid PCD token space's guid,
+ if not NULL, this PCD is dynamicEx type PCD.
+ @param CallBackFunction Callback function pointer
+
+ @return EFI_SUCCESS Always success for registering callback function.
+
+**/
+EFI_STATUS
+DxeRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ );
+
+/**
+ UnRegister the callback function for a PCD entry.
+
+ This routine will unregister a callback function to a PCD entry by given token number
+ and token space guid.
+
+ @param TokenNumber PCD token's number, it is autogened by build tools.
+ @param Guid PCD token space's guid.
+ if not NULL, this PCD is dynamicEx type PCD.
+ @param CallBackFunction Callback function pointer
+
+ @retval EFI_SUCCESS Callback function is success to be unregister.
+ @retval EFI_INVALID_PARAMETER Can not find the PCD entry by given token number.
+**/
+EFI_STATUS
+DxeUnRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PROTOCOL_CALLBACK CallBackFunction
+ );
+
+/**
+ Initialize the PCD database in DXE phase.
+
+ PCD database in DXE phase also contains PCD database in PEI phase which is copied
+ from GUID Hob.
+
+**/
+VOID
+BuildPcdDxeDataBase (
+ VOID
+ );
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Dynamic-ex PCD token number.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINT32 ExTokenNumber
+ );
+
+/**
+ Get next token number in given token space.
+
+ This routine is used for dynamicEx type PCD. It will firstly scan token space
+ table to get token space according to given token space guid. Then scan given
+ token number in found token space, if found, then return next token number in
+ this token space.
+
+ @param Guid Token space guid. Next token number will be scaned in
+ this token space.
+ @param TokenNumber Token number.
+ If PCD_INVALID_TOKEN_NUMBER, return first token number in
+ token space table.
+ If not PCD_INVALID_TOKEN_NUMBER, return next token number
+ in token space table.
+ @param GuidTable Token space guid table. It will be used for scan token space
+ by given token space guid.
+ @param SizeOfGuidTable The size of guid table.
+ @param ExMapTable DynamicEx token number mapping table.
+ @param SizeOfExMapTable The size of dynamicEx token number mapping table.
+
+ @retval EFI_NOT_FOUND Can not given token space or token number.
+ @retval EFI_SUCCESS Success to get next token number.
+
+**/
+EFI_STATUS
+ExGetNextTokeNumber (
+ IN CONST EFI_GUID *Guid,
+ IN OUT UINTN *TokenNumber,
+ IN EFI_GUID *GuidTable,
+ IN UINTN SizeOfGuidTable,
+ IN DYNAMICEX_MAPPING *ExMapTable,
+ IN UINTN SizeOfExMapTable
+ );
+
+/**
+ Get size of POINTER type PCD value.
+
+ @param LocalTokenNumberTableIdx Index of local token number in local token number table.
+ @param MaxSize Maximum size of POINTER type PCD value.
+
+ @return size of POINTER type PCD value.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize
+ );
+
+/**
+ Set size of POINTER type PCD value. The size should not exceed the maximum size
+ of this PCD value.
+
+ @param LocalTokenNumberTableIdx Index of local token number in local token number table.
+ @param CurrentSize Size of POINTER type PCD value.
+
+ @retval TRUE Success to set size of PCD value.
+ @retval FALSE Fail to set size of PCD value.
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize
+ );
+
+/**
+ VariableLockProtocol callback
+ to lock the variables referenced by DynamicHii PCDs with RO property set in *.dsc.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableLockCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Update PCD database base on current SkuId
+
+ @param SkuId Current SkuId
+ @param IsPeiDb Whether to update PEI PCD database.
+
+ @retval EFI_SUCCESS Update PCD database successfully.
+ @retval EFI_NOT_FOUND Not found PCD database for current SkuId.
+**/
+EFI_STATUS
+UpdatePcdDatabase (
+ IN SKU_ID SkuId,
+ IN BOOLEAN IsPeiDb
+ );
+
+extern PCD_DATABASE mPcdDatabase;
+
+extern UINT32 mPcdTotalTokenCount;
+extern UINT32 mPeiLocalTokenCount;
+extern UINT32 mDxeLocalTokenCount;
+extern UINT32 mPeiNexTokenCount;
+extern UINT32 mDxeNexTokenCount;
+extern UINT32 mPeiExMapppingTableSize;
+extern UINT32 mDxeExMapppingTableSize;
+extern UINT32 mPeiGuidTableSize;
+extern UINT32 mDxeGuidTableSize;
+
+extern BOOLEAN mPeiExMapTableEmpty;
+extern BOOLEAN mDxeExMapTableEmpty;
+extern BOOLEAN mPeiDatabaseEmpty;
+
+extern EFI_GUID **TmpTokenSpaceBuffer;
+extern UINTN TmpTokenSpaceBufferCount;
+
+extern EFI_LOCK mPcdDatabaseLock;
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.c b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.c
new file mode 100644
index 000000000..9c6346924
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.c
@@ -0,0 +1,1672 @@
+/** @file
+ All Pcd Ppi services are implemented here.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Service.h"
+
+///
+/// Instance of PCD_PPI protocol is EDKII native implementation.
+/// This protocol instance support dynamic and dynamicEx type PCDs.
+///
+PCD_PPI mPcdPpiInstance = {
+ PeiPcdSetSku,
+
+ PeiPcdGet8,
+ PeiPcdGet16,
+ PeiPcdGet32,
+ PeiPcdGet64,
+ PeiPcdGetPtr,
+ PeiPcdGetBool,
+ PeiPcdGetSize,
+
+ PeiPcdGet8Ex,
+ PeiPcdGet16Ex,
+ PeiPcdGet32Ex,
+ PeiPcdGet64Ex,
+ PeiPcdGetPtrEx,
+ PeiPcdGetBoolEx,
+ PeiPcdGetSizeEx,
+
+ PeiPcdSet8,
+ PeiPcdSet16,
+ PeiPcdSet32,
+ PeiPcdSet64,
+ PeiPcdSetPtr,
+ PeiPcdSetBool,
+
+ PeiPcdSet8Ex,
+ PeiPcdSet16Ex,
+ PeiPcdSet32Ex,
+ PeiPcdSet64Ex,
+ PeiPcdSetPtrEx,
+ PeiPcdSetBoolEx,
+
+ PeiRegisterCallBackOnSet,
+ PcdUnRegisterCallBackOnSet,
+ PeiPcdGetNextToken,
+ PeiPcdGetNextTokenSpace
+};
+
+///
+/// Instance of EFI_PEI_PCD_PPI which is defined in PI 1.2 Vol 3.
+/// This PPI instance only support dyanmicEx type PCD.
+///
+EFI_PEI_PCD_PPI mEfiPcdPpiInstance = {
+ PeiPcdSetSku,
+
+ PeiPcdGet8Ex,
+ PeiPcdGet16Ex,
+ PeiPcdGet32Ex,
+ PeiPcdGet64Ex,
+ PeiPcdGetPtrEx,
+ PeiPcdGetBoolEx,
+ PeiPcdGetSizeEx,
+ PeiPcdSet8Ex,
+ PeiPcdSet16Ex,
+ PeiPcdSet32Ex,
+ PeiPcdSet64Ex,
+ PeiPcdSetPtrEx,
+ PeiPcdSetBoolEx,
+ (EFI_PEI_PCD_PPI_CALLBACK_ON_SET) PeiRegisterCallBackOnSet,
+ (EFI_PEI_PCD_PPI_CANCEL_CALLBACK) PcdUnRegisterCallBackOnSet,
+ PeiPcdGetNextToken,
+ PeiPcdGetNextTokenSpace
+};
+
+///
+/// Instance of GET_PCD_INFO_PPI protocol is EDKII native implementation.
+/// This protocol instance support dynamic and dynamicEx type PCDs.
+///
+GET_PCD_INFO_PPI mGetPcdInfoInstance = {
+ PeiGetPcdInfoGetInfo,
+ PeiGetPcdInfoGetInfoEx,
+ PeiGetPcdInfoGetSku
+};
+
+///
+/// Instance of EFI_GET_PCD_INFO_PPI which is defined in PI 1.2.1 Vol 3.
+/// This PPI instance only support dyanmicEx type PCD.
+///
+EFI_GET_PCD_INFO_PPI mEfiGetPcdInfoInstance = {
+ PeiGetPcdInfoGetInfoEx,
+ PeiGetPcdInfoGetSku
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gPcdPpiGuid,
+ &mPcdPpiInstance
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiPcdPpiGuid,
+ &mEfiPcdPpiInstance
+ }
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList2[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gGetPcdInfoPpiGuid,
+ &mGetPcdInfoInstance
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiGetPcdInfoPpiGuid,
+ &mEfiGetPcdInfoInstance
+ }
+};
+
+/**
+ Callback on SET PcdSetNvStoreDefaultId
+
+ Once PcdSetNvStoreDefaultId is set, the default NV storage will be found from
+ PcdNvStoreDefaultValueBuffer, and built into VariableHob.
+
+ @param[in] CallBackGuid The PCD token GUID being set.
+ @param[in] CallBackToken The PCD token number being set.
+ @param[in, out] TokenData A pointer to the token data being set.
+ @param[in] TokenDataSize The size, in bytes, of the data being set.
+
+**/
+VOID
+EFIAPI
+PcdSetNvStoreDefaultIdCallBack (
+ IN CONST EFI_GUID *CallBackGuid, OPTIONAL
+ IN UINTN CallBackToken,
+ IN OUT VOID *TokenData,
+ IN UINTN TokenDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 DefaultId;
+ SKU_ID SkuId;
+ UINTN FullSize;
+ UINTN Index;
+ UINT8 *DataBuffer;
+ UINT8 *VarStoreHobData;
+ UINT8 *BufferEnd;
+ BOOLEAN IsFound;
+ VARIABLE_STORE_HEADER *NvStoreBuffer;
+ PCD_DEFAULT_DATA *DataHeader;
+ PCD_DEFAULT_INFO *DefaultInfo;
+ PCD_DATA_DELTA *DeltaData;
+
+ DefaultId = *(UINT16 *) TokenData;
+ SkuId = GetPcdDatabase()->SystemSkuId;
+ IsFound = FALSE;
+
+ if (PeiPcdGetSizeEx (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdNvStoreDefaultValueBuffer)) > sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+ DataBuffer = (UINT8 *) PeiPcdGetPtrEx (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdNvStoreDefaultValueBuffer));
+ FullSize = ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) DataBuffer)->Length;
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER));
+ //
+ // The first section data includes NV storage default setting.
+ //
+ NvStoreBuffer = (VARIABLE_STORE_HEADER *) ((UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize);
+ VarStoreHobData = (UINT8 *) BuildGuidHob (&NvStoreBuffer->Signature, NvStoreBuffer->Size);
+ ASSERT (VarStoreHobData != NULL);
+ CopyMem (VarStoreHobData, NvStoreBuffer, NvStoreBuffer->Size);
+ //
+ // Find the matched SkuId and DefaultId in the first section
+ //
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == SkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ //
+ // Find the matched SkuId and DefaultId in the remaining section
+ //
+ Index = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + ((DataHeader->DataSize + 7) & (~7));
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ while (!IsFound && Index < FullSize && DataHeader->DataSize != 0xFFFFFFFF) {
+ DefaultInfo = &(DataHeader->DefaultInfo[0]);
+ BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize;
+ while ((UINT8 *) DefaultInfo < BufferEnd) {
+ if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == SkuId) {
+ IsFound = TRUE;
+ break;
+ }
+ DefaultInfo ++;
+ }
+ if (IsFound) {
+ DeltaData = (PCD_DATA_DELTA *) BufferEnd;
+ BufferEnd = (UINT8 *) DataHeader + DataHeader->DataSize;
+ while ((UINT8 *) DeltaData < BufferEnd) {
+ *(VarStoreHobData + DeltaData->Offset) = (UINT8) DeltaData->Value;
+ DeltaData ++;
+ }
+ break;
+ }
+ Index = (Index + DataHeader->DataSize + 7) & (~7) ;
+ DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index);
+ }
+ }
+
+ Status = PcdUnRegisterCallBackOnSet (
+ &gEfiMdeModulePkgTokenSpaceGuid,
+ PcdToken(PcdSetNvStoreDefaultId),
+ PcdSetNvStoreDefaultIdCallBack
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Report Pei PCD database of all SKUs as Guid HOB so that DxePcd can access it.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Successfully update the Boot records.
+**/
+EFI_STATUS
+EFIAPI
+EndOfPeiSignalPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_PCD_DATABASE *Database;
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *PcdDb;
+ UINT32 Length;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ Status = PeiServicesGetBootMode(&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Don't need to report it on S3 boot.
+ //
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ return EFI_SUCCESS;
+ }
+
+ PeiPcdDb = GetPcdDatabase();
+ if (PeiPcdDb->SystemSkuId != (SKU_ID) 0) {
+ //
+ // SkuId has been set. Don't need to report it to DXE phase.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get full PCD database from PcdPeim FileHandle
+ //
+ Instance = 0;
+ FileHandle = NULL;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances
+ //
+ Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+ //
+ // Error should not happen
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find PcdDb file from the beginning in this firmware volume.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindFileByName (&gEfiCallerIdGuid, VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find PcdPeim FileHandle in this volume
+ //
+ break;
+ }
+ //
+ // We cannot find PcdPeim in this firmware volume, then search the next volume.
+ //
+ Instance++;
+ }
+
+ //
+ // Find PEI PcdDb and Build second PcdDB GuidHob
+ //
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+ Length = PeiPcdDb->LengthForAllSkus;
+ Database = BuildGuidHob (&gPcdDataBaseHobGuid, Length);
+ CopyMem (Database, PcdDb, Length);
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mEndOfPeiSignalPpiNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndOfPeiSignalPpiNotifyCallback
+ }
+};
+
+/**
+ Main entry for PCD PEIM driver.
+
+ This routine initialize the PCD database for PEI phase and install PCD_PPI/EFI_PEI_PCD_PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return Status of install PCD_PPI
+
+**/
+EFI_STATUS
+EFIAPI
+PcdPeimInit (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ BuildPcdDatabase (FileHandle);
+
+ //
+ // Install PCD_PPI and EFI_PEI_PCD_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
+ //
+ Status = PeiServicesInstallPpi (&mPpiList2[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiServicesNotifyPpi (&mEndOfPeiSignalPpiNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiRegisterCallBackOnSet (
+ &gEfiMdeModulePkgTokenSpaceGuid,
+ PcdToken(PcdSetNvStoreDefaultId),
+ PcdSetNvStoreDefaultIdCallBack
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return PeiGetPcdInfo (NULL, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ return PeiGetPcdInfo (Guid, TokenNumber, PcdInfo);
+}
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+PeiGetPcdInfoGetSku (
+ VOID
+ )
+{
+ return (UINTN) GetPcdDatabase()->SystemSkuId;
+}
+
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+PeiPcdSetSku (
+ IN UINTN SkuId
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ SKU_ID *SkuIdTable;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN Instance;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *PcdDb;
+ UINT32 Length;
+ PCD_DATABASE_SKU_DELTA *SkuDelta;
+ PCD_DATA_DELTA *SkuDeltaData;
+
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId 0x%lx is to be set.\n", (SKU_ID) SkuId));
+
+ PeiPcdDb = GetPcdDatabase();
+
+ if (SkuId == PeiPcdDb->SystemSkuId) {
+ //
+ // The input SKU Id is equal to current SKU Id, return directly.
+ //
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId is same to current system Sku.\n"));
+ return;
+ }
+
+ if (PeiPcdDb->SystemSkuId != (SKU_ID) 0) {
+ DEBUG ((DEBUG_ERROR, "PcdPei - The SKU Id could be changed only once."));
+ DEBUG ((
+ DEBUG_ERROR,
+ "PcdPei - The SKU Id was set to 0x%lx already, it could not be set to 0x%lx any more.",
+ PeiPcdDb->SystemSkuId,
+ (SKU_ID) SkuId
+ ));
+ ASSERT (FALSE);
+ return;
+ }
+
+ SkuIdTable = (SKU_ID *) ((UINT8 *) PeiPcdDb + PeiPcdDb->SkuIdTableOffset);
+ for (Index = 0; Index < SkuIdTable[0]; Index++) {
+ if (SkuId == SkuIdTable[Index + 1]) {
+ DEBUG ((DEBUG_INFO, "PcdPei - SkuId is found in SkuId table.\n"));
+ break;
+ }
+ }
+
+ if (Index < SkuIdTable[0]) {
+ //
+ // Get full PCD database from PcdPeim FileHandle
+ //
+ Instance = 0;
+ FileHandle = NULL;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances
+ //
+ Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+ //
+ // Error should not happen
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find PcdDb file from the beginning in this firmware volume.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindFileByName (&gEfiCallerIdGuid, VolumeHandle, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find PcdPeim FileHandle in this volume
+ //
+ break;
+ }
+ //
+ // We cannot find PcdPeim in this firmware volume, then search the next volume.
+ //
+ Instance++;
+ }
+
+ //
+ // Find the delta data between the different Skus
+ //
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+ Length = PeiPcdDb->LengthForAllSkus;
+ Index = (PeiPcdDb->Length + 7) & (~7);
+ SkuDelta = NULL;
+ while (Index < Length) {
+ SkuDelta = (PCD_DATABASE_SKU_DELTA *) ((UINT8 *) PcdDb + Index);
+ if (SkuDelta->SkuId == SkuId && SkuDelta->SkuIdCompared == 0) {
+ break;
+ }
+ Index = (Index + SkuDelta->Length + 7) & (~7);
+ }
+
+ //
+ // Patch the delta data into current PCD database
+ //
+ if (Index < Length && SkuDelta != NULL) {
+ SkuDeltaData = (PCD_DATA_DELTA *) (SkuDelta + 1);
+ while ((UINT8 *) SkuDeltaData < (UINT8 *) SkuDelta + SkuDelta->Length) {
+ *((UINT8 *) PeiPcdDb + SkuDeltaData->Offset) = (UINT8) SkuDeltaData->Value;
+ SkuDeltaData ++;
+ }
+ PeiPcdDb->SystemSkuId = (SKU_ID) SkuId;
+ DEBUG ((DEBUG_INFO, "PcdPei - Set current SKU Id to 0x%lx.\n", (SKU_ID) SkuId));
+ return;
+ }
+ }
+
+ //
+ // Invalid input SkuId, the default SKU Id will be still used for the system.
+ //
+ DEBUG ((DEBUG_ERROR, "PcdPei - Invalid input SkuId, the default SKU Id will be still used.\n"));
+
+ return;
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8 (
+ IN UINTN TokenNumber
+ )
+{
+ return *((UINT8 *) GetWorker (TokenNumber, sizeof (UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned16 (GetWorker (TokenNumber, sizeof (UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned32 (GetWorker (TokenNumber, sizeof (UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64 (
+ IN UINTN TokenNumber
+ )
+{
+ return ReadUnaligned64 (GetWorker (TokenNumber, sizeof (UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtr (
+ IN UINTN TokenNumber
+ )
+{
+ return GetWorker (TokenNumber, 0);
+}
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBool (
+ IN UINTN TokenNumber
+ )
+{
+ return *((BOOLEAN *) GetWorker (TokenNumber, sizeof (BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSize (
+ IN UINTN TokenNumber
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINTN Size;
+ UINTN MaxSize;
+ UINT32 LocalTokenCount;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ Size = (*((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber) & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
+
+ if (Size == 0) {
+ //
+ // For pointer type, we need to scan the SIZE_TABLE to get the current size.
+ //
+ return GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);
+ } else {
+ return Size;
+ }
+
+}
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((UINT8 *) ExGetWorker (Guid, ExTokenNumber, sizeof (UINT8)));
+}
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned16 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT16)));
+}
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned32 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT32)));
+}
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ReadUnaligned64 (ExGetWorker (Guid, ExTokenNumber, sizeof (UINT64)));
+}
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrieved.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return ExGetWorker (Guid, ExTokenNumber, 0);
+}
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return *((BOOLEAN *) ExGetWorker (Guid, ExTokenNumber, sizeof (BOOLEAN)));
+}
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] ExTokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ return PeiPcdGetSize (GetExPcdTokenNumber (Guid, ExTokenNumber));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ )
+{
+ return SetWorker (TokenNumber, Buffer, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return SetValueWorker (TokenNumber, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT8 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT16 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT32 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINT64 Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Value The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Value
+ )
+{
+ return ExSetWorker (ExTokenNumber, Guid, Value, SizeOfBuffer, TRUE);
+}
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param [in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param [in] ExTokenNumber The PCD token number.
+ @param [in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN BOOLEAN Value
+ )
+{
+ return ExSetValueWorker (ExTokenNumber, Guid, &Value, sizeof (Value));
+}
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN ExTokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ )
+{
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return PeiRegisterCallBackWorker (ExTokenNumber, Guid, CallBackFunction, TRUE);
+}
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] ExTokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PcdUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN ExTokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ )
+{
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CallBackFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return PeiRegisterCallBackWorker (ExTokenNumber, Guid, CallBackFunction, FALSE);
+}
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request
+ is being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service has retrieved the next valid token number.
+ @retval EFI_NOT_FOUND The PCD service could not find data from the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ )
+{
+ UINTN GuidTableIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ EFI_GUID *MatchGuid;
+ EFI_GUID *GuidTable;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ BOOLEAN Found;
+ BOOLEAN PeiExMapTableEmpty;
+ UINTN PeiNexTokenNumber;
+
+ if (!FeaturePcdGet (PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ PeiPcdDb = GetPcdDatabase ();
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+ if (Guid == NULL) {
+ if (*TokenNumber > PeiNexTokenNumber) {
+ return EFI_NOT_FOUND;
+ }
+ (*TokenNumber)++;
+ if (*TokenNumber > PeiNexTokenNumber) {
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+
+ Found = FALSE;
+ //
+ // Locate the GUID in ExMapTable first.
+ //
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ //
+ // If given token number is PCD_INVALID_TOKEN_NUMBER, then return the first
+ // token number in found token space.
+ //
+ if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+
+ for ( ; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if ((ExMapTable[Index].ExTokenNumber == *TokenNumber) && (ExMapTable[Index].ExGuidIndex == GuidTableIdx)) {
+ break;
+ }
+ }
+
+ while (Index < PeiPcdDb->ExTokenCount) {
+ Index++;
+ if (Index == PeiPcdDb->ExTokenCount) {
+ //
+ // Exceed the length of ExMap Table
+ //
+ *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
+ return EFI_NOT_FOUND;
+ } else if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ //
+ // Found the next match
+ //
+ *TokenNumber = ExMapTable[Index].ExTokenNumber;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieves the next valid PCD token namespace for a given namespace.
+
+ Gets the next valid token namespace for a given namespace. This is useful to traverse the valid
+ token namespaces on a platform.
+
+ @param[in, out] Guid An indirect pointer to EFI_GUID. On input it designates a known token
+ namespace from which the search will start. On output, it designates the next valid
+ token namespace on the platform. If *Guid is NULL, then the GUID of the first token
+ space of the current platform is returned. If the search cannot locate the next valid
+ token namespace, an error is returned and the value of *Guid is undefined.
+
+ @retval EFI_SUCCESS The PCD service retrieved the value requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the next valid token namespace.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ )
+{
+ UINTN GuidTableIdx;
+ EFI_GUID *MatchGuid;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN Found;
+ BOOLEAN PeiExMapTableEmpty;
+ EFI_GUID *GuidTable;
+
+ if (!FeaturePcdGet (PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ASSERT (Guid != NULL);
+
+ PeiPcdDb = GetPcdDatabase ();
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ if (*Guid == NULL) {
+ //
+ // return the first Token Space Guid.
+ //
+ *Guid = GuidTable + ExMapTable[0].ExGuidIndex;
+ return EFI_SUCCESS;
+ }
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(GuidTable[0]), *Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ Found = FALSE;
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ Index++;
+ for ( ; Index < PeiPcdDb->ExTokenCount; Index++ ) {
+ if (ExMapTable[Index].ExGuidIndex != GuidTableIdx) {
+ Found = FALSE;
+ for (Index2 = 0 ; Index2 < Index; Index2++) {
+ if (ExMapTable[Index2].ExGuidIndex == ExMapTable[Index].ExGuidIndex) {
+ //
+ // This token namespace should have been found and output at preceding getting.
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+ if (!Found) {
+ *Guid = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + ExMapTable[Index].ExGuidIndex;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ *Guid = NULL;
+ }
+
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Get PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specified size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param MaxSize Maximum size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @return PCD value's size for POINTER type PCD.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, Database);
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTable = (SIZE_INFO *)((UINT8 *)Database + Database->SizeTableOffset);
+
+ *MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // We consider current size is equal to MAX size.
+ //
+ return *MaxSize;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ return SizeTable[SizeTableIdx + 1];
+ }
+}
+
+/**
+ Set PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specified size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param CurrentSize Maximum size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @retval TRUE Success to set PCD's value size, which is not exceed maximum size
+ @retval FALSE Fail to set PCD's value size, which maybe exceed maximum size
+
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ INTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+ SIZE_INFO *SizeTable;
+ UINTN MaxSize;
+
+ SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, Database);
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
+
+ ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
+
+ SizeTable = (SIZE_INFO *)((UINT8 *)Database + Database->SizeTableOffset);
+
+ MaxSize = SizeTable[SizeTableIdx];
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We shouldn't come here as we don't support SET for VPD
+ //
+ ASSERT (FALSE);
+ return FALSE;
+ } else {
+ if ((*CurrentSize > MaxSize) ||
+ (*CurrentSize == MAX_ADDRESS)) {
+ *CurrentSize = MaxSize;
+ return FALSE;
+ }
+
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
+ return TRUE;
+ }
+
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.inf b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.inf
new file mode 100644
index 000000000..7152a7d53
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Pcd.inf
@@ -0,0 +1,351 @@
+## @file
+# PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service.
+#
+# This version PCD PEIM depends on the external PCD database binary file, not built in PCD data base.
+# There are two PCD PPIs as follows:
+# 1) PCD_PPI
+# It is EDKII implementation which support Dynamic/DynamicEx Pcds.
+# 2) EFI_PEI_PCD_PPI
+# It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+# type Pcd.
+# For dynamicEx type PCD, it is compatible between PCD_PPI and EFI_PEI_PCD_PPI.
+# PCD PEIM driver will produce above two PPIs at same time.
+#
+# PCD database is generated as the separate binary image at build time. The binary image
+# will be intergrated into Firmware volume together with PCD driver.
+#
+# ////////////////////////////////////////////////////////////////////////////////
+# // //
+# // Introduction of PCD database //
+# // //
+# ////////////////////////////////////////////////////////////////////////////////
+#
+# 1, Introduction
+# PCD database hold all dynamic type PCD information. The structure of PEI PCD
+# database is generated by build tools according to dynamic PCD usage for
+# specified platform.
+#
+# 2, Dynamic Type PCD
+# Dynamic type PCD is used for the configuration/setting which value is determined
+# dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+# PatchablePcd) is fixed in final generated FD image in build time.
+#
+# 2.1 The "dynamic" determination means one of below cases:
+# a) The PCD setting value is produced by someone driver and consumed by
+# other driver in execution time.
+# b) The PCD setting value is set/get by user from FrontPage.
+# c) The PCD setting value is produced by platform OEM vendor in specified area.
+#
+# 2.2 According to module distribution way, dynamic PCD could be classfied as:
+# a) Dynamic:
+# If module is released in source code and will be built with platform
+# DSC, the dynamic PCD used by this module can be accessed as:
+# PcdGetxx(PcdSampleDynamicPcd);
+# In building platform, build tools will translate PcdSampleDynamicPcd to
+# pair of {Token Space Guid: Token Number} for this PCD.
+# b) DynamicEx:
+# If module is release as binary and will not pariticpate platform building,
+# the dynamic PCD used by this module need be accessed as:
+# PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+# Developer need explicity gives {Token Space Guid:Token Number} as parameter
+# in writting source code.
+#
+# 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+# a) Default Storage:
+# - The PCD value is stored in PCD database maintained by PCD driver in boot
+# time memory.
+# - This type is used for communication between PEIM/DXE driver, DXE/DXE
+# driver. But all set/get value will be losted after boot-time memory
+# is turn off.
+# - [PcdsDynamicDefault] is used as section name for this type PCD in
+# platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+#
+# b) Variable Storage:
+# - The PCD value is stored in variable area.
+# - As default storage type, this type PCD could be used for PEI/DXE driver
+# communication. But beside it, this type PCD could also be used to store
+# the value associate with a HII setting via variable interface.
+# - In PEI phase, the PCD value could only be got but can not be set due
+# to variable area is readonly.
+# - [PcdsDynamicHii] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+#
+# c) OEM specificed storage area:
+# - The PCD value is stored in OEM specified area which base address is
+# specified by PCD setting - PcdVpdBaseAddress64 or PcdVpdBaseAddress.
+# - The area is read only for PEI and DXE phase.
+# - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+# DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+#
+# 2.4 When and how to use dynamic PCD
+# Module developer do not care the used PCD is dynamic or static when writting
+# source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+# in platform DSC file. Please ref section 2.3 to get matching between dynamic
+# PCD type and section name in DSC file.
+#
+# 3, PCD database:
+# Although dynamic PCD could be in different storage type as above description,
+# but the basic information and default value for all dynamic PCD is hold
+# by PCD database maintained by PEI/DXE driver.
+#
+# As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+# also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+# To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+# PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+# database contains all PCDs used in PEI/DXE phase in memory.
+#
+# Build tool will generate PCD database into the separate binary file for
+# PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+#
+# 3.1 PcdPeim and PcdDxe
+# PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+# build guid hob in temporary memory and copy the binary data base from flash
+# to temporary memory for PEI PCD database.
+# DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+# a new PCD database is allocated in boot-time memory which including all
+# PEI PCD and DXE PCD entry.
+#
+# Pcd driver should run as early as possible before any other driver access
+# dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+# making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+#
+# 3.2 Token space Guid/Token number, Platform token, Local token number
+# Dynamic PCD
+# +-----------+ +---------+
+# |TokenSpace | |Platform |
+# | Guid | build tool | Token |
+# | + +-------------->| Number |
+# | Token | +---------+`._
+# | Number | `.
+# +-----------+ `. +------+
+# `-|Local |
+# |Token |
+# DynamicEx PCD ,-|Number|
+# +-----------+ ,-' +------+
+# |TokenSpace | ,-'
+# | Guid | _,-'
+# | + +.'
+# | Token |
+# | Number |
+# +-----------+
+#
+#
+# 3.2.1 Pair of Token space guid + Token number
+# Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+# is not easy maintained by PCD driver, and hashed token number will make
+# searching slowly.
+#
+# 3.2.2 Platform Token Number
+# "Platform token number" concept is introduced for mapping to a pair of
+# "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+# build tool in autogen.h and all of them are continual in a platform scope
+# started from 1.(0 meaning invalid internal token number)
+# With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+# in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+# in autogen.h.
+# Notes: The mapping between pair of "tokenspace guid + token number" and
+# "internal token number" need build tool establish, so "platform token number"
+# mechanism is not suitable for binary module which use DynamicEx type PCD.
+# To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+# to be specificed for PcdSet/PcdGet accessing macro.
+#
+# Platform Token Number is started from 1, and inceased continuous. From whole
+# platform scope, there are two zones: PEI Zone and DXE Zone
+# | Platform Token Number
+# ----------|----------------------------------------------------------------
+# PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+# DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+#
+# 3.2.3 Local Token Number
+# To fast searching a PCD entry in PCD database, PCD driver translate
+# platform token number to local token number via a mapping table.
+# For binary DynamicEx type PCD, there is a another mapping table to translate
+# "token space guid + token number" to local token number directly.
+# Local token number is identifier for all internal interface in PCD PEI/DXE
+# driver.
+#
+# A local token number is a 32-bit value in following meaning:
+# 32 ------------- 28 ---------- 24 -------- 0
+# | PCD type mask | Datum Type | Offset |
+# +-----------------------------------------+
+# where:
+# PCd type mask: indicate Pcd type from following macro:
+# PCD_TYPE_DATA
+# PCD_TYPE_HII
+# PCD_TYPE_VPD
+# PCD_TYPE_STRING
+# Datum Type : indicate PCD vaue type from following macro:
+# PCD_DATUM_TYPE_POINTER
+# PCD_DATUM_TYPE_UINT8
+# PCD_DATUM_TYPE_UINT16
+# PCD_DATUM_TYPE_UINT32
+# PCD_DATUM_TYPE_UINT64
+# Offset : indicate the related offset of PCD value in PCD database array.
+# Based on local token number, PCD driver could fast determine PCD type, value
+# type and get PCD entry from PCD database.
+#
+# 3.3 PCD Database binary file
+# PCD Database binary file will be created at build time as the standalone binary image.
+# To understand the binary image layout, PCD Database C structure is still generated
+# as comments by build tools in PCD driver's autogen.h/
+# autogen.c file. In generated C structure, following information is stored:
+# - ExMapTable: This table is used translate a binary dynamicex type PCD's
+# "tokenguid + token" to local token number.
+# - LocalTokenNumberTable:
+# This table stores all local token number in array, use "Internal
+# token number" as array index to get PCD entry's offset fastly.
+# - SizeTable: This table stores the size information for all PCD entry.
+# - GuidTable: This table stores guid value for DynamicEx's token space,
+# HII type PCD's variable GUID.
+# - SkuIdTable: TBD
+# - SystemSkuId: TBD
+# - PCD value structure:
+# Every PCD has a value record in PCD database. For different
+# datum type PCD has different record structure which will be
+# introduced in 3.3.1
+#
+# In a PCD database structure, there are two major area: Init and UnInit.
+# Init area is use stored above PCD internal structure such as ExMapTable,
+# LocalTokenNumberTable etc and the (default) value of PCD which has default
+# value specified in platform DSC file.
+# Unint area is used stored the value of PCD which has no default value in
+# platform DSC file, the value of NULL, 0 specified in platform DSC file can
+# be seemed as "no default value".
+#
+# 3.3.1 Simple Sample PCD Database C Structure
+# A general sample of PCD database structue is as follows:
+# typedef struct _PCD_DATABASE {
+# typedef struct _PCD_DATABASE_INIT {
+# //===== Following is PCD database internal maintain structures
+# DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+# UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+# GUID GuidTable[PEI_GUID_TABLE_SIZE];
+# SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+# UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+# SKU_ID SystemSkuId;
+#
+# //===== Following is value structure for PCD with default value
+# ....
+# ....
+# ....
+# } Init;
+# typedef struct _PCD_DATABSE_UNINIT {
+# //==== Following is value structure for PCD without default value
+# ....
+# ....
+# } UnInit;
+# }
+#
+# 3.3.2 PCD value structure in PCD database C structure
+# The value's structure is generated by build tool in PCD database C structure.
+# The PCDs in different datum type has different value structure.
+#
+# 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+# The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+# data member in PCD database, For example:
+# UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+# Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+# Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+# in DEC file.
+#
+# 3.3.2.2 VOID* datum type PCD
+# The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+#
+# 3.3.2.2.1 VOID* - string type
+# If the default value for VOID* datum type PCD like L"xxx", the PCD is
+# used for unicode string, and C structure of this datum type PCD is
+# UINT16 string array in PCD database, for example:
+# UINT16 StringTable[29];
+# The number of 29 in above sample is max size of a unicode string.
+#
+# If the default value for VOID* datum type PCD like "xxx", the PCD is
+# used for ascii string, and C structure of this datum type PCD is
+# UINT8 string array in PCD database, for example:
+# UINT8 StringTable[20];
+# The number of 20 in above sample is max size of a ascii string.
+#
+# 3.3.2.2.2 VOID* - byte array
+# If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+# the PCD is used for byte array. The generated structrue is same as
+# above ascii string table,
+# UINT8 StringTable[13];
+# The number of 13 in above sample is max size of byte array.
+#
+# 3.3.3 Some utility structures in PCD Database
+# 3.3.3.1 GuidTable
+# GuidTable array is used to store all related GUID value in PCD database:
+# - Variable GUID for HII type PCD
+# - Token space GUID for dynamicex type PCD
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PcdPeim
+ MODULE_UNI_FILE = PcdPeim.uni
+ FILE_GUID = 9B3ADA4F-AE56-4c24-8DEA-F03B7558AE50
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 4.0
+ PCD_IS_DRIVER = PEI_PCD_DRIVER
+ ENTRY_POINT = PcdPeimInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ Service.c
+ Service.h
+ Pcd.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ PeiServicesLib
+ HobLib
+ BaseLib
+ PeimEntryPoint
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gPcdDataBaseHobGuid
+ gPcdDataBaseSignatureGuid ## CONSUMES ## GUID # PCD database signature GUID.
+ gEfiMdeModulePkgTokenSpaceGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_CONSUMES
+ gPcdPpiGuid ## PRODUCES
+ gEfiPeiPcdPpiGuid ## PRODUCES
+ gGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiGetPcdInfoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiFullPcdDatabaseEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress64 ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PcdPeimExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni
new file mode 100644
index 000000000..0a800889a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeim.uni
@@ -0,0 +1,290 @@
+// /** @file
+// PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service.
+//
+// This version PCD PEIM depends on the external PCD database binary file, not built in PCD data base.
+// There are two PCD PPIs as follows:
+// 1) PCD_PPI
+// It is EDKII implementation which support Dynamic/DynamicEx Pcds.
+// 2) EFI_PEI_PCD_PPI
+// It is defined by PI specification 1.2, Vol 3 which only support dynamicEx
+// type Pcd.
+// For dynamicEx type PCD, it is compatible between PCD_PPI and EFI_PEI_PCD_PPI.
+// PCD PEIM driver will produce above two PPIs at same time.
+//
+// PCD database is generated as the separate binary image at build time. The binary image
+// will be intergrated into Firmware volume together with PCD driver.
+//
+// ////////////////////////////////////////////////////////////////////////////////
+// // //
+// // Introduction of PCD database //
+// // //
+// ////////////////////////////////////////////////////////////////////////////////
+//
+// 1, Introduction
+// PCD database hold all dynamic type PCD information. The structure of PEI PCD
+// database is generated by build tools according to dynamic PCD usage for
+// specified platform.
+//
+// 2, Dynamic Type PCD
+// Dynamic type PCD is used for the configuration/setting which value is determined
+// dynamic. In contrast, the value of static type PCD (FeatureFlag, FixedPcd,
+// PatchablePcd) is fixed in final generated FD image in build time.
+//
+// 2.1 The "dynamic" determination means one of below cases:
+// a) The PCD setting value is produced by someone driver and consumed by
+// other driver in execution time.
+// b) The PCD setting value is set/get by user from FrontPage.
+// c) The PCD setting value is produced by platform OEM vendor in specified area.
+//
+// 2.2 According to module distribution way, dynamic PCD could be classfied as:
+// a) Dynamic:
+// If module is released in source code and will be built with platform
+// DSC, the dynamic PCD used by this module can be accessed as:
+// PcdGetxx(PcdSampleDynamicPcd);
+// In building platform, build tools will translate PcdSampleDynamicPcd to
+// pair of {Token Space Guid: Token Number} for this PCD.
+// b) DynamicEx:
+// If module is release as binary and will not pariticpate platform building,
+// the dynamic PCD used by this module need be accessed as:
+// PcdGetxxEx(gEfiMyTokenspaceGuid, PcdSampleDynamicPcd)
+// Developer need explicity gives {Token Space Guid:Token Number} as parameter
+// in writting source code.
+//
+// 2.3 According to PCD value's storage method, dynamic PCD could be classfied as:
+// a) Default Storage:
+// - The PCD value is stored in PCD database maintained by PCD driver in boot
+// time memory.
+// - This type is used for communication between PEIM/DXE driver, DXE/DXE
+// driver. But all set/get value will be losted after boot-time memory
+// is turn off.
+// - [PcdsDynamicDefault] is used as section name for this type PCD in
+// platform DSC file. [PcdsDynamicExDefault] is used for dynamicEx type PCD.
+//
+// b) Variable Storage:
+// - The PCD value is stored in variable area.
+// - As default storage type, this type PCD could be used for PEI/DXE driver
+// communication. But beside it, this type PCD could also be used to store
+// the value associate with a HII setting via variable interface.
+// - In PEI phase, the PCD value could only be got but can not be set due
+// to variable area is readonly.
+// - [PcdsDynamicHii] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExHii] is for dynamicEx type PCD.
+//
+// c) OEM specificed storage area:
+// - The PCD value is stored in OEM specified area which base address is
+// specified by a FixedAtBuild PCD setting - PcdVpdBaseAddress.
+// - The area is read only for PEI and DXE phase.
+// - [PcdsDynamicVpd] is used as section name for this type PCD in platform
+// DSC file. [PcdsDynamicExVpd] is for dynamicex type PCD.
+//
+// 2.4 When and how to use dynamic PCD
+// Module developer do not care the used PCD is dynamic or static when writting
+// source code/INF. Dynamic PCD and dynamic type is pointed by platform integrator
+// in platform DSC file. Please ref section 2.3 to get matching between dynamic
+// PCD type and section name in DSC file.
+//
+// 3, PCD database:
+// Although dynamic PCD could be in different storage type as above description,
+// but the basic information and default value for all dynamic PCD is hold
+// by PCD database maintained by PEI/DXE driver.
+//
+// As the whole EFI BIOS boot path is divided into PEI/DXE phase, the PCD database
+// also is divided into Pei/Dxe database maintaied by PcdPeim/PcdDxe driver separatly.
+// To make PcdPeim's driver image smaller, PEI PCD database only hold all dynamic
+// PCD information used in PEI phase or use in both PEI/DXE phase. And DXE PCD
+// database contains all PCDs used in PEI/DXE phase in memory.
+//
+// Build tool will generate PCD database into the separate binary file for
+// PEI/DXE PCD driver according to dynamic PCD section in platform DSC file.
+//
+// 3.1 PcdPeim and PcdDxe
+// PEI PCD database is maintained by PcdPeim driver run from flash. PcdPeim driver
+// build guid hob in temporary memory and copy the binary data base from flash
+// to temporary memory for PEI PCD database.
+// DXE PCD database is maintained by PcdDxe driver.At entry point of PcdDxe driver,
+// a new PCD database is allocated in boot-time memory which including all
+// PEI PCD and DXE PCD entry.
+//
+// Pcd driver should run as early as possible before any other driver access
+// dynamic PCD's value. PEI/DXE "Apriori File" mechanism make it possible by
+// making PcdPeim/PcdDxe as first dispatching driver in PEI/DXE phase.
+//
+// 3.2 Token space Guid/Token number, Platform token, Local token number
+// Dynamic PCD
+// +-----------+ +---------+
+// |TokenSpace | |Platform |
+// | Guid | build tool | Token |
+// | + +-------------->| Number |
+// | Token | +---------+`._
+// | Number | `.
+// +-----------+ `. +------+
+// `-|Local |
+// |Token |
+// DynamicEx PCD ,-|Number|
+// +-----------+ ,-' +------+
+// |TokenSpace | ,-'
+// | Guid | _,-'
+// | + +.'
+// | Token |
+// | Number |
+// +-----------+
+//
+//
+// 3.2.1 Pair of Token space guid + Token number
+// Any type PCD is identified by pair of "TokenSpaceGuid + TokeNumber". But it
+// is not easy maintained by PCD driver, and hashed token number will make
+// searching slowly.
+//
+// 3.2.2 Platform Token Number
+// "Platform token number" concept is introduced for mapping to a pair of
+// "TokenSpaceGuid + TokenNumber". The platform token number is generated by
+// build tool in autogen.h and all of them are continual in a platform scope
+// started from 1.(0 meaning invalid internal token number)
+// With auto-generated "platform token number", PcdGet(PcdSampleDynamicPcd)
+// in source code is translated to LibPcdGet(_PCD_TOKEN_PcdSampleDynamicPcd)
+// in autogen.h.
+// Notes: The mapping between pair of "tokenspace guid + token number" and
+// "internal token number" need build tool establish, so "platform token number"
+// mechanism is not suitable for binary module which use DynamicEx type PCD.
+// To access a dynamicEx type PCD, pair of "token space guid/token number" all need
+// to be specificed for PcdSet/PcdGet accessing macro.
+//
+// Platform Token Number is started from 1, and inceased continuous. From whole
+// platform scope, there are two zones: PEI Zone and DXE Zone
+// | Platform Token Number
+// ----------|----------------------------------------------------------------
+// PEI Zone: | 1 ~ PEI_LOCAL_TOKEN_NUMBER
+// DXE Zone: | (PEI_LOCAL_TOKEN_NUMBER + 1) ~ (PEI_LOCAL_TOKEN_NUMBER + DXE_LOCAL_TOKEN_NUMBER)
+//
+// 3.2.3 Local Token Number
+// To fast searching a PCD entry in PCD database, PCD driver translate
+// platform token number to local token number via a mapping table.
+// For binary DynamicEx type PCD, there is a another mapping table to translate
+// "token space guid + token number" to local token number directly.
+// Local token number is identifier for all internal interface in PCD PEI/DXE
+// driver.
+//
+// A local token number is a 32-bit value in following meaning:
+// 32 ------------- 28 ---------- 24 -------- 0
+// | PCD type mask | Datum Type | Offset |
+// +-----------------------------------------+
+// where:
+// PCd type mask: indicate Pcd type from following macro:
+// PCD_TYPE_DATA
+// PCD_TYPE_HII
+// PCD_TYPE_VPD
+// PCD_TYPE_STRING
+// Datum Type : indicate PCD vaue type from following macro:
+// PCD_DATUM_TYPE_POINTER
+// PCD_DATUM_TYPE_UINT8
+// PCD_DATUM_TYPE_UINT16
+// PCD_DATUM_TYPE_UINT32
+// PCD_DATUM_TYPE_UINT64
+// Offset : indicate the related offset of PCD value in PCD database array.
+// Based on local token number, PCD driver could fast determine PCD type, value
+// type and get PCD entry from PCD database.
+//
+// 3.3 PCD Database binary file
+// PCD Database binary file will be created at build time as the standalone binary image.
+// To understand the binary image layout, PCD Database C structure is still generated
+// as comments by build tools in PCD driver's autogen.h/
+// autogen.c file. In generated C structure, following information is stored:
+// - ExMapTable: This table is used translate a binary dynamicex type PCD's
+// "tokenguid + token" to local token number.
+// - LocalTokenNumberTable:
+// This table stores all local token number in array, use "Internal
+// token number" as array index to get PCD entry's offset fastly.
+// - SizeTable: This table stores the size information for all PCD entry.
+// - GuidTable: This table stores guid value for DynamicEx's token space,
+// HII type PCD's variable GUID.
+// - SkuIdTable: TBD
+// - SystemSkuId: TBD
+// - PCD value structure:
+// Every PCD has a value record in PCD database. For different
+// datum type PCD has different record structure which will be
+// introduced in 3.3.1
+//
+// In a PCD database structure, there are two major area: Init and UnInit.
+// Init area is use stored above PCD internal structure such as ExMapTable,
+// LocalTokenNumberTable etc and the (default) value of PCD which has default
+// value specified in platform DSC file.
+// Unint area is used stored the value of PCD which has no default value in
+// platform DSC file, the value of NULL, 0 specified in platform DSC file can
+// be seemed as "no default value".
+//
+// 3.3.1 Simple Sample PCD Database C Structure
+// A general sample of PCD database structue is as follows:
+// typedef struct _PCD_DATABASE {
+// typedef struct _PCD_DATABASE_INIT {
+// //===== Following is PCD database internal maintain structures
+// DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
+// UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
+// GUID GuidTable[PEI_GUID_TABLE_SIZE];
+// SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
+// UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
+// SKU_ID SystemSkuId;
+//
+// //===== Following is value structure for PCD with default value
+// ....
+// ....
+// ....
+// } Init;
+// typedef struct _PCD_DATABSE_UNINIT {
+// //==== Following is value structure for PCD without default value
+// ....
+// ....
+// } UnInit;
+// }
+//
+// 3.3.2 PCD value structure in PCD database C structure
+// The value's structure is generated by build tool in PCD database C structure.
+// The PCDs in different datum type has different value structure.
+//
+// 3.3.2.1 UINT8/UINT16/UINT32/UINT64 datum type PCD
+// The C structure for these datum type PCD is just a UINT8/UINT16/UINT32/UINT64
+// data member in PCD database, For example:
+// UINT16 PcdHardwareErrorRecordLevel_d3705011_bc19_4af7_be16_f68030378c15_VariableDefault_0;
+// Above structure is generated by build tool, the member name is "PcdCName_Guidvalue"
+// Member type is UINT16 according to PcdHardwareErrorRecordLevel declaration
+// in DEC file.
+//
+// 3.3.2.2 VOID* datum type PCD
+// The value of VOID* datum type PCD is a UINT8/UINT16 array in PCD database.
+//
+// 3.3.2.2.1 VOID* - string type
+// If the default value for VOID* datum type PCD like L"xxx", the PCD is
+// used for unicode string, and C structure of this datum type PCD is
+// UINT16 string array in PCD database, for example:
+// UINT16 StringTable[29];
+// The number of 29 in above sample is max size of a unicode string.
+//
+// If the default value for VOID* datum type PCD like "xxx", the PCD is
+// used for ascii string, and C structure of this datum type PCD is
+// UINT8 string array in PCD database, for example:
+// UINT8 StringTable[20];
+// The number of 20 in above sample is max size of a ascii string.
+//
+// 3.3.2.2.2 VOID* - byte array
+// If the default value of VOID* datum type PCD like {'0x29', '0x01', '0xf2'}
+// the PCD is used for byte array. The generated structrue is same as
+// above ascii string table,
+// UINT8 StringTable[13];
+// The number of 13 in above sample is max size of byte array.
+//
+// 3.3.3 Some utility structures in PCD Database
+// 3.3.3.1 GuidTable
+// GuidTable array is used to store all related GUID value in PCD database:
+// - Variable GUID for HII type PCD
+// - Token space GUID for dynamicex type PCD
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service."
+
+#string STR_MODULE_DESCRIPTION #language en-US "PCD PEIM produces PCD database to manage all dynamic PCD in PEI phase and install Pcd Ppi service."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni
new file mode 100644
index 000000000..1e47f0e79
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/PcdPeimExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PcdPeim Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform Configuration Database PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.c b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.c
new file mode 100644
index 000000000..5b037353a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.c
@@ -0,0 +1,1081 @@
+/** @file
+ The driver internal functions are implmented here.
+ They build Pei PCD database, and provide access service to PCD database.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Service.h"
+
+/**
+ Get Local Token Number by Token Number.
+
+ @param[in] Database PCD database.
+ @param[in] TokenNumber The PCD token number.
+
+ @return Local Token Number.
+**/
+UINT32
+GetLocalTokenNumber (
+ IN PEI_PCD_DATABASE *Database,
+ IN UINTN TokenNumber
+ )
+{
+ UINT32 LocalTokenNumber;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + TokenNumber);
+
+ return LocalTokenNumber;
+}
+
+/**
+ Get PCD type by Local Token Number.
+
+ @param[in] LocalTokenNumber The PCD local token number.
+
+ @return PCD type.
+**/
+EFI_PCD_TYPE
+GetPcdType (
+ IN UINT32 LocalTokenNumber
+ )
+{
+ switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
+ case PCD_DATUM_TYPE_POINTER:
+ return EFI_PCD_TYPE_PTR;
+ case PCD_DATUM_TYPE_UINT8:
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {
+ return EFI_PCD_TYPE_BOOL;
+ } else {
+ return EFI_PCD_TYPE_8;
+ }
+ case PCD_DATUM_TYPE_UINT16:
+ return EFI_PCD_TYPE_16;
+ case PCD_DATUM_TYPE_UINT32:
+ return EFI_PCD_TYPE_32;
+ case PCD_DATUM_TYPE_UINT64:
+ return EFI_PCD_TYPE_64;
+ default:
+ ASSERT (FALSE);
+ return EFI_PCD_TYPE_8;
+ }
+}
+
+/**
+ Get PCD name.
+
+ @param[in] OnlyTokenSpaceName If TRUE, only need to get the TokenSpaceCName.
+ If FALSE, need to get the full PCD name.
+ @param[in] Database PCD database.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The TokenSpaceCName or full PCD name.
+**/
+CHAR8 *
+GetPcdName (
+ IN BOOLEAN OnlyTokenSpaceName,
+ IN PEI_PCD_DATABASE *Database,
+ IN UINTN TokenNumber
+ )
+{
+ UINT8 *StringTable;
+ UINTN NameSize;
+ PCD_NAME_INDEX *PcdNameIndex;
+ CHAR8 *TokenSpaceName;
+ CHAR8 *PcdName;
+ CHAR8 *Name;
+
+ //
+ // Return NULL when PCD name table is absent.
+ //
+ if (Database->PcdNameTableOffset == 0) {
+ return NULL;
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ StringTable = (UINT8 *) Database + Database->StringTableOffset;
+
+ //
+ // Get the PCD name index.
+ //
+ PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
+ TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
+ PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
+
+ if (OnlyTokenSpaceName) {
+ //
+ // Only need to get the TokenSpaceCName.
+ //
+ Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
+ } else {
+ //
+ // Need to get the full PCD name.
+ //
+ NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ //
+ // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
+ //
+ AsciiStrCatS (Name, NameSize, TokenSpaceName);
+ Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
+ AsciiStrCatS (Name, NameSize, PcdName);
+ }
+
+ return Name;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Database PCD database.
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+ExGetPcdInfo (
+ IN PEI_PCD_DATABASE *Database,
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ UINTN GuidTableIdx;
+ EFI_GUID *MatchGuid;
+ EFI_GUID *GuidTable;
+ DYNAMICEX_MAPPING *ExMapTable;
+ UINTN Index;
+ UINT32 LocalTokenNumber;
+
+ GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
+ MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
+
+ if (MatchGuid == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GuidTableIdx = MatchGuid - GuidTable;
+
+ ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
+
+ //
+ // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
+ //
+ for (Index = 0; Index < Database->ExTokenCount; Index++) {
+ if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to the null-terminated ASCII string
+ // associated with the token's namespace Guid.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ //
+ // Here use one representative in the token space to get the TokenSpaceCName.
+ //
+ PcdInfo->PcdName = GetPcdName (TRUE, Database, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
+ PcdInfo->PcdSize = PeiPcdGetSize (ExMapTable[Index].TokenNumber);
+ LocalTokenNumber = GetLocalTokenNumber (Database, ExMapTable[Index].TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, Database, ExMapTable[Index].TokenNumber);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+PeiGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ )
+{
+ PEI_PCD_DATABASE *PeiPcdDb;
+ BOOLEAN PeiExMapTableEmpty;
+ UINTN PeiNexTokenNumber;
+ UINT32 LocalTokenNumber;
+
+ ASSERT (PcdInfo != NULL);
+
+ PeiPcdDb = GetPcdDatabase ();
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+
+ if (PeiPcdDb->ExTokenCount == 0) {
+ PeiExMapTableEmpty = TRUE;
+ } else {
+ PeiExMapTableEmpty = FALSE;
+ }
+
+ if (Guid == NULL) {
+ if (TokenNumber > PeiNexTokenNumber) {
+ return EFI_NOT_FOUND;
+ } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ //
+ // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
+ // PcdSize to 0 and PcdName to NULL for default Token Space.
+ //
+ PcdInfo->PcdType = EFI_PCD_TYPE_8;
+ PcdInfo->PcdSize = 0;
+ PcdInfo->PcdName = NULL;
+ } else {
+ PcdInfo->PcdSize = PeiPcdGetSize (TokenNumber);
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber);
+ PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
+ PcdInfo->PcdName = GetPcdName (FALSE, PeiPcdDb, TokenNumber);
+ }
+ return EFI_SUCCESS;
+ } else {
+ if (PeiExMapTableEmpty) {
+ return EFI_NOT_FOUND;
+ }
+ return ExGetPcdInfo (
+ PeiPcdDb,
+ Guid,
+ TokenNumber,
+ PcdInfo
+ );
+ }
+}
+
+/**
+ The function registers the CallBackOnSet fucntion
+ according to TokenNumber and EFI_GUID space.
+
+ @param ExTokenNumber The token number.
+ @param Guid The GUID space.
+ @param CallBackFunction The Callback function to be registered.
+ @param Register To register or unregister the callback function.
+
+ @retval EFI_SUCCESS If the Callback function is registered.
+ @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.
+ @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free
+ slot left in the CallbackFnTable.
+ @retval EFI_INVALID_PARAMETER If the callback function want to be de-registered can not be found.
+**/
+EFI_STATUS
+PeiRegisterCallBackWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PPI_CALLBACK CallBackFunction,
+ IN BOOLEAN Register
+)
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PCD_PPI_CALLBACK *CallbackTable;
+ PCD_PPI_CALLBACK Compare;
+ PCD_PPI_CALLBACK Assign;
+ UINT32 LocalTokenNumber;
+ UINT32 LocalTokenCount;
+ UINTN PeiNexTokenNumber;
+ UINTN TokenNumber;
+ UINTN Idx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ PeiPcdDb = GetPcdDatabase();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+
+ if (Guid == NULL) {
+ TokenNumber = ExTokenNumber;
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ ASSERT (TokenNumber + 1 < (PeiNexTokenNumber + 1));
+ } else {
+ TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT ((TokenNumber + 1) < (LocalTokenCount + 1));
+ }
+
+
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);
+
+ //
+ // We don't support SET for HII and VPD type PCD entry in PEI phase.
+ // So we will assert if any register callback for such PCD entry.
+ //
+ ASSERT ((LocalTokenNumber & PCD_TYPE_HII) == 0);
+ ASSERT ((LocalTokenNumber & PCD_TYPE_VPD) == 0);
+
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ ASSERT (GuidHob != NULL);
+
+ CallbackTable = GET_GUID_HOB_DATA (GuidHob);
+ CallbackTable = CallbackTable + (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
+
+ Compare = Register? NULL: CallBackFunction;
+ Assign = Register? CallBackFunction: NULL;
+
+
+ for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
+ if (CallbackTable[Idx] == Compare) {
+ CallbackTable[Idx] = Assign;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return Register? EFI_OUT_OF_RESOURCES : EFI_INVALID_PARAMETER;
+
+}
+
+
+/**
+ Find the Pcd database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @retval The base address of external PCD database binary.
+ @retval NULL Return NULL if not find.
+**/
+VOID *
+LocateExPcdBinary (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ EFI_STATUS Status;
+ VOID *PcdDb;
+
+ PcdDb = NULL;
+
+ ASSERT (FileHandle != NULL);
+
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check the first bytes (Header Signature Guid) and build version.
+ //
+ if (!CompareGuid (PcdDb, &gPcdDataBaseSignatureGuid) ||
+ (((PEI_PCD_DATABASE *) PcdDb)->BuildVersion != PCD_SERVICE_PEIM_VERSION)) {
+ ASSERT (FALSE);
+ }
+ return PcdDb;
+}
+
+
+/**
+ The function builds the PCD database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @return Pointer to PCD database.
+**/
+PEI_PCD_DATABASE *
+BuildPcdDatabase (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ )
+{
+ PEI_PCD_DATABASE *Database;
+ PEI_PCD_DATABASE *PeiPcdDbBinary;
+ VOID *CallbackFnTable;
+ UINTN SizeOfCallbackFnTable;
+
+ //
+ // Locate the external PCD database binary for one section of current FFS
+ //
+ PeiPcdDbBinary = LocateExPcdBinary (FileHandle);
+
+ ASSERT(PeiPcdDbBinary != NULL);
+
+ Database = BuildGuidHob (&gPcdDataBaseHobGuid, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ ZeroMem (Database, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
+
+ //
+ // PeiPcdDbBinary is smaller than Database
+ //
+ CopyMem (Database, PeiPcdDbBinary, PeiPcdDbBinary->Length);
+
+ SizeOfCallbackFnTable = Database->LocalTokenCount * sizeof (PCD_PPI_CALLBACK) * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry);
+
+ CallbackFnTable = BuildGuidHob (&gEfiCallerIdGuid, SizeOfCallbackFnTable);
+
+ ZeroMem (CallbackFnTable, SizeOfCallbackFnTable);
+
+ return Database;
+}
+
+/**
+ The function is provided by PCD PEIM and PCD DXE driver to
+ do the work of reading a HII variable from variable service.
+
+ @param VariableGuid The Variable GUID.
+ @param VariableName The Variable Name.
+ @param VariableData The output data.
+ @param VariableSize The size of the variable.
+
+ @retval EFI_SUCCESS Operation successful.
+ @retval EFI_NOT_FOUND Variablel not found.
+**/
+EFI_STATUS
+GetHiiVariable (
+ IN CONST EFI_GUID *VariableGuid,
+ IN UINT16 *VariableName,
+ OUT VOID **VariableData,
+ OUT UINTN *VariableSize
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+ VOID *Buffer;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = 0;
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ VariableName,
+ (EFI_GUID *) VariableGuid,
+ NULL,
+ &Size,
+ NULL
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = PeiServicesAllocatePool (Size, &Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ (UINT16 *) VariableName,
+ (EFI_GUID *) VariableGuid,
+ NULL,
+ &Size,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ *VariableSize = Size;
+ *VariableData = Buffer;
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Invoke the callback function when dynamic PCD entry was set, if this PCD entry
+ has registered callback function.
+
+ @param ExTokenNumber DynamicEx PCD's token number, if this PCD entry is dyanmicEx
+ type PCD.
+ @param Guid DynamicEx PCD's guid, if this PCD entry is dynamicEx type
+ PCD.
+ @param TokenNumber PCD token number generated by build tools.
+ @param Data Value want to be set for this PCD entry
+ @param Size The size of value
+
+**/
+VOID
+InvokeCallbackOnSet (
+ UINTN ExTokenNumber,
+ CONST EFI_GUID *Guid, OPTIONAL
+ UINTN TokenNumber,
+ VOID *Data,
+ UINTN Size
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PCD_PPI_CALLBACK *CallbackTable;
+ UINTN Idx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINT32 LocalTokenCount;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ if (Guid == NULL) {
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+ }
+
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ ASSERT (GuidHob != NULL);
+
+ CallbackTable = GET_GUID_HOB_DATA (GuidHob);
+
+ CallbackTable += (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
+
+ for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
+ if (CallbackTable[Idx] != NULL) {
+ CallbackTable[Idx] (Guid,
+ (Guid == NULL) ? (TokenNumber + 1) : ExTokenNumber,
+ Data,
+ Size
+ );
+ }
+ }
+}
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ return SetWorker (TokenNumber, Data, &Size, FALSE);
+}
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ )
+{
+ UINT32 LocalTokenNumber;
+ UINTN PeiNexTokenNumber;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ STRING_HEAD StringTableIdx;
+ UINTN Offset;
+ VOID *InternalData;
+ UINTN MaxSize;
+ UINT32 LocalTokenCount;
+
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ if (PtrType) {
+ //
+ // Get MaxSize first, then check new size with max buffer size.
+ //
+ GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);
+ if (*Size > MaxSize) {
+ *Size = MaxSize;
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (*Size != PeiPcdGetSize (TokenNumber + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // We only invoke the callback function for Dynamic Type PCD Entry.
+ // For Dynamic EX PCD entry, we have invoked the callback function for Dynamic EX
+ // type PCD entry in ExSetWorker.
+ //
+ PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
+ if (TokenNumber + 1 < PeiNexTokenNumber + 1) {
+ InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
+ }
+
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ InternalData = (VOID *) ((UINT8 *) PeiPcdDb + Offset);
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ case PCD_TYPE_HII:
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ case PCD_TYPE_STRING:
+ if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
+ StringTableIdx = *((STRING_HEAD *)InternalData);
+ CopyMem ((UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset + StringTableIdx, Data, *Size);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ case PCD_TYPE_DATA:
+ {
+ if (PtrType) {
+ if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
+ CopyMem (InternalData, Data, *Size);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ switch (*Size) {
+ case sizeof(UINT8):
+ *((UINT8 *) InternalData) = *((UINT8 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT16):
+ *((UINT16 *) InternalData) = *((UINT16 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT32):
+ *((UINT32 *) InternalData) = *((UINT32 *) Data);
+ return EFI_SUCCESS;
+
+ case sizeof(UINT64):
+ *((UINT64 *) InternalData) = *((UINT64 *) Data);
+ return EFI_SUCCESS;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ }
+
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ return ExSetWorker (ExTokenNumber, Guid, Data, &Size, FALSE);
+}
+
+/**
+ Set value for a dynamic-ex PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ )
+{
+ UINTN TokenNumber;
+
+ if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
+ if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
+ return EFI_NOT_FOUND;
+ }
+
+ InvokeCallbackOnSet (ExTokenNumber, Guid, TokenNumber, Data, *Size);
+
+ return SetWorker (TokenNumber, Data, Size, PtrType);
+
+}
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dyanmic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ )
+{
+ return GetWorker (GetExPcdTokenNumber (Guid, ExTokenNumber), GetSize);
+}
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ )
+{
+ UINT32 Offset;
+ EFI_GUID *Guid;
+ UINT16 *Name;
+ VARIABLE_HEAD *VariableHead;
+ EFI_STATUS Status;
+ UINTN DataSize;
+ VOID *Data;
+ UINT8 *StringTable;
+ STRING_HEAD StringTableIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+ UINT32 LocalTokenNumber;
+ UINT32 LocalTokenCount;
+ UINT8 *VaraiableDefaultBuffer;
+ UINTN VpdBaseAddress;
+
+ //
+ // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
+ // We have to decrement TokenNumber by 1 to make it usable
+ // as the array index.
+ //
+ TokenNumber--;
+
+ PeiPcdDb = GetPcdDatabase ();
+ LocalTokenCount = PeiPcdDb->LocalTokenCount;
+
+ // EBC compiler is very choosy. It may report warning about comparison
+ // between UINTN and 0 . So we add 1 in each size of the
+ // comparison.
+ ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
+
+ ASSERT ((GetSize == PeiPcdGetSize(TokenNumber + 1)) || (GetSize == 0));
+
+ LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
+
+ Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
+ StringTable = (UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset;
+
+ switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
+ case PCD_TYPE_VPD:
+ {
+ VPD_HEAD *VpdHead;
+ VpdHead = (VPD_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
+
+ //
+ // PcdVpdBaseAddress64 is DynamicEx PCD only. So, PeiPcdGet64Ex() is used to get its value.
+ //
+ VpdBaseAddress = (UINTN) PeiPcdGet64Ex (&gEfiMdeModulePkgTokenSpaceGuid, PcdToken (PcdVpdBaseAddress64));
+ if (VpdBaseAddress == 0) {
+ //
+ // PcdVpdBaseAddress64 is not set, get value from PcdVpdBaseAddress.
+ //
+ VpdBaseAddress = (UINTN) PcdGet32 (PcdVpdBaseAddress);
+ }
+ ASSERT (VpdBaseAddress != 0);
+ return (VOID *)(VpdBaseAddress + VpdHead->Offset);
+ }
+
+ case PCD_TYPE_HII|PCD_TYPE_STRING:
+ case PCD_TYPE_HII:
+ {
+ VariableHead = (VARIABLE_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
+
+ Guid = (EFI_GUID *) ((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + VariableHead->GuidTableIndex;
+ Name = (UINT16*)&StringTable[VariableHead->StringIndex];
+
+ if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
+ //
+ // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
+ // string array in string table.
+ //
+ VaraiableDefaultBuffer = (UINT8 *) &StringTable[*(STRING_HEAD*)((UINT8*) PeiPcdDb + VariableHead->DefaultValueOffset)];
+ } else {
+ VaraiableDefaultBuffer = (UINT8 *) PeiPcdDb + VariableHead->DefaultValueOffset;
+ }
+ Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
+ if ((Status == EFI_SUCCESS) && (DataSize >= (VariableHead->Offset + GetSize))) {
+ if (GetSize == 0) {
+ //
+ // It is a pointer type. So get the MaxSize reserved for
+ // this PCD entry.
+ //
+ GetPtrTypeSize (TokenNumber, &GetSize, PeiPcdDb);
+ if (GetSize > (DataSize - VariableHead->Offset)) {
+ //
+ // Use actual valid size.
+ //
+ GetSize = DataSize - VariableHead->Offset;
+ }
+ }
+ //
+ // If the operation is successful, we copy the data
+ // to the default value buffer in the PCD Database.
+ //
+ CopyMem (VaraiableDefaultBuffer, (UINT8 *) Data + VariableHead->Offset, GetSize);
+ }
+ return (VOID *) VaraiableDefaultBuffer;
+ }
+
+ case PCD_TYPE_DATA:
+ return (VOID *) ((UINT8 *)PeiPcdDb + Offset);
+
+ case PCD_TYPE_STRING:
+ StringTableIdx = * (STRING_HEAD*) ((UINT8 *) PeiPcdDb + Offset);
+ return (VOID *) (&StringTable[StringTableIdx]);
+
+ default:
+ ASSERT (FALSE);
+ break;
+
+ }
+
+ ASSERT (FALSE);
+
+ return NULL;
+
+}
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Dynamic-ex PCD token number.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ )
+{
+ UINT32 Index;
+ DYNAMICEX_MAPPING *ExMap;
+ EFI_GUID *GuidTable;
+ EFI_GUID *MatchGuid;
+ UINTN MatchGuidIdx;
+ PEI_PCD_DATABASE *PeiPcdDb;
+
+ PeiPcdDb = GetPcdDatabase();
+
+ ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
+ GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
+
+ MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);
+ //
+ // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
+ // error in the BUILD system.
+ //
+ ASSERT (MatchGuid != NULL);
+
+ MatchGuidIdx = MatchGuid - GuidTable;
+
+ for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
+ if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
+ (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
+ return ExMap[Index].TokenNumber;
+ }
+ }
+
+ return PCD_INVALID_TOKEN_NUMBER;
+}
+
+/**
+ Get PCD database from GUID HOB in PEI phase.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+GetPcdDatabase (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
+ ASSERT (GuidHob != NULL);
+
+ return (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
+}
+
+/**
+ Get index of PCD entry in size table.
+
+ @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
+ @param Database Pointer to PCD database in PEI phase.
+
+ @return index of PCD entry in size table.
+
+**/
+UINTN
+GetSizeTableIndex (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ )
+{
+ UINTN Index;
+ UINTN SizeTableIdx;
+ UINTN LocalTokenNumber;
+
+ SizeTableIdx = 0;
+
+ for (Index = 0; Index < LocalTokenNumberTableIdx; Index++) {
+ LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + Index);
+
+ if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
+ //
+ // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
+ // PCD entry.
+ //
+ if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
+ //
+ // We have only two entry for VPD enabled PCD entry:
+ // 1) MAX Size.
+ // 2) Current Size
+ // Current size is equal to MAX size.
+ //
+ SizeTableIdx += 2;
+ } else {
+ //
+ // We have only two entry for Non-Sku enabled PCD entry:
+ // 1) MAX SIZE
+ // 2) Current Size
+ //
+ SizeTableIdx += 2;
+ }
+ }
+
+ }
+
+ return SizeTableIdx;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.h b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.h
new file mode 100644
index 000000000..547094fe8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PCD/Pei/Service.h
@@ -0,0 +1,1082 @@
+/** @file
+ The internal header file declares the private functions used by PeiPcd driver.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_PCD_SERVICE_H_
+#define _PEI_PCD_SERVICE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/Pcd.h>
+#include <Ppi/PiPcd.h>
+#include <Ppi/PcdInfo.h>
+#include <Ppi/PiPcdInfo.h>
+#include <Guid/PcdDataBaseHobGuid.h>
+#include <Guid/PcdDataBaseSignatureGuid.h>
+#include <Guid/VariableFormat.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Please make sure the PCD Serivce PEIM Version is consistent with
+// the version of the generated PEIM PCD Database by build tool.
+//
+#define PCD_SERVICE_PEIM_VERSION 7
+
+//
+// PCD_PEI_SERVICE_DRIVER_VERSION is defined in Autogen.h.
+//
+#if (PCD_SERVICE_PEIM_VERSION != PCD_PEI_SERVICE_DRIVER_VERSION)
+ #error "Please make sure the version of PCD PEIM Service and the generated PCD PEI Database match."
+#endif
+
+/**
+ Retrieve additional information associated with a PCD token in the default token space.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfo (
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetPcdInfoGetInfoEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/**
+ Retrieve the currently set SKU Id.
+
+ @return The currently set SKU Id. If the platform has not set at a SKU Id, then the
+ default SKU Id value of 0 is returned. If the platform has set a SKU Id, then the currently set SKU
+ Id is returned.
+**/
+UINTN
+EFIAPI
+PeiGetPcdInfoGetSku (
+ VOID
+ );
+
+//
+// PPI Interface Implementation Declaration.
+//
+
+/**
+ Sets the SKU value for subsequent calls to set or get PCD token values.
+
+ SetSku() sets the SKU Id to be used for subsequent calls to set or get PCD values.
+ SetSku() is normally called only once by the system.
+
+ For each item (token), the database can hold a single value that applies to all SKUs,
+ or multiple values, where each value is associated with a specific SKU Id. Items with multiple,
+ SKU-specific values are called SKU enabled.
+
+ The SKU Id of zero is reserved as a default. The valid SkuId range is 1 to 255.
+ For tokens that are not SKU enabled, the system ignores any set SKU Id and works with the
+ single value for that token. For SKU-enabled tokens, the system will use the SKU Id set by the
+ last call to SetSku(). If no SKU Id is set or the currently set SKU Id isn't valid for the specified token,
+ the system uses the default SKU Id. If the system attempts to use the default SKU Id and no value has been
+ set for that Id, the results are unpredictable.
+
+ @param[in] SkuId The SKU value that will be used when the PCD service will retrieve and
+ set values associated with a PCD token.
+
+**/
+VOID
+EFIAPI
+PeiPcdSetSku (
+ IN UINTN SkuId
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the current byte-sized value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT8 value.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the current 16-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT16 value.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the current 32-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT32 value.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the current 64-bits value for a PCD token number.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The UINT64 value.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64 (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtr (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a Boolean value for a given PCD token.
+
+ Retrieves the current boolean value for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The Boolean value.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBool (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSize (
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 8-bit value for a given PCD token.
+
+ Retrieves the 8-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 8-bit value for the PCD token.
+
+**/
+UINT8
+EFIAPI
+PeiPcdGet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 16-bit value for a given PCD token.
+
+ Retrieves the 16-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 16-bit value for the PCD token.
+
+**/
+UINT16
+EFIAPI
+PeiPcdGet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 32-bit value for a given PCD token.
+
+ Retrieves the 32-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 32-bit value for the PCD token.
+
+**/
+UINT32
+EFIAPI
+PeiPcdGet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an 64-bit value for a given PCD token.
+
+ Retrieves the 64-bit value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size 64-bit value for the PCD token.
+
+**/
+UINT64
+EFIAPI
+PeiPcdGet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves a pointer to a value for a given PCD token.
+
+ Retrieves the current pointer to the buffer for a PCD token number.
+ Do not make any assumptions about the alignment of the pointer that
+ is returned by this function call. If the TokenNumber is invalid,
+ the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The pointer to the buffer to be retrived.
+
+**/
+VOID *
+EFIAPI
+PeiPcdGetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves an Boolean value for a given PCD token.
+
+ Retrieves the Boolean value of a particular PCD token.
+ If the TokenNumber is invalid or the token space
+ specified by Guid does not exist, the results are
+ unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size Boolean value for the PCD token.
+
+**/
+BOOLEAN
+EFIAPI
+PeiPcdGetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Retrieves the size of the value for a given PCD token.
+
+ Retrieves the current size of a particular PCD token.
+ If the TokenNumber is invalid, the results are unpredictable.
+
+ @param[in] Guid The token space for the token number.
+ @param[in] TokenNumber The PCD token number.
+
+ @return The size of the value for the PCD token.
+
+**/
+UINTN
+EFIAPI
+PeiPcdGetSizeEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber
+ );
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8 (
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16 (
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32 (
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64 (
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtr (
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBool (
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+/**
+ Sets an 8-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet8Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT8 Value
+ );
+
+/**
+ Sets an 16-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet16Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT16 Value
+ );
+
+/**
+ Sets an 32-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet32Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT32 Value
+ );
+
+/**
+ Sets an 64-bit value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSet64Ex (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN UINT64 Value
+ );
+
+/**
+ Sets a value of a specified size for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in, out] SizeOfBuffer A pointer to the length of the value being set for the PCD token.
+ On input, if the SizeOfValue is greater than the maximum size supported
+ for this TokenNumber then the output value of SizeOfValue will reflect
+ the maximum size supported for this TokenNumber.
+ @param[in] Buffer The buffer to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetPtrEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN OUT UINTN *SizeOfBuffer,
+ IN VOID *Buffer
+ );
+
+/**
+ Sets an Boolean value for a given PCD token.
+
+ When the PCD service sets a value, it will check to ensure that the
+ size of the value being set is compatible with the Token's existing definition.
+ If it is not, an error will be returned.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] Value The value to set for the PCD token.
+
+ @retval EFI_SUCCESS Procedure returned successfully.
+ @retval EFI_INVALID_PARAMETER The PCD service determined that the size of the data
+ being set was incompatible with a call to this function.
+ Use GetSize() to retrieve the size of the target data.
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdSetBoolEx (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ IN BOOLEAN Value
+ );
+
+/**
+ Specifies a function to be called anytime the value of a designated token is changed.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ );
+
+/**
+ Cancels a previously set callback function for a particular PCD token number.
+
+ @param [in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param [in] TokenNumber The PCD token number.
+ @param [in] CallBackFunction The function prototype called when the value associated with the CallBackToken is set.
+
+ @retval EFI_SUCCESS The PCD service has successfully established a call event
+ for the CallBackToken requested.
+ @retval EFI_NOT_FOUND The PCD service could not find the referenced token number.
+
+**/
+EFI_STATUS
+EFIAPI
+PcdUnRegisterCallBackOnSet (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN UINTN TokenNumber,
+ IN PCD_PPI_CALLBACK CallBackFunction
+ );
+
+/**
+ Retrieves the next valid token number in a given namespace.
+
+ This is useful since the PCD infrastructure contains a sparse list of token numbers,
+ and one cannot a priori know what token numbers are valid in the database.
+
+ If TokenNumber is 0 and Guid is not NULL, then the first token from the token space specified by Guid is returned.
+ If TokenNumber is not 0 and Guid is not NULL, then the next token in the token space specified by Guid is returned.
+ If TokenNumber is 0 and Guid is NULL, then the first token in the default token space is returned.
+ If TokenNumber is not 0 and Guid is NULL, then the next token in the default token space is returned.
+ The token numbers in the default token space may not be related to token numbers in token spaces that are named by Guid.
+ If the next token number can be retrieved, then it is returned in TokenNumber, and EFI_SUCCESS is returned.
+ If TokenNumber represents the last token number in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+ If TokenNumber is not present in the token space specified by Guid, then EFI_NOT_FOUND is returned.
+
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ This is an optional parameter that may be NULL. If this parameter is NULL, then a request
+ is being made to retrieve tokens from the default token space.
+ @param[in, out] TokenNumber A pointer to the PCD token number to use to find the subsequent token number.
+
+ @retval EFI_SUCCESS The PCD service has retrieved the next valid token number.
+ Or the input token number is already the last valid token number in the PCD database.
+ In the later case, *TokenNumber is updated with the value of 0.
+ @retval EFI_NOT_FOUND If this input token number and token namespace does not exist on the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextToken (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN OUT UINTN *TokenNumber
+ );
+
+/**
+ Retrieves the next valid PCD token namespace for a given namespace.
+
+ @param[in, out] Guid An indirect pointer to EFI_GUID. On input it designates
+ a known token namespace from which the search will start. On output,
+ it designates the next valid token namespace on the platform. If the input
+ token namespace does not exist on the platform, an error is returned and
+ the value of *Guid is undefined. If *Guid is NULL, then the GUID of the
+ first token space of the current platform is assigned to *Guid the function
+ return EFI_SUCCESS. If *Guid is NULL and there is no namespace exist in
+ the platform other than the default (NULL) tokennamespace, *Guid is unchanged
+ and the function return EFI_SUCCESS. If this input token namespace is the last
+ namespace on the platform, *Guid will be assigned to NULL and the function return
+ EFI_SUCCESS.
+
+ @retval EFI_SUCCESS The PCD service retrieved the next valid token space Guid.
+ Or the input token space Guid is already the last valid token space Guid
+ in the PCD database. In the later case, *Guid is updated with the value of NULL.
+ @retval EFI_NOT_FOUND If the input token namespace does not exist on the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiPcdGetNextTokenSpace (
+ IN OUT CONST EFI_GUID **Guid
+ );
+
+/**
+ Retrieve additional information associated with a PCD token.
+
+ This includes information such as the type of value the TokenNumber is associated with as well as possible
+ human readable name that is associated with the token.
+
+ @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
+ @param[in] TokenNumber The PCD token number.
+ @param[out] PcdInfo The returned information associated with the requested TokenNumber.
+ The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
+
+ @retval EFI_SUCCESS The PCD information was returned successfully
+ @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
+**/
+EFI_STATUS
+PeiGetPcdInfo (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN TokenNumber,
+ OUT EFI_PCD_INFO *PcdInfo
+ );
+
+/* Internal Function definitions */
+/**
+ Get PCD database from GUID HOB in PEI phase.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+GetPcdDatabase (
+ VOID
+ );
+
+/**
+ Wrapper function for setting non-pointer type value for a PCD entry.
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+
+ @return status of SetWorker.
+
+**/
+EFI_STATUS
+SetValueWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN UINTN Size
+ );
+
+/**
+ Set value for an PCD entry
+
+ @param TokenNumber Pcd token number autogenerated by build tools.
+ @param Data Value want to be set for PCD entry
+ @param Size Size of value.
+ @param PtrType If TRUE, the type of PCD entry's value is Pointer.
+ If False, the type of PCD entry's value is not Pointer.
+
+ @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
+ @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
+ @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
+ @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
+ range of UINT8, UINT16, UINT32, UINT64
+ @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
+**/
+EFI_STATUS
+SetWorker (
+ IN UINTN TokenNumber,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
+
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data Value want to be set.
+ @param SetSize The size of value.
+
+ @return status of ExSetWorker().
+
+**/
+EFI_STATUS
+ExSetValueWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN Size
+ );
+
+/**
+ Set value for a dynamic PCD entry.
+
+ This routine find the local token number according to dynamic-ex PCD's token
+ space guid and token number firstly, and invoke callback function if this PCD
+ entry registered callback function. Finally, invoken general SetWorker to set
+ PCD value.
+
+ @param ExTokenNumber Dynamic-ex PCD token number.
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param Data PCD value want to be set
+ @param SetSize Size of value.
+ @param PtrType If TRUE, this PCD entry is pointer type.
+ If FALSE, this PCD entry is not pointer type.
+
+ @return status of SetWorker().
+
+**/
+EFI_STATUS
+ExSetWorker (
+ IN UINTN ExTokenNumber,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN OUT UINTN *Size,
+ IN BOOLEAN PtrType
+ );
+
+/**
+ Get the PCD entry pointer in PCD database.
+
+ This routine will visit PCD database to find the PCD entry according to given
+ token number. The given token number is autogened by build tools and it will be
+ translated to local token number. Local token number contains PCD's type and
+ offset of PCD entry in PCD database.
+
+ @param TokenNumber Token's number, it is autogened by build tools
+ @param GetSize The size of token's value
+
+ @return PCD entry pointer in PCD database
+
+**/
+VOID *
+GetWorker (
+ IN UINTN TokenNumber,
+ IN UINTN GetSize
+ );
+
+/**
+ Wrapper function for get PCD value for dynamic-ex PCD.
+
+ @param Guid Token space guid for dynamic-ex PCD.
+ @param ExTokenNumber Token number for dyanmic-ex PCD.
+ @param GetSize The size of dynamic-ex PCD value.
+
+ @return PCD entry in PCD database.
+
+**/
+VOID *
+ExGetWorker (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber,
+ IN UINTN GetSize
+ );
+
+typedef struct {
+ UINTN TokenNumber;
+ UINTN Size;
+ UINT32 LocalTokenNumberAlias;
+} EX_PCD_ENTRY_ATTRIBUTE;
+
+/**
+ Get Token Number according to dynamic-ex PCD's {token space guid:token number}
+
+ A dynamic-ex type PCD, developer must provide pair of token space guid: token number
+ in DEC file. PCD database maintain a mapping table that translate pair of {token
+ space guid: token number} to Token Number.
+
+ @param Guid Token space guid for dynamic-ex PCD entry.
+ @param ExTokenNumber Token number for dynamic-ex PCD.
+
+ @return Token Number for dynamic-ex PCD.
+
+**/
+UINTN
+GetExPcdTokenNumber (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN ExTokenNumber
+ );
+
+/**
+ The function registers the CallBackOnSet fucntion
+ according to TokenNumber and EFI_GUID space.
+
+ @param TokenNumber The token number.
+ @param Guid The GUID space.
+ @param CallBackFunction The Callback function to be registered.
+ @param Register To register or unregister the callback function.
+
+ @retval EFI_SUCCESS If the Callback function is registered.
+ @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.
+ @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free
+ slot left in the CallbackFnTable.
+**/
+EFI_STATUS
+PeiRegisterCallBackWorker (
+ IN UINTN TokenNumber,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN PCD_PPI_CALLBACK CallBackFunction,
+ IN BOOLEAN Register
+ );
+
+/**
+ The function builds the PCD database.
+
+ @param FileHandle Handle of the file the external PCD database binary located.
+
+ @return Pointer to PCD database.
+
+**/
+PEI_PCD_DATABASE *
+BuildPcdDatabase (
+ IN EFI_PEI_FILE_HANDLE FileHandle
+ );
+
+/**
+ Get index of PCD entry in size table.
+
+ @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
+ @param Database Pointer to PCD database.
+
+ @return index of PCD entry in size table.
+
+**/
+UINTN
+GetSizeTableIndex (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+/**
+ Get PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specificed size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param MaxSize Maxmium size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @return PCD value's size for POINTER type PCD.
+
+**/
+UINTN
+GetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ OUT UINTN *MaxSize,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+/**
+ Set PCD value's size for POINTER type PCD.
+
+ The POINTER type PCD's value will be stored into a buffer in specificed size.
+ The max size of this PCD's value is described in PCD's definition in DEC file.
+
+ @param LocalTokenNumberTableIdx Index of PCD token number in PCD token table
+ @param CurrentSize Maxmium size of PCD's value
+ @param Database Pcd database in PEI phase.
+
+ @retval TRUE Success to set PCD's value size, which is not exceed maxmium size
+ @retval FALSE Fail to set PCD's value size, which maybe exceed maxmium size
+
+**/
+BOOLEAN
+SetPtrTypeSize (
+ IN UINTN LocalTokenNumberTableIdx,
+ IN OUT UINTN *CurrentSize,
+ IN PEI_PCD_DATABASE *Database
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.inf b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.inf
new file mode 100644
index 000000000..94665213d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.inf
@@ -0,0 +1,50 @@
+## @file
+# Pcat SingleSegmentPciCfg2Pei Pei Module.
+#
+# It installs SingleSegmentPciConfiguration2 PPI to provide read, write and modify access to Pci configuration space in PEI phase.
+# To follow PI specification, these services also support access to the unaligned Pci address.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PcatSingleSegmentPciCfg2Pei
+ MODULE_UNI_FILE = PcatSingleSegmentPciCfg2Pei.uni
+ FILE_GUID = 4F1F379F-2A62-48bb-AC34-D3F135C6E2B7
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimInitializePciCfg
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ PciCfg2.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ PeimEntryPoint
+ PciLib
+ BaseLib
+ DebugLib
+ PeiServicesLib
+
+[Ppis]
+ gEfiPciCfg2PpiGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PcatSingleSegmentPciCfg2PeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.uni b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.uni
new file mode 100644
index 000000000..78a7a7836
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2Pei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Pcat SingleSegmentPciCfg2Pei Pei Module.
+//
+// It installs SingleSegmentPciConfiguration2 PPI to provide read, write and modify access to Pci configuration space in PEI phase.
+// To follow PI specification, these services also support access to the unaligned Pci address.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Pcat SingleSegmentPciCfg2Pei Pei Module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "It installs SingleSegmentPciConfiguration2 PPI to provide read, write, and modify access to PCI configuration space in the PEI phase. These services also support access to the unaligned PCI address."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2PeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2PeiExtra.uni
new file mode 100644
index 000000000..8b0dd5f73
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PcatSingleSegmentPciCfg2PeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PcatSingleSegmentPciCfg2Pei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Single Segment PCI Configuration PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
new file mode 100644
index 000000000..41fa92911
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PcatSingleSegmentPciCfg2Pei/PciCfg2.c
@@ -0,0 +1,311 @@
+/** @file
+ This driver installs Single Segment Pci Configuration 2 PPI
+ to provide read, write and modify access to Pci configuration space in PEI phase.
+ To follow PI specification, these services also support access to the unaligned Pci address.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/PciCfg2.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <IndustryStandard/Pci.h>
+
+/**
+ Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
+
+ @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
+
+ @return PCI address with PCI_LIB_ADDRESS format.
+
+**/
+UINTN
+PciCfgAddressConvert (
+ EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address
+ )
+{
+ if (Address->ExtendedRegister == 0) {
+ return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register);
+ }
+
+ return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister);
+}
+
+/**
+ Reads from a given location in the PCI configuration space.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+
+**/
+EFI_STATUS
+EFIAPI
+PciCfg2Read (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN PciLibAddress;
+
+ PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
+
+ if (Width == EfiPeiPciCfgWidthUint8) {
+ *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
+ } else if (Width == EfiPeiPciCfgWidthUint16) {
+ if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
+ *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);
+ }
+ } else if (Width == EfiPeiPciCfgWidthUint32) {
+ if ((PciLibAddress & 0x03) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress));
+ } else if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Unaligned Pci address access, break up the request into word by word.
+ //
+ WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
+ WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2));
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
+ *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);
+ *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2);
+ *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3);
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write to a given location in the PCI configuration space.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes.
+ See EFI_PEI_PCI_CFG_PPI_WIDTH above.
+ @param Address The physical address of the access. The format of
+ the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
+ @param Buffer A pointer to the buffer of data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+
+**/
+EFI_STATUS
+EFIAPI
+PciCfg2Write (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN PciLibAddress;
+
+ PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
+
+ if (Width == EfiPeiPciCfgWidthUint8) {
+ PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
+ } else if (Width == EfiPeiPciCfgWidthUint16) {
+ if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
+ PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));
+ }
+ } else if (Width == EfiPeiPciCfgWidthUint32) {
+ if ((PciLibAddress & 0x03) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer));
+ } else if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Unaligned Pci address access, break up the request into word by word.
+ //
+ PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
+ PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1));
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
+ PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));
+ PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2));
+ PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3));
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function performs a read-modify-write operation on the contents from a given
+ location in the PCI configuration space.
+
+ @param PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param This Pointer to local data for the interface.
+ @param Width The width of the access. Enumerated in bytes. Type
+ EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
+ @param Address The physical address of the access.
+ @param SetBits Points to value to bitwise-OR with the read configuration value.
+ The size of the value is determined by Width.
+ @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
+ The size of the value is determined by Width.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER The invalid access width.
+
+**/
+EFI_STATUS
+EFIAPI
+PciCfg2Modify (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_PEI_PCI_CFG2_PPI *This,
+ IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *SetBits,
+ IN VOID *ClearBits
+ )
+{
+ UINTN PciLibAddress;
+ UINT16 ClearValue16;
+ UINT16 SetValue16;
+ UINT32 ClearValue32;
+ UINT32 SetValue32;
+
+ PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
+
+ if (Width == EfiPeiPciCfgWidthUint8) {
+ PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
+ } else if (Width == EfiPeiPciCfgWidthUint16) {
+ if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
+ PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
+ PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));
+ }
+ } else if (Width == EfiPeiPciCfgWidthUint32) {
+ if ((PciLibAddress & 0x03) == 0) {
+ //
+ // Aligned Pci address access
+ //
+ ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));
+ SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);
+ PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);
+ } else if ((PciLibAddress & 0x01) == 0) {
+ //
+ // Unaligned Pci address access, break up the request into word by word.
+ //
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
+ PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
+
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1));
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1);
+ PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);
+ } else {
+ //
+ // Unaligned Pci address access, break up the request into byte by byte.
+ //
+ PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
+ PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));
+ PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2));
+ PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3));
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {
+ PciCfg2Read,
+ PciCfg2Write,
+ PciCfg2Modify,
+ 0
+};
+
+EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPciCfg2PpiGuid,
+ &gPciCfg2Ppi
+};
+
+/**
+ Module's entry function.
+ This routine will install EFI_PEI_PCI_CFG2_PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return Whether success to install service.
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializePciCfg (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;
+ Status = PeiServicesInstallPpi (&gPciCfg2PpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/InternalPlatDriOverrideDxe.h b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/InternalPlatDriOverrideDxe.h
new file mode 100644
index 000000000..d7bb7822c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/InternalPlatDriOverrideDxe.h
@@ -0,0 +1,211 @@
+/** @file
+ Ihe internal heder file includes the required Protocol/Guid/Library
+ and the shared function APIs.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _INTERNAL_PLATFORM_DRIVER_OVERRIDE_H_
+#define _INTERNAL_PLATFORM_DRIVER_OVERRIDE_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PlatformDriverOverride.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/VariableFormat.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HiiLib.h>
+
+/**
+ Free all the mapping database memory resource and initialize the mapping list entry.
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER mapping database list entry is NULL
+ @retval EFI_SUCCESS Free success
+
+**/
+EFI_STATUS
+EFIAPI
+FreeMappingDatabase (
+ IN OUT LIST_ENTRY *MappingDataBase
+ )
+;
+
+/**
+ Read the NV environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths, and create the mapping database in memory to contain these variable info.
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_NOT_FOUND Cannot find the 'PlatDriOver' NV variable
+ @retval EFI_VOLUME_CORRUPTED The found NV variable is corrupted
+ @retval EFI_SUCCESS Create the mapping database in memory successfully
+
+**/
+EFI_STATUS
+EFIAPI
+InitOverridesMapping (
+ OUT LIST_ENTRY *MappingDataBase
+ )
+;
+
+/**
+ Save the memory mapping database into NV environment variable(s).
+ If MappingDataBase list is empty, then delete all platform override NV variables.
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_SUCCESS Save memory mapping database successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SaveOverridesMapping (
+ IN LIST_ENTRY *MappingDataBase
+ )
+;
+
+/**
+ Retrieves the image handle of the platform override driver for a controller in the system from the memory mapping database.
+
+ @param ControllerHandle The device handle of the controller to check if
+ a driver override exists.
+ @param DriverImageHandle On output, a pointer to the next driver handle.
+ Passing in a pointer to NULL, will return the
+ first driver handle for ControllerHandle.
+ @param MappingDataBase MappingDataBase - Mapping database list entry
+ pointer
+ @param CallerImageHandle The caller driver's image handle, for
+ UpdateFvFileDevicePath use.
+
+ @retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is not
+ a valid handle. Or DriverImagePath is not a
+ device path that was returned on a previous call
+ to GetDriverPath().
+ @retval EFI_NOT_FOUND A driver override for ControllerHandle was not
+ found.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SUCCESS The driver override for ControllerHandle was
+ returned in DriverImagePath.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriverFromMapping (
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle,
+ IN LIST_ENTRY *MappingDataBase,
+ IN EFI_HANDLE CallerImageHandle
+ )
+;
+
+/**
+ Check mapping database whether already has the mapping info which
+ records the input Controller to input DriverImage.
+
+ @param ControllerDevicePath The controller device path is to be check.
+ @param DriverImageDevicePath The driver image device path is to be check.
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverInfoNum the controller's total override driver number
+ @param DriverImageNO The driver order number for the input DriverImage.
+ If the DriverImageDevicePath is NULL, DriverImageNO is not set.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath or MappingDataBase is NULL.
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS The controller's total override driver number and
+ input DriverImage's order number is correctly return.
+**/
+EFI_STATUS
+EFIAPI
+CheckMapping (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath OPTIONAL,
+ IN LIST_ENTRY *MappingDataBase,
+ OUT UINT32 *DriverInfoNum OPTIONAL,
+ OUT UINT32 *DriverImageNO OPTIONAL
+ )
+;
+
+/**
+ Insert a driver image as a controller's override driver into the mapping database.
+ The driver image's order number is indicated by DriverImageNO.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverImageNO The inserted order number. If this number is taken,
+ the larger available number will be used.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or DriverImageDevicePath is NULL
+ or MappingDataBase is NULL
+ @retval EFI_ALREADY_STARTED The input Controller to input DriverImage has been
+ recorded into the mapping database.
+ @retval EFI_SUCCESS The Controller and DriverImage are inserted into
+ the mapping database successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase,
+ IN UINT32 DriverImageNO
+ )
+;
+
+/**
+ Delete a controller's override driver from the mapping database.
+
+ @param ControllerDevicePath The controller device path will be deleted
+ when all drivers images on it are removed.
+ @param DriverImageDevicePath The driver image device path will be delete.
+ If NULL, all driver image will be delete.
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or MappingDataBase is NULL
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS Delete the specified driver successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase
+ )
+;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c
new file mode 100644
index 000000000..045c57415
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c
@@ -0,0 +1,1744 @@
+/** @file
+ This file also installs UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL.
+
+ The main code offers a UI interface in device manager to let user configure
+ platform override protocol to override the default algorithm for matching
+ drivers to controllers.
+
+ The main flow:
+ 1. It dynamicly locate all controller device path.
+ 2. It dynamicly locate all drivers which support binding protocol.
+ 3. It export and dynamicly update two menu to let user select the
+ mapping between drivers to controllers.
+ 4. It save all the mapping info in NV variables which will be consumed
+ by platform override protocol driver to publish the platform override protocol.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalPlatDriOverrideDxe.h"
+#include "PlatOverMngr.h"
+
+#define EFI_CALLBACK_INFO_SIGNATURE SIGNATURE_32 ('C', 'l', 'b', 'k')
+#define EFI_CALLBACK_INFO_FROM_THIS(a) CR (a, EFI_CALLBACK_INFO, ConfigAccess, EFI_CALLBACK_INFO_SIGNATURE)
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE RegisteredHandle;
+ PLAT_OVER_MNGR_DATA FakeNvData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL PlatformDriverOverride;
+} EFI_CALLBACK_INFO;
+
+#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()
+
+//
+// uni string and Vfr Binary data.
+//
+extern UINT8 VfrBin[];
+extern UINT8 PlatDriOverrideDxeStrings[];
+
+//
+// module global data
+//
+CHAR16 mVariableName[] = L"Data";
+LIST_ENTRY mMappingDataBase = INITIALIZE_LIST_HEAD_VARIABLE (mMappingDataBase);
+BOOLEAN mEnvironmentVariableRead = FALSE;
+EFI_HANDLE mCallerImageHandle = NULL;
+
+EFI_HANDLE *mDevicePathHandleBuffer;
+EFI_HANDLE *mDriverImageHandleBuffer;
+
+INTN mSelectedCtrIndex;
+EFI_STRING_ID *mControllerToken;
+UINTN mDriverImageHandleCount;
+EFI_STRING_ID *mDriverImageToken;
+EFI_DEVICE_PATH_PROTOCOL **mControllerDevicePathProtocol;
+UINTN mSelectedDriverImageNum;
+UINTN mLastSavedDriverImageNum;
+UINT16 mCurrentPage;
+EFI_CALLBACK_INFO *mCallbackInfo;
+BOOLEAN *mDriSelection;
+UINTN mMaxDeviceCount;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ PLAT_OVER_MNGR_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Converting a given device to an unicode string.
+
+ @param DevPath Given device path instance
+
+ @return Converted string from given device path.
+ @retval L"?" Converting failed.
+**/
+CHAR16 *
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ CHAR16 *Text;
+ Text = ConvertDevicePathToText (
+ DevPath,
+ FALSE,
+ TRUE
+ );
+ if (Text == NULL) {
+ Text = AllocateCopyPool (sizeof (L"?"), L"?");
+ ASSERT (Text != NULL);
+ }
+
+ return Text;
+}
+
+/**
+ Worker function to get the driver name by ComponentName or ComponentName2 protocol
+ according to the driver binding handle.
+
+ @param DriverBindingHandle The Handle of DriverBinding.
+ @param ProtocolGuid The pointer to Component Name (2) protocol GUID.
+ @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
+
+ @retval !NULL Pointer into the image name if the image name is found,
+ @retval NULL Pointer to NULL if the image name is not found.
+
+**/
+CHAR16 *
+GetComponentNameWorker (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_GUID *ProtocolGuid,
+ IN CONST CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+ CHAR16 *DriverName;
+ CHAR8 *Language;
+ CHAR8 *BestLanguage;
+
+ Status = gBS->OpenProtocol (
+ DriverBindingHandle,
+ ProtocolGuid,
+ (VOID *) &ComponentName,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Find the best matching language.
+ //
+ GetEfiGlobalVariable2 (VariableName, (VOID**)&Language, NULL);
+ BestLanguage = GetBestLanguage (
+ ComponentName->SupportedLanguages,
+ (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid),
+ Language,
+ NULL
+ );
+
+ DriverName = NULL;
+ if (BestLanguage != NULL) {
+ ComponentName->GetDriverName (
+ ComponentName,
+ BestLanguage,
+ &DriverName
+ );
+ FreePool (BestLanguage);
+ }
+
+ if (Language != NULL) {
+ FreePool (Language);
+ }
+
+ return DriverName;
+}
+
+
+/**
+ Get the driver name by ComponentName or ComponentName2 protocol
+ according to the driver binding handle
+
+ @param DriverBindingHandle The Handle of DriverBinding.
+
+ @retval !NULL Pointer into the image name if the image name is found,
+ @retval NULL Pointer to NULL if the image name is not found.
+
+**/
+CHAR16 *
+GetComponentName (
+ IN EFI_HANDLE DriverBindingHandle
+ )
+{
+ CHAR16 *DriverName;
+
+ //
+ // Try RFC 4646 Component Name 2 protocol first.
+ //
+ DriverName = GetComponentNameWorker (DriverBindingHandle, &gEfiComponentName2ProtocolGuid, L"PlatformLang");
+ if (DriverName == NULL) {
+ //
+ // If we can not get driver name from Component Name 2 protocol, we can try ISO 639-2 Component Name protocol.
+ //
+ DriverName = GetComponentNameWorker (DriverBindingHandle, &gEfiComponentNameProtocolGuid, L"Lang");
+ }
+
+ return DriverName;
+}
+
+/**
+ Get the image name from EFI UI section.
+ Get FV protocol by its loaded image protocol to abstract EFI UI section.
+
+ @param Image Pointer to the loaded image protocol
+
+ @retval !NULL Pointer to the image name if the image name is found,
+ @retval NULL NULL if the image name is not found.
+
+**/
+CHAR16 *
+GetImageName (
+ IN EFI_LOADED_IMAGE_PROTOCOL *Image
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
+ EFI_DEVICE_PATH_PROTOCOL *AlignedDevPathNode;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
+ VOID *Buffer;
+ UINTN BufferSize;
+ UINT32 AuthenticationStatus;
+ EFI_GUID *NameGuid;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
+
+ Fv2 = NULL;
+ Buffer = NULL;
+ BufferSize = 0;
+
+ if (Image->FilePath == NULL) {
+ return NULL;
+ }
+ DevPathNode = Image->FilePath;
+
+ while (!IsDevicePathEnd (DevPathNode)) {
+ //
+ // Make sure device path node is aligned when accessing it's FV Name Guid field.
+ //
+ AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength(DevPathNode), DevPathNode);
+
+ //
+ // Find the Fv File path
+ //
+ NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)AlignedDevPathNode);
+ if (NameGuid != NULL) {
+ FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) AlignedDevPathNode;
+ Status = gBS->HandleProtocol (
+ Image->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv2
+ );
+ //
+ // Locate Image EFI UI section to get the image name.
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = Fv2->ReadSection (
+ Fv2,
+ &FvFilePath->FvFileName,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ &Buffer,
+ &BufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ FreePool (AlignedDevPathNode);
+ break;
+ }
+ Buffer = NULL;
+ }
+ }
+
+ FreePool (AlignedDevPathNode);
+
+ //
+ // Next device path node
+ //
+ DevPathNode = NextDevicePathNode (DevPathNode);
+ }
+
+ return Buffer;
+}
+
+/**
+ Prepare the first page to let user select the device controller which need to
+ add mapping drivers if user select 'Refresh' in first page.
+ During first page, user will see all currnet controller device path in system,
+ select any device path will go to second page to select its overrides drivers.
+
+ @param Private Pointer to EFI_CALLBACK_INFO.
+ @param KeyValue The callback key value of device controller item in first page.
+ @param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+UpdateDeviceSelectPage (
+ IN EFI_CALLBACK_INFO *Private,
+ IN UINT16 KeyValue,
+ IN PLAT_OVER_MNGR_DATA *FakeNvData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DevicePathHandleCount;
+ UINTN NewStrSize;
+ CHAR16 *NewString;
+ EFI_STRING_ID NewStringToken;
+ CHAR16 *ControllerName;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN Len;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // Set current page form ID.
+ //
+ mCurrentPage = FORM_ID_DEVICE;
+
+ //
+ // Initial the mapping database in memory
+ //
+ FreeMappingDatabase (&mMappingDataBase);
+ InitOverridesMapping (&mMappingDataBase);
+
+ //
+ // Init OpCode Handle
+ //
+ 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 = FORM_ID_DEVICE;
+
+ //
+ // 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;
+
+ //
+ // Clear first page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_DEVICE,
+ StartOpCodeHandle, // Label FORM_ID_DEVICE
+ EndOpCodeHandle // LABEL_END
+ );
+
+ //
+ // When user enter the page at first time, the 'first refresh' string is given to notify user to refresh all the drivers,
+ // then the 'first refresh' string will be replaced by the 'refresh' string, and the two strings content are same after the replacement
+ //
+ NewStringToken = STRING_TOKEN (STR_FIRST_REFRESH);
+ NewString = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_REFRESH), NULL);
+ ASSERT (NewString != NULL);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, NewString, NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ FreePool (NewString);
+
+ NewStringToken = STRING_TOKEN (STR_FIRST_REFRESH_HELP);
+ NewString = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_REFRESH_HELP), NULL);
+ ASSERT (NewString != NULL);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, NewString, NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ FreePool (NewString);
+
+ //
+ // created needed controller device item in first page
+ //
+ DevicePathHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ &DevicePathHandleCount,
+ &mDevicePathHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DevicePathHandleCount == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ mMaxDeviceCount = DevicePathHandleCount;
+ mControllerDevicePathProtocol = AllocateZeroPool (DevicePathHandleCount * sizeof (EFI_DEVICE_PATH_PROTOCOL *));
+ ASSERT (mControllerDevicePathProtocol != NULL);
+ mControllerToken = AllocateZeroPool (DevicePathHandleCount * sizeof (EFI_STRING_ID));
+ ASSERT (mControllerToken != NULL);
+
+ for (Index = 0; Index < DevicePathHandleCount; Index++) {
+ if (FakeNvData->PciDeviceFilter == 0x01) {
+ //
+ // Only care PCI device which contain efi driver in its option rom.
+ //
+
+ //
+ // Check whether it is a pci device
+ //
+ ControllerDevicePath = NULL;
+ Status = gBS->OpenProtocol (
+ mDevicePathHandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Check whether it contain efi driver in its option rom
+ //
+ Status = gBS->HandleProtocol(
+ mDevicePathHandleBuffer[Index],
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (EFI_ERROR (Status) || BusSpecificDriverOverride == NULL) {
+ continue;
+ }
+ }
+
+ ControllerDevicePath = NULL;
+ Status = gBS->OpenProtocol (
+ mDevicePathHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ControllerDevicePath,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Save the device path protocol interface
+ //
+ mControllerDevicePathProtocol[Index] = ControllerDevicePath;
+
+ //
+ // Get the driver name
+ //
+ ControllerName = DevicePathToStr (ControllerDevicePath);
+
+ //
+ // Export the driver name string and create item in set options page
+ //
+ Len = StrSize (ControllerName);
+ NewStrSize = Len + StrSize (L"--");
+ NewString = AllocateZeroPool (NewStrSize);
+ ASSERT (NewString != NULL);
+ if (EFI_ERROR (CheckMapping (ControllerDevicePath,NULL, &mMappingDataBase, NULL, NULL))) {
+ StrCatS (NewString, NewStrSize/sizeof(CHAR16), L"--");
+ } else {
+ StrCatS (NewString, NewStrSize/sizeof(CHAR16), L"**");
+ }
+ StrCatS (NewString, NewStrSize/sizeof(CHAR16), ControllerName);
+
+ NewStringToken = HiiSetString (Private->RegisteredHandle, mControllerToken[Index], NewString, NULL);
+ ASSERT (NewStringToken != 0);
+ FreePool (NewString);
+ //
+ // Save the device path string toke for next access use
+ //
+ mControllerToken[Index] = NewStringToken;
+
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ FORM_ID_DRIVER,
+ NewStringToken,
+ STRING_TOKEN (STR_GOTO_HELP_DRIVER),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (Index + KEY_VALUE_DEVICE_OFFSET)
+ );
+ }
+
+ //
+ // Update first page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_DEVICE,
+ StartOpCodeHandle, // Label FORM_ID_DEVICE
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the first Driver Binding handle which has the specific image handle.
+
+ @param ImageHandle The Image handle
+
+ @return Handle to Driver binding
+ @retval NULL The parameter is not valid or the driver binding handle is not found.
+
+**/
+EFI_HANDLE
+GetDriverBindingHandleFromImageHandle (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBindingInterface;
+ EFI_HANDLE DriverBindingHandle;
+
+ DriverBindingHandle = NULL;
+
+ if (ImageHandle == NULL) {
+ return NULL;
+ }
+ //
+ // Get all drivers which support driver binding protocol
+ //
+ DriverBindingHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return NULL;
+ }
+
+ //
+ // Get the first Driver Binding handle which has the specific image handle.
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ DriverBindingInterface = NULL;
+ Status = gBS->OpenProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBindingInterface,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DriverBindingInterface->ImageHandle == ImageHandle) {
+ DriverBindingHandle = DriverBindingHandleBuffer[Index];
+ break;
+ }
+ }
+
+ FreePool (DriverBindingHandleBuffer);
+ return DriverBindingHandle;
+}
+
+/**
+ Prepare to let user select the drivers which need mapping with the device controller
+ selected in first page.
+
+ @param Private Pointer to EFI_CALLBACK_INFO.
+ @param KeyValue The callback key value of device controller item in first page.
+ KeyValue is larger than or equal to KEY_VALUE_DEVICE_OFFSET.
+ @param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+UpdateBindingDriverSelectPage (
+ IN EFI_CALLBACK_INFO *Private,
+ IN UINT16 KeyValue,
+ IN PLAT_OVER_MNGR_DATA *FakeNvData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NewStrSize;
+ CHAR16 *NewString;
+ EFI_STRING_ID NewStringToken;
+ EFI_STRING_ID NewStringHelpToken;
+ UINTN DriverImageHandleCount;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ CHAR16 *DriverName;
+ BOOLEAN FreeDriverName;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ EFI_HANDLE DriverBindingHandle;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_LOADED_IMAGE_PROTOCOL **DriverImageProtocol;
+ EFI_STRING_ID *DriverImageFilePathToken;
+ UINT8 CheckFlags;
+
+ //
+ // If user select a controller item in the first page the following code will be run.
+ // During second page, user will see all currnet driver bind protocol driver, the driver name and its device path will be shown
+ //
+ //First acquire the list of Loaded Image Protocols, and then when want the name of the driver, look up all the Driver Binding Protocols
+ // and find the first one whose ImageHandle field matches the image handle of the Loaded Image Protocol.
+ // then use the Component Name Protocol on the same handle as the first matching Driver Binding Protocol to look up the name of the driver.
+ //
+
+ mCurrentPage = FORM_ID_DRIVER;
+ //
+ // Switch the item callback key value to its NO. in mDevicePathHandleBuffer
+ //
+ mSelectedCtrIndex = KeyValue - KEY_VALUE_DEVICE_OFFSET;
+ ASSERT (mSelectedCtrIndex >= 0 && mSelectedCtrIndex < MAX_CHOICE_NUM);
+
+ mLastSavedDriverImageNum = 0;
+
+ //
+ // Init OpCode Handle
+ //
+ 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 = FORM_ID_DRIVER;
+
+ //
+ // 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;
+
+ //
+ // Clear second page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_DRIVER,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ //
+ // Show all driver which support loaded image protocol in second page
+ //
+ DriverImageHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &DriverImageHandleCount,
+ &mDriverImageHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverImageHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ mDriverImageToken = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_STRING_ID));
+ ASSERT (mDriverImageToken != NULL);
+ mDriSelection = AllocateZeroPool (DriverImageHandleCount * sizeof (BOOLEAN));
+ ASSERT (mDriSelection != NULL);
+
+ DriverImageProtocol = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_LOADED_IMAGE_PROTOCOL *));
+ ASSERT (DriverImageProtocol != NULL);
+ DriverImageFilePathToken = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_STRING_ID));
+ ASSERT (DriverImageFilePathToken != NULL);
+
+ mDriverImageHandleCount = DriverImageHandleCount;
+ for (Index = 0; Index < DriverImageHandleCount; Index++) {
+ //
+ // Step1: Get the driver image total file path for help string and the driver name.
+ //
+
+ //
+ // Find driver's Loaded Image protocol
+ //
+ LoadedImage =NULL;
+
+ Status = gBS->OpenProtocol (
+ mDriverImageHandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ mDriSelection[Index] = FALSE;
+ continue;
+ }
+ DriverImageProtocol[Index] = LoadedImage;
+ //
+ // Find its related driver binding protocol
+ //
+ DriverBindingHandle = GetDriverBindingHandleFromImageHandle (mDriverImageHandleBuffer[Index]);
+ if (DriverBindingHandle == NULL) {
+ mDriSelection[Index] = FALSE;
+ continue;
+ }
+
+ //
+ // Get the EFI Loaded Image Device Path Protocol
+ //
+ LoadedImageDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ mDriverImageHandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ if (LoadedImageDevicePath == NULL) {
+ mDriSelection[Index] = FALSE;
+ continue;
+ }
+
+ if (FakeNvData->PciDeviceFilter == 0x01) {
+ //
+ // only care the driver which is in a Pci device option rom,
+ // and the driver's LoadedImage->DeviceHandle must point to a pci device which has efi option rom
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol(
+ LoadedImage->DeviceHandle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (EFI_ERROR (Status) || BusSpecificDriverOverride == NULL) {
+ mDriSelection[Index] = FALSE;
+ continue;
+ }
+ } else {
+ mDriSelection[Index] = FALSE;
+ continue;
+ }
+ }
+
+ //
+ // For driver name, try to get its component name, if fail, get its image name,
+ // if also fail, give a default name.
+ //
+ FreeDriverName = FALSE;
+ DriverName = GetComponentName (DriverBindingHandle);
+ if (DriverName == NULL) {
+ //
+ // get its image name
+ //
+ DriverName = GetImageName (LoadedImage);
+ }
+ if (DriverName == NULL) {
+ //
+ // give a default name
+ //
+ DriverName = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_DRIVER_DEFAULT_NAME), NULL);
+ ASSERT (DriverName != NULL);
+ FreeDriverName = TRUE; // the DriverName string need to free pool
+ }
+
+
+ //
+ // Step2 Export the driver name string and create check box item in second page
+ //
+
+ //
+ // First create the driver image name
+ //
+ NewStrSize = StrSize (DriverName);
+ NewString = AllocateZeroPool (NewStrSize);
+ ASSERT (NewString != NULL);
+ if (EFI_ERROR (CheckMapping (mControllerDevicePathProtocol[mSelectedCtrIndex], LoadedImageDevicePath, &mMappingDataBase, NULL, NULL))) {
+ mDriSelection[Index] = FALSE;
+ } else {
+ mDriSelection[Index] = TRUE;
+ mLastSavedDriverImageNum++;
+ }
+ StrCatS (NewString, NewStrSize/sizeof(CHAR16), DriverName);
+ NewStringToken = HiiSetString (Private->RegisteredHandle, mDriverImageToken[Index], NewString, NULL);
+ ASSERT (NewStringToken != 0);
+ mDriverImageToken[Index] = NewStringToken;
+ FreePool (NewString);
+ if (FreeDriverName) {
+ FreePool (DriverName);
+ }
+
+ //
+ // Second create the driver image device path as item help string
+ //
+ DriverName = DevicePathToStr (LoadedImageDevicePath);
+
+ NewStrSize = StrSize (DriverName);
+ NewString = AllocateZeroPool (NewStrSize);
+ ASSERT (NewString != NULL);
+ StrCatS (NewString, NewStrSize/sizeof(CHAR16), DriverName);
+ NewStringHelpToken = HiiSetString (Private->RegisteredHandle, DriverImageFilePathToken[Index], NewString, NULL);
+ ASSERT (NewStringHelpToken != 0);
+ DriverImageFilePathToken[Index] = NewStringHelpToken;
+ FreePool (NewString);
+ FreePool (DriverName);
+
+ CheckFlags = 0;
+ if (mDriSelection[Index]) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ }
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ (UINT16) (KEY_VALUE_DRIVER_OFFSET + Index),
+ 0,
+ 0,
+ NewStringToken,
+ NewStringHelpToken,
+ EFI_IFR_FLAG_CALLBACK,
+ CheckFlags,
+ NULL
+ );
+ }
+
+ //
+ // Update second page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_DRIVER,
+ StartOpCodeHandle, // Label FORM_ID_DRIVER
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ if (DriverImageProtocol != NULL) {
+ FreePool (DriverImageProtocol);
+ }
+
+ if (DriverImageFilePathToken != NULL) {
+ FreePool (DriverImageFilePathToken);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare to let user select the priority order of the drivers which are
+ selected in second page.
+
+ @param Private Pointer to EFI_CALLBACK_INFO.
+ @param KeyValue The callback key value of device controller item in first page.
+ @param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+UpdatePrioritySelectPage (
+ IN EFI_CALLBACK_INFO *Private,
+ IN UINT16 KeyValue,
+ IN PLAT_OVER_MNGR_DATA *FakeNvData
+ )
+{
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ UINTN SelectedDriverImageNum;
+ UINT32 DriverImageNO;
+ UINTN MinNO;
+ UINTN Index1;
+ UINTN TempNO[100];
+ UINTN OrderNO[100];
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ VOID *OptionsOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // Following code will be run if user select 'order ... priority' item in second page
+ // Prepare third page. In third page, user will order the drivers priority which are selected in second page
+ //
+ mCurrentPage = FORM_ID_ORDER;
+
+ //
+ // Init OpCode Handle
+ //
+ 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 = FORM_ID_ORDER;
+
+ //
+ // 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;
+
+ //
+ // Clear third page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_ORDER,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ //
+ // Check how many drivers have been selected
+ //
+ SelectedDriverImageNum = 0;
+ for (Index = 0; Index < mDriverImageHandleCount; Index++) {
+ if (mDriSelection[Index]) {
+ SelectedDriverImageNum ++;
+ }
+ }
+
+ mSelectedDriverImageNum = SelectedDriverImageNum;
+ if (SelectedDriverImageNum == 0) {
+ return EFI_SUCCESS;
+ }
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ //
+ // Create order list for those selected drivers
+ //
+ SelectedDriverImageNum = 0;
+ for (Index = 0; Index < mDriverImageHandleCount; Index++) {
+ if (mDriSelection[Index]) {
+ //
+ // Use the NO. in driver binding buffer as value, will use it later
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ mDriverImageToken[Index],
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ Index + 1
+ );
+
+ //
+ // Get the EFI Loaded Image Device Path Protocol
+ //
+ LoadedImageDevicePath = NULL;
+ gBS->HandleProtocol (
+ mDriverImageHandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ ASSERT (LoadedImageDevicePath != NULL);
+
+ //
+ // Check the driver DriverImage's order number in mapping database
+ //
+ DriverImageNO = 0;
+ CheckMapping (
+ mControllerDevicePathProtocol[mSelectedCtrIndex],
+ LoadedImageDevicePath,
+ &mMappingDataBase,
+ NULL,
+ &DriverImageNO
+ );
+ if (DriverImageNO == 0) {
+ DriverImageNO = (UINT32) mLastSavedDriverImageNum + 1;
+ mLastSavedDriverImageNum++;
+ }
+ TempNO[SelectedDriverImageNum] = DriverImageNO;
+ OrderNO[SelectedDriverImageNum] = Index + 1;
+ SelectedDriverImageNum ++;
+ }
+ }
+
+ ASSERT (SelectedDriverImageNum == mSelectedDriverImageNum);
+ //
+ // NvRamMap Must be clear firstly
+ //
+ ZeroMem (FakeNvData->DriOrder, sizeof (FakeNvData->DriOrder));
+
+ //
+ // Order the selected drivers according to the info already in mapping database
+ // the less order number in mapping database the less order number in NvRamMap
+ //
+ for (Index=0; Index < SelectedDriverImageNum; Index++) {
+ //
+ // Find the minimal order number in TempNO array, its index in TempNO is same as IfrOptionList array
+ //
+ MinNO = 0;
+ for (Index1=0; Index1 < SelectedDriverImageNum; Index1++) {
+ if (TempNO[Index1] < TempNO[MinNO]) {
+ MinNO = Index1;
+ }
+ }
+ //
+ // the IfrOptionList[MinNO].Value = the driver NO. in driver binding buffer
+ //
+ FakeNvData->DriOrder[Index] = (UINT8) OrderNO[MinNO];
+ TempNO[MinNO] = MAX_CHOICE_NUM + 1;
+ }
+
+ //
+ // Create Order List OpCode
+ //
+ HiiCreateOrderedListOpCode (
+ StartOpCodeHandle,
+ (UINT16) DRIVER_ORDER_QUESTION_ID,
+ VARSTORE_ID_PLAT_OVER_MNGR,
+ (UINT16) DRIVER_ORDER_VAR_OFFSET,
+ mControllerToken[mSelectedCtrIndex],
+ mControllerToken[mSelectedCtrIndex],
+ EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ (UINT8) MAX_CHOICE_NUM,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ //
+ // Update third page form
+ //
+ HiiUpdateForm (
+ Private->RegisteredHandle,
+ &gPlatformOverridesManagerGuid,
+ FORM_ID_ORDER,
+ StartOpCodeHandle, // Label FORM_ID_ORDER
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Save the save the mapping database to NV variable.
+
+ @param Private Pointer to EFI_CALLBACK_INFO.
+ @param KeyValue The callback key value of device controller item in first page.
+ @param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
+
+ @retval EFI_SUCCESS Always returned.
+
+**/
+EFI_STATUS
+CommitChanges (
+ IN EFI_CALLBACK_INFO *Private,
+ IN UINT16 KeyValue,
+ IN PLAT_OVER_MNGR_DATA *FakeNvData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN SelectedDriverImageNum;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ //
+ // Following code will be run if user select 'commint changes' in third page
+ // user enter 'Commit Changes' to save the mapping database
+ //
+ DeleteDriverImage (mControllerDevicePathProtocol[mSelectedCtrIndex], NULL, &mMappingDataBase);
+ for (SelectedDriverImageNum = 0; SelectedDriverImageNum < mSelectedDriverImageNum; SelectedDriverImageNum++) {
+ //
+ // DriOrder[SelectedDriverImageNum] = the driver NO. in driver binding buffer
+ //
+ Index = FakeNvData->DriOrder[SelectedDriverImageNum] - 1;
+
+ //
+ // Get the EFI Loaded Image Device Path Protocol
+ //
+ LoadedImageDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ mDriverImageHandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ ASSERT (LoadedImageDevicePath != NULL);
+
+ InsertDriverImage (
+ mControllerDevicePathProtocol[mSelectedCtrIndex],
+ LoadedImageDevicePath,
+ &mMappingDataBase,
+ (UINT32)SelectedDriverImageNum + 1
+ );
+ }
+ Status = SaveOverridesMapping (&mMappingDataBase);
+
+ 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
+PlatOverMngrExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ EFI_CALLBACK_INFO *Private;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+ UINTN BufferSize;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gPlatformOverridesManagerGuid, mVariableName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ AllocatedRequest = FALSE;
+
+ Private = EFI_CALLBACK_INFO_FROM_THIS (This);
+ HiiConfigRouting = Private->HiiConfigRouting;
+ 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 (&gPlatformOverridesManagerGuid, mVariableName, Private->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ BufferSize = sizeof (PLAT_OVER_MNGR_DATA);
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Private->FakeNvData,
+ sizeof (PLAT_OVER_MNGR_DATA),
+ 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 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 <ConfigRequest> 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
+PlatOverMngrRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_CALLBACK_INFO *Private;
+ UINT16 KeyValue;
+ PLAT_OVER_MNGR_DATA *FakeNvData;
+ EFI_STATUS Status;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Configuration;
+
+ if (!HiiIsConfigHdrMatch (Configuration, &gPlatformOverridesManagerGuid, mVariableName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Progress = Configuration + StrLen (Configuration);
+ Private = EFI_CALLBACK_INFO_FROM_THIS (This);
+ FakeNvData = &Private->FakeNvData;
+ if (!HiiGetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData)) {
+ //
+ // FakeNvData can't be got from SetupBrowser, which doesn't need to be set.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (mCurrentPage == FORM_ID_ORDER) {
+ KeyValue = KEY_VALUE_ORDER_SAVE_AND_EXIT;
+ Status = CommitChanges (Private, KeyValue, FakeNvData);
+ }
+
+ return Status;
+}
+
+/**
+ This is the function that is called to provide results data to the driver. This data
+ consists of a unique key which is used to identify what data is either being passed back
+ or being asked for.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action A null-terminated Unicode string in <ConfigRequest> format.
+ @param KeyValue A unique Goto OpCode callback value which record user's selection.
+ 0x100 <= KeyValue <0x500 : user select a controller item in the first page;
+ KeyValue == 0x1234 : user select 'Refresh' in first page, or user select 'Go to Previous Menu' in second page
+ KeyValue == 0x1235 : user select 'Pci device filter' in first page
+ KeyValue == 0x1500 : user select 'order ... priority' item in second page
+ KeyValue == 0x1800 : user select 'commint changes' in third page
+ KeyValue == 0x2000 : user select 'Go to Previous Menu' in third page
+ @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 Always returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatOverMngrCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID KeyValue,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_CALLBACK_INFO *Private;
+ EFI_STATUS Status;
+ EFI_STRING_ID NewStringToken;
+ EFI_INPUT_KEY Key;
+ PLAT_OVER_MNGR_DATA *FakeNvData;
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = EFI_CALLBACK_INFO_FROM_THIS (This);
+ FakeNvData = &Private->FakeNvData;
+ if (!HiiGetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (KeyValue == KEY_VALUE_DRIVER_GOTO_PREVIOUS) {
+ UpdateDeviceSelectPage (Private, KeyValue, FakeNvData);
+ //
+ // Update page title string
+ //
+ NewStringToken = STRING_TOKEN (STR_TITLE);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"First, Select the controller by device path", NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ }
+
+ if (((KeyValue >= KEY_VALUE_DEVICE_OFFSET) && (KeyValue < KEY_VALUE_DEVICE_OFFSET + mMaxDeviceCount)) || (KeyValue == KEY_VALUE_ORDER_GOTO_PREVIOUS)) {
+ if (KeyValue == KEY_VALUE_ORDER_GOTO_PREVIOUS) {
+ KeyValue = (EFI_QUESTION_ID) (mSelectedCtrIndex + KEY_VALUE_DEVICE_OFFSET);
+ }
+ UpdateBindingDriverSelectPage (Private, KeyValue, FakeNvData);
+ //
+ // Update page title string
+ //
+ NewStringToken = STRING_TOKEN (STR_TITLE);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"Second, Select drivers for the previous selected controller", NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ }
+
+ if (KeyValue == KEY_VALUE_DRIVER_GOTO_ORDER) {
+ UpdatePrioritySelectPage (Private, KeyValue, FakeNvData);
+ //
+ // Update page title string
+ //
+ NewStringToken = STRING_TOKEN (STR_TITLE);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"Finally, Set the priority order for the drivers and save them", NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ }
+
+ if (KeyValue == KEY_VALUE_DEVICE_CLEAR) {
+ //
+ // Deletes all environment variable(s) that contain the override mappings info
+ //
+ FreeMappingDatabase (&mMappingDataBase);
+ Status = SaveOverridesMapping (&mMappingDataBase);
+ UpdateDeviceSelectPage (Private, KeyValue, FakeNvData);
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((KeyValue >= KEY_VALUE_DRIVER_OFFSET) && (KeyValue < KEY_VALUE_DRIVER_OFFSET + mDriverImageHandleCount)) {
+ mDriSelection[KeyValue - KEY_VALUE_DRIVER_OFFSET] = Value->b;
+ } else {
+ switch (KeyValue) {
+ case KEY_VALUE_DEVICE_REFRESH:
+ case KEY_VALUE_DEVICE_FILTER:
+ UpdateDeviceSelectPage (Private, KeyValue, FakeNvData);
+ //
+ // Update page title string
+ //
+ NewStringToken = STRING_TOKEN (STR_TITLE);
+ if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"First, Select the controller by device path", NULL) == 0) {
+ ASSERT (FALSE);
+ }
+ break;
+
+ case KEY_VALUE_ORDER_SAVE_AND_EXIT:
+ Status = CommitChanges (Private, KeyValue, FakeNvData);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Single Override Info too large, Saving Error!", NULL);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ HiiSetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData, NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the image handle of the platform override driver for a controller in the system.
+
+ @param This A pointer to the
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param ControllerHandle The device handle of the controller to check if a
+ driver override exists.
+ @param DriverImageHandle On input, a pointer to the previous driver image
+ handle returned by GetDriver(). On output, a
+ pointer to the next driver image handle. Passing
+ in a NULL, will return the first driver image
+ handle for ControllerHandle.
+
+ @retval EFI_SUCCESS The driver override for ControllerHandle was
+ returned in DriverImageHandle.
+ @retval EFI_NOT_FOUND A driver override for ControllerHandle was not
+ found.
+ @retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is NULL.
+ DriverImageHandle is not a handle that was returned
+ on a previous call to GetDriver().
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriver (
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the environment variable(s) that contain the override mappings from Controller Device Path to
+ // a set of Driver Device Paths, and initialize in memory database of the overrides that map Controller
+ // Device Paths to an ordered set of Driver Device Paths and Driver Handles. This action is only performed
+ // once and finished in first call.
+ //
+ if (!mEnvironmentVariableRead) {
+ mEnvironmentVariableRead = TRUE;
+
+ Status = InitOverridesMapping (&mMappingDataBase);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_INFO, "The status to Get Platform Driver Override Variable is %r\n", Status));
+ InitializeListHead (&mMappingDataBase);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // if the environment variable does not exist, just return not found
+ //
+ if (IsListEmpty (&mMappingDataBase)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return GetDriverFromMapping (
+ ControllerHandle,
+ DriverImageHandle,
+ &mMappingDataBase,
+ mCallerImageHandle
+ );
+}
+
+/**
+ Retrieves the device path of the platform override driver for a controller in the system.
+ This driver doesn't support this API.
+
+ @param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
+ PROTOCOL instance.
+ @param ControllerHandle The device handle of the controller to check if a driver override
+ exists.
+ @param DriverImagePath On input, a pointer to the previous driver device path returned by
+ GetDriverPath(). On output, a pointer to the next driver
+ device path. Passing in a pointer to NULL, will return the first
+ driver device path for ControllerHandle.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+GetDriverPath (
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DriverImagePath
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Used to associate a driver image handle with a device path that was returned on a prior call to the
+ GetDriverPath() service. This driver image handle will then be available through the
+ GetDriver() service. This driver doesn't support this API.
+
+ @param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
+ PROTOCOL instance.
+ @param ControllerHandle The device handle of the controller.
+ @param DriverImagePath A pointer to the driver device path that was returned in a prior
+ call to GetDriverPath().
+ @param DriverImageHandle The driver image handle that was returned by LoadImage()
+ when the driver specified by DriverImagePath was loaded
+ into memory.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+DriverLoaded (
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath,
+ IN EFI_HANDLE DriverImageHandle
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The driver Entry Point. The function will export a disk device class formset and
+ its callback function to hii database.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatDriOverrideDxeInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ VOID *Instance;
+
+ //
+ // There should only be one Form Configuration protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFormBrowser2ProtocolGuid,
+ NULL,
+ (VOID **) &FormBrowser2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // According to UEFI spec, there can be at most a single instance
+ // in the system of the EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL.
+ // So here we check the existence.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ NULL,
+ &Instance
+ );
+ //
+ // If there was no error, assume there is an installation and return error
+ //
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mCallerImageHandle = ImageHandle;
+ mCallbackInfo = AllocateZeroPool (sizeof (EFI_CALLBACK_INFO));
+ if (mCallbackInfo == NULL) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ mCallbackInfo->Signature = EFI_CALLBACK_INFO_SIGNATURE;
+ mCallbackInfo->ConfigAccess.ExtractConfig = PlatOverMngrExtractConfig;
+ mCallbackInfo->ConfigAccess.RouteConfig = PlatOverMngrRouteConfig;
+ mCallbackInfo->ConfigAccess.Callback = PlatOverMngrCallback;
+ mCallbackInfo->PlatformDriverOverride.GetDriver = GetDriver;
+ mCallbackInfo->PlatformDriverOverride.GetDriverPath = GetDriverPath;
+ mCallbackInfo->PlatformDriverOverride.DriverLoaded = DriverLoaded;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **) &mCallbackInfo->HiiConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ // Install Platform Driver Override Protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mCallbackInfo->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mCallbackInfo->ConfigAccess,
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ &mCallbackInfo->PlatformDriverOverride,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Publish our HII data
+ //
+ mCallbackInfo->RegisteredHandle = HiiAddPackages (
+ &gPlatformOverridesManagerGuid,
+ mCallbackInfo->DriverHandle,
+ VfrBin,
+ PlatDriOverrideDxeStrings,
+ NULL
+ );
+ if (mCallbackInfo->RegisteredHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ //
+ // Clear all the globle variable
+ //
+ mDriverImageHandleCount = 0;
+ mCurrentPage = 0;
+
+ return EFI_SUCCESS;
+
+Finish:
+ PlatDriOverrideDxeUnload (ImageHandle);
+
+ return Status;
+}
+
+/**
+ Unload its installed protocol.
+
+ @param[in] ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+PlatDriOverrideDxeUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ ASSERT (mCallbackInfo != NULL);
+
+ if (mCallbackInfo->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ mCallbackInfo->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mCallbackInfo->ConfigAccess,
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ &mCallbackInfo->PlatformDriverOverride,
+ NULL
+ );
+ }
+
+ if (mCallbackInfo->RegisteredHandle != NULL) {
+ HiiRemovePackages (mCallbackInfo->RegisteredHandle);
+ }
+
+ FreePool (mCallbackInfo);
+
+ if (mControllerToken != NULL) {
+ FreePool (mControllerToken);
+ }
+
+ if (mControllerDevicePathProtocol != NULL) {
+ FreePool (mControllerDevicePathProtocol);
+ }
+
+ if (mDriverImageToken != NULL) {
+ FreePool (mDriverImageToken);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.uni b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.uni
new file mode 100644
index 000000000..9905a28d7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.uni
@@ -0,0 +1,37 @@
+// /** @file
+// This driver produces UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL if this protocol doesn't exist.
+//
+// It doesn't install again if this protocol exists.
+// It only implements one interface GetDriver of PLATFORM_DRIVER_OVERRIDE_PROTOCOL protocol
+// and doesn't support other two interfaces GetDriverPath, DriverLoaded.
+//
+// This driver also offers an UI interface in device manager to let user configure
+// platform override protocol to override the default algorithm for matching
+// drivers to controllers.
+//
+// The main flow:
+// 1. It dynamicly locate all controller device path.
+// 2. It dynamicly locate all drivers which support binding protocol.
+// 3. It export and dynamicly update two menu to let user select the
+// mapping between drivers to controllers.
+// 4. It save all the mapping info in NV variables for the following boot,
+// which will be consumed by GetDriver API of the produced the platform override protocol.
+//
+// Caution: This module is a sample implementation for the test purpose.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL if this protocol doesn't exist"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL if this protocol doesn't exist. It only implements the GetDriver() interface of PLATFORM_DRIVER_OVERRIDE_PROTOCOL protocol This driver also offers an UI interface in device manager to let users configure PlatformOverrideProtocol to override the default algorithm for matching drivers to controllers.<BR><BR>\n"
+ "The main flow:<BR>\n"
+ "1. It dynamically locates all controller device path.<BR>\n"
+ "2. It dynamically locates all drivers which support binding protocol.<BR>\n"
+ "3. It exports and dynamicly updates two menu to let user select the mapping between drivers to controllers.<BR>\n"
+ "4. It saves all the mapping info in NV variables for the following boot, which will be consumed by GetDriver API of the produced the platform override protocol.<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxeExtra.uni
new file mode 100644
index 000000000..01210ef63
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PlatDriOverrideDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform Driver Override DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c
new file mode 100644
index 000000000..f91f038b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideLib.c
@@ -0,0 +1,1941 @@
+/** @file
+ Implementation of the shared functions to do the platform driver vverride mapping.
+
+ Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalPlatDriOverrideDxe.h"
+
+#define PLATFORM_OVERRIDE_ITEM_SIGNATURE SIGNATURE_32('p','d','o','i')
+ typedef struct _PLATFORM_OVERRIDE_ITEM {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT32 DriverInfoNum;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ ///
+ /// List of DRIVER_IMAGE_INFO
+ ///
+ LIST_ENTRY DriverInfoList;
+ EFI_HANDLE LastReturnedImageHandle;
+} PLATFORM_OVERRIDE_ITEM;
+
+#define DRIVER_IMAGE_INFO_SIGNATURE SIGNATURE_32('p','d','i','i')
+typedef struct _DRIVER_IMAGE_INFO {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
+ BOOLEAN UnLoadable;
+ BOOLEAN UnStartable;
+} DRIVER_IMAGE_INFO;
+
+#define DEVICE_PATH_STACK_ITEM_SIGNATURE SIGNATURE_32('d','p','s','i')
+typedef struct _DEVICE_PATH_STACK_ITEM{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} DEVICE_PATH_STACK_ITEM;
+
+
+LIST_ENTRY mDevicePathStack = INITIALIZE_LIST_HEAD_VARIABLE (mDevicePathStack);
+
+/**
+ Push a controller device path into a globle device path list.
+
+ @param DevicePath The controller device path to push into stack
+
+ @retval EFI_SUCCESS Device path successfully pushed into the stack.
+
+**/
+EFI_STATUS
+EFIAPI
+PushDevPathStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+
+ DevicePathStackItem = AllocateZeroPool (sizeof (DEVICE_PATH_STACK_ITEM));
+ ASSERT (DevicePathStackItem != NULL);
+ DevicePathStackItem->Signature = DEVICE_PATH_STACK_ITEM_SIGNATURE;
+ DevicePathStackItem->DevicePath = DuplicateDevicePath (DevicePath);
+ InsertTailList (&mDevicePathStack, &DevicePathStackItem->Link);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop a controller device path from a globle device path list
+
+ @param DevicePath The controller device path popped from stack
+
+ @retval EFI_SUCCESS Controller device path successfully popped.
+ @retval EFI_NOT_FOUND Stack is empty.
+
+**/
+EFI_STATUS
+EFIAPI
+PopDevPathStack (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+
+ ItemListIndex = mDevicePathStack.BackLink;
+ //
+ // Check if the stack is empty
+ //
+ if (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ if (DevicePath != NULL) {
+ *DevicePath = DuplicateDevicePath (DevicePathStackItem->DevicePath);
+ }
+ FreePool (DevicePathStackItem->DevicePath);
+ RemoveEntryList (&DevicePathStackItem->Link);
+ FreePool (DevicePathStackItem);
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check whether a controller device path is in a globle device path list
+
+ @param DevicePath The controller device path to check
+
+ @retval TRUE DevicePath exists in the stack.
+ @retval FALSE DevicePath does not exist in the stack.
+
+**/
+BOOLEAN
+EFIAPI
+CheckExistInStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+ UINTN DevicePathSize;
+
+ ItemListIndex = mDevicePathStack.BackLink;
+ while (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ if (DevicePathSize == GetDevicePathSize (DevicePathStackItem->DevicePath)) {
+ if (CompareMem (DevicePath, DevicePathStackItem->DevicePath, DevicePathSize) == 0) {
+ return TRUE;
+ }
+ }
+ ItemListIndex = ItemListIndex->BackLink;
+ }
+
+ return FALSE;
+}
+
+/**
+ Update the FV file device path if it is not valid.
+
+ According to a file GUID, 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 to check
+ On output, the updated valid FV file device path
+ @param FileGuid The FV file GUID
+ @param CallerImageHandle Image handle of the caller
+
+ @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
+ parameter
+ @retval EFI_UNSUPPORTED the input DevicePath does not contain FV file
+ GUID at all
+ @retval EFI_ALREADY_STARTED the input DevicePath has pointed to FV file, it
+ is valid
+ @retval EFI_SUCCESS Successfully updated the invalid DevicePath,
+ and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ IN EFI_GUID *FileGuid,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ 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;
+ BOOLEAN HasFvNode;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the device path points 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 point to a FV file, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if (FileGuid != NULL) {
+ if (!CompareGuid (GuidPoint, FileGuid)) {
+ //
+ // If the FV file is not the input file GUID, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ FileGuid = GuidPoint;
+ }
+
+ //
+ // Check to see if the device path contains memory map node
+ //
+ TempDevicePath = *DevicePath;
+ HasFvNode = FALSE;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Use old Device Path
+ //
+ if (DevicePathType (TempDevicePath) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (TempDevicePath) == HW_MEMMAP_DP) {
+ HasFvNode = TRUE;
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!HasFvNode) {
+ 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 Caller own FV. Caller and input wanted FV file usually are in the same FV
+ //
+ FindFvFile = FALSE;
+ FoundFvHandle = NULL;
+ Status = gBS->HandleProtocol (
+ CallerImageHandle,
+ &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) {
+ 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 (FindFvFile) {
+ //
+ // Build the shell device path
+ //
+ NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+ *DevicePath = NewDevicePath;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Gets the data and size of a variable.
+
+ 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
+GetVariableAndSize (
+ 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) {
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ BufferSize = 0;
+ }
+ }
+
+ *VariableSize = BufferSize;
+ return Buffer;
+}
+
+/**
+ Connect to the handle to a device on the device path.
+
+ 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 success, then still give one 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
+ConnectDevicePath (
+ 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;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ DevicePath = DuplicateDevicePath (DevicePathToConnect);
+ CopyOfDevicePath = DevicePath;
+ if (DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ 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);
+ ASSERT (Instance != NULL);
+
+ 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
+ //
+ Status = gDS->Dispatch ();
+ }
+
+ 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 fails, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect succeeds, 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;
+}
+
+/**
+ Free all the mapping database memory resource and initialize the mapping list entry.
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Mapping database successfully freed
+ @retval EFI_INVALID_PARAMETER MappingDataBase is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FreeMappingDatabase (
+ IN OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ //
+ // Free PLATFORM_OVERRIDE_ITEM.ControllerDevicePath[]
+ //
+ if (OverrideItem->ControllerDevicePath != NULL){
+ FreePool (OverrideItem->ControllerDevicePath);
+ }
+
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ //
+ // Free DRIVER_IMAGE_INFO.DriverImagePath[]
+ //
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->DriverImagePath != NULL) {
+ FreePool(DriverImageInfo->DriverImagePath);
+ }
+ //
+ // Free DRIVER_IMAGE_INFO itself
+ //
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ RemoveEntryList (&DriverImageInfo->Link);
+ FreePool (DriverImageInfo);
+ }
+ //
+ // Free PLATFORM_OVERRIDE_ITEM itself
+ //
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ InitializeListHead (MappingDataBase);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Create the mapping database according to variable.
+
+ Read the environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths, and create the mapping database in memory with those variable info.
+ VariableLayout{
+ //
+ // NotEnd indicate whether the variable is the last one, and has no subsequent variable need to load.
+ // Each variable has MaximumVariableSize limitation, so we maybe need multiple variables to store
+ // large mapping infos.
+ // The variable(s) name rule is PlatDriOver, PlatDriOver1, PlatDriOver2, ....
+ //
+ UINT32 NotEnd; //Zero is the last one.
+ //
+ // The entry which contains the mapping that Controller Device Path to a set of Driver Device Paths
+ // There are often multi mapping entries in a variable.
+ //
+ UINT32 SIGNATURE; //SIGNATURE_32('p','d','o','i')
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ UINT32 NotEnd; //Zero is the last one.
+ UINT32 SIGNATURE;
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ }
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Create the mapping database in memory successfully
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_NOT_FOUND Cannot find the 'PlatDriOver' NV variable
+ @retval EFI_VOLUME_CORRUPTED The found NV variable is corrupted
+
+**/
+EFI_STATUS
+EFIAPI
+InitOverridesMapping (
+ OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ UINTN BufferSize;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN VariableNum;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ UINT32 DriverNumber;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Corrupted;
+ UINT32 Signature;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN Index;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the environment variable(s) that contain the override mappings .
+ //
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiCallerIdGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Traverse all variables.
+ //
+ VariableNum = 1;
+ Corrupted = FALSE;
+ NotEnd = 0;
+ do {
+ VariableIndex = VariableBuffer;
+ if (VariableIndex + sizeof (UINT32) > (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ } else {
+ //
+ // End flag
+ //
+ NotEnd = *(UINT32*) VariableIndex;
+ }
+ //
+ // Traverse the entries containing the mapping that Controller Device Path
+ // to a set of Driver Device Paths within this variable.
+ //
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ while (VariableIndex < ((UINT8 *)VariableBuffer + BufferSize)) {
+ //
+ // Check signature of this entry
+ //
+ if (VariableIndex + sizeof (UINT32) > (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ break;
+ }
+ Signature = *(UINT32 *) VariableIndex;
+ if (Signature != PLATFORM_OVERRIDE_ITEM_SIGNATURE) {
+ Corrupted = TRUE;
+ break;
+ }
+ //
+ // Create PLATFORM_OVERRIDE_ITEM for this mapping
+ //
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ //
+ // Get DriverNum
+ //
+ if (VariableIndex + sizeof (UINT32) >= (UINT8 *) VariableBuffer + BufferSize) {
+ Corrupted = TRUE;
+ break;
+ }
+ DriverNumber = *(UINT32*) VariableIndex;
+ OverrideItem->DriverInfoNum = DriverNumber;
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ //
+ // Get ControllerDevicePath[]
+ //
+ ControllerDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (ControllerDevicePath);
+ //
+ // Align the VariableIndex since the controller device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ //
+ // Check buffer overflow.
+ //
+ if ((OverrideItem->ControllerDevicePath == NULL) || (VariableIndex < (UINT8 *) ControllerDevicePath) ||
+ (VariableIndex > (UINT8 *) VariableBuffer + BufferSize)) {
+ Corrupted = TRUE;
+ break;
+ }
+
+ //
+ // Get all DriverImageDevicePath[]
+ //
+ for (Index = 0; Index < DriverNumber; Index++) {
+ //
+ // Create DRIVER_IMAGE_INFO for this DriverDevicePath[]
+ //
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+
+ DriverDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (DriverDevicePath);
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+
+ //
+ // Check buffer overflow
+ //
+ if ((DriverImageInfo->DriverImagePath == NULL) || (VariableIndex < (UINT8 *) DriverDevicePath) ||
+ (VariableIndex < (UINT8 *) VariableBuffer + BufferSize)) {
+ Corrupted = TRUE;
+ break;
+ }
+ }
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ if (Corrupted) {
+ break;
+ }
+ }
+
+ FreePool (VariableBuffer);
+ if (Corrupted) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If there are additional variables (PlatDriOver1, PlatDriOver2, PlatDriOver3.....), get them.
+ // NotEnd indicates whether current variable is the end variable.
+ //
+ if (NotEnd != 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum++);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiCallerIdGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ if (VariableBuffer == NULL) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ } while (NotEnd != 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Calculate the needed size in NV variable for recording a specific PLATFORM_OVERRIDE_ITEM info.
+
+ @param OverrideItemListIndex Pointer to the list of a specific PLATFORM_OVERRIDE_ITEM
+
+ @return The needed size number
+
+**/
+UINTN
+EFIAPI
+GetOneItemNeededSize (
+ IN LIST_ENTRY *OverrideItemListIndex
+ )
+{
+ UINTN NeededSize;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ UINTN DevicePathSize;
+
+ NeededSize = 0;
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ NeededSize += sizeof (UINT32); //UINT32 SIGNATURE;
+ NeededSize += sizeof (UINT32); //UINT32 DriverNum;
+ DevicePathSize = GetDevicePathSize (OverrideItem->ControllerDevicePath);
+ NeededSize += DevicePathSize; // ControllerDevicePath
+ //
+ // Align the controller device path
+ //
+ NeededSize += ((sizeof(UINT32) - DevicePathSize) & (sizeof(UINT32) - 1));
+ //
+ // Traverse the Driver Info List of this Override Item
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ NeededSize += DevicePathSize; //DriverDevicePath
+ //
+ // Align the driver image device path
+ //
+ NeededSize += ((sizeof(UINT32) - DevicePathSize) & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ return NeededSize;
+}
+
+/**
+ Deletes all environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths.
+
+ @retval EFI_SUCCESS Delete all variable(s) successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteOverridesVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINTN VariableNum;
+ UINTN BufferSize;
+ UINTN Index;
+ CHAR16 OverrideVariableName[40];
+
+ //
+ // Get environment variable(s) number
+ //
+ VariableNum = 0;
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiCallerIdGuid, &BufferSize);
+ VariableNum++;
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check NotEnd to get all PlatDriOverX variable(s)
+ //
+ while ((VariableBuffer != NULL) && ((*(UINT32*)VariableBuffer) != 0)) {
+ FreePool (VariableBuffer);
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiCallerIdGuid, &BufferSize);
+ VariableNum++;
+ }
+
+ //
+ // Delete PlatDriOver and all additional variables, if exist.
+ //
+ Status = gRT->SetVariable (
+ L"PlatDriOver",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ for (Index = 1; Index < VariableNum; Index++) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", Index);
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Save the memory mapping database into NV environment variable(s).
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_SUCCESS Save memory mapping database successfully
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+
+**/
+EFI_STATUS
+EFIAPI
+SaveOverridesMapping (
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN NumIndex;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ItemIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ UINTN VariableNeededSize;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINTN OneItemNeededSize;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsListEmpty (MappingDataBase)) {
+ Status = DeleteOverridesVariables ();
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the the maximum size of an individual EFI variable in current system
+ //
+ gRT->QueryVariableInfo (
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+
+ NumIndex = 0;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ //
+ // Try to find the most proper variable size which <= MaximumVariableSize,
+ // but can contain mapping info as much as possible
+ //
+ VariableNeededSize = sizeof (UINT32); // NotEnd;
+ ItemIndex = OverrideItemListIndex;
+ NotEnd = FALSE;
+ //
+ // Traverse all PLATFORM_OVERRIDE_ITEMs and get the total size.
+ //
+ while (!IsNull (MappingDataBase, ItemIndex)) {
+ OneItemNeededSize = GetOneItemNeededSize (ItemIndex);
+ //
+ // If the total size exceeds the MaximumVariableSize, then we must use
+ // multiple variables.
+ //
+ if ((VariableNeededSize +
+ OneItemNeededSize +
+ StrSize (L"PlatDriOver ")
+ ) >= MaximumVariableSize
+ ) {
+ NotEnd = TRUE;
+ break;
+ }
+
+ VariableNeededSize += OneItemNeededSize;
+ ItemIndex = GetNextNode (MappingDataBase, ItemIndex);
+ }
+
+ if (NotEnd != 0) {
+ if (VariableNeededSize == sizeof (UINT32)) {
+ //
+ // If an individual EFI variable cannot contain a single Item, return error
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // VariableNeededSize is the most proper variable size, allocate variable buffer
+ // ItemIndex now points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ VariableBuffer = AllocateZeroPool (VariableNeededSize);
+ ASSERT (VariableBuffer != NULL);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+
+ //
+ // Fill the variable buffer according to MappingDataBase
+ //
+ VariableIndex = VariableBuffer;
+ *(UINT32 *) VariableIndex = NotEnd;
+ VariableIndex += sizeof (UINT32); // pass NotEnd
+ //
+ // ItemIndex points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ while (OverrideItemListIndex != ItemIndex){
+ *(UINT32 *) VariableIndex = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ VariableIndex += sizeof (UINT32); // pass SIGNATURE
+
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ *(UINT32 *) VariableIndex = OverrideItem->DriverInfoNum;
+ VariableIndex += sizeof (UINT32); // pass DriverNum
+
+ CopyMem (VariableIndex, OverrideItem->ControllerDevicePath, GetDevicePathSize (OverrideItem->ControllerDevicePath));
+ VariableIndex += GetDevicePathSize (OverrideItem->ControllerDevicePath); // pass ControllerDevicePath
+
+ //
+ // Align the VariableIndex since the controller device path may not be aligned
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ //
+ // Save the Driver Info List of this PLATFORM_OVERRIDE_ITEM
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ CopyMem (VariableIndex, DriverImageInfo->DriverImagePath, GetDevicePathSize (DriverImageInfo->DriverImagePath));
+ VariableIndex += GetDevicePathSize (DriverImageInfo->DriverImagePath); // pass DriverImageDevicePath
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ ASSERT (((UINTN)VariableIndex - (UINTN)VariableBuffer) == VariableNeededSize);
+
+ if (NumIndex == 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver");
+ } else {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", NumIndex );
+ }
+
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VariableNeededSize,
+ VariableBuffer
+ );
+ FreePool (VariableBuffer);
+
+ if (EFI_ERROR (Status)) {
+ if (NumIndex > 0) {
+ //
+ // Delete all PlatDriOver variables when full mapping can't be set.
+ //
+ DeleteOverridesVariables ();
+ }
+ return Status;
+ }
+
+ NumIndex ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the first Binding protocol which has the specific image handle.
+
+ @param ImageHandle The Image handle
+ @param BindingHandle The BindingHandle of the found Driver Binding protocol.
+ If Binding protocol is not found, it is set to NULL.
+
+ @return Pointer into the Binding Protocol interface
+ @retval NULL The parameter is not valid or the binding protocol is not found.
+
+**/
+EFI_DRIVER_BINDING_PROTOCOL *
+EFIAPI
+GetBindingProtocolFromImageHandle (
+ IN EFI_HANDLE ImageHandle,
+ OUT EFI_HANDLE *BindingHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBindingInterface;
+
+ if (BindingHandle == NULL || ImageHandle == NULL) {
+ return NULL;
+ }
+ //
+ // Get all drivers which support driver binding protocol
+ //
+ DriverBindingHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ DriverBindingInterface = NULL;
+ Status = gBS->OpenProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBindingInterface,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DriverBindingInterface->ImageHandle == ImageHandle) {
+ *BindingHandle = DriverBindingHandleBuffer[Index];
+ FreePool (DriverBindingHandleBuffer);
+ return DriverBindingInterface;
+ }
+ }
+
+ //
+ // If no Driver Binding Protocol instance is found
+ //
+ FreePool (DriverBindingHandleBuffer);
+ *BindingHandle = NULL;
+ return NULL;
+}
+
+/**
+ Return the current TPL.
+
+ @return Current TPL
+
+**/
+EFI_TPL
+GetCurrentTpl (
+ VOID
+ )
+{
+ EFI_TPL Tpl;
+
+ Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (Tpl);
+
+ return Tpl;
+}
+
+
+/**
+ Retrieves the image handle of the platform override driver for a controller in
+ the system from the memory mapping database.
+
+ @param ControllerHandle The device handle of the controller to check if
+ a driver override exists.
+ @param DriverImageHandle On input, the previously returnd driver image handle.
+ On output, a pointer to the next driver handle.
+ Passing in a pointer to NULL, will return the
+ first driver handle for ControllerHandle.
+ @param MappingDataBase Mapping database list entry pointer
+ @param CallerImageHandle The caller driver's image handle, for
+ UpdateFvFileDevicePath use.
+
+ @retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is not
+ a valid handle. Or DriverImagePath is not a
+ device path that was returned on a previous call
+ to GetDriverPath().
+ @retval EFI_NOT_FOUND A driver override for ControllerHandle was not
+ found.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SUCCESS The driver override for ControllerHandle was
+ returned in DriverImagePath.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriverFromMapping (
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE *DriverImageHandle,
+ IN LIST_ENTRY *MappingDataBase,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ BOOLEAN ControllerFound;
+ BOOLEAN ImageFound;
+ EFI_HANDLE *ImageHandleBuffer;
+ UINTN ImageHandleCount;
+ UINTN Index;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_HANDLE DriverBindingHandle;
+ BOOLEAN FoundLastReturned;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ EFI_DEVICE_PATH_PROTOCOL *TempDriverImagePath;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get the device path of ControllerHandle
+ //
+ Status = gBS->HandleProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ControllerDevicePath
+ );
+ if (EFI_ERROR (Status) || ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ OverrideItem = NULL;
+ ControllerFound = FALSE;
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ ControllerFound = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ if (!ControllerFound) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Passing in a pointer to NULL, will return the first driver device path for ControllerHandle.
+ // Check whether the driverImagePath is not a device path that was returned on a previous call to GetDriverPath().
+ //
+ if (*DriverImageHandle != NULL) {
+ if (*DriverImageHandle != OverrideItem->LastReturnedImageHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // The GetDriverPath() may be called recursively, because it use ConnectDevicePath() internally,
+ // so should check whether there is a dead loop.
+ // Here use a controller device path stack to record all processed controller device path during a GetDriverPath() call,
+ // and check the controller device path whether appear again during the GetDriverPath() call.
+ //
+ if (CheckExistInStack (OverrideItem->ControllerDevicePath)) {
+ //
+ // There is a dependency dead loop if the ControllerDevicePath appear in stack twice
+ //
+ return EFI_UNSUPPORTED;
+ }
+ PushDevPathStack (OverrideItem->ControllerDevicePath);
+
+ //
+ // Check every override driver, try to load and start them
+ //
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle == NULL) {
+ //
+ // Skip if the image is unloadable or unstartable
+ //
+ if ((!DriverImageInfo->UnLoadable) && ((!DriverImageInfo->UnStartable))) {
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ //
+ // If the image device path contains an FV node, check the 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.
+ //
+ Status = UpdateFvFileDevicePath (&TempDriverImagePath, NULL, CallerImageHandle);
+ if (!EFI_ERROR (Status)) {
+ FreePool (DriverImageInfo->DriverImagePath);
+ DriverImageInfo->DriverImagePath = TempDriverImagePath;
+ }
+ //
+ // Get all Loaded Image protocol to check whether the driver image has been loaded and started
+ //
+ ImageFound = FALSE;
+ ImageHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &ImageHandleCount,
+ &ImageHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (ImageHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for(Index = 0; Index < ImageHandleCount; Index ++) {
+ //
+ // Get the EFI Loaded Image Device Path Protocol
+ //
+ LoadedImageDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ ImageHandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Maybe not all EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL existed.
+ //
+ continue;
+ }
+
+ DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ if (DevicePathSize == GetDevicePathSize (LoadedImageDevicePath)) {
+ if (CompareMem (
+ DriverImageInfo->DriverImagePath,
+ LoadedImageDevicePath,
+ GetDevicePathSize (LoadedImageDevicePath)
+ ) == 0
+ ) {
+ ImageFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (ImageFound) {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image Handle.
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandleBuffer[Index],
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandleBuffer[Index];
+ } else if (GetCurrentTpl() <= TPL_CALLBACK){
+ //
+ // The driver image has not been loaded and started. Try to load and start it now.
+ // Try to connect all device in the driver image path.
+ //
+ // Note: LoadImage() and StartImage() should be called under CALLBACK TPL in theory, but
+ // since many device need to be connected in CALLBACK level environment( e.g. Usb devices )
+ // and the Fat and Patition driver can endure executing in CALLBACK level in fact, so here permit
+ // to use LoadImage() and StartImage() in CALLBACK TPL.
+ //
+ Status = ConnectDevicePath (DriverImageInfo->DriverImagePath);
+ //
+ // check whether it points to a PCI Option Rom image,
+ // and try to use bus override protocol to get its first option rom image driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ ImageHandle = NULL;
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image handle
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandle,
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ }
+ //
+ // Skip if any device cannot be connected now, future passes through GetDriver() may be able to load that driver.
+ // Only file path media or FwVol Device Path Node remain if all device is connected
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ if (((DevicePathType (TempDriverImagePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDriverImagePath) == MEDIA_FILEPATH_DP)) ||
+ (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempDriverImagePath) != NULL)
+ ) {
+ //
+ // Try to load the driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ Status = gBS->LoadImage (
+ FALSE,
+ CallerImageHandle,
+ TempDriverImagePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to start the driver
+ //
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (EFI_ERROR (Status)){
+ DriverImageInfo->UnStartable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ } else {
+ //
+ // Find its related driver binding protocol
+ // Driver binding handle may be different with its driver's Image handle
+ //
+ DriverBindingHandle = NULL;
+ DriverBinding = GetBindingProtocolFromImageHandle (
+ ImageHandle,
+ &DriverBindingHandle
+ );
+ ASSERT (DriverBinding != NULL);
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ } else {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+ DriverImageInfo->UnLoadable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ }
+ }
+ }
+ FreePool (ImageHandleBuffer);
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+ //
+ // Finish try to load and start the override driver of a controller, popup the controller's device path
+ //
+ PopDevPathStack (NULL);
+
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ FoundLastReturned = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle != NULL) {
+ if ((*DriverImageHandle == NULL) || FoundLastReturned) {
+ //
+ // If DriverImageHandle is NULL, then we just need to return the first driver.
+ // If FoundLastReturned, this means we have just encountered the previously returned driver.
+ // For both cases, we just return the image handle of this driver.
+ //
+ OverrideItem->LastReturnedImageHandle = DriverImageInfo->ImageHandle;
+ *DriverImageHandle = DriverImageInfo->ImageHandle;
+ return EFI_SUCCESS;
+ } else if (*DriverImageHandle == DriverImageInfo->ImageHandle){
+ //
+ // We have found the previously returned driver.
+ //
+ FoundLastReturned = TRUE;
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check mapping database whether already has the mapping info which
+ records the input Controller to input DriverImage.
+
+ @param ControllerDevicePath The controller device path is to be check.
+ @param DriverImageDevicePath The driver image device path is to be check.
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverInfoNum the controller's total override driver number
+ @param DriverImageNO The driver order number for the input DriverImage.
+ If the DriverImageDevicePath is NULL, DriverImageNO is not set.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath or MappingDataBase is NULL.
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS The controller's total override driver number and
+ input DriverImage's order number is correctly return.
+**/
+EFI_STATUS
+EFIAPI
+CheckMapping (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath OPTIONAL,
+ IN LIST_ENTRY *MappingDataBase,
+ OUT UINT32 *DriverInfoNum OPTIONAL,
+ OUT UINT32 *DriverImageNO OPTIONAL
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ if (!Found) {
+ //
+ // ControllerDevicePath is not in MappingDataBase
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+ if (DriverInfoNum != NULL) {
+ *DriverInfoNum = OverrideItem->DriverInfoNum;
+ }
+
+ //
+ // If DriverImageDevicePath is NULL, skip checking DriverImageDevicePath
+ // in the controller's Driver Image Info List
+ //
+ if (DriverImageDevicePath == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageNO++;
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ if (!Found) {
+ //
+ // DriverImageDevicePath is not found in the controller's Driver Image Info List
+ //
+ return EFI_NOT_FOUND;
+ } else {
+ if (DriverImageNO != NULL) {
+ *DriverImageNO = ImageNO;
+ }
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Insert a driver image as a controller's override driver into the mapping database.
+ The driver image's order number is indicated by DriverImageNO.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverImageNO The inserted order number. If this number is taken,
+ the larger available number will be used.
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or DriverImageDevicePath is NULL
+ or MappingDataBase is NULL
+ @retval EFI_ALREADY_STARTED The input Controller to input DriverImage has been
+ recorded into the mapping database.
+ @retval EFI_SUCCESS The Controller and DriverImage are inserted into
+ the mapping database successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase,
+ IN UINT32 DriverImageNO
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DriverImageDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If the driver is already in the controller's Driver Image Info List,
+ // just return EFI_ALREADY_STARTED.
+ //
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (Status == EFI_SUCCESS) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Search the input ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+ //
+ // If cannot find, this is a new controller item
+ // Add the Controller related PLATFORM_OVERRIDE_ITEM structrue in mapping data base
+ //
+ if (!Found) {
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ }
+
+ //
+ // Prepare the driver image related DRIVER_IMAGE_INFO structure.
+ //
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverImageDevicePath);
+ //
+ // Find the driver image wanted order location
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ if (ImageNO == (DriverImageNO - 1)) {
+ //
+ // find the wanted order location, insert it
+ //
+ InsertTailList (ImageInfoListIndex, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ Found = TRUE;
+ break;
+ }
+ ImageNO++;
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ }
+
+ if (!Found) {
+ //
+ // if not find the wanted order location, add it as last item of the controller mapping item
+ //
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete a controller's override driver from the mapping database.
+
+ @param ControllerDevicePath The controller device path will be deleted
+ when all drivers images on it are removed.
+ @param DriverImageDevicePath The driver image device path will be delete.
+ If NULL, all driver image will be delete.
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER ControllerDevicePath is NULL, or MappingDataBase is NULL
+ @retval EFI_NOT_FOUND ControllerDevicePath is not found in MappingDataBase or
+ DriverImageDevicePath is not found in the found DriverImage Info list.
+ @retval EFI_SUCCESS Delete the specified driver successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINTN DevicePathSize;
+
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If ControllerDevicePath is not found in mapping database, return EFI_NOT_FOUND.
+ //
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = GetFirstNode (MappingDataBase);
+ while (!IsNull (MappingDataBase, OverrideItemListIndex)) {
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ DevicePathSize
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = GetNextNode (MappingDataBase, OverrideItemListIndex);
+ }
+
+ ASSERT (Found);
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+
+ Found = FALSE;
+ ImageInfoListIndex = GetFirstNode (&OverrideItem->DriverInfoList);
+ while (!IsNull (&OverrideItem->DriverInfoList, ImageInfoListIndex)) {
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageInfoListIndex = GetNextNode (&OverrideItem->DriverInfoList, ImageInfoListIndex);
+ if (DriverImageDevicePath != NULL) {
+ //
+ // Search for the specified DriverImageDevicePath and remove it, then break.
+ //
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ break;
+ }
+ }
+ } else {
+ //
+ // Remove all existing driver image info entries, so no break here.
+ //
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ }
+ }
+
+ //
+ // Confirm all driver image info entries have been removed,
+ // if DriverImageDevicePath is NULL.
+ //
+ if (DriverImageDevicePath == NULL) {
+ ASSERT (OverrideItem->DriverInfoNum == 0);
+ }
+ //
+ // If Override Item has no driver image info entry, then delete this item.
+ //
+ if (OverrideItem->DriverInfoNum == 0) {
+ FreePool(OverrideItem->ControllerDevicePath);
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ if (!Found) {
+ //
+ // DriverImageDevicePath is not NULL and cannot be found in the controller's
+ // driver image info list.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatOverMngr.h b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatOverMngr.h
new file mode 100644
index 000000000..766521159
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatOverMngr.h
@@ -0,0 +1,61 @@
+/** @file
+
+ The defintions are required both by Source code and Vfr file.
+ The PLAT_OVER_MNGR_DATA structure, form guid and Ifr question ID are defined.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PLAT_OVER_MNGR_H_
+#define _PLAT_OVER_MNGR_H_
+
+#include <Guid/PlatDriOverrideHii.h>
+
+//
+// The max number of the supported driver list.
+//
+#define MAX_CHOICE_NUM 0x00FF
+#define UPDATE_DATA_SIZE 0x1000
+
+#define FORM_ID_DEVICE 0x1100
+#define FORM_ID_DRIVER 0x1200
+#define FORM_ID_ORDER 0x1500
+
+#define KEY_VALUE_DEVICE_OFFSET 0x0100
+#define KEY_VALUE_DRIVER_OFFSET 0x0300
+
+#define KEY_VALUE_DEVICE_REFRESH 0x1234
+#define KEY_VALUE_DEVICE_FILTER 0x1235
+#define KEY_VALUE_DEVICE_CLEAR 0x1236
+
+#define KEY_VALUE_DRIVER_GOTO_PREVIOUS 0x1300
+#define KEY_VALUE_DRIVER_GOTO_ORDER 0x1301
+
+#define KEY_VALUE_ORDER_GOTO_PREVIOUS 0x2000
+#define KEY_VALUE_ORDER_SAVE_AND_EXIT 0x1800
+
+#define VARSTORE_ID_PLAT_OVER_MNGR 0x1000
+
+#define LABEL_END 0xffff
+
+typedef struct {
+ UINT8 DriOrder[MAX_CHOICE_NUM];
+ UINT8 PciDeviceFilter;
+} PLAT_OVER_MNGR_DATA;
+
+//
+// Field offset of structure PLAT_OVER_MNGR_DATA
+//
+#define VAR_OFFSET(Field) ((UINTN) &(((PLAT_OVER_MNGR_DATA *) 0)->Field))
+#define DRIVER_ORDER_VAR_OFFSET (VAR_OFFSET (DriOrder))
+
+//
+// Tool automatic generated Question Id start from 1
+// In order to avoid to conflict them, the Driver Selection and Order QuestionID offset is defined from 0x0500.
+//
+#define QUESTION_ID_OFFSET 0x0500
+#define DRIVER_ORDER_QUESTION_ID (VAR_OFFSET (DriOrder) + QUESTION_ID_OFFSET)
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatformDriOverrideDxe.inf b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatformDriOverrideDxe.inf
new file mode 100644
index 000000000..97c8e3cce
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatformDriOverrideDxe.inf
@@ -0,0 +1,109 @@
+## @file
+# This driver produces UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL if this protocol doesn't exist.
+# It doesn't install again if this protocol exists.
+# It only implements one interface GetDriver of PLATFORM_DRIVER_OVERRIDE_PROTOCOL protocol
+# and doesn't support other two interfaces GetDriverPath, DriverLoaded.
+#
+# This driver also offers an UI interface in device manager to let user configure
+# platform override protocol to override the default algorithm for matching
+# drivers to controllers.
+#
+# The main flow:
+# 1. It dynamicly locate all controller device path.
+# 2. It dynamicly locate all drivers which support binding protocol.
+# 3. It export and dynamicly update two menu to let user select the
+# mapping between drivers to controllers.
+# 4. It save all the mapping info in NV variables for the following boot,
+# which will be consumed by GetDriver API of the produced the platform override protocol.
+#
+# Caution: This module is a sample implementation for the test purpose.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatDriOverrideDxe
+ MODULE_UNI_FILE = PlatDriOverrideDxe.uni
+ FILE_GUID = 35034CE2-A6E5-4fb4-BABE-A0156E9B2549
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PlatDriOverrideDxeInit
+ UNLOAD_IMAGE = PlatDriOverrideDxeUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ VfrStrings.uni
+ Vfr.vfr
+ PlatDriOverrideDxe.c
+ PlatOverMngr.h
+ PlatDriOverrideLib.c
+ InternalPlatDriOverrideDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ HiiLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DevicePathLib
+ DxeServicesTableLib
+ UefiRuntimeServicesTableLib
+ PrintLib
+
+[Guids]
+ #
+ # This GUID C Name is not required for build since it is from UefiLib and not directly used by this module source.
+ # gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" # this variable specifies the platform supported language string (RFC 4646 format)
+ # gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"Lang" # this variable specifies the platform supported language string (ISO 639-2 format)
+ #
+ # There could be more than one variables, from PlatDriOver, PlatDriOver1, PlatDriOver2,...
+ # gEfiCallerIdGuid ## Private ## Variable:L"PlatDriOver"
+ #
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## UNDEFINED
+ ## SOMETIMES_CONSUMES ## GUID # HiiIsConfigHdrMatch Data
+ ## SOMETIMES_PRODUCES ## GUID # HiiGetBrowserData Data
+ ## SOMETIMES_CONSUMES ## GUID # HiiSetBrowserData Data
+ ## SOMETIMES_PRODUCES ## GUID # HiiConstructConfigHdr Data
+ ## CONSUMES ## HII
+ gPlatformOverridesManagerGuid
+
+[Protocols]
+ gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES # Get Driver Name if ComponentName2Protocol exists
+ gEfiComponentNameProtocolGuid ## SOMETIMES_CONSUMES # Get Driver Name if ComponentNameProtocol exists and ComponentName2Protocol doesn't exist
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES # Get Driver Name from EFI UI section if ComponentName2Protocol and ComponentNameProtocol don't exist
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES # Find the PCI device if PciIo protocol is installed
+ gEfiBusSpecificDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES # Check whether the PCI device contains one or more efi drivers in its option rom by this protocol
+
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## SOMETIMES_CONSUMES # Show the drivers in the second page that support DriverBindingProtocol, LoadedImageProtocol and LoadedImageDevicePathProtocol
+
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiPlatformDriverOverrideProtocolGuid ## PRODUCES
+ ## PRODUCES
+ ## SOMETIMES_CONSUMES # Show the controller device in the first page that support DevicePathProtocol
+ gEfiDevicePathProtocolGuid
+
+[Depex]
+ gEfiFormBrowser2ProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PlatDriOverrideDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/Vfr.vfr b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/Vfr.vfr
new file mode 100644
index 000000000..23aa90bd0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/Vfr.vfr
@@ -0,0 +1,100 @@
+// *++
+//
+// Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// Vfr.vfr
+//
+// Abstract:
+//
+// Platform driver Override manager formset
+//
+//
+// --*/
+
+#include "PlatOverMngr.h"
+
+#define EFI_DISK_DEVICE_CLASS 0x01
+
+formset
+ guid = PLAT_OVER_MNGR_GUID,
+ title = STRING_TOKEN(STR_ENTRY_TITLE),
+ help = STRING_TOKEN(STR_TITLE_HELP),
+
+ varstore PLAT_OVER_MNGR_DATA,
+ varid = VARSTORE_ID_PLAT_OVER_MNGR,
+ name = Data,
+ guid = PLAT_OVER_MNGR_GUID;
+
+ form formid = FORM_ID_DEVICE,
+ title = STRING_TOKEN(STR_TITLE);
+
+ text
+ help = STRING_TOKEN(STR_FIRST_REFRESH_HELP),
+ text = STRING_TOKEN(STR_FIRST_REFRESH),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_DEVICE_REFRESH;
+
+ checkbox varid = Data.PciDeviceFilter,
+ prompt = STRING_TOKEN(STR_PCI_DEVICE_FILTER_PROMPT),
+ help = STRING_TOKEN(STR_PCI_DEVICE_FILTER_HELP),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_DEVICE_FILTER,
+ endcheckbox;
+
+ label FORM_ID_DEVICE;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_ID_DEVICE,
+ prompt = STRING_TOKEN(STR_CLEAR_ALL),
+ help = STRING_TOKEN(STR_CLEAR_ALL_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ key = KEY_VALUE_DEVICE_CLEAR;
+ endform;
+
+ form formid = FORM_ID_DRIVER,
+ title = STRING_TOKEN(STR_TITLE);
+
+ goto FORM_ID_DEVICE,
+ prompt = STRING_TOKEN(STR_GOTO_PREVIOUS),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_DRIVER_GOTO_PREVIOUS;
+
+ goto FORM_ID_ORDER,
+ prompt = STRING_TOKEN(STR_TITLE_ORDER),
+ help = STRING_TOKEN(STR_TITLE_ORDER_HELP),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_DRIVER_GOTO_ORDER;
+
+ label FORM_ID_DRIVER;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_ID_ORDER,
+ title = STRING_TOKEN(STR_TITLE);
+
+ goto FORM_ID_DRIVER,
+ prompt = STRING_TOKEN(STR_GOTO_PREVIOUS),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_ORDER_GOTO_PREVIOUS;
+
+ label FORM_ID_ORDER;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN (STR_NULL_STRING),
+ text = STRING_TOKEN (STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ key = KEY_VALUE_ORDER_SAVE_AND_EXIT;
+ endform;
+
+endformset;
diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/VfrStrings.uni b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/VfrStrings.uni
new file mode 100644
index 000000000..e060e8c7a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/VfrStrings.uni
@@ -0,0 +1,59 @@
+// *++
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+// VfrStrings.vfr
+//
+// Abstract:
+//
+// String definitions for platform driver override manager formset.
+//
+//
+// --*/
+
+
+/=#
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+
+#string STR_ENTRY_TITLE #language en-US "Platform Driver Override selection"
+ #language fr-FR "fr-FR: Platform Driver Override selection"
+#string STR_TITLE #language en-US " "
+ #language fr-FR " "
+#string STR_TITLE_HELP #language en-US "Select driver connection order as platform policy for specific controller"
+ #language fr-FR "fr-FR: Select driver connection order as platform policy for specific controller"
+#string STR_TITLE_ORDER #language en-US "Order Platform Override driver priority"
+ #language fr-FR "fr-FR: Order Platform Override driver priority"
+#string STR_TITLE_ORDER_HELP #language en-US "Select the drivers you need to add as previous controller's override driver in the following check box, and go on to order them priority in this entry. '?' means you have not select the driver"
+ #language fr-FR "fr-FR: Select the drivers you need to add as previous controller's override driver in the following check box, and go on to order them priority in this entry. '?' means you have not select the driver"
+#string STR_FIRST_REFRESH #language en-US "Please refresh page firstly"
+ #language fr-FR "fr-FR: Please Refresh page firstly"
+#string STR_FIRST_REFRESH_HELP #language en-US "When enter the page at first time, refresh is needed to show all the controller device paths"
+ #language fr-FR "fr-FR: When enter the page at first time, refresh is needed to show all the controller device paths"
+#string STR_REFRESH #language en-US "Refresh"
+ #language fr-FR "fr-FR: Refresh"
+#string STR_REFRESH_HELP #language en-US "Refresh to show all the current controllers device paths"
+ #language fr-FR "fr-FR: Refresh to show all the current controllers device paths"
+#string STR_PCI_DEVICE_FILTER_PROMPT #language en-US "PCI device filter"
+ #language fr-FR "fr-FR: PCI device filter"
+#string STR_PCI_DEVICE_FILTER_HELP #language en-US "Only show the PCI device which has EFI driver in its option rom"
+ #language fr-FR "fr-FR: Only show the PCI device which has EFI driver in its option rom"
+#string STR_DRIVER_DEFAULT_NAME #language en-US "Driver Default Name"
+ #language fr-FR "fr-FR: Driver Default Name"
+#string STR_GOTO_HELP_DRIVER #language en-US "Select the controller device path which you need combine override drivers, '**' means you have saved its info before"
+ #language fr-FR "fr-FR: Select the controller device path which you need combine override drivers"
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_GOTO_PREVIOUS #language en-US "Go to Previous Menu"
+ #language fr-FR "fr-FR: Go to Previous Menu"
+#string STR_SAVE_AND_EXIT #language en-US "Commit Changes"
+ #language fr-FR "fr-FR: Commit Changes"
+#string STR_CLEAR_ALL #language en-US "Clear all mapping record!"
+ #language fr-FR "fr-FR: Clear all mapping record!"
+#string STR_CLEAR_ALL_HELP #language en-US "Deletes all environment variable(s) that contain the override mappings info"
+ #language fr-FR "fr-FR: Clear all mapping record!"
diff --git a/roms/edk2/MdeModulePkg/Universal/PrintDxe/Print.c b/roms/edk2/MdeModulePkg/Universal/PrintDxe/Print.c
new file mode 100644
index 000000000..c417a2c81
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PrintDxe/Print.c
@@ -0,0 +1,163 @@
+/** @file
+ This driver produces Print2 protocols layered on top of the PrintLib from the MdePkg.
+
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/Print2.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+/**
+ Implementaion of the UnicodeValueToString service in EFI_PRINT2_PROTOCOL.
+
+ If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, then ASSERT().
+
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Unicode string.
+ @param Flags The bitmask of flags that specify left justification, zero
+ pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in Buffer,
+ not including the Null-terminator.
+
+ @return If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, return 0.
+ Otherwise, return the number of Unicode characters in Buffer not
+ including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+PrintDxeUnicodeValueToString (
+ IN OUT CHAR16 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+#ifdef DISABLE_NEW_DEPRECATED_INTERFACES
+ //
+ // If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, then the
+ // PrintLib API UnicodeValueToString is already deprecated.
+ // In this case, ASSERT will be triggered and zero will be returned for the
+ // implementation of the UnicodeValueToString service in EFI_PRINT2_PROTOCOL
+ // to indicate that the service is no longer supported.
+ //
+ DEBUG ((DEBUG_ERROR, "PrintDxe: The UnicodeValueToString service in EFI_PRINT2_PROTOCOL is no longer supported for security reason.\n"));
+ DEBUG ((DEBUG_ERROR, "PrintDxe: Please consider using the UnicodeValueToStringS service in EFI_PRINT2S_PROTOCOL.\n"));
+ ASSERT (FALSE);
+ return 0;
+#else
+ return UnicodeValueToString (Buffer, Flags, Value, Width);
+#endif
+}
+
+/**
+ Implementaion of the AsciiValueToString service in EFI_PRINT2_PROTOCOL.
+
+ If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, then ASSERT().
+
+ @param Buffer A pointer to the output buffer for the produced
+ Null-terminated ASCII string.
+ @param Flags The bitmask of flags that specify left justification, zero
+ pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of ASCII characters to place in Buffer,
+ not including the Null-terminator.
+
+ @return If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, return 0.
+ Otherwise, return the number of ASCII characters in Buffer not
+ including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+PrintDxeAsciiValueToString (
+ OUT CHAR8 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+#ifdef DISABLE_NEW_DEPRECATED_INTERFACES
+ //
+ // If the macro DISABLE_NEW_DEPRECATED_INTERFACES is defined, then the
+ // PrintLib API AsciiValueToString is already deprecated.
+ // In this case, ASSERT will be triggered and zero will be returned for the
+ // implementation of the AsciiValueToString service in EFI_PRINT2_PROTOCOL
+ // to indicate that the service is no longer supported.
+ //
+ DEBUG ((DEBUG_ERROR, "PrintDxe: The AsciiValueToString service in EFI_PRINT2_PROTOCOL is no longer supported for security reason.\n"));
+ DEBUG ((DEBUG_ERROR, "PrintDxe: Please consider using the AsciiValueToStringS service in EFI_PRINT2S_PROTOCOL.\n"));
+ ASSERT (FALSE);
+ return 0;
+#else
+ return AsciiValueToString (Buffer, Flags, Value, Width);
+#endif
+}
+
+EFI_HANDLE mPrintThunkHandle = NULL;
+
+CONST EFI_PRINT2_PROTOCOL mPrint2Protocol = {
+ UnicodeBSPrint,
+ UnicodeSPrint,
+ UnicodeBSPrintAsciiFormat,
+ UnicodeSPrintAsciiFormat,
+ PrintDxeUnicodeValueToString,
+ AsciiBSPrint,
+ AsciiSPrint,
+ AsciiBSPrintUnicodeFormat,
+ AsciiSPrintUnicodeFormat,
+ PrintDxeAsciiValueToString
+};
+
+CONST EFI_PRINT2S_PROTOCOL mPrint2SProtocol = {
+ UnicodeBSPrint,
+ UnicodeSPrint,
+ UnicodeBSPrintAsciiFormat,
+ UnicodeSPrintAsciiFormat,
+ UnicodeValueToStringS,
+ AsciiBSPrint,
+ AsciiSPrint,
+ AsciiBSPrintUnicodeFormat,
+ AsciiSPrintUnicodeFormat,
+ AsciiValueToStringS
+};
+
+/**
+ The user Entry Point for Print module.
+
+ This is the entry point for Print DXE Driver. It installs the Print2 Protocol.
+
+ @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 Others Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PrintEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPrintThunkHandle,
+ &gEfiPrint2ProtocolGuid, &mPrint2Protocol,
+ &gEfiPrint2SProtocolGuid, &mPrint2SProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.inf b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
new file mode 100644
index 000000000..b9096d29d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# Print DXE driver that produces Print2 Protocols.
+#
+# This driver produces Print2 protocols layered on top of the PrintLib from the MdePkg.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PrintDxe
+ MODULE_UNI_FILE = PrintDxe.uni
+ FILE_GUID = 79E4A61C-ED73-4312-94FE-E3E7563362A9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PrintEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Print.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiPrint2ProtocolGuid ## PRODUCES
+ gEfiPrint2SProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PrintDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.uni b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.uni
new file mode 100644
index 000000000..85c9b26d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Print DXE driver that produces Print2 Protocols.
+//
+// This driver produces Print2 protocols layered on top of the PrintLib from the MdePkg.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Print DXE driver that produces Print2 Protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces Print2 protocols layered on top of the PrintLib from the MdePkg."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxeExtra.uni
new file mode 100644
index 000000000..108dd9939
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/PrintDxe/PrintDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PrintDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Formatted String DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.c
new file mode 100644
index 000000000..2b2b0d420
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.c
@@ -0,0 +1,98 @@
+/** @file
+
+ Module to rewrite stdlib references within Oniguruma
+
+ (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "OnigurumaUefiPort.h"
+
+#define ONIGMEM_HEAD_SIGNATURE SIGNATURE_32('o','m','h','d')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN Size;
+} ONIGMEM_HEAD;
+
+#define ONIGMEM_OVERHEAD sizeof(ONIGMEM_HEAD)
+
+int EFIAPI sprintf_s(char *str, size_t sizeOfBuffer, char const *fmt, ...)
+{
+ VA_LIST Marker;
+ int NumberOfPrinted;
+
+ VA_START (Marker, fmt);
+ NumberOfPrinted = (int)AsciiVSPrint (str, sizeOfBuffer, fmt, Marker);
+ VA_END (Marker);
+
+ return NumberOfPrinted;
+}
+
+int OnigStrCmp (const char* Str1, const char* Str2)
+{
+ return (int)AsciiStrCmp (Str1, Str2);
+}
+
+int strlen(const char* str)
+{
+ return strlen_s(str, MAX_STRING_SIZE);
+}
+
+void * malloc (size_t size)
+{
+ ONIGMEM_HEAD *PoolHdr;
+ UINTN NewSize;
+ VOID *Data;
+
+ NewSize = (UINTN)(size) + ONIGMEM_OVERHEAD;
+
+ Data = AllocatePool (NewSize);
+ if (Data != NULL) {
+ PoolHdr = (ONIGMEM_HEAD *)Data;
+ PoolHdr->Signature = ONIGMEM_HEAD_SIGNATURE;
+ PoolHdr->Size = size;
+
+ return (VOID *)(PoolHdr + 1);
+ }
+ return NULL;
+}
+
+void * realloc (void *ptr, size_t size)
+{
+ ONIGMEM_HEAD *OldPoolHdr;
+ ONIGMEM_HEAD *NewPoolHdr;
+ UINTN OldSize;
+ UINTN NewSize;
+ VOID *Data;
+
+ NewSize = (UINTN)size + ONIGMEM_OVERHEAD;
+ Data = AllocatePool (NewSize);
+ if (Data != NULL) {
+ NewPoolHdr = (ONIGMEM_HEAD *)Data;
+ NewPoolHdr->Signature = ONIGMEM_HEAD_SIGNATURE;
+ NewPoolHdr->Size = size;
+ if (ptr != NULL) {
+ OldPoolHdr = (ONIGMEM_HEAD *)ptr - 1;
+ ASSERT (OldPoolHdr->Signature == ONIGMEM_HEAD_SIGNATURE);
+ OldSize = OldPoolHdr->Size;
+
+ CopyMem ((VOID *)(NewPoolHdr + 1), ptr, MIN (OldSize, size));
+ FreePool ((VOID *)OldPoolHdr);
+ }
+ return (VOID *)(NewPoolHdr + 1);
+ }
+ return NULL;
+}
+
+void* memcpy (void *dest, const void *src, unsigned int count)
+{
+ return CopyMem (dest, src, (UINTN)count);
+}
+
+void* memset (void *dest, char ch, unsigned int count)
+{
+ return SetMem (dest, ch, count);
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.h
new file mode 100644
index 000000000..20b75c336
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/OnigurumaUefiPort.h
@@ -0,0 +1,104 @@
+/** @file
+
+ Module to rewrite stdlib references within Oniguruma
+
+ (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef ONIGURUMA_UEFI_PORT_H
+#define ONIGURUMA_UEFI_PORT_H
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+
+#define ONIG_NO_STANDARD_C_HEADERS
+#define ONIG_NO_PRINT
+#define P_(args) args
+
+#define INT_MAX 0x7FFFFFFF
+#define LONG_MAX 0x7FFFFFFF
+#define UINT_MAX 0xFFFFFFFF
+#define ULONG_MAX 0xFFFFFFFF
+
+
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+typedef UINTN size_t;
+typedef UINT32 uint32_t;
+typedef INTN intptr_t;
+
+#ifndef offsetof
+#define offsetof OFFSET_OF
+#endif
+
+#ifdef MDE_CPU_IA32
+#define SIZEOF_VOIDP 4
+#endif
+
+#ifdef MDE_CPU_X64
+#define SIZEOF_VOIDP 8
+#endif
+
+#define calloc(n,s) AllocateZeroPool((n)*(s))
+
+#define free(p) \
+ do { \
+ VOID *EvalOnce; \
+ \
+ EvalOnce = (p); \
+ if (EvalOnce != NULL) { \
+ FreePool (EvalOnce); \
+ } \
+ } while (FALSE)
+
+#define xmemmove(Dest,Src,Length) CopyMem(Dest,Src,Length)
+#define xmemcpy(Dest,Src,Length) CopyMem(Dest,Src,Length)
+#define xmemset(Buffer,Value,Length) SetMem(Buffer,Length,Value)
+
+#define va_init_list(a,b) VA_START(a,b)
+#define va_list VA_LIST
+#define va_arg(a,b) VA_ARG(a,b)
+#define va_end(a) VA_END(a)
+#define va_start VA_START
+
+#define FILE VOID
+#define stdout NULL
+#define fprintf(...)
+#define fputs(a,b)
+#define vsnprintf (int)AsciiVSPrint
+#define _vsnprintf vsnprintf
+#define xsnprintf sprintf_s
+#define xvsnprintf vsnprintf
+#define alloca malloc
+
+#define setlocale(a,b)
+#define LC_ALL 0
+
+#define UCHAR_MAX 255
+#define MAX_STRING_SIZE 0x1000
+#define strlen_s(String,MaxSize) AsciiStrnLenS (String, MaxSize)
+#define xstrncpy(Dest, Src, MaxSize) strcat_s(Dest,MaxSize,Src)
+#define xstrcat(Dest,Src,MaxSize) strcat(Dest,Src,MaxSize)
+#define strcat(Dest,Src,MaxSize) strcat_s(Dest,MaxSize,Src)
+#define strcat_s(Dest,MaxSize,Src) AsciiStrCatS (Dest, MaxSize, Src)
+#define strncpy_s(Dest,MaxSize,Src,Length) AsciiStrnCpyS (Dest, MaxSize, Src, Length)
+#define strcmp OnigStrCmp
+
+int OnigStrCmp (const char* Str1, const char* Str2);
+
+int EFIAPI sprintf_s (char *str, size_t sizeOfBuffer, char const *fmt, ...);
+int strlen(const char* str);
+void* malloc(size_t size);
+void* realloc(void *ptr, size_t size);
+void* memcpy (void *dest, const void *src, unsigned int count);
+void* memset (void *dest, char ch, unsigned int count);
+
+#define exit(n) ASSERT(FALSE);
+
+#endif // !ONIGURUMA_UEFI_PORT_H
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c
new file mode 100644
index 000000000..d1324c135
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c
@@ -0,0 +1,381 @@
+/** @file
+
+ EFI_REGULAR_EXPRESSION_PROTOCOL Implementation
+
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RegularExpressionDxe.h"
+
+STATIC
+EFI_REGEX_SYNTAX_TYPE * CONST mSupportedSyntaxes[] = {
+ &gEfiRegexSyntaxTypePosixExtendedGuid,
+ &gEfiRegexSyntaxTypePerlGuid
+};
+
+STATIC
+EFI_REGULAR_EXPRESSION_PROTOCOL mProtocolInstance = {
+ RegularExpressionMatch,
+ RegularExpressionGetInfo
+};
+
+
+
+#define CHAR16_ENCODING ONIG_ENCODING_UTF16_LE
+
+/**
+ Call the Oniguruma regex match API.
+
+ Same parameters as RegularExpressionMatch, except SyntaxType is required.
+
+ @param String A pointer to a NULL terminated string to match against the
+ regular expression string specified by Pattern.
+
+ @param Pattern A pointer to a NULL terminated string that represents the
+ regular expression.
+ @param SyntaxType A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
+ regular expression syntax type to use. May be NULL in which
+ case the function will use its default regular expression
+ syntax type.
+
+ @param Result On return, points to TRUE if String fully matches against
+ the regular expression Pattern using the regular expression
+ SyntaxType. Otherwise, points to FALSE.
+
+ @param Captures A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
+ the captured groups in the event of a match. The full
+ sub-string match is put in Captures[0], and the results of N
+ capturing groups are put in Captures[1:N]. If Captures is
+ NULL, then this function doesn't allocate the memory for the
+ array and does not build up the elements. It only returns the
+ number of matching patterns in CapturesCount. If Captures is
+ not NULL, this function returns a pointer to an array and
+ builds up the elements in the array. CapturesCount is also
+ updated to the number of matching patterns found. It is the
+ caller's responsibility to free the memory pool in Captures
+ and in each CapturePtr in the array elements.
+
+ @param CapturesCount On output, CapturesCount is the number of matching patterns
+ found in String. Zero means no matching patterns were found
+ in the string.
+
+ @retval EFI_SUCCESS Regex compilation and match completed successfully.
+ @retval EFI_DEVICE_ERROR Regex compilation failed.
+
+**/
+STATIC
+EFI_STATUS
+OnigurumaMatch (
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern,
+ IN EFI_REGEX_SYNTAX_TYPE *SyntaxType,
+ OUT BOOLEAN *Result,
+ OUT EFI_REGEX_CAPTURE **Captures, OPTIONAL
+ OUT UINTN *CapturesCount
+ )
+{
+ regex_t *OnigRegex;
+ OnigSyntaxType *OnigSyntax;
+ OnigRegion *Region;
+ INT32 OnigResult;
+ OnigErrorInfo ErrorInfo;
+ OnigUChar ErrorMessage[ONIG_MAX_ERROR_MESSAGE_LEN];
+ UINT32 Index;
+ OnigUChar *Start;
+ EFI_STATUS Status;
+
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Detemine the internal syntax type
+ //
+ OnigSyntax = ONIG_SYNTAX_DEFAULT;
+ if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePosixExtendedGuid)) {
+ OnigSyntax = ONIG_SYNTAX_POSIX_EXTENDED;
+ } else if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePerlGuid)) {
+ OnigSyntax = ONIG_SYNTAX_PERL;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Unsupported regex syntax - using default\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Compile pattern
+ //
+ Start = (OnigUChar*)Pattern;
+ OnigResult = onig_new (
+ &OnigRegex,
+ Start,
+ Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
+ ONIG_OPTION_DEFAULT,
+ CHAR16_ENCODING,
+ OnigSyntax,
+ &ErrorInfo
+ );
+
+ if (OnigResult != ONIG_NORMAL) {
+ onig_error_code_to_str (ErrorMessage, OnigResult, &ErrorInfo);
+ DEBUG ((DEBUG_ERROR, "Regex compilation failed: %a\n", ErrorMessage));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Try to match
+ //
+ Start = (OnigUChar*)String;
+ Region = onig_region_new ();
+ if (Region == NULL) {
+ onig_free (OnigRegex);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OnigResult = onig_search (
+ OnigRegex,
+ Start,
+ Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
+ Start,
+ Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
+ Region,
+ ONIG_OPTION_NONE
+ );
+
+ if (OnigResult >= 0) {
+ *Result = TRUE;
+ } else {
+ *Result = FALSE;
+ if (OnigResult != ONIG_MISMATCH) {
+ onig_error_code_to_str (ErrorMessage, OnigResult);
+ DEBUG ((DEBUG_ERROR, "Regex match failed: %a\n", ErrorMessage));
+ onig_region_free (Region, 1);
+ onig_free (OnigRegex);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // If successful, copy out the region (capture) information
+ //
+ if (*Result && Captures != NULL) {
+ *CapturesCount = Region->num_regs;
+ *Captures = AllocateZeroPool (*CapturesCount * sizeof(**Captures));
+ if (*Captures != NULL) {
+ for (Index = 0; Index < *CapturesCount; ++Index) {
+ //
+ // Region beg/end values represent bytes, not characters
+ //
+ (*Captures)[Index].Length = (Region->end[Index] - Region->beg[Index]) / sizeof(CHAR16);
+ (*Captures)[Index].CapturePtr = AllocateCopyPool (
+ ((*Captures)[Index].Length) * sizeof (CHAR16),
+ (CHAR16*)((UINTN)String + Region->beg[Index])
+ );
+ if ((*Captures)[Index].CapturePtr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ for (Index = 0; Index < *CapturesCount; ++Index) {
+ if ((*Captures)[Index].CapturePtr != NULL) {
+ FreePool ((CHAR16*)(*Captures)[Index].CapturePtr);
+ }
+ }
+ FreePool (*Captures);
+ }
+ }
+ }
+
+ onig_region_free (Region, 1);
+ onig_free (OnigRegex);
+
+ return Status;
+}
+
+/**
+ Returns information about the regular expression syntax types supported
+ by the implementation.
+
+ @param This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL
+ instance.
+
+ @param RegExSyntaxTypeListSize On input, the size in bytes of RegExSyntaxTypeList.
+ On output with a return code of EFI_SUCCESS, the
+ size in bytes of the data returned in
+ RegExSyntaxTypeList. On output with a return code
+ of EFI_BUFFER_TOO_SMALL, the size of
+ RegExSyntaxTypeList required to obtain the list.
+
+ @param RegExSyntaxTypeList A caller-allocated memory buffer filled by the
+ driver with one EFI_REGEX_SYNTAX_TYPE element
+ for each supported Regular expression syntax
+ type. The list must not change across multiple
+ calls to the same driver. The first syntax
+ type in the list is the default type for the
+ driver.
+
+ @retval EFI_SUCCESS The regular expression syntax types list
+ was returned successfully.
+ @retval EFI_UNSUPPORTED The service is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The list of syntax types could not be
+ retrieved due to a hardware or firmware error.
+ @retval EFI_BUFFER_TOO_SMALL The buffer RegExSyntaxTypeList is too small
+ to hold the result.
+ @retval EFI_INVALID_PARAMETER RegExSyntaxTypeListSize is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+RegularExpressionGetInfo (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *This,
+ IN OUT UINTN *RegExSyntaxTypeListSize,
+ OUT EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList
+ )
+{
+ UINTN SyntaxSize;
+ UINTN Index;
+
+ if (This == NULL || RegExSyntaxTypeListSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*RegExSyntaxTypeListSize != 0 && RegExSyntaxTypeList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SyntaxSize = ARRAY_SIZE (mSupportedSyntaxes) * sizeof(**mSupportedSyntaxes);
+
+ if (*RegExSyntaxTypeListSize < SyntaxSize) {
+ *RegExSyntaxTypeListSize = SyntaxSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
+ CopyMem (&RegExSyntaxTypeList[Index], mSupportedSyntaxes[Index], sizeof(**mSupportedSyntaxes));
+ }
+ *RegExSyntaxTypeListSize = SyntaxSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks if the input string matches to the regular expression pattern.
+
+ @param This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL instance.
+ Type EFI_REGULAR_EXPRESSION_PROTOCOL is defined in Section
+ XYZ.
+
+ @param String A pointer to a NULL terminated string to match against the
+ regular expression string specified by Pattern.
+
+ @param Pattern A pointer to a NULL terminated string that represents the
+ regular expression.
+
+ @param SyntaxType A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
+ regular expression syntax type to use. May be NULL in which
+ case the function will use its default regular expression
+ syntax type.
+
+ @param Result On return, points to TRUE if String fully matches against
+ the regular expression Pattern using the regular expression
+ SyntaxType. Otherwise, points to FALSE.
+
+ @param Captures A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
+ the captured groups in the event of a match. The full
+ sub-string match is put in Captures[0], and the results of N
+ capturing groups are put in Captures[1:N]. If Captures is
+ NULL, then this function doesn't allocate the memory for the
+ array and does not build up the elements. It only returns the
+ number of matching patterns in CapturesCount. If Captures is
+ not NULL, this function returns a pointer to an array and
+ builds up the elements in the array. CapturesCount is also
+ updated to the number of matching patterns found. It is the
+ caller's responsibility to free the memory pool in Captures
+ and in each CapturePtr in the array elements.
+
+ @param CapturesCount On output, CapturesCount is the number of matching patterns
+ found in String. Zero means no matching patterns were found
+ in the string.
+
+ @retval EFI_SUCCESS The regular expression string matching
+ completed successfully.
+ @retval EFI_UNSUPPORTED The regular expression syntax specified by
+ SyntaxType is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The regular expression string matching
+ failed due to a hardware or firmware error.
+ @retval EFI_INVALID_PARAMETER String, Pattern, Result, or CapturesCountis
+ NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+RegularExpressionMatch (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern,
+ IN EFI_REGEX_SYNTAX_TYPE *SyntaxType, OPTIONAL
+ OUT BOOLEAN *Result,
+ OUT EFI_REGEX_CAPTURE **Captures, OPTIONAL
+ OUT UINTN *CapturesCount
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ BOOLEAN Supported;
+
+ if (This == NULL || String == NULL || Pattern == NULL || Result == NULL || CapturesCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Figure out which syntax to use
+ //
+ if (SyntaxType == NULL) {
+ SyntaxType = mSupportedSyntaxes[0];
+ } else {
+ Supported = FALSE;
+ for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
+ if (CompareGuid (SyntaxType, mSupportedSyntaxes[Index])) {
+ Supported = TRUE;
+ break;
+ }
+ }
+ if (!Supported) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Status = OnigurumaMatch (String, Pattern, SyntaxType, Result, Captures, CapturesCount);
+
+ return Status;
+}
+
+/**
+ Entry point for RegularExpressionDxe.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @retval Status Whether this function complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+RegularExpressionDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiRegularExpressionProtocolGuid,
+ &mProtocolInstance,
+ NULL
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.h
new file mode 100644
index 000000000..3f046af36
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.h
@@ -0,0 +1,125 @@
+/** @file
+ EFI_REGULAR_EXPRESSION_PROTOCOL Header File.
+
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __REGULAR_EXPRESSIONDXE_H__
+#define __REGULAR_EXPRESSIONDXE_H__
+
+#include "oniguruma/src/oniguruma.h"
+
+#include <Uefi.h>
+#include <Protocol/RegularExpressionProtocol.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ Checks if the input string matches to the regular expression pattern.
+
+ @param This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL instance.
+ Type EFI_REGULAR_EXPRESSION_PROTOCOL is defined in Section
+ XYZ.
+
+ @param String A pointer to a NULL terminated string to match against the
+ regular expression string specified by Pattern.
+
+ @param Pattern A pointer to a NULL terminated string that represents the
+ regular expression.
+
+ @param SyntaxType A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
+ regular expression syntax type to use. May be NULL in which
+ case the function will use its default regular expression
+ syntax type.
+
+ @param Result On return, points to TRUE if String fully matches against
+ the regular expression Pattern using the regular expression
+ SyntaxType. Otherwise, points to FALSE.
+
+ @param Captures A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
+ the captured groups in the event of a match. The full
+ sub-string match is put in Captures[0], and the results of N
+ capturing groups are put in Captures[1:N]. If Captures is
+ NULL, then this function doesn't allocate the memory for the
+ array and does not build up the elements. It only returns the
+ number of matching patterns in CapturesCount. If Captures is
+ not NULL, this function returns a pointer to an array and
+ builds up the elements in the array. CapturesCount is also
+ updated to the number of matching patterns found. It is the
+ caller's responsibility to free the memory pool in Captures
+ and in each CapturePtr in the array elements.
+
+ @param CapturesCount On output, CapturesCount is the number of matching patterns
+ found in String. Zero means no matching patterns were found
+ in the string.
+
+ @retval EFI_SUCCESS The regular expression string matching
+ completed successfully.
+ @retval EFI_UNSUPPORTED The regular expression syntax specified by
+ SyntaxType is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The regular expression string matching
+ failed due to a hardware or firmware error.
+ @retval EFI_INVALID_PARAMETER String, Pattern, Result, or CapturesCountis
+ NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+RegularExpressionMatch (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern,
+ IN EFI_REGEX_SYNTAX_TYPE *SyntaxType, OPTIONAL
+ OUT BOOLEAN *Result,
+ OUT EFI_REGEX_CAPTURE **Captures, OPTIONAL
+ OUT UINTN *CapturesCount
+ );
+
+/**
+ Returns information about the regular expression syntax types supported
+ by the implementation.
+
+ @param This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL
+ instance.
+
+ @param RegExSyntaxTypeListSize On input, the size in bytes of RegExSyntaxTypeList.
+ On output with a return code of EFI_SUCCESS, the
+ size in bytes of the data returned in
+ RegExSyntaxTypeList. On output with a return code
+ of EFI_BUFFER_TOO_SMALL, the size of
+ RegExSyntaxTypeList required to obtain the list.
+
+ @param RegExSyntaxTypeList A caller-allocated memory buffer filled by the
+ driver with one EFI_REGEX_SYNTAX_TYPE element
+ for each supported Regular expression syntax
+ type. The list must not change across multiple
+ calls to the same driver. The first syntax
+ type in the list is the default type for the
+ driver.
+
+ @retval EFI_SUCCESS The regular expression syntax types list
+ was returned successfully.
+ @retval EFI_UNSUPPORTED The service is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The list of syntax types could not be
+ retrieved due to a hardware or firmware error.
+ @retval EFI_BUFFER_TOO_SMALL The buffer RegExSyntaxTypeList is too small
+ to hold the result.
+ @retval EFI_INVALID_PARAMETER RegExSyntaxTypeListSize is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+RegularExpressionGetInfo (
+ IN EFI_REGULAR_EXPRESSION_PROTOCOL *This,
+ IN OUT UINTN *RegExSyntaxTypeListSize,
+ OUT EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
new file mode 100644
index 000000000..84489c294
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf
@@ -0,0 +1,129 @@
+## @file
+# EFI_REGULAR_EXPRESSION_PROTOCOL Implementation
+#
+# Copyright (c) 2018-2020, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010018
+ BASE_NAME = RegularExpressionDxe
+ FILE_GUID = 3E197E9C-D8DC-42D3-89CE-B04FA9833756
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RegularExpressionDxeEntry
+
+[Sources]
+ RegularExpressionDxe.c
+ RegularExpressionDxe.h
+ OnigurumaUefiPort.h
+ OnigurumaUefiPort.c
+
+# Wrapper header files start #
+ stdio.h
+ stdarg.h
+ stddef.h
+ stdlib.h
+ string.h
+ config.h
+# Wrapper header files end #
+
+# Upstream Oniguruma code
+ oniguruma/src/onig_init.c
+ oniguruma/src/oniguruma.h
+ oniguruma/src/regcomp.c
+ oniguruma/src/regenc.c
+ oniguruma/src/regenc.h
+ oniguruma/src/regerror.c
+ oniguruma/src/regexec.c
+ oniguruma/src/oniggnu.h
+ oniguruma/src/reggnu.c
+ oniguruma/src/regint.h
+ oniguruma/src/regparse.c
+ oniguruma/src/regparse.h
+ oniguruma/src/regposerr.c
+ oniguruma/src/onigposix.h
+ oniguruma/src/regposix.c
+ oniguruma/src/regsyntax.c
+ oniguruma/src/regtrav.c
+ oniguruma/src/regversion.c
+ oniguruma/src/st.c
+ oniguruma/src/st.h
+
+# Supported Character Encodings
+ oniguruma/src/ascii.c
+ oniguruma/src/unicode.c
+ oniguruma/src/unicode_fold1_key.c
+ oniguruma/src/unicode_fold2_key.c
+ oniguruma/src/unicode_fold3_key.c
+ oniguruma/src/unicode_unfold_key.c
+ oniguruma/src/utf16_le.c
+ oniguruma/src/utf8.c
+ oniguruma/src/utf16_be.c
+ oniguruma/src/euc_jp.c
+ oniguruma/src/sjis.c
+ oniguruma/src/sjis_prop.c
+ oniguruma/src/euc_jp_prop.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+
+[Guids]
+ gEfiRegexSyntaxTypePosixExtendedGuid ## CONSUMES ## GUID
+ gEfiRegexSyntaxTypePerlGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiRegularExpressionProtocolGuid ## PRODUCES
+
+[BuildOptions]
+ # Enable STDARG for variable arguments
+ *_*_*_CC_FLAGS = -DHAVE_STDARG_H -U_WIN32 -DONIG_VARIADIC_FUNC_ATTR=EFIAPI
+
+ # Override MSFT build option to remove /Oi and /GL
+ MSFT:*_*_*_CC_FLAGS = /GL-
+ INTEL:*_*_*_CC_FLAGS = /Oi-
+
+ # Oniguruma: potentially uninitialized local variable used
+ MSFT:*_*_*_CC_FLAGS = /wd4701 /wd4703
+
+ # Oniguruma: intrinsic function not declared
+ MSFT:*_*_*_CC_FLAGS = /wd4164
+
+ # Oniguruma: old style declaration in st.c
+ MSFT:*_*_*_CC_FLAGS = /wd4131
+
+ # Oniguruma: 'type cast' : truncation from 'OnigUChar *' to 'unsigned int'
+ MSFT:*_*_*_CC_FLAGS = /wd4305 /wd4306
+
+ # Oniguruma: nameless union declared in regparse.h
+ MSFT:*_*_*_CC_FLAGS = /wd4201
+
+ # Oniguruma: 'type cast' : "int" to "OnigUChar", function pointer to "void *"
+ MSFT:*_*_*_CC_FLAGS = /wd4244 /wd4054
+
+ # Oniguruma: previous local declaration
+ MSFT:*_*_*_CC_FLAGS = /wd4456
+
+ # Oniguruma: signed and unsigned mismatch/cast
+ MSFT:*_*_*_CC_FLAGS = /wd4018 /wd4245 /wd4389 /wd4090
+
+ # Oniguruma: tag_end in parse_callout_of_name
+ GCC:*_*_*_CC_FLAGS = -Wno-error=maybe-uninitialized
+
+ # Oniguruma: implicit conversion from 'UINTN' (aka 'unsigned long long') to 'long'
+ GCC:*_CLANGPDB_*_CC_FLAGS = -Wno-error=constant-conversion
+
+ # Not add -Wno-error=maybe-uninitialized option for XCODE
+ # XCODE doesn't know this option
+ XCODE:*_*_*_CC_FLAGS =
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/config.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/config.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/config.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.gitignore b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.gitignore
new file mode 100644
index 000000000..045e58e96
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.gitignore
@@ -0,0 +1,79 @@
+Makefile
+autom4te.cache/
+ltmain.sh
+stamp-h1
+configure
+config.status
+config.h
+config.h.in
+onig-config
+libtool
+aclocal.m4
+Makefile.in
+.python-version
+*.o
+*.obj
+*.so
+*.lo
+*.la
+*.pc
+*.log
+*.dll
+*.lib
+*.exe
+*.exp
+*.gcno
+*.gcda
+*.gcov
+*~
+.libs/
+.deps/
+/build
+/onig-*.tar.gz
+m4/*.m4
+/coverage
+/coverage.info
+/fuzzers
+
+# src/
+/src/unicode_fold?_key.gperf
+/src/unicode_unfold_key.gperf
+/src/UNICODE_PROPERTIES
+/src/*.txt
+/src/mktable
+
+# test/
+/test/test_utf8
+/test/testc
+/test/testcu
+/test/testp
+/test/test_regset
+/test/test_syntax
+/test/kofu-utf8.txt
+
+# sample/
+/sample/crnl
+/sample/encode
+/sample/listcap
+/sample/names
+/sample/posix
+/sample/simple
+/sample/sql
+/sample/syntax
+/sample/user_property
+/sample/callout
+/sample/echo
+/sample/count
+/sample/bug_fix
+/sample/regset
+/sample/log*
+
+/harnesses/utf16*.dict
+/harnesses/fuzzer-*
+/harnesses/read-*
+/harnesses/libfuzzer-onig
+/harnesses/libfuzzer-onig-full
+/harnesses/slow-unit-*
+/harnesses/timeout-*
+/harnesses/crash-*
+/harnesses/oom-*
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.travis.yml b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.travis.yml
new file mode 100644
index 000000000..be21241ea
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/.travis.yml
@@ -0,0 +1,17 @@
+language: c
+
+compiler:
+ - gcc
+ - clang
+
+install: true
+
+branches:
+ except:
+ - 5.9.6
+
+before_script:
+ - autoreconf -fi
+
+script:
+ - ./configure && make && make all-test
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/AUTHORS b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/AUTHORS
new file mode 100644
index 000000000..cf2798131
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/AUTHORS
@@ -0,0 +1 @@
+<kkosako0@gmail.com> (K.Kosako)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/CMakeLists.txt b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/CMakeLists.txt
new file mode 100644
index 000000000..bce888a29
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/CMakeLists.txt
@@ -0,0 +1,180 @@
+cmake_minimum_required(VERSION 3.1)
+project(oniguruma
+ VERSION 6.9.4
+ LANGUAGES C)
+
+set(PACKAGE onig)
+set(PACKAGE_VERSION ${PROJECT_VERSION})
+
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
+option(ENABLE_POSIX_API "Include POSIX API" ON)
+if(MSVC)
+ option(MSVC_STATIC_RUNTIME "Build with static runtime" OFF)
+endif()
+
+set(USE_CRNL_AS_LINE_TERMINATOR 0)
+set(VERSION ${PACKAGE_VERSION})
+
+include(CheckCSourceCompiles)
+include(CheckIncludeFiles)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckTypeSize)
+include(TestBigEndian)
+
+check_function_exists(alloca HAVE_ALLOCA)
+check_include_files(alloca.h HAVE_ALLOCA_H)
+check_include_files(stdint.h HAVE_STDINT_H)
+check_include_files(sys/times.h HAVE_SYS_TIMES_H)
+check_include_files(sys/time.h HAVE_SYS_TIME_H)
+check_include_files(sys/types.h HAVE_SYS_TYPES_H)
+check_include_files(unistd.h HAVE_UNISTD_H)
+check_include_files(inttypes.h HAVE_INTTYPES_H)
+check_type_size(int SIZEOF_INT)
+check_type_size(long SIZEOF_LONG)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/oniguruma.pc.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/oniguruma.pc @ONLY)
+
+set(_SRCS src/regint.h src/regparse.h src/regenc.h src/st.h
+ src/regerror.c src/regparse.c src/regext.c src/regcomp.c src/regexec.c
+ src/reggnu.c src/regenc.c src/regsyntax.c src/regtrav.c src/regversion.c
+ src/st.c src/onig_init.c
+ src/unicode.c src/ascii.c src/utf8.c src/utf16_be.c src/utf16_le.c
+ src/utf32_be.c src/utf32_le.c src/euc_jp.c src/sjis.c src/iso8859_1.c
+ src/iso8859_2.c src/iso8859_3.c src/iso8859_4.c src/iso8859_5.c
+ src/iso8859_6.c src/iso8859_7.c src/iso8859_8.c src/iso8859_9.c
+ src/iso8859_10.c src/iso8859_11.c src/iso8859_13.c src/iso8859_14.c
+ src/iso8859_15.c src/iso8859_16.c src/euc_tw.c src/euc_kr.c src/big5.c
+ src/gb18030.c src/koi8_r.c src/cp1251.c
+ src/euc_jp_prop.c src/sjis_prop.c
+ src/unicode_unfold_key.c
+ src/unicode_fold1_key.c src/unicode_fold2_key.c src/unicode_fold3_key.c)
+
+set(_INST_HEADERS src/oniguruma.h src/oniggnu.h)
+
+if(ENABLE_POSIX_API)
+ set(_SRCS ${_SRCS} src/regposix.c src/regposerr.c)
+ set(_INST_HEADERS ${_INST_HEADERS} src/onigposix.h)
+endif()
+
+add_library(onig ${_SRCS})
+target_include_directories(onig PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+
+target_compile_definitions(onig PUBLIC
+ $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:ONIG_STATIC>)
+
+if(MSVC)
+ target_compile_options(onig PRIVATE
+ #/W4
+ )
+ if(MSVC_STATIC_RUNTIME)
+ target_compile_options(onig PRIVATE
+ $<$<CONFIG:Release>:/MT>
+ $<$<CONFIG:Debug>:/MTd>
+ $<$<CONFIG:MinSizeRel>:/MT>
+ $<$<CONFIG:RelWithDebgInfo>:/MTd>
+ )
+ endif()
+elseif(CMAKE_COMPILER_IS_GNUCC)
+ target_compile_options(onig PRIVATE
+ -Wall
+ )
+endif()
+
+
+# Installation (https://github.com/forexample/package-example)
+
+# Introduce variables:
+# * CMAKE_INSTALL_LIBDIR
+# * CMAKE_INSTALL_BINDIR
+# * CMAKE_INSTALL_INCLUDEDIR
+include(GNUInstallDirs)
+
+# Layout. This works for all platforms:
+# * <prefix>/lib*/cmake/<PROJECT-NAME>
+# * <prefix>/lib*/
+# * <prefix>/include/
+set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
+
+# Configuration
+set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
+set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
+set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
+set(namespace "${PROJECT_NAME}::")
+
+# Include module with fuction 'write_basic_package_version_file'
+include(CMakePackageConfigHelpers)
+
+# Configure '<PROJECT-NAME>ConfigVersion.cmake'
+# Use:
+# * PROJECT_VERSION
+write_basic_package_version_file(
+ "${version_config}" COMPATIBILITY SameMajorVersion
+)
+
+# Configure '<PROJECT-NAME>Config.cmake'
+# Use variables:
+# * TARGETS_EXPORT_NAME
+# * PROJECT_NAME
+configure_package_config_file(
+ "cmake/Config.cmake.in"
+ "${project_config}"
+ INSTALL_DESTINATION "${config_install_dir}"
+)
+
+# Targets:
+# * <prefix>/lib/libonig.a
+# * header location after install: <prefix>/include/
+# * headers can be included by C code `#include <oniguruma.h>`
+install(
+ TARGETS onig
+ EXPORT "${TARGETS_EXPORT_NAME}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+# Headers:
+# * src/oniguruma.h -> <prefix>/include/oniguruma
+install(
+ FILES ${_INST_HEADERS}
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+# Config
+# * <prefix>/lib/cmake/oniguruma/onigurumaConfig.cmake
+# * <prefix>/lib/cmake/oniguruma/onigurumaConfigVersion.cmake
+install(
+ FILES "${project_config}" "${version_config}"
+ DESTINATION "${config_install_dir}"
+)
+
+# Config
+# * <prefix>/lib/cmake/oniguruma/onigurumaTargets.cmake
+install(
+ EXPORT "${TARGETS_EXPORT_NAME}"
+ NAMESPACE "${namespace}"
+ DESTINATION "${config_install_dir}"
+)
+
+# Documentation (uses onig not oniguruma for directory)
+install(FILES doc/API doc/API.ja doc/RE doc/RE.ja doc/FAQ doc/FAQ.ja
+ doc/CALLOUTS.BUILTIN doc/CALLOUTS.BUILTIN.ja
+ doc/CALLOUTS.API doc/CALLOUTS.API.ja
+ doc/UNICODE_PROPERTIES
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/${PACKAGE}")
+
+# Other files (uses onig not oniguruma for directory)
+install(FILES AUTHORS COPYING HISTORY README.md
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/${PACKAGE}")
+
+# pkg-config
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/oniguruma.pc
+ DESTINATION lib/pkgconfig)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/COPYING b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/COPYING
new file mode 100644
index 000000000..ee9a74998
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/COPYING
@@ -0,0 +1,26 @@
+Oniguruma LICENSE
+-----------------
+
+Copyright (c) 2002-2020 K.Kosako <kkosako0@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/ChangeLog b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/ChangeLog
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/ChangeLog
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/HISTORY b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/HISTORY
new file mode 100644
index 000000000..f4d4f6744
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/HISTORY
@@ -0,0 +1,2359 @@
+History
+
+2019/11/29: Version 6.9.4
+
+2019/11/22: Release Candidate 3 for Version 6.9.4
+
+2019/11/20: fix a problem found by libFuzzer test
+2019/11/14: Release Candidate 2 for Version 6.9.4
+2019/11/12: fix integer overflow by nested quantifier
+2019/11/11: fix CVE-2019-19012: Integer overflow related to reg->dmax in search_in_range()
+2019/11/07: fix CVE-2019-19203: heap-buffer-overflow in gb18030_mbc_enc_len()
+2019/11/06: fix CVE-2019-19204: heap-buffer-overflow in fetch_interval_quantifier()
+2019/11/06: add HAVE_INTTYPES_H into config.h.windows.in and config.h.win{32,64}
+2019/11/06: add HAVE_STDINT_H into config.h.win{32,64}
+2019/11/05: Release Candidate 1 for Version 6.9.4
+2019/10/31: Update Unicode Emoji version to 12.1 (Nothing data changed)
+2019/10/29: implement USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR configuration
+2019/10/18: re-implement case fold conversion
+2019/10/04: fix #156: Heap buffer overflow in match_at() with case-insensitive match
+2019/09/30: NEW API: add onig_regset_replace()
+2019/09/30: change Unicode VERSION value format
+2019/09/20: NEW API: add regset functions
+2019/09/20: add data ensure check before peek string value in OP_PUSH_IF_PEEK_NEXT
+2019/09/20: fix loose code in encode-harness.c
+2019/08/13: fix heap-buffer-overflow
+2019/08/13: Add a macro to disable direct threading in the match engine (PR#149)
+
+2019/08/06: Version 6.9.3 (secirity fix release)
+
+2019/07/30: add ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC
+2019/07/29: add STK_PREC_READ_START/END stack type
+2019/07/29: Fix #147: Stack Exhaustion Problem caused by some parsing functions
+2019/07/11: add a dictionary file for libfuzzer
+2019/07/07: add harnesses directory
+2019/07/05-2019/07/29: fix many problems found by libfuzzer programs
+2019/06/27: deprecate onig_new_deluxe()
+2019/06/27: Fix CVE-2019-13224: don't allow different encodings for onig_new_deluxe()
+2019/06/27: Fix CVE-2019-13225: problem in converting if-then-else pattern
+
+2019/05/07: Version 6.9.2 (same as Release Candidate 3)
+
+2019/04/23: Release Candidate 3 for 6.9.2
+2019/04/23: add doc/SYNTAX.md into distribution file
+2019/04/09: Release Candidate 2 for 6.9.2
+2019/04/09: fix #139: UAF in match_at()
+2019/04/01: Release Candidate 1 for 6.9.2
+2019/04/01: update Unicode version to 12.1.0 (draft)
+2019/03/29: allow {n,m} (n>m) as possessive interval
+2019/03/25: add ONIG_SYN_OP2_OPTION_ONIGURUMA
+2019/03/22: add new options ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER and
+ ONIG_OPTION_TEXT_SEGMENT_WORD
+2019/03/21: PR #137: fix cross-compilation
+2019/03/20: update Unicode version to 12.0.0
+2019/03/17: add doc/SYNTAX.md
+2019/03/13: {n,m}+ and {n,m}? are possessive and reluctant range operator
+ in Perl syntax
+2019/03/04: fix #132: don't execute testp if ENABLE_POSIX_API == no
+2019/02/28: re-implement bytecode by using Operation struct
+2019/02/26: fix #130: Build error on UWP with VS2017
+2019/02/03: PR #128: regerror/toascii: do not attempt to serialize NULL pointer
+2019/01/30: Build breaks without autoreconf #73
+2019/01/02: fix #127: Windows VS 2008 build errors
+2018/12/19: fix #126: Unable to compile when USE_CALLOUT is not defined
+
+2018/12/11: Version 6.9.1
+
+2018/10/08: use ENC_FLAG_SKIP_OFFSET_XXX values
+2018/10/06: UTF-8 supports code range from 0x0000 to 0x10FFFF
+ (https://tools.ietf.org/html/rfc3629)
+2018/10/05: speed improvement
+2018/10/03: use OPTIMIZE_STR_CASE_FOLD_FAST
+2018/10/01: convert CRLF line endings to LF
+2018/09/27: set SIZEOF_SIZE_T for windows platforms
+2018/09/22: use Sunday quick search algorithm instead of Boyer-Moor-Horspool
+2018/09/20: introduce threaded code into match_at()
+2018/09/17: remove HAVE_STRINGS_H
+2018/09/16: remove HAVE_PROTOTYPES and HAVE_STDARG_PROTOTYPES
+2018/09/14: add a command line option '-gc' for make_unicode_property_data.py.
+2018/09/08: remove AC_HEADER_STDC
+2018/09/06: remove AC_OUTPUT macro call
+2018/09/06: remove AC_FUNC_MEMCMP, AC_HEADER_TIME, AC_C_CONST, HAVE__SETJMP and
+ HAVE_STRING_H
+2018/09/05: remove HAVE_LIMITS_H, HAVE_FLOAT_H and HAVE_STDLIB_H
+
+2018/09/03: Version 6.9.0
+
+2018/08/24: add Unicode Emoji properties
+2018/08/24: update Unicode version 11.0.0
+2018/08/21: support gperf 3.1 instead of 3.0.4
+2018/08/07: add ENABLE_POSIX_API switch into src/Makefile.windows
+2018/08/02: add make_win.bat and src/config.h.windows.in
+2018/06/25: add ENABLE_POSIX_API option into CMakeLists.txt
+2018/06/04: add .travis.yml (for TravisCI)
+
+2018/04/17: Version 6.8.2
+
+2018/04/13: add doc/CALLOUTS.API.ja
+2018/04/10: add doc/CALLOUTS.API
+2018/04/10: fix #87: Read unknown address in onig_error_code_to_str()
+2018/04/06: fix #86: typedef StateCheckNumType is unused
+2018/04/02: update automake 1.16.1
+2018/03/30: fix #84: stack-buffer-overflow in mbc_enc_len
+2018/03/28: PR #83: Improve CMake build
+2018/03/21: switch uses of UChar to OnigUChar in oniguruma.h (#80)
+
+2018/03/19: Version 6.8.1
+
+2018/03/19: update LTVERSION from 4:0:0 to 5:0:0
+2018/03/19: add flag, sb_range etc.. into OnigEncodingType
+2018/03/19: move regex structure from oniguruma.h to regint.h
+2018/03/19: ONIGENC_CTYPE_XXX to be enum (Issue #33)
+
+2018/03/16: Version 6.8.0
+
+2018/03/12: add doc/CALLOUTS.BUILTIN for builtin callouts
+2018/03/08: allow abbreviated notation for callouts (?(*name)..|..) (?(?{...})..|..)
+2018/03/02: NEW API: move onigenc_strdup() from regenc.h to oniguruma.h
+2018/02/21: remove all USE_COMBINATION_EXPLOSION_CHECK
+2018/02/15: fix #78: bad definition of PV_()
+2018/02/14: add configure option --enable-posix-api (for #77)
+2018/02/08: implement callouts of name
+2018/02/01: implement callouts of contents
+2018/01/30: define ONIGURUMA_VERSION_INT
+2018/01/29: enable USE_TRY_IN_MATCH_LIMIT by default
+2018/01/29: NEW API: onig_search_with_param() onig_match_with_param()
+2018/01/26: remove include windows.h from oniguruma.h
+
+2018/01/26: Version 6.7.1
+
+2018/01/25: disable USE_TRY_IN_MATCH_LIMIT by default
+2018/01/24: implement mechanism of try-in-match-limit
+2018/01/24: #76: rename EXPORT to ONIGURUMA_EXPORT
+2018/01/15: #73: update for automake 1.15.1
+2018/01/14: #74: update description of README
+2018/01/10: #72: Correct spelling and grammar in FAQ (English)
+2017/12/25: remove USE_COMBINATION_EXPLOSION_CHECK codes
+
+2017/12/11: Version 6.7.0
+
+2017/12/08: Disable \N and \O on ONIG_SYNTAX_RUBY
+2017/12/08: add ONIG_SYNTAX_ONIGURUMA (default syntax)
+2017/12/05: restructure StackType
+2017/11/13: implement subexp calls (?R), (?&name), (?-n), (?+n) for Perl syntax
+2017/09/25: use string pool of gperf for Unicode Property lookup function
+2017/09/16: fix #70: an empty greedy regex and a word boundary (.*\b) fails
+2017/09/13: remove a stack type STK_POS
+2017/09/08: fix #69: add a declaration of onig_end()
+2017/09/07: fix #68: Compilation failure in out-of-source build
+2017/09/03: [new] hexadecimal codepoint \uHHHH
+
+2017/08/30: Version 6.6.1
+
+2017/08/29: fix definition of \X to (?>\O(?:\Y\O)*)
+
+2017/08/28: Version 6.6.0
+
+2017/08/26: fix #67: can't compile with Visual Studio 2005
+2017/08/24: rename Absent clear to Range clear
+2017/08/21: [new] Extended Grapheme Cluster \X and boundary \y, \Y
+2017/08/17: fix: invalid index(ctype) value assigned to Unicode Block properties
+2017/08/16: --enable-crnl-as-line-terminator to be deprecated
+2017/08/15: [new] ASCII only mode options (?WDSP)
+2017/08/14: [new] ONIG_OPTION_XXXX_IS_ASCII options
+2017/08/11: disable OP_CCLASS_NODE
+2017/08/11: [spec] Absent clear restore previous range value at backtrack
+2017/08/07: optimize for simple one char repetition in Absent expression
+2017/08/07: fix: invalid impl. for reluctant repetition in Absent expression
+2017/08/04: remove compile switch USE_NAMED_GROUP
+
+2017/08/03: Version 6.5.0
+
+2017/07/30: [new] support Absent clear (Absent functions)
+2017/07/25: abolish configure option: --enable-combination-explosion-check
+2017/07/23: [new] support Absent functions (?~...)
+2017/07/14: fix #65: SIZEOF_SIZE_T doesn't exist on certain architecutres
+2017/07/11: [new] support \O (true anychar)
+2017/07/10: [new] support \K (keep)
+2017/07/10: add new node type: NODE_GIMMICK
+2017/07/07: [new] support \N (no newline)
+2017/07/05: [new] support \R (general newline)
+2017/07/05: [new] support if-then-else syntax
+2017/07/04: [new] support backref validity checker
+
+2017/07/03: Version 6.4.0
+
+2017/06/30: fix memory leaks
+2017/06/29: fix memory leaks
+2017/06/28: change encoding of doc/XXXX.ja from EUC-JP to UTF-8
+2017/06/28: update doc/RE, and doc/RE.ja
+2017/06/26: fix fatal bug of endless repeat check on Windows
+2017/06/26: PR #62 : add check for return values
+2017/06/23: [new] support call zero (\g{0})
+2017/06/23: [new] support relative call by positive number
+2017/06/23: [new] support relative back-reference by positive number
+2017/06/15: fix #60 : check value type
+2017/06/02: change output format for ONIG_DEBUG_COMPILE and ONIG_DEBUG_MATCH
+
+2017/05/29: Version 6.3.0
+
+2017/05/24: fix #60 : invalid state(CCS_VALUE) in parse_char_class()
+2017/05/24: fix #59 : access to invalid address by reg->dmax value
+2017/05/23: fix invalid increment of start position in onig_scan()
+2017/05/23: fix #58 : access to invalid address by reg->dmin value
+2017/05/23: fix #57 : DATA_ENSURE() check must be before data access
+2017/05/22: fix #56 : return invalid result for codepoint 0xFFFFFFFF
+2017/05/19: [new] add \o{17777777777} syntax.
+2017/05/19: fix #55 : Byte value expressed in octal must be smaller than 256
+
+2017/04/08: Version 6.2.0
+
+2017/03/15: fix: size in xmemcpy in stack_double (PR #51)
+2017/02/21: Initialize return value
+2017/01/03: NEW API: add onig_set_capture_num_limit()
+2017/01/03: change MemNumType from short int to int
+2016/12/13: fix: [0-9-a] was not allowed as [0-9\-a]
+2016/12/13: fix: illegal capture after recursive call
+2016/12/13: fix: problem with optimization of \z
+2016/12/13: fix: .* optimization
+2016/12/13: Set a limit of parser recursion
+2016/12/12: fix; that warnings are not shown properly
+2016/12/12: fix: /[a-c#]+\W/ =~ "def#" fails when encoding is UTF-16/32
+2016/12/12: fix: /[\x{0}-X]/i doesn't match properly when UTF-16/32 is used.
+
+2016/12/11: Version 6.1.3
+
+2016/12/11: fix: Syntax error: redirection unexpected (expecting word) #35
+
+2016/11/07: Version 6.1.2
+
+2016/10/25: allow word bound, word begin and word end in look-behind.
+2016/10/19: add ONIG_OPTION_CHECK_VALIDITY_OF_STRING option.
+2016/10/16: fix use after free node.
+2016/10/10: fix memory leaks after parsing regexp error.
+2016/09/22: implement many of is_valid_mbc_string().
+
+2016/09/02: Version 6.1.1
+
+2016/08/31: fix segfault /W.?{888}{888}{888}\x00/ (found by libfuzzer)
+2016/08/31: fix error unmatched close parenthesis for %{(.*?)} #23
+
+2016/08/29: Version 6.1.0
+
+2016/08/28: add contributed/libfuzzer-onig.cpp (thanks hannob)
+2016/08/28: update LTVERSION 4:0:0
+2016/08/28: NEW API: onigenc_is_valid_mbc_string().
+2016/08/27: add is_valid_mbc_string() member into OnigEncodingType.
+2016/08/27: fix out of bounds read.
+2016/08/26: fix out of bounds read.
+2016/08/25: disable USE_INVALID_CODE_SCHEME.
+2016/08/24: fix out of bounds read.
+2016/08/23: doc/RE improved.
+2016/08/22: add onig_scan() into doc/API.
+2016/08/22: fix bug: Out of bounds read in onig_strcpy() #17
+2016/08/21: fix bug: infinite loop of backreference and group.
+2016/08/21: fix out of bounds read in mbc_to_code() #16
+2016/08/18: doc/RE refinements.
+2016/08/16: add onig_scan() (NEW API)
+2016/08/16: reimplement match stack allocation for case too many repeat
+ and too many captures in regexp.
+2016/08/15: number of captures <= 32767 for bytecode representation.
+2016/07/17: don't use int_map_backward for thread-safe.
+2016/07/04: fix case of enclosed option in look-behind.
+2016/07/04: fix ignore case in look-behind.
+2016/05/23: fix memory leak in onig_unicode_define_user_property()
+2016/05/20: declare variables at the top of scope. (thanks nmaya)
+
+2016/05/09: Version 6.0.0
+
+2016/05/05: add NEW API: onig_unicode_define_user_property()
+2016/05/04: update Unicode data to 8.0.0
+2016/05/02: change OnigCodePoint type to unsigned int.
+2016/05/02: add doc/UNICODE_PROPERTIES.
+2016/04/19: add error code ONIGERR_FAIL_TO_INITIALIZE.
+2016/04/18: add make_win64/32.bat.
+2016/04/18: fix bug of uninitialized regex_t value on error.
+2016/04/16: reimplement Unicode case folding.
+2016/04/11: update LTVERSION = 3.0.0
+2016/04/05: remove all THREAD_ macro.
+2016/04/05: add init member into OnigEncoding. (add onig_initialize())
+2016/03/28: remove state member of regex.
+2016/03/25: move source files into src/
+2016/03/23: rename configre.in to configure.ac.
+2015/11/17: fix memory leak. (thanks pigzang)
+2015/07/13: change mail address.
+
+2014/12/12: Version 5.9.6
+
+2013/11/27: [impl] add onigenc_end_unicode(). (thanks Takenori Imoto)
+2013/11/27: [impl] add onig_add_end_call(). (thanks Takenori Imoto)
+
+2013/10/21: Version 5.9.5
+
+2013/10/21: [impl] escape warnings for -Wall. (regparse.c)
+2013/10/21: [bug] fixes an issue on Windows x64. (thanks Anatoliy Belsky)
+ The issue was discovered in PHP, see https://bugs.php.net/64769.
+2013/10/21: [impl] remove unused variable. (regcomp.c)
+
+2013/04/04: Version 5.9.4
+
+2013/04/04: [dev] remove Makefile.in from git repository.
+2013/04/04: [dist] add oniguruma.pc.in file. (for pkg-config)
+ (thanks Giulio Paci)
+
+2012/10/26: Version 5.9.3
+
+2012/10/15: remove warnings "test: =: unary operator expected" in ./configure.
+ (thanks t_okazaki)
+2012/10/15: fix print_tree ENCLOSE_OPTION bug. (thanks Suraj N. Kurapati)
+
+2010/01/09: Version 5.9.2
+
+2010/01/05: [bug] fix utf16be_code_to_mbc() and utf16le_code_to_mbc().
+2008/09/16: [bug] fix memory leaks in parse_exp().
+2008/08/01: [bug] fix memory leaks.
+2008/06/17: [bug] invalid type of argument was used
+ in onig_st_lookup_strend().
+2008/06/16: [bug] invalid CaseFoldMap entry in ISO-8859-5. 0xdf -> 0xde
+2008/02/19: [new] add: onig_reg_init().
+2008/02/19: [new] add: onig_free_body().
+2008/02/19: [new] add: onig_new_without_alloc().
+2008/02/19: [API] rename onig_alloc_init() to onig_reg_init(),
+ and argument type changed.
+2008/01/31: [impl] move UTF16_IS_SURROGATE_XXX() to regenc.h.
+2008/01/30: [bug] (thanks akr)
+ fix euctw_islead().
+2008/01/23: [bug] update enc/koi8.c.
+
+2007/12/22: Version 5.9.1
+
+2007/12/21: [impl] add sprint_byte().
+2007/11/28: [bug] (thanks Andy Armstrong)
+ don't overwrite error code in fetch_name().
+2007/11/12: [bug] utf8 mbc length of code 0xfe, 0xff are not 1,
+2007/10/23: [spec] onig_enc_len() takes three arguments. (not used)
+2007/10/15: [impl] (thanks Rui Hirokawa)
+ add check HAVE_STDARG_H.
+2007/09/07: [API] rename enc_len() to onig_enc_len() in oniguruma.h.
+2007/09/04: [API] remove ONIGENC_ERR_XXXXX.
+2007/09/03: [API] add error ONIGERR_INVALID_CODE_POINT_VALUE.
+2007/09/03: [impl] change error message to "invaid code point value"
+ for ONIGERR_INVALID_WIDE_CHAR_VALUE.
+2007/09/03: [bug] xxx_code_to_mbclen() should return
+ ONIGERR_INVALID_WIDE_CHAR_VALUE for invalid code point.
+ ex. /[\x{7fffffff}]/ for ASCII encoding.
+2007/08/28: [impl] remove "warning: no previous declaration ...".
+2007/08/21: [impl] remove warnings in enc/mktable.c.
+2007/08/20: [impl] remove "warning: unused parameter"
+2007/08/20: [impl] remove "warning: comparison between signed and unsigned".
+2007/08/06: [impl] remove clear_not_flag_cclass().
+2007/08/03: [bug] fix the case of undefined USE_NAMED_GROUP.
+2007/08/02: [spec] add backref by number.
+2007/08/01: [API] add OnigCtype.
+2007/07/27: [spec] add USE_CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS.
+2007/07/24: [impl] define PLATFORM_UNALIGNED_WORD_ACCESS.
+2007/07/23: [dist] fix doc/FAQ.ja.
+
+2007/07/14: Version 5.9.0
+
+2007/07/13: [bug] add check into onig_reduce_nested_quantifier().
+2007/06/26: [spec] (thanks K.Takata)
+ ONIG_OPTION_SINGLELINE: '$' -> '\Z' (as Perl)
+2007/06/26: [dist] (thanks K.Takata)
+ fix documents API and API.ja.
+2007/06/19: [impl] remove IS_NOT_NULL() check before onig_node_free().
+2007/06/18: [bug] (thanks KUBO Takehiro)
+ WORD_ALIGNMENT_SIZE must be sizeof(OnigCodePoint).
+2007/06/18: [impl] rename CClassNode flags.
+2007/06/18: [bug] initialization miss.
+2007/06/13: [impl] change node type reference NXXXX.
+2007/06/11: [impl] add node type bit.
+2007/06/11: [spec] allow anchor in enclosed repeater. /(\z)*/
+2007/06/11: [impl] rename node types.
+2007/06/08: [impl] remove OP_SET_OPTION_PUSH and OP_SET_OPTION from match_at().
+2007/06/07: [impl] use xvsnprintf().
+2007/06/06: [tune] don't set qn->next_head_exact for string first byte is zero.
+2007/06/06: [impl] remove unused variables.
+
+2007/06/04: Version 5.8.0
+
+2007/06/04: [impl] add #ifndef vsnprintf into regint.h.
+2007/05/31: [dist] add configure option '--enable-crnl-as-line-terminator'.
+2007/05/30: [dist] add sample/crnl.c.
+2007/05/30: [bug] should check USE_CRNL_AS_LINE_TERMINATOR case
+ in onig_search().
+2007/05/29: [impl] move USE_CRNL_AS_LINE_TERMINATOR into regenc.h.
+2007/05/29: [impl] should check USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ in forward_search_range() and backward_search_range().
+
+2007/04/27: Version 5.7.0
+
+2007/04/20: [spec] add config USE_MATCH_RANGE_IS_COMPLETE_RANGE.
+2007/04/20: [impl] refactoring in match_at().
+
+2007/04/12: Version 5.6.1
+
+2007/04/12: [bug] must not use UChar in oniguruma.h.
+2007/04/09: [impl] change STATE_CHECK_BUFF_MAX_SIZE value from 0x8000
+ to 0x4000. [ruby-core:10883]
+
+2007/04/04: Version 5.6.0 (mourning for Hideo Takamatsu)
+
+2007/04/03: [spec] add new notation (?'name'), \k'name', \g'name'.
+2007/04/03: [impl] remove unused variable.
+2007/03/26: [impl] add 'void' to function declarations.
+
+2007/03/06: Version 5.5.3
+
+2007/03/06: [bug] add #include <malloc.h> for bcc32.
+ (In bcc32, alloca() is declared in malloc.h.)
+2007/03/02: [bug] invalid optimization for semi-end-buf in onig_search().
+ ex. /\n\Z/.match("aaaaaaaaaa\n")
+2007/03/02: [impl] move range > start check position in end_buf process.
+
+2007/01/09: Version 5.5.2
+
+2007/01/09: [impl] rename USE_EXTERNAL_LOWER_CASE_CONV_TABLE.
+2007/01/05: [tune] select_opt_exact_info() didn't work for empty info.
+ ex. /.a/ make MAP info instead of EXACT info.
+2006/12/28: [impl] add print_enc_string() for ONIG_DEBUG mode.
+
+2006/12/22: Version 5.5.1
+
+2006/12/22: [impl] rename ADD_PAD_TO_SHORT_BYTE_STRING
+ . to USE_PAD_TO_SHORT_BYTE_CHAR.
+2006/12/21: [spec] should check too short multibyte char in parse_exp().
+ add ADD_PAD_TO_SHORT_BYTE_STRING.
+ ex. /\x00/ in UTF16 should be error.
+
+2006/12/06: Version 5.5.0
+
+2006/12/05: [bug] should add unfold-1 codes from folded code into
+ onigenc_unicode_get_case_fold_codes_by_str().
+ (ex. "S" -> "s" -> 0x017f)
+2006/12/05: [new] add flag ONIGENC_CASE_FOLD_TURKISH_AZERI and
+ USE_UNICODE_CASE_FOLD_TURKISH_AZERI. (disabled in default)
+2006/12/04: [spec] remove ONIGENC_CASE_FOLD_FULL.
+2006/11/30: [impl] remove unnecessary check in xxx_mbc_case_fold().
+
+2006/11/29: Version 5.4.0
+
+2006/11/28: [spec] INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR is enabled in
+ default case fold status.
+2006/11/28: [spec] rename ONIGENC_CASE_FOLD_MULTI_CHAR to
+ INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR.
+2006/11/28: [impl] remove USE_UNICODE_CASE_FOLD_MULTI_CHAR.
+2006/11/28: [impl] remove Fold[123]Table and add FoldTable.
+2006/11/27: [impl] change tool/unicode_fc.rb to see CaseFolding.txt.
+2006/11/24: [bug] should call callback for to[j] <-> to[k] in
+ onigenc_unicode_apply_all_case_fold().
+
+2006/11/22: Version 5.3.0
+
+2006/11/22: [dist] add index_ja.html.
+2006/11/22: [impl] undef ONIG_ESCAPE_UCHAR_COLLISION in regint.h and regenc.h.
+2006/11/21: [bug] invalid array access.
+2006/11/21: [impl] escape UChar collision from config.h.
+2006/11/20: [new] add Hiragana/Katakana properties into Shift_JIS.
+2006/11/20: [impl] fix CR_Katakana[] values in EUC-JP.
+2006/11/17: [impl] declare strend hash table functions in regint.h.
+2006/11/17: [impl] move property list functions to regenc.c.
+2006/11/17: [new] add Hiragana/Katakana properties into EUC-JP.
+2006/11/15: [impl] remove NOT_RUBY from AM_CFLAGS.
+
+2006/11/14: Version 5.2.0
+
+2006/11/14: [impl] remove program codes for Ruby.
+2006/11/14: [impl] reduce program codes for Ruby.
+2006/11/10: [bug] 0x24, 0x2b, 0x3c, 0x3d, 0x3e, 0x5e, 0x60, 0x7c, 0x7e
+ should be [:punct:].
+2006/11/09: [new] (thanks Byte)
+ add new character encoding CP1251.
+2006/11/08: [impl] rename QUALIFIER -> QUANTIFIER.
+
+2006/11/07: Version 5.1.0
+
+2006/11/07: [dist] remove test.rb, testconv.rb and testconvu.rb.
+2006/11/07: [bug] get_case_fold_codes_by_str() should handle 'Ss' and 'sS'
+ combination for ess-tsett.
+2006/11/07: [impl] apply_all_case_fold() doesn't need to return all
+ case character combination for multi-character folding.
+ (ONIGENC_CASE_FOLD_MULTI_CHAR)
+2006/11/07: [bug] (thanks Byte)
+ add { 0xa3, 0xb3 } to CaseFoldMap[] for KOI8-R.
+2006/11/06: [spec] change ONIG_OPTION_FIND_LONGEST to search all of
+ the string range.
+ add USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE.
+2006/11/02: [impl] re-implement expand_case_fold_string() for
+ ONIGENC_CASE_FOLD_MULTI_CHAR.
+2006/10/30: [impl] add NSTR_DONT_GET_OPTINFO flag.
+2006/10/30: [impl] (thanks K.Takata)
+ add THREAD_SYSTEM_INIT and THREAD_SYSTEM_END.
+2006/10/30: [bug] (thanks Wolfgang Nadasi-Donner)
+ invalid offset value was used in STATE_CHECK_BUFF_INIT().
+2006/10/27: [tune] speed up ONIGENC_MBC_CASE_FOLD() for UTF-16, UTF-32.
+ (ASCII code check)
+2006/10/27: [tune] (thanks Kornelius Kalnbach)
+ String#scan for long string needs long time compare with
+ old Ruby
+ by initialization time for combination explosion check
+ ex. ("test " * 100_000).scan(/\w*\s?/)
+ change STATE_CHECK_BUFF_MAX_SIZE from 0x8000000 to 0x8000.
+ reduce initialization area of state_check_buff.
+2006/10/25: [impl] add DISABLE_CASE_FOLD_MULTI_CHAR().
+
+2006/10/23: Version 5.0.1
+
+2006/10/23: [bug] should fold string in expand_case_fold_string().
+2006/10/23: [bug] (thanks Km)
+ too many case fold/unfold expansion problem.
+ don't expand and set ambig flag to the string node.
+ (except ONIGENC_CASE_FOLD_MULTI_CHAR).
+2006/10/23: [bug] (thanks K.Takata)
+ invalid \p{Alnum}, \p{ASCII}, [:alnum:], [:ascii:].
+ fix OnigEncAsciiCtypeTable[] etc...
+2006/10/23: [spec] (thanks K.Takata)
+ add [:word:] POSIX bracket.
+2006/10/23: [bug] (thanks K.Takata)
+ \p{Word} doesn't work.
+2006/10/20: [impl] don't expand for AMBIG_FLAG string in
+ expand_case_fold_string().
+
+2006/10/19: Version 5.0.0
+
+2006/10/18: [bug] ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM should be 13.
+2006/10/18: [impl] remove unused functions.
+2006/10/18: [dist] update documents.
+2006/10/18: [API] move OnigMetaCharTableType to OnigSyntaxType.
+2006/10/18: [dev] add too/unicode_fc.rb, unicode_pc.rb.
+2006/10/18: [dist] remove MANIFEST-RUBY from distribution.
+2006/10/18: [bug] return duplicated code in
+ onigenc_unicode_get_case_fold_codes_by_str().
+2006/10/18 [API] remove ONIG_SYN_OP2_CHAR_PROPERTY_PREFIX_IS.
+2006/10/18: [dev] add tool/19.
+2006/10/18: [dist] remove target 19 from Makefile.am.
+2006/10/17: [dist] add enc/unicode.c to target 19 of win32/Makefile.
+2006/10/17: [impl] change type for escape VC++ warning.
+2006/10/17: [API] rename ONIGENC_CASE_FOLD_NONE to ONIGENC_CASE_FOLD_MIN.
+2006/10/17: [dist] remove INSTALL-RUBY from distribution.
+2006/10/17: [dist] update LTVERSION to "2:0:0".
+2006/10/17: [impl] remove warnings for [make CFLAGS="-g -O2 -Wall"]
+ in the case USE_UNICODE_PROPERTIES and
+ USE_UNICODE_CASE_FOLD_MULTI_CHAR are undefined.
+2006/10/17: [impl] remove warnings for [make CFLAGS="-g -O2 -Wall"].
+2006/10/17: [impl] re-implement onigenc_unicode_apply_all_case_fold().
+ multi-char by case folded char-class is treated as
+ caseless-string (ambig flag on).
+ enable OP_EXACT1_IC and OP_EXACTN_IC.
+2006/10/16: [bug] unfold expand for 1->2, 1->3 folding in
+ onigenc_unicode_apply_all_case_fold().
+ add CaseFoldExpand_12[], CaseFoldExpand_13[].
+2006/10/16: [bug] (thanks Akinori Musha)
+ first argument of rb_warn() should be format string.
+2006/10/16: [impl] add msa.state_check_buff_size initialization
+ in onig_search().
+2006/10/16: [spec] re-implement Unicode Caseless Match codes.
+2006/10/10: [bug] should call onig_st_free_table() in
+ onig_free_shared_cclass_table().
+2006/10/10: [impl] remove OnigCompCaseFoldCodes.
+2006/10/10: [impl] remove onigenc_ascii_is_mbc_ambiguous() and
+ onigenc_mbn_is_mbc_ambiguous().
+2006/10/10: [API] remove is_mbc_ambiguous() member from OnigEncodingType.
+2006/10/10: [API] rename onig_set_default_ambig_flag() to
+ onig_set_default_case_fold_flag(),
+ onig_get_default_ambig_flag() to
+ onig_get_default_case_fold_flag(),
+ onig_get_ambig_flag() to onig_get_case_fold_flag().
+2006/10/10: [API] rename ambig_flag to case_fold_flag.
+2006/10/10: [API] rename OnigAmbigType to OnigCaseFoldType.
+2006/10/10: [impl] rename ONIGENC_IS_CODE_SB_WORD() to IS_CODE_SB_WORD()
+ and move to regint.h.
+2006/10/10: [impl] remove OP_WORD_SB and OP_WORD_MB.
+2006/10/10: [impl] remove OP_EXACT1_IC and OP_EXACTN_IC from match_at().
+2006/10/10: [impl] should free new_str in expand_case_fold_string().
+2006/10/06: [dist] add test entries to sample/encode.c.
+2006/10/06: [impl] re-implement caseless match (case-fold).
+2006/10/06: [impl] expand string node by case fold variations.
+ add expand_case_fold_string().
+2006/10/05: [spec] rename OnigCompAmbigCodeItem to OnigCaseFoldCodeItem.
+2006/10/05: [spec] add apply_all_case_fold() and get_case_fold_codes_by_str()
+ to OnigEncodingType.
+2006/10/05: [spec] remove ambig_flag, get_all_pair_ambig_codes() and
+ get_all_comp_ambig_codes() member from OnigEncodingType.
+2006/10/03: [impl] rename mbc_to_normalize() to mbc_case_fold().
+2006/10/03: [spec] rename ONIGENC_AMBIGUOUS_MATCH_XXX
+ to ONIGENC_CASE_FOLD_XXX.
+ rename ONIGENC_CASE_FOLD_COMPOUND
+ to ONIGENC_CASE_FOLD_MULTI_CHAR.
+2006/10/02: [impl] remove all ONIG_RUBY_M17N part.
+2006/09/29: [impl] initialize state_check_buff_size in STATE_CHECK_BUFF_INIT().
+ make valgrind happy.
+2006/09/22: [impl] remove parse time ctype values (CTYPE_WORD etc...)
+2006/09/22: [ruby] enable USE_BACKREF_AT_LEVEL for Ruby mode.
+2006/09/22: [spec] (thanks Allan Odgaard)
+ allow upper case letter as the first character
+ of group name.
+ fetch_name() and fetch_name_with_level()
+2006/09/21: [impl] convert to ascii for parameter string in
+ onig_error_code_to_str().
+ add enc member into OnigErrorInfo.
+2006/09/21: [dist] update documents for Unicode Property.
+2006/09/21: [new] add Unicode Properties. (enc/unicode.c)
+ Any, Assigned, C, Cc, L, Lm, Arabic, Greek etc...
+2006/09/21: [impl] add USE_UNICODE_PROPERTIES into regenc.h.
+2006/09/21: [impl] remove USE_UNICODE_FULL_RANGE_CTYPE.
+2006/09/20: [impl] change ONIGENC_CTYPE_XXXX to sequencial values.
+ add BIT_CTYPE_XXXX bit flags to regenc.h.
+ update XXXX_CtypeTable[] for BIT_CTYPE_ALNUM.
+2006/09/19: [memo] move from CVS to Subversion (1.3.2).
+2006/09/19: [impl] (thanks KOYAMA Tetsuji)
+ HAVE_STDARG_PROTOTYPES was not defined in Mac OS X
+ by Xcode 2.4(gcc 4.0.1) problem. [php-dev 1312] etc...
+2006/09/15: [bug] (thanks Allan Odgaard)
+ out of range access in bm_search_notrev().
+ (p < s)
+2006/09/13: [impl] add ONIGENC_CTYPE_ENC_EXT flag.
+2006/09/13: [spec] remove 'Is' prefix check for property name
+ from fetch_char_property_to_ctype().
+2006/09/13: [API] add property_name_to_ctype member to OnigEncodingType.
+2006/09/12: [spec][ruby] add ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY and
+ ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT to OnigSyntaxRuby.
+
+2006/09/08: Version 4.4.2
+
+2006/09/08: [test] success in ruby 1.9.0 (2006-08-22) [i686-linux].
+2006/09/08: [bug] (thanks K.Takata)
+ out of range access in bm_search_notrev().
+2006/09/04: [spec] (thanks K.Takata)
+ allow look-behind in negative look-behind.
+ ex. /(?<!(?<=a)b|c)d/
+
+2006/08/29: Version 4.4.1
+
+2006/08/29: [test] success in ruby 1.9.0 (2006-08-22) [i686-linux].
+2006/08/29: [dist] (thanks Seiji Masugata)
+ add configure option --enable-combination-explosion-check
+
+2006/08/25: Version 4.4.0
+
+2006/08/25: [test] success in ruby 1.9.0 (2006-08-22) [i686-linux].
+2006/08/25: [impl] add_state_check_num() should be enclosed in
+ ifdef USE_COMBINATION_EXPLOSION_CHECK.
+2006/08/23: [spec] config USE_COMBINATION_EXPLOSION_CHECK is enabled
+ in Ruby mode only.
+2006/08/22: [impl] remove last line comma in enum OpCode.
+2006/08/22: [impl] remove OP_STATE_CHECK_ANYCHAR_STAR_PEEK_NEXT and
+ OP_STATE_CHECK_ANYCHAR_ML_STAR_PEEK_NEXT.
+2006/08/22: [impl] remove OP_BACKREF3.
+
+2006/08/21: Version 4.3.1
+
+2006/08/21: [test] success in ruby 1.9.0 (2006-07-28) [i686-linux].
+2006/08/21: [impl] change stack type values
+ and re-define STK_MASK_TO_VOID_TARGET etc...
+2006/08/21: [impl] set repeat_range[].upper to 0x7fffffff as infinite.
+2006/08/21: [impl] add STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE.
+2006/08/21: [impl] reduce (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n}
+2006/09/21: [impl] reduce (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n}
+ if backreference is not used.
+2006/08/17: [bug] should check scan_env.num_call > 0 for backrefed pattern
+ in combination explosion check.
+
+2006/08/17: Version 4.3.0
+
+2006/08/17: [test] success in ruby 1.9.0 (2006-07-28) [i686-linux].
+2006/08/17: [new] add config USE_COMBINATION_EXPLOSION_CHECK.
+ check /(.+)*/, /(\s*foo\s*)*/ etc...
+ [API] add num_comb_exp_check member in regex_t.
+ [dist] change LTVERSION value to "1:0:0" in configure.in.
+2006/08/15: [bug] OP_REPEAT_INC process in match_at().
+ should check repeat-count >= range-upper and
+ range-upper may be infinite.
+
+2006/08/11: Version 4.2.3
+
+2006/08/11: [test] success in ruby 1.9.0 (2006-07-28) [i686-linux].
+2006/08/10: [impl] remove double call in set_qualifier().
+2006/08/10: [impl] remove by_number member in QualifierNode.
+2006/08/09: [impl] remove a comma at the end of enum ReduceType
+ for escape warning on Mac OS X.
+2006/08/07: [impl] remove warning in regcomp.c.
+2006/08/07: [spec] move definition of USE_BACKREF_AT_LEVEL into NOT_RUBY.
+
+2006/08/03: Version 4.2.2
+
+2006/08/03: [test] success in ruby 1.9.0 (2006-07-28) [i686-linux].
+2006/08/03: [bug] (thanks Hiroyuki Yamamoto)
+ segmentation fault in regexec(). (POSIX API)
+2006/08/02: [bug] combination of \G in look-ahead/look-behind and other
+ anchors(\A, \z, \Z) cause invalid result.
+ ex. /(?!\G)a\z/.match("ba")
+ start arg. of MATCH_ARG_INIT() should be original
+ arg. of onig_search().
+
+2006/07/31: Version 4.2.1
+
+2006/07/31: [test] success in ruby 1.9.0 (2006-07-28) [i686-linux].
+2006/07/31: [bug] (thanks Kimura Minoru)
+ re-implement bm_search_notrev().
+2006/07/31: [impl] bm_search_notrev() refactoring.
+2006/07/31: [bug] (thanks Kimura Minoru)
+ fix incomplete multibyte string in exact info.
+2006/07/31: [impl] (thanks Seiji Masugata)
+ remove cast in va_init_list() for Intel C Compiler.
+
+2006/07/18: Version 4.2.0
+
+2006/07/18: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/07/18: [new] (thanks Wolfgang Nadasi-Donner)
+ add back reference with nest level.
+ \k<name+n>, \k<name-n>
+2006/07/11: [impl] change long to unsigned long for ONIG_OPTION_XXX
+ and ONIG_SYN_XXX number literals.
+
+2006/07/03: Version 4.1.2
+
+2006/07/03: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/07/03: [spec] (thanks Wolfgang Nadasi-Donner)
+ allow \G in look-behind.
+ add ANCHOR_BEGIN_POSITION flag in setup_tree().
+2006/06/12: [impl] (thanks matz)
+ fix cast from char* to const char*
+ in onig_snprintf_with_pattern().
+ fix cast from char* to const char*
+ for PopularQStr[] and ReduceQStr[].
+
+2006/05/22: Version 4.1.1
+
+2006/05/22: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/05/22: [impl] add position string argument to STACK_BASE_CHECK().
+2006/05/22: [bug] (thanks NARUSE, Yui)
+ add STK_NULL_CHECK_END to IS_TO_VOID_TARGET().
+ ex. core dump in
+ /(?<pare>\(([^\(\)]++|\g<pare>)*+\))/.match('((a))')
+
+2006/05/15: Version 4.1.0
+
+2006/05/15: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/05/15: [impl] thread atomic changes for onig_end() and
+ onig_free_node_list().
+2006/05/15: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2005/05/15: [dist] update API, API.ja, FAQ, FAQ.ja.
+2006/05/15: [spec] remove onig_recompile(), onig_recompile_deluxe()
+ and re_recompile_pattern().
+ add config USE_RECOMPILE_API.
+2006/05/15: [impl] improved thread safe implementation of onig_search()
+ and onig_match().
+
+2006/05/11: Version 4.0.4
+
+2006/05/11: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/05/11: [bug] (thanks Yuji Kaneda)
+ dead-lock in onig_end().
+2006/05/11: [dist] update index.html.
+
+2006/05/08: Version 4.0.3
+
+2006/05/08: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/05/08: [bug] (thanks Allan Odgaard)
+ Segmentation fault in backward search.
+ ex. /^\t.*$/
+2006/04/18: [dist] update index.html.
+2006/04/05: [dist] update index.html.
+2006/03/24: [dist] update doc/RE, doc/RE.ja.
+
+2006/03/23: Version 4.0.2
+
+2006/03/22: [test] success in ruby 1.9.0 (2006-03-01) [i686-linux].
+2006/03/22: [impl] add both of ONIG_OPTION_DONT_CAPTURE_GROUP
+ and ONIG_OPTION_CAPTURE_GROUP check.
+2006/03/22: [spec] add error code ONIGERR_INVALID_COMBINATION_OF_OPTIONS.
+2006/03/22: [impl] remove USE_NAMED_GROUP condition from
+ ONIG_OPTION_DONT_CAPTURE_GROUP check in parse_effect().
+2006/03/22: [new] add API onig_noname_group_capture_is_active().
+2006/03/01: [spec] rename regex object type from regex_t to OnigRegexType.
+ add typedef OnigRegexType regex_t
+ unless ONIG_ESCAPE_REGEX_T_COLLISION is defined.
+2006/02/27: [spec] change ONIG_MAX_MULTI_BYTE_RANGES_NUM from 1000
+ to 10000. (for docdiff program)
+2006/02/17: [dist] change COPYING year 2005 -> 2006.
+
+2006/02/07: Version 4.0.1
+
+2006/02/07: [test] success in ruby 1.9.0 (2005-11-28) [i686-linux].
+2006/02/07: [bug] memory leaks in onig_free_shared_cclass_table().
+2006/02/03: [ruby] add -m 0644 option to install command in "make 19".
+2006/02/03: [impl] rename ANCHOR_ANYCHAR_STAR_PL to ANCHOR_ANYCHAR_STAR_ML.
+ change from IS_POSIXLINE() to IS_MULTILINE()
+ for ANCHOR_ANYCHAR_START/_ML decision
+ in optimize_node_left().
+2006/01/26: [dist] update index.html for Oniguruma 2.5.3.
+2006/01/25: [dist] update URL in index.html.
+
+2006/01/24: Version 4.0.0
+
+2006/01/24: [test] success in ruby 1.9.0 (2005-11-28) [i386-cygwin].
+2006/01/24: [test] success in ruby 1.9.0 (2005-11-28) [i686-linux].
+2006/01/24: [dist] remove warnings from sample/encode.c.
+2006/01/24: [dist] change install description in README(.ja).
+2006/01/24: [dist] remove re.c.XXX.patch from distribution and CVS.
+2006/01/24: [dist] --- support shared library ---
+ use GNU libtool/automake.
+ change configure.in and add Makefile.am, sample/Makefile.am.
+ add AUTHORS file.
+2006/01/24: [dist] test programs return exit code -1 when test fails.
+2006/01/24: [bug] (thanks KIMURA Koichi)
+ invalid syntax definition in ONIG_SYNTAX_GREP.
+ ONIG_SYN_OP_BRACE_INTERVAL
+ -> ONIG_SYN_OP_ESC_BRACE_INTERVAL
+2006/01/23: [dist] fix configure.in for onig-config.
+2006/01/19: [new] add new config USE_UNICODE_ALL_LINE_TERMINATORS.
+ (U+000d, U+0085, U+2028, U+2029)
+2005/12/29: [dist] change pmatch array size to 25 in testconv.rb.
+2005/12/26: [dist] fix name in test.rb.
+2005/12/26: [dist] update index.html for 2.5.1.
+
+2005/11/29: Version 3.9.1
+
+2005/11/29: [test] success in ruby 1.9.0 (2005-11-28) [i686-linux].
+2005/11/24: [test] success in ruby 1.9.0 (2005-08-09) [i686-linux].
+2005/11/21: [test] success in ruby 1.9.0 (2005-11-20) [i386-cygwin].
+2005/11/21: [bug] (thanks Allan Odgaard)
+ utf-8 character comments in extended mode leads
+ invalid result.
+ ex. /(?x)(?<= # <any-utf-8 multibyte char>o\n~) /
+ fix onigenc_unicode_is_code_ctype() and
+ utf8_is_code_ctype().
+2005/11/20: [bug] (thanks MATSUMOTO Satoshi) (thanks Isao Sonobe)
+ begin-line anchor and BM search optimization leads
+ invalid result in UTF-16/32.
+ fix in set_optimize_exact_info().
+
+2005/11/20: Version 3.9.0
+
+2005/11/20: [test] success in ruby 1.9.0 (2005-11-20) [i386-cygwin].
+2005/11/20: [test] success in ruby 1.9.0 (2005-10-18) [i386-cygwin].
+2005/11/20: [new] add new config USE_CRNL_AS_LINE_TERMINATOR.
+ (!!! NO SUPPORT experimental option !!!)
+2005/11/15: [bug] (thanks Allan Odgaard)
+ tok->escape was not cleared in fetch_token_in_cc().
+ ex. [\s&&[^\n]] makes wrong result.
+2005/10/18: [impl] (thanks nobu)
+ change sjis_mbc_enc_len()
+ and node_new_cclass_by_codepoint_range() scope to static.
+2005/09/05: [dist] remove link to MultiFind.
+2005/09/01: [dist] add link to yagrep.
+
+2005/08/23: Version 3.8.9
+
+2005/08/23: [test] success in ruby 1.9.0 (2005-08-09) [i686-linux].
+2005/08/23: [inst] fix Makefile.in for make ctest/ptest.
+
+2005/08/23: Version 3.8.8
+
+2005/08/23: [test] success in ruby 1.9.0 (2005-08-09) [i686-linux].
+2005/08/23: [impl] split is_code_in_cc() from onig_is_code_in_cc().
+2005/08/23: [impl] should check DATA_ENSURE() at OP_CCLASS_NODE in match_at().
+2005/08/23: [impl] (thanks akr)
+ add ONIG_OPTION_MAXBIT for escape conflict with
+ Ruby's option.
+2005/08/22: [impl] escape GCC 4.0 warnings for testc.c.
+2005/08/22: [bug] (thanks nobu, matz) [ruby-dev:26840]
+ UTF-8 0xFE, 0xFF handling bug in code_is_in_cclass_node().
+ abort on /\S*/ =~ "\xfe"
+2005/08/22: [impl] escape GCC 4.0 warnings for sample/*.c.
+2005/08/22: [impl] fix testconvu.rb.
+2005/08/22: [impl] escape GCC 4.0 warnings.
+
+2005/08/09: Version 3.8.7
+
+2005/08/09: [test] success in ruby 1.9.0 (2005-08-09) [i686-linux].
+2005/08/09: [bug] (thanks Allan Odgaard)
+ should not call enc_len() for s == range
+ in onig_search().
+2005/08/01: [dist] add mkdir $prefix, mkdir $exec_prefix to make install.
+
+2005/07/27: Version 3.8.6
+
+2005/07/27: [test] success in ruby 1.9.0 (2005-07-26) [i686-linux].
+2005/07/27: [impl] update onig-config.in.
+2005/07/26: [new] (thanks Yen-Ju Chen)
+ add Oniguruma configuration check program.
+ (onig-config.in)
+
+2005/07/14: Version 3.8.5
+
+2005/07/14: [test] success in ruby 1.9.0 (2005-07-14) [i686-linux].
+2005/07/11: [test] success in ruby 1.9.0 (2005-07-04) [i686-linux].
+2005/07/11: [bug] (thanks nobu) [ruby-dev:26505]
+ invalid handling for /\c\x/ and /\C-\x/.
+ fix fetch_escaped_value().
+2005/07/05: [impl] (thanks Alexey Zakhlestine)
+ escape GCC 4.0 warnings.
+
+2005/07/01: Version 3.8.4
+
+2005/07/01: [test] success in ruby 1.9.0 (2005-07-01) [i686-linux].
+2005/06/30: [test] success in ruby 1.9.0 (2005-06-28) [i686-linux].
+2005/06/30: [dist] add GB 18030 test to sample/encode.c.
+2005/06/30: [impl] escape warning of gb18030_left_adjust_char_head().
+2005/06/30: [new] (contributed by KUBO Takehiro)
+ add new character encoding ONIG_ENCODING_GB18030.
+2005/06/30: [bug] invalid ctype check for multibyte encodings.
+ ("graph", "print")
+ fix onigenc_mb2/4_is_code_ctype(),
+ eucjp_is_code_ctype() and sjis_is_code_ctype().
+2005/06/30: [bug] invalid conversion from code point to mbc in
+ onigenc_mb4_code_to_mbc().
+
+2005/06/28: Version 3.8.3
+
+2005/06/28: [test] success in ruby 1.9.0 (2005-06-28) [i686-linux].
+2005/06/27: [test] success in ruby 1.9.0 (2005-05-31) [i686-linux].
+2005/06/27: [bug] (thanks Wolfgang Nadasi-Donner)
+ invalid check for never ending recursion.
+ lower zero quantifier should be treated as
+ a non-recursive call alternative.
+ ex. /(?<bal>[^()]*(\(\g<bal>\)[^()]*)*)/
+2005/06/15: [impl] add divide_ambig_string_node_sub().
+2005/06/15: [dist] add a test to sample/encode.c.
+2005/06/10: [new] add ONIG_SYNTAX_PERL_NG. (Perl + named group)
+
+2005/06/01: Version 3.8.2
+
+2005/06/01: [test] success in ruby 1.9.0 (2005-05-31) [i686-linux].
+2005/05/31: [dist] add doc/FAQ and doc/FAQ.ja.
+2005/05/31: [impl] minor change in node_new().
+2005/05/30: [test] success in ruby 1.9.0 (2005-05-11) [i686-linux].
+2005/05/30: [bug] (thanks Allan Odgaard)
+ FreeNodeList null check should be on thread-atomic
+ in node_new().
+
+2005/05/11: Version 3.8.1
+
+2005/05/11: [test] success in ruby 1.9.0 (2005-05-11) [i386-mswin32].
+2005/05/11: [dist] update win32/Makefile (make 19).
+2005/05/11: [test] success in ruby 1.9.0 (2005-05-11) [i686-linux].
+2005/05/06: [test] success in ruby 1.9.0 (2005-05-06) [i686-linux].
+2005/05/06: [impl] (thanks nobu) [ruby-core:4815]
+ add #ifdef USE_VARIABLE_META_CHARS to goto label.
+2005/04/25: [test] success in ruby 1.9.0 (2005-04-25) [i686-linux].
+2005/04/25: [impl] change DEFAULT_WARN_FUNCTION and DEFAULT_VERB_WARN_FUNCTION
+ to onig_rb_warn() and onig_rb_warning().
+
+2005/04/15: Version 3.8.0
+
+2005/04/15: [test] success in ruby 1.9.0 (2005-04-14) [i686-linux].
+2005/04/01: [test] success in ruby 1.9.0 (2005-03-24) [i686-linux].
+2005/04/01: [impl] (thanks Joe Orton)
+ (thanks Moriyoshi Koizumi)
+ many const-ification to many *.[ch] files.
+
+2005/03/25: Version 3.7.2
+
+2005/03/25: [test] success in ruby 1.9.0 (2005-03-24) [i686-linux].
+2005/03/23: [test] success in ruby 1.9.0 (2005-03-20) [i686-linux].
+2005/03/23: [test] success in ruby 1.9.0 (2005-03-08) [i686-linux].
+2005/03/23: [new] add ONIG_SYNTAX_ASIS.
+2005/03/23: [new] add ONIG_SYN_OP2_INEFFECTIVE_ESCAPE.
+2005/03/09: [spec] rename MBCTYPE_XXX to RE_MBCTYPE_XXX. (GNU API)
+2005/03/08: [test] success in ruby 1.9.0 (2005-03-08) [i686-linux].
+2005/03/08: [impl] (thanks matz) [ruby-dev:25783]
+ should not allocate memory for key data in st.c.
+ move st_*_strend() functions from st.c. fixed some
+ potential memory leaks.
+ (imported from Ruby 1.9 2005-03-08)
+
+2005/03/07: Version 3.7.1
+
+2005/03/07: [test] success in ruby 1.9.0 (2005-03-07) [i686-linux].
+2005/03/07: [impl] (thanks Rui Hirokawa)
+ add ONIG_ESCAPE_UCHAR_COLLISION.
+ rename UChar to OnigUChar in oniguruma.h.
+2005/03/07: [impl] remove declarations for Ruby in oniggnu.h.
+2005/03/05: [bug] ANCHOR_ANYCHAR_STAR didn't work in onig_search().
+2005/03/01: [dist] remove oniggnu.h from MANIFEST-RUBY.
+ remove oniggnu.h from make 19.
+2005/03/01: [bug] (thanks matz) [ruby-dev:25778]
+ uninitialized member (OptEnv.backrefed_status)
+ was used.
+
+2005/02/19: Version 3.7.0
+
+2005/02/19: [test] success in ruby 1.9.0 (2005-02-19) [i386-cygwin].
+2005/02/19: [new] (thanks Minero Aoki)
+ add onig_region_set().
+2005/02/19: [API] change onig_region_init() to extern.
+2005/02/19: [dist] remove reggnu.c from MANIFEST-RUBY.
+ remove reggnu.c from make 19.
+2005/02/19: [dist] update doc/API and doc/API.ja.
+2005/02/19: [test] success in ruby 1.9.0 (2005-02-19) [i386-cygwin].
+2005/02/19: [impl] (thanks Alexey Zakhlestine)
+ change UChar* to const UChar* in oniguruma.h,
+ regenc.h and regparse.h.
+2005/02/13: [impl] change UChar* to const UChar* in oniguruma.h and
+ onigposix.h and st.h.
+2005/02/12: [test] success in ruby 1.9.0 (2005-02-11) [i386-cygwin].
+2005/02/12: [bug] (thanks nobu) [ruby-dev:25676]
+ type_cclass_hash() fix overrun.
+2005/02/09: [test] success in ruby 1.9.0 (2005-02-09) [i686-linux].
+2005/02/09: [spec] add RE_OPTION_FIND_NOT_EMPTY etc.. to oniggnu.h.
+2005/02/09: [dist] remove hash.c.patch.
+2005/02/07: [impl] remove re_mbctab, mbctab_ascii etc...
+ (USE_COMPATIBILITY_FOR_RUBY_EXTENSION_LIBRARY)
+
+2005/02/04: Version 3.6.0
+
+2005/02/04: [test] success in ruby 1.9.0 (2005-02-04) [i686-linux].
+2005/02/01: [bug] add key_free() call to st_free_table().
+2005/02/01: [new] add onig_get_default_ambig_flag() and
+ onig_set_default_ambig_flag().
+2005/02/01: [dist] update MANIFEST-RUBY.
+2005/01/31: [test] success in ruby 1.9.0 (2005-01-29) [i686-linux].
+2005/01/31: [spec] remove ONIGENC_AMBIGUOUS_MATCH_COMPOUND
+ from ONIGENC_AMBIGUOUS_MATCH_DEFAULT.
+2005/01/31: [dist] update Makefile.in (make 19).
+2005/01/29: [memo] (thanks Kazuo Saito)
+ Oniguruma 3.5.4 was merged to Ruby 1.9.0.
+2005/01/28: [impl] (thanks UK-taniyama)
+ add extern "C" { } directive to oniguruma.h, oniggnu.h
+ and onigposix.h for C++.
+2005/01/25: [impl] remove nested function call for xxx_code_to_mbclen().
+ (euc_kr.c, euc_tw.c, big5.c)
+
+2005/01/19: Version 3.5.4
+
+2005/01/19: [test] success in ruby 1.9.0 (2005-01-05) [i686-linux].
+2005/01/19: [bug] (thanks Isao Sonobe)
+ callback function argument name_end of onig_foreach_name()
+ was wrong.
+ name key of name table should be null terminated for
+ character encoding length.
+ add strdup_with_null(), rename onig_strdup() to k_strdup().
+ use e->name_len in i_names().
+2005/01/17: [impl] (thanks UK-taniyama)
+ add HAVE_SYS_TYPES_H to config.h.in.
+
+2005/01/13: Version 3.5.3
+
+2005/01/13: [test] success in ruby 1.9.0 (2005-01-05) [i686-linux].
+2005/01/13: [bug] ignore case match bug.
+ ex. /s+/iu.match("SSSSS") ==> [4..5]
+ fix OP_EXACT1_IC, OP_EXACTN_IC process.
+2005/01/13: [bug] (thanks Isao Sonobe)
+ ignore case match bug.
+ ex. /is/iu.match("ss") fail.
+ fix str_lower_case_match() etc.
+
+2005/01/05: Version 3.5.2
+
+2005/01/05: [test] success in ruby 1.9.0 (2005-01-05) [i686-linux].
+2005/01/05: [test] success in ruby 1.9.0 (2004-12-16) [i686-linux].
+2005/01/05: [bug] (thanks Isao Sonobe)
+ ignore case match bug.
+ ex. /s+/iu.match("sssss") ==> [4..5]
+ fix OP_EXACT1_IC, OP_EXACTN_IC process.
+2005/01/05: [bug] (thanks Isao Sonobe)
+ group name table should be renumbered.
+ add onig_renumber_name_table().
+2004/12/24: [dist] remove file onigcmpt200.h.
+
+2004/12/17: Version 3.5.1
+
+2004/12/17: [dist] add INSTALL-RUBY to archive.
+2004/12/16: [test] success in ruby 1.9.0 (2004-12-16) [i686-linux].
+2004/12/16: [dist] update hash.c.patch.
+2004/12/15: [bug] (thanks matz)
+ char > 127 should be casted to unsigned char. (utf8.c)
+2004/12/13: [impl] add HAVE_PROTOTYPES and HAVE_STDARG_PROTOTYPES definition
+ to oniguruma.h in the case __cplusplus.
+2004/12/06: [dist] update doc/RE and doc/RE.ja.
+2004/12/03: [impl] (thanks nobu)
+ st.h fix prototype for C++.
+
+2004/12/03: Version 3.5.0
+
+2004/12/02: [test] success in ruby 1.9.0 (2004-12-02) [i686-linux].
+2004/12/01: [test] success in ruby 1.9.0 (2004-12-01) [i386-mswin32].
+2004/12/01: [dist] add make targets 19 and 19up to win32/Makefile.
+2004/12/01: [test] success in ruby 1.9.0 (2004-12-01) [i386-cygwin].
+2004/12/01: [test] success in ruby 1.9.0 (2004-12-01) [i686-linux].
+2004/12/01: [impl] double cast for escape warning in Cygwin.
+ (HashDataType* )((void* )(&e)) in regparse.c
+2004/12/01: [test] success in ruby 1.9.0 (2004-11-30) [i686-linux].
+2004/12/01: [tune] change implementation of clear_opt_map_info().
+ (which was 10-16% cost in gprof result for my test program)
+2004/12/01: [dist] remove regex.c from distribution files.
+2004/11/30: [memo] remove targets 16 and 18 from Makefile.in.
+2004/11/30: [test] success in ruby 1.9.0 (2004-11-30) [i686-linux].
+2004/11/30: [inst] add "cp -p st.[ch] st.[ch].ruby_orig" to "make 19".
+2004/11/30: [tune] map_position_value() return 20 if code is 0
+ and minimum enclen > 1.
+2004/11/30: [test] success in ruby 1.9.0 (2004-11-29) [i686-linux].
+2004/11/30: [impl] minor changes for multi-thread in regexec.c and regcomp.c.
+2004/11/30: [impl] change THREAD_PASS_LIMIT_COUNT value from 10 to 8.
+2004/11/30: [impl] add THREAD_ATOMIC_XXX to FreeNodeList access in regparse.c
+2004/11/29: [impl] add USE_MULTI_THREAD_SYSTEM.
+2004/11/29: [memo] add hash.c.patch to CVS.
+2004/11/29: [dist] change mail address to 'sndgk393 AT ...'
+2004/11/29: [dist] add -s option (silent mode) to test.rb.
+2004/11/29: [tune] change THRESHOLD_RANGE_NUM_FOR_SHARE_CCLASS value
+ from 20 to 8.
+2004/11/29: [inst] add make target "19up".
+2004/11/29: [dist] change Oniguruma Home Page URL.
+2004/11/29: [impl] remove onig_is_in_code_range_array().
+2004/11/29: [dist] fix doc/RE and RE.ja (character types).
+2004/11/26: [dist] fix win32/Makefile.
+2004/11/26: [dist] fix doc/RE and RE.ja (multibyte character types).
+2004/11/26: [impl] add onig_free_shared_cclass_table().
+2004/11/26: [impl] move definition USE_UNICODE_FULL_RANGE_CTYPE to regenc.h.
+2004/11/26: [impl] add opcode OP_CCLASS_NODE.
+2004/11/26: [impl] move definition of CClassNode to regint.h.
+2004/11/26: [impl] add type PointerType in regint.h.
+2004/11/25: [impl] remove ONIGENC_CTYPE_MOD_NOT.
+2004/11/25: [impl] rename onig_node_new_cclass_by_codepoint_range to
+ node_new_cclass_by_codepoint_range.
+2004/11/25: [impl] remove get_type_cc_node method from OnigEncodingType.
+2004/11/25: [impl] move implementation of shared char-class from enc/*.c
+ to regparse.c.
+2004/11/25: [dist] add hash.c.patch for Ruby 1.9 hash.c change.
+2004/11/22: [impl] change utf8_get_type_node().
+2004/11/22: [impl] add ONIGENC_CTYPE_MOD_NOT.
+2004/11/22: [bug] (thanks MIYAMUKO Katsuyuki)
+ ruby make test fail in HP-UX B.11.23 ia64.
+ should use tok->u.code instead of tok->u.c in
+ the case of TK_CODE_POINT.
+2004/11/19: [bug] (thanks Yoshida Masato)
+ invalid multibyte code causes segmentation fault.
+ ex. /[\xFF-\xFF]/u
+2004/11/19: [bug] (thanks Yoshida Masato)
+ illegal check in char-class range in UTF-8.
+ ex. s = "[\xC2\xA0-\xC3\xBE]"
+ p(Regexp.new(s, nil, "u") =~ "\xC3\xBE")
+2004/11/18: [impl] add onig_node_new_cclass_by_codepoint_range().
+2004/11/18: [impl] remove OnigCodePointRange type. (use OnigCodePoint[].)
+2004/11/17: [bug] (thanks nobu)
+ abort in "a".gsub(/a\Z/, "")
+ fix ONIGENC_STEP_BACK() argument in onig_search().
+2004/11/16: [impl] add key2 member to st_table_entry in st.[ch].
+ change API of st for non-null terminated string key.
+2004/11/16: [impl] add get_type_cc_node method to OnigEncodingType.
+2004/11/15: [impl] add st.h and st.c from Ruby 1.9.
+ use st-hash always.
+2004/11/12: [impl] change member 'not' of CClassNode to 'flags'.
+ add flags FLAG_CCLASS_NOT and FLAG_CCLASS_SHARE.
+2004/11/12: [impl] add onig_is_in_code_range_array() to enc/unicode.c.
+2004/11/12: [impl] fix CRWord in enc/unicode.c and MBWord in enc/utf8.c.
+2004/11/11: [bug] fix enc/utf8.c.
+ size 0 array initializer was compile error in VC++.
+2004/11/09: [inst] (thanks Hiroki YAGITA)
+ change installed file mode to 0644.
+2004/11/09: [bug] (thanks UK-taniyama)
+ wrong definitions GET_RELADDR_INC(), GET_ABSADDR_INC()
+ etc... (NOT PLATFORM_UNALIGNED_WORD_ACCESS)
+2004/11/09: [impl] type cast in regexec() for remove compile time warning.
+ (WIN32, regposix.c)
+2004/11/08: [spec] fix Unicode character types.
+ 0x00ad (soft hyphen) should be [:cntrl:] and [:space:] type.
+ [0x0009..0x000d], 0x0085 should be [:print:] type.
+ 0x00ad should not be [:punct:] type.
+2004/11/08: [inst] fix Makefile.in. (for make ctest/ptest/testcu)
+2004/11/06: [impl] (thanks Kazuo Saito)
+ too many alternatives pattern causes core dump.
+ change implementation of onig_node_free().
+2004/11/05: [spec] rename ONIGERR_END_PATTERN_AT_BACKSLASH to
+ ONIGERR_END_PATTERN_AT_ESCAPE.
+2004/11/05: [impl] (thanks matz)
+ escape compile time warnings for x86-64 Linux.
+ StackIndex type int -> long
+2004/11/05: [memo] (thanks Kazuo Saito)
+ Oniguruma 3.4.0 was merged to Ruby 1.9.0.
+
+2004/10/30: Version 3.4.0
+
+2004/10/30: [test] success in ruby 1.9.0 (2004-09-24) [i686-linux].
+2004/10/30: [new] add hexadecimal digit char type. (\h, \H)
+ syntax: ONIG_SYN_OP2_ESC_H_XDIGIT
+2004/10/30: [bug] (thanks Guy Decoux)
+ reluctant infinite repeat bug.
+ ex. /^[a-z]{2,}?$/.match("aaa") fail.
+ fix OP_REPEAT_INC_NG process in match_at().
+
+2004/10/18: Version 3.3.1
+
+2004/10/18: [test] success in ruby 1.9.0 (2004-09-24) [i686-linux].
+2004/10/18: [impl] (thanks Imai Yasumasa)
+ enclose #include <sys/types.h> by #ifndef __BORLANDC__.
+2004/10/18: [bug] (thanks Imai Yasumasa)
+ memory access violation in select_opt_exact_info().
+2004/09/25: [dist] fix doc/API and doc/API.ja.
+2004/09/25: [bug] fix OP_SEMI_END_BUF process in match_at() for
+ the case USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ is not defined.
+
+2004/09/17: Version 3.3.0
+
+2004/09/17: [dist] add COPYING to program source files.
+2004/09/17: [test] success in ruby 1.9.0 (2004-07-23) [i686-linux].
+2004/09/17: [bug] (thanks Isao Sonobe)
+ memory access violations in xxx_mbc_enc_len(),
+ and xxx_mbc_to_normalize() and
+ xxx_left_adjust_char_head().
+ add string range check in match_at() and onig_search().
+2004/09/08: [dist] change mail address format.(kosako AT sofnec ...)
+
+2004/09/04: Version 3.2.9
+
+2004/09/04: [test] success in ruby 1.9.0 (2004-07-23) [i686-linux].
+2004/09/04: [bug] (thanks Bob Kerstetter and Richard Koch)
+ search fail in ignore case mode.
+ fix str_lower_case_match().
+2004/09/04: [inst] (thanks Isao Sonobe)
+ clear sample directory in 'make clean'.
+2004/09/04: [bug] fix ONIGENC_AMBIGUOUS_MATCH_COMPOUND/ASCII/NONASCII
+ meanings in XXXXX_mbc_to_normalize() and
+ XXXXX_is_mbc_ambiguous().
+2004/08/28: [bug] fix ONIGENC_AMBIGUOUS_MATCH_COMPOUND/ASCII/NONASCII
+ meanings in iso_8859_XX_mbc_to_normalize() and
+ iso_8859_XX_is_mbc_ambiguous().
+
+2004/08/24: Version 3.2.8
+
+2004/08/24: [test] success in ruby 1.9.0 (2004-07-23) [i686-linux].
+2004/08/24: [spec] add ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY.
+ /a{n}?/ == /(?:a{n})?/
+2004/08/24: [dist] fix doc/RE and doc/RE.ja.
+2004/08/24: [bug] (thanks starfish)
+ memory leak in set_optimize_exact_info().
+
+2004/08/21: Version 3.2.7
+
+2004/08/21: [test] success in ruby 1.8.2 (2004-07-28) [i686-linux].
+ (1.8.2 preview2)
+2004/08/21: [test] success in ruby 1.9.0 (2004-07-23) [i686-linux].
+2004/08/21: [bug] (thanks Isao Sonobe) (thanks kage)
+ memory access violation in bm_search_notrev().
+ (forgotten to merge from 2.X)
+
+2004/07/24: Version 3.2.6
+
+2004/07/24: [test] success in ruby 1.9.0 (2004-07-23) [i686-linux].
+2004/07/24: [test] success in ruby 1.8.2 (2004-07-16) [i686-linux].
+2004/07/24: [bug] fix warnings for regexec.c. (gcc 2.91.66)
+2004/07/24: [memo] change version control system from Subversion
+ to CVS 1.11.17.
+2004/07/20: [bug] (thanks Isao Sonobe)
+ illegal result in negative character class in ignore case
+ mode. fix pair-ambig-codes process in parse_exp().
+ ex. /[^a]/i.match("A")
+2004/07/20: [bug] (thanks Isao Sonobe)
+ undefined bytecode error happens in UTF-16BE etc..
+ compile_length_cclass_node() was not consistent with
+ compile_cclass_node().
+
+2004/07/01: Version 3.2.5
+
+2004/07/01: [test] success in ruby 1.8.2 (2004-06-23) [i686-linux].
+2004/07/01: [new] add onig_get_syntax_{op,op2,behavior,options}.
+2004/07/01: [bug] (thanks Isao Sonobe)
+ invalid result in onig_capture_tree_traverse().
+ fix make_capture_history_tree().
+
+2004/06/29: Version 3.2.4
+
+2004/06/29: [test] success in ruby 1.8.2 (2004-06-23) [i686-linux].
+2004/06/29: [new] (thanks Isao Sonobe)
+ add onig_number_of_captures().
+
+2004/06/25: Version 3.2.3
+
+2004/06/25: [test] success in ruby 1.8.2 (2004-06-23) [i686-linux].
+2004/06/25: [bug] (thanks Isao Sonobe)
+ invalid result in onig_capture_tree_traverse().
+ fix make_capture_history_tree().
+
+2004/06/24: Version 3.2.2
+
+2004/06/24: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/06/24: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/06/24: [test] success in ruby 1.8.2 (2004-06-23) [i686-linux].
+2004/06/24: [new] (thanks Isao Sonobe)
+ add onig_number_of_capture_histories().
+2004/06/24: [bug] (thanks Isao Sonobe)
+ invalid char position match in UTF-16 and UTF-32.
+ add onigenc_always_false_is_allowed_reverse_match().
+
+2004/06/17: Version 3.2.1
+
+2004/06/17: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/06/17: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/06/17: [test] success in ruby 1.8.2 (2004-05-18) [i686-linux].
+2004/06/17: [impl] should not use OP_REPEAT for (...)? even if target size
+ is long.
+2004/06/17: [bug] (thanks nobu) [ruby-dev:23703]
+ should use STACK_AT() instead of stkp in OP_REPEAT_INC.
+ add IN_VAR_REPEAT flag in setup_tree().
+2004/06/16: [impl] change select_opt_exact_info() to use ByteValTable[].
+2004/06/16: [impl] change map_position_value() table values.
+2004/06/14: [impl] (thanks John Carter)
+ RelAddrType, AbsAddrType and LengthType change
+ from short int to int type for the very long string match.
+2004/06/14: [bug] (thanks Greg A. Woods)
+ fix nmatch argument of regexec() is smaller than
+ reg->num_mem + 1 case. (POSIX API)
+2004/06/14: [spec] (thanks Greg A. Woods)
+ set pmatch to NULL if nmatch is 0 in regexec(). (POSIX API)
+
+2004/06/10: Version 3.2.0
+
+2004/06/10: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/06/10: [test] success in ruby 1.9.0 (2004-05-27) [i386-mswin32].
+2004/06/10: [test] success in ruby 1.8.2 (2004-05-18) [i686-linux].
+2004/06/10: [dist] add README.ja.
+2004/06/10: [new] add onig_copy_encoding().
+2004/06/10: [API] add encoding argument to onig_set_meta_char().
+ add meta_char_table member to OnigEncodingType.
+2004/06/08: [dist] add doc/API.ja.
+2004/06/07: [API] add num_of_elements member to OnigCompileInfo.
+2004/05/29: [memo] (thanks Kazuo Saito)
+ Oniguruma 3.1.0 was merged to Ruby 1.9.0.
+2004/05/26: [impl] rename NST_SIMPLE_REPEAT to NST_STOP_BT_SIMPLE_REPEAT.
+2004/05/26: [impl] doesn't need to check that target's simple repeat-ness
+ for EFFECT_MEMORY type node in setup_tree().
+
+2004/05/25: Version 3.1.0
+
+2004/05/25: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/05/25: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/05/25: [test] success in ruby 1.9.0 (2004-05-23) [i686-linux].
+2004/05/25: [test] success in ruby 1.8.2 (2004-05-18) [i686-linux].
+2004/05/25: [bug] (thanks Masahiro Sakai) [ruby-dev:23560]
+ ruby -ruri -ve 'URI::ABS_URI =~
+ "http://example.org/Andr\xC3\xA9"'
+ nested STK_REPEAT type stack can't backtrack repeat_stk[].
+ add OP_REPEAT_INC_SG and OP_REPEAT_INC_NG_SG.
+2004/05/25: [new] support UTF-32LE. (ONIG_ENCODING_UTF32_LE)
+2004/05/25: [new] support UTF-32BE. (ONIG_ENCODING_UTF32_BE)
+2004/05/24: [impl] divide enc/utf16.c to utf16_be.c and utf16_le.c.
+2004/05/24: [impl] add enc/unicode.c.
+2004/05/24: [API] change calling sequences of onig_new_deluxe() and
+ onig_recompile_deluxe().
+ define OnigCompileInfo type.
+2004/05/21: [impl] perform ensure process for rb_trap_exec() in match_at().
+ add onig_exec_trap() and CHECK_INTERRUPT_IN_MATCH_AT.
+2004/05/21: [impl] add regex status check to onig_match().
+2004/05/21: [new] add onig_get_capture_tree() and
+ onig_capture_tree_traverse().
+2004/05/20: [spec] (thanks Isao Sonobe)
+ capture history return capture data tree.
+ (see sample/listcap.c)
+2004/05/19: [bug] (thanks Simon Strandgaard)
+ Control-C does not work in matching process on Ruby.
+ add calling of CHECK_INTERRUPT into match_at().
+ ex. /<(?:[^">]+|"[^"]*")+>/.match('<META http-equiv= \
+ "Content-Type content="text/html; charset=iso-8859-1">')
+2004/05/19: [bug] (thanks Simon Strandgaard)
+ define virtual codepoint values for invalid encoding
+ byte 0xfe and 0xff in UTF-8.
+ ex. /\w+/u.match("%a\xffb\xfec%") ==> "a"
+2004/05/19: [spec] (thanks Simon Strandgaard)
+ too big backref number should be treated as a sequence of
+ an octal char and number digits.
+ ex. /b\3777\c/.match("b\3777\c")
+2004/05/17: [spec] rename encoding names "UTF-16 BE" and "UTF-16 LE"
+ to "UTF-16BE" and "UTF-16LE".
+2004/05/17: [impl] move ismbchar() and mbclen() from oniguruma.h to oniggnu.h.
+2004/05/17: [impl] rename onigenc_single_byte_is_allowed_reverse_match() to
+ onigenc_always_true_is_allowed_reverse_match().
+
+2004/05/14: Version 3.0.0
+
+2004/05/14: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/05/14: [test] success in ruby 1.9.0 (2004-05-14) [i686-linux].
+2004/05/14: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+ (* need to edit parse.y:
+ register int c; ---> int c; in yylex())
+2004/05/14: [impl] add regext.c.
+2004/05/14: [spec] KOI8 is not included in library archive by default setup.
+2004/05/14: [impl] implementation changes are completed for all encoding files.
+2004/05/12: [impl] add divide_ambig_string_node().
+ ambiguous string is divided and normalized before
+ optimization and compilation process.
+2004/05/11: [dist] remove INSTALL-RUBY from distribution.
+2004/04/28: [memo] (thanks Kazuo Saito)
+ Oniguruma 2.2.8 was merged to Ruby 1.9.0.
+2004/04/26: [spec] change value DEFAULT_MATCH_STACK_LIMIT_SIZE = 0 : unlimited
+2004/04/26: [new] add onig_get_match_stack_limit_size() and
+ onig_set_match_stack_limit_size().
+2004/04/26: [bug] add error check to re.c.181.patch and re.c.168.patch.
+2004/04/23: [impl] remove ctype_support_level from OnigEncodingType.
+2004/04/22: [spec] allow the range from single byte char to multibyte char in
+ character class for implementation reason.
+ ex. /[a-\xbb\xcc]/ in EUC-JP encoding.
+2004/04/21: [impl] remove max_enc_len_by_first_byte() from OnigEncodingType.
+2004/04/20: [new] add onig_copyright().
+2004/04/20: [impl] add regversion.c.
+2004/04/15: [new] add onig_get_ambig_flag().
+2004/04/14: [bug] (thanks Isao Sonobe)
+ undefined bytecode error happens if ONIG_OPTION_FIND_LONGEST
+ is set.
+ should finish matching process if find-condition
+ is fail at OP_END in match_at().
+2004/04/12: [impl] add ambig_flag to regex_t.
+2004/04/09: [impl] move onig_set_meta_char() to regsyntax.c.
+2004/04/09: [bug] (thanks HIROSE Masaaki) fix onig_version().
+2004/04/08: [impl] add regsyntax.c.
+2004/04/07: [new] support UTF-16 LE. (ONIG_ENCODING_UTF16_LE)
+2004/04/05: [impl] add ONIGENC_CTYPE_NEWLINE.
+2004/04/05: [memo] (thanks Kazuo Saito)
+ Oniguruma 2.2.6 was merged to Ruby 1.9.0.
+2004/04/02: [memo] Version 2.2.6 was released.
+2004/03/26: [new] support UTF-16 BE. (ONIG_ENCODING_UTF16_BE)
+2004/03/25: [spec] support non 8-bit encodings.
+2004/03/16: [memo] 2.X branch for 8-bit encodings only.
+
+2004/03/16: Version 2.2.5
+
+2004/03/16: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/03/16: [test] success in ruby 1.9.0 (2004-02-24) [i686-linux].
+2004/03/16: [impl] add property name to error message of
+ ONIGERR_INVALID_CHAR_PROPERTY_NAME.
+2004/03/16: [spec] allow prefix 'Is' for \p{...} in ONIG_SYNTAX_PERL.
+ add syntax op. ONIG_SYN_OP2_CHAR_PROPERTY_PREFIX_IS.
+2004/03/15: [dist] add sample/syntax.c.
+2004/03/15: [spec] support NOT op. in char property. \p{^...}, \P{^...}.
+ add syntax op. ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT.
+2004/03/15: [spec] rename ONIG_SYN_OP2_ESC_P_CHAR_PROPERTY to
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY.
+2004/03/10: [impl] move ONIGERR_XXX from regenc.h to oniguruma.h,
+ rename ONIGERR_XXX to ONIGENCERR_XXX in regenc.h.
+2004/03/08: [impl] (thanks eban)
+ replace defined(__CYGWIN__) to defined(__GNUC__).
+2004/03/08: [bug] (thanks eban) [ruby-dev:23172]
+ need to separate initialization for bcc32.
+2004/03/06: [memo] (thanks Kazuo Saito)
+ Oniguruma 2.2.4 was merged to Ruby 1.9.0.
+2004/03/05: [API] change second argument type of onig_set_meta_char()
+ from unsigned int to OnigCodePoint.
+2004/03/05: [dist] (thanks Kazuo Saito)
+ add MANIFEST-RUBY.
+
+2004/03/04: Version 2.2.4
+
+2004/03/04: [impl] (thanks Moriyoshi Koizumi)
+ fix many warnings in Win32 VC++ with /W3 option.
+
+2004/03/02: Version 2.2.3
+
+2004/03/02: [bug] (thanks Isao Sonobe)
+ return invalid capture region value if capture history
+ is used. (OP_MEMORY_END_PUSH_REC bug)
+ ex. /\g<p>(?@<p>\(\g<s>\)){0}(?<s>(?:\g<p>)*|){0}/
+ .match("((())())")
+2004/03/02: [impl] (thanks Kazuo Saito)
+ add :nodoc: to onig_stat_print() for RDoc.
+2004/03/02: [impl] don't use ONIG_SOURCE_IS_WRAPPED.
+
+2004/02/27: Version 2.2.2
+
+2004/02/27: [impl] fix the position of onig_stat_print().
+2004/02/27: [impl] define ONIG_RUBY_DEFINE_GLOBAL_FUNCTION() in regint.h
+ for ignored by RDoc.
+
+2004/02/26: Version 2.2.1
+
+2004/02/26: [bug] [bugs.php.net:#26677] (thanks behrens)
+ invalid definition at onig_error_code_to_str()
+ in the case of NOT HAVE_STDARG_PROTOTYPES.
+
+2004/02/25: Version 2.2.0
+
+2004/02/25: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/02/24: [test] success in ruby 1.9.0 (2004-02-24) [i686-linux].
+2004/02/24: [bug] undefined IS_BLANK() and IS_GRAPH() was used in
+ onigenc_is_code_ctype() in the case of Ruby M17N.
+2004/02/24: [new] support ISO-8859-16. (ONIG_ENCODING_ISO_8859_16)
+2004/02/24: [bug] should not fold match for 0xdf in iso8859_6.c.
+2004/02/24: [new] support ISO-8859-14. (ONIG_ENCODING_ISO_8859_14)
+2004/02/23: [new] support ISO-8859-13. (ONIG_ENCODING_ISO_8859_13)
+2004/02/23: [new] support ISO-8859-10. (ONIG_ENCODING_ISO_8859_10)
+2004/02/20: [bug] fix iso_8859_4_mbc_is_case_ambig().
+2004/02/20: [new] support ISO-8859-9. (ONIG_ENCODING_ISO_8859_9)
+2004/02/19: [bug] correct ctype tables for ISO-8859-3, ISO-8859-4,
+ ISO-8859-6, ISO-8859-7, ISO-8859-8, KOI8_R.
+2004/02/18: [bug] wrong replaced name OnigSyntaxGnuOnigex.
+2004/02/17: [spec] check capture status for empty infinite loop.
+ [ruby-dev:20224] etc...
+ ex. /(?:\1a|())*/.match("a"),
+ /(?:()|()|()|(x)|()|())*\2b\5/.match("b")
+ add USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK.
+ add OP_NULL_CHECK_END_MEMST, OP_NULL_CHECK_END_MEMST_PUSH.
+ add stack type STK_NULL_CHECK_END.
+2004/02/13: [impl] add OnigEncodingEUC_CN to enc/euc_kr.c.
+2004/02/13: [bug] (thanks Simon Strandgaard)
+ parsing of nested repeat was invalid.
+ ex. /ab{2,3}*/ was /(?:a(?:b{2,3}))*/,
+ should be /a(?:b{2,3}*)/
+2004/02/12: [bug] (thanks Simon Strandgaard)
+ OP_REPEAT_INC_NG process in match_at() is wrong.
+ ex. bad match /a.{0,2}?a/ =~ "0aXXXa0"
+2004/02/12: [bug] (thanks Simon Strandgaard)
+ wrong fetch after (?x) option. ex. "(?x)\ta .\n+b"
+2004/02/12: [bug] (thanks Simon Strandgaard)
+ [\^] is not a empty char class.
+2004/02/09: [new] add onig_set_syntax_op(), onig_set_syntax_op2(),
+ onig_set_syntax_behavior(), onig_set_syntax_options().
+2004/02/06: [dist] add a new target 'site' to Makefile.in.
+2004/02/06: [dist] add index.html.
+2004/02/03: [bug] oniggnu.h was not installed by 'make install'.
+
+2004/02/02: Version 2.1.0
+
+2004/02/02: [test] success in ruby 1.9.0 (2004-02-02) [i686-linux].
+2004/02/02: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/02/02: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2004/02/02: [new] support ISO-8859-11. (ONIG_ENCODING_ISO_8859_11)
+2004/02/02: [new] support ISO-8859-5. (ONIG_ENCODING_ISO_8859_5)
+2004/02/02: [impl] should check single byte encoding or not in and_cclass()
+ and or_cclass().
+2004/01/30: [dist] add oniggnu.h.
+2004/01/30: [bug] ISO-8859-7 0xb7 (middle dot) is Punct type.
+2004/01/30: [new] support ISO-8859-8. (ONIG_ENCODING_ISO_8859_8)
+2004/01/29: [new] support ISO-8859-7. (ONIG_ENCODING_ISO_8859_7)
+2004/01/29: [new] support ISO-8859-6. (ONIG_ENCODING_ISO_8859_6)
+2004/01/28: [new] support KOI8-R. (ONIG_ENCODING_KOI8_R)
+2004/01/28: [new] support KOI8. (ONIG_ENCODING_KOI8)
+2004/01/27: [dist] rename enc/isotable.c to enc/mktable.c.
+2004/01/27: [new] support ISO-8859-4. (ONIG_ENCODING_ISO_8859_4)
+2004/01/26: [new] support ISO-8859-3. (ONIG_ENCODING_ISO_8859_3)
+2004/01/26: [bug] EncISO_8859_{1,15}_CtypeTable[256] was wrong.
+ (0x80 - 0xff is not ASCII)
+2004/01/23: [new] support ISO-8859-2. (ONIG_ENCODING_ISO_8859_2)
+2004/01/23: [dist] add enc/isotable.c.
+2004/01/22: [new] support EUC-TW. (ONIG_ENCODING_EUC_TW)
+2004/01/22: [bug] definition of GET_ALIGNMENT_PAD_SIZE() and
+ ALIGNMENT_RIGHT() was wrong.
+ type casting should be unsigned int, not int.
+2004/01/22: [impl] add defined(__x86_64) || defined(__x86_64__)
+ to unaligned word access condition. (AMD64 ?)
+2004/01/21: [dist] rename enc/eucjp.c to enc/euc_jp.c.
+2004/01/21: [new] support EUC-KR. (ONIG_ENCODING_EUC_KR)
+2004/01/20: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2004/01/20: [dist] change Makefile.in.
+2004/01/20: [spec] add \p{...}, \P{...} in char class.
+2004/01/20: [new] character property operators \p{...}, \P{...}.
+ supported in ONIG_SYNTAX_JAVA and ONIG_SYNTAX_PERL.
+2004/01/19: [spec] allow /a{,n}/ as /a{0,n}/. (but don't allow /a{,}/)
+2004/01/19: [dist] rename onigcomp200.h to onigcmpt200.h.
+2004/01/19: [dist] update re.c.168.patch. svn add re.c.181.patch.
+2004/01/16: [dist] update sample/*.c for new API.
+2004/01/16: [dist] add onigcomp200.h. (for old API compatibility)
+2004/01/16: [dist] update documents API, RE and RE.ja.
+2004/01/16: [spec] change prefix REG_ -> ONIG_, regex_ onig_,
+ ENC_ -> ONIGENC, enc_ -> onigenc_.
+2004/01/15: [impl] rename ENC_IS_MBC_E_WORD() to ENC_IS_MBC_WORD().
+ rename ENC_CTYPE_SUPPORT_LEVEL_SB_ONLY to
+ ENC_CTYPE_SUPPORT_LEVEL_SB.
+2004/01/14: [impl] rename UNALIGNED_WORD_ACCESS to
+ PLATFORM_UNALIGNED_WORD_ACCESS.
+2004/01/14: [impl] change MATCH_STACK_LIMIT_SIZE value from 200000 to 500000.
+2004/01/13: [impl] remove ENC_CODE_TO_MBC_FIRST(enc,code) in regenc.h.
+ remove code_to_mbc_first member in RegCharEncodingType.
+2004/01/13: [impl] remove head byte bitset information in cclass->mbuf.
+2003/12/26: [impl] change macro name ismb_xxxx() in enc/*.c for
+ escape conflict.
+
+2003/12/24: Version 2.0.0
+
+2003/12/24: [spec] ignore case option is effective to numbered char.
+ ex. /\x61/i =~ "A"
+2003/12/24: [test] success in ruby 1.8.1 (2003-12-24) [i686-linux].
+2003/12/24: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2003/12/24: [test] success in ruby 1.8.0 (2003-08-08) [i386-mswin32].
+2003/12/24: [test] success in regex.c compile test on ruby-m17n.
+ (but can't make miniruby because re.c patch fail.)
+2003/12/24: [bug] (thanks H.Miyamoto) /[\W]/ was wrong in 1.9.5.
+2003/12/22: [spec] implement fold match on UTF-8 encoding.
+2003/12/19: [impl] add ctype_support_level and ctype_add_codes() member to
+ RegCharEncoding type.
+2003/12/19: [impl] add add_ctype_to_cc() in regparse.c.
+2003/12/19: [impl] add enc_is_code_ctype() in REG_RUBY_M17N case.
+2003/12/19: [impl] change ENC_CODE_TO_MBC() interface.
+2003/12/18: [new] implement fold match. (variable number of char
+ match in ignore case mode.)
+ ex. German alphabet ess-tsett(U+00DF) match "SS" and "ss".
+2003/12/17: [impl] refactoring of encoding system.
+2003/12/17: [impl] add enc_init() in regenc.c.
+2003/12/17: [new] support Big5. (REG_ENCODING_BIG5)
+2003/12/16: [impl] change CodePoint from unsigned int to unsigned long.
+2003/12/16: [new] support ISO 8859-15. (REG_ENCODING_ISO_8859_15)
+2003/12/16: [impl] change P_() macro definition condition for Win32.
+2003/12/16: [dist] add sample/encode.c
+2003/12/16: [new] support ISO 8859-1. (REG_ENCODING_ISO_8859_1)
+2003/12/15: [impl] rename IS_ENC_XXXX to ENC_IS_XXXX.
+2003/12/15: [impl] rename RegDefaultCharEncoding to EncDefaultCharEncoding.
+2003/12/15: [impl] divide encoding files. (enc/ascii.c, enc/utf8.c etc...)
+2003/12/15: [bug] unexpected infinite loop in regex_snprintf_with_pattern().
+ change local var. type char* to UChar*.
+2003/12/15: [impl] remove REG_MBLEN_TABLE[].
+2003/12/15: [spec] rename function prefix regex_get_prev_char_head(),
+ regex_get_left_adjust_char_head() and
+ regex_get_right_adjust_char_head() to enc_xxxxxx().
+2003/12/15: [impl] rename function prefixes in regenc.h from regex_ to enc_.
+2003/12/12: [impl] remove USE_SBMB_CLASS.
+2003/12/12: [impl] rename mb -> mbc, mblen() to enc_len().
+2003/12/12: [impl] rename WCINT to CodePoint.
+2003/12/11: [impl] delete IS_XXXX() ctype macros from regint.h.
+2003/12/11: [impl] add enc->wc_is_ctype() and RegAsciiCtypeTable[256].
+2003/12/11: [impl] remove RegAsciiCaseAmbigTable.
+2003/12/10: [impl] use ENC_TO_LOWER() for ignore case comparison.
+2003/12/08: [impl] *** re-defined RegCharEncoding in oniguruma.h. ***
+2003/12/08: [impl] add USE_POSIX_REGION_OPTION to regint.h.
+2003/12/08: [impl] add IS_ENC_WORD() to regenc.h.
+2003/12/05: [impl] rename IS_CODE_XXXX() to IS_ENC_XXXX().
+2003/12/05: [impl] delete IS_CODE_WORD() from regenc.h.
+2003/12/04: [spec] rename REG_SYN_OP_BACK_REF to REG_SYN_OP_DECIMAL_BACKREF.
+2003/12/04: [spec] add (REG_SYN_OP_ESC_W_WORD | REG_SYN_OP_ESC_B_WORD_BOUND |
+ REG_SYN_OP_ESC_LTGT_WORD_BEGIN_END | REG_SYN_OP_BACK_REF)
+ to RegSyntaxGrep.
+2003/12/04: [spec] remove REG_ENCODING_DEFAULT and REGCODE_DEFAULT.
+2003/12/04: [spec] move declarations of regex_get_default_encoding() and
+ regex_set_default_encoding() from oniguruma.h to regenc.h.
+2003/12/03: [new] add regex_get_default_encoding() and
+ regex_set_default_encoding().
+2003/12/03: [spec] REG_ENCODING_DEFAULT meaning is changed.
+ (current default value, not initial default value.)
+2003/12/03: [spec] REGCODE_XXX is obsoleted. use REG_ENCODING_XXX.
+2003/12/02: [memo] alias svnst='svn status | grep -v "^\?"'
+2003/12/02: [spec] move regex_set_default_trans_table() declaration
+ from oniguruma.h to regenc.h. (obsoleted API)
+2003/12/02: [impl] move variables RegDefaultCharEncoding, DefaultTransTable and
+ AmbiguityTable to regenc.c.
+2003/12/01: [impl] add regex_continuous_sbmb() to regenc.c.
+2003/12/01: [dist] add regenc.h and regenc.c.
+2003/11/18: [dist] change testconv.rb.
+2003/11/18: [bug] (thanks Masaru Tsuda)
+ memory leak in parse_subexp().
+2003/11/18: [bug] (thanks Masaru Tsuda)
+ memory leak in names_clear() and parse_char_class().
+2003/11/17: [bug] memory leak in parse_char_class().
+2003/11/17: [bug] (thanks Masaru Tsuda)
+ OptExactInfo length should not over OPT_EXACT_MAXLEN.
+ (concat_opt_exact_info_str())
+
+2003/11/12: Version 1.9.5
+
+2003/11/12: [test] success in ruby 1.8.0 (2003-08-08) [i386-cygwin].
+2003/11/12: [test] success in ruby 1.8.1 (2003-11-11) [i686-linux].
+2003/11/12: [spec] add definition of REG_INEFFECTIVE_META_CHAR.
+2003/11/11: [dist] add a sample program sample/sql.c.
+2003/11/11: [new] add variable meta character.
+ regex_set_meta_char()
+2003/11/11: [spec] add syntax op. REG_SYN_OP_VARIABLE_META_CHARS.
+2003/11/11: [spec] rename REG_SYN_OP_ESC_CAPITAL_Q_QUOTE to
+ REG_SYN_OP2_ESC_CAPITAL_Q_QUOTE,
+ REG_SYN_OP_QMARK_GROUP_EFFECT to
+ REG_SYN_OP2_QMARK_GROUP_EFFECT.
+2003/11/06: [impl] define THREAD_PASS as rb_thread_schedule() in Ruby mode.
+2003/11/05: [spec] add syntax behavior REG_SYN_WARN_REDUNDANT_NESTED_REPEAT.
+2003/11/05: [spec] rename REG_SYN_WARN_FOR_CC_OP_NOT_ESCAPED to
+ REG_SYN_WARN_CC_OP_NOT_ESCAPED.
+2003/11/04: [new] add regex_set_warn_func() and regex_set_verb_warn_func().
+2003/10/30: [new] add regex_name_to_backref_number().
+ (for multiplex definition name, see sample/names.c)
+2003/10/30: [spec] add name_end and reg argument to callback function of
+ regex_foreach_name(). (see sample/names.c)
+2003/10/29: [spec] add syntax behavior REG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME.
+ add error code REGERR_MULTIPLEX_DEFINED_NAME.
+2003/10/14: [dist] modify sample/simple.c.
+2003/10/03: [bug] (thanks nobu) [ruby-dev:21472]
+ sub-anchor of optimization map info was wrong
+ in concat_left_node_opt_info().
+ ex. /^(x?y)/ = "xy" fail.
+
+2003/09/17: Version 1.9.4
+
+2003/09/17: [spec] change specification of char-class range in ignore case mode
+ follows with Ruby 1.8(2003-09-17).
+ ex. /[H-c]/i ==> (H-Z, 0x5b-0x60, a-c)/i
+ ==> H-Z, h-z, 0x5b-0x60, a-c, A-C
+2003/09/16: [bug] (thanks Guy Decoux)
+ remove env->option == option check in parse_effect().
+ change env->option for dynamic option in parse_exp().
+ (ex. bad match /(?i)(?-i)a/ =~ "A")
+2003/09/12: [spec] rename REG_SYN_ALLOW_RANGE_OP_IN_CC to
+ REG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC,
+ REG_SYN_ESCAPE_IN_CC to REG_SYN_BACKSLASH_ESCAPE_IN_CC.
+2003/09/11: [bug] change to IS_SYNTAX_OP2 at REG_SYN_OP2_ESC_GNU_BUF_ANCHOR.
+2003/09/09: [spec] rename REG_SYN_OP2_ESC_M_BAR_META to
+ REG_SYN_OP2_ESC_CAPITAL_M_BAR_META,
+ REG_SYN_OP_ESC_Q_QUOTE to REG_SYN_OP_ESC_CAPITAL_Q_QUOTE,
+ REG_SYN_OP_ESC_SUBEXP to REG_SYN_OP_ESC_LPAREN_SUBEXP,
+ REG_SYN_OP_ESC_BUF_ANCHOR to REG_SYN_OP_ESC_AZ_BUF_ANCHOR,
+ REG_SYN_OP_ESC_GNU_BUF_ANCHOR to
+ REG_SYN_OP2_ESC_GNU_BUF_ANCHOR,
+ REG_SYN_OP_ESC_CONTROL_CHAR to REG_SYN_OP_ESC_CONTROL_CHARS,
+ REG_SYN_OP_ESC_WORD to REG_SYN_OP_ESC_W_WORD,
+ REG_SYN_OP_ESC_WORD_BEGIN_END to
+ REG_SYN_OP_ESC_LTGT_WORD_BEGIN_END,
+ REG_SYN_OP_ESC_WORD_BOUND to REG_SYN_OP_ESC_B_WORD_BOUND,
+ REG_SYN_OP_ESC_WHITE_SPACE to REG_SYN_OP_ESC_S_WHITE_SPACE,
+ REG_SYN_OP_ESC_DIGIT to REG_SYN_OP_ESC_D_DIGIT,
+ REG_SYN_OP_CC to REG_SYN_OP_BRACKET_CC,
+ REG_SYN_OP2_CCLASS_SET to REG_SYN_OP2_CCLASS_SET_OP,
+ REG_SYN_CONTEXT_INDEP_OPS to
+ REG_SYN_CONTEXT_INDEP_REPEAT_OPS,
+ REG_SYN_CONTEXT_INVALID_REPEAT_OPS to
+ REG_SYN_CONTEXT_INVALID_REPEAT_OPS.
+ add REG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR.
+2003/09/08: [spec] rename REG_SYN_OP_ANYCHAR to REG_SYN_OP_DOT_ANYCHAR,
+ REG_SYN_OP_0INF to REG_SYN_OP_ASTERISK_ZERO_INF,
+ REG_SYN_OP_ESC_0INF to REG_SYN_OP_ESC_ASTERISK_ZERO_INF,
+ REG_SYN_OP_1INF to REG_SYN_OP_PLUS_ONE_INF,
+ REG_SYN_OP_ESC_1INF to REG_SYN_OP_ESC_PLUS_ONE_INF,
+ REG_SYN_OP_0INF to REG_SYN_OP_QMARK_ZERO_ONE,
+ REG_SYN_OP_ESC_0INF to REG_SYN_OP_ESC_QMARK_ZERO_ONE,
+ REG_SYN_OP_INTERVAL to REG_SYN_OP_BRACE_INTERVAL,
+ REG_SYN_OP_ESC_INTERVAL to REG_SYN_OP_ESC_BRACE_INTERVAL,
+ REG_SYN_OP_SUBEXP to REG_SYN_OP_LPAREN_SUBEXP,
+ REG_SYN_OP_ALT to REG_SYN_OP_VBAR_ALT,
+ REG_SYN_OP_ESC_ALT to REG_SYN_OP_ESC_VBAR_ALT,
+ REG_SYN_OP_NON_GREEDY to REG_SYN_OP_QMARK_NON_GREEDY,
+ REG_SYN_OP_SUBEXP_EFFECT to REG_SYN_OP_QMARK_GROUP_EFFECT,
+ REG_SYN_OP2_POSSESSIVE_{REPEAT,INTERVAL} to
+ REG_SYN_OP2_PLUS_POSSESSIVE_{REPEAT,INTERVAL},
+ REG_SYN_OP2_SUBEXP_CALL to REG_SYN_OP2_ESC_G_SUBEXP_CALL,
+ REG_SYN_OP2_NAMED_GROUP to REG_SYN_OP2_QMARK_LT_NAMED_GROUP
+ and REG_SYN_OP2_ESC_K_NAMED_BACKREF.
+2003/09/02: [tune] call reduce_nested_qualifier() after disabling capture for
+ no-name group in noname_disable_map().
+ ex. /(a+)*(?<name>...)/
+2003/09/02: [impl] include <stdio.h> is forgotten to erase in regcomp.c.
+2003/09/01: [dist] update doc/RE and doc/RE.ja.
+2003/08/26: [bug] (thanks Guy Decoux)
+ should not double free node at the case TK_CC_CC_OPEN
+ in parse_char_class().
+
+2003/08/19: Version 1.9.3
+
+2003/08/19: [inst] change re.c.180.patch.
+2003/08/19: [impl] rename 'list of captures' to 'capture history'.
+2003/08/19: [dist] add doc/RE.ja. (Japanese)
+2003/08/19: [new] add regex_copy_syntax().
+2003/08/19: [spec] rename REG_SYN_OP2_ATMARK_LIST_OF_CAPTURES to
+ REG_SYN_OP2_ATMARK_CAPTURE_HISTORY.
+2003/08/18: [spec] (thanks nobu)
+ don't use IMPORT in oniguruma.h and onigposix.h.
+2003/08/18: [impl] (thanks nobu) change error output to stdout in testconv.rb.
+2003/08/18: [inst] (thanks nobu) lacked $(srcdir) in Makefile.in.
+2003/08/18: [bug] REG_MBLEN_TABLE[SJIS][0xFD-0xFF] should be 1.
+2003/08/18: [bug] (thanks nobu) mbctab_sjis[0x80] should be 0.
+2003/08/18: [bug] (thanks nobu)
+ single/multi-byte decision was wrong in parse_char_class().
+ add regex_wc2mblen().
+ should not set fetched to 1 in TK_RAW_BYTE case.
+2003/08/18: [bug] should update BitSet in the case inc_n >= 0
+ in add_wc_range_to_buf().
+2003/08/13: [bug] change re.c.180.patch for fix rb_reg_to_s() in re.c.
+2003/08/11: [bug] should clear region->list in regex_region_resize().
+
+2003/08/08: Version 1.9.2
+
+2003/08/08: [test] success in ruby 1.8.0 (2003-08-08) on Windows 2000
+ VC++ 6.0 and Cygwin.
+2003/08/08: [impl] don't define macro vsnprintf for WIN32 platform,
+ because definition is added in win32\win32.h.
+2003/08/08: [test] success in ruby 1.8.0 and ruby 1.6.8(2003-08-03) on Linux.
+2003/08/08: [dist] change re.c.180.patch and re.c.168.patch.
+2003/08/08: [new] (thanks akr)
+ implemented list of captures. (?@...), (?@<name>...)
+2003/08/07: [dist] add sample/listcap.c.
+2003/08/06: [bug] OP_MEMORY_END_PUSH_REC case in match_at().
+ renewal of mem_start_stk[] should be after
+ STACK_PUSH_MEM_END() call.
+2003/07/29: [new] add regex_get_encoding(), regex_get_options() and
+ regex_get_syntax().
+2003/07/25: [spec] (thanks akr)
+ change group(...) to shy-group(?:...) if named group is
+ used in the pattern.
+ add REG_SYN_CAPTURE_ONLY_NAMED_GROUP.
+2003/07/24: [spec] rename REG_OPTION_CAPTURE_ONLY_NAMED_GROUP to
+ REG_OPTION_DONT_CAPTURE_GROUP.
+ add REG_OPTION_CAPTURE_GROUP.
+2003/07/17: [spec] rename REG_SYN_OP2_NAMED_SUBEXP to REG_SYN_OP2_NAMED_GROUP.
+2003/07/17: [spec] add REGERR_EMPTY_GROUP_NAME.
+2003/07/17: [spec] rename REGERR_INVALID_SUBEXP_NAME
+ to REGERR_INVALID_CHAR_IN_GROUP_NAME.
+2003/07/17: [spec] restrict usable chars of group name to alphabet, digit,
+ '_' or multibyte-char in fetch_name(). [ruby-dev:20706]
+2003/07/16: [impl] minor change of sample/names.c.
+2003/07/14: [impl] rename USE_NAMED_SUBEXP to USE_NAMED_GROUP.
+2003/07/14: [bug] add fetch_name() for USE_NAMED_SUBEXP off case.
+2003/07/14: [API] add regex_number_of_names().
+2003/07/08: [impl] change error message for undefined group number call.
+ 'undefined group reference: /(a)\g<2>/'
+ --> 'undefined group <2> reference: /(a)\g<2>/'
+2003/07/08: [dist] modify doc/RE.
+2003/07/07: [impl] OP_SET_OPTION is not needed in compiled code.
+ add IS_DYNAMIC_OPTION() to regint.h.
+2003/07/07: [spec] called group should not ignore outside option (?i:...).
+ ex. /(?i:(?<n>(a)\2)){0}\g<n>/.match("aA")
+ add opcode OP_BACKREFN_IC and OP_BACKREF_MULTI_IC.
+ set option status to effect memory in optimize_node_left().
+2003/07/07: [impl] add opcode OP_ANYCHAR_ML, OP_ANYCHAR_ML_STAR and
+ OP_ANYCHAR_ML_START_PEEK_NEXT.
+2003/07/07: [bug] (thanks nobu) REG_MBLEN_TABLE[SJIS][0x80] should be 1.
+2003/07/07: [spec] rename REG_SYN_OP_QUOTE to REG_SYN_OP_ESC_Q_QUOTE.
+
+2003/07/04: Version 1.9.1
+
+2003/07/04: [new] add REG_OPTION_CAPTURE_ONLY_NAMED_GROUP. (thanks .NET)
+2003/07/04: [spec] check mbuf member in the case of
+ REG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC in parse_char_class().
+2003/07/04: [spec] typo REG_SYN_WARN_FOR_CC_OP_NOT_ESCAPEED.
+ should be REG_SYN_WARN_FOR_CC_OP_NOT_ESCAPED.
+2003/07/04: [bug] conflict values on REG_SYN_WARN_FOR_CC_OP_NOT_ESCAPEED and
+ REG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC. (thanks nobu)
+2003/07/03: [spec] add REG_SYN_OP_ESC_CONTROL_CHAR flag.
+2003/07/03: [spec] remove REG_SYN_OP_ESC_OCTAL3 and REG_SYN_OP_ESC_X_HEX2
+ flag from RegSyntaxGnuRegex.
+2003/07/03: [spec] remove REG_SYN_OP_NON_GREEDY flag from RegSyntaxGnuRegex.
+2003/07/02: [dist] fix doc/RE.
+2003/07/01: [impl] add config flag USE_VARIABLE_SYNTAX.
+ (turn off variable syntax on Ruby)
+2003/07/01: [spec] add syntax behavior REG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND.
+2003/06/30: [spec] allow different length top-level alternatives
+ in look-behind. ex. (?<=abc|abcd), (?<!a|bc)
+2003/06/26: [spec] add option REG_OPTION_NEGATE_SINGLELINE.
+2003/06/26: [spec] should default on REG_OPTION_SINGLELINE
+ for REG_SYNTAX_PERL and REG_SYNTAX_JAVA.
+2003/06/26: [impl] add options member to RegStntaxType.
+2003/06/26: [spec] don't change the meaning of '\Z' for REG_OPTION_SINGLELINE.
+2003/06/25: [dist] don't use option REG_NEWLINE for sample/posix.c.
+2003/06/25: [dist] modify testconv.rb.
+ should match and convert double quoted string data.
+ ex. x(/\ca/, "\001", 0, 1)
+2003/06/25: [impl] add REG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL and
+ REG_SYN_OP2_ESC_M_BAR_META.
+2003/06/25: [impl] add REG_SYN_OP_ESC_OCTAL3 and REG_SYN_OP_ESC_X_HEX2.
+2003/06/24: [impl] add REG_SYN_OP2_ESC_V_VTAB. (\v is VTAB)
+2003/06/24: [bug] should invert REG_OPTION_SINGLELINE flag
+ in REG_SYN_OP2_OPTION_PERL.
+2003/06/24: [impl] add REG_SYN_OP2_OPTION_PERL and REG_SYN_OP2_OPTION_RUBY.
+ meaning of (?m) and (?s) are depend on syntax.
+
+2003/06/20: Version 1.9.0
+
+2003/06/20: [spec] \Q...\E is not effective on REG_SYNTAX_RUBY. (thanks akr)
+2003/06/19: [inst] rename regex.h to oniguruma.h.
+2003/06/18: [impl] change REG_EXTERN setting condition. (__CYGWIN__)
+2003/06/18: [bug] return wrong result UTF-8 case in regex_mb2wc().
+2003/06/18: [impl] add REG_SYN_OP2_POSSESSIVE_INTERVAL. a{n,m}+
+2003/06/18: [new] add REG_SYNTAX_JAVA.
+2003/06/18: [spec] add REG_SYN_OP_QUOTE.
+2003/06/18: [spec] add op2 member to RegSyntaxType.
+ rename some REG_SYN_OP_XXX to REG_SYN_OP2.
+2003/06/16: [new] Perl-like quotation operator \Q, \E.
+2003/06/16: [spec] should not control ignore case mode by escaped char.
+ ex. /\J/i =~ "j", /[\J]/i =~ "j" (same as Perl)
+2003/06/13: [bug] modify onigposix.h.
+2003/06/13: [bug] should use -DIMPORT for link with DLL in win32/Makefile.
+2003/06/13: [dist] add sample/names.c
+2003/06/12: [bug] range should be from - 1 in not_wc_range_buf().
+2003/06/12: [spec] should warn for '-' before '&&' operator in char-class.
+2003/06/12: [new] add REG_SYNTAX_PERL.
+2003/06/12: [spec] add syntax behavior REG_SYN_WARN_FOR_CC_OP_NOT_ESCAPEED.
+2003/06/12: [spec] invalid POSIX bracket should be error. ex. [[:upper :]]
+2003/06/11: [new] char-class in char-class (as Java(TM)).
+2003/06/11: [spec] change AND operator in char-class from &&[..] to &&.
+2003/06/04: [spec] {n,m}+ should not be possessive operator.
+ ex. a{3}+ should be (?:a{3})+
+2003/06/03: [bug] should compare strings with min-length in is_not_included().
+2003/06/03: [impl] automatic possessivate optimization. a*b ==> (?>a*)b
+ (thanks Jeffrey E. F. Friedl)
+2003/06/02: [impl] remove multibyte-BitSet for OP_CCLASS_MB/OP_CCLASS_MB_NOT.
+2003/05/30: [new] char class intersection operator &&[...] like Java(TM).
+ (thanks akr)
+2003/05/30: [bug] should use bbuf_free() for CClassNode in regex_node_free().
+2003/05/29: [bug] wrong usage of syntax REG_SYN_ALLOW_EMPTY_RANGE_IN_CC.
+ /[d-a]/ should be error.
+2003/05/28: [impl] optimize stop-backtrack compiled code.
+ (/(?>a*)/, /(?>\w+)/ etc...)
+ add OP_POP opcode.
+2003/05/28: [new] possessive repeat operator. (?+, *+, ++, {n,m}+)
+2003/05/27: [spec] '-' at beginning of char-class should be warn only if
+ it is start of range. (ex. /[--a]/)
+2003/05/27: [spec] should not warn for right bracket at beginning of pattern.
+ ex. /]aaa/
+2003/05/27: [spec] change CCEND_ESC_WARN() from VERB_WARNING() to WARNING().
+2003/05/27: [spec] /[]aaa/ should be empty char-class error.
+ /[]aaa]/ should be warn for 'without backslash'.
+ (add char_exist_check() in regparse.c)
+2003/05/26: [bug] OP_REPEAT in recursive subexp call.
+ ex. /(?<n>(a|b\g<n>c){3,5})/.match("baaaaca") => "baaaaca"
+ was wrong result. (should be "aaaa")
+2003/05/26: [impl] add num_call member to regex_t.
+2003/05/26: [impl] add repeat_range member to regex_t.
+ (for delete upper,lower members from StackType.u.repeat)
+2003/05/26: [bug] change print_names() to external regex_print_names().
+2003/05/26: [tune] change OP_NULL_CHECK_END process in match_at().
+2003/05/26: [spec] change CCEND_ESC_WARN() from WARNING() to VERB_WARNING().
+2003/05/26: [spec] remove POSIXLINE option. (?p:...)
+ (be made the same as Ruby.)
+2003/05/22: [spec] use OP_NULL_CHECK_XXX only if repeat is infinite.
+ prev. /(?:()|()){0,10}\1\2/ =~ "" ==> FAIL
+ now /(?:()|()){0,10}\1\2/ =~ "" ==> MATCH
+
+2003/05/22: [impl] change target_empty setting condition in setup_tree().
+2003/05/19: [impl] avoid zero length repeat optimization. (thanks matz)
+ /()*/ ==> /()?/, /()+/ ==> /()/ etc...
+2003/05/19: [impl] minor changes for gcc -Wall. (-DREG_DEBUG_STATISTICS case)
+2003/05/19: [spec] rename regex_foreach_names() to regex_foreach_name().
+2003/05/16: [new] add --with-statistics option to configure.
+2003/05/16: [bug] move RegOpInfo[] definition to regint.h.
+2003/05/16: [new] add regex_version().
+
+2003/05/14: Version 1.8.6
+
+2003/05/14: [bug] use _vsnprintf() on Win32.
+2003/05/14: [spec] define USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE.
+ (/\n$/ =~ "\n", /\n\Z/ =~ "\n") [ruby-dev:20125]
+2003/05/14: [impl] minor changes for gcc -Wall.
+2003/05/14: [impl] add string.h check in AC_CHECK_HEADERS().
+2003/05/13: [impl] minor changes for gcc -Wall.
+2003/05/13: [impl] add regex_snprintf_with_pattern().
+2003/05/13: [spec] add warning for char class meta character without escape
+ in Ruby mode ('[', '-', ']').
+2003/05/13: [impl] define WARNING() and VERB_WARNING() in regint.h.
+2003/05/13: [bug] correct is_code_ascii() for /[[:ascii:]]/.
+2003/05/12: [dist] add regular expression document (doc/RE).
+2003/05/12: [spec] specification of $(END_LINE) was made the same as Ruby 1.8.
+ [ruby-dev:20130] (thanks matz)
+2003/05/12: [memo] shifted to Subversion(version 0.21.0) from CVS.
+
+2003/03/19: Version 1.8.5
+
+2003/03/19: [impl] change REG_EXTERN definition. (thanks nobu)
+2003/03/19: [impl] abbreviation for long error_par in regex_error_code_to_str().
+2003/03/18: [dist] change re.c.XXX.patch for GNU regex API changes.
+2003/03/18: [spec] change API regex_new(), regex_recompile() and
+ regex_error_code_to_str().
+ change API re_compile_pattern() and re_recompile_pattern().
+2003/03/18: [spec] replace REGERR_END_PATTERN_AT_GROUP_{COMMENT|OPTION} to
+ REGERR_END_PATTERN_IN_GROUP.
+2003/03/17: [impl] should free err_arg.
+2003/03/17: [bug] mistake(high -> to) in add_wc_range_to_buf().
+2003/03/17: [spec] add err_arg argument to regex_new() and regex_recompile().
+ for detail error message. (thanks akr)
+
+2003/03/12: Version 1.8.4
+
+2003/03/12: [tune] use cached value of effect node in get_min_match_length().
+2003/03/12: [bug] escaped alphabet should be TK_RAW_BYTE
+ in fetch_token() and fetch_token_in_cc().
+2003/03/12: [spec] change named backref and subexp call format.
+ backref: \k<name>, call: \g<name> (thanks akr)
+2003/03/11: [inst] add regparse.[ch] in win32/Makefile.
+2003/03/11: [bug] if UNALIGNED_WORD_ACCESS isn't set,
+ then compile error in unset_addr_list_fix(). (thanks knu)
+2003/03/10: [impl] divide regcomp.c to regcomp.c, regparse.c and regparse.h.
+2003/03/10: [bug] should handle multi-byte code name in fetch_name().
+2003/03/10: [spec] remove REGERR_TABLE_FOR_IGNORE_CASE_IS_NOT_SETTED.
+2003/03/10: [spec] support POSIX API option REG_NOSUB.
+ add comp_options member to POSIX API regex_t.
+
+2003/03/10: Version 1.8.3
+
+2003/03/10: [bug] can not compile with Ruby 1.6.8.
+ (inconsistent st.h with 1.6 and 1.8)
+ use hash table on Ruby 1.8 only.
+2003/03/10: [spec] forbid to use '\' in group name.
+2003/03/08: [impl] remove check_backref_number().
+2003/03/08: [bug] called group in 0-repeat should not be eliminated from
+ compile code. ex. /(?*n)(?<n>){0}/ (thanks akr)
+ add is_refered member to QualifierNode.
+2003/03/07: [impl] use hash table(st.[ch]) for implementation of name table.
+ (enable on Ruby in default)
+2003/03/07: [new] add regex_foreach_names().
+2003/03/06: [impl] add member reg->stack_pop_level.
+2003/03/06: [impl] add operator OP_MEMORY_START and member reg->backtrack_mem.
+2003/03/06: [bug] if REG_OPTION_FIND_LONGEST or REG_OPTION_NOT_EMPTY,
+ should handle backtrack of MEM_END.
+ add OP_MEMORY_END_PUSH and OP_MEMORY_END_PUSH_REC.
+2003/03/06: [impl] rename OP_MEMORY_END_PUSH to OP_MEMORY_END_MARK.
+2003/03/06: [spec] change error messages.
+2003/03/06: [tune] add tiny_pop check in STACK_POP.
+
+2003/03/05: Version 1.8.2
+
+2003/03/05: [impl] use cache info in EFFECT_MEMORY case
+ in optimize_node_info().
+2003/03/05: [impl] add EFFECT_MEMORY node reference count check
+ in optimize_node_left().
+2003/03/05: [impl] add min-len, max-len, char-len cache in EffectNode.
+2003/03/05: [spec] allow to call in look behind. ex. /(?<=(?*a))/
+2003/03/05: [bug] forgotten N_ANCHOR case in check_backref_number(),
+ subexp_inf_recursive_check_trav() etc...
+2003/03/05: [impl] rename USE_ONIGURUMA_EXTENSION to USE_SBMB_CLASS.
+2003/03/04: [impl] add CALL-node info in optimize_node_left().
+2003/03/04: [spec] prohibit left recursion of subexp call. ex. (?<n>|(?*n)a)
+ add subexp_inf_recursive_check_trav().
+2003/03/04: [spec] rename REG_SYN_STRICT_CHECK_BACKREF_NUMBER
+ to REG_SYN_STRICT_CHECK_BACKREF
+2003/03/03: [bug] /(?<n>a(?*n)|)/ isn't infinite recursion.
+ fix N_LIST case in subexp_recursive_check(). (thanks akr)
+2003/03/03: [bug] /(?<n>|(?*n))+/ segmentation fault.
+ should re-allocate in unset_addr_list_add(). (thanks akr)
+
+2003/03/01: Version 1.8.1
+
+2003/03/01: [bug] change STACK_GET_MEM_START() and STACK_PUSH_MEM_END().
+2003/03/01: [new] add reg_name_to_group_numbers() to POSIX API.
+2003/03/01: [impl] use OP_MEMORY_END_PUSH in callable subexp compiled code
+ only if subexp is recursive.
+2003/03/01: [spec] rename regex_name_to_backrefs() to
+ regex_name_to_group_numbers().
+2003/02/28: [impl] use function stack_double() instead of macro.
+2003/02/28: [new] subexp call. (?*name) (thanks akr)
+2003/02/28: [spec] add match stack limit check. (MATCH_STACK_LIMIT_SIZE)
+2003/02/28: [impl] check recursive subexp call.
+2003/02/28: [impl] add opcode OP_MEMORY_END_PUSH for callable subexp.
+2003/02/28: [impl] add opcode OP_CALL, OP_RETURN.
+ add stack type STK_CALL_FRAME, STK_RETURN, STK_MEM_END.
+2003/02/26: [spec] add new syntax behavior REG_SYN_STRICT_CHECK_BACKREF_NUMBER.
+ if it is set, then error /(\1)/, /\1(..)/ etc...
+2003/02/26: [spec] if backref number is greater than max group number,
+ then return compile error. (REGERR_INVALID_BACKREF_NUMBER)
+2003/02/26: [tune] bad implemented N_ALT case in get_min_match_length().
+2003/02/26: [dist] auto update testc.c and win32/testc.c in dist target.
+2003/02/26: [impl] add -win option to testconv.rb.
+2003/02/25: [spec] allow to assign same name to different group.
+ add OP_BACKREF_MULTI.
+2003/02/24: [impl] reduce redundant repeat of empty target.
+ ex. /()*/ ==> /()?/, /()+/ ==> /()/, /(?:)+/ ==> //
+2003/02/24: [impl] change condition in regex_is_allow_reverse_match().
+2003/02/24: [impl] convert i(/../, ...) functions in testconv.rb.
+2003/02/24: [impl] change name table struct.
+
+2003/02/22: Version 1.8.0
+
+2003/02/22: [new] named subexp, named back reference. (thanks akr)
+ define: (?<name>...), back-ref: \g<name>
+2003/02/22: [impl] use str_node_can_be_split().
+2003/02/21: [dist] add sample/posix.c
+2003/02/21: [spec] rename some error code symbols.
+2003/02/21: [spec] max number of multibyte ranges(255) is small.
+ 255 --> 1000. (thanks MoonWolf)
+2003/02/20: [new] supported Basic Regular Expression(BRE) in POSIX API.
+ (REG_EXTENDED option: Extended RE)
+2003/02/20: [new] variable syntax.
+
+2003/02/12: Version 1.7.2
+
+2003/02/12: [bug] mismatch /\?a/i.match('?A').
+ check raw value in scan_make_node() and scan_backslash().
+ (thanks Nobu)
+2003/02/12: [impl] rename 'max_mem' to 'num_mem' in regex_t.
+2003/02/12: [impl] rename 'code' to 'enc' in regex_t.
+2003/02/12: [spec] remove transtable argument in regex_new and regex_recompile.
+ remove transtable member in regex_t.
+2003/02/10: [inst] change backup file suffix name from '.orig' to '.ruby_orig'.
+ (win32/Makefile)
+2003/02/10: [spec] number check in scan_char_class() ignore-case mode.
+ ex. /[\x58-\x64]/i
+2003/02/10: [impl] don't use OP_MEMORY_END_PUSH (and STK_MEM_END).
+2003/02/10: [impl] lift up head_exact value from child qualifier node to parent.
+2003/02/10: [tune] change stack type values.
+2003/02/10: [dist] add HISTORY.
+2003/02/08: [tune] change stack type values.
+2003/02/08: [tune] add STACK_BASE_CHECK().
+2003/02/08: [tune] add STACK_PUSH_ENSURED().
+2003/02/08: [dist] change contents of doc/API.
+2003/02/07: [inst] change backup file suffix name from '.orig' to '.ruby_orig'.
+2003/02/07: [spec] range in char-class should be same spec. with Ruby
+ in ignore-case mode. (ex. /[A-c]/i == /[a-c]/i)
+ (thanks MoonWolf)
+2003/02/07: [spec] [!--] should be allowed. (thanks MoonWolf)
+2003/02/07: [dist] refresh re.c.180.patch for re.c (2003-02-06).
+
+2003/02/07: Version 1.7.1
+
+2003/02/07: [impl] check first byte of string in ignore-case mode.
+ (get_head_exact_node())
+2003/02/07: [impl] remove redundant statements in setup_tree().
+2003/02/06: [new] create Win32 DLL.
+2003/02/06: [impl] use P_() macro for function prototype.
+2003/02/06: [impl] add HAVE_PROTOTYPE, HAVE_STDARG_PROTOTYPES in
+ configure.in and config.h.in.
+2003/02/06: [spec] /[0-9-a]/ is allowed as usual char '-' and 'a' in Ruby.
+ add USE_BETTER_COMPATIBILITY_FOR_ORIGINAL_REGEX in
+ regint.h. (thanks MoonWolf)
+2003/02/06: [spec] rename REG_MBCTYPE_XXXX to REG_ENCODING_XXXX in onigposix.h.
+2003/02/05: [spec] rename MBCTYPE_XXXX to REG_MBCTYPE_XXXX in onigposix.h.
+2003/02/05: [spec] add POSIX API error REG_EONIG_THREAD to onigposix.h.
+2003/02/05: [dist] add .cvsignore file.
+
+2003/02/04: Version 1.7
+
+2003/02/04: [bug] typo miss in regex_region_copy().
+2003/02/04: [impl] change THREAD_PASS macro. (regint.h)
+2003/02/04: [dist] add API document file doc/API.
+2003/02/04: [tune] if sub_anchor has ANCHOR_BEGIN_LINE then
+ set REG_OPTIMIZE_EXACT_BM in set_optimize_exact_info().
+2003/02/04: [spec] reimplement regex_clone() and it is obsoleted.
+2003/02/04: [bug] add REGERR_OVER_THREAD_PASS_LIMIT_COUNT
+ to regerror.c regposix.c.
+2003/02/03: [bug] Hankaku-Kana may be second byte in Shift_JIS
+ regex_is_allow_reverse_match().
+2003/02/03: [impl] add optimization type REG_OPTIMIZE_EXACT_BM_NOT_REV.
+ remove exact_allow_reverse_match member in regex_t.
+2003/02/03: [impl] add exact_allow_reverse_match member in regex_t.
+2003/02/03: [impl] compile-search conflict in regex_search() is handled.
+2003/02/01: [tune] decrease regex_region_clear() calling from regex_search().
+2003/02/01: [tune] remove region argument from match_at().
+2003/01/31: [tune] don't use strlen() in regexec() and regcomp().
+2003/01/31: [tune] decrease regex_reduce_chain() calling in regex_search().
+2003/01/31: [bug] STRING_CMP() in regexec.c was wrong in ignore-case.
+2003/01/31: [impl] convert to lower-case char at string compile time.
+ change SBTRANSCMP() in regexec.c.
+2003/01/31: [impl] rename TTRANS() to TOLOWER().
+2003/01/30: [bug] .c.o --> .c.obj in win32\Makefile.
+2003/01/30: [impl] add -DNOT_RUBY to Makefile.in.
+ NOT_RUBY is referred in regint.h for escape double
+ including config.h.
+2003/01/30: [impl] when string hasn't case ambiguity, don't compile
+ to ignore case opcode.
+2003/01/29: [impl] add SJIS, UTF-8 test_sb() test.
+2003/01/29: [dist] add INSTALL-RUBY file.
+2003/01/28: [test] success in Cygwin, Ruby 1.8.0 (2003-01-27).
+2003/01/24: [inst] add rback target to Makefile.in.
+2003/01/24: [impl] change SBCMP() -> IS_NEWLINE() in match_at().
+2003/01/23: [impl] add encoding arg to scan_xxxx_number().
+2003/01/23: [impl] rename WCInt to WCINT.
+2003/01/22: [bug] POSIX API regexec() was not thread safe.
+ remove region member from POSIX regex_t.
+ [new] add search time option REG_OPTION_POSIX_REGION.
+ (region argument is treated as regmatch_t[] type)
+ speed up regexec().
+2003/01/22: [memo] start CVS entry in my box.
+
+2003/01/21: Version 1.6
+
+2003/01/21: [test] Mac OS X 10.1, Ruby 1.8.0 (2003-01-20)
+2003/01/20: [impl] add UTF-8 check to test.rb. (thanks UENO Katsuhiro)
+2003/01/18: [impl] change REGION_NOTPOS to REG_REGION_NOTPOS in regex.h.
+2003/01/17: [dist] add sample/simple.c.
+2003/01/17: [inst] add configure option --with-rubydir.
+2003/01/17: [bug] bad implemeted POSIX API options.
+ default: /./ not match "\n", anchor not match "\n"
+ REG_NEWLINE: /./ not match "\n", anchor match "\n"
+2003/01/16: [impl] rewrite POSIX API regexec() for speed up.
+2003/01/16: [impl] add region member to POSIX regex_t struct.
+2003/01/16: [inst] rename library file from 'libregex.a' to 'libonig.a'.
+2003/01/15: [dist] add testc.c to distribution file.
+2003/01/15: [test] success in 'make rtest/ctest/ptest' on Windows 2000.
+2003/01/15: [bug] change '/' to \' in win32/Makefile.
+2003/01/14: [test] success in Ruby make test on Windows 2000.
+ VC++6.0, Ruby 1.6.8 (2003-01-12)
+2003/01/14: [inst] change Makefile.in and win32/Makefile.
+2003/01/11: [inst] changes for Win32 platform. (regint.h, reggnu.c, regcomp.c)
+2003/01/11: [dist] add win32 directory. (config.h, Makefile, testc.c)
+2003/01/10: [inst] add onigposix.h to install target. (Makefile.in)
+2003/01/10: [bug] lacked a comma in ESTRING[]. (regposerr.c)
+2003/01/10: [bug] local variable name was wrong. buf -> tbuf (regerror())
+2003/01/10: [spec] remove REG_RUBY_M17N case from onigposix.h and regposix.c.
+
+2003/01/09: Version 1.5
+
+2003/01/09: [inst] replace Ruby re.c.XXX.patch files. (166 -> 168, 172 -> 180)
+2003/01/09: [new] implement POSIX API. (thanks knu)
+ (onigposix.h, regposix.c, regposerr.c)
+2003/01/08: [spec] remove REGERR_END_PATTERN_AFTER_BACKSLASH in regex.h.
+2003/01/08: [spec] region arg can be NULL in regex_search() and regex_match().
+
+2003/01/08: Version 1.4
+
+2003/01/08: [inst] add test program converter (test.rb -> testc.c).
+2003/01/08: [bug] move GET_WCINT() from regcomp.c to regint.h.
+2003/01/07: [inst] add new test script (test.rb).
+2002/12/30: [bug] wrong merge in multibyte mode (alt_merge_opt_exact_info()).
+2002/12/28: [inst] add rtest target to Makefile.in.
+2002/12/28: [bug] /\xfe/.match("\xfe") mismatch in multibyte mode.
+ add "raw" flag arg to concat_opt_exact_info_str().
+2002/12/25: [bug] check condition was wrong in alt_merge_opt_map_info().
+2002/12/25: [impl] add threshold_len check in regex_search().
+2002/12/23: [bug] prec-read in alternative (/a|(?=z).f/.match("zf") => nil)
+2002/12/23: [bug] \G in alternative (/a|\Gz/.match("bza") => "z").
+ add start member in MatchArg. (regexec.c)
+2002/12/21: [impl] **** rewrite all optimization process. ****
+2002/12/16: [impl] remove node subtype EFFECT_EMPTY.
+2002/12/12: [impl] reconstruct node types. (regcomp.c)
+2002/12/11: [impl] add regerror.c
+2002/12/10: [bug] [ruby-dev:19042] (thanks Nobu)
+ anchor(\G etc...) influenced outside of "|". (/a|\Gb/)
+2002/11/30: [bug] [ruby-dev:18966] (thanks Nobu)
+ char-class(\S, [^\s] etc...) optimize map-info was wrong.
+2002/11/29: [bug] infinite loop on NULL-pointer str search (regex_search()).
+ (thanks matz)
+2002/11/29: [bug] change static -> extern (regex_chain_reduce()).
+2002/11/29: [bug] change encoding to RegDefaultCharEncoding
+ in re_recompile_pattern(). (adapt to re.c)
+2002/04/24: [spec] USE_ONIGURUMA_EXTENSION is disabled in default.
+2002/04/24: [new] add searching time option: REG_OPTION_NOTBOL/NOTEOL.
+ add searching time option argument to regex_search() and
+ regex_match(). (prepare for POSIX API)
+2002/04/20: [impl] divide regex.c file into regcomp.c, regexec.c, reggnu.c
+ and regint.h.
+2002/04/09: [impl] move IS_MULTILINE() to outside of loop in OP_ANYCHAR_STAR.
+2002/04/08: [impl] don't use OP_REPEAT operator for '??'.
+2002/04/06: [impl] reduce redundant nested repeat operators(?,*,+,??,*?,+?).
+ ex. (?:a*)?, (?:a??)* etc..
+2002/04/06: [spec] should not warn for /(?:a?)+?/.
+2002/04/04: [spec] should allow fixed length alternative and repeat pattern
+ in look-behind. ex. /(?<=(a|b){3})/ (thanks Guy Decoux)
+2002/04/02: [spec] should warn for /(?:a+)?/ and /(?:a*)??/. (thanks akr)
+
+2002/04/01: Version 1.3
+
+2002/04/01: [dist] add COPYING.
+2002/03/30: [spec] warn redundant nested repeat operator
+ in Ruby verbose mode. ex. (?:a*)?
+2002/03/30: [spec] nested repeat operator error check should be
+ same with GNU regex. (thanks Guy Decoux)
+2002/03/30: [new] add \x{hexadecimal-wide-char}. (thanks matz)
+2002/03/27: [bug] MBCTYPE_XXX symbol values should be same with GNU regex.
+2002/03/27: [impl] add THREAD_ATOMIC to regex_clone(), regex_init(), regex_end().
+2002/03/25: [spec] if encoding is utf-8, allow combination of singlebyte and
+ multibyte code range in char class.
+ (cancelled 2002/04/01: for M17N compatibility)
+2002/03/25: [dist] description of the license condition is added to README.
+2002/03/23: [bug] should set all bits of reg->mem_stats,
+ if REG_OPTION_FIND_LONGEST or REG_OPTION_NOT_EMPTY.
+2002/03/23: [new] add a new option REG_OPTION_NOT_EMPTY.
+2002/03/20: [spec] allow incompleted left brace as an usual char.
+ ex. /{/, /({)/, /a{2,3/ etc...
+2002/03/20: [impl] serialize integer in bytecode.
+ (switch by UNALIGNED_WORD_ACCESS in regex.c)
+2002/03/20: [impl] change re_mbcinit() for REG_RUBY_M17N.
+2002/03/19: [impl] word alignment of char class multi-byte code ranges.
+2002/03/19: [impl] replace OP_EXACTMB4N with OP_EXACTMB3N.
+2002/03/19: [bug] OP_CCLASS_MB_NOT process in matchAt() is wrong.
+2002/03/19: [new] add re_mbctab[] for Ruby extension library compatibility.
+2002/03/19: [spec] allow nested repeat operator, if operator is {n,m} type.
+2002/03/19: [new] add REG_IS_PATTERN_ERROR(ecode) in regex.h
+2002/03/18: [spec] /[a-b-c]/ should be error.
+2002/03/18: [bug] /[\w-a]/ should be error. (thanks Guy Decoux)
+2002/03/18: [bug] /[\]/ should be error. (thanks Guy Decoux)
+2002/03/18: [bug] /()*/ etc.. should not be error. (thanks Guy Decoux)
+2002/03/18: [spec] /a{1}*/ should not be error. (thanks Guy Decoux)
+2002/03/18: [bug] ab{2}{3} was interpreded to (?:a(?:b{2})){3}
+ (thanks Guy Decoux)
+2002/03/18: [bug] abort /(?i)*a/ etc... (thanks Guy Decoux)
+2002/03/18: [bug] abort /a|*/,/a|{1}/ etc... (thanks Guy Decoux)
+
+2002/03/13: Version 1.2
+
+2002/03/13: [test] success in rubicon/builtin/AllBuiltinTests.rb.
+ (thanks rubicon)
+2002/03/13: [bug] OP_EXACTMBN process in matchAt() is wrong.
+2002/03/13: [bug] start argument of BackwardSearchRange() is wrong.
+2002/03/12: [spec] change function name style from CamelCase
+ to underline_separation. (includes API)
+2002/03/12: [bug] if pattern has nested null-check, cause infinite loop.
+ correct STACK_NULL_CHECK() macro. (thanks Guy Decoux)
+2002/03/11: [bug] it is wrong that four numbers to continue as
+ an octal value in scanBackSlash(). ex. /\0111/
+ (thanks matz)
+2002/03/11: [new] \k (single-byte word char), \K (multi-byte char).
+2002/03/09: [inst] add two targets to Makefile.in (166 and 172).
+2002/03/09: [spec] decrease REG_MAX_BACKREF_NUM, REG_MAX_REPEAT_NUM
+ values.
+2002/03/08: [spec] allow use of "\A"(begin-buf) in look-behind.
+2002/03/08: [impl] add a new opcode OP_PUSH_IF_PEEK_NEXT.
+2002/03/08: [impl] add a new opcode OP_ANYCHAR_STAR_PEEK_NEXT.
+2002/03/07: [spec] prohibit use of capture group "(...)"
+ in negative look-behind.
+2002/03/07: [inst] add configure.in, config.h.in, Makefile.in.
+2002/03/07: [impl] call Init_REGEX_STAT() in RegexInit().
+2002/03/07: [spec] less length string match with negative look-behind.
+ ex. /(?<!XXX)a/.match("Xa"). (thanks Nobu)
+2002/03/06: [impl] expand repeated string, if expanded length <= 100.
+ ex. /(?:abc){10}/
+2002/03/06: [new] add a symbol REG_TRANSTABLE_USE_DEFAULT in regex.h.
+2002/03/06: [impl] rename RegDefaultCharCode to RegDefaultCharEncoding.
+2002/03/06: [bug] if pattern has NULL(\000) char, infinite loop happens
+ in ScanMakeNode(). (beware of strchr(). thanks Nobu)
+2002/03/06: [bug] range argument of ForwardSearchRange() is wrong.
+ ex. /\A.a/, /\G.a/ mismatched with "aa". (thanks Nobu)
+2002/03/05: [new] add RegexMatch() API. rename regexMatch() to matchAt().
+2002/03/05: [impl] change function definition style.
+2002/03/05: [impl] abolish use of macro symbol which name begin with underline.
+2002/03/04: [bug] make up a break-statement in compileTree().
+ (compile error on Mac OS X 10.1.3)
+
+2002/03/04: Version 1.1
+
+2002/03/04: [impl] replace STK_BOTTOM with STK_ALT.
+2002/03/02: [impl] add new opcode OP_FINISH and new stack type
+ STK_BOTTOM for (little bit) speed up STACK_POP.
+2002/03/02: [impl] add new opcode OP_EXACT1_IC, OP_EXACTN_IC
+ for compile time ignore case check.
+ remove opcode OP_EXACT1_RAW, OP_EXACTN_RAW.
+2002/03/02: [impl] add OpTime info to statistical data.
+2002/02/28: [bug] sub_anchor($) in ForwardSearch() and BackwardSearch().
+ ex. /$\x0az/.match("\nz")
+2002/02/28: [new] look-behind (?<=pattern), (?<!pattern).
+2002/02/27: [bug] use StackIndex instead of StackType* for realloc problem.
+2002/02/27: [impl] use m17n_codepoint() as mb2wc() in REG_RUBY_M17N.
+2002/02/27: [spec] undefined POSIX bracket /[[:xyz:]]/ should be syntax error.
+2002/02/26: [bug] ex. /$*/, /[a-]/, /((?i)a)b/ (thanks matz)
+
+2002/02/25: Version 1.0 (first release)
+
+--
+[bug: bug fix]
+[API: API change/new/delete]
+[new: new feature]
+[spec: specification change]
+[impl: implementation change]
+[tune: tune for speed up]
+[inst: changes for installation]
+[dist: distribution change]
+[test: test]
+[dev: development]
+[memo: memo]
+--
+<create tag>
+svn copy file:///home/kosako/svnreps/svnrep_onig/trunk file:///home/kosako/svnreps/svnrep_onig/tags/5.0.0 -m "ADD TAG: 5.0.0"
+
+<set ignore files by .cvsignore>
+svn propset svn:ignore -F .cvsignore .
+svn commit -m "..."
+
+
+<CVS: show all tags>
+cvs history -T
+
+<CVS: add tag>
+cvs rtag "VERSION_X_X_X" oniguruma
+
+
+<GNU Autotools: bootstrap>
+* write Makefile.am and configure.in.
+> aclocal
+> libtoolize or glibtoolize
+> automake --foreign --add-missing
+> autoconf
+> configure --with-rubydir=... CFLAGS="-O2 -Wall"
+
+
+<GNU libtool: version management>
+
+ VERSION = current:revision:age
+
+ current: interface number (from 0)
+ revision: implementation number of same interface (from 0)
+ age: number of supported previous interfaces
+ (if current only supported then age == 0)
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/INSTALL b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/INSTALL
new file mode 100644
index 000000000..8865734f8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/INSTALL
@@ -0,0 +1,368 @@
+Installation Instructions
+*************************
+
+ Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
+Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell command './configure && make && make install'
+should configure, build, and install this package. The following
+more-detailed instructions are generic; see the 'README' file for
+instructions specific to this package. Some packages provide this
+'INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The 'configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a 'Makefile' in each directory of the package.
+It may also create one or more '.h' files containing system-dependent
+definitions. Finally, it creates a shell script 'config.status' that
+you can run in the future to recreate the current configuration, and a
+file 'config.log' containing compiler output (useful mainly for
+debugging 'configure').
+
+ It can also use an optional file (typically called 'config.cache' and
+enabled with '--cache-file=config.cache' or simply '-C') that saves the
+results of its tests to speed up reconfiguring. Caching is disabled by
+default to prevent problems with accidental use of stale cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how 'configure' could check whether to do them, and mail
+diffs or instructions to the address given in the 'README' so they can
+be considered for the next release. If you are using the cache, and at
+some point 'config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file 'configure.ac' (or 'configure.in') is used to create
+'configure' by a program called 'autoconf'. You need 'configure.ac' if
+you want to change it or regenerate 'configure' using a newer version of
+'autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. 'cd' to the directory containing the package's source code and type
+ './configure' to configure the package for your system.
+
+ Running 'configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type 'make' to compile the package.
+
+ 3. Optionally, type 'make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type 'make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the 'make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type 'make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior 'make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing 'make clean'. To also remove the
+ files that 'configure' created (so you can compile the package for
+ a different kind of computer), type 'make distclean'. There is
+ also a 'make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type 'make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide 'make
+ distcheck', which can by used by developers to test that all other
+ targets like 'make install' and 'make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the 'configure' script does not know about. Run './configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give 'configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here is
+an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU 'make'. 'cd' to the
+directory where you want the object files and executables to go and run
+the 'configure' script. 'configure' automatically checks for the source
+code in the directory that 'configure' is in and in '..'. This is known
+as a "VPATH" build.
+
+ With a non-GNU 'make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use 'make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple '-arch' options to the
+compiler but only a single '-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the 'lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, 'make install' installs the package's commands under
+'/usr/local/bin', include files under '/usr/local/include', etc. You
+can specify an installation prefix other than '/usr/local' by giving
+'configure' the option '--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like '--bindir=DIR' to specify different values for particular
+kinds of files. Run 'configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the default
+for these options is expressed in terms of '${prefix}', so that
+specifying just '--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to 'configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+'make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, 'make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+'${prefix}'. Any directories that were specified during 'configure',
+but not in terms of '${prefix}', must each be overridden at install time
+for the entire installation to be relocated. The approach of makefile
+variable overrides for each directory variable is required by the GNU
+Coding Standards, and ideally causes no recompilation. However, some
+platforms have known limitations with the semantics of shared libraries
+that end up requiring recompilation when using this method, particularly
+noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the 'DESTDIR' variable. For
+example, 'make install DESTDIR=/alternate/directory' will prepend
+'/alternate/directory' before all installation names. The approach of
+'DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of '${prefix}'
+at 'configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving 'configure' the
+option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
+
+ Some packages pay attention to '--enable-FEATURE' options to
+'configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to '--with-PACKAGE' options, where PACKAGE
+is something like 'gnu-as' or 'x' (for the X Window System). The
+'README' should mention any '--enable-' and '--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, 'configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the 'configure' options '--x-includes=DIR' and
+'--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of 'make' will be. For these packages, running './configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with 'make V=1'; while running './configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with 'make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
+is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ HP-UX 'make' updates targets which have the same time stamps as their
+prerequisites, which makes it generally unusable when shipped generated
+files such as 'configure' are involved. Use GNU 'make' instead.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
+workaround. If GNU CC is not installed, it is therefore recommended to
+try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
+in your 'PATH', put it _after_ '/usr/bin'.
+
+ On Haiku, software installed for all users goes in '/boot/common',
+not '/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features 'configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, 'configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+'--build=TYPE' option. TYPE can either be a short name for the system
+type, such as 'sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file 'config.sub' for the possible values of each field. If
+'config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option '--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with '--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for 'configure' scripts to share,
+you can create a site shell script called 'config.site' that gives
+default values for variables like 'CC', 'cache_file', and 'prefix'.
+'configure' looks for 'PREFIX/share/config.site' if it exists, then
+'PREFIX/etc/config.site' if it exists. Or, you can set the
+'CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all 'configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to 'configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the 'configure' command line, using 'VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified 'gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
+Autoconf limitation. Until the limitation is lifted, you can use this
+workaround:
+
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+'configure' Invocation
+======================
+
+ 'configure' recognizes the following options to control how it
+operates.
+
+'--help'
+'-h'
+ Print a summary of all of the options to 'configure', and exit.
+
+'--help=short'
+'--help=recursive'
+ Print a summary of the options unique to this package's
+ 'configure', and exit. The 'short' variant lists options used only
+ in the top level, while the 'recursive' variant lists options also
+ present in any nested packages.
+
+'--version'
+'-V'
+ Print the version of Autoconf used to generate the 'configure'
+ script, and exit.
+
+'--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally 'config.cache'. FILE defaults to '/dev/null' to
+ disable caching.
+
+'--config-cache'
+'-C'
+ Alias for '--cache-file=config.cache'.
+
+'--quiet'
+'--silent'
+'-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to '/dev/null' (any error
+ messages will still be shown).
+
+'--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ 'configure' can determine that directory automatically.
+
+'--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names:: for
+ more details, including other options available for fine-tuning the
+ installation locations.
+
+'--no-create'
+'-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+'configure' also accepts some other, not widely useful, options. Run
+'configure --help' for more details.
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/Makefile.am b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/Makefile.am
new file mode 100644
index 000000000..fc3885b4d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/Makefile.am
@@ -0,0 +1,81 @@
+## Makefile.am for Oniguruma
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src test sample
+
+EXTRA_DIST = oniguruma.pc.in HISTORY README_japanese README.md \
+ index.html index_ja.html make_win.bat \
+ CMakeLists.txt oniguruma.pc.cmake.in cmake/Config.cmake.in \
+ src/config.h.cmake.in \
+ doc/API doc/API.ja doc/RE doc/RE.ja doc/FAQ doc/FAQ.ja \
+ doc/CALLOUTS.BUILTIN doc/CALLOUTS.BUILTIN.ja \
+ doc/CALLOUTS.API doc/CALLOUTS.API.ja \
+ doc/SYNTAX.md doc/UNICODE_PROPERTIES \
+ src/Makefile.windows src/config.h.windows.in \
+ src/config.h.win32 src/config.h.win64 \
+ windows/testc.c
+
+bin_SCRIPTS = onig-config
+
+onig-config: onig-config.in
+
+do_subst = sed \
+ -e 's,[@]datadir[@],$(datadir),g' \
+ -e 's,[@]datarootdir[@],$(datarootdir),g' \
+ -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g' \
+ -e 's,[@]prefix[@],$(prefix),g' \
+ -e 's,[@]exec_prefix[@],$(exec_prefix),g' \
+ -e 's,[@]libdir[@],$(libdir),g' \
+ -e 's,[@]includedir[@],$(includedir),g'
+
+oniguruma.pc: $(srcdir)/oniguruma.pc.in Makefile
+ $(do_subst) < $(srcdir)/oniguruma.pc.in > $(@)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = oniguruma.pc
+
+
+all-test:
+ cd test; make test
+
+archive:
+ git archive --format=tar --prefix=oniguruma/ HEAD | gzip > ../oniguruma-archive.tar.gz
+
+tar:
+ cd ..; tar cvf oniguruma-`date +%Y%m%d`.tar oniguruma; gzip oniguruma-`date +%Y%m%d`.tar
+
+debug:
+ make clean
+ ./configure CFLAGS="-O0 -g"
+ make
+
+debug_out:
+ make clean
+ ./configure CFLAGS="-O0 -g -DONIG_DEBUG_PARSE -DONIG_DEBUG_COMPILE"
+ make
+
+sanitize:
+ make clean
+ ./configure CFLAGS="-O -g -fsanitize=address" LDFLAGS="-fsanitize=address"
+ make
+ make all-test
+
+cov:
+ make lcov-clear
+ cd test; make CFLAGS="--coverage" test
+ make lcov
+
+gcov:
+ make CFLAGS="--coverage"
+
+lcov:
+ lcov -c -d src/.libs -o coverage.info
+ genhtml -o coverage coverage.info
+
+lcov-clear:
+ lcov -z -d .
+
+cov-clean: clean
+ rm -rf coverage coverage.info
+ find . -name '*.gcno' | xargs rm -f
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/NEWS b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/NEWS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/NEWS
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README
new file mode 100644
index 000000000..90b420ddd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README
@@ -0,0 +1,195 @@
+README 2018/04/05
+
+Oniguruma ---- (C) K.Kosako
+
+https://github.com/kkos/oniguruma
+
+FIXED Security Issues (in Oniguruma 6.3.0):
+ CVE-2017-9224, CVE-2017-9225, CVE-2017-9226
+ CVE-2017-9227, CVE-2017-9228, CVE-2017-9229
+
+---
+Oniguruma is a modern and flexible regular expressions library. It
+encompasses features from different regular expression implementations
+that traditionally exist in different languages. It comes close to
+being a complete superset of all regular expression features found
+in other regular expression implementations.
+
+Its features include:
+* Character encoding can be specified per regular expression object.
+* Several regular expression types are supported:
+ * POSIX
+ * Grep
+ * GNU Regex
+ * Perl
+ * Java
+ * Ruby
+ * Emacs
+
+Supported character encodings:
+
+ ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE,
+ EUC-JP, EUC-TW, EUC-KR, EUC-CN,
+ Shift_JIS, Big5, GB18030, KOI8-R, CP1251,
+ ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5,
+ ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10,
+ ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16
+
+* GB18030: contributed by KUBO Takehiro
+* CP1251: contributed by Byte
+------------------------------------------------------------
+
+License
+
+ BSD license.
+
+
+Install
+
+ Case 1: Unix and Cygwin platform
+
+ 1. autoreconf -vfi (* case: configure script is not found.)
+
+ 2. ./configure
+ 3. make
+ 4. make install
+
+ * uninstall
+
+ make uninstall
+
+ * configuration check
+
+ onig-config --cflags
+ onig-config --libs
+ onig-config --prefix
+ onig-config --exec-prefix
+
+
+
+ Case 2: Windows 64/32bit platform (Visual Studio)
+
+ execute make_win64 or make_win32
+
+ src/onig_s.lib: static link library
+ src/onig.dll: dynamic link library
+
+ * test (ASCII/Shift_JIS)
+ 1. cd src
+ 2. copy ..\windows\testc.c .
+ 3. nmake -f Makefile.windows ctest
+
+ (I have checked by Visual Studio Community 2015)
+
+
+
+Regular Expressions
+
+ See doc/RE (or doc/RE.ja for Japanese).
+
+
+Usage
+
+ Include oniguruma.h in your program. (Oniguruma API)
+ See doc/API for Oniguruma API.
+
+ If you want to disable UChar type (== unsigned char) definition
+ in oniguruma.h, define ONIG_ESCAPE_UCHAR_COLLISION and then
+ include oniguruma.h.
+
+ If you want to disable regex_t type definition in oniguruma.h,
+ define ONIG_ESCAPE_REGEX_T_COLLISION and then include oniguruma.h.
+
+ Example of the compiling/linking command line in Unix or Cygwin,
+ (prefix == /usr/local case)
+
+ cc sample.c -L/usr/local/lib -lonig
+
+
+ If you want to use static link library(onig_s.lib) in Win32,
+ add option -DONIG_EXTERN=extern to C compiler.
+
+
+
+Sample Programs
+
+ sample/simple.c example of the minimum (Oniguruma API)
+ sample/names.c example of the named group callback.
+ sample/encode.c example of some encodings.
+ sample/listcap.c example of the capture history.
+ sample/posix.c POSIX API sample.
+ sample/sql.c example of the variable meta characters.
+ (SQL-like pattern matching)
+ sample/user_property.c example of user defined Unicode property.
+
+Test Programs
+ sample/syntax.c Perl, Java and ASIS syntax test.
+ sample/crnl.c --enable-crnl-as-line-terminator test
+
+
+Source Files
+
+ oniguruma.h Oniguruma API header file. (public)
+ onig-config.in configuration check program template.
+
+ regenc.h character encodings framework header file.
+ regint.h internal definitions
+ regparse.h internal definitions for regparse.c and regcomp.c
+ regcomp.c compiling and optimization functions
+ regenc.c character encodings framework.
+ regerror.c error message function
+ regext.c extended API functions. (deluxe version API)
+ regexec.c search and match functions
+ regparse.c parsing functions.
+ regsyntax.c pattern syntax functions and built-in syntax definitions.
+ regtrav.c capture history tree data traverse functions.
+ regversion.c version info function.
+ st.h hash table functions header file
+ st.c hash table functions
+
+ oniggnu.h GNU regex API header file. (public)
+ reggnu.c GNU regex API functions
+
+ onigposix.h POSIX API header file. (public)
+ regposerr.c POSIX error message function.
+ regposix.c POSIX API functions.
+
+ mktable.c character type table generator.
+ ascii.c ASCII encoding.
+ euc_jp.c EUC-JP encoding.
+ euc_tw.c EUC-TW encoding.
+ euc_kr.c EUC-KR, EUC-CN encoding.
+ sjis.c Shift_JIS encoding.
+ big5.c Big5 encoding.
+ gb18030.c GB18030 encoding.
+ koi8.c KOI8 encoding.
+ koi8_r.c KOI8-R encoding.
+ cp1251.c CP1251 encoding.
+ iso8859_1.c ISO-8859-1 encoding. (Latin-1)
+ iso8859_2.c ISO-8859-2 encoding. (Latin-2)
+ iso8859_3.c ISO-8859-3 encoding. (Latin-3)
+ iso8859_4.c ISO-8859-4 encoding. (Latin-4)
+ iso8859_5.c ISO-8859-5 encoding. (Cyrillic)
+ iso8859_6.c ISO-8859-6 encoding. (Arabic)
+ iso8859_7.c ISO-8859-7 encoding. (Greek)
+ iso8859_8.c ISO-8859-8 encoding. (Hebrew)
+ iso8859_9.c ISO-8859-9 encoding. (Latin-5 or Turkish)
+ iso8859_10.c ISO-8859-10 encoding. (Latin-6 or Nordic)
+ iso8859_11.c ISO-8859-11 encoding. (Thai)
+ iso8859_13.c ISO-8859-13 encoding. (Latin-7 or Baltic Rim)
+ iso8859_14.c ISO-8859-14 encoding. (Latin-8 or Celtic)
+ iso8859_15.c ISO-8859-15 encoding. (Latin-9 or West European with Euro)
+ iso8859_16.c ISO-8859-16 encoding.
+ (Latin-10 or South-Eastern European with Euro)
+ utf8.c UTF-8 encoding.
+ utf16_be.c UTF-16BE encoding.
+ utf16_le.c UTF-16LE encoding.
+ utf32_be.c UTF-32BE encoding.
+ utf32_le.c UTF-32LE encoding.
+ unicode.c common codes of Unicode encoding.
+
+ win32/Makefile Makefile for Win32 (VC++)
+ win32/config.h config.h for Win32
+
+
+and I'm thankful to Akinori MUSHA.
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README.md b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README.md
new file mode 100644
index 000000000..01900e1e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README.md
@@ -0,0 +1,346 @@
+[![Build Status](https://travis-ci.org/kkos/oniguruma.svg?branch=master)](https://travis-ci.org/kkos/oniguruma)
+[![Code Quality: Cpp](https://img.shields.io/lgtm/grade/cpp/g/kkos/oniguruma.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/kkos/oniguruma/context:cpp)
+[![Total Alerts](https://img.shields.io/lgtm/alerts/g/kkos/oniguruma.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/kkos/oniguruma/alerts)
+
+Oniguruma
+=========
+
+https://github.com/kkos/oniguruma
+
+Oniguruma is a modern and flexible regular expressions library. It
+encompasses features from different regular expression implementations
+that traditionally exist in different languages.
+
+Character encoding can be specified per regular expression object.
+
+Supported character encodings:
+
+ ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE,
+ EUC-JP, EUC-TW, EUC-KR, EUC-CN,
+ Shift_JIS, Big5, GB18030, KOI8-R, CP1251,
+ ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5,
+ ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10,
+ ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16
+
+* GB18030: contributed by KUBO Takehiro
+* CP1251: contributed by Byte
+* doc/SYNTAX.md: contributed by seanofw
+
+
+Master branch
+-------------
+
+* NEW API: retry limit in search functions
+* Limit on maximum nesting level of subexp call (16)
+* Fixed behavior of isolated options in Perl and Java syntaxes. /...(?i).../
+
+
+Version 6.9.4
+-------------
+
+* NEW API: RegSet (set of regexes)
+* Fixed CVE-2019-19012
+* Fixed CVE-2019-19203 (Does not affect UTF-8, UTF-16 and UTF-32 encodings)
+* Fixed CVE-2019-19204 (Affects only PosixBasic, Emacs and Grep syntaxes)
+* Fixed CVE-2019-19246
+* Fixed some problems (found by libFuzzer test)
+
+
+Version 6.9.3 (security fix release)
+------------------------------------
+
+* Fixed CVE-2019-13224
+* Fixed CVE-2019-13225
+* Fixed CVE-2019-16163
+* Fixed many problems (found by libFuzzer test)
+
+
+Version 6.9.2 (Reiwa)
+---------------------
+
+* add doc/SYNTAX.md
+* Direct threaded code (for GCC and Clang)
+* Update Unicode version 12.1.0
+* NEW: Unicode Text Segment mode option (?y{g}) (?y{w}) (*original)
+
+
+Version 6.9.1
+-------------
+
+* Speed improvement (* especially UTF-8)
+
+
+Version 6.9.0
+-------------
+
+* Update Unicode version 11.0.0
+* NEW: add Emoji properties
+
+
+Version 6.8.2
+-------------
+
+* Fix: #80 UChar in header causes issue
+* NEW API: onig_set_callout_user_data_of_match_param() (* omission in 6.8.0)
+* add doc/CALLOUTS.API and doc/CALLOUTS.API.ja
+
+
+Version 6.8.1
+-------------
+
+* Update shared library version to 5.0.0 for API incompatible changes from 6.7.1
+
+
+Version 6.8.0
+-------------
+
+* Retry-limit-in-match function enabled by default
+* NEW: configure option --enable-posix-api=no (* enabled by default)
+* NEW API: onig_search_with_param(), onig_match_with_param()
+* NEW: Callouts of contents (?{...contents...}) (?{...}\[tag]\[X<>]) (?{{...}})
+* NEW: Callouts of name (*name) (*name\[tag]{args...})
+* NEW: Builtin callouts (*FAIL) (*MISMATCH) (*ERROR{n}) (*COUNT) (*MAX{n}) etc..
+* Examples of Callouts program: [callout.c](sample/callout.c), [count.c](sample/count.c), [echo.c](sample/echo.c)
+
+
+Version 6.7.1
+-------------
+
+* NEW: Mechanism of retry-limit-in-match (* disabled by default)
+
+
+Version 6.7.0
+-------------
+
+* NEW: hexadecimal codepoint \uHHHH
+* NEW: add ONIG_SYNTAX_ONIGURUMA (== ONIG_SYNTAX_DEFAULT)
+* Disabled \N and \O on ONIG_SYNTAX_RUBY
+* Reduced size of object file
+
+
+Version 6.6.0
+-------------
+
+* NEW: ASCII only mode options for character type/property (?WDSP)
+* NEW: Extended Grapheme Cluster boundary \y, \Y
+* NEW: Extended Grapheme Cluster \X
+* Range-clear (Absent-clear) operator restores previous range in retractions.
+
+
+Version 6.5.0
+-------------
+
+* NEW: \K (keep)
+* NEW: \R (general newline) \N (no newline)
+* NEW: \O (true anychar)
+* NEW: if-then-else (?(...)...\|...)
+* NEW: Backreference validity checker (?(xxx)) (*original)
+* NEW: Absent repeater (?~absent) \[is equal to (?\~\|(?:absent)|\O*)]
+* NEW: Absent expression (?~|absent|expr) (*original)
+* NEW: Absent stopper (?~|absent) (*original)
+
+
+Version 6.4.0
+-------------
+
+* Fix fatal problem of endless repeat on Windows
+* NEW: call zero (call the total regexp) \g<0>
+* NEW: relative backref/call by positive number \k<+n>, \g<+n>
+
+
+Version 6.3.0
+-------------
+
+* NEW: octal codepoint \o{.....}
+* Fixed CVE-2017-9224
+* Fixed CVE-2017-9225
+* Fixed CVE-2017-9226
+* Fixed CVE-2017-9227
+* Fixed CVE-2017-9228
+* Fixed CVE-2017-9229
+
+
+Version 6.1.2
+-------------
+
+* allow word bound, word begin and word end in look-behind.
+* NEW option: ONIG_OPTION_CHECK_VALIDITY_OF_STRING
+
+Version 6.1
+-----------
+
+* improved doc/RE
+* NEW API: onig_scan()
+
+Version 6.0
+-----------
+
+* Update Unicode 8.0 Property/Case-folding
+* NEW API: onig_unicode_define_user_property()
+
+
+License
+-------
+
+ BSD license.
+
+
+Install
+-------
+
+### Case 1: Unix and Cygwin platform
+
+ 1. autoreconf -vfi (* case: configure script is not found.)
+
+ 2. ./configure
+ 3. make
+ 4. make install
+
+ * uninstall
+
+ make uninstall
+
+ * configuration check
+
+ onig-config --cflags
+ onig-config --libs
+ onig-config --prefix
+ onig-config --exec-prefix
+
+
+
+### Case 2: Windows 64/32bit platform (Visual Studio)
+
+ Execute make_win.bat
+
+ onig_s.lib: static link library
+ onig.dll: dynamic link library
+
+ * test (ASCII/Shift_JIS)
+
+ 1. cd src
+ 2. copy ..\windows\testc.c .
+ 3. nmake -f Makefile.windows ctest
+
+ (I have checked by Visual Studio Community 2015)
+
+
+
+Regular Expressions
+-------------------
+
+ See [doc/RE](doc/RE) or [doc/RE.ja](doc/RE.ja) for Japanese.
+
+
+Usage
+-----
+
+ Include oniguruma.h in your program. (Oniguruma API)
+ See doc/API for Oniguruma API.
+
+ If you want to disable UChar type (== unsigned char) definition
+ in oniguruma.h, define ONIG_ESCAPE_UCHAR_COLLISION and then
+ include oniguruma.h.
+
+ If you want to disable regex_t type definition in oniguruma.h,
+ define ONIG_ESCAPE_REGEX_T_COLLISION and then include oniguruma.h.
+
+ Example of the compiling/linking command line in Unix or Cygwin,
+ (prefix == /usr/local case)
+
+ cc sample.c -L/usr/local/lib -lonig
+
+
+ If you want to use static link library(onig_s.lib) in Win32,
+ add option -DONIG_EXTERN=extern to C compiler.
+
+
+
+Sample Programs
+---------------
+
+|File |Description |
+|:---------------------|:-----------------------------------------|
+|sample/callout.c |example of callouts |
+|sample/count.c |example of built-in callout *COUNT |
+|sample/echo.c |example of user defined callouts of name |
+|sample/encode.c |example of some encodings |
+|sample/listcap.c |example of the capture history |
+|sample/names.c |example of the named group callback |
+|sample/posix.c |POSIX API sample |
+|sample/regset.c |example of using RegSet API |
+|sample/scan.c |example of using onig_scan() |
+|sample/simple.c |example of the minimum (Oniguruma API) |
+|sample/sql.c |example of the variable meta characters |
+|sample/user_property.c|example of user defined Unicode property |
+
+
+Test Programs
+
+|File |Description |
+|:------------------|:--------------------------------------|
+|sample/syntax.c |Perl, Java and ASIS syntax test. |
+|sample/crnl.c |--enable-crnl-as-line-terminator test |
+
+
+
+Source Files
+------------
+
+|File |Description |
+|:------------------|:-------------------------------------------------------|
+|oniguruma.h |Oniguruma API header file (public) |
+|onig-config.in |configuration check program template |
+|regenc.h |character encodings framework header file |
+|regint.h |internal definitions |
+|regparse.h |internal definitions for regparse.c and regcomp.c |
+|regcomp.c |compiling and optimization functions |
+|regenc.c |character encodings framework |
+|regerror.c |error message function |
+|regext.c |extended API functions (deluxe version API) |
+|regexec.c |search and match functions |
+|regparse.c |parsing functions. |
+|regsyntax.c |pattern syntax functions and built-in syntax definitions|
+|regtrav.c |capture history tree data traverse functions |
+|regversion.c |version info function |
+|st.h |hash table functions header file |
+|st.c |hash table functions |
+|oniggnu.h |GNU regex API header file (public) |
+|reggnu.c |GNU regex API functions |
+|onigposix.h |POSIX API header file (public) |
+|regposerr.c |POSIX error message function |
+|regposix.c |POSIX API functions |
+|mktable.c |character type table generator |
+|ascii.c |ASCII encoding |
+|euc_jp.c |EUC-JP encoding |
+|euc_tw.c |EUC-TW encoding |
+|euc_kr.c |EUC-KR, EUC-CN encoding |
+|sjis.c |Shift_JIS encoding |
+|big5.c |Big5 encoding |
+|gb18030.c |GB18030 encoding |
+|koi8.c |KOI8 encoding |
+|koi8_r.c |KOI8-R encoding |
+|cp1251.c |CP1251 encoding |
+|iso8859_1.c |ISO-8859-1 (Latin-1) |
+|iso8859_2.c |ISO-8859-2 (Latin-2) |
+|iso8859_3.c |ISO-8859-3 (Latin-3) |
+|iso8859_4.c |ISO-8859-4 (Latin-4) |
+|iso8859_5.c |ISO-8859-5 (Cyrillic) |
+|iso8859_6.c |ISO-8859-6 (Arabic) |
+|iso8859_7.c |ISO-8859-7 (Greek) |
+|iso8859_8.c |ISO-8859-8 (Hebrew) |
+|iso8859_9.c |ISO-8859-9 (Latin-5 or Turkish) |
+|iso8859_10.c |ISO-8859-10 (Latin-6 or Nordic) |
+|iso8859_11.c |ISO-8859-11 (Thai) |
+|iso8859_13.c |ISO-8859-13 (Latin-7 or Baltic Rim) |
+|iso8859_14.c |ISO-8859-14 (Latin-8 or Celtic) |
+|iso8859_15.c |ISO-8859-15 (Latin-9 or West European with Euro) |
+|iso8859_16.c |ISO-8859-16 (Latin-10) |
+|utf8.c |UTF-8 encoding |
+|utf16_be.c |UTF-16BE encoding |
+|utf16_le.c |UTF-16LE encoding |
+|utf32_be.c |UTF-32BE encoding |
+|utf32_le.c |UTF-32LE encoding |
+|unicode.c |common codes of Unicode encoding |
+|unicode_fold_data.c|Unicode folding data |
+|windows/testc.c |Test program for Windows (VC++) |
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README_japanese b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README_japanese
new file mode 100644
index 000000000..b1b249acd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/README_japanese
@@ -0,0 +1,183 @@
+README.ja 2017/08/25
+
+鬼車 ---- (C) K.Kosako <kkosako0@gmail.com>
+
+https://github.com/kkos/oniguruma
+
+鬼車ã¯æ­£è¦è¡¨ç¾ãƒ©ã‚¤ãƒ–ラリã§ã‚る。
+ã“ã®ãƒ©ã‚¤ãƒ–ラリã®ç‰¹é•·ã¯ã€ãã‚Œãžã‚Œã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã”ã¨ã«
+文字エンコーディングを指定ã§ãã‚‹ã“ã¨ã§ã‚る。
+
+サãƒãƒ¼ãƒˆã—ã¦ã„る文字エンコーディング:
+
+ ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE,
+ EUC-JP, EUC-TW, EUC-KR, EUC-CN,
+ Shift_JIS, Big5, GB18030, KOI8-R, CP1251,
+ ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5,
+ ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10,
+ ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16
+
+* GB18030: ä¹…ä¿å¥æ´‹æ°æä¾›
+* CP1251: Byteæ°æä¾›
+------------------------------------------------------------
+
+ライセンス
+
+ BSDライセンス
+
+
+インストール
+
+ ケース1: Unixã¨Cygwin環境
+
+ 1. autoreconf -vfi (* configureスクリプトãŒãªã„ã¨ãã ã‘)
+
+ 2. ./configure
+ 3. make
+ 4. make install
+
+ アンインストール
+
+ make uninstall
+
+ 構æˆç¢ºèª
+
+ onig-config --cflags
+ onig-config --libs
+ onig-config --prefix
+ onig-config --exec-prefix
+
+
+
+ ケース2: Windows 64/32bit (Visual Studio)環境
+
+ make_win64 ã‚ã‚‹ã„㯠make_win32 を実行
+
+ onig_s.lib: static link library
+ onig.dll: dynamic link library
+
+ * 動作テスト (ASCII/Shift_JIS)
+ 1. cd src
+ 2. copy ..\windows\testc.c .
+ 3. nmake -f Makefile.windows ctest
+
+ (Visual Studio Community 2015 ã§å‹•ä½œç¢ºèª)
+
+
+
+æ­£è¦è¡¨ç¾
+
+ doc/RE.jaã‚’å‚ç…§
+
+
+使用方法
+
+ 使用ã™ã‚‹ãƒ—ログラムã§ã€oniguruma.hをインクルードã™ã‚‹(Oniguruma APIã®å ´åˆ)。
+ Oniguruma APIã«ã¤ã„ã¦ã¯ã€doc/API.jaã‚’å‚照。
+
+ oniguruma.hã§å®šç¾©ã•ã‚Œã¦ã„ã‚‹åž‹åUChar(== unsigned char)を無効ã«ã—ãŸã„å ´åˆ
+ ã«ã¯ã€ONIG_ESCAPE_UCHAR_COLLISIONã‚’defineã—ã¦ã‹ã‚‰oniguruma.hをインクルード
+ ã™ã‚‹ã“ã¨ã€‚ã“ã®ã¨ãã«ã¯UCharã¯å®šç¾©ã•ã‚Œãšã€OnigUCharã¨ã„ã†åå‰ã®å®šç¾©ã®ã¿ãŒ
+ 有効ã«ãªã‚‹ã€‚
+
+ oniguruma.hã§å®šç¾©ã•ã‚Œã¦ã„ã‚‹åž‹åregex_tを無効ã«ã—ãŸã„å ´åˆã«ã¯ã€
+ ONIG_ESCAPE_REGEX_T_COLLISIONã‚’defineã—ã¦ã‹ã‚‰oniguruma.hをインクルード
+ ã™ã‚‹ã“ã¨ã€‚ã“ã®ã¨ãã«ã¯regex_tã¯å®šç¾©ã•ã‚Œãšã€OnigRegexType, OnigRegexã¨ã„ã†
+ åå‰ã®å®šç¾©ã®ã¿ãŒæœ‰åŠ¹ã«ãªã‚‹ã€‚
+
+ Unix/Cygwin上ã§ã‚³ãƒ³ãƒ‘イルã€ãƒªãƒ³ã‚¯ã™ã‚‹å ´åˆã®ä¾‹ï¼š
+ (prefixãŒ/usr/localã®ã¨ã)
+ cc sample.c -L/usr/local/lib -lonig
+
+ GNU libtoolを使用ã—ã¦ã„ã‚‹ã®ã§ã€ãƒ—ラットフォームãŒå…±æœ‰ãƒ©ã‚¤ãƒ–ラリをサãƒãƒ¼ãƒˆã—ã¦
+ ã„ã‚Œã°ã€ä½¿ç”¨ã§ãるよã†ã«ãªã£ã¦ã„る。
+ é™çš„ライブラリã¨å…±æœ‰ãƒ©ã‚¤ãƒ–ラリã®ã©ã¡ã‚‰ã‚’使用ã™ã‚‹ã‹ã‚’指定ã™ã‚‹æ–¹æ³•ã€å®Ÿè¡Œæ™‚点ã§ã®
+ 環境設定方法ã«ã¤ã„ã¦ã¯ã€è‡ªåˆ†ã§èª¿ã¹ã¦ä¸‹ã•ã„。
+
+
+ Win32ã§ã‚¹ã‚¿ãƒ†ã‚£ãƒƒã‚¯ãƒªãƒ³ã‚¯ãƒ©ã‚¤ãƒ–ラリ(onig_s.lib)をリンクã™ã‚‹å ´åˆã«ã¯ã€
+ コンパイルã™ã‚‹ã¨ãã« -DONIG_EXTERN=extern をコンパイル引数ã«è¿½åŠ ã™ã‚‹ã“ã¨ã€‚
+
+
+使用例プログラム
+
+ sample/simple.c 最å°ä¾‹ (Oniguruma API)
+ sample/names.c åå‰ä»˜ãグループコールãƒãƒƒã‚¯ä½¿ç”¨ä¾‹
+ sample/encode.c å¹¾ã¤ã‹ã®æ–‡å­—エンコーディング使用例
+ sample/listcap.c æ•ç²å±¥æ­´æ©Ÿèƒ½ã®ä½¿ç”¨ä¾‹
+ sample/posix.c POSIX API使用例
+ sample/sql.c å¯å¤‰ãƒ¡ã‚¿æ–‡å­—機能使用例 (SQL-like パターン)
+ sample/user_property.c ユーザ定義Unicodeプロパティã®ä½¿ç”¨ä¾‹
+
+
+テストプログラム
+ sample/syntax.c Perlã€Javaã€ASIS文法ã®ãƒ†ã‚¹ãƒˆ
+ sample/crnl.c --enable-crnl-as-line-terminator テスト
+
+
+ソースファイル
+
+ oniguruma.h 鬼車APIヘッダ (公開)
+ onig-config.in onig-configプログラム テンプレート
+
+ regenc.h 文字エンコーディング枠組ã¿ãƒ˜ãƒƒãƒ€
+ regint.h 内部宣言
+ regparse.h regparse.cã¨regcomp.cã®ãŸã‚ã®å†…部宣言
+ regcomp.c コンパイルã€æœ€é©åŒ–関数
+ regenc.c 文字エンコーディング枠組ã¿
+ regerror.c エラーメッセージ関数
+ regext.c 拡張API関数
+ regexec.c 検索ã€ç…§åˆé–¢æ•°
+ regparse.c æ­£è¦è¡¨ç¾ãƒ‘ターン解æžé–¢æ•°
+ regsyntax.c æ­£è¦è¡¨ç¾ãƒ‘ターン文法関数ã€çµ„è¾¼ã¿æ–‡æ³•å®šç¾©
+ regtrav.c æ•ç²å±¥æ­´æœ¨å·¡å›žé–¢æ•°
+ regversion.c 版情報関数
+ st.h ãƒãƒƒã‚·ãƒ¥ãƒ†ãƒ¼ãƒ–ル関数宣言
+ st.c ãƒãƒƒã‚·ãƒ¥ãƒ†ãƒ¼ãƒ–ル関数
+
+ oniggnu.h GNU regex APIヘッダ (公開)
+ reggnu.c GNU regex API関数
+
+ onigposix.h POSIX APIヘッダ (公開)
+ regposerr.c POSIX APIエラーメッセージ関数
+ regposix.c POSIX API関数
+
+ mktable.c 文字タイプテーブル生æˆãƒ—ログラム
+ ascii.c ASCII エンコーディング
+ euc_jp.c EUC-JP エンコーディング
+ euc_tw.c EUC-TW エンコーディング
+ euc_kr.c EUC-KR, EUC-CN エンコーディング
+ sjis.c Shift_JIS エンコーディング
+ big5.c Big5 エンコーディング
+ gb18030.c GB18030 エンコーディング
+ koi8.c KOI8 エンコーディング
+ koi8_r.c KOI8-R エンコーディング
+ cp1251.c CP1251 エンコーディング
+ iso8859_1.c ISO-8859-1 (Latin-1)
+ iso8859_2.c ISO-8859-2 (Latin-2)
+ iso8859_3.c ISO-8859-3 (Latin-3)
+ iso8859_4.c ISO-8859-4 (Latin-4)
+ iso8859_5.c ISO-8859-5 (Cyrillic)
+ iso8859_6.c ISO-8859-6 (Arabic)
+ iso8859_7.c ISO-8859-7 (Greek)
+ iso8859_8.c ISO-8859-8 (Hebrew)
+ iso8859_9.c ISO-8859-9 (Latin-5 ã¾ãŸã¯ Turkish)
+ iso8859_10.c ISO-8859-10 (Latin-6 ã¾ãŸã¯ Nordic)
+ iso8859_11.c ISO-8859-11 (Thai)
+ iso8859_13.c ISO-8859-13 (Latin-7 ã¾ãŸã¯ Baltic Rim)
+ iso8859_14.c ISO-8859-14 (Latin-8 ã¾ãŸã¯ Celtic)
+ iso8859_15.c ISO-8859-15 (Latin-9 ã¾ãŸã¯ West European with Euro)
+ iso8859_16.c ISO-8859-16
+ (Latin-10 ã¾ãŸã¯ South-Eastern European with Euro)
+ utf8.c UTF-8 エンコーディング
+ utf16_be.c UTF-16BE エンコーディング
+ utf16_le.c UTF-16LE エンコーディング
+ utf32_be.c UTF-32BE エンコーディング
+ utf32_le.c UTF-32LE エンコーディング
+ unicode.c Unicodeエンコーディングã®å…±é€šå‡¦ç†
+
+ win32/Makefile Win32用 Makefile (for VC++)
+ win32/config.h Win32用 config.h
+
+
+and I'm thankful to Akinori MUSHA.
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/autogen.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/autogen.sh
new file mode 100755
index 000000000..006fd36df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# autogen.sh for Oniguruma
+
+echo "Generating autotools files."
+#autoreconf --install --force --symlink || exit 1
+autoreconf --install --force || exit 1
+
+echo ""
+echo "Run ./configure, make, and make install."
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/cmake/Config.cmake.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/cmake/Config.cmake.in
new file mode 100644
index 000000000..38bbde7b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/cmake/Config.cmake.in
@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
+check_required_components("@PROJECT_NAME@")
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/compile b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/compile
new file mode 100755
index 000000000..99e50524b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/compile
@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.guess b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.guess
new file mode 100755
index 000000000..256083a70
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.guess
@@ -0,0 +1,1476 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-03-08'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > "$dummy.c" ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "$UNAME_SYSTEM" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval "$set_cc_for_build"
+ cat <<-EOF > "$dummy.c"
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+ # If ldd exists, use it to detect musl libc.
+ if command -v ldd >/dev/null && \
+ ldd --version 2>&1 | grep -q ^musl
+ then
+ LIBC=musl
+ fi
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ "/sbin/$sysctl" 2>/dev/null || \
+ "/usr/sbin/$sysctl" 2>/dev/null || \
+ echo unknown)`
+ case "$UNAME_MACHINE_ARCH" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine="${arch}${endian}"-unknown
+ ;;
+ *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval "$set_cc_for_build"
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "$UNAME_VERSION" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "$machine-${os}${release}${abi}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+ exit ;;
+ *:MidnightBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
+ exit ;;
+ *:SolidBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:MirBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:Sortix:*:*)
+ echo "$UNAME_MACHINE"-unknown-sortix
+ exit ;;
+ *:Redox:*:*)
+ echo "$UNAME_MACHINE"-unknown-redox
+ exit ;;
+ mips:OSF1:*.*)
+ echo mips-dec-osf1
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix"$UNAME_RELEASE"
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux"$UNAME_RELEASE"
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval "$set_cc_for_build"
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ ;;
+ sun4)
+ echo sparc-sun-sunos"$UNAME_RELEASE"
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos"$UNAME_RELEASE"
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint"$UNAME_RELEASE"
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint"$UNAME_RELEASE"
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint"$UNAME_RELEASE"
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix"$UNAME_RELEASE"
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos"$UNAME_RELEASE"
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ then
+ if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+ [ "$TARGET_BINARY_INTERFACE"x = x ]
+ then
+ echo m88k-dg-dgux"$UNAME_RELEASE"
+ else
+ echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ fi
+ else
+ echo i586-dg-dgux"$UNAME_RELEASE"
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ case "$UNAME_MACHINE" in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "$sc_cpu_version" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "$sc_kernel_bits" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "$HP_ARCH" = "" ]; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ "$HP_ARCH" = hppa2.0w ]
+ then
+ eval "$set_cc_for_build"
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux"$HPUX_REV"
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo "$UNAME_MACHINE"-unknown-osf1mk
+ else
+ echo "$UNAME_MACHINE"-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:BSD/OS:*:*)
+ echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case "$UNAME_PROCESSOR" in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ i*:CYGWIN*:*)
+ echo "$UNAME_MACHINE"-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo "$UNAME_MACHINE"-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo "$UNAME_MACHINE"-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo "$UNAME_MACHINE"-pc-msys
+ exit ;;
+ i*:PW*:*)
+ echo "$UNAME_MACHINE"-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case "$UNAME_MACHINE" in
+ x86)
+ echo i586-pc-interix"$UNAME_RELEASE"
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ esac ;;
+ i*:UWIN*:*)
+ echo "$UNAME_MACHINE"-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+ exit ;;
+ i*86:Minix:*:*)
+ echo "$UNAME_MACHINE"-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arm*:Linux:*:*)
+ eval "$set_cc_for_build"
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ else
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ cris:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ crisv32:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ e2k:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ frv:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ hexagon:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:Linux:*:*)
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ exit ;;
+ ia64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m32r*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m68*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
+ test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-"$LIBC"
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-"$LIBC"
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-"$LIBC"
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+ PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+ *) echo hppa-unknown-linux-"$LIBC" ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-"$LIBC"
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-"$LIBC"
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-"$LIBC"
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-"$LIBC"
+ exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
+ exit ;;
+ sh64*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sh*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ tile*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ vax:Linux:*:*)
+ echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
+ exit ;;
+ x86_64:Linux:*:*)
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo "$UNAME_MACHINE"-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo "$UNAME_MACHINE"-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo "$UNAME_MACHINE"-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo "$UNAME_MACHINE"-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ i*86:*DOS:*:*)
+ echo "$UNAME_MACHINE"-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:*)
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv"$UNAME_RELEASE"
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo "$UNAME_MACHINE"-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo "$UNAME_MACHINE"-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux"$UNAME_RELEASE"
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv"$UNAME_RELEASE"
+ else
+ echo mips-unknown-sysv"$UNAME_RELEASE"
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Rhapsody:*:*)
+ echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval "$set_cc_for_build"
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSV-*:NONSTOP_KERNEL:*:*)
+ echo nsv-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = 386; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo "$UNAME_MACHINE"-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux"$UNAME_RELEASE"
+ exit ;;
+ *:DragonFly:*:*)
+ echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "$UNAME_MACHINE" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+ exit ;;
+ i*86:rdos:*:*)
+ echo "$UNAME_MACHINE"-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo "$UNAME_MACHINE"-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo "$UNAME_MACHINE"-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
+esac
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.sub b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.sub
new file mode 100755
index 000000000..9ccf09a7a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/config.sub
@@ -0,0 +1,1801 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-03-08'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo "$1"
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo "$1" | sed 's/-[^-]*$//'`
+ if [ "$basic_machine" != "$1" ]
+ then os=`echo "$1" | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | ba \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | visium \
+ | wasm32 \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ leon|leon[3-9])
+ basic_machine=sparc-$basic_machine
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | ba-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | e2k-* | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
+ | pyramid-* \
+ | riscv32-* | riscv64-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | visium-* \
+ | wasm32-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-pc
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2*)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ e500v[12])
+ basic_machine=powerpc-unknown
+ os=$os"spe"
+ ;;
+ e500v[12]-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=$os"spe"
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ leon-*|leon[3-9]-*)
+ basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next)
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ nsv-tandem)
+ basic_machine=nsv-tandem
+ ;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ x64)
+ basic_machine=x86_64-pc
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # es1800 is here to avoid being matched by es* (a different OS)
+ -es1800*)
+ os=-ose
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \
+ | -midnightbsd*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -xray | -os68k* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2)
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $basic_machine in
+ arm*)
+ os=-eabi
+ ;;
+ *)
+ os=-elf
+ ;;
+ esac
+ ;;
+ -nacl*)
+ ;;
+ -ios)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ pru-*)
+ os=-elf
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next)
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo "$basic_machine$os"
+exit
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/configure.ac b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/configure.ac
new file mode 100644
index 000000000..ae46876a2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/configure.ac
@@ -0,0 +1,68 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(onig, 6.9.4)
+
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE([-Wno-portability])
+AC_CONFIG_HEADERS([src/config.h])
+
+
+dnl default value for STATISTICS
+STATISTICS=""
+AC_ARG_WITH([statistics],
+ [AS_HELP_STRING([--with-statistics],
+ [take matching time statistical data])],
+ [STATISTICS=-DONIG_DEBUG_STATISTICS])
+AC_SUBST(STATISTICS)
+
+
+dnl check for POSIX API
+AC_ARG_ENABLE([posix-api],
+ [AS_HELP_STRING([--enable-posix-api],
+ [turn on to include POSIX API [default=yes]])],
+[\
+case "${enableval}" in
+ yes) enable_posix_api=yes ;;
+ no) enable_posix_api=no ;;
+ *) AC_MSG_ERROR(bad value for --enable-posix-api) ;;
+esac],
+enable_posix_api=yes)
+AM_CONDITIONAL(ENABLE_POSIX_API, test x"${enable_posix_api}" = xyes)
+
+
+dnl check for CRNL_AS_LINE_TERMINATOR
+AC_ARG_ENABLE([crnl-as-line-terminator],
+ [AS_HELP_STRING([--enable-crnl-as-line-terminator],
+ [deprecated])],
+ [crnl_as_line_terminator=$enableval])
+if test "${crnl_as_line_terminator}" = yes; then
+ AC_DEFINE(USE_CRNL_AS_LINE_TERMINATOR,1,[Define if enable CR+NL as line terminator])
+fi
+
+
+dnl Checks for programs.
+AC_PROG_CC
+LT_INIT
+LTVERSION="5:0:0"
+AC_SUBST(LTVERSION)
+
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_CHECK_HEADERS(sys/time.h unistd.h sys/times.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_CHECK_SIZEOF([int])
+AC_CHECK_SIZEOF([long])
+AC_CHECK_SIZEOF([long long])
+AC_CHECK_SIZEOF([void*])
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+
+AC_CONFIG_FILES([Makefile src/Makefile test/Makefile sample/Makefile onig-config])
+AC_CONFIG_COMMANDS([default],[chmod +x onig-config],[])
+AC_OUTPUT
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/depcomp b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/depcomp
new file mode 100755
index 000000000..65cbf7093
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API
new file mode 100644
index 000000000..5795e1327
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API
@@ -0,0 +1,982 @@
+Oniguruma API Version 6.9.5 2020/02/19
+
+#include <oniguruma.h>
+
+
+# int onig_initialize(OnigEncoding use_encodings[], int num_encodings)
+
+ Initialize library.
+
+ You have to call it explicitly.
+
+ * onig_init() is deprecated.
+
+ arguments
+ 1 use_encodings: array of encodings used in application.
+ 2 num_encodings: number of encodings.
+
+
+# int onig_error_code_to_str(UChar* err_buf, int err_code, ...)
+
+ Get error message string.
+ If this function is used for onig_new(),
+ don't call this after the pattern argument of onig_new() is freed.
+
+ normal return: error message string length
+
+ arguments
+ 1 err_buf: error message string buffer.
+ (required size: ONIG_MAX_ERROR_MESSAGE_LEN)
+ 2 err_code: error code returned by other API functions.
+ 3 err_info (optional): error info returned by onig_new().
+
+
+# void onig_set_warn_func(OnigWarnFunc func)
+
+ Set warning function.
+
+ WARNING:
+ '[', '-', ']' in character class without escape.
+ ']' in pattern without escape.
+
+ arguments
+ 1 func: function pointer. void (*func)(char* warning_message)
+
+
+# void onig_set_verb_warn_func(OnigWarnFunc func)
+
+ Set verbose warning function.
+
+ WARNING:
+ redundant nested repeat operator.
+
+ arguments
+ 1 func: function pointer. void (*func)(char* warning_message)
+
+
+# int onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax,
+ OnigErrorInfo* err_info)
+
+ Create a regex object.
+
+ normal return: ONIG_NORMAL
+
+ arguments
+ 1 reg: return regex object's address.
+ 2 pattern: regex pattern string.
+ 3 pattern_end: terminate address of pattern. (pattern + pattern length)
+ 4 option: compile time options.
+
+ ONIG_OPTION_NONE no option
+ ONIG_OPTION_SINGLELINE '^' -> '\A', '$' -> '\Z'
+ ONIG_OPTION_MULTILINE '.' match with newline
+ ONIG_OPTION_IGNORECASE ambiguity match on
+ ONIG_OPTION_EXTEND extended pattern form
+ ONIG_OPTION_FIND_LONGEST find longest match
+ ONIG_OPTION_FIND_NOT_EMPTY ignore empty match
+ ONIG_OPTION_NEGATE_SINGLELINE
+ clear ONIG_OPTION_SINGLELINE which is enabled on
+ ONIG_SYNTAX_POSIX_BASIC, ONIG_SYNTAX_POSIX_EXTENDED,
+ ONIG_SYNTAX_PERL, ONIG_SYNTAX_PERL_NG, ONIG_SYNTAX_JAVA
+
+ ONIG_OPTION_DONT_CAPTURE_GROUP only named group captured.
+ ONIG_OPTION_CAPTURE_GROUP named and no-named group captured.
+
+ ONIG_OPTION_WORD_IS_ASCII ASCII only word (\w, \p{Word}, [[:word:]])
+ ASCII only word bound (\b)
+ ONIG_OPTION_DIGIT_IS_ASCII ASCII only digit (\d, \p{Digit}, [[:digit:]])
+ ONIG_OPTION_SPACE_IS_ASCII ASCII only space (\s, \p{Space}, [[:space:]])
+ ONIG_OPTION_POSIX_IS_ASCII ASCII only POSIX properties
+ (includes word, digit, space)
+ (alnum, alpha, blank, cntrl, digit, graph,
+ lower, print, punct, space, upper, xdigit,
+ word)
+ ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER Extended Grapheme Cluster mode
+ ONIG_OPTION_TEXT_SEGMENT_WORD Word mode
+
+ 5 enc: character encoding.
+
+ ONIG_ENCODING_ASCII ASCII
+ ONIG_ENCODING_ISO_8859_1 ISO 8859-1
+ ONIG_ENCODING_ISO_8859_2 ISO 8859-2
+ ONIG_ENCODING_ISO_8859_3 ISO 8859-3
+ ONIG_ENCODING_ISO_8859_4 ISO 8859-4
+ ONIG_ENCODING_ISO_8859_5 ISO 8859-5
+ ONIG_ENCODING_ISO_8859_6 ISO 8859-6
+ ONIG_ENCODING_ISO_8859_7 ISO 8859-7
+ ONIG_ENCODING_ISO_8859_8 ISO 8859-8
+ ONIG_ENCODING_ISO_8859_9 ISO 8859-9
+ ONIG_ENCODING_ISO_8859_10 ISO 8859-10
+ ONIG_ENCODING_ISO_8859_11 ISO 8859-11
+ ONIG_ENCODING_ISO_8859_13 ISO 8859-13
+ ONIG_ENCODING_ISO_8859_14 ISO 8859-14
+ ONIG_ENCODING_ISO_8859_15 ISO 8859-15
+ ONIG_ENCODING_ISO_8859_16 ISO 8859-16
+ ONIG_ENCODING_UTF8 UTF-8
+ ONIG_ENCODING_UTF16_BE UTF-16BE
+ ONIG_ENCODING_UTF16_LE UTF-16LE
+ ONIG_ENCODING_UTF32_BE UTF-32BE
+ ONIG_ENCODING_UTF32_LE UTF-32LE
+ ONIG_ENCODING_EUC_JP EUC-JP
+ ONIG_ENCODING_EUC_TW EUC-TW
+ ONIG_ENCODING_EUC_KR EUC-KR
+ ONIG_ENCODING_EUC_CN EUC-CN
+ ONIG_ENCODING_SJIS Shift_JIS
+ ONIG_ENCODING_KOI8_R KOI8-R
+ ONIG_ENCODING_CP1251 CP1251
+ ONIG_ENCODING_BIG5 Big5
+ ONIG_ENCODING_GB18030 GB18030
+
+ or any OnigEncodingType data address defined by user.
+
+ 6 syntax: address of pattern syntax definition.
+
+ ONIG_SYNTAX_ASIS plain text
+ ONIG_SYNTAX_POSIX_BASIC POSIX Basic RE
+ ONIG_SYNTAX_POSIX_EXTENDED POSIX Extended RE
+ ONIG_SYNTAX_EMACS Emacs
+ ONIG_SYNTAX_GREP grep
+ ONIG_SYNTAX_GNU_REGEX GNU regex
+ ONIG_SYNTAX_JAVA Java (Sun java.util.regex)
+ ONIG_SYNTAX_PERL Perl
+ ONIG_SYNTAX_PERL_NG Perl + named group
+ ONIG_SYNTAX_RUBY Ruby
+ ONIG_SYNTAX_ONIGURUMA Oniguruma
+ ONIG_SYNTAX_DEFAULT default (== ONIG_SYNTAX_ONIGURUMA)
+ onig_set_default_syntax()
+
+ or any OnigSyntaxType data address defined by user.
+
+ 7 err_info: address for return optional error info.
+ Use this value as 3rd argument of onig_error_code_to_str().
+
+
+
+# int onig_new_without_alloc(regex_t* reg, const UChar* pattern,
+ const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax,
+ OnigErrorInfo* err_info)
+
+ Create a regex object.
+ reg object area is not allocated in this function.
+
+ normal return: ONIG_NORMAL
+
+
+
+# int onig_new_deluxe(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigCompileInfo* ci, OnigErrorInfo* einfo)
+
+ This function is deprecated, and it does not allow the case where
+ the encoding of pattern and target is different.
+
+ Create a regex object.
+ This function is deluxe version of onig_new().
+
+ normal return: ONIG_NORMAL
+
+ arguments
+ 1 reg: return address of regex object.
+ 2 pattern: regex pattern string.
+ 3 pattern_end: terminate address of pattern. (pattern + pattern length)
+ 4 ci: compile time info.
+
+ ci->num_of_elements: number of elements in ci. (current version: 5)
+ ci->pattern_enc: pattern string character encoding.
+ ci->target_enc: target string character encoding.
+ ci->syntax: address of pattern syntax definition.
+ ci->option: compile time option.
+ ci->case_fold_flag: character matching case fold bit flag for
+ ONIG_OPTION_IGNORECASE mode.
+
+ ONIGENC_CASE_FOLD_MIN: minimum
+ ONIGENC_CASE_FOLD_DEFAULT: minimum
+ onig_set_default_case_fold_flag()
+
+ 5 err_info: address for return optional error info.
+ Use this value as 3rd argument of onig_error_code_to_str().
+
+
+ Different character encoding combination is allowed for
+ the following cases only.
+
+ pattern_enc: ASCII, ISO_8859_1
+ target_enc: UTF16_BE, UTF16_LE, UTF32_BE, UTF32_LE
+
+ pattern_enc: UTF16_BE/LE
+ target_enc: UTF16_LE/BE
+
+ pattern_enc: UTF32_BE/LE
+ target_enc: UTF32_LE/BE
+
+
+# void onig_free(regex_t* reg)
+
+ Free memory used by regex object.
+
+ arguments
+ 1 reg: regex object.
+
+
+# void onig_free_body(regex_t* reg)
+
+ Free memory used by regex object. (Except reg oneself.)
+
+ arguments
+ 1 reg: regex object.
+
+
+# OnigMatchParam* onig_new_match_param()
+
+ Allocate a OnigMatchParam object and initialize the contents by
+ onig_initialize_match_param().
+
+
+# void onig_free_match_param(OnigMatchParam* mp)
+
+ Free memory used by a OnigMatchParam object.
+
+ arguments
+ 1 mp: OnigMatchParam object
+
+
+# void onig_initialize_match_param(OnigMatchParam* mp)
+
+ Set match-param fields to default values.
+ Match-param is used in onig_match_with_param() and onig_search_with_param().
+
+ arguments
+ 1 mp: match-param pointer
+
+
+# int onig_set_match_stack_limit_size_of_match_param(OnigMatchParam* mp, unsigned int limit)
+
+ Set a maximum number of match-stack depth.
+ 0 means unlimited.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 limit: number of limit
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_match_of_match_param(OnigMatchParam* mp, unsigned long limit)
+
+ Set a retry limit count of a match process.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 limit: number of limit
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_search_of_match_param(OnigMatchParam* mp, unsigned long limit)
+
+ Set a retry limit count of a search process.
+ 0 means unlimited.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 limit: number of limit
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_progress_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ Set a function for callouts of contents in progress.
+ If 0 (NULL) is set, never called in progress.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 f: function
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_retraction_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ Set a function for callouts of contents in retraction (backtrack).
+ If 0 (NULL) is set, never called in retraction.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 f: function
+
+ normal return: ONIG_NORMAL
+
+
+
+# int onig_search(regex_t* reg, const UChar* str, const UChar* end, const UChar* start,
+ const UChar* range, OnigRegion* region, OnigOptionType option)
+
+ Search string and return search result and matching region.
+ Do not pass invalid byte string in the regex character encoding.
+
+ normal return: match position offset (i.e. p - str >= 0)
+ not found: ONIG_MISMATCH (< 0)
+ error: error code (< 0)
+
+ arguments
+ 1 reg: regex object
+ 2 str: target string
+ 3 end: terminate address of target string
+ 4 start: search start address of target string
+ 5 range: search terminate address of target string
+ in forward search (start <= searched string < range)
+ in backward search (range <= searched string <= start)
+ 6 region: address for return group match range info (NULL is allowed)
+ 7 option: search time option
+
+ ONIG_OPTION_NOTBOL string head(str) isn't considered as begin of line
+ ONIG_OPTION_NOTEOL string end (end) isn't considered as end of line
+ ONIG_OPTION_POSIX_REGION region argument is regmatch_t[] of POSIX API.
+
+
+# int onig_search_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+
+ Search string and return search result and matching region.
+ Do not pass invalid byte string in the regex character encoding.
+
+ arguments
+ 1-7: same as onig_search()
+ 8 mp: match parameter values (match_stack_limit, retry_limit_in_match, retry_limit_in_search)
+
+
+# int onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at,
+ OnigRegion* region, OnigOptionType option)
+
+ Match string and return result and matching region.
+ Do not pass invalid byte string in the regex character encoding.
+
+ normal return: match length (>= 0)
+ not match: ONIG_MISMATCH (< 0)
+ error: error code (< 0)
+
+ arguments
+ 1 reg: regex object
+ 2 str: target string
+ 3 end: terminate address of target string
+ 4 at: match address of target string
+ 5 region: address for return group match range info (NULL is allowed)
+ 6 option: search time option
+
+ ONIG_OPTION_NOTBOL string head(str) isn't considered as begin of line
+ ONIG_OPTION_NOTEOL string end (end) isn't considered as end of line
+ ONIG_OPTION_POSIX_REGION region argument is regmatch_t[] type of POSIX API.
+
+
+# int onig_match_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* at, OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+
+ Match string and return result and matching region.
+ Do not pass invalid byte string in the regex character encoding.
+
+ arguments
+ 1-6: same as onig_match()
+ 7 mp: match parameter values (match_stack_limit, retry_limit_in_match, retry_limit_in_search)
+
+
+# int onig_scan(regex_t* reg, const UChar* str, const UChar* end,
+ OnigRegion* region, OnigOptionType option,
+ int (*scan_callback)(int, int, OnigRegion*, void*),
+ void* callback_arg)
+
+ Scan string and callback with matching region.
+ Do not pass invalid byte string in the regex character encoding.
+
+ normal return: number of matching times
+ error: error code
+ interruption: return value of callback function (!= 0)
+
+ arguments
+ 1 reg: regex object
+ 2 str: target string
+ 3 end: terminate address of target string
+ 4 region: address for return group match range info (NULL is allowed)
+ 5 option: search time option
+ 6 scan_callback: callback function (defined by user)
+ 7 callback_arg: optional argument passed to callback
+
+
+# int onig_regset_new(OnigRegSet** rset, int n, regex_t* regs[])
+
+ Create a regset object.
+ All regex objects must have the same character encoding.
+ All regex objects are prohibited from having the ONIG_OPTION_FIND_LONGEST option.
+
+ arguments
+ 1 rset: return address of regset object
+ 2 n: number of regex in regs
+ 3 regs: array of regex
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_regset_add(OnigRegSet* set, regex_t* reg)
+
+ Add a regex into regset.
+ The regex object must have the same character encoding with the regset.
+ The regex object is prohibited from having the ONIG_OPTION_FIND_LONGEST option.
+
+ arguments
+ 1 set: regset object
+ 2 reg: regex object
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_regset_replace(OnigRegSet* set, int at, regex_t* reg)
+
+ Replace a regex in regset with another one.
+ If the reg argument value is NULL, then remove at-th regex. (and indexes of other regexes are changed)
+
+ arguments
+ 1 set: regset object
+ 2 at: index of regex (zero origin)
+ 3 reg: regex object
+
+ normal return: ONIG_NORMAL
+
+
+# void onig_regset_free(OnigRegSet* set)
+
+ Free memory used by regset object and regex objects in the regset.
+ If the same regex object is registered twice, the situation becomes destructive.
+
+ arguments
+ 1 set: regset object
+
+
+# int onig_regset_number_of_regex(OnigRegSet* set)
+
+ Returns number of regex objects in the regset.
+
+ arguments
+ 1 set: regset object
+
+
+# regex_t* onig_regset_get_regex(OnigRegSet* set, int at)
+
+ Returns the regex object corresponding to the at-th regex.
+
+ arguments
+ 1 set: regset object
+ 2 at: index of regex array (zero origin)
+
+
+# OnigRegion* onig_regset_get_region(OnigRegSet* set, int at)
+
+ Returns the region object corresponding to the at-th regex.
+
+ arguments
+ 1 set: regset object
+ 2 at: index of regex array (zero origin)
+
+
+# int onig_regset_search(OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, int* rmatch_pos)
+
+ Perform a search with regset.
+
+ return value:
+ normal return: index of match regex (zero origin)
+ not found: ONIG_MISMATCH (< 0)
+ error: error code (< 0)
+
+ arguments
+ 1 set: regset object
+ 2 str: target string
+ 3 end: terminate address of target string
+ 4 start: search start address of target string
+ 5 range: search terminate address of target string
+ 6 lead: outer loop element
+ ONIG_REGSET_POSITION_LEAD (returns most left position)
+ ONIG_REGSET_REGEX_LEAD (returns most left position)
+ ONIG_REGSET_PRIORITY_TO_REGEX_ORDER (returns first match regex)
+ 7 option: search time option
+ ONIG_OPTION_NOTBOL string head(str) isn't considered as begin of line
+ ONIG_OPTION_NOTEOL string end (end) isn't considered as end of line
+ 8 rmatch_pos: return address of match position (match_address - str)
+
+ * ONIG_REGSET_POSITION_LEAD and ONIG_REGSET_REGEX_LEAD return the same result.
+ These differences only appear in search time.
+ In most cases, ONIG_REGSET_POSITION_LEAD seems to be faster.
+
+
+# int onig_regset_search_with_param(OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, OnigMatchParam* mps[], int* rmatch_pos)
+
+ Perform a search with regset and match-params.
+
+ return value:
+ normal return: index of match regex (zero origin)
+ not found: ONIG_MISMATCH (< 0)
+ error: error code (< 0)
+
+ arguments
+ 1 set: regset object
+ 2 str: target string
+ 3 end: terminate address of target string
+ 4 start: search start address of target string
+ 5 range: search terminate address of target string
+ 6 lead: outer loop element
+ ONIG_REGSET_POSITION_LEAD (returns most left position)
+ ONIG_REGSET_REGEX_LEAD (returns most left position)
+ ONIG_REGSET_PRIORITY_TO_REGEX_ORDER (returns first match regex)
+ 7 option: search time option
+ ONIG_OPTION_NOTBOL string head(str) isn't considered as begin of line
+ ONIG_OPTION_NOTEOL string end (end) isn't considered as end of line
+ 8 mps: array of match-params
+ 9 rmatch_pos: return address of match position (match_address - str)
+
+
+# OnigRegion* onig_region_new(void)
+
+ Create a region.
+
+
+# void onig_region_free(OnigRegion* region, int free_self)
+
+ Free memory used by region.
+
+ arguments
+ 1 region: target region
+ 2 free_self: [1: free all, 0: free memory used in region but not self]
+
+
+# void onig_region_copy(OnigRegion* to, OnigRegion* from)
+
+ Copy contents of region.
+
+ arguments
+ 1 to: target region
+ 2 from: source region
+
+
+# void onig_region_clear(OnigRegion* region)
+
+ Clear contents of region.
+
+ arguments
+ 1 region: target region
+
+
+# int onig_region_resize(OnigRegion* region, int n)
+
+ Resize group range area of region.
+
+ normal return: ONIG_NORMAL
+
+ arguments
+ 1 region: target region
+ 2 n: new size
+
+
+# int onig_name_to_group_numbers(regex_t* reg, const UChar* name, const UChar* name_end,
+ int** num_list)
+
+ Return the group number list of the name.
+ Named subexp is defined by (?<name>....).
+
+ normal return: number of groups for the name.
+ (ex. /(?<x>..)(?<x>..)/ ==> 2)
+ name not found: -1
+
+ arguments
+ 1 reg: regex object.
+ 2 name: group name.
+ 3 name_end: terminate address of group name.
+ 4 num_list: return list of group number.
+
+
+# int onig_name_to_backref_number(regex_t* reg, const UChar* name, const UChar* name_end,
+ OnigRegion *region)
+
+ Return the group number corresponding to the named backref (\k<name>).
+ If two or more regions for the groups of the name are effective,
+ the greatest number in it is obtained.
+
+ normal return: group number.
+
+ arguments
+ 1 reg: regex object.
+ 2 name: group name.
+ 3 name_end: terminate address of group name.
+ 4 region: search/match result region.
+
+
+# int onig_foreach_name(regex_t* reg,
+ int (*func)(const UChar*, const UChar*, int,int*,regex_t*,void*),
+ void* arg)
+
+ Iterate function call for all names.
+
+ normal return: 0
+ error: func's return value.
+
+ arguments
+ 1 reg: regex object.
+ 2 func: callback function.
+ func(name, name_end, <number of groups>, <group number's list>,
+ reg, arg);
+ if func does not return 0, then iteration is stopped.
+ 3 arg: argument for func.
+
+
+# int onig_number_of_names(regex_t* reg)
+
+ Return the number of names defined in the pattern.
+ Multiple definitions of one name is counted as one.
+
+ arguments
+ 1 reg: regex object.
+
+
+# OnigEncoding onig_get_encoding(regex_t* reg)
+# OnigOptionType onig_get_options(regex_t* reg)
+# OnigCaseFoldType onig_get_case_fold_flag(regex_t* reg)
+# OnigSyntaxType* onig_get_syntax(regex_t* reg)
+
+ Return a value of the regex object.
+
+ arguments
+ 1 reg: regex object.
+
+
+# int onig_number_of_captures(regex_t* reg)
+
+ Return the number of capture group in the pattern.
+
+ arguments
+ 1 reg: regex object.
+
+
+# int onig_number_of_capture_histories(regex_t* reg)
+
+ Return the number of capture history defined in the pattern.
+
+ You can't use capture history if ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY
+ is disabled in the pattern syntax.(disabled in the default syntax)
+
+ arguments
+ 1 reg: regex object.
+
+
+
+# OnigCaptureTreeNode* onig_get_capture_tree(OnigRegion* region)
+
+ Return the root node of capture history data tree.
+
+ This value is undefined if matching has faild.
+
+ arguments
+ 1 region: matching result.
+
+
+# int onig_capture_tree_traverse(OnigRegion* region, int at,
+ int(*func)(int,int,int,int,int,void*), void* arg)
+
+ Traverse and callback in capture history data tree.
+
+ normal return: 0
+ error: callback func's return value.
+
+ arguments
+ 1 region: match region data.
+ 2 at: callback position.
+
+ ONIG_TRAVERSE_CALLBACK_AT_FIRST: callback first, then traverse children.
+ ONIG_TRAVERSE_CALLBACK_AT_LAST: traverse children first, then callback.
+ ONIG_TRAVERSE_CALLBACK_AT_BOTH: callback first, then traverse children,
+ and at last callback again.
+
+ 3 func: callback function.
+ if func does not return 0, then traverse is stopped.
+
+ int func(int group, int beg, int end, int level, int at,
+ void* arg)
+
+ group: group number
+ beg: capture start position
+ end: capture end position
+ level: nest level (from 0)
+ at: callback position
+ ONIG_TRAVERSE_CALLBACK_AT_FIRST
+ ONIG_TRAVERSE_CALLBACK_AT_LAST
+ arg: optional callback argument
+
+ 4 arg; optional callback argument.
+
+
+# int onig_noname_group_capture_is_active(regex_t* reg)
+
+ Return noname group capture activity.
+
+ active: 1
+ inactive: 0
+
+ arguments
+ 1 reg: regex object.
+
+ if option ONIG_OPTION_DONT_CAPTURE_GROUP == ON
+ --> inactive
+
+ if the regex pattern have named group
+ and syntax ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP == ON
+ and option ONIG_OPTION_CAPTURE_GROUP == OFF
+ --> inactive
+
+ else --> active
+
+
+# UChar* onigenc_get_prev_char_head(OnigEncoding enc, const UChar* start, const UChar* s)
+
+ Return previous character head address.
+
+ arguments
+ 1 enc: character encoding
+ 2 start: string address
+ 3 s: target address of string
+
+
+# UChar* onigenc_get_left_adjust_char_head(OnigEncoding enc,
+ const UChar* start, const UChar* s)
+
+ Return left-adjusted head address of a character.
+
+ arguments
+ 1 enc: character encoding
+ 2 start: string address
+ 3 s: target address of string
+
+
+# UChar* onigenc_get_right_adjust_char_head(OnigEncoding enc,
+ const UChar* start, const UChar* s)
+
+ Return right-adjusted head address of a character.
+
+ arguments
+ 1 enc: character encoding
+ 2 start: string address
+ 3 s: target address of string
+
+
+# int onigenc_strlen(OnigEncoding enc, const UChar* s, const UChar* end)
+
+ Return number of characters in the string.
+
+
+# int onigenc_strlen_null(OnigEncoding enc, const UChar* s)
+
+ Return number of characters in the string.
+ Do not pass invalid byte string in the character encoding.
+
+
+# int onigenc_str_bytelen_null(OnigEncoding enc, const UChar* s)
+
+ Return number of bytes in the string.
+ Do not pass invalid byte string in the character encoding.
+
+
+# int onig_set_default_syntax(OnigSyntaxType* syntax)
+
+ Set default syntax.
+
+ arguments
+ 1 syntax: address of pattern syntax definition.
+
+
+# void onig_copy_syntax(OnigSyntaxType* to, OnigSyntaxType* from)
+
+ Copy syntax.
+
+ arguments
+ 1 to: destination address.
+ 2 from: source address.
+
+
+# unsigned int onig_get_syntax_op(OnigSyntaxType* syntax)
+# unsigned int onig_get_syntax_op2(OnigSyntaxType* syntax)
+# unsigned int onig_get_syntax_behavior(OnigSyntaxType* syntax)
+# OnigOptionType onig_get_syntax_options(OnigSyntaxType* syntax)
+
+# void onig_set_syntax_op(OnigSyntaxType* syntax, unsigned int op)
+# void onig_set_syntax_op2(OnigSyntaxType* syntax, unsigned int op2)
+# void onig_set_syntax_behavior(OnigSyntaxType* syntax, unsigned int behavior)
+# void onig_set_syntax_options(OnigSyntaxType* syntax, OnigOptionType options)
+
+ Get/Set elements of the syntax.
+
+ arguments
+ 1 syntax: syntax
+ 2 op, op2, behavior, options: value of element.
+
+
+# void onig_copy_encoding(OnigEncoding to, OnigEncoding from)
+
+ Copy encoding.
+
+ arguments
+ 1 to: destination address.
+ 2 from: source address.
+
+
+# int onig_set_meta_char(OnigSyntaxType* syntax, unsigned int what,
+ OnigCodePoint code)
+
+ Set a variable meta character to the code point value.
+ Except for an escape character, this meta characters specification
+ is not work, if ONIG_SYN_OP_VARIABLE_META_CHARACTERS is not effective
+ by the syntax. (Build-in syntaxes are not effective.)
+
+ normal return: ONIG_NORMAL
+
+ arguments
+ 1 syntax: target syntax
+ 2 what: specifies which meta character it is.
+
+ ONIG_META_CHAR_ESCAPE
+ ONIG_META_CHAR_ANYCHAR
+ ONIG_META_CHAR_ANYTIME
+ ONIG_META_CHAR_ZERO_OR_ONE_TIME
+ ONIG_META_CHAR_ONE_OR_MORE_TIME
+ ONIG_META_CHAR_ANYCHAR_ANYTIME
+
+ 3 code: meta character or ONIG_INEFFECTIVE_META_CHAR.
+
+
+# OnigCaseFoldType onig_get_default_case_fold_flag()
+
+ Get default case fold flag.
+
+
+# int onig_set_default_case_fold_flag(OnigCaseFoldType case_fold_flag)
+
+ Set default case fold flag.
+
+ 1 case_fold_flag: case fold flag
+
+
+# unsigned int onig_get_match_stack_limit_size(void)
+
+ Return the maximum number of stack size.
+ (default: 0 == unlimited)
+
+
+# int onig_set_match_stack_limit_size(unsigned int size)
+
+ Set the maximum number of stack size.
+ (size = 0: unlimited)
+
+ normal return: ONIG_NORMAL
+
+
+# unsigned long onig_get_retry_limit_in_match(void)
+
+ Return the limit of retry counts in a matching process.
+ (default: 10000000)
+
+ normal return: current limit value
+
+
+# unsigned long onig_get_retry_limit_in_search(void)
+
+ Return the limit of retry counts in a search process.
+ 0 means unlimited.
+ (default: 0)
+
+ normal return: current limit value
+
+
+# int onig_set_retry_limit_in_match(unsigned long limit)
+
+ Set the limit of retry counts in matching process.
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_search(unsigned long limit)
+
+ Set a retry limit count of a search process.
+ 0 means unlimited.
+
+ normal return: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_progress_callout(void)
+
+ Get a function for callouts of contents in progress.
+
+
+# int onig_set_progress_callout(OnigCalloutFunc f)
+
+ Set a function for callouts of contents in progress.
+ If 0 (NULL) is set, never called in progress.
+
+ normal return: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_retraction_callout(void)
+
+ Get a function for callouts of contents in retraction (backtrack).
+
+
+# int onig_set_retraction_callout(OnigCalloutFunc f)
+
+ Set a function for callouts of contents in retraction (backtrack).
+ If 0 (NULL) is set, never called in retraction.
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_unicode_define_user_property(const char* name, OnigCodePoint* ranges))
+
+ Define new Unicode property.
+ (This function is not thread safe.)
+
+ arguments
+ 1 name: property name (ASCII only. character ' ', '-', '_' are ignored.)
+ 2 ranges: property code point ranges
+ (first element is number of ranges.)
+
+ [num-of-ranges, 1st-range-start, 1st-range-end, 2nd-range-start... ]
+
+ * Don't destroy the ranges after having called this function.
+
+ normal return: ONIG_NORMAL
+
+
+# unsigned int onig_get_parse_depth_limit(void)
+
+ Return the maximum depth of parser recursion.
+ (default: DEFAULT_PARSE_DEPTH_LIMIT defined in regint.h. Currently 4096.)
+
+
+# int onig_set_parse_depth_limit(unsigned int depth)
+
+ Set the maximum depth of parser recursion.
+ (depth = 0: Set to the default value defined in regint.h.)
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_end(void)
+
+ The use of this library is finished.
+
+ normal return: ONIG_NORMAL
+
+ It is not allowed to use regex objects which created
+ before onig_end() call.
+
+
+# const char* onig_version(void)
+
+ Return version string. (ex. "5.0.3")
+
+// END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API.ja b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API.ja
new file mode 100644
index 000000000..044d1256e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/API.ja
@@ -0,0 +1,989 @@
+鬼車インターフェース Version 6.9.5 2020/02/19
+
+#include <oniguruma.h>
+
+
+# int onig_initialize(OnigEncoding use_encodings[], int num_encodings)
+
+ ライブラリã®åˆæœŸåŒ–
+ 最åˆã«å‘¼ã³å‡ºã™å¿…è¦ãŒã‚る。
+
+ * onig_init() ã¯å»ƒæ­¢
+
+ 引数
+ 1 use_encodings: 使用ã™ã‚‹æ–‡å­—エンコーディングã®é…列
+ 2 num_encodings: 文字エンコーディングã®æ•°
+
+
+# int onig_error_code_to_str(UChar* err_buf, int err_code, ...)
+
+ エラーメッセージをå–å¾—ã™ã‚‹ã€‚
+
+ ã“ã®é–¢æ•°ã‚’ã€onig_new()ã®çµæžœã«å¯¾ã—ã¦å‘¼ã³å‡ºã™å ´åˆã«ã¯ã€onig_new()ã®pattern引数を
+ メモリ解放ã™ã‚‹ã‚ˆã‚Šã‚‚å‰ã«å‘¼ã³å‡ºã•ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+
+ 正常終了戻り値: エラーメッセージ文字列ã®ãƒã‚¤ãƒˆé•·
+
+ 引数
+ 1 err_buf: エラーメッセージを格ç´ã™ã‚‹é ˜åŸŸ
+ (å¿…è¦ãªã‚µã‚¤ã‚º: ONIG_MAX_ERROR_MESSAGE_LEN)
+ 2 err_code: エラーコード
+ 3 err_info (optional): onig_new()ã®err_info
+
+
+# void onig_set_warn_func(OnigWarnFunc func)
+
+ 警告通知関数をセットã™ã‚‹ã€‚
+
+ 警告:
+ '[', '-', ']' in character class without escape.
+ ']' in pattern without escape.
+
+ 引数
+ 1 func: 警告関数 void (*func)(char* warning_message)
+
+
+# void onig_set_verb_warn_func(OnigWarnFunc func)
+
+ 詳細警告通知関数をセットã™ã‚‹ã€‚
+
+ 詳細警告:
+ redundant nested repeat operator.
+
+ 引数
+ 1 func: 詳細警告関数 void (*func)(char* warning_message)
+
+
+# int onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax,
+ OnigErrorInfo* err_info)
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト(regex)を作æˆã™ã‚‹ã€‚
+
+ 正常終了戻り値: ONIG_NORMAL
+
+ 引数
+ 1 reg: 作æˆã•ã‚ŒãŸæ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトを返ã™ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 2 pattern: æ­£è¦è¡¨ç¾ãƒ‘ターン文字列
+ 3 pattern_end: æ­£è¦è¡¨ç¾ãƒ‘ターン文字列ã®çµ‚端アドレス(pattern + pattern length)
+ 4 option: æ­£è¦è¡¨ç¾ã‚³ãƒ³ãƒ‘イル時オプション
+
+ ONIG_OPTION_NONE オプションãªã—
+ ONIG_OPTION_SINGLELINE '^' -> '\A', '$' -> '\Z'
+ ONIG_OPTION_MULTILINE '.'ãŒæ”¹è¡Œã«ãƒžãƒƒãƒã™ã‚‹
+ ONIG_OPTION_IGNORECASE 曖昧マッムオン
+ ONIG_OPTION_EXTEND パターン拡張形å¼
+ ONIG_OPTION_FIND_LONGEST 最長マッãƒ
+ ONIG_OPTION_FIND_NOT_EMPTY 空マッãƒã‚’無視
+ ONIG_OPTION_NEGATE_SINGLELINE
+ ONIG_SYNTAX_POSIX_BASIC, ONIG_SYNTAX_POSIX_EXTENDED,
+ ONIG_SYNTAX_PERL, ONIG_SYNTAX_PERL_NG, ONIG_SYNTAX_JAVAã§
+ デフォルトã§æœ‰åŠ¹ãªONIG_OPTION_SINGLELINEをクリアã™ã‚‹ã€‚
+
+ ONIG_OPTION_DONT_CAPTURE_GROUP åå‰ä»˜ãæ•ç²å¼é›†åˆã®ã¿æ•ç²
+ ONIG_OPTION_CAPTURE_GROUP åå‰ç„¡ã—æ•ç²å¼é›†åˆã‚‚æ•ç²
+ ONIG_OPTION_WORD_IS_ASCII wordãŒASCIIã®ã¿ (\w, \p{Word}, [[:word:]])
+ word boundãŒASCIIã®ã¿ (\b)
+ ONIG_OPTION_DIGIT_IS_ASCII digitãŒASCIIã®ã¿ (\d, \p{Digit}, [[:digit:]])
+ ONIG_OPTION_SPACE_IS_ASCII spaceãŒASCIIã®ã¿ (\s, \p{Space}, [[:space:]])
+ ONIG_OPTION_POSIX_IS_ASCII POSIXプロパティãŒASCIIã®ã¿
+ (word, digit, spaceã‚’å…¨ã¦å«ã‚“ã§ã„ã‚‹)
+ (alnum, alpha, blank, cntrl, digit, graph,
+ lower, print, punct, space, upper, xdigit,
+ word)
+ ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER 拡張書記素房モード
+ ONIG_OPTION_TEXT_SEGMENT_WORD å˜èªžãƒ¢ãƒ¼ãƒ‰
+
+ 5 enc: 文字エンコーディング
+
+ ONIG_ENCODING_ASCII ASCII
+ ONIG_ENCODING_ISO_8859_1 ISO 8859-1
+ ONIG_ENCODING_ISO_8859_2 ISO 8859-2
+ ONIG_ENCODING_ISO_8859_3 ISO 8859-3
+ ONIG_ENCODING_ISO_8859_4 ISO 8859-4
+ ONIG_ENCODING_ISO_8859_5 ISO 8859-5
+ ONIG_ENCODING_ISO_8859_6 ISO 8859-6
+ ONIG_ENCODING_ISO_8859_7 ISO 8859-7
+ ONIG_ENCODING_ISO_8859_8 ISO 8859-8
+ ONIG_ENCODING_ISO_8859_9 ISO 8859-9
+ ONIG_ENCODING_ISO_8859_10 ISO 8859-10
+ ONIG_ENCODING_ISO_8859_11 ISO 8859-11
+ ONIG_ENCODING_ISO_8859_13 ISO 8859-13
+ ONIG_ENCODING_ISO_8859_14 ISO 8859-14
+ ONIG_ENCODING_ISO_8859_15 ISO 8859-15
+ ONIG_ENCODING_ISO_8859_16 ISO 8859-16
+ ONIG_ENCODING_UTF8 UTF-8
+ ONIG_ENCODING_UTF16_BE UTF-16BE
+ ONIG_ENCODING_UTF16_LE UTF-16LE
+ ONIG_ENCODING_UTF32_BE UTF-32BE
+ ONIG_ENCODING_UTF32_LE UTF-32LE
+ ONIG_ENCODING_EUC_JP EUC-JP
+ ONIG_ENCODING_EUC_TW EUC-TW
+ ONIG_ENCODING_EUC_KR EUC-KR
+ ONIG_ENCODING_EUC_CN EUC-CN
+ ONIG_ENCODING_SJIS Shift_JIS
+ ONIG_ENCODING_KOI8_R KOI8-R
+ ONIG_ENCODING_CP1251 CP1251
+ ONIG_ENCODING_BIG5 Big5
+ ONIG_ENCODING_GB18030 GB18030
+
+ ã¾ãŸã¯ã€ãƒ¦ãƒ¼ã‚¶ãŒå®šç¾©ã—ãŸOnigEncodingTypeデータã®ã‚¢ãƒ‰ãƒ¬ã‚¹
+
+ 6 syntax: æ­£è¦è¡¨ç¾ãƒ‘ターン文法定義
+
+ ONIG_SYNTAX_ASIS plain text
+ ONIG_SYNTAX_POSIX_BASIC POSIX Basic RE
+ ONIG_SYNTAX_POSIX_EXTENDED POSIX Extended RE
+ ONIG_SYNTAX_EMACS Emacs
+ ONIG_SYNTAX_GREP grep
+ ONIG_SYNTAX_GNU_REGEX GNU regex
+ ONIG_SYNTAX_JAVA Java (Sun java.util.regex)
+ ONIG_SYNTAX_PERL Perl
+ ONIG_SYNTAX_PERL_NG Perl + åå‰ä»˜ãæ•ç²å¼é›†åˆ
+ ONIG_SYNTAX_RUBY Ruby
+ ONIG_SYNTAX_ONIGURUMA Oniguruma
+ ONIG_SYNTAX_DEFAULT default (== ONIG_SYNTAX_ONIGURUMA)
+ onig_set_default_syntax()
+
+ ã¾ãŸã¯ã€ãƒ¦ãƒ¼ã‚¶ãŒå®šç¾©ã—ãŸOnigSyntaxTypeデータã®ã‚¢ãƒ‰ãƒ¬ã‚¹
+
+ 7 err_info: エラー情報を返ã™ãŸã‚ã®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ onig_error_code_to_str()ã®ä¸‰ç•ªç›®ã®å¼•æ•°ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹
+
+
+
+# int onig_new_without_alloc(regex_t* reg, const UChar* pattern,
+ const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax,
+ OnigErrorInfo* err_info)
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト(regex)を作æˆã™ã‚‹ã€‚
+ regã®é ˜åŸŸã‚’内部ã§å‰²ã‚Šå½“ã¦ãªã„。
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+
+# int onig_new_deluxe(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigCompileInfo* ci, OnigErrorInfo* einfo)
+
+ ã“ã®é–¢æ•°ã¯å»ƒæ­¢äºˆå®šã€‚
+ パターンã¨å¯¾è±¡æ–‡å­—列ã®æ–‡å­—エンコーディングãŒç•°ãªã‚‹å ´åˆã‚’許ã•ãªããªã£ãŸã€‚
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト(regex)を作æˆã™ã‚‹ã€‚
+ ã“ã®é–¢æ•°ã¯ã€onig_new()ã®ãƒ‡ãƒ©ãƒƒã‚¯ã‚¹ç‰ˆã€‚
+
+ 正常終了戻り値: ONIG_NORMAL
+
+ 引数
+ 1 reg: 作æˆã•ã‚ŒãŸæ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトを返ã™ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 2 pattern: æ­£è¦è¡¨ç¾ãƒ‘ターン文字列
+ 3 pattern_end: æ­£è¦è¡¨ç¾ãƒ‘ターン文字列ã®çµ‚端アドレス(pattern + pattern length)
+ 4 ci: コンパイル情報
+
+ ci->num_of_elements: ciã®è¦ç´ æ•° (ç¾åœ¨ã®ç‰ˆã§ã¯: 5)
+ ci->pattern_enc: パターン文字列ã®æ–‡å­—エンコーディング
+ ci->target_enc: 対象文字列ã®æ–‡å­—エンコーディング
+ ci->syntax: æ­£è¦è¡¨ç¾ãƒ‘ターン文法定義
+ ci->option: æ­£è¦è¡¨ç¾ã‚³ãƒ³ãƒ‘イル時オプション
+ ci->case_fold_flag: ONIG_OPTION_IGNORECASEモードã§ã®
+ 文字曖昧マッãƒæŒ‡å®šãƒ“ットフラグ
+
+ ONIGENC_CASE_FOLD_MIN: 最å°
+ ONIGENC_CASE_FOLD_DEFAULT: 最å°
+ onig_set_default_case_fold_flag()
+
+ 5 err_info: エラー情報を返ã™ãŸã‚ã®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ onig_error_code_to_str()ã®ä¸‰ç•ªç›®ã®å¼•æ•°ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹
+
+
+ ç•°ãªã‚‹æ–‡å­—エンコーディングã®çµ„ã¿åˆã‚ã›ã¯ã€ä»¥ä¸‹ã®å ´åˆã«ã®ã¿è¨±ã•ã‚Œã‚‹ã€‚
+
+ pattern_enc: ASCII, ISO_8859_1
+ target_enc: UTF16_BE, UTF16_LE, UTF32_BE, UTF32_LE
+
+ pattern_enc: UTF16_BE/LE
+ target_enc: UTF16_LE/BE
+
+ pattern_enc: UTF32_BE/LE
+ target_enc: UTF32_LE/BE
+
+
+# void onig_free(regex_t* reg)
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ãƒ¡ãƒ¢ãƒªã‚’解放ã™ã‚‹ã€‚
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# void onig_free_body(regex_t* reg)
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ãƒ¡ãƒ¢ãƒªã‚’解放ã™ã‚‹ã€‚(reg自身ã®é ˜åŸŸã‚’除ã„ã¦)
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# OnigMatchParam* onig_new_match_param()
+
+ OnigMatchParamオブジェクトを生æˆã—ã€onig_initialize_match_param()を使用ã—ã¦
+ 中身をåˆæœŸåŒ–ã™ã‚‹ã€‚
+
+
+# void onig_free_match_param(OnigMatchParam* mp)
+
+ OnigMatchParamオブジェクトã§ä½¿ç”¨ã—ã¦ã„るメモリを開放ã™ã‚‹ã€‚
+
+ 引数
+ 1 mp: OnigMatchParamオブジェクト
+
+
+# void onig_initialize_match_param(OnigMatchParam* mp)
+
+ マッãƒãƒ‘ラメタ構造体ã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã‚’セットã™ã‚‹ã€‚
+ マッãƒãƒ‘ラメタã¯ã€onig_match_with_param(), onig_search_with_param()ã§
+ 使用ã•ã‚Œã‚‹ã€‚
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+
+
+# int onig_set_match_stack_limit_size_of_match_param(OnigMatchParam* mp, unsigned int limit)
+
+ マッãƒã‚¹ã‚¿ãƒƒã‚¯ã®æœ€å¤§æ·±ã•ã‚’セットã™ã‚‹ã€‚
+ 0ã¯ã€ç„¡åˆ¶é™ã‚’表ã™ã€‚
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+ 2 limit: 制é™æ•°
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_match_of_match_param(OnigMatchParam* mp, unsigned long limit)
+
+ 一回ã®ãƒžãƒƒãƒã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’セットã™ã‚‹ã€‚
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+ 2 limit: 制é™å›žæ•°
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_search_of_match_param(OnigMatchParam* mp, unsigned long limit)
+
+ 一回ã®æ¤œç´¢ã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’セットã™ã‚‹ã€‚
+ ï¼ã¯ç„¡åˆ¶é™ã‚’æ„味ã™ã‚‹ã€‚
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+ 2 limit: 制é™å›žæ•°
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_set_progress_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ å‰é€²æ™‚ã®å†…容ã®å‘¼ã³å‡ºã—(callouts)ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’セットã™ã‚‹ã€‚
+ ã‚‚ã—ï¼(NULL)ãŒã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã¨ã€å‰é€²æ™‚ã«å‘¼ã³å‡ºã—ã¯èµ·ã“らãªã„。
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+ 2 f: 呼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_set_retraction_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ 後退時ã®å†…容ã®å‘¼ã³å‡ºã—(callouts)ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’セットã™ã‚‹ã€‚
+ ã‚‚ã—ï¼(NULL)ãŒã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã¨ã€å¾Œé€€æ™‚ã«å‘¼ã³å‡ºã—ã¯èµ·ã“らãªã„。
+
+ 引数
+ 1 mp: マッãƒãƒ‘ラメタオブジェクトアドレス
+ 2 f: 呼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+
+# int onig_search(regex_t* reg, const UChar* str, const UChar* end, const UChar* start,
+ const UChar* range, OnigRegion* region, OnigOptionType option)
+
+ æ­£è¦è¡¨ç¾ã§æ–‡å­—列を検索ã—ã€æ¤œç´¢çµæžœã¨ãƒžãƒƒãƒé ˜åŸŸã‚’è¿”ã™ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®æ–‡å­—エンコーディングã§ã€æ¤œç´¢æ–‡å­—列ã¨ã—ã¦ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+ 正常終了戻り値: マッãƒä½ç½® (p - str >= 0)
+ 検索失敗: ONIG_MISMATCH (< 0)
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 str: 検索対象文字列
+ 3 end: 検索対象文字列ã®çµ‚端アドレス
+ 4 start: 検索対象文字列ã®æ¤œç´¢å…ˆé ­ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 5 range: 検索対象文字列ã®æ¤œç´¢çµ‚了ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ å‰æ–¹æŽ¢ç´¢ (start <= 探索ã•ã‚Œã‚‹æ–‡å­—列 < range)
+ 後方探索 (range <= 探索ã•ã‚Œã‚‹æ–‡å­—列 <= start)
+ 6 region: マッãƒé ˜åŸŸæƒ…å ±(region) (NULLも許ã•ã‚Œã‚‹)
+ 7 option: 検索時オプション
+
+ ONIG_OPTION_NOTBOL 文字列ã®å…ˆé ­(str)を行頭ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_NOTEOL 文字列ã®çµ‚端(end)を行末ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_POSIX_REGION region引数をPOSIX APIã®regmatch_t[]ã«ã™ã‚‹
+
+
+# int onig_search_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+
+ æ­£è¦è¡¨ç¾ã§æ–‡å­—列を検索ã—ã€æ¤œç´¢çµæžœã¨ãƒžãƒƒãƒé ˜åŸŸã‚’è¿”ã™ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®æ–‡å­—エンコーディングã§ã€æ¤œç´¢æ–‡å­—列ã¨ã—ã¦ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+ 引数
+ 1-7: onig_search()ã¨åŒã˜
+ 8 mp: マッãƒãƒ‘ラメタ値 (match_stack_limit, retry_limit_in_match, retry_limit_in_search)
+
+
+# int onig_match(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* at, OnigRegion* region, OnigOptionType option)
+
+ 文字列ã®æŒ‡å®šä½ç½®ã§ãƒžãƒƒãƒãƒ³ã‚°ã‚’è¡Œã„ã€çµæžœã¨ãƒžãƒƒãƒé ˜åŸŸã‚’è¿”ã™ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®æ–‡å­—エンコーディングã§ã€æ¤œç´¢æ–‡å­—列ã¨ã—ã¦ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+ 正常終了戻り値: マッãƒã—ãŸãƒã‚¤ãƒˆé•· (>= 0)
+ not match: ONIG_MISMATCH ( < 0)
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 str: 検索対象文字列
+ 3 end: 検索対象文字列ã®çµ‚端アドレス
+ 4 at: 検索対象文字列ã®æ¤œç´¢ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 5 region: マッãƒé ˜åŸŸæƒ…å ±(region) (NULLも許ã•ã‚Œã‚‹)
+ 6 option: 検索時オプション
+
+ ONIG_OPTION_NOTBOL 文字列ã®å…ˆé ­(str)を行頭ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_NOTEOL 文字列ã®çµ‚端(end)を行末ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_POSIX_REGION region引数をPOSIX APIã®regmatch_t[]ã«ã™ã‚‹
+
+
+# int onig_match_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* at, OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+
+ 文字列ã®æŒ‡å®šä½ç½®ã§ãƒžãƒƒãƒãƒ³ã‚°ã‚’è¡Œã„ã€çµæžœã¨ãƒžãƒƒãƒé ˜åŸŸã‚’è¿”ã™ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®æ–‡å­—エンコーディングã§ã€æ¤œç´¢æ–‡å­—列ã¨ã—ã¦ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+ 引数
+ 1-6: onig_match()ã¨åŒã˜
+ 7 mp: マッãƒãƒ‘ラメタ値 (match_stack_limit, retry_limit_in_match, retry_limit_in_search)
+
+
+# int onig_scan(regex_t* reg, const UChar* str, const UChar* end,
+ OnigRegion* region, OnigOptionType option,
+ int (*scan_callback)(int, int, OnigRegion*, void*),
+ void* callback_arg)
+
+ æ­£è¦è¡¨ç¾ã§æ–‡å­—列をスキャンã—ã¦ã€ãƒžãƒƒãƒãƒ³ã‚°ã™ã‚‹æ¯Žã«ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯é–¢æ•°ã‚’呼ã³å‡ºã™ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®æ–‡å­—エンコーディングã§ã€æ¤œç´¢æ–‡å­—列ã¨ã—ã¦ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+ 正常終了: マッãƒå›žæ•° (0回もå«ã‚ã‚‹)
+ エラー: エラーコード (< 0)
+ 中断: コールãƒãƒƒã‚¯é–¢æ•°ãŒï¼ä»¥å¤–ã®æˆ»ã‚Šå€¤ã‚’è¿”ã—ãŸã¨ãã€ãã®å€¤ã‚’戻り値ã¨ã—ã¦ä¸­æ–­
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 str: 検索対象文字列
+ 3 end: 検索対象文字列ã®çµ‚端アドレス
+ 4 region: マッãƒé ˜åŸŸæƒ…å ±(region) (NULLも許ã•ã‚Œã‚‹)
+ 5 option: 検索時オプション
+ 6 scan_callback: コールãƒãƒƒã‚¯é–¢æ•°
+ 7 callback_arg: コールãƒãƒƒã‚¯é–¢æ•°ã«æ¸¡ã•ã‚Œã‚‹ä»˜åŠ å¼•æ•°å€¤
+
+
+# int onig_regset_new(OnigRegSet** rset, int n, regex_t* regs[])
+
+ regsetオブジェクトを生æˆã™ã‚‹ã€‚
+ å…¨ã¦ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã¯ã€åŒã˜æ–‡å­—エンコーディングã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+ å…¨ã¦ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã¯ã€ONIG_OPTION_FIND_LONGESTオプションã§ã‚³ãƒ³ãƒ‘イルã•ã‚Œã¦ã„ã¦ã¯ãªã‚‰ãªã„。
+
+ 引数
+ 1 rset: regsetオブジェクトを返ã™ãŸã‚ã®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 2 n: æ­£è¦è¡¨ç¾ã®å€‹æ•°
+ 3 regs: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®é…列
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_regset_add(OnigRegSet* set, regex_t* reg)
+
+ regsetオブジェクトã«æ­£è¦è¡¨ç¾ã‚’追加ã™ã‚‹ã€‚
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã¯ã€regsetã¨åŒã˜æ–‡å­—エンコーディングã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã¯ã€ONIG_OPTION_FIND_LONGESTオプションã§ã‚³ãƒ³ãƒ‘イルã•ã‚Œã¦ã„ã¦ã¯ãªã‚‰ãªã„。
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_regset_replace(OnigRegSet* set, int at, regex_t* reg)
+
+ regsetã®ä¸­ã®ä¸€å€‹ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトを別ã®ã‚‚ã®ã«å¤‰æ›´ã™ã‚‹ã€‚
+ è‹¥ã—reg引数ã®å€¤ãŒNULLã§ã‚ã‚Œã°ã€at番目ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトを外ã™ã€‚(ãã—ã¦ã€ä»¥é™ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã¯å¤‰åŒ–ã™ã‚‹)
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 at: 変更ã™ã‚‹å ´æ‰€ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹
+ 2 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# void onig_regset_free(OnigRegSet* set)
+
+ regsetオブジェクトã¨ãã®ä¸­ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ä½¿ç”¨ãƒ¡ãƒ¢ãƒªã‚’開放ã™ã‚‹ã€‚
+ è‹¥ã—ã€åŒä¸€ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトをé‡è¤‡ã—ã¦ç™»éŒ²ã—ã¦ã„ã‚Œã°ã€ç ´å£Šçš„ãªçŠ¶æ³ã«ãªã‚‹ã€‚
+
+ 引数
+ 1 set: regsetオブジェクト
+
+
+# int onig_regset_number_of_regex(OnigRegSet* set)
+
+ regsetã®ä¸­ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®å€‹æ•°ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 set: regsetオブジェクト
+
+
+# regex_t* onig_regset_get_regex(OnigRegSet* set, int at)
+
+ regsetã®at番目ã®æ­£è¦è¡¨ç¾ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 at: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ (ゼロ開始)
+
+
+# OnigRegion* onig_regset_get_region(OnigRegSet* set, int at)
+
+ regsetã®at番目ã®æ­£è¦è¡¨ç¾ã«å¯¾å¿œã™ã‚‹é ˜åŸŸã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 at: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ (ゼロ開始)
+
+
+# int onig_regset_search(OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, int* rmatch_pos)
+
+ regsetã«ã‚ˆã‚‹æ¤œç´¢ã‚’実行ã™ã‚‹ã€‚
+
+ 戻り値:
+ 検索æˆåŠŸ: マッãƒã—ãŸæ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ (ゼロ開始)
+ 検索失敗: ONIG_MISMATCH (< 0)
+ エラー: エラーコード (< 0)
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 str: 検索対象文字列
+ 3 end: 検索対象文字列ã®çµ‚端アドレス
+ 4 start: 検索対象文字列ã®æ¤œç´¢å…ˆé ­ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 5 range: 検索対象文字列ã®æ¤œç´¢çµ‚了ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ (start <= 探索ã•ã‚Œã‚‹æ–‡å­—列 < range)
+ 6 lead: 外å´ã®ãƒ«ãƒ¼ãƒ—è¦ç´ 
+ ONIG_REGSET_POSITION_LEAD (最左ä½ç½®ã§ãƒžãƒƒãƒã—ãŸçµæžœã‚’è¿”ã™)
+ ONIG_REGSET_REGEX_LEAD (最左ä½ç½®ã§ãƒžãƒƒãƒã—ãŸçµæžœã‚’è¿”ã™)
+ ONIG_REGSET_PRIORITY_TO_REGEX_ORDER (最åˆã«ãƒžãƒƒãƒã—ãŸæ­£è¦è¡¨ç¾ã®çµæžœã‚’è¿”ã™)
+ 7 option: 検索時オプション
+ ONIG_OPTION_NOTBOL 文字列ã®å…ˆé ­(str)を行頭ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_NOTEOL 文字列ã®çµ‚端(end)を行末ã¨çœ‹åšã•ãªã„
+ 8 rmatch_pos: マッãƒã—ãŸä½ç½®ã‚’è¿”ã™ãŸã‚ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ (match_address - str)
+
+ * ONIG_REGSET_POSITION_LEADã¨ONIG_REGSET_REGEX_LEADã¯åŒã˜çµæžœã‚’è¿”ã™ã€‚
+ ã“れらã®é•ã„ã¯æ¤œç´¢æ™‚é–“ã«ã—ã‹ç¾ã‚Œãªã„。
+ ã»ã¨ã‚“ã©ã®å ´åˆã€ONIG_REGSET_POSITION_LEADã®ã»ã†ãŒé€Ÿã„ã¨æ€ã‚れる。
+
+
+# int onig_regset_search_with_param(OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, OnigMatchParam* mps[], int* rmatch_pos)
+
+ regsetã¨OnigMatchParamオブジェクトã«ã‚ˆã‚‹æ¤œç´¢ã‚’実行ã™ã‚‹ã€‚
+
+ 戻り値:
+ 検索æˆåŠŸ: マッãƒã—ãŸæ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ (ゼロ開始)
+ 検索失敗: ONIG_MISMATCH (< 0)
+ エラー: エラーコード (< 0)
+
+ 引数
+ 1 set: regsetオブジェクト
+ 2 str: 検索対象文字列
+ 3 end: 検索対象文字列ã®çµ‚端アドレス
+ 4 start: 検索対象文字列ã®æ¤œç´¢å…ˆé ­ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 5 range: 検索対象文字列ã®æ¤œç´¢çµ‚了ä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹
+ (start <= 探索ã•ã‚Œã‚‹æ–‡å­—列 < range)
+ 6 lead: 外å´ã®ãƒ«ãƒ¼ãƒ—è¦ç´ 
+ ONIG_REGSET_POSITION_LEAD (最左ä½ç½®ã§ãƒžãƒƒãƒã—ãŸçµæžœã‚’è¿”ã™)
+ ONIG_REGSET_REGEX_LEAD (最左ä½ç½®ã§ãƒžãƒƒãƒã—ãŸçµæžœã‚’è¿”ã™)
+ ONIG_REGSET_PRIORITY_TO_REGEX_ORDER (最åˆã«ãƒžãƒƒãƒã—ãŸæ­£è¦è¡¨ç¾ã®çµæžœã‚’è¿”ã™)
+ 7 option: 検索時オプション
+ ONIG_OPTION_NOTBOL 文字列ã®å…ˆé ­(str)を行頭ã¨çœ‹åšã•ãªã„
+ ONIG_OPTION_NOTEOL 文字列ã®çµ‚端(end)を行末ã¨çœ‹åšã•ãªã„
+ 8 mps: OnigMatchParamオブジェクトã®é…列
+ 9 rmatch_pos: マッãƒã—ãŸä½ç½®ã‚’è¿”ã™ãŸã‚ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ (match_address - str)
+
+
+# OnigRegion* onig_region_new(void)
+
+ マッãƒé ˜åŸŸæƒ…å ±(region)を作æˆã™ã‚‹ã€‚
+
+
+# void onig_region_free(OnigRegion* region, int free_self)
+
+ マッãƒé ˜åŸŸæƒ…å ±(region)ã§ä½¿ç”¨ã•ã‚Œã¦ã„るメモリを解放ã™ã‚‹ã€‚
+
+ 引数
+ 1 region: マッãƒé ˜åŸŸæƒ…報オブジェクト
+ 2 free_self: [1: region自身をå«ã‚ã¦å…¨ã¦è§£æ”¾, 0: region自身ã¯è§£æ”¾ã—ãªã„]
+
+
+# void onig_region_copy(OnigRegion* to, OnigRegion* from)
+
+ マッãƒé ˜åŸŸæƒ…å ±(region)を複製ã™ã‚‹ã€‚
+
+ 引数
+ 1 to: 対象領域
+ 2 from: 元領域
+
+
+# void onig_region_clear(OnigRegion* region)
+
+ マッãƒé ˜åŸŸæƒ…å ±(region)ã®ä¸­å‘³ã‚’クリアã™ã‚‹ã€‚
+
+ 引数
+ 1 region: 対象領域
+
+
+# int onig_region_resize(OnigRegion* region, int n)
+
+ マッãƒé ˜åŸŸæƒ…å ±(region)ã®æ•ç²å¼é›†åˆ(グループ)数を変更ã™ã‚‹ã€‚
+
+ 正常終了戻り値: ONIG_NORMAL
+
+ 引数
+ 1 region: 対象領域
+ 2 n: æ–°ã—ã„サイズ
+
+
+# int onig_name_to_group_numbers(regex_t* reg, const UChar* name, const UChar* name_end,
+ int** num_list)
+
+ 指定ã—ãŸåå‰ã«å¯¾ã™ã‚‹åå‰ä»˜ãæ•ç²å¼é›†åˆ(グループ)ã®
+ グループ番å·ãƒªã‚¹ãƒˆã‚’è¿”ã™ã€‚
+ åå‰ä»˜ãæ•ç²å¼é›†åˆã¯ã€(?<name>....)ã«ã‚ˆã£ã¦å®šç¾©ã§ãる。
+
+ 正常終了戻り値: 指定ã•ã‚ŒãŸåå‰ã«å¯¾ã™ã‚‹ã‚°ãƒ«ãƒ¼ãƒ—æ•°
+ (例 /(?<x>..)(?<x>..)/ ==> 2)
+ åå‰ã«å¯¾ã™ã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ãŒå­˜åœ¨ã—ãªã„: -1
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 name: æ•ç²å¼é›†åˆ(グループ)å
+ 3 name_end: æ•ç²å¼é›†åˆ(グループ)åã®çµ‚端アドレス
+ 4 num_list: 番å·ãƒªã‚¹ãƒˆã‚’è¿”ã™ã‚¢ãƒ‰ãƒ¬ã‚¹
+
+
+# int onig_name_to_backref_number(regex_t* reg, const UChar* name, const UChar* name_end,
+ OnigRegion *region)
+
+ 指定ã•ã‚ŒãŸåå‰ã®å¾Œæ–¹å‚ç…§(\k<name>)ã«å¯¾ã™ã‚‹æ•ç²å¼é›†åˆ(グループ)ã®ç•ªå·ã‚’è¿”ã™ã€‚
+ åå‰ã«å¯¾ã—ã¦ã€è¤‡æ•°ã®ãƒžãƒƒãƒé ˜åŸŸãŒæœ‰åŠ¹ã§ã‚ã‚Œã°ã€ãã®ä¸­ã®æœ€å¤§ã®ç•ªå·ã‚’è¿”ã™ã€‚
+ åå‰ã«å¯¾ã™ã‚‹æ•ç²å¼é›†åˆãŒä¸€å€‹ã—ã‹ãªã„ã¨ãã«ã¯ã€å¯¾å¿œã™ã‚‹ãƒžãƒƒãƒé ˜åŸŸãŒæœ‰åŠ¹ã‹
+ ã©ã†ã‹ã«é–¢ä¿‚ãªãã€ãã®ç•ªå·ã‚’è¿”ã™ã€‚(従ã£ã¦ã€regionã«ã¯NULLを渡ã—ã¦ã‚‚よã„。)
+
+ 正常終了戻り値: 番å·
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 name: æ•ç²å¼é›†åˆ(グループ)å
+ 3 name_end: æ•ç²å¼é›†åˆ(グループ)åã®çµ‚端アドレス
+ 4 region: search/matchçµæžœã®ãƒžãƒƒãƒé ˜åŸŸ
+
+
+# int onig_foreach_name(regex_t* reg,
+ int (*func)(const UChar*, const UChar*, int,int*,regex_t*,void*),
+ void* arg)
+
+ å…¨ã¦ã®åå‰ã«å¯¾ã—ã¦ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯é–¢æ•°å‘¼ã³å‡ºã—を実行ã™ã‚‹ã€‚
+
+ 正常終了戻り値: 0
+ エラー: コールãƒãƒƒã‚¯é–¢æ•°ã®æˆ»ã‚Šå€¤
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ 2 func: コールãƒãƒƒã‚¯é–¢æ•°
+ func(name, name_end, <number of groups>, <group number's list>,
+ reg, arg);
+
+ funcãŒ0以外ã®å€¤ã‚’è¿”ã™ã¨ã€ãれ以é™ã®ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã¯è¡Œãªã‚ãšã«
+ 終了ã™ã‚‹ã€‚
+
+ 3 arg: funcã«å¯¾ã™ã‚‹è¿½åŠ å¼•æ•°
+
+
+# int onig_number_of_names(regex_t* reg)
+
+ パターン中ã§å®šç¾©ã•ã‚ŒãŸåå‰ã®æ•°ã‚’è¿”ã™ã€‚
+ 一個ã®åå‰ã®å¤šé‡å®šç¾©ã¯ä¸€å€‹ã¨çœ‹åšã™ã€‚
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# OnigEncoding onig_get_encoding(regex_t* reg)
+# OnigOptionType onig_get_options(regex_t* reg)
+# OnigCaseFoldType onig_get_case_fold_flag(regex_t* reg)
+# OnigSyntaxType* onig_get_syntax(regex_t* reg)
+
+ æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã«å¯¾ã—ã¦ã€å¯¾å¿œã™ã‚‹å€¤ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# int onig_number_of_captures(regex_t* reg)
+
+ パターン中ã§å®šç¾©ã•ã‚ŒãŸæ•ç²ã‚°ãƒ«ãƒ¼ãƒ—ã®æ•°ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# int onig_number_of_capture_histories(regex_t* reg)
+
+ パターン中ã§å®šç¾©ã•ã‚ŒãŸæ•ç²å±¥æ­´(?@...)ã®æ•°ã‚’è¿”ã™ã€‚
+
+ 使用ã™ã‚‹æ–‡æ³•ã§æ•ç²å±¥æ­´æ©Ÿèƒ½ãŒæœ‰åŠ¹(ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY)
+ ã§ãªã‘ã‚Œã°ã€æ•ç²å±¥æ­´æ©Ÿèƒ½ã¯ä½¿ç”¨ã§ããªã„。
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+# OnigCaptureTreeNode* onig_get_capture_tree(OnigRegion* region)
+
+ æ•ç²å±¥æ­´ãƒ‡ãƒ¼ã‚¿ã®ãƒ«ãƒ¼ãƒˆãƒŽãƒ¼ãƒ‰ã‚’è¿”ã™ã€‚
+
+ マッãƒãŒå¤±æ•—ã—ã¦ã„ã‚‹å ´åˆã«ã¯ã€ã“ã®å€¤ã¯ä¸å®šã§ã‚る。
+
+ 引数
+ 1 region: マッãƒé ˜åŸŸ
+
+
+# int onig_capture_tree_traverse(OnigRegion* region, int at,
+ int(*func)(int,int,int,int,int,void*), void* arg)
+
+ æ•ç²å±¥æ­´ãƒ‡ãƒ¼ã‚¿æœ¨ã‚’巡回ã—ã¦ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã™ã‚‹ã€‚
+
+ 正常終了戻り値: 0
+ エラー: コールãƒãƒƒã‚¯é–¢æ•°ã®æˆ»ã‚Šå€¤
+
+ 引数
+ 1 region: マッãƒé ˜åŸŸ
+ 2 at: コールãƒãƒƒã‚¯ã‚’è¡Œãªã†ã‚¿ã‚¤ãƒŸãƒ³ã‚°
+
+ ONIG_TRAVERSE_CALLBACK_AT_FIRST:
+ 最åˆã«ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã—ã¦ã€å­ãƒŽãƒ¼ãƒ‰ã‚’巡回
+ ONIG_TRAVERSE_CALLBACK_AT_LAST:
+ å­ãƒŽãƒ¼ãƒ‰ã‚’巡回ã—ã¦ã€ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯
+ ONIG_TRAVERSE_CALLBACK_AT_BOTH:
+ 最åˆã«ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã—ã¦ã€å­ãƒŽãƒ¼ãƒ‰ã‚’巡回ã€æœ€å¾Œã«ã‚‚ã†ä¸€åº¦ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯
+
+ 3 func: コールãƒãƒƒã‚¯é–¢æ•°
+ funcãŒ0以外ã®å€¤ã‚’è¿”ã™ã¨ã€ãれ以é™ã®å·¡å›žã¯è¡Œãªã‚ãšã«
+ 終了ã™ã‚‹ã€‚
+
+ int func(int group, int beg, int end, int level, int at,
+ void* arg)
+ group: グループ番å·
+ beg: マッãƒé–‹å§‹ä½ç½®
+ end マッãƒçµ‚了ä½ç½®
+ level: ãƒã‚¹ãƒˆãƒ¬ãƒ™ãƒ« (0ã‹ã‚‰)
+ at: コールãƒãƒƒã‚¯ãŒå‘¼ã³å‡ºã•ã‚ŒãŸã‚¿ã‚¤ãƒŸãƒ³ã‚°
+ ONIG_TRAVERSE_CALLBACK_AT_FIRST
+ ONIG_TRAVERSE_CALLBACK_AT_LAST
+ arg: 追加引数
+
+ 4 arg; funcã«å¯¾ã™ã‚‹è¿½åŠ å¼•æ•°
+
+
+# int onig_noname_group_capture_is_active(regex_t* reg)
+
+ åå‰ãªã—å¼é›†åˆã®æ•ç²æ©Ÿèƒ½ãŒæœ‰åŠ¹ã‹ã©ã†ã‹ã‚’è¿”ã™ã€‚
+
+ 有効: 1
+ 無効: 0
+
+ 引数
+ 1 reg: æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+
+
+ オプションã®ONIG_OPTION_DONT_CAPTURE_GROUPãŒON --> 無効
+
+ パターンãŒåå‰ã¤ãå¼é›†åˆã‚’使用ã—ã¦ã„ã‚‹
+ AND 使用文法ã§ã€ONIG_SYN_CAPTURE_ONLY_NAMED_GROUPãŒON
+ AND オプションã®ONIG_OPTION_CAPTURE_GROUPãŒOFF
+ --> 無効
+
+ 上記以外ã®å ´åˆ --> 有効
+
+
+# UChar* onigenc_get_prev_char_head(OnigEncoding enc, const UChar* start, const UChar* s)
+
+ 文字一個分å‰ã®æ–‡å­—列ä½ç½®ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 enc: 文字エンコーディング
+ 2 start: 文字列ã®å…ˆé ­ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 3 s: 文字列中ã®ä½ç½®
+
+
+# UChar* onigenc_get_left_adjust_char_head(OnigEncoding enc,
+ const UChar* start, const UChar* s)
+
+ 文字ã®å…ˆé ­ãƒã‚¤ãƒˆä½ç½®ã«ãªã‚‹ã‚ˆã†ã«å·¦å´ã«èª¿æ•´ã—ãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 enc: 文字エンコーディング
+ 2 start: 文字列ã®å…ˆé ­ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 3 s: 文字列中ã®ä½ç½®
+
+
+# UChar* onigenc_get_right_adjust_char_head(OnigEncoding enc,
+ const UChar* start, const UChar* s)
+
+ 文字ã®å…ˆé ­ãƒã‚¤ãƒˆä½ç½®ã«ãªã‚‹ã‚ˆã†ã«å³å´ã«èª¿æ•´ã—ãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+ 引数
+ 1 enc: 文字エンコーディング
+ 2 start: 文字列ã®å…ˆé ­ã‚¢ãƒ‰ãƒ¬ã‚¹
+ 3 s: 文字列中ã®ä½ç½®
+
+
+# int onigenc_strlen(OnigEncoding enc, const UChar* s, const UChar* end)
+
+ 文字列ã®æ–‡å­—æ•°ã‚’è¿”ã™ã€‚
+
+
+# int onigenc_strlen_null(OnigEncoding enc, const UChar* s)
+
+ 文字列ã®æ–‡å­—æ•°ã‚’è¿”ã™ã€‚
+ 文字エンコーディングã«å¯¾ã—ã¦ã€ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+
+# int onigenc_str_bytelen_null(OnigEncoding enc, const UChar* s)
+
+ 文字列ã®ãƒã‚¤ãƒˆæ•°ã‚’è¿”ã™ã€‚
+ 文字エンコーディングã«å¯¾ã—ã¦ã€ä¸æ­£ãªæ–‡å­—列を渡ã—ã¦ã¯ã„ã‘ãªã„。
+
+
+# int onig_set_default_syntax(OnigSyntaxType* syntax)
+
+ デフォルトã®æ­£è¦è¡¨ç¾ãƒ‘ターン文法をセットã™ã‚‹ã€‚
+
+ 引数
+ 1 syntax: æ­£è¦è¡¨ç¾ãƒ‘ターン文法
+
+
+# void onig_copy_syntax(OnigSyntaxType* to, OnigSyntaxType* from)
+
+ æ­£è¦è¡¨ç¾ãƒ‘ターン文法をコピーã™ã‚‹ã€‚
+
+ 引数
+ 1 to: 対象
+ 2 from: å…ƒ
+
+
+# unsigned int onig_get_syntax_op(OnigSyntaxType* syntax)
+# unsigned int onig_get_syntax_op2(OnigSyntaxType* syntax)
+# unsigned int onig_get_syntax_behavior(OnigSyntaxType* syntax)
+# OnigOptionType onig_get_syntax_options(OnigSyntaxType* syntax)
+
+# void onig_set_syntax_op(OnigSyntaxType* syntax, unsigned int op)
+# void onig_set_syntax_op2(OnigSyntaxType* syntax, unsigned int op2)
+# void onig_set_syntax_behavior(OnigSyntaxType* syntax, unsigned int behavior)
+# void onig_set_syntax_options(OnigSyntaxType* syntax, OnigOptionType options)
+
+ æ­£è¦è¡¨ç¾ãƒ‘ターン文法ã®è¦ç´ ã‚’å‚ç…§/å–å¾—ã™ã‚‹ã€‚
+
+ 引数
+ 1 syntax: æ­£è¦è¡¨ç¾ãƒ‘ターン文法
+ 2 op, op2, behavior, options: è¦ç´ ã®å€¤
+
+
+# void onig_copy_encoding(OnigEncoding to, OnigEncoding from)
+
+ 文字エンコーディングをコピーã™ã‚‹ã€‚
+
+ 引数
+ 1 to: 対象
+ 2 from: å…ƒ
+
+
+# int onig_set_meta_char(OnigSyntaxType* syntax, unsigned int what,
+ OnigCodePoint code)
+
+ メタ文字を指定ã—ãŸã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤ã«ã‚»ãƒƒãƒˆã™ã‚‹ã€‚
+ ONIG_SYN_OP_VARIABLE_META_CHARACTERSãŒæ­£è¦è¡¨ç¾ãƒ‘ターン文法ã§æœ‰åŠ¹ã«
+ ãªã£ã¦ã„ãªã„å ´åˆã«ã¯ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—文字を除ã„ã¦ã€ã“ã“ã§æŒ‡å®šã—ãŸãƒ¡ã‚¿æ–‡å­—ã¯
+ 機能ã—ãªã„。(組込ã¿ã®æ–‡æ³•ã§ã¯æœ‰åŠ¹ã«ã—ã¦ã„ãªã„。)
+
+ 正常終了戻り値: ONIG_NORMAL
+
+ 引数
+ 1 syntax: 対象文法
+ 2 what: メタ文字機能ã®æŒ‡å®š
+
+ ONIG_META_CHAR_ESCAPE
+ ONIG_META_CHAR_ANYCHAR
+ ONIG_META_CHAR_ANYTIME
+ ONIG_META_CHAR_ZERO_OR_ONE_TIME
+ ONIG_META_CHAR_ONE_OR_MORE_TIME
+ ONIG_META_CHAR_ANYCHAR_ANYTIME
+
+ 3 code: メタ文字ã®ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆ ã¾ãŸã¯ ONIG_INEFFECTIVE_META_CHAR.
+
+
+# OnigCaseFoldType onig_get_default_case_fold_flag()
+
+ デフォルトã®case foldフラグをå–å¾—ã™ã‚‹ã€‚
+
+
+# int onig_set_default_case_fold_flag(OnigCaseFoldType case_fold_flag)
+
+ デフォルトã®case foldフラグをセットã™ã‚‹ã€‚
+
+ 引数
+ 1 case_fold_flag: case foldフラグ
+
+
+# unsigned int onig_get_match_stack_limit_size(void)
+
+ マッãƒã‚¹ã‚¿ãƒƒã‚¯ã‚µã‚¤ã‚ºã®æœ€å¤§å€¤ã‚’è¿”ã™ã€‚
+ (デフォルト: 0 == 無制é™)
+
+
+# int onig_set_match_stack_limit_size(unsigned int size)
+
+ マッãƒã‚¹ã‚¿ãƒƒã‚¯ã‚µã‚¤ã‚ºã®æœ€å¤§å€¤ã‚’指定ã™ã‚‹ã€‚
+ (size = 0: 無制é™)
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# unsigned long onig_get_retry_limit_in_match(void)
+
+ 一回ã®ãƒžãƒƒãƒãƒ³ã‚°ã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’è¿”ã™ã€‚
+ (デフォルト: 10000000)
+
+ 正常終了戻り値: 制é™å€¤
+
+
+# unsigned long onig_get_retry_limit_in_search(void)
+
+ 一回ã®æ¤œç´¢ã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’è¿”ã™ã€‚
+ 0ã¯ç„¡åˆ¶é™ã‚’æ„味ã™ã‚‹ã€‚
+ (デフォルト: 0)
+
+ 正常終了戻り値: 制é™å€¤
+
+
+# int onig_set_retry_limit_in_match(unsigned long limit)
+
+ 一回ã®ãƒžãƒƒãƒãƒ³ã‚°å†…ã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’指定ã™ã‚‹ã€‚
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_set_retry_limit_in_search(unsigned long limit)
+
+ 一回ã®æ¤œç´¢ã§ã®ãƒªãƒˆãƒ©ã‚¤æ•°ã®åˆ¶é™å€¤ã‚’セットã™ã‚‹ã€‚
+ 0ã¯ç„¡åˆ¶é™ã‚’æ„味ã™ã‚‹ã€‚
+ (デフォルト: 0)
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_progress_callout(void)
+
+ å‰é€²æ™‚ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’è¿”ã™ã€‚
+
+
+# int onig_set_progress_callout(OnigCalloutFunc f)
+
+ å‰é€²æ™‚ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’指定ã™ã‚‹ã€‚
+ ã‚‚ã—0(NULL)を指定ã™ã‚‹ã¨ã€å‰é€²æ™‚ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã—ã¯èµ·ã“らãªã„。
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_retraction_callout(void)
+
+ 後退時ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’è¿”ã™ã€‚
+
+
+# int onig_set_retraction_callout(OnigCalloutFunc f)
+
+ 後退時ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã•ã‚Œã‚‹é–¢æ•°ã‚’指定ã™ã‚‹ã€‚
+ ã‚‚ã—0(NULL)を指定ã™ã‚‹ã¨ã€å¾Œé€€æ™‚ã®å†…容ã®å‘¼ã³å‡ºã—ã§å‘¼ã³å‡ºã—ã¯èµ·ã“らãªã„。
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_unicode_define_user_property(const char* name, OnigCodePoint* ranges))
+
+ æ–°ã—ã„Unicodeプロパティを定義ã™ã‚‹ã€‚
+ (ã“ã®é–¢æ•°ã¯ã‚¹ãƒ¬ãƒƒãƒ‰ã‚»ãƒ¼ãƒ•ã§ã¯ãªã„)
+
+ 引数
+ 1 name: プロパティå (ASCIIコードã®ã¿ã€‚ 文字 ' ', '-', '_' ã¯ç„¡è¦–ã•ã‚Œã‚‹ã€‚)
+ 2 ranges: プロパティコードãƒã‚¤ãƒ³ãƒˆç¯„囲
+ (最åˆã®è¦ç´ ã¯ç¯„囲ã®æ•°)
+
+ [num-of-ranges, 1st-range-start, 1st-range-end, 2nd-range-start... ]
+
+ * ã“ã®é–¢æ•°ã‚’呼んã å¾Œã§ã€rangesを変更/破壊ã—ãªã„ã“ã¨
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# unsigned int onig_get_parse_depth_limit(void)
+
+ å†å¸°ãƒ‘ース処ç†ã®æœ€å¤§æ·±ã•ã‚’è¿”ã™ã€‚
+ (デフォルト: regint.h ã§å®šç¾©ã•ã‚Œã¦ã„ã‚‹ DEFAULT_PARSE_DEPTH_LIMIT。ç¾åœ¨ã¯ 4096)
+
+
+# int onig_set_parse_depth_limit(unsigned int depth)
+
+ å†å¸°ãƒ‘ース処ç†ã®æœ€å¤§æ·±ã•ã‚’指定ã™ã‚‹ã€‚
+ (depth = 0: regint.h ã§å®šç¾©ã•ã‚ŒãŸãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã«è¨­å®šã™ã‚‹ã€‚)
+
+ 正常終了戻り値: ONIG_NORMAL
+
+
+# int onig_end(void)
+
+ ライブラリã®ä½¿ç”¨ã‚’終了ã™ã‚‹ã€‚
+
+ 正常終了戻り値: ONIG_NORMAL
+
+ onig_init()ã‚’å†åº¦å‘¼ã³å‡ºã—ã¦ã‚‚ã€ä»¥å‰ã«ä½œæˆã—ãŸæ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクト
+ を使用ã™ã‚‹ã“ã¨ã¯ã§ããªã„。
+
+
+# const char* onig_version(void)
+
+ ãƒãƒ¼ã‚¸ãƒ§ãƒ³æ–‡å­—列を返ã™ã€‚(例 "5.0.3")
+
+// END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API
new file mode 100644
index 000000000..057a054d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API
@@ -0,0 +1,385 @@
+Callouts API Version 6.8.2 2018/06/08
+
+#include <oniguruma.h>
+
+(1) Callout functions
+(2) Set/Get functions for Callouts of contents
+(3) Set functions for Callouts of name
+(4) User data
+(5) Get values from OnigCalloutArgs
+(6) Tag
+(7) Callout data (used in callout functions)
+(8) Callout data (used in applications)
+(9) Miscellaneous functions
+
+
+(1) Callout functions
+
+ type: OnigCalloutFunc
+
+ typedef int (*OnigCalloutFunc)(OnigCalloutArgs* args, void* user_data);
+
+ If 0 (NULL) is set as a callout function value, never called.
+
+
+ * Callout function return value (int)
+
+ ONIG_CALLOUT_FAIL (== 1): fail
+ ONIG_CALLOUT_SUCCESS (== 0): success
+ less than -1: error code (terminate search/match)
+
+ ONIG_CALLOUT_FAIL/SUCCESS values are ignored in retractions,
+ because retraction is a part of recovery process after failure.
+
+ * Example of callout function
+
+ extern int always_success(OnigCalloutArgs* args, void* user_data)
+ {
+ return ONIG_CALLOUT_SUCCESS;
+ }
+
+
+
+(2) Set/Get functions for Callouts of contents
+
+# OnigCalloutFunc onig_get_progress_callout(void)
+
+ Get a function for callouts of contents in progress.
+
+
+# int onig_set_progress_callout(OnigCalloutFunc f)
+
+ Set a function for callouts of contents in progress.
+ This value set in onig_initialize_match_param() as a default
+ callout function.
+
+ normal return: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_retraction_callout(void)
+
+ Get a function for callouts of contents in retraction (backtrack).
+
+
+# int onig_set_retraction_callout(OnigCalloutFunc f)
+
+ Set a function for callouts of contents in retraction (backtrack).
+ This value set in onig_initialize_match_param() as a default
+ callout function.
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_progress_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ Set a function for callouts of contents in progress.
+
+ arguments
+ 1 mp: match-param pointer
+ 2 f: function
+
+ normal return: ONIG_NORMAL
+
+
+# int onig_set_retraction_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ Set a function for callouts of contents in retraction (backtrack).
+
+ arguments
+ 1 mp: match-param pointer
+ 2 f: function
+
+ normal return: ONIG_NORMAL
+
+
+
+(3) Set functions for Callouts of name
+
+# int onig_set_callout_of_name(OnigEncoding enc, OnigCalloutType type, OnigUChar* name, OnigUChar* name_end, int callout_in, OnigCalloutFunc callout, OnigCalloutFunc end_callout, int arg_num, unsigned int arg_types[], int opt_arg_num, OnigValue opt_defaults[])
+
+ Set a function for callouts of name.
+ Allowed name string characters: _ A-Z a-z 0-9 (* first character: _ A-Z a-z)
+
+ (enc, name) pair is used as key value to find callout function.
+ You have to call this function for every encoding used in your applications.
+ But if enc is ASCII compatible and (enc, name) entry is not found,
+ then (ASCII, name) entry is used.
+ Therefore, if you use ASCII compatible encodings only, it is enough to call
+ this function one time for (ASCII, name).
+
+ arguments
+ 1 enc: character encoding
+ 2 type: callout type (currently ONIG_CALLOUT_TYPE_SINGLE only supported)
+ 3 name: name string address (the string is encoded by enc)
+ 4 name_end: name string end address
+ 5 callout_in: direction (ONIG_CALLOUT_IN_PROGRESS/RETRACTION/BOTH)
+ 6 callout: callout function
+ 7 end_callout: * not used currently (set 0)
+ 8 arg_num: number of arguments (*limit by ONIG_CALLOUT_MAX_ARGS_NUM == 4)
+ 9 arg_types: type array of arguments
+ 10 opt_arg_num: number of optional arguments
+ 11 opt_defaults: default values array of optional arguments
+
+ normal return: ONIG_NORMAL
+ error:
+ ONIGERR_INVALID_CALLOUT_NAME
+ ONIGERR_INVALID_ARGUMENT
+ ONIGERR_INVALID_CALLOUT_ARG
+
+
+
+(4) User data
+
+# int onig_set_callout_user_data_of_match_param(OnigMatchParam* param, void* user_data)
+
+ Set a user_data value which passed as second argument of callout.
+
+ normal return: ONIG_NORMAL
+
+
+
+(5) Get values from OnigCalloutArgs
+
+# int onig_get_callout_num_by_callout_args(OnigCalloutArgs* args)
+
+ Returns callout number of this callout.
+ "Callout number" is an identifier of callout in a regex pattern.
+
+
+# OnigCalloutIn onig_get_callout_in_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the direction of this callout.
+ (ONIG_CALLOUT_IN_PROGRESS or ONIG_CALLOUT_IN_RETRACTION)
+
+
+# int onig_get_name_id_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the name identifier of this callout.
+ If this callout is callout of contents, then returns ONIG_NON_NAME_ID.
+
+
+# const OnigUChar* onig_get_contents_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the contents string of this callout. (NULL terminated string)
+ If this callout is callout of name, then returns NULL.
+
+
+# const OnigUChar* onig_get_contents_end_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the end of contents string of this callout.
+ If this callout is callout of name, then returns NULL.
+
+
+# int onig_get_args_num_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the number of args of this callout.
+ It includes optional arguments that doesn't passed in regex pattern.
+ If this callout is callout of contents, then returns
+ ONIGERR_INVALID_ARGUMENT.
+
+
+# int onig_get_passed_args_num_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the number of args that passed really in regex pattern.
+ If this callout is callout of contents, then returns
+ ONIGERR_INVALID_ARGUMENT.
+
+
+# int onig_get_arg_by_callout_args(OnigCalloutArgs* args, int index, OnigType* type, OnigValue* val)
+
+ Returns a value and a type of the callout argument.
+ If this callout is callout of contents, then returns
+ ONIGERR_INVALID_ARGUMENT.
+
+ normal return: ONIG_NORMAL
+
+
+# const OnigUChar* onig_get_string_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the subject string address.
+ This is the second argument(str) of onig_search().
+
+
+# const OnigUChar* onig_get_string_end_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the end address of subject string.
+ This is the third argument(end) of onig_search().
+
+
+# const OnigUChar* onig_get_start_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the start address of subject string in current match process.
+
+
+# const OnigUChar* onig_get_right_range_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the right range address of subject string.
+
+
+# const OnigUChar* onig_get_current_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the current address of subject string in current match process.
+
+
+# OnigRegex onig_get_regex_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the regex object address of this callout.
+
+
+# unsigned long onig_get_retry_counter_by_callout_args(OnigCalloutArgs* args)
+
+ Returns the current counter value for retry-limit-in-match.
+
+
+
+(6) Tag
+
+ "Tag" is a name assigned to a callout in regexp pattern.
+ Allowed tag string characters: _ A-Z a-z 0-9 (* first character: _ A-Z a-z)
+
+
+# int onig_callout_tag_is_exist_at_callout_num(OnigRegex reg, int callout_num)
+
+ Returns 1 if tag is assigned for the callout, else returns 0.
+
+
+# int onig_get_callout_num_by_tag(OnigRegex reg, const OnigUChar* tag, const OnigUChar* tag_end)
+
+ Returns the callout number for the tag.
+
+
+# const OnigUChar* onig_get_callout_tag_start(OnigRegex reg, int callout_num)
+
+ Returns the start address of tag string for the callout.
+ (NULL terminated string)
+
+
+# const OnigUChar* onig_get_callout_tag_end(OnigRegex reg, int callout_num)
+
+ Returns the end address of tag string for the callout.
+
+
+
+(7) Callout data (used in callout functions)
+
+ "Callout data" is ONIG_CALLOUT_DATA_SLOT_NUM(5) values area
+ for each callout in each search process.
+ Each value area in a callout is indicated by "slot" number (0 - 4).
+ Callout data are used for any purpose by callout function implementers.
+
+
+# int onig_get_callout_data_by_callout_args(OnigCalloutArgs* args, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ Returns the callout data value/type for a callout slot indicated by
+ callout_num/slot.
+
+ normal return: ONIG_NORMAL
+ 1: not yet set (type is ONIG_TYPE_VOID)
+ < 0: error code
+
+
+# int onig_get_callout_data_by_callout_args_self(OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val)
+
+ Returns self callout data value/type.
+
+ normal return: ONIG_NORMAL
+ 1: not yet set (type is ONIG_TYPE_VOID)
+ < 0: error code
+
+
+# int onig_set_callout_data_by_callout_args(OnigCalloutArgs* args, int callout_num, int slot, OnigType type, OnigValue* val)
+
+ Set the callout data value/type for a callout slot indicated by callout_num/slot.
+
+ normal return: ONIG_NORMAL
+ < 0: error code
+
+
+# int onig_set_callout_data_by_callout_args_self(OnigCalloutArgs* args, int slot, OnigType type, OnigValue* val)
+
+ Set self callout data value/type for a callout slot indicated by slot.
+
+ normal return: ONIG_NORMAL
+ < 0: error code
+
+
+# int onig_get_callout_data_by_callout_args_self_dont_clear_old(OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val)
+
+ This function is almost same as onig_get_callout_data_by_callout_args_self().
+ But this function doesn't clear values which set in previous failed match process.
+ Other onig_get_callout_data_xxxx() functions clear all values which set
+ in previous failed match process.
+
+ For example, Builtin callout (*TOTAL_COUNT) is implemented by using this
+ function for accumulate count of all of match processes in a search process.
+ Builtin callout (*COUNT) returns count in last success match process only,
+ because it doesn't use this function.
+
+
+(8) Callout data (used in apllications)
+
+# int onig_get_callout_data(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ Returns the callout data value/type for a callout slot indicated by
+ callout_num/slot.
+
+ normal return: ONIG_NORMAL
+ 1: not yet set (type is ONIG_TYPE_VOID)
+ < 0: error code
+
+
+# int onig_get_callout_data_by_tag(OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType* type, OnigValue* val)
+
+ Returns the callout data value/type for a callout slot indicated by tag/slot.
+
+ normal return: ONIG_NORMAL
+ 1: not yet set (type is ONIG_TYPE_VOID)
+ < 0: error code
+
+
+# int onig_set_callout_data(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType type, OnigValue* val)
+
+ Set the callout data value/type for a callout slot indicated by callout_num/slot.
+
+ normal return: ONIG_NORMAL
+ < 0: error code
+
+
+# int onig_set_callout_data_by_tag(OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType type, OnigValue* val)
+
+ Set the callout data value/type for a callout slot indicated by tag/slot.
+
+ normal return: ONIG_NORMAL
+ < 0: error code
+
+
+# int onig_get_callout_data_dont_clear_old(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ No needs to use this function.
+ It will be abolished.
+
+
+
+(9) Miscellaneous functions
+
+# OnigUChar* onig_get_callout_name_by_name_id(int name_id)
+
+ Returns callout name of the name id.
+ if invalid name id is passed, return 0.
+
+
+# int onig_get_capture_range_in_callout(OnigCalloutArgs* args, int mem_num, int* begin, int* end)
+
+ Returns current capture range position.
+ Position is byte length offset from subject string.
+ For uncaptured mem_num, ONIG_REGION_NOTPOS is set.
+
+
+# int onig_get_used_stack_size_in_callout(OnigCalloutArgs* args, int* used_num, int* used_bytes)
+
+ Returns current used match-stack size.
+
+ used_num: number of match-stack elements
+ used_bytes: used byte size of match-stack
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API.ja b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API.ja
new file mode 100644
index 000000000..c56555ad1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.API.ja
@@ -0,0 +1,382 @@
+Callouts API Version 6.8.2 2018/06/08
+
+#include <oniguruma.h>
+
+(1) 呼ã³å‡ºã—関数
+(2) 内容ã®å‘¼ã³å‡ºã—関数ã®è¨­å®š/å–å¾—
+(3) åå‰ã®å‘¼ã³å‡ºã—関数ã®è¨­å®š
+(4) ユーザデータ
+(5) OnigCalloutArgsã‹ã‚‰ã®å€¤ã®å–å¾—
+(6) å札
+(7) 呼ã³å‡ºã—データ (呼ã³å‡ºã—関数内ã‹ã‚‰ä½¿ç”¨ã•ã‚Œã‚‹)
+(8) 呼ã³å‡ºã—データ (アプリケーションã‹ã‚‰ä½¿ç”¨ã•ã‚Œã‚‹)
+(9) ãã®ä»–ã®é–¢æ•°
+
+
+(1) 呼ã³å‡ºã—関数
+
+ åž‹: OnigCalloutFunc
+
+ typedef int (*OnigCalloutFunc)(OnigCalloutArgs* args, void* user_data);
+
+ è‹¥ã—呼ã³å‡ºã—関数ã¨ã—ã¦ï¼(NULL)ãŒã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã¨ã€å‘¼ã°ã‚Œã‚‹ã“ã¨ã¯ãªã„
+
+
+ * 呼ã³å‡ºã—関数ã®æˆ»ã‚Šå€¤ (int)
+
+ ONIG_CALLOUT_FAIL (== 1): 失敗
+ ONIG_CALLOUT_SUCCESS (== 0): æˆåŠŸ
+ -1未満: エラーコード (検索/ç…§åˆã®çµ‚了)
+
+ ONIG_CALLOUT_FAIL/SUCCESSã¯ã€å¾Œé€€ä¸­ã®å‘¼ã³å‡ºã—ã§ã¯ç„¡è¦–ã•ã‚Œã‚‹ã€‚
+ 後退ã¯å¤±æ•—ã®å›žå¾©éŽç¨‹ãªã®ã§ã€‚
+
+ * 呼ã³å‡ºã—関数ã®ä¾‹
+
+ extern int always_success(OnigCalloutArgs* args, void* user_data)
+ {
+ return ONIG_CALLOUT_SUCCESS;
+ }
+
+
+
+(2) 内容ã®å‘¼ã³å‡ºã—関数ã®è¨­å®š/å–å¾—
+
+# OnigCalloutFunc onig_get_progress_callout(void)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(å‰é€²ä¸­)ã‚’è¿”ã™
+
+
+# int onig_set_progress_callout(OnigCalloutFunc f)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(å‰é€²ä¸­)をセットã™ã‚‹ã€‚
+ ã“ã®å€¤ã¯onig_initialize_match_param()ã®ä¸­ã§ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å‘¼ã³å‡ºã—関数ã¨ã—ã¦
+ セットã•ã‚Œã‚‹ã€‚
+
+ 正常終了: ONIG_NORMAL
+
+
+# OnigCalloutFunc onig_get_retraction_callout(void)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(後退中)ã‚’è¿”ã™
+
+
+# int onig_set_retraction_callout(OnigCalloutFunc f)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(後退中)をセットã™ã‚‹ã€‚
+ ã“ã®å€¤ã¯onig_initialize_match_param()ã®ä¸­ã§ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å‘¼ã³å‡ºã—関数ã¨ã—ã¦
+ セットã•ã‚Œã‚‹ã€‚
+
+ 正常終了: ONIG_NORMAL
+
+
+# int onig_set_progress_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(å‰é€²ä¸­)をセットã™ã‚‹ã€‚
+
+ 引数
+ 1 mp: match-paramアドレス
+ 2 f: 関数
+
+ 正常終了: ONIG_NORMAL
+
+
+# int onig_set_retraction_callout_of_match_param(OnigMatchParam* mp, OnigCalloutFunc f)
+
+ 内容ã®å‘¼ã³å‡ºã—関数(後退中)をセットã™ã‚‹ã€‚
+
+ 引数
+ 1 mp: match-paramアドレス
+ 2 f: 関数
+
+ 正常終了: ONIG_NORMAL
+
+
+
+(3) åå‰ã®å‘¼ã³å‡ºã—関数ã®è¨­å®š
+
+# int onig_set_callout_of_name(OnigEncoding enc, OnigCalloutType type, OnigUChar* name, OnigUChar* name_end, int callout_in, OnigCalloutFunc callout, OnigCalloutFunc end_callout, int arg_num, unsigned int arg_types[], int opt_arg_num, OnigValue opt_defaults[])
+
+ åå‰ã®å‘¼ã³å‡ºã—関数をセットã™ã‚‹ã€‚
+ åå‰ã«è¨±ã•ã‚Œã‚‹æ–‡å­—: _ A-Z a-z 0-9 (* 最åˆã®æ–‡å­—: _ A-Z a-z)
+
+ (enc, name)ã®ãƒšã‚¢ãŒã€å‘¼ã³å‡ºã—関数を見ã¤ã‘ã‚‹ãŸã‚ã®ã‚­ãƒ¼ã¨ã—ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã€‚
+ アプリケーションã§ä½¿ç”¨ã•ã‚Œã‚‹å„エンコーディングã«å¯¾ã—ã¦ã“ã®é–¢æ•°ã‚’呼ã¶å¿…è¦ãŒã‚る。
+ ã—ã‹ã—è‹¥ã—encエンコーディングãŒASCII互æ›ã§ã‚ã‚Šã€(enc, name)ã«å¯¾ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒ
+ 見ã¤ã‹ã‚‰ãªã„å ´åˆã«ã¯ã€(ASCII, name)エントリãŒå‚ç…§ã•ã‚Œã‚‹ã€‚
+ 従ã£ã¦ã€è‹¥ã—ASCII互æ›ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã®ã¿ä½¿ç”¨ã—ã¦ã„ã‚‹å ´åˆã«ã¯ã€ã“ã®é–¢æ•°ã‚’(ASCII, name)
+ ã«ã¤ã„ã¦ä¸€å›žå‘¼ã¹ã°å分ã§ã‚る。
+
+ 引数
+ 1 enc: 文字エンコーディング
+ 2 type: 呼ã³å‡ºã—åž‹ (ç¾åœ¨ã¯ ONIG_CALLOUT_TYPE_SINGLE ã®ã¿ã‚µãƒãƒ¼ãƒˆ)
+ 3 name: åå‰ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ (encã§ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã•ã‚Œã¦ã„る文字列)
+ 4 name_end: åå‰ã®çµ‚端アドレス
+ 5 callout_in: æ–¹å‘フラグ (ONIG_CALLOUT_IN_PROGRESS/RETRACTION/BOTH)
+ 6 callout: 呼ã³å‡ºã—関数
+ 7 end_callout: *ã¾ã ä½¿ç”¨ã—ã¦ã„ãªã„ (ï¼ã‚’セット)
+ 8 arg_num: 引数ã®æ•° (* 最大値 ONIG_CALLOUT_MAX_ARGS_NUM == 4)
+ 9 arg_types: 引数ã®åž‹ã®é…列
+ 10 opt_arg_num: オプション引数ã®æ•°
+ 11 opt_defaults: オプション引数ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤
+
+ 正常終了: ONIG_NORMAL
+ error:
+ ONIGERR_INVALID_CALLOUT_NAME
+ ONIGERR_INVALID_ARGUMENT
+ ONIGERR_INVALID_CALLOUT_ARG
+
+
+
+(4) ユーザデータ
+
+# int onig_set_callout_user_data_of_match_param(OnigMatchParam* param, void* user_data)
+
+ 呼ã³å‡ºã—関数ã®å¼•æ•°ã¨ã—ã¦æ¸¡ã•ã‚Œã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ‡ãƒ¼ã‚¿ã‚’セットã™ã‚‹ã€‚
+
+ 正常終了: ONIG_NORMAL
+
+
+
+(5) OnigCalloutArgsã‹ã‚‰ã®å€¤ã®å–å¾—
+
+# int onig_get_callout_num_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®å‘¼ã³å‡ºã—番å·ã‚’è¿”ã™ã€‚
+ "呼ã³å‡ºã—番å·"ã¨ã¯ã€æ­£è¦è¡¨ç¾ãƒ‘ターンã®ä¸­ã®å‘¼ã³å‡ºã—ã«å¯¾ã™ã‚‹è­˜åˆ¥å­ã§ã‚る。
+
+
+# OnigCalloutIn onig_get_callout_in_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ãŒèµ·ããŸæ™‚ã®æ–¹å‘(å‰é€²ä¸­/後退中)ã‚’è¿”ã™ã€‚
+ (ONIG_CALLOUT_IN_PROGRESS ã‹ ONIG_CALLOUT_IN_RETRACTION)
+
+
+# int onig_get_name_id_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®åå‰(name)ã®è­˜åˆ¥å­ã‚’è¿”ã™ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒå†…容ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€ONIG_NON_NAME_IDãŒè¿”ã•ã‚Œã‚‹ã€‚
+
+
+# const OnigUChar* onig_get_contents_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®å†…容文字列(NULL終端ã‚ã‚Š)ã‚’è¿”ã™ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒåå‰ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€NULLã‚’è¿”ã™ã€‚
+
+
+# const OnigUChar* onig_get_contents_end_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®å†…容(contents)ã®çµ‚端を返ã™ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒåå‰ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€NULLã‚’è¿”ã™ã€‚
+
+
+# int onig_get_args_num_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®å¼•æ•°ã®æ•°ã‚’è¿”ã™ã€‚
+ æ­£è¦è¡¨ç¾ãƒ‘ターンã®ä¸­ã§æ¸¡ã•ã‚Œãªã‹ã£ãŸã‚ªãƒ—ション引数もå«ã‚€ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒå†…容ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€ONIGERR_INVALID_ARGUMENTãŒè¿”ã•ã‚Œã‚‹ã€‚
+
+
+# int onig_get_passed_args_num_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®æœ¬å½“ã«æ¸¡ã•ã‚ŒãŸå¼•æ•°ã®æ•°ã‚’è¿”ã™ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒå†…容ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€ONIGERR_INVALID_ARGUMENTãŒè¿”ã•ã‚Œã‚‹ã€‚
+
+
+# int onig_get_arg_by_callout_args(OnigCalloutArgs* args, int index, OnigType* type, OnigValue* val)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®ä¸€å€‹ã®å¼•æ•°ã®å€¤ã¨åž‹ã‚’è¿”ã™ã€‚
+ è‹¥ã—ã“ã®å‘¼ã³å‡ºã—ãŒå†…容ã®å‘¼ã³å‡ºã—ã®ã¨ãã«ã¯ã€ONIGERR_INVALID_ARGUMENTãŒè¿”ã•ã‚Œã‚‹ã€‚
+
+ 正常終了: ONIG_NORMAL
+
+
+# const OnigUChar* onig_get_string_by_callout_args(OnigCalloutArgs* args)
+
+ 対象文字列ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+ onig_search()ã®äºŒç•ªç›®ã®å¼•æ•°(str)ã§ã‚る。
+
+
+# const OnigUChar* onig_get_string_end_by_callout_args(OnigCalloutArgs* args)
+
+ 対象文字列ã®çµ‚端アドレスを返ã™ã€‚
+ onig_search()ã®ä¸‰ç•ªç›®ã®å¼•æ•°(end)ã§ã‚る。
+
+
+# const OnigUChar* onig_get_start_by_callout_args(OnigCalloutArgs* args)
+
+ 対象文字列ã®ç¾åœ¨ã®ç…§åˆå‡¦ç†é–‹å§‹ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+
+# const OnigUChar* onig_get_right_range_by_callout_args(OnigCalloutArgs* args)
+
+ 対象文字列ã®ç¾åœ¨ã®ç…§åˆç¯„囲アドレスを返ã™ã€‚
+
+
+# const OnigUChar* onig_get_current_by_callout_args(OnigCalloutArgs* args)
+
+ 対象文字列ã®ç¾åœ¨ã®ç…§åˆä½ç½®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+
+# OnigRegex onig_get_regex_by_callout_args(OnigCalloutArgs* args)
+
+ ã“ã®å‘¼ã³å‡ºã—ã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+
+# unsigned long onig_get_retry_counter_by_callout_args(OnigCalloutArgs* args)
+
+ retry-limit-in-matchã®ãŸã‚ã®ãƒªãƒˆãƒ©ã‚¤ã‚«ã‚¦ãƒ³ã‚¿ã®ç¾åœ¨å€¤ã‚’è¿”ã™ã€‚
+
+
+
+(6) å札
+
+ "Tag" (å札)ã¨ã¯ã€æ­£è¦è¡¨ç¾ãƒ‘ターンã®ä¸­ã§å‘¼ã³å‡ºã—ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸåå‰ã§ã‚る。
+ tag文字列ã«ä½¿ç”¨ã§ãる文字: _ A-Z a-z 0-9 (* 先頭ã®æ–‡å­—: _ A-Z a-z)
+
+
+# int onig_callout_tag_is_exist_at_callout_num(OnigRegex reg, int callout_num)
+
+ ãã®å‘¼ã³å‡ºã—ã«tagãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ã‚Œã°1ã‚’è¿”ã™ã€ãã†ã§ãªã‘ã‚Œã°0ã‚’è¿”ã™ã€‚
+
+
+# const OnigUChar* onig_get_callout_tag_start(OnigRegex reg, int callout_num)
+
+ ãã®å‘¼ã³å‡ºã—ã«å¯¾ã™ã‚‹tag文字列(NULL終端ã‚ã‚Š)ã®å…ˆé ­ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’è¿”ã™ã€‚
+
+
+# const OnigUChar* onig_get_callout_tag_end(OnigRegex reg, int callout_num)
+
+ ãã®å‘¼ã³å‡ºã—ã«å¯¾ã™ã‚‹tag文字列ã®çµ‚端アドレスを返ã™ã€‚
+
+
+# int onig_get_callout_num_by_tag(OnigRegex reg, const OnigUChar* tag, const OnigUChar* tag_end)
+
+ ãã®tagã«å¯¾ã™ã‚‹å‘¼ã³å‡ºã—番å·ã‚’è¿”ã™ã€‚
+
+
+
+(7) 呼ã³å‡ºã—データ (呼ã³å‡ºã—関数内ã‹ã‚‰ä½¿ç”¨ã•ã‚Œã‚‹)
+
+ "呼ã³å‡ºã—データ" (callout data)ã¨ã¯ã€
+ ãã‚Œãžã‚Œã®å‘¼ã³å‡ºã—ã«å¯¾ã—ã¦ãã‚Œãžã‚Œã®æ¤œç´¢å‡¦ç†ã®ä¸­ã§å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸã€
+ ONIG_CALLOUT_DATA_SLOT_NUM(== 5)個ã®å€¤ã®é ˜åŸŸã§ã‚る。
+ 一個ã®å‘¼ã³å‡ºã—ã«å¯¾ã™ã‚‹å„値ã®é ˜åŸŸã¯ã€"スロット"(slot)番å·(0 - 4)ã«ã‚ˆã£ã¦ç¤ºã•ã‚Œã‚‹ã€‚
+ 呼ã³å‡ºã—データã¯å‘¼ã³å‡ºã—関数ã®å®Ÿè£…者ã«ã‚ˆã£ã¦ä»»æ„ã®ç›®çš„ã«ä½¿ç”¨ã•ã‚Œã‚‹ã€‚
+
+
+# int onig_get_callout_data_by_callout_args(OnigCalloutArgs* args, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ callout_num/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®å€¤/åž‹ã‚’è¿”ã™ã€‚
+
+ 正常終了: ONIG_NORMAL
+ 1: 値ãŒæœªã‚»ãƒƒãƒˆ (type㯠ONIG_TYPE_VOID)
+ < 0: エラーコード
+
+
+# int onig_get_callout_data_by_callout_args_self(OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val)
+
+ 自分自身ã®å‘¼ã³å‡ºã—ã®slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸã‚¹ãƒ­ãƒƒãƒˆã«å¯¾ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®å€¤/åž‹ã‚’è¿”ã™ã€‚
+
+ 正常終了: ONIG_NORMAL
+ 1: 値ãŒæœªã‚»ãƒƒãƒˆ (type㯠ONIG_TYPE_VOID)
+ < 0: エラーコード
+
+
+# int onig_set_callout_data_by_callout_args(OnigCalloutArgs* args, int callout_num, int slot, OnigType type, OnigValue* val)
+
+ callout_num/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹å€¤/型をセットã™ã‚‹ã€‚。
+
+ 正常終了: ONIG_NORMAL
+ < 0: エラーコード
+
+
+# int onig_set_callout_data_by_callout_args_self(OnigCalloutArgs* args, int slot, OnigType type, OnigValue* val)
+
+ 自分自身ã®å‘¼ã³å‡ºã—ã®slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸã‚¹ãƒ­ãƒƒãƒˆã«å¯¾ã™ã‚‹å€¤/型をセットã™ã‚‹ã€‚。
+
+ 正常終了: ONIG_NORMAL
+ < 0: エラーコード
+
+
+# int onig_get_callout_data_by_callout_args_self_dont_clear_old(OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val)
+
+ ã“ã®é–¢æ•°ã¯ã€onig_get_callout_data_by_callout_args_self()ã¨ã»ã¼åŒã˜ã§ã‚る。
+ ã—ã‹ã—ã“ã®é–¢æ•°ã¯ã€ç¾åœ¨ã®ç…§åˆå‡¦ç†ä»¥å‰ã®å¤±æ•—ã—ãŸç…§åˆå‡¦ç†ã®ä¸­ã§ã‚»ãƒƒãƒˆã•ã‚ŒãŸå€¤ã‚’
+ クリアã—ãªã„。
+ ä»–ã®onig_get_callout_data_xxxx()関数ã¯ã€ä»¥å‰ã®å¤±æ•—ã—ãŸç…§åˆå‡¦ç†ã®ä¸­ã§ã‚»ãƒƒãƒˆã•ã‚ŒãŸå€¤ã‚’
+ クリアã™ã‚‹ã€‚
+
+ 例ãˆã°ã€çµ„ã¿è¾¼ã¿å‘¼ã³å‡ºã—(*TOTAL_COUNT)ã¯ã€æ¤œç´¢å‡¦ç†ã®ä¸­ã®å…¨ã¦ã®ç…§åˆå‡¦ç†ã®ç©ç®—カウントを
+ å¾—ã‚‹ãŸã‚ã«ã“ã®é–¢æ•°ã‚’使用ã—ã¦å®Ÿè£…ã•ã‚Œã¦ã„る。
+ 組ã¿è¾¼ã‚€å‘¼ã³å‡ºã—(*COUNT)ã¯ã€ã“ã®é–¢æ•°ã‚’使用ã—ãªã„ã®ã§ã€æœ€å¾Œã®æˆåŠŸã—ãŸç…§åˆå‡¦ç†ã ã‘ã®
+ カウントを返ã™ã€‚
+
+
+
+(8) 呼ã³å‡ºã—データ (アプリケーションã‹ã‚‰ä½¿ç”¨ã•ã‚Œã‚‹)
+
+# int onig_get_callout_data(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ callout_num/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®å€¤/åž‹ã‚’è¿”ã™ã€‚
+
+ 正常終了: ONIG_NORMAL
+ 1: 値ãŒæœªã‚»ãƒƒãƒˆ (type㯠ONIG_TYPE_VOID)
+ < 0: エラーコード
+
+
+# int onig_get_callout_data_by_tag(OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType* type, OnigValue* val)
+
+ tag/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®å€¤/åž‹ã‚’è¿”ã™ã€‚
+
+ 正常終了: ONIG_NORMAL
+ 1: 値ãŒæœªã‚»ãƒƒãƒˆ (type㯠ONIG_TYPE_VOID)
+ < 0: エラーコード
+
+
+# int onig_set_callout_data(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType type, OnigValue* val)
+
+ callout_num/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹å€¤/型をセットã™ã‚‹ã€‚。
+
+ 正常終了: ONIG_NORMAL
+ < 0: エラーコード
+
+
+# int onig_set_callout_data_by_tag(OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType type, OnigValue* val)
+
+ tag/slotã«ã‚ˆã£ã¦ç¤ºã•ã‚ŒãŸå‘¼ã³å‡ºã—スロットã«å¯¾ã™ã‚‹å€¤/型をセットã™ã‚‹ã€‚。
+
+ 正常終了: ONIG_NORMAL
+ < 0: エラーコード
+
+
+# int onig_get_callout_data_dont_clear_old(OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val)
+
+ ã“ã®é–¢æ•°ã‚’使用ã™ã‚‹å¿…è¦ã¯ãªã„ã¨æ€ã‚れる。
+ 廃止予定。
+
+
+
+(9) ãã®ä»–ã®é–¢æ•°
+
+# OnigUChar* onig_get_callout_name_by_name_id(int name_id)
+
+ åå‰ã®è­˜åˆ¥å­ã«å¯¾ã™ã‚‹åå‰ã‚’è¿”ã™ã€‚
+ ä¸æ­£ãªè­˜åˆ¥å­ãŒæ¸¡ã•ã‚ŒãŸå ´åˆã«ã¯ï¼ã‚’è¿”ã™ã€‚
+
+
+# int onig_get_capture_range_in_callout(OnigCalloutArgs* args, int mem_num, int* begin, int* end)
+
+ ç¾åœ¨ã®æ•ç²ç¯„囲を返ã™ã€‚
+ ä½ç½®ã¯ã€å¯¾è±¡æ–‡å­—列ã«å¯¾ã™ã‚‹ãƒã‚¤ãƒˆå˜ä½ã§è¡¨ã•ã‚Œã‚‹ã€‚
+ 未æ•ç²ã®mem_numã«å¯¾ã—ã¦ã¯ã€ONIG_REGION_NOTPOSãŒã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã€‚
+
+
+# int onig_get_used_stack_size_in_callout(OnigCalloutArgs* args, int* used_num, int* used_bytes)
+
+ ç¾åœ¨ä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹ç…§åˆå‡¦ç†ç”¨ã‚¹ã‚¿ãƒƒã‚¯ã‚µã‚¤ã‚ºã‚’è¿”ã™ã€‚
+
+ used_num: è¦ç´ æ•°
+ used_bytes: ãƒã‚¤ãƒˆæ•°
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN
new file mode 100644
index 000000000..26840e74c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN
@@ -0,0 +1,95 @@
+CALLOUTS.BUILTIN 2018/03/26
+
+
+* FAIL (progress)
+
+ (*FAIL)
+
+ Always fail.
+
+
+* MISMATCH (progress)
+
+ (*MISMATCH)
+
+ Terminates Match process.
+ Continues Search process.
+
+
+* ERROR (progress)
+
+ (*ERROR{n::LONG})
+
+ Terminates Search/Match process.
+
+ Return value is the argument 'n'. (The value must be less than -1)
+ 'n' is an optional argument. (default value is ONIG_ABORT)
+
+
+* MAX (progress/retraction)
+
+ (*MAX{n::LONG/TAG, c::CHAR})
+
+ Restricts the maximum count of success(default), progress or retraction.
+ If 'n' type is tag, slot 0 value of the tag are used.
+ Depends on 'c' argument, the slot 0 value changes.
+ 'c' is an optional argument, default value is 'X'.
+
+ (* success count = progress count - retraction count)
+
+
+ ex. "(?:(*COUNT[T]{X})a)*(?:(*MAX{T})c)*"
+
+ [callout data]
+ slot 0: '>': progress count, '<': retraction count, 'X': success count (default)
+
+
+* COUNT (progress/retraction)
+
+ (*COUNT{c::CHAR})
+
+ Counter.
+ Depends on 'c' argument, the slot 0 value changes.
+ 'c' is an optional argument, default value is '>'.
+
+ [callout data]
+ slot 0: '>': progress count (default), '<': retraction count, 'X': success count
+ slot 1: progress count
+ slot 2: retraction count
+
+ ** If option ONIG_OPTION_FIND_LONGEST or ONIG_OPTION_FIND_NOT_EMPTY is used,
+ counts are not accurate.
+
+
+* TOTAL_COUNT (progress/retraction)
+
+ (*TOTAL_COUNT{c::CHAR})
+
+ It's the almost same as COUNT.
+ But the counts are integrated in a search process.
+ 'c' is an optional argument, default value is '>'.
+
+ [callout data]
+ slot 0: '>': progress count (default), '<': retraction count, 'X': success count
+ slot 1: progress count
+ slot 2: retraction count
+
+ ** If option ONIG_OPTION_FIND_LONGEST or ONIG_OPTION_FIND_NOT_EMPTY is used,
+ counts are not accurate.
+
+
+* CMP (progress)
+
+ (*CMP{x::TAG/LONG, op::STRING, y::TAG/LONG})
+
+ Compares x value and y value with op operator.
+ If x and y types are tag, slot 0 value of the tag are used.
+
+ op: '==', '!=', '>', '<', '>=', '<='
+
+ ex. "(?:(*MAX[TA]{7})a|(*MAX[TB]{5})b)*(*CMP{TA,>=,4})"
+
+ [callout data]
+ slot 0: op value (enum OP_CMP in src/regexec.c)
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN.ja b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN.ja
new file mode 100644
index 000000000..d371beb6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/CALLOUTS.BUILTIN.ja
@@ -0,0 +1,93 @@
+CALLOUTS.BUILTIN.ja 2018/03/26
+
+
+* FAIL (å‰é€²)
+
+ (*FAIL)
+
+ 常ã«å¤±æ•—ã™ã‚‹
+
+
+* MISMATCH (å‰é€²)
+
+ (*MISMATCH)
+
+ ç…§åˆã‚’中止ã™ã‚‹
+ 検索ã¯ç¶™ç¶šã™ã‚‹
+
+
+* ERROR (å‰é€²)
+
+ (*ERROR{n::LONG})
+
+ 検索/ç…§åˆã‚’中止ã™ã‚‹
+ 戻り値ã¯å¼•æ•°'n'ã®å€¤ã€‚(-1よりå°ã•ã„è² ã®å€¤ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„)
+ 'n'ã¯ã‚ªãƒ—ション引数ã§ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã¯ONIG_ABORT
+
+
+* MAX (å‰é€²/後退)
+
+ (*MAX{n::LONG/TAG, c::CHAR})
+
+ æˆåŠŸ(デフォルト)ã€å‰é€²ã¾ãŸã¯å¾Œé€€å›žæ•°ã‚’制é™ã™ã‚‹
+ 'n'ãŒTAGã®ã¨ãã¯ã€ãã®TAGã®calloutã®slot 0ã®å€¤ãŒä½¿ç”¨ã•ã‚Œã‚‹
+ 'c'引数ã®å€¤ã«ã‚ˆã£ã¦ã€slot 0ã®å€¤ãŒå¤‰åŒ–ã™ã‚‹
+ 'c'ã¯ã‚ªãƒ—ション引数ã§ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã¯'X'
+
+ 例: "(?:(*COUNT[T]{X})a)*(?:(*MAX{T})c)*"
+
+ [callout data]
+ slot 0: '>': å‰é€²å›žæ•°, '<': 後退回数, 'X': æˆåŠŸå›žæ•°(デフォルト)
+
+
+* COUNT (å‰é€²/後退)
+
+ (*COUNT{c::CHAR})
+
+ カウンタ
+ 'c'引数ã®å€¤ã«ã‚ˆã£ã¦ã€slot 0ã®å€¤ãŒå¤‰åŒ–ã™ã‚‹
+ 'c'ã¯ã‚ªãƒ—ション引数ã§ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã¯'>'
+
+ [callout data]
+ slot 0: '>': å‰é€²å›žæ•°(デフォルト), '<': 後退回数, 'X': æˆåŠŸå›žæ•°
+ slot 1: å‰é€²å›žæ•°
+ slot 2: 後退回数
+
+ (* æˆåŠŸå›žæ•° = å‰é€²å›žæ•° - 後退回数)
+
+ ** ONIG_OPTION_FIND_LONGEST ã¾ãŸã¯ ONIG_OPTION_FIND_NOT_EMPTY ãŒä½¿ç”¨ã•ã‚Œã‚‹ã¨
+ 正確ãªå‹•ä½œãŒã§ããªããªã‚‹
+
+
+* TOTAL_COUNT (å‰é€²/後退)
+
+ (*TOTAL_COUNT{c::CHAR})
+
+ ã“ã‚Œã¯COUNTã¨ã»ã¨ã‚“ã©åŒã˜
+ ã—ã‹ã—ã€ã‚«ã‚¦ãƒ³ãƒˆãŒæ¤œç´¢éŽç¨‹ã§ç©ç®—ã•ã‚Œã‚‹
+ 'c'ã¯ã‚ªãƒ—ション引数ã§ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã¯'>'
+
+ [callout data]
+ slot 0: '>': å‰é€²å›žæ•°(デフォルト), '<': 後退回数, 'X': æˆåŠŸå›žæ•°
+ slot 1: å‰é€²å›žæ•°
+ slot 2: 後退回数
+
+ ** ONIG_OPTION_FIND_LONGEST ã¾ãŸã¯ ONIG_OPTION_FIND_NOT_EMPTY ãŒä½¿ç”¨ã•ã‚Œã‚‹ã¨
+ 正確ãªå‹•ä½œãŒã§ããªããªã‚‹
+
+
+* CMP (å‰é€²)
+
+ (*CMP{x::TAG/LONG, op::STRING, y::TAG/LONG})
+
+ xã®å€¤ã¨yã®å€¤ã‚’op演算å­ã§æ¯”較ã™ã‚‹
+ x, yãŒTAGã®ã¨ãã«ã¯ãã®calloutã®slot 0ã®å€¤ãŒå‚ç…§ã•ã‚Œã‚‹
+
+ op: '==', '!=', '>', '<', '>=', '<='
+
+ 例: "(?:(*MAX[TA]{7})a|(*MAX[TB]{5})b)*(*CMP{TA,>=,4})"
+
+ [callout data]
+ slot 0: op値 (src/regexec.c ã®ä¸­ã® enum OP_CMP)
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ
new file mode 100644
index 000000000..dfbd7fac7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ
@@ -0,0 +1,12 @@
+FAQ 2006/11/14
+
+1. Longest match
+
+ You can execute the longest match by using ONIG_OPTION_FIND_LONGEST option
+ in onig_new().
+
+2. Mailing list
+
+ There is no mailing list for Oniguruma.
+
+// END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ.ja b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ.ja
new file mode 100644
index 000000000..ffb25f4a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/FAQ.ja
@@ -0,0 +1,22 @@
+FAQ 2016/04/06
+
+1. 最長マッãƒ
+
+ onig_new()ã®ä¸­ã§ã€ONIG_OPTION_FIND_LONGESTオプション
+ を使用ã™ã‚Œã°æœ€é•·ãƒžãƒƒãƒã«ãªã‚‹ã€‚
+
+
+2. CR + LF
+
+ DOSã®æ”¹è¡Œ(CR(0x0c) + LF(0x0a)ã®é€£ç¶š)
+
+ regenc.hã®ä¸­ã®ã€ä»¥ä¸‹ã®éƒ¨åˆ†ã‚’有効ã«ã™ã‚‹ã€‚
+
+ /* #define USE_CRNL_AS_LINE_TERMINATOR */
+
+
+3. メーリングリスト
+
+ 鬼車ã«é–¢ã™ã‚‹ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã¯å­˜åœ¨ã—ãªã„。
+
+//END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE
new file mode 100644
index 000000000..4561698a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE
@@ -0,0 +1,578 @@
+Oniguruma Regular Expressions Version 6.9.5 2020/01/28
+
+syntax: ONIG_SYNTAX_ONIGURUMA (default)
+
+
+1. Syntax elements
+
+ \ escape (enable or disable meta character)
+ | alternation
+ (...) group
+ [...] character class
+
+
+2. Characters
+
+ \t horizontal tab (0x09)
+ \v vertical tab (0x0B)
+ \n newline (line feed) (0x0A)
+ \r carriage return (0x0D)
+ \b backspace (0x08)
+ \f form feed (0x0C)
+ \a bell (0x07)
+ \e escape (0x1B)
+ \nnn octal char (encoded byte value)
+ \o{17777777777} wide octal char (character code point value)
+ \uHHHH wide hexadecimal char (character code point value)
+ \xHH hexadecimal char (encoded byte value)
+ \x{7HHHHHHH} wide hexadecimal char (character code point value)
+ \cx control char (character code point value)
+ \C-x control char (character code point value)
+ \M-x meta (x|0x80) (character code point value)
+ \M-\C-x meta control char (character code point value)
+
+ (* \b as backspace is effective in character class only)
+
+
+3. Character types
+
+ . any character (except newline)
+
+ \w word character
+
+ Not Unicode:
+ alphanumeric, "_" and multibyte char.
+
+ Unicode:
+ General_Category -- (Letter|Mark|Number|Connector_Punctuation)
+
+ \W non-word char
+
+ \s whitespace char
+
+ Not Unicode:
+ \t, \n, \v, \f, \r, \x20
+
+ Unicode case:
+ U+0009, U+000A, U+000B, U+000C, U+000D, U+0085(NEL),
+ General_Category -- Line_Separator
+ -- Paragraph_Separator
+ -- Space_Separator
+
+ \S non-whitespace char
+
+ \d decimal digit char
+
+ Unicode: General_Category -- Decimal_Number
+
+ \D non-decimal-digit char
+
+ \h hexadecimal digit char [0-9a-fA-F]
+
+ \H non-hexdigit char
+
+ \R general newline (* can't be used in character-class)
+ "\r\n" or \n,\v,\f,\r (* but doesn't backtrack from \r\n to \r)
+
+ Unicode case:
+ "\r\n" or \n,\v,\f,\r or U+0085, U+2028, U+2029
+
+ \N negative newline (?-m:.)
+
+ \O true anychar (?m:.) (* original function)
+
+ \X Text Segment \X === (?>\O(?:\Y\O)*)
+
+ The meaning of this operator changes depending on the setting of
+ the option (?y{..}).
+
+ \X doesn't check whether matching start position is boundary or not.
+ Please write as \y\X if you want to ensure it.
+
+ [Extended Grapheme Cluster mode] (default)
+ Unicode case:
+ See [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+ Not Unicode case: \X === (?>\r\n|\O)
+
+ [Word mode]
+ Currently, this mode is supported in Unicode only.
+ See [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+
+ Character Property
+
+ * \p{property-name}
+ * \p{^property-name} (negative)
+ * \P{property-name} (negative)
+
+ property-name:
+
+ + works on all encodings
+ Alnum, Alpha, Blank, Cntrl, Digit, Graph, Lower,
+ Print, Punct, Space, Upper, XDigit, Word, ASCII
+
+ + works on EUC_JP, Shift_JIS
+ Hiragana, Katakana
+
+ + works on UTF8, UTF16, UTF32
+ See doc/UNICODE_PROPERTIES.
+
+
+
+4. Quantifier
+
+ greedy
+
+ ? 1 or 0 times
+ * 0 or more times
+ + 1 or more times
+ {n,m} (n <= m) at least n but no more than m times
+ {n,} at least n times
+ {,n} at least 0 but no more than n times ({0,n})
+ {n} n times
+
+
+ reluctant
+
+ ?? 0 or 1 times
+ *? 0 or more times
+ +? 1 or more times
+ {n,m}? (n <= m) at least n but not more than m times
+ {n,}? at least n times
+ {,n}? at least 0 but not more than n times (== {0,n}?)
+
+ {n}? is reluctant operator in ONIG_SYNTAX_JAVA and ONIG_SYNTAX_PERL only.
+ (In that case, it doesn't make sense to write so.)
+ In default syntax, /a{n}?/ === /(?:a{n})?/
+
+
+ possessive (greedy and does not backtrack once match)
+
+ ?+ 1 or 0 times
+ *+ 0 or more times
+ ++ 1 or more times
+ {n,m} (n > m) at least m but not more than n times
+
+ {n,m}+, {n,}+, {n}+ are possessive operators in ONIG_SYNTAX_JAVA and
+ ONIG_SYNTAX_PERL only.
+
+ ex. /a*+/ === /(?>a*)/
+
+
+5. Anchors
+
+ ^ beginning of the line
+ $ end of the line
+ \b word boundary
+ \B non-word boundary
+
+ \A beginning of string
+ \Z end of string, or before newline at the end
+ \z end of string
+ \G where the current search attempt begins
+ \K keep (keep start position of the result string)
+
+
+ \y Text Segment boundary
+ \Y Text Segment non-boundary
+
+ The meaning of these operators(\y, \Y) changes depending on the setting
+ of the option (?y{..}).
+
+ [Extended Grapheme Cluster mode] (default)
+ Unicode case:
+ See [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+ Not Unicode:
+ All positions except between \r and \n.
+
+ [Word mode]
+ Currently, this mode is supported in Unicode only.
+ See [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+
+
+6. Character class
+
+ ^... negative class (lowest precedence)
+ x-y range from x to y
+ [...] set (character class in character class)
+ ..&&.. intersection (low precedence, only higher than ^)
+
+ ex. [a-w&&[^c-g]z] ==> ([a-w] AND ([^c-g] OR z)) ==> [abh-w]
+
+ * If you want to use '[', '-', or ']' as a normal character
+ in character class, you should escape them with '\'.
+
+
+ POSIX bracket ([:xxxxx:], negate [:^xxxxx:])
+
+ Not Unicode Case:
+
+ alnum alphabet or digit char
+ alpha alphabet
+ ascii code value: [0 - 127]
+ blank \t, \x20
+ cntrl
+ digit 0-9
+ graph include all of multibyte encoded characters
+ lower
+ print include all of multibyte encoded characters
+ punct
+ space \t, \n, \v, \f, \r, \x20
+ upper
+ xdigit 0-9, a-f, A-F
+ word alphanumeric, "_" and multibyte characters
+
+
+ Unicode Case:
+
+ alnum Letter | Mark | Decimal_Number
+ alpha Letter | Mark
+ ascii 0000 - 007F
+ blank Space_Separator | 0009
+ cntrl Control | Format | Unassigned | Private_Use | Surrogate
+ digit Decimal_Number
+ graph [[:^space:]] && ^Control && ^Unassigned && ^Surrogate
+ lower Lowercase_Letter
+ print [[:graph:]] | [[:space:]]
+ punct Connector_Punctuation | Dash_Punctuation | Close_Punctuation |
+ Final_Punctuation | Initial_Punctuation | Other_Punctuation |
+ Open_Punctuation
+ space Space_Separator | Line_Separator | Paragraph_Separator |
+ U+0009 | U+000A | U+000B | U+000C | U+000D | U+0085
+ upper Uppercase_Letter
+ xdigit U+0030 - U+0039 | U+0041 - U+0046 | U+0061 - U+0066
+ (0-9, a-f, A-F)
+ word Letter | Mark | Decimal_Number | Connector_Punctuation
+
+
+
+7. Extended groups
+
+ (?#...) comment
+
+ (?imxWDSPy-imxWDSP:subexp) option on/off for subexp
+
+ i: ignore case
+ m: multi-line (dot (.) also matches newline)
+ x: extended form
+ W: ASCII only word (\w, \p{Word}, [[:word:]])
+ ASCII only word bound (\b)
+ D: ASCII only digit (\d, \p{Digit}, [[:digit:]])
+ S: ASCII only space (\s, \p{Space}, [[:space:]])
+ P: ASCII only POSIX properties (includes W,D,S)
+ (alnum, alpha, blank, cntrl, digit, graph,
+ lower, print, punct, space, upper, xdigit, word)
+
+ y{?}: Text Segment mode
+ This option changes the meaning of \X, \y, \Y.
+ Currently, this option is supported in Unicode only.
+
+ y{g}: Extended Grapheme Cluster mode (default)
+ y{w}: Word mode
+ See [Unicode Standard Annex #29]
+
+ (?imxWDSPy-imxWDSP) isolated option
+
+ * It makes a group to the next ')' or end of the pattern.
+ /ab(?i)c|def|gh/ == /ab(?i:c|def|gh)/
+
+
+ (?:subexp) non-capturing group
+ (subexp) capturing group
+
+ (?=subexp) look-ahead
+ (?!subexp) negative look-ahead
+
+ (?<=subexp) look-behind
+ (?<!subexp) negative look-behind
+
+ * Cannot use Absent stopper (?~|expr) and Range clear
+ (?~|) operators in look-behind and negative look-behind.
+
+ * In look-behind and negative look-behind, support for
+ ignore-case option is limited. Only supports conversion
+ between single characters. (Does not support conversion
+ of multiple characters in Unicode)
+
+ (?>subexp) atomic group
+ no backtracks in subexp.
+
+ (?<name>subexp), (?'name'subexp)
+ define named group
+ (Each character of the name must be a word character.)
+
+ Not only a name but a number is assigned like a capturing
+ group.
+
+ Assigning the same name to two or more subexps is allowed.
+
+
+ <Callouts>
+
+ * Callouts of contents
+ (?{...contents...}) callout in progress
+ (?{...contents...}D) D is a direction flag char
+ D = 'X': in progress and retraction
+ '<': in retraction only
+ '>': in progress only
+ (?{...contents...}[tag]) tag assigned
+ (?{...contents...}[tag]D)
+
+ * Escape characters have no effects in contents.
+ * contents is not allowed to start with '{'.
+
+ (?{{{...contents...}}}) n times continuations '}' in contents is allowed in
+ (n+1) times continuations {{{...}}}.
+
+ Allowed tag string characters: _ A-Z a-z 0-9 (* first character: _ A-Z a-z)
+
+
+ * Callouts of name
+ (*name)
+ (*name{args...}) with args
+ (*name[tag]) tag assigned
+ (*name[tag]{args...})
+
+ Allowed name string characters: _ A-Z a-z 0-9 (* first character: _ A-Z a-z)
+ Allowed tag string characters: _ A-Z a-z 0-9 (* first character: _ A-Z a-z)
+
+
+ <Absent functions>
+
+ (?~absent) Absent repeater (* proposed by Tanaka Akira)
+ This works like .* (more precisely \O*), but it is
+ limited by the range that does not include the string
+ match with <absent>.
+ This is a written abbreviation of (?~|(?:absent)|\O*).
+ \O* is used as a repeater.
+
+ (?~|absent|exp) Absent expression (* original)
+ This works like "exp", but it is limited by the range
+ that does not include the string match with <absent>.
+
+ ex. (?~|345|\d*) "12345678" ==> "12", "1", ""
+
+ (?~|absent) Absent stopper (* original)
+ After passed this operator, string right range is limited
+ at the point that does not include the string match whth
+ <absent>.
+
+ (?~|) Range clear
+ Clear the effects caused by Absent stoppers.
+
+ * Nested Absent functions are not supported and the behavior
+ is undefined.
+
+
+ <if-then-else>
+
+ (?(condition_exp)then_exp|else_exp) if-then-else
+ (?(condition_exp)then_exp) if-then
+
+ condition_exp can be a backreference number/name or a normal
+ regular expression.
+ When condition_exp is a backreference number/name, both then_exp and
+ else_exp can be omitted.
+ Then it works as a backreference validity checker.
+
+ [ Backreference validity checker ] (* original)
+
+ (?(n)), (?(-n)), (?(+n)), (?(n+level)) ...
+ (?(<n>)), (?('-n')), (?(<+n>)) ...
+ (?(<name>)), (?('name')), (?(<name+level>)) ...
+
+
+
+8. Backreferences
+
+ When we say "backreference a group," it actually means, "re-match the same
+ text matched by the subexp in that group."
+
+ \n \k<n> \k'n' (n >= 1) backreference the nth group in the regexp
+ \k<-n> \k'-n' (n >= 1) backreference the nth group counting
+ backwards from the referring position
+ \k<+n> \k'+n' (n >= 1) backreference the nth group counting
+ forwards from the referring position
+ \k<name> \k'name' backreference a group with the specified name
+
+ When backreferencing with a name that is assigned to more than one groups,
+ the last group with the name is checked first, if not matched then the
+ previous one with the name, and so on, until there is a match.
+
+ * Backreference by number is forbidden if any named group is defined and
+ ONIG_OPTION_CAPTURE_GROUP is not set.
+
+
+ backreference with recursion level
+
+ (n >= 1, level >= 0)
+
+ \k<n+level> \k'n+level'
+ \k<n-level> \k'n-level'
+
+ \k<name+level> \k'name+level'
+ \k<name-level> \k'name-level'
+
+ Destine a group on the recursion level relative to the referring position.
+
+ ex 1.
+
+ /\A(?<a>|.|(?:(?<b>.)\g<a>\k<b>))\z/.match("reee")
+ /\A(?<a>|.|(?:(?<b>.)\g<a>\k<b+0>))\z/.match("reer")
+
+ \k<b+0> refers to the (?<b>.) on the same recursion level with it.
+
+ ex 2.
+
+ r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED)
+ (?<element> \g<stag> \g<content>* \g<etag> ){0}
+ (?<stag> < \g<name> \s* > ){0}
+ (?<name> [a-zA-Z_:]+ ){0}
+ (?<content> [^<&]+ (\g<element> | [^<&]+)* ){0}
+ (?<etag> </ \k<name+1> >){0}
+ \g<element>
+ __REGEXP__
+
+ p r.match("<foo>f<bar>bbb</bar>f</foo>").captures
+
+
+9. Subexp calls ("Tanaka Akira special") (* original function)
+
+ When we say "call a group," it actually means, "re-execute the subexp in
+ that group."
+
+ \g<n> \g'n' (n >= 1) call the nth group
+ \g<0> \g'0' call zero (call the total regexp)
+ \g<-n> \g'-n' (n >= 1) call the nth group counting backwards from
+ the calling position
+ \g<+n> \g'+n' (n >= 1) call the nth group counting forwards from
+ the calling position
+ \g<name> \g'name' call the group with the specified name
+
+ * Left-most recursive calls are not allowed.
+
+ ex. (?<name>a|\g<name>b) => error
+ (?<name>a|b\g<name>c) => OK
+
+ * Calls with a name that is assigned to more than one groups are not
+ allowed.
+
+ * Call by number is forbidden if any named group is defined and
+ ONIG_OPTION_CAPTURE_GROUP is not set.
+
+ * The option status of the called group is always effective.
+
+ ex. /(?-i:\g<name>)(?i:(?<name>a)){0}/.match("A")
+
+
+10. Captured group
+
+ Behavior of an unnamed group (...) changes with the following conditions.
+ (But named group is not changed.)
+
+ case 1. /.../ (named group is not used, no option)
+
+ (...) is treated as a capturing group.
+
+ case 2. /.../g (named group is not used, 'g' option)
+
+ (...) is treated as a non-capturing group (?:...).
+
+ case 3. /..(?<name>..)../ (named group is used, no option)
+
+ (...) is treated as a non-capturing group.
+ numbered-backref/call is not allowed.
+
+ case 4. /..(?<name>..)../G (named group is used, 'G' option)
+
+ (...) is treated as a capturing group.
+ numbered-backref/call is allowed.
+
+ where
+ g: ONIG_OPTION_DONT_CAPTURE_GROUP
+ G: ONIG_OPTION_CAPTURE_GROUP
+
+ ('g' and 'G' options are argued in ruby-dev ML)
+
+
+
+-----------------------------
+A-1. Syntax-dependent options
+
+ + ONIG_SYNTAX_ONIGURUMA
+ (?m): dot (.) also matches newline
+
+ + ONIG_SYNTAX_PERL and ONIG_SYNTAX_JAVA
+ (?s): dot (.) also matches newline
+ (?m): ^ matches after newline, $ matches before newline
+
+
+A-2. Original extensions
+
+ + hexadecimal digit char type \h, \H
+ + true anychar \O
+ + text segment boundary \y, \Y
+ + backreference validity checker (?(...))
+ + named group (?<name>...), (?'name'...)
+ + named backref \k<name>
+ + subexp call \g<name>, \g<group-num>
+ + absent expression (?~|...|...)
+ + absent stopper (?|...)
+
+
+A-3. Missing features compared with perl 5.8.0
+
+ + \N{name}
+ + \l,\u,\L,\U,\C
+ + (??{code})
+
+ * \Q...\E
+ This is effective on ONIG_SYNTAX_PERL and ONIG_SYNTAX_JAVA.
+
+
+A-4. Differences with Japanized GNU regex(version 0.12) of Ruby 1.8
+
+ + add character property (\p{property}, \P{property})
+ + add hexadecimal digit char type (\h, \H)
+ + add look-behind
+ (?<=fixed-width-pattern), (?<!fixed-width-pattern)
+ + add possessive quantifier. ?+, *+, ++
+ + add operations in character class. [], &&
+ ('[' must be escaped as an usual char in character class.)
+ + add named group and subexp call.
+ + octal or hexadecimal number sequence can be treated as
+ a multibyte code char in character class if multibyte encoding
+ is specified.
+ (ex. [\xa1\xa2], [\xa1\xa7-\xa4\xa1])
+ + allow the range of single byte char and multibyte char in character
+ class.
+ ex. /[a-<<any EUC-JP character>>]/ in EUC-JP encoding.
+ + effect range of isolated option is to next ')'.
+ ex. (?:(?i)a|b) is interpreted as (?:(?i:a|b)), not (?:(?i:a)|b).
+ + isolated option is not transparent to previous pattern.
+ ex. a(?i)* is a syntax error pattern.
+ + allowed unpaired left brace as a normal character.
+ ex. /{/, /({)/, /a{2,3/ etc...
+ + negative POSIX bracket [:^xxxx:] is supported.
+ + POSIX bracket [:ascii:] is added.
+ + repeat of look-ahead is not allowed.
+ ex. /(?=a)*/, /(?!b){5}/
+ + Ignore case option is effective to escape sequence.
+ ex. /\x61/i =~ "A"
+ + In the range quantifier, the number of the minimum is optional.
+ /a{,n}/ == /a{0,n}/
+ The omission of both minimum and maximum values is not allowed.
+ /a{,}/
+ + /{n}?/ is not a reluctant quantifier.
+ /a{n}?/ == /(?:a{n})?/
+ + invalid back reference is checked and raises error.
+ /\1/, /(a)\2/
+ + Zero-width match in an infinite loop stops the repeat,
+ then changes of the capture group status are checked as stop condition.
+ /(?:()|())*\1\2/ =~ ""
+ /(?:\1a|())*/ =~ "a"
+
+// END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE.ja b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE.ja
new file mode 100644
index 000000000..12c7df40d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/RE.ja
@@ -0,0 +1,585 @@
+鬼車 æ­£è¦è¡¨ç¾ Version 6.9.5 2020/01/28
+
+使用文法: ONIG_SYNTAX_ONIGURUMA (既定値)
+
+
+1. 基本è¦ç´ 
+
+ \ 退é¿ä¿®é£¾ (エスケープ) æ­£è¦è¡¨ç¾è¨˜å·ã®æœ‰åŠ¹/無効ã®åˆ¶å¾¡
+ | é¸æŠžå­
+ (...) å¼é›†åˆ (グループ)
+ [...] æ–‡å­—é›†åˆ (文字クラス)
+
+
+2. 文字
+
+ \t 水平タブ (0x09)
+ \v 垂直タブ (0x0B)
+ \n 改行 (0x0A)
+ \r 復帰 (0x0D)
+ \b 後退空白 (0x08)
+ \f æ”¹é  (0x0C)
+ \a é˜ (0x07)
+ \e 退é¿ä¿®é£¾ (0x1B)
+ \nnn å…«é€²æ•°è¡¨ç¾ ç¬¦å·åŒ–ãƒã‚¤ãƒˆå€¤
+ \o{17777777777} æ‹¡å¼µå…«é€²æ•°è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+ \uHHHH æ‹¡å¼µåå…­é€²æ•°è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+ \xHH åå…­é€²æ•°è¡¨ç¾ ç¬¦å·åŒ–ãƒã‚¤ãƒˆå€¤
+ \x{7HHHHHHH} æ‹¡å¼µåå…­é€²æ•°è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+ \cx åˆ¶å¾¡æ–‡å­—è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+ \C-x åˆ¶å¾¡æ–‡å­—è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+ \M-x 超 (x|0x80) コードãƒã‚¤ãƒ³ãƒˆå€¤
+ \M-\C-x 超 + åˆ¶å¾¡æ–‡å­—è¡¨ç¾ ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒˆå€¤
+
+ ※ \bã¯ã€æ–‡å­—集åˆå†…ã§ã®ã¿æœ‰åŠ¹
+
+
+3. 文字種
+
+ . ä»»æ„文字 (改行を除ã: オプションã«ä¾å­˜)
+
+ \w å˜èªžæ§‹æˆæ–‡å­—
+
+ Unicode以外ã®å ´åˆ:
+ 英数字, "_" ãŠã‚ˆã³ 多ãƒã‚¤ãƒˆæ–‡å­—。
+
+ Unicodeã®å ´åˆ:
+ General_Category -- (Letter|Mark|Number|Connector_Punctuation)
+
+ \W éžå˜èªžæ§‹æˆæ–‡å­—
+
+ \s 空白文字
+
+ Unicode以外ã®å ´åˆ:
+ \t, \n, \v, \f, \r, \x20
+
+ Unicodeã®å ´åˆ:
+ U+0009, U+000A, U+000B, U+000C, U+000D, U+0085(NEL),
+ General_Category -- Line_Separator
+ -- Paragraph_Separator
+ -- Space_Separator
+
+ \S éžç©ºç™½æ–‡å­—
+
+ \d 10進数字
+
+ Unicodeã®å ´åˆ: General_Category -- Decimal_Number
+
+ \D éž10進数字
+
+ \h 16進数字 [0-9a-fA-F]
+
+ \H éž16進数字
+
+ \R 汎改行 (* 文字集åˆã®ä¸­ã§ã¯ä½¿ç”¨ã§ããªã„)
+ "\r\n" or \n,\v,\f,\r (* 但㗠\r\nã‹ã‚‰\rã«ã¯ãƒãƒƒã‚¯ãƒˆãƒ©ãƒƒã‚¯ã—ãªã„)
+
+ Unicodeã®å ´åˆ:
+ "\r\n" or \n,\v,\f,\r or U+0085, U+2028, U+2029
+
+ \N éžæ”¹è¡Œæ–‡å­— (?-m:.)
+
+ \O 真任æ„文字 (?m:.) (* 原作)
+
+ \X 文章区分 \X === (?>\O(?:\Y\O)*)
+
+ ã“ã®æ¼”ç®—å­ã®æ„味ã¯ã€ã‚ªãƒ—ション (?y{..})ã®è¨­å®šã«ã‚ˆã£ã¦å¤‰åŒ–ã™ã‚‹ã€‚
+
+ \Xã¯ç…§åˆã®é–‹å§‹ä½ç½®ãŒåŒºåˆ†ã®å¢ƒç•Œã‹ã©ã†ã‹ã‚’確èªã—ãªã„。
+ ãれを確実ã«ã—ãŸã‘ã‚Œã°ã€\y\Xã¨æ›¸ã‘ã°è‰¯ã„。
+
+ [拡張書記素房-状態ã®ã¨ã] (デフォルト)
+ Unicodeã®å ´åˆ:
+ å‚ç…§ [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+ Unicode以外ã®å ´åˆ: \X === (?>\r\n|\O)
+
+ [å˜èªž-状態ã®ã¨ã]
+ ç¾åœ¨ã€Unicodeã—ã‹ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ãªã„。
+ å‚ç…§ [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+
+ Character Property
+
+ * \p{property-name}
+ * \p{^property-name} (negative)
+ * \P{property-name} (negative)
+
+ property-name:
+
+ + å…¨ã¦ã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã§æœ‰åŠ¹
+ Alnum, Alpha, Blank, Cntrl, Digit, Graph, Lower,
+ Print, Punct, Space, Upper, XDigit, Word, ASCII,
+
+ + EUC-JP, Shift_JISã§æœ‰åŠ¹
+ Hiragana, Katakana
+
+ + UTF8, UTF16, UTF32ã§æœ‰åŠ¹
+ doc/UNICODE_PROPERTIESå‚ç…§
+
+
+
+4. é‡æŒ‡å®šå­
+
+ 欲張り
+
+ ? 一回ã¾ãŸã¯é›¶å›ž
+ * 零回以上
+ + 一回以上
+ {n,m} (n <= m) n回以上 ã‹ã¤ m回以下
+ {n,} n回以上
+ {,n} 零回以上n回以下 ({0,n})
+ {n} n回
+
+
+ 無欲
+
+ ?? 零回ã¾ãŸã¯ä¸€å›ž
+ *? 零回以上
+ +? 一回以上
+ {n,m}? (n <= m) n回以上 ã‹ã¤ m回以下
+ {n,}? n回以上
+ {,n}? 零回以上n回以下 (== {0,n}?)
+
+ {n}? ã¯ONIG_SYNTAX_JAVAã¨ONIG_SYNTAX_PERLã§ã®ã¿ç„¡æ¬²ãªæŒ‡å®šå­
+ (ãã®å ´åˆã«ã¯ã€æ…‹ã€…ãã†æ›¸ãæ„味ã¯ãªã„ãŒ)
+ デフォルトã®æ–‡æ³•ã§ã¯ã€/a{n}?/ === /(?:a{n})?/
+
+
+ 強欲 (欲張りã§ã€ç¹°ã‚Šè¿”ã—ã«æˆåŠŸã—ãŸå¾Œã¯å›žæ•°ã‚’減らã™ã‚ˆã†ãªå¾Œé€€å†è©¦è¡Œã‚’ã—ãªã„)
+
+ ?+ 一回ã¾ãŸã¯é›¶å›ž
+ *+ 零回以上
+ ++ 一回以上
+ {n,m} (n > m) m回以上 ã‹ã¤ n回以下
+
+ {n,m}+, {n,}+, {n}+ ã¯ã€ONIG_SYNTAX_JAVAã¨ONIG_SYNTAX_PERLã§ã®ã¿
+ 強欲ãªæŒ‡å®šå­
+
+ 例. /a*+/ === /(?>a*)/
+
+
+5. 錨
+
+ ^ 行頭
+ $ 行末
+ \b å˜èªžå¢ƒç•Œ
+ \B éžå˜èªžå¢ƒç•Œ
+
+ \A 文字列先頭
+ \Z 文字列末尾ã€ã¾ãŸã¯æ–‡å­—列末尾ã®æ”¹è¡Œã®ç›´å‰
+ \z 文字列末尾
+ \G 探索開始ä½ç½®
+ \K ä¿æŒ (çµæžœã®é–‹å§‹ä½ç½®ã‚’ã“ã®ä½ç½®ã«ä¿ã¤)
+
+
+ \y 文章区分 境界
+ \Y 文章区分 éžå¢ƒç•Œ
+
+ ã“ã®æ¼”ç®—å­ã®æ„味ã¯ã€ã‚ªãƒ—ション (?y{..})ã®è¨­å®šã«ã‚ˆã£ã¦å¤‰åŒ–ã™ã‚‹ã€‚
+
+ [拡張書記素房-状態ã®ã¨ã] (デフォルト)
+ Unicodeã®å ´åˆ:
+ å‚ç…§ [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+ Unicode以外ã®å ´åˆ:
+ \rã¨\nã®é–“を除ãå…¨ã¦ã®ä½ç½®
+
+ [å˜èªž-状態ã®ã¨ã]
+ ç¾åœ¨ã€Unicodeã—ã‹ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ãªã„。
+ å‚ç…§ [Unicode Standard Annex #29: http://unicode.org/reports/tr29/]
+
+
+
+6. 文字集åˆ
+
+ ^... å¦å®š (最低優先度演算å­)
+ x-y 範囲 (xã‹ã‚‰yã¾ã§)
+ [...] é›†åˆ (文字集åˆå†…文字集åˆ)
+ ..&&.. ç©æ¼”ç®— (^ã®æ¬¡ã«å„ªå…ˆåº¦ãŒä½Žã„演算å­)
+
+ 例. [a-w&&[^c-g]z] ==> ([a-w] and ([^c-g] or z)) ==> [abh-w]
+
+ ※ '[', '-', ']'ã‚’ã€æ–‡å­—集åˆå†…ã§é€šå¸¸æ–‡å­—ã®æ„味ã§ä½¿ç”¨ã—ãŸã„å ´åˆã«ã¯ã€
+ ã“れらã®æ–‡å­—ã‚’'\'ã§é€€é¿ä¿®é£¾ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+
+
+ POSIXブラケット ([:xxxxx:], å¦å®š [:^xxxxx:])
+
+ Unicode以外ã®å ´åˆ:
+
+ alnum 英数字
+ alpha 英字
+ ascii 0 - 127
+ blank \t, \x20
+ cntrl
+ digit 0-9
+ graph 多ãƒã‚¤ãƒˆæ–‡å­—全部をå«ã‚€
+ lower
+ print 多ãƒã‚¤ãƒˆæ–‡å­—全部をå«ã‚€
+ punct
+ space \t, \n, \v, \f, \r, \x20
+ upper
+ xdigit 0-9, a-f, A-F
+ word 英数字, "_" ãŠã‚ˆã³ 多ãƒã‚¤ãƒˆæ–‡å­—
+
+ Unicodeã®å ´åˆ:
+
+ alnum Letter | Mark | Decimal_Number
+ alpha Letter | Mark
+ ascii 0000 - 007F
+ blank Space_Separator | 0009
+ cntrl Control | Format | Unassigned | Private_Use | Surrogate
+ digit Decimal_Number
+ graph [[:^space:]] && ^Control && ^Unassigned && ^Surrogate
+ lower Lowercase_Letter
+ print [[:graph:]] | [[:space:]]
+ punct Connector_Punctuation | Dash_Punctuation | Close_Punctuation |
+ Final_Punctuation | Initial_Punctuation | Other_Punctuation |
+ Open_Punctuation
+ space Space_Separator | Line_Separator | Paragraph_Separator |
+ U+0009 | U+000A | U+000B | U+000C | U+000D | U+0085
+ upper Uppercase_Letter
+ xdigit U+0030 - U+0039 | U+0041 - U+0046 | U+0061 - U+0066
+ (0-9, a-f, A-F)
+ word Letter | Mark | Decimal_Number | Connector_Punctuation
+
+
+
+7. æ‹¡å¼µå¼é›†åˆ
+
+ (?#...) 注釈
+
+ (?imxWDSPy-imxWDSP:å¼) å¼ã‚ªãƒ—ション
+
+ i: 大文字å°æ–‡å­—ç…§åˆ
+ m: 複数行
+ x: 拡張形å¼
+ W: wordãŒASCIIã®ã¿ (\w, \p{Word}, [[:word:]])
+ word境界ãŒASCIIã®ã¿ (\b)
+ D: digitãŒASCIIã®ã¿ (\d, \p{Digit}, [[:digit:]])
+ S: spaceãŒASCIIã®ã¿ (\s, \p{Space}, [[:space:]])
+ P: POSIXプロパティãŒASCIIã®ã¿ (W,D,Sã‚’å…¨ã¦å«ã‚“ã§ã„ã‚‹)
+ (alnum, alpha, blank, cntrl, digit, graph,
+ lower, print, punct, space, upper, xdigit, word)
+
+ y{?}: 文章区分状態
+ ã“ã®ã‚ªãƒ—ションã¯\X, \y, \Yã®æ„味を変更ã™ã‚‹ã€‚
+ ç¾åœ¨ã“ã®ã‚ªãƒ—ションã¯Unicodeã§ã—ã‹ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ãªã„
+ y{g}: 拡張書記素房-状態 (デフォルト)
+ y{w}: å˜èªž-状態
+ å‚ç…§ [Unicode Standard Annex #29]
+
+ (?imxWDSPy-imxWDSP) 孤立オプション
+
+ * ã“ã‚Œã¯æ¬¡ã®')'ã¾ãŸã¯ãƒ‘ターンã®çµ‚ã‚ã‚Šã¾ã§ã®ã‚°ãƒ«ãƒ¼ãƒ—ã‚’å½¢æˆã™ã‚‹
+ /ab(?i)c|def|gh/ == /ab(?i:c|def|gh)/
+
+
+ (å¼) æ•ç²å¼é›†åˆ
+ (?:å¼) éžæ•ç²å¼é›†åˆ
+
+ (?=å¼) 先読ã¿
+ (?!å¼) å¦å®šå…ˆèª­ã¿
+
+ (?<=å¼) 戻り読ã¿
+ (?<!å¼) å¦å®šæˆ»ã‚Šèª­ã¿
+
+ * 戻り読ã¿ã€å¦å®šæˆ»ã‚Šèª­ã¿ã®å¼ã®ä¸­ã§ã¯ã€ä¸åœ¨åœæ­¢æ¼”ç®—å­
+ (?~|expr)ã¨ç¯„囲消去演算å­(?~|)を使用ã™ã‚‹ã“ã¨ã¯ã§ããªã„
+
+ * 戻り読ã¿ã€å¦å®šæˆ»ã‚Šèª­ã¿ã®ä¸­ã§ã¯ã€ignore-caseオプションã®
+ 対応ãŒåˆ¶é™ã•ã‚Œã‚‹ã€‚一文字ã¨ä¸€æ–‡å­—ã®é–“ã®å¤‰æ›ã—ã‹å¯¾å¿œã—ãªã„。
+ (Unicodeã§ã®è¤‡æ•°æ–‡å­—ã®å¤‰æ›ã«å¯¾å¿œã—ãªã„)
+
+ (?>å¼) 原å­çš„å¼é›†åˆ
+ å¼å…¨ä½“を通éŽã—ãŸã¨ãã€å¼ã®ä¸­ã§ã®å¾Œé€€å†è©¦è¡Œã‚’è¡Œãªã‚ãªã„
+
+ (?<name>å¼), (?'name'å¼)
+ åå‰ä»˜ãæ•ç²å¼é›†åˆ
+ å¼é›†åˆã«åå‰ã‚’割り当ã¦ã‚‹(定義ã™ã‚‹)。
+ (åå‰ã¯å˜èªžæ§‹æˆæ–‡å­—ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„。)
+
+ åå‰ã ã‘ã§ãªãã€æ•ç²å¼é›†åˆã¨åŒæ§˜ã«ç•ªå·ã‚‚割り当ã¦ã‚‰ã‚Œã‚‹ã€‚
+ 番å·æŒ‡å®šãŒç¦æ­¢ã•ã‚Œã¦ã„ãªã„状態 (10. æ•ç²å¼é›†åˆ ã‚’å‚ç…§)
+ ã®ã¨ãã¯ã€åå‰ã‚’使ã‚ãªã„ã§ç•ªå·ã§ã‚‚å‚ç…§ã§ãる。
+
+ 複数ã®å¼é›†åˆã«åŒã˜åå‰ã‚’与ãˆã‚‹ã“ã¨ã¯è¨±ã•ã‚Œã¦ã„る。
+ ã“ã®å ´åˆã«ã¯ã€ã“ã®åå‰ã‚’使用ã—ãŸå¾Œæ–¹å‚ç…§ã¯å¯èƒ½ã§ã‚ã‚‹ãŒã€
+ 部分å¼å‘¼å‡ºã—ã¯ã§ããªã„。
+
+
+ <呼ã³å‡ºã—>
+
+ * 内容ã®å‘¼ã³å‡ºã—
+ (?{...contents...}) å‰é€²ä¸­ã®ã¿ã®å‘¼ã³å‡ºã—
+ (?{...contents...}D) Dã¯æ–¹å‘指定文字
+ D = 'X': å‰é€²ä¸­ãŠã‚ˆã³å¾Œé€€ä¸­
+ '<': 後退中ã®ã¿
+ '>': å‰é€²ä¸­ã®ã¿
+ (?{...contents...}[tag]) å札付ã
+ (?{...contents...}[tag]D)
+
+ * エスケープ文字ã¯contentsã®ä¸­ã§ä½•ã®æ©Ÿèƒ½ã‚‚æŒãŸãªã„
+ * contentsã¯ã€'{'文字ã§å§‹ã¾ã£ã¦ã¯ãªã‚‰ãªã„
+
+ (?{{{...contents...}}}) contentsã®ä¸­ã®n個連続ã®'}'ã¯ã€(n+1)個連続ã®{{{...}}}
+ ã®ä¸­ã§è¨±ã•ã‚Œã‚‹
+
+ tagã«è¨±ã•ã‚Œã‚‹æ–‡å­—: _ A-Z a-z 0-9 (* 最åˆã®æ–‡å­—: _ A-Z a-z)
+
+
+ * åå‰ã®å‘¼ã³å‡ºã—
+ (*name)
+ (*name{args...}) 引数付ã
+ (*name[tag]) å札付ã
+ (*name[tag]{args...})
+
+ nameã«è¨±ã•ã‚Œã‚‹æ–‡å­—: _ A-Z a-z 0-9 (* 最åˆã®æ–‡å­—: _ A-Z a-z)
+ tag ã«è¨±ã•ã‚Œã‚‹æ–‡å­—: _ A-Z a-z 0-9 (* 最åˆã®æ–‡å­—: _ A-Z a-z)
+
+
+
+ <ä¸åœ¨æ©Ÿèƒ½ç¾¤>
+
+ (?~ä¸åœ¨) ä¸åœ¨ç¹°ã‚Šè¿”ã— (*原案 田中哲)
+ ã“れ㯠.*(より正確ã«ã¯\O*)ã®ã‚ˆã†ã«å‹•ä½œã™ã‚‹ãŒã€<ä¸åœ¨>ã«
+ é©åˆã™ã‚‹æ–‡å­—列をå«ã¾ãªã„範囲ã«åˆ¶é™ã•ã‚Œã‚‹ã€‚
+ ã“ã‚Œã¯(?~|(?:ä¸åœ¨)|\O*)ã®çœç•¥è¡¨è¨˜ã§ã‚る。
+
+ (?~|ä¸åœ¨|å¼) ä¸åœ¨å¼ (* 原作)
+ ã“ã‚Œã¯<å¼>ã®ã‚ˆã†ã«å‹•ä½œã™ã‚‹ãŒã€<ä¸åœ¨>ã«é©åˆã™ã‚‹æ–‡å­—列を
+ å«ã¾ãªã„範囲ã«åˆ¶é™ã•ã‚Œã‚‹ã€‚
+
+ 例 (?~|345|\d*) "12345678" ==> "12", "1", ""
+
+ (?~|ä¸åœ¨) ä¸åœ¨åœæ­¢ (* 原作)
+ ã“ã®æ¼”ç®—å­ã‚’通éŽã—ãŸå¾Œã¯ã€å¯¾è±¡æ–‡å­—列ã®é©åˆç¯„囲ãŒ
+ <ä¸åœ¨>ã«é©åˆã™ã‚‹æ–‡å­—列をå«ã¾ãªã„範囲ã«åˆ¶é™ã•ã‚Œã‚‹ã€‚
+
+ (?~|) 範囲消去
+ ä¸åœ¨åœæ­¢ã®åŠ¹æžœã‚’消ã—ã¦ã€ãれ以å‰ã®çŠ¶æ…‹ã«ã™ã‚‹ã€‚
+
+ * ä¸åœ¨æ©Ÿèƒ½ã®å…¥ã‚Œå­ã«ã¯å¯¾å¿œã—ã¦ãŠã‚‰ãšã€ãã®å ´åˆã®æŒ™å‹•ã¯ä¸å®šã¨ã™ã‚‹ã€‚
+
+
+
+ <æ¡ä»¶æ–‡>
+
+ (?(æ¡ä»¶å¼)æˆåŠŸå¼|失敗å¼) æ¡ä»¶å¼ãŒæˆåŠŸã™ã‚Œã°æˆåŠŸå¼ã€å¤±æ•—ã™ã‚Œã°å¤±æ•—å¼ã‚’実行ã™ã‚‹
+ ã“ã®æ©Ÿèƒ½ã®å­˜åœ¨ç†ç”±ã¯ã€æˆåŠŸå¼ãŒå¤±æ•—ã—ã¦ã‚‚失敗å¼ã«ã¯
+ è¡Œã‹ãªã„ã“ã¨ã€‚ã“ã‚Œã¯ä»–ã®æ­£è¦è¡¨ç¾ã§æ›¸ãã“ã¨ãŒã§ããªã„。
+ ã‚‚ã†ã²ã¨ã¤ã¯ã€æ¡ä»¶å¼ãŒå¾Œæ–¹å‚ç…§ã®ç•ªå·/åå‰ã®ã¨ãã€
+ 後方å‚照値ã®æœ‰åŠ¹æ€§ã‚’調ã¹ã‚‹(文字列ã¨ç…§åˆã¯ã—ãªã„)
+ æ„味ã«ãªã‚‹ã€‚
+
+ (?(æ¡ä»¶å¼)æˆåŠŸå¼) æ¡ä»¶å¼ãŒæˆåŠŸã™ã‚Œã°æˆåŠŸå¼ã‚’実行ã™ã‚‹
+ (æ¡ä»¶å¼ãŒé€šå¸¸ã®å¼ã®ã¨ãã«ã¯ã€ã“ã®æ§‹æ–‡ã¯ä¸å¿…è¦ã ãŒ
+ 今ã®ã¨ã“ã‚エラーã«ã¯ã—ãªã„。)
+
+
+ æ¡ä»¶å¼ã¯å¾Œæ–¹å‚ç…§ã®ç•ªå·/åå‰ã¾ãŸã¯æ™®é€šã®å¼ã‚’使用ã§ãる。
+ æ¡ä»¶å¼ãŒå¾Œæ–¹å‚ç…§ã®å ´åˆã€æˆåŠŸå¼ã¨å¤±æ•—å¼ã®ä¸¡æ–¹ã‚’çœç•¥å¯èƒ½ã§ã‚ã‚Šã€
+ ã“ã®å ´åˆã€å¾Œæ–¹å‚照値有効性を調ã¹ã‚‹(æˆåŠŸ/失敗)機能ã®ã¿ã«ãªã‚‹ã€‚
+
+ [後方å‚照値有効性確èªå™¨] (* 原作)
+ (?(n)), (?(-n)), (?(+n)), (?(n+level)) ...
+ (?(<n>)), (?('-n')), (?(<+n>)) ...
+ (?(<name>)), (?('name')), (?(<name+level>)) ...
+
+
+
+8. 後方å‚ç…§
+
+ \n 番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k<n> 番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k'n' 番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k<-n> 相対番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k'-n' 相対番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k<+n> 相対番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k'+n' 相対番å·æŒ‡å®šå‚ç…§ (n >= 1)
+ \k<name> åå‰æŒ‡å®šå‚ç…§
+ \k'name' åå‰æŒ‡å®šå‚ç…§
+
+ åå‰æŒ‡å®šå‚ç…§ã§ã€ãã®åå‰ãŒè¤‡æ•°ã®å¼é›†åˆã§å¤šé‡å®šç¾©ã•ã‚Œã¦ã„ã‚‹å ´åˆã«ã¯ã€
+ 番å·ã®å¤§ãã„å¼é›†åˆã‹ã‚‰å„ªå…ˆçš„ã«å‚ç…§ã•ã‚Œã‚‹ã€‚
+ (マッãƒã—ãªã„ã¨ãã«ã¯ç•ªå·ã®å°ã•ã„å¼é›†åˆãŒå‚ç…§ã•ã‚Œã‚‹)
+
+ ※ 番å·æŒ‡å®šå‚ç…§ã¯ã€åå‰ä»˜ãæ•ç²å¼é›†åˆãŒå®šç¾©ã•ã‚Œã€
+ ã‹ã¤ ONIG_OPTION_CAPTURE_GROUPãŒæŒ‡å®šã•ã‚Œã¦ã„ãªã„å ´åˆã«ã¯ã€
+ ç¦æ­¢ã•ã‚Œã‚‹ã€‚(10. æ•ç²å¼é›†åˆ ã‚’å‚ç…§)
+
+
+ ãƒã‚¹ãƒˆãƒ¬ãƒ™ãƒ«ä»˜ã後方å‚ç…§
+
+ level: 0, 1, 2, ...
+
+ \k<n+level> (n >= 1)
+ \k<n-level> (n >= 1)
+ \k'n+level' (n >= 1)
+ \k'n-level' (n >= 1)
+
+ \k<name+level>
+ \k<name-level>
+ \k'name+level'
+ \k'name-level'
+
+ 後方å‚ç…§ã®ä½ç½®ã‹ã‚‰ç›¸å¯¾çš„ãªéƒ¨åˆ†å¼å‘¼å‡ºã—ãƒã‚¹ãƒˆãƒ¬ãƒ™ãƒ«ã‚’指定ã—ã¦ã€ãã®ãƒ¬ãƒ™ãƒ«ã§ã®
+ æ•ç²å€¤ã‚’å‚ç…§ã™ã‚‹ã€‚
+
+ 例-1.
+
+ /\A(?<a>|.|(?:(?<b>.)\g<a>\k<b+0>))\z/.match("reer")
+
+ 例-2.
+
+ r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED)
+ (?<element> \g<stag> \g<content>* \g<etag> ){0}
+ (?<stag> < \g<name> \s* > ){0}
+ (?<name> [a-zA-Z_:]+ ){0}
+ (?<content> [^<&]+ (\g<element> | [^<&]+)* ){0}
+ (?<etag> </ \k<name+1> >){0}
+ \g<element>
+ __REGEXP__
+
+ p r.match('<foo>f<bar>bbb</bar>f</foo>').captures
+
+
+
+9. 部分å¼å‘¼å‡ºã— ("田中哲スペシャル") (* 原作)
+
+ \g<name> åå‰æŒ‡å®šå‘¼å‡ºã—
+ \g'name' åå‰æŒ‡å®šå‘¼å‡ºã—
+ \g<n> 番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+ \g'n' 番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+ \g<0> 番å·æŒ‡å®šå‘¼å‡ºã—(全体呼ã³å‡ºã—)
+ \g'0' 番å·æŒ‡å®šå‘¼å‡ºã—(全体呼ã³å‡ºã—)
+ \g<-n> 相対番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+ \g'-n' 相対番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+ \g<+n> 相対番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+ \g'+n' 相対番å·æŒ‡å®šå‘¼å‡ºã— (n >= 1)
+
+ ※ 最左ä½ç½®ã§ã®å†å¸°å‘¼å‡ºã—ã¯ç¦æ­¢ã•ã‚Œã‚‹ã€‚
+ 例. (?<name>a|\g<name>b) => error
+ (?<name>a|b\g<name>c) => OK
+
+ ※ 番å·æŒ‡å®šå‘¼å‡ºã—ã¯ã€åå‰ä»˜ãæ•ç²å¼é›†åˆãŒå®šç¾©ã•ã‚Œã€
+ ã‹ã¤ ONIG_OPTION_CAPTURE_GROUPãŒæŒ‡å®šã•ã‚Œã¦ã„ãªã„å ´åˆã«ã¯ã€
+ ç¦æ­¢ã•ã‚Œã‚‹ã€‚ (10. æ•ç²å¼é›†åˆ ã‚’å‚ç…§)
+
+ ※ 呼ã³å‡ºã•ã‚ŒãŸå¼é›†åˆã®ã‚ªãƒ—ション状態ãŒå‘¼å‡ºã—å´ã®ã‚ªãƒ—ション状態ã¨ç•°ãªã£ã¦ã„ã‚‹
+ ã¨ãã€å‘¼ã³å‡ºã•ã‚ŒãŸå´ã®ã‚ªãƒ—ション状態ãŒæœ‰åŠ¹ã§ã‚る。
+
+ 例. (?-i:\g<name>)(?i:(?<name>a)){0} 㯠"A" ã«ç…§åˆæˆåŠŸã™ã‚‹ã€‚
+
+
+10. æ•ç²å¼é›†åˆ
+
+ æ•ç²å¼é›†åˆ(...)ã¯ã€ä»¥ä¸‹ã®æ¡ä»¶ã«å¿œã˜ã¦æŒ¯èˆžãŒå¤‰åŒ–ã™ã‚‹ã€‚
+ (åå‰ä»˜ãæ•ç²å¼é›†åˆã¯å¤‰åŒ–ã—ãªã„)
+
+ case 1. /.../ (åå‰ä»˜ãæ•ç²å¼é›†åˆã¯ä¸ä½¿ç”¨ã€ã‚ªãƒ—ションãªã—)
+
+ (...) ã¯ã€æ•ç²å¼é›†åˆã¨ã—ã¦æ‰±ã‚れる。
+
+ case 2. /.../g (åå‰ä»˜ãæ•ç²å¼é›†åˆã¯ä¸ä½¿ç”¨ã€ã‚ªãƒ—ション 'g'を指定)
+
+ (...) ã¯ã€éžæ•ç²å¼é›†åˆã¨ã—ã¦æ‰±ã‚れる。
+
+ case 3. /..(?<name>..)../ (åå‰ä»˜ãæ•ç²å¼é›†åˆã¯ä½¿ç”¨ã€ã‚ªãƒ—ションãªã—)
+
+ (...) ã¯ã€éžæ•ç²å¼é›†åˆã¨ã—ã¦æ‰±ã‚れる。
+ 番å·æŒ‡å®šå‚ç…§/呼ã³å‡ºã—ã¯ä¸è¨±å¯ã€‚
+
+ case 4. /..(?<name>..)../G (åå‰ä»˜ãæ•ç²å¼é›†åˆã¯ä½¿ç”¨ã€ã‚ªãƒ—ション 'G'を指定)
+
+ (...) ã¯ã€æ•ç²å¼é›†åˆã¨ã—ã¦æ‰±ã‚れる。
+ 番å·æŒ‡å®šå‚ç…§/呼ã³å‡ºã—ã¯è¨±å¯ã€‚
+
+ 但ã—
+ g: ONIG_OPTION_DONT_CAPTURE_GROUP
+ G: ONIG_OPTION_CAPTURE_GROUP
+ ('g'ã¨'G'オプションã¯ã€ruby-dev MLã§è­°è«–ã•ã‚ŒãŸã€‚)
+
+ ã“れらã®æŒ¯èˆžã®æ„味ã¯ã€
+ åå‰ä»˜ãæ•ç²ã¨åå‰ç„¡ã—æ•ç²ã‚’åŒæ™‚ã«ä½¿ç”¨ã™ã‚‹å¿…然性ã®ã‚ã‚‹å ´é¢ã¯å°‘ãªã„ã§ã‚ã‚ã†
+ ã¨ã„ã†ç†ç”±ã‹ã‚‰è€ƒãˆã‚‰ã‚ŒãŸã‚‚ã®ã§ã‚る。
+
+
+-----------------------------
+補記 1. 文法ä¾å­˜ã‚ªãƒ—ション
+
+ + ONIG_SYNTAX_ONIGURUMA
+ (?m): 終止符記å·(.)ã¯æ”¹è¡Œã¨ç…§åˆæˆåŠŸ
+
+ + ONIG_SYNTAX_PERL 㨠ONIG_SYNTAX_JAVA
+ (?s): 終止符記å·(.)ã¯æ”¹è¡Œã¨ç…§åˆæˆåŠŸ
+ (?m): ^ ã¯æ”¹è¡Œã®ç›´å¾Œã«ç…§åˆã™ã‚‹ã€$ ã¯æ”¹è¡Œã®ç›´å‰ã«ç…§åˆã™ã‚‹
+
+
+補記 2. 独自拡張機能
+
+ + 16進数数字ã€éž16進数字 \h, \H
+ + 真任æ„文字 \O
+ + 文章区分境界 \y, \Y
+ + 後方å‚照値有効性確èªå™¨ (?(...))
+ + åå‰ä»˜ãæ•ç²å¼é›†åˆ (?<name>...), (?'name'...)
+ + åå‰æŒ‡å®šå¾Œæ–¹å‚ç…§ \k<name>
+ + 部分å¼å‘¼å‡ºã— \g<name>, \g<group-num>
+ + ä¸åœ¨å¼ (?~|...|...)
+ + ä¸åœ¨åœæ­¢ (?|...)
+
+
+補記 3. Perl 5.8.0ã¨æ¯”較ã—ã¦å­˜åœ¨ã—ãªã„機能
+
+ + \N{name}
+ + \l,\u,\L,\U,\C
+ + (??{code})
+
+ * \Q...\E
+ 但ã—ONIG_SYNTAX_PERLã¨ONIG_SYNTAX_JAVAã§ã¯æœ‰åŠ¹
+
+
+補記 4. Ruby 1.8 ã®æ—¥æœ¬èªžåŒ– GNU regex(version 0.12)ã¨ã®é•ã„
+
+ + 文字Property機能追加 (\p{property}, \P{Property})
+ + 16進数字タイプ追加 (\h, \H)
+ + 戻り読ã¿æ©Ÿèƒ½ã‚’追加
+ + 強欲ãªç¹°ã‚Šè¿”ã—指定å­ã‚’追加 (?+, *+, ++)
+ + 文字集åˆã®ä¸­ã®æ¼”ç®—å­ã‚’追加 ([...], &&)
+ ('[' ã¯ã€æ–‡å­—集åˆã®ä¸­ã§é€šå¸¸ã®æ–‡å­—ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã¨ãã«ã¯
+ 退é¿ä¿®é£¾ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„)
+ + åå‰ä»˜ãæ•ç²å¼é›†åˆã¨ã€éƒ¨åˆ†å¼å‘¼å‡ºã—機能追加
+ + 多ãƒã‚¤ãƒˆæ–‡å­—コードãŒæŒ‡å®šã•ã‚Œã¦ã„ã‚‹ã¨ãã€
+ 文字集åˆã®ä¸­ã§å…«é€²æ•°ã¾ãŸã¯å六進数表ç¾ã®é€£ç¶šã¯ã€å¤šãƒã‚¤ãƒˆç¬¦å·ã§è¡¨ç¾ã•ã‚ŒãŸ
+ 一個ã®æ–‡å­—ã¨è§£é‡ˆã•ã‚Œã‚‹
+ (例. [\xa1\xa2], [\xa1\xa7-\xa4\xa1])
+ + 文字集åˆã®ä¸­ã§ã€ä¸€ãƒã‚¤ãƒˆæ–‡å­—ã¨å¤šãƒã‚¤ãƒˆæ–‡å­—ã®ç¯„囲指定ã¯è¨±ã•ã‚Œã‚‹ã€‚
+ ex. /[a-ã‚]/
+ + 孤立オプションã®æœ‰åŠ¹ç¯„囲ã¯ã€ãã®å­¤ç«‹ã‚ªãƒ—ションをå«ã‚“ã§ã„ã‚‹å¼é›†åˆã®
+ 終ã‚ã‚Šã¾ã§ã§ã‚ã‚‹
+ 例. (?:(?i)a|b) 㯠(?:(?i:a|b)) ã¨è§£é‡ˆã•ã‚Œã‚‹ã€(?:(?i:a)|b)ã§ã¯ãªã„
+ + 孤立オプションã¯ãã®å‰ã®å¼ã«å¯¾ã—ã¦é€éŽçš„ã§ã¯ãªã„
+ 例. /a(?i)*/ ã¯æ–‡æ³•ã‚¨ãƒ©ãƒ¼ã¨ãªã‚‹
+ + ä¸å®Œå…¨ãªç¹°ã‚Šè¿”ã—範囲指定å­ã¯é€šå¸¸ã®æ–‡å­—列ã¨ã—ã¦è¨±å¯ã•ã‚Œã‚‹
+ 例. /{/, /({)/, /a{2,3/
+ + å¦å®šçš„POSIXブラケット [:^xxxx:] を追加
+ + POSIXブラケット [:ascii:] を追加
+ + 先読ã¿ã®ç¹°ã‚Šè¿”ã—ã¯ä¸è¨±å¯
+ 例. /(?=a)*/, /(?!b){5}/
+ + 数値ã§æŒ‡å®šã•ã‚ŒãŸæ–‡å­—ã«å¯¾ã—ã¦ã‚‚ã€å¤§æ–‡å­—å°æ–‡å­—ç…§åˆã‚ªãƒ—ションã¯æœ‰åŠ¹
+ 例. /\x61/i =~ "A"
+ + ç¹°ã‚Šè¿”ã—回数指定ã§ã€æœ€ä½Žå›žæ•°ã®çœç•¥(0回)ãŒã§ãã‚‹
+ /a{,n}/ == /a{0,n}/
+ 最低回数ã¨æœ€å¤§å›žæ•°ã®åŒæ™‚çœç•¥ã¯è¨±ã•ã‚Œãªã„。(/a{,}/)
+ + /a{n}?/ã¯ç„¡æ¬²ãªæ¼”ç®—å­ã§ã¯ãªã„。
+ /a{n}?/ == /(?:a{n})?/
+ + 無効ãªå¾Œæ–¹å‚照をãƒã‚§ãƒƒã‚¯ã—ã¦ã‚¨ãƒ©ãƒ¼ã«ã™ã‚‹ã€‚
+ /\1/, /(a)\2/
+ + ç„¡é™ç¹°ã‚Šè¿”ã—ã®ä¸­ã§ã€é•·ã•é›¶ã§ã®ç…§åˆæˆåŠŸã¯ç¹°ã‚Šè¿”ã—を中断ã•ã›ã‚‹ãŒã€
+ ã“ã®ã¨ãã€ä¸­æ–­ã™ã¹ãã‹ã©ã†ã‹ã®åˆ¤å®šã¨ã—ã¦ã€æ•ç²å¼é›†åˆã®æ•ç²çŠ¶æ…‹ã®
+ 変化ã¾ã§è€ƒæ…®ã—ã¦ã„ã‚‹
+ /(?:()|())*\1\2/ =~ ""
+ /(?:\1a|())*/ =~ "a"
+
+終り
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/SYNTAX.md b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/SYNTAX.md
new file mode 100644
index 000000000..c38e5c873
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/SYNTAX.md
@@ -0,0 +1,1091 @@
+
+# Oniguruma syntax (operator) configuration
+
+_Documented for Oniguruma 6.9.5 (2020/01/23)_
+
+
+----------
+
+
+## Overview
+
+This document details how to configure Oniguruma's syntax, by describing the desired
+syntax operators and behaviors in an instance of the OnigSyntaxType struct, just like
+the built-in Oniguruma syntaxes do.
+
+Configuration operators are bit flags, and are broken into multiple groups, somewhat arbitrarily,
+because Oniguruma takes its configuration as a trio of 32-bit `unsigned int` values, assigned as
+the first three fields in an `OnigSyntaxType` struct:
+
+```C
+typedef struct {
+ unsigned int op;
+ unsigned int op2;
+ unsigned int behavior;
+ OnigOptionType options; /* default option */
+ OnigMetaCharTableType meta_char_table;
+} OnigSyntaxType;
+```
+
+The first group of configuration flags (`op`) roughly corresponds to the
+configuration for "basic regex." The second group (`op2`) roughly corresponds
+to the configuration for "advanced regex." And the third group (`behavior`)
+describes more-or-less what to do for broken input, bad input, or other corner-case
+regular expressions whose meaning is not well-defined. These three groups of
+flags are described in full below, and tables of their usages for various syntaxes
+follow.
+
+The `options` field describes the default compile options to use if the caller does
+not specify any options when invoking `onig_new()`.
+
+The `meta_char_table` field is used exclusively by the ONIG_SYN_OP_VARIABLE_META_CHARACTERS
+option, which allows the various regex metacharacters, like `*` and `?`, to be replaced
+with alternates (for example, SQL typically uses `%` instead of `.*` and `_` instead of `?`).
+
+
+----------
+
+
+## Group One Flags (op)
+
+
+This group contains "basic regex" constructs, features common to most regex systems.
+
+
+### 0. ONIG_SYN_OP_VARIABLE_META_CHARACTERS
+
+_Set in: none_
+
+Enables support for `onig_set_meta_char()`, which allows you to provide alternate
+characters that will be used instead of the six special characters that are normally
+these characters below:
+
+ - `ONIG_META_CHAR_ESCAPE`: `\`
+ - `ONIG_META_CHAR_ANYCHAR`: `.`
+ - `ONIG_META_CHAR_ANYTIME`: `*`
+ - `ONIG_META_CHAR_ZERO_OR_ONE_TIME`: `?`
+ - `ONIG_META_CHAR_ONE_OR_MORE_TIME`: `+`
+ - `ONIG_META_CHAR_ANYCHAR_ANYTIME`: Equivalent in normal regex to `.*`, but supported
+ explicitly so that Oniguruma can support matching SQL `%` wildcards or shell `*` wildcards.
+
+If this flag is set, then the values defined using `onig_set_meta_char()` will be used;
+if this flag is clear, then the default regex characters will be used instead, and
+data set by `onig_set_meta_char()` will be ignored.
+
+
+### 1. ONIG_SYN_OP_DOT_ANYCHAR (enable `.`)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Emacs, Grep, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+Enables support for the standard `.` metacharacter, meaning "any one character." You
+usually want this flag on unless you have turned on `ONIG_SYN_OP_VARIABLE_META_CHARACTERS`
+so that you can use a metacharacter other than `.` instead.
+
+
+### 2. ONIG_SYN_OP_ASTERISK_ZERO_INF (enable `r*`)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Emacs, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the standard `r*` metacharacter, meaning "zero or more r's."
+You usually want this flag set unless you have turned on `ONIG_SYN_OP_VARIABLE_META_CHARACTERS`
+so that you can use a metacharacter other than `*` instead.
+
+
+### 3. ONIG_SYN_OP_ESC_ASTERISK_ZERO_INF (enable `r\*`)
+
+_Set in: none_
+
+Enables support for an escaped `r\*` metacharacter, meaning "zero or more r's." This is
+useful if you have disabled support for the normal `r*` metacharacter because you want `*`
+to simply match a literal `*` character, but you still want some way of activating "zero or more"
+behavior.
+
+
+### 4. ONIG_SYN_OP_PLUS_ONE_INF (enable `r+`)
+
+_Set in: Oniguruma, PosixExtended, Emacs, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the standard `r+` metacharacter, meaning "one or more r's."
+You usually want this flag set unless you have turned on `ONIG_SYN_OP_VARIABLE_META_CHARACTERS`
+so that you can use a metacharacter other than `+` instead.
+
+
+### 5. ONIG_SYN_OP_ESC_PLUS_ONE_INF (enable `r\+`)
+
+_Set in: Grep_
+
+Enables support for an escaped `r\+` metacharacter, meaning "one or more r's." This is
+useful if you have disabled support for the normal `r+` metacharacter because you want `+`
+to simply match a literal `+` character, but you still want some way of activating "one or more"
+behavior.
+
+
+### 6. ONIG_SYN_OP_QMARK_ZERO_ONE (enable `r?`)
+
+_Set in: Oniguruma, PosixExtended, Emacs, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the standard `r?` metacharacter, meaning "zero or one r" or "an optional r."
+You usually want this flag set unless you have turned on `ONIG_SYN_OP_VARIABLE_META_CHARACTERS`
+so that you can use a metacharacter other than `?` instead.
+
+
+### 7. ONIG_SYN_OP_ESC_QMARK_ZERO_ONE (enable `r\?`)
+
+_Set in: Grep_
+
+Enables support for an escaped `r\?` metacharacter, meaning "zero or one r" or "an optional
+r." This is useful if you have disabled support for the normal `r?` metacharacter because
+you want `?` to simply match a literal `?` character, but you still want some way of activating
+"optional" behavior.
+
+
+### 8. ONIG_SYN_OP_BRACE_INTERVAL (enable `r{l,u}`)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the `r{lower,upper}` range form, common to more advanced
+regex engines, which lets you specify precisely a minimum and maximum range on how many r's
+must match (and not simply "zero or more").
+
+This form also allows `r{count}` to specify a precise count of r's that must match.
+
+This form also allows `r{lower,}` to be equivalent to `r{lower,infinity}`.
+
+If and only if the `ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV` behavior flag is set,
+this form also allows `r{,upper}` to be equivalent to `r{0,upper}`; otherwise,
+`r{,upper}` will be treated as an error.
+
+
+### 9. ONIG_SYN_OP_ESC_BRACE_INTERVAL (enable `\{` and `\}`)
+
+_Set in: PosixBasic, Emacs, Grep_
+
+Enables support for an escaped `r\{lower,upper\}` range form. This is useful if you
+have disabled support for the normal `r{...}` range form and want curly braces to simply
+match literal curly brace characters, but you still want some way of activating
+"range" behavior.
+
+
+### 10. ONIG_SYN_OP_VBAR_ALT (enable `r|s`)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `r|s` alternation operator. You usually want this
+flag set.
+
+
+### 11. ONIG_SYN_OP_ESC_VBAR_ALT (enable `\|`)
+
+_Set in: Emacs, Grep_
+
+Enables support for an escaped `r\|s` alternation form. This is useful if you
+have disabled support for the normal `r|s` alternation form and want `|` to simply
+match a literal `|` character, but you still want some way of activating "alternate" behavior.
+
+
+### 12. ONIG_SYN_OP_LPAREN_SUBEXP (enable `(r)`)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `(...)` grouping-and-capturing operators. You usually
+want this flag set.
+
+
+### 13. ONIG_SYN_OP_ESC_LPAREN_SUBEXP (enable `\(` and `\)`)
+
+_Set in: PosixBasic, Emacs, Grep_
+
+Enables support for escaped `\(...\)` grouping-and-capturing operators. This is useful if you
+have disabled support for the normal `(...)` grouping-and-capturing operators and want
+parentheses to simply match literal parenthesis characters, but you still want some way of
+activating "grouping" or "capturing" behavior.
+
+
+### 14. ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR (enable `\A` and `\Z` and `\z`)
+
+_Set in: Oniguruma, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the anchors `\A` (start-of-string), `\Z` (end-of-string or
+newline-at-end-of-string), and `\z` (end-of-string) escapes.
+
+(If the escape metacharacter has been changed from the default of `\`, this
+option will recognize that metacharacter instead.)
+
+
+### 15. ONIG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR (enable `\G`)
+
+_Set in: Oniguruma, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the special anchor `\G` (start-of-previous-match).
+
+(If the escape metacharacter has been changed from the default of `\`, this
+option will recognize that metacharacter instead.)
+
+Note that `OnigRegex`/`regex_t` are not stateful objects, and do _not_ record
+the location of the previous match. The `\G` flag uses the `start` parameter
+explicitly passed to `onig_search()` (or `onig_search_with_param()` to determine
+the "start of the previous match," so if the caller always passes the start of
+the entire buffer as the function's `start` parameter, then `\G` will behave
+exactly the same as `\A`.
+
+
+### 16. ONIG_SYN_OP_DECIMAL_BACKREF (enable `\num`)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Emacs, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for subsequent matches to back references to prior capture groups `(...)` using
+the common `\num` syntax (like `\3`).
+
+If this flag is clear, then a numeric escape like `\3` will either be treated as a literal `3`,
+or, if `ONIG_SYN_OP_ESC_OCTAL3` is set, will be treated as an octal character code `\3`.
+
+You usually want this enabled, and it is enabled by default in every built-in syntax.
+
+
+### 17. ONIG_SYN_OP_BRACKET_CC (enable `[...]`)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Emacs, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for recognizing character classes, like `[a-z]`. If this flag is not set, `[`
+and `]` will be treated as ordinary literal characters instead of as metacharacters.
+
+You usually want this enabled, and it is enabled by default in every built-in syntax.
+
+
+### 18. ONIG_SYN_OP_ESC_W_WORD (enable `\w` and `\W`)
+
+_Set in: Oniguruma, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `\w` and `\W` shorthand forms. These match "word characters,"
+whose meaning varies depending on the encoding being used.
+
+In ASCII encoding, `\w` is equivalent to `[A-Za-z0-9_]`.
+
+In most other encodings, `\w` matches many more characters, including accented letters, Greek letters,
+Cyrillic letters, Braille letters and numbers, Runic letters, Hebrew letters, Arabic letters and numerals,
+Chinese Han ideographs, Japanese Katakana and Hiragana, Korean Hangul, and generally any symbol that
+could qualify as a phonetic "letter" or counting "number" in any language. (Note that emoji are _not_
+considered "word characters.")
+
+`\W` always matches the opposite of whatever `\w` matches.
+
+
+### 19. ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END (enable `\<` and `\>`)
+
+_Set in: Grep, GnuRegex_
+
+Enables support for the GNU-specific `\<` and `\>` word-boundary metacharacters. These work like
+the `\b` word-boundary metacharacter, but only match at one end of the word or the other: `\<`
+only matches at a transition from a non-word character to a word character (i.e., at the start
+of a word), and `\>` only matches at a transition from a word character to a non-word character
+(i.e., at the end of a word).
+
+Most regex syntaxes do _not_ support these metacharacters.
+
+
+### 20. ONIG_SYN_OP_ESC_B_WORD_BOUND (enable `\b` and `\B`)
+
+_Set in: Oniguruma, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `\b` and `\B` word-boundary metacharacters. The `\b` metacharacter
+matches a zero-width position at a transition from word-characters to non-word-characters, or vice
+versa. The `\B` metacharacter matches at all positions _not_ matched by `\b`.
+
+See details in `ONIG_SYN_OP_ESC_W_WORD` above for an explanation as to which characters
+are considered "word characters."
+
+
+### 21. ONIG_SYN_OP_ESC_S_WHITE_SPACE (enable `\s` and `\S`)
+
+_Set in: Oniguruma, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `\s` and `\S` whitespace-matching metacharacters.
+
+The `\s` metacharacter in ASCII encoding is exactly equivalent to the character class
+`[\t\n\v\f\r ]`, or characters codes 9 through 13 (inclusive), and 32.
+
+The `\s` metacharacter in Unicode is exactly equivalent to the character class
+`[\t\n\v\f\r \x85\xA0\x1680\x2000-\x200A\x2028-\x2029\x202F\x205F\x3000]` — that is, it matches
+the same as ASCII, plus U+0085 (next line), U+00A0 (nonbreaking space), U+1680 (Ogham space mark),
+U+2000 (en quad) through U+200A (hair space) (this range includes several widths of Unicode spaces),
+U+2028 (line separator) through U+2029 (paragraph separator),
+U+202F (narrow no-break space), U+205F (medium mathematical space), and U+3000 (CJK ideographic space).
+
+All non-Unicode encodings are handled by converting their code points to the appropriate
+Unicode-equivalent code points, and then matching according to Unicode rules.
+
+`\S` always matches any one character that is _not_ in the set matched by `\s`.
+
+
+### 22. ONIG_SYN_OP_ESC_D_DIGIT (enable `\d` and `\D`)
+
+_Set in: Oniguruma, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `\d` and `\D` digit-matching metacharacters.
+
+The `\d` metacharacter in ASCII encoding is exactly equivalent to the character class
+`[0-9]`, or characters codes 48 through 57 (inclusive).
+
+The `\d` metacharacter in Unicode matches `[0-9]`, as well as digits in Arabic, Devanagari,
+Bengali, Laotian, Mongolian, CJK fullwidth numerals, and many more.
+
+All non-Unicode encodings are handled by converting their code points to the appropriate
+Unicode-equivalent code points, and then matching according to Unicode rules.
+
+`\D` always matches any one character that is _not_ in the set matched by `\d`.
+
+
+### 23. ONIG_SYN_OP_LINE_ANCHOR (enable `^r` and `r$`)
+
+_Set in: Oniguruma, Emacs, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the common `^` and `$` line-anchor metacharacters.
+
+In single-line mode, `^` matches the start of the input buffer, and `$` matches
+the end of the input buffer. In multi-line mode, `^` matches if the preceding
+character is `\n`; and `$` matches if the following character is `\n`.
+
+(Note that Oniguruma does not recognize other newline types: It only matches
+`^` and `$` against `\n`: not `\r`, not `\r\n`, not the U+2028 line separator,
+and not any other form.)
+
+
+### 24. ONIG_SYN_OP_POSIX_BRACKET (enable POSIX `[:xxxx:]`)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Grep, GnuRegex, Perl, Java, Perl_NG, Ruby_
+
+Enables support for the POSIX `[:xxxx:]` character classes, like `[:alpha:]` and `[:digit:]`.
+The supported POSIX character classes are `alnum`, `alpha`, `blank`, `cntrl`, `digit`,
+`graph`, `lower`, `print`, `punct`, `space`, `upper`, `xdigit`, `ascii`, `word`.
+
+
+### 25. ONIG_SYN_OP_QMARK_NON_GREEDY (enable `r??`, `r*?`, `r+?`, and `r{n,m}?`)
+
+_Set in: Oniguruma, Perl, Java, Perl_NG, Ruby_
+
+Enables support for lazy (non-greedy) quantifiers: That is, if you append a `?` after
+another quantifier such as `?`, `*`, `+`, or `{n,m}`, Oniguruma will try to match
+as _little_ as possible instead of as _much_ as possible.
+
+
+### 26. ONIG_SYN_OP_ESC_CONTROL_CHARS (enable `\n`, `\r`, `\t`, etc.)
+
+_Set in: Oniguruma, PosixBasic, PosixExtended, Java, Perl, Perl_NG, Ruby_
+
+Enables support for C-style control-code escapes, like `\n` and `\r`. Specifically,
+this recognizes `\a` (7), `\b` (8), `\t` (9), `\n` (10), `\f` (12), `\r` (13), and
+`\e` (27). If ONIG_SYN_OP2_ESC_V_VTAB is enabled (see below), this also enables
+support for recognizing `\v` as code point 11.
+
+
+### 27. ONIG_SYN_OP_ESC_C_CONTROL (enable `\cx` control codes)
+
+_Set in: Oniguruma, Java, Perl, Perl_NG, Ruby_
+
+Enables support for named control-code escapes, like `\cm` or `\cM` for code-point
+13. In this shorthand form, control codes may be specified by `\c` (for "Control")
+followed by an alphabetic letter, a-z or A-Z, indicating which code point to represent
+(1 through 26). So `\cA` is code point 1, and `\cZ` is code point 26.
+
+
+### 28. ONIG_SYN_OP_ESC_OCTAL3 (enable `\OOO` octal codes)
+
+_Set in: Oniguruma, Java, Perl, Perl_NG, Ruby_
+
+Enables support for octal-style escapes of up to three digits, like `\1` for code
+point 1, and `\177` for code point 127. Octal values greater than 255 will result
+in an error message.
+
+
+### 29. ONIG_SYN_OP_ESC_X_HEX2 (enable `\xHH` hex codes)
+
+_Set in: Oniguruma, Java, Perl, Perl_NG, Ruby_
+
+Enables support for hexadecimal-style escapes of up to two digits, like `\x1` for code
+point 1, and `\x7F` for code point 127.
+
+
+### 30. ONIG_SYN_OP_ESC_X_BRACE_HEX8 (enable `\x{7HHHHHHH}` hex codes)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for brace-wrapped hexadecimal-style escapes of up to eight digits,
+like `\x{1}` for code point 1, and `\x{FFFE}` for code point 65534.
+
+
+### 31. ONIG_SYN_OP_ESC_O_BRACE_OCTAL (enable `\o{1OOOOOOOOOO}` octal codes)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for brace-wrapped octal-style escapes of up to eleven digits,
+like `\o{1}` for code point 1, and `\o{177776}` for code point 65534.
+
+(New feature as of Oniguruma 6.3.)
+
+
+----------
+
+
+## Group Two Flags (op2)
+
+
+This group contains support for lesser-known regex syntax constructs.
+
+
+### 0. ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE (enable `\Q...\E`)
+
+_Set in: Java, Perl, Perl_NG_
+
+Enables support for "quoted" parts of a pattern: Between `\Q` and `\E`, all
+syntax parsing is turned off, so that metacharacters like `*` and `+` will no
+longer be treated as metacharacters, and instead will be matched as literal
+`*` and `+`, as if they had been escaped with `\*` and `\+`.
+
+
+### 1. ONIG_SYN_OP2_QMARK_GROUP_EFFECT (enable `(?...)`)
+
+_Set in: Oniguruma, Java, Perl, Perl_NG, Ruby_
+
+Enables support for the fairly-common `(?...)` grouping operator, which
+controls precedence but which does _not_ capture its contents.
+
+
+### 2. ONIG_SYN_OP2_OPTION_PERL (enable options `(?imsx)` and `(?-imsx)`)
+
+_Set in: Java, Perl, Perl_NG_
+
+Enables support of regex options. (i,m,s,x)
+The supported toggle-able options for this flag are:
+
+ - `i` - Case-insensitivity
+ - `m` - Multi-line mode (`^` and `$` match at `\n` as well as start/end of buffer)
+ - `s` - Single-line mode (`.` can match `\n`)
+ - `x` - Extended pattern (free-formatting: whitespace will ignored)
+
+
+### 3. ONIG_SYN_OP2_OPTION_RUBY (enable options `(?imx)` and `(?-imx)`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support of regex options. (i,m,x)
+The supported toggle-able options for this flag are:
+
+ - `i` - Case-insensitivity
+ - `m` - Multi-line mode (`.` can match `\n`)
+ - `x` - Extended pattern (free-formatting: whitespace will ignored)
+
+
+### 4. ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT (enable `r?+`, `r*+`, and `r++`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support for the _possessive_ quantifiers `?+`, `*+`, and `++`, which
+work similarly to `?` and `*` and `+`, respectively, but which do not backtrack
+after matching: Like the normal greedy quantifiers, they match as much as
+possible, but they do not attempt to match _less_ than their maximum possible
+extent if subsequent parts of the pattern fail to match.
+
+
+### 5. ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL (enable `r{n,m}+`)
+
+_Set in: Java_
+
+Enables support for the _possessive_ quantifier `{n,m}+`, which
+works similarly to `{n,m}`, but which does not backtrack
+after matching: Like the normal greedy quantifier, it matches as much as
+possible, but it do not attempt to match _less_ than its maximum possible
+extent if subsequent parts of the pattern fail to match.
+
+
+### 6. ONIG_SYN_OP2_CCLASS_SET_OP (enable `&&` within `[...]`)
+
+_Set in: Oniguruma, Java, Ruby_
+
+Enables support for character-class _intersection_. For example, with this
+feature enabled, you can write `[a-z&&[^aeiou]]` to produce a character class
+of only consonants, or `[\0-\37&&[^\n\r]]` to produce a character class of
+all control codes _except_ newlines.
+
+
+### 7. ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP (enable named captures `(?<name>...)`)
+
+_Set in: Oniguruma, Perl_NG, Ruby_
+
+Enables support for _naming_ capture groups, so that instead of having to
+refer to captures by position (like `\3` or `$3`), you can refer to them by names
+(like `server` and `path`). This supports the Perl/Ruby naming syntaxes `(?<name>...)`
+and `(?'name'...)`, but not the Python `(?P<name>...)` syntax.
+
+
+### 8. ONIG_SYN_OP2_ESC_K_NAMED_BACKREF (enable named backreferences `\k<name>`)
+
+_Set in: Oniguruma, Perl_NG, Ruby_
+
+Enables support for substituted backreferences by name, not just by position.
+This supports using `\k'name'` in addition to supporting `\k<name>`. This also
+supports an Oniguruma-specific extension that lets you specify the _distance_ of
+the match, if the capture matched multiple times, by writing `\k<name+n>` or
+`\k<name-n>`.
+
+
+### 9. ONIG_SYN_OP2_ESC_G_SUBEXP_CALL (enable backreferences `\g<name>` and `\g<n>`)
+
+_Set in: Oniguruma, Perl_NG, Ruby_
+
+Enables support for substituted backreferences by both name and position using
+the same syntax. This supports using `\g'name'` and `\g'1'` in addition to
+supporting `\g<name>` and `\g<1>`.
+
+
+### 10. ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY (enable `(?@...)` and `(?@<name>...)`)
+
+_Set in: none_
+
+Enables support for _capture history_, which can answer via the `onig_*capture*()`
+functions exactly which captures were matched, how many times, and where in the
+input they were matched, by placing `?@` in front of the capture. Per Oniguruma's
+regex syntax documentation (appendix A-5):
+
+`/(?@a)*/.match("aaa")` ==> `[<0-1>, <1-2>, <2-3>]`
+
+This can require substantial memory, is primarily useful for debugging, and is not
+enabled by default in any syntax.
+
+
+### 11. ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL (enable `\C-x`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support for Ruby legacy control-code escapes, like `\C-m` or `\C-M` for code-point
+13. In this shorthand form, control codes may be specified by `\C-` (for "Control")
+followed by a single character (or equivalent), indicating which code point to represent,
+based on that character's lowest five bits. So, like `\c`, you can represent code-point
+10 with `\C-j`, but you can also represent it with `\C-*` as well.
+
+See also ONIG_SYN_OP_ESC_C_CONTROL, which enables the more-common `\cx` syntax.
+
+
+### 12. ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META (enable `\M-x`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support for Ruby legacy meta-code escapes. When you write `\M-x`, Oniguruma
+will match an `x` whose 8th bit is set (i.e., the character code of `x` will be or'ed
+with `0x80`). So, for example, you can match `\x81` using `\x81`, or you can write
+`\M-\1`. This is mostly useful when working with legacy 8-bit character encodings.
+
+
+### 13. ONIG_SYN_OP2_ESC_V_VTAB (enable `\v` as vertical tab)
+
+_Set in: Oniguruma, Java, Ruby_
+
+Enables support for a C-style `\v` escape code, meaning "vertical tab." If enabled,
+`\v` will be equivalent to ASCII code point 11.
+
+
+### 14. ONIG_SYN_OP2_ESC_U_HEX4 (enable `\uHHHH` for Unicode)
+
+_Set in: Oniguruma, Java, Ruby_
+
+Enables support for a Java-style `\uHHHH` escape code for representing Unicode
+code-points by number, using up to four hexadecimal digits (up to `\uFFFF`). So,
+for example, `\u221E` will match an infinity symbol, `∞`.
+
+For code points larger than four digits, like the emoji `🚡` (aerial tramway, or code
+point U+1F6A1), you must either represent the character directly using an encoding like
+UTF-8, or you must enable support for ONIG_SYN_OP_ESC_X_BRACE_HEX8 or
+ONIG_SYN_OP_ESC_O_BRACE_OCTAL, which support more than four digits.
+
+(New feature as of Oniguruma 6.7.)
+
+
+### 15. ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR (enable ``\` `` and `\'` anchors)
+
+_Set in: Emacs_
+
+This flag makes the ``\` `` and `\'` escapes function identically to
+`\A` and `\z`, respectively (when ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR is enabled).
+
+These anchor forms are very obscure, and rarely supported by other regex libraries.
+
+
+### 16. ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY (enable `\p{...}` and `\P{...}`)
+
+_Set in: Oniguruma, Java, Perl, Perl_NG, Ruby_
+
+Enables support for an alternate syntax for POSIX character classes; instead of
+writing `[:alpha:]` when this is enabled, you can instead write `\p{alpha}`.
+
+See also ONIG_SYN_OP_POSIX_BRACKET for the classic POSIX form.
+
+
+### 17. ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT (enable `\p{^...}` and `\P{^...}`)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for an alternate syntax for POSIX character classes; instead of
+writing `[:^alpha:]` when this is enabled, you can instead write `\p{^alpha}`.
+
+See also ONIG_SYN_OP_POSIX_BRACKET for the classic POSIX form.
+
+
+### 18. ONIG_SYN_OP2_CHAR_PROPERTY_PREFIX_IS
+
+_(not presently used)_
+
+
+### 19. ONIG_SYN_OP2_ESC_H_XDIGIT (enable `\h` and `\H`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support for the Ruby-specific shorthand `\h` and `\H` metacharacters.
+Somewhat like `\d` matches decimal digits, `\h` matches hexadecimal digits — that is,
+characters in `[0-9a-fA-F]`.
+
+`\H` matches the opposite of whatever `\h` matches.
+
+
+### 20. ONIG_SYN_OP2_INEFFECTIVE_ESCAPE (disable `\`)
+
+_Set in: As-is_
+
+If set, this disables all escape codes, shorthands, and metacharacters that start
+with `\` (or whatever the configured escape character is), allowing `\` to be treated
+as a literal `\`.
+
+You usually do not want this flag to be enabled.
+
+
+### 21. ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE (enable `(?(...)then|else)`)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for conditional inclusion of subsequent regex patterns based on whether
+a prior named or numbered capture matched, or based on whether a pattern will
+match. This supports many different forms, including:
+
+ - `(?(<foo>)then|else)` - condition based on a capture by name.
+ - `(?('foo')then|else)` - condition based on a capture by name.
+ - `(?(3)then|else)` - condition based on a capture by number.
+ - `(?(+3)then|else)` - forward conditional to a future match, by relative position.
+ - `(?(-3)then|else)` - backward conditional to a prior match, by relative position.
+ - `(?(foo)then|else)` - this matches a pattern `foo`. (foo is any sub-expression)
+
+(New feature as of Oniguruma 6.5.)
+
+
+### 22. ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP (enable `\K`)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for `\K`, which excludes all content before it from the overall
+regex match (i.e., capture #0). So, for example, pattern `foo\Kbar` would match
+`foobar`, but capture #0 would only include `bar`.
+
+(New feature as of Oniguruma 6.5.)
+
+
+### 23. ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE (enable `\R`)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+Enables support for `\R`, the "general newline" shorthand, which matches
+`(\r\n|[\n\v\f\r\u0085\u2028\u2029])` (obviously, the Unicode values are cannot be
+matched in ASCII encodings).
+
+(New feature as of Oniguruma 6.5.)
+
+
+### 24. ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT (enable `\N` and `\O`)
+
+_Set in: Oniguruma, Perl, Perl_NG_
+
+Enables support for `\N` and `\O`. `\N` is "not a line break," which is much
+like the standard `.` metacharacter, except that while `.` can be affected by
+the single-line setting, `\N` always matches exactly one character that is not
+one of the various line-break characters (like `\n` and `\r`).
+
+`\O` matches exactly one character, regardless of whether single-line or
+multi-line mode are enabled or disabled.
+
+(New feature as of Oniguruma 6.5.)
+
+
+### 25. ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP (enable `(?~...)`)
+
+_Set in: Oniguruma, Ruby_
+
+Enables support for the `(?~r)` "absent operator" syntax, which matches
+as much as possible as long as the result _doesn't_ match pattern `r`. This is
+_not_ the same as negative lookahead or negative lookbehind.
+
+Among the most useful examples of this is `\/\*(?~\*\/)\*\/`, which matches
+C-style comments by simply saying "starts with /*, ends with */, and _doesn't_
+contain a */ in between."
+
+A full explanation of this feature is complicated, but it is useful, and an
+excellent article about it is [available on Medium](https://medium.com/rubyinside/the-new-absent-operator-in-ruby-s-regular-expressions-7c3ef6cd0b99).
+
+(New feature as of Oniguruma 6.5.)
+
+
+### 26. ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT (enable `\X` and `\Y` and `\y`)
+
+_Set in: Oniguruma, Perl, Perl_NG, Ruby_
+
+`\X` is another variation on `.`, designed to support Unicode, in that it matches
+a full _grapheme cluster_. In Unicode, `à` can be encoded as one code point,
+`U+00E0`, or as two, `U+0061 U+0300`. If those are further escaped using UTF-8,
+the former becomes two bytes, and the latter becomes three. Unfortunately, `.`
+would naively match only one or two bytes, depending on the encoding, and would
+likely incorrectly match anything from just `a` to a broken half of a code point.
+`\X` is designed to fix this: It matches the full `à`, no matter how `à` is
+encoded or decomposed.
+
+`\y` matches a cluster boundary, i.e., a zero-width position between
+graphemes, somewhat like `\b` matches boundaries between words. `\Y` matches
+the _opposite_ of `\y`, that is, a zero-width position between code points in
+the _middle_ of a grapheme.
+
+(New feature as of Oniguruma 6.6.)
+
+
+### 27. ONIG_SYN_OP2_QMARK_PERL_SUBEXP_CALL (enable `(?R)` and `(?&name)`)
+
+_Set in: Perl_NG_
+
+Enables support for substituted backreferences by both name and position using
+Perl-5-specific syntax. This supports using `(?R3)` and `(?&name)` to reference
+previous (and future) matches, similar to the more-common `\g<3>` and `\g<name>`
+backreferences.
+
+(New feature as of Oniguruma 6.7.)
+
+
+### 28. ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS (enable `(?{...})`)
+
+_Set in: Oniguruma, Perl, Perl_NG_
+
+Enables support for Perl-style "callouts" — pattern substitutions that result from
+invoking a callback method. When `(?{foo})` is reached in a pattern, the callback
+function set in `onig_set_progress_callout()` will be invoked, and be able to perform
+custom computation during the pattern match (and during backtracking).
+
+Full documentation for this advanced feature can be found in the Oniguruma
+`docs/CALLOUT.md` file, with an example in `samples/callout.c`.
+
+(New feature as of Oniguruma 6.8.)
+
+
+### 29. ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME (enable `(*name)`)
+
+_Set in: Oniguruma, Perl, Perl_NG_
+
+Enables support for Perl-style "callouts" — pattern substitutions that result from
+invoking a callback method. When `(*foo)` is reached in a pattern, the callback
+function set in `onig_set_callout_of_name()` will be invoked, passing the given name
+`foo` to it, and it can perform custom computation during the pattern match (and
+during backtracking).
+
+Full documentation for this advanced feature can be found in the Oniguruma
+`docs/CALLOUT.md` file, with an example in `samples/callout.c`.
+
+(New feature as of Oniguruma 6.8.)
+
+
+### 30. ONIG_SYN_OP2_OPTION_ONIGURUMA (enable options `(?imxWSDPy)` and `(?-imxWDSP)`)
+
+_Set in: Oniguruma_
+
+Enables support of regex options. (i,m,x,W,S,D,P,y)
+
+(New feature as of Oniguruma 6.9.2)
+
+ - `i` - Case-insensitivity
+ - `m` - Multi-line mode (`.` can match `\n`)
+ - `x` - Extended pattern (free-formatting: whitespace will ignored)
+ - `W` - ASCII only word.
+ - `D` - ASCII only digit.
+ - `S` - ASCII only space.
+ - `P` - ASCII only POSIX properties. (includes W,D,S)
+
+----------
+
+
+## Syntax Flags (syn)
+
+
+This group contains rules to handle corner cases and constructs that are errors in
+some syntaxes but not in others.
+
+### 0. ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS (independent `?`, `*`, `+`, `{n,m}`)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+This flag specifies how to handle operators like `?` and `*` when they aren't
+directly attached to an operand, as in `^*` or `(*)`: Are they an error, are
+they discarded, or are they taken as literals? If this flag is clear, they
+are taken as literals; otherwise, the ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS flag
+determines if they are errors or if they are discarded.
+
+### 1. ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS (error or ignore independent operators)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+If ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS is set, this flag controls what happens when
+independent operators appear in a pattern: If this flag is set, then independent
+operators produce an error message; if this flag is clear, then independent
+operators are silently discarded.
+
+### 2. ONIG_SYN_ALLOW_UNMATCHED_CLOSE_SUBEXP (allow `...)...`)
+
+_Set in: PosixExtended_
+
+This flag, if set, causes a `)` character without a preceding `(` to be treated as
+a literal `)`, equivalent to `\)`. If this flag is clear, then an unmatched `)`
+character will produce an error message.
+
+### 3. ONIG_SYN_ALLOW_INVALID_INTERVAL (allow `{???`)
+
+_Set in: Oniguruma, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+This flag, if set, causes an invalid range, like `foo{bar}` or `foo{}`, to be
+silently discarded, as if `foo` had been written instead. If clear, an invalid
+range will produce an error message.
+
+### 4. ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV (allow `{,n}` to mean `{0,n}`)
+
+_Set in: Oniguruma, Ruby_
+
+If this flag is set, then `r{,n}` will be treated as equivalent to writing
+`{0,n}`. If this flag is clear, then `r{,n}` will produce an error message.
+
+Note that regardless of whether this flag is set or clear, if
+ONIG_SYN_OP_BRACE_INTERVAL is enabled, then `r{n,}` will always be legal: This
+flag *only* controls the behavior of the opposite form, `r{,n}`.
+
+### 5. ONIG_SYN_STRICT_CHECK_BACKREF (error on invalid backrefs)
+
+_Set in: none_
+
+If this flag is set, an invalid backref, like `\1` in a pattern with no captures,
+will produce an error. If this flag is clear, then an invalid backref will be
+equivalent to the empty string.
+
+No built-in syntax has this flag enabled.
+
+### 6. ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND (allow `(?<=a|bc)`)
+
+_Set in: Oniguruma, Java, Ruby_
+
+If this flag is set, lookbehind patterns with alternate options may have differing
+lengths among those options. If this flag is clear, lookbehind patterns with options
+must have each option have identical length to the other options.
+
+Oniguruma can handle either form, but not all regex engines can, so for compatibility,
+Oniguruma allows you to cause regexes for other regex engines to fail if they might
+depend on this rule.
+
+### 7. ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP (prefer `\k<name>` over `\3`)
+
+_Set in: Oniguruma, Perl_NG, Ruby_
+
+If this flag is set on the syntax *and* ONIG_OPTION_CAPTURE_GROUP is set when calling
+Oniguruma, then if a name is used on any capture, all captures must also use names: A
+single use of a named capture prohibits the use of numbered captures.
+
+### 8. ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME (allow `(?<x>)...(?<x>)`)
+
+_Set in: Oniguruma, Perl_NG, Ruby_
+
+If this flag is set, multiple capture groups may use the same name. If this flag is
+clear, then reuse of a name will produce an error message.
+
+### 9. ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY (`a{n}?` is equivalent to `(?:a{n})?`)
+
+_Set in: Oniguruma, Ruby_
+
+If this flag is set, then intervals of a fixed size will ignore a lazy (non-greedy)
+`?` quantifier and treat it as an optional match (an ordinary `r?`), since "match as
+little as possible" is meaningless for a fixed-size interval. If this flag is clear,
+then `r{n}?` will mean the same as `r{n}`, and the useless `?` will be discarded.
+
+### 10. ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH (`..(?i)..`)
+
+_Set in: Perl, Perl_NG, Java_
+
+If this flag is set, then an isolated option doesn't break the branch and affects until the end of the group (or end of the pattern).
+If this flag is not set, then an isolated option is interpreted as the starting point of a new branch. /a(?i)b|c/ ==> /a(?i:b|c)/
+
+### 11. ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND (`(?<=...a+...)`)
+
+_Set in: Oniguruma, Java_
+
+If this flag is set, then a variable length expressions are allowed in look-behind.
+
+### 20. ONIG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC (add `\n` to `[^...]`)
+
+_Set in: Grep_
+
+If this flag is set, all newline characters (like `\n`) will be excluded from a negative
+character class automatically, as if the pattern had been written as `[^...\n]`. If this
+flag is clear, negative character classes do not automatically exclude newlines, and
+only exclude those characters and ranges written in them.
+
+### 21. ONIG_SYN_BACKSLASH_ESCAPE_IN_CC (allow `[...\w...]`)
+
+_Set in: Oniguruma, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+If this flag is set, shorthands like `\w` are allowed to describe characters in character
+classes. If this flag is clear, shorthands like `\w` are treated as a redundantly-escaped
+literal `w`.
+
+### 22. ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC (silently discard `[z-a]`)
+
+_Set in: Emacs, Grep_
+
+If this flag is set, then character ranges like `[z-a]` that are broken or contain no
+characters will be silently ignored. If this flag is clear, then broken or empty
+character ranges will produce an error message.
+
+### 23. ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC (treat `[0-9-a]` as `[0-9\-a]`)
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+If this flag is set, then a trailing `-` after a character range will be taken as a
+literal `-`, as if it had been escaped as `\-`. If this flag is clear, then a trailing
+`-` after a character range will produce an error message.
+
+### 24. ONIG_SYN_WARN_CC_OP_NOT_ESCAPED (warn on `[[...]` and `[-x]`)
+
+_Set in: Oniguruma, Ruby_
+
+If this flag is set, Oniguruma will be stricter about warning for bad forms in
+character classes: `[[...]` will produce a warning, but `[\[...]` will not;
+`[-x]` will produce a warning, but `[\-x]` will not; `[x&&-y]` will produce a warning,
+while `[x&&\-y]` will not; and so on. If this flag is clear, all of these warnings
+will be silently discarded.
+
+### 25. ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT (warn on `(?:a*)+`)
+
+_Set in: Oniguruma, Ruby_
+
+If this flag is set, Oniguruma will warn about nested repeat operators those have no meaning, like `(?:a*)+`.
+If this flag is clear, Oniguruma will allow the nested repeat operators without warning about them.
+
+### 26. ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC (allow [a-\x{7fffffff}])
+
+_Set in: Oniguruma_
+
+If this flag is set, then invalid code points at the end of range in character class are allowed.
+
+### 31. ONIG_SYN_CONTEXT_INDEP_ANCHORS
+
+_Set in: Oniguruma, PosixExtended, GnuRegex, Java, Perl, Perl_NG, Ruby_
+
+Not currently used, and does nothing. (But still set in several syntaxes for some
+reason.)
+
+----------
+
+## Usage tables
+
+These tables show which of the built-in syntaxes use which flags and options, for easy comparison between them.
+
+### Group One Flags (op)
+
+| ID | Option | PosB | PosEx | Emacs | Grep | Gnu | Java | Perl | PeNG | Ruby | Onig |
+| ----- | --------------------------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- |
+| 0 | `ONIG_SYN_OP_VARIABLE_META_CHARACTERS` | - | - | - | - | - | - | - | - | - | - |
+| 1 | `ONIG_SYN_OP_DOT_ANYCHAR` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 2 | `ONIG_SYN_OP_ASTERISK_ZERO_INF` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 3 | `ONIG_SYN_OP_ESC_ASTERISK_ZERO_INF` | - | - | - | - | - | - | - | - | - | - |
+| 4 | `ONIG_SYN_OP_PLUS_ONE_INF` | - | Yes | Yes | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 5 | `ONIG_SYN_OP_ESC_PLUS_ONE_INF` | - | - | - | Yes | - | - | - | - | - | - |
+| 6 | `ONIG_SYN_OP_QMARK_ZERO_ONE` | - | Yes | Yes | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 7 | `ONIG_SYN_OP_ESC_QMARK_ZERO_ONE` | - | - | - | Yes | - | - | - | - | - | - |
+| 8 | `ONIG_SYN_OP_BRACE_INTERVAL` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 9 | `ONIG_SYN_OP_ESC_BRACE_INTERVAL` | Yes | - | Yes | Yes | - | - | - | - | - | - |
+| 10 | `ONIG_SYN_OP_VBAR_ALT` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 11 | `ONIG_SYN_OP_ESC_VBAR_ALT` | - | - | Yes | Yes | - | - | - | - | - | - |
+| 12 | `ONIG_SYN_OP_LPAREN_SUBEXP` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 13 | `ONIG_SYN_OP_ESC_LPAREN_SUBEXP` | Yes | - | Yes | Yes | - | - | - | - | - | - |
+| 14 | `ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 15 | `ONIG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 16 | `ONIG_SYN_OP_DECIMAL_BACKREF` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 17 | `ONIG_SYN_OP_BRACKET_CC` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 18 | `ONIG_SYN_OP_ESC_W_WORD` | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 19 | `ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END` | - | - | - | Yes | Yes | - | - | - | - | - |
+| 20 | `ONIG_SYN_OP_ESC_B_WORD_BOUND` | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 21 | `ONIG_SYN_OP_ESC_S_WHITE_SPACE` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 22 | `ONIG_SYN_OP_ESC_D_DIGIT` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 23 | `ONIG_SYN_OP_LINE_ANCHOR` | - | - | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+| 24 | `ONIG_SYN_OP_POSIX_BRACKET` | Yes | Yes | Yes | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 25 | `ONIG_SYN_OP_QMARK_NON_GREEDY` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 26 | `ONIG_SYN_OP_ESC_CONTROL_CHARS` | Yes | Yes | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 27 | `ONIG_SYN_OP_ESC_C_CONTROL` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 28 | `ONIG_SYN_OP_ESC_OCTAL3` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 29 | `ONIG_SYN_OP_ESC_X_HEX2` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 30 | `ONIG_SYN_OP_ESC_X_BRACE_HEX8` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 31 | `ONIG_SYN_OP_ESC_O_BRACE_OCTAL` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+
+### Group Two Flags (op2)
+
+| ID | Option | PosB | PosEx | Emacs | Grep | Gnu | Java | Perl | PeNG | Ruby | Onig |
+| ----- | --------------------------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- |
+| 0 | `ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE` | - | - | - | - | - | Yes | Yes | Yes | - | - |
+| 1 | `ONIG_SYN_OP2_QMARK_GROUP_EFFECT` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 2 | `ONIG_SYN_OP2_OPTION_PERL` | - | - | - | - | - | Yes | Yes | Yes | - | - |
+| 3 | `ONIG_SYN_OP2_OPTION_RUBY` | - | - | - | - | - | - | - | - | Yes | - |
+| 4 | `ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 5 | `ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL` | - | - | - | - | - | Yes | - | - | - | - |
+| 6 | `ONIG_SYN_OP2_CCLASS_SET_OP` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 7 | `ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 8 | `ONIG_SYN_OP2_ESC_K_NAMED_BACKREF` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 9 | `ONIG_SYN_OP2_ESC_G_SUBEXP_CALL` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 10 | `ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY` | - | - | - | - | - | - | - | - | - | - |
+| 11 | `ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 12 | `ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 13 | `ONIG_SYN_OP2_ESC_V_VTAB` | - | - | - | - | - | Yes | - | - | Yes | Yes |
+| 14 | `ONIG_SYN_OP2_ESC_U_HEX4` | - | - | - | - | - | Yes | - | - | Yes | Yes |
+| 15 | `ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR` | - | - | Yes | - | - | - | - | - | - | - |
+| 16 | `ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY` | - | - | - | - | - | Yes | Yes | Yes | Yes | Yes |
+| 17 | `ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 18 | `ONIG_SYN_OP2_CHAR_PROPERTY_PREFIX_IS` | - | - | - | - | - | - | - | - | - | - |
+| 19 | `ONIG_SYN_OP2_ESC_H_XDIGIT` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 20 | `ONIG_SYN_OP2_INEFFECTIVE_ESCAPE` | - | - | - | - | - | - | - | - | - | - |
+| 21 | `ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 22 | `ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 23 | `ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 24 | `ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT` | - | - | - | - | - | - | Yes | Yes | - | Yes |
+| 25 | `ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 26 | `ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT` | - | - | - | - | - | - | Yes | Yes | Yes | Yes |
+| 27 | `ONIG_SYN_OP2_QMARK_PERL_SUBEXP_CALL` | - | - | - | - | - | - | - | Yes | - | - |
+| 28 | `ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS` | - | - | - | - | - | - | Yes | Yes | Yes | - |
+| 29 | `ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME` | - | - | - | - | - | - | Yes | Yes | Yes | - |
+| 30 | `ONIG_SYN_OP2_OPTION_ONIGURUMA` | - | - | - | - | - | - | - | - | - | Yes |
+
+### Syntax Flags (syn)
+
+| ID | Option | PosB | PosEx | Emacs | Grep | Gnu | Java | Perl | PeNG | Ruby | Onig |
+| ----- | --------------------------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- |
+| 0 | `ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 1 | `ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 2 | `ONIG_SYN_ALLOW_UNMATCHED_CLOSE_SUBEXP` | - | Yes | - | - | - | - | - | - | - | - |
+| 3 | `ONIG_SYN_ALLOW_INVALID_INTERVAL` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 4 | `ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 5 | `ONIG_SYN_STRICT_CHECK_BACKREF` | - | - | - | - | - | - | - | - | - | - |
+| 6 | `ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND` | - | - | - | - | - | Yes | - | - | Yes | Yes |
+| 7 | `ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 8 | `ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME` | - | - | - | - | - | - | - | Yes | Yes | Yes |
+| 9 | `ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 10 | `ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH` | - | - | - | - | - | Yes | Yes | Yes | - | - |
+| 11 | `ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND` | - | - | - | - | - | Yes | - | - | - | Yes |
+| 20 | `ONIG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC` | - | - | - | Yes | - | - | - | - | - | - |
+| 21 | `ONIG_SYN_BACKSLASH_ESCAPE_IN_CC` | - | - | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 22 | `ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC` | - | - | Yes | Yes | - | - | - | - | - | - |
+| 23 | `ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
+| 24 | `ONIG_SYN_WARN_CC_OP_NOT_ESCAPED` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 25 | `ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT` | - | - | - | - | - | - | - | - | Yes | Yes |
+| 26 | `ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC` | - | - | - | - | - | - | - | - | - | Yes |
+| 31 | `ONIG_SYN_CONTEXT_INDEP_ANCHORS` | - | Yes | - | - | Yes | Yes | Yes | Yes | Yes | Yes |
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/UNICODE_PROPERTIES b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/UNICODE_PROPERTIES
new file mode 100644
index 000000000..24c203156
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/doc/UNICODE_PROPERTIES
@@ -0,0 +1,788 @@
+Unicode Properties (Unicode Version: 12.1.0, Emoji: 12.1)
+
+ 15: ASCII_Hex_Digit
+ 16: Adlam
+ 17: Ahom
+ 18: Alphabetic
+ 19: Anatolian_Hieroglyphs
+ 20: Any
+ 21: Arabic
+ 22: Armenian
+ 23: Assigned
+ 24: Avestan
+ 25: Balinese
+ 26: Bamum
+ 27: Bassa_Vah
+ 28: Batak
+ 29: Bengali
+ 30: Bhaiksuki
+ 31: Bidi_Control
+ 32: Bopomofo
+ 33: Brahmi
+ 34: Braille
+ 35: Buginese
+ 36: Buhid
+ 37: C
+ 38: Canadian_Aboriginal
+ 39: Carian
+ 40: Case_Ignorable
+ 41: Cased
+ 42: Caucasian_Albanian
+ 43: Cc
+ 44: Cf
+ 45: Chakma
+ 46: Cham
+ 47: Changes_When_Casefolded
+ 48: Changes_When_Casemapped
+ 49: Changes_When_Lowercased
+ 50: Changes_When_Titlecased
+ 51: Changes_When_Uppercased
+ 52: Cherokee
+ 53: Cn
+ 54: Co
+ 55: Common
+ 56: Coptic
+ 57: Cs
+ 58: Cuneiform
+ 59: Cypriot
+ 60: Cyrillic
+ 61: Dash
+ 62: Default_Ignorable_Code_Point
+ 63: Deprecated
+ 64: Deseret
+ 65: Devanagari
+ 66: Diacritic
+ 67: Dogra
+ 68: Duployan
+ 69: Egyptian_Hieroglyphs
+ 70: Elbasan
+ 71: Elymaic
+ 72: Emoji
+ 73: Emoji_Component
+ 74: Emoji_Modifier
+ 75: Emoji_Modifier_Base
+ 76: Emoji_Presentation
+ 77: Ethiopic
+ 78: Extended_Pictographic
+ 79: Extender
+ 80: Georgian
+ 81: Glagolitic
+ 82: Gothic
+ 83: Grantha
+ 84: Grapheme_Base
+ 85: Grapheme_Extend
+ 86: Grapheme_Link
+ 87: Greek
+ 88: Gujarati
+ 89: Gunjala_Gondi
+ 90: Gurmukhi
+ 91: Han
+ 92: Hangul
+ 93: Hanifi_Rohingya
+ 94: Hanunoo
+ 95: Hatran
+ 96: Hebrew
+ 97: Hex_Digit
+ 98: Hiragana
+ 99: Hyphen
+100: IDS_Binary_Operator
+101: IDS_Trinary_Operator
+102: ID_Continue
+103: ID_Start
+104: Ideographic
+105: Imperial_Aramaic
+106: Inherited
+107: Inscriptional_Pahlavi
+108: Inscriptional_Parthian
+109: Javanese
+110: Join_Control
+111: Kaithi
+112: Kannada
+113: Katakana
+114: Kayah_Li
+115: Kharoshthi
+116: Khmer
+117: Khojki
+118: Khudawadi
+119: L
+120: LC
+121: Lao
+122: Latin
+123: Lepcha
+124: Limbu
+125: Linear_A
+126: Linear_B
+127: Lisu
+128: Ll
+129: Lm
+130: Lo
+131: Logical_Order_Exception
+132: Lowercase
+133: Lt
+134: Lu
+135: Lycian
+136: Lydian
+137: M
+138: Mahajani
+139: Makasar
+140: Malayalam
+141: Mandaic
+142: Manichaean
+143: Marchen
+144: Masaram_Gondi
+145: Math
+146: Mc
+147: Me
+148: Medefaidrin
+149: Meetei_Mayek
+150: Mende_Kikakui
+151: Meroitic_Cursive
+152: Meroitic_Hieroglyphs
+153: Miao
+154: Mn
+155: Modi
+156: Mongolian
+157: Mro
+158: Multani
+159: Myanmar
+160: N
+161: Nabataean
+162: Nandinagari
+163: Nd
+164: New_Tai_Lue
+165: Newa
+166: Nko
+167: Nl
+168: No
+169: Noncharacter_Code_Point
+170: Nushu
+171: Nyiakeng_Puachue_Hmong
+172: Ogham
+173: Ol_Chiki
+174: Old_Hungarian
+175: Old_Italic
+176: Old_North_Arabian
+177: Old_Permic
+178: Old_Persian
+179: Old_Sogdian
+180: Old_South_Arabian
+181: Old_Turkic
+182: Oriya
+183: Osage
+184: Osmanya
+185: Other_Alphabetic
+186: Other_Default_Ignorable_Code_Point
+187: Other_Grapheme_Extend
+188: Other_ID_Continue
+189: Other_ID_Start
+190: Other_Lowercase
+191: Other_Math
+192: Other_Uppercase
+193: P
+194: Pahawh_Hmong
+195: Palmyrene
+196: Pattern_Syntax
+197: Pattern_White_Space
+198: Pau_Cin_Hau
+199: Pc
+200: Pd
+201: Pe
+202: Pf
+203: Phags_Pa
+204: Phoenician
+205: Pi
+206: Po
+207: Prepended_Concatenation_Mark
+208: Ps
+209: Psalter_Pahlavi
+210: Quotation_Mark
+211: Radical
+212: Regional_Indicator
+213: Rejang
+214: Runic
+215: S
+216: Samaritan
+217: Saurashtra
+218: Sc
+219: Sentence_Terminal
+220: Sharada
+221: Shavian
+222: Siddham
+223: SignWriting
+224: Sinhala
+225: Sk
+226: Sm
+227: So
+228: Soft_Dotted
+229: Sogdian
+230: Sora_Sompeng
+231: Soyombo
+232: Sundanese
+233: Syloti_Nagri
+234: Syriac
+235: Tagalog
+236: Tagbanwa
+237: Tai_Le
+238: Tai_Tham
+239: Tai_Viet
+240: Takri
+241: Tamil
+242: Tangut
+243: Telugu
+244: Terminal_Punctuation
+245: Thaana
+246: Thai
+247: Tibetan
+248: Tifinagh
+249: Tirhuta
+250: Ugaritic
+251: Unified_Ideograph
+252: Unknown
+253: Uppercase
+254: Vai
+255: Variation_Selector
+256: Wancho
+257: Warang_Citi
+258: White_Space
+259: XID_Continue
+260: XID_Start
+261: Yi
+262: Z
+263: Zanabazar_Square
+264: Zl
+265: Zp
+266: Zs
+ 16: Adlm
+ 42: Aghb
+ 15: AHex
+ 21: Arab
+105: Armi
+ 22: Armn
+ 24: Avst
+ 25: Bali
+ 26: Bamu
+ 27: Bass
+ 28: Batk
+ 29: Beng
+ 30: Bhks
+ 31: Bidi_C
+ 32: Bopo
+ 33: Brah
+ 34: Brai
+ 35: Bugi
+ 36: Buhd
+ 45: Cakm
+ 38: Cans
+ 39: Cari
+120: Cased_Letter
+ 52: Cher
+ 40: CI
+201: Close_Punctuation
+137: Combining_Mark
+199: Connector_Punctuation
+ 43: Control
+ 56: Copt
+ 59: Cprt
+218: Currency_Symbol
+ 47: CWCF
+ 48: CWCM
+ 49: CWL
+ 50: CWT
+ 51: CWU
+ 60: Cyrl
+200: Dash_Punctuation
+163: Decimal_Number
+ 63: Dep
+ 65: Deva
+ 62: DI
+ 66: Dia
+ 67: Dogr
+ 64: Dsrt
+ 68: Dupl
+ 69: Egyp
+ 70: Elba
+ 71: Elym
+147: Enclosing_Mark
+ 77: Ethi
+ 79: Ext
+202: Final_Punctuation
+ 44: Format
+ 80: Geor
+ 81: Glag
+ 89: Gong
+144: Gonm
+ 82: Goth
+ 83: Gran
+ 84: Gr_Base
+ 87: Grek
+ 85: Gr_Ext
+ 86: Gr_Link
+ 88: Gujr
+ 90: Guru
+ 92: Hang
+ 91: Hani
+ 94: Hano
+ 95: Hatr
+ 96: Hebr
+ 97: Hex
+ 98: Hira
+ 19: Hluw
+194: Hmng
+171: Hmnp
+174: Hung
+102: IDC
+104: Ideo
+103: IDS
+100: IDSB
+101: IDST
+205: Initial_Punctuation
+175: Ital
+109: Java
+110: Join_C
+114: Kali
+113: Kana
+115: Khar
+116: Khmr
+117: Khoj
+112: Knda
+111: Kthi
+238: Lana
+121: Laoo
+122: Latn
+123: Lepc
+119: Letter
+167: Letter_Number
+124: Limb
+125: Lina
+126: Linb
+264: Line_Separator
+131: LOE
+128: Lowercase_Letter
+135: Lyci
+136: Lydi
+138: Mahj
+139: Maka
+141: Mand
+142: Mani
+143: Marc
+137: Mark
+226: Math_Symbol
+148: Medf
+150: Mend
+151: Merc
+152: Mero
+140: Mlym
+129: Modifier_Letter
+225: Modifier_Symbol
+156: Mong
+157: Mroo
+149: Mtei
+158: Mult
+159: Mymr
+162: Nand
+176: Narb
+161: Nbat
+169: NChar
+166: Nkoo
+154: Nonspacing_Mark
+170: Nshu
+160: Number
+185: OAlpha
+186: ODI
+172: Ogam
+187: OGr_Ext
+188: OIDC
+189: OIDS
+173: Olck
+190: OLower
+191: OMath
+208: Open_Punctuation
+181: Orkh
+182: Orya
+183: Osge
+184: Osma
+ 37: Other
+130: Other_Letter
+168: Other_Number
+206: Other_Punctuation
+227: Other_Symbol
+192: OUpper
+195: Palm
+265: Paragraph_Separator
+196: Pat_Syn
+197: Pat_WS
+198: Pauc
+207: PCM
+177: Perm
+203: Phag
+107: Phli
+209: Phlp
+204: Phnx
+153: Plrd
+ 54: Private_Use
+108: Prti
+193: Punctuation
+ 56: Qaac
+106: Qaai
+210: QMark
+212: RI
+213: Rjng
+ 93: Rohg
+214: Runr
+216: Samr
+180: Sarb
+217: Saur
+228: SD
+262: Separator
+223: Sgnw
+221: Shaw
+220: Shrd
+222: Sidd
+118: Sind
+224: Sinh
+229: Sogd
+179: Sogo
+230: Sora
+231: Soyo
+266: Space_Separator
+146: Spacing_Mark
+219: STerm
+232: Sund
+ 57: Surrogate
+233: Sylo
+215: Symbol
+234: Syrc
+236: Tagb
+240: Takr
+237: Tale
+164: Talu
+241: Taml
+242: Tang
+239: Tavt
+243: Telu
+244: Term
+248: Tfng
+235: Tglg
+245: Thaa
+247: Tibt
+249: Tirh
+133: Titlecase_Letter
+250: Ugar
+251: UIdeo
+ 53: Unassigned
+134: Uppercase_Letter
+254: Vaii
+255: VS
+257: Wara
+256: Wcho
+258: WSpace
+259: XIDC
+260: XIDS
+178: Xpeo
+ 58: Xsux
+261: Yiii
+263: Zanb
+106: Zinh
+ 55: Zyyy
+252: Zzzz
+267: In_Basic_Latin
+268: In_Latin_1_Supplement
+269: In_Latin_Extended_A
+270: In_Latin_Extended_B
+271: In_IPA_Extensions
+272: In_Spacing_Modifier_Letters
+273: In_Combining_Diacritical_Marks
+274: In_Greek_and_Coptic
+275: In_Cyrillic
+276: In_Cyrillic_Supplement
+277: In_Armenian
+278: In_Hebrew
+279: In_Arabic
+280: In_Syriac
+281: In_Arabic_Supplement
+282: In_Thaana
+283: In_NKo
+284: In_Samaritan
+285: In_Mandaic
+286: In_Syriac_Supplement
+287: In_Arabic_Extended_A
+288: In_Devanagari
+289: In_Bengali
+290: In_Gurmukhi
+291: In_Gujarati
+292: In_Oriya
+293: In_Tamil
+294: In_Telugu
+295: In_Kannada
+296: In_Malayalam
+297: In_Sinhala
+298: In_Thai
+299: In_Lao
+300: In_Tibetan
+301: In_Myanmar
+302: In_Georgian
+303: In_Hangul_Jamo
+304: In_Ethiopic
+305: In_Ethiopic_Supplement
+306: In_Cherokee
+307: In_Unified_Canadian_Aboriginal_Syllabics
+308: In_Ogham
+309: In_Runic
+310: In_Tagalog
+311: In_Hanunoo
+312: In_Buhid
+313: In_Tagbanwa
+314: In_Khmer
+315: In_Mongolian
+316: In_Unified_Canadian_Aboriginal_Syllabics_Extended
+317: In_Limbu
+318: In_Tai_Le
+319: In_New_Tai_Lue
+320: In_Khmer_Symbols
+321: In_Buginese
+322: In_Tai_Tham
+323: In_Combining_Diacritical_Marks_Extended
+324: In_Balinese
+325: In_Sundanese
+326: In_Batak
+327: In_Lepcha
+328: In_Ol_Chiki
+329: In_Cyrillic_Extended_C
+330: In_Georgian_Extended
+331: In_Sundanese_Supplement
+332: In_Vedic_Extensions
+333: In_Phonetic_Extensions
+334: In_Phonetic_Extensions_Supplement
+335: In_Combining_Diacritical_Marks_Supplement
+336: In_Latin_Extended_Additional
+337: In_Greek_Extended
+338: In_General_Punctuation
+339: In_Superscripts_and_Subscripts
+340: In_Currency_Symbols
+341: In_Combining_Diacritical_Marks_for_Symbols
+342: In_Letterlike_Symbols
+343: In_Number_Forms
+344: In_Arrows
+345: In_Mathematical_Operators
+346: In_Miscellaneous_Technical
+347: In_Control_Pictures
+348: In_Optical_Character_Recognition
+349: In_Enclosed_Alphanumerics
+350: In_Box_Drawing
+351: In_Block_Elements
+352: In_Geometric_Shapes
+353: In_Miscellaneous_Symbols
+354: In_Dingbats
+355: In_Miscellaneous_Mathematical_Symbols_A
+356: In_Supplemental_Arrows_A
+357: In_Braille_Patterns
+358: In_Supplemental_Arrows_B
+359: In_Miscellaneous_Mathematical_Symbols_B
+360: In_Supplemental_Mathematical_Operators
+361: In_Miscellaneous_Symbols_and_Arrows
+362: In_Glagolitic
+363: In_Latin_Extended_C
+364: In_Coptic
+365: In_Georgian_Supplement
+366: In_Tifinagh
+367: In_Ethiopic_Extended
+368: In_Cyrillic_Extended_A
+369: In_Supplemental_Punctuation
+370: In_CJK_Radicals_Supplement
+371: In_Kangxi_Radicals
+372: In_Ideographic_Description_Characters
+373: In_CJK_Symbols_and_Punctuation
+374: In_Hiragana
+375: In_Katakana
+376: In_Bopomofo
+377: In_Hangul_Compatibility_Jamo
+378: In_Kanbun
+379: In_Bopomofo_Extended
+380: In_CJK_Strokes
+381: In_Katakana_Phonetic_Extensions
+382: In_Enclosed_CJK_Letters_and_Months
+383: In_CJK_Compatibility
+384: In_CJK_Unified_Ideographs_Extension_A
+385: In_Yijing_Hexagram_Symbols
+386: In_CJK_Unified_Ideographs
+387: In_Yi_Syllables
+388: In_Yi_Radicals
+389: In_Lisu
+390: In_Vai
+391: In_Cyrillic_Extended_B
+392: In_Bamum
+393: In_Modifier_Tone_Letters
+394: In_Latin_Extended_D
+395: In_Syloti_Nagri
+396: In_Common_Indic_Number_Forms
+397: In_Phags_pa
+398: In_Saurashtra
+399: In_Devanagari_Extended
+400: In_Kayah_Li
+401: In_Rejang
+402: In_Hangul_Jamo_Extended_A
+403: In_Javanese
+404: In_Myanmar_Extended_B
+405: In_Cham
+406: In_Myanmar_Extended_A
+407: In_Tai_Viet
+408: In_Meetei_Mayek_Extensions
+409: In_Ethiopic_Extended_A
+410: In_Latin_Extended_E
+411: In_Cherokee_Supplement
+412: In_Meetei_Mayek
+413: In_Hangul_Syllables
+414: In_Hangul_Jamo_Extended_B
+415: In_High_Surrogates
+416: In_High_Private_Use_Surrogates
+417: In_Low_Surrogates
+418: In_Private_Use_Area
+419: In_CJK_Compatibility_Ideographs
+420: In_Alphabetic_Presentation_Forms
+421: In_Arabic_Presentation_Forms_A
+422: In_Variation_Selectors
+423: In_Vertical_Forms
+424: In_Combining_Half_Marks
+425: In_CJK_Compatibility_Forms
+426: In_Small_Form_Variants
+427: In_Arabic_Presentation_Forms_B
+428: In_Halfwidth_and_Fullwidth_Forms
+429: In_Specials
+430: In_Linear_B_Syllabary
+431: In_Linear_B_Ideograms
+432: In_Aegean_Numbers
+433: In_Ancient_Greek_Numbers
+434: In_Ancient_Symbols
+435: In_Phaistos_Disc
+436: In_Lycian
+437: In_Carian
+438: In_Coptic_Epact_Numbers
+439: In_Old_Italic
+440: In_Gothic
+441: In_Old_Permic
+442: In_Ugaritic
+443: In_Old_Persian
+444: In_Deseret
+445: In_Shavian
+446: In_Osmanya
+447: In_Osage
+448: In_Elbasan
+449: In_Caucasian_Albanian
+450: In_Linear_A
+451: In_Cypriot_Syllabary
+452: In_Imperial_Aramaic
+453: In_Palmyrene
+454: In_Nabataean
+455: In_Hatran
+456: In_Phoenician
+457: In_Lydian
+458: In_Meroitic_Hieroglyphs
+459: In_Meroitic_Cursive
+460: In_Kharoshthi
+461: In_Old_South_Arabian
+462: In_Old_North_Arabian
+463: In_Manichaean
+464: In_Avestan
+465: In_Inscriptional_Parthian
+466: In_Inscriptional_Pahlavi
+467: In_Psalter_Pahlavi
+468: In_Old_Turkic
+469: In_Old_Hungarian
+470: In_Hanifi_Rohingya
+471: In_Rumi_Numeral_Symbols
+472: In_Old_Sogdian
+473: In_Sogdian
+474: In_Elymaic
+475: In_Brahmi
+476: In_Kaithi
+477: In_Sora_Sompeng
+478: In_Chakma
+479: In_Mahajani
+480: In_Sharada
+481: In_Sinhala_Archaic_Numbers
+482: In_Khojki
+483: In_Multani
+484: In_Khudawadi
+485: In_Grantha
+486: In_Newa
+487: In_Tirhuta
+488: In_Siddham
+489: In_Modi
+490: In_Mongolian_Supplement
+491: In_Takri
+492: In_Ahom
+493: In_Dogra
+494: In_Warang_Citi
+495: In_Nandinagari
+496: In_Zanabazar_Square
+497: In_Soyombo
+498: In_Pau_Cin_Hau
+499: In_Bhaiksuki
+500: In_Marchen
+501: In_Masaram_Gondi
+502: In_Gunjala_Gondi
+503: In_Makasar
+504: In_Tamil_Supplement
+505: In_Cuneiform
+506: In_Cuneiform_Numbers_and_Punctuation
+507: In_Early_Dynastic_Cuneiform
+508: In_Egyptian_Hieroglyphs
+509: In_Egyptian_Hieroglyph_Format_Controls
+510: In_Anatolian_Hieroglyphs
+511: In_Bamum_Supplement
+512: In_Mro
+513: In_Bassa_Vah
+514: In_Pahawh_Hmong
+515: In_Medefaidrin
+516: In_Miao
+517: In_Ideographic_Symbols_and_Punctuation
+518: In_Tangut
+519: In_Tangut_Components
+520: In_Kana_Supplement
+521: In_Kana_Extended_A
+522: In_Small_Kana_Extension
+523: In_Nushu
+524: In_Duployan
+525: In_Shorthand_Format_Controls
+526: In_Byzantine_Musical_Symbols
+527: In_Musical_Symbols
+528: In_Ancient_Greek_Musical_Notation
+529: In_Mayan_Numerals
+530: In_Tai_Xuan_Jing_Symbols
+531: In_Counting_Rod_Numerals
+532: In_Mathematical_Alphanumeric_Symbols
+533: In_Sutton_SignWriting
+534: In_Glagolitic_Supplement
+535: In_Nyiakeng_Puachue_Hmong
+536: In_Wancho
+537: In_Mende_Kikakui
+538: In_Adlam
+539: In_Indic_Siyaq_Numbers
+540: In_Ottoman_Siyaq_Numbers
+541: In_Arabic_Mathematical_Alphabetic_Symbols
+542: In_Mahjong_Tiles
+543: In_Domino_Tiles
+544: In_Playing_Cards
+545: In_Enclosed_Alphanumeric_Supplement
+546: In_Enclosed_Ideographic_Supplement
+547: In_Miscellaneous_Symbols_and_Pictographs
+548: In_Emoticons
+549: In_Ornamental_Dingbats
+550: In_Transport_and_Map_Symbols
+551: In_Alchemical_Symbols
+552: In_Geometric_Shapes_Extended
+553: In_Supplemental_Arrows_C
+554: In_Supplemental_Symbols_and_Pictographs
+555: In_Chess_Symbols
+556: In_Symbols_and_Pictographs_Extended_A
+557: In_CJK_Unified_Ideographs_Extension_B
+558: In_CJK_Unified_Ideographs_Extension_C
+559: In_CJK_Unified_Ideographs_Extension_D
+560: In_CJK_Unified_Ideographs_Extension_E
+561: In_CJK_Unified_Ideographs_Extension_F
+562: In_CJK_Compatibility_Ideographs_Supplement
+563: In_Tags
+564: In_Variation_Selectors_Supplement
+565: In_Supplementary_Private_Use_Area_A
+566: In_Supplementary_Private_Use_Area_B
+567: In_No_Block
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/ascii_compatible.dict b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/ascii_compatible.dict
new file mode 100644
index 000000000..a3e978b23
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/ascii_compatible.dict
@@ -0,0 +1,113 @@
+# First-pass fuzzing dictionary for Oniguruma by Mark Griffin
+"\\o{34}"
+"\\123"
+"\\x{40}"
+"\\C-"
+"\\M-\\C-"
+"\\X"
+"\\p{"
+"\\p{^"
+"}"
+"]"
+"]"
+")"
+")"
+"\\n"
+"\\r"
+"\\R"
+"\\W"
+"\\w"
+"\\s"
+"\\S"
+"\\d"
+"\\O"
+"\\X"
+"\\b"
+"\\y"
+"\\Y"
+"\\A"
+"\\z"
+"\\K"
+"\\G"
+"\\p{Print}"
+"\\p{ASCII}"
+"\\p{Alnum}"
+"{0,2}"
+"{3,}"
+"{,3}"
+"{5}"
+"{4,2}"
+"??"
+"*?"
+"+?"
+"*+"
+"{1,3}+"
+"(?>"
+"\\B"
+"(?y{"
+"[abcd1-9]"
+"[\\w]"
+"[\\W]"
+"[\\s]"
+"[\\S]"
+"[\\w\\d"
+"[\\p{Alphabetic}"
+"[\\x{03}"
+"[a-w&&"
+"[^"
+"[:graph:]"
+"[^:cntrl:]"
+"(?i:"
+"(?i)"
+"(?m:"
+"(?x:"
+"(?W:"
+"(?y-:"
+"(?y{w}:"
+"(?P:"
+"(?#"
+"(?:"
+"(?="
+"(?!"
+"(?<="
+"(?<!"
+"(?>"
+"(?<name>"
+"(?{"
+"(?{....}[x])"
+"(?{.}[x]>)"
+"(?{{{.}}})"
+"(?~"
+"(?~a)"
+"(?~|a|.*)"
+"(?~|(?:a|b))"
+"(?~|)"
+"(?(.) |.)"
+"(?('-n'))"
+"(?(n+0))"
+"(?(n+1))"
+"(?(n-1))"
+"(?(<name+0>))"
+"(?(<name+1>))"
+"(?(<name-1>))"
+"(*COUNT[tag]{X})"
+"\\1"
+"\\2"
+"\\k<name>"
+"\\k<1>"
+"\\k<2>"
+"\\k<-1>"
+"\\k<-2>"
+"\\k<name+0>"
+"\\k<name+1>"
+"\\k<name-1>"
+"\\g<-1>"
+"\\g<name>"
+"name"
+"(?<name>a|b\\g<name>c)"
+"(?-i:\\g<name>)"
+"\\N{name}"
+"\\p{Katakana}"
+"\\p{Emoji}"
+"ss"
+"SS"
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/base.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/base.c
new file mode 100644
index 000000000..54879bd19
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/base.c
@@ -0,0 +1,389 @@
+/*
+ * base.c
+ * contributed by Mark Griffin
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "oniguruma.h"
+
+
+#define PARSE_DEPTH_LIMIT 8
+#define RETRY_LIMIT 5000
+#define EXEC_PRINT_INTERVAL 5000000
+
+typedef unsigned char uint8_t;
+
+
+#ifdef STANDALONE
+
+#include <ctype.h>
+
+static void
+dump_data(FILE* fp, unsigned char* data, int len)
+{
+ int i;
+
+ fprintf(fp, "{\n");
+ for (i = 0; i < len; i++) {
+ unsigned char c = data[i];
+
+ if (isprint((int )c)) {
+ if (c == '\\')
+ fprintf(fp, " '\\\\'");
+ else
+ fprintf(fp, " '%c'", c);
+ }
+ else {
+ fprintf(fp, "0x%02x", (int )c);
+ }
+
+ if (i == len - 1) {
+ fprintf(fp, "\n");
+ }
+ else {
+ if (i % 8 == 7)
+ fprintf(fp, ",\n");
+ else
+ fprintf(fp, ", ");
+ }
+ }
+ fprintf(fp, "};\n");
+}
+
+#else
+
+static void
+output_current_time(FILE* fp)
+{
+ char d[64];
+ time_t t;
+
+ t = time(NULL);
+ strftime(d, sizeof(d), "%m/%d %H:%M:%S", localtime(&t));
+
+ fprintf(fp, "%s", d);
+}
+
+#endif
+
+static int
+search(regex_t* reg, unsigned char* str, unsigned char* end)
+{
+ int r;
+ unsigned char *start, *range;
+ OnigRegion *region;
+
+ region = onig_region_new();
+
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+#ifdef STANDALONE
+ int i;
+
+ fprintf(stdout, "match at %d (%s)\n", r,
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stdout, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+#endif
+ }
+ else if (r == ONIG_MISMATCH) {
+#ifdef STANDALONE
+ fprintf(stdout, "search fail (%s)\n",
+ ONIGENC_NAME(onig_get_encoding(reg)));
+#endif
+ }
+ else { /* error */
+#ifdef STANDALONE
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stdout, "ERROR: %s\n", s);
+ fprintf(stdout, " (%s)\n", ONIGENC_NAME(onig_get_encoding(reg)));
+#endif
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+
+ if (r == ONIGERR_STACK_BUG ||
+ r == ONIGERR_UNDEFINED_BYTECODE ||
+ r == ONIGERR_UNEXPECTED_BYTECODE)
+ return -2;
+
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return 0;
+}
+
+static long INPUT_COUNT;
+static long EXEC_COUNT;
+static long EXEC_COUNT_INTERVAL;
+static long REGEX_SUCCESS_COUNT;
+static long VALID_STRING_COUNT;
+
+static int
+exec(OnigEncoding enc, OnigOptionType options, OnigSyntaxType* syntax,
+ char* apattern, char* apattern_end, char* astr, UChar* end)
+{
+ int r;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+ UChar* pattern_end = (UChar* )apattern_end;
+
+ EXEC_COUNT++;
+ EXEC_COUNT_INTERVAL++;
+
+ onig_initialize(&enc, 1);
+ onig_set_retry_limit_in_search(RETRY_LIMIT);
+#ifdef PARSE_DEPTH_LIMIT
+ onig_set_parse_depth_limit(PARSE_DEPTH_LIMIT);
+#endif
+
+ r = onig_new(&reg, pattern, pattern_end,
+ options, enc, syntax, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+#ifdef STANDALONE
+ fprintf(stdout, "ERROR: %s\n", s);
+#endif
+ onig_end();
+
+ if (r == ONIGERR_PARSER_BUG ||
+ r == ONIGERR_STACK_BUG ||
+ r == ONIGERR_UNDEFINED_BYTECODE ||
+ r == ONIGERR_UNEXPECTED_BYTECODE) {
+ return -2;
+ }
+ else
+ return -1;
+ }
+ REGEX_SUCCESS_COUNT++;
+
+ r = search(reg, pattern, pattern_end);
+ if (r == -2) return -2;
+
+ if (onigenc_is_valid_mbc_string(enc, str, end) != 0) {
+ VALID_STRING_COUNT++;
+ r = search(reg, str, end);
+ if (r == -2) return -2;
+ }
+
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
+
+static int
+alloc_exec(OnigEncoding enc, OnigOptionType options, OnigSyntaxType* syntax,
+ int pattern_size, size_t remaining_size, unsigned char *data)
+{
+ int r;
+ unsigned char *pattern_end;
+ unsigned char *str_null_end;
+
+ // copy first PATTERN_SIZE bytes off to be the pattern
+ unsigned char *pattern = (unsigned char *)malloc(pattern_size != 0 ? pattern_size : 1);
+ memcpy(pattern, data, pattern_size);
+ pattern_end = pattern + pattern_size;
+ data += pattern_size;
+ remaining_size -= pattern_size;
+
+#if defined(UTF16_BE) || defined(UTF16_LE)
+ if (remaining_size % 2 == 1) remaining_size--;
+#endif
+
+ unsigned char *str = (unsigned char*)malloc(remaining_size != 0 ? remaining_size : 1);
+ memcpy(str, data, remaining_size);
+ str_null_end = str + remaining_size;
+
+ r = exec(enc, options, syntax,
+ (char *)pattern, (char *)pattern_end,
+ (char *)str, str_null_end);
+
+ free(pattern);
+ free(str);
+ return r;
+}
+
+
+#ifdef SYNTAX_TEST
+#define NUM_CONTROL_BYTES 4
+#else
+#define NUM_CONTROL_BYTES 3
+#endif
+
+int LLVMFuzzerTestOneInput(const uint8_t * Data, size_t Size)
+{
+#if !defined(UTF16_BE) && !defined(UTF16_LE)
+ static OnigEncoding encodings[] = {
+ ONIG_ENCODING_UTF8,
+ ONIG_ENCODING_UTF8,
+ ONIG_ENCODING_UTF8,
+ ONIG_ENCODING_SJIS,
+ //ONIG_ENCODING_EUC_JP,
+ ONIG_ENCODING_ISO_8859_1,
+ ONIG_ENCODING_BIG5,
+ ONIG_ENCODING_GB18030,
+ ONIG_ENCODING_EUC_TW
+ };
+ unsigned char encoding_choice;
+#endif
+
+#ifdef SYNTAX_TEST
+ static OnigSyntaxType* syntaxes[] = {
+ ONIG_SYNTAX_POSIX_EXTENDED,
+ ONIG_SYNTAX_EMACS,
+ ONIG_SYNTAX_GREP,
+ ONIG_SYNTAX_GNU_REGEX,
+ ONIG_SYNTAX_JAVA,
+ ONIG_SYNTAX_PERL_NG,
+ ONIG_SYNTAX_ONIGURUMA
+ };
+
+#ifdef STANDALONE
+ static char* syntax_names[] = {
+ "Posix Extended",
+ "Emacs",
+ "Grep",
+ "GNU Regex",
+ "Java",
+ "Perl+NG",
+ "Oniguruma"
+ };
+#endif
+
+ unsigned char syntax_choice;
+#endif
+
+ int r;
+ int pattern_size;
+ size_t remaining_size;
+ unsigned char *data;
+ unsigned char options_choice;
+ unsigned char pattern_size_choice;
+ OnigOptionType options;
+ OnigEncoding enc;
+ OnigSyntaxType* syntax;
+
+ INPUT_COUNT++;
+ if (Size < NUM_CONTROL_BYTES) return 0;
+
+ remaining_size = Size;
+ data = (unsigned char* )(Data);
+
+#ifdef UTF16_BE
+ enc = ONIG_ENCODING_UTF16_BE;
+#else
+#ifdef UTF16_LE
+ enc = ONIG_ENCODING_UTF16_LE;
+#else
+ encoding_choice = data[0];
+ data++;
+ remaining_size--;
+
+ int num_encodings = sizeof(encodings)/sizeof(encodings[0]);
+ enc = encodings[encoding_choice % num_encodings];
+#endif
+#endif
+
+#ifdef SYNTAX_TEST
+ syntax_choice = data[0];
+ data++;
+ remaining_size--;
+
+ int num_syntaxes = sizeof(syntaxes)/sizeof(syntaxes[0]);
+ syntax = syntaxes[syntax_choice % num_syntaxes];
+#else
+ syntax = ONIG_SYNTAX_DEFAULT;
+#endif
+
+ options_choice = data[0];
+ options = (options_choice % 2 == 0) ? ONIG_OPTION_NONE : ONIG_OPTION_IGNORECASE;
+ data++;
+ remaining_size--;
+
+ pattern_size_choice = data[0];
+ data++;
+ remaining_size--;
+
+ if (remaining_size == 0)
+ pattern_size = 0;
+ else {
+ pattern_size = (int )pattern_size_choice % remaining_size;
+#if defined(UTF16_BE) || defined(UTF16_LE)
+ if (pattern_size % 2 == 1) pattern_size--;
+#endif
+ }
+
+#ifdef STANDALONE
+ dump_data(stdout, data, pattern_size);
+#ifdef SYNTAX_TEST
+ fprintf(stdout, "enc: %s, syntax: %s, options: %u, pattern_size: %d\n",
+ ONIGENC_NAME(enc),
+ syntax_names[syntax_choice % num_syntaxes],
+ options,
+ pattern_size);
+#else
+ fprintf(stdout, "enc: %s, options: %u, pattern_size: %d\n",
+ ONIGENC_NAME(enc), options, pattern_size);
+#endif
+#endif
+
+ r = alloc_exec(enc, options, syntax, pattern_size, remaining_size, data);
+ if (r == -2) exit(-2);
+
+#ifndef STANDALONE
+ if (EXEC_COUNT_INTERVAL == EXEC_PRINT_INTERVAL) {
+ float fexec, freg, fvalid;
+
+ output_current_time(stdout);
+
+ if (INPUT_COUNT != 0) { // overflow check
+ fexec = (float )EXEC_COUNT / INPUT_COUNT;
+ freg = (float )REGEX_SUCCESS_COUNT / INPUT_COUNT;
+ fvalid = (float )VALID_STRING_COUNT / INPUT_COUNT;
+
+ fprintf(stdout, ": %ld: EXEC:%.2f, REG:%.2f, VALID:%.2f\n",
+ EXEC_COUNT, fexec, freg, fvalid);
+ }
+ else {
+ fprintf(stdout, ": ignore (input count overflow)\n");
+ }
+
+ EXEC_COUNT_INTERVAL = 0;
+ }
+ else if (EXEC_COUNT == 1) {
+ output_current_time(stdout);
+ fprintf(stdout, ": ------------ START ------------\n");
+ }
+#endif
+
+ return r;
+}
+
+#ifdef STANDALONE
+
+extern int main(int argc, char* argv[])
+{
+ size_t n;
+ uint8_t Data[10000];
+
+ n = read(0, Data, sizeof(Data));
+ fprintf(stdout, "n: %ld\n", n);
+ LLVMFuzzerTestOneInput(Data, n);
+
+ return 0;
+}
+#endif /* STANDALONE */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/deluxe.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/deluxe.c
new file mode 100644
index 000000000..5441de934
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/deluxe.c
@@ -0,0 +1,206 @@
+/*
+ * deluxe.c
+ * contributed by Mark Griffin
+ */
+#include <stdio.h>
+#include "oniguruma.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define RETRY_LIMIT 10000
+#define DEPTH_LIMIT 10
+
+typedef unsigned char uint8_t;
+
+static int
+search(regex_t* reg, unsigned char* str, unsigned char* end)
+{
+ int r;
+ unsigned char *start, *range;
+ OnigRegion *region;
+
+ region = onig_region_new();
+
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stdout, "match at %d (%s)\n", r,
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stdout, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stdout, "search fail (%s)\n",
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stdout, "ERROR: %s\n", s);
+ fprintf(stdout, " (%s)\n", ONIGENC_NAME(onig_get_encoding(reg)));
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return 0;
+}
+
+static OnigCaseFoldType CF = ONIGENC_CASE_FOLD_MIN;
+
+static int
+exec_deluxe(OnigEncoding pattern_enc, OnigEncoding str_enc,
+ OnigOptionType options, char* apattern, char* apattern_end,
+ char* astr, char* astr_end)
+{
+ int r;
+ regex_t* reg;
+ OnigCompileInfo ci;
+ OnigErrorInfo einfo;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+ UChar* pattern_end = (UChar* )apattern_end;
+ unsigned char* end = (unsigned char* )astr_end;
+
+ onig_initialize(&str_enc, 1);
+ onig_set_retry_limit_in_search(RETRY_LIMIT);
+ onig_set_parse_depth_limit(DEPTH_LIMIT);
+
+ ci.num_of_elements = 5;
+ ci.pattern_enc = pattern_enc;
+ ci.target_enc = str_enc;
+ ci.syntax = ONIG_SYNTAX_DEFAULT;
+ ci.option = options;
+ ci.case_fold_flag = CF;
+
+ r = onig_new_deluxe(&reg, pattern, pattern_end, &ci, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stdout, "ERROR: %s\n", s);
+ onig_end();
+ return -1;
+ }
+
+ if (onigenc_is_valid_mbc_string(str_enc, str, end) != 0) {
+ r = search(reg, str, end);
+ }
+
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
+
+#define PATTERN_SIZE 48
+#define NUM_CONTROL_BYTES 1
+#define MIN_STR_SIZE 2
+int LLVMFuzzerTestOneInput(const uint8_t * Data, size_t Size)
+{
+ int r;
+ size_t remaining_size;
+ unsigned char *data;
+ unsigned char pat_encoding_choice;
+ unsigned char str_encoding_choice;
+ unsigned char *pattern;
+ unsigned char *str;
+ unsigned char *pattern_end;
+ unsigned char *str_end;
+ unsigned int num_encodings;
+ OnigEncodingType *pattern_enc;
+ OnigEncodingType *str_enc;
+
+ OnigEncodingType *encodings[] = {
+ ONIG_ENCODING_ASCII,
+ ONIG_ENCODING_ISO_8859_1,
+ ONIG_ENCODING_ISO_8859_2,
+ ONIG_ENCODING_ISO_8859_3,
+ ONIG_ENCODING_ISO_8859_4,
+ ONIG_ENCODING_ISO_8859_5,
+ ONIG_ENCODING_ISO_8859_6,
+ ONIG_ENCODING_ISO_8859_7,
+ ONIG_ENCODING_ISO_8859_8,
+ ONIG_ENCODING_ISO_8859_9,
+ ONIG_ENCODING_ISO_8859_10,
+ ONIG_ENCODING_ISO_8859_11,
+ ONIG_ENCODING_ISO_8859_13,
+ ONIG_ENCODING_ISO_8859_14,
+ ONIG_ENCODING_ISO_8859_15,
+ ONIG_ENCODING_ISO_8859_16,
+ ONIG_ENCODING_UTF8,
+ ONIG_ENCODING_UTF16_BE,
+ ONIG_ENCODING_UTF16_LE,
+ ONIG_ENCODING_UTF32_BE,
+ ONIG_ENCODING_UTF32_LE,
+ ONIG_ENCODING_EUC_JP,
+ ONIG_ENCODING_EUC_TW,
+ ONIG_ENCODING_EUC_KR,
+ ONIG_ENCODING_EUC_CN,
+ ONIG_ENCODING_SJIS,
+ //ONIG_ENCODING_KOI8,
+ ONIG_ENCODING_KOI8_R,
+ ONIG_ENCODING_CP1251,
+ ONIG_ENCODING_BIG5,
+ ONIG_ENCODING_GB18030,
+ };
+
+ if (Size <= (NUM_CONTROL_BYTES + PATTERN_SIZE + MIN_STR_SIZE))
+ return 0;
+ if (Size > 0x1000)
+ return 0;
+
+ remaining_size = Size;
+ data = (unsigned char *)(Data);
+
+ // pull off bytes to switch off
+ pat_encoding_choice = data[0];
+ data++;
+ remaining_size--;
+ str_encoding_choice = data[0];
+ data++;
+ remaining_size--;
+
+ // copy first PATTERN_SIZE bytes off to be the pattern
+ pattern = (unsigned char *)malloc(PATTERN_SIZE);
+ memcpy(pattern, data, PATTERN_SIZE);
+ pattern_end = pattern + PATTERN_SIZE;
+ data += PATTERN_SIZE;
+ remaining_size -= PATTERN_SIZE;
+
+ str = (unsigned char*)malloc(remaining_size);
+ memcpy(str, data, remaining_size);
+ str_end = str + remaining_size;
+
+ num_encodings = sizeof(encodings) / sizeof(encodings[0]);
+ pattern_enc = encodings[pat_encoding_choice % num_encodings];
+ str_enc = encodings[str_encoding_choice % num_encodings];
+
+ r = exec_deluxe(pattern_enc, str_enc, ONIG_OPTION_NONE, (char *)pattern, (char *)pattern_end, (char *)str, (char *)str_end);
+
+ free(pattern);
+ free(str);
+
+ return r;
+}
+
+
+#ifdef STANDALONE
+
+#include <unistd.h>
+
+extern int main(int argc, char* argv[])
+{
+ size_t n;
+ uint8_t Data[10000];
+
+ n = read(0, Data, sizeof(Data));
+ fprintf(stdout, "n: %ld\n", n);
+ LLVMFuzzerTestOneInput(Data, n);
+
+ return 0;
+}
+#endif /* STANDALONE */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/dict_conv.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/dict_conv.py
new file mode 100644
index 000000000..f7212939f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/dict_conv.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# dict_conv.py (Python3 script)
+
+import sys
+
+ENC_UTF16_BE = 1
+ENC_UTF16_LE = 2
+
+def add_char(enc, s, c):
+ if enc == ENC_UTF16_BE:
+ s += "\\x00"
+
+ s += c
+ if enc == ENC_UTF16_LE:
+ s += "\\x00"
+
+ return s
+
+def conv(enc, s):
+ n = len(s)
+ r = ""
+ i = 0
+ while i < n:
+ c = s[i]
+ if c == '\\':
+ c = s[i+1]
+ if c == '\\' or c == '"':
+ r = add_char(enc, r, "\\" + c)
+ i += 2
+ continue
+ else:
+ raise("Unknown escape {0}".format(s))
+
+ r = add_char(enc, r, c)
+ i += 1
+
+ return r
+
+def main(enc):
+ print("# This file was generated by dict_conv.py.")
+ for line in sys.stdin:
+ s = line.strip()
+ if s[0] == '#':
+ print(s)
+ continue
+
+ if s[0] == '"' and s[-1] == '"':
+ s = conv(enc, s[1:-1])
+ print("\"{0}\"".format(s))
+ else:
+ raise("Invalid format {0}".format(s))
+
+def usage(argv):
+ raise RuntimeError("Usage: python {0} utf16_be/utf16_le".format(argv[0]))
+
+
+if __name__ == "__main__":
+ argv = sys.argv
+ argc = len(argv)
+
+ if argc >= 2:
+ s = argv[1]
+ if s == 'utf16_be':
+ enc = ENC_UTF16_BE
+ elif s == 'utf16_le':
+ enc = ENC_UTF16_LE
+ else:
+ usage(argv)
+ else:
+ usage(argv)
+
+ main(enc)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/fuzzer.options b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/fuzzer.options
new file mode 100644
index 000000000..ab447447b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/fuzzer.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+dict = ascii_compatible.dict
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/libfuzzer-onig.cpp b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/libfuzzer-onig.cpp
new file mode 100644
index 000000000..526c82683
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/libfuzzer-onig.cpp
@@ -0,0 +1,45 @@
+/* libfuzzer test code for oniguruma
+ * author: Hanno Böck, license: CC0/public domain
+
+Usage:
+* compile oniguruma with something like
+ ./configure CC=clang LD=clang CFLAGS="-fsanitize-coverage=edge -fsanitize=address" \
+ LDFLAGS="-fsanitize-coverage=edge -fsanitize=address"
+* Compile libfuzzer stub and link against static libonig.a and libFuzzer.a:
+ clang++ libfuzzer-onig.cpp src/.libs/libonig.a libFuzzer.a -o libfuzzer-onig \
+ -fsanitize-coverage=edge -fsanitize=address
+* Put sample patterns in directory "in/"
+* Run
+ ./libfuzzer-onig in
+
+Consult libfuzzer docs for further details and how to create libFuzzer.a:
+http://llvm.org/docs/LibFuzzer.html
+
+ */
+#include <stdint.h>
+#include <string.h>
+#include <oniguruma.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t * Data, size_t Size)
+{
+ regex_t *reg;
+ OnigEncoding enc;
+
+ enc = ONIG_ENCODING_UTF8;
+
+#ifdef FULL_TEST
+ onig_initialize(&enc, 1);
+ onig_set_retry_limit_in_match(120);
+ onig_set_parse_depth_limit(120);
+#endif
+
+ if (onig_new(&reg, Data, Data + Size, ONIG_OPTION_DEFAULT, enc,
+ ONIG_SYNTAX_DEFAULT, 0) == 0)
+ onig_free(reg);
+
+#ifdef FULL_TEST
+ onig_end();
+#endif
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/makefile b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/makefile
new file mode 100644
index 000000000..b32429550
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/makefile
@@ -0,0 +1,68 @@
+# makefile for harness
+SRC = ../src
+CFLAGS = -I$(SRC) -Wall -g -fsanitize=fuzzer,address -fno-omit-frame-pointer
+CFLAGS_M = -I$(SRC) -Wall -g -fsanitize=fuzzer-no-link,address -fno-omit-frame-pointer -DSTANDALONE
+ONIG_LIB = $(SRC)/.libs/libonig.a
+LIBS = $(ONIG_LIB)
+
+TARGETS = fuzzer-encode fuzzer-syntax fuzzer-utf16-be fuzzer-utf16-le \
+ fuzzer-regset \
+ read-encode read-syntax read-utf16-be read-utf16-le read-regset
+
+OTHER_TARGETS = libfuzzer-onig libfuzzer-onig-full fuzzer-deluxe read-deluxe
+
+
+default: $(TARGETS)
+
+fuzzer-encode: base.c $(ONIG_LIB)
+ clang $(CFLAGS) $< $(LIBS) -o $@
+
+fuzzer-syntax: base.c $(ONIG_LIB)
+ clang -DSYNTAX_TEST $(CFLAGS) $< $(LIBS) -o $@
+
+fuzzer-deluxe: deluxe.c $(ONIG_LIB)
+ clang $(CFLAGS) $< $(LIBS) -o $@
+
+fuzzer-utf16-be: base.c $(ONIG_LIB)
+ clang -DUTF16_BE $(CFLAGS) $< $(LIBS) -o $@
+
+fuzzer-utf16-le: base.c $(ONIG_LIB)
+ clang -DUTF16_LE $(CFLAGS) $< $(LIBS) -o $@
+
+fuzzer-regset: regset.c $(ONIG_LIB)
+ clang $(CFLAGS) $< $(LIBS) -o $@
+
+read-encode: base.c $(ONIG_LIB)
+ clang $(CFLAGS_M) $< $(LIBS) -o $@
+
+read-syntax: base.c $(ONIG_LIB)
+ clang -DSYNTAX_TEST $(CFLAGS_M) $< $(LIBS) -o $@
+
+read-deluxe: deluxe.c $(ONIG_LIB)
+ clang $(CFLAGS_M) $< $(LIBS) -o $@
+
+read-utf16-be: base.c $(ONIG_LIB)
+ clang -DUTF16_BE $(CFLAGS_M) $< $(LIBS) -o $@
+
+read-utf16-le: base.c $(ONIG_LIB)
+ clang -DUTF16_LE $(CFLAGS_M) $< $(LIBS) -o $@
+
+read-regset: regset.c $(ONIG_LIB)
+ clang $(CFLAGS_M) $< $(LIBS) -o $@
+
+libfuzzer-onig: libfuzzer-onig.cpp $(ONIG_LIB)
+ clang++ $(CFLAGS) $< $(LIBS) -o $@
+
+libfuzzer-onig-full: libfuzzer-onig.cpp $(ONIG_LIB)
+ clang++ -DFULL_TEST $(CFLAGS) $< $(LIBS) -o $@
+
+
+$(ONIG_LIB):
+ cd ..; make clean
+ #cd ..; autoreconf -vfi
+ cd ..; ./configure CC=clang LD=clang CFLAGS="-g -fsanitize=address -fno-omit-frame-pointer" LDFLAGS="-g -fsanitize=address -fno-omit-frame-pointer"
+ cd ..; make -j4
+
+
+clean:
+ rm -f $(TARGETS) $(OTHER_TARGETS)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/regset.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/regset.c
new file mode 100644
index 000000000..a8dd1810a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/harnesses/regset.c
@@ -0,0 +1,392 @@
+/*
+ * regset.c
+ * Copyright (c) 2019 K.Kosako
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "oniguruma.h"
+
+
+#define RETRY_LIMIT 5000
+
+#ifdef STANDALONE
+//#define CHECK_EACH_REGEX_SEARCH_TIME
+#endif
+
+#define MAX_REG_NUM 256
+
+typedef unsigned char uint8_t;
+static OnigEncoding ENC;
+
+static void
+output_current_time(FILE* fp)
+{
+ char d[64];
+ time_t t;
+
+ t = time(NULL);
+ strftime(d, sizeof(d), "%m/%d %H:%M:%S", localtime(&t));
+
+ fprintf(fp, "%s", d);
+}
+
+#ifdef CHECK_EACH_REGEX_SEARCH_TIME
+static double
+get_sec(struct timespec* ts, struct timespec* te)
+{
+ double t;
+
+ t = (te->tv_sec - ts->tv_sec) +
+ (double )(te->tv_nsec - ts->tv_nsec) / 1000000000.0;
+ return t;
+}
+
+static int
+check_each_regex_search_time(OnigRegSet* set, unsigned char* str, unsigned char* end)
+{
+ int n;
+ int i;
+ int r;
+ OnigRegion* region;
+
+ n = onig_regset_number_of_regex(set);
+ region = onig_region_new();
+
+ for (i = 0; i < n; i++) {
+ regex_t* reg;
+ unsigned char* start;
+ unsigned char* range;
+ struct timespec ts1, ts2;
+ double t;
+
+ reg = onig_regset_get_regex(set, i);
+ start = str;
+ range = end;
+
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts1);
+
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts2);
+ t = get_sec(&ts1, &ts2);
+
+ fprintf(stdout, "regex search time %d: %6.2lfmsec.\n", i, t * 1000.0);
+ }
+
+ onig_region_free(region, 1);
+ return 0;
+}
+#endif
+
+static int
+search(OnigRegSet* set, OnigRegSetLead lead, unsigned char* str, unsigned char* end)
+{
+ int r;
+ int match_pos;
+ unsigned char *start, *range;
+
+ start = str;
+ range = end;
+ r = onig_regset_search(set, str, end, start, range, lead,
+ ONIG_OPTION_NONE, &match_pos);
+ if (r >= 0) {
+#ifdef STANDALONE
+ int i;
+ int match_index;
+ OnigRegion* region;
+
+ match_index = r;
+ fprintf(stdout, "match reg index: %d, pos: %d (%s)\n",
+ match_index, match_pos, ONIGENC_NAME(ENC));
+ region = onig_regset_get_region(set, match_index);
+ if (region == 0) {
+ fprintf(stdout, "ERROR: can't get region.\n");
+ return -1;
+ }
+
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stdout, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+#endif
+ }
+ else if (r == ONIG_MISMATCH) {
+#ifdef STANDALONE
+ fprintf(stdout, "search fail (%s)\n", ONIGENC_NAME(ENC));
+#endif
+ }
+ else { /* error */
+#ifdef STANDALONE
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stdout, "ERROR: %s\n", s);
+ fprintf(stdout, " (%s)\n", ONIGENC_NAME(ENC));
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static long INPUT_COUNT;
+static long EXEC_COUNT;
+static long EXEC_COUNT_INTERVAL;
+static long REGEX_SUCCESS_COUNT;
+static long VALID_STRING_COUNT;
+
+static int
+exec(OnigEncoding enc, int reg_num, int init_reg_num,
+ UChar* pat[], UChar* pat_end[],
+ OnigRegSetLead lead, UChar* str, UChar* end)
+{
+ int r;
+ int i, j;
+ OnigRegSet* set;
+ regex_t* reg;
+ OnigOptionType options;
+ OnigErrorInfo einfo;
+ regex_t* regs[MAX_REG_NUM];
+
+ EXEC_COUNT++;
+ EXEC_COUNT_INTERVAL++;
+
+ options = (EXEC_COUNT % 4 == 0) ? ONIG_OPTION_IGNORECASE : ONIG_OPTION_NONE;
+
+ onig_initialize(&enc, 1);
+ onig_set_retry_limit_in_search(RETRY_LIMIT);
+
+ for (i = 0; i < init_reg_num; i++) {
+ r = onig_new(&regs[i], pat[i], pat_end[i], options, ENC,
+ ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != 0) {
+#ifdef STANDALONE
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stdout, "ERROR: index: %d, %s\n", i, s);
+#endif
+
+ for (j = 0; j < i; j++) onig_free(regs[j]);
+
+ onig_end();
+
+ if (r == ONIGERR_PARSER_BUG ||
+ r == ONIGERR_STACK_BUG ||
+ r == ONIGERR_UNDEFINED_BYTECODE ||
+ r == ONIGERR_UNEXPECTED_BYTECODE) {
+ return -2;
+ }
+ else
+ return -1;
+ }
+ }
+
+ r = onig_regset_new(&set, init_reg_num, regs);
+ if (r != 0) {
+ for (i = 0; i < init_reg_num; i++) {
+ onig_free(regs[i]);
+ }
+ onig_end();
+ return -1;
+ }
+
+ for (i = init_reg_num; i < reg_num; i++) {
+ r = onig_new(&reg, pat[i], pat_end[i], options, ENC,
+ ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != 0) {
+#ifdef STANDALONE
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stdout, "ERROR: index: %d, %s\n", i, s);
+#endif
+ onig_regset_free(set);
+ onig_end();
+
+ if (r == ONIGERR_PARSER_BUG ||
+ r == ONIGERR_STACK_BUG ||
+ r == ONIGERR_UNDEFINED_BYTECODE ||
+ r == ONIGERR_UNEXPECTED_BYTECODE) {
+ return -2;
+ }
+ else
+ return -1;
+ }
+
+ r = onig_regset_add(set, reg);
+ if (r != 0) {
+ onig_regset_free(set);
+ onig_end();
+ fprintf(stdout, "ERROR: onig_regset_add(): %d\n", i);
+ return r;
+ }
+ }
+
+ REGEX_SUCCESS_COUNT++;
+
+ if (onigenc_is_valid_mbc_string(enc, str, end) != 0) {
+ VALID_STRING_COUNT++;
+ r = search(set, lead, str, end);
+#ifdef CHECK_EACH_REGEX_SEARCH_TIME
+ r = check_each_regex_search_time(set, str, end);
+#endif
+ }
+
+ onig_regset_free(set);
+ onig_end();
+ return 0;
+}
+
+#define MAX_PATTERN_SIZE 30
+#define NUM_CONTROL_BYTES 3
+
+#define EXEC_PRINT_INTERVAL 2000000
+
+static int MaxRegNum;
+static int MaxInitRegNum;
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t * Data, size_t Size)
+{
+ int r, i;
+ int pattern_size;
+ unsigned char *str_null_end;
+ size_t remaining_size;
+ unsigned char *data;
+ unsigned int reg_num;
+ unsigned int init_reg_num;
+ unsigned char* pat[256];
+ unsigned char* pat_end[256];
+ int len;
+ unsigned int lead_num;
+ OnigRegSetLead lead;
+
+ INPUT_COUNT++;
+
+ if (Size < NUM_CONTROL_BYTES) return 0;
+
+ remaining_size = Size;
+ data = (unsigned char* )(Data);
+
+ reg_num = data[0];
+ data++;
+ remaining_size--;
+
+ init_reg_num = data[0];
+ data++;
+ remaining_size--;
+
+ lead_num = data[0];
+ data++;
+ remaining_size--;
+ lead = (lead_num % 2 == 0 ? ONIG_REGSET_POSITION_LEAD : ONIG_REGSET_REGEX_LEAD);
+
+ if (remaining_size < reg_num * 2) {
+ reg_num = reg_num % 15; // zero is OK.
+ }
+
+ init_reg_num %= (reg_num + 1);
+
+ if (MaxRegNum < reg_num)
+ MaxRegNum = reg_num;
+
+ if (MaxInitRegNum < init_reg_num)
+ MaxInitRegNum = init_reg_num;
+
+ if (reg_num == 0)
+ pattern_size = 1;
+ else
+ pattern_size = remaining_size / (reg_num * 2);
+
+ if (pattern_size > MAX_PATTERN_SIZE)
+ pattern_size = MAX_PATTERN_SIZE;
+
+ len = pattern_size * reg_num;
+ if (len == 0) len = 1;
+
+ for (i = 0; i < reg_num; i++) {
+ pat[i] = (unsigned char* )malloc(pattern_size);
+ memcpy(pat[i], data, pattern_size);
+ pat_end[i] = pat[i] + pattern_size;
+ data += pattern_size;
+ remaining_size -= pattern_size;
+ }
+
+ unsigned char *str = (unsigned char*)malloc(remaining_size != 0 ? remaining_size : 1);
+ memcpy(str, data, remaining_size);
+ str_null_end = str + remaining_size;
+
+#ifdef STANDALONE
+ fprintf(stdout, "reg num: %d, pattern size: %d, lead: %s\n",
+ reg_num, pattern_size,
+ lead == ONIG_REGSET_POSITION_LEAD ? "position" : "regex");
+
+ if (reg_num != 0) {
+ unsigned char* p;
+ i = 0;
+ p = pat[0];
+ while (p < pat_end[0]) {
+ fprintf(stdout, " 0x%02x", (int )*p++);
+ i++;
+ if (i % 8 == 0) fprintf(stdout, "\n");
+ }
+ fprintf(stdout, "\n");
+ }
+#endif
+
+ ENC = ONIG_ENCODING_UTF8;
+
+ r = exec(ENC, reg_num, init_reg_num, pat, pat_end, lead, str, str_null_end);
+
+ for (i = 0; i < reg_num; i++) {
+ free(pat[i]);
+ }
+ free(str);
+
+ if (r == -2) {
+ //output_data("parser-bug", Data, Size);
+ exit(-2);
+ }
+
+ if (EXEC_COUNT_INTERVAL == EXEC_PRINT_INTERVAL) {
+ float fexec, freg, fvalid;
+
+ fexec = (float )EXEC_COUNT / INPUT_COUNT;
+ freg = (float )REGEX_SUCCESS_COUNT / INPUT_COUNT;
+ fvalid = (float )VALID_STRING_COUNT / INPUT_COUNT;
+
+ output_current_time(stdout);
+ fprintf(stdout, ": %ld: EXEC:%.2f, REG:%.2f, VALID:%.2f MAX REG:%d-%d\n",
+ EXEC_COUNT, fexec, freg, fvalid, MaxRegNum, MaxInitRegNum);
+
+ EXEC_COUNT_INTERVAL = 0;
+ }
+ else if (EXEC_COUNT == 1) {
+ output_current_time(stdout);
+ fprintf(stdout, ": ------------ START ------------\n");
+ }
+
+ return r;
+}
+
+#ifdef STANDALONE
+
+extern int main(int argc, char* argv[])
+{
+ size_t n;
+ uint8_t Data[10000];
+
+ n = read(0, Data, sizeof(Data));
+ fprintf(stdout, "n: %ld\n", n);
+ LLVMFuzzerTestOneInput(Data, n);
+
+ return 0;
+}
+#endif /* STANDALONE */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index.html b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index.html
new file mode 100644
index 000000000..58ba66d3b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index.html
@@ -0,0 +1,192 @@
+<html>
+<head>
+ <meta HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=x-sjis">
+ <title>Oniguruma</title>
+</head>
+<body BGCOLOR="#ffffff" VLINK="#808040" TEXT="#696969">
+
+<h1>Oniguruma</h1> (<a href="index_ja.html">Japanese</a>)
+
+<p>
+(c) K.Kosako, updated at: 2019/08/05
+</p>
+
+<dl>
+<font color="orange">
+<dt><b>What's new</b>
+</font>
+<ul>
+<li>2019/08/06: Version 6.9.3 released.</li>
+<li>2019/05/07: Version 6.9.2 released.</li>
+<li>2018/12/11: Version 6.9.1 released.</li>
+<li>2018/09/03: Version 6.9.0 released.</li>
+<li>2018/04/17: Version 6.8.2 released.</li>
+<li>2018/03/19: Version 6.8.1 released.</li>
+<li>2018/03/16: Version 6.8.0 released.</li>
+<li>2018/01/26: Version 6.7.1 released.</li>
+<li>2017/12/11: Version 6.7.0 released.</li>
+<li>2017/08/30: Version 6.6.1 released.</li>
+<li>2017/08/28: Version 6.6.0 released.</li>
+<li>2017/08/03: Version 6.5.0 released.</li>
+<li>2017/07/03: Version 6.4.0 released.</li>
+<li>2017/05/29: Version 6.3.0 released.</li>
+<li>2017/04/08: Version 6.2.0 released.</li>
+<li>2016/12/11: Version 6.1.3 released.</li>
+</ul>
+</dl>
+<hr>
+
+<p>
+Oniguruma is a regular expressions library.<br>
+The characteristics of this library is that different character encoding
+<br>for every regular expression object can be specified.
+<br>(supported APIs: GNU regex, POSIX and Oniguruma native)
+</p>
+
+<dl>
+<dt><b>Supported character encodings:</b><br>
+ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE,<br>
+EUC-JP, EUC-TW, EUC-KR, EUC-CN,<br>
+Shift_JIS, Big5, GB18030, KOI8-R, CP1251,<br>
+ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5,<br>
+ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10,<br>
+ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16<br>
+<font color="orange">
+(GB18030 encoding was contributed by KUBO Takehiro)<br>
+(CP1251 encoding was contributed by Byte)
+</font>
+</p>
+</dl>
+
+<hr>
+
+<dt><b>License:</b> BSD license.
+
+<dl>
+<dt><b>Platform:</b>
+<ul>
+<li> Unix (include Mac OS X)
+<li> Cygwin
+<li> Win32
+</ul>
+
+<br>
+<font color="red">
+Maintainer of 2.x was changed to Hannes Wyss &lt;hwyss AT ywesee.com&gt;.<br>
+About 2.x, please contact him.<br>
+</font>
+* 5.x supports Unicode Property/Script.<br>
+* 2.x supports Ruby1.6/1.8.<br>
+
+<br>
+<dt><b>Documents:</b> (version 6.1.0)
+<ul>
+ <li> <a href="doc/RE.txt">Regular Expressions</a>
+ <a href="doc/RE.ja.txt">(Japanese: EUC-JP)</a>
+ <li> <a href="doc/API.txt">Oniguruma API</a>
+ <a href="doc/API.ja.txt">(Japanese: EUC-JP)</a>
+</ul>
+
+<br>
+<dt><b>Sample Programs:</b>
+<ul>
+ <li><a href="sample/simple.c">example of the minimum</a>
+ <li><a href="sample/sql.c">example of the variable syntax and meta character (SQL-like pattern match)</a>
+</ul>
+
+<br>
+<dt><b>Site Links:</b>
+<ul>
+<li> <a href="http://www.freebsd.org/cgi/cvsweb.cgi/ports/devel/oniguruma/">FreeBSD ports</a>
+<li> <a href="http://www.softantenna.com/lib/1953/index.html">SoftAntenna &gt; Lib &gt; Oniguruma</a> (Japanese page)
+</ul>
+
+<br>
+<dt><b>Links:</b>
+<ul>
+<li> <a href="http://www.perzl.org/aix/index.php?n=Main.Oniguruma">AIX Open Source Packages</a>
+<li> <a href="https://aur.archlinux.org/packages/oniguruma/">Arch Linux Package</a>
+<li> <a href="http://homepage3.nifty.com/k-takata/mysoft/bregonig.html">bregonig.dll (Win32)</a> (Japanese page)
+<li> <a href="http://www.halbiz.com/osaru/cnregex.html">cnRegex 4D Plugin (Mac OS X)</a> (Japanese page)
+<li> <a href="http://limechat.net/cocoaoniguruma/">CocoaOniguruma</a>
+<li> <a href="http://kmaebashi.com/">crowbar</a> (Japanese page)
+<li> <a href="http://oniguruma5.darwinports.com">Darwin Ports (Mac OS X)</a>
+<li> <a href="http://homepage2.nifty.com/Km/onig.htm">Delphi interface (Win32)</a> (Japanese page)
+<li> <a href="http://pyxis-project.net/ensemble/">Ensemble (Mac OS X)</a> (Japanese page)
+<li> <a href="http://www.srcw.net/FaEdit/">FaEdit (Win32)</a> (Japanese page)
+<li> <a href="http://www.tom.sfc.keio.ac.jp/~sakai/d/?date=20050209">GHC patch</a> Masahiro Sakai (Japanese Blog)
+<li> <a href="http://www.gyazsquare.com/gyazmail/index.php">GyazMail (Mac OS X)</a>
+<li> <a href="http://www5d.biglobe.ne.jp/~f-taste/knt3/jcref3.html">J-cref v3</a> (Japanese page)
+<li> <a href="http://www.artman21.net/">Jedit X (Mac OS X)</a>
+<li> <a href="http://www.chitora.jp/lhaz.html">Lhaz (Win32)</a> (Japanese page)
+<li> <a href="http://limechat.net/">LimeChat</a> (Japanese page)
+<li> <a href="http://medb.enhiro.com/">meDB</a> (Japanese page)
+<li> <a href="http://monaos.org/">Mona OS</a>
+<li> <a href="http://mongoose.jp/">mongoose</a> (Japanese page)
+<li> <a href="http://www.irori.org/tool/mregexp.html">mregexp</a> (Japanese page)
+<li> <a href="http://ochusha.sourceforge.jp/">Ochusha</a> (Japanese page)
+<li> <a href="http://sonoisa.github.com/ogrekit/About_%28English%29.html">OgreKit (Mac OS X)</a> Regular Expression Framework for Cocoa (Japanese page)
+<li> <a href="http://www.kanetaka.net/4dapi/wiki4d.dll/4dcgi/wiki.cgi?plugins-oniguruma">OnigRegexp</a> (Japanese page)
+<li> <a href="http://rubyforge.org/projects/oniguruma">Oniguruma for Ruby</a>
+<li> <a href="http://openspace.timedia.co.jp/~yasuyuki/wiliki/wiliki.cgi?Oniguruma-mysqld&l=jp">Oniguruma-mysqld</a>
+<li> <a href="http://www.void.in/wiki/OnigPP">OnigPP</a> (Japanese page)
+<li> <a href="http://www.kt.rim.or.jp/~kbk/sed/index.html">Onigsed (Win32)</a> (Japanese page)
+<li> <a href="http://glozer.net/code.html#oregexp">oregexp</a> Erlang binding
+<li> <a href="http://www.kt.rim.or.jp/~kbk/yagrep/index.html">yagrep (Win32)</a> (Japanese page)
+<li> <a href="http://www.php.gr.jp/">Japan PHP User Group</a> PHP 5.0 mb_ereg (Japanese page)
+<li> <a href="http://yatsu.info/wiki/Pufui/">Pufui (Mac OS X)</a> (Japanese page)
+<li> <a href="http://ultrapop.jp/?q2ch">q2ch</a> (Japanese page)
+<li> <a href="http://search.cpan.org/~andya/re-engine-Oniguruma">re-engine-Oniguruma</a>
+<li> <a href="http://harumune.s56.xrea.com/assari/index.php?RSSTyping">RSSTyping</a> (Japanese page)
+<li> <a href="http://tobysoft.net/wiki/index.php?Ruby%2Fruby-win32-oniguruma">ruby-win32-oniguruma</a> (Japanese page)
+<li> <a href="http://quux.s74.xrea.com/">SevenFour (Mac OS X)</a> (Japanese page)
+<li> <a href="http://storklab.cyber-ninja.jp/">Stork Lab. Products (Mac OS X)</a> (Japanese page)
+<li> <a href="http://sourceforge.jp/projects/ttssh2/">TeraTerm (Win32)</a>
+<li> <a href="http://www8.ocn.ne.jp/~sonoisa/TiddlyWikiPod/">TiddlyWikiPod (Mac OS X)</a>
+<li> <a href="http://www.cyanworks.net/mac.html">TunesTEXT (Mac OS X)</a>
+<li> <a href="https://code.google.com/p/oniguruma-visualworks/">oniguruma-visualworks</a>
+<li> <a href="http://sourceforge.jp/projects/frogger/">XML parser</a>
+<li> <a href="http://www.yokkasoft.net/">YokkaSoft (Win32)</a> (Japanese page)
+<li> <a href="http://www.hi-ho.ne.jp/kuze/tool.htm">Zed (Win32)</a> (Japanese page)
+</ul>
+
+<br>
+<dt><b>References:</b>
+<ul>
+<li> <a href="http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%C0%B5%B5%AC%C9%BD%B8%BD">Ruby Reference Manual Regexp</a> (Japanese page)
+<li> <a href="http://www.perl.com/doc/manual/html/pod/perlre.html">Perl regular expressions</a>
+<li> <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html">java.util.regex.Pattern (J2SE 1.4.2)</a>
+<li> <a href="http://www.opengroup.org/onlinepubs/007908799/xbd/re.html">The Open Group</a>
+<li> <a href="http://regex.info/">Mastering Regular Expressions</a>
+<li> <a href="http://www.unicode.org/">Unicode Home Page</a>
+<li> <a href="http://www.kt.rim.or.jp/~kbk/regex/regex.html">Regular expressions memo</a> (Japanese page)
+<li> <a href="http://www.din.or.jp/~ohzaki/regex.htm">Regular expressions technique</a> (Japanese page)
+</ul>
+
+<br>
+</dl>
+<p>
+and I'm thankful to Akinori MUSHA.
+</p>
+
+<hr>
+<dl>
+<dt><b>Other Libraries:</b>
+<ul>
+<li> <a href="http://www.boost.org/libs/regex/doc/">Boost.Regex</a>
+<li> <a href="http://arglist.com/regex/">A copy of Henry Spencer's</a>
+<li> <a href="http://directory.fsf.org/regex.html">GNU regex</a>
+<li> <a href="http://www.pcre.org/">PCRE</a>
+<li> <a href="http://re2c.org/">re2c</a>
+<li> <a href="http://tiny-rex.sourceforge.net/">T-Rex</a>
+<li> <a href="http://laurikari.net/tre/">TRE</a>
+<li> <a href="http://svn.codehaus.org/jruby/joni/">Joni (Java)</a>
+<li> <a href="http://jregex.sourceforge.net/">JRegex (Java)</a>
+<li> <a href="http://www.cacas.org/java/gnu/regexp/">gnu.regexp for Java</a>
+<li> <a href="http://jakarta.apache.org/regexp/index.html">Jakarta Project Regexp</a>
+<li> <a href="http://jakarta.apache.org/oro/">Jakarta Project ORO</a>
+<li> <a href="http://sourceforge.jp/projects/onig4j/">Oniguruma for Java</a>
+</ul>
+</dl>
+</body>
+</html>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index_ja.html b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index_ja.html
new file mode 100644
index 000000000..6b75c6c2c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/index_ja.html
@@ -0,0 +1,195 @@
+<html>
+<head>
+ <meta HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=utf-8">
+ <title>鬼車</title>
+</head>
+<body BGCOLOR="#ffffff" VLINK="#808040" TEXT="#696969">
+
+<h1>鬼車</h1>
+
+<p>
+(c) K.Kosako, 最終更新: 2019/08/05
+</p>
+
+<dl>
+<font color="orange">
+<dt><b>更新情報</b>
+</font>
+<ul>
+<li>2019/08/06: Version 6.9.3 リリース</li>
+<li>2019/05/07: Version 6.9.2 リリース</li>
+<li>2018/12/11: Version 6.9.1 リリース</li>
+<li>2018/09/03: Version 6.9.0 リリース</li>
+<li>2018/04/17: Version 6.8.2 リリース</li>
+<li>2018/03/19: Version 6.8.1 リリース</li>
+<li>2018/03/16: Version 6.8.0 リリース</li>
+<li>2018/01/26: Version 6.7.1 リリース</li>
+<li>2017/12/11: Version 6.7.0 リリース</li>
+<li>2017/08/30: Version 6.6.1 リリース</li>
+<li>2017/08/28: Version 6.6.0 リリース</li>
+<li>2017/08/03: Version 6.5.0 リリース</li>
+<li>2017/07/03: Version 6.4.0 リリース</li>
+<li>2017/05/29: Version 6.3.0 リリース</li>
+<li>2017/04/08: Version 6.2.0 リリース</li>
+<li>2016/12/11: Version 6.1.3 リリース</li>
+</ul>
+</dl>
+<hr>
+
+<p>
+鬼車ã¯æ­£è¦è¡¨ç¾ãƒ©ã‚¤ãƒ–ラリã§ã‚る。<br>
+ã“ã®ãƒ©ã‚¤ãƒ–ラリã®ç‰¹å¾´ã¯ã€ãã‚Œãžã‚Œã®æ­£è¦è¡¨ç¾ã‚ªãƒ–ジェクトã”ã¨ã«ç•°ãªã‚‹æ–‡å­—エンコーディングを
+指定ã§ãã‚‹ã“ã¨ã€‚<br>
+(API: GNU regex, POSIX and Oniguruma native)
+</p>
+
+<dl>
+<dt><b>対応ã—ã¦ã„る文字エンコーディング:</b><br>
+ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE,<br>
+EUC-JP, EUC-TW, EUC-KR, EUC-CN,<br>
+Shift_JIS, Big5, GB18030, KOI8-R, CP1251,<br>
+ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5,<br>
+ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10,<br>
+ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16<br>
+<font color="orange">
+(GB18030ã¯ã€KUBO Takehiroæ°æä¾›)<br>
+(CP1251ã¯ã€Byteæ°æä¾›)
+</font>
+</p>
+</dl>
+
+<hr>
+
+<dt><b>ライセンス:</b>BSDライセンス
+
+<dl>
+<dt><b>プラットフォーム:</b>
+<ul>
+<li> Unix (Mac OS Xã‚’å«ã‚€)
+<li> Cygwin
+<li> Win32
+</ul>
+
+<br>
+<font color="red">
+2.xã®ä¿å®ˆæ‹…当ã¯ã€Hannes Wyss &lt;hwyss AT ywesee.com&gt;ã«äº¤æ›¿ã—ã¾ã—ãŸã€‚<br>
+2.xã«ã¤ã„ã¦ã¯ã€å½¼ã«é€£çµ¡ã—ã¦ãã ã•ã„。<br>
+</font>
+* 5.xã¯Unicode Property/Scriptã‚’æä¾›<br>
+* 2.xã¯Ruby1.6/1.8組込ã¿ãƒ©ã‚¤ãƒ–ラリã¨ã—ã¦å‹•ä½œã™ã‚‹ã€‚ (2006年末ã§ä¿å®ˆã‚’終了)<br>
+
+<br>
+<dt><b>ドキュメント:</b> (version 6.1.0)
+<ul>
+ <li> <a href="doc/RE.txt">æ­£è¦è¡¨ç¾</a>
+ <a href="doc/RE.ja.txt">(日本語: EUC-JP)</a>
+ <li> <a href="doc/API.txt">鬼車API</a>
+ <a href="doc/API.ja.txt">(日本語: EUC-JP)</a>
+</ul>
+
+<br>
+<dt><b>サンプルプログラム:</b>
+<ul>
+ <li><a href="sample/simple.c">最å°ä½¿ç”¨ä¾‹</a>
+ <li><a href="sample/sql.c">å¯å¤‰æ–‡æ³•ã¨å¯å¤‰ãƒ¡ã‚¿æ–‡å­—機能使用例(SQL-like pattern match)</a>
+</ul>
+
+<br>
+<dt><b>サイト:</b>
+<ul>
+<li> <a href="http://www.freebsd.org/cgi/cvsweb.cgi/ports/devel/oniguruma/">FreeBSD ports</a>
+<li> <a href="http://www.softantenna.com/lib/1953/index.html">SoftAntenna &gt; Lib &gt; Oniguruma</a> (日本語)
+</ul>
+
+<br>
+<dt><b>リンク:</b>
+<ul>
+<li> <a href="http://www.perzl.org/aix/index.php?n=Main.Oniguruma">AIX Open Source Packages</a>
+<li> <a href="https://aur.archlinux.org/packages/oniguruma/">Arch Linux Package</a>
+<li> <a href="http://homepage3.nifty.com/k-takata/mysoft/bregonig.html">bregonig.dll (Win32)</a> (日本語)
+<li> <a href="http://www.halbiz.com/osaru/cnregex.html">cnRegex 4D Plugin (Mac OS X)</a> (日本語)
+<li> <a href="http://limechat.net/cocoaoniguruma/index_ja.html">CocoaOniguruma</a> (日本語)
+<li> <a href="http://kmaebashi.com/">crowbar</a> (日本語)
+<li> <a href="http://oniguruma5.darwinports.com">Darwin Ports (Mac OS X)</a>
+<li> <a href="http://homepage2.nifty.com/Km/onig.htm">Delphi interface (Win32)</a> (日本語)
+<li> <a href="http://pyxis-project.net/ensemble/">Ensemble (Mac OS X)</a> (日本語)
+<li> <a href="http://www.srcw.net/FaEdit/">FaEdit (Win32)</a> (日本語)
+<li> <a href="http://www.tom.sfc.keio.ac.jp/~sakai/d/?date=20050209">GHC patch</a> Masahiro Sakai (Japanese Blog)
+<li> <a href="http://www.gyazsquare.com/gyazmail/index.php">GyazMail (Mac OS X)</a>
+<li> <a href="http://www5d.biglobe.ne.jp/~f-taste/knt3/jcref3.html">J-cref v3</a> (日本語)
+<li> <a href="http://www.artman21.net/">Jedit X (Mac OS X)</a>
+<li> <a href="http://www.chitora.jp/lhaz.html">Lhaz (Win32)</a> (日本語)
+<li> <a href="http://limechat.net/">LimeChat</a> (日本語)
+<li> <a href="http://medb.enhiro.com/">meDB</a> (日本語)
+<li> <a href="http://monaos.org/">Mona OS</a>
+<li> <a href="http://mongoose.jp/">mongoose</a> (日本語)
+<li> <a href="http://www.irori.org/tool/mregexp.html">mregexp</a> (日本語)
+<li> <a href="http://ochusha.sourceforge.jp/">ãŠã¡ã‚…〜ã—ゃ</a> (日本語)
+<li> <a href="http://sonoisa.github.com/ogrekit/About.html">OgreKit (Mac OS X)</a> Regular Expression Framework for Cocoa (日本語)
+<li> <a href="http://www.kanetaka.net/4dapi/wiki4d.dll/4dcgi/wiki.cgi?plugins-oniguruma">OnigRegexp</a> (日本語)
+<li> <a href="http://rubyforge.org/projects/oniguruma">Oniguruma for Ruby</a>
+<li> <a href="http://openspace.timedia.co.jp/~yasuyuki/wiliki/wiliki.cgi?Oniguruma-mysqld&l=jp">Oniguruma-mysqld</a>
+<li> <a href="http://www.void.in/wiki/OnigPP">OnigPP</a> (日本語)
+<li> <a href="http://www.kt.rim.or.jp/~kbk/sed/index.html">Onigsed (Win32)</a> (日本語)
+<li> <a href="http://glozer.net/code.html#oregexp">oregexp</a> Erlang binding
+<li> <a href="http://www.kt.rim.or.jp/~kbk/yagrep/index.html">yagrep (Win32)</a> (日本語)
+<li> <a href="http://www.php.gr.jp/">日本PHPユーザ会</a> PHP 5.0 mb_ereg (日本語)
+<li> <a href="http://yatsu.info/wiki/Pufui/">Pufui (Mac OS X)</a> (日本語)
+<li> <a href="http://ultrapop.jp/?q2ch">q2ch</a> (日本語)
+<li> <a href="http://search.cpan.org/~andya/re-engine-Oniguruma">re-engine-Oniguruma</a>
+<li> <a href="http://harumune.s56.xrea.com/assari/index.php?RSSTyping">RSSTyping</a> (日本語)
+<li> <a href="http://tobysoft.net/wiki/index.php?Ruby%2Fruby-win32-oniguruma">ruby-win32-oniguruma</a> (日本語)
+<li> <a href="http://quux.s74.xrea.com/">SevenFour (Mac OS X)</a> (日本語)
+<li> <a href="http://storklab.cyber-ninja.jp/">Stork Lab. Products (Mac OS X)</a> (日本語)
+<li> <a href="http://sourceforge.jp/projects/ttssh2/">TeraTerm (Win32)</a>
+<li> <a href="http://www8.ocn.ne.jp/~sonoisa/TiddlyWikiPod/">TiddlyWikiPod (Mac OS X)</a>
+<li> <a href="http://www.cyanworks.net/mac.html">TunesTEXT (Mac OS X)</a>
+<li> <a href="https://code.google.com/p/oniguruma-visualworks/">oniguruma-visualworks</a>
+<li> <a href="http://sourceforge.jp/projects/frogger/">XML parser</a>
+<li> <a href="http://www.yokkasoft.net/">YokkaSoft (Win32)</a> (日本語)
+<li> <a href="http://www.hi-ho.ne.jp/kuze/tool.htm">Zed (Win32)</a> (日本語)
+</ul>
+
+<br>
+<dt><b>å‚考資料:</b>
+<ul>
+<li> <a href="http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%C0%B5%B5%AC%C9%BD%B8%BD">Rubyリファレンスマニュアル</a> (日本語)
+<li> <a href="http://www.perl.com/doc/manual/html/pod/perlre.html">Perl regular expressions</a>
+<li> <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html">java.util.regex.Pattern (J2SE 1.4.2)</a>
+<li> <a href="http://www.opengroup.org/onlinepubs/007908799/xbd/re.html">The Open Group</a>
+<li> <a href="http://regex.info/">Mastering Regular Expressions</a>
+<li> <a href="http://www.unicode.org/">Unicode Home Page</a>
+<li> <a href="http://www.kt.rim.or.jp/~kbk/regex/regex.html">æ­£è¦è¡¨ç¾ãƒ¡ãƒ¢</a> (日本語)
+<li> <a href="http://www.din.or.jp/~ohzaki/regex.htm">Perlæ­£è¦è¡¨ç¾é›‘技</a> (日本語)
+</ul>
+
+<br>
+</dl>
+<p>
+and I'm thankful to Akinori MUSHA.
+</p>
+
+<hr>
+<dl>
+<dt><b>ä»–ã®ãƒ©ã‚¤ãƒ–ラリ:</b>
+<ul>
+<li> <a href="http://www.boost.org/libs/regex/doc/">Boost.Regex</a>
+<li> <a href="http://arglist.com/regex/">A copy of Henry Spencer's</a>
+<li> <a href="http://directory.fsf.org/regex.html">GNU regex</a>
+<li> <a href="http://www.pcre.org/">PCRE</a>
+<li> <a href="http://re2c.org/">re2c</a>
+<li> <a href="http://tiny-rex.sourceforge.net/">T-Rex</a>
+<li> <a href="http://laurikari.net/tre/">TRE</a>
+<li> <a href="http://svn.codehaus.org/jruby/joni/">Joni (Java)</a>
+<li> <a href="http://jregex.sourceforge.net/">JRegex (Java)</a>
+<li> <a href="http://www.cacas.org/java/gnu/regexp/">gnu.regexp for Java</a>
+<li> <a href="http://jakarta.apache.org/regexp/index.html">Jakarta Project Regexp</a>
+<li> <a href="http://jakarta.apache.org/oro/">Jakarta Project ORO</a>
+<li> <a href="http://sourceforge.jp/projects/onig4j/">Oniguruma for Java</a>
+</ul>
+</dl>
+
+<hr>
+<a href="../">ホームã«ã‚‚ã©ã‚‹</a>
+</body>
+</html>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/install-sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/install-sh
new file mode 100755
index 000000000..8175c640f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/install-sh
@@ -0,0 +1,518 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2018-03-11.20; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ # Note that $RANDOM variable is not portable (e.g. dash); Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p' feature.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/m4/.whatever b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/m4/.whatever
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/m4/.whatever
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win.bat b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win.bat
new file mode 100644
index 000000000..470ef1198
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win.bat
@@ -0,0 +1,5 @@
+SET ONIG_DIR=%~dp0\src
+set THIS_DIR=%~dp0
+set BUILD_DIR=%cd%
+copy %ONIG_DIR%\config.h.windows.in %BUILD_DIR%\config.h
+nmake -f %ONIG_DIR%\Makefile.windows %1
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win32.bat b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win32.bat
new file mode 100644
index 000000000..bd1a07216
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win32.bat
@@ -0,0 +1,5 @@
+SET ONIG_DIR=%~dp0\src
+set THIS_DIR=%~dp0
+set BUILD_DIR=%cd%
+copy %ONIG_DIR%\config.h.win32 %BUILD_DIR%\config.h
+nmake -f %ONIG_DIR%\Makefile.windows %1
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win64.bat b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win64.bat
new file mode 100644
index 000000000..ee0a04991
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/make_win64.bat
@@ -0,0 +1,5 @@
+SET ONIG_DIR=%~dp0\src
+set THIS_DIR=%~dp0
+set BUILD_DIR=%cd%
+copy %ONIG_DIR%\config.h.win64 %BUILD_DIR%\config.h
+nmake -f %ONIG_DIR%\Makefile.windows %1
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/missing b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/missing
new file mode 100755
index 000000000..625aeb118
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=https://www.perl.org/
+flex_URL=https://github.com/westes/flex
+gnu_software_URL=https://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/onig-config.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/onig-config.in
new file mode 100644
index 000000000..788d6bae2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/onig-config.in
@@ -0,0 +1,78 @@
+#!/bin/sh
+# Copyright (C) 2006 K.Kosako
+
+ONIG_VERSION=@PACKAGE_VERSION@
+
+show_usage()
+{
+ cat <<EOF
+Usage: onig-config [OPTION]
+
+ Values for OPTION are:
+ --prefix[=DIR] change prefix to DIR
+ --prefix print prefix
+ --exec-prefix[=DIR] change exec_prefix to DIR
+ --exec-prefix print exec_prefix
+ --cflags print C compiler flags
+ --libs print library information
+ --version print oniguruma version
+ --help print this help
+
+EOF
+
+ exit 1
+}
+
+if test $# -eq 0; then
+ show_usage
+fi
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+is_set_exec_prefix=no
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) val=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'`
+ ;;
+ *) val=
+ ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ prefix=$val
+ if test $is_set_exec_prefix = no ; then
+ exec_prefix=$val
+ fi
+ ;;
+ --prefix)
+ echo $prefix
+ ;;
+ --exec-prefix=*)
+ exec_prefix=$val
+ is_set_exec_prefix=yes
+ ;;
+ --exec-prefix)
+ echo $exec_prefix
+ ;;
+ --cflags)
+ if test @includedir@ != /usr/include ; then
+ show_includedir=-I@includedir@
+ fi
+ echo $show_includedir
+ ;;
+ --libs)
+ echo -L@libdir@ -lonig
+ ;;
+ --version)
+ echo $ONIG_VERSION
+ ;;
+ *)
+ show_usage
+ ;;
+ esac
+ shift
+done
+
+# END
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.cmake.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.cmake.in
new file mode 100644
index 000000000..28562afa1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.cmake.in
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+datarootdir=${prefix}/share
+datadir=${prefix}/share
+
+Name: oniguruma
+Description: Regular expression library
+Version: @PACKAGE_VERSION@
+Requires:
+Libs: -L${libdir} -lonig
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.in
new file mode 100644
index 000000000..ab27016a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/oniguruma.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+
+Name: oniguruma
+Description: Regular expression library
+Version: @PACKAGE_VERSION@
+Requires:
+Libs: -L${libdir} -lonig
+Cflags: -I${includedir}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/CMakeLists.txt b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/CMakeLists.txt
new file mode 100644
index 000000000..c0bd05728
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 2.8)
+project(oniguruma_sample C)
+
+add_executable(crnl crnl.c)
+target_link_libraries(crnl onig)
+
+add_executable(callout callout.c)
+target_link_libraries(callout onig)
+
+add_executable(echo echo.c)
+target_link_libraries(echo onig)
+
+add_executable(count count.c)
+target_link_libraries(count onig)
+
+add_executable(encode encode.c)
+target_link_libraries(encode onig)
+
+add_executable(listcap listcap.c)
+target_link_libraries(listcap onig)
+
+add_executable(names names.c)
+target_link_libraries(names onig)
+
+add_executable(posix posix.c)
+target_link_libraries(posix onig)
+
+add_executable(simple simple.c)
+target_link_libraries(simple onig)
+
+add_executable(sql sql.c)
+target_link_libraries(sql onig)
+
+add_executable(syntax syntax.c)
+target_link_libraries(syntax onig)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/Makefile.am b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/Makefile.am
new file mode 100644
index 000000000..2bf469711
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/Makefile.am
@@ -0,0 +1,49 @@
+#noinst_PROGRAMS = encode listcap names posix simple sql syntax crnl
+
+lib_onig = ../src/libonig.la
+LDADD = $(lib_onig)
+
+AM_CFLAGS = -Wall
+AM_LDFLAGS = -L$(prefix)/lib
+AM_CPPFLAGS = -I$(top_srcdir)/src
+
+if ENABLE_POSIX_API
+TESTS = encode listcap names posix simple sql syntax user_property callout echo count bug_fix regset
+else
+TESTS = encode listcap names simple sql syntax user_property callout echo count bug_fix regset
+endif
+
+check_PROGRAMS = $(TESTS)
+
+encode_SOURCES = encode.c
+listcap_SOURCES = listcap.c
+names_SOURCES = names.c
+posix_SOURCES = posix.c
+simple_SOURCES = simple.c
+sql_SOURCES = sql.c
+syntax_SOURCES = syntax.c
+user_property_SOURCES = user_property.c
+callout_SOURCES = callout.c
+echo_SOURCES = echo.c
+count_SOURCES = count.c
+bug_fix = bug_fix.c
+regset_SOURCES = regset.c
+
+sampledir = .
+
+test: $(TESTS)
+ $(sampledir)/encode
+ $(sampledir)/listcap
+ $(sampledir)/names
+if ENABLE_POSIX_API
+ $(sampledir)/posix
+endif
+ $(sampledir)/simple
+ $(sampledir)/sql
+ $(sampledir)/syntax
+ $(sampledir)/user_property
+ $(sampledir)/callout
+ $(sampledir)/echo
+ $(sampledir)/count
+ $(sampledir)/bug_fix
+ $(sampledir)/regset
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/bug_fix.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/bug_fix.c
new file mode 100644
index 000000000..f295bfde8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/bug_fix.c
@@ -0,0 +1,93 @@
+/*
+ * bug_fix.c
+ */
+#include <stdio.h>
+#include "oniguruma.h"
+
+static int
+search(regex_t* reg, unsigned char* str, unsigned char* end)
+{
+ int r;
+ unsigned char *start, *range;
+ OnigRegion *region;
+
+ region = onig_region_new();
+
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d (%s)\n", r,
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail (%s)\n",
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ fprintf(stderr, " (%s)\n", ONIGENC_NAME(onig_get_encoding(reg)));
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return 0;
+}
+
+static int
+exec(OnigEncoding enc, OnigOptionType options, char* apattern, char* astr)
+{
+ int r;
+ unsigned char *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+
+ r = onig_new(&reg, pattern,
+ pattern + onigenc_str_bytelen_null(enc, pattern),
+ options, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ end = str + onigenc_str_bytelen_null(enc, str);
+ r = search(reg, str, end);
+
+ onig_free(reg);
+ return 0;
+}
+
+
+
+extern int main(int argc, char* argv[])
+{
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, 1);
+
+ /* fix ignore case in look-behind
+ commit: 3340ec2cc5627172665303fe248c9793354d2251 */
+ exec(ONIG_ENCODING_UTF8, ONIG_OPTION_IGNORECASE,
+ "\305\211a", "\312\274na"); /* \u{0149}a \u{02bc}na */
+
+ exec(ONIG_ENCODING_UTF8, ONIG_OPTION_NONE, "(\\2)(\\1)", "aa"); /* fail. */
+
+ exec(ONIG_ENCODING_UTF8, ONIG_OPTION_FIND_LONGEST,
+ "a*", "aa aaa aaaa aaaaa "); /* match 12-17 */
+
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/callout.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/callout.c
new file mode 100644
index 000000000..b5e3d91ba
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/callout.c
@@ -0,0 +1,268 @@
+/*
+ * callout.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+static int
+callout_body(OnigCalloutArgs* args, void* user_data)
+{
+ int r;
+ int i;
+ int n;
+ int begin, end;
+ int used_num;
+ int used_bytes;
+ OnigCalloutIn in;
+ int name_id;
+ const UChar* contents;
+ const UChar* start;
+ const UChar* current;
+ regex_t* regex;
+
+ in = onig_get_callout_in_by_callout_args(args);
+ name_id = onig_get_name_id_by_callout_args(args);
+ start = onig_get_start_by_callout_args(args);
+ current = onig_get_current_by_callout_args(args);
+ regex = onig_get_regex_by_callout_args(args);
+
+ contents = onig_get_contents_by_callout_args(args);
+
+ if (name_id != ONIG_NON_NAME_ID) {
+ UChar* name = onig_get_callout_name_by_name_id(name_id);
+ fprintf(stdout, "name: %s\n", name);
+ }
+ fprintf(stdout,
+ "%s %s: contents: \"%s\", start: \"%s\", current: \"%s\"\n",
+ contents != 0 ? "CONTENTS" : "NAME",
+ in == ONIG_CALLOUT_IN_PROGRESS ? "PROGRESS" : "RETRACTION",
+ contents, start, current);
+
+ fprintf(stdout, "user_data: %s\n", (char* )user_data);
+
+ (void )onig_get_used_stack_size_in_callout(args, &used_num, &used_bytes);
+ fprintf(stdout, "stack: used_num: %d, used_bytes: %d\n", used_num, used_bytes);
+
+ n = onig_number_of_captures(regex);
+ for (i = 1; i <= n; i++) {
+ r = onig_get_capture_range_in_callout(args, i, &begin, &end);
+ if (r != ONIG_NORMAL) return r;
+
+ fprintf(stdout, "capture %d: (%d-%d)\n", i, begin, end);
+ }
+
+ fflush(stdout);
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+static int
+progress_callout_func(OnigCalloutArgs* args, void* user_data)
+{
+ return callout_body(args, user_data);
+}
+
+static int
+retraction_callout_func(OnigCalloutArgs* args, void* user_data)
+{
+ return callout_body(args, user_data);
+}
+
+static int
+foo(OnigCalloutArgs* args, void* user_data)
+{
+ return callout_body(args, user_data);
+}
+
+static int
+bar(OnigCalloutArgs* args, void* user_data)
+{
+ int r;
+ int i;
+ int n;
+ OnigType type;
+ OnigValue val;
+
+ fprintf(stdout, "bar called.\n");
+
+ n = onig_get_args_num_by_callout_args(args);
+ if (n < 0) {
+ fprintf(stderr, "FAIL: onig_get_args_num_by_callout_args(): %d\n", n);
+ return n;
+ }
+
+ for (i = 0; i < n; i++) {
+ r = onig_get_arg_by_callout_args(args, i, &type, &val);
+ if (r != 0) {
+ fprintf(stderr, "FAIL: onig_get_arg_by_callout_args(): %d\n", r);
+ return r;
+ }
+
+ fprintf(stdout, "arg[%d]: ", i);
+ switch (type) {
+ case ONIG_TYPE_LONG:
+ fprintf(stdout, "%ld\n", val.l);
+ break;
+ case ONIG_TYPE_CHAR:
+ fprintf(stdout, "0x%06x\n", val.c);
+ break;
+ case ONIG_TYPE_STRING:
+ fprintf(stdout, "'%s'\n", val.s.start);
+ break;
+ default:
+ /* Never come here. But escape warning. */
+ break;
+ };
+ }
+
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+static int
+test(OnigEncoding enc, OnigMatchParam* mp, char* in_pattern, char* in_str)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ UChar* pattern;
+ UChar* str;
+
+ pattern = (UChar* )in_pattern;
+ str = (UChar* )in_str;
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "COMPILE ERROR: %d: %s\n", r, s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search_with_param(reg, str, end, start, range, region,
+ ONIG_OPTION_NONE, mp);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "SEARCH ERROR: %d: %s\n", r, s);
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return r;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ int id;
+ void* user_data;
+ UChar* name;
+ OnigEncoding use_encs[1];
+ unsigned int arg_types[4];
+ OnigValue opt_defaults[4];
+ OnigEncoding enc;
+ OnigMatchParam* mp;
+
+ enc = ONIG_ENCODING_UTF8;
+ use_encs[0] = enc;
+
+ r = onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+ if (r != ONIG_NORMAL) return -1;
+
+ /* monitor on */
+ r = onig_setup_builtin_monitors_by_ascii_encoded_name(stdout);
+ if (r != ONIG_NORMAL) return -1;
+
+ name = (UChar* )"foo";
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,
+ name, name + strlen((char* )name),
+ ONIG_CALLOUT_IN_BOTH, foo, 0, 0, 0, 0, 0);
+ if (id < 0) {
+ fprintf(stderr, "ERROR: fail to set callout of name: %s\n", name);
+ //return -1;
+ }
+
+ name = (UChar* )"bar";
+ arg_types[0] = ONIG_TYPE_LONG;
+ arg_types[1] = ONIG_TYPE_STRING;
+ arg_types[2] = ONIG_TYPE_CHAR;
+ opt_defaults[0].s.start = (UChar* )"I am a option argument's default value.";
+ opt_defaults[0].s.end = opt_defaults[0].s.start +
+ strlen((char* )opt_defaults[0].s.start);
+ opt_defaults[1].c = 0x4422;
+
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,
+ name, name + strlen((char* )name),
+ ONIG_CALLOUT_IN_PROGRESS, bar, 0,
+ 3, arg_types, 2, opt_defaults);
+ if (id < 0) {
+ fprintf(stderr, "ERROR: fail to set callout of name: %s\n", name);
+ //return -1;
+ }
+
+ (void)onig_set_progress_callout(progress_callout_func);
+ (void)onig_set_retraction_callout(retraction_callout_func);
+
+ mp = onig_new_match_param();
+
+ user_data = (void* )"something data";
+ r = onig_set_callout_user_data_of_match_param(mp, user_data);
+ if (r != ONIG_NORMAL) {
+ fprintf(stderr, "ERROR: fail onig_set_callout_user_data_of_match_param(): %d\n", r);
+ }
+
+ /* callout of contents */
+ test(enc, mp, "a+(?{foo bar baz...}X)$", "aaab");
+ test(enc, mp, "(?{{!{}#$%&'()=-~^|[_]`@*:+;<>?/.\\,}}[symbols])c", "abc");
+ test(enc, mp, "\\A(...)(?{{{booooooooooooo{{ooo}}ooooooooooz}}}<)", "aaab");
+ test(enc, mp, "\\A(?!a(?{in prec-read-not}[xxx]X)b)", "ac");
+ test(enc, mp, "(?<!a(?{in look-behind-not}X)c)c", "abc");
+
+ // callout of name
+ test(enc, mp, "\\A(*foo)abc", "abc");
+ test(enc, mp, "abc(?:(*FAIL)|$)", "abcabc");
+ test(enc, mp, "abc(?:$|(*MISMATCH)|abc$)", "abcabc");
+ test(enc, mp, "abc(?:(*ERROR)|$)", "abcabc");
+ test(enc, mp, "ab(*foo{})(*FAIL)", "abc");
+ test(enc, mp, "abc(d|(*ERROR{-999}))", "abc");
+ test(enc, mp, "ab(*bar{372,I am a bar's argument,ã‚})c(*FAIL)", "abc");
+ test(enc, mp, "ab(*bar{1234567890})", "abc");
+ test(enc, mp, "(?:a(*MAX{2})|b)*", "abbabbabbabb");
+ test(enc, mp, "(?:(*MAX{2})a|b)*", "abbabbabbabb");
+ test(enc, mp, "(?:(*MAX{1})a|b)*", "bbbbbabbbbbabbbbb");
+ test(enc, mp, "(?:(*MAX{3})a|(*MAX{4})b)*", "bbbaabbab");
+ test(enc, mp, "(?:(*MAX[A]{3})a|(*MAX[B]{5})b)*(*CMP{A,<,B})", "abababc");
+ test(enc, mp, "(?:(*MAX[A]{7})a|(*MAX[B]{5})b)*(*CMP{A,>=,4})", "abababcabababaa");
+ test(enc, mp, "(?:(*MAX[T]{3})a)*(?:(*MAX{T})c)*", "aaccc");
+
+ /* callouts in condition */
+ test(enc, mp, "\\A(?(?{in condition})then|else)\\z", "then");
+ test(enc, mp, "\\A(?(*FAIL)then|else)\\z", "else");
+
+ /* monitor test */
+ test(enc, mp, "(?:(*MON{X})(*FAIL)|.{,3}(*MON[FOO])k)", "abcdefghijk");
+
+ onig_free_match_param(mp);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/count.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/count.c
new file mode 100644
index 000000000..2b67db746
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/count.c
@@ -0,0 +1,125 @@
+/*
+ * count.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+#define ulen(enc, p) onigenc_str_bytelen_null(enc, (UChar* )p)
+
+static int
+test(OnigEncoding enc, OnigMatchParam* mp, char* in_pattern, char* in_str)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ UChar* pattern;
+ UChar* str;
+
+ pattern = (UChar* )in_pattern;
+ str = (UChar* )in_str;
+
+ r = onig_new(&reg, pattern, pattern + ulen(enc, pattern),
+ ONIG_OPTION_DEFAULT, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "COMPILE ERROR: %d: %s\n", r, s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + ulen(enc, str);
+ start = str;
+ range = end;
+ r = onig_search_with_param(reg, str, end, start, range, region,
+ ONIG_OPTION_NONE, mp);
+ if (r >= 0) {
+ int slot;
+ OnigValue val;
+ char* tag;
+ int tag_len;
+
+ fprintf(stdout, "match at %d\n", r);
+
+ show_count:
+ if (enc == ONIG_ENCODING_UTF16_BE) {
+ tag = "\000x\000\000";
+ }
+ else if (enc == ONIG_ENCODING_UTF16_LE) {
+ tag = "x\000\000\000";
+ }
+ else {
+ tag = "x";
+ }
+ tag_len = ulen(enc, tag);
+
+ slot = 0;
+ r = onig_get_callout_data_by_tag(reg, mp, (UChar* )tag, (UChar* )tag + tag_len,
+ slot, 0, &val);
+ if (r < ONIG_NORMAL) goto err;
+ else if (r > ONIG_NORMAL) {
+ fprintf(stdout, "COUNT[x]: NO DATA\n");
+ }
+ else {
+ fprintf(stdout, "COUNT[x]: %ld\n", val.l);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stdout, "search fail\n");
+ goto show_count;
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ err:
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stdout, "SEARCH ERROR: %d: %s\n", r, s);
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return r;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ OnigMatchParam* mp;
+ OnigEncoding encs[3];
+
+ encs[0] = ONIG_ENCODING_UTF8;
+ encs[1] = ONIG_ENCODING_UTF16_BE;
+ encs[2] = ONIG_ENCODING_UTF16_LE;
+
+ r = onig_initialize(encs, sizeof(encs)/sizeof(encs[0]));
+ if (r != ONIG_NORMAL) {
+ fprintf(stderr, "FAIL: onig_initialize(): %d\n", r);
+ return -1;
+ }
+
+ mp = onig_new_match_param();
+
+ test(encs[0], mp, "abc(.(*COUNT[x]))*(*FAIL)", "abcdefg");
+ test(encs[0], mp, "abc(.(*COUNT[_any_]))*(.(*COUNT[x]))*d", "abcdefg");
+ /* fail count */
+ test(encs[0], mp, "abc(.(*COUNT[x]{<}))*f", "abcdefg");
+ /* success count */
+ test(encs[0], mp, "abc(.(*COUNT[x]{X}))*f", "abcdefg");
+ /* passed count */
+ test(encs[0], mp, "abc(.(*COUNT[x]))*f", "abcdefg");
+ test(encs[0], mp, "a(.(*COUNT[x]))*z", "abcd\nabcdz");
+ /* total count */
+ test(encs[0], mp, "a(.(*TOTAL_COUNT[x]))*z", "abcd\nabcdz");
+
+ test(encs[1], mp, "\000a\000b\000c\000(\000.\000(\000*\000C\000O\000U\000N\000T\000[\000x\000]\000)\000)\000*\000(\000*\000F\000A\000I\000L\000)\000\000", "\000a\000b\000c\000d\000e\000f\000g\000\000");
+
+ test(encs[2], mp, "a\000b\000c\000(\000.\000(\000*\000C\000O\000U\000N\000T\000[\000x\000]\000)\000)\000*\000(\000*\000F\000A\000I\000L\000)\000\000\000", "a\000b\000c\000d\000e\000f\000g\000\000\000");
+
+ onig_free_match_param(mp);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/crnl.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/crnl.c
new file mode 100644
index 000000000..bfa563eb7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/crnl.c
@@ -0,0 +1,129 @@
+/*
+ * crnl.c 2007/05/30 K.Kosako
+ *
+ * !!! You should enable USE_CRNL_AS_LINE_TERMINATOR. !!!
+ *
+ * USE_CRNL_AS_LINE_TERMINATOR config test program.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+static int nfail = 0;
+
+static void result(int no, int from, int to,
+ int expected_from, int expected_to)
+{
+ fprintf(stderr, "%3d: ", no);
+ if (from == expected_from && to == expected_to) {
+ fprintf(stderr, "Success\n");
+ }
+ else {
+ fprintf(stderr, "Fail: expected: (%d-%d), result: (%d-%d)\n",
+ expected_from, expected_to, from, to);
+
+ nfail++;
+ }
+}
+
+static int
+x(int no, char* pattern_arg, char* str_arg,
+ int expected_from, int expected_to)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ UChar *pattern, *str;
+
+ pattern = (UChar* )pattern_arg;
+ str = (UChar* )str_arg;
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str(s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0 || r == ONIG_MISMATCH) {
+ result(no, region->beg[0], region->end[0], expected_from, expected_to);
+ }
+ else if (r == ONIG_MISMATCH) {
+ result(no, r, -1, expected_from, expected_to);
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str(s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return 0;
+}
+
+static int
+f(int no, char* pattern_arg, char* str_arg)
+{
+ return x(no, pattern_arg, str_arg, -1, -1);
+}
+
+extern int main(int argc, char* argv[])
+{
+ x( 1, "", "\r\n", 0, 0);
+ x( 2, ".", "\r\n", 0, 1);
+ f( 3, "..", "\r\n");
+ x( 4, "^", "\r\n", 0, 0);
+ x( 5, "\\n^", "\r\nf", 1, 2);
+ x( 6, "\\n^a", "\r\na", 1, 3);
+ x( 7, "$", "\r\n", 0, 0);
+ x( 8, "T$", "T\r\n", 0, 1);
+ x( 9, "T$", "T\raT\r\n", 3, 4);
+ x(10, "\\z", "\r\n", 2, 2);
+ f(11, "a\\z", "a\r\n");
+ x(12, "\\Z", "\r\n", 0, 0);
+ x(13, "\\Z", "\r\na", 3, 3);
+ x(14, "\\Z", "\r\n\r\n\n", 4, 4);
+ x(15, "\\Z", "\r\n\r\nX", 5, 5);
+ x(16, "a\\Z", "a\r\n", 0, 1);
+ x(17, "aaaaaaaaaaaaaaa\\Z", "aaaaaaaaaaaaaaa\r\n", 0, 15);
+ x(18, "a|$", "b\r\n", 1, 1);
+ x(19, "$|b", "\rb", 1, 2);
+ x(20, "a$|ab$", "\r\nab\r\n", 2, 4);
+
+ x(21, "a|\\Z", "b\r\n", 1, 1);
+ x(22, "\\Z|b", "\rb", 1, 2);
+ x(23, "a\\Z|ab\\Z", "\r\nab\r\n", 2, 4);
+ x(24, "(?=a$).", "a\r\n", 0, 1);
+ f(25, "(?=a$).", "a\r");
+ x(26, "(?!a$)..", "a\r", 0, 2);
+ x(27, "(?<=a$).\\n", "a\r\n", 1, 3);
+ f(28, "(?<!a$).\\n", "a\r\n");
+ x(29, "(?=a\\Z).", "a\r\n", 0, 1);
+ f(30, "(?=a\\Z).", "a\r");
+ x(31, "(?!a\\Z)..", "a\r", 0, 2);
+
+ onig_end();
+
+ if (nfail > 0) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "!!! You have to enable USE_CRNL_AS_LINE_TERMINATOR\n");
+ fprintf(stderr, "!!! in regenc.h for this test program.\n");
+ fprintf(stderr, "\n");
+ }
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/echo.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/echo.c
new file mode 100644
index 000000000..76df20770
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/echo.c
@@ -0,0 +1,136 @@
+/*
+ * echo.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+static int
+echo(OnigCalloutArgs* args, void* user_data)
+{
+ int r;
+ OnigCalloutIn in;
+ OnigType type;
+ OnigValue val;
+ FILE* fp;
+
+ fp = stdout;
+
+ in = onig_get_callout_in_by_callout_args(args);
+
+ r = onig_get_arg_by_callout_args(args, 1, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ if (in == ONIG_CALLOUT_IN_PROGRESS) {
+ if (val.c == '<')
+ return ONIG_CALLOUT_SUCCESS;
+ }
+ else {
+ if (val.c != 'X' && val.c != '<')
+ return ONIG_CALLOUT_SUCCESS;
+ }
+
+ r = onig_get_arg_by_callout_args(args, 0, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+
+ fprintf(fp, "%s %s\n",
+ (in == ONIG_CALLOUT_IN_PROGRESS ? "=>" : "<="),
+ val.s.start);
+ fflush(fp);
+
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+
+static int
+test(OnigEncoding enc, char* in_pattern, char* in_str)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ UChar* pattern;
+ UChar* str;
+
+ pattern = (UChar* )in_pattern;
+ str = (UChar* )in_str;
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "COMPILE ERROR: %d: %s\n", r, s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "SEARCH ERROR: %d: %s\n", r, s);
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return r;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ int id;
+ UChar* name;
+ OnigEncoding use_encs[1];
+ OnigType arg_types[4];
+ OnigValue opt_defaults[4];
+ OnigEncoding enc;
+
+ enc = ONIG_ENCODING_UTF8;
+ use_encs[0] = enc;
+
+ r = onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+ if (r != ONIG_NORMAL) return -1;
+
+ name = (UChar* )"echo";
+ arg_types[0] = ONIG_TYPE_STRING;
+ arg_types[1] = ONIG_TYPE_CHAR;
+ opt_defaults[0].s.start = (UChar* )"echo";
+ opt_defaults[0].s.end = opt_defaults[0].s.start +
+ strlen((char* )opt_defaults[0].s.start);
+ opt_defaults[1].c = '>';
+
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,
+ name, name + strlen((char* )name),
+ ONIG_CALLOUT_IN_BOTH, echo, 0,
+ 2, arg_types, 2, opt_defaults);
+ if (id < 0) {
+ fprintf(stderr, "ERROR: fail to set callout of name: %s\n", name);
+ return -1;
+ }
+
+ test(enc, "(?:(*echo{abc!!!})a|b)*", "abba");
+ test(enc, "(?:(*echo{xyz,X})a|b)*", "abba");
+
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/encode.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/encode.c
new file mode 100644
index 000000000..c5d4771b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/encode.c
@@ -0,0 +1,212 @@
+/*
+ * encode.c
+ */
+#include <stdio.h>
+#include "oniguruma.h"
+
+static int
+search(regex_t* reg, unsigned char* str, unsigned char* end)
+{
+ int r;
+ unsigned char *start, *range;
+ OnigRegion *region;
+
+ region = onig_region_new();
+
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d (%s)\n", r,
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail (%s)\n",
+ ONIGENC_NAME(onig_get_encoding(reg)));
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ fprintf(stderr, " (%s)\n", ONIGENC_NAME(onig_get_encoding(reg)));
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return 0;
+}
+
+static int
+exec(OnigEncoding enc, OnigOptionType options,
+ char* apattern, char* astr)
+{
+ int r;
+ unsigned char *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+
+ onig_initialize(&enc, 1);
+
+ r = onig_new(&reg, pattern,
+ pattern + onigenc_str_bytelen_null(enc, pattern),
+ options, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ end = str + onigenc_str_bytelen_null(enc, str);
+ r = search(reg, str, end);
+
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ /* ISO 8859-1 test */
+ static unsigned char str[] = { 0xc7, 0xd6, 0xfe, 0xea, 0xe0, 0xe2, 0x00 };
+ static unsigned char pattern[] = { 0xe7, 0xf6, 0xde, '\\', 'w', '+', 0x00 };
+
+ r = exec(ONIG_ENCODING_SJIS, ONIG_OPTION_NONE,
+ "^a\\p{Hiragana}c$", "a\202\274c");
+
+ r = exec(ONIG_ENCODING_EUC_JP, ONIG_OPTION_NONE,
+ "^a\\p{Hiragana}c$", "a\244\276c");
+
+ r = exec(ONIG_ENCODING_CP1251, ONIG_OPTION_IGNORECASE,
+ "aBc", " AbC");
+
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ " [a-c\337z] ", " SS ");
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ " [\330-\341] ", " SS ");
+
+ r = exec(ONIG_ENCODING_ISO_8859_2, ONIG_OPTION_IGNORECASE,
+ "\337 ", " Ss ");
+ r = exec(ONIG_ENCODING_ISO_8859_2, ONIG_OPTION_IGNORECASE,
+ "SS ", " \337 ");
+ r = exec(ONIG_ENCODING_ISO_8859_2, ONIG_OPTION_IGNORECASE,
+ "\\A\\S\\z", "ss");
+
+ r = exec(ONIG_ENCODING_ISO_8859_2, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+
+ r = exec(ONIG_ENCODING_ISO_8859_3, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_4, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_5, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_6, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_7, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_8, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_9, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_10, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_11, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_13, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_14, ONIG_OPTION_IGNORECASE,
+ "[ac]+", "bbbaAaCCC");
+ r = exec(ONIG_ENCODING_ISO_8859_15, ONIG_OPTION_IGNORECASE,
+ (char* )pattern, (char* )str);
+ r = exec(ONIG_ENCODING_ISO_8859_16, ONIG_OPTION_IGNORECASE,
+ (char* )pattern, (char* )str);
+
+ r = exec(ONIG_ENCODING_KOI8_R, ONIG_OPTION_NONE, "a+", "bbbaaaccc");
+ r = exec(ONIG_ENCODING_EUC_TW, ONIG_OPTION_NONE, "b*a+?c+", "bbbaaaccc");
+ r = exec(ONIG_ENCODING_EUC_KR, ONIG_OPTION_NONE, "a+", "bbbaaaccc");
+ r = exec(ONIG_ENCODING_EUC_CN, ONIG_OPTION_NONE, "c+", "bbbaaaccc");
+ r = exec(ONIG_ENCODING_BIG5, ONIG_OPTION_NONE, "a+", "bbbaaaccc");
+
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ "\337", "SS");
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ "SS", "\337");
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ "SSb\337ssc", "a\337bSS\337cd");
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ "[a\337]{0,2}", "aSS");
+ r = exec(ONIG_ENCODING_ISO_8859_1, ONIG_OPTION_IGNORECASE,
+ "is", "iss");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_NONE,
+ "\000[\000[\000:\000a\000l\000n\000u\000m\000:\000]\000]\000+\000\000",
+ "\000#\002\120\000a\000Z\012\077\012\076\012\075\000\000");
+ /* 0x0a3d == \012\075 : is not alnum */
+ /* 0x0a3e == \012\076 : is alnum */
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_NONE,
+ "\000\\\000d\000+\000\000",
+ "\0003\0001\377\020\377\031\377\032\000\000");
+
+ r = exec(ONIG_ENCODING_GB18030, ONIG_OPTION_IGNORECASE,
+ "(Aa\\d)+", "BaA5Aa0234");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000[\000\337\000]\000\000", "\000S\000S\000\000");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000[\000\337\000]\000\000", "\000s\000S\000\000");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000^\000[\000\001\000-\377\375\000]\000$\000\000",
+ "\000s\000S\000\000");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000S\000S\000\000",
+ "\000S\000T\000\337\000\000");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000S\000T\000S\000S\000\000",
+ "\000S\000t\000s\000S\000\000");
+
+ {
+ UChar pat[] = { 0x1f, 0xfc, 0x00, 0x00 };
+ UChar str1[] = { 0x21, 0x26, 0x1f, 0xbe, 0x00, 0x00 };
+ UChar str2[] = { 0x1f, 0xf3, 0x00, 0x00 };
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ (char* )pat, (char* )str1);
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ (char* )pat, (char* )str2);
+ }
+
+#if 0
+ /* You should define USE_UNICODE_CASE_FOLD_TURKISH_AZERI in regenc.h. */
+
+ set_case_fold(ONIGENC_CASE_FOLD_TURKISH_AZERI);
+
+ r = exec(ONIG_ENCODING_UTF8, ONIG_ENCODING_UTF8, ONIG_OPTION_IGNORECASE,
+ "Ii", "\304\261\304\260");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\000I\000i\000\000", "\001\061\001\060\000\000");
+
+ r = exec(ONIG_ENCODING_UTF16_BE, ONIG_OPTION_IGNORECASE,
+ "\001\061\001\060\000\000", "\000I\000i\000\000");
+
+ set_case_fold(ONIGENC_CASE_FOLD_MIN);
+#endif
+
+ return r;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/listcap.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/listcap.c
new file mode 100644
index 000000000..c0d3014d6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/listcap.c
@@ -0,0 +1,118 @@
+/*
+ * listcap.c
+ *
+ * capture history (?@...) sample.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+static int
+node_callback(int group, int beg, int end, int level, int at, void* arg)
+{
+ int i;
+
+ if (at != ONIG_TRAVERSE_CALLBACK_AT_FIRST)
+ return -1; /* error */
+
+ /* indent */
+ for (i = 0; i < level * 2; i++)
+ fputc(' ', stderr);
+
+ fprintf(stderr, "%d: (%d-%d)\n", group, beg, end);
+ return 0;
+}
+
+extern int ex(unsigned char* str, unsigned char* pattern,
+ OnigSyntaxType* syntax, OnigOptionType options)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ options, ONIG_ENCODING_ASCII, syntax, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ fprintf(stderr, "number of captures: %d\n", onig_number_of_captures(reg));
+ fprintf(stderr, "number of capture histories: %d\n",
+ onig_number_of_capture_histories(reg));
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ fprintf(stderr, "\n");
+
+ r = onig_capture_tree_traverse(region, ONIG_TRAVERSE_CALLBACK_AT_FIRST,
+ node_callback, (void* )0);
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return 0;
+}
+
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ OnigSyntaxType syn;
+ OnigEncoding use_encs[1];
+
+ static UChar* str1 = (UChar* )"((())())";
+ static UChar* pattern1
+ = (UChar* )"\\g<p>(?@<p>\\(\\g<s>\\)){0}(?@<s>(?:\\g<p>)*|){0}";
+
+ static UChar* str2 = (UChar* )"x00x00x00";
+ static UChar* pattern2 = (UChar* )"(?@x(?@\\d+))+";
+
+ static UChar* str3 = (UChar* )"0123";
+ static UChar* pattern3 = (UChar* )"(?@.)(?@.)(?@.)(?@.)";
+
+ static UChar* str4 = (UChar* )"(((a))(a)) ((((a))(a)))";
+ static UChar* pattern4
+ = (UChar* )"\\g<p>(?@<p>\\(\\g<s>\\)){0}(?@<s>(?:\\g<p>)*|a){0}";
+
+ use_encs[0] = ONIG_ENCODING_ASCII;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ /* enable capture hostory */
+ onig_copy_syntax(&syn, ONIG_SYNTAX_DEFAULT);
+ onig_set_syntax_op2(&syn,
+ onig_get_syntax_op2(&syn) | ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY);
+
+ r = ex(str1, pattern1, &syn, ONIG_OPTION_NONE);
+ r = ex(str2, pattern2, &syn, ONIG_OPTION_NONE);
+ r = ex(str3, pattern3, &syn, ONIG_OPTION_NONE);
+ r = ex(str4, pattern4, &syn, ONIG_OPTION_FIND_LONGEST);
+
+ onig_end();
+ return r;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/names.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/names.c
new file mode 100644
index 000000000..bf47f6346
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/names.c
@@ -0,0 +1,79 @@
+/*
+ * names.c -- example of group name callback.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+static int
+name_callback(const UChar* name, const UChar* name_end,
+ int ngroup_num, int* group_nums,
+ regex_t* reg, void* arg)
+{
+ int i, gn, ref;
+ char* s;
+ OnigRegion *region = (OnigRegion* )arg;
+
+ for (i = 0; i < ngroup_num; i++) {
+ gn = group_nums[i];
+ ref = onig_name_to_backref_number(reg, name, name_end, region);
+ s = (ref == gn ? "*" : "");
+ fprintf(stderr, "%s (%d): ", name, gn);
+ fprintf(stderr, "(%d-%d) %s\n", region->beg[gn], region->end[gn], s);
+ }
+ return 0; /* 0: continue */
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ OnigEncoding use_encs[1];
+
+ static UChar* pattern = (UChar* )"(?<foo>a*)(?<bar>b*)(?<foo>c*)";
+ static UChar* str = (UChar* )"aaabbbbcc";
+
+ use_encs[0] = ONIG_ENCODING_ASCII;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ fprintf(stderr, "number of names: %d\n", onig_number_of_names(reg));
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ fprintf(stderr, "match at %d\n\n", r);
+ r = onig_foreach_name(reg, name_callback, (void* )region);
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/posix.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/posix.c
new file mode 100644
index 000000000..c5559362e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/posix.c
@@ -0,0 +1,107 @@
+/*
+ * posix.c
+ */
+#include <stdio.h>
+#include "onigposix.h"
+
+typedef unsigned char UChar;
+
+static int x(regex_t* reg, unsigned char* pattern, unsigned char* str)
+{
+ int r, i;
+ char buf[200];
+ regmatch_t pmatch[20];
+
+ r = regexec(reg, (char* )str, reg->re_nsub + 1, pmatch, 0);
+ if (r != 0 && r != REG_NOMATCH) {
+ regerror(r, reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(reg);
+ return -1;
+ }
+
+ if (r == REG_NOMATCH) {
+ fprintf(stderr, "FAIL: /%s/ '%s'\n", pattern, str);
+ }
+ else {
+ fprintf(stderr, "OK: /%s/ '%s'\n", pattern, str);
+ for (i = 0; i <= (int )reg->re_nsub; i++) {
+ fprintf(stderr, "%d: %d-%d\n", i, pmatch[i].rm_so, pmatch[i].rm_eo);
+ }
+ }
+ regfree(reg);
+ return 0;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ char buf[200];
+ regex_t reg;
+ UChar* pattern;
+
+ reg_set_encoding(REG_POSIX_ENCODING_ASCII);
+
+ /* default syntax (ONIG_SYNTAX_ONIGURUMA) */
+ pattern = (UChar* )"^a+b{2,7}[c-f]?$|uuu";
+ r = regcomp(&reg, (char* )pattern, REG_EXTENDED);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(&reg);
+ onig_end();
+ return -1;
+ }
+ x(&reg, pattern, (UChar* )"aaabbbbd");
+
+ /* POSIX Basic RE (REG_EXTENDED is not specified.) */
+ pattern = (UChar* )"^a+b{2,7}[c-f]?|uuu";
+ r = regcomp(&reg, (char* )pattern, 0);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(&reg);
+ onig_end();
+ return -1;
+ }
+ x(&reg, pattern, (UChar* )"a+b{2,7}d?|uuu");
+
+ /* POSIX Basic RE (REG_EXTENDED is not specified.) */
+ pattern = (UChar* )"^a*b\\{2,7\\}\\([c-f]\\)$";
+ r = regcomp(&reg, (char* )pattern, 0);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(&reg);
+ onig_end();
+ return -1;
+ }
+ x(&reg, pattern, (UChar* )"aaaabbbbbbd");
+
+ /* POSIX Extended RE */
+ onig_set_default_syntax(ONIG_SYNTAX_POSIX_EXTENDED);
+ pattern = (UChar* )"^a+b{2,7}[c-f]?)$|uuu";
+ r = regcomp(&reg, (char* )pattern, REG_EXTENDED);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(&reg);
+ onig_end();
+ return -1;
+ }
+ x(&reg, pattern, (UChar* )"aaabbbbd)");
+
+ pattern = (UChar* )"^b.";
+ r = regcomp(&reg, (char* )pattern, REG_EXTENDED | REG_NEWLINE);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(stderr, "ERROR: %s\n", buf);
+ regfree(&reg);
+ onig_end();
+ return -1;
+ }
+ x(&reg, pattern, (UChar* )"a\nb\n");
+
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/regset.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/regset.c
new file mode 100644
index 000000000..6be511a6e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/regset.c
@@ -0,0 +1,95 @@
+/*
+ * regset.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ int i, n;
+ int match_pos;
+ unsigned char *start, *range, *end;
+ OnigRegSet* set;
+ OnigRegSetLead lead;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ char ebuf[ONIG_MAX_ERROR_MESSAGE_LEN];
+ OnigEncoding use_encs[1];
+
+ static UChar* str = (UChar* )"aaaaaaaaaaaaaaaaaaaaaaca";
+
+ static char* pat[] = {
+ "a(.*)b|a(.)c",
+ "^(abc)",
+ "a(.....)c"
+ };
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ r = onig_regset_new(&set, 0, NULL);
+ if (r != ONIG_NORMAL) {
+ onig_error_code_to_str((UChar* )ebuf, r);
+ fprintf(stderr, "ERROR: %s\n", ebuf);
+ onig_end();
+ return -1;
+ }
+
+ n = sizeof(pat) / sizeof(pat[0]);
+
+ for (i = 0; i < n; i++) {
+ r = onig_new(&reg, (UChar* )pat[i], (UChar* )(pat[i] + strlen(pat[i])),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT,
+ &einfo);
+ if (r != ONIG_NORMAL) {
+ onig_error_code_to_str((UChar* )ebuf, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", ebuf);
+ onig_regset_free(set);
+ onig_end();
+ return -1;
+ }
+
+ r = onig_regset_add(set, reg);
+ if (r != ONIG_NORMAL) {
+ onig_free(reg);
+ onig_regset_free(set);
+ onig_end();
+ return -1;
+ }
+ }
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ lead = ONIG_REGSET_POSITION_LEAD;
+ //lead = ONIG_REGSET_PRIORITY_TO_REGEX_ORDER;
+ r = onig_regset_search(set, str, end, start, range, lead, ONIG_OPTION_NONE,
+ &match_pos);
+ if (r >= 0) {
+ OnigRegion *region;
+
+ fprintf(stderr, "match regex index: %d\n", r);
+ fprintf(stderr, "match position: %d\n", match_pos);
+
+ region = onig_regset_get_region(set, r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ onig_error_code_to_str((UChar* )ebuf, r);
+ fprintf(stderr, "ERROR: %s\n", ebuf);
+ onig_regset_free(set);
+ onig_end();
+ return -1;
+ }
+
+ onig_regset_free(set);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/scan.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/scan.c
new file mode 100644
index 000000000..4039e46db
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/scan.c
@@ -0,0 +1,90 @@
+/*
+ * scan.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "oniguruma.h"
+
+static int
+scan_callback(int n, int r, OnigRegion* region, void* arg)
+{
+ int i;
+
+ fprintf(stdout, "scan: %d\n", n);
+
+ fprintf(stdout, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stdout, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+
+ return 0;
+}
+
+static int
+scan(regex_t* reg, unsigned char* str, unsigned char* end)
+{
+ int r;
+ OnigRegion *region;
+
+ region = onig_region_new();
+
+ r = onig_scan(reg, str, end, region, ONIG_OPTION_NONE, scan_callback, NULL);
+ if (r >= 0) {
+ fprintf(stdout, "total: %d match\n", r);
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((OnigUChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ return 0;
+}
+
+static int
+exec(OnigEncoding enc, OnigOptionType options, char* apattern, char* astr)
+{
+ int r;
+ unsigned char *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ UChar* pattern_end;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+
+ onig_initialize(&enc, 1);
+
+ pattern_end = pattern + onigenc_str_bytelen_null(enc, pattern);
+
+ r = onig_new(&reg, pattern, pattern_end, options, enc, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((OnigUChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_end();
+ return -1;
+ }
+
+ end = str + onigenc_str_bytelen_null(enc, str);
+ r = scan(reg, str, end);
+
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
+
+
+extern int main(int argc, char* argv[])
+{
+ exec(ONIG_ENCODING_UTF8, ONIG_OPTION_NONE,
+ "\\Ga+\\s*", "a aa aaa baaa");
+
+ fprintf(stdout, "\n");
+ exec(ONIG_ENCODING_UTF8, ONIG_OPTION_NONE,
+ "a+\\s*", "a aa aaa baaa");
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/simple.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/simple.c
new file mode 100644
index 000000000..a08ea86d3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/simple.c
@@ -0,0 +1,63 @@
+/*
+ * simple.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ OnigEncoding use_encs[1];
+
+ static UChar* pattern = (UChar* )"a(.*)b|[e-f]+";
+ static UChar* str = (UChar* )"zzzzaffffffffb";
+
+ use_encs[0] = ONIG_ENCODING_ASCII;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/sql.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/sql.c
new file mode 100644
index 000000000..21147aa13
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/sql.c
@@ -0,0 +1,81 @@
+/*
+ * sql.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+extern int main(int argc, char* argv[])
+{
+ static OnigSyntaxType SQLSyntax;
+
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ OnigEncoding use_encs[1];
+
+ static UChar* pattern = (UChar* )"\\_%\\\\__zz";
+ static UChar* str = (UChar* )"a_abcabcabc\\ppzz";
+
+ use_encs[0] = ONIG_ENCODING_ASCII;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ onig_set_syntax_op (&SQLSyntax, ONIG_SYN_OP_VARIABLE_META_CHARACTERS);
+ onig_set_syntax_op2 (&SQLSyntax, 0);
+ onig_set_syntax_behavior(&SQLSyntax, 0);
+ onig_set_syntax_options (&SQLSyntax, ONIG_OPTION_MULTILINE);
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ESCAPE, (OnigCodePoint )'\\');
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ANYCHAR, (OnigCodePoint )'_');
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ANYTIME,
+ ONIG_INEFFECTIVE_META_CHAR);
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ZERO_OR_ONE_TIME,
+ ONIG_INEFFECTIVE_META_CHAR);
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ONE_OR_MORE_TIME,
+ ONIG_INEFFECTIVE_META_CHAR);
+ onig_set_meta_char(&SQLSyntax, ONIG_META_CHAR_ANYCHAR_ANYTIME,
+ (OnigCodePoint )'%');
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, &SQLSyntax, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_end();
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/syntax.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/syntax.c
new file mode 100644
index 000000000..3a5a7cf13
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/syntax.c
@@ -0,0 +1,77 @@
+/*
+ * syntax.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+extern int exec(OnigSyntaxType* syntax, char* apattern, char* astr)
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ UChar* pattern = (UChar* )apattern;
+ UChar* str = (UChar* )astr;
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, syntax, &einfo);
+ if (r != ONIG_NORMAL) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %s\n", s);
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ return 0;
+}
+
+extern int main(int argc, char* argv[])
+{
+ int r;
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_ASCII;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ r = exec(ONIG_SYNTAX_PERL,
+ "\\p{XDigit}\\P{XDigit}\\p{^XDigit}\\P{^XDigit}\\p{XDigit}",
+ "bgh3a");
+
+ r = exec(ONIG_SYNTAX_JAVA, "\\p{XDigit}\\P{XDigit}[a-c&&b-g]", "bgc");
+
+ r = exec(ONIG_SYNTAX_ASIS,
+ "abc def* e+ g?ddd[a-rvvv] (vv){3,7}hv\\dvv(?:aczui ss)\\W\\w$",
+ "abc def* e+ g?ddd[a-rvvv] (vv){3,7}hv\\dvv(?:aczui ss)\\W\\w$");
+ onig_end();
+ return r;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/user_property.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/user_property.c
new file mode 100644
index 000000000..ecb842c15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/sample/user_property.c
@@ -0,0 +1,92 @@
+/*
+ * user_property.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+extern int
+main(int argc, char* argv[])
+{
+ int r;
+ unsigned char *start, *range, *end;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+ OnigRegion *region;
+ OnigEncoding use_encs[1];
+
+ static OnigCodePoint handakuon_hiragana[] = {
+ 5, /* number of ranges */
+ 0x3071, 0x3071, /* PA */
+ 0x3074, 0x3074, /* PI */
+ 0x3077, 0x3077, /* PU */
+ 0x307a, 0x307a, /* PE */
+ 0x307d, 0x307d /* PO */
+ };
+
+ static UChar* pattern = (UChar* )"\\A(\\p{HandakuonHiragana}{5})\\p{^HandakuonHiragana}\\z";
+ //static UChar* pattern = (UChar* )"\\p{Handakuon_Hiragana}{5}\\P{Handakuon Hiragana}";
+
+ /* "PA PI PU PE PO a" */
+ static UChar* str = (UChar* )"\343\201\261\343\201\264\343\201\267\343\201\272\343\201\275a";
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ r = onig_unicode_define_user_property("HandakuonHiragana", handakuon_hiragana);
+ if (r == ONIG_NORMAL) {
+ fprintf(stdout, "define HandakuonHiragana\n");
+ }
+ else {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_end();
+ return -1;
+ }
+
+ r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r == ONIG_NORMAL) {
+ fprintf(stdout, "onig_new: success.\n");
+ }
+ else {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "onig_new: ERROR: %s\n", s);
+ onig_end();
+ return -1;
+ }
+
+ region = onig_region_new();
+
+ end = str + strlen((char* )str);
+ start = str;
+ range = end;
+ r = onig_search(reg, str, end, start, range, region, ONIG_OPTION_NONE);
+ if (r >= 0) {
+ int i;
+
+ fprintf(stderr, "match at %d\n", r);
+ for (i = 0; i < region->num_regs; i++) {
+ fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ fprintf(stderr, "search fail\n");
+ }
+ else { /* error */
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(stderr, "ERROR: %s\n", s);
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return -1;
+ }
+
+ onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
+ onig_free(reg);
+ onig_end();
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.am b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.am
new file mode 100644
index 000000000..1600311f0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.am
@@ -0,0 +1,69 @@
+## Makefile.am for Oniguruma
+libname = libonig.la
+
+AM_CFLAGS = -Wall
+AM_CPPFLAGS = -I$(top_srcdir)
+
+include_HEADERS = oniguruma.h oniggnu.h
+
+posix_headers = onigposix.h
+
+if ENABLE_POSIX_API
+posix_sources = regposix.c regposerr.c
+include_HEADERS += $(posix_headers)
+else
+posix_sources =
+endif
+
+
+lib_LTLIBRARIES = $(libname)
+
+libonig_la_SOURCES = regint.h regparse.h regenc.h st.h \
+ regparse.c regcomp.c regexec.c \
+ regenc.c regerror.c regext.c regsyntax.c regtrav.c regversion.c st.c \
+ reggnu.c \
+ $(posix_sources) \
+ unicode.c \
+ unicode_unfold_key.c \
+ unicode_fold1_key.c \
+ unicode_fold2_key.c \
+ unicode_fold3_key.c \
+ ascii.c utf8.c \
+ utf16_be.c utf16_le.c \
+ utf32_be.c utf32_le.c \
+ euc_jp.c euc_jp_prop.c \
+ sjis.c sjis_prop.c \
+ iso8859_1.c \
+ iso8859_2.c iso8859_3.c \
+ iso8859_4.c iso8859_5.c \
+ iso8859_6.c iso8859_7.c \
+ iso8859_8.c iso8859_9.c \
+ iso8859_10.c iso8859_11.c \
+ iso8859_13.c iso8859_14.c \
+ iso8859_15.c iso8859_16.c \
+ euc_tw.c euc_kr.c big5.c \
+ gb18030.c koi8_r.c cp1251.c \
+ onig_init.c
+
+libonig_la_LDFLAGS = -version-info $(LTVERSION)
+
+EXTRA_DIST = koi8.c mktable.c \
+ unicode_fold_data.c unicode_property_data.c \
+ unicode_property_data_posix.c \
+ unicode_egcb_data.c unicode_wb_data.c \
+ make_unicode_egcb.sh make_unicode_egcb_data.py \
+ make_unicode_wb.sh make_unicode_wb_data.py \
+ make_unicode_fold.sh make_unicode_fold_data.py \
+ make_unicode_property.sh make_unicode_property_data.py \
+ make_property.sh \
+ gperf_fold_key_conv.py gperf_unfold_key_conv.py
+
+dll:
+ $(CXX) -shared -Wl,--output-def,libonig.def -o libonig.dll *.o \
+ $(LIBS)
+ strip libonig.dll
+
+
+# character-types-table source generator
+mktable: mktable.c regenc.h
+ $(CC) -I$(top_srcdir) -o mktable mktable.c
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.windows b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.windows
new file mode 100644
index 000000000..90ebf287e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/Makefile.windows
@@ -0,0 +1,189 @@
+# Oniguruma Makefile for Windows
+
+product_name = oniguruma
+
+TEST_DIR = $(ONIG_DIR)/../test
+WIN_DIR = $(ONIG_DIR)/../windows
+
+CPPFLAGS =
+CFLAGS = -O2 -nologo /W3
+LDFLAGS =
+LOADLIBES =
+ARLIB = lib
+ARLIB_FLAGS = -nologo
+ARDLL = cl
+ARDLL_FLAGS = -nologo -LD $(LINKFLAGS) -dll
+LINKFLAGS = -link -incremental:no -pdb:none
+
+INSTALL = install -c
+CP = copy
+CC = cl
+DEFS = -DHAVE_CONFIG_H
+
+subdirs =
+
+libbase = onig
+libname = $(libbase)_s.lib
+dllname = $(libbase).dll
+dlllib = $(libbase).lib
+
+!IF defined(ENABLE_POSIX_API) && "$(ENABLE_POSIX_API)" == "NO"
+posixobjs =
+!ELSE
+posixobjs = $(BUILD_DIR)/regposix.obj $(BUILD_DIR)/regposerr.obj
+!ENDIF
+
+onigheaders = $(ONIG_DIR)/oniguruma.h $(ONIG_DIR)/regint.h $(ONIG_DIR)/regparse.h $(ONIG_DIR)/regenc.h $(ONIG_DIR)/st.h
+posixheaders = $(ONIG_DIR)/onigposix.h
+headers = $(posixheaders) $(onigheaders)
+
+onigobjs = $(BUILD_DIR)/reggnu.obj $(BUILD_DIR)/regerror.obj $(BUILD_DIR)/regparse.obj $(BUILD_DIR)/regext.obj $(BUILD_DIR)/regcomp.obj \
+ $(BUILD_DIR)/regexec.obj $(BUILD_DIR)/regenc.obj $(BUILD_DIR)/regsyntax.obj $(BUILD_DIR)/regtrav.obj \
+ $(BUILD_DIR)/regversion.obj $(BUILD_DIR)/st.obj $(BUILD_DIR)/onig_init.obj
+libobjs = $(onigobjs) $(posixobjs)
+
+jp_objs = $(BUILD_DIR)/euc_jp.obj $(BUILD_DIR)/sjis.obj
+iso8859_objs = $(BUILD_DIR)/iso8859_1.obj $(BUILD_DIR)/iso8859_2.obj \
+ $(BUILD_DIR)/iso8859_3.obj $(BUILD_DIR)/iso8859_4.obj \
+ $(BUILD_DIR)/iso8859_5.obj $(BUILD_DIR)/iso8859_6.obj \
+ $(BUILD_DIR)/iso8859_7.obj $(BUILD_DIR)/iso8859_8.obj \
+ $(BUILD_DIR)/iso8859_9.obj $(BUILD_DIR)/iso8859_10.obj \
+ $(BUILD_DIR)/iso8859_11.obj $(BUILD_DIR)/iso8859_13.obj \
+ $(BUILD_DIR)/iso8859_14.obj $(BUILD_DIR)/iso8859_15.obj \
+ $(BUILD_DIR)/iso8859_16.obj
+
+encobjs = $(BUILD_DIR)/ascii.obj $(BUILD_DIR)/utf8.obj \
+ $(BUILD_DIR)/unicode.obj \
+ $(BUILD_DIR)/utf16_be.obj $(BUILD_DIR)/utf16_le.obj \
+ $(BUILD_DIR)/utf32_be.obj $(BUILD_DIR)/utf32_le.obj \
+ $(jp_objs) $(iso8859_objs) \
+ $(BUILD_DIR)/euc_tw.obj $(BUILD_DIR)/euc_kr.obj $(BUILD_DIR)/big5.obj \
+ $(BUILD_DIR)/gb18030.obj \
+ $(BUILD_DIR)/koi8_r.obj \
+ $(BUILD_DIR)/cp1251.obj \
+ $(BUILD_DIR)/euc_jp_prop.obj $(BUILD_DIR)/sjis_prop.obj \
+ $(BUILD_DIR)/unicode_unfold_key.obj $(BUILD_DIR)/unicode_fold1_key.obj \
+ $(BUILD_DIR)/unicode_fold2_key.obj $(BUILD_DIR)/unicode_fold3_key.obj # $(BUILD_DIR)/koi8.obj
+
+onigsources = $(ONIG_DIR)/regerror.c $(ONIG_DIR)/regparse.c $(ONIG_DIR)/regext.c $(ONIG_DIR)/regcomp.c $(ONIG_DIR)/regexec.c $(ONIG_DIR)/regenc.c \
+ $(ONIG_DIR)/regsyntax.c $(ONIG_DIR)/regtrav.c $(ONIG_DIR)/regversion.c $(ONIG_DIR)/reggnu.c $(ONIG_DIR)/st.c
+posixsources = $(ONIG_DIR)/regposix.c $(ONIG_DIR)/regposerr.c
+libsources = $(posixsources) $(onigsources)
+
+patchfiles = re.c.168.patch re.c.181.patch
+distfiles = README COPYING HISTORY \
+ Makefile.in configure.in config.h.in configure \
+ $(headers) $(libsources) $(patchfiles) \
+ test.rb testconv.rb
+testc = testc
+testp = testp
+
+makeargs = $(MFLAGS) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' CC='$(CC)'
+
+.SUFFIXES:
+.SUFFIXES: .obj .c .h .ps .dvi .info .texinfo
+
+{$(ONIG_DIR)}.c{$(BUILD_DIR)}.obj:
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) /I. /I.. /Fo$@ /c $<
+
+# targets
+default: all
+
+setup:
+ $(CP) ..\win32\config.h config.h
+ $(CP) ..\win32\testc.c testc.c
+
+
+all: $(libname) $(dllname)
+
+$(libname): $(libobjs) $(encobjs)
+ $(ARLIB) $(ARLIB_FLAGS) -out:$@ $(libobjs) $(encobjs)
+
+$(dllname): $(libobjs) $(encobjs)
+ $(ARDLL) $(libobjs) $(encobjs) -Fe$@ $(ARDLL_FLAGS)
+
+$(BUILD_DIR)/regparse.obj: $(ONIG_DIR)/regparse.c $(onigheaders) $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regext.obj: $(ONIG_DIR)/regext.c $(onigheaders) $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regtrav.obj: $(ONIG_DIR)/regtrav.c $(onigheaders) $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regcomp.obj: $(ONIG_DIR)/regcomp.c $(onigheaders) $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regexec.obj: $(ONIG_DIR)/regexec.c $(ONIG_DIR)/regint.h $(ONIG_DIR)/regenc.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/reggnu.obj: $(ONIG_DIR)/reggnu.c $(ONIG_DIR)/regint.h $(ONIG_DIR)/regenc.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h $(ONIG_DIR)/oniggnu.h
+$(BUILD_DIR)/regerror.obj: $(ONIG_DIR)/regerror.c $(ONIG_DIR)/regint.h $(ONIG_DIR)/regenc.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regenc.obj: $(ONIG_DIR)/regenc.c $(ONIG_DIR)/regenc.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regsyntax.obj: $(ONIG_DIR)/regsyntax.c $(ONIG_DIR)/regint.h $(ONIG_DIR)/regenc.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regversion.obj: $(ONIG_DIR)/regversion.c $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regposix.obj: $(ONIG_DIR)/regposix.c $(posixheaders) $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/regposerr.obj: $(ONIG_DIR)/regposerr.c $(posixheaders) $(BUILD_DIR)/config.h
+$(BUILD_DIR)/st.obj: $(ONIG_DIR)/st.c $(ONIG_DIR)/regint.h $(ONIG_DIR)/oniguruma.h $(BUILD_DIR)/config.h $(ONIG_DIR)/st.h
+$(BUILD_DIR)/onig_init.obj: $(ONIG_DIR)/onig_init.c $(ONIG_DIR)/oniguruma.h
+
+$(BUILD_DIR)/ascii.obj: $(ONIG_DIR)/ascii.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/unicode.obj: $(ONIG_DIR)/unicode.c $(ONIG_DIR)/unicode_fold_data.c $(ONIG_DIR)/unicode_property_data.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/utf8.obj: $(ONIG_DIR)/utf8.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/utf16_be.obj: $(ONIG_DIR)/utf16_be.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/utf16_le.obj: $(ONIG_DIR)/utf16_le.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/utf32_be.obj: $(ONIG_DIR)/utf32_be.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/utf32_le.obj: $(ONIG_DIR)/utf32_le.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/euc_jp.obj: $(ONIG_DIR)/euc_jp.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/euc_tw.obj: $(ONIG_DIR)/euc_tw.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/euc_kr.obj: $(ONIG_DIR)/euc_kr.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/sjis.obj: $(ONIG_DIR)/sjis.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_1.obj: $(ONIG_DIR)/iso8859_1.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_2.obj: $(ONIG_DIR)/iso8859_2.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_3.obj: $(ONIG_DIR)/iso8859_3.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_4.obj: $(ONIG_DIR)/iso8859_4.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_5.obj: $(ONIG_DIR)/iso8859_5.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_6.obj: $(ONIG_DIR)/iso8859_6.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_7.obj: $(ONIG_DIR)/iso8859_7.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_8.obj: $(ONIG_DIR)/iso8859_8.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_9.obj: $(ONIG_DIR)/iso8859_9.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_10.obj: $(ONIG_DIR)/iso8859_10.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_11.obj: $(ONIG_DIR)/iso8859_11.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_13.obj: $(ONIG_DIR)/iso8859_13.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_14.obj: $(ONIG_DIR)/iso8859_14.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_15.obj: $(ONIG_DIR)/iso8859_15.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/iso8859_16.obj: $(ONIG_DIR)/iso8859_16.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/koi8.obj: $(ONIG_DIR)/koi8.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/koi8_r.obj: $(ONIG_DIR)/koi8_r.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/cp1251.obj: $(ONIG_DIR)/cp1251.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/big5.obj: $(ONIG_DIR)/big5.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/gb18030.obj: $(ONIG_DIR)/gb18030.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/euc_jp_prop.obj: $(ONIG_DIR)/euc_jp_prop.c $(ONIG_DIR)/regenc.h
+$(BUILD_DIR)/sjis_prop.obj: $(ONIG_DIR)/sjis_prop.c $(ONIG_DIR)/regenc.h
+$(BUILD_DIR)/unicode_unfold_key.obj: $(ONIG_DIR)/unicode_unfold_key.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/unicode_fold1_key.obj: $(ONIG_DIR)/unicode_fold1_key.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/unicode_fold2_key.obj: $(ONIG_DIR)/unicode_fold2_key.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+$(BUILD_DIR)/unicode_fold3_key.obj: $(ONIG_DIR)/unicode_fold3_key.c $(ONIG_DIR)/regenc.h $(BUILD_DIR)/config.h
+
+all-test: test_syntax test_regset test_utf8 testc testp testu
+
+test_syntax: $(TEST_DIR)/test_syntax.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern /utf-8 $(TEST_DIR)/test_syntax.c $(libname)
+
+test_regset: $(TEST_DIR)/test_regset.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern /utf-8 $(TEST_DIR)/test_regset.c $(libname)
+
+test_utf8: $(TEST_DIR)/test_utf8.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern /utf-8 $(TEST_DIR)/test_utf8.c $(libname)
+
+testc: $(WIN_DIR)/testc.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern $(WIN_DIR)/testc.c $(libname)
+
+testp: $(WIN_DIR)/testc.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern /DPOSIX_TEST $(WIN_DIR)/testc.c $(libname)
+
+testu: $(TEST_DIR)/testu.c $(libname)
+ $(CC) -nologo /Fe:$@ /I. /I$(ONIG_DIR) /DONIG_EXTERN=extern $(TEST_DIR)/testu.c $(libname)
+
+clean:
+ del $(BUILD_DIR)\*.obj $(BUILD_DIR)\*.lib $(BUILD_DIR)\*.exp $(BUILD_DIR)\*.dll $(BUILD_DIR)\test_regset.exe $(BUILD_DIR)\test_syntax.exe $(BUILD_DIR)\test_utf8.exe $(BUILD_DIR)\testp.exe $(BUILD_DIR)\testc.exe $(BUILD_DIR)\testu.exe
+
+
+samples: all
+ $(CC) $(CFLAGS) -I. /Fe:simple $(ONIG_DIR)\sample\simple.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:posix $(ONIG_DIR)\sample\posix.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:names $(ONIG_DIR)\sample\names.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:listcap $(ONIG_DIR)\sample\listcap.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:sql $(ONIG_DIR)\sample\sql.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:encode $(ONIG_DIR)\sample\encode.c $(dlllib)
+ $(CC) $(CFLAGS) -I. /Fe:syntax $(ONIG_DIR)\sample\syntax.c $(dlllib)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/ascii.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/ascii.c
new file mode 100644
index 000000000..f2dc0d316
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/ascii.c
@@ -0,0 +1,118 @@
+/**********************************************************************
+ ascii.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h" /* for USE_CALLOUT */
+
+static int
+init(void)
+{
+#ifdef USE_CALLOUT
+
+ int id;
+ OnigEncoding enc;
+ char* name;
+ unsigned int args[4];
+ OnigValue opts[4];
+
+ enc = ONIG_ENCODING_ASCII;
+
+ name = "FAIL"; BC0_P(name, fail);
+ name = "MISMATCH"; BC0_P(name, mismatch);
+
+ name = "MAX";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_CHAR;
+ opts[0].c = 'X';
+ BC_B_O(name, max, 2, args, 1, opts);
+
+ name = "ERROR";
+ args[0] = ONIG_TYPE_LONG; opts[0].l = ONIG_ABORT;
+ BC_P_O(name, error, 1, args, 1, opts);
+
+ name = "COUNT";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, count, 1, args, 1, opts);
+
+ name = "TOTAL_COUNT";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, total_count, 1, args, 1, opts);
+
+ name = "CMP";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_STRING;
+ args[2] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ BC_P(name, cmp, 3, args);
+
+#endif /* USE_CALLOUT */
+
+ return ONIG_NORMAL;
+}
+
+#if 0
+static int
+is_initialized(void)
+{
+ /* Don't use this function */
+ /* can't answer, because builtin callout entries removed in onig_end() */
+ return 0;
+}
+#endif
+
+static int
+ascii_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 128)
+ return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingASCII = {
+ onigenc_single_byte_mbc_enc_len,
+ "US-ASCII", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ onigenc_ascii_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ ascii_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ init,
+ 0, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/big5.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/big5.c
new file mode 100644
index 000000000..79ae1e343
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/big5.c
@@ -0,0 +1,193 @@
+/**********************************************************************
+ big5.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+static const int EncLen_BIG5[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1
+};
+
+static int
+big5_mbc_enc_len(const UChar* p)
+{
+ return EncLen_BIG5[*p];
+}
+
+static int
+big5_code_to_mbclen(OnigCodePoint code)
+{
+ if ((code & (~0xffff)) != 0) return ONIGERR_INVALID_CODE_POINT_VALUE;
+ if ((code & 0xff00) != 0) return 2;
+ if (EncLen_BIG5[(int )(code & 0xff)] == 1) return 1;
+
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p < 0xa1) {
+ return FALSE;
+ }
+ else if (*p < 0xff) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x40) return FALSE;
+ if (*p > 0x7e && *p < 0xa1) return FALSE;
+ if (*p == 0xff) return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+big5_mbc_to_code(const UChar* p, const UChar* end)
+{
+ return onigenc_mbn_mbc_to_code(ONIG_ENCODING_BIG5, p, end);
+}
+
+static int
+big5_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ return onigenc_mb2_code_to_mbc(ONIG_ENCODING_BIG5, code, buf);
+}
+
+static int
+big5_mbc_case_fold(OnigCaseFoldType flag, const UChar** pp, const UChar* end,
+ UChar* lower)
+{
+ return onigenc_mbn_mbc_case_fold(ONIG_ENCODING_BIG5, flag,
+ pp, end, lower);
+}
+
+static int
+big5_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ return onigenc_mb2_is_code_ctype(ONIG_ENCODING_BIG5, code, ctype);
+}
+
+static const char BIG5_CAN_BE_TRAIL_TABLE[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
+};
+
+#define BIG5_ISMB_FIRST(byte) (EncLen_BIG5[byte] > 1)
+#define BIG5_ISMB_TRAIL(byte) BIG5_CAN_BE_TRAIL_TABLE[(byte)]
+
+static UChar*
+big5_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ const UChar *p;
+ int len;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ if (BIG5_ISMB_TRAIL(*p)) {
+ while (p > start) {
+ if (! BIG5_ISMB_FIRST(*--p)) {
+ p++;
+ break;
+ }
+ }
+ }
+ len = enclen(ONIG_ENCODING_BIG5, p);
+ if (p + len > s) return (UChar* )p;
+ p += len;
+ return (UChar* )(p + ((s - p) & ~1));
+}
+
+static int
+big5_is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ const UChar c = *s;
+
+ return (BIG5_ISMB_TRAIL(c) ? FALSE : TRUE);
+}
+
+OnigEncodingType OnigEncodingBIG5 = {
+ big5_mbc_enc_len,
+ "Big5", /* name */
+ 2, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ big5_mbc_to_code,
+ big5_code_to_mbclen,
+ big5_code_to_mbc,
+ big5_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ big5_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ big5_left_adjust_char_head,
+ big5_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.cmake.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.cmake.in
new file mode 100644
index 000000000..60db86cb5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.cmake.in
@@ -0,0 +1,50 @@
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#cmakedefine CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#cmakedefine C_ALLOCA
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#cmakedefine HAVE_ALLOCA ${HAVE_ALLOCA}
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#cmakedefine HAVE_SYS_TIMES_H ${HAVE_SYS_TIMES_H}
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H}
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
+
+/* Name of package */
+#cmakedefine PACKAGE ${PACKAGE}
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
+
+/* The size of `int', as computed by sizeof. */
+#cmakedefine SIZEOF_INT ${SIZEOF_INT}
+
+/* The size of `long', as computed by sizeof. */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* Define if enable CR+NL as line terminator */
+#cmakedefine USE_CRNL_AS_LINE_TERMINATOR ${USE_CRNL_AS_LINE_TERMINATOR}
+
+/* Version number of package */
+#cmakedefine VERSION ${VERSION}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win32 b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win32
new file mode 100644
index 000000000..82a35b933
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win32
@@ -0,0 +1,56 @@
+#if defined(__MINGW32__) || _MSC_VER >= 1600
+#define HAVE_STDINT_H 1
+#endif
+#if defined(__MINGW32__) || _MSC_VER >= 1800
+#define HAVE_INTTYPES_H 1
+#endif
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_OFF_T 1
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF___INT64 8
+#define SIZEOF_OFF_T 4
+#define SIZEOF_VOIDP 4
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+#define SIZEOF_SIZE_T 4
+#define TOKEN_PASTE(x,y) x##y
+#ifndef NORETURN
+#if _MSC_VER > 1100
+#define NORETURN(x) __declspec(noreturn) x
+#else
+#define NORETURN(x) x
+#endif
+#endif
+#define HAVE_DECL_SYS_NERR 1
+#define HAVE_FCNTL_H 1
+#define HAVE_SYS_UTIME_H 1
+#define HAVE_MEMORY_H 1
+#define uid_t int
+#define gid_t int
+#define GETGROUPS_T int
+#define HAVE_ALLOCA 1
+#define HAVE_DUP2 1
+#define HAVE_MKDIR 1
+#define HAVE_FLOCK 1
+#define HAVE_FINITE 1
+#define HAVE_HYPOT 1
+#define HAVE_WAITPID 1
+#define HAVE_CHSIZE 1
+#define HAVE_TIMES 1
+#define HAVE_TELLDIR 1
+#define HAVE_SEEKDIR 1
+#define HAVE_EXECVE 1
+#define HAVE_DAYLIGHT 1
+#define SETPGRP_VOID 1
+#define inline __inline
+#define NEED_IO_SEEK_BETWEEN_RW 1
+#define RSHIFT(x,y) ((x)>>(int)y)
+#define FILE_COUNT _cnt
+#define FILE_READPTR _ptr
+#define DEFAULT_KCODE KCODE_NONE
+#define DLEXT ".so"
+#define DLEXT2 ".dll"
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win64 b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win64
new file mode 100644
index 000000000..7f1969934
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.win64
@@ -0,0 +1,56 @@
+#if defined(__MINGW32__) || _MSC_VER >= 1600
+#define HAVE_STDINT_H 1
+#endif
+#if defined(__MINGW32__) || _MSC_VER >= 1800
+#define HAVE_INTTYPES_H 1
+#endif
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_OFF_T 1
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF___INT64 8
+#define SIZEOF_OFF_T 4
+#define SIZEOF_VOIDP 8
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+#define SIZEOF_SIZE_T 8
+#define TOKEN_PASTE(x,y) x##y
+#ifndef NORETURN
+#if _MSC_VER > 1100
+#define NORETURN(x) __declspec(noreturn) x
+#else
+#define NORETURN(x) x
+#endif
+#endif
+#define HAVE_DECL_SYS_NERR 1
+#define HAVE_FCNTL_H 1
+#define HAVE_SYS_UTIME_H 1
+#define HAVE_MEMORY_H 1
+#define uid_t int
+#define gid_t int
+#define GETGROUPS_T int
+#define HAVE_ALLOCA 1
+#define HAVE_DUP2 1
+#define HAVE_MKDIR 1
+#define HAVE_FLOCK 1
+#define HAVE_FINITE 1
+#define HAVE_HYPOT 1
+#define HAVE_WAITPID 1
+#define HAVE_CHSIZE 1
+#define HAVE_TIMES 1
+#define HAVE_TELLDIR 1
+#define HAVE_SEEKDIR 1
+#define HAVE_EXECVE 1
+#define HAVE_DAYLIGHT 1
+#define SETPGRP_VOID 1
+#define inline __inline
+#define NEED_IO_SEEK_BETWEEN_RW 1
+#define RSHIFT(x,y) ((x)>>(int)y)
+#define FILE_COUNT _cnt
+#define FILE_READPTR _ptr
+#define DEFAULT_KCODE KCODE_NONE
+#define DLEXT ".so"
+#define DLEXT2 ".dll"
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.windows.in b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.windows.in
new file mode 100644
index 000000000..d4f73d761
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/config.h.windows.in
@@ -0,0 +1,62 @@
+#if defined(__MINGW32__) || _MSC_VER >= 1600
+#define HAVE_STDINT_H 1
+#endif
+#if defined(__MINGW32__) || _MSC_VER >= 1800
+#define HAVE_INTTYPES_H 1
+#endif
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_OFF_T 1
+
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF___INT64 8
+#define SIZEOF_OFF_T 4
+#ifdef _WIN64
+#define SIZEOF_VOIDP 8
+#define SIZEOF_SIZE_T 8
+#else
+#define SIZEOF_VOIDP 4
+#define SIZEOF_SIZE_T 4
+#endif
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+#define TOKEN_PASTE(x,y) x##y
+#ifndef NORETURN
+#if _MSC_VER > 1100
+#define NORETURN(x) __declspec(noreturn) x
+#else
+#define NORETURN(x) x
+#endif
+#endif
+#define HAVE_DECL_SYS_NERR 1
+#define HAVE_FCNTL_H 1
+#define HAVE_SYS_UTIME_H 1
+#define HAVE_MEMORY_H 1
+#define uid_t int
+#define gid_t int
+#define GETGROUPS_T int
+#define HAVE_ALLOCA 1
+#define HAVE_DUP2 1
+#define HAVE_MKDIR 1
+#define HAVE_FLOCK 1
+#define HAVE_FINITE 1
+#define HAVE_HYPOT 1
+#define HAVE_WAITPID 1
+#define HAVE_CHSIZE 1
+#define HAVE_TIMES 1
+#define HAVE_TELLDIR 1
+#define HAVE_SEEKDIR 1
+#define HAVE_EXECVE 1
+#define HAVE_DAYLIGHT 1
+#define SETPGRP_VOID 1
+#define inline __inline
+#define NEED_IO_SEEK_BETWEEN_RW 1
+#define RSHIFT(x,y) ((x)>>(int)y)
+#define FILE_COUNT _cnt
+#define FILE_READPTR _ptr
+#define DEFAULT_KCODE KCODE_NONE
+#define DLEXT ".so"
+#define DLEXT2 ".dll"
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/cp1251.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/cp1251.c
new file mode 100644
index 000000000..fa2078093
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/cp1251.c
@@ -0,0 +1,205 @@
+/**********************************************************************
+ cp1251.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2006-2019 Byte <byte AT mail DOT kna DOT ru>
+ * K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_CP1251_TO_LOWER_CASE(c) EncCP1251_ToLowerCaseTable[c]
+#define ENC_IS_CP1251_CTYPE(code,ctype) \
+ ((EncCP1251_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncCP1251_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\220', '\203', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\232', '\213', '\234', '\235', '\236', '\237',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\242', '\242', '\274', '\244', '\264', '\246', '\247',
+ '\270', '\251', '\272', '\253', '\254', '\255', '\256', '\277',
+ '\260', '\261', '\263', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\276', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncCP1251_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x428c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x34a2, 0x34a2, 0x01a0, 0x30e2, 0x01a0, 0x01a0, 0x01a0, 0x01a0,
+ 0x0000, 0x01a0, 0x34a2, 0x01a0, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x30e2, 0x01a0, 0x01a0, 0x01a0, 0x01a0, 0x01a0, 0x01a0, 0x01a0,
+ 0x0008, 0x0000, 0x30e2, 0x01a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x0280, 0x34a2, 0x30e2, 0x34a2, 0x01a0, 0x34a2, 0x01a0, 0x01a0,
+ 0x34a2, 0x01a0, 0x34a2, 0x01a0, 0x01a0, 0x01a0, 0x01a0, 0x34a2,
+ 0x01a0, 0x01a0, 0x34a2, 0x30e2, 0x30e2, 0x31e2, 0x01a0, 0x01a0,
+ 0x30e2, 0x0000, 0x30e2, 0x01a0, 0x30e2, 0x34a2, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+cp1251_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ *lower = ENC_CP1251_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+cp1251_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_CP1251_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xb8, 0xa8 },
+
+ { 0xe0, 0xc0 },
+ { 0xe1, 0xc1 },
+ { 0xe2, 0xc2 },
+ { 0xe3, 0xc3 },
+ { 0xe4, 0xc4 },
+ { 0xe5, 0xc5 },
+ { 0xe6, 0xc6 },
+ { 0xe7, 0xc7 },
+ { 0xe8, 0xc8 },
+ { 0xe9, 0xc9 },
+ { 0xea, 0xca },
+ { 0xeb, 0xcb },
+ { 0xec, 0xcc },
+ { 0xed, 0xcd },
+ { 0xee, 0xce },
+ { 0xef, 0xcf },
+
+ { 0xf0, 0xd0 },
+ { 0xf1, 0xd1 },
+ { 0xf2, 0xd2 },
+ { 0xf3, 0xd3 },
+ { 0xf4, 0xd4 },
+ { 0xf5, 0xd5 },
+ { 0xf6, 0xd6 },
+ { 0xf7, 0xd7 },
+ { 0xf8, 0xd8 },
+ { 0xf9, 0xd9 },
+ { 0xfa, 0xda },
+ { 0xfb, 0xdb },
+ { 0xfc, 0xdc },
+ { 0xfd, 0xdd },
+ { 0xfe, 0xde },
+ { 0xff, 0xdf }
+};
+
+static int
+cp1251_apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, f, arg);
+}
+
+static int
+cp1251_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingCP1251 = {
+ onigenc_single_byte_mbc_enc_len,
+ "CP1251", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ cp1251_mbc_case_fold,
+ cp1251_apply_all_case_fold,
+ cp1251_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ cp1251_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp.c
new file mode 100644
index 000000000..640b3e3c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp.c
@@ -0,0 +1,293 @@
+/**********************************************************************
+ euc_jp.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+#define eucjp_islead(c) ((UChar )((c) - 0xa1) > 0xfe - 0xa1)
+
+static const int EncLen_EUCJP[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1
+};
+
+static int
+mbc_enc_len(const UChar* p)
+{
+ return EncLen_EUCJP[*p];
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p > 0xa0) {
+ if (*p == 0xff) return FALSE;
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff) return FALSE;
+ p++;
+ }
+ else if (*p == 0x8e) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p > 0xdf) return FALSE;
+ p++;
+ }
+ else if (*p == 0x8f) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff) return FALSE;
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff) return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+mbc_to_code(const UChar* p, const UChar* end)
+{
+ int c, i, len;
+ OnigCodePoint n;
+
+ len = enclen(ONIG_ENCODING_EUC_JP, p);
+ n = (OnigCodePoint )*p++;
+ if (len == 1) return n;
+
+ for (i = 1; i < len; i++) {
+ if (p >= end) break;
+ c = *p++;
+ n <<= 8; n += c;
+ }
+ return n;
+}
+
+static int
+code_to_mbclen(OnigCodePoint code)
+{
+ if (ONIGENC_IS_CODE_ASCII(code)) return 1;
+ else if ((code & 0xff0000) != 0) return 3;
+ else if ((code & 0xff00) != 0) return 2;
+ else
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+}
+
+static int
+code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar *p = buf;
+
+ if ((code & 0xff0000) != 0) *p++ = (UChar )(((code >> 16) & 0xff));
+ if ((code & 0xff00) != 0) *p++ = (UChar )(((code >> 8) & 0xff));
+ *p++ = (UChar )(code & 0xff);
+
+#if 1
+ if (enclen(ONIG_ENCODING_EUC_JP, buf) != (p - buf))
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+#endif
+ return (int )(p - buf);
+}
+
+static int
+mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ int len;
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_MBC_ASCII(p)) {
+ *lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+ }
+ else {
+ int i;
+
+ len = enclen(ONIG_ENCODING_EUC_JP, p);
+ for (i = 0; i < len; i++) {
+ *lower++ = *p++;
+ }
+ (*pp) += len;
+ return len; /* return byte length of converted char to lower */
+ }
+}
+
+static UChar*
+left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ /* In this encoding
+ mb-trail bytes doesn't mix with single bytes.
+ */
+ const UChar *p;
+ int len;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ while (!eucjp_islead(*p) && p > start) p--;
+ len = enclen(ONIG_ENCODING_EUC_JP, p);
+ if (p + len > s) return (UChar* )p;
+ p += len;
+ return (UChar* )(p + ((s - p) & ~1));
+}
+
+static int
+is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ const UChar c = *s;
+ if (c <= 0x7e || c == 0x8e || c == 0x8f)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+static const OnigCodePoint CR_Hiragana[] = {
+ 1,
+ 0xa4a1, 0xa4f3
+}; /* CR_Hiragana */
+
+static const OnigCodePoint CR_Katakana[] = {
+ 3,
+ 0xa5a1, 0xa5f6,
+ 0xaaa6, 0xaaaf,
+ 0xaab1, 0xaadd
+}; /* CR_Katakana */
+
+static const OnigCodePoint* PropertyList[] = {
+ CR_Hiragana,
+ CR_Katakana
+};
+
+static int
+property_name_to_ctype(OnigEncoding enc, UChar* p, UChar* end)
+{
+ struct PropertyNameCtype* pc;
+ int len = (int )(end - p);
+ char q[32];
+
+ if (len < sizeof(q) - 1) {
+ xmemcpy(q, p, (size_t )len);
+ q[len] = '\0';
+ pc = onigenc_euc_jp_lookup_property_name(q, len);
+ if (pc != 0)
+ return pc->ctype;
+ }
+
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (ctype <= ONIGENC_MAX_STD_CTYPE) {
+ if (code < 128)
+ return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
+ else {
+ if (CTYPE_IS_WORD_GRAPH_PRINT(ctype)) {
+ return (code_to_mbclen(code) > 1 ? TRUE : FALSE);
+ }
+ }
+ }
+ else {
+ ctype -= (ONIGENC_MAX_STD_CTYPE + 1);
+ if (ctype >= (unsigned int )(sizeof(PropertyList)/sizeof(PropertyList[0])))
+ return ONIGERR_TYPE_BUG;
+
+ return onig_is_in_code_range((UChar* )PropertyList[ctype], code);
+ }
+
+ return FALSE;
+}
+
+static int
+get_ctype_code_range(OnigCtype ctype, OnigCodePoint* sb_out,
+ const OnigCodePoint* ranges[])
+{
+ if (ctype <= ONIGENC_MAX_STD_CTYPE) {
+ return ONIG_NO_SUPPORT_CONFIG;
+ }
+ else {
+ *sb_out = 0x80;
+
+ ctype -= (ONIGENC_MAX_STD_CTYPE + 1);
+ if (ctype >= (OnigCtype )sizeof(PropertyList)/sizeof(PropertyList[0]))
+ return ONIGERR_TYPE_BUG;
+
+ *ranges = PropertyList[ctype];
+ return 0;
+ }
+}
+
+
+OnigEncodingType OnigEncodingEUC_JP = {
+ mbc_enc_len,
+ "EUC-JP", /* name */
+ 3, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ mbc_to_code,
+ code_to_mbclen,
+ code_to_mbc,
+ mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ property_name_to_ctype,
+ is_code_ctype,
+ get_ctype_code_range,
+ left_adjust_char_head,
+ is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1_OR_0,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.c
new file mode 100644
index 000000000..cb884c4a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.c
@@ -0,0 +1,151 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -pt -T -L ANSI-C -N onigenc_euc_jp_lookup_property_name --output-file gperf1.tmp euc_jp_prop.gperf */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 1 "euc_jp_prop.gperf"
+
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 16
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 8
+#define MIN_HASH_VALUE 4
+#define MAX_HASH_VALUE 55
+/* maximum key range = 52, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (register const char *str, register size_t len)
+{
+ static unsigned char asso_values[] =
+ {
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 0, 3, 10, 25, 56,
+ 56, 30, 0, 56, 56, 0, 20, 56, 56, 56,
+ 15, 56, 56, 20, 56, 30, 56, 0, 0, 56,
+ 56, 56, 56, 56, 56, 56, 56, 15, 56, 56,
+ 56, 56, 56, 25, 56, 10, 56, 56, 56, 56,
+ 5, 56, 0, 56, 0, 56, 5, 56, 56, 20,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56
+ };
+ return (unsigned int )len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
+}
+
+struct PropertyNameCtype *
+onigenc_euc_jp_lookup_property_name (register const char *str, register size_t len)
+{
+ static struct PropertyNameCtype wordlist[] =
+ {
+ {""}, {""}, {""}, {""},
+#line 22 "euc_jp_prop.gperf"
+ {"Word", 12},
+#line 11 "euc_jp_prop.gperf"
+ {"Alpha", 1},
+ {""}, {""},
+#line 25 "euc_jp_prop.gperf"
+ {"Hiragana", 15},
+ {""},
+#line 23 "euc_jp_prop.gperf"
+ {"Alnum", 13},
+ {""}, {""},
+#line 26 "euc_jp_prop.gperf"
+ {"Katakana", 16},
+ {""},
+#line 24 "euc_jp_prop.gperf"
+ {"ASCII", 14},
+#line 21 "euc_jp_prop.gperf"
+ {"XDigit", 11},
+ {""}, {""}, {""},
+#line 13 "euc_jp_prop.gperf"
+ {"Cntrl", 3},
+ {""}, {""},
+#line 12 "euc_jp_prop.gperf"
+ {"Blank", 2},
+ {""},
+#line 18 "euc_jp_prop.gperf"
+ {"Punct", 8},
+ {""}, {""}, {""}, {""},
+#line 17 "euc_jp_prop.gperf"
+ {"Print", 7},
+ {""}, {""}, {""}, {""},
+#line 20 "euc_jp_prop.gperf"
+ {"Upper", 10},
+ {""}, {""}, {""}, {""},
+#line 19 "euc_jp_prop.gperf"
+ {"Space", 9},
+ {""}, {""}, {""}, {""},
+#line 16 "euc_jp_prop.gperf"
+ {"Lower", 6},
+ {""}, {""}, {""}, {""},
+#line 15 "euc_jp_prop.gperf"
+ {"Graph", 5},
+ {""}, {""}, {""}, {""},
+#line 14 "euc_jp_prop.gperf"
+ {"Digit", 4}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.gperf b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.gperf
new file mode 100644
index 000000000..842b61b65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_jp_prop.gperf
@@ -0,0 +1,26 @@
+%{
+#include "regint.h"
+%}
+
+struct PropertyNameCtype {
+ char *name;
+ int ctype;
+};
+
+%%
+Alpha, 1
+Blank, 2
+Cntrl, 3
+Digit, 4
+Graph, 5
+Lower, 6
+Print, 7
+Punct, 8
+Space, 9
+Upper, 10
+XDigit, 11
+Word, 12
+Alnum, 13
+ASCII, 14
+Hiragana, 15
+Katakana, 16
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_kr.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_kr.c
new file mode 100644
index 000000000..7fa50afb7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_kr.c
@@ -0,0 +1,193 @@
+/**********************************************************************
+ euc_kr.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+static const int EncLen_EUCKR[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1
+};
+
+static int
+euckr_mbc_enc_len(const UChar* p)
+{
+ return EncLen_EUCKR[*p];
+}
+
+static int
+euckr_code_to_mbclen(OnigCodePoint code)
+{
+ if ((code & (~0xffff)) != 0) return ONIGERR_INVALID_CODE_POINT_VALUE;
+ if ((code & 0xff00) != 0) return 2;
+ if (EncLen_EUCKR[(int )(code & 0xff)] == 1) return 1;
+
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p < 0xa1) {
+ return FALSE;
+ }
+ else if (*p < 0xff) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff)
+ return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+euckr_mbc_to_code(const UChar* p, const UChar* end)
+{
+ return onigenc_mbn_mbc_to_code(ONIG_ENCODING_EUC_KR, p, end);
+}
+
+static int
+euckr_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ return onigenc_mb2_code_to_mbc(ONIG_ENCODING_EUC_KR, code, buf);
+}
+
+static int
+euckr_mbc_case_fold(OnigCaseFoldType flag, const UChar** pp, const UChar* end,
+ UChar* lower)
+{
+ return onigenc_mbn_mbc_case_fold(ONIG_ENCODING_EUC_KR, flag,
+ pp, end, lower);
+}
+
+static int
+euckr_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ return onigenc_mb2_is_code_ctype(ONIG_ENCODING_EUC_KR, code, ctype);
+}
+
+#define euckr_islead(c) ((c) < 0xa1 || (c) == 0xff)
+
+static UChar*
+euckr_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ /* Assumed in this encoding,
+ mb-trail bytes don't mix with single bytes.
+ */
+ const UChar *p;
+ int len;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ while (!euckr_islead(*p) && p > start) p--;
+ len = enclen(ONIG_ENCODING_EUC_KR, p);
+ if (p + len > s) return (UChar* )p;
+ p += len;
+ return (UChar* )(p + ((s - p) & ~1));
+}
+
+static int
+euckr_is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ const UChar c = *s;
+ if (c <= 0x7e) return TRUE;
+ else return FALSE;
+}
+
+OnigEncodingType OnigEncodingEUC_KR = {
+ euckr_mbc_enc_len,
+ "EUC-KR", /* name */
+ 2, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ euckr_mbc_to_code,
+ euckr_code_to_mbclen,
+ euckr_code_to_mbc,
+ euckr_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ euckr_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ euckr_left_adjust_char_head,
+ euckr_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1_OR_0,
+ 0, 0
+};
+
+/* Same with OnigEncodingEUC_KR except the name */
+OnigEncodingType OnigEncodingEUC_CN = {
+ euckr_mbc_enc_len,
+ "EUC-CN", /* name */
+ 2, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ euckr_mbc_to_code,
+ euckr_code_to_mbclen,
+ euckr_code_to_mbc,
+ euckr_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ euckr_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ euckr_left_adjust_char_head,
+ euckr_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1_OR_0,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_tw.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_tw.c
new file mode 100644
index 000000000..8e72b9708
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/euc_tw.c
@@ -0,0 +1,187 @@
+/**********************************************************************
+ euc_tw.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+static const int EncLen_EUCTW[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1
+};
+
+static int
+euctw_mbc_enc_len(const UChar* p)
+{
+ return EncLen_EUCTW[*p];
+}
+
+static int
+euctw_code_to_mbclen(OnigCodePoint code)
+{
+ if ((code & 0xff000000) != 0) return 4;
+ else if ((code & 0xff0000) != 0) return ONIGERR_INVALID_CODE_POINT_VALUE;
+ else if ((code & 0xff00) != 0) return 2;
+ else {
+ if (EncLen_EUCTW[(int )(code & 0xff)] == 1)
+ return 1;
+
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+ }
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p < 0xa1) {
+ if (*p == 0x8e) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p > 0xb0) return FALSE;
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff)
+ return FALSE;
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff)
+ return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+ else if (*p < 0xff) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0xa1 || *p == 0xff)
+ return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+euctw_mbc_to_code(const UChar* p, const UChar* end)
+{
+ return onigenc_mbn_mbc_to_code(ONIG_ENCODING_EUC_TW, p, end);
+}
+
+static int
+euctw_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ return onigenc_mb4_code_to_mbc(ONIG_ENCODING_EUC_TW, code, buf);
+}
+
+static int
+euctw_mbc_case_fold(OnigCaseFoldType flag, const UChar** pp, const UChar* end,
+ UChar* lower)
+{
+ return onigenc_mbn_mbc_case_fold(ONIG_ENCODING_EUC_TW, flag,
+ pp, end, lower);
+}
+
+static int
+euctw_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ return onigenc_mb4_is_code_ctype(ONIG_ENCODING_EUC_TW, code, ctype);
+}
+
+#define euctw_islead(c) ((UChar )((c) - 0xa1) > 0xfe - 0xa1)
+
+static UChar*
+euctw_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ /* Assumed in this encoding,
+ mb-trail bytes don't mix with single bytes.
+ */
+ const UChar *p;
+ int len;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ while (!euctw_islead(*p) && p > start) p--;
+ len = enclen(ONIG_ENCODING_EUC_TW, p);
+ if (p + len > s) return (UChar* )p;
+ p += len;
+ return (UChar* )(p + ((s - p) & ~1));
+}
+
+static int
+euctw_is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ const UChar c = *s;
+ if (c <= 0x7e) return TRUE;
+ else return FALSE;
+}
+
+OnigEncodingType OnigEncodingEUC_TW = {
+ euctw_mbc_enc_len,
+ "EUC-TW", /* name */
+ 4, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ euctw_mbc_to_code,
+ euctw_code_to_mbclen,
+ euctw_code_to_mbc,
+ euctw_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ euctw_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ euctw_left_adjust_char_head,
+ euctw_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gb18030.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gb18030.c
new file mode 100644
index 000000000..1385a7fad
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gb18030.c
@@ -0,0 +1,556 @@
+/**********************************************************************
+ gb18030.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2005-2020 KUBO Takehiro <kubo AT jiubao DOT org>
+ * K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#if 1
+
+#define DEBUG_GB18030(arg)
+
+#else
+
+#ifndef NEED_TO_INCLUDE_STDIO
+#define NEED_TO_INCLUDE_STDIO
+#endif
+
+/* for printf() */
+#include "regint.h"
+
+#define DEBUG_GB18030(arg) printf arg
+
+#endif
+
+enum {
+ C1, /* one-byte char */
+ C2, /* one-byte or second of two-byte char */
+ C4, /* one-byte or second or fourth of four-byte char */
+ CM /* first of two- or four-byte char or second of two-byte char */
+};
+
+static const char GB18030_MAP[] = {
+ C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1,
+ C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1,
+ C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1, C1,
+ C4, C4, C4, C4, C4, C4, C4, C4, C4, C4, C1, C1, C1, C1, C1, C1,
+ C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2,
+ C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2,
+ C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2,
+ C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C1,
+ C2, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM,
+ CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, CM, C1
+};
+
+static int
+gb18030_mbc_enc_len(const UChar* p)
+{
+ if (GB18030_MAP[*p] != CM)
+ return 1;
+
+ p++;
+ if (GB18030_MAP[*p] == C4)
+ return 4;
+
+ return 2;
+}
+
+static int
+gb18030_code_to_mbclen(OnigCodePoint code)
+{
+ if ((code & 0xff000000) != 0) return 4;
+ else if ((code & 0xff0000) != 0) return ONIGERR_INVALID_CODE_POINT_VALUE;
+ else if ((code & 0xff00) != 0) return 2;
+ else {
+ if (GB18030_MAP[(int )(code & 0xff)] == CM)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ return 1;
+ }
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p == 0x80 || *p == 0xff) {
+ return FALSE;
+ }
+ else {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x40) {
+ if (*p < 0x30 || *p > 0x39)
+ return FALSE;
+
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x81 || *p == 0xff) return FALSE;
+
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x30 || *p > 0x39)
+ return FALSE;
+
+ p++;
+ }
+ else if (*p == 0x7f || *p == 0xff) {
+ return FALSE;
+ }
+ else {
+ p++;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+gb18030_mbc_to_code(const UChar* p, const UChar* end)
+{
+ return onigenc_mbn_mbc_to_code(ONIG_ENCODING_GB18030, p, end);
+}
+
+static int
+gb18030_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ return onigenc_mb4_code_to_mbc(ONIG_ENCODING_GB18030, code, buf);
+}
+
+static int
+gb18030_mbc_case_fold(OnigCaseFoldType flag, const UChar** pp, const UChar* end,
+ UChar* lower)
+{
+ return onigenc_mbn_mbc_case_fold(ONIG_ENCODING_GB18030, flag,
+ pp, end, lower);
+}
+
+static int
+gb18030_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ return onigenc_mb4_is_code_ctype(ONIG_ENCODING_GB18030, code, ctype);
+}
+
+enum state {
+ S_START,
+ S_one_C2,
+ S_one_C4,
+ S_one_CM,
+
+ S_odd_CM_one_CX,
+ S_even_CM_one_CX,
+
+ /* CMC4 : pair of "CM C4" */
+ S_one_CMC4,
+ S_odd_CMC4,
+ S_one_C4_odd_CMC4,
+ S_even_CMC4,
+ S_one_C4_even_CMC4,
+
+ S_odd_CM_odd_CMC4,
+ S_even_CM_odd_CMC4,
+
+ S_odd_CM_even_CMC4,
+ S_even_CM_even_CMC4,
+
+ /* C4CM : pair of "C4 CM" */
+ S_odd_C4CM,
+ S_one_CM_odd_C4CM,
+ S_even_C4CM,
+ S_one_CM_even_C4CM,
+
+ S_even_CM_odd_C4CM,
+ S_odd_CM_odd_C4CM,
+ S_even_CM_even_C4CM,
+ S_odd_CM_even_C4CM,
+};
+
+static UChar*
+gb18030_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ const UChar *p;
+ enum state state = S_START;
+
+ DEBUG_GB18030(("----------------\n"));
+ for (p = s; p >= start; p--) {
+ DEBUG_GB18030(("state %d --(%02x)-->\n", state, *p));
+ switch (state) {
+ case S_START:
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ return (UChar *)s;
+ case C2:
+ state = S_one_C2; /* C2 */
+ break;
+ case C4:
+ state = S_one_C4; /* C4 */
+ break;
+ case CM:
+ state = S_one_CM; /* CM */
+ break;
+ }
+ break;
+ case S_one_C2: /* C2 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)s;
+ case CM:
+ state = S_odd_CM_one_CX; /* CM C2 */
+ break;
+ }
+ break;
+ case S_one_C4: /* C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)s;
+ case CM:
+ state = S_one_CMC4;
+ break;
+ }
+ break;
+ case S_one_CM: /* CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)s;
+ case C4:
+ state = S_odd_C4CM;
+ break;
+ case CM:
+ state = S_odd_CM_one_CX; /* CM CM */
+ break;
+ }
+ break;
+
+ case S_odd_CM_one_CX: /* CM C2 */ /* CM CM */ /* CM CM CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 1);
+ case CM:
+ state = S_even_CM_one_CX;
+ break;
+ }
+ break;
+ case S_even_CM_one_CX: /* CM CM C2 */ /* CM CM CM */ /* CM CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)s;
+ case CM:
+ state = S_odd_CM_one_CX;
+ break;
+ }
+ break;
+
+ case S_one_CMC4: /* CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)(s - 1);
+ case C4:
+ state = S_one_C4_odd_CMC4; /* C4 CM C4 */
+ break;
+ case CM:
+ state = S_even_CM_one_CX; /* CM CM C4 */
+ break;
+ }
+ break;
+ case S_odd_CMC4: /* CM C4 CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)(s - 1);
+ case C4:
+ state = S_one_C4_odd_CMC4;
+ break;
+ case CM:
+ state = S_odd_CM_odd_CMC4;
+ break;
+ }
+ break;
+ case S_one_C4_odd_CMC4: /* C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 1);
+ case CM:
+ state = S_even_CMC4; /* CM C4 CM C4 */
+ break;
+ }
+ break;
+ case S_even_CMC4: /* CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)(s - 3);
+ case C4:
+ state = S_one_C4_even_CMC4;
+ break;
+ case CM:
+ state = S_odd_CM_even_CMC4;
+ break;
+ }
+ break;
+ case S_one_C4_even_CMC4: /* C4 CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 3);
+ case CM:
+ state = S_odd_CMC4;
+ break;
+ }
+ break;
+
+ case S_odd_CM_odd_CMC4: /* CM CM C4 CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 3);
+ case CM:
+ state = S_even_CM_odd_CMC4;
+ break;
+ }
+ break;
+ case S_even_CM_odd_CMC4: /* CM CM CM C4 CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 1);
+ case CM:
+ state = S_odd_CM_odd_CMC4;
+ break;
+ }
+ break;
+
+ case S_odd_CM_even_CMC4: /* CM CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 1);
+ case CM:
+ state = S_even_CM_even_CMC4;
+ break;
+ }
+ break;
+ case S_even_CM_even_CMC4: /* CM CM CM C4 CM C4 */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 3);
+ case CM:
+ state = S_odd_CM_even_CMC4;
+ break;
+ }
+ break;
+
+ case S_odd_C4CM: /* C4 CM */ /* C4 CM C4 CM C4 CM*/
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)s;
+ case CM:
+ state = S_one_CM_odd_C4CM; /* CM C4 CM */
+ break;
+ }
+ break;
+ case S_one_CM_odd_C4CM: /* CM C4 CM */ /* CM C4 CM C4 CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)(s - 2); /* |CM C4 CM */
+ case C4:
+ state = S_even_C4CM;
+ break;
+ case CM:
+ state = S_even_CM_odd_C4CM;
+ break;
+ }
+ break;
+ case S_even_C4CM: /* C4 CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 2); /* C4|CM C4 CM */
+ case CM:
+ state = S_one_CM_even_C4CM;
+ break;
+ }
+ break;
+ case S_one_CM_even_C4CM: /* CM C4 CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ return (UChar *)(s - 0); /*|CM C4 CM C4|CM */
+ case C4:
+ state = S_odd_C4CM;
+ break;
+ case CM:
+ state = S_even_CM_even_C4CM;
+ break;
+ }
+ break;
+
+ case S_even_CM_odd_C4CM: /* CM CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 0); /* |CM CM|C4|CM */
+ case CM:
+ state = S_odd_CM_odd_C4CM;
+ break;
+ }
+ break;
+ case S_odd_CM_odd_C4CM: /* CM CM CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 2); /* |CM CM|CM C4 CM */
+ case CM:
+ state = S_even_CM_odd_C4CM;
+ break;
+ }
+ break;
+
+ case S_even_CM_even_C4CM: /* CM CM C4 CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 2); /* |CM CM|C4|CM C4 CM */
+ case CM:
+ state = S_odd_CM_even_C4CM;
+ break;
+ }
+ break;
+ case S_odd_CM_even_C4CM: /* CM CM CM C4 CM C4 CM */
+ switch (GB18030_MAP[*p]) {
+ case C1:
+ case C2:
+ case C4:
+ return (UChar *)(s - 0); /* |CM CM|CM C4 CM C4|CM */
+ case CM:
+ state = S_even_CM_even_C4CM;
+ break;
+ }
+ break;
+ }
+ }
+
+ DEBUG_GB18030(("state %d\n", state));
+ switch (state) {
+ case S_START: return (UChar *)(s - 0);
+ case S_one_C2: return (UChar *)(s - 0);
+ case S_one_C4: return (UChar *)(s - 0);
+ case S_one_CM: return (UChar *)(s - 0);
+
+ case S_odd_CM_one_CX: return (UChar *)(s - 1);
+ case S_even_CM_one_CX: return (UChar *)(s - 0);
+
+ case S_one_CMC4: return (UChar *)(s - 1);
+ case S_odd_CMC4: return (UChar *)(s - 1);
+ case S_one_C4_odd_CMC4: return (UChar *)(s - 1);
+ case S_even_CMC4: return (UChar *)(s - 3);
+ case S_one_C4_even_CMC4: return (UChar *)(s - 3);
+
+ case S_odd_CM_odd_CMC4: return (UChar *)(s - 3);
+ case S_even_CM_odd_CMC4: return (UChar *)(s - 1);
+
+ case S_odd_CM_even_CMC4: return (UChar *)(s - 1);
+ case S_even_CM_even_CMC4: return (UChar *)(s - 3);
+
+ case S_odd_C4CM: return (UChar *)(s - 0);
+ case S_one_CM_odd_C4CM: return (UChar *)(s - 2);
+ case S_even_C4CM: return (UChar *)(s - 2);
+ case S_one_CM_even_C4CM: return (UChar *)(s - 0);
+
+ case S_even_CM_odd_C4CM: return (UChar *)(s - 0);
+ case S_odd_CM_odd_C4CM: return (UChar *)(s - 2);
+ case S_even_CM_even_C4CM: return (UChar *)(s - 2);
+ case S_odd_CM_even_C4CM: return (UChar *)(s - 0);
+ }
+
+ return (UChar* )s; /* never come here. (escape warning) */
+}
+
+static int
+gb18030_is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ return GB18030_MAP[*s] == C1 ? TRUE : FALSE;
+}
+
+OnigEncodingType OnigEncodingGB18030 = {
+ gb18030_mbc_enc_len,
+ "GB18030", /* name */
+ 4, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ gb18030_mbc_to_code,
+ gb18030_code_to_mbclen,
+ gb18030_code_to_mbc,
+ gb18030_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ gb18030_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ gb18030_left_adjust_char_head,
+ gb18030_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_fold_key_conv.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_fold_key_conv.py
new file mode 100755
index 000000000..c633100df
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_fold_key_conv.py
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# gperf_fold_key_conv.py
+# Copyright (c) 2016-2018 K.Kosako
+
+import sys
+import re
+
+REG_LINE_GPERF = re.compile('#line .+gperf"')
+REG_HASH_FUNC = re.compile('hash\s*\(register\s+const\s+char\s*\*\s*str,\s*register\s+size_t\s+len\s*\)')
+REG_STR_AT = re.compile('str\[(\d+)\]')
+REG_RETURN_TYPE = re.compile('^const\s+short\s+int\s*\*')
+REG_FOLD_KEY = re.compile('unicode_fold(\d)_key\s*\(register\s+const\s+char\s*\*\s*str,\s*register\s+size_t\s+len\)')
+REG_ENTRY = re.compile('\{".*?",\s*(-?\d+)\s*\}')
+REG_IF_LEN = re.compile('\s*if\s*\(\s*len\s*<=\s*MAX_WORD_LENGTH.+')
+REG_GET_HASH = re.compile('(?:register\s+)?(?:unsigned\s+)?int\s+key\s*=\s*hash\s*\(str,\s*len\);')
+REG_GET_CODE = re.compile('(?:register\s+)?const\s+char\s*\*\s*s\s*=\s*wordlist\[key\]\.name;')
+REG_CODE_CHECK = re.compile('if\s*\(\*str\s*==\s*\*s\s*&&\s*!strncmp.+\)')
+REG_RETURN_WL = re.compile('return\s+&wordlist\[key\];')
+REG_RETURN_0 = re.compile('return 0;')
+
+def parse_line(s, key_len):
+ s = s.rstrip()
+
+ r = re.sub(REG_LINE_GPERF, '', s)
+ if r != s: return r
+ r = re.sub(REG_HASH_FUNC, 'hash(OnigCodePoint codes[])', s)
+ if r != s: return r
+ r = re.sub(REG_STR_AT, 'onig_codes_byte_at(codes, \\1)', s)
+ if r != s: return r
+ r = re.sub(REG_RETURN_TYPE, 'int', s)
+ if r != s: return r
+ r = re.sub(REG_FOLD_KEY, 'unicode_fold\\1_key(OnigCodePoint codes[])', s)
+ if r != s: return r
+ r = re.sub(REG_ENTRY, '\\1', s)
+ if r != s: return r
+ r = re.sub(REG_IF_LEN, '', s)
+ if r != s: return r
+ r = re.sub(REG_GET_HASH, 'int key = hash(codes);', s)
+ if r != s: return r
+ r = re.sub(REG_GET_CODE, 'int index = wordlist[key];', s)
+ if r != s: return r
+ r = re.sub(REG_CODE_CHECK,
+ 'if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds%d + index, %d) == 0)' % (key_len, key_len), s)
+ if r != s: return r
+
+ r = re.sub(REG_RETURN_WL, 'return index;', s)
+ if r != s: return r
+ r = re.sub(REG_RETURN_0, 'return -1;', s)
+ if r != s: return r
+
+ return s
+
+def parse_file(f, key_len):
+ print "/* This file was converted by gperf_fold_key_conv.py\n from gperf output file. */"
+
+ while True:
+ line = f.readline()
+ if not line:
+ break
+
+ s = parse_line(line, key_len)
+ print s
+
+
+# main
+argv = sys.argv
+argc = len(argv)
+
+key_len = int(argv[1])
+parse_file(sys.stdin, key_len)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_unfold_key_conv.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_unfold_key_conv.py
new file mode 100755
index 000000000..d999d4e97
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/gperf_unfold_key_conv.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# gperf_unfold_key_conv.py
+# Copyright (c) 2016-2018 K.Kosako
+
+import sys
+import re
+
+REG_LINE_GPERF = re.compile('#line .+gperf"')
+REG_HASH_FUNC = re.compile('hash\s*\(register\s+const\s+char\s*\*\s*str,\s*register\s+size_t\s+len\s*\)')
+REG_STR_AT = re.compile('str\[(\d+)\]')
+REG_UNFOLD_KEY = re.compile('onigenc_unicode_unfold_key\s*\(register\s+const\s+char\s*\*\s*str,\s*register\s+size_t\s+len\)')
+REG_ENTRY = re.compile('\{".+?",\s*/\*(.+?)\*/\s*(-?\d+),\s*(\d)\}')
+REG_EMPTY_ENTRY = re.compile('\{"",\s*(-?\d+),\s*(\d)\}')
+REG_IF_LEN = re.compile('\s*if\s*\(\s*len\s*<=\s*MAX_WORD_LENGTH.+')
+REG_GET_HASH = re.compile('(?:register\s+)?(?:unsigned\s+)?int\s+key\s*=\s*hash\s*\(str,\s*len\);')
+REG_GET_CODE = re.compile('(?:register\s+)?const\s+char\s*\*\s*s\s*=\s*wordlist\[key\]\.name;')
+REG_CODE_CHECK = re.compile('if\s*\(\*str\s*==\s*\*s\s*&&\s*!strncmp.+\)')
+
+def parse_line(s):
+ s = s.rstrip()
+
+ r = re.sub(REG_LINE_GPERF, '', s)
+ if r != s: return r
+ r = re.sub(REG_HASH_FUNC, 'hash(OnigCodePoint codes[])', s)
+ if r != s: return r
+ r = re.sub(REG_STR_AT, 'onig_codes_byte_at(codes, \\1)', s)
+ if r != s: return r
+ r = re.sub(REG_UNFOLD_KEY, 'onigenc_unicode_unfold_key(OnigCodePoint code)', s)
+ if r != s: return r
+ r = re.sub(REG_ENTRY, '{\\1, \\2, \\3}', s)
+ if r != s: return r
+ r = re.sub(REG_EMPTY_ENTRY, '{0xffffffff, \\1, \\2}', s)
+ if r != s: return r
+ r = re.sub(REG_IF_LEN, '', s)
+ if r != s: return r
+ r = re.sub(REG_GET_HASH, 'int key = hash(&code);', s)
+ if r != s: return r
+ r = re.sub(REG_GET_CODE, 'OnigCodePoint gcode = wordlist[key].code;', s)
+ if r != s: return r
+ r = re.sub(REG_CODE_CHECK, 'if (code == gcode && wordlist[key].index >= 0)', s)
+ if r != s: return r
+
+ return s
+
+def parse_file(f):
+ print "/* This file was converted by gperf_unfold_key_conv.py\n from gperf output file. */"
+
+ line = f.readline()
+ while line:
+ s = parse_line(line)
+ print s
+ line = f.readline()
+
+
+# main
+parse_file(sys.stdin)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_1.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_1.c
new file mode 100644
index 000000000..d75509e43
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_1.c
@@ -0,0 +1,268 @@
+/**********************************************************************
+ iso8859_1.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define LARGE_S 0x53
+#define SMALL_S 0x73
+
+#define ENC_IS_ISO_8859_1_CTYPE(code,ctype) \
+ ((EncISO_8859_1_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const unsigned short EncISO_8859_1_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x30e2, 0x01a0, 0x00a0, 0x01a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x00a0, 0x01a0,
+ 0x00a0, 0x10a0, 0x30e2, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x01a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag ARG_UNUSED,
+ const OnigUChar* p, const OnigUChar* end,
+ OnigCaseFoldCodeItem items[])
+{
+ static OnigUChar sa[] = { LARGE_S, SMALL_S };
+ int i, j, n;
+
+ if (0x41 <= *p && *p <= 0x5a) {
+ if (*p == LARGE_S && end > p + 1
+ && (*(p+1) == LARGE_S || *(p+1) == SMALL_S)) { /* SS */
+ ss_combination:
+ items[0].byte_len = 2;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )0xdf;
+
+ n = 1;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ if (sa[i] == *p && sa[j] == *(p+1))
+ continue;
+
+ items[n].byte_len = 2;
+ items[n].code_len = 2;
+ items[n].code[0] = (OnigCodePoint )sa[i];
+ items[n].code[1] = (OnigCodePoint )sa[j];
+ n++;
+ }
+ }
+ return 4;
+ }
+
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p + 0x20);
+ return 1;
+ }
+ else if (0x61 <= *p && *p <= 0x7a) {
+ if (*p == SMALL_S && end > p + 1
+ && (*(p+1) == SMALL_S || *(p+1) == LARGE_S)) { /* ss */
+ goto ss_combination;
+ }
+
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p - 0x20);
+ return 1;
+ }
+ else if (0xc0 <= *p && *p <= 0xcf) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p + 0x20);
+ return 1;
+ }
+ else if (0xd0 <= *p && *p <= 0xdf) {
+ if (*p == 0xdf) {
+ items[0].byte_len = 1;
+ items[0].code_len = 2;
+ items[0].code[0] = (OnigCodePoint )'s';
+ items[0].code[1] = (OnigCodePoint )'s';
+
+ items[1].byte_len = 1;
+ items[1].code_len = 2;
+ items[1].code[0] = (OnigCodePoint )'S';
+ items[1].code[1] = (OnigCodePoint )'S';
+
+ items[2].byte_len = 1;
+ items[2].code_len = 2;
+ items[2].code[0] = (OnigCodePoint )'s';
+ items[2].code[1] = (OnigCodePoint )'S';
+
+ items[3].byte_len = 1;
+ items[3].code_len = 2;
+ items[3].code[0] = (OnigCodePoint )'S';
+ items[3].code[1] = (OnigCodePoint )'s';
+
+ return 4;
+ }
+ else if (*p != 0xd7) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p + 0x20);
+ return 1;
+ }
+ }
+ else if (0xe0 <= *p && *p <= 0xef) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p - 0x20);
+ return 1;
+ }
+ else if (0xf0 <= *p && *p <= 0xfe) {
+ if (*p != 0xf7) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p - 0x20);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+mbc_case_fold(OnigCaseFoldType flag, const UChar** pp,
+ const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ONIGENC_ISO_8859_1_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_1_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingISO_8859_1 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-1", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_10.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_10.c
new file mode 100644
index 000000000..e98cffb86
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_10.c
@@ -0,0 +1,222 @@
+/**********************************************************************
+ iso8859_10.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_10_TO_LOWER_CASE(c) EncISO_8859_10_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_10_CTYPE(code,ctype) \
+ ((EncISO_8859_10_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_10_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\261', '\262', '\263', '\264', '\265', '\266', '\247',
+ '\270', '\271', '\272', '\273', '\274', '\255', '\276', '\277',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_10_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x34a2, 0x34a2,
+ 0x00a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x01a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x01a0, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_10_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_10_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xb1 },
+ { 0xa2, 0xb2 },
+ { 0xa3, 0xb3 },
+ { 0xa4, 0xb4 },
+ { 0xa5, 0xb5 },
+ { 0xa6, 0xb6 },
+ { 0xa8, 0xb8 },
+ { 0xa9, 0xb9 },
+ { 0xaa, 0xba },
+ { 0xab, 0xbb },
+ { 0xac, 0xbc },
+ { 0xae, 0xbe },
+ { 0xaf, 0xbf },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_10 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-10", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_11.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_11.c
new file mode 100644
index 000000000..8639ce23c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_11.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+ iso8859_11.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_IS_ISO_8859_11_CTYPE(code,ctype) \
+ ((EncISO_8859_11_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const unsigned short EncISO_8859_11_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_11_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingISO_8859_11 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-11", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ onigenc_ascii_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_13.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_13.c
new file mode 100644
index 000000000..2bd460fe0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_13.c
@@ -0,0 +1,207 @@
+/**********************************************************************
+ iso8859_13.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_13_TO_LOWER_CASE(c) EncISO_8859_13_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_13_CTYPE(code,ctype) \
+ ((EncISO_8859_13_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_13_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\270', '\251', '\272', '\253', '\254', '\255', '\256', '\277',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_13_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x01a0, 0x00a0, 0x00a0,
+ 0x34a2, 0x00a0, 0x34a2, 0x01a0, 0x00a0, 0x01a0, 0x00a0, 0x34a2,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x01a0, 0x30e2, 0x00a0, 0x01a0,
+ 0x30e2, 0x10a0, 0x30e2, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x01a0
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_13_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_13_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_13 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-13", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_14.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_14.c
new file mode 100644
index 000000000..5030b5578
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_14.c
@@ -0,0 +1,223 @@
+/**********************************************************************
+ iso8859_14.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_14_TO_LOWER_CASE(c) EncISO_8859_14_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_14_CTYPE(code,ctype) \
+ ((EncISO_8859_14_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_14_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\242', '\242', '\243', '\245', '\245', '\253', '\247',
+ '\270', '\251', '\272', '\253', '\274', '\255', '\256', '\377',
+ '\261', '\261', '\263', '\263', '\265', '\265', '\266', '\271',
+ '\270', '\271', '\272', '\277', '\274', '\276', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_14_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x30e2, 0x00a0, 0x34a2, 0x30e2, 0x34a2, 0x00a0,
+ 0x34a2, 0x00a0, 0x34a2, 0x30e2, 0x34a2, 0x01a0, 0x00a0, 0x34a2,
+ 0x34a2, 0x30e2, 0x34a2, 0x30e2, 0x34a2, 0x30e2, 0x00a0, 0x34a2,
+ 0x30e2, 0x30e2, 0x30e2, 0x34a2, 0x30e2, 0x34a2, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_14_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_14_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xa2 },
+ { 0xa4, 0xa5 },
+ { 0xa6, 0xab },
+ { 0xa8, 0xb8 },
+ { 0xaa, 0xba },
+ { 0xac, 0xbc },
+ { 0xaf, 0xff },
+
+ { 0xb0, 0xb1 },
+ { 0xb2, 0xb3 },
+ { 0xb4, 0xb5 },
+ { 0xb7, 0xb9 },
+ { 0xbb, 0xbf },
+ { 0xbd, 0xbe },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_14 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-14", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_15.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_15.c
new file mode 100644
index 000000000..f32c3dedd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_15.c
@@ -0,0 +1,213 @@
+/**********************************************************************
+ iso8859_15.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_15_TO_LOWER_CASE(c) EncISO_8859_15_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_15_CTYPE(code,ctype) \
+ ((EncISO_8859_15_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_15_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\250', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\270', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\275', '\275', '\377', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_15_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x34a2, 0x00a0,
+ 0x30e2, 0x00a0, 0x30e2, 0x01a0, 0x00a0, 0x01a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x34a2, 0x30e2, 0x00a0, 0x01a0,
+ 0x30e2, 0x10a0, 0x30e2, 0x01a0, 0x34a2, 0x30e2, 0x34a2, 0x01a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_15_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_15_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa6, 0xa8 },
+
+ { 0xb4, 0xb8 },
+ { 0xbc, 0xbd },
+ { 0xbe, 0xff },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_15 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-15", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_16.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_16.c
new file mode 100644
index 000000000..22a653a57
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_16.c
@@ -0,0 +1,220 @@
+/**********************************************************************
+ iso8859_16.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_16_TO_LOWER_CASE(c) EncISO_8859_16_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_16_CTYPE(code,ctype) \
+ ((EncISO_8859_16_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_16_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\242', '\242', '\263', '\245', '\245', '\250', '\247',
+ '\250', '\251', '\272', '\253', '\256', '\255', '\256', '\277',
+ '\260', '\261', '\271', '\263', '\270', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\275', '\275', '\377', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_16_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x30e2, 0x34a2, 0x00a0, 0x01a0, 0x34a2, 0x00a0,
+ 0x30e2, 0x00a0, 0x34a2, 0x01a0, 0x34a2, 0x01a0, 0x30e2, 0x34a2,
+ 0x00a0, 0x00a0, 0x34a2, 0x30e2, 0x34a2, 0x01a0, 0x00a0, 0x01a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x01a0, 0x34a2, 0x30e2, 0x34a2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_16_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_16_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xa2 },
+ { 0xa3, 0xb3 },
+ { 0xa6, 0xa8 },
+ { 0xaa, 0xba },
+ { 0xac, 0xae },
+ { 0xaf, 0xbf },
+
+ { 0xb2, 0xb9 },
+ { 0xb4, 0xb8 },
+ { 0xbc, 0xbd },
+ { 0xbe, 0xff },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_16 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-16", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_2.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_2.c
new file mode 100644
index 000000000..dc3d0a141
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_2.c
@@ -0,0 +1,218 @@
+/**********************************************************************
+ iso8859_2.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_2_TO_LOWER_CASE(c) EncISO_8859_2_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_2_CTYPE(code,ctype) \
+ ((EncISO_8859_2_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_2_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\261', '\242', '\263', '\244', '\265', '\266', '\247',
+ '\250', '\271', '\272', '\273', '\274', '\255', '\276', '\277',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_2_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x00a0, 0x34a2, 0x00a0, 0x34a2, 0x34a2, 0x00a0,
+ 0x00a0, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x34a2, 0x34a2,
+ 0x00a0, 0x30e2, 0x00a0, 0x30e2, 0x00a0, 0x30e2, 0x30e2, 0x00a0,
+ 0x00a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_2_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xb1 },
+ { 0xa3, 0xb3 },
+ { 0xa5, 0xb5 },
+ { 0xa6, 0xb6 },
+ { 0xa9, 0xb9 },
+ { 0xaa, 0xba },
+ { 0xab, 0xbb },
+ { 0xac, 0xbc },
+ { 0xae, 0xbe },
+ { 0xaf, 0xbf },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_2_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingISO_8859_2 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-2", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_3.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_3.c
new file mode 100644
index 000000000..49dc6b205
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_3.c
@@ -0,0 +1,214 @@
+/**********************************************************************
+ iso8859_3.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_3_TO_LOWER_CASE(c) EncISO_8859_3_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_3_CTYPE(code,ctype) \
+ ((EncISO_8859_3_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_3_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\261', '\242', '\243', '\244', '\245', '\266', '\247',
+ '\250', '\271', '\272', '\273', '\274', '\255', '\256', '\277',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\303', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\320', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_3_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x00a0, 0x00a0, 0x00a0, 0x0000, 0x34a2, 0x00a0,
+ 0x00a0, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x0000, 0x34a2,
+ 0x00a0, 0x30e2, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x30e2, 0x01a0,
+ 0x00a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x11a0, 0x0000, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x0000, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x0000, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x0000, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x0000, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag, const UChar** pp,
+ const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_3_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_3_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xb1 },
+ { 0xa6, 0xb6 },
+ { 0xa9, 0xb9 },
+ { 0xaa, 0xba },
+ { 0xab, 0xbb },
+ { 0xac, 0xbc },
+ { 0xaf, 0xbf },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_3 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-3", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_4.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_4.c
new file mode 100644
index 000000000..f3f6ba96f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_4.c
@@ -0,0 +1,217 @@
+/**********************************************************************
+ iso8859_4.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_4_TO_LOWER_CASE(c) EncISO_8859_4_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_4_CTYPE(code,ctype) \
+ ((EncISO_8859_4_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_4_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\261', '\242', '\263', '\244', '\265', '\266', '\247',
+ '\250', '\271', '\272', '\273', '\274', '\255', '\276', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\277', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_4_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x30e2, 0x34a2, 0x00a0, 0x34a2, 0x34a2, 0x00a0,
+ 0x00a0, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x34a2, 0x00a0,
+ 0x00a0, 0x30e2, 0x00a0, 0x30e2, 0x00a0, 0x30e2, 0x30e2, 0x00a0,
+ 0x00a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x34a2, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_4_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_4_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xb1 },
+ { 0xa3, 0xb3 },
+ { 0xa5, 0xb5 },
+ { 0xa6, 0xb6 },
+ { 0xa9, 0xb9 },
+ { 0xaa, 0xba },
+ { 0xab, 0xbb },
+ { 0xac, 0xbc },
+ { 0xae, 0xbe },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_4 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-4", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_5.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_5.c
new file mode 100644
index 000000000..a5f587c72
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_5.c
@@ -0,0 +1,218 @@
+/**********************************************************************
+ iso8859_5.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_5_TO_LOWER_CASE(c) EncISO_8859_5_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_5_CTYPE(code,ctype) \
+ ((EncISO_8859_5_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_5_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\255', '\376', '\377',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_5_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x00a0, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ *lower = ENC_ISO_8859_5_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_5_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa1, 0xf1 },
+ { 0xa2, 0xf2 },
+ { 0xa3, 0xf3 },
+ { 0xa4, 0xf4 },
+ { 0xa5, 0xf5 },
+ { 0xa6, 0xf6 },
+ { 0xa7, 0xf7 },
+ { 0xa8, 0xf8 },
+ { 0xa9, 0xf9 },
+ { 0xaa, 0xfa },
+ { 0xab, 0xfb },
+ { 0xac, 0xfc },
+ { 0xae, 0xfe },
+ { 0xaf, 0xff },
+
+ { 0xb0, 0xd0 },
+ { 0xb1, 0xd1 },
+ { 0xb2, 0xd2 },
+ { 0xb3, 0xd3 },
+ { 0xb4, 0xd4 },
+ { 0xb5, 0xd5 },
+ { 0xb6, 0xd6 },
+ { 0xb7, 0xd7 },
+ { 0xb8, 0xd8 },
+ { 0xb9, 0xd9 },
+ { 0xba, 0xda },
+ { 0xbb, 0xdb },
+ { 0xbc, 0xdc },
+ { 0xbd, 0xdd },
+ { 0xbe, 0xde },
+ { 0xbf, 0xdf },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end,
+ OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_5 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-5", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_6.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_6.c
new file mode 100644
index 000000000..fb724420c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_6.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+ iso8859_6.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_IS_ISO_8859_6_CTYPE(code,ctype) \
+ ((EncISO_8859_6_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const unsigned short EncISO_8859_6_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x0000, 0x0000, 0x0000, 0x00a0, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x01a0, 0x01a0, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x01a0, 0x0000, 0x0000, 0x0000, 0x01a0,
+ 0x0000, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_6_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingISO_8859_6 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-6", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ onigenc_ascii_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_7.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_7.c
new file mode 100644
index 000000000..018efac72
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_7.c
@@ -0,0 +1,206 @@
+/**********************************************************************
+ iso8859_7.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_7_TO_LOWER_CASE(c) EncISO_8859_7_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_7_CTYPE(code,ctype) \
+ ((EncISO_8859_7_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_7_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\334', '\267',
+ '\335', '\336', '\337', '\273', '\374', '\275', '\375', '\376',
+ '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\322', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_7_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x01a0, 0x00a0, 0x0000, 0x0000, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x0000, 0x01a0, 0x00a0, 0x01a0, 0x0000, 0x01a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x00a0, 0x34a2, 0x01a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x01a0, 0x34a2, 0x10a0, 0x34a2, 0x34a2,
+ 0x30e2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x0000, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x0000
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ *lower = ENC_ISO_8859_7_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_7_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xb6, 0xdc },
+ { 0xb8, 0xdd },
+ { 0xb9, 0xde },
+ { 0xba, 0xdf },
+ { 0xbc, 0xfc },
+ { 0xbe, 0xfd },
+ { 0xbf, 0xfe },
+
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, p, end, items);
+}
+
+
+OnigEncodingType OnigEncodingISO_8859_7 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-7", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_8.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_8.c
new file mode 100644
index 000000000..92a5eb118
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_8.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+ iso8859_8.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_IS_ISO_8859_8_CTYPE(code,ctype) \
+ ((EncISO_8859_8_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const unsigned short EncISO_8859_8_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x0000, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x01a0, 0x00a0, 0x01a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x00a0, 0x01a0,
+ 0x00a0, 0x10a0, 0x00a0, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01a0,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2, 0x30a2,
+ 0x30a2, 0x30a2, 0x30a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_8_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+OnigEncodingType OnigEncodingISO_8859_8 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-8", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ onigenc_ascii_mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_9.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_9.c
new file mode 100644
index 000000000..1f9bdead5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/iso8859_9.c
@@ -0,0 +1,207 @@
+/**********************************************************************
+ iso8859_9.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_ISO_8859_9_TO_LOWER_CASE(c) EncISO_8859_9_ToLowerCaseTable[c]
+#define ENC_IS_ISO_8859_9_CTYPE(code,ctype) \
+ ((EncISO_8859_9_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncISO_8859_9_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\335', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static const unsigned short EncISO_8859_9_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x30e2, 0x01a0, 0x00a0, 0x01a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x00a0, 0x01a0,
+ 0x00a0, 0x10a0, 0x30e2, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x01a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+static int
+mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (*p == 0xdf && (flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ *lower++ = 's';
+ *lower = 's';
+ (*pp)++;
+ return 2;
+ }
+
+ *lower = ENC_ISO_8859_9_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_ISO_8859_9_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe }
+};
+
+static int
+apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, f, arg);
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 1,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingISO_8859_9 = {
+ onigenc_single_byte_mbc_enc_len,
+ "ISO-8859-9", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ mbc_case_fold,
+ apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8.c
new file mode 100644
index 000000000..37023c697
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8.c
@@ -0,0 +1,236 @@
+/**********************************************************************
+ koi8.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_KOI8_TO_LOWER_CASE(c) EncKOI8_ToLowerCaseTable[c]
+#define ENC_IS_KOI8_CTYPE(code,ctype) \
+ ((EncKOI8_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncKOI8_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337'
+};
+
+static const unsigned short EncKOI8_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2
+};
+
+
+static int
+koi8_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ *lower = ENC_KOI8_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+koi8_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_KOI8_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe },
+ { 0xdf, 0xff },
+
+ { 0xe0, 0xc0 },
+ { 0xe1, 0xc1 },
+ { 0xe2, 0xc2 },
+ { 0xe3, 0xc3 },
+ { 0xe4, 0xc4 },
+ { 0xe5, 0xc5 },
+ { 0xe6, 0xc6 },
+ { 0xe7, 0xc7 },
+ { 0xe8, 0xc8 },
+ { 0xe9, 0xc9 },
+ { 0xea, 0xca },
+ { 0xeb, 0xcb },
+ { 0xec, 0xcc },
+ { 0xed, 0xcd },
+ { 0xee, 0xce },
+ { 0xef, 0xcf },
+
+ { 0xf0, 0xd0 },
+ { 0xf1, 0xd1 },
+ { 0xf2, 0xd2 },
+ { 0xf3, 0xd3 },
+ { 0xf4, 0xd4 },
+ { 0xf5, 0xd5 },
+ { 0xf6, 0xd6 },
+ { 0xf7, 0xd7 },
+ { 0xf8, 0xd8 },
+ { 0xf9, 0xd9 },
+ { 0xfa, 0xda },
+ { 0xfb, 0xdb },
+ { 0xfc, 0xdc },
+ { 0xfe, 0xde },
+ { 0xff, 0xdf }
+};
+
+static int
+koi8_apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, f, arg);
+}
+
+static int
+koi8_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingKOI8 = {
+ onigenc_single_byte_mbc_enc_len,
+ "KOI8", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ koi8_mbc_case_fold,
+ koi8_apply_all_case_fold,
+ koi8_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ koi8_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8_r.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8_r.c
new file mode 100644
index 000000000..c77302fcc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/koi8_r.c
@@ -0,0 +1,204 @@
+/**********************************************************************
+ koi8_r.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+#define ENC_KOI8_R_TO_LOWER_CASE(c) EncKOI8_R_ToLowerCaseTable[c]
+#define ENC_IS_KOI8_R_CTYPE(code,ctype) \
+ ((EncKOI8_R_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const UChar EncKOI8_R_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\243', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337'
+};
+
+static const unsigned short EncKOI8_R_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x0284, 0x00a0, 0x00a0, 0x10a0, 0x01a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x30e2, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x34a2, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2
+};
+
+static int
+koi8_r_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ *lower = ENC_KOI8_R_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+}
+
+static int
+koi8_r_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (code < 256)
+ return ENC_IS_KOI8_R_CTYPE(code, ctype);
+ else
+ return FALSE;
+}
+
+static const OnigPairCaseFoldCodes CaseFoldMap[] = {
+ { 0xa3, 0xb3 },
+
+ { 0xc0, 0xe0 },
+ { 0xc1, 0xe1 },
+ { 0xc2, 0xe2 },
+ { 0xc3, 0xe3 },
+ { 0xc4, 0xe4 },
+ { 0xc5, 0xe5 },
+ { 0xc6, 0xe6 },
+ { 0xc7, 0xe7 },
+ { 0xc8, 0xe8 },
+ { 0xc9, 0xe9 },
+ { 0xca, 0xea },
+ { 0xcb, 0xeb },
+ { 0xcc, 0xec },
+ { 0xcd, 0xed },
+ { 0xce, 0xee },
+ { 0xcf, 0xef },
+
+ { 0xd0, 0xf0 },
+ { 0xd1, 0xf1 },
+ { 0xd2, 0xf2 },
+ { 0xd3, 0xf3 },
+ { 0xd4, 0xf4 },
+ { 0xd5, 0xf5 },
+ { 0xd6, 0xf6 },
+ { 0xd7, 0xf7 },
+ { 0xd8, 0xf8 },
+ { 0xd9, 0xf9 },
+ { 0xda, 0xfa },
+ { 0xdb, 0xfb },
+ { 0xdc, 0xfc },
+ { 0xdd, 0xfd },
+ { 0xde, 0xfe },
+ { 0xdf, 0xff }
+};
+
+static int
+koi8_r_apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ return onigenc_apply_all_case_fold_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, f, arg);
+}
+
+static int
+koi8_r_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_get_case_fold_codes_by_str_with_map(
+ sizeof(CaseFoldMap)/sizeof(OnigPairCaseFoldCodes), CaseFoldMap, 0,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingKOI8_R = {
+ onigenc_single_byte_mbc_enc_len,
+ "KOI8-R", /* name */
+ 1, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ onigenc_single_byte_mbc_to_code,
+ onigenc_single_byte_code_to_mbclen,
+ onigenc_single_byte_code_to_mbc,
+ koi8_r_mbc_case_fold,
+ koi8_r_apply_all_case_fold,
+ koi8_r_get_case_fold_codes_by_str,
+ onigenc_minimum_property_name_to_ctype,
+ koi8_r_is_code_ctype,
+ onigenc_not_support_get_ctype_code_range,
+ onigenc_single_byte_left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ onigenc_always_true_is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_property.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_property.sh
new file mode 100755
index 000000000..cef0a9614
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_property.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+GPERF=gperf
+
+TMP1=gperf1.tmp
+TMP2=gperf2.tmp
+
+GPERF_OPT='-pt -T -L ANSI-C'
+
+ADD_CAST='s/return +len +\+ +asso_values/return (unsigned int )len + asso_values/'
+
+${GPERF} ${GPERF_OPT} -N onigenc_euc_jp_lookup_property_name --output-file ${TMP1} euc_jp_prop.gperf
+cat ${TMP1} | sed -r "${ADD_CAST}" > euc_jp_prop.c
+
+${GPERF} ${GPERF_OPT} -N onigenc_sjis_lookup_property_name --output-file ${TMP2} sjis_prop.gperf
+cat ${TMP2} | sed -r "${ADD_CAST}" > sjis_prop.c
+
+rm -f ${TMP1} ${TMP2}
+
+exit 0
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb.sh
new file mode 100755
index 000000000..89cfa18cb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+NAME=unicode_egcb_data
+
+./make_unicode_egcb_data.py > ${NAME}.c
+
+exit 0
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb_data.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb_data.py
new file mode 100755
index 000000000..9c71796fd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_egcb_data.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# make_unicode_egcb_data.py
+# Copyright (c) 2017-2019 K.Kosako
+
+import sys
+import re
+
+MAX_CODE_POINT = 0x10ffff
+
+PR_TOTAL_REG = re.compile("#\s*Total\s+(?:code\s+points|elements):")
+PR_LINE_REG = re.compile("([0-9A-Fa-f]+)(?:..([0-9A-Fa-f]+))?\s*;\s*(\w+)")
+PA_LINE_REG = re.compile("(\w+)\s*;\s*(\w+)")
+PVA_LINE_REG = re.compile("(sc|gc)\s*;\s*(\w+)\s*;\s*(\w+)(?:\s*;\s*(\w+))?")
+BL_LINE_REG = re.compile("([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+)\s*;\s*(.*)")
+VERSION_REG = re.compile("#\s*.*-(\d+)\.(\d+)\.(\d+)\.txt")
+
+VERSION_INFO = [-1, -1, -1]
+DIC = { }
+PROPS = []
+PropIndex = { }
+
+def check_version_info(s):
+ m = VERSION_REG.match(s)
+ if m is not None:
+ VERSION_INFO[0] = int(m.group(1))
+ VERSION_INFO[1] = int(m.group(2))
+ VERSION_INFO[2] = int(m.group(3))
+
+def print_ranges(ranges):
+ for (start, end) in ranges:
+ print "0x%06x, 0x%06x" % (start, end)
+
+def print_prop_and_index(prop, i):
+ print "%-35s %3d" % (prop + ',', i)
+ PropIndex[prop] = i
+
+def dic_find_by_value(dic, v):
+ for key, val in dic.items():
+ if val == v:
+ return key
+
+ return None
+
+
+def normalize_ranges(in_ranges, sort=False):
+ if sort:
+ ranges = sorted(in_ranges)
+ else:
+ ranges = in_ranges
+
+ r = []
+ prev = None
+ for (start, end) in ranges:
+ if prev >= start - 1:
+ (pstart, pend) = r.pop()
+ end = max(pend, end)
+ start = pstart
+
+ r.append((start, end))
+ prev = end
+
+ return r
+
+def inverse_ranges(in_ranges):
+ r = []
+ prev = 0x000000
+ for (start, end) in in_ranges:
+ if prev < start:
+ r.append((prev, start - 1))
+
+ prev = end + 1
+
+ if prev < MAX_CODE_POINT:
+ r.append((prev, MAX_CODE_POINT))
+
+ return r
+
+def add_ranges(r1, r2):
+ r = r1 + r2
+ return normalize_ranges(r, True)
+
+def sub_one_range(one_range, rs):
+ r = []
+ (s1, e1) = one_range
+ n = len(rs)
+ for i in range(0, n):
+ (s2, e2) = rs[i]
+ if s2 >= s1 and s2 <= e1:
+ if s2 > s1:
+ r.append((s1, s2 - 1))
+ if e2 >= e1:
+ return r
+
+ s1 = e2 + 1
+ elif s2 < s1 and e2 >= s1:
+ if e2 < e1:
+ s1 = e2 + 1
+ else:
+ return r
+
+ r.append((s1, e1))
+ return r
+
+def sub_ranges(r1, r2):
+ r = []
+ for one_range in r1:
+ rs = sub_one_range(one_range, r2)
+ r.extend(rs)
+
+ return r
+
+def add_ranges_in_dic(dic):
+ r = []
+ for k, v in dic.items():
+ r = r + v
+
+ return normalize_ranges(r, True)
+
+def normalize_ranges_in_dic(dic, sort=False):
+ for k, v in dic.items():
+ r = normalize_ranges(v, sort)
+ dic[k] = r
+
+def merge_dic(to_dic, from_dic):
+ to_keys = to_dic.keys()
+ from_keys = from_dic.keys()
+ common = list(set(to_keys) & set(from_keys))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_dic: collision: %s" % sorted(common)
+
+ to_dic.update(from_dic)
+
+def merge_props(to_props, from_props):
+ common = list(set(to_props) & set(from_props))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_props: collision: %s" % sorted(common)
+
+ to_props.extend(from_props)
+
+def add_range_into_dic(dic, name, start, end):
+ d = dic.get(name, None)
+ if d is None:
+ d = [(start, end)]
+ dic[name] = d
+ else:
+ d.append((start, end))
+
+def list_sub(a, b):
+ x = set(a) - set(b)
+ return list(x)
+
+def parse_properties(path):
+ with open(path, 'r') as f:
+ dic = { }
+ prop = None
+ props = []
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ if s[0] == '#':
+ if VERSION_INFO[0] < 0:
+ check_version_info(s)
+
+ m = PR_LINE_REG.match(s)
+ if m:
+ prop = m.group(3)
+ if m.group(2):
+ start = int(m.group(1), 16)
+ end = int(m.group(2), 16)
+ add_range_into_dic(dic, prop, start, end)
+ else:
+ start = int(m.group(1), 16)
+ add_range_into_dic(dic, prop, start, start)
+
+ elif PR_TOTAL_REG.match(s) is not None:
+ props.append(prop)
+
+ normalize_ranges_in_dic(dic)
+ return (dic, props)
+
+
+### main ###
+argv = sys.argv
+argc = len(argv)
+
+dic, props = parse_properties('GraphemeBreakProperty.txt')
+merge_dic(DIC, dic)
+merge_props(PROPS, props)
+
+PROPS = sorted(PROPS)
+
+print '/* unicode_egcb_data.c: Generated by make_unicode_egcb_data.py. */'
+COPYRIGHT = '''
+/*-
+ * Copyright (c) 2017-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+'''.strip()
+
+print COPYRIGHT
+print ''
+if VERSION_INFO[0] < 0:
+ raise RuntimeError("Version is not found")
+
+print "#define GRAPHEME_BREAK_PROPERTY_VERSION %02d%02d%02d" % (VERSION_INFO[0], VERSION_INFO[1], VERSION_INFO[2])
+print ''
+
+ranges = []
+for prop in PROPS:
+ rs = DIC[prop]
+ for (start, end) in rs:
+ ranges.append((start, end, prop))
+
+ranges = sorted(ranges, key=lambda x: x[0])
+
+prev = -1
+for (start, end, prop) in ranges:
+ if prev >= start:
+ raise ValueError("{2}:{0} - {1} range overlap prev value {3}".format(start, end, prop, prev))
+
+
+print '/*'
+for prop in PROPS:
+ print "%s" % prop
+print '*/'
+print ''
+
+num_ranges = len(ranges)
+print "static int EGCB_RANGE_NUM = %d;" % num_ranges
+
+print 'static EGCB_RANGE_TYPE EGCB_RANGES[] = {'
+for i, (start, end, prop) in enumerate(ranges):
+ if i == num_ranges - 1:
+ comma = ''
+ else:
+ comma = ','
+
+ type_name = 'EGCB_' + prop
+ print " {0x%06x, 0x%06x, %s }%s" % (start, end, type_name, comma)
+
+print '};'
+
+sys.exit(0)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold.sh
new file mode 100755
index 000000000..1d5cc1e17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+GPERF=gperf
+
+TMP0=gperf0.tmp
+TMP1=gperf1.tmp
+TMP2=gperf2.tmp
+TMP3=gperf3.tmp
+
+GPERF_OPT='-n -C -T -c -t -j1 -L ANSI-C '
+
+./make_unicode_fold_data.py > unicode_fold_data.c
+
+${GPERF} ${GPERF_OPT} -F,-1,0 -N onigenc_unicode_unfold_key unicode_unfold_key.gperf > ${TMP0}
+./gperf_unfold_key_conv.py < ${TMP0} > unicode_unfold_key.c
+
+${GPERF} ${GPERF_OPT} -F,-1 -N onigenc_unicode_fold1_key unicode_fold1_key.gperf > ${TMP1}
+./gperf_fold_key_conv.py 1 < ${TMP1} > unicode_fold1_key.c
+
+${GPERF} ${GPERF_OPT} -F,-1 -N onigenc_unicode_fold2_key unicode_fold2_key.gperf > ${TMP2}
+./gperf_fold_key_conv.py 2 < ${TMP2} > unicode_fold2_key.c
+
+${GPERF} ${GPERF_OPT} -F,-1 -N onigenc_unicode_fold3_key unicode_fold3_key.gperf > ${TMP3}
+./gperf_fold_key_conv.py 3 < ${TMP3} > unicode_fold3_key.c
+
+# remove redundant EOLs before EOF
+perl -i -pe 'BEGIN{undef $/}s/\n\n*\z/\n/;' unicode_fold_data.c
+perl -i -pe 'BEGIN{undef $/}s/\n\n*\z/\n/;' unicode_fold1_key.c
+perl -i -pe 'BEGIN{undef $/}s/\n\n*\z/\n/;' unicode_fold2_key.c
+perl -i -pe 'BEGIN{undef $/}s/\n\n*\z/\n/;' unicode_fold3_key.c
+perl -i -pe 'BEGIN{undef $/}s/\n\n*\z/\n/;' unicode_unfold_key.c
+
+rm -f ${TMP0} ${TMP1} ${TMP2} ${TMP3}
+rm -f unicode_unfold_key.gperf unicode_fold1_key.gperf unicode_fold2_key.gperf unicode_fold3_key.gperf
+
+exit 0
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold_data.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold_data.py
new file mode 100755
index 000000000..0e6c6354f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_fold_data.py
@@ -0,0 +1,486 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# make_unicode_fold_data.py
+# Copyright (c) 2016-2020 K.Kosako
+
+import sys
+import re
+
+SOURCE_FILE = 'CaseFolding.txt'
+GPERF_UNFOLD_KEY_FILE = 'unicode_unfold_key.gperf'
+GPERF_FOLD_KEY_FILES = ['unicode_fold1_key.gperf', 'unicode_fold2_key.gperf', 'unicode_fold3_key.gperf']
+
+
+DataName = 'OnigUnicodeFolds'
+
+ENCODING = 'utf-8'
+
+LINE_REG = re.compile("([0-9A-F]{1,6}); (.); ([0-9A-F]{1,6})(?: ([0-9A-F]{1,6}))?(?: ([0-9A-F]{1,6}))?;(?:\s*#\s*)(.*)")
+VERSION_REG = re.compile("#.*-(\d+)\.(\d+)\.(\d+)\.txt")
+
+VERSION_INFO = [-1, -1, -1]
+
+FOLDS = {}
+TURKISH_FOLDS = {}
+LOCALE_FOLDS = {}
+
+UNFOLDS = {}
+TURKISH_UNFOLDS = {}
+LOCALE_UNFOLDS = {}
+
+COPYRIGHT = '''
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+'''.strip()
+
+
+class Entry:
+ def __init__(self, fold):
+ self.fold = fold
+ self.unfolds = []
+ self.fold_len = len(fold)
+ self.index = -1
+ self.comment = None
+
+def fold_key(fold):
+ sfold = map(lambda i: "%06x" % i, fold)
+ return ':'.join(sfold)
+
+def form16(x, size):
+ form = "0x%06x" if x > 0xffff else "0x%04x"
+ s = form % x
+ rem = size - len(s)
+ if rem > 0:
+ s = ' ' * rem + s
+
+ return s
+
+def form3bytes(x):
+ x0 = x & 0xff
+ x1 = (x>>8) & 0xff
+ x2 = (x>>16) & 0xff
+ return "\\x%02x\\x%02x\\x%02x" % (x2, x1, x0)
+
+def enc_len(code, encode):
+ u = unichr(code)
+ s = u.encode(encode)
+ return len(s)
+
+def check_version_info(s):
+ m = VERSION_REG.match(s)
+ if m is not None:
+ VERSION_INFO[0] = int(m.group(1))
+ VERSION_INFO[1] = int(m.group(2))
+ VERSION_INFO[2] = int(m.group(3))
+
+def parse_line(s):
+ if len(s) == 0:
+ return False
+ if s[0] == '#':
+ if VERSION_INFO[0] < 0:
+ check_version_info(s)
+ return False
+
+ m = LINE_REG.match(s)
+ if m is None:
+ print >> sys.stderr, s.encode(ENCODING)
+ sys.exit(-1)
+
+ s_unfold = m.group(1)
+ s_type = m.group(2)
+ s_fold = m.group(3)
+ comment = m.group(6)
+
+ if s_type == 'S':
+ return False;
+
+ unfold = int(s_unfold, 16)
+ f1 = int(s_fold, 16)
+ fold = [f1]
+ if m.group(4) is not None:
+ f2 = int(m.group(4), 16)
+ fold.append(f2)
+ if m.group(5) is not None:
+ f3 = int(m.group(5), 16)
+ fold.append(f3)
+
+ if s_type == 'T':
+ dic = TURKISH_FOLDS
+ undic = TURKISH_UNFOLDS
+ else:
+ dic = FOLDS
+ undic = UNFOLDS
+
+ key = fold_key(fold)
+ e = dic.get(key, None)
+ if e is None:
+ e = Entry(fold)
+ e.comment = comment
+ dic[key] = e
+
+ e.unfolds.append(unfold)
+
+ if undic.get(unfold, None) is not None:
+ print >> sys.stderr, ("unfold dup: 0x%04x %s\n" % (unfold, s_type))
+ undic[unfold] = e
+
+ return True
+
+def parse_file(f):
+ line = f.readline()
+ while line:
+ s = line.strip()
+ parse_line(s)
+ line = f.readline()
+
+def make_locale():
+ for unfold, te in TURKISH_UNFOLDS.items():
+ e = UNFOLDS.get(unfold, None)
+ if e is None:
+ continue
+
+ fkey = fold_key(e.fold)
+ if len(e.unfolds) == 1:
+ del FOLDS[fkey]
+ else:
+ e.unfolds.remove(unfold)
+ e = Entry(e.fold)
+ e.unfolds.append(unfold)
+
+ LOCALE_FOLDS[fkey] = e
+ LOCALE_UNFOLDS[unfold] = e
+ del UNFOLDS[unfold]
+
+def output_typedef(f):
+ s = """\
+typedef unsigned long OnigCodePoint;
+"""
+ print >> f, s
+
+def divide_by_fold_len(d):
+ l = d.items()
+ l1 = filter(lambda (k,e):e.fold_len == 1, l)
+ l2 = filter(lambda (k,e):e.fold_len == 2, l)
+ l3 = filter(lambda (k,e):e.fold_len == 3, l)
+ sl1 = sorted(l1, key=lambda (k,e):k)
+ sl2 = sorted(l2, key=lambda (k,e):k)
+ sl3 = sorted(l3, key=lambda (k,e):k)
+ return (sl1, sl2, sl3)
+
+def output_comment(f, s):
+ f.write(" /* %s */" % s)
+
+def output_data_n1(f, n, fn, c, out_comment):
+ for k, e in fn:
+ e.index = c
+ if out_comment and n > 1 and e.comment is not None:
+ output_comment(f, e.comment)
+ print >> f, ''
+
+ f.write(' ')
+ f.write("/*%4d*/ " % c)
+ for i in range(0, n):
+ s = form16(e.fold[i], 8)
+ f.write(" %s," % s)
+
+ usize = len(e.unfolds)
+ f.write(" %d," % usize)
+ for u in e.unfolds:
+ s = form16(u, 8)
+ f.write(" %s," % s)
+
+ if out_comment and n == 1 and e.comment is not None:
+ if len(e.comment) < 35:
+ s = e.comment
+ else:
+ s = e.comment[0:33] + '..'
+
+ output_comment(f, s)
+
+ f.write("\n")
+ c += n + 1 + usize
+
+ return c
+
+def output_data_n(f, name, n, fn, lfn, out_comment):
+ print >> f, "OnigCodePoint %s%d[] = {" % (name, n)
+ c = 0
+ c = output_data_n1(f, n, fn, c, out_comment)
+ print >> f, "#define FOLDS%d_NORMAL_END_INDEX %d" % (n, c)
+ print >> f, " /* ----- LOCALE ----- */"
+ c = output_data_n1(f, n, lfn, c, out_comment)
+ print >> f, "#define FOLDS%d_END_INDEX %d" % (n, c)
+ print >> f, "};"
+
+def output_fold_data(f, name, out_comment):
+ f1, f2, f3 = divide_by_fold_len(FOLDS)
+ lf1, lf2, lf3 = divide_by_fold_len(LOCALE_FOLDS)
+
+ output_data_n(f, name, 1, f1, lf1, out_comment)
+ print >> f, ''
+ output_data_n(f, name, 2, f2, lf2, out_comment)
+ print >> f, ''
+ output_data_n(f, name, 3, f3, lf3, out_comment)
+ print >> f, ''
+
+def output_macros(f, name):
+ print >> f, "#define FOLDS1_FOLD(i) (%s1 + (i))" % name
+ print >> f, "#define FOLDS2_FOLD(i) (%s2 + (i))" % name
+ print >> f, "#define FOLDS3_FOLD(i) (%s3 + (i))" % name
+
+ print >> f, "#define FOLDS1_UNFOLDS_NUM(i) %s1[(i)+1]" % name
+ print >> f, "#define FOLDS2_UNFOLDS_NUM(i) %s2[(i)+2]" % name
+ print >> f, "#define FOLDS3_UNFOLDS_NUM(i) %s3[(i)+3]" % name
+
+ print >> f, "#define FOLDS1_UNFOLDS(i) (%s1 + (i) + 2)" % name
+ print >> f, "#define FOLDS2_UNFOLDS(i) (%s2 + (i) + 3)" % name
+ print >> f, "#define FOLDS3_UNFOLDS(i) (%s3 + (i) + 4)" % name
+
+ print >> f, "#define FOLDS1_NEXT_INDEX(i) ((i) + 2 + %s1[(i)+1])" % name
+ print >> f, "#define FOLDS2_NEXT_INDEX(i) ((i) + 3 + %s1[(i)+2])" % name
+ print >> f, "#define FOLDS3_NEXT_INDEX(i) ((i) + 4 + %s1[(i)+3])" % name
+
+def output_fold_source(f, out_comment):
+ print >> f, "/* This file was generated by make_unicode_fold_data.py. */"
+ print >> f, COPYRIGHT
+ print >> f, "\n"
+ print >> f, '#include "regenc.h"'
+ print >> f, ''
+ if VERSION_INFO[0] < 0:
+ raise RuntimeError("Version is not found")
+
+ print "#define UNICODE_CASEFOLD_VERSION %02d%02d%02d" % (VERSION_INFO[0], VERSION_INFO[1], VERSION_INFO[2])
+ print ''
+ #output_macros(f, DataName)
+ print >> f, ''
+ #output_typedef(f)
+ output_fold_data(f, DataName, out_comment)
+
+
+def output_gperf_unfold_key(f):
+ head = "%{\n/* This gperf source file was generated by make_unicode_fold_data.py */\n\n" + COPYRIGHT + """\
+
+#include "regint.h"
+%}
+
+struct ByUnfoldKey {
+ OnigCodePoint code;
+ short int index;
+ short int fold_len;
+};
+%%
+"""
+ f.write(head)
+ UNFOLDS.update(LOCALE_UNFOLDS)
+ l = UNFOLDS.items()
+ sl = sorted(l, key=lambda (k,e):(e.fold_len, e.index))
+ for k, e in sl:
+ f.write('"%s", /*0x%04x*/ %4d, %d\n' %
+ (form3bytes(k), k, e.index, e.fold_len))
+
+ print >> f, '%%'
+
+def output_gperf_fold_key(f, key_len):
+ head = "%{\n/* This gperf source file was generated by make_unicode_fold_data.py */\n\n" + COPYRIGHT + """\
+
+#include "regint.h"
+%}
+
+short int
+%%
+"""
+ f.write(head)
+ l = FOLDS.items()
+ l = filter(lambda (k,e):e.fold_len == key_len, l)
+ sl = sorted(l, key=lambda (k,e):e.index)
+ for k, e in sl:
+ skey = ''.join(map(lambda i: form3bytes(i), e.fold))
+ f.write('"%s", %4d\n' % (skey, e.index))
+
+ print >> f, '%%'
+
+def output_gperf_source():
+ with open(GPERF_UNFOLD_KEY_FILE, 'w') as f:
+ output_gperf_unfold_key(f)
+
+ FOLDS.update(LOCALE_FOLDS)
+
+ for i in range(1, 4):
+ with open(GPERF_FOLD_KEY_FILES[i-1], 'w') as f:
+ output_gperf_fold_key(f, i)
+
+def unfolds_byte_length_check(encode):
+ l = UNFOLDS.items()
+ sl = sorted(l, key=lambda (k,e):(e.fold_len, e.index))
+ for unfold, e in sl:
+ key_len = enc_len(unfold, encode)
+ fold_len = sum(map(lambda c: enc_len(c, encode), e.fold))
+ if key_len > fold_len:
+ sfolds = ' '.join(map(lambda c: "0x%06x" % c, e.fold))
+ s = "%s byte length: %d > %d: 0x%06x => %s" % (encode, key_len, fold_len, unfold, sfolds)
+ print >> sys.stderr, s
+
+def double_fold_check():
+ l = UNFOLDS.items()
+ sl = sorted(l, key=lambda (k,e):(e.fold_len, e.index))
+ for unfold, e in sl:
+ for f in e.fold:
+ #print >> sys.stderr, ("check 0x%06x" % f)
+ e2 = UNFOLDS.get(f)
+ if e2 is not None:
+ s = "double folds: 0x%06x => %s, 0x%06x => %s" % (unfold, e.fold, f, e2.fold)
+ print >> sys.stderr, s
+
+def unfold_is_multi_code_folds_head_check():
+ l = UNFOLDS.items()
+ l2 = filter(lambda (k,e):e.fold_len == 2, l)
+ l3 = filter(lambda (k,e):e.fold_len == 3, l)
+ sl = sorted(l, key=lambda (k,e):(e.fold_len, e.index))
+ for unfold, _ in sl:
+ for k, e in l2:
+ if e.fold[0] == unfold:
+ s = "unfold 0x%06x is multi-code fold head in %s" % (unfold, e.fold)
+ print >> sys.stderr, s
+ for k, e in l3:
+ if e.fold[0] == unfold:
+ s = "unfold 0x%06x is multi-code fold head in %s" % (unfold, e.fold)
+ print >> sys.stderr, s
+
+def make_one_folds(l):
+ h = {}
+ for unfold, e in l:
+ if e.fold_len != 1:
+ continue
+ fold = e.fold[0]
+ unfolds = h.get(fold)
+ if unfolds is None:
+ unfolds = [unfold]
+ h[fold] = unfolds
+ else:
+ unfolds.append(unfold)
+
+ return h
+
+def make_foldn_heads(l, fold_len, one_folds):
+ h = {}
+ for unfold, e in l:
+ if e.fold_len != fold_len:
+ continue
+ unfolds = one_folds.get(e.fold[0])
+ h[e.fold[0]] = (e, unfolds)
+
+ return h
+
+def fold2_expansion_num(e, one_folds):
+ n = len(e.unfolds)
+ n0 = 1
+ u0 = one_folds.get(e.fold[0])
+ if u0 is not None:
+ n0 += len(u0)
+ n1 = 1
+ u1 = one_folds.get(e.fold[1])
+ if u1 is not None:
+ n1 += len(u1)
+ n += (n0 * n1)
+ return n
+
+def fold3_expansion_num(e, one_folds):
+ n = len(e.unfolds)
+ n0 = 1
+ u0 = one_folds.get(e.fold[0])
+ if u0 is not None:
+ n0 += len(u0)
+ n1 = 1
+ u1 = one_folds.get(e.fold[1])
+ if u1 is not None:
+ n1 += len(u1)
+ n2 = 1
+ u2 = one_folds.get(e.fold[2])
+ if u2 is not None:
+ n2 += len(u2)
+ n += (n0 * n1 * n2)
+ return n
+
+def get_all_folds_expansion_num(x, one_folds, fold2_heads, fold3_heads):
+ e = UNFOLDS[x]
+ n = 0
+ if e.fold_len == 1:
+ n1 = len(e.unfolds) + 1 # +1: fold
+ fx = e.fold[0]
+ r = fold2_heads.get(fx)
+ n2 = n3 = 0
+ if r is not None:
+ e2, _ = r
+ n2 = fold2_expansion_num(e2, one_folds)
+ r = fold3_heads.get(fx)
+ if r is not None:
+ e3, _ = r
+ n3 = fold3_expansion_num(e3, one_folds)
+ n = max(n1, n2, n3)
+ elif e.fold_len == 2:
+ n = fold2_expansion_num(e, one_folds)
+ elif e.fold_len == 3:
+ n = fold3_expansion_num(e, one_folds)
+ else:
+ raise RuntimeError("Invalid fold_len %d" % (e.fold_len))
+
+ return n
+
+def get_all_folds_expansion_max_num():
+ l = UNFOLDS.items()
+ one_folds = make_one_folds(l)
+ fold2_heads = make_foldn_heads(l, 2, one_folds)
+ fold3_heads = make_foldn_heads(l, 3, one_folds)
+ sl = sorted(l, key=lambda (k,e):(e.fold_len, e.index))
+ nmax = 0
+ max_unfold = None
+ for unfold, e in sl:
+ n = get_all_folds_expansion_num(unfold, one_folds, fold2_heads, fold3_heads)
+ if nmax < n:
+ nmax = n
+ max_unfold = unfold
+
+ return (nmax, max_unfold)
+
+## main ##
+with open(SOURCE_FILE, 'r') as f:
+ parse_file(f)
+
+make_locale()
+
+out_comment = True
+output_fold_source(sys.stdout, out_comment)
+
+output_gperf_source()
+
+#unfolds_byte_length_check('utf-8')
+#unfolds_byte_length_check('utf-16')
+double_fold_check()
+unfold_is_multi_code_folds_head_check()
+
+#max_num, max_code = get_all_folds_expansion_max_num()
+#max_num -= 1 # remove self
+#print >> sys.stderr, "max expansion: 0x%06x: %d" % (max_code, max_num)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property.sh
new file mode 100755
index 000000000..51c895147
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+GPERF=gperf
+
+NAME=unicode_property_data
+TMP1=gperf1.tmp
+TMP2=gperf2.tmp
+TMP=
+
+GPERF_OPT='-T -C -c -t -j1 -L ANSI-C --ignore-case --pic -Q unicode_prop_name_pool'
+POOL_CAST='s/\(int *\)\(size_t *\)&\(\(struct +unicode_prop_name_pool_t *\* *\) *0\)->unicode_prop_name_pool_str([^,]+)/pool_offset(\1)/g'
+ADD_STATIC='s/(const +struct +PoolPropertyNameCtype +\*)/static \1/'
+ADD_CAST='s/unsigned +int +hval *= *len/unsigned int hval = (unsigned int )len/'
+
+./make_unicode_property_data.py > ${NAME}.gperf
+./make_unicode_property_data.py -posix > ${NAME}_posix.gperf
+
+${GPERF} ${GPERF_OPT} -N unicode_lookup_property_name --output-file ${TMP1} ${NAME}.gperf
+cat ${TMP1} | sed -e 's/^#line.*$//g' | sed -r "${POOL_CAST}" | sed -r "${ADD_STATIC}" | sed -r "${ADD_CAST}" > ${NAME}.c
+
+${GPERF} ${GPERF_OPT} -N unicode_lookup_property_name --output-file ${TMP2} ${NAME}_posix.gperf
+cat ${TMP2} | sed -e 's/^#line.*$//g' | sed -r "${POOL_CAST}" | sed -r "${ADD_STATIC}" > ${NAME}_posix.c
+
+rm -f ${NAME}.gperf ${NAME}_posix.gperf ${TMP1} ${TMP2}
+
+exit 0
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property_data.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property_data.py
new file mode 100755
index 000000000..9776628f5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_property_data.py
@@ -0,0 +1,605 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# make_unicode_property_data.py
+# Copyright (c) 2016-2019 K.Kosako
+
+import sys
+import re
+
+POSIX_LIST = [
+ 'NEWLINE', 'Alpha', 'Blank', 'Cntrl', 'Digit', 'Graph', 'Lower',
+ 'Print', 'Punct', 'Space', 'Upper', 'XDigit', 'Word', 'Alnum', 'ASCII'
+]
+
+MAX_CODE_POINT = 0x10ffff
+
+GRAPHEME_CLUSTER_BREAK_NAME_PREFIX = 'Grapheme_Cluster_Break_'
+
+UD_FIRST_REG = re.compile("<.+,\s*First>")
+UD_LAST_REG = re.compile("<.+,\s*Last>")
+PR_TOTAL_REG = re.compile("#\s*Total\s+(?:code\s+points|elements):")
+PR_LINE_REG = re.compile("([0-9A-Fa-f]+)(?:..([0-9A-Fa-f]+))?\s*;\s*(\w+)")
+PA_LINE_REG = re.compile("(\w+)\s*;\s*(\w+)")
+PVA_LINE_REG = re.compile("(sc|gc)\s*;\s*(\w+)\s*;\s*(\w+)(?:\s*;\s*(\w+))?")
+BL_LINE_REG = re.compile("([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+)\s*;\s*(.*)")
+UNICODE_VERSION_REG = re.compile("#\s*.*-(\d+)\.(\d+)\.(\d+)\.txt")
+EMOJI_VERSION_REG = re.compile("(?i)#\s*Version:\s*(\d+)\.(\d+)")
+
+VERSION_INFO = [-1, -1, -1]
+EMOJI_VERSION_INFO = [-1, -1]
+
+DIC = { }
+KDIC = { }
+PropIndex = { }
+PROPERTY_NAME_MAX_LEN = 0
+PROPS = None
+
+def normalize_prop_name(name):
+ name = re.sub(r'[ _]', '', name)
+ name = name.lower()
+ return name
+
+def fix_block_name(name):
+ s = re.sub(r'[- ]+', '_', name)
+ return 'In_' + s
+
+def print_ranges(ranges):
+ for (start, end) in ranges:
+ print "0x%06x, 0x%06x" % (start, end)
+
+ print len(ranges)
+
+def print_prop_and_index(prop, i):
+ print "%-35s %3d" % (prop + ',', i)
+ PropIndex[prop] = i
+
+PRINT_CACHE = { }
+
+def print_property(prop, data, desc):
+ print ''
+ print "/* PROPERTY: '%s': %s */" % (prop, desc)
+
+ prev_prop = dic_find_by_value(PRINT_CACHE, data)
+ if prev_prop is not None:
+ print "#define CR_%s CR_%s" % (prop, prev_prop)
+ else:
+ PRINT_CACHE[prop] = data
+ print "static const OnigCodePoint"
+ print "CR_%s[] = { %d," % (prop, len(data))
+ for (start, end) in data:
+ print "0x%04x, 0x%04x," % (start, end)
+
+ print "}; /* END of CR_%s */" % prop
+
+
+def dic_find_by_value(dic, v):
+ for key, val in dic.items():
+ if val == v:
+ return key
+
+ return None
+
+def make_reverse_dic(dic):
+ rev = {}
+ for key, val in dic.items():
+ d = rev.get(val, None)
+ if d is None:
+ rev[val] = [key]
+ else:
+ d.append(key)
+
+ return rev
+
+def normalize_ranges(in_ranges, sort=False):
+ if sort:
+ ranges = sorted(in_ranges)
+ else:
+ ranges = in_ranges
+
+ r = []
+ prev = None
+ for (start, end) in ranges:
+ if prev >= start - 1:
+ (pstart, pend) = r.pop()
+ end = max(pend, end)
+ start = pstart
+
+ r.append((start, end))
+ prev = end
+
+ return r
+
+def inverse_ranges(in_ranges):
+ r = []
+ prev = 0x000000
+ for (start, end) in in_ranges:
+ if prev < start:
+ r.append((prev, start - 1))
+
+ prev = end + 1
+
+ if prev < MAX_CODE_POINT:
+ r.append((prev, MAX_CODE_POINT))
+
+ return r
+
+def add_ranges(r1, r2):
+ r = r1 + r2
+ return normalize_ranges(r, True)
+
+def sub_one_range(one_range, rs):
+ r = []
+ (s1, e1) = one_range
+ n = len(rs)
+ for i in range(0, n):
+ (s2, e2) = rs[i]
+ if s2 >= s1 and s2 <= e1:
+ if s2 > s1:
+ r.append((s1, s2 - 1))
+ if e2 >= e1:
+ return r
+
+ s1 = e2 + 1
+ elif s2 < s1 and e2 >= s1:
+ if e2 < e1:
+ s1 = e2 + 1
+ else:
+ return r
+
+ r.append((s1, e1))
+ return r
+
+def sub_ranges(r1, r2):
+ r = []
+ for one_range in r1:
+ rs = sub_one_range(one_range, r2)
+ r.extend(rs)
+
+ return r
+
+def add_ranges_in_dic(dic):
+ r = []
+ for k, v in dic.items():
+ r = r + v
+
+ return normalize_ranges(r, True)
+
+def normalize_ranges_in_dic(dic, sort=False):
+ for k, v in dic.items():
+ r = normalize_ranges(v, sort)
+ dic[k] = r
+
+def merge_dic(to_dic, from_dic):
+ to_keys = to_dic.keys()
+ from_keys = from_dic.keys()
+ common = list(set(to_keys) & set(from_keys))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_dic: collision: %s" % sorted(common)
+
+ to_dic.update(from_dic)
+
+def merge_props(to_props, from_props):
+ common = list(set(to_props) & set(from_props))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_props: collision: %s" % sorted(common)
+
+ to_props.extend(from_props)
+
+def add_range_into_dic(dic, name, start, end):
+ d = dic.get(name, None)
+ if d is None:
+ d = [(start, end)]
+ dic[name] = d
+ else:
+ d.append((start, end))
+
+def list_sub(a, b):
+ x = set(a) - set(b)
+ return list(x)
+
+
+def parse_unicode_data_file(f):
+ dic = { }
+ assigned = []
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+ if s[0] == '#':
+ continue
+
+ a = s.split(';')
+ code = int(a[0], 16)
+ desc = a[1]
+ prop = a[2]
+ if UD_FIRST_REG.match(desc) is not None:
+ start = code
+ end = None
+ elif UD_LAST_REG.match(desc) is not None:
+ end = code
+ else:
+ start = end = code
+
+ if end is not None:
+ assigned.append((start, end))
+ add_range_into_dic(dic, prop, start, end)
+ if len(prop) == 2:
+ add_range_into_dic(dic, prop[0:1], start, end)
+
+ normalize_ranges_in_dic(dic)
+ return dic, assigned
+
+def parse_properties(path, klass, prop_prefix = None, version_reg = None):
+ version_match = None
+ with open(path, 'r') as f:
+ dic = { }
+ prop = None
+ props = []
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ if s[0] == '#' and version_reg is not None and version_match is None:
+ version_match = version_reg.match(s)
+ if version_match is not None:
+ continue
+
+ m = PR_LINE_REG.match(s)
+ if m:
+ prop = m.group(3)
+ if prop_prefix is not None:
+ prop = prop_prefix + prop
+
+ if m.group(2):
+ start = int(m.group(1), 16)
+ end = int(m.group(2), 16)
+ add_range_into_dic(dic, prop, start, end)
+ else:
+ start = int(m.group(1), 16)
+ add_range_into_dic(dic, prop, start, start)
+
+ elif PR_TOTAL_REG.match(s) is not None:
+ KDIC[prop] = klass
+ props.append(prop)
+
+ normalize_ranges_in_dic(dic)
+ return (dic, props, version_match)
+
+def parse_property_aliases(path):
+ a = { }
+ with open(path, 'r') as f:
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ m = PA_LINE_REG.match(s)
+ if not(m):
+ continue
+
+ if m.group(1) == m.group(2):
+ continue
+
+ a[m.group(1)] = m.group(2)
+
+ return a
+
+def parse_property_value_aliases(path):
+ a = { }
+ with open(path, 'r') as f:
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ m = PVA_LINE_REG.match(s)
+ if not(m):
+ continue
+
+ cat = m.group(1)
+ x2 = m.group(2)
+ x3 = m.group(3)
+ x4 = m.group(4)
+ if cat == 'sc':
+ if x2 != x3:
+ a[x2] = x3
+ if x4 and x4 != x3:
+ a[x4] = x3
+ else:
+ if x2 != x3:
+ a[x3] = x2
+ if x4 and x4 != x2:
+ a[x4] = x2
+
+ return a
+
+def parse_blocks(path):
+ dic = { }
+ blocks = []
+ with open(path, 'r') as f:
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ m = BL_LINE_REG.match(s)
+ if not(m):
+ continue
+
+ start = int(m.group(1), 16)
+ end = int(m.group(2), 16)
+ block = fix_block_name(m.group(3))
+ add_range_into_dic(dic, block, start, end)
+ blocks.append(block)
+
+ noblock = fix_block_name('No_Block')
+ dic[noblock] = inverse_ranges(add_ranges_in_dic(dic))
+ blocks.append(noblock)
+ return dic, blocks
+
+def add_primitive_props(assigned):
+ DIC['Assigned'] = normalize_ranges(assigned)
+ DIC['Any'] = [(0x000000, 0x10ffff)]
+ DIC['ASCII'] = [(0x000000, 0x00007f)]
+ DIC['NEWLINE'] = [(0x00000a, 0x00000a)]
+ DIC['Cn'] = inverse_ranges(DIC['Assigned'])
+ DIC['C'].extend(DIC['Cn'])
+ DIC['C'] = normalize_ranges(DIC['C'], True)
+
+ d = []
+ d.extend(DIC['Ll'])
+ d.extend(DIC['Lt'])
+ d.extend(DIC['Lu'])
+ DIC['LC'] = normalize_ranges(d, True)
+
+def add_posix_props(dic):
+ alnum = []
+ alnum.extend(dic['Alphabetic'])
+ alnum.extend(dic['Nd']) # Nd == Decimal_Number
+ alnum = normalize_ranges(alnum, True)
+
+ blank = [(0x0009, 0x0009)]
+ blank.extend(dic['Zs']) # Zs == Space_Separator
+ blank = normalize_ranges(blank, True)
+
+ word = []
+ word.extend(dic['Alphabetic'])
+ word.extend(dic['M']) # M == Mark
+ word.extend(dic['Nd'])
+ word.extend(dic['Pc']) # Pc == Connector_Punctuation
+ word = normalize_ranges(word, True)
+
+ graph = sub_ranges(dic['Any'], dic['White_Space'])
+ graph = sub_ranges(graph, dic['Cc'])
+ graph = sub_ranges(graph, dic['Cs']) # Cs == Surrogate
+ graph = sub_ranges(graph, dic['Cn']) # Cn == Unassigned
+ graph = normalize_ranges(graph, True)
+
+ p = []
+ p.extend(graph)
+ p.extend(dic['Zs'])
+ p = normalize_ranges(p, True)
+
+ dic['Alpha'] = dic['Alphabetic']
+ dic['Upper'] = dic['Uppercase']
+ dic['Lower'] = dic['Lowercase']
+ dic['Punct'] = dic['P'] # P == Punctuation
+ dic['Digit'] = dic['Nd']
+ dic['XDigit'] = [(0x0030, 0x0039), (0x0041, 0x0046), (0x0061, 0x0066)]
+ dic['Alnum'] = alnum
+ dic['Space'] = dic['White_Space']
+ dic['Blank'] = blank
+ dic['Cntrl'] = dic['Cc']
+ dic['Word'] = word
+ dic['Graph'] = graph
+ dic['Print'] = p
+
+
+def set_max_prop_name(name):
+ global PROPERTY_NAME_MAX_LEN
+ n = len(name)
+ if n > PROPERTY_NAME_MAX_LEN:
+ PROPERTY_NAME_MAX_LEN = n
+
+def entry_prop_name(name, index):
+ set_max_prop_name(name)
+ if OUTPUT_LIST_MODE and index >= len(POSIX_LIST):
+ print >> UPF, "%3d: %s" % (index, name)
+
+def entry_and_print_prop_and_index(name, index):
+ entry_prop_name(name, index)
+ nname = normalize_prop_name(name)
+ print_prop_and_index(nname, index)
+
+def parse_and_merge_properties(path, klass, prop_prefix = None, version_reg = None):
+ dic, props, ver_m = parse_properties(path, klass, prop_prefix, version_reg)
+ merge_dic(DIC, dic)
+ merge_props(PROPS, props)
+ return dic, props, ver_m
+
+### main ###
+argv = sys.argv
+argc = len(argv)
+
+POSIX_ONLY = False
+INCLUDE_GRAPHEME_CLUSTER_DATA = False
+
+for i in range(1, argc):
+ arg = argv[i]
+ if arg == '-posix':
+ POSIX_ONLY = True
+ elif arg == '-gc':
+ INCLUDE_GRAPHEME_CLUSTER_DATA = True
+ else:
+ print >> sys.stderr, "Invalid argument: %s" % arg
+
+
+OUTPUT_LIST_MODE = not(POSIX_ONLY)
+
+with open('UnicodeData.txt', 'r') as f:
+ dic, assigned = parse_unicode_data_file(f)
+ DIC = dic
+ add_primitive_props(assigned)
+
+PROPS = DIC.keys()
+PROPS = list_sub(PROPS, POSIX_LIST)
+
+_, _, ver_m = parse_and_merge_properties('DerivedCoreProperties.txt', 'Derived Property', None, UNICODE_VERSION_REG)
+if ver_m is not None:
+ VERSION_INFO[0] = int(ver_m.group(1))
+ VERSION_INFO[1] = int(ver_m.group(2))
+ VERSION_INFO[2] = int(ver_m.group(3))
+
+dic, props, _ = parse_and_merge_properties('Scripts.txt', 'Script')
+DIC['Unknown'] = inverse_ranges(add_ranges_in_dic(dic))
+
+parse_and_merge_properties('PropList.txt', 'Binary Property')
+
+_, _, ver_m = parse_and_merge_properties('emoji-data.txt', 'Emoji Property', None, EMOJI_VERSION_REG)
+if ver_m is not None:
+ EMOJI_VERSION_INFO[0] = int(ver_m.group(1))
+ EMOJI_VERSION_INFO[1] = int(ver_m.group(2))
+
+PROPS.append('Unknown')
+KDIC['Unknown'] = 'Script'
+
+ALIASES = parse_property_aliases('PropertyAliases.txt')
+a = parse_property_value_aliases('PropertyValueAliases.txt')
+merge_dic(ALIASES, a)
+
+dic, BLOCKS = parse_blocks('Blocks.txt')
+merge_dic(DIC, dic)
+
+if INCLUDE_GRAPHEME_CLUSTER_DATA:
+ dic, props, _ = parse_properties('GraphemeBreakProperty.txt',
+ 'GraphemeBreak Property',
+ GRAPHEME_CLUSTER_BREAK_NAME_PREFIX)
+ merge_dic(DIC, dic)
+ merge_props(PROPS, props)
+ #prop = GRAPHEME_CLUSTER_BREAK_NAME_PREFIX + 'Other'
+ #DIC[prop] = inverse_ranges(add_ranges_in_dic(dic))
+ #PROPS.append(prop)
+ #KDIC[prop] = 'GrapemeBreak Property'
+
+add_posix_props(DIC)
+PROPS = sorted(PROPS)
+
+s = '''%{
+/* Generated by make_unicode_property_data.py. */
+'''
+print s
+for prop in POSIX_LIST:
+ print_property(prop, DIC[prop], "POSIX [[:%s:]]" % prop)
+
+print ''
+
+if not(POSIX_ONLY):
+ for prop in PROPS:
+ klass = KDIC.get(prop, None)
+ if klass is None:
+ n = len(prop)
+ if n == 1:
+ klass = 'Major Category'
+ elif n == 2:
+ klass = 'General Category'
+ else:
+ klass = '-'
+
+ print_property(prop, DIC[prop], klass)
+
+ for block in BLOCKS:
+ print_property(block, DIC[block], 'Block')
+
+
+print ''
+print "static const OnigCodePoint*\nconst CodeRanges[] = {"
+
+for prop in POSIX_LIST:
+ print " CR_%s," % prop
+
+if not(POSIX_ONLY):
+ for prop in PROPS:
+ print " CR_%s," % prop
+
+ for prop in BLOCKS:
+ print " CR_%s," % prop
+
+s = '''};
+
+#define pool_offset(s) offsetof(struct unicode_prop_name_pool_t, unicode_prop_name_pool_str##s)
+
+%}
+struct PoolPropertyNameCtype {
+ short int name;
+ short int ctype;
+};
+
+%%
+'''
+sys.stdout.write(s)
+
+if OUTPUT_LIST_MODE:
+ UPF = open("UNICODE_PROPERTIES", "w")
+ if VERSION_INFO[0] < 0:
+ raise RuntimeError("Unicode Version is not found")
+ if EMOJI_VERSION_INFO[0] < 0:
+ raise RuntimeError("Emoji Version is not found")
+
+ print >> UPF, "Unicode Properties (Unicode Version: %d.%d.%d, Emoji: %d.%d)" % (VERSION_INFO[0], VERSION_INFO[1], VERSION_INFO[2], EMOJI_VERSION_INFO[0], EMOJI_VERSION_INFO[1])
+ print >> UPF, ''
+
+index = -1
+for prop in POSIX_LIST:
+ index += 1
+ entry_and_print_prop_and_index(prop, index)
+
+if not(POSIX_ONLY):
+ for prop in PROPS:
+ index += 1
+ entry_and_print_prop_and_index(prop, index)
+
+ NALIASES = map(lambda (k,v):(normalize_prop_name(k), k, v), ALIASES.items())
+ NALIASES = sorted(NALIASES)
+ for (nk, k, v) in NALIASES:
+ nv = normalize_prop_name(v)
+ if PropIndex.get(nk, None) is not None:
+ print >> sys.stderr, "ALIASES: already exists: %s => %s" % (k, v)
+ continue
+ aindex = PropIndex.get(nv, None)
+ if aindex is None:
+ #print >> sys.stderr, "ALIASES: value is not exist: %s => %s" % (k, v)
+ continue
+
+ entry_prop_name(k, aindex)
+ print_prop_and_index(nk, aindex)
+
+ for name in BLOCKS:
+ index += 1
+ entry_and_print_prop_and_index(name, index)
+
+print '%%'
+print ''
+if not(POSIX_ONLY):
+ if VERSION_INFO[0] < 0:
+ raise RuntimeError("Unicode Version is not found")
+ if EMOJI_VERSION_INFO[0] < 0:
+ raise RuntimeError("Emoji Version is not found")
+
+ print "#define UNICODE_PROPERTY_VERSION %02d%02d%02d" % (VERSION_INFO[0], VERSION_INFO[1], VERSION_INFO[2])
+ print "#define UNICODE_EMOJI_VERSION %02d%02d" % (EMOJI_VERSION_INFO[0], EMOJI_VERSION_INFO[1])
+ print ''
+
+print "#define PROPERTY_NAME_MAX_SIZE %d" % (PROPERTY_NAME_MAX_LEN + 10)
+print "#define CODE_RANGES_NUM %d" % (index + 1)
+
+index_props = make_reverse_dic(PropIndex)
+print ''
+for i in range(index + 1):
+ for p in index_props[i]:
+ print "#define PROP_INDEX_%s %d" % (p.upper(), i)
+
+if OUTPUT_LIST_MODE:
+ UPF.close()
+
+sys.exit(0)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb.sh b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb.sh
new file mode 100755
index 000000000..e2e98fae5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+NAME=unicode_wb_data
+
+./make_unicode_wb_data.py > ${NAME}.c
+
+exit 0
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb_data.py b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb_data.py
new file mode 100755
index 000000000..ddedd5da6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/make_unicode_wb_data.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# make_unicode_wb_data.py
+# Copyright (c) 2019 K.Kosako
+
+import sys
+import re
+
+MAX_CODE_POINT = 0x10ffff
+
+PR_TOTAL_REG = re.compile("#\s*Total\s+(?:code\s+points|elements):")
+PR_LINE_REG = re.compile("([0-9A-Fa-f]+)(?:..([0-9A-Fa-f]+))?\s*;\s*(\w+)")
+PA_LINE_REG = re.compile("(\w+)\s*;\s*(\w+)")
+PVA_LINE_REG = re.compile("(sc|gc)\s*;\s*(\w+)\s*;\s*(\w+)(?:\s*;\s*(\w+))?")
+BL_LINE_REG = re.compile("([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+)\s*;\s*(.*)")
+VERSION_REG = re.compile("#\s*.*-(\d+)\.(\d+)\.(\d+)\.txt")
+
+VERSION_INFO = [-1, -1, -1]
+DIC = { }
+PROPS = []
+PropIndex = { }
+
+def check_version_info(s):
+ m = VERSION_REG.match(s)
+ if m is not None:
+ VERSION_INFO[0] = int(m.group(1))
+ VERSION_INFO[1] = int(m.group(2))
+ VERSION_INFO[2] = int(m.group(3))
+
+def print_ranges(ranges):
+ for (start, end) in ranges:
+ print "0x%06x, 0x%06x" % (start, end)
+
+def print_prop_and_index(prop, i):
+ print "%-35s %3d" % (prop + ',', i)
+ PropIndex[prop] = i
+
+def dic_find_by_value(dic, v):
+ for key, val in dic.items():
+ if val == v:
+ return key
+
+ return None
+
+
+def normalize_ranges(in_ranges, sort=False):
+ if sort:
+ ranges = sorted(in_ranges)
+ else:
+ ranges = in_ranges
+
+ r = []
+ prev = None
+ for (start, end) in ranges:
+ if prev >= start - 1:
+ (pstart, pend) = r.pop()
+ end = max(pend, end)
+ start = pstart
+
+ r.append((start, end))
+ prev = end
+
+ return r
+
+def inverse_ranges(in_ranges):
+ r = []
+ prev = 0x000000
+ for (start, end) in in_ranges:
+ if prev < start:
+ r.append((prev, start - 1))
+
+ prev = end + 1
+
+ if prev < MAX_CODE_POINT:
+ r.append((prev, MAX_CODE_POINT))
+
+ return r
+
+def add_ranges(r1, r2):
+ r = r1 + r2
+ return normalize_ranges(r, True)
+
+def sub_one_range(one_range, rs):
+ r = []
+ (s1, e1) = one_range
+ n = len(rs)
+ for i in range(0, n):
+ (s2, e2) = rs[i]
+ if s2 >= s1 and s2 <= e1:
+ if s2 > s1:
+ r.append((s1, s2 - 1))
+ if e2 >= e1:
+ return r
+
+ s1 = e2 + 1
+ elif s2 < s1 and e2 >= s1:
+ if e2 < e1:
+ s1 = e2 + 1
+ else:
+ return r
+
+ r.append((s1, e1))
+ return r
+
+def sub_ranges(r1, r2):
+ r = []
+ for one_range in r1:
+ rs = sub_one_range(one_range, r2)
+ r.extend(rs)
+
+ return r
+
+def add_ranges_in_dic(dic):
+ r = []
+ for k, v in dic.items():
+ r = r + v
+
+ return normalize_ranges(r, True)
+
+def normalize_ranges_in_dic(dic, sort=False):
+ for k, v in dic.items():
+ r = normalize_ranges(v, sort)
+ dic[k] = r
+
+def merge_dic(to_dic, from_dic):
+ to_keys = to_dic.keys()
+ from_keys = from_dic.keys()
+ common = list(set(to_keys) & set(from_keys))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_dic: collision: %s" % sorted(common)
+
+ to_dic.update(from_dic)
+
+def merge_props(to_props, from_props):
+ common = list(set(to_props) & set(from_props))
+ if len(common) != 0:
+ print >> sys.stderr, "merge_props: collision: %s" % sorted(common)
+
+ to_props.extend(from_props)
+
+def add_range_into_dic(dic, name, start, end):
+ d = dic.get(name, None)
+ if d is None:
+ d = [(start, end)]
+ dic[name] = d
+ else:
+ d.append((start, end))
+
+def list_sub(a, b):
+ x = set(a) - set(b)
+ return list(x)
+
+def parse_properties(path):
+ with open(path, 'r') as f:
+ dic = { }
+ prop = None
+ props = []
+ for line in f:
+ s = line.strip()
+ if len(s) == 0:
+ continue
+
+ if s[0] == '#':
+ if VERSION_INFO[0] < 0:
+ check_version_info(s)
+
+ m = PR_LINE_REG.match(s)
+ if m:
+ prop = m.group(3)
+ if m.group(2):
+ start = int(m.group(1), 16)
+ end = int(m.group(2), 16)
+ add_range_into_dic(dic, prop, start, end)
+ else:
+ start = int(m.group(1), 16)
+ add_range_into_dic(dic, prop, start, start)
+
+ elif PR_TOTAL_REG.match(s) is not None:
+ props.append(prop)
+
+ normalize_ranges_in_dic(dic)
+ return (dic, props)
+
+
+### main ###
+argv = sys.argv
+argc = len(argv)
+
+dic, props = parse_properties('WordBreakProperty.txt')
+merge_dic(DIC, dic)
+merge_props(PROPS, props)
+
+PROPS = sorted(PROPS)
+
+print '/* unicode_wb_data.c: Generated by make_unicode_wb_data.py. */'
+COPYRIGHT = '''
+/*-
+ * Copyright (c) 2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+'''.strip()
+
+print COPYRIGHT
+print ''
+if VERSION_INFO[0] < 0:
+ raise RuntimeError("Version is not found.")
+
+print "#define WORD_BREAK_PROPERTY_VERSION %02d%02d%02d" % (VERSION_INFO[0], VERSION_INFO[1], VERSION_INFO[2])
+print ''
+
+ranges = []
+for prop in PROPS:
+ rs = DIC[prop]
+ for (start, end) in rs:
+ ranges.append((start, end, prop))
+
+ranges = sorted(ranges, key=lambda x: x[0])
+
+prev = -1
+for (start, end, prop) in ranges:
+ if prev >= start:
+ raise ValueError("{2}:{0} - {1} range overlap prev value {3}".format(start, end, prop, prev))
+
+
+print '/*'
+for prop in PROPS:
+ print "%s" % prop
+print '*/'
+print ''
+
+num_ranges = len(ranges)
+print "static int WB_RANGE_NUM = %d;" % num_ranges
+
+print 'static WB_RANGE_TYPE WB_RANGES[] = {'
+for i, (start, end, prop) in enumerate(ranges):
+ if i == num_ranges - 1:
+ comma = ''
+ else:
+ comma = ','
+
+ type_name = 'WB_' + prop
+ print " {0x%06x, 0x%06x, %s }%s" % (start, end, type_name, comma)
+
+print '};'
+
+sys.exit(0)
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/mktable.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/mktable.c
new file mode 100644
index 000000000..5f36ee357
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/mktable.c
@@ -0,0 +1,1184 @@
+/**********************************************************************
+ mktable.c
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+
+#ifndef __USE_ISOC99
+#define __USE_ISOC99
+#endif
+
+#include <ctype.h>
+
+#include "regenc.h"
+
+#define ASCII 0
+#define UNICODE_ISO_8859_1 1
+#define ISO_8859_1 2
+#define ISO_8859_2 3
+#define ISO_8859_3 4
+#define ISO_8859_4 5
+#define ISO_8859_5 6
+#define ISO_8859_6 7
+#define ISO_8859_7 8
+#define ISO_8859_8 9
+#define ISO_8859_9 10
+#define ISO_8859_10 11
+#define ISO_8859_11 12
+#define ISO_8859_13 13
+#define ISO_8859_14 14
+#define ISO_8859_15 15
+#define ISO_8859_16 16
+#define KOI8 17
+#define KOI8_R 18
+
+typedef struct {
+ int num;
+ char* name;
+} ENC_INFO;
+
+static ENC_INFO Info[] = {
+ { ASCII, "ASCII" },
+ { UNICODE_ISO_8859_1, "UNICODE_ISO_8859_1" },
+ { ISO_8859_1, "ISO_8859_1" },
+ { ISO_8859_2, "ISO_8859_2" },
+ { ISO_8859_3, "ISO_8859_3" },
+ { ISO_8859_4, "ISO_8859_4" },
+ { ISO_8859_5, "ISO_8859_5" },
+ { ISO_8859_6, "ISO_8859_6" },
+ { ISO_8859_7, "ISO_8859_7" },
+ { ISO_8859_8, "ISO_8859_8" },
+ { ISO_8859_9, "ISO_8859_9" },
+ { ISO_8859_10, "ISO_8859_10" },
+ { ISO_8859_11, "ISO_8859_11" },
+ { ISO_8859_13, "ISO_8859_13" },
+ { ISO_8859_14, "ISO_8859_14" },
+ { ISO_8859_15, "ISO_8859_15" },
+ { ISO_8859_16, "ISO_8859_16" },
+ { KOI8, "KOI8" },
+ { KOI8_R, "KOI8_R" }
+};
+
+
+static int IsAlpha(int enc, int c)
+{
+ if (enc == ASCII)
+ return isalpha(c);
+
+ if (c >= 0x41 && c <= 0x5a) return 1;
+ if (c >= 0x61 && c <= 0x7a) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_9:
+ if (c == 0xaa) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_2:
+ if (c == 0xa1 || c == 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c >= 0xae && c <= 0xaf) return 1;
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c == 0xa1) return 1;
+ if (c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb1) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xc2) return 1;
+ if (c >= 0xc4 && c <= 0xcf) return 1;
+ if (c >= 0xd1 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xe2) return 1;
+ if (c >= 0xe4 && c <= 0xef) return 1;
+ if (c >= 0xf1 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_4:
+ if (c >= 0xa1 && c <= 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_5:
+ if (c >= 0xa1 && c <= 0xcf && c != 0xad) return 1;
+ if (c >= 0xd0 && c <= 0xff && c != 0xf0 && c != 0xfd) return 1;
+ break;
+
+ case ISO_8859_6:
+ if (c >= 0xc1 && c <= 0xda) return 1;
+ if (c >= 0xe0 && c <= 0xf2) return 1;
+ break;
+
+ case ISO_8859_7:
+ if (c == 0xb6) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c == 0xc0) return 1;
+ if (c >= 0xc1 && c <= 0xdb && c != 0xd2) return 1;
+ if (c >= 0xdc && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c == 0xb5) return 1;
+ if (c >= 0xe0 && c <= 0xfa) return 1;
+ break;
+
+ case ISO_8859_10:
+ if (c >= 0xa1 && c <= 0xa6) return 1;
+ if (c >= 0xa8 && c <= 0xac) return 1;
+ if (c == 0xae || c == 0xaf) return 1;
+ if (c >= 0xb1 && c <= 0xb6) return 1;
+ if (c >= 0xb8 && c <= 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_11:
+ if (c >= 0xa1 && c <= 0xda) return 1;
+ if (c >= 0xdf && c <= 0xfb) return 1;
+ break;
+
+ case ISO_8859_13:
+ if (c == 0xa8) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xb8) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xbf && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_14:
+ if (c == 0xa1 || c == 0xa2) return 1;
+ if (c == 0xa4 || c == 0xa5) return 1;
+ if (c == 0xa6 || c == 0xa8) return 1;
+ if (c >= 0xaa && c <= 0xac) return 1;
+ if (c >= 0xaf && c <= 0xb5) return 1;
+ if (c >= 0xb7 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_15:
+ if (c == 0xaa) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xb4) return 1;
+ if (c == 0xb8) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbd) return 1;
+ if (c == 0xbe) return 1;
+ break;
+
+ case ISO_8859_16:
+ if (c == 0xa1) return 1;
+ if (c == 0xa2) return 1;
+ if (c == 0xa3) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xac) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb2) return 1;
+ if (c == 0xb3) return 1;
+ if (c == 0xb4) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbd) return 1;
+ if (c == 0xbe) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xde) return 1;
+ if (c >= 0xdf && c <= 0xff) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0xa3 || c == 0xb3) return 1;
+ /* fall */
+ case KOI8:
+ if (c >= 0xc0 && c <= 0xff) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsBlank(int enc, int c)
+{
+ if (enc == ASCII)
+ return isblank(c);
+
+ if (c == 0x09 || c == 0x20) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_2:
+ case ISO_8859_3:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_6:
+ case ISO_8859_7:
+ case ISO_8859_8:
+ case ISO_8859_9:
+ case ISO_8859_10:
+ case ISO_8859_11:
+ case ISO_8859_13:
+ case ISO_8859_14:
+ case ISO_8859_15:
+ case ISO_8859_16:
+ case KOI8:
+ if (c == 0xa0) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0x9a) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsCntrl(int enc, int c)
+{
+ if (enc == ASCII)
+ return iscntrl(c);
+
+ if (c >= 0x00 && c <= 0x1F) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ if (c == 0xad) return 1;
+ /* fall */
+ case ISO_8859_1:
+ case ISO_8859_2:
+ case ISO_8859_3:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_6:
+ case ISO_8859_7:
+ case ISO_8859_8:
+ case ISO_8859_9:
+ case ISO_8859_10:
+ case ISO_8859_11:
+ case ISO_8859_13:
+ case ISO_8859_14:
+ case ISO_8859_15:
+ case ISO_8859_16:
+ case KOI8:
+ if (c >= 0x7f && c <= 0x9F) return 1;
+ break;
+
+
+ case KOI8_R:
+ if (c == 0x7f) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsDigit(int enc ARG_UNUSED, int c)
+{
+ if (c >= 0x30 && c <= 0x39) return 1;
+ return 0;
+}
+
+static int IsGraph(int enc, int c)
+{
+ if (enc == ASCII)
+ return isgraph(c);
+
+ if (c >= 0x21 && c <= 0x7e) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_2:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_9:
+ case ISO_8859_10:
+ case ISO_8859_13:
+ case ISO_8859_14:
+ case ISO_8859_15:
+ case ISO_8859_16:
+ if (c >= 0xa1 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c >= 0xa1) {
+ if (c == 0xa5 || c == 0xae || c == 0xbe || c == 0xc3 || c == 0xd0 ||
+ c == 0xe3 || c == 0xf0)
+ return 0;
+ else
+ return 1;
+ }
+ break;
+
+ case ISO_8859_6:
+ if (c == 0xa4 || c == 0xac || c == 0xad || c == 0xbb || c == 0xbf)
+ return 1;
+ if (c >= 0xc1 && c <= 0xda) return 1;
+ if (c >= 0xe0 && c <= 0xf2) return 1;
+ break;
+
+ case ISO_8859_7:
+ if (c >= 0xa1 && c <= 0xfe &&
+ c != 0xa4 && c != 0xa5 && c != 0xaa &&
+ c != 0xae && c != 0xd2) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c >= 0xa2 && c <= 0xfa) {
+ if (c >= 0xbf && c <= 0xde) return 0;
+ return 1;
+ }
+ break;
+
+ case ISO_8859_11:
+ if (c >= 0xa1 && c <= 0xda) return 1;
+ if (c >= 0xdf && c <= 0xfb) return 1;
+ break;
+
+ case KOI8:
+ if (c >= 0xc0 && c <= 0xff) return 1;
+ break;
+
+ case KOI8_R:
+ if (c >= 0x80 && c <= 0xff && c != 0x9a) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsLower(int enc, int c)
+{
+ if (enc == ASCII)
+ return islower(c);
+
+ if (c >= 0x61 && c <= 0x7a) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_9:
+ if (c == 0xaa) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xdf && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_2:
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c >= 0xdf && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c == 0xb1) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c == 0xbf) return 1;
+ if (c == 0xdf) return 1;
+ if (c >= 0xe0 && c <= 0xe2) return 1;
+ if (c >= 0xe4 && c <= 0xef) return 1;
+ if (c >= 0xf1 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_4:
+ if (c == 0xa2) return 1;
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c == 0xdf) return 1;
+ if (c >= 0xe0 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_5:
+ if (c >= 0xd0 && c <= 0xff && c != 0xf0 && c != 0xfd) return 1;
+ break;
+
+ case ISO_8859_6:
+ break;
+
+ case ISO_8859_7:
+ if (c == 0xc0) return 1;
+ if (c >= 0xdc && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c == 0xb5) return 1;
+ break;
+
+ case ISO_8859_10:
+ if (c >= 0xb1 && c <= 0xb6) return 1;
+ if (c >= 0xb8 && c <= 0xbc) return 1;
+ if (c == 0xbe || c == 0xbf) return 1;
+ if (c >= 0xdf && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_11:
+ break;
+
+ case ISO_8859_13:
+ if (c == 0xb5) return 1;
+ if (c == 0xb8) return 1;
+ if (c == 0xba) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xdf && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_14:
+ if (c == 0xa2) return 1;
+ if (c == 0xa5) return 1;
+ if (c == 0xab) return 1;
+ if (c == 0xb1 || c == 0xb3 || c == 0xb5) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbe || c == 0xbf) return 1;
+ if (c >= 0xdf && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_15:
+ if (c == 0xaa) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xdf && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xb8) return 1;
+ if (c == 0xbd) return 1;
+ break;
+
+ case ISO_8859_16:
+ if (c == 0xa2) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xb3) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbd) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xdf && c <= 0xff) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0xa3) return 1;
+ /* fall */
+ case KOI8:
+ if (c >= 0xc0 && c <= 0xdf) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsPrint(int enc, int c)
+{
+ if (enc == ASCII)
+ return isprint(c);
+
+ if (c >= 0x20 && c <= 0x7e) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ if (c >= 0x09 && c <= 0x0d) return 1;
+ if (c == 0x85) return 1;
+ /* fall */
+ case ISO_8859_1:
+ case ISO_8859_2:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_9:
+ case ISO_8859_10:
+ case ISO_8859_13:
+ case ISO_8859_14:
+ case ISO_8859_15:
+ case ISO_8859_16:
+ if (c >= 0xa0 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c >= 0xa0) {
+ if (c == 0xa5 || c == 0xae || c == 0xbe || c == 0xc3 || c == 0xd0 ||
+ c == 0xe3 || c == 0xf0)
+ return 0;
+ else
+ return 1;
+ }
+ break;
+
+ case ISO_8859_6:
+ if (c == 0xa0) return 1;
+ if (c == 0xa4 || c == 0xac || c == 0xad || c == 0xbb || c == 0xbf)
+ return 1;
+ if (c >= 0xc1 && c <= 0xda) return 1;
+ if (c >= 0xe0 && c <= 0xf2) return 1;
+ break;
+
+ case ISO_8859_7:
+ if (c >= 0xa0 && c <= 0xfe &&
+ c != 0xa4 && c != 0xa5 && c != 0xaa &&
+ c != 0xae && c != 0xd2) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c >= 0xa0 && c <= 0xfa) {
+ if (c >= 0xbf && c <= 0xde) return 0;
+ if (c == 0xa1) return 0;
+ return 1;
+ }
+ break;
+
+ case ISO_8859_11:
+ if (c >= 0xa0 && c <= 0xda) return 1;
+ if (c >= 0xdf && c <= 0xfb) return 1;
+ break;
+
+ case KOI8:
+ if (c == 0xa0) return 1;
+ if (c >= 0xc0 && c <= 0xff) return 1;
+ break;
+
+ case KOI8_R:
+ if (c >= 0x80 && c <= 0xff) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsPunct(int enc, int c)
+{
+ if (enc == ASCII)
+ return ispunct(c);
+
+ if (enc == UNICODE_ISO_8859_1) {
+ if (c == 0x24 || c == 0x2b || c == 0x5e || c == 0x60 ||
+ c == 0x7c || c == 0x7e) return 1;
+ if (c >= 0x3c && c <= 0x3e) return 1;
+ }
+
+ if (c >= 0x21 && c <= 0x2f) return 1;
+ if (c >= 0x3a && c <= 0x40) return 1;
+ if (c >= 0x5b && c <= 0x60) return 1;
+ if (c >= 0x7b && c <= 0x7e) return 1;
+
+ switch (enc) {
+ case ISO_8859_1:
+ case ISO_8859_9:
+ case ISO_8859_15:
+ if (c == 0xad) return 1;
+ /* fall */
+ case UNICODE_ISO_8859_1:
+ if (c == 0xa1) return 1;
+ if (c == 0xab) return 1;
+ if (c == 0xb7) return 1;
+ if (c == 0xbb) return 1;
+ if (c == 0xbf) return 1;
+ break;
+
+ case ISO_8859_2:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_14:
+ if (c == 0xad) return 1;
+ break;
+
+ case ISO_8859_3:
+ case ISO_8859_10:
+ if (c == 0xad) return 1;
+ if (c == 0xb7) return 1;
+ if (c == 0xbd) return 1;
+ break;
+
+ case ISO_8859_6:
+ if (c == 0xac) return 1;
+ if (c == 0xad) return 1;
+ if (c == 0xbb) return 1;
+ if (c == 0xbf) return 1;
+ break;
+
+ case ISO_8859_7:
+ if (c == 0xa1 || c == 0xa2) return 1;
+ if (c == 0xab) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xad) return 1;
+ if (c == 0xb7 || c == 0xbb) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c == 0xab) return 1;
+ if (c == 0xad) return 1;
+ if (c == 0xb7) return 1;
+ if (c == 0xbb) return 1;
+ if (c == 0xdf) return 1;
+ break;
+
+ case ISO_8859_13:
+ if (c == 0xa1 || c == 0xa5) return 1;
+ if (c == 0xab || c == 0xad) return 1;
+ if (c == 0xb4 || c == 0xb7) return 1;
+ if (c == 0xbb) return 1;
+ if (c == 0xff) return 1;
+ break;
+
+ case ISO_8859_16:
+ if (c == 0xa5) return 1;
+ if (c == 0xab) return 1;
+ if (c == 0xad) return 1;
+ if (c == 0xb5) return 1;
+ if (c == 0xb7) return 1;
+ if (c == 0xbb) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0x9e) return 1;
+ break;
+
+ case ISO_8859_11:
+ case KOI8:
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsSpace(int enc, int c)
+{
+ if (enc == ASCII)
+ return isspace(c);
+
+ if (c >= 0x09 && c <= 0x0d) return 1;
+ if (c == 0x20) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ if (c == 0x85) return 1;
+ /* fall */
+ case ISO_8859_1:
+ case ISO_8859_2:
+ case ISO_8859_3:
+ case ISO_8859_4:
+ case ISO_8859_5:
+ case ISO_8859_6:
+ case ISO_8859_7:
+ case ISO_8859_8:
+ case ISO_8859_9:
+ case ISO_8859_10:
+ case ISO_8859_11:
+ case ISO_8859_13:
+ case ISO_8859_14:
+ case ISO_8859_15:
+ case ISO_8859_16:
+ case KOI8:
+ if (c == 0xa0) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0x9a) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsUpper(int enc, int c)
+{
+ if (enc == ASCII)
+ return isupper(c);
+
+ if (c >= 0x41 && c <= 0x5a) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_9:
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_2:
+ if (c == 0xa1 || c == 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c >= 0xae && c <= 0xaf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c == 0xa1) return 1;
+ if (c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xaf) return 1;
+ if (c >= 0xc0 && c <= 0xc2) return 1;
+ if (c >= 0xc4 && c <= 0xcf) return 1;
+ if (c >= 0xd1 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_4:
+ if (c == 0xa1 || c == 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xbd) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_5:
+ if (c >= 0xa1 && c <= 0xcf && c != 0xad) return 1;
+ break;
+
+ case ISO_8859_6:
+ break;
+
+ case ISO_8859_7:
+ if (c == 0xb6) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c >= 0xc1 && c <= 0xdb && c != 0xd2) return 1;
+ break;
+
+ case ISO_8859_8:
+ case ISO_8859_11:
+ break;
+
+ case ISO_8859_10:
+ if (c >= 0xa1 && c <= 0xa6) return 1;
+ if (c >= 0xa8 && c <= 0xac) return 1;
+ if (c == 0xae || c == 0xaf) return 1;
+ if (c >= 0xc0 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_13:
+ if (c == 0xa8) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xaf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_14:
+ if (c == 0xa1) return 1;
+ if (c == 0xa4 || c == 0xa6) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xaa || c == 0xac) return 1;
+ if (c == 0xaf || c == 0xb0) return 1;
+ if (c == 0xb2 || c == 0xb4 || c == 0xb7) return 1;
+ if (c == 0xbb || c == 0xbd) return 1;
+ if (c >= 0xc0 && c <= 0xde) return 1;
+ break;
+
+ case ISO_8859_15:
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xde) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xb4) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbe) return 1;
+ break;
+
+ case ISO_8859_16:
+ if (c == 0xa1) return 1;
+ if (c == 0xa3) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xac) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb2) return 1;
+ if (c == 0xb4) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbe) return 1;
+ if (c >= 0xc0 && c <= 0xde) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0xb3) return 1;
+ /* fall */
+ case KOI8:
+ if (c >= 0xe0 && c <= 0xff) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsXDigit(int enc, int c)
+{
+ if (enc == ASCII)
+ return isxdigit(c);
+
+ if (c >= 0x30 && c <= 0x39) return 1;
+ if (c >= 0x41 && c <= 0x46) return 1;
+ if (c >= 0x61 && c <= 0x66) return 1;
+ return 0;
+}
+
+static int IsWord(int enc, int c)
+{
+ if (enc == ASCII) {
+ return (isalpha(c) || isdigit(c) || c == 0x5f);
+ }
+
+ if (c >= 0x30 && c <= 0x39) return 1;
+ if (c >= 0x41 && c <= 0x5a) return 1;
+ if (c == 0x5f) return 1;
+ if (c >= 0x61 && c <= 0x7a) return 1;
+
+ switch (enc) {
+ case UNICODE_ISO_8859_1:
+ case ISO_8859_1:
+ case ISO_8859_9:
+ if (c == 0xaa) return 1;
+ if (c >= 0xb2 && c <= 0xb3) return 1;
+ if (c == 0xb5) return 1;
+ if (c >= 0xb9 && c <= 0xba) return 1;
+ if (c >= 0xbc && c <= 0xbe) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ break;
+
+ case ISO_8859_2:
+ if (c == 0xa1 || c == 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c >= 0xae && c <= 0xaf) return 1;
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbc) return 1;
+ if (c >= 0xbe && c <= 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_3:
+ if (c == 0xa1) return 1;
+ if (c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xaf) return 1;
+ if (c >= 0xb1 && c <= 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbd) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xc2) return 1;
+ if (c >= 0xc4 && c <= 0xcf) return 1;
+ if (c >= 0xd1 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xe2) return 1;
+ if (c >= 0xe4 && c <= 0xef) return 1;
+ if (c >= 0xf1 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_4:
+ if (c >= 0xa1 && c <= 0xa3) return 1;
+ if (c == 0xa5 || c == 0xa6) return 1;
+ if (c >= 0xa9 && c <= 0xac) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xb1 || c == 0xb3) return 1;
+ if (c == 0xb5 || c == 0xb6) return 1;
+ if (c >= 0xb9 && c <= 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_5:
+ if (c >= 0xa1 && c <= 0xcf && c != 0xad) return 1;
+ if (c >= 0xd0 && c <= 0xff && c != 0xf0 && c != 0xfd) return 1;
+ break;
+
+ case ISO_8859_6:
+ if (c >= 0xc1 && c <= 0xda) return 1;
+ if (c >= 0xe0 && c <= 0xea) return 1;
+ if (c >= 0xeb && c <= 0xf2) return 1;
+ break;
+
+ case ISO_8859_7:
+ if (c == 0xb2 || c == 0xb3) return 1;
+ if (c == 0xb6) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c >= 0xbc && c <= 0xbf) return 1;
+ if (c == 0xc0) return 1;
+ if (c >= 0xc1 && c <= 0xdb && c != 0xd2) return 1;
+ if (c >= 0xdc && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_8:
+ if (c == 0xb2 || c == 0xb3 || c == 0xb5 || c == 0xb9) return 1;
+ if (c >= 0xbc && c <= 0xbe) return 1;
+ if (c >= 0xe0 && c <= 0xfa) return 1;
+ break;
+
+ case ISO_8859_10:
+ if (c >= 0xa1 && c <= 0xff) {
+ if (c != 0xa7 && c != 0xad && c != 0xb0 && c != 0xb7 && c != 0xbd)
+ return 1;
+ }
+ break;
+
+ case ISO_8859_11:
+ if (c >= 0xa1 && c <= 0xda) return 1;
+ if (c >= 0xdf && c <= 0xfb) return 1;
+ break;
+
+ case ISO_8859_13:
+ if (c == 0xa8) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb2 || c == 0xb3 || c == 0xb5 || c == 0xb9) return 1;
+ if (c >= 0xbc && c <= 0xbe) return 1;
+ if (c == 0xb8) return 1;
+ if (c == 0xba) return 1;
+ if (c >= 0xbf && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xfe) return 1;
+ break;
+
+ case ISO_8859_14:
+ if (c >= 0xa1 && c <= 0xff) {
+ if (c == 0xa3 || c == 0xa7 || c == 0xa9 || c == 0xad || c == 0xae ||
+ c == 0xb6) return 0;
+ return 1;
+ }
+ break;
+
+ case ISO_8859_15:
+ if (c == 0xaa) return 1;
+ if (c >= 0xb2 && c <= 0xb3) return 1;
+ if (c == 0xb5) return 1;
+ if (c >= 0xb9 && c <= 0xba) return 1;
+ if (c >= 0xbc && c <= 0xbe) return 1;
+ if (c >= 0xc0 && c <= 0xd6) return 1;
+ if (c >= 0xd8 && c <= 0xf6) return 1;
+ if (c >= 0xf8 && c <= 0xff) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xb4) return 1;
+ if (c == 0xb8) return 1;
+ break;
+
+ case ISO_8859_16:
+ if (c == 0xa1) return 1;
+ if (c == 0xa2) return 1;
+ if (c == 0xa3) return 1;
+ if (c == 0xa6) return 1;
+ if (c == 0xa8) return 1;
+ if (c == 0xaa) return 1;
+ if (c == 0xac) return 1;
+ if (c == 0xae) return 1;
+ if (c == 0xaf) return 1;
+ if (c == 0xb2) return 1;
+ if (c == 0xb3) return 1;
+ if (c == 0xb4) return 1;
+ if (c >= 0xb8 && c <= 0xba) return 1;
+ if (c == 0xbc) return 1;
+ if (c == 0xbd) return 1;
+ if (c == 0xbe) return 1;
+ if (c == 0xbf) return 1;
+ if (c >= 0xc0 && c <= 0xde) return 1;
+ if (c >= 0xdf && c <= 0xff) return 1;
+ break;
+
+ case KOI8_R:
+ if (c == 0x9d) return 1;
+ if (c == 0xa3 || c == 0xb3) return 1;
+ /* fall */
+ case KOI8:
+ if (c >= 0xc0 && c <= 0xff) return 1;
+ break;
+
+ default:
+ exit(-1);
+ }
+
+ return 0;
+}
+
+static int IsAscii(int enc ARG_UNUSED, int c)
+{
+ if (c >= 0x00 && c <= 0x7f) return 1;
+ return 0;
+}
+
+static int IsNewline(int enc ARG_UNUSED, int c)
+{
+ if (c == NEWLINE_CODE) return 1;
+ return 0;
+}
+
+static int exec(FILE* fp, ENC_INFO* einfo)
+{
+#define NCOL 8
+
+ int c, val, enc;
+ int r;
+
+ enc = einfo->num;
+
+ r = fprintf(fp, "static const unsigned short Enc%s_CtypeTable[256] = {\n",
+ einfo->name);
+ if (r < 0) return -1;
+
+ for (c = 0; c < 256; c++) {
+ val = 0;
+ if (IsNewline(enc, c)) val |= BIT_CTYPE_NEWLINE;
+ if (IsAlpha (enc, c)) val |= (BIT_CTYPE_ALPHA | BIT_CTYPE_ALNUM);
+ if (IsBlank (enc, c)) val |= BIT_CTYPE_BLANK;
+ if (IsCntrl (enc, c)) val |= BIT_CTYPE_CNTRL;
+ if (IsDigit (enc, c)) val |= (BIT_CTYPE_DIGIT | BIT_CTYPE_ALNUM);
+ if (IsGraph (enc, c)) val |= BIT_CTYPE_GRAPH;
+ if (IsLower (enc, c)) val |= BIT_CTYPE_LOWER;
+ if (IsPrint (enc, c)) val |= BIT_CTYPE_PRINT;
+ if (IsPunct (enc, c)) val |= BIT_CTYPE_PUNCT;
+ if (IsSpace (enc, c)) val |= BIT_CTYPE_SPACE;
+ if (IsUpper (enc, c)) val |= BIT_CTYPE_UPPER;
+ if (IsXDigit(enc, c)) val |= BIT_CTYPE_XDIGIT;
+ if (IsWord (enc, c)) val |= BIT_CTYPE_WORD;
+ if (IsAscii (enc, c)) val |= BIT_CTYPE_ASCII;
+
+ if (c % NCOL == 0) {
+ r = fputs(" ", fp);
+ if (r < 0) return -1;
+ }
+ r = fprintf(fp, "0x%04x", val);
+ if (r < 0) return -1;
+
+ if (c != 255) {
+ r = fputs(",", fp);
+ if (r < 0) return -1;
+ }
+ if (c != 0 && c % NCOL == (NCOL-1))
+ r = fputs("\n", fp);
+ else
+ r = fputs(" ", fp);
+
+ if (r < 0) return -1;
+ }
+ r = fprintf(fp, "};\n");
+ if (r < 0) return -1;
+
+ return 0;
+}
+
+extern int main(int argc ARG_UNUSED, char* argv[] ARG_UNUSED)
+{
+ int r;
+ int i;
+ FILE* fp = stdout;
+
+ setlocale(LC_ALL, "C");
+ /* setlocale(LC_ALL, "POSIX"); */
+ /* setlocale(LC_ALL, "en_GB.iso88591"); */
+ /* setlocale(LC_ALL, "de_BE.iso88591"); */
+ /* setlocale(LC_ALL, "fr_FR.iso88591"); */
+
+ for (i = 0; i < (int )(sizeof(Info)/sizeof(ENC_INFO)); i++) {
+ r = exec(fp, &Info[i]);
+ if (r < 0) {
+ fprintf(stderr, "FAIL exec(): %d\n", r);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onig_init.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onig_init.c
new file mode 100644
index 000000000..c660e7df7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onig_init.c
@@ -0,0 +1,45 @@
+/**********************************************************************
+ onig_init.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2016-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+/* onig_init(): deprecated function */
+extern int
+onig_init(void)
+{
+#if 0
+ OnigEncoding encs[] = {
+ ONIG_ENCODING_UTF8
+ };
+
+ return onig_initialize(encs, sizeof(encs)/sizeof(encs[0]));
+#else
+ return onig_initialize(0, 0);
+#endif
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniggnu.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniggnu.h
new file mode 100644
index 000000000..96d90855a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniggnu.h
@@ -0,0 +1,87 @@
+#ifndef ONIGGNU_H
+#define ONIGGNU_H
+/**********************************************************************
+ oniggnu.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "oniguruma.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ RE_MBCTYPE_ASCII = 0,
+ RE_MBCTYPE_EUC = 1,
+ RE_MBCTYPE_SJIS = 2,
+ RE_MBCTYPE_UTF8 = 3
+};
+
+/* GNU regex options */
+#ifndef RE_NREGS
+#define RE_NREGS ONIG_NREGION
+#endif
+
+#define RE_OPTION_IGNORECASE ONIG_OPTION_IGNORECASE
+#define RE_OPTION_EXTENDED ONIG_OPTION_EXTEND
+#define RE_OPTION_MULTILINE ONIG_OPTION_MULTILINE
+#define RE_OPTION_SINGLELINE ONIG_OPTION_SINGLELINE
+#define RE_OPTION_LONGEST ONIG_OPTION_FIND_LONGEST
+#define RE_OPTION_POSIXLINE (RE_OPTION_MULTILINE|RE_OPTION_SINGLELINE)
+#define RE_OPTION_FIND_NOT_EMPTY ONIG_OPTION_FIND_NOT_EMPTY
+#define RE_OPTION_NEGATE_SINGLELINE ONIG_OPTION_NEGATE_SINGLELINE
+#define RE_OPTION_DONT_CAPTURE_GROUP ONIG_OPTION_DONT_CAPTURE_GROUP
+#define RE_OPTION_CAPTURE_GROUP ONIG_OPTION_CAPTURE_GROUP
+
+
+ONIG_EXTERN
+void re_mbcinit P_((int));
+ONIG_EXTERN
+int re_compile_pattern P_((const char*, int, struct re_pattern_buffer*, char* err_buf));
+ONIG_EXTERN
+int re_recompile_pattern P_((const char*, int, struct re_pattern_buffer*, char* err_buf));
+ONIG_EXTERN
+void re_free_pattern P_((struct re_pattern_buffer*));
+ONIG_EXTERN
+int re_adjust_startpos P_((struct re_pattern_buffer*, const char*, int, int, int));
+ONIG_EXTERN
+int re_search P_((struct re_pattern_buffer*, const char*, int, int, int, struct re_registers*));
+ONIG_EXTERN
+int re_match P_((struct re_pattern_buffer*, const char *, int, int, struct re_registers*));
+ONIG_EXTERN
+void re_set_casetable P_((const char*));
+ONIG_EXTERN
+void re_free_registers P_((struct re_registers*));
+ONIG_EXTERN
+int re_alloc_pattern P_((struct re_pattern_buffer**)); /* added */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ONIGGNU_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onigposix.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onigposix.h
new file mode 100644
index 000000000..37e09ea91
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/onigposix.h
@@ -0,0 +1,178 @@
+#ifndef ONIGPOSIX_H
+#define ONIGPOSIX_H
+/**********************************************************************
+ onigposix.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#ifndef ONIG_NO_STANDARD_C_HEADERS
+#include <stddef.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* options */
+#define REG_ICASE (1<<0)
+#define REG_NEWLINE (1<<1)
+#define REG_NOTBOL (1<<2)
+#define REG_NOTEOL (1<<3)
+#define REG_EXTENDED (1<<4) /* if not set, Basic Onigular Expression */
+#define REG_NOSUB (1<<5)
+
+/* POSIX error codes */
+#define REG_NOMATCH 1
+#define REG_BADPAT 2
+#define REG_ECOLLATE 3
+#define REG_ECTYPE 4
+#define REG_EESCAPE 5
+#define REG_ESUBREG 6
+#define REG_EBRACK 7
+#define REG_EPAREN 8
+#define REG_EBRACE 9
+#define REG_BADBR 10
+#define REG_ERANGE 11
+#define REG_ESPACE 12
+#define REG_BADRPT 13
+
+/* extended error codes */
+#define REG_EONIG_INTERNAL 14
+#define REG_EONIG_BADWC 15
+#define REG_EONIG_BADARG 16
+/* #define REG_EONIG_THREAD 17 */
+
+/* character encodings (for reg_set_encoding()) */
+#define REG_POSIX_ENCODING_ASCII 0
+#define REG_POSIX_ENCODING_EUC_JP 1
+#define REG_POSIX_ENCODING_SJIS 2
+#define REG_POSIX_ENCODING_UTF8 3
+#define REG_POSIX_ENCODING_UTF16_BE 4
+#define REG_POSIX_ENCODING_UTF16_LE 5
+
+
+typedef int regoff_t;
+
+typedef struct {
+ regoff_t rm_so;
+ regoff_t rm_eo;
+} regmatch_t;
+
+/* POSIX regex_t */
+typedef struct {
+ void* onig; /* Oniguruma regex_t* */
+ size_t re_nsub;
+ int comp_options;
+} regex_t;
+
+
+#ifndef P_
+#if defined(__STDC__) || defined(_WIN32)
+# define P_(args) args
+#else
+# define P_(args) ()
+#endif
+#endif
+
+#ifndef ONIG_STATIC
+#ifndef ONIG_EXTERN
+#if defined(_WIN32) && !defined(__GNUC__)
+#if defined(ONIGURUMA_EXPORT)
+#define ONIG_EXTERN extern __declspec(dllexport)
+#else
+#define ONIG_EXTERN extern __declspec(dllimport)
+#endif
+#endif
+#endif
+
+#ifndef ONIG_EXTERN
+#define ONIG_EXTERN extern
+#endif
+#else
+#define ONIG_EXTERN extern
+#endif
+
+#ifndef ONIGURUMA_H
+typedef unsigned int OnigOptionType;
+
+/* syntax */
+typedef struct {
+ unsigned int op;
+ unsigned int op2;
+ unsigned int behavior;
+ OnigOptionType options; /* default option */
+} OnigSyntaxType;
+
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPosixBasic;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPosixExtended;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxEmacs;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxGrep;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxGnuRegex;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxJava;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPerl;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxRuby;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxOniguruma;
+
+/* predefined syntaxes (see regsyntax.c) */
+#define ONIG_SYNTAX_POSIX_BASIC (&OnigSyntaxPosixBasic)
+#define ONIG_SYNTAX_POSIX_EXTENDED (&OnigSyntaxPosixExtended)
+#define ONIG_SYNTAX_EMACS (&OnigSyntaxEmacs)
+#define ONIG_SYNTAX_GREP (&OnigSyntaxGrep)
+#define ONIG_SYNTAX_GNU_REGEX (&OnigSyntaxGnuRegex)
+#define ONIG_SYNTAX_JAVA (&OnigSyntaxJava)
+#define ONIG_SYNTAX_PERL (&OnigSyntaxPerl)
+#define ONIG_SYNTAX_RUBY (&OnigSyntaxRuby)
+#define ONIG_SYNTAX_ONIGURUMA (&OnigSyntaxOniguruma)
+/* default syntax */
+#define ONIG_SYNTAX_DEFAULT OnigDefaultSyntax
+
+ONIG_EXTERN OnigSyntaxType* OnigDefaultSyntax;
+
+ONIG_EXTERN int onig_set_default_syntax P_((OnigSyntaxType* syntax));
+ONIG_EXTERN void onig_copy_syntax P_((OnigSyntaxType* to, OnigSyntaxType* from));
+ONIG_EXTERN const char* onig_version P_((void));
+ONIG_EXTERN const char* onig_copyright P_((void));
+ONIG_EXTERN int onig_end P_((void));
+
+#endif /* ONIGURUMA_H */
+
+
+ONIG_EXTERN int regcomp P_((regex_t* reg, const char* pat, int options));
+ONIG_EXTERN int regexec P_((regex_t* reg, const char* str, size_t nmatch, regmatch_t* matches, int options));
+ONIG_EXTERN void regfree P_((regex_t* reg));
+ONIG_EXTERN size_t regerror P_((int code, const regex_t* reg, char* buf, size_t size));
+
+/* extended API */
+ONIG_EXTERN void reg_set_encoding P_((int enc));
+ONIG_EXTERN int reg_name_to_group_numbers P_((regex_t* reg, const unsigned char* name, const unsigned char* name_end, int** nums));
+ONIG_EXTERN int reg_foreach_name P_((regex_t* reg, int (*func)(const unsigned char*, const unsigned char*,int,int*,regex_t*,void*), void* arg));
+ONIG_EXTERN int reg_number_of_names P_((regex_t* reg));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ONIGPOSIX_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniguruma.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniguruma.h
new file mode 100644
index 000000000..6b1397a7e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/oniguruma.h
@@ -0,0 +1,1053 @@
+#ifndef ONIGURUMA_H
+#define ONIGURUMA_H
+/**********************************************************************
+ oniguruma.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ONIGURUMA
+#define ONIGURUMA_VERSION_MAJOR 6
+#define ONIGURUMA_VERSION_MINOR 9
+#define ONIGURUMA_VERSION_TEENY 4
+
+#define ONIGURUMA_VERSION_INT 60904
+
+#ifndef P_
+#if defined(__STDC__) || defined(_WIN32)
+# define P_(args) args
+#else
+# define P_(args) ()
+#endif
+#endif
+
+#ifndef PV_
+# define PV_(args) args
+#endif
+
+#ifndef ONIG_STATIC
+#ifndef ONIG_EXTERN
+#if defined(_WIN32) && !defined(__GNUC__)
+#if defined(ONIGURUMA_EXPORT)
+#define ONIG_EXTERN extern __declspec(dllexport)
+#else
+#define ONIG_EXTERN extern __declspec(dllimport)
+#endif
+#endif
+#endif
+
+#ifndef ONIG_EXTERN
+#define ONIG_EXTERN extern
+#endif
+#else
+#define ONIG_EXTERN extern
+#endif
+
+#ifndef ONIG_VARIADIC_FUNC_ATTR
+#define ONIG_VARIADIC_FUNC_ATTR
+#endif
+
+/* PART: character encoding */
+
+#ifndef ONIG_ESCAPE_UCHAR_COLLISION
+#define UChar OnigUChar
+#endif
+
+typedef unsigned int OnigCodePoint;
+typedef unsigned char OnigUChar;
+typedef unsigned int OnigCtype;
+typedef unsigned int OnigLen;
+
+#define ONIG_INFINITE_DISTANCE ~((OnigLen )0)
+
+typedef unsigned int OnigCaseFoldType; /* case fold flag */
+
+ONIG_EXTERN OnigCaseFoldType OnigDefaultCaseFoldFlag;
+
+/* #define ONIGENC_CASE_FOLD_HIRAGANA_KATAKANA (1<<1) */
+/* #define ONIGENC_CASE_FOLD_KATAKANA_WIDTH (1<<2) */
+#define ONIGENC_CASE_FOLD_TURKISH_AZERI (1<<20)
+#define INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR (1<<30)
+
+#define ONIGENC_CASE_FOLD_MIN INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR
+#define ONIGENC_CASE_FOLD_DEFAULT OnigDefaultCaseFoldFlag
+
+
+#define ONIGENC_MAX_COMP_CASE_FOLD_CODE_LEN 3
+#define ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM 13
+/* 13 => Unicode:0x1ffc */
+
+/* code range */
+#define ONIGENC_CODE_RANGE_NUM(range) ((int )range[0])
+#define ONIGENC_CODE_RANGE_FROM(range,i) range[((i)*2) + 1]
+#define ONIGENC_CODE_RANGE_TO(range,i) range[((i)*2) + 2]
+
+typedef struct {
+ int byte_len; /* argument(original) character(s) byte length */
+ int code_len; /* number of code */
+ OnigCodePoint code[ONIGENC_MAX_COMP_CASE_FOLD_CODE_LEN];
+} OnigCaseFoldCodeItem;
+
+typedef struct {
+ OnigCodePoint esc;
+ OnigCodePoint anychar;
+ OnigCodePoint anytime;
+ OnigCodePoint zero_or_one_time;
+ OnigCodePoint one_or_more_time;
+ OnigCodePoint anychar_anytime;
+} OnigMetaCharTableType;
+
+typedef int (*OnigApplyAllCaseFoldFunc)(OnigCodePoint from, OnigCodePoint* to, int to_len, void* arg);
+
+typedef struct OnigEncodingTypeST {
+ int (*mbc_enc_len)(const OnigUChar* p);
+ const char* name;
+ int max_enc_len;
+ int min_enc_len;
+ int (*is_mbc_newline)(const OnigUChar* p, const OnigUChar* end);
+ OnigCodePoint (*mbc_to_code)(const OnigUChar* p, const OnigUChar* end);
+ int (*code_to_mbclen)(OnigCodePoint code);
+ int (*code_to_mbc)(OnigCodePoint code, OnigUChar *buf);
+ int (*mbc_case_fold)(OnigCaseFoldType flag, const OnigUChar** pp, const OnigUChar* end, OnigUChar* to);
+ int (*apply_all_case_fold)(OnigCaseFoldType flag, OnigApplyAllCaseFoldFunc f, void* arg);
+ int (*get_case_fold_codes_by_str)(OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem acs[]);
+ int (*property_name_to_ctype)(struct OnigEncodingTypeST* enc, OnigUChar* p, OnigUChar* end);
+ int (*is_code_ctype)(OnigCodePoint code, OnigCtype ctype);
+ int (*get_ctype_code_range)(OnigCtype ctype, OnigCodePoint* sb_out, const OnigCodePoint* ranges[]);
+ OnigUChar* (*left_adjust_char_head)(const OnigUChar* start, const OnigUChar* p);
+ int (*is_allowed_reverse_match)(const OnigUChar* p, const OnigUChar* end);
+ int (*init)(void);
+ int (*is_initialized)(void);
+ int (*is_valid_mbc_string)(const OnigUChar* s, const OnigUChar* end);
+ unsigned int flag;
+ OnigCodePoint sb_range;
+ int index;
+} OnigEncodingType;
+
+typedef OnigEncodingType* OnigEncoding;
+
+ONIG_EXTERN OnigEncodingType OnigEncodingASCII;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_1;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_2;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_3;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_4;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_5;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_6;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_7;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_8;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_9;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_10;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_11;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_13;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_14;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_15;
+ONIG_EXTERN OnigEncodingType OnigEncodingISO_8859_16;
+ONIG_EXTERN OnigEncodingType OnigEncodingUTF8;
+ONIG_EXTERN OnigEncodingType OnigEncodingUTF16_BE;
+ONIG_EXTERN OnigEncodingType OnigEncodingUTF16_LE;
+ONIG_EXTERN OnigEncodingType OnigEncodingUTF32_BE;
+ONIG_EXTERN OnigEncodingType OnigEncodingUTF32_LE;
+ONIG_EXTERN OnigEncodingType OnigEncodingEUC_JP;
+ONIG_EXTERN OnigEncodingType OnigEncodingEUC_TW;
+ONIG_EXTERN OnigEncodingType OnigEncodingEUC_KR;
+ONIG_EXTERN OnigEncodingType OnigEncodingEUC_CN;
+ONIG_EXTERN OnigEncodingType OnigEncodingSJIS;
+ONIG_EXTERN OnigEncodingType OnigEncodingKOI8;
+ONIG_EXTERN OnigEncodingType OnigEncodingKOI8_R;
+ONIG_EXTERN OnigEncodingType OnigEncodingCP1251;
+ONIG_EXTERN OnigEncodingType OnigEncodingBIG5;
+ONIG_EXTERN OnigEncodingType OnigEncodingGB18030;
+
+#define ONIG_ENCODING_ASCII (&OnigEncodingASCII)
+#define ONIG_ENCODING_ISO_8859_1 (&OnigEncodingISO_8859_1)
+#define ONIG_ENCODING_ISO_8859_2 (&OnigEncodingISO_8859_2)
+#define ONIG_ENCODING_ISO_8859_3 (&OnigEncodingISO_8859_3)
+#define ONIG_ENCODING_ISO_8859_4 (&OnigEncodingISO_8859_4)
+#define ONIG_ENCODING_ISO_8859_5 (&OnigEncodingISO_8859_5)
+#define ONIG_ENCODING_ISO_8859_6 (&OnigEncodingISO_8859_6)
+#define ONIG_ENCODING_ISO_8859_7 (&OnigEncodingISO_8859_7)
+#define ONIG_ENCODING_ISO_8859_8 (&OnigEncodingISO_8859_8)
+#define ONIG_ENCODING_ISO_8859_9 (&OnigEncodingISO_8859_9)
+#define ONIG_ENCODING_ISO_8859_10 (&OnigEncodingISO_8859_10)
+#define ONIG_ENCODING_ISO_8859_11 (&OnigEncodingISO_8859_11)
+#define ONIG_ENCODING_ISO_8859_13 (&OnigEncodingISO_8859_13)
+#define ONIG_ENCODING_ISO_8859_14 (&OnigEncodingISO_8859_14)
+#define ONIG_ENCODING_ISO_8859_15 (&OnigEncodingISO_8859_15)
+#define ONIG_ENCODING_ISO_8859_16 (&OnigEncodingISO_8859_16)
+#define ONIG_ENCODING_UTF8 (&OnigEncodingUTF8)
+#define ONIG_ENCODING_UTF16_BE (&OnigEncodingUTF16_BE)
+#define ONIG_ENCODING_UTF16_LE (&OnigEncodingUTF16_LE)
+#define ONIG_ENCODING_UTF32_BE (&OnigEncodingUTF32_BE)
+#define ONIG_ENCODING_UTF32_LE (&OnigEncodingUTF32_LE)
+#define ONIG_ENCODING_EUC_JP (&OnigEncodingEUC_JP)
+#define ONIG_ENCODING_EUC_TW (&OnigEncodingEUC_TW)
+#define ONIG_ENCODING_EUC_KR (&OnigEncodingEUC_KR)
+#define ONIG_ENCODING_EUC_CN (&OnigEncodingEUC_CN)
+#define ONIG_ENCODING_SJIS (&OnigEncodingSJIS)
+#define ONIG_ENCODING_KOI8 (&OnigEncodingKOI8)
+#define ONIG_ENCODING_KOI8_R (&OnigEncodingKOI8_R)
+#define ONIG_ENCODING_CP1251 (&OnigEncodingCP1251)
+#define ONIG_ENCODING_BIG5 (&OnigEncodingBIG5)
+#define ONIG_ENCODING_GB18030 (&OnigEncodingGB18030)
+
+#define ONIG_ENCODING_UNDEF ((OnigEncoding )0)
+
+
+/* work size */
+#define ONIGENC_CODE_TO_MBC_MAXLEN 7
+#define ONIGENC_MBC_CASE_FOLD_MAXLEN 18
+/* 18: 6(max-byte) * 3(case-fold chars) */
+
+/* character types */
+typedef enum {
+ ONIGENC_CTYPE_NEWLINE = 0,
+ ONIGENC_CTYPE_ALPHA = 1,
+ ONIGENC_CTYPE_BLANK = 2,
+ ONIGENC_CTYPE_CNTRL = 3,
+ ONIGENC_CTYPE_DIGIT = 4,
+ ONIGENC_CTYPE_GRAPH = 5,
+ ONIGENC_CTYPE_LOWER = 6,
+ ONIGENC_CTYPE_PRINT = 7,
+ ONIGENC_CTYPE_PUNCT = 8,
+ ONIGENC_CTYPE_SPACE = 9,
+ ONIGENC_CTYPE_UPPER = 10,
+ ONIGENC_CTYPE_XDIGIT = 11,
+ ONIGENC_CTYPE_WORD = 12,
+ ONIGENC_CTYPE_ALNUM = 13, /* alpha || digit */
+ ONIGENC_CTYPE_ASCII = 14
+} OnigEncCtype;
+
+#define ONIGENC_MAX_STD_CTYPE ONIGENC_CTYPE_ASCII
+
+
+#define onig_enc_len(enc,p,end) ONIGENC_MBC_ENC_LEN(enc,p)
+
+#define ONIGENC_IS_UNDEF(enc) ((enc) == ONIG_ENCODING_UNDEF)
+#define ONIGENC_IS_SINGLEBYTE(enc) (ONIGENC_MBC_MAXLEN(enc) == 1)
+#define ONIGENC_IS_MBC_HEAD(enc,p) (ONIGENC_MBC_ENC_LEN(enc,p) != 1)
+#define ONIGENC_IS_MBC_ASCII(p) (*(p) < 128)
+#define ONIGENC_IS_CODE_ASCII(code) ((code) < 128)
+#define ONIGENC_IS_MBC_WORD(enc,s,end) \
+ ONIGENC_IS_CODE_WORD(enc,ONIGENC_MBC_TO_CODE(enc,s,end))
+#define ONIGENC_IS_MBC_WORD_ASCII(enc,s,end) onigenc_is_mbc_word_ascii(enc,s,end)
+
+#define ONIGENC_NAME(enc) ((enc)->name)
+
+#define ONIGENC_MBC_CASE_FOLD(enc,flag,pp,end,buf) \
+ (enc)->mbc_case_fold(flag,(const OnigUChar** )pp,end,buf)
+#define ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc,s,end) \
+ (enc)->is_allowed_reverse_match(s,end)
+#define ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc,start,s) \
+ (enc)->left_adjust_char_head(start, s)
+#define ONIGENC_IS_VALID_MBC_STRING(enc,s,end) \
+ (enc)->is_valid_mbc_string(s,end)
+#define ONIGENC_APPLY_ALL_CASE_FOLD(enc,case_fold_flag,f,arg) \
+ (enc)->apply_all_case_fold(case_fold_flag,f,arg)
+#define ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc,case_fold_flag,p,end,acs) \
+ (enc)->get_case_fold_codes_by_str(case_fold_flag,p,end,acs)
+#define ONIGENC_STEP_BACK(enc,start,s,n) \
+ onigenc_step_back((enc),(start),(s),(n))
+
+#define ONIGENC_MBC_ENC_LEN(enc,p) (enc)->mbc_enc_len(p)
+#define ONIGENC_MBC_MAXLEN(enc) ((enc)->max_enc_len)
+#define ONIGENC_MBC_MAXLEN_DIST(enc) ONIGENC_MBC_MAXLEN(enc)
+#define ONIGENC_MBC_MINLEN(enc) ((enc)->min_enc_len)
+#define ONIGENC_IS_MBC_NEWLINE(enc,p,end) (enc)->is_mbc_newline((p),(end))
+#define ONIGENC_MBC_TO_CODE(enc,p,end) (enc)->mbc_to_code((p),(end))
+#define ONIGENC_CODE_TO_MBCLEN(enc,code) (enc)->code_to_mbclen(code)
+#define ONIGENC_CODE_TO_MBC(enc,code,buf) (enc)->code_to_mbc(code,buf)
+#define ONIGENC_PROPERTY_NAME_TO_CTYPE(enc,p,end) \
+ (enc)->property_name_to_ctype(enc,p,end)
+
+#define ONIGENC_IS_CODE_CTYPE(enc,code,ctype) (enc)->is_code_ctype(code,ctype)
+
+#define ONIGENC_IS_CODE_NEWLINE(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_NEWLINE)
+#define ONIGENC_IS_CODE_GRAPH(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_GRAPH)
+#define ONIGENC_IS_CODE_PRINT(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_PRINT)
+#define ONIGENC_IS_CODE_ALNUM(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_ALNUM)
+#define ONIGENC_IS_CODE_ALPHA(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_ALPHA)
+#define ONIGENC_IS_CODE_LOWER(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_LOWER)
+#define ONIGENC_IS_CODE_UPPER(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_UPPER)
+#define ONIGENC_IS_CODE_CNTRL(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_CNTRL)
+#define ONIGENC_IS_CODE_PUNCT(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_PUNCT)
+#define ONIGENC_IS_CODE_SPACE(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_SPACE)
+#define ONIGENC_IS_CODE_BLANK(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_BLANK)
+#define ONIGENC_IS_CODE_DIGIT(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_DIGIT)
+#define ONIGENC_IS_CODE_XDIGIT(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_XDIGIT)
+#define ONIGENC_IS_CODE_WORD(enc,code) \
+ ONIGENC_IS_CODE_CTYPE(enc,code,ONIGENC_CTYPE_WORD)
+
+#define ONIGENC_GET_CTYPE_CODE_RANGE(enc,ctype,sbout,ranges) \
+ (enc)->get_ctype_code_range(ctype,sbout,ranges)
+
+ONIG_EXTERN
+OnigUChar* onigenc_step_back P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, int n));
+
+
+/* encoding API */
+ONIG_EXTERN
+int onigenc_init P_((void));
+ONIG_EXTERN
+int onig_initialize_encoding P_((OnigEncoding enc));
+ONIG_EXTERN
+int onigenc_set_default_encoding P_((OnigEncoding enc));
+ONIG_EXTERN
+OnigEncoding onigenc_get_default_encoding P_((void));
+ONIG_EXTERN
+void onigenc_set_default_caseconv_table P_((const OnigUChar* table));
+ONIG_EXTERN
+OnigUChar* onigenc_get_right_adjust_char_head_with_prev P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar** prev));
+ONIG_EXTERN
+OnigUChar* onigenc_get_prev_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s));
+ONIG_EXTERN
+OnigUChar* onigenc_get_left_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s));
+ONIG_EXTERN
+OnigUChar* onigenc_get_right_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s));
+ONIG_EXTERN
+int onigenc_strlen P_((OnigEncoding enc, const OnigUChar* p, const OnigUChar* end));
+ONIG_EXTERN
+int onigenc_strlen_null P_((OnigEncoding enc, const OnigUChar* p));
+ONIG_EXTERN
+int onigenc_str_bytelen_null P_((OnigEncoding enc, const OnigUChar* p));
+ONIG_EXTERN
+int onigenc_is_valid_mbc_string P_((OnigEncoding enc, const OnigUChar* s, const OnigUChar* end));
+ONIG_EXTERN
+OnigUChar* onigenc_strdup P_((OnigEncoding enc, const OnigUChar* s, const OnigUChar* end));
+
+
+/* PART: regular expression */
+
+/* config parameters */
+#define ONIG_NREGION 10
+#define ONIG_MAX_CAPTURE_NUM 2147483647 /* 2**31 - 1 */
+#define ONIG_MAX_BACKREF_NUM 1000
+#define ONIG_MAX_REPEAT_NUM 100000
+#define ONIG_MAX_MULTI_BYTE_RANGES_NUM 10000
+/* constants */
+#define ONIG_MAX_ERROR_MESSAGE_LEN 90
+
+typedef unsigned int OnigOptionType;
+
+#define ONIG_OPTION_DEFAULT ONIG_OPTION_NONE
+
+/* options */
+#define ONIG_OPTION_NONE 0U
+/* options (compile time) */
+#define ONIG_OPTION_IGNORECASE 1U
+#define ONIG_OPTION_EXTEND (ONIG_OPTION_IGNORECASE << 1)
+#define ONIG_OPTION_MULTILINE (ONIG_OPTION_EXTEND << 1)
+#define ONIG_OPTION_SINGLELINE (ONIG_OPTION_MULTILINE << 1)
+#define ONIG_OPTION_FIND_LONGEST (ONIG_OPTION_SINGLELINE << 1)
+#define ONIG_OPTION_FIND_NOT_EMPTY (ONIG_OPTION_FIND_LONGEST << 1)
+#define ONIG_OPTION_NEGATE_SINGLELINE (ONIG_OPTION_FIND_NOT_EMPTY << 1)
+#define ONIG_OPTION_DONT_CAPTURE_GROUP (ONIG_OPTION_NEGATE_SINGLELINE << 1)
+#define ONIG_OPTION_CAPTURE_GROUP (ONIG_OPTION_DONT_CAPTURE_GROUP << 1)
+/* options (search time) */
+#define ONIG_OPTION_NOTBOL (ONIG_OPTION_CAPTURE_GROUP << 1)
+#define ONIG_OPTION_NOTEOL (ONIG_OPTION_NOTBOL << 1)
+#define ONIG_OPTION_POSIX_REGION (ONIG_OPTION_NOTEOL << 1)
+#define ONIG_OPTION_CHECK_VALIDITY_OF_STRING (ONIG_OPTION_POSIX_REGION << 1)
+/* #define ONIG_OPTION_CRLF_AS_LINE_SEPARATOR (ONIG_OPTION_CHECK_VALIDITY_OF_STRING << 1) */
+/* options (compile time) */
+#define ONIG_OPTION_WORD_IS_ASCII (ONIG_OPTION_CHECK_VALIDITY_OF_STRING << 4)
+#define ONIG_OPTION_DIGIT_IS_ASCII (ONIG_OPTION_WORD_IS_ASCII << 1)
+#define ONIG_OPTION_SPACE_IS_ASCII (ONIG_OPTION_DIGIT_IS_ASCII << 1)
+#define ONIG_OPTION_POSIX_IS_ASCII (ONIG_OPTION_SPACE_IS_ASCII << 1)
+#define ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER (ONIG_OPTION_POSIX_IS_ASCII << 1)
+#define ONIG_OPTION_TEXT_SEGMENT_WORD (ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER << 1)
+
+#define ONIG_OPTION_MAXBIT ONIG_OPTION_TEXT_SEGMENT_WORD /* limit */
+
+#define ONIG_OPTION_ON(options,regopt) ((options) |= (regopt))
+#define ONIG_OPTION_OFF(options,regopt) ((options) &= ~(regopt))
+#define ONIG_IS_OPTION_ON(options,option) ((options) & (option))
+
+/* syntax */
+typedef struct {
+ unsigned int op;
+ unsigned int op2;
+ unsigned int behavior;
+ OnigOptionType options; /* default option */
+ OnigMetaCharTableType meta_char_table;
+} OnigSyntaxType;
+
+ONIG_EXTERN OnigSyntaxType OnigSyntaxASIS;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPosixBasic;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPosixExtended;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxEmacs;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxGrep;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxGnuRegex;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxJava;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPerl;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxPerl_NG;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxRuby;
+ONIG_EXTERN OnigSyntaxType OnigSyntaxOniguruma;
+
+/* predefined syntaxes (see regsyntax.c) */
+#define ONIG_SYNTAX_ASIS (&OnigSyntaxASIS)
+#define ONIG_SYNTAX_POSIX_BASIC (&OnigSyntaxPosixBasic)
+#define ONIG_SYNTAX_POSIX_EXTENDED (&OnigSyntaxPosixExtended)
+#define ONIG_SYNTAX_EMACS (&OnigSyntaxEmacs)
+#define ONIG_SYNTAX_GREP (&OnigSyntaxGrep)
+#define ONIG_SYNTAX_GNU_REGEX (&OnigSyntaxGnuRegex)
+#define ONIG_SYNTAX_JAVA (&OnigSyntaxJava)
+#define ONIG_SYNTAX_PERL (&OnigSyntaxPerl)
+#define ONIG_SYNTAX_PERL_NG (&OnigSyntaxPerl_NG)
+#define ONIG_SYNTAX_RUBY (&OnigSyntaxRuby)
+#define ONIG_SYNTAX_ONIGURUMA (&OnigSyntaxOniguruma)
+
+/* default syntax */
+ONIG_EXTERN OnigSyntaxType* OnigDefaultSyntax;
+#define ONIG_SYNTAX_DEFAULT OnigDefaultSyntax
+
+/* syntax (operators) */
+#define ONIG_SYN_OP_VARIABLE_META_CHARACTERS (1U<<0)
+#define ONIG_SYN_OP_DOT_ANYCHAR (1U<<1) /* . */
+#define ONIG_SYN_OP_ASTERISK_ZERO_INF (1U<<2) /* * */
+#define ONIG_SYN_OP_ESC_ASTERISK_ZERO_INF (1U<<3)
+#define ONIG_SYN_OP_PLUS_ONE_INF (1U<<4) /* + */
+#define ONIG_SYN_OP_ESC_PLUS_ONE_INF (1U<<5)
+#define ONIG_SYN_OP_QMARK_ZERO_ONE (1U<<6) /* ? */
+#define ONIG_SYN_OP_ESC_QMARK_ZERO_ONE (1U<<7)
+#define ONIG_SYN_OP_BRACE_INTERVAL (1U<<8) /* {lower,upper} */
+#define ONIG_SYN_OP_ESC_BRACE_INTERVAL (1U<<9) /* \{lower,upper\} */
+#define ONIG_SYN_OP_VBAR_ALT (1U<<10) /* | */
+#define ONIG_SYN_OP_ESC_VBAR_ALT (1U<<11) /* \| */
+#define ONIG_SYN_OP_LPAREN_SUBEXP (1U<<12) /* (...) */
+#define ONIG_SYN_OP_ESC_LPAREN_SUBEXP (1U<<13) /* \(...\) */
+#define ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR (1U<<14) /* \A, \Z, \z */
+#define ONIG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR (1U<<15) /* \G */
+#define ONIG_SYN_OP_DECIMAL_BACKREF (1U<<16) /* \num */
+#define ONIG_SYN_OP_BRACKET_CC (1U<<17) /* [...] */
+#define ONIG_SYN_OP_ESC_W_WORD (1U<<18) /* \w, \W */
+#define ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END (1U<<19) /* \<. \> */
+#define ONIG_SYN_OP_ESC_B_WORD_BOUND (1U<<20) /* \b, \B */
+#define ONIG_SYN_OP_ESC_S_WHITE_SPACE (1U<<21) /* \s, \S */
+#define ONIG_SYN_OP_ESC_D_DIGIT (1U<<22) /* \d, \D */
+#define ONIG_SYN_OP_LINE_ANCHOR (1U<<23) /* ^, $ */
+#define ONIG_SYN_OP_POSIX_BRACKET (1U<<24) /* [:xxxx:] */
+#define ONIG_SYN_OP_QMARK_NON_GREEDY (1U<<25) /* ??,*?,+?,{n,m}? */
+#define ONIG_SYN_OP_ESC_CONTROL_CHARS (1U<<26) /* \n,\r,\t,\a ... */
+#define ONIG_SYN_OP_ESC_C_CONTROL (1U<<27) /* \cx */
+#define ONIG_SYN_OP_ESC_OCTAL3 (1U<<28) /* \OOO */
+#define ONIG_SYN_OP_ESC_X_HEX2 (1U<<29) /* \xHH */
+#define ONIG_SYN_OP_ESC_X_BRACE_HEX8 (1U<<30) /* \x{7HHHHHHH} */
+#define ONIG_SYN_OP_ESC_O_BRACE_OCTAL (1U<<31) /* \o{1OOOOOOOOOO} */
+
+#define ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE (1U<<0) /* \Q...\E */
+#define ONIG_SYN_OP2_QMARK_GROUP_EFFECT (1U<<1) /* (?...) */
+#define ONIG_SYN_OP2_OPTION_PERL (1U<<2) /* (?imsx),(?-imsx) */
+#define ONIG_SYN_OP2_OPTION_RUBY (1U<<3) /* (?imx), (?-imx) */
+#define ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT (1U<<4) /* ?+,*+,++ */
+#define ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL (1U<<5) /* {n,m}+ */
+#define ONIG_SYN_OP2_CCLASS_SET_OP (1U<<6) /* [...&&..[..]..] */
+#define ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP (1U<<7) /* (?<name>...) */
+#define ONIG_SYN_OP2_ESC_K_NAMED_BACKREF (1U<<8) /* \k<name> */
+#define ONIG_SYN_OP2_ESC_G_SUBEXP_CALL (1U<<9) /* \g<name>, \g<n> */
+#define ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY (1U<<10) /* (?@..),(?@<x>..) */
+#define ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL (1U<<11) /* \C-x */
+#define ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META (1U<<12) /* \M-x */
+#define ONIG_SYN_OP2_ESC_V_VTAB (1U<<13) /* \v as VTAB */
+#define ONIG_SYN_OP2_ESC_U_HEX4 (1U<<14) /* \uHHHH */
+#define ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR (1U<<15) /* \`, \' */
+#define ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY (1U<<16) /* \p{...}, \P{...} */
+#define ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT (1U<<17) /* \p{^..}, \P{^..} */
+/* #define ONIG_SYN_OP2_CHAR_PROPERTY_PREFIX_IS (1U<<18) */
+#define ONIG_SYN_OP2_ESC_H_XDIGIT (1U<<19) /* \h, \H */
+#define ONIG_SYN_OP2_INEFFECTIVE_ESCAPE (1U<<20) /* \ */
+#define ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE (1U<<21) /* (?(n)) (?(...)...|...) */
+#define ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP (1U<<22) /* \K */
+#define ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE (1U<<23) /* \R \r\n else [\x0a-\x0d] */
+#define ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT (1U<<24) /* \N (?-m:.), \O (?m:.) */
+#define ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP (1U<<25) /* (?~...) */
+#define ONIG_SYN_OP2_ESC_X_Y_GRAPHEME_CLUSTER (1U<<26) /* obsoleted: use next */
+#define ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT (1U<<26) /* \X \y \Y */
+#define ONIG_SYN_OP2_QMARK_PERL_SUBEXP_CALL (1U<<27) /* (?R), (?&name)... */
+#define ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS (1U<<28) /* (?{...}) (?{{...}}) */
+#define ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME (1U<<29) /* (*name) (*name{a,..}) */
+#define ONIG_SYN_OP2_OPTION_ONIGURUMA (1U<<30) /* (?imxWDSPy) */
+
+/* syntax (behavior) */
+#define ONIG_SYN_CONTEXT_INDEP_ANCHORS (1U<<31) /* not implemented */
+#define ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS (1U<<0) /* ?, *, +, {n,m} */
+#define ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS (1U<<1) /* error or ignore */
+#define ONIG_SYN_ALLOW_UNMATCHED_CLOSE_SUBEXP (1U<<2) /* ...)... */
+#define ONIG_SYN_ALLOW_INVALID_INTERVAL (1U<<3) /* {??? */
+#define ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV (1U<<4) /* {,n} => {0,n} */
+#define ONIG_SYN_STRICT_CHECK_BACKREF (1U<<5) /* /(\1)/,/\1()/ ..*/
+#define ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND (1U<<6) /* (?<=a|bc) */
+#define ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP (1U<<7) /* see doc/RE */
+#define ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME (1U<<8) /* (?<x>)(?<x>) */
+#define ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY (1U<<9) /* a{n}?=(?:a{n})? */
+#define ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH (1U<<10) /* ..(?i)...|... */
+#define ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND (1U<<11) /* (?<=a+|..) */
+
+/* syntax (behavior) in char class [...] */
+#define ONIG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC (1U<<20) /* [^...] */
+#define ONIG_SYN_BACKSLASH_ESCAPE_IN_CC (1U<<21) /* [..\w..] etc.. */
+#define ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC (1U<<22)
+#define ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC (1U<<23) /* [0-9-a]=[0-9\-a] */
+#define ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC (1U<<26)
+/* syntax (behavior) warning */
+#define ONIG_SYN_WARN_CC_OP_NOT_ESCAPED (1U<<24) /* [,-,] */
+#define ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT (1U<<25) /* (?:a*)+ */
+
+/* meta character specifiers (onig_set_meta_char()) */
+#define ONIG_META_CHAR_ESCAPE 0
+#define ONIG_META_CHAR_ANYCHAR 1
+#define ONIG_META_CHAR_ANYTIME 2
+#define ONIG_META_CHAR_ZERO_OR_ONE_TIME 3
+#define ONIG_META_CHAR_ONE_OR_MORE_TIME 4
+#define ONIG_META_CHAR_ANYCHAR_ANYTIME 5
+
+#define ONIG_INEFFECTIVE_META_CHAR 0
+
+/* error codes */
+#define ONIG_IS_PATTERN_ERROR(ecode) ((ecode) <= -100 && (ecode) > -1000)
+/* normal return */
+#define ONIG_NORMAL 0
+#define ONIG_MISMATCH -1
+#define ONIG_NO_SUPPORT_CONFIG -2
+#define ONIG_ABORT -3
+
+/* internal error */
+#define ONIGERR_MEMORY -5
+#define ONIGERR_TYPE_BUG -6
+#define ONIGERR_PARSER_BUG -11
+#define ONIGERR_STACK_BUG -12
+#define ONIGERR_UNDEFINED_BYTECODE -13
+#define ONIGERR_UNEXPECTED_BYTECODE -14
+#define ONIGERR_MATCH_STACK_LIMIT_OVER -15
+#define ONIGERR_PARSE_DEPTH_LIMIT_OVER -16
+#define ONIGERR_RETRY_LIMIT_IN_MATCH_OVER -17
+#define ONIGERR_RETRY_LIMIT_IN_SEARCH_OVER -18
+#define ONIGERR_DEFAULT_ENCODING_IS_NOT_SETTED -21
+#define ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR -22
+#define ONIGERR_FAIL_TO_INITIALIZE -23
+/* general error */
+#define ONIGERR_INVALID_ARGUMENT -30
+/* syntax error */
+#define ONIGERR_END_PATTERN_AT_LEFT_BRACE -100
+#define ONIGERR_END_PATTERN_AT_LEFT_BRACKET -101
+#define ONIGERR_EMPTY_CHAR_CLASS -102
+#define ONIGERR_PREMATURE_END_OF_CHAR_CLASS -103
+#define ONIGERR_END_PATTERN_AT_ESCAPE -104
+#define ONIGERR_END_PATTERN_AT_META -105
+#define ONIGERR_END_PATTERN_AT_CONTROL -106
+#define ONIGERR_META_CODE_SYNTAX -108
+#define ONIGERR_CONTROL_CODE_SYNTAX -109
+#define ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE -110
+#define ONIGERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE -111
+#define ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS -112
+#define ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED -113
+#define ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID -114
+#define ONIGERR_NESTED_REPEAT_OPERATOR -115
+#define ONIGERR_UNMATCHED_CLOSE_PARENTHESIS -116
+#define ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS -117
+#define ONIGERR_END_PATTERN_IN_GROUP -118
+#define ONIGERR_UNDEFINED_GROUP_OPTION -119
+#define ONIGERR_INVALID_POSIX_BRACKET_TYPE -121
+#define ONIGERR_INVALID_LOOK_BEHIND_PATTERN -122
+#define ONIGERR_INVALID_REPEAT_RANGE_PATTERN -123
+/* values error (syntax error) */
+#define ONIGERR_TOO_BIG_NUMBER -200
+#define ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE -201
+#define ONIGERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE -202
+#define ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS -203
+#define ONIGERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE -204
+#define ONIGERR_TOO_MANY_MULTI_BYTE_RANGES -205
+#define ONIGERR_TOO_SHORT_MULTI_BYTE_STRING -206
+#define ONIGERR_TOO_BIG_BACKREF_NUMBER -207
+#define ONIGERR_INVALID_BACKREF -208
+#define ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED -209
+#define ONIGERR_TOO_MANY_CAPTURES -210
+#define ONIGERR_TOO_LONG_WIDE_CHAR_VALUE -212
+#define ONIGERR_EMPTY_GROUP_NAME -214
+#define ONIGERR_INVALID_GROUP_NAME -215
+#define ONIGERR_INVALID_CHAR_IN_GROUP_NAME -216
+#define ONIGERR_UNDEFINED_NAME_REFERENCE -217
+#define ONIGERR_UNDEFINED_GROUP_REFERENCE -218
+#define ONIGERR_MULTIPLEX_DEFINED_NAME -219
+#define ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL -220
+#define ONIGERR_NEVER_ENDING_RECURSION -221
+#define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222
+#define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223
+#define ONIGERR_INVALID_IF_ELSE_SYNTAX -224
+#define ONIGERR_INVALID_ABSENT_GROUP_PATTERN -225
+#define ONIGERR_INVALID_ABSENT_GROUP_GENERATOR_PATTERN -226
+#define ONIGERR_INVALID_CALLOUT_PATTERN -227
+#define ONIGERR_INVALID_CALLOUT_NAME -228
+#define ONIGERR_UNDEFINED_CALLOUT_NAME -229
+#define ONIGERR_INVALID_CALLOUT_BODY -230
+#define ONIGERR_INVALID_CALLOUT_TAG_NAME -231
+#define ONIGERR_INVALID_CALLOUT_ARG -232
+#define ONIGERR_INVALID_CODE_POINT_VALUE -400
+#define ONIGERR_INVALID_WIDE_CHAR_VALUE -400
+#define ONIGERR_TOO_BIG_WIDE_CHAR_VALUE -401
+#define ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION -402
+#define ONIGERR_INVALID_COMBINATION_OF_OPTIONS -403
+#define ONIGERR_TOO_MANY_USER_DEFINED_OBJECTS -404
+#define ONIGERR_TOO_LONG_PROPERTY_NAME -405
+#define ONIGERR_LIBRARY_IS_NOT_INITIALIZED -500
+
+/* errors related to thread */
+/* #define ONIGERR_OVER_THREAD_PASS_LIMIT_COUNT -1001 */
+
+
+/* must be smaller than MEM_STATUS_BITS_NUM (unsigned int * 8) */
+#define ONIG_MAX_CAPTURE_HISTORY_GROUP 31
+#define ONIG_IS_CAPTURE_HISTORY_GROUP(r, i) \
+ ((i) <= ONIG_MAX_CAPTURE_HISTORY_GROUP && (r)->list && (r)->list[i])
+
+typedef struct OnigCaptureTreeNodeStruct {
+ int group; /* group number */
+ int beg;
+ int end;
+ int allocated;
+ int num_childs;
+ struct OnigCaptureTreeNodeStruct** childs;
+} OnigCaptureTreeNode;
+
+/* match result region type */
+struct re_registers {
+ int allocated;
+ int num_regs;
+ int* beg;
+ int* end;
+ /* extended */
+ OnigCaptureTreeNode* history_root; /* capture history tree root */
+};
+
+/* capture tree traverse */
+#define ONIG_TRAVERSE_CALLBACK_AT_FIRST 1
+#define ONIG_TRAVERSE_CALLBACK_AT_LAST 2
+#define ONIG_TRAVERSE_CALLBACK_AT_BOTH \
+ ( ONIG_TRAVERSE_CALLBACK_AT_FIRST | ONIG_TRAVERSE_CALLBACK_AT_LAST )
+
+
+#define ONIG_REGION_NOTPOS -1
+
+typedef struct re_registers OnigRegion;
+
+typedef struct {
+ OnigEncoding enc;
+ OnigUChar* par;
+ OnigUChar* par_end;
+} OnigErrorInfo;
+
+typedef struct {
+ int lower;
+ int upper;
+} OnigRepeatRange;
+
+typedef void (*OnigWarnFunc) P_((const char* s));
+extern void onig_null_warn P_((const char* s));
+#define ONIG_NULL_WARN onig_null_warn
+
+#define ONIG_CHAR_TABLE_SIZE 256
+
+struct re_pattern_buffer;
+typedef struct re_pattern_buffer OnigRegexType;
+typedef OnigRegexType* OnigRegex;
+
+#ifndef ONIG_ESCAPE_REGEX_T_COLLISION
+ typedef OnigRegexType regex_t;
+#endif
+
+struct OnigRegSetStruct;
+typedef struct OnigRegSetStruct OnigRegSet;
+
+typedef enum {
+ ONIG_REGSET_POSITION_LEAD = 0,
+ ONIG_REGSET_REGEX_LEAD = 1,
+ ONIG_REGSET_PRIORITY_TO_REGEX_ORDER = 2
+} OnigRegSetLead;
+
+typedef struct {
+ int num_of_elements;
+ OnigEncoding pattern_enc;
+ OnigEncoding target_enc;
+ OnigSyntaxType* syntax;
+ OnigOptionType option;
+ OnigCaseFoldType case_fold_flag;
+} OnigCompileInfo;
+
+
+/* types for callout */
+typedef enum {
+ ONIG_CALLOUT_IN_PROGRESS = 1, /* 1<<0 */
+ ONIG_CALLOUT_IN_RETRACTION = 2 /* 1<<1 */
+} OnigCalloutIn;
+
+#define ONIG_CALLOUT_IN_BOTH (ONIG_CALLOUT_IN_PROGRESS | ONIG_CALLOUT_IN_RETRACTION)
+
+typedef enum {
+ ONIG_CALLOUT_OF_CONTENTS = 0,
+ ONIG_CALLOUT_OF_NAME = 1
+} OnigCalloutOf;
+
+typedef enum {
+ ONIG_CALLOUT_TYPE_SINGLE = 0,
+ ONIG_CALLOUT_TYPE_START_CALL = 1,
+ ONIG_CALLOUT_TYPE_BOTH_CALL = 2,
+ ONIG_CALLOUT_TYPE_START_MARK_END_CALL = 3,
+} OnigCalloutType;
+
+
+#define ONIG_NON_NAME_ID -1
+#define ONIG_NON_CALLOUT_NUM 0
+
+#define ONIG_CALLOUT_MAX_ARGS_NUM 4
+#define ONIG_CALLOUT_DATA_SLOT_NUM 5
+
+struct OnigCalloutArgsStruct;
+typedef struct OnigCalloutArgsStruct OnigCalloutArgs;
+
+typedef int (*OnigCalloutFunc)(OnigCalloutArgs* args, void* user_data);
+
+/* callout function return values (less than -1: error code) */
+typedef enum {
+ ONIG_CALLOUT_FAIL = 1,
+ ONIG_CALLOUT_SUCCESS = 0
+} OnigCalloutResult;
+
+typedef enum {
+ ONIG_TYPE_VOID = 0,
+ ONIG_TYPE_LONG = 1<<0,
+ ONIG_TYPE_CHAR = 1<<1,
+ ONIG_TYPE_STRING = 1<<2,
+ ONIG_TYPE_POINTER = 1<<3,
+ ONIG_TYPE_TAG = 1<<4,
+} OnigType;
+
+typedef union {
+ long l;
+ OnigCodePoint c;
+ struct {
+ OnigUChar* start;
+ OnigUChar* end;
+ } s;
+ void* p;
+ int tag; /* tag -> callout_num */
+} OnigValue;
+
+
+struct OnigMatchParamStruct;
+typedef struct OnigMatchParamStruct OnigMatchParam;
+
+
+/* Oniguruma Native API */
+
+ONIG_EXTERN
+int onig_initialize P_((OnigEncoding encodings[], int number_of_encodings));
+/* onig_init(): deprecated function. Use onig_initialize(). */
+ONIG_EXTERN
+int onig_init P_((void));
+ONIG_EXTERN
+int ONIG_VARIADIC_FUNC_ATTR onig_error_code_to_str PV_((OnigUChar* s, int err_code, ...));
+ONIG_EXTERN
+int onig_is_error_code_needs_param PV_((int code));
+ONIG_EXTERN
+void onig_set_warn_func P_((OnigWarnFunc f));
+ONIG_EXTERN
+void onig_set_verb_warn_func P_((OnigWarnFunc f));
+ONIG_EXTERN
+int onig_new P_((OnigRegex*, const OnigUChar* pattern, const OnigUChar* pattern_end, OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax, OnigErrorInfo* einfo));
+ONIG_EXTERN
+int onig_reg_init P_((OnigRegex reg, OnigOptionType option, OnigCaseFoldType case_fold_flag, OnigEncoding enc, OnigSyntaxType* syntax));
+int onig_new_without_alloc P_((OnigRegex, const OnigUChar* pattern, const OnigUChar* pattern_end, OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax, OnigErrorInfo* einfo));
+ONIG_EXTERN
+int onig_new_deluxe P_((OnigRegex* reg, const OnigUChar* pattern, const OnigUChar* pattern_end, OnigCompileInfo* ci, OnigErrorInfo* einfo));
+ONIG_EXTERN
+void onig_free P_((OnigRegex));
+ONIG_EXTERN
+void onig_free_body P_((OnigRegex));
+ONIG_EXTERN
+int onig_scan(OnigRegex reg, const OnigUChar* str, const OnigUChar* end, OnigRegion* region, OnigOptionType option, int (*scan_callback)(int, int, OnigRegion*, void*), void* callback_arg);
+ONIG_EXTERN
+int onig_search P_((OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegion* region, OnigOptionType option));
+ONIG_EXTERN
+int onig_search_with_param P_((OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegion* region, OnigOptionType option, OnigMatchParam* mp));
+ONIG_EXTERN
+int onig_match P_((OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* at, OnigRegion* region, OnigOptionType option));
+ONIG_EXTERN
+int onig_match_with_param P_((OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* at, OnigRegion* region, OnigOptionType option, OnigMatchParam* mp));
+
+ONIG_EXTERN
+int onig_regset_new P_((OnigRegSet** rset, int n, regex_t* regs[]));
+ONIG_EXTERN
+int onig_regset_add P_((OnigRegSet* set, regex_t* reg));
+ONIG_EXTERN
+int onig_regset_replace P_((OnigRegSet* set, int at, regex_t* reg));
+ONIG_EXTERN
+void onig_regset_free P_((OnigRegSet* set));
+ONIG_EXTERN
+int onig_regset_number_of_regex P_((OnigRegSet* set));
+ONIG_EXTERN
+regex_t* onig_regset_get_regex P_((OnigRegSet* set, int at));
+ONIG_EXTERN
+OnigRegion* onig_regset_get_region P_((OnigRegSet* set, int at));
+ONIG_EXTERN
+int onig_regset_search P_((OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, int* rmatch_pos));
+ONIG_EXTERN
+int onig_regset_search_with_param P_((OnigRegSet* set, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegSetLead lead, OnigOptionType option, OnigMatchParam* mps[], int* rmatch_pos));
+
+ONIG_EXTERN
+OnigRegion* onig_region_new P_((void));
+ONIG_EXTERN
+void onig_region_init P_((OnigRegion* region));
+ONIG_EXTERN
+void onig_region_free P_((OnigRegion* region, int free_self));
+ONIG_EXTERN
+void onig_region_copy P_((OnigRegion* to, OnigRegion* from));
+ONIG_EXTERN
+void onig_region_clear P_((OnigRegion* region));
+ONIG_EXTERN
+int onig_region_resize P_((OnigRegion* region, int n));
+ONIG_EXTERN
+int onig_region_set P_((OnigRegion* region, int at, int beg, int end));
+ONIG_EXTERN
+int onig_name_to_group_numbers P_((OnigRegex reg, const OnigUChar* name, const OnigUChar* name_end, int** nums));
+ONIG_EXTERN
+int onig_name_to_backref_number P_((OnigRegex reg, const OnigUChar* name, const OnigUChar* name_end, OnigRegion *region));
+ONIG_EXTERN
+int onig_foreach_name P_((OnigRegex reg, int (*func)(const OnigUChar*, const OnigUChar*,int,int*,OnigRegex,void*), void* arg));
+ONIG_EXTERN
+int onig_number_of_names P_((OnigRegex reg));
+ONIG_EXTERN
+int onig_number_of_captures P_((OnigRegex reg));
+ONIG_EXTERN
+int onig_number_of_capture_histories P_((OnigRegex reg));
+ONIG_EXTERN
+OnigCaptureTreeNode* onig_get_capture_tree P_((OnigRegion* region));
+ONIG_EXTERN
+int onig_capture_tree_traverse P_((OnigRegion* region, int at, int(*callback_func)(int,int,int,int,int,void*), void* arg));
+ONIG_EXTERN
+int onig_noname_group_capture_is_active P_((OnigRegex reg));
+ONIG_EXTERN
+OnigEncoding onig_get_encoding P_((OnigRegex reg));
+ONIG_EXTERN
+OnigOptionType onig_get_options P_((OnigRegex reg));
+ONIG_EXTERN
+OnigCaseFoldType onig_get_case_fold_flag P_((OnigRegex reg));
+ONIG_EXTERN
+OnigSyntaxType* onig_get_syntax P_((OnigRegex reg));
+ONIG_EXTERN
+int onig_set_default_syntax P_((OnigSyntaxType* syntax));
+ONIG_EXTERN
+void onig_copy_syntax P_((OnigSyntaxType* to, OnigSyntaxType* from));
+ONIG_EXTERN
+unsigned int onig_get_syntax_op P_((OnigSyntaxType* syntax));
+ONIG_EXTERN
+unsigned int onig_get_syntax_op2 P_((OnigSyntaxType* syntax));
+ONIG_EXTERN
+unsigned int onig_get_syntax_behavior P_((OnigSyntaxType* syntax));
+ONIG_EXTERN
+OnigOptionType onig_get_syntax_options P_((OnigSyntaxType* syntax));
+ONIG_EXTERN
+void onig_set_syntax_op P_((OnigSyntaxType* syntax, unsigned int op));
+ONIG_EXTERN
+void onig_set_syntax_op2 P_((OnigSyntaxType* syntax, unsigned int op2));
+ONIG_EXTERN
+void onig_set_syntax_behavior P_((OnigSyntaxType* syntax, unsigned int behavior));
+ONIG_EXTERN
+void onig_set_syntax_options P_((OnigSyntaxType* syntax, OnigOptionType options));
+ONIG_EXTERN
+int onig_set_meta_char P_((OnigSyntaxType* syntax, unsigned int what, OnigCodePoint code));
+ONIG_EXTERN
+void onig_copy_encoding P_((OnigEncoding to, OnigEncoding from));
+ONIG_EXTERN
+OnigCaseFoldType onig_get_default_case_fold_flag P_((void));
+ONIG_EXTERN
+int onig_set_default_case_fold_flag P_((OnigCaseFoldType case_fold_flag));
+ONIG_EXTERN
+unsigned int onig_get_match_stack_limit_size P_((void));
+ONIG_EXTERN
+int onig_set_match_stack_limit_size P_((unsigned int size));
+ONIG_EXTERN
+unsigned long onig_get_retry_limit_in_match P_((void));
+ONIG_EXTERN
+int onig_set_retry_limit_in_match P_((unsigned long n));
+ONIG_EXTERN
+unsigned long onig_get_retry_limit_in_search P_((void));
+ONIG_EXTERN
+int onig_set_retry_limit_in_search P_((unsigned long n));
+ONIG_EXTERN
+unsigned int onig_get_parse_depth_limit P_((void));
+ONIG_EXTERN
+int onig_set_capture_num_limit P_((int num));
+ONIG_EXTERN
+int onig_set_parse_depth_limit P_((unsigned int depth));
+ONIG_EXTERN
+int onig_unicode_define_user_property P_((const char* name, OnigCodePoint* ranges));
+ONIG_EXTERN
+int onig_end P_((void));
+ONIG_EXTERN
+const char* onig_version P_((void));
+ONIG_EXTERN
+const char* onig_copyright P_((void));
+
+/* for OnigMatchParam */
+ONIG_EXTERN
+OnigMatchParam* onig_new_match_param P_((void));
+ONIG_EXTERN
+void onig_free_match_param P_((OnigMatchParam* p));
+ONIG_EXTERN
+void onig_free_match_param_content P_((OnigMatchParam* p));
+ONIG_EXTERN
+int onig_initialize_match_param P_((OnigMatchParam* mp));
+ONIG_EXTERN
+int onig_set_match_stack_limit_size_of_match_param P_((OnigMatchParam* param, unsigned int limit));
+ONIG_EXTERN
+int onig_set_retry_limit_in_match_of_match_param P_((OnigMatchParam* param, unsigned long limit));
+ONIG_EXTERN
+int onig_set_retry_limit_in_search_of_match_param P_((OnigMatchParam* param, unsigned long limit));
+ONIG_EXTERN
+int onig_set_progress_callout_of_match_param P_((OnigMatchParam* param, OnigCalloutFunc f));
+ONIG_EXTERN
+int onig_set_retraction_callout_of_match_param P_((OnigMatchParam* param, OnigCalloutFunc f));
+ONIG_EXTERN
+int onig_set_callout_user_data_of_match_param P_((OnigMatchParam* param, void* user_data));
+
+/* for callout functions */
+ONIG_EXTERN
+OnigCalloutFunc onig_get_progress_callout P_((void));
+ONIG_EXTERN
+int onig_set_progress_callout P_((OnigCalloutFunc f));
+ONIG_EXTERN
+OnigCalloutFunc onig_get_retraction_callout P_((void));
+ONIG_EXTERN
+int onig_set_retraction_callout P_((OnigCalloutFunc f));
+ONIG_EXTERN
+int onig_set_callout_of_name P_((OnigEncoding enc, OnigCalloutType type, OnigUChar* name, OnigUChar* name_end, int callout_in, OnigCalloutFunc callout, OnigCalloutFunc end_callout, int arg_num, unsigned int arg_types[], int optional_arg_num, OnigValue opt_defaults[]));
+ONIG_EXTERN
+OnigUChar* onig_get_callout_name_by_name_id P_((int id));
+ONIG_EXTERN
+int onig_get_callout_num_by_tag P_((OnigRegex reg, const OnigUChar* tag, const OnigUChar* tag_end));
+ONIG_EXTERN
+int onig_get_callout_data_by_tag P_((OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_set_callout_data_by_tag P_((OnigRegex reg, OnigMatchParam* mp, const OnigUChar* tag, const OnigUChar* tag_end, int slot, OnigType type, OnigValue* val));
+
+/* used in callout functions */
+ONIG_EXTERN
+int onig_get_callout_num_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+OnigCalloutIn onig_get_callout_in_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+int onig_get_name_id_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_contents_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_contents_end_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+int onig_get_args_num_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+int onig_get_passed_args_num_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+int onig_get_arg_by_callout_args P_((OnigCalloutArgs* args, int index, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+const OnigUChar* onig_get_string_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_string_end_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_start_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_right_range_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+const OnigUChar* onig_get_current_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+OnigRegex onig_get_regex_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+unsigned long onig_get_retry_counter_by_callout_args P_((OnigCalloutArgs* args));
+ONIG_EXTERN
+int onig_callout_tag_is_exist_at_callout_num P_((OnigRegex reg, int callout_num));
+ONIG_EXTERN
+const OnigUChar* onig_get_callout_tag_start P_((OnigRegex reg, int callout_num));
+ONIG_EXTERN
+const OnigUChar* onig_get_callout_tag_end P_((OnigRegex reg, int callout_num));
+ONIG_EXTERN
+int onig_get_callout_data_dont_clear_old P_((OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_get_callout_data_by_callout_args_self_dont_clear_old P_((OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_get_callout_data P_((OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_get_callout_data_by_callout_args P_((OnigCalloutArgs* args, int callout_num, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_get_callout_data_by_callout_args_self P_((OnigCalloutArgs* args, int slot, OnigType* type, OnigValue* val));
+ONIG_EXTERN
+int onig_set_callout_data P_((OnigRegex reg, OnigMatchParam* mp, int callout_num, int slot, OnigType type, OnigValue* val));
+ONIG_EXTERN
+int onig_set_callout_data_by_callout_args P_((OnigCalloutArgs* args, int callout_num, int slot, OnigType type, OnigValue* val));
+ONIG_EXTERN
+int onig_set_callout_data_by_callout_args_self P_((OnigCalloutArgs* args, int slot, OnigType type, OnigValue* val));
+ONIG_EXTERN
+int onig_get_capture_range_in_callout P_((OnigCalloutArgs* args, int mem_num, int* begin, int* end));
+ONIG_EXTERN
+int onig_get_used_stack_size_in_callout P_((OnigCalloutArgs* args, int* used_num, int* used_bytes));
+
+/* builtin callout functions */
+ONIG_EXTERN
+int onig_builtin_fail P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_mismatch P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_error P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_count P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_total_count P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_max P_((OnigCalloutArgs* args, void* user_data));
+ONIG_EXTERN
+int onig_builtin_cmp P_((OnigCalloutArgs* args, void* user_data));
+
+ONIG_EXTERN
+int onig_setup_builtin_monitors_by_ascii_encoded_name P_((void* fp));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ONIGURUMA_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regcomp.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regcomp.c
new file mode 100644
index 000000000..f61e89260
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regcomp.c
@@ -0,0 +1,7928 @@
+/**********************************************************************
+ regcomp.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regparse.h"
+
+#define OPS_INIT_SIZE 8
+
+typedef struct {
+ OnigLen min;
+ OnigLen max;
+} MinMaxLen;
+
+typedef struct {
+ OnigLen min;
+ OnigLen max;
+ int min_is_sure;
+} MinMaxCharLen;
+
+OnigCaseFoldType OnigDefaultCaseFoldFlag = ONIGENC_CASE_FOLD_MIN;
+
+static OnigLen node_min_byte_len(Node* node, ScanEnv* env);
+
+#if 0
+typedef struct {
+ int n;
+ int alloc;
+ int* v;
+} int_stack;
+
+static int
+make_int_stack(int_stack** rs, int init_size)
+{
+ int_stack* s;
+ int* v;
+
+ *rs = 0;
+
+ s = xmalloc(sizeof(*s));
+ if (IS_NULL(s)) return ONIGERR_MEMORY;
+
+ v = (int* )xmalloc(sizeof(int) * init_size);
+ if (IS_NULL(v)) {
+ xfree(s);
+ return ONIGERR_MEMORY;
+ }
+
+ s->n = 0;
+ s->alloc = init_size;
+ s->v = v;
+
+ *rs = s;
+ return ONIG_NORMAL;
+}
+
+static void
+free_int_stack(int_stack* s)
+{
+ if (IS_NOT_NULL(s)) {
+ if (IS_NOT_NULL(s->v))
+ xfree(s->v);
+ xfree(s);
+ }
+}
+
+static int
+int_stack_push(int_stack* s, int v)
+{
+ if (s->n >= s->alloc) {
+ int new_size = s->alloc * 2;
+ int* nv = (int* )xrealloc(s->v, sizeof(int) * new_size);
+ if (IS_NULL(nv)) return ONIGERR_MEMORY;
+
+ s->alloc = new_size;
+ s->v = nv;
+ }
+
+ s->v[s->n] = v;
+ s->n++;
+ return ONIG_NORMAL;
+}
+
+static int
+int_stack_pop(int_stack* s)
+{
+ int v;
+
+#ifdef ONIG_DEBUG
+ if (s->n <= 0) {
+ fprintf(DBGFP, "int_stack_pop: fail empty. %p\n", s);
+ return 0;
+ }
+#endif
+
+ v = s->v[s->n];
+ s->n--;
+ return v;
+}
+#endif
+
+static int
+ops_init(regex_t* reg, int init_alloc_size)
+{
+ Operation* p;
+ size_t size;
+
+ if (init_alloc_size > 0) {
+ size = sizeof(Operation) * init_alloc_size;
+ p = (Operation* )xrealloc(reg->ops, size);
+ CHECK_NULL_RETURN_MEMERR(p);
+#ifdef USE_DIRECT_THREADED_CODE
+ {
+ enum OpCode* cp;
+ size = sizeof(enum OpCode) * init_alloc_size;
+ cp = (enum OpCode* )xrealloc(reg->ocs, size);
+ CHECK_NULL_RETURN_MEMERR(cp);
+ reg->ocs = cp;
+ }
+#endif
+ }
+ else {
+ p = (Operation* )0;
+#ifdef USE_DIRECT_THREADED_CODE
+ reg->ocs = (enum OpCode* )0;
+#endif
+ }
+
+ reg->ops = p;
+ reg->ops_curr = 0; /* !!! not yet done ops_new() */
+ reg->ops_alloc = init_alloc_size;
+ reg->ops_used = 0;
+
+ return ONIG_NORMAL;
+}
+
+static int
+ops_expand(regex_t* reg, int n)
+{
+#define MIN_OPS_EXPAND_SIZE 4
+
+#ifdef USE_DIRECT_THREADED_CODE
+ enum OpCode* cp;
+#endif
+ Operation* p;
+ size_t size;
+
+ if (n <= 0) n = MIN_OPS_EXPAND_SIZE;
+
+ n += reg->ops_alloc;
+
+ size = sizeof(Operation) * n;
+ p = (Operation* )xrealloc(reg->ops, size);
+ CHECK_NULL_RETURN_MEMERR(p);
+
+#ifdef USE_DIRECT_THREADED_CODE
+ size = sizeof(enum OpCode) * n;
+ cp = (enum OpCode* )xrealloc(reg->ocs, size);
+ CHECK_NULL_RETURN_MEMERR(cp);
+ reg->ocs = cp;
+#endif
+
+ reg->ops = p;
+ reg->ops_alloc = n;
+ if (reg->ops_used == 0)
+ reg->ops_curr = 0;
+ else
+ reg->ops_curr = reg->ops + (reg->ops_used - 1);
+
+ return ONIG_NORMAL;
+}
+
+static int
+ops_new(regex_t* reg)
+{
+ int r;
+
+ if (reg->ops_used >= reg->ops_alloc) {
+ r = ops_expand(reg, reg->ops_alloc);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ reg->ops_curr = reg->ops + reg->ops_used;
+ reg->ops_used++;
+
+ xmemset(reg->ops_curr, 0, sizeof(Operation));
+ return ONIG_NORMAL;
+}
+
+static int
+is_in_string_pool(regex_t* reg, UChar* s)
+{
+ return (s >= reg->string_pool && s < reg->string_pool_end);
+}
+
+static void
+ops_free(regex_t* reg)
+{
+ int i;
+
+ if (IS_NULL(reg->ops)) return ;
+
+ for (i = 0; i < (int )reg->ops_used; i++) {
+ enum OpCode opcode;
+ Operation* op;
+
+ op = reg->ops + i;
+
+#ifdef USE_DIRECT_THREADED_CODE
+ opcode = *(reg->ocs + i);
+#else
+ opcode = op->opcode;
+#endif
+
+ switch (opcode) {
+ case OP_STR_MBN:
+ if (! is_in_string_pool(reg, op->exact_len_n.s))
+ xfree(op->exact_len_n.s);
+ break;
+ case OP_STR_N: case OP_STR_MB2N: case OP_STR_MB3N:
+ if (! is_in_string_pool(reg, op->exact_n.s))
+ xfree(op->exact_n.s);
+ break;
+ case OP_STR_1: case OP_STR_2: case OP_STR_3: case OP_STR_4:
+ case OP_STR_5: case OP_STR_MB2N1: case OP_STR_MB2N2:
+ case OP_STR_MB2N3:
+ break;
+
+ case OP_CCLASS_NOT: case OP_CCLASS:
+ xfree(op->cclass.bsp);
+ break;
+
+ case OP_CCLASS_MB_NOT: case OP_CCLASS_MB:
+ xfree(op->cclass_mb.mb);
+ break;
+ case OP_CCLASS_MIX_NOT: case OP_CCLASS_MIX:
+ xfree(op->cclass_mix.mb);
+ xfree(op->cclass_mix.bsp);
+ break;
+
+ case OP_BACKREF1: case OP_BACKREF2: case OP_BACKREF_N: case OP_BACKREF_N_IC:
+ break;
+ case OP_BACKREF_MULTI: case OP_BACKREF_MULTI_IC:
+ case OP_BACKREF_WITH_LEVEL:
+ case OP_BACKREF_WITH_LEVEL_IC:
+ case OP_BACKREF_CHECK:
+ case OP_BACKREF_CHECK_WITH_LEVEL:
+ if (op->backref_general.num != 1)
+ xfree(op->backref_general.ns);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ xfree(reg->ops);
+#ifdef USE_DIRECT_THREADED_CODE
+ xfree(reg->ocs);
+ reg->ocs = 0;
+#endif
+
+ reg->ops = 0;
+ reg->ops_curr = 0;
+ reg->ops_alloc = 0;
+ reg->ops_used = 0;
+}
+
+static int
+ops_calc_size_of_string_pool(regex_t* reg)
+{
+ int i;
+ int total;
+
+ if (IS_NULL(reg->ops)) return 0;
+
+ total = 0;
+ for (i = 0; i < (int )reg->ops_used; i++) {
+ enum OpCode opcode;
+ Operation* op;
+
+ op = reg->ops + i;
+#ifdef USE_DIRECT_THREADED_CODE
+ opcode = *(reg->ocs + i);
+#else
+ opcode = op->opcode;
+#endif
+
+ switch (opcode) {
+ case OP_STR_MBN:
+ total += op->exact_len_n.len * op->exact_len_n.n;
+ break;
+ case OP_STR_N:
+ case OP_STR_MB2N:
+ total += op->exact_n.n * 2;
+ break;
+ case OP_STR_MB3N:
+ total += op->exact_n.n * 3;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return total;
+}
+
+static int
+ops_make_string_pool(regex_t* reg)
+{
+ int i;
+ int len;
+ int size;
+ UChar* pool;
+ UChar* curr;
+
+ size = ops_calc_size_of_string_pool(reg);
+ if (size <= 0) {
+ return 0;
+ }
+
+ curr = pool = (UChar* )xmalloc((size_t )size);
+ CHECK_NULL_RETURN_MEMERR(pool);
+
+ for (i = 0; i < (int )reg->ops_used; i++) {
+ enum OpCode opcode;
+ Operation* op;
+
+ op = reg->ops + i;
+#ifdef USE_DIRECT_THREADED_CODE
+ opcode = *(reg->ocs + i);
+#else
+ opcode = op->opcode;
+#endif
+
+ switch (opcode) {
+ case OP_STR_MBN:
+ len = op->exact_len_n.len * op->exact_len_n.n;
+ xmemcpy(curr, op->exact_len_n.s, len);
+ xfree(op->exact_len_n.s);
+ op->exact_len_n.s = curr;
+ curr += len;
+ break;
+ case OP_STR_N:
+ len = op->exact_n.n;
+ copy:
+ xmemcpy(curr, op->exact_n.s, len);
+ xfree(op->exact_n.s);
+ op->exact_n.s = curr;
+ curr += len;
+ break;
+ case OP_STR_MB2N:
+ len = op->exact_n.n * 2;
+ goto copy;
+ break;
+ case OP_STR_MB3N:
+ len = op->exact_n.n * 3;
+ goto copy;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ reg->string_pool = pool;
+ reg->string_pool_end = pool + size;
+ return 0;
+}
+
+extern OnigCaseFoldType
+onig_get_default_case_fold_flag(void)
+{
+ return OnigDefaultCaseFoldFlag;
+}
+
+extern int
+onig_set_default_case_fold_flag(OnigCaseFoldType case_fold_flag)
+{
+ OnigDefaultCaseFoldFlag = case_fold_flag;
+ return 0;
+}
+
+static int
+len_multiply_cmp(OnigLen x, int y, OnigLen v)
+{
+ if (x == 0 || y == 0) return -1;
+
+ if (x < INFINITE_LEN / y) {
+ OnigLen xy = x * (OnigLen )y;
+ if (xy > v) return 1;
+ else {
+ if (xy == v) return 0;
+ else return -1;
+ }
+ }
+ else
+ return v == INFINITE_LEN ? 0 : 1;
+}
+
+extern int
+onig_positive_int_multiply(int x, int y)
+{
+ if (x == 0 || y == 0) return 0;
+
+ if (x < ONIG_INT_MAX / y)
+ return x * y;
+ else
+ return -1;
+}
+
+
+static void
+node_swap(Node* a, Node* b)
+{
+ Node c;
+
+ c = *a; *a = *b; *b = c;
+
+ if (NODE_TYPE(a) == NODE_STRING) {
+ StrNode* sn = STR_(a);
+ if (sn->capacity == 0) {
+ int len = (int )(sn->end - sn->s);
+ sn->s = sn->buf;
+ sn->end = sn->s + len;
+ }
+ }
+
+ if (NODE_TYPE(b) == NODE_STRING) {
+ StrNode* sn = STR_(b);
+ if (sn->capacity == 0) {
+ int len = (int )(sn->end - sn->s);
+ sn->s = sn->buf;
+ sn->end = sn->s + len;
+ }
+ }
+}
+
+static int
+node_list_len(Node* list)
+{
+ int len;
+
+ len = 1;
+ while (IS_NOT_NULL(NODE_CDR(list))) {
+ list = NODE_CDR(list);
+ len++;
+ }
+
+ return len;
+}
+
+static Node*
+node_list_add(Node* list, Node* x)
+{
+ Node *n;
+
+ n = onig_node_new_list(x, NULL);
+ if (IS_NULL(n)) return NULL_NODE;
+
+ if (IS_NOT_NULL(list)) {
+ while (IS_NOT_NULL(NODE_CDR(list)))
+ list = NODE_CDR(list);
+
+ NODE_CDR(list) = n;
+ }
+
+ return n;
+}
+
+static int
+node_str_node_cat(Node* node, Node* add)
+{
+ int r;
+
+ if (NODE_STATUS(node) != NODE_STATUS(add))
+ return ONIGERR_TYPE_BUG;
+
+ if (STR_(node)->flag != STR_(add)->flag)
+ return ONIGERR_TYPE_BUG;
+
+ r = onig_node_str_cat(node, STR_(add)->s, STR_(add)->end);
+ if (r != 0) return r;
+
+ return 0;
+}
+
+static void
+node_conv_to_str_node(Node* node, Node* ref_node)
+{
+ xmemset(node, 0, sizeof(*node));
+ NODE_SET_TYPE(node, NODE_STRING);
+ NODE_STATUS(node) = NODE_STATUS(ref_node);
+
+ STR_(node)->flag = STR_(ref_node)->flag;
+ STR_(node)->s = STR_(node)->buf;
+ STR_(node)->end = STR_(node)->buf;
+ STR_(node)->capacity = 0;
+}
+
+static OnigLen
+distance_add(OnigLen d1, OnigLen d2)
+{
+ if (d1 == INFINITE_LEN || d2 == INFINITE_LEN)
+ return INFINITE_LEN;
+ else {
+ if (d1 <= INFINITE_LEN - d2) return d1 + d2;
+ else return INFINITE_LEN;
+ }
+}
+
+static OnigLen
+distance_multiply(OnigLen d, int m)
+{
+ if (m == 0) return 0;
+
+ if (d < INFINITE_LEN / m)
+ return d * m;
+ else
+ return INFINITE_LEN;
+}
+
+static int
+bitset_is_empty(BitSetRef bs)
+{
+ int i;
+
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) {
+ if (bs[i] != 0) return 0;
+ }
+ return 1;
+}
+
+#ifdef USE_CALL
+
+static int
+unset_addr_list_init(UnsetAddrList* list, int size)
+{
+ UnsetAddr* p = (UnsetAddr* )xmalloc(sizeof(UnsetAddr)* size);
+ CHECK_NULL_RETURN_MEMERR(p);
+
+ list->num = 0;
+ list->alloc = size;
+ list->us = p;
+ return 0;
+}
+
+static void
+unset_addr_list_end(UnsetAddrList* list)
+{
+ if (IS_NOT_NULL(list->us))
+ xfree(list->us);
+}
+
+static int
+unset_addr_list_add(UnsetAddrList* list, int offset, struct _Node* node)
+{
+ UnsetAddr* p;
+ int size;
+
+ if (list->num >= list->alloc) {
+ size = list->alloc * 2;
+ p = (UnsetAddr* )xrealloc(list->us, sizeof(UnsetAddr) * size);
+ CHECK_NULL_RETURN_MEMERR(p);
+ list->alloc = size;
+ list->us = p;
+ }
+
+ list->us[list->num].offset = offset;
+ list->us[list->num].target = node;
+ list->num++;
+ return 0;
+}
+#endif /* USE_CALL */
+
+enum CharLenReturnType {
+ CHAR_LEN_NORMAL = 0, /* fixed or variable */
+ CHAR_LEN_TOP_ALT_FIXED = 1
+};
+
+static int
+mmcl_fixed(MinMaxCharLen* c)
+{
+ return (c->min == c->max && c->min != INFINITE_LEN);
+}
+
+static void
+mmcl_set(MinMaxCharLen* l, OnigLen len)
+{
+ l->min = len;
+ l->max = len;
+ l->min_is_sure = TRUE;
+}
+
+static void
+mmcl_set_min_max(MinMaxCharLen* l, OnigLen min, OnigLen max, int min_is_sure)
+{
+ l->min = min;
+ l->max = max;
+ l->min_is_sure = min_is_sure;
+}
+
+static void
+mmcl_add(MinMaxCharLen* to, MinMaxCharLen* add)
+{
+ to->min = distance_add(to->min, add->min);
+ to->max = distance_add(to->max, add->max);
+
+ to->min_is_sure = add->min_is_sure != 0 && to->min_is_sure != 0;
+}
+
+static void
+mmcl_multiply(MinMaxCharLen* to, int m)
+{
+ to->min = distance_multiply(to->min, m);
+ to->max = distance_multiply(to->max, m);
+}
+
+static void
+mmcl_repeat_range_multiply(MinMaxCharLen* to, int mlow, int mhigh)
+{
+ to->min = distance_multiply(to->min, mlow);
+
+ if (IS_INFINITE_REPEAT(mhigh))
+ to->max = INFINITE_LEN;
+ else
+ to->max = distance_multiply(to->max, mhigh);
+}
+
+static void
+mmcl_alt_merge(MinMaxCharLen* to, MinMaxCharLen* alt)
+{
+ if (to->min > alt->min) {
+ to->min = alt->min;
+ if (alt->min_is_sure != 0)
+ to->min_is_sure = TRUE;
+ }
+
+ if (to->max < alt->max) to->max = alt->max;
+}
+
+static int
+mml_is_equal(MinMaxLen* a, MinMaxLen* b)
+{
+ return a->min == b->min && a->max == b->max;
+}
+
+static void
+mml_set_min_max(MinMaxLen* l, OnigLen min, OnigLen max)
+{
+ l->min = min;
+ l->max = max;
+}
+
+static void
+mml_clear(MinMaxLen* l)
+{
+ l->min = l->max = 0;
+}
+
+static void
+mml_copy(MinMaxLen* to, MinMaxLen* from)
+{
+ to->min = from->min;
+ to->max = from->max;
+}
+
+static void
+mml_add(MinMaxLen* to, MinMaxLen* add)
+{
+ to->min = distance_add(to->min, add->min);
+ to->max = distance_add(to->max, add->max);
+}
+
+static void
+mml_alt_merge(MinMaxLen* to, MinMaxLen* alt)
+{
+ if (to->min > alt->min) to->min = alt->min;
+ if (to->max < alt->max) to->max = alt->max;
+}
+
+/* fixed size pattern node only */
+static int
+node_char_len1(Node* node, regex_t* reg, MinMaxCharLen* ci, ScanEnv* env,
+ int level)
+{
+ MinMaxCharLen tci;
+ int r = CHAR_LEN_NORMAL;
+
+ level++;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ {
+ int first = TRUE;
+ do {
+ r = node_char_len1(NODE_CAR(node), reg, &tci, env, level);
+ if (r < 0) break;
+ if (first == TRUE) {
+ *ci = tci;
+ first = FALSE;
+ }
+ else
+ mmcl_add(ci, &tci);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ }
+ break;
+
+ case NODE_ALT:
+ {
+ int fixed;
+
+ r = node_char_len1(NODE_CAR(node), reg, ci, env, level);
+ if (r < 0) break;
+
+ fixed = TRUE;
+ while (IS_NOT_NULL(node = NODE_CDR(node))) {
+ r = node_char_len1(NODE_CAR(node), reg, &tci, env, level);
+ if (r < 0) break;
+ if (! mmcl_fixed(&tci))
+ fixed = FALSE;
+ mmcl_alt_merge(ci, &tci);
+ }
+ if (r < 0) break;
+
+ r = CHAR_LEN_NORMAL;
+ if (mmcl_fixed(ci)) break;
+
+ if (fixed == TRUE && level == 1) {
+ r = CHAR_LEN_TOP_ALT_FIXED;
+ }
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ OnigLen clen;
+ StrNode* sn = STR_(node);
+ UChar *s = sn->s;
+
+ if (NODE_IS_IGNORECASE(node) && ! NODE_STRING_IS_CRUDE(node)) {
+ /* Such a case is possible.
+ ex. /(?i)(?<=\1)(a)/
+ Backref node refer to capture group, but it doesn't tune yet.
+ */
+ r = ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ break;
+ }
+
+ clen = 0;
+ while (s < sn->end) {
+ s += enclen(reg->enc, s);
+ clen = distance_add(clen, 1);
+ }
+ mmcl_set(ci, clen);
+ }
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (qn->lower == qn->upper) {
+ if (qn->upper == 0) {
+ mmcl_set(ci, 0);
+ }
+ else {
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ if (r < 0) break;
+ mmcl_multiply(ci, qn->lower);
+ }
+ }
+ else {
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ if (r < 0) break;
+ mmcl_repeat_range_multiply(ci, qn->lower, qn->upper);
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ if (NODE_IS_RECURSION(node))
+ mmcl_set_min_max(ci, 0, INFINITE_LEN, FALSE);
+ else
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ break;
+#endif
+
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ mmcl_set(ci, 1);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ switch (en->type) {
+ case BAG_MEMORY:
+ if (NODE_IS_FIXED_CLEN(node)) {
+ mmcl_set_min_max(ci, en->min_char_len, en->max_char_len,
+ NODE_IS_FIXED_CLEN_MIN_SURE(node));
+ }
+ else {
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ if (r < 0) break;
+
+ en->min_char_len = ci->min;
+ en->max_char_len = ci->max;
+ NODE_STATUS_ADD(node, FIXED_CLEN);
+ if (ci->min_is_sure != 0)
+ NODE_STATUS_ADD(node, FIXED_CLEN_MIN_SURE);
+ }
+ /* can't optimize look-behind if capture exists. */
+ ci->min_is_sure = FALSE;
+ break;
+ case BAG_OPTION:
+ case BAG_STOP_BACKTRACK:
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ break;
+ case BAG_IF_ELSE:
+ {
+ MinMaxCharLen eci;
+
+ r = node_char_len1(NODE_BODY(node), reg, ci, env, level);
+ if (r < 0) break;
+
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = node_char_len1(en->te.Then, reg, &tci, env, level);
+ if (r < 0) break;
+ mmcl_add(ci, &tci);
+ }
+
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = node_char_len1(en->te.Else, reg, &eci, env, level);
+ if (r < 0) break;
+ }
+ else {
+ mmcl_set(&eci, 0);
+ }
+
+ mmcl_alt_merge(ci, &eci);
+ }
+ break;
+ default: /* never come here */
+ r = ONIGERR_PARSER_BUG;
+ break;
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ mmcl_set(ci, 0);
+ /* can't optimize look-behind if anchor exists. */
+ ci->min_is_sure = FALSE;
+ break;
+
+ case NODE_GIMMICK:
+ zero:
+ mmcl_set(ci, 0);
+ break;
+
+ case NODE_BACKREF:
+ if (NODE_IS_CHECKER(node))
+ goto zero;
+
+ if (NODE_IS_RECURSION(node)) {
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (NODE_IS_NEST_LEVEL(node)) {
+ mmcl_set_min_max(ci, 0, INFINITE_LEN, FALSE);
+ break;
+ }
+#endif
+
+ mmcl_set_min_max(ci, 0, 0, FALSE);
+ break;
+ }
+
+ {
+ int i;
+ int* backs;
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+ BackRefNode* br = BACKREF_(node);
+
+ backs = BACKREFS_P(br);
+ r = node_char_len1(mem_env[backs[0]].mem_node, reg, ci, env, level);
+ if (r < 0) break;
+ if (! mmcl_fixed(ci)) ci->min_is_sure = FALSE;
+
+ for (i = 1; i < br->back_num; i++) {
+ r = node_char_len1(mem_env[backs[i]].mem_node, reg, &tci, env, level);
+ if (r < 0) break;
+ if (! mmcl_fixed(&tci)) tci.min_is_sure = FALSE;
+ mmcl_alt_merge(ci, &tci);
+ }
+ }
+ break;
+
+ default: /* never come here */
+ r = ONIGERR_PARSER_BUG;
+ break;
+ }
+
+ return r;
+}
+
+static int
+node_char_len(Node* node, regex_t* reg, MinMaxCharLen* ci, ScanEnv* env)
+{
+ return node_char_len1(node, reg, ci, env, 0);
+}
+
+
+static int
+add_op(regex_t* reg, int opcode)
+{
+ int r;
+
+ r = ops_new(reg);
+ if (r != ONIG_NORMAL) return r;
+
+#ifdef USE_DIRECT_THREADED_CODE
+ *(reg->ocs + (reg->ops_curr - reg->ops)) = opcode;
+#else
+ reg->ops_curr->opcode = opcode;
+#endif
+
+ return 0;
+}
+
+static int compile_length_tree(Node* node, regex_t* reg);
+static int compile_tree(Node* node, regex_t* reg, ScanEnv* env);
+
+
+#define IS_NEED_STR_LEN_OP(op) \
+ ((op) == OP_STR_N || (op) == OP_STR_MB2N ||\
+ (op) == OP_STR_MB3N || (op) == OP_STR_MBN)
+
+static int
+select_str_opcode(int mb_len, int str_len)
+{
+ int op;
+
+ switch (mb_len) {
+ case 1:
+ switch (str_len) {
+ case 1: op = OP_STR_1; break;
+ case 2: op = OP_STR_2; break;
+ case 3: op = OP_STR_3; break;
+ case 4: op = OP_STR_4; break;
+ case 5: op = OP_STR_5; break;
+ default: op = OP_STR_N; break;
+ }
+ break;
+
+ case 2:
+ switch (str_len) {
+ case 1: op = OP_STR_MB2N1; break;
+ case 2: op = OP_STR_MB2N2; break;
+ case 3: op = OP_STR_MB2N3; break;
+ default: op = OP_STR_MB2N; break;
+ }
+ break;
+
+ case 3:
+ op = OP_STR_MB3N;
+ break;
+
+ default:
+ op = OP_STR_MBN;
+ break;
+ }
+
+ return op;
+}
+
+static int
+is_strict_real_node(Node* node)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+ return (sn->end != sn->s);
+ }
+ break;
+
+ case NODE_CCLASS:
+ case NODE_CTYPE:
+ return 1;
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+}
+
+static int
+compile_quant_body_with_empty_check(QuantNode* qn, regex_t* reg, ScanEnv* env)
+{
+ int r;
+ int saved_num_empty_check;
+ int emptiness;
+ Node* body;
+
+ body = NODE_BODY((Node* )qn);
+ emptiness = qn->emptiness;
+ saved_num_empty_check = reg->num_empty_check;
+
+ if (emptiness != BODY_IS_NOT_EMPTY) {
+ r = add_op(reg, OP_EMPTY_CHECK_START);
+ if (r != 0) return r;
+ COP(reg)->empty_check_start.mem = reg->num_empty_check; /* NULL CHECK ID */
+ reg->num_empty_check++;
+ }
+
+ r = compile_tree(body, reg, env);
+ if (r != 0) return r;
+
+ if (emptiness != BODY_IS_NOT_EMPTY) {
+ if (emptiness == BODY_MAY_BE_EMPTY)
+ r = add_op(reg, OP_EMPTY_CHECK_END);
+ else if (emptiness == BODY_MAY_BE_EMPTY_MEM) {
+ if (NODE_IS_EMPTY_STATUS_CHECK(qn) != 0)
+ r = add_op(reg, OP_EMPTY_CHECK_END_MEMST);
+ else
+ r = add_op(reg, OP_EMPTY_CHECK_END);
+ }
+#ifdef USE_CALL
+ else if (emptiness == BODY_MAY_BE_EMPTY_REC)
+ r = add_op(reg, OP_EMPTY_CHECK_END_MEMST_PUSH);
+#endif
+
+ if (r != 0) return r;
+ COP(reg)->empty_check_end.mem = saved_num_empty_check; /* NULL CHECK ID */
+ }
+ return r;
+}
+
+#ifdef USE_CALL
+static int
+compile_call(CallNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r;
+ int offset;
+
+ r = add_op(reg, OP_CALL);
+ if (r != 0) return r;
+
+ COP(reg)->call.addr = 0; /* dummy addr. */
+
+ offset = COP_CURR_OFFSET_BYTES(reg, call.addr);
+ r = unset_addr_list_add(env->unset_addr_list, offset, NODE_CALL_BODY(node));
+ return r;
+}
+#endif
+
+static int
+compile_tree_n_times(Node* node, int n, regex_t* reg, ScanEnv* env)
+{
+ int i, r;
+
+ for (i = 0; i < n; i++) {
+ r = compile_tree(node, reg, env);
+ if (r != 0) return r;
+ }
+ return 0;
+}
+
+static int
+add_compile_string_length(UChar* s ARG_UNUSED, int mb_len, int str_len,
+ regex_t* reg ARG_UNUSED)
+{
+ return 1;
+}
+
+static int
+add_compile_string(UChar* s, int mb_len, int str_len, regex_t* reg)
+{
+ int op;
+ int r;
+ int byte_len;
+ UChar* p;
+ UChar* end;
+
+ op = select_str_opcode(mb_len, str_len);
+ r = add_op(reg, op);
+ if (r != 0) return r;
+
+ byte_len = mb_len * str_len;
+ end = s + byte_len;
+
+ if (op == OP_STR_MBN) {
+ p = onigenc_strdup(reg->enc, s, end);
+ CHECK_NULL_RETURN_MEMERR(p);
+
+ COP(reg)->exact_len_n.len = mb_len;
+ COP(reg)->exact_len_n.n = str_len;
+ COP(reg)->exact_len_n.s = p;
+ }
+ else if (IS_NEED_STR_LEN_OP(op)) {
+ p = onigenc_strdup(reg->enc, s, end);
+ CHECK_NULL_RETURN_MEMERR(p);
+ COP(reg)->exact_n.n = str_len;
+ COP(reg)->exact_n.s = p;
+ }
+ else {
+ xmemset(COP(reg)->exact.s, 0, sizeof(COP(reg)->exact.s));
+ xmemcpy(COP(reg)->exact.s, s, (size_t )byte_len);
+ }
+
+ return 0;
+}
+
+static int
+compile_length_string_node(Node* node, regex_t* reg)
+{
+ int rlen, r, len, prev_len, slen;
+ UChar *p, *prev;
+ StrNode* sn;
+ OnigEncoding enc = reg->enc;
+
+ sn = STR_(node);
+ if (sn->end <= sn->s)
+ return 0;
+
+ p = prev = sn->s;
+ prev_len = enclen(enc, p);
+ p += prev_len;
+ slen = 1;
+ rlen = 0;
+
+ for (; p < sn->end; ) {
+ len = enclen(enc, p);
+ if (len == prev_len) {
+ slen++;
+ }
+ else {
+ r = add_compile_string_length(prev, prev_len, slen, reg);
+ rlen += r;
+ prev = p;
+ slen = 1;
+ prev_len = len;
+ }
+ p += len;
+ }
+
+ r = add_compile_string_length(prev, prev_len, slen, reg);
+ rlen += r;
+ return rlen;
+}
+
+static int
+compile_length_string_crude_node(StrNode* sn, regex_t* reg)
+{
+ if (sn->end <= sn->s)
+ return 0;
+
+ return add_compile_string_length(sn->s, 1 /* sb */, (int )(sn->end - sn->s),
+ reg);
+}
+
+static int
+compile_string_node(Node* node, regex_t* reg)
+{
+ int r, len, prev_len, slen;
+ UChar *p, *prev, *end;
+ StrNode* sn;
+ OnigEncoding enc = reg->enc;
+
+ sn = STR_(node);
+ if (sn->end <= sn->s)
+ return 0;
+
+ end = sn->end;
+
+ p = prev = sn->s;
+ prev_len = enclen(enc, p);
+ p += prev_len;
+ slen = 1;
+
+ for (; p < end; ) {
+ len = enclen(enc, p);
+ if (len == prev_len) {
+ slen++;
+ }
+ else {
+ r = add_compile_string(prev, prev_len, slen, reg);
+ if (r != 0) return r;
+
+ prev = p;
+ slen = 1;
+ prev_len = len;
+ }
+
+ p += len;
+ }
+
+ return add_compile_string(prev, prev_len, slen, reg);
+}
+
+static int
+compile_string_crude_node(StrNode* sn, regex_t* reg)
+{
+ if (sn->end <= sn->s)
+ return 0;
+
+ return add_compile_string(sn->s, 1 /* sb */, (int )(sn->end - sn->s), reg);
+}
+
+static void*
+set_multi_byte_cclass(BBuf* mbuf, regex_t* reg)
+{
+ size_t len;
+ void* p;
+
+ len = (size_t )mbuf->used;
+ p = xmalloc(len);
+ if (IS_NULL(p)) return NULL;
+
+ xmemcpy(p, mbuf->p, len);
+ return p;
+}
+
+static int
+compile_length_cclass_node(CClassNode* cc, regex_t* reg)
+{
+ return 1;
+}
+
+static int
+compile_cclass_node(CClassNode* cc, regex_t* reg)
+{
+ int r;
+
+ if (IS_NULL(cc->mbuf)) {
+ r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_NOT : OP_CCLASS);
+ if (r != 0) return r;
+
+ COP(reg)->cclass.bsp = xmalloc(SIZE_BITSET);
+ CHECK_NULL_RETURN_MEMERR(COP(reg)->cclass.bsp);
+ xmemcpy(COP(reg)->cclass.bsp, cc->bs, SIZE_BITSET);
+ }
+ else {
+ void* p;
+
+ if (ONIGENC_MBC_MINLEN(reg->enc) > 1 || bitset_is_empty(cc->bs)) {
+ r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_MB_NOT : OP_CCLASS_MB);
+ if (r != 0) return r;
+
+ p = set_multi_byte_cclass(cc->mbuf, reg);
+ CHECK_NULL_RETURN_MEMERR(p);
+ COP(reg)->cclass_mb.mb = p;
+ }
+ else {
+ r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_MIX_NOT : OP_CCLASS_MIX);
+ if (r != 0) return r;
+
+ COP(reg)->cclass_mix.bsp = xmalloc(SIZE_BITSET);
+ CHECK_NULL_RETURN_MEMERR(COP(reg)->cclass_mix.bsp);
+ xmemcpy(COP(reg)->cclass_mix.bsp, cc->bs, SIZE_BITSET);
+
+ p = set_multi_byte_cclass(cc->mbuf, reg);
+ CHECK_NULL_RETURN_MEMERR(p);
+ COP(reg)->cclass_mix.mb = p;
+ }
+ }
+
+ return 0;
+}
+
+static void
+set_addr_in_repeat_range(regex_t* reg)
+{
+ int i;
+
+ for (i = 0; i < reg->num_repeat; i++) {
+ RepeatRange* p = reg->repeat_range + i;
+ int offset = p->u.offset;
+ p->u.pcode = reg->ops + offset;
+ }
+}
+
+static int
+entry_repeat_range(regex_t* reg, int id, int lower, int upper, int ops_index)
+{
+#define REPEAT_RANGE_ALLOC 4
+
+ RepeatRange* p;
+
+ if (reg->repeat_range_alloc == 0) {
+ p = (RepeatRange* )xmalloc(sizeof(RepeatRange) * REPEAT_RANGE_ALLOC);
+ CHECK_NULL_RETURN_MEMERR(p);
+ reg->repeat_range = p;
+ reg->repeat_range_alloc = REPEAT_RANGE_ALLOC;
+ }
+ else if (reg->repeat_range_alloc <= id) {
+ int n;
+ n = reg->repeat_range_alloc + REPEAT_RANGE_ALLOC;
+ p = (RepeatRange* )xrealloc(reg->repeat_range, sizeof(RepeatRange) * n);
+ CHECK_NULL_RETURN_MEMERR(p);
+ reg->repeat_range = p;
+ reg->repeat_range_alloc = n;
+ }
+ else {
+ p = reg->repeat_range;
+ }
+
+ p[id].lower = lower;
+ p[id].upper = (IS_INFINITE_REPEAT(upper) ? 0x7fffffff : upper);
+ p[id].u.offset = ops_index;
+ return 0;
+}
+
+static int
+compile_range_repeat_node(QuantNode* qn, int target_len, int emptiness,
+ regex_t* reg, ScanEnv* env)
+{
+ int r;
+ int num_repeat = reg->num_repeat++;
+
+ r = add_op(reg, qn->greedy ? OP_REPEAT : OP_REPEAT_NG);
+ if (r != 0) return r;
+
+ COP(reg)->repeat.id = num_repeat;
+ COP(reg)->repeat.addr = SIZE_INC + target_len + OPSIZE_REPEAT_INC;
+
+ r = entry_repeat_range(reg, num_repeat, qn->lower, qn->upper,
+ COP_CURR_OFFSET(reg) + OPSIZE_REPEAT);
+ if (r != 0) return r;
+
+ r = compile_quant_body_with_empty_check(qn, reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, qn->greedy ? OP_REPEAT_INC : OP_REPEAT_INC_NG);
+ if (r != 0) return r;
+
+ COP(reg)->repeat_inc.id = num_repeat;
+ return r;
+}
+
+static int
+is_anychar_infinite_greedy(QuantNode* qn)
+{
+ if (qn->greedy && IS_INFINITE_REPEAT(qn->upper) &&
+ NODE_IS_ANYCHAR(NODE_QUANT_BODY(qn)))
+ return 1;
+ else
+ return 0;
+}
+
+#define QUANTIFIER_EXPAND_LIMIT_SIZE 10
+#define CKN_ON (ckn > 0)
+
+static int
+compile_length_quantifier_node(QuantNode* qn, regex_t* reg)
+{
+ int len, mod_tlen;
+ int infinite = IS_INFINITE_REPEAT(qn->upper);
+ enum BodyEmptyType emptiness = qn->emptiness;
+ int tlen = compile_length_tree(NODE_QUANT_BODY(qn), reg);
+
+ if (tlen < 0) return tlen;
+ if (tlen == 0) return 0;
+
+ /* anychar repeat */
+ if (is_anychar_infinite_greedy(qn)) {
+ if (qn->lower <= 1 ||
+ len_multiply_cmp((OnigLen )tlen, qn->lower, QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0) {
+ if (IS_NOT_NULL(qn->next_head_exact))
+ return OPSIZE_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower;
+ else
+ return OPSIZE_ANYCHAR_STAR + tlen * qn->lower;
+ }
+ }
+
+ mod_tlen = tlen;
+ if (emptiness != BODY_IS_NOT_EMPTY)
+ mod_tlen += OPSIZE_EMPTY_CHECK_START + OPSIZE_EMPTY_CHECK_END;
+
+ if (infinite &&
+ (qn->lower <= 1 ||
+ len_multiply_cmp(tlen, qn->lower, QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+ if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
+ len = OPSIZE_JUMP;
+ }
+ else {
+ len = tlen * qn->lower;
+ }
+
+ if (qn->greedy) {
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ if (IS_NOT_NULL(qn->head_exact))
+ len += OPSIZE_PUSH_OR_JUMP_EXACT1 + mod_tlen + OPSIZE_JUMP;
+ else
+#endif
+ if (IS_NOT_NULL(qn->next_head_exact))
+ len += OPSIZE_PUSH_IF_PEEK_NEXT + mod_tlen + OPSIZE_JUMP;
+ else
+ len += OPSIZE_PUSH + mod_tlen + OPSIZE_JUMP;
+ }
+ else
+ len += OPSIZE_JUMP + mod_tlen + OPSIZE_PUSH;
+ }
+ else if (qn->upper == 0) {
+ if (qn->include_referred != 0) { /* /(?<n>..){0}/ */
+ len = OPSIZE_JUMP + tlen;
+ }
+ else
+ len = 0;
+ }
+ else if (!infinite && qn->greedy &&
+ (qn->upper == 1 ||
+ len_multiply_cmp((OnigLen )tlen + OPSIZE_PUSH, qn->upper,
+ QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+ len = tlen * qn->lower;
+ len += (OPSIZE_PUSH + tlen) * (qn->upper - qn->lower);
+ }
+ else if (!qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
+ len = OPSIZE_PUSH + OPSIZE_JUMP + tlen;
+ }
+ else {
+ len = OPSIZE_REPEAT_INC + mod_tlen + OPSIZE_REPEAT;
+ }
+
+ return len;
+}
+
+static int
+compile_quantifier_node(QuantNode* qn, regex_t* reg, ScanEnv* env)
+{
+ int i, r, mod_tlen;
+ int infinite = IS_INFINITE_REPEAT(qn->upper);
+ enum BodyEmptyType emptiness = qn->emptiness;
+ int tlen = compile_length_tree(NODE_QUANT_BODY(qn), reg);
+
+ if (tlen < 0) return tlen;
+ if (tlen == 0) return 0;
+
+ if (is_anychar_infinite_greedy(qn) &&
+ (qn->lower <= 1 ||
+ len_multiply_cmp((OnigLen )tlen, qn->lower,
+ QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+ r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
+ if (r != 0) return r;
+ if (IS_NOT_NULL(qn->next_head_exact)) {
+ r = add_op(reg, NODE_IS_MULTILINE(NODE_QUANT_BODY(qn)) ?
+ OP_ANYCHAR_ML_STAR_PEEK_NEXT : OP_ANYCHAR_STAR_PEEK_NEXT);
+ if (r != 0) return r;
+
+ COP(reg)->anychar_star_peek_next.c = STR_(qn->next_head_exact)->s[0];
+ return 0;
+ }
+ else {
+ r = add_op(reg, NODE_IS_MULTILINE(NODE_QUANT_BODY(qn)) ?
+ OP_ANYCHAR_ML_STAR : OP_ANYCHAR_STAR);
+ return r;
+ }
+ }
+
+ mod_tlen = tlen;
+ if (emptiness != BODY_IS_NOT_EMPTY)
+ mod_tlen += OPSIZE_EMPTY_CHECK_START + OPSIZE_EMPTY_CHECK_END;
+
+ if (infinite &&
+ (qn->lower <= 1 ||
+ len_multiply_cmp((OnigLen )tlen, qn->lower,
+ QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+ int addr;
+
+ if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ if (qn->greedy) {
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ if (IS_NOT_NULL(qn->head_exact))
+ COP(reg)->jump.addr = OPSIZE_PUSH_OR_JUMP_EXACT1 + SIZE_INC;
+ else
+#endif
+ if (IS_NOT_NULL(qn->next_head_exact))
+ COP(reg)->jump.addr = OPSIZE_PUSH_IF_PEEK_NEXT + SIZE_INC;
+ else
+ COP(reg)->jump.addr = OPSIZE_PUSH + SIZE_INC;
+ }
+ else {
+ COP(reg)->jump.addr = OPSIZE_JUMP + SIZE_INC;
+ }
+ }
+ else {
+ r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
+ if (r != 0) return r;
+ }
+
+ if (qn->greedy) {
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ if (IS_NOT_NULL(qn->head_exact)) {
+ r = add_op(reg, OP_PUSH_OR_JUMP_EXACT1);
+ if (r != 0) return r;
+ COP(reg)->push_or_jump_exact1.addr = SIZE_INC + mod_tlen + OPSIZE_JUMP;
+ COP(reg)->push_or_jump_exact1.c = STR_(qn->head_exact)->s[0];
+
+ r = compile_quant_body_with_empty_check(qn, reg, env);
+ if (r != 0) return r;
+
+ addr = -(mod_tlen + (int )OPSIZE_PUSH_OR_JUMP_EXACT1);
+ }
+ else
+#endif
+ if (IS_NOT_NULL(qn->next_head_exact)) {
+ r = add_op(reg, OP_PUSH_IF_PEEK_NEXT);
+ if (r != 0) return r;
+ COP(reg)->push_if_peek_next.addr = SIZE_INC + mod_tlen + OPSIZE_JUMP;
+ COP(reg)->push_if_peek_next.c = STR_(qn->next_head_exact)->s[0];
+
+ r = compile_quant_body_with_empty_check(qn, reg, env);
+ if (r != 0) return r;
+
+ addr = -(mod_tlen + (int )OPSIZE_PUSH_IF_PEEK_NEXT);
+ }
+ else {
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + mod_tlen + OPSIZE_JUMP;
+
+ r = compile_quant_body_with_empty_check(qn, reg, env);
+ if (r != 0) return r;
+
+ addr = -(mod_tlen + (int )OPSIZE_PUSH);
+ }
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = addr;
+ }
+ else {
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = mod_tlen + SIZE_INC;
+
+ r = compile_quant_body_with_empty_check(qn, reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = -mod_tlen;
+ }
+ }
+ else if (qn->upper == 0) {
+ if (qn->include_referred != 0) { /* /(?<n>..){0}/ */
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = tlen + SIZE_INC;
+
+ r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
+ }
+ else {
+ /* Nothing output */
+ r = 0;
+ }
+ }
+ else if (! infinite && qn->greedy &&
+ (qn->upper == 1 ||
+ len_multiply_cmp((OnigLen )tlen + OPSIZE_PUSH, qn->upper,
+ QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+ int n = qn->upper - qn->lower;
+
+ r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
+ if (r != 0) return r;
+
+ for (i = 0; i < n; i++) {
+ int v = onig_positive_int_multiply(n - i, tlen + OPSIZE_PUSH);
+ if (v < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = v;
+
+ r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
+ if (r != 0) return r;
+ }
+ }
+ else if (! qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + OPSIZE_JUMP;
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = tlen + SIZE_INC;
+
+ r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
+ }
+ else {
+ r = compile_range_repeat_node(qn, mod_tlen, emptiness, reg, env);
+ }
+ return r;
+}
+
+static int
+compile_length_option_node(BagNode* node, regex_t* reg)
+{
+ int tlen;
+
+ tlen = compile_length_tree(NODE_BAG_BODY(node), reg);
+
+ return tlen;
+}
+
+static int
+compile_option_node(BagNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r;
+
+ r = compile_tree(NODE_BAG_BODY(node), reg, env);
+
+ return r;
+}
+
+static int
+compile_length_bag_node(BagNode* node, regex_t* reg)
+{
+ int len;
+ int tlen;
+
+ if (node->type == BAG_OPTION)
+ return compile_length_option_node(node, reg);
+
+ if (NODE_BAG_BODY(node)) {
+ tlen = compile_length_tree(NODE_BAG_BODY(node), reg);
+ if (tlen < 0) return tlen;
+ }
+ else
+ tlen = 0;
+
+ switch (node->type) {
+ case BAG_MEMORY:
+#ifdef USE_CALL
+
+ if (node->m.regnum == 0 && NODE_IS_CALLED(node)) {
+ len = tlen + OPSIZE_CALL + OPSIZE_JUMP + OPSIZE_RETURN;
+ return len;
+ }
+
+ if (NODE_IS_CALLED(node)) {
+ len = OPSIZE_MEM_START_PUSH + tlen
+ + OPSIZE_CALL + OPSIZE_JUMP + OPSIZE_RETURN;
+ if (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum))
+ len += (NODE_IS_RECURSION(node)
+ ? OPSIZE_MEM_END_PUSH_REC : OPSIZE_MEM_END_PUSH);
+ else
+ len += (NODE_IS_RECURSION(node)
+ ? OPSIZE_MEM_END_REC : OPSIZE_MEM_END);
+ }
+ else if (NODE_IS_RECURSION(node)) {
+ len = OPSIZE_MEM_START_PUSH;
+ len += tlen + (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum)
+ ? OPSIZE_MEM_END_PUSH_REC : OPSIZE_MEM_END_REC);
+ }
+ else
+#endif
+ {
+ if (MEM_STATUS_AT0(reg->push_mem_start, node->m.regnum))
+ len = OPSIZE_MEM_START_PUSH;
+ else
+ len = OPSIZE_MEM_START;
+
+ len += tlen + (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum)
+ ? OPSIZE_MEM_END_PUSH : OPSIZE_MEM_END);
+ }
+ break;
+
+ case BAG_STOP_BACKTRACK:
+ if (NODE_IS_STRICT_REAL_REPEAT(node)) {
+ int v;
+ QuantNode* qn;
+
+ qn = QUANT_(NODE_BAG_BODY(node));
+ tlen = compile_length_tree(NODE_QUANT_BODY(qn), reg);
+ if (tlen < 0) return tlen;
+
+ v = onig_positive_int_multiply(qn->lower, tlen);
+ if (v < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+ len = v + OPSIZE_PUSH + tlen + OPSIZE_POP + OPSIZE_JUMP;
+ }
+ else {
+ len = OPSIZE_MARK + tlen + OPSIZE_CUT_TO_MARK;
+ }
+ break;
+
+ case BAG_IF_ELSE:
+ {
+ Node* cond = NODE_BAG_BODY(node);
+ Node* Then = node->te.Then;
+ Node* Else = node->te.Else;
+
+ len = compile_length_tree(cond, reg);
+ if (len < 0) return len;
+ len += OPSIZE_PUSH + OPSIZE_MARK + OPSIZE_CUT_TO_MARK;
+
+ if (IS_NOT_NULL(Then)) {
+ tlen = compile_length_tree(Then, reg);
+ if (tlen < 0) return tlen;
+ len += tlen;
+ }
+
+ len += OPSIZE_JUMP + OPSIZE_CUT_TO_MARK;
+
+ if (IS_NOT_NULL(Else)) {
+ tlen = compile_length_tree(Else, reg);
+ if (tlen < 0) return tlen;
+ len += tlen;
+ }
+ }
+ break;
+
+ case BAG_OPTION:
+ /* never come here, but set for escape warning */
+ len = 0;
+ break;
+ }
+
+ return len;
+}
+
+static int
+compile_bag_memory_node(BagNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r;
+
+#ifdef USE_CALL
+ if (NODE_IS_CALLED(node)) {
+ int len;
+
+ r = add_op(reg, OP_CALL);
+ if (r != 0) return r;
+
+ node->m.called_addr = COP_CURR_OFFSET(reg) + 1 + OPSIZE_JUMP;
+ NODE_STATUS_ADD(node, FIXED_ADDR);
+ COP(reg)->call.addr = (int )node->m.called_addr;
+
+ if (node->m.regnum == 0) {
+ len = compile_length_tree(NODE_BAG_BODY(node), reg);
+ len += OPSIZE_RETURN;
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = len + SIZE_INC;
+
+ r = compile_tree(NODE_BAG_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_RETURN);
+ return r;
+ }
+ else {
+ len = compile_length_tree(NODE_BAG_BODY(node), reg);
+ len += (OPSIZE_MEM_START_PUSH + OPSIZE_RETURN);
+ if (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum))
+ len += (NODE_IS_RECURSION(node)
+ ? OPSIZE_MEM_END_PUSH_REC : OPSIZE_MEM_END_PUSH);
+ else
+ len += (NODE_IS_RECURSION(node) ? OPSIZE_MEM_END_REC : OPSIZE_MEM_END);
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = len + SIZE_INC;
+ }
+ }
+#endif
+
+ if (MEM_STATUS_AT0(reg->push_mem_start, node->m.regnum))
+ r = add_op(reg, OP_MEM_START_PUSH);
+ else
+ r = add_op(reg, OP_MEM_START);
+ if (r != 0) return r;
+ COP(reg)->memory_start.num = node->m.regnum;
+
+ r = compile_tree(NODE_BAG_BODY(node), reg, env);
+ if (r != 0) return r;
+
+#ifdef USE_CALL
+ if (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum))
+ r = add_op(reg, (NODE_IS_RECURSION(node)
+ ? OP_MEM_END_PUSH_REC : OP_MEM_END_PUSH));
+ else
+ r = add_op(reg, (NODE_IS_RECURSION(node) ? OP_MEM_END_REC : OP_MEM_END));
+ if (r != 0) return r;
+ COP(reg)->memory_end.num = node->m.regnum;
+
+ if (NODE_IS_CALLED(node)) {
+ if (r != 0) return r;
+ r = add_op(reg, OP_RETURN);
+ }
+#else
+ if (MEM_STATUS_AT0(reg->push_mem_end, node->m.regnum))
+ r = add_op(reg, OP_MEM_END_PUSH);
+ else
+ r = add_op(reg, OP_MEM_END);
+ if (r != 0) return r;
+ COP(reg)->memory_end.num = node->m.regnum;
+#endif
+
+ return r;
+}
+
+static int
+compile_bag_node(BagNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r, len;
+
+ switch (node->type) {
+ case BAG_MEMORY:
+ r = compile_bag_memory_node(node, reg, env);
+ break;
+
+ case BAG_OPTION:
+ r = compile_option_node(node, reg, env);
+ break;
+
+ case BAG_STOP_BACKTRACK:
+ if (NODE_IS_STRICT_REAL_REPEAT(node)) {
+ QuantNode* qn = QUANT_(NODE_BAG_BODY(node));
+ r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
+ if (r != 0) return r;
+
+ len = compile_length_tree(NODE_QUANT_BODY(qn), reg);
+ if (len < 0) return len;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + len + OPSIZE_POP + OPSIZE_JUMP;
+
+ r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
+ if (r != 0) return r;
+ r = add_op(reg, OP_POP);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = -((int )OPSIZE_PUSH + len + (int )OPSIZE_POP);
+ }
+ else {
+ MemNumType mid;
+
+ ID_ENTRY(env, mid);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = 0;
+
+ r = compile_tree(NODE_BAG_BODY(node), reg, env);
+ if (r != 0) return r;
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid;
+ COP(reg)->cut_to_mark.restore_pos = 0;
+ }
+ break;
+
+ case BAG_IF_ELSE:
+ {
+ int cond_len, then_len, else_len, jump_len;
+ MemNumType mid;
+ Node* cond = NODE_BAG_BODY(node);
+ Node* Then = node->te.Then;
+ Node* Else = node->te.Else;
+
+ ID_ENTRY(env, mid);
+
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = 0;
+
+ cond_len = compile_length_tree(cond, reg);
+ if (cond_len < 0) return cond_len;
+ if (IS_NOT_NULL(Then)) {
+ then_len = compile_length_tree(Then, reg);
+ if (then_len < 0) return then_len;
+ }
+ else
+ then_len = 0;
+
+ jump_len = cond_len + then_len + OPSIZE_CUT_TO_MARK + OPSIZE_JUMP;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + jump_len;
+
+ r = compile_tree(cond, reg, env);
+ if (r != 0) return r;
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid;
+ COP(reg)->cut_to_mark.restore_pos = 0;
+
+ if (IS_NOT_NULL(Then)) {
+ r = compile_tree(Then, reg, env);
+ if (r != 0) return r;
+ }
+
+ if (IS_NOT_NULL(Else)) {
+ else_len = compile_length_tree(Else, reg);
+ if (else_len < 0) return else_len;
+ }
+ else
+ else_len = 0;
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = OPSIZE_CUT_TO_MARK + else_len + SIZE_INC;
+
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid;
+ COP(reg)->cut_to_mark.restore_pos = 0;
+
+ if (IS_NOT_NULL(Else)) {
+ r = compile_tree(Else, reg, env);
+ }
+ }
+ break;
+ }
+
+ return r;
+}
+
+static int
+compile_length_anchor_node(AnchorNode* node, regex_t* reg)
+{
+ int len;
+ int tlen = 0;
+
+ if (IS_NOT_NULL(NODE_ANCHOR_BODY(node))) {
+ tlen = compile_length_tree(NODE_ANCHOR_BODY(node), reg);
+ if (tlen < 0) return tlen;
+ }
+
+ switch (node->type) {
+ case ANCR_PREC_READ:
+ len = OPSIZE_MARK + tlen + OPSIZE_CUT_TO_MARK;
+ break;
+ case ANCR_PREC_READ_NOT:
+ len = OPSIZE_PUSH + OPSIZE_MARK + tlen + OPSIZE_POP_TO_MARK + OPSIZE_POP + OPSIZE_FAIL;
+ break;
+ case ANCR_LOOK_BEHIND:
+ if (node->char_min_len == node->char_max_len)
+ len = OPSIZE_MARK + OPSIZE_STEP_BACK_START + tlen + OPSIZE_CUT_TO_MARK;
+ else {
+ len = OPSIZE_SAVE_VAL + OPSIZE_UPDATE_VAR + OPSIZE_MARK + OPSIZE_PUSH + OPSIZE_UPDATE_VAR + OPSIZE_FAIL + OPSIZE_JUMP + OPSIZE_STEP_BACK_START + OPSIZE_STEP_BACK_NEXT + tlen + OPSIZE_CHECK_POSITION + OPSIZE_CUT_TO_MARK + OPSIZE_UPDATE_VAR;
+
+ if (IS_NOT_NULL(node->lead_node)) {
+ int llen = compile_length_tree(node->lead_node, reg);
+ if (llen < 0) return llen;
+
+ len += OPSIZE_MOVE + llen;
+ }
+ }
+ break;
+ case ANCR_LOOK_BEHIND_NOT:
+ if (node->char_min_len == node->char_max_len)
+ len = OPSIZE_MARK + OPSIZE_PUSH + OPSIZE_STEP_BACK_START + tlen + OPSIZE_POP_TO_MARK + OPSIZE_FAIL + OPSIZE_POP;
+ else {
+ len = OPSIZE_SAVE_VAL + OPSIZE_UPDATE_VAR + OPSIZE_MARK + OPSIZE_PUSH + OPSIZE_STEP_BACK_START + OPSIZE_STEP_BACK_NEXT + tlen + OPSIZE_CHECK_POSITION + OPSIZE_POP_TO_MARK + OPSIZE_UPDATE_VAR + OPSIZE_POP + OPSIZE_FAIL + OPSIZE_UPDATE_VAR + OPSIZE_POP + OPSIZE_POP;
+
+ if (IS_NOT_NULL(node->lead_node)) {
+ int llen = compile_length_tree(node->lead_node, reg);
+ if (llen < 0) return llen;
+
+ len += OPSIZE_MOVE + llen;
+ }
+ }
+ break;
+
+ case ANCR_WORD_BOUNDARY:
+ case ANCR_NO_WORD_BOUNDARY:
+#ifdef USE_WORD_BEGIN_END
+ case ANCR_WORD_BEGIN:
+ case ANCR_WORD_END:
+#endif
+ len = OPSIZE_WORD_BOUNDARY;
+ break;
+
+ case ANCR_TEXT_SEGMENT_BOUNDARY:
+ case ANCR_NO_TEXT_SEGMENT_BOUNDARY:
+ len = SIZE_OPCODE;
+ break;
+
+ default:
+ len = SIZE_OPCODE;
+ break;
+ }
+
+ return len;
+}
+
+static int
+compile_anchor_look_behind_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r;
+
+ if (node->char_min_len == node->char_max_len) {
+ MemNumType mid;
+
+ ID_ENTRY(env, mid);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = FALSE;
+
+ r = add_op(reg, OP_STEP_BACK_START);
+ if (r != 0) return r;
+ COP(reg)->step_back_start.initial = node->char_min_len;
+ COP(reg)->step_back_start.remaining = 0;
+ COP(reg)->step_back_start.addr = 1;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid;
+ COP(reg)->cut_to_mark.restore_pos = FALSE;
+ }
+ else {
+ MemNumType mid1, mid2;
+ OnigLen diff;
+
+ if (IS_NOT_NULL(node->lead_node)) {
+ MinMaxCharLen ci;
+
+ r = node_char_len(node->lead_node, reg, &ci, env);
+ if (r < 0) return r;
+ r = add_op(reg, OP_MOVE);
+ if (r != 0) return r;
+ COP(reg)->move.n = -((RelPositionType )ci.min);
+ r = compile_tree(node->lead_node, reg, env);
+ if (r != 0) return r;
+ }
+
+ ID_ENTRY(env, mid1);
+ r = add_op(reg, OP_SAVE_VAL);
+ if (r != 0) return r;
+ COP(reg)->save_val.type = SAVE_RIGHT_RANGE;
+ COP(reg)->save_val.id = mid1;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_TO_S;
+
+ ID_ENTRY(env, mid2);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid2;
+ COP(reg)->mark.save_pos = FALSE;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + OPSIZE_JUMP;
+
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) return r;
+ COP(reg)->jump.addr = SIZE_INC + OPSIZE_UPDATE_VAR + OPSIZE_FAIL;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_FROM_STACK;
+ COP(reg)->update_var.id = mid1;
+ COP(reg)->update_var.clear = FALSE;
+ r = add_op(reg, OP_FAIL);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_STEP_BACK_START);
+ if (r != 0) return r;
+
+ if (node->char_max_len != INFINITE_LEN)
+ diff = node->char_max_len - node->char_min_len;
+ else
+ diff = INFINITE_LEN;
+
+ COP(reg)->step_back_start.initial = node->char_min_len;
+ COP(reg)->step_back_start.remaining = diff;
+ COP(reg)->step_back_start.addr = 2;
+
+ r = add_op(reg, OP_STEP_BACK_NEXT);
+ if (r != 0) return r;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_CHECK_POSITION);
+ if (r != 0) return r;
+ COP(reg)->check_position.type = CHECK_POSITION_CURRENT_RIGHT_RANGE;
+
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid2;
+ COP(reg)->cut_to_mark.restore_pos = FALSE;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_FROM_STACK;
+ COP(reg)->update_var.id = mid1;
+ COP(reg)->update_var.clear = TRUE;
+ }
+
+ return r;
+}
+
+static int
+compile_anchor_look_behind_not_node(AnchorNode* node, regex_t* reg,
+ ScanEnv* env)
+{
+ int r;
+ int len;
+
+ len = compile_length_tree(NODE_ANCHOR_BODY(node), reg);
+
+ if (node->char_min_len == node->char_max_len) {
+ MemNumType mid;
+
+ ID_ENTRY(env, mid);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = FALSE;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + OPSIZE_STEP_BACK_START + len + OPSIZE_POP_TO_MARK + OPSIZE_FAIL;
+
+ r = add_op(reg, OP_STEP_BACK_START);
+ if (r != 0) return r;
+ COP(reg)->step_back_start.initial = node->char_min_len;
+ COP(reg)->step_back_start.remaining = 0;
+ COP(reg)->step_back_start.addr = 1;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_POP_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->pop_to_mark.id = mid;
+ r = add_op(reg, OP_FAIL);
+ if (r != 0) return r;
+ r = add_op(reg, OP_POP);
+ }
+ else {
+ MemNumType mid1, mid2;
+ OnigLen diff;
+
+ ID_ENTRY(env, mid1);
+ r = add_op(reg, OP_SAVE_VAL);
+ if (r != 0) return r;
+ COP(reg)->save_val.type = SAVE_RIGHT_RANGE;
+ COP(reg)->save_val.id = mid1;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_TO_S;
+
+ ID_ENTRY(env, mid2);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid2;
+ COP(reg)->mark.save_pos = FALSE;
+
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + OPSIZE_STEP_BACK_START + OPSIZE_STEP_BACK_NEXT + len + OPSIZE_CHECK_POSITION + OPSIZE_POP_TO_MARK + OPSIZE_UPDATE_VAR + OPSIZE_POP + OPSIZE_FAIL;
+
+ if (IS_NOT_NULL(node->lead_node)) {
+ int clen;
+ MinMaxCharLen ci;
+
+ clen = compile_length_tree(node->lead_node, reg);
+ COP(reg)->push.addr += OPSIZE_MOVE + clen;
+
+ r = node_char_len(node->lead_node, reg, &ci, env);
+ if (r < 0) return r;
+ r = add_op(reg, OP_MOVE);
+ if (r != 0) return r;
+ COP(reg)->move.n = -((RelPositionType )ci.min);
+
+ r = compile_tree(node->lead_node, reg, env);
+ if (r != 0) return r;
+ }
+
+ r = add_op(reg, OP_STEP_BACK_START);
+ if (r != 0) return r;
+
+ if (node->char_max_len != INFINITE_LEN)
+ diff = node->char_max_len - node->char_min_len;
+ else
+ diff = INFINITE_LEN;
+
+ COP(reg)->step_back_start.initial = node->char_min_len;
+ COP(reg)->step_back_start.remaining = diff;
+ COP(reg)->step_back_start.addr = 2;
+
+ r = add_op(reg, OP_STEP_BACK_NEXT);
+ if (r != 0) return r;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_CHECK_POSITION);
+ if (r != 0) return r;
+ COP(reg)->check_position.type = CHECK_POSITION_CURRENT_RIGHT_RANGE;
+
+ r = add_op(reg, OP_POP_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->pop_to_mark.id = mid2;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_FROM_STACK;
+ COP(reg)->update_var.id = mid1;
+ COP(reg)->update_var.clear = FALSE;
+
+ r = add_op(reg, OP_POP); /* pop save val */
+ if (r != 0) return r;
+ r = add_op(reg, OP_FAIL);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = UPDATE_VAR_RIGHT_RANGE_FROM_STACK;
+ COP(reg)->update_var.id = mid1;
+ COP(reg)->update_var.clear = FALSE;
+
+ r = add_op(reg, OP_POP); /* pop mark */
+ if (r != 0) return r;
+ r = add_op(reg, OP_POP); /* pop save val */
+ }
+
+ return r;
+}
+
+static int
+compile_anchor_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
+{
+ int r, len;
+ enum OpCode op;
+ MemNumType mid;
+
+ switch (node->type) {
+ case ANCR_BEGIN_BUF: r = add_op(reg, OP_BEGIN_BUF); break;
+ case ANCR_END_BUF: r = add_op(reg, OP_END_BUF); break;
+ case ANCR_BEGIN_LINE: r = add_op(reg, OP_BEGIN_LINE); break;
+ case ANCR_END_LINE: r = add_op(reg, OP_END_LINE); break;
+ case ANCR_SEMI_END_BUF: r = add_op(reg, OP_SEMI_END_BUF); break;
+ case ANCR_BEGIN_POSITION:
+ r = add_op(reg, OP_CHECK_POSITION);
+ if (r != 0) return r;
+ COP(reg)->check_position.type = CHECK_POSITION_SEARCH_START;
+ break;
+
+ case ANCR_WORD_BOUNDARY:
+ op = OP_WORD_BOUNDARY;
+ word:
+ r = add_op(reg, op);
+ if (r != 0) return r;
+ COP(reg)->word_boundary.mode = (ModeType )node->ascii_mode;
+ break;
+
+ case ANCR_NO_WORD_BOUNDARY:
+ op = OP_NO_WORD_BOUNDARY; goto word;
+ break;
+#ifdef USE_WORD_BEGIN_END
+ case ANCR_WORD_BEGIN:
+ op = OP_WORD_BEGIN; goto word;
+ break;
+ case ANCR_WORD_END:
+ op = OP_WORD_END; goto word;
+ break;
+#endif
+
+ case ANCR_TEXT_SEGMENT_BOUNDARY:
+ case ANCR_NO_TEXT_SEGMENT_BOUNDARY:
+ {
+ enum TextSegmentBoundaryType type;
+
+ r = add_op(reg, OP_TEXT_SEGMENT_BOUNDARY);
+ if (r != 0) return r;
+
+ type = EXTENDED_GRAPHEME_CLUSTER_BOUNDARY;
+#ifdef USE_UNICODE_WORD_BREAK
+ if (NODE_IS_TEXT_SEGMENT_WORD(node))
+ type = WORD_BOUNDARY;
+#endif
+
+ COP(reg)->text_segment_boundary.type = type;
+ COP(reg)->text_segment_boundary.not =
+ (node->type == ANCR_NO_TEXT_SEGMENT_BOUNDARY ? 1 : 0);
+ }
+ break;
+
+ case ANCR_PREC_READ:
+ {
+ ID_ENTRY(env, mid);
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = TRUE;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_CUT_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->cut_to_mark.id = mid;
+ COP(reg)->cut_to_mark.restore_pos = TRUE;
+ }
+ break;
+
+ case ANCR_PREC_READ_NOT:
+ {
+ len = compile_length_tree(NODE_ANCHOR_BODY(node), reg);
+ if (len < 0) return len;
+
+ ID_ENTRY(env, mid);
+ r = add_op(reg, OP_PUSH);
+ if (r != 0) return r;
+ COP(reg)->push.addr = SIZE_INC + OPSIZE_MARK + len +
+ OPSIZE_POP_TO_MARK + OPSIZE_POP + OPSIZE_FAIL;
+
+ r = add_op(reg, OP_MARK);
+ if (r != 0) return r;
+ COP(reg)->mark.id = mid;
+ COP(reg)->mark.save_pos = FALSE;
+
+ r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
+ if (r != 0) return r;
+
+ r = add_op(reg, OP_POP_TO_MARK);
+ if (r != 0) return r;
+ COP(reg)->pop_to_mark.id = mid;
+
+ r = add_op(reg, OP_POP);
+ if (r != 0) return r;
+ r = add_op(reg, OP_FAIL);
+ }
+ break;
+
+ case ANCR_LOOK_BEHIND:
+ r = compile_anchor_look_behind_node(node, reg, env);
+ break;
+
+ case ANCR_LOOK_BEHIND_NOT:
+ r = compile_anchor_look_behind_not_node(node, reg, env);
+ break;
+
+ default:
+ return ONIGERR_TYPE_BUG;
+ break;
+ }
+
+ return r;
+}
+
+static int
+compile_gimmick_node(GimmickNode* node, regex_t* reg)
+{
+ int r = 0;
+
+ switch (node->type) {
+ case GIMMICK_FAIL:
+ r = add_op(reg, OP_FAIL);
+ break;
+
+ case GIMMICK_SAVE:
+ r = add_op(reg, OP_SAVE_VAL);
+ if (r != 0) return r;
+ COP(reg)->save_val.type = node->detail_type;
+ COP(reg)->save_val.id = node->id;
+ break;
+
+ case GIMMICK_UPDATE_VAR:
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) return r;
+ COP(reg)->update_var.type = node->detail_type;
+ COP(reg)->update_var.id = node->id;
+ COP(reg)->update_var.clear = FALSE;
+ break;
+
+#ifdef USE_CALLOUT
+ case GIMMICK_CALLOUT:
+ switch (node->detail_type) {
+ case ONIG_CALLOUT_OF_CONTENTS:
+ case ONIG_CALLOUT_OF_NAME:
+ {
+ if (node->detail_type == ONIG_CALLOUT_OF_NAME) {
+ r = add_op(reg, OP_CALLOUT_NAME);
+ if (r != 0) return r;
+ COP(reg)->callout_name.id = node->id;
+ COP(reg)->callout_name.num = node->num;
+ }
+ else {
+ r = add_op(reg, OP_CALLOUT_CONTENTS);
+ if (r != 0) return r;
+ COP(reg)->callout_contents.num = node->num;
+ }
+ }
+ break;
+
+ default:
+ r = ONIGERR_TYPE_BUG;
+ break;
+ }
+#endif
+ }
+
+ return r;
+}
+
+static int
+compile_length_gimmick_node(GimmickNode* node, regex_t* reg)
+{
+ int len;
+
+ switch (node->type) {
+ case GIMMICK_FAIL:
+ len = OPSIZE_FAIL;
+ break;
+
+ case GIMMICK_SAVE:
+ len = OPSIZE_SAVE_VAL;
+ break;
+
+ case GIMMICK_UPDATE_VAR:
+ len = OPSIZE_UPDATE_VAR;
+ break;
+
+#ifdef USE_CALLOUT
+ case GIMMICK_CALLOUT:
+ switch (node->detail_type) {
+ case ONIG_CALLOUT_OF_CONTENTS:
+ len = OPSIZE_CALLOUT_CONTENTS;
+ break;
+ case ONIG_CALLOUT_OF_NAME:
+ len = OPSIZE_CALLOUT_NAME;
+ break;
+
+ default:
+ len = ONIGERR_TYPE_BUG;
+ break;
+ }
+ break;
+#endif
+ }
+
+ return len;
+}
+
+static int
+compile_length_tree(Node* node, regex_t* reg)
+{
+ int len, r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ len = 0;
+ do {
+ r = compile_length_tree(NODE_CAR(node), reg);
+ if (r < 0) return r;
+ len += r;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ r = len;
+ break;
+
+ case NODE_ALT:
+ {
+ int n;
+
+ n = r = 0;
+ do {
+ r += compile_length_tree(NODE_CAR(node), reg);
+ n++;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ r += (OPSIZE_PUSH + OPSIZE_JUMP) * (n - 1);
+ }
+ break;
+
+ case NODE_STRING:
+ if (NODE_STRING_IS_CRUDE(node))
+ r = compile_length_string_crude_node(STR_(node), reg);
+ else
+ r = compile_length_string_node(node, reg);
+ break;
+
+ case NODE_CCLASS:
+ r = compile_length_cclass_node(CCLASS_(node), reg);
+ break;
+
+ case NODE_CTYPE:
+ r = SIZE_OPCODE;
+ break;
+
+ case NODE_BACKREF:
+ r = OPSIZE_BACKREF;
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ r = OPSIZE_CALL;
+ break;
+#endif
+
+ case NODE_QUANT:
+ r = compile_length_quantifier_node(QUANT_(node), reg);
+ break;
+
+ case NODE_BAG:
+ r = compile_length_bag_node(BAG_(node), reg);
+ break;
+
+ case NODE_ANCHOR:
+ r = compile_length_anchor_node(ANCHOR_(node), reg);
+ break;
+
+ case NODE_GIMMICK:
+ r = compile_length_gimmick_node(GIMMICK_(node), reg);
+ break;
+
+ default:
+ return ONIGERR_TYPE_BUG;
+ break;
+ }
+
+ return r;
+}
+
+static int
+compile_tree(Node* node, regex_t* reg, ScanEnv* env)
+{
+ int n, len, pos, r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ do {
+ r = compile_tree(NODE_CAR(node), reg, env);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ALT:
+ {
+ Node* x = node;
+ len = 0;
+ do {
+ len += compile_length_tree(NODE_CAR(x), reg);
+ if (IS_NOT_NULL(NODE_CDR(x))) {
+ len += OPSIZE_PUSH + OPSIZE_JUMP;
+ }
+ } while (IS_NOT_NULL(x = NODE_CDR(x)));
+ pos = COP_CURR_OFFSET(reg) + 1 + len; /* goal position */
+
+ do {
+ len = compile_length_tree(NODE_CAR(node), reg);
+ if (IS_NOT_NULL(NODE_CDR(node))) {
+ enum OpCode push = NODE_IS_SUPER(node) ? OP_PUSH_SUPER : OP_PUSH;
+ r = add_op(reg, push);
+ if (r != 0) break;
+ COP(reg)->push.addr = SIZE_INC + len + OPSIZE_JUMP;
+ }
+ r = compile_tree(NODE_CAR(node), reg, env);
+ if (r != 0) break;
+ if (IS_NOT_NULL(NODE_CDR(node))) {
+ len = pos - (COP_CURR_OFFSET(reg) + 1);
+ r = add_op(reg, OP_JUMP);
+ if (r != 0) break;
+ COP(reg)->jump.addr = len;
+ }
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ }
+ break;
+
+ case NODE_STRING:
+ if (NODE_STRING_IS_CRUDE(node))
+ r = compile_string_crude_node(STR_(node), reg);
+ else
+ r = compile_string_node(node, reg);
+ break;
+
+ case NODE_CCLASS:
+ r = compile_cclass_node(CCLASS_(node), reg);
+ break;
+
+ case NODE_CTYPE:
+ {
+ int op;
+
+ switch (CTYPE_(node)->ctype) {
+ case CTYPE_ANYCHAR:
+ r = add_op(reg, NODE_IS_MULTILINE(node) ? OP_ANYCHAR_ML : OP_ANYCHAR);
+ break;
+
+ case ONIGENC_CTYPE_WORD:
+ if (CTYPE_(node)->ascii_mode == 0) {
+ op = CTYPE_(node)->not != 0 ? OP_NO_WORD : OP_WORD;
+ }
+ else {
+ op = CTYPE_(node)->not != 0 ? OP_NO_WORD_ASCII : OP_WORD_ASCII;
+ }
+ r = add_op(reg, op);
+ break;
+
+ default:
+ return ONIGERR_TYPE_BUG;
+ break;
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ {
+ BackRefNode* br = BACKREF_(node);
+
+ if (NODE_IS_CHECKER(node)) {
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (NODE_IS_NEST_LEVEL(node)) {
+ r = add_op(reg, OP_BACKREF_CHECK_WITH_LEVEL);
+ if (r != 0) return r;
+ COP(reg)->backref_general.nest_level = br->nest_level;
+ }
+ else
+#endif
+ {
+ r = add_op(reg, OP_BACKREF_CHECK);
+ if (r != 0) return r;
+ }
+ goto add_bacref_mems;
+ }
+ else {
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (NODE_IS_NEST_LEVEL(node)) {
+ if (NODE_IS_IGNORECASE(node))
+ r = add_op(reg, OP_BACKREF_WITH_LEVEL_IC);
+ else
+ r = add_op(reg, OP_BACKREF_WITH_LEVEL);
+
+ if (r != 0) return r;
+ COP(reg)->backref_general.nest_level = br->nest_level;
+ goto add_bacref_mems;
+ }
+ else
+#endif
+ if (br->back_num == 1) {
+ n = br->back_static[0];
+ if (NODE_IS_IGNORECASE(node)) {
+ r = add_op(reg, OP_BACKREF_N_IC);
+ if (r != 0) return r;
+ COP(reg)->backref_n.n1 = n;
+ }
+ else {
+ switch (n) {
+ case 1: r = add_op(reg, OP_BACKREF1); break;
+ case 2: r = add_op(reg, OP_BACKREF2); break;
+ default:
+ r = add_op(reg, OP_BACKREF_N);
+ if (r != 0) return r;
+ COP(reg)->backref_n.n1 = n;
+ break;
+ }
+ }
+ }
+ else {
+ int num;
+ int* p;
+
+ r = add_op(reg, NODE_IS_IGNORECASE(node) ?
+ OP_BACKREF_MULTI_IC : OP_BACKREF_MULTI);
+ if (r != 0) return r;
+
+ add_bacref_mems:
+ num = br->back_num;
+ COP(reg)->backref_general.num = num;
+ if (num == 1) {
+ COP(reg)->backref_general.n1 = br->back_static[0];
+ }
+ else {
+ int i, j;
+ MemNumType* ns;
+
+ ns = xmalloc(sizeof(MemNumType) * num);
+ CHECK_NULL_RETURN_MEMERR(ns);
+ COP(reg)->backref_general.ns = ns;
+ p = BACKREFS_P(br);
+ for (i = num - 1, j = 0; i >= 0; i--, j++) {
+ ns[j] = p[i];
+ }
+ }
+ }
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ r = compile_call(CALL_(node), reg, env);
+ break;
+#endif
+
+ case NODE_QUANT:
+ r = compile_quantifier_node(QUANT_(node), reg, env);
+ break;
+
+ case NODE_BAG:
+ r = compile_bag_node(BAG_(node), reg, env);
+ break;
+
+ case NODE_ANCHOR:
+ r = compile_anchor_node(ANCHOR_(node), reg, env);
+ break;
+
+ case NODE_GIMMICK:
+ r = compile_gimmick_node(GIMMICK_(node), reg);
+ break;
+
+ default:
+#ifdef ONIG_DEBUG
+ fprintf(DBGFP, "compile_tree: undefined node type %d\n", NODE_TYPE(node));
+#endif
+ break;
+ }
+
+ return r;
+}
+
+static int
+make_named_capture_number_map(Node** plink, GroupNumMap* map, int* counter)
+{
+ int r = 0;
+ Node* node = *plink;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = make_named_capture_number_map(&(NODE_CAR(node)), map, counter);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ {
+ Node** ptarget = &(NODE_BODY(node));
+ Node* old = *ptarget;
+ r = make_named_capture_number_map(ptarget, map, counter);
+ if (r != 0) return r;
+ if (*ptarget != old && NODE_TYPE(*ptarget) == NODE_QUANT) {
+ r = onig_reduce_nested_quantifier(node);
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_NAMED_GROUP(node)) {
+ (*counter)++;
+ map[en->m.regnum].new_val = *counter;
+ en->m.regnum = *counter;
+ r = make_named_capture_number_map(&(NODE_BODY(node)), map, counter);
+ }
+ else {
+ *plink = NODE_BODY(node);
+ NODE_BODY(node) = NULL_NODE;
+ onig_node_free(node);
+ r = make_named_capture_number_map(plink, map, counter);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ r = make_named_capture_number_map(&(NODE_BAG_BODY(en)), map, counter);
+ if (r != 0) return r;
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = make_named_capture_number_map(&(en->te.Then), map, counter);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = make_named_capture_number_map(&(en->te.Else), map, counter);
+ if (r != 0) return r;
+ }
+ }
+ else
+ r = make_named_capture_number_map(&(NODE_BODY(node)), map, counter);
+ }
+ break;
+
+ case NODE_ANCHOR:
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ r = make_named_capture_number_map(&(NODE_BODY(node)), map, counter);
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+static int
+renumber_backref_node(Node* node, GroupNumMap* map)
+{
+ int i, pos, n, old_num;
+ int *backs;
+ BackRefNode* bn = BACKREF_(node);
+
+ if (! NODE_IS_BY_NAME(node))
+ return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
+
+ old_num = bn->back_num;
+ if (IS_NULL(bn->back_dynamic))
+ backs = bn->back_static;
+ else
+ backs = bn->back_dynamic;
+
+ for (i = 0, pos = 0; i < old_num; i++) {
+ n = map[backs[i]].new_val;
+ if (n > 0) {
+ backs[pos] = n;
+ pos++;
+ }
+ }
+
+ bn->back_num = pos;
+ return 0;
+}
+
+static int
+renumber_backref_traverse(Node* node, GroupNumMap* map)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = renumber_backref_traverse(NODE_CAR(node), map);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ r = renumber_backref_traverse(NODE_BODY(node), map);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ r = renumber_backref_traverse(NODE_BODY(node), map);
+ if (r != 0) return r;
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = renumber_backref_traverse(en->te.Then, map);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = renumber_backref_traverse(en->te.Else, map);
+ if (r != 0) return r;
+ }
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ r = renumber_backref_node(node, map);
+ break;
+
+ case NODE_ANCHOR:
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ r = renumber_backref_traverse(NODE_BODY(node), map);
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+static int
+numbered_ref_check(Node* node)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = numbered_ref_check(NODE_CAR(node));
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (IS_NULL(NODE_BODY(node)))
+ break;
+ /* fall */
+ case NODE_QUANT:
+ r = numbered_ref_check(NODE_BODY(node));
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ r = numbered_ref_check(NODE_BODY(node));
+ if (r != 0) return r;
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = numbered_ref_check(en->te.Then);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = numbered_ref_check(en->te.Else);
+ if (r != 0) return r;
+ }
+ }
+ }
+
+ break;
+
+ case NODE_BACKREF:
+ if (! NODE_IS_BY_NAME(node))
+ return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+static int
+disable_noname_group_capture(Node** root, regex_t* reg, ScanEnv* env)
+{
+ int r, i, pos, counter;
+ MemStatusType loc;
+ GroupNumMap* map;
+
+ map = (GroupNumMap* )xalloca(sizeof(GroupNumMap) * (env->num_mem + 1));
+ CHECK_NULL_RETURN_MEMERR(map);
+ for (i = 1; i <= env->num_mem; i++) {
+ map[i].new_val = 0;
+ }
+ counter = 0;
+ r = make_named_capture_number_map(root, map, &counter);
+ if (r != 0) return r;
+
+ r = renumber_backref_traverse(*root, map);
+ if (r != 0) return r;
+
+ for (i = 1, pos = 1; i <= env->num_mem; i++) {
+ if (map[i].new_val > 0) {
+ SCANENV_MEMENV(env)[pos] = SCANENV_MEMENV(env)[i];
+ pos++;
+ }
+ }
+
+ loc = env->cap_history;
+ MEM_STATUS_CLEAR(env->cap_history);
+ for (i = 1; i <= ONIG_MAX_CAPTURE_HISTORY_GROUP; i++) {
+ if (MEM_STATUS_AT(loc, i)) {
+ MEM_STATUS_ON_SIMPLE(env->cap_history, map[i].new_val);
+ }
+ }
+
+ env->num_mem = env->num_named;
+ reg->num_mem = env->num_named;
+
+ return onig_renumber_name_table(reg, map);
+}
+
+#ifdef USE_CALL
+static int
+fix_unset_addr_list(UnsetAddrList* uslist, regex_t* reg)
+{
+ int i, offset;
+ BagNode* en;
+ AbsAddrType addr;
+ AbsAddrType* paddr;
+
+ for (i = 0; i < uslist->num; i++) {
+ if (! NODE_IS_FIXED_ADDR(uslist->us[i].target)) {
+ if (NODE_IS_CALLED(uslist->us[i].target))
+ return ONIGERR_PARSER_BUG;
+ else {
+ /* CASE: called node doesn't have called address.
+ ex. /((|a\g<1>)(.){0}){0}\g<3>/
+ group-1 doesn't called, but compiled into bytecodes,
+ because group-3 is referred from outside.
+ */
+ continue;
+ }
+ }
+
+ en = BAG_(uslist->us[i].target);
+ addr = en->m.called_addr;
+ offset = uslist->us[i].offset;
+
+ paddr = (AbsAddrType* )((char* )reg->ops + offset);
+ *paddr = addr;
+ }
+ return 0;
+}
+#endif
+
+/* x is not included y ==> 1 : 0 */
+static int
+is_exclusive(Node* x, Node* y, regex_t* reg)
+{
+ int i, len;
+ OnigCodePoint code;
+ UChar *p;
+ NodeType ytype;
+
+ retry:
+ ytype = NODE_TYPE(y);
+ switch (NODE_TYPE(x)) {
+ case NODE_CTYPE:
+ {
+ if (CTYPE_(x)->ctype == CTYPE_ANYCHAR ||
+ CTYPE_(y)->ctype == CTYPE_ANYCHAR)
+ break;
+
+ switch (ytype) {
+ case NODE_CTYPE:
+ if (CTYPE_(y)->ctype == CTYPE_(x)->ctype &&
+ CTYPE_(y)->not != CTYPE_(x)->not &&
+ CTYPE_(y)->ascii_mode == CTYPE_(x)->ascii_mode)
+ return 1;
+ else
+ return 0;
+ break;
+
+ case NODE_CCLASS:
+ swap:
+ {
+ Node* tmp;
+ tmp = x; x = y; y = tmp;
+ goto retry;
+ }
+ break;
+
+ case NODE_STRING:
+ goto swap;
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ int range;
+ CClassNode* xc = CCLASS_(x);
+
+ switch (ytype) {
+ case NODE_CTYPE:
+ switch (CTYPE_(y)->ctype) {
+ case CTYPE_ANYCHAR:
+ return 0;
+ break;
+
+ case ONIGENC_CTYPE_WORD:
+ if (CTYPE_(y)->not == 0) {
+ if (IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) {
+ range = CTYPE_(y)->ascii_mode != 0 ? 128 : SINGLE_BYTE_SIZE;
+ for (i = 0; i < range; i++) {
+ if (BITSET_AT(xc->bs, i)) {
+ if (ONIGENC_IS_CODE_WORD(reg->enc, i)) return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+ }
+ else {
+ if (IS_NOT_NULL(xc->mbuf)) return 0;
+ if (IS_NCCLASS_NOT(xc)) return 0;
+
+ range = CTYPE_(y)->ascii_mode != 0 ? 128 : SINGLE_BYTE_SIZE;
+ for (i = 0; i < range; i++) {
+ if (! ONIGENC_IS_CODE_WORD(reg->enc, i)) {
+ if (BITSET_AT(xc->bs, i))
+ return 0;
+ }
+ }
+ for (i = range; i < SINGLE_BYTE_SIZE; i++) {
+ if (BITSET_AT(xc->bs, i)) return 0;
+ }
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ int v;
+ CClassNode* yc = CCLASS_(y);
+
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ v = BITSET_AT(xc->bs, i);
+ if ((v != 0 && !IS_NCCLASS_NOT(xc)) || (v == 0 && IS_NCCLASS_NOT(xc))) {
+ v = BITSET_AT(yc->bs, i);
+ if ((v != 0 && !IS_NCCLASS_NOT(yc)) ||
+ (v == 0 && IS_NCCLASS_NOT(yc)))
+ return 0;
+ }
+ }
+ if ((IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) ||
+ (IS_NULL(yc->mbuf) && !IS_NCCLASS_NOT(yc)))
+ return 1;
+ return 0;
+ }
+ break;
+
+ case NODE_STRING:
+ goto swap;
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* xs = STR_(x);
+
+ if (NODE_STRING_LEN(x) == 0)
+ break;
+
+ switch (ytype) {
+ case NODE_CTYPE:
+ switch (CTYPE_(y)->ctype) {
+ case CTYPE_ANYCHAR:
+ break;
+
+ case ONIGENC_CTYPE_WORD:
+ if (CTYPE_(y)->ascii_mode == 0) {
+ if (ONIGENC_IS_MBC_WORD(reg->enc, xs->s, xs->end))
+ return CTYPE_(y)->not;
+ else
+ return !(CTYPE_(y)->not);
+ }
+ else {
+ if (ONIGENC_IS_MBC_WORD_ASCII(reg->enc, xs->s, xs->end))
+ return CTYPE_(y)->not;
+ else
+ return !(CTYPE_(y)->not);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ CClassNode* cc = CCLASS_(y);
+
+ code = ONIGENC_MBC_TO_CODE(reg->enc, xs->s,
+ xs->s + ONIGENC_MBC_MAXLEN(reg->enc));
+ return onig_is_code_in_cc(reg->enc, code, cc) == 0;
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ UChar *q;
+ StrNode* ys = STR_(y);
+
+ len = NODE_STRING_LEN(x);
+ if (len > NODE_STRING_LEN(y)) len = NODE_STRING_LEN(y);
+
+ for (i = 0, p = ys->s, q = xs->s; i < len; i++, p++, q++) {
+ if (*p != *q) return 1;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static Node*
+get_tree_head_literal(Node* node, int exact, regex_t* reg)
+{
+ Node* n = NULL_NODE;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_BACKREF:
+ case NODE_ALT:
+#ifdef USE_CALL
+ case NODE_CALL:
+#endif
+ break;
+
+ case NODE_CTYPE:
+ if (CTYPE_(node)->ctype == CTYPE_ANYCHAR)
+ break;
+ /* fall */
+ case NODE_CCLASS:
+ if (exact == 0) {
+ n = node;
+ }
+ break;
+
+ case NODE_LIST:
+ n = get_tree_head_literal(NODE_CAR(node), exact, reg);
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+
+ if (sn->end <= sn->s)
+ break;
+
+ if (exact == 0 ||
+ ! NODE_IS_IGNORECASE(node) || NODE_STRING_IS_CRUDE(node)) {
+ n = node;
+ }
+ }
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+ if (qn->lower > 0) {
+ if (IS_NOT_NULL(qn->head_exact))
+ n = qn->head_exact;
+ else
+ n = get_tree_head_literal(NODE_BODY(node), exact, reg);
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ switch (en->type) {
+ case BAG_OPTION:
+ case BAG_MEMORY:
+ case BAG_STOP_BACKTRACK:
+ case BAG_IF_ELSE:
+ n = get_tree_head_literal(NODE_BODY(node), exact, reg);
+ break;
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ if (ANCHOR_(node)->type == ANCR_PREC_READ)
+ n = get_tree_head_literal(NODE_BODY(node), exact, reg);
+ break;
+
+ case NODE_GIMMICK:
+ default:
+ break;
+ }
+
+ return n;
+}
+
+enum GetValue {
+ GET_VALUE_NONE = -1,
+ GET_VALUE_IGNORE = 0,
+ GET_VALUE_FOUND = 1
+};
+
+static int
+get_tree_tail_literal(Node* node, Node** rnode, regex_t* reg)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ if (IS_NULL(NODE_CDR(node))) {
+ r = get_tree_tail_literal(NODE_CAR(node), rnode, reg);
+ }
+ else {
+ r = get_tree_tail_literal(NODE_CDR(node), rnode, reg);
+ if (r == GET_VALUE_IGNORE) {
+ r = get_tree_tail_literal(NODE_CAR(node), rnode, reg);
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ r = get_tree_tail_literal(NODE_BODY(node), rnode, reg);
+ break;
+#endif
+
+ case NODE_CTYPE:
+ if (CTYPE_(node)->ctype == CTYPE_ANYCHAR) {
+ r = GET_VALUE_NONE;
+ break;
+ }
+ /* fall */
+ case NODE_CCLASS:
+ *rnode = node;
+ r = GET_VALUE_FOUND;
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+
+ if (sn->end <= sn->s) {
+ r = GET_VALUE_IGNORE;
+ break;
+ }
+
+ if (NODE_IS_IGNORECASE(node) && ! NODE_STRING_IS_CRUDE(node)) {
+ r = GET_VALUE_NONE;
+ break;
+ }
+
+ *rnode = node;
+ r = GET_VALUE_FOUND;
+ }
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+ if (qn->lower != 0) {
+ r = get_tree_tail_literal(NODE_BODY(node), rnode, reg);
+ }
+ else
+ r = GET_VALUE_NONE;
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_MARK1(node))
+ r = GET_VALUE_NONE;
+ else {
+ NODE_STATUS_ADD(node, MARK1);
+ r = get_tree_tail_literal(NODE_BODY(node), rnode, reg);
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ }
+ else {
+ r = get_tree_tail_literal(NODE_BODY(node), rnode, reg);
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ case NODE_GIMMICK:
+ r = GET_VALUE_IGNORE;
+ break;
+
+ case NODE_ALT:
+ case NODE_BACKREF:
+ default:
+ r = GET_VALUE_NONE;
+ break;
+ }
+
+ return r;
+}
+
+static int
+check_called_node_in_look_behind(Node* node, int not)
+{
+ int r;
+
+ r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = check_called_node_in_look_behind(NODE_CAR(node), not);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ r = check_called_node_in_look_behind(NODE_BODY(node), not);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_MARK1(node))
+ return 0;
+ else {
+ NODE_STATUS_ADD(node, MARK1);
+ r = check_called_node_in_look_behind(NODE_BODY(node), not);
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ }
+ else {
+ r = check_called_node_in_look_behind(NODE_BODY(node), not);
+ if (r == 0 && en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = check_called_node_in_look_behind(en->te.Then, not);
+ if (r != 0) break;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = check_called_node_in_look_behind(en->te.Else, not);
+ }
+ }
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ r = check_called_node_in_look_behind(NODE_BODY(node), not);
+ break;
+
+ case NODE_GIMMICK:
+ if (NODE_IS_ABSENT_WITH_SIDE_EFFECTS(node) != 0)
+ return 1;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+/* allowed node types in look-behind */
+#define ALLOWED_TYPE_IN_LB \
+ ( NODE_BIT_LIST | NODE_BIT_ALT | NODE_BIT_STRING | NODE_BIT_CCLASS \
+ | NODE_BIT_CTYPE | NODE_BIT_ANCHOR | NODE_BIT_BAG | NODE_BIT_QUANT \
+ | NODE_BIT_CALL | NODE_BIT_BACKREF | NODE_BIT_GIMMICK)
+
+#define ALLOWED_BAG_IN_LB ( 1<<BAG_MEMORY | 1<<BAG_OPTION | 1<<BAG_STOP_BACKTRACK | 1<<BAG_IF_ELSE )
+#define ALLOWED_BAG_IN_LB_NOT ( 1<<BAG_OPTION | 1<<BAG_STOP_BACKTRACK | 1<<BAG_IF_ELSE )
+
+#define ALLOWED_ANCHOR_IN_LB \
+ ( ANCR_LOOK_BEHIND | ANCR_BEGIN_LINE | ANCR_END_LINE | ANCR_BEGIN_BUF \
+ | ANCR_BEGIN_POSITION | ANCR_WORD_BOUNDARY | ANCR_NO_WORD_BOUNDARY \
+ | ANCR_WORD_BEGIN | ANCR_WORD_END \
+ | ANCR_TEXT_SEGMENT_BOUNDARY | ANCR_NO_TEXT_SEGMENT_BOUNDARY )
+
+#define ALLOWED_ANCHOR_IN_LB_NOT \
+ ( ANCR_LOOK_BEHIND | ANCR_LOOK_BEHIND_NOT | ANCR_BEGIN_LINE \
+ | ANCR_END_LINE | ANCR_BEGIN_BUF | ANCR_BEGIN_POSITION | ANCR_WORD_BOUNDARY \
+ | ANCR_NO_WORD_BOUNDARY | ANCR_WORD_BEGIN | ANCR_WORD_END \
+ | ANCR_TEXT_SEGMENT_BOUNDARY | ANCR_NO_TEXT_SEGMENT_BOUNDARY )
+
+
+static int
+check_node_in_look_behind(Node* node, int not, int* used)
+{
+ static unsigned int
+ bag_mask[2] = { ALLOWED_BAG_IN_LB, ALLOWED_BAG_IN_LB_NOT };
+
+ static unsigned int
+ anchor_mask[2] = { ALLOWED_ANCHOR_IN_LB, ALLOWED_ANCHOR_IN_LB_NOT };
+
+ NodeType type;
+ int r = 0;
+
+ type = NODE_TYPE(node);
+ if ((NODE_TYPE2BIT(type) & ALLOWED_TYPE_IN_LB) == 0)
+ return 1;
+
+ switch (type) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = check_node_in_look_behind(NODE_CAR(node), not, used);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ r = check_node_in_look_behind(NODE_BODY(node), not, used);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ if (((1<<en->type) & bag_mask[not]) == 0)
+ return 1;
+
+ r = check_node_in_look_behind(NODE_BODY(node), not, used);
+ if (r != 0) break;
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_BACKREF(node) || NODE_IS_CALLED(node)) *used = TRUE;
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = check_node_in_look_behind(en->te.Then, not, used);
+ if (r != 0) break;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = check_node_in_look_behind(en->te.Else, not, used);
+ }
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ type = ANCHOR_(node)->type;
+ if ((type & anchor_mask[not]) == 0)
+ return 1;
+
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ r = check_node_in_look_behind(NODE_BODY(node), not, used);
+ break;
+
+ case NODE_GIMMICK:
+ if (NODE_IS_ABSENT_WITH_SIDE_EFFECTS(node) != 0)
+ return 1;
+ break;
+
+ case NODE_CALL:
+ r = check_called_node_in_look_behind(NODE_BODY(node), not);
+ break;
+
+ default:
+ break;
+ }
+ return r;
+}
+
+static OnigLen
+node_min_byte_len(Node* node, ScanEnv* env)
+{
+ OnigLen len;
+ OnigLen tmin;
+
+ len = 0;
+ switch (NODE_TYPE(node)) {
+ case NODE_BACKREF:
+ if (! NODE_IS_CHECKER(node)) {
+ int i;
+ int* backs;
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+ BackRefNode* br = BACKREF_(node);
+ if (NODE_IS_RECURSION(node)) break;
+
+ backs = BACKREFS_P(br);
+ len = node_min_byte_len(mem_env[backs[0]].mem_node, env);
+ for (i = 1; i < br->back_num; i++) {
+ tmin = node_min_byte_len(mem_env[backs[i]].mem_node, env);
+ if (len > tmin) len = tmin;
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ {
+ Node* t = NODE_BODY(node);
+ if (NODE_IS_RECURSION(node)) {
+ if (NODE_IS_FIXED_MIN(t))
+ len = BAG_(t)->min_len;
+ }
+ else
+ len = node_min_byte_len(t, env);
+ }
+ break;
+#endif
+
+ case NODE_LIST:
+ do {
+ tmin = node_min_byte_len(NODE_CAR(node), env);
+ len = distance_add(len, tmin);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ALT:
+ {
+ Node *x, *y;
+ y = node;
+ do {
+ x = NODE_CAR(y);
+ tmin = node_min_byte_len(x, env);
+ if (y == node) len = tmin;
+ else if (len > tmin) len = tmin;
+ } while (IS_NOT_NULL(y = NODE_CDR(y)));
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+ len = (int )(sn->end - sn->s);
+ }
+ break;
+
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ len = ONIGENC_MBC_MINLEN(env->enc);
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (qn->lower > 0) {
+ len = node_min_byte_len(NODE_BODY(node), env);
+ len = distance_multiply(len, qn->lower);
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ switch (en->type) {
+ case BAG_MEMORY:
+ if (NODE_IS_FIXED_MIN(node))
+ len = en->min_len;
+ else {
+ if (NODE_IS_MARK1(node))
+ len = 0; /* recursive */
+ else {
+ NODE_STATUS_ADD(node, MARK1);
+ len = node_min_byte_len(NODE_BODY(node), env);
+ NODE_STATUS_REMOVE(node, MARK1);
+
+ en->min_len = len;
+ NODE_STATUS_ADD(node, FIXED_MIN);
+ }
+ }
+ break;
+
+ case BAG_OPTION:
+ case BAG_STOP_BACKTRACK:
+ len = node_min_byte_len(NODE_BODY(node), env);
+ break;
+ case BAG_IF_ELSE:
+ {
+ OnigLen elen;
+
+ len = node_min_byte_len(NODE_BODY(node), env);
+ if (IS_NOT_NULL(en->te.Then))
+ len += node_min_byte_len(en->te.Then, env);
+ if (IS_NOT_NULL(en->te.Else))
+ elen = node_min_byte_len(en->te.Else, env);
+ else elen = 0;
+
+ if (elen < len) len = elen;
+ }
+ break;
+ }
+ }
+ break;
+
+ case NODE_GIMMICK:
+ {
+ GimmickNode* g = GIMMICK_(node);
+ if (g->type == GIMMICK_FAIL) {
+ len = INFINITE_LEN;
+ break;
+ }
+ }
+ /* fall */
+ case NODE_ANCHOR:
+ default:
+ break;
+ }
+
+ return len;
+}
+
+static OnigLen
+node_max_byte_len(Node* node, ScanEnv* env)
+{
+ OnigLen len;
+ OnigLen tmax;
+
+ len = 0;
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ do {
+ tmax = node_max_byte_len(NODE_CAR(node), env);
+ len = distance_add(len, tmax);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ALT:
+ do {
+ tmax = node_max_byte_len(NODE_CAR(node), env);
+ if (len < tmax) len = tmax;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+ len = (OnigLen )(sn->end - sn->s);
+ }
+ break;
+
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ len = ONIGENC_MBC_MAXLEN_DIST(env->enc);
+ break;
+
+ case NODE_BACKREF:
+ if (! NODE_IS_CHECKER(node)) {
+ int i;
+ int* backs;
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+ BackRefNode* br = BACKREF_(node);
+ if (NODE_IS_RECURSION(node)) {
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (NODE_IS_NEST_LEVEL(node)) {
+ len = INFINITE_LEN;
+ }
+#endif
+ break;
+ }
+ backs = BACKREFS_P(br);
+ for (i = 0; i < br->back_num; i++) {
+ tmax = node_max_byte_len(mem_env[backs[i]].mem_node, env);
+ if (len < tmax) len = tmax;
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ if (! NODE_IS_RECURSION(node))
+ len = node_max_byte_len(NODE_BODY(node), env);
+ else
+ len = INFINITE_LEN;
+ break;
+#endif
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (qn->upper != 0) {
+ len = node_max_byte_len(NODE_BODY(node), env);
+ if (len != 0) {
+ if (! IS_INFINITE_REPEAT(qn->upper))
+ len = distance_multiply(len, qn->upper);
+ else
+ len = INFINITE_LEN;
+ }
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ switch (en->type) {
+ case BAG_MEMORY:
+ if (NODE_IS_FIXED_MAX(node))
+ len = en->max_len;
+ else {
+ if (NODE_IS_MARK1(node))
+ len = INFINITE_LEN;
+ else {
+ NODE_STATUS_ADD(node, MARK1);
+ len = node_max_byte_len(NODE_BODY(node), env);
+ NODE_STATUS_REMOVE(node, MARK1);
+
+ en->max_len = len;
+ NODE_STATUS_ADD(node, FIXED_MAX);
+ }
+ }
+ break;
+
+ case BAG_OPTION:
+ case BAG_STOP_BACKTRACK:
+ len = node_max_byte_len(NODE_BODY(node), env);
+ break;
+ case BAG_IF_ELSE:
+ {
+ OnigLen tlen, elen;
+
+ len = node_max_byte_len(NODE_BODY(node), env);
+ if (IS_NOT_NULL(en->te.Then)) {
+ tlen = node_max_byte_len(en->te.Then, env);
+ len = distance_add(len, tlen);
+ }
+ if (IS_NOT_NULL(en->te.Else))
+ elen = node_max_byte_len(en->te.Else, env);
+ else elen = 0;
+
+ if (elen > len) len = elen;
+ }
+ break;
+ }
+ }
+ break;
+
+ case NODE_ANCHOR:
+ case NODE_GIMMICK:
+ default:
+ break;
+ }
+
+ return len;
+}
+
+static int
+check_backrefs(Node* node, ScanEnv* env)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = check_backrefs(NODE_CAR(node), env);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (! ANCHOR_HAS_BODY(ANCHOR_(node))) {
+ r = 0;
+ break;
+ }
+ /* fall */
+ case NODE_QUANT:
+ r = check_backrefs(NODE_BODY(node), env);
+ break;
+
+ case NODE_BAG:
+ r = check_backrefs(NODE_BODY(node), env);
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_IF_ELSE) {
+ if (r != 0) return r;
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = check_backrefs(en->te.Then, env);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = check_backrefs(en->te.Else, env);
+ }
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ {
+ int i;
+ BackRefNode* br = BACKREF_(node);
+ int* backs = BACKREFS_P(br);
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+
+ for (i = 0; i < br->back_num; i++) {
+ if (backs[i] > env->num_mem)
+ return ONIGERR_INVALID_BACKREF;
+
+ NODE_STATUS_ADD(mem_env[backs[i]].mem_node, BACKREF);
+ }
+ r = 0;
+ }
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+static int
+set_empty_repeat_node_trav(Node* node, Node* empty, ScanEnv* env)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = set_empty_repeat_node_trav(NODE_CAR(node), empty, env);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ {
+ AnchorNode* an = ANCHOR_(node);
+
+ if (! ANCHOR_HAS_BODY(an)) {
+ r = 0;
+ break;
+ }
+
+ switch (an->type) {
+ case ANCR_PREC_READ:
+ case ANCR_LOOK_BEHIND:
+ empty = NULL_NODE;
+ break;
+ default:
+ break;
+ }
+ r = set_empty_repeat_node_trav(NODE_BODY(node), empty, env);
+ }
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (qn->emptiness != BODY_IS_NOT_EMPTY) empty = node;
+ r = set_empty_repeat_node_trav(NODE_BODY(node), empty, env);
+ }
+ break;
+
+ case NODE_BAG:
+ if (IS_NOT_NULL(NODE_BODY(node))) {
+ r = set_empty_repeat_node_trav(NODE_BODY(node), empty, env);
+ if (r != 0) return r;
+ }
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_BACKREF(node)) {
+ if (IS_NOT_NULL(empty))
+ SCANENV_MEMENV(env)[en->m.regnum].empty_repeat_node = empty;
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = set_empty_repeat_node_trav(en->te.Then, empty, env);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = set_empty_repeat_node_trav(en->te.Else, empty, env);
+ }
+ }
+ }
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+static int
+is_ancestor_node(Node* node, Node* me)
+{
+ Node* parent;
+
+ while ((parent = NODE_PARENT(me)) != NULL_NODE) {
+ if (parent == node) return 1;
+ me = parent;
+ }
+ return 0;
+}
+
+static void
+set_empty_status_check_trav(Node* node, ScanEnv* env)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ set_empty_status_check_trav(NODE_CAR(node), env);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ {
+ AnchorNode* an = ANCHOR_(node);
+
+ if (! ANCHOR_HAS_BODY(an)) break;
+ set_empty_status_check_trav(NODE_BODY(node), env);
+ }
+ break;
+
+ case NODE_QUANT:
+ set_empty_status_check_trav(NODE_BODY(node), env);
+ break;
+
+ case NODE_BAG:
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ set_empty_status_check_trav(NODE_BODY(node), env);
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ set_empty_status_check_trav(en->te.Then, env);
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ set_empty_status_check_trav(en->te.Else, env);
+ }
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ {
+ int i;
+ int* backs;
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+ BackRefNode* br = BACKREF_(node);
+ backs = BACKREFS_P(br);
+ for (i = 0; i < br->back_num; i++) {
+ Node* ernode = mem_env[backs[i]].empty_repeat_node;
+ if (IS_NOT_NULL(ernode)) {
+ if (! is_ancestor_node(ernode, node)) {
+ MEM_STATUS_LIMIT_ON(env->reg->empty_status_mem, backs[i]);
+ NODE_STATUS_ADD(ernode, EMPTY_STATUS_CHECK);
+ NODE_STATUS_ADD(mem_env[backs[i]].mem_node, EMPTY_STATUS_CHECK);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+set_parent_node_trav(Node* node, Node* parent)
+{
+ NODE_PARENT(node) = parent;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ set_parent_node_trav(NODE_CAR(node), node);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (! ANCHOR_HAS_BODY(ANCHOR_(node))) break;
+ set_parent_node_trav(NODE_BODY(node), node);
+ break;
+
+ case NODE_QUANT:
+ set_parent_node_trav(NODE_BODY(node), node);
+ break;
+
+ case NODE_BAG:
+ if (IS_NOT_NULL(NODE_BODY(node)))
+ set_parent_node_trav(NODE_BODY(node), node);
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then))
+ set_parent_node_trav(en->te.Then, node);
+ if (IS_NOT_NULL(en->te.Else)) {
+ set_parent_node_trav(en->te.Else, node);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+#ifdef USE_CALL
+
+#define RECURSION_EXIST (1<<0)
+#define RECURSION_MUST (1<<1)
+#define RECURSION_INFINITE (1<<2)
+
+static int
+infinite_recursive_call_check(Node* node, ScanEnv* env, int head)
+{
+ int ret;
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ {
+ Node *x;
+ OnigLen min;
+
+ x = node;
+ do {
+ ret = infinite_recursive_call_check(NODE_CAR(x), env, head);
+ if (ret < 0 || (ret & RECURSION_INFINITE) != 0) return ret;
+ r |= ret;
+ if (head != 0) {
+ min = node_min_byte_len(NODE_CAR(x), env);
+ if (min != 0) head = 0;
+ }
+ } while (IS_NOT_NULL(x = NODE_CDR(x)));
+ }
+ break;
+
+ case NODE_ALT:
+ {
+ int must;
+
+ must = RECURSION_MUST;
+ do {
+ ret = infinite_recursive_call_check(NODE_CAR(node), env, head);
+ if (ret < 0 || (ret & RECURSION_INFINITE) != 0) return ret;
+
+ r |= (ret & RECURSION_EXIST);
+ must &= ret;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ r |= must;
+ }
+ break;
+
+ case NODE_QUANT:
+ r = infinite_recursive_call_check(NODE_BODY(node), env, head);
+ if (r < 0) return r;
+ if ((r & RECURSION_MUST) != 0) {
+ if (QUANT_(node)->lower == 0)
+ r &= ~RECURSION_MUST;
+ }
+ break;
+
+ case NODE_ANCHOR:
+ if (! ANCHOR_HAS_BODY(ANCHOR_(node)))
+ break;
+ /* fall */
+ case NODE_CALL:
+ r = infinite_recursive_call_check(NODE_BODY(node), env, head);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_MARK2(node))
+ return 0;
+ else if (NODE_IS_MARK1(node))
+ return (head == 0 ? RECURSION_EXIST | RECURSION_MUST
+ : RECURSION_EXIST | RECURSION_MUST | RECURSION_INFINITE);
+ else {
+ NODE_STATUS_ADD(node, MARK2);
+ r = infinite_recursive_call_check(NODE_BODY(node), env, head);
+ NODE_STATUS_REMOVE(node, MARK2);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ int eret;
+
+ ret = infinite_recursive_call_check(NODE_BODY(node), env, head);
+ if (ret < 0 || (ret & RECURSION_INFINITE) != 0) return ret;
+ r |= ret;
+ if (IS_NOT_NULL(en->te.Then)) {
+ OnigLen min;
+ if (head != 0) {
+ min = node_min_byte_len(NODE_BODY(node), env);
+ }
+ else min = 0;
+
+ ret = infinite_recursive_call_check(en->te.Then, env, min != 0 ? 0:head);
+ if (ret < 0 || (ret & RECURSION_INFINITE) != 0) return ret;
+ r |= ret;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ eret = infinite_recursive_call_check(en->te.Else, env, head);
+ if (eret < 0 || (eret & RECURSION_INFINITE) != 0) return eret;
+ r |= (eret & RECURSION_EXIST);
+ if ((eret & RECURSION_MUST) == 0)
+ r &= ~RECURSION_MUST;
+ }
+ else {
+ r &= ~RECURSION_MUST;
+ }
+ }
+ else {
+ r = infinite_recursive_call_check(NODE_BODY(node), env, head);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+static int
+infinite_recursive_call_check_trav(Node* node, ScanEnv* env)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = infinite_recursive_call_check_trav(NODE_CAR(node), env);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (! ANCHOR_HAS_BODY(ANCHOR_(node))) {
+ r = 0;
+ break;
+ }
+ /* fall */
+ case NODE_QUANT:
+ r = infinite_recursive_call_check_trav(NODE_BODY(node), env);
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_RECURSION(node) && NODE_IS_CALLED(node)) {
+ int ret;
+
+ NODE_STATUS_ADD(node, MARK1);
+
+ ret = infinite_recursive_call_check(NODE_BODY(node), env, 1);
+ if (ret < 0) return ret;
+ else if ((ret & (RECURSION_MUST | RECURSION_INFINITE)) != 0)
+ return ONIGERR_NEVER_ENDING_RECURSION;
+
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = infinite_recursive_call_check_trav(en->te.Then, env);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = infinite_recursive_call_check_trav(en->te.Else, env);
+ if (r != 0) return r;
+ }
+ }
+ }
+
+ r = infinite_recursive_call_check_trav(NODE_BODY(node), env);
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+static int
+recursive_call_check(Node* node)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ r = 0;
+ do {
+ r |= recursive_call_check(NODE_CAR(node));
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (! ANCHOR_HAS_BODY(ANCHOR_(node))) {
+ r = 0;
+ break;
+ }
+ /* fall */
+ case NODE_QUANT:
+ r = recursive_call_check(NODE_BODY(node));
+ break;
+
+ case NODE_CALL:
+ r = recursive_call_check(NODE_BODY(node));
+ if (r != 0) {
+ if (NODE_IS_MARK1(NODE_BODY(node)))
+ NODE_STATUS_ADD(node, RECURSION);
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_MARK2(node))
+ return 0;
+ else if (NODE_IS_MARK1(node))
+ return 1; /* recursion */
+ else {
+ NODE_STATUS_ADD(node, MARK2);
+ r = recursive_call_check(NODE_BODY(node));
+ NODE_STATUS_REMOVE(node, MARK2);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ r = 0;
+ if (IS_NOT_NULL(en->te.Then)) {
+ r |= recursive_call_check(en->te.Then);
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r |= recursive_call_check(en->te.Else);
+ }
+ r |= recursive_call_check(NODE_BODY(node));
+ }
+ else {
+ r = recursive_call_check(NODE_BODY(node));
+ }
+ }
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+#define IN_RECURSION (1<<0)
+#define FOUND_CALLED_NODE 1
+
+static int
+recursive_call_check_trav(Node* node, ScanEnv* env, int state)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ {
+ int ret;
+ do {
+ ret = recursive_call_check_trav(NODE_CAR(node), env, state);
+ if (ret == FOUND_CALLED_NODE) r = FOUND_CALLED_NODE;
+ else if (ret < 0) return ret;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ }
+ break;
+
+ case NODE_QUANT:
+ r = recursive_call_check_trav(NODE_BODY(node), env, state);
+ if (QUANT_(node)->upper == 0) {
+ if (r == FOUND_CALLED_NODE)
+ QUANT_(node)->include_referred = 1;
+ }
+ break;
+
+ case NODE_ANCHOR:
+ {
+ AnchorNode* an = ANCHOR_(node);
+ if (ANCHOR_HAS_BODY(an))
+ r = recursive_call_check_trav(NODE_ANCHOR_BODY(an), env, state);
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ int ret;
+ int state1;
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_CALLED(node) || (state & IN_RECURSION) != 0) {
+ if (! NODE_IS_RECURSION(node)) {
+ NODE_STATUS_ADD(node, MARK1);
+ r = recursive_call_check(NODE_BODY(node));
+ if (r != 0) {
+ NODE_STATUS_ADD(node, RECURSION);
+ MEM_STATUS_ON(env->backtrack_mem, en->m.regnum);
+ }
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+
+ if (NODE_IS_CALLED(node))
+ r = FOUND_CALLED_NODE;
+ }
+ }
+
+ state1 = state;
+ if (NODE_IS_RECURSION(node))
+ state1 |= IN_RECURSION;
+
+ ret = recursive_call_check_trav(NODE_BODY(node), env, state1);
+ if (ret == FOUND_CALLED_NODE)
+ r = FOUND_CALLED_NODE;
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ ret = recursive_call_check_trav(en->te.Then, env, state1);
+ if (ret == FOUND_CALLED_NODE)
+ r = FOUND_CALLED_NODE;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ ret = recursive_call_check_trav(en->te.Else, env, state1);
+ if (ret == FOUND_CALLED_NODE)
+ r = FOUND_CALLED_NODE;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+#endif
+
+static void
+remove_from_list(Node* prev, Node* a)
+{
+ if (NODE_CDR(prev) != a) return ;
+
+ NODE_CDR(prev) = NODE_CDR(a);
+ NODE_CDR(a) = NULL_NODE;
+}
+
+static int
+reduce_string_list(Node* node)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ {
+ Node* prev;
+ Node* curr;
+ Node* prev_node;
+ Node* next_node;
+
+ prev = NULL_NODE;
+ do {
+ next_node = NODE_CDR(node);
+ curr = NODE_CAR(node);
+ if (NODE_TYPE(curr) == NODE_STRING) {
+ if (IS_NULL(prev)
+ || STR_(curr)->flag != STR_(prev)->flag
+ || NODE_STATUS(curr) != NODE_STATUS(prev)) {
+ prev = curr;
+ prev_node = node;
+ }
+ else {
+ r = node_str_node_cat(prev, curr);
+ if (r != 0) return r;
+ remove_from_list(prev_node, node);
+ onig_node_free(node);
+ }
+ }
+ else {
+ prev = NULL_NODE;
+ prev_node = node;
+ }
+
+ node = next_node;
+ } while (r == 0 && IS_NOT_NULL(node));
+ }
+ break;
+
+ case NODE_ALT:
+ do {
+ r = reduce_string_list(NODE_CAR(node));
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_ANCHOR:
+ if (IS_NULL(NODE_BODY(node)))
+ break;
+ /* fall */
+ case NODE_QUANT:
+ r = reduce_string_list(NODE_BODY(node));
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ r = reduce_string_list(NODE_BODY(node));
+ if (r != 0) return r;
+
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = reduce_string_list(en->te.Then);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = reduce_string_list(en->te.Else);
+ if (r != 0) return r;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+
+#define IN_ALT (1<<0)
+#define IN_NOT (1<<1)
+#define IN_REAL_REPEAT (1<<2)
+#define IN_VAR_REPEAT (1<<3)
+#define IN_ZERO_REPEAT (1<<4)
+#define IN_MULTI_ENTRY (1<<5)
+#define IN_LOOK_BEHIND (1<<6)
+
+
+/* divide different length alternatives in look-behind.
+ (?<=A|B) ==> (?<=A)|(?<=B)
+ (?<!A|B) ==> (?<!A)(?<!B)
+*/
+static int
+divide_look_behind_alternatives(Node* node)
+{
+ int r;
+ int anc_type;
+ Node *head, *np, *insert_node;
+ AnchorNode* an;
+
+ an = ANCHOR_(node);
+ anc_type = an->type;
+
+ head = NODE_ANCHOR_BODY(an);
+ np = NODE_CAR(head);
+ node_swap(node, head);
+ NODE_CAR(node) = head;
+ NODE_BODY(head) = np;
+
+ np = node;
+ while (IS_NOT_NULL(np = NODE_CDR(np))) {
+ r = onig_node_copy(&insert_node, head);
+ if (r != 0) return r;
+ CHECK_NULL_RETURN_MEMERR(insert_node);
+ NODE_BODY(insert_node) = NODE_CAR(np);
+ NODE_CAR(np) = insert_node;
+ }
+
+ if (anc_type == ANCR_LOOK_BEHIND_NOT) {
+ np = node;
+ do {
+ NODE_SET_TYPE(np, NODE_LIST); /* alt -> list */
+ } while (IS_NOT_NULL(np = NODE_CDR(np)));
+ }
+ return 0;
+}
+
+static int
+node_reduce_in_look_behind(Node* node)
+{
+ NodeType type;
+ Node* body;
+
+ if (NODE_TYPE(node) != NODE_QUANT) return 0;
+
+ body = NODE_BODY(node);
+ type = NODE_TYPE(body);
+ if (type == NODE_STRING || type == NODE_CTYPE ||
+ type == NODE_CCLASS || type == NODE_BACKREF) {
+ QuantNode* qn = QUANT_(node);
+ qn->upper = qn->lower;
+ if (qn->upper == 0)
+ return 1; /* removed */
+ }
+
+ return 0;
+}
+
+static int
+list_reduce_in_look_behind(Node* node)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_QUANT:
+ r = node_reduce_in_look_behind(node);
+ if (r > 0) r = 0;
+ break;
+
+ case NODE_LIST:
+ do {
+ r = node_reduce_in_look_behind(NODE_CAR(node));
+ if (r <= 0) break;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+static int
+alt_reduce_in_look_behind(Node* node, regex_t* reg, ScanEnv* env)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_ALT:
+ do {
+ r = list_reduce_in_look_behind(NODE_CAR(node));
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ default:
+ r = list_reduce_in_look_behind(node);
+ break;
+ }
+
+ return r;
+}
+
+static int tune_tree(Node* node, regex_t* reg, int state, ScanEnv* env);
+
+static int
+tune_look_behind(Node* node, regex_t* reg, int state, ScanEnv* env)
+{
+ int r;
+ int state1;
+ int used;
+ MinMaxCharLen ci;
+ Node* body;
+ AnchorNode* an = ANCHOR_(node);
+
+ used = FALSE;
+ r = check_node_in_look_behind(NODE_ANCHOR_BODY(an),
+ an->type == ANCR_LOOK_BEHIND_NOT ? 1 : 0,
+ &used);
+ if (r < 0) return r;
+ if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+
+ if (an->type == ANCR_LOOK_BEHIND_NOT)
+ state1 = state | IN_NOT | IN_LOOK_BEHIND;
+ else
+ state1 = state | IN_LOOK_BEHIND;
+
+ body = NODE_ANCHOR_BODY(an);
+ /* Execute tune_tree(body) before call node_char_len().
+ Because case-fold expansion must be done before node_char_len().
+ */
+ r = tune_tree(body, reg, state1, env);
+ if (r != 0) return r;
+
+ r = alt_reduce_in_look_behind(body, reg, env);
+ if (r != 0) return r;
+
+ r = node_char_len(body, reg, &ci, env);
+ if (r >= 0) {
+ /* #177: overflow in onigenc_step_back() */
+ if ((ci.max != INFINITE_LEN && ci.max > LOOK_BEHIND_MAX_CHAR_LEN)
+ || ci.min > LOOK_BEHIND_MAX_CHAR_LEN) {
+ return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ }
+
+ if (ci.min == 0 && ci.min_is_sure != 0 && used == FALSE) {
+ if (an->type == ANCR_LOOK_BEHIND_NOT)
+ r = onig_node_reset_fail(node);
+ else
+ r = onig_node_reset_empty(node);
+
+ return r;
+ }
+
+ if (r == CHAR_LEN_TOP_ALT_FIXED) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND)) {
+ r = divide_look_behind_alternatives(node);
+ if (r == 0)
+ r = tune_tree(node, reg, state, env);
+ }
+ else if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND))
+ goto normal;
+ else
+ r = ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ }
+ else { /* CHAR_LEN_NORMAL */
+ normal:
+ if (ci.min == INFINITE_LEN) {
+ r = ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ }
+ else {
+ if (ci.min != ci.max &&
+ ! IS_SYNTAX_BV(env->syntax, ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND)) {
+ r = ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ }
+ else {
+ Node* tail;
+
+ /* check lead_node is already set by double call after
+ divide_look_behind_alternatives() */
+ if (IS_NULL(an->lead_node)) {
+ an->char_min_len = ci.min;
+ an->char_max_len = ci.max;
+ r = get_tree_tail_literal(body, &tail, reg);
+ if (r == GET_VALUE_FOUND) {
+ r = onig_node_copy(&(an->lead_node), tail);
+ if (r != 0) return r;
+ }
+ }
+ r = ONIG_NORMAL;
+ }
+ }
+ }
+ }
+
+ return r;
+}
+
+static int
+tune_next(Node* node, Node* next_node, regex_t* reg)
+{
+ NodeType type;
+
+ retry:
+ type = NODE_TYPE(node);
+ if (type == NODE_QUANT) {
+ QuantNode* qn = QUANT_(node);
+ if (qn->greedy && IS_INFINITE_REPEAT(qn->upper)) {
+#ifdef USE_QUANT_PEEK_NEXT
+ Node* n = get_tree_head_literal(next_node, 1, reg);
+ /* '\0': for UTF-16BE etc... */
+ if (IS_NOT_NULL(n) && STR_(n)->s[0] != '\0') {
+ qn->next_head_exact = n;
+ }
+#endif
+ /* automatic posseivation a*b ==> (?>a*)b */
+ if (qn->lower <= 1) {
+ if (is_strict_real_node(NODE_BODY(node))) {
+ Node *x, *y;
+ x = get_tree_head_literal(NODE_BODY(node), 0, reg);
+ if (IS_NOT_NULL(x)) {
+ y = get_tree_head_literal(next_node, 0, reg);
+ if (IS_NOT_NULL(y) && is_exclusive(x, y, reg)) {
+ Node* en = onig_node_new_bag(BAG_STOP_BACKTRACK);
+ CHECK_NULL_RETURN_MEMERR(en);
+ NODE_STATUS_ADD(en, STRICT_REAL_REPEAT);
+ node_swap(node, en);
+ NODE_BODY(node) = en;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (type == NODE_BAG) {
+ BagNode* en = BAG_(node);
+ if (en->type == BAG_MEMORY) {
+ node = NODE_BODY(node);
+ goto retry;
+ }
+ }
+ return 0;
+}
+
+
+static int
+is_all_code_len_1_items(int n, OnigCaseFoldCodeItem items[])
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+ if (item->code_len != 1) return 0;
+ }
+
+ return 1;
+}
+
+static int
+get_min_max_byte_len_case_fold_items(int n, OnigCaseFoldCodeItem items[],
+ OnigLen* rmin, OnigLen* rmax)
+{
+ int i;
+ OnigLen len, minlen, maxlen;
+
+ minlen = INFINITE_LEN;
+ maxlen = 0;
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+
+ len = item->byte_len;
+ if (len < minlen) minlen = len;
+ if (len > maxlen) maxlen = len;
+ }
+
+ *rmin = minlen;
+ *rmax = maxlen;
+ return 0;
+}
+
+static int
+make_code_list_to_string(Node** rnode, OnigEncoding enc,
+ int n, OnigCodePoint codes[])
+{
+ int r, i, len;
+ Node* node;
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
+
+ *rnode = NULL_NODE;
+ node = onig_node_new_str(NULL, NULL);
+ CHECK_NULL_RETURN_MEMERR(node);
+
+ for (i = 0; i < n; i++) {
+ len = ONIGENC_CODE_TO_MBC(enc, codes[i], buf);
+ if (len < 0) {
+ r = len;
+ goto err;
+ }
+
+ r = onig_node_str_cat(node, buf, buf + len);
+ if (r != 0) goto err;
+ }
+
+ *rnode = node;
+ return 0;
+
+ err:
+ onig_node_free(node);
+ return r;
+}
+
+static int
+unravel_cf_node_add(Node** rlist, Node* add)
+{
+ Node *list;
+
+ list = *rlist;
+ if (IS_NULL(list)) {
+ list = onig_node_new_list(add, NULL);
+ CHECK_NULL_RETURN_MEMERR(list);
+ *rlist = list;
+ }
+ else {
+ Node* r = node_list_add(list, add);
+ CHECK_NULL_RETURN_MEMERR(r);
+ }
+
+ return 0;
+}
+
+static int
+unravel_cf_string_add(Node** rlist, Node** rsn, UChar* s, UChar* end,
+ unsigned int flag)
+{
+ int r;
+ Node *sn, *list;
+
+ list = *rlist;
+ sn = *rsn;
+
+ if (IS_NOT_NULL(sn) && STR_(sn)->flag == flag) {
+ r = onig_node_str_cat(sn, s, end);
+ }
+ else {
+ sn = onig_node_new_str(s, end);
+ CHECK_NULL_RETURN_MEMERR(sn);
+
+ STR_(sn)->flag = flag;
+ r = unravel_cf_node_add(&list, sn);
+ }
+
+ if (r == 0) {
+ *rlist = list;
+ *rsn = sn;
+ }
+ return r;
+}
+
+static int
+unravel_cf_string_alt_or_cc_add(Node** rlist, int n,
+ OnigCaseFoldCodeItem items[], OnigEncoding enc,
+ OnigCaseFoldType case_fold_flag, UChar* s, UChar* end)
+{
+ int r, i;
+ Node* node;
+
+ if (is_all_code_len_1_items(n, items)) {
+ OnigCodePoint codes[14];/* least ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM + 1 */
+
+ codes[0] = ONIGENC_MBC_TO_CODE(enc, s, end);
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+ codes[i+1] = item->code[0];
+ }
+ r = onig_new_cclass_with_code_list(&node, enc, n + 1, codes);
+ if (r != 0) return r;
+ }
+ else {
+ Node *snode, *alt, *curr;
+
+ snode = onig_node_new_str(s, end);
+ CHECK_NULL_RETURN_MEMERR(snode);
+ node = curr = onig_node_new_alt(snode, NULL_NODE);
+ if (IS_NULL(curr)) {
+ onig_node_free(snode);
+ return ONIGERR_MEMORY;
+ }
+
+ r = 0;
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+ r = make_code_list_to_string(&snode, enc, item->code_len, item->code);
+ if (r != 0) {
+ onig_node_free(node);
+ return r;
+ }
+
+ alt = onig_node_new_alt(snode, NULL_NODE);
+ if (IS_NULL(alt)) {
+ onig_node_free(snode);
+ onig_node_free(node);
+ return ONIGERR_MEMORY;
+ }
+
+ NODE_CDR(curr) = alt;
+ curr = alt;
+ }
+ }
+
+ r = unravel_cf_node_add(rlist, node);
+ if (r != 0) onig_node_free(node);
+ return r;
+}
+
+static int
+unravel_cf_look_behind_add(Node** rlist, Node** rsn,
+ int n, OnigCaseFoldCodeItem items[], OnigEncoding enc,
+ UChar* s, OnigLen one_len)
+{
+ int r, i, found;
+
+ found = 0;
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+ if (item->byte_len == one_len) {
+ if (item->code_len == 1) {
+ found = 1;
+ }
+ }
+ }
+
+ if (found == 0) {
+ r = unravel_cf_string_add(rlist, rsn, s, s + one_len, 0 /* flag */);
+ }
+ else {
+ Node* node;
+ OnigCodePoint codes[14];/* least ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM + 1 */
+
+ found = 0;
+ codes[found++] = ONIGENC_MBC_TO_CODE(enc, s, s + one_len);
+ for (i = 0; i < n; i++) {
+ OnigCaseFoldCodeItem* item = items + i;
+ if (item->byte_len == one_len) {
+ if (item->code_len == 1) {
+ codes[found++] = item->code[0];
+ }
+ }
+ }
+ r = onig_new_cclass_with_code_list(&node, enc, found, codes);
+ if (r != 0) return r;
+
+ r = unravel_cf_node_add(rlist, node);
+ if (r != 0) onig_node_free(node);
+
+ *rsn = NULL_NODE;
+ }
+
+ return r;
+}
+
+static int
+unravel_case_fold_string(Node* node, regex_t* reg, int state)
+{
+ int r, n, in_look_behind;
+ OnigLen min_len, max_len, one_len;
+ UChar *start, *end, *p, *q;
+ StrNode* snode;
+ Node *sn, *list;
+ OnigEncoding enc;
+ OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
+
+ if (NODE_STRING_IS_CASE_EXPANDED(node)) return 0;
+
+ NODE_STATUS_REMOVE(node, IGNORECASE);
+ snode = STR_(node);
+ start = snode->s;
+ end = snode->end;
+ if (start >= end) return 0;
+
+ in_look_behind = (state & IN_LOOK_BEHIND) != 0;
+ enc = reg->enc;
+
+ list = sn = NULL_NODE;
+ p = start;
+ while (p < end) {
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag, p, end,
+ items);
+ if (n < 0) {
+ r = n;
+ goto err;
+ }
+
+ one_len = (OnigLen )enclen(enc, p);
+ if (n == 0) {
+ q = p + one_len;
+ r = unravel_cf_string_add(&list, &sn, p, q, 0 /* flag */);
+ if (r != 0) goto err;
+ }
+ else {
+ if (in_look_behind != 0) {
+ q = p + one_len;
+ if (items[0].byte_len != one_len) {
+ r = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag, p, q,
+ items);
+ if (r < 0) goto err;
+ n = r;
+ }
+ r = unravel_cf_look_behind_add(&list, &sn, n, items, enc, p, one_len);
+ if (r != 0) goto err;
+ }
+ else {
+ get_min_max_byte_len_case_fold_items(n, items, &min_len, &max_len);
+ if (min_len != max_len) {
+ r = ONIGERR_PARSER_BUG;
+ goto err;
+ }
+
+ q = p + max_len;
+ r = unravel_cf_string_alt_or_cc_add(&list, n, items, enc,
+ reg->case_fold_flag, p, q);
+ if (r != 0) goto err;
+ sn = NULL_NODE;
+ }
+ }
+
+ p = q;
+ }
+
+ if (IS_NOT_NULL(list)) {
+ if (node_list_len(list) == 1) {
+ node_swap(node, NODE_CAR(list));
+ }
+ else {
+ node_swap(node, list);
+ }
+ onig_node_free(list);
+ }
+ else {
+ node_swap(node, sn);
+ onig_node_free(sn);
+ }
+ return 0;
+
+ err:
+ if (IS_NOT_NULL(list))
+ onig_node_free(list);
+ else if (IS_NOT_NULL(sn))
+ onig_node_free(sn);
+
+ return r;
+}
+
+#ifdef USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT
+static enum BodyEmptyType
+quantifiers_memory_node_info(Node* node)
+{
+ int r = BODY_MAY_BE_EMPTY;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ {
+ int v;
+ do {
+ v = quantifiers_memory_node_info(NODE_CAR(node));
+ if (v > r) r = v;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ if (NODE_IS_RECURSION(node)) {
+ return BODY_MAY_BE_EMPTY_REC; /* tiny version */
+ }
+ else
+ r = quantifiers_memory_node_info(NODE_BODY(node));
+ break;
+#endif
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+ if (qn->upper != 0) {
+ r = quantifiers_memory_node_info(NODE_BODY(node));
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+ switch (en->type) {
+ case BAG_MEMORY:
+ if (NODE_IS_RECURSION(node)) {
+ return BODY_MAY_BE_EMPTY_REC;
+ }
+ return BODY_MAY_BE_EMPTY_MEM;
+ break;
+
+ case BAG_OPTION:
+ case BAG_STOP_BACKTRACK:
+ r = quantifiers_memory_node_info(NODE_BODY(node));
+ break;
+ case BAG_IF_ELSE:
+ {
+ int v;
+ r = quantifiers_memory_node_info(NODE_BODY(node));
+ if (IS_NOT_NULL(en->te.Then)) {
+ v = quantifiers_memory_node_info(en->te.Then);
+ if (v > r) r = v;
+ }
+ if (IS_NOT_NULL(en->te.Else)) {
+ v = quantifiers_memory_node_info(en->te.Else);
+ if (v > r) r = v;
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ case NODE_STRING:
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ case NODE_ANCHOR:
+ case NODE_GIMMICK:
+ default:
+ break;
+ }
+
+ return r;
+}
+#endif /* USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT */
+
+
+#ifdef USE_CALL
+
+#ifdef __GNUC__
+__inline
+#endif
+static int
+tune_call_node_call(CallNode* cn, ScanEnv* env, int state)
+{
+ MemEnv* mem_env = SCANENV_MEMENV(env);
+
+ if (cn->by_number != 0) {
+ int gnum = cn->group_num;
+
+ if (env->num_named > 0 &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
+ ! OPTON_CAPTURE_GROUP(env->options)) {
+ return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
+ }
+
+ if (gnum > env->num_mem) {
+ onig_scan_env_set_error_string(env, ONIGERR_UNDEFINED_GROUP_REFERENCE,
+ cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_GROUP_REFERENCE;
+ }
+
+ set_call_attr:
+ NODE_CALL_BODY(cn) = mem_env[cn->group_num].mem_node;
+ if (IS_NULL(NODE_CALL_BODY(cn))) {
+ onig_scan_env_set_error_string(env, ONIGERR_UNDEFINED_NAME_REFERENCE,
+ cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ }
+ else {
+ int *refs;
+
+ int n = onig_name_to_group_numbers(env->reg, cn->name, cn->name_end, &refs);
+ if (n <= 0) {
+ onig_scan_env_set_error_string(env, ONIGERR_UNDEFINED_NAME_REFERENCE,
+ cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ else if (n > 1) {
+ onig_scan_env_set_error_string(env, ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL,
+ cn->name, cn->name_end);
+ return ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL;
+ }
+ else {
+ cn->group_num = refs[0];
+ goto set_call_attr;
+ }
+ }
+
+ return 0;
+}
+
+static void
+tune_call2_call(Node* node)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ tune_call2_call(NODE_CAR(node));
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ tune_call2_call(NODE_BODY(node));
+ break;
+
+ case NODE_ANCHOR:
+ if (ANCHOR_HAS_BODY(ANCHOR_(node)))
+ tune_call2_call(NODE_BODY(node));
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (! NODE_IS_MARK1(node)) {
+ NODE_STATUS_ADD(node, MARK1);
+ tune_call2_call(NODE_BODY(node));
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ tune_call2_call(NODE_BODY(node));
+ if (IS_NOT_NULL(en->te.Then))
+ tune_call2_call(en->te.Then);
+ if (IS_NOT_NULL(en->te.Else))
+ tune_call2_call(en->te.Else);
+ }
+ else {
+ tune_call2_call(NODE_BODY(node));
+ }
+ }
+ break;
+
+ case NODE_CALL:
+ if (! NODE_IS_MARK1(node)) {
+ NODE_STATUS_ADD(node, MARK1);
+ {
+ CallNode* cn = CALL_(node);
+ Node* called = NODE_CALL_BODY(cn);
+
+ cn->entry_count++;
+
+ NODE_STATUS_ADD(called, CALLED);
+ BAG_(called)->m.entry_count++;
+ tune_call2_call(called);
+ }
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int
+tune_call(Node* node, ScanEnv* env, int state)
+{
+ int r;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = tune_call(NODE_CAR(node), env, state);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ if (QUANT_(node)->upper == 0)
+ state |= IN_ZERO_REPEAT;
+
+ r = tune_call(NODE_BODY(node), env, state);
+ break;
+
+ case NODE_ANCHOR:
+ if (ANCHOR_HAS_BODY(ANCHOR_(node)))
+ r = tune_call(NODE_BODY(node), env, state);
+ else
+ r = 0;
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if ((state & IN_ZERO_REPEAT) != 0) {
+ NODE_STATUS_ADD(node, IN_ZERO_REPEAT);
+ BAG_(node)->m.entry_count--;
+ }
+ r = tune_call(NODE_BODY(node), env, state);
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ r = tune_call(NODE_BODY(node), env, state);
+ if (r != 0) return r;
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = tune_call(en->te.Then, env, state);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else))
+ r = tune_call(en->te.Else, env, state);
+ }
+ else
+ r = tune_call(NODE_BODY(node), env, state);
+ }
+ break;
+
+ case NODE_CALL:
+ if ((state & IN_ZERO_REPEAT) != 0) {
+ NODE_STATUS_ADD(node, IN_ZERO_REPEAT);
+ CALL_(node)->entry_count--;
+ }
+
+ r = tune_call_node_call(CALL_(node), env, state);
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+static int
+tune_call2(Node* node)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ do {
+ r = tune_call2(NODE_CAR(node));
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ if (QUANT_(node)->upper != 0)
+ r = tune_call2(NODE_BODY(node));
+ break;
+
+ case NODE_ANCHOR:
+ if (ANCHOR_HAS_BODY(ANCHOR_(node)))
+ r = tune_call2(NODE_BODY(node));
+ break;
+
+ case NODE_BAG:
+ if (! NODE_IS_IN_ZERO_REPEAT(node))
+ r = tune_call2(NODE_BODY(node));
+
+ {
+ BagNode* en = BAG_(node);
+
+ if (r != 0) return r;
+ if (en->type == BAG_IF_ELSE) {
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = tune_call2(en->te.Then);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else))
+ r = tune_call2(en->te.Else);
+ }
+ }
+ break;
+
+ case NODE_CALL:
+ if (! NODE_IS_IN_ZERO_REPEAT(node)) {
+ tune_call2_call(node);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+
+static void
+tune_called_state_call(Node* node, int state)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_ALT:
+ state |= IN_ALT;
+ /* fall */
+ case NODE_LIST:
+ do {
+ tune_called_state_call(NODE_CAR(node), state);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (IS_INFINITE_REPEAT(qn->upper) || qn->upper >= 2)
+ state |= IN_REAL_REPEAT;
+ if (qn->lower != qn->upper)
+ state |= IN_VAR_REPEAT;
+
+ tune_called_state_call(NODE_QUANT_BODY(qn), state);
+ }
+ break;
+
+ case NODE_ANCHOR:
+ {
+ AnchorNode* an = ANCHOR_(node);
+
+ switch (an->type) {
+ case ANCR_PREC_READ_NOT:
+ case ANCR_LOOK_BEHIND_NOT:
+ state |= IN_NOT;
+ /* fall */
+ case ANCR_PREC_READ:
+ case ANCR_LOOK_BEHIND:
+ tune_called_state_call(NODE_ANCHOR_BODY(an), state);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ if (en->type == BAG_MEMORY) {
+ if (NODE_IS_MARK1(node)) {
+ if ((~en->m.called_state & state) != 0) {
+ en->m.called_state |= state;
+ tune_called_state_call(NODE_BODY(node), state);
+ }
+ }
+ else {
+ NODE_STATUS_ADD(node, MARK1);
+ en->m.called_state |= state;
+ tune_called_state_call(NODE_BODY(node), state);
+ NODE_STATUS_REMOVE(node, MARK1);
+ }
+ }
+ else if (en->type == BAG_IF_ELSE) {
+ state |= IN_ALT;
+ tune_called_state_call(NODE_BODY(node), state);
+ if (IS_NOT_NULL(en->te.Then)) {
+ tune_called_state_call(en->te.Then, state);
+ }
+ if (IS_NOT_NULL(en->te.Else))
+ tune_called_state_call(en->te.Else, state);
+ }
+ else {
+ tune_called_state_call(NODE_BODY(node), state);
+ }
+ }
+ break;
+
+ case NODE_CALL:
+ tune_called_state_call(NODE_BODY(node), state);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+tune_called_state(Node* node, int state)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_ALT:
+ state |= IN_ALT;
+ /* fall */
+ case NODE_LIST:
+ do {
+ tune_called_state(NODE_CAR(node), state);
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ tune_called_state_call(node, state);
+ break;
+#endif
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ switch (en->type) {
+ case BAG_MEMORY:
+ if (en->m.entry_count > 1)
+ state |= IN_MULTI_ENTRY;
+
+ en->m.called_state |= state;
+ /* fall */
+ case BAG_OPTION:
+ case BAG_STOP_BACKTRACK:
+ tune_called_state(NODE_BODY(node), state);
+ break;
+ case BAG_IF_ELSE:
+ state |= IN_ALT;
+ tune_called_state(NODE_BODY(node), state);
+ if (IS_NOT_NULL(en->te.Then))
+ tune_called_state(en->te.Then, state);
+ if (IS_NOT_NULL(en->te.Else))
+ tune_called_state(en->te.Else, state);
+ break;
+ }
+ }
+ break;
+
+ case NODE_QUANT:
+ {
+ QuantNode* qn = QUANT_(node);
+
+ if (IS_INFINITE_REPEAT(qn->upper) || qn->upper >= 2)
+ state |= IN_REAL_REPEAT;
+ if (qn->lower != qn->upper)
+ state |= IN_VAR_REPEAT;
+
+ tune_called_state(NODE_QUANT_BODY(qn), state);
+ }
+ break;
+
+ case NODE_ANCHOR:
+ {
+ AnchorNode* an = ANCHOR_(node);
+
+ switch (an->type) {
+ case ANCR_PREC_READ_NOT:
+ case ANCR_LOOK_BEHIND_NOT:
+ state |= IN_NOT;
+ /* fall */
+ case ANCR_PREC_READ:
+ case ANCR_LOOK_BEHIND:
+ tune_called_state(NODE_ANCHOR_BODY(an), state);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case NODE_BACKREF:
+ case NODE_STRING:
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ case NODE_GIMMICK:
+ default:
+ break;
+ }
+}
+
+#endif /* USE_CALL */
+
+
+#ifdef __GNUC__
+__inline
+#endif
+static int
+tune_anchor(Node* node, regex_t* reg, int state, ScanEnv* env)
+{
+ int r;
+ AnchorNode* an = ANCHOR_(node);
+
+ switch (an->type) {
+ case ANCR_PREC_READ:
+ r = tune_tree(NODE_ANCHOR_BODY(an), reg, state, env);
+ break;
+ case ANCR_PREC_READ_NOT:
+ r = tune_tree(NODE_ANCHOR_BODY(an), reg, (state | IN_NOT), env);
+ break;
+
+ case ANCR_LOOK_BEHIND:
+ case ANCR_LOOK_BEHIND_NOT:
+ r = tune_look_behind(node, reg, state, env);
+ break;
+
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+#ifdef __GNUC__
+__inline
+#endif
+static int
+tune_quant(Node* node, regex_t* reg, int state, ScanEnv* env)
+{
+ int r;
+ QuantNode* qn = QUANT_(node);
+ Node* body = NODE_BODY(node);
+
+ if ((state & IN_REAL_REPEAT) != 0) {
+ NODE_STATUS_ADD(node, IN_REAL_REPEAT);
+ }
+ if ((state & IN_MULTI_ENTRY) != 0) {
+ NODE_STATUS_ADD(node, IN_MULTI_ENTRY);
+ }
+
+ if (IS_INFINITE_REPEAT(qn->upper) || qn->upper >= 1) {
+ OnigLen d = node_min_byte_len(body, env);
+ if (d == 0) {
+#ifdef USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT
+ qn->emptiness = quantifiers_memory_node_info(body);
+#else
+ qn->emptiness = BODY_MAY_BE_EMPTY;
+#endif
+ }
+ }
+
+ if (IS_INFINITE_REPEAT(qn->upper) || qn->upper >= 2)
+ state |= IN_REAL_REPEAT;
+ if (qn->lower != qn->upper)
+ state |= IN_VAR_REPEAT;
+
+ r = tune_tree(body, reg, state, env);
+ if (r != 0) return r;
+
+ /* expand string */
+#define EXPAND_STRING_MAX_LENGTH 100
+ if (NODE_TYPE(body) == NODE_STRING) {
+ if (!IS_INFINITE_REPEAT(qn->lower) && qn->lower == qn->upper &&
+ qn->lower > 1 && qn->lower <= EXPAND_STRING_MAX_LENGTH) {
+ int len = NODE_STRING_LEN(body);
+
+ if (len * qn->lower <= EXPAND_STRING_MAX_LENGTH) {
+ int i, n = qn->lower;
+ node_conv_to_str_node(node, body);
+ for (i = 0; i < n; i++) {
+ r = node_str_node_cat(node, body);
+ if (r != 0) return r;
+ }
+ onig_node_free(body);
+ return r;
+ }
+ }
+ }
+
+ if (qn->greedy && (qn->emptiness == BODY_IS_NOT_EMPTY)) {
+ if (NODE_TYPE(body) == NODE_QUANT) {
+ QuantNode* tqn = QUANT_(body);
+ if (IS_NOT_NULL(tqn->head_exact)) {
+ qn->head_exact = tqn->head_exact;
+ tqn->head_exact = NULL;
+ }
+ }
+ else {
+ qn->head_exact = get_tree_head_literal(NODE_BODY(node), 1, reg);
+ }
+ }
+
+ return r;
+}
+
+/* tune_tree does the following work.
+ 1. check empty loop. (set qn->emptiness)
+ 2. expand ignore-case in char class.
+ 3. set memory status bit flags. (reg->mem_stats)
+ 4. set qn->head_exact for [push, exact] -> [push_or_jump_exact1, exact].
+ 5. find invalid patterns in look-behind.
+ 6. expand repeated string.
+ */
+static int
+tune_tree(Node* node, regex_t* reg, int state, ScanEnv* env)
+{
+ int r = 0;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ {
+ Node* prev = NULL_NODE;
+ do {
+ r = tune_tree(NODE_CAR(node), reg, state, env);
+ if (IS_NOT_NULL(prev) && r == 0) {
+ r = tune_next(prev, NODE_CAR(node), reg);
+ }
+ prev = NODE_CAR(node);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ }
+ break;
+
+ case NODE_ALT:
+ do {
+ r = tune_tree(NODE_CAR(node), reg, (state | IN_ALT), env);
+ } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ case NODE_STRING:
+ if (NODE_IS_IGNORECASE(node) && ! NODE_STRING_IS_CRUDE(node)) {
+ r = unravel_case_fold_string(node, reg, state);
+ }
+ break;
+
+ case NODE_BACKREF:
+ {
+ int i;
+ int* p;
+ BackRefNode* br = BACKREF_(node);
+ p = BACKREFS_P(br);
+ for (i = 0; i < br->back_num; i++) {
+ if (p[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
+ MEM_STATUS_ON(env->backrefed_mem, p[i]);
+#if 0
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (NODE_IS_NEST_LEVEL(node)) {
+ MEM_STATUS_ON(env->backtrack_mem, p[i]);
+ }
+#endif
+#else
+ /* More precisely, it should be checked whether alt/repeat exists before
+ the subject capture node, and then this backreference position
+ exists before (or in) the capture node. */
+ MEM_STATUS_ON(env->backtrack_mem, p[i]);
+#endif
+ }
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ switch (en->type) {
+ case BAG_OPTION:
+ {
+ OnigOptionType options = reg->options;
+ reg->options = BAG_(node)->o.options;
+ r = tune_tree(NODE_BODY(node), reg, state, env);
+ reg->options = options;
+ }
+ break;
+
+ case BAG_MEMORY:
+#ifdef USE_CALL
+ state |= en->m.called_state;
+#endif
+
+ if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT | IN_MULTI_ENTRY)) != 0
+ || NODE_IS_RECURSION(node)) {
+ MEM_STATUS_ON(env->backtrack_mem, en->m.regnum);
+ }
+ r = tune_tree(NODE_BODY(node), reg, state, env);
+ break;
+
+ case BAG_STOP_BACKTRACK:
+ {
+ Node* target = NODE_BODY(node);
+ r = tune_tree(target, reg, state, env);
+ if (NODE_TYPE(target) == NODE_QUANT) {
+ QuantNode* tqn = QUANT_(target);
+ if (IS_INFINITE_REPEAT(tqn->upper) && tqn->lower <= 1 &&
+ tqn->greedy != 0) { /* (?>a*), a*+ etc... */
+ if (is_strict_real_node(NODE_BODY(target)))
+ NODE_STATUS_ADD(node, STRICT_REAL_REPEAT);
+ }
+ }
+ }
+ break;
+
+ case BAG_IF_ELSE:
+ r = tune_tree(NODE_BODY(node), reg, (state | IN_ALT), env);
+ if (r != 0) return r;
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = tune_tree(en->te.Then, reg, (state | IN_ALT), env);
+ if (r != 0) return r;
+ }
+ if (IS_NOT_NULL(en->te.Else))
+ r = tune_tree(en->te.Else, reg, (state | IN_ALT), env);
+ break;
+ }
+ }
+ break;
+
+ case NODE_QUANT:
+ r = tune_quant(node, reg, state, env);
+ break;
+
+ case NODE_ANCHOR:
+ r = tune_anchor(node, reg, state, env);
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+#endif
+ case NODE_CTYPE:
+ case NODE_CCLASS:
+ case NODE_GIMMICK:
+ default:
+ break;
+ }
+
+ return r;
+}
+
+static int
+set_sunday_quick_search_or_bmh_skip_table(regex_t* reg, int case_expand,
+ UChar* s, UChar* end,
+ UChar skip[], int* roffset)
+{
+ int i, j, k, len, offset;
+ int n, clen;
+ UChar* p;
+ OnigEncoding enc;
+ OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
+ UChar buf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
+
+ enc = reg->enc;
+ offset = ENC_GET_SKIP_OFFSET(enc);
+ if (offset == ENC_SKIP_OFFSET_1_OR_0) {
+ UChar* p = s;
+ while (1) {
+ len = enclen(enc, p);
+ if (p + len >= end) {
+ if (len == 1) offset = 1;
+ else offset = 0;
+ break;
+ }
+ p += len;
+ }
+ }
+
+ len = (int )(end - s);
+ if (len + offset >= UCHAR_MAX)
+ return ONIGERR_PARSER_BUG;
+
+ *roffset = offset;
+
+ for (i = 0; i < CHAR_MAP_SIZE; i++) {
+ skip[i] = (UChar )(len + offset);
+ }
+
+ for (p = s; p < end; ) {
+ int z;
+
+ clen = enclen(enc, p);
+ if (p + clen > end) clen = (int )(end - p);
+
+ len = (int )(end - p);
+ for (j = 0; j < clen; j++) {
+ z = len - j + (offset - 1);
+ if (z <= 0) break;
+ skip[p[j]] = z;
+ }
+
+ if (case_expand != 0) {
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
+ p, end, items);
+ for (k = 0; k < n; k++) {
+ ONIGENC_CODE_TO_MBC(enc, items[k].code[0], buf);
+ for (j = 0; j < clen; j++) {
+ z = len - j + (offset - 1);
+ if (z <= 0) break;
+ if (skip[buf[j]] > z)
+ skip[buf[j]] = z;
+ }
+ }
+ }
+
+ p += clen;
+ }
+
+ return 0;
+}
+
+
+#define OPT_EXACT_MAXLEN 24
+
+#if OPT_EXACT_MAXLEN >= UCHAR_MAX
+#error Too big OPT_EXACT_MAXLEN
+#endif
+
+typedef struct {
+ MinMaxLen mm;
+ OnigEncoding enc;
+ OnigCaseFoldType case_fold_flag;
+ ScanEnv* scan_env;
+} OptEnv;
+
+typedef struct {
+ int left;
+ int right;
+} OptAnc;
+
+typedef struct {
+ MinMaxLen mm; /* position */
+ OptAnc anc;
+ int reach_end;
+ int len;
+ UChar s[OPT_EXACT_MAXLEN];
+} OptStr;
+
+typedef struct {
+ MinMaxLen mm; /* position */
+ OptAnc anc;
+ int value; /* weighted value */
+ UChar map[CHAR_MAP_SIZE];
+} OptMap;
+
+typedef struct {
+ MinMaxLen len;
+ OptAnc anc;
+ OptStr sb; /* boundary */
+ OptStr sm; /* middle */
+ OptStr spr; /* prec read (?=...) */
+ OptMap map; /* boundary */
+} OptNode;
+
+
+static int
+map_position_value(OnigEncoding enc, int i)
+{
+ static const short int Vals[] = {
+ 5, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 1, 1, 10, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 12, 4, 7, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5,
+ 5, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 5, 5, 5,
+ 5, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 1
+ };
+
+ if (i < (int )(sizeof(Vals)/sizeof(Vals[0]))) {
+ if (i == 0 && ONIGENC_MBC_MINLEN(enc) > 1)
+ return 20;
+ else
+ return (int )Vals[i];
+ }
+ else
+ return 4; /* Take it easy. */
+}
+
+static int
+distance_value(MinMaxLen* mm)
+{
+ /* 1000 / (min-max-dist + 1) */
+ static const short int dist_vals[] = {
+ 1000, 500, 333, 250, 200, 167, 143, 125, 111, 100,
+ 91, 83, 77, 71, 67, 63, 59, 56, 53, 50,
+ 48, 45, 43, 42, 40, 38, 37, 36, 34, 33,
+ 32, 31, 30, 29, 29, 28, 27, 26, 26, 25,
+ 24, 24, 23, 23, 22, 22, 21, 21, 20, 20,
+ 20, 19, 19, 19, 18, 18, 18, 17, 17, 17,
+ 16, 16, 16, 16, 15, 15, 15, 15, 14, 14,
+ 14, 14, 14, 14, 13, 13, 13, 13, 13, 13,
+ 12, 12, 12, 12, 12, 12, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 10, 10, 10, 10, 10
+ };
+
+ OnigLen d;
+
+ if (mm->max == INFINITE_LEN) return 0;
+
+ d = mm->max - mm->min;
+ if (d < (OnigLen )(sizeof(dist_vals)/sizeof(dist_vals[0])))
+ /* return dist_vals[d] * 16 / (mm->min + 12); */
+ return (int )dist_vals[d];
+ else
+ return 1;
+}
+
+static int
+comp_distance_value(MinMaxLen* d1, MinMaxLen* d2, int v1, int v2)
+{
+ if (v2 <= 0) return -1;
+ if (v1 <= 0) return 1;
+
+ v1 *= distance_value(d1);
+ v2 *= distance_value(d2);
+
+ if (v2 > v1) return 1;
+ if (v2 < v1) return -1;
+
+ if (d2->min < d1->min) return 1;
+ if (d2->min > d1->min) return -1;
+ return 0;
+}
+
+static void
+copy_opt_env(OptEnv* to, OptEnv* from)
+{
+ *to = *from;
+}
+
+static void
+clear_opt_anc_info(OptAnc* a)
+{
+ a->left = 0;
+ a->right = 0;
+}
+
+static void
+copy_opt_anc_info(OptAnc* to, OptAnc* from)
+{
+ *to = *from;
+}
+
+static void
+concat_opt_anc_info(OptAnc* to, OptAnc* left, OptAnc* right,
+ OnigLen left_len, OnigLen right_len)
+{
+ clear_opt_anc_info(to);
+
+ to->left = left->left;
+ if (left_len == 0) {
+ to->left |= right->left;
+ }
+
+ to->right = right->right;
+ if (right_len == 0) {
+ to->right |= left->right;
+ }
+ else {
+ to->right |= (left->right & ANCR_PREC_READ_NOT);
+ }
+}
+
+static int
+is_left(int a)
+{
+ if (a == ANCR_END_BUF || a == ANCR_SEMI_END_BUF ||
+ a == ANCR_END_LINE || a == ANCR_PREC_READ || a == ANCR_PREC_READ_NOT)
+ return 0;
+
+ return 1;
+}
+
+static int
+is_set_opt_anc_info(OptAnc* to, int anc)
+{
+ if ((to->left & anc) != 0) return 1;
+
+ return ((to->right & anc) != 0 ? 1 : 0);
+}
+
+static void
+add_opt_anc_info(OptAnc* to, int anc)
+{
+ if (is_left(anc))
+ to->left |= anc;
+ else
+ to->right |= anc;
+}
+
+static void
+remove_opt_anc_info(OptAnc* to, int anc)
+{
+ if (is_left(anc))
+ to->left &= ~anc;
+ else
+ to->right &= ~anc;
+}
+
+static void
+alt_merge_opt_anc_info(OptAnc* to, OptAnc* add)
+{
+ to->left &= add->left;
+ to->right &= add->right;
+}
+
+static int
+is_full_opt_exact(OptStr* e)
+{
+ return e->len >= OPT_EXACT_MAXLEN;
+}
+
+static void
+clear_opt_exact(OptStr* e)
+{
+ mml_clear(&e->mm);
+ clear_opt_anc_info(&e->anc);
+ e->reach_end = 0;
+ e->len = 0;
+ e->s[0] = '\0';
+}
+
+static void
+copy_opt_exact(OptStr* to, OptStr* from)
+{
+ *to = *from;
+}
+
+static int
+concat_opt_exact(OptStr* to, OptStr* add, OnigEncoding enc)
+{
+ int i, j, len, r;
+ UChar *p, *end;
+ OptAnc tanc;
+
+ r = 0;
+ p = add->s;
+ end = p + add->len;
+ for (i = to->len; p < end; ) {
+ len = enclen(enc, p);
+ if (i + len > OPT_EXACT_MAXLEN) {
+ r = 1; /* 1:full */
+ break;
+ }
+ for (j = 0; j < len && p < end; j++)
+ to->s[i++] = *p++;
+ }
+
+ to->len = i;
+ to->reach_end = (p == end ? add->reach_end : 0);
+
+ concat_opt_anc_info(&tanc, &to->anc, &add->anc, 1, 1);
+ if (! to->reach_end) tanc.right = 0;
+ copy_opt_anc_info(&to->anc, &tanc);
+
+ return r;
+}
+
+static void
+concat_opt_exact_str(OptStr* to, UChar* s, UChar* end, OnigEncoding enc)
+{
+ int i, j, len;
+ UChar *p;
+
+ for (i = to->len, p = s; p < end && i < OPT_EXACT_MAXLEN; ) {
+ len = enclen(enc, p);
+ if (i + len > OPT_EXACT_MAXLEN) break;
+ for (j = 0; j < len && p < end; j++)
+ to->s[i++] = *p++;
+ }
+
+ to->len = i;
+
+ if (p >= end)
+ to->reach_end = 1;
+}
+
+static void
+alt_merge_opt_exact(OptStr* to, OptStr* add, OptEnv* env)
+{
+ int i, j, len;
+
+ if (add->len == 0 || to->len == 0) {
+ clear_opt_exact(to);
+ return ;
+ }
+
+ if (! mml_is_equal(&to->mm, &add->mm)) {
+ clear_opt_exact(to);
+ return ;
+ }
+
+ for (i = 0; i < to->len && i < add->len; ) {
+ if (to->s[i] != add->s[i]) break;
+ len = enclen(env->enc, to->s + i);
+
+ for (j = 1; j < len; j++) {
+ if (to->s[i+j] != add->s[i+j]) break;
+ }
+ if (j < len) break;
+ i += len;
+ }
+
+ if (! add->reach_end || i < add->len || i < to->len) {
+ to->reach_end = 0;
+ }
+ to->len = i;
+
+ alt_merge_opt_anc_info(&to->anc, &add->anc);
+ if (! to->reach_end) to->anc.right = 0;
+}
+
+static void
+select_opt_exact(OnigEncoding enc, OptStr* now, OptStr* alt)
+{
+ int vn, va;
+
+ vn = now->len;
+ va = alt->len;
+
+ if (va == 0) {
+ return ;
+ }
+ else if (vn == 0) {
+ copy_opt_exact(now, alt);
+ return ;
+ }
+ else if (vn <= 2 && va <= 2) {
+ /* ByteValTable[x] is big value --> low price */
+ va = map_position_value(enc, now->s[0]);
+ vn = map_position_value(enc, alt->s[0]);
+
+ if (now->len > 1) vn += 5;
+ if (alt->len > 1) va += 5;
+ }
+
+ vn *= 2;
+ va *= 2;
+
+ if (comp_distance_value(&now->mm, &alt->mm, vn, va) > 0)
+ copy_opt_exact(now, alt);
+}
+
+static void
+clear_opt_map(OptMap* map)
+{
+ static const OptMap clean_info = {
+ {0, 0}, {0, 0}, 0,
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ };
+
+ xmemcpy(map, &clean_info, sizeof(OptMap));
+}
+
+static void
+copy_opt_map(OptMap* to, OptMap* from)
+{
+ *to = *from;
+}
+
+static void
+add_char_opt_map(OptMap* m, UChar c, OnigEncoding enc)
+{
+ if (m->map[c] == 0) {
+ m->map[c] = 1;
+ m->value += map_position_value(enc, c);
+ }
+}
+
+static void
+select_opt_map(OptMap* now, OptMap* alt)
+{
+ static int z = 1<<15; /* 32768: something big value */
+
+ int vn, va;
+
+ if (alt->value == 0) return ;
+ if (now->value == 0) {
+ copy_opt_map(now, alt);
+ return ;
+ }
+
+ vn = z / now->value;
+ va = z / alt->value;
+ if (comp_distance_value(&now->mm, &alt->mm, vn, va) > 0)
+ copy_opt_map(now, alt);
+}
+
+static int
+comp_opt_exact_or_map(OptStr* e, OptMap* m)
+{
+#define COMP_EM_BASE 20
+ int ae, am;
+ int case_value;
+
+ if (m->value <= 0) return -1;
+
+ case_value = 3;
+ ae = COMP_EM_BASE * e->len * case_value;
+ am = COMP_EM_BASE * 5 * 2 / m->value;
+ return comp_distance_value(&e->mm, &m->mm, ae, am);
+}
+
+static void
+alt_merge_opt_map(OnigEncoding enc, OptMap* to, OptMap* add)
+{
+ int i, val;
+
+ /* if (! mml_is_equal(&to->mm, &add->mm)) return ; */
+ if (to->value == 0) return ;
+ if (add->value == 0 || to->mm.max < add->mm.min) {
+ clear_opt_map(to);
+ return ;
+ }
+
+ mml_alt_merge(&to->mm, &add->mm);
+
+ val = 0;
+ for (i = 0; i < CHAR_MAP_SIZE; i++) {
+ if (add->map[i])
+ to->map[i] = 1;
+
+ if (to->map[i])
+ val += map_position_value(enc, i);
+ }
+ to->value = val;
+
+ alt_merge_opt_anc_info(&to->anc, &add->anc);
+}
+
+static void
+set_bound_node_opt_info(OptNode* opt, MinMaxLen* plen)
+{
+ mml_copy(&(opt->sb.mm), plen);
+ mml_copy(&(opt->spr.mm), plen);
+ mml_copy(&(opt->map.mm), plen);
+}
+
+static void
+clear_node_opt_info(OptNode* opt)
+{
+ mml_clear(&opt->len);
+ clear_opt_anc_info(&opt->anc);
+ clear_opt_exact(&opt->sb);
+ clear_opt_exact(&opt->sm);
+ clear_opt_exact(&opt->spr);
+ clear_opt_map(&opt->map);
+}
+
+static void
+copy_node_opt_info(OptNode* to, OptNode* from)
+{
+ *to = *from;
+}
+
+static void
+concat_left_node_opt_info(OnigEncoding enc, OptNode* to, OptNode* add)
+{
+ int sb_reach, sm_reach;
+ OptAnc tanc;
+
+ concat_opt_anc_info(&tanc, &to->anc, &add->anc, to->len.max, add->len.max);
+ copy_opt_anc_info(&to->anc, &tanc);
+
+ if (add->sb.len > 0 && to->len.max == 0) {
+ concat_opt_anc_info(&tanc, &to->anc, &add->sb.anc, to->len.max, add->len.max);
+ copy_opt_anc_info(&add->sb.anc, &tanc);
+ }
+
+ if (add->map.value > 0 && to->len.max == 0) {
+ if (add->map.mm.max == 0)
+ add->map.anc.left |= to->anc.left;
+ }
+
+ sb_reach = to->sb.reach_end;
+ sm_reach = to->sm.reach_end;
+
+ if (add->len.max != 0)
+ to->sb.reach_end = to->sm.reach_end = 0;
+
+ if (add->sb.len > 0) {
+ if (sb_reach) {
+ concat_opt_exact(&to->sb, &add->sb, enc);
+ clear_opt_exact(&add->sb);
+ }
+ else if (sm_reach) {
+ concat_opt_exact(&to->sm, &add->sb, enc);
+ clear_opt_exact(&add->sb);
+ }
+ }
+ select_opt_exact(enc, &to->sm, &add->sb);
+ select_opt_exact(enc, &to->sm, &add->sm);
+
+ if (to->spr.len > 0) {
+ if (add->len.max > 0) {
+ if (to->spr.mm.max == 0)
+ select_opt_exact(enc, &to->sb, &to->spr);
+ else
+ select_opt_exact(enc, &to->sm, &to->spr);
+ }
+ }
+ else if (add->spr.len > 0) {
+ copy_opt_exact(&to->spr, &add->spr);
+ }
+
+ select_opt_map(&to->map, &add->map);
+ mml_add(&to->len, &add->len);
+}
+
+static void
+alt_merge_node_opt_info(OptNode* to, OptNode* add, OptEnv* env)
+{
+ alt_merge_opt_anc_info(&to->anc, &add->anc);
+ alt_merge_opt_exact(&to->sb, &add->sb, env);
+ alt_merge_opt_exact(&to->sm, &add->sm, env);
+ alt_merge_opt_exact(&to->spr, &add->spr, env);
+ alt_merge_opt_map(env->enc, &to->map, &add->map);
+
+ mml_alt_merge(&to->len, &add->len);
+}
+
+
+#define MAX_NODE_OPT_INFO_REF_COUNT 5
+
+static int
+optimize_nodes(Node* node, OptNode* opt, OptEnv* env)
+{
+ int i;
+ int r;
+ OptNode xo;
+ OnigEncoding enc;
+
+ r = 0;
+ enc = env->enc;
+ clear_node_opt_info(opt);
+ set_bound_node_opt_info(opt, &env->mm);
+
+ switch (NODE_TYPE(node)) {
+ case NODE_LIST:
+ {
+ OptEnv nenv;
+ Node* nd = node;
+
+ copy_opt_env(&nenv, env);
+ do {
+ r = optimize_nodes(NODE_CAR(nd), &xo, &nenv);
+ if (r == 0) {
+ mml_add(&nenv.mm, &xo.len);
+ concat_left_node_opt_info(enc, opt, &xo);
+ }
+ } while (r == 0 && IS_NOT_NULL(nd = NODE_CDR(nd)));
+ }
+ break;
+
+ case NODE_ALT:
+ {
+ Node* nd = node;
+
+ do {
+ r = optimize_nodes(NODE_CAR(nd), &xo, env);
+ if (r == 0) {
+ if (nd == node) copy_node_opt_info(opt, &xo);
+ else alt_merge_node_opt_info(opt, &xo, env);
+ }
+ } while ((r == 0) && IS_NOT_NULL(nd = NODE_CDR(nd)));
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ StrNode* sn = STR_(node);
+ int slen = (int )(sn->end - sn->s);
+
+ concat_opt_exact_str(&opt->sb, sn->s, sn->end, enc);
+ if (slen > 0) {
+ add_char_opt_map(&opt->map, *(sn->s), enc);
+ }
+ mml_set_min_max(&opt->len, slen, slen);
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ int z;
+ CClassNode* cc = CCLASS_(node);
+
+ /* no need to check ignore case. (set in tune_tree()) */
+
+ if (IS_NOT_NULL(cc->mbuf) || IS_NCCLASS_NOT(cc)) {
+ OnigLen min = ONIGENC_MBC_MINLEN(enc);
+ OnigLen max = ONIGENC_MBC_MAXLEN_DIST(enc);
+
+ mml_set_min_max(&opt->len, min, max);
+ }
+ else {
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ z = BITSET_AT(cc->bs, i);
+ if ((z && ! IS_NCCLASS_NOT(cc)) || (! z && IS_NCCLASS_NOT(cc))) {
+ add_char_opt_map(&opt->map, (UChar )i, enc);
+ }
+ }
+ mml_set_min_max(&opt->len, 1, 1);
+ }
+ }
+ break;
+
+ case NODE_CTYPE:
+ {
+ int min, max;
+ int range;
+
+ max = ONIGENC_MBC_MAXLEN_DIST(enc);
+
+ if (max == 1) {
+ min = 1;
+
+ switch (CTYPE_(node)->ctype) {
+ case CTYPE_ANYCHAR:
+ break;
+
+ case ONIGENC_CTYPE_WORD:
+ range = CTYPE_(node)->ascii_mode != 0 ? 128 : SINGLE_BYTE_SIZE;
+ if (CTYPE_(node)->not != 0) {
+ for (i = 0; i < range; i++) {
+ if (! ONIGENC_IS_CODE_WORD(enc, i)) {
+ add_char_opt_map(&opt->map, (UChar )i, enc);
+ }
+ }
+ for (i = range; i < SINGLE_BYTE_SIZE; i++) {
+ add_char_opt_map(&opt->map, (UChar )i, enc);
+ }
+ }
+ else {
+ for (i = 0; i < range; i++) {
+ if (ONIGENC_IS_CODE_WORD(enc, i)) {
+ add_char_opt_map(&opt->map, (UChar )i, enc);
+ }
+ }
+ }
+ break;
+ }
+ }
+ else {
+ min = ONIGENC_MBC_MINLEN(enc);
+ }
+ mml_set_min_max(&opt->len, min, max);
+ }
+ break;
+
+ case NODE_ANCHOR:
+ switch (ANCHOR_(node)->type) {
+ case ANCR_BEGIN_BUF:
+ case ANCR_BEGIN_POSITION:
+ case ANCR_BEGIN_LINE:
+ case ANCR_END_BUF:
+ case ANCR_SEMI_END_BUF:
+ case ANCR_END_LINE:
+ case ANCR_PREC_READ_NOT:
+ case ANCR_LOOK_BEHIND:
+ add_opt_anc_info(&opt->anc, ANCHOR_(node)->type);
+ break;
+
+ case ANCR_PREC_READ:
+ {
+ r = optimize_nodes(NODE_BODY(node), &xo, env);
+ if (r == 0) {
+ if (xo.sb.len > 0)
+ copy_opt_exact(&opt->spr, &xo.sb);
+ else if (xo.sm.len > 0)
+ copy_opt_exact(&opt->spr, &xo.sm);
+
+ opt->spr.reach_end = 0;
+
+ if (xo.map.value > 0)
+ copy_opt_map(&opt->map, &xo.map);
+ }
+ }
+ break;
+
+ case ANCR_LOOK_BEHIND_NOT:
+ break;
+ }
+ break;
+
+ case NODE_BACKREF:
+ if (! NODE_IS_CHECKER(node)) {
+ OnigLen min, max;
+
+ min = node_min_byte_len(node, env->scan_env);
+ max = node_max_byte_len(node, env->scan_env);
+ mml_set_min_max(&opt->len, min, max);
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ if (NODE_IS_RECURSION(node))
+ mml_set_min_max(&opt->len, 0, INFINITE_LEN);
+ else {
+ r = optimize_nodes(NODE_BODY(node), opt, env);
+ }
+ break;
+#endif
+
+ case NODE_QUANT:
+ {
+ OnigLen min, max;
+ QuantNode* qn = QUANT_(node);
+
+ /* Issue #175
+ ex. /\g<1>{0}(?<=|())/
+
+ Empty and unused nodes in look-behind is removed in
+ tune_look_behind().
+ Called group nodes are assigned to be not called if the caller side is
+ inside of zero-repetition.
+ As a result, the nodes are considered unused.
+ */
+ if (qn->upper == 0) {
+ mml_set_min_max(&opt->len, 0, 0);
+ break;
+ }
+
+ r = optimize_nodes(NODE_BODY(node), &xo, env);
+ if (r != 0) break;
+
+ if (qn->lower > 0) {
+ copy_node_opt_info(opt, &xo);
+ if (xo.sb.len > 0) {
+ if (xo.sb.reach_end) {
+ for (i = 2; i <= qn->lower && ! is_full_opt_exact(&opt->sb); i++) {
+ int rc = concat_opt_exact(&opt->sb, &xo.sb, enc);
+ if (rc > 0) break;
+ }
+ if (i < qn->lower) opt->sb.reach_end = 0;
+ }
+ }
+
+ if (qn->lower != qn->upper) {
+ opt->sb.reach_end = 0;
+ opt->sm.reach_end = 0;
+ }
+ if (qn->lower > 1)
+ opt->sm.reach_end = 0;
+ }
+
+ if (IS_INFINITE_REPEAT(qn->upper)) {
+ if (env->mm.max == 0 &&
+ NODE_IS_ANYCHAR(NODE_BODY(node)) && qn->greedy != 0) {
+ if (NODE_IS_MULTILINE(NODE_QUANT_BODY(qn)))
+ add_opt_anc_info(&opt->anc, ANCR_ANYCHAR_INF_ML);
+ else
+ add_opt_anc_info(&opt->anc, ANCR_ANYCHAR_INF);
+ }
+
+ max = (xo.len.max > 0 ? INFINITE_LEN : 0);
+ }
+ else {
+ max = distance_multiply(xo.len.max, qn->upper);
+ }
+
+ min = distance_multiply(xo.len.min, qn->lower);
+ mml_set_min_max(&opt->len, min, max);
+ }
+ break;
+
+ case NODE_BAG:
+ {
+ BagNode* en = BAG_(node);
+
+ switch (en->type) {
+ case BAG_STOP_BACKTRACK:
+ case BAG_OPTION:
+ r = optimize_nodes(NODE_BODY(node), opt, env);
+ break;
+
+ case BAG_MEMORY:
+#ifdef USE_CALL
+ en->opt_count++;
+ if (en->opt_count > MAX_NODE_OPT_INFO_REF_COUNT) {
+ OnigLen min, max;
+
+ min = 0;
+ max = INFINITE_LEN;
+ if (NODE_IS_FIXED_MIN(node)) min = en->min_len;
+ if (NODE_IS_FIXED_MAX(node)) max = en->max_len;
+ mml_set_min_max(&opt->len, min, max);
+ }
+ else
+#endif
+ {
+ r = optimize_nodes(NODE_BODY(node), opt, env);
+ if (is_set_opt_anc_info(&opt->anc, ANCR_ANYCHAR_INF_MASK)) {
+ if (MEM_STATUS_AT0(env->scan_env->backrefed_mem, en->m.regnum))
+ remove_opt_anc_info(&opt->anc, ANCR_ANYCHAR_INF_MASK);
+ }
+ }
+ break;
+
+ case BAG_IF_ELSE:
+ {
+ OptEnv nenv;
+
+ copy_opt_env(&nenv, env);
+ r = optimize_nodes(NODE_BAG_BODY(en), &xo, &nenv);
+ if (r == 0) {
+ mml_add(&nenv.mm, &xo.len);
+ concat_left_node_opt_info(enc, opt, &xo);
+ if (IS_NOT_NULL(en->te.Then)) {
+ r = optimize_nodes(en->te.Then, &xo, &nenv);
+ if (r == 0) {
+ concat_left_node_opt_info(enc, opt, &xo);
+ }
+ }
+
+ if (IS_NOT_NULL(en->te.Else)) {
+ r = optimize_nodes(en->te.Else, &xo, env);
+ if (r == 0)
+ alt_merge_node_opt_info(opt, &xo, env);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case NODE_GIMMICK:
+ break;
+
+ default:
+#ifdef ONIG_DEBUG
+ fprintf(DBGFP, "optimize_nodes: undefined node type %d\n", NODE_TYPE(node));
+#endif
+ r = ONIGERR_TYPE_BUG;
+ break;
+ }
+
+ return r;
+}
+
+static int
+set_optimize_exact(regex_t* reg, OptStr* e)
+{
+ int r;
+ int allow_reverse;
+
+ if (e->len == 0) return 0;
+
+ reg->exact = (UChar* )xmalloc(e->len);
+ CHECK_NULL_RETURN_MEMERR(reg->exact);
+ xmemcpy(reg->exact, e->s, e->len);
+ reg->exact_end = reg->exact + e->len;
+
+ allow_reverse =
+ ONIGENC_IS_ALLOWED_REVERSE_MATCH(reg->enc, reg->exact, reg->exact_end);
+
+ if (e->len >= 2 || (e->len >= 1 && allow_reverse)) {
+ r = set_sunday_quick_search_or_bmh_skip_table(reg, 0,
+ reg->exact, reg->exact_end,
+ reg->map, &(reg->map_offset));
+ if (r != 0) return r;
+
+ reg->optimize = (allow_reverse != 0
+ ? OPTIMIZE_STR_FAST
+ : OPTIMIZE_STR_FAST_STEP_FORWARD);
+ }
+ else {
+ reg->optimize = OPTIMIZE_STR;
+ }
+
+ reg->dist_min = e->mm.min;
+ reg->dist_max = e->mm.max;
+
+ if (reg->dist_min != INFINITE_LEN) {
+ int n = (int )(reg->exact_end - reg->exact);
+ reg->threshold_len = reg->dist_min + n;
+ }
+
+ return 0;
+}
+
+static void
+set_optimize_map(regex_t* reg, OptMap* m)
+{
+ int i;
+
+ for (i = 0; i < CHAR_MAP_SIZE; i++)
+ reg->map[i] = m->map[i];
+
+ reg->optimize = OPTIMIZE_MAP;
+ reg->dist_min = m->mm.min;
+ reg->dist_max = m->mm.max;
+
+ if (reg->dist_min != INFINITE_LEN) {
+ reg->threshold_len = reg->dist_min + ONIGENC_MBC_MINLEN(reg->enc);
+ }
+}
+
+static void
+set_sub_anchor(regex_t* reg, OptAnc* anc)
+{
+ reg->sub_anchor |= anc->left & ANCR_BEGIN_LINE;
+ reg->sub_anchor |= anc->right & ANCR_END_LINE;
+}
+
+#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH)
+static void print_optimize_info(FILE* f, regex_t* reg);
+#endif
+
+static int
+set_optimize_info_from_tree(Node* node, regex_t* reg, ScanEnv* scan_env)
+{
+ int r;
+ OptNode opt;
+ OptEnv env;
+
+ env.enc = reg->enc;
+ env.case_fold_flag = reg->case_fold_flag;
+ env.scan_env = scan_env;
+ mml_clear(&env.mm);
+
+ r = optimize_nodes(node, &opt, &env);
+ if (r != 0) return r;
+
+ reg->anchor = opt.anc.left & (ANCR_BEGIN_BUF |
+ ANCR_BEGIN_POSITION | ANCR_ANYCHAR_INF | ANCR_ANYCHAR_INF_ML |
+ ANCR_LOOK_BEHIND);
+
+ if ((opt.anc.left & (ANCR_LOOK_BEHIND | ANCR_PREC_READ_NOT)) != 0)
+ reg->anchor &= ~ANCR_ANYCHAR_INF_ML;
+
+ reg->anchor |= opt.anc.right & (ANCR_END_BUF | ANCR_SEMI_END_BUF |
+ ANCR_PREC_READ_NOT);
+
+ if (reg->anchor & (ANCR_END_BUF | ANCR_SEMI_END_BUF)) {
+ reg->anc_dist_min = opt.len.min;
+ reg->anc_dist_max = opt.len.max;
+ }
+
+ if (opt.sb.len > 0 || opt.sm.len > 0) {
+ select_opt_exact(reg->enc, &opt.sb, &opt.sm);
+ if (opt.map.value > 0 && comp_opt_exact_or_map(&opt.sb, &opt.map) > 0) {
+ goto set_map;
+ }
+ else {
+ r = set_optimize_exact(reg, &opt.sb);
+ set_sub_anchor(reg, &opt.sb.anc);
+ }
+ }
+ else if (opt.map.value > 0) {
+ set_map:
+ set_optimize_map(reg, &opt.map);
+ set_sub_anchor(reg, &opt.map.anc);
+ }
+ else {
+ reg->sub_anchor |= opt.anc.left & ANCR_BEGIN_LINE;
+ if (opt.len.max == 0)
+ reg->sub_anchor |= opt.anc.right & ANCR_END_LINE;
+ }
+
+#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH)
+ print_optimize_info(DBGFP, reg);
+#endif
+ return r;
+}
+
+static void
+clear_optimize_info(regex_t* reg)
+{
+ reg->optimize = OPTIMIZE_NONE;
+ reg->anchor = 0;
+ reg->anc_dist_min = 0;
+ reg->anc_dist_max = 0;
+ reg->sub_anchor = 0;
+ reg->exact_end = (UChar* )NULL;
+ reg->map_offset = 0;
+ reg->threshold_len = 0;
+ if (IS_NOT_NULL(reg->exact)) {
+ xfree(reg->exact);
+ reg->exact = (UChar* )NULL;
+ }
+}
+
+#ifdef ONIG_DEBUG
+
+static void print_enc_string(FILE* fp, OnigEncoding enc,
+ const UChar *s, const UChar *end)
+{
+ if (ONIGENC_MBC_MINLEN(enc) > 1) {
+ const UChar *p;
+ OnigCodePoint code;
+
+ p = s;
+ while (p < end) {
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ if (code >= 0x80) {
+ fprintf(fp, " 0x%04x ", (int )code);
+ }
+ else {
+ fputc((int )code, fp);
+ }
+
+ p += enclen(enc, p);
+ }
+ }
+ else {
+ while (s < end) {
+ fputc((int )*s, fp);
+ s++;
+ }
+ }
+
+ fprintf(fp, "/\n");
+}
+
+#endif /* ONIG_DEBUG */
+
+#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH)
+
+static void
+print_distance_range(FILE* f, OnigLen a, OnigLen b)
+{
+ if (a == INFINITE_LEN)
+ fputs("inf", f);
+ else
+ fprintf(f, "(%u)", a);
+
+ fputs("-", f);
+
+ if (b == INFINITE_LEN)
+ fputs("inf", f);
+ else
+ fprintf(f, "(%u)", b);
+}
+
+static void
+print_anchor(FILE* f, int anchor)
+{
+ int q = 0;
+
+ fprintf(f, "[");
+
+ if (anchor & ANCR_BEGIN_BUF) {
+ fprintf(f, "begin-buf");
+ q = 1;
+ }
+ if (anchor & ANCR_BEGIN_LINE) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "begin-line");
+ }
+ if (anchor & ANCR_BEGIN_POSITION) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "begin-pos");
+ }
+ if (anchor & ANCR_END_BUF) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "end-buf");
+ }
+ if (anchor & ANCR_SEMI_END_BUF) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "semi-end-buf");
+ }
+ if (anchor & ANCR_END_LINE) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "end-line");
+ }
+ if (anchor & ANCR_ANYCHAR_INF) {
+ if (q) fprintf(f, ", ");
+ q = 1;
+ fprintf(f, "anychar-inf");
+ }
+ if (anchor & ANCR_ANYCHAR_INF_ML) {
+ if (q) fprintf(f, ", ");
+ fprintf(f, "anychar-inf-ml");
+ }
+
+ fprintf(f, "]");
+}
+
+static void
+print_optimize_info(FILE* f, regex_t* reg)
+{
+ static const char* on[] =
+ { "NONE", "STR", "STR_FAST", "STR_FAST_STEP_FORWARD", "MAP" };
+
+ fprintf(f, "optimize: %s\n", on[reg->optimize]);
+ fprintf(f, " anchor: "); print_anchor(f, reg->anchor);
+ if ((reg->anchor & ANCR_END_BUF_MASK) != 0)
+ print_distance_range(f, reg->anc_dist_min, reg->anc_dist_max);
+ fprintf(f, "\n");
+
+ if (reg->optimize) {
+ fprintf(f, " sub anchor: "); print_anchor(f, reg->sub_anchor);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n");
+
+ if (reg->exact) {
+ UChar *p;
+ fprintf(f, "exact: [");
+ for (p = reg->exact; p < reg->exact_end; p++) {
+ fputc(*p, f);
+ }
+ fprintf(f, "]: length: %ld, dmin: %u, dmax: %u\n",
+ (reg->exact_end - reg->exact), reg->dist_min, reg->dist_max);
+ }
+ else if (reg->optimize & OPTIMIZE_MAP) {
+ int c, i, n = 0;
+
+ for (i = 0; i < CHAR_MAP_SIZE; i++)
+ if (reg->map[i]) n++;
+
+ fprintf(f, "map: n=%d, dmin: %u, dmax: %u\n",
+ n, reg->dist_min, reg->dist_max);
+ if (n > 0) {
+ c = 0;
+ fputc('[', f);
+ for (i = 0; i < CHAR_MAP_SIZE; i++) {
+ if (reg->map[i] != 0) {
+ if (c > 0) fputs(", ", f);
+ c++;
+ if (ONIGENC_MBC_MAXLEN(reg->enc) == 1 &&
+ ONIGENC_IS_CODE_PRINT(reg->enc, (OnigCodePoint )i))
+ fputc(i, f);
+ else
+ fprintf(f, "%d", i);
+ }
+ }
+ fprintf(f, "]\n");
+ }
+ }
+}
+#endif
+
+
+extern RegexExt*
+onig_get_regex_ext(regex_t* reg)
+{
+ if (IS_NULL(reg->extp)) {
+ RegexExt* ext = (RegexExt* )xmalloc(sizeof(*ext));
+ if (IS_NULL(ext)) return 0;
+
+ ext->pattern = 0;
+ ext->pattern_end = 0;
+#ifdef USE_CALLOUT
+ ext->tag_table = 0;
+ ext->callout_num = 0;
+ ext->callout_list_alloc = 0;
+ ext->callout_list = 0;
+#endif
+
+ reg->extp = ext;
+ }
+
+ return reg->extp;
+}
+
+static void
+free_regex_ext(RegexExt* ext)
+{
+ if (IS_NOT_NULL(ext)) {
+ if (IS_NOT_NULL(ext->pattern))
+ xfree((void* )ext->pattern);
+
+#ifdef USE_CALLOUT
+ if (IS_NOT_NULL(ext->tag_table))
+ onig_callout_tag_table_free(ext->tag_table);
+
+ if (IS_NOT_NULL(ext->callout_list))
+ onig_free_reg_callout_list(ext->callout_num, ext->callout_list);
+#endif
+
+ xfree(ext);
+ }
+}
+
+extern int
+onig_ext_set_pattern(regex_t* reg, const UChar* pattern, const UChar* pattern_end)
+{
+ RegexExt* ext;
+ UChar* s;
+
+ ext = onig_get_regex_ext(reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+
+ s = onigenc_strdup(reg->enc, pattern, pattern_end);
+ CHECK_NULL_RETURN_MEMERR(s);
+
+ ext->pattern = s;
+ ext->pattern_end = s + (pattern_end - pattern);
+
+ return ONIG_NORMAL;
+}
+
+extern void
+onig_free_body(regex_t* reg)
+{
+ if (IS_NOT_NULL(reg)) {
+ ops_free(reg);
+ if (IS_NOT_NULL(reg->string_pool)) {
+ xfree(reg->string_pool);
+ reg->string_pool_end = reg->string_pool = 0;
+ }
+ if (IS_NOT_NULL(reg->exact)) xfree(reg->exact);
+ if (IS_NOT_NULL(reg->repeat_range)) xfree(reg->repeat_range);
+ if (IS_NOT_NULL(reg->extp)) {
+ free_regex_ext(reg->extp);
+ reg->extp = 0;
+ }
+
+ onig_names_free(reg);
+ }
+}
+
+extern void
+onig_free(regex_t* reg)
+{
+ if (IS_NOT_NULL(reg)) {
+ onig_free_body(reg);
+ xfree(reg);
+ }
+}
+
+
+#ifdef ONIG_DEBUG_PARSE
+static void print_tree P_((FILE* f, Node* node));
+#endif
+
+extern int onig_init_for_match_at(regex_t* reg);
+
+extern int
+onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
+ OnigErrorInfo* einfo)
+{
+ int r;
+ Node* root;
+ ScanEnv scan_env;
+#ifdef USE_CALL
+ UnsetAddrList uslist = {0};
+#endif
+
+ root = 0;
+ if (IS_NOT_NULL(einfo)) {
+ einfo->enc = reg->enc;
+ einfo->par = (UChar* )NULL;
+ }
+
+#ifdef ONIG_DEBUG
+ fprintf(DBGFP, "\nPATTERN: /");
+ print_enc_string(DBGFP, reg->enc, pattern, pattern_end);
+#endif
+
+ if (reg->ops_alloc == 0) {
+ r = ops_init(reg, OPS_INIT_SIZE);
+ if (r != 0) goto end;
+ }
+ else
+ reg->ops_used = 0;
+
+ reg->string_pool = 0;
+ reg->string_pool_end = 0;
+ reg->num_mem = 0;
+ reg->num_repeat = 0;
+ reg->num_empty_check = 0;
+ reg->repeat_range_alloc = 0;
+ reg->repeat_range = (RepeatRange* )NULL;
+ reg->empty_status_mem = 0;
+
+ r = onig_parse_tree(&root, pattern, pattern_end, reg, &scan_env);
+ if (r != 0) goto err;
+
+ r = reduce_string_list(root);
+ if (r != 0) goto err;
+
+ /* mixed use named group and no-named group */
+ if (scan_env.num_named > 0 &&
+ IS_SYNTAX_BV(scan_env.syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
+ ! OPTON_CAPTURE_GROUP(reg->options)) {
+ if (scan_env.num_named != scan_env.num_mem)
+ r = disable_noname_group_capture(&root, reg, &scan_env);
+ else
+ r = numbered_ref_check(root);
+
+ if (r != 0) goto err;
+ }
+
+ r = check_backrefs(root, &scan_env);
+ if (r != 0) goto err;
+
+#ifdef USE_CALL
+ if (scan_env.num_call > 0) {
+ r = unset_addr_list_init(&uslist, scan_env.num_call);
+ if (r != 0) goto err;
+ scan_env.unset_addr_list = &uslist;
+ r = tune_call(root, &scan_env, 0);
+ if (r != 0) goto err_unset;
+ r = tune_call2(root);
+ if (r != 0) goto err_unset;
+ r = recursive_call_check_trav(root, &scan_env, 0);
+ if (r < 0) goto err_unset;
+ r = infinite_recursive_call_check_trav(root, &scan_env);
+ if (r != 0) goto err_unset;
+
+ tune_called_state(root, 0);
+ }
+
+ reg->num_call = scan_env.num_call;
+#endif
+
+#ifdef ONIG_DEBUG_PARSE
+ fprintf(DBGFP, "MAX PARSE DEPTH: %d\n", scan_env.max_parse_depth);
+ fprintf(DBGFP, "TREE (parsed)\n");
+ print_tree(DBGFP, root);
+ fprintf(DBGFP, "\n");
+#endif
+
+ r = tune_tree(root, reg, 0, &scan_env);
+ if (r != 0) goto err_unset;
+
+ if (scan_env.backref_num != 0) {
+ set_parent_node_trav(root, NULL_NODE);
+ r = set_empty_repeat_node_trav(root, NULL_NODE, &scan_env);
+ if (r != 0) goto err_unset;
+ set_empty_status_check_trav(root, &scan_env);
+ }
+
+#ifdef ONIG_DEBUG_PARSE
+ fprintf(DBGFP, "TREE (after tune)\n");
+ print_tree(DBGFP, root);
+ fprintf(DBGFP, "\n");
+#endif
+
+ reg->capture_history = scan_env.cap_history;
+ reg->push_mem_start = scan_env.backtrack_mem | scan_env.cap_history;
+
+#ifdef USE_CALLOUT
+ if (IS_NOT_NULL(reg->extp) && reg->extp->callout_num != 0) {
+ reg->push_mem_end = reg->push_mem_start;
+ }
+ else {
+ if (MEM_STATUS_IS_ALL_ON(reg->push_mem_start))
+ reg->push_mem_end = scan_env.backrefed_mem | scan_env.cap_history;
+ else
+ reg->push_mem_end = reg->push_mem_start &
+ (scan_env.backrefed_mem | scan_env.cap_history);
+ }
+#else
+ if (MEM_STATUS_IS_ALL_ON(reg->push_mem_start))
+ reg->push_mem_end = scan_env.backrefed_mem | scan_env.cap_history;
+ else
+ reg->push_mem_end = reg->push_mem_start &
+ (scan_env.backrefed_mem | scan_env.cap_history);
+#endif
+
+ clear_optimize_info(reg);
+#ifndef ONIG_DONT_OPTIMIZE
+ r = set_optimize_info_from_tree(root, reg, &scan_env);
+ if (r != 0) goto err_unset;
+#endif
+
+ if (IS_NOT_NULL(scan_env.mem_env_dynamic)) {
+ xfree(scan_env.mem_env_dynamic);
+ scan_env.mem_env_dynamic = (MemEnv* )NULL;
+ }
+
+ r = compile_tree(root, reg, &scan_env);
+ if (r == 0) {
+ if (scan_env.keep_num > 0) {
+ r = add_op(reg, OP_UPDATE_VAR);
+ if (r != 0) goto err;
+
+ COP(reg)->update_var.type = UPDATE_VAR_KEEP_FROM_STACK_LAST;
+ COP(reg)->update_var.id = 0; /* not used */
+ COP(reg)->update_var.clear = FALSE;
+ }
+
+ r = add_op(reg, OP_END);
+ if (r != 0) goto err;
+
+#ifdef USE_CALL
+ if (scan_env.num_call > 0) {
+ r = fix_unset_addr_list(&uslist, reg);
+ unset_addr_list_end(&uslist);
+ if (r != 0) goto err;
+ }
+#endif
+
+ set_addr_in_repeat_range(reg);
+
+ if ((reg->push_mem_end != 0)
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+ || (reg->num_repeat != 0)
+ || (reg->num_empty_check != 0)
+#endif
+#ifdef USE_CALLOUT
+ || (IS_NOT_NULL(reg->extp) && reg->extp->callout_num != 0)
+#endif
+#ifdef USE_CALL
+ || scan_env.num_call > 0
+#endif
+ )
+ reg->stack_pop_level = STACK_POP_LEVEL_ALL;
+ else {
+ if (reg->push_mem_start != 0)
+ reg->stack_pop_level = STACK_POP_LEVEL_MEM_START;
+ else
+ reg->stack_pop_level = STACK_POP_LEVEL_FREE;
+ }
+
+ r = ops_make_string_pool(reg);
+ if (r != 0) goto err;
+ }
+#ifdef USE_CALL
+ else if (scan_env.num_call > 0) {
+ unset_addr_list_end(&uslist);
+ }
+#endif
+ onig_node_free(root);
+
+#ifdef ONIG_DEBUG_COMPILE
+ onig_print_names(DBGFP, reg);
+ onig_print_compiled_byte_code_list(DBGFP, reg);
+#endif
+
+#ifdef USE_DIRECT_THREADED_CODE
+ /* opcode -> opaddr */
+ onig_init_for_match_at(reg);
+#endif
+
+ end:
+ return r;
+
+ err_unset:
+#ifdef USE_CALL
+ if (scan_env.num_call > 0) {
+ unset_addr_list_end(&uslist);
+ }
+#endif
+ err:
+ if (IS_NOT_NULL(scan_env.error)) {
+ if (IS_NOT_NULL(einfo)) {
+ einfo->par = scan_env.error;
+ einfo->par_end = scan_env.error_end;
+ }
+ }
+
+ onig_node_free(root);
+ if (IS_NOT_NULL(scan_env.mem_env_dynamic))
+ xfree(scan_env.mem_env_dynamic);
+ return r;
+}
+
+
+static int onig_inited = 0;
+
+extern int
+onig_reg_init(regex_t* reg, OnigOptionType option, OnigCaseFoldType case_fold_flag,
+ OnigEncoding enc, OnigSyntaxType* syntax)
+{
+ int r;
+
+ xmemset(reg, 0, sizeof(*reg));
+
+ if (onig_inited == 0) {
+#if 0
+ return ONIGERR_LIBRARY_IS_NOT_INITIALIZED;
+#else
+ r = onig_initialize(&enc, 1);
+ if (r != 0)
+ return ONIGERR_FAIL_TO_INITIALIZE;
+
+ onig_warning("You didn't call onig_initialize() explicitly");
+#endif
+ }
+
+ if (IS_NULL(reg))
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (ONIGENC_IS_UNDEF(enc))
+ return ONIGERR_DEFAULT_ENCODING_IS_NOT_SETTED;
+
+ if ((option & (ONIG_OPTION_DONT_CAPTURE_GROUP|ONIG_OPTION_CAPTURE_GROUP))
+ == (ONIG_OPTION_DONT_CAPTURE_GROUP|ONIG_OPTION_CAPTURE_GROUP)) {
+ return ONIGERR_INVALID_COMBINATION_OF_OPTIONS;
+ }
+
+ if ((option & ONIG_OPTION_NEGATE_SINGLELINE) != 0) {
+ option |= syntax->options;
+ option &= ~ONIG_OPTION_SINGLELINE;
+ }
+ else
+ option |= syntax->options;
+
+ (reg)->enc = enc;
+ (reg)->options = option;
+ (reg)->syntax = syntax;
+ (reg)->optimize = 0;
+ (reg)->exact = (UChar* )NULL;
+ (reg)->extp = (RegexExt* )NULL;
+ (reg)->ops = (Operation* )NULL;
+ (reg)->ops_curr = (Operation* )NULL;
+ (reg)->ops_used = 0;
+ (reg)->ops_alloc = 0;
+ (reg)->name_table = (void* )NULL;
+ (reg)->case_fold_flag = case_fold_flag;
+ return 0;
+}
+
+extern int
+onig_new_without_alloc(regex_t* reg,
+ const UChar* pattern, const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc,
+ OnigSyntaxType* syntax, OnigErrorInfo* einfo)
+{
+ int r;
+
+ r = onig_reg_init(reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax);
+ if (r != 0) return r;
+
+ r = onig_compile(reg, pattern, pattern_end, einfo);
+ return r;
+}
+
+extern int
+onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax,
+ OnigErrorInfo* einfo)
+{
+ int r;
+
+ *reg = (regex_t* )xmalloc(sizeof(regex_t));
+ if (IS_NULL(*reg)) return ONIGERR_MEMORY;
+
+ r = onig_reg_init(*reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax);
+ if (r != 0) {
+ xfree(*reg);
+ *reg = NULL;
+ return r;
+ }
+
+ r = onig_compile(*reg, pattern, pattern_end, einfo);
+ if (r != 0) {
+ onig_free(*reg);
+ *reg = NULL;
+ }
+ return r;
+}
+
+extern int
+onig_initialize(OnigEncoding encodings[], int n)
+{
+ int i;
+ int r;
+
+ if (onig_inited != 0)
+ return 0;
+
+ onigenc_init();
+
+ onig_inited = 1;
+
+ for (i = 0; i < n; i++) {
+ OnigEncoding enc = encodings[i];
+ r = onig_initialize_encoding(enc);
+ if (r != 0)
+ return r;
+ }
+
+ return ONIG_NORMAL;
+}
+
+typedef struct EndCallListItem {
+ struct EndCallListItem* next;
+ void (*func)(void);
+} EndCallListItemType;
+
+static EndCallListItemType* EndCallTop;
+
+extern void onig_add_end_call(void (*func)(void))
+{
+ EndCallListItemType* item;
+
+ item = (EndCallListItemType* )xmalloc(sizeof(*item));
+ if (item == 0) return ;
+
+ item->next = EndCallTop;
+ item->func = func;
+
+ EndCallTop = item;
+}
+
+static void
+exec_end_call_list(void)
+{
+ EndCallListItemType* prev;
+ void (*func)(void);
+
+ while (EndCallTop != 0) {
+ func = EndCallTop->func;
+ (*func)();
+
+ prev = EndCallTop;
+ EndCallTop = EndCallTop->next;
+ xfree(prev);
+ }
+}
+
+extern int
+onig_end(void)
+{
+ exec_end_call_list();
+
+#ifdef USE_CALLOUT
+ onig_global_callout_names_free();
+#endif
+
+ onigenc_end();
+
+ onig_inited = 0;
+
+ return 0;
+}
+
+extern int
+onig_is_in_code_range(const UChar* p, OnigCodePoint code)
+{
+ OnigCodePoint n, *data;
+ OnigCodePoint low, high, x;
+
+ GET_CODE_POINT(n, p);
+ data = (OnigCodePoint* )p;
+ data++;
+
+ for (low = 0, high = n; low < high; ) {
+ x = (low + high) >> 1;
+ if (code > data[x * 2 + 1])
+ low = x + 1;
+ else
+ high = x;
+ }
+
+ return ((low < n && code >= data[low * 2]) ? 1 : 0);
+}
+
+extern int
+onig_is_code_in_cc_len(int elen, OnigCodePoint code, /* CClassNode* */ void* cc_arg)
+{
+ int found;
+ CClassNode* cc = (CClassNode* )cc_arg;
+
+ if (elen > 1 || (code >= SINGLE_BYTE_SIZE)) {
+ if (IS_NULL(cc->mbuf)) {
+ found = 0;
+ }
+ else {
+ found = onig_is_in_code_range(cc->mbuf->p, code) != 0;
+ }
+ }
+ else {
+ found = BITSET_AT(cc->bs, code) != 0;
+ }
+
+ if (IS_NCCLASS_NOT(cc))
+ return !found;
+ else
+ return found;
+}
+
+extern int
+onig_is_code_in_cc(OnigEncoding enc, OnigCodePoint code, CClassNode* cc)
+{
+ int len;
+
+ if (ONIGENC_MBC_MINLEN(enc) > 1) {
+ len = 2;
+ }
+ else {
+ len = ONIGENC_CODE_TO_MBCLEN(enc, code);
+ if (len < 0) return 0;
+ }
+ return onig_is_code_in_cc_len(len, code, cc);
+}
+
+
+#ifdef ONIG_DEBUG_PARSE
+
+#ifdef USE_CALL
+static void
+p_string(FILE* f, int len, UChar* s)
+{
+ fputs(":", f);
+ while (len-- > 0) { fputc(*s++, f); }
+}
+#endif
+
+static void
+Indent(FILE* f, int indent)
+{
+ int i;
+ for (i = 0; i < indent; i++) putc(' ', f);
+}
+
+static void
+print_indent_tree(FILE* f, Node* node, int indent)
+{
+ int i;
+ NodeType type;
+ UChar* p;
+ int add = 3;
+
+ Indent(f, indent);
+ if (IS_NULL(node)) {
+ fprintf(f, "ERROR: null node!!!\n");
+ exit(0);
+ }
+
+ type = NODE_TYPE(node);
+ switch (type) {
+ case NODE_LIST:
+ case NODE_ALT:
+ if (type == NODE_LIST)
+ fprintf(f, "<list:%p>\n", node);
+ else
+ fprintf(f, "<alt:%p>\n", node);
+
+ print_indent_tree(f, NODE_CAR(node), indent + add);
+ while (IS_NOT_NULL(node = NODE_CDR(node))) {
+ if (NODE_TYPE(node) != type) {
+ fprintf(f, "ERROR: list/alt right is not a cons. %d\n", NODE_TYPE(node));
+ exit(0);
+ }
+ print_indent_tree(f, NODE_CAR(node), indent + add);
+ }
+ break;
+
+ case NODE_STRING:
+ {
+ char* str;
+ char* mode;
+
+ if (NODE_STRING_IS_CRUDE(node))
+ mode = "-crude";
+ else if (NODE_IS_IGNORECASE(node))
+ mode = "-ignorecase";
+ else
+ mode = "";
+
+ if (STR_(node)->s == STR_(node)->end)
+ str = "empty-string";
+ else
+ str = "string";
+
+ fprintf(f, "<%s%s:%p>", str, mode, node);
+ for (p = STR_(node)->s; p < STR_(node)->end; p++) {
+ if (*p >= 0x20 && *p < 0x7f)
+ fputc(*p, f);
+ else {
+ fprintf(f, " 0x%02x", *p);
+ }
+ }
+ }
+ break;
+
+ case NODE_CCLASS:
+ fprintf(f, "<cclass:%p>", node);
+ if (IS_NCCLASS_NOT(CCLASS_(node))) fputs(" not", f);
+ if (CCLASS_(node)->mbuf) {
+ BBuf* bbuf = CCLASS_(node)->mbuf;
+ for (i = 0; i < bbuf->used; i++) {
+ if (i > 0) fprintf(f, ",");
+ fprintf(f, "%0x", bbuf->p[i]);
+ }
+ }
+ break;
+
+ case NODE_CTYPE:
+ fprintf(f, "<ctype:%p> ", node);
+ switch (CTYPE_(node)->ctype) {
+ case CTYPE_ANYCHAR:
+ fprintf(f, "anychar");
+ break;
+
+ case ONIGENC_CTYPE_WORD:
+ if (CTYPE_(node)->not != 0)
+ fputs("not word", f);
+ else
+ fputs("word", f);
+
+ if (CTYPE_(node)->ascii_mode != 0)
+ fputs(" (ascii)", f);
+
+ break;
+
+ default:
+ fprintf(f, "ERROR: undefined ctype.\n");
+ exit(0);
+ }
+ break;
+
+ case NODE_ANCHOR:
+ fprintf(f, "<anchor:%p> ", node);
+ switch (ANCHOR_(node)->type) {
+ case ANCR_BEGIN_BUF: fputs("begin buf", f); break;
+ case ANCR_END_BUF: fputs("end buf", f); break;
+ case ANCR_BEGIN_LINE: fputs("begin line", f); break;
+ case ANCR_END_LINE: fputs("end line", f); break;
+ case ANCR_SEMI_END_BUF: fputs("semi end buf", f); break;
+ case ANCR_BEGIN_POSITION: fputs("begin position", f); break;
+
+ case ANCR_WORD_BOUNDARY: fputs("word boundary", f); break;
+ case ANCR_NO_WORD_BOUNDARY: fputs("not word boundary", f); break;
+#ifdef USE_WORD_BEGIN_END
+ case ANCR_WORD_BEGIN: fputs("word begin", f); break;
+ case ANCR_WORD_END: fputs("word end", f); break;
+#endif
+ case ANCR_TEXT_SEGMENT_BOUNDARY:
+ fputs("text-segment boundary", f); break;
+ case ANCR_NO_TEXT_SEGMENT_BOUNDARY:
+ fputs("no text-segment boundary", f); break;
+ case ANCR_PREC_READ:
+ fprintf(f, "prec read\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+ case ANCR_PREC_READ_NOT:
+ fprintf(f, "prec read not\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+ case ANCR_LOOK_BEHIND:
+ fprintf(f, "look behind\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+ case ANCR_LOOK_BEHIND_NOT:
+ fprintf(f, "look behind not\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+
+ default:
+ fprintf(f, "ERROR: undefined anchor type.\n");
+ break;
+ }
+ break;
+
+ case NODE_BACKREF:
+ {
+ int* p;
+ BackRefNode* br = BACKREF_(node);
+ p = BACKREFS_P(br);
+ fprintf(f, "<backref%s:%p>", NODE_IS_CHECKER(node) ? "-checker" : "", node);
+ for (i = 0; i < br->back_num; i++) {
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", p[i]);
+ }
+ }
+ break;
+
+#ifdef USE_CALL
+ case NODE_CALL:
+ {
+ CallNode* cn = CALL_(node);
+ fprintf(f, "<call:%p>", node);
+ p_string(f, cn->name_end - cn->name, cn->name);
+ }
+ break;
+#endif
+
+ case NODE_QUANT:
+ fprintf(f, "<quantifier:%p>{%d,%d}%s%s\n", node,
+ QUANT_(node)->lower, QUANT_(node)->upper,
+ (QUANT_(node)->greedy ? "" : "?"),
+ QUANT_(node)->include_referred == 0 ? "" : " referred");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+
+ case NODE_BAG:
+ fprintf(f, "<bag:%p> ", node);
+ if (BAG_(node)->type == BAG_IF_ELSE) {
+ Node* Then;
+ Node* Else;
+ BagNode* bn;
+
+ bn = BAG_(node);
+ fprintf(f, "if-else\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+
+ Then = bn->te.Then;
+ Else = bn->te.Else;
+ if (IS_NULL(Then)) {
+ Indent(f, indent + add);
+ fprintf(f, "THEN empty\n");
+ }
+ else
+ print_indent_tree(f, Then, indent + add);
+
+ if (IS_NULL(Else)) {
+ Indent(f, indent + add);
+ fprintf(f, "ELSE empty\n");
+ }
+ else
+ print_indent_tree(f, Else, indent + add);
+
+ break;
+ }
+
+ switch (BAG_(node)->type) {
+ case BAG_OPTION:
+ fprintf(f, "option:%d", BAG_(node)->o.options);
+ break;
+ case BAG_MEMORY:
+ fprintf(f, "memory:%d", BAG_(node)->m.regnum);
+ if (NODE_IS_CALLED(node))
+ fprintf(f, ", called");
+ if (NODE_IS_FIXED_ADDR(node))
+ fprintf(f, ", fixed-addr");
+ break;
+ case BAG_STOP_BACKTRACK:
+ fprintf(f, "stop-bt");
+ break;
+ default:
+ break;
+ }
+ fprintf(f, "\n");
+ print_indent_tree(f, NODE_BODY(node), indent + add);
+ break;
+
+ case NODE_GIMMICK:
+ fprintf(f, "<gimmick:%p> ", node);
+ switch (GIMMICK_(node)->type) {
+ case GIMMICK_FAIL:
+ fprintf(f, "fail");
+ break;
+ case GIMMICK_SAVE:
+ fprintf(f, "save:%d:%d", GIMMICK_(node)->detail_type, GIMMICK_(node)->id);
+ break;
+ case GIMMICK_UPDATE_VAR:
+ fprintf(f, "update_var:%d:%d", GIMMICK_(node)->detail_type, GIMMICK_(node)->id);
+ break;
+#ifdef USE_CALLOUT
+ case GIMMICK_CALLOUT:
+ switch (GIMMICK_(node)->detail_type) {
+ case ONIG_CALLOUT_OF_CONTENTS:
+ fprintf(f, "callout:contents:%d", GIMMICK_(node)->num);
+ break;
+ case ONIG_CALLOUT_OF_NAME:
+ fprintf(f, "callout:name:%d:%d", GIMMICK_(node)->id, GIMMICK_(node)->num);
+ break;
+ }
+#endif
+ }
+ break;
+
+ default:
+ fprintf(f, "print_indent_tree: undefined node type %d\n", NODE_TYPE(node));
+ break;
+ }
+
+ if (type != NODE_LIST && type != NODE_ALT && type != NODE_QUANT &&
+ type != NODE_BAG)
+ fprintf(f, "\n");
+ fflush(f);
+}
+
+static void
+print_tree(FILE* f, Node* node)
+{
+ print_indent_tree(f, node, 0);
+}
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.c
new file mode 100644
index 000000000..dbfbc8922
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.c
@@ -0,0 +1,985 @@
+/**********************************************************************
+ regenc.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+#define LARGE_S 0x53
+#define SMALL_S 0x73
+
+OnigEncoding OnigEncDefaultCharEncoding = ONIG_ENCODING_INIT_DEFAULT;
+
+#define INITED_LIST_SIZE 20
+
+static int InitedListNum;
+
+static struct {
+ OnigEncoding enc;
+ int inited;
+} InitedList[INITED_LIST_SIZE];
+
+static int
+enc_inited_entry(OnigEncoding enc)
+{
+ int i;
+
+ for (i = 0; i < InitedListNum; i++) {
+ if (InitedList[i].enc == enc) {
+ InitedList[i].inited = 1;
+ return i;
+ }
+ }
+
+ i = InitedListNum;
+ if (i < INITED_LIST_SIZE - 1) {
+ InitedList[i].enc = enc;
+ InitedList[i].inited = 1;
+ InitedListNum++;
+ return i;
+ }
+
+ return -1;
+}
+
+static int
+enc_is_inited(OnigEncoding enc)
+{
+ int i;
+
+ for (i = 0; i < InitedListNum; i++) {
+ if (InitedList[i].enc == enc) {
+ return InitedList[i].inited;
+ }
+ }
+
+ return 0;
+}
+
+static int OnigEncInited;
+
+extern int
+onigenc_init(void)
+{
+ if (OnigEncInited != 0) return 0;
+
+ OnigEncInited = 1;
+ return 0;
+}
+
+extern int
+onigenc_end(void)
+{
+ int i;
+
+ for (i = 0; i < InitedListNum; i++) {
+ InitedList[i].enc = 0;
+ InitedList[i].inited = 0;
+ }
+ InitedListNum = 0;
+
+ OnigEncInited = 0;
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_initialize_encoding(OnigEncoding enc)
+{
+ int r;
+
+ if (enc != ONIG_ENCODING_ASCII &&
+ ONIGENC_IS_ASCII_COMPATIBLE_ENCODING(enc)) {
+ OnigEncoding ascii = ONIG_ENCODING_ASCII;
+ if (ascii->init != 0 && enc_is_inited(ascii) == 0) {
+ r = ascii->init();
+ if (r != ONIG_NORMAL) return r;
+ enc_inited_entry(ascii);
+ }
+ }
+
+ if (enc->init != 0 &&
+ enc_is_inited(enc) == 0) {
+ r = (enc->init)();
+ if (r == ONIG_NORMAL)
+ enc_inited_entry(enc);
+ return r;
+ }
+
+ return 0;
+}
+
+extern OnigEncoding
+onigenc_get_default_encoding(void)
+{
+ return OnigEncDefaultCharEncoding;
+}
+
+extern int
+onigenc_set_default_encoding(OnigEncoding enc)
+{
+ OnigEncDefaultCharEncoding = enc;
+ return 0;
+}
+
+extern UChar*
+onigenc_strdup(OnigEncoding enc, const UChar* s, const UChar* end)
+{
+ int slen, term_len, i;
+ UChar *r;
+
+ slen = (int )(end - s);
+ term_len = ONIGENC_MBC_MINLEN(enc);
+
+ r = (UChar* )xmalloc(slen + term_len);
+ CHECK_NULL_RETURN(r);
+ xmemcpy(r, s, slen);
+
+ for (i = 0; i < term_len; i++)
+ r[slen + i] = (UChar )0;
+
+ return r;
+}
+
+extern UChar*
+onigenc_get_right_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s)
+{
+ UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s);
+ if (p < s) {
+ p += enclen(enc, p);
+ }
+ return p;
+}
+
+extern UChar*
+onigenc_get_right_adjust_char_head_with_prev(OnigEncoding enc,
+ const UChar* start, const UChar* s, const UChar** prev)
+{
+ UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s);
+
+ if (p < s) {
+ if (prev) *prev = (const UChar* )p;
+ p += enclen(enc, p);
+ }
+ else {
+ if (prev)
+ *prev = onigenc_get_prev_char_head(enc, start, p);
+ }
+ return p;
+}
+
+extern UChar*
+onigenc_get_prev_char_head(OnigEncoding enc, const UChar* start, const UChar* s)
+{
+ if (s <= start)
+ return (UChar* )NULL;
+
+ return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1);
+}
+
+extern UChar*
+onigenc_step_back(OnigEncoding enc, const UChar* start, const UChar* s, int n)
+{
+ while (ONIG_IS_NOT_NULL(s) && n-- > 0) {
+ if (s <= start)
+ return (UChar* )NULL;
+
+ s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1);
+ }
+ return (UChar* )s;
+}
+
+extern UChar*
+onigenc_step(OnigEncoding enc, const UChar* p, const UChar* end, int n)
+{
+ UChar* q = (UChar* )p;
+ while (n-- > 0) {
+ q += ONIGENC_MBC_ENC_LEN(enc, q);
+ }
+ return (q <= end ? q : NULL);
+}
+
+extern int
+onigenc_strlen(OnigEncoding enc, const UChar* p, const UChar* end)
+{
+ int n = 0;
+ UChar* q = (UChar* )p;
+
+ while (q < end) {
+ q += ONIGENC_MBC_ENC_LEN(enc, q);
+ n++;
+ }
+ return n;
+}
+
+extern int
+onigenc_strlen_null(OnigEncoding enc, const UChar* s)
+{
+ int n = 0;
+ UChar* p = (UChar* )s;
+
+ while (1) {
+ if (*p == '\0') {
+ UChar* q;
+ int len = ONIGENC_MBC_MINLEN(enc);
+
+ if (len == 1) return n;
+ q = p + 1;
+ while (len > 1) {
+ if (*q != '\0') break;
+ q++;
+ len--;
+ }
+ if (len == 1) return n;
+ }
+ p += ONIGENC_MBC_ENC_LEN(enc, p);
+ n++;
+ }
+}
+
+extern int
+onigenc_str_bytelen_null(OnigEncoding enc, const UChar* s)
+{
+ UChar* start = (UChar* )s;
+ UChar* p = (UChar* )s;
+
+ while (1) {
+ if (*p == '\0') {
+ UChar* q;
+ int len = ONIGENC_MBC_MINLEN(enc);
+
+ if (len == 1) return (int )(p - start);
+ q = p + 1;
+ while (len > 1) {
+ if (*q != '\0') break;
+ q++;
+ len--;
+ }
+ if (len == 1) return (int )(p - start);
+ }
+ p += ONIGENC_MBC_ENC_LEN(enc, p);
+ }
+}
+
+const UChar OnigEncAsciiToLowerCaseTable[] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+#ifdef USE_UPPER_CASE_TABLE
+const UChar OnigEncAsciiToUpperCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\101', '\102', '\103', '\104', '\105', '\106', '\107',
+ '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117',
+ '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+ '\130', '\131', '\132', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\101', '\102', '\103', '\104', '\105', '\106', '\107',
+ '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117',
+ '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+ '\130', '\131', '\132', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+#endif
+
+const unsigned short OnigEncAsciiCtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x420c, 0x4209, 0x4208, 0x4208, 0x4208, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+const UChar OnigEncISO_8859_1_ToLowerCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+#ifdef USE_UPPER_CASE_TABLE
+const UChar OnigEncISO_8859_1_ToUpperCaseTable[256] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\101', '\102', '\103', '\104', '\105', '\106', '\107',
+ '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117',
+ '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+ '\130', '\131', '\132', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\101', '\102', '\103', '\104', '\105', '\106', '\107',
+ '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117',
+ '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+ '\130', '\131', '\132', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\367',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\377',
+};
+#endif
+
+extern void
+onigenc_set_default_caseconv_table(const UChar* table ARG_UNUSED)
+{
+ /* nothing */
+ /* obsoleted. */
+}
+
+extern UChar*
+onigenc_get_left_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s)
+{
+ return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s);
+}
+
+const OnigPairCaseFoldCodes OnigAsciiLowerMap[] = {
+ { 0x41, 0x61 },
+ { 0x42, 0x62 },
+ { 0x43, 0x63 },
+ { 0x44, 0x64 },
+ { 0x45, 0x65 },
+ { 0x46, 0x66 },
+ { 0x47, 0x67 },
+ { 0x48, 0x68 },
+ { 0x49, 0x69 },
+ { 0x4a, 0x6a },
+ { 0x4b, 0x6b },
+ { 0x4c, 0x6c },
+ { 0x4d, 0x6d },
+ { 0x4e, 0x6e },
+ { 0x4f, 0x6f },
+ { 0x50, 0x70 },
+ { 0x51, 0x71 },
+ { 0x52, 0x72 },
+ { 0x53, 0x73 },
+ { 0x54, 0x74 },
+ { 0x55, 0x75 },
+ { 0x56, 0x76 },
+ { 0x57, 0x77 },
+ { 0x58, 0x78 },
+ { 0x59, 0x79 },
+ { 0x5a, 0x7a }
+};
+
+extern int
+onigenc_ascii_apply_all_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ OnigCodePoint code;
+ int i, r;
+
+ for (i = 0;
+ i < (int )(sizeof(OnigAsciiLowerMap)/sizeof(OnigPairCaseFoldCodes));
+ i++) {
+ code = OnigAsciiLowerMap[i].to;
+ r = (*f)(OnigAsciiLowerMap[i].from, &code, 1, arg);
+ if (r != 0) return r;
+
+ code = OnigAsciiLowerMap[i].from;
+ r = (*f)(OnigAsciiLowerMap[i].to, &code, 1, arg);
+ if (r != 0) return r;
+ }
+
+ return 0;
+}
+
+extern int
+onigenc_ascii_get_case_fold_codes_by_str(OnigCaseFoldType flag ARG_UNUSED,
+ const OnigUChar* p, const OnigUChar* end ARG_UNUSED,
+ OnigCaseFoldCodeItem items[])
+{
+ if (0x41 <= *p && *p <= 0x5a) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p + 0x20);
+ return 1;
+ }
+ else if (0x61 <= *p && *p <= 0x7a) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p - 0x20);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int
+ss_apply_all_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ static OnigCodePoint ss[] = { SMALL_S, SMALL_S };
+
+ return (*f)((OnigCodePoint )0xdf, ss, 2, arg);
+}
+
+extern int
+onigenc_apply_all_case_fold_with_map(int map_size,
+ const OnigPairCaseFoldCodes map[],
+ int ess_tsett_flag, OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ OnigCodePoint code;
+ int i, r;
+
+ r = onigenc_ascii_apply_all_case_fold(flag, f, arg);
+ if (r != 0) return r;
+
+ for (i = 0; i < map_size; i++) {
+ code = map[i].to;
+ r = (*f)(map[i].from, &code, 1, arg);
+ if (r != 0) return r;
+
+ code = map[i].from;
+ r = (*f)(map[i].to, &code, 1, arg);
+ if (r != 0) return r;
+ }
+
+ if (ess_tsett_flag != 0)
+ return ss_apply_all_case_fold(flag, f, arg);
+
+ return 0;
+}
+
+extern int
+onigenc_get_case_fold_codes_by_str_with_map(int map_size,
+ const OnigPairCaseFoldCodes map[],
+ int ess_tsett_flag, OnigCaseFoldType flag ARG_UNUSED,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ int i, j, n;
+ static OnigUChar sa[] = { LARGE_S, SMALL_S };
+
+ if (0x41 <= *p && *p <= 0x5a) { /* A - Z */
+ if (*p == LARGE_S && ess_tsett_flag != 0 && end > p + 1
+ && (*(p+1) == LARGE_S || *(p+1) == SMALL_S)) { /* SS */
+ ss_combination:
+ items[0].byte_len = 2;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )0xdf;
+
+ n = 1;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ if (sa[i] == *p && sa[j] == *(p+1))
+ continue;
+
+ items[n].byte_len = 2;
+ items[n].code_len = 2;
+ items[n].code[0] = (OnigCodePoint )sa[i];
+ items[n].code[1] = (OnigCodePoint )sa[j];
+ n++;
+ }
+ }
+ return 4;
+ }
+
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p + 0x20);
+ return 1;
+ }
+ else if (0x61 <= *p && *p <= 0x7a) { /* a - z */
+ if (*p == SMALL_S && ess_tsett_flag != 0 && end > p + 1
+ && (*(p+1) == SMALL_S || *(p+1) == LARGE_S)) {
+ goto ss_combination;
+ }
+
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = (OnigCodePoint )(*p - 0x20);
+ return 1;
+ }
+ else if (*p == 0xdf && ess_tsett_flag != 0) {
+ items[0].byte_len = 1;
+ items[0].code_len = 2;
+ items[0].code[0] = (OnigCodePoint )'s';
+ items[0].code[1] = (OnigCodePoint )'s';
+
+ items[1].byte_len = 1;
+ items[1].code_len = 2;
+ items[1].code[0] = (OnigCodePoint )'S';
+ items[1].code[1] = (OnigCodePoint )'S';
+
+ items[2].byte_len = 1;
+ items[2].code_len = 2;
+ items[2].code[0] = (OnigCodePoint )'s';
+ items[2].code[1] = (OnigCodePoint )'S';
+
+ items[3].byte_len = 1;
+ items[3].code_len = 2;
+ items[3].code[0] = (OnigCodePoint )'S';
+ items[3].code[1] = (OnigCodePoint )'s';
+
+ return 4;
+ }
+ else {
+ int i;
+
+ for (i = 0; i < map_size; i++) {
+ if (*p == map[i].from) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = map[i].to;
+ return 1;
+ }
+ else if (*p == map[i].to) {
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = map[i].from;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+extern int
+onigenc_not_support_get_ctype_code_range(OnigCtype ctype ARG_UNUSED,
+ OnigCodePoint* sb_out ARG_UNUSED,
+ const OnigCodePoint* ranges[] ARG_UNUSED)
+{
+ return ONIG_NO_SUPPORT_CONFIG;
+}
+
+extern int
+onigenc_is_mbc_newline_0x0a(const UChar* p, const UChar* end)
+{
+ if (p < end) {
+ if (*p == NEWLINE_CODE) return 1;
+ }
+ return 0;
+}
+
+/* for single byte encodings */
+extern int
+onigenc_ascii_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED, const UChar** p,
+ const UChar*end ARG_UNUSED, UChar* lower)
+{
+ *lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(**p);
+
+ (*p)++;
+ return 1; /* return byte length of converted char to lower */
+}
+
+extern int
+onigenc_single_byte_mbc_enc_len(const UChar* p ARG_UNUSED)
+{
+ return 1;
+}
+
+extern OnigCodePoint
+onigenc_single_byte_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
+{
+ return (OnigCodePoint )(*p);
+}
+
+extern int
+onigenc_single_byte_code_to_mbclen(OnigCodePoint code ARG_UNUSED)
+{
+ return (code < 0x100 ? 1 : ONIGERR_INVALID_CODE_POINT_VALUE);
+}
+
+extern int
+onigenc_single_byte_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ *buf = (UChar )(code & 0xff);
+ return 1;
+}
+
+extern UChar*
+onigenc_single_byte_left_adjust_char_head(const UChar* start ARG_UNUSED,
+ const UChar* s)
+{
+ return (UChar* )s;
+}
+
+extern int
+onigenc_always_true_is_allowed_reverse_match(const UChar* s ARG_UNUSED,
+ const UChar* end ARG_UNUSED)
+{
+ return TRUE;
+}
+
+extern int
+onigenc_always_false_is_allowed_reverse_match(const UChar* s ARG_UNUSED,
+ const UChar* end ARG_UNUSED)
+{
+ return FALSE;
+}
+
+extern int
+onigenc_always_true_is_valid_mbc_string(const UChar* s ARG_UNUSED,
+ const UChar* end ARG_UNUSED)
+{
+ return TRUE;
+}
+
+extern int
+onigenc_length_check_is_valid_mbc_string(OnigEncoding enc,
+ const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ p += enclen(enc, p);
+ }
+
+ if (p != end)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+extern int
+onigenc_is_valid_mbc_string(OnigEncoding enc, const UChar* s, const UChar* end)
+{
+ return ONIGENC_IS_VALID_MBC_STRING(enc, s, end);
+}
+
+extern OnigCodePoint
+onigenc_mbn_mbc_to_code(OnigEncoding enc, const UChar* p, const UChar* end)
+{
+ int c, i, len;
+ OnigCodePoint n;
+
+ len = enclen(enc, p);
+ n = (OnigCodePoint )(*p++);
+ if (len == 1) return n;
+
+ for (i = 1; i < len; i++) {
+ if (p >= end) break;
+ c = *p++;
+ n <<= 8; n += c;
+ }
+ return n;
+}
+
+extern int
+onigenc_mbn_mbc_case_fold(OnigEncoding enc, OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED,
+ UChar* lower)
+{
+ int len;
+ const UChar *p = *pp;
+
+ if (ONIGENC_IS_MBC_ASCII(p)) {
+ *lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+ }
+ else {
+ int i;
+
+ len = enclen(enc, p);
+ for (i = 0; i < len; i++) {
+ *lower++ = *p++;
+ }
+ (*pp) += len;
+ return len; /* return byte length of converted to lower char */
+ }
+}
+
+extern int
+onigenc_mb2_code_to_mbc(OnigEncoding enc, OnigCodePoint code, UChar *buf)
+{
+ UChar *p = buf;
+
+ if ((code & 0xff00) != 0) {
+ *p++ = (UChar )((code >> 8) & 0xff);
+ }
+ *p++ = (UChar )(code & 0xff);
+
+#if 1
+ if (enclen(enc, buf) != (p - buf))
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+#endif
+ return (int )(p - buf);
+}
+
+extern int
+onigenc_mb4_code_to_mbc(OnigEncoding enc, OnigCodePoint code, UChar *buf)
+{
+ UChar *p = buf;
+
+ if ((code & 0xff000000) != 0) {
+ *p++ = (UChar )((code >> 24) & 0xff);
+ }
+ if ((code & 0xff0000) != 0 || p != buf) {
+ *p++ = (UChar )((code >> 16) & 0xff);
+ }
+ if ((code & 0xff00) != 0 || p != buf) {
+ *p++ = (UChar )((code >> 8) & 0xff);
+ }
+ *p++ = (UChar )(code & 0xff);
+
+#if 1
+ if (enclen(enc, buf) != (p - buf))
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+#endif
+ return (int )(p - buf);
+}
+
+extern int
+onigenc_minimum_property_name_to_ctype(OnigEncoding enc, UChar* p, UChar* end)
+{
+ static PosixBracketEntryType PBS[] = {
+ { (UChar* )"Alnum", ONIGENC_CTYPE_ALNUM, 5 },
+ { (UChar* )"Alpha", ONIGENC_CTYPE_ALPHA, 5 },
+ { (UChar* )"Blank", ONIGENC_CTYPE_BLANK, 5 },
+ { (UChar* )"Cntrl", ONIGENC_CTYPE_CNTRL, 5 },
+ { (UChar* )"Digit", ONIGENC_CTYPE_DIGIT, 5 },
+ { (UChar* )"Graph", ONIGENC_CTYPE_GRAPH, 5 },
+ { (UChar* )"Lower", ONIGENC_CTYPE_LOWER, 5 },
+ { (UChar* )"Print", ONIGENC_CTYPE_PRINT, 5 },
+ { (UChar* )"Punct", ONIGENC_CTYPE_PUNCT, 5 },
+ { (UChar* )"Space", ONIGENC_CTYPE_SPACE, 5 },
+ { (UChar* )"Upper", ONIGENC_CTYPE_UPPER, 5 },
+ { (UChar* )"XDigit", ONIGENC_CTYPE_XDIGIT, 6 },
+ { (UChar* )"ASCII", ONIGENC_CTYPE_ASCII, 5 },
+ { (UChar* )"Word", ONIGENC_CTYPE_WORD, 4 },
+ { (UChar* )NULL, -1, 0 }
+ };
+
+ PosixBracketEntryType *pb;
+ int len;
+
+ len = onigenc_strlen(enc, p, end);
+ for (pb = PBS; IS_NOT_NULL(pb->name); pb++) {
+ if (len == pb->len &&
+ onigenc_with_ascii_strncmp(enc, p, end, pb->name, pb->len) == 0)
+ return pb->ctype;
+ }
+
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+}
+
+extern int
+onigenc_is_mbc_word_ascii(OnigEncoding enc, UChar* s, const UChar* end)
+{
+ OnigCodePoint code = ONIGENC_MBC_TO_CODE(enc, s, end);
+
+ if (code > ASCII_LIMIT) return 0;
+
+ return ONIGENC_IS_ASCII_CODE_WORD(code);
+}
+
+extern int
+onigenc_mb2_is_code_ctype(OnigEncoding enc, OnigCodePoint code,
+ unsigned int ctype)
+{
+ if (code < 128)
+ return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
+ else {
+ if (CTYPE_IS_WORD_GRAPH_PRINT(ctype)) {
+ return (ONIGENC_CODE_TO_MBCLEN(enc, code) > 1 ? TRUE : FALSE);
+ }
+ }
+
+ return FALSE;
+}
+
+extern int
+onigenc_mb4_is_code_ctype(OnigEncoding enc, OnigCodePoint code,
+ unsigned int ctype)
+{
+ if (code < 128)
+ return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
+ else {
+ if (CTYPE_IS_WORD_GRAPH_PRINT(ctype)) {
+ return (ONIGENC_CODE_TO_MBCLEN(enc, code) > 1 ? TRUE : FALSE);
+ }
+ }
+
+ return FALSE;
+}
+
+extern int
+onigenc_with_ascii_strncmp(OnigEncoding enc, const UChar* p, const UChar* end,
+ const UChar* sascii /* ascii */, int n)
+{
+ int x, c;
+
+ while (n-- > 0) {
+ if (p >= end) return (int )(*sascii);
+
+ c = (int )ONIGENC_MBC_TO_CODE(enc, p, end);
+ x = *sascii - c;
+ if (x) return x;
+
+ sascii++;
+ p += enclen(enc, p);
+ }
+ return 0;
+}
+
+extern int
+onig_codes_cmp(OnigCodePoint a[], OnigCodePoint b[], int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (a[i] != b[i])
+ return -1;
+ }
+
+ return 0;
+}
+
+extern int
+onig_codes_byte_at(OnigCodePoint codes[], int at)
+{
+ int index;
+ int b;
+ OnigCodePoint code;
+
+ index = at / 3;
+ b = at % 3;
+ code = codes[index];
+
+ return ((code >> ((2 - b) * 8)) & 0xff);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.h
new file mode 100644
index 000000000..d183b9725
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regenc.h
@@ -0,0 +1,282 @@
+#ifndef REGENC_H
+#define REGENC_H
+/**********************************************************************
+ regenc.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef ONIGURUMA_EXPORT
+#define ONIGURUMA_EXPORT
+#endif
+
+#include "config.h"
+
+#ifndef ONIG_NO_STANDARD_C_HEADERS
+#include <stddef.h>
+#endif
+
+#ifdef ONIG_ESCAPE_UCHAR_COLLISION
+#undef ONIG_ESCAPE_UCHAR_COLLISION
+#endif
+
+#include "oniguruma.h"
+
+typedef struct {
+ OnigCodePoint from;
+ OnigCodePoint to;
+} OnigPairCaseFoldCodes;
+
+
+#ifndef NULL
+#define NULL ((void* )0)
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef ARG_UNUSED
+#if defined(__GNUC__)
+# define ARG_UNUSED __attribute__ ((unused))
+#else
+# define ARG_UNUSED
+#endif
+#endif
+
+#define ONIG_IS_NULL(p) (((void*)(p)) == (void*)0)
+#define ONIG_IS_NOT_NULL(p) (((void*)(p)) != (void*)0)
+#define ONIG_CHECK_NULL_RETURN(p) if (ONIG_IS_NULL(p)) return NULL
+#define ONIG_CHECK_NULL_RETURN_VAL(p,val) if (ONIG_IS_NULL(p)) return (val)
+
+#define MAX_CODE_POINT (~((OnigCodePoint )0))
+#define ASCII_LIMIT 127
+#define NEWLINE_CODE 0x0a
+
+#define enclen(enc,p) ONIGENC_MBC_ENC_LEN(enc,p)
+
+/* character types bit flag */
+#define BIT_CTYPE_NEWLINE (1<< ONIGENC_CTYPE_NEWLINE)
+#define BIT_CTYPE_ALPHA (1<< ONIGENC_CTYPE_ALPHA)
+#define BIT_CTYPE_BLANK (1<< ONIGENC_CTYPE_BLANK)
+#define BIT_CTYPE_CNTRL (1<< ONIGENC_CTYPE_CNTRL)
+#define BIT_CTYPE_DIGIT (1<< ONIGENC_CTYPE_DIGIT)
+#define BIT_CTYPE_GRAPH (1<< ONIGENC_CTYPE_GRAPH)
+#define BIT_CTYPE_LOWER (1<< ONIGENC_CTYPE_LOWER)
+#define BIT_CTYPE_PRINT (1<< ONIGENC_CTYPE_PRINT)
+#define BIT_CTYPE_PUNCT (1<< ONIGENC_CTYPE_PUNCT)
+#define BIT_CTYPE_SPACE (1<< ONIGENC_CTYPE_SPACE)
+#define BIT_CTYPE_UPPER (1<< ONIGENC_CTYPE_UPPER)
+#define BIT_CTYPE_XDIGIT (1<< ONIGENC_CTYPE_XDIGIT)
+#define BIT_CTYPE_WORD (1<< ONIGENC_CTYPE_WORD)
+#define BIT_CTYPE_ALNUM (1<< ONIGENC_CTYPE_ALNUM)
+#define BIT_CTYPE_ASCII (1<< ONIGENC_CTYPE_ASCII)
+
+#define CTYPE_TO_BIT(ctype) (1<<(ctype))
+#define CTYPE_IS_WORD_GRAPH_PRINT(ctype) \
+ ((ctype) == ONIGENC_CTYPE_WORD || (ctype) == ONIGENC_CTYPE_GRAPH ||\
+ (ctype) == ONIGENC_CTYPE_PRINT)
+
+
+typedef struct {
+ UChar *name;
+ int ctype;
+ short int len;
+} PosixBracketEntryType;
+
+struct PropertyNameCtype {
+ char *name;
+ int ctype;
+};
+
+/* #define USE_CRNL_AS_LINE_TERMINATOR */
+#define USE_UNICODE_PROPERTIES
+#define USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
+#define USE_UNICODE_WORD_BREAK
+/* #define USE_UNICODE_CASE_FOLD_TURKISH_AZERI */
+/* #define USE_UNICODE_ALL_LINE_TERMINATORS */ /* see Unicode.org UTS #18 */
+
+
+#define ONIG_ENCODING_INIT_DEFAULT ONIG_ENCODING_ASCII
+
+
+#define ENC_SKIP_OFFSET_1_OR_0 7
+
+#define ENC_FLAG_ASCII_COMPATIBLE (1<<0)
+#define ENC_FLAG_UNICODE (1<<1)
+#define ENC_FLAG_SKIP_OFFSET_MASK (7<<2)
+#define ENC_FLAG_SKIP_OFFSET_0 0
+#define ENC_FLAG_SKIP_OFFSET_1 (1<<2)
+#define ENC_FLAG_SKIP_OFFSET_2 (2<<2)
+#define ENC_FLAG_SKIP_OFFSET_3 (3<<2)
+#define ENC_FLAG_SKIP_OFFSET_4 (4<<2)
+#define ENC_FLAG_SKIP_OFFSET_1_OR_0 (ENC_SKIP_OFFSET_1_OR_0<<2)
+
+#define ENC_GET_SKIP_OFFSET(enc) \
+ (((enc)->flag & ENC_FLAG_SKIP_OFFSET_MASK)>>2)
+
+
+/* for encoding system implementation (internal) */
+extern int onigenc_end(void);
+extern int onigenc_ascii_apply_all_case_fold P_((OnigCaseFoldType flag, OnigApplyAllCaseFoldFunc f, void* arg));
+extern int onigenc_ascii_get_case_fold_codes_by_str P_((OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[]));
+extern int onigenc_apply_all_case_fold_with_map P_((int map_size, const OnigPairCaseFoldCodes map[], int ess_tsett_flag, OnigCaseFoldType flag, OnigApplyAllCaseFoldFunc f, void* arg));
+extern int onigenc_get_case_fold_codes_by_str_with_map P_((int map_size, const OnigPairCaseFoldCodes map[], int ess_tsett_flag, OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[]));
+extern int onigenc_not_support_get_ctype_code_range P_((OnigCtype ctype, OnigCodePoint* sb_out, const OnigCodePoint* ranges[]));
+extern int onigenc_is_mbc_newline_0x0a P_((const UChar* p, const UChar* end));
+
+
+/* methods for single byte encoding */
+extern int onigenc_ascii_mbc_case_fold P_((OnigCaseFoldType flag, const UChar** p, const UChar* end, UChar* lower));
+extern int onigenc_single_byte_mbc_enc_len P_((const UChar* p));
+extern OnigCodePoint onigenc_single_byte_mbc_to_code P_((const UChar* p, const UChar* end));
+extern int onigenc_single_byte_code_to_mbclen P_((OnigCodePoint code));
+extern int onigenc_single_byte_code_to_mbc P_((OnigCodePoint code, UChar *buf));
+extern UChar* onigenc_single_byte_left_adjust_char_head P_((const UChar* start, const UChar* s));
+extern int onigenc_always_true_is_allowed_reverse_match P_((const UChar* s, const UChar* end));
+extern int onigenc_always_false_is_allowed_reverse_match P_((const UChar* s, const UChar* end));
+extern int onigenc_always_true_is_valid_mbc_string P_((const UChar* s, const UChar* end));
+extern int onigenc_length_check_is_valid_mbc_string P_((OnigEncoding enc, const UChar* s, const UChar* end));
+
+/* methods for multi byte encoding */
+extern OnigCodePoint onigenc_mbn_mbc_to_code P_((OnigEncoding enc, const UChar* p, const UChar* end));
+extern int onigenc_mbn_mbc_case_fold P_((OnigEncoding enc, OnigCaseFoldType flag, const UChar** p, const UChar* end, UChar* lower));
+extern int onigenc_mb2_code_to_mbc P_((OnigEncoding enc, OnigCodePoint code, UChar *buf));
+extern int onigenc_minimum_property_name_to_ctype P_((OnigEncoding enc, UChar* p, UChar* end));
+extern int onigenc_unicode_property_name_to_ctype P_((OnigEncoding enc, UChar* p, UChar* end));
+extern int onigenc_is_mbc_word_ascii P_((OnigEncoding enc, UChar* s, const UChar* end));
+extern int onigenc_mb2_is_code_ctype P_((OnigEncoding enc, OnigCodePoint code, unsigned int ctype));
+extern int onigenc_mb4_code_to_mbc P_((OnigEncoding enc, OnigCodePoint code, UChar *buf));
+extern int onigenc_mb4_is_code_ctype P_((OnigEncoding enc, OnigCodePoint code, unsigned int ctype));
+extern struct PropertyNameCtype* onigenc_euc_jp_lookup_property_name P_((register const char *str, register size_t len));
+extern struct PropertyNameCtype* onigenc_sjis_lookup_property_name P_((register const char *str, register size_t len));
+
+/* in unicode.c */
+extern int onigenc_unicode_is_code_ctype P_((OnigCodePoint code, unsigned int ctype));
+extern int onigenc_utf16_32_get_ctype_code_range P_((OnigCtype ctype, OnigCodePoint *sb_out, const OnigCodePoint* ranges[]));
+extern int onigenc_unicode_ctype_code_range P_((OnigCtype ctype, const OnigCodePoint* ranges[]));
+extern int onigenc_unicode_get_case_fold_codes_by_str P_((OnigEncoding enc, OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[]));
+extern int onigenc_unicode_mbc_case_fold P_((OnigEncoding enc, OnigCaseFoldType flag, const UChar** pp, const UChar* end, UChar* fold));
+extern int onigenc_unicode_apply_all_case_fold P_((OnigCaseFoldType flag, OnigApplyAllCaseFoldFunc f, void* arg));
+
+extern int onigenc_egcb_is_break_position P_((OnigEncoding enc, UChar* p, UChar* prev, const UChar* start, const UChar* end));
+
+#ifdef USE_UNICODE_WORD_BREAK
+extern int onigenc_wb_is_break_position P_((OnigEncoding enc, UChar* p, UChar* prev, const UChar* start, const UChar* end));
+#endif
+
+#define UTF16_IS_SURROGATE_FIRST(c) (((c) & 0xfc) == 0xd8)
+#define UTF16_IS_SURROGATE_SECOND(c) (((c) & 0xfc) == 0xdc)
+
+/* from unicode generated codes */
+#define FOLDS1_FOLD(i) (OnigUnicodeFolds1 + (i))
+#define FOLDS2_FOLD(i) (OnigUnicodeFolds2 + (i))
+#define FOLDS3_FOLD(i) (OnigUnicodeFolds3 + (i))
+#define FOLDS1_UNFOLDS_NUM(i) (OnigUnicodeFolds1[(i)+1])
+#define FOLDS2_UNFOLDS_NUM(i) (OnigUnicodeFolds2[(i)+2])
+#define FOLDS3_UNFOLDS_NUM(i) (OnigUnicodeFolds3[(i)+3])
+#define FOLDS1_UNFOLDS(i) (OnigUnicodeFolds1 + (i) + 2)
+#define FOLDS2_UNFOLDS(i) (OnigUnicodeFolds2 + (i) + 3)
+#define FOLDS3_UNFOLDS(i) (OnigUnicodeFolds3 + (i) + 4)
+#define FOLDS1_NEXT_INDEX(i) ((i) + 2 + OnigUnicodeFolds1[(i)+1])
+#define FOLDS2_NEXT_INDEX(i) ((i) + 3 + OnigUnicodeFolds2[(i)+2])
+#define FOLDS3_NEXT_INDEX(i) ((i) + 4 + OnigUnicodeFolds3[(i)+3])
+
+#define FOLDS_FOLD_ADDR_BUK(buk, addr) do {\
+ if ((buk)->fold_len == 1)\
+ addr = OnigUnicodeFolds1 + (buk)->index;\
+ else if ((buk)->fold_len == 2)\
+ addr = OnigUnicodeFolds2 + (buk)->index;\
+ else if ((buk)->fold_len == 3)\
+ addr = OnigUnicodeFolds3 + (buk)->index;\
+ else\
+ return ONIGERR_INVALID_CODE_POINT_VALUE;\
+} while (0)
+
+extern OnigCodePoint OnigUnicodeFolds1[];
+extern OnigCodePoint OnigUnicodeFolds2[];
+extern OnigCodePoint OnigUnicodeFolds3[];
+
+struct ByUnfoldKey {
+ OnigCodePoint code;
+ short int index;
+ short int fold_len;
+};
+
+extern const struct ByUnfoldKey* onigenc_unicode_unfold_key(OnigCodePoint code);
+extern int onigenc_unicode_fold1_key(OnigCodePoint code[]);
+extern int onigenc_unicode_fold2_key(OnigCodePoint code[]);
+extern int onigenc_unicode_fold3_key(OnigCodePoint code[]);
+
+extern int onig_codes_cmp(OnigCodePoint a[], OnigCodePoint b[], int n);
+extern int onig_codes_byte_at(OnigCodePoint code[], int at);
+
+
+
+#define ONIGENC_ISO_8859_1_TO_LOWER_CASE(c) \
+ OnigEncISO_8859_1_ToLowerCaseTable[c]
+#define ONIGENC_ISO_8859_1_TO_UPPER_CASE(c) \
+ OnigEncISO_8859_1_ToUpperCaseTable[c]
+
+extern const UChar OnigEncISO_8859_1_ToLowerCaseTable[];
+extern const UChar OnigEncISO_8859_1_ToUpperCaseTable[];
+
+extern int
+onigenc_with_ascii_strncmp P_((OnigEncoding enc, const UChar* p, const UChar* end, const UChar* sascii /* ascii */, int n));
+extern UChar*
+onigenc_step P_((OnigEncoding enc, const UChar* p, const UChar* end, int n));
+
+/* defined in regexec.c, but used in enc/xxx.c */
+extern int onig_is_in_code_range P_((const UChar* p, OnigCodePoint code));
+
+extern OnigEncoding OnigEncDefaultCharEncoding;
+extern const UChar OnigEncAsciiToLowerCaseTable[];
+extern const UChar OnigEncAsciiToUpperCaseTable[];
+extern const unsigned short OnigEncAsciiCtypeTable[];
+
+
+#define ONIGENC_IS_ASCII_CODE(code) ((code) < 0x80)
+#define ONIGENC_ASCII_CODE_TO_LOWER_CASE(c) OnigEncAsciiToLowerCaseTable[c]
+#define ONIGENC_ASCII_CODE_TO_UPPER_CASE(c) OnigEncAsciiToUpperCaseTable[c]
+#define ONIGENC_IS_ASCII_CODE_CTYPE(code,ctype) \
+ ((OnigEncAsciiCtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+#define ONIGENC_IS_ASCII_CODE_WORD(code) \
+ ((OnigEncAsciiCtypeTable[code] & CTYPE_TO_BIT(ONIGENC_CTYPE_WORD)) != 0)
+#define ONIGENC_IS_ASCII_CODE_CASE_AMBIG(code) \
+ (ONIGENC_IS_ASCII_CODE_CTYPE(code, ONIGENC_CTYPE_UPPER) ||\
+ ONIGENC_IS_ASCII_CODE_CTYPE(code, ONIGENC_CTYPE_LOWER))
+
+#define ONIGENC_IS_UNICODE_ENCODING(enc) \
+ (((enc)->flag & ENC_FLAG_UNICODE) != 0)
+
+#define ONIGENC_IS_ASCII_COMPATIBLE_ENCODING(enc) \
+ (((enc)->flag & ENC_FLAG_ASCII_COMPATIBLE) != 0)
+
+#endif /* REGENC_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regerror.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regerror.c
new file mode 100644
index 000000000..58bc7fdc7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regerror.c
@@ -0,0 +1,406 @@
+/**********************************************************************
+ regerror.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef NEED_TO_INCLUDE_STDIO
+/* for vsnprintf() */
+#define NEED_TO_INCLUDE_STDIO
+#endif
+
+#include "regint.h"
+
+extern UChar*
+onig_error_code_to_format(int code)
+{
+ char *p;
+
+ switch (code) {
+ case ONIG_MISMATCH:
+ p = "mismatch"; break;
+ case ONIG_NO_SUPPORT_CONFIG:
+ p = "no support in this configuration"; break;
+ case ONIG_ABORT:
+ p = "abort"; break;
+ case ONIGERR_MEMORY:
+ p = "fail to memory allocation"; break;
+ case ONIGERR_MATCH_STACK_LIMIT_OVER:
+ p = "match-stack limit over"; break;
+ case ONIGERR_PARSE_DEPTH_LIMIT_OVER:
+ p = "parse depth limit over"; break;
+ case ONIGERR_RETRY_LIMIT_IN_MATCH_OVER:
+ p = "retry-limit-in-match over"; break;
+ case ONIGERR_RETRY_LIMIT_IN_SEARCH_OVER:
+ p = "retry-limit-in-search over"; break;
+ case ONIGERR_TYPE_BUG:
+ p = "undefined type (bug)"; break;
+ case ONIGERR_PARSER_BUG:
+ p = "internal parser error (bug)"; break;
+ case ONIGERR_STACK_BUG:
+ p = "stack error (bug)"; break;
+ case ONIGERR_UNDEFINED_BYTECODE:
+ p = "undefined bytecode (bug)"; break;
+ case ONIGERR_UNEXPECTED_BYTECODE:
+ p = "unexpected bytecode (bug)"; break;
+ case ONIGERR_DEFAULT_ENCODING_IS_NOT_SETTED:
+ p = "default multibyte-encoding is not setted"; break;
+ case ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR:
+ p = "can't convert to wide-char on specified multibyte-encoding"; break;
+ case ONIGERR_FAIL_TO_INITIALIZE:
+ p = "fail to initialize"; break;
+ case ONIGERR_INVALID_ARGUMENT:
+ p = "invalid argument"; break;
+ case ONIGERR_END_PATTERN_AT_LEFT_BRACE:
+ p = "end pattern at left brace"; break;
+ case ONIGERR_END_PATTERN_AT_LEFT_BRACKET:
+ p = "end pattern at left bracket"; break;
+ case ONIGERR_EMPTY_CHAR_CLASS:
+ p = "empty char-class"; break;
+ case ONIGERR_PREMATURE_END_OF_CHAR_CLASS:
+ p = "premature end of char-class"; break;
+ case ONIGERR_END_PATTERN_AT_ESCAPE:
+ p = "end pattern at escape"; break;
+ case ONIGERR_END_PATTERN_AT_META:
+ p = "end pattern at meta"; break;
+ case ONIGERR_END_PATTERN_AT_CONTROL:
+ p = "end pattern at control"; break;
+ case ONIGERR_META_CODE_SYNTAX:
+ p = "invalid meta-code syntax"; break;
+ case ONIGERR_CONTROL_CODE_SYNTAX:
+ p = "invalid control-code syntax"; break;
+ case ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE:
+ p = "char-class value at end of range"; break;
+ case ONIGERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE:
+ p = "char-class value at start of range"; break;
+ case ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS:
+ p = "unmatched range specifier in char-class"; break;
+ case ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED:
+ p = "target of repeat operator is not specified"; break;
+ case ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID:
+ p = "target of repeat operator is invalid"; break;
+ case ONIGERR_NESTED_REPEAT_OPERATOR:
+ p = "nested repeat operator"; break;
+ case ONIGERR_UNMATCHED_CLOSE_PARENTHESIS:
+ p = "unmatched close parenthesis"; break;
+ case ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS:
+ p = "end pattern with unmatched parenthesis"; break;
+ case ONIGERR_END_PATTERN_IN_GROUP:
+ p = "end pattern in group"; break;
+ case ONIGERR_UNDEFINED_GROUP_OPTION:
+ p = "undefined group option"; break;
+ case ONIGERR_INVALID_POSIX_BRACKET_TYPE:
+ p = "invalid POSIX bracket type"; break;
+ case ONIGERR_INVALID_LOOK_BEHIND_PATTERN:
+ p = "invalid pattern in look-behind"; break;
+ case ONIGERR_INVALID_REPEAT_RANGE_PATTERN:
+ p = "invalid repeat range {lower,upper}"; break;
+ case ONIGERR_TOO_BIG_NUMBER:
+ p = "too big number"; break;
+ case ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE:
+ p = "too big number for repeat range"; break;
+ case ONIGERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE:
+ p = "upper is smaller than lower in repeat range"; break;
+ case ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS:
+ p = "empty range in char class"; break;
+ case ONIGERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE:
+ p = "mismatch multibyte code length in char-class range"; break;
+ case ONIGERR_TOO_MANY_MULTI_BYTE_RANGES:
+ p = "too many multibyte code ranges are specified"; break;
+ case ONIGERR_TOO_SHORT_MULTI_BYTE_STRING:
+ p = "too short multibyte code string"; break;
+ case ONIGERR_TOO_BIG_BACKREF_NUMBER:
+ p = "too big backref number"; break;
+ case ONIGERR_INVALID_BACKREF:
+ p = "invalid backref number/name"; break;
+ case ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED:
+ p = "numbered backref/call is not allowed. (use name)"; break;
+ case ONIGERR_TOO_MANY_CAPTURES:
+ p = "too many captures"; break;
+ case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
+ p = "too big wide-char value"; break;
+ case ONIGERR_TOO_LONG_WIDE_CHAR_VALUE:
+ p = "too long wide-char value"; break;
+ case ONIGERR_INVALID_CODE_POINT_VALUE:
+ p = "invalid code point value"; break;
+ case ONIGERR_EMPTY_GROUP_NAME:
+ p = "group name is empty"; break;
+ case ONIGERR_INVALID_GROUP_NAME:
+ p = "invalid group name <%n>"; break;
+ case ONIGERR_INVALID_CHAR_IN_GROUP_NAME:
+ p = "invalid char in group name <%n>"; break;
+ case ONIGERR_UNDEFINED_NAME_REFERENCE:
+ p = "undefined name <%n> reference"; break;
+ case ONIGERR_UNDEFINED_GROUP_REFERENCE:
+ p = "undefined group <%n> reference"; break;
+ case ONIGERR_MULTIPLEX_DEFINED_NAME:
+ p = "multiplex defined name <%n>"; break;
+ case ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL:
+ p = "multiplex definition name <%n> call"; break;
+ case ONIGERR_NEVER_ENDING_RECURSION:
+ p = "never ending recursion"; break;
+ case ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY:
+ p = "group number is too big for capture history"; break;
+ case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
+ p = "invalid character property name {%n}"; break;
+ case ONIGERR_INVALID_IF_ELSE_SYNTAX:
+ p = "invalid if-else syntax"; break;
+ case ONIGERR_INVALID_ABSENT_GROUP_PATTERN:
+ p = "invalid absent group pattern"; break;
+ case ONIGERR_INVALID_ABSENT_GROUP_GENERATOR_PATTERN:
+ p = "invalid absent group generator pattern"; break;
+ case ONIGERR_INVALID_CALLOUT_PATTERN:
+ p = "invalid callout pattern"; break;
+ case ONIGERR_INVALID_CALLOUT_NAME:
+ p = "invalid callout name"; break;
+ case ONIGERR_UNDEFINED_CALLOUT_NAME:
+ p = "undefined callout name"; break;
+ case ONIGERR_INVALID_CALLOUT_BODY:
+ p = "invalid callout body"; break;
+ case ONIGERR_INVALID_CALLOUT_TAG_NAME:
+ p = "invalid callout tag name"; break;
+ case ONIGERR_INVALID_CALLOUT_ARG:
+ p = "invalid callout arg"; break;
+ case ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION:
+ p = "not supported encoding combination"; break;
+ case ONIGERR_INVALID_COMBINATION_OF_OPTIONS:
+ p = "invalid combination of options"; break;
+ case ONIGERR_LIBRARY_IS_NOT_INITIALIZED:
+ p = "library is not initialized"; break;
+
+ default:
+ p = "undefined error code"; break;
+ }
+
+ return (UChar* )p;
+}
+
+static void sprint_byte(char* s, unsigned int v)
+{
+ xsnprintf(s, 3, "%02x", (v & 0377));
+}
+
+static void sprint_byte_with_x(char* s, unsigned int v)
+{
+ xsnprintf(s, 5, "\\x%02x", (v & 0377));
+}
+
+static int to_ascii(OnigEncoding enc, UChar *s, UChar *end,
+ UChar buf[], int buf_size, int *is_over)
+{
+ int len;
+ UChar *p;
+ OnigCodePoint code;
+
+ if (!s) {
+ len = 0;
+ *is_over = 0;
+ }
+ else if (ONIGENC_MBC_MINLEN(enc) > 1) {
+ p = s;
+ len = 0;
+ while (p < end) {
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ if (code >= 0x80) {
+ if (code > 0xffff && len + 10 <= buf_size) {
+ sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 24));
+ sprint_byte((char*)(&(buf[len+4])), (unsigned int)(code >> 16));
+ sprint_byte((char*)(&(buf[len+6])), (unsigned int)(code >> 8));
+ sprint_byte((char*)(&(buf[len+8])), (unsigned int)code);
+ len += 10;
+ }
+ else if (len + 6 <= buf_size) {
+ sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 8));
+ sprint_byte((char*)(&(buf[len+4])), (unsigned int)code);
+ len += 6;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ buf[len++] = (UChar )code;
+ }
+
+ p += enclen(enc, p);
+ if (len >= buf_size) break;
+ }
+
+ *is_over = p < end;
+ }
+ else {
+ len = MIN((int )(end - s), buf_size);
+ xmemcpy(buf, s, (size_t )len);
+ *is_over = ((buf_size < (end - s)) ? 1 : 0);
+ }
+
+ return len;
+}
+
+
+extern int
+onig_is_error_code_needs_param(int code)
+{
+ switch (code) {
+ case ONIGERR_UNDEFINED_NAME_REFERENCE:
+ case ONIGERR_UNDEFINED_GROUP_REFERENCE:
+ case ONIGERR_MULTIPLEX_DEFINED_NAME:
+ case ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL:
+ case ONIGERR_INVALID_GROUP_NAME:
+ case ONIGERR_INVALID_CHAR_IN_GROUP_NAME:
+ case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* for ONIG_MAX_ERROR_MESSAGE_LEN */
+#define MAX_ERROR_PAR_LEN 30
+
+extern int ONIG_VARIADIC_FUNC_ATTR
+onig_error_code_to_str(UChar* s, int code, ...)
+{
+ UChar *p, *q;
+ OnigErrorInfo* einfo;
+ int len, is_over;
+ UChar parbuf[MAX_ERROR_PAR_LEN];
+ va_list vargs;
+
+ va_start(vargs, code);
+
+ switch (code) {
+ case ONIGERR_UNDEFINED_NAME_REFERENCE:
+ case ONIGERR_UNDEFINED_GROUP_REFERENCE:
+ case ONIGERR_MULTIPLEX_DEFINED_NAME:
+ case ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL:
+ case ONIGERR_INVALID_GROUP_NAME:
+ case ONIGERR_INVALID_CHAR_IN_GROUP_NAME:
+ case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
+ einfo = va_arg(vargs, OnigErrorInfo*);
+ len = to_ascii(einfo->enc, einfo->par, einfo->par_end,
+ parbuf, MAX_ERROR_PAR_LEN - 3, &is_over);
+ q = onig_error_code_to_format(code);
+ p = s;
+ while (*q != '\0') {
+ if (*q == '%') {
+ q++;
+ if (*q == 'n') { /* '%n': name */
+ xmemcpy(p, parbuf, len);
+ p += len;
+ if (is_over != 0) {
+ xmemcpy(p, "...", 3);
+ p += 3;
+ }
+ q++;
+ }
+ else
+ goto normal_char;
+ }
+ else {
+ normal_char:
+ *p++ = *q++;
+ }
+ }
+ *p = '\0';
+ len = (int )(p - s);
+ break;
+
+ default:
+ q = onig_error_code_to_format(code);
+ len = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, q);
+ xmemcpy(s, q, len);
+ s[len] = '\0';
+ break;
+ }
+
+ va_end(vargs);
+ return len;
+}
+
+
+void ONIG_VARIADIC_FUNC_ATTR
+onig_snprintf_with_pattern(UChar buf[], int bufsize, OnigEncoding enc,
+ UChar* pat, UChar* pat_end, const UChar *fmt, ...)
+{
+ int n, need, len;
+ UChar *p, *s, *bp;
+ UChar bs[6];
+ va_list args;
+
+ va_start(args, fmt);
+ n = xvsnprintf((char* )buf, bufsize, (const char* )fmt, args);
+ va_end(args);
+
+ need = (int )(pat_end - pat) * 4 + 4;
+
+ if (n + need < bufsize) {
+ xstrcat((char* )buf, ": /", bufsize);
+ s = buf + onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, buf);
+
+ p = pat;
+ while (p < pat_end) {
+ if (ONIGENC_IS_MBC_HEAD(enc, p)) {
+ len = enclen(enc, p);
+ if (ONIGENC_MBC_MINLEN(enc) == 1) {
+ while (len-- > 0) *s++ = *p++;
+ }
+ else { /* for UTF16/32 */
+ int blen;
+
+ while (len-- > 0) {
+ sprint_byte_with_x((char* )bs, (unsigned int )(*p++));
+ blen = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, bs);
+ bp = bs;
+ while (blen-- > 0) *s++ = *bp++;
+ }
+ }
+ }
+ else if (*p == '\\') {
+ *s++ = *p++;
+ len = enclen(enc, p);
+ while (len-- > 0) *s++ = *p++;
+ }
+ else if (*p == '/') {
+ *s++ = (unsigned char )'\\';
+ *s++ = *p++;
+ }
+ else if (!ONIGENC_IS_CODE_PRINT(enc, *p) &&
+ !ONIGENC_IS_CODE_SPACE(enc, *p)) {
+ sprint_byte_with_x((char* )bs, (unsigned int )(*p++));
+ len = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, bs);
+ bp = bs;
+ while (len-- > 0) *s++ = *bp++;
+ }
+ else {
+ *s++ = *p++;
+ }
+ }
+
+ *s++ = '/';
+ *s = '\0';
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regexec.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regexec.c
new file mode 100644
index 000000000..1ac961f45
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regexec.c
@@ -0,0 +1,6518 @@
+/**********************************************************************
+ regexec.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef ONIG_NO_PRINT
+#ifndef NEED_TO_INCLUDE_STDIO
+#define NEED_TO_INCLUDE_STDIO
+#endif
+#endif
+
+#include "regint.h"
+
+#define IS_MBC_WORD_ASCII_MODE(enc,s,end,mode) \
+ ((mode) == 0 ? ONIGENC_IS_MBC_WORD(enc,s,end) : ONIGENC_IS_MBC_WORD_ASCII(enc,s,end))
+
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+#define ONIGENC_IS_MBC_CRNL(enc,p,end) \
+ (ONIGENC_MBC_TO_CODE(enc,p,end) == 13 && \
+ ONIGENC_IS_MBC_NEWLINE(enc,(p+enclen(enc,p)),end))
+#endif
+
+#define CHECK_INTERRUPT_IN_MATCH
+
+#define STACK_MEM_START(reg, i) \
+ (MEM_STATUS_AT((reg)->push_mem_start, (i)) != 0 ? \
+ STACK_AT(mem_start_stk[i])->u.mem.pstr : (UChar* )((void* )(mem_start_stk[i])))
+
+#define STACK_MEM_END(reg, i) \
+ (MEM_STATUS_AT((reg)->push_mem_end, (i)) != 0 ? \
+ STACK_AT(mem_end_stk[i])->u.mem.pstr : (UChar* )((void* )(mem_end_stk[i])))
+
+static int forward_search(regex_t* reg, const UChar* str, const UChar* end, UChar* start, UChar* range, UChar** low, UChar** high, UChar** low_prev);
+
+static int
+search_in_range(regex_t* reg, const UChar* str, const UChar* end, const UChar* start, const UChar* range, /* match range */ const UChar* data_range, /* subject string range */ OnigRegion* region, OnigOptionType option, OnigMatchParam* mp);
+
+
+#ifdef USE_CALLOUT
+typedef struct {
+ int last_match_at_call_counter;
+ struct {
+ OnigType type;
+ OnigValue val;
+ } slot[ONIG_CALLOUT_DATA_SLOT_NUM];
+} CalloutData;
+#endif
+
+struct OnigMatchParamStruct {
+ unsigned int match_stack_limit;
+#ifdef USE_RETRY_LIMIT
+ unsigned long retry_limit_in_match;
+ unsigned long retry_limit_in_search;
+#endif
+#ifdef USE_CALLOUT
+ OnigCalloutFunc progress_callout_of_contents;
+ OnigCalloutFunc retraction_callout_of_contents;
+ int match_at_call_counter;
+ void* callout_user_data;
+ CalloutData* callout_data;
+ int callout_data_alloc_num;
+#endif
+};
+
+extern int
+onig_set_match_stack_limit_size_of_match_param(OnigMatchParam* param,
+ unsigned int limit)
+{
+ param->match_stack_limit = limit;
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_set_retry_limit_in_match_of_match_param(OnigMatchParam* param,
+ unsigned long limit)
+{
+#ifdef USE_RETRY_LIMIT
+ param->retry_limit_in_match = limit;
+ return ONIG_NORMAL;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+extern int
+onig_set_retry_limit_in_search_of_match_param(OnigMatchParam* param,
+ unsigned long limit)
+{
+#ifdef USE_RETRY_LIMIT
+ param->retry_limit_in_search = limit;
+ return ONIG_NORMAL;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+extern int
+onig_set_progress_callout_of_match_param(OnigMatchParam* param, OnigCalloutFunc f)
+{
+#ifdef USE_CALLOUT
+ param->progress_callout_of_contents = f;
+ return ONIG_NORMAL;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+extern int
+onig_set_retraction_callout_of_match_param(OnigMatchParam* param, OnigCalloutFunc f)
+{
+#ifdef USE_CALLOUT
+ param->retraction_callout_of_contents = f;
+ return ONIG_NORMAL;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+extern int
+onig_set_callout_user_data_of_match_param(OnigMatchParam* param, void* user_data)
+{
+#ifdef USE_CALLOUT
+ param->callout_user_data = user_data;
+ return ONIG_NORMAL;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+
+typedef struct {
+ void* stack_p;
+ int stack_n;
+ OnigOptionType options;
+ OnigRegion* region;
+ int ptr_num;
+ const UChar* start; /* search start position (for \G: BEGIN_POSITION) */
+ unsigned int match_stack_limit;
+#ifdef USE_RETRY_LIMIT
+ unsigned long retry_limit_in_match;
+ unsigned long retry_limit_in_search;
+ unsigned long retry_limit_in_search_counter;
+#endif
+ OnigMatchParam* mp;
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+ int best_len; /* for ONIG_OPTION_FIND_LONGEST */
+ UChar* best_s;
+#endif
+} MatchArg;
+
+
+#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH)
+
+/* arguments type */
+typedef enum {
+ ARG_SPECIAL = -1,
+ ARG_NON = 0,
+ ARG_RELADDR = 1,
+ ARG_ABSADDR = 2,
+ ARG_LENGTH = 3,
+ ARG_MEMNUM = 4,
+ ARG_OPTION = 5,
+ ARG_MODE = 6
+} OpArgType;
+
+typedef struct {
+ short int opcode;
+ char* name;
+} OpInfoType;
+
+static OpInfoType OpInfo[] = {
+ { OP_FINISH, "finish"},
+ { OP_END, "end"},
+ { OP_STR_1, "str_1"},
+ { OP_STR_2, "str_2"},
+ { OP_STR_3, "str_3"},
+ { OP_STR_4, "str_4"},
+ { OP_STR_5, "str_5"},
+ { OP_STR_N, "str_n"},
+ { OP_STR_MB2N1, "str_mb2-n1"},
+ { OP_STR_MB2N2, "str_mb2-n2"},
+ { OP_STR_MB2N3, "str_mb2-n3"},
+ { OP_STR_MB2N, "str_mb2-n"},
+ { OP_STR_MB3N, "str_mb3n"},
+ { OP_STR_MBN, "str_mbn"},
+ { OP_CCLASS, "cclass"},
+ { OP_CCLASS_MB, "cclass-mb"},
+ { OP_CCLASS_MIX, "cclass-mix"},
+ { OP_CCLASS_NOT, "cclass-not"},
+ { OP_CCLASS_MB_NOT, "cclass-mb-not"},
+ { OP_CCLASS_MIX_NOT, "cclass-mix-not"},
+ { OP_ANYCHAR, "anychar"},
+ { OP_ANYCHAR_ML, "anychar-ml"},
+ { OP_ANYCHAR_STAR, "anychar*"},
+ { OP_ANYCHAR_ML_STAR, "anychar-ml*"},
+ { OP_ANYCHAR_STAR_PEEK_NEXT, "anychar*-peek-next"},
+ { OP_ANYCHAR_ML_STAR_PEEK_NEXT, "anychar-ml*-peek-next"},
+ { OP_WORD, "word"},
+ { OP_WORD_ASCII, "word-ascii"},
+ { OP_NO_WORD, "not-word"},
+ { OP_NO_WORD_ASCII, "not-word-ascii"},
+ { OP_WORD_BOUNDARY, "word-boundary"},
+ { OP_NO_WORD_BOUNDARY, "not-word-boundary"},
+ { OP_WORD_BEGIN, "word-begin"},
+ { OP_WORD_END, "word-end"},
+ { OP_TEXT_SEGMENT_BOUNDARY, "text-segment-boundary"},
+ { OP_BEGIN_BUF, "begin-buf"},
+ { OP_END_BUF, "end-buf"},
+ { OP_BEGIN_LINE, "begin-line"},
+ { OP_END_LINE, "end-line"},
+ { OP_SEMI_END_BUF, "semi-end-buf"},
+ { OP_CHECK_POSITION, "check-position"},
+ { OP_BACKREF1, "backref1"},
+ { OP_BACKREF2, "backref2"},
+ { OP_BACKREF_N, "backref-n"},
+ { OP_BACKREF_N_IC, "backref-n-ic"},
+ { OP_BACKREF_MULTI, "backref_multi"},
+ { OP_BACKREF_MULTI_IC, "backref_multi-ic"},
+ { OP_BACKREF_WITH_LEVEL, "backref_with_level"},
+ { OP_BACKREF_WITH_LEVEL_IC, "backref_with_level-c"},
+ { OP_BACKREF_CHECK, "backref_check"},
+ { OP_BACKREF_CHECK_WITH_LEVEL, "backref_check_with_level"},
+ { OP_MEM_START_PUSH, "mem-start-push"},
+ { OP_MEM_START, "mem-start"},
+ { OP_MEM_END_PUSH, "mem-end-push"},
+#ifdef USE_CALL
+ { OP_MEM_END_PUSH_REC, "mem-end-push-rec"},
+#endif
+ { OP_MEM_END, "mem-end"},
+#ifdef USE_CALL
+ { OP_MEM_END_REC, "mem-end-rec"},
+#endif
+ { OP_FAIL, "fail"},
+ { OP_JUMP, "jump"},
+ { OP_PUSH, "push"},
+ { OP_PUSH_SUPER, "push-super"},
+ { OP_POP, "pop"},
+ { OP_POP_TO_MARK, "pop-to-mark"},
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ { OP_PUSH_OR_JUMP_EXACT1, "push-or-jump-e1"},
+#endif
+ { OP_PUSH_IF_PEEK_NEXT, "push-if-peek-next"},
+ { OP_REPEAT, "repeat"},
+ { OP_REPEAT_NG, "repeat-ng"},
+ { OP_REPEAT_INC, "repeat-inc"},
+ { OP_REPEAT_INC_NG, "repeat-inc-ng"},
+ { OP_EMPTY_CHECK_START, "empty-check-start"},
+ { OP_EMPTY_CHECK_END, "empty-check-end"},
+ { OP_EMPTY_CHECK_END_MEMST, "empty-check-end-memst"},
+#ifdef USE_CALL
+ { OP_EMPTY_CHECK_END_MEMST_PUSH,"empty-check-end-memst-push"},
+#endif
+ { OP_MOVE, "move"},
+ { OP_STEP_BACK_START, "step-back-start"},
+ { OP_STEP_BACK_NEXT, "step-back-next"},
+ { OP_CUT_TO_MARK, "cut-to-mark"},
+ { OP_MARK, "mark"},
+ { OP_SAVE_VAL, "save-val"},
+ { OP_UPDATE_VAR, "update-var"},
+#ifdef USE_CALL
+ { OP_CALL, "call"},
+ { OP_RETURN, "return"},
+#endif
+#ifdef USE_CALLOUT
+ { OP_CALLOUT_CONTENTS, "callout-contents"},
+ { OP_CALLOUT_NAME, "callout-name"},
+#endif
+ { -1, ""}
+};
+
+static char*
+op2name(int opcode)
+{
+ int i;
+
+ for (i = 0; OpInfo[i].opcode >= 0; i++) {
+ if (opcode == OpInfo[i].opcode) return OpInfo[i].name;
+ }
+
+ return "";
+}
+
+static void
+p_string(FILE* f, int len, UChar* s)
+{
+ fputs(":", f);
+ while (len-- > 0) { fputc(*s++, f); }
+}
+
+static void
+p_len_string(FILE* f, LengthType len, int mb_len, UChar* s)
+{
+ int x = len * mb_len;
+
+ fprintf(f, ":%d:", len);
+ while (x-- > 0) { fputc(*s++, f); }
+}
+
+static void
+p_rel_addr(FILE* f, RelAddrType rel_addr, Operation* p, Operation* start)
+{
+ RelAddrType curr = (RelAddrType )(p - start);
+
+ fprintf(f, "{%d/%d}", rel_addr, curr + rel_addr);
+}
+
+static int
+bitset_on_num(BitSetRef bs)
+{
+ int i, n;
+
+ n = 0;
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ if (BITSET_AT(bs, i)) n++;
+ }
+
+ return n;
+}
+
+
+#ifdef USE_DIRECT_THREADED_CODE
+#define GET_OPCODE(reg,index) (reg)->ocs[index]
+#else
+#define GET_OPCODE(reg,index) (reg)->ops[index].opcode
+#endif
+
+static void
+print_compiled_byte_code(FILE* f, regex_t* reg, int index,
+ Operation* start, OnigEncoding enc)
+{
+ int i, n;
+ RelAddrType addr;
+ LengthType len;
+ MemNumType mem;
+ OnigCodePoint code;
+ ModeType mode;
+ UChar *q;
+ Operation* p;
+ enum OpCode opcode;
+
+ p = reg->ops + index;
+
+ opcode = GET_OPCODE(reg, index);
+
+ fprintf(f, "%s", op2name(opcode));
+ switch (opcode) {
+ case OP_STR_1:
+ p_string(f, 1, p->exact.s); break;
+ case OP_STR_2:
+ p_string(f, 2, p->exact.s); break;
+ case OP_STR_3:
+ p_string(f, 3, p->exact.s); break;
+ case OP_STR_4:
+ p_string(f, 4, p->exact.s); break;
+ case OP_STR_5:
+ p_string(f, 5, p->exact.s); break;
+ case OP_STR_N:
+ len = p->exact_n.n;
+ p_string(f, len, p->exact_n.s); break;
+ case OP_STR_MB2N1:
+ p_string(f, 2, p->exact.s); break;
+ case OP_STR_MB2N2:
+ p_string(f, 4, p->exact.s); break;
+ case OP_STR_MB2N3:
+ p_string(f, 3, p->exact.s); break;
+ case OP_STR_MB2N:
+ len = p->exact_n.n;
+ p_len_string(f, len, 2, p->exact_n.s); break;
+ case OP_STR_MB3N:
+ len = p->exact_n.n;
+ p_len_string(f, len, 3, p->exact_n.s); break;
+ case OP_STR_MBN:
+ {
+ int mb_len;
+
+ mb_len = p->exact_len_n.len;
+ len = p->exact_len_n.n;
+ q = p->exact_len_n.s;
+ fprintf(f, ":%d:%d:", mb_len, len);
+ n = len * mb_len;
+ while (n-- > 0) { fputc(*q++, f); }
+ }
+ break;
+
+ case OP_CCLASS:
+ case OP_CCLASS_NOT:
+ n = bitset_on_num(p->cclass.bsp);
+ fprintf(f, ":%d", n);
+ break;
+ case OP_CCLASS_MB:
+ case OP_CCLASS_MB_NOT:
+ {
+ OnigCodePoint ncode;
+ OnigCodePoint* codes;
+
+ codes = (OnigCodePoint* )p->cclass_mb.mb;
+ GET_CODE_POINT(ncode, codes);
+ codes++;
+ GET_CODE_POINT(code, codes);
+ fprintf(f, ":%d:0x%x", ncode, code);
+ }
+ break;
+ case OP_CCLASS_MIX:
+ case OP_CCLASS_MIX_NOT:
+ {
+ OnigCodePoint ncode;
+ OnigCodePoint* codes;
+
+ codes = (OnigCodePoint* )p->cclass_mix.mb;
+ n = bitset_on_num(p->cclass_mix.bsp);
+
+ GET_CODE_POINT(ncode, codes);
+ codes++;
+ GET_CODE_POINT(code, codes);
+ fprintf(f, ":%d:%u:%u", n, code, ncode);
+ }
+ break;
+
+ case OP_ANYCHAR_STAR_PEEK_NEXT:
+ case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
+ p_string(f, 1, &(p->anychar_star_peek_next.c));
+ break;
+
+ case OP_WORD_BOUNDARY:
+ case OP_NO_WORD_BOUNDARY:
+ case OP_WORD_BEGIN:
+ case OP_WORD_END:
+ mode = p->word_boundary.mode;
+ fprintf(f, ":%d", mode);
+ break;
+
+ case OP_BACKREF_N:
+ case OP_BACKREF_N_IC:
+ mem = p->backref_n.n1;
+ fprintf(f, ":%d", mem);
+ break;
+ case OP_BACKREF_MULTI_IC:
+ case OP_BACKREF_MULTI:
+ case OP_BACKREF_CHECK:
+ fputs(" ", f);
+ n = p->backref_general.num;
+ for (i = 0; i < n; i++) {
+ mem = (n == 1) ? p->backref_general.n1 : p->backref_general.ns[i];
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", mem);
+ }
+ break;
+ case OP_BACKREF_WITH_LEVEL:
+ case OP_BACKREF_WITH_LEVEL_IC:
+ case OP_BACKREF_CHECK_WITH_LEVEL:
+ {
+ LengthType level;
+
+ level = p->backref_general.nest_level;
+ fprintf(f, ":%d", level);
+ fputs(" ", f);
+ n = p->backref_general.num;
+ for (i = 0; i < n; i++) {
+ mem = (n == 1) ? p->backref_general.n1 : p->backref_general.ns[i];
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", mem);
+ }
+ }
+ break;
+
+ case OP_MEM_START:
+ case OP_MEM_START_PUSH:
+ mem = p->memory_start.num;
+ fprintf(f, ":%d", mem);
+ break;
+
+ case OP_MEM_END:
+ case OP_MEM_END_PUSH:
+#ifdef USE_CALL
+ case OP_MEM_END_REC:
+ case OP_MEM_END_PUSH_REC:
+#endif
+ mem = p->memory_end.num;
+ fprintf(f, ":%d", mem);
+ break;
+
+ case OP_JUMP:
+ addr = p->jump.addr;
+ fputc(':', f);
+ p_rel_addr(f, addr, p, start);
+ break;
+
+ case OP_PUSH:
+ case OP_PUSH_SUPER:
+ addr = p->push.addr;
+ fputc(':', f);
+ p_rel_addr(f, addr, p, start);
+ break;
+
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ case OP_PUSH_OR_JUMP_EXACT1:
+ addr = p->push_or_jump_exact1.addr;
+ fputc(':', f);
+ p_rel_addr(f, addr, p, start);
+ p_string(f, 1, &(p->push_or_jump_exact1.c));
+ break;
+#endif
+
+ case OP_PUSH_IF_PEEK_NEXT:
+ addr = p->push_if_peek_next.addr;
+ fputc(':', f);
+ p_rel_addr(f, addr, p, start);
+ p_string(f, 1, &(p->push_if_peek_next.c));
+ break;
+
+ case OP_REPEAT:
+ case OP_REPEAT_NG:
+ mem = p->repeat.id;
+ addr = p->repeat.addr;
+ fprintf(f, ":%d:", mem);
+ p_rel_addr(f, addr, p, start);
+ break;
+
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ mem = p->repeat.id;
+ fprintf(f, ":%d", mem);
+ break;
+
+ case OP_EMPTY_CHECK_START:
+ mem = p->empty_check_start.mem;
+ fprintf(f, ":%d", mem);
+ break;
+ case OP_EMPTY_CHECK_END:
+ case OP_EMPTY_CHECK_END_MEMST:
+#ifdef USE_CALL
+ case OP_EMPTY_CHECK_END_MEMST_PUSH:
+#endif
+ mem = p->empty_check_end.mem;
+ fprintf(f, ":%d", mem);
+ break;
+
+#ifdef USE_CALL
+ case OP_CALL:
+ addr = p->call.addr;
+ fprintf(f, ":{/%d}", addr);
+ break;
+#endif
+
+ case OP_MOVE:
+ fprintf(f, ":%d", p->move.n);
+ break;
+
+ case OP_STEP_BACK_START:
+ addr = p->step_back_start.addr;
+ fprintf(f, ":%d:%d:",
+ p->step_back_start.initial,
+ p->step_back_start.remaining);
+ p_rel_addr(f, addr, p, start);
+ break;
+
+ case OP_POP_TO_MARK:
+ mem = p->pop_to_mark.id;
+ fprintf(f, ":%d", mem);
+ break;
+
+ case OP_CUT_TO_MARK:
+ {
+ int restore;
+
+ mem = p->cut_to_mark.id;
+ restore = p->cut_to_mark.restore_pos;
+ fprintf(f, ":%d:%d", mem, restore);
+ }
+ break;
+
+ case OP_MARK:
+ {
+ int save;
+
+ mem = p->mark.id;
+ save = p->mark.save_pos;
+ fprintf(f, ":%d:%d", mem, save);
+ }
+ break;
+
+ case OP_SAVE_VAL:
+ {
+ SaveType type;
+
+ type = p->save_val.type;
+ mem = p->save_val.id;
+ fprintf(f, ":%d:%d", type, mem);
+ }
+ break;
+
+ case OP_UPDATE_VAR:
+ {
+ UpdateVarType type;
+ int clear;
+
+ type = p->update_var.type;
+ mem = p->update_var.id;
+ clear = p->update_var.clear;
+ fprintf(f, ":%d:%d", type, mem);
+ if (type == UPDATE_VAR_RIGHT_RANGE_FROM_S_STACK ||
+ type == UPDATE_VAR_RIGHT_RANGE_FROM_STACK)
+ fprintf(f, ":%d", clear);
+ }
+ break;
+
+#ifdef USE_CALLOUT
+ case OP_CALLOUT_CONTENTS:
+ mem = p->callout_contents.num;
+ fprintf(f, ":%d", mem);
+ break;
+
+ case OP_CALLOUT_NAME:
+ {
+ int id;
+
+ id = p->callout_name.id;
+ mem = p->callout_name.num;
+ fprintf(f, ":%d:%d", id, mem);
+ }
+ break;
+#endif
+
+ case OP_TEXT_SEGMENT_BOUNDARY:
+ if (p->text_segment_boundary.not != 0)
+ fprintf(f, ":not");
+ break;
+
+ case OP_CHECK_POSITION:
+ switch (p->check_position.type) {
+ case CHECK_POSITION_SEARCH_START:
+ fprintf(f, ":search-start"); break;
+ case CHECK_POSITION_CURRENT_RIGHT_RANGE:
+ fprintf(f, ":current-right-range"); break;
+ default:
+ break;
+ };
+ break;
+
+ case OP_FINISH:
+ case OP_END:
+ case OP_ANYCHAR:
+ case OP_ANYCHAR_ML:
+ case OP_ANYCHAR_STAR:
+ case OP_ANYCHAR_ML_STAR:
+ case OP_WORD:
+ case OP_WORD_ASCII:
+ case OP_NO_WORD:
+ case OP_NO_WORD_ASCII:
+ case OP_BEGIN_BUF:
+ case OP_END_BUF:
+ case OP_BEGIN_LINE:
+ case OP_END_LINE:
+ case OP_SEMI_END_BUF:
+ case OP_BACKREF1:
+ case OP_BACKREF2:
+ case OP_FAIL:
+ case OP_POP:
+ case OP_STEP_BACK_NEXT:
+#ifdef USE_CALL
+ case OP_RETURN:
+#endif
+ break;
+
+ default:
+ fprintf(DBGFP, "print_compiled_byte_code: undefined code %d\n", opcode);
+ break;
+ }
+}
+#endif /* defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH) */
+
+#ifdef ONIG_DEBUG_COMPILE
+extern void
+onig_print_compiled_byte_code_list(FILE* f, regex_t* reg)
+{
+ Operation* bp;
+ Operation* start = reg->ops;
+ Operation* end = reg->ops + reg->ops_used;
+
+ fprintf(f, "push_mem_start: 0x%x, push_mem_end: 0x%x\n",
+ reg->push_mem_start, reg->push_mem_end);
+ fprintf(f, "code-length: %d\n", reg->ops_used);
+
+ bp = start;
+ while (bp < end) {
+ int pos = bp - start;
+
+ fprintf(f, "%4d: ", pos);
+ print_compiled_byte_code(f, reg, pos, start, reg->enc);
+ fprintf(f, "\n");
+ bp++;
+ }
+ fprintf(f, "\n");
+}
+#endif
+
+
+#ifdef USE_CAPTURE_HISTORY
+static void history_tree_free(OnigCaptureTreeNode* node);
+
+static void
+history_tree_clear(OnigCaptureTreeNode* node)
+{
+ int i;
+
+ if (IS_NULL(node)) return ;
+
+ for (i = 0; i < node->num_childs; i++) {
+ if (IS_NOT_NULL(node->childs[i])) {
+ history_tree_free(node->childs[i]);
+ }
+ }
+ for (i = 0; i < node->allocated; i++) {
+ node->childs[i] = (OnigCaptureTreeNode* )0;
+ }
+ node->num_childs = 0;
+ node->beg = ONIG_REGION_NOTPOS;
+ node->end = ONIG_REGION_NOTPOS;
+ node->group = -1;
+}
+
+static void
+history_tree_free(OnigCaptureTreeNode* node)
+{
+ history_tree_clear(node);
+ if (IS_NOT_NULL(node->childs)) xfree(node->childs);
+
+ xfree(node);
+}
+
+static void
+history_root_free(OnigRegion* r)
+{
+ if (IS_NULL(r->history_root)) return ;
+
+ history_tree_free(r->history_root);
+ r->history_root = (OnigCaptureTreeNode* )0;
+}
+
+static OnigCaptureTreeNode*
+history_node_new(void)
+{
+ OnigCaptureTreeNode* node;
+
+ node = (OnigCaptureTreeNode* )xmalloc(sizeof(OnigCaptureTreeNode));
+ CHECK_NULL_RETURN(node);
+
+ node->childs = (OnigCaptureTreeNode** )0;
+ node->allocated = 0;
+ node->num_childs = 0;
+ node->group = -1;
+ node->beg = ONIG_REGION_NOTPOS;
+ node->end = ONIG_REGION_NOTPOS;
+
+ return node;
+}
+
+static int
+history_tree_add_child(OnigCaptureTreeNode* parent, OnigCaptureTreeNode* child)
+{
+#define HISTORY_TREE_INIT_ALLOC_SIZE 8
+
+ if (parent->num_childs >= parent->allocated) {
+ int n, i;
+
+ if (IS_NULL(parent->childs)) {
+ n = HISTORY_TREE_INIT_ALLOC_SIZE;
+ parent->childs =
+ (OnigCaptureTreeNode** )xmalloc(sizeof(parent->childs[0]) * n);
+ }
+ else {
+ n = parent->allocated * 2;
+ parent->childs =
+ (OnigCaptureTreeNode** )xrealloc(parent->childs,
+ sizeof(parent->childs[0]) * n);
+ }
+ CHECK_NULL_RETURN_MEMERR(parent->childs);
+ for (i = parent->allocated; i < n; i++) {
+ parent->childs[i] = (OnigCaptureTreeNode* )0;
+ }
+ parent->allocated = n;
+ }
+
+ parent->childs[parent->num_childs] = child;
+ parent->num_childs++;
+ return 0;
+}
+
+static OnigCaptureTreeNode*
+history_tree_clone(OnigCaptureTreeNode* node)
+{
+ int i;
+ OnigCaptureTreeNode *clone, *child;
+
+ clone = history_node_new();
+ CHECK_NULL_RETURN(clone);
+
+ clone->beg = node->beg;
+ clone->end = node->end;
+ for (i = 0; i < node->num_childs; i++) {
+ child = history_tree_clone(node->childs[i]);
+ if (IS_NULL(child)) {
+ history_tree_free(clone);
+ return (OnigCaptureTreeNode* )0;
+ }
+ history_tree_add_child(clone, child);
+ }
+
+ return clone;
+}
+
+extern OnigCaptureTreeNode*
+onig_get_capture_tree(OnigRegion* region)
+{
+ return region->history_root;
+}
+#endif /* USE_CAPTURE_HISTORY */
+
+extern void
+onig_region_clear(OnigRegion* region)
+{
+ int i;
+
+ for (i = 0; i < region->num_regs; i++) {
+ region->beg[i] = region->end[i] = ONIG_REGION_NOTPOS;
+ }
+#ifdef USE_CAPTURE_HISTORY
+ history_root_free(region);
+#endif
+}
+
+extern int
+onig_region_resize(OnigRegion* region, int n)
+{
+ region->num_regs = n;
+
+ if (n < ONIG_NREGION)
+ n = ONIG_NREGION;
+
+ if (region->allocated == 0) {
+ region->beg = (int* )xmalloc(n * sizeof(int));
+ region->end = (int* )xmalloc(n * sizeof(int));
+
+ if (region->beg == 0 || region->end == 0)
+ return ONIGERR_MEMORY;
+
+ region->allocated = n;
+ }
+ else if (region->allocated < n) {
+ region->beg = (int* )xrealloc(region->beg, n * sizeof(int));
+ region->end = (int* )xrealloc(region->end, n * sizeof(int));
+
+ if (region->beg == 0 || region->end == 0)
+ return ONIGERR_MEMORY;
+
+ region->allocated = n;
+ }
+
+ return 0;
+}
+
+static int
+onig_region_resize_clear(OnigRegion* region, int n)
+{
+ int r;
+
+ r = onig_region_resize(region, n);
+ if (r != 0) return r;
+ onig_region_clear(region);
+ return 0;
+}
+
+extern int
+onig_region_set(OnigRegion* region, int at, int beg, int end)
+{
+ if (at < 0) return ONIGERR_INVALID_ARGUMENT;
+
+ if (at >= region->allocated) {
+ int r = onig_region_resize(region, at + 1);
+ if (r < 0) return r;
+ }
+
+ region->beg[at] = beg;
+ region->end[at] = end;
+ return 0;
+}
+
+extern void
+onig_region_init(OnigRegion* region)
+{
+ region->num_regs = 0;
+ region->allocated = 0;
+ region->beg = (int* )0;
+ region->end = (int* )0;
+ region->history_root = (OnigCaptureTreeNode* )0;
+}
+
+extern OnigRegion*
+onig_region_new(void)
+{
+ OnigRegion* r;
+
+ r = (OnigRegion* )xmalloc(sizeof(OnigRegion));
+ CHECK_NULL_RETURN(r);
+ onig_region_init(r);
+ return r;
+}
+
+extern void
+onig_region_free(OnigRegion* r, int free_self)
+{
+ if (r != 0) {
+ if (r->allocated > 0) {
+ if (r->beg) xfree(r->beg);
+ if (r->end) xfree(r->end);
+ r->allocated = 0;
+ }
+#ifdef USE_CAPTURE_HISTORY
+ history_root_free(r);
+#endif
+ if (free_self) xfree(r);
+ }
+}
+
+extern void
+onig_region_copy(OnigRegion* to, OnigRegion* from)
+{
+#define RREGC_SIZE (sizeof(int) * from->num_regs)
+ int i;
+
+ if (to == from) return;
+
+ if (to->allocated == 0) {
+ if (from->num_regs > 0) {
+ to->beg = (int* )xmalloc(RREGC_SIZE);
+ if (IS_NULL(to->beg)) return;
+ to->end = (int* )xmalloc(RREGC_SIZE);
+ if (IS_NULL(to->end)) return;
+ to->allocated = from->num_regs;
+ }
+ }
+ else if (to->allocated < from->num_regs) {
+ to->beg = (int* )xrealloc(to->beg, RREGC_SIZE);
+ if (IS_NULL(to->beg)) return;
+ to->end = (int* )xrealloc(to->end, RREGC_SIZE);
+ if (IS_NULL(to->end)) return;
+ to->allocated = from->num_regs;
+ }
+
+ for (i = 0; i < from->num_regs; i++) {
+ to->beg[i] = from->beg[i];
+ to->end[i] = from->end[i];
+ }
+ to->num_regs = from->num_regs;
+
+#ifdef USE_CAPTURE_HISTORY
+ history_root_free(to);
+
+ if (IS_NOT_NULL(from->history_root)) {
+ to->history_root = history_tree_clone(from->history_root);
+ }
+#endif
+}
+
+#ifdef USE_CALLOUT
+#define CALLOUT_BODY(func, ain, aname_id, anum, user, args, result) do { \
+ args.in = (ain);\
+ args.name_id = (aname_id);\
+ args.num = anum;\
+ args.regex = reg;\
+ args.string = str;\
+ args.string_end = end;\
+ args.start = sstart;\
+ args.right_range = right_range;\
+ args.current = s;\
+ args.retry_in_match_counter = retry_in_match_counter;\
+ args.msa = msa;\
+ args.stk_base = stk_base;\
+ args.stk = stk;\
+ args.mem_start_stk = mem_start_stk;\
+ args.mem_end_stk = mem_end_stk;\
+ result = (func)(&args, user);\
+} while (0)
+
+#define RETRACTION_CALLOUT(func, aname_id, anum, user) do {\
+ int result;\
+ OnigCalloutArgs args;\
+ CALLOUT_BODY(func, ONIG_CALLOUT_IN_RETRACTION, aname_id, anum, user, args, result);\
+ switch (result) {\
+ case ONIG_CALLOUT_FAIL:\
+ case ONIG_CALLOUT_SUCCESS:\
+ break;\
+ default:\
+ if (result > 0) {\
+ result = ONIGERR_INVALID_ARGUMENT;\
+ }\
+ best_len = result;\
+ goto match_at_end;\
+ break;\
+ }\
+} while(0)
+#endif
+
+
+/** stack **/
+#define INVALID_STACK_INDEX -1
+
+#define STK_ALT_FLAG 0x0001
+
+/* stack type */
+/* used by normal-POP */
+#define STK_SUPER_ALT STK_ALT_FLAG
+#define STK_ALT (0x0002 | STK_ALT_FLAG)
+
+/* handled by normal-POP */
+#define STK_MEM_START 0x0010
+#define STK_MEM_END 0x8030
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+#define STK_REPEAT_INC (0x0040 | STK_MASK_POP_HANDLED)
+#else
+#define STK_REPEAT_INC 0x0040
+#endif
+#ifdef USE_CALLOUT
+#define STK_CALLOUT 0x0070
+#endif
+
+/* avoided by normal-POP */
+#define STK_VOID 0x0000 /* for fill a blank */
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+#define STK_EMPTY_CHECK_START (0x3000 | STK_MASK_POP_HANDLED)
+#else
+#define STK_EMPTY_CHECK_START 0x3000
+#endif
+#define STK_EMPTY_CHECK_END 0x5000 /* for recursive call */
+#define STK_MEM_END_MARK 0x8100
+#define STK_CALL_FRAME (0x0400 | STK_MASK_POP_HANDLED)
+#define STK_RETURN (0x0500 | STK_MASK_POP_HANDLED)
+#define STK_SAVE_VAL 0x0600
+#define STK_MARK 0x0704
+
+/* stack type check mask */
+#define STK_MASK_POP_USED STK_ALT_FLAG
+#define STK_MASK_POP_HANDLED 0x0010
+#define STK_MASK_POP_HANDLED_TIL (STK_MASK_POP_HANDLED | 0x0004)
+#define STK_MASK_TO_VOID_TARGET 0x100e
+#define STK_MASK_MEM_END_OR_MARK 0x8000 /* MEM_END or MEM_END_MARK */
+
+typedef intptr_t StackIndex;
+
+typedef struct _StackType {
+ unsigned int type;
+ int zid;
+ union {
+ struct {
+ Operation* pcode; /* byte code position */
+ UChar* pstr; /* string position */
+ UChar* pstr_prev; /* previous char position of pstr */
+ } state;
+ struct {
+ int count;
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+ StackIndex prev_index; /* index of stack */
+#endif
+ } repeat_inc;
+ struct {
+ UChar *pstr; /* start/end position */
+ /* Following information is set, if this stack type is MEM-START */
+ StackIndex prev_start; /* prev. info (for backtrack "(...)*" ) */
+ StackIndex prev_end; /* prev. info (for backtrack "(...)*" ) */
+ } mem;
+ struct {
+ UChar *pstr; /* start position */
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+ StackIndex prev_index; /* index of stack */
+#endif
+ } empty_check;
+#ifdef USE_CALL
+ struct {
+ Operation *ret_addr; /* byte code position */
+ UChar *pstr; /* string position */
+ } call_frame;
+#endif
+ struct {
+ enum SaveType type;
+ UChar* v;
+ UChar* v2;
+ } val;
+#ifdef USE_CALLOUT
+ struct {
+ int num;
+ OnigCalloutFunc func;
+ } callout;
+#endif
+ } u;
+} StackType;
+
+#ifdef USE_CALLOUT
+
+struct OnigCalloutArgsStruct {
+ OnigCalloutIn in;
+ int name_id; /* name id or ONIG_NON_NAME_ID */
+ int num;
+ OnigRegex regex;
+ const OnigUChar* string;
+ const OnigUChar* string_end;
+ const OnigUChar* start;
+ const OnigUChar* right_range;
+ const OnigUChar* current; /* current matching position */
+ unsigned long retry_in_match_counter;
+
+ /* invisible to users */
+ MatchArg* msa;
+ StackType* stk_base;
+ StackType* stk;
+ StackIndex* mem_start_stk;
+ StackIndex* mem_end_stk;
+};
+
+#endif
+
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+
+#define PTR_NUM_SIZE(reg) ((reg)->num_repeat + (reg)->num_empty_check + ((reg)->num_mem + 1) * 2)
+#define UPDATE_FOR_STACK_REALLOC do{\
+ repeat_stk = (StackIndex* )alloc_base;\
+ empty_check_stk = (StackIndex* )(repeat_stk + reg->num_repeat);\
+ mem_start_stk = (StackIndex* )(empty_check_stk + reg->num_empty_check);\
+ mem_end_stk = mem_start_stk + num_mem + 1;\
+} while(0)
+
+#define SAVE_REPEAT_STK_VAR(sid) stk->u.repeat_inc.prev_index = repeat_stk[sid]
+#define LOAD_TO_REPEAT_STK_VAR(sid) repeat_stk[sid] = GET_STACK_INDEX(stk)
+#define POP_REPEAT_INC else if (stk->type == STK_REPEAT_INC) {repeat_stk[stk->zid] = stk->u.repeat_inc.prev_index;}
+
+#define SAVE_EMPTY_CHECK_STK_VAR(sid) stk->u.empty_check.prev_index = empty_check_stk[sid]
+#define LOAD_TO_EMPTY_CHECK_STK_VAR(sid) empty_check_stk[sid] = GET_STACK_INDEX(stk)
+#define POP_EMPTY_CHECK_START else if (stk->type == STK_EMPTY_CHECK_START) {empty_check_stk[stk->zid] = stk->u.empty_check.prev_index;}
+
+#else
+
+#define PTR_NUM_SIZE(reg) (((reg)->num_mem + 1) * 2)
+#define UPDATE_FOR_STACK_REALLOC do{\
+ mem_start_stk = (StackIndex* )alloc_base;\
+ mem_end_stk = mem_start_stk + num_mem + 1;\
+} while(0)
+
+#define SAVE_REPEAT_STK_VAR(sid)
+#define LOAD_TO_REPEAT_STK_VAR(sid)
+#define POP_REPEAT_INC
+
+#define SAVE_EMPTY_CHECK_STK_VAR(sid)
+#define LOAD_TO_EMPTY_CHECK_STK_VAR(sid)
+#define POP_EMPTY_CHECK_START
+
+#endif /* USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR */
+
+#ifdef USE_RETRY_LIMIT
+#define RETRY_IN_MATCH_ARG_INIT(msa,mpv) \
+ (msa).retry_limit_in_match = (mpv)->retry_limit_in_match;\
+ (msa).retry_limit_in_search = (mpv)->retry_limit_in_search;\
+ (msa).retry_limit_in_search_counter = 0;
+#else
+#define RETRY_IN_MATCH_ARG_INIT(msa,mpv)
+#endif
+
+#if defined(USE_CALL) && defined(SUBEXP_CALL_MAX_NEST_LEVEL)
+#define POP_CALL else if (stk->type == STK_RETURN) {subexp_call_nest_counter++;} else if (stk->type == STK_CALL_FRAME) {subexp_call_nest_counter--;}
+#else
+#define POP_CALL
+#endif
+
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+#define MATCH_ARG_INIT(msa, reg, arg_option, arg_region, arg_start, mpv) do { \
+ (msa).stack_p = (void* )0;\
+ (msa).options = (arg_option);\
+ (msa).region = (arg_region);\
+ (msa).start = (arg_start);\
+ (msa).match_stack_limit = (mpv)->match_stack_limit;\
+ RETRY_IN_MATCH_ARG_INIT(msa,mpv)\
+ (msa).mp = mpv;\
+ (msa).best_len = ONIG_MISMATCH;\
+ (msa).ptr_num = PTR_NUM_SIZE(reg);\
+} while(0)
+#else
+#define MATCH_ARG_INIT(msa, reg, arg_option, arg_region, arg_start, mpv) do { \
+ (msa).stack_p = (void* )0;\
+ (msa).options = (arg_option);\
+ (msa).region = (arg_region);\
+ (msa).start = (arg_start);\
+ (msa).match_stack_limit = (mpv)->match_stack_limit;\
+ RETRY_IN_MATCH_ARG_INIT(msa,mpv)\
+ (msa).mp = mpv;\
+ (msa).ptr_num = PTR_NUM_SIZE(reg);\
+} while(0)
+#endif
+
+#define MATCH_ARG_FREE(msa) if ((msa).stack_p) xfree((msa).stack_p)
+
+
+#define ALLOCA_PTR_NUM_LIMIT 50
+
+#define STACK_INIT(stack_num) do {\
+ if (msa->stack_p) {\
+ is_alloca = 0;\
+ alloc_base = msa->stack_p;\
+ stk_base = (StackType* )(alloc_base\
+ + (sizeof(StackIndex) * msa->ptr_num));\
+ stk = stk_base;\
+ stk_end = stk_base + msa->stack_n;\
+ }\
+ else if (msa->ptr_num > ALLOCA_PTR_NUM_LIMIT) {\
+ is_alloca = 0;\
+ alloc_base = (char* )xmalloc(sizeof(StackIndex) * msa->ptr_num\
+ + sizeof(StackType) * (stack_num));\
+ CHECK_NULL_RETURN_MEMERR(alloc_base);\
+ stk_base = (StackType* )(alloc_base\
+ + (sizeof(StackIndex) * msa->ptr_num));\
+ stk = stk_base;\
+ stk_end = stk_base + (stack_num);\
+ }\
+ else {\
+ is_alloca = 1;\
+ alloc_base = (char* )xalloca(sizeof(StackIndex) * msa->ptr_num\
+ + sizeof(StackType) * (stack_num));\
+ CHECK_NULL_RETURN_MEMERR(alloc_base);\
+ stk_base = (StackType* )(alloc_base\
+ + (sizeof(StackIndex) * msa->ptr_num));\
+ stk = stk_base;\
+ stk_end = stk_base + (stack_num);\
+ }\
+} while(0);
+
+
+#define STACK_SAVE(msa,is_alloca,alloc_base) do{\
+ (msa)->stack_n = (int )(stk_end - stk_base);\
+ if ((is_alloca) != 0) {\
+ size_t size = sizeof(StackIndex) * (msa)->ptr_num\
+ + sizeof(StackType) * (msa)->stack_n;\
+ (msa)->stack_p = xmalloc(size);\
+ CHECK_NULL_RETURN_MEMERR((msa)->stack_p);\
+ xmemcpy((msa)->stack_p, (alloc_base), size);\
+ }\
+ else {\
+ (msa)->stack_p = (alloc_base);\
+ };\
+} while(0)
+
+static unsigned int MatchStackLimit = DEFAULT_MATCH_STACK_LIMIT_SIZE;
+
+extern unsigned int
+onig_get_match_stack_limit_size(void)
+{
+ return MatchStackLimit;
+}
+
+extern int
+onig_set_match_stack_limit_size(unsigned int size)
+{
+ MatchStackLimit = size;
+ return 0;
+}
+
+#ifdef USE_RETRY_LIMIT
+
+static unsigned long RetryLimitInMatch = DEFAULT_RETRY_LIMIT_IN_MATCH;
+static unsigned long RetryLimitInSearch = DEFAULT_RETRY_LIMIT_IN_SEARCH;
+
+#define CHECK_RETRY_LIMIT_IN_MATCH do {\
+ if (++retry_in_match_counter > retry_limit_in_match) {\
+ MATCH_AT_ERROR_RETURN(retry_in_match_counter > msa->retry_limit_in_match ? ONIGERR_RETRY_LIMIT_IN_MATCH_OVER : ONIGERR_RETRY_LIMIT_IN_SEARCH_OVER); \
+ }\
+} while (0)
+
+#else
+
+#define CHECK_RETRY_LIMIT_IN_MATCH
+
+#endif /* USE_RETRY_LIMIT */
+
+extern unsigned long
+onig_get_retry_limit_in_match(void)
+{
+#ifdef USE_RETRY_LIMIT
+ return RetryLimitInMatch;
+#else
+ return 0;
+#endif
+}
+
+extern int
+onig_set_retry_limit_in_match(unsigned long n)
+{
+#ifdef USE_RETRY_LIMIT
+ RetryLimitInMatch = n;
+ return 0;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+extern unsigned long
+onig_get_retry_limit_in_search(void)
+{
+#ifdef USE_RETRY_LIMIT
+ return RetryLimitInSearch;
+#else
+ return 0;
+#endif
+}
+
+extern int
+onig_set_retry_limit_in_search(unsigned long n)
+{
+#ifdef USE_RETRY_LIMIT
+ RetryLimitInSearch = n;
+ return 0;
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
+
+#ifdef USE_CALLOUT
+static OnigCalloutFunc DefaultProgressCallout;
+static OnigCalloutFunc DefaultRetractionCallout;
+#endif
+
+extern OnigMatchParam*
+onig_new_match_param(void)
+{
+ OnigMatchParam* p;
+
+ p = (OnigMatchParam* )xmalloc(sizeof(*p));
+ if (IS_NOT_NULL(p)) {
+ onig_initialize_match_param(p);
+ }
+
+ return p;
+}
+
+extern void
+onig_free_match_param_content(OnigMatchParam* p)
+{
+#ifdef USE_CALLOUT
+ if (IS_NOT_NULL(p->callout_data)) {
+ xfree(p->callout_data);
+ p->callout_data = 0;
+ }
+#endif
+}
+
+extern void
+onig_free_match_param(OnigMatchParam* p)
+{
+ if (IS_NOT_NULL(p)) {
+ onig_free_match_param_content(p);
+ xfree(p);
+ }
+}
+
+extern int
+onig_initialize_match_param(OnigMatchParam* mp)
+{
+ mp->match_stack_limit = MatchStackLimit;
+#ifdef USE_RETRY_LIMIT
+ mp->retry_limit_in_match = RetryLimitInMatch;
+ mp->retry_limit_in_search = RetryLimitInSearch;
+#endif
+
+#ifdef USE_CALLOUT
+ mp->progress_callout_of_contents = DefaultProgressCallout;
+ mp->retraction_callout_of_contents = DefaultRetractionCallout;
+ mp->match_at_call_counter = 0;
+ mp->callout_user_data = 0;
+ mp->callout_data = 0;
+ mp->callout_data_alloc_num = 0;
+#endif
+
+ return ONIG_NORMAL;
+}
+
+#ifdef USE_CALLOUT
+
+static int
+adjust_match_param(regex_t* reg, OnigMatchParam* mp)
+{
+ RegexExt* ext = reg->extp;
+
+ mp->match_at_call_counter = 0;
+
+ if (IS_NULL(ext) || ext->callout_num == 0) return ONIG_NORMAL;
+
+ if (ext->callout_num > mp->callout_data_alloc_num) {
+ CalloutData* d;
+ size_t n = ext->callout_num * sizeof(*d);
+ if (IS_NOT_NULL(mp->callout_data))
+ d = (CalloutData* )xrealloc(mp->callout_data, n);
+ else
+ d = (CalloutData* )xmalloc(n);
+ CHECK_NULL_RETURN_MEMERR(d);
+
+ mp->callout_data = d;
+ mp->callout_data_alloc_num = ext->callout_num;
+ }
+
+ xmemset(mp->callout_data, 0, mp->callout_data_alloc_num * sizeof(CalloutData));
+ return ONIG_NORMAL;
+}
+
+#define ADJUST_MATCH_PARAM(reg, mp) \
+ r = adjust_match_param(reg, mp);\
+ if (r != ONIG_NORMAL) return r;
+
+#define CALLOUT_DATA_AT_NUM(mp, num) ((mp)->callout_data + ((num) - 1))
+
+extern int
+onig_check_callout_data_and_clear_old_values(OnigCalloutArgs* args)
+{
+ OnigMatchParam* mp;
+ int num;
+ CalloutData* d;
+
+ mp = args->msa->mp;
+ num = args->num;
+
+ d = CALLOUT_DATA_AT_NUM(mp, num);
+ if (d->last_match_at_call_counter != mp->match_at_call_counter) {
+ xmemset(d, 0, sizeof(*d));
+ d->last_match_at_call_counter = mp->match_at_call_counter;
+ return d->last_match_at_call_counter;
+ }
+
+ return 0;
+}
+
+extern int
+onig_get_callout_data_dont_clear_old(regex_t* reg, OnigMatchParam* mp,
+ int callout_num, int slot,
+ OnigType* type, OnigValue* val)
+{
+ OnigType t;
+ CalloutData* d;
+
+ if (callout_num <= 0) return ONIGERR_INVALID_ARGUMENT;
+
+ d = CALLOUT_DATA_AT_NUM(mp, callout_num);
+ t = d->slot[slot].type;
+ if (IS_NOT_NULL(type)) *type = t;
+ if (IS_NOT_NULL(val)) *val = d->slot[slot].val;
+ return (t == ONIG_TYPE_VOID ? 1 : ONIG_NORMAL);
+}
+
+extern int
+onig_get_callout_data_by_callout_args_self_dont_clear_old(OnigCalloutArgs* args,
+ int slot, OnigType* type,
+ OnigValue* val)
+{
+ return onig_get_callout_data_dont_clear_old(args->regex, args->msa->mp,
+ args->num, slot, type, val);
+}
+
+extern int
+onig_get_callout_data(regex_t* reg, OnigMatchParam* mp,
+ int callout_num, int slot,
+ OnigType* type, OnigValue* val)
+{
+ OnigType t;
+ CalloutData* d;
+
+ if (callout_num <= 0) return ONIGERR_INVALID_ARGUMENT;
+
+ d = CALLOUT_DATA_AT_NUM(mp, callout_num);
+ if (d->last_match_at_call_counter != mp->match_at_call_counter) {
+ xmemset(d, 0, sizeof(*d));
+ d->last_match_at_call_counter = mp->match_at_call_counter;
+ }
+
+ t = d->slot[slot].type;
+ if (IS_NOT_NULL(type)) *type = t;
+ if (IS_NOT_NULL(val)) *val = d->slot[slot].val;
+ return (t == ONIG_TYPE_VOID ? 1 : ONIG_NORMAL);
+}
+
+extern int
+onig_get_callout_data_by_tag(regex_t* reg, OnigMatchParam* mp,
+ const UChar* tag, const UChar* tag_end, int slot,
+ OnigType* type, OnigValue* val)
+{
+ int num;
+
+ num = onig_get_callout_num_by_tag(reg, tag, tag_end);
+ if (num < 0) return num;
+ if (num == 0) return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ return onig_get_callout_data(reg, mp, num, slot, type, val);
+}
+
+extern int
+onig_get_callout_data_by_callout_args(OnigCalloutArgs* args,
+ int callout_num, int slot,
+ OnigType* type, OnigValue* val)
+{
+ return onig_get_callout_data(args->regex, args->msa->mp, callout_num, slot,
+ type, val);
+}
+
+extern int
+onig_get_callout_data_by_callout_args_self(OnigCalloutArgs* args,
+ int slot, OnigType* type, OnigValue* val)
+{
+ return onig_get_callout_data(args->regex, args->msa->mp, args->num, slot,
+ type, val);
+}
+
+extern int
+onig_set_callout_data(regex_t* reg, OnigMatchParam* mp,
+ int callout_num, int slot,
+ OnigType type, OnigValue* val)
+{
+ CalloutData* d;
+
+ if (callout_num <= 0) return ONIGERR_INVALID_ARGUMENT;
+
+ d = CALLOUT_DATA_AT_NUM(mp, callout_num);
+ d->slot[slot].type = type;
+ d->slot[slot].val = *val;
+ d->last_match_at_call_counter = mp->match_at_call_counter;
+
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_set_callout_data_by_tag(regex_t* reg, OnigMatchParam* mp,
+ const UChar* tag, const UChar* tag_end, int slot,
+ OnigType type, OnigValue* val)
+{
+ int num;
+
+ num = onig_get_callout_num_by_tag(reg, tag, tag_end);
+ if (num < 0) return num;
+ if (num == 0) return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ return onig_set_callout_data(reg, mp, num, slot, type, val);
+}
+
+extern int
+onig_set_callout_data_by_callout_args(OnigCalloutArgs* args,
+ int callout_num, int slot,
+ OnigType type, OnigValue* val)
+{
+ return onig_set_callout_data(args->regex, args->msa->mp, callout_num, slot,
+ type, val);
+}
+
+extern int
+onig_set_callout_data_by_callout_args_self(OnigCalloutArgs* args,
+ int slot, OnigType type, OnigValue* val)
+{
+ return onig_set_callout_data(args->regex, args->msa->mp, args->num, slot,
+ type, val);
+}
+
+#else
+#define ADJUST_MATCH_PARAM(reg, mp)
+#endif /* USE_CALLOUT */
+
+
+static int
+stack_double(int* is_alloca, char** arg_alloc_base,
+ StackType** arg_stk_base, StackType** arg_stk_end,
+ StackType** arg_stk, MatchArg* msa)
+{
+ unsigned int n;
+ int used;
+ size_t size;
+ size_t new_size;
+ char* alloc_base;
+ char* new_alloc_base;
+ StackType *stk_base, *stk_end, *stk;
+
+ alloc_base = *arg_alloc_base;
+ stk_base = *arg_stk_base;
+ stk_end = *arg_stk_end;
+ stk = *arg_stk;
+
+ n = (unsigned int )(stk_end - stk_base);
+ size = sizeof(StackIndex) * msa->ptr_num + sizeof(StackType) * n;
+ n *= 2;
+ new_size = sizeof(StackIndex) * msa->ptr_num + sizeof(StackType) * n;
+ if (*is_alloca != 0) {
+ new_alloc_base = (char* )xmalloc(new_size);
+ if (IS_NULL(new_alloc_base)) {
+ STACK_SAVE(msa, *is_alloca, alloc_base);
+ return ONIGERR_MEMORY;
+ }
+ xmemcpy(new_alloc_base, alloc_base, size);
+ *is_alloca = 0;
+ }
+ else {
+ if (msa->match_stack_limit != 0 && n > msa->match_stack_limit) {
+ if ((unsigned int )(stk_end - stk_base) == msa->match_stack_limit) {
+ STACK_SAVE(msa, *is_alloca, alloc_base);
+ return ONIGERR_MATCH_STACK_LIMIT_OVER;
+ }
+ else
+ n = msa->match_stack_limit;
+ }
+ new_alloc_base = (char* )xrealloc(alloc_base, new_size);
+ if (IS_NULL(new_alloc_base)) {
+ STACK_SAVE(msa, *is_alloca, alloc_base);
+ return ONIGERR_MEMORY;
+ }
+ }
+
+ alloc_base = new_alloc_base;
+ used = (int )(stk - stk_base);
+ *arg_alloc_base = alloc_base;
+ *arg_stk_base = (StackType* )(alloc_base
+ + (sizeof(StackIndex) * msa->ptr_num));
+ *arg_stk = *arg_stk_base + used;
+ *arg_stk_end = *arg_stk_base + n;
+ return 0;
+}
+
+#define STACK_ENSURE(n) do {\
+ if ((int )(stk_end - stk) < (n)) {\
+ int r = stack_double(&is_alloca, &alloc_base, &stk_base, &stk_end, &stk, msa);\
+ if (r != 0) return r;\
+ UPDATE_FOR_STACK_REALLOC;\
+ }\
+} while(0)
+
+#define STACK_AT(index) (stk_base + (index))
+#define GET_STACK_INDEX(stk) ((stk) - stk_base)
+
+#define STACK_PUSH_TYPE(stack_type) do {\
+ STACK_ENSURE(1);\
+ stk->type = (stack_type);\
+ STACK_INC;\
+} while(0)
+
+#define IS_TO_VOID_TARGET(stk) (((stk)->type & STK_MASK_TO_VOID_TARGET) != 0)
+
+#define STACK_PUSH(stack_type,pat,s,sprev) do {\
+ STACK_ENSURE(1);\
+ stk->type = (stack_type);\
+ stk->u.state.pcode = (pat);\
+ stk->u.state.pstr = (s);\
+ stk->u.state.pstr_prev = (sprev);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_WITH_ZID(stack_type,pat,s,sprev,id) do {\
+ STACK_ENSURE(1);\
+ stk->type = (stack_type);\
+ stk->zid = (int )(id);\
+ stk->u.state.pcode = (pat);\
+ stk->u.state.pstr = (s);\
+ stk->u.state.pstr_prev = (sprev);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_ENSURED(stack_type,pat) do {\
+ stk->type = (stack_type);\
+ stk->u.state.pcode = (pat);\
+ STACK_INC;\
+} while(0)
+
+#ifdef ONIG_DEBUG_MATCH
+#define STACK_PUSH_BOTTOM(stack_type,pat) do {\
+ stk->type = (stack_type);\
+ stk->u.state.pcode = (pat);\
+ stk->u.state.pstr = s;\
+ stk->u.state.pstr_prev = sprev;\
+ STACK_INC;\
+} while (0)
+#else
+#define STACK_PUSH_BOTTOM(stack_type,pat) do {\
+ stk->type = (stack_type);\
+ stk->u.state.pcode = (pat);\
+ STACK_INC;\
+} while (0)
+#endif
+
+#define STACK_PUSH_ALT(pat,s,sprev) STACK_PUSH(STK_ALT,pat,s,sprev)
+#define STACK_PUSH_SUPER_ALT(pat,s,sprev) STACK_PUSH(STK_SUPER_ALT,pat,s,sprev)
+#define STACK_PUSH_ALT_WITH_ZID(pat,s,sprev,id) \
+ STACK_PUSH_WITH_ZID(STK_ALT,pat,s,sprev,id)
+
+#if 0
+#define STACK_PUSH_REPEAT(sid, pat) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_REPEAT;\
+ stk->zid = (sid);\
+ stk->u.repeat.pcode = (pat);\
+ STACK_INC;\
+} while(0)
+#endif
+
+#define STACK_PUSH_REPEAT_INC(sid, ct) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_REPEAT_INC;\
+ stk->zid = (sid);\
+ stk->u.repeat_inc.count = (ct);\
+ SAVE_REPEAT_STK_VAR(sid);\
+ LOAD_TO_REPEAT_STK_VAR(sid);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_MEM_START(mnum, s) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_MEM_START;\
+ stk->zid = (mnum);\
+ stk->u.mem.pstr = (s);\
+ stk->u.mem.prev_start = mem_start_stk[mnum];\
+ stk->u.mem.prev_end = mem_end_stk[mnum];\
+ mem_start_stk[mnum] = GET_STACK_INDEX(stk);\
+ mem_end_stk[mnum] = INVALID_STACK_INDEX;\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_MEM_END(mnum, s) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_MEM_END;\
+ stk->zid = (mnum);\
+ stk->u.mem.pstr = (s);\
+ stk->u.mem.prev_start = mem_start_stk[mnum];\
+ stk->u.mem.prev_end = mem_end_stk[mnum];\
+ mem_end_stk[mnum] = GET_STACK_INDEX(stk);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_MEM_END_MARK(mnum) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_MEM_END_MARK;\
+ stk->zid = (mnum);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_GET_MEM_START(mnum, k) do {\
+ int level = 0;\
+ k = stk;\
+ while (k > stk_base) {\
+ k--;\
+ if ((k->type & STK_MASK_MEM_END_OR_MARK) != 0 \
+ && k->zid == (mnum)) {\
+ level++;\
+ }\
+ else if (k->type == STK_MEM_START && k->zid == (mnum)) {\
+ if (level == 0) break;\
+ level--;\
+ }\
+ }\
+} while(0)
+
+#define STACK_GET_MEM_RANGE(k, mnum, start, end) do {\
+ int level = 0;\
+ while (k < stk) {\
+ if (k->type == STK_MEM_START && k->u.mem.num == (mnum)) {\
+ if (level == 0) (start) = k->u.mem.pstr;\
+ level++;\
+ }\
+ else if (k->type == STK_MEM_END && k->u.mem.num == (mnum)) {\
+ level--;\
+ if (level == 0) {\
+ (end) = k->u.mem.pstr;\
+ break;\
+ }\
+ }\
+ k++;\
+ }\
+} while(0)
+
+#define STACK_PUSH_EMPTY_CHECK_START(cnum, s) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_EMPTY_CHECK_START;\
+ stk->zid = (cnum);\
+ stk->u.empty_check.pstr = (s);\
+ SAVE_EMPTY_CHECK_STK_VAR(cnum);\
+ LOAD_TO_EMPTY_CHECK_STK_VAR(cnum);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_EMPTY_CHECK_END(cnum) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_EMPTY_CHECK_END;\
+ stk->zid = (cnum);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_CALL_FRAME(pat) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_CALL_FRAME;\
+ stk->u.call_frame.ret_addr = (pat);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_RETURN do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_RETURN;\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_MARK(sid) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_MARK;\
+ stk->zid = (sid);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_MARK_WITH_POS(sid, s, sprev) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_MARK;\
+ stk->zid = (sid);\
+ stk->u.val.v = (UChar* )(s);\
+ stk->u.val.v2 = (sprev);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_SAVE_VAL(sid, stype, sval) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_SAVE_VAL;\
+ stk->zid = (sid);\
+ stk->u.val.type = (stype);\
+ stk->u.val.v = (UChar* )(sval);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_SAVE_VAL_WITH_SPREV(sid, stype, sval) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_SAVE_VAL;\
+ stk->zid = (sid);\
+ stk->u.val.type = (stype);\
+ stk->u.val.v = (UChar* )(sval);\
+ stk->u.val.v2 = sprev;\
+ STACK_INC;\
+} while(0)
+
+#define STACK_GET_SAVE_VAL_TYPE_LAST(stype, sval) do {\
+ StackType *k = stk;\
+ while (k > stk_base) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_GET_SAVE_VAL_TYPE_LAST"); \
+ if (k->type == STK_SAVE_VAL && k->u.val.type == (stype)) {\
+ (sval) = k->u.val.v;\
+ break;\
+ }\
+ }\
+} while (0)
+
+#define STACK_GET_SAVE_VAL_TYPE_LAST_ID(stype, sid, sval, clear) do {\
+ int level = 0;\
+ StackType *k = stk;\
+ while (k > stk_base) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_GET_SAVE_VAL_TYPE_LAST_ID"); \
+ if (k->type == STK_SAVE_VAL && k->u.val.type == (stype)\
+ && k->zid == (sid)) {\
+ if (level == 0) {\
+ (sval) = k->u.val.v;\
+ if (clear != 0) k->type = STK_VOID;\
+ break;\
+ }\
+ }\
+ else if (k->type == STK_CALL_FRAME)\
+ level--;\
+ else if (k->type == STK_RETURN)\
+ level++;\
+ }\
+} while (0)
+
+#define STACK_GET_SAVE_VAL_TYPE_LAST_ID_WITH_SPREV(stype, sid, sval) do { \
+ int level = 0;\
+ StackType *k = stk;\
+ while (k > stk_base) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_GET_SAVE_VAL_TYPE_LAST_ID"); \
+ if (k->type == STK_SAVE_VAL && k->u.val.type == (stype)\
+ && k->zid == (sid)) {\
+ if (level == 0) {\
+ (sval) = k->u.val.v;\
+ sprev = k->u.val.v2;\
+ break;\
+ }\
+ }\
+ else if (k->type == STK_CALL_FRAME)\
+ level--;\
+ else if (k->type == STK_RETURN)\
+ level++;\
+ }\
+} while (0)
+
+#define STACK_PUSH_CALLOUT_CONTENTS(anum, func) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_CALLOUT;\
+ stk->zid = ONIG_NON_NAME_ID;\
+ stk->u.callout.num = (anum);\
+ stk->u.callout.func = (func);\
+ STACK_INC;\
+} while(0)
+
+#define STACK_PUSH_CALLOUT_NAME(aid, anum, func) do {\
+ STACK_ENSURE(1);\
+ stk->type = STK_CALLOUT;\
+ stk->zid = (aid);\
+ stk->u.callout.num = (anum);\
+ stk->u.callout.func = (func);\
+ STACK_INC;\
+} while(0)
+
+#ifdef ONIG_DEBUG
+#define STACK_BASE_CHECK(p, at) \
+ if ((p) < stk_base) {\
+ fprintf(DBGFP, "at %s\n", at);\
+ MATCH_AT_ERROR_RETURN(ONIGERR_STACK_BUG);\
+ }
+#else
+#define STACK_BASE_CHECK(p, at)
+#endif
+
+#define STACK_POP_ONE do {\
+ stk--;\
+ STACK_BASE_CHECK(stk, "STACK_POP_ONE"); \
+} while(0)
+
+
+#ifdef USE_CALLOUT
+#define POP_CALLOUT_CASE \
+ else if (stk->type == STK_CALLOUT) {\
+ RETRACTION_CALLOUT(stk->u.callout.func, stk->zid, stk->u.callout.num, msa->mp->callout_user_data);\
+ }
+#else
+#define POP_CALLOUT_CASE
+#endif
+
+#define STACK_POP do {\
+ switch (pop_level) {\
+ case STACK_POP_LEVEL_FREE:\
+ while (1) {\
+ stk--;\
+ STACK_BASE_CHECK(stk, "STACK_POP"); \
+ if ((stk->type & STK_MASK_POP_USED) != 0) break;\
+ }\
+ break;\
+ case STACK_POP_LEVEL_MEM_START:\
+ while (1) {\
+ stk--;\
+ STACK_BASE_CHECK(stk, "STACK_POP 2"); \
+ if ((stk->type & STK_MASK_POP_USED) != 0) break;\
+ else if (stk->type == STK_MEM_START) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ }\
+ break;\
+ default:\
+ while (1) {\
+ stk--;\
+ STACK_BASE_CHECK(stk, "STACK_POP 3"); \
+ if ((stk->type & STK_MASK_POP_USED) != 0) break;\
+ else if ((stk->type & STK_MASK_POP_HANDLED) != 0) {\
+ if (stk->type == STK_MEM_START) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ else if (stk->type == STK_MEM_END) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ POP_REPEAT_INC \
+ POP_EMPTY_CHECK_START \
+ POP_CALL \
+ POP_CALLOUT_CASE\
+ }\
+ }\
+ break;\
+ }\
+} while(0)
+
+#define STACK_POP_TO_MARK(sid) do {\
+ while (1) {\
+ stk--;\
+ STACK_BASE_CHECK(stk, "STACK_POP_TO_MARK");\
+ if ((stk->type & STK_MASK_POP_HANDLED_TIL) != 0) {\
+ if (stk->type == STK_MARK) {\
+ if (stk->zid == (sid)) break;\
+ }\
+ else {\
+ if (stk->type == STK_MEM_START) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ else if (stk->type == STK_MEM_END) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ POP_REPEAT_INC \
+ POP_EMPTY_CHECK_START \
+ POP_CALL \
+ /* Don't call callout here because negation of total success by (?!..) (?<!..) */\
+ }\
+ }\
+ }\
+} while(0)
+
+
+#define POP_TIL_BODY(aname, til_type) do {\
+ while (1) {\
+ stk--;\
+ STACK_BASE_CHECK(stk, (aname));\
+ if ((stk->type & STK_MASK_POP_HANDLED_TIL) != 0) {\
+ if (stk->type == (til_type)) break;\
+ else {\
+ if (stk->type == STK_MEM_START) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ else if (stk->type == STK_MEM_END) {\
+ mem_start_stk[stk->zid] = stk->u.mem.prev_start;\
+ mem_end_stk[stk->zid] = stk->u.mem.prev_end;\
+ }\
+ POP_REPEAT_INC \
+ POP_EMPTY_CHECK_START \
+ POP_CALL \
+ /* Don't call callout here because negation of total success by (?!..) (?<!..) */\
+ }\
+ }\
+ }\
+} while(0)
+
+
+#define STACK_TO_VOID_TO_MARK(k,sid) do {\
+ k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_TO_VOID_TO_MARK");\
+ if (IS_TO_VOID_TARGET(k)) {\
+ if (k->type == STK_MARK) {\
+ if (k->zid == (sid)) {\
+ k->type = STK_VOID;\
+ break;\
+ } /* don't void different id mark */ \
+ }\
+ else\
+ k->type = STK_VOID;\
+ }\
+ }\
+} while(0)
+
+#define EMPTY_CHECK_START_SEARCH(sid, k) do {\
+ k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "EMPTY_CHECK_START_SEARCH"); \
+ if (k->type == STK_EMPTY_CHECK_START) {\
+ if (k->zid == (sid)) break;\
+ }\
+ }\
+} while(0)
+
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+
+#define GET_EMPTY_CHECK_START(sid, k) do {\
+ if (reg->num_call == 0) {\
+ k = STACK_AT(empty_check_stk[sid]);\
+ }\
+ else {\
+ EMPTY_CHECK_START_SEARCH(sid, k);\
+ }\
+} while(0)
+#else
+
+#define GET_EMPTY_CHECK_START(sid, k) EMPTY_CHECK_START_SEARCH(sid, k)
+
+#endif
+
+
+#define STACK_EMPTY_CHECK(isnull, sid, s) do {\
+ StackType* k;\
+ GET_EMPTY_CHECK_START(sid, k);\
+ (isnull) = (k->u.empty_check.pstr == (s));\
+} while(0)
+
+#define STACK_MEM_START_GET_PREV_END_ADDR(k /* STK_MEM_START*/, reg, addr) do {\
+ if (k->u.mem.prev_end == INVALID_STACK_INDEX) {\
+ (addr) = 0;\
+ }\
+ else {\
+ if (MEM_STATUS_AT((reg)->push_mem_end, k->zid))\
+ (addr) = STACK_AT(k->u.mem.prev_end)->u.mem.pstr;\
+ else\
+ (addr) = (UChar* )k->u.mem.prev_end;\
+ }\
+} while (0)
+
+#ifdef USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT
+#define STACK_EMPTY_CHECK_MEM(isnull, sid, s, reg) do {\
+ StackType* k;\
+ GET_EMPTY_CHECK_START(sid, k);\
+ if (k->u.empty_check.pstr != (s)) {\
+ (isnull) = 0;\
+ }\
+ else {\
+ UChar* endp;\
+ (isnull) = 1;\
+ while (k < stk) {\
+ if (k->type == STK_MEM_START &&\
+ MEM_STATUS_LIMIT_AT((reg)->empty_status_mem, k->zid)) {\
+ STACK_MEM_START_GET_PREV_END_ADDR(k, reg, endp);\
+ if (endp == 0) {\
+ (isnull) = 0; break;\
+ }\
+ else if (STACK_AT(k->u.mem.prev_start)->u.mem.pstr != endp) {\
+ (isnull) = 0; break;\
+ }\
+ else if (endp != s) {\
+ (isnull) = -1; /* empty, but position changed */ \
+ }\
+ }\
+ k++;\
+ }\
+ }\
+} while(0)
+
+#define STACK_EMPTY_CHECK_MEM_REC(isnull,sid,s,reg) do {\
+ int level = 0;\
+ StackType* k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_EMPTY_CHECK_MEM_REC");\
+ if (k->type == STK_EMPTY_CHECK_START) {\
+ if (k->zid == (sid)) {\
+ if (level == 0) {\
+ if (k->u.empty_check.pstr != (s)) {\
+ (isnull) = 0;\
+ break;\
+ }\
+ else {\
+ UChar* endp;\
+ (isnull) = 1;\
+ while (k < stk) {\
+ if (k->type == STK_MEM_START) {\
+ if (level == 0 && \
+ MEM_STATUS_LIMIT_AT((reg)->empty_status_mem, k->zid) !=0) {\
+ STACK_MEM_START_GET_PREV_END_ADDR(k, reg, endp);\
+ if (endp == 0) {\
+ (isnull) = 0; break;\
+ }\
+ else if (STACK_AT(k->u.mem.prev_start)->u.mem.pstr != endp) { \
+ (isnull) = 0; break;\
+ }\
+ else if (endp != s) {\
+ (isnull) = -1; /* empty, but position changed */\
+ }\
+ }\
+ }\
+ else if (k->type == STK_EMPTY_CHECK_START) {\
+ if (k->zid == (sid)) level++;\
+ }\
+ else if (k->type == STK_EMPTY_CHECK_END) {\
+ if (k->zid == (sid)) level--;\
+ }\
+ k++;\
+ }\
+ break;\
+ }\
+ }\
+ else {\
+ level--;\
+ }\
+ }\
+ }\
+ else if (k->type == STK_EMPTY_CHECK_END) {\
+ if (k->zid == (sid)) level++;\
+ }\
+ }\
+} while(0)
+#else
+#define STACK_EMPTY_CHECK_REC(isnull,id,s) do {\
+ int level = 0;\
+ StackType* k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_EMPTY_CHECK_REC"); \
+ if (k->type == STK_EMPTY_CHECK_START) {\
+ if (k->u.empty_check.num == (id)) {\
+ if (level == 0) {\
+ (isnull) = (k->u.empty_check.pstr == (s));\
+ break;\
+ }\
+ }\
+ level--;\
+ }\
+ else if (k->type == STK_EMPTY_CHECK_END) {\
+ level++;\
+ }\
+ }\
+} while(0)
+#endif /* USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT */
+
+#define STACK_GET_REPEAT_COUNT_SEARCH(sid, c) do {\
+ StackType* k = stk;\
+ while (1) {\
+ (k)--;\
+ STACK_BASE_CHECK(k, "STACK_GET_REPEAT_COUNT_SEARCH");\
+ if ((k)->type == STK_REPEAT_INC) {\
+ if ((k)->zid == (sid)) {\
+ (c) = (k)->u.repeat_inc.count;\
+ break;\
+ }\
+ }\
+ else if ((k)->type == STK_RETURN) {\
+ int level = -1;\
+ while (1) {\
+ (k)--;\
+ if ((k)->type == STK_CALL_FRAME) {\
+ level++;\
+ if (level == 0) break;\
+ }\
+ else if ((k)->type == STK_RETURN) level--;\
+ }\
+ }\
+ }\
+} while(0)
+
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+
+#define STACK_GET_REPEAT_COUNT(sid, c) do {\
+ if (reg->num_call == 0) {\
+ (c) = (STACK_AT(repeat_stk[sid]))->u.repeat_inc.count;\
+ }\
+ else {\
+ STACK_GET_REPEAT_COUNT_SEARCH(sid, c);\
+ }\
+} while(0)
+#else
+#define STACK_GET_REPEAT_COUNT(sid, c) STACK_GET_REPEAT_COUNT_SEARCH(sid, c)
+#endif
+
+#ifdef USE_CALL
+#define STACK_RETURN(addr) do {\
+ int level = 0;\
+ StackType* k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "STACK_RETURN"); \
+ if (k->type == STK_CALL_FRAME) {\
+ if (level == 0) {\
+ (addr) = k->u.call_frame.ret_addr;\
+ break;\
+ }\
+ else level--;\
+ }\
+ else if (k->type == STK_RETURN)\
+ level++;\
+ }\
+} while(0)
+
+#define GET_STACK_RETURN_CALL(k,addr) do {\
+ int level = 0;\
+ k = stk;\
+ while (1) {\
+ k--;\
+ STACK_BASE_CHECK(k, "GET_STACK_RETURN_CALL");\
+ if (k->type == STK_CALL_FRAME) {\
+ if (level == 0) {\
+ (addr) = k->u.call_frame.ret_addr;\
+ break;\
+ }\
+ else level--;\
+ }\
+ else if (k->type == STK_RETURN)\
+ level++;\
+ }\
+} while(0)
+#endif
+
+
+#define STRING_CMP(s1,s2,len) do {\
+ while (len-- > 0) {\
+ if (*s1++ != *s2++) goto fail;\
+ }\
+} while(0)
+
+#define STRING_CMP_IC(case_fold_flag,s1,ps2,len) do {\
+ if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len) == 0) \
+ goto fail; \
+} while(0)
+
+static int string_cmp_ic(OnigEncoding enc, int case_fold_flag,
+ UChar* s1, UChar** ps2, int mblen)
+{
+ UChar buf1[ONIGENC_MBC_CASE_FOLD_MAXLEN];
+ UChar buf2[ONIGENC_MBC_CASE_FOLD_MAXLEN];
+ UChar *p1, *p2, *end1, *s2, *end2;
+ int len1, len2;
+
+ s2 = *ps2;
+ end1 = s1 + mblen;
+ end2 = s2 + mblen;
+ while (s1 < end1) {
+ len1 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s1, end1, buf1);
+ len2 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s2, end2, buf2);
+ if (len1 != len2) return 0;
+ p1 = buf1;
+ p2 = buf2;
+ while (len1-- > 0) {
+ if (*p1 != *p2) return 0;
+ p1++;
+ p2++;
+ }
+ }
+
+ *ps2 = s2;
+ return 1;
+}
+
+#define STRING_CMP_VALUE(s1,s2,len,is_fail) do {\
+ is_fail = 0;\
+ while (len-- > 0) {\
+ if (*s1++ != *s2++) {\
+ is_fail = 1; break;\
+ }\
+ }\
+} while(0)
+
+#define STRING_CMP_VALUE_IC(case_fold_flag,s1,ps2,len,is_fail) do {\
+ if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len) == 0) \
+ is_fail = 1; \
+ else \
+ is_fail = 0; \
+} while(0)
+
+
+#define IS_EMPTY_STR (str == end)
+#define ON_STR_BEGIN(s) ((s) == str)
+#define ON_STR_END(s) ((s) == end)
+#define DATA_ENSURE_CHECK1 (s < right_range)
+#define DATA_ENSURE_CHECK(n) (s + (n) <= right_range)
+#define DATA_ENSURE(n) if (s + (n) > right_range) goto fail
+
+#define INIT_RIGHT_RANGE right_range = (UChar* )in_right_range
+
+#ifdef USE_CAPTURE_HISTORY
+static int
+make_capture_history_tree(OnigCaptureTreeNode* node, StackType** kp,
+ StackType* stk_top, UChar* str, regex_t* reg)
+{
+ int n, r;
+ OnigCaptureTreeNode* child;
+ StackType* k = *kp;
+
+ while (k < stk_top) {
+ if (k->type == STK_MEM_START) {
+ n = k->zid;
+ if (n <= ONIG_MAX_CAPTURE_HISTORY_GROUP &&
+ MEM_STATUS_AT(reg->capture_history, n) != 0) {
+ child = history_node_new();
+ CHECK_NULL_RETURN_MEMERR(child);
+ child->group = n;
+ child->beg = (int )(k->u.mem.pstr - str);
+ r = history_tree_add_child(node, child);
+ if (r != 0) return r;
+ *kp = (k + 1);
+ r = make_capture_history_tree(child, kp, stk_top, str, reg);
+ if (r != 0) return r;
+
+ k = *kp;
+ child->end = (int )(k->u.mem.pstr - str);
+ }
+ }
+ else if (k->type == STK_MEM_END) {
+ if (k->zid == node->group) {
+ node->end = (int )(k->u.mem.pstr - str);
+ *kp = k;
+ return 0;
+ }
+ }
+ k++;
+ }
+
+ return 1; /* 1: root node ending. */
+}
+#endif
+
+#ifdef USE_BACKREF_WITH_LEVEL
+static int mem_is_in_memp(int mem, int num, MemNumType* memp)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (mem == (int )memp[i]) return 1;
+ }
+ return 0;
+}
+
+static int
+backref_match_at_nested_level(regex_t* reg,
+ StackType* top, StackType* stk_base,
+ int ignore_case, int case_fold_flag,
+ int nest, int mem_num, MemNumType* memp,
+ UChar** s, const UChar* send)
+{
+ UChar *ss, *p, *pstart, *pend = NULL_UCHARP;
+ int level;
+ StackType* k;
+
+ level = 0;
+ k = top;
+ k--;
+ while (k >= stk_base) {
+ if (k->type == STK_CALL_FRAME) {
+ level--;
+ }
+ else if (k->type == STK_RETURN) {
+ level++;
+ }
+ else if (level == nest) {
+ if (k->type == STK_MEM_START) {
+ if (mem_is_in_memp(k->zid, mem_num, memp)) {
+ pstart = k->u.mem.pstr;
+ if (IS_NOT_NULL(pend)) {
+ if (pend - pstart > send - *s) return 0; /* or goto next_mem; */
+ p = pstart;
+ ss = *s;
+
+ if (ignore_case != 0) {
+ if (string_cmp_ic(reg->enc, case_fold_flag,
+ pstart, &ss, (int )(pend - pstart)) == 0)
+ return 0; /* or goto next_mem; */
+ }
+ else {
+ while (p < pend) {
+ if (*p++ != *ss++) return 0; /* or goto next_mem; */
+ }
+ }
+
+ *s = ss;
+ return 1;
+ }
+ }
+ }
+ else if (k->type == STK_MEM_END) {
+ if (mem_is_in_memp(k->zid, mem_num, memp)) {
+ pend = k->u.mem.pstr;
+ }
+ }
+ }
+ k--;
+ }
+
+ return 0;
+}
+
+static int
+backref_check_at_nested_level(regex_t* reg,
+ StackType* top, StackType* stk_base,
+ int nest, int mem_num, MemNumType* memp)
+{
+ int level;
+ StackType* k;
+
+ level = 0;
+ k = top;
+ k--;
+ while (k >= stk_base) {
+ if (k->type == STK_CALL_FRAME) {
+ level--;
+ }
+ else if (k->type == STK_RETURN) {
+ level++;
+ }
+ else if (level == nest) {
+ if (k->type == STK_MEM_END) {
+ if (mem_is_in_memp(k->zid, mem_num, memp)) {
+ return 1;
+ }
+ }
+ }
+ k--;
+ }
+
+ return 0;
+}
+#endif /* USE_BACKREF_WITH_LEVEL */
+
+
+#ifdef ONIG_DEBUG_STATISTICS
+
+#ifdef USE_TIMEOFDAY
+
+static struct timeval ts, te;
+#define GETTIME(t) gettimeofday(&(t), (struct timezone* )0)
+#define TIMEDIFF(te,ts) (((te).tv_usec - (ts).tv_usec) + \
+ (((te).tv_sec - (ts).tv_sec)*1000000))
+#else
+
+static struct tms ts, te;
+#define GETTIME(t) times(&(t))
+#define TIMEDIFF(te,ts) ((te).tms_utime - (ts).tms_utime)
+
+#endif /* USE_TIMEOFDAY */
+
+static int OpCounter[256];
+static int OpPrevCounter[256];
+static unsigned long OpTime[256];
+static int OpCurr = OP_FINISH;
+static int OpPrevTarget = OP_FAIL;
+static int MaxStackDepth = 0;
+
+#define SOP_IN(opcode) do {\
+ if (opcode == OpPrevTarget) OpPrevCounter[OpCurr]++;\
+ OpCurr = opcode;\
+ OpCounter[opcode]++;\
+ GETTIME(ts);\
+} while(0)
+
+#define SOP_OUT do {\
+ GETTIME(te);\
+ OpTime[OpCurr] += TIMEDIFF(te, ts);\
+} while(0)
+
+extern void
+onig_statistics_init(void)
+{
+ int i;
+ for (i = 0; i < 256; i++) {
+ OpCounter[i] = OpPrevCounter[i] = 0; OpTime[i] = 0;
+ }
+ MaxStackDepth = 0;
+}
+
+extern int
+onig_print_statistics(FILE* f)
+{
+ int r;
+ int i;
+
+ r = fprintf(f, " count prev time\n");
+ if (r < 0) return -1;
+
+ for (i = 0; OpInfo[i].opcode >= 0; i++) {
+ r = fprintf(f, "%8d: %8d: %10ld: %s\n",
+ OpCounter[i], OpPrevCounter[i], OpTime[i], OpInfo[i].name);
+ if (r < 0) return -1;
+ }
+ r = fprintf(f, "\nmax stack depth: %d\n", MaxStackDepth);
+ if (r < 0) return -1;
+
+ return 0;
+}
+
+#define STACK_INC do {\
+ stk++;\
+ if (stk - stk_base > MaxStackDepth) \
+ MaxStackDepth = stk - stk_base;\
+} while(0)
+
+#else
+#define STACK_INC stk++
+
+#define SOP_IN(opcode)
+#define SOP_OUT
+#endif
+
+
+/* matching region of POSIX API */
+typedef int regoff_t;
+
+typedef struct {
+ regoff_t rm_so;
+ regoff_t rm_eo;
+} posix_regmatch_t;
+
+
+
+#ifdef USE_THREADED_CODE
+
+#define BYTECODE_INTERPRETER_START GOTO_OP;
+#define BYTECODE_INTERPRETER_END
+#define CASE_OP(x) L_##x: SOP_IN(OP_##x); sbegin = s; MATCH_DEBUG_OUT(0)
+#define DEFAULT_OP /* L_DEFAULT: */
+#define NEXT_OP sprev = sbegin; JUMP_OP
+#define JUMP_OP GOTO_OP
+#ifdef USE_DIRECT_THREADED_CODE
+#define GOTO_OP goto *(p->opaddr)
+#else
+#define GOTO_OP goto *opcode_to_label[p->opcode]
+#endif
+#define BREAK_OP /* Nothing */
+
+#else
+
+#define BYTECODE_INTERPRETER_START \
+ while (1) {\
+ MATCH_DEBUG_OUT(0)\
+ sbegin = s;\
+ switch (p->opcode) {
+#define BYTECODE_INTERPRETER_END } sprev = sbegin; }
+#define CASE_OP(x) case OP_##x: SOP_IN(OP_##x);
+#define DEFAULT_OP default:
+#define NEXT_OP break
+#define JUMP_OP GOTO_OP
+#define GOTO_OP continue; break
+#define BREAK_OP break
+
+#endif /* USE_THREADED_CODE */
+
+#define INC_OP p++
+#define JUMP_OUT_WITH_SPREV_SET SOP_OUT; NEXT_OP
+#define JUMP_OUT SOP_OUT; JUMP_OP
+#define BREAK_OUT SOP_OUT; BREAK_OP
+#define CHECK_INTERRUPT_JUMP_OUT SOP_OUT; CHECK_INTERRUPT_IN_MATCH; JUMP_OP
+
+
+#ifdef ONIG_DEBUG_MATCH
+#define MATCH_DEBUG_OUT(offset) do {\
+ Operation *xp;\
+ UChar *q, *bp, buf[50];\
+ int len, spos;\
+ spos = IS_NOT_NULL(s) ? (int )(s - str) : -1;\
+ xp = p - (offset);\
+ fprintf(DBGFP, "%7u: %7ld: %4d> \"",\
+ counter, GET_STACK_INDEX(stk), spos);\
+ counter++;\
+ bp = buf;\
+ if (IS_NOT_NULL(s)) {\
+ for (i = 0, q = s; i < 7 && q < end; i++) {\
+ len = enclen(encode, q);\
+ while (len-- > 0) *bp++ = *q++;\
+ }\
+ if (q < end) { xmemcpy(bp, "...\"", 4); bp += 4; }\
+ else { xmemcpy(bp, "\"", 1); bp += 1; }\
+ }\
+ else {\
+ xmemcpy(bp, "\"", 1); bp += 1;\
+ }\
+ *bp = 0;\
+ fputs((char* )buf, DBGFP);\
+ for (i = 0; i < 20 - (bp - buf); i++) fputc(' ', DBGFP);\
+ if (xp == FinishCode)\
+ fprintf(DBGFP, "----: finish");\
+ else {\
+ int index;\
+ enum OpCode zopcode;\
+ Operation* addr;\
+ index = (int )(xp - reg->ops);\
+ fprintf(DBGFP, "%4d: ", index);\
+ print_compiled_byte_code(DBGFP, reg, index, reg->ops, encode); \
+ zopcode = GET_OPCODE(reg, index);\
+ if (zopcode == OP_RETURN) {\
+ GET_STACK_RETURN_CALL(stkp, addr);\
+ fprintf(DBGFP, " f:%ld -> %d", \
+ GET_STACK_INDEX(stkp), (int )(addr - reg->ops));\
+ }\
+ }\
+ fprintf(DBGFP, "\n");\
+ } while(0);
+#else
+#define MATCH_DEBUG_OUT(offset)
+#endif
+
+#define MATCH_AT_ERROR_RETURN(err_code) do {\
+ best_len = err_code; goto match_at_end;\
+} while(0)
+
+
+/* match data(str - end) from position (sstart). */
+/* if sstart == str then set sprev to NULL. */
+static int
+match_at(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* in_right_range, const UChar* sstart, UChar* sprev,
+ MatchArg* msa)
+{
+
+#if defined(USE_DIRECT_THREADED_CODE)
+ static Operation FinishCode[] = { { .opaddr=&&L_FINISH } };
+#else
+ static Operation FinishCode[] = { { OP_FINISH } };
+#endif
+
+#ifdef USE_THREADED_CODE
+ static const void *opcode_to_label[] = {
+ &&L_FINISH,
+ &&L_END,
+ &&L_STR_1,
+ &&L_STR_2,
+ &&L_STR_3,
+ &&L_STR_4,
+ &&L_STR_5,
+ &&L_STR_N,
+ &&L_STR_MB2N1,
+ &&L_STR_MB2N2,
+ &&L_STR_MB2N3,
+ &&L_STR_MB2N,
+ &&L_STR_MB3N,
+ &&L_STR_MBN,
+ &&L_CCLASS,
+ &&L_CCLASS_MB,
+ &&L_CCLASS_MIX,
+ &&L_CCLASS_NOT,
+ &&L_CCLASS_MB_NOT,
+ &&L_CCLASS_MIX_NOT,
+ &&L_ANYCHAR,
+ &&L_ANYCHAR_ML,
+ &&L_ANYCHAR_STAR,
+ &&L_ANYCHAR_ML_STAR,
+ &&L_ANYCHAR_STAR_PEEK_NEXT,
+ &&L_ANYCHAR_ML_STAR_PEEK_NEXT,
+ &&L_WORD,
+ &&L_WORD_ASCII,
+ &&L_NO_WORD,
+ &&L_NO_WORD_ASCII,
+ &&L_WORD_BOUNDARY,
+ &&L_NO_WORD_BOUNDARY,
+ &&L_WORD_BEGIN,
+ &&L_WORD_END,
+ &&L_TEXT_SEGMENT_BOUNDARY,
+ &&L_BEGIN_BUF,
+ &&L_END_BUF,
+ &&L_BEGIN_LINE,
+ &&L_END_LINE,
+ &&L_SEMI_END_BUF,
+ &&L_CHECK_POSITION,
+ &&L_BACKREF1,
+ &&L_BACKREF2,
+ &&L_BACKREF_N,
+ &&L_BACKREF_N_IC,
+ &&L_BACKREF_MULTI,
+ &&L_BACKREF_MULTI_IC,
+ &&L_BACKREF_WITH_LEVEL,
+ &&L_BACKREF_WITH_LEVEL_IC,
+ &&L_BACKREF_CHECK,
+ &&L_BACKREF_CHECK_WITH_LEVEL,
+ &&L_MEM_START,
+ &&L_MEM_START_PUSH,
+ &&L_MEM_END_PUSH,
+#ifdef USE_CALL
+ &&L_MEM_END_PUSH_REC,
+#endif
+ &&L_MEM_END,
+#ifdef USE_CALL
+ &&L_MEM_END_REC,
+#endif
+ &&L_FAIL,
+ &&L_JUMP,
+ &&L_PUSH,
+ &&L_PUSH_SUPER,
+ &&L_POP,
+ &&L_POP_TO_MARK,
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ &&L_PUSH_OR_JUMP_EXACT1,
+#endif
+ &&L_PUSH_IF_PEEK_NEXT,
+ &&L_REPEAT,
+ &&L_REPEAT_NG,
+ &&L_REPEAT_INC,
+ &&L_REPEAT_INC_NG,
+ &&L_EMPTY_CHECK_START,
+ &&L_EMPTY_CHECK_END,
+ &&L_EMPTY_CHECK_END_MEMST,
+#ifdef USE_CALL
+ &&L_EMPTY_CHECK_END_MEMST_PUSH,
+#endif
+ &&L_MOVE,
+ &&L_STEP_BACK_START,
+ &&L_STEP_BACK_NEXT,
+ &&L_CUT_TO_MARK,
+ &&L_MARK,
+ &&L_SAVE_VAL,
+ &&L_UPDATE_VAR,
+#ifdef USE_CALL
+ &&L_CALL,
+ &&L_RETURN,
+#endif
+#ifdef USE_CALLOUT
+ &&L_CALLOUT_CONTENTS,
+ &&L_CALLOUT_NAME,
+#endif
+ };
+#endif
+
+ int i, n, num_mem, best_len, pop_level;
+ LengthType tlen, tlen2;
+ MemNumType mem;
+ RelAddrType addr;
+ UChar *s, *ps, *sbegin;
+ UChar *right_range;
+ int is_alloca;
+ char *alloc_base;
+ StackType *stk_base, *stk, *stk_end;
+ StackType *stkp; /* used as any purpose. */
+ StackIndex *mem_start_stk, *mem_end_stk;
+ UChar* keep;
+
+#ifdef USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR
+ StackIndex *repeat_stk;
+ StackIndex *empty_check_stk;
+#endif
+#ifdef USE_RETRY_LIMIT
+ unsigned long retry_limit_in_match;
+ unsigned long retry_in_match_counter;
+#endif
+#ifdef USE_CALLOUT
+ int of;
+#endif
+
+ Operation* p = reg->ops;
+ OnigOptionType option = reg->options;
+ OnigEncoding encode = reg->enc;
+ OnigCaseFoldType case_fold_flag = reg->case_fold_flag;
+
+#if defined(USE_CALL) && defined(SUBEXP_CALL_MAX_NEST_LEVEL)
+ unsigned long subexp_call_nest_counter = 0;
+#endif
+
+#ifdef ONIG_DEBUG_MATCH
+ static unsigned int counter = 1;
+#endif
+
+#ifdef USE_DIRECT_THREADED_CODE
+ if (IS_NULL(msa)) {
+ for (i = 0; i < reg->ops_used; i++) {
+ const void* addr;
+ addr = opcode_to_label[reg->ocs[i]];
+ p->opaddr = addr;
+ p++;
+ }
+ return ONIG_NORMAL;
+ }
+#endif
+
+#ifdef USE_CALLOUT
+ msa->mp->match_at_call_counter++;
+#endif
+
+#ifdef USE_RETRY_LIMIT
+ retry_limit_in_match = msa->retry_limit_in_match;
+ if (msa->retry_limit_in_search != 0) {
+ unsigned long rem = msa->retry_limit_in_search
+ - msa->retry_limit_in_search_counter;
+ if (rem < retry_limit_in_match)
+ retry_limit_in_match = rem;
+ }
+#endif
+
+ pop_level = reg->stack_pop_level;
+ num_mem = reg->num_mem;
+ STACK_INIT(INIT_MATCH_STACK_SIZE);
+ UPDATE_FOR_STACK_REALLOC;
+ for (i = 1; i <= num_mem; i++) {
+ mem_start_stk[i] = mem_end_stk[i] = INVALID_STACK_INDEX;
+ }
+
+#ifdef ONIG_DEBUG_MATCH
+ fprintf(DBGFP, "match_at: str: %p, end: %p, start: %p, sprev: %p\n",
+ str, end, sstart, sprev);
+ fprintf(DBGFP, "size: %d, start offset: %d\n",
+ (int )(end - str), (int )(sstart - str));
+#endif
+
+ best_len = ONIG_MISMATCH;
+ keep = s = (UChar* )sstart;
+ STACK_PUSH_BOTTOM(STK_ALT, FinishCode); /* bottom stack */
+ INIT_RIGHT_RANGE;
+
+#ifdef USE_RETRY_LIMIT
+ retry_in_match_counter = 0;
+#endif
+
+ BYTECODE_INTERPRETER_START {
+ CASE_OP(END)
+ n = (int )(s - sstart);
+ if (n > best_len) {
+ OnigRegion* region;
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+ if (OPTON_FIND_LONGEST(option)) {
+ if (n > msa->best_len) {
+ msa->best_len = n;
+ msa->best_s = (UChar* )sstart;
+ }
+ else
+ goto end_best_len;
+ }
+#endif
+ best_len = n;
+ region = msa->region;
+ if (region) {
+ if (keep > s) keep = s;
+
+#ifdef USE_POSIX_API_REGION_OPTION
+ if (OPTON_POSIX_REGION(msa->options)) {
+ posix_regmatch_t* rmt = (posix_regmatch_t* )region;
+
+ rmt[0].rm_so = (regoff_t )(keep - str);
+ rmt[0].rm_eo = (regoff_t )(s - str);
+ for (i = 1; i <= num_mem; i++) {
+ if (mem_end_stk[i] != INVALID_STACK_INDEX) {
+ rmt[i].rm_so = (regoff_t )(STACK_MEM_START(reg, i) - str);
+ rmt[i].rm_eo = (regoff_t )(STACK_MEM_END(reg, i) - str);
+ }
+ else {
+ rmt[i].rm_so = rmt[i].rm_eo = ONIG_REGION_NOTPOS;
+ }
+ }
+ }
+ else {
+#endif /* USE_POSIX_API_REGION_OPTION */
+ region->beg[0] = (int )(keep - str);
+ region->end[0] = (int )(s - str);
+ for (i = 1; i <= num_mem; i++) {
+ if (mem_end_stk[i] != INVALID_STACK_INDEX) {
+ region->beg[i] = (int )(STACK_MEM_START(reg, i) - str);
+ region->end[i] = (int )(STACK_MEM_END(reg, i) - str);
+ }
+ else {
+ region->beg[i] = region->end[i] = ONIG_REGION_NOTPOS;
+ }
+ }
+
+#ifdef USE_CAPTURE_HISTORY
+ if (reg->capture_history != 0) {
+ int r;
+ OnigCaptureTreeNode* node;
+
+ if (IS_NULL(region->history_root)) {
+ region->history_root = node = history_node_new();
+ CHECK_NULL_RETURN_MEMERR(node);
+ }
+ else {
+ node = region->history_root;
+ history_tree_clear(node);
+ }
+
+ node->group = 0;
+ node->beg = (int )(keep - str);
+ node->end = (int )(s - str);
+
+ stkp = stk_base;
+ r = make_capture_history_tree(region->history_root, &stkp,
+ stk, (UChar* )str, reg);
+ if (r < 0) MATCH_AT_ERROR_RETURN(r);
+ }
+#endif /* USE_CAPTURE_HISTORY */
+#ifdef USE_POSIX_API_REGION_OPTION
+ } /* else OPTON_POSIX_REGION() */
+#endif
+ } /* if (region) */
+ } /* n > best_len */
+
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+ end_best_len:
+#endif
+ SOP_OUT;
+
+ if (OPTON_FIND_CONDITION(option)) {
+ if (OPTON_FIND_NOT_EMPTY(option) && s == sstart) {
+ best_len = ONIG_MISMATCH;
+ goto fail; /* for retry */
+ }
+ if (OPTON_FIND_LONGEST(option) && DATA_ENSURE_CHECK1) {
+ goto fail; /* for retry */
+ }
+ }
+
+ /* default behavior: return first-matching result. */
+ goto match_at_end;
+
+ CASE_OP(STR_1)
+ DATA_ENSURE(1);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ s++;
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(STR_2)
+ DATA_ENSURE(2);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ sprev = s;
+ s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_3)
+ DATA_ENSURE(3);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ sprev = s;
+ s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_4)
+ DATA_ENSURE(4);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ sprev = s;
+ s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_5)
+ DATA_ENSURE(5);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ sprev = s;
+ s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_N)
+ tlen = p->exact_n.n;
+ DATA_ENSURE(tlen);
+ ps = p->exact_n.s;
+ while (tlen-- > 0) {
+ if (*ps++ != *s++) goto fail;
+ }
+ sprev = s - 1;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_MB2N1)
+ DATA_ENSURE(2);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ s++;
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(STR_MB2N2)
+ DATA_ENSURE(4);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ sprev = s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_MB2N3)
+ DATA_ENSURE(6);
+ ps = p->exact.s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ sprev = s;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_MB2N)
+ tlen = p->exact_n.n;
+ DATA_ENSURE(tlen * 2);
+ ps = p->exact_n.s;
+ while (tlen-- > 0) {
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ }
+ sprev = s - 2;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_MB3N)
+ tlen = p->exact_n.n;
+ DATA_ENSURE(tlen * 3);
+ ps = p->exact_n.s;
+ while (tlen-- > 0) {
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ }
+ sprev = s - 3;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STR_MBN)
+ tlen = p->exact_len_n.len; /* mb byte len */
+ tlen2 = p->exact_len_n.n; /* number of chars */
+ tlen2 *= tlen;
+ DATA_ENSURE(tlen2);
+ ps = p->exact_len_n.s;
+ while (tlen2-- > 0) {
+ if (*ps != *s) goto fail;
+ ps++; s++;
+ }
+ sprev = s - tlen;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(CCLASS)
+ DATA_ENSURE(1);
+ if (BITSET_AT(p->cclass.bsp, *s) == 0) goto fail;
+ s++;
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(CCLASS_MB)
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_HEAD(encode, s)) goto fail;
+
+ cclass_mb:
+ {
+ OnigCodePoint code;
+ UChar *ss;
+ int mb_len;
+
+ mb_len = enclen(encode, s);
+ DATA_ENSURE(mb_len);
+ ss = s;
+ s += mb_len;
+ code = ONIGENC_MBC_TO_CODE(encode, ss, s);
+ if (! onig_is_in_code_range(p->cclass_mb.mb, code)) goto fail;
+ }
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(CCLASS_MIX)
+ DATA_ENSURE(1);
+ if (ONIGENC_IS_MBC_HEAD(encode, s)) {
+ goto cclass_mb;
+ }
+ else {
+ if (BITSET_AT(p->cclass_mix.bsp, *s) == 0)
+ goto fail;
+
+ s++;
+ }
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(CCLASS_NOT)
+ DATA_ENSURE(1);
+ if (BITSET_AT(p->cclass.bsp, *s) != 0) goto fail;
+ s += enclen(encode, s);
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(CCLASS_MB_NOT)
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_HEAD(encode, s)) {
+ s++;
+ goto cc_mb_not_success;
+ }
+
+ cclass_mb_not:
+ {
+ OnigCodePoint code;
+ UChar *ss;
+ int mb_len = enclen(encode, s);
+
+ if (! DATA_ENSURE_CHECK(mb_len)) {
+ DATA_ENSURE(1);
+ s = (UChar* )end;
+ goto cc_mb_not_success;
+ }
+
+ ss = s;
+ s += mb_len;
+ code = ONIGENC_MBC_TO_CODE(encode, ss, s);
+ if (onig_is_in_code_range(p->cclass_mb.mb, code)) goto fail;
+ }
+
+ cc_mb_not_success:
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(CCLASS_MIX_NOT)
+ DATA_ENSURE(1);
+ if (ONIGENC_IS_MBC_HEAD(encode, s)) {
+ goto cclass_mb_not;
+ }
+ else {
+ if (BITSET_AT(p->cclass_mix.bsp, *s) != 0)
+ goto fail;
+
+ s++;
+ }
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(ANYCHAR)
+ DATA_ENSURE(1);
+ n = enclen(encode, s);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) goto fail;
+ s += n;
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(ANYCHAR_ML)
+ DATA_ENSURE(1);
+ n = enclen(encode, s);
+ DATA_ENSURE(n);
+ s += n;
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(ANYCHAR_STAR)
+ INC_OP;
+ while (DATA_ENSURE_CHECK1) {
+ STACK_PUSH_ALT(p, s, sprev);
+ n = enclen(encode, s);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) goto fail;
+ sprev = s;
+ s += n;
+ }
+ JUMP_OUT;
+
+ CASE_OP(ANYCHAR_ML_STAR)
+ INC_OP;
+ while (DATA_ENSURE_CHECK1) {
+ STACK_PUSH_ALT(p, s, sprev);
+ n = enclen(encode, s);
+ if (n > 1) {
+ DATA_ENSURE(n);
+ sprev = s;
+ s += n;
+ }
+ else {
+ sprev = s;
+ s++;
+ }
+ }
+ JUMP_OUT;
+
+ CASE_OP(ANYCHAR_STAR_PEEK_NEXT)
+ {
+ UChar c;
+
+ c = p->anychar_star_peek_next.c;
+ INC_OP;
+ while (DATA_ENSURE_CHECK1) {
+ if (c == *s) {
+ STACK_PUSH_ALT(p, s, sprev);
+ }
+ n = enclen(encode, s);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) goto fail;
+ sprev = s;
+ s += n;
+ }
+ }
+ JUMP_OUT;
+
+ CASE_OP(ANYCHAR_ML_STAR_PEEK_NEXT)
+ {
+ UChar c;
+
+ c = p->anychar_star_peek_next.c;
+ INC_OP;
+ while (DATA_ENSURE_CHECK1) {
+ if (c == *s) {
+ STACK_PUSH_ALT(p, s, sprev);
+ }
+ n = enclen(encode, s);
+ if (n > 1) {
+ DATA_ENSURE(n);
+ sprev = s;
+ s += n;
+ }
+ else {
+ sprev = s;
+ s++;
+ }
+ }
+ }
+ JUMP_OUT;
+
+ CASE_OP(WORD)
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_WORD(encode, s, end))
+ goto fail;
+
+ s += enclen(encode, s);
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(WORD_ASCII)
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_WORD_ASCII(encode, s, end))
+ goto fail;
+
+ s += enclen(encode, s);
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(NO_WORD)
+ DATA_ENSURE(1);
+ if (ONIGENC_IS_MBC_WORD(encode, s, end))
+ goto fail;
+
+ s += enclen(encode, s);
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(NO_WORD_ASCII)
+ DATA_ENSURE(1);
+ if (ONIGENC_IS_MBC_WORD_ASCII(encode, s, end))
+ goto fail;
+
+ s += enclen(encode, s);
+ INC_OP;
+ JUMP_OUT_WITH_SPREV_SET;
+
+ CASE_OP(WORD_BOUNDARY)
+ {
+ ModeType mode;
+
+ mode = p->word_boundary.mode;
+ if (ON_STR_BEGIN(s)) {
+ DATA_ENSURE(1);
+ if (! IS_MBC_WORD_ASCII_MODE(encode, s, end, mode))
+ goto fail;
+ }
+ else if (ON_STR_END(s)) {
+ if (! IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode))
+ goto fail;
+ }
+ else {
+ if (IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)
+ == IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode))
+ goto fail;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(NO_WORD_BOUNDARY)
+ {
+ ModeType mode;
+
+ mode = p->word_boundary.mode;
+ if (ON_STR_BEGIN(s)) {
+ if (DATA_ENSURE_CHECK1 && IS_MBC_WORD_ASCII_MODE(encode, s, end, mode))
+ goto fail;
+ }
+ else if (ON_STR_END(s)) {
+ if (IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode))
+ goto fail;
+ }
+ else {
+ if (IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)
+ != IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode))
+ goto fail;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+#ifdef USE_WORD_BEGIN_END
+ CASE_OP(WORD_BEGIN)
+ {
+ ModeType mode;
+
+ mode = p->word_boundary.mode;
+ if (DATA_ENSURE_CHECK1 && IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)) {
+ if (ON_STR_BEGIN(s) || !IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+ }
+ }
+ goto fail;
+
+ CASE_OP(WORD_END)
+ {
+ ModeType mode;
+
+ mode = p->word_boundary.mode;
+ if (!ON_STR_BEGIN(s) && IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode)) {
+ if (ON_STR_END(s) || ! IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+ }
+ }
+ goto fail;
+#endif
+
+ CASE_OP(TEXT_SEGMENT_BOUNDARY)
+ {
+ int is_break;
+
+ switch (p->text_segment_boundary.type) {
+ case EXTENDED_GRAPHEME_CLUSTER_BOUNDARY:
+ is_break = onigenc_egcb_is_break_position(encode, s, sprev, str, end);
+ break;
+#ifdef USE_UNICODE_WORD_BREAK
+ case WORD_BOUNDARY:
+ is_break = onigenc_wb_is_break_position(encode, s, sprev, str, end);
+ break;
+#endif
+ default:
+ MATCH_AT_ERROR_RETURN(ONIGERR_UNDEFINED_BYTECODE);
+ break;
+ }
+
+ if (p->text_segment_boundary.not != 0)
+ is_break = ! is_break;
+
+ if (is_break != 0) {
+ INC_OP;
+ JUMP_OUT;
+ }
+ else {
+ goto fail;
+ }
+ }
+
+ CASE_OP(BEGIN_BUF)
+ if (! ON_STR_BEGIN(s)) goto fail;
+
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(END_BUF)
+ if (! ON_STR_END(s)) goto fail;
+
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(BEGIN_LINE)
+ if (ON_STR_BEGIN(s)) {
+ if (OPTON_NOTBOL(msa->options)) goto fail;
+ INC_OP;
+ JUMP_OUT;
+ }
+ else if (ONIGENC_IS_MBC_NEWLINE(encode, sprev, end) && !ON_STR_END(s)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+ goto fail;
+
+ CASE_OP(END_LINE)
+ if (ON_STR_END(s)) {
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE(encode, sprev, end)) {
+#endif
+ if (OPTON_NOTEOL(msa->options)) goto fail;
+ INC_OP;
+ JUMP_OUT;
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ }
+#endif
+ }
+ else if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ else if (ONIGENC_IS_MBC_CRNL(encode, s, end)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+#endif
+ goto fail;
+
+ CASE_OP(SEMI_END_BUF)
+ if (ON_STR_END(s)) {
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE(encode, sprev, end)) {
+#endif
+ if (OPTON_NOTEOL(msa->options)) goto fail;
+ INC_OP;
+ JUMP_OUT;
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ }
+#endif
+ }
+ else if (ONIGENC_IS_MBC_NEWLINE(encode, s, end) &&
+ ON_STR_END(s + enclen(encode, s))) {
+ INC_OP;
+ JUMP_OUT;
+ }
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ else if (ONIGENC_IS_MBC_CRNL(encode, s, end)) {
+ UChar* ss = s + enclen(encode, s);
+ ss += enclen(encode, ss);
+ if (ON_STR_END(ss)) {
+ INC_OP;
+ JUMP_OUT;
+ }
+ }
+#endif
+ goto fail;
+
+ CASE_OP(CHECK_POSITION)
+ switch (p->check_position.type) {
+ case CHECK_POSITION_SEARCH_START:
+ if (s != msa->start) goto fail;
+ break;
+ case CHECK_POSITION_CURRENT_RIGHT_RANGE:
+ if (s != right_range) goto fail;
+ break;
+ default:
+ break;
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(MEM_START_PUSH)
+ mem = p->memory_start.num;
+ STACK_PUSH_MEM_START(mem, s);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(MEM_START)
+ mem = p->memory_start.num;
+ mem_start_stk[mem] = (StackIndex )((void* )s);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(MEM_END_PUSH)
+ mem = p->memory_end.num;
+ STACK_PUSH_MEM_END(mem, s);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(MEM_END)
+ mem = p->memory_end.num;
+ mem_end_stk[mem] = (StackIndex )((void* )s);
+ INC_OP;
+ JUMP_OUT;
+
+#ifdef USE_CALL
+ CASE_OP(MEM_END_PUSH_REC)
+ {
+ StackIndex si;
+
+ mem = p->memory_end.num;
+ STACK_GET_MEM_START(mem, stkp); /* should be before push mem-end. */
+ si = GET_STACK_INDEX(stkp);
+ STACK_PUSH_MEM_END(mem, s);
+ mem_start_stk[mem] = si;
+ INC_OP;
+ JUMP_OUT;
+ }
+
+ CASE_OP(MEM_END_REC)
+ mem = p->memory_end.num;
+ mem_end_stk[mem] = (StackIndex )((void* )s);
+ STACK_GET_MEM_START(mem, stkp);
+
+ if (MEM_STATUS_AT(reg->push_mem_start, mem))
+ mem_start_stk[mem] = GET_STACK_INDEX(stkp);
+ else
+ mem_start_stk[mem] = (StackIndex )((void* )stkp->u.mem.pstr);
+
+ STACK_PUSH_MEM_END_MARK(mem);
+ INC_OP;
+ JUMP_OUT;
+#endif
+
+ CASE_OP(BACKREF1)
+ mem = 1;
+ goto backref;
+
+ CASE_OP(BACKREF2)
+ mem = 2;
+ goto backref;
+
+ CASE_OP(BACKREF_N)
+ mem = p->backref_n.n1;
+ backref:
+ {
+ int len;
+ UChar *pstart, *pend;
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
+
+ pstart = STACK_MEM_START(reg, mem);
+ pend = STACK_MEM_END(reg, mem);
+ n = (int )(pend - pstart);
+ if (n != 0) {
+ DATA_ENSURE(n);
+ sprev = s;
+ STRING_CMP(s, pstart, n);
+ while (sprev + (len = enclen(encode, sprev)) < s)
+ sprev += len;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(BACKREF_N_IC)
+ mem = p->backref_n.n1;
+ {
+ int len;
+ UChar *pstart, *pend;
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
+
+ pstart = STACK_MEM_START(reg, mem);
+ pend = STACK_MEM_END(reg, mem);
+ n = (int )(pend - pstart);
+ if (n != 0) {
+ DATA_ENSURE(n);
+ sprev = s;
+ STRING_CMP_IC(case_fold_flag, pstart, &s, n);
+ while (sprev + (len = enclen(encode, sprev)) < s)
+ sprev += len;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(BACKREF_MULTI)
+ {
+ int len, is_fail;
+ UChar *pstart, *pend, *swork;
+
+ tlen = p->backref_general.num;
+ for (i = 0; i < tlen; i++) {
+ mem = tlen == 1 ? p->backref_general.n1 : p->backref_general.ns[i];
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
+
+ pstart = STACK_MEM_START(reg, mem);
+ pend = STACK_MEM_END(reg, mem);
+ n = (int )(pend - pstart);
+ if (n != 0) {
+ DATA_ENSURE(n);
+ sprev = s;
+ swork = s;
+ STRING_CMP_VALUE(swork, pstart, n, is_fail);
+ if (is_fail) continue;
+ s = swork;
+ while (sprev + (len = enclen(encode, sprev)) < s)
+ sprev += len;
+ }
+ break; /* success */
+ }
+ if (i == tlen) goto fail;
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(BACKREF_MULTI_IC)
+ {
+ int len, is_fail;
+ UChar *pstart, *pend, *swork;
+
+ tlen = p->backref_general.num;
+ for (i = 0; i < tlen; i++) {
+ mem = tlen == 1 ? p->backref_general.n1 : p->backref_general.ns[i];
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
+
+ pstart = STACK_MEM_START(reg, mem);
+ pend = STACK_MEM_END(reg, mem);
+ n = (int )(pend - pstart);
+ if (n != 0) {
+ DATA_ENSURE(n);
+ sprev = s;
+ swork = s;
+ STRING_CMP_VALUE_IC(case_fold_flag, pstart, &swork, n, is_fail);
+ if (is_fail) continue;
+ s = swork;
+ while (sprev + (len = enclen(encode, sprev)) < s)
+ sprev += len;
+ }
+ break; /* success */
+ }
+ if (i == tlen) goto fail;
+ }
+ INC_OP;
+ JUMP_OUT;
+
+#ifdef USE_BACKREF_WITH_LEVEL
+ CASE_OP(BACKREF_WITH_LEVEL_IC)
+ n = 1; /* ignore case */
+ goto backref_with_level;
+ CASE_OP(BACKREF_WITH_LEVEL)
+ {
+ int len;
+ int level;
+ MemNumType* mems;
+ UChar* ssave;
+
+ n = 0;
+ backref_with_level:
+ level = p->backref_general.nest_level;
+ tlen = p->backref_general.num;
+ mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
+
+ ssave = s;
+ if (backref_match_at_nested_level(reg, stk, stk_base, n,
+ case_fold_flag, level, (int )tlen, mems, &s, end)) {
+ if (ssave != s) {
+ sprev = ssave;
+ while (sprev + (len = enclen(encode, sprev)) < s)
+ sprev += len;
+ }
+ }
+ else
+ goto fail;
+ }
+ INC_OP;
+ JUMP_OUT;
+#endif
+
+ CASE_OP(BACKREF_CHECK)
+ {
+ MemNumType* mems;
+
+ tlen = p->backref_general.num;
+ mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
+
+ for (i = 0; i < tlen; i++) {
+ mem = mems[i];
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
+ break; /* success */
+ }
+ if (i == tlen) goto fail;
+ }
+ INC_OP;
+ JUMP_OUT;
+
+#ifdef USE_BACKREF_WITH_LEVEL
+ CASE_OP(BACKREF_CHECK_WITH_LEVEL)
+ {
+ LengthType level;
+ MemNumType* mems;
+
+ level = p->backref_general.nest_level;
+ tlen = p->backref_general.num;
+ mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
+
+ if (backref_check_at_nested_level(reg, stk, stk_base,
+ (int )level, (int )tlen, mems) == 0)
+ goto fail;
+ }
+ INC_OP;
+ JUMP_OUT;
+#endif
+
+ CASE_OP(EMPTY_CHECK_START)
+ mem = p->empty_check_start.mem; /* mem: null check id */
+ STACK_PUSH_EMPTY_CHECK_START(mem, s);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(EMPTY_CHECK_END)
+ {
+ int is_empty;
+
+ mem = p->empty_check_end.mem; /* mem: null check id */
+ STACK_EMPTY_CHECK(is_empty, mem, s);
+ INC_OP;
+ if (is_empty) {
+#ifdef ONIG_DEBUG_MATCH
+ fprintf(DBGFP, "EMPTY_CHECK_END: skip id:%d, s:%p\n", (int )mem, s);
+#endif
+ empty_check_found:
+ /* empty loop founded, skip next instruction */
+#if defined(ONIG_DEBUG) && !defined(USE_DIRECT_THREADED_CODE)
+ switch (p->opcode) {
+ case OP_JUMP:
+ case OP_PUSH:
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ INC_OP;
+ break;
+ default:
+ MATCH_AT_ERROR_RETURN(ONIGERR_UNEXPECTED_BYTECODE);
+ break;
+ }
+#else
+ INC_OP;
+#endif
+ }
+ }
+ JUMP_OUT;
+
+#ifdef USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT
+ CASE_OP(EMPTY_CHECK_END_MEMST)
+ {
+ int is_empty;
+
+ mem = p->empty_check_end.mem; /* mem: null check id */
+ STACK_EMPTY_CHECK_MEM(is_empty, mem, s, reg);
+ INC_OP;
+ if (is_empty) {
+#ifdef ONIG_DEBUG_MATCH
+ fprintf(DBGFP, "EMPTY_CHECK_END_MEM: skip id:%d, s:%p\n", (int)mem, s);
+#endif
+ if (is_empty == -1) goto fail;
+ goto empty_check_found;
+ }
+ }
+ JUMP_OUT;
+#endif
+
+#ifdef USE_CALL
+ CASE_OP(EMPTY_CHECK_END_MEMST_PUSH)
+ {
+ int is_empty;
+
+ mem = p->empty_check_end.mem; /* mem: null check id */
+#ifdef USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT
+ STACK_EMPTY_CHECK_MEM_REC(is_empty, mem, s, reg);
+#else
+ STACK_EMPTY_CHECK_REC(is_empty, mem, s);
+#endif
+ INC_OP;
+ if (is_empty) {
+#ifdef ONIG_DEBUG_MATCH
+ fprintf(DBGFP, "EMPTY_CHECK_END_MEM_PUSH: skip id:%d, s:%p\n",
+ (int )mem, s);
+#endif
+ if (is_empty == -1) goto fail;
+ goto empty_check_found;
+ }
+ else {
+ STACK_PUSH_EMPTY_CHECK_END(mem);
+ }
+ }
+ JUMP_OUT;
+#endif
+
+ CASE_OP(JUMP)
+ addr = p->jump.addr;
+ p += addr;
+ CHECK_INTERRUPT_JUMP_OUT;
+
+ CASE_OP(PUSH)
+ addr = p->push.addr;
+ STACK_PUSH_ALT(p + addr, s, sprev);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(PUSH_SUPER)
+ addr = p->push.addr;
+ STACK_PUSH_SUPER_ALT(p + addr, s, sprev);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(POP)
+ STACK_POP_ONE;
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(POP_TO_MARK)
+ STACK_POP_TO_MARK(p->pop_to_mark.id);
+ INC_OP;
+ JUMP_OUT;
+
+ #ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ CASE_OP(PUSH_OR_JUMP_EXACT1)
+ {
+ UChar c;
+
+ addr = p->push_or_jump_exact1.addr;
+ c = p->push_or_jump_exact1.c;
+ if (DATA_ENSURE_CHECK1 && c == *s) {
+ STACK_PUSH_ALT(p + addr, s, sprev);
+ INC_OP;
+ JUMP_OUT;
+ }
+ }
+ p += addr;
+ JUMP_OUT;
+#endif
+
+ CASE_OP(PUSH_IF_PEEK_NEXT)
+ {
+ UChar c;
+
+ addr = p->push_if_peek_next.addr;
+ c = p->push_if_peek_next.c;
+ if (DATA_ENSURE_CHECK1 && c == *s) {
+ STACK_PUSH_ALT(p + addr, s, sprev);
+ INC_OP;
+ JUMP_OUT;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(REPEAT)
+ mem = p->repeat.id; /* mem: OP_REPEAT ID */
+ addr = p->repeat.addr;
+
+ STACK_PUSH_REPEAT_INC(mem, 0);
+ if (reg->repeat_range[mem].lower == 0) {
+ STACK_PUSH_ALT(p + addr, s, sprev);
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(REPEAT_NG)
+ mem = p->repeat.id; /* mem: OP_REPEAT ID */
+ addr = p->repeat.addr;
+
+ STACK_PUSH_REPEAT_INC(mem, 0);
+ if (reg->repeat_range[mem].lower == 0) {
+ STACK_PUSH_ALT(p + 1, s, sprev);
+ p += addr;
+ }
+ else
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(REPEAT_INC)
+ mem = p->repeat_inc.id; /* mem: OP_REPEAT ID */
+ STACK_GET_REPEAT_COUNT(mem, n);
+ n++;
+ if (n >= reg->repeat_range[mem].upper) {
+ /* end of repeat. Nothing to do. */
+ INC_OP;
+ }
+ else if (n >= reg->repeat_range[mem].lower) {
+ INC_OP;
+ STACK_PUSH_ALT(p, s, sprev);
+ p = reg->repeat_range[mem].u.pcode;
+ }
+ else {
+ p = reg->repeat_range[mem].u.pcode;
+ }
+ STACK_PUSH_REPEAT_INC(mem, n);
+ CHECK_INTERRUPT_JUMP_OUT;
+
+ CASE_OP(REPEAT_INC_NG)
+ mem = p->repeat_inc.id; /* mem: OP_REPEAT ID */
+ STACK_GET_REPEAT_COUNT(mem, n);
+ n++;
+ STACK_PUSH_REPEAT_INC(mem, n);
+ if (n == reg->repeat_range[mem].upper) {
+ INC_OP;
+ }
+ else {
+ if (n >= reg->repeat_range[mem].lower) {
+ STACK_PUSH_ALT(reg->repeat_range[mem].u.pcode, s, sprev);
+ INC_OP;
+ }
+ else {
+ p = reg->repeat_range[mem].u.pcode;
+ }
+ }
+ CHECK_INTERRUPT_JUMP_OUT;
+
+#ifdef USE_CALL
+ CASE_OP(CALL)
+#ifdef SUBEXP_CALL_MAX_NEST_LEVEL
+ if (subexp_call_nest_counter == SUBEXP_CALL_MAX_NEST_LEVEL)
+ goto fail;
+ subexp_call_nest_counter++;
+#endif
+ addr = p->call.addr;
+ INC_OP; STACK_PUSH_CALL_FRAME(p);
+ p = reg->ops + addr;
+
+ JUMP_OUT;
+
+ CASE_OP(RETURN)
+ STACK_RETURN(p);
+ STACK_PUSH_RETURN;
+#ifdef SUBEXP_CALL_MAX_NEST_LEVEL
+ subexp_call_nest_counter--;
+#endif
+ JUMP_OUT;
+#endif
+
+ CASE_OP(MOVE)
+ if (p->move.n < 0) {
+ s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, -p->move.n);
+ if (IS_NULL(s)) goto fail;
+ }
+ else {
+ int len;
+
+ for (tlen = p->move.n; tlen > 0; tlen--) {
+ len = enclen(encode, s);
+ sprev = s;
+ s += len;
+ if (s > end) goto fail;
+ if (s == end) {
+ if (tlen != 1) goto fail;
+ else break;
+ }
+ }
+ }
+ sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s);
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STEP_BACK_START)
+ tlen = p->step_back_start.initial;
+ if (tlen != 0) {
+ s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, (int )tlen);
+ if (IS_NULL(s)) goto fail;
+ sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s);
+ }
+ if (p->step_back_start.remaining != 0) {
+ STACK_PUSH_ALT_WITH_ZID(p + 1, s, sprev, p->step_back_start.remaining);
+ p += p->step_back_start.addr;
+ }
+ else
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(STEP_BACK_NEXT)
+ tlen = (LengthType )stk->zid; /* remaining count */
+ if (tlen != INFINITE_LEN) tlen--;
+ s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, 1);
+ if (IS_NULL(s)) goto fail;
+ sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s);
+ if (tlen != 0) {
+ STACK_PUSH_ALT_WITH_ZID(p, s, sprev, (int )tlen);
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(CUT_TO_MARK)
+ mem = p->cut_to_mark.id; /* mem: mark id */
+ STACK_TO_VOID_TO_MARK(stkp, mem);
+ if (p->cut_to_mark.restore_pos != 0) {
+ s = stkp->u.val.v;
+ sprev = stkp->u.val.v2;
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(MARK)
+ mem = p->mark.id; /* mem: mark id */
+ if (p->mark.save_pos != 0)
+ STACK_PUSH_MARK_WITH_POS(mem, s, sprev);
+ else
+ STACK_PUSH_MARK(mem);
+
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(SAVE_VAL)
+ {
+ SaveType type;
+
+ type = p->save_val.type;
+ mem = p->save_val.id; /* mem: save id */
+ switch ((enum SaveType )type) {
+ case SAVE_KEEP:
+ STACK_PUSH_SAVE_VAL(mem, type, s);
+ break;
+
+ case SAVE_S:
+ STACK_PUSH_SAVE_VAL_WITH_SPREV(mem, type, s);
+ break;
+
+ case SAVE_RIGHT_RANGE:
+ STACK_PUSH_SAVE_VAL(mem, SAVE_RIGHT_RANGE, right_range);
+ break;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+ CASE_OP(UPDATE_VAR)
+ {
+ UpdateVarType type;
+ enum SaveType save_type;
+
+ type = p->update_var.type;
+
+ switch ((enum UpdateVarType )type) {
+ case UPDATE_VAR_KEEP_FROM_STACK_LAST:
+ STACK_GET_SAVE_VAL_TYPE_LAST(SAVE_KEEP, keep);
+ break;
+ case UPDATE_VAR_S_FROM_STACK:
+ mem = p->update_var.id; /* mem: save id */
+ STACK_GET_SAVE_VAL_TYPE_LAST_ID_WITH_SPREV(SAVE_S, mem, s);
+ break;
+ case UPDATE_VAR_RIGHT_RANGE_FROM_S_STACK:
+ save_type = SAVE_S;
+ goto get_save_val_type_last_id;
+ break;
+ case UPDATE_VAR_RIGHT_RANGE_FROM_STACK:
+ save_type = SAVE_RIGHT_RANGE;
+ get_save_val_type_last_id:
+ mem = p->update_var.id; /* mem: save id */
+ STACK_GET_SAVE_VAL_TYPE_LAST_ID(save_type, mem, right_range, p->update_var.clear);
+ break;
+ case UPDATE_VAR_RIGHT_RANGE_TO_S:
+ right_range = s;
+ break;
+ case UPDATE_VAR_RIGHT_RANGE_INIT:
+ INIT_RIGHT_RANGE;
+ break;
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+
+#ifdef USE_CALLOUT
+ CASE_OP(CALLOUT_CONTENTS)
+ of = ONIG_CALLOUT_OF_CONTENTS;
+ mem = p->callout_contents.num;
+ goto callout_common_entry;
+ BREAK_OUT;
+
+ CASE_OP(CALLOUT_NAME)
+ {
+ int call_result;
+ int name_id;
+ int in;
+ CalloutListEntry* e;
+ OnigCalloutFunc func;
+ OnigCalloutArgs args;
+
+ of = ONIG_CALLOUT_OF_NAME;
+ mem = p->callout_name.num;
+
+ callout_common_entry:
+ e = onig_reg_callout_list_at(reg, mem);
+ in = e->in;
+ if (of == ONIG_CALLOUT_OF_NAME) {
+ name_id = p->callout_name.id;
+ func = onig_get_callout_start_func(reg, mem);
+ }
+ else {
+ name_id = ONIG_NON_NAME_ID;
+ func = msa->mp->progress_callout_of_contents;
+ }
+
+ if (IS_NOT_NULL(func) && (in & ONIG_CALLOUT_IN_PROGRESS) != 0) {
+ CALLOUT_BODY(func, ONIG_CALLOUT_IN_PROGRESS, name_id,
+ (int )mem, msa->mp->callout_user_data, args, call_result);
+ switch (call_result) {
+ case ONIG_CALLOUT_FAIL:
+ goto fail;
+ break;
+ case ONIG_CALLOUT_SUCCESS:
+ goto retraction_callout2;
+ break;
+ default: /* error code */
+ if (call_result > 0) {
+ call_result = ONIGERR_INVALID_ARGUMENT;
+ }
+ best_len = call_result;
+ goto match_at_end;
+ break;
+ }
+ }
+ else {
+ retraction_callout2:
+ if ((in & ONIG_CALLOUT_IN_RETRACTION) != 0) {
+ if (of == ONIG_CALLOUT_OF_NAME) {
+ if (IS_NOT_NULL(func)) {
+ STACK_PUSH_CALLOUT_NAME(name_id, mem, func);
+ }
+ }
+ else {
+ func = msa->mp->retraction_callout_of_contents;
+ if (IS_NOT_NULL(func)) {
+ STACK_PUSH_CALLOUT_CONTENTS(mem, func);
+ }
+ }
+ }
+ }
+ }
+ INC_OP;
+ JUMP_OUT;
+#endif
+
+ CASE_OP(FINISH)
+ goto match_at_end;
+
+#ifdef ONIG_DEBUG_STATISTICS
+ fail:
+ SOP_OUT;
+ goto fail2;
+#endif
+ CASE_OP(FAIL)
+#ifdef ONIG_DEBUG_STATISTICS
+ fail2:
+#else
+ fail:
+#endif
+ STACK_POP;
+ p = stk->u.state.pcode;
+ s = stk->u.state.pstr;
+ sprev = stk->u.state.pstr_prev;
+ CHECK_RETRY_LIMIT_IN_MATCH;
+ JUMP_OUT;
+
+ DEFAULT_OP
+ MATCH_AT_ERROR_RETURN(ONIGERR_UNDEFINED_BYTECODE);
+
+ } BYTECODE_INTERPRETER_END;
+
+ match_at_end:
+ if (msa->retry_limit_in_search != 0) {
+ msa->retry_limit_in_search_counter += retry_in_match_counter;
+ }
+ STACK_SAVE(msa, is_alloca, alloc_base);
+ return best_len;
+}
+
+
+#ifdef USE_REGSET
+
+typedef struct {
+ regex_t* reg;
+ OnigRegion* region;
+} RR;
+
+struct OnigRegSetStruct {
+ RR* rs;
+ int n;
+ int alloc;
+ OnigEncoding enc;
+ int anchor; /* BEGIN_BUF, BEGIN_POS, (SEMI_)END_BUF */
+ OnigLen anc_dmin; /* (SEMI_)END_BUF anchor distance */
+ OnigLen anc_dmax; /* (SEMI_)END_BUF anchor distance */
+ int all_low_high;
+ int anychar_inf;
+};
+
+enum SearchRangeStatus {
+ SRS_DEAD = 0,
+ SRS_LOW_HIGH = 1,
+ SRS_ALL_RANGE = 2
+};
+
+typedef struct {
+ int state; /* value of enum SearchRangeStatus */
+ UChar* low;
+ UChar* high;
+ UChar* low_prev;
+ UChar* sch_range;
+} SearchRange;
+
+#define REGSET_MATCH_AND_RETURN_CHECK(upper_range) \
+ r = match_at(reg, str, end, (upper_range), s, prev, msas + i); \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
+ }
+
+static inline int
+regset_search_body_position_lead(OnigRegSet* set,
+ const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, /* match start range */
+ const UChar* orig_range, /* data range */
+ OnigOptionType option, MatchArg* msas, int* rmatch_pos)
+{
+ int r, n, i;
+ UChar *s, *prev;
+ UChar *low, *high, *low_prev;
+ UChar* sch_range;
+ regex_t* reg;
+ OnigEncoding enc;
+ SearchRange* sr;
+
+ n = set->n;
+ enc = set->enc;
+
+ s = (UChar* )start;
+ if (s > str)
+ prev = onigenc_get_prev_char_head(enc, str, s);
+ else
+ prev = (UChar* )NULL;
+
+ sr = (SearchRange* )xmalloc(sizeof(*sr) * n);
+ CHECK_NULL_RETURN_MEMERR(sr);
+
+ for (i = 0; i < n; i++) {
+ reg = set->rs[i].reg;
+
+ sr[i].state = SRS_DEAD;
+ if (reg->optimize != OPTIMIZE_NONE) {
+ if (reg->dist_max != INFINITE_LEN) {
+ if (end - range > reg->dist_max)
+ sch_range = (UChar* )range + reg->dist_max;
+ else
+ sch_range = (UChar* )end;
+
+ if (forward_search(reg, str, end, s, sch_range, &low, &high, &low_prev)) {
+ sr[i].state = SRS_LOW_HIGH;
+ sr[i].low = low;
+ sr[i].high = high;
+ sr[i].low_prev = low_prev;
+ sr[i].sch_range = sch_range;
+ }
+ }
+ else {
+ sch_range = (UChar* )end;
+ if (forward_search(reg, str, end, s, sch_range,
+ &low, &high, (UChar** )NULL)) {
+ goto total_active;
+ }
+ }
+ }
+ else {
+ total_active:
+ sr[i].state = SRS_ALL_RANGE;
+ sr[i].low = s;
+ sr[i].high = (UChar* )range;
+ sr[i].low_prev = prev;
+ }
+ }
+
+#define ACTIVATE_ALL_LOW_HIGH_SEARCH_THRESHOLD_LEN 500
+
+ if (set->all_low_high != 0
+ && range - start > ACTIVATE_ALL_LOW_HIGH_SEARCH_THRESHOLD_LEN) {
+ do {
+ int try_count = 0;
+ for (i = 0; i < n; i++) {
+ if (sr[i].state == SRS_DEAD) continue;
+
+ if (s < sr[i].low) continue;
+ if (s >= sr[i].high) {
+ if (forward_search(set->rs[i].reg, str, end, s, sr[i].sch_range,
+ &low, &high, &low_prev) != 0) {
+ sr[i].low = low;
+ sr[i].high = high;
+ sr[i].low_prev = low_prev;
+ if (s < low) continue;
+ }
+ else {
+ sr[i].state = SRS_DEAD;
+ continue;
+ }
+ }
+
+ reg = set->rs[i].reg;
+ REGSET_MATCH_AND_RETURN_CHECK(orig_range);
+ try_count++;
+ } /* for (i) */
+
+ if (s >= range) break;
+
+ if (try_count == 0) {
+ low = (UChar* )range;
+ for (i = 0; i < n; i++) {
+ if (sr[i].state == SRS_LOW_HIGH && low > sr[i].low) {
+ low = sr[i].low;
+ low_prev = sr[i].low_prev;
+ }
+ }
+ if (low == range) break;
+
+ s = low;
+ prev = low_prev;
+ }
+ else {
+ prev = s;
+ s += enclen(enc, s);
+ }
+ } while (1);
+ }
+ else {
+ int prev_is_newline = 1;
+ do {
+ for (i = 0; i < n; i++) {
+ if (sr[i].state == SRS_DEAD) continue;
+ if (sr[i].state == SRS_LOW_HIGH) {
+ if (s < sr[i].low) continue;
+ if (s >= sr[i].high) {
+ if (forward_search(set->rs[i].reg, str, end, s, sr[i].sch_range,
+ &low, &high, &low_prev) != 0) {
+ sr[i].low = low;
+ sr[i].high = high;
+ /* sr[i].low_prev = low_prev; */
+ if (s < low) continue;
+ }
+ else {
+ sr[i].state = SRS_DEAD;
+ continue;
+ }
+ }
+ }
+
+ reg = set->rs[i].reg;
+ if ((reg->anchor & ANCR_ANYCHAR_INF) == 0 || prev_is_newline != 0) {
+ REGSET_MATCH_AND_RETURN_CHECK(orig_range);
+ }
+ }
+
+ if (s >= range) break;
+
+ if (set->anychar_inf != 0)
+ prev_is_newline = ONIGENC_IS_MBC_NEWLINE(set->enc, s, end);
+
+ prev = s;
+ s += enclen(enc, s);
+ } while (1);
+ }
+
+ xfree(sr);
+ return ONIG_MISMATCH;
+
+ finish:
+ xfree(sr);
+ return r;
+
+ match:
+ xfree(sr);
+ *rmatch_pos = (int )(s - str);
+ return i;
+}
+
+static inline int
+regset_search_body_regex_lead(OnigRegSet* set,
+ const UChar* str, const UChar* end,
+ const UChar* start, const UChar* orig_range, OnigRegSetLead lead,
+ OnigOptionType option, OnigMatchParam* mps[], int* rmatch_pos)
+{
+ int r;
+ int i;
+ int n;
+ int match_index;
+ const UChar* ep;
+ regex_t* reg;
+ OnigRegion* region;
+
+ n = set->n;
+
+ match_index = ONIG_MISMATCH;
+ ep = orig_range;
+ for (i = 0; i < n; i++) {
+ reg = set->rs[i].reg;
+ region = set->rs[i].region;
+ r = search_in_range(reg, str, end, start, ep, orig_range, region, option, mps[i]);
+ if (r > 0) {
+ if (str + r < ep) {
+ match_index = i;
+ *rmatch_pos = r;
+ if (lead == ONIG_REGSET_PRIORITY_TO_REGEX_ORDER)
+ break;
+
+ ep = str + r;
+ }
+ }
+ else if (r == 0) {
+ match_index = i;
+ *rmatch_pos = r;
+ break;
+ }
+ }
+
+ return match_index;
+}
+
+extern int
+onig_regset_search_with_param(OnigRegSet* set,
+ const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range,
+ OnigRegSetLead lead, OnigOptionType option, OnigMatchParam* mps[],
+ int* rmatch_pos)
+{
+ int r;
+ int i;
+ UChar *s, *prev;
+ regex_t* reg;
+ OnigEncoding enc;
+ OnigRegion* region;
+ MatchArg* msas;
+ const UChar *orig_start = start;
+ const UChar *orig_range = range;
+
+ if (set->n == 0)
+ return ONIG_MISMATCH;
+
+ if (OPTON_POSIX_REGION(option))
+ return ONIGERR_INVALID_ARGUMENT;
+
+ r = 0;
+ enc = set->enc;
+ msas = (MatchArg* )NULL;
+
+ for (i = 0; i < set->n; i++) {
+ reg = set->rs[i].reg;
+ region = set->rs[i].region;
+ ADJUST_MATCH_PARAM(reg, mps[i]);
+ if (IS_NOT_NULL(region)) {
+ r = onig_region_resize_clear(region, reg->num_mem + 1);
+ if (r != 0) goto finish_no_msa;
+ }
+ }
+
+ if (start > end || start < str) goto mismatch_no_msa;
+ if (str < end) {
+ /* forward search only */
+ if (range <= start)
+ return ONIGERR_INVALID_ARGUMENT;
+ }
+
+ if (OPTON_CHECK_VALIDITY_OF_STRING(option)) {
+ if (! ONIGENC_IS_VALID_MBC_STRING(enc, str, end)) {
+ r = ONIGERR_INVALID_WIDE_CHAR_VALUE;
+ goto finish_no_msa;
+ }
+ }
+
+ if (set->anchor != OPTIMIZE_NONE && str < end) {
+ UChar *min_semi_end, *max_semi_end;
+
+ if ((set->anchor & ANCR_BEGIN_POSITION) != 0) {
+ /* search start-position only */
+ begin_position:
+ range = start + 1;
+ }
+ else if ((set->anchor & ANCR_BEGIN_BUF) != 0) {
+ /* search str-position only */
+ if (start != str) goto mismatch_no_msa;
+ range = str + 1;
+ }
+ else if ((set->anchor & ANCR_END_BUF) != 0) {
+ min_semi_end = max_semi_end = (UChar* )end;
+
+ end_buf:
+ if ((OnigLen )(max_semi_end - str) < set->anc_dmin)
+ goto mismatch_no_msa;
+
+ if ((OnigLen )(min_semi_end - start) > set->anc_dmax) {
+ start = min_semi_end - set->anc_dmax;
+ if (start < end)
+ start = onigenc_get_right_adjust_char_head(enc, str, start);
+ }
+ if ((OnigLen )(max_semi_end - (range - 1)) < set->anc_dmin) {
+ range = max_semi_end - set->anc_dmin + 1;
+ }
+ if (start > range) goto mismatch_no_msa;
+ }
+ else if ((set->anchor & ANCR_SEMI_END_BUF) != 0) {
+ UChar* pre_end = ONIGENC_STEP_BACK(enc, str, end, 1);
+
+ max_semi_end = (UChar* )end;
+ if (ONIGENC_IS_MBC_NEWLINE(enc, pre_end, end)) {
+ min_semi_end = pre_end;
+
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ pre_end = ONIGENC_STEP_BACK(enc, str, pre_end, 1);
+ if (IS_NOT_NULL(pre_end) &&
+ ONIGENC_IS_MBC_CRNL(enc, pre_end, end)) {
+ min_semi_end = pre_end;
+ }
+#endif
+ if (min_semi_end > str && start <= min_semi_end) {
+ goto end_buf;
+ }
+ }
+ else {
+ min_semi_end = (UChar* )end;
+ goto end_buf;
+ }
+ }
+ else if ((set->anchor & ANCR_ANYCHAR_INF_ML) != 0) {
+ goto begin_position;
+ }
+ }
+ else if (str == end) { /* empty string */
+ start = end = str;
+ s = (UChar* )start;
+ prev = (UChar* )NULL;
+
+ msas = (MatchArg* )xmalloc(sizeof(*msas) * set->n);
+ CHECK_NULL_RETURN_MEMERR(msas);
+ for (i = 0; i < set->n; i++) {
+ reg = set->rs[i].reg;
+ MATCH_ARG_INIT(msas[i], reg, option, set->rs[i].region, start, mps[i]);
+ }
+ for (i = 0; i < set->n; i++) {
+ reg = set->rs[i].reg;
+ if (reg->threshold_len == 0) {
+ REGSET_MATCH_AND_RETURN_CHECK(end);
+ }
+ }
+
+ goto mismatch;
+ }
+
+ if (lead == ONIG_REGSET_POSITION_LEAD) {
+ msas = (MatchArg* )xmalloc(sizeof(*msas) * set->n);
+ CHECK_NULL_RETURN_MEMERR(msas);
+
+ for (i = 0; i < set->n; i++) {
+ MATCH_ARG_INIT(msas[i], set->rs[i].reg, option, set->rs[i].region,
+ orig_start, mps[i]);
+ }
+
+ r = regset_search_body_position_lead(set, str, end, start, range,
+ orig_range, option, msas, rmatch_pos);
+ }
+ else {
+ r = regset_search_body_regex_lead(set, str, end, start, orig_range,
+ lead, option, mps, rmatch_pos);
+ }
+ if (r < 0) goto finish;
+ else goto match2;
+
+ mismatch:
+ r = ONIG_MISMATCH;
+ finish:
+ for (i = 0; i < set->n; i++) {
+ if (IS_NOT_NULL(msas))
+ MATCH_ARG_FREE(msas[i]);
+ if (OPTON_FIND_NOT_EMPTY(set->rs[i].reg->options) &&
+ IS_NOT_NULL(set->rs[i].region)) {
+ onig_region_clear(set->rs[i].region);
+ }
+ }
+ if (IS_NOT_NULL(msas)) xfree(msas);
+ return r;
+
+ mismatch_no_msa:
+ r = ONIG_MISMATCH;
+ finish_no_msa:
+ return r;
+
+ match:
+ *rmatch_pos = (int )(s - str);
+ match2:
+ for (i = 0; i < set->n; i++) {
+ if (IS_NOT_NULL(msas))
+ MATCH_ARG_FREE(msas[i]);
+ if (OPTON_FIND_NOT_EMPTY(set->rs[i].reg->options) &&
+ IS_NOT_NULL(set->rs[i].region)) {
+ onig_region_clear(set->rs[i].region);
+ }
+ }
+ if (IS_NOT_NULL(msas)) xfree(msas);
+ return r; /* regex index */
+}
+
+extern int
+onig_regset_search(OnigRegSet* set, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range,
+ OnigRegSetLead lead, OnigOptionType option, int* rmatch_pos)
+{
+ int r;
+ int i;
+ OnigMatchParam* mp;
+ OnigMatchParam** mps;
+
+ mps = (OnigMatchParam** )xmalloc((sizeof(OnigMatchParam*) + sizeof(OnigMatchParam)) * set->n);
+ CHECK_NULL_RETURN_MEMERR(mps);
+
+ mp = (OnigMatchParam* )(mps + set->n);
+
+ for (i = 0; i < set->n; i++) {
+ onig_initialize_match_param(mp + i);
+ mps[i] = mp + i;
+ }
+
+ r = onig_regset_search_with_param(set, str, end, start, range, lead, option, mps,
+ rmatch_pos);
+ for (i = 0; i < set->n; i++)
+ onig_free_match_param_content(mp + i);
+
+ xfree(mps);
+
+ return r;
+}
+
+#endif /* USE_REGSET */
+
+
+static UChar*
+slow_search(OnigEncoding enc, UChar* target, UChar* target_end,
+ const UChar* text, const UChar* text_end, UChar* text_range)
+{
+ UChar *t, *p, *s, *end;
+
+ end = (UChar* )text_end;
+ end -= target_end - target - 1;
+ if (end > text_range)
+ end = text_range;
+
+ s = (UChar* )text;
+
+ while (s < end) {
+ if (*s == *target) {
+ p = s + 1;
+ t = target + 1;
+ while (t < target_end) {
+ if (*t != *p++)
+ break;
+ t++;
+ }
+ if (t == target_end)
+ return s;
+ }
+ s += enclen(enc, s);
+ }
+
+ return (UChar* )NULL;
+}
+
+static UChar*
+slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end,
+ const UChar* text, const UChar* adjust_text,
+ const UChar* text_end, const UChar* text_start)
+{
+ UChar *t, *p, *s;
+
+ s = (UChar* )text_end;
+ s -= (target_end - target);
+ if (s > text_start)
+ s = (UChar* )text_start;
+ else
+ s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, adjust_text, s);
+
+ while (s >= text) {
+ if (*s == *target) {
+ p = s + 1;
+ t = target + 1;
+ while (t < target_end) {
+ if (*t != *p++)
+ break;
+ t++;
+ }
+ if (t == target_end)
+ return s;
+ }
+ s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s);
+ }
+
+ return (UChar* )NULL;
+}
+
+static UChar*
+sunday_quick_search_step_forward(regex_t* reg,
+ const UChar* target, const UChar* target_end,
+ const UChar* text, const UChar* text_end,
+ const UChar* text_range)
+{
+ const UChar *s, *se, *t, *p, *end;
+ const UChar *tail;
+ int skip, tlen1;
+ int map_offset;
+ OnigEncoding enc;
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP,
+ "sunday_quick_search_step_forward: text: %p, text_end: %p, text_range: %p\n",
+ text, text_end, text_range);
+#endif
+
+ enc = reg->enc;
+
+ tail = target_end - 1;
+ tlen1 = (int )(tail - target);
+ end = text_range;
+ if (end + tlen1 > text_end)
+ end = text_end - tlen1;
+
+ map_offset = reg->map_offset;
+ s = text;
+
+ while (s < end) {
+ p = se = s + tlen1;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )s;
+ p--; t--;
+ }
+ if (se + map_offset >= text_end) break;
+ skip = reg->map[*(se + map_offset)];
+#if 0
+ t = s;
+ do {
+ s += enclen(enc, s);
+ } while ((s - t) < skip && s < end);
+#else
+ s += skip;
+ if (s < end)
+ s = onigenc_get_right_adjust_char_head(enc, text, s);
+#endif
+ }
+
+ return (UChar* )NULL;
+}
+
+static UChar*
+sunday_quick_search(regex_t* reg, const UChar* target, const UChar* target_end,
+ const UChar* text, const UChar* text_end,
+ const UChar* text_range)
+{
+ const UChar *s, *t, *p, *end;
+ const UChar *tail;
+ int map_offset;
+
+ end = text_range + (target_end - target);
+ if (end > text_end)
+ end = text_end;
+
+ map_offset = reg->map_offset;
+ tail = target_end - 1;
+ s = text + (tail - target);
+
+ while (s < end) {
+ p = s;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )p;
+ p--; t--;
+ }
+ if (s + map_offset >= text_end) break;
+ s += reg->map[*(s + map_offset)];
+ }
+
+ return (UChar* )NULL;
+}
+
+static UChar*
+map_search(OnigEncoding enc, UChar map[],
+ const UChar* text, const UChar* text_range)
+{
+ const UChar *s = text;
+
+ while (s < text_range) {
+ if (map[*s]) return (UChar* )s;
+
+ s += enclen(enc, s);
+ }
+ return (UChar* )NULL;
+}
+
+static UChar*
+map_search_backward(OnigEncoding enc, UChar map[],
+ const UChar* text, const UChar* adjust_text,
+ const UChar* text_start)
+{
+ const UChar *s = text_start;
+
+ while (s >= text) {
+ if (map[*s]) return (UChar* )s;
+
+ s = onigenc_get_prev_char_head(enc, adjust_text, s);
+ }
+ return (UChar* )NULL;
+}
+extern int
+onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at,
+ OnigRegion* region, OnigOptionType option)
+{
+ int r;
+ OnigMatchParam mp;
+
+ onig_initialize_match_param(&mp);
+ r = onig_match_with_param(reg, str, end, at, region, option, &mp);
+ onig_free_match_param_content(&mp);
+ return r;
+}
+
+extern int
+onig_match_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* at, OnigRegion* region, OnigOptionType option,
+ OnigMatchParam* mp)
+{
+ int r;
+ UChar *prev;
+ MatchArg msa;
+
+ ADJUST_MATCH_PARAM(reg, mp);
+ MATCH_ARG_INIT(msa, reg, option, region, at, mp);
+ if (region
+#ifdef USE_POSIX_API_REGION_OPTION
+ && !OPTON_POSIX_REGION(option)
+#endif
+ ) {
+ r = onig_region_resize_clear(region, reg->num_mem + 1);
+ }
+ else
+ r = 0;
+
+ if (r == 0) {
+ if (OPTON_CHECK_VALIDITY_OF_STRING(option)) {
+ if (! ONIGENC_IS_VALID_MBC_STRING(reg->enc, str, end)) {
+ r = ONIGERR_INVALID_WIDE_CHAR_VALUE;
+ goto end;
+ }
+ }
+
+ prev = (UChar* )onigenc_get_prev_char_head(reg->enc, str, at);
+ r = match_at(reg, str, end, end, at, prev, &msa);
+ }
+
+ end:
+ MATCH_ARG_FREE(msa);
+ return r;
+}
+
+static int
+forward_search(regex_t* reg, const UChar* str, const UChar* end, UChar* start,
+ UChar* range, UChar** low, UChar** high, UChar** low_prev)
+{
+ UChar *p, *pprev = (UChar* )NULL;
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP, "forward_search: str: %p, end: %p, start: %p, range: %p\n",
+ str, end, start, range);
+#endif
+
+ p = start;
+ if (reg->dist_min != 0) {
+ if (end - p <= reg->dist_min)
+ return 0; /* fail */
+
+ if (ONIGENC_IS_SINGLEBYTE(reg->enc)) {
+ p += reg->dist_min;
+ }
+ else {
+ UChar *q = p + reg->dist_min;
+ while (p < q) p += enclen(reg->enc, p);
+ }
+ }
+
+ retry:
+ switch (reg->optimize) {
+ case OPTIMIZE_STR:
+ p = slow_search(reg->enc, reg->exact, reg->exact_end, p, end, range);
+ break;
+
+ case OPTIMIZE_STR_FAST:
+ p = sunday_quick_search(reg, reg->exact, reg->exact_end, p, end, range);
+ break;
+
+ case OPTIMIZE_STR_FAST_STEP_FORWARD:
+ p = sunday_quick_search_step_forward(reg, reg->exact, reg->exact_end,
+ p, end, range);
+ break;
+
+ case OPTIMIZE_MAP:
+ p = map_search(reg->enc, reg->map, p, range);
+ break;
+ }
+
+ if (p && p < range) {
+ if (p - start < reg->dist_min) {
+ retry_gate:
+ pprev = p;
+ p += enclen(reg->enc, p);
+ goto retry;
+ }
+
+ if (reg->sub_anchor) {
+ UChar* prev;
+
+ switch (reg->sub_anchor) {
+ case ANCR_BEGIN_LINE:
+ if (!ON_STR_BEGIN(p)) {
+ prev = onigenc_get_prev_char_head(reg->enc, (pprev ? pprev : str), p);
+ if (!ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end))
+ goto retry_gate;
+ }
+ break;
+
+ case ANCR_END_LINE:
+ if (ON_STR_END(p)) {
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ prev = (UChar* )onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), p);
+ if (prev && ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end))
+ goto retry_gate;
+#endif
+ }
+ else if (! ONIGENC_IS_MBC_NEWLINE(reg->enc, p, end)
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ && ! ONIGENC_IS_MBC_CRNL(reg->enc, p, end)
+#endif
+ )
+ goto retry_gate;
+
+ break;
+ }
+ }
+
+ if (reg->dist_max == 0) {
+ *low = p;
+ if (low_prev) {
+ if (*low > start)
+ *low_prev = onigenc_get_prev_char_head(reg->enc, start, p);
+ else
+ *low_prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), p);
+ }
+ *high = p;
+ }
+ else {
+ if (reg->dist_max != INFINITE_LEN) {
+ if (p - str < reg->dist_max) {
+ *low = (UChar* )str;
+ if (low_prev)
+ *low_prev = onigenc_get_prev_char_head(reg->enc, str, *low);
+ }
+ else {
+ *low = p - reg->dist_max;
+ if (*low > start) {
+ *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, start,
+ *low, (const UChar** )low_prev);
+ }
+ else {
+ if (low_prev)
+ *low_prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), *low);
+ }
+ }
+ }
+ /* no needs to adjust *high, *high is used as range check only */
+ if (p - str < reg->dist_min)
+ *high = (UChar* )str;
+ else
+ *high = p - reg->dist_min;
+ }
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP,
+ "forward_search success: low: %d, high: %d, dmin: %u, dmax: %u\n",
+ (int )(*low - str), (int )(*high - str),
+ reg->dist_min, reg->dist_max);
+#endif
+ return 1; /* success */
+ }
+
+ return 0; /* fail */
+}
+
+
+static int
+backward_search(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
+ const UChar* range, UChar* adjrange, UChar** low, UChar** high)
+{
+ UChar *p;
+
+ p = s;
+
+ retry:
+ switch (reg->optimize) {
+ case OPTIMIZE_STR:
+ exact_method:
+ p = slow_search_backward(reg->enc, reg->exact, reg->exact_end,
+ range, adjrange, end, p);
+ break;
+
+ case OPTIMIZE_STR_FAST:
+ case OPTIMIZE_STR_FAST_STEP_FORWARD:
+ goto exact_method;
+ break;
+
+ case OPTIMIZE_MAP:
+ p = map_search_backward(reg->enc, reg->map, range, adjrange, p);
+ break;
+ }
+
+ if (p) {
+ if (reg->sub_anchor) {
+ UChar* prev;
+
+ switch (reg->sub_anchor) {
+ case ANCR_BEGIN_LINE:
+ if (!ON_STR_BEGIN(p)) {
+ prev = onigenc_get_prev_char_head(reg->enc, str, p);
+ if (IS_NOT_NULL(prev) && !ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end)) {
+ p = prev;
+ goto retry;
+ }
+ }
+ break;
+
+ case ANCR_END_LINE:
+ if (ON_STR_END(p)) {
+#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
+ prev = onigenc_get_prev_char_head(reg->enc, adjrange, p);
+ if (IS_NULL(prev)) goto fail;
+ if (ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end)) {
+ p = prev;
+ goto retry;
+ }
+#endif
+ }
+ else if (! ONIGENC_IS_MBC_NEWLINE(reg->enc, p, end)
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ && ! ONIGENC_IS_MBC_CRNL(reg->enc, p, end)
+#endif
+ ) {
+ p = onigenc_get_prev_char_head(reg->enc, adjrange, p);
+ if (IS_NULL(p)) goto fail;
+ goto retry;
+ }
+ break;
+ }
+ }
+
+ if (reg->dist_max != INFINITE_LEN) {
+ if (p - str < reg->dist_max)
+ *low = (UChar* )str;
+ else
+ *low = p - reg->dist_max;
+
+ if (reg->dist_min != 0) {
+ if (p - str < reg->dist_min)
+ *high = (UChar* )str;
+ else
+ *high = p - reg->dist_min;
+ }
+ else {
+ *high = p;
+ }
+
+ *high = onigenc_get_right_adjust_char_head(reg->enc, adjrange, *high);
+ }
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP, "backward_search: low: %d, high: %d\n",
+ (int )(*low - str), (int )(*high - str));
+#endif
+ return 1; /* success */
+ }
+
+ fail:
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP, "backward_search: fail.\n");
+#endif
+ return 0; /* fail */
+}
+
+
+extern int
+onig_search(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, OnigRegion* region,
+ OnigOptionType option)
+{
+ int r;
+ OnigMatchParam mp;
+ const UChar* data_range;
+
+ onig_initialize_match_param(&mp);
+
+ /* The following is an expanded code of onig_search_with_param() */
+ if (range > start)
+ data_range = range;
+ else
+ data_range = end;
+
+ r = search_in_range(reg, str, end, start, range, data_range, region,
+ option, &mp);
+
+ onig_free_match_param_content(&mp);
+ return r;
+
+}
+
+static int
+search_in_range(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, /* match start range */
+ const UChar* data_range, /* subject string range */
+ OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+{
+ int r;
+ UChar *s, *prev;
+ MatchArg msa;
+ const UChar *orig_start = start;
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP,
+ "onig_search (entry point): str: %p, end: %d, start: %d, range: %d\n",
+ str, (int )(end - str), (int )(start - str), (int )(range - str));
+#endif
+
+ ADJUST_MATCH_PARAM(reg, mp);
+
+ if (region
+#ifdef USE_POSIX_API_REGION_OPTION
+ && ! OPTON_POSIX_REGION(option)
+#endif
+ ) {
+ r = onig_region_resize_clear(region, reg->num_mem + 1);
+ if (r != 0) goto finish_no_msa;
+ }
+
+ if (start > end || start < str) goto mismatch_no_msa;
+
+ if (OPTON_CHECK_VALIDITY_OF_STRING(option)) {
+ if (! ONIGENC_IS_VALID_MBC_STRING(reg->enc, str, end)) {
+ r = ONIGERR_INVALID_WIDE_CHAR_VALUE;
+ goto finish_no_msa;
+ }
+ }
+
+
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+#define MATCH_AND_RETURN_CHECK(upper_range) \
+ r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ if (! OPTON_FIND_LONGEST(reg->options)) {\
+ goto match;\
+ }\
+ }\
+ else goto finish; /* error */ \
+ }
+#else
+#define MATCH_AND_RETURN_CHECK(upper_range) \
+ r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
+ }
+#endif /* USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE */
+
+
+ /* anchor optimize: resume search range */
+ if (reg->anchor != 0 && str < end) {
+ UChar *min_semi_end, *max_semi_end;
+
+ if (reg->anchor & ANCR_BEGIN_POSITION) {
+ /* search start-position only */
+ begin_position:
+ if (range > start)
+ range = start + 1;
+ else
+ range = start;
+ }
+ else if (reg->anchor & ANCR_BEGIN_BUF) {
+ /* search str-position only */
+ if (range > start) {
+ if (start != str) goto mismatch_no_msa;
+ range = str + 1;
+ }
+ else {
+ if (range <= str) {
+ start = str;
+ range = str;
+ }
+ else
+ goto mismatch_no_msa;
+ }
+ }
+ else if (reg->anchor & ANCR_END_BUF) {
+ min_semi_end = max_semi_end = (UChar* )end;
+
+ end_buf:
+ if ((OnigLen )(max_semi_end - str) < reg->anc_dist_min)
+ goto mismatch_no_msa;
+
+ if (range > start) {
+ if (reg->anc_dist_max != INFINITE_LEN &&
+ min_semi_end - start > reg->anc_dist_max) {
+ start = min_semi_end - reg->anc_dist_max;
+ if (start < end)
+ start = onigenc_get_right_adjust_char_head(reg->enc, str, start);
+ }
+ if (max_semi_end - (range - 1) < reg->anc_dist_min) {
+ if (max_semi_end - str + 1 < reg->anc_dist_min)
+ goto mismatch_no_msa;
+ else
+ range = max_semi_end - reg->anc_dist_min + 1;
+ }
+
+ if (start > range) goto mismatch_no_msa;
+ /* If start == range, match with empty at end.
+ Backward search is used. */
+ }
+ else {
+ if (reg->anc_dist_max != INFINITE_LEN &&
+ min_semi_end - range > reg->anc_dist_max) {
+ range = min_semi_end - reg->anc_dist_max;
+ }
+ if (max_semi_end - start < reg->anc_dist_min) {
+ if (max_semi_end - str < reg->anc_dist_min)
+ goto mismatch_no_msa;
+ else {
+ start = max_semi_end - reg->anc_dist_min;
+ start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, start);
+ }
+ }
+ if (range > start) goto mismatch_no_msa;
+ }
+ }
+ else if (reg->anchor & ANCR_SEMI_END_BUF) {
+ UChar* pre_end = ONIGENC_STEP_BACK(reg->enc, str, end, 1);
+
+ max_semi_end = (UChar* )end;
+ if (ONIGENC_IS_MBC_NEWLINE(reg->enc, pre_end, end)) {
+ min_semi_end = pre_end;
+
+#ifdef USE_CRNL_AS_LINE_TERMINATOR
+ pre_end = ONIGENC_STEP_BACK(reg->enc, str, pre_end, 1);
+ if (IS_NOT_NULL(pre_end) &&
+ ONIGENC_IS_MBC_CRNL(reg->enc, pre_end, end)) {
+ min_semi_end = pre_end;
+ }
+#endif
+ if (min_semi_end > str && start <= min_semi_end) {
+ goto end_buf;
+ }
+ }
+ else {
+ min_semi_end = (UChar* )end;
+ goto end_buf;
+ }
+ }
+ else if ((reg->anchor & ANCR_ANYCHAR_INF_ML)) {
+ goto begin_position;
+ }
+ }
+ else if (str == end) { /* empty string */
+ static const UChar* address_for_empty_string = (UChar* )"";
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP, "onig_search: empty string.\n");
+#endif
+
+ if (reg->threshold_len == 0) {
+ start = end = str = address_for_empty_string;
+ s = (UChar* )start;
+ prev = (UChar* )NULL;
+
+ MATCH_ARG_INIT(msa, reg, option, region, start, mp);
+ MATCH_AND_RETURN_CHECK(end);
+ goto mismatch;
+ }
+ goto mismatch_no_msa;
+ }
+
+#ifdef ONIG_DEBUG_SEARCH
+ fprintf(DBGFP, "onig_search(apply anchor): end: %d, start: %d, range: %d\n",
+ (int )(end - str), (int )(start - str), (int )(range - str));
+#endif
+
+ MATCH_ARG_INIT(msa, reg, option, region, orig_start, mp);
+
+ s = (UChar* )start;
+ if (range > start) { /* forward search */
+ if (s > str)
+ prev = onigenc_get_prev_char_head(reg->enc, str, s);
+ else
+ prev = (UChar* )NULL;
+
+ if (reg->optimize != OPTIMIZE_NONE) {
+ UChar *sch_range, *low, *high, *low_prev;
+
+ if (reg->dist_max != 0) {
+ if (reg->dist_max == INFINITE_LEN)
+ sch_range = (UChar* )end;
+ else {
+ if ((end - range) < reg->dist_max)
+ sch_range = (UChar* )end;
+ else {
+ sch_range = (UChar* )range + reg->dist_max;
+ }
+ }
+ }
+ else
+ sch_range = (UChar* )range;
+
+ if ((end - start) < reg->threshold_len)
+ goto mismatch;
+
+ if (reg->dist_max != INFINITE_LEN) {
+ do {
+ if (! forward_search(reg, str, end, s, sch_range, &low, &high,
+ &low_prev)) goto mismatch;
+ if (s < low) {
+ s = low;
+ prev = low_prev;
+ }
+ while (s <= high) {
+ MATCH_AND_RETURN_CHECK(data_range);
+ prev = s;
+ s += enclen(reg->enc, s);
+ }
+ } while (s < range);
+ goto mismatch;
+ }
+ else { /* check only. */
+ if (! forward_search(reg, str, end, s, sch_range, &low, &high,
+ (UChar** )NULL)) goto mismatch;
+
+ if ((reg->anchor & ANCR_ANYCHAR_INF) != 0 &&
+ (reg->anchor & (ANCR_LOOK_BEHIND | ANCR_PREC_READ_NOT)) == 0) {
+ do {
+ MATCH_AND_RETURN_CHECK(data_range);
+ prev = s;
+ s += enclen(reg->enc, s);
+
+ while (!ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end) && s < range) {
+ prev = s;
+ s += enclen(reg->enc, s);
+ }
+ } while (s < range);
+ goto mismatch;
+ }
+ }
+ }
+
+ do {
+ MATCH_AND_RETURN_CHECK(data_range);
+ prev = s;
+ s += enclen(reg->enc, s);
+ } while (s < range);
+
+ if (s == range) { /* because empty match with /$/. */
+ MATCH_AND_RETURN_CHECK(data_range);
+ }
+ }
+ else { /* backward search */
+ if (range < str) goto mismatch;
+
+ if (orig_start < end)
+ orig_start += enclen(reg->enc, orig_start); /* is upper range */
+
+ if (reg->optimize != OPTIMIZE_NONE) {
+ UChar *low, *high, *adjrange, *sch_start;
+ const UChar *min_range;
+
+ if ((end - range) < reg->threshold_len) goto mismatch;
+
+ if (range < end)
+ adjrange = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, range);
+ else
+ adjrange = (UChar* )end;
+
+ if (end - range > reg->dist_min)
+ min_range = range + reg->dist_min;
+ else
+ min_range = end;
+
+ if (reg->dist_max != INFINITE_LEN) {
+ do {
+ if (end - s > reg->dist_max)
+ sch_start = s + reg->dist_max;
+ else {
+ sch_start = onigenc_get_prev_char_head(reg->enc, str, end);
+ }
+
+ if (backward_search(reg, str, end, sch_start, min_range, adjrange,
+ &low, &high) <= 0)
+ goto mismatch;
+
+ if (s > high)
+ s = high;
+
+ while (s >= low) {
+ prev = onigenc_get_prev_char_head(reg->enc, str, s);
+ MATCH_AND_RETURN_CHECK(orig_start);
+ s = prev;
+ }
+ } while (s >= range);
+ goto mismatch;
+ }
+ else { /* check only. */
+ sch_start = onigenc_get_prev_char_head(reg->enc, str, end);
+
+ if (backward_search(reg, str, end, sch_start, min_range, adjrange,
+ &low, &high) <= 0) goto mismatch;
+ }
+ }
+
+ do {
+ prev = onigenc_get_prev_char_head(reg->enc, str, s);
+ MATCH_AND_RETURN_CHECK(orig_start);
+ s = prev;
+ } while (s >= range);
+ }
+
+ mismatch:
+#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+ if (OPTON_FIND_LONGEST(reg->options)) {
+ if (msa.best_len >= 0) {
+ s = msa.best_s;
+ goto match;
+ }
+ }
+#endif
+ r = ONIG_MISMATCH;
+
+ finish:
+ MATCH_ARG_FREE(msa);
+
+ /* If result is mismatch and no FIND_NOT_EMPTY option,
+ then the region is not set in match_at(). */
+ if (OPTON_FIND_NOT_EMPTY(reg->options) && region
+#ifdef USE_POSIX_API_REGION_OPTION
+ && !OPTON_POSIX_REGION(option)
+#endif
+ ) {
+ onig_region_clear(region);
+ }
+
+#ifdef ONIG_DEBUG
+ if (r != ONIG_MISMATCH)
+ fprintf(DBGFP, "onig_search: error %d\n", r);
+#endif
+ return r;
+
+ mismatch_no_msa:
+ r = ONIG_MISMATCH;
+ finish_no_msa:
+#ifdef ONIG_DEBUG
+ if (r != ONIG_MISMATCH)
+ fprintf(DBGFP, "onig_search: error %d\n", r);
+#endif
+ return r;
+
+ match:
+ MATCH_ARG_FREE(msa);
+ return (int )(s - str);
+}
+
+extern int
+onig_search_with_param(regex_t* reg, const UChar* str, const UChar* end,
+ const UChar* start, const UChar* range, OnigRegion* region,
+ OnigOptionType option, OnigMatchParam* mp)
+{
+ const UChar* data_range;
+
+ if (range > start)
+ data_range = range;
+ else
+ data_range = end;
+
+ return search_in_range(reg, str, end, start, range, data_range, region,
+ option, mp);
+}
+
+extern int
+onig_scan(regex_t* reg, const UChar* str, const UChar* end,
+ OnigRegion* region, OnigOptionType option,
+ int (*scan_callback)(int, int, OnigRegion*, void*),
+ void* callback_arg)
+{
+ int r;
+ int n;
+ int rs;
+ const UChar* start;
+
+ if (OPTON_CHECK_VALIDITY_OF_STRING(option)) {
+ if (! ONIGENC_IS_VALID_MBC_STRING(reg->enc, str, end))
+ return ONIGERR_INVALID_WIDE_CHAR_VALUE;
+
+ ONIG_OPTION_OFF(option, ONIG_OPTION_CHECK_VALIDITY_OF_STRING);
+ }
+
+ n = 0;
+ start = str;
+ while (1) {
+ r = onig_search(reg, str, end, start, end, region, option);
+ if (r >= 0) {
+ rs = scan_callback(n, r, region, callback_arg);
+ n++;
+ if (rs != 0)
+ return rs;
+
+ if (region->end[0] == start - str) {
+ if (start >= end) break;
+ start += enclen(reg->enc, start);
+ }
+ else
+ start = str + region->end[0];
+
+ if (start > end)
+ break;
+ }
+ else if (r == ONIG_MISMATCH) {
+ break;
+ }
+ else { /* error */
+ return r;
+ }
+ }
+
+ return n;
+}
+
+extern OnigEncoding
+onig_get_encoding(regex_t* reg)
+{
+ return reg->enc;
+}
+
+extern OnigOptionType
+onig_get_options(regex_t* reg)
+{
+ return reg->options;
+}
+
+extern OnigCaseFoldType
+onig_get_case_fold_flag(regex_t* reg)
+{
+ return reg->case_fold_flag;
+}
+
+extern OnigSyntaxType*
+onig_get_syntax(regex_t* reg)
+{
+ return reg->syntax;
+}
+
+extern int
+onig_number_of_captures(regex_t* reg)
+{
+ return reg->num_mem;
+}
+
+extern int
+onig_number_of_capture_histories(regex_t* reg)
+{
+#ifdef USE_CAPTURE_HISTORY
+ int i, n;
+
+ n = 0;
+ for (i = 0; i <= ONIG_MAX_CAPTURE_HISTORY_GROUP; i++) {
+ if (MEM_STATUS_AT(reg->capture_history, i) != 0)
+ n++;
+ }
+ return n;
+#else
+ return 0;
+#endif
+}
+
+extern void
+onig_copy_encoding(OnigEncoding to, OnigEncoding from)
+{
+ *to = *from;
+}
+
+#ifdef USE_REGSET
+
+extern int
+onig_regset_new(OnigRegSet** rset, int n, regex_t* regs[])
+{
+#define REGSET_INITIAL_ALLOC_SIZE 10
+
+ int i;
+ int r;
+ int alloc;
+ OnigRegSet* set;
+ RR* rs;
+
+ *rset = 0;
+
+ set = (OnigRegSet* )xmalloc(sizeof(*set));
+ CHECK_NULL_RETURN_MEMERR(set);
+
+ alloc = n > REGSET_INITIAL_ALLOC_SIZE ? n : REGSET_INITIAL_ALLOC_SIZE;
+ rs = (RR* )xmalloc(sizeof(set->rs[0]) * alloc);
+ if (IS_NULL(rs)) {
+ xfree(set);
+ return ONIGERR_MEMORY;
+ }
+
+ set->rs = rs;
+ set->n = 0;
+ set->alloc = alloc;
+
+ for (i = 0; i < n; i++) {
+ regex_t* reg = regs[i];
+
+ r = onig_regset_add(set, reg);
+ if (r != 0) {
+ for (i = 0; i < set->n; i++) {
+ OnigRegion* region = set->rs[i].region;
+ if (IS_NOT_NULL(region))
+ onig_region_free(region, 1);
+ }
+ xfree(set->rs);
+ xfree(set);
+ return r;
+ }
+ }
+
+ *rset = set;
+ return 0;
+}
+
+static void
+update_regset_by_reg(OnigRegSet* set, regex_t* reg)
+{
+ if (set->n == 1) {
+ set->enc = reg->enc;
+ set->anchor = reg->anchor;
+ set->anc_dmin = reg->anc_dist_min;
+ set->anc_dmax = reg->anc_dist_max;
+ set->all_low_high =
+ (reg->optimize == OPTIMIZE_NONE || reg->dist_max == INFINITE_LEN) ? 0 : 1;
+ set->anychar_inf = (reg->anchor & ANCR_ANYCHAR_INF) != 0 ? 1 : 0;
+ }
+ else {
+ int anchor;
+
+ anchor = set->anchor & reg->anchor;
+ if (anchor != 0) {
+ OnigLen anc_dmin;
+ OnigLen anc_dmax;
+
+ anc_dmin = set->anc_dmin;
+ anc_dmax = set->anc_dmax;
+ if (anc_dmin > reg->anc_dist_min) anc_dmin = reg->anc_dist_min;
+ if (anc_dmax < reg->anc_dist_max) anc_dmax = reg->anc_dist_max;
+ set->anc_dmin = anc_dmin;
+ set->anc_dmax = anc_dmax;
+ }
+
+ set->anchor = anchor;
+
+ if (reg->optimize == OPTIMIZE_NONE || reg->dist_max == INFINITE_LEN)
+ set->all_low_high = 0;
+
+ if ((reg->anchor & ANCR_ANYCHAR_INF) != 0)
+ set->anychar_inf = 1;
+ }
+}
+
+extern int
+onig_regset_add(OnigRegSet* set, regex_t* reg)
+{
+ OnigRegion* region;
+
+ if (OPTON_FIND_LONGEST(reg->options))
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (set->n != 0 && reg->enc != set->enc)
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (set->n >= set->alloc) {
+ RR* nrs;
+ int new_alloc;
+
+ new_alloc = set->alloc * 2;
+ nrs = (RR* )xrealloc(set->rs, sizeof(set->rs[0]) * new_alloc);
+ CHECK_NULL_RETURN_MEMERR(nrs);
+
+ set->rs = nrs;
+ set->alloc = new_alloc;
+ }
+
+ region = onig_region_new();
+ CHECK_NULL_RETURN_MEMERR(region);
+
+ set->rs[set->n].reg = reg;
+ set->rs[set->n].region = region;
+ set->n++;
+
+ update_regset_by_reg(set, reg);
+ return 0;
+}
+
+extern int
+onig_regset_replace(OnigRegSet* set, int at, regex_t* reg)
+{
+ int i;
+
+ if (at < 0 || at >= set->n)
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (IS_NULL(reg)) {
+ onig_region_free(set->rs[at].region, 1);
+ for (i = at; i < set->n - 1; i++) {
+ set->rs[i].reg = set->rs[i+1].reg;
+ set->rs[i].region = set->rs[i+1].region;
+ }
+ set->n--;
+ }
+ else {
+ if (OPTON_FIND_LONGEST(reg->options))
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (set->n > 1 && reg->enc != set->enc)
+ return ONIGERR_INVALID_ARGUMENT;
+
+ set->rs[at].reg = reg;
+ }
+
+ for (i = 0; i < set->n; i++)
+ update_regset_by_reg(set, set->rs[i].reg);
+
+ return 0;
+}
+
+extern void
+onig_regset_free(OnigRegSet* set)
+{
+ int i;
+
+ for (i = 0; i < set->n; i++) {
+ regex_t* reg;
+ OnigRegion* region;
+
+ reg = set->rs[i].reg;
+ region = set->rs[i].region;
+ onig_free(reg);
+ if (IS_NOT_NULL(region))
+ onig_region_free(region, 1);
+ }
+
+ xfree(set->rs);
+ xfree(set);
+}
+
+extern int
+onig_regset_number_of_regex(OnigRegSet* set)
+{
+ return set->n;
+}
+
+extern regex_t*
+onig_regset_get_regex(OnigRegSet* set, int at)
+{
+ if (at < 0 || at >= set->n)
+ return (regex_t* )0;
+
+ return set->rs[at].reg;
+}
+
+extern OnigRegion*
+onig_regset_get_region(OnigRegSet* set, int at)
+{
+ if (at < 0 || at >= set->n)
+ return (OnigRegion* )0;
+
+ return set->rs[at].region;
+}
+
+#endif /* USE_REGSET */
+
+
+#ifdef USE_DIRECT_THREADED_CODE
+extern int
+onig_init_for_match_at(regex_t* reg)
+{
+ return match_at(reg, (const UChar* )NULL, (const UChar* )NULL,
+ (const UChar* )NULL, (const UChar* )NULL, (UChar* )NULL,
+ (MatchArg* )NULL);
+}
+#endif
+
+
+/* for callout functions */
+
+#ifdef USE_CALLOUT
+
+extern OnigCalloutFunc
+onig_get_progress_callout(void)
+{
+ return DefaultProgressCallout;
+}
+
+extern int
+onig_set_progress_callout(OnigCalloutFunc f)
+{
+ DefaultProgressCallout = f;
+ return ONIG_NORMAL;
+}
+
+extern OnigCalloutFunc
+onig_get_retraction_callout(void)
+{
+ return DefaultRetractionCallout;
+}
+
+extern int
+onig_set_retraction_callout(OnigCalloutFunc f)
+{
+ DefaultRetractionCallout = f;
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_get_callout_num_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->num;
+}
+
+extern OnigCalloutIn
+onig_get_callout_in_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->in;
+}
+
+extern int
+onig_get_name_id_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->name_id;
+}
+
+extern const UChar*
+onig_get_contents_by_callout_args(OnigCalloutArgs* args)
+{
+ int num;
+ CalloutListEntry* e;
+
+ num = args->num;
+ e = onig_reg_callout_list_at(args->regex, num);
+ if (IS_NULL(e)) return 0;
+ if (e->of == ONIG_CALLOUT_OF_CONTENTS) {
+ return e->u.content.start;
+ }
+
+ return 0;
+}
+
+extern const UChar*
+onig_get_contents_end_by_callout_args(OnigCalloutArgs* args)
+{
+ int num;
+ CalloutListEntry* e;
+
+ num = args->num;
+ e = onig_reg_callout_list_at(args->regex, num);
+ if (IS_NULL(e)) return 0;
+ if (e->of == ONIG_CALLOUT_OF_CONTENTS) {
+ return e->u.content.end;
+ }
+
+ return 0;
+}
+
+extern int
+onig_get_args_num_by_callout_args(OnigCalloutArgs* args)
+{
+ int num;
+ CalloutListEntry* e;
+
+ num = args->num;
+ e = onig_reg_callout_list_at(args->regex, num);
+ if (IS_NULL(e)) return ONIGERR_INVALID_ARGUMENT;
+ if (e->of == ONIG_CALLOUT_OF_NAME) {
+ return e->u.arg.num;
+ }
+
+ return ONIGERR_INVALID_ARGUMENT;
+}
+
+extern int
+onig_get_passed_args_num_by_callout_args(OnigCalloutArgs* args)
+{
+ int num;
+ CalloutListEntry* e;
+
+ num = args->num;
+ e = onig_reg_callout_list_at(args->regex, num);
+ if (IS_NULL(e)) return ONIGERR_INVALID_ARGUMENT;
+ if (e->of == ONIG_CALLOUT_OF_NAME) {
+ return e->u.arg.passed_num;
+ }
+
+ return ONIGERR_INVALID_ARGUMENT;
+}
+
+extern int
+onig_get_arg_by_callout_args(OnigCalloutArgs* args, int index,
+ OnigType* type, OnigValue* val)
+{
+ int num;
+ CalloutListEntry* e;
+
+ num = args->num;
+ e = onig_reg_callout_list_at(args->regex, num);
+ if (IS_NULL(e)) return ONIGERR_INVALID_ARGUMENT;
+ if (e->of == ONIG_CALLOUT_OF_NAME) {
+ if (IS_NOT_NULL(type)) *type = e->u.arg.types[index];
+ if (IS_NOT_NULL(val)) *val = e->u.arg.vals[index];
+ return ONIG_NORMAL;
+ }
+
+ return ONIGERR_INVALID_ARGUMENT;
+}
+
+extern const UChar*
+onig_get_string_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->string;
+}
+
+extern const UChar*
+onig_get_string_end_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->string_end;
+}
+
+extern const UChar*
+onig_get_start_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->start;
+}
+
+extern const UChar*
+onig_get_right_range_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->right_range;
+}
+
+extern const UChar*
+onig_get_current_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->current;
+}
+
+extern OnigRegex
+onig_get_regex_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->regex;
+}
+
+extern unsigned long
+onig_get_retry_counter_by_callout_args(OnigCalloutArgs* args)
+{
+ return args->retry_in_match_counter;
+}
+
+
+extern int
+onig_get_capture_range_in_callout(OnigCalloutArgs* a, int mem_num, int* begin, int* end)
+{
+ OnigRegex reg;
+ const UChar* str;
+ StackType* stk_base;
+ int i;
+ StackIndex* mem_start_stk;
+ StackIndex* mem_end_stk;
+
+ i = mem_num;
+ reg = a->regex;
+ str = a->string;
+ stk_base = a->stk_base;
+ mem_start_stk = a->mem_start_stk;
+ mem_end_stk = a->mem_end_stk;
+
+ if (i > 0) {
+ if (a->mem_end_stk[i] != INVALID_STACK_INDEX) {
+ *begin = (int )(STACK_MEM_START(reg, i) - str);
+ *end = (int )(STACK_MEM_END(reg, i) - str);
+ }
+ else {
+ *begin = *end = ONIG_REGION_NOTPOS;
+ }
+ }
+ else
+ return ONIGERR_INVALID_ARGUMENT;
+
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_get_used_stack_size_in_callout(OnigCalloutArgs* a, int* used_num, int* used_bytes)
+{
+ int n;
+
+ n = (int )(a->stk - a->stk_base);
+
+ if (used_num != 0)
+ *used_num = n;
+
+ if (used_bytes != 0)
+ *used_bytes = n * sizeof(StackType);
+
+ return ONIG_NORMAL;
+}
+
+
+/* builtin callout functions */
+
+extern int
+onig_builtin_fail(OnigCalloutArgs* args ARG_UNUSED, void* user_data ARG_UNUSED)
+{
+ return ONIG_CALLOUT_FAIL;
+}
+
+extern int
+onig_builtin_mismatch(OnigCalloutArgs* args ARG_UNUSED, void* user_data ARG_UNUSED)
+{
+ return ONIG_MISMATCH;
+}
+
+extern int
+onig_builtin_error(OnigCalloutArgs* args, void* user_data ARG_UNUSED)
+{
+ int r;
+ int n;
+ OnigValue val;
+
+ r = onig_get_arg_by_callout_args(args, 0, 0, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ n = (int )val.l;
+ if (n >= 0) {
+ n = ONIGERR_INVALID_CALLOUT_BODY;
+ }
+ else if (onig_is_error_code_needs_param(n)) {
+ n = ONIGERR_INVALID_CALLOUT_BODY;
+ }
+
+ return n;
+}
+
+extern int
+onig_builtin_count(OnigCalloutArgs* args, void* user_data)
+{
+ (void )onig_check_callout_data_and_clear_old_values(args);
+
+ return onig_builtin_total_count(args, user_data);
+}
+
+extern int
+onig_builtin_total_count(OnigCalloutArgs* args, void* user_data ARG_UNUSED)
+{
+ int r;
+ int slot;
+ OnigType type;
+ OnigValue val;
+ OnigValue aval;
+ OnigCodePoint count_type;
+
+ r = onig_get_arg_by_callout_args(args, 0, &type, &aval);
+ if (r != ONIG_NORMAL) return r;
+
+ count_type = aval.c;
+ if (count_type != '>' && count_type != 'X' && count_type != '<')
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ r = onig_get_callout_data_by_callout_args_self_dont_clear_old(args, 0,
+ &type, &val);
+ if (r < ONIG_NORMAL)
+ return r;
+ else if (r > ONIG_NORMAL) {
+ /* type == void: initial state */
+ val.l = 0;
+ }
+
+ if (args->in == ONIG_CALLOUT_IN_RETRACTION) {
+ slot = 2;
+ if (count_type == '<')
+ val.l++;
+ else if (count_type == 'X')
+ val.l--;
+ }
+ else {
+ slot = 1;
+ if (count_type != '<')
+ val.l++;
+ }
+
+ r = onig_set_callout_data_by_callout_args_self(args, 0, ONIG_TYPE_LONG, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ /* slot 1: in progress counter, slot 2: in retraction counter */
+ r = onig_get_callout_data_by_callout_args_self_dont_clear_old(args, slot,
+ &type, &val);
+ if (r < ONIG_NORMAL)
+ return r;
+ else if (r > ONIG_NORMAL) {
+ val.l = 0;
+ }
+
+ val.l++;
+ r = onig_set_callout_data_by_callout_args_self(args, slot, ONIG_TYPE_LONG, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+extern int
+onig_builtin_max(OnigCalloutArgs* args, void* user_data ARG_UNUSED)
+{
+ int r;
+ int slot;
+ long max_val;
+ OnigCodePoint count_type;
+ OnigType type;
+ OnigValue val;
+ OnigValue aval;
+
+ (void )onig_check_callout_data_and_clear_old_values(args);
+
+ slot = 0;
+ r = onig_get_callout_data_by_callout_args_self(args, slot, &type, &val);
+ if (r < ONIG_NORMAL)
+ return r;
+ else if (r > ONIG_NORMAL) {
+ /* type == void: initial state */
+ type = ONIG_TYPE_LONG;
+ val.l = 0;
+ }
+
+ r = onig_get_arg_by_callout_args(args, 0, &type, &aval);
+ if (r != ONIG_NORMAL) return r;
+ if (type == ONIG_TYPE_TAG) {
+ r = onig_get_callout_data_by_callout_args(args, aval.tag, 0, &type, &aval);
+ if (r < ONIG_NORMAL) return r;
+ else if (r > ONIG_NORMAL)
+ max_val = 0L;
+ else
+ max_val = aval.l;
+ }
+ else { /* LONG */
+ max_val = aval.l;
+ }
+
+ r = onig_get_arg_by_callout_args(args, 1, &type, &aval);
+ if (r != ONIG_NORMAL) return r;
+
+ count_type = aval.c;
+ if (count_type != '>' && count_type != 'X' && count_type != '<')
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if (args->in == ONIG_CALLOUT_IN_RETRACTION) {
+ if (count_type == '<') {
+ if (val.l >= max_val) return ONIG_CALLOUT_FAIL;
+ val.l++;
+ }
+ else if (count_type == 'X')
+ val.l--;
+ }
+ else {
+ if (count_type != '<') {
+ if (val.l >= max_val) return ONIG_CALLOUT_FAIL;
+ val.l++;
+ }
+ }
+
+ r = onig_set_callout_data_by_callout_args_self(args, slot, ONIG_TYPE_LONG, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+enum OP_CMP {
+ OP_EQ,
+ OP_NE,
+ OP_LT,
+ OP_GT,
+ OP_LE,
+ OP_GE
+};
+
+extern int
+onig_builtin_cmp(OnigCalloutArgs* args, void* user_data ARG_UNUSED)
+{
+ int r;
+ int slot;
+ long lv;
+ long rv;
+ OnigType type;
+ OnigValue val;
+ regex_t* reg;
+ enum OP_CMP op;
+
+ reg = args->regex;
+
+ r = onig_get_arg_by_callout_args(args, 0, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ if (type == ONIG_TYPE_TAG) {
+ r = onig_get_callout_data_by_callout_args(args, val.tag, 0, &type, &val);
+ if (r < ONIG_NORMAL) return r;
+ else if (r > ONIG_NORMAL)
+ lv = 0L;
+ else
+ lv = val.l;
+ }
+ else { /* ONIG_TYPE_LONG */
+ lv = val.l;
+ }
+
+ r = onig_get_arg_by_callout_args(args, 2, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ if (type == ONIG_TYPE_TAG) {
+ r = onig_get_callout_data_by_callout_args(args, val.tag, 0, &type, &val);
+ if (r < ONIG_NORMAL) return r;
+ else if (r > ONIG_NORMAL)
+ rv = 0L;
+ else
+ rv = val.l;
+ }
+ else { /* ONIG_TYPE_LONG */
+ rv = val.l;
+ }
+
+ slot = 0;
+ r = onig_get_callout_data_by_callout_args_self(args, slot, &type, &val);
+ if (r < ONIG_NORMAL)
+ return r;
+ else if (r > ONIG_NORMAL) {
+ /* type == void: initial state */
+ OnigCodePoint c1, c2;
+ UChar* p;
+
+ r = onig_get_arg_by_callout_args(args, 1, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ p = val.s.start;
+ c1 = ONIGENC_MBC_TO_CODE(reg->enc, p, val.s.end);
+ p += ONIGENC_MBC_ENC_LEN(reg->enc, p);
+ if (p < val.s.end) {
+ c2 = ONIGENC_MBC_TO_CODE(reg->enc, p, val.s.end);
+ p += ONIGENC_MBC_ENC_LEN(reg->enc, p);
+ if (p != val.s.end) return ONIGERR_INVALID_CALLOUT_ARG;
+ }
+ else
+ c2 = 0;
+
+ switch (c1) {
+ case '=':
+ if (c2 != '=') return ONIGERR_INVALID_CALLOUT_ARG;
+ op = OP_EQ;
+ break;
+ case '!':
+ if (c2 != '=') return ONIGERR_INVALID_CALLOUT_ARG;
+ op = OP_NE;
+ break;
+ case '<':
+ if (c2 == '=') op = OP_LE;
+ else if (c2 == 0) op = OP_LT;
+ else return ONIGERR_INVALID_CALLOUT_ARG;
+ break;
+ case '>':
+ if (c2 == '=') op = OP_GE;
+ else if (c2 == 0) op = OP_GT;
+ else return ONIGERR_INVALID_CALLOUT_ARG;
+ break;
+ default:
+ return ONIGERR_INVALID_CALLOUT_ARG;
+ break;
+ }
+ val.l = (long )op;
+ r = onig_set_callout_data_by_callout_args_self(args, slot, ONIG_TYPE_LONG, &val);
+ if (r != ONIG_NORMAL) return r;
+ }
+ else {
+ op = (enum OP_CMP )val.l;
+ }
+
+ switch (op) {
+ case OP_EQ: r = (lv == rv); break;
+ case OP_NE: r = (lv != rv); break;
+ case OP_LT: r = (lv < rv); break;
+ case OP_GT: r = (lv > rv); break;
+ case OP_LE: r = (lv <= rv); break;
+ case OP_GE: r = (lv >= rv); break;
+ }
+
+ return r == 0 ? ONIG_CALLOUT_FAIL : ONIG_CALLOUT_SUCCESS;
+}
+
+
+#ifndef ONIG_NO_PRINT
+
+static FILE* OutFp;
+
+/* name start with "onig_" for macros. */
+static int
+onig_builtin_monitor(OnigCalloutArgs* args, void* user_data)
+{
+ int r;
+ int num;
+ size_t tag_len;
+ const UChar* start;
+ const UChar* right;
+ const UChar* current;
+ const UChar* string;
+ const UChar* strend;
+ const UChar* tag_start;
+ const UChar* tag_end;
+ regex_t* reg;
+ OnigCalloutIn in;
+ OnigType type;
+ OnigValue val;
+ char buf[20];
+ FILE* fp;
+
+ fp = OutFp;
+
+ r = onig_get_arg_by_callout_args(args, 0, &type, &val);
+ if (r != ONIG_NORMAL) return r;
+
+ in = onig_get_callout_in_by_callout_args(args);
+ if (in == ONIG_CALLOUT_IN_PROGRESS) {
+ if (val.c == '<')
+ return ONIG_CALLOUT_SUCCESS;
+ }
+ else {
+ if (val.c != 'X' && val.c != '<')
+ return ONIG_CALLOUT_SUCCESS;
+ }
+
+ num = onig_get_callout_num_by_callout_args(args);
+ start = onig_get_start_by_callout_args(args);
+ right = onig_get_right_range_by_callout_args(args);
+ current = onig_get_current_by_callout_args(args);
+ string = onig_get_string_by_callout_args(args);
+ strend = onig_get_string_end_by_callout_args(args);
+ reg = onig_get_regex_by_callout_args(args);
+ tag_start = onig_get_callout_tag_start(reg, num);
+ tag_end = onig_get_callout_tag_end(reg, num);
+
+ if (tag_start == 0)
+ xsnprintf(buf, sizeof(buf), "#%d", num);
+ else {
+ /* CAUTION: tag string is not terminated with NULL. */
+ int i;
+
+ tag_len = tag_end - tag_start;
+ if (tag_len >= sizeof(buf)) tag_len = sizeof(buf) - 1;
+ for (i = 0; i < tag_len; i++) buf[i] = tag_start[i];
+ buf[tag_len] = '\0';
+ }
+
+ fprintf(fp, "ONIG-MONITOR: %-4s %s at: %d [%d - %d] len: %d\n",
+ buf,
+ in == ONIG_CALLOUT_IN_PROGRESS ? "=>" : "<=",
+ (int )(current - string),
+ (int )(start - string),
+ (int )(right - string),
+ (int )(strend - string));
+ fflush(fp);
+
+ return ONIG_CALLOUT_SUCCESS;
+}
+
+extern int
+onig_setup_builtin_monitors_by_ascii_encoded_name(void* fp /* FILE* */)
+{
+ int id;
+ char* name;
+ OnigEncoding enc;
+ unsigned int ts[4];
+ OnigValue opts[4];
+
+ if (IS_NOT_NULL(fp))
+ OutFp = (FILE* )fp;
+ else
+ OutFp = stdout;
+
+ enc = ONIG_ENCODING_ASCII;
+
+ name = "MON";
+ ts[0] = ONIG_TYPE_CHAR;
+ opts[0].c = '>';
+ BC_B_O(name, monitor, 1, ts, 1, opts);
+
+ return ONIG_NORMAL;
+}
+
+#endif /* ONIG_NO_PRINT */
+
+#endif /* USE_CALLOUT */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regext.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regext.c
new file mode 100644
index 000000000..c46f630c5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regext.c
@@ -0,0 +1,202 @@
+/**********************************************************************
+ regext.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+#if 0
+static void
+conv_ext0be32(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = '\0';
+ *conv++ = '\0';
+ *conv++ = '\0';
+ *conv++ = *s++;
+ }
+}
+
+static void
+conv_ext0le32(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = *s++;
+ *conv++ = '\0';
+ *conv++ = '\0';
+ *conv++ = '\0';
+ }
+}
+
+static void
+conv_ext0be(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = '\0';
+ *conv++ = *s++;
+ }
+}
+
+static void
+conv_ext0le(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = *s++;
+ *conv++ = '\0';
+ }
+}
+
+static void
+conv_swap4bytes(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = s[3];
+ *conv++ = s[2];
+ *conv++ = s[1];
+ *conv++ = s[0];
+ s += 4;
+ }
+}
+
+static void
+conv_swap2bytes(const UChar* s, const UChar* end, UChar* conv)
+{
+ while (s < end) {
+ *conv++ = s[1];
+ *conv++ = s[0];
+ s += 2;
+ }
+}
+
+static int
+conv_encoding(OnigEncoding from, OnigEncoding to, const UChar* s, const UChar* end,
+ UChar** conv, UChar** conv_end)
+{
+ int len = (int )(end - s);
+
+ if (to == ONIG_ENCODING_UTF16_BE) {
+ if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
+ *conv = (UChar* )xmalloc(len * 2);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + (len * 2);
+ conv_ext0be(s, end, *conv);
+ return 0;
+ }
+ else if (from == ONIG_ENCODING_UTF16_LE) {
+ swap16:
+ *conv = (UChar* )xmalloc(len);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + len;
+ conv_swap2bytes(s, end, *conv);
+ return 0;
+ }
+ }
+ else if (to == ONIG_ENCODING_UTF16_LE) {
+ if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
+ *conv = (UChar* )xmalloc(len * 2);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + (len * 2);
+ conv_ext0le(s, end, *conv);
+ return 0;
+ }
+ else if (from == ONIG_ENCODING_UTF16_BE) {
+ goto swap16;
+ }
+ }
+ if (to == ONIG_ENCODING_UTF32_BE) {
+ if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
+ *conv = (UChar* )xmalloc(len * 4);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + (len * 4);
+ conv_ext0be32(s, end, *conv);
+ return 0;
+ }
+ else if (from == ONIG_ENCODING_UTF32_LE) {
+ swap32:
+ *conv = (UChar* )xmalloc(len);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + len;
+ conv_swap4bytes(s, end, *conv);
+ return 0;
+ }
+ }
+ else if (to == ONIG_ENCODING_UTF32_LE) {
+ if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
+ *conv = (UChar* )xmalloc(len * 4);
+ CHECK_NULL_RETURN_MEMERR(*conv);
+ *conv_end = *conv + (len * 4);
+ conv_ext0le32(s, end, *conv);
+ return 0;
+ }
+ else if (from == ONIG_ENCODING_UTF32_BE) {
+ goto swap32;
+ }
+ }
+
+ return ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION;
+}
+#endif
+
+extern int
+onig_new_deluxe(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
+ OnigCompileInfo* ci, OnigErrorInfo* einfo)
+{
+ int r;
+ UChar *cpat, *cpat_end;
+
+ if (IS_NOT_NULL(einfo)) einfo->par = (UChar* )NULL;
+
+ if (ci->pattern_enc != ci->target_enc) {
+ return ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION;
+ }
+ else {
+ cpat = (UChar* )pattern;
+ cpat_end = (UChar* )pattern_end;
+ }
+
+ *reg = (regex_t* )xmalloc(sizeof(regex_t));
+ if (IS_NULL(*reg)) {
+ r = ONIGERR_MEMORY;
+ goto err2;
+ }
+
+ r = onig_reg_init(*reg, ci->option, ci->case_fold_flag, ci->target_enc,
+ ci->syntax);
+ if (r != 0) goto err;
+
+ r = onig_compile(*reg, cpat, cpat_end, einfo);
+ if (r != 0) {
+ err:
+ onig_free(*reg);
+ *reg = NULL;
+ }
+
+ err2:
+ if (cpat != pattern) xfree(cpat);
+
+ return r;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/reggnu.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/reggnu.c
new file mode 100644
index 000000000..8a450780d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/reggnu.c
@@ -0,0 +1,143 @@
+/**********************************************************************
+ reggnu.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+#include "oniggnu.h"
+
+extern void
+re_free_registers(OnigRegion* r)
+{
+ /* 0: don't free self */
+ onig_region_free(r, 0);
+}
+
+extern int
+re_adjust_startpos(regex_t* reg, const char* string, int size,
+ int startpos, int range)
+{
+ if (startpos > 0 && ONIGENC_MBC_MAXLEN(reg->enc) != 1 && startpos < size) {
+ UChar *p;
+ UChar *s = (UChar* )string + startpos;
+
+ if (range > 0) {
+ p = onigenc_get_right_adjust_char_head(reg->enc, (UChar* )string, s);
+ }
+ else {
+ p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, (UChar* )string, s);
+ }
+ return (int )(p - (UChar* )string);
+ }
+
+ return startpos;
+}
+
+extern int
+re_match(regex_t* reg, const char* str, int size, int pos,
+ struct re_registers* regs)
+{
+ return onig_match(reg, (UChar* )str, (UChar* )(str + size),
+ (UChar* )(str + pos), regs, ONIG_OPTION_NONE);
+}
+
+extern int
+re_search(regex_t* bufp, const char* string, int size, int startpos, int range,
+ struct re_registers* regs)
+{
+ return onig_search(bufp, (UChar* )string, (UChar* )(string + size),
+ (UChar* )(string + startpos),
+ (UChar* )(string + startpos + range),
+ regs, ONIG_OPTION_NONE);
+}
+
+extern int
+re_compile_pattern(const char* pattern, int size, regex_t* reg, char* ebuf)
+{
+ int r;
+ OnigErrorInfo einfo;
+
+ r = onig_compile(reg, (UChar* )pattern, (UChar* )(pattern + size), &einfo);
+ if (r != ONIG_NORMAL) {
+ if (IS_NOT_NULL(ebuf))
+ (void )onig_error_code_to_str((UChar* )ebuf, r, &einfo);
+ }
+
+ return r;
+}
+
+extern void
+re_free_pattern(regex_t* reg)
+{
+ onig_free(reg);
+}
+
+extern int
+re_alloc_pattern(regex_t** reg)
+{
+ *reg = (regex_t* )xmalloc(sizeof(regex_t));
+ if (IS_NULL(*reg)) return ONIGERR_MEMORY;
+
+ return onig_reg_init(*reg, ONIG_OPTION_DEFAULT,
+ ONIGENC_CASE_FOLD_DEFAULT,
+ OnigEncDefaultCharEncoding,
+ OnigDefaultSyntax);
+}
+
+extern void
+re_set_casetable(const char* table)
+{
+ onigenc_set_default_caseconv_table((UChar* )table);
+}
+
+extern void
+re_mbcinit(int mb_code)
+{
+ OnigEncoding enc;
+
+ switch (mb_code) {
+ case RE_MBCTYPE_ASCII:
+ enc = ONIG_ENCODING_ASCII;
+ break;
+ case RE_MBCTYPE_EUC:
+ enc = ONIG_ENCODING_EUC_JP;
+ break;
+ case RE_MBCTYPE_SJIS:
+ enc = ONIG_ENCODING_SJIS;
+ break;
+ case RE_MBCTYPE_UTF8:
+ enc = ONIG_ENCODING_UTF8;
+ break;
+ default:
+ return ;
+ break;
+ }
+
+ onig_initialize(&enc, 1);
+
+ onigenc_set_default_encoding(enc);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regint.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regint.h
new file mode 100644
index 000000000..9fd1689b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regint.h
@@ -0,0 +1,1084 @@
+#ifndef REGINT_H
+#define REGINT_H
+/**********************************************************************
+ regint.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+/* for debug */
+/* #define ONIG_DEBUG_PARSE */
+/* #define ONIG_DEBUG_COMPILE */
+/* #define ONIG_DEBUG_SEARCH */
+/* #define ONIG_DEBUG_MATCH */
+/* #define ONIG_DONT_OPTIMIZE */
+
+/* for byte-code statistical data. */
+/* #define ONIG_DEBUG_STATISTICS */
+
+#if defined(ONIG_DEBUG_PARSE) || defined(ONIG_DEBUG_MATCH) || \
+ defined(ONIG_DEBUG_SEARCH) || defined(ONIG_DEBUG_COMPILE) || \
+ defined(ONIG_DEBUG_STATISTICS)
+#ifndef ONIG_DEBUG
+#define ONIG_DEBUG
+#define DBGFP stderr
+#endif
+#endif
+
+#ifndef ONIG_DISABLE_DIRECT_THREADING
+#ifdef __GNUC__
+#define USE_GOTO_LABELS_AS_VALUES
+#endif
+#endif
+
+/* config */
+/* spec. config */
+#define USE_REGSET
+#define USE_CALL
+#define USE_CALLOUT
+#define USE_BACKREF_WITH_LEVEL /* \k<name+n>, \k<name-n> */
+#define USE_STUBBORN_CHECK_CAPTURES_IN_EMPTY_REPEAT /* /(?:()|())*\2/ */
+#define USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE /* /\n$/ =~ "\n" */
+#define USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR
+#define USE_RETRY_LIMIT
+#ifdef USE_GOTO_LABELS_AS_VALUES
+#define USE_THREADED_CODE
+#define USE_DIRECT_THREADED_CODE
+#endif
+
+/* internal config */
+#define USE_OP_PUSH_OR_JUMP_EXACT
+#define USE_QUANT_PEEK_NEXT
+#define USE_ST_LIBRARY
+#define USE_TIMEOFDAY
+
+#define USE_WORD_BEGIN_END /* "\<", "\>" */
+#define USE_CAPTURE_HISTORY
+#define USE_VARIABLE_META_CHARS
+#define USE_POSIX_API_REGION_OPTION
+#define USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
+/* #define USE_REPEAT_AND_EMPTY_CHECK_LOCAL_VAR */
+
+#define INIT_MATCH_STACK_SIZE 160
+#define DEFAULT_MATCH_STACK_LIMIT_SIZE 0 /* unlimited */
+#define DEFAULT_RETRY_LIMIT_IN_MATCH 10000000
+#define DEFAULT_RETRY_LIMIT_IN_SEARCH 0 /* unlimited */
+#define DEFAULT_PARSE_DEPTH_LIMIT 4096
+#define SUBEXP_CALL_MAX_NEST_LEVEL 16
+
+
+#include "regenc.h"
+
+#ifndef ONIG_NO_STANDARD_C_HEADERS
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#if defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
+#include <alloca.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#ifndef __BORLANDC__
+#include <sys/types.h>
+#endif
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#if defined(_WIN32) || defined(__BORLANDC__)
+#include <malloc.h>
+#endif
+
+#if defined(ONIG_DEBUG) || defined(NEED_TO_INCLUDE_STDIO)
+# include <stdio.h>
+#endif
+
+#ifdef ONIG_DEBUG_STATISTICS
+#ifdef USE_TIMEOFDAY
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#else /* USE_TIMEOFDAY */
+
+#ifdef HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+
+#endif /* USE_TIMEOFDAY */
+#endif /* ONIG_DEBUG_STATISTICS */
+
+/* I don't think these x....'s need to be included in
+ ONIG_NO_STANDARD_C_HEADERS, but they are required by Issue #170
+ and do so since there is no problem.
+ */
+#ifndef xmemset
+#define xmemset memset
+#endif
+
+#ifndef xmemcpy
+#define xmemcpy memcpy
+#endif
+
+#ifndef xmemmove
+#define xmemmove memmove
+#endif
+
+#endif /* ONIG_NO_STANDARD_C_HEADERS */
+
+
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)<(b))?(b):(a))
+
+#define IS_NULL(p) (((void*)(p)) == (void*)0)
+#define IS_NOT_NULL(p) (((void*)(p)) != (void*)0)
+#define CHECK_NULL_RETURN(p) if (IS_NULL(p)) return NULL
+#define CHECK_NULL_RETURN_MEMERR(p) if (IS_NULL(p)) return ONIGERR_MEMORY
+#define NULL_UCHARP ((UChar* )0)
+
+#ifndef ONIG_INT_MAX
+#define ONIG_INT_MAX INT_MAX
+#endif
+
+#define CHAR_MAP_SIZE 256
+#define INFINITE_LEN ONIG_INFINITE_DISTANCE
+#define STEP_BACK_MAX_CHAR_LEN 65535 /* INT_MAX is too big */
+#define LOOK_BEHIND_MAX_CHAR_LEN STEP_BACK_MAX_CHAR_LEN
+
+/* escape other system UChar definition */
+#ifdef ONIG_ESCAPE_UCHAR_COLLISION
+#undef ONIG_ESCAPE_UCHAR_COLLISION
+#endif
+
+#define xmalloc malloc
+#define xrealloc realloc
+#define xcalloc calloc
+#define xfree free
+
+#define st_init_table onig_st_init_table
+#define st_init_table_with_size onig_st_init_table_with_size
+#define st_init_numtable onig_st_init_numtable
+#define st_init_numtable_with_size onig_st_init_numtable_with_size
+#define st_init_strtable onig_st_init_strtable
+#define st_init_strtable_with_size onig_st_init_strtable_with_size
+#define st_delete onig_st_delete
+#define st_delete_safe onig_st_delete_safe
+#define st_insert onig_st_insert
+#define st_lookup onig_st_lookup
+#define st_foreach onig_st_foreach
+#define st_add_direct onig_st_add_direct
+#define st_free_table onig_st_free_table
+#define st_cleanup_safe onig_st_cleanup_safe
+#define st_copy onig_st_copy
+#define st_nothing_key_clone onig_st_nothing_key_clone
+#define st_nothing_key_free onig_st_nothing_key_free
+/* */
+#define onig_st_is_member st_is_member
+
+
+#if defined(_WIN32) && !defined(__GNUC__)
+
+#ifndef xalloca
+#define xalloca _alloca
+#endif
+#ifndef xvsnprintf
+#define xvsnprintf(buf,size,fmt,args) _vsnprintf_s(buf,size,_TRUNCATE,fmt,args)
+#endif
+#ifndef xsnprintf
+#define xsnprintf sprintf_s
+#endif
+#ifndef xstrcat
+#define xstrcat(dest,src,size) strcat_s(dest,size,src)
+#endif
+
+#else
+
+#ifndef xalloca
+#define xalloca alloca
+#endif
+#ifndef xvsnprintf
+#define xvsnprintf vsnprintf
+#endif
+#ifndef xsnprintf
+#define xsnprintf snprintf
+#endif
+#ifndef xstrcat
+#define xstrcat(dest,src,size) strcat(dest,src)
+#endif
+
+#endif /* defined(_WIN32) && !defined(__GNUC__) */
+
+
+#ifdef _WIN32
+#if defined(_MSC_VER) && (_MSC_VER < 1300)
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+#endif
+#endif
+
+#if SIZEOF_VOIDP == SIZEOF_LONG
+typedef unsigned long hash_data_type;
+#elif SIZEOF_VOIDP == SIZEOF_LONG_LONG
+typedef unsigned long long hash_data_type;
+#endif
+
+/* strend hash */
+typedef void* hash_table_type;
+
+
+#ifdef USE_CALLOUT
+
+typedef struct {
+ int flag;
+ OnigCalloutOf of;
+ int in;
+ int name_id;
+ const UChar* tag_start;
+ const UChar* tag_end;
+ OnigCalloutType type;
+ OnigCalloutFunc start_func;
+ OnigCalloutFunc end_func;
+ union {
+ struct {
+ const UChar* start;
+ const UChar* end;
+ } content;
+ struct {
+ int num;
+ int passed_num;
+ OnigType types[ONIG_CALLOUT_MAX_ARGS_NUM];
+ OnigValue vals[ONIG_CALLOUT_MAX_ARGS_NUM];
+ } arg;
+ } u;
+} CalloutListEntry;
+
+#endif
+
+/* stack pop level */
+enum StackPopLevel {
+ STACK_POP_LEVEL_FREE = 0,
+ STACK_POP_LEVEL_MEM_START = 1,
+ STACK_POP_LEVEL_ALL = 2
+};
+
+/* optimize flags */
+enum OptimizeType {
+ OPTIMIZE_NONE = 0,
+ OPTIMIZE_STR, /* Slow Search */
+ OPTIMIZE_STR_FAST, /* Sunday quick search / BMH */
+ OPTIMIZE_STR_FAST_STEP_FORWARD, /* Sunday quick search / BMH */
+ OPTIMIZE_MAP /* char map */
+};
+
+/* bit status */
+typedef unsigned int MemStatusType;
+
+#define MEM_STATUS_BITS_NUM (sizeof(MemStatusType) * 8)
+#define MEM_STATUS_CLEAR(stats) (stats) = 0
+#define MEM_STATUS_ON_ALL(stats) (stats) = ~((MemStatusType )0)
+#define MEM_STATUS_AT(stats,n) \
+ ((n) < (int )MEM_STATUS_BITS_NUM ? ((stats) & ((MemStatusType )1 << n)) : ((stats) & 1))
+#define MEM_STATUS_AT0(stats,n) \
+ ((n) > 0 && (n) < (int )MEM_STATUS_BITS_NUM ? ((stats) & ((MemStatusType )1 << n)) : ((stats) & 1))
+
+#define MEM_STATUS_IS_ALL_ON(stats) (((stats) & 1) != 0)
+
+#define MEM_STATUS_ON(stats,n) do {\
+ if ((n) < (int )MEM_STATUS_BITS_NUM) {\
+ if ((n) != 0)\
+ (stats) |= ((MemStatusType )1 << (n));\
+ }\
+ else\
+ (stats) |= 1;\
+} while (0)
+
+#define MEM_STATUS_ON_SIMPLE(stats,n) do {\
+ if ((n) < (int )MEM_STATUS_BITS_NUM)\
+ (stats) |= ((MemStatusType )1 << (n));\
+} while (0)
+
+#define MEM_STATUS_LIMIT_AT(stats,n) \
+ ((n) < (int )MEM_STATUS_BITS_NUM ? ((stats) & ((MemStatusType )1 << n)) : 0)
+#define MEM_STATUS_LIMIT_ON(stats,n) do {\
+ if ((n) < (int )MEM_STATUS_BITS_NUM && (n) != 0) {\
+ (stats) |= ((MemStatusType )1 << (n));\
+ }\
+} while (0)
+
+
+#define IS_CODE_WORD_ASCII(enc,code) \
+ (ONIGENC_IS_CODE_ASCII(code) && ONIGENC_IS_CODE_WORD(enc,code))
+#define IS_CODE_DIGIT_ASCII(enc, code) \
+ (ONIGENC_IS_CODE_ASCII(code) && ONIGENC_IS_CODE_DIGIT(enc,code))
+#define IS_CODE_XDIGIT_ASCII(enc, code) \
+ (ONIGENC_IS_CODE_ASCII(code) && ONIGENC_IS_CODE_XDIGIT(enc,code))
+
+#define DIGITVAL(code) ((code) - '0')
+#define ODIGITVAL(code) DIGITVAL(code)
+#define XDIGITVAL(enc,code) \
+ (IS_CODE_DIGIT_ASCII(enc,code) ? DIGITVAL(code) \
+ : (ONIGENC_IS_CODE_UPPER(enc,code) ? (code) - 'A' + 10 : (code) - 'a' + 10))
+
+#define OPTON_FIND_LONGEST(option) ((option) & ONIG_OPTION_FIND_LONGEST)
+#define OPTON_FIND_NOT_EMPTY(option) ((option) & ONIG_OPTION_FIND_NOT_EMPTY)
+#define OPTON_FIND_CONDITION(option) ((option) & \
+ (ONIG_OPTION_FIND_LONGEST | ONIG_OPTION_FIND_NOT_EMPTY))
+#define OPTON_NEGATE_SINGLELINE(option) ((option) & \
+ ONIG_OPTION_NEGATE_SINGLELINE)
+#define OPTON_DONT_CAPTURE_GROUP(option) ((option) & \
+ ONIG_OPTION_DONT_CAPTURE_GROUP)
+#define OPTON_CAPTURE_GROUP(option) ((option) & ONIG_OPTION_CAPTURE_GROUP)
+#define OPTON_NOTBOL(option) ((option) & ONIG_OPTION_NOTBOL)
+#define OPTON_NOTEOL(option) ((option) & ONIG_OPTION_NOTEOL)
+#define OPTON_POSIX_REGION(option) ((option) & ONIG_OPTION_POSIX_REGION)
+#define OPTON_CHECK_VALIDITY_OF_STRING(option) ((option) & \
+ ONIG_OPTION_CHECK_VALIDITY_OF_STRING)
+
+#define DISABLE_CASE_FOLD_MULTI_CHAR(case_fold_flag) \
+ ((case_fold_flag) & ~INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR)
+
+#define INFINITE_REPEAT -1
+#define IS_INFINITE_REPEAT(n) ((n) == INFINITE_REPEAT)
+
+/* bitset */
+#define BITS_PER_BYTE 8
+#define SINGLE_BYTE_SIZE (1 << BITS_PER_BYTE)
+#define BITS_IN_ROOM 32 /* 4 * BITS_PER_BYTE */
+#define BITSET_REAL_SIZE (SINGLE_BYTE_SIZE / BITS_IN_ROOM)
+
+typedef uint32_t Bits;
+typedef Bits BitSet[BITSET_REAL_SIZE];
+typedef Bits* BitSetRef;
+
+#define SIZE_BITSET sizeof(BitSet)
+
+#define BITSET_CLEAR(bs) do {\
+ int i;\
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { (bs)[i] = 0; } \
+} while (0)
+
+#define BS_ROOM(bs,pos) (bs)[(unsigned int )(pos) >> 5]
+#define BS_BIT(pos) (1u << ((unsigned int )(pos) & 0x1f))
+
+#define BITSET_AT(bs, pos) (BS_ROOM(bs,pos) & BS_BIT(pos))
+#define BITSET_SET_BIT(bs, pos) BS_ROOM(bs,pos) |= BS_BIT(pos)
+#define BITSET_CLEAR_BIT(bs, pos) BS_ROOM(bs,pos) &= ~(BS_BIT(pos))
+#define BITSET_INVERT_BIT(bs, pos) BS_ROOM(bs,pos) ^= BS_BIT(pos)
+
+/* bytes buffer */
+typedef struct _BBuf {
+ UChar* p;
+ unsigned int used;
+ unsigned int alloc;
+} BBuf;
+
+#define BB_INIT(buf,size) bbuf_init((BBuf* )(buf), (size))
+
+#define BB_EXPAND(buf,low) do{\
+ do { (buf)->alloc *= 2; } while ((buf)->alloc < (unsigned int )low);\
+ (buf)->p = (UChar* )xrealloc((buf)->p, (buf)->alloc);\
+ if (IS_NULL((buf)->p)) return(ONIGERR_MEMORY);\
+} while (0)
+
+#define BB_ENSURE_SIZE(buf,size) do{\
+ unsigned int new_alloc = (buf)->alloc;\
+ while (new_alloc < (unsigned int )(size)) { new_alloc *= 2; }\
+ if ((buf)->alloc != new_alloc) {\
+ (buf)->p = (UChar* )xrealloc((buf)->p, new_alloc);\
+ if (IS_NULL((buf)->p)) return(ONIGERR_MEMORY);\
+ (buf)->alloc = new_alloc;\
+ }\
+} while (0)
+
+#define BB_WRITE(buf,pos,bytes,n) do{\
+ int used = (pos) + (n);\
+ if ((buf)->alloc < (unsigned int )used) BB_EXPAND((buf),used);\
+ xmemcpy((buf)->p + (pos), (bytes), (n));\
+ if ((buf)->used < (unsigned int )used) (buf)->used = used;\
+} while (0)
+
+#define BB_WRITE1(buf,pos,byte) do{\
+ int used = (pos) + 1;\
+ if ((buf)->alloc < (unsigned int )used) BB_EXPAND((buf),used);\
+ (buf)->p[(pos)] = (byte);\
+ if ((buf)->used < (unsigned int )used) (buf)->used = used;\
+} while (0)
+
+#define BB_ADD(buf,bytes,n) BB_WRITE((buf),(buf)->used,(bytes),(n))
+#define BB_ADD1(buf,byte) BB_WRITE1((buf),(buf)->used,(byte))
+#define BB_GET_ADD_ADDRESS(buf) ((buf)->p + (buf)->used)
+#define BB_GET_OFFSET_POS(buf) ((buf)->used)
+
+/* from < to */
+#define BB_MOVE_RIGHT(buf,from,to,n) do {\
+ if ((unsigned int )((to)+(n)) > (buf)->alloc) BB_EXPAND((buf),(to) + (n));\
+ xmemmove((buf)->p + (to), (buf)->p + (from), (n));\
+ if ((unsigned int )((to)+(n)) > (buf)->used) (buf)->used = (to) + (n);\
+} while (0)
+
+/* from > to */
+#define BB_MOVE_LEFT(buf,from,to,n) do {\
+ xmemmove((buf)->p + (to), (buf)->p + (from), (n));\
+} while (0)
+
+/* from > to */
+#define BB_MOVE_LEFT_REDUCE(buf,from,to) do {\
+ xmemmove((buf)->p + (to), (buf)->p + (from), (buf)->used - (from));\
+ (buf)->used -= (from - to);\
+} while (0)
+
+#define BB_INSERT(buf,pos,bytes,n) do {\
+ if (pos >= (buf)->used) {\
+ BB_WRITE(buf,pos,bytes,n);\
+ }\
+ else {\
+ BB_MOVE_RIGHT((buf),(pos),(pos) + (n),((buf)->used - (pos)));\
+ xmemcpy((buf)->p + (pos), (bytes), (n));\
+ }\
+} while (0)
+
+#define BB_GET_BYTE(buf, pos) (buf)->p[(pos)]
+
+
+/* has body */
+#define ANCR_PREC_READ (1<<0)
+#define ANCR_PREC_READ_NOT (1<<1)
+#define ANCR_LOOK_BEHIND (1<<2)
+#define ANCR_LOOK_BEHIND_NOT (1<<3)
+/* no body */
+#define ANCR_BEGIN_BUF (1<<4)
+#define ANCR_BEGIN_LINE (1<<5)
+#define ANCR_BEGIN_POSITION (1<<6)
+#define ANCR_END_BUF (1<<7)
+#define ANCR_SEMI_END_BUF (1<<8)
+#define ANCR_END_LINE (1<<9)
+#define ANCR_WORD_BOUNDARY (1<<10)
+#define ANCR_NO_WORD_BOUNDARY (1<<11)
+#define ANCR_WORD_BEGIN (1<<12)
+#define ANCR_WORD_END (1<<13)
+#define ANCR_ANYCHAR_INF (1<<14)
+#define ANCR_ANYCHAR_INF_ML (1<<15)
+#define ANCR_TEXT_SEGMENT_BOUNDARY (1<<16)
+#define ANCR_NO_TEXT_SEGMENT_BOUNDARY (1<<17)
+
+
+#define ANCHOR_HAS_BODY(a) ((a)->type < ANCR_BEGIN_BUF)
+
+#define IS_WORD_ANCHOR_TYPE(type) \
+ ((type) == ANCR_WORD_BOUNDARY || (type) == ANCR_NO_WORD_BOUNDARY || \
+ (type) == ANCR_WORD_BEGIN || (type) == ANCR_WORD_END)
+
+/* operation code */
+enum OpCode {
+ OP_FINISH = 0, /* matching process terminator (no more alternative) */
+ OP_END = 1, /* pattern code terminator (success end) */
+ OP_STR_1 = 2, /* single byte, N = 1 */
+ OP_STR_2, /* single byte, N = 2 */
+ OP_STR_3, /* single byte, N = 3 */
+ OP_STR_4, /* single byte, N = 4 */
+ OP_STR_5, /* single byte, N = 5 */
+ OP_STR_N, /* single byte */
+ OP_STR_MB2N1, /* mb-length = 2 N = 1 */
+ OP_STR_MB2N2, /* mb-length = 2 N = 2 */
+ OP_STR_MB2N3, /* mb-length = 2 N = 3 */
+ OP_STR_MB2N, /* mb-length = 2 */
+ OP_STR_MB3N, /* mb-length = 3 */
+ OP_STR_MBN, /* other length */
+ OP_CCLASS,
+ OP_CCLASS_MB,
+ OP_CCLASS_MIX,
+ OP_CCLASS_NOT,
+ OP_CCLASS_MB_NOT,
+ OP_CCLASS_MIX_NOT,
+ OP_ANYCHAR, /* "." */
+ OP_ANYCHAR_ML, /* "." multi-line */
+ OP_ANYCHAR_STAR, /* ".*" */
+ OP_ANYCHAR_ML_STAR, /* ".*" multi-line */
+ OP_ANYCHAR_STAR_PEEK_NEXT,
+ OP_ANYCHAR_ML_STAR_PEEK_NEXT,
+ OP_WORD,
+ OP_WORD_ASCII,
+ OP_NO_WORD,
+ OP_NO_WORD_ASCII,
+ OP_WORD_BOUNDARY,
+ OP_NO_WORD_BOUNDARY,
+ OP_WORD_BEGIN,
+ OP_WORD_END,
+ OP_TEXT_SEGMENT_BOUNDARY,
+ OP_BEGIN_BUF,
+ OP_END_BUF,
+ OP_BEGIN_LINE,
+ OP_END_LINE,
+ OP_SEMI_END_BUF,
+ OP_CHECK_POSITION,
+ OP_BACKREF1,
+ OP_BACKREF2,
+ OP_BACKREF_N,
+ OP_BACKREF_N_IC,
+ OP_BACKREF_MULTI,
+ OP_BACKREF_MULTI_IC,
+ OP_BACKREF_WITH_LEVEL, /* \k<xxx+n>, \k<xxx-n> */
+ OP_BACKREF_WITH_LEVEL_IC, /* \k<xxx+n>, \k<xxx-n> */
+ OP_BACKREF_CHECK, /* (?(n)), (?('name')) */
+ OP_BACKREF_CHECK_WITH_LEVEL, /* (?(n-level)), (?('name-level')) */
+ OP_MEM_START,
+ OP_MEM_START_PUSH, /* push back-tracker to stack */
+ OP_MEM_END_PUSH, /* push back-tracker to stack */
+#ifdef USE_CALL
+ OP_MEM_END_PUSH_REC, /* push back-tracker to stack */
+#endif
+ OP_MEM_END,
+#ifdef USE_CALL
+ OP_MEM_END_REC, /* push marker to stack */
+#endif
+ OP_FAIL, /* pop stack and move */
+ OP_JUMP,
+ OP_PUSH,
+ OP_PUSH_SUPER,
+ OP_POP,
+ OP_POP_TO_MARK,
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+ OP_PUSH_OR_JUMP_EXACT1, /* if match exact then push, else jump. */
+#endif
+ OP_PUSH_IF_PEEK_NEXT, /* if match exact then push, else none. */
+ OP_REPEAT, /* {n,m} */
+ OP_REPEAT_NG, /* {n,m}? (non greedy) */
+ OP_REPEAT_INC,
+ OP_REPEAT_INC_NG, /* non greedy */
+ OP_EMPTY_CHECK_START, /* null loop checker start */
+ OP_EMPTY_CHECK_END, /* null loop checker end */
+ OP_EMPTY_CHECK_END_MEMST, /* null loop checker end (with capture status) */
+#ifdef USE_CALL
+ OP_EMPTY_CHECK_END_MEMST_PUSH, /* with capture status and push check-end */
+#endif
+ OP_MOVE,
+ OP_STEP_BACK_START,
+ OP_STEP_BACK_NEXT,
+ OP_CUT_TO_MARK,
+ OP_MARK,
+ OP_SAVE_VAL,
+ OP_UPDATE_VAR,
+#ifdef USE_CALL
+ OP_CALL, /* \g<name> */
+ OP_RETURN,
+#endif
+#ifdef USE_CALLOUT
+ OP_CALLOUT_CONTENTS, /* (?{...}) (?{{...}}) */
+ OP_CALLOUT_NAME, /* (*name) (*name[tag](args...)) */
+#endif
+};
+
+enum SaveType {
+ SAVE_KEEP = 0, /* SAVE S */
+ SAVE_S = 1,
+ SAVE_RIGHT_RANGE = 2,
+};
+
+enum UpdateVarType {
+ UPDATE_VAR_KEEP_FROM_STACK_LAST = 0,
+ UPDATE_VAR_S_FROM_STACK = 1,
+ UPDATE_VAR_RIGHT_RANGE_FROM_STACK = 2,
+ UPDATE_VAR_RIGHT_RANGE_FROM_S_STACK = 3,
+ UPDATE_VAR_RIGHT_RANGE_TO_S = 4,
+ UPDATE_VAR_RIGHT_RANGE_INIT = 5,
+};
+
+enum CheckPositionType {
+ CHECK_POSITION_SEARCH_START = 0,
+ CHECK_POSITION_CURRENT_RIGHT_RANGE = 1,
+};
+
+enum TextSegmentBoundaryType {
+ EXTENDED_GRAPHEME_CLUSTER_BOUNDARY = 0,
+ WORD_BOUNDARY = 1,
+};
+
+typedef int RelAddrType;
+typedef int AbsAddrType;
+typedef int LengthType;
+typedef int RelPositionType;
+typedef int RepeatNumType;
+typedef int MemNumType;
+typedef void* PointerType;
+typedef int SaveType;
+typedef int UpdateVarType;
+typedef int ModeType;
+
+#define SIZE_OPCODE 1
+#define SIZE_RELADDR sizeof(RelAddrType)
+#define SIZE_ABSADDR sizeof(AbsAddrType)
+#define SIZE_LENGTH sizeof(LengthType)
+#define SIZE_MEMNUM sizeof(MemNumType)
+#define SIZE_REPEATNUM sizeof(RepeatNumType)
+#define SIZE_OPTION sizeof(OnigOptionType)
+#define SIZE_CODE_POINT sizeof(OnigCodePoint)
+#define SIZE_POINTER sizeof(PointerType)
+#define SIZE_SAVE_TYPE sizeof(SaveType)
+#define SIZE_UPDATE_VAR_TYPE sizeof(UpdateVarType)
+#define SIZE_MODE sizeof(ModeType)
+
+/* code point's address must be aligned address. */
+#define GET_CODE_POINT(code,p) code = *((OnigCodePoint* )(p))
+
+
+/* op-code + arg size */
+
+/* for relative address increment to go next op. */
+#define SIZE_INC 1
+
+#define OPSIZE_ANYCHAR_STAR 1
+#define OPSIZE_ANYCHAR_STAR_PEEK_NEXT 1
+#define OPSIZE_JUMP 1
+#define OPSIZE_PUSH 1
+#define OPSIZE_PUSH_SUPER 1
+#define OPSIZE_POP 1
+#define OPSIZE_POP_TO_MARK 1
+#ifdef USE_OP_PUSH_OR_JUMP_EXACT
+#define OPSIZE_PUSH_OR_JUMP_EXACT1 1
+#endif
+#define OPSIZE_PUSH_IF_PEEK_NEXT 1
+#define OPSIZE_REPEAT 1
+#define OPSIZE_REPEAT_INC 1
+#define OPSIZE_REPEAT_INC_NG 1
+#define OPSIZE_WORD_BOUNDARY 1
+#define OPSIZE_BACKREF 1
+#define OPSIZE_FAIL 1
+#define OPSIZE_MEM_START 1
+#define OPSIZE_MEM_START_PUSH 1
+#define OPSIZE_MEM_END_PUSH 1
+#define OPSIZE_MEM_END_PUSH_REC 1
+#define OPSIZE_MEM_END 1
+#define OPSIZE_MEM_END_REC 1
+#define OPSIZE_EMPTY_CHECK_START 1
+#define OPSIZE_EMPTY_CHECK_END 1
+#define OPSIZE_CHECK_POSITION 1
+#define OPSIZE_CALL 1
+#define OPSIZE_RETURN 1
+#define OPSIZE_MOVE 1
+#define OPSIZE_STEP_BACK_START 1
+#define OPSIZE_STEP_BACK_NEXT 1
+#define OPSIZE_CUT_TO_MARK 1
+#define OPSIZE_MARK 1
+#define OPSIZE_SAVE_VAL 1
+#define OPSIZE_UPDATE_VAR 1
+
+#ifdef USE_CALLOUT
+#define OPSIZE_CALLOUT_CONTENTS 1
+#define OPSIZE_CALLOUT_NAME 1
+#endif
+
+
+#define MC_ESC(syn) (syn)->meta_char_table.esc
+#define MC_ANYCHAR(syn) (syn)->meta_char_table.anychar
+#define MC_ANYTIME(syn) (syn)->meta_char_table.anytime
+#define MC_ZERO_OR_ONE_TIME(syn) (syn)->meta_char_table.zero_or_one_time
+#define MC_ONE_OR_MORE_TIME(syn) (syn)->meta_char_table.one_or_more_time
+#define MC_ANYCHAR_ANYTIME(syn) (syn)->meta_char_table.anychar_anytime
+
+#define IS_MC_ESC_CODE(code, syn) \
+ ((code) == MC_ESC(syn) && \
+ !IS_SYNTAX_OP2((syn), ONIG_SYN_OP2_INEFFECTIVE_ESCAPE))
+
+
+#define SYN_POSIX_COMMON_OP \
+ ( ONIG_SYN_OP_DOT_ANYCHAR | ONIG_SYN_OP_POSIX_BRACKET | \
+ ONIG_SYN_OP_DECIMAL_BACKREF | \
+ ONIG_SYN_OP_BRACKET_CC | ONIG_SYN_OP_ASTERISK_ZERO_INF | \
+ ONIG_SYN_OP_LINE_ANCHOR | \
+ ONIG_SYN_OP_ESC_CONTROL_CHARS )
+
+#define SYN_GNU_REGEX_OP \
+ ( ONIG_SYN_OP_DOT_ANYCHAR | ONIG_SYN_OP_BRACKET_CC | \
+ ONIG_SYN_OP_POSIX_BRACKET | ONIG_SYN_OP_DECIMAL_BACKREF | \
+ ONIG_SYN_OP_BRACE_INTERVAL | ONIG_SYN_OP_LPAREN_SUBEXP | \
+ ONIG_SYN_OP_VBAR_ALT | \
+ ONIG_SYN_OP_ASTERISK_ZERO_INF | ONIG_SYN_OP_PLUS_ONE_INF | \
+ ONIG_SYN_OP_QMARK_ZERO_ONE | \
+ ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR | ONIG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR | \
+ ONIG_SYN_OP_ESC_W_WORD | \
+ ONIG_SYN_OP_ESC_B_WORD_BOUND | ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END | \
+ ONIG_SYN_OP_ESC_S_WHITE_SPACE | ONIG_SYN_OP_ESC_D_DIGIT | \
+ ONIG_SYN_OP_LINE_ANCHOR )
+
+#define SYN_GNU_REGEX_BV \
+ ( ONIG_SYN_CONTEXT_INDEP_ANCHORS | ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS | \
+ ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS | ONIG_SYN_ALLOW_INVALID_INTERVAL | \
+ ONIG_SYN_BACKSLASH_ESCAPE_IN_CC | ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC )
+
+
+#define NCCLASS_FLAGS(cc) ((cc)->flags)
+#define NCCLASS_FLAG_SET(cc,flag) (NCCLASS_FLAGS(cc) |= (flag))
+#define NCCLASS_FLAG_CLEAR(cc,flag) (NCCLASS_FLAGS(cc) &= ~(flag))
+#define IS_NCCLASS_FLAG_ON(cc,flag) ((NCCLASS_FLAGS(cc) & (flag)) != 0)
+
+/* cclass node */
+#define FLAG_NCCLASS_NOT (1<<0)
+#define FLAG_NCCLASS_SHARE (1<<1)
+
+#define NCCLASS_SET_NOT(nd) NCCLASS_FLAG_SET(nd, FLAG_NCCLASS_NOT)
+#define NCCLASS_CLEAR_NOT(nd) NCCLASS_FLAG_CLEAR(nd, FLAG_NCCLASS_NOT)
+#define IS_NCCLASS_NOT(nd) IS_NCCLASS_FLAG_ON(nd, FLAG_NCCLASS_NOT)
+
+
+typedef struct {
+#ifdef USE_DIRECT_THREADED_CODE
+ const void* opaddr;
+#else
+ enum OpCode opcode;
+#endif
+ union {
+ struct {
+ UChar s[16]; /* Now used first 7 bytes only. */
+ } exact;
+ struct {
+ UChar* s;
+ LengthType n; /* number of chars */
+ } exact_n; /* EXACTN, EXACTN_IC, EXACTMB2N, EXACTMB3N */
+ struct {
+ UChar* s;
+ LengthType n; /* number of chars */
+ LengthType len; /* char byte length */
+ } exact_len_n; /* EXACTMBN */
+ struct {
+ BitSetRef bsp;
+ } cclass;
+ struct {
+ void* mb;
+ } cclass_mb;
+ struct {
+ void* mb; /* mb must be same position with cclass_mb for match_at(). */
+ BitSetRef bsp;
+ } cclass_mix;
+ struct {
+ UChar c;
+ } anychar_star_peek_next;
+ struct {
+ ModeType mode;
+ } word_boundary; /* OP_WORD_BOUNDARY, OP_NO_WORD_BOUNDARY, OP_WORD_BEGIN, OP_WORD_END */
+ struct {
+ enum TextSegmentBoundaryType type;
+ int not;
+ } text_segment_boundary;
+ struct {
+ enum CheckPositionType type;
+ } check_position;
+ struct {
+ union {
+ MemNumType n1; /* num == 1 */
+ MemNumType* ns; /* num > 1 */
+ };
+ int num;
+ int nest_level;
+ } backref_general; /* BACKREF_MULTI, BACKREF_MULTI_IC, BACKREF_WITH_LEVEL, BACKREF_CHECK, BACKREF_CHECK_WITH_LEVEL, */
+ struct {
+ MemNumType n1;
+ } backref_n; /* BACKREF_N, BACKREF_N_IC */
+ struct {
+ MemNumType num;
+ } memory_start; /* MEMORY_START, MEMORY_START_PUSH */
+ struct {
+ MemNumType num;
+ } memory_end; /* MEMORY_END, MEMORY_END_REC, MEMORY_END_PUSH, MEMORY_END_PUSH_REC */
+ struct {
+ RelAddrType addr;
+ } jump;
+ struct {
+ RelAddrType addr;
+ } push;
+ struct {
+ RelAddrType addr;
+ UChar c;
+ } push_or_jump_exact1;
+ struct {
+ RelAddrType addr;
+ UChar c;
+ } push_if_peek_next;
+ struct {
+ MemNumType id;
+ } pop_to_mark;
+ struct {
+ MemNumType id;
+ RelAddrType addr;
+ } repeat; /* REPEAT, REPEAT_NG */
+ struct {
+ MemNumType id;
+ } repeat_inc; /* REPEAT_INC, REPEAT_INC_NG */
+ struct {
+ MemNumType mem;
+ } empty_check_start;
+ struct {
+ MemNumType mem;
+ } empty_check_end; /* EMPTY_CHECK_END, EMPTY_CHECK_END_MEMST, EMPTY_CHECK_END_MEMST_PUSH */
+ struct {
+ RelAddrType addr;
+ } prec_read_not_start;
+ struct {
+ LengthType len;
+ } look_behind;
+ struct {
+ LengthType len;
+ RelAddrType addr;
+ } look_behind_not_start;
+ struct {
+ RelPositionType n; /* char relative position */
+ } move;
+ struct {
+ LengthType initial; /* char length */
+ LengthType remaining; /* char length */
+ RelAddrType addr;
+ } step_back_start;
+ struct {
+ MemNumType id;
+ int restore_pos; /* flag: restore current string position */
+ } cut_to_mark;
+ struct {
+ MemNumType id;
+ int save_pos; /* flag: save current string position */
+ } mark;
+ struct {
+ SaveType type;
+ MemNumType id;
+ } save_val;
+ struct {
+ UpdateVarType type;
+ MemNumType id;
+ int clear; /* UPDATE_VAR_RIGHT_RANGE_FROM_S_STACK or UPDATE_VAR_RIGHT_RANGE_FROM_STACK */
+ } update_var;
+ struct {
+ AbsAddrType addr;
+ } call;
+#ifdef USE_CALLOUT
+ struct {
+ MemNumType num;
+ } callout_contents;
+ struct {
+ MemNumType num;
+ MemNumType id;
+ } callout_name;
+#endif
+ };
+} Operation;
+
+typedef struct {
+ const UChar* pattern;
+ const UChar* pattern_end;
+#ifdef USE_CALLOUT
+ void* tag_table;
+ int callout_num;
+ int callout_list_alloc;
+ CalloutListEntry* callout_list; /* index: callout num */
+#endif
+} RegexExt;
+
+typedef struct {
+ int lower;
+ int upper;
+ union {
+ Operation* pcode; /* address of repeated body */
+ int offset;
+ } u;
+} RepeatRange;
+
+struct re_pattern_buffer {
+ /* common members of BBuf(bytes-buffer) */
+ Operation* ops;
+#ifdef USE_DIRECT_THREADED_CODE
+ enum OpCode* ocs;
+#endif
+ Operation* ops_curr;
+ unsigned int ops_used; /* used space for ops */
+ unsigned int ops_alloc; /* allocated space for ops */
+ unsigned char* string_pool;
+ unsigned char* string_pool_end;
+
+ int num_mem; /* used memory(...) num counted from 1 */
+ int num_repeat; /* OP_REPEAT/OP_REPEAT_NG id-counter */
+ int num_empty_check; /* OP_EMPTY_CHECK_START/END id counter */
+ int num_call; /* number of subexp call */
+ MemStatusType capture_history; /* (?@...) flag (1-31) */
+ MemStatusType push_mem_start; /* need backtrack flag */
+ MemStatusType push_mem_end; /* need backtrack flag */
+ MemStatusType empty_status_mem;
+ int stack_pop_level;
+ int repeat_range_alloc;
+ RepeatRange* repeat_range;
+
+ OnigEncoding enc;
+ OnigOptionType options;
+ OnigSyntaxType* syntax;
+ OnigCaseFoldType case_fold_flag;
+ void* name_table;
+
+ /* optimization info (string search, char-map and anchors) */
+ int optimize; /* optimize flag */
+ int threshold_len; /* search str-length for apply optimize */
+ int anchor; /* BEGIN_BUF, BEGIN_POS, (SEMI_)END_BUF */
+ OnigLen anc_dist_min; /* (SEMI_)END_BUF anchor distance */
+ OnigLen anc_dist_max; /* (SEMI_)END_BUF anchor distance */
+ int sub_anchor; /* start-anchor for exact or map */
+ unsigned char *exact;
+ unsigned char *exact_end;
+ unsigned char map[CHAR_MAP_SIZE]; /* used as BMH skip or char-map */
+ int map_offset;
+ OnigLen dist_min; /* min-distance of exact or map */
+ OnigLen dist_max; /* max-distance of exact or map */
+ RegexExt* extp;
+};
+
+#define COP(reg) ((reg)->ops_curr)
+#define COP_CURR_OFFSET(reg) ((reg)->ops_used - 1)
+#define COP_CURR_OFFSET_BYTES(reg, p) \
+ ((int )((char* )(&((reg)->ops_curr->p)) - (char* )((reg)->ops)))
+
+
+extern void onig_add_end_call(void (*func)(void));
+extern void onig_warning(const char* s);
+extern UChar* onig_error_code_to_format P_((int code));
+extern void ONIG_VARIADIC_FUNC_ATTR onig_snprintf_with_pattern PV_((UChar buf[], int bufsize, OnigEncoding enc, UChar* pat, UChar* pat_end, const UChar *fmt, ...));
+extern int onig_compile P_((regex_t* reg, const UChar* pattern, const UChar* pattern_end, OnigErrorInfo* einfo));
+extern int onig_is_code_in_cc_len P_((int enclen, OnigCodePoint code, void* /* CClassNode* */ cc));
+extern RegexExt* onig_get_regex_ext(regex_t* reg);
+extern int onig_ext_set_pattern(regex_t* reg, const UChar* pattern, const UChar* pattern_end);
+extern int onig_positive_int_multiply(int x, int y);
+extern hash_table_type onig_st_init_strend_table_with_size P_((int size));
+extern int onig_st_lookup_strend P_((hash_table_type table, const UChar* str_key, const UChar* end_key, hash_data_type *value));
+extern int onig_st_insert_strend P_((hash_table_type table, const UChar* str_key, const UChar* end_key, hash_data_type value));
+
+#ifdef ONIG_DEBUG
+
+#ifdef ONIG_DEBUG_COMPILE
+extern void onig_print_compiled_byte_code_list(FILE* f, regex_t* reg);
+#endif
+
+#ifdef ONIG_DEBUG_STATISTICS
+extern void onig_statistics_init P_((void));
+extern int onig_print_statistics P_((FILE* f));
+#endif
+
+#endif /* ONIG_DEBUG */
+
+#ifdef USE_CALLOUT
+
+extern OnigCalloutType onig_get_callout_type_by_name_id(int name_id);
+extern OnigCalloutFunc onig_get_callout_start_func_by_name_id(int id);
+extern OnigCalloutFunc onig_get_callout_end_func_by_name_id(int id);
+extern int onig_callout_tag_table_free(void* table);
+extern void onig_free_reg_callout_list(int n, CalloutListEntry* list);
+extern CalloutListEntry* onig_reg_callout_list_at(regex_t* reg, int num);
+extern OnigCalloutFunc onig_get_callout_start_func(regex_t* reg, int callout_num);
+
+/* for definition of builtin callout */
+#define BC0_P(name, func) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_PROGRESS,\
+ onig_builtin_ ## func, 0, 0, 0, 0, 0);\
+ if (id < 0) return id;\
+} while(0)
+
+#define BC0_R(name, func) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_RETRACTION,\
+ onig_builtin_ ## func, 0, 0, 0, 0, 0);\
+ if (id < 0) return id;\
+} while(0)
+
+#define BC0_B(name, func) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_BOTH,\
+ onig_builtin_ ## func, 0, 0, 0, 0, 0);\
+ if (id < 0) return id;\
+} while(0)
+
+#define BC_P(name, func, na, ts) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_PROGRESS,\
+ onig_builtin_ ## func, 0, (na), (ts), 0, 0); \
+ if (id < 0) return id;\
+} while(0)
+
+#define BC_P_O(name, func, nts, ts, nopts, opts) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_PROGRESS,\
+ onig_builtin_ ## func, 0, (nts), (ts), (nopts), (opts));\
+ if (id < 0) return id;\
+} while(0)
+
+#define BC_B(name, func, na, ts) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_BOTH,\
+ onig_builtin_ ## func, 0, (na), (ts), 0, 0);\
+ if (id < 0) return id;\
+} while(0)
+
+#define BC_B_O(name, func, nts, ts, nopts, opts) do {\
+ int len = onigenc_str_bytelen_null(enc, (UChar* )name);\
+ id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,\
+ (UChar* )(name), (UChar* )((name) + len),\
+ ONIG_CALLOUT_IN_BOTH,\
+ onig_builtin_ ## func, 0, (nts), (ts), (nopts), (opts));\
+ if (id < 0) return id;\
+} while(0)
+
+#endif /* USE_CALLOUT */
+
+
+typedef int (*ONIGENC_INIT_PROPERTY_LIST_FUNC_TYPE)(void);
+
+#endif /* REGINT_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.c
new file mode 100644
index 000000000..07d1e7aee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.c
@@ -0,0 +1,8678 @@
+/**********************************************************************
+ regparse.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifdef DEBUG_NODE_FREE
+#ifndef NEED_TO_INCLUDE_STDIO
+#define NEED_TO_INCLUDE_STDIO
+#endif
+#endif
+
+#include "regparse.h"
+#include "st.h"
+
+#define INIT_TAG_NAMES_ALLOC_NUM 5
+
+#define WARN_BUFSIZE 256
+
+#define CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
+
+#define IS_ALLOWED_CODE_IN_CALLOUT_NAME(c) \
+ ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' /* || c == '!' */)
+#define IS_ALLOWED_CODE_IN_CALLOUT_TAG_NAME(c) \
+ ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')
+
+#define OPTON_SINGLELINE(option) ((option) & ONIG_OPTION_SINGLELINE)
+#define OPTON_MULTILINE(option) ((option) & ONIG_OPTION_MULTILINE)
+#define OPTON_IGNORECASE(option) ((option) & ONIG_OPTION_IGNORECASE)
+#define OPTON_EXTEND(option) ((option) & ONIG_OPTION_EXTEND)
+#define OPTON_WORD_ASCII(option) \
+ ((option) & (ONIG_OPTION_WORD_IS_ASCII | ONIG_OPTION_POSIX_IS_ASCII))
+#define OPTON_DIGIT_ASCII(option) \
+ ((option) & (ONIG_OPTION_DIGIT_IS_ASCII | ONIG_OPTION_POSIX_IS_ASCII))
+#define OPTON_SPACE_ASCII(option) \
+ ((option) & (ONIG_OPTION_SPACE_IS_ASCII | ONIG_OPTION_POSIX_IS_ASCII))
+#define OPTON_POSIX_ASCII(option) ((option) & ONIG_OPTION_POSIX_IS_ASCII)
+#define OPTON_TEXT_SEGMENT_WORD(option) ((option) & ONIG_OPTION_TEXT_SEGMENT_WORD)
+
+#define OPTON_IS_ASCII_MODE_CTYPE(ctype, options) \
+ ((ctype) >= 0 && \
+ (((ctype) < ONIGENC_CTYPE_ASCII && OPTON_POSIX_ASCII(options)) ||\
+ ((ctype) == ONIGENC_CTYPE_WORD && OPTON_WORD_ASCII(options)) ||\
+ ((ctype) == ONIGENC_CTYPE_DIGIT && OPTON_DIGIT_ASCII(options)) ||\
+ ((ctype) == ONIGENC_CTYPE_SPACE && OPTON_SPACE_ASCII(options))))
+
+
+OnigSyntaxType OnigSyntaxOniguruma = {
+ (( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
+ ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 |
+ ONIG_SYN_OP_ESC_X_BRACE_HEX8 | ONIG_SYN_OP_ESC_O_BRACE_OCTAL |
+ ONIG_SYN_OP_ESC_CONTROL_CHARS |
+ ONIG_SYN_OP_ESC_C_CONTROL )
+ & ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
+ , ( ONIG_SYN_OP2_QMARK_GROUP_EFFECT |
+ ONIG_SYN_OP2_OPTION_ONIGURUMA |
+ ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP | ONIG_SYN_OP2_ESC_K_NAMED_BACKREF |
+ ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE |
+ ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP |
+ ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS |
+ ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME |
+ ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT |
+ ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE |
+ ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT |
+ ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP |
+ ONIG_SYN_OP2_ESC_G_SUBEXP_CALL |
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY |
+ ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT |
+ ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT |
+ ONIG_SYN_OP2_CCLASS_SET_OP | ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL |
+ ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META | ONIG_SYN_OP2_ESC_V_VTAB |
+ ONIG_SYN_OP2_ESC_H_XDIGIT | ONIG_SYN_OP2_ESC_U_HEX4 )
+ , ( SYN_GNU_REGEX_BV |
+ ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV |
+ ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND |
+ ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND |
+ ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP |
+ ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME |
+ ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY |
+ ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC |
+ ONIG_SYN_WARN_CC_OP_NOT_ESCAPED |
+ ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT )
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxRuby = {
+ (( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
+ ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 |
+ ONIG_SYN_OP_ESC_X_BRACE_HEX8 | ONIG_SYN_OP_ESC_O_BRACE_OCTAL |
+ ONIG_SYN_OP_ESC_CONTROL_CHARS |
+ ONIG_SYN_OP_ESC_C_CONTROL )
+ & ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
+ , ( ONIG_SYN_OP2_QMARK_GROUP_EFFECT |
+ ONIG_SYN_OP2_OPTION_RUBY |
+ ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP | ONIG_SYN_OP2_ESC_K_NAMED_BACKREF |
+ ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE |
+ ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP |
+ ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT |
+ ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE |
+ ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP |
+ ONIG_SYN_OP2_ESC_G_SUBEXP_CALL |
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY |
+ ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT |
+ ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT |
+ ONIG_SYN_OP2_CCLASS_SET_OP | ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL |
+ ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META | ONIG_SYN_OP2_ESC_V_VTAB |
+ ONIG_SYN_OP2_ESC_H_XDIGIT | ONIG_SYN_OP2_ESC_U_HEX4 )
+ , ( SYN_GNU_REGEX_BV |
+ ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV |
+ ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND |
+ ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP |
+ ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME |
+ ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY |
+ ONIG_SYN_WARN_CC_OP_NOT_ESCAPED |
+ ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT )
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType* OnigDefaultSyntax = ONIG_SYNTAX_ONIGURUMA;
+
+extern void onig_null_warn(const char* s ARG_UNUSED) { }
+
+#ifdef DEFAULT_WARN_FUNCTION
+static OnigWarnFunc onig_warn = (OnigWarnFunc )DEFAULT_WARN_FUNCTION;
+#else
+static OnigWarnFunc onig_warn = onig_null_warn;
+#endif
+
+#ifdef DEFAULT_VERB_WARN_FUNCTION
+static OnigWarnFunc onig_verb_warn = (OnigWarnFunc )DEFAULT_VERB_WARN_FUNCTION;
+#else
+static OnigWarnFunc onig_verb_warn = onig_null_warn;
+#endif
+
+extern void onig_set_warn_func(OnigWarnFunc f)
+{
+ onig_warn = f;
+}
+
+extern void onig_set_verb_warn_func(OnigWarnFunc f)
+{
+ onig_verb_warn = f;
+}
+
+extern void
+onig_warning(const char* s)
+{
+ if (onig_warn == onig_null_warn) return ;
+
+ (*onig_warn)(s);
+}
+
+#define DEFAULT_MAX_CAPTURE_NUM 32767
+
+static int MaxCaptureNum = DEFAULT_MAX_CAPTURE_NUM;
+
+extern int
+onig_set_capture_num_limit(int num)
+{
+ if (num < 0) return -1;
+
+ MaxCaptureNum = num;
+ return 0;
+}
+
+static unsigned int ParseDepthLimit = DEFAULT_PARSE_DEPTH_LIMIT;
+
+extern unsigned int
+onig_get_parse_depth_limit(void)
+{
+ return ParseDepthLimit;
+}
+
+extern int
+onig_set_parse_depth_limit(unsigned int depth)
+{
+ if (depth == 0)
+ ParseDepthLimit = DEFAULT_PARSE_DEPTH_LIMIT;
+ else
+ ParseDepthLimit = depth;
+ return 0;
+}
+
+#ifdef ONIG_DEBUG_PARSE
+#define INC_PARSE_DEPTH(d) do {\
+ (d)++;\
+ if (env->max_parse_depth < (d)) env->max_parse_depth = d;\
+ if ((d) > ParseDepthLimit) \
+ return ONIGERR_PARSE_DEPTH_LIMIT_OVER;\
+} while (0)
+#else
+#define INC_PARSE_DEPTH(d) do {\
+ (d)++;\
+ if ((d) > ParseDepthLimit) \
+ return ONIGERR_PARSE_DEPTH_LIMIT_OVER;\
+} while (0)
+#endif
+
+#define DEC_PARSE_DEPTH(d) (d)--
+
+
+static int
+bbuf_init(BBuf* buf, int size)
+{
+ if (size <= 0) {
+ size = 0;
+ buf->p = NULL;
+ }
+ else {
+ buf->p = (UChar* )xmalloc(size);
+ if (IS_NULL(buf->p)) return(ONIGERR_MEMORY);
+ }
+
+ buf->alloc = size;
+ buf->used = 0;
+ return 0;
+}
+
+static void
+bbuf_free(BBuf* bbuf)
+{
+ if (IS_NOT_NULL(bbuf)) {
+ if (IS_NOT_NULL(bbuf->p)) xfree(bbuf->p);
+ xfree(bbuf);
+ }
+}
+
+static int
+bbuf_clone(BBuf** rto, BBuf* from)
+{
+ int r;
+ BBuf *to;
+
+ *rto = to = (BBuf* )xmalloc(sizeof(BBuf));
+ CHECK_NULL_RETURN_MEMERR(to);
+ r = BB_INIT(to, from->alloc);
+ if (r != 0) {
+ xfree(to->p);
+ *rto = 0;
+ return r;
+ }
+ to->used = from->used;
+ xmemcpy(to->p, from->p, from->used);
+ return 0;
+}
+
+static int
+backref_rel_to_abs(int rel_no, ScanEnv* env)
+{
+ if (rel_no > 0) {
+ return env->num_mem + rel_no;
+ }
+ else {
+ return env->num_mem + 1 + rel_no;
+ }
+}
+
+#define OPTION_ON(v,f) ((v) |= (f))
+#define OPTION_OFF(v,f) ((v) &= ~(f))
+
+#define OPTION_NEGATE(v,f,negative) (negative) ? ((v) &= ~(f)) : ((v) |= (f))
+
+#define MBCODE_START_POS(enc) \
+ (OnigCodePoint )(ONIGENC_MBC_MINLEN(enc) > 1 ? 0 : 0x80)
+
+#define SET_ALL_MULTI_BYTE_RANGE(enc, pbuf) \
+ add_code_range_to_buf(pbuf, MBCODE_START_POS(enc), ~((OnigCodePoint )0))
+
+#define ADD_ALL_MULTI_BYTE_RANGE(enc, mbuf) do {\
+ if (! ONIGENC_IS_SINGLEBYTE(enc)) {\
+ r = SET_ALL_MULTI_BYTE_RANGE(enc, &(mbuf));\
+ if (r != 0) return r;\
+ }\
+} while (0)
+
+
+#define BITSET_IS_EMPTY(bs,empty) do {\
+ int i;\
+ empty = 1;\
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) {\
+ if ((bs)[i] != 0) {\
+ empty = 0; break;\
+ }\
+ }\
+} while (0)
+
+static void
+bitset_set_range(BitSetRef bs, int from, int to)
+{
+ int i;
+ for (i = from; i <= to && i < SINGLE_BYTE_SIZE; i++) {
+ BITSET_SET_BIT(bs, i);
+ }
+}
+
+static void
+bitset_invert(BitSetRef bs)
+{
+ int i;
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { bs[i] = ~(bs[i]); }
+}
+
+static void
+bitset_invert_to(BitSetRef from, BitSetRef to)
+{
+ int i;
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { to[i] = ~(from[i]); }
+}
+
+static void
+bitset_and(BitSetRef dest, BitSetRef bs)
+{
+ int i;
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { dest[i] &= bs[i]; }
+}
+
+static void
+bitset_or(BitSetRef dest, BitSetRef bs)
+{
+ int i;
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { dest[i] |= bs[i]; }
+}
+
+static void
+bitset_copy(BitSetRef dest, BitSetRef bs)
+{
+ int i;
+ for (i = 0; i < (int )BITSET_REAL_SIZE; i++) { dest[i] = bs[i]; }
+}
+
+extern int
+onig_strncmp(const UChar* s1, const UChar* s2, int n)
+{
+ int x;
+
+ while (n-- > 0) {
+ x = *s2++ - *s1++;
+ if (x) return x;
+ }
+ return 0;
+}
+
+extern void
+onig_strcpy(UChar* dest, const UChar* src, const UChar* end)
+{
+ int len = (int )(end - src);
+ if (len > 0) {
+ xmemcpy(dest, src, len);
+ dest[len] = (UChar )0;
+ }
+}
+
+/* scan pattern methods */
+#define PEND_VALUE 0
+
+#define PFETCH_READY UChar* pfetch_prev
+#define PEND (p < end ? 0 : 1)
+#define PUNFETCH p = pfetch_prev
+#define PINC do { \
+ pfetch_prev = p; \
+ p += ONIGENC_MBC_ENC_LEN(enc, p); \
+} while (0)
+#define PFETCH(c) do { \
+ c = ONIGENC_MBC_TO_CODE(enc, p, end); \
+ pfetch_prev = p; \
+ p += ONIGENC_MBC_ENC_LEN(enc, p); \
+} while (0)
+
+#define PINC_S do { \
+ p += ONIGENC_MBC_ENC_LEN(enc, p); \
+} while (0)
+#define PFETCH_S(c) do { \
+ c = ONIGENC_MBC_TO_CODE(enc, p, end); \
+ p += ONIGENC_MBC_ENC_LEN(enc, p); \
+} while (0)
+
+#define PPEEK (p < end ? ONIGENC_MBC_TO_CODE(enc, p, end) : PEND_VALUE)
+#define PPEEK_IS(c) (PPEEK == (OnigCodePoint )c)
+
+static UChar*
+strcat_capa(UChar* dest, UChar* dest_end, const UChar* src, const UChar* src_end,
+ int capa)
+{
+ UChar* r;
+
+ if (dest)
+ r = (UChar* )xrealloc(dest, capa + 1);
+ else
+ r = (UChar* )xmalloc(capa + 1);
+
+ CHECK_NULL_RETURN(r);
+ onig_strcpy(r + (dest_end - dest), src, src_end);
+ return r;
+}
+
+/* dest on static area */
+static UChar*
+strcat_capa_from_static(UChar* dest, UChar* dest_end,
+ const UChar* src, const UChar* src_end, int capa)
+{
+ UChar* r;
+
+ r = (UChar* )xmalloc(capa + 1);
+ CHECK_NULL_RETURN(r);
+ onig_strcpy(r, dest, dest_end);
+ onig_strcpy(r + (dest_end - dest), src, src_end);
+ return r;
+}
+
+
+#ifdef USE_ST_LIBRARY
+
+typedef struct {
+ UChar* s;
+ UChar* end;
+} st_str_end_key;
+
+static int
+str_end_cmp(st_str_end_key* x, st_str_end_key* y)
+{
+ UChar *p, *q;
+ int c;
+
+ if ((x->end - x->s) != (y->end - y->s))
+ return 1;
+
+ p = x->s;
+ q = y->s;
+ while (p < x->end) {
+ c = (int )*p - (int )*q;
+ if (c != 0) return c;
+
+ p++; q++;
+ }
+
+ return 0;
+}
+
+static int
+str_end_hash(st_str_end_key* x)
+{
+ UChar *p;
+ unsigned val = 0;
+
+ p = x->s;
+ while (p < x->end) {
+ val = val * 997 + (unsigned )*p++;
+ }
+
+ return (int) (val + (val >> 5));
+}
+
+extern hash_table_type
+onig_st_init_strend_table_with_size(int size)
+{
+ static struct st_hash_type hashType = {
+ str_end_cmp,
+ str_end_hash,
+ };
+
+ return (hash_table_type )onig_st_init_table_with_size(&hashType, size);
+}
+
+extern int
+onig_st_lookup_strend(hash_table_type table, const UChar* str_key,
+ const UChar* end_key, hash_data_type *value)
+{
+ st_str_end_key key;
+
+ key.s = (UChar* )str_key;
+ key.end = (UChar* )end_key;
+
+ return onig_st_lookup(table, (st_data_t )(&key), value);
+}
+
+extern int
+onig_st_insert_strend(hash_table_type table, const UChar* str_key,
+ const UChar* end_key, hash_data_type value)
+{
+ st_str_end_key* key;
+ int result;
+
+ key = (st_str_end_key* )xmalloc(sizeof(st_str_end_key));
+ CHECK_NULL_RETURN_MEMERR(key);
+
+ key->s = (UChar* )str_key;
+ key->end = (UChar* )end_key;
+ result = onig_st_insert(table, (st_data_t )key, value);
+ if (result) {
+ xfree(key);
+ }
+ return result;
+}
+
+
+#ifdef USE_CALLOUT
+
+typedef struct {
+ OnigEncoding enc;
+ int type; /* callout type: single or not */
+ UChar* s;
+ UChar* end;
+} st_callout_name_key;
+
+static int
+callout_name_table_cmp(st_callout_name_key* x, st_callout_name_key* y)
+{
+ UChar *p, *q;
+ int c;
+
+ if (x->enc != y->enc) return 1;
+ if (x->type != y->type) return 1;
+ if ((x->end - x->s) != (y->end - y->s))
+ return 1;
+
+ p = x->s;
+ q = y->s;
+ while (p < x->end) {
+ c = (int )*p - (int )*q;
+ if (c != 0) return c;
+
+ p++; q++;
+ }
+
+ return 0;
+}
+
+static int
+callout_name_table_hash(st_callout_name_key* x)
+{
+ UChar *p;
+ unsigned int val = 0;
+
+ p = x->s;
+ while (p < x->end) {
+ val = val * 997 + (unsigned int )*p++;
+ }
+
+ /* use intptr_t for escape warning in Windows */
+ return (int )(val + (val >> 5) + ((intptr_t )x->enc & 0xffff) + x->type);
+}
+
+extern hash_table_type
+onig_st_init_callout_name_table_with_size(int size)
+{
+ static struct st_hash_type hashType = {
+ callout_name_table_cmp,
+ callout_name_table_hash,
+ };
+
+ return (hash_table_type )onig_st_init_table_with_size(&hashType, size);
+}
+
+extern int
+onig_st_lookup_callout_name_table(hash_table_type table,
+ OnigEncoding enc,
+ int type,
+ const UChar* str_key,
+ const UChar* end_key,
+ hash_data_type *value)
+{
+ st_callout_name_key key;
+
+ key.enc = enc;
+ key.type = type;
+ key.s = (UChar* )str_key;
+ key.end = (UChar* )end_key;
+
+ return onig_st_lookup(table, (st_data_t )(&key), value);
+}
+
+static int
+st_insert_callout_name_table(hash_table_type table,
+ OnigEncoding enc, int type,
+ UChar* str_key, UChar* end_key,
+ hash_data_type value)
+{
+ st_callout_name_key* key;
+ int result;
+
+ key = (st_callout_name_key* )xmalloc(sizeof(st_callout_name_key));
+ CHECK_NULL_RETURN_MEMERR(key);
+
+ /* key->s: don't duplicate, because str_key is duped in callout_name_entry() */
+ key->enc = enc;
+ key->type = type;
+ key->s = str_key;
+ key->end = end_key;
+ result = onig_st_insert(table, (st_data_t )key, value);
+ if (result) {
+ xfree(key);
+ }
+ return result;
+}
+#endif
+
+#endif /* USE_ST_LIBRARY */
+
+
+#define INIT_NAME_BACKREFS_ALLOC_NUM 8
+
+typedef struct {
+ UChar* name;
+ int name_len; /* byte length */
+ int back_num; /* number of backrefs */
+ int back_alloc;
+ int back_ref1;
+ int* back_refs;
+} NameEntry;
+
+#ifdef USE_ST_LIBRARY
+
+#define INIT_NAMES_ALLOC_NUM 5
+
+typedef st_table NameTable;
+typedef st_data_t HashDataType; /* 1.6 st.h doesn't define st_data_t type */
+
+#define NAMEBUF_SIZE 24
+#define NAMEBUF_SIZE_1 25
+
+#ifdef ONIG_DEBUG
+static int
+i_print_name_entry(UChar* key, NameEntry* e, void* arg)
+{
+ int i;
+ FILE* fp = (FILE* )arg;
+
+ fprintf(fp, "%s: ", e->name);
+ if (e->back_num == 0)
+ fputs("-", fp);
+ else if (e->back_num == 1)
+ fprintf(fp, "%d", e->back_ref1);
+ else {
+ for (i = 0; i < e->back_num; i++) {
+ if (i > 0) fprintf(fp, ", ");
+ fprintf(fp, "%d", e->back_refs[i]);
+ }
+ }
+ fputs("\n", fp);
+ return ST_CONTINUE;
+}
+
+extern int
+onig_print_names(FILE* fp, regex_t* reg)
+{
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ fprintf(fp, "name table\n");
+ onig_st_foreach(t, i_print_name_entry, (HashDataType )fp);
+ fputs("\n", fp);
+ }
+ return 0;
+}
+#endif /* ONIG_DEBUG */
+
+static int
+i_free_name_entry(UChar* key, NameEntry* e, void* arg ARG_UNUSED)
+{
+ xfree(e->name);
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
+ xfree(key);
+ xfree(e);
+ return ST_DELETE;
+}
+
+static int
+names_clear(regex_t* reg)
+{
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ onig_st_foreach(t, i_free_name_entry, 0);
+ }
+ return 0;
+}
+
+extern int
+onig_names_free(regex_t* reg)
+{
+ int r;
+ NameTable* t;
+
+ r = names_clear(reg);
+ if (r != 0) return r;
+
+ t = (NameTable* )reg->name_table;
+ if (IS_NOT_NULL(t)) onig_st_free_table(t);
+ reg->name_table = (void* )NULL;
+ return 0;
+}
+
+static NameEntry*
+name_find(regex_t* reg, const UChar* name, const UChar* name_end)
+{
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ e = (NameEntry* )NULL;
+ if (IS_NOT_NULL(t)) {
+ onig_st_lookup_strend(t, name, name_end, (HashDataType* )((void* )(&e)));
+ }
+ return e;
+}
+
+typedef struct {
+ int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*);
+ regex_t* reg;
+ void* arg;
+ int ret;
+ OnigEncoding enc;
+} INamesArg;
+
+static int
+i_names(UChar* key ARG_UNUSED, NameEntry* e, INamesArg* arg)
+{
+ int r = (*(arg->func))(e->name,
+ e->name + e->name_len,
+ e->back_num,
+ (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
+ arg->reg, arg->arg);
+ if (r != 0) {
+ arg->ret = r;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+extern int
+onig_foreach_name(regex_t* reg,
+ int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*), void* arg)
+{
+ INamesArg narg;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ narg.ret = 0;
+ if (IS_NOT_NULL(t)) {
+ narg.func = func;
+ narg.reg = reg;
+ narg.arg = arg;
+ narg.enc = reg->enc; /* should be pattern encoding. */
+ onig_st_foreach(t, i_names, (HashDataType )&narg);
+ }
+ return narg.ret;
+}
+
+static int
+i_renumber_name(UChar* key ARG_UNUSED, NameEntry* e, GroupNumMap* map)
+{
+ int i;
+
+ if (e->back_num > 1) {
+ for (i = 0; i < e->back_num; i++) {
+ e->back_refs[i] = map[e->back_refs[i]].new_val;
+ }
+ }
+ else if (e->back_num == 1) {
+ e->back_ref1 = map[e->back_ref1].new_val;
+ }
+
+ return ST_CONTINUE;
+}
+
+extern int
+onig_renumber_name_table(regex_t* reg, GroupNumMap* map)
+{
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ onig_st_foreach(t, i_renumber_name, (HashDataType )map);
+ }
+ return 0;
+}
+
+
+extern int
+onig_number_of_names(regex_t* reg)
+{
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t))
+ return t->num_entries;
+ else
+ return 0;
+}
+
+#else /* USE_ST_LIBRARY */
+
+#define INIT_NAMES_ALLOC_NUM 8
+
+typedef struct {
+ NameEntry* e;
+ int num;
+ int alloc;
+} NameTable;
+
+#ifdef ONIG_DEBUG
+extern int
+onig_print_names(FILE* fp, regex_t* reg)
+{
+ int i, j;
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t) && t->num > 0) {
+ fprintf(fp, "name table\n");
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ fprintf(fp, "%s: ", e->name);
+ if (e->back_num == 0) {
+ fputs("-", fp);
+ }
+ else if (e->back_num == 1) {
+ fprintf(fp, "%d", e->back_ref1);
+ }
+ else {
+ for (j = 0; j < e->back_num; j++) {
+ if (j > 0) fprintf(fp, ", ");
+ fprintf(fp, "%d", e->back_refs[j]);
+ }
+ }
+ fputs("\n", fp);
+ }
+ fputs("\n", fp);
+ }
+ return 0;
+}
+#endif
+
+static int
+names_clear(regex_t* reg)
+{
+ int i;
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ if (IS_NOT_NULL(e->name)) {
+ xfree(e->name);
+ e->name = NULL;
+ e->name_len = 0;
+ e->back_num = 0;
+ e->back_alloc = 0;
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
+ e->back_refs = (int* )NULL;
+ }
+ }
+ if (IS_NOT_NULL(t->e)) {
+ xfree(t->e);
+ t->e = NULL;
+ }
+ t->num = 0;
+ }
+ return 0;
+}
+
+extern int
+onig_names_free(regex_t* reg)
+{
+ int r;
+ NameTable* t;
+
+ r = names_clear(reg);
+ if (r != 0) return r;
+
+ t = (NameTable* )reg->name_table;
+ if (IS_NOT_NULL(t)) xfree(t);
+ reg->name_table = NULL;
+ return 0;
+}
+
+static NameEntry*
+name_find(regex_t* reg, UChar* name, UChar* name_end)
+{
+ int i, len;
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ len = name_end - name;
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ if (len == e->name_len && onig_strncmp(name, e->name, len) == 0)
+ return e;
+ }
+ }
+ return (NameEntry* )NULL;
+}
+
+extern int
+onig_foreach_name(regex_t* reg,
+ int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*), void* arg)
+{
+ int i, r;
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t)) {
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ r = (*func)(e->name, e->name + e->name_len, e->back_num,
+ (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
+ reg, arg);
+ if (r != 0) return r;
+ }
+ }
+ return 0;
+}
+
+extern int
+onig_number_of_names(regex_t* reg)
+{
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (IS_NOT_NULL(t))
+ return t->num;
+ else
+ return 0;
+}
+
+#endif /* else USE_ST_LIBRARY */
+
+static int
+name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
+{
+ int r;
+ int alloc;
+ NameEntry* e;
+ NameTable* t = (NameTable* )reg->name_table;
+
+ if (name_end - name <= 0)
+ return ONIGERR_EMPTY_GROUP_NAME;
+
+ e = name_find(reg, name, name_end);
+ if (IS_NULL(e)) {
+#ifdef USE_ST_LIBRARY
+ if (IS_NULL(t)) {
+ t = onig_st_init_strend_table_with_size(INIT_NAMES_ALLOC_NUM);
+ CHECK_NULL_RETURN_MEMERR(t);
+ reg->name_table = (void* )t;
+ }
+ e = (NameEntry* )xmalloc(sizeof(NameEntry));
+ CHECK_NULL_RETURN_MEMERR(e);
+
+ e->name = onigenc_strdup(reg->enc, name, name_end);
+ if (IS_NULL(e->name)) {
+ xfree(e); return ONIGERR_MEMORY;
+ }
+ r = onig_st_insert_strend(t, e->name, (e->name + (name_end - name)),
+ (HashDataType )e);
+ if (r < 0) return r;
+
+ e->name_len = (int )(name_end - name);
+ e->back_num = 0;
+ e->back_alloc = 0;
+ e->back_refs = (int* )NULL;
+
+#else
+
+ if (IS_NULL(t)) {
+ alloc = INIT_NAMES_ALLOC_NUM;
+ t = (NameTable* )xmalloc(sizeof(NameTable));
+ CHECK_NULL_RETURN_MEMERR(t);
+ t->e = NULL;
+ t->alloc = 0;
+ t->num = 0;
+
+ t->e = (NameEntry* )xmalloc(sizeof(NameEntry) * alloc);
+ if (IS_NULL(t->e)) {
+ xfree(t);
+ return ONIGERR_MEMORY;
+ }
+ t->alloc = alloc;
+ reg->name_table = t;
+ goto clear;
+ }
+ else if (t->num == t->alloc) {
+ int i;
+
+ alloc = t->alloc * 2;
+ t->e = (NameEntry* )xrealloc(t->e, sizeof(NameEntry) * alloc);
+ CHECK_NULL_RETURN_MEMERR(t->e);
+ t->alloc = alloc;
+
+ clear:
+ for (i = t->num; i < t->alloc; i++) {
+ t->e[i].name = NULL;
+ t->e[i].name_len = 0;
+ t->e[i].back_num = 0;
+ t->e[i].back_alloc = 0;
+ t->e[i].back_refs = (int* )NULL;
+ }
+ }
+ e = &(t->e[t->num]);
+ t->num++;
+ e->name = onigenc_strdup(reg->enc, name, name_end);
+ if (IS_NULL(e->name)) return ONIGERR_MEMORY;
+ e->name_len = name_end - name;
+#endif
+ }
+
+ if (e->back_num >= 1 &&
+ ! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME)) {
+ onig_scan_env_set_error_string(env, ONIGERR_MULTIPLEX_DEFINED_NAME,
+ name, name_end);
+ return ONIGERR_MULTIPLEX_DEFINED_NAME;
+ }
+
+ e->back_num++;
+ if (e->back_num == 1) {
+ e->back_ref1 = backref;
+ }
+ else {
+ if (e->back_num == 2) {
+ alloc = INIT_NAME_BACKREFS_ALLOC_NUM;
+ e->back_refs = (int* )xmalloc(sizeof(int) * alloc);
+ CHECK_NULL_RETURN_MEMERR(e->back_refs);
+ e->back_alloc = alloc;
+ e->back_refs[0] = e->back_ref1;
+ e->back_refs[1] = backref;
+ }
+ else {
+ if (e->back_num > e->back_alloc) {
+ alloc = e->back_alloc * 2;
+ e->back_refs = (int* )xrealloc(e->back_refs, sizeof(int) * alloc);
+ CHECK_NULL_RETURN_MEMERR(e->back_refs);
+ e->back_alloc = alloc;
+ }
+ e->back_refs[e->back_num - 1] = backref;
+ }
+ }
+
+ return 0;
+}
+
+extern int
+onig_name_to_group_numbers(regex_t* reg, const UChar* name,
+ const UChar* name_end, int** nums)
+{
+ NameEntry* e = name_find(reg, name, name_end);
+
+ if (IS_NULL(e)) return ONIGERR_UNDEFINED_NAME_REFERENCE;
+
+ switch (e->back_num) {
+ case 0:
+ break;
+ case 1:
+ *nums = &(e->back_ref1);
+ break;
+ default:
+ *nums = e->back_refs;
+ break;
+ }
+ return e->back_num;
+}
+
+static int
+name_to_group_numbers(ScanEnv* env, const UChar* name, const UChar* name_end,
+ int** nums)
+{
+ regex_t* reg;
+ NameEntry* e;
+
+ reg = env->reg;
+ e = name_find(reg, name, name_end);
+
+ if (IS_NULL(e)) {
+ onig_scan_env_set_error_string(env, ONIGERR_UNDEFINED_NAME_REFERENCE,
+ (UChar* )name, (UChar* )name_end);
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+
+ switch (e->back_num) {
+ case 0:
+ break;
+ case 1:
+ *nums = &(e->back_ref1);
+ break;
+ default:
+ *nums = e->back_refs;
+ break;
+ }
+ return e->back_num;
+}
+
+extern int
+onig_name_to_backref_number(regex_t* reg, const UChar* name,
+ const UChar* name_end, OnigRegion *region)
+{
+ int i, n, *nums;
+
+ n = onig_name_to_group_numbers(reg, name, name_end, &nums);
+ if (n < 0)
+ return n;
+ else if (n == 0)
+ return ONIGERR_PARSER_BUG;
+ else if (n == 1)
+ return nums[0];
+ else {
+ if (IS_NOT_NULL(region)) {
+ for (i = n - 1; i >= 0; i--) {
+ if (region->beg[nums[i]] != ONIG_REGION_NOTPOS)
+ return nums[i];
+ }
+ }
+ return nums[n - 1];
+ }
+}
+
+extern int
+onig_noname_group_capture_is_active(regex_t* reg)
+{
+ if (OPTON_DONT_CAPTURE_GROUP(reg->options))
+ return 0;
+
+ if (onig_number_of_names(reg) > 0 &&
+ IS_SYNTAX_BV(reg->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
+ ! OPTON_CAPTURE_GROUP(reg->options)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef USE_CALLOUT
+
+typedef struct {
+ OnigCalloutType type;
+ int in;
+ OnigCalloutFunc start_func;
+ OnigCalloutFunc end_func;
+ int arg_num;
+ int opt_arg_num;
+ unsigned int arg_types[ONIG_CALLOUT_MAX_ARGS_NUM];
+ OnigValue opt_defaults[ONIG_CALLOUT_MAX_ARGS_NUM];
+ UChar* name; /* reference to GlobalCalloutNameTable entry: e->name */
+} CalloutNameListEntry;
+
+typedef struct {
+ int n;
+ int alloc;
+ CalloutNameListEntry* v;
+} CalloutNameListType;
+
+static CalloutNameListType* GlobalCalloutNameList;
+
+static int
+make_callout_func_list(CalloutNameListType** rs, int init_size)
+{
+ CalloutNameListType* s;
+ CalloutNameListEntry* v;
+
+ *rs = 0;
+
+ s = xmalloc(sizeof(*s));
+ if (IS_NULL(s)) return ONIGERR_MEMORY;
+
+ v = (CalloutNameListEntry* )xmalloc(sizeof(CalloutNameListEntry) * init_size);
+ if (IS_NULL(v)) {
+ xfree(s);
+ return ONIGERR_MEMORY;
+ }
+
+ s->n = 0;
+ s->alloc = init_size;
+ s->v = v;
+
+ *rs = s;
+ return ONIG_NORMAL;
+}
+
+static void
+free_callout_func_list(CalloutNameListType* s)
+{
+ if (IS_NOT_NULL(s)) {
+ if (IS_NOT_NULL(s->v)) {
+ int i, j;
+
+ for (i = 0; i < s->n; i++) {
+ CalloutNameListEntry* e = s->v + i;
+ for (j = e->arg_num - e->opt_arg_num; j < e->arg_num; j++) {
+ if (e->arg_types[j] == ONIG_TYPE_STRING) {
+ UChar* p = e->opt_defaults[j].s.start;
+ if (IS_NOT_NULL(p)) xfree(p);
+ }
+ }
+ }
+ xfree(s->v);
+ }
+ xfree(s);
+ }
+}
+
+static int
+callout_func_list_add(CalloutNameListType* s, int* rid)
+{
+ if (s->n >= s->alloc) {
+ int new_size = s->alloc * 2;
+ CalloutNameListEntry* nv = (CalloutNameListEntry* )
+ xrealloc(s->v, sizeof(CalloutNameListEntry) * new_size);
+ if (IS_NULL(nv)) return ONIGERR_MEMORY;
+
+ s->alloc = new_size;
+ s->v = nv;
+ }
+
+ *rid = s->n;
+
+ xmemset(&(s->v[s->n]), 0, sizeof(*(s->v)));
+ s->n++;
+ return ONIG_NORMAL;
+}
+
+
+typedef struct {
+ UChar* name;
+ int name_len; /* byte length */
+ int id;
+} CalloutNameEntry;
+
+#ifdef USE_ST_LIBRARY
+typedef st_table CalloutNameTable;
+#else
+typedef struct {
+ CalloutNameEntry* e;
+ int num;
+ int alloc;
+} CalloutNameTable;
+#endif
+
+static CalloutNameTable* GlobalCalloutNameTable;
+static int CalloutNameIDCounter;
+
+#ifdef USE_ST_LIBRARY
+
+static int
+i_free_callout_name_entry(st_callout_name_key* key, CalloutNameEntry* e,
+ void* arg ARG_UNUSED)
+{
+ xfree(e->name);
+ /*xfree(key->s); */ /* is same as e->name */
+ xfree(key);
+ xfree(e);
+ return ST_DELETE;
+}
+
+static int
+callout_name_table_clear(CalloutNameTable* t)
+{
+ if (IS_NOT_NULL(t)) {
+ onig_st_foreach(t, i_free_callout_name_entry, 0);
+ }
+ return 0;
+}
+
+static int
+global_callout_name_table_free(void)
+{
+ if (IS_NOT_NULL(GlobalCalloutNameTable)) {
+ int r = callout_name_table_clear(GlobalCalloutNameTable);
+ if (r != 0) return r;
+
+ onig_st_free_table(GlobalCalloutNameTable);
+ GlobalCalloutNameTable = 0;
+ CalloutNameIDCounter = 0;
+ }
+
+ return 0;
+}
+
+static CalloutNameEntry*
+callout_name_find(OnigEncoding enc, int is_not_single,
+ const UChar* name, const UChar* name_end)
+{
+ int r;
+ CalloutNameEntry* e;
+ CalloutNameTable* t = GlobalCalloutNameTable;
+
+ e = (CalloutNameEntry* )NULL;
+ if (IS_NOT_NULL(t)) {
+ r = onig_st_lookup_callout_name_table(t, enc, is_not_single, name, name_end,
+ (HashDataType* )((void* )(&e)));
+ if (r == 0) { /* not found */
+ if (enc != ONIG_ENCODING_ASCII &&
+ ONIGENC_IS_ASCII_COMPATIBLE_ENCODING(enc)) {
+ enc = ONIG_ENCODING_ASCII;
+ onig_st_lookup_callout_name_table(t, enc, is_not_single, name, name_end,
+ (HashDataType* )((void* )(&e)));
+ }
+ }
+ }
+ return e;
+}
+
+#else
+
+static int
+callout_name_table_clear(CalloutNameTable* t)
+{
+ int i;
+ CalloutNameEntry* e;
+
+ if (IS_NOT_NULL(t)) {
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ if (IS_NOT_NULL(e->name)) {
+ xfree(e->name);
+ e->name = NULL;
+ e->name_len = 0;
+ e->id = 0;
+ e->func = 0;
+ }
+ }
+ if (IS_NOT_NULL(t->e)) {
+ xfree(t->e);
+ t->e = NULL;
+ }
+ t->num = 0;
+ }
+ return 0;
+}
+
+static int
+global_callout_name_table_free(void)
+{
+ if (IS_NOT_NULL(GlobalCalloutNameTable)) {
+ int r = callout_name_table_clear(GlobalCalloutNameTable);
+ if (r != 0) return r;
+
+ xfree(GlobalCalloutNameTable);
+ GlobalCalloutNameTable = 0;
+ CalloutNameIDCounter = 0;
+ }
+ return 0;
+}
+
+static CalloutNameEntry*
+callout_name_find(UChar* name, UChar* name_end)
+{
+ int i, len;
+ CalloutNameEntry* e;
+ CalloutNameTable* t = Calloutnames;
+
+ if (IS_NOT_NULL(t)) {
+ len = name_end - name;
+ for (i = 0; i < t->num; i++) {
+ e = &(t->e[i]);
+ if (len == e->name_len && onig_strncmp(name, e->name, len) == 0)
+ return e;
+ }
+ }
+ return (CalloutNameEntry* )NULL;
+}
+
+#endif
+
+/* name string must be single byte char string. */
+static int
+callout_name_entry(CalloutNameEntry** rentry, OnigEncoding enc,
+ int is_not_single, UChar* name, UChar* name_end)
+{
+ int r;
+ CalloutNameEntry* e;
+ CalloutNameTable* t = GlobalCalloutNameTable;
+
+ *rentry = 0;
+ if (name_end - name <= 0)
+ return ONIGERR_INVALID_CALLOUT_NAME;
+
+ e = callout_name_find(enc, is_not_single, name, name_end);
+ if (IS_NULL(e)) {
+#ifdef USE_ST_LIBRARY
+ if (IS_NULL(t)) {
+ t = onig_st_init_callout_name_table_with_size(INIT_NAMES_ALLOC_NUM);
+ CHECK_NULL_RETURN_MEMERR(t);
+ GlobalCalloutNameTable = t;
+ }
+ e = (CalloutNameEntry* )xmalloc(sizeof(CalloutNameEntry));
+ CHECK_NULL_RETURN_MEMERR(e);
+
+ e->name = onigenc_strdup(enc, name, name_end);
+ if (IS_NULL(e->name)) {
+ xfree(e); return ONIGERR_MEMORY;
+ }
+
+ r = st_insert_callout_name_table(t, enc, is_not_single,
+ e->name, (e->name + (name_end - name)),
+ (HashDataType )e);
+ if (r < 0) return r;
+
+#else
+
+ int alloc;
+
+ if (IS_NULL(t)) {
+ alloc = INIT_NAMES_ALLOC_NUM;
+ t = (CalloutNameTable* )xmalloc(sizeof(CalloutNameTable));
+ CHECK_NULL_RETURN_MEMERR(t);
+ t->e = NULL;
+ t->alloc = 0;
+ t->num = 0;
+
+ t->e = (CalloutNameEntry* )xmalloc(sizeof(CalloutNameEntry) * alloc);
+ if (IS_NULL(t->e)) {
+ xfree(t);
+ return ONIGERR_MEMORY;
+ }
+ t->alloc = alloc;
+ GlobalCalloutNameTable = t;
+ goto clear;
+ }
+ else if (t->num == t->alloc) {
+ int i;
+
+ alloc = t->alloc * 2;
+ t->e = (CalloutNameEntry* )xrealloc(t->e, sizeof(CalloutNameEntry) * alloc);
+ CHECK_NULL_RETURN_MEMERR(t->e);
+ t->alloc = alloc;
+
+ clear:
+ for (i = t->num; i < t->alloc; i++) {
+ t->e[i].name = NULL;
+ t->e[i].name_len = 0;
+ t->e[i].id = 0;
+ }
+ }
+ e = &(t->e[t->num]);
+ t->num++;
+ e->name = onigenc_strdup(enc, name, name_end);
+ if (IS_NULL(e->name)) return ONIGERR_MEMORY;
+#endif
+
+ CalloutNameIDCounter++;
+ e->id = CalloutNameIDCounter;
+ e->name_len = (int )(name_end - name);
+ }
+
+ *rentry = e;
+ return e->id;
+}
+
+static int
+is_allowed_callout_name(OnigEncoding enc, UChar* name, UChar* name_end)
+{
+ UChar* p;
+ OnigCodePoint c;
+
+ if (name >= name_end) return 0;
+
+ p = name;
+ while (p < name_end) {
+ c = ONIGENC_MBC_TO_CODE(enc, p, name_end);
+ if (! IS_ALLOWED_CODE_IN_CALLOUT_NAME(c))
+ return 0;
+
+ if (p == name) {
+ if (c >= '0' && c <= '9') return 0;
+ }
+
+ p += ONIGENC_MBC_ENC_LEN(enc, p);
+ }
+
+ return 1;
+}
+
+static int
+is_allowed_callout_tag_name(OnigEncoding enc, UChar* name, UChar* name_end)
+{
+ UChar* p;
+ OnigCodePoint c;
+
+ if (name >= name_end) return 0;
+
+ p = name;
+ while (p < name_end) {
+ c = ONIGENC_MBC_TO_CODE(enc, p, name_end);
+ if (! IS_ALLOWED_CODE_IN_CALLOUT_TAG_NAME(c))
+ return 0;
+
+ if (p == name) {
+ if (c >= '0' && c <= '9') return 0;
+ }
+
+ p += ONIGENC_MBC_ENC_LEN(enc, p);
+ }
+
+ return 1;
+}
+
+extern int
+onig_set_callout_of_name(OnigEncoding enc, OnigCalloutType callout_type,
+ UChar* name, UChar* name_end, int in,
+ OnigCalloutFunc start_func,
+ OnigCalloutFunc end_func,
+ int arg_num, unsigned int arg_types[],
+ int opt_arg_num, OnigValue opt_defaults[])
+{
+ int r;
+ int i;
+ int j;
+ int id;
+ int is_not_single;
+ CalloutNameEntry* e;
+ CalloutNameListEntry* fe;
+
+ if (callout_type != ONIG_CALLOUT_TYPE_SINGLE)
+ return ONIGERR_INVALID_ARGUMENT;
+
+ if (arg_num < 0 || arg_num > ONIG_CALLOUT_MAX_ARGS_NUM)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if (opt_arg_num < 0 || opt_arg_num > arg_num)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if (start_func == 0 && end_func == 0)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if ((in & ONIG_CALLOUT_IN_PROGRESS) == 0 && (in & ONIG_CALLOUT_IN_RETRACTION) == 0)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ for (i = 0; i < arg_num; i++) {
+ unsigned int t = arg_types[i];
+ if (t == ONIG_TYPE_VOID)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+ else {
+ if (i >= arg_num - opt_arg_num) {
+ if (t != ONIG_TYPE_LONG && t != ONIG_TYPE_CHAR && t != ONIG_TYPE_STRING &&
+ t != ONIG_TYPE_TAG)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+ }
+ else {
+ if (t != ONIG_TYPE_LONG) {
+ t = t & ~ONIG_TYPE_LONG;
+ if (t != ONIG_TYPE_CHAR && t != ONIG_TYPE_STRING && t != ONIG_TYPE_TAG)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+ }
+ }
+ }
+ }
+
+ if (! is_allowed_callout_name(enc, name, name_end)) {
+ return ONIGERR_INVALID_CALLOUT_NAME;
+ }
+
+ is_not_single = (callout_type != ONIG_CALLOUT_TYPE_SINGLE);
+ id = callout_name_entry(&e, enc, is_not_single, name, name_end);
+ if (id < 0) return id;
+
+ r = ONIG_NORMAL;
+ if (IS_NULL(GlobalCalloutNameList)) {
+ r = make_callout_func_list(&GlobalCalloutNameList, 10);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ while (id >= GlobalCalloutNameList->n) {
+ int rid;
+ r = callout_func_list_add(GlobalCalloutNameList, &rid);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ fe = GlobalCalloutNameList->v + id;
+ fe->type = callout_type;
+ fe->in = in;
+ fe->start_func = start_func;
+ fe->end_func = end_func;
+ fe->arg_num = arg_num;
+ fe->opt_arg_num = opt_arg_num;
+ fe->name = e->name;
+
+ for (i = 0; i < arg_num; i++) {
+ fe->arg_types[i] = arg_types[i];
+ }
+ for (i = arg_num - opt_arg_num, j = 0; i < arg_num; i++, j++) {
+ if (IS_NULL(opt_defaults)) return ONIGERR_INVALID_ARGUMENT;
+ if (fe->arg_types[i] == ONIG_TYPE_STRING) {
+ OnigValue* val;
+ UChar* ds;
+
+ val = opt_defaults + j;
+ ds = onigenc_strdup(enc, val->s.start, val->s.end);
+ CHECK_NULL_RETURN_MEMERR(ds);
+
+ fe->opt_defaults[i].s.start = ds;
+ fe->opt_defaults[i].s.end = ds + (val->s.end - val->s.start);
+ }
+ else {
+ fe->opt_defaults[i] = opt_defaults[j];
+ }
+ }
+
+ r = id;
+ return r;
+}
+
+static int
+get_callout_name_id_by_name(OnigEncoding enc, int is_not_single,
+ UChar* name, UChar* name_end, int* rid)
+{
+ int r;
+ CalloutNameEntry* e;
+
+ if (! is_allowed_callout_name(enc, name, name_end)) {
+ return ONIGERR_INVALID_CALLOUT_NAME;
+ }
+
+ e = callout_name_find(enc, is_not_single, name, name_end);
+ if (IS_NULL(e)) {
+ return ONIGERR_UNDEFINED_CALLOUT_NAME;
+ }
+
+ r = ONIG_NORMAL;
+ *rid = e->id;
+
+ return r;
+}
+
+extern OnigCalloutFunc
+onig_get_callout_start_func(regex_t* reg, int callout_num)
+{
+ /* If used for callouts of contents, return 0. */
+ CalloutListEntry* e;
+
+ e = onig_reg_callout_list_at(reg, callout_num);
+ CHECK_NULL_RETURN(e);
+ return e->start_func;
+}
+
+extern const UChar*
+onig_get_callout_tag_start(regex_t* reg, int callout_num)
+{
+ CalloutListEntry* e = onig_reg_callout_list_at(reg, callout_num);
+ CHECK_NULL_RETURN(e);
+ return e->tag_start;
+}
+
+extern const UChar*
+onig_get_callout_tag_end(regex_t* reg, int callout_num)
+{
+ CalloutListEntry* e = onig_reg_callout_list_at(reg, callout_num);
+ CHECK_NULL_RETURN(e);
+ return e->tag_end;
+}
+
+
+extern OnigCalloutType
+onig_get_callout_type_by_name_id(int name_id)
+{
+ if (name_id < 0 || name_id >= GlobalCalloutNameList->n)
+ return 0;
+
+ return GlobalCalloutNameList->v[name_id].type;
+}
+
+extern OnigCalloutFunc
+onig_get_callout_start_func_by_name_id(int name_id)
+{
+ if (name_id < 0 || name_id >= GlobalCalloutNameList->n)
+ return 0;
+
+ return GlobalCalloutNameList->v[name_id].start_func;
+}
+
+extern OnigCalloutFunc
+onig_get_callout_end_func_by_name_id(int name_id)
+{
+ if (name_id < 0 || name_id >= GlobalCalloutNameList->n)
+ return 0;
+
+ return GlobalCalloutNameList->v[name_id].end_func;
+}
+
+extern int
+onig_get_callout_in_by_name_id(int name_id)
+{
+ if (name_id < 0 || name_id >= GlobalCalloutNameList->n)
+ return 0;
+
+ return GlobalCalloutNameList->v[name_id].in;
+}
+
+static int
+get_callout_arg_num_by_name_id(int name_id)
+{
+ return GlobalCalloutNameList->v[name_id].arg_num;
+}
+
+static int
+get_callout_opt_arg_num_by_name_id(int name_id)
+{
+ return GlobalCalloutNameList->v[name_id].opt_arg_num;
+}
+
+static unsigned int
+get_callout_arg_type_by_name_id(int name_id, int index)
+{
+ return GlobalCalloutNameList->v[name_id].arg_types[index];
+}
+
+static OnigValue
+get_callout_opt_default_by_name_id(int name_id, int index)
+{
+ return GlobalCalloutNameList->v[name_id].opt_defaults[index];
+}
+
+extern UChar*
+onig_get_callout_name_by_name_id(int name_id)
+{
+ if (name_id < 0 || name_id >= GlobalCalloutNameList->n)
+ return 0;
+
+ return GlobalCalloutNameList->v[name_id].name;
+}
+
+extern int
+onig_global_callout_names_free(void)
+{
+ free_callout_func_list(GlobalCalloutNameList);
+ GlobalCalloutNameList = 0;
+
+ global_callout_name_table_free();
+ return ONIG_NORMAL;
+}
+
+
+typedef st_table CalloutTagTable;
+typedef intptr_t CalloutTagVal;
+
+#define CALLOUT_TAG_LIST_FLAG_TAG_EXIST (1<<0)
+
+static int
+i_callout_callout_list_set(UChar* key, CalloutTagVal e, void* arg)
+{
+ int num;
+ RegexExt* ext = (RegexExt* )arg;
+
+ num = (int )e - 1;
+ ext->callout_list[num].flag |= CALLOUT_TAG_LIST_FLAG_TAG_EXIST;
+ return ST_CONTINUE;
+}
+
+static int
+setup_ext_callout_list_values(regex_t* reg)
+{
+ int i, j;
+ RegexExt* ext;
+
+ ext = reg->extp;
+ if (IS_NOT_NULL(ext->tag_table)) {
+ onig_st_foreach((CalloutTagTable *)ext->tag_table, i_callout_callout_list_set,
+ (st_data_t )ext);
+ }
+
+ for (i = 0; i < ext->callout_num; i++) {
+ CalloutListEntry* e = ext->callout_list + i;
+ if (e->of == ONIG_CALLOUT_OF_NAME) {
+ for (j = 0; j < e->u.arg.num; j++) {
+ if (e->u.arg.types[j] == ONIG_TYPE_TAG) {
+ UChar* start;
+ UChar* end;
+ int num;
+ start = e->u.arg.vals[j].s.start;
+ end = e->u.arg.vals[j].s.end;
+ num = onig_get_callout_num_by_tag(reg, start, end);
+ if (num < 0) return num;
+ e->u.arg.vals[j].tag = num;
+ }
+ }
+ }
+ }
+
+ return ONIG_NORMAL;
+}
+
+extern int
+onig_callout_tag_is_exist_at_callout_num(regex_t* reg, int callout_num)
+{
+ RegexExt* ext = reg->extp;
+
+ if (IS_NULL(ext) || IS_NULL(ext->callout_list)) return 0;
+ if (callout_num > ext->callout_num) return 0;
+
+ return (ext->callout_list[callout_num].flag &
+ CALLOUT_TAG_LIST_FLAG_TAG_EXIST) != 0;
+}
+
+static int
+i_free_callout_tag_entry(UChar* key, CalloutTagVal e, void* arg ARG_UNUSED)
+{
+ xfree(key);
+ return ST_DELETE;
+}
+
+static int
+callout_tag_table_clear(CalloutTagTable* t)
+{
+ if (IS_NOT_NULL(t)) {
+ onig_st_foreach(t, i_free_callout_tag_entry, 0);
+ }
+ return 0;
+}
+
+extern int
+onig_callout_tag_table_free(void* table)
+{
+ CalloutTagTable* t = (CalloutTagTable* )table;
+
+ if (IS_NOT_NULL(t)) {
+ int r = callout_tag_table_clear(t);
+ if (r != 0) return r;
+
+ onig_st_free_table(t);
+ }
+
+ return 0;
+}
+
+extern int
+onig_get_callout_num_by_tag(regex_t* reg,
+ const UChar* tag, const UChar* tag_end)
+{
+ int r;
+ RegexExt* ext;
+ CalloutTagVal e;
+
+ ext = reg->extp;
+ if (IS_NULL(ext) || IS_NULL(ext->tag_table))
+ return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ r = onig_st_lookup_strend(ext->tag_table, tag, tag_end,
+ (HashDataType* )((void* )(&e)));
+ if (r == 0) return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+ return (int )e;
+}
+
+static CalloutTagVal
+callout_tag_find(CalloutTagTable* t, const UChar* name, const UChar* name_end)
+{
+ CalloutTagVal e;
+
+ e = -1;
+ if (IS_NOT_NULL(t)) {
+ onig_st_lookup_strend(t, name, name_end, (HashDataType* )((void* )(&e)));
+ }
+ return e;
+}
+
+static int
+callout_tag_table_new(CalloutTagTable** rt)
+{
+ CalloutTagTable* t;
+
+ *rt = 0;
+ t = onig_st_init_strend_table_with_size(INIT_TAG_NAMES_ALLOC_NUM);
+ CHECK_NULL_RETURN_MEMERR(t);
+
+ *rt = t;
+ return ONIG_NORMAL;
+}
+
+static int
+callout_tag_entry_raw(ScanEnv* env, CalloutTagTable* t, UChar* name,
+ UChar* name_end, CalloutTagVal entry_val)
+{
+ int r;
+ CalloutTagVal val;
+
+ if (name_end - name <= 0)
+ return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ val = callout_tag_find(t, name, name_end);
+ if (val >= 0) {
+ onig_scan_env_set_error_string(env, ONIGERR_MULTIPLEX_DEFINED_NAME,
+ name, name_end);
+ return ONIGERR_MULTIPLEX_DEFINED_NAME;
+ }
+
+ r = onig_st_insert_strend(t, name, name_end, (HashDataType )entry_val);
+ if (r < 0) return r;
+
+ return ONIG_NORMAL;
+}
+
+static int
+ext_ensure_tag_table(regex_t* reg)
+{
+ int r;
+ RegexExt* ext;
+ CalloutTagTable* t;
+
+ ext = onig_get_regex_ext(reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+
+ if (IS_NULL(ext->tag_table)) {
+ r = callout_tag_table_new(&t);
+ if (r != ONIG_NORMAL) return r;
+
+ ext->tag_table = t;
+ }
+
+ return ONIG_NORMAL;
+}
+
+static int
+callout_tag_entry(ScanEnv* env, regex_t* reg, UChar* name, UChar* name_end,
+ CalloutTagVal entry_val)
+{
+ int r;
+ RegexExt* ext;
+ CalloutListEntry* e;
+
+ r = ext_ensure_tag_table(reg);
+ if (r != ONIG_NORMAL) return r;
+
+ ext = onig_get_regex_ext(reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+ r = callout_tag_entry_raw(env, ext->tag_table, name, name_end, entry_val);
+
+ e = onig_reg_callout_list_at(reg, (int )entry_val);
+ CHECK_NULL_RETURN_MEMERR(e);
+ e->tag_start = name;
+ e->tag_end = name_end;
+
+ return r;
+}
+
+#endif /* USE_CALLOUT */
+
+
+#define INIT_SCANENV_MEMENV_ALLOC_SIZE 16
+
+static void
+scan_env_clear(ScanEnv* env)
+{
+ MEM_STATUS_CLEAR(env->cap_history);
+ MEM_STATUS_CLEAR(env->backtrack_mem);
+ MEM_STATUS_CLEAR(env->backrefed_mem);
+ env->error = (UChar* )NULL;
+ env->error_end = (UChar* )NULL;
+ env->num_call = 0;
+
+#ifdef USE_CALL
+ env->unset_addr_list = NULL;
+ env->has_call_zero = 0;
+#endif
+
+ env->num_mem = 0;
+ env->num_named = 0;
+ env->mem_alloc = 0;
+ env->mem_env_dynamic = (MemEnv* )NULL;
+
+ xmemset(env->mem_env_static, 0, sizeof(env->mem_env_static));
+
+ env->parse_depth = 0;
+#ifdef ONIG_DEBUG_PARSE
+ env->max_parse_depth = 0;
+#endif
+ env->backref_num = 0;
+ env->keep_num = 0;
+ env->id_num = 0;
+ env->save_alloc_num = 0;
+ env->saves = 0;
+}
+
+static int
+scan_env_add_mem_entry(ScanEnv* env)
+{
+ int i, need, alloc;
+ MemEnv* p;
+
+ need = env->num_mem + 1;
+ if (need > MaxCaptureNum && MaxCaptureNum != 0)
+ return ONIGERR_TOO_MANY_CAPTURES;
+
+ if (need >= SCANENV_MEMENV_SIZE) {
+ if (env->mem_alloc <= need) {
+ if (IS_NULL(env->mem_env_dynamic)) {
+ alloc = INIT_SCANENV_MEMENV_ALLOC_SIZE;
+ p = (MemEnv* )xmalloc(sizeof(MemEnv) * alloc);
+ CHECK_NULL_RETURN_MEMERR(p);
+ xmemcpy(p, env->mem_env_static, sizeof(env->mem_env_static));
+ }
+ else {
+ alloc = env->mem_alloc * 2;
+ p = (MemEnv* )xrealloc(env->mem_env_dynamic, sizeof(MemEnv) * alloc);
+ CHECK_NULL_RETURN_MEMERR(p);
+ }
+
+ for (i = env->num_mem + 1; i < alloc; i++) {
+ p[i].mem_node = NULL_NODE;
+ p[i].empty_repeat_node = NULL_NODE;
+ }
+
+ env->mem_env_dynamic = p;
+ env->mem_alloc = alloc;
+ }
+ }
+
+ env->num_mem++;
+ return env->num_mem;
+}
+
+static int
+scan_env_set_mem_node(ScanEnv* env, int num, Node* node)
+{
+ if (env->num_mem >= num)
+ SCANENV_MEMENV(env)[num].mem_node = node;
+ else
+ return ONIGERR_PARSER_BUG;
+ return 0;
+}
+
+static void
+node_free_body(Node* node)
+{
+ if (IS_NULL(node)) return ;
+
+ switch (NODE_TYPE(node)) {
+ case NODE_STRING:
+ if (STR_(node)->capacity != 0 &&
+ IS_NOT_NULL(STR_(node)->s) && STR_(node)->s != STR_(node)->buf) {
+ xfree(STR_(node)->s);
+ }
+ break;
+
+ case NODE_LIST:
+ case NODE_ALT:
+ onig_node_free(NODE_CAR(node));
+ node = NODE_CDR(node);
+ while (IS_NOT_NULL(node)) {
+ Node* next = NODE_CDR(node);
+ onig_node_free(NODE_CAR(node));
+ xfree(node);
+ node = next;
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ CClassNode* cc = CCLASS_(node);
+
+ if (cc->mbuf)
+ bbuf_free(cc->mbuf);
+ }
+ break;
+
+ case NODE_BACKREF:
+ if (IS_NOT_NULL(BACKREF_(node)->back_dynamic))
+ xfree(BACKREF_(node)->back_dynamic);
+ break;
+
+ case NODE_BAG:
+ if (NODE_BODY(node))
+ onig_node_free(NODE_BODY(node));
+
+ {
+ BagNode* en = BAG_(node);
+ if (en->type == BAG_IF_ELSE) {
+ onig_node_free(en->te.Then);
+ onig_node_free(en->te.Else);
+ }
+ }
+ break;
+
+ case NODE_QUANT:
+ if (NODE_BODY(node))
+ onig_node_free(NODE_BODY(node));
+ break;
+
+ case NODE_ANCHOR:
+ if (NODE_BODY(node))
+ onig_node_free(NODE_BODY(node));
+ if (IS_NOT_NULL(ANCHOR_(node)->lead_node))
+ onig_node_free(ANCHOR_(node)->lead_node);
+ break;
+
+ case NODE_CTYPE:
+ case NODE_CALL:
+ case NODE_GIMMICK:
+ break;
+ }
+}
+
+extern void
+onig_node_free(Node* node)
+{
+ if (IS_NULL(node)) return ;
+
+#ifdef DEBUG_NODE_FREE
+ fprintf(stderr, "onig_node_free: %p\n", node);
+#endif
+
+ node_free_body(node);
+ xfree(node);
+}
+
+static void
+cons_node_free_alone(Node* node)
+{
+ NODE_CAR(node) = 0;
+ NODE_CDR(node) = 0;
+ onig_node_free(node);
+}
+
+static Node*
+node_new(void)
+{
+ Node* node;
+
+ node = (Node* )xmalloc(sizeof(Node));
+ CHECK_NULL_RETURN(node);
+ xmemset(node, 0, sizeof(*node));
+
+#ifdef DEBUG_NODE_FREE
+ fprintf(stderr, "node_new: %p\n", node);
+#endif
+ return node;
+}
+
+extern int
+onig_node_copy(Node** rcopy, Node* from)
+{
+ int r;
+ Node* copy;
+
+ *rcopy = NULL_NODE;
+
+ switch (NODE_TYPE(from)) {
+ case NODE_LIST:
+ case NODE_ALT:
+ case NODE_ANCHOR:
+ /* These node's link to other nodes are processed by caller. */
+ break;
+ case NODE_STRING:
+ case NODE_CCLASS:
+ case NODE_CTYPE:
+ /* Fixed contents after copy. */
+ break;
+ default:
+ /* Not supported yet. */
+ return ONIGERR_TYPE_BUG;
+ break;
+ }
+
+ copy = node_new();
+ CHECK_NULL_RETURN_MEMERR(copy);
+ xmemcpy(copy, from, sizeof(*copy));
+
+ switch (NODE_TYPE(copy)) {
+ case NODE_STRING:
+ r = onig_node_str_set(copy, STR_(from)->s, STR_(from)->end, FALSE);
+ if (r != 0) {
+ err:
+ onig_node_free(copy);
+ return r;
+ }
+ break;
+
+ case NODE_CCLASS:
+ {
+ CClassNode *fcc, *tcc;
+
+ fcc = CCLASS_(from);
+ tcc = CCLASS_(copy);
+ if (IS_NOT_NULL(fcc->mbuf)) {
+ r = bbuf_clone(&(tcc->mbuf), fcc->mbuf);
+ if (r != 0) goto err;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ *rcopy = copy;
+ return ONIG_NORMAL;
+}
+
+
+static void
+initialize_cclass(CClassNode* cc)
+{
+ BITSET_CLEAR(cc->bs);
+ cc->flags = 0;
+ cc->mbuf = NULL;
+}
+
+static Node*
+node_new_cclass(void)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_CCLASS);
+ initialize_cclass(CCLASS_(node));
+ return node;
+}
+
+static Node*
+node_new_ctype(int type, int not, OnigOptionType options)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_CTYPE);
+ CTYPE_(node)->ctype = type;
+ CTYPE_(node)->not = not;
+ CTYPE_(node)->ascii_mode = OPTON_IS_ASCII_MODE_CTYPE(type, options);
+ return node;
+}
+
+static Node*
+node_new_anychar(OnigOptionType options)
+{
+ Node* node;
+
+ node = node_new_ctype(CTYPE_ANYCHAR, FALSE, options);
+ CHECK_NULL_RETURN(node);
+
+ if (OPTON_MULTILINE(options))
+ NODE_STATUS_ADD(node, MULTILINE);
+ return node;
+}
+
+static int
+node_new_no_newline(Node** node, ScanEnv* env)
+{
+ Node* n;
+
+ n = node_new_anychar(ONIG_OPTION_NONE);
+ CHECK_NULL_RETURN_MEMERR(n);
+ *node = n;
+ return 0;
+}
+
+static int
+node_new_true_anychar(Node** node)
+{
+ Node* n;
+
+ n = node_new_anychar(ONIG_OPTION_MULTILINE);
+ CHECK_NULL_RETURN_MEMERR(n);
+ *node = n;
+ return 0;
+}
+
+static Node*
+node_new_list(Node* left, Node* right)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_LIST);
+ NODE_CAR(node) = left;
+ NODE_CDR(node) = right;
+ return node;
+}
+
+extern Node*
+onig_node_new_list(Node* left, Node* right)
+{
+ return node_new_list(left, right);
+}
+
+extern Node*
+onig_node_new_alt(Node* left, Node* right)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_ALT);
+ NODE_CAR(node) = left;
+ NODE_CDR(node) = right;
+ return node;
+}
+
+static Node*
+make_list_or_alt(NodeType type, int n, Node* ns[])
+{
+ Node* r;
+
+ if (n <= 0) return NULL_NODE;
+
+ if (n == 1) {
+ r = node_new();
+ CHECK_NULL_RETURN(r);
+ NODE_SET_TYPE(r, type);
+ NODE_CAR(r) = ns[0];
+ NODE_CDR(r) = NULL_NODE;
+ }
+ else {
+ Node* right;
+
+ r = node_new();
+ CHECK_NULL_RETURN(r);
+
+ right = make_list_or_alt(type, n - 1, ns + 1);
+ if (IS_NULL(right)) {
+ onig_node_free(r);
+ return NULL_NODE;
+ }
+
+ NODE_SET_TYPE(r, type);
+ NODE_CAR(r) = ns[0];
+ NODE_CDR(r) = right;
+ }
+
+ return r;
+}
+
+static Node*
+make_list(int n, Node* ns[])
+{
+ return make_list_or_alt(NODE_LIST, n, ns);
+}
+
+static Node*
+make_alt(int n, Node* ns[])
+{
+ return make_list_or_alt(NODE_ALT, n, ns);
+}
+
+static Node*
+node_new_anchor(int type)
+{
+ Node* node;
+
+ node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_ANCHOR);
+ ANCHOR_(node)->type = type;
+ ANCHOR_(node)->char_min_len = 0;
+ ANCHOR_(node)->char_max_len = INFINITE_LEN;
+ ANCHOR_(node)->ascii_mode = 0;
+ ANCHOR_(node)->lead_node = NULL_NODE;
+ return node;
+}
+
+static Node*
+node_new_anchor_with_options(int type, OnigOptionType options)
+{
+ int ascii_mode;
+ Node* node;
+
+ node = node_new_anchor(type);
+ CHECK_NULL_RETURN(node);
+
+ ascii_mode = OPTON_WORD_ASCII(options) && IS_WORD_ANCHOR_TYPE(type) ? 1 : 0;
+ ANCHOR_(node)->ascii_mode = ascii_mode;
+
+ if (type == ANCR_TEXT_SEGMENT_BOUNDARY ||
+ type == ANCR_NO_TEXT_SEGMENT_BOUNDARY) {
+ if (OPTON_TEXT_SEGMENT_WORD(options))
+ NODE_STATUS_ADD(node, TEXT_SEGMENT_WORD);
+ }
+
+ return node;
+}
+
+static Node*
+node_new_backref(int back_num, int* backrefs, int by_name,
+#ifdef USE_BACKREF_WITH_LEVEL
+ int exist_level, int nest_level,
+#endif
+ ScanEnv* env)
+{
+ int i;
+ Node* node;
+
+ node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_BACKREF);
+ BACKREF_(node)->back_num = back_num;
+ BACKREF_(node)->back_dynamic = (int* )NULL;
+ if (by_name != 0)
+ NODE_STATUS_ADD(node, BY_NAME);
+
+ if (OPTON_IGNORECASE(env->options))
+ NODE_STATUS_ADD(node, IGNORECASE);
+
+#ifdef USE_BACKREF_WITH_LEVEL
+ if (exist_level != 0) {
+ NODE_STATUS_ADD(node, NEST_LEVEL);
+ BACKREF_(node)->nest_level = nest_level;
+ }
+#endif
+
+ for (i = 0; i < back_num; i++) {
+ if (backrefs[i] <= env->num_mem &&
+ IS_NULL(SCANENV_MEMENV(env)[backrefs[i]].mem_node)) {
+ NODE_STATUS_ADD(node, RECURSION); /* /...(\1).../ */
+ break;
+ }
+ }
+
+ if (back_num <= NODE_BACKREFS_SIZE) {
+ for (i = 0; i < back_num; i++)
+ BACKREF_(node)->back_static[i] = backrefs[i];
+ }
+ else {
+ int* p = (int* )xmalloc(sizeof(int) * back_num);
+ if (IS_NULL(p)) {
+ onig_node_free(node);
+ return NULL;
+ }
+ BACKREF_(node)->back_dynamic = p;
+ for (i = 0; i < back_num; i++)
+ p[i] = backrefs[i];
+ }
+
+ env->backref_num++;
+ return node;
+}
+
+static Node*
+node_new_backref_checker(int back_num, int* backrefs, int by_name,
+#ifdef USE_BACKREF_WITH_LEVEL
+ int exist_level, int nest_level,
+#endif
+ ScanEnv* env)
+{
+ Node* node;
+
+ node = node_new_backref(back_num, backrefs, by_name,
+#ifdef USE_BACKREF_WITH_LEVEL
+ exist_level, nest_level,
+#endif
+ env);
+ CHECK_NULL_RETURN(node);
+
+ NODE_STATUS_ADD(node, CHECKER);
+ return node;
+}
+
+#ifdef USE_CALL
+static Node*
+node_new_call(UChar* name, UChar* name_end, int gnum, int by_number)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_CALL);
+ CALL_(node)->by_number = by_number;
+ CALL_(node)->name = name;
+ CALL_(node)->name_end = name_end;
+ CALL_(node)->group_num = gnum;
+ CALL_(node)->entry_count = 1;
+ return node;
+}
+#endif
+
+static Node*
+node_new_quantifier(int lower, int upper, int by_number)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_QUANT);
+ QUANT_(node)->lower = lower;
+ QUANT_(node)->upper = upper;
+ QUANT_(node)->greedy = 1;
+ QUANT_(node)->emptiness = BODY_IS_NOT_EMPTY;
+ QUANT_(node)->head_exact = NULL_NODE;
+ QUANT_(node)->next_head_exact = NULL_NODE;
+ QUANT_(node)->include_referred = 0;
+ if (by_number != 0)
+ NODE_STATUS_ADD(node, BY_NUMBER);
+
+ return node;
+}
+
+static Node*
+node_new_bag(enum BagType type)
+{
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ NODE_SET_TYPE(node, NODE_BAG);
+ BAG_(node)->type = type;
+
+ switch (type) {
+ case BAG_MEMORY:
+ BAG_(node)->m.regnum = 0;
+ BAG_(node)->m.called_addr = -1;
+ BAG_(node)->m.entry_count = 1;
+ BAG_(node)->m.called_state = 0;
+ break;
+
+ case BAG_OPTION:
+ BAG_(node)->o.options = 0;
+ break;
+
+ case BAG_STOP_BACKTRACK:
+ break;
+
+ case BAG_IF_ELSE:
+ BAG_(node)->te.Then = 0;
+ BAG_(node)->te.Else = 0;
+ break;
+ }
+
+ BAG_(node)->opt_count = 0;
+ return node;
+}
+
+extern Node*
+onig_node_new_bag(enum BagType type)
+{
+ return node_new_bag(type);
+}
+
+static Node*
+node_new_bag_if_else(Node* cond, Node* Then, Node* Else)
+{
+ Node* n;
+ n = node_new_bag(BAG_IF_ELSE);
+ CHECK_NULL_RETURN(n);
+
+ NODE_BODY(n) = cond;
+ BAG_(n)->te.Then = Then;
+ BAG_(n)->te.Else = Else;
+ return n;
+}
+
+static Node*
+node_new_memory(int is_named)
+{
+ Node* node = node_new_bag(BAG_MEMORY);
+ CHECK_NULL_RETURN(node);
+ if (is_named != 0)
+ NODE_STATUS_ADD(node, NAMED_GROUP);
+
+ return node;
+}
+
+static Node*
+node_new_option(OnigOptionType option)
+{
+ Node* node = node_new_bag(BAG_OPTION);
+ CHECK_NULL_RETURN(node);
+ BAG_(node)->o.options = option;
+ return node;
+}
+
+static Node*
+node_new_group(Node* content)
+{
+ Node* node;
+
+ node = node_new();
+ CHECK_NULL_RETURN(node);
+ NODE_SET_TYPE(node, NODE_LIST);
+ NODE_CAR(node) = content;
+ NODE_CDR(node) = NULL_NODE;
+
+ return node;
+}
+
+static Node*
+node_drop_group(Node* group)
+{
+ Node* content;
+
+ content = NODE_CAR(group);
+ NODE_CAR(group) = NULL_NODE;
+ onig_node_free(group);
+ return content;
+}
+
+static int
+node_set_fail(Node* node)
+{
+ NODE_SET_TYPE(node, NODE_GIMMICK);
+ GIMMICK_(node)->type = GIMMICK_FAIL;
+ return ONIG_NORMAL;
+}
+
+static int
+node_new_fail(Node** node, ScanEnv* env)
+{
+ *node = node_new();
+ CHECK_NULL_RETURN_MEMERR(*node);
+
+ return node_set_fail(*node);
+}
+
+extern int
+onig_node_reset_fail(Node* node)
+{
+ node_free_body(node);
+ return node_set_fail(node);
+}
+
+static int
+node_new_save_gimmick(Node** node, enum SaveType save_type, ScanEnv* env)
+{
+ int id;
+
+ ID_ENTRY(env, id);
+
+ *node = node_new();
+ CHECK_NULL_RETURN_MEMERR(*node);
+
+ NODE_SET_TYPE(*node, NODE_GIMMICK);
+ GIMMICK_(*node)->id = id;
+ GIMMICK_(*node)->type = GIMMICK_SAVE;
+ GIMMICK_(*node)->detail_type = (int )save_type;
+
+ return ONIG_NORMAL;
+}
+
+static int
+node_new_update_var_gimmick(Node** node, enum UpdateVarType update_var_type,
+ int id, ScanEnv* env)
+{
+ *node = node_new();
+ CHECK_NULL_RETURN_MEMERR(*node);
+
+ NODE_SET_TYPE(*node, NODE_GIMMICK);
+ GIMMICK_(*node)->id = id;
+ GIMMICK_(*node)->type = GIMMICK_UPDATE_VAR;
+ GIMMICK_(*node)->detail_type = (int )update_var_type;
+
+ return ONIG_NORMAL;
+}
+
+static int
+node_new_keep(Node** node, ScanEnv* env)
+{
+ int r;
+
+ r = node_new_save_gimmick(node, SAVE_KEEP, env);
+ if (r != 0) return r;
+
+ env->keep_num++;
+ return ONIG_NORMAL;
+}
+
+#ifdef USE_CALLOUT
+
+extern void
+onig_free_reg_callout_list(int n, CalloutListEntry* list)
+{
+ int i;
+ int j;
+
+ if (IS_NULL(list)) return ;
+
+ for (i = 0; i < n; i++) {
+ if (list[i].of == ONIG_CALLOUT_OF_NAME) {
+ for (j = 0; j < list[i].u.arg.passed_num; j++) {
+ if (list[i].u.arg.types[j] == ONIG_TYPE_STRING) {
+ if (IS_NOT_NULL(list[i].u.arg.vals[j].s.start))
+ xfree(list[i].u.arg.vals[j].s.start);
+ }
+ }
+ }
+ else { /* ONIG_CALLOUT_OF_CONTENTS */
+ if (IS_NOT_NULL(list[i].u.content.start)) {
+ xfree((void* )list[i].u.content.start);
+ }
+ }
+ }
+
+ xfree(list);
+}
+
+extern CalloutListEntry*
+onig_reg_callout_list_at(regex_t* reg, int num)
+{
+ RegexExt* ext = reg->extp;
+ CHECK_NULL_RETURN(ext);
+
+ if (num <= 0 || num > ext->callout_num)
+ return 0;
+
+ num--;
+ return ext->callout_list + num;
+}
+
+static int
+reg_callout_list_entry(ScanEnv* env, int* rnum)
+{
+#define INIT_CALLOUT_LIST_NUM 3
+
+ int num;
+ CalloutListEntry* list;
+ CalloutListEntry* e;
+ RegexExt* ext;
+
+ ext = onig_get_regex_ext(env->reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+
+ if (IS_NULL(ext->callout_list)) {
+ list = (CalloutListEntry* )xmalloc(sizeof(*list) * INIT_CALLOUT_LIST_NUM);
+ CHECK_NULL_RETURN_MEMERR(list);
+
+ ext->callout_list = list;
+ ext->callout_list_alloc = INIT_CALLOUT_LIST_NUM;
+ ext->callout_num = 0;
+ }
+
+ num = ext->callout_num + 1;
+ if (num > ext->callout_list_alloc) {
+ int alloc = ext->callout_list_alloc * 2;
+ list = (CalloutListEntry* )xrealloc(ext->callout_list,
+ sizeof(CalloutListEntry) * alloc);
+ CHECK_NULL_RETURN_MEMERR(list);
+
+ ext->callout_list = list;
+ ext->callout_list_alloc = alloc;
+ }
+
+ e = ext->callout_list + (num - 1);
+
+ e->flag = 0;
+ e->of = 0;
+ e->in = ONIG_CALLOUT_OF_CONTENTS;
+ e->type = 0;
+ e->tag_start = 0;
+ e->tag_end = 0;
+ e->start_func = 0;
+ e->end_func = 0;
+ e->u.arg.num = 0;
+ e->u.arg.passed_num = 0;
+
+ ext->callout_num = num;
+ *rnum = num;
+ return ONIG_NORMAL;
+}
+
+static int
+node_new_callout(Node** node, OnigCalloutOf callout_of, int num, int id,
+ ScanEnv* env)
+{
+ *node = node_new();
+ CHECK_NULL_RETURN_MEMERR(*node);
+
+ NODE_SET_TYPE(*node, NODE_GIMMICK);
+ GIMMICK_(*node)->id = id;
+ GIMMICK_(*node)->num = num;
+ GIMMICK_(*node)->type = GIMMICK_CALLOUT;
+ GIMMICK_(*node)->detail_type = (int )callout_of;
+
+ return ONIG_NORMAL;
+}
+#endif
+
+static int
+make_text_segment(Node** node, ScanEnv* env)
+{
+ int r;
+ int i;
+ Node* x;
+ Node* ns[2];
+
+ /* \X == (?>\O(?:\Y\O)*) */
+
+ ns[1] = NULL_NODE;
+
+ r = ONIGERR_MEMORY;
+ ns[0] = node_new_anchor_with_options(ANCR_NO_TEXT_SEGMENT_BOUNDARY, env->options);
+ if (IS_NULL(ns[0])) goto err;
+
+ r = node_new_true_anychar(&ns[1]);
+ if (r != 0) goto err1;
+
+ x = make_list(2, ns);
+ if (IS_NULL(x)) goto err;
+ ns[0] = x;
+ ns[1] = NULL_NODE;
+
+ x = node_new_quantifier(0, INFINITE_REPEAT, TRUE);
+ if (IS_NULL(x)) goto err;
+
+ NODE_BODY(x) = ns[0];
+ ns[0] = NULL_NODE;
+ ns[1] = x;
+
+ r = node_new_true_anychar(&ns[0]);
+ if (r != 0) goto err1;
+
+ x = make_list(2, ns);
+ if (IS_NULL(x)) goto err;
+
+ ns[0] = x;
+ ns[1] = NULL_NODE;
+
+ x = node_new_bag(BAG_STOP_BACKTRACK);
+ if (IS_NULL(x)) goto err;
+
+ NODE_BODY(x) = ns[0];
+
+ *node = x;
+ return ONIG_NORMAL;
+
+ err:
+ r = ONIGERR_MEMORY;
+ err1:
+ for (i = 0; i < 2; i++) onig_node_free(ns[i]);
+ return r;
+}
+
+static int
+make_absent_engine(Node** node, int pre_save_right_id, Node* absent,
+ Node* step_one, int lower, int upper, int possessive,
+ int is_range_cutter, ScanEnv* env)
+{
+ int r;
+ int i;
+ int id;
+ Node* x;
+ Node* ns[4];
+
+ for (i = 0; i < 4; i++) ns[i] = NULL_NODE;
+
+ ns[1] = absent;
+ ns[3] = step_one; /* for err */
+ r = node_new_save_gimmick(&ns[0], SAVE_S, env);
+ if (r != 0) goto err;
+
+ id = GIMMICK_(ns[0])->id;
+ r = node_new_update_var_gimmick(&ns[2], UPDATE_VAR_RIGHT_RANGE_FROM_S_STACK,
+ id, env);
+ if (r != 0) goto err;
+
+ if (is_range_cutter != 0)
+ NODE_STATUS_ADD(ns[2], ABSENT_WITH_SIDE_EFFECTS);
+
+ r = node_new_fail(&ns[3], env);
+ if (r != 0) goto err;
+
+ x = make_list(4, ns);
+ if (IS_NULL(x)) goto err0;
+
+ ns[0] = x;
+ ns[1] = step_one;
+ ns[2] = ns[3] = NULL_NODE;
+
+ x = make_alt(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ ns[0] = x;
+
+ x = node_new_quantifier(lower, upper, FALSE);
+ if (IS_NULL(x)) goto err0;
+
+ NODE_BODY(x) = ns[0];
+ ns[0] = x;
+
+ if (possessive != 0) {
+ x = node_new_bag(BAG_STOP_BACKTRACK);
+ if (IS_NULL(x)) goto err0;
+
+ NODE_BODY(x) = ns[0];
+ ns[0] = x;
+ }
+
+ r = node_new_update_var_gimmick(&ns[1], UPDATE_VAR_RIGHT_RANGE_FROM_STACK,
+ pre_save_right_id, env);
+ if (r != 0) goto err;
+
+ r = node_new_fail(&ns[2], env);
+ if (r != 0) goto err;
+
+ x = make_list(2, ns + 1);
+ if (IS_NULL(x)) goto err0;
+
+ ns[1] = x; ns[2] = NULL_NODE;
+
+ x = make_alt(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ if (is_range_cutter != FALSE)
+ NODE_STATUS_ADD(x, SUPER);
+
+ *node = x;
+ return ONIG_NORMAL;
+
+ err0:
+ r = ONIGERR_MEMORY;
+ err:
+ for (i = 0; i < 4; i++) onig_node_free(ns[i]);
+ return r;
+}
+
+static int
+make_absent_tail(Node** node1, Node** node2, int pre_save_right_id,
+ ScanEnv* env)
+{
+ int r;
+ int id;
+ Node* save;
+ Node* x;
+ Node* ns[2];
+
+ *node1 = *node2 = NULL_NODE;
+ save = ns[0] = ns[1] = NULL_NODE;
+
+ r = node_new_save_gimmick(&save, SAVE_RIGHT_RANGE, env);
+ if (r != 0) goto err;
+
+ id = GIMMICK_(save)->id;
+ r = node_new_update_var_gimmick(&ns[0], UPDATE_VAR_RIGHT_RANGE_FROM_STACK,
+ id, env);
+ if (r != 0) goto err;
+
+ r = node_new_fail(&ns[1], env);
+ if (r != 0) goto err;
+
+ x = make_list(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ ns[0] = NULL_NODE; ns[1] = x;
+
+ r = node_new_update_var_gimmick(&ns[0], UPDATE_VAR_RIGHT_RANGE_FROM_STACK,
+ pre_save_right_id, env);
+ if (r != 0) goto err;
+
+ x = make_alt(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ *node1 = save;
+ *node2 = x;
+ return ONIG_NORMAL;
+
+ err0:
+ r = ONIGERR_MEMORY;
+ err:
+ onig_node_free(save);
+ onig_node_free(ns[0]);
+ onig_node_free(ns[1]);
+ return r;
+}
+
+static int
+make_range_clear(Node** node, ScanEnv* env)
+{
+ int r;
+ int id;
+ Node* save;
+ Node* x;
+ Node* ns[2];
+
+ *node = NULL_NODE;
+ save = ns[0] = ns[1] = NULL_NODE;
+
+ r = node_new_save_gimmick(&save, SAVE_RIGHT_RANGE, env);
+ if (r != 0) goto err;
+
+ id = GIMMICK_(save)->id;
+ r = node_new_update_var_gimmick(&ns[0], UPDATE_VAR_RIGHT_RANGE_FROM_STACK,
+ id, env);
+ if (r != 0) goto err;
+
+ r = node_new_fail(&ns[1], env);
+ if (r != 0) goto err;
+
+ x = make_list(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ ns[0] = NULL_NODE; ns[1] = x;
+
+#define ID_NOT_USED_DONT_CARE_ME 0
+
+ r = node_new_update_var_gimmick(&ns[0], UPDATE_VAR_RIGHT_RANGE_INIT,
+ ID_NOT_USED_DONT_CARE_ME, env);
+ if (r != 0) goto err;
+ NODE_STATUS_ADD(ns[0], ABSENT_WITH_SIDE_EFFECTS);
+
+ x = make_alt(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ NODE_STATUS_ADD(x, SUPER);
+
+ ns[0] = save;
+ ns[1] = x;
+ save = NULL_NODE;
+ x = make_list(2, ns);
+ if (IS_NULL(x)) goto err0;
+
+ *node = x;
+ return ONIG_NORMAL;
+
+ err0:
+ r = ONIGERR_MEMORY;
+ err:
+ onig_node_free(save);
+ onig_node_free(ns[0]);
+ onig_node_free(ns[1]);
+ return r;
+}
+
+static int
+is_simple_one_char_repeat(Node* node, Node** rquant, Node** rbody,
+ int* is_possessive, ScanEnv* env)
+{
+ Node* quant;
+ Node* body;
+
+ *rquant = *rbody = 0;
+ *is_possessive = 0;
+
+ if (NODE_TYPE(node) == NODE_QUANT) {
+ quant = node;
+ }
+ else {
+ if (NODE_TYPE(node) == NODE_BAG) {
+ BagNode* en = BAG_(node);
+ if (en->type == BAG_STOP_BACKTRACK) {
+ *is_possessive = 1;
+ quant = NODE_BAG_BODY(en);
+ if (NODE_TYPE(quant) != NODE_QUANT)
+ return 0;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+
+ if (QUANT_(quant)->greedy == 0)
+ return 0;
+
+ body = NODE_BODY(quant);
+ switch (NODE_TYPE(body)) {
+ case NODE_STRING:
+ {
+ int len;
+ StrNode* sn = STR_(body);
+ UChar *s = sn->s;
+
+ len = 0;
+ while (s < sn->end) {
+ s += enclen(env->enc, s);
+ len++;
+ }
+ if (len != 1)
+ return 0;
+ }
+
+ case NODE_CCLASS:
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+
+ if (node != quant) {
+ NODE_BODY(node) = 0;
+ onig_node_free(node);
+ }
+ NODE_BODY(quant) = NULL_NODE;
+ *rquant = quant;
+ *rbody = body;
+ return 1;
+}
+
+static int
+make_absent_tree_for_simple_one_char_repeat(Node** node, Node* absent, Node* quant,
+ Node* body, int possessive, ScanEnv* env)
+{
+ int r;
+ int i;
+ int id1;
+ int lower, upper;
+ Node* x;
+ Node* ns[4];
+
+ *node = NULL_NODE;
+ r = ONIGERR_MEMORY;
+ ns[0] = ns[1] = NULL_NODE;
+ ns[2] = body, ns[3] = absent;
+
+ lower = QUANT_(quant)->lower;
+ upper = QUANT_(quant)->upper;
+ onig_node_free(quant);
+
+ r = node_new_save_gimmick(&ns[0], SAVE_RIGHT_RANGE, env);
+ if (r != 0) goto err;
+
+ id1 = GIMMICK_(ns[0])->id;
+
+ r = make_absent_engine(&ns[1], id1, absent, body, lower, upper, possessive,
+ FALSE, env);
+ if (r != 0) goto err;
+
+ ns[2] = ns[3] = NULL_NODE;
+
+ r = node_new_update_var_gimmick(&ns[2], UPDATE_VAR_RIGHT_RANGE_FROM_STACK,
+ id1, env);
+ if (r != 0) goto err;
+
+ x = make_list(3, ns);
+ if (IS_NULL(x)) goto err0;
+
+ *node = x;
+ return ONIG_NORMAL;
+
+ err0:
+ r = ONIGERR_MEMORY;
+ err:
+ for (i = 0; i < 4; i++) onig_node_free(ns[i]);
+ return r;
+}
+
+static int
+make_absent_tree(Node** node, Node* absent, Node* expr, int is_range_cutter,
+ ScanEnv* env)
+{
+ int r;
+ int i;
+ int id1, id2;
+ int possessive;
+ Node* x;
+ Node* ns[7];
+
+ r = ONIGERR_MEMORY;
+ for (i = 0; i < 7; i++) ns[i] = NULL_NODE;
+ ns[4] = expr; ns[5] = absent;
+
+ if (is_range_cutter == 0) {
+ Node* quant;
+ Node* body;
+
+ if (expr == NULL_NODE) {
+ /* default expr \O* */
+ quant = node_new_quantifier(0, INFINITE_REPEAT, FALSE);
+ if (IS_NULL(quant)) goto err0;
+
+ r = node_new_true_anychar(&body);
+ if (r != 0) {
+ onig_node_free(quant);
+ goto err;
+ }
+ possessive = 0;
+ goto simple;
+ }
+ else {
+ if (is_simple_one_char_repeat(expr, &quant, &body, &possessive, env)) {
+ simple:
+ r = make_absent_tree_for_simple_one_char_repeat(node, absent, quant,
+ body, possessive, env);
+ if (r != 0) {
+ ns[4] = NULL_NODE;
+ onig_node_free(quant);
+ onig_node_free(body);
+ goto err;
+ }
+
+ return ONIG_NORMAL;
+ }
+ }
+ }
+
+ r = node_new_save_gimmick(&ns[0], SAVE_RIGHT_RANGE, env);
+ if (r != 0) goto err;
+
+ id1 = GIMMICK_(ns[0])->id;
+
+ r = node_new_save_gimmick(&ns[1], SAVE_S, env);
+ if (r != 0) goto err;
+
+ id2 = GIMMICK_(ns[1])->id;
+
+ r = node_new_true_anychar(&ns[3]);
+ if (r != 0) goto err;
+
+ possessive = 1;
+ r = make_absent_engine(&ns[2], id1, absent, ns[3], 0, INFINITE_REPEAT,
+ possessive, is_range_cutter, env);
+ if (r != 0) goto err;
+
+ ns[3] = NULL_NODE;
+ ns[5] = NULL_NODE;
+
+ r = node_new_update_var_gimmick(&ns[3], UPDATE_VAR_S_FROM_STACK, id2, env);
+ if (r != 0) goto err;
+
+ if (is_range_cutter != 0) {
+ x = make_list(4, ns);
+ if (IS_NULL(x)) goto err0;
+ }
+ else {
+ r = make_absent_tail(&ns[5], &ns[6], id1, env);
+ if (r != 0) goto err;
+
+ x = make_list(7, ns);
+ if (IS_NULL(x)) goto err0;
+ }
+
+ *node = x;
+ return ONIG_NORMAL;
+
+ err0:
+ r = ONIGERR_MEMORY;
+ err:
+ for (i = 0; i < 7; i++) onig_node_free(ns[i]);
+ return r;
+}
+
+extern int
+onig_node_str_cat(Node* node, const UChar* s, const UChar* end)
+{
+ int addlen = (int )(end - s);
+
+ if (addlen > 0) {
+ int len = (int )(STR_(node)->end - STR_(node)->s);
+
+ if (STR_(node)->capacity > 0 || (len + addlen > NODE_STRING_BUF_SIZE - 1)) {
+ UChar* p;
+ int capa = len + addlen + NODE_STRING_MARGIN;
+
+ if (capa <= STR_(node)->capacity) {
+ onig_strcpy(STR_(node)->s + len, s, end);
+ }
+ else {
+ if (STR_(node)->s == STR_(node)->buf)
+ p = strcat_capa_from_static(STR_(node)->s, STR_(node)->end,
+ s, end, capa);
+ else
+ p = strcat_capa(STR_(node)->s, STR_(node)->end, s, end, capa);
+
+ CHECK_NULL_RETURN_MEMERR(p);
+ STR_(node)->s = p;
+ STR_(node)->capacity = capa;
+ }
+ }
+ else {
+ onig_strcpy(STR_(node)->s + len, s, end);
+ }
+ STR_(node)->end = STR_(node)->s + len + addlen;
+ }
+
+ return 0;
+}
+
+extern int
+onig_node_str_set(Node* node, const UChar* s, const UChar* end, int need_free)
+{
+ onig_node_str_clear(node, need_free);
+ return onig_node_str_cat(node, s, end);
+}
+
+static int
+node_str_cat_char(Node* node, UChar c)
+{
+ UChar s[1];
+
+ s[0] = c;
+ return onig_node_str_cat(node, s, s + 1);
+}
+
+extern void
+onig_node_str_clear(Node* node, int need_free)
+{
+ if (need_free != 0 &&
+ STR_(node)->capacity != 0 &&
+ IS_NOT_NULL(STR_(node)->s) && STR_(node)->s != STR_(node)->buf) {
+ xfree(STR_(node)->s);
+ }
+
+ STR_(node)->flag = 0;
+ STR_(node)->s = STR_(node)->buf;
+ STR_(node)->end = STR_(node)->buf;
+ STR_(node)->capacity = 0;
+}
+
+static int
+node_set_str(Node* node, const UChar* s, const UChar* end)
+{
+ int r;
+
+ NODE_SET_TYPE(node, NODE_STRING);
+ STR_(node)->flag = 0;
+ STR_(node)->s = STR_(node)->buf;
+ STR_(node)->end = STR_(node)->buf;
+ STR_(node)->capacity = 0;
+
+ r = onig_node_str_cat(node, s, end);
+ return r;
+}
+
+static Node*
+node_new_str(const UChar* s, const UChar* end)
+{
+ int r;
+ Node* node = node_new();
+ CHECK_NULL_RETURN(node);
+
+ r = node_set_str(node, s, end);
+ if (r != 0) {
+ onig_node_free(node);
+ return NULL;
+ }
+
+ return node;
+}
+
+static int
+node_reset_str(Node* node, const UChar* s, const UChar* end)
+{
+ node_free_body(node);
+ return node_set_str(node, s, end);
+}
+
+extern int
+onig_node_reset_empty(Node* node)
+{
+ return node_reset_str(node, NULL, NULL);
+}
+
+extern Node*
+onig_node_new_str(const UChar* s, const UChar* end)
+{
+ return node_new_str(s, end);
+}
+
+static Node*
+node_new_str_with_options(const UChar* s, const UChar* end,
+ OnigOptionType options)
+{
+ Node* node;
+ node = node_new_str(s, end);
+
+ if (OPTON_IGNORECASE(options))
+ NODE_STATUS_ADD(node, IGNORECASE);
+
+ return node;
+}
+
+static Node*
+node_new_str_crude(UChar* s, UChar* end, OnigOptionType options)
+{
+ Node* node = node_new_str_with_options(s, end, options);
+ CHECK_NULL_RETURN(node);
+ NODE_STRING_SET_CRUDE(node);
+ return node;
+}
+
+static Node*
+node_new_empty(void)
+{
+ return node_new_str(NULL, NULL);
+}
+
+static Node*
+node_new_str_crude_char(UChar c, OnigOptionType options)
+{
+ int i;
+ UChar p[1];
+ Node* node;
+
+ p[0] = c;
+ node = node_new_str_crude(p, p + 1, options);
+
+ /* clear buf tail */
+ for (i = 1; i < NODE_STRING_BUF_SIZE; i++)
+ STR_(node)->buf[i] = '\0';
+
+ return node;
+}
+
+static Node*
+str_node_split_last_char(Node* node, OnigEncoding enc)
+{
+ const UChar *p;
+ Node* rn;
+ StrNode* sn;
+
+ sn = STR_(node);
+ rn = NULL_NODE;
+ if (sn->end > sn->s) {
+ p = onigenc_get_prev_char_head(enc, sn->s, sn->end);
+ if (p && p > sn->s) { /* can be split. */
+ rn = node_new_str(p, sn->end);
+ CHECK_NULL_RETURN(rn);
+
+ sn->end = (UChar* )p;
+ STR_(rn)->flag = sn->flag;
+ NODE_STATUS(rn) = NODE_STATUS(node);
+ }
+ }
+
+ return rn;
+}
+
+static int
+str_node_can_be_split(Node* node, OnigEncoding enc)
+{
+ StrNode* sn = STR_(node);
+ if (sn->end > sn->s) {
+ return ((enclen(enc, sn->s) < sn->end - sn->s) ? 1 : 0);
+ }
+ return 0;
+}
+
+static int
+scan_number(UChar** src, const UChar* end, OnigEncoding enc)
+{
+ int num, val;
+ OnigCodePoint c;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ num = 0;
+ while (! PEND) {
+ PFETCH(c);
+ if (IS_CODE_DIGIT_ASCII(enc, c)) {
+ val = (int )DIGITVAL(c);
+ if ((ONIG_INT_MAX - val) / 10 < num)
+ return -1; /* overflow */
+
+ num = num * 10 + val;
+ }
+ else {
+ PUNFETCH;
+ break;
+ }
+ }
+ *src = p;
+ return num;
+}
+
+static int
+scan_hexadecimal_number(UChar** src, UChar* end, int minlen, int maxlen,
+ OnigEncoding enc, OnigCodePoint* rcode)
+{
+ OnigCodePoint code;
+ OnigCodePoint c;
+ unsigned int val;
+ int n;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ code = 0;
+ n = 0;
+ while (! PEND && n < maxlen) {
+ PFETCH(c);
+ if (IS_CODE_XDIGIT_ASCII(enc, c)) {
+ n++;
+ val = (unsigned int )XDIGITVAL(enc, c);
+ if ((UINT_MAX - val) / 16UL < code)
+ return ONIGERR_TOO_BIG_NUMBER; /* overflow */
+
+ code = (code << 4) + val;
+ }
+ else {
+ PUNFETCH;
+ break;
+ }
+ }
+
+ if (n < minlen)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ *rcode = code;
+ *src = p;
+ return ONIG_NORMAL;
+}
+
+static int
+scan_octal_number(UChar** src, UChar* end, int minlen, int maxlen,
+ OnigEncoding enc, OnigCodePoint* rcode)
+{
+ OnigCodePoint code;
+ OnigCodePoint c;
+ unsigned int val;
+ int n;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ code = 0;
+ n = 0;
+ while (! PEND && n < maxlen) {
+ PFETCH(c);
+ if (IS_CODE_DIGIT_ASCII(enc, c) && c < '8') {
+ n++;
+ val = (unsigned int )ODIGITVAL(c);
+ if ((UINT_MAX - val) / 8UL < code)
+ return ONIGERR_TOO_BIG_NUMBER; /* overflow */
+
+ code = (code << 3) + val;
+ }
+ else {
+ PUNFETCH;
+ break;
+ }
+ }
+
+ if (n < minlen)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ *rcode = code;
+ *src = p;
+ return ONIG_NORMAL;
+}
+
+
+#define BB_WRITE_CODE_POINT(bbuf,pos,code) \
+ BB_WRITE(bbuf, pos, &(code), SIZE_CODE_POINT)
+
+/* data format:
+ [n][from-1][to-1][from-2][to-2] ... [from-n][to-n]
+ (all data size is OnigCodePoint)
+ */
+static int
+new_code_range(BBuf** pbuf)
+{
+#define INIT_MULTI_BYTE_RANGE_SIZE (SIZE_CODE_POINT * 5)
+ int r;
+ OnigCodePoint n;
+ BBuf* bbuf;
+
+ bbuf = *pbuf = (BBuf* )xmalloc(sizeof(BBuf));
+ CHECK_NULL_RETURN_MEMERR(bbuf);
+ r = BB_INIT(bbuf, INIT_MULTI_BYTE_RANGE_SIZE);
+ if (r != 0) {
+ xfree(bbuf);
+ *pbuf = 0;
+ return r;
+ }
+
+ n = 0;
+ BB_WRITE_CODE_POINT(bbuf, 0, n);
+ return 0;
+}
+
+static int
+add_code_range_to_buf(BBuf** pbuf, OnigCodePoint from, OnigCodePoint to)
+{
+ int r, inc_n, pos;
+ int low, high, bound, x;
+ OnigCodePoint n, *data;
+ BBuf* bbuf;
+
+ if (from > to) {
+ n = from; from = to; to = n;
+ }
+
+ if (IS_NULL(*pbuf)) {
+ r = new_code_range(pbuf);
+ if (r != 0) return r;
+ bbuf = *pbuf;
+ n = 0;
+ }
+ else {
+ bbuf = *pbuf;
+ GET_CODE_POINT(n, bbuf->p);
+ }
+ data = (OnigCodePoint* )(bbuf->p);
+ data++;
+
+ for (low = 0, bound = n; low < bound; ) {
+ x = (low + bound) >> 1;
+ if (from > data[x*2 + 1])
+ low = x + 1;
+ else
+ bound = x;
+ }
+
+ high = (to == ~((OnigCodePoint )0)) ? n : low;
+ for (bound = n; high < bound; ) {
+ x = (high + bound) >> 1;
+ if (to + 1 >= data[x*2])
+ high = x + 1;
+ else
+ bound = x;
+ }
+
+ inc_n = low + 1 - high;
+ if (n + inc_n > ONIG_MAX_MULTI_BYTE_RANGES_NUM)
+ return ONIGERR_TOO_MANY_MULTI_BYTE_RANGES;
+
+ if (inc_n != 1) {
+ if (from > data[low*2])
+ from = data[low*2];
+ if (to < data[(high - 1)*2 + 1])
+ to = data[(high - 1)*2 + 1];
+ }
+
+ if (inc_n != 0 && (OnigCodePoint )high < n) {
+ int from_pos = SIZE_CODE_POINT * (1 + high * 2);
+ int to_pos = SIZE_CODE_POINT * (1 + (low + 1) * 2);
+ int size = (n - high) * 2 * SIZE_CODE_POINT;
+
+ if (inc_n > 0) {
+ BB_MOVE_RIGHT(bbuf, from_pos, to_pos, size);
+ }
+ else {
+ BB_MOVE_LEFT_REDUCE(bbuf, from_pos, to_pos);
+ }
+ }
+
+ pos = SIZE_CODE_POINT * (1 + low * 2);
+ BB_ENSURE_SIZE(bbuf, pos + SIZE_CODE_POINT * 2);
+ BB_WRITE_CODE_POINT(bbuf, pos, from);
+ BB_WRITE_CODE_POINT(bbuf, pos + SIZE_CODE_POINT, to);
+ n += inc_n;
+ BB_WRITE_CODE_POINT(bbuf, 0, n);
+
+ return 0;
+}
+
+static int
+add_code_range(BBuf** pbuf, ScanEnv* env, OnigCodePoint from, OnigCodePoint to)
+{
+ if (from > to) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
+ return 0;
+ else
+ return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
+ }
+
+ return add_code_range_to_buf(pbuf, from, to);
+}
+
+static int
+not_code_range_buf(OnigEncoding enc, BBuf* bbuf, BBuf** pbuf)
+{
+ int r, i, n;
+ OnigCodePoint pre, from, *data, to = 0;
+
+ *pbuf = (BBuf* )NULL;
+ if (IS_NULL(bbuf)) {
+ set_all:
+ return SET_ALL_MULTI_BYTE_RANGE(enc, pbuf);
+ }
+
+ data = (OnigCodePoint* )(bbuf->p);
+ GET_CODE_POINT(n, data);
+ data++;
+ if (n <= 0) goto set_all;
+
+ r = 0;
+ pre = MBCODE_START_POS(enc);
+ for (i = 0; i < n; i++) {
+ from = data[i*2];
+ to = data[i*2+1];
+ if (pre <= from - 1) {
+ r = add_code_range_to_buf(pbuf, pre, from - 1);
+ if (r != 0) return r;
+ }
+ if (to == ~((OnigCodePoint )0)) break;
+ pre = to + 1;
+ }
+ if (to < ~((OnigCodePoint )0)) {
+ r = add_code_range_to_buf(pbuf, to + 1, ~((OnigCodePoint )0));
+ }
+ return r;
+}
+
+#define SWAP_BB_NOT(bbuf1, not1, bbuf2, not2) do {\
+ BBuf *tbuf; \
+ int tnot; \
+ tnot = not1; not1 = not2; not2 = tnot; \
+ tbuf = bbuf1; bbuf1 = bbuf2; bbuf2 = tbuf; \
+} while (0)
+
+static int
+or_code_range_buf(OnigEncoding enc, BBuf* bbuf1, int not1,
+ BBuf* bbuf2, int not2, BBuf** pbuf)
+{
+ int r;
+ OnigCodePoint i, n1, *data1;
+ OnigCodePoint from, to;
+
+ *pbuf = (BBuf* )NULL;
+ if (IS_NULL(bbuf1) && IS_NULL(bbuf2)) {
+ if (not1 != 0 || not2 != 0)
+ return SET_ALL_MULTI_BYTE_RANGE(enc, pbuf);
+ return 0;
+ }
+
+ r = 0;
+ if (IS_NULL(bbuf2))
+ SWAP_BB_NOT(bbuf1, not1, bbuf2, not2);
+
+ if (IS_NULL(bbuf1)) {
+ if (not1 != 0) {
+ return SET_ALL_MULTI_BYTE_RANGE(enc, pbuf);
+ }
+ else {
+ if (not2 == 0) {
+ return bbuf_clone(pbuf, bbuf2);
+ }
+ else {
+ return not_code_range_buf(enc, bbuf2, pbuf);
+ }
+ }
+ }
+
+ if (not1 != 0)
+ SWAP_BB_NOT(bbuf1, not1, bbuf2, not2);
+
+ data1 = (OnigCodePoint* )(bbuf1->p);
+ GET_CODE_POINT(n1, data1);
+ data1++;
+
+ if (not2 == 0 && not1 == 0) { /* 1 OR 2 */
+ r = bbuf_clone(pbuf, bbuf2);
+ }
+ else if (not1 == 0) { /* 1 OR (not 2) */
+ r = not_code_range_buf(enc, bbuf2, pbuf);
+ }
+ if (r != 0) return r;
+
+ for (i = 0; i < n1; i++) {
+ from = data1[i*2];
+ to = data1[i*2+1];
+ r = add_code_range_to_buf(pbuf, from, to);
+ if (r != 0) return r;
+ }
+ return 0;
+}
+
+static int
+and_code_range1(BBuf** pbuf, OnigCodePoint from1, OnigCodePoint to1,
+ OnigCodePoint* data, int n)
+{
+ int i, r;
+ OnigCodePoint from2, to2;
+
+ for (i = 0; i < n; i++) {
+ from2 = data[i*2];
+ to2 = data[i*2+1];
+ if (from2 < from1) {
+ if (to2 < from1) continue;
+ else {
+ from1 = to2 + 1;
+ }
+ }
+ else if (from2 <= to1) {
+ if (to2 < to1) {
+ if (from1 <= from2 - 1) {
+ r = add_code_range_to_buf(pbuf, from1, from2-1);
+ if (r != 0) return r;
+ }
+ from1 = to2 + 1;
+ }
+ else {
+ to1 = from2 - 1;
+ }
+ }
+ else {
+ from1 = from2;
+ }
+ if (from1 > to1) break;
+ }
+ if (from1 <= to1) {
+ r = add_code_range_to_buf(pbuf, from1, to1);
+ if (r != 0) return r;
+ }
+ return 0;
+}
+
+static int
+and_code_range_buf(BBuf* bbuf1, int not1, BBuf* bbuf2, int not2, BBuf** pbuf)
+{
+ int r;
+ OnigCodePoint i, j, n1, n2, *data1, *data2;
+ OnigCodePoint from, to, from1, to1, from2, to2;
+
+ *pbuf = (BBuf* )NULL;
+ if (IS_NULL(bbuf1)) {
+ if (not1 != 0 && IS_NOT_NULL(bbuf2)) /* not1 != 0 -> not2 == 0 */
+ return bbuf_clone(pbuf, bbuf2);
+ return 0;
+ }
+ else if (IS_NULL(bbuf2)) {
+ if (not2 != 0)
+ return bbuf_clone(pbuf, bbuf1);
+ return 0;
+ }
+
+ if (not1 != 0)
+ SWAP_BB_NOT(bbuf1, not1, bbuf2, not2);
+
+ data1 = (OnigCodePoint* )(bbuf1->p);
+ data2 = (OnigCodePoint* )(bbuf2->p);
+ GET_CODE_POINT(n1, data1);
+ GET_CODE_POINT(n2, data2);
+ data1++;
+ data2++;
+
+ if (not2 == 0 && not1 == 0) { /* 1 AND 2 */
+ for (i = 0; i < n1; i++) {
+ from1 = data1[i*2];
+ to1 = data1[i*2+1];
+ for (j = 0; j < n2; j++) {
+ from2 = data2[j*2];
+ to2 = data2[j*2+1];
+ if (from2 > to1) break;
+ if (to2 < from1) continue;
+ from = MAX(from1, from2);
+ to = MIN(to1, to2);
+ r = add_code_range_to_buf(pbuf, from, to);
+ if (r != 0) return r;
+ }
+ }
+ }
+ else if (not1 == 0) { /* 1 AND (not 2) */
+ for (i = 0; i < n1; i++) {
+ from1 = data1[i*2];
+ to1 = data1[i*2+1];
+ r = and_code_range1(pbuf, from1, to1, data2, n2);
+ if (r != 0) return r;
+ }
+ }
+
+ return 0;
+}
+
+static int
+and_cclass(CClassNode* dest, CClassNode* cc, OnigEncoding enc)
+{
+ int r, not1, not2;
+ BBuf *buf1, *buf2, *pbuf;
+ BitSetRef bsr1, bsr2;
+ BitSet bs1, bs2;
+
+ not1 = IS_NCCLASS_NOT(dest);
+ bsr1 = dest->bs;
+ buf1 = dest->mbuf;
+ not2 = IS_NCCLASS_NOT(cc);
+ bsr2 = cc->bs;
+ buf2 = cc->mbuf;
+
+ if (not1 != 0) {
+ bitset_invert_to(bsr1, bs1);
+ bsr1 = bs1;
+ }
+ if (not2 != 0) {
+ bitset_invert_to(bsr2, bs2);
+ bsr2 = bs2;
+ }
+ bitset_and(bsr1, bsr2);
+ if (bsr1 != dest->bs) {
+ bitset_copy(dest->bs, bsr1);
+ }
+ if (not1 != 0) {
+ bitset_invert(dest->bs);
+ }
+
+ if (! ONIGENC_IS_SINGLEBYTE(enc)) {
+ if (not1 != 0 && not2 != 0) {
+ r = or_code_range_buf(enc, buf1, 0, buf2, 0, &pbuf);
+ }
+ else {
+ r = and_code_range_buf(buf1, not1, buf2, not2, &pbuf);
+ if (r == 0 && not1 != 0) {
+ BBuf *tbuf;
+ r = not_code_range_buf(enc, pbuf, &tbuf);
+ if (r != 0) {
+ bbuf_free(pbuf);
+ return r;
+ }
+ bbuf_free(pbuf);
+ pbuf = tbuf;
+ }
+ }
+ if (r != 0) return r;
+
+ dest->mbuf = pbuf;
+ bbuf_free(buf1);
+ return r;
+ }
+ return 0;
+}
+
+static int
+or_cclass(CClassNode* dest, CClassNode* cc, OnigEncoding enc)
+{
+ int r, not1, not2;
+ BBuf *buf1, *buf2, *pbuf;
+ BitSetRef bsr1, bsr2;
+ BitSet bs1, bs2;
+
+ not1 = IS_NCCLASS_NOT(dest);
+ bsr1 = dest->bs;
+ buf1 = dest->mbuf;
+ not2 = IS_NCCLASS_NOT(cc);
+ bsr2 = cc->bs;
+ buf2 = cc->mbuf;
+
+ if (not1 != 0) {
+ bitset_invert_to(bsr1, bs1);
+ bsr1 = bs1;
+ }
+ if (not2 != 0) {
+ bitset_invert_to(bsr2, bs2);
+ bsr2 = bs2;
+ }
+ bitset_or(bsr1, bsr2);
+ if (bsr1 != dest->bs) {
+ bitset_copy(dest->bs, bsr1);
+ }
+ if (not1 != 0) {
+ bitset_invert(dest->bs);
+ }
+
+ if (! ONIGENC_IS_SINGLEBYTE(enc)) {
+ if (not1 != 0 && not2 != 0) {
+ r = and_code_range_buf(buf1, 0, buf2, 0, &pbuf);
+ }
+ else {
+ r = or_code_range_buf(enc, buf1, not1, buf2, not2, &pbuf);
+ if (r == 0 && not1 != 0) {
+ BBuf *tbuf;
+ r = not_code_range_buf(enc, pbuf, &tbuf);
+ if (r != 0) {
+ bbuf_free(pbuf);
+ return r;
+ }
+ bbuf_free(pbuf);
+ pbuf = tbuf;
+ }
+ }
+ if (r != 0) return r;
+
+ dest->mbuf = pbuf;
+ bbuf_free(buf1);
+ return r;
+ }
+ else
+ return 0;
+}
+
+static OnigCodePoint
+conv_backslash_value(OnigCodePoint c, ScanEnv* env)
+{
+ if (IS_SYNTAX_OP(env->syntax, ONIG_SYN_OP_ESC_CONTROL_CHARS)) {
+ switch (c) {
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\007';
+ case 'b': return '\010';
+ case 'e': return '\033';
+ case 'v':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ESC_V_VTAB))
+ return '\v';
+ break;
+
+ default:
+ break;
+ }
+ }
+ return c;
+}
+
+static int
+is_invalid_quantifier_target(Node* node)
+{
+ switch (NODE_TYPE(node)) {
+ case NODE_ANCHOR:
+ case NODE_GIMMICK:
+ return 1;
+ break;
+
+ case NODE_BAG:
+ /* allow enclosed elements */
+ /* return is_invalid_quantifier_target(NODE_BODY(node)); */
+ break;
+
+ case NODE_LIST:
+ do {
+ if (! is_invalid_quantifier_target(NODE_CAR(node))) return 0;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ return 0;
+ break;
+
+ case NODE_ALT:
+ do {
+ if (is_invalid_quantifier_target(NODE_CAR(node))) return 1;
+ } while (IS_NOT_NULL(node = NODE_CDR(node)));
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* ?:0, *:1, +:2, ??:3, *?:4, +?:5 */
+static int
+quantifier_type_num(QuantNode* q)
+{
+ if (q->greedy) {
+ if (q->lower == 0) {
+ if (q->upper == 1) return 0;
+ else if (IS_INFINITE_REPEAT(q->upper)) return 1;
+ }
+ else if (q->lower == 1) {
+ if (IS_INFINITE_REPEAT(q->upper)) return 2;
+ }
+ }
+ else {
+ if (q->lower == 0) {
+ if (q->upper == 1) return 3;
+ else if (IS_INFINITE_REPEAT(q->upper)) return 4;
+ }
+ else if (q->lower == 1) {
+ if (IS_INFINITE_REPEAT(q->upper)) return 5;
+ }
+ }
+ return -1;
+}
+
+
+enum ReduceType {
+ RQ_ASIS = 0, /* as is */
+ RQ_DEL = 1, /* delete parent */
+ RQ_A, /* to '*' */
+ RQ_AQ, /* to '*?' */
+ RQ_QQ, /* to '??' */
+ RQ_P_QQ, /* to '+)??' */
+ RQ_PQ_Q /* to '+?)?' */
+};
+
+static enum ReduceType ReduceTypeTable[6][6] = {
+ {RQ_DEL, RQ_A, RQ_A, RQ_QQ, RQ_AQ, RQ_ASIS}, /* '?' */
+ {RQ_DEL, RQ_DEL, RQ_DEL, RQ_P_QQ, RQ_P_QQ, RQ_DEL}, /* '*' */
+ {RQ_A, RQ_A, RQ_DEL, RQ_ASIS, RQ_P_QQ, RQ_DEL}, /* '+' */
+ {RQ_DEL, RQ_AQ, RQ_AQ, RQ_DEL, RQ_AQ, RQ_AQ}, /* '??' */
+ {RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL}, /* '*?' */
+ {RQ_ASIS, RQ_PQ_Q, RQ_DEL, RQ_AQ, RQ_AQ, RQ_DEL} /* '+?' */
+};
+
+extern int
+onig_reduce_nested_quantifier(Node* pnode)
+{
+ int pnum, cnum;
+ QuantNode *p, *c;
+ Node* cnode;
+
+ cnode = NODE_BODY(pnode);
+
+ p = QUANT_(pnode);
+ c = QUANT_(cnode);
+ pnum = quantifier_type_num(p);
+ cnum = quantifier_type_num(c);
+ if (pnum < 0 || cnum < 0) {
+ if (p->lower == p->upper && c->lower == c->upper) {
+ int n = onig_positive_int_multiply(p->lower, c->lower);
+ if (n < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+
+ p->lower = p->upper = n;
+ NODE_BODY(pnode) = NODE_BODY(cnode);
+ goto remove_cnode;
+ }
+
+ return 0;
+ }
+
+ switch(ReduceTypeTable[cnum][pnum]) {
+ case RQ_DEL:
+ *pnode = *cnode;
+ goto remove_cnode;
+ break;
+ case RQ_A:
+ NODE_BODY(pnode) = NODE_BODY(cnode);
+ p->lower = 0; p->upper = INFINITE_REPEAT; p->greedy = 1;
+ goto remove_cnode;
+ break;
+ case RQ_AQ:
+ NODE_BODY(pnode) = NODE_BODY(cnode);
+ p->lower = 0; p->upper = INFINITE_REPEAT; p->greedy = 0;
+ goto remove_cnode;
+ break;
+ case RQ_QQ:
+ NODE_BODY(pnode) = NODE_BODY(cnode);
+ p->lower = 0; p->upper = 1; p->greedy = 0;
+ goto remove_cnode;
+ break;
+ case RQ_P_QQ:
+ p->lower = 0; p->upper = 1; p->greedy = 0;
+ c->lower = 1; c->upper = INFINITE_REPEAT; c->greedy = 1;
+ break;
+ case RQ_PQ_Q:
+ p->lower = 0; p->upper = 1; p->greedy = 1;
+ c->lower = 1; c->upper = INFINITE_REPEAT; c->greedy = 0;
+ break;
+ case RQ_ASIS:
+ break;
+ }
+
+ return 0;
+
+ remove_cnode:
+ NODE_BODY(cnode) = NULL_NODE;
+ onig_node_free(cnode);
+ return 0;
+}
+
+static int
+node_new_general_newline(Node** node, ScanEnv* env)
+{
+ int r;
+ int dlen, alen;
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN * 2];
+ Node* crnl;
+ Node* ncc;
+ Node* x;
+ CClassNode* cc;
+
+ dlen = ONIGENC_CODE_TO_MBC(env->enc, 0x0d, buf);
+ if (dlen < 0) return dlen;
+ alen = ONIGENC_CODE_TO_MBC(env->enc, NEWLINE_CODE, buf + dlen);
+ if (alen < 0) return alen;
+
+ crnl = node_new_str_crude(buf, buf + dlen + alen, ONIG_OPTION_NONE);
+ CHECK_NULL_RETURN_MEMERR(crnl);
+
+ ncc = node_new_cclass();
+ if (IS_NULL(ncc)) goto err2;
+
+ cc = CCLASS_(ncc);
+ if (dlen == 1) {
+ bitset_set_range(cc->bs, NEWLINE_CODE, 0x0d);
+ }
+ else {
+ r = add_code_range(&(cc->mbuf), env, NEWLINE_CODE, 0x0d);
+ if (r != 0) {
+ err1:
+ onig_node_free(ncc);
+ err2:
+ onig_node_free(crnl);
+ return ONIGERR_MEMORY;
+ }
+ }
+
+ if (ONIGENC_IS_UNICODE_ENCODING(env->enc)) {
+ r = add_code_range(&(cc->mbuf), env, 0x85, 0x85);
+ if (r != 0) goto err1;
+ r = add_code_range(&(cc->mbuf), env, 0x2028, 0x2029);
+ if (r != 0) goto err1;
+ }
+
+ x = node_new_bag_if_else(crnl, NULL_NODE, ncc);
+ if (IS_NULL(x)) goto err1;
+
+ *node = x;
+ return 0;
+}
+
+enum TokenSyms {
+ TK_EOT = 0, /* end of token */
+ TK_CRUDE_BYTE = 1,
+ TK_CHAR,
+ TK_STRING,
+ TK_CODE_POINT,
+ TK_ANYCHAR,
+ TK_CHAR_TYPE,
+ TK_BACKREF,
+ TK_CALL,
+ TK_ANCHOR,
+ TK_REPEAT,
+ TK_INTERVAL,
+ TK_ANYCHAR_ANYTIME, /* SQL '%' == .* */
+ TK_ALT,
+ TK_SUBEXP_OPEN,
+ TK_SUBEXP_CLOSE,
+ TK_OPEN_CC,
+ TK_QUOTE_OPEN,
+ TK_CHAR_PROPERTY, /* \p{...}, \P{...} */
+ TK_KEEP, /* \K */
+ TK_GENERAL_NEWLINE, /* \R */
+ TK_NO_NEWLINE, /* \N */
+ TK_TRUE_ANYCHAR, /* \O */
+ TK_TEXT_SEGMENT, /* \X */
+
+ /* in cc */
+ TK_CC_CLOSE,
+ TK_CC_RANGE,
+ TK_CC_POSIX_BRACKET_OPEN,
+ TK_CC_AND, /* && */
+ TK_CC_OPEN_CC /* [ */
+};
+
+typedef struct {
+ enum TokenSyms type;
+ int escaped;
+ int base; /* is number: 8, 16 (used in [....]) */
+ UChar* backp;
+ union {
+ UChar* s;
+ UChar byte;
+ OnigCodePoint code;
+ int anchor;
+ int subtype;
+ struct {
+ int lower;
+ int upper;
+ int greedy;
+ int possessive;
+ } repeat;
+ struct {
+ int num;
+ int ref1;
+ int* refs;
+ int by_name;
+#ifdef USE_BACKREF_WITH_LEVEL
+ int exist_level;
+ int level; /* \k<name+n> */
+#endif
+ } backref;
+ struct {
+ UChar* name;
+ UChar* name_end;
+ int gnum;
+ int by_number;
+ } call;
+ struct {
+ int ctype;
+ int not;
+ } prop;
+ } u;
+} PToken;
+
+
+static int
+fetch_interval(UChar** src, UChar* end, PToken* tok, ScanEnv* env)
+{
+ int low, up, syn_allow, non_low = 0;
+ int r = 0;
+ OnigCodePoint c;
+ OnigEncoding enc = env->enc;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ syn_allow = IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_INVALID_INTERVAL);
+
+ if (PEND) {
+ if (syn_allow)
+ return 1; /* "....{" : OK! */
+ else
+ return ONIGERR_END_PATTERN_AT_LEFT_BRACE; /* "....{" syntax error */
+ }
+
+ if (! syn_allow) {
+ c = PPEEK;
+ if (c == ')' || c == '(' || c == '|') {
+ return ONIGERR_END_PATTERN_AT_LEFT_BRACE;
+ }
+ }
+
+ low = scan_number(&p, end, env->enc);
+ if (low < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+ if (low > ONIG_MAX_REPEAT_NUM)
+ return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+
+ if (p == *src) { /* can't read low */
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV)) {
+ /* allow {,n} as {0,n} */
+ low = 0;
+ non_low = 1;
+ }
+ else
+ goto invalid;
+ }
+
+ if (PEND) goto invalid;
+ PFETCH(c);
+ if (c == ',') {
+ UChar* prev = p;
+ up = scan_number(&p, end, env->enc);
+ if (up < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+ if (up > ONIG_MAX_REPEAT_NUM)
+ return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
+
+ if (p == prev) {
+ if (non_low != 0)
+ goto invalid;
+ up = INFINITE_REPEAT; /* {n,} : {n,infinite} */
+ }
+ }
+ else {
+ if (non_low != 0)
+ goto invalid;
+
+ PUNFETCH;
+ up = low; /* {n} : exact n times */
+ r = 2; /* fixed */
+ }
+
+ if (PEND) goto invalid;
+ PFETCH(c);
+ if (IS_SYNTAX_OP(env->syntax, ONIG_SYN_OP_ESC_BRACE_INTERVAL)) {
+ if (c != MC_ESC(env->syntax) || PEND) goto invalid;
+ PFETCH(c);
+ }
+ if (c != '}') goto invalid;
+
+ if (!IS_INFINITE_REPEAT(up) && low > up) {
+ /* {n,m}+ supported case */
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL))
+ return ONIGERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE;
+
+ tok->u.repeat.possessive = 1;
+ {
+ int tmp;
+ tmp = low; low = up; up = tmp;
+ }
+ }
+ else
+ tok->u.repeat.possessive = 0;
+
+ tok->type = TK_INTERVAL;
+ tok->u.repeat.lower = low;
+ tok->u.repeat.upper = up;
+ *src = p;
+ return r; /* 0: normal {n,m}, 2: fixed {n} */
+
+ invalid:
+ if (syn_allow) {
+ /* *src = p; */ /* !!! Don't do this line !!! */
+ return 1; /* OK */
+ }
+ else
+ return ONIGERR_INVALID_REPEAT_RANGE_PATTERN;
+}
+
+/* \M-, \C-, \c, or \... */
+static int
+fetch_escaped_value(UChar** src, UChar* end, ScanEnv* env, OnigCodePoint* val)
+{
+ int v;
+ OnigCodePoint c;
+ OnigEncoding enc = env->enc;
+ UChar* p = *src;
+
+ if (PEND) return ONIGERR_END_PATTERN_AT_ESCAPE;
+
+ PFETCH_S(c);
+ switch (c) {
+ case 'M':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META)) {
+ if (PEND) return ONIGERR_END_PATTERN_AT_META;
+ PFETCH_S(c);
+ if (c != '-') return ONIGERR_META_CODE_SYNTAX;
+ if (PEND) return ONIGERR_END_PATTERN_AT_META;
+ PFETCH_S(c);
+ if (c == MC_ESC(env->syntax)) {
+ v = fetch_escaped_value(&p, end, env, &c);
+ if (v < 0) return v;
+ }
+ c = ((c & 0xff) | 0x80);
+ }
+ else
+ goto backslash;
+ break;
+
+ case 'C':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL)) {
+ if (PEND) return ONIGERR_END_PATTERN_AT_CONTROL;
+ PFETCH_S(c);
+ if (c != '-') return ONIGERR_CONTROL_CODE_SYNTAX;
+ goto control;
+ }
+ else
+ goto backslash;
+
+ case 'c':
+ if (IS_SYNTAX_OP(env->syntax, ONIG_SYN_OP_ESC_C_CONTROL)) {
+ control:
+ if (PEND) return ONIGERR_END_PATTERN_AT_CONTROL;
+ PFETCH_S(c);
+ if (c == '?') {
+ c = 0177;
+ }
+ else {
+ if (c == MC_ESC(env->syntax)) {
+ v = fetch_escaped_value(&p, end, env, &c);
+ if (v < 0) return v;
+ }
+ c &= 0x9f;
+ }
+ break;
+ }
+ /* fall through */
+
+ default:
+ {
+ backslash:
+ c = conv_backslash_value(c, env);
+ }
+ break;
+ }
+
+ *src = p;
+ *val = c;
+ return 0;
+}
+
+static int fetch_token(PToken* tok, UChar** src, UChar* end, ScanEnv* env);
+
+static OnigCodePoint
+get_name_end_code_point(OnigCodePoint start)
+{
+ switch (start) {
+ case '<': return (OnigCodePoint )'>'; break;
+ case '\'': return (OnigCodePoint )'\''; break;
+ case '(': return (OnigCodePoint )')'; break;
+ default:
+ break;
+ }
+
+ return (OnigCodePoint )0;
+}
+
+enum REF_NUM {
+ IS_NOT_NUM = 0,
+ IS_ABS_NUM = 1,
+ IS_REL_NUM = 2
+};
+
+#ifdef USE_BACKREF_WITH_LEVEL
+/*
+ \k<name+n>, \k<name-n>
+ \k<num+n>, \k<num-n>
+ \k<-num+n>, \k<-num-n>
+ \k<+num+n>, \k<+num-n>
+*/
+static int
+fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
+ UChar** rname_end, ScanEnv* env,
+ int* rback_num, int* rlevel, enum REF_NUM* num_type)
+{
+ int r, sign, exist_level;
+ int digit_count;
+ OnigCodePoint end_code;
+ OnigCodePoint c = 0;
+ OnigEncoding enc = env->enc;
+ UChar *name_end;
+ UChar *pnum_head;
+ UChar *p = *src;
+ PFETCH_READY;
+
+ *rback_num = 0;
+ exist_level = 0;
+ *num_type = IS_NOT_NUM;
+ sign = 1;
+ pnum_head = *src;
+
+ end_code = get_name_end_code_point(start_code);
+
+ digit_count = 0;
+ name_end = end;
+ r = 0;
+ if (PEND) {
+ return ONIGERR_EMPTY_GROUP_NAME;
+ }
+ else {
+ PFETCH(c);
+ if (c == end_code)
+ return ONIGERR_EMPTY_GROUP_NAME;
+
+ if (IS_CODE_DIGIT_ASCII(enc, c)) {
+ *num_type = IS_ABS_NUM;
+ digit_count++;
+ }
+ else if (c == '-') {
+ *num_type = IS_REL_NUM;
+ sign = -1;
+ pnum_head = p;
+ }
+ else if (c == '+') {
+ *num_type = IS_REL_NUM;
+ sign = 1;
+ pnum_head = p;
+ }
+ else if (!ONIGENC_IS_CODE_WORD(enc, c)) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ }
+ }
+
+ while (!PEND) {
+ name_end = p;
+ PFETCH(c);
+ if (c == end_code || c == ')' || c == '+' || c == '-') {
+ if (*num_type != IS_NOT_NUM && digit_count == 0)
+ r = ONIGERR_INVALID_GROUP_NAME;
+ break;
+ }
+
+ if (*num_type != IS_NOT_NUM) {
+ if (IS_CODE_DIGIT_ASCII(enc, c)) {
+ digit_count++;
+ }
+ else {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ *num_type = IS_NOT_NUM;
+ }
+ }
+ else if (!ONIGENC_IS_CODE_WORD(enc, c)) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ }
+ }
+
+ if (r == 0 && c != end_code) {
+ if (c == '+' || c == '-') {
+ int level;
+ int flag = (c == '-' ? -1 : 1);
+
+ if (PEND) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ goto end;
+ }
+ PFETCH(c);
+ if (! IS_CODE_DIGIT_ASCII(enc, c)) goto err;
+ PUNFETCH;
+ level = scan_number(&p, end, enc);
+ if (level < 0) return ONIGERR_TOO_BIG_NUMBER;
+ *rlevel = (level * flag);
+ exist_level = 1;
+
+ if (!PEND) {
+ PFETCH(c);
+ if (c == end_code)
+ goto end;
+ }
+ }
+
+ err:
+ name_end = end;
+ err2:
+ r = ONIGERR_INVALID_GROUP_NAME;
+ }
+
+ end:
+ if (r == 0) {
+ if (*num_type != IS_NOT_NUM) {
+ *rback_num = scan_number(&pnum_head, name_end, enc);
+ if (*rback_num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ else if (*rback_num == 0) {
+ if (*num_type == IS_REL_NUM)
+ goto err2;
+ }
+
+ *rback_num *= sign;
+ }
+
+ *rname_end = name_end;
+ *src = p;
+ return (exist_level ? 1 : 0);
+ }
+ else {
+ onig_scan_env_set_error_string(env, r, *src, name_end);
+ return r;
+ }
+}
+#endif /* USE_BACKREF_WITH_LEVEL */
+
+/*
+ ref: 0 -> define name (don't allow number name)
+ 1 -> reference name (allow number name)
+*/
+static int
+fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
+ UChar** rname_end, ScanEnv* env, int* rback_num,
+ enum REF_NUM* num_type, int is_ref)
+{
+ int r, sign;
+ int digit_count;
+ OnigCodePoint end_code;
+ OnigCodePoint c = 0;
+ OnigEncoding enc = env->enc;
+ UChar *name_end;
+ UChar *pnum_head;
+ UChar *p = *src;
+
+ *rback_num = 0;
+
+ end_code = get_name_end_code_point(start_code);
+
+ digit_count = 0;
+ name_end = end;
+ pnum_head = *src;
+ r = 0;
+ *num_type = IS_NOT_NUM;
+ sign = 1;
+ if (PEND) {
+ return ONIGERR_EMPTY_GROUP_NAME;
+ }
+ else {
+ PFETCH_S(c);
+ if (c == end_code)
+ return ONIGERR_EMPTY_GROUP_NAME;
+
+ if (IS_CODE_DIGIT_ASCII(enc, c)) {
+ if (is_ref == TRUE)
+ *num_type = IS_ABS_NUM;
+ else {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ }
+ digit_count++;
+ }
+ else if (c == '-') {
+ if (is_ref == TRUE) {
+ *num_type = IS_REL_NUM;
+ sign = -1;
+ pnum_head = p;
+ }
+ else {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ }
+ }
+ else if (c == '+') {
+ if (is_ref == TRUE) {
+ *num_type = IS_REL_NUM;
+ sign = 1;
+ pnum_head = p;
+ }
+ else {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ }
+ }
+ else if (!ONIGENC_IS_CODE_WORD(enc, c)) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ }
+ }
+
+ if (r == 0) {
+ while (!PEND) {
+ name_end = p;
+ PFETCH_S(c);
+ if (c == end_code || c == ')') {
+ if (*num_type != IS_NOT_NUM && digit_count == 0)
+ r = ONIGERR_INVALID_GROUP_NAME;
+ break;
+ }
+
+ if (*num_type != IS_NOT_NUM) {
+ if (IS_CODE_DIGIT_ASCII(enc, c)) {
+ digit_count++;
+ }
+ else {
+ if (!ONIGENC_IS_CODE_WORD(enc, c))
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ else
+ r = ONIGERR_INVALID_GROUP_NAME;
+
+ *num_type = IS_NOT_NUM;
+ }
+ }
+ else {
+ if (!ONIGENC_IS_CODE_WORD(enc, c)) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ }
+ }
+ }
+
+ if (c != end_code) {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ goto err;
+ }
+
+ if (*num_type != IS_NOT_NUM) {
+ *rback_num = scan_number(&pnum_head, name_end, enc);
+ if (*rback_num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ else if (*rback_num == 0) {
+ if (*num_type == IS_REL_NUM) {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ goto err;
+ }
+ }
+
+ *rback_num *= sign;
+ }
+
+ *rname_end = name_end;
+ *src = p;
+ return 0;
+ }
+ else {
+ while (!PEND) {
+ name_end = p;
+ PFETCH_S(c);
+ if (c == end_code || c == ')')
+ break;
+ }
+ if (PEND)
+ name_end = end;
+
+ err:
+ onig_scan_env_set_error_string(env, r, *src, name_end);
+ return r;
+ }
+}
+
+static void
+CC_ESC_WARN(ScanEnv* env, UChar *c)
+{
+ if (onig_warn == onig_null_warn) return ;
+
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_WARN_CC_OP_NOT_ESCAPED) &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_BACKSLASH_ESCAPE_IN_CC)) {
+ UChar buf[WARN_BUFSIZE];
+ onig_snprintf_with_pattern(buf, WARN_BUFSIZE, env->enc,
+ env->pattern, env->pattern_end,
+ (UChar* )"character class has '%s' without escape",
+ c);
+ (*onig_warn)((char* )buf);
+ }
+}
+
+static void
+CLOSE_BRACKET_WITHOUT_ESC_WARN(ScanEnv* env, UChar* c)
+{
+ if (onig_warn == onig_null_warn) return ;
+
+ if (IS_SYNTAX_BV((env)->syntax, ONIG_SYN_WARN_CC_OP_NOT_ESCAPED)) {
+ UChar buf[WARN_BUFSIZE];
+ onig_snprintf_with_pattern(buf, WARN_BUFSIZE, (env)->enc,
+ (env)->pattern, (env)->pattern_end,
+ (UChar* )"regular expression has '%s' without escape", c);
+ (*onig_warn)((char* )buf);
+ }
+}
+
+static UChar*
+find_str_position(OnigCodePoint s[], int n, UChar* from, UChar* to,
+ UChar **next, OnigEncoding enc)
+{
+ int i;
+ OnigCodePoint x;
+ UChar *q;
+ UChar *p = from;
+
+ while (p < to) {
+ x = ONIGENC_MBC_TO_CODE(enc, p, to);
+ q = p + enclen(enc, p);
+ if (x == s[0]) {
+ for (i = 1; i < n && q < to; i++) {
+ x = ONIGENC_MBC_TO_CODE(enc, q, to);
+ if (x != s[i]) break;
+ q += enclen(enc, q);
+ }
+ if (i >= n) {
+ if (IS_NOT_NULL(next))
+ *next = q;
+ return p;
+ }
+ }
+ p = q;
+ }
+ return NULL_UCHARP;
+}
+
+static int
+str_exist_check_with_esc(OnigCodePoint s[], int n, UChar* from, UChar* to,
+ OnigCodePoint bad, OnigEncoding enc, OnigSyntaxType* syn)
+{
+ int i, in_esc;
+ OnigCodePoint x;
+ UChar *q;
+ UChar *p = from;
+
+ in_esc = 0;
+ while (p < to) {
+ if (in_esc) {
+ in_esc = 0;
+ p += enclen(enc, p);
+ }
+ else {
+ x = ONIGENC_MBC_TO_CODE(enc, p, to);
+ q = p + enclen(enc, p);
+ if (x == s[0]) {
+ for (i = 1; i < n && q < to; i++) {
+ x = ONIGENC_MBC_TO_CODE(enc, q, to);
+ if (x != s[i]) break;
+ q += enclen(enc, q);
+ }
+ if (i >= n) return 1;
+ p += enclen(enc, p);
+ }
+ else {
+ x = ONIGENC_MBC_TO_CODE(enc, p, to);
+ if (x == bad) return 0;
+ else if (x == MC_ESC(syn)) in_esc = 1;
+ p = q;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+fetch_token_in_cc(PToken* tok, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ OnigCodePoint code;
+ OnigCodePoint c, c2;
+ OnigSyntaxType* syn = env->syntax;
+ OnigEncoding enc = env->enc;
+ UChar* prev;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ if (PEND) {
+ tok->type = TK_EOT;
+ return tok->type;
+ }
+
+ PFETCH(c);
+ tok->type = TK_CHAR;
+ tok->base = 0;
+ tok->u.code = c;
+ tok->escaped = 0;
+
+ if (c == ']') {
+ tok->type = TK_CC_CLOSE;
+ }
+ else if (c == '-') {
+ tok->type = TK_CC_RANGE;
+ }
+ else if (c == MC_ESC(syn)) {
+ if (! IS_SYNTAX_BV(syn, ONIG_SYN_BACKSLASH_ESCAPE_IN_CC))
+ goto end;
+
+ if (PEND) return ONIGERR_END_PATTERN_AT_ESCAPE;
+
+ PFETCH(c);
+ tok->escaped = 1;
+ tok->u.code = c;
+ switch (c) {
+ case 'w':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_WORD;
+ tok->u.prop.not = 0;
+ break;
+ case 'W':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_WORD;
+ tok->u.prop.not = 1;
+ break;
+ case 'd':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_DIGIT;
+ tok->u.prop.not = 0;
+ break;
+ case 'D':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_DIGIT;
+ tok->u.prop.not = 1;
+ break;
+ case 's':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_SPACE;
+ tok->u.prop.not = 0;
+ break;
+ case 'S':
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_SPACE;
+ tok->u.prop.not = 1;
+ break;
+ case 'h':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_H_XDIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_XDIGIT;
+ tok->u.prop.not = 0;
+ break;
+ case 'H':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_H_XDIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_XDIGIT;
+ tok->u.prop.not = 1;
+ break;
+
+ case 'p':
+ case 'P':
+ if (PEND) break;
+
+ c2 = PPEEK;
+ if (c2 == '{' &&
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
+ PINC;
+ tok->type = TK_CHAR_PROPERTY;
+ tok->u.prop.not = c == 'P';
+
+ if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
+ PFETCH(c2);
+ if (c2 == '^') {
+ tok->u.prop.not = tok->u.prop.not == 0;
+ }
+ else
+ PUNFETCH;
+ }
+ }
+ break;
+
+ case 'o':
+ if (PEND) break;
+
+ prev = p;
+ if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_O_BRACE_OCTAL)) {
+ PINC;
+ r = scan_octal_number(&p, end, 0, 11, enc, &code);
+ if (r < 0) return r;
+ if (!PEND) {
+ c2 = PPEEK;
+ if (IS_CODE_DIGIT_ASCII(enc, c2))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if (p > prev + enclen(enc, prev) && !PEND && (PPEEK_IS('}'))) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->base = 8;
+ tok->u.code = code;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
+ }
+ break;
+
+ case 'x':
+ if (PEND) break;
+
+ prev = p;
+ if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_BRACE_HEX8)) {
+ PINC;
+ r = scan_hexadecimal_number(&p, end, 0, 8, enc, &code);
+ if (r < 0) return r;
+ if (!PEND) {
+ c2 = PPEEK;
+ if (IS_CODE_XDIGIT_ASCII(enc, c2))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if (p > prev + enclen(enc, prev) && !PEND && (PPEEK_IS('}'))) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = code;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
+ }
+ else if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_HEX2)) {
+ r = scan_hexadecimal_number(&p, end, 0, 2, enc, &code);
+ if (r < 0) return r;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CRUDE_BYTE;
+ tok->base = 16;
+ tok->u.byte = (UChar )code;
+ }
+ break;
+
+ case 'u':
+ if (PEND) break;
+
+ prev = p;
+ if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_U_HEX4)) {
+ r = scan_hexadecimal_number(&p, end, 4, 4, enc, &code);
+ if (r < 0) return r;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = code;
+ }
+ break;
+
+ case '0':
+ case '1': case '2': case '3': case '4': case '5': case '6': case '7':
+ if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_OCTAL3)) {
+ PUNFETCH;
+ prev = p;
+ r = scan_octal_number(&p, end, 0, 3, enc, &code);
+ if (r < 0) return r;
+ if (code >= 256) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CRUDE_BYTE;
+ tok->base = 8;
+ tok->u.byte = (UChar )code;
+ }
+ break;
+
+ default:
+ PUNFETCH;
+ r = fetch_escaped_value(&p, end, env, &c2);
+ if (r < 0) return r;
+ if (tok->u.code != c2) {
+ tok->u.code = c2;
+ tok->type = TK_CODE_POINT;
+ }
+ break;
+ }
+ }
+ else if (c == '[') {
+ if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_POSIX_BRACKET) && (PPEEK_IS(':'))) {
+ OnigCodePoint send[] = { (OnigCodePoint )':', (OnigCodePoint )']' };
+ tok->backp = p; /* point at '[' is read */
+ PINC;
+ if (str_exist_check_with_esc(send, 2, p, end,
+ (OnigCodePoint )']', enc, syn)) {
+ tok->type = TK_CC_POSIX_BRACKET_OPEN;
+ }
+ else {
+ PUNFETCH;
+ goto cc_in_cc;
+ }
+ }
+ else {
+ cc_in_cc:
+ if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_CCLASS_SET_OP)) {
+ tok->type = TK_CC_OPEN_CC;
+ }
+ else {
+ CC_ESC_WARN(env, (UChar* )"[");
+ }
+ }
+ }
+ else if (c == '&') {
+ if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_CCLASS_SET_OP) &&
+ !PEND && (PPEEK_IS('&'))) {
+ PINC;
+ tok->type = TK_CC_AND;
+ }
+ }
+
+ end:
+ *src = p;
+ return tok->type;
+}
+
+static int
+fetch_token(PToken* tok, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ OnigCodePoint code;
+ OnigCodePoint c;
+ OnigEncoding enc = env->enc;
+ OnigSyntaxType* syn = env->syntax;
+ UChar* prev;
+ UChar* p = *src;
+ PFETCH_READY;
+
+ start:
+ if (PEND) {
+ tok->type = TK_EOT;
+ return tok->type;
+ }
+
+ tok->type = TK_STRING;
+ tok->base = 0;
+ tok->backp = p;
+
+ PFETCH(c);
+ if (IS_MC_ESC_CODE(c, syn)) {
+ if (PEND) return ONIGERR_END_PATTERN_AT_ESCAPE;
+
+ tok->backp = p;
+ PFETCH(c);
+
+ tok->u.code = c;
+ tok->escaped = 1;
+ switch (c) {
+ case '*':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_ASTERISK_ZERO_INF)) break;
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 0;
+ tok->u.repeat.upper = INFINITE_REPEAT;
+ goto greedy_check;
+ break;
+
+ case '+':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_PLUS_ONE_INF)) break;
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 1;
+ tok->u.repeat.upper = INFINITE_REPEAT;
+ goto greedy_check;
+ break;
+
+ case '?':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_QMARK_ZERO_ONE)) break;
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 0;
+ tok->u.repeat.upper = 1;
+ greedy_check:
+ tok->u.repeat.possessive = 0;
+ greedy_check2:
+ if (!PEND && PPEEK_IS('?') &&
+ IS_SYNTAX_OP(syn, ONIG_SYN_OP_QMARK_NON_GREEDY) &&
+ tok->u.repeat.possessive == 0) {
+ PFETCH(c);
+ tok->u.repeat.greedy = 0;
+ tok->u.repeat.possessive = 0;
+ }
+ else {
+ possessive_check:
+ tok->u.repeat.greedy = 1;
+ if (!PEND && PPEEK_IS('+') &&
+ ((IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT) &&
+ tok->type != TK_INTERVAL) ||
+ (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL) &&
+ tok->type == TK_INTERVAL)) &&
+ tok->u.repeat.possessive == 0) {
+ PFETCH(c);
+ tok->u.repeat.possessive = 1;
+ }
+ }
+ break;
+
+ case '{':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_BRACE_INTERVAL)) break;
+ r = fetch_interval(&p, end, tok, env);
+ if (r < 0) return r; /* error */
+ if (r == 0) goto greedy_check2;
+ else if (r == 2) { /* {n} */
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
+ goto possessive_check;
+
+ goto greedy_check2;
+ }
+ /* r == 1 : normal char */
+ break;
+
+ case '|':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_VBAR_ALT)) break;
+ tok->type = TK_ALT;
+ break;
+
+ case '(':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_LPAREN_SUBEXP)) break;
+ tok->type = TK_SUBEXP_OPEN;
+ break;
+
+ case ')':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_LPAREN_SUBEXP)) break;
+ tok->type = TK_SUBEXP_CLOSE;
+ break;
+
+ case 'w':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_W_WORD)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_WORD;
+ tok->u.prop.not = 0;
+ break;
+
+ case 'W':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_W_WORD)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_WORD;
+ tok->u.prop.not = 1;
+ break;
+
+ case 'b':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_B_WORD_BOUND)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_WORD_BOUNDARY;
+ break;
+
+ case 'B':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_B_WORD_BOUND)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_NO_WORD_BOUNDARY;
+ break;
+
+ case 'y':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_TEXT_SEGMENT_BOUNDARY;
+ break;
+
+ case 'Y':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_NO_TEXT_SEGMENT_BOUNDARY;
+ break;
+
+#ifdef USE_WORD_BEGIN_END
+ case '<':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_WORD_BEGIN;
+ break;
+
+ case '>':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.anchor = ANCR_WORD_END;
+ break;
+#endif
+
+ case 's':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_S_WHITE_SPACE)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_SPACE;
+ tok->u.prop.not = 0;
+ break;
+
+ case 'S':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_S_WHITE_SPACE)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_SPACE;
+ tok->u.prop.not = 1;
+ break;
+
+ case 'd':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_D_DIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_DIGIT;
+ tok->u.prop.not = 0;
+ break;
+
+ case 'D':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_D_DIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_DIGIT;
+ tok->u.prop.not = 1;
+ break;
+
+ case 'h':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_H_XDIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_XDIGIT;
+ tok->u.prop.not = 0;
+ break;
+
+ case 'H':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_H_XDIGIT)) break;
+ tok->type = TK_CHAR_TYPE;
+ tok->u.prop.ctype = ONIGENC_CTYPE_XDIGIT;
+ tok->u.prop.not = 1;
+ break;
+
+ case 'K':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP)) break;
+ tok->type = TK_KEEP;
+ break;
+
+ case 'R':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE)) break;
+ tok->type = TK_GENERAL_NEWLINE;
+ break;
+
+ case 'N':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT)) break;
+ tok->type = TK_NO_NEWLINE;
+ break;
+
+ case 'O':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT)) break;
+ tok->type = TK_TRUE_ANYCHAR;
+ break;
+
+ case 'X':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT)) break;
+ tok->type = TK_TEXT_SEGMENT;
+ break;
+
+ case 'A':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR)) break;
+ begin_buf:
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = ANCR_BEGIN_BUF;
+ break;
+
+ case 'Z':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = ANCR_SEMI_END_BUF;
+ break;
+
+ case 'z':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_AZ_BUF_ANCHOR)) break;
+ end_buf:
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = ANCR_END_BUF;
+ break;
+
+ case 'G':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_CAPITAL_G_BEGIN_ANCHOR)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = ANCR_BEGIN_POSITION;
+ break;
+
+ case '`':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR)) break;
+ goto begin_buf;
+ break;
+
+ case '\'':
+ if (! IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR)) break;
+ goto end_buf;
+ break;
+
+ case 'o':
+ if (PEND) break;
+
+ prev = p;
+ if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_O_BRACE_OCTAL)) {
+ PINC;
+ r = scan_octal_number(&p, end, 0, 11, enc, &code);
+ if (r < 0) return r;
+ if (!PEND) {
+ if (IS_CODE_DIGIT_ASCII(enc, PPEEK))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if ((p > prev + enclen(enc, prev)) && !PEND && PPEEK_IS('}')) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->u.code = code;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
+ }
+ break;
+
+ case 'x':
+ if (PEND) break;
+
+ prev = p;
+ if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_BRACE_HEX8)) {
+ PINC;
+ r = scan_hexadecimal_number(&p, end, 0, 8, enc, &code);
+ if (r < 0) return r;
+ if (!PEND) {
+ if (IS_CODE_XDIGIT_ASCII(enc, PPEEK))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if ((p > prev + enclen(enc, prev)) && !PEND && PPEEK_IS('}')) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->u.code = code;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
+ }
+ else if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_HEX2)) {
+ r = scan_hexadecimal_number(&p, end, 0, 2, enc, &code);
+ if (r < 0) return r;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CRUDE_BYTE;
+ tok->base = 16;
+ tok->u.byte = (UChar )code;
+ }
+ break;
+
+ case 'u':
+ if (PEND) break;
+
+ prev = p;
+ if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_U_HEX4)) {
+ r = scan_hexadecimal_number(&p, end, 4, 4, enc, &code);
+ if (r < 0) return r;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = code;
+ }
+ break;
+
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ PUNFETCH;
+ prev = p;
+ r = scan_number(&p, end, enc);
+ if (r < 0 || r > ONIG_MAX_BACKREF_NUM) {
+ goto skip_backref;
+ }
+
+ if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_DECIMAL_BACKREF) &&
+ (r <= env->num_mem || r <= 9)) { /* This spec. from GNU regex */
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ if (r > env->num_mem || IS_NULL(SCANENV_MEMENV(env)[r].mem_node))
+ return ONIGERR_INVALID_BACKREF;
+ }
+
+ tok->type = TK_BACKREF;
+ tok->u.backref.num = 1;
+ tok->u.backref.ref1 = r;
+ tok->u.backref.by_name = 0;
+#ifdef USE_BACKREF_WITH_LEVEL
+ tok->u.backref.exist_level = 0;
+#endif
+ break;
+ }
+
+ skip_backref:
+ if (c == '8' || c == '9') {
+ /* normal char */
+ p = prev; PINC;
+ break;
+ }
+
+ p = prev;
+ /* fall through */
+ case '0':
+ if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_OCTAL3)) {
+ prev = p;
+ r = scan_octal_number(&p, end, 0, (c == '0' ? 2:3), enc, &code);
+ if (r < 0 || r >= 256) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ code = 0; /* but, it's not error */
+ }
+ tok->type = TK_CRUDE_BYTE;
+ tok->base = 8;
+ tok->u.byte = (UChar )code;
+ }
+ else if (c != '0') {
+ PINC;
+ }
+ break;
+
+ case 'k':
+ if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_K_NAMED_BACKREF)) {
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ UChar* name_end;
+ int* backs;
+ int back_num;
+ enum REF_NUM num_type;
+
+ prev = p;
+
+#ifdef USE_BACKREF_WITH_LEVEL
+ name_end = NULL_UCHARP; /* no need. escape gcc warning. */
+ r = fetch_name_with_level((OnigCodePoint )c, &p, end, &name_end,
+ env, &back_num, &tok->u.backref.level, &num_type);
+ if (r == 1) tok->u.backref.exist_level = 1;
+ else tok->u.backref.exist_level = 0;
+#else
+ r = fetch_name(c, &p, end, &name_end, env, &back_num, &num_type, TRUE);
+#endif
+ if (r < 0) return r;
+
+ if (num_type != IS_NOT_NUM) {
+ if (num_type == IS_REL_NUM) {
+ back_num = backref_rel_to_abs(back_num, env);
+ }
+ if (back_num <= 0)
+ return ONIGERR_INVALID_BACKREF;
+
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ if (back_num > env->num_mem ||
+ IS_NULL(SCANENV_MEMENV(env)[back_num].mem_node))
+ return ONIGERR_INVALID_BACKREF;
+ }
+ tok->type = TK_BACKREF;
+ tok->u.backref.by_name = 0;
+ tok->u.backref.num = 1;
+ tok->u.backref.ref1 = back_num;
+ }
+ else {
+ int num = name_to_group_numbers(env, prev, name_end, &backs);
+ if (num <= 0) {
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ int i;
+ for (i = 0; i < num; i++) {
+ if (backs[i] > env->num_mem ||
+ IS_NULL(SCANENV_MEMENV(env)[backs[i]].mem_node))
+ return ONIGERR_INVALID_BACKREF;
+ }
+ }
+
+ tok->type = TK_BACKREF;
+ tok->u.backref.by_name = 1;
+ if (num == 1) {
+ tok->u.backref.num = 1;
+ tok->u.backref.ref1 = backs[0];
+ }
+ else {
+ tok->u.backref.num = num;
+ tok->u.backref.refs = backs;
+ }
+ }
+ }
+ else
+ PUNFETCH;
+ }
+ break;
+
+#ifdef USE_CALL
+ case 'g':
+ if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_G_SUBEXP_CALL)) {
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ int gnum;
+ UChar* name_end;
+ enum REF_NUM num_type;
+
+ prev = p;
+ r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env,
+ &gnum, &num_type, TRUE);
+ if (r < 0) return r;
+
+ if (num_type != IS_NOT_NUM) {
+ if (num_type == IS_REL_NUM) {
+ gnum = backref_rel_to_abs(gnum, env);
+ if (gnum < 0) {
+ onig_scan_env_set_error_string(env, ONIGERR_UNDEFINED_NAME_REFERENCE,
+ prev, name_end);
+ return ONIGERR_UNDEFINED_GROUP_REFERENCE;
+ }
+ }
+ tok->u.call.by_number = 1;
+ tok->u.call.gnum = gnum;
+ }
+ else {
+ tok->u.call.by_number = 0;
+ tok->u.call.gnum = 0;
+ }
+
+ tok->type = TK_CALL;
+ tok->u.call.name = prev;
+ tok->u.call.name_end = name_end;
+ }
+ else
+ PUNFETCH;
+ }
+ break;
+#endif
+
+ case 'Q':
+ if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE)) {
+ tok->type = TK_QUOTE_OPEN;
+ }
+ break;
+
+ case 'p':
+ case 'P':
+ if (!PEND && PPEEK_IS('{') &&
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
+ PINC;
+ tok->type = TK_CHAR_PROPERTY;
+ tok->u.prop.not = c == 'P';
+
+ if (!PEND &&
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
+ PFETCH(c);
+ if (c == '^') {
+ tok->u.prop.not = tok->u.prop.not == 0;
+ }
+ else
+ PUNFETCH;
+ }
+ }
+ break;
+
+ default:
+ {
+ OnigCodePoint c2;
+
+ PUNFETCH;
+ r = fetch_escaped_value(&p, end, env, &c2);
+ if (r < 0) return r;
+ if (tok->u.code != c2) {
+ tok->type = TK_CODE_POINT;
+ tok->u.code = c2;
+ }
+ else { /* string */
+ p = tok->backp + enclen(enc, tok->backp);
+ }
+ }
+ break;
+ }
+ }
+ else {
+ tok->u.code = c;
+ tok->escaped = 0;
+
+#ifdef USE_VARIABLE_META_CHARS
+ if ((c != ONIG_INEFFECTIVE_META_CHAR) &&
+ IS_SYNTAX_OP(syn, ONIG_SYN_OP_VARIABLE_META_CHARACTERS)) {
+ if (c == MC_ANYCHAR(syn))
+ goto any_char;
+ else if (c == MC_ANYTIME(syn))
+ goto any_time;
+ else if (c == MC_ZERO_OR_ONE_TIME(syn))
+ goto zero_or_one_time;
+ else if (c == MC_ONE_OR_MORE_TIME(syn))
+ goto one_or_more_time;
+ else if (c == MC_ANYCHAR_ANYTIME(syn)) {
+ tok->type = TK_ANYCHAR_ANYTIME;
+ goto out;
+ }
+ }
+#endif
+
+ switch (c) {
+ case '.':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_DOT_ANYCHAR)) break;
+#ifdef USE_VARIABLE_META_CHARS
+ any_char:
+#endif
+ tok->type = TK_ANYCHAR;
+ break;
+
+ case '*':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_ASTERISK_ZERO_INF)) break;
+#ifdef USE_VARIABLE_META_CHARS
+ any_time:
+#endif
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 0;
+ tok->u.repeat.upper = INFINITE_REPEAT;
+ goto greedy_check;
+ break;
+
+ case '+':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_PLUS_ONE_INF)) break;
+#ifdef USE_VARIABLE_META_CHARS
+ one_or_more_time:
+#endif
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 1;
+ tok->u.repeat.upper = INFINITE_REPEAT;
+ goto greedy_check;
+ break;
+
+ case '?':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_QMARK_ZERO_ONE)) break;
+#ifdef USE_VARIABLE_META_CHARS
+ zero_or_one_time:
+#endif
+ tok->type = TK_REPEAT;
+ tok->u.repeat.lower = 0;
+ tok->u.repeat.upper = 1;
+ goto greedy_check;
+ break;
+
+ case '{':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_BRACE_INTERVAL)) break;
+ r = fetch_interval(&p, end, tok, env);
+ if (r < 0) return r; /* error */
+ if (r == 0) goto greedy_check2;
+ else if (r == 2) { /* {n} */
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
+ goto possessive_check;
+
+ goto greedy_check2;
+ }
+ /* r == 1 : normal char */
+ break;
+
+ case '|':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_VBAR_ALT)) break;
+ tok->type = TK_ALT;
+ break;
+
+ case '(':
+ if (!PEND && PPEEK_IS('?') &&
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_QMARK_GROUP_EFFECT)) {
+ PINC;
+ if (! PEND) {
+ c = PPEEK;
+ if (c == '#') {
+ PFETCH(c);
+ while (1) {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ if (c == MC_ESC(syn)) {
+ if (! PEND) PFETCH(c);
+ }
+ else {
+ if (c == ')') break;
+ }
+ }
+ goto start;
+ }
+ else if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_QMARK_PERL_SUBEXP_CALL)) {
+ int gnum;
+ UChar* name;
+ UChar* name_end;
+ enum REF_NUM num_type;
+
+ switch (c) {
+ case '&':
+ {
+ PINC;
+ name = p;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env,
+ &gnum, &num_type, FALSE);
+ if (r < 0) return r;
+
+ tok->type = TK_CALL;
+ tok->u.call.by_number = 0;
+ tok->u.call.gnum = 0;
+ tok->u.call.name = name;
+ tok->u.call.name_end = name_end;
+ }
+ break;
+
+ case 'R':
+ tok->type = TK_CALL;
+ tok->u.call.by_number = 1;
+ tok->u.call.gnum = 0;
+ tok->u.call.name = p;
+ PINC;
+ if (! PPEEK_IS(')')) return ONIGERR_UNDEFINED_GROUP_OPTION;
+ tok->u.call.name_end = p;
+ break;
+
+ case '-':
+ case '+':
+ goto lparen_qmark_num;
+ break;
+ default:
+ if (! ONIGENC_IS_CODE_DIGIT(enc, c)) goto lparen_qmark_end;
+
+ lparen_qmark_num:
+ {
+ name = p;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env,
+ &gnum, &num_type, TRUE);
+ if (r < 0) return r;
+
+ if (num_type == IS_NOT_NUM) {
+ return ONIGERR_INVALID_GROUP_NAME;
+ }
+ else {
+ if (num_type == IS_REL_NUM) {
+ gnum = backref_rel_to_abs(gnum, env);
+ if (gnum < 0) {
+ onig_scan_env_set_error_string(env,
+ ONIGERR_UNDEFINED_NAME_REFERENCE, name, name_end);
+ return ONIGERR_UNDEFINED_GROUP_REFERENCE;
+ }
+ }
+ tok->u.call.by_number = 1;
+ tok->u.call.gnum = gnum;
+ }
+
+ tok->type = TK_CALL;
+ tok->u.call.name = name;
+ tok->u.call.name_end = name_end;
+ }
+ break;
+ }
+ }
+ }
+ lparen_qmark_end:
+ PUNFETCH;
+ }
+
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LPAREN_SUBEXP)) break;
+ tok->type = TK_SUBEXP_OPEN;
+ break;
+
+ case ')':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LPAREN_SUBEXP)) break;
+ tok->type = TK_SUBEXP_CLOSE;
+ break;
+
+ case '^':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LINE_ANCHOR)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = (OPTON_SINGLELINE(env->options)
+ ? ANCR_BEGIN_BUF : ANCR_BEGIN_LINE);
+ break;
+
+ case '$':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LINE_ANCHOR)) break;
+ tok->type = TK_ANCHOR;
+ tok->u.subtype = (OPTON_SINGLELINE(env->options)
+ ? ANCR_SEMI_END_BUF : ANCR_END_LINE);
+ break;
+
+ case '[':
+ if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_BRACKET_CC)) break;
+ tok->type = TK_OPEN_CC;
+ break;
+
+ case ']':
+ if (*src > env->pattern) /* /].../ is allowed. */
+ CLOSE_BRACKET_WITHOUT_ESC_WARN(env, (UChar* )"]");
+ break;
+
+ case '#':
+ if (OPTON_EXTEND(env->options)) {
+ while (!PEND) {
+ PFETCH(c);
+ if (ONIGENC_IS_CODE_NEWLINE(enc, c))
+ break;
+ }
+ goto start;
+ break;
+ }
+ break;
+
+ case ' ': case '\t': case '\n': case '\r': case '\f':
+ if (OPTON_EXTEND(env->options))
+ goto start;
+ break;
+
+ default:
+ /* string */
+ break;
+ }
+ }
+
+#ifdef USE_VARIABLE_META_CHARS
+ out:
+#endif
+ *src = p;
+ return tok->type;
+}
+
+static int
+add_ctype_to_cc_by_range(CClassNode* cc, int ctype ARG_UNUSED, int not,
+ OnigEncoding enc ARG_UNUSED, OnigCodePoint sb_out,
+ const OnigCodePoint mbr[])
+{
+ int i, r;
+ OnigCodePoint j;
+
+ int n = ONIGENC_CODE_RANGE_NUM(mbr);
+
+ if (not == 0) {
+ for (i = 0; i < n; i++) {
+ for (j = ONIGENC_CODE_RANGE_FROM(mbr, i);
+ j <= ONIGENC_CODE_RANGE_TO(mbr, i); j++) {
+ if (j >= sb_out) {
+ if (j > ONIGENC_CODE_RANGE_FROM(mbr, i)) {
+ r = add_code_range_to_buf(&(cc->mbuf), j,
+ ONIGENC_CODE_RANGE_TO(mbr, i));
+ if (r != 0) return r;
+ i++;
+ }
+
+ goto sb_end;
+ }
+ BITSET_SET_BIT(cc->bs, j);
+ }
+ }
+
+ sb_end:
+ for ( ; i < n; i++) {
+ r = add_code_range_to_buf(&(cc->mbuf),
+ ONIGENC_CODE_RANGE_FROM(mbr, i),
+ ONIGENC_CODE_RANGE_TO(mbr, i));
+ if (r != 0) return r;
+ }
+ }
+ else {
+ OnigCodePoint prev = 0;
+
+ for (i = 0; i < n; i++) {
+ for (j = prev; j < ONIGENC_CODE_RANGE_FROM(mbr, i); j++) {
+ if (j >= sb_out) {
+ goto sb_end2;
+ }
+ BITSET_SET_BIT(cc->bs, j);
+ }
+ prev = ONIGENC_CODE_RANGE_TO(mbr, i) + 1;
+ }
+ for (j = prev; j < sb_out; j++) {
+ BITSET_SET_BIT(cc->bs, j);
+ }
+
+ sb_end2:
+ prev = sb_out;
+
+ for (i = 0; i < n; i++) {
+ if (prev < ONIGENC_CODE_RANGE_FROM(mbr, i)) {
+ r = add_code_range_to_buf(&(cc->mbuf), prev,
+ ONIGENC_CODE_RANGE_FROM(mbr, i) - 1);
+ if (r != 0) return r;
+ }
+ prev = ONIGENC_CODE_RANGE_TO(mbr, i) + 1;
+ if (prev == 0) goto end;
+ }
+
+ r = add_code_range_to_buf(&(cc->mbuf), prev, MAX_CODE_POINT);
+ if (r != 0) return r;
+ }
+
+ end:
+ return 0;
+}
+
+static int
+add_ctype_to_cc_by_range_limit(CClassNode* cc, int ctype ARG_UNUSED, int not,
+ OnigEncoding enc ARG_UNUSED,
+ OnigCodePoint sb_out,
+ const OnigCodePoint mbr[], OnigCodePoint limit)
+{
+ int i, r;
+ OnigCodePoint j;
+ OnigCodePoint from;
+ OnigCodePoint to;
+
+ int n = ONIGENC_CODE_RANGE_NUM(mbr);
+
+ if (not == 0) {
+ for (i = 0; i < n; i++) {
+ for (j = ONIGENC_CODE_RANGE_FROM(mbr, i);
+ j <= ONIGENC_CODE_RANGE_TO(mbr, i); j++) {
+ if (j > limit) goto end;
+ if (j >= sb_out) {
+ if (j > ONIGENC_CODE_RANGE_FROM(mbr, i)) {
+ to = ONIGENC_CODE_RANGE_TO(mbr, i);
+ if (to > limit) to = limit;
+ r = add_code_range_to_buf(&(cc->mbuf), j, to);
+ if (r != 0) return r;
+ i++;
+ }
+
+ goto sb_end;
+ }
+ BITSET_SET_BIT(cc->bs, j);
+ }
+ }
+
+ sb_end:
+ for ( ; i < n; i++) {
+ from = ONIGENC_CODE_RANGE_FROM(mbr, i);
+ to = ONIGENC_CODE_RANGE_TO(mbr, i);
+ if (from > limit) break;
+ if (to > limit) to = limit;
+ r = add_code_range_to_buf(&(cc->mbuf), from, to);
+ if (r != 0) return r;
+ }
+ }
+ else {
+ OnigCodePoint prev = 0;
+
+ for (i = 0; i < n; i++) {
+ from = ONIGENC_CODE_RANGE_FROM(mbr, i);
+ if (from > limit) {
+ for (j = prev; j < sb_out; j++) {
+ BITSET_SET_BIT(cc->bs, j);
+ }
+ goto sb_end2;
+ }
+ for (j = prev; j < from; j++) {
+ if (j >= sb_out) goto sb_end2;
+ BITSET_SET_BIT(cc->bs, j);
+ }
+ prev = ONIGENC_CODE_RANGE_TO(mbr, i);
+ if (prev > limit) prev = limit;
+ prev++;
+ if (prev == 0) goto end;
+ }
+ for (j = prev; j < sb_out; j++) {
+ BITSET_SET_BIT(cc->bs, j);
+ }
+
+ sb_end2:
+ prev = sb_out;
+
+ for (i = 0; i < n; i++) {
+ from = ONIGENC_CODE_RANGE_FROM(mbr, i);
+ if (from > limit) goto last;
+
+ if (prev < from) {
+ r = add_code_range_to_buf(&(cc->mbuf), prev, from - 1);
+ if (r != 0) return r;
+ }
+ prev = ONIGENC_CODE_RANGE_TO(mbr, i);
+ if (prev > limit) prev = limit;
+ prev++;
+ if (prev == 0) goto end;
+ }
+
+ last:
+ r = add_code_range_to_buf(&(cc->mbuf), prev, MAX_CODE_POINT);
+ if (r != 0) return r;
+ }
+
+ end:
+ return 0;
+}
+
+static int
+add_ctype_to_cc(CClassNode* cc, int ctype, int not, ScanEnv* env)
+{
+ int c, r;
+ int ascii_mode;
+ int is_single;
+ const OnigCodePoint *ranges;
+ OnigCodePoint limit;
+ OnigCodePoint sb_out;
+ OnigEncoding enc = env->enc;
+
+ ascii_mode = OPTON_IS_ASCII_MODE_CTYPE(ctype, env->options);
+
+ r = ONIGENC_GET_CTYPE_CODE_RANGE(enc, ctype, &sb_out, &ranges);
+ if (r == 0) {
+ if (ascii_mode == 0)
+ r = add_ctype_to_cc_by_range(cc, ctype, not, env->enc, sb_out, ranges);
+ else
+ r = add_ctype_to_cc_by_range_limit(cc, ctype, not, env->enc, sb_out,
+ ranges, ASCII_LIMIT);
+ return r;
+ }
+ else if (r != ONIG_NO_SUPPORT_CONFIG) {
+ return r;
+ }
+
+ r = 0;
+ is_single = ONIGENC_IS_SINGLEBYTE(enc);
+ limit = ascii_mode ? ASCII_LIMIT : SINGLE_BYTE_SIZE;
+
+ switch (ctype) {
+ case ONIGENC_CTYPE_ALPHA:
+ case ONIGENC_CTYPE_BLANK:
+ case ONIGENC_CTYPE_CNTRL:
+ case ONIGENC_CTYPE_DIGIT:
+ case ONIGENC_CTYPE_LOWER:
+ case ONIGENC_CTYPE_PUNCT:
+ case ONIGENC_CTYPE_SPACE:
+ case ONIGENC_CTYPE_UPPER:
+ case ONIGENC_CTYPE_XDIGIT:
+ case ONIGENC_CTYPE_ASCII:
+ case ONIGENC_CTYPE_ALNUM:
+ if (not != 0) {
+ for (c = 0; c < (int )limit; c++) {
+ if (is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1) {
+ if (! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT(cc->bs, c);
+ }
+ }
+ for (c = limit; c < SINGLE_BYTE_SIZE; c++) {
+ if (is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1)
+ BITSET_SET_BIT(cc->bs, c);
+ }
+
+ if (is_single == 0)
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ }
+ else {
+ for (c = 0; c < (int )limit; c++) {
+ if (is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1) {
+ if (ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT(cc->bs, c);
+ }
+ }
+ }
+ break;
+
+ case ONIGENC_CTYPE_GRAPH:
+ case ONIGENC_CTYPE_PRINT:
+ case ONIGENC_CTYPE_WORD:
+ if (not != 0) {
+ for (c = 0; c < (int )limit; c++) {
+ /* check invalid code point */
+ if ((is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1)
+ && ! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT(cc->bs, c);
+ }
+ for (c = limit; c < SINGLE_BYTE_SIZE; c++) {
+ if (is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1)
+ BITSET_SET_BIT(cc->bs, c);
+ }
+ if (ascii_mode != 0 && is_single == 0)
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ }
+ else {
+ for (c = 0; c < (int )limit; c++) {
+ if ((is_single != 0 || ONIGENC_CODE_TO_MBCLEN(enc, c) == 1)
+ && ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT(cc->bs, c);
+ }
+ if (ascii_mode == 0 && is_single == 0)
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ }
+ break;
+
+ default:
+ return ONIGERR_PARSER_BUG;
+ break;
+ }
+
+ return r;
+}
+
+static int
+parse_posix_bracket(CClassNode* cc, UChar** src, UChar* end, ScanEnv* env)
+{
+#define POSIX_BRACKET_CHECK_LIMIT_LENGTH 20
+#define POSIX_BRACKET_NAME_MIN_LEN 4
+
+ static PosixBracketEntryType PBS[] = {
+ { (UChar* )"alnum", ONIGENC_CTYPE_ALNUM, 5 },
+ { (UChar* )"alpha", ONIGENC_CTYPE_ALPHA, 5 },
+ { (UChar* )"blank", ONIGENC_CTYPE_BLANK, 5 },
+ { (UChar* )"cntrl", ONIGENC_CTYPE_CNTRL, 5 },
+ { (UChar* )"digit", ONIGENC_CTYPE_DIGIT, 5 },
+ { (UChar* )"graph", ONIGENC_CTYPE_GRAPH, 5 },
+ { (UChar* )"lower", ONIGENC_CTYPE_LOWER, 5 },
+ { (UChar* )"print", ONIGENC_CTYPE_PRINT, 5 },
+ { (UChar* )"punct", ONIGENC_CTYPE_PUNCT, 5 },
+ { (UChar* )"space", ONIGENC_CTYPE_SPACE, 5 },
+ { (UChar* )"upper", ONIGENC_CTYPE_UPPER, 5 },
+ { (UChar* )"xdigit", ONIGENC_CTYPE_XDIGIT, 6 },
+ { (UChar* )"ascii", ONIGENC_CTYPE_ASCII, 5 },
+ { (UChar* )"word", ONIGENC_CTYPE_WORD, 4 },
+ { (UChar* )NULL, -1, 0 }
+ };
+
+ PosixBracketEntryType *pb;
+ int not, i, r;
+ OnigCodePoint c;
+ OnigEncoding enc = env->enc;
+ UChar *p = *src;
+
+ if (PPEEK_IS('^')) {
+ PINC_S;
+ not = 1;
+ }
+ else
+ not = 0;
+
+ if (onigenc_strlen(enc, p, end) < POSIX_BRACKET_NAME_MIN_LEN + 3)
+ goto not_posix_bracket;
+
+ for (pb = PBS; IS_NOT_NULL(pb->name); pb++) {
+ if (onigenc_with_ascii_strncmp(enc, p, end, pb->name, pb->len) == 0) {
+ p = (UChar* )onigenc_step(enc, p, end, pb->len);
+ if (onigenc_with_ascii_strncmp(enc, p, end, (UChar* )":]", 2) != 0)
+ return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
+
+ r = add_ctype_to_cc(cc, pb->ctype, not, env);
+ if (r != 0) return r;
+
+ PINC_S; PINC_S;
+ *src = p;
+ return 0;
+ }
+ }
+
+ not_posix_bracket:
+ c = 0;
+ i = 0;
+ while (!PEND && ((c = PPEEK) != ':') && c != ']') {
+ PINC_S;
+ if (++i > POSIX_BRACKET_CHECK_LIMIT_LENGTH) break;
+ }
+ if (c == ':' && ! PEND) {
+ PINC_S;
+ if (! PEND) {
+ PFETCH_S(c);
+ if (c == ']')
+ return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
+ }
+ }
+
+ return 1; /* 1: is not POSIX bracket, but no error. */
+}
+
+static int
+fetch_char_property_to_ctype(UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ OnigCodePoint c;
+ OnigEncoding enc;
+ UChar *prev, *start, *p;
+
+ p = *src;
+ enc = env->enc;
+ r = ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS;
+ start = prev = p;
+
+ while (!PEND) {
+ prev = p;
+ PFETCH_S(c);
+ if (c == '}') {
+ r = ONIGENC_PROPERTY_NAME_TO_CTYPE(enc, start, prev);
+ if (r >= 0) {
+ *src = p;
+ }
+ else {
+ onig_scan_env_set_error_string(env, r, *src, prev);
+ }
+
+ return r;
+ }
+ else if (c == '(' || c == ')' || c == '{' || c == '|') {
+ break;
+ }
+ }
+
+ return r;
+}
+
+static int
+parse_char_property(Node** np, PToken* tok, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r, ctype;
+ CClassNode* cc;
+
+ ctype = fetch_char_property_to_ctype(src, end, env);
+ if (ctype < 0) return ctype;
+
+ *np = node_new_cclass();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ cc = CCLASS_(*np);
+ r = add_ctype_to_cc(cc, ctype, FALSE, env);
+ if (r != 0) return r;
+ if (tok->u.prop.not != 0) NCCLASS_SET_NOT(cc);
+
+ return 0;
+}
+
+
+typedef enum {
+ CS_VALUE,
+ CS_RANGE,
+ CS_COMPLETE,
+ CS_START
+} CSTATE;
+
+typedef enum {
+ CV_UNDEF,
+ CV_SB,
+ CV_MB,
+ CV_CPROP
+} CVAL;
+
+static int
+cc_cprop_next(CClassNode* cc, OnigCodePoint* pcode, CVAL* val, CSTATE* state,
+ ScanEnv* env)
+{
+ int r;
+
+ if (*state == CS_RANGE)
+ return ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE;
+
+ if (*state == CS_VALUE) {
+ if (*val == CV_SB)
+ BITSET_SET_BIT(cc->bs, (int )(*pcode));
+ else if (*val == CV_MB) {
+ r = add_code_range(&(cc->mbuf), env, *pcode, *pcode);
+ if (r < 0) return r;
+ }
+ }
+
+ *state = CS_VALUE;
+ *val = CV_CPROP;
+ return 0;
+}
+
+static int
+cc_char_next(CClassNode* cc, OnigCodePoint *from, OnigCodePoint to,
+ int* from_raw, int to_raw, CVAL intype, CVAL* type,
+ CSTATE* state, ScanEnv* env)
+{
+ int r;
+
+ switch (*state) {
+ case CS_VALUE:
+ if (*type == CV_SB) {
+ if (*from > 0xff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ BITSET_SET_BIT(cc->bs, (int )(*from));
+ }
+ else if (*type == CV_MB) {
+ r = add_code_range(&(cc->mbuf), env, *from, *from);
+ if (r < 0) return r;
+ }
+ break;
+
+ case CS_RANGE:
+ if (intype == *type) {
+ if (intype == CV_SB) {
+ if (*from > 0xff || to > 0xff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ if (*from > to) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
+ goto ccs_range_end;
+ else
+ return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
+ }
+ bitset_set_range(cc->bs, (int )*from, (int )to);
+ }
+ else {
+ r = add_code_range(&(cc->mbuf), env, *from, to);
+ if (r < 0) return r;
+ }
+ }
+ else {
+ if (*from > to) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
+ goto ccs_range_end;
+ else
+ return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
+ }
+ bitset_set_range(cc->bs, (int )*from, (int )(to < 0xff ? to : 0xff));
+ r = add_code_range(&(cc->mbuf), env, (OnigCodePoint )*from, to);
+ if (r < 0) return r;
+ }
+ ccs_range_end:
+ *state = CS_COMPLETE;
+ break;
+
+ case CS_COMPLETE:
+ case CS_START:
+ *state = CS_VALUE;
+ break;
+
+ default:
+ break;
+ }
+
+ *from_raw = to_raw;
+ *from = to;
+ *type = intype;
+ return 0;
+}
+
+static int
+code_exist_check(OnigCodePoint c, UChar* from, UChar* end, int ignore_escaped,
+ ScanEnv* env)
+{
+ int in_esc;
+ OnigCodePoint code;
+ OnigEncoding enc = env->enc;
+ UChar* p = from;
+
+ in_esc = 0;
+ while (! PEND) {
+ if (ignore_escaped && in_esc) {
+ in_esc = 0;
+ }
+ else {
+ PFETCH_S(code);
+ if (code == c) return 1;
+ if (code == MC_ESC(env->syntax)) in_esc = 1;
+ }
+ }
+ return 0;
+}
+
+static int
+parse_cc(Node** np, PToken* tok, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r, neg, len, fetched, and_start;
+ OnigCodePoint in_code, curr_code;
+ UChar *p;
+ Node* node;
+ CClassNode *cc, *prev_cc;
+ CClassNode work_cc;
+ int curr_raw, in_raw;
+ CSTATE state;
+ CVAL in_type;
+ CVAL curr_type;
+
+ *np = NULL_NODE;
+ INC_PARSE_DEPTH(env->parse_depth);
+
+ prev_cc = (CClassNode* )NULL;
+ r = fetch_token_in_cc(tok, src, end, env);
+ if (r == TK_CHAR && tok->u.code == (OnigCodePoint )'^' && tok->escaped == 0) {
+ neg = 1;
+ r = fetch_token_in_cc(tok, src, end, env);
+ }
+ else {
+ neg = 0;
+ }
+
+ if (r < 0) return r;
+ if (r == TK_CC_CLOSE) {
+ if (! code_exist_check((OnigCodePoint )']',
+ *src, env->pattern_end, 1, env))
+ return ONIGERR_EMPTY_CHAR_CLASS;
+
+ CC_ESC_WARN(env, (UChar* )"]");
+ r = tok->type = TK_CHAR; /* allow []...] */
+ }
+
+ *np = node = node_new_cclass();
+ CHECK_NULL_RETURN_MEMERR(node);
+ cc = CCLASS_(node);
+
+ and_start = 0;
+ state = CS_START;
+ curr_type = CV_UNDEF;
+
+ p = *src;
+ while (r != TK_CC_CLOSE) {
+ fetched = 0;
+ switch (r) {
+ case TK_CHAR:
+ any_char_in:
+ len = ONIGENC_CODE_TO_MBCLEN(env->enc, tok->u.code);
+ if (len < 0) {
+ r = len;
+ goto err;
+ }
+ in_type = (len == 1) ? CV_SB : CV_MB;
+ in_code = tok->u.code;
+ in_raw = 0;
+ goto val_entry2;
+ break;
+
+ case TK_CRUDE_BYTE:
+ /* tok->base != 0 : octal or hexadec. */
+ if (! ONIGENC_IS_SINGLEBYTE(env->enc) && tok->base != 0) {
+ int i, j;
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
+ UChar* bufe = buf + ONIGENC_CODE_TO_MBC_MAXLEN;
+ UChar* psave = p;
+ int base = tok->base;
+
+ buf[0] = tok->u.byte;
+ for (i = 1; i < ONIGENC_MBC_MAXLEN(env->enc); i++) {
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ if (r != TK_CRUDE_BYTE || tok->base != base) {
+ fetched = 1;
+ break;
+ }
+ buf[i] = tok->u.byte;
+ }
+
+ if (i < ONIGENC_MBC_MINLEN(env->enc)) {
+ r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+ goto err;
+ }
+
+ /* clear buf tail */
+ for (j = i; j < ONIGENC_CODE_TO_MBC_MAXLEN; j++) buf[j] = '\0';
+
+ len = enclen(env->enc, buf);
+ if (i < len) {
+ r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+ goto err;
+ }
+ else if (i > len) { /* fetch back */
+ p = psave;
+ for (i = 1; i < len; i++) {
+ r = fetch_token_in_cc(tok, &p, end, env);
+ }
+ fetched = 0;
+ }
+
+ if (i == 1) {
+ in_code = (OnigCodePoint )buf[0];
+ goto crude_single;
+ }
+ else {
+ in_code = ONIGENC_MBC_TO_CODE(env->enc, buf, bufe);
+ in_type = CV_MB;
+ }
+ }
+ else {
+ in_code = (OnigCodePoint )tok->u.byte;
+ crude_single:
+ in_type = CV_SB;
+ }
+ in_raw = 1;
+ goto val_entry2;
+ break;
+
+ case TK_CODE_POINT:
+ in_code = tok->u.code;
+ in_raw = 1;
+ val_entry:
+ len = ONIGENC_CODE_TO_MBCLEN(env->enc, in_code);
+ if (len < 0) {
+ if (state != CS_RANGE ||
+ ! IS_SYNTAX_BV(env->syntax,
+ ONIG_SYN_ALLOW_INVALID_CODE_END_OF_RANGE_IN_CC) ||
+ in_code < 0x100 || ONIGENC_MBC_MAXLEN(env->enc) == 1) {
+ r = len;
+ goto err;
+ }
+ }
+ in_type = (len == 1 ? CV_SB : CV_MB);
+ val_entry2:
+ r = cc_char_next(cc, &curr_code, in_code, &curr_raw, in_raw, in_type,
+ &curr_type, &state, env);
+ if (r != 0) goto err;
+ break;
+
+ case TK_CC_POSIX_BRACKET_OPEN:
+ r = parse_posix_bracket(cc, &p, end, env);
+ if (r < 0) goto err;
+ if (r == 1) { /* is not POSIX bracket */
+ CC_ESC_WARN(env, (UChar* )"[");
+ p = tok->backp;
+ in_code = tok->u.code;
+ in_raw = 0;
+ goto val_entry;
+ }
+ goto next_cprop;
+ break;
+
+ case TK_CHAR_TYPE:
+ r = add_ctype_to_cc(cc, tok->u.prop.ctype, tok->u.prop.not, env);
+ if (r != 0) goto err;
+
+ next_cprop:
+ r = cc_cprop_next(cc, &curr_code, &curr_type, &state, env);
+ if (r != 0) goto err;
+ break;
+
+ case TK_CHAR_PROPERTY:
+ {
+ int ctype = fetch_char_property_to_ctype(&p, end, env);
+ if (ctype < 0) {
+ r = ctype;
+ goto err;
+ }
+ r = add_ctype_to_cc(cc, ctype, tok->u.prop.not, env);
+ if (r != 0) goto err;
+ goto next_cprop;
+ }
+ break;
+
+ case TK_CC_RANGE:
+ if (state == CS_VALUE) {
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+
+ fetched = 1;
+ if (r == TK_CC_CLOSE) { /* allow [x-] */
+ range_end_val:
+ in_code = (OnigCodePoint )'-';
+ in_raw = 0;
+ goto val_entry;
+ }
+ else if (r == TK_CC_AND) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val;
+ }
+
+ if (curr_type == CV_CPROP) {
+ r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
+ goto err;
+ }
+
+ state = CS_RANGE;
+ }
+ else if (state == CS_START) {
+ /* [-xa] is allowed */
+ in_code = tok->u.code;
+ in_raw = 0;
+
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+
+ fetched = 1;
+ /* [--x] or [a&&-x] is warned. */
+ if (r == TK_CC_RANGE || and_start != 0)
+ CC_ESC_WARN(env, (UChar* )"-");
+
+ goto val_entry;
+ }
+ else if (state == CS_RANGE) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto any_char_in; /* [!--] is allowed */
+ }
+ else { /* CS_COMPLETE */
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+
+ fetched = 1;
+ if (r == TK_CC_CLOSE)
+ goto range_end_val; /* allow [a-b-] */
+ else if (r == TK_CC_AND) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val;
+ }
+
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC)) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val; /* [0-9-a] is allowed as [0-9\-a] */
+ }
+ r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
+ goto err;
+ }
+ break;
+
+ case TK_CC_OPEN_CC: /* [ */
+ {
+ Node *anode;
+ CClassNode* acc;
+
+ if (state == CS_VALUE) {
+ r = cc_char_next(cc, &curr_code, 0, &curr_raw, 0, curr_type, &curr_type,
+ &state, env);
+ if (r != 0) goto err;
+ }
+ state = CS_COMPLETE;
+
+ r = parse_cc(&anode, tok, &p, end, env);
+ if (r != 0) {
+ onig_node_free(anode);
+ goto cc_open_err;
+ }
+ acc = CCLASS_(anode);
+ r = or_cclass(cc, acc, env->enc);
+ onig_node_free(anode);
+
+ cc_open_err:
+ if (r != 0) goto err;
+ }
+ break;
+
+ case TK_CC_AND: /* && */
+ {
+ if (state == CS_VALUE) {
+ r = cc_char_next(cc, &curr_code, 0, &curr_raw, 0, curr_type, &curr_type,
+ &state, env);
+ if (r != 0) goto err;
+ }
+ /* initialize local variables */
+ and_start = 1;
+ state = CS_START;
+
+ if (IS_NOT_NULL(prev_cc)) {
+ r = and_cclass(prev_cc, cc, env->enc);
+ if (r != 0) goto err;
+ bbuf_free(cc->mbuf);
+ }
+ else {
+ prev_cc = cc;
+ cc = &work_cc;
+ }
+ initialize_cclass(cc);
+ }
+ break;
+
+ case TK_EOT:
+ r = ONIGERR_PREMATURE_END_OF_CHAR_CLASS;
+ goto err;
+ break;
+ default:
+ r = ONIGERR_PARSER_BUG;
+ goto err;
+ break;
+ }
+
+ if (fetched)
+ r = tok->type;
+ else {
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ }
+ }
+
+ if (state == CS_VALUE) {
+ r = cc_char_next(cc, &curr_code, 0, &curr_raw, 0, curr_type, &curr_type,
+ &state, env);
+ if (r != 0) goto err;
+ }
+
+ if (IS_NOT_NULL(prev_cc)) {
+ r = and_cclass(prev_cc, cc, env->enc);
+ if (r != 0) goto err;
+ bbuf_free(cc->mbuf);
+ cc = prev_cc;
+ }
+
+ if (neg != 0)
+ NCCLASS_SET_NOT(cc);
+ else
+ NCCLASS_CLEAR_NOT(cc);
+ if (IS_NCCLASS_NOT(cc) &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC)) {
+ int is_empty = (IS_NULL(cc->mbuf) ? 1 : 0);
+ if (is_empty != 0)
+ BITSET_IS_EMPTY(cc->bs, is_empty);
+
+ if (is_empty == 0) {
+ if (ONIGENC_IS_CODE_NEWLINE(env->enc, NEWLINE_CODE)) {
+ if (ONIGENC_CODE_TO_MBCLEN(env->enc, NEWLINE_CODE) == 1)
+ BITSET_SET_BIT(cc->bs, NEWLINE_CODE);
+ else
+ add_code_range(&(cc->mbuf), env, NEWLINE_CODE, NEWLINE_CODE);
+ }
+ }
+ }
+ *src = p;
+ DEC_PARSE_DEPTH(env->parse_depth);
+ return 0;
+
+ err:
+ if (cc != CCLASS_(*np))
+ bbuf_free(cc->mbuf);
+ return r;
+}
+
+static int parse_alts(Node** top, PToken* tok, int term,
+ UChar** src, UChar* end, ScanEnv* env, int group_head);
+
+#ifdef USE_CALLOUT
+
+/* (?{...}[tag][+-]) (?{{...}}[tag][+-]) */
+static int
+parse_callout_of_contents(Node** np, int cterm, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ int i;
+ int in;
+ int num;
+ OnigCodePoint c;
+ UChar* code_start;
+ UChar* code_end;
+ UChar* contents;
+ UChar* tag_start;
+ UChar* tag_end;
+ int brace_nest;
+ CalloutListEntry* e;
+ RegexExt* ext;
+ OnigEncoding enc = env->enc;
+ UChar* p = *src;
+
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ brace_nest = 0;
+ while (PPEEK_IS('{')) {
+ brace_nest++;
+ PINC_S;
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+ }
+
+ in = ONIG_CALLOUT_IN_PROGRESS;
+ code_start = p;
+ while (1) {
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ code_end = p;
+ PFETCH_S(c);
+ if (c == '}') {
+ i = brace_nest;
+ while (i > 0) {
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+ PFETCH_S(c);
+ if (c == '}') i--;
+ else break;
+ }
+ if (i == 0) break;
+ }
+ }
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ PFETCH_S(c);
+ if (c == '[') {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ tag_end = tag_start = p;
+ while (! PEND) {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ tag_end = p;
+ PFETCH_S(c);
+ if (c == ']') break;
+ }
+ if (! is_allowed_callout_tag_name(enc, tag_start, tag_end))
+ return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+ else {
+ tag_start = tag_end = 0;
+ }
+
+ if (c == 'X') {
+ in |= ONIG_CALLOUT_IN_RETRACTION;
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+ else if (c == '<') {
+ in = ONIG_CALLOUT_IN_RETRACTION;
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+ else if (c == '>') { /* no needs (default) */
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+
+ if (c != cterm)
+ return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ r = reg_callout_list_entry(env, &num);
+ if (r != 0) return r;
+
+ ext = onig_get_regex_ext(env->reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+ if (IS_NULL(ext->pattern)) {
+ r = onig_ext_set_pattern(env->reg, env->pattern, env->pattern_end);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ if (tag_start != tag_end) {
+ r = callout_tag_entry(env, env->reg, tag_start, tag_end, num);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ contents = onigenc_strdup(enc, code_start, code_end);
+ CHECK_NULL_RETURN_MEMERR(contents);
+
+ r = node_new_callout(np, ONIG_CALLOUT_OF_CONTENTS, num, ONIG_NON_NAME_ID, env);
+ if (r != 0) {
+ xfree(contents);
+ return r;
+ }
+
+ e = onig_reg_callout_list_at(env->reg, num);
+ if (IS_NULL(e)) {
+ xfree(contents);
+ return ONIGERR_MEMORY;
+ }
+
+ e->of = ONIG_CALLOUT_OF_CONTENTS;
+ e->in = in;
+ e->name_id = ONIG_NON_NAME_ID;
+ e->u.content.start = contents;
+ e->u.content.end = contents + (code_end - code_start);
+
+ *src = p;
+ return 0;
+}
+
+static long
+parse_long(OnigEncoding enc, UChar* s, UChar* end, int sign_on, long max, long* rl)
+{
+ long v;
+ long d;
+ int flag;
+ UChar* p;
+ OnigCodePoint c;
+
+ if (s >= end) return ONIGERR_INVALID_CALLOUT_ARG;
+
+ flag = 1;
+ v = 0;
+ p = s;
+ while (p < end) {
+ c = ONIGENC_MBC_TO_CODE(enc, p, end);
+ p += ONIGENC_MBC_ENC_LEN(enc, p);
+ if (c >= '0' && c <= '9') {
+ d = (long )(c - '0');
+ if (v > (max - d) / 10)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ v = v * 10 + d;
+ }
+ else if (sign_on != 0 && (c == '-' || c == '+')) {
+ if (c == '-') flag = -1;
+ }
+ else
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ sign_on = 0;
+ }
+
+ *rl = flag * v;
+ return ONIG_NORMAL;
+}
+
+static int
+parse_callout_args(int skip_mode, int cterm, UChar** src, UChar* end,
+ int max_arg_num, unsigned int types[], OnigValue vals[],
+ ScanEnv* env)
+{
+#define MAX_CALLOUT_ARG_BYTE_LENGTH 128
+
+ int r;
+ int n;
+ int esc;
+ int cn;
+ UChar* s;
+ UChar* e;
+ UChar* eesc;
+ OnigCodePoint c;
+ UChar* bufend;
+ UChar buf[MAX_CALLOUT_ARG_BYTE_LENGTH];
+ OnigEncoding enc = env->enc;
+ UChar* p = *src;
+
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ c = 0;
+ n = 0;
+ while (n < ONIG_CALLOUT_MAX_ARGS_NUM) {
+ cn = 0;
+ esc = 0;
+ eesc = 0;
+ bufend = buf;
+ s = e = p;
+ while (1) {
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ e = p;
+ PFETCH_S(c);
+ if (esc != 0) {
+ esc = 0;
+ if (c == '\\' || c == cterm || c == ',') {
+ /* */
+ }
+ else {
+ e = eesc;
+ cn++;
+ }
+ goto add_char;
+ }
+ else {
+ if (c == '\\') {
+ esc = 1;
+ eesc = e;
+ }
+ else if (c == cterm || c == ',')
+ break;
+ else {
+ size_t clen;
+
+ add_char:
+ if (skip_mode == FALSE) {
+ clen = p - e;
+ if (bufend + clen > buf + MAX_CALLOUT_ARG_BYTE_LENGTH)
+ return ONIGERR_INVALID_CALLOUT_ARG; /* too long argument */
+
+ xmemcpy(bufend, e, clen);
+ bufend += clen;
+ }
+ cn++;
+ }
+ }
+ }
+
+ if (cn != 0) {
+ if (max_arg_num >= 0 && n >= max_arg_num)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if (skip_mode == FALSE) {
+ if ((types[n] & ONIG_TYPE_LONG) != 0) {
+ int fixed = 0;
+ if (cn > 0) {
+ long rl;
+ r = parse_long(enc, buf, bufend, 1, LONG_MAX, &rl);
+ if (r == ONIG_NORMAL) {
+ vals[n].l = rl;
+ fixed = 1;
+ types[n] = ONIG_TYPE_LONG;
+ }
+ }
+
+ if (fixed == 0) {
+ types[n] = (types[n] & ~ONIG_TYPE_LONG);
+ if (types[n] == ONIG_TYPE_VOID)
+ return ONIGERR_INVALID_CALLOUT_ARG;
+ }
+ }
+
+ switch (types[n]) {
+ case ONIG_TYPE_LONG:
+ break;
+
+ case ONIG_TYPE_CHAR:
+ if (cn != 1) return ONIGERR_INVALID_CALLOUT_ARG;
+ vals[n].c = ONIGENC_MBC_TO_CODE(enc, buf, bufend);
+ break;
+
+ case ONIG_TYPE_STRING:
+ {
+ UChar* rs = onigenc_strdup(enc, buf, bufend);
+ CHECK_NULL_RETURN_MEMERR(rs);
+ vals[n].s.start = rs;
+ vals[n].s.end = rs + (e - s);
+ }
+ break;
+
+ case ONIG_TYPE_TAG:
+ if (eesc != 0 || ! is_allowed_callout_tag_name(enc, s, e))
+ return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ vals[n].s.start = s;
+ vals[n].s.end = e;
+ break;
+
+ case ONIG_TYPE_VOID:
+ case ONIG_TYPE_POINTER:
+ return ONIGERR_PARSER_BUG;
+ break;
+ }
+ }
+
+ n++;
+ }
+
+ if (c == cterm) break;
+ }
+
+ if (c != cterm) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ *src = p;
+ return n;
+}
+
+/* (*name[TAG]) (*name[TAG]{a,b,..}) */
+static int
+parse_callout_of_name(Node** np, int cterm, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ int i;
+ int in;
+ int num;
+ int name_id;
+ int arg_num;
+ int max_arg_num;
+ int opt_arg_num;
+ int is_not_single;
+ OnigCodePoint c;
+ UChar* name_start;
+ UChar* name_end;
+ UChar* tag_start;
+ UChar* tag_end;
+ Node* node;
+ CalloutListEntry* e;
+ RegexExt* ext;
+ unsigned int types[ONIG_CALLOUT_MAX_ARGS_NUM];
+ OnigValue vals[ONIG_CALLOUT_MAX_ARGS_NUM];
+ OnigEncoding enc = env->enc;
+ UChar* p = *src;
+
+ /* PFETCH_READY; */
+ if (PEND) return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ node = 0;
+ name_start = p;
+ while (1) {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ name_end = p;
+ PFETCH_S(c);
+ if (c == cterm || c == '[' || c == '{') break;
+ }
+
+ if (! is_allowed_callout_name(enc, name_start, name_end))
+ return ONIGERR_INVALID_CALLOUT_NAME;
+
+ if (c == '[') {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ tag_end = tag_start = p;
+ while (! PEND) {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ tag_end = p;
+ PFETCH_S(c);
+ if (c == ']') break;
+ }
+ if (! is_allowed_callout_tag_name(enc, tag_start, tag_end))
+ return ONIGERR_INVALID_CALLOUT_TAG_NAME;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+ else {
+ tag_start = tag_end = 0;
+ }
+
+ if (c == '{') {
+ UChar* save;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ /* read for single check only */
+ save = p;
+ arg_num = parse_callout_args(TRUE, '}', &p, end, -1, NULL, NULL, env);
+ if (arg_num < 0) return arg_num;
+
+ is_not_single = PPEEK_IS(cterm) ? 0 : 1;
+ p = save;
+ r = get_callout_name_id_by_name(enc, is_not_single, name_start, name_end,
+ &name_id);
+ if (r != ONIG_NORMAL) return r;
+
+ max_arg_num = get_callout_arg_num_by_name_id(name_id);
+ for (i = 0; i < max_arg_num; i++) {
+ types[i] = get_callout_arg_type_by_name_id(name_id, i);
+ }
+
+ arg_num = parse_callout_args(FALSE, '}', &p, end, max_arg_num, types, vals, env);
+ if (arg_num < 0) return arg_num;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH_S(c);
+ }
+ else {
+ arg_num = 0;
+
+ is_not_single = 0;
+ r = get_callout_name_id_by_name(enc, is_not_single, name_start, name_end,
+ &name_id);
+ if (r != ONIG_NORMAL) return r;
+
+ max_arg_num = get_callout_arg_num_by_name_id(name_id);
+ for (i = 0; i < max_arg_num; i++) {
+ types[i] = get_callout_arg_type_by_name_id(name_id, i);
+ }
+ }
+
+ in = onig_get_callout_in_by_name_id(name_id);
+ opt_arg_num = get_callout_opt_arg_num_by_name_id(name_id);
+ if (arg_num > max_arg_num || arg_num < (max_arg_num - opt_arg_num))
+ return ONIGERR_INVALID_CALLOUT_ARG;
+
+ if (c != cterm)
+ return ONIGERR_INVALID_CALLOUT_PATTERN;
+
+ r = reg_callout_list_entry(env, &num);
+ if (r != 0) return r;
+
+ ext = onig_get_regex_ext(env->reg);
+ CHECK_NULL_RETURN_MEMERR(ext);
+ if (IS_NULL(ext->pattern)) {
+ r = onig_ext_set_pattern(env->reg, env->pattern, env->pattern_end);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ if (tag_start != tag_end) {
+ r = callout_tag_entry(env, env->reg, tag_start, tag_end, num);
+ if (r != ONIG_NORMAL) return r;
+ }
+
+ r = node_new_callout(&node, ONIG_CALLOUT_OF_NAME, num, name_id, env);
+ if (r != ONIG_NORMAL) return r;
+
+ e = onig_reg_callout_list_at(env->reg, num);
+ CHECK_NULL_RETURN_MEMERR(e);
+
+ e->of = ONIG_CALLOUT_OF_NAME;
+ e->in = in;
+ e->name_id = name_id;
+ e->type = onig_get_callout_type_by_name_id(name_id);
+ e->start_func = onig_get_callout_start_func_by_name_id(name_id);
+ e->end_func = onig_get_callout_end_func_by_name_id(name_id);
+ e->u.arg.num = max_arg_num;
+ e->u.arg.passed_num = arg_num;
+ for (i = 0; i < max_arg_num; i++) {
+ e->u.arg.types[i] = types[i];
+ if (i < arg_num)
+ e->u.arg.vals[i] = vals[i];
+ else
+ e->u.arg.vals[i] = get_callout_opt_default_by_name_id(name_id, i);
+ }
+
+ *np = node;
+ *src = p;
+ return 0;
+}
+#endif
+
+static int
+parse_bag(Node** np, PToken* tok, int term, UChar** src, UChar* end,
+ ScanEnv* env)
+{
+ int r, num;
+ Node *target;
+ OnigOptionType option;
+ OnigCodePoint c;
+ int list_capture;
+ OnigEncoding enc = env->enc;
+
+ UChar* p = *src;
+ PFETCH_READY;
+
+ *np = NULL;
+ if (PEND) return ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS;
+
+ option = env->options;
+ c = PPEEK;
+ if (c == '?' && IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_GROUP_EFFECT)) {
+ PINC;
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ PFETCH(c);
+ switch (c) {
+ case ':': /* (?:...) grouping only */
+ group:
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) return r;
+ r = parse_alts(np, tok, term, &p, end, env, FALSE);
+ if (r < 0) return r;
+ *src = p;
+ return 1; /* group */
+ break;
+
+ case '=':
+ *np = node_new_anchor(ANCR_PREC_READ);
+ break;
+ case '!': /* preceding read */
+ *np = node_new_anchor(ANCR_PREC_READ_NOT);
+ break;
+ case '>': /* (?>...) stop backtrack */
+ *np = node_new_bag(BAG_STOP_BACKTRACK);
+ break;
+
+ case '\'':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
+ goto named_group1;
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case '<': /* look behind (?<=...), (?<!...) */
+ if (PEND) return ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS;
+ PFETCH(c);
+ if (c == '=')
+ *np = node_new_anchor(ANCR_LOOK_BEHIND);
+ else if (c == '!')
+ *np = node_new_anchor(ANCR_LOOK_BEHIND_NOT);
+ else {
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
+ UChar *name;
+ UChar *name_end;
+ enum REF_NUM num_type;
+
+ PUNFETCH;
+ c = '<';
+
+ named_group1:
+ list_capture = 0;
+
+#ifdef USE_CAPTURE_HISTORY
+ named_group2:
+#endif
+ name = p;
+ r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env, &num,
+ &num_type, FALSE);
+ if (r < 0) return r;
+
+ num = scan_env_add_mem_entry(env);
+ if (num < 0) return num;
+ if (list_capture != 0 && num >= (int )MEM_STATUS_BITS_NUM)
+ return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
+
+ r = name_add(env->reg, name, name_end, num, env);
+ if (r != 0) return r;
+ *np = node_new_memory(1);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ BAG_(*np)->m.regnum = num;
+ if (list_capture != 0)
+ MEM_STATUS_ON_SIMPLE(env->cap_history, num);
+ env->num_named++;
+ }
+ else {
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+ }
+ break;
+
+ case '~':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP)) {
+ Node* absent;
+ Node* expr;
+ int head_bar;
+ int is_range_cutter;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ if (PPEEK_IS('|')) { /* (?~|generator|absent) */
+ PINC;
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ head_bar = 1;
+ if (PPEEK_IS(')')) { /* (?~|) : range clear */
+ PINC;
+ r = make_range_clear(np, env);
+ if (r != 0) return r;
+ goto end;
+ }
+ }
+ else
+ head_bar = 0;
+
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) return r;
+ r = parse_alts(&absent, tok, term, &p, end, env, TRUE);
+ if (r < 0) {
+ onig_node_free(absent);
+ return r;
+ }
+
+ expr = NULL_NODE;
+ is_range_cutter = 0;
+ if (head_bar != 0) {
+ Node* top = absent;
+ if (NODE_TYPE(top) != NODE_ALT || IS_NULL(NODE_CDR(top))) {
+ expr = NULL_NODE;
+ is_range_cutter = 1;
+ /* return ONIGERR_INVALID_ABSENT_GROUP_GENERATOR_PATTERN; */
+ }
+ else {
+ absent = NODE_CAR(top);
+ expr = NODE_CDR(top);
+ NODE_CAR(top) = NULL_NODE;
+ NODE_CDR(top) = NULL_NODE;
+ onig_node_free(top);
+ if (IS_NULL(NODE_CDR(expr))) {
+ top = expr;
+ expr = NODE_CAR(top);
+ NODE_CAR(top) = NULL_NODE;
+ onig_node_free(top);
+ }
+ }
+ }
+
+ r = make_absent_tree(np, absent, expr, is_range_cutter, env);
+ if (r != 0) {
+ return r;
+ }
+ goto end;
+ }
+ else {
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+ break;
+
+#ifdef USE_CALLOUT
+ case '{':
+ if (! IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS))
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+
+ r = parse_callout_of_contents(np, ')', &p, end, env);
+ if (r != 0) return r;
+
+ goto end;
+ break;
+#endif
+
+ case '(':
+ /* (?()...) */
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE)) {
+ UChar *prev;
+ Node* condition;
+ int condition_is_checker;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+
+ if (IS_CODE_DIGIT_ASCII(enc, c)
+ || c == '-' || c == '+' || c == '<' || c == '\'') {
+ UChar* name_end;
+ int back_num;
+ int exist_level;
+ int level;
+ enum REF_NUM num_type;
+ int is_enclosed;
+
+ is_enclosed = (c == '<' || c == '\'') ? 1 : 0;
+ if (! is_enclosed)
+ PUNFETCH;
+ prev = p;
+ exist_level = 0;
+#ifdef USE_BACKREF_WITH_LEVEL
+ name_end = NULL_UCHARP; /* no need. escape gcc warning. */
+ r = fetch_name_with_level(
+ (OnigCodePoint )(is_enclosed != 0 ? c : '('),
+ &p, end, &name_end,
+ env, &back_num, &level, &num_type);
+ if (r == 1) exist_level = 1;
+#else
+ r = fetch_name((OnigCodePoint )(is_enclosed != 0 ? c : '('),
+ &p, end, &name_end, env, &back_num, &num_type, TRUE);
+#endif
+ if (r < 0) {
+ if (is_enclosed == 0) {
+ goto any_condition;
+ }
+ else
+ return r;
+ }
+
+ condition_is_checker = 1;
+ if (num_type != IS_NOT_NUM) {
+ if (num_type == IS_REL_NUM) {
+ back_num = backref_rel_to_abs(back_num, env);
+ }
+ if (back_num <= 0)
+ return ONIGERR_INVALID_BACKREF;
+
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ if (back_num > env->num_mem ||
+ IS_NULL(SCANENV_MEMENV(env)[back_num].mem_node))
+ return ONIGERR_INVALID_BACKREF;
+ }
+
+ condition = node_new_backref_checker(1, &back_num, FALSE,
+#ifdef USE_BACKREF_WITH_LEVEL
+ exist_level, level,
+#endif
+ env);
+ }
+ else {
+ int num;
+ int* backs;
+
+ num = name_to_group_numbers(env, prev, name_end, &backs);
+ if (num <= 0) {
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ int i;
+ for (i = 0; i < num; i++) {
+ if (backs[i] > env->num_mem ||
+ IS_NULL(SCANENV_MEMENV(env)[backs[i]].mem_node))
+ return ONIGERR_INVALID_BACKREF;
+ }
+ }
+
+ condition = node_new_backref_checker(num, backs, TRUE,
+#ifdef USE_BACKREF_WITH_LEVEL
+ exist_level, level,
+#endif
+ env);
+ }
+
+ if (is_enclosed != 0) {
+ if (PEND) goto err_if_else;
+ PFETCH(c);
+ if (c != ')') goto err_if_else;
+ }
+ }
+#ifdef USE_CALLOUT
+ else if (c == '?') {
+ if (IS_SYNTAX_OP2(env->syntax,
+ ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS)) {
+ if (! PEND && PPEEK_IS('{')) {
+ /* condition part is callouts of contents: (?(?{...})THEN|ELSE) */
+ condition_is_checker = 0;
+ PFETCH(c);
+ r = parse_callout_of_contents(&condition, ')', &p, end, env);
+ if (r != 0) return r;
+ goto end_condition;
+ }
+ }
+ goto any_condition;
+ }
+ else if (c == '*' &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME)) {
+ condition_is_checker = 0;
+ r = parse_callout_of_name(&condition, ')', &p, end, env);
+ if (r != 0) return r;
+ goto end_condition;
+ }
+#endif
+ else {
+ any_condition:
+ PUNFETCH;
+ condition_is_checker = 0;
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) return r;
+ r = parse_alts(&condition, tok, term, &p, end, env, FALSE);
+ if (r < 0) {
+ onig_node_free(condition);
+ return r;
+ }
+ }
+
+#ifdef USE_CALLOUT
+ end_condition:
+#endif
+ CHECK_NULL_RETURN_MEMERR(condition);
+
+ if (PEND) {
+ err_if_else:
+ onig_node_free(condition);
+ return ONIGERR_END_PATTERN_IN_GROUP;
+ }
+
+ if (PPEEK_IS(')')) { /* case: empty body: make backref checker */
+ if (condition_is_checker == 0) {
+ onig_node_free(condition);
+ return ONIGERR_INVALID_IF_ELSE_SYNTAX;
+ }
+ PFETCH(c);
+ *np = condition;
+ }
+ else { /* if-else */
+ int then_is_empty;
+ Node *Then, *Else;
+
+ Then = 0;
+ if (PPEEK_IS('|')) {
+ PFETCH(c);
+ then_is_empty = 1;
+ }
+ else
+ then_is_empty = 0;
+
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) {
+ onig_node_free(condition);
+ return r;
+ }
+ r = parse_alts(&target, tok, term, &p, end, env, TRUE);
+ if (r < 0) {
+ onig_node_free(condition);
+ onig_node_free(target);
+ return r;
+ }
+
+ if (then_is_empty != 0) {
+ Else = target;
+ }
+ else {
+ if (NODE_TYPE(target) == NODE_ALT) {
+ Then = NODE_CAR(target);
+ if (NODE_CDR(NODE_CDR(target)) == NULL_NODE) {
+ Else = NODE_CAR(NODE_CDR(target));
+ cons_node_free_alone(NODE_CDR(target));
+ }
+ else {
+ Else = NODE_CDR(target);
+ }
+ cons_node_free_alone(target);
+ }
+ else {
+ Then = target;
+ Else = 0;
+ }
+ }
+
+ *np = node_new_bag_if_else(condition, Then, Else);
+ if (IS_NULL(*np)) {
+ onig_node_free(condition);
+ onig_node_free(Then);
+ onig_node_free(Else);
+ return ONIGERR_MEMORY;
+ }
+ }
+ goto end;
+ }
+ else {
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+ break;
+
+#ifdef USE_CAPTURE_HISTORY
+ case '@':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY)) {
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ list_capture = 1;
+ goto named_group2; /* (?@<name>...) */
+ }
+ PUNFETCH;
+ }
+
+ *np = node_new_memory(0);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ num = scan_env_add_mem_entry(env);
+ if (num < 0) {
+ return num;
+ }
+ else if (num >= (int )MEM_STATUS_BITS_NUM) {
+ return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
+ }
+ BAG_(*np)->m.regnum = num;
+ MEM_STATUS_ON_SIMPLE(env->cap_history, num);
+ }
+ else {
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+ break;
+#endif
+
+#ifdef USE_POSIXLINE_OPTION
+ case 'p':
+#endif
+ case '-': case 'i': case 'm': case 's': case 'x':
+ case 'W': case 'D': case 'S': case 'P':
+ case 'y':
+ {
+ int neg = 0;
+
+ while (1) {
+ switch (c) {
+ case ':':
+ case ')':
+ break;
+
+ case '-': neg = 1; break;
+ case 'x': OPTION_NEGATE(option, ONIG_OPTION_EXTEND, neg); break;
+ case 'i': OPTION_NEGATE(option, ONIG_OPTION_IGNORECASE, neg); break;
+ case 's':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
+ OPTION_NEGATE(option, ONIG_OPTION_MULTILINE, neg);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case 'm':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
+ OPTION_NEGATE(option, ONIG_OPTION_SINGLELINE, (neg == 0 ? TRUE : FALSE));
+ }
+ else if (IS_SYNTAX_OP2(env->syntax,
+ ONIG_SYN_OP2_OPTION_ONIGURUMA|ONIG_SYN_OP2_OPTION_RUBY)) {
+ OPTION_NEGATE(option, ONIG_OPTION_MULTILINE, neg);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+#ifdef USE_POSIXLINE_OPTION
+ case 'p':
+ OPTION_NEGATE(option, ONIG_OPTION_MULTILINE|ONIG_OPTION_SINGLELINE, neg);
+ break;
+#endif
+ case 'W': OPTION_NEGATE(option, ONIG_OPTION_WORD_IS_ASCII, neg); break;
+ case 'D': OPTION_NEGATE(option, ONIG_OPTION_DIGIT_IS_ASCII, neg); break;
+ case 'S': OPTION_NEGATE(option, ONIG_OPTION_SPACE_IS_ASCII, neg); break;
+ case 'P': OPTION_NEGATE(option, ONIG_OPTION_POSIX_IS_ASCII, neg); break;
+
+ case 'y': /* y{g}, y{w} */
+ {
+ if (! IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_ONIGURUMA))
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+
+ if (neg != 0) return ONIGERR_UNDEFINED_GROUP_OPTION;
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ if (! PPEEK_IS('{')) return ONIGERR_UNDEFINED_GROUP_OPTION;
+ PFETCH(c);
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ switch (c) {
+ case 'g':
+ if (! ONIGENC_IS_UNICODE_ENCODING(enc))
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+
+ OPTION_NEGATE(option, ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER, FALSE);
+ OPTION_NEGATE(option, ONIG_OPTION_TEXT_SEGMENT_WORD, TRUE);
+ break;
+#ifdef USE_UNICODE_WORD_BREAK
+ case 'w':
+ if (! ONIGENC_IS_UNICODE_ENCODING(enc))
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+
+ OPTION_NEGATE(option, ONIG_OPTION_TEXT_SEGMENT_WORD, FALSE);
+ OPTION_NEGATE(option, ONIG_OPTION_TEXT_SEGMENT_EXTENDED_GRAPHEME_CLUSTER, TRUE);
+ break;
+#endif
+ default:
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+ }
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ if (c != '}')
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+ } /* case 'y' */
+
+ default:
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+
+ if (c == ')') {
+ *np = node_new_option(option);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ *src = p;
+ return 2; /* option only */
+ }
+ else if (c == ':') {
+ OnigOptionType prev = env->options;
+
+ env->options = option;
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) return r;
+ r = parse_alts(&target, tok, term, &p, end, env, FALSE);
+ env->options = prev;
+ if (r < 0) {
+ onig_node_free(target);
+ return r;
+ }
+ *np = node_new_option(option);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ NODE_BODY(*np) = target;
+ *src = p;
+ return 0;
+ }
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ } /* while (1) */
+ }
+ break;
+
+ default:
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+ }
+#ifdef USE_CALLOUT
+ else if (c == '*' &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME)) {
+ PINC;
+ r = parse_callout_of_name(np, ')', &p, end, env);
+ if (r != 0) return r;
+
+ goto end;
+ }
+#endif
+ else {
+ if (OPTON_DONT_CAPTURE_GROUP(env->options))
+ goto group;
+
+ *np = node_new_memory(0);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ num = scan_env_add_mem_entry(env);
+ if (num < 0) return num;
+ BAG_(*np)->m.regnum = num;
+ }
+
+ CHECK_NULL_RETURN_MEMERR(*np);
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) return r;
+ r = parse_alts(&target, tok, term, &p, end, env, FALSE);
+ if (r < 0) {
+ onig_node_free(target);
+ return r;
+ }
+
+ NODE_BODY(*np) = target;
+
+ if (NODE_TYPE(*np) == NODE_BAG) {
+ if (BAG_(*np)->type == BAG_MEMORY) {
+ /* Don't move this to previous of parse_alts() */
+ r = scan_env_set_mem_node(env, BAG_(*np)->m.regnum, *np);
+ if (r != 0) return r;
+ }
+ }
+
+ end:
+ *src = p;
+ return 0;
+}
+
+static const char* PopularQStr[] = {
+ "?", "*", "+", "??", "*?", "+?"
+};
+
+static const char* ReduceQStr[] = {
+ "", "", "*", "*?", "??", "+ and ??", "+? and ?"
+};
+
+static int
+assign_quantifier_body(Node* qnode, Node* target, int group, ScanEnv* env)
+{
+ QuantNode* qn;
+
+ qn = QUANT_(qnode);
+ if (qn->lower == 1 && qn->upper == 1)
+ return 1;
+
+ switch (NODE_TYPE(target)) {
+ case NODE_STRING:
+ if (group == 0) {
+ if (str_node_can_be_split(target, env->enc)) {
+ Node* n = str_node_split_last_char(target, env->enc);
+ if (IS_NOT_NULL(n)) {
+ NODE_BODY(qnode) = n;
+ return 2;
+ }
+ }
+ }
+ break;
+
+ case NODE_QUANT:
+ { /* check redundant double repeat. */
+ /* verbose warn (?:.?)? etc... but not warn (.?)? etc... */
+ QuantNode* qnt = QUANT_(target);
+ int nestq_num = quantifier_type_num(qn);
+ int targetq_num = quantifier_type_num(qnt);
+
+#ifdef USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR
+ if (targetq_num >= 0 && nestq_num >= 0 &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT)) {
+ UChar buf[WARN_BUFSIZE];
+
+ switch(ReduceTypeTable[targetq_num][nestq_num]) {
+ case RQ_ASIS:
+ break;
+
+ case RQ_DEL:
+ if (onig_verb_warn != onig_null_warn) {
+ onig_snprintf_with_pattern(buf, WARN_BUFSIZE, env->enc,
+ env->pattern, env->pattern_end,
+ (UChar* )"redundant nested repeat operator");
+ (*onig_verb_warn)((char* )buf);
+ }
+ goto warn_exit;
+ break;
+
+ default:
+ if (onig_verb_warn != onig_null_warn) {
+ onig_snprintf_with_pattern(buf, WARN_BUFSIZE, env->enc,
+ env->pattern, env->pattern_end,
+ (UChar* )"nested repeat operator %s and %s was replaced with '%s'",
+ PopularQStr[targetq_num], PopularQStr[nestq_num],
+ ReduceQStr[ReduceTypeTable[targetq_num][nestq_num]]);
+ (*onig_verb_warn)((char* )buf);
+ }
+ goto warn_exit;
+ break;
+ }
+ }
+
+ warn_exit:
+#endif
+ if (targetq_num >= 0 && nestq_num < 0) {
+ if (targetq_num == 1 || targetq_num == 2) { /* * or + */
+ /* (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n} */
+ if (! IS_INFINITE_REPEAT(qn->upper) && qn->upper > 1 && qn->greedy) {
+ qn->upper = (qn->lower == 0 ? 1 : qn->lower);
+ }
+ }
+ }
+ else {
+ int r;
+
+ NODE_BODY(qnode) = target;
+ r = onig_reduce_nested_quantifier(qnode);
+ return r;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ NODE_BODY(qnode) = target;
+ return 0;
+}
+
+
+#ifndef CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
+static int
+clear_not_flag_cclass(CClassNode* cc, OnigEncoding enc)
+{
+ BBuf *tbuf;
+ int r;
+
+ if (IS_NCCLASS_NOT(cc)) {
+ bitset_invert(cc->bs);
+
+ if (! ONIGENC_IS_SINGLEBYTE(enc)) {
+ r = not_code_range_buf(enc, cc->mbuf, &tbuf);
+ if (r != 0) return r;
+
+ bbuf_free(cc->mbuf);
+ cc->mbuf = tbuf;
+ }
+
+ NCCLASS_CLEAR_NOT(cc);
+ }
+
+ return 0;
+}
+#endif /* CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS */
+
+#define ADD_CODE_INTO_CC(cc, code, enc) do {\
+ if (ONIGENC_MBC_MINLEN(enc) > 1 || ONIGENC_CODE_TO_MBCLEN(enc, code) != 1) {\
+ add_code_range_to_buf(&((cc)->mbuf), code, code);\
+ }\
+ else {\
+ BITSET_SET_BIT((cc)->bs, code);\
+ }\
+} while (0)
+
+extern int
+onig_new_cclass_with_code_list(Node** rnode, OnigEncoding enc,
+ int n, OnigCodePoint codes[])
+{
+ int i;
+ Node* node;
+ CClassNode* cc;
+
+ *rnode = NULL_NODE;
+
+ node = node_new_cclass();
+ CHECK_NULL_RETURN_MEMERR(node);
+
+ cc = CCLASS_(node);
+
+ for (i = 0; i < n; i++) {
+ ADD_CODE_INTO_CC(cc, codes[i], enc);
+ }
+
+ *rnode = node;
+ return 0;
+}
+
+typedef struct {
+ ScanEnv* env;
+ CClassNode* cc;
+ Node* alt_root;
+ Node** ptail;
+} IApplyCaseFoldArg;
+
+static int
+i_apply_case_fold(OnigCodePoint from, OnigCodePoint to[], int to_len, void* arg)
+{
+ IApplyCaseFoldArg* iarg;
+ ScanEnv* env;
+ CClassNode* cc;
+
+ iarg = (IApplyCaseFoldArg* )arg;
+ env = iarg->env;
+ cc = iarg->cc;
+
+ if (to_len == 1) {
+ int is_in = onig_is_code_in_cc(env->enc, from, cc);
+#ifdef CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
+ if ((is_in != 0 && !IS_NCCLASS_NOT(cc)) ||
+ (is_in == 0 && IS_NCCLASS_NOT(cc))) {
+ ADD_CODE_INTO_CC(cc, *to, env->enc);
+ }
+#else
+ if (is_in != 0) {
+ if (ONIGENC_MBC_MINLEN(env->enc) > 1 ||
+ ONIGENC_CODE_TO_MBCLEN(env->enc, *to) != 1) {
+ if (IS_NCCLASS_NOT(cc)) clear_not_flag_cclass(cc, env->enc);
+ add_code_range(&(cc->mbuf), env, *to, *to);
+ }
+ else {
+ if (IS_NCCLASS_NOT(cc)) {
+ BITSET_CLEAR_BIT(cc->bs, *to);
+ }
+ else
+ BITSET_SET_BIT(cc->bs, *to);
+ }
+ }
+#endif /* CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS */
+ }
+ else {
+ int r, i, len;
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
+
+ if (onig_is_code_in_cc(env->enc, from, cc)
+#ifdef CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
+ && !IS_NCCLASS_NOT(cc)
+#endif
+ ) {
+ int n, j, m, index;
+ Node* list_node;
+ Node* ns[3];
+
+ n = 0;
+ for (i = 0; i < to_len; i++) {
+ OnigCodePoint code;
+ Node* csnode;
+ CClassNode* cs_cc;
+
+ index = onigenc_unicode_fold1_key(&to[i]);
+ if (index >= 0) {
+ csnode = node_new_cclass();
+ cs_cc = CCLASS_(csnode);
+ if (IS_NULL(csnode)) {
+ err_free_ns:
+ for (j = 0; j < n; j++) onig_node_free(ns[j]);
+ return ONIGERR_MEMORY;
+ }
+ m = FOLDS1_UNFOLDS_NUM(index);
+ for (j = 0; j < m; j++) {
+ code = FOLDS1_UNFOLDS(index)[j];
+ ADD_CODE_INTO_CC(cs_cc, code, env->enc);
+ }
+ ADD_CODE_INTO_CC(cs_cc, to[i], env->enc);
+ ns[n++] = csnode;
+ }
+ else {
+ len = ONIGENC_CODE_TO_MBC(env->enc, to[i], buf);
+ if (n == 0 || NODE_TYPE(ns[n-1]) != NODE_STRING) {
+ csnode = node_new_str(buf, buf + len);
+ if (IS_NULL(csnode)) goto err_free_ns;
+
+ NODE_STRING_SET_CASE_EXPANDED(csnode);
+ ns[n++] = csnode;
+ }
+ else {
+ r = onig_node_str_cat(ns[n-1], buf, buf + len);
+ if (r < 0) goto err_free_ns;
+ }
+ }
+ }
+
+ if (n == 1)
+ list_node = ns[0];
+ else
+ list_node = make_list(n, ns);
+
+ *(iarg->ptail) = onig_node_new_alt(list_node, NULL_NODE);
+ if (IS_NULL(*(iarg->ptail))) {
+ onig_node_free(list_node);
+ return ONIGERR_MEMORY;
+ }
+ iarg->ptail = &(NODE_CDR((*(iarg->ptail))));
+ }
+ }
+
+ return 0;
+}
+
+static int
+parse_exp(Node** np, PToken* tok, int term, UChar** src, UChar* end,
+ ScanEnv* env, int group_head)
+{
+ int r, len, group;
+ Node* qn;
+ Node** tp;
+ unsigned int parse_depth;
+
+ retry:
+ group = 0;
+ *np = NULL;
+ if (tok->type == (enum TokenSyms )term)
+ goto end_of_token;
+
+ parse_depth = env->parse_depth;
+
+ switch (tok->type) {
+ case TK_ALT:
+ case TK_EOT:
+ end_of_token:
+ *np = node_new_empty();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ return tok->type;
+ break;
+
+ case TK_SUBEXP_OPEN:
+ r = parse_bag(np, tok, TK_SUBEXP_CLOSE, src, end, env);
+ if (r < 0) return r;
+ if (r == 1) { /* group */
+ if (group_head == 0)
+ group = 1;
+ else {
+ Node* target = *np;
+ *np = node_new_group(target);
+ if (IS_NULL(*np)) {
+ onig_node_free(target);
+ return ONIGERR_MEMORY;
+ }
+ group = 2;
+ }
+ }
+ else if (r == 2) { /* option only */
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH)) {
+ env->options = BAG_(*np)->o.options;
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ onig_node_free(*np);
+ goto retry;
+ }
+ else {
+ Node* target;
+ OnigOptionType prev = env->options;
+
+ env->options = BAG_(*np)->o.options;
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ r = parse_alts(&target, tok, term, src, end, env, FALSE);
+ env->options = prev;
+ if (r < 0) {
+ onig_node_free(target);
+ return r;
+ }
+ NODE_BODY(*np) = target;
+ }
+ return tok->type;
+ }
+ break;
+
+ case TK_SUBEXP_CLOSE:
+ if (! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_UNMATCHED_CLOSE_SUBEXP))
+ return ONIGERR_UNMATCHED_CLOSE_PARENTHESIS;
+
+ if (tok->escaped) goto tk_crude_byte;
+ else goto tk_byte;
+ break;
+
+ case TK_STRING:
+ tk_byte:
+ {
+ *np = node_new_str_with_options(tok->backp, *src, env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+
+ while (1) {
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ if (r != TK_STRING) break;
+
+ r = onig_node_str_cat(*np, tok->backp, *src);
+ if (r < 0) return r;
+ }
+
+ string_end:
+ tp = np;
+ goto repeat;
+ }
+ break;
+
+ case TK_CRUDE_BYTE:
+ tk_crude_byte:
+ {
+ *np = node_new_str_crude_char(tok->u.byte, env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ len = 1;
+ while (1) {
+ if (len >= ONIGENC_MBC_MINLEN(env->enc)) {
+ if (len == enclen(env->enc, STR_(*np)->s)) {
+ r = fetch_token(tok, src, end, env);
+ goto tk_crude_byte_end;
+ }
+ }
+
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ if (r != TK_CRUDE_BYTE)
+ return ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+
+ r = node_str_cat_char(*np, tok->u.byte);
+ if (r < 0) return r;
+
+ len++;
+ }
+
+ tk_crude_byte_end:
+ if (! ONIGENC_IS_VALID_MBC_STRING(env->enc, STR_(*np)->s, STR_(*np)->end))
+ return ONIGERR_INVALID_WIDE_CHAR_VALUE;
+
+ NODE_STRING_CLEAR_CRUDE(*np);
+ goto string_end;
+ }
+ break;
+
+ case TK_CODE_POINT:
+ {
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
+ len = ONIGENC_CODE_TO_MBC(env->enc, tok->u.code, buf);
+ if (len < 0) return len;
+#ifdef NUMBERED_CHAR_IS_NOT_CASE_AMBIG
+ *np = node_new_str_crude(buf, buf + len, env->options);
+#else
+ *np = node_new_str_with_options(buf, buf + len, env->options);
+#endif
+ CHECK_NULL_RETURN_MEMERR(*np);
+ }
+ break;
+
+ case TK_QUOTE_OPEN:
+ {
+ OnigCodePoint end_op[2];
+ UChar *qstart, *qend, *nextp;
+
+ end_op[0] = (OnigCodePoint )MC_ESC(env->syntax);
+ end_op[1] = (OnigCodePoint )'E';
+ qstart = *src;
+ qend = find_str_position(end_op, 2, qstart, end, &nextp, env->enc);
+ if (IS_NULL(qend)) {
+ nextp = qend = end;
+ }
+ *np = node_new_str_with_options(qstart, qend, env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ *src = nextp;
+ }
+ break;
+
+ case TK_CHAR_TYPE:
+ {
+ switch (tok->u.prop.ctype) {
+ case ONIGENC_CTYPE_WORD:
+ *np = node_new_ctype(tok->u.prop.ctype, tok->u.prop.not, env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ break;
+
+ case ONIGENC_CTYPE_SPACE:
+ case ONIGENC_CTYPE_DIGIT:
+ case ONIGENC_CTYPE_XDIGIT:
+ {
+ CClassNode* cc;
+
+ *np = node_new_cclass();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ cc = CCLASS_(*np);
+ add_ctype_to_cc(cc, tok->u.prop.ctype, FALSE, env);
+ if (tok->u.prop.not != 0) NCCLASS_SET_NOT(cc);
+ }
+ break;
+
+ default:
+ return ONIGERR_PARSER_BUG;
+ break;
+ }
+ }
+ break;
+
+ case TK_CHAR_PROPERTY:
+ r = parse_char_property(np, tok, src, end, env);
+ if (r != 0) return r;
+ break;
+
+ case TK_OPEN_CC:
+ {
+ CClassNode* cc;
+
+ r = parse_cc(np, tok, src, end, env);
+ if (r != 0) return r;
+
+ cc = CCLASS_(*np);
+ if (OPTON_IGNORECASE(env->options)) {
+ IApplyCaseFoldArg iarg;
+
+ iarg.env = env;
+ iarg.cc = cc;
+ iarg.alt_root = NULL_NODE;
+ iarg.ptail = &(iarg.alt_root);
+
+ r = ONIGENC_APPLY_ALL_CASE_FOLD(env->enc, env->case_fold_flag,
+ i_apply_case_fold, &iarg);
+ if (r != 0) {
+ onig_node_free(iarg.alt_root);
+ return r;
+ }
+ if (IS_NOT_NULL(iarg.alt_root)) {
+ Node* work = onig_node_new_alt(*np, iarg.alt_root);
+ if (IS_NULL(work)) {
+ onig_node_free(iarg.alt_root);
+ return ONIGERR_MEMORY;
+ }
+ *np = work;
+ }
+ }
+ }
+ break;
+
+ case TK_ANYCHAR:
+ *np = node_new_anychar(env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ break;
+
+ case TK_ANYCHAR_ANYTIME:
+ *np = node_new_anychar(env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ qn = node_new_quantifier(0, INFINITE_REPEAT, FALSE);
+ CHECK_NULL_RETURN_MEMERR(qn);
+ NODE_BODY(qn) = *np;
+ *np = qn;
+ break;
+
+ case TK_BACKREF:
+ len = tok->u.backref.num;
+ *np = node_new_backref(len,
+ (len > 1 ? tok->u.backref.refs : &(tok->u.backref.ref1)),
+ tok->u.backref.by_name,
+#ifdef USE_BACKREF_WITH_LEVEL
+ tok->u.backref.exist_level,
+ tok->u.backref.level,
+#endif
+ env);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ break;
+
+#ifdef USE_CALL
+ case TK_CALL:
+ {
+ int gnum = tok->u.call.gnum;
+
+ *np = node_new_call(tok->u.call.name, tok->u.call.name_end,
+ gnum, tok->u.call.by_number);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ env->num_call++;
+ if (tok->u.call.by_number != 0 && gnum == 0) {
+ env->has_call_zero = 1;
+ }
+ }
+ break;
+#endif
+
+ case TK_ANCHOR:
+ *np = node_new_anchor_with_options(tok->u.anchor, env->options);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ break;
+
+ case TK_REPEAT:
+ case TK_INTERVAL:
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS)) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS))
+ return ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED;
+ else {
+ *np = node_new_empty();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ }
+ }
+ else {
+ goto tk_byte;
+ }
+ break;
+
+ case TK_KEEP:
+ r = node_new_keep(np, env);
+ if (r < 0) return r;
+ break;
+
+ case TK_GENERAL_NEWLINE:
+ r = node_new_general_newline(np, env);
+ if (r < 0) return r;
+ break;
+
+ case TK_NO_NEWLINE:
+ r = node_new_no_newline(np, env);
+ if (r < 0) return r;
+ break;
+
+ case TK_TRUE_ANYCHAR:
+ r = node_new_true_anychar(np);
+ if (r < 0) return r;
+ break;
+
+ case TK_TEXT_SEGMENT:
+ r = make_text_segment(np, env);
+ if (r < 0) return r;
+ break;
+
+ default:
+ return ONIGERR_PARSER_BUG;
+ break;
+ }
+
+ {
+ tp = np;
+
+ re_entry:
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+
+ repeat:
+ if (r == TK_REPEAT || r == TK_INTERVAL) {
+ Node* target;
+
+ if (is_invalid_quantifier_target(*tp))
+ return ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID;
+
+ INC_PARSE_DEPTH(parse_depth);
+
+ qn = node_new_quantifier(tok->u.repeat.lower, tok->u.repeat.upper,
+ r == TK_INTERVAL);
+ CHECK_NULL_RETURN_MEMERR(qn);
+ QUANT_(qn)->greedy = tok->u.repeat.greedy;
+ if (group == 2) {
+ target = node_drop_group(*tp);
+ *tp = NULL_NODE;
+ }
+ else {
+ target = *tp;
+ }
+ r = assign_quantifier_body(qn, target, group, env);
+ if (r < 0) {
+ onig_node_free(qn);
+ *tp = NULL_NODE;
+ return r;
+ }
+
+ if (tok->u.repeat.possessive != 0) {
+ Node* en;
+ en = node_new_bag(BAG_STOP_BACKTRACK);
+ if (IS_NULL(en)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ NODE_BODY(en) = qn;
+ qn = en;
+ }
+
+ if (r == 0) {
+ *tp = qn;
+ }
+ else if (r == 1) { /* x{1,1} ==> x */
+ onig_node_free(qn);
+ *tp = target;
+ }
+ else if (r == 2) { /* split case: /abc+/ */
+ Node *tmp;
+
+ *tp = node_new_list(*tp, NULL);
+ if (IS_NULL(*tp)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ tmp = NODE_CDR(*tp) = node_new_list(qn, NULL);
+ if (IS_NULL(tmp)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ tp = &(NODE_CAR(tmp));
+ }
+ group = 0;
+ goto re_entry;
+ }
+ }
+
+ return r;
+}
+
+static int
+parse_branch(Node** top, PToken* tok, int term, UChar** src, UChar* end,
+ ScanEnv* env, int group_head)
+{
+ int r;
+ Node *node, **headp;
+
+ *top = NULL;
+ INC_PARSE_DEPTH(env->parse_depth);
+
+ r = parse_exp(&node, tok, term, src, end, env, group_head);
+ if (r < 0) {
+ onig_node_free(node);
+ return r;
+ }
+
+ if (r == TK_EOT || r == term || r == TK_ALT) {
+ *top = node;
+ }
+ else {
+ *top = node_new_list(node, NULL);
+ if (IS_NULL(*top)) {
+ onig_node_free(node);
+ return ONIGERR_MEMORY;
+ }
+
+ headp = &(NODE_CDR(*top));
+ while (r != TK_EOT && r != term && r != TK_ALT) {
+ r = parse_exp(&node, tok, term, src, end, env, FALSE);
+ if (r < 0) {
+ onig_node_free(node);
+ return r;
+ }
+
+ if (NODE_TYPE(node) == NODE_LIST) {
+ *headp = node;
+ while (IS_NOT_NULL(NODE_CDR(node))) node = NODE_CDR(node);
+ headp = &(NODE_CDR(node));
+ }
+ else {
+ *headp = node_new_list(node, NULL);
+ headp = &(NODE_CDR(*headp));
+ }
+ }
+ }
+
+ DEC_PARSE_DEPTH(env->parse_depth);
+ return r;
+}
+
+/* term_tok: TK_EOT or TK_SUBEXP_CLOSE */
+static int
+parse_alts(Node** top, PToken* tok, int term, UChar** src, UChar* end,
+ ScanEnv* env, int group_head)
+{
+ int r;
+ Node *node, **headp;
+ OnigOptionType save_options;
+
+ *top = NULL;
+ INC_PARSE_DEPTH(env->parse_depth);
+ save_options = env->options;
+
+ r = parse_branch(&node, tok, term, src, end, env, group_head);
+ if (r < 0) {
+ onig_node_free(node);
+ return r;
+ }
+
+ if (r == term) {
+ *top = node;
+ }
+ else if (r == TK_ALT) {
+ *top = onig_node_new_alt(node, NULL);
+ if (IS_NULL(*top)) {
+ onig_node_free(node);
+ return ONIGERR_MEMORY;
+ }
+
+ headp = &(NODE_CDR(*top));
+ while (r == TK_ALT) {
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ r = parse_branch(&node, tok, term, src, end, env, FALSE);
+ if (r < 0) {
+ onig_node_free(node);
+ return r;
+ }
+ *headp = onig_node_new_alt(node, NULL);
+ if (IS_NULL(*headp)) {
+ onig_node_free(node);
+ onig_node_free(*top);
+ return ONIGERR_MEMORY;
+ }
+
+ headp = &(NODE_CDR(*headp));
+ }
+
+ if (tok->type != (enum TokenSyms )term)
+ goto err;
+ }
+ else {
+ onig_node_free(node);
+ err:
+ if (term == TK_SUBEXP_CLOSE)
+ return ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS;
+ else
+ return ONIGERR_PARSER_BUG;
+ }
+
+ env->options = save_options;
+ DEC_PARSE_DEPTH(env->parse_depth);
+ return r;
+}
+
+static int
+parse_regexp(Node** top, UChar** src, UChar* end, ScanEnv* env)
+{
+ int r;
+ PToken tok;
+
+ r = fetch_token(&tok, src, end, env);
+ if (r < 0) return r;
+ r = parse_alts(top, &tok, TK_EOT, src, end, env, FALSE);
+ if (r < 0) return r;
+
+ return 0;
+}
+
+#ifdef USE_CALL
+static int
+make_call_zero_body(Node* node, ScanEnv* env, Node** rnode)
+{
+ int r;
+
+ Node* x = node_new_memory(0 /* 0: is not named */);
+ CHECK_NULL_RETURN_MEMERR(x);
+
+ NODE_BODY(x) = node;
+ BAG_(x)->m.regnum = 0;
+ r = scan_env_set_mem_node(env, 0, x);
+ if (r != 0) {
+ onig_node_free(x);
+ return r;
+ }
+
+ *rnode = x;
+ return 0;
+}
+#endif
+
+extern int
+onig_parse_tree(Node** root, const UChar* pattern, const UChar* end,
+ regex_t* reg, ScanEnv* env)
+{
+ int r;
+ UChar* p;
+#ifdef USE_CALLOUT
+ RegexExt* ext;
+#endif
+
+ names_clear(reg);
+
+ scan_env_clear(env);
+ env->options = reg->options;
+ env->case_fold_flag = reg->case_fold_flag;
+ env->enc = reg->enc;
+ env->syntax = reg->syntax;
+ env->pattern = (UChar* )pattern;
+ env->pattern_end = (UChar* )end;
+ env->reg = reg;
+
+ *root = NULL;
+
+ if (! ONIGENC_IS_VALID_MBC_STRING(env->enc, pattern, end))
+ return ONIGERR_INVALID_WIDE_CHAR_VALUE;
+
+ p = (UChar* )pattern;
+ r = parse_regexp(root, &p, (UChar* )end, env);
+
+#ifdef USE_CALL
+ if (r != 0) return r;
+
+ if (env->has_call_zero != 0) {
+ Node* zero_node;
+ r = make_call_zero_body(*root, env, &zero_node);
+ if (r != 0) return r;
+
+ *root = zero_node;
+ }
+#endif
+
+ reg->num_mem = env->num_mem;
+
+#ifdef USE_CALLOUT
+ ext = reg->extp;
+ if (IS_NOT_NULL(ext) && ext->callout_num > 0) {
+ r = setup_ext_callout_list_values(reg);
+ }
+#endif
+
+ return r;
+}
+
+extern void
+onig_scan_env_set_error_string(ScanEnv* env, int ecode ARG_UNUSED,
+ UChar* arg, UChar* arg_end)
+{
+ env->error = arg;
+ env->error_end = arg_end;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.h
new file mode 100644
index 000000000..979e982f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regparse.h
@@ -0,0 +1,475 @@
+#ifndef REGPARSE_H
+#define REGPARSE_H
+/**********************************************************************
+ regparse.h - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+#define NODE_STRING_MARGIN 16
+#define NODE_STRING_BUF_SIZE 24 /* sizeof(CClassNode) - sizeof(int)*4 */
+#define NODE_BACKREFS_SIZE 6
+
+/* node type */
+typedef enum {
+ NODE_STRING = 0,
+ NODE_CCLASS = 1,
+ NODE_CTYPE = 2,
+ NODE_BACKREF = 3,
+ NODE_QUANT = 4,
+ NODE_BAG = 5,
+ NODE_ANCHOR = 6,
+ NODE_LIST = 7,
+ NODE_ALT = 8,
+ NODE_CALL = 9,
+ NODE_GIMMICK = 10
+} NodeType;
+
+enum BagType {
+ BAG_MEMORY = 0,
+ BAG_OPTION = 1,
+ BAG_STOP_BACKTRACK = 2,
+ BAG_IF_ELSE = 3,
+};
+
+enum GimmickType {
+ GIMMICK_FAIL = 0,
+ GIMMICK_SAVE = 1,
+ GIMMICK_UPDATE_VAR = 2,
+#ifdef USE_CALLOUT
+ GIMMICK_CALLOUT = 3,
+#endif
+};
+
+enum BodyEmptyType {
+ BODY_IS_NOT_EMPTY = 0,
+ BODY_MAY_BE_EMPTY = 1,
+ BODY_MAY_BE_EMPTY_MEM = 2,
+ BODY_MAY_BE_EMPTY_REC = 3
+};
+
+struct _Node;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ UChar* s;
+ UChar* end;
+ unsigned int flag;
+ UChar buf[NODE_STRING_BUF_SIZE];
+ int capacity; /* (allocated size - 1) or 0: use buf[] */
+} StrNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ unsigned int flags;
+ BitSet bs;
+ BBuf* mbuf; /* multi-byte info or NULL */
+} CClassNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+ struct _Node* body;
+
+ int lower;
+ int upper;
+ int greedy;
+ enum BodyEmptyType emptiness;
+ struct _Node* head_exact;
+ struct _Node* next_head_exact;
+ int include_referred; /* include called node. don't eliminate even if {0} */
+} QuantNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+ struct _Node* body;
+
+ enum BagType type;
+ union {
+ struct {
+ int regnum;
+ AbsAddrType called_addr;
+ int entry_count;
+ int called_state;
+ } m;
+ struct {
+ OnigOptionType options;
+ } o;
+ struct {
+ /* body is condition */
+ struct _Node* Then;
+ struct _Node* Else;
+ } te;
+ };
+ /* for multiple call reference */
+ OnigLen min_len; /* min length (byte) */
+ OnigLen max_len; /* max length (byte) */
+ OnigLen min_char_len;
+ OnigLen max_char_len;
+ int opt_count; /* referenced count in optimize_nodes() */
+} BagNode;
+
+#ifdef USE_CALL
+
+typedef struct {
+ int offset;
+ struct _Node* target;
+} UnsetAddr;
+
+typedef struct {
+ int num;
+ int alloc;
+ UnsetAddr* us;
+} UnsetAddrList;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+ struct _Node* body; /* to BagNode : BAG_MEMORY */
+
+ int by_number;
+ int group_num;
+ UChar* name;
+ UChar* name_end;
+ int entry_count;
+} CallNode;
+
+#endif
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ int back_num;
+ int back_static[NODE_BACKREFS_SIZE];
+ int* back_dynamic;
+ int nest_level;
+} BackRefNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+ struct _Node* body;
+
+ int type;
+ OnigLen char_min_len;
+ OnigLen char_max_len;
+ int ascii_mode;
+ struct _Node* lead_node;
+} AnchorNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ struct _Node* car;
+ struct _Node* cdr;
+} ConsAltNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ int ctype;
+ int not;
+ int ascii_mode;
+} CtypeNode;
+
+typedef struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+
+ enum GimmickType type;
+ int detail_type;
+ int num;
+ int id;
+} GimmickNode;
+
+typedef struct _Node {
+ union {
+ struct {
+ NodeType node_type;
+ int status;
+ struct _Node* parent;
+ struct _Node* body;
+ } base;
+
+ StrNode str;
+ CClassNode cclass;
+ QuantNode quant;
+ BagNode bag;
+ BackRefNode backref;
+ AnchorNode anchor;
+ ConsAltNode cons;
+ CtypeNode ctype;
+#ifdef USE_CALL
+ CallNode call;
+#endif
+ GimmickNode gimmick;
+ } u;
+} Node;
+
+typedef struct {
+ int new_val;
+} GroupNumMap;
+
+
+#define NULL_NODE ((Node* )0)
+
+
+/* node type bit */
+#define NODE_TYPE2BIT(type) (1<<(type))
+
+#define NODE_BIT_STRING NODE_TYPE2BIT(NODE_STRING)
+#define NODE_BIT_CCLASS NODE_TYPE2BIT(NODE_CCLASS)
+#define NODE_BIT_CTYPE NODE_TYPE2BIT(NODE_CTYPE)
+#define NODE_BIT_BACKREF NODE_TYPE2BIT(NODE_BACKREF)
+#define NODE_BIT_QUANT NODE_TYPE2BIT(NODE_QUANT)
+#define NODE_BIT_BAG NODE_TYPE2BIT(NODE_BAG)
+#define NODE_BIT_ANCHOR NODE_TYPE2BIT(NODE_ANCHOR)
+#define NODE_BIT_LIST NODE_TYPE2BIT(NODE_LIST)
+#define NODE_BIT_ALT NODE_TYPE2BIT(NODE_ALT)
+#define NODE_BIT_CALL NODE_TYPE2BIT(NODE_CALL)
+#define NODE_BIT_GIMMICK NODE_TYPE2BIT(NODE_GIMMICK)
+
+#define NODE_TYPE(node) ((node)->u.base.node_type)
+#define NODE_SET_TYPE(node, ntype) (node)->u.base.node_type = (ntype)
+
+#define STR_(node) (&((node)->u.str))
+#define CCLASS_(node) (&((node)->u.cclass))
+#define CTYPE_(node) (&((node)->u.ctype))
+#define BACKREF_(node) (&((node)->u.backref))
+#define QUANT_(node) (&((node)->u.quant))
+#define BAG_(node) (&((node)->u.bag))
+#define ANCHOR_(node) (&((node)->u.anchor))
+#define CONS_(node) (&((node)->u.cons))
+#define CALL_(node) (&((node)->u.call))
+#define GIMMICK_(node) (&((node)->u.gimmick))
+
+#define NODE_CAR(node) (CONS_(node)->car)
+#define NODE_CDR(node) (CONS_(node)->cdr)
+
+#define CTYPE_ANYCHAR -1
+#define NODE_IS_ANYCHAR(node) \
+ (NODE_TYPE(node) == NODE_CTYPE && CTYPE_(node)->ctype == CTYPE_ANYCHAR)
+
+
+#define ANCR_ANYCHAR_INF_MASK (ANCR_ANYCHAR_INF | ANCR_ANYCHAR_INF_ML)
+#define ANCR_END_BUF_MASK (ANCR_END_BUF | ANCR_SEMI_END_BUF)
+
+#define NODE_STRING_CRUDE (1<<0)
+#define NODE_STRING_CASE_EXPANDED (1<<1)
+
+#define NODE_STRING_LEN(node) (int )((node)->u.str.end - (node)->u.str.s)
+#define NODE_STRING_SET_CRUDE(node) (node)->u.str.flag |= NODE_STRING_CRUDE
+#define NODE_STRING_CLEAR_CRUDE(node) (node)->u.str.flag &= ~NODE_STRING_CRUDE
+#define NODE_STRING_SET_CASE_EXPANDED(node) (node)->u.str.flag |= NODE_STRING_CASE_EXPANDED
+#define NODE_STRING_IS_CRUDE(node) \
+ (((node)->u.str.flag & NODE_STRING_CRUDE) != 0)
+#define NODE_STRING_IS_CASE_EXPANDED(node) \
+ (((node)->u.str.flag & NODE_STRING_CASE_EXPANDED) != 0)
+
+#define BACKREFS_P(br) \
+ (IS_NOT_NULL((br)->back_dynamic) ? (br)->back_dynamic : (br)->back_static)
+
+/* node status bits */
+#define NODE_ST_FIXED_MIN (1<<0)
+#define NODE_ST_FIXED_MAX (1<<1)
+#define NODE_ST_FIXED_CLEN (1<<2)
+#define NODE_ST_MARK1 (1<<3)
+#define NODE_ST_MARK2 (1<<4)
+#define NODE_ST_STRICT_REAL_REPEAT (1<<5)
+#define NODE_ST_RECURSION (1<<6)
+#define NODE_ST_CALLED (1<<7)
+#define NODE_ST_FIXED_ADDR (1<<8)
+#define NODE_ST_NAMED_GROUP (1<<9)
+#define NODE_ST_IN_REAL_REPEAT (1<<10) /* STK_REPEAT is nested in stack. */
+#define NODE_ST_IN_ZERO_REPEAT (1<<11) /* (....){0} */
+#define NODE_ST_IN_MULTI_ENTRY (1<<12)
+#define NODE_ST_NEST_LEVEL (1<<13)
+#define NODE_ST_BY_NUMBER (1<<14) /* {n,m} */
+#define NODE_ST_BY_NAME (1<<15) /* backref by name */
+#define NODE_ST_BACKREF (1<<16)
+#define NODE_ST_CHECKER (1<<17)
+#define NODE_ST_PROHIBIT_RECURSION (1<<18)
+#define NODE_ST_SUPER (1<<19)
+#define NODE_ST_EMPTY_STATUS_CHECK (1<<20)
+#define NODE_ST_IGNORECASE (1<<21)
+#define NODE_ST_MULTILINE (1<<22)
+#define NODE_ST_TEXT_SEGMENT_WORD (1<<23)
+#define NODE_ST_ABSENT_WITH_SIDE_EFFECTS (1<<24) /* stopper or clear */
+#define NODE_ST_FIXED_CLEN_MIN_SURE (1<<25)
+
+
+#define NODE_STATUS(node) (((Node* )node)->u.base.status)
+#define NODE_STATUS_ADD(node,f) (NODE_STATUS(node) |= (NODE_ST_ ## f))
+#define NODE_STATUS_REMOVE(node,f) (NODE_STATUS(node) &= ~(NODE_ST_ ## f))
+
+#define NODE_IS_BY_NUMBER(node) ((NODE_STATUS(node) & NODE_ST_BY_NUMBER) != 0)
+#define NODE_IS_IN_REAL_REPEAT(node) ((NODE_STATUS(node) & NODE_ST_IN_REAL_REPEAT) != 0)
+#define NODE_IS_CALLED(node) ((NODE_STATUS(node) & NODE_ST_CALLED) != 0)
+#define NODE_IS_IN_MULTI_ENTRY(node) ((NODE_STATUS(node) & NODE_ST_IN_MULTI_ENTRY) != 0)
+#define NODE_IS_RECURSION(node) ((NODE_STATUS(node) & NODE_ST_RECURSION) != 0)
+#define NODE_IS_IN_ZERO_REPEAT(node) ((NODE_STATUS(node) & NODE_ST_IN_ZERO_REPEAT) != 0)
+#define NODE_IS_NAMED_GROUP(node) ((NODE_STATUS(node) & NODE_ST_NAMED_GROUP) != 0)
+#define NODE_IS_FIXED_ADDR(node) ((NODE_STATUS(node) & NODE_ST_FIXED_ADDR) != 0)
+#define NODE_IS_FIXED_CLEN(node) ((NODE_STATUS(node) & NODE_ST_FIXED_CLEN) != 0)
+#define NODE_IS_FIXED_MIN(node) ((NODE_STATUS(node) & NODE_ST_FIXED_MIN) != 0)
+#define NODE_IS_FIXED_MAX(node) ((NODE_STATUS(node) & NODE_ST_FIXED_MAX) != 0)
+#define NODE_IS_MARK1(node) ((NODE_STATUS(node) & NODE_ST_MARK1) != 0)
+#define NODE_IS_MARK2(node) ((NODE_STATUS(node) & NODE_ST_MARK2) != 0)
+#define NODE_IS_NEST_LEVEL(node) ((NODE_STATUS(node) & NODE_ST_NEST_LEVEL) != 0)
+#define NODE_IS_BY_NAME(node) ((NODE_STATUS(node) & NODE_ST_BY_NAME) != 0)
+#define NODE_IS_BACKREF(node) ((NODE_STATUS(node) & NODE_ST_BACKREF) != 0)
+#define NODE_IS_CHECKER(node) ((NODE_STATUS(node) & NODE_ST_CHECKER) != 0)
+#define NODE_IS_SUPER(node) ((NODE_STATUS(node) & NODE_ST_SUPER) != 0)
+#define NODE_IS_PROHIBIT_RECURSION(node) \
+ ((NODE_STATUS(node) & NODE_ST_PROHIBIT_RECURSION) != 0)
+#define NODE_IS_STRICT_REAL_REPEAT(node) \
+ ((NODE_STATUS(node) & NODE_ST_STRICT_REAL_REPEAT) != 0)
+#define NODE_IS_EMPTY_STATUS_CHECK(node) \
+ ((NODE_STATUS(node) & NODE_ST_EMPTY_STATUS_CHECK) != 0)
+#define NODE_IS_IGNORECASE(node) ((NODE_STATUS(node) & NODE_ST_IGNORECASE) != 0)
+#define NODE_IS_MULTILINE(node) ((NODE_STATUS(node) & NODE_ST_MULTILINE) != 0)
+#define NODE_IS_TEXT_SEGMENT_WORD(node) ((NODE_STATUS(node) & NODE_ST_TEXT_SEGMENT_WORD) != 0)
+#define NODE_IS_ABSENT_WITH_SIDE_EFFECTS(node) ((NODE_STATUS(node) & NODE_ST_ABSENT_WITH_SIDE_EFFECTS) != 0)
+#define NODE_IS_FIXED_CLEN_MIN_SURE(node) ((NODE_STATUS(node) & NODE_ST_FIXED_CLEN_MIN_SURE) != 0)
+
+#define NODE_PARENT(node) ((node)->u.base.parent)
+#define NODE_BODY(node) ((node)->u.base.body)
+#define NODE_QUANT_BODY(node) ((node)->body)
+#define NODE_BAG_BODY(node) ((node)->body)
+#define NODE_CALL_BODY(node) ((node)->body)
+#define NODE_ANCHOR_BODY(node) ((node)->body)
+
+#define SCANENV_MEMENV_SIZE 8
+#define SCANENV_MEMENV(senv) \
+ (IS_NOT_NULL((senv)->mem_env_dynamic) ? \
+ (senv)->mem_env_dynamic : (senv)->mem_env_static)
+
+#define IS_SYNTAX_OP(syn, opm) (((syn)->op & (opm)) != 0)
+#define IS_SYNTAX_OP2(syn, opm) (((syn)->op2 & (opm)) != 0)
+#define IS_SYNTAX_BV(syn, bvm) (((syn)->behavior & (bvm)) != 0)
+
+#define ID_ENTRY(env, id) do {\
+ id = (env)->id_num++;\
+} while(0)
+
+
+typedef struct {
+ Node* mem_node;
+ Node* empty_repeat_node;
+} MemEnv;
+
+typedef struct {
+ enum SaveType type;
+} SaveItem;
+
+typedef struct {
+ OnigOptionType options;
+ OnigCaseFoldType case_fold_flag;
+ OnigEncoding enc;
+ OnigSyntaxType* syntax;
+ MemStatusType cap_history;
+ MemStatusType backtrack_mem; /* backtrack/recursion */
+ MemStatusType backrefed_mem;
+ UChar* pattern;
+ UChar* pattern_end;
+ UChar* error;
+ UChar* error_end;
+ regex_t* reg; /* for reg->names only */
+ int num_call;
+ int num_mem;
+ int num_named;
+ int mem_alloc;
+ MemEnv mem_env_static[SCANENV_MEMENV_SIZE];
+ MemEnv* mem_env_dynamic;
+ int backref_num;
+ int keep_num;
+ int id_num;
+ int save_alloc_num;
+ SaveItem* saves;
+#ifdef USE_CALL
+ UnsetAddrList* unset_addr_list;
+ int has_call_zero;
+#endif
+ unsigned int parse_depth;
+#ifdef ONIG_DEBUG_PARSE
+ unsigned int max_parse_depth;
+#endif
+} ScanEnv;
+
+
+extern int onig_renumber_name_table P_((regex_t* reg, GroupNumMap* map));
+
+extern int onig_strncmp P_((const UChar* s1, const UChar* s2, int n));
+extern void onig_strcpy P_((UChar* dest, const UChar* src, const UChar* end));
+extern void onig_scan_env_set_error_string P_((ScanEnv* env, int ecode, UChar* arg, UChar* arg_end));
+extern int onig_reduce_nested_quantifier P_((Node* pnode));
+extern int onig_node_copy(Node** rcopy, Node* from);
+extern int onig_node_str_cat P_((Node* node, const UChar* s, const UChar* end));
+extern int onig_node_str_set P_((Node* node, const UChar* s, const UChar* end, int need_free));
+extern void onig_node_str_clear P_((Node* node, int need_free));
+extern void onig_node_free P_((Node* node));
+extern int onig_node_reset_empty P_((Node* node));
+extern int onig_node_reset_fail P_((Node* node));
+extern Node* onig_node_new_bag P_((enum BagType type));
+extern Node* onig_node_new_str P_((const UChar* s, const UChar* end));
+extern Node* onig_node_new_list P_((Node* left, Node* right));
+extern Node* onig_node_new_alt P_((Node* left, Node* right));
+extern int onig_names_free P_((regex_t* reg));
+extern int onig_parse_tree P_((Node** root, const UChar* pattern, const UChar* end, regex_t* reg, ScanEnv* env));
+extern int onig_free_shared_cclass_table P_((void));
+extern int onig_is_code_in_cc P_((OnigEncoding enc, OnigCodePoint code, CClassNode* cc));
+extern int onig_new_cclass_with_code_list(Node** rnode, OnigEncoding enc, int n, OnigCodePoint codes[]);
+extern OnigLen onig_get_tiny_min_len(Node* node, unsigned int inhibit_node_types, int* invalid_node);
+
+#ifdef USE_CALLOUT
+extern int onig_global_callout_names_free(void);
+#endif
+
+#ifdef ONIG_DEBUG
+extern int onig_print_names(FILE*, regex_t*);
+#endif
+
+#endif /* REGPARSE_H */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposerr.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposerr.c
new file mode 100644
index 000000000..12d95a9bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposerr.c
@@ -0,0 +1,123 @@
+/**********************************************************************
+ regposerr.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+/* Can't include regint.h etc.. for conflict of regex_t.
+ Define ONIGURUMA_EXPORT here for onigposix.h.
+ */
+#ifndef ONIGURUMA_EXPORT
+#define ONIGURUMA_EXPORT
+#endif
+
+#include "config.h"
+#include "onigposix.h"
+
+#ifndef ONIG_NO_STANDARD_C_HEADERS
+#include <string.h>
+#include <stdio.h>
+#endif
+
+#if defined(__GNUC__)
+# define ARG_UNUSED __attribute__ ((unused))
+#else
+# define ARG_UNUSED
+#endif
+
+#if defined(_WIN32) && !defined(__GNUC__)
+
+#ifndef xsnprintf
+#define xsnprintf sprintf_s
+#endif
+#ifndef xstrncpy
+#define xstrncpy(dest,src,size) strncpy_s(dest,size,src,_TRUNCATE)
+#endif
+
+#else
+
+#ifndef xsnprintf
+#define xsnprintf snprintf
+#endif
+#ifndef xstrncpy
+#define xstrncpy strncpy
+#endif
+
+#endif
+
+
+static char* ESTRING[] = {
+ NULL,
+ "failed to match", /* REG_NOMATCH */
+ "Invalid regular expression", /* REG_BADPAT */
+ "invalid collating element referenced", /* REG_ECOLLATE */
+ "invalid character class type referenced", /* REG_ECTYPE */
+ "bad backslash-escape sequence", /* REG_EESCAPE */
+ "invalid back reference number", /* REG_ESUBREG */
+ "imbalanced [ and ]", /* REG_EBRACK */
+ "imbalanced ( and )", /* REG_EPAREN */
+ "imbalanced { and }", /* REG_EBRACE */
+ "invalid repeat range {n,m}", /* REG_BADBR */
+ "invalid range", /* REG_ERANGE */
+ "Out of memory", /* REG_ESPACE */
+ "? * + not preceded by valid regular expression", /* REG_BADRPT */
+
+ /* Extended errors */
+ "internal error", /* REG_EONIG_INTERNAL */
+ "invalid wide char value", /* REG_EONIG_BADWC */
+ "invalid argument" /* REG_EONIG_BADARG */
+};
+
+
+
+extern size_t
+regerror(int posix_ecode, const regex_t* reg ARG_UNUSED, char* buf,
+ size_t size)
+{
+ char* s;
+ char tbuf[35];
+ size_t len;
+
+ if (posix_ecode > 0
+ && posix_ecode < (int )(sizeof(ESTRING) / sizeof(ESTRING[0]))) {
+ s = ESTRING[posix_ecode];
+ }
+ else if (posix_ecode == 0) {
+ s = "";
+ }
+ else {
+ xsnprintf(tbuf, sizeof(tbuf), "undefined error code (%d)", posix_ecode);
+ s = tbuf;
+ }
+
+ len = strlen(s) + 1; /* use strlen() because s is ascii encoding. */
+
+ if (buf != NULL && size > 0) {
+ xstrncpy(buf, s, size - 1);
+ buf[size - 1] = '\0';
+ }
+ return len;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposix.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposix.c
new file mode 100644
index 000000000..4e523a417
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regposix.c
@@ -0,0 +1,321 @@
+/**********************************************************************
+ regposix.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#define regex_t onig_regex_t
+#include "regint.h"
+#undef regex_t
+
+#include "onigposix.h"
+
+#define ONIG_C(reg) ((onig_regex_t* )((reg)->onig))
+#define PONIG_C(reg) ((onig_regex_t** )(&(reg)->onig))
+
+/* #define ENC_STRING_LEN(enc,s,len) len = strlen(s) */
+#define ENC_STRING_LEN(enc,s,len) do { \
+ if (ONIGENC_MBC_MINLEN(enc) == 1) { \
+ UChar* tmps = (UChar* )(s); \
+ while (*tmps != 0) tmps++; \
+ len = (int )(tmps - (UChar* )(s));\
+ } \
+ else { \
+ len = onigenc_str_bytelen_null(enc, (UChar* )s); \
+ } \
+} while(0)
+
+typedef struct {
+ int onig_err;
+ int posix_err;
+} O2PERR;
+
+static int
+onig2posix_error_code(int code)
+{
+ static const O2PERR o2p[] = {
+ { ONIG_MISMATCH, REG_NOMATCH },
+ { ONIG_NO_SUPPORT_CONFIG, REG_EONIG_INTERNAL },
+ { ONIG_ABORT, REG_EONIG_INTERNAL },
+ { ONIGERR_MEMORY, REG_ESPACE },
+ { ONIGERR_MATCH_STACK_LIMIT_OVER, REG_EONIG_INTERNAL },
+ { ONIGERR_RETRY_LIMIT_IN_MATCH_OVER, REG_EONIG_INTERNAL },
+ { ONIGERR_RETRY_LIMIT_IN_SEARCH_OVER, REG_EONIG_INTERNAL },
+ { ONIGERR_TYPE_BUG, REG_EONIG_INTERNAL },
+ { ONIGERR_PARSER_BUG, REG_EONIG_INTERNAL },
+ { ONIGERR_STACK_BUG, REG_EONIG_INTERNAL },
+ { ONIGERR_UNDEFINED_BYTECODE, REG_EONIG_INTERNAL },
+ { ONIGERR_UNEXPECTED_BYTECODE, REG_EONIG_INTERNAL },
+ { ONIGERR_DEFAULT_ENCODING_IS_NOT_SETTED, REG_EONIG_BADARG },
+ { ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR, REG_EONIG_BADARG },
+ { ONIGERR_FAIL_TO_INITIALIZE, REG_EONIG_INTERNAL },
+ { ONIGERR_INVALID_ARGUMENT, REG_EONIG_BADARG },
+ { ONIGERR_END_PATTERN_AT_LEFT_BRACE, REG_EBRACE },
+ { ONIGERR_END_PATTERN_AT_LEFT_BRACKET, REG_EBRACK },
+ { ONIGERR_EMPTY_CHAR_CLASS, REG_ECTYPE },
+ { ONIGERR_PREMATURE_END_OF_CHAR_CLASS, REG_ECTYPE },
+ { ONIGERR_END_PATTERN_AT_ESCAPE, REG_EESCAPE },
+ { ONIGERR_END_PATTERN_AT_META, REG_EESCAPE },
+ { ONIGERR_END_PATTERN_AT_CONTROL, REG_EESCAPE },
+ { ONIGERR_META_CODE_SYNTAX, REG_BADPAT },
+ { ONIGERR_CONTROL_CODE_SYNTAX, REG_BADPAT },
+ { ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE, REG_ECTYPE },
+ { ONIGERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE, REG_ECTYPE },
+ { ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS, REG_ECTYPE },
+ { ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED, REG_BADRPT },
+ { ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID, REG_BADRPT },
+ { ONIGERR_NESTED_REPEAT_OPERATOR, REG_BADRPT },
+ { ONIGERR_UNMATCHED_CLOSE_PARENTHESIS, REG_EPAREN },
+ { ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS, REG_EPAREN },
+ { ONIGERR_END_PATTERN_IN_GROUP, REG_BADPAT },
+ { ONIGERR_UNDEFINED_GROUP_OPTION, REG_BADPAT },
+ { ONIGERR_INVALID_POSIX_BRACKET_TYPE, REG_BADPAT },
+ { ONIGERR_INVALID_LOOK_BEHIND_PATTERN, REG_BADPAT },
+ { ONIGERR_INVALID_REPEAT_RANGE_PATTERN, REG_BADPAT },
+ { ONIGERR_TOO_BIG_NUMBER, REG_BADPAT },
+ { ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE, REG_BADBR },
+ { ONIGERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE, REG_BADBR },
+ { ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS, REG_ECTYPE },
+ { ONIGERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE, REG_ECTYPE },
+ { ONIGERR_TOO_MANY_MULTI_BYTE_RANGES, REG_ECTYPE },
+ { ONIGERR_TOO_SHORT_MULTI_BYTE_STRING, REG_BADPAT },
+ { ONIGERR_TOO_BIG_BACKREF_NUMBER, REG_ESUBREG },
+ { ONIGERR_INVALID_BACKREF, REG_ESUBREG },
+ { ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED, REG_BADPAT },
+ { ONIGERR_TOO_BIG_WIDE_CHAR_VALUE, REG_EONIG_BADWC },
+ { ONIGERR_TOO_LONG_WIDE_CHAR_VALUE, REG_EONIG_BADWC },
+ { ONIGERR_INVALID_CODE_POINT_VALUE, REG_EONIG_BADWC },
+ { ONIGERR_EMPTY_GROUP_NAME, REG_BADPAT },
+ { ONIGERR_INVALID_GROUP_NAME, REG_BADPAT },
+ { ONIGERR_INVALID_CHAR_IN_GROUP_NAME, REG_BADPAT },
+ { ONIGERR_UNDEFINED_NAME_REFERENCE, REG_BADPAT },
+ { ONIGERR_UNDEFINED_GROUP_REFERENCE, REG_BADPAT },
+ { ONIGERR_MULTIPLEX_DEFINED_NAME, REG_BADPAT },
+ { ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL, REG_BADPAT },
+ { ONIGERR_NEVER_ENDING_RECURSION, REG_BADPAT },
+ { ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY, REG_BADPAT },
+ { ONIGERR_INVALID_CHAR_PROPERTY_NAME, REG_BADPAT },
+ { ONIGERR_INVALID_IF_ELSE_SYNTAX, REG_BADPAT },
+ { ONIGERR_INVALID_ABSENT_GROUP_PATTERN, REG_BADPAT },
+ { ONIGERR_INVALID_ABSENT_GROUP_GENERATOR_PATTERN, REG_BADPAT },
+ { ONIGERR_INVALID_CALLOUT_PATTERN, REG_BADPAT },
+ { ONIGERR_INVALID_CALLOUT_NAME, REG_BADPAT },
+ { ONIGERR_UNDEFINED_CALLOUT_NAME, REG_BADPAT },
+ { ONIGERR_INVALID_CALLOUT_BODY, REG_BADPAT },
+ { ONIGERR_INVALID_CALLOUT_TAG_NAME, REG_BADPAT },
+ { ONIGERR_INVALID_CALLOUT_ARG, REG_BADPAT },
+ { ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION, REG_EONIG_BADARG },
+ { ONIGERR_LIBRARY_IS_NOT_INITIALIZED, REG_EONIG_INTERNAL }
+ };
+
+ int i;
+
+ if (code >= 0) return 0;
+
+ for (i = 0; i < (int )(sizeof(o2p) / sizeof(o2p[0])); i++) {
+ if (code == o2p[i].onig_err)
+ return o2p[i].posix_err;
+ }
+
+ return REG_EONIG_INTERNAL; /* but, unknown error code */
+}
+
+extern int
+regcomp(regex_t* reg, const char* pattern, int posix_options)
+{
+ int r, len;
+ OnigSyntaxType* syntax = OnigDefaultSyntax;
+ OnigOptionType options;
+
+ reg->onig = (void* )0;
+
+ if ((posix_options & REG_EXTENDED) == 0)
+ syntax = ONIG_SYNTAX_POSIX_BASIC;
+
+ options = syntax->options;
+ if ((posix_options & REG_ICASE) != 0)
+ ONIG_OPTION_ON(options, ONIG_OPTION_IGNORECASE);
+ if ((posix_options & REG_NEWLINE) != 0) {
+ ONIG_OPTION_ON( options, ONIG_OPTION_NEGATE_SINGLELINE);
+ ONIG_OPTION_OFF(options, ONIG_OPTION_SINGLELINE);
+ }
+
+ reg->comp_options = posix_options;
+
+ ENC_STRING_LEN(OnigEncDefaultCharEncoding, pattern, len);
+ r = onig_new(PONIG_C(reg), (UChar* )pattern, (UChar* )(pattern + len),
+ options, OnigEncDefaultCharEncoding, syntax,
+ (OnigErrorInfo* )NULL);
+ if (r != ONIG_NORMAL) {
+ return onig2posix_error_code(r);
+ }
+
+ reg->re_nsub = ONIG_C(reg)->num_mem;
+ return 0;
+}
+
+extern int
+regexec(regex_t* reg, const char* str, size_t nmatch,
+ regmatch_t pmatch[], int posix_options)
+{
+ int r, i, len;
+ UChar* end;
+ regmatch_t* pm;
+ OnigOptionType options;
+
+ options = ONIG_OPTION_POSIX_REGION;
+ if ((posix_options & REG_NOTBOL) != 0) options |= ONIG_OPTION_NOTBOL;
+ if ((posix_options & REG_NOTEOL) != 0) options |= ONIG_OPTION_NOTEOL;
+
+ if (nmatch == 0 || (reg->comp_options & REG_NOSUB) != 0) {
+ pm = (regmatch_t* )NULL;
+ nmatch = 0;
+ }
+ else if ((int )nmatch < ONIG_C(reg)->num_mem + 1) {
+ pm = (regmatch_t* )xmalloc(sizeof(regmatch_t)
+ * (ONIG_C(reg)->num_mem + 1));
+ if (pm == NULL)
+ return REG_ESPACE;
+ }
+ else {
+ pm = pmatch;
+ }
+
+ ENC_STRING_LEN(ONIG_C(reg)->enc, str, len);
+ end = (UChar* )(str + len);
+ r = onig_search(ONIG_C(reg), (UChar* )str, end, (UChar* )str, end,
+ (OnigRegion* )pm, options);
+
+ if (r >= 0) {
+ r = 0; /* Match */
+ if (pm != pmatch && pm != NULL) {
+ xmemcpy(pmatch, pm, sizeof(regmatch_t) * nmatch);
+ }
+ }
+ else if (r == ONIG_MISMATCH) {
+ r = REG_NOMATCH;
+ for (i = 0; i < (int )nmatch; i++)
+ pmatch[i].rm_so = pmatch[i].rm_eo = ONIG_REGION_NOTPOS;
+ }
+ else {
+ r = onig2posix_error_code(r);
+ }
+
+ if (pm != pmatch && pm != NULL)
+ xfree(pm);
+
+#if 0
+ if (reg->re_nsub > nmatch - 1)
+ reg->re_nsub = (nmatch <= 1 ? 0 : nmatch - 1);
+#endif
+
+ return r;
+}
+
+extern void
+regfree(regex_t* reg)
+{
+ onig_free(ONIG_C(reg));
+ reg->onig = (void* )0;
+}
+
+
+extern void
+reg_set_encoding(int mb_code)
+{
+ OnigEncoding enc;
+
+ switch (mb_code) {
+ case REG_POSIX_ENCODING_ASCII:
+ enc = ONIG_ENCODING_ASCII;
+ break;
+ case REG_POSIX_ENCODING_EUC_JP:
+ enc = ONIG_ENCODING_EUC_JP;
+ break;
+ case REG_POSIX_ENCODING_SJIS:
+ enc = ONIG_ENCODING_SJIS;
+ break;
+ case REG_POSIX_ENCODING_UTF8:
+ enc = ONIG_ENCODING_UTF8;
+ break;
+ case REG_POSIX_ENCODING_UTF16_BE:
+ enc = ONIG_ENCODING_UTF16_BE;
+ break;
+ case REG_POSIX_ENCODING_UTF16_LE:
+ enc = ONIG_ENCODING_UTF16_LE;
+ break;
+
+ default:
+ return ;
+ break;
+ }
+
+ onig_initialize(&enc, 1);
+
+ onigenc_set_default_encoding(enc);
+}
+
+extern int
+reg_name_to_group_numbers(regex_t* reg,
+ const unsigned char* name, const unsigned char* name_end, int** nums)
+{
+ return onig_name_to_group_numbers(ONIG_C(reg), name, name_end, nums);
+}
+
+typedef struct {
+ int (*func)(const unsigned char*, const unsigned char*,int,int*,regex_t*,void*);
+ regex_t* reg;
+ void* arg;
+} i_wrap;
+
+static int
+i_wrapper(const UChar* name, const UChar* name_end, int ng, int* gs,
+ onig_regex_t* reg ARG_UNUSED, void* arg)
+{
+ i_wrap* warg = (i_wrap* )arg;
+
+ return (*warg->func)(name, name_end, ng, gs, warg->reg, warg->arg);
+}
+
+extern int
+reg_foreach_name(regex_t* reg,
+ int (*func)(const unsigned char*, const unsigned char*,int,int*,regex_t*,void*),
+ void* arg)
+{
+ i_wrap warg;
+
+ warg.func = func;
+ warg.reg = reg;
+ warg.arg = arg;
+
+ return onig_foreach_name(ONIG_C(reg), i_wrapper, &warg);
+}
+
+extern int
+reg_number_of_names(regex_t* reg)
+{
+ return onig_number_of_names(ONIG_C(reg));
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regsyntax.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regsyntax.c
new file mode 100644
index 000000000..984aac662
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regsyntax.c
@@ -0,0 +1,338 @@
+/**********************************************************************
+ regsyntax.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+OnigSyntaxType OnigSyntaxASIS = {
+ 0
+ , ONIG_SYN_OP2_INEFFECTIVE_ESCAPE
+ , 0
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxPosixBasic = {
+ ( SYN_POSIX_COMMON_OP | ONIG_SYN_OP_ESC_LPAREN_SUBEXP |
+ ONIG_SYN_OP_ESC_BRACE_INTERVAL )
+ , 0
+ , 0
+ , ( ONIG_OPTION_SINGLELINE | ONIG_OPTION_MULTILINE )
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxPosixExtended = {
+ ( SYN_POSIX_COMMON_OP | ONIG_SYN_OP_LPAREN_SUBEXP |
+ ONIG_SYN_OP_BRACE_INTERVAL |
+ ONIG_SYN_OP_PLUS_ONE_INF | ONIG_SYN_OP_QMARK_ZERO_ONE | ONIG_SYN_OP_VBAR_ALT )
+ , 0
+ , ( ONIG_SYN_CONTEXT_INDEP_ANCHORS |
+ ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS | ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS |
+ ONIG_SYN_ALLOW_UNMATCHED_CLOSE_SUBEXP |
+ ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC )
+ , ( ONIG_OPTION_SINGLELINE | ONIG_OPTION_MULTILINE )
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxEmacs = {
+ ( ONIG_SYN_OP_DOT_ANYCHAR | ONIG_SYN_OP_BRACKET_CC |
+ ONIG_SYN_OP_ESC_BRACE_INTERVAL |
+ ONIG_SYN_OP_ESC_LPAREN_SUBEXP | ONIG_SYN_OP_ESC_VBAR_ALT |
+ ONIG_SYN_OP_ASTERISK_ZERO_INF | ONIG_SYN_OP_PLUS_ONE_INF |
+ ONIG_SYN_OP_QMARK_ZERO_ONE | ONIG_SYN_OP_DECIMAL_BACKREF |
+ ONIG_SYN_OP_LINE_ANCHOR | ONIG_SYN_OP_ESC_CONTROL_CHARS )
+ , ONIG_SYN_OP2_ESC_GNU_BUF_ANCHOR
+ , ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxGrep = {
+ ( ONIG_SYN_OP_DOT_ANYCHAR | ONIG_SYN_OP_BRACKET_CC | ONIG_SYN_OP_POSIX_BRACKET |
+ ONIG_SYN_OP_ESC_BRACE_INTERVAL | ONIG_SYN_OP_ESC_LPAREN_SUBEXP |
+ ONIG_SYN_OP_ESC_VBAR_ALT |
+ ONIG_SYN_OP_ASTERISK_ZERO_INF | ONIG_SYN_OP_ESC_PLUS_ONE_INF |
+ ONIG_SYN_OP_ESC_QMARK_ZERO_ONE | ONIG_SYN_OP_LINE_ANCHOR |
+ ONIG_SYN_OP_ESC_W_WORD | ONIG_SYN_OP_ESC_B_WORD_BOUND |
+ ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END | ONIG_SYN_OP_DECIMAL_BACKREF )
+ , 0
+ , ( ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC | ONIG_SYN_NOT_NEWLINE_IN_NEGATIVE_CC )
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxGnuRegex = {
+ SYN_GNU_REGEX_OP
+ , 0
+ , SYN_GNU_REGEX_BV
+ , ONIG_OPTION_NONE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxJava = {
+ (( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
+ ONIG_SYN_OP_ESC_CONTROL_CHARS | ONIG_SYN_OP_ESC_C_CONTROL |
+ ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 )
+ & ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
+ , ( ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE | ONIG_SYN_OP2_QMARK_GROUP_EFFECT |
+ ONIG_SYN_OP2_OPTION_PERL | ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT |
+ ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL | ONIG_SYN_OP2_CCLASS_SET_OP |
+ ONIG_SYN_OP2_ESC_V_VTAB | ONIG_SYN_OP2_ESC_U_HEX4 |
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY )
+ , ( SYN_GNU_REGEX_BV | ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH |
+ ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND |
+ ONIG_SYN_VARIABLE_LEN_LOOK_BEHIND )
+ , ONIG_OPTION_SINGLELINE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+OnigSyntaxType OnigSyntaxPerl = {
+ (( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
+ ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 |
+ ONIG_SYN_OP_ESC_X_BRACE_HEX8 | ONIG_SYN_OP_ESC_O_BRACE_OCTAL |
+ ONIG_SYN_OP_ESC_CONTROL_CHARS |
+ ONIG_SYN_OP_ESC_C_CONTROL )
+ & ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
+ , ( ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE |
+ ONIG_SYN_OP2_QMARK_GROUP_EFFECT | ONIG_SYN_OP2_OPTION_PERL |
+ ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT | ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL |
+ ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE |
+ ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP |
+ ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS |
+ ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME |
+ ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT |
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY |
+ ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT |
+ ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP |
+ ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE |
+ ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT )
+ , SYN_GNU_REGEX_BV | ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH
+ , ONIG_OPTION_SINGLELINE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+/* Perl + named group */
+OnigSyntaxType OnigSyntaxPerl_NG = {
+ (( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
+ ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 |
+ ONIG_SYN_OP_ESC_X_BRACE_HEX8 | ONIG_SYN_OP_ESC_O_BRACE_OCTAL |
+ ONIG_SYN_OP_ESC_CONTROL_CHARS |
+ ONIG_SYN_OP_ESC_C_CONTROL )
+ & ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
+ , ( ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE |
+ ONIG_SYN_OP2_QMARK_GROUP_EFFECT | ONIG_SYN_OP2_OPTION_PERL |
+ ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT | ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL |
+ ONIG_SYN_OP2_QMARK_LPAREN_IF_ELSE |
+ ONIG_SYN_OP2_QMARK_TILDE_ABSENT_GROUP |
+ ONIG_SYN_OP2_QMARK_BRACE_CALLOUT_CONTENTS |
+ ONIG_SYN_OP2_ASTERISK_CALLOUT_NAME |
+ ONIG_SYN_OP2_ESC_X_Y_TEXT_SEGMENT |
+ ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY |
+ ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT |
+ ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP |
+ ONIG_SYN_OP2_ESC_K_NAMED_BACKREF |
+ ONIG_SYN_OP2_ESC_G_SUBEXP_CALL |
+ ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP |
+ ONIG_SYN_OP2_ESC_CAPITAL_R_GENERAL_NEWLINE |
+ ONIG_SYN_OP2_ESC_CAPITAL_N_O_SUPER_DOT |
+ ONIG_SYN_OP2_QMARK_PERL_SUBEXP_CALL )
+ , ( SYN_GNU_REGEX_BV | ONIG_SYN_ISOLATED_OPTION_CONTINUE_BRANCH |
+ ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP |
+ ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME )
+ , ONIG_OPTION_SINGLELINE
+ ,
+ {
+ (OnigCodePoint )'\\' /* esc */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
+ , (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
+ }
+};
+
+
+
+extern int
+onig_set_default_syntax(OnigSyntaxType* syntax)
+{
+ if (IS_NULL(syntax))
+ syntax = ONIG_SYNTAX_ONIGURUMA;
+
+ OnigDefaultSyntax = syntax;
+ return 0;
+}
+
+extern void
+onig_copy_syntax(OnigSyntaxType* to, OnigSyntaxType* from)
+{
+ *to = *from;
+}
+
+extern void
+onig_set_syntax_op(OnigSyntaxType* syntax, unsigned int op)
+{
+ syntax->op = op;
+}
+
+extern void
+onig_set_syntax_op2(OnigSyntaxType* syntax, unsigned int op2)
+{
+ syntax->op2 = op2;
+}
+
+extern void
+onig_set_syntax_behavior(OnigSyntaxType* syntax, unsigned int behavior)
+{
+ syntax->behavior = behavior;
+}
+
+extern void
+onig_set_syntax_options(OnigSyntaxType* syntax, OnigOptionType options)
+{
+ syntax->options = options;
+}
+
+extern unsigned int
+onig_get_syntax_op(OnigSyntaxType* syntax)
+{
+ return syntax->op;
+}
+
+extern unsigned int
+onig_get_syntax_op2(OnigSyntaxType* syntax)
+{
+ return syntax->op2;
+}
+
+extern unsigned int
+onig_get_syntax_behavior(OnigSyntaxType* syntax)
+{
+ return syntax->behavior;
+}
+
+extern OnigOptionType
+onig_get_syntax_options(OnigSyntaxType* syntax)
+{
+ return syntax->options;
+}
+
+#ifdef USE_VARIABLE_META_CHARS
+extern int onig_set_meta_char(OnigSyntaxType* enc,
+ unsigned int what, OnigCodePoint code)
+{
+ switch (what) {
+ case ONIG_META_CHAR_ESCAPE:
+ enc->meta_char_table.esc = code;
+ break;
+ case ONIG_META_CHAR_ANYCHAR:
+ enc->meta_char_table.anychar = code;
+ break;
+ case ONIG_META_CHAR_ANYTIME:
+ enc->meta_char_table.anytime = code;
+ break;
+ case ONIG_META_CHAR_ZERO_OR_ONE_TIME:
+ enc->meta_char_table.zero_or_one_time = code;
+ break;
+ case ONIG_META_CHAR_ONE_OR_MORE_TIME:
+ enc->meta_char_table.one_or_more_time = code;
+ break;
+ case ONIG_META_CHAR_ANYCHAR_ANYTIME:
+ enc->meta_char_table.anychar_anytime = code;
+ break;
+ default:
+ return ONIGERR_INVALID_ARGUMENT;
+ break;
+ }
+ return 0;
+}
+#endif /* USE_VARIABLE_META_CHARS */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regtrav.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regtrav.c
new file mode 100644
index 000000000..8307695d1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regtrav.c
@@ -0,0 +1,76 @@
+/**********************************************************************
+ regtrav.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+#ifdef USE_CAPTURE_HISTORY
+
+static int
+capture_tree_traverse(OnigCaptureTreeNode* node, int at,
+ int(*callback_func)(int,int,int,int,int,void*),
+ int level, void* arg)
+{
+ int r, i;
+
+ if (node == (OnigCaptureTreeNode* )0)
+ return 0;
+
+ if ((at & ONIG_TRAVERSE_CALLBACK_AT_FIRST) != 0) {
+ r = (*callback_func)(node->group, node->beg, node->end,
+ level, ONIG_TRAVERSE_CALLBACK_AT_FIRST, arg);
+ if (r != 0) return r;
+ }
+
+ for (i = 0; i < node->num_childs; i++) {
+ r = capture_tree_traverse(node->childs[i], at,
+ callback_func, level + 1, arg);
+ if (r != 0) return r;
+ }
+
+ if ((at & ONIG_TRAVERSE_CALLBACK_AT_LAST) != 0) {
+ r = (*callback_func)(node->group, node->beg, node->end,
+ level, ONIG_TRAVERSE_CALLBACK_AT_LAST, arg);
+ if (r != 0) return r;
+ }
+
+ return 0;
+}
+#endif /* USE_CAPTURE_HISTORY */
+
+extern int
+onig_capture_tree_traverse(OnigRegion* region, int at,
+ int(*callback_func)(int,int,int,int,int,void*), void* arg)
+{
+#ifdef USE_CAPTURE_HISTORY
+ return capture_tree_traverse(region->history_root, at,
+ callback_func, 0, arg);
+#else
+ return ONIG_NO_SUPPORT_CONFIG;
+#endif
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regversion.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regversion.c
new file mode 100644
index 000000000..1f0faa16a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/regversion.c
@@ -0,0 +1,59 @@
+/**********************************************************************
+ regversion.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef NEED_TO_INCLUDE_STDIO
+#define NEED_TO_INCLUDE_STDIO
+#endif
+
+#include "regint.h"
+
+extern const char*
+onig_version(void)
+{
+ static char s[12];
+
+ xsnprintf(s, sizeof(s), "%d.%d.%d",
+ ONIGURUMA_VERSION_MAJOR,
+ ONIGURUMA_VERSION_MINOR,
+ ONIGURUMA_VERSION_TEENY);
+ return s;
+}
+
+extern const char*
+onig_copyright(void)
+{
+ static char s[58];
+
+ xsnprintf(s, sizeof(s),
+ "Oniguruma %d.%d.%d : Copyright (C) 2002-2018 K.Kosako",
+ ONIGURUMA_VERSION_MAJOR,
+ ONIGURUMA_VERSION_MINOR,
+ ONIGURUMA_VERSION_TEENY);
+ return s;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis.c
new file mode 100644
index 000000000..1fd92d93f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis.c
@@ -0,0 +1,310 @@
+/**********************************************************************
+ sjis.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+static const int EncLen_SJIS[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1
+};
+
+static const char SJIS_CAN_BE_TRAIL_TABLE[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0
+};
+
+#define SJIS_ISMB_FIRST(byte) (EncLen_SJIS[byte] > 1)
+#define SJIS_ISMB_TRAIL(byte) SJIS_CAN_BE_TRAIL_TABLE[(byte)]
+
+static int
+mbc_enc_len(const UChar* p)
+{
+ return EncLen_SJIS[*p];
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ while (p < end) {
+ if (*p < 0x80) {
+ p++;
+ }
+ else if (*p < 0xa1) {
+ if (*p == 0xa0 || *p == 0x80)
+ return FALSE;
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x40 || *p > 0xfc || *p == 0x7f)
+ return FALSE;
+ p++;
+ }
+ else if (*p < 0xe0) {
+ p++;
+ }
+ else if (*p < 0xfd) {
+ p++;
+ if (p >= end) return FALSE;
+ if (*p < 0x40 || *p > 0xfc || *p == 0x7f)
+ return FALSE;
+ p++;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+code_to_mbclen(OnigCodePoint code)
+{
+ if (code < 256) {
+ return EncLen_SJIS[(int )code] == 1;
+ }
+ else if (code <= 0xffff) {
+ return 2;
+ }
+ else
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+}
+
+static OnigCodePoint
+mbc_to_code(const UChar* p, const UChar* end)
+{
+ int c, i, len;
+ OnigCodePoint n;
+
+ len = enclen(ONIG_ENCODING_SJIS, p);
+ c = *p++;
+ n = c;
+ if (len == 1) return n;
+
+ for (i = 1; i < len; i++) {
+ if (p >= end) break;
+ c = *p++;
+ n <<= 8; n += c;
+ }
+ return n;
+}
+
+static int
+code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar *p = buf;
+
+ if ((code & 0xff00) != 0) *p++ = (UChar )(((code >> 8) & 0xff));
+ *p++ = (UChar )(code & 0xff);
+
+ return (int )(p - buf);
+}
+
+static int
+mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED,
+ const UChar** pp, const UChar* end ARG_UNUSED, UChar* lower)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_MBC_ASCII(p)) {
+ *lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1;
+ }
+ else {
+ int i;
+ int len = enclen(ONIG_ENCODING_SJIS, p);
+
+ for (i = 0; i < len; i++) {
+ *lower++ = *p++;
+ }
+ (*pp) += len;
+ return len; /* return byte length of converted char to lower */
+ }
+}
+
+static UChar*
+left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ const UChar *p;
+ int len;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ if (SJIS_ISMB_TRAIL(*p)) {
+ while (p > start) {
+ if (! SJIS_ISMB_FIRST(*--p)) {
+ p++;
+ break;
+ }
+ }
+ }
+ len = enclen(ONIG_ENCODING_SJIS, p);
+ if (p + len > s) return (UChar* )p;
+ p += len;
+ return (UChar* )(p + ((s - p) & ~1));
+}
+
+static int
+is_allowed_reverse_match(const UChar* s, const UChar* end ARG_UNUSED)
+{
+ const UChar c = *s;
+ return (SJIS_ISMB_TRAIL(c) ? FALSE : TRUE);
+}
+
+
+static const OnigCodePoint CR_Hiragana[] = {
+ 1,
+ 0x829f, 0x82f1
+}; /* CR_Hiragana */
+
+static const OnigCodePoint CR_Katakana[] = {
+ 4,
+ 0x00a6, 0x00af,
+ 0x00b1, 0x00dd,
+ 0x8340, 0x837e,
+ 0x8380, 0x8396,
+}; /* CR_Katakana */
+
+static const OnigCodePoint* PropertyList[] = {
+ CR_Hiragana,
+ CR_Katakana
+};
+
+
+static int
+property_name_to_ctype(OnigEncoding enc, UChar* p, UChar* end)
+{
+ struct PropertyNameCtype* pc;
+ int len = (int )(end - p);
+ char q[32];
+
+ if (len < sizeof(q) - 1) {
+ xmemcpy(q, p, (size_t )len);
+ q[len] = '\0';
+ pc = onigenc_sjis_lookup_property_name(q, len);
+ if (pc != 0)
+ return pc->ctype;
+ }
+
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+}
+
+static int
+is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (ctype <= ONIGENC_MAX_STD_CTYPE) {
+ if (code < 128)
+ return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
+ else {
+ if (CTYPE_IS_WORD_GRAPH_PRINT(ctype)) {
+ return (code_to_mbclen(code) > 1 ? TRUE : FALSE);
+ }
+ }
+ }
+ else {
+ ctype -= (ONIGENC_MAX_STD_CTYPE + 1);
+ if (ctype >= (unsigned int )(sizeof(PropertyList)/sizeof(PropertyList[0])))
+ return ONIGERR_TYPE_BUG;
+
+ return onig_is_in_code_range((UChar* )PropertyList[ctype], code);
+ }
+
+ return FALSE;
+}
+
+static int
+get_ctype_code_range(OnigCtype ctype, OnigCodePoint* sb_out,
+ const OnigCodePoint* ranges[])
+{
+ if (ctype <= ONIGENC_MAX_STD_CTYPE) {
+ return ONIG_NO_SUPPORT_CONFIG;
+ }
+ else {
+ *sb_out = 0x80;
+
+ ctype -= (ONIGENC_MAX_STD_CTYPE + 1);
+ if (ctype >= (OnigCtype )(sizeof(PropertyList)/sizeof(PropertyList[0])))
+ return ONIGERR_TYPE_BUG;
+
+ *ranges = PropertyList[ctype];
+ return 0;
+ }
+}
+
+OnigEncodingType OnigEncodingSJIS = {
+ mbc_enc_len,
+ "Shift_JIS", /* name */
+ 2, /* max enc length */
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ mbc_to_code,
+ code_to_mbclen,
+ code_to_mbc,
+ mbc_case_fold,
+ onigenc_ascii_apply_all_case_fold,
+ onigenc_ascii_get_case_fold_codes_by_str,
+ property_name_to_ctype,
+ is_code_ctype,
+ get_ctype_code_range,
+ left_adjust_char_head,
+ is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_SKIP_OFFSET_1_OR_0,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.c
new file mode 100644
index 000000000..2597a9f86
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.c
@@ -0,0 +1,151 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -pt -T -L ANSI-C -N onigenc_sjis_lookup_property_name --output-file gperf2.tmp sjis_prop.gperf */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 1 "sjis_prop.gperf"
+
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 16
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 8
+#define MIN_HASH_VALUE 4
+#define MAX_HASH_VALUE 55
+/* maximum key range = 52, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (register const char *str, register size_t len)
+{
+ static unsigned char asso_values[] =
+ {
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 0, 3, 10, 25, 56,
+ 56, 30, 0, 56, 56, 0, 20, 56, 56, 56,
+ 15, 56, 56, 20, 56, 30, 56, 0, 0, 56,
+ 56, 56, 56, 56, 56, 56, 56, 15, 56, 56,
+ 56, 56, 56, 25, 56, 10, 56, 56, 56, 56,
+ 5, 56, 0, 56, 0, 56, 5, 56, 56, 20,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56
+ };
+ return (unsigned int )len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
+}
+
+struct PropertyNameCtype *
+onigenc_sjis_lookup_property_name (register const char *str, register size_t len)
+{
+ static struct PropertyNameCtype wordlist[] =
+ {
+ {""}, {""}, {""}, {""},
+#line 22 "sjis_prop.gperf"
+ {"Word", 12},
+#line 11 "sjis_prop.gperf"
+ {"Alpha", 1},
+ {""}, {""},
+#line 25 "sjis_prop.gperf"
+ {"Hiragana", 15},
+ {""},
+#line 23 "sjis_prop.gperf"
+ {"Alnum", 13},
+ {""}, {""},
+#line 26 "sjis_prop.gperf"
+ {"Katakana", 16},
+ {""},
+#line 24 "sjis_prop.gperf"
+ {"ASCII", 14},
+#line 21 "sjis_prop.gperf"
+ {"XDigit", 11},
+ {""}, {""}, {""},
+#line 13 "sjis_prop.gperf"
+ {"Cntrl", 3},
+ {""}, {""},
+#line 12 "sjis_prop.gperf"
+ {"Blank", 2},
+ {""},
+#line 18 "sjis_prop.gperf"
+ {"Punct", 8},
+ {""}, {""}, {""}, {""},
+#line 17 "sjis_prop.gperf"
+ {"Print", 7},
+ {""}, {""}, {""}, {""},
+#line 20 "sjis_prop.gperf"
+ {"Upper", 10},
+ {""}, {""}, {""}, {""},
+#line 19 "sjis_prop.gperf"
+ {"Space", 9},
+ {""}, {""}, {""}, {""},
+#line 16 "sjis_prop.gperf"
+ {"Lower", 6},
+ {""}, {""}, {""}, {""},
+#line 15 "sjis_prop.gperf"
+ {"Graph", 5},
+ {""}, {""}, {""}, {""},
+#line 14 "sjis_prop.gperf"
+ {"Digit", 4}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.gperf b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.gperf
new file mode 100644
index 000000000..842b61b65
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/sjis_prop.gperf
@@ -0,0 +1,26 @@
+%{
+#include "regint.h"
+%}
+
+struct PropertyNameCtype {
+ char *name;
+ int ctype;
+};
+
+%%
+Alpha, 1
+Blank, 2
+Cntrl, 3
+Digit, 4
+Graph, 5
+Lower, 6
+Print, 7
+Punct, 8
+Space, 9
+Upper, 10
+XDigit, 11
+Word, 12
+Alnum, 13
+ASCII, 14
+Hiragana, 15
+Katakana, 16
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.c
new file mode 100644
index 000000000..522f205ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.c
@@ -0,0 +1,584 @@
+/* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
+
+/* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
+
+#ifndef NEED_TO_INCLUDE_STDIO
+#define NEED_TO_INCLUDE_STDIO
+#endif
+
+#include "regint.h"
+#include "st.h"
+
+
+typedef struct st_table_entry st_table_entry;
+
+struct st_table_entry {
+ unsigned int hash;
+ st_data_t key;
+ st_data_t record;
+ st_table_entry *next;
+};
+
+#define ST_DEFAULT_MAX_DENSITY 5
+#define ST_DEFAULT_INIT_TABLE_SIZE 11
+
+ /*
+ * DEFAULT_MAX_DENSITY is the default for the largest we allow the
+ * average number of items per bin before increasing the number of
+ * bins
+ *
+ * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
+ * allocated initially
+ *
+ */
+
+static int numcmp(long, long);
+static int numhash(long);
+static struct st_hash_type type_numhash = {
+ numcmp,
+ numhash,
+};
+
+/* extern int strcmp(const char *, const char *); */
+static int strhash(const char *);
+static struct st_hash_type type_strhash = {
+ strcmp,
+ strhash,
+};
+
+static void rehash(st_table *);
+
+#define alloc(type) (type*)xmalloc((unsigned)sizeof(type))
+#define Calloc(n,s) (char*)xcalloc((n),(s))
+
+#define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
+
+#define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
+#define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
+
+/*
+ * MINSIZE is the minimum size of a dictionary.
+ */
+
+#define MINSIZE 8
+
+/*
+Table of prime numbers 2^n+a, 2<=n<=30.
+*/
+static const long primes[] = {
+ 8 + 3,
+ 16 + 3,
+ 32 + 5,
+ 64 + 3,
+ 128 + 3,
+ 256 + 27,
+ 512 + 9,
+ 1024 + 9,
+ 2048 + 5,
+ 4096 + 3,
+ 8192 + 27,
+ 16384 + 43,
+ 32768 + 3,
+ 65536 + 45,
+ 131072 + 29,
+ 262144 + 3,
+ 524288 + 21,
+ 1048576 + 7,
+ 2097152 + 17,
+ 4194304 + 15,
+ 8388608 + 9,
+ 16777216 + 43,
+ 33554432 + 35,
+ 67108864 + 15,
+ 134217728 + 29,
+ 268435456 + 3,
+ 536870912 + 11,
+ 1073741824 + 85,
+ 0
+};
+
+static int
+new_size(size)
+ int size;
+{
+ int i;
+
+#if 0
+ for (i=3; i<31; i++) {
+ if ((1<<i) > size) return 1<<i;
+ }
+ return -1;
+#else
+ int newsize;
+
+ for (i = 0, newsize = MINSIZE;
+ i < (int )(sizeof(primes)/sizeof(primes[0]));
+ i++, newsize <<= 1) {
+ if (newsize > size) return primes[i];
+ }
+ /* Ran out of polynomials */
+ return -1; /* should raise exception */
+#endif
+}
+
+#ifdef HASH_LOG
+static int collision = 0;
+static int init_st = 0;
+
+static void
+stat_col(void)
+{
+ FILE *f = fopen("/tmp/col", "w");
+ if (f == 0) return ;
+
+ (void) fprintf(f, "collision: %d\n", collision);
+ (void) fclose(f);
+}
+#endif
+
+st_table*
+st_init_table_with_size(type, size)
+ struct st_hash_type *type;
+ int size;
+{
+ st_table *tbl;
+
+#ifdef HASH_LOG
+ if (init_st == 0) {
+ init_st = 1;
+ atexit(stat_col);
+ }
+#endif
+
+ size = new_size(size); /* round up to prime number */
+
+ tbl = alloc(st_table);
+ if (tbl == 0) return 0;
+
+ tbl->type = type;
+ tbl->num_entries = 0;
+ tbl->num_bins = size;
+ tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*));
+ if (tbl->bins == 0) {
+ free(tbl);
+ return 0;
+ }
+
+ return tbl;
+}
+
+st_table*
+st_init_table(type)
+ struct st_hash_type *type;
+{
+ return st_init_table_with_size(type, 0);
+}
+
+st_table*
+st_init_numtable(void)
+{
+ return st_init_table(&type_numhash);
+}
+
+st_table*
+st_init_numtable_with_size(size)
+ int size;
+{
+ return st_init_table_with_size(&type_numhash, size);
+}
+
+st_table*
+st_init_strtable(void)
+{
+ return st_init_table(&type_strhash);
+}
+
+st_table*
+st_init_strtable_with_size(size)
+ int size;
+{
+ return st_init_table_with_size(&type_strhash, size);
+}
+
+void
+st_free_table(table)
+ st_table *table;
+{
+ register st_table_entry *ptr, *next;
+ int i;
+
+ for(i = 0; i < table->num_bins; i++) {
+ ptr = table->bins[i];
+ while (ptr != 0) {
+ next = ptr->next;
+ free(ptr);
+ ptr = next;
+ }
+ }
+ free(table->bins);
+ free(table);
+}
+
+#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
+((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
+
+#ifdef HASH_LOG
+#define COLLISION collision++
+#else
+#define COLLISION
+#endif
+
+#define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
+ bin_pos = hash_val%(table)->num_bins;\
+ ptr = (table)->bins[bin_pos];\
+ if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
+ COLLISION;\
+ while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
+ ptr = ptr->next;\
+ }\
+ ptr = ptr->next;\
+ }\
+} while (0)
+
+int
+st_lookup(table, key, value)
+ st_table *table;
+ register st_data_t key;
+ st_data_t *value;
+{
+ unsigned int hash_val, bin_pos;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash(key, table);
+ FIND_ENTRY(table, ptr, hash_val, bin_pos);
+
+ if (ptr == 0) {
+ return 0;
+ }
+ else {
+ if (value != 0) *value = ptr->record;
+ return 1;
+ }
+}
+
+#define ADD_DIRECT(table, key, value, hash_val, bin_pos, ret) \
+do {\
+ st_table_entry *entry;\
+ if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
+ rehash(table);\
+ bin_pos = hash_val % table->num_bins;\
+ }\
+ entry = alloc(st_table_entry);\
+ if (IS_NULL(entry)) return ret;\
+ entry->hash = hash_val;\
+ entry->key = key;\
+ entry->record = value;\
+ entry->next = table->bins[bin_pos];\
+ table->bins[bin_pos] = entry;\
+ table->num_entries++;\
+} while (0)
+
+int
+st_insert(table, key, value)
+ register st_table *table;
+ register st_data_t key;
+ st_data_t value;
+{
+ unsigned int hash_val, bin_pos;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash(key, table);
+ FIND_ENTRY(table, ptr, hash_val, bin_pos);
+
+ if (ptr == 0) {
+ ADD_DIRECT(table, key, value, hash_val, bin_pos, ONIGERR_MEMORY);
+ return 0;
+ }
+ else {
+ ptr->record = value;
+ return 1;
+ }
+}
+
+void
+st_add_direct(table, key, value)
+ st_table *table;
+ st_data_t key;
+ st_data_t value;
+{
+ unsigned int hash_val, bin_pos;
+
+ hash_val = do_hash(key, table);
+ bin_pos = hash_val % table->num_bins;
+ ADD_DIRECT(table, key, value, hash_val, bin_pos,);
+}
+
+static void
+rehash(table)
+ register st_table *table;
+{
+ register st_table_entry *ptr, *next, **new_bins;
+ int i, old_num_bins = table->num_bins, new_num_bins;
+ unsigned int hash_val;
+
+ new_num_bins = new_size(old_num_bins+1);
+ new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*));
+ if (new_bins == 0) {
+ return ;
+ }
+
+ for(i = 0; i < old_num_bins; i++) {
+ ptr = table->bins[i];
+ while (ptr != 0) {
+ next = ptr->next;
+ hash_val = ptr->hash % new_num_bins;
+ ptr->next = new_bins[hash_val];
+ new_bins[hash_val] = ptr;
+ ptr = next;
+ }
+ }
+ free(table->bins);
+ table->num_bins = new_num_bins;
+ table->bins = new_bins;
+}
+
+st_table*
+st_copy(old_table)
+ st_table *old_table;
+{
+ st_table *new_table;
+ st_table_entry *ptr, *entry;
+ int i, num_bins = old_table->num_bins;
+
+ new_table = alloc(st_table);
+ if (new_table == 0) {
+ return 0;
+ }
+
+ *new_table = *old_table;
+ new_table->bins = (st_table_entry**)
+ Calloc((unsigned)num_bins, sizeof(st_table_entry*));
+
+ if (new_table->bins == 0) {
+ free(new_table);
+ return 0;
+ }
+
+ for(i = 0; i < num_bins; i++) {
+ new_table->bins[i] = 0;
+ ptr = old_table->bins[i];
+ while (ptr != 0) {
+ entry = alloc(st_table_entry);
+ if (entry == 0) {
+ free(new_table->bins);
+ free(new_table);
+ return 0;
+ }
+ *entry = *ptr;
+ entry->next = new_table->bins[i];
+ new_table->bins[i] = entry;
+ ptr = ptr->next;
+ }
+ }
+ return new_table;
+}
+
+int
+st_delete(table, key, value)
+ register st_table *table;
+ register st_data_t *key;
+ st_data_t *value;
+{
+ unsigned int hash_val;
+ st_table_entry *tmp;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash_bin(*key, table);
+ ptr = table->bins[hash_val];
+
+ if (ptr == 0) {
+ if (value != 0) *value = 0;
+ return 0;
+ }
+
+ if (EQUAL(table, *key, ptr->key)) {
+ table->bins[hash_val] = ptr->next;
+ table->num_entries--;
+ if (value != 0) *value = ptr->record;
+ *key = ptr->key;
+ free(ptr);
+ return 1;
+ }
+
+ for(; ptr->next != 0; ptr = ptr->next) {
+ if (EQUAL(table, ptr->next->key, *key)) {
+ tmp = ptr->next;
+ ptr->next = ptr->next->next;
+ table->num_entries--;
+ if (value != 0) *value = tmp->record;
+ *key = tmp->key;
+ free(tmp);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+st_delete_safe(table, key, value, never)
+ register st_table *table;
+ register st_data_t *key;
+ st_data_t *value;
+ st_data_t never;
+{
+ unsigned int hash_val;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash_bin(*key, table);
+ ptr = table->bins[hash_val];
+
+ if (ptr == 0) {
+ if (value != 0) *value = 0;
+ return 0;
+ }
+
+ for(; ptr != 0; ptr = ptr->next) {
+ if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
+ table->num_entries--;
+ *key = ptr->key;
+ if (value != 0) *value = ptr->record;
+ ptr->key = ptr->record = never;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+#if defined(__GNUC__)
+delete_never(st_data_t key __attribute__ ((unused)), st_data_t value,
+ st_data_t never)
+#else
+delete_never(key, value, never)
+ st_data_t key, value, never;
+#endif
+{
+ if (value == never) return ST_DELETE;
+ return ST_CONTINUE;
+}
+
+void
+st_cleanup_safe(table, never)
+ st_table *table;
+ st_data_t never;
+{
+ int num_entries = table->num_entries;
+
+ st_foreach(table, delete_never, never);
+ table->num_entries = num_entries;
+}
+
+int
+st_foreach(table, func, arg)
+ st_table *table;
+ int (*func)();
+ st_data_t arg;
+{
+ st_table_entry *ptr, *last, *tmp;
+ enum st_retval retval;
+ int i;
+
+ for(i = 0; i < table->num_bins; i++) {
+ last = 0;
+ for(ptr = table->bins[i]; ptr != 0;) {
+ retval = (*func)(ptr->key, ptr->record, arg);
+ switch (retval) {
+ case ST_CHECK: /* check if hash is modified during iteration */
+ tmp = 0;
+ if (i < table->num_bins) {
+ for (tmp = table->bins[i]; tmp; tmp=tmp->next) {
+ if (tmp == ptr) break;
+ }
+ }
+ if (!tmp) {
+ /* call func with error notice */
+ return 1;
+ }
+ /* fall through */
+ case ST_CONTINUE:
+ last = ptr;
+ ptr = ptr->next;
+ break;
+ case ST_STOP:
+ return 0;
+ case ST_DELETE:
+ tmp = ptr;
+ if (last == 0) {
+ table->bins[i] = ptr->next;
+ }
+ else {
+ last->next = ptr->next;
+ }
+ ptr = ptr->next;
+ free(tmp);
+ table->num_entries--;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+strhash(string)
+ register const char *string;
+{
+ register int c;
+
+#ifdef HASH_ELFHASH
+ register unsigned int h = 0, g;
+
+ while ((c = *string++) != '\0') {
+ h = ( h << 4 ) + c;
+ if ( g = h & 0xF0000000 )
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ return h;
+#elif HASH_PERL
+ register int val = 0;
+
+ while ((c = *string++) != '\0') {
+ val += c;
+ val += (val << 10);
+ val ^= (val >> 6);
+ }
+ val += (val << 3);
+ val ^= (val >> 11);
+
+ return val + (val << 15);
+#else
+ register int val = 0;
+
+ while ((c = *string++) != '\0') {
+ val = val*997 + c;
+ }
+
+ return val + (val>>5);
+#endif
+}
+
+static int
+numcmp(x, y)
+ long x, y;
+{
+ return x != y;
+}
+
+static int
+numhash(n)
+ long n;
+{
+ return n;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.h
new file mode 100644
index 000000000..7961c065d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/st.h
@@ -0,0 +1,67 @@
+/* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
+
+/* @(#) st.h 5.1 89/12/14 */
+
+#ifndef ST_INCLUDED
+#define ST_INCLUDED
+
+#if SIZEOF_VOIDP == SIZEOF_LONG
+typedef unsigned long st_data_t;
+#elif SIZEOF_VOIDP == SIZEOF_LONG_LONG
+typedef unsigned long long st_data_t;
+#endif
+
+#define ST_DATA_T_DEFINED
+
+typedef struct st_table st_table;
+
+struct st_hash_type {
+ int (*compare)();
+ int (*hash)();
+};
+
+struct st_table {
+ struct st_hash_type *type;
+ int num_bins;
+ int num_entries;
+ struct st_table_entry **bins;
+};
+
+#define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0)
+
+enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK};
+
+#ifndef _
+# define _(args) args
+#endif
+#ifndef ANYARGS
+# ifdef __cplusplus
+# define ANYARGS ...
+# else
+# define ANYARGS
+# endif
+#endif
+
+st_table *st_init_table _((struct st_hash_type *));
+st_table *st_init_table_with_size _((struct st_hash_type *, int));
+st_table *st_init_numtable _((void));
+st_table *st_init_numtable_with_size _((int));
+st_table *st_init_strtable _((void));
+st_table *st_init_strtable_with_size _((int));
+int st_delete _((st_table *, st_data_t *, st_data_t *));
+int st_delete_safe _((st_table *, st_data_t *, st_data_t *, st_data_t));
+int st_insert _((st_table *, st_data_t, st_data_t));
+int st_lookup _((st_table *, st_data_t, st_data_t *));
+int st_foreach _((st_table *, int (*)(ANYARGS), st_data_t));
+void st_add_direct _((st_table *, st_data_t, st_data_t));
+void st_free_table _((st_table *));
+void st_cleanup_safe _((st_table *, st_data_t));
+st_table *st_copy _((st_table *));
+
+#define ST_NUMCMP ((int (*)()) 0)
+#define ST_NUMHASH ((int (*)()) -2)
+
+#define st_numcmp ST_NUMCMP
+#define st_numhash ST_NUMHASH
+
+#endif /* ST_INCLUDED */
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode.c
new file mode 100644
index 000000000..080da74b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode.c
@@ -0,0 +1,1215 @@
+/**********************************************************************
+ unicode.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h"
+
+struct PoolPropertyNameCtype {
+ short int name;
+ short int ctype;
+};
+
+#define ONIGENC_IS_UNICODE_ISO_8859_1_CTYPE(code,ctype) \
+ ((EncUNICODE_ISO_8859_1_CtypeTable[code] & CTYPE_TO_BIT(ctype)) != 0)
+
+static const unsigned short EncUNICODE_ISO_8859_1_CtypeTable[256] = {
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x428c, 0x4289, 0x4288, 0x4288, 0x4288, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008,
+ 0x4284, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0, 0x78b0,
+ 0x78b0, 0x78b0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x41a0,
+ 0x41a0, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x7ca2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2, 0x74a2,
+ 0x74a2, 0x74a2, 0x74a2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x51a0,
+ 0x41a0, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x78e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2, 0x70e2,
+ 0x70e2, 0x70e2, 0x70e2, 0x41a0, 0x41a0, 0x41a0, 0x41a0, 0x4008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0288, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0284, 0x01a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x30e2, 0x01a0, 0x00a0, 0x00a8, 0x00a0, 0x00a0,
+ 0x00a0, 0x00a0, 0x10a0, 0x10a0, 0x00a0, 0x30e2, 0x00a0, 0x01a0,
+ 0x00a0, 0x10a0, 0x30e2, 0x01a0, 0x10a0, 0x10a0, 0x10a0, 0x01a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x00a0,
+ 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x34a2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x00a0,
+ 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2, 0x30e2
+};
+
+#include "st.h"
+
+#include "unicode_fold_data.c"
+
+extern int
+onigenc_unicode_mbc_case_fold(OnigEncoding enc,
+ OnigCaseFoldType flag ARG_UNUSED, const UChar** pp, const UChar* end,
+ UChar* fold)
+{
+ const struct ByUnfoldKey* buk;
+
+ OnigCodePoint code;
+ int i, len, rlen;
+ const UChar *p = *pp;
+
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ len = enclen(enc, p);
+ *pp += len;
+
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (code == 0x0130) {
+ return ONIGENC_CODE_TO_MBC(enc, 0x0069, fold);
+ }
+#if 0
+ if (code == 0x0049) {
+ return ONIGENC_CODE_TO_MBC(enc, 0x0131, fold);
+ }
+#endif
+ }
+#endif
+
+ buk = onigenc_unicode_unfold_key(code);
+ if (buk != 0) {
+ if (buk->fold_len == 1) {
+ return ONIGENC_CODE_TO_MBC(enc, *FOLDS1_FOLD(buk->index), fold);
+ }
+ else {
+ OnigCodePoint* addr;
+
+ FOLDS_FOLD_ADDR_BUK(buk, addr);
+ rlen = 0;
+ for (i = 0; i < buk->fold_len; i++) {
+ OnigCodePoint c = addr[i];
+ len = ONIGENC_CODE_TO_MBC(enc, c, fold);
+ fold += len;
+ rlen += len;
+ }
+ return rlen;
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ *fold++ = *p++;
+ }
+ return len;
+}
+
+static int
+apply_case_fold1(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ int i, j, k, n, r;
+
+ for (i = from; i < to; ) {
+ OnigCodePoint fold = *FOLDS1_FOLD(i);
+ n = FOLDS1_UNFOLDS_NUM(i);
+ for (j = 0; j < n; j++) {
+ OnigCodePoint unfold = FOLDS1_UNFOLDS(i)[j];
+
+ r = (*f)(fold, &unfold, 1, arg);
+ if (r != 0) return r;
+ r = (*f)(unfold, &fold, 1, arg);
+ if (r != 0) return r;
+
+ for (k = 0; k < j; k++) {
+ OnigCodePoint unfold2 = FOLDS1_UNFOLDS(i)[k];
+ r = (*f)(unfold, &unfold2, 1, arg);
+ if (r != 0) return r;
+ r = (*f)(unfold2, &unfold, 1, arg);
+ if (r != 0) return r;
+ }
+ }
+
+ i = FOLDS1_NEXT_INDEX(i);
+ }
+
+ return 0;
+}
+
+static int
+apply_case_fold2(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ int i, j, k, n, r;
+
+ for (i = from; i < to; ) {
+ OnigCodePoint* fold = FOLDS2_FOLD(i);
+ n = FOLDS2_UNFOLDS_NUM(i);
+ for (j = 0; j < n; j++) {
+ OnigCodePoint unfold = FOLDS2_UNFOLDS(i)[j];
+
+ r = (*f)(unfold, fold, 2, arg);
+ if (r != 0) return r;
+
+ for (k = 0; k < j; k++) {
+ OnigCodePoint unfold2 = FOLDS2_UNFOLDS(i)[k];
+ r = (*f)(unfold, &unfold2, 1, arg);
+ if (r != 0) return r;
+ r = (*f)(unfold2, &unfold, 1, arg);
+ if (r != 0) return r;
+ }
+ }
+
+ i = FOLDS2_NEXT_INDEX(i);
+ }
+
+ return 0;
+}
+
+static int
+apply_case_fold3(int from, int to, OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ int i, j, k, n, r;
+
+ for (i = from; i < to; ) {
+ OnigCodePoint* fold = FOLDS3_FOLD(i);
+ n = FOLDS3_UNFOLDS_NUM(i);
+ for (j = 0; j < n; j++) {
+ OnigCodePoint unfold = FOLDS3_UNFOLDS(i)[j];
+
+ r = (*f)(unfold, fold, 3, arg);
+ if (r != 0) return r;
+
+ for (k = 0; k < j; k++) {
+ OnigCodePoint unfold2 = FOLDS3_UNFOLDS(i)[k];
+ r = (*f)(unfold, &unfold2, 1, arg);
+ if (r != 0) return r;
+ r = (*f)(unfold2, &unfold, 1, arg);
+ if (r != 0) return r;
+ }
+ }
+
+ i = FOLDS3_NEXT_INDEX(i);
+ }
+
+ return 0;
+}
+
+extern int
+onigenc_unicode_apply_all_case_fold(OnigCaseFoldType flag,
+ OnigApplyAllCaseFoldFunc f, void* arg)
+{
+ int r;
+
+ r = apply_case_fold1(0, FOLDS1_NORMAL_END_INDEX, f, arg);
+ if (r != 0) return r;
+
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ code = 0x0131;
+ r = (*f)(0x0049, &code, 1, arg);
+ if (r != 0) return r;
+ code = 0x0049;
+ r = (*f)(0x0131, &code, 1, arg);
+ if (r != 0) return r;
+
+ code = 0x0130;
+ r = (*f)(0x0069, &code, 1, arg);
+ if (r != 0) return r;
+ code = 0x0069;
+ r = (*f)(0x0130, &code, 1, arg);
+ if (r != 0) return r;
+ }
+ else {
+#endif
+ r = apply_case_fold1(FOLDS1_NORMAL_END_INDEX, FOLDS1_END_INDEX, f, arg);
+ if (r != 0) return r;
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ }
+#endif
+
+ if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) == 0)
+ return 0;
+
+ r = apply_case_fold2(0, FOLDS2_NORMAL_END_INDEX, f, arg);
+ if (r != 0) return r;
+
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) == 0) {
+#endif
+ r = apply_case_fold2(FOLDS2_NORMAL_END_INDEX, FOLDS2_END_INDEX, f, arg);
+ if (r != 0) return r;
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ }
+#endif
+
+ r = apply_case_fold3(0, FOLDS3_NORMAL_END_INDEX, f, arg);
+ if (r != 0) return r;
+
+ return 0;
+}
+
+extern int
+onigenc_unicode_get_case_fold_codes_by_str(OnigEncoding enc,
+ OnigCaseFoldType flag, const OnigUChar* p, const OnigUChar* end,
+ OnigCaseFoldCodeItem items[])
+{
+ int n, m, i, j, k, len, lens[3];
+ int index;
+ int fn, ncs[3];
+ OnigCodePoint cs[3][4];
+ OnigCodePoint code, codes[3], orig_codes[3];
+ const struct ByUnfoldKey* buk1;
+
+ n = 0;
+
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ len = enclen(enc, p);
+
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (code == 0x0049) {
+ items[0].byte_len = len;
+ items[0].code_len = 1;
+ items[0].code[0] = 0x0131;
+ return 1;
+ }
+ else if (code == 0x0130) {
+ items[0].byte_len = len;
+ items[0].code_len = 1;
+ items[0].code[0] = 0x0069;
+ return 1;
+ }
+ else if (code == 0x0131) {
+ items[0].byte_len = len;
+ items[0].code_len = 1;
+ items[0].code[0] = 0x0049;
+ return 1;
+ }
+ else if (code == 0x0069) {
+ items[0].byte_len = len;
+ items[0].code_len = 1;
+ items[0].code[0] = 0x0130;
+ return 1;
+ }
+ }
+#endif
+
+ orig_codes[0] = code;
+ lens[0] = len;
+ p += len;
+
+ buk1 = onigenc_unicode_unfold_key(orig_codes[0]);
+ if (buk1 != 0 && buk1->fold_len == 1) {
+ codes[0] = *FOLDS1_FOLD(buk1->index);
+ }
+ else
+ codes[0] = orig_codes[0];
+
+ if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) == 0)
+ goto fold1;
+
+ if (p < end) {
+ const struct ByUnfoldKey* buk;
+
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ orig_codes[1] = code;
+ len = enclen(enc, p);
+ lens[1] = lens[0] + len;
+ buk = onigenc_unicode_unfold_key(orig_codes[1]);
+ if (buk != 0 && buk->fold_len == 1) {
+ codes[1] = *FOLDS1_FOLD(buk->index);
+ }
+ else
+ codes[1] = orig_codes[1];
+
+ p += len;
+ if (p < end) {
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ orig_codes[2] = code;
+ len = enclen(enc, p);
+ lens[2] = lens[1] + len;
+ buk = onigenc_unicode_unfold_key(orig_codes[2]);
+ if (buk != 0 && buk->fold_len == 1) {
+ codes[2] = *FOLDS1_FOLD(buk->index);
+ }
+ else
+ codes[2] = orig_codes[2];
+
+ index = onigenc_unicode_fold3_key(codes);
+ if (index >= 0) {
+ m = FOLDS3_UNFOLDS_NUM(index);
+ for (i = 0; i < m; i++) {
+ items[n].byte_len = lens[2];
+ items[n].code_len = 1;
+ items[n].code[0] = FOLDS3_UNFOLDS(index)[i];
+ n++;
+ }
+
+ for (fn = 0; fn < 3; fn++) {
+ int sindex;
+ cs[fn][0] = FOLDS3_FOLD(index)[fn];
+ ncs[fn] = 1;
+ sindex = onigenc_unicode_fold1_key(&cs[fn][0]);
+ if (sindex >= 0) {
+ int m = FOLDS1_UNFOLDS_NUM(sindex);
+ for (i = 0; i < m; i++) {
+ cs[fn][i+1] = FOLDS1_UNFOLDS(sindex)[i];
+ }
+ ncs[fn] += m;
+ }
+ }
+
+ for (i = 0; i < ncs[0]; i++) {
+ for (j = 0; j < ncs[1]; j++) {
+ for (k = 0; k < ncs[2]; k++) {
+ items[n].byte_len = lens[2];
+ items[n].code_len = 3;
+ items[n].code[0] = cs[0][i];
+ items[n].code[1] = cs[1][j];
+ items[n].code[2] = cs[2][k];
+ if (items[n].code[0] == orig_codes[0] &&
+ items[n].code[1] == orig_codes[1] &&
+ items[n].code[2] == orig_codes[2])
+ continue;
+ n++;
+ }
+ }
+ }
+
+ return n;
+ }
+ }
+
+ index = onigenc_unicode_fold2_key(codes);
+ if (index >= 0) {
+ m = FOLDS2_UNFOLDS_NUM(index);
+ for (i = 0; i < m; i++) {
+ items[n].byte_len = lens[1];
+ items[n].code_len = 1;
+ items[n].code[0] = FOLDS2_UNFOLDS(index)[i];
+ n++;
+ }
+
+ for (fn = 0; fn < 2; fn++) {
+ int sindex;
+ cs[fn][0] = FOLDS2_FOLD(index)[fn];
+ ncs[fn] = 1;
+ sindex = onigenc_unicode_fold1_key(&cs[fn][0]);
+ if (sindex >= 0) {
+ int m = FOLDS1_UNFOLDS_NUM(sindex);
+ for (i = 0; i < m; i++) {
+ cs[fn][i+1] = FOLDS1_UNFOLDS(sindex)[i];
+ }
+ ncs[fn] += m;
+ }
+ }
+
+ for (i = 0; i < ncs[0]; i++) {
+ for (j = 0; j < ncs[1]; j++) {
+ items[n].byte_len = lens[1];
+ items[n].code_len = 2;
+ items[n].code[0] = cs[0][i];
+ items[n].code[1] = cs[1][j];
+ if (items[n].code[0] == orig_codes[0] &&
+ items[n].code[1] == orig_codes[1])
+ continue;
+ n++;
+ }
+ }
+
+ return n;
+ }
+ }
+
+ fold1:
+ if (buk1 != 0) {
+ if (buk1->fold_len == 1) {
+ int un;
+ items[0].byte_len = lens[0];
+ items[0].code_len = 1;
+ items[0].code[0] = *FOLDS1_FOLD(buk1->index);
+ n++;
+
+ un = FOLDS1_UNFOLDS_NUM(buk1->index);
+ for (i = 0; i < un; i++) {
+ OnigCodePoint unfold = FOLDS1_UNFOLDS(buk1->index)[i];
+ if (unfold != orig_codes[0]) {
+ items[n].byte_len = lens[0];
+ items[n].code_len = 1;
+ items[n].code[0] = unfold;
+ n++;
+ }
+ }
+ }
+ else if ((flag & INTERNAL_ONIGENC_CASE_FOLD_MULTI_CHAR) != 0) {
+ if (buk1->fold_len == 2) {
+ m = FOLDS2_UNFOLDS_NUM(buk1->index);
+ for (i = 0; i < m; i++) {
+ OnigCodePoint unfold = FOLDS2_UNFOLDS(buk1->index)[i];
+ if (unfold == orig_codes[0]) continue;
+
+ items[n].byte_len = lens[0];
+ items[n].code_len = 1;
+ items[n].code[0] = unfold;
+ n++;
+ }
+
+ for (fn = 0; fn < 2; fn++) {
+ int index;
+ cs[fn][0] = FOLDS2_FOLD(buk1->index)[fn];
+ ncs[fn] = 1;
+ index = onigenc_unicode_fold1_key(&cs[fn][0]);
+ if (index >= 0) {
+ int m = FOLDS1_UNFOLDS_NUM(index);
+ for (i = 0; i < m; i++) {
+ cs[fn][i+1] = FOLDS1_UNFOLDS(index)[i];
+ }
+ ncs[fn] += m;
+ }
+ }
+
+ for (i = 0; i < ncs[0]; i++) {
+ for (j = 0; j < ncs[1]; j++) {
+ items[n].byte_len = lens[0];
+ items[n].code_len = 2;
+ items[n].code[0] = cs[0][i];
+ items[n].code[1] = cs[1][j];
+ n++;
+ }
+ }
+ }
+ else { /* fold_len == 3 */
+ m = FOLDS3_UNFOLDS_NUM(buk1->index);
+ for (i = 0; i < m; i++) {
+ OnigCodePoint unfold = FOLDS3_UNFOLDS(buk1->index)[i];
+ if (unfold == orig_codes[0]) continue;
+
+ items[n].byte_len = lens[0];
+ items[n].code_len = 1;
+ items[n].code[0] = unfold;
+ n++;
+ }
+
+ for (fn = 0; fn < 3; fn++) {
+ int index;
+ cs[fn][0] = FOLDS3_FOLD(buk1->index)[fn];
+ ncs[fn] = 1;
+ index = onigenc_unicode_fold1_key(&cs[fn][0]);
+ if (index >= 0) {
+ int m = FOLDS1_UNFOLDS_NUM(index);
+ for (i = 0; i < m; i++) {
+ cs[fn][i+1] = FOLDS1_UNFOLDS(index)[i];
+ }
+ ncs[fn] += m;
+ }
+ }
+
+ for (i = 0; i < ncs[0]; i++) {
+ for (j = 0; j < ncs[1]; j++) {
+ for (k = 0; k < ncs[2]; k++) {
+ items[n].byte_len = lens[0];
+ items[n].code_len = 3;
+ items[n].code[0] = cs[0][i];
+ items[n].code[1] = cs[1][j];
+ items[n].code[2] = cs[2][k];
+ n++;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ int index = onigenc_unicode_fold1_key(orig_codes);
+ if (index >= 0) {
+ int m = FOLDS1_UNFOLDS_NUM(index);
+ for (i = 0; i < m; i++) {
+ items[n].byte_len = lens[0];
+ items[n].code_len = 1;
+ items[n].code[0] = FOLDS1_UNFOLDS(index)[i];
+ n++;
+ }
+ }
+ }
+
+ return n;
+}
+
+#ifdef USE_UNICODE_PROPERTIES
+#include "unicode_property_data.c"
+#else
+#include "unicode_property_data_posix.c"
+#endif
+
+
+#ifdef USE_UNICODE_WORD_BREAK
+
+enum WB_TYPE {
+ WB_Any = 0,
+ WB_ALetter,
+ WB_CR,
+ WB_Double_Quote,
+ WB_Extend,
+ WB_ExtendNumLet,
+ WB_Format,
+ WB_Hebrew_Letter,
+ WB_Katakana,
+ WB_LF,
+ WB_MidLetter,
+ WB_MidNum,
+ WB_MidNumLet,
+ WB_Newline,
+ WB_Numeric,
+ WB_Regional_Indicator,
+ WB_Single_Quote,
+ WB_WSegSpace,
+ WB_ZWJ,
+};
+
+typedef struct {
+ OnigCodePoint start;
+ OnigCodePoint end;
+ enum WB_TYPE type;
+} WB_RANGE_TYPE;
+
+#include "unicode_wb_data.c"
+
+static enum WB_TYPE
+wb_get_type(OnigCodePoint code)
+{
+ OnigCodePoint low, high, x;
+ enum WB_TYPE type;
+
+ for (low = 0, high = (OnigCodePoint )WB_RANGE_NUM; low < high; ) {
+ x = (low + high) >> 1;
+ if (code > WB_RANGES[x].end)
+ low = x + 1;
+ else
+ high = x;
+ }
+
+ type = (low < (OnigCodePoint )WB_RANGE_NUM &&
+ code >= WB_RANGES[low].start) ?
+ WB_RANGES[low].type : WB_Any;
+
+ return type;
+}
+
+#define IS_WB_IGNORE_TAIL(t) ((t) == WB_Extend || (t) == WB_Format || (t) == WB_ZWJ)
+#define IS_WB_AHLetter(t) ((t) == WB_ALetter || (t) == WB_Hebrew_Letter)
+#define IS_WB_MidNumLetQ(t) ((t) == WB_MidNumLet || (t) == WB_Single_Quote)
+
+static int
+wb_get_next_main_code(OnigEncoding enc, UChar* p, const UChar* end,
+ OnigCodePoint* rcode, enum WB_TYPE* rtype)
+{
+ OnigCodePoint code;
+ enum WB_TYPE type;
+
+ while (TRUE) {
+ p += enclen(enc, p);
+ if (p >= end) break;
+
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ type = wb_get_type(code);
+ if (! IS_WB_IGNORE_TAIL(type)) {
+ *rcode = code;
+ *rtype = type;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+extern int
+onigenc_wb_is_break_position(OnigEncoding enc, UChar* p, UChar* prev,
+ const UChar* start, const UChar* end)
+{
+ int r;
+ UChar* pp;
+ OnigCodePoint cfrom;
+ OnigCodePoint cfrom2;
+ OnigCodePoint cto;
+ OnigCodePoint cto2;
+ enum WB_TYPE from;
+ enum WB_TYPE from2;
+ enum WB_TYPE to;
+ enum WB_TYPE to2;
+
+ /* WB1: sot / Any */
+ if (p == start) return TRUE;
+ /* WB2: Any / eot */
+ if (p == end) return TRUE;
+
+ if (IS_NULL(prev)) {
+ prev = onigenc_get_prev_char_head(enc, start, p);
+ if (IS_NULL(prev)) return TRUE;
+ }
+
+ cfrom = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ cto = ONIGENC_MBC_TO_CODE(enc, p, end);
+
+ from = wb_get_type(cfrom);
+ to = wb_get_type(cto);
+
+ /* short cut */
+ if (from == 0 && to == 0) goto WB999;
+
+ /* WB3: CR + LF */
+ if (from == WB_CR && to == WB_LF) return FALSE;
+
+ /* WB3a: (Newline|CR|LF) / */
+ if (from == WB_Newline || from == WB_CR || from == WB_LF) return TRUE;
+ /* WB3b: / (Newline|CR|LF) */
+ if (to == WB_Newline || to == WB_CR || to == WB_LF) return TRUE;
+
+ /* WB3c: ZWJ + {Extended_Pictographic} */
+ if (from == WB_ZWJ) {
+ if (onigenc_unicode_is_code_ctype(cto, PROP_INDEX_EXTENDEDPICTOGRAPHIC))
+ return FALSE;
+ }
+
+ /* WB3d: WSegSpace + WSegSpace */
+ if (from == WB_WSegSpace && to == WB_WSegSpace) return FALSE;
+
+ /* WB4: X (Extend|Format|ZWJ)* -> X */
+ if (IS_WB_IGNORE_TAIL(to)) return FALSE;
+ if (IS_WB_IGNORE_TAIL(from)) {
+ while ((pp = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ prev = pp;
+ cfrom = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ from = wb_get_type(cfrom);
+ if (! IS_WB_IGNORE_TAIL(from))
+ break;
+ }
+ }
+
+ if (IS_WB_AHLetter(from)) {
+ /* WB5: AHLetter + AHLetter */
+ if (IS_WB_AHLetter(to)) return FALSE;
+
+ /* WB6: AHLetter + (MidLetter | MidNumLetQ) AHLetter */
+ if (to == WB_MidLetter || IS_WB_MidNumLetQ(to)) {
+ r = wb_get_next_main_code(enc, p, end, &cto2, &to2);
+ if (r == 1) {
+ if (IS_WB_AHLetter(to2)) return FALSE;
+ }
+ }
+ }
+
+ /* WB7: AHLetter (MidLetter | MidNumLetQ) + AHLetter */
+ if (from == WB_MidLetter || IS_WB_MidNumLetQ(from)) {
+ if (IS_WB_AHLetter(to)) {
+ from2 = WB_Any;
+ while ((pp = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ prev = pp;
+ cfrom2 = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ from2 = wb_get_type(cfrom2);
+ if (! IS_WB_IGNORE_TAIL(from2))
+ break;
+ }
+
+ if (IS_WB_AHLetter(from2)) return FALSE;
+ }
+ }
+
+ if (from == WB_Hebrew_Letter) {
+ /* WB7a: Hebrew_Letter + Single_Quote */
+ if (to == WB_Single_Quote) return FALSE;
+
+ /* WB7b: Hebrew_Letter + Double_Quote Hebrew_Letter */
+ if (to == WB_Double_Quote) {
+ r = wb_get_next_main_code(enc, p, end, &cto2, &to2);
+ if (r == 1) {
+ if (to2 == WB_Hebrew_Letter) return FALSE;
+ }
+ }
+ }
+
+ /* WB7c: Hebrew_Letter Double_Quote + Hebrew_Letter */
+ if (from == WB_Double_Quote) {
+ if (to == WB_Hebrew_Letter) {
+ from2 = WB_Any;
+ while ((pp = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ prev = pp;
+ cfrom2 = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ from2 = wb_get_type(cfrom2);
+ if (! IS_WB_IGNORE_TAIL(from2))
+ break;
+ }
+
+ if (from2 == WB_Hebrew_Letter) return FALSE;
+ }
+ }
+
+ if (to == WB_Numeric) {
+ /* WB8: Numeric + Numeric */
+ if (from == WB_Numeric) return FALSE;
+
+ /* WB9: AHLetter + Numeric */
+ if (IS_WB_AHLetter(from)) return FALSE;
+
+ /* WB11: Numeric (MidNum | MidNumLetQ) + Numeric */
+ if (from == WB_MidNum || IS_WB_MidNumLetQ(from)) {
+ from2 = WB_Any;
+ while ((pp = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ prev = pp;
+ cfrom2 = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ from2 = wb_get_type(cfrom2);
+ if (! IS_WB_IGNORE_TAIL(from2))
+ break;
+ }
+
+ if (from2 == WB_Numeric) return FALSE;
+ }
+ }
+
+ if (from == WB_Numeric) {
+ /* WB10: Numeric + AHLetter */
+ if (IS_WB_AHLetter(to)) return FALSE;
+
+ /* WB12: Numeric + (MidNum | MidNumLetQ) Numeric */
+ if (to == WB_MidNum || IS_WB_MidNumLetQ(to)) {
+ r = wb_get_next_main_code(enc, p, end, &cto2, &to2);
+ if (r == 1) {
+ if (to2 == WB_Numeric) return FALSE;
+ }
+ }
+ }
+
+ /* WB13: Katakana + Katakana */
+ if (from == WB_Katakana && to == WB_Katakana) return FALSE;
+
+ /* WB13a: (AHLetter | Numeric | Katakana | ExtendNumLet) + ExtendNumLet */
+ if (IS_WB_AHLetter(from) || from == WB_Numeric || from == WB_Katakana
+ || from == WB_ExtendNumLet) {
+ if (to == WB_ExtendNumLet) return FALSE;
+ }
+
+ /* WB13b: ExtendNumLet + (AHLetter | Numeric | Katakana) */
+ if (from == WB_ExtendNumLet) {
+ if (IS_WB_AHLetter(to) || to == WB_Numeric || to == WB_Katakana)
+ return FALSE;
+ }
+
+
+ /* WB15: sot (RI RI)* RI + RI */
+ /* WB16: [^RI] (RI RI)* RI + RI */
+ if (from == WB_Regional_Indicator && to == WB_Regional_Indicator) {
+ int n = 0;
+ while ((prev = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ cfrom2 = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ from2 = wb_get_type(cfrom2);
+ if (from2 != WB_Regional_Indicator)
+ break;
+
+ n++;
+ }
+ if ((n % 2) == 0) return FALSE;
+ }
+
+ WB999:
+ /* WB999: Any / Any */
+ return TRUE;
+}
+
+#endif /* USE_UNICODE_WORD_BREAK */
+
+
+#ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
+
+enum EGCB_BREAK_TYPE {
+ EGCB_NOT_BREAK = 0,
+ EGCB_BREAK = 1,
+ EGCB_BREAK_UNDEF_GB11 = 2,
+ EGCB_BREAK_UNDEF_RI_RI = 3
+};
+
+enum EGCB_TYPE {
+ EGCB_Other = 0,
+ EGCB_CR = 1,
+ EGCB_LF = 2,
+ EGCB_Control = 3,
+ EGCB_Extend = 4,
+ EGCB_Prepend = 5,
+ EGCB_Regional_Indicator = 6,
+ EGCB_SpacingMark = 7,
+ EGCB_ZWJ = 8,
+#if 0
+ /* obsoleted */
+ EGCB_E_Base = 9,
+ EGCB_E_Base_GAZ = 10,
+ EGCB_E_Modifier = 11,
+ EGCB_Glue_After_Zwj = 12,
+#endif
+ EGCB_L = 13,
+ EGCB_LV = 14,
+ EGCB_LVT = 15,
+ EGCB_T = 16,
+ EGCB_V = 17
+};
+
+typedef struct {
+ OnigCodePoint start;
+ OnigCodePoint end;
+ enum EGCB_TYPE type;
+} EGCB_RANGE_TYPE;
+
+#include "unicode_egcb_data.c"
+
+static enum EGCB_TYPE
+egcb_get_type(OnigCodePoint code)
+{
+ OnigCodePoint low, high, x;
+ enum EGCB_TYPE type;
+
+ for (low = 0, high = (OnigCodePoint )EGCB_RANGE_NUM; low < high; ) {
+ x = (low + high) >> 1;
+ if (code > EGCB_RANGES[x].end)
+ low = x + 1;
+ else
+ high = x;
+ }
+
+ type = (low < (OnigCodePoint )EGCB_RANGE_NUM &&
+ code >= EGCB_RANGES[low].start) ?
+ EGCB_RANGES[low].type : EGCB_Other;
+
+ return type;
+}
+
+#define IS_CONTROL_CR_LF(code) ((code) <= EGCB_Control && (code) >= EGCB_CR)
+#define IS_HANGUL(code) ((code) >= EGCB_L)
+
+/* GB1 and GB2 are outside of this function. */
+static enum EGCB_BREAK_TYPE
+unicode_egcb_is_break_2code(OnigCodePoint from_code, OnigCodePoint to_code)
+{
+ enum EGCB_TYPE from;
+ enum EGCB_TYPE to;
+
+ from = egcb_get_type(from_code);
+ to = egcb_get_type(to_code);
+
+ /* short cut */
+ if (from == 0 && to == 0) goto GB999;
+
+ /* GB3 */
+ if (from == EGCB_CR && to == EGCB_LF) return EGCB_NOT_BREAK;
+ /* GB4 */
+ if (IS_CONTROL_CR_LF(from)) return EGCB_BREAK;
+ /* GB5 */
+ if (IS_CONTROL_CR_LF(to)) return EGCB_BREAK;
+
+ if (IS_HANGUL(from) && IS_HANGUL(to)) {
+ /* GB6 */
+ if (from == EGCB_L && to != EGCB_T) return EGCB_NOT_BREAK;
+ /* GB7 */
+ if ((from == EGCB_LV || from == EGCB_V)
+ && (to == EGCB_V || to == EGCB_T)) return EGCB_NOT_BREAK;
+
+ /* GB8 */
+ if ((to == EGCB_T) && (from == EGCB_LVT || from == EGCB_T))
+ return EGCB_NOT_BREAK;
+
+ goto GB999;
+ }
+
+ /* GB9 */
+ if (to == EGCB_Extend || to == EGCB_ZWJ) return EGCB_NOT_BREAK;
+
+ /* GB9a */
+ if (to == EGCB_SpacingMark) return EGCB_NOT_BREAK;
+ /* GB9b */
+ if (from == EGCB_Prepend) return EGCB_NOT_BREAK;
+
+ /* GB10 removed */
+
+ /* GB11 */
+ if (from == EGCB_ZWJ) {
+ if (onigenc_unicode_is_code_ctype(to_code, PROP_INDEX_EXTENDEDPICTOGRAPHIC))
+ return EGCB_BREAK_UNDEF_GB11;
+
+ goto GB999;
+ }
+
+ /* GB12, GB13 */
+ if (from == EGCB_Regional_Indicator && to == EGCB_Regional_Indicator) {
+ return EGCB_BREAK_UNDEF_RI_RI;
+ }
+
+ GB999:
+ return EGCB_BREAK;
+}
+
+#endif /* USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER */
+
+extern int
+onigenc_egcb_is_break_position(OnigEncoding enc, UChar* p, UChar* prev,
+ const UChar* start, const UChar* end)
+{
+ OnigCodePoint from;
+ OnigCodePoint to;
+#ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
+ enum EGCB_BREAK_TYPE btype;
+ enum EGCB_TYPE type;
+#endif
+
+ /* GB1 and GB2 */
+ if (p == start) return 1;
+ if (p == end) return 1;
+
+ if (IS_NULL(prev)) {
+ prev = onigenc_get_prev_char_head(enc, start, p);
+ if (IS_NULL(prev)) return 1;
+ }
+
+ from = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ to = ONIGENC_MBC_TO_CODE(enc, p, end);
+
+#ifdef USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER
+ if (! ONIGENC_IS_UNICODE_ENCODING(enc)) {
+ return from != 0x000d || to != NEWLINE_CODE;
+ }
+
+ btype = unicode_egcb_is_break_2code(from, to);
+ switch (btype) {
+ case EGCB_NOT_BREAK:
+ return 0;
+ break;
+ case EGCB_BREAK:
+ return 1;
+ break;
+
+ case EGCB_BREAK_UNDEF_GB11:
+ while ((prev = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ from = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ if (onigenc_unicode_is_code_ctype(from, PROP_INDEX_EXTENDEDPICTOGRAPHIC))
+ return 0;
+
+ type = egcb_get_type(from);
+ if (type != EGCB_Extend)
+ break;
+ }
+ break;
+
+ case EGCB_BREAK_UNDEF_RI_RI:
+ {
+ int n = 0;
+ while ((prev = onigenc_get_prev_char_head(enc, start, prev)) != NULL) {
+ from = ONIGENC_MBC_TO_CODE(enc, prev, end);
+ type = egcb_get_type(from);
+ if (type != EGCB_Regional_Indicator)
+ break;
+
+ n++;
+ }
+ if ((n % 2) == 0) return 0;
+ }
+ break;
+ }
+
+ return 1;
+
+#else
+ return from != 0x000d || to != NEWLINE_CODE;
+#endif /* USE_UNICODE_EXTENDED_GRAPHEME_CLUSTER */
+}
+
+
+#define USER_DEFINED_PROPERTY_MAX_NUM 20
+
+typedef struct {
+ int ctype;
+ OnigCodePoint* ranges;
+} UserDefinedPropertyValue;
+
+static int UserDefinedPropertyNum;
+static UserDefinedPropertyValue
+UserDefinedPropertyRanges[USER_DEFINED_PROPERTY_MAX_NUM];
+static st_table* UserDefinedPropertyTable;
+
+extern int
+onig_unicode_define_user_property(const char* name, OnigCodePoint* ranges)
+{
+ UserDefinedPropertyValue* e;
+ int r;
+ int i;
+ int n;
+ int len;
+ int c;
+ char* s;
+ UChar* uname;
+
+ if (UserDefinedPropertyNum >= USER_DEFINED_PROPERTY_MAX_NUM)
+ return ONIGERR_TOO_MANY_USER_DEFINED_OBJECTS;
+
+ len = (int )strlen(name);
+ if (len >= PROPERTY_NAME_MAX_SIZE)
+ return ONIGERR_TOO_LONG_PROPERTY_NAME;
+
+ s = (char* )xmalloc(len + 1);
+ if (s == 0)
+ return ONIGERR_MEMORY;
+
+ uname = (UChar* )name;
+ n = 0;
+ for (i = 0; i < len; i++) {
+ c = uname[i];
+ if (c < 0x20 || c >= 0x80) {
+ xfree(s);
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+ }
+
+ if (c != ' ' && c != '-' && c != '_') {
+ s[n] = c;
+ n++;
+ }
+ }
+ s[n] = '\0';
+
+ if (UserDefinedPropertyTable == 0) {
+ UserDefinedPropertyTable = onig_st_init_strend_table_with_size(10);
+ if (IS_NULL(UserDefinedPropertyTable)) {
+ xfree(s);
+ return ONIGERR_MEMORY;
+ }
+ }
+
+ e = UserDefinedPropertyRanges + UserDefinedPropertyNum;
+ e->ctype = CODE_RANGES_NUM + UserDefinedPropertyNum;
+ e->ranges = ranges;
+ r = onig_st_insert_strend(UserDefinedPropertyTable,
+ (const UChar* )s, (const UChar* )s + n,
+ (hash_data_type )((void* )e));
+ if (r < 0) return r;
+
+ UserDefinedPropertyNum++;
+ return 0;
+}
+
+extern int
+onigenc_unicode_is_code_ctype(OnigCodePoint code, unsigned int ctype)
+{
+ if (
+#ifdef USE_UNICODE_PROPERTIES
+ ctype <= ONIGENC_MAX_STD_CTYPE &&
+#endif
+ code < 256) {
+ return ONIGENC_IS_UNICODE_ISO_8859_1_CTYPE(code, ctype);
+ }
+
+ if (ctype >= CODE_RANGES_NUM) {
+ int index = ctype - CODE_RANGES_NUM;
+ if (index < UserDefinedPropertyNum)
+ return onig_is_in_code_range((UChar* )UserDefinedPropertyRanges[index].ranges, code);
+ else
+ return ONIGERR_TYPE_BUG;
+ }
+
+ return onig_is_in_code_range((UChar* )CodeRanges[ctype], code);
+}
+
+
+extern int
+onigenc_unicode_ctype_code_range(OnigCtype ctype, const OnigCodePoint* ranges[])
+{
+ if (ctype >= CODE_RANGES_NUM) {
+ int index = ctype - CODE_RANGES_NUM;
+ if (index < UserDefinedPropertyNum) {
+ *ranges = UserDefinedPropertyRanges[index].ranges;
+ return 0;
+ }
+ else
+ return ONIGERR_TYPE_BUG;
+ }
+
+ *ranges = CodeRanges[ctype];
+ return 0;
+}
+
+extern int
+onigenc_utf16_32_get_ctype_code_range(OnigCtype ctype, OnigCodePoint* sb_out,
+ const OnigCodePoint* ranges[])
+{
+ *sb_out = 0x00;
+ return onigenc_unicode_ctype_code_range(ctype, ranges);
+}
+
+extern int
+onigenc_unicode_property_name_to_ctype(OnigEncoding enc, UChar* name, UChar* end)
+{
+ int len;
+ UChar *p;
+ OnigCodePoint code;
+ const struct PoolPropertyNameCtype* pc;
+ char buf[PROPERTY_NAME_MAX_SIZE];
+
+ p = name;
+ len = 0;
+ while (p < end) {
+ code = ONIGENC_MBC_TO_CODE(enc, p, end);
+ if (code >= 0x80)
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+
+ if (code != ' ' && code != '-' && code != '_') {
+ buf[len++] = (char )code;
+ if (len >= PROPERTY_NAME_MAX_SIZE)
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+ }
+
+ p += enclen(enc, p);
+ }
+
+ buf[len] = 0;
+
+ if (UserDefinedPropertyTable != 0) {
+ UserDefinedPropertyValue* e;
+ e = (UserDefinedPropertyValue* )NULL;
+ onig_st_lookup_strend(UserDefinedPropertyTable,
+ (const UChar* )buf, (const UChar* )buf + len,
+ (hash_data_type* )((void* )(&e)));
+ if (e != 0) {
+ return e->ctype;
+ }
+ }
+
+ pc = unicode_lookup_property_name(buf, len);
+ if (pc != 0) {
+ /* fprintf(stderr, "LOOKUP: %s: %d\n", buf, pc->ctype); */
+#ifndef USE_UNICODE_PROPERTIES
+ if (pc->ctype > ONIGENC_MAX_STD_CTYPE)
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+#endif
+
+ return (int )pc->ctype;
+ }
+
+ return ONIGERR_INVALID_CHAR_PROPERTY_NAME;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_egcb_data.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_egcb_data.c
new file mode 100644
index 000000000..3c49422a5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_egcb_data.c
@@ -0,0 +1,1374 @@
+/* unicode_egcb_data.c: Generated by make_unicode_egcb_data.py. */
+/*-
+ * Copyright (c) 2017-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#define GRAPHEME_BREAK_PROPERTY_VERSION 120100
+
+/*
+CR
+Control
+Extend
+L
+LF
+LV
+LVT
+Prepend
+Regional_Indicator
+SpacingMark
+T
+V
+ZWJ
+*/
+
+static int EGCB_RANGE_NUM = 1326;
+static EGCB_RANGE_TYPE EGCB_RANGES[] = {
+ {0x000000, 0x000009, EGCB_Control },
+ {0x00000a, 0x00000a, EGCB_LF },
+ {0x00000b, 0x00000c, EGCB_Control },
+ {0x00000d, 0x00000d, EGCB_CR },
+ {0x00000e, 0x00001f, EGCB_Control },
+ {0x00007f, 0x00009f, EGCB_Control },
+ {0x0000ad, 0x0000ad, EGCB_Control },
+ {0x000300, 0x00036f, EGCB_Extend },
+ {0x000483, 0x000489, EGCB_Extend },
+ {0x000591, 0x0005bd, EGCB_Extend },
+ {0x0005bf, 0x0005bf, EGCB_Extend },
+ {0x0005c1, 0x0005c2, EGCB_Extend },
+ {0x0005c4, 0x0005c5, EGCB_Extend },
+ {0x0005c7, 0x0005c7, EGCB_Extend },
+ {0x000600, 0x000605, EGCB_Prepend },
+ {0x000610, 0x00061a, EGCB_Extend },
+ {0x00061c, 0x00061c, EGCB_Control },
+ {0x00064b, 0x00065f, EGCB_Extend },
+ {0x000670, 0x000670, EGCB_Extend },
+ {0x0006d6, 0x0006dc, EGCB_Extend },
+ {0x0006dd, 0x0006dd, EGCB_Prepend },
+ {0x0006df, 0x0006e4, EGCB_Extend },
+ {0x0006e7, 0x0006e8, EGCB_Extend },
+ {0x0006ea, 0x0006ed, EGCB_Extend },
+ {0x00070f, 0x00070f, EGCB_Prepend },
+ {0x000711, 0x000711, EGCB_Extend },
+ {0x000730, 0x00074a, EGCB_Extend },
+ {0x0007a6, 0x0007b0, EGCB_Extend },
+ {0x0007eb, 0x0007f3, EGCB_Extend },
+ {0x0007fd, 0x0007fd, EGCB_Extend },
+ {0x000816, 0x000819, EGCB_Extend },
+ {0x00081b, 0x000823, EGCB_Extend },
+ {0x000825, 0x000827, EGCB_Extend },
+ {0x000829, 0x00082d, EGCB_Extend },
+ {0x000859, 0x00085b, EGCB_Extend },
+ {0x0008d3, 0x0008e1, EGCB_Extend },
+ {0x0008e2, 0x0008e2, EGCB_Prepend },
+ {0x0008e3, 0x000902, EGCB_Extend },
+ {0x000903, 0x000903, EGCB_SpacingMark },
+ {0x00093a, 0x00093a, EGCB_Extend },
+ {0x00093b, 0x00093b, EGCB_SpacingMark },
+ {0x00093c, 0x00093c, EGCB_Extend },
+ {0x00093e, 0x000940, EGCB_SpacingMark },
+ {0x000941, 0x000948, EGCB_Extend },
+ {0x000949, 0x00094c, EGCB_SpacingMark },
+ {0x00094d, 0x00094d, EGCB_Extend },
+ {0x00094e, 0x00094f, EGCB_SpacingMark },
+ {0x000951, 0x000957, EGCB_Extend },
+ {0x000962, 0x000963, EGCB_Extend },
+ {0x000981, 0x000981, EGCB_Extend },
+ {0x000982, 0x000983, EGCB_SpacingMark },
+ {0x0009bc, 0x0009bc, EGCB_Extend },
+ {0x0009be, 0x0009be, EGCB_Extend },
+ {0x0009bf, 0x0009c0, EGCB_SpacingMark },
+ {0x0009c1, 0x0009c4, EGCB_Extend },
+ {0x0009c7, 0x0009c8, EGCB_SpacingMark },
+ {0x0009cb, 0x0009cc, EGCB_SpacingMark },
+ {0x0009cd, 0x0009cd, EGCB_Extend },
+ {0x0009d7, 0x0009d7, EGCB_Extend },
+ {0x0009e2, 0x0009e3, EGCB_Extend },
+ {0x0009fe, 0x0009fe, EGCB_Extend },
+ {0x000a01, 0x000a02, EGCB_Extend },
+ {0x000a03, 0x000a03, EGCB_SpacingMark },
+ {0x000a3c, 0x000a3c, EGCB_Extend },
+ {0x000a3e, 0x000a40, EGCB_SpacingMark },
+ {0x000a41, 0x000a42, EGCB_Extend },
+ {0x000a47, 0x000a48, EGCB_Extend },
+ {0x000a4b, 0x000a4d, EGCB_Extend },
+ {0x000a51, 0x000a51, EGCB_Extend },
+ {0x000a70, 0x000a71, EGCB_Extend },
+ {0x000a75, 0x000a75, EGCB_Extend },
+ {0x000a81, 0x000a82, EGCB_Extend },
+ {0x000a83, 0x000a83, EGCB_SpacingMark },
+ {0x000abc, 0x000abc, EGCB_Extend },
+ {0x000abe, 0x000ac0, EGCB_SpacingMark },
+ {0x000ac1, 0x000ac5, EGCB_Extend },
+ {0x000ac7, 0x000ac8, EGCB_Extend },
+ {0x000ac9, 0x000ac9, EGCB_SpacingMark },
+ {0x000acb, 0x000acc, EGCB_SpacingMark },
+ {0x000acd, 0x000acd, EGCB_Extend },
+ {0x000ae2, 0x000ae3, EGCB_Extend },
+ {0x000afa, 0x000aff, EGCB_Extend },
+ {0x000b01, 0x000b01, EGCB_Extend },
+ {0x000b02, 0x000b03, EGCB_SpacingMark },
+ {0x000b3c, 0x000b3c, EGCB_Extend },
+ {0x000b3e, 0x000b3f, EGCB_Extend },
+ {0x000b40, 0x000b40, EGCB_SpacingMark },
+ {0x000b41, 0x000b44, EGCB_Extend },
+ {0x000b47, 0x000b48, EGCB_SpacingMark },
+ {0x000b4b, 0x000b4c, EGCB_SpacingMark },
+ {0x000b4d, 0x000b4d, EGCB_Extend },
+ {0x000b56, 0x000b57, EGCB_Extend },
+ {0x000b62, 0x000b63, EGCB_Extend },
+ {0x000b82, 0x000b82, EGCB_Extend },
+ {0x000bbe, 0x000bbe, EGCB_Extend },
+ {0x000bbf, 0x000bbf, EGCB_SpacingMark },
+ {0x000bc0, 0x000bc0, EGCB_Extend },
+ {0x000bc1, 0x000bc2, EGCB_SpacingMark },
+ {0x000bc6, 0x000bc8, EGCB_SpacingMark },
+ {0x000bca, 0x000bcc, EGCB_SpacingMark },
+ {0x000bcd, 0x000bcd, EGCB_Extend },
+ {0x000bd7, 0x000bd7, EGCB_Extend },
+ {0x000c00, 0x000c00, EGCB_Extend },
+ {0x000c01, 0x000c03, EGCB_SpacingMark },
+ {0x000c04, 0x000c04, EGCB_Extend },
+ {0x000c3e, 0x000c40, EGCB_Extend },
+ {0x000c41, 0x000c44, EGCB_SpacingMark },
+ {0x000c46, 0x000c48, EGCB_Extend },
+ {0x000c4a, 0x000c4d, EGCB_Extend },
+ {0x000c55, 0x000c56, EGCB_Extend },
+ {0x000c62, 0x000c63, EGCB_Extend },
+ {0x000c81, 0x000c81, EGCB_Extend },
+ {0x000c82, 0x000c83, EGCB_SpacingMark },
+ {0x000cbc, 0x000cbc, EGCB_Extend },
+ {0x000cbe, 0x000cbe, EGCB_SpacingMark },
+ {0x000cbf, 0x000cbf, EGCB_Extend },
+ {0x000cc0, 0x000cc1, EGCB_SpacingMark },
+ {0x000cc2, 0x000cc2, EGCB_Extend },
+ {0x000cc3, 0x000cc4, EGCB_SpacingMark },
+ {0x000cc6, 0x000cc6, EGCB_Extend },
+ {0x000cc7, 0x000cc8, EGCB_SpacingMark },
+ {0x000cca, 0x000ccb, EGCB_SpacingMark },
+ {0x000ccc, 0x000ccd, EGCB_Extend },
+ {0x000cd5, 0x000cd6, EGCB_Extend },
+ {0x000ce2, 0x000ce3, EGCB_Extend },
+ {0x000d00, 0x000d01, EGCB_Extend },
+ {0x000d02, 0x000d03, EGCB_SpacingMark },
+ {0x000d3b, 0x000d3c, EGCB_Extend },
+ {0x000d3e, 0x000d3e, EGCB_Extend },
+ {0x000d3f, 0x000d40, EGCB_SpacingMark },
+ {0x000d41, 0x000d44, EGCB_Extend },
+ {0x000d46, 0x000d48, EGCB_SpacingMark },
+ {0x000d4a, 0x000d4c, EGCB_SpacingMark },
+ {0x000d4d, 0x000d4d, EGCB_Extend },
+ {0x000d4e, 0x000d4e, EGCB_Prepend },
+ {0x000d57, 0x000d57, EGCB_Extend },
+ {0x000d62, 0x000d63, EGCB_Extend },
+ {0x000d82, 0x000d83, EGCB_SpacingMark },
+ {0x000dca, 0x000dca, EGCB_Extend },
+ {0x000dcf, 0x000dcf, EGCB_Extend },
+ {0x000dd0, 0x000dd1, EGCB_SpacingMark },
+ {0x000dd2, 0x000dd4, EGCB_Extend },
+ {0x000dd6, 0x000dd6, EGCB_Extend },
+ {0x000dd8, 0x000dde, EGCB_SpacingMark },
+ {0x000ddf, 0x000ddf, EGCB_Extend },
+ {0x000df2, 0x000df3, EGCB_SpacingMark },
+ {0x000e31, 0x000e31, EGCB_Extend },
+ {0x000e33, 0x000e33, EGCB_SpacingMark },
+ {0x000e34, 0x000e3a, EGCB_Extend },
+ {0x000e47, 0x000e4e, EGCB_Extend },
+ {0x000eb1, 0x000eb1, EGCB_Extend },
+ {0x000eb3, 0x000eb3, EGCB_SpacingMark },
+ {0x000eb4, 0x000ebc, EGCB_Extend },
+ {0x000ec8, 0x000ecd, EGCB_Extend },
+ {0x000f18, 0x000f19, EGCB_Extend },
+ {0x000f35, 0x000f35, EGCB_Extend },
+ {0x000f37, 0x000f37, EGCB_Extend },
+ {0x000f39, 0x000f39, EGCB_Extend },
+ {0x000f3e, 0x000f3f, EGCB_SpacingMark },
+ {0x000f71, 0x000f7e, EGCB_Extend },
+ {0x000f7f, 0x000f7f, EGCB_SpacingMark },
+ {0x000f80, 0x000f84, EGCB_Extend },
+ {0x000f86, 0x000f87, EGCB_Extend },
+ {0x000f8d, 0x000f97, EGCB_Extend },
+ {0x000f99, 0x000fbc, EGCB_Extend },
+ {0x000fc6, 0x000fc6, EGCB_Extend },
+ {0x00102d, 0x001030, EGCB_Extend },
+ {0x001031, 0x001031, EGCB_SpacingMark },
+ {0x001032, 0x001037, EGCB_Extend },
+ {0x001039, 0x00103a, EGCB_Extend },
+ {0x00103b, 0x00103c, EGCB_SpacingMark },
+ {0x00103d, 0x00103e, EGCB_Extend },
+ {0x001056, 0x001057, EGCB_SpacingMark },
+ {0x001058, 0x001059, EGCB_Extend },
+ {0x00105e, 0x001060, EGCB_Extend },
+ {0x001071, 0x001074, EGCB_Extend },
+ {0x001082, 0x001082, EGCB_Extend },
+ {0x001084, 0x001084, EGCB_SpacingMark },
+ {0x001085, 0x001086, EGCB_Extend },
+ {0x00108d, 0x00108d, EGCB_Extend },
+ {0x00109d, 0x00109d, EGCB_Extend },
+ {0x001100, 0x00115f, EGCB_L },
+ {0x001160, 0x0011a7, EGCB_V },
+ {0x0011a8, 0x0011ff, EGCB_T },
+ {0x00135d, 0x00135f, EGCB_Extend },
+ {0x001712, 0x001714, EGCB_Extend },
+ {0x001732, 0x001734, EGCB_Extend },
+ {0x001752, 0x001753, EGCB_Extend },
+ {0x001772, 0x001773, EGCB_Extend },
+ {0x0017b4, 0x0017b5, EGCB_Extend },
+ {0x0017b6, 0x0017b6, EGCB_SpacingMark },
+ {0x0017b7, 0x0017bd, EGCB_Extend },
+ {0x0017be, 0x0017c5, EGCB_SpacingMark },
+ {0x0017c6, 0x0017c6, EGCB_Extend },
+ {0x0017c7, 0x0017c8, EGCB_SpacingMark },
+ {0x0017c9, 0x0017d3, EGCB_Extend },
+ {0x0017dd, 0x0017dd, EGCB_Extend },
+ {0x00180b, 0x00180d, EGCB_Extend },
+ {0x00180e, 0x00180e, EGCB_Control },
+ {0x001885, 0x001886, EGCB_Extend },
+ {0x0018a9, 0x0018a9, EGCB_Extend },
+ {0x001920, 0x001922, EGCB_Extend },
+ {0x001923, 0x001926, EGCB_SpacingMark },
+ {0x001927, 0x001928, EGCB_Extend },
+ {0x001929, 0x00192b, EGCB_SpacingMark },
+ {0x001930, 0x001931, EGCB_SpacingMark },
+ {0x001932, 0x001932, EGCB_Extend },
+ {0x001933, 0x001938, EGCB_SpacingMark },
+ {0x001939, 0x00193b, EGCB_Extend },
+ {0x001a17, 0x001a18, EGCB_Extend },
+ {0x001a19, 0x001a1a, EGCB_SpacingMark },
+ {0x001a1b, 0x001a1b, EGCB_Extend },
+ {0x001a55, 0x001a55, EGCB_SpacingMark },
+ {0x001a56, 0x001a56, EGCB_Extend },
+ {0x001a57, 0x001a57, EGCB_SpacingMark },
+ {0x001a58, 0x001a5e, EGCB_Extend },
+ {0x001a60, 0x001a60, EGCB_Extend },
+ {0x001a62, 0x001a62, EGCB_Extend },
+ {0x001a65, 0x001a6c, EGCB_Extend },
+ {0x001a6d, 0x001a72, EGCB_SpacingMark },
+ {0x001a73, 0x001a7c, EGCB_Extend },
+ {0x001a7f, 0x001a7f, EGCB_Extend },
+ {0x001ab0, 0x001abe, EGCB_Extend },
+ {0x001b00, 0x001b03, EGCB_Extend },
+ {0x001b04, 0x001b04, EGCB_SpacingMark },
+ {0x001b34, 0x001b3a, EGCB_Extend },
+ {0x001b3b, 0x001b3b, EGCB_SpacingMark },
+ {0x001b3c, 0x001b3c, EGCB_Extend },
+ {0x001b3d, 0x001b41, EGCB_SpacingMark },
+ {0x001b42, 0x001b42, EGCB_Extend },
+ {0x001b43, 0x001b44, EGCB_SpacingMark },
+ {0x001b6b, 0x001b73, EGCB_Extend },
+ {0x001b80, 0x001b81, EGCB_Extend },
+ {0x001b82, 0x001b82, EGCB_SpacingMark },
+ {0x001ba1, 0x001ba1, EGCB_SpacingMark },
+ {0x001ba2, 0x001ba5, EGCB_Extend },
+ {0x001ba6, 0x001ba7, EGCB_SpacingMark },
+ {0x001ba8, 0x001ba9, EGCB_Extend },
+ {0x001baa, 0x001baa, EGCB_SpacingMark },
+ {0x001bab, 0x001bad, EGCB_Extend },
+ {0x001be6, 0x001be6, EGCB_Extend },
+ {0x001be7, 0x001be7, EGCB_SpacingMark },
+ {0x001be8, 0x001be9, EGCB_Extend },
+ {0x001bea, 0x001bec, EGCB_SpacingMark },
+ {0x001bed, 0x001bed, EGCB_Extend },
+ {0x001bee, 0x001bee, EGCB_SpacingMark },
+ {0x001bef, 0x001bf1, EGCB_Extend },
+ {0x001bf2, 0x001bf3, EGCB_SpacingMark },
+ {0x001c24, 0x001c2b, EGCB_SpacingMark },
+ {0x001c2c, 0x001c33, EGCB_Extend },
+ {0x001c34, 0x001c35, EGCB_SpacingMark },
+ {0x001c36, 0x001c37, EGCB_Extend },
+ {0x001cd0, 0x001cd2, EGCB_Extend },
+ {0x001cd4, 0x001ce0, EGCB_Extend },
+ {0x001ce1, 0x001ce1, EGCB_SpacingMark },
+ {0x001ce2, 0x001ce8, EGCB_Extend },
+ {0x001ced, 0x001ced, EGCB_Extend },
+ {0x001cf4, 0x001cf4, EGCB_Extend },
+ {0x001cf7, 0x001cf7, EGCB_SpacingMark },
+ {0x001cf8, 0x001cf9, EGCB_Extend },
+ {0x001dc0, 0x001df9, EGCB_Extend },
+ {0x001dfb, 0x001dff, EGCB_Extend },
+ {0x00200b, 0x00200b, EGCB_Control },
+ {0x00200c, 0x00200c, EGCB_Extend },
+ {0x00200d, 0x00200d, EGCB_ZWJ },
+ {0x00200e, 0x00200f, EGCB_Control },
+ {0x002028, 0x00202e, EGCB_Control },
+ {0x002060, 0x00206f, EGCB_Control },
+ {0x0020d0, 0x0020f0, EGCB_Extend },
+ {0x002cef, 0x002cf1, EGCB_Extend },
+ {0x002d7f, 0x002d7f, EGCB_Extend },
+ {0x002de0, 0x002dff, EGCB_Extend },
+ {0x00302a, 0x00302f, EGCB_Extend },
+ {0x003099, 0x00309a, EGCB_Extend },
+ {0x00a66f, 0x00a672, EGCB_Extend },
+ {0x00a674, 0x00a67d, EGCB_Extend },
+ {0x00a69e, 0x00a69f, EGCB_Extend },
+ {0x00a6f0, 0x00a6f1, EGCB_Extend },
+ {0x00a802, 0x00a802, EGCB_Extend },
+ {0x00a806, 0x00a806, EGCB_Extend },
+ {0x00a80b, 0x00a80b, EGCB_Extend },
+ {0x00a823, 0x00a824, EGCB_SpacingMark },
+ {0x00a825, 0x00a826, EGCB_Extend },
+ {0x00a827, 0x00a827, EGCB_SpacingMark },
+ {0x00a880, 0x00a881, EGCB_SpacingMark },
+ {0x00a8b4, 0x00a8c3, EGCB_SpacingMark },
+ {0x00a8c4, 0x00a8c5, EGCB_Extend },
+ {0x00a8e0, 0x00a8f1, EGCB_Extend },
+ {0x00a8ff, 0x00a8ff, EGCB_Extend },
+ {0x00a926, 0x00a92d, EGCB_Extend },
+ {0x00a947, 0x00a951, EGCB_Extend },
+ {0x00a952, 0x00a953, EGCB_SpacingMark },
+ {0x00a960, 0x00a97c, EGCB_L },
+ {0x00a980, 0x00a982, EGCB_Extend },
+ {0x00a983, 0x00a983, EGCB_SpacingMark },
+ {0x00a9b3, 0x00a9b3, EGCB_Extend },
+ {0x00a9b4, 0x00a9b5, EGCB_SpacingMark },
+ {0x00a9b6, 0x00a9b9, EGCB_Extend },
+ {0x00a9ba, 0x00a9bb, EGCB_SpacingMark },
+ {0x00a9bc, 0x00a9bd, EGCB_Extend },
+ {0x00a9be, 0x00a9c0, EGCB_SpacingMark },
+ {0x00a9e5, 0x00a9e5, EGCB_Extend },
+ {0x00aa29, 0x00aa2e, EGCB_Extend },
+ {0x00aa2f, 0x00aa30, EGCB_SpacingMark },
+ {0x00aa31, 0x00aa32, EGCB_Extend },
+ {0x00aa33, 0x00aa34, EGCB_SpacingMark },
+ {0x00aa35, 0x00aa36, EGCB_Extend },
+ {0x00aa43, 0x00aa43, EGCB_Extend },
+ {0x00aa4c, 0x00aa4c, EGCB_Extend },
+ {0x00aa4d, 0x00aa4d, EGCB_SpacingMark },
+ {0x00aa7c, 0x00aa7c, EGCB_Extend },
+ {0x00aab0, 0x00aab0, EGCB_Extend },
+ {0x00aab2, 0x00aab4, EGCB_Extend },
+ {0x00aab7, 0x00aab8, EGCB_Extend },
+ {0x00aabe, 0x00aabf, EGCB_Extend },
+ {0x00aac1, 0x00aac1, EGCB_Extend },
+ {0x00aaeb, 0x00aaeb, EGCB_SpacingMark },
+ {0x00aaec, 0x00aaed, EGCB_Extend },
+ {0x00aaee, 0x00aaef, EGCB_SpacingMark },
+ {0x00aaf5, 0x00aaf5, EGCB_SpacingMark },
+ {0x00aaf6, 0x00aaf6, EGCB_Extend },
+ {0x00abe3, 0x00abe4, EGCB_SpacingMark },
+ {0x00abe5, 0x00abe5, EGCB_Extend },
+ {0x00abe6, 0x00abe7, EGCB_SpacingMark },
+ {0x00abe8, 0x00abe8, EGCB_Extend },
+ {0x00abe9, 0x00abea, EGCB_SpacingMark },
+ {0x00abec, 0x00abec, EGCB_SpacingMark },
+ {0x00abed, 0x00abed, EGCB_Extend },
+ {0x00ac00, 0x00ac00, EGCB_LV },
+ {0x00ac01, 0x00ac1b, EGCB_LVT },
+ {0x00ac1c, 0x00ac1c, EGCB_LV },
+ {0x00ac1d, 0x00ac37, EGCB_LVT },
+ {0x00ac38, 0x00ac38, EGCB_LV },
+ {0x00ac39, 0x00ac53, EGCB_LVT },
+ {0x00ac54, 0x00ac54, EGCB_LV },
+ {0x00ac55, 0x00ac6f, EGCB_LVT },
+ {0x00ac70, 0x00ac70, EGCB_LV },
+ {0x00ac71, 0x00ac8b, EGCB_LVT },
+ {0x00ac8c, 0x00ac8c, EGCB_LV },
+ {0x00ac8d, 0x00aca7, EGCB_LVT },
+ {0x00aca8, 0x00aca8, EGCB_LV },
+ {0x00aca9, 0x00acc3, EGCB_LVT },
+ {0x00acc4, 0x00acc4, EGCB_LV },
+ {0x00acc5, 0x00acdf, EGCB_LVT },
+ {0x00ace0, 0x00ace0, EGCB_LV },
+ {0x00ace1, 0x00acfb, EGCB_LVT },
+ {0x00acfc, 0x00acfc, EGCB_LV },
+ {0x00acfd, 0x00ad17, EGCB_LVT },
+ {0x00ad18, 0x00ad18, EGCB_LV },
+ {0x00ad19, 0x00ad33, EGCB_LVT },
+ {0x00ad34, 0x00ad34, EGCB_LV },
+ {0x00ad35, 0x00ad4f, EGCB_LVT },
+ {0x00ad50, 0x00ad50, EGCB_LV },
+ {0x00ad51, 0x00ad6b, EGCB_LVT },
+ {0x00ad6c, 0x00ad6c, EGCB_LV },
+ {0x00ad6d, 0x00ad87, EGCB_LVT },
+ {0x00ad88, 0x00ad88, EGCB_LV },
+ {0x00ad89, 0x00ada3, EGCB_LVT },
+ {0x00ada4, 0x00ada4, EGCB_LV },
+ {0x00ada5, 0x00adbf, EGCB_LVT },
+ {0x00adc0, 0x00adc0, EGCB_LV },
+ {0x00adc1, 0x00addb, EGCB_LVT },
+ {0x00addc, 0x00addc, EGCB_LV },
+ {0x00addd, 0x00adf7, EGCB_LVT },
+ {0x00adf8, 0x00adf8, EGCB_LV },
+ {0x00adf9, 0x00ae13, EGCB_LVT },
+ {0x00ae14, 0x00ae14, EGCB_LV },
+ {0x00ae15, 0x00ae2f, EGCB_LVT },
+ {0x00ae30, 0x00ae30, EGCB_LV },
+ {0x00ae31, 0x00ae4b, EGCB_LVT },
+ {0x00ae4c, 0x00ae4c, EGCB_LV },
+ {0x00ae4d, 0x00ae67, EGCB_LVT },
+ {0x00ae68, 0x00ae68, EGCB_LV },
+ {0x00ae69, 0x00ae83, EGCB_LVT },
+ {0x00ae84, 0x00ae84, EGCB_LV },
+ {0x00ae85, 0x00ae9f, EGCB_LVT },
+ {0x00aea0, 0x00aea0, EGCB_LV },
+ {0x00aea1, 0x00aebb, EGCB_LVT },
+ {0x00aebc, 0x00aebc, EGCB_LV },
+ {0x00aebd, 0x00aed7, EGCB_LVT },
+ {0x00aed8, 0x00aed8, EGCB_LV },
+ {0x00aed9, 0x00aef3, EGCB_LVT },
+ {0x00aef4, 0x00aef4, EGCB_LV },
+ {0x00aef5, 0x00af0f, EGCB_LVT },
+ {0x00af10, 0x00af10, EGCB_LV },
+ {0x00af11, 0x00af2b, EGCB_LVT },
+ {0x00af2c, 0x00af2c, EGCB_LV },
+ {0x00af2d, 0x00af47, EGCB_LVT },
+ {0x00af48, 0x00af48, EGCB_LV },
+ {0x00af49, 0x00af63, EGCB_LVT },
+ {0x00af64, 0x00af64, EGCB_LV },
+ {0x00af65, 0x00af7f, EGCB_LVT },
+ {0x00af80, 0x00af80, EGCB_LV },
+ {0x00af81, 0x00af9b, EGCB_LVT },
+ {0x00af9c, 0x00af9c, EGCB_LV },
+ {0x00af9d, 0x00afb7, EGCB_LVT },
+ {0x00afb8, 0x00afb8, EGCB_LV },
+ {0x00afb9, 0x00afd3, EGCB_LVT },
+ {0x00afd4, 0x00afd4, EGCB_LV },
+ {0x00afd5, 0x00afef, EGCB_LVT },
+ {0x00aff0, 0x00aff0, EGCB_LV },
+ {0x00aff1, 0x00b00b, EGCB_LVT },
+ {0x00b00c, 0x00b00c, EGCB_LV },
+ {0x00b00d, 0x00b027, EGCB_LVT },
+ {0x00b028, 0x00b028, EGCB_LV },
+ {0x00b029, 0x00b043, EGCB_LVT },
+ {0x00b044, 0x00b044, EGCB_LV },
+ {0x00b045, 0x00b05f, EGCB_LVT },
+ {0x00b060, 0x00b060, EGCB_LV },
+ {0x00b061, 0x00b07b, EGCB_LVT },
+ {0x00b07c, 0x00b07c, EGCB_LV },
+ {0x00b07d, 0x00b097, EGCB_LVT },
+ {0x00b098, 0x00b098, EGCB_LV },
+ {0x00b099, 0x00b0b3, EGCB_LVT },
+ {0x00b0b4, 0x00b0b4, EGCB_LV },
+ {0x00b0b5, 0x00b0cf, EGCB_LVT },
+ {0x00b0d0, 0x00b0d0, EGCB_LV },
+ {0x00b0d1, 0x00b0eb, EGCB_LVT },
+ {0x00b0ec, 0x00b0ec, EGCB_LV },
+ {0x00b0ed, 0x00b107, EGCB_LVT },
+ {0x00b108, 0x00b108, EGCB_LV },
+ {0x00b109, 0x00b123, EGCB_LVT },
+ {0x00b124, 0x00b124, EGCB_LV },
+ {0x00b125, 0x00b13f, EGCB_LVT },
+ {0x00b140, 0x00b140, EGCB_LV },
+ {0x00b141, 0x00b15b, EGCB_LVT },
+ {0x00b15c, 0x00b15c, EGCB_LV },
+ {0x00b15d, 0x00b177, EGCB_LVT },
+ {0x00b178, 0x00b178, EGCB_LV },
+ {0x00b179, 0x00b193, EGCB_LVT },
+ {0x00b194, 0x00b194, EGCB_LV },
+ {0x00b195, 0x00b1af, EGCB_LVT },
+ {0x00b1b0, 0x00b1b0, EGCB_LV },
+ {0x00b1b1, 0x00b1cb, EGCB_LVT },
+ {0x00b1cc, 0x00b1cc, EGCB_LV },
+ {0x00b1cd, 0x00b1e7, EGCB_LVT },
+ {0x00b1e8, 0x00b1e8, EGCB_LV },
+ {0x00b1e9, 0x00b203, EGCB_LVT },
+ {0x00b204, 0x00b204, EGCB_LV },
+ {0x00b205, 0x00b21f, EGCB_LVT },
+ {0x00b220, 0x00b220, EGCB_LV },
+ {0x00b221, 0x00b23b, EGCB_LVT },
+ {0x00b23c, 0x00b23c, EGCB_LV },
+ {0x00b23d, 0x00b257, EGCB_LVT },
+ {0x00b258, 0x00b258, EGCB_LV },
+ {0x00b259, 0x00b273, EGCB_LVT },
+ {0x00b274, 0x00b274, EGCB_LV },
+ {0x00b275, 0x00b28f, EGCB_LVT },
+ {0x00b290, 0x00b290, EGCB_LV },
+ {0x00b291, 0x00b2ab, EGCB_LVT },
+ {0x00b2ac, 0x00b2ac, EGCB_LV },
+ {0x00b2ad, 0x00b2c7, EGCB_LVT },
+ {0x00b2c8, 0x00b2c8, EGCB_LV },
+ {0x00b2c9, 0x00b2e3, EGCB_LVT },
+ {0x00b2e4, 0x00b2e4, EGCB_LV },
+ {0x00b2e5, 0x00b2ff, EGCB_LVT },
+ {0x00b300, 0x00b300, EGCB_LV },
+ {0x00b301, 0x00b31b, EGCB_LVT },
+ {0x00b31c, 0x00b31c, EGCB_LV },
+ {0x00b31d, 0x00b337, EGCB_LVT },
+ {0x00b338, 0x00b338, EGCB_LV },
+ {0x00b339, 0x00b353, EGCB_LVT },
+ {0x00b354, 0x00b354, EGCB_LV },
+ {0x00b355, 0x00b36f, EGCB_LVT },
+ {0x00b370, 0x00b370, EGCB_LV },
+ {0x00b371, 0x00b38b, EGCB_LVT },
+ {0x00b38c, 0x00b38c, EGCB_LV },
+ {0x00b38d, 0x00b3a7, EGCB_LVT },
+ {0x00b3a8, 0x00b3a8, EGCB_LV },
+ {0x00b3a9, 0x00b3c3, EGCB_LVT },
+ {0x00b3c4, 0x00b3c4, EGCB_LV },
+ {0x00b3c5, 0x00b3df, EGCB_LVT },
+ {0x00b3e0, 0x00b3e0, EGCB_LV },
+ {0x00b3e1, 0x00b3fb, EGCB_LVT },
+ {0x00b3fc, 0x00b3fc, EGCB_LV },
+ {0x00b3fd, 0x00b417, EGCB_LVT },
+ {0x00b418, 0x00b418, EGCB_LV },
+ {0x00b419, 0x00b433, EGCB_LVT },
+ {0x00b434, 0x00b434, EGCB_LV },
+ {0x00b435, 0x00b44f, EGCB_LVT },
+ {0x00b450, 0x00b450, EGCB_LV },
+ {0x00b451, 0x00b46b, EGCB_LVT },
+ {0x00b46c, 0x00b46c, EGCB_LV },
+ {0x00b46d, 0x00b487, EGCB_LVT },
+ {0x00b488, 0x00b488, EGCB_LV },
+ {0x00b489, 0x00b4a3, EGCB_LVT },
+ {0x00b4a4, 0x00b4a4, EGCB_LV },
+ {0x00b4a5, 0x00b4bf, EGCB_LVT },
+ {0x00b4c0, 0x00b4c0, EGCB_LV },
+ {0x00b4c1, 0x00b4db, EGCB_LVT },
+ {0x00b4dc, 0x00b4dc, EGCB_LV },
+ {0x00b4dd, 0x00b4f7, EGCB_LVT },
+ {0x00b4f8, 0x00b4f8, EGCB_LV },
+ {0x00b4f9, 0x00b513, EGCB_LVT },
+ {0x00b514, 0x00b514, EGCB_LV },
+ {0x00b515, 0x00b52f, EGCB_LVT },
+ {0x00b530, 0x00b530, EGCB_LV },
+ {0x00b531, 0x00b54b, EGCB_LVT },
+ {0x00b54c, 0x00b54c, EGCB_LV },
+ {0x00b54d, 0x00b567, EGCB_LVT },
+ {0x00b568, 0x00b568, EGCB_LV },
+ {0x00b569, 0x00b583, EGCB_LVT },
+ {0x00b584, 0x00b584, EGCB_LV },
+ {0x00b585, 0x00b59f, EGCB_LVT },
+ {0x00b5a0, 0x00b5a0, EGCB_LV },
+ {0x00b5a1, 0x00b5bb, EGCB_LVT },
+ {0x00b5bc, 0x00b5bc, EGCB_LV },
+ {0x00b5bd, 0x00b5d7, EGCB_LVT },
+ {0x00b5d8, 0x00b5d8, EGCB_LV },
+ {0x00b5d9, 0x00b5f3, EGCB_LVT },
+ {0x00b5f4, 0x00b5f4, EGCB_LV },
+ {0x00b5f5, 0x00b60f, EGCB_LVT },
+ {0x00b610, 0x00b610, EGCB_LV },
+ {0x00b611, 0x00b62b, EGCB_LVT },
+ {0x00b62c, 0x00b62c, EGCB_LV },
+ {0x00b62d, 0x00b647, EGCB_LVT },
+ {0x00b648, 0x00b648, EGCB_LV },
+ {0x00b649, 0x00b663, EGCB_LVT },
+ {0x00b664, 0x00b664, EGCB_LV },
+ {0x00b665, 0x00b67f, EGCB_LVT },
+ {0x00b680, 0x00b680, EGCB_LV },
+ {0x00b681, 0x00b69b, EGCB_LVT },
+ {0x00b69c, 0x00b69c, EGCB_LV },
+ {0x00b69d, 0x00b6b7, EGCB_LVT },
+ {0x00b6b8, 0x00b6b8, EGCB_LV },
+ {0x00b6b9, 0x00b6d3, EGCB_LVT },
+ {0x00b6d4, 0x00b6d4, EGCB_LV },
+ {0x00b6d5, 0x00b6ef, EGCB_LVT },
+ {0x00b6f0, 0x00b6f0, EGCB_LV },
+ {0x00b6f1, 0x00b70b, EGCB_LVT },
+ {0x00b70c, 0x00b70c, EGCB_LV },
+ {0x00b70d, 0x00b727, EGCB_LVT },
+ {0x00b728, 0x00b728, EGCB_LV },
+ {0x00b729, 0x00b743, EGCB_LVT },
+ {0x00b744, 0x00b744, EGCB_LV },
+ {0x00b745, 0x00b75f, EGCB_LVT },
+ {0x00b760, 0x00b760, EGCB_LV },
+ {0x00b761, 0x00b77b, EGCB_LVT },
+ {0x00b77c, 0x00b77c, EGCB_LV },
+ {0x00b77d, 0x00b797, EGCB_LVT },
+ {0x00b798, 0x00b798, EGCB_LV },
+ {0x00b799, 0x00b7b3, EGCB_LVT },
+ {0x00b7b4, 0x00b7b4, EGCB_LV },
+ {0x00b7b5, 0x00b7cf, EGCB_LVT },
+ {0x00b7d0, 0x00b7d0, EGCB_LV },
+ {0x00b7d1, 0x00b7eb, EGCB_LVT },
+ {0x00b7ec, 0x00b7ec, EGCB_LV },
+ {0x00b7ed, 0x00b807, EGCB_LVT },
+ {0x00b808, 0x00b808, EGCB_LV },
+ {0x00b809, 0x00b823, EGCB_LVT },
+ {0x00b824, 0x00b824, EGCB_LV },
+ {0x00b825, 0x00b83f, EGCB_LVT },
+ {0x00b840, 0x00b840, EGCB_LV },
+ {0x00b841, 0x00b85b, EGCB_LVT },
+ {0x00b85c, 0x00b85c, EGCB_LV },
+ {0x00b85d, 0x00b877, EGCB_LVT },
+ {0x00b878, 0x00b878, EGCB_LV },
+ {0x00b879, 0x00b893, EGCB_LVT },
+ {0x00b894, 0x00b894, EGCB_LV },
+ {0x00b895, 0x00b8af, EGCB_LVT },
+ {0x00b8b0, 0x00b8b0, EGCB_LV },
+ {0x00b8b1, 0x00b8cb, EGCB_LVT },
+ {0x00b8cc, 0x00b8cc, EGCB_LV },
+ {0x00b8cd, 0x00b8e7, EGCB_LVT },
+ {0x00b8e8, 0x00b8e8, EGCB_LV },
+ {0x00b8e9, 0x00b903, EGCB_LVT },
+ {0x00b904, 0x00b904, EGCB_LV },
+ {0x00b905, 0x00b91f, EGCB_LVT },
+ {0x00b920, 0x00b920, EGCB_LV },
+ {0x00b921, 0x00b93b, EGCB_LVT },
+ {0x00b93c, 0x00b93c, EGCB_LV },
+ {0x00b93d, 0x00b957, EGCB_LVT },
+ {0x00b958, 0x00b958, EGCB_LV },
+ {0x00b959, 0x00b973, EGCB_LVT },
+ {0x00b974, 0x00b974, EGCB_LV },
+ {0x00b975, 0x00b98f, EGCB_LVT },
+ {0x00b990, 0x00b990, EGCB_LV },
+ {0x00b991, 0x00b9ab, EGCB_LVT },
+ {0x00b9ac, 0x00b9ac, EGCB_LV },
+ {0x00b9ad, 0x00b9c7, EGCB_LVT },
+ {0x00b9c8, 0x00b9c8, EGCB_LV },
+ {0x00b9c9, 0x00b9e3, EGCB_LVT },
+ {0x00b9e4, 0x00b9e4, EGCB_LV },
+ {0x00b9e5, 0x00b9ff, EGCB_LVT },
+ {0x00ba00, 0x00ba00, EGCB_LV },
+ {0x00ba01, 0x00ba1b, EGCB_LVT },
+ {0x00ba1c, 0x00ba1c, EGCB_LV },
+ {0x00ba1d, 0x00ba37, EGCB_LVT },
+ {0x00ba38, 0x00ba38, EGCB_LV },
+ {0x00ba39, 0x00ba53, EGCB_LVT },
+ {0x00ba54, 0x00ba54, EGCB_LV },
+ {0x00ba55, 0x00ba6f, EGCB_LVT },
+ {0x00ba70, 0x00ba70, EGCB_LV },
+ {0x00ba71, 0x00ba8b, EGCB_LVT },
+ {0x00ba8c, 0x00ba8c, EGCB_LV },
+ {0x00ba8d, 0x00baa7, EGCB_LVT },
+ {0x00baa8, 0x00baa8, EGCB_LV },
+ {0x00baa9, 0x00bac3, EGCB_LVT },
+ {0x00bac4, 0x00bac4, EGCB_LV },
+ {0x00bac5, 0x00badf, EGCB_LVT },
+ {0x00bae0, 0x00bae0, EGCB_LV },
+ {0x00bae1, 0x00bafb, EGCB_LVT },
+ {0x00bafc, 0x00bafc, EGCB_LV },
+ {0x00bafd, 0x00bb17, EGCB_LVT },
+ {0x00bb18, 0x00bb18, EGCB_LV },
+ {0x00bb19, 0x00bb33, EGCB_LVT },
+ {0x00bb34, 0x00bb34, EGCB_LV },
+ {0x00bb35, 0x00bb4f, EGCB_LVT },
+ {0x00bb50, 0x00bb50, EGCB_LV },
+ {0x00bb51, 0x00bb6b, EGCB_LVT },
+ {0x00bb6c, 0x00bb6c, EGCB_LV },
+ {0x00bb6d, 0x00bb87, EGCB_LVT },
+ {0x00bb88, 0x00bb88, EGCB_LV },
+ {0x00bb89, 0x00bba3, EGCB_LVT },
+ {0x00bba4, 0x00bba4, EGCB_LV },
+ {0x00bba5, 0x00bbbf, EGCB_LVT },
+ {0x00bbc0, 0x00bbc0, EGCB_LV },
+ {0x00bbc1, 0x00bbdb, EGCB_LVT },
+ {0x00bbdc, 0x00bbdc, EGCB_LV },
+ {0x00bbdd, 0x00bbf7, EGCB_LVT },
+ {0x00bbf8, 0x00bbf8, EGCB_LV },
+ {0x00bbf9, 0x00bc13, EGCB_LVT },
+ {0x00bc14, 0x00bc14, EGCB_LV },
+ {0x00bc15, 0x00bc2f, EGCB_LVT },
+ {0x00bc30, 0x00bc30, EGCB_LV },
+ {0x00bc31, 0x00bc4b, EGCB_LVT },
+ {0x00bc4c, 0x00bc4c, EGCB_LV },
+ {0x00bc4d, 0x00bc67, EGCB_LVT },
+ {0x00bc68, 0x00bc68, EGCB_LV },
+ {0x00bc69, 0x00bc83, EGCB_LVT },
+ {0x00bc84, 0x00bc84, EGCB_LV },
+ {0x00bc85, 0x00bc9f, EGCB_LVT },
+ {0x00bca0, 0x00bca0, EGCB_LV },
+ {0x00bca1, 0x00bcbb, EGCB_LVT },
+ {0x00bcbc, 0x00bcbc, EGCB_LV },
+ {0x00bcbd, 0x00bcd7, EGCB_LVT },
+ {0x00bcd8, 0x00bcd8, EGCB_LV },
+ {0x00bcd9, 0x00bcf3, EGCB_LVT },
+ {0x00bcf4, 0x00bcf4, EGCB_LV },
+ {0x00bcf5, 0x00bd0f, EGCB_LVT },
+ {0x00bd10, 0x00bd10, EGCB_LV },
+ {0x00bd11, 0x00bd2b, EGCB_LVT },
+ {0x00bd2c, 0x00bd2c, EGCB_LV },
+ {0x00bd2d, 0x00bd47, EGCB_LVT },
+ {0x00bd48, 0x00bd48, EGCB_LV },
+ {0x00bd49, 0x00bd63, EGCB_LVT },
+ {0x00bd64, 0x00bd64, EGCB_LV },
+ {0x00bd65, 0x00bd7f, EGCB_LVT },
+ {0x00bd80, 0x00bd80, EGCB_LV },
+ {0x00bd81, 0x00bd9b, EGCB_LVT },
+ {0x00bd9c, 0x00bd9c, EGCB_LV },
+ {0x00bd9d, 0x00bdb7, EGCB_LVT },
+ {0x00bdb8, 0x00bdb8, EGCB_LV },
+ {0x00bdb9, 0x00bdd3, EGCB_LVT },
+ {0x00bdd4, 0x00bdd4, EGCB_LV },
+ {0x00bdd5, 0x00bdef, EGCB_LVT },
+ {0x00bdf0, 0x00bdf0, EGCB_LV },
+ {0x00bdf1, 0x00be0b, EGCB_LVT },
+ {0x00be0c, 0x00be0c, EGCB_LV },
+ {0x00be0d, 0x00be27, EGCB_LVT },
+ {0x00be28, 0x00be28, EGCB_LV },
+ {0x00be29, 0x00be43, EGCB_LVT },
+ {0x00be44, 0x00be44, EGCB_LV },
+ {0x00be45, 0x00be5f, EGCB_LVT },
+ {0x00be60, 0x00be60, EGCB_LV },
+ {0x00be61, 0x00be7b, EGCB_LVT },
+ {0x00be7c, 0x00be7c, EGCB_LV },
+ {0x00be7d, 0x00be97, EGCB_LVT },
+ {0x00be98, 0x00be98, EGCB_LV },
+ {0x00be99, 0x00beb3, EGCB_LVT },
+ {0x00beb4, 0x00beb4, EGCB_LV },
+ {0x00beb5, 0x00becf, EGCB_LVT },
+ {0x00bed0, 0x00bed0, EGCB_LV },
+ {0x00bed1, 0x00beeb, EGCB_LVT },
+ {0x00beec, 0x00beec, EGCB_LV },
+ {0x00beed, 0x00bf07, EGCB_LVT },
+ {0x00bf08, 0x00bf08, EGCB_LV },
+ {0x00bf09, 0x00bf23, EGCB_LVT },
+ {0x00bf24, 0x00bf24, EGCB_LV },
+ {0x00bf25, 0x00bf3f, EGCB_LVT },
+ {0x00bf40, 0x00bf40, EGCB_LV },
+ {0x00bf41, 0x00bf5b, EGCB_LVT },
+ {0x00bf5c, 0x00bf5c, EGCB_LV },
+ {0x00bf5d, 0x00bf77, EGCB_LVT },
+ {0x00bf78, 0x00bf78, EGCB_LV },
+ {0x00bf79, 0x00bf93, EGCB_LVT },
+ {0x00bf94, 0x00bf94, EGCB_LV },
+ {0x00bf95, 0x00bfaf, EGCB_LVT },
+ {0x00bfb0, 0x00bfb0, EGCB_LV },
+ {0x00bfb1, 0x00bfcb, EGCB_LVT },
+ {0x00bfcc, 0x00bfcc, EGCB_LV },
+ {0x00bfcd, 0x00bfe7, EGCB_LVT },
+ {0x00bfe8, 0x00bfe8, EGCB_LV },
+ {0x00bfe9, 0x00c003, EGCB_LVT },
+ {0x00c004, 0x00c004, EGCB_LV },
+ {0x00c005, 0x00c01f, EGCB_LVT },
+ {0x00c020, 0x00c020, EGCB_LV },
+ {0x00c021, 0x00c03b, EGCB_LVT },
+ {0x00c03c, 0x00c03c, EGCB_LV },
+ {0x00c03d, 0x00c057, EGCB_LVT },
+ {0x00c058, 0x00c058, EGCB_LV },
+ {0x00c059, 0x00c073, EGCB_LVT },
+ {0x00c074, 0x00c074, EGCB_LV },
+ {0x00c075, 0x00c08f, EGCB_LVT },
+ {0x00c090, 0x00c090, EGCB_LV },
+ {0x00c091, 0x00c0ab, EGCB_LVT },
+ {0x00c0ac, 0x00c0ac, EGCB_LV },
+ {0x00c0ad, 0x00c0c7, EGCB_LVT },
+ {0x00c0c8, 0x00c0c8, EGCB_LV },
+ {0x00c0c9, 0x00c0e3, EGCB_LVT },
+ {0x00c0e4, 0x00c0e4, EGCB_LV },
+ {0x00c0e5, 0x00c0ff, EGCB_LVT },
+ {0x00c100, 0x00c100, EGCB_LV },
+ {0x00c101, 0x00c11b, EGCB_LVT },
+ {0x00c11c, 0x00c11c, EGCB_LV },
+ {0x00c11d, 0x00c137, EGCB_LVT },
+ {0x00c138, 0x00c138, EGCB_LV },
+ {0x00c139, 0x00c153, EGCB_LVT },
+ {0x00c154, 0x00c154, EGCB_LV },
+ {0x00c155, 0x00c16f, EGCB_LVT },
+ {0x00c170, 0x00c170, EGCB_LV },
+ {0x00c171, 0x00c18b, EGCB_LVT },
+ {0x00c18c, 0x00c18c, EGCB_LV },
+ {0x00c18d, 0x00c1a7, EGCB_LVT },
+ {0x00c1a8, 0x00c1a8, EGCB_LV },
+ {0x00c1a9, 0x00c1c3, EGCB_LVT },
+ {0x00c1c4, 0x00c1c4, EGCB_LV },
+ {0x00c1c5, 0x00c1df, EGCB_LVT },
+ {0x00c1e0, 0x00c1e0, EGCB_LV },
+ {0x00c1e1, 0x00c1fb, EGCB_LVT },
+ {0x00c1fc, 0x00c1fc, EGCB_LV },
+ {0x00c1fd, 0x00c217, EGCB_LVT },
+ {0x00c218, 0x00c218, EGCB_LV },
+ {0x00c219, 0x00c233, EGCB_LVT },
+ {0x00c234, 0x00c234, EGCB_LV },
+ {0x00c235, 0x00c24f, EGCB_LVT },
+ {0x00c250, 0x00c250, EGCB_LV },
+ {0x00c251, 0x00c26b, EGCB_LVT },
+ {0x00c26c, 0x00c26c, EGCB_LV },
+ {0x00c26d, 0x00c287, EGCB_LVT },
+ {0x00c288, 0x00c288, EGCB_LV },
+ {0x00c289, 0x00c2a3, EGCB_LVT },
+ {0x00c2a4, 0x00c2a4, EGCB_LV },
+ {0x00c2a5, 0x00c2bf, EGCB_LVT },
+ {0x00c2c0, 0x00c2c0, EGCB_LV },
+ {0x00c2c1, 0x00c2db, EGCB_LVT },
+ {0x00c2dc, 0x00c2dc, EGCB_LV },
+ {0x00c2dd, 0x00c2f7, EGCB_LVT },
+ {0x00c2f8, 0x00c2f8, EGCB_LV },
+ {0x00c2f9, 0x00c313, EGCB_LVT },
+ {0x00c314, 0x00c314, EGCB_LV },
+ {0x00c315, 0x00c32f, EGCB_LVT },
+ {0x00c330, 0x00c330, EGCB_LV },
+ {0x00c331, 0x00c34b, EGCB_LVT },
+ {0x00c34c, 0x00c34c, EGCB_LV },
+ {0x00c34d, 0x00c367, EGCB_LVT },
+ {0x00c368, 0x00c368, EGCB_LV },
+ {0x00c369, 0x00c383, EGCB_LVT },
+ {0x00c384, 0x00c384, EGCB_LV },
+ {0x00c385, 0x00c39f, EGCB_LVT },
+ {0x00c3a0, 0x00c3a0, EGCB_LV },
+ {0x00c3a1, 0x00c3bb, EGCB_LVT },
+ {0x00c3bc, 0x00c3bc, EGCB_LV },
+ {0x00c3bd, 0x00c3d7, EGCB_LVT },
+ {0x00c3d8, 0x00c3d8, EGCB_LV },
+ {0x00c3d9, 0x00c3f3, EGCB_LVT },
+ {0x00c3f4, 0x00c3f4, EGCB_LV },
+ {0x00c3f5, 0x00c40f, EGCB_LVT },
+ {0x00c410, 0x00c410, EGCB_LV },
+ {0x00c411, 0x00c42b, EGCB_LVT },
+ {0x00c42c, 0x00c42c, EGCB_LV },
+ {0x00c42d, 0x00c447, EGCB_LVT },
+ {0x00c448, 0x00c448, EGCB_LV },
+ {0x00c449, 0x00c463, EGCB_LVT },
+ {0x00c464, 0x00c464, EGCB_LV },
+ {0x00c465, 0x00c47f, EGCB_LVT },
+ {0x00c480, 0x00c480, EGCB_LV },
+ {0x00c481, 0x00c49b, EGCB_LVT },
+ {0x00c49c, 0x00c49c, EGCB_LV },
+ {0x00c49d, 0x00c4b7, EGCB_LVT },
+ {0x00c4b8, 0x00c4b8, EGCB_LV },
+ {0x00c4b9, 0x00c4d3, EGCB_LVT },
+ {0x00c4d4, 0x00c4d4, EGCB_LV },
+ {0x00c4d5, 0x00c4ef, EGCB_LVT },
+ {0x00c4f0, 0x00c4f0, EGCB_LV },
+ {0x00c4f1, 0x00c50b, EGCB_LVT },
+ {0x00c50c, 0x00c50c, EGCB_LV },
+ {0x00c50d, 0x00c527, EGCB_LVT },
+ {0x00c528, 0x00c528, EGCB_LV },
+ {0x00c529, 0x00c543, EGCB_LVT },
+ {0x00c544, 0x00c544, EGCB_LV },
+ {0x00c545, 0x00c55f, EGCB_LVT },
+ {0x00c560, 0x00c560, EGCB_LV },
+ {0x00c561, 0x00c57b, EGCB_LVT },
+ {0x00c57c, 0x00c57c, EGCB_LV },
+ {0x00c57d, 0x00c597, EGCB_LVT },
+ {0x00c598, 0x00c598, EGCB_LV },
+ {0x00c599, 0x00c5b3, EGCB_LVT },
+ {0x00c5b4, 0x00c5b4, EGCB_LV },
+ {0x00c5b5, 0x00c5cf, EGCB_LVT },
+ {0x00c5d0, 0x00c5d0, EGCB_LV },
+ {0x00c5d1, 0x00c5eb, EGCB_LVT },
+ {0x00c5ec, 0x00c5ec, EGCB_LV },
+ {0x00c5ed, 0x00c607, EGCB_LVT },
+ {0x00c608, 0x00c608, EGCB_LV },
+ {0x00c609, 0x00c623, EGCB_LVT },
+ {0x00c624, 0x00c624, EGCB_LV },
+ {0x00c625, 0x00c63f, EGCB_LVT },
+ {0x00c640, 0x00c640, EGCB_LV },
+ {0x00c641, 0x00c65b, EGCB_LVT },
+ {0x00c65c, 0x00c65c, EGCB_LV },
+ {0x00c65d, 0x00c677, EGCB_LVT },
+ {0x00c678, 0x00c678, EGCB_LV },
+ {0x00c679, 0x00c693, EGCB_LVT },
+ {0x00c694, 0x00c694, EGCB_LV },
+ {0x00c695, 0x00c6af, EGCB_LVT },
+ {0x00c6b0, 0x00c6b0, EGCB_LV },
+ {0x00c6b1, 0x00c6cb, EGCB_LVT },
+ {0x00c6cc, 0x00c6cc, EGCB_LV },
+ {0x00c6cd, 0x00c6e7, EGCB_LVT },
+ {0x00c6e8, 0x00c6e8, EGCB_LV },
+ {0x00c6e9, 0x00c703, EGCB_LVT },
+ {0x00c704, 0x00c704, EGCB_LV },
+ {0x00c705, 0x00c71f, EGCB_LVT },
+ {0x00c720, 0x00c720, EGCB_LV },
+ {0x00c721, 0x00c73b, EGCB_LVT },
+ {0x00c73c, 0x00c73c, EGCB_LV },
+ {0x00c73d, 0x00c757, EGCB_LVT },
+ {0x00c758, 0x00c758, EGCB_LV },
+ {0x00c759, 0x00c773, EGCB_LVT },
+ {0x00c774, 0x00c774, EGCB_LV },
+ {0x00c775, 0x00c78f, EGCB_LVT },
+ {0x00c790, 0x00c790, EGCB_LV },
+ {0x00c791, 0x00c7ab, EGCB_LVT },
+ {0x00c7ac, 0x00c7ac, EGCB_LV },
+ {0x00c7ad, 0x00c7c7, EGCB_LVT },
+ {0x00c7c8, 0x00c7c8, EGCB_LV },
+ {0x00c7c9, 0x00c7e3, EGCB_LVT },
+ {0x00c7e4, 0x00c7e4, EGCB_LV },
+ {0x00c7e5, 0x00c7ff, EGCB_LVT },
+ {0x00c800, 0x00c800, EGCB_LV },
+ {0x00c801, 0x00c81b, EGCB_LVT },
+ {0x00c81c, 0x00c81c, EGCB_LV },
+ {0x00c81d, 0x00c837, EGCB_LVT },
+ {0x00c838, 0x00c838, EGCB_LV },
+ {0x00c839, 0x00c853, EGCB_LVT },
+ {0x00c854, 0x00c854, EGCB_LV },
+ {0x00c855, 0x00c86f, EGCB_LVT },
+ {0x00c870, 0x00c870, EGCB_LV },
+ {0x00c871, 0x00c88b, EGCB_LVT },
+ {0x00c88c, 0x00c88c, EGCB_LV },
+ {0x00c88d, 0x00c8a7, EGCB_LVT },
+ {0x00c8a8, 0x00c8a8, EGCB_LV },
+ {0x00c8a9, 0x00c8c3, EGCB_LVT },
+ {0x00c8c4, 0x00c8c4, EGCB_LV },
+ {0x00c8c5, 0x00c8df, EGCB_LVT },
+ {0x00c8e0, 0x00c8e0, EGCB_LV },
+ {0x00c8e1, 0x00c8fb, EGCB_LVT },
+ {0x00c8fc, 0x00c8fc, EGCB_LV },
+ {0x00c8fd, 0x00c917, EGCB_LVT },
+ {0x00c918, 0x00c918, EGCB_LV },
+ {0x00c919, 0x00c933, EGCB_LVT },
+ {0x00c934, 0x00c934, EGCB_LV },
+ {0x00c935, 0x00c94f, EGCB_LVT },
+ {0x00c950, 0x00c950, EGCB_LV },
+ {0x00c951, 0x00c96b, EGCB_LVT },
+ {0x00c96c, 0x00c96c, EGCB_LV },
+ {0x00c96d, 0x00c987, EGCB_LVT },
+ {0x00c988, 0x00c988, EGCB_LV },
+ {0x00c989, 0x00c9a3, EGCB_LVT },
+ {0x00c9a4, 0x00c9a4, EGCB_LV },
+ {0x00c9a5, 0x00c9bf, EGCB_LVT },
+ {0x00c9c0, 0x00c9c0, EGCB_LV },
+ {0x00c9c1, 0x00c9db, EGCB_LVT },
+ {0x00c9dc, 0x00c9dc, EGCB_LV },
+ {0x00c9dd, 0x00c9f7, EGCB_LVT },
+ {0x00c9f8, 0x00c9f8, EGCB_LV },
+ {0x00c9f9, 0x00ca13, EGCB_LVT },
+ {0x00ca14, 0x00ca14, EGCB_LV },
+ {0x00ca15, 0x00ca2f, EGCB_LVT },
+ {0x00ca30, 0x00ca30, EGCB_LV },
+ {0x00ca31, 0x00ca4b, EGCB_LVT },
+ {0x00ca4c, 0x00ca4c, EGCB_LV },
+ {0x00ca4d, 0x00ca67, EGCB_LVT },
+ {0x00ca68, 0x00ca68, EGCB_LV },
+ {0x00ca69, 0x00ca83, EGCB_LVT },
+ {0x00ca84, 0x00ca84, EGCB_LV },
+ {0x00ca85, 0x00ca9f, EGCB_LVT },
+ {0x00caa0, 0x00caa0, EGCB_LV },
+ {0x00caa1, 0x00cabb, EGCB_LVT },
+ {0x00cabc, 0x00cabc, EGCB_LV },
+ {0x00cabd, 0x00cad7, EGCB_LVT },
+ {0x00cad8, 0x00cad8, EGCB_LV },
+ {0x00cad9, 0x00caf3, EGCB_LVT },
+ {0x00caf4, 0x00caf4, EGCB_LV },
+ {0x00caf5, 0x00cb0f, EGCB_LVT },
+ {0x00cb10, 0x00cb10, EGCB_LV },
+ {0x00cb11, 0x00cb2b, EGCB_LVT },
+ {0x00cb2c, 0x00cb2c, EGCB_LV },
+ {0x00cb2d, 0x00cb47, EGCB_LVT },
+ {0x00cb48, 0x00cb48, EGCB_LV },
+ {0x00cb49, 0x00cb63, EGCB_LVT },
+ {0x00cb64, 0x00cb64, EGCB_LV },
+ {0x00cb65, 0x00cb7f, EGCB_LVT },
+ {0x00cb80, 0x00cb80, EGCB_LV },
+ {0x00cb81, 0x00cb9b, EGCB_LVT },
+ {0x00cb9c, 0x00cb9c, EGCB_LV },
+ {0x00cb9d, 0x00cbb7, EGCB_LVT },
+ {0x00cbb8, 0x00cbb8, EGCB_LV },
+ {0x00cbb9, 0x00cbd3, EGCB_LVT },
+ {0x00cbd4, 0x00cbd4, EGCB_LV },
+ {0x00cbd5, 0x00cbef, EGCB_LVT },
+ {0x00cbf0, 0x00cbf0, EGCB_LV },
+ {0x00cbf1, 0x00cc0b, EGCB_LVT },
+ {0x00cc0c, 0x00cc0c, EGCB_LV },
+ {0x00cc0d, 0x00cc27, EGCB_LVT },
+ {0x00cc28, 0x00cc28, EGCB_LV },
+ {0x00cc29, 0x00cc43, EGCB_LVT },
+ {0x00cc44, 0x00cc44, EGCB_LV },
+ {0x00cc45, 0x00cc5f, EGCB_LVT },
+ {0x00cc60, 0x00cc60, EGCB_LV },
+ {0x00cc61, 0x00cc7b, EGCB_LVT },
+ {0x00cc7c, 0x00cc7c, EGCB_LV },
+ {0x00cc7d, 0x00cc97, EGCB_LVT },
+ {0x00cc98, 0x00cc98, EGCB_LV },
+ {0x00cc99, 0x00ccb3, EGCB_LVT },
+ {0x00ccb4, 0x00ccb4, EGCB_LV },
+ {0x00ccb5, 0x00cccf, EGCB_LVT },
+ {0x00ccd0, 0x00ccd0, EGCB_LV },
+ {0x00ccd1, 0x00cceb, EGCB_LVT },
+ {0x00ccec, 0x00ccec, EGCB_LV },
+ {0x00cced, 0x00cd07, EGCB_LVT },
+ {0x00cd08, 0x00cd08, EGCB_LV },
+ {0x00cd09, 0x00cd23, EGCB_LVT },
+ {0x00cd24, 0x00cd24, EGCB_LV },
+ {0x00cd25, 0x00cd3f, EGCB_LVT },
+ {0x00cd40, 0x00cd40, EGCB_LV },
+ {0x00cd41, 0x00cd5b, EGCB_LVT },
+ {0x00cd5c, 0x00cd5c, EGCB_LV },
+ {0x00cd5d, 0x00cd77, EGCB_LVT },
+ {0x00cd78, 0x00cd78, EGCB_LV },
+ {0x00cd79, 0x00cd93, EGCB_LVT },
+ {0x00cd94, 0x00cd94, EGCB_LV },
+ {0x00cd95, 0x00cdaf, EGCB_LVT },
+ {0x00cdb0, 0x00cdb0, EGCB_LV },
+ {0x00cdb1, 0x00cdcb, EGCB_LVT },
+ {0x00cdcc, 0x00cdcc, EGCB_LV },
+ {0x00cdcd, 0x00cde7, EGCB_LVT },
+ {0x00cde8, 0x00cde8, EGCB_LV },
+ {0x00cde9, 0x00ce03, EGCB_LVT },
+ {0x00ce04, 0x00ce04, EGCB_LV },
+ {0x00ce05, 0x00ce1f, EGCB_LVT },
+ {0x00ce20, 0x00ce20, EGCB_LV },
+ {0x00ce21, 0x00ce3b, EGCB_LVT },
+ {0x00ce3c, 0x00ce3c, EGCB_LV },
+ {0x00ce3d, 0x00ce57, EGCB_LVT },
+ {0x00ce58, 0x00ce58, EGCB_LV },
+ {0x00ce59, 0x00ce73, EGCB_LVT },
+ {0x00ce74, 0x00ce74, EGCB_LV },
+ {0x00ce75, 0x00ce8f, EGCB_LVT },
+ {0x00ce90, 0x00ce90, EGCB_LV },
+ {0x00ce91, 0x00ceab, EGCB_LVT },
+ {0x00ceac, 0x00ceac, EGCB_LV },
+ {0x00cead, 0x00cec7, EGCB_LVT },
+ {0x00cec8, 0x00cec8, EGCB_LV },
+ {0x00cec9, 0x00cee3, EGCB_LVT },
+ {0x00cee4, 0x00cee4, EGCB_LV },
+ {0x00cee5, 0x00ceff, EGCB_LVT },
+ {0x00cf00, 0x00cf00, EGCB_LV },
+ {0x00cf01, 0x00cf1b, EGCB_LVT },
+ {0x00cf1c, 0x00cf1c, EGCB_LV },
+ {0x00cf1d, 0x00cf37, EGCB_LVT },
+ {0x00cf38, 0x00cf38, EGCB_LV },
+ {0x00cf39, 0x00cf53, EGCB_LVT },
+ {0x00cf54, 0x00cf54, EGCB_LV },
+ {0x00cf55, 0x00cf6f, EGCB_LVT },
+ {0x00cf70, 0x00cf70, EGCB_LV },
+ {0x00cf71, 0x00cf8b, EGCB_LVT },
+ {0x00cf8c, 0x00cf8c, EGCB_LV },
+ {0x00cf8d, 0x00cfa7, EGCB_LVT },
+ {0x00cfa8, 0x00cfa8, EGCB_LV },
+ {0x00cfa9, 0x00cfc3, EGCB_LVT },
+ {0x00cfc4, 0x00cfc4, EGCB_LV },
+ {0x00cfc5, 0x00cfdf, EGCB_LVT },
+ {0x00cfe0, 0x00cfe0, EGCB_LV },
+ {0x00cfe1, 0x00cffb, EGCB_LVT },
+ {0x00cffc, 0x00cffc, EGCB_LV },
+ {0x00cffd, 0x00d017, EGCB_LVT },
+ {0x00d018, 0x00d018, EGCB_LV },
+ {0x00d019, 0x00d033, EGCB_LVT },
+ {0x00d034, 0x00d034, EGCB_LV },
+ {0x00d035, 0x00d04f, EGCB_LVT },
+ {0x00d050, 0x00d050, EGCB_LV },
+ {0x00d051, 0x00d06b, EGCB_LVT },
+ {0x00d06c, 0x00d06c, EGCB_LV },
+ {0x00d06d, 0x00d087, EGCB_LVT },
+ {0x00d088, 0x00d088, EGCB_LV },
+ {0x00d089, 0x00d0a3, EGCB_LVT },
+ {0x00d0a4, 0x00d0a4, EGCB_LV },
+ {0x00d0a5, 0x00d0bf, EGCB_LVT },
+ {0x00d0c0, 0x00d0c0, EGCB_LV },
+ {0x00d0c1, 0x00d0db, EGCB_LVT },
+ {0x00d0dc, 0x00d0dc, EGCB_LV },
+ {0x00d0dd, 0x00d0f7, EGCB_LVT },
+ {0x00d0f8, 0x00d0f8, EGCB_LV },
+ {0x00d0f9, 0x00d113, EGCB_LVT },
+ {0x00d114, 0x00d114, EGCB_LV },
+ {0x00d115, 0x00d12f, EGCB_LVT },
+ {0x00d130, 0x00d130, EGCB_LV },
+ {0x00d131, 0x00d14b, EGCB_LVT },
+ {0x00d14c, 0x00d14c, EGCB_LV },
+ {0x00d14d, 0x00d167, EGCB_LVT },
+ {0x00d168, 0x00d168, EGCB_LV },
+ {0x00d169, 0x00d183, EGCB_LVT },
+ {0x00d184, 0x00d184, EGCB_LV },
+ {0x00d185, 0x00d19f, EGCB_LVT },
+ {0x00d1a0, 0x00d1a0, EGCB_LV },
+ {0x00d1a1, 0x00d1bb, EGCB_LVT },
+ {0x00d1bc, 0x00d1bc, EGCB_LV },
+ {0x00d1bd, 0x00d1d7, EGCB_LVT },
+ {0x00d1d8, 0x00d1d8, EGCB_LV },
+ {0x00d1d9, 0x00d1f3, EGCB_LVT },
+ {0x00d1f4, 0x00d1f4, EGCB_LV },
+ {0x00d1f5, 0x00d20f, EGCB_LVT },
+ {0x00d210, 0x00d210, EGCB_LV },
+ {0x00d211, 0x00d22b, EGCB_LVT },
+ {0x00d22c, 0x00d22c, EGCB_LV },
+ {0x00d22d, 0x00d247, EGCB_LVT },
+ {0x00d248, 0x00d248, EGCB_LV },
+ {0x00d249, 0x00d263, EGCB_LVT },
+ {0x00d264, 0x00d264, EGCB_LV },
+ {0x00d265, 0x00d27f, EGCB_LVT },
+ {0x00d280, 0x00d280, EGCB_LV },
+ {0x00d281, 0x00d29b, EGCB_LVT },
+ {0x00d29c, 0x00d29c, EGCB_LV },
+ {0x00d29d, 0x00d2b7, EGCB_LVT },
+ {0x00d2b8, 0x00d2b8, EGCB_LV },
+ {0x00d2b9, 0x00d2d3, EGCB_LVT },
+ {0x00d2d4, 0x00d2d4, EGCB_LV },
+ {0x00d2d5, 0x00d2ef, EGCB_LVT },
+ {0x00d2f0, 0x00d2f0, EGCB_LV },
+ {0x00d2f1, 0x00d30b, EGCB_LVT },
+ {0x00d30c, 0x00d30c, EGCB_LV },
+ {0x00d30d, 0x00d327, EGCB_LVT },
+ {0x00d328, 0x00d328, EGCB_LV },
+ {0x00d329, 0x00d343, EGCB_LVT },
+ {0x00d344, 0x00d344, EGCB_LV },
+ {0x00d345, 0x00d35f, EGCB_LVT },
+ {0x00d360, 0x00d360, EGCB_LV },
+ {0x00d361, 0x00d37b, EGCB_LVT },
+ {0x00d37c, 0x00d37c, EGCB_LV },
+ {0x00d37d, 0x00d397, EGCB_LVT },
+ {0x00d398, 0x00d398, EGCB_LV },
+ {0x00d399, 0x00d3b3, EGCB_LVT },
+ {0x00d3b4, 0x00d3b4, EGCB_LV },
+ {0x00d3b5, 0x00d3cf, EGCB_LVT },
+ {0x00d3d0, 0x00d3d0, EGCB_LV },
+ {0x00d3d1, 0x00d3eb, EGCB_LVT },
+ {0x00d3ec, 0x00d3ec, EGCB_LV },
+ {0x00d3ed, 0x00d407, EGCB_LVT },
+ {0x00d408, 0x00d408, EGCB_LV },
+ {0x00d409, 0x00d423, EGCB_LVT },
+ {0x00d424, 0x00d424, EGCB_LV },
+ {0x00d425, 0x00d43f, EGCB_LVT },
+ {0x00d440, 0x00d440, EGCB_LV },
+ {0x00d441, 0x00d45b, EGCB_LVT },
+ {0x00d45c, 0x00d45c, EGCB_LV },
+ {0x00d45d, 0x00d477, EGCB_LVT },
+ {0x00d478, 0x00d478, EGCB_LV },
+ {0x00d479, 0x00d493, EGCB_LVT },
+ {0x00d494, 0x00d494, EGCB_LV },
+ {0x00d495, 0x00d4af, EGCB_LVT },
+ {0x00d4b0, 0x00d4b0, EGCB_LV },
+ {0x00d4b1, 0x00d4cb, EGCB_LVT },
+ {0x00d4cc, 0x00d4cc, EGCB_LV },
+ {0x00d4cd, 0x00d4e7, EGCB_LVT },
+ {0x00d4e8, 0x00d4e8, EGCB_LV },
+ {0x00d4e9, 0x00d503, EGCB_LVT },
+ {0x00d504, 0x00d504, EGCB_LV },
+ {0x00d505, 0x00d51f, EGCB_LVT },
+ {0x00d520, 0x00d520, EGCB_LV },
+ {0x00d521, 0x00d53b, EGCB_LVT },
+ {0x00d53c, 0x00d53c, EGCB_LV },
+ {0x00d53d, 0x00d557, EGCB_LVT },
+ {0x00d558, 0x00d558, EGCB_LV },
+ {0x00d559, 0x00d573, EGCB_LVT },
+ {0x00d574, 0x00d574, EGCB_LV },
+ {0x00d575, 0x00d58f, EGCB_LVT },
+ {0x00d590, 0x00d590, EGCB_LV },
+ {0x00d591, 0x00d5ab, EGCB_LVT },
+ {0x00d5ac, 0x00d5ac, EGCB_LV },
+ {0x00d5ad, 0x00d5c7, EGCB_LVT },
+ {0x00d5c8, 0x00d5c8, EGCB_LV },
+ {0x00d5c9, 0x00d5e3, EGCB_LVT },
+ {0x00d5e4, 0x00d5e4, EGCB_LV },
+ {0x00d5e5, 0x00d5ff, EGCB_LVT },
+ {0x00d600, 0x00d600, EGCB_LV },
+ {0x00d601, 0x00d61b, EGCB_LVT },
+ {0x00d61c, 0x00d61c, EGCB_LV },
+ {0x00d61d, 0x00d637, EGCB_LVT },
+ {0x00d638, 0x00d638, EGCB_LV },
+ {0x00d639, 0x00d653, EGCB_LVT },
+ {0x00d654, 0x00d654, EGCB_LV },
+ {0x00d655, 0x00d66f, EGCB_LVT },
+ {0x00d670, 0x00d670, EGCB_LV },
+ {0x00d671, 0x00d68b, EGCB_LVT },
+ {0x00d68c, 0x00d68c, EGCB_LV },
+ {0x00d68d, 0x00d6a7, EGCB_LVT },
+ {0x00d6a8, 0x00d6a8, EGCB_LV },
+ {0x00d6a9, 0x00d6c3, EGCB_LVT },
+ {0x00d6c4, 0x00d6c4, EGCB_LV },
+ {0x00d6c5, 0x00d6df, EGCB_LVT },
+ {0x00d6e0, 0x00d6e0, EGCB_LV },
+ {0x00d6e1, 0x00d6fb, EGCB_LVT },
+ {0x00d6fc, 0x00d6fc, EGCB_LV },
+ {0x00d6fd, 0x00d717, EGCB_LVT },
+ {0x00d718, 0x00d718, EGCB_LV },
+ {0x00d719, 0x00d733, EGCB_LVT },
+ {0x00d734, 0x00d734, EGCB_LV },
+ {0x00d735, 0x00d74f, EGCB_LVT },
+ {0x00d750, 0x00d750, EGCB_LV },
+ {0x00d751, 0x00d76b, EGCB_LVT },
+ {0x00d76c, 0x00d76c, EGCB_LV },
+ {0x00d76d, 0x00d787, EGCB_LVT },
+ {0x00d788, 0x00d788, EGCB_LV },
+ {0x00d789, 0x00d7a3, EGCB_LVT },
+ {0x00d7b0, 0x00d7c6, EGCB_V },
+ {0x00d7cb, 0x00d7fb, EGCB_T },
+ {0x00fb1e, 0x00fb1e, EGCB_Extend },
+ {0x00fe00, 0x00fe0f, EGCB_Extend },
+ {0x00fe20, 0x00fe2f, EGCB_Extend },
+ {0x00feff, 0x00feff, EGCB_Control },
+ {0x00ff9e, 0x00ff9f, EGCB_Extend },
+ {0x00fff0, 0x00fffb, EGCB_Control },
+ {0x0101fd, 0x0101fd, EGCB_Extend },
+ {0x0102e0, 0x0102e0, EGCB_Extend },
+ {0x010376, 0x01037a, EGCB_Extend },
+ {0x010a01, 0x010a03, EGCB_Extend },
+ {0x010a05, 0x010a06, EGCB_Extend },
+ {0x010a0c, 0x010a0f, EGCB_Extend },
+ {0x010a38, 0x010a3a, EGCB_Extend },
+ {0x010a3f, 0x010a3f, EGCB_Extend },
+ {0x010ae5, 0x010ae6, EGCB_Extend },
+ {0x010d24, 0x010d27, EGCB_Extend },
+ {0x010f46, 0x010f50, EGCB_Extend },
+ {0x011000, 0x011000, EGCB_SpacingMark },
+ {0x011001, 0x011001, EGCB_Extend },
+ {0x011002, 0x011002, EGCB_SpacingMark },
+ {0x011038, 0x011046, EGCB_Extend },
+ {0x01107f, 0x011081, EGCB_Extend },
+ {0x011082, 0x011082, EGCB_SpacingMark },
+ {0x0110b0, 0x0110b2, EGCB_SpacingMark },
+ {0x0110b3, 0x0110b6, EGCB_Extend },
+ {0x0110b7, 0x0110b8, EGCB_SpacingMark },
+ {0x0110b9, 0x0110ba, EGCB_Extend },
+ {0x0110bd, 0x0110bd, EGCB_Prepend },
+ {0x0110cd, 0x0110cd, EGCB_Prepend },
+ {0x011100, 0x011102, EGCB_Extend },
+ {0x011127, 0x01112b, EGCB_Extend },
+ {0x01112c, 0x01112c, EGCB_SpacingMark },
+ {0x01112d, 0x011134, EGCB_Extend },
+ {0x011145, 0x011146, EGCB_SpacingMark },
+ {0x011173, 0x011173, EGCB_Extend },
+ {0x011180, 0x011181, EGCB_Extend },
+ {0x011182, 0x011182, EGCB_SpacingMark },
+ {0x0111b3, 0x0111b5, EGCB_SpacingMark },
+ {0x0111b6, 0x0111be, EGCB_Extend },
+ {0x0111bf, 0x0111c0, EGCB_SpacingMark },
+ {0x0111c2, 0x0111c3, EGCB_Prepend },
+ {0x0111c9, 0x0111cc, EGCB_Extend },
+ {0x01122c, 0x01122e, EGCB_SpacingMark },
+ {0x01122f, 0x011231, EGCB_Extend },
+ {0x011232, 0x011233, EGCB_SpacingMark },
+ {0x011234, 0x011234, EGCB_Extend },
+ {0x011235, 0x011235, EGCB_SpacingMark },
+ {0x011236, 0x011237, EGCB_Extend },
+ {0x01123e, 0x01123e, EGCB_Extend },
+ {0x0112df, 0x0112df, EGCB_Extend },
+ {0x0112e0, 0x0112e2, EGCB_SpacingMark },
+ {0x0112e3, 0x0112ea, EGCB_Extend },
+ {0x011300, 0x011301, EGCB_Extend },
+ {0x011302, 0x011303, EGCB_SpacingMark },
+ {0x01133b, 0x01133c, EGCB_Extend },
+ {0x01133e, 0x01133e, EGCB_Extend },
+ {0x01133f, 0x01133f, EGCB_SpacingMark },
+ {0x011340, 0x011340, EGCB_Extend },
+ {0x011341, 0x011344, EGCB_SpacingMark },
+ {0x011347, 0x011348, EGCB_SpacingMark },
+ {0x01134b, 0x01134d, EGCB_SpacingMark },
+ {0x011357, 0x011357, EGCB_Extend },
+ {0x011362, 0x011363, EGCB_SpacingMark },
+ {0x011366, 0x01136c, EGCB_Extend },
+ {0x011370, 0x011374, EGCB_Extend },
+ {0x011435, 0x011437, EGCB_SpacingMark },
+ {0x011438, 0x01143f, EGCB_Extend },
+ {0x011440, 0x011441, EGCB_SpacingMark },
+ {0x011442, 0x011444, EGCB_Extend },
+ {0x011445, 0x011445, EGCB_SpacingMark },
+ {0x011446, 0x011446, EGCB_Extend },
+ {0x01145e, 0x01145e, EGCB_Extend },
+ {0x0114b0, 0x0114b0, EGCB_Extend },
+ {0x0114b1, 0x0114b2, EGCB_SpacingMark },
+ {0x0114b3, 0x0114b8, EGCB_Extend },
+ {0x0114b9, 0x0114b9, EGCB_SpacingMark },
+ {0x0114ba, 0x0114ba, EGCB_Extend },
+ {0x0114bb, 0x0114bc, EGCB_SpacingMark },
+ {0x0114bd, 0x0114bd, EGCB_Extend },
+ {0x0114be, 0x0114be, EGCB_SpacingMark },
+ {0x0114bf, 0x0114c0, EGCB_Extend },
+ {0x0114c1, 0x0114c1, EGCB_SpacingMark },
+ {0x0114c2, 0x0114c3, EGCB_Extend },
+ {0x0115af, 0x0115af, EGCB_Extend },
+ {0x0115b0, 0x0115b1, EGCB_SpacingMark },
+ {0x0115b2, 0x0115b5, EGCB_Extend },
+ {0x0115b8, 0x0115bb, EGCB_SpacingMark },
+ {0x0115bc, 0x0115bd, EGCB_Extend },
+ {0x0115be, 0x0115be, EGCB_SpacingMark },
+ {0x0115bf, 0x0115c0, EGCB_Extend },
+ {0x0115dc, 0x0115dd, EGCB_Extend },
+ {0x011630, 0x011632, EGCB_SpacingMark },
+ {0x011633, 0x01163a, EGCB_Extend },
+ {0x01163b, 0x01163c, EGCB_SpacingMark },
+ {0x01163d, 0x01163d, EGCB_Extend },
+ {0x01163e, 0x01163e, EGCB_SpacingMark },
+ {0x01163f, 0x011640, EGCB_Extend },
+ {0x0116ab, 0x0116ab, EGCB_Extend },
+ {0x0116ac, 0x0116ac, EGCB_SpacingMark },
+ {0x0116ad, 0x0116ad, EGCB_Extend },
+ {0x0116ae, 0x0116af, EGCB_SpacingMark },
+ {0x0116b0, 0x0116b5, EGCB_Extend },
+ {0x0116b6, 0x0116b6, EGCB_SpacingMark },
+ {0x0116b7, 0x0116b7, EGCB_Extend },
+ {0x01171d, 0x01171f, EGCB_Extend },
+ {0x011720, 0x011721, EGCB_SpacingMark },
+ {0x011722, 0x011725, EGCB_Extend },
+ {0x011726, 0x011726, EGCB_SpacingMark },
+ {0x011727, 0x01172b, EGCB_Extend },
+ {0x01182c, 0x01182e, EGCB_SpacingMark },
+ {0x01182f, 0x011837, EGCB_Extend },
+ {0x011838, 0x011838, EGCB_SpacingMark },
+ {0x011839, 0x01183a, EGCB_Extend },
+ {0x0119d1, 0x0119d3, EGCB_SpacingMark },
+ {0x0119d4, 0x0119d7, EGCB_Extend },
+ {0x0119da, 0x0119db, EGCB_Extend },
+ {0x0119dc, 0x0119df, EGCB_SpacingMark },
+ {0x0119e0, 0x0119e0, EGCB_Extend },
+ {0x0119e4, 0x0119e4, EGCB_SpacingMark },
+ {0x011a01, 0x011a0a, EGCB_Extend },
+ {0x011a33, 0x011a38, EGCB_Extend },
+ {0x011a39, 0x011a39, EGCB_SpacingMark },
+ {0x011a3a, 0x011a3a, EGCB_Prepend },
+ {0x011a3b, 0x011a3e, EGCB_Extend },
+ {0x011a47, 0x011a47, EGCB_Extend },
+ {0x011a51, 0x011a56, EGCB_Extend },
+ {0x011a57, 0x011a58, EGCB_SpacingMark },
+ {0x011a59, 0x011a5b, EGCB_Extend },
+ {0x011a84, 0x011a89, EGCB_Prepend },
+ {0x011a8a, 0x011a96, EGCB_Extend },
+ {0x011a97, 0x011a97, EGCB_SpacingMark },
+ {0x011a98, 0x011a99, EGCB_Extend },
+ {0x011c2f, 0x011c2f, EGCB_SpacingMark },
+ {0x011c30, 0x011c36, EGCB_Extend },
+ {0x011c38, 0x011c3d, EGCB_Extend },
+ {0x011c3e, 0x011c3e, EGCB_SpacingMark },
+ {0x011c3f, 0x011c3f, EGCB_Extend },
+ {0x011c92, 0x011ca7, EGCB_Extend },
+ {0x011ca9, 0x011ca9, EGCB_SpacingMark },
+ {0x011caa, 0x011cb0, EGCB_Extend },
+ {0x011cb1, 0x011cb1, EGCB_SpacingMark },
+ {0x011cb2, 0x011cb3, EGCB_Extend },
+ {0x011cb4, 0x011cb4, EGCB_SpacingMark },
+ {0x011cb5, 0x011cb6, EGCB_Extend },
+ {0x011d31, 0x011d36, EGCB_Extend },
+ {0x011d3a, 0x011d3a, EGCB_Extend },
+ {0x011d3c, 0x011d3d, EGCB_Extend },
+ {0x011d3f, 0x011d45, EGCB_Extend },
+ {0x011d46, 0x011d46, EGCB_Prepend },
+ {0x011d47, 0x011d47, EGCB_Extend },
+ {0x011d8a, 0x011d8e, EGCB_SpacingMark },
+ {0x011d90, 0x011d91, EGCB_Extend },
+ {0x011d93, 0x011d94, EGCB_SpacingMark },
+ {0x011d95, 0x011d95, EGCB_Extend },
+ {0x011d96, 0x011d96, EGCB_SpacingMark },
+ {0x011d97, 0x011d97, EGCB_Extend },
+ {0x011ef3, 0x011ef4, EGCB_Extend },
+ {0x011ef5, 0x011ef6, EGCB_SpacingMark },
+ {0x013430, 0x013438, EGCB_Control },
+ {0x016af0, 0x016af4, EGCB_Extend },
+ {0x016b30, 0x016b36, EGCB_Extend },
+ {0x016f4f, 0x016f4f, EGCB_Extend },
+ {0x016f51, 0x016f87, EGCB_SpacingMark },
+ {0x016f8f, 0x016f92, EGCB_Extend },
+ {0x01bc9d, 0x01bc9e, EGCB_Extend },
+ {0x01bca0, 0x01bca3, EGCB_Control },
+ {0x01d165, 0x01d165, EGCB_Extend },
+ {0x01d166, 0x01d166, EGCB_SpacingMark },
+ {0x01d167, 0x01d169, EGCB_Extend },
+ {0x01d16d, 0x01d16d, EGCB_SpacingMark },
+ {0x01d16e, 0x01d172, EGCB_Extend },
+ {0x01d173, 0x01d17a, EGCB_Control },
+ {0x01d17b, 0x01d182, EGCB_Extend },
+ {0x01d185, 0x01d18b, EGCB_Extend },
+ {0x01d1aa, 0x01d1ad, EGCB_Extend },
+ {0x01d242, 0x01d244, EGCB_Extend },
+ {0x01da00, 0x01da36, EGCB_Extend },
+ {0x01da3b, 0x01da6c, EGCB_Extend },
+ {0x01da75, 0x01da75, EGCB_Extend },
+ {0x01da84, 0x01da84, EGCB_Extend },
+ {0x01da9b, 0x01da9f, EGCB_Extend },
+ {0x01daa1, 0x01daaf, EGCB_Extend },
+ {0x01e000, 0x01e006, EGCB_Extend },
+ {0x01e008, 0x01e018, EGCB_Extend },
+ {0x01e01b, 0x01e021, EGCB_Extend },
+ {0x01e023, 0x01e024, EGCB_Extend },
+ {0x01e026, 0x01e02a, EGCB_Extend },
+ {0x01e130, 0x01e136, EGCB_Extend },
+ {0x01e2ec, 0x01e2ef, EGCB_Extend },
+ {0x01e8d0, 0x01e8d6, EGCB_Extend },
+ {0x01e944, 0x01e94a, EGCB_Extend },
+ {0x01f1e6, 0x01f1ff, EGCB_Regional_Indicator },
+ {0x01f3fb, 0x01f3ff, EGCB_Extend },
+ {0x0e0000, 0x0e001f, EGCB_Control },
+ {0x0e0020, 0x0e007f, EGCB_Extend },
+ {0x0e0080, 0x0e00ff, EGCB_Control },
+ {0x0e0100, 0x0e01ef, EGCB_Extend },
+ {0x0e01f0, 0x0e0fff, EGCB_Control }
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold1_key.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold1_key.c
new file mode 100644
index 000000000..2089a883f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold1_key.c
@@ -0,0 +1,2998 @@
+/* This file was converted by gperf_fold_key_conv.py
+ from gperf output file. */
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -n -C -T -c -t -j1 -L ANSI-C -F,-1 -N onigenc_unicode_fold1_key unicode_fold1_key.gperf */
+/* Computed positions: -k'1-3' */
+
+
+
+/* This gperf source file was generated by make_unicode_fold_data.py */
+
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 1353
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 3
+#define MIN_HASH_VALUE 3
+#define MAX_HASH_VALUE 1791
+/* maximum key range = 1789, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+hash(OnigCodePoint codes[])
+{
+ static const unsigned short asso_values[] =
+ {
+ 4, 2, 147, 16, 1, 13, 1228, 725, 1224, 638,
+ 1204, 95, 9, 82, 1403, 80, 8, 68, 1391, 6,
+ 1203, 602, 1200, 320, 151, 67, 1385, 61, 1384, 158,
+ 0, 11, 1252, 3, 733, 278, 23, 425, 660, 424,
+ 640, 20, 635, 105, 5, 29, 916, 34, 630, 0,
+ 906, 1378, 899, 1377, 470, 1363, 623, 902, 610, 230,
+ 1193, 1358, 1190, 779, 986, 1336, 890, 883, 456, 597,
+ 285, 158, 590, 477, 583, 42, 576, 1447, 447, 1440,
+ 440, 1353, 426, 1429, 400, 1417, 327, 1407, 567, 1389,
+ 386, 1207, 458, 724, 854, 979, 1016, 66, 232, 413,
+ 204, 1431, 226, 1317, 190, 1167, 379, 1319, 198, 1270,
+ 175, 209, 561, 362, 528, 1323, 257, 1099, 240, 1309,
+ 508, 1172, 484, 1306, 699, 865, 850, 488, 679, 755,
+ 420, 639, 1149, 105, 691, 789, 1125, 46, 809, 652,
+ 1293, 3, 1262, 166, 1426, 0, 1424, 1792, 1220, 460,
+ 706, 1, 367, 1792, 1341, 1792, 1151, 56, 1235, 1792,
+ 384, 345, 965, 40, 1168, 33, 218, 180, 1159, 20,
+ 1296, 276, 1243, 14, 1401, 777, 1142, 682, 1284, 129,
+ 1135, 610, 1181, 871, 1123, 858, 1042, 510, 842, 499,
+ 999, 346, 830, 0, 823, 1288, 1115, 768, 732, 1272,
+ 1101, 1098, 1082, 1270, 811, 177, 1078, 1074, 1061, 1058,
+ 1050, 789, 353, 1018, 548, 1006, 517, 988, 334, 765,
+ 166, 753, 138, 743, 100, 969, 87, 720, 49, 975,
+ 75, 965, 62, 411, 126, 955, 113, 1262, 317, 943,
+ 304, 679, 293, 1252, 714, 937, 275, 490, 263, 469,
+ 395, 1345, 931, 208, 921, 80, 542, 11, 246
+ };
+ return asso_values[(unsigned char)onig_codes_byte_at(codes, 2)+3] + asso_values[(unsigned char)onig_codes_byte_at(codes, 1)] + asso_values[(unsigned char)onig_codes_byte_at(codes, 0)];
+}
+
+int
+onigenc_unicode_fold1_key(OnigCodePoint codes[])
+{
+ static const short int wordlist[] =
+ {
+ -1, -1, -1,
+
+ 3429,
+
+ 1906,
+
+ 1867,
+
+ 210,
+
+ 171,
+
+ 3414,
+
+ 1927,
+
+ 1690,
+
+ 231,
+
+ 1885,
+
+ 1879,
+
+ 189,
+
+ 183,
+
+ 2240,
+
+ 1315,
+
+ 1276,
+
+ 165,
+
+ 792,
+
+ 2261,
+
+ 1336,
+
+ 1594,
+
+ 1630,
+
+ 1294,
+
+ 1288,
+
+ 1915,
+
+ 2243,
+
+ 219,
+
+ 1618,
+
+ 2237,
+
+ 3417,
+
+ 2981,
+
+ 2903,
+
+ 2297,
+
+ 2990,
+
+ 3423,
+
+ 2282,
+
+ 2948,
+
+ 1324,
+
+ 2939,
+
+ 2927,
+
+ 1606,
+
+ 2984,
+
+ 3507,
+
+ 2906,
+
+ 974,
+
+ 273,
+
+ 2900,
+
+ 1600,
+
+ 2648,
+
+ 3558,
+
+ 2189,
+
+ 1228,
+
+ 459,
+
+ 2999,
+
+ 80,
+
+ 2885,
+
+ 1795,
+
+ 3738,
+
+ 1513,
+
+ 378,
+
+ 1459,
+
+ 2438,
+
+ 3570,
+
+ 2195,
+
+ 1234,
+
+ 465,
+
+ 860,
+
+ 92,
+
+ 1041,
+
+ 1807,
+
+ 3750,
+
+ 1525,
+
+ 2714,
+
+ 2549,
+
+ 2441,
+
+ 3564,
+
+ 2192,
+
+ 1231,
+
+ 462,
+
+ 866,
+
+ 86,
+
+ 2888,
+
+ 1801,
+
+ 3744,
+
+ 1519,
+
+ 159,
+
+ 2561,
+
+ 3552,
+
+ 2186,
+
+ 1225,
+
+ 456,
+
+ 2972,
+
+ 863,
+
+ 2882,
+
+ 1789,
+
+ 3732,
+
+ 1507,
+
+ 2966,
+
+ 2942,
+
+ 2555,
+
+ 3546,
+
+ 2183,
+
+ 1222,
+
+ 453,
+
+ 857,
+
+ 3411,
+
+ 2879,
+
+ 1783,
+
+ 3726,
+
+ 1501,
+
+ 2936,
+
+ 2543,
+
+ 2930,
+
+ 3582,
+
+ 2201,
+
+ 1240,
+
+ 471,
+
+ 854,
+
+ 105,
+
+ 1447,
+
+ 1819,
+
+ 3762,
+
+ 1537,
+
+ 3354,
+
+ 2537,
+
+ 2924,
+
+ 3576,
+
+ 2198,
+
+ 1237,
+
+ 468,
+
+ 872,
+
+ 99,
+
+ 399,
+
+ 1813,
+
+ 3756,
+
+ 1531,
+
+ 1648,
+
+ 2573,
+
+ 3540,
+
+ 2180,
+
+ 1219,
+
+ 2423,
+ -1,
+
+ 869,
+
+ 2876,
+
+ 1777,
+
+ 3720,
+
+ 1495,
+
+ 541,
+
+ 502,
+
+ 2567,
+
+ 697,
+
+ 1897,
+
+ 559,
+
+ 201,
+
+ 851,
+
+ 520,
+
+ 514,
+
+ 3495,
+
+ 1864,
+
+ 962,
+
+ 267,
+
+ 2531,
+
+ 2276,
+
+ 2636,
+
+ 1306,
+
+ 3534,
+
+ 2177,
+
+ 1216,
+
+ 366,
+
+ 2339,
+ -1,
+
+ 2873,
+
+ 1771,
+
+ 3714,
+
+ 1489,
+
+ 2027,
+
+ 1063,
+
+ 324,
+
+ 1192,
+
+ 27,
+
+ 2963,
+
+ 3276,
+
+ 848,
+
+ 1726,
+
+ 3669,
+
+ 3141,
+
+ 1612,
+
+ 2978,
+
+ 1378,
+
+ 2525,
+
+ 2018,
+
+ 1054,
+
+ 315,
+
+ 830,
+
+ 12,
+
+ 2720,
+ -1, -1,
+
+ 2024,
+
+ 1060,
+
+ 321,
+
+ 2372,
+
+ 4086,
+
+ 1360,
+
+ 2011,
+
+ 1047,
+
+ 309,
+
+ 3633,
+
+ 0,
+
+ 2717,
+ -1,
+
+ 1372,
+
+ 153,
+
+ 31,
+
+ 2732,
+
+ 2360,
+
+ 1588,
+
+ 1348,
+
+ 2096,
+
+ 1135,
+
+ 387,
+ -1,
+
+ 1381,
+
+ 2792,
+
+ 1609,
+ -1,
+
+ 2015,
+
+ 1050,
+
+ 312,
+
+ 3459,
+
+ 6,
+
+ 922,
+
+ 2008,
+
+ 1044,
+
+ 306,
+
+ 2600,
+
+ 3885,
+
+ 2366,
+
+ 3342,
+
+ 1354,
+
+ 2039,
+
+ 1075,
+
+ 336,
+
+ 2456,
+
+ 52,
+
+ 2735,
+
+ 2234,
+
+ 1273,
+
+ 499,
+
+ 3879,
+
+ 168,
+
+ 2390,
+
+ 682,
+
+ 1402,
+
+ 1597,
+ -1,
+
+ 718,
+
+ 2036,
+
+ 1072,
+
+ 333,
+
+ 2450,
+
+ 46,
+
+ 3618,
+
+ 2219,
+
+ 1258,
+
+ 487,
+ -1,
+
+ 141,
+
+ 2384,
+
+ 1855,
+
+ 1396,
+
+ 1573,
+ -1,
+
+ 715,
+
+ 3612,
+
+ 2216,
+
+ 1255,
+
+ 483,
+
+ 393,
+
+ 135,
+
+ 2897,
+
+ 1849,
+
+ 1624,
+
+ 1567,
+
+ 3492,
+
+ 1966,
+
+ 959,
+
+ 3873,
+ -1,
+
+ 2279,
+
+ 2633,
+
+ 887,
+
+ 3600,
+
+ 2210,
+
+ 1249,
+
+ 480,
+
+ 2336,
+
+ 123,
+
+ 532,
+
+ 1837,
+
+ 3780,
+
+ 1555,
+ -1,
+
+ 3594,
+
+ 2207,
+
+ 1246,
+
+ 477,
+
+ 2996,
+
+ 117,
+
+ 881,
+
+ 1831,
+
+ 3774,
+
+ 1549,
+
+ 703,
+ -1,
+
+ 3867,
+
+ 3588,
+
+ 2204,
+
+ 1243,
+
+ 474,
+
+ 878,
+
+ 111,
+
+ 658,
+
+ 1825,
+
+ 3768,
+
+ 1543,
+
+ 3822,
+
+ 1990,
+
+ 1008,
+
+ 288,
+ -1,
+
+ 2273,
+
+ 2681,
+
+ 875,
+
+ 2174,
+
+ 1213,
+ -1,
+
+ 643,
+
+ 2348,
+
+ 2870,
+
+ 1765,
+
+ 3708,
+
+ 1483,
+ -1, -1,
+
+ 652,
+
+ 3267,
+
+ 381,
+
+ 3921,
+
+ 2960,
+
+ 845,
+
+ 637,
+
+ 1684,
+
+ 2165,
+
+ 1204,
+
+ 3237,
+
+ 661,
+
+ 2519,
+
+ 2861,
+
+ 1747,
+
+ 3690,
+
+ 1465,
+
+ 785,
+
+ 3903,
+
+ 2432,
+
+ 3339,
+
+ 37,
+
+ 2090,
+
+ 1114,
+
+ 372,
+
+ 3228,
+
+ 3915,
+
+ 2771,
+
+ 640,
+ -1,
+
+ 1387,
+
+ 2501,
+
+ 3891,
+
+ 3234,
+
+ 2021,
+
+ 1057,
+
+ 318,
+
+ 3924,
+
+ 18,
+
+ 3222,
+
+ 1126,
+
+ 1996,
+
+ 1020,
+
+ 294,
+
+ 2783,
+
+ 2378,
+
+ 2693,
+
+ 1366,
+
+ 3084,
+
+ 3624,
+
+ 2222,
+
+ 1261,
+
+ 2354,
+
+ 3297,
+
+ 3897,
+
+ 1987,
+
+ 1002,
+
+ 285,
+
+ 1579,
+
+ 667,
+
+ 2675,
+
+ 3225,
+
+ 3387,
+
+ 3075,
+
+ 4020,
+
+ 3573,
+
+ 2345,
+
+ 3219,
+
+ 3945,
+
+ 4005,
+
+ 96,
+
+ 3081,
+
+ 1810,
+
+ 3753,
+
+ 1528,
+
+ 2057,
+
+ 1093,
+
+ 3069,
+
+ 2492,
+
+ 2357,
+
+ 3528,
+
+ 1984,
+
+ 996,
+
+ 282,
+
+ 3996,
+
+ 3939,
+
+ 2669,
+ -1,
+
+ 1438,
+
+ 2564,
+
+ 2291,
+
+ 2285,
+ -1,
+
+ 4008,
+
+ 3522,
+
+ 1981,
+
+ 990,
+
+ 279,
+
+ 4014,
+
+ 3072,
+
+ 2663,
+
+ 3516,
+
+ 1978,
+
+ 984,
+
+ 276,
+
+ 3066,
+ -1,
+
+ 2657,
+
+ 3008,
+
+ 3002,
+
+ 3486,
+
+ 1963,
+
+ 950,
+
+ 1999,
+
+ 1026,
+
+ 297,
+
+ 2627,
+
+ 369,
+
+ 2699,
+ -1,
+
+ 3177,
+
+ 3399,
+
+ 2330,
+
+ 3621,
+
+ 3444,
+
+ 1942,
+
+ 906,
+
+ 243,
+
+ 144,
+
+ 613,
+
+ 2585,
+
+ 3501,
+
+ 1576,
+
+ 968,
+
+ 270,
+
+ 3381,
+
+ 2312,
+
+ 2642,
+
+ 3861,
+
+ 2045,
+
+ 1081,
+
+ 342,
+
+ 2468,
+
+ 65,
+
+ 3615,
+
+ 348,
+
+ 2483,
+
+ 712,
+ -1,
+
+ 138,
+
+ 2402,
+
+ 1852,
+
+ 1414,
+
+ 1570,
+
+ 2417,
+
+ 721,
+
+ 1429,
+
+ 3843,
+
+ 3023,
+
+ 727,
+
+ 1678,
+
+ 3375,
+
+ 3201,
+
+ 2042,
+
+ 1078,
+
+ 339,
+
+ 2462,
+
+ 59,
+ -1,
+
+ 4002,
+
+ 778,
+
+ 1672,
+
+ 2171,
+
+ 1210,
+
+ 2396,
+
+ 3369,
+
+ 1408,
+
+ 2867,
+
+ 1759,
+
+ 3702,
+
+ 1477,
+
+ 768,
+
+ 3363,
+
+ 2033,
+
+ 1069,
+
+ 330,
+
+ 709,
+
+ 40,
+
+ 622,
+ -1,
+
+ 3930,
+
+ 3333,
+ -1,
+
+ 3405,
+ -1,
+
+ 2513,
+
+ 1390,
+
+ 2231,
+
+ 1270,
+
+ 496,
+
+ 3048,
+
+ 162,
+
+ 607,
+
+ 2168,
+
+ 1207,
+
+ 1591,
+ -1,
+
+ 3909,
+
+ 2864,
+
+ 1753,
+
+ 3696,
+
+ 1471,
+
+ 3348,
+ -1,
+
+ 3231,
+
+ 634,
+
+ 2030,
+
+ 1066,
+
+ 327,
+
+ 3288,
+
+ 34,
+
+ 3207,
+
+ 1993,
+
+ 1014,
+
+ 291,
+ -1,
+
+ 2507,
+
+ 2687,
+
+ 601,
+
+ 1384,
+
+ 3510,
+
+ 1975,
+
+ 977,
+
+ 2351,
+ -1,
+
+ 3198,
+
+ 2651,
+
+ 3504,
+
+ 1972,
+
+ 971,
+
+ 3120,
+
+ 3888,
+
+ 598,
+
+ 2645,
+
+ 3498,
+
+ 1969,
+
+ 965,
+ -1,
+
+ 3981,
+
+ 595,
+
+ 2639,
+
+ 3489,
+
+ 3078,
+
+ 954,
+
+ 264,
+
+ 3252,
+
+ 2342,
+
+ 2630,
+
+ 3330,
+
+ 3054,
+
+ 625,
+
+ 3195,
+
+ 706,
+
+ 2333,
+
+ 3456,
+
+ 1948,
+
+ 919,
+
+ 249,
+
+ 2267,
+ -1,
+
+ 2597,
+
+ 1654,
+
+ 574,
+
+ 3045,
+ -1,
+
+ 3192,
+
+ 2324,
+
+ 3450,
+
+ 1945,
+
+ 913,
+
+ 246,
+
+ 748,
+
+ 3189,
+
+ 2591,
+
+ 3426,
+
+ 1933,
+
+ 2954,
+
+ 237,
+ -1,
+
+ 2318,
+
+ 1924,
+
+ 3174,
+
+ 228,
+
+ 3210,
+
+ 4050,
+
+ 1921,
+
+ 354,
+
+ 225,
+
+ 1342,
+
+ 3042,
+ -1,
+
+ 2300,
+
+ 3393,
+
+ 1333,
+
+ 2255,
+
+ 3153,
+
+ 2294,
+
+ 1441,
+
+ 1330,
+
+ 363,
+
+ 673,
+
+ 3357,
+
+ 3957,
+
+ 3039,
+
+ 3017,
+
+ 1918,
+
+ 3972,
+
+ 222,
+
+ 3351,
+
+ 3014,
+
+ 3035,
+
+ 3855,
+
+ 2918,
+
+ 3249,
+
+ 3011,
+
+ 3345,
+
+ 2288,
+ -1,
+
+ 1327,
+
+ 3020,
+
+ 664,
+
+ 3057,
+
+ 3336,
+
+ 3597,
+
+ 2054,
+
+ 1090,
+
+ 3951,
+
+ 2486,
+
+ 120,
+
+ 2894,
+
+ 1834,
+
+ 3777,
+
+ 1552,
+
+ 1642,
+
+ 3005,
+
+ 2420,
+
+ 2063,
+
+ 1432,
+
+ 357,
+
+ 4083,
+
+ 730,
+
+ 2744,
+
+ 3849,
+
+ 739,
+
+ 2048,
+
+ 1084,
+
+ 3933,
+
+ 2474,
+
+ 71,
+
+ 1450,
+ -1,
+
+ 2087,
+
+ 1111,
+
+ 3243,
+ -1,
+
+ 2408,
+
+ 2768,
+
+ 1420,
+
+ 3606,
+
+ 2213,
+
+ 1252,
+ -1, -1,
+
+ 129,
+
+ 3555,
+
+ 1843,
+
+ 3786,
+
+ 1561,
+
+ 592,
+
+ 77,
+
+ 1029,
+
+ 1792,
+
+ 3735,
+
+ 1510,
+
+ 2702,
+
+ 589,
+
+ 2435,
+
+ 2144,
+
+ 1912,
+
+ 3927,
+
+ 216,
+
+ 2249,
+
+ 2840,
+
+ 1705,
+
+ 3648,
+ -1,
+
+ 3240,
+
+ 3543,
+
+ 2546,
+
+ 586,
+
+ 450,
+
+ 1321,
+
+ 3204,
+
+ 806,
+
+ 1780,
+
+ 3723,
+
+ 1498,
+
+ 3537,
+ -1,
+
+ 2912,
+
+ 447,
+
+ 3186,
+
+ 351,
+
+ 2489,
+
+ 1774,
+
+ 3717,
+
+ 1492,
+
+ 2993,
+
+ 3183,
+
+ 3531,
+ -1,
+
+ 2534,
+
+ 444,
+
+ 1435,
+
+ 1180,
+
+ 3180,
+
+ 1768,
+
+ 3711,
+
+ 1486,
+
+ 1702,
+
+ 3645,
+
+ 2528,
+
+ 565,
+
+ 3471,
+
+ 3087,
+
+ 934,
+
+ 255,
+
+ 556,
+
+ 1636,
+
+ 2612,
+
+ 3051,
+
+ 679,
+
+ 553,
+
+ 2522,
+ -1,
+
+ 3159,
+
+ 432,
+
+ 2495,
+
+ 733,
+
+ 3032,
+
+ 1744,
+
+ 3687,
+
+ 1462,
+ -1,
+
+ 691,
+
+ 2429,
+
+ 3029,
+
+ 1453,
+
+ 3156,
+
+ 3408,
+ -1, -1,
+
+ 550,
+
+ 3026,
+
+ 2069,
+
+ 3147,
+
+ 2153,
+
+ 2498,
+
+ 421,
+
+ 2750,
+
+ 3138,
+
+ 2849,
+
+ 1723,
+
+ 3666,
+ -1,
+
+ 3135,
+ -1, -1,
+
+ 2138,
+
+ 1177,
+
+ 414,
+
+ 676,
+
+ 826,
+
+ 2834,
+
+ 1693,
+
+ 2135,
+
+ 1174,
+
+ 411,
+
+ 3990,
+
+ 3984,
+
+ 2831,
+
+ 1687,
+
+ 1861,
+
+ 685,
+
+ 795,
+
+ 3132,
+ -1,
+
+ 2129,
+
+ 1168,
+
+ 408,
+ -1,
+
+ 789,
+
+ 2825,
+
+ 1675,
+ -1,
+
+ 2051,
+
+ 1087,
+
+ 3975,
+
+ 2480,
+
+ 2002,
+
+ 1032,
+
+ 300,
+
+ 1858,
+
+ 773,
+
+ 2705,
+
+ 405,
+
+ 2414,
+ -1,
+
+ 1426,
+
+ 1666,
+
+ 4077,
+
+ 724,
+
+ 345,
+
+ 2477,
+
+ 74,
+ -1,
+
+ 3258,
+
+ 3963,
+
+ 402,
+
+ 762,
+ -1,
+
+ 2411,
+
+ 1660,
+
+ 1423,
+
+ 4035,
+
+ 547,
+
+ 3801,
+
+ 3483,
+ -1,
+
+ 947,
+
+ 261,
+
+ 3273,
+
+ 755,
+
+ 2624,
+
+ 3480,
+
+ 1960,
+
+ 944,
+
+ 3876,
+ -1,
+
+ 2327,
+
+ 2621,
+ -1, -1,
+
+ 3438,
+
+ 1939,
+
+ 899,
+
+ 3453,
+
+ 3870,
+
+ 916,
+
+ 2579,
+
+ 3432,
+
+ 1936,
+
+ 2594,
+
+ 240,
+
+ 3093,
+
+ 2306,
+ -1,
+
+ 3327,
+
+ 2321,
+
+ 3864,
+
+ 3420,
+
+ 1930,
+
+ 3798,
+
+ 234,
+
+ 1345,
+
+ 3636,
+
+ 2228,
+
+ 1267,
+
+ 493,
+
+ 3117,
+
+ 156,
+
+ 577,
+ -1,
+
+ 3978,
+
+ 1339,
+
+ 3630,
+
+ 2225,
+
+ 1264,
+
+ 490,
+ -1,
+
+ 150,
+
+ 3609,
+
+ 893,
+
+ 3840,
+
+ 1585,
+ -1,
+
+ 132,
+
+ 3591,
+
+ 1846,
+
+ 3789,
+
+ 1564,
+ -1,
+
+ 114,
+
+ 2891,
+
+ 1828,
+
+ 3771,
+
+ 1546,
+ -1,
+
+ 884,
+
+ 3579,
+ -1,
+
+ 688,
+ -1, -1,
+
+ 102,
+
+ 3819,
+
+ 1816,
+
+ 3759,
+
+ 1534,
+
+ 3567,
+ -1,
+
+ 1129,
+ -1,
+
+ 3549,
+
+ 89,
+
+ 2786,
+
+ 1804,
+
+ 3747,
+
+ 1522,
+
+ 3561,
+
+ 1786,
+
+ 3729,
+
+ 1504,
+
+ 2570,
+
+ 83,
+
+ 1035,
+
+ 1798,
+
+ 3741,
+
+ 1516,
+
+ 2708,
+
+ 3474,
+
+ 1957,
+
+ 937,
+
+ 2558,
+
+ 3264,
+
+ 441,
+
+ 2615,
+
+ 2540,
+ -1,
+
+ 1762,
+
+ 3705,
+
+ 1480,
+ -1,
+
+ 2552,
+
+ 2132,
+
+ 1171,
+
+ 628,
+ -1,
+
+ 3324,
+
+ 2828,
+
+ 1681,
+
+ 4080,
+ -1,
+
+ 438,
+ -1,
+
+ 3321,
+
+ 2516,
+
+ 1756,
+
+ 3699,
+
+ 1474,
+
+ 782,
+
+ 2005,
+
+ 1038,
+
+ 303,
+
+ 4047,
+
+ 435,
+
+ 2711,
+
+ 3315,
+
+ 3969,
+
+ 1750,
+
+ 3693,
+
+ 1468,
+
+ 3099,
+ -1,
+
+ 2510,
+
+ 583,
+ -1,
+
+ 4041,
+ -1,
+
+ 3213,
+ -1, -1,
+
+ 580,
+
+ 3966,
+
+ 4017,
+ -1,
+
+ 2504,
+
+ 2126,
+
+ 1165,
+
+ 3999,
+
+ 3246,
+
+ 571,
+
+ 2822,
+
+ 1669,
+
+ 3993,
+
+ 2162,
+
+ 1201,
+ -1,
+
+ 568,
+ -1,
+
+ 2858,
+
+ 1741,
+
+ 3684,
+
+ 765,
+
+ 1198,
+
+ 429,
+
+ 2159,
+ -1,
+
+ 562,
+
+ 1738,
+
+ 3681,
+
+ 2855,
+
+ 1735,
+
+ 3678,
+
+ 3987,
+
+ 3171,
+ -1,
+
+ 3060,
+ -1,
+
+ 842,
+
+ 1195,
+
+ 425,
+
+ 839,
+
+ 2156,
+ -1,
+
+ 1732,
+
+ 3675,
+
+ 2150,
+
+ 2852,
+
+ 1729,
+
+ 3672,
+
+ 3150,
+
+ 2846,
+
+ 1717,
+
+ 3660,
+
+ 836,
+ -1, -1, -1,
+
+ 833,
+ -1,
+
+ 3144,
+ -1,
+
+ 820,
+
+ 1186,
+
+ 417,
+
+ 2147,
+
+ 2453,
+
+ 49,
+
+ 1714,
+
+ 3657,
+
+ 2843,
+
+ 1711,
+
+ 3654,
+ -1,
+
+ 2387,
+ -1,
+
+ 1399,
+ -1,
+
+ 816,
+
+ 2141,
+ -1,
+
+ 813,
+
+ 3882,
+ -1,
+
+ 2837,
+
+ 1699,
+
+ 3642,
+
+ 2123,
+
+ 1162,
+
+ 2066,
+
+ 631,
+
+ 360,
+
+ 2819,
+
+ 1663,
+
+ 2747,
+
+ 802,
+ -1, -1, -1,
+
+ 2117,
+
+ 1156,
+
+ 3858,
+
+ 1456,
+
+ 758,
+
+ 2813,
+
+ 1651,
+
+ 2111,
+
+ 1150,
+
+ 396,
+
+ 3291,
+
+ 2426,
+
+ 2807,
+
+ 1639,
+
+ 2060,
+
+ 1096,
+
+ 745,
+
+ 1120,
+
+ 375,
+
+ 2741,
+
+ 3852,
+
+ 2777,
+ -1,
+
+ 736,
+
+ 2099,
+
+ 1138,
+
+ 390,
+
+ 1444,
+ -1,
+
+ 2795,
+
+ 1615,
+
+ 3168,
+
+ 3846,
+
+ 2093,
+
+ 1132,
+
+ 384,
+
+ 15,
+
+ 2723,
+
+ 2789,
+
+ 1603,
+
+ 2465,
+
+ 62,
+
+ 2738,
+
+ 2375,
+
+ 3318,
+
+ 1363,
+
+ 2120,
+
+ 1159,
+
+ 2399,
+ -1,
+
+ 1411,
+
+ 2816,
+
+ 1657,
+
+ 4062,
+
+ 3468,
+
+ 1954,
+
+ 931,
+
+ 3462,
+
+ 1951,
+
+ 925,
+
+ 2609,
+
+ 3216,
+
+ 752,
+
+ 2603,
+
+ 3837,
+
+ 1894,
+ -1,
+
+ 198,
+
+ 1891,
+
+ 1876,
+
+ 195,
+
+ 180,
+
+ 3834,
+
+ 1023,
+ -1,
+
+ 3831,
+
+ 2270,
+
+ 2696,
+
+ 1303,
+
+ 2264,
+
+ 2258,
+
+ 1300,
+
+ 1285,
+ -1, -1,
+
+ 2084,
+
+ 1108,
+
+ 3312,
+
+ 3828,
+
+ 1873,
+
+ 2765,
+
+ 177,
+
+ 3825,
+
+ 1870,
+
+ 2957,
+
+ 174,
+
+ 3813,
+
+ 2951,
+
+ 2921,
+
+ 3063,
+
+ 2252,
+
+ 1123,
+
+ 1282,
+ -1,
+
+ 2246,
+
+ 2780,
+
+ 1279,
+ -1,
+
+ 2105,
+
+ 1144,
+ -1,
+
+ 670,
+
+ 3810,
+
+ 2801,
+
+ 1627,
+
+ 3807,
+
+ 3603,
+
+ 1909,
+
+ 2915,
+
+ 213,
+ -1,
+
+ 126,
+
+ 2909,
+
+ 1840,
+
+ 3783,
+
+ 1558,
+
+ 3585,
+
+ 2075,
+
+ 1099,
+
+ 3795,
+
+ 1318,
+
+ 108,
+
+ 2756,
+
+ 1822,
+
+ 3765,
+
+ 1540,
+
+ 1189,
+
+ 3942,
+
+ 1183,
+
+ 24,
+
+ 2729,
+
+ 1720,
+
+ 3663,
+
+ 1708,
+
+ 3651,
+ -1,
+
+ 2987,
+ -1,
+
+ 1375,
+
+ 2114,
+
+ 1153,
+
+ 823,
+
+ 3402,
+
+ 810,
+
+ 2810,
+
+ 1645,
+ -1,
+
+ 4074,
+
+ 2072,
+
+ 1696,
+
+ 3639,
+
+ 2102,
+
+ 1141,
+
+ 2753,
+
+ 4071,
+
+ 742,
+
+ 2798,
+
+ 1621,
+
+ 3309,
+
+ 798,
+
+ 3261,
+ -1, -1,
+
+ 4029,
+
+ 2471,
+
+ 68,
+
+ 4044,
+
+ 2459,
+
+ 56,
+
+ 646,
+
+ 4023,
+ -1,
+
+ 2405,
+ -1,
+
+ 1417,
+
+ 2393,
+
+ 9,
+
+ 1405,
+
+ 21,
+
+ 2726,
+
+ 4011,
+
+ 2447,
+
+ 43,
+
+ 2369,
+
+ 3255,
+
+ 1357,
+
+ 3282,
+
+ 1369,
+ -1,
+
+ 2381,
+
+ 3477,
+
+ 1393,
+
+ 940,
+
+ 258,
+
+ 3300,
+
+ 3906,
+
+ 2618,
+
+ 1117,
+
+ 3096,
+
+ 3627,
+
+ 3954,
+
+ 2774,
+
+ 529,
+
+ 3294,
+
+ 147,
+
+ 526,
+
+ 511,
+
+ 3525,
+
+ 1582,
+
+ 993,
+ -1,
+
+ 2444,
+
+ 3465,
+
+ 2666,
+
+ 928,
+
+ 252,
+
+ 890,
+
+ 3447,
+
+ 2606,
+
+ 909,
+ -1, -1,
+
+ 3090,
+
+ 2588,
+
+ 3126,
+
+ 3165,
+
+ 508,
+ -1,
+
+ 3162,
+
+ 2315,
+
+ 505,
+
+ 3441,
+
+ 3435,
+
+ 902,
+
+ 896,
+ -1, -1,
+
+ 2582,
+
+ 2576,
+
+ 1903,
+
+ 1900,
+
+ 207,
+
+ 204,
+
+ 2309,
+
+ 2303,
+
+ 1017,
+
+ 1888,
+ -1,
+
+ 192,
+
+ 2690,
+
+ 4065,
+ -1,
+
+ 1312,
+
+ 1309,
+
+ 544,
+
+ 3270,
+
+ 2108,
+
+ 1147,
+
+ 1882,
+
+ 1297,
+
+ 186,
+
+ 2804,
+
+ 1633,
+
+ 1011,
+
+ 700,
+ -1, -1,
+
+ 2684,
+
+ 2975,
+
+ 2969,
+
+ 3285,
+
+ 1291,
+
+ 655,
+
+ 1005,
+
+ 3816,
+
+ 2945,
+
+ 3804,
+
+ 2678,
+
+ 3306,
+
+ 2081,
+
+ 1105,
+
+ 2078,
+
+ 1102,
+ -1,
+
+ 2762,
+
+ 999,
+
+ 2759,
+
+ 2933,
+
+ 3372,
+
+ 2672,
+
+ 3,
+ -1,
+
+ 3792,
+
+ 3114,
+
+ 3519,
+
+ 694,
+
+ 987,
+
+ 2363,
+
+ 3918,
+
+ 1351,
+
+ 2660,
+
+ 3513,
+ -1,
+
+ 980,
+ -1, -1, -1,
+
+ 2654,
+
+ 3129,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+
+ 649,
+ -1, -1,
+
+ 3396,
+ -1, -1, -1, -1, -1, -1,
+
+ 3303,
+ -1, -1,
+
+ 3960,
+
+ 3105,
+ -1,
+
+ 3948,
+ -1, -1, -1, -1,
+
+ 3390,
+ -1, -1,
+
+ 3900,
+ -1,
+
+ 3912,
+ -1, -1, -1,
+
+ 3936,
+
+ 3384,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+
+ 3378,
+ -1,
+
+ 3102,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+
+ 3366,
+
+ 3279,
+ -1, -1, -1, -1, -1,
+
+ 3360,
+ -1, -1, -1,
+
+ 538,
+
+ 535,
+ -1, -1, -1,
+
+ 619,
+ -1,
+
+ 523,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+
+ 517,
+ -1, -1, -1,
+
+ 616,
+ -1, -1, -1, -1,
+
+ 3123,
+ -1, -1, -1, -1,
+
+ 610,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+
+ 604,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+
+ 4059,
+ -1, -1,
+
+ 4053,
+ -1,
+
+ 3894,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+
+ 3111,
+ -1,
+
+ 3108,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+
+ 4068,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+
+ 4056,
+ -1, -1, -1, -1,
+
+ 4038,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+
+ 4032,
+
+ 4026
+ };
+
+
+ {
+ int key = hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ int index = wordlist[key];
+
+ if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds1 + index, 1) == 0)
+ return index;
+ }
+ }
+ return -1;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold2_key.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold2_key.c
new file mode 100644
index 000000000..e06ba0be1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold2_key.c
@@ -0,0 +1,226 @@
+/* This file was converted by gperf_fold_key_conv.py
+ from gperf output file. */
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -n -C -T -c -t -j1 -L ANSI-C -F,-1 -N onigenc_unicode_fold2_key unicode_fold2_key.gperf */
+/* Computed positions: -k'3,6' */
+
+
+
+/* This gperf source file was generated by make_unicode_fold_data.py */
+
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 59
+#define MIN_WORD_LENGTH 6
+#define MAX_WORD_LENGTH 6
+#define MIN_HASH_VALUE 0
+#define MAX_HASH_VALUE 58
+/* maximum key range = 59, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+hash(OnigCodePoint codes[])
+{
+ static const unsigned char asso_values[] =
+ {
+ 58, 57, 56, 55, 54, 53, 52, 16, 50, 59,
+ 15, 59, 25, 59, 59, 59, 59, 59, 59, 3,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 49, 48, 47, 46, 45, 44, 43, 42,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 21,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 2, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 40, 20, 39, 38,
+ 37, 14, 5, 36, 20, 7, 25, 34, 29, 32,
+ 16, 59, 31, 59, 59, 2, 1, 59, 25, 15,
+ 59, 14, 59, 59, 28, 59, 2, 59, 59, 59,
+ 11, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 24, 59, 22, 59, 59, 11, 59, 59,
+ 59, 59, 59, 7, 59, 0, 59, 59, 16, 59,
+ 1, 59, 59, 16, 59, 59, 59, 15, 59, 59,
+ 59, 6, 59, 59, 59, 59, 0, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59
+ };
+ return asso_values[(unsigned char)onig_codes_byte_at(codes, 5)] + asso_values[(unsigned char)onig_codes_byte_at(codes, 2)];
+}
+
+int
+onigenc_unicode_fold2_key(OnigCodePoint codes[])
+{
+ static const short int wordlist[] =
+ {
+
+ 101,
+
+ 253,
+
+ 76,
+
+ 29,
+
+ 24,
+
+ 239,
+
+ 96,
+
+ 71,
+
+ 92,
+
+ 67,
+
+ 4,
+
+ 62,
+
+ 8,
+
+ 58,
+
+ 234,
+
+ 109,
+
+ 164,
+
+ 88,
+
+ 84,
+
+ 80,
+
+ 214,
+
+ 0,
+
+ 54,
+
+ 261,
+
+ 50,
+
+ 105,
+
+ 121,
+
+ 125,
+
+ 257,
+
+ 42,
+
+ 38,
+
+ 249,
+
+ 46,
+
+ 117,
+
+ 12,
+
+ 113,
+
+ 244,
+
+ 229,
+
+ 224,
+
+ 219,
+
+ 209,
+
+ 16,
+
+ 204,
+
+ 199,
+
+ 194,
+
+ 189,
+
+ 184,
+
+ 179,
+
+ 174,
+
+ 169,
+
+ 20,
+
+ 34,
+
+ 159,
+
+ 154,
+
+ 149,
+
+ 144,
+
+ 139,
+
+ 134,
+
+ 129
+ };
+
+
+ {
+ int key = hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ int index = wordlist[key];
+
+ if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds2 + index, 2) == 0)
+ return index;
+ }
+ }
+ return -1;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold3_key.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold3_key.c
new file mode 100644
index 000000000..7ab24d1d4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold3_key.c
@@ -0,0 +1,136 @@
+/* This file was converted by gperf_fold_key_conv.py
+ from gperf output file. */
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -n -C -T -c -t -j1 -L ANSI-C -F,-1 -N onigenc_unicode_fold3_key unicode_fold3_key.gperf */
+/* Computed positions: -k'3,6,9' */
+
+
+
+/* This gperf source file was generated by make_unicode_fold_data.py */
+
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 14
+#define MIN_WORD_LENGTH 9
+#define MAX_WORD_LENGTH 9
+#define MIN_HASH_VALUE 0
+#define MAX_HASH_VALUE 13
+/* maximum key range = 14, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+hash(OnigCodePoint codes[])
+{
+ static const unsigned char asso_values[] =
+ {
+ 6, 3, 14, 14, 14, 14, 14, 14, 1, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 0, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 4, 14, 14, 5, 14, 14, 4, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 10, 14, 14,
+ 14, 14, 14, 9, 14, 1, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 0, 14, 14,
+ 14, 8, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14
+ };
+ return asso_values[(unsigned char)onig_codes_byte_at(codes, 8)] + asso_values[(unsigned char)onig_codes_byte_at(codes, 5)] + asso_values[(unsigned char)onig_codes_byte_at(codes, 2)];
+}
+
+int
+onigenc_unicode_fold3_key(OnigCodePoint codes[])
+{
+ static const short int wordlist[] =
+ {
+
+ 62,
+
+ 47,
+
+ 31,
+
+ 57,
+
+ 41,
+
+ 25,
+
+ 52,
+
+ 36,
+
+ 20,
+
+ 67,
+
+ 15,
+
+ 10,
+
+ 5,
+
+ 0
+ };
+
+
+ {
+ int key = hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ int index = wordlist[key];
+
+ if (index >= 0 && onig_codes_cmp(codes, OnigUnicodeFolds3 + index, 3) == 0)
+ return index;
+ }
+ }
+ return -1;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold_data.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold_data.c
new file mode 100644
index 000000000..f2429b056
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_fold_data.c
@@ -0,0 +1,1549 @@
+/* This file was generated by make_unicode_fold_data.py. */
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+
+#include "regenc.h"
+
+#define UNICODE_CASEFOLD_VERSION 120100
+
+
+OnigCodePoint OnigUnicodeFolds1[] = {
+ /* 0*/ 0x0061, 1, 0x0041, /* LATIN CAPITAL LETTER A */
+ /* 3*/ 0x0062, 1, 0x0042, /* LATIN CAPITAL LETTER B */
+ /* 6*/ 0x0063, 1, 0x0043, /* LATIN CAPITAL LETTER C */
+ /* 9*/ 0x0064, 1, 0x0044, /* LATIN CAPITAL LETTER D */
+ /* 12*/ 0x0065, 1, 0x0045, /* LATIN CAPITAL LETTER E */
+ /* 15*/ 0x0066, 1, 0x0046, /* LATIN CAPITAL LETTER F */
+ /* 18*/ 0x0067, 1, 0x0047, /* LATIN CAPITAL LETTER G */
+ /* 21*/ 0x0068, 1, 0x0048, /* LATIN CAPITAL LETTER H */
+ /* 24*/ 0x006a, 1, 0x004a, /* LATIN CAPITAL LETTER J */
+ /* 27*/ 0x006b, 2, 0x004b, 0x212a, /* LATIN CAPITAL LETTER K */
+ /* 31*/ 0x006c, 1, 0x004c, /* LATIN CAPITAL LETTER L */
+ /* 34*/ 0x006d, 1, 0x004d, /* LATIN CAPITAL LETTER M */
+ /* 37*/ 0x006e, 1, 0x004e, /* LATIN CAPITAL LETTER N */
+ /* 40*/ 0x006f, 1, 0x004f, /* LATIN CAPITAL LETTER O */
+ /* 43*/ 0x0070, 1, 0x0050, /* LATIN CAPITAL LETTER P */
+ /* 46*/ 0x0071, 1, 0x0051, /* LATIN CAPITAL LETTER Q */
+ /* 49*/ 0x0072, 1, 0x0052, /* LATIN CAPITAL LETTER R */
+ /* 52*/ 0x0073, 2, 0x0053, 0x017f, /* LATIN CAPITAL LETTER S */
+ /* 56*/ 0x0074, 1, 0x0054, /* LATIN CAPITAL LETTER T */
+ /* 59*/ 0x0075, 1, 0x0055, /* LATIN CAPITAL LETTER U */
+ /* 62*/ 0x0076, 1, 0x0056, /* LATIN CAPITAL LETTER V */
+ /* 65*/ 0x0077, 1, 0x0057, /* LATIN CAPITAL LETTER W */
+ /* 68*/ 0x0078, 1, 0x0058, /* LATIN CAPITAL LETTER X */
+ /* 71*/ 0x0079, 1, 0x0059, /* LATIN CAPITAL LETTER Y */
+ /* 74*/ 0x007a, 1, 0x005a, /* LATIN CAPITAL LETTER Z */
+ /* 77*/ 0x00e0, 1, 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
+ /* 80*/ 0x00e1, 1, 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
+ /* 83*/ 0x00e2, 1, 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /* 86*/ 0x00e3, 1, 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
+ /* 89*/ 0x00e4, 1, 0x00c4, /* LATIN CAPITAL LETTER A WITH DIAER.. */
+ /* 92*/ 0x00e5, 2, 0x00c5, 0x212b, /* LATIN CAPITAL LETTER A WITH RING .. */
+ /* 96*/ 0x00e6, 1, 0x00c6, /* LATIN CAPITAL LETTER AE */
+ /* 99*/ 0x00e7, 1, 0x00c7, /* LATIN CAPITAL LETTER C WITH CEDIL.. */
+ /* 102*/ 0x00e8, 1, 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
+ /* 105*/ 0x00e9, 1, 0x00c9, /* LATIN CAPITAL LETTER E WITH ACUTE */
+ /* 108*/ 0x00ea, 1, 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /* 111*/ 0x00eb, 1, 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAER.. */
+ /* 114*/ 0x00ec, 1, 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
+ /* 117*/ 0x00ed, 1, 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
+ /* 120*/ 0x00ee, 1, 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCU.. */
+ /* 123*/ 0x00ef, 1, 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAER.. */
+ /* 126*/ 0x00f0, 1, 0x00d0, /* LATIN CAPITAL LETTER ETH */
+ /* 129*/ 0x00f1, 1, 0x00d1, /* LATIN CAPITAL LETTER N WITH TILDE */
+ /* 132*/ 0x00f2, 1, 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
+ /* 135*/ 0x00f3, 1, 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
+ /* 138*/ 0x00f4, 1, 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /* 141*/ 0x00f5, 1, 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
+ /* 144*/ 0x00f6, 1, 0x00d6, /* LATIN CAPITAL LETTER O WITH DIAER.. */
+ /* 147*/ 0x00f8, 1, 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
+ /* 150*/ 0x00f9, 1, 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
+ /* 153*/ 0x00fa, 1, 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
+ /* 156*/ 0x00fb, 1, 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCU.. */
+ /* 159*/ 0x00fc, 1, 0x00dc, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /* 162*/ 0x00fd, 1, 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
+ /* 165*/ 0x00fe, 1, 0x00de, /* LATIN CAPITAL LETTER THORN */
+ /* 168*/ 0x00ff, 1, 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAER.. */
+ /* 171*/ 0x0101, 1, 0x0100, /* LATIN CAPITAL LETTER A WITH MACRON */
+ /* 174*/ 0x0103, 1, 0x0102, /* LATIN CAPITAL LETTER A WITH BREVE */
+ /* 177*/ 0x0105, 1, 0x0104, /* LATIN CAPITAL LETTER A WITH OGONEK */
+ /* 180*/ 0x0107, 1, 0x0106, /* LATIN CAPITAL LETTER C WITH ACUTE */
+ /* 183*/ 0x0109, 1, 0x0108, /* LATIN CAPITAL LETTER C WITH CIRCU.. */
+ /* 186*/ 0x010b, 1, 0x010a, /* LATIN CAPITAL LETTER C WITH DOT A.. */
+ /* 189*/ 0x010d, 1, 0x010c, /* LATIN CAPITAL LETTER C WITH CARON */
+ /* 192*/ 0x010f, 1, 0x010e, /* LATIN CAPITAL LETTER D WITH CARON */
+ /* 195*/ 0x0111, 1, 0x0110, /* LATIN CAPITAL LETTER D WITH STROKE */
+ /* 198*/ 0x0113, 1, 0x0112, /* LATIN CAPITAL LETTER E WITH MACRON */
+ /* 201*/ 0x0115, 1, 0x0114, /* LATIN CAPITAL LETTER E WITH BREVE */
+ /* 204*/ 0x0117, 1, 0x0116, /* LATIN CAPITAL LETTER E WITH DOT A.. */
+ /* 207*/ 0x0119, 1, 0x0118, /* LATIN CAPITAL LETTER E WITH OGONEK */
+ /* 210*/ 0x011b, 1, 0x011a, /* LATIN CAPITAL LETTER E WITH CARON */
+ /* 213*/ 0x011d, 1, 0x011c, /* LATIN CAPITAL LETTER G WITH CIRCU.. */
+ /* 216*/ 0x011f, 1, 0x011e, /* LATIN CAPITAL LETTER G WITH BREVE */
+ /* 219*/ 0x0121, 1, 0x0120, /* LATIN CAPITAL LETTER G WITH DOT A.. */
+ /* 222*/ 0x0123, 1, 0x0122, /* LATIN CAPITAL LETTER G WITH CEDIL.. */
+ /* 225*/ 0x0125, 1, 0x0124, /* LATIN CAPITAL LETTER H WITH CIRCU.. */
+ /* 228*/ 0x0127, 1, 0x0126, /* LATIN CAPITAL LETTER H WITH STROKE */
+ /* 231*/ 0x0129, 1, 0x0128, /* LATIN CAPITAL LETTER I WITH TILDE */
+ /* 234*/ 0x012b, 1, 0x012a, /* LATIN CAPITAL LETTER I WITH MACRON */
+ /* 237*/ 0x012d, 1, 0x012c, /* LATIN CAPITAL LETTER I WITH BREVE */
+ /* 240*/ 0x012f, 1, 0x012e, /* LATIN CAPITAL LETTER I WITH OGONEK */
+ /* 243*/ 0x0133, 1, 0x0132, /* LATIN CAPITAL LIGATURE IJ */
+ /* 246*/ 0x0135, 1, 0x0134, /* LATIN CAPITAL LETTER J WITH CIRCU.. */
+ /* 249*/ 0x0137, 1, 0x0136, /* LATIN CAPITAL LETTER K WITH CEDIL.. */
+ /* 252*/ 0x013a, 1, 0x0139, /* LATIN CAPITAL LETTER L WITH ACUTE */
+ /* 255*/ 0x013c, 1, 0x013b, /* LATIN CAPITAL LETTER L WITH CEDIL.. */
+ /* 258*/ 0x013e, 1, 0x013d, /* LATIN CAPITAL LETTER L WITH CARON */
+ /* 261*/ 0x0140, 1, 0x013f, /* LATIN CAPITAL LETTER L WITH MIDDL.. */
+ /* 264*/ 0x0142, 1, 0x0141, /* LATIN CAPITAL LETTER L WITH STROKE */
+ /* 267*/ 0x0144, 1, 0x0143, /* LATIN CAPITAL LETTER N WITH ACUTE */
+ /* 270*/ 0x0146, 1, 0x0145, /* LATIN CAPITAL LETTER N WITH CEDIL.. */
+ /* 273*/ 0x0148, 1, 0x0147, /* LATIN CAPITAL LETTER N WITH CARON */
+ /* 276*/ 0x014b, 1, 0x014a, /* LATIN CAPITAL LETTER ENG */
+ /* 279*/ 0x014d, 1, 0x014c, /* LATIN CAPITAL LETTER O WITH MACRON */
+ /* 282*/ 0x014f, 1, 0x014e, /* LATIN CAPITAL LETTER O WITH BREVE */
+ /* 285*/ 0x0151, 1, 0x0150, /* LATIN CAPITAL LETTER O WITH DOUBL.. */
+ /* 288*/ 0x0153, 1, 0x0152, /* LATIN CAPITAL LIGATURE OE */
+ /* 291*/ 0x0155, 1, 0x0154, /* LATIN CAPITAL LETTER R WITH ACUTE */
+ /* 294*/ 0x0157, 1, 0x0156, /* LATIN CAPITAL LETTER R WITH CEDIL.. */
+ /* 297*/ 0x0159, 1, 0x0158, /* LATIN CAPITAL LETTER R WITH CARON */
+ /* 300*/ 0x015b, 1, 0x015a, /* LATIN CAPITAL LETTER S WITH ACUTE */
+ /* 303*/ 0x015d, 1, 0x015c, /* LATIN CAPITAL LETTER S WITH CIRCU.. */
+ /* 306*/ 0x015f, 1, 0x015e, /* LATIN CAPITAL LETTER S WITH CEDIL.. */
+ /* 309*/ 0x0161, 1, 0x0160, /* LATIN CAPITAL LETTER S WITH CARON */
+ /* 312*/ 0x0163, 1, 0x0162, /* LATIN CAPITAL LETTER T WITH CEDIL.. */
+ /* 315*/ 0x0165, 1, 0x0164, /* LATIN CAPITAL LETTER T WITH CARON */
+ /* 318*/ 0x0167, 1, 0x0166, /* LATIN CAPITAL LETTER T WITH STROKE */
+ /* 321*/ 0x0169, 1, 0x0168, /* LATIN CAPITAL LETTER U WITH TILDE */
+ /* 324*/ 0x016b, 1, 0x016a, /* LATIN CAPITAL LETTER U WITH MACRON */
+ /* 327*/ 0x016d, 1, 0x016c, /* LATIN CAPITAL LETTER U WITH BREVE */
+ /* 330*/ 0x016f, 1, 0x016e, /* LATIN CAPITAL LETTER U WITH RING .. */
+ /* 333*/ 0x0171, 1, 0x0170, /* LATIN CAPITAL LETTER U WITH DOUBL.. */
+ /* 336*/ 0x0173, 1, 0x0172, /* LATIN CAPITAL LETTER U WITH OGONEK */
+ /* 339*/ 0x0175, 1, 0x0174, /* LATIN CAPITAL LETTER W WITH CIRCU.. */
+ /* 342*/ 0x0177, 1, 0x0176, /* LATIN CAPITAL LETTER Y WITH CIRCU.. */
+ /* 345*/ 0x017a, 1, 0x0179, /* LATIN CAPITAL LETTER Z WITH ACUTE */
+ /* 348*/ 0x017c, 1, 0x017b, /* LATIN CAPITAL LETTER Z WITH DOT A.. */
+ /* 351*/ 0x017e, 1, 0x017d, /* LATIN CAPITAL LETTER Z WITH CARON */
+ /* 354*/ 0x0180, 1, 0x0243, /* LATIN CAPITAL LETTER B WITH STROKE */
+ /* 357*/ 0x0183, 1, 0x0182, /* LATIN CAPITAL LETTER B WITH TOPBAR */
+ /* 360*/ 0x0185, 1, 0x0184, /* LATIN CAPITAL LETTER TONE SIX */
+ /* 363*/ 0x0188, 1, 0x0187, /* LATIN CAPITAL LETTER C WITH HOOK */
+ /* 366*/ 0x018c, 1, 0x018b, /* LATIN CAPITAL LETTER D WITH TOPBAR */
+ /* 369*/ 0x0192, 1, 0x0191, /* LATIN CAPITAL LETTER F WITH HOOK */
+ /* 372*/ 0x0195, 1, 0x01f6, /* LATIN CAPITAL LETTER HWAIR */
+ /* 375*/ 0x0199, 1, 0x0198, /* LATIN CAPITAL LETTER K WITH HOOK */
+ /* 378*/ 0x019a, 1, 0x023d, /* LATIN CAPITAL LETTER L WITH BAR */
+ /* 381*/ 0x019e, 1, 0x0220, /* LATIN CAPITAL LETTER N WITH LONG .. */
+ /* 384*/ 0x01a1, 1, 0x01a0, /* LATIN CAPITAL LETTER O WITH HORN */
+ /* 387*/ 0x01a3, 1, 0x01a2, /* LATIN CAPITAL LETTER OI */
+ /* 390*/ 0x01a5, 1, 0x01a4, /* LATIN CAPITAL LETTER P WITH HOOK */
+ /* 393*/ 0x01a8, 1, 0x01a7, /* LATIN CAPITAL LETTER TONE TWO */
+ /* 396*/ 0x01ad, 1, 0x01ac, /* LATIN CAPITAL LETTER T WITH HOOK */
+ /* 399*/ 0x01b0, 1, 0x01af, /* LATIN CAPITAL LETTER U WITH HORN */
+ /* 402*/ 0x01b4, 1, 0x01b3, /* LATIN CAPITAL LETTER Y WITH HOOK */
+ /* 405*/ 0x01b6, 1, 0x01b5, /* LATIN CAPITAL LETTER Z WITH STROKE */
+ /* 408*/ 0x01b9, 1, 0x01b8, /* LATIN CAPITAL LETTER EZH REVERSED */
+ /* 411*/ 0x01bd, 1, 0x01bc, /* LATIN CAPITAL LETTER TONE FIVE */
+ /* 414*/ 0x01bf, 1, 0x01f7, /* LATIN CAPITAL LETTER WYNN */
+ /* 417*/ 0x01c6, 2, 0x01c4, 0x01c5, /* LATIN CAPITAL LETTER DZ WITH CARON */
+ /* 421*/ 0x01c9, 2, 0x01c7, 0x01c8, /* LATIN CAPITAL LETTER LJ */
+ /* 425*/ 0x01cc, 2, 0x01ca, 0x01cb, /* LATIN CAPITAL LETTER NJ */
+ /* 429*/ 0x01ce, 1, 0x01cd, /* LATIN CAPITAL LETTER A WITH CARON */
+ /* 432*/ 0x01d0, 1, 0x01cf, /* LATIN CAPITAL LETTER I WITH CARON */
+ /* 435*/ 0x01d2, 1, 0x01d1, /* LATIN CAPITAL LETTER O WITH CARON */
+ /* 438*/ 0x01d4, 1, 0x01d3, /* LATIN CAPITAL LETTER U WITH CARON */
+ /* 441*/ 0x01d6, 1, 0x01d5, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /* 444*/ 0x01d8, 1, 0x01d7, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /* 447*/ 0x01da, 1, 0x01d9, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /* 450*/ 0x01dc, 1, 0x01db, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /* 453*/ 0x01dd, 1, 0x018e, /* LATIN CAPITAL LETTER REVERSED E */
+ /* 456*/ 0x01df, 1, 0x01de, /* LATIN CAPITAL LETTER A WITH DIAER.. */
+ /* 459*/ 0x01e1, 1, 0x01e0, /* LATIN CAPITAL LETTER A WITH DOT A.. */
+ /* 462*/ 0x01e3, 1, 0x01e2, /* LATIN CAPITAL LETTER AE WITH MACR.. */
+ /* 465*/ 0x01e5, 1, 0x01e4, /* LATIN CAPITAL LETTER G WITH STROKE */
+ /* 468*/ 0x01e7, 1, 0x01e6, /* LATIN CAPITAL LETTER G WITH CARON */
+ /* 471*/ 0x01e9, 1, 0x01e8, /* LATIN CAPITAL LETTER K WITH CARON */
+ /* 474*/ 0x01eb, 1, 0x01ea, /* LATIN CAPITAL LETTER O WITH OGONEK */
+ /* 477*/ 0x01ed, 1, 0x01ec, /* LATIN CAPITAL LETTER O WITH OGONE.. */
+ /* 480*/ 0x01ef, 1, 0x01ee, /* LATIN CAPITAL LETTER EZH WITH CAR.. */
+ /* 483*/ 0x01f3, 2, 0x01f1, 0x01f2, /* LATIN CAPITAL LETTER DZ */
+ /* 487*/ 0x01f5, 1, 0x01f4, /* LATIN CAPITAL LETTER G WITH ACUTE */
+ /* 490*/ 0x01f9, 1, 0x01f8, /* LATIN CAPITAL LETTER N WITH GRAVE */
+ /* 493*/ 0x01fb, 1, 0x01fa, /* LATIN CAPITAL LETTER A WITH RING .. */
+ /* 496*/ 0x01fd, 1, 0x01fc, /* LATIN CAPITAL LETTER AE WITH ACUTE */
+ /* 499*/ 0x01ff, 1, 0x01fe, /* LATIN CAPITAL LETTER O WITH STROK.. */
+ /* 502*/ 0x0201, 1, 0x0200, /* LATIN CAPITAL LETTER A WITH DOUBL.. */
+ /* 505*/ 0x0203, 1, 0x0202, /* LATIN CAPITAL LETTER A WITH INVER.. */
+ /* 508*/ 0x0205, 1, 0x0204, /* LATIN CAPITAL LETTER E WITH DOUBL.. */
+ /* 511*/ 0x0207, 1, 0x0206, /* LATIN CAPITAL LETTER E WITH INVER.. */
+ /* 514*/ 0x0209, 1, 0x0208, /* LATIN CAPITAL LETTER I WITH DOUBL.. */
+ /* 517*/ 0x020b, 1, 0x020a, /* LATIN CAPITAL LETTER I WITH INVER.. */
+ /* 520*/ 0x020d, 1, 0x020c, /* LATIN CAPITAL LETTER O WITH DOUBL.. */
+ /* 523*/ 0x020f, 1, 0x020e, /* LATIN CAPITAL LETTER O WITH INVER.. */
+ /* 526*/ 0x0211, 1, 0x0210, /* LATIN CAPITAL LETTER R WITH DOUBL.. */
+ /* 529*/ 0x0213, 1, 0x0212, /* LATIN CAPITAL LETTER R WITH INVER.. */
+ /* 532*/ 0x0215, 1, 0x0214, /* LATIN CAPITAL LETTER U WITH DOUBL.. */
+ /* 535*/ 0x0217, 1, 0x0216, /* LATIN CAPITAL LETTER U WITH INVER.. */
+ /* 538*/ 0x0219, 1, 0x0218, /* LATIN CAPITAL LETTER S WITH COMMA.. */
+ /* 541*/ 0x021b, 1, 0x021a, /* LATIN CAPITAL LETTER T WITH COMMA.. */
+ /* 544*/ 0x021d, 1, 0x021c, /* LATIN CAPITAL LETTER YOGH */
+ /* 547*/ 0x021f, 1, 0x021e, /* LATIN CAPITAL LETTER H WITH CARON */
+ /* 550*/ 0x0223, 1, 0x0222, /* LATIN CAPITAL LETTER OU */
+ /* 553*/ 0x0225, 1, 0x0224, /* LATIN CAPITAL LETTER Z WITH HOOK */
+ /* 556*/ 0x0227, 1, 0x0226, /* LATIN CAPITAL LETTER A WITH DOT A.. */
+ /* 559*/ 0x0229, 1, 0x0228, /* LATIN CAPITAL LETTER E WITH CEDIL.. */
+ /* 562*/ 0x022b, 1, 0x022a, /* LATIN CAPITAL LETTER O WITH DIAER.. */
+ /* 565*/ 0x022d, 1, 0x022c, /* LATIN CAPITAL LETTER O WITH TILDE.. */
+ /* 568*/ 0x022f, 1, 0x022e, /* LATIN CAPITAL LETTER O WITH DOT A.. */
+ /* 571*/ 0x0231, 1, 0x0230, /* LATIN CAPITAL LETTER O WITH DOT A.. */
+ /* 574*/ 0x0233, 1, 0x0232, /* LATIN CAPITAL LETTER Y WITH MACRON */
+ /* 577*/ 0x023c, 1, 0x023b, /* LATIN CAPITAL LETTER C WITH STROKE */
+ /* 580*/ 0x023f, 1, 0x2c7e, /* LATIN CAPITAL LETTER S WITH SWASH.. */
+ /* 583*/ 0x0240, 1, 0x2c7f, /* LATIN CAPITAL LETTER Z WITH SWASH.. */
+ /* 586*/ 0x0242, 1, 0x0241, /* LATIN CAPITAL LETTER GLOTTAL STOP */
+ /* 589*/ 0x0247, 1, 0x0246, /* LATIN CAPITAL LETTER E WITH STROKE */
+ /* 592*/ 0x0249, 1, 0x0248, /* LATIN CAPITAL LETTER J WITH STROKE */
+ /* 595*/ 0x024b, 1, 0x024a, /* LATIN CAPITAL LETTER SMALL Q WITH.. */
+ /* 598*/ 0x024d, 1, 0x024c, /* LATIN CAPITAL LETTER R WITH STROKE */
+ /* 601*/ 0x024f, 1, 0x024e, /* LATIN CAPITAL LETTER Y WITH STROKE */
+ /* 604*/ 0x0250, 1, 0x2c6f, /* LATIN CAPITAL LETTER TURNED A */
+ /* 607*/ 0x0251, 1, 0x2c6d, /* LATIN CAPITAL LETTER ALPHA */
+ /* 610*/ 0x0252, 1, 0x2c70, /* LATIN CAPITAL LETTER TURNED ALPHA */
+ /* 613*/ 0x0253, 1, 0x0181, /* LATIN CAPITAL LETTER B WITH HOOK */
+ /* 616*/ 0x0254, 1, 0x0186, /* LATIN CAPITAL LETTER OPEN O */
+ /* 619*/ 0x0256, 1, 0x0189, /* LATIN CAPITAL LETTER AFRICAN D */
+ /* 622*/ 0x0257, 1, 0x018a, /* LATIN CAPITAL LETTER D WITH HOOK */
+ /* 625*/ 0x0259, 1, 0x018f, /* LATIN CAPITAL LETTER SCHWA */
+ /* 628*/ 0x025b, 1, 0x0190, /* LATIN CAPITAL LETTER OPEN E */
+ /* 631*/ 0x025c, 1, 0xa7ab, /* LATIN CAPITAL LETTER REVERSED OPE.. */
+ /* 634*/ 0x0260, 1, 0x0193, /* LATIN CAPITAL LETTER G WITH HOOK */
+ /* 637*/ 0x0261, 1, 0xa7ac, /* LATIN CAPITAL LETTER SCRIPT G */
+ /* 640*/ 0x0263, 1, 0x0194, /* LATIN CAPITAL LETTER GAMMA */
+ /* 643*/ 0x0265, 1, 0xa78d, /* LATIN CAPITAL LETTER TURNED H */
+ /* 646*/ 0x0266, 1, 0xa7aa, /* LATIN CAPITAL LETTER H WITH HOOK */
+ /* 649*/ 0x0268, 1, 0x0197, /* LATIN CAPITAL LETTER I WITH STROKE */
+ /* 652*/ 0x0269, 1, 0x0196, /* LATIN CAPITAL LETTER IOTA */
+ /* 655*/ 0x026a, 1, 0xa7ae, /* LATIN CAPITAL LETTER SMALL CAPITA.. */
+ /* 658*/ 0x026b, 1, 0x2c62, /* LATIN CAPITAL LETTER L WITH MIDDL.. */
+ /* 661*/ 0x026c, 1, 0xa7ad, /* LATIN CAPITAL LETTER L WITH BELT */
+ /* 664*/ 0x026f, 1, 0x019c, /* LATIN CAPITAL LETTER TURNED M */
+ /* 667*/ 0x0271, 1, 0x2c6e, /* LATIN CAPITAL LETTER M WITH HOOK */
+ /* 670*/ 0x0272, 1, 0x019d, /* LATIN CAPITAL LETTER N WITH LEFT .. */
+ /* 673*/ 0x0275, 1, 0x019f, /* LATIN CAPITAL LETTER O WITH MIDDL.. */
+ /* 676*/ 0x027d, 1, 0x2c64, /* LATIN CAPITAL LETTER R WITH TAIL */
+ /* 679*/ 0x0280, 1, 0x01a6, /* LATIN LETTER YR */
+ /* 682*/ 0x0282, 1, 0xa7c5, /* LATIN CAPITAL LETTER S WITH HOOK */
+ /* 685*/ 0x0283, 1, 0x01a9, /* LATIN CAPITAL LETTER ESH */
+ /* 688*/ 0x0287, 1, 0xa7b1, /* LATIN CAPITAL LETTER TURNED T */
+ /* 691*/ 0x0288, 1, 0x01ae, /* LATIN CAPITAL LETTER T WITH RETRO.. */
+ /* 694*/ 0x0289, 1, 0x0244, /* LATIN CAPITAL LETTER U BAR */
+ /* 697*/ 0x028a, 1, 0x01b1, /* LATIN CAPITAL LETTER UPSILON */
+ /* 700*/ 0x028b, 1, 0x01b2, /* LATIN CAPITAL LETTER V WITH HOOK */
+ /* 703*/ 0x028c, 1, 0x0245, /* LATIN CAPITAL LETTER TURNED V */
+ /* 706*/ 0x0292, 1, 0x01b7, /* LATIN CAPITAL LETTER EZH */
+ /* 709*/ 0x029d, 1, 0xa7b2, /* LATIN CAPITAL LETTER J WITH CROSS.. */
+ /* 712*/ 0x029e, 1, 0xa7b0, /* LATIN CAPITAL LETTER TURNED K */
+ /* 715*/ 0x0371, 1, 0x0370, /* GREEK CAPITAL LETTER HETA */
+ /* 718*/ 0x0373, 1, 0x0372, /* GREEK CAPITAL LETTER ARCHAIC SAMPI */
+ /* 721*/ 0x0377, 1, 0x0376, /* GREEK CAPITAL LETTER PAMPHYLIAN D.. */
+ /* 724*/ 0x037b, 1, 0x03fd, /* GREEK CAPITAL REVERSED LUNATE SIG.. */
+ /* 727*/ 0x037c, 1, 0x03fe, /* GREEK CAPITAL DOTTED LUNATE SIGMA.. */
+ /* 730*/ 0x037d, 1, 0x03ff, /* GREEK CAPITAL REVERSED DOTTED LUN.. */
+ /* 733*/ 0x03ac, 1, 0x0386, /* GREEK CAPITAL LETTER ALPHA WITH T.. */
+ /* 736*/ 0x03ad, 1, 0x0388, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /* 739*/ 0x03ae, 1, 0x0389, /* GREEK CAPITAL LETTER ETA WITH TON.. */
+ /* 742*/ 0x03af, 1, 0x038a, /* GREEK CAPITAL LETTER IOTA WITH TO.. */
+ /* 745*/ 0x03b1, 1, 0x0391, /* GREEK CAPITAL LETTER ALPHA */
+ /* 748*/ 0x03b2, 2, 0x0392, 0x03d0, /* GREEK CAPITAL LETTER BETA */
+ /* 752*/ 0x03b3, 1, 0x0393, /* GREEK CAPITAL LETTER GAMMA */
+ /* 755*/ 0x03b4, 1, 0x0394, /* GREEK CAPITAL LETTER DELTA */
+ /* 758*/ 0x03b5, 2, 0x0395, 0x03f5, /* GREEK CAPITAL LETTER EPSILON */
+ /* 762*/ 0x03b6, 1, 0x0396, /* GREEK CAPITAL LETTER ZETA */
+ /* 765*/ 0x03b7, 1, 0x0397, /* GREEK CAPITAL LETTER ETA */
+ /* 768*/ 0x03b8, 3, 0x0398, 0x03d1, 0x03f4, /* GREEK CAPITAL LETTER THETA */
+ /* 773*/ 0x03b9, 3, 0x0345, 0x0399, 0x1fbe, /* COMBINING GREEK YPOGEGRAMMENI */
+ /* 778*/ 0x03ba, 2, 0x039a, 0x03f0, /* GREEK CAPITAL LETTER KAPPA */
+ /* 782*/ 0x03bb, 1, 0x039b, /* GREEK CAPITAL LETTER LAMDA */
+ /* 785*/ 0x03bc, 2, 0x00b5, 0x039c, /* MICRO SIGN */
+ /* 789*/ 0x03bd, 1, 0x039d, /* GREEK CAPITAL LETTER NU */
+ /* 792*/ 0x03be, 1, 0x039e, /* GREEK CAPITAL LETTER XI */
+ /* 795*/ 0x03bf, 1, 0x039f, /* GREEK CAPITAL LETTER OMICRON */
+ /* 798*/ 0x03c0, 2, 0x03a0, 0x03d6, /* GREEK CAPITAL LETTER PI */
+ /* 802*/ 0x03c1, 2, 0x03a1, 0x03f1, /* GREEK CAPITAL LETTER RHO */
+ /* 806*/ 0x03c3, 2, 0x03a3, 0x03c2, /* GREEK CAPITAL LETTER SIGMA */
+ /* 810*/ 0x03c4, 1, 0x03a4, /* GREEK CAPITAL LETTER TAU */
+ /* 813*/ 0x03c5, 1, 0x03a5, /* GREEK CAPITAL LETTER UPSILON */
+ /* 816*/ 0x03c6, 2, 0x03a6, 0x03d5, /* GREEK CAPITAL LETTER PHI */
+ /* 820*/ 0x03c7, 1, 0x03a7, /* GREEK CAPITAL LETTER CHI */
+ /* 823*/ 0x03c8, 1, 0x03a8, /* GREEK CAPITAL LETTER PSI */
+ /* 826*/ 0x03c9, 2, 0x03a9, 0x2126, /* GREEK CAPITAL LETTER OMEGA */
+ /* 830*/ 0x03ca, 1, 0x03aa, /* GREEK CAPITAL LETTER IOTA WITH DI.. */
+ /* 833*/ 0x03cb, 1, 0x03ab, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /* 836*/ 0x03cc, 1, 0x038c, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /* 839*/ 0x03cd, 1, 0x038e, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /* 842*/ 0x03ce, 1, 0x038f, /* GREEK CAPITAL LETTER OMEGA WITH T.. */
+ /* 845*/ 0x03d7, 1, 0x03cf, /* GREEK CAPITAL KAI SYMBOL */
+ /* 848*/ 0x03d9, 1, 0x03d8, /* GREEK LETTER ARCHAIC KOPPA */
+ /* 851*/ 0x03db, 1, 0x03da, /* GREEK LETTER STIGMA */
+ /* 854*/ 0x03dd, 1, 0x03dc, /* GREEK LETTER DIGAMMA */
+ /* 857*/ 0x03df, 1, 0x03de, /* GREEK LETTER KOPPA */
+ /* 860*/ 0x03e1, 1, 0x03e0, /* GREEK LETTER SAMPI */
+ /* 863*/ 0x03e3, 1, 0x03e2, /* COPTIC CAPITAL LETTER SHEI */
+ /* 866*/ 0x03e5, 1, 0x03e4, /* COPTIC CAPITAL LETTER FEI */
+ /* 869*/ 0x03e7, 1, 0x03e6, /* COPTIC CAPITAL LETTER KHEI */
+ /* 872*/ 0x03e9, 1, 0x03e8, /* COPTIC CAPITAL LETTER HORI */
+ /* 875*/ 0x03eb, 1, 0x03ea, /* COPTIC CAPITAL LETTER GANGIA */
+ /* 878*/ 0x03ed, 1, 0x03ec, /* COPTIC CAPITAL LETTER SHIMA */
+ /* 881*/ 0x03ef, 1, 0x03ee, /* COPTIC CAPITAL LETTER DEI */
+ /* 884*/ 0x03f2, 1, 0x03f9, /* GREEK CAPITAL LUNATE SIGMA SYMBOL */
+ /* 887*/ 0x03f3, 1, 0x037f, /* GREEK CAPITAL LETTER YOT */
+ /* 890*/ 0x03f8, 1, 0x03f7, /* GREEK CAPITAL LETTER SHO */
+ /* 893*/ 0x03fb, 1, 0x03fa, /* GREEK CAPITAL LETTER SAN */
+ /* 896*/ 0x0430, 1, 0x0410, /* CYRILLIC CAPITAL LETTER A */
+ /* 899*/ 0x0431, 1, 0x0411, /* CYRILLIC CAPITAL LETTER BE */
+ /* 902*/ 0x0432, 2, 0x0412, 0x1c80, /* CYRILLIC CAPITAL LETTER VE */
+ /* 906*/ 0x0433, 1, 0x0413, /* CYRILLIC CAPITAL LETTER GHE */
+ /* 909*/ 0x0434, 2, 0x0414, 0x1c81, /* CYRILLIC CAPITAL LETTER DE */
+ /* 913*/ 0x0435, 1, 0x0415, /* CYRILLIC CAPITAL LETTER IE */
+ /* 916*/ 0x0436, 1, 0x0416, /* CYRILLIC CAPITAL LETTER ZHE */
+ /* 919*/ 0x0437, 1, 0x0417, /* CYRILLIC CAPITAL LETTER ZE */
+ /* 922*/ 0x0438, 1, 0x0418, /* CYRILLIC CAPITAL LETTER I */
+ /* 925*/ 0x0439, 1, 0x0419, /* CYRILLIC CAPITAL LETTER SHORT I */
+ /* 928*/ 0x043a, 1, 0x041a, /* CYRILLIC CAPITAL LETTER KA */
+ /* 931*/ 0x043b, 1, 0x041b, /* CYRILLIC CAPITAL LETTER EL */
+ /* 934*/ 0x043c, 1, 0x041c, /* CYRILLIC CAPITAL LETTER EM */
+ /* 937*/ 0x043d, 1, 0x041d, /* CYRILLIC CAPITAL LETTER EN */
+ /* 940*/ 0x043e, 2, 0x041e, 0x1c82, /* CYRILLIC CAPITAL LETTER O */
+ /* 944*/ 0x043f, 1, 0x041f, /* CYRILLIC CAPITAL LETTER PE */
+ /* 947*/ 0x0440, 1, 0x0420, /* CYRILLIC CAPITAL LETTER ER */
+ /* 950*/ 0x0441, 2, 0x0421, 0x1c83, /* CYRILLIC CAPITAL LETTER ES */
+ /* 954*/ 0x0442, 3, 0x0422, 0x1c84, 0x1c85, /* CYRILLIC CAPITAL LETTER TE */
+ /* 959*/ 0x0443, 1, 0x0423, /* CYRILLIC CAPITAL LETTER U */
+ /* 962*/ 0x0444, 1, 0x0424, /* CYRILLIC CAPITAL LETTER EF */
+ /* 965*/ 0x0445, 1, 0x0425, /* CYRILLIC CAPITAL LETTER HA */
+ /* 968*/ 0x0446, 1, 0x0426, /* CYRILLIC CAPITAL LETTER TSE */
+ /* 971*/ 0x0447, 1, 0x0427, /* CYRILLIC CAPITAL LETTER CHE */
+ /* 974*/ 0x0448, 1, 0x0428, /* CYRILLIC CAPITAL LETTER SHA */
+ /* 977*/ 0x0449, 1, 0x0429, /* CYRILLIC CAPITAL LETTER SHCHA */
+ /* 980*/ 0x044a, 2, 0x042a, 0x1c86, /* CYRILLIC CAPITAL LETTER HARD SIGN */
+ /* 984*/ 0x044b, 1, 0x042b, /* CYRILLIC CAPITAL LETTER YERU */
+ /* 987*/ 0x044c, 1, 0x042c, /* CYRILLIC CAPITAL LETTER SOFT SIGN */
+ /* 990*/ 0x044d, 1, 0x042d, /* CYRILLIC CAPITAL LETTER E */
+ /* 993*/ 0x044e, 1, 0x042e, /* CYRILLIC CAPITAL LETTER YU */
+ /* 996*/ 0x044f, 1, 0x042f, /* CYRILLIC CAPITAL LETTER YA */
+ /* 999*/ 0x0450, 1, 0x0400, /* CYRILLIC CAPITAL LETTER IE WITH G.. */
+ /*1002*/ 0x0451, 1, 0x0401, /* CYRILLIC CAPITAL LETTER IO */
+ /*1005*/ 0x0452, 1, 0x0402, /* CYRILLIC CAPITAL LETTER DJE */
+ /*1008*/ 0x0453, 1, 0x0403, /* CYRILLIC CAPITAL LETTER GJE */
+ /*1011*/ 0x0454, 1, 0x0404, /* CYRILLIC CAPITAL LETTER UKRAINIAN.. */
+ /*1014*/ 0x0455, 1, 0x0405, /* CYRILLIC CAPITAL LETTER DZE */
+ /*1017*/ 0x0456, 1, 0x0406, /* CYRILLIC CAPITAL LETTER BYELORUSS.. */
+ /*1020*/ 0x0457, 1, 0x0407, /* CYRILLIC CAPITAL LETTER YI */
+ /*1023*/ 0x0458, 1, 0x0408, /* CYRILLIC CAPITAL LETTER JE */
+ /*1026*/ 0x0459, 1, 0x0409, /* CYRILLIC CAPITAL LETTER LJE */
+ /*1029*/ 0x045a, 1, 0x040a, /* CYRILLIC CAPITAL LETTER NJE */
+ /*1032*/ 0x045b, 1, 0x040b, /* CYRILLIC CAPITAL LETTER TSHE */
+ /*1035*/ 0x045c, 1, 0x040c, /* CYRILLIC CAPITAL LETTER KJE */
+ /*1038*/ 0x045d, 1, 0x040d, /* CYRILLIC CAPITAL LETTER I WITH GR.. */
+ /*1041*/ 0x045e, 1, 0x040e, /* CYRILLIC CAPITAL LETTER SHORT U */
+ /*1044*/ 0x045f, 1, 0x040f, /* CYRILLIC CAPITAL LETTER DZHE */
+ /*1047*/ 0x0461, 1, 0x0460, /* CYRILLIC CAPITAL LETTER OMEGA */
+ /*1050*/ 0x0463, 2, 0x0462, 0x1c87, /* CYRILLIC CAPITAL LETTER YAT */
+ /*1054*/ 0x0465, 1, 0x0464, /* CYRILLIC CAPITAL LETTER IOTIFIED E */
+ /*1057*/ 0x0467, 1, 0x0466, /* CYRILLIC CAPITAL LETTER LITTLE YUS */
+ /*1060*/ 0x0469, 1, 0x0468, /* CYRILLIC CAPITAL LETTER IOTIFIED .. */
+ /*1063*/ 0x046b, 1, 0x046a, /* CYRILLIC CAPITAL LETTER BIG YUS */
+ /*1066*/ 0x046d, 1, 0x046c, /* CYRILLIC CAPITAL LETTER IOTIFIED .. */
+ /*1069*/ 0x046f, 1, 0x046e, /* CYRILLIC CAPITAL LETTER KSI */
+ /*1072*/ 0x0471, 1, 0x0470, /* CYRILLIC CAPITAL LETTER PSI */
+ /*1075*/ 0x0473, 1, 0x0472, /* CYRILLIC CAPITAL LETTER FITA */
+ /*1078*/ 0x0475, 1, 0x0474, /* CYRILLIC CAPITAL LETTER IZHITSA */
+ /*1081*/ 0x0477, 1, 0x0476, /* CYRILLIC CAPITAL LETTER IZHITSA W.. */
+ /*1084*/ 0x0479, 1, 0x0478, /* CYRILLIC CAPITAL LETTER UK */
+ /*1087*/ 0x047b, 1, 0x047a, /* CYRILLIC CAPITAL LETTER ROUND OME.. */
+ /*1090*/ 0x047d, 1, 0x047c, /* CYRILLIC CAPITAL LETTER OMEGA WIT.. */
+ /*1093*/ 0x047f, 1, 0x047e, /* CYRILLIC CAPITAL LETTER OT */
+ /*1096*/ 0x0481, 1, 0x0480, /* CYRILLIC CAPITAL LETTER KOPPA */
+ /*1099*/ 0x048b, 1, 0x048a, /* CYRILLIC CAPITAL LETTER SHORT I W.. */
+ /*1102*/ 0x048d, 1, 0x048c, /* CYRILLIC CAPITAL LETTER SEMISOFT .. */
+ /*1105*/ 0x048f, 1, 0x048e, /* CYRILLIC CAPITAL LETTER ER WITH T.. */
+ /*1108*/ 0x0491, 1, 0x0490, /* CYRILLIC CAPITAL LETTER GHE WITH .. */
+ /*1111*/ 0x0493, 1, 0x0492, /* CYRILLIC CAPITAL LETTER GHE WITH .. */
+ /*1114*/ 0x0495, 1, 0x0494, /* CYRILLIC CAPITAL LETTER GHE WITH .. */
+ /*1117*/ 0x0497, 1, 0x0496, /* CYRILLIC CAPITAL LETTER ZHE WITH .. */
+ /*1120*/ 0x0499, 1, 0x0498, /* CYRILLIC CAPITAL LETTER ZE WITH D.. */
+ /*1123*/ 0x049b, 1, 0x049a, /* CYRILLIC CAPITAL LETTER KA WITH D.. */
+ /*1126*/ 0x049d, 1, 0x049c, /* CYRILLIC CAPITAL LETTER KA WITH V.. */
+ /*1129*/ 0x049f, 1, 0x049e, /* CYRILLIC CAPITAL LETTER KA WITH S.. */
+ /*1132*/ 0x04a1, 1, 0x04a0, /* CYRILLIC CAPITAL LETTER BASHKIR KA */
+ /*1135*/ 0x04a3, 1, 0x04a2, /* CYRILLIC CAPITAL LETTER EN WITH D.. */
+ /*1138*/ 0x04a5, 1, 0x04a4, /* CYRILLIC CAPITAL LIGATURE EN GHE */
+ /*1141*/ 0x04a7, 1, 0x04a6, /* CYRILLIC CAPITAL LETTER PE WITH M.. */
+ /*1144*/ 0x04a9, 1, 0x04a8, /* CYRILLIC CAPITAL LETTER ABKHASIAN.. */
+ /*1147*/ 0x04ab, 1, 0x04aa, /* CYRILLIC CAPITAL LETTER ES WITH D.. */
+ /*1150*/ 0x04ad, 1, 0x04ac, /* CYRILLIC CAPITAL LETTER TE WITH D.. */
+ /*1153*/ 0x04af, 1, 0x04ae, /* CYRILLIC CAPITAL LETTER STRAIGHT U */
+ /*1156*/ 0x04b1, 1, 0x04b0, /* CYRILLIC CAPITAL LETTER STRAIGHT .. */
+ /*1159*/ 0x04b3, 1, 0x04b2, /* CYRILLIC CAPITAL LETTER HA WITH D.. */
+ /*1162*/ 0x04b5, 1, 0x04b4, /* CYRILLIC CAPITAL LIGATURE TE TSE */
+ /*1165*/ 0x04b7, 1, 0x04b6, /* CYRILLIC CAPITAL LETTER CHE WITH .. */
+ /*1168*/ 0x04b9, 1, 0x04b8, /* CYRILLIC CAPITAL LETTER CHE WITH .. */
+ /*1171*/ 0x04bb, 1, 0x04ba, /* CYRILLIC CAPITAL LETTER SHHA */
+ /*1174*/ 0x04bd, 1, 0x04bc, /* CYRILLIC CAPITAL LETTER ABKHASIAN.. */
+ /*1177*/ 0x04bf, 1, 0x04be, /* CYRILLIC CAPITAL LETTER ABKHASIAN.. */
+ /*1180*/ 0x04c2, 1, 0x04c1, /* CYRILLIC CAPITAL LETTER ZHE WITH .. */
+ /*1183*/ 0x04c4, 1, 0x04c3, /* CYRILLIC CAPITAL LETTER KA WITH H.. */
+ /*1186*/ 0x04c6, 1, 0x04c5, /* CYRILLIC CAPITAL LETTER EL WITH T.. */
+ /*1189*/ 0x04c8, 1, 0x04c7, /* CYRILLIC CAPITAL LETTER EN WITH H.. */
+ /*1192*/ 0x04ca, 1, 0x04c9, /* CYRILLIC CAPITAL LETTER EN WITH T.. */
+ /*1195*/ 0x04cc, 1, 0x04cb, /* CYRILLIC CAPITAL LETTER KHAKASSIA.. */
+ /*1198*/ 0x04ce, 1, 0x04cd, /* CYRILLIC CAPITAL LETTER EM WITH T.. */
+ /*1201*/ 0x04cf, 1, 0x04c0, /* CYRILLIC LETTER PALOCHKA */
+ /*1204*/ 0x04d1, 1, 0x04d0, /* CYRILLIC CAPITAL LETTER A WITH BR.. */
+ /*1207*/ 0x04d3, 1, 0x04d2, /* CYRILLIC CAPITAL LETTER A WITH DI.. */
+ /*1210*/ 0x04d5, 1, 0x04d4, /* CYRILLIC CAPITAL LIGATURE A IE */
+ /*1213*/ 0x04d7, 1, 0x04d6, /* CYRILLIC CAPITAL LETTER IE WITH B.. */
+ /*1216*/ 0x04d9, 1, 0x04d8, /* CYRILLIC CAPITAL LETTER SCHWA */
+ /*1219*/ 0x04db, 1, 0x04da, /* CYRILLIC CAPITAL LETTER SCHWA WIT.. */
+ /*1222*/ 0x04dd, 1, 0x04dc, /* CYRILLIC CAPITAL LETTER ZHE WITH .. */
+ /*1225*/ 0x04df, 1, 0x04de, /* CYRILLIC CAPITAL LETTER ZE WITH D.. */
+ /*1228*/ 0x04e1, 1, 0x04e0, /* CYRILLIC CAPITAL LETTER ABKHASIAN.. */
+ /*1231*/ 0x04e3, 1, 0x04e2, /* CYRILLIC CAPITAL LETTER I WITH MA.. */
+ /*1234*/ 0x04e5, 1, 0x04e4, /* CYRILLIC CAPITAL LETTER I WITH DI.. */
+ /*1237*/ 0x04e7, 1, 0x04e6, /* CYRILLIC CAPITAL LETTER O WITH DI.. */
+ /*1240*/ 0x04e9, 1, 0x04e8, /* CYRILLIC CAPITAL LETTER BARRED O */
+ /*1243*/ 0x04eb, 1, 0x04ea, /* CYRILLIC CAPITAL LETTER BARRED O .. */
+ /*1246*/ 0x04ed, 1, 0x04ec, /* CYRILLIC CAPITAL LETTER E WITH DI.. */
+ /*1249*/ 0x04ef, 1, 0x04ee, /* CYRILLIC CAPITAL LETTER U WITH MA.. */
+ /*1252*/ 0x04f1, 1, 0x04f0, /* CYRILLIC CAPITAL LETTER U WITH DI.. */
+ /*1255*/ 0x04f3, 1, 0x04f2, /* CYRILLIC CAPITAL LETTER U WITH DO.. */
+ /*1258*/ 0x04f5, 1, 0x04f4, /* CYRILLIC CAPITAL LETTER CHE WITH .. */
+ /*1261*/ 0x04f7, 1, 0x04f6, /* CYRILLIC CAPITAL LETTER GHE WITH .. */
+ /*1264*/ 0x04f9, 1, 0x04f8, /* CYRILLIC CAPITAL LETTER YERU WITH.. */
+ /*1267*/ 0x04fb, 1, 0x04fa, /* CYRILLIC CAPITAL LETTER GHE WITH .. */
+ /*1270*/ 0x04fd, 1, 0x04fc, /* CYRILLIC CAPITAL LETTER HA WITH H.. */
+ /*1273*/ 0x04ff, 1, 0x04fe, /* CYRILLIC CAPITAL LETTER HA WITH S.. */
+ /*1276*/ 0x0501, 1, 0x0500, /* CYRILLIC CAPITAL LETTER KOMI DE */
+ /*1279*/ 0x0503, 1, 0x0502, /* CYRILLIC CAPITAL LETTER KOMI DJE */
+ /*1282*/ 0x0505, 1, 0x0504, /* CYRILLIC CAPITAL LETTER KOMI ZJE */
+ /*1285*/ 0x0507, 1, 0x0506, /* CYRILLIC CAPITAL LETTER KOMI DZJE */
+ /*1288*/ 0x0509, 1, 0x0508, /* CYRILLIC CAPITAL LETTER KOMI LJE */
+ /*1291*/ 0x050b, 1, 0x050a, /* CYRILLIC CAPITAL LETTER KOMI NJE */
+ /*1294*/ 0x050d, 1, 0x050c, /* CYRILLIC CAPITAL LETTER KOMI SJE */
+ /*1297*/ 0x050f, 1, 0x050e, /* CYRILLIC CAPITAL LETTER KOMI TJE */
+ /*1300*/ 0x0511, 1, 0x0510, /* CYRILLIC CAPITAL LETTER REVERSED .. */
+ /*1303*/ 0x0513, 1, 0x0512, /* CYRILLIC CAPITAL LETTER EL WITH H.. */
+ /*1306*/ 0x0515, 1, 0x0514, /* CYRILLIC CAPITAL LETTER LHA */
+ /*1309*/ 0x0517, 1, 0x0516, /* CYRILLIC CAPITAL LETTER RHA */
+ /*1312*/ 0x0519, 1, 0x0518, /* CYRILLIC CAPITAL LETTER YAE */
+ /*1315*/ 0x051b, 1, 0x051a, /* CYRILLIC CAPITAL LETTER QA */
+ /*1318*/ 0x051d, 1, 0x051c, /* CYRILLIC CAPITAL LETTER WE */
+ /*1321*/ 0x051f, 1, 0x051e, /* CYRILLIC CAPITAL LETTER ALEUT KA */
+ /*1324*/ 0x0521, 1, 0x0520, /* CYRILLIC CAPITAL LETTER EL WITH M.. */
+ /*1327*/ 0x0523, 1, 0x0522, /* CYRILLIC CAPITAL LETTER EN WITH M.. */
+ /*1330*/ 0x0525, 1, 0x0524, /* CYRILLIC CAPITAL LETTER PE WITH D.. */
+ /*1333*/ 0x0527, 1, 0x0526, /* CYRILLIC CAPITAL LETTER SHHA WITH.. */
+ /*1336*/ 0x0529, 1, 0x0528, /* CYRILLIC CAPITAL LETTER EN WITH L.. */
+ /*1339*/ 0x052b, 1, 0x052a, /* CYRILLIC CAPITAL LETTER DZZHE */
+ /*1342*/ 0x052d, 1, 0x052c, /* CYRILLIC CAPITAL LETTER DCHE */
+ /*1345*/ 0x052f, 1, 0x052e, /* CYRILLIC CAPITAL LETTER EL WITH D.. */
+ /*1348*/ 0x0561, 1, 0x0531, /* ARMENIAN CAPITAL LETTER AYB */
+ /*1351*/ 0x0562, 1, 0x0532, /* ARMENIAN CAPITAL LETTER BEN */
+ /*1354*/ 0x0563, 1, 0x0533, /* ARMENIAN CAPITAL LETTER GIM */
+ /*1357*/ 0x0564, 1, 0x0534, /* ARMENIAN CAPITAL LETTER DA */
+ /*1360*/ 0x0565, 1, 0x0535, /* ARMENIAN CAPITAL LETTER ECH */
+ /*1363*/ 0x0566, 1, 0x0536, /* ARMENIAN CAPITAL LETTER ZA */
+ /*1366*/ 0x0567, 1, 0x0537, /* ARMENIAN CAPITAL LETTER EH */
+ /*1369*/ 0x0568, 1, 0x0538, /* ARMENIAN CAPITAL LETTER ET */
+ /*1372*/ 0x0569, 1, 0x0539, /* ARMENIAN CAPITAL LETTER TO */
+ /*1375*/ 0x056a, 1, 0x053a, /* ARMENIAN CAPITAL LETTER ZHE */
+ /*1378*/ 0x056b, 1, 0x053b, /* ARMENIAN CAPITAL LETTER INI */
+ /*1381*/ 0x056c, 1, 0x053c, /* ARMENIAN CAPITAL LETTER LIWN */
+ /*1384*/ 0x056d, 1, 0x053d, /* ARMENIAN CAPITAL LETTER XEH */
+ /*1387*/ 0x056e, 1, 0x053e, /* ARMENIAN CAPITAL LETTER CA */
+ /*1390*/ 0x056f, 1, 0x053f, /* ARMENIAN CAPITAL LETTER KEN */
+ /*1393*/ 0x0570, 1, 0x0540, /* ARMENIAN CAPITAL LETTER HO */
+ /*1396*/ 0x0571, 1, 0x0541, /* ARMENIAN CAPITAL LETTER JA */
+ /*1399*/ 0x0572, 1, 0x0542, /* ARMENIAN CAPITAL LETTER GHAD */
+ /*1402*/ 0x0573, 1, 0x0543, /* ARMENIAN CAPITAL LETTER CHEH */
+ /*1405*/ 0x0574, 1, 0x0544, /* ARMENIAN CAPITAL LETTER MEN */
+ /*1408*/ 0x0575, 1, 0x0545, /* ARMENIAN CAPITAL LETTER YI */
+ /*1411*/ 0x0576, 1, 0x0546, /* ARMENIAN CAPITAL LETTER NOW */
+ /*1414*/ 0x0577, 1, 0x0547, /* ARMENIAN CAPITAL LETTER SHA */
+ /*1417*/ 0x0578, 1, 0x0548, /* ARMENIAN CAPITAL LETTER VO */
+ /*1420*/ 0x0579, 1, 0x0549, /* ARMENIAN CAPITAL LETTER CHA */
+ /*1423*/ 0x057a, 1, 0x054a, /* ARMENIAN CAPITAL LETTER PEH */
+ /*1426*/ 0x057b, 1, 0x054b, /* ARMENIAN CAPITAL LETTER JHEH */
+ /*1429*/ 0x057c, 1, 0x054c, /* ARMENIAN CAPITAL LETTER RA */
+ /*1432*/ 0x057d, 1, 0x054d, /* ARMENIAN CAPITAL LETTER SEH */
+ /*1435*/ 0x057e, 1, 0x054e, /* ARMENIAN CAPITAL LETTER VEW */
+ /*1438*/ 0x057f, 1, 0x054f, /* ARMENIAN CAPITAL LETTER TIWN */
+ /*1441*/ 0x0580, 1, 0x0550, /* ARMENIAN CAPITAL LETTER REH */
+ /*1444*/ 0x0581, 1, 0x0551, /* ARMENIAN CAPITAL LETTER CO */
+ /*1447*/ 0x0582, 1, 0x0552, /* ARMENIAN CAPITAL LETTER YIWN */
+ /*1450*/ 0x0583, 1, 0x0553, /* ARMENIAN CAPITAL LETTER PIWR */
+ /*1453*/ 0x0584, 1, 0x0554, /* ARMENIAN CAPITAL LETTER KEH */
+ /*1456*/ 0x0585, 1, 0x0555, /* ARMENIAN CAPITAL LETTER OH */
+ /*1459*/ 0x0586, 1, 0x0556, /* ARMENIAN CAPITAL LETTER FEH */
+ /*1462*/ 0x10d0, 1, 0x1c90, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1465*/ 0x10d1, 1, 0x1c91, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1468*/ 0x10d2, 1, 0x1c92, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1471*/ 0x10d3, 1, 0x1c93, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1474*/ 0x10d4, 1, 0x1c94, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1477*/ 0x10d5, 1, 0x1c95, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1480*/ 0x10d6, 1, 0x1c96, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1483*/ 0x10d7, 1, 0x1c97, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1486*/ 0x10d8, 1, 0x1c98, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1489*/ 0x10d9, 1, 0x1c99, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1492*/ 0x10da, 1, 0x1c9a, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1495*/ 0x10db, 1, 0x1c9b, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1498*/ 0x10dc, 1, 0x1c9c, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1501*/ 0x10dd, 1, 0x1c9d, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1504*/ 0x10de, 1, 0x1c9e, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1507*/ 0x10df, 1, 0x1c9f, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1510*/ 0x10e0, 1, 0x1ca0, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1513*/ 0x10e1, 1, 0x1ca1, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1516*/ 0x10e2, 1, 0x1ca2, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1519*/ 0x10e3, 1, 0x1ca3, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1522*/ 0x10e4, 1, 0x1ca4, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1525*/ 0x10e5, 1, 0x1ca5, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1528*/ 0x10e6, 1, 0x1ca6, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1531*/ 0x10e7, 1, 0x1ca7, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1534*/ 0x10e8, 1, 0x1ca8, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1537*/ 0x10e9, 1, 0x1ca9, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1540*/ 0x10ea, 1, 0x1caa, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1543*/ 0x10eb, 1, 0x1cab, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1546*/ 0x10ec, 1, 0x1cac, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1549*/ 0x10ed, 1, 0x1cad, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1552*/ 0x10ee, 1, 0x1cae, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1555*/ 0x10ef, 1, 0x1caf, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1558*/ 0x10f0, 1, 0x1cb0, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1561*/ 0x10f1, 1, 0x1cb1, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1564*/ 0x10f2, 1, 0x1cb2, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1567*/ 0x10f3, 1, 0x1cb3, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1570*/ 0x10f4, 1, 0x1cb4, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1573*/ 0x10f5, 1, 0x1cb5, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1576*/ 0x10f6, 1, 0x1cb6, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1579*/ 0x10f7, 1, 0x1cb7, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1582*/ 0x10f8, 1, 0x1cb8, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1585*/ 0x10f9, 1, 0x1cb9, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1588*/ 0x10fa, 1, 0x1cba, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1591*/ 0x10fd, 1, 0x1cbd, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1594*/ 0x10fe, 1, 0x1cbe, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1597*/ 0x10ff, 1, 0x1cbf, /* GEORGIAN MTAVRULI CAPITAL LETTER .. */
+ /*1600*/ 0x13a0, 1, 0xab70, /* CHEROKEE SMALL LETTER A */
+ /*1603*/ 0x13a1, 1, 0xab71, /* CHEROKEE SMALL LETTER E */
+ /*1606*/ 0x13a2, 1, 0xab72, /* CHEROKEE SMALL LETTER I */
+ /*1609*/ 0x13a3, 1, 0xab73, /* CHEROKEE SMALL LETTER O */
+ /*1612*/ 0x13a4, 1, 0xab74, /* CHEROKEE SMALL LETTER U */
+ /*1615*/ 0x13a5, 1, 0xab75, /* CHEROKEE SMALL LETTER V */
+ /*1618*/ 0x13a6, 1, 0xab76, /* CHEROKEE SMALL LETTER GA */
+ /*1621*/ 0x13a7, 1, 0xab77, /* CHEROKEE SMALL LETTER KA */
+ /*1624*/ 0x13a8, 1, 0xab78, /* CHEROKEE SMALL LETTER GE */
+ /*1627*/ 0x13a9, 1, 0xab79, /* CHEROKEE SMALL LETTER GI */
+ /*1630*/ 0x13aa, 1, 0xab7a, /* CHEROKEE SMALL LETTER GO */
+ /*1633*/ 0x13ab, 1, 0xab7b, /* CHEROKEE SMALL LETTER GU */
+ /*1636*/ 0x13ac, 1, 0xab7c, /* CHEROKEE SMALL LETTER GV */
+ /*1639*/ 0x13ad, 1, 0xab7d, /* CHEROKEE SMALL LETTER HA */
+ /*1642*/ 0x13ae, 1, 0xab7e, /* CHEROKEE SMALL LETTER HE */
+ /*1645*/ 0x13af, 1, 0xab7f, /* CHEROKEE SMALL LETTER HI */
+ /*1648*/ 0x13b0, 1, 0xab80, /* CHEROKEE SMALL LETTER HO */
+ /*1651*/ 0x13b1, 1, 0xab81, /* CHEROKEE SMALL LETTER HU */
+ /*1654*/ 0x13b2, 1, 0xab82, /* CHEROKEE SMALL LETTER HV */
+ /*1657*/ 0x13b3, 1, 0xab83, /* CHEROKEE SMALL LETTER LA */
+ /*1660*/ 0x13b4, 1, 0xab84, /* CHEROKEE SMALL LETTER LE */
+ /*1663*/ 0x13b5, 1, 0xab85, /* CHEROKEE SMALL LETTER LI */
+ /*1666*/ 0x13b6, 1, 0xab86, /* CHEROKEE SMALL LETTER LO */
+ /*1669*/ 0x13b7, 1, 0xab87, /* CHEROKEE SMALL LETTER LU */
+ /*1672*/ 0x13b8, 1, 0xab88, /* CHEROKEE SMALL LETTER LV */
+ /*1675*/ 0x13b9, 1, 0xab89, /* CHEROKEE SMALL LETTER MA */
+ /*1678*/ 0x13ba, 1, 0xab8a, /* CHEROKEE SMALL LETTER ME */
+ /*1681*/ 0x13bb, 1, 0xab8b, /* CHEROKEE SMALL LETTER MI */
+ /*1684*/ 0x13bc, 1, 0xab8c, /* CHEROKEE SMALL LETTER MO */
+ /*1687*/ 0x13bd, 1, 0xab8d, /* CHEROKEE SMALL LETTER MU */
+ /*1690*/ 0x13be, 1, 0xab8e, /* CHEROKEE SMALL LETTER NA */
+ /*1693*/ 0x13bf, 1, 0xab8f, /* CHEROKEE SMALL LETTER HNA */
+ /*1696*/ 0x13c0, 1, 0xab90, /* CHEROKEE SMALL LETTER NAH */
+ /*1699*/ 0x13c1, 1, 0xab91, /* CHEROKEE SMALL LETTER NE */
+ /*1702*/ 0x13c2, 1, 0xab92, /* CHEROKEE SMALL LETTER NI */
+ /*1705*/ 0x13c3, 1, 0xab93, /* CHEROKEE SMALL LETTER NO */
+ /*1708*/ 0x13c4, 1, 0xab94, /* CHEROKEE SMALL LETTER NU */
+ /*1711*/ 0x13c5, 1, 0xab95, /* CHEROKEE SMALL LETTER NV */
+ /*1714*/ 0x13c6, 1, 0xab96, /* CHEROKEE SMALL LETTER QUA */
+ /*1717*/ 0x13c7, 1, 0xab97, /* CHEROKEE SMALL LETTER QUE */
+ /*1720*/ 0x13c8, 1, 0xab98, /* CHEROKEE SMALL LETTER QUI */
+ /*1723*/ 0x13c9, 1, 0xab99, /* CHEROKEE SMALL LETTER QUO */
+ /*1726*/ 0x13ca, 1, 0xab9a, /* CHEROKEE SMALL LETTER QUU */
+ /*1729*/ 0x13cb, 1, 0xab9b, /* CHEROKEE SMALL LETTER QUV */
+ /*1732*/ 0x13cc, 1, 0xab9c, /* CHEROKEE SMALL LETTER SA */
+ /*1735*/ 0x13cd, 1, 0xab9d, /* CHEROKEE SMALL LETTER S */
+ /*1738*/ 0x13ce, 1, 0xab9e, /* CHEROKEE SMALL LETTER SE */
+ /*1741*/ 0x13cf, 1, 0xab9f, /* CHEROKEE SMALL LETTER SI */
+ /*1744*/ 0x13d0, 1, 0xaba0, /* CHEROKEE SMALL LETTER SO */
+ /*1747*/ 0x13d1, 1, 0xaba1, /* CHEROKEE SMALL LETTER SU */
+ /*1750*/ 0x13d2, 1, 0xaba2, /* CHEROKEE SMALL LETTER SV */
+ /*1753*/ 0x13d3, 1, 0xaba3, /* CHEROKEE SMALL LETTER DA */
+ /*1756*/ 0x13d4, 1, 0xaba4, /* CHEROKEE SMALL LETTER TA */
+ /*1759*/ 0x13d5, 1, 0xaba5, /* CHEROKEE SMALL LETTER DE */
+ /*1762*/ 0x13d6, 1, 0xaba6, /* CHEROKEE SMALL LETTER TE */
+ /*1765*/ 0x13d7, 1, 0xaba7, /* CHEROKEE SMALL LETTER DI */
+ /*1768*/ 0x13d8, 1, 0xaba8, /* CHEROKEE SMALL LETTER TI */
+ /*1771*/ 0x13d9, 1, 0xaba9, /* CHEROKEE SMALL LETTER DO */
+ /*1774*/ 0x13da, 1, 0xabaa, /* CHEROKEE SMALL LETTER DU */
+ /*1777*/ 0x13db, 1, 0xabab, /* CHEROKEE SMALL LETTER DV */
+ /*1780*/ 0x13dc, 1, 0xabac, /* CHEROKEE SMALL LETTER DLA */
+ /*1783*/ 0x13dd, 1, 0xabad, /* CHEROKEE SMALL LETTER TLA */
+ /*1786*/ 0x13de, 1, 0xabae, /* CHEROKEE SMALL LETTER TLE */
+ /*1789*/ 0x13df, 1, 0xabaf, /* CHEROKEE SMALL LETTER TLI */
+ /*1792*/ 0x13e0, 1, 0xabb0, /* CHEROKEE SMALL LETTER TLO */
+ /*1795*/ 0x13e1, 1, 0xabb1, /* CHEROKEE SMALL LETTER TLU */
+ /*1798*/ 0x13e2, 1, 0xabb2, /* CHEROKEE SMALL LETTER TLV */
+ /*1801*/ 0x13e3, 1, 0xabb3, /* CHEROKEE SMALL LETTER TSA */
+ /*1804*/ 0x13e4, 1, 0xabb4, /* CHEROKEE SMALL LETTER TSE */
+ /*1807*/ 0x13e5, 1, 0xabb5, /* CHEROKEE SMALL LETTER TSI */
+ /*1810*/ 0x13e6, 1, 0xabb6, /* CHEROKEE SMALL LETTER TSO */
+ /*1813*/ 0x13e7, 1, 0xabb7, /* CHEROKEE SMALL LETTER TSU */
+ /*1816*/ 0x13e8, 1, 0xabb8, /* CHEROKEE SMALL LETTER TSV */
+ /*1819*/ 0x13e9, 1, 0xabb9, /* CHEROKEE SMALL LETTER WA */
+ /*1822*/ 0x13ea, 1, 0xabba, /* CHEROKEE SMALL LETTER WE */
+ /*1825*/ 0x13eb, 1, 0xabbb, /* CHEROKEE SMALL LETTER WI */
+ /*1828*/ 0x13ec, 1, 0xabbc, /* CHEROKEE SMALL LETTER WO */
+ /*1831*/ 0x13ed, 1, 0xabbd, /* CHEROKEE SMALL LETTER WU */
+ /*1834*/ 0x13ee, 1, 0xabbe, /* CHEROKEE SMALL LETTER WV */
+ /*1837*/ 0x13ef, 1, 0xabbf, /* CHEROKEE SMALL LETTER YA */
+ /*1840*/ 0x13f0, 1, 0x13f8, /* CHEROKEE SMALL LETTER YE */
+ /*1843*/ 0x13f1, 1, 0x13f9, /* CHEROKEE SMALL LETTER YI */
+ /*1846*/ 0x13f2, 1, 0x13fa, /* CHEROKEE SMALL LETTER YO */
+ /*1849*/ 0x13f3, 1, 0x13fb, /* CHEROKEE SMALL LETTER YU */
+ /*1852*/ 0x13f4, 1, 0x13fc, /* CHEROKEE SMALL LETTER YV */
+ /*1855*/ 0x13f5, 1, 0x13fd, /* CHEROKEE SMALL LETTER MV */
+ /*1858*/ 0x1d79, 1, 0xa77d, /* LATIN CAPITAL LETTER INSULAR G */
+ /*1861*/ 0x1d7d, 1, 0x2c63, /* LATIN CAPITAL LETTER P WITH STROKE */
+ /*1864*/ 0x1d8e, 1, 0xa7c6, /* LATIN CAPITAL LETTER Z WITH PALAT.. */
+ /*1867*/ 0x1e01, 1, 0x1e00, /* LATIN CAPITAL LETTER A WITH RING .. */
+ /*1870*/ 0x1e03, 1, 0x1e02, /* LATIN CAPITAL LETTER B WITH DOT A.. */
+ /*1873*/ 0x1e05, 1, 0x1e04, /* LATIN CAPITAL LETTER B WITH DOT B.. */
+ /*1876*/ 0x1e07, 1, 0x1e06, /* LATIN CAPITAL LETTER B WITH LINE .. */
+ /*1879*/ 0x1e09, 1, 0x1e08, /* LATIN CAPITAL LETTER C WITH CEDIL.. */
+ /*1882*/ 0x1e0b, 1, 0x1e0a, /* LATIN CAPITAL LETTER D WITH DOT A.. */
+ /*1885*/ 0x1e0d, 1, 0x1e0c, /* LATIN CAPITAL LETTER D WITH DOT B.. */
+ /*1888*/ 0x1e0f, 1, 0x1e0e, /* LATIN CAPITAL LETTER D WITH LINE .. */
+ /*1891*/ 0x1e11, 1, 0x1e10, /* LATIN CAPITAL LETTER D WITH CEDIL.. */
+ /*1894*/ 0x1e13, 1, 0x1e12, /* LATIN CAPITAL LETTER D WITH CIRCU.. */
+ /*1897*/ 0x1e15, 1, 0x1e14, /* LATIN CAPITAL LETTER E WITH MACRO.. */
+ /*1900*/ 0x1e17, 1, 0x1e16, /* LATIN CAPITAL LETTER E WITH MACRO.. */
+ /*1903*/ 0x1e19, 1, 0x1e18, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*1906*/ 0x1e1b, 1, 0x1e1a, /* LATIN CAPITAL LETTER E WITH TILDE.. */
+ /*1909*/ 0x1e1d, 1, 0x1e1c, /* LATIN CAPITAL LETTER E WITH CEDIL.. */
+ /*1912*/ 0x1e1f, 1, 0x1e1e, /* LATIN CAPITAL LETTER F WITH DOT A.. */
+ /*1915*/ 0x1e21, 1, 0x1e20, /* LATIN CAPITAL LETTER G WITH MACRON */
+ /*1918*/ 0x1e23, 1, 0x1e22, /* LATIN CAPITAL LETTER H WITH DOT A.. */
+ /*1921*/ 0x1e25, 1, 0x1e24, /* LATIN CAPITAL LETTER H WITH DOT B.. */
+ /*1924*/ 0x1e27, 1, 0x1e26, /* LATIN CAPITAL LETTER H WITH DIAER.. */
+ /*1927*/ 0x1e29, 1, 0x1e28, /* LATIN CAPITAL LETTER H WITH CEDIL.. */
+ /*1930*/ 0x1e2b, 1, 0x1e2a, /* LATIN CAPITAL LETTER H WITH BREVE.. */
+ /*1933*/ 0x1e2d, 1, 0x1e2c, /* LATIN CAPITAL LETTER I WITH TILDE.. */
+ /*1936*/ 0x1e2f, 1, 0x1e2e, /* LATIN CAPITAL LETTER I WITH DIAER.. */
+ /*1939*/ 0x1e31, 1, 0x1e30, /* LATIN CAPITAL LETTER K WITH ACUTE */
+ /*1942*/ 0x1e33, 1, 0x1e32, /* LATIN CAPITAL LETTER K WITH DOT B.. */
+ /*1945*/ 0x1e35, 1, 0x1e34, /* LATIN CAPITAL LETTER K WITH LINE .. */
+ /*1948*/ 0x1e37, 1, 0x1e36, /* LATIN CAPITAL LETTER L WITH DOT B.. */
+ /*1951*/ 0x1e39, 1, 0x1e38, /* LATIN CAPITAL LETTER L WITH DOT B.. */
+ /*1954*/ 0x1e3b, 1, 0x1e3a, /* LATIN CAPITAL LETTER L WITH LINE .. */
+ /*1957*/ 0x1e3d, 1, 0x1e3c, /* LATIN CAPITAL LETTER L WITH CIRCU.. */
+ /*1960*/ 0x1e3f, 1, 0x1e3e, /* LATIN CAPITAL LETTER M WITH ACUTE */
+ /*1963*/ 0x1e41, 1, 0x1e40, /* LATIN CAPITAL LETTER M WITH DOT A.. */
+ /*1966*/ 0x1e43, 1, 0x1e42, /* LATIN CAPITAL LETTER M WITH DOT B.. */
+ /*1969*/ 0x1e45, 1, 0x1e44, /* LATIN CAPITAL LETTER N WITH DOT A.. */
+ /*1972*/ 0x1e47, 1, 0x1e46, /* LATIN CAPITAL LETTER N WITH DOT B.. */
+ /*1975*/ 0x1e49, 1, 0x1e48, /* LATIN CAPITAL LETTER N WITH LINE .. */
+ /*1978*/ 0x1e4b, 1, 0x1e4a, /* LATIN CAPITAL LETTER N WITH CIRCU.. */
+ /*1981*/ 0x1e4d, 1, 0x1e4c, /* LATIN CAPITAL LETTER O WITH TILDE.. */
+ /*1984*/ 0x1e4f, 1, 0x1e4e, /* LATIN CAPITAL LETTER O WITH TILDE.. */
+ /*1987*/ 0x1e51, 1, 0x1e50, /* LATIN CAPITAL LETTER O WITH MACRO.. */
+ /*1990*/ 0x1e53, 1, 0x1e52, /* LATIN CAPITAL LETTER O WITH MACRO.. */
+ /*1993*/ 0x1e55, 1, 0x1e54, /* LATIN CAPITAL LETTER P WITH ACUTE */
+ /*1996*/ 0x1e57, 1, 0x1e56, /* LATIN CAPITAL LETTER P WITH DOT A.. */
+ /*1999*/ 0x1e59, 1, 0x1e58, /* LATIN CAPITAL LETTER R WITH DOT A.. */
+ /*2002*/ 0x1e5b, 1, 0x1e5a, /* LATIN CAPITAL LETTER R WITH DOT B.. */
+ /*2005*/ 0x1e5d, 1, 0x1e5c, /* LATIN CAPITAL LETTER R WITH DOT B.. */
+ /*2008*/ 0x1e5f, 1, 0x1e5e, /* LATIN CAPITAL LETTER R WITH LINE .. */
+ /*2011*/ 0x1e61, 2, 0x1e60, 0x1e9b, /* LATIN CAPITAL LETTER S WITH DOT A.. */
+ /*2015*/ 0x1e63, 1, 0x1e62, /* LATIN CAPITAL LETTER S WITH DOT B.. */
+ /*2018*/ 0x1e65, 1, 0x1e64, /* LATIN CAPITAL LETTER S WITH ACUTE.. */
+ /*2021*/ 0x1e67, 1, 0x1e66, /* LATIN CAPITAL LETTER S WITH CARON.. */
+ /*2024*/ 0x1e69, 1, 0x1e68, /* LATIN CAPITAL LETTER S WITH DOT B.. */
+ /*2027*/ 0x1e6b, 1, 0x1e6a, /* LATIN CAPITAL LETTER T WITH DOT A.. */
+ /*2030*/ 0x1e6d, 1, 0x1e6c, /* LATIN CAPITAL LETTER T WITH DOT B.. */
+ /*2033*/ 0x1e6f, 1, 0x1e6e, /* LATIN CAPITAL LETTER T WITH LINE .. */
+ /*2036*/ 0x1e71, 1, 0x1e70, /* LATIN CAPITAL LETTER T WITH CIRCU.. */
+ /*2039*/ 0x1e73, 1, 0x1e72, /* LATIN CAPITAL LETTER U WITH DIAER.. */
+ /*2042*/ 0x1e75, 1, 0x1e74, /* LATIN CAPITAL LETTER U WITH TILDE.. */
+ /*2045*/ 0x1e77, 1, 0x1e76, /* LATIN CAPITAL LETTER U WITH CIRCU.. */
+ /*2048*/ 0x1e79, 1, 0x1e78, /* LATIN CAPITAL LETTER U WITH TILDE.. */
+ /*2051*/ 0x1e7b, 1, 0x1e7a, /* LATIN CAPITAL LETTER U WITH MACRO.. */
+ /*2054*/ 0x1e7d, 1, 0x1e7c, /* LATIN CAPITAL LETTER V WITH TILDE */
+ /*2057*/ 0x1e7f, 1, 0x1e7e, /* LATIN CAPITAL LETTER V WITH DOT B.. */
+ /*2060*/ 0x1e81, 1, 0x1e80, /* LATIN CAPITAL LETTER W WITH GRAVE */
+ /*2063*/ 0x1e83, 1, 0x1e82, /* LATIN CAPITAL LETTER W WITH ACUTE */
+ /*2066*/ 0x1e85, 1, 0x1e84, /* LATIN CAPITAL LETTER W WITH DIAER.. */
+ /*2069*/ 0x1e87, 1, 0x1e86, /* LATIN CAPITAL LETTER W WITH DOT A.. */
+ /*2072*/ 0x1e89, 1, 0x1e88, /* LATIN CAPITAL LETTER W WITH DOT B.. */
+ /*2075*/ 0x1e8b, 1, 0x1e8a, /* LATIN CAPITAL LETTER X WITH DOT A.. */
+ /*2078*/ 0x1e8d, 1, 0x1e8c, /* LATIN CAPITAL LETTER X WITH DIAER.. */
+ /*2081*/ 0x1e8f, 1, 0x1e8e, /* LATIN CAPITAL LETTER Y WITH DOT A.. */
+ /*2084*/ 0x1e91, 1, 0x1e90, /* LATIN CAPITAL LETTER Z WITH CIRCU.. */
+ /*2087*/ 0x1e93, 1, 0x1e92, /* LATIN CAPITAL LETTER Z WITH DOT B.. */
+ /*2090*/ 0x1e95, 1, 0x1e94, /* LATIN CAPITAL LETTER Z WITH LINE .. */
+ /*2093*/ 0x1ea1, 1, 0x1ea0, /* LATIN CAPITAL LETTER A WITH DOT B.. */
+ /*2096*/ 0x1ea3, 1, 0x1ea2, /* LATIN CAPITAL LETTER A WITH HOOK .. */
+ /*2099*/ 0x1ea5, 1, 0x1ea4, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /*2102*/ 0x1ea7, 1, 0x1ea6, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /*2105*/ 0x1ea9, 1, 0x1ea8, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /*2108*/ 0x1eab, 1, 0x1eaa, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /*2111*/ 0x1ead, 1, 0x1eac, /* LATIN CAPITAL LETTER A WITH CIRCU.. */
+ /*2114*/ 0x1eaf, 1, 0x1eae, /* LATIN CAPITAL LETTER A WITH BREVE.. */
+ /*2117*/ 0x1eb1, 1, 0x1eb0, /* LATIN CAPITAL LETTER A WITH BREVE.. */
+ /*2120*/ 0x1eb3, 1, 0x1eb2, /* LATIN CAPITAL LETTER A WITH BREVE.. */
+ /*2123*/ 0x1eb5, 1, 0x1eb4, /* LATIN CAPITAL LETTER A WITH BREVE.. */
+ /*2126*/ 0x1eb7, 1, 0x1eb6, /* LATIN CAPITAL LETTER A WITH BREVE.. */
+ /*2129*/ 0x1eb9, 1, 0x1eb8, /* LATIN CAPITAL LETTER E WITH DOT B.. */
+ /*2132*/ 0x1ebb, 1, 0x1eba, /* LATIN CAPITAL LETTER E WITH HOOK .. */
+ /*2135*/ 0x1ebd, 1, 0x1ebc, /* LATIN CAPITAL LETTER E WITH TILDE */
+ /*2138*/ 0x1ebf, 1, 0x1ebe, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*2141*/ 0x1ec1, 1, 0x1ec0, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*2144*/ 0x1ec3, 1, 0x1ec2, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*2147*/ 0x1ec5, 1, 0x1ec4, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*2150*/ 0x1ec7, 1, 0x1ec6, /* LATIN CAPITAL LETTER E WITH CIRCU.. */
+ /*2153*/ 0x1ec9, 1, 0x1ec8, /* LATIN CAPITAL LETTER I WITH HOOK .. */
+ /*2156*/ 0x1ecb, 1, 0x1eca, /* LATIN CAPITAL LETTER I WITH DOT B.. */
+ /*2159*/ 0x1ecd, 1, 0x1ecc, /* LATIN CAPITAL LETTER O WITH DOT B.. */
+ /*2162*/ 0x1ecf, 1, 0x1ece, /* LATIN CAPITAL LETTER O WITH HOOK .. */
+ /*2165*/ 0x1ed1, 1, 0x1ed0, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /*2168*/ 0x1ed3, 1, 0x1ed2, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /*2171*/ 0x1ed5, 1, 0x1ed4, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /*2174*/ 0x1ed7, 1, 0x1ed6, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /*2177*/ 0x1ed9, 1, 0x1ed8, /* LATIN CAPITAL LETTER O WITH CIRCU.. */
+ /*2180*/ 0x1edb, 1, 0x1eda, /* LATIN CAPITAL LETTER O WITH HORN .. */
+ /*2183*/ 0x1edd, 1, 0x1edc, /* LATIN CAPITAL LETTER O WITH HORN .. */
+ /*2186*/ 0x1edf, 1, 0x1ede, /* LATIN CAPITAL LETTER O WITH HORN .. */
+ /*2189*/ 0x1ee1, 1, 0x1ee0, /* LATIN CAPITAL LETTER O WITH HORN .. */
+ /*2192*/ 0x1ee3, 1, 0x1ee2, /* LATIN CAPITAL LETTER O WITH HORN .. */
+ /*2195*/ 0x1ee5, 1, 0x1ee4, /* LATIN CAPITAL LETTER U WITH DOT B.. */
+ /*2198*/ 0x1ee7, 1, 0x1ee6, /* LATIN CAPITAL LETTER U WITH HOOK .. */
+ /*2201*/ 0x1ee9, 1, 0x1ee8, /* LATIN CAPITAL LETTER U WITH HORN .. */
+ /*2204*/ 0x1eeb, 1, 0x1eea, /* LATIN CAPITAL LETTER U WITH HORN .. */
+ /*2207*/ 0x1eed, 1, 0x1eec, /* LATIN CAPITAL LETTER U WITH HORN .. */
+ /*2210*/ 0x1eef, 1, 0x1eee, /* LATIN CAPITAL LETTER U WITH HORN .. */
+ /*2213*/ 0x1ef1, 1, 0x1ef0, /* LATIN CAPITAL LETTER U WITH HORN .. */
+ /*2216*/ 0x1ef3, 1, 0x1ef2, /* LATIN CAPITAL LETTER Y WITH GRAVE */
+ /*2219*/ 0x1ef5, 1, 0x1ef4, /* LATIN CAPITAL LETTER Y WITH DOT B.. */
+ /*2222*/ 0x1ef7, 1, 0x1ef6, /* LATIN CAPITAL LETTER Y WITH HOOK .. */
+ /*2225*/ 0x1ef9, 1, 0x1ef8, /* LATIN CAPITAL LETTER Y WITH TILDE */
+ /*2228*/ 0x1efb, 1, 0x1efa, /* LATIN CAPITAL LETTER MIDDLE-WELSH.. */
+ /*2231*/ 0x1efd, 1, 0x1efc, /* LATIN CAPITAL LETTER MIDDLE-WELSH.. */
+ /*2234*/ 0x1eff, 1, 0x1efe, /* LATIN CAPITAL LETTER Y WITH LOOP */
+ /*2237*/ 0x1f00, 1, 0x1f08, /* GREEK CAPITAL LETTER ALPHA WITH P.. */
+ /*2240*/ 0x1f01, 1, 0x1f09, /* GREEK CAPITAL LETTER ALPHA WITH D.. */
+ /*2243*/ 0x1f02, 1, 0x1f0a, /* GREEK CAPITAL LETTER ALPHA WITH P.. */
+ /*2246*/ 0x1f03, 1, 0x1f0b, /* GREEK CAPITAL LETTER ALPHA WITH D.. */
+ /*2249*/ 0x1f04, 1, 0x1f0c, /* GREEK CAPITAL LETTER ALPHA WITH P.. */
+ /*2252*/ 0x1f05, 1, 0x1f0d, /* GREEK CAPITAL LETTER ALPHA WITH D.. */
+ /*2255*/ 0x1f06, 1, 0x1f0e, /* GREEK CAPITAL LETTER ALPHA WITH P.. */
+ /*2258*/ 0x1f07, 1, 0x1f0f, /* GREEK CAPITAL LETTER ALPHA WITH D.. */
+ /*2261*/ 0x1f10, 1, 0x1f18, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2264*/ 0x1f11, 1, 0x1f19, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2267*/ 0x1f12, 1, 0x1f1a, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2270*/ 0x1f13, 1, 0x1f1b, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2273*/ 0x1f14, 1, 0x1f1c, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2276*/ 0x1f15, 1, 0x1f1d, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2279*/ 0x1f20, 1, 0x1f28, /* GREEK CAPITAL LETTER ETA WITH PSI.. */
+ /*2282*/ 0x1f21, 1, 0x1f29, /* GREEK CAPITAL LETTER ETA WITH DAS.. */
+ /*2285*/ 0x1f22, 1, 0x1f2a, /* GREEK CAPITAL LETTER ETA WITH PSI.. */
+ /*2288*/ 0x1f23, 1, 0x1f2b, /* GREEK CAPITAL LETTER ETA WITH DAS.. */
+ /*2291*/ 0x1f24, 1, 0x1f2c, /* GREEK CAPITAL LETTER ETA WITH PSI.. */
+ /*2294*/ 0x1f25, 1, 0x1f2d, /* GREEK CAPITAL LETTER ETA WITH DAS.. */
+ /*2297*/ 0x1f26, 1, 0x1f2e, /* GREEK CAPITAL LETTER ETA WITH PSI.. */
+ /*2300*/ 0x1f27, 1, 0x1f2f, /* GREEK CAPITAL LETTER ETA WITH DAS.. */
+ /*2303*/ 0x1f30, 1, 0x1f38, /* GREEK CAPITAL LETTER IOTA WITH PS.. */
+ /*2306*/ 0x1f31, 1, 0x1f39, /* GREEK CAPITAL LETTER IOTA WITH DA.. */
+ /*2309*/ 0x1f32, 1, 0x1f3a, /* GREEK CAPITAL LETTER IOTA WITH PS.. */
+ /*2312*/ 0x1f33, 1, 0x1f3b, /* GREEK CAPITAL LETTER IOTA WITH DA.. */
+ /*2315*/ 0x1f34, 1, 0x1f3c, /* GREEK CAPITAL LETTER IOTA WITH PS.. */
+ /*2318*/ 0x1f35, 1, 0x1f3d, /* GREEK CAPITAL LETTER IOTA WITH DA.. */
+ /*2321*/ 0x1f36, 1, 0x1f3e, /* GREEK CAPITAL LETTER IOTA WITH PS.. */
+ /*2324*/ 0x1f37, 1, 0x1f3f, /* GREEK CAPITAL LETTER IOTA WITH DA.. */
+ /*2327*/ 0x1f40, 1, 0x1f48, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2330*/ 0x1f41, 1, 0x1f49, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2333*/ 0x1f42, 1, 0x1f4a, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2336*/ 0x1f43, 1, 0x1f4b, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2339*/ 0x1f44, 1, 0x1f4c, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2342*/ 0x1f45, 1, 0x1f4d, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2345*/ 0x1f51, 1, 0x1f59, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2348*/ 0x1f53, 1, 0x1f5b, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2351*/ 0x1f55, 1, 0x1f5d, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2354*/ 0x1f57, 1, 0x1f5f, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2357*/ 0x1f60, 1, 0x1f68, /* GREEK CAPITAL LETTER OMEGA WITH P.. */
+ /*2360*/ 0x1f61, 1, 0x1f69, /* GREEK CAPITAL LETTER OMEGA WITH D.. */
+ /*2363*/ 0x1f62, 1, 0x1f6a, /* GREEK CAPITAL LETTER OMEGA WITH P.. */
+ /*2366*/ 0x1f63, 1, 0x1f6b, /* GREEK CAPITAL LETTER OMEGA WITH D.. */
+ /*2369*/ 0x1f64, 1, 0x1f6c, /* GREEK CAPITAL LETTER OMEGA WITH P.. */
+ /*2372*/ 0x1f65, 1, 0x1f6d, /* GREEK CAPITAL LETTER OMEGA WITH D.. */
+ /*2375*/ 0x1f66, 1, 0x1f6e, /* GREEK CAPITAL LETTER OMEGA WITH P.. */
+ /*2378*/ 0x1f67, 1, 0x1f6f, /* GREEK CAPITAL LETTER OMEGA WITH D.. */
+ /*2381*/ 0x1f70, 1, 0x1fba, /* GREEK CAPITAL LETTER ALPHA WITH V.. */
+ /*2384*/ 0x1f71, 1, 0x1fbb, /* GREEK CAPITAL LETTER ALPHA WITH O.. */
+ /*2387*/ 0x1f72, 1, 0x1fc8, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2390*/ 0x1f73, 1, 0x1fc9, /* GREEK CAPITAL LETTER EPSILON WITH.. */
+ /*2393*/ 0x1f74, 1, 0x1fca, /* GREEK CAPITAL LETTER ETA WITH VAR.. */
+ /*2396*/ 0x1f75, 1, 0x1fcb, /* GREEK CAPITAL LETTER ETA WITH OXIA */
+ /*2399*/ 0x1f76, 1, 0x1fda, /* GREEK CAPITAL LETTER IOTA WITH VA.. */
+ /*2402*/ 0x1f77, 1, 0x1fdb, /* GREEK CAPITAL LETTER IOTA WITH OX.. */
+ /*2405*/ 0x1f78, 1, 0x1ff8, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2408*/ 0x1f79, 1, 0x1ff9, /* GREEK CAPITAL LETTER OMICRON WITH.. */
+ /*2411*/ 0x1f7a, 1, 0x1fea, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2414*/ 0x1f7b, 1, 0x1feb, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2417*/ 0x1f7c, 1, 0x1ffa, /* GREEK CAPITAL LETTER OMEGA WITH V.. */
+ /*2420*/ 0x1f7d, 1, 0x1ffb, /* GREEK CAPITAL LETTER OMEGA WITH O.. */
+ /*2423*/ 0x1fb0, 1, 0x1fb8, /* GREEK CAPITAL LETTER ALPHA WITH V.. */
+ /*2426*/ 0x1fb1, 1, 0x1fb9, /* GREEK CAPITAL LETTER ALPHA WITH M.. */
+ /*2429*/ 0x1fd0, 1, 0x1fd8, /* GREEK CAPITAL LETTER IOTA WITH VR.. */
+ /*2432*/ 0x1fd1, 1, 0x1fd9, /* GREEK CAPITAL LETTER IOTA WITH MA.. */
+ /*2435*/ 0x1fe0, 1, 0x1fe8, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2438*/ 0x1fe1, 1, 0x1fe9, /* GREEK CAPITAL LETTER UPSILON WITH.. */
+ /*2441*/ 0x1fe5, 1, 0x1fec, /* GREEK CAPITAL LETTER RHO WITH DAS.. */
+ /*2444*/ 0x214e, 1, 0x2132, /* TURNED CAPITAL F */
+ /*2447*/ 0x2170, 1, 0x2160, /* ROMAN NUMERAL ONE */
+ /*2450*/ 0x2171, 1, 0x2161, /* ROMAN NUMERAL TWO */
+ /*2453*/ 0x2172, 1, 0x2162, /* ROMAN NUMERAL THREE */
+ /*2456*/ 0x2173, 1, 0x2163, /* ROMAN NUMERAL FOUR */
+ /*2459*/ 0x2174, 1, 0x2164, /* ROMAN NUMERAL FIVE */
+ /*2462*/ 0x2175, 1, 0x2165, /* ROMAN NUMERAL SIX */
+ /*2465*/ 0x2176, 1, 0x2166, /* ROMAN NUMERAL SEVEN */
+ /*2468*/ 0x2177, 1, 0x2167, /* ROMAN NUMERAL EIGHT */
+ /*2471*/ 0x2178, 1, 0x2168, /* ROMAN NUMERAL NINE */
+ /*2474*/ 0x2179, 1, 0x2169, /* ROMAN NUMERAL TEN */
+ /*2477*/ 0x217a, 1, 0x216a, /* ROMAN NUMERAL ELEVEN */
+ /*2480*/ 0x217b, 1, 0x216b, /* ROMAN NUMERAL TWELVE */
+ /*2483*/ 0x217c, 1, 0x216c, /* ROMAN NUMERAL FIFTY */
+ /*2486*/ 0x217d, 1, 0x216d, /* ROMAN NUMERAL ONE HUNDRED */
+ /*2489*/ 0x217e, 1, 0x216e, /* ROMAN NUMERAL FIVE HUNDRED */
+ /*2492*/ 0x217f, 1, 0x216f, /* ROMAN NUMERAL ONE THOUSAND */
+ /*2495*/ 0x2184, 1, 0x2183, /* ROMAN NUMERAL REVERSED ONE HUNDRED */
+ /*2498*/ 0x24d0, 1, 0x24b6, /* CIRCLED LATIN CAPITAL LETTER A */
+ /*2501*/ 0x24d1, 1, 0x24b7, /* CIRCLED LATIN CAPITAL LETTER B */
+ /*2504*/ 0x24d2, 1, 0x24b8, /* CIRCLED LATIN CAPITAL LETTER C */
+ /*2507*/ 0x24d3, 1, 0x24b9, /* CIRCLED LATIN CAPITAL LETTER D */
+ /*2510*/ 0x24d4, 1, 0x24ba, /* CIRCLED LATIN CAPITAL LETTER E */
+ /*2513*/ 0x24d5, 1, 0x24bb, /* CIRCLED LATIN CAPITAL LETTER F */
+ /*2516*/ 0x24d6, 1, 0x24bc, /* CIRCLED LATIN CAPITAL LETTER G */
+ /*2519*/ 0x24d7, 1, 0x24bd, /* CIRCLED LATIN CAPITAL LETTER H */
+ /*2522*/ 0x24d8, 1, 0x24be, /* CIRCLED LATIN CAPITAL LETTER I */
+ /*2525*/ 0x24d9, 1, 0x24bf, /* CIRCLED LATIN CAPITAL LETTER J */
+ /*2528*/ 0x24da, 1, 0x24c0, /* CIRCLED LATIN CAPITAL LETTER K */
+ /*2531*/ 0x24db, 1, 0x24c1, /* CIRCLED LATIN CAPITAL LETTER L */
+ /*2534*/ 0x24dc, 1, 0x24c2, /* CIRCLED LATIN CAPITAL LETTER M */
+ /*2537*/ 0x24dd, 1, 0x24c3, /* CIRCLED LATIN CAPITAL LETTER N */
+ /*2540*/ 0x24de, 1, 0x24c4, /* CIRCLED LATIN CAPITAL LETTER O */
+ /*2543*/ 0x24df, 1, 0x24c5, /* CIRCLED LATIN CAPITAL LETTER P */
+ /*2546*/ 0x24e0, 1, 0x24c6, /* CIRCLED LATIN CAPITAL LETTER Q */
+ /*2549*/ 0x24e1, 1, 0x24c7, /* CIRCLED LATIN CAPITAL LETTER R */
+ /*2552*/ 0x24e2, 1, 0x24c8, /* CIRCLED LATIN CAPITAL LETTER S */
+ /*2555*/ 0x24e3, 1, 0x24c9, /* CIRCLED LATIN CAPITAL LETTER T */
+ /*2558*/ 0x24e4, 1, 0x24ca, /* CIRCLED LATIN CAPITAL LETTER U */
+ /*2561*/ 0x24e5, 1, 0x24cb, /* CIRCLED LATIN CAPITAL LETTER V */
+ /*2564*/ 0x24e6, 1, 0x24cc, /* CIRCLED LATIN CAPITAL LETTER W */
+ /*2567*/ 0x24e7, 1, 0x24cd, /* CIRCLED LATIN CAPITAL LETTER X */
+ /*2570*/ 0x24e8, 1, 0x24ce, /* CIRCLED LATIN CAPITAL LETTER Y */
+ /*2573*/ 0x24e9, 1, 0x24cf, /* CIRCLED LATIN CAPITAL LETTER Z */
+ /*2576*/ 0x2c30, 1, 0x2c00, /* GLAGOLITIC CAPITAL LETTER AZU */
+ /*2579*/ 0x2c31, 1, 0x2c01, /* GLAGOLITIC CAPITAL LETTER BUKY */
+ /*2582*/ 0x2c32, 1, 0x2c02, /* GLAGOLITIC CAPITAL LETTER VEDE */
+ /*2585*/ 0x2c33, 1, 0x2c03, /* GLAGOLITIC CAPITAL LETTER GLAGOLI */
+ /*2588*/ 0x2c34, 1, 0x2c04, /* GLAGOLITIC CAPITAL LETTER DOBRO */
+ /*2591*/ 0x2c35, 1, 0x2c05, /* GLAGOLITIC CAPITAL LETTER YESTU */
+ /*2594*/ 0x2c36, 1, 0x2c06, /* GLAGOLITIC CAPITAL LETTER ZHIVETE */
+ /*2597*/ 0x2c37, 1, 0x2c07, /* GLAGOLITIC CAPITAL LETTER DZELO */
+ /*2600*/ 0x2c38, 1, 0x2c08, /* GLAGOLITIC CAPITAL LETTER ZEMLJA */
+ /*2603*/ 0x2c39, 1, 0x2c09, /* GLAGOLITIC CAPITAL LETTER IZHE */
+ /*2606*/ 0x2c3a, 1, 0x2c0a, /* GLAGOLITIC CAPITAL LETTER INITIAL.. */
+ /*2609*/ 0x2c3b, 1, 0x2c0b, /* GLAGOLITIC CAPITAL LETTER I */
+ /*2612*/ 0x2c3c, 1, 0x2c0c, /* GLAGOLITIC CAPITAL LETTER DJERVI */
+ /*2615*/ 0x2c3d, 1, 0x2c0d, /* GLAGOLITIC CAPITAL LETTER KAKO */
+ /*2618*/ 0x2c3e, 1, 0x2c0e, /* GLAGOLITIC CAPITAL LETTER LJUDIJE */
+ /*2621*/ 0x2c3f, 1, 0x2c0f, /* GLAGOLITIC CAPITAL LETTER MYSLITE */
+ /*2624*/ 0x2c40, 1, 0x2c10, /* GLAGOLITIC CAPITAL LETTER NASHI */
+ /*2627*/ 0x2c41, 1, 0x2c11, /* GLAGOLITIC CAPITAL LETTER ONU */
+ /*2630*/ 0x2c42, 1, 0x2c12, /* GLAGOLITIC CAPITAL LETTER POKOJI */
+ /*2633*/ 0x2c43, 1, 0x2c13, /* GLAGOLITIC CAPITAL LETTER RITSI */
+ /*2636*/ 0x2c44, 1, 0x2c14, /* GLAGOLITIC CAPITAL LETTER SLOVO */
+ /*2639*/ 0x2c45, 1, 0x2c15, /* GLAGOLITIC CAPITAL LETTER TVRIDO */
+ /*2642*/ 0x2c46, 1, 0x2c16, /* GLAGOLITIC CAPITAL LETTER UKU */
+ /*2645*/ 0x2c47, 1, 0x2c17, /* GLAGOLITIC CAPITAL LETTER FRITU */
+ /*2648*/ 0x2c48, 1, 0x2c18, /* GLAGOLITIC CAPITAL LETTER HERU */
+ /*2651*/ 0x2c49, 1, 0x2c19, /* GLAGOLITIC CAPITAL LETTER OTU */
+ /*2654*/ 0x2c4a, 1, 0x2c1a, /* GLAGOLITIC CAPITAL LETTER PE */
+ /*2657*/ 0x2c4b, 1, 0x2c1b, /* GLAGOLITIC CAPITAL LETTER SHTA */
+ /*2660*/ 0x2c4c, 1, 0x2c1c, /* GLAGOLITIC CAPITAL LETTER TSI */
+ /*2663*/ 0x2c4d, 1, 0x2c1d, /* GLAGOLITIC CAPITAL LETTER CHRIVI */
+ /*2666*/ 0x2c4e, 1, 0x2c1e, /* GLAGOLITIC CAPITAL LETTER SHA */
+ /*2669*/ 0x2c4f, 1, 0x2c1f, /* GLAGOLITIC CAPITAL LETTER YERU */
+ /*2672*/ 0x2c50, 1, 0x2c20, /* GLAGOLITIC CAPITAL LETTER YERI */
+ /*2675*/ 0x2c51, 1, 0x2c21, /* GLAGOLITIC CAPITAL LETTER YATI */
+ /*2678*/ 0x2c52, 1, 0x2c22, /* GLAGOLITIC CAPITAL LETTER SPIDERY.. */
+ /*2681*/ 0x2c53, 1, 0x2c23, /* GLAGOLITIC CAPITAL LETTER YU */
+ /*2684*/ 0x2c54, 1, 0x2c24, /* GLAGOLITIC CAPITAL LETTER SMALL Y.. */
+ /*2687*/ 0x2c55, 1, 0x2c25, /* GLAGOLITIC CAPITAL LETTER SMALL Y.. */
+ /*2690*/ 0x2c56, 1, 0x2c26, /* GLAGOLITIC CAPITAL LETTER YO */
+ /*2693*/ 0x2c57, 1, 0x2c27, /* GLAGOLITIC CAPITAL LETTER IOTATED.. */
+ /*2696*/ 0x2c58, 1, 0x2c28, /* GLAGOLITIC CAPITAL LETTER BIG YUS */
+ /*2699*/ 0x2c59, 1, 0x2c29, /* GLAGOLITIC CAPITAL LETTER IOTATED.. */
+ /*2702*/ 0x2c5a, 1, 0x2c2a, /* GLAGOLITIC CAPITAL LETTER FITA */
+ /*2705*/ 0x2c5b, 1, 0x2c2b, /* GLAGOLITIC CAPITAL LETTER IZHITSA */
+ /*2708*/ 0x2c5c, 1, 0x2c2c, /* GLAGOLITIC CAPITAL LETTER SHTAPIC */
+ /*2711*/ 0x2c5d, 1, 0x2c2d, /* GLAGOLITIC CAPITAL LETTER TROKUTA.. */
+ /*2714*/ 0x2c5e, 1, 0x2c2e, /* GLAGOLITIC CAPITAL LETTER LATINAT.. */
+ /*2717*/ 0x2c61, 1, 0x2c60, /* LATIN CAPITAL LETTER L WITH DOUBL.. */
+ /*2720*/ 0x2c65, 1, 0x023a, /* LATIN CAPITAL LETTER A WITH STROKE */
+ /*2723*/ 0x2c66, 1, 0x023e, /* LATIN CAPITAL LETTER T WITH DIAGO.. */
+ /*2726*/ 0x2c68, 1, 0x2c67, /* LATIN CAPITAL LETTER H WITH DESCE.. */
+ /*2729*/ 0x2c6a, 1, 0x2c69, /* LATIN CAPITAL LETTER K WITH DESCE.. */
+ /*2732*/ 0x2c6c, 1, 0x2c6b, /* LATIN CAPITAL LETTER Z WITH DESCE.. */
+ /*2735*/ 0x2c73, 1, 0x2c72, /* LATIN CAPITAL LETTER W WITH HOOK */
+ /*2738*/ 0x2c76, 1, 0x2c75, /* LATIN CAPITAL LETTER HALF H */
+ /*2741*/ 0x2c81, 1, 0x2c80, /* COPTIC CAPITAL LETTER ALFA */
+ /*2744*/ 0x2c83, 1, 0x2c82, /* COPTIC CAPITAL LETTER VIDA */
+ /*2747*/ 0x2c85, 1, 0x2c84, /* COPTIC CAPITAL LETTER GAMMA */
+ /*2750*/ 0x2c87, 1, 0x2c86, /* COPTIC CAPITAL LETTER DALDA */
+ /*2753*/ 0x2c89, 1, 0x2c88, /* COPTIC CAPITAL LETTER EIE */
+ /*2756*/ 0x2c8b, 1, 0x2c8a, /* COPTIC CAPITAL LETTER SOU */
+ /*2759*/ 0x2c8d, 1, 0x2c8c, /* COPTIC CAPITAL LETTER ZATA */
+ /*2762*/ 0x2c8f, 1, 0x2c8e, /* COPTIC CAPITAL LETTER HATE */
+ /*2765*/ 0x2c91, 1, 0x2c90, /* COPTIC CAPITAL LETTER THETHE */
+ /*2768*/ 0x2c93, 1, 0x2c92, /* COPTIC CAPITAL LETTER IAUDA */
+ /*2771*/ 0x2c95, 1, 0x2c94, /* COPTIC CAPITAL LETTER KAPA */
+ /*2774*/ 0x2c97, 1, 0x2c96, /* COPTIC CAPITAL LETTER LAULA */
+ /*2777*/ 0x2c99, 1, 0x2c98, /* COPTIC CAPITAL LETTER MI */
+ /*2780*/ 0x2c9b, 1, 0x2c9a, /* COPTIC CAPITAL LETTER NI */
+ /*2783*/ 0x2c9d, 1, 0x2c9c, /* COPTIC CAPITAL LETTER KSI */
+ /*2786*/ 0x2c9f, 1, 0x2c9e, /* COPTIC CAPITAL LETTER O */
+ /*2789*/ 0x2ca1, 1, 0x2ca0, /* COPTIC CAPITAL LETTER PI */
+ /*2792*/ 0x2ca3, 1, 0x2ca2, /* COPTIC CAPITAL LETTER RO */
+ /*2795*/ 0x2ca5, 1, 0x2ca4, /* COPTIC CAPITAL LETTER SIMA */
+ /*2798*/ 0x2ca7, 1, 0x2ca6, /* COPTIC CAPITAL LETTER TAU */
+ /*2801*/ 0x2ca9, 1, 0x2ca8, /* COPTIC CAPITAL LETTER UA */
+ /*2804*/ 0x2cab, 1, 0x2caa, /* COPTIC CAPITAL LETTER FI */
+ /*2807*/ 0x2cad, 1, 0x2cac, /* COPTIC CAPITAL LETTER KHI */
+ /*2810*/ 0x2caf, 1, 0x2cae, /* COPTIC CAPITAL LETTER PSI */
+ /*2813*/ 0x2cb1, 1, 0x2cb0, /* COPTIC CAPITAL LETTER OOU */
+ /*2816*/ 0x2cb3, 1, 0x2cb2, /* COPTIC CAPITAL LETTER DIALECT-P A.. */
+ /*2819*/ 0x2cb5, 1, 0x2cb4, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2822*/ 0x2cb7, 1, 0x2cb6, /* COPTIC CAPITAL LETTER CRYPTOGRAMM.. */
+ /*2825*/ 0x2cb9, 1, 0x2cb8, /* COPTIC CAPITAL LETTER DIALECT-P K.. */
+ /*2828*/ 0x2cbb, 1, 0x2cba, /* COPTIC CAPITAL LETTER DIALECT-P NI */
+ /*2831*/ 0x2cbd, 1, 0x2cbc, /* COPTIC CAPITAL LETTER CRYPTOGRAMM.. */
+ /*2834*/ 0x2cbf, 1, 0x2cbe, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2837*/ 0x2cc1, 1, 0x2cc0, /* COPTIC CAPITAL LETTER SAMPI */
+ /*2840*/ 0x2cc3, 1, 0x2cc2, /* COPTIC CAPITAL LETTER CROSSED SHEI */
+ /*2843*/ 0x2cc5, 1, 0x2cc4, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2846*/ 0x2cc7, 1, 0x2cc6, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2849*/ 0x2cc9, 1, 0x2cc8, /* COPTIC CAPITAL LETTER AKHMIMIC KH.. */
+ /*2852*/ 0x2ccb, 1, 0x2cca, /* COPTIC CAPITAL LETTER DIALECT-P H.. */
+ /*2855*/ 0x2ccd, 1, 0x2ccc, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2858*/ 0x2ccf, 1, 0x2cce, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2861*/ 0x2cd1, 1, 0x2cd0, /* COPTIC CAPITAL LETTER L-SHAPED HA */
+ /*2864*/ 0x2cd3, 1, 0x2cd2, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2867*/ 0x2cd5, 1, 0x2cd4, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2870*/ 0x2cd7, 1, 0x2cd6, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2873*/ 0x2cd9, 1, 0x2cd8, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2876*/ 0x2cdb, 1, 0x2cda, /* COPTIC CAPITAL LETTER OLD COPTIC .. */
+ /*2879*/ 0x2cdd, 1, 0x2cdc, /* COPTIC CAPITAL LETTER OLD NUBIAN .. */
+ /*2882*/ 0x2cdf, 1, 0x2cde, /* COPTIC CAPITAL LETTER OLD NUBIAN .. */
+ /*2885*/ 0x2ce1, 1, 0x2ce0, /* COPTIC CAPITAL LETTER OLD NUBIAN .. */
+ /*2888*/ 0x2ce3, 1, 0x2ce2, /* COPTIC CAPITAL LETTER OLD NUBIAN .. */
+ /*2891*/ 0x2cec, 1, 0x2ceb, /* COPTIC CAPITAL LETTER CRYPTOGRAMM.. */
+ /*2894*/ 0x2cee, 1, 0x2ced, /* COPTIC CAPITAL LETTER CRYPTOGRAMM.. */
+ /*2897*/ 0x2cf3, 1, 0x2cf2, /* COPTIC CAPITAL LETTER BOHAIRIC KH.. */
+ /*2900*/ 0x2d00, 1, 0x10a0, /* GEORGIAN CAPITAL LETTER AN */
+ /*2903*/ 0x2d01, 1, 0x10a1, /* GEORGIAN CAPITAL LETTER BAN */
+ /*2906*/ 0x2d02, 1, 0x10a2, /* GEORGIAN CAPITAL LETTER GAN */
+ /*2909*/ 0x2d03, 1, 0x10a3, /* GEORGIAN CAPITAL LETTER DON */
+ /*2912*/ 0x2d04, 1, 0x10a4, /* GEORGIAN CAPITAL LETTER EN */
+ /*2915*/ 0x2d05, 1, 0x10a5, /* GEORGIAN CAPITAL LETTER VIN */
+ /*2918*/ 0x2d06, 1, 0x10a6, /* GEORGIAN CAPITAL LETTER ZEN */
+ /*2921*/ 0x2d07, 1, 0x10a7, /* GEORGIAN CAPITAL LETTER TAN */
+ /*2924*/ 0x2d08, 1, 0x10a8, /* GEORGIAN CAPITAL LETTER IN */
+ /*2927*/ 0x2d09, 1, 0x10a9, /* GEORGIAN CAPITAL LETTER KAN */
+ /*2930*/ 0x2d0a, 1, 0x10aa, /* GEORGIAN CAPITAL LETTER LAS */
+ /*2933*/ 0x2d0b, 1, 0x10ab, /* GEORGIAN CAPITAL LETTER MAN */
+ /*2936*/ 0x2d0c, 1, 0x10ac, /* GEORGIAN CAPITAL LETTER NAR */
+ /*2939*/ 0x2d0d, 1, 0x10ad, /* GEORGIAN CAPITAL LETTER ON */
+ /*2942*/ 0x2d0e, 1, 0x10ae, /* GEORGIAN CAPITAL LETTER PAR */
+ /*2945*/ 0x2d0f, 1, 0x10af, /* GEORGIAN CAPITAL LETTER ZHAR */
+ /*2948*/ 0x2d10, 1, 0x10b0, /* GEORGIAN CAPITAL LETTER RAE */
+ /*2951*/ 0x2d11, 1, 0x10b1, /* GEORGIAN CAPITAL LETTER SAN */
+ /*2954*/ 0x2d12, 1, 0x10b2, /* GEORGIAN CAPITAL LETTER TAR */
+ /*2957*/ 0x2d13, 1, 0x10b3, /* GEORGIAN CAPITAL LETTER UN */
+ /*2960*/ 0x2d14, 1, 0x10b4, /* GEORGIAN CAPITAL LETTER PHAR */
+ /*2963*/ 0x2d15, 1, 0x10b5, /* GEORGIAN CAPITAL LETTER KHAR */
+ /*2966*/ 0x2d16, 1, 0x10b6, /* GEORGIAN CAPITAL LETTER GHAN */
+ /*2969*/ 0x2d17, 1, 0x10b7, /* GEORGIAN CAPITAL LETTER QAR */
+ /*2972*/ 0x2d18, 1, 0x10b8, /* GEORGIAN CAPITAL LETTER SHIN */
+ /*2975*/ 0x2d19, 1, 0x10b9, /* GEORGIAN CAPITAL LETTER CHIN */
+ /*2978*/ 0x2d1a, 1, 0x10ba, /* GEORGIAN CAPITAL LETTER CAN */
+ /*2981*/ 0x2d1b, 1, 0x10bb, /* GEORGIAN CAPITAL LETTER JIL */
+ /*2984*/ 0x2d1c, 1, 0x10bc, /* GEORGIAN CAPITAL LETTER CIL */
+ /*2987*/ 0x2d1d, 1, 0x10bd, /* GEORGIAN CAPITAL LETTER CHAR */
+ /*2990*/ 0x2d1e, 1, 0x10be, /* GEORGIAN CAPITAL LETTER XAN */
+ /*2993*/ 0x2d1f, 1, 0x10bf, /* GEORGIAN CAPITAL LETTER JHAN */
+ /*2996*/ 0x2d20, 1, 0x10c0, /* GEORGIAN CAPITAL LETTER HAE */
+ /*2999*/ 0x2d21, 1, 0x10c1, /* GEORGIAN CAPITAL LETTER HE */
+ /*3002*/ 0x2d22, 1, 0x10c2, /* GEORGIAN CAPITAL LETTER HIE */
+ /*3005*/ 0x2d23, 1, 0x10c3, /* GEORGIAN CAPITAL LETTER WE */
+ /*3008*/ 0x2d24, 1, 0x10c4, /* GEORGIAN CAPITAL LETTER HAR */
+ /*3011*/ 0x2d25, 1, 0x10c5, /* GEORGIAN CAPITAL LETTER HOE */
+ /*3014*/ 0x2d27, 1, 0x10c7, /* GEORGIAN CAPITAL LETTER YN */
+ /*3017*/ 0x2d2d, 1, 0x10cd, /* GEORGIAN CAPITAL LETTER AEN */
+ /*3020*/ 0xa641, 1, 0xa640, /* CYRILLIC CAPITAL LETTER ZEMLYA */
+ /*3023*/ 0xa643, 1, 0xa642, /* CYRILLIC CAPITAL LETTER DZELO */
+ /*3026*/ 0xa645, 1, 0xa644, /* CYRILLIC CAPITAL LETTER REVERSED .. */
+ /*3029*/ 0xa647, 1, 0xa646, /* CYRILLIC CAPITAL LETTER IOTA */
+ /*3032*/ 0xa649, 1, 0xa648, /* CYRILLIC CAPITAL LETTER DJERV */
+ /*3035*/ 0xa64b, 2, 0x1c88, 0xa64a, /* CYRILLIC SMALL LETTER UNBLENDED UK */
+ /*3039*/ 0xa64d, 1, 0xa64c, /* CYRILLIC CAPITAL LETTER BROAD OME.. */
+ /*3042*/ 0xa64f, 1, 0xa64e, /* CYRILLIC CAPITAL LETTER NEUTRAL Y.. */
+ /*3045*/ 0xa651, 1, 0xa650, /* CYRILLIC CAPITAL LETTER YERU WITH.. */
+ /*3048*/ 0xa653, 1, 0xa652, /* CYRILLIC CAPITAL LETTER IOTIFIED .. */
+ /*3051*/ 0xa655, 1, 0xa654, /* CYRILLIC CAPITAL LETTER REVERSED .. */
+ /*3054*/ 0xa657, 1, 0xa656, /* CYRILLIC CAPITAL LETTER IOTIFIED A */
+ /*3057*/ 0xa659, 1, 0xa658, /* CYRILLIC CAPITAL LETTER CLOSED LI.. */
+ /*3060*/ 0xa65b, 1, 0xa65a, /* CYRILLIC CAPITAL LETTER BLENDED Y.. */
+ /*3063*/ 0xa65d, 1, 0xa65c, /* CYRILLIC CAPITAL LETTER IOTIFIED .. */
+ /*3066*/ 0xa65f, 1, 0xa65e, /* CYRILLIC CAPITAL LETTER YN */
+ /*3069*/ 0xa661, 1, 0xa660, /* CYRILLIC CAPITAL LETTER REVERSED .. */
+ /*3072*/ 0xa663, 1, 0xa662, /* CYRILLIC CAPITAL LETTER SOFT DE */
+ /*3075*/ 0xa665, 1, 0xa664, /* CYRILLIC CAPITAL LETTER SOFT EL */
+ /*3078*/ 0xa667, 1, 0xa666, /* CYRILLIC CAPITAL LETTER SOFT EM */
+ /*3081*/ 0xa669, 1, 0xa668, /* CYRILLIC CAPITAL LETTER MONOCULAR.. */
+ /*3084*/ 0xa66b, 1, 0xa66a, /* CYRILLIC CAPITAL LETTER BINOCULAR.. */
+ /*3087*/ 0xa66d, 1, 0xa66c, /* CYRILLIC CAPITAL LETTER DOUBLE MO.. */
+ /*3090*/ 0xa681, 1, 0xa680, /* CYRILLIC CAPITAL LETTER DWE */
+ /*3093*/ 0xa683, 1, 0xa682, /* CYRILLIC CAPITAL LETTER DZWE */
+ /*3096*/ 0xa685, 1, 0xa684, /* CYRILLIC CAPITAL LETTER ZHWE */
+ /*3099*/ 0xa687, 1, 0xa686, /* CYRILLIC CAPITAL LETTER CCHE */
+ /*3102*/ 0xa689, 1, 0xa688, /* CYRILLIC CAPITAL LETTER DZZE */
+ /*3105*/ 0xa68b, 1, 0xa68a, /* CYRILLIC CAPITAL LETTER TE WITH M.. */
+ /*3108*/ 0xa68d, 1, 0xa68c, /* CYRILLIC CAPITAL LETTER TWE */
+ /*3111*/ 0xa68f, 1, 0xa68e, /* CYRILLIC CAPITAL LETTER TSWE */
+ /*3114*/ 0xa691, 1, 0xa690, /* CYRILLIC CAPITAL LETTER TSSE */
+ /*3117*/ 0xa693, 1, 0xa692, /* CYRILLIC CAPITAL LETTER TCHE */
+ /*3120*/ 0xa695, 1, 0xa694, /* CYRILLIC CAPITAL LETTER HWE */
+ /*3123*/ 0xa697, 1, 0xa696, /* CYRILLIC CAPITAL LETTER SHWE */
+ /*3126*/ 0xa699, 1, 0xa698, /* CYRILLIC CAPITAL LETTER DOUBLE O */
+ /*3129*/ 0xa69b, 1, 0xa69a, /* CYRILLIC CAPITAL LETTER CROSSED O */
+ /*3132*/ 0xa723, 1, 0xa722, /* LATIN CAPITAL LETTER EGYPTOLOGICA.. */
+ /*3135*/ 0xa725, 1, 0xa724, /* LATIN CAPITAL LETTER EGYPTOLOGICA.. */
+ /*3138*/ 0xa727, 1, 0xa726, /* LATIN CAPITAL LETTER HENG */
+ /*3141*/ 0xa729, 1, 0xa728, /* LATIN CAPITAL LETTER TZ */
+ /*3144*/ 0xa72b, 1, 0xa72a, /* LATIN CAPITAL LETTER TRESILLO */
+ /*3147*/ 0xa72d, 1, 0xa72c, /* LATIN CAPITAL LETTER CUATRILLO */
+ /*3150*/ 0xa72f, 1, 0xa72e, /* LATIN CAPITAL LETTER CUATRILLO WI.. */
+ /*3153*/ 0xa733, 1, 0xa732, /* LATIN CAPITAL LETTER AA */
+ /*3156*/ 0xa735, 1, 0xa734, /* LATIN CAPITAL LETTER AO */
+ /*3159*/ 0xa737, 1, 0xa736, /* LATIN CAPITAL LETTER AU */
+ /*3162*/ 0xa739, 1, 0xa738, /* LATIN CAPITAL LETTER AV */
+ /*3165*/ 0xa73b, 1, 0xa73a, /* LATIN CAPITAL LETTER AV WITH HORI.. */
+ /*3168*/ 0xa73d, 1, 0xa73c, /* LATIN CAPITAL LETTER AY */
+ /*3171*/ 0xa73f, 1, 0xa73e, /* LATIN CAPITAL LETTER REVERSED C W.. */
+ /*3174*/ 0xa741, 1, 0xa740, /* LATIN CAPITAL LETTER K WITH STROKE */
+ /*3177*/ 0xa743, 1, 0xa742, /* LATIN CAPITAL LETTER K WITH DIAGO.. */
+ /*3180*/ 0xa745, 1, 0xa744, /* LATIN CAPITAL LETTER K WITH STROK.. */
+ /*3183*/ 0xa747, 1, 0xa746, /* LATIN CAPITAL LETTER BROKEN L */
+ /*3186*/ 0xa749, 1, 0xa748, /* LATIN CAPITAL LETTER L WITH HIGH .. */
+ /*3189*/ 0xa74b, 1, 0xa74a, /* LATIN CAPITAL LETTER O WITH LONG .. */
+ /*3192*/ 0xa74d, 1, 0xa74c, /* LATIN CAPITAL LETTER O WITH LOOP */
+ /*3195*/ 0xa74f, 1, 0xa74e, /* LATIN CAPITAL LETTER OO */
+ /*3198*/ 0xa751, 1, 0xa750, /* LATIN CAPITAL LETTER P WITH STROK.. */
+ /*3201*/ 0xa753, 1, 0xa752, /* LATIN CAPITAL LETTER P WITH FLOUR.. */
+ /*3204*/ 0xa755, 1, 0xa754, /* LATIN CAPITAL LETTER P WITH SQUIR.. */
+ /*3207*/ 0xa757, 1, 0xa756, /* LATIN CAPITAL LETTER Q WITH STROK.. */
+ /*3210*/ 0xa759, 1, 0xa758, /* LATIN CAPITAL LETTER Q WITH DIAGO.. */
+ /*3213*/ 0xa75b, 1, 0xa75a, /* LATIN CAPITAL LETTER R ROTUNDA */
+ /*3216*/ 0xa75d, 1, 0xa75c, /* LATIN CAPITAL LETTER RUM ROTUNDA */
+ /*3219*/ 0xa75f, 1, 0xa75e, /* LATIN CAPITAL LETTER V WITH DIAGO.. */
+ /*3222*/ 0xa761, 1, 0xa760, /* LATIN CAPITAL LETTER VY */
+ /*3225*/ 0xa763, 1, 0xa762, /* LATIN CAPITAL LETTER VISIGOTHIC Z */
+ /*3228*/ 0xa765, 1, 0xa764, /* LATIN CAPITAL LETTER THORN WITH S.. */
+ /*3231*/ 0xa767, 1, 0xa766, /* LATIN CAPITAL LETTER THORN WITH S.. */
+ /*3234*/ 0xa769, 1, 0xa768, /* LATIN CAPITAL LETTER VEND */
+ /*3237*/ 0xa76b, 1, 0xa76a, /* LATIN CAPITAL LETTER ET */
+ /*3240*/ 0xa76d, 1, 0xa76c, /* LATIN CAPITAL LETTER IS */
+ /*3243*/ 0xa76f, 1, 0xa76e, /* LATIN CAPITAL LETTER CON */
+ /*3246*/ 0xa77a, 1, 0xa779, /* LATIN CAPITAL LETTER INSULAR D */
+ /*3249*/ 0xa77c, 1, 0xa77b, /* LATIN CAPITAL LETTER INSULAR F */
+ /*3252*/ 0xa77f, 1, 0xa77e, /* LATIN CAPITAL LETTER TURNED INSUL.. */
+ /*3255*/ 0xa781, 1, 0xa780, /* LATIN CAPITAL LETTER TURNED L */
+ /*3258*/ 0xa783, 1, 0xa782, /* LATIN CAPITAL LETTER INSULAR R */
+ /*3261*/ 0xa785, 1, 0xa784, /* LATIN CAPITAL LETTER INSULAR S */
+ /*3264*/ 0xa787, 1, 0xa786, /* LATIN CAPITAL LETTER INSULAR T */
+ /*3267*/ 0xa78c, 1, 0xa78b, /* LATIN CAPITAL LETTER SALTILLO */
+ /*3270*/ 0xa791, 1, 0xa790, /* LATIN CAPITAL LETTER N WITH DESCE.. */
+ /*3273*/ 0xa793, 1, 0xa792, /* LATIN CAPITAL LETTER C WITH BAR */
+ /*3276*/ 0xa794, 1, 0xa7c4, /* LATIN CAPITAL LETTER C WITH PALAT.. */
+ /*3279*/ 0xa797, 1, 0xa796, /* LATIN CAPITAL LETTER B WITH FLOUR.. */
+ /*3282*/ 0xa799, 1, 0xa798, /* LATIN CAPITAL LETTER F WITH STROKE */
+ /*3285*/ 0xa79b, 1, 0xa79a, /* LATIN CAPITAL LETTER VOLAPUK AE */
+ /*3288*/ 0xa79d, 1, 0xa79c, /* LATIN CAPITAL LETTER VOLAPUK OE */
+ /*3291*/ 0xa79f, 1, 0xa79e, /* LATIN CAPITAL LETTER VOLAPUK UE */
+ /*3294*/ 0xa7a1, 1, 0xa7a0, /* LATIN CAPITAL LETTER G WITH OBLIQ.. */
+ /*3297*/ 0xa7a3, 1, 0xa7a2, /* LATIN CAPITAL LETTER K WITH OBLIQ.. */
+ /*3300*/ 0xa7a5, 1, 0xa7a4, /* LATIN CAPITAL LETTER N WITH OBLIQ.. */
+ /*3303*/ 0xa7a7, 1, 0xa7a6, /* LATIN CAPITAL LETTER R WITH OBLIQ.. */
+ /*3306*/ 0xa7a9, 1, 0xa7a8, /* LATIN CAPITAL LETTER S WITH OBLIQ.. */
+ /*3309*/ 0xa7b5, 1, 0xa7b4, /* LATIN CAPITAL LETTER BETA */
+ /*3312*/ 0xa7b7, 1, 0xa7b6, /* LATIN CAPITAL LETTER OMEGA */
+ /*3315*/ 0xa7b9, 1, 0xa7b8, /* LATIN CAPITAL LETTER U WITH STROKE */
+ /*3318*/ 0xa7bb, 1, 0xa7ba, /* LATIN CAPITAL LETTER GLOTTAL A */
+ /*3321*/ 0xa7bd, 1, 0xa7bc, /* LATIN CAPITAL LETTER GLOTTAL I */
+ /*3324*/ 0xa7bf, 1, 0xa7be, /* LATIN CAPITAL LETTER GLOTTAL U */
+ /*3327*/ 0xa7c3, 1, 0xa7c2, /* LATIN CAPITAL LETTER ANGLICANA W */
+ /*3330*/ 0xab53, 1, 0xa7b3, /* LATIN CAPITAL LETTER CHI */
+ /*3333*/ 0xff41, 1, 0xff21, /* FULLWIDTH LATIN CAPITAL LETTER A */
+ /*3336*/ 0xff42, 1, 0xff22, /* FULLWIDTH LATIN CAPITAL LETTER B */
+ /*3339*/ 0xff43, 1, 0xff23, /* FULLWIDTH LATIN CAPITAL LETTER C */
+ /*3342*/ 0xff44, 1, 0xff24, /* FULLWIDTH LATIN CAPITAL LETTER D */
+ /*3345*/ 0xff45, 1, 0xff25, /* FULLWIDTH LATIN CAPITAL LETTER E */
+ /*3348*/ 0xff46, 1, 0xff26, /* FULLWIDTH LATIN CAPITAL LETTER F */
+ /*3351*/ 0xff47, 1, 0xff27, /* FULLWIDTH LATIN CAPITAL LETTER G */
+ /*3354*/ 0xff48, 1, 0xff28, /* FULLWIDTH LATIN CAPITAL LETTER H */
+ /*3357*/ 0xff49, 1, 0xff29, /* FULLWIDTH LATIN CAPITAL LETTER I */
+ /*3360*/ 0xff4a, 1, 0xff2a, /* FULLWIDTH LATIN CAPITAL LETTER J */
+ /*3363*/ 0xff4b, 1, 0xff2b, /* FULLWIDTH LATIN CAPITAL LETTER K */
+ /*3366*/ 0xff4c, 1, 0xff2c, /* FULLWIDTH LATIN CAPITAL LETTER L */
+ /*3369*/ 0xff4d, 1, 0xff2d, /* FULLWIDTH LATIN CAPITAL LETTER M */
+ /*3372*/ 0xff4e, 1, 0xff2e, /* FULLWIDTH LATIN CAPITAL LETTER N */
+ /*3375*/ 0xff4f, 1, 0xff2f, /* FULLWIDTH LATIN CAPITAL LETTER O */
+ /*3378*/ 0xff50, 1, 0xff30, /* FULLWIDTH LATIN CAPITAL LETTER P */
+ /*3381*/ 0xff51, 1, 0xff31, /* FULLWIDTH LATIN CAPITAL LETTER Q */
+ /*3384*/ 0xff52, 1, 0xff32, /* FULLWIDTH LATIN CAPITAL LETTER R */
+ /*3387*/ 0xff53, 1, 0xff33, /* FULLWIDTH LATIN CAPITAL LETTER S */
+ /*3390*/ 0xff54, 1, 0xff34, /* FULLWIDTH LATIN CAPITAL LETTER T */
+ /*3393*/ 0xff55, 1, 0xff35, /* FULLWIDTH LATIN CAPITAL LETTER U */
+ /*3396*/ 0xff56, 1, 0xff36, /* FULLWIDTH LATIN CAPITAL LETTER V */
+ /*3399*/ 0xff57, 1, 0xff37, /* FULLWIDTH LATIN CAPITAL LETTER W */
+ /*3402*/ 0xff58, 1, 0xff38, /* FULLWIDTH LATIN CAPITAL LETTER X */
+ /*3405*/ 0xff59, 1, 0xff39, /* FULLWIDTH LATIN CAPITAL LETTER Y */
+ /*3408*/ 0xff5a, 1, 0xff3a, /* FULLWIDTH LATIN CAPITAL LETTER Z */
+ /*3411*/ 0x010428, 1, 0x010400, /* DESERET CAPITAL LETTER LONG I */
+ /*3414*/ 0x010429, 1, 0x010401, /* DESERET CAPITAL LETTER LONG E */
+ /*3417*/ 0x01042a, 1, 0x010402, /* DESERET CAPITAL LETTER LONG A */
+ /*3420*/ 0x01042b, 1, 0x010403, /* DESERET CAPITAL LETTER LONG AH */
+ /*3423*/ 0x01042c, 1, 0x010404, /* DESERET CAPITAL LETTER LONG O */
+ /*3426*/ 0x01042d, 1, 0x010405, /* DESERET CAPITAL LETTER LONG OO */
+ /*3429*/ 0x01042e, 1, 0x010406, /* DESERET CAPITAL LETTER SHORT I */
+ /*3432*/ 0x01042f, 1, 0x010407, /* DESERET CAPITAL LETTER SHORT E */
+ /*3435*/ 0x010430, 1, 0x010408, /* DESERET CAPITAL LETTER SHORT A */
+ /*3438*/ 0x010431, 1, 0x010409, /* DESERET CAPITAL LETTER SHORT AH */
+ /*3441*/ 0x010432, 1, 0x01040a, /* DESERET CAPITAL LETTER SHORT O */
+ /*3444*/ 0x010433, 1, 0x01040b, /* DESERET CAPITAL LETTER SHORT OO */
+ /*3447*/ 0x010434, 1, 0x01040c, /* DESERET CAPITAL LETTER AY */
+ /*3450*/ 0x010435, 1, 0x01040d, /* DESERET CAPITAL LETTER OW */
+ /*3453*/ 0x010436, 1, 0x01040e, /* DESERET CAPITAL LETTER WU */
+ /*3456*/ 0x010437, 1, 0x01040f, /* DESERET CAPITAL LETTER YEE */
+ /*3459*/ 0x010438, 1, 0x010410, /* DESERET CAPITAL LETTER H */
+ /*3462*/ 0x010439, 1, 0x010411, /* DESERET CAPITAL LETTER PEE */
+ /*3465*/ 0x01043a, 1, 0x010412, /* DESERET CAPITAL LETTER BEE */
+ /*3468*/ 0x01043b, 1, 0x010413, /* DESERET CAPITAL LETTER TEE */
+ /*3471*/ 0x01043c, 1, 0x010414, /* DESERET CAPITAL LETTER DEE */
+ /*3474*/ 0x01043d, 1, 0x010415, /* DESERET CAPITAL LETTER CHEE */
+ /*3477*/ 0x01043e, 1, 0x010416, /* DESERET CAPITAL LETTER JEE */
+ /*3480*/ 0x01043f, 1, 0x010417, /* DESERET CAPITAL LETTER KAY */
+ /*3483*/ 0x010440, 1, 0x010418, /* DESERET CAPITAL LETTER GAY */
+ /*3486*/ 0x010441, 1, 0x010419, /* DESERET CAPITAL LETTER EF */
+ /*3489*/ 0x010442, 1, 0x01041a, /* DESERET CAPITAL LETTER VEE */
+ /*3492*/ 0x010443, 1, 0x01041b, /* DESERET CAPITAL LETTER ETH */
+ /*3495*/ 0x010444, 1, 0x01041c, /* DESERET CAPITAL LETTER THEE */
+ /*3498*/ 0x010445, 1, 0x01041d, /* DESERET CAPITAL LETTER ES */
+ /*3501*/ 0x010446, 1, 0x01041e, /* DESERET CAPITAL LETTER ZEE */
+ /*3504*/ 0x010447, 1, 0x01041f, /* DESERET CAPITAL LETTER ESH */
+ /*3507*/ 0x010448, 1, 0x010420, /* DESERET CAPITAL LETTER ZHEE */
+ /*3510*/ 0x010449, 1, 0x010421, /* DESERET CAPITAL LETTER ER */
+ /*3513*/ 0x01044a, 1, 0x010422, /* DESERET CAPITAL LETTER EL */
+ /*3516*/ 0x01044b, 1, 0x010423, /* DESERET CAPITAL LETTER EM */
+ /*3519*/ 0x01044c, 1, 0x010424, /* DESERET CAPITAL LETTER EN */
+ /*3522*/ 0x01044d, 1, 0x010425, /* DESERET CAPITAL LETTER ENG */
+ /*3525*/ 0x01044e, 1, 0x010426, /* DESERET CAPITAL LETTER OI */
+ /*3528*/ 0x01044f, 1, 0x010427, /* DESERET CAPITAL LETTER EW */
+ /*3531*/ 0x0104d8, 1, 0x0104b0, /* OSAGE CAPITAL LETTER A */
+ /*3534*/ 0x0104d9, 1, 0x0104b1, /* OSAGE CAPITAL LETTER AI */
+ /*3537*/ 0x0104da, 1, 0x0104b2, /* OSAGE CAPITAL LETTER AIN */
+ /*3540*/ 0x0104db, 1, 0x0104b3, /* OSAGE CAPITAL LETTER AH */
+ /*3543*/ 0x0104dc, 1, 0x0104b4, /* OSAGE CAPITAL LETTER BRA */
+ /*3546*/ 0x0104dd, 1, 0x0104b5, /* OSAGE CAPITAL LETTER CHA */
+ /*3549*/ 0x0104de, 1, 0x0104b6, /* OSAGE CAPITAL LETTER EHCHA */
+ /*3552*/ 0x0104df, 1, 0x0104b7, /* OSAGE CAPITAL LETTER E */
+ /*3555*/ 0x0104e0, 1, 0x0104b8, /* OSAGE CAPITAL LETTER EIN */
+ /*3558*/ 0x0104e1, 1, 0x0104b9, /* OSAGE CAPITAL LETTER HA */
+ /*3561*/ 0x0104e2, 1, 0x0104ba, /* OSAGE CAPITAL LETTER HYA */
+ /*3564*/ 0x0104e3, 1, 0x0104bb, /* OSAGE CAPITAL LETTER I */
+ /*3567*/ 0x0104e4, 1, 0x0104bc, /* OSAGE CAPITAL LETTER KA */
+ /*3570*/ 0x0104e5, 1, 0x0104bd, /* OSAGE CAPITAL LETTER EHKA */
+ /*3573*/ 0x0104e6, 1, 0x0104be, /* OSAGE CAPITAL LETTER KYA */
+ /*3576*/ 0x0104e7, 1, 0x0104bf, /* OSAGE CAPITAL LETTER LA */
+ /*3579*/ 0x0104e8, 1, 0x0104c0, /* OSAGE CAPITAL LETTER MA */
+ /*3582*/ 0x0104e9, 1, 0x0104c1, /* OSAGE CAPITAL LETTER NA */
+ /*3585*/ 0x0104ea, 1, 0x0104c2, /* OSAGE CAPITAL LETTER O */
+ /*3588*/ 0x0104eb, 1, 0x0104c3, /* OSAGE CAPITAL LETTER OIN */
+ /*3591*/ 0x0104ec, 1, 0x0104c4, /* OSAGE CAPITAL LETTER PA */
+ /*3594*/ 0x0104ed, 1, 0x0104c5, /* OSAGE CAPITAL LETTER EHPA */
+ /*3597*/ 0x0104ee, 1, 0x0104c6, /* OSAGE CAPITAL LETTER SA */
+ /*3600*/ 0x0104ef, 1, 0x0104c7, /* OSAGE CAPITAL LETTER SHA */
+ /*3603*/ 0x0104f0, 1, 0x0104c8, /* OSAGE CAPITAL LETTER TA */
+ /*3606*/ 0x0104f1, 1, 0x0104c9, /* OSAGE CAPITAL LETTER EHTA */
+ /*3609*/ 0x0104f2, 1, 0x0104ca, /* OSAGE CAPITAL LETTER TSA */
+ /*3612*/ 0x0104f3, 1, 0x0104cb, /* OSAGE CAPITAL LETTER EHTSA */
+ /*3615*/ 0x0104f4, 1, 0x0104cc, /* OSAGE CAPITAL LETTER TSHA */
+ /*3618*/ 0x0104f5, 1, 0x0104cd, /* OSAGE CAPITAL LETTER DHA */
+ /*3621*/ 0x0104f6, 1, 0x0104ce, /* OSAGE CAPITAL LETTER U */
+ /*3624*/ 0x0104f7, 1, 0x0104cf, /* OSAGE CAPITAL LETTER WA */
+ /*3627*/ 0x0104f8, 1, 0x0104d0, /* OSAGE CAPITAL LETTER KHA */
+ /*3630*/ 0x0104f9, 1, 0x0104d1, /* OSAGE CAPITAL LETTER GHA */
+ /*3633*/ 0x0104fa, 1, 0x0104d2, /* OSAGE CAPITAL LETTER ZA */
+ /*3636*/ 0x0104fb, 1, 0x0104d3, /* OSAGE CAPITAL LETTER ZHA */
+ /*3639*/ 0x010cc0, 1, 0x010c80, /* OLD HUNGARIAN CAPITAL LETTER A */
+ /*3642*/ 0x010cc1, 1, 0x010c81, /* OLD HUNGARIAN CAPITAL LETTER AA */
+ /*3645*/ 0x010cc2, 1, 0x010c82, /* OLD HUNGARIAN CAPITAL LETTER EB */
+ /*3648*/ 0x010cc3, 1, 0x010c83, /* OLD HUNGARIAN CAPITAL LETTER AMB */
+ /*3651*/ 0x010cc4, 1, 0x010c84, /* OLD HUNGARIAN CAPITAL LETTER EC */
+ /*3654*/ 0x010cc5, 1, 0x010c85, /* OLD HUNGARIAN CAPITAL LETTER ENC */
+ /*3657*/ 0x010cc6, 1, 0x010c86, /* OLD HUNGARIAN CAPITAL LETTER ECS */
+ /*3660*/ 0x010cc7, 1, 0x010c87, /* OLD HUNGARIAN CAPITAL LETTER ED */
+ /*3663*/ 0x010cc8, 1, 0x010c88, /* OLD HUNGARIAN CAPITAL LETTER AND */
+ /*3666*/ 0x010cc9, 1, 0x010c89, /* OLD HUNGARIAN CAPITAL LETTER E */
+ /*3669*/ 0x010cca, 1, 0x010c8a, /* OLD HUNGARIAN CAPITAL LETTER CLOS.. */
+ /*3672*/ 0x010ccb, 1, 0x010c8b, /* OLD HUNGARIAN CAPITAL LETTER EE */
+ /*3675*/ 0x010ccc, 1, 0x010c8c, /* OLD HUNGARIAN CAPITAL LETTER EF */
+ /*3678*/ 0x010ccd, 1, 0x010c8d, /* OLD HUNGARIAN CAPITAL LETTER EG */
+ /*3681*/ 0x010cce, 1, 0x010c8e, /* OLD HUNGARIAN CAPITAL LETTER EGY */
+ /*3684*/ 0x010ccf, 1, 0x010c8f, /* OLD HUNGARIAN CAPITAL LETTER EH */
+ /*3687*/ 0x010cd0, 1, 0x010c90, /* OLD HUNGARIAN CAPITAL LETTER I */
+ /*3690*/ 0x010cd1, 1, 0x010c91, /* OLD HUNGARIAN CAPITAL LETTER II */
+ /*3693*/ 0x010cd2, 1, 0x010c92, /* OLD HUNGARIAN CAPITAL LETTER EJ */
+ /*3696*/ 0x010cd3, 1, 0x010c93, /* OLD HUNGARIAN CAPITAL LETTER EK */
+ /*3699*/ 0x010cd4, 1, 0x010c94, /* OLD HUNGARIAN CAPITAL LETTER AK */
+ /*3702*/ 0x010cd5, 1, 0x010c95, /* OLD HUNGARIAN CAPITAL LETTER UNK */
+ /*3705*/ 0x010cd6, 1, 0x010c96, /* OLD HUNGARIAN CAPITAL LETTER EL */
+ /*3708*/ 0x010cd7, 1, 0x010c97, /* OLD HUNGARIAN CAPITAL LETTER ELY */
+ /*3711*/ 0x010cd8, 1, 0x010c98, /* OLD HUNGARIAN CAPITAL LETTER EM */
+ /*3714*/ 0x010cd9, 1, 0x010c99, /* OLD HUNGARIAN CAPITAL LETTER EN */
+ /*3717*/ 0x010cda, 1, 0x010c9a, /* OLD HUNGARIAN CAPITAL LETTER ENY */
+ /*3720*/ 0x010cdb, 1, 0x010c9b, /* OLD HUNGARIAN CAPITAL LETTER O */
+ /*3723*/ 0x010cdc, 1, 0x010c9c, /* OLD HUNGARIAN CAPITAL LETTER OO */
+ /*3726*/ 0x010cdd, 1, 0x010c9d, /* OLD HUNGARIAN CAPITAL LETTER NIKO.. */
+ /*3729*/ 0x010cde, 1, 0x010c9e, /* OLD HUNGARIAN CAPITAL LETTER RUDI.. */
+ /*3732*/ 0x010cdf, 1, 0x010c9f, /* OLD HUNGARIAN CAPITAL LETTER OEE */
+ /*3735*/ 0x010ce0, 1, 0x010ca0, /* OLD HUNGARIAN CAPITAL LETTER EP */
+ /*3738*/ 0x010ce1, 1, 0x010ca1, /* OLD HUNGARIAN CAPITAL LETTER EMP */
+ /*3741*/ 0x010ce2, 1, 0x010ca2, /* OLD HUNGARIAN CAPITAL LETTER ER */
+ /*3744*/ 0x010ce3, 1, 0x010ca3, /* OLD HUNGARIAN CAPITAL LETTER SHOR.. */
+ /*3747*/ 0x010ce4, 1, 0x010ca4, /* OLD HUNGARIAN CAPITAL LETTER ES */
+ /*3750*/ 0x010ce5, 1, 0x010ca5, /* OLD HUNGARIAN CAPITAL LETTER ESZ */
+ /*3753*/ 0x010ce6, 1, 0x010ca6, /* OLD HUNGARIAN CAPITAL LETTER ET */
+ /*3756*/ 0x010ce7, 1, 0x010ca7, /* OLD HUNGARIAN CAPITAL LETTER ENT */
+ /*3759*/ 0x010ce8, 1, 0x010ca8, /* OLD HUNGARIAN CAPITAL LETTER ETY */
+ /*3762*/ 0x010ce9, 1, 0x010ca9, /* OLD HUNGARIAN CAPITAL LETTER ECH */
+ /*3765*/ 0x010cea, 1, 0x010caa, /* OLD HUNGARIAN CAPITAL LETTER U */
+ /*3768*/ 0x010ceb, 1, 0x010cab, /* OLD HUNGARIAN CAPITAL LETTER UU */
+ /*3771*/ 0x010cec, 1, 0x010cac, /* OLD HUNGARIAN CAPITAL LETTER NIKO.. */
+ /*3774*/ 0x010ced, 1, 0x010cad, /* OLD HUNGARIAN CAPITAL LETTER RUDI.. */
+ /*3777*/ 0x010cee, 1, 0x010cae, /* OLD HUNGARIAN CAPITAL LETTER EV */
+ /*3780*/ 0x010cef, 1, 0x010caf, /* OLD HUNGARIAN CAPITAL LETTER EZ */
+ /*3783*/ 0x010cf0, 1, 0x010cb0, /* OLD HUNGARIAN CAPITAL LETTER EZS */
+ /*3786*/ 0x010cf1, 1, 0x010cb1, /* OLD HUNGARIAN CAPITAL LETTER ENT-.. */
+ /*3789*/ 0x010cf2, 1, 0x010cb2, /* OLD HUNGARIAN CAPITAL LETTER US */
+ /*3792*/ 0x0118c0, 1, 0x0118a0, /* WARANG CITI CAPITAL LETTER NGAA */
+ /*3795*/ 0x0118c1, 1, 0x0118a1, /* WARANG CITI CAPITAL LETTER A */
+ /*3798*/ 0x0118c2, 1, 0x0118a2, /* WARANG CITI CAPITAL LETTER WI */
+ /*3801*/ 0x0118c3, 1, 0x0118a3, /* WARANG CITI CAPITAL LETTER YU */
+ /*3804*/ 0x0118c4, 1, 0x0118a4, /* WARANG CITI CAPITAL LETTER YA */
+ /*3807*/ 0x0118c5, 1, 0x0118a5, /* WARANG CITI CAPITAL LETTER YO */
+ /*3810*/ 0x0118c6, 1, 0x0118a6, /* WARANG CITI CAPITAL LETTER II */
+ /*3813*/ 0x0118c7, 1, 0x0118a7, /* WARANG CITI CAPITAL LETTER UU */
+ /*3816*/ 0x0118c8, 1, 0x0118a8, /* WARANG CITI CAPITAL LETTER E */
+ /*3819*/ 0x0118c9, 1, 0x0118a9, /* WARANG CITI CAPITAL LETTER O */
+ /*3822*/ 0x0118ca, 1, 0x0118aa, /* WARANG CITI CAPITAL LETTER ANG */
+ /*3825*/ 0x0118cb, 1, 0x0118ab, /* WARANG CITI CAPITAL LETTER GA */
+ /*3828*/ 0x0118cc, 1, 0x0118ac, /* WARANG CITI CAPITAL LETTER KO */
+ /*3831*/ 0x0118cd, 1, 0x0118ad, /* WARANG CITI CAPITAL LETTER ENY */
+ /*3834*/ 0x0118ce, 1, 0x0118ae, /* WARANG CITI CAPITAL LETTER YUJ */
+ /*3837*/ 0x0118cf, 1, 0x0118af, /* WARANG CITI CAPITAL LETTER UC */
+ /*3840*/ 0x0118d0, 1, 0x0118b0, /* WARANG CITI CAPITAL LETTER ENN */
+ /*3843*/ 0x0118d1, 1, 0x0118b1, /* WARANG CITI CAPITAL LETTER ODD */
+ /*3846*/ 0x0118d2, 1, 0x0118b2, /* WARANG CITI CAPITAL LETTER TTE */
+ /*3849*/ 0x0118d3, 1, 0x0118b3, /* WARANG CITI CAPITAL LETTER NUNG */
+ /*3852*/ 0x0118d4, 1, 0x0118b4, /* WARANG CITI CAPITAL LETTER DA */
+ /*3855*/ 0x0118d5, 1, 0x0118b5, /* WARANG CITI CAPITAL LETTER AT */
+ /*3858*/ 0x0118d6, 1, 0x0118b6, /* WARANG CITI CAPITAL LETTER AM */
+ /*3861*/ 0x0118d7, 1, 0x0118b7, /* WARANG CITI CAPITAL LETTER BU */
+ /*3864*/ 0x0118d8, 1, 0x0118b8, /* WARANG CITI CAPITAL LETTER PU */
+ /*3867*/ 0x0118d9, 1, 0x0118b9, /* WARANG CITI CAPITAL LETTER HIYO */
+ /*3870*/ 0x0118da, 1, 0x0118ba, /* WARANG CITI CAPITAL LETTER HOLO */
+ /*3873*/ 0x0118db, 1, 0x0118bb, /* WARANG CITI CAPITAL LETTER HORR */
+ /*3876*/ 0x0118dc, 1, 0x0118bc, /* WARANG CITI CAPITAL LETTER HAR */
+ /*3879*/ 0x0118dd, 1, 0x0118bd, /* WARANG CITI CAPITAL LETTER SSUU */
+ /*3882*/ 0x0118de, 1, 0x0118be, /* WARANG CITI CAPITAL LETTER SII */
+ /*3885*/ 0x0118df, 1, 0x0118bf, /* WARANG CITI CAPITAL LETTER VIYO */
+ /*3888*/ 0x016e60, 1, 0x016e40, /* MEDEFAIDRIN CAPITAL LETTER M */
+ /*3891*/ 0x016e61, 1, 0x016e41, /* MEDEFAIDRIN CAPITAL LETTER S */
+ /*3894*/ 0x016e62, 1, 0x016e42, /* MEDEFAIDRIN CAPITAL LETTER V */
+ /*3897*/ 0x016e63, 1, 0x016e43, /* MEDEFAIDRIN CAPITAL LETTER W */
+ /*3900*/ 0x016e64, 1, 0x016e44, /* MEDEFAIDRIN CAPITAL LETTER ATIU */
+ /*3903*/ 0x016e65, 1, 0x016e45, /* MEDEFAIDRIN CAPITAL LETTER Z */
+ /*3906*/ 0x016e66, 1, 0x016e46, /* MEDEFAIDRIN CAPITAL LETTER KP */
+ /*3909*/ 0x016e67, 1, 0x016e47, /* MEDEFAIDRIN CAPITAL LETTER P */
+ /*3912*/ 0x016e68, 1, 0x016e48, /* MEDEFAIDRIN CAPITAL LETTER T */
+ /*3915*/ 0x016e69, 1, 0x016e49, /* MEDEFAIDRIN CAPITAL LETTER G */
+ /*3918*/ 0x016e6a, 1, 0x016e4a, /* MEDEFAIDRIN CAPITAL LETTER F */
+ /*3921*/ 0x016e6b, 1, 0x016e4b, /* MEDEFAIDRIN CAPITAL LETTER I */
+ /*3924*/ 0x016e6c, 1, 0x016e4c, /* MEDEFAIDRIN CAPITAL LETTER K */
+ /*3927*/ 0x016e6d, 1, 0x016e4d, /* MEDEFAIDRIN CAPITAL LETTER A */
+ /*3930*/ 0x016e6e, 1, 0x016e4e, /* MEDEFAIDRIN CAPITAL LETTER J */
+ /*3933*/ 0x016e6f, 1, 0x016e4f, /* MEDEFAIDRIN CAPITAL LETTER E */
+ /*3936*/ 0x016e70, 1, 0x016e50, /* MEDEFAIDRIN CAPITAL LETTER B */
+ /*3939*/ 0x016e71, 1, 0x016e51, /* MEDEFAIDRIN CAPITAL LETTER C */
+ /*3942*/ 0x016e72, 1, 0x016e52, /* MEDEFAIDRIN CAPITAL LETTER U */
+ /*3945*/ 0x016e73, 1, 0x016e53, /* MEDEFAIDRIN CAPITAL LETTER YU */
+ /*3948*/ 0x016e74, 1, 0x016e54, /* MEDEFAIDRIN CAPITAL LETTER L */
+ /*3951*/ 0x016e75, 1, 0x016e55, /* MEDEFAIDRIN CAPITAL LETTER Q */
+ /*3954*/ 0x016e76, 1, 0x016e56, /* MEDEFAIDRIN CAPITAL LETTER HP */
+ /*3957*/ 0x016e77, 1, 0x016e57, /* MEDEFAIDRIN CAPITAL LETTER NY */
+ /*3960*/ 0x016e78, 1, 0x016e58, /* MEDEFAIDRIN CAPITAL LETTER X */
+ /*3963*/ 0x016e79, 1, 0x016e59, /* MEDEFAIDRIN CAPITAL LETTER D */
+ /*3966*/ 0x016e7a, 1, 0x016e5a, /* MEDEFAIDRIN CAPITAL LETTER OE */
+ /*3969*/ 0x016e7b, 1, 0x016e5b, /* MEDEFAIDRIN CAPITAL LETTER N */
+ /*3972*/ 0x016e7c, 1, 0x016e5c, /* MEDEFAIDRIN CAPITAL LETTER R */
+ /*3975*/ 0x016e7d, 1, 0x016e5d, /* MEDEFAIDRIN CAPITAL LETTER O */
+ /*3978*/ 0x016e7e, 1, 0x016e5e, /* MEDEFAIDRIN CAPITAL LETTER AI */
+ /*3981*/ 0x016e7f, 1, 0x016e5f, /* MEDEFAIDRIN CAPITAL LETTER Y */
+ /*3984*/ 0x01e922, 1, 0x01e900, /* ADLAM CAPITAL LETTER ALIF */
+ /*3987*/ 0x01e923, 1, 0x01e901, /* ADLAM CAPITAL LETTER DAALI */
+ /*3990*/ 0x01e924, 1, 0x01e902, /* ADLAM CAPITAL LETTER LAAM */
+ /*3993*/ 0x01e925, 1, 0x01e903, /* ADLAM CAPITAL LETTER MIIM */
+ /*3996*/ 0x01e926, 1, 0x01e904, /* ADLAM CAPITAL LETTER BA */
+ /*3999*/ 0x01e927, 1, 0x01e905, /* ADLAM CAPITAL LETTER SINNYIIYHE */
+ /*4002*/ 0x01e928, 1, 0x01e906, /* ADLAM CAPITAL LETTER PE */
+ /*4005*/ 0x01e929, 1, 0x01e907, /* ADLAM CAPITAL LETTER BHE */
+ /*4008*/ 0x01e92a, 1, 0x01e908, /* ADLAM CAPITAL LETTER RA */
+ /*4011*/ 0x01e92b, 1, 0x01e909, /* ADLAM CAPITAL LETTER E */
+ /*4014*/ 0x01e92c, 1, 0x01e90a, /* ADLAM CAPITAL LETTER FA */
+ /*4017*/ 0x01e92d, 1, 0x01e90b, /* ADLAM CAPITAL LETTER I */
+ /*4020*/ 0x01e92e, 1, 0x01e90c, /* ADLAM CAPITAL LETTER O */
+ /*4023*/ 0x01e92f, 1, 0x01e90d, /* ADLAM CAPITAL LETTER DHA */
+ /*4026*/ 0x01e930, 1, 0x01e90e, /* ADLAM CAPITAL LETTER YHE */
+ /*4029*/ 0x01e931, 1, 0x01e90f, /* ADLAM CAPITAL LETTER WAW */
+ /*4032*/ 0x01e932, 1, 0x01e910, /* ADLAM CAPITAL LETTER NUN */
+ /*4035*/ 0x01e933, 1, 0x01e911, /* ADLAM CAPITAL LETTER KAF */
+ /*4038*/ 0x01e934, 1, 0x01e912, /* ADLAM CAPITAL LETTER YA */
+ /*4041*/ 0x01e935, 1, 0x01e913, /* ADLAM CAPITAL LETTER U */
+ /*4044*/ 0x01e936, 1, 0x01e914, /* ADLAM CAPITAL LETTER JIIM */
+ /*4047*/ 0x01e937, 1, 0x01e915, /* ADLAM CAPITAL LETTER CHI */
+ /*4050*/ 0x01e938, 1, 0x01e916, /* ADLAM CAPITAL LETTER HA */
+ /*4053*/ 0x01e939, 1, 0x01e917, /* ADLAM CAPITAL LETTER QAAF */
+ /*4056*/ 0x01e93a, 1, 0x01e918, /* ADLAM CAPITAL LETTER GA */
+ /*4059*/ 0x01e93b, 1, 0x01e919, /* ADLAM CAPITAL LETTER NYA */
+ /*4062*/ 0x01e93c, 1, 0x01e91a, /* ADLAM CAPITAL LETTER TU */
+ /*4065*/ 0x01e93d, 1, 0x01e91b, /* ADLAM CAPITAL LETTER NHA */
+ /*4068*/ 0x01e93e, 1, 0x01e91c, /* ADLAM CAPITAL LETTER VA */
+ /*4071*/ 0x01e93f, 1, 0x01e91d, /* ADLAM CAPITAL LETTER KHA */
+ /*4074*/ 0x01e940, 1, 0x01e91e, /* ADLAM CAPITAL LETTER GBE */
+ /*4077*/ 0x01e941, 1, 0x01e91f, /* ADLAM CAPITAL LETTER ZAL */
+ /*4080*/ 0x01e942, 1, 0x01e920, /* ADLAM CAPITAL LETTER KPO */
+ /*4083*/ 0x01e943, 1, 0x01e921, /* ADLAM CAPITAL LETTER SHA */
+#define FOLDS1_NORMAL_END_INDEX 4086
+ /* ----- LOCALE ----- */
+ /*4086*/ 0x0069, 1, 0x0049, /* LATIN CAPITAL LETTER I */
+#define FOLDS1_END_INDEX 4089
+};
+
+OnigCodePoint OnigUnicodeFolds2[] = {
+ /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
+ /* 0*/ 0x0061, 0x02be, 1, 0x1e9a,
+ /* LATIN SMALL LIGATURE FF */
+ /* 4*/ 0x0066, 0x0066, 1, 0xfb00,
+ /* LATIN SMALL LIGATURE FI */
+ /* 8*/ 0x0066, 0x0069, 1, 0xfb01,
+ /* LATIN SMALL LIGATURE FL */
+ /* 12*/ 0x0066, 0x006c, 1, 0xfb02,
+ /* LATIN SMALL LETTER H WITH LINE BELOW */
+ /* 16*/ 0x0068, 0x0331, 1, 0x1e96,
+ /* LATIN SMALL LETTER J WITH CARON */
+ /* 20*/ 0x006a, 0x030c, 1, 0x01f0,
+ /* LATIN SMALL LETTER SHARP S */
+ /* 24*/ 0x0073, 0x0073, 2, 0x00df, 0x1e9e,
+ /* LATIN SMALL LIGATURE LONG S T */
+ /* 29*/ 0x0073, 0x0074, 2, 0xfb05, 0xfb06,
+ /* LATIN SMALL LETTER T WITH DIAERESIS */
+ /* 34*/ 0x0074, 0x0308, 1, 0x1e97,
+ /* LATIN SMALL LETTER W WITH RING ABOVE */
+ /* 38*/ 0x0077, 0x030a, 1, 0x1e98,
+ /* LATIN SMALL LETTER Y WITH RING ABOVE */
+ /* 42*/ 0x0079, 0x030a, 1, 0x1e99,
+ /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
+ /* 46*/ 0x02bc, 0x006e, 1, 0x0149,
+ /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
+ /* 50*/ 0x03ac, 0x03b9, 1, 0x1fb4,
+ /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
+ /* 54*/ 0x03ae, 0x03b9, 1, 0x1fc4,
+ /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
+ /* 58*/ 0x03b1, 0x0342, 1, 0x1fb6,
+ /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
+ /* 62*/ 0x03b1, 0x03b9, 2, 0x1fb3, 0x1fbc,
+ /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
+ /* 67*/ 0x03b7, 0x0342, 1, 0x1fc6,
+ /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
+ /* 71*/ 0x03b7, 0x03b9, 2, 0x1fc3, 0x1fcc,
+ /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
+ /* 76*/ 0x03b9, 0x0342, 1, 0x1fd6,
+ /* GREEK SMALL LETTER RHO WITH PSILI */
+ /* 80*/ 0x03c1, 0x0313, 1, 0x1fe4,
+ /* GREEK SMALL LETTER UPSILON WITH PSILI */
+ /* 84*/ 0x03c5, 0x0313, 1, 0x1f50,
+ /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
+ /* 88*/ 0x03c5, 0x0342, 1, 0x1fe6,
+ /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
+ /* 92*/ 0x03c9, 0x0342, 1, 0x1ff6,
+ /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
+ /* 96*/ 0x03c9, 0x03b9, 2, 0x1ff3, 0x1ffc,
+ /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
+ /* 101*/ 0x03ce, 0x03b9, 1, 0x1ff4,
+ /* ARMENIAN SMALL LIGATURE ECH YIWN */
+ /* 105*/ 0x0565, 0x0582, 1, 0x0587,
+ /* ARMENIAN SMALL LIGATURE MEN ECH */
+ /* 109*/ 0x0574, 0x0565, 1, 0xfb14,
+ /* ARMENIAN SMALL LIGATURE MEN INI */
+ /* 113*/ 0x0574, 0x056b, 1, 0xfb15,
+ /* ARMENIAN SMALL LIGATURE MEN XEH */
+ /* 117*/ 0x0574, 0x056d, 1, 0xfb17,
+ /* ARMENIAN SMALL LIGATURE MEN NOW */
+ /* 121*/ 0x0574, 0x0576, 1, 0xfb13,
+ /* ARMENIAN SMALL LIGATURE VEW NOW */
+ /* 125*/ 0x057e, 0x0576, 1, 0xfb16,
+ /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
+ /* 129*/ 0x1f00, 0x03b9, 2, 0x1f80, 0x1f88,
+ /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
+ /* 134*/ 0x1f01, 0x03b9, 2, 0x1f81, 0x1f89,
+ /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+ /* 139*/ 0x1f02, 0x03b9, 2, 0x1f82, 0x1f8a,
+ /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+ /* 144*/ 0x1f03, 0x03b9, 2, 0x1f83, 0x1f8b,
+ /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+ /* 149*/ 0x1f04, 0x03b9, 2, 0x1f84, 0x1f8c,
+ /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+ /* 154*/ 0x1f05, 0x03b9, 2, 0x1f85, 0x1f8d,
+ /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 159*/ 0x1f06, 0x03b9, 2, 0x1f86, 0x1f8e,
+ /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 164*/ 0x1f07, 0x03b9, 2, 0x1f87, 0x1f8f,
+ /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
+ /* 169*/ 0x1f20, 0x03b9, 2, 0x1f90, 0x1f98,
+ /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
+ /* 174*/ 0x1f21, 0x03b9, 2, 0x1f91, 0x1f99,
+ /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+ /* 179*/ 0x1f22, 0x03b9, 2, 0x1f92, 0x1f9a,
+ /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+ /* 184*/ 0x1f23, 0x03b9, 2, 0x1f93, 0x1f9b,
+ /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+ /* 189*/ 0x1f24, 0x03b9, 2, 0x1f94, 0x1f9c,
+ /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+ /* 194*/ 0x1f25, 0x03b9, 2, 0x1f95, 0x1f9d,
+ /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 199*/ 0x1f26, 0x03b9, 2, 0x1f96, 0x1f9e,
+ /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 204*/ 0x1f27, 0x03b9, 2, 0x1f97, 0x1f9f,
+ /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI */
+ /* 209*/ 0x1f60, 0x03b9, 2, 0x1fa0, 0x1fa8,
+ /* GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI */
+ /* 214*/ 0x1f61, 0x03b9, 2, 0x1fa1, 0x1fa9,
+ /* GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+ /* 219*/ 0x1f62, 0x03b9, 2, 0x1fa2, 0x1faa,
+ /* GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+ /* 224*/ 0x1f63, 0x03b9, 2, 0x1fa3, 0x1fab,
+ /* GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+ /* 229*/ 0x1f64, 0x03b9, 2, 0x1fa4, 0x1fac,
+ /* GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+ /* 234*/ 0x1f65, 0x03b9, 2, 0x1fa5, 0x1fad,
+ /* GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 239*/ 0x1f66, 0x03b9, 2, 0x1fa6, 0x1fae,
+ /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+ /* 244*/ 0x1f67, 0x03b9, 2, 0x1fa7, 0x1faf,
+ /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
+ /* 249*/ 0x1f70, 0x03b9, 1, 0x1fb2,
+ /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
+ /* 253*/ 0x1f74, 0x03b9, 1, 0x1fc2,
+ /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
+ /* 257*/ 0x1f7c, 0x03b9, 1, 0x1ff2,
+#define FOLDS2_NORMAL_END_INDEX 261
+ /* ----- LOCALE ----- */
+ /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ /* 261*/ 0x0069, 0x0307, 1, 0x0130,
+#define FOLDS2_END_INDEX 265
+};
+
+OnigCodePoint OnigUnicodeFolds3[] = {
+ /* LATIN SMALL LIGATURE FFI */
+ /* 0*/ 0x0066, 0x0066, 0x0069, 1, 0xfb03,
+ /* LATIN SMALL LIGATURE FFL */
+ /* 5*/ 0x0066, 0x0066, 0x006c, 1, 0xfb04,
+ /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
+ /* 10*/ 0x03b1, 0x0342, 0x03b9, 1, 0x1fb7,
+ /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
+ /* 15*/ 0x03b7, 0x0342, 0x03b9, 1, 0x1fc7,
+ /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
+ /* 20*/ 0x03b9, 0x0308, 0x0300, 1, 0x1fd2,
+ /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+ /* 25*/ 0x03b9, 0x0308, 0x0301, 2, 0x0390, 0x1fd3,
+ /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
+ /* 31*/ 0x03b9, 0x0308, 0x0342, 1, 0x1fd7,
+ /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
+ /* 36*/ 0x03c5, 0x0308, 0x0300, 1, 0x1fe2,
+ /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+ /* 41*/ 0x03c5, 0x0308, 0x0301, 2, 0x03b0, 0x1fe3,
+ /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
+ /* 47*/ 0x03c5, 0x0308, 0x0342, 1, 0x1fe7,
+ /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
+ /* 52*/ 0x03c5, 0x0313, 0x0300, 1, 0x1f52,
+ /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
+ /* 57*/ 0x03c5, 0x0313, 0x0301, 1, 0x1f54,
+ /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
+ /* 62*/ 0x03c5, 0x0313, 0x0342, 1, 0x1f56,
+ /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
+ /* 67*/ 0x03c9, 0x0342, 0x03b9, 1, 0x1ff7,
+#define FOLDS3_NORMAL_END_INDEX 72
+ /* ----- LOCALE ----- */
+#define FOLDS3_END_INDEX 72
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data.c
new file mode 100644
index 000000000..0083dd66b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data.c
@@ -0,0 +1,30389 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -T -C -c -t -j1 -L ANSI-C --ignore-case --pic -Q unicode_prop_name_pool -N unicode_lookup_property_name --output-file gperf1.tmp unicode_property_data.gperf */
+/* Computed positions: -k'1-3,5-6,12,16,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+
+
+/* Generated by make_unicode_property_data.py. */
+
+
+/* PROPERTY: 'NEWLINE': POSIX [[:NEWLINE:]] */
+static const OnigCodePoint
+CR_NEWLINE[] = { 1,
+0x000a, 0x000a,
+}; /* END of CR_NEWLINE */
+
+/* PROPERTY: 'Alpha': POSIX [[:Alpha:]] */
+static const OnigCodePoint
+CR_Alpha[] = { 679,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0345, 0x0345,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05b0, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0657,
+0x0659, 0x065f,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06e1, 0x06e8,
+0x06ed, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x073f,
+0x074d, 0x07b1,
+0x07ca, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0817,
+0x081a, 0x082c,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d4, 0x08df,
+0x08e3, 0x08e9,
+0x08f0, 0x093b,
+0x093d, 0x094c,
+0x094e, 0x0950,
+0x0955, 0x0963,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09ce, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4c,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a70, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0af9, 0x0afc,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0c00, 0x0c03,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4c,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccc,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e46,
+0x0e4d, 0x0e4d,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb9,
+0x0ebb, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ecd, 0x0ecd,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f81,
+0x0f88, 0x0f97,
+0x0f99, 0x0fbc,
+0x1000, 0x1036,
+0x1038, 0x1038,
+0x103b, 0x103f,
+0x1050, 0x108f,
+0x109a, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1713,
+0x1720, 0x1733,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17b3,
+0x17b6, 0x17c8,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x1938,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a61, 0x1a74,
+0x1aa7, 0x1aa7,
+0x1b00, 0x1b33,
+0x1b35, 0x1b43,
+0x1b45, 0x1b4b,
+0x1b80, 0x1ba9,
+0x1bac, 0x1baf,
+0x1bba, 0x1be5,
+0x1be7, 0x1bf1,
+0x1c00, 0x1c36,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1de7, 0x1df4,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa640, 0xa66e,
+0xa674, 0xa67b,
+0xa67f, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa805,
+0xa807, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c3,
+0xa8c5, 0xa8c5,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8ff,
+0xa90a, 0xa92a,
+0xa930, 0xa952,
+0xa960, 0xa97c,
+0xa980, 0xa9b2,
+0xa9b4, 0xa9bf,
+0xa9cf, 0xa9cf,
+0xa9e0, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa60, 0xaa76,
+0xaa7a, 0xaabe,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf5,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11000, 0x11045,
+0x11082, 0x110b8,
+0x110d0, 0x110e8,
+0x11100, 0x11132,
+0x11144, 0x11146,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11180, 0x111bf,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11234,
+0x11237, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112e8,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134c,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11400, 0x11441,
+0x11443, 0x11445,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114c1,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115b5,
+0x115b8, 0x115be,
+0x115d8, 0x115dd,
+0x11600, 0x1163e,
+0x11640, 0x11640,
+0x11644, 0x11644,
+0x11680, 0x116b5,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x1171d, 0x1172a,
+0x11800, 0x11838,
+0x118a0, 0x118df,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119df,
+0x119e1, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a32,
+0x11a35, 0x11a3e,
+0x11a50, 0x11a97,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c3e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d41,
+0x11d43, 0x11d43,
+0x11d46, 0x11d47,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d96,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9e, 0x1bc9e,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e947, 0x1e947,
+0x1e94b, 0x1e94b,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Alpha */
+
+/* PROPERTY: 'Blank': POSIX [[:Blank:]] */
+static const OnigCodePoint
+CR_Blank[] = { 8,
+0x0009, 0x0009,
+0x0020, 0x0020,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Blank */
+
+/* PROPERTY: 'Cntrl': POSIX [[:Cntrl:]] */
+static const OnigCodePoint
+CR_Cntrl[] = { 2,
+0x0000, 0x001f,
+0x007f, 0x009f,
+}; /* END of CR_Cntrl */
+
+/* PROPERTY: 'Digit': POSIX [[:Digit:]] */
+static const OnigCodePoint
+CR_Digit[] = { 59,
+0x0030, 0x0039,
+0x0660, 0x0669,
+0x06f0, 0x06f9,
+0x07c0, 0x07c9,
+0x0966, 0x096f,
+0x09e6, 0x09ef,
+0x0a66, 0x0a6f,
+0x0ae6, 0x0aef,
+0x0b66, 0x0b6f,
+0x0be6, 0x0bef,
+0x0c66, 0x0c6f,
+0x0ce6, 0x0cef,
+0x0d66, 0x0d6f,
+0x0de6, 0x0def,
+0x0e50, 0x0e59,
+0x0ed0, 0x0ed9,
+0x0f20, 0x0f29,
+0x1040, 0x1049,
+0x1090, 0x1099,
+0x17e0, 0x17e9,
+0x1810, 0x1819,
+0x1946, 0x194f,
+0x19d0, 0x19d9,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1b50, 0x1b59,
+0x1bb0, 0x1bb9,
+0x1c40, 0x1c49,
+0x1c50, 0x1c59,
+0xa620, 0xa629,
+0xa8d0, 0xa8d9,
+0xa900, 0xa909,
+0xa9d0, 0xa9d9,
+0xa9f0, 0xa9f9,
+0xaa50, 0xaa59,
+0xabf0, 0xabf9,
+0xff10, 0xff19,
+0x104a0, 0x104a9,
+0x10d30, 0x10d39,
+0x11066, 0x1106f,
+0x110f0, 0x110f9,
+0x11136, 0x1113f,
+0x111d0, 0x111d9,
+0x112f0, 0x112f9,
+0x11450, 0x11459,
+0x114d0, 0x114d9,
+0x11650, 0x11659,
+0x116c0, 0x116c9,
+0x11730, 0x11739,
+0x118e0, 0x118e9,
+0x11c50, 0x11c59,
+0x11d50, 0x11d59,
+0x11da0, 0x11da9,
+0x16a60, 0x16a69,
+0x16b50, 0x16b59,
+0x1d7ce, 0x1d7ff,
+0x1e140, 0x1e149,
+0x1e2f0, 0x1e2f9,
+0x1e950, 0x1e959,
+}; /* END of CR_Digit */
+
+/* PROPERTY: 'Graph': POSIX [[:Graph:]] */
+static const OnigCodePoint
+CR_Graph[] = { 671,
+0x0021, 0x007e,
+0x00a1, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0600, 0x061c,
+0x061e, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07fa,
+0x07fd, 0x082d,
+0x0830, 0x083e,
+0x0840, 0x085b,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e3a,
+0x0e3f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x167f,
+0x1681, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1736,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a1b,
+0x1a1e, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+0x1b80, 0x1bf3,
+0x1bfc, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd0, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x200b, 0x2027,
+0x202a, 0x202e,
+0x2030, 0x205e,
+0x2060, 0x2064,
+0x2066, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x20d0, 0x20f0,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3001, 0x303f,
+0x3041, 0x3096,
+0x3099, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+0xa8e0, 0xa953,
+0xa95f, 0xa97c,
+0xa980, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaac2,
+0xaadb, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xe000, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe00, 0xfe19,
+0xfe20, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xfeff, 0xfeff,
+0xff01, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d27,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x110c1,
+0x110cd, 0x110cd,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x11146,
+0x11150, 0x11176,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+0x11600, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+0x11800, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+0x11a00, 0x11a47,
+0x11a50, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d1e8,
+0x1d200, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Graph */
+
+/* PROPERTY: 'Lower': POSIX [[:Lower:]] */
+static const OnigCodePoint
+CR_Lower[] = { 649,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00df, 0x00f6,
+0x00f8, 0x00ff,
+0x0101, 0x0101,
+0x0103, 0x0103,
+0x0105, 0x0105,
+0x0107, 0x0107,
+0x0109, 0x0109,
+0x010b, 0x010b,
+0x010d, 0x010d,
+0x010f, 0x010f,
+0x0111, 0x0111,
+0x0113, 0x0113,
+0x0115, 0x0115,
+0x0117, 0x0117,
+0x0119, 0x0119,
+0x011b, 0x011b,
+0x011d, 0x011d,
+0x011f, 0x011f,
+0x0121, 0x0121,
+0x0123, 0x0123,
+0x0125, 0x0125,
+0x0127, 0x0127,
+0x0129, 0x0129,
+0x012b, 0x012b,
+0x012d, 0x012d,
+0x012f, 0x012f,
+0x0131, 0x0131,
+0x0133, 0x0133,
+0x0135, 0x0135,
+0x0137, 0x0138,
+0x013a, 0x013a,
+0x013c, 0x013c,
+0x013e, 0x013e,
+0x0140, 0x0140,
+0x0142, 0x0142,
+0x0144, 0x0144,
+0x0146, 0x0146,
+0x0148, 0x0149,
+0x014b, 0x014b,
+0x014d, 0x014d,
+0x014f, 0x014f,
+0x0151, 0x0151,
+0x0153, 0x0153,
+0x0155, 0x0155,
+0x0157, 0x0157,
+0x0159, 0x0159,
+0x015b, 0x015b,
+0x015d, 0x015d,
+0x015f, 0x015f,
+0x0161, 0x0161,
+0x0163, 0x0163,
+0x0165, 0x0165,
+0x0167, 0x0167,
+0x0169, 0x0169,
+0x016b, 0x016b,
+0x016d, 0x016d,
+0x016f, 0x016f,
+0x0171, 0x0171,
+0x0173, 0x0173,
+0x0175, 0x0175,
+0x0177, 0x0177,
+0x017a, 0x017a,
+0x017c, 0x017c,
+0x017e, 0x0180,
+0x0183, 0x0183,
+0x0185, 0x0185,
+0x0188, 0x0188,
+0x018c, 0x018d,
+0x0192, 0x0192,
+0x0195, 0x0195,
+0x0199, 0x019b,
+0x019e, 0x019e,
+0x01a1, 0x01a1,
+0x01a3, 0x01a3,
+0x01a5, 0x01a5,
+0x01a8, 0x01a8,
+0x01aa, 0x01ab,
+0x01ad, 0x01ad,
+0x01b0, 0x01b0,
+0x01b4, 0x01b4,
+0x01b6, 0x01b6,
+0x01b9, 0x01ba,
+0x01bd, 0x01bf,
+0x01c6, 0x01c6,
+0x01c9, 0x01c9,
+0x01cc, 0x01cc,
+0x01ce, 0x01ce,
+0x01d0, 0x01d0,
+0x01d2, 0x01d2,
+0x01d4, 0x01d4,
+0x01d6, 0x01d6,
+0x01d8, 0x01d8,
+0x01da, 0x01da,
+0x01dc, 0x01dd,
+0x01df, 0x01df,
+0x01e1, 0x01e1,
+0x01e3, 0x01e3,
+0x01e5, 0x01e5,
+0x01e7, 0x01e7,
+0x01e9, 0x01e9,
+0x01eb, 0x01eb,
+0x01ed, 0x01ed,
+0x01ef, 0x01f0,
+0x01f3, 0x01f3,
+0x01f5, 0x01f5,
+0x01f9, 0x01f9,
+0x01fb, 0x01fb,
+0x01fd, 0x01fd,
+0x01ff, 0x01ff,
+0x0201, 0x0201,
+0x0203, 0x0203,
+0x0205, 0x0205,
+0x0207, 0x0207,
+0x0209, 0x0209,
+0x020b, 0x020b,
+0x020d, 0x020d,
+0x020f, 0x020f,
+0x0211, 0x0211,
+0x0213, 0x0213,
+0x0215, 0x0215,
+0x0217, 0x0217,
+0x0219, 0x0219,
+0x021b, 0x021b,
+0x021d, 0x021d,
+0x021f, 0x021f,
+0x0221, 0x0221,
+0x0223, 0x0223,
+0x0225, 0x0225,
+0x0227, 0x0227,
+0x0229, 0x0229,
+0x022b, 0x022b,
+0x022d, 0x022d,
+0x022f, 0x022f,
+0x0231, 0x0231,
+0x0233, 0x0239,
+0x023c, 0x023c,
+0x023f, 0x0240,
+0x0242, 0x0242,
+0x0247, 0x0247,
+0x0249, 0x0249,
+0x024b, 0x024b,
+0x024d, 0x024d,
+0x024f, 0x0293,
+0x0295, 0x02b8,
+0x02c0, 0x02c1,
+0x02e0, 0x02e4,
+0x0345, 0x0345,
+0x0371, 0x0371,
+0x0373, 0x0373,
+0x0377, 0x0377,
+0x037a, 0x037d,
+0x0390, 0x0390,
+0x03ac, 0x03ce,
+0x03d0, 0x03d1,
+0x03d5, 0x03d7,
+0x03d9, 0x03d9,
+0x03db, 0x03db,
+0x03dd, 0x03dd,
+0x03df, 0x03df,
+0x03e1, 0x03e1,
+0x03e3, 0x03e3,
+0x03e5, 0x03e5,
+0x03e7, 0x03e7,
+0x03e9, 0x03e9,
+0x03eb, 0x03eb,
+0x03ed, 0x03ed,
+0x03ef, 0x03f3,
+0x03f5, 0x03f5,
+0x03f8, 0x03f8,
+0x03fb, 0x03fc,
+0x0430, 0x045f,
+0x0461, 0x0461,
+0x0463, 0x0463,
+0x0465, 0x0465,
+0x0467, 0x0467,
+0x0469, 0x0469,
+0x046b, 0x046b,
+0x046d, 0x046d,
+0x046f, 0x046f,
+0x0471, 0x0471,
+0x0473, 0x0473,
+0x0475, 0x0475,
+0x0477, 0x0477,
+0x0479, 0x0479,
+0x047b, 0x047b,
+0x047d, 0x047d,
+0x047f, 0x047f,
+0x0481, 0x0481,
+0x048b, 0x048b,
+0x048d, 0x048d,
+0x048f, 0x048f,
+0x0491, 0x0491,
+0x0493, 0x0493,
+0x0495, 0x0495,
+0x0497, 0x0497,
+0x0499, 0x0499,
+0x049b, 0x049b,
+0x049d, 0x049d,
+0x049f, 0x049f,
+0x04a1, 0x04a1,
+0x04a3, 0x04a3,
+0x04a5, 0x04a5,
+0x04a7, 0x04a7,
+0x04a9, 0x04a9,
+0x04ab, 0x04ab,
+0x04ad, 0x04ad,
+0x04af, 0x04af,
+0x04b1, 0x04b1,
+0x04b3, 0x04b3,
+0x04b5, 0x04b5,
+0x04b7, 0x04b7,
+0x04b9, 0x04b9,
+0x04bb, 0x04bb,
+0x04bd, 0x04bd,
+0x04bf, 0x04bf,
+0x04c2, 0x04c2,
+0x04c4, 0x04c4,
+0x04c6, 0x04c6,
+0x04c8, 0x04c8,
+0x04ca, 0x04ca,
+0x04cc, 0x04cc,
+0x04ce, 0x04cf,
+0x04d1, 0x04d1,
+0x04d3, 0x04d3,
+0x04d5, 0x04d5,
+0x04d7, 0x04d7,
+0x04d9, 0x04d9,
+0x04db, 0x04db,
+0x04dd, 0x04dd,
+0x04df, 0x04df,
+0x04e1, 0x04e1,
+0x04e3, 0x04e3,
+0x04e5, 0x04e5,
+0x04e7, 0x04e7,
+0x04e9, 0x04e9,
+0x04eb, 0x04eb,
+0x04ed, 0x04ed,
+0x04ef, 0x04ef,
+0x04f1, 0x04f1,
+0x04f3, 0x04f3,
+0x04f5, 0x04f5,
+0x04f7, 0x04f7,
+0x04f9, 0x04f9,
+0x04fb, 0x04fb,
+0x04fd, 0x04fd,
+0x04ff, 0x04ff,
+0x0501, 0x0501,
+0x0503, 0x0503,
+0x0505, 0x0505,
+0x0507, 0x0507,
+0x0509, 0x0509,
+0x050b, 0x050b,
+0x050d, 0x050d,
+0x050f, 0x050f,
+0x0511, 0x0511,
+0x0513, 0x0513,
+0x0515, 0x0515,
+0x0517, 0x0517,
+0x0519, 0x0519,
+0x051b, 0x051b,
+0x051d, 0x051d,
+0x051f, 0x051f,
+0x0521, 0x0521,
+0x0523, 0x0523,
+0x0525, 0x0525,
+0x0527, 0x0527,
+0x0529, 0x0529,
+0x052b, 0x052b,
+0x052d, 0x052d,
+0x052f, 0x052f,
+0x0560, 0x0588,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1d00, 0x1dbf,
+0x1e01, 0x1e01,
+0x1e03, 0x1e03,
+0x1e05, 0x1e05,
+0x1e07, 0x1e07,
+0x1e09, 0x1e09,
+0x1e0b, 0x1e0b,
+0x1e0d, 0x1e0d,
+0x1e0f, 0x1e0f,
+0x1e11, 0x1e11,
+0x1e13, 0x1e13,
+0x1e15, 0x1e15,
+0x1e17, 0x1e17,
+0x1e19, 0x1e19,
+0x1e1b, 0x1e1b,
+0x1e1d, 0x1e1d,
+0x1e1f, 0x1e1f,
+0x1e21, 0x1e21,
+0x1e23, 0x1e23,
+0x1e25, 0x1e25,
+0x1e27, 0x1e27,
+0x1e29, 0x1e29,
+0x1e2b, 0x1e2b,
+0x1e2d, 0x1e2d,
+0x1e2f, 0x1e2f,
+0x1e31, 0x1e31,
+0x1e33, 0x1e33,
+0x1e35, 0x1e35,
+0x1e37, 0x1e37,
+0x1e39, 0x1e39,
+0x1e3b, 0x1e3b,
+0x1e3d, 0x1e3d,
+0x1e3f, 0x1e3f,
+0x1e41, 0x1e41,
+0x1e43, 0x1e43,
+0x1e45, 0x1e45,
+0x1e47, 0x1e47,
+0x1e49, 0x1e49,
+0x1e4b, 0x1e4b,
+0x1e4d, 0x1e4d,
+0x1e4f, 0x1e4f,
+0x1e51, 0x1e51,
+0x1e53, 0x1e53,
+0x1e55, 0x1e55,
+0x1e57, 0x1e57,
+0x1e59, 0x1e59,
+0x1e5b, 0x1e5b,
+0x1e5d, 0x1e5d,
+0x1e5f, 0x1e5f,
+0x1e61, 0x1e61,
+0x1e63, 0x1e63,
+0x1e65, 0x1e65,
+0x1e67, 0x1e67,
+0x1e69, 0x1e69,
+0x1e6b, 0x1e6b,
+0x1e6d, 0x1e6d,
+0x1e6f, 0x1e6f,
+0x1e71, 0x1e71,
+0x1e73, 0x1e73,
+0x1e75, 0x1e75,
+0x1e77, 0x1e77,
+0x1e79, 0x1e79,
+0x1e7b, 0x1e7b,
+0x1e7d, 0x1e7d,
+0x1e7f, 0x1e7f,
+0x1e81, 0x1e81,
+0x1e83, 0x1e83,
+0x1e85, 0x1e85,
+0x1e87, 0x1e87,
+0x1e89, 0x1e89,
+0x1e8b, 0x1e8b,
+0x1e8d, 0x1e8d,
+0x1e8f, 0x1e8f,
+0x1e91, 0x1e91,
+0x1e93, 0x1e93,
+0x1e95, 0x1e9d,
+0x1e9f, 0x1e9f,
+0x1ea1, 0x1ea1,
+0x1ea3, 0x1ea3,
+0x1ea5, 0x1ea5,
+0x1ea7, 0x1ea7,
+0x1ea9, 0x1ea9,
+0x1eab, 0x1eab,
+0x1ead, 0x1ead,
+0x1eaf, 0x1eaf,
+0x1eb1, 0x1eb1,
+0x1eb3, 0x1eb3,
+0x1eb5, 0x1eb5,
+0x1eb7, 0x1eb7,
+0x1eb9, 0x1eb9,
+0x1ebb, 0x1ebb,
+0x1ebd, 0x1ebd,
+0x1ebf, 0x1ebf,
+0x1ec1, 0x1ec1,
+0x1ec3, 0x1ec3,
+0x1ec5, 0x1ec5,
+0x1ec7, 0x1ec7,
+0x1ec9, 0x1ec9,
+0x1ecb, 0x1ecb,
+0x1ecd, 0x1ecd,
+0x1ecf, 0x1ecf,
+0x1ed1, 0x1ed1,
+0x1ed3, 0x1ed3,
+0x1ed5, 0x1ed5,
+0x1ed7, 0x1ed7,
+0x1ed9, 0x1ed9,
+0x1edb, 0x1edb,
+0x1edd, 0x1edd,
+0x1edf, 0x1edf,
+0x1ee1, 0x1ee1,
+0x1ee3, 0x1ee3,
+0x1ee5, 0x1ee5,
+0x1ee7, 0x1ee7,
+0x1ee9, 0x1ee9,
+0x1eeb, 0x1eeb,
+0x1eed, 0x1eed,
+0x1eef, 0x1eef,
+0x1ef1, 0x1ef1,
+0x1ef3, 0x1ef3,
+0x1ef5, 0x1ef5,
+0x1ef7, 0x1ef7,
+0x1ef9, 0x1ef9,
+0x1efb, 0x1efb,
+0x1efd, 0x1efd,
+0x1eff, 0x1f07,
+0x1f10, 0x1f15,
+0x1f20, 0x1f27,
+0x1f30, 0x1f37,
+0x1f40, 0x1f45,
+0x1f50, 0x1f57,
+0x1f60, 0x1f67,
+0x1f70, 0x1f7d,
+0x1f80, 0x1f87,
+0x1f90, 0x1f97,
+0x1fa0, 0x1fa7,
+0x1fb0, 0x1fb4,
+0x1fb6, 0x1fb7,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fc7,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fd7,
+0x1fe0, 0x1fe7,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ff7,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x210a, 0x210a,
+0x210e, 0x210f,
+0x2113, 0x2113,
+0x212f, 0x212f,
+0x2134, 0x2134,
+0x2139, 0x2139,
+0x213c, 0x213d,
+0x2146, 0x2149,
+0x214e, 0x214e,
+0x2170, 0x217f,
+0x2184, 0x2184,
+0x24d0, 0x24e9,
+0x2c30, 0x2c5e,
+0x2c61, 0x2c61,
+0x2c65, 0x2c66,
+0x2c68, 0x2c68,
+0x2c6a, 0x2c6a,
+0x2c6c, 0x2c6c,
+0x2c71, 0x2c71,
+0x2c73, 0x2c74,
+0x2c76, 0x2c7d,
+0x2c81, 0x2c81,
+0x2c83, 0x2c83,
+0x2c85, 0x2c85,
+0x2c87, 0x2c87,
+0x2c89, 0x2c89,
+0x2c8b, 0x2c8b,
+0x2c8d, 0x2c8d,
+0x2c8f, 0x2c8f,
+0x2c91, 0x2c91,
+0x2c93, 0x2c93,
+0x2c95, 0x2c95,
+0x2c97, 0x2c97,
+0x2c99, 0x2c99,
+0x2c9b, 0x2c9b,
+0x2c9d, 0x2c9d,
+0x2c9f, 0x2c9f,
+0x2ca1, 0x2ca1,
+0x2ca3, 0x2ca3,
+0x2ca5, 0x2ca5,
+0x2ca7, 0x2ca7,
+0x2ca9, 0x2ca9,
+0x2cab, 0x2cab,
+0x2cad, 0x2cad,
+0x2caf, 0x2caf,
+0x2cb1, 0x2cb1,
+0x2cb3, 0x2cb3,
+0x2cb5, 0x2cb5,
+0x2cb7, 0x2cb7,
+0x2cb9, 0x2cb9,
+0x2cbb, 0x2cbb,
+0x2cbd, 0x2cbd,
+0x2cbf, 0x2cbf,
+0x2cc1, 0x2cc1,
+0x2cc3, 0x2cc3,
+0x2cc5, 0x2cc5,
+0x2cc7, 0x2cc7,
+0x2cc9, 0x2cc9,
+0x2ccb, 0x2ccb,
+0x2ccd, 0x2ccd,
+0x2ccf, 0x2ccf,
+0x2cd1, 0x2cd1,
+0x2cd3, 0x2cd3,
+0x2cd5, 0x2cd5,
+0x2cd7, 0x2cd7,
+0x2cd9, 0x2cd9,
+0x2cdb, 0x2cdb,
+0x2cdd, 0x2cdd,
+0x2cdf, 0x2cdf,
+0x2ce1, 0x2ce1,
+0x2ce3, 0x2ce4,
+0x2cec, 0x2cec,
+0x2cee, 0x2cee,
+0x2cf3, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa641, 0xa641,
+0xa643, 0xa643,
+0xa645, 0xa645,
+0xa647, 0xa647,
+0xa649, 0xa649,
+0xa64b, 0xa64b,
+0xa64d, 0xa64d,
+0xa64f, 0xa64f,
+0xa651, 0xa651,
+0xa653, 0xa653,
+0xa655, 0xa655,
+0xa657, 0xa657,
+0xa659, 0xa659,
+0xa65b, 0xa65b,
+0xa65d, 0xa65d,
+0xa65f, 0xa65f,
+0xa661, 0xa661,
+0xa663, 0xa663,
+0xa665, 0xa665,
+0xa667, 0xa667,
+0xa669, 0xa669,
+0xa66b, 0xa66b,
+0xa66d, 0xa66d,
+0xa681, 0xa681,
+0xa683, 0xa683,
+0xa685, 0xa685,
+0xa687, 0xa687,
+0xa689, 0xa689,
+0xa68b, 0xa68b,
+0xa68d, 0xa68d,
+0xa68f, 0xa68f,
+0xa691, 0xa691,
+0xa693, 0xa693,
+0xa695, 0xa695,
+0xa697, 0xa697,
+0xa699, 0xa699,
+0xa69b, 0xa69d,
+0xa723, 0xa723,
+0xa725, 0xa725,
+0xa727, 0xa727,
+0xa729, 0xa729,
+0xa72b, 0xa72b,
+0xa72d, 0xa72d,
+0xa72f, 0xa731,
+0xa733, 0xa733,
+0xa735, 0xa735,
+0xa737, 0xa737,
+0xa739, 0xa739,
+0xa73b, 0xa73b,
+0xa73d, 0xa73d,
+0xa73f, 0xa73f,
+0xa741, 0xa741,
+0xa743, 0xa743,
+0xa745, 0xa745,
+0xa747, 0xa747,
+0xa749, 0xa749,
+0xa74b, 0xa74b,
+0xa74d, 0xa74d,
+0xa74f, 0xa74f,
+0xa751, 0xa751,
+0xa753, 0xa753,
+0xa755, 0xa755,
+0xa757, 0xa757,
+0xa759, 0xa759,
+0xa75b, 0xa75b,
+0xa75d, 0xa75d,
+0xa75f, 0xa75f,
+0xa761, 0xa761,
+0xa763, 0xa763,
+0xa765, 0xa765,
+0xa767, 0xa767,
+0xa769, 0xa769,
+0xa76b, 0xa76b,
+0xa76d, 0xa76d,
+0xa76f, 0xa778,
+0xa77a, 0xa77a,
+0xa77c, 0xa77c,
+0xa77f, 0xa77f,
+0xa781, 0xa781,
+0xa783, 0xa783,
+0xa785, 0xa785,
+0xa787, 0xa787,
+0xa78c, 0xa78c,
+0xa78e, 0xa78e,
+0xa791, 0xa791,
+0xa793, 0xa795,
+0xa797, 0xa797,
+0xa799, 0xa799,
+0xa79b, 0xa79b,
+0xa79d, 0xa79d,
+0xa79f, 0xa79f,
+0xa7a1, 0xa7a1,
+0xa7a3, 0xa7a3,
+0xa7a5, 0xa7a5,
+0xa7a7, 0xa7a7,
+0xa7a9, 0xa7a9,
+0xa7af, 0xa7af,
+0xa7b5, 0xa7b5,
+0xa7b7, 0xa7b7,
+0xa7b9, 0xa7b9,
+0xa7bb, 0xa7bb,
+0xa7bd, 0xa7bd,
+0xa7bf, 0xa7bf,
+0xa7c3, 0xa7c3,
+0xa7f8, 0xa7fa,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff41, 0xff5a,
+0x10428, 0x1044f,
+0x104d8, 0x104fb,
+0x10cc0, 0x10cf2,
+0x118c0, 0x118df,
+0x16e60, 0x16e7f,
+0x1d41a, 0x1d433,
+0x1d44e, 0x1d454,
+0x1d456, 0x1d467,
+0x1d482, 0x1d49b,
+0x1d4b6, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d4cf,
+0x1d4ea, 0x1d503,
+0x1d51e, 0x1d537,
+0x1d552, 0x1d56b,
+0x1d586, 0x1d59f,
+0x1d5ba, 0x1d5d3,
+0x1d5ee, 0x1d607,
+0x1d622, 0x1d63b,
+0x1d656, 0x1d66f,
+0x1d68a, 0x1d6a5,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6e1,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d71b,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d755,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d78f,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7c9,
+0x1d7cb, 0x1d7cb,
+0x1e922, 0x1e943,
+}; /* END of CR_Lower */
+
+/* PROPERTY: 'Print': POSIX [[:Print:]] */
+static const OnigCodePoint
+CR_Print[] = { 668,
+0x0020, 0x007e,
+0x00a0, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0600, 0x061c,
+0x061e, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07fa,
+0x07fd, 0x082d,
+0x0830, 0x083e,
+0x0840, 0x085b,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e3a,
+0x0e3f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1736,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a1b,
+0x1a1e, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+0x1b80, 0x1bf3,
+0x1bfc, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd0, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x2000, 0x2027,
+0x202a, 0x2064,
+0x2066, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x20d0, 0x20f0,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3000, 0x303f,
+0x3041, 0x3096,
+0x3099, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+0xa8e0, 0xa953,
+0xa95f, 0xa97c,
+0xa980, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaac2,
+0xaadb, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xe000, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe00, 0xfe19,
+0xfe20, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xfeff, 0xfeff,
+0xff01, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d27,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x110c1,
+0x110cd, 0x110cd,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x11146,
+0x11150, 0x11176,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+0x11600, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+0x11800, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+0x11a00, 0x11a47,
+0x11a50, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d1e8,
+0x1d200, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Print */
+
+/* PROPERTY: 'Punct': POSIX [[:Punct:]] */
+static const OnigCodePoint
+CR_Punct[] = { 182,
+0x0021, 0x0023,
+0x0025, 0x002a,
+0x002c, 0x002f,
+0x003a, 0x003b,
+0x003f, 0x0040,
+0x005b, 0x005d,
+0x005f, 0x005f,
+0x007b, 0x007b,
+0x007d, 0x007d,
+0x00a1, 0x00a1,
+0x00a7, 0x00a7,
+0x00ab, 0x00ab,
+0x00b6, 0x00b7,
+0x00bb, 0x00bb,
+0x00bf, 0x00bf,
+0x037e, 0x037e,
+0x0387, 0x0387,
+0x055a, 0x055f,
+0x0589, 0x058a,
+0x05be, 0x05be,
+0x05c0, 0x05c0,
+0x05c3, 0x05c3,
+0x05c6, 0x05c6,
+0x05f3, 0x05f4,
+0x0609, 0x060a,
+0x060c, 0x060d,
+0x061b, 0x061b,
+0x061e, 0x061f,
+0x066a, 0x066d,
+0x06d4, 0x06d4,
+0x0700, 0x070d,
+0x07f7, 0x07f9,
+0x0830, 0x083e,
+0x085e, 0x085e,
+0x0964, 0x0965,
+0x0970, 0x0970,
+0x09fd, 0x09fd,
+0x0a76, 0x0a76,
+0x0af0, 0x0af0,
+0x0c77, 0x0c77,
+0x0c84, 0x0c84,
+0x0df4, 0x0df4,
+0x0e4f, 0x0e4f,
+0x0e5a, 0x0e5b,
+0x0f04, 0x0f12,
+0x0f14, 0x0f14,
+0x0f3a, 0x0f3d,
+0x0f85, 0x0f85,
+0x0fd0, 0x0fd4,
+0x0fd9, 0x0fda,
+0x104a, 0x104f,
+0x10fb, 0x10fb,
+0x1360, 0x1368,
+0x1400, 0x1400,
+0x166e, 0x166e,
+0x169b, 0x169c,
+0x16eb, 0x16ed,
+0x1735, 0x1736,
+0x17d4, 0x17d6,
+0x17d8, 0x17da,
+0x1800, 0x180a,
+0x1944, 0x1945,
+0x1a1e, 0x1a1f,
+0x1aa0, 0x1aa6,
+0x1aa8, 0x1aad,
+0x1b5a, 0x1b60,
+0x1bfc, 0x1bff,
+0x1c3b, 0x1c3f,
+0x1c7e, 0x1c7f,
+0x1cc0, 0x1cc7,
+0x1cd3, 0x1cd3,
+0x2010, 0x2027,
+0x2030, 0x2043,
+0x2045, 0x2051,
+0x2053, 0x205e,
+0x207d, 0x207e,
+0x208d, 0x208e,
+0x2308, 0x230b,
+0x2329, 0x232a,
+0x2768, 0x2775,
+0x27c5, 0x27c6,
+0x27e6, 0x27ef,
+0x2983, 0x2998,
+0x29d8, 0x29db,
+0x29fc, 0x29fd,
+0x2cf9, 0x2cfc,
+0x2cfe, 0x2cff,
+0x2d70, 0x2d70,
+0x2e00, 0x2e2e,
+0x2e30, 0x2e4f,
+0x3001, 0x3003,
+0x3008, 0x3011,
+0x3014, 0x301f,
+0x3030, 0x3030,
+0x303d, 0x303d,
+0x30a0, 0x30a0,
+0x30fb, 0x30fb,
+0xa4fe, 0xa4ff,
+0xa60d, 0xa60f,
+0xa673, 0xa673,
+0xa67e, 0xa67e,
+0xa6f2, 0xa6f7,
+0xa874, 0xa877,
+0xa8ce, 0xa8cf,
+0xa8f8, 0xa8fa,
+0xa8fc, 0xa8fc,
+0xa92e, 0xa92f,
+0xa95f, 0xa95f,
+0xa9c1, 0xa9cd,
+0xa9de, 0xa9df,
+0xaa5c, 0xaa5f,
+0xaade, 0xaadf,
+0xaaf0, 0xaaf1,
+0xabeb, 0xabeb,
+0xfd3e, 0xfd3f,
+0xfe10, 0xfe19,
+0xfe30, 0xfe52,
+0xfe54, 0xfe61,
+0xfe63, 0xfe63,
+0xfe68, 0xfe68,
+0xfe6a, 0xfe6b,
+0xff01, 0xff03,
+0xff05, 0xff0a,
+0xff0c, 0xff0f,
+0xff1a, 0xff1b,
+0xff1f, 0xff20,
+0xff3b, 0xff3d,
+0xff3f, 0xff3f,
+0xff5b, 0xff5b,
+0xff5d, 0xff5d,
+0xff5f, 0xff65,
+0x10100, 0x10102,
+0x1039f, 0x1039f,
+0x103d0, 0x103d0,
+0x1056f, 0x1056f,
+0x10857, 0x10857,
+0x1091f, 0x1091f,
+0x1093f, 0x1093f,
+0x10a50, 0x10a58,
+0x10a7f, 0x10a7f,
+0x10af0, 0x10af6,
+0x10b39, 0x10b3f,
+0x10b99, 0x10b9c,
+0x10f55, 0x10f59,
+0x11047, 0x1104d,
+0x110bb, 0x110bc,
+0x110be, 0x110c1,
+0x11140, 0x11143,
+0x11174, 0x11175,
+0x111c5, 0x111c8,
+0x111cd, 0x111cd,
+0x111db, 0x111db,
+0x111dd, 0x111df,
+0x11238, 0x1123d,
+0x112a9, 0x112a9,
+0x1144b, 0x1144f,
+0x1145b, 0x1145b,
+0x1145d, 0x1145d,
+0x114c6, 0x114c6,
+0x115c1, 0x115d7,
+0x11641, 0x11643,
+0x11660, 0x1166c,
+0x1173c, 0x1173e,
+0x1183b, 0x1183b,
+0x119e2, 0x119e2,
+0x11a3f, 0x11a46,
+0x11a9a, 0x11a9c,
+0x11a9e, 0x11aa2,
+0x11c41, 0x11c45,
+0x11c70, 0x11c71,
+0x11ef7, 0x11ef8,
+0x11fff, 0x11fff,
+0x12470, 0x12474,
+0x16a6e, 0x16a6f,
+0x16af5, 0x16af5,
+0x16b37, 0x16b3b,
+0x16b44, 0x16b44,
+0x16e97, 0x16e9a,
+0x16fe2, 0x16fe2,
+0x1bc9f, 0x1bc9f,
+0x1da87, 0x1da8b,
+0x1e95e, 0x1e95f,
+}; /* END of CR_Punct */
+
+/* PROPERTY: 'Space': POSIX [[:Space:]] */
+static const OnigCodePoint
+CR_Space[] = { 10,
+0x0009, 0x000d,
+0x0020, 0x0020,
+0x0085, 0x0085,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x2028, 0x2029,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Space */
+
+/* PROPERTY: 'Upper': POSIX [[:Upper:]] */
+static const OnigCodePoint
+CR_Upper[] = { 641,
+0x0041, 0x005a,
+0x00c0, 0x00d6,
+0x00d8, 0x00de,
+0x0100, 0x0100,
+0x0102, 0x0102,
+0x0104, 0x0104,
+0x0106, 0x0106,
+0x0108, 0x0108,
+0x010a, 0x010a,
+0x010c, 0x010c,
+0x010e, 0x010e,
+0x0110, 0x0110,
+0x0112, 0x0112,
+0x0114, 0x0114,
+0x0116, 0x0116,
+0x0118, 0x0118,
+0x011a, 0x011a,
+0x011c, 0x011c,
+0x011e, 0x011e,
+0x0120, 0x0120,
+0x0122, 0x0122,
+0x0124, 0x0124,
+0x0126, 0x0126,
+0x0128, 0x0128,
+0x012a, 0x012a,
+0x012c, 0x012c,
+0x012e, 0x012e,
+0x0130, 0x0130,
+0x0132, 0x0132,
+0x0134, 0x0134,
+0x0136, 0x0136,
+0x0139, 0x0139,
+0x013b, 0x013b,
+0x013d, 0x013d,
+0x013f, 0x013f,
+0x0141, 0x0141,
+0x0143, 0x0143,
+0x0145, 0x0145,
+0x0147, 0x0147,
+0x014a, 0x014a,
+0x014c, 0x014c,
+0x014e, 0x014e,
+0x0150, 0x0150,
+0x0152, 0x0152,
+0x0154, 0x0154,
+0x0156, 0x0156,
+0x0158, 0x0158,
+0x015a, 0x015a,
+0x015c, 0x015c,
+0x015e, 0x015e,
+0x0160, 0x0160,
+0x0162, 0x0162,
+0x0164, 0x0164,
+0x0166, 0x0166,
+0x0168, 0x0168,
+0x016a, 0x016a,
+0x016c, 0x016c,
+0x016e, 0x016e,
+0x0170, 0x0170,
+0x0172, 0x0172,
+0x0174, 0x0174,
+0x0176, 0x0176,
+0x0178, 0x0179,
+0x017b, 0x017b,
+0x017d, 0x017d,
+0x0181, 0x0182,
+0x0184, 0x0184,
+0x0186, 0x0187,
+0x0189, 0x018b,
+0x018e, 0x0191,
+0x0193, 0x0194,
+0x0196, 0x0198,
+0x019c, 0x019d,
+0x019f, 0x01a0,
+0x01a2, 0x01a2,
+0x01a4, 0x01a4,
+0x01a6, 0x01a7,
+0x01a9, 0x01a9,
+0x01ac, 0x01ac,
+0x01ae, 0x01af,
+0x01b1, 0x01b3,
+0x01b5, 0x01b5,
+0x01b7, 0x01b8,
+0x01bc, 0x01bc,
+0x01c4, 0x01c4,
+0x01c7, 0x01c7,
+0x01ca, 0x01ca,
+0x01cd, 0x01cd,
+0x01cf, 0x01cf,
+0x01d1, 0x01d1,
+0x01d3, 0x01d3,
+0x01d5, 0x01d5,
+0x01d7, 0x01d7,
+0x01d9, 0x01d9,
+0x01db, 0x01db,
+0x01de, 0x01de,
+0x01e0, 0x01e0,
+0x01e2, 0x01e2,
+0x01e4, 0x01e4,
+0x01e6, 0x01e6,
+0x01e8, 0x01e8,
+0x01ea, 0x01ea,
+0x01ec, 0x01ec,
+0x01ee, 0x01ee,
+0x01f1, 0x01f1,
+0x01f4, 0x01f4,
+0x01f6, 0x01f8,
+0x01fa, 0x01fa,
+0x01fc, 0x01fc,
+0x01fe, 0x01fe,
+0x0200, 0x0200,
+0x0202, 0x0202,
+0x0204, 0x0204,
+0x0206, 0x0206,
+0x0208, 0x0208,
+0x020a, 0x020a,
+0x020c, 0x020c,
+0x020e, 0x020e,
+0x0210, 0x0210,
+0x0212, 0x0212,
+0x0214, 0x0214,
+0x0216, 0x0216,
+0x0218, 0x0218,
+0x021a, 0x021a,
+0x021c, 0x021c,
+0x021e, 0x021e,
+0x0220, 0x0220,
+0x0222, 0x0222,
+0x0224, 0x0224,
+0x0226, 0x0226,
+0x0228, 0x0228,
+0x022a, 0x022a,
+0x022c, 0x022c,
+0x022e, 0x022e,
+0x0230, 0x0230,
+0x0232, 0x0232,
+0x023a, 0x023b,
+0x023d, 0x023e,
+0x0241, 0x0241,
+0x0243, 0x0246,
+0x0248, 0x0248,
+0x024a, 0x024a,
+0x024c, 0x024c,
+0x024e, 0x024e,
+0x0370, 0x0370,
+0x0372, 0x0372,
+0x0376, 0x0376,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x038f,
+0x0391, 0x03a1,
+0x03a3, 0x03ab,
+0x03cf, 0x03cf,
+0x03d2, 0x03d4,
+0x03d8, 0x03d8,
+0x03da, 0x03da,
+0x03dc, 0x03dc,
+0x03de, 0x03de,
+0x03e0, 0x03e0,
+0x03e2, 0x03e2,
+0x03e4, 0x03e4,
+0x03e6, 0x03e6,
+0x03e8, 0x03e8,
+0x03ea, 0x03ea,
+0x03ec, 0x03ec,
+0x03ee, 0x03ee,
+0x03f4, 0x03f4,
+0x03f7, 0x03f7,
+0x03f9, 0x03fa,
+0x03fd, 0x042f,
+0x0460, 0x0460,
+0x0462, 0x0462,
+0x0464, 0x0464,
+0x0466, 0x0466,
+0x0468, 0x0468,
+0x046a, 0x046a,
+0x046c, 0x046c,
+0x046e, 0x046e,
+0x0470, 0x0470,
+0x0472, 0x0472,
+0x0474, 0x0474,
+0x0476, 0x0476,
+0x0478, 0x0478,
+0x047a, 0x047a,
+0x047c, 0x047c,
+0x047e, 0x047e,
+0x0480, 0x0480,
+0x048a, 0x048a,
+0x048c, 0x048c,
+0x048e, 0x048e,
+0x0490, 0x0490,
+0x0492, 0x0492,
+0x0494, 0x0494,
+0x0496, 0x0496,
+0x0498, 0x0498,
+0x049a, 0x049a,
+0x049c, 0x049c,
+0x049e, 0x049e,
+0x04a0, 0x04a0,
+0x04a2, 0x04a2,
+0x04a4, 0x04a4,
+0x04a6, 0x04a6,
+0x04a8, 0x04a8,
+0x04aa, 0x04aa,
+0x04ac, 0x04ac,
+0x04ae, 0x04ae,
+0x04b0, 0x04b0,
+0x04b2, 0x04b2,
+0x04b4, 0x04b4,
+0x04b6, 0x04b6,
+0x04b8, 0x04b8,
+0x04ba, 0x04ba,
+0x04bc, 0x04bc,
+0x04be, 0x04be,
+0x04c0, 0x04c1,
+0x04c3, 0x04c3,
+0x04c5, 0x04c5,
+0x04c7, 0x04c7,
+0x04c9, 0x04c9,
+0x04cb, 0x04cb,
+0x04cd, 0x04cd,
+0x04d0, 0x04d0,
+0x04d2, 0x04d2,
+0x04d4, 0x04d4,
+0x04d6, 0x04d6,
+0x04d8, 0x04d8,
+0x04da, 0x04da,
+0x04dc, 0x04dc,
+0x04de, 0x04de,
+0x04e0, 0x04e0,
+0x04e2, 0x04e2,
+0x04e4, 0x04e4,
+0x04e6, 0x04e6,
+0x04e8, 0x04e8,
+0x04ea, 0x04ea,
+0x04ec, 0x04ec,
+0x04ee, 0x04ee,
+0x04f0, 0x04f0,
+0x04f2, 0x04f2,
+0x04f4, 0x04f4,
+0x04f6, 0x04f6,
+0x04f8, 0x04f8,
+0x04fa, 0x04fa,
+0x04fc, 0x04fc,
+0x04fe, 0x04fe,
+0x0500, 0x0500,
+0x0502, 0x0502,
+0x0504, 0x0504,
+0x0506, 0x0506,
+0x0508, 0x0508,
+0x050a, 0x050a,
+0x050c, 0x050c,
+0x050e, 0x050e,
+0x0510, 0x0510,
+0x0512, 0x0512,
+0x0514, 0x0514,
+0x0516, 0x0516,
+0x0518, 0x0518,
+0x051a, 0x051a,
+0x051c, 0x051c,
+0x051e, 0x051e,
+0x0520, 0x0520,
+0x0522, 0x0522,
+0x0524, 0x0524,
+0x0526, 0x0526,
+0x0528, 0x0528,
+0x052a, 0x052a,
+0x052c, 0x052c,
+0x052e, 0x052e,
+0x0531, 0x0556,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x13a0, 0x13f5,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1e00, 0x1e00,
+0x1e02, 0x1e02,
+0x1e04, 0x1e04,
+0x1e06, 0x1e06,
+0x1e08, 0x1e08,
+0x1e0a, 0x1e0a,
+0x1e0c, 0x1e0c,
+0x1e0e, 0x1e0e,
+0x1e10, 0x1e10,
+0x1e12, 0x1e12,
+0x1e14, 0x1e14,
+0x1e16, 0x1e16,
+0x1e18, 0x1e18,
+0x1e1a, 0x1e1a,
+0x1e1c, 0x1e1c,
+0x1e1e, 0x1e1e,
+0x1e20, 0x1e20,
+0x1e22, 0x1e22,
+0x1e24, 0x1e24,
+0x1e26, 0x1e26,
+0x1e28, 0x1e28,
+0x1e2a, 0x1e2a,
+0x1e2c, 0x1e2c,
+0x1e2e, 0x1e2e,
+0x1e30, 0x1e30,
+0x1e32, 0x1e32,
+0x1e34, 0x1e34,
+0x1e36, 0x1e36,
+0x1e38, 0x1e38,
+0x1e3a, 0x1e3a,
+0x1e3c, 0x1e3c,
+0x1e3e, 0x1e3e,
+0x1e40, 0x1e40,
+0x1e42, 0x1e42,
+0x1e44, 0x1e44,
+0x1e46, 0x1e46,
+0x1e48, 0x1e48,
+0x1e4a, 0x1e4a,
+0x1e4c, 0x1e4c,
+0x1e4e, 0x1e4e,
+0x1e50, 0x1e50,
+0x1e52, 0x1e52,
+0x1e54, 0x1e54,
+0x1e56, 0x1e56,
+0x1e58, 0x1e58,
+0x1e5a, 0x1e5a,
+0x1e5c, 0x1e5c,
+0x1e5e, 0x1e5e,
+0x1e60, 0x1e60,
+0x1e62, 0x1e62,
+0x1e64, 0x1e64,
+0x1e66, 0x1e66,
+0x1e68, 0x1e68,
+0x1e6a, 0x1e6a,
+0x1e6c, 0x1e6c,
+0x1e6e, 0x1e6e,
+0x1e70, 0x1e70,
+0x1e72, 0x1e72,
+0x1e74, 0x1e74,
+0x1e76, 0x1e76,
+0x1e78, 0x1e78,
+0x1e7a, 0x1e7a,
+0x1e7c, 0x1e7c,
+0x1e7e, 0x1e7e,
+0x1e80, 0x1e80,
+0x1e82, 0x1e82,
+0x1e84, 0x1e84,
+0x1e86, 0x1e86,
+0x1e88, 0x1e88,
+0x1e8a, 0x1e8a,
+0x1e8c, 0x1e8c,
+0x1e8e, 0x1e8e,
+0x1e90, 0x1e90,
+0x1e92, 0x1e92,
+0x1e94, 0x1e94,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1ea0,
+0x1ea2, 0x1ea2,
+0x1ea4, 0x1ea4,
+0x1ea6, 0x1ea6,
+0x1ea8, 0x1ea8,
+0x1eaa, 0x1eaa,
+0x1eac, 0x1eac,
+0x1eae, 0x1eae,
+0x1eb0, 0x1eb0,
+0x1eb2, 0x1eb2,
+0x1eb4, 0x1eb4,
+0x1eb6, 0x1eb6,
+0x1eb8, 0x1eb8,
+0x1eba, 0x1eba,
+0x1ebc, 0x1ebc,
+0x1ebe, 0x1ebe,
+0x1ec0, 0x1ec0,
+0x1ec2, 0x1ec2,
+0x1ec4, 0x1ec4,
+0x1ec6, 0x1ec6,
+0x1ec8, 0x1ec8,
+0x1eca, 0x1eca,
+0x1ecc, 0x1ecc,
+0x1ece, 0x1ece,
+0x1ed0, 0x1ed0,
+0x1ed2, 0x1ed2,
+0x1ed4, 0x1ed4,
+0x1ed6, 0x1ed6,
+0x1ed8, 0x1ed8,
+0x1eda, 0x1eda,
+0x1edc, 0x1edc,
+0x1ede, 0x1ede,
+0x1ee0, 0x1ee0,
+0x1ee2, 0x1ee2,
+0x1ee4, 0x1ee4,
+0x1ee6, 0x1ee6,
+0x1ee8, 0x1ee8,
+0x1eea, 0x1eea,
+0x1eec, 0x1eec,
+0x1eee, 0x1eee,
+0x1ef0, 0x1ef0,
+0x1ef2, 0x1ef2,
+0x1ef4, 0x1ef4,
+0x1ef6, 0x1ef6,
+0x1ef8, 0x1ef8,
+0x1efa, 0x1efa,
+0x1efc, 0x1efc,
+0x1efe, 0x1efe,
+0x1f08, 0x1f0f,
+0x1f18, 0x1f1d,
+0x1f28, 0x1f2f,
+0x1f38, 0x1f3f,
+0x1f48, 0x1f4d,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f5f,
+0x1f68, 0x1f6f,
+0x1fb8, 0x1fbb,
+0x1fc8, 0x1fcb,
+0x1fd8, 0x1fdb,
+0x1fe8, 0x1fec,
+0x1ff8, 0x1ffb,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210b, 0x210d,
+0x2110, 0x2112,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x2130, 0x2133,
+0x213e, 0x213f,
+0x2145, 0x2145,
+0x2160, 0x216f,
+0x2183, 0x2183,
+0x24b6, 0x24cf,
+0x2c00, 0x2c2e,
+0x2c60, 0x2c60,
+0x2c62, 0x2c64,
+0x2c67, 0x2c67,
+0x2c69, 0x2c69,
+0x2c6b, 0x2c6b,
+0x2c6d, 0x2c70,
+0x2c72, 0x2c72,
+0x2c75, 0x2c75,
+0x2c7e, 0x2c80,
+0x2c82, 0x2c82,
+0x2c84, 0x2c84,
+0x2c86, 0x2c86,
+0x2c88, 0x2c88,
+0x2c8a, 0x2c8a,
+0x2c8c, 0x2c8c,
+0x2c8e, 0x2c8e,
+0x2c90, 0x2c90,
+0x2c92, 0x2c92,
+0x2c94, 0x2c94,
+0x2c96, 0x2c96,
+0x2c98, 0x2c98,
+0x2c9a, 0x2c9a,
+0x2c9c, 0x2c9c,
+0x2c9e, 0x2c9e,
+0x2ca0, 0x2ca0,
+0x2ca2, 0x2ca2,
+0x2ca4, 0x2ca4,
+0x2ca6, 0x2ca6,
+0x2ca8, 0x2ca8,
+0x2caa, 0x2caa,
+0x2cac, 0x2cac,
+0x2cae, 0x2cae,
+0x2cb0, 0x2cb0,
+0x2cb2, 0x2cb2,
+0x2cb4, 0x2cb4,
+0x2cb6, 0x2cb6,
+0x2cb8, 0x2cb8,
+0x2cba, 0x2cba,
+0x2cbc, 0x2cbc,
+0x2cbe, 0x2cbe,
+0x2cc0, 0x2cc0,
+0x2cc2, 0x2cc2,
+0x2cc4, 0x2cc4,
+0x2cc6, 0x2cc6,
+0x2cc8, 0x2cc8,
+0x2cca, 0x2cca,
+0x2ccc, 0x2ccc,
+0x2cce, 0x2cce,
+0x2cd0, 0x2cd0,
+0x2cd2, 0x2cd2,
+0x2cd4, 0x2cd4,
+0x2cd6, 0x2cd6,
+0x2cd8, 0x2cd8,
+0x2cda, 0x2cda,
+0x2cdc, 0x2cdc,
+0x2cde, 0x2cde,
+0x2ce0, 0x2ce0,
+0x2ce2, 0x2ce2,
+0x2ceb, 0x2ceb,
+0x2ced, 0x2ced,
+0x2cf2, 0x2cf2,
+0xa640, 0xa640,
+0xa642, 0xa642,
+0xa644, 0xa644,
+0xa646, 0xa646,
+0xa648, 0xa648,
+0xa64a, 0xa64a,
+0xa64c, 0xa64c,
+0xa64e, 0xa64e,
+0xa650, 0xa650,
+0xa652, 0xa652,
+0xa654, 0xa654,
+0xa656, 0xa656,
+0xa658, 0xa658,
+0xa65a, 0xa65a,
+0xa65c, 0xa65c,
+0xa65e, 0xa65e,
+0xa660, 0xa660,
+0xa662, 0xa662,
+0xa664, 0xa664,
+0xa666, 0xa666,
+0xa668, 0xa668,
+0xa66a, 0xa66a,
+0xa66c, 0xa66c,
+0xa680, 0xa680,
+0xa682, 0xa682,
+0xa684, 0xa684,
+0xa686, 0xa686,
+0xa688, 0xa688,
+0xa68a, 0xa68a,
+0xa68c, 0xa68c,
+0xa68e, 0xa68e,
+0xa690, 0xa690,
+0xa692, 0xa692,
+0xa694, 0xa694,
+0xa696, 0xa696,
+0xa698, 0xa698,
+0xa69a, 0xa69a,
+0xa722, 0xa722,
+0xa724, 0xa724,
+0xa726, 0xa726,
+0xa728, 0xa728,
+0xa72a, 0xa72a,
+0xa72c, 0xa72c,
+0xa72e, 0xa72e,
+0xa732, 0xa732,
+0xa734, 0xa734,
+0xa736, 0xa736,
+0xa738, 0xa738,
+0xa73a, 0xa73a,
+0xa73c, 0xa73c,
+0xa73e, 0xa73e,
+0xa740, 0xa740,
+0xa742, 0xa742,
+0xa744, 0xa744,
+0xa746, 0xa746,
+0xa748, 0xa748,
+0xa74a, 0xa74a,
+0xa74c, 0xa74c,
+0xa74e, 0xa74e,
+0xa750, 0xa750,
+0xa752, 0xa752,
+0xa754, 0xa754,
+0xa756, 0xa756,
+0xa758, 0xa758,
+0xa75a, 0xa75a,
+0xa75c, 0xa75c,
+0xa75e, 0xa75e,
+0xa760, 0xa760,
+0xa762, 0xa762,
+0xa764, 0xa764,
+0xa766, 0xa766,
+0xa768, 0xa768,
+0xa76a, 0xa76a,
+0xa76c, 0xa76c,
+0xa76e, 0xa76e,
+0xa779, 0xa779,
+0xa77b, 0xa77b,
+0xa77d, 0xa77e,
+0xa780, 0xa780,
+0xa782, 0xa782,
+0xa784, 0xa784,
+0xa786, 0xa786,
+0xa78b, 0xa78b,
+0xa78d, 0xa78d,
+0xa790, 0xa790,
+0xa792, 0xa792,
+0xa796, 0xa796,
+0xa798, 0xa798,
+0xa79a, 0xa79a,
+0xa79c, 0xa79c,
+0xa79e, 0xa79e,
+0xa7a0, 0xa7a0,
+0xa7a2, 0xa7a2,
+0xa7a4, 0xa7a4,
+0xa7a6, 0xa7a6,
+0xa7a8, 0xa7a8,
+0xa7aa, 0xa7ae,
+0xa7b0, 0xa7b4,
+0xa7b6, 0xa7b6,
+0xa7b8, 0xa7b8,
+0xa7ba, 0xa7ba,
+0xa7bc, 0xa7bc,
+0xa7be, 0xa7be,
+0xa7c2, 0xa7c2,
+0xa7c4, 0xa7c6,
+0xff21, 0xff3a,
+0x10400, 0x10427,
+0x104b0, 0x104d3,
+0x10c80, 0x10cb2,
+0x118a0, 0x118bf,
+0x16e40, 0x16e5f,
+0x1d400, 0x1d419,
+0x1d434, 0x1d44d,
+0x1d468, 0x1d481,
+0x1d49c, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b5,
+0x1d4d0, 0x1d4e9,
+0x1d504, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d538, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d56c, 0x1d585,
+0x1d5a0, 0x1d5b9,
+0x1d5d4, 0x1d5ed,
+0x1d608, 0x1d621,
+0x1d63c, 0x1d655,
+0x1d670, 0x1d689,
+0x1d6a8, 0x1d6c0,
+0x1d6e2, 0x1d6fa,
+0x1d71c, 0x1d734,
+0x1d756, 0x1d76e,
+0x1d790, 0x1d7a8,
+0x1d7ca, 0x1d7ca,
+0x1e900, 0x1e921,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+}; /* END of CR_Upper */
+
+/* PROPERTY: 'XDigit': POSIX [[:XDigit:]] */
+static const OnigCodePoint
+CR_XDigit[] = { 3,
+0x0030, 0x0039,
+0x0041, 0x0046,
+0x0061, 0x0066,
+}; /* END of CR_XDigit */
+
+/* PROPERTY: 'Word': POSIX [[:Word:]] */
+static const OnigCodePoint
+CR_Word[] = { 716,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x005f, 0x005f,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0300, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x0483, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06df, 0x06e8,
+0x06ea, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07f5,
+0x07fa, 0x07fa,
+0x07fd, 0x07fd,
+0x0800, 0x082d,
+0x0840, 0x085b,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x08e1,
+0x08e3, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x09fe, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e4e,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f18, 0x0f19,
+0x0f20, 0x0f29,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f84,
+0x0f86, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x1000, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x135f,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1734,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17d3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dd,
+0x17e0, 0x17e9,
+0x180b, 0x180d,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19d9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b6b, 0x1b73,
+0x1b80, 0x1bf3,
+0x1c00, 0x1c37,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x203f, 0x2040,
+0x2054, 0x2054,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x20d0, 0x20f0,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x302f,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x3099, 0x309a,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa672,
+0xa674, 0xa67d,
+0xa67f, 0xa6f1,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8e0, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92d,
+0xa930, 0xa953,
+0xa960, 0xa97c,
+0xa980, 0xa9c0,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabec, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0xfe33, 0xfe34,
+0xfe4d, 0xfe4f,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff3f, 0xff3f,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x101fd, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102e0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae6,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f50,
+0x10fe0, 0x10ff6,
+0x11000, 0x11046,
+0x11066, 0x1106f,
+0x1107f, 0x110ba,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11173,
+0x11176, 0x11176,
+0x11180, 0x111c4,
+0x111c9, 0x111cc,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x1144a,
+0x11450, 0x11459,
+0x1145e, 0x1145f,
+0x11480, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115c0,
+0x115d8, 0x115dd,
+0x11600, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x11739,
+0x11800, 0x1183a,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a50, 0x11a99,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af4,
+0x16b00, 0x16b36,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e8d0, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0100, 0xe01ef,
+}; /* END of CR_Word */
+
+/* PROPERTY: 'Alnum': POSIX [[:Alnum:]] */
+static const OnigCodePoint
+CR_Alnum[] = { 715,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0345, 0x0345,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05b0, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0657,
+0x0659, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06e1, 0x06e8,
+0x06ed, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x073f,
+0x074d, 0x07b1,
+0x07c0, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0817,
+0x081a, 0x082c,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d4, 0x08df,
+0x08e3, 0x08e9,
+0x08f0, 0x093b,
+0x093d, 0x094c,
+0x094e, 0x0950,
+0x0955, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09ce, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4c,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0afc,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c03,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4c,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccc,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e46,
+0x0e4d, 0x0e4d,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb9,
+0x0ebb, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ecd, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f20, 0x0f29,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f81,
+0x0f88, 0x0f97,
+0x0f99, 0x0fbc,
+0x1000, 0x1036,
+0x1038, 0x1038,
+0x103b, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1713,
+0x1720, 0x1733,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17b3,
+0x17b6, 0x17c8,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x17e0, 0x17e9,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x1938,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19d9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a61, 0x1a74,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1b00, 0x1b33,
+0x1b35, 0x1b43,
+0x1b45, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b80, 0x1ba9,
+0x1bac, 0x1be5,
+0x1be7, 0x1bf1,
+0x1c00, 0x1c36,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1de7, 0x1df4,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa66e,
+0xa674, 0xa67b,
+0xa67f, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa805,
+0xa807, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c3,
+0xa8c5, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92a,
+0xa930, 0xa952,
+0xa960, 0xa97c,
+0xa980, 0xa9b2,
+0xa9b4, 0xa9bf,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaabe,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf5,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11000, 0x11045,
+0x11066, 0x1106f,
+0x11082, 0x110b8,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11132,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11180, 0x111bf,
+0x111c1, 0x111c4,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11234,
+0x11237, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112e8,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134c,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11400, 0x11441,
+0x11443, 0x11445,
+0x11447, 0x1144a,
+0x11450, 0x11459,
+0x1145f, 0x1145f,
+0x11480, 0x114c1,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115be,
+0x115d8, 0x115dd,
+0x11600, 0x1163e,
+0x11640, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b5,
+0x116b8, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172a,
+0x11730, 0x11739,
+0x11800, 0x11838,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119df,
+0x119e1, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a32,
+0x11a35, 0x11a3e,
+0x11a50, 0x11a97,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c3e,
+0x11c40, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d41,
+0x11d43, 0x11d43,
+0x11d46, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d96,
+0x11d98, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9e, 0x1bc9e,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e2f0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e947, 0x1e947,
+0x1e94b, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Alnum */
+
+/* PROPERTY: 'ASCII': POSIX [[:ASCII:]] */
+static const OnigCodePoint
+CR_ASCII[] = { 1,
+0x0000, 0x007f,
+}; /* END of CR_ASCII */
+
+
+/* PROPERTY: 'ASCII_Hex_Digit': Binary Property */
+#define CR_ASCII_Hex_Digit CR_XDigit
+
+/* PROPERTY: 'Adlam': Script */
+static const OnigCodePoint
+CR_Adlam[] = { 3,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+}; /* END of CR_Adlam */
+
+/* PROPERTY: 'Ahom': Script */
+static const OnigCodePoint
+CR_Ahom[] = { 3,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+}; /* END of CR_Ahom */
+
+/* PROPERTY: 'Alphabetic': Derived Property */
+#define CR_Alphabetic CR_Alpha
+
+/* PROPERTY: 'Anatolian_Hieroglyphs': Script */
+static const OnigCodePoint
+CR_Anatolian_Hieroglyphs[] = { 1,
+0x14400, 0x14646,
+}; /* END of CR_Anatolian_Hieroglyphs */
+
+/* PROPERTY: 'Any': - */
+static const OnigCodePoint
+CR_Any[] = { 1,
+0x0000, 0x10ffff,
+}; /* END of CR_Any */
+
+/* PROPERTY: 'Arabic': Script */
+static const OnigCodePoint
+CR_Arabic[] = { 57,
+0x0600, 0x0604,
+0x0606, 0x060b,
+0x060d, 0x061a,
+0x061c, 0x061c,
+0x061e, 0x061e,
+0x0620, 0x063f,
+0x0641, 0x064a,
+0x0656, 0x066f,
+0x0671, 0x06dc,
+0x06de, 0x06ff,
+0x0750, 0x077f,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x08e1,
+0x08e3, 0x08ff,
+0xfb50, 0xfbc1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0x10e60, 0x10e7e,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+}; /* END of CR_Arabic */
+
+/* PROPERTY: 'Armenian': Script */
+static const OnigCodePoint
+CR_Armenian[] = { 5,
+0x0531, 0x0556,
+0x0559, 0x0588,
+0x058a, 0x058a,
+0x058d, 0x058f,
+0xfb13, 0xfb17,
+}; /* END of CR_Armenian */
+
+/* PROPERTY: 'Assigned': - */
+static const OnigCodePoint
+CR_Assigned[] = { 666,
+0x0000, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0600, 0x061c,
+0x061e, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07fa,
+0x07fd, 0x082d,
+0x0830, 0x083e,
+0x0840, 0x085b,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e3a,
+0x0e3f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1736,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a1b,
+0x1a1e, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+0x1b80, 0x1bf3,
+0x1bfc, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd0, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x2000, 0x2064,
+0x2066, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x20d0, 0x20f0,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3000, 0x303f,
+0x3041, 0x3096,
+0x3099, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+0xa8e0, 0xa953,
+0xa95f, 0xa97c,
+0xa980, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaac2,
+0xaadb, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xd800, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe00, 0xfe19,
+0xfe20, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xfeff, 0xfeff,
+0xff01, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d27,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x110c1,
+0x110cd, 0x110cd,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x11146,
+0x11150, 0x11176,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+0x11600, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+0x11800, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+0x11a00, 0x11a47,
+0x11a50, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d1e8,
+0x1d200, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Assigned */
+
+/* PROPERTY: 'Avestan': Script */
+static const OnigCodePoint
+CR_Avestan[] = { 2,
+0x10b00, 0x10b35,
+0x10b39, 0x10b3f,
+}; /* END of CR_Avestan */
+
+/* PROPERTY: 'Balinese': Script */
+static const OnigCodePoint
+CR_Balinese[] = { 2,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+}; /* END of CR_Balinese */
+
+/* PROPERTY: 'Bamum': Script */
+static const OnigCodePoint
+CR_Bamum[] = { 2,
+0xa6a0, 0xa6f7,
+0x16800, 0x16a38,
+}; /* END of CR_Bamum */
+
+/* PROPERTY: 'Bassa_Vah': Script */
+static const OnigCodePoint
+CR_Bassa_Vah[] = { 2,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+}; /* END of CR_Bassa_Vah */
+
+/* PROPERTY: 'Batak': Script */
+static const OnigCodePoint
+CR_Batak[] = { 2,
+0x1bc0, 0x1bf3,
+0x1bfc, 0x1bff,
+}; /* END of CR_Batak */
+
+/* PROPERTY: 'Bengali': Script */
+static const OnigCodePoint
+CR_Bengali[] = { 14,
+0x0980, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+}; /* END of CR_Bengali */
+
+/* PROPERTY: 'Bhaiksuki': Script */
+static const OnigCodePoint
+CR_Bhaiksuki[] = { 4,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+}; /* END of CR_Bhaiksuki */
+
+/* PROPERTY: 'Bidi_Control': Binary Property */
+static const OnigCodePoint
+CR_Bidi_Control[] = { 4,
+0x061c, 0x061c,
+0x200e, 0x200f,
+0x202a, 0x202e,
+0x2066, 0x2069,
+}; /* END of CR_Bidi_Control */
+
+/* PROPERTY: 'Bopomofo': Script */
+static const OnigCodePoint
+CR_Bopomofo[] = { 3,
+0x02ea, 0x02eb,
+0x3105, 0x312f,
+0x31a0, 0x31ba,
+}; /* END of CR_Bopomofo */
+
+/* PROPERTY: 'Brahmi': Script */
+static const OnigCodePoint
+CR_Brahmi[] = { 3,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x1107f,
+}; /* END of CR_Brahmi */
+
+/* PROPERTY: 'Braille': Script */
+static const OnigCodePoint
+CR_Braille[] = { 1,
+0x2800, 0x28ff,
+}; /* END of CR_Braille */
+
+/* PROPERTY: 'Buginese': Script */
+static const OnigCodePoint
+CR_Buginese[] = { 2,
+0x1a00, 0x1a1b,
+0x1a1e, 0x1a1f,
+}; /* END of CR_Buginese */
+
+/* PROPERTY: 'Buhid': Script */
+static const OnigCodePoint
+CR_Buhid[] = { 1,
+0x1740, 0x1753,
+}; /* END of CR_Buhid */
+
+/* PROPERTY: 'C': Major Category */
+static const OnigCodePoint
+CR_C[] = { 668,
+0x0000, 0x001f,
+0x007f, 0x009f,
+0x00ad, 0x00ad,
+0x0378, 0x0379,
+0x0380, 0x0383,
+0x038b, 0x038b,
+0x038d, 0x038d,
+0x03a2, 0x03a2,
+0x0530, 0x0530,
+0x0557, 0x0558,
+0x058b, 0x058c,
+0x0590, 0x0590,
+0x05c8, 0x05cf,
+0x05eb, 0x05ee,
+0x05f5, 0x0605,
+0x061c, 0x061d,
+0x06dd, 0x06dd,
+0x070e, 0x070f,
+0x074b, 0x074c,
+0x07b2, 0x07bf,
+0x07fb, 0x07fc,
+0x082e, 0x082f,
+0x083f, 0x083f,
+0x085c, 0x085d,
+0x085f, 0x085f,
+0x086b, 0x089f,
+0x08b5, 0x08b5,
+0x08be, 0x08d2,
+0x08e2, 0x08e2,
+0x0984, 0x0984,
+0x098d, 0x098e,
+0x0991, 0x0992,
+0x09a9, 0x09a9,
+0x09b1, 0x09b1,
+0x09b3, 0x09b5,
+0x09ba, 0x09bb,
+0x09c5, 0x09c6,
+0x09c9, 0x09ca,
+0x09cf, 0x09d6,
+0x09d8, 0x09db,
+0x09de, 0x09de,
+0x09e4, 0x09e5,
+0x09ff, 0x0a00,
+0x0a04, 0x0a04,
+0x0a0b, 0x0a0e,
+0x0a11, 0x0a12,
+0x0a29, 0x0a29,
+0x0a31, 0x0a31,
+0x0a34, 0x0a34,
+0x0a37, 0x0a37,
+0x0a3a, 0x0a3b,
+0x0a3d, 0x0a3d,
+0x0a43, 0x0a46,
+0x0a49, 0x0a4a,
+0x0a4e, 0x0a50,
+0x0a52, 0x0a58,
+0x0a5d, 0x0a5d,
+0x0a5f, 0x0a65,
+0x0a77, 0x0a80,
+0x0a84, 0x0a84,
+0x0a8e, 0x0a8e,
+0x0a92, 0x0a92,
+0x0aa9, 0x0aa9,
+0x0ab1, 0x0ab1,
+0x0ab4, 0x0ab4,
+0x0aba, 0x0abb,
+0x0ac6, 0x0ac6,
+0x0aca, 0x0aca,
+0x0ace, 0x0acf,
+0x0ad1, 0x0adf,
+0x0ae4, 0x0ae5,
+0x0af2, 0x0af8,
+0x0b00, 0x0b00,
+0x0b04, 0x0b04,
+0x0b0d, 0x0b0e,
+0x0b11, 0x0b12,
+0x0b29, 0x0b29,
+0x0b31, 0x0b31,
+0x0b34, 0x0b34,
+0x0b3a, 0x0b3b,
+0x0b45, 0x0b46,
+0x0b49, 0x0b4a,
+0x0b4e, 0x0b55,
+0x0b58, 0x0b5b,
+0x0b5e, 0x0b5e,
+0x0b64, 0x0b65,
+0x0b78, 0x0b81,
+0x0b84, 0x0b84,
+0x0b8b, 0x0b8d,
+0x0b91, 0x0b91,
+0x0b96, 0x0b98,
+0x0b9b, 0x0b9b,
+0x0b9d, 0x0b9d,
+0x0ba0, 0x0ba2,
+0x0ba5, 0x0ba7,
+0x0bab, 0x0bad,
+0x0bba, 0x0bbd,
+0x0bc3, 0x0bc5,
+0x0bc9, 0x0bc9,
+0x0bce, 0x0bcf,
+0x0bd1, 0x0bd6,
+0x0bd8, 0x0be5,
+0x0bfb, 0x0bff,
+0x0c0d, 0x0c0d,
+0x0c11, 0x0c11,
+0x0c29, 0x0c29,
+0x0c3a, 0x0c3c,
+0x0c45, 0x0c45,
+0x0c49, 0x0c49,
+0x0c4e, 0x0c54,
+0x0c57, 0x0c57,
+0x0c5b, 0x0c5f,
+0x0c64, 0x0c65,
+0x0c70, 0x0c76,
+0x0c8d, 0x0c8d,
+0x0c91, 0x0c91,
+0x0ca9, 0x0ca9,
+0x0cb4, 0x0cb4,
+0x0cba, 0x0cbb,
+0x0cc5, 0x0cc5,
+0x0cc9, 0x0cc9,
+0x0cce, 0x0cd4,
+0x0cd7, 0x0cdd,
+0x0cdf, 0x0cdf,
+0x0ce4, 0x0ce5,
+0x0cf0, 0x0cf0,
+0x0cf3, 0x0cff,
+0x0d04, 0x0d04,
+0x0d0d, 0x0d0d,
+0x0d11, 0x0d11,
+0x0d45, 0x0d45,
+0x0d49, 0x0d49,
+0x0d50, 0x0d53,
+0x0d64, 0x0d65,
+0x0d80, 0x0d81,
+0x0d84, 0x0d84,
+0x0d97, 0x0d99,
+0x0db2, 0x0db2,
+0x0dbc, 0x0dbc,
+0x0dbe, 0x0dbf,
+0x0dc7, 0x0dc9,
+0x0dcb, 0x0dce,
+0x0dd5, 0x0dd5,
+0x0dd7, 0x0dd7,
+0x0de0, 0x0de5,
+0x0df0, 0x0df1,
+0x0df5, 0x0e00,
+0x0e3b, 0x0e3e,
+0x0e5c, 0x0e80,
+0x0e83, 0x0e83,
+0x0e85, 0x0e85,
+0x0e8b, 0x0e8b,
+0x0ea4, 0x0ea4,
+0x0ea6, 0x0ea6,
+0x0ebe, 0x0ebf,
+0x0ec5, 0x0ec5,
+0x0ec7, 0x0ec7,
+0x0ece, 0x0ecf,
+0x0eda, 0x0edb,
+0x0ee0, 0x0eff,
+0x0f48, 0x0f48,
+0x0f6d, 0x0f70,
+0x0f98, 0x0f98,
+0x0fbd, 0x0fbd,
+0x0fcd, 0x0fcd,
+0x0fdb, 0x0fff,
+0x10c6, 0x10c6,
+0x10c8, 0x10cc,
+0x10ce, 0x10cf,
+0x1249, 0x1249,
+0x124e, 0x124f,
+0x1257, 0x1257,
+0x1259, 0x1259,
+0x125e, 0x125f,
+0x1289, 0x1289,
+0x128e, 0x128f,
+0x12b1, 0x12b1,
+0x12b6, 0x12b7,
+0x12bf, 0x12bf,
+0x12c1, 0x12c1,
+0x12c6, 0x12c7,
+0x12d7, 0x12d7,
+0x1311, 0x1311,
+0x1316, 0x1317,
+0x135b, 0x135c,
+0x137d, 0x137f,
+0x139a, 0x139f,
+0x13f6, 0x13f7,
+0x13fe, 0x13ff,
+0x169d, 0x169f,
+0x16f9, 0x16ff,
+0x170d, 0x170d,
+0x1715, 0x171f,
+0x1737, 0x173f,
+0x1754, 0x175f,
+0x176d, 0x176d,
+0x1771, 0x1771,
+0x1774, 0x177f,
+0x17de, 0x17df,
+0x17ea, 0x17ef,
+0x17fa, 0x17ff,
+0x180e, 0x180f,
+0x181a, 0x181f,
+0x1879, 0x187f,
+0x18ab, 0x18af,
+0x18f6, 0x18ff,
+0x191f, 0x191f,
+0x192c, 0x192f,
+0x193c, 0x193f,
+0x1941, 0x1943,
+0x196e, 0x196f,
+0x1975, 0x197f,
+0x19ac, 0x19af,
+0x19ca, 0x19cf,
+0x19db, 0x19dd,
+0x1a1c, 0x1a1d,
+0x1a5f, 0x1a5f,
+0x1a7d, 0x1a7e,
+0x1a8a, 0x1a8f,
+0x1a9a, 0x1a9f,
+0x1aae, 0x1aaf,
+0x1abf, 0x1aff,
+0x1b4c, 0x1b4f,
+0x1b7d, 0x1b7f,
+0x1bf4, 0x1bfb,
+0x1c38, 0x1c3a,
+0x1c4a, 0x1c4c,
+0x1c89, 0x1c8f,
+0x1cbb, 0x1cbc,
+0x1cc8, 0x1ccf,
+0x1cfb, 0x1cff,
+0x1dfa, 0x1dfa,
+0x1f16, 0x1f17,
+0x1f1e, 0x1f1f,
+0x1f46, 0x1f47,
+0x1f4e, 0x1f4f,
+0x1f58, 0x1f58,
+0x1f5a, 0x1f5a,
+0x1f5c, 0x1f5c,
+0x1f5e, 0x1f5e,
+0x1f7e, 0x1f7f,
+0x1fb5, 0x1fb5,
+0x1fc5, 0x1fc5,
+0x1fd4, 0x1fd5,
+0x1fdc, 0x1fdc,
+0x1ff0, 0x1ff1,
+0x1ff5, 0x1ff5,
+0x1fff, 0x1fff,
+0x200b, 0x200f,
+0x202a, 0x202e,
+0x2060, 0x206f,
+0x2072, 0x2073,
+0x208f, 0x208f,
+0x209d, 0x209f,
+0x20c0, 0x20cf,
+0x20f1, 0x20ff,
+0x218c, 0x218f,
+0x2427, 0x243f,
+0x244b, 0x245f,
+0x2b74, 0x2b75,
+0x2b96, 0x2b97,
+0x2c2f, 0x2c2f,
+0x2c5f, 0x2c5f,
+0x2cf4, 0x2cf8,
+0x2d26, 0x2d26,
+0x2d28, 0x2d2c,
+0x2d2e, 0x2d2f,
+0x2d68, 0x2d6e,
+0x2d71, 0x2d7e,
+0x2d97, 0x2d9f,
+0x2da7, 0x2da7,
+0x2daf, 0x2daf,
+0x2db7, 0x2db7,
+0x2dbf, 0x2dbf,
+0x2dc7, 0x2dc7,
+0x2dcf, 0x2dcf,
+0x2dd7, 0x2dd7,
+0x2ddf, 0x2ddf,
+0x2e50, 0x2e7f,
+0x2e9a, 0x2e9a,
+0x2ef4, 0x2eff,
+0x2fd6, 0x2fef,
+0x2ffc, 0x2fff,
+0x3040, 0x3040,
+0x3097, 0x3098,
+0x3100, 0x3104,
+0x3130, 0x3130,
+0x318f, 0x318f,
+0x31bb, 0x31bf,
+0x31e4, 0x31ef,
+0x321f, 0x321f,
+0x4db6, 0x4dbf,
+0x9ff0, 0x9fff,
+0xa48d, 0xa48f,
+0xa4c7, 0xa4cf,
+0xa62c, 0xa63f,
+0xa6f8, 0xa6ff,
+0xa7c0, 0xa7c1,
+0xa7c7, 0xa7f6,
+0xa82c, 0xa82f,
+0xa83a, 0xa83f,
+0xa878, 0xa87f,
+0xa8c6, 0xa8cd,
+0xa8da, 0xa8df,
+0xa954, 0xa95e,
+0xa97d, 0xa97f,
+0xa9ce, 0xa9ce,
+0xa9da, 0xa9dd,
+0xa9ff, 0xa9ff,
+0xaa37, 0xaa3f,
+0xaa4e, 0xaa4f,
+0xaa5a, 0xaa5b,
+0xaac3, 0xaada,
+0xaaf7, 0xab00,
+0xab07, 0xab08,
+0xab0f, 0xab10,
+0xab17, 0xab1f,
+0xab27, 0xab27,
+0xab2f, 0xab2f,
+0xab68, 0xab6f,
+0xabee, 0xabef,
+0xabfa, 0xabff,
+0xd7a4, 0xd7af,
+0xd7c7, 0xd7ca,
+0xd7fc, 0xf8ff,
+0xfa6e, 0xfa6f,
+0xfada, 0xfaff,
+0xfb07, 0xfb12,
+0xfb18, 0xfb1c,
+0xfb37, 0xfb37,
+0xfb3d, 0xfb3d,
+0xfb3f, 0xfb3f,
+0xfb42, 0xfb42,
+0xfb45, 0xfb45,
+0xfbc2, 0xfbd2,
+0xfd40, 0xfd4f,
+0xfd90, 0xfd91,
+0xfdc8, 0xfdef,
+0xfdfe, 0xfdff,
+0xfe1a, 0xfe1f,
+0xfe53, 0xfe53,
+0xfe67, 0xfe67,
+0xfe6c, 0xfe6f,
+0xfe75, 0xfe75,
+0xfefd, 0xff00,
+0xffbf, 0xffc1,
+0xffc8, 0xffc9,
+0xffd0, 0xffd1,
+0xffd8, 0xffd9,
+0xffdd, 0xffdf,
+0xffe7, 0xffe7,
+0xffef, 0xfffb,
+0xfffe, 0xffff,
+0x1000c, 0x1000c,
+0x10027, 0x10027,
+0x1003b, 0x1003b,
+0x1003e, 0x1003e,
+0x1004e, 0x1004f,
+0x1005e, 0x1007f,
+0x100fb, 0x100ff,
+0x10103, 0x10106,
+0x10134, 0x10136,
+0x1018f, 0x1018f,
+0x1019c, 0x1019f,
+0x101a1, 0x101cf,
+0x101fe, 0x1027f,
+0x1029d, 0x1029f,
+0x102d1, 0x102df,
+0x102fc, 0x102ff,
+0x10324, 0x1032c,
+0x1034b, 0x1034f,
+0x1037b, 0x1037f,
+0x1039e, 0x1039e,
+0x103c4, 0x103c7,
+0x103d6, 0x103ff,
+0x1049e, 0x1049f,
+0x104aa, 0x104af,
+0x104d4, 0x104d7,
+0x104fc, 0x104ff,
+0x10528, 0x1052f,
+0x10564, 0x1056e,
+0x10570, 0x105ff,
+0x10737, 0x1073f,
+0x10756, 0x1075f,
+0x10768, 0x107ff,
+0x10806, 0x10807,
+0x10809, 0x10809,
+0x10836, 0x10836,
+0x10839, 0x1083b,
+0x1083d, 0x1083e,
+0x10856, 0x10856,
+0x1089f, 0x108a6,
+0x108b0, 0x108df,
+0x108f3, 0x108f3,
+0x108f6, 0x108fa,
+0x1091c, 0x1091e,
+0x1093a, 0x1093e,
+0x10940, 0x1097f,
+0x109b8, 0x109bb,
+0x109d0, 0x109d1,
+0x10a04, 0x10a04,
+0x10a07, 0x10a0b,
+0x10a14, 0x10a14,
+0x10a18, 0x10a18,
+0x10a36, 0x10a37,
+0x10a3b, 0x10a3e,
+0x10a49, 0x10a4f,
+0x10a59, 0x10a5f,
+0x10aa0, 0x10abf,
+0x10ae7, 0x10aea,
+0x10af7, 0x10aff,
+0x10b36, 0x10b38,
+0x10b56, 0x10b57,
+0x10b73, 0x10b77,
+0x10b92, 0x10b98,
+0x10b9d, 0x10ba8,
+0x10bb0, 0x10bff,
+0x10c49, 0x10c7f,
+0x10cb3, 0x10cbf,
+0x10cf3, 0x10cf9,
+0x10d28, 0x10d2f,
+0x10d3a, 0x10e5f,
+0x10e7f, 0x10eff,
+0x10f28, 0x10f2f,
+0x10f5a, 0x10fdf,
+0x10ff7, 0x10fff,
+0x1104e, 0x11051,
+0x11070, 0x1107e,
+0x110bd, 0x110bd,
+0x110c2, 0x110cf,
+0x110e9, 0x110ef,
+0x110fa, 0x110ff,
+0x11135, 0x11135,
+0x11147, 0x1114f,
+0x11177, 0x1117f,
+0x111ce, 0x111cf,
+0x111e0, 0x111e0,
+0x111f5, 0x111ff,
+0x11212, 0x11212,
+0x1123f, 0x1127f,
+0x11287, 0x11287,
+0x11289, 0x11289,
+0x1128e, 0x1128e,
+0x1129e, 0x1129e,
+0x112aa, 0x112af,
+0x112eb, 0x112ef,
+0x112fa, 0x112ff,
+0x11304, 0x11304,
+0x1130d, 0x1130e,
+0x11311, 0x11312,
+0x11329, 0x11329,
+0x11331, 0x11331,
+0x11334, 0x11334,
+0x1133a, 0x1133a,
+0x11345, 0x11346,
+0x11349, 0x1134a,
+0x1134e, 0x1134f,
+0x11351, 0x11356,
+0x11358, 0x1135c,
+0x11364, 0x11365,
+0x1136d, 0x1136f,
+0x11375, 0x113ff,
+0x1145a, 0x1145a,
+0x1145c, 0x1145c,
+0x11460, 0x1147f,
+0x114c8, 0x114cf,
+0x114da, 0x1157f,
+0x115b6, 0x115b7,
+0x115de, 0x115ff,
+0x11645, 0x1164f,
+0x1165a, 0x1165f,
+0x1166d, 0x1167f,
+0x116b9, 0x116bf,
+0x116ca, 0x116ff,
+0x1171b, 0x1171c,
+0x1172c, 0x1172f,
+0x11740, 0x117ff,
+0x1183c, 0x1189f,
+0x118f3, 0x118fe,
+0x11900, 0x1199f,
+0x119a8, 0x119a9,
+0x119d8, 0x119d9,
+0x119e5, 0x119ff,
+0x11a48, 0x11a4f,
+0x11aa3, 0x11abf,
+0x11af9, 0x11bff,
+0x11c09, 0x11c09,
+0x11c37, 0x11c37,
+0x11c46, 0x11c4f,
+0x11c6d, 0x11c6f,
+0x11c90, 0x11c91,
+0x11ca8, 0x11ca8,
+0x11cb7, 0x11cff,
+0x11d07, 0x11d07,
+0x11d0a, 0x11d0a,
+0x11d37, 0x11d39,
+0x11d3b, 0x11d3b,
+0x11d3e, 0x11d3e,
+0x11d48, 0x11d4f,
+0x11d5a, 0x11d5f,
+0x11d66, 0x11d66,
+0x11d69, 0x11d69,
+0x11d8f, 0x11d8f,
+0x11d92, 0x11d92,
+0x11d99, 0x11d9f,
+0x11daa, 0x11edf,
+0x11ef9, 0x11fbf,
+0x11ff2, 0x11ffe,
+0x1239a, 0x123ff,
+0x1246f, 0x1246f,
+0x12475, 0x1247f,
+0x12544, 0x12fff,
+0x1342f, 0x143ff,
+0x14647, 0x167ff,
+0x16a39, 0x16a3f,
+0x16a5f, 0x16a5f,
+0x16a6a, 0x16a6d,
+0x16a70, 0x16acf,
+0x16aee, 0x16aef,
+0x16af6, 0x16aff,
+0x16b46, 0x16b4f,
+0x16b5a, 0x16b5a,
+0x16b62, 0x16b62,
+0x16b78, 0x16b7c,
+0x16b90, 0x16e3f,
+0x16e9b, 0x16eff,
+0x16f4b, 0x16f4e,
+0x16f88, 0x16f8e,
+0x16fa0, 0x16fdf,
+0x16fe4, 0x16fff,
+0x187f8, 0x187ff,
+0x18af3, 0x1afff,
+0x1b11f, 0x1b14f,
+0x1b153, 0x1b163,
+0x1b168, 0x1b16f,
+0x1b2fc, 0x1bbff,
+0x1bc6b, 0x1bc6f,
+0x1bc7d, 0x1bc7f,
+0x1bc89, 0x1bc8f,
+0x1bc9a, 0x1bc9b,
+0x1bca0, 0x1cfff,
+0x1d0f6, 0x1d0ff,
+0x1d127, 0x1d128,
+0x1d173, 0x1d17a,
+0x1d1e9, 0x1d1ff,
+0x1d246, 0x1d2df,
+0x1d2f4, 0x1d2ff,
+0x1d357, 0x1d35f,
+0x1d379, 0x1d3ff,
+0x1d455, 0x1d455,
+0x1d49d, 0x1d49d,
+0x1d4a0, 0x1d4a1,
+0x1d4a3, 0x1d4a4,
+0x1d4a7, 0x1d4a8,
+0x1d4ad, 0x1d4ad,
+0x1d4ba, 0x1d4ba,
+0x1d4bc, 0x1d4bc,
+0x1d4c4, 0x1d4c4,
+0x1d506, 0x1d506,
+0x1d50b, 0x1d50c,
+0x1d515, 0x1d515,
+0x1d51d, 0x1d51d,
+0x1d53a, 0x1d53a,
+0x1d53f, 0x1d53f,
+0x1d545, 0x1d545,
+0x1d547, 0x1d549,
+0x1d551, 0x1d551,
+0x1d6a6, 0x1d6a7,
+0x1d7cc, 0x1d7cd,
+0x1da8c, 0x1da9a,
+0x1daa0, 0x1daa0,
+0x1dab0, 0x1dfff,
+0x1e007, 0x1e007,
+0x1e019, 0x1e01a,
+0x1e022, 0x1e022,
+0x1e025, 0x1e025,
+0x1e02b, 0x1e0ff,
+0x1e12d, 0x1e12f,
+0x1e13e, 0x1e13f,
+0x1e14a, 0x1e14d,
+0x1e150, 0x1e2bf,
+0x1e2fa, 0x1e2fe,
+0x1e300, 0x1e7ff,
+0x1e8c5, 0x1e8c6,
+0x1e8d7, 0x1e8ff,
+0x1e94c, 0x1e94f,
+0x1e95a, 0x1e95d,
+0x1e960, 0x1ec70,
+0x1ecb5, 0x1ed00,
+0x1ed3e, 0x1edff,
+0x1ee04, 0x1ee04,
+0x1ee20, 0x1ee20,
+0x1ee23, 0x1ee23,
+0x1ee25, 0x1ee26,
+0x1ee28, 0x1ee28,
+0x1ee33, 0x1ee33,
+0x1ee38, 0x1ee38,
+0x1ee3a, 0x1ee3a,
+0x1ee3c, 0x1ee41,
+0x1ee43, 0x1ee46,
+0x1ee48, 0x1ee48,
+0x1ee4a, 0x1ee4a,
+0x1ee4c, 0x1ee4c,
+0x1ee50, 0x1ee50,
+0x1ee53, 0x1ee53,
+0x1ee55, 0x1ee56,
+0x1ee58, 0x1ee58,
+0x1ee5a, 0x1ee5a,
+0x1ee5c, 0x1ee5c,
+0x1ee5e, 0x1ee5e,
+0x1ee60, 0x1ee60,
+0x1ee63, 0x1ee63,
+0x1ee65, 0x1ee66,
+0x1ee6b, 0x1ee6b,
+0x1ee73, 0x1ee73,
+0x1ee78, 0x1ee78,
+0x1ee7d, 0x1ee7d,
+0x1ee7f, 0x1ee7f,
+0x1ee8a, 0x1ee8a,
+0x1ee9c, 0x1eea0,
+0x1eea4, 0x1eea4,
+0x1eeaa, 0x1eeaa,
+0x1eebc, 0x1eeef,
+0x1eef2, 0x1efff,
+0x1f02c, 0x1f02f,
+0x1f094, 0x1f09f,
+0x1f0af, 0x1f0b0,
+0x1f0c0, 0x1f0c0,
+0x1f0d0, 0x1f0d0,
+0x1f0f6, 0x1f0ff,
+0x1f10d, 0x1f10f,
+0x1f16d, 0x1f16f,
+0x1f1ad, 0x1f1e5,
+0x1f203, 0x1f20f,
+0x1f23c, 0x1f23f,
+0x1f249, 0x1f24f,
+0x1f252, 0x1f25f,
+0x1f266, 0x1f2ff,
+0x1f6d6, 0x1f6df,
+0x1f6ed, 0x1f6ef,
+0x1f6fb, 0x1f6ff,
+0x1f774, 0x1f77f,
+0x1f7d9, 0x1f7df,
+0x1f7ec, 0x1f7ff,
+0x1f80c, 0x1f80f,
+0x1f848, 0x1f84f,
+0x1f85a, 0x1f85f,
+0x1f888, 0x1f88f,
+0x1f8ae, 0x1f8ff,
+0x1f90c, 0x1f90c,
+0x1f972, 0x1f972,
+0x1f977, 0x1f979,
+0x1f9a3, 0x1f9a4,
+0x1f9ab, 0x1f9ad,
+0x1f9cb, 0x1f9cc,
+0x1fa54, 0x1fa5f,
+0x1fa6e, 0x1fa6f,
+0x1fa74, 0x1fa77,
+0x1fa7b, 0x1fa7f,
+0x1fa83, 0x1fa8f,
+0x1fa96, 0x1ffff,
+0x2a6d7, 0x2a6ff,
+0x2b735, 0x2b73f,
+0x2b81e, 0x2b81f,
+0x2cea2, 0x2ceaf,
+0x2ebe1, 0x2f7ff,
+0x2fa1e, 0xe00ff,
+0xe01f0, 0x10ffff,
+}; /* END of CR_C */
+
+/* PROPERTY: 'Canadian_Aboriginal': Script */
+static const OnigCodePoint
+CR_Canadian_Aboriginal[] = { 2,
+0x1400, 0x167f,
+0x18b0, 0x18f5,
+}; /* END of CR_Canadian_Aboriginal */
+
+/* PROPERTY: 'Carian': Script */
+static const OnigCodePoint
+CR_Carian[] = { 1,
+0x102a0, 0x102d0,
+}; /* END of CR_Carian */
+
+/* PROPERTY: 'Case_Ignorable': Derived Property */
+static const OnigCodePoint
+CR_Case_Ignorable[] = { 401,
+0x0027, 0x0027,
+0x002e, 0x002e,
+0x003a, 0x003a,
+0x005e, 0x005e,
+0x0060, 0x0060,
+0x00a8, 0x00a8,
+0x00ad, 0x00ad,
+0x00af, 0x00af,
+0x00b4, 0x00b4,
+0x00b7, 0x00b8,
+0x02b0, 0x036f,
+0x0374, 0x0375,
+0x037a, 0x037a,
+0x0384, 0x0385,
+0x0387, 0x0387,
+0x0483, 0x0489,
+0x0559, 0x0559,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05f4, 0x05f4,
+0x0600, 0x0605,
+0x0610, 0x061a,
+0x061c, 0x061c,
+0x0640, 0x0640,
+0x064b, 0x065f,
+0x0670, 0x0670,
+0x06d6, 0x06dd,
+0x06df, 0x06e8,
+0x06ea, 0x06ed,
+0x070f, 0x070f,
+0x0711, 0x0711,
+0x0730, 0x074a,
+0x07a6, 0x07b0,
+0x07eb, 0x07f5,
+0x07fa, 0x07fa,
+0x07fd, 0x07fd,
+0x0816, 0x082d,
+0x0859, 0x085b,
+0x08d3, 0x0902,
+0x093a, 0x093a,
+0x093c, 0x093c,
+0x0941, 0x0948,
+0x094d, 0x094d,
+0x0951, 0x0957,
+0x0962, 0x0963,
+0x0971, 0x0971,
+0x0981, 0x0981,
+0x09bc, 0x09bc,
+0x09c1, 0x09c4,
+0x09cd, 0x09cd,
+0x09e2, 0x09e3,
+0x09fe, 0x09fe,
+0x0a01, 0x0a02,
+0x0a3c, 0x0a3c,
+0x0a41, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a70, 0x0a71,
+0x0a75, 0x0a75,
+0x0a81, 0x0a82,
+0x0abc, 0x0abc,
+0x0ac1, 0x0ac5,
+0x0ac7, 0x0ac8,
+0x0acd, 0x0acd,
+0x0ae2, 0x0ae3,
+0x0afa, 0x0aff,
+0x0b01, 0x0b01,
+0x0b3c, 0x0b3c,
+0x0b3f, 0x0b3f,
+0x0b41, 0x0b44,
+0x0b4d, 0x0b4d,
+0x0b56, 0x0b56,
+0x0b62, 0x0b63,
+0x0b82, 0x0b82,
+0x0bc0, 0x0bc0,
+0x0bcd, 0x0bcd,
+0x0c00, 0x0c00,
+0x0c04, 0x0c04,
+0x0c3e, 0x0c40,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c62, 0x0c63,
+0x0c81, 0x0c81,
+0x0cbc, 0x0cbc,
+0x0cbf, 0x0cbf,
+0x0cc6, 0x0cc6,
+0x0ccc, 0x0ccd,
+0x0ce2, 0x0ce3,
+0x0d00, 0x0d01,
+0x0d3b, 0x0d3c,
+0x0d41, 0x0d44,
+0x0d4d, 0x0d4d,
+0x0d62, 0x0d63,
+0x0dca, 0x0dca,
+0x0dd2, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0e31, 0x0e31,
+0x0e34, 0x0e3a,
+0x0e46, 0x0e4e,
+0x0eb1, 0x0eb1,
+0x0eb4, 0x0ebc,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0f18, 0x0f19,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f71, 0x0f7e,
+0x0f80, 0x0f84,
+0x0f86, 0x0f87,
+0x0f8d, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x102d, 0x1030,
+0x1032, 0x1037,
+0x1039, 0x103a,
+0x103d, 0x103e,
+0x1058, 0x1059,
+0x105e, 0x1060,
+0x1071, 0x1074,
+0x1082, 0x1082,
+0x1085, 0x1086,
+0x108d, 0x108d,
+0x109d, 0x109d,
+0x10fc, 0x10fc,
+0x135d, 0x135f,
+0x1712, 0x1714,
+0x1732, 0x1734,
+0x1752, 0x1753,
+0x1772, 0x1773,
+0x17b4, 0x17b5,
+0x17b7, 0x17bd,
+0x17c6, 0x17c6,
+0x17c9, 0x17d3,
+0x17d7, 0x17d7,
+0x17dd, 0x17dd,
+0x180b, 0x180e,
+0x1843, 0x1843,
+0x1885, 0x1886,
+0x18a9, 0x18a9,
+0x1920, 0x1922,
+0x1927, 0x1928,
+0x1932, 0x1932,
+0x1939, 0x193b,
+0x1a17, 0x1a18,
+0x1a1b, 0x1a1b,
+0x1a56, 0x1a56,
+0x1a58, 0x1a5e,
+0x1a60, 0x1a60,
+0x1a62, 0x1a62,
+0x1a65, 0x1a6c,
+0x1a73, 0x1a7c,
+0x1a7f, 0x1a7f,
+0x1aa7, 0x1aa7,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b03,
+0x1b34, 0x1b34,
+0x1b36, 0x1b3a,
+0x1b3c, 0x1b3c,
+0x1b42, 0x1b42,
+0x1b6b, 0x1b73,
+0x1b80, 0x1b81,
+0x1ba2, 0x1ba5,
+0x1ba8, 0x1ba9,
+0x1bab, 0x1bad,
+0x1be6, 0x1be6,
+0x1be8, 0x1be9,
+0x1bed, 0x1bed,
+0x1bef, 0x1bf1,
+0x1c2c, 0x1c33,
+0x1c36, 0x1c37,
+0x1c78, 0x1c7d,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1ce0,
+0x1ce2, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf8, 0x1cf9,
+0x1d2c, 0x1d6a,
+0x1d78, 0x1d78,
+0x1d9b, 0x1df9,
+0x1dfb, 0x1dff,
+0x1fbd, 0x1fbd,
+0x1fbf, 0x1fc1,
+0x1fcd, 0x1fcf,
+0x1fdd, 0x1fdf,
+0x1fed, 0x1fef,
+0x1ffd, 0x1ffe,
+0x200b, 0x200f,
+0x2018, 0x2019,
+0x2024, 0x2024,
+0x2027, 0x2027,
+0x202a, 0x202e,
+0x2060, 0x2064,
+0x2066, 0x206f,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x20d0, 0x20f0,
+0x2c7c, 0x2c7d,
+0x2cef, 0x2cf1,
+0x2d6f, 0x2d6f,
+0x2d7f, 0x2d7f,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3005,
+0x302a, 0x302d,
+0x3031, 0x3035,
+0x303b, 0x303b,
+0x3099, 0x309e,
+0x30fc, 0x30fe,
+0xa015, 0xa015,
+0xa4f8, 0xa4fd,
+0xa60c, 0xa60c,
+0xa66f, 0xa672,
+0xa674, 0xa67d,
+0xa67f, 0xa67f,
+0xa69c, 0xa69f,
+0xa6f0, 0xa6f1,
+0xa700, 0xa721,
+0xa770, 0xa770,
+0xa788, 0xa78a,
+0xa7f8, 0xa7f9,
+0xa802, 0xa802,
+0xa806, 0xa806,
+0xa80b, 0xa80b,
+0xa825, 0xa826,
+0xa8c4, 0xa8c5,
+0xa8e0, 0xa8f1,
+0xa8ff, 0xa8ff,
+0xa926, 0xa92d,
+0xa947, 0xa951,
+0xa980, 0xa982,
+0xa9b3, 0xa9b3,
+0xa9b6, 0xa9b9,
+0xa9bc, 0xa9bd,
+0xa9cf, 0xa9cf,
+0xa9e5, 0xa9e6,
+0xaa29, 0xaa2e,
+0xaa31, 0xaa32,
+0xaa35, 0xaa36,
+0xaa43, 0xaa43,
+0xaa4c, 0xaa4c,
+0xaa70, 0xaa70,
+0xaa7c, 0xaa7c,
+0xaab0, 0xaab0,
+0xaab2, 0xaab4,
+0xaab7, 0xaab8,
+0xaabe, 0xaabf,
+0xaac1, 0xaac1,
+0xaadd, 0xaadd,
+0xaaec, 0xaaed,
+0xaaf3, 0xaaf4,
+0xaaf6, 0xaaf6,
+0xab5b, 0xab5f,
+0xabe5, 0xabe5,
+0xabe8, 0xabe8,
+0xabed, 0xabed,
+0xfb1e, 0xfb1e,
+0xfbb2, 0xfbc1,
+0xfe00, 0xfe0f,
+0xfe13, 0xfe13,
+0xfe20, 0xfe2f,
+0xfe52, 0xfe52,
+0xfe55, 0xfe55,
+0xfeff, 0xfeff,
+0xff07, 0xff07,
+0xff0e, 0xff0e,
+0xff1a, 0xff1a,
+0xff3e, 0xff3e,
+0xff40, 0xff40,
+0xff70, 0xff70,
+0xff9e, 0xff9f,
+0xffe3, 0xffe3,
+0xfff9, 0xfffb,
+0x101fd, 0x101fd,
+0x102e0, 0x102e0,
+0x10376, 0x1037a,
+0x10a01, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a0f,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10ae5, 0x10ae6,
+0x10d24, 0x10d27,
+0x10f46, 0x10f50,
+0x11001, 0x11001,
+0x11038, 0x11046,
+0x1107f, 0x11081,
+0x110b3, 0x110b6,
+0x110b9, 0x110ba,
+0x110bd, 0x110bd,
+0x110cd, 0x110cd,
+0x11100, 0x11102,
+0x11127, 0x1112b,
+0x1112d, 0x11134,
+0x11173, 0x11173,
+0x11180, 0x11181,
+0x111b6, 0x111be,
+0x111c9, 0x111cc,
+0x1122f, 0x11231,
+0x11234, 0x11234,
+0x11236, 0x11237,
+0x1123e, 0x1123e,
+0x112df, 0x112df,
+0x112e3, 0x112ea,
+0x11300, 0x11301,
+0x1133b, 0x1133c,
+0x11340, 0x11340,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11438, 0x1143f,
+0x11442, 0x11444,
+0x11446, 0x11446,
+0x1145e, 0x1145e,
+0x114b3, 0x114b8,
+0x114ba, 0x114ba,
+0x114bf, 0x114c0,
+0x114c2, 0x114c3,
+0x115b2, 0x115b5,
+0x115bc, 0x115bd,
+0x115bf, 0x115c0,
+0x115dc, 0x115dd,
+0x11633, 0x1163a,
+0x1163d, 0x1163d,
+0x1163f, 0x11640,
+0x116ab, 0x116ab,
+0x116ad, 0x116ad,
+0x116b0, 0x116b5,
+0x116b7, 0x116b7,
+0x1171d, 0x1171f,
+0x11722, 0x11725,
+0x11727, 0x1172b,
+0x1182f, 0x11837,
+0x11839, 0x1183a,
+0x119d4, 0x119d7,
+0x119da, 0x119db,
+0x119e0, 0x119e0,
+0x11a01, 0x11a0a,
+0x11a33, 0x11a38,
+0x11a3b, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a51, 0x11a56,
+0x11a59, 0x11a5b,
+0x11a8a, 0x11a96,
+0x11a98, 0x11a99,
+0x11c30, 0x11c36,
+0x11c38, 0x11c3d,
+0x11c3f, 0x11c3f,
+0x11c92, 0x11ca7,
+0x11caa, 0x11cb0,
+0x11cb2, 0x11cb3,
+0x11cb5, 0x11cb6,
+0x11d31, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d45,
+0x11d47, 0x11d47,
+0x11d90, 0x11d91,
+0x11d95, 0x11d95,
+0x11d97, 0x11d97,
+0x11ef3, 0x11ef4,
+0x13430, 0x13438,
+0x16af0, 0x16af4,
+0x16b30, 0x16b36,
+0x16b40, 0x16b43,
+0x16f4f, 0x16f4f,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x1bc9d, 0x1bc9e,
+0x1bca0, 0x1bca3,
+0x1d167, 0x1d169,
+0x1d173, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e130, 0x1e13d,
+0x1e2ec, 0x1e2ef,
+0x1e8d0, 0x1e8d6,
+0x1e944, 0x1e94b,
+0x1f3fb, 0x1f3ff,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+}; /* END of CR_Case_Ignorable */
+
+/* PROPERTY: 'Cased': Derived Property */
+static const OnigCodePoint
+CR_Cased[] = { 140,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x01ba,
+0x01bc, 0x01bf,
+0x01c4, 0x0293,
+0x0295, 0x02b8,
+0x02c0, 0x02c1,
+0x02e0, 0x02e4,
+0x0345, 0x0345,
+0x0370, 0x0373,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0560, 0x0588,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1d00, 0x1dbf,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2134,
+0x2139, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x217f,
+0x2183, 0x2184,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa640, 0xa66d,
+0xa680, 0xa69d,
+0xa722, 0xa787,
+0xa78b, 0xa78e,
+0xa790, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f8, 0xa7fa,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0x10400, 0x1044f,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x118a0, 0x118df,
+0x16e40, 0x16e7f,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e900, 0x1e943,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+}; /* END of CR_Cased */
+
+/* PROPERTY: 'Caucasian_Albanian': Script */
+static const OnigCodePoint
+CR_Caucasian_Albanian[] = { 2,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+}; /* END of CR_Caucasian_Albanian */
+
+/* PROPERTY: 'Cc': General Category */
+#define CR_Cc CR_Cntrl
+
+/* PROPERTY: 'Cf': General Category */
+static const OnigCodePoint
+CR_Cf[] = { 20,
+0x00ad, 0x00ad,
+0x0600, 0x0605,
+0x061c, 0x061c,
+0x06dd, 0x06dd,
+0x070f, 0x070f,
+0x08e2, 0x08e2,
+0x180e, 0x180e,
+0x200b, 0x200f,
+0x202a, 0x202e,
+0x2060, 0x2064,
+0x2066, 0x206f,
+0xfeff, 0xfeff,
+0xfff9, 0xfffb,
+0x110bd, 0x110bd,
+0x110cd, 0x110cd,
+0x13430, 0x13438,
+0x1bca0, 0x1bca3,
+0x1d173, 0x1d17a,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+}; /* END of CR_Cf */
+
+/* PROPERTY: 'Chakma': Script */
+static const OnigCodePoint
+CR_Chakma[] = { 2,
+0x11100, 0x11134,
+0x11136, 0x11146,
+}; /* END of CR_Chakma */
+
+/* PROPERTY: 'Cham': Script */
+static const OnigCodePoint
+CR_Cham[] = { 4,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaa5f,
+}; /* END of CR_Cham */
+
+/* PROPERTY: 'Changes_When_Casefolded': Derived Property */
+static const OnigCodePoint
+CR_Changes_When_Casefolded[] = { 612,
+0x0041, 0x005a,
+0x00b5, 0x00b5,
+0x00c0, 0x00d6,
+0x00d8, 0x00df,
+0x0100, 0x0100,
+0x0102, 0x0102,
+0x0104, 0x0104,
+0x0106, 0x0106,
+0x0108, 0x0108,
+0x010a, 0x010a,
+0x010c, 0x010c,
+0x010e, 0x010e,
+0x0110, 0x0110,
+0x0112, 0x0112,
+0x0114, 0x0114,
+0x0116, 0x0116,
+0x0118, 0x0118,
+0x011a, 0x011a,
+0x011c, 0x011c,
+0x011e, 0x011e,
+0x0120, 0x0120,
+0x0122, 0x0122,
+0x0124, 0x0124,
+0x0126, 0x0126,
+0x0128, 0x0128,
+0x012a, 0x012a,
+0x012c, 0x012c,
+0x012e, 0x012e,
+0x0130, 0x0130,
+0x0132, 0x0132,
+0x0134, 0x0134,
+0x0136, 0x0136,
+0x0139, 0x0139,
+0x013b, 0x013b,
+0x013d, 0x013d,
+0x013f, 0x013f,
+0x0141, 0x0141,
+0x0143, 0x0143,
+0x0145, 0x0145,
+0x0147, 0x0147,
+0x0149, 0x014a,
+0x014c, 0x014c,
+0x014e, 0x014e,
+0x0150, 0x0150,
+0x0152, 0x0152,
+0x0154, 0x0154,
+0x0156, 0x0156,
+0x0158, 0x0158,
+0x015a, 0x015a,
+0x015c, 0x015c,
+0x015e, 0x015e,
+0x0160, 0x0160,
+0x0162, 0x0162,
+0x0164, 0x0164,
+0x0166, 0x0166,
+0x0168, 0x0168,
+0x016a, 0x016a,
+0x016c, 0x016c,
+0x016e, 0x016e,
+0x0170, 0x0170,
+0x0172, 0x0172,
+0x0174, 0x0174,
+0x0176, 0x0176,
+0x0178, 0x0179,
+0x017b, 0x017b,
+0x017d, 0x017d,
+0x017f, 0x017f,
+0x0181, 0x0182,
+0x0184, 0x0184,
+0x0186, 0x0187,
+0x0189, 0x018b,
+0x018e, 0x0191,
+0x0193, 0x0194,
+0x0196, 0x0198,
+0x019c, 0x019d,
+0x019f, 0x01a0,
+0x01a2, 0x01a2,
+0x01a4, 0x01a4,
+0x01a6, 0x01a7,
+0x01a9, 0x01a9,
+0x01ac, 0x01ac,
+0x01ae, 0x01af,
+0x01b1, 0x01b3,
+0x01b5, 0x01b5,
+0x01b7, 0x01b8,
+0x01bc, 0x01bc,
+0x01c4, 0x01c5,
+0x01c7, 0x01c8,
+0x01ca, 0x01cb,
+0x01cd, 0x01cd,
+0x01cf, 0x01cf,
+0x01d1, 0x01d1,
+0x01d3, 0x01d3,
+0x01d5, 0x01d5,
+0x01d7, 0x01d7,
+0x01d9, 0x01d9,
+0x01db, 0x01db,
+0x01de, 0x01de,
+0x01e0, 0x01e0,
+0x01e2, 0x01e2,
+0x01e4, 0x01e4,
+0x01e6, 0x01e6,
+0x01e8, 0x01e8,
+0x01ea, 0x01ea,
+0x01ec, 0x01ec,
+0x01ee, 0x01ee,
+0x01f1, 0x01f2,
+0x01f4, 0x01f4,
+0x01f6, 0x01f8,
+0x01fa, 0x01fa,
+0x01fc, 0x01fc,
+0x01fe, 0x01fe,
+0x0200, 0x0200,
+0x0202, 0x0202,
+0x0204, 0x0204,
+0x0206, 0x0206,
+0x0208, 0x0208,
+0x020a, 0x020a,
+0x020c, 0x020c,
+0x020e, 0x020e,
+0x0210, 0x0210,
+0x0212, 0x0212,
+0x0214, 0x0214,
+0x0216, 0x0216,
+0x0218, 0x0218,
+0x021a, 0x021a,
+0x021c, 0x021c,
+0x021e, 0x021e,
+0x0220, 0x0220,
+0x0222, 0x0222,
+0x0224, 0x0224,
+0x0226, 0x0226,
+0x0228, 0x0228,
+0x022a, 0x022a,
+0x022c, 0x022c,
+0x022e, 0x022e,
+0x0230, 0x0230,
+0x0232, 0x0232,
+0x023a, 0x023b,
+0x023d, 0x023e,
+0x0241, 0x0241,
+0x0243, 0x0246,
+0x0248, 0x0248,
+0x024a, 0x024a,
+0x024c, 0x024c,
+0x024e, 0x024e,
+0x0345, 0x0345,
+0x0370, 0x0370,
+0x0372, 0x0372,
+0x0376, 0x0376,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x038f,
+0x0391, 0x03a1,
+0x03a3, 0x03ab,
+0x03c2, 0x03c2,
+0x03cf, 0x03d1,
+0x03d5, 0x03d6,
+0x03d8, 0x03d8,
+0x03da, 0x03da,
+0x03dc, 0x03dc,
+0x03de, 0x03de,
+0x03e0, 0x03e0,
+0x03e2, 0x03e2,
+0x03e4, 0x03e4,
+0x03e6, 0x03e6,
+0x03e8, 0x03e8,
+0x03ea, 0x03ea,
+0x03ec, 0x03ec,
+0x03ee, 0x03ee,
+0x03f0, 0x03f1,
+0x03f4, 0x03f5,
+0x03f7, 0x03f7,
+0x03f9, 0x03fa,
+0x03fd, 0x042f,
+0x0460, 0x0460,
+0x0462, 0x0462,
+0x0464, 0x0464,
+0x0466, 0x0466,
+0x0468, 0x0468,
+0x046a, 0x046a,
+0x046c, 0x046c,
+0x046e, 0x046e,
+0x0470, 0x0470,
+0x0472, 0x0472,
+0x0474, 0x0474,
+0x0476, 0x0476,
+0x0478, 0x0478,
+0x047a, 0x047a,
+0x047c, 0x047c,
+0x047e, 0x047e,
+0x0480, 0x0480,
+0x048a, 0x048a,
+0x048c, 0x048c,
+0x048e, 0x048e,
+0x0490, 0x0490,
+0x0492, 0x0492,
+0x0494, 0x0494,
+0x0496, 0x0496,
+0x0498, 0x0498,
+0x049a, 0x049a,
+0x049c, 0x049c,
+0x049e, 0x049e,
+0x04a0, 0x04a0,
+0x04a2, 0x04a2,
+0x04a4, 0x04a4,
+0x04a6, 0x04a6,
+0x04a8, 0x04a8,
+0x04aa, 0x04aa,
+0x04ac, 0x04ac,
+0x04ae, 0x04ae,
+0x04b0, 0x04b0,
+0x04b2, 0x04b2,
+0x04b4, 0x04b4,
+0x04b6, 0x04b6,
+0x04b8, 0x04b8,
+0x04ba, 0x04ba,
+0x04bc, 0x04bc,
+0x04be, 0x04be,
+0x04c0, 0x04c1,
+0x04c3, 0x04c3,
+0x04c5, 0x04c5,
+0x04c7, 0x04c7,
+0x04c9, 0x04c9,
+0x04cb, 0x04cb,
+0x04cd, 0x04cd,
+0x04d0, 0x04d0,
+0x04d2, 0x04d2,
+0x04d4, 0x04d4,
+0x04d6, 0x04d6,
+0x04d8, 0x04d8,
+0x04da, 0x04da,
+0x04dc, 0x04dc,
+0x04de, 0x04de,
+0x04e0, 0x04e0,
+0x04e2, 0x04e2,
+0x04e4, 0x04e4,
+0x04e6, 0x04e6,
+0x04e8, 0x04e8,
+0x04ea, 0x04ea,
+0x04ec, 0x04ec,
+0x04ee, 0x04ee,
+0x04f0, 0x04f0,
+0x04f2, 0x04f2,
+0x04f4, 0x04f4,
+0x04f6, 0x04f6,
+0x04f8, 0x04f8,
+0x04fa, 0x04fa,
+0x04fc, 0x04fc,
+0x04fe, 0x04fe,
+0x0500, 0x0500,
+0x0502, 0x0502,
+0x0504, 0x0504,
+0x0506, 0x0506,
+0x0508, 0x0508,
+0x050a, 0x050a,
+0x050c, 0x050c,
+0x050e, 0x050e,
+0x0510, 0x0510,
+0x0512, 0x0512,
+0x0514, 0x0514,
+0x0516, 0x0516,
+0x0518, 0x0518,
+0x051a, 0x051a,
+0x051c, 0x051c,
+0x051e, 0x051e,
+0x0520, 0x0520,
+0x0522, 0x0522,
+0x0524, 0x0524,
+0x0526, 0x0526,
+0x0528, 0x0528,
+0x052a, 0x052a,
+0x052c, 0x052c,
+0x052e, 0x052e,
+0x0531, 0x0556,
+0x0587, 0x0587,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1e00, 0x1e00,
+0x1e02, 0x1e02,
+0x1e04, 0x1e04,
+0x1e06, 0x1e06,
+0x1e08, 0x1e08,
+0x1e0a, 0x1e0a,
+0x1e0c, 0x1e0c,
+0x1e0e, 0x1e0e,
+0x1e10, 0x1e10,
+0x1e12, 0x1e12,
+0x1e14, 0x1e14,
+0x1e16, 0x1e16,
+0x1e18, 0x1e18,
+0x1e1a, 0x1e1a,
+0x1e1c, 0x1e1c,
+0x1e1e, 0x1e1e,
+0x1e20, 0x1e20,
+0x1e22, 0x1e22,
+0x1e24, 0x1e24,
+0x1e26, 0x1e26,
+0x1e28, 0x1e28,
+0x1e2a, 0x1e2a,
+0x1e2c, 0x1e2c,
+0x1e2e, 0x1e2e,
+0x1e30, 0x1e30,
+0x1e32, 0x1e32,
+0x1e34, 0x1e34,
+0x1e36, 0x1e36,
+0x1e38, 0x1e38,
+0x1e3a, 0x1e3a,
+0x1e3c, 0x1e3c,
+0x1e3e, 0x1e3e,
+0x1e40, 0x1e40,
+0x1e42, 0x1e42,
+0x1e44, 0x1e44,
+0x1e46, 0x1e46,
+0x1e48, 0x1e48,
+0x1e4a, 0x1e4a,
+0x1e4c, 0x1e4c,
+0x1e4e, 0x1e4e,
+0x1e50, 0x1e50,
+0x1e52, 0x1e52,
+0x1e54, 0x1e54,
+0x1e56, 0x1e56,
+0x1e58, 0x1e58,
+0x1e5a, 0x1e5a,
+0x1e5c, 0x1e5c,
+0x1e5e, 0x1e5e,
+0x1e60, 0x1e60,
+0x1e62, 0x1e62,
+0x1e64, 0x1e64,
+0x1e66, 0x1e66,
+0x1e68, 0x1e68,
+0x1e6a, 0x1e6a,
+0x1e6c, 0x1e6c,
+0x1e6e, 0x1e6e,
+0x1e70, 0x1e70,
+0x1e72, 0x1e72,
+0x1e74, 0x1e74,
+0x1e76, 0x1e76,
+0x1e78, 0x1e78,
+0x1e7a, 0x1e7a,
+0x1e7c, 0x1e7c,
+0x1e7e, 0x1e7e,
+0x1e80, 0x1e80,
+0x1e82, 0x1e82,
+0x1e84, 0x1e84,
+0x1e86, 0x1e86,
+0x1e88, 0x1e88,
+0x1e8a, 0x1e8a,
+0x1e8c, 0x1e8c,
+0x1e8e, 0x1e8e,
+0x1e90, 0x1e90,
+0x1e92, 0x1e92,
+0x1e94, 0x1e94,
+0x1e9a, 0x1e9b,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1ea0,
+0x1ea2, 0x1ea2,
+0x1ea4, 0x1ea4,
+0x1ea6, 0x1ea6,
+0x1ea8, 0x1ea8,
+0x1eaa, 0x1eaa,
+0x1eac, 0x1eac,
+0x1eae, 0x1eae,
+0x1eb0, 0x1eb0,
+0x1eb2, 0x1eb2,
+0x1eb4, 0x1eb4,
+0x1eb6, 0x1eb6,
+0x1eb8, 0x1eb8,
+0x1eba, 0x1eba,
+0x1ebc, 0x1ebc,
+0x1ebe, 0x1ebe,
+0x1ec0, 0x1ec0,
+0x1ec2, 0x1ec2,
+0x1ec4, 0x1ec4,
+0x1ec6, 0x1ec6,
+0x1ec8, 0x1ec8,
+0x1eca, 0x1eca,
+0x1ecc, 0x1ecc,
+0x1ece, 0x1ece,
+0x1ed0, 0x1ed0,
+0x1ed2, 0x1ed2,
+0x1ed4, 0x1ed4,
+0x1ed6, 0x1ed6,
+0x1ed8, 0x1ed8,
+0x1eda, 0x1eda,
+0x1edc, 0x1edc,
+0x1ede, 0x1ede,
+0x1ee0, 0x1ee0,
+0x1ee2, 0x1ee2,
+0x1ee4, 0x1ee4,
+0x1ee6, 0x1ee6,
+0x1ee8, 0x1ee8,
+0x1eea, 0x1eea,
+0x1eec, 0x1eec,
+0x1eee, 0x1eee,
+0x1ef0, 0x1ef0,
+0x1ef2, 0x1ef2,
+0x1ef4, 0x1ef4,
+0x1ef6, 0x1ef6,
+0x1ef8, 0x1ef8,
+0x1efa, 0x1efa,
+0x1efc, 0x1efc,
+0x1efe, 0x1efe,
+0x1f08, 0x1f0f,
+0x1f18, 0x1f1d,
+0x1f28, 0x1f2f,
+0x1f38, 0x1f3f,
+0x1f48, 0x1f4d,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f5f,
+0x1f68, 0x1f6f,
+0x1f80, 0x1faf,
+0x1fb2, 0x1fb4,
+0x1fb7, 0x1fbc,
+0x1fc2, 0x1fc4,
+0x1fc7, 0x1fcc,
+0x1fd8, 0x1fdb,
+0x1fe8, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff7, 0x1ffc,
+0x2126, 0x2126,
+0x212a, 0x212b,
+0x2132, 0x2132,
+0x2160, 0x216f,
+0x2183, 0x2183,
+0x24b6, 0x24cf,
+0x2c00, 0x2c2e,
+0x2c60, 0x2c60,
+0x2c62, 0x2c64,
+0x2c67, 0x2c67,
+0x2c69, 0x2c69,
+0x2c6b, 0x2c6b,
+0x2c6d, 0x2c70,
+0x2c72, 0x2c72,
+0x2c75, 0x2c75,
+0x2c7e, 0x2c80,
+0x2c82, 0x2c82,
+0x2c84, 0x2c84,
+0x2c86, 0x2c86,
+0x2c88, 0x2c88,
+0x2c8a, 0x2c8a,
+0x2c8c, 0x2c8c,
+0x2c8e, 0x2c8e,
+0x2c90, 0x2c90,
+0x2c92, 0x2c92,
+0x2c94, 0x2c94,
+0x2c96, 0x2c96,
+0x2c98, 0x2c98,
+0x2c9a, 0x2c9a,
+0x2c9c, 0x2c9c,
+0x2c9e, 0x2c9e,
+0x2ca0, 0x2ca0,
+0x2ca2, 0x2ca2,
+0x2ca4, 0x2ca4,
+0x2ca6, 0x2ca6,
+0x2ca8, 0x2ca8,
+0x2caa, 0x2caa,
+0x2cac, 0x2cac,
+0x2cae, 0x2cae,
+0x2cb0, 0x2cb0,
+0x2cb2, 0x2cb2,
+0x2cb4, 0x2cb4,
+0x2cb6, 0x2cb6,
+0x2cb8, 0x2cb8,
+0x2cba, 0x2cba,
+0x2cbc, 0x2cbc,
+0x2cbe, 0x2cbe,
+0x2cc0, 0x2cc0,
+0x2cc2, 0x2cc2,
+0x2cc4, 0x2cc4,
+0x2cc6, 0x2cc6,
+0x2cc8, 0x2cc8,
+0x2cca, 0x2cca,
+0x2ccc, 0x2ccc,
+0x2cce, 0x2cce,
+0x2cd0, 0x2cd0,
+0x2cd2, 0x2cd2,
+0x2cd4, 0x2cd4,
+0x2cd6, 0x2cd6,
+0x2cd8, 0x2cd8,
+0x2cda, 0x2cda,
+0x2cdc, 0x2cdc,
+0x2cde, 0x2cde,
+0x2ce0, 0x2ce0,
+0x2ce2, 0x2ce2,
+0x2ceb, 0x2ceb,
+0x2ced, 0x2ced,
+0x2cf2, 0x2cf2,
+0xa640, 0xa640,
+0xa642, 0xa642,
+0xa644, 0xa644,
+0xa646, 0xa646,
+0xa648, 0xa648,
+0xa64a, 0xa64a,
+0xa64c, 0xa64c,
+0xa64e, 0xa64e,
+0xa650, 0xa650,
+0xa652, 0xa652,
+0xa654, 0xa654,
+0xa656, 0xa656,
+0xa658, 0xa658,
+0xa65a, 0xa65a,
+0xa65c, 0xa65c,
+0xa65e, 0xa65e,
+0xa660, 0xa660,
+0xa662, 0xa662,
+0xa664, 0xa664,
+0xa666, 0xa666,
+0xa668, 0xa668,
+0xa66a, 0xa66a,
+0xa66c, 0xa66c,
+0xa680, 0xa680,
+0xa682, 0xa682,
+0xa684, 0xa684,
+0xa686, 0xa686,
+0xa688, 0xa688,
+0xa68a, 0xa68a,
+0xa68c, 0xa68c,
+0xa68e, 0xa68e,
+0xa690, 0xa690,
+0xa692, 0xa692,
+0xa694, 0xa694,
+0xa696, 0xa696,
+0xa698, 0xa698,
+0xa69a, 0xa69a,
+0xa722, 0xa722,
+0xa724, 0xa724,
+0xa726, 0xa726,
+0xa728, 0xa728,
+0xa72a, 0xa72a,
+0xa72c, 0xa72c,
+0xa72e, 0xa72e,
+0xa732, 0xa732,
+0xa734, 0xa734,
+0xa736, 0xa736,
+0xa738, 0xa738,
+0xa73a, 0xa73a,
+0xa73c, 0xa73c,
+0xa73e, 0xa73e,
+0xa740, 0xa740,
+0xa742, 0xa742,
+0xa744, 0xa744,
+0xa746, 0xa746,
+0xa748, 0xa748,
+0xa74a, 0xa74a,
+0xa74c, 0xa74c,
+0xa74e, 0xa74e,
+0xa750, 0xa750,
+0xa752, 0xa752,
+0xa754, 0xa754,
+0xa756, 0xa756,
+0xa758, 0xa758,
+0xa75a, 0xa75a,
+0xa75c, 0xa75c,
+0xa75e, 0xa75e,
+0xa760, 0xa760,
+0xa762, 0xa762,
+0xa764, 0xa764,
+0xa766, 0xa766,
+0xa768, 0xa768,
+0xa76a, 0xa76a,
+0xa76c, 0xa76c,
+0xa76e, 0xa76e,
+0xa779, 0xa779,
+0xa77b, 0xa77b,
+0xa77d, 0xa77e,
+0xa780, 0xa780,
+0xa782, 0xa782,
+0xa784, 0xa784,
+0xa786, 0xa786,
+0xa78b, 0xa78b,
+0xa78d, 0xa78d,
+0xa790, 0xa790,
+0xa792, 0xa792,
+0xa796, 0xa796,
+0xa798, 0xa798,
+0xa79a, 0xa79a,
+0xa79c, 0xa79c,
+0xa79e, 0xa79e,
+0xa7a0, 0xa7a0,
+0xa7a2, 0xa7a2,
+0xa7a4, 0xa7a4,
+0xa7a6, 0xa7a6,
+0xa7a8, 0xa7a8,
+0xa7aa, 0xa7ae,
+0xa7b0, 0xa7b4,
+0xa7b6, 0xa7b6,
+0xa7b8, 0xa7b8,
+0xa7ba, 0xa7ba,
+0xa7bc, 0xa7bc,
+0xa7be, 0xa7be,
+0xa7c2, 0xa7c2,
+0xa7c4, 0xa7c6,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff21, 0xff3a,
+0x10400, 0x10427,
+0x104b0, 0x104d3,
+0x10c80, 0x10cb2,
+0x118a0, 0x118bf,
+0x16e40, 0x16e5f,
+0x1e900, 0x1e921,
+}; /* END of CR_Changes_When_Casefolded */
+
+/* PROPERTY: 'Changes_When_Casemapped': Derived Property */
+static const OnigCodePoint
+CR_Changes_When_Casemapped[] = { 123,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00b5, 0x00b5,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x0137,
+0x0139, 0x018c,
+0x018e, 0x019a,
+0x019c, 0x01a9,
+0x01ac, 0x01b9,
+0x01bc, 0x01bd,
+0x01bf, 0x01bf,
+0x01c4, 0x0220,
+0x0222, 0x0233,
+0x023a, 0x0254,
+0x0256, 0x0257,
+0x0259, 0x0259,
+0x025b, 0x025c,
+0x0260, 0x0261,
+0x0263, 0x0263,
+0x0265, 0x0266,
+0x0268, 0x026c,
+0x026f, 0x026f,
+0x0271, 0x0272,
+0x0275, 0x0275,
+0x027d, 0x027d,
+0x0280, 0x0280,
+0x0282, 0x0283,
+0x0287, 0x028c,
+0x0292, 0x0292,
+0x029d, 0x029e,
+0x0345, 0x0345,
+0x0370, 0x0373,
+0x0376, 0x0377,
+0x037b, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03d1,
+0x03d5, 0x03f5,
+0x03f7, 0x03fb,
+0x03fd, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0561, 0x0587,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1d79, 0x1d79,
+0x1d7d, 0x1d7d,
+0x1d8e, 0x1d8e,
+0x1e00, 0x1e9b,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2126, 0x2126,
+0x212a, 0x212b,
+0x2132, 0x2132,
+0x214e, 0x214e,
+0x2160, 0x217f,
+0x2183, 0x2184,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2c70,
+0x2c72, 0x2c73,
+0x2c75, 0x2c76,
+0x2c7e, 0x2ce3,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa640, 0xa66d,
+0xa680, 0xa69b,
+0xa722, 0xa72f,
+0xa732, 0xa76f,
+0xa779, 0xa787,
+0xa78b, 0xa78d,
+0xa790, 0xa794,
+0xa796, 0xa7ae,
+0xa7b0, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xab53, 0xab53,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0x10400, 0x1044f,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x118a0, 0x118df,
+0x16e40, 0x16e7f,
+0x1e900, 0x1e943,
+}; /* END of CR_Changes_When_Casemapped */
+
+/* PROPERTY: 'Changes_When_Lowercased': Derived Property */
+static const OnigCodePoint
+CR_Changes_When_Lowercased[] = { 599,
+0x0041, 0x005a,
+0x00c0, 0x00d6,
+0x00d8, 0x00de,
+0x0100, 0x0100,
+0x0102, 0x0102,
+0x0104, 0x0104,
+0x0106, 0x0106,
+0x0108, 0x0108,
+0x010a, 0x010a,
+0x010c, 0x010c,
+0x010e, 0x010e,
+0x0110, 0x0110,
+0x0112, 0x0112,
+0x0114, 0x0114,
+0x0116, 0x0116,
+0x0118, 0x0118,
+0x011a, 0x011a,
+0x011c, 0x011c,
+0x011e, 0x011e,
+0x0120, 0x0120,
+0x0122, 0x0122,
+0x0124, 0x0124,
+0x0126, 0x0126,
+0x0128, 0x0128,
+0x012a, 0x012a,
+0x012c, 0x012c,
+0x012e, 0x012e,
+0x0130, 0x0130,
+0x0132, 0x0132,
+0x0134, 0x0134,
+0x0136, 0x0136,
+0x0139, 0x0139,
+0x013b, 0x013b,
+0x013d, 0x013d,
+0x013f, 0x013f,
+0x0141, 0x0141,
+0x0143, 0x0143,
+0x0145, 0x0145,
+0x0147, 0x0147,
+0x014a, 0x014a,
+0x014c, 0x014c,
+0x014e, 0x014e,
+0x0150, 0x0150,
+0x0152, 0x0152,
+0x0154, 0x0154,
+0x0156, 0x0156,
+0x0158, 0x0158,
+0x015a, 0x015a,
+0x015c, 0x015c,
+0x015e, 0x015e,
+0x0160, 0x0160,
+0x0162, 0x0162,
+0x0164, 0x0164,
+0x0166, 0x0166,
+0x0168, 0x0168,
+0x016a, 0x016a,
+0x016c, 0x016c,
+0x016e, 0x016e,
+0x0170, 0x0170,
+0x0172, 0x0172,
+0x0174, 0x0174,
+0x0176, 0x0176,
+0x0178, 0x0179,
+0x017b, 0x017b,
+0x017d, 0x017d,
+0x0181, 0x0182,
+0x0184, 0x0184,
+0x0186, 0x0187,
+0x0189, 0x018b,
+0x018e, 0x0191,
+0x0193, 0x0194,
+0x0196, 0x0198,
+0x019c, 0x019d,
+0x019f, 0x01a0,
+0x01a2, 0x01a2,
+0x01a4, 0x01a4,
+0x01a6, 0x01a7,
+0x01a9, 0x01a9,
+0x01ac, 0x01ac,
+0x01ae, 0x01af,
+0x01b1, 0x01b3,
+0x01b5, 0x01b5,
+0x01b7, 0x01b8,
+0x01bc, 0x01bc,
+0x01c4, 0x01c5,
+0x01c7, 0x01c8,
+0x01ca, 0x01cb,
+0x01cd, 0x01cd,
+0x01cf, 0x01cf,
+0x01d1, 0x01d1,
+0x01d3, 0x01d3,
+0x01d5, 0x01d5,
+0x01d7, 0x01d7,
+0x01d9, 0x01d9,
+0x01db, 0x01db,
+0x01de, 0x01de,
+0x01e0, 0x01e0,
+0x01e2, 0x01e2,
+0x01e4, 0x01e4,
+0x01e6, 0x01e6,
+0x01e8, 0x01e8,
+0x01ea, 0x01ea,
+0x01ec, 0x01ec,
+0x01ee, 0x01ee,
+0x01f1, 0x01f2,
+0x01f4, 0x01f4,
+0x01f6, 0x01f8,
+0x01fa, 0x01fa,
+0x01fc, 0x01fc,
+0x01fe, 0x01fe,
+0x0200, 0x0200,
+0x0202, 0x0202,
+0x0204, 0x0204,
+0x0206, 0x0206,
+0x0208, 0x0208,
+0x020a, 0x020a,
+0x020c, 0x020c,
+0x020e, 0x020e,
+0x0210, 0x0210,
+0x0212, 0x0212,
+0x0214, 0x0214,
+0x0216, 0x0216,
+0x0218, 0x0218,
+0x021a, 0x021a,
+0x021c, 0x021c,
+0x021e, 0x021e,
+0x0220, 0x0220,
+0x0222, 0x0222,
+0x0224, 0x0224,
+0x0226, 0x0226,
+0x0228, 0x0228,
+0x022a, 0x022a,
+0x022c, 0x022c,
+0x022e, 0x022e,
+0x0230, 0x0230,
+0x0232, 0x0232,
+0x023a, 0x023b,
+0x023d, 0x023e,
+0x0241, 0x0241,
+0x0243, 0x0246,
+0x0248, 0x0248,
+0x024a, 0x024a,
+0x024c, 0x024c,
+0x024e, 0x024e,
+0x0370, 0x0370,
+0x0372, 0x0372,
+0x0376, 0x0376,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x038f,
+0x0391, 0x03a1,
+0x03a3, 0x03ab,
+0x03cf, 0x03cf,
+0x03d8, 0x03d8,
+0x03da, 0x03da,
+0x03dc, 0x03dc,
+0x03de, 0x03de,
+0x03e0, 0x03e0,
+0x03e2, 0x03e2,
+0x03e4, 0x03e4,
+0x03e6, 0x03e6,
+0x03e8, 0x03e8,
+0x03ea, 0x03ea,
+0x03ec, 0x03ec,
+0x03ee, 0x03ee,
+0x03f4, 0x03f4,
+0x03f7, 0x03f7,
+0x03f9, 0x03fa,
+0x03fd, 0x042f,
+0x0460, 0x0460,
+0x0462, 0x0462,
+0x0464, 0x0464,
+0x0466, 0x0466,
+0x0468, 0x0468,
+0x046a, 0x046a,
+0x046c, 0x046c,
+0x046e, 0x046e,
+0x0470, 0x0470,
+0x0472, 0x0472,
+0x0474, 0x0474,
+0x0476, 0x0476,
+0x0478, 0x0478,
+0x047a, 0x047a,
+0x047c, 0x047c,
+0x047e, 0x047e,
+0x0480, 0x0480,
+0x048a, 0x048a,
+0x048c, 0x048c,
+0x048e, 0x048e,
+0x0490, 0x0490,
+0x0492, 0x0492,
+0x0494, 0x0494,
+0x0496, 0x0496,
+0x0498, 0x0498,
+0x049a, 0x049a,
+0x049c, 0x049c,
+0x049e, 0x049e,
+0x04a0, 0x04a0,
+0x04a2, 0x04a2,
+0x04a4, 0x04a4,
+0x04a6, 0x04a6,
+0x04a8, 0x04a8,
+0x04aa, 0x04aa,
+0x04ac, 0x04ac,
+0x04ae, 0x04ae,
+0x04b0, 0x04b0,
+0x04b2, 0x04b2,
+0x04b4, 0x04b4,
+0x04b6, 0x04b6,
+0x04b8, 0x04b8,
+0x04ba, 0x04ba,
+0x04bc, 0x04bc,
+0x04be, 0x04be,
+0x04c0, 0x04c1,
+0x04c3, 0x04c3,
+0x04c5, 0x04c5,
+0x04c7, 0x04c7,
+0x04c9, 0x04c9,
+0x04cb, 0x04cb,
+0x04cd, 0x04cd,
+0x04d0, 0x04d0,
+0x04d2, 0x04d2,
+0x04d4, 0x04d4,
+0x04d6, 0x04d6,
+0x04d8, 0x04d8,
+0x04da, 0x04da,
+0x04dc, 0x04dc,
+0x04de, 0x04de,
+0x04e0, 0x04e0,
+0x04e2, 0x04e2,
+0x04e4, 0x04e4,
+0x04e6, 0x04e6,
+0x04e8, 0x04e8,
+0x04ea, 0x04ea,
+0x04ec, 0x04ec,
+0x04ee, 0x04ee,
+0x04f0, 0x04f0,
+0x04f2, 0x04f2,
+0x04f4, 0x04f4,
+0x04f6, 0x04f6,
+0x04f8, 0x04f8,
+0x04fa, 0x04fa,
+0x04fc, 0x04fc,
+0x04fe, 0x04fe,
+0x0500, 0x0500,
+0x0502, 0x0502,
+0x0504, 0x0504,
+0x0506, 0x0506,
+0x0508, 0x0508,
+0x050a, 0x050a,
+0x050c, 0x050c,
+0x050e, 0x050e,
+0x0510, 0x0510,
+0x0512, 0x0512,
+0x0514, 0x0514,
+0x0516, 0x0516,
+0x0518, 0x0518,
+0x051a, 0x051a,
+0x051c, 0x051c,
+0x051e, 0x051e,
+0x0520, 0x0520,
+0x0522, 0x0522,
+0x0524, 0x0524,
+0x0526, 0x0526,
+0x0528, 0x0528,
+0x052a, 0x052a,
+0x052c, 0x052c,
+0x052e, 0x052e,
+0x0531, 0x0556,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x13a0, 0x13f5,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1e00, 0x1e00,
+0x1e02, 0x1e02,
+0x1e04, 0x1e04,
+0x1e06, 0x1e06,
+0x1e08, 0x1e08,
+0x1e0a, 0x1e0a,
+0x1e0c, 0x1e0c,
+0x1e0e, 0x1e0e,
+0x1e10, 0x1e10,
+0x1e12, 0x1e12,
+0x1e14, 0x1e14,
+0x1e16, 0x1e16,
+0x1e18, 0x1e18,
+0x1e1a, 0x1e1a,
+0x1e1c, 0x1e1c,
+0x1e1e, 0x1e1e,
+0x1e20, 0x1e20,
+0x1e22, 0x1e22,
+0x1e24, 0x1e24,
+0x1e26, 0x1e26,
+0x1e28, 0x1e28,
+0x1e2a, 0x1e2a,
+0x1e2c, 0x1e2c,
+0x1e2e, 0x1e2e,
+0x1e30, 0x1e30,
+0x1e32, 0x1e32,
+0x1e34, 0x1e34,
+0x1e36, 0x1e36,
+0x1e38, 0x1e38,
+0x1e3a, 0x1e3a,
+0x1e3c, 0x1e3c,
+0x1e3e, 0x1e3e,
+0x1e40, 0x1e40,
+0x1e42, 0x1e42,
+0x1e44, 0x1e44,
+0x1e46, 0x1e46,
+0x1e48, 0x1e48,
+0x1e4a, 0x1e4a,
+0x1e4c, 0x1e4c,
+0x1e4e, 0x1e4e,
+0x1e50, 0x1e50,
+0x1e52, 0x1e52,
+0x1e54, 0x1e54,
+0x1e56, 0x1e56,
+0x1e58, 0x1e58,
+0x1e5a, 0x1e5a,
+0x1e5c, 0x1e5c,
+0x1e5e, 0x1e5e,
+0x1e60, 0x1e60,
+0x1e62, 0x1e62,
+0x1e64, 0x1e64,
+0x1e66, 0x1e66,
+0x1e68, 0x1e68,
+0x1e6a, 0x1e6a,
+0x1e6c, 0x1e6c,
+0x1e6e, 0x1e6e,
+0x1e70, 0x1e70,
+0x1e72, 0x1e72,
+0x1e74, 0x1e74,
+0x1e76, 0x1e76,
+0x1e78, 0x1e78,
+0x1e7a, 0x1e7a,
+0x1e7c, 0x1e7c,
+0x1e7e, 0x1e7e,
+0x1e80, 0x1e80,
+0x1e82, 0x1e82,
+0x1e84, 0x1e84,
+0x1e86, 0x1e86,
+0x1e88, 0x1e88,
+0x1e8a, 0x1e8a,
+0x1e8c, 0x1e8c,
+0x1e8e, 0x1e8e,
+0x1e90, 0x1e90,
+0x1e92, 0x1e92,
+0x1e94, 0x1e94,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1ea0,
+0x1ea2, 0x1ea2,
+0x1ea4, 0x1ea4,
+0x1ea6, 0x1ea6,
+0x1ea8, 0x1ea8,
+0x1eaa, 0x1eaa,
+0x1eac, 0x1eac,
+0x1eae, 0x1eae,
+0x1eb0, 0x1eb0,
+0x1eb2, 0x1eb2,
+0x1eb4, 0x1eb4,
+0x1eb6, 0x1eb6,
+0x1eb8, 0x1eb8,
+0x1eba, 0x1eba,
+0x1ebc, 0x1ebc,
+0x1ebe, 0x1ebe,
+0x1ec0, 0x1ec0,
+0x1ec2, 0x1ec2,
+0x1ec4, 0x1ec4,
+0x1ec6, 0x1ec6,
+0x1ec8, 0x1ec8,
+0x1eca, 0x1eca,
+0x1ecc, 0x1ecc,
+0x1ece, 0x1ece,
+0x1ed0, 0x1ed0,
+0x1ed2, 0x1ed2,
+0x1ed4, 0x1ed4,
+0x1ed6, 0x1ed6,
+0x1ed8, 0x1ed8,
+0x1eda, 0x1eda,
+0x1edc, 0x1edc,
+0x1ede, 0x1ede,
+0x1ee0, 0x1ee0,
+0x1ee2, 0x1ee2,
+0x1ee4, 0x1ee4,
+0x1ee6, 0x1ee6,
+0x1ee8, 0x1ee8,
+0x1eea, 0x1eea,
+0x1eec, 0x1eec,
+0x1eee, 0x1eee,
+0x1ef0, 0x1ef0,
+0x1ef2, 0x1ef2,
+0x1ef4, 0x1ef4,
+0x1ef6, 0x1ef6,
+0x1ef8, 0x1ef8,
+0x1efa, 0x1efa,
+0x1efc, 0x1efc,
+0x1efe, 0x1efe,
+0x1f08, 0x1f0f,
+0x1f18, 0x1f1d,
+0x1f28, 0x1f2f,
+0x1f38, 0x1f3f,
+0x1f48, 0x1f4d,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f5f,
+0x1f68, 0x1f6f,
+0x1f88, 0x1f8f,
+0x1f98, 0x1f9f,
+0x1fa8, 0x1faf,
+0x1fb8, 0x1fbc,
+0x1fc8, 0x1fcc,
+0x1fd8, 0x1fdb,
+0x1fe8, 0x1fec,
+0x1ff8, 0x1ffc,
+0x2126, 0x2126,
+0x212a, 0x212b,
+0x2132, 0x2132,
+0x2160, 0x216f,
+0x2183, 0x2183,
+0x24b6, 0x24cf,
+0x2c00, 0x2c2e,
+0x2c60, 0x2c60,
+0x2c62, 0x2c64,
+0x2c67, 0x2c67,
+0x2c69, 0x2c69,
+0x2c6b, 0x2c6b,
+0x2c6d, 0x2c70,
+0x2c72, 0x2c72,
+0x2c75, 0x2c75,
+0x2c7e, 0x2c80,
+0x2c82, 0x2c82,
+0x2c84, 0x2c84,
+0x2c86, 0x2c86,
+0x2c88, 0x2c88,
+0x2c8a, 0x2c8a,
+0x2c8c, 0x2c8c,
+0x2c8e, 0x2c8e,
+0x2c90, 0x2c90,
+0x2c92, 0x2c92,
+0x2c94, 0x2c94,
+0x2c96, 0x2c96,
+0x2c98, 0x2c98,
+0x2c9a, 0x2c9a,
+0x2c9c, 0x2c9c,
+0x2c9e, 0x2c9e,
+0x2ca0, 0x2ca0,
+0x2ca2, 0x2ca2,
+0x2ca4, 0x2ca4,
+0x2ca6, 0x2ca6,
+0x2ca8, 0x2ca8,
+0x2caa, 0x2caa,
+0x2cac, 0x2cac,
+0x2cae, 0x2cae,
+0x2cb0, 0x2cb0,
+0x2cb2, 0x2cb2,
+0x2cb4, 0x2cb4,
+0x2cb6, 0x2cb6,
+0x2cb8, 0x2cb8,
+0x2cba, 0x2cba,
+0x2cbc, 0x2cbc,
+0x2cbe, 0x2cbe,
+0x2cc0, 0x2cc0,
+0x2cc2, 0x2cc2,
+0x2cc4, 0x2cc4,
+0x2cc6, 0x2cc6,
+0x2cc8, 0x2cc8,
+0x2cca, 0x2cca,
+0x2ccc, 0x2ccc,
+0x2cce, 0x2cce,
+0x2cd0, 0x2cd0,
+0x2cd2, 0x2cd2,
+0x2cd4, 0x2cd4,
+0x2cd6, 0x2cd6,
+0x2cd8, 0x2cd8,
+0x2cda, 0x2cda,
+0x2cdc, 0x2cdc,
+0x2cde, 0x2cde,
+0x2ce0, 0x2ce0,
+0x2ce2, 0x2ce2,
+0x2ceb, 0x2ceb,
+0x2ced, 0x2ced,
+0x2cf2, 0x2cf2,
+0xa640, 0xa640,
+0xa642, 0xa642,
+0xa644, 0xa644,
+0xa646, 0xa646,
+0xa648, 0xa648,
+0xa64a, 0xa64a,
+0xa64c, 0xa64c,
+0xa64e, 0xa64e,
+0xa650, 0xa650,
+0xa652, 0xa652,
+0xa654, 0xa654,
+0xa656, 0xa656,
+0xa658, 0xa658,
+0xa65a, 0xa65a,
+0xa65c, 0xa65c,
+0xa65e, 0xa65e,
+0xa660, 0xa660,
+0xa662, 0xa662,
+0xa664, 0xa664,
+0xa666, 0xa666,
+0xa668, 0xa668,
+0xa66a, 0xa66a,
+0xa66c, 0xa66c,
+0xa680, 0xa680,
+0xa682, 0xa682,
+0xa684, 0xa684,
+0xa686, 0xa686,
+0xa688, 0xa688,
+0xa68a, 0xa68a,
+0xa68c, 0xa68c,
+0xa68e, 0xa68e,
+0xa690, 0xa690,
+0xa692, 0xa692,
+0xa694, 0xa694,
+0xa696, 0xa696,
+0xa698, 0xa698,
+0xa69a, 0xa69a,
+0xa722, 0xa722,
+0xa724, 0xa724,
+0xa726, 0xa726,
+0xa728, 0xa728,
+0xa72a, 0xa72a,
+0xa72c, 0xa72c,
+0xa72e, 0xa72e,
+0xa732, 0xa732,
+0xa734, 0xa734,
+0xa736, 0xa736,
+0xa738, 0xa738,
+0xa73a, 0xa73a,
+0xa73c, 0xa73c,
+0xa73e, 0xa73e,
+0xa740, 0xa740,
+0xa742, 0xa742,
+0xa744, 0xa744,
+0xa746, 0xa746,
+0xa748, 0xa748,
+0xa74a, 0xa74a,
+0xa74c, 0xa74c,
+0xa74e, 0xa74e,
+0xa750, 0xa750,
+0xa752, 0xa752,
+0xa754, 0xa754,
+0xa756, 0xa756,
+0xa758, 0xa758,
+0xa75a, 0xa75a,
+0xa75c, 0xa75c,
+0xa75e, 0xa75e,
+0xa760, 0xa760,
+0xa762, 0xa762,
+0xa764, 0xa764,
+0xa766, 0xa766,
+0xa768, 0xa768,
+0xa76a, 0xa76a,
+0xa76c, 0xa76c,
+0xa76e, 0xa76e,
+0xa779, 0xa779,
+0xa77b, 0xa77b,
+0xa77d, 0xa77e,
+0xa780, 0xa780,
+0xa782, 0xa782,
+0xa784, 0xa784,
+0xa786, 0xa786,
+0xa78b, 0xa78b,
+0xa78d, 0xa78d,
+0xa790, 0xa790,
+0xa792, 0xa792,
+0xa796, 0xa796,
+0xa798, 0xa798,
+0xa79a, 0xa79a,
+0xa79c, 0xa79c,
+0xa79e, 0xa79e,
+0xa7a0, 0xa7a0,
+0xa7a2, 0xa7a2,
+0xa7a4, 0xa7a4,
+0xa7a6, 0xa7a6,
+0xa7a8, 0xa7a8,
+0xa7aa, 0xa7ae,
+0xa7b0, 0xa7b4,
+0xa7b6, 0xa7b6,
+0xa7b8, 0xa7b8,
+0xa7ba, 0xa7ba,
+0xa7bc, 0xa7bc,
+0xa7be, 0xa7be,
+0xa7c2, 0xa7c2,
+0xa7c4, 0xa7c6,
+0xff21, 0xff3a,
+0x10400, 0x10427,
+0x104b0, 0x104d3,
+0x10c80, 0x10cb2,
+0x118a0, 0x118bf,
+0x16e40, 0x16e5f,
+0x1e900, 0x1e921,
+}; /* END of CR_Changes_When_Lowercased */
+
+/* PROPERTY: 'Changes_When_Titlecased': Derived Property */
+static const OnigCodePoint
+CR_Changes_When_Titlecased[] = { 615,
+0x0061, 0x007a,
+0x00b5, 0x00b5,
+0x00df, 0x00f6,
+0x00f8, 0x00ff,
+0x0101, 0x0101,
+0x0103, 0x0103,
+0x0105, 0x0105,
+0x0107, 0x0107,
+0x0109, 0x0109,
+0x010b, 0x010b,
+0x010d, 0x010d,
+0x010f, 0x010f,
+0x0111, 0x0111,
+0x0113, 0x0113,
+0x0115, 0x0115,
+0x0117, 0x0117,
+0x0119, 0x0119,
+0x011b, 0x011b,
+0x011d, 0x011d,
+0x011f, 0x011f,
+0x0121, 0x0121,
+0x0123, 0x0123,
+0x0125, 0x0125,
+0x0127, 0x0127,
+0x0129, 0x0129,
+0x012b, 0x012b,
+0x012d, 0x012d,
+0x012f, 0x012f,
+0x0131, 0x0131,
+0x0133, 0x0133,
+0x0135, 0x0135,
+0x0137, 0x0137,
+0x013a, 0x013a,
+0x013c, 0x013c,
+0x013e, 0x013e,
+0x0140, 0x0140,
+0x0142, 0x0142,
+0x0144, 0x0144,
+0x0146, 0x0146,
+0x0148, 0x0149,
+0x014b, 0x014b,
+0x014d, 0x014d,
+0x014f, 0x014f,
+0x0151, 0x0151,
+0x0153, 0x0153,
+0x0155, 0x0155,
+0x0157, 0x0157,
+0x0159, 0x0159,
+0x015b, 0x015b,
+0x015d, 0x015d,
+0x015f, 0x015f,
+0x0161, 0x0161,
+0x0163, 0x0163,
+0x0165, 0x0165,
+0x0167, 0x0167,
+0x0169, 0x0169,
+0x016b, 0x016b,
+0x016d, 0x016d,
+0x016f, 0x016f,
+0x0171, 0x0171,
+0x0173, 0x0173,
+0x0175, 0x0175,
+0x0177, 0x0177,
+0x017a, 0x017a,
+0x017c, 0x017c,
+0x017e, 0x0180,
+0x0183, 0x0183,
+0x0185, 0x0185,
+0x0188, 0x0188,
+0x018c, 0x018c,
+0x0192, 0x0192,
+0x0195, 0x0195,
+0x0199, 0x019a,
+0x019e, 0x019e,
+0x01a1, 0x01a1,
+0x01a3, 0x01a3,
+0x01a5, 0x01a5,
+0x01a8, 0x01a8,
+0x01ad, 0x01ad,
+0x01b0, 0x01b0,
+0x01b4, 0x01b4,
+0x01b6, 0x01b6,
+0x01b9, 0x01b9,
+0x01bd, 0x01bd,
+0x01bf, 0x01bf,
+0x01c4, 0x01c4,
+0x01c6, 0x01c7,
+0x01c9, 0x01ca,
+0x01cc, 0x01cc,
+0x01ce, 0x01ce,
+0x01d0, 0x01d0,
+0x01d2, 0x01d2,
+0x01d4, 0x01d4,
+0x01d6, 0x01d6,
+0x01d8, 0x01d8,
+0x01da, 0x01da,
+0x01dc, 0x01dd,
+0x01df, 0x01df,
+0x01e1, 0x01e1,
+0x01e3, 0x01e3,
+0x01e5, 0x01e5,
+0x01e7, 0x01e7,
+0x01e9, 0x01e9,
+0x01eb, 0x01eb,
+0x01ed, 0x01ed,
+0x01ef, 0x01f1,
+0x01f3, 0x01f3,
+0x01f5, 0x01f5,
+0x01f9, 0x01f9,
+0x01fb, 0x01fb,
+0x01fd, 0x01fd,
+0x01ff, 0x01ff,
+0x0201, 0x0201,
+0x0203, 0x0203,
+0x0205, 0x0205,
+0x0207, 0x0207,
+0x0209, 0x0209,
+0x020b, 0x020b,
+0x020d, 0x020d,
+0x020f, 0x020f,
+0x0211, 0x0211,
+0x0213, 0x0213,
+0x0215, 0x0215,
+0x0217, 0x0217,
+0x0219, 0x0219,
+0x021b, 0x021b,
+0x021d, 0x021d,
+0x021f, 0x021f,
+0x0223, 0x0223,
+0x0225, 0x0225,
+0x0227, 0x0227,
+0x0229, 0x0229,
+0x022b, 0x022b,
+0x022d, 0x022d,
+0x022f, 0x022f,
+0x0231, 0x0231,
+0x0233, 0x0233,
+0x023c, 0x023c,
+0x023f, 0x0240,
+0x0242, 0x0242,
+0x0247, 0x0247,
+0x0249, 0x0249,
+0x024b, 0x024b,
+0x024d, 0x024d,
+0x024f, 0x0254,
+0x0256, 0x0257,
+0x0259, 0x0259,
+0x025b, 0x025c,
+0x0260, 0x0261,
+0x0263, 0x0263,
+0x0265, 0x0266,
+0x0268, 0x026c,
+0x026f, 0x026f,
+0x0271, 0x0272,
+0x0275, 0x0275,
+0x027d, 0x027d,
+0x0280, 0x0280,
+0x0282, 0x0283,
+0x0287, 0x028c,
+0x0292, 0x0292,
+0x029d, 0x029e,
+0x0345, 0x0345,
+0x0371, 0x0371,
+0x0373, 0x0373,
+0x0377, 0x0377,
+0x037b, 0x037d,
+0x0390, 0x0390,
+0x03ac, 0x03ce,
+0x03d0, 0x03d1,
+0x03d5, 0x03d7,
+0x03d9, 0x03d9,
+0x03db, 0x03db,
+0x03dd, 0x03dd,
+0x03df, 0x03df,
+0x03e1, 0x03e1,
+0x03e3, 0x03e3,
+0x03e5, 0x03e5,
+0x03e7, 0x03e7,
+0x03e9, 0x03e9,
+0x03eb, 0x03eb,
+0x03ed, 0x03ed,
+0x03ef, 0x03f3,
+0x03f5, 0x03f5,
+0x03f8, 0x03f8,
+0x03fb, 0x03fb,
+0x0430, 0x045f,
+0x0461, 0x0461,
+0x0463, 0x0463,
+0x0465, 0x0465,
+0x0467, 0x0467,
+0x0469, 0x0469,
+0x046b, 0x046b,
+0x046d, 0x046d,
+0x046f, 0x046f,
+0x0471, 0x0471,
+0x0473, 0x0473,
+0x0475, 0x0475,
+0x0477, 0x0477,
+0x0479, 0x0479,
+0x047b, 0x047b,
+0x047d, 0x047d,
+0x047f, 0x047f,
+0x0481, 0x0481,
+0x048b, 0x048b,
+0x048d, 0x048d,
+0x048f, 0x048f,
+0x0491, 0x0491,
+0x0493, 0x0493,
+0x0495, 0x0495,
+0x0497, 0x0497,
+0x0499, 0x0499,
+0x049b, 0x049b,
+0x049d, 0x049d,
+0x049f, 0x049f,
+0x04a1, 0x04a1,
+0x04a3, 0x04a3,
+0x04a5, 0x04a5,
+0x04a7, 0x04a7,
+0x04a9, 0x04a9,
+0x04ab, 0x04ab,
+0x04ad, 0x04ad,
+0x04af, 0x04af,
+0x04b1, 0x04b1,
+0x04b3, 0x04b3,
+0x04b5, 0x04b5,
+0x04b7, 0x04b7,
+0x04b9, 0x04b9,
+0x04bb, 0x04bb,
+0x04bd, 0x04bd,
+0x04bf, 0x04bf,
+0x04c2, 0x04c2,
+0x04c4, 0x04c4,
+0x04c6, 0x04c6,
+0x04c8, 0x04c8,
+0x04ca, 0x04ca,
+0x04cc, 0x04cc,
+0x04ce, 0x04cf,
+0x04d1, 0x04d1,
+0x04d3, 0x04d3,
+0x04d5, 0x04d5,
+0x04d7, 0x04d7,
+0x04d9, 0x04d9,
+0x04db, 0x04db,
+0x04dd, 0x04dd,
+0x04df, 0x04df,
+0x04e1, 0x04e1,
+0x04e3, 0x04e3,
+0x04e5, 0x04e5,
+0x04e7, 0x04e7,
+0x04e9, 0x04e9,
+0x04eb, 0x04eb,
+0x04ed, 0x04ed,
+0x04ef, 0x04ef,
+0x04f1, 0x04f1,
+0x04f3, 0x04f3,
+0x04f5, 0x04f5,
+0x04f7, 0x04f7,
+0x04f9, 0x04f9,
+0x04fb, 0x04fb,
+0x04fd, 0x04fd,
+0x04ff, 0x04ff,
+0x0501, 0x0501,
+0x0503, 0x0503,
+0x0505, 0x0505,
+0x0507, 0x0507,
+0x0509, 0x0509,
+0x050b, 0x050b,
+0x050d, 0x050d,
+0x050f, 0x050f,
+0x0511, 0x0511,
+0x0513, 0x0513,
+0x0515, 0x0515,
+0x0517, 0x0517,
+0x0519, 0x0519,
+0x051b, 0x051b,
+0x051d, 0x051d,
+0x051f, 0x051f,
+0x0521, 0x0521,
+0x0523, 0x0523,
+0x0525, 0x0525,
+0x0527, 0x0527,
+0x0529, 0x0529,
+0x052b, 0x052b,
+0x052d, 0x052d,
+0x052f, 0x052f,
+0x0561, 0x0587,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1d79, 0x1d79,
+0x1d7d, 0x1d7d,
+0x1d8e, 0x1d8e,
+0x1e01, 0x1e01,
+0x1e03, 0x1e03,
+0x1e05, 0x1e05,
+0x1e07, 0x1e07,
+0x1e09, 0x1e09,
+0x1e0b, 0x1e0b,
+0x1e0d, 0x1e0d,
+0x1e0f, 0x1e0f,
+0x1e11, 0x1e11,
+0x1e13, 0x1e13,
+0x1e15, 0x1e15,
+0x1e17, 0x1e17,
+0x1e19, 0x1e19,
+0x1e1b, 0x1e1b,
+0x1e1d, 0x1e1d,
+0x1e1f, 0x1e1f,
+0x1e21, 0x1e21,
+0x1e23, 0x1e23,
+0x1e25, 0x1e25,
+0x1e27, 0x1e27,
+0x1e29, 0x1e29,
+0x1e2b, 0x1e2b,
+0x1e2d, 0x1e2d,
+0x1e2f, 0x1e2f,
+0x1e31, 0x1e31,
+0x1e33, 0x1e33,
+0x1e35, 0x1e35,
+0x1e37, 0x1e37,
+0x1e39, 0x1e39,
+0x1e3b, 0x1e3b,
+0x1e3d, 0x1e3d,
+0x1e3f, 0x1e3f,
+0x1e41, 0x1e41,
+0x1e43, 0x1e43,
+0x1e45, 0x1e45,
+0x1e47, 0x1e47,
+0x1e49, 0x1e49,
+0x1e4b, 0x1e4b,
+0x1e4d, 0x1e4d,
+0x1e4f, 0x1e4f,
+0x1e51, 0x1e51,
+0x1e53, 0x1e53,
+0x1e55, 0x1e55,
+0x1e57, 0x1e57,
+0x1e59, 0x1e59,
+0x1e5b, 0x1e5b,
+0x1e5d, 0x1e5d,
+0x1e5f, 0x1e5f,
+0x1e61, 0x1e61,
+0x1e63, 0x1e63,
+0x1e65, 0x1e65,
+0x1e67, 0x1e67,
+0x1e69, 0x1e69,
+0x1e6b, 0x1e6b,
+0x1e6d, 0x1e6d,
+0x1e6f, 0x1e6f,
+0x1e71, 0x1e71,
+0x1e73, 0x1e73,
+0x1e75, 0x1e75,
+0x1e77, 0x1e77,
+0x1e79, 0x1e79,
+0x1e7b, 0x1e7b,
+0x1e7d, 0x1e7d,
+0x1e7f, 0x1e7f,
+0x1e81, 0x1e81,
+0x1e83, 0x1e83,
+0x1e85, 0x1e85,
+0x1e87, 0x1e87,
+0x1e89, 0x1e89,
+0x1e8b, 0x1e8b,
+0x1e8d, 0x1e8d,
+0x1e8f, 0x1e8f,
+0x1e91, 0x1e91,
+0x1e93, 0x1e93,
+0x1e95, 0x1e9b,
+0x1ea1, 0x1ea1,
+0x1ea3, 0x1ea3,
+0x1ea5, 0x1ea5,
+0x1ea7, 0x1ea7,
+0x1ea9, 0x1ea9,
+0x1eab, 0x1eab,
+0x1ead, 0x1ead,
+0x1eaf, 0x1eaf,
+0x1eb1, 0x1eb1,
+0x1eb3, 0x1eb3,
+0x1eb5, 0x1eb5,
+0x1eb7, 0x1eb7,
+0x1eb9, 0x1eb9,
+0x1ebb, 0x1ebb,
+0x1ebd, 0x1ebd,
+0x1ebf, 0x1ebf,
+0x1ec1, 0x1ec1,
+0x1ec3, 0x1ec3,
+0x1ec5, 0x1ec5,
+0x1ec7, 0x1ec7,
+0x1ec9, 0x1ec9,
+0x1ecb, 0x1ecb,
+0x1ecd, 0x1ecd,
+0x1ecf, 0x1ecf,
+0x1ed1, 0x1ed1,
+0x1ed3, 0x1ed3,
+0x1ed5, 0x1ed5,
+0x1ed7, 0x1ed7,
+0x1ed9, 0x1ed9,
+0x1edb, 0x1edb,
+0x1edd, 0x1edd,
+0x1edf, 0x1edf,
+0x1ee1, 0x1ee1,
+0x1ee3, 0x1ee3,
+0x1ee5, 0x1ee5,
+0x1ee7, 0x1ee7,
+0x1ee9, 0x1ee9,
+0x1eeb, 0x1eeb,
+0x1eed, 0x1eed,
+0x1eef, 0x1eef,
+0x1ef1, 0x1ef1,
+0x1ef3, 0x1ef3,
+0x1ef5, 0x1ef5,
+0x1ef7, 0x1ef7,
+0x1ef9, 0x1ef9,
+0x1efb, 0x1efb,
+0x1efd, 0x1efd,
+0x1eff, 0x1f07,
+0x1f10, 0x1f15,
+0x1f20, 0x1f27,
+0x1f30, 0x1f37,
+0x1f40, 0x1f45,
+0x1f50, 0x1f57,
+0x1f60, 0x1f67,
+0x1f70, 0x1f7d,
+0x1f80, 0x1f87,
+0x1f90, 0x1f97,
+0x1fa0, 0x1fa7,
+0x1fb0, 0x1fb4,
+0x1fb6, 0x1fb7,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fc7,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fd7,
+0x1fe0, 0x1fe7,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ff7,
+0x214e, 0x214e,
+0x2170, 0x217f,
+0x2184, 0x2184,
+0x24d0, 0x24e9,
+0x2c30, 0x2c5e,
+0x2c61, 0x2c61,
+0x2c65, 0x2c66,
+0x2c68, 0x2c68,
+0x2c6a, 0x2c6a,
+0x2c6c, 0x2c6c,
+0x2c73, 0x2c73,
+0x2c76, 0x2c76,
+0x2c81, 0x2c81,
+0x2c83, 0x2c83,
+0x2c85, 0x2c85,
+0x2c87, 0x2c87,
+0x2c89, 0x2c89,
+0x2c8b, 0x2c8b,
+0x2c8d, 0x2c8d,
+0x2c8f, 0x2c8f,
+0x2c91, 0x2c91,
+0x2c93, 0x2c93,
+0x2c95, 0x2c95,
+0x2c97, 0x2c97,
+0x2c99, 0x2c99,
+0x2c9b, 0x2c9b,
+0x2c9d, 0x2c9d,
+0x2c9f, 0x2c9f,
+0x2ca1, 0x2ca1,
+0x2ca3, 0x2ca3,
+0x2ca5, 0x2ca5,
+0x2ca7, 0x2ca7,
+0x2ca9, 0x2ca9,
+0x2cab, 0x2cab,
+0x2cad, 0x2cad,
+0x2caf, 0x2caf,
+0x2cb1, 0x2cb1,
+0x2cb3, 0x2cb3,
+0x2cb5, 0x2cb5,
+0x2cb7, 0x2cb7,
+0x2cb9, 0x2cb9,
+0x2cbb, 0x2cbb,
+0x2cbd, 0x2cbd,
+0x2cbf, 0x2cbf,
+0x2cc1, 0x2cc1,
+0x2cc3, 0x2cc3,
+0x2cc5, 0x2cc5,
+0x2cc7, 0x2cc7,
+0x2cc9, 0x2cc9,
+0x2ccb, 0x2ccb,
+0x2ccd, 0x2ccd,
+0x2ccf, 0x2ccf,
+0x2cd1, 0x2cd1,
+0x2cd3, 0x2cd3,
+0x2cd5, 0x2cd5,
+0x2cd7, 0x2cd7,
+0x2cd9, 0x2cd9,
+0x2cdb, 0x2cdb,
+0x2cdd, 0x2cdd,
+0x2cdf, 0x2cdf,
+0x2ce1, 0x2ce1,
+0x2ce3, 0x2ce3,
+0x2cec, 0x2cec,
+0x2cee, 0x2cee,
+0x2cf3, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa641, 0xa641,
+0xa643, 0xa643,
+0xa645, 0xa645,
+0xa647, 0xa647,
+0xa649, 0xa649,
+0xa64b, 0xa64b,
+0xa64d, 0xa64d,
+0xa64f, 0xa64f,
+0xa651, 0xa651,
+0xa653, 0xa653,
+0xa655, 0xa655,
+0xa657, 0xa657,
+0xa659, 0xa659,
+0xa65b, 0xa65b,
+0xa65d, 0xa65d,
+0xa65f, 0xa65f,
+0xa661, 0xa661,
+0xa663, 0xa663,
+0xa665, 0xa665,
+0xa667, 0xa667,
+0xa669, 0xa669,
+0xa66b, 0xa66b,
+0xa66d, 0xa66d,
+0xa681, 0xa681,
+0xa683, 0xa683,
+0xa685, 0xa685,
+0xa687, 0xa687,
+0xa689, 0xa689,
+0xa68b, 0xa68b,
+0xa68d, 0xa68d,
+0xa68f, 0xa68f,
+0xa691, 0xa691,
+0xa693, 0xa693,
+0xa695, 0xa695,
+0xa697, 0xa697,
+0xa699, 0xa699,
+0xa69b, 0xa69b,
+0xa723, 0xa723,
+0xa725, 0xa725,
+0xa727, 0xa727,
+0xa729, 0xa729,
+0xa72b, 0xa72b,
+0xa72d, 0xa72d,
+0xa72f, 0xa72f,
+0xa733, 0xa733,
+0xa735, 0xa735,
+0xa737, 0xa737,
+0xa739, 0xa739,
+0xa73b, 0xa73b,
+0xa73d, 0xa73d,
+0xa73f, 0xa73f,
+0xa741, 0xa741,
+0xa743, 0xa743,
+0xa745, 0xa745,
+0xa747, 0xa747,
+0xa749, 0xa749,
+0xa74b, 0xa74b,
+0xa74d, 0xa74d,
+0xa74f, 0xa74f,
+0xa751, 0xa751,
+0xa753, 0xa753,
+0xa755, 0xa755,
+0xa757, 0xa757,
+0xa759, 0xa759,
+0xa75b, 0xa75b,
+0xa75d, 0xa75d,
+0xa75f, 0xa75f,
+0xa761, 0xa761,
+0xa763, 0xa763,
+0xa765, 0xa765,
+0xa767, 0xa767,
+0xa769, 0xa769,
+0xa76b, 0xa76b,
+0xa76d, 0xa76d,
+0xa76f, 0xa76f,
+0xa77a, 0xa77a,
+0xa77c, 0xa77c,
+0xa77f, 0xa77f,
+0xa781, 0xa781,
+0xa783, 0xa783,
+0xa785, 0xa785,
+0xa787, 0xa787,
+0xa78c, 0xa78c,
+0xa791, 0xa791,
+0xa793, 0xa794,
+0xa797, 0xa797,
+0xa799, 0xa799,
+0xa79b, 0xa79b,
+0xa79d, 0xa79d,
+0xa79f, 0xa79f,
+0xa7a1, 0xa7a1,
+0xa7a3, 0xa7a3,
+0xa7a5, 0xa7a5,
+0xa7a7, 0xa7a7,
+0xa7a9, 0xa7a9,
+0xa7b5, 0xa7b5,
+0xa7b7, 0xa7b7,
+0xa7b9, 0xa7b9,
+0xa7bb, 0xa7bb,
+0xa7bd, 0xa7bd,
+0xa7bf, 0xa7bf,
+0xa7c3, 0xa7c3,
+0xab53, 0xab53,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff41, 0xff5a,
+0x10428, 0x1044f,
+0x104d8, 0x104fb,
+0x10cc0, 0x10cf2,
+0x118c0, 0x118df,
+0x16e60, 0x16e7f,
+0x1e922, 0x1e943,
+}; /* END of CR_Changes_When_Titlecased */
+
+/* PROPERTY: 'Changes_When_Uppercased': Derived Property */
+static const OnigCodePoint
+CR_Changes_When_Uppercased[] = { 616,
+0x0061, 0x007a,
+0x00b5, 0x00b5,
+0x00df, 0x00f6,
+0x00f8, 0x00ff,
+0x0101, 0x0101,
+0x0103, 0x0103,
+0x0105, 0x0105,
+0x0107, 0x0107,
+0x0109, 0x0109,
+0x010b, 0x010b,
+0x010d, 0x010d,
+0x010f, 0x010f,
+0x0111, 0x0111,
+0x0113, 0x0113,
+0x0115, 0x0115,
+0x0117, 0x0117,
+0x0119, 0x0119,
+0x011b, 0x011b,
+0x011d, 0x011d,
+0x011f, 0x011f,
+0x0121, 0x0121,
+0x0123, 0x0123,
+0x0125, 0x0125,
+0x0127, 0x0127,
+0x0129, 0x0129,
+0x012b, 0x012b,
+0x012d, 0x012d,
+0x012f, 0x012f,
+0x0131, 0x0131,
+0x0133, 0x0133,
+0x0135, 0x0135,
+0x0137, 0x0137,
+0x013a, 0x013a,
+0x013c, 0x013c,
+0x013e, 0x013e,
+0x0140, 0x0140,
+0x0142, 0x0142,
+0x0144, 0x0144,
+0x0146, 0x0146,
+0x0148, 0x0149,
+0x014b, 0x014b,
+0x014d, 0x014d,
+0x014f, 0x014f,
+0x0151, 0x0151,
+0x0153, 0x0153,
+0x0155, 0x0155,
+0x0157, 0x0157,
+0x0159, 0x0159,
+0x015b, 0x015b,
+0x015d, 0x015d,
+0x015f, 0x015f,
+0x0161, 0x0161,
+0x0163, 0x0163,
+0x0165, 0x0165,
+0x0167, 0x0167,
+0x0169, 0x0169,
+0x016b, 0x016b,
+0x016d, 0x016d,
+0x016f, 0x016f,
+0x0171, 0x0171,
+0x0173, 0x0173,
+0x0175, 0x0175,
+0x0177, 0x0177,
+0x017a, 0x017a,
+0x017c, 0x017c,
+0x017e, 0x0180,
+0x0183, 0x0183,
+0x0185, 0x0185,
+0x0188, 0x0188,
+0x018c, 0x018c,
+0x0192, 0x0192,
+0x0195, 0x0195,
+0x0199, 0x019a,
+0x019e, 0x019e,
+0x01a1, 0x01a1,
+0x01a3, 0x01a3,
+0x01a5, 0x01a5,
+0x01a8, 0x01a8,
+0x01ad, 0x01ad,
+0x01b0, 0x01b0,
+0x01b4, 0x01b4,
+0x01b6, 0x01b6,
+0x01b9, 0x01b9,
+0x01bd, 0x01bd,
+0x01bf, 0x01bf,
+0x01c5, 0x01c6,
+0x01c8, 0x01c9,
+0x01cb, 0x01cc,
+0x01ce, 0x01ce,
+0x01d0, 0x01d0,
+0x01d2, 0x01d2,
+0x01d4, 0x01d4,
+0x01d6, 0x01d6,
+0x01d8, 0x01d8,
+0x01da, 0x01da,
+0x01dc, 0x01dd,
+0x01df, 0x01df,
+0x01e1, 0x01e1,
+0x01e3, 0x01e3,
+0x01e5, 0x01e5,
+0x01e7, 0x01e7,
+0x01e9, 0x01e9,
+0x01eb, 0x01eb,
+0x01ed, 0x01ed,
+0x01ef, 0x01f0,
+0x01f2, 0x01f3,
+0x01f5, 0x01f5,
+0x01f9, 0x01f9,
+0x01fb, 0x01fb,
+0x01fd, 0x01fd,
+0x01ff, 0x01ff,
+0x0201, 0x0201,
+0x0203, 0x0203,
+0x0205, 0x0205,
+0x0207, 0x0207,
+0x0209, 0x0209,
+0x020b, 0x020b,
+0x020d, 0x020d,
+0x020f, 0x020f,
+0x0211, 0x0211,
+0x0213, 0x0213,
+0x0215, 0x0215,
+0x0217, 0x0217,
+0x0219, 0x0219,
+0x021b, 0x021b,
+0x021d, 0x021d,
+0x021f, 0x021f,
+0x0223, 0x0223,
+0x0225, 0x0225,
+0x0227, 0x0227,
+0x0229, 0x0229,
+0x022b, 0x022b,
+0x022d, 0x022d,
+0x022f, 0x022f,
+0x0231, 0x0231,
+0x0233, 0x0233,
+0x023c, 0x023c,
+0x023f, 0x0240,
+0x0242, 0x0242,
+0x0247, 0x0247,
+0x0249, 0x0249,
+0x024b, 0x024b,
+0x024d, 0x024d,
+0x024f, 0x0254,
+0x0256, 0x0257,
+0x0259, 0x0259,
+0x025b, 0x025c,
+0x0260, 0x0261,
+0x0263, 0x0263,
+0x0265, 0x0266,
+0x0268, 0x026c,
+0x026f, 0x026f,
+0x0271, 0x0272,
+0x0275, 0x0275,
+0x027d, 0x027d,
+0x0280, 0x0280,
+0x0282, 0x0283,
+0x0287, 0x028c,
+0x0292, 0x0292,
+0x029d, 0x029e,
+0x0345, 0x0345,
+0x0371, 0x0371,
+0x0373, 0x0373,
+0x0377, 0x0377,
+0x037b, 0x037d,
+0x0390, 0x0390,
+0x03ac, 0x03ce,
+0x03d0, 0x03d1,
+0x03d5, 0x03d7,
+0x03d9, 0x03d9,
+0x03db, 0x03db,
+0x03dd, 0x03dd,
+0x03df, 0x03df,
+0x03e1, 0x03e1,
+0x03e3, 0x03e3,
+0x03e5, 0x03e5,
+0x03e7, 0x03e7,
+0x03e9, 0x03e9,
+0x03eb, 0x03eb,
+0x03ed, 0x03ed,
+0x03ef, 0x03f3,
+0x03f5, 0x03f5,
+0x03f8, 0x03f8,
+0x03fb, 0x03fb,
+0x0430, 0x045f,
+0x0461, 0x0461,
+0x0463, 0x0463,
+0x0465, 0x0465,
+0x0467, 0x0467,
+0x0469, 0x0469,
+0x046b, 0x046b,
+0x046d, 0x046d,
+0x046f, 0x046f,
+0x0471, 0x0471,
+0x0473, 0x0473,
+0x0475, 0x0475,
+0x0477, 0x0477,
+0x0479, 0x0479,
+0x047b, 0x047b,
+0x047d, 0x047d,
+0x047f, 0x047f,
+0x0481, 0x0481,
+0x048b, 0x048b,
+0x048d, 0x048d,
+0x048f, 0x048f,
+0x0491, 0x0491,
+0x0493, 0x0493,
+0x0495, 0x0495,
+0x0497, 0x0497,
+0x0499, 0x0499,
+0x049b, 0x049b,
+0x049d, 0x049d,
+0x049f, 0x049f,
+0x04a1, 0x04a1,
+0x04a3, 0x04a3,
+0x04a5, 0x04a5,
+0x04a7, 0x04a7,
+0x04a9, 0x04a9,
+0x04ab, 0x04ab,
+0x04ad, 0x04ad,
+0x04af, 0x04af,
+0x04b1, 0x04b1,
+0x04b3, 0x04b3,
+0x04b5, 0x04b5,
+0x04b7, 0x04b7,
+0x04b9, 0x04b9,
+0x04bb, 0x04bb,
+0x04bd, 0x04bd,
+0x04bf, 0x04bf,
+0x04c2, 0x04c2,
+0x04c4, 0x04c4,
+0x04c6, 0x04c6,
+0x04c8, 0x04c8,
+0x04ca, 0x04ca,
+0x04cc, 0x04cc,
+0x04ce, 0x04cf,
+0x04d1, 0x04d1,
+0x04d3, 0x04d3,
+0x04d5, 0x04d5,
+0x04d7, 0x04d7,
+0x04d9, 0x04d9,
+0x04db, 0x04db,
+0x04dd, 0x04dd,
+0x04df, 0x04df,
+0x04e1, 0x04e1,
+0x04e3, 0x04e3,
+0x04e5, 0x04e5,
+0x04e7, 0x04e7,
+0x04e9, 0x04e9,
+0x04eb, 0x04eb,
+0x04ed, 0x04ed,
+0x04ef, 0x04ef,
+0x04f1, 0x04f1,
+0x04f3, 0x04f3,
+0x04f5, 0x04f5,
+0x04f7, 0x04f7,
+0x04f9, 0x04f9,
+0x04fb, 0x04fb,
+0x04fd, 0x04fd,
+0x04ff, 0x04ff,
+0x0501, 0x0501,
+0x0503, 0x0503,
+0x0505, 0x0505,
+0x0507, 0x0507,
+0x0509, 0x0509,
+0x050b, 0x050b,
+0x050d, 0x050d,
+0x050f, 0x050f,
+0x0511, 0x0511,
+0x0513, 0x0513,
+0x0515, 0x0515,
+0x0517, 0x0517,
+0x0519, 0x0519,
+0x051b, 0x051b,
+0x051d, 0x051d,
+0x051f, 0x051f,
+0x0521, 0x0521,
+0x0523, 0x0523,
+0x0525, 0x0525,
+0x0527, 0x0527,
+0x0529, 0x0529,
+0x052b, 0x052b,
+0x052d, 0x052d,
+0x052f, 0x052f,
+0x0561, 0x0587,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1d79, 0x1d79,
+0x1d7d, 0x1d7d,
+0x1d8e, 0x1d8e,
+0x1e01, 0x1e01,
+0x1e03, 0x1e03,
+0x1e05, 0x1e05,
+0x1e07, 0x1e07,
+0x1e09, 0x1e09,
+0x1e0b, 0x1e0b,
+0x1e0d, 0x1e0d,
+0x1e0f, 0x1e0f,
+0x1e11, 0x1e11,
+0x1e13, 0x1e13,
+0x1e15, 0x1e15,
+0x1e17, 0x1e17,
+0x1e19, 0x1e19,
+0x1e1b, 0x1e1b,
+0x1e1d, 0x1e1d,
+0x1e1f, 0x1e1f,
+0x1e21, 0x1e21,
+0x1e23, 0x1e23,
+0x1e25, 0x1e25,
+0x1e27, 0x1e27,
+0x1e29, 0x1e29,
+0x1e2b, 0x1e2b,
+0x1e2d, 0x1e2d,
+0x1e2f, 0x1e2f,
+0x1e31, 0x1e31,
+0x1e33, 0x1e33,
+0x1e35, 0x1e35,
+0x1e37, 0x1e37,
+0x1e39, 0x1e39,
+0x1e3b, 0x1e3b,
+0x1e3d, 0x1e3d,
+0x1e3f, 0x1e3f,
+0x1e41, 0x1e41,
+0x1e43, 0x1e43,
+0x1e45, 0x1e45,
+0x1e47, 0x1e47,
+0x1e49, 0x1e49,
+0x1e4b, 0x1e4b,
+0x1e4d, 0x1e4d,
+0x1e4f, 0x1e4f,
+0x1e51, 0x1e51,
+0x1e53, 0x1e53,
+0x1e55, 0x1e55,
+0x1e57, 0x1e57,
+0x1e59, 0x1e59,
+0x1e5b, 0x1e5b,
+0x1e5d, 0x1e5d,
+0x1e5f, 0x1e5f,
+0x1e61, 0x1e61,
+0x1e63, 0x1e63,
+0x1e65, 0x1e65,
+0x1e67, 0x1e67,
+0x1e69, 0x1e69,
+0x1e6b, 0x1e6b,
+0x1e6d, 0x1e6d,
+0x1e6f, 0x1e6f,
+0x1e71, 0x1e71,
+0x1e73, 0x1e73,
+0x1e75, 0x1e75,
+0x1e77, 0x1e77,
+0x1e79, 0x1e79,
+0x1e7b, 0x1e7b,
+0x1e7d, 0x1e7d,
+0x1e7f, 0x1e7f,
+0x1e81, 0x1e81,
+0x1e83, 0x1e83,
+0x1e85, 0x1e85,
+0x1e87, 0x1e87,
+0x1e89, 0x1e89,
+0x1e8b, 0x1e8b,
+0x1e8d, 0x1e8d,
+0x1e8f, 0x1e8f,
+0x1e91, 0x1e91,
+0x1e93, 0x1e93,
+0x1e95, 0x1e9b,
+0x1ea1, 0x1ea1,
+0x1ea3, 0x1ea3,
+0x1ea5, 0x1ea5,
+0x1ea7, 0x1ea7,
+0x1ea9, 0x1ea9,
+0x1eab, 0x1eab,
+0x1ead, 0x1ead,
+0x1eaf, 0x1eaf,
+0x1eb1, 0x1eb1,
+0x1eb3, 0x1eb3,
+0x1eb5, 0x1eb5,
+0x1eb7, 0x1eb7,
+0x1eb9, 0x1eb9,
+0x1ebb, 0x1ebb,
+0x1ebd, 0x1ebd,
+0x1ebf, 0x1ebf,
+0x1ec1, 0x1ec1,
+0x1ec3, 0x1ec3,
+0x1ec5, 0x1ec5,
+0x1ec7, 0x1ec7,
+0x1ec9, 0x1ec9,
+0x1ecb, 0x1ecb,
+0x1ecd, 0x1ecd,
+0x1ecf, 0x1ecf,
+0x1ed1, 0x1ed1,
+0x1ed3, 0x1ed3,
+0x1ed5, 0x1ed5,
+0x1ed7, 0x1ed7,
+0x1ed9, 0x1ed9,
+0x1edb, 0x1edb,
+0x1edd, 0x1edd,
+0x1edf, 0x1edf,
+0x1ee1, 0x1ee1,
+0x1ee3, 0x1ee3,
+0x1ee5, 0x1ee5,
+0x1ee7, 0x1ee7,
+0x1ee9, 0x1ee9,
+0x1eeb, 0x1eeb,
+0x1eed, 0x1eed,
+0x1eef, 0x1eef,
+0x1ef1, 0x1ef1,
+0x1ef3, 0x1ef3,
+0x1ef5, 0x1ef5,
+0x1ef7, 0x1ef7,
+0x1ef9, 0x1ef9,
+0x1efb, 0x1efb,
+0x1efd, 0x1efd,
+0x1eff, 0x1f07,
+0x1f10, 0x1f15,
+0x1f20, 0x1f27,
+0x1f30, 0x1f37,
+0x1f40, 0x1f45,
+0x1f50, 0x1f57,
+0x1f60, 0x1f67,
+0x1f70, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fb7,
+0x1fbc, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fc7,
+0x1fcc, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fd7,
+0x1fe0, 0x1fe7,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ff7,
+0x1ffc, 0x1ffc,
+0x214e, 0x214e,
+0x2170, 0x217f,
+0x2184, 0x2184,
+0x24d0, 0x24e9,
+0x2c30, 0x2c5e,
+0x2c61, 0x2c61,
+0x2c65, 0x2c66,
+0x2c68, 0x2c68,
+0x2c6a, 0x2c6a,
+0x2c6c, 0x2c6c,
+0x2c73, 0x2c73,
+0x2c76, 0x2c76,
+0x2c81, 0x2c81,
+0x2c83, 0x2c83,
+0x2c85, 0x2c85,
+0x2c87, 0x2c87,
+0x2c89, 0x2c89,
+0x2c8b, 0x2c8b,
+0x2c8d, 0x2c8d,
+0x2c8f, 0x2c8f,
+0x2c91, 0x2c91,
+0x2c93, 0x2c93,
+0x2c95, 0x2c95,
+0x2c97, 0x2c97,
+0x2c99, 0x2c99,
+0x2c9b, 0x2c9b,
+0x2c9d, 0x2c9d,
+0x2c9f, 0x2c9f,
+0x2ca1, 0x2ca1,
+0x2ca3, 0x2ca3,
+0x2ca5, 0x2ca5,
+0x2ca7, 0x2ca7,
+0x2ca9, 0x2ca9,
+0x2cab, 0x2cab,
+0x2cad, 0x2cad,
+0x2caf, 0x2caf,
+0x2cb1, 0x2cb1,
+0x2cb3, 0x2cb3,
+0x2cb5, 0x2cb5,
+0x2cb7, 0x2cb7,
+0x2cb9, 0x2cb9,
+0x2cbb, 0x2cbb,
+0x2cbd, 0x2cbd,
+0x2cbf, 0x2cbf,
+0x2cc1, 0x2cc1,
+0x2cc3, 0x2cc3,
+0x2cc5, 0x2cc5,
+0x2cc7, 0x2cc7,
+0x2cc9, 0x2cc9,
+0x2ccb, 0x2ccb,
+0x2ccd, 0x2ccd,
+0x2ccf, 0x2ccf,
+0x2cd1, 0x2cd1,
+0x2cd3, 0x2cd3,
+0x2cd5, 0x2cd5,
+0x2cd7, 0x2cd7,
+0x2cd9, 0x2cd9,
+0x2cdb, 0x2cdb,
+0x2cdd, 0x2cdd,
+0x2cdf, 0x2cdf,
+0x2ce1, 0x2ce1,
+0x2ce3, 0x2ce3,
+0x2cec, 0x2cec,
+0x2cee, 0x2cee,
+0x2cf3, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa641, 0xa641,
+0xa643, 0xa643,
+0xa645, 0xa645,
+0xa647, 0xa647,
+0xa649, 0xa649,
+0xa64b, 0xa64b,
+0xa64d, 0xa64d,
+0xa64f, 0xa64f,
+0xa651, 0xa651,
+0xa653, 0xa653,
+0xa655, 0xa655,
+0xa657, 0xa657,
+0xa659, 0xa659,
+0xa65b, 0xa65b,
+0xa65d, 0xa65d,
+0xa65f, 0xa65f,
+0xa661, 0xa661,
+0xa663, 0xa663,
+0xa665, 0xa665,
+0xa667, 0xa667,
+0xa669, 0xa669,
+0xa66b, 0xa66b,
+0xa66d, 0xa66d,
+0xa681, 0xa681,
+0xa683, 0xa683,
+0xa685, 0xa685,
+0xa687, 0xa687,
+0xa689, 0xa689,
+0xa68b, 0xa68b,
+0xa68d, 0xa68d,
+0xa68f, 0xa68f,
+0xa691, 0xa691,
+0xa693, 0xa693,
+0xa695, 0xa695,
+0xa697, 0xa697,
+0xa699, 0xa699,
+0xa69b, 0xa69b,
+0xa723, 0xa723,
+0xa725, 0xa725,
+0xa727, 0xa727,
+0xa729, 0xa729,
+0xa72b, 0xa72b,
+0xa72d, 0xa72d,
+0xa72f, 0xa72f,
+0xa733, 0xa733,
+0xa735, 0xa735,
+0xa737, 0xa737,
+0xa739, 0xa739,
+0xa73b, 0xa73b,
+0xa73d, 0xa73d,
+0xa73f, 0xa73f,
+0xa741, 0xa741,
+0xa743, 0xa743,
+0xa745, 0xa745,
+0xa747, 0xa747,
+0xa749, 0xa749,
+0xa74b, 0xa74b,
+0xa74d, 0xa74d,
+0xa74f, 0xa74f,
+0xa751, 0xa751,
+0xa753, 0xa753,
+0xa755, 0xa755,
+0xa757, 0xa757,
+0xa759, 0xa759,
+0xa75b, 0xa75b,
+0xa75d, 0xa75d,
+0xa75f, 0xa75f,
+0xa761, 0xa761,
+0xa763, 0xa763,
+0xa765, 0xa765,
+0xa767, 0xa767,
+0xa769, 0xa769,
+0xa76b, 0xa76b,
+0xa76d, 0xa76d,
+0xa76f, 0xa76f,
+0xa77a, 0xa77a,
+0xa77c, 0xa77c,
+0xa77f, 0xa77f,
+0xa781, 0xa781,
+0xa783, 0xa783,
+0xa785, 0xa785,
+0xa787, 0xa787,
+0xa78c, 0xa78c,
+0xa791, 0xa791,
+0xa793, 0xa794,
+0xa797, 0xa797,
+0xa799, 0xa799,
+0xa79b, 0xa79b,
+0xa79d, 0xa79d,
+0xa79f, 0xa79f,
+0xa7a1, 0xa7a1,
+0xa7a3, 0xa7a3,
+0xa7a5, 0xa7a5,
+0xa7a7, 0xa7a7,
+0xa7a9, 0xa7a9,
+0xa7b5, 0xa7b5,
+0xa7b7, 0xa7b7,
+0xa7b9, 0xa7b9,
+0xa7bb, 0xa7bb,
+0xa7bd, 0xa7bd,
+0xa7bf, 0xa7bf,
+0xa7c3, 0xa7c3,
+0xab53, 0xab53,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff41, 0xff5a,
+0x10428, 0x1044f,
+0x104d8, 0x104fb,
+0x10cc0, 0x10cf2,
+0x118c0, 0x118df,
+0x16e60, 0x16e7f,
+0x1e922, 0x1e943,
+}; /* END of CR_Changes_When_Uppercased */
+
+/* PROPERTY: 'Cherokee': Script */
+static const OnigCodePoint
+CR_Cherokee[] = { 3,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0xab70, 0xabbf,
+}; /* END of CR_Cherokee */
+
+/* PROPERTY: 'Cn': General Category */
+static const OnigCodePoint
+CR_Cn[] = { 666,
+0x0378, 0x0379,
+0x0380, 0x0383,
+0x038b, 0x038b,
+0x038d, 0x038d,
+0x03a2, 0x03a2,
+0x0530, 0x0530,
+0x0557, 0x0558,
+0x058b, 0x058c,
+0x0590, 0x0590,
+0x05c8, 0x05cf,
+0x05eb, 0x05ee,
+0x05f5, 0x05ff,
+0x061d, 0x061d,
+0x070e, 0x070e,
+0x074b, 0x074c,
+0x07b2, 0x07bf,
+0x07fb, 0x07fc,
+0x082e, 0x082f,
+0x083f, 0x083f,
+0x085c, 0x085d,
+0x085f, 0x085f,
+0x086b, 0x089f,
+0x08b5, 0x08b5,
+0x08be, 0x08d2,
+0x0984, 0x0984,
+0x098d, 0x098e,
+0x0991, 0x0992,
+0x09a9, 0x09a9,
+0x09b1, 0x09b1,
+0x09b3, 0x09b5,
+0x09ba, 0x09bb,
+0x09c5, 0x09c6,
+0x09c9, 0x09ca,
+0x09cf, 0x09d6,
+0x09d8, 0x09db,
+0x09de, 0x09de,
+0x09e4, 0x09e5,
+0x09ff, 0x0a00,
+0x0a04, 0x0a04,
+0x0a0b, 0x0a0e,
+0x0a11, 0x0a12,
+0x0a29, 0x0a29,
+0x0a31, 0x0a31,
+0x0a34, 0x0a34,
+0x0a37, 0x0a37,
+0x0a3a, 0x0a3b,
+0x0a3d, 0x0a3d,
+0x0a43, 0x0a46,
+0x0a49, 0x0a4a,
+0x0a4e, 0x0a50,
+0x0a52, 0x0a58,
+0x0a5d, 0x0a5d,
+0x0a5f, 0x0a65,
+0x0a77, 0x0a80,
+0x0a84, 0x0a84,
+0x0a8e, 0x0a8e,
+0x0a92, 0x0a92,
+0x0aa9, 0x0aa9,
+0x0ab1, 0x0ab1,
+0x0ab4, 0x0ab4,
+0x0aba, 0x0abb,
+0x0ac6, 0x0ac6,
+0x0aca, 0x0aca,
+0x0ace, 0x0acf,
+0x0ad1, 0x0adf,
+0x0ae4, 0x0ae5,
+0x0af2, 0x0af8,
+0x0b00, 0x0b00,
+0x0b04, 0x0b04,
+0x0b0d, 0x0b0e,
+0x0b11, 0x0b12,
+0x0b29, 0x0b29,
+0x0b31, 0x0b31,
+0x0b34, 0x0b34,
+0x0b3a, 0x0b3b,
+0x0b45, 0x0b46,
+0x0b49, 0x0b4a,
+0x0b4e, 0x0b55,
+0x0b58, 0x0b5b,
+0x0b5e, 0x0b5e,
+0x0b64, 0x0b65,
+0x0b78, 0x0b81,
+0x0b84, 0x0b84,
+0x0b8b, 0x0b8d,
+0x0b91, 0x0b91,
+0x0b96, 0x0b98,
+0x0b9b, 0x0b9b,
+0x0b9d, 0x0b9d,
+0x0ba0, 0x0ba2,
+0x0ba5, 0x0ba7,
+0x0bab, 0x0bad,
+0x0bba, 0x0bbd,
+0x0bc3, 0x0bc5,
+0x0bc9, 0x0bc9,
+0x0bce, 0x0bcf,
+0x0bd1, 0x0bd6,
+0x0bd8, 0x0be5,
+0x0bfb, 0x0bff,
+0x0c0d, 0x0c0d,
+0x0c11, 0x0c11,
+0x0c29, 0x0c29,
+0x0c3a, 0x0c3c,
+0x0c45, 0x0c45,
+0x0c49, 0x0c49,
+0x0c4e, 0x0c54,
+0x0c57, 0x0c57,
+0x0c5b, 0x0c5f,
+0x0c64, 0x0c65,
+0x0c70, 0x0c76,
+0x0c8d, 0x0c8d,
+0x0c91, 0x0c91,
+0x0ca9, 0x0ca9,
+0x0cb4, 0x0cb4,
+0x0cba, 0x0cbb,
+0x0cc5, 0x0cc5,
+0x0cc9, 0x0cc9,
+0x0cce, 0x0cd4,
+0x0cd7, 0x0cdd,
+0x0cdf, 0x0cdf,
+0x0ce4, 0x0ce5,
+0x0cf0, 0x0cf0,
+0x0cf3, 0x0cff,
+0x0d04, 0x0d04,
+0x0d0d, 0x0d0d,
+0x0d11, 0x0d11,
+0x0d45, 0x0d45,
+0x0d49, 0x0d49,
+0x0d50, 0x0d53,
+0x0d64, 0x0d65,
+0x0d80, 0x0d81,
+0x0d84, 0x0d84,
+0x0d97, 0x0d99,
+0x0db2, 0x0db2,
+0x0dbc, 0x0dbc,
+0x0dbe, 0x0dbf,
+0x0dc7, 0x0dc9,
+0x0dcb, 0x0dce,
+0x0dd5, 0x0dd5,
+0x0dd7, 0x0dd7,
+0x0de0, 0x0de5,
+0x0df0, 0x0df1,
+0x0df5, 0x0e00,
+0x0e3b, 0x0e3e,
+0x0e5c, 0x0e80,
+0x0e83, 0x0e83,
+0x0e85, 0x0e85,
+0x0e8b, 0x0e8b,
+0x0ea4, 0x0ea4,
+0x0ea6, 0x0ea6,
+0x0ebe, 0x0ebf,
+0x0ec5, 0x0ec5,
+0x0ec7, 0x0ec7,
+0x0ece, 0x0ecf,
+0x0eda, 0x0edb,
+0x0ee0, 0x0eff,
+0x0f48, 0x0f48,
+0x0f6d, 0x0f70,
+0x0f98, 0x0f98,
+0x0fbd, 0x0fbd,
+0x0fcd, 0x0fcd,
+0x0fdb, 0x0fff,
+0x10c6, 0x10c6,
+0x10c8, 0x10cc,
+0x10ce, 0x10cf,
+0x1249, 0x1249,
+0x124e, 0x124f,
+0x1257, 0x1257,
+0x1259, 0x1259,
+0x125e, 0x125f,
+0x1289, 0x1289,
+0x128e, 0x128f,
+0x12b1, 0x12b1,
+0x12b6, 0x12b7,
+0x12bf, 0x12bf,
+0x12c1, 0x12c1,
+0x12c6, 0x12c7,
+0x12d7, 0x12d7,
+0x1311, 0x1311,
+0x1316, 0x1317,
+0x135b, 0x135c,
+0x137d, 0x137f,
+0x139a, 0x139f,
+0x13f6, 0x13f7,
+0x13fe, 0x13ff,
+0x169d, 0x169f,
+0x16f9, 0x16ff,
+0x170d, 0x170d,
+0x1715, 0x171f,
+0x1737, 0x173f,
+0x1754, 0x175f,
+0x176d, 0x176d,
+0x1771, 0x1771,
+0x1774, 0x177f,
+0x17de, 0x17df,
+0x17ea, 0x17ef,
+0x17fa, 0x17ff,
+0x180f, 0x180f,
+0x181a, 0x181f,
+0x1879, 0x187f,
+0x18ab, 0x18af,
+0x18f6, 0x18ff,
+0x191f, 0x191f,
+0x192c, 0x192f,
+0x193c, 0x193f,
+0x1941, 0x1943,
+0x196e, 0x196f,
+0x1975, 0x197f,
+0x19ac, 0x19af,
+0x19ca, 0x19cf,
+0x19db, 0x19dd,
+0x1a1c, 0x1a1d,
+0x1a5f, 0x1a5f,
+0x1a7d, 0x1a7e,
+0x1a8a, 0x1a8f,
+0x1a9a, 0x1a9f,
+0x1aae, 0x1aaf,
+0x1abf, 0x1aff,
+0x1b4c, 0x1b4f,
+0x1b7d, 0x1b7f,
+0x1bf4, 0x1bfb,
+0x1c38, 0x1c3a,
+0x1c4a, 0x1c4c,
+0x1c89, 0x1c8f,
+0x1cbb, 0x1cbc,
+0x1cc8, 0x1ccf,
+0x1cfb, 0x1cff,
+0x1dfa, 0x1dfa,
+0x1f16, 0x1f17,
+0x1f1e, 0x1f1f,
+0x1f46, 0x1f47,
+0x1f4e, 0x1f4f,
+0x1f58, 0x1f58,
+0x1f5a, 0x1f5a,
+0x1f5c, 0x1f5c,
+0x1f5e, 0x1f5e,
+0x1f7e, 0x1f7f,
+0x1fb5, 0x1fb5,
+0x1fc5, 0x1fc5,
+0x1fd4, 0x1fd5,
+0x1fdc, 0x1fdc,
+0x1ff0, 0x1ff1,
+0x1ff5, 0x1ff5,
+0x1fff, 0x1fff,
+0x2065, 0x2065,
+0x2072, 0x2073,
+0x208f, 0x208f,
+0x209d, 0x209f,
+0x20c0, 0x20cf,
+0x20f1, 0x20ff,
+0x218c, 0x218f,
+0x2427, 0x243f,
+0x244b, 0x245f,
+0x2b74, 0x2b75,
+0x2b96, 0x2b97,
+0x2c2f, 0x2c2f,
+0x2c5f, 0x2c5f,
+0x2cf4, 0x2cf8,
+0x2d26, 0x2d26,
+0x2d28, 0x2d2c,
+0x2d2e, 0x2d2f,
+0x2d68, 0x2d6e,
+0x2d71, 0x2d7e,
+0x2d97, 0x2d9f,
+0x2da7, 0x2da7,
+0x2daf, 0x2daf,
+0x2db7, 0x2db7,
+0x2dbf, 0x2dbf,
+0x2dc7, 0x2dc7,
+0x2dcf, 0x2dcf,
+0x2dd7, 0x2dd7,
+0x2ddf, 0x2ddf,
+0x2e50, 0x2e7f,
+0x2e9a, 0x2e9a,
+0x2ef4, 0x2eff,
+0x2fd6, 0x2fef,
+0x2ffc, 0x2fff,
+0x3040, 0x3040,
+0x3097, 0x3098,
+0x3100, 0x3104,
+0x3130, 0x3130,
+0x318f, 0x318f,
+0x31bb, 0x31bf,
+0x31e4, 0x31ef,
+0x321f, 0x321f,
+0x4db6, 0x4dbf,
+0x9ff0, 0x9fff,
+0xa48d, 0xa48f,
+0xa4c7, 0xa4cf,
+0xa62c, 0xa63f,
+0xa6f8, 0xa6ff,
+0xa7c0, 0xa7c1,
+0xa7c7, 0xa7f6,
+0xa82c, 0xa82f,
+0xa83a, 0xa83f,
+0xa878, 0xa87f,
+0xa8c6, 0xa8cd,
+0xa8da, 0xa8df,
+0xa954, 0xa95e,
+0xa97d, 0xa97f,
+0xa9ce, 0xa9ce,
+0xa9da, 0xa9dd,
+0xa9ff, 0xa9ff,
+0xaa37, 0xaa3f,
+0xaa4e, 0xaa4f,
+0xaa5a, 0xaa5b,
+0xaac3, 0xaada,
+0xaaf7, 0xab00,
+0xab07, 0xab08,
+0xab0f, 0xab10,
+0xab17, 0xab1f,
+0xab27, 0xab27,
+0xab2f, 0xab2f,
+0xab68, 0xab6f,
+0xabee, 0xabef,
+0xabfa, 0xabff,
+0xd7a4, 0xd7af,
+0xd7c7, 0xd7ca,
+0xd7fc, 0xd7ff,
+0xfa6e, 0xfa6f,
+0xfada, 0xfaff,
+0xfb07, 0xfb12,
+0xfb18, 0xfb1c,
+0xfb37, 0xfb37,
+0xfb3d, 0xfb3d,
+0xfb3f, 0xfb3f,
+0xfb42, 0xfb42,
+0xfb45, 0xfb45,
+0xfbc2, 0xfbd2,
+0xfd40, 0xfd4f,
+0xfd90, 0xfd91,
+0xfdc8, 0xfdef,
+0xfdfe, 0xfdff,
+0xfe1a, 0xfe1f,
+0xfe53, 0xfe53,
+0xfe67, 0xfe67,
+0xfe6c, 0xfe6f,
+0xfe75, 0xfe75,
+0xfefd, 0xfefe,
+0xff00, 0xff00,
+0xffbf, 0xffc1,
+0xffc8, 0xffc9,
+0xffd0, 0xffd1,
+0xffd8, 0xffd9,
+0xffdd, 0xffdf,
+0xffe7, 0xffe7,
+0xffef, 0xfff8,
+0xfffe, 0xffff,
+0x1000c, 0x1000c,
+0x10027, 0x10027,
+0x1003b, 0x1003b,
+0x1003e, 0x1003e,
+0x1004e, 0x1004f,
+0x1005e, 0x1007f,
+0x100fb, 0x100ff,
+0x10103, 0x10106,
+0x10134, 0x10136,
+0x1018f, 0x1018f,
+0x1019c, 0x1019f,
+0x101a1, 0x101cf,
+0x101fe, 0x1027f,
+0x1029d, 0x1029f,
+0x102d1, 0x102df,
+0x102fc, 0x102ff,
+0x10324, 0x1032c,
+0x1034b, 0x1034f,
+0x1037b, 0x1037f,
+0x1039e, 0x1039e,
+0x103c4, 0x103c7,
+0x103d6, 0x103ff,
+0x1049e, 0x1049f,
+0x104aa, 0x104af,
+0x104d4, 0x104d7,
+0x104fc, 0x104ff,
+0x10528, 0x1052f,
+0x10564, 0x1056e,
+0x10570, 0x105ff,
+0x10737, 0x1073f,
+0x10756, 0x1075f,
+0x10768, 0x107ff,
+0x10806, 0x10807,
+0x10809, 0x10809,
+0x10836, 0x10836,
+0x10839, 0x1083b,
+0x1083d, 0x1083e,
+0x10856, 0x10856,
+0x1089f, 0x108a6,
+0x108b0, 0x108df,
+0x108f3, 0x108f3,
+0x108f6, 0x108fa,
+0x1091c, 0x1091e,
+0x1093a, 0x1093e,
+0x10940, 0x1097f,
+0x109b8, 0x109bb,
+0x109d0, 0x109d1,
+0x10a04, 0x10a04,
+0x10a07, 0x10a0b,
+0x10a14, 0x10a14,
+0x10a18, 0x10a18,
+0x10a36, 0x10a37,
+0x10a3b, 0x10a3e,
+0x10a49, 0x10a4f,
+0x10a59, 0x10a5f,
+0x10aa0, 0x10abf,
+0x10ae7, 0x10aea,
+0x10af7, 0x10aff,
+0x10b36, 0x10b38,
+0x10b56, 0x10b57,
+0x10b73, 0x10b77,
+0x10b92, 0x10b98,
+0x10b9d, 0x10ba8,
+0x10bb0, 0x10bff,
+0x10c49, 0x10c7f,
+0x10cb3, 0x10cbf,
+0x10cf3, 0x10cf9,
+0x10d28, 0x10d2f,
+0x10d3a, 0x10e5f,
+0x10e7f, 0x10eff,
+0x10f28, 0x10f2f,
+0x10f5a, 0x10fdf,
+0x10ff7, 0x10fff,
+0x1104e, 0x11051,
+0x11070, 0x1107e,
+0x110c2, 0x110cc,
+0x110ce, 0x110cf,
+0x110e9, 0x110ef,
+0x110fa, 0x110ff,
+0x11135, 0x11135,
+0x11147, 0x1114f,
+0x11177, 0x1117f,
+0x111ce, 0x111cf,
+0x111e0, 0x111e0,
+0x111f5, 0x111ff,
+0x11212, 0x11212,
+0x1123f, 0x1127f,
+0x11287, 0x11287,
+0x11289, 0x11289,
+0x1128e, 0x1128e,
+0x1129e, 0x1129e,
+0x112aa, 0x112af,
+0x112eb, 0x112ef,
+0x112fa, 0x112ff,
+0x11304, 0x11304,
+0x1130d, 0x1130e,
+0x11311, 0x11312,
+0x11329, 0x11329,
+0x11331, 0x11331,
+0x11334, 0x11334,
+0x1133a, 0x1133a,
+0x11345, 0x11346,
+0x11349, 0x1134a,
+0x1134e, 0x1134f,
+0x11351, 0x11356,
+0x11358, 0x1135c,
+0x11364, 0x11365,
+0x1136d, 0x1136f,
+0x11375, 0x113ff,
+0x1145a, 0x1145a,
+0x1145c, 0x1145c,
+0x11460, 0x1147f,
+0x114c8, 0x114cf,
+0x114da, 0x1157f,
+0x115b6, 0x115b7,
+0x115de, 0x115ff,
+0x11645, 0x1164f,
+0x1165a, 0x1165f,
+0x1166d, 0x1167f,
+0x116b9, 0x116bf,
+0x116ca, 0x116ff,
+0x1171b, 0x1171c,
+0x1172c, 0x1172f,
+0x11740, 0x117ff,
+0x1183c, 0x1189f,
+0x118f3, 0x118fe,
+0x11900, 0x1199f,
+0x119a8, 0x119a9,
+0x119d8, 0x119d9,
+0x119e5, 0x119ff,
+0x11a48, 0x11a4f,
+0x11aa3, 0x11abf,
+0x11af9, 0x11bff,
+0x11c09, 0x11c09,
+0x11c37, 0x11c37,
+0x11c46, 0x11c4f,
+0x11c6d, 0x11c6f,
+0x11c90, 0x11c91,
+0x11ca8, 0x11ca8,
+0x11cb7, 0x11cff,
+0x11d07, 0x11d07,
+0x11d0a, 0x11d0a,
+0x11d37, 0x11d39,
+0x11d3b, 0x11d3b,
+0x11d3e, 0x11d3e,
+0x11d48, 0x11d4f,
+0x11d5a, 0x11d5f,
+0x11d66, 0x11d66,
+0x11d69, 0x11d69,
+0x11d8f, 0x11d8f,
+0x11d92, 0x11d92,
+0x11d99, 0x11d9f,
+0x11daa, 0x11edf,
+0x11ef9, 0x11fbf,
+0x11ff2, 0x11ffe,
+0x1239a, 0x123ff,
+0x1246f, 0x1246f,
+0x12475, 0x1247f,
+0x12544, 0x12fff,
+0x1342f, 0x1342f,
+0x13439, 0x143ff,
+0x14647, 0x167ff,
+0x16a39, 0x16a3f,
+0x16a5f, 0x16a5f,
+0x16a6a, 0x16a6d,
+0x16a70, 0x16acf,
+0x16aee, 0x16aef,
+0x16af6, 0x16aff,
+0x16b46, 0x16b4f,
+0x16b5a, 0x16b5a,
+0x16b62, 0x16b62,
+0x16b78, 0x16b7c,
+0x16b90, 0x16e3f,
+0x16e9b, 0x16eff,
+0x16f4b, 0x16f4e,
+0x16f88, 0x16f8e,
+0x16fa0, 0x16fdf,
+0x16fe4, 0x16fff,
+0x187f8, 0x187ff,
+0x18af3, 0x1afff,
+0x1b11f, 0x1b14f,
+0x1b153, 0x1b163,
+0x1b168, 0x1b16f,
+0x1b2fc, 0x1bbff,
+0x1bc6b, 0x1bc6f,
+0x1bc7d, 0x1bc7f,
+0x1bc89, 0x1bc8f,
+0x1bc9a, 0x1bc9b,
+0x1bca4, 0x1cfff,
+0x1d0f6, 0x1d0ff,
+0x1d127, 0x1d128,
+0x1d1e9, 0x1d1ff,
+0x1d246, 0x1d2df,
+0x1d2f4, 0x1d2ff,
+0x1d357, 0x1d35f,
+0x1d379, 0x1d3ff,
+0x1d455, 0x1d455,
+0x1d49d, 0x1d49d,
+0x1d4a0, 0x1d4a1,
+0x1d4a3, 0x1d4a4,
+0x1d4a7, 0x1d4a8,
+0x1d4ad, 0x1d4ad,
+0x1d4ba, 0x1d4ba,
+0x1d4bc, 0x1d4bc,
+0x1d4c4, 0x1d4c4,
+0x1d506, 0x1d506,
+0x1d50b, 0x1d50c,
+0x1d515, 0x1d515,
+0x1d51d, 0x1d51d,
+0x1d53a, 0x1d53a,
+0x1d53f, 0x1d53f,
+0x1d545, 0x1d545,
+0x1d547, 0x1d549,
+0x1d551, 0x1d551,
+0x1d6a6, 0x1d6a7,
+0x1d7cc, 0x1d7cd,
+0x1da8c, 0x1da9a,
+0x1daa0, 0x1daa0,
+0x1dab0, 0x1dfff,
+0x1e007, 0x1e007,
+0x1e019, 0x1e01a,
+0x1e022, 0x1e022,
+0x1e025, 0x1e025,
+0x1e02b, 0x1e0ff,
+0x1e12d, 0x1e12f,
+0x1e13e, 0x1e13f,
+0x1e14a, 0x1e14d,
+0x1e150, 0x1e2bf,
+0x1e2fa, 0x1e2fe,
+0x1e300, 0x1e7ff,
+0x1e8c5, 0x1e8c6,
+0x1e8d7, 0x1e8ff,
+0x1e94c, 0x1e94f,
+0x1e95a, 0x1e95d,
+0x1e960, 0x1ec70,
+0x1ecb5, 0x1ed00,
+0x1ed3e, 0x1edff,
+0x1ee04, 0x1ee04,
+0x1ee20, 0x1ee20,
+0x1ee23, 0x1ee23,
+0x1ee25, 0x1ee26,
+0x1ee28, 0x1ee28,
+0x1ee33, 0x1ee33,
+0x1ee38, 0x1ee38,
+0x1ee3a, 0x1ee3a,
+0x1ee3c, 0x1ee41,
+0x1ee43, 0x1ee46,
+0x1ee48, 0x1ee48,
+0x1ee4a, 0x1ee4a,
+0x1ee4c, 0x1ee4c,
+0x1ee50, 0x1ee50,
+0x1ee53, 0x1ee53,
+0x1ee55, 0x1ee56,
+0x1ee58, 0x1ee58,
+0x1ee5a, 0x1ee5a,
+0x1ee5c, 0x1ee5c,
+0x1ee5e, 0x1ee5e,
+0x1ee60, 0x1ee60,
+0x1ee63, 0x1ee63,
+0x1ee65, 0x1ee66,
+0x1ee6b, 0x1ee6b,
+0x1ee73, 0x1ee73,
+0x1ee78, 0x1ee78,
+0x1ee7d, 0x1ee7d,
+0x1ee7f, 0x1ee7f,
+0x1ee8a, 0x1ee8a,
+0x1ee9c, 0x1eea0,
+0x1eea4, 0x1eea4,
+0x1eeaa, 0x1eeaa,
+0x1eebc, 0x1eeef,
+0x1eef2, 0x1efff,
+0x1f02c, 0x1f02f,
+0x1f094, 0x1f09f,
+0x1f0af, 0x1f0b0,
+0x1f0c0, 0x1f0c0,
+0x1f0d0, 0x1f0d0,
+0x1f0f6, 0x1f0ff,
+0x1f10d, 0x1f10f,
+0x1f16d, 0x1f16f,
+0x1f1ad, 0x1f1e5,
+0x1f203, 0x1f20f,
+0x1f23c, 0x1f23f,
+0x1f249, 0x1f24f,
+0x1f252, 0x1f25f,
+0x1f266, 0x1f2ff,
+0x1f6d6, 0x1f6df,
+0x1f6ed, 0x1f6ef,
+0x1f6fb, 0x1f6ff,
+0x1f774, 0x1f77f,
+0x1f7d9, 0x1f7df,
+0x1f7ec, 0x1f7ff,
+0x1f80c, 0x1f80f,
+0x1f848, 0x1f84f,
+0x1f85a, 0x1f85f,
+0x1f888, 0x1f88f,
+0x1f8ae, 0x1f8ff,
+0x1f90c, 0x1f90c,
+0x1f972, 0x1f972,
+0x1f977, 0x1f979,
+0x1f9a3, 0x1f9a4,
+0x1f9ab, 0x1f9ad,
+0x1f9cb, 0x1f9cc,
+0x1fa54, 0x1fa5f,
+0x1fa6e, 0x1fa6f,
+0x1fa74, 0x1fa77,
+0x1fa7b, 0x1fa7f,
+0x1fa83, 0x1fa8f,
+0x1fa96, 0x1ffff,
+0x2a6d7, 0x2a6ff,
+0x2b735, 0x2b73f,
+0x2b81e, 0x2b81f,
+0x2cea2, 0x2ceaf,
+0x2ebe1, 0x2f7ff,
+0x2fa1e, 0xe0000,
+0xe0002, 0xe001f,
+0xe0080, 0xe00ff,
+0xe01f0, 0xeffff,
+0xffffe, 0xfffff,
+0x10fffe, 0x10ffff,
+}; /* END of CR_Cn */
+
+/* PROPERTY: 'Co': General Category */
+static const OnigCodePoint
+CR_Co[] = { 3,
+0xe000, 0xf8ff,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Co */
+
+/* PROPERTY: 'Common': Script */
+static const OnigCodePoint
+CR_Common[] = { 172,
+0x0000, 0x0040,
+0x005b, 0x0060,
+0x007b, 0x00a9,
+0x00ab, 0x00b9,
+0x00bb, 0x00bf,
+0x00d7, 0x00d7,
+0x00f7, 0x00f7,
+0x02b9, 0x02df,
+0x02e5, 0x02e9,
+0x02ec, 0x02ff,
+0x0374, 0x0374,
+0x037e, 0x037e,
+0x0385, 0x0385,
+0x0387, 0x0387,
+0x0589, 0x0589,
+0x0605, 0x0605,
+0x060c, 0x060c,
+0x061b, 0x061b,
+0x061f, 0x061f,
+0x0640, 0x0640,
+0x06dd, 0x06dd,
+0x08e2, 0x08e2,
+0x0964, 0x0965,
+0x0e3f, 0x0e3f,
+0x0fd5, 0x0fd8,
+0x10fb, 0x10fb,
+0x16eb, 0x16ed,
+0x1735, 0x1736,
+0x1802, 0x1803,
+0x1805, 0x1805,
+0x1cd3, 0x1cd3,
+0x1ce1, 0x1ce1,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf7,
+0x1cfa, 0x1cfa,
+0x2000, 0x200b,
+0x200e, 0x2064,
+0x2066, 0x2070,
+0x2074, 0x207e,
+0x2080, 0x208e,
+0x20a0, 0x20bf,
+0x2100, 0x2125,
+0x2127, 0x2129,
+0x212c, 0x2131,
+0x2133, 0x214d,
+0x214f, 0x215f,
+0x2189, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x27ff,
+0x2900, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2bff,
+0x2e00, 0x2e4f,
+0x2ff0, 0x2ffb,
+0x3000, 0x3004,
+0x3006, 0x3006,
+0x3008, 0x3020,
+0x3030, 0x3037,
+0x303c, 0x303f,
+0x309b, 0x309c,
+0x30a0, 0x30a0,
+0x30fb, 0x30fc,
+0x3190, 0x319f,
+0x31c0, 0x31e3,
+0x3220, 0x325f,
+0x327f, 0x32cf,
+0x32ff, 0x32ff,
+0x3358, 0x33ff,
+0x4dc0, 0x4dff,
+0xa700, 0xa721,
+0xa788, 0xa78a,
+0xa830, 0xa839,
+0xa92e, 0xa92e,
+0xa9cf, 0xa9cf,
+0xab5b, 0xab5b,
+0xfd3e, 0xfd3f,
+0xfe10, 0xfe19,
+0xfe30, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfeff, 0xfeff,
+0xff01, 0xff20,
+0xff3b, 0xff40,
+0xff5b, 0xff65,
+0xff70, 0xff70,
+0xff9e, 0xff9f,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1013f,
+0x10190, 0x1019b,
+0x101d0, 0x101fc,
+0x102e1, 0x102fb,
+0x16fe2, 0x16fe3,
+0x1bca0, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d166,
+0x1d16a, 0x1d17a,
+0x1d183, 0x1d184,
+0x1d18c, 0x1d1a9,
+0x1d1ae, 0x1d1e8,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f1ff,
+0x1f201, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+}; /* END of CR_Common */
+
+/* PROPERTY: 'Coptic': Script */
+static const OnigCodePoint
+CR_Coptic[] = { 3,
+0x03e2, 0x03ef,
+0x2c80, 0x2cf3,
+0x2cf9, 0x2cff,
+}; /* END of CR_Coptic */
+
+/* PROPERTY: 'Cs': General Category */
+static const OnigCodePoint
+CR_Cs[] = { 1,
+0xd800, 0xdfff,
+}; /* END of CR_Cs */
+
+/* PROPERTY: 'Cuneiform': Script */
+static const OnigCodePoint
+CR_Cuneiform[] = { 4,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+}; /* END of CR_Cuneiform */
+
+/* PROPERTY: 'Cypriot': Script */
+static const OnigCodePoint
+CR_Cypriot[] = { 6,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x1083f,
+}; /* END of CR_Cypriot */
+
+/* PROPERTY: 'Cyrillic': Script */
+static const OnigCodePoint
+CR_Cyrillic[] = { 8,
+0x0400, 0x0484,
+0x0487, 0x052f,
+0x1c80, 0x1c88,
+0x1d2b, 0x1d2b,
+0x1d78, 0x1d78,
+0x2de0, 0x2dff,
+0xa640, 0xa69f,
+0xfe2e, 0xfe2f,
+}; /* END of CR_Cyrillic */
+
+/* PROPERTY: 'Dash': Binary Property */
+static const OnigCodePoint
+CR_Dash[] = { 21,
+0x002d, 0x002d,
+0x058a, 0x058a,
+0x05be, 0x05be,
+0x1400, 0x1400,
+0x1806, 0x1806,
+0x2010, 0x2015,
+0x2053, 0x2053,
+0x207b, 0x207b,
+0x208b, 0x208b,
+0x2212, 0x2212,
+0x2e17, 0x2e17,
+0x2e1a, 0x2e1a,
+0x2e3a, 0x2e3b,
+0x2e40, 0x2e40,
+0x301c, 0x301c,
+0x3030, 0x3030,
+0x30a0, 0x30a0,
+0xfe31, 0xfe32,
+0xfe58, 0xfe58,
+0xfe63, 0xfe63,
+0xff0d, 0xff0d,
+}; /* END of CR_Dash */
+
+/* PROPERTY: 'Default_Ignorable_Code_Point': Derived Property */
+static const OnigCodePoint
+CR_Default_Ignorable_Code_Point[] = { 17,
+0x00ad, 0x00ad,
+0x034f, 0x034f,
+0x061c, 0x061c,
+0x115f, 0x1160,
+0x17b4, 0x17b5,
+0x180b, 0x180e,
+0x200b, 0x200f,
+0x202a, 0x202e,
+0x2060, 0x206f,
+0x3164, 0x3164,
+0xfe00, 0xfe0f,
+0xfeff, 0xfeff,
+0xffa0, 0xffa0,
+0xfff0, 0xfff8,
+0x1bca0, 0x1bca3,
+0x1d173, 0x1d17a,
+0xe0000, 0xe0fff,
+}; /* END of CR_Default_Ignorable_Code_Point */
+
+/* PROPERTY: 'Deprecated': Binary Property */
+static const OnigCodePoint
+CR_Deprecated[] = { 8,
+0x0149, 0x0149,
+0x0673, 0x0673,
+0x0f77, 0x0f77,
+0x0f79, 0x0f79,
+0x17a3, 0x17a4,
+0x206a, 0x206f,
+0x2329, 0x232a,
+0xe0001, 0xe0001,
+}; /* END of CR_Deprecated */
+
+/* PROPERTY: 'Deseret': Script */
+static const OnigCodePoint
+CR_Deseret[] = { 1,
+0x10400, 0x1044f,
+}; /* END of CR_Deseret */
+
+/* PROPERTY: 'Devanagari': Script */
+static const OnigCodePoint
+CR_Devanagari[] = { 4,
+0x0900, 0x0950,
+0x0955, 0x0963,
+0x0966, 0x097f,
+0xa8e0, 0xa8ff,
+}; /* END of CR_Devanagari */
+
+/* PROPERTY: 'Diacritic': Binary Property */
+static const OnigCodePoint
+CR_Diacritic[] = { 171,
+0x005e, 0x005e,
+0x0060, 0x0060,
+0x00a8, 0x00a8,
+0x00af, 0x00af,
+0x00b4, 0x00b4,
+0x00b7, 0x00b8,
+0x02b0, 0x034e,
+0x0350, 0x0357,
+0x035d, 0x0362,
+0x0374, 0x0375,
+0x037a, 0x037a,
+0x0384, 0x0385,
+0x0483, 0x0487,
+0x0559, 0x0559,
+0x0591, 0x05a1,
+0x05a3, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c4,
+0x064b, 0x0652,
+0x0657, 0x0658,
+0x06df, 0x06e0,
+0x06e5, 0x06e6,
+0x06ea, 0x06ec,
+0x0730, 0x074a,
+0x07a6, 0x07b0,
+0x07eb, 0x07f5,
+0x0818, 0x0819,
+0x08e3, 0x08fe,
+0x093c, 0x093c,
+0x094d, 0x094d,
+0x0951, 0x0954,
+0x0971, 0x0971,
+0x09bc, 0x09bc,
+0x09cd, 0x09cd,
+0x0a3c, 0x0a3c,
+0x0a4d, 0x0a4d,
+0x0abc, 0x0abc,
+0x0acd, 0x0acd,
+0x0afd, 0x0aff,
+0x0b3c, 0x0b3c,
+0x0b4d, 0x0b4d,
+0x0bcd, 0x0bcd,
+0x0c4d, 0x0c4d,
+0x0cbc, 0x0cbc,
+0x0ccd, 0x0ccd,
+0x0d3b, 0x0d3c,
+0x0d4d, 0x0d4d,
+0x0dca, 0x0dca,
+0x0e47, 0x0e4c,
+0x0e4e, 0x0e4e,
+0x0eba, 0x0eba,
+0x0ec8, 0x0ecc,
+0x0f18, 0x0f19,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f3f,
+0x0f82, 0x0f84,
+0x0f86, 0x0f87,
+0x0fc6, 0x0fc6,
+0x1037, 0x1037,
+0x1039, 0x103a,
+0x1063, 0x1064,
+0x1069, 0x106d,
+0x1087, 0x108d,
+0x108f, 0x108f,
+0x109a, 0x109b,
+0x135d, 0x135f,
+0x17c9, 0x17d3,
+0x17dd, 0x17dd,
+0x1939, 0x193b,
+0x1a75, 0x1a7c,
+0x1a7f, 0x1a7f,
+0x1ab0, 0x1abd,
+0x1b34, 0x1b34,
+0x1b44, 0x1b44,
+0x1b6b, 0x1b73,
+0x1baa, 0x1bab,
+0x1c36, 0x1c37,
+0x1c78, 0x1c7d,
+0x1cd0, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf7, 0x1cf9,
+0x1d2c, 0x1d6a,
+0x1dc4, 0x1dcf,
+0x1df5, 0x1df9,
+0x1dfd, 0x1dff,
+0x1fbd, 0x1fbd,
+0x1fbf, 0x1fc1,
+0x1fcd, 0x1fcf,
+0x1fdd, 0x1fdf,
+0x1fed, 0x1fef,
+0x1ffd, 0x1ffe,
+0x2cef, 0x2cf1,
+0x2e2f, 0x2e2f,
+0x302a, 0x302f,
+0x3099, 0x309c,
+0x30fc, 0x30fc,
+0xa66f, 0xa66f,
+0xa67c, 0xa67d,
+0xa67f, 0xa67f,
+0xa69c, 0xa69d,
+0xa6f0, 0xa6f1,
+0xa700, 0xa721,
+0xa788, 0xa78a,
+0xa7f8, 0xa7f9,
+0xa8c4, 0xa8c4,
+0xa8e0, 0xa8f1,
+0xa92b, 0xa92e,
+0xa953, 0xa953,
+0xa9b3, 0xa9b3,
+0xa9c0, 0xa9c0,
+0xa9e5, 0xa9e5,
+0xaa7b, 0xaa7d,
+0xaabf, 0xaac2,
+0xaaf6, 0xaaf6,
+0xab5b, 0xab5f,
+0xabec, 0xabed,
+0xfb1e, 0xfb1e,
+0xfe20, 0xfe2f,
+0xff3e, 0xff3e,
+0xff40, 0xff40,
+0xff70, 0xff70,
+0xff9e, 0xff9f,
+0xffe3, 0xffe3,
+0x102e0, 0x102e0,
+0x10ae5, 0x10ae6,
+0x10d22, 0x10d27,
+0x10f46, 0x10f50,
+0x110b9, 0x110ba,
+0x11133, 0x11134,
+0x11173, 0x11173,
+0x111c0, 0x111c0,
+0x111ca, 0x111cc,
+0x11235, 0x11236,
+0x112e9, 0x112ea,
+0x1133c, 0x1133c,
+0x1134d, 0x1134d,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11442, 0x11442,
+0x11446, 0x11446,
+0x114c2, 0x114c3,
+0x115bf, 0x115c0,
+0x1163f, 0x1163f,
+0x116b6, 0x116b7,
+0x1172b, 0x1172b,
+0x11839, 0x1183a,
+0x119e0, 0x119e0,
+0x11a34, 0x11a34,
+0x11a47, 0x11a47,
+0x11a99, 0x11a99,
+0x11c3f, 0x11c3f,
+0x11d42, 0x11d42,
+0x11d44, 0x11d45,
+0x11d97, 0x11d97,
+0x16af0, 0x16af4,
+0x16b30, 0x16b36,
+0x16f8f, 0x16f9f,
+0x1d167, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1e130, 0x1e136,
+0x1e2ec, 0x1e2ef,
+0x1e8d0, 0x1e8d6,
+0x1e944, 0x1e946,
+0x1e948, 0x1e94a,
+}; /* END of CR_Diacritic */
+
+/* PROPERTY: 'Dogra': Script */
+static const OnigCodePoint
+CR_Dogra[] = { 1,
+0x11800, 0x1183b,
+}; /* END of CR_Dogra */
+
+/* PROPERTY: 'Duployan': Script */
+static const OnigCodePoint
+CR_Duployan[] = { 5,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bc9f,
+}; /* END of CR_Duployan */
+
+/* PROPERTY: 'Egyptian_Hieroglyphs': Script */
+static const OnigCodePoint
+CR_Egyptian_Hieroglyphs[] = { 2,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+}; /* END of CR_Egyptian_Hieroglyphs */
+
+/* PROPERTY: 'Elbasan': Script */
+static const OnigCodePoint
+CR_Elbasan[] = { 1,
+0x10500, 0x10527,
+}; /* END of CR_Elbasan */
+
+/* PROPERTY: 'Elymaic': Script */
+static const OnigCodePoint
+CR_Elymaic[] = { 1,
+0x10fe0, 0x10ff6,
+}; /* END of CR_Elymaic */
+
+/* PROPERTY: 'Emoji': Emoji Property */
+static const OnigCodePoint
+CR_Emoji[] = { 151,
+0x0023, 0x0023,
+0x002a, 0x002a,
+0x0030, 0x0039,
+0x00a9, 0x00a9,
+0x00ae, 0x00ae,
+0x203c, 0x203c,
+0x2049, 0x2049,
+0x2122, 0x2122,
+0x2139, 0x2139,
+0x2194, 0x2199,
+0x21a9, 0x21aa,
+0x231a, 0x231b,
+0x2328, 0x2328,
+0x23cf, 0x23cf,
+0x23e9, 0x23f3,
+0x23f8, 0x23fa,
+0x24c2, 0x24c2,
+0x25aa, 0x25ab,
+0x25b6, 0x25b6,
+0x25c0, 0x25c0,
+0x25fb, 0x25fe,
+0x2600, 0x2604,
+0x260e, 0x260e,
+0x2611, 0x2611,
+0x2614, 0x2615,
+0x2618, 0x2618,
+0x261d, 0x261d,
+0x2620, 0x2620,
+0x2622, 0x2623,
+0x2626, 0x2626,
+0x262a, 0x262a,
+0x262e, 0x262f,
+0x2638, 0x263a,
+0x2640, 0x2640,
+0x2642, 0x2642,
+0x2648, 0x2653,
+0x265f, 0x2660,
+0x2663, 0x2663,
+0x2665, 0x2666,
+0x2668, 0x2668,
+0x267b, 0x267b,
+0x267e, 0x267f,
+0x2692, 0x2697,
+0x2699, 0x2699,
+0x269b, 0x269c,
+0x26a0, 0x26a1,
+0x26aa, 0x26ab,
+0x26b0, 0x26b1,
+0x26bd, 0x26be,
+0x26c4, 0x26c5,
+0x26c8, 0x26c8,
+0x26ce, 0x26cf,
+0x26d1, 0x26d1,
+0x26d3, 0x26d4,
+0x26e9, 0x26ea,
+0x26f0, 0x26f5,
+0x26f7, 0x26fa,
+0x26fd, 0x26fd,
+0x2702, 0x2702,
+0x2705, 0x2705,
+0x2708, 0x270d,
+0x270f, 0x270f,
+0x2712, 0x2712,
+0x2714, 0x2714,
+0x2716, 0x2716,
+0x271d, 0x271d,
+0x2721, 0x2721,
+0x2728, 0x2728,
+0x2733, 0x2734,
+0x2744, 0x2744,
+0x2747, 0x2747,
+0x274c, 0x274c,
+0x274e, 0x274e,
+0x2753, 0x2755,
+0x2757, 0x2757,
+0x2763, 0x2764,
+0x2795, 0x2797,
+0x27a1, 0x27a1,
+0x27b0, 0x27b0,
+0x27bf, 0x27bf,
+0x2934, 0x2935,
+0x2b05, 0x2b07,
+0x2b1b, 0x2b1c,
+0x2b50, 0x2b50,
+0x2b55, 0x2b55,
+0x3030, 0x3030,
+0x303d, 0x303d,
+0x3297, 0x3297,
+0x3299, 0x3299,
+0x1f004, 0x1f004,
+0x1f0cf, 0x1f0cf,
+0x1f170, 0x1f171,
+0x1f17e, 0x1f17f,
+0x1f18e, 0x1f18e,
+0x1f191, 0x1f19a,
+0x1f1e6, 0x1f1ff,
+0x1f201, 0x1f202,
+0x1f21a, 0x1f21a,
+0x1f22f, 0x1f22f,
+0x1f232, 0x1f23a,
+0x1f250, 0x1f251,
+0x1f300, 0x1f321,
+0x1f324, 0x1f393,
+0x1f396, 0x1f397,
+0x1f399, 0x1f39b,
+0x1f39e, 0x1f3f0,
+0x1f3f3, 0x1f3f5,
+0x1f3f7, 0x1f4fd,
+0x1f4ff, 0x1f53d,
+0x1f549, 0x1f54e,
+0x1f550, 0x1f567,
+0x1f56f, 0x1f570,
+0x1f573, 0x1f57a,
+0x1f587, 0x1f587,
+0x1f58a, 0x1f58d,
+0x1f590, 0x1f590,
+0x1f595, 0x1f596,
+0x1f5a4, 0x1f5a5,
+0x1f5a8, 0x1f5a8,
+0x1f5b1, 0x1f5b2,
+0x1f5bc, 0x1f5bc,
+0x1f5c2, 0x1f5c4,
+0x1f5d1, 0x1f5d3,
+0x1f5dc, 0x1f5de,
+0x1f5e1, 0x1f5e1,
+0x1f5e3, 0x1f5e3,
+0x1f5e8, 0x1f5e8,
+0x1f5ef, 0x1f5ef,
+0x1f5f3, 0x1f5f3,
+0x1f5fa, 0x1f64f,
+0x1f680, 0x1f6c5,
+0x1f6cb, 0x1f6d2,
+0x1f6d5, 0x1f6d5,
+0x1f6e0, 0x1f6e5,
+0x1f6e9, 0x1f6e9,
+0x1f6eb, 0x1f6ec,
+0x1f6f0, 0x1f6f0,
+0x1f6f3, 0x1f6fa,
+0x1f7e0, 0x1f7eb,
+0x1f90d, 0x1f93a,
+0x1f93c, 0x1f945,
+0x1f947, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1f9ff,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+}; /* END of CR_Emoji */
+
+/* PROPERTY: 'Emoji_Component': Emoji Property */
+static const OnigCodePoint
+CR_Emoji_Component[] = { 10,
+0x0023, 0x0023,
+0x002a, 0x002a,
+0x0030, 0x0039,
+0x200d, 0x200d,
+0x20e3, 0x20e3,
+0xfe0f, 0xfe0f,
+0x1f1e6, 0x1f1ff,
+0x1f3fb, 0x1f3ff,
+0x1f9b0, 0x1f9b3,
+0xe0020, 0xe007f,
+}; /* END of CR_Emoji_Component */
+
+/* PROPERTY: 'Emoji_Modifier': Emoji Property */
+static const OnigCodePoint
+CR_Emoji_Modifier[] = { 1,
+0x1f3fb, 0x1f3ff,
+}; /* END of CR_Emoji_Modifier */
+
+/* PROPERTY: 'Emoji_Modifier_Base': Emoji Property */
+static const OnigCodePoint
+CR_Emoji_Modifier_Base[] = { 36,
+0x261d, 0x261d,
+0x26f9, 0x26f9,
+0x270a, 0x270d,
+0x1f385, 0x1f385,
+0x1f3c2, 0x1f3c4,
+0x1f3c7, 0x1f3c7,
+0x1f3ca, 0x1f3cc,
+0x1f442, 0x1f443,
+0x1f446, 0x1f450,
+0x1f466, 0x1f478,
+0x1f47c, 0x1f47c,
+0x1f481, 0x1f483,
+0x1f485, 0x1f487,
+0x1f48f, 0x1f48f,
+0x1f491, 0x1f491,
+0x1f4aa, 0x1f4aa,
+0x1f574, 0x1f575,
+0x1f57a, 0x1f57a,
+0x1f590, 0x1f590,
+0x1f595, 0x1f596,
+0x1f645, 0x1f647,
+0x1f64b, 0x1f64f,
+0x1f6a3, 0x1f6a3,
+0x1f6b4, 0x1f6b6,
+0x1f6c0, 0x1f6c0,
+0x1f6cc, 0x1f6cc,
+0x1f90f, 0x1f90f,
+0x1f918, 0x1f91f,
+0x1f926, 0x1f926,
+0x1f930, 0x1f939,
+0x1f93c, 0x1f93e,
+0x1f9b5, 0x1f9b6,
+0x1f9b8, 0x1f9b9,
+0x1f9bb, 0x1f9bb,
+0x1f9cd, 0x1f9cf,
+0x1f9d1, 0x1f9dd,
+}; /* END of CR_Emoji_Modifier_Base */
+
+/* PROPERTY: 'Emoji_Presentation': Emoji Property */
+static const OnigCodePoint
+CR_Emoji_Presentation[] = { 81,
+0x231a, 0x231b,
+0x23e9, 0x23ec,
+0x23f0, 0x23f0,
+0x23f3, 0x23f3,
+0x25fd, 0x25fe,
+0x2614, 0x2615,
+0x2648, 0x2653,
+0x267f, 0x267f,
+0x2693, 0x2693,
+0x26a1, 0x26a1,
+0x26aa, 0x26ab,
+0x26bd, 0x26be,
+0x26c4, 0x26c5,
+0x26ce, 0x26ce,
+0x26d4, 0x26d4,
+0x26ea, 0x26ea,
+0x26f2, 0x26f3,
+0x26f5, 0x26f5,
+0x26fa, 0x26fa,
+0x26fd, 0x26fd,
+0x2705, 0x2705,
+0x270a, 0x270b,
+0x2728, 0x2728,
+0x274c, 0x274c,
+0x274e, 0x274e,
+0x2753, 0x2755,
+0x2757, 0x2757,
+0x2795, 0x2797,
+0x27b0, 0x27b0,
+0x27bf, 0x27bf,
+0x2b1b, 0x2b1c,
+0x2b50, 0x2b50,
+0x2b55, 0x2b55,
+0x1f004, 0x1f004,
+0x1f0cf, 0x1f0cf,
+0x1f18e, 0x1f18e,
+0x1f191, 0x1f19a,
+0x1f1e6, 0x1f1ff,
+0x1f201, 0x1f201,
+0x1f21a, 0x1f21a,
+0x1f22f, 0x1f22f,
+0x1f232, 0x1f236,
+0x1f238, 0x1f23a,
+0x1f250, 0x1f251,
+0x1f300, 0x1f320,
+0x1f32d, 0x1f335,
+0x1f337, 0x1f37c,
+0x1f37e, 0x1f393,
+0x1f3a0, 0x1f3ca,
+0x1f3cf, 0x1f3d3,
+0x1f3e0, 0x1f3f0,
+0x1f3f4, 0x1f3f4,
+0x1f3f8, 0x1f43e,
+0x1f440, 0x1f440,
+0x1f442, 0x1f4fc,
+0x1f4ff, 0x1f53d,
+0x1f54b, 0x1f54e,
+0x1f550, 0x1f567,
+0x1f57a, 0x1f57a,
+0x1f595, 0x1f596,
+0x1f5a4, 0x1f5a4,
+0x1f5fb, 0x1f64f,
+0x1f680, 0x1f6c5,
+0x1f6cc, 0x1f6cc,
+0x1f6d0, 0x1f6d2,
+0x1f6d5, 0x1f6d5,
+0x1f6eb, 0x1f6ec,
+0x1f6f4, 0x1f6fa,
+0x1f7e0, 0x1f7eb,
+0x1f90d, 0x1f93a,
+0x1f93c, 0x1f945,
+0x1f947, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1f9ff,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+}; /* END of CR_Emoji_Presentation */
+
+/* PROPERTY: 'Ethiopic': Script */
+static const OnigCodePoint
+CR_Ethiopic[] = { 32,
+0x1200, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+}; /* END of CR_Ethiopic */
+
+/* PROPERTY: 'Extended_Pictographic': Emoji Property */
+static const OnigCodePoint
+CR_Extended_Pictographic[] = { 77,
+0x00a9, 0x00a9,
+0x00ae, 0x00ae,
+0x203c, 0x203c,
+0x2049, 0x2049,
+0x2122, 0x2122,
+0x2139, 0x2139,
+0x2194, 0x2199,
+0x21a9, 0x21aa,
+0x231a, 0x231b,
+0x2328, 0x2328,
+0x2388, 0x2388,
+0x23cf, 0x23cf,
+0x23e9, 0x23f3,
+0x23f8, 0x23fa,
+0x24c2, 0x24c2,
+0x25aa, 0x25ab,
+0x25b6, 0x25b6,
+0x25c0, 0x25c0,
+0x25fb, 0x25fe,
+0x2600, 0x2605,
+0x2607, 0x2612,
+0x2614, 0x2685,
+0x2690, 0x2705,
+0x2708, 0x2712,
+0x2714, 0x2714,
+0x2716, 0x2716,
+0x271d, 0x271d,
+0x2721, 0x2721,
+0x2728, 0x2728,
+0x2733, 0x2734,
+0x2744, 0x2744,
+0x2747, 0x2747,
+0x274c, 0x274c,
+0x274e, 0x274e,
+0x2753, 0x2755,
+0x2757, 0x2757,
+0x2763, 0x2767,
+0x2795, 0x2797,
+0x27a1, 0x27a1,
+0x27b0, 0x27b0,
+0x27bf, 0x27bf,
+0x2934, 0x2935,
+0x2b05, 0x2b07,
+0x2b1b, 0x2b1c,
+0x2b50, 0x2b50,
+0x2b55, 0x2b55,
+0x3030, 0x3030,
+0x303d, 0x303d,
+0x3297, 0x3297,
+0x3299, 0x3299,
+0x1f000, 0x1f0ff,
+0x1f10d, 0x1f10f,
+0x1f12f, 0x1f12f,
+0x1f16c, 0x1f171,
+0x1f17e, 0x1f17f,
+0x1f18e, 0x1f18e,
+0x1f191, 0x1f19a,
+0x1f1ad, 0x1f1e5,
+0x1f201, 0x1f20f,
+0x1f21a, 0x1f21a,
+0x1f22f, 0x1f22f,
+0x1f232, 0x1f23a,
+0x1f23c, 0x1f23f,
+0x1f249, 0x1f3fa,
+0x1f400, 0x1f53d,
+0x1f546, 0x1f64f,
+0x1f680, 0x1f6ff,
+0x1f774, 0x1f77f,
+0x1f7d5, 0x1f7ff,
+0x1f80c, 0x1f80f,
+0x1f848, 0x1f84f,
+0x1f85a, 0x1f85f,
+0x1f888, 0x1f88f,
+0x1f8ae, 0x1f8ff,
+0x1f90c, 0x1f93a,
+0x1f93c, 0x1f945,
+0x1f947, 0x1fffd,
+}; /* END of CR_Extended_Pictographic */
+
+/* PROPERTY: 'Extender': Binary Property */
+static const OnigCodePoint
+CR_Extender[] = { 31,
+0x00b7, 0x00b7,
+0x02d0, 0x02d1,
+0x0640, 0x0640,
+0x07fa, 0x07fa,
+0x0e46, 0x0e46,
+0x0ec6, 0x0ec6,
+0x180a, 0x180a,
+0x1843, 0x1843,
+0x1aa7, 0x1aa7,
+0x1c36, 0x1c36,
+0x1c7b, 0x1c7b,
+0x3005, 0x3005,
+0x3031, 0x3035,
+0x309d, 0x309e,
+0x30fc, 0x30fe,
+0xa015, 0xa015,
+0xa60c, 0xa60c,
+0xa9cf, 0xa9cf,
+0xa9e6, 0xa9e6,
+0xaa70, 0xaa70,
+0xaadd, 0xaadd,
+0xaaf3, 0xaaf4,
+0xff70, 0xff70,
+0x1135d, 0x1135d,
+0x115c6, 0x115c8,
+0x11a98, 0x11a98,
+0x16b42, 0x16b43,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x1e13c, 0x1e13d,
+0x1e944, 0x1e946,
+}; /* END of CR_Extender */
+
+/* PROPERTY: 'Georgian': Script */
+static const OnigCodePoint
+CR_Georgian[] = { 10,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x10ff,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+}; /* END of CR_Georgian */
+
+/* PROPERTY: 'Glagolitic': Script */
+static const OnigCodePoint
+CR_Glagolitic[] = { 7,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+}; /* END of CR_Glagolitic */
+
+/* PROPERTY: 'Gothic': Script */
+static const OnigCodePoint
+CR_Gothic[] = { 1,
+0x10330, 0x1034a,
+}; /* END of CR_Gothic */
+
+/* PROPERTY: 'Grantha': Script */
+static const OnigCodePoint
+CR_Grantha[] = { 15,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133c, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+}; /* END of CR_Grantha */
+
+/* PROPERTY: 'Grapheme_Base': Derived Property */
+static const OnigCodePoint
+CR_Grapheme_Base[] = { 819,
+0x0020, 0x007e,
+0x00a0, 0x00ac,
+0x00ae, 0x02ff,
+0x0370, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x0482,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x05be, 0x05be,
+0x05c0, 0x05c0,
+0x05c3, 0x05c3,
+0x05c6, 0x05c6,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0606, 0x060f,
+0x061b, 0x061b,
+0x061e, 0x064a,
+0x0660, 0x066f,
+0x0671, 0x06d5,
+0x06de, 0x06de,
+0x06e5, 0x06e6,
+0x06e9, 0x06e9,
+0x06ee, 0x070d,
+0x0710, 0x0710,
+0x0712, 0x072f,
+0x074d, 0x07a5,
+0x07b1, 0x07b1,
+0x07c0, 0x07ea,
+0x07f4, 0x07fa,
+0x07fe, 0x0815,
+0x081a, 0x081a,
+0x0824, 0x0824,
+0x0828, 0x0828,
+0x0830, 0x083e,
+0x0840, 0x0858,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x0903, 0x0939,
+0x093b, 0x093b,
+0x093d, 0x0940,
+0x0949, 0x094c,
+0x094e, 0x0950,
+0x0958, 0x0961,
+0x0964, 0x0980,
+0x0982, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09bd,
+0x09bf, 0x09c0,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09ce, 0x09ce,
+0x09dc, 0x09dd,
+0x09df, 0x09e1,
+0x09e6, 0x09fd,
+0x0a03, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3e, 0x0a40,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a6f,
+0x0a72, 0x0a74,
+0x0a76, 0x0a76,
+0x0a83, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0ac0,
+0x0ac9, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae1,
+0x0ae6, 0x0af1,
+0x0af9, 0x0af9,
+0x0b02, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b3d,
+0x0b40, 0x0b40,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b61,
+0x0b66, 0x0b77,
+0x0b83, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbf, 0x0bbf,
+0x0bc1, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd0, 0x0bd0,
+0x0be6, 0x0bfa,
+0x0c01, 0x0c03,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c3d,
+0x0c41, 0x0c44,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c61,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c80,
+0x0c82, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cbe,
+0x0cc0, 0x0cc1,
+0x0cc3, 0x0cc4,
+0x0cc7, 0x0cc8,
+0x0cca, 0x0ccb,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce1,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d02, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d3d,
+0x0d3f, 0x0d40,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d4e, 0x0d4f,
+0x0d54, 0x0d56,
+0x0d58, 0x0d61,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dd0, 0x0dd1,
+0x0dd8, 0x0dde,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e30,
+0x0e32, 0x0e33,
+0x0e3f, 0x0e46,
+0x0e4f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb0,
+0x0eb2, 0x0eb3,
+0x0ebd, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f17,
+0x0f1a, 0x0f34,
+0x0f36, 0x0f36,
+0x0f38, 0x0f38,
+0x0f3a, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f7f, 0x0f7f,
+0x0f85, 0x0f85,
+0x0f88, 0x0f8c,
+0x0fbe, 0x0fc5,
+0x0fc7, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x102c,
+0x1031, 0x1031,
+0x1038, 0x1038,
+0x103b, 0x103c,
+0x103f, 0x1057,
+0x105a, 0x105d,
+0x1061, 0x1070,
+0x1075, 0x1081,
+0x1083, 0x1084,
+0x1087, 0x108c,
+0x108e, 0x109c,
+0x109e, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1360, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1711,
+0x1720, 0x1731,
+0x1735, 0x1736,
+0x1740, 0x1751,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1780, 0x17b3,
+0x17b6, 0x17b6,
+0x17be, 0x17c5,
+0x17c7, 0x17c8,
+0x17d4, 0x17dc,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180a,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x1884,
+0x1887, 0x18a8,
+0x18aa, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1923, 0x1926,
+0x1929, 0x192b,
+0x1930, 0x1931,
+0x1933, 0x1938,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a16,
+0x1a19, 0x1a1a,
+0x1a1e, 0x1a55,
+0x1a57, 0x1a57,
+0x1a61, 0x1a61,
+0x1a63, 0x1a64,
+0x1a6d, 0x1a72,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1b04, 0x1b33,
+0x1b3b, 0x1b3b,
+0x1b3d, 0x1b41,
+0x1b43, 0x1b4b,
+0x1b50, 0x1b6a,
+0x1b74, 0x1b7c,
+0x1b82, 0x1ba1,
+0x1ba6, 0x1ba7,
+0x1baa, 0x1baa,
+0x1bae, 0x1be5,
+0x1be7, 0x1be7,
+0x1bea, 0x1bec,
+0x1bee, 0x1bee,
+0x1bf2, 0x1bf3,
+0x1bfc, 0x1c2b,
+0x1c34, 0x1c35,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd3, 0x1cd3,
+0x1ce1, 0x1ce1,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf7,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x2000, 0x200a,
+0x2010, 0x2027,
+0x202f, 0x205f,
+0x2070, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2e00, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3000, 0x3029,
+0x3030, 0x303f,
+0x3041, 0x3096,
+0x309b, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa66e,
+0xa673, 0xa673,
+0xa67e, 0xa69d,
+0xa6a0, 0xa6ef,
+0xa6f2, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa801,
+0xa803, 0xa805,
+0xa807, 0xa80a,
+0xa80c, 0xa824,
+0xa827, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c3,
+0xa8ce, 0xa8d9,
+0xa8f2, 0xa8fe,
+0xa900, 0xa925,
+0xa92e, 0xa946,
+0xa952, 0xa953,
+0xa95f, 0xa97c,
+0xa983, 0xa9b2,
+0xa9b4, 0xa9b5,
+0xa9ba, 0xa9bb,
+0xa9be, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9e4,
+0xa9e6, 0xa9fe,
+0xaa00, 0xaa28,
+0xaa2f, 0xaa30,
+0xaa33, 0xaa34,
+0xaa40, 0xaa42,
+0xaa44, 0xaa4b,
+0xaa4d, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaa7b,
+0xaa7d, 0xaaaf,
+0xaab1, 0xaab1,
+0xaab5, 0xaab6,
+0xaab9, 0xaabd,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaaeb,
+0xaaee, 0xaaf5,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabe4,
+0xabe6, 0xabe7,
+0xabe9, 0xabec,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb1d,
+0xfb1f, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe10, 0xfe19,
+0xfe30, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff01, 0xff9d,
+0xffa0, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfffc, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fc,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e1, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x10375,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a00,
+0x10a10, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a40, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae4,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d23,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f45,
+0x10f51, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x11000,
+0x11002, 0x11037,
+0x11047, 0x1104d,
+0x11052, 0x1106f,
+0x11082, 0x110b2,
+0x110b7, 0x110b8,
+0x110bb, 0x110bc,
+0x110be, 0x110c1,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11103, 0x11126,
+0x1112c, 0x1112c,
+0x11136, 0x11146,
+0x11150, 0x11172,
+0x11174, 0x11176,
+0x11182, 0x111b5,
+0x111bf, 0x111c8,
+0x111cd, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1122e,
+0x11232, 0x11233,
+0x11235, 0x11235,
+0x11238, 0x1123d,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112de,
+0x112e0, 0x112e2,
+0x112f0, 0x112f9,
+0x11302, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x1133d,
+0x1133f, 0x1133f,
+0x11341, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x1135d, 0x11363,
+0x11400, 0x11437,
+0x11440, 0x11441,
+0x11445, 0x11445,
+0x11447, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145d,
+0x1145f, 0x1145f,
+0x11480, 0x114af,
+0x114b1, 0x114b2,
+0x114b9, 0x114b9,
+0x114bb, 0x114bc,
+0x114be, 0x114be,
+0x114c1, 0x114c1,
+0x114c4, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115ae,
+0x115b0, 0x115b1,
+0x115b8, 0x115bb,
+0x115be, 0x115be,
+0x115c1, 0x115db,
+0x11600, 0x11632,
+0x1163b, 0x1163c,
+0x1163e, 0x1163e,
+0x11641, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116aa,
+0x116ac, 0x116ac,
+0x116ae, 0x116af,
+0x116b6, 0x116b6,
+0x116b8, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x11720, 0x11721,
+0x11726, 0x11726,
+0x11730, 0x1173f,
+0x11800, 0x1182e,
+0x11838, 0x11838,
+0x1183b, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d3,
+0x119dc, 0x119df,
+0x119e1, 0x119e4,
+0x11a00, 0x11a00,
+0x11a0b, 0x11a32,
+0x11a39, 0x11a3a,
+0x11a3f, 0x11a46,
+0x11a50, 0x11a50,
+0x11a57, 0x11a58,
+0x11a5c, 0x11a89,
+0x11a97, 0x11a97,
+0x11a9a, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c2f,
+0x11c3e, 0x11c3e,
+0x11c40, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11ca9, 0x11ca9,
+0x11cb1, 0x11cb1,
+0x11cb4, 0x11cb4,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d30,
+0x11d46, 0x11d46,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d93, 0x11d94,
+0x11d96, 0x11d96,
+0x11d98, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef2,
+0x11ef5, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af5, 0x16af5,
+0x16b00, 0x16b2f,
+0x16b37, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f50, 0x16f87,
+0x16f93, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bc9c,
+0x1bc9f, 0x1bc9f,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d164,
+0x1d166, 0x1d166,
+0x1d16a, 0x1d16d,
+0x1d183, 0x1d184,
+0x1d18c, 0x1d1a9,
+0x1d1ae, 0x1d1e8,
+0x1d200, 0x1d241,
+0x1d245, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1d9ff,
+0x1da37, 0x1da3a,
+0x1da6d, 0x1da74,
+0x1da76, 0x1da83,
+0x1da85, 0x1da8b,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2eb,
+0x1e2f0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8cf,
+0x1e900, 0x1e943,
+0x1e94b, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Grapheme_Base */
+
+/* PROPERTY: 'Grapheme_Extend': Derived Property */
+static const OnigCodePoint
+CR_Grapheme_Extend[] = { 335,
+0x0300, 0x036f,
+0x0483, 0x0489,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x0610, 0x061a,
+0x064b, 0x065f,
+0x0670, 0x0670,
+0x06d6, 0x06dc,
+0x06df, 0x06e4,
+0x06e7, 0x06e8,
+0x06ea, 0x06ed,
+0x0711, 0x0711,
+0x0730, 0x074a,
+0x07a6, 0x07b0,
+0x07eb, 0x07f3,
+0x07fd, 0x07fd,
+0x0816, 0x0819,
+0x081b, 0x0823,
+0x0825, 0x0827,
+0x0829, 0x082d,
+0x0859, 0x085b,
+0x08d3, 0x08e1,
+0x08e3, 0x0902,
+0x093a, 0x093a,
+0x093c, 0x093c,
+0x0941, 0x0948,
+0x094d, 0x094d,
+0x0951, 0x0957,
+0x0962, 0x0963,
+0x0981, 0x0981,
+0x09bc, 0x09bc,
+0x09be, 0x09be,
+0x09c1, 0x09c4,
+0x09cd, 0x09cd,
+0x09d7, 0x09d7,
+0x09e2, 0x09e3,
+0x09fe, 0x09fe,
+0x0a01, 0x0a02,
+0x0a3c, 0x0a3c,
+0x0a41, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a70, 0x0a71,
+0x0a75, 0x0a75,
+0x0a81, 0x0a82,
+0x0abc, 0x0abc,
+0x0ac1, 0x0ac5,
+0x0ac7, 0x0ac8,
+0x0acd, 0x0acd,
+0x0ae2, 0x0ae3,
+0x0afa, 0x0aff,
+0x0b01, 0x0b01,
+0x0b3c, 0x0b3c,
+0x0b3e, 0x0b3f,
+0x0b41, 0x0b44,
+0x0b4d, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b62, 0x0b63,
+0x0b82, 0x0b82,
+0x0bbe, 0x0bbe,
+0x0bc0, 0x0bc0,
+0x0bcd, 0x0bcd,
+0x0bd7, 0x0bd7,
+0x0c00, 0x0c00,
+0x0c04, 0x0c04,
+0x0c3e, 0x0c40,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c62, 0x0c63,
+0x0c81, 0x0c81,
+0x0cbc, 0x0cbc,
+0x0cbf, 0x0cbf,
+0x0cc2, 0x0cc2,
+0x0cc6, 0x0cc6,
+0x0ccc, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0ce2, 0x0ce3,
+0x0d00, 0x0d01,
+0x0d3b, 0x0d3c,
+0x0d3e, 0x0d3e,
+0x0d41, 0x0d44,
+0x0d4d, 0x0d4d,
+0x0d57, 0x0d57,
+0x0d62, 0x0d63,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dcf,
+0x0dd2, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0ddf, 0x0ddf,
+0x0e31, 0x0e31,
+0x0e34, 0x0e3a,
+0x0e47, 0x0e4e,
+0x0eb1, 0x0eb1,
+0x0eb4, 0x0ebc,
+0x0ec8, 0x0ecd,
+0x0f18, 0x0f19,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f71, 0x0f7e,
+0x0f80, 0x0f84,
+0x0f86, 0x0f87,
+0x0f8d, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x102d, 0x1030,
+0x1032, 0x1037,
+0x1039, 0x103a,
+0x103d, 0x103e,
+0x1058, 0x1059,
+0x105e, 0x1060,
+0x1071, 0x1074,
+0x1082, 0x1082,
+0x1085, 0x1086,
+0x108d, 0x108d,
+0x109d, 0x109d,
+0x135d, 0x135f,
+0x1712, 0x1714,
+0x1732, 0x1734,
+0x1752, 0x1753,
+0x1772, 0x1773,
+0x17b4, 0x17b5,
+0x17b7, 0x17bd,
+0x17c6, 0x17c6,
+0x17c9, 0x17d3,
+0x17dd, 0x17dd,
+0x180b, 0x180d,
+0x1885, 0x1886,
+0x18a9, 0x18a9,
+0x1920, 0x1922,
+0x1927, 0x1928,
+0x1932, 0x1932,
+0x1939, 0x193b,
+0x1a17, 0x1a18,
+0x1a1b, 0x1a1b,
+0x1a56, 0x1a56,
+0x1a58, 0x1a5e,
+0x1a60, 0x1a60,
+0x1a62, 0x1a62,
+0x1a65, 0x1a6c,
+0x1a73, 0x1a7c,
+0x1a7f, 0x1a7f,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b03,
+0x1b34, 0x1b3a,
+0x1b3c, 0x1b3c,
+0x1b42, 0x1b42,
+0x1b6b, 0x1b73,
+0x1b80, 0x1b81,
+0x1ba2, 0x1ba5,
+0x1ba8, 0x1ba9,
+0x1bab, 0x1bad,
+0x1be6, 0x1be6,
+0x1be8, 0x1be9,
+0x1bed, 0x1bed,
+0x1bef, 0x1bf1,
+0x1c2c, 0x1c33,
+0x1c36, 0x1c37,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1ce0,
+0x1ce2, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf8, 0x1cf9,
+0x1dc0, 0x1df9,
+0x1dfb, 0x1dff,
+0x200c, 0x200c,
+0x20d0, 0x20f0,
+0x2cef, 0x2cf1,
+0x2d7f, 0x2d7f,
+0x2de0, 0x2dff,
+0x302a, 0x302f,
+0x3099, 0x309a,
+0xa66f, 0xa672,
+0xa674, 0xa67d,
+0xa69e, 0xa69f,
+0xa6f0, 0xa6f1,
+0xa802, 0xa802,
+0xa806, 0xa806,
+0xa80b, 0xa80b,
+0xa825, 0xa826,
+0xa8c4, 0xa8c5,
+0xa8e0, 0xa8f1,
+0xa8ff, 0xa8ff,
+0xa926, 0xa92d,
+0xa947, 0xa951,
+0xa980, 0xa982,
+0xa9b3, 0xa9b3,
+0xa9b6, 0xa9b9,
+0xa9bc, 0xa9bd,
+0xa9e5, 0xa9e5,
+0xaa29, 0xaa2e,
+0xaa31, 0xaa32,
+0xaa35, 0xaa36,
+0xaa43, 0xaa43,
+0xaa4c, 0xaa4c,
+0xaa7c, 0xaa7c,
+0xaab0, 0xaab0,
+0xaab2, 0xaab4,
+0xaab7, 0xaab8,
+0xaabe, 0xaabf,
+0xaac1, 0xaac1,
+0xaaec, 0xaaed,
+0xaaf6, 0xaaf6,
+0xabe5, 0xabe5,
+0xabe8, 0xabe8,
+0xabed, 0xabed,
+0xfb1e, 0xfb1e,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0xff9e, 0xff9f,
+0x101fd, 0x101fd,
+0x102e0, 0x102e0,
+0x10376, 0x1037a,
+0x10a01, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a0f,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10ae5, 0x10ae6,
+0x10d24, 0x10d27,
+0x10f46, 0x10f50,
+0x11001, 0x11001,
+0x11038, 0x11046,
+0x1107f, 0x11081,
+0x110b3, 0x110b6,
+0x110b9, 0x110ba,
+0x11100, 0x11102,
+0x11127, 0x1112b,
+0x1112d, 0x11134,
+0x11173, 0x11173,
+0x11180, 0x11181,
+0x111b6, 0x111be,
+0x111c9, 0x111cc,
+0x1122f, 0x11231,
+0x11234, 0x11234,
+0x11236, 0x11237,
+0x1123e, 0x1123e,
+0x112df, 0x112df,
+0x112e3, 0x112ea,
+0x11300, 0x11301,
+0x1133b, 0x1133c,
+0x1133e, 0x1133e,
+0x11340, 0x11340,
+0x11357, 0x11357,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11438, 0x1143f,
+0x11442, 0x11444,
+0x11446, 0x11446,
+0x1145e, 0x1145e,
+0x114b0, 0x114b0,
+0x114b3, 0x114b8,
+0x114ba, 0x114ba,
+0x114bd, 0x114bd,
+0x114bf, 0x114c0,
+0x114c2, 0x114c3,
+0x115af, 0x115af,
+0x115b2, 0x115b5,
+0x115bc, 0x115bd,
+0x115bf, 0x115c0,
+0x115dc, 0x115dd,
+0x11633, 0x1163a,
+0x1163d, 0x1163d,
+0x1163f, 0x11640,
+0x116ab, 0x116ab,
+0x116ad, 0x116ad,
+0x116b0, 0x116b5,
+0x116b7, 0x116b7,
+0x1171d, 0x1171f,
+0x11722, 0x11725,
+0x11727, 0x1172b,
+0x1182f, 0x11837,
+0x11839, 0x1183a,
+0x119d4, 0x119d7,
+0x119da, 0x119db,
+0x119e0, 0x119e0,
+0x11a01, 0x11a0a,
+0x11a33, 0x11a38,
+0x11a3b, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a51, 0x11a56,
+0x11a59, 0x11a5b,
+0x11a8a, 0x11a96,
+0x11a98, 0x11a99,
+0x11c30, 0x11c36,
+0x11c38, 0x11c3d,
+0x11c3f, 0x11c3f,
+0x11c92, 0x11ca7,
+0x11caa, 0x11cb0,
+0x11cb2, 0x11cb3,
+0x11cb5, 0x11cb6,
+0x11d31, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d45,
+0x11d47, 0x11d47,
+0x11d90, 0x11d91,
+0x11d95, 0x11d95,
+0x11d97, 0x11d97,
+0x11ef3, 0x11ef4,
+0x16af0, 0x16af4,
+0x16b30, 0x16b36,
+0x16f4f, 0x16f4f,
+0x16f8f, 0x16f92,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d165,
+0x1d167, 0x1d169,
+0x1d16e, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e130, 0x1e136,
+0x1e2ec, 0x1e2ef,
+0x1e8d0, 0x1e8d6,
+0x1e944, 0x1e94a,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+}; /* END of CR_Grapheme_Extend */
+
+/* PROPERTY: 'Grapheme_Link': Derived Property */
+static const OnigCodePoint
+CR_Grapheme_Link[] = { 52,
+0x094d, 0x094d,
+0x09cd, 0x09cd,
+0x0a4d, 0x0a4d,
+0x0acd, 0x0acd,
+0x0b4d, 0x0b4d,
+0x0bcd, 0x0bcd,
+0x0c4d, 0x0c4d,
+0x0ccd, 0x0ccd,
+0x0d3b, 0x0d3c,
+0x0d4d, 0x0d4d,
+0x0dca, 0x0dca,
+0x0e3a, 0x0e3a,
+0x0eba, 0x0eba,
+0x0f84, 0x0f84,
+0x1039, 0x103a,
+0x1714, 0x1714,
+0x1734, 0x1734,
+0x17d2, 0x17d2,
+0x1a60, 0x1a60,
+0x1b44, 0x1b44,
+0x1baa, 0x1bab,
+0x1bf2, 0x1bf3,
+0x2d7f, 0x2d7f,
+0xa806, 0xa806,
+0xa8c4, 0xa8c4,
+0xa953, 0xa953,
+0xa9c0, 0xa9c0,
+0xaaf6, 0xaaf6,
+0xabed, 0xabed,
+0x10a3f, 0x10a3f,
+0x11046, 0x11046,
+0x1107f, 0x1107f,
+0x110b9, 0x110b9,
+0x11133, 0x11134,
+0x111c0, 0x111c0,
+0x11235, 0x11235,
+0x112ea, 0x112ea,
+0x1134d, 0x1134d,
+0x11442, 0x11442,
+0x114c2, 0x114c2,
+0x115bf, 0x115bf,
+0x1163f, 0x1163f,
+0x116b6, 0x116b6,
+0x1172b, 0x1172b,
+0x11839, 0x11839,
+0x119e0, 0x119e0,
+0x11a34, 0x11a34,
+0x11a47, 0x11a47,
+0x11a99, 0x11a99,
+0x11c3f, 0x11c3f,
+0x11d44, 0x11d45,
+0x11d97, 0x11d97,
+}; /* END of CR_Grapheme_Link */
+
+/* PROPERTY: 'Greek': Script */
+static const OnigCodePoint
+CR_Greek[] = { 36,
+0x0370, 0x0373,
+0x0375, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0384, 0x0384,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03e1,
+0x03f0, 0x03ff,
+0x1d26, 0x1d2a,
+0x1d5d, 0x1d61,
+0x1d66, 0x1d6a,
+0x1dbf, 0x1dbf,
+0x1f00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x2126, 0x2126,
+0xab65, 0xab65,
+0x10140, 0x1018e,
+0x101a0, 0x101a0,
+0x1d200, 0x1d245,
+}; /* END of CR_Greek */
+
+/* PROPERTY: 'Gujarati': Script */
+static const OnigCodePoint
+CR_Gujarati[] = { 14,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+}; /* END of CR_Gujarati */
+
+/* PROPERTY: 'Gunjala_Gondi': Script */
+static const OnigCodePoint
+CR_Gunjala_Gondi[] = { 6,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+}; /* END of CR_Gunjala_Gondi */
+
+/* PROPERTY: 'Gurmukhi': Script */
+static const OnigCodePoint
+CR_Gurmukhi[] = { 16,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+}; /* END of CR_Gurmukhi */
+
+/* PROPERTY: 'Han': Script */
+static const OnigCodePoint
+CR_Han[] = { 17,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x3005, 0x3005,
+0x3007, 0x3007,
+0x3021, 0x3029,
+0x3038, 0x303b,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Han */
+
+/* PROPERTY: 'Hangul': Script */
+static const OnigCodePoint
+CR_Hangul[] = { 14,
+0x1100, 0x11ff,
+0x302e, 0x302f,
+0x3131, 0x318e,
+0x3200, 0x321e,
+0x3260, 0x327e,
+0xa960, 0xa97c,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xffa0, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+}; /* END of CR_Hangul */
+
+/* PROPERTY: 'Hanifi_Rohingya': Script */
+static const OnigCodePoint
+CR_Hanifi_Rohingya[] = { 2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+}; /* END of CR_Hanifi_Rohingya */
+
+/* PROPERTY: 'Hanunoo': Script */
+static const OnigCodePoint
+CR_Hanunoo[] = { 1,
+0x1720, 0x1734,
+}; /* END of CR_Hanunoo */
+
+/* PROPERTY: 'Hatran': Script */
+static const OnigCodePoint
+CR_Hatran[] = { 3,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x108ff,
+}; /* END of CR_Hatran */
+
+/* PROPERTY: 'Hebrew': Script */
+static const OnigCodePoint
+CR_Hebrew[] = { 9,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfb4f,
+}; /* END of CR_Hebrew */
+
+/* PROPERTY: 'Hex_Digit': Binary Property */
+static const OnigCodePoint
+CR_Hex_Digit[] = { 6,
+0x0030, 0x0039,
+0x0041, 0x0046,
+0x0061, 0x0066,
+0xff10, 0xff19,
+0xff21, 0xff26,
+0xff41, 0xff46,
+}; /* END of CR_Hex_Digit */
+
+/* PROPERTY: 'Hiragana': Script */
+static const OnigCodePoint
+CR_Hiragana[] = { 5,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x1b001, 0x1b11e,
+0x1b150, 0x1b152,
+0x1f200, 0x1f200,
+}; /* END of CR_Hiragana */
+
+/* PROPERTY: 'Hyphen': Binary Property */
+static const OnigCodePoint
+CR_Hyphen[] = { 10,
+0x002d, 0x002d,
+0x00ad, 0x00ad,
+0x058a, 0x058a,
+0x1806, 0x1806,
+0x2010, 0x2011,
+0x2e17, 0x2e17,
+0x30fb, 0x30fb,
+0xfe63, 0xfe63,
+0xff0d, 0xff0d,
+0xff65, 0xff65,
+}; /* END of CR_Hyphen */
+
+/* PROPERTY: 'IDS_Binary_Operator': Binary Property */
+static const OnigCodePoint
+CR_IDS_Binary_Operator[] = { 2,
+0x2ff0, 0x2ff1,
+0x2ff4, 0x2ffb,
+}; /* END of CR_IDS_Binary_Operator */
+
+/* PROPERTY: 'IDS_Trinary_Operator': Binary Property */
+static const OnigCodePoint
+CR_IDS_Trinary_Operator[] = { 1,
+0x2ff2, 0x2ff3,
+}; /* END of CR_IDS_Trinary_Operator */
+
+/* PROPERTY: 'ID_Continue': Derived Property */
+static const OnigCodePoint
+CR_ID_Continue[] = { 713,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x005f, 0x005f,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00b7, 0x00b7,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0300, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x0483, 0x0487,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06df, 0x06e8,
+0x06ea, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07f5,
+0x07fa, 0x07fa,
+0x07fd, 0x07fd,
+0x0800, 0x082d,
+0x0840, 0x085b,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x08e1,
+0x08e3, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x09fe, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e4e,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f18, 0x0f19,
+0x0f20, 0x0f29,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f84,
+0x0f86, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x1000, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x135f,
+0x1369, 0x1371,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1734,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17d3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dd,
+0x17e0, 0x17e9,
+0x180b, 0x180d,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1ab0, 0x1abd,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b6b, 0x1b73,
+0x1b80, 0x1bf3,
+0x1c00, 0x1c37,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x203f, 0x2040,
+0x2054, 0x2054,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x20d0, 0x20dc,
+0x20e1, 0x20e1,
+0x20e5, 0x20f0,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2118, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x3005, 0x3007,
+0x3021, 0x302f,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x3099, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa66f,
+0xa674, 0xa67d,
+0xa67f, 0xa6f1,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8e0, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92d,
+0xa930, 0xa953,
+0xa960, 0xa97c,
+0xa980, 0xa9c0,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabec, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0xfe33, 0xfe34,
+0xfe4d, 0xfe4f,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff3f, 0xff3f,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x101fd, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102e0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae6,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f50,
+0x10fe0, 0x10ff6,
+0x11000, 0x11046,
+0x11066, 0x1106f,
+0x1107f, 0x110ba,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11173,
+0x11176, 0x11176,
+0x11180, 0x111c4,
+0x111c9, 0x111cc,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x1144a,
+0x11450, 0x11459,
+0x1145e, 0x1145f,
+0x11480, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115c0,
+0x115d8, 0x115dd,
+0x11600, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x11739,
+0x11800, 0x1183a,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a50, 0x11a99,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af4,
+0x16b00, 0x16b36,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e8d0, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0100, 0xe01ef,
+}; /* END of CR_ID_Continue */
+
+/* PROPERTY: 'ID_Start': Derived Property */
+static const OnigCodePoint
+CR_ID_Start[] = { 609,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0620, 0x064a,
+0x066e, 0x066f,
+0x0671, 0x06d3,
+0x06d5, 0x06d5,
+0x06e5, 0x06e6,
+0x06ee, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x0710,
+0x0712, 0x072f,
+0x074d, 0x07a5,
+0x07b1, 0x07b1,
+0x07ca, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0815,
+0x081a, 0x081a,
+0x0824, 0x0824,
+0x0828, 0x0828,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x0904, 0x0939,
+0x093d, 0x093d,
+0x0950, 0x0950,
+0x0958, 0x0961,
+0x0971, 0x0980,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09bd,
+0x09ce, 0x09ce,
+0x09dc, 0x09dd,
+0x09df, 0x09e1,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a72, 0x0a74,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0abd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae1,
+0x0af9, 0x0af9,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b3d,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b61,
+0x0b71, 0x0b71,
+0x0b83, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bd0, 0x0bd0,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c3d,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c61,
+0x0c80, 0x0c80,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cbd,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce1,
+0x0cf1, 0x0cf2,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d3d,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d56,
+0x0d5f, 0x0d61,
+0x0d7a, 0x0d7f,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0e01, 0x0e30,
+0x0e32, 0x0e33,
+0x0e40, 0x0e46,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb0,
+0x0eb2, 0x0eb3,
+0x0ebd, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f88, 0x0f8c,
+0x1000, 0x102a,
+0x103f, 0x103f,
+0x1050, 0x1055,
+0x105a, 0x105d,
+0x1061, 0x1061,
+0x1065, 0x1066,
+0x106e, 0x1070,
+0x1075, 0x1081,
+0x108e, 0x108e,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1711,
+0x1720, 0x1731,
+0x1740, 0x1751,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1780, 0x17b3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x1820, 0x1878,
+0x1880, 0x18a8,
+0x18aa, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a16,
+0x1a20, 0x1a54,
+0x1aa7, 0x1aa7,
+0x1b05, 0x1b33,
+0x1b45, 0x1b4b,
+0x1b83, 0x1ba0,
+0x1bae, 0x1baf,
+0x1bba, 0x1be5,
+0x1c00, 0x1c23,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2118, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309b, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa640, 0xa66e,
+0xa67f, 0xa69d,
+0xa6a0, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa801,
+0xa803, 0xa805,
+0xa807, 0xa80a,
+0xa80c, 0xa822,
+0xa840, 0xa873,
+0xa882, 0xa8b3,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8fe,
+0xa90a, 0xa925,
+0xa930, 0xa946,
+0xa960, 0xa97c,
+0xa984, 0xa9b2,
+0xa9cf, 0xa9cf,
+0xa9e0, 0xa9e4,
+0xa9e6, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa28,
+0xaa40, 0xaa42,
+0xaa44, 0xaa4b,
+0xaa60, 0xaa76,
+0xaa7a, 0xaa7a,
+0xaa7e, 0xaaaf,
+0xaab1, 0xaab1,
+0xaab5, 0xaab6,
+0xaab9, 0xaabd,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaea,
+0xaaf2, 0xaaf4,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabe2,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb1d,
+0xfb1f, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x10375,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a00,
+0x10a10, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d23,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11003, 0x11037,
+0x11083, 0x110af,
+0x110d0, 0x110e8,
+0x11103, 0x11126,
+0x11144, 0x11144,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11183, 0x111b2,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x1122b,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112de,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x1133d,
+0x11350, 0x11350,
+0x1135d, 0x11361,
+0x11400, 0x11434,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114af,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115ae,
+0x115d8, 0x115db,
+0x11600, 0x1162f,
+0x11644, 0x11644,
+0x11680, 0x116aa,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x11800, 0x1182b,
+0x118a0, 0x118df,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d0,
+0x119e1, 0x119e1,
+0x119e3, 0x119e3,
+0x11a00, 0x11a00,
+0x11a0b, 0x11a32,
+0x11a3a, 0x11a3a,
+0x11a50, 0x11a50,
+0x11a5c, 0x11a89,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c2e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d30,
+0x11d46, 0x11d46,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d89,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef2,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f50, 0x16f50,
+0x16f93, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e94b, 0x1e94b,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_ID_Start */
+
+/* PROPERTY: 'Ideographic': Binary Property */
+static const OnigCodePoint
+CR_Ideographic[] = { 16,
+0x3006, 0x3007,
+0x3021, 0x3029,
+0x3038, 0x303a,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b170, 0x1b2fb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Ideographic */
+
+/* PROPERTY: 'Imperial_Aramaic': Script */
+static const OnigCodePoint
+CR_Imperial_Aramaic[] = { 2,
+0x10840, 0x10855,
+0x10857, 0x1085f,
+}; /* END of CR_Imperial_Aramaic */
+
+/* PROPERTY: 'Inherited': Script */
+static const OnigCodePoint
+CR_Inherited[] = { 28,
+0x0300, 0x036f,
+0x0485, 0x0486,
+0x064b, 0x0655,
+0x0670, 0x0670,
+0x0951, 0x0954,
+0x1ab0, 0x1abe,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1ce0,
+0x1ce2, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf8, 0x1cf9,
+0x1dc0, 0x1df9,
+0x1dfb, 0x1dff,
+0x200c, 0x200d,
+0x20d0, 0x20f0,
+0x302a, 0x302d,
+0x3099, 0x309a,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2d,
+0x101fd, 0x101fd,
+0x102e0, 0x102e0,
+0x1133b, 0x1133b,
+0x1d167, 0x1d169,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0xe0100, 0xe01ef,
+}; /* END of CR_Inherited */
+
+/* PROPERTY: 'Inscriptional_Pahlavi': Script */
+static const OnigCodePoint
+CR_Inscriptional_Pahlavi[] = { 2,
+0x10b60, 0x10b72,
+0x10b78, 0x10b7f,
+}; /* END of CR_Inscriptional_Pahlavi */
+
+/* PROPERTY: 'Inscriptional_Parthian': Script */
+static const OnigCodePoint
+CR_Inscriptional_Parthian[] = { 2,
+0x10b40, 0x10b55,
+0x10b58, 0x10b5f,
+}; /* END of CR_Inscriptional_Parthian */
+
+/* PROPERTY: 'Javanese': Script */
+static const OnigCodePoint
+CR_Javanese[] = { 3,
+0xa980, 0xa9cd,
+0xa9d0, 0xa9d9,
+0xa9de, 0xa9df,
+}; /* END of CR_Javanese */
+
+/* PROPERTY: 'Join_Control': Binary Property */
+static const OnigCodePoint
+CR_Join_Control[] = { 1,
+0x200c, 0x200d,
+}; /* END of CR_Join_Control */
+
+/* PROPERTY: 'Kaithi': Script */
+static const OnigCodePoint
+CR_Kaithi[] = { 2,
+0x11080, 0x110c1,
+0x110cd, 0x110cd,
+}; /* END of CR_Kaithi */
+
+/* PROPERTY: 'Kannada': Script */
+static const OnigCodePoint
+CR_Kannada[] = { 13,
+0x0c80, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+}; /* END of CR_Kannada */
+
+/* PROPERTY: 'Katakana': Script */
+static const OnigCodePoint
+CR_Katakana[] = { 9,
+0x30a1, 0x30fa,
+0x30fd, 0x30ff,
+0x31f0, 0x31ff,
+0x32d0, 0x32fe,
+0x3300, 0x3357,
+0xff66, 0xff6f,
+0xff71, 0xff9d,
+0x1b000, 0x1b000,
+0x1b164, 0x1b167,
+}; /* END of CR_Katakana */
+
+/* PROPERTY: 'Kayah_Li': Script */
+static const OnigCodePoint
+CR_Kayah_Li[] = { 2,
+0xa900, 0xa92d,
+0xa92f, 0xa92f,
+}; /* END of CR_Kayah_Li */
+
+/* PROPERTY: 'Kharoshthi': Script */
+static const OnigCodePoint
+CR_Kharoshthi[] = { 8,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+}; /* END of CR_Kharoshthi */
+
+/* PROPERTY: 'Khmer': Script */
+static const OnigCodePoint
+CR_Khmer[] = { 4,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x19e0, 0x19ff,
+}; /* END of CR_Khmer */
+
+/* PROPERTY: 'Khojki': Script */
+static const OnigCodePoint
+CR_Khojki[] = { 2,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+}; /* END of CR_Khojki */
+
+/* PROPERTY: 'Khudawadi': Script */
+static const OnigCodePoint
+CR_Khudawadi[] = { 2,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+}; /* END of CR_Khudawadi */
+
+/* PROPERTY: 'L': Major Category */
+static const OnigCodePoint
+CR_L[] = { 609,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0620, 0x064a,
+0x066e, 0x066f,
+0x0671, 0x06d3,
+0x06d5, 0x06d5,
+0x06e5, 0x06e6,
+0x06ee, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x0710,
+0x0712, 0x072f,
+0x074d, 0x07a5,
+0x07b1, 0x07b1,
+0x07ca, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0815,
+0x081a, 0x081a,
+0x0824, 0x0824,
+0x0828, 0x0828,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x0904, 0x0939,
+0x093d, 0x093d,
+0x0950, 0x0950,
+0x0958, 0x0961,
+0x0971, 0x0980,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09bd,
+0x09ce, 0x09ce,
+0x09dc, 0x09dd,
+0x09df, 0x09e1,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a72, 0x0a74,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0abd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae1,
+0x0af9, 0x0af9,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b3d,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b61,
+0x0b71, 0x0b71,
+0x0b83, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bd0, 0x0bd0,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c3d,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c61,
+0x0c80, 0x0c80,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cbd,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce1,
+0x0cf1, 0x0cf2,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d3d,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d56,
+0x0d5f, 0x0d61,
+0x0d7a, 0x0d7f,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0e01, 0x0e30,
+0x0e32, 0x0e33,
+0x0e40, 0x0e46,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb0,
+0x0eb2, 0x0eb3,
+0x0ebd, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f88, 0x0f8c,
+0x1000, 0x102a,
+0x103f, 0x103f,
+0x1050, 0x1055,
+0x105a, 0x105d,
+0x1061, 0x1061,
+0x1065, 0x1066,
+0x106e, 0x1070,
+0x1075, 0x1081,
+0x108e, 0x108e,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16f1, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1711,
+0x1720, 0x1731,
+0x1740, 0x1751,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1780, 0x17b3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x1820, 0x1878,
+0x1880, 0x1884,
+0x1887, 0x18a8,
+0x18aa, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a16,
+0x1a20, 0x1a54,
+0x1aa7, 0x1aa7,
+0x1b05, 0x1b33,
+0x1b45, 0x1b4b,
+0x1b83, 0x1ba0,
+0x1bae, 0x1baf,
+0x1bba, 0x1be5,
+0x1c00, 0x1c23,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2183, 0x2184,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2e2f, 0x2e2f,
+0x3005, 0x3006,
+0x3031, 0x3035,
+0x303b, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa640, 0xa66e,
+0xa67f, 0xa69d,
+0xa6a0, 0xa6e5,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa801,
+0xa803, 0xa805,
+0xa807, 0xa80a,
+0xa80c, 0xa822,
+0xa840, 0xa873,
+0xa882, 0xa8b3,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8fe,
+0xa90a, 0xa925,
+0xa930, 0xa946,
+0xa960, 0xa97c,
+0xa984, 0xa9b2,
+0xa9cf, 0xa9cf,
+0xa9e0, 0xa9e4,
+0xa9e6, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa28,
+0xaa40, 0xaa42,
+0xaa44, 0xaa4b,
+0xaa60, 0xaa76,
+0xaa7a, 0xaa7a,
+0xaa7e, 0xaaaf,
+0xaab1, 0xaab1,
+0xaab5, 0xaab6,
+0xaab9, 0xaabd,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaea,
+0xaaf2, 0xaaf4,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabe2,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb1d,
+0xfb1f, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x10340,
+0x10342, 0x10349,
+0x10350, 0x10375,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x10400, 0x1049d,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a00,
+0x10a10, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d23,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11003, 0x11037,
+0x11083, 0x110af,
+0x110d0, 0x110e8,
+0x11103, 0x11126,
+0x11144, 0x11144,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11183, 0x111b2,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x1122b,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112de,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x1133d,
+0x11350, 0x11350,
+0x1135d, 0x11361,
+0x11400, 0x11434,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114af,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115ae,
+0x115d8, 0x115db,
+0x11600, 0x1162f,
+0x11644, 0x11644,
+0x11680, 0x116aa,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x11800, 0x1182b,
+0x118a0, 0x118df,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d0,
+0x119e1, 0x119e1,
+0x119e3, 0x119e3,
+0x11a00, 0x11a00,
+0x11a0b, 0x11a32,
+0x11a3a, 0x11a3a,
+0x11a50, 0x11a50,
+0x11a5c, 0x11a89,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c2e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d30,
+0x11d46, 0x11d46,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d89,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef2,
+0x12000, 0x12399,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f50, 0x16f50,
+0x16f93, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e94b, 0x1e94b,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_L */
+
+/* PROPERTY: 'LC': General Category */
+static const OnigCodePoint
+CR_LC[] = { 131,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00b5, 0x00b5,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x01ba,
+0x01bc, 0x01bf,
+0x01c4, 0x0293,
+0x0295, 0x02af,
+0x0370, 0x0373,
+0x0376, 0x0377,
+0x037b, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0560, 0x0588,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1d00, 0x1d2b,
+0x1d6b, 0x1d77,
+0x1d79, 0x1d9a,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2134,
+0x2139, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2183, 0x2184,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2c7b,
+0x2c7e, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa640, 0xa66d,
+0xa680, 0xa69b,
+0xa722, 0xa76f,
+0xa771, 0xa787,
+0xa78b, 0xa78e,
+0xa790, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7fa, 0xa7fa,
+0xab30, 0xab5a,
+0xab60, 0xab67,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0x10400, 0x1044f,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x118a0, 0x118df,
+0x16e40, 0x16e7f,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e900, 0x1e943,
+}; /* END of CR_LC */
+
+/* PROPERTY: 'Lao': Script */
+static const OnigCodePoint
+CR_Lao[] = { 11,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+}; /* END of CR_Lao */
+
+/* PROPERTY: 'Latin': Script */
+static const OnigCodePoint
+CR_Latin[] = { 32,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02b8,
+0x02e0, 0x02e4,
+0x1d00, 0x1d25,
+0x1d2c, 0x1d5c,
+0x1d62, 0x1d65,
+0x1d6b, 0x1d77,
+0x1d79, 0x1dbe,
+0x1e00, 0x1eff,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x212a, 0x212b,
+0x2132, 0x2132,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x2c60, 0x2c7f,
+0xa722, 0xa787,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa7ff,
+0xab30, 0xab5a,
+0xab5c, 0xab64,
+0xab66, 0xab67,
+0xfb00, 0xfb06,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+}; /* END of CR_Latin */
+
+/* PROPERTY: 'Lepcha': Script */
+static const OnigCodePoint
+CR_Lepcha[] = { 3,
+0x1c00, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c4f,
+}; /* END of CR_Lepcha */
+
+/* PROPERTY: 'Limbu': Script */
+static const OnigCodePoint
+CR_Limbu[] = { 5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x194f,
+}; /* END of CR_Limbu */
+
+/* PROPERTY: 'Linear_A': Script */
+static const OnigCodePoint
+CR_Linear_A[] = { 3,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+}; /* END of CR_Linear_A */
+
+/* PROPERTY: 'Linear_B': Script */
+static const OnigCodePoint
+CR_Linear_B[] = { 7,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+}; /* END of CR_Linear_B */
+
+/* PROPERTY: 'Lisu': Script */
+static const OnigCodePoint
+CR_Lisu[] = { 1,
+0xa4d0, 0xa4ff,
+}; /* END of CR_Lisu */
+
+/* PROPERTY: 'Ll': General Category */
+static const OnigCodePoint
+CR_Ll[] = { 642,
+0x0061, 0x007a,
+0x00b5, 0x00b5,
+0x00df, 0x00f6,
+0x00f8, 0x00ff,
+0x0101, 0x0101,
+0x0103, 0x0103,
+0x0105, 0x0105,
+0x0107, 0x0107,
+0x0109, 0x0109,
+0x010b, 0x010b,
+0x010d, 0x010d,
+0x010f, 0x010f,
+0x0111, 0x0111,
+0x0113, 0x0113,
+0x0115, 0x0115,
+0x0117, 0x0117,
+0x0119, 0x0119,
+0x011b, 0x011b,
+0x011d, 0x011d,
+0x011f, 0x011f,
+0x0121, 0x0121,
+0x0123, 0x0123,
+0x0125, 0x0125,
+0x0127, 0x0127,
+0x0129, 0x0129,
+0x012b, 0x012b,
+0x012d, 0x012d,
+0x012f, 0x012f,
+0x0131, 0x0131,
+0x0133, 0x0133,
+0x0135, 0x0135,
+0x0137, 0x0138,
+0x013a, 0x013a,
+0x013c, 0x013c,
+0x013e, 0x013e,
+0x0140, 0x0140,
+0x0142, 0x0142,
+0x0144, 0x0144,
+0x0146, 0x0146,
+0x0148, 0x0149,
+0x014b, 0x014b,
+0x014d, 0x014d,
+0x014f, 0x014f,
+0x0151, 0x0151,
+0x0153, 0x0153,
+0x0155, 0x0155,
+0x0157, 0x0157,
+0x0159, 0x0159,
+0x015b, 0x015b,
+0x015d, 0x015d,
+0x015f, 0x015f,
+0x0161, 0x0161,
+0x0163, 0x0163,
+0x0165, 0x0165,
+0x0167, 0x0167,
+0x0169, 0x0169,
+0x016b, 0x016b,
+0x016d, 0x016d,
+0x016f, 0x016f,
+0x0171, 0x0171,
+0x0173, 0x0173,
+0x0175, 0x0175,
+0x0177, 0x0177,
+0x017a, 0x017a,
+0x017c, 0x017c,
+0x017e, 0x0180,
+0x0183, 0x0183,
+0x0185, 0x0185,
+0x0188, 0x0188,
+0x018c, 0x018d,
+0x0192, 0x0192,
+0x0195, 0x0195,
+0x0199, 0x019b,
+0x019e, 0x019e,
+0x01a1, 0x01a1,
+0x01a3, 0x01a3,
+0x01a5, 0x01a5,
+0x01a8, 0x01a8,
+0x01aa, 0x01ab,
+0x01ad, 0x01ad,
+0x01b0, 0x01b0,
+0x01b4, 0x01b4,
+0x01b6, 0x01b6,
+0x01b9, 0x01ba,
+0x01bd, 0x01bf,
+0x01c6, 0x01c6,
+0x01c9, 0x01c9,
+0x01cc, 0x01cc,
+0x01ce, 0x01ce,
+0x01d0, 0x01d0,
+0x01d2, 0x01d2,
+0x01d4, 0x01d4,
+0x01d6, 0x01d6,
+0x01d8, 0x01d8,
+0x01da, 0x01da,
+0x01dc, 0x01dd,
+0x01df, 0x01df,
+0x01e1, 0x01e1,
+0x01e3, 0x01e3,
+0x01e5, 0x01e5,
+0x01e7, 0x01e7,
+0x01e9, 0x01e9,
+0x01eb, 0x01eb,
+0x01ed, 0x01ed,
+0x01ef, 0x01f0,
+0x01f3, 0x01f3,
+0x01f5, 0x01f5,
+0x01f9, 0x01f9,
+0x01fb, 0x01fb,
+0x01fd, 0x01fd,
+0x01ff, 0x01ff,
+0x0201, 0x0201,
+0x0203, 0x0203,
+0x0205, 0x0205,
+0x0207, 0x0207,
+0x0209, 0x0209,
+0x020b, 0x020b,
+0x020d, 0x020d,
+0x020f, 0x020f,
+0x0211, 0x0211,
+0x0213, 0x0213,
+0x0215, 0x0215,
+0x0217, 0x0217,
+0x0219, 0x0219,
+0x021b, 0x021b,
+0x021d, 0x021d,
+0x021f, 0x021f,
+0x0221, 0x0221,
+0x0223, 0x0223,
+0x0225, 0x0225,
+0x0227, 0x0227,
+0x0229, 0x0229,
+0x022b, 0x022b,
+0x022d, 0x022d,
+0x022f, 0x022f,
+0x0231, 0x0231,
+0x0233, 0x0239,
+0x023c, 0x023c,
+0x023f, 0x0240,
+0x0242, 0x0242,
+0x0247, 0x0247,
+0x0249, 0x0249,
+0x024b, 0x024b,
+0x024d, 0x024d,
+0x024f, 0x0293,
+0x0295, 0x02af,
+0x0371, 0x0371,
+0x0373, 0x0373,
+0x0377, 0x0377,
+0x037b, 0x037d,
+0x0390, 0x0390,
+0x03ac, 0x03ce,
+0x03d0, 0x03d1,
+0x03d5, 0x03d7,
+0x03d9, 0x03d9,
+0x03db, 0x03db,
+0x03dd, 0x03dd,
+0x03df, 0x03df,
+0x03e1, 0x03e1,
+0x03e3, 0x03e3,
+0x03e5, 0x03e5,
+0x03e7, 0x03e7,
+0x03e9, 0x03e9,
+0x03eb, 0x03eb,
+0x03ed, 0x03ed,
+0x03ef, 0x03f3,
+0x03f5, 0x03f5,
+0x03f8, 0x03f8,
+0x03fb, 0x03fc,
+0x0430, 0x045f,
+0x0461, 0x0461,
+0x0463, 0x0463,
+0x0465, 0x0465,
+0x0467, 0x0467,
+0x0469, 0x0469,
+0x046b, 0x046b,
+0x046d, 0x046d,
+0x046f, 0x046f,
+0x0471, 0x0471,
+0x0473, 0x0473,
+0x0475, 0x0475,
+0x0477, 0x0477,
+0x0479, 0x0479,
+0x047b, 0x047b,
+0x047d, 0x047d,
+0x047f, 0x047f,
+0x0481, 0x0481,
+0x048b, 0x048b,
+0x048d, 0x048d,
+0x048f, 0x048f,
+0x0491, 0x0491,
+0x0493, 0x0493,
+0x0495, 0x0495,
+0x0497, 0x0497,
+0x0499, 0x0499,
+0x049b, 0x049b,
+0x049d, 0x049d,
+0x049f, 0x049f,
+0x04a1, 0x04a1,
+0x04a3, 0x04a3,
+0x04a5, 0x04a5,
+0x04a7, 0x04a7,
+0x04a9, 0x04a9,
+0x04ab, 0x04ab,
+0x04ad, 0x04ad,
+0x04af, 0x04af,
+0x04b1, 0x04b1,
+0x04b3, 0x04b3,
+0x04b5, 0x04b5,
+0x04b7, 0x04b7,
+0x04b9, 0x04b9,
+0x04bb, 0x04bb,
+0x04bd, 0x04bd,
+0x04bf, 0x04bf,
+0x04c2, 0x04c2,
+0x04c4, 0x04c4,
+0x04c6, 0x04c6,
+0x04c8, 0x04c8,
+0x04ca, 0x04ca,
+0x04cc, 0x04cc,
+0x04ce, 0x04cf,
+0x04d1, 0x04d1,
+0x04d3, 0x04d3,
+0x04d5, 0x04d5,
+0x04d7, 0x04d7,
+0x04d9, 0x04d9,
+0x04db, 0x04db,
+0x04dd, 0x04dd,
+0x04df, 0x04df,
+0x04e1, 0x04e1,
+0x04e3, 0x04e3,
+0x04e5, 0x04e5,
+0x04e7, 0x04e7,
+0x04e9, 0x04e9,
+0x04eb, 0x04eb,
+0x04ed, 0x04ed,
+0x04ef, 0x04ef,
+0x04f1, 0x04f1,
+0x04f3, 0x04f3,
+0x04f5, 0x04f5,
+0x04f7, 0x04f7,
+0x04f9, 0x04f9,
+0x04fb, 0x04fb,
+0x04fd, 0x04fd,
+0x04ff, 0x04ff,
+0x0501, 0x0501,
+0x0503, 0x0503,
+0x0505, 0x0505,
+0x0507, 0x0507,
+0x0509, 0x0509,
+0x050b, 0x050b,
+0x050d, 0x050d,
+0x050f, 0x050f,
+0x0511, 0x0511,
+0x0513, 0x0513,
+0x0515, 0x0515,
+0x0517, 0x0517,
+0x0519, 0x0519,
+0x051b, 0x051b,
+0x051d, 0x051d,
+0x051f, 0x051f,
+0x0521, 0x0521,
+0x0523, 0x0523,
+0x0525, 0x0525,
+0x0527, 0x0527,
+0x0529, 0x0529,
+0x052b, 0x052b,
+0x052d, 0x052d,
+0x052f, 0x052f,
+0x0560, 0x0588,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1d00, 0x1d2b,
+0x1d6b, 0x1d77,
+0x1d79, 0x1d9a,
+0x1e01, 0x1e01,
+0x1e03, 0x1e03,
+0x1e05, 0x1e05,
+0x1e07, 0x1e07,
+0x1e09, 0x1e09,
+0x1e0b, 0x1e0b,
+0x1e0d, 0x1e0d,
+0x1e0f, 0x1e0f,
+0x1e11, 0x1e11,
+0x1e13, 0x1e13,
+0x1e15, 0x1e15,
+0x1e17, 0x1e17,
+0x1e19, 0x1e19,
+0x1e1b, 0x1e1b,
+0x1e1d, 0x1e1d,
+0x1e1f, 0x1e1f,
+0x1e21, 0x1e21,
+0x1e23, 0x1e23,
+0x1e25, 0x1e25,
+0x1e27, 0x1e27,
+0x1e29, 0x1e29,
+0x1e2b, 0x1e2b,
+0x1e2d, 0x1e2d,
+0x1e2f, 0x1e2f,
+0x1e31, 0x1e31,
+0x1e33, 0x1e33,
+0x1e35, 0x1e35,
+0x1e37, 0x1e37,
+0x1e39, 0x1e39,
+0x1e3b, 0x1e3b,
+0x1e3d, 0x1e3d,
+0x1e3f, 0x1e3f,
+0x1e41, 0x1e41,
+0x1e43, 0x1e43,
+0x1e45, 0x1e45,
+0x1e47, 0x1e47,
+0x1e49, 0x1e49,
+0x1e4b, 0x1e4b,
+0x1e4d, 0x1e4d,
+0x1e4f, 0x1e4f,
+0x1e51, 0x1e51,
+0x1e53, 0x1e53,
+0x1e55, 0x1e55,
+0x1e57, 0x1e57,
+0x1e59, 0x1e59,
+0x1e5b, 0x1e5b,
+0x1e5d, 0x1e5d,
+0x1e5f, 0x1e5f,
+0x1e61, 0x1e61,
+0x1e63, 0x1e63,
+0x1e65, 0x1e65,
+0x1e67, 0x1e67,
+0x1e69, 0x1e69,
+0x1e6b, 0x1e6b,
+0x1e6d, 0x1e6d,
+0x1e6f, 0x1e6f,
+0x1e71, 0x1e71,
+0x1e73, 0x1e73,
+0x1e75, 0x1e75,
+0x1e77, 0x1e77,
+0x1e79, 0x1e79,
+0x1e7b, 0x1e7b,
+0x1e7d, 0x1e7d,
+0x1e7f, 0x1e7f,
+0x1e81, 0x1e81,
+0x1e83, 0x1e83,
+0x1e85, 0x1e85,
+0x1e87, 0x1e87,
+0x1e89, 0x1e89,
+0x1e8b, 0x1e8b,
+0x1e8d, 0x1e8d,
+0x1e8f, 0x1e8f,
+0x1e91, 0x1e91,
+0x1e93, 0x1e93,
+0x1e95, 0x1e9d,
+0x1e9f, 0x1e9f,
+0x1ea1, 0x1ea1,
+0x1ea3, 0x1ea3,
+0x1ea5, 0x1ea5,
+0x1ea7, 0x1ea7,
+0x1ea9, 0x1ea9,
+0x1eab, 0x1eab,
+0x1ead, 0x1ead,
+0x1eaf, 0x1eaf,
+0x1eb1, 0x1eb1,
+0x1eb3, 0x1eb3,
+0x1eb5, 0x1eb5,
+0x1eb7, 0x1eb7,
+0x1eb9, 0x1eb9,
+0x1ebb, 0x1ebb,
+0x1ebd, 0x1ebd,
+0x1ebf, 0x1ebf,
+0x1ec1, 0x1ec1,
+0x1ec3, 0x1ec3,
+0x1ec5, 0x1ec5,
+0x1ec7, 0x1ec7,
+0x1ec9, 0x1ec9,
+0x1ecb, 0x1ecb,
+0x1ecd, 0x1ecd,
+0x1ecf, 0x1ecf,
+0x1ed1, 0x1ed1,
+0x1ed3, 0x1ed3,
+0x1ed5, 0x1ed5,
+0x1ed7, 0x1ed7,
+0x1ed9, 0x1ed9,
+0x1edb, 0x1edb,
+0x1edd, 0x1edd,
+0x1edf, 0x1edf,
+0x1ee1, 0x1ee1,
+0x1ee3, 0x1ee3,
+0x1ee5, 0x1ee5,
+0x1ee7, 0x1ee7,
+0x1ee9, 0x1ee9,
+0x1eeb, 0x1eeb,
+0x1eed, 0x1eed,
+0x1eef, 0x1eef,
+0x1ef1, 0x1ef1,
+0x1ef3, 0x1ef3,
+0x1ef5, 0x1ef5,
+0x1ef7, 0x1ef7,
+0x1ef9, 0x1ef9,
+0x1efb, 0x1efb,
+0x1efd, 0x1efd,
+0x1eff, 0x1f07,
+0x1f10, 0x1f15,
+0x1f20, 0x1f27,
+0x1f30, 0x1f37,
+0x1f40, 0x1f45,
+0x1f50, 0x1f57,
+0x1f60, 0x1f67,
+0x1f70, 0x1f7d,
+0x1f80, 0x1f87,
+0x1f90, 0x1f97,
+0x1fa0, 0x1fa7,
+0x1fb0, 0x1fb4,
+0x1fb6, 0x1fb7,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fc7,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fd7,
+0x1fe0, 0x1fe7,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ff7,
+0x210a, 0x210a,
+0x210e, 0x210f,
+0x2113, 0x2113,
+0x212f, 0x212f,
+0x2134, 0x2134,
+0x2139, 0x2139,
+0x213c, 0x213d,
+0x2146, 0x2149,
+0x214e, 0x214e,
+0x2184, 0x2184,
+0x2c30, 0x2c5e,
+0x2c61, 0x2c61,
+0x2c65, 0x2c66,
+0x2c68, 0x2c68,
+0x2c6a, 0x2c6a,
+0x2c6c, 0x2c6c,
+0x2c71, 0x2c71,
+0x2c73, 0x2c74,
+0x2c76, 0x2c7b,
+0x2c81, 0x2c81,
+0x2c83, 0x2c83,
+0x2c85, 0x2c85,
+0x2c87, 0x2c87,
+0x2c89, 0x2c89,
+0x2c8b, 0x2c8b,
+0x2c8d, 0x2c8d,
+0x2c8f, 0x2c8f,
+0x2c91, 0x2c91,
+0x2c93, 0x2c93,
+0x2c95, 0x2c95,
+0x2c97, 0x2c97,
+0x2c99, 0x2c99,
+0x2c9b, 0x2c9b,
+0x2c9d, 0x2c9d,
+0x2c9f, 0x2c9f,
+0x2ca1, 0x2ca1,
+0x2ca3, 0x2ca3,
+0x2ca5, 0x2ca5,
+0x2ca7, 0x2ca7,
+0x2ca9, 0x2ca9,
+0x2cab, 0x2cab,
+0x2cad, 0x2cad,
+0x2caf, 0x2caf,
+0x2cb1, 0x2cb1,
+0x2cb3, 0x2cb3,
+0x2cb5, 0x2cb5,
+0x2cb7, 0x2cb7,
+0x2cb9, 0x2cb9,
+0x2cbb, 0x2cbb,
+0x2cbd, 0x2cbd,
+0x2cbf, 0x2cbf,
+0x2cc1, 0x2cc1,
+0x2cc3, 0x2cc3,
+0x2cc5, 0x2cc5,
+0x2cc7, 0x2cc7,
+0x2cc9, 0x2cc9,
+0x2ccb, 0x2ccb,
+0x2ccd, 0x2ccd,
+0x2ccf, 0x2ccf,
+0x2cd1, 0x2cd1,
+0x2cd3, 0x2cd3,
+0x2cd5, 0x2cd5,
+0x2cd7, 0x2cd7,
+0x2cd9, 0x2cd9,
+0x2cdb, 0x2cdb,
+0x2cdd, 0x2cdd,
+0x2cdf, 0x2cdf,
+0x2ce1, 0x2ce1,
+0x2ce3, 0x2ce4,
+0x2cec, 0x2cec,
+0x2cee, 0x2cee,
+0x2cf3, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa641, 0xa641,
+0xa643, 0xa643,
+0xa645, 0xa645,
+0xa647, 0xa647,
+0xa649, 0xa649,
+0xa64b, 0xa64b,
+0xa64d, 0xa64d,
+0xa64f, 0xa64f,
+0xa651, 0xa651,
+0xa653, 0xa653,
+0xa655, 0xa655,
+0xa657, 0xa657,
+0xa659, 0xa659,
+0xa65b, 0xa65b,
+0xa65d, 0xa65d,
+0xa65f, 0xa65f,
+0xa661, 0xa661,
+0xa663, 0xa663,
+0xa665, 0xa665,
+0xa667, 0xa667,
+0xa669, 0xa669,
+0xa66b, 0xa66b,
+0xa66d, 0xa66d,
+0xa681, 0xa681,
+0xa683, 0xa683,
+0xa685, 0xa685,
+0xa687, 0xa687,
+0xa689, 0xa689,
+0xa68b, 0xa68b,
+0xa68d, 0xa68d,
+0xa68f, 0xa68f,
+0xa691, 0xa691,
+0xa693, 0xa693,
+0xa695, 0xa695,
+0xa697, 0xa697,
+0xa699, 0xa699,
+0xa69b, 0xa69b,
+0xa723, 0xa723,
+0xa725, 0xa725,
+0xa727, 0xa727,
+0xa729, 0xa729,
+0xa72b, 0xa72b,
+0xa72d, 0xa72d,
+0xa72f, 0xa731,
+0xa733, 0xa733,
+0xa735, 0xa735,
+0xa737, 0xa737,
+0xa739, 0xa739,
+0xa73b, 0xa73b,
+0xa73d, 0xa73d,
+0xa73f, 0xa73f,
+0xa741, 0xa741,
+0xa743, 0xa743,
+0xa745, 0xa745,
+0xa747, 0xa747,
+0xa749, 0xa749,
+0xa74b, 0xa74b,
+0xa74d, 0xa74d,
+0xa74f, 0xa74f,
+0xa751, 0xa751,
+0xa753, 0xa753,
+0xa755, 0xa755,
+0xa757, 0xa757,
+0xa759, 0xa759,
+0xa75b, 0xa75b,
+0xa75d, 0xa75d,
+0xa75f, 0xa75f,
+0xa761, 0xa761,
+0xa763, 0xa763,
+0xa765, 0xa765,
+0xa767, 0xa767,
+0xa769, 0xa769,
+0xa76b, 0xa76b,
+0xa76d, 0xa76d,
+0xa76f, 0xa76f,
+0xa771, 0xa778,
+0xa77a, 0xa77a,
+0xa77c, 0xa77c,
+0xa77f, 0xa77f,
+0xa781, 0xa781,
+0xa783, 0xa783,
+0xa785, 0xa785,
+0xa787, 0xa787,
+0xa78c, 0xa78c,
+0xa78e, 0xa78e,
+0xa791, 0xa791,
+0xa793, 0xa795,
+0xa797, 0xa797,
+0xa799, 0xa799,
+0xa79b, 0xa79b,
+0xa79d, 0xa79d,
+0xa79f, 0xa79f,
+0xa7a1, 0xa7a1,
+0xa7a3, 0xa7a3,
+0xa7a5, 0xa7a5,
+0xa7a7, 0xa7a7,
+0xa7a9, 0xa7a9,
+0xa7af, 0xa7af,
+0xa7b5, 0xa7b5,
+0xa7b7, 0xa7b7,
+0xa7b9, 0xa7b9,
+0xa7bb, 0xa7bb,
+0xa7bd, 0xa7bd,
+0xa7bf, 0xa7bf,
+0xa7c3, 0xa7c3,
+0xa7fa, 0xa7fa,
+0xab30, 0xab5a,
+0xab60, 0xab67,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff41, 0xff5a,
+0x10428, 0x1044f,
+0x104d8, 0x104fb,
+0x10cc0, 0x10cf2,
+0x118c0, 0x118df,
+0x16e60, 0x16e7f,
+0x1d41a, 0x1d433,
+0x1d44e, 0x1d454,
+0x1d456, 0x1d467,
+0x1d482, 0x1d49b,
+0x1d4b6, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d4cf,
+0x1d4ea, 0x1d503,
+0x1d51e, 0x1d537,
+0x1d552, 0x1d56b,
+0x1d586, 0x1d59f,
+0x1d5ba, 0x1d5d3,
+0x1d5ee, 0x1d607,
+0x1d622, 0x1d63b,
+0x1d656, 0x1d66f,
+0x1d68a, 0x1d6a5,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6e1,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d71b,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d755,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d78f,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7c9,
+0x1d7cb, 0x1d7cb,
+0x1e922, 0x1e943,
+}; /* END of CR_Ll */
+
+/* PROPERTY: 'Lm': General Category */
+static const OnigCodePoint
+CR_Lm[] = { 60,
+0x02b0, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0374, 0x0374,
+0x037a, 0x037a,
+0x0559, 0x0559,
+0x0640, 0x0640,
+0x06e5, 0x06e6,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x081a, 0x081a,
+0x0824, 0x0824,
+0x0828, 0x0828,
+0x0971, 0x0971,
+0x0e46, 0x0e46,
+0x0ec6, 0x0ec6,
+0x10fc, 0x10fc,
+0x17d7, 0x17d7,
+0x1843, 0x1843,
+0x1aa7, 0x1aa7,
+0x1c78, 0x1c7d,
+0x1d2c, 0x1d6a,
+0x1d78, 0x1d78,
+0x1d9b, 0x1dbf,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2c7c, 0x2c7d,
+0x2d6f, 0x2d6f,
+0x2e2f, 0x2e2f,
+0x3005, 0x3005,
+0x3031, 0x3035,
+0x303b, 0x303b,
+0x309d, 0x309e,
+0x30fc, 0x30fe,
+0xa015, 0xa015,
+0xa4f8, 0xa4fd,
+0xa60c, 0xa60c,
+0xa67f, 0xa67f,
+0xa69c, 0xa69d,
+0xa717, 0xa71f,
+0xa770, 0xa770,
+0xa788, 0xa788,
+0xa7f8, 0xa7f9,
+0xa9cf, 0xa9cf,
+0xa9e6, 0xa9e6,
+0xaa70, 0xaa70,
+0xaadd, 0xaadd,
+0xaaf3, 0xaaf4,
+0xab5c, 0xab5f,
+0xff70, 0xff70,
+0xff9e, 0xff9f,
+0x16b40, 0x16b43,
+0x16f93, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x1e137, 0x1e13d,
+0x1e94b, 0x1e94b,
+}; /* END of CR_Lm */
+
+/* PROPERTY: 'Lo': General Category */
+static const OnigCodePoint
+CR_Lo[] = { 476,
+0x00aa, 0x00aa,
+0x00ba, 0x00ba,
+0x01bb, 0x01bb,
+0x01c0, 0x01c3,
+0x0294, 0x0294,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0620, 0x063f,
+0x0641, 0x064a,
+0x066e, 0x066f,
+0x0671, 0x06d3,
+0x06d5, 0x06d5,
+0x06ee, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x0710,
+0x0712, 0x072f,
+0x074d, 0x07a5,
+0x07b1, 0x07b1,
+0x07ca, 0x07ea,
+0x0800, 0x0815,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x0904, 0x0939,
+0x093d, 0x093d,
+0x0950, 0x0950,
+0x0958, 0x0961,
+0x0972, 0x0980,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09bd,
+0x09ce, 0x09ce,
+0x09dc, 0x09dd,
+0x09df, 0x09e1,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a72, 0x0a74,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0abd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae1,
+0x0af9, 0x0af9,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b3d,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b61,
+0x0b71, 0x0b71,
+0x0b83, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bd0, 0x0bd0,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c3d,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c61,
+0x0c80, 0x0c80,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cbd,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce1,
+0x0cf1, 0x0cf2,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d3d,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d56,
+0x0d5f, 0x0d61,
+0x0d7a, 0x0d7f,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0e01, 0x0e30,
+0x0e32, 0x0e33,
+0x0e40, 0x0e45,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb0,
+0x0eb2, 0x0eb3,
+0x0ebd, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f88, 0x0f8c,
+0x1000, 0x102a,
+0x103f, 0x103f,
+0x1050, 0x1055,
+0x105a, 0x105d,
+0x1061, 0x1061,
+0x1065, 0x1066,
+0x106e, 0x1070,
+0x1075, 0x1081,
+0x108e, 0x108e,
+0x1100, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16f1, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1711,
+0x1720, 0x1731,
+0x1740, 0x1751,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1780, 0x17b3,
+0x17dc, 0x17dc,
+0x1820, 0x1842,
+0x1844, 0x1878,
+0x1880, 0x1884,
+0x1887, 0x18a8,
+0x18aa, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a16,
+0x1a20, 0x1a54,
+0x1b05, 0x1b33,
+0x1b45, 0x1b4b,
+0x1b83, 0x1ba0,
+0x1bae, 0x1baf,
+0x1bba, 0x1be5,
+0x1c00, 0x1c23,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c77,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x2135, 0x2138,
+0x2d30, 0x2d67,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x3006, 0x3006,
+0x303c, 0x303c,
+0x3041, 0x3096,
+0x309f, 0x309f,
+0x30a1, 0x30fa,
+0x30ff, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa014,
+0xa016, 0xa48c,
+0xa4d0, 0xa4f7,
+0xa500, 0xa60b,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa66e, 0xa66e,
+0xa6a0, 0xa6e5,
+0xa78f, 0xa78f,
+0xa7f7, 0xa7f7,
+0xa7fb, 0xa801,
+0xa803, 0xa805,
+0xa807, 0xa80a,
+0xa80c, 0xa822,
+0xa840, 0xa873,
+0xa882, 0xa8b3,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8fe,
+0xa90a, 0xa925,
+0xa930, 0xa946,
+0xa960, 0xa97c,
+0xa984, 0xa9b2,
+0xa9e0, 0xa9e4,
+0xa9e7, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa28,
+0xaa40, 0xaa42,
+0xaa44, 0xaa4b,
+0xaa60, 0xaa6f,
+0xaa71, 0xaa76,
+0xaa7a, 0xaa7a,
+0xaa7e, 0xaaaf,
+0xaab1, 0xaab1,
+0xaab5, 0xaab6,
+0xaab9, 0xaabd,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadc,
+0xaae0, 0xaaea,
+0xaaf2, 0xaaf2,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xabc0, 0xabe2,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb1d, 0xfb1d,
+0xfb1f, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff66, 0xff6f,
+0xff71, 0xff9d,
+0xffa0, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x10340,
+0x10342, 0x10349,
+0x10350, 0x10375,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x10450, 0x1049d,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a00,
+0x10a10, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10d00, 0x10d23,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11003, 0x11037,
+0x11083, 0x110af,
+0x110d0, 0x110e8,
+0x11103, 0x11126,
+0x11144, 0x11144,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11183, 0x111b2,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x1122b,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112de,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x1133d,
+0x11350, 0x11350,
+0x1135d, 0x11361,
+0x11400, 0x11434,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114af,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115ae,
+0x115d8, 0x115db,
+0x11600, 0x1162f,
+0x11644, 0x11644,
+0x11680, 0x116aa,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x11800, 0x1182b,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d0,
+0x119e1, 0x119e1,
+0x119e3, 0x119e3,
+0x11a00, 0x11a00,
+0x11a0b, 0x11a32,
+0x11a3a, 0x11a3a,
+0x11a50, 0x11a50,
+0x11a5c, 0x11a89,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c2e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d30,
+0x11d46, 0x11d46,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d89,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef2,
+0x12000, 0x12399,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16f00, 0x16f4a,
+0x16f50, 0x16f50,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1e100, 0x1e12c,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Lo */
+
+/* PROPERTY: 'Logical_Order_Exception': Binary Property */
+static const OnigCodePoint
+CR_Logical_Order_Exception[] = { 7,
+0x0e40, 0x0e44,
+0x0ec0, 0x0ec4,
+0x19b5, 0x19b7,
+0x19ba, 0x19ba,
+0xaab5, 0xaab6,
+0xaab9, 0xaab9,
+0xaabb, 0xaabc,
+}; /* END of CR_Logical_Order_Exception */
+
+/* PROPERTY: 'Lowercase': Derived Property */
+#define CR_Lowercase CR_Lower
+
+/* PROPERTY: 'Lt': General Category */
+static const OnigCodePoint
+CR_Lt[] = { 10,
+0x01c5, 0x01c5,
+0x01c8, 0x01c8,
+0x01cb, 0x01cb,
+0x01f2, 0x01f2,
+0x1f88, 0x1f8f,
+0x1f98, 0x1f9f,
+0x1fa8, 0x1faf,
+0x1fbc, 0x1fbc,
+0x1fcc, 0x1fcc,
+0x1ffc, 0x1ffc,
+}; /* END of CR_Lt */
+
+/* PROPERTY: 'Lu': General Category */
+static const OnigCodePoint
+CR_Lu[] = { 636,
+0x0041, 0x005a,
+0x00c0, 0x00d6,
+0x00d8, 0x00de,
+0x0100, 0x0100,
+0x0102, 0x0102,
+0x0104, 0x0104,
+0x0106, 0x0106,
+0x0108, 0x0108,
+0x010a, 0x010a,
+0x010c, 0x010c,
+0x010e, 0x010e,
+0x0110, 0x0110,
+0x0112, 0x0112,
+0x0114, 0x0114,
+0x0116, 0x0116,
+0x0118, 0x0118,
+0x011a, 0x011a,
+0x011c, 0x011c,
+0x011e, 0x011e,
+0x0120, 0x0120,
+0x0122, 0x0122,
+0x0124, 0x0124,
+0x0126, 0x0126,
+0x0128, 0x0128,
+0x012a, 0x012a,
+0x012c, 0x012c,
+0x012e, 0x012e,
+0x0130, 0x0130,
+0x0132, 0x0132,
+0x0134, 0x0134,
+0x0136, 0x0136,
+0x0139, 0x0139,
+0x013b, 0x013b,
+0x013d, 0x013d,
+0x013f, 0x013f,
+0x0141, 0x0141,
+0x0143, 0x0143,
+0x0145, 0x0145,
+0x0147, 0x0147,
+0x014a, 0x014a,
+0x014c, 0x014c,
+0x014e, 0x014e,
+0x0150, 0x0150,
+0x0152, 0x0152,
+0x0154, 0x0154,
+0x0156, 0x0156,
+0x0158, 0x0158,
+0x015a, 0x015a,
+0x015c, 0x015c,
+0x015e, 0x015e,
+0x0160, 0x0160,
+0x0162, 0x0162,
+0x0164, 0x0164,
+0x0166, 0x0166,
+0x0168, 0x0168,
+0x016a, 0x016a,
+0x016c, 0x016c,
+0x016e, 0x016e,
+0x0170, 0x0170,
+0x0172, 0x0172,
+0x0174, 0x0174,
+0x0176, 0x0176,
+0x0178, 0x0179,
+0x017b, 0x017b,
+0x017d, 0x017d,
+0x0181, 0x0182,
+0x0184, 0x0184,
+0x0186, 0x0187,
+0x0189, 0x018b,
+0x018e, 0x0191,
+0x0193, 0x0194,
+0x0196, 0x0198,
+0x019c, 0x019d,
+0x019f, 0x01a0,
+0x01a2, 0x01a2,
+0x01a4, 0x01a4,
+0x01a6, 0x01a7,
+0x01a9, 0x01a9,
+0x01ac, 0x01ac,
+0x01ae, 0x01af,
+0x01b1, 0x01b3,
+0x01b5, 0x01b5,
+0x01b7, 0x01b8,
+0x01bc, 0x01bc,
+0x01c4, 0x01c4,
+0x01c7, 0x01c7,
+0x01ca, 0x01ca,
+0x01cd, 0x01cd,
+0x01cf, 0x01cf,
+0x01d1, 0x01d1,
+0x01d3, 0x01d3,
+0x01d5, 0x01d5,
+0x01d7, 0x01d7,
+0x01d9, 0x01d9,
+0x01db, 0x01db,
+0x01de, 0x01de,
+0x01e0, 0x01e0,
+0x01e2, 0x01e2,
+0x01e4, 0x01e4,
+0x01e6, 0x01e6,
+0x01e8, 0x01e8,
+0x01ea, 0x01ea,
+0x01ec, 0x01ec,
+0x01ee, 0x01ee,
+0x01f1, 0x01f1,
+0x01f4, 0x01f4,
+0x01f6, 0x01f8,
+0x01fa, 0x01fa,
+0x01fc, 0x01fc,
+0x01fe, 0x01fe,
+0x0200, 0x0200,
+0x0202, 0x0202,
+0x0204, 0x0204,
+0x0206, 0x0206,
+0x0208, 0x0208,
+0x020a, 0x020a,
+0x020c, 0x020c,
+0x020e, 0x020e,
+0x0210, 0x0210,
+0x0212, 0x0212,
+0x0214, 0x0214,
+0x0216, 0x0216,
+0x0218, 0x0218,
+0x021a, 0x021a,
+0x021c, 0x021c,
+0x021e, 0x021e,
+0x0220, 0x0220,
+0x0222, 0x0222,
+0x0224, 0x0224,
+0x0226, 0x0226,
+0x0228, 0x0228,
+0x022a, 0x022a,
+0x022c, 0x022c,
+0x022e, 0x022e,
+0x0230, 0x0230,
+0x0232, 0x0232,
+0x023a, 0x023b,
+0x023d, 0x023e,
+0x0241, 0x0241,
+0x0243, 0x0246,
+0x0248, 0x0248,
+0x024a, 0x024a,
+0x024c, 0x024c,
+0x024e, 0x024e,
+0x0370, 0x0370,
+0x0372, 0x0372,
+0x0376, 0x0376,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x038f,
+0x0391, 0x03a1,
+0x03a3, 0x03ab,
+0x03cf, 0x03cf,
+0x03d2, 0x03d4,
+0x03d8, 0x03d8,
+0x03da, 0x03da,
+0x03dc, 0x03dc,
+0x03de, 0x03de,
+0x03e0, 0x03e0,
+0x03e2, 0x03e2,
+0x03e4, 0x03e4,
+0x03e6, 0x03e6,
+0x03e8, 0x03e8,
+0x03ea, 0x03ea,
+0x03ec, 0x03ec,
+0x03ee, 0x03ee,
+0x03f4, 0x03f4,
+0x03f7, 0x03f7,
+0x03f9, 0x03fa,
+0x03fd, 0x042f,
+0x0460, 0x0460,
+0x0462, 0x0462,
+0x0464, 0x0464,
+0x0466, 0x0466,
+0x0468, 0x0468,
+0x046a, 0x046a,
+0x046c, 0x046c,
+0x046e, 0x046e,
+0x0470, 0x0470,
+0x0472, 0x0472,
+0x0474, 0x0474,
+0x0476, 0x0476,
+0x0478, 0x0478,
+0x047a, 0x047a,
+0x047c, 0x047c,
+0x047e, 0x047e,
+0x0480, 0x0480,
+0x048a, 0x048a,
+0x048c, 0x048c,
+0x048e, 0x048e,
+0x0490, 0x0490,
+0x0492, 0x0492,
+0x0494, 0x0494,
+0x0496, 0x0496,
+0x0498, 0x0498,
+0x049a, 0x049a,
+0x049c, 0x049c,
+0x049e, 0x049e,
+0x04a0, 0x04a0,
+0x04a2, 0x04a2,
+0x04a4, 0x04a4,
+0x04a6, 0x04a6,
+0x04a8, 0x04a8,
+0x04aa, 0x04aa,
+0x04ac, 0x04ac,
+0x04ae, 0x04ae,
+0x04b0, 0x04b0,
+0x04b2, 0x04b2,
+0x04b4, 0x04b4,
+0x04b6, 0x04b6,
+0x04b8, 0x04b8,
+0x04ba, 0x04ba,
+0x04bc, 0x04bc,
+0x04be, 0x04be,
+0x04c0, 0x04c1,
+0x04c3, 0x04c3,
+0x04c5, 0x04c5,
+0x04c7, 0x04c7,
+0x04c9, 0x04c9,
+0x04cb, 0x04cb,
+0x04cd, 0x04cd,
+0x04d0, 0x04d0,
+0x04d2, 0x04d2,
+0x04d4, 0x04d4,
+0x04d6, 0x04d6,
+0x04d8, 0x04d8,
+0x04da, 0x04da,
+0x04dc, 0x04dc,
+0x04de, 0x04de,
+0x04e0, 0x04e0,
+0x04e2, 0x04e2,
+0x04e4, 0x04e4,
+0x04e6, 0x04e6,
+0x04e8, 0x04e8,
+0x04ea, 0x04ea,
+0x04ec, 0x04ec,
+0x04ee, 0x04ee,
+0x04f0, 0x04f0,
+0x04f2, 0x04f2,
+0x04f4, 0x04f4,
+0x04f6, 0x04f6,
+0x04f8, 0x04f8,
+0x04fa, 0x04fa,
+0x04fc, 0x04fc,
+0x04fe, 0x04fe,
+0x0500, 0x0500,
+0x0502, 0x0502,
+0x0504, 0x0504,
+0x0506, 0x0506,
+0x0508, 0x0508,
+0x050a, 0x050a,
+0x050c, 0x050c,
+0x050e, 0x050e,
+0x0510, 0x0510,
+0x0512, 0x0512,
+0x0514, 0x0514,
+0x0516, 0x0516,
+0x0518, 0x0518,
+0x051a, 0x051a,
+0x051c, 0x051c,
+0x051e, 0x051e,
+0x0520, 0x0520,
+0x0522, 0x0522,
+0x0524, 0x0524,
+0x0526, 0x0526,
+0x0528, 0x0528,
+0x052a, 0x052a,
+0x052c, 0x052c,
+0x052e, 0x052e,
+0x0531, 0x0556,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x13a0, 0x13f5,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1e00, 0x1e00,
+0x1e02, 0x1e02,
+0x1e04, 0x1e04,
+0x1e06, 0x1e06,
+0x1e08, 0x1e08,
+0x1e0a, 0x1e0a,
+0x1e0c, 0x1e0c,
+0x1e0e, 0x1e0e,
+0x1e10, 0x1e10,
+0x1e12, 0x1e12,
+0x1e14, 0x1e14,
+0x1e16, 0x1e16,
+0x1e18, 0x1e18,
+0x1e1a, 0x1e1a,
+0x1e1c, 0x1e1c,
+0x1e1e, 0x1e1e,
+0x1e20, 0x1e20,
+0x1e22, 0x1e22,
+0x1e24, 0x1e24,
+0x1e26, 0x1e26,
+0x1e28, 0x1e28,
+0x1e2a, 0x1e2a,
+0x1e2c, 0x1e2c,
+0x1e2e, 0x1e2e,
+0x1e30, 0x1e30,
+0x1e32, 0x1e32,
+0x1e34, 0x1e34,
+0x1e36, 0x1e36,
+0x1e38, 0x1e38,
+0x1e3a, 0x1e3a,
+0x1e3c, 0x1e3c,
+0x1e3e, 0x1e3e,
+0x1e40, 0x1e40,
+0x1e42, 0x1e42,
+0x1e44, 0x1e44,
+0x1e46, 0x1e46,
+0x1e48, 0x1e48,
+0x1e4a, 0x1e4a,
+0x1e4c, 0x1e4c,
+0x1e4e, 0x1e4e,
+0x1e50, 0x1e50,
+0x1e52, 0x1e52,
+0x1e54, 0x1e54,
+0x1e56, 0x1e56,
+0x1e58, 0x1e58,
+0x1e5a, 0x1e5a,
+0x1e5c, 0x1e5c,
+0x1e5e, 0x1e5e,
+0x1e60, 0x1e60,
+0x1e62, 0x1e62,
+0x1e64, 0x1e64,
+0x1e66, 0x1e66,
+0x1e68, 0x1e68,
+0x1e6a, 0x1e6a,
+0x1e6c, 0x1e6c,
+0x1e6e, 0x1e6e,
+0x1e70, 0x1e70,
+0x1e72, 0x1e72,
+0x1e74, 0x1e74,
+0x1e76, 0x1e76,
+0x1e78, 0x1e78,
+0x1e7a, 0x1e7a,
+0x1e7c, 0x1e7c,
+0x1e7e, 0x1e7e,
+0x1e80, 0x1e80,
+0x1e82, 0x1e82,
+0x1e84, 0x1e84,
+0x1e86, 0x1e86,
+0x1e88, 0x1e88,
+0x1e8a, 0x1e8a,
+0x1e8c, 0x1e8c,
+0x1e8e, 0x1e8e,
+0x1e90, 0x1e90,
+0x1e92, 0x1e92,
+0x1e94, 0x1e94,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1ea0,
+0x1ea2, 0x1ea2,
+0x1ea4, 0x1ea4,
+0x1ea6, 0x1ea6,
+0x1ea8, 0x1ea8,
+0x1eaa, 0x1eaa,
+0x1eac, 0x1eac,
+0x1eae, 0x1eae,
+0x1eb0, 0x1eb0,
+0x1eb2, 0x1eb2,
+0x1eb4, 0x1eb4,
+0x1eb6, 0x1eb6,
+0x1eb8, 0x1eb8,
+0x1eba, 0x1eba,
+0x1ebc, 0x1ebc,
+0x1ebe, 0x1ebe,
+0x1ec0, 0x1ec0,
+0x1ec2, 0x1ec2,
+0x1ec4, 0x1ec4,
+0x1ec6, 0x1ec6,
+0x1ec8, 0x1ec8,
+0x1eca, 0x1eca,
+0x1ecc, 0x1ecc,
+0x1ece, 0x1ece,
+0x1ed0, 0x1ed0,
+0x1ed2, 0x1ed2,
+0x1ed4, 0x1ed4,
+0x1ed6, 0x1ed6,
+0x1ed8, 0x1ed8,
+0x1eda, 0x1eda,
+0x1edc, 0x1edc,
+0x1ede, 0x1ede,
+0x1ee0, 0x1ee0,
+0x1ee2, 0x1ee2,
+0x1ee4, 0x1ee4,
+0x1ee6, 0x1ee6,
+0x1ee8, 0x1ee8,
+0x1eea, 0x1eea,
+0x1eec, 0x1eec,
+0x1eee, 0x1eee,
+0x1ef0, 0x1ef0,
+0x1ef2, 0x1ef2,
+0x1ef4, 0x1ef4,
+0x1ef6, 0x1ef6,
+0x1ef8, 0x1ef8,
+0x1efa, 0x1efa,
+0x1efc, 0x1efc,
+0x1efe, 0x1efe,
+0x1f08, 0x1f0f,
+0x1f18, 0x1f1d,
+0x1f28, 0x1f2f,
+0x1f38, 0x1f3f,
+0x1f48, 0x1f4d,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f5f,
+0x1f68, 0x1f6f,
+0x1fb8, 0x1fbb,
+0x1fc8, 0x1fcb,
+0x1fd8, 0x1fdb,
+0x1fe8, 0x1fec,
+0x1ff8, 0x1ffb,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210b, 0x210d,
+0x2110, 0x2112,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x2130, 0x2133,
+0x213e, 0x213f,
+0x2145, 0x2145,
+0x2183, 0x2183,
+0x2c00, 0x2c2e,
+0x2c60, 0x2c60,
+0x2c62, 0x2c64,
+0x2c67, 0x2c67,
+0x2c69, 0x2c69,
+0x2c6b, 0x2c6b,
+0x2c6d, 0x2c70,
+0x2c72, 0x2c72,
+0x2c75, 0x2c75,
+0x2c7e, 0x2c80,
+0x2c82, 0x2c82,
+0x2c84, 0x2c84,
+0x2c86, 0x2c86,
+0x2c88, 0x2c88,
+0x2c8a, 0x2c8a,
+0x2c8c, 0x2c8c,
+0x2c8e, 0x2c8e,
+0x2c90, 0x2c90,
+0x2c92, 0x2c92,
+0x2c94, 0x2c94,
+0x2c96, 0x2c96,
+0x2c98, 0x2c98,
+0x2c9a, 0x2c9a,
+0x2c9c, 0x2c9c,
+0x2c9e, 0x2c9e,
+0x2ca0, 0x2ca0,
+0x2ca2, 0x2ca2,
+0x2ca4, 0x2ca4,
+0x2ca6, 0x2ca6,
+0x2ca8, 0x2ca8,
+0x2caa, 0x2caa,
+0x2cac, 0x2cac,
+0x2cae, 0x2cae,
+0x2cb0, 0x2cb0,
+0x2cb2, 0x2cb2,
+0x2cb4, 0x2cb4,
+0x2cb6, 0x2cb6,
+0x2cb8, 0x2cb8,
+0x2cba, 0x2cba,
+0x2cbc, 0x2cbc,
+0x2cbe, 0x2cbe,
+0x2cc0, 0x2cc0,
+0x2cc2, 0x2cc2,
+0x2cc4, 0x2cc4,
+0x2cc6, 0x2cc6,
+0x2cc8, 0x2cc8,
+0x2cca, 0x2cca,
+0x2ccc, 0x2ccc,
+0x2cce, 0x2cce,
+0x2cd0, 0x2cd0,
+0x2cd2, 0x2cd2,
+0x2cd4, 0x2cd4,
+0x2cd6, 0x2cd6,
+0x2cd8, 0x2cd8,
+0x2cda, 0x2cda,
+0x2cdc, 0x2cdc,
+0x2cde, 0x2cde,
+0x2ce0, 0x2ce0,
+0x2ce2, 0x2ce2,
+0x2ceb, 0x2ceb,
+0x2ced, 0x2ced,
+0x2cf2, 0x2cf2,
+0xa640, 0xa640,
+0xa642, 0xa642,
+0xa644, 0xa644,
+0xa646, 0xa646,
+0xa648, 0xa648,
+0xa64a, 0xa64a,
+0xa64c, 0xa64c,
+0xa64e, 0xa64e,
+0xa650, 0xa650,
+0xa652, 0xa652,
+0xa654, 0xa654,
+0xa656, 0xa656,
+0xa658, 0xa658,
+0xa65a, 0xa65a,
+0xa65c, 0xa65c,
+0xa65e, 0xa65e,
+0xa660, 0xa660,
+0xa662, 0xa662,
+0xa664, 0xa664,
+0xa666, 0xa666,
+0xa668, 0xa668,
+0xa66a, 0xa66a,
+0xa66c, 0xa66c,
+0xa680, 0xa680,
+0xa682, 0xa682,
+0xa684, 0xa684,
+0xa686, 0xa686,
+0xa688, 0xa688,
+0xa68a, 0xa68a,
+0xa68c, 0xa68c,
+0xa68e, 0xa68e,
+0xa690, 0xa690,
+0xa692, 0xa692,
+0xa694, 0xa694,
+0xa696, 0xa696,
+0xa698, 0xa698,
+0xa69a, 0xa69a,
+0xa722, 0xa722,
+0xa724, 0xa724,
+0xa726, 0xa726,
+0xa728, 0xa728,
+0xa72a, 0xa72a,
+0xa72c, 0xa72c,
+0xa72e, 0xa72e,
+0xa732, 0xa732,
+0xa734, 0xa734,
+0xa736, 0xa736,
+0xa738, 0xa738,
+0xa73a, 0xa73a,
+0xa73c, 0xa73c,
+0xa73e, 0xa73e,
+0xa740, 0xa740,
+0xa742, 0xa742,
+0xa744, 0xa744,
+0xa746, 0xa746,
+0xa748, 0xa748,
+0xa74a, 0xa74a,
+0xa74c, 0xa74c,
+0xa74e, 0xa74e,
+0xa750, 0xa750,
+0xa752, 0xa752,
+0xa754, 0xa754,
+0xa756, 0xa756,
+0xa758, 0xa758,
+0xa75a, 0xa75a,
+0xa75c, 0xa75c,
+0xa75e, 0xa75e,
+0xa760, 0xa760,
+0xa762, 0xa762,
+0xa764, 0xa764,
+0xa766, 0xa766,
+0xa768, 0xa768,
+0xa76a, 0xa76a,
+0xa76c, 0xa76c,
+0xa76e, 0xa76e,
+0xa779, 0xa779,
+0xa77b, 0xa77b,
+0xa77d, 0xa77e,
+0xa780, 0xa780,
+0xa782, 0xa782,
+0xa784, 0xa784,
+0xa786, 0xa786,
+0xa78b, 0xa78b,
+0xa78d, 0xa78d,
+0xa790, 0xa790,
+0xa792, 0xa792,
+0xa796, 0xa796,
+0xa798, 0xa798,
+0xa79a, 0xa79a,
+0xa79c, 0xa79c,
+0xa79e, 0xa79e,
+0xa7a0, 0xa7a0,
+0xa7a2, 0xa7a2,
+0xa7a4, 0xa7a4,
+0xa7a6, 0xa7a6,
+0xa7a8, 0xa7a8,
+0xa7aa, 0xa7ae,
+0xa7b0, 0xa7b4,
+0xa7b6, 0xa7b6,
+0xa7b8, 0xa7b8,
+0xa7ba, 0xa7ba,
+0xa7bc, 0xa7bc,
+0xa7be, 0xa7be,
+0xa7c2, 0xa7c2,
+0xa7c4, 0xa7c6,
+0xff21, 0xff3a,
+0x10400, 0x10427,
+0x104b0, 0x104d3,
+0x10c80, 0x10cb2,
+0x118a0, 0x118bf,
+0x16e40, 0x16e5f,
+0x1d400, 0x1d419,
+0x1d434, 0x1d44d,
+0x1d468, 0x1d481,
+0x1d49c, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b5,
+0x1d4d0, 0x1d4e9,
+0x1d504, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d538, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d56c, 0x1d585,
+0x1d5a0, 0x1d5b9,
+0x1d5d4, 0x1d5ed,
+0x1d608, 0x1d621,
+0x1d63c, 0x1d655,
+0x1d670, 0x1d689,
+0x1d6a8, 0x1d6c0,
+0x1d6e2, 0x1d6fa,
+0x1d71c, 0x1d734,
+0x1d756, 0x1d76e,
+0x1d790, 0x1d7a8,
+0x1d7ca, 0x1d7ca,
+0x1e900, 0x1e921,
+}; /* END of CR_Lu */
+
+/* PROPERTY: 'Lycian': Script */
+static const OnigCodePoint
+CR_Lycian[] = { 1,
+0x10280, 0x1029c,
+}; /* END of CR_Lycian */
+
+/* PROPERTY: 'Lydian': Script */
+static const OnigCodePoint
+CR_Lydian[] = { 2,
+0x10920, 0x10939,
+0x1093f, 0x1093f,
+}; /* END of CR_Lydian */
+
+/* PROPERTY: 'M': Major Category */
+static const OnigCodePoint
+CR_M[] = { 280,
+0x0300, 0x036f,
+0x0483, 0x0489,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x0610, 0x061a,
+0x064b, 0x065f,
+0x0670, 0x0670,
+0x06d6, 0x06dc,
+0x06df, 0x06e4,
+0x06e7, 0x06e8,
+0x06ea, 0x06ed,
+0x0711, 0x0711,
+0x0730, 0x074a,
+0x07a6, 0x07b0,
+0x07eb, 0x07f3,
+0x07fd, 0x07fd,
+0x0816, 0x0819,
+0x081b, 0x0823,
+0x0825, 0x0827,
+0x0829, 0x082d,
+0x0859, 0x085b,
+0x08d3, 0x08e1,
+0x08e3, 0x0903,
+0x093a, 0x093c,
+0x093e, 0x094f,
+0x0951, 0x0957,
+0x0962, 0x0963,
+0x0981, 0x0983,
+0x09bc, 0x09bc,
+0x09be, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cd,
+0x09d7, 0x09d7,
+0x09e2, 0x09e3,
+0x09fe, 0x09fe,
+0x0a01, 0x0a03,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a70, 0x0a71,
+0x0a75, 0x0a75,
+0x0a81, 0x0a83,
+0x0abc, 0x0abc,
+0x0abe, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ae2, 0x0ae3,
+0x0afa, 0x0aff,
+0x0b01, 0x0b03,
+0x0b3c, 0x0b3c,
+0x0b3e, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b62, 0x0b63,
+0x0b82, 0x0b82,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd7, 0x0bd7,
+0x0c00, 0x0c04,
+0x0c3e, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c62, 0x0c63,
+0x0c81, 0x0c83,
+0x0cbc, 0x0cbc,
+0x0cbe, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0ce2, 0x0ce3,
+0x0d00, 0x0d03,
+0x0d3b, 0x0d3c,
+0x0d3e, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4d,
+0x0d57, 0x0d57,
+0x0d62, 0x0d63,
+0x0d82, 0x0d83,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0df2, 0x0df3,
+0x0e31, 0x0e31,
+0x0e34, 0x0e3a,
+0x0e47, 0x0e4e,
+0x0eb1, 0x0eb1,
+0x0eb4, 0x0ebc,
+0x0ec8, 0x0ecd,
+0x0f18, 0x0f19,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f3f,
+0x0f71, 0x0f84,
+0x0f86, 0x0f87,
+0x0f8d, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x102b, 0x103e,
+0x1056, 0x1059,
+0x105e, 0x1060,
+0x1062, 0x1064,
+0x1067, 0x106d,
+0x1071, 0x1074,
+0x1082, 0x108d,
+0x108f, 0x108f,
+0x109a, 0x109d,
+0x135d, 0x135f,
+0x1712, 0x1714,
+0x1732, 0x1734,
+0x1752, 0x1753,
+0x1772, 0x1773,
+0x17b4, 0x17d3,
+0x17dd, 0x17dd,
+0x180b, 0x180d,
+0x1885, 0x1886,
+0x18a9, 0x18a9,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1a17, 0x1a1b,
+0x1a55, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a7f,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b04,
+0x1b34, 0x1b44,
+0x1b6b, 0x1b73,
+0x1b80, 0x1b82,
+0x1ba1, 0x1bad,
+0x1be6, 0x1bf3,
+0x1c24, 0x1c37,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf7, 0x1cf9,
+0x1dc0, 0x1df9,
+0x1dfb, 0x1dff,
+0x20d0, 0x20f0,
+0x2cef, 0x2cf1,
+0x2d7f, 0x2d7f,
+0x2de0, 0x2dff,
+0x302a, 0x302f,
+0x3099, 0x309a,
+0xa66f, 0xa672,
+0xa674, 0xa67d,
+0xa69e, 0xa69f,
+0xa6f0, 0xa6f1,
+0xa802, 0xa802,
+0xa806, 0xa806,
+0xa80b, 0xa80b,
+0xa823, 0xa827,
+0xa880, 0xa881,
+0xa8b4, 0xa8c5,
+0xa8e0, 0xa8f1,
+0xa8ff, 0xa8ff,
+0xa926, 0xa92d,
+0xa947, 0xa953,
+0xa980, 0xa983,
+0xa9b3, 0xa9c0,
+0xa9e5, 0xa9e5,
+0xaa29, 0xaa36,
+0xaa43, 0xaa43,
+0xaa4c, 0xaa4d,
+0xaa7b, 0xaa7d,
+0xaab0, 0xaab0,
+0xaab2, 0xaab4,
+0xaab7, 0xaab8,
+0xaabe, 0xaabf,
+0xaac1, 0xaac1,
+0xaaeb, 0xaaef,
+0xaaf5, 0xaaf6,
+0xabe3, 0xabea,
+0xabec, 0xabed,
+0xfb1e, 0xfb1e,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0x101fd, 0x101fd,
+0x102e0, 0x102e0,
+0x10376, 0x1037a,
+0x10a01, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a0f,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10ae5, 0x10ae6,
+0x10d24, 0x10d27,
+0x10f46, 0x10f50,
+0x11000, 0x11002,
+0x11038, 0x11046,
+0x1107f, 0x11082,
+0x110b0, 0x110ba,
+0x11100, 0x11102,
+0x11127, 0x11134,
+0x11145, 0x11146,
+0x11173, 0x11173,
+0x11180, 0x11182,
+0x111b3, 0x111c0,
+0x111c9, 0x111cc,
+0x1122c, 0x11237,
+0x1123e, 0x1123e,
+0x112df, 0x112ea,
+0x11300, 0x11303,
+0x1133b, 0x1133c,
+0x1133e, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11357, 0x11357,
+0x11362, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11435, 0x11446,
+0x1145e, 0x1145e,
+0x114b0, 0x114c3,
+0x115af, 0x115b5,
+0x115b8, 0x115c0,
+0x115dc, 0x115dd,
+0x11630, 0x11640,
+0x116ab, 0x116b7,
+0x1171d, 0x1172b,
+0x1182c, 0x1183a,
+0x119d1, 0x119d7,
+0x119da, 0x119e0,
+0x119e4, 0x119e4,
+0x11a01, 0x11a0a,
+0x11a33, 0x11a39,
+0x11a3b, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a51, 0x11a5b,
+0x11a8a, 0x11a99,
+0x11c2f, 0x11c36,
+0x11c38, 0x11c3f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d31, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d45,
+0x11d47, 0x11d47,
+0x11d8a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d97,
+0x11ef3, 0x11ef6,
+0x16af0, 0x16af4,
+0x16b30, 0x16b36,
+0x16f4f, 0x16f4f,
+0x16f51, 0x16f87,
+0x16f8f, 0x16f92,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e130, 0x1e136,
+0x1e2ec, 0x1e2ef,
+0x1e8d0, 0x1e8d6,
+0x1e944, 0x1e94a,
+0xe0100, 0xe01ef,
+}; /* END of CR_M */
+
+/* PROPERTY: 'Mahajani': Script */
+static const OnigCodePoint
+CR_Mahajani[] = { 1,
+0x11150, 0x11176,
+}; /* END of CR_Mahajani */
+
+/* PROPERTY: 'Makasar': Script */
+static const OnigCodePoint
+CR_Makasar[] = { 1,
+0x11ee0, 0x11ef8,
+}; /* END of CR_Makasar */
+
+/* PROPERTY: 'Malayalam': Script */
+static const OnigCodePoint
+CR_Malayalam[] = { 8,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+}; /* END of CR_Malayalam */
+
+/* PROPERTY: 'Mandaic': Script */
+static const OnigCodePoint
+CR_Mandaic[] = { 2,
+0x0840, 0x085b,
+0x085e, 0x085e,
+}; /* END of CR_Mandaic */
+
+/* PROPERTY: 'Manichaean': Script */
+static const OnigCodePoint
+CR_Manichaean[] = { 2,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+}; /* END of CR_Manichaean */
+
+/* PROPERTY: 'Marchen': Script */
+static const OnigCodePoint
+CR_Marchen[] = { 3,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+}; /* END of CR_Marchen */
+
+/* PROPERTY: 'Masaram_Gondi': Script */
+static const OnigCodePoint
+CR_Masaram_Gondi[] = { 7,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+}; /* END of CR_Masaram_Gondi */
+
+/* PROPERTY: 'Math': Derived Property */
+static const OnigCodePoint
+CR_Math[] = { 138,
+0x002b, 0x002b,
+0x003c, 0x003e,
+0x005e, 0x005e,
+0x007c, 0x007c,
+0x007e, 0x007e,
+0x00ac, 0x00ac,
+0x00b1, 0x00b1,
+0x00d7, 0x00d7,
+0x00f7, 0x00f7,
+0x03d0, 0x03d2,
+0x03d5, 0x03d5,
+0x03f0, 0x03f1,
+0x03f4, 0x03f6,
+0x0606, 0x0608,
+0x2016, 0x2016,
+0x2032, 0x2034,
+0x2040, 0x2040,
+0x2044, 0x2044,
+0x2052, 0x2052,
+0x2061, 0x2064,
+0x207a, 0x207e,
+0x208a, 0x208e,
+0x20d0, 0x20dc,
+0x20e1, 0x20e1,
+0x20e5, 0x20e6,
+0x20eb, 0x20ef,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2118, 0x211d,
+0x2124, 0x2124,
+0x2128, 0x2129,
+0x212c, 0x212d,
+0x212f, 0x2131,
+0x2133, 0x2138,
+0x213c, 0x2149,
+0x214b, 0x214b,
+0x2190, 0x21a7,
+0x21a9, 0x21ae,
+0x21b0, 0x21b1,
+0x21b6, 0x21b7,
+0x21bc, 0x21db,
+0x21dd, 0x21dd,
+0x21e4, 0x21e5,
+0x21f4, 0x22ff,
+0x2308, 0x230b,
+0x2320, 0x2321,
+0x237c, 0x237c,
+0x239b, 0x23b5,
+0x23b7, 0x23b7,
+0x23d0, 0x23d0,
+0x23dc, 0x23e2,
+0x25a0, 0x25a1,
+0x25ae, 0x25b7,
+0x25bc, 0x25c1,
+0x25c6, 0x25c7,
+0x25ca, 0x25cb,
+0x25cf, 0x25d3,
+0x25e2, 0x25e2,
+0x25e4, 0x25e4,
+0x25e7, 0x25ec,
+0x25f8, 0x25ff,
+0x2605, 0x2606,
+0x2640, 0x2640,
+0x2642, 0x2642,
+0x2660, 0x2663,
+0x266d, 0x266f,
+0x27c0, 0x27ff,
+0x2900, 0x2aff,
+0x2b30, 0x2b44,
+0x2b47, 0x2b4c,
+0xfb29, 0xfb29,
+0xfe61, 0xfe66,
+0xfe68, 0xfe68,
+0xff0b, 0xff0b,
+0xff1c, 0xff1e,
+0xff3c, 0xff3c,
+0xff3e, 0xff3e,
+0xff5c, 0xff5c,
+0xff5e, 0xff5e,
+0xffe2, 0xffe2,
+0xffe9, 0xffec,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+}; /* END of CR_Math */
+
+/* PROPERTY: 'Mc': General Category */
+static const OnigCodePoint
+CR_Mc[] = { 168,
+0x0903, 0x0903,
+0x093b, 0x093b,
+0x093e, 0x0940,
+0x0949, 0x094c,
+0x094e, 0x094f,
+0x0982, 0x0983,
+0x09be, 0x09c0,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09d7, 0x09d7,
+0x0a03, 0x0a03,
+0x0a3e, 0x0a40,
+0x0a83, 0x0a83,
+0x0abe, 0x0ac0,
+0x0ac9, 0x0ac9,
+0x0acb, 0x0acc,
+0x0b02, 0x0b03,
+0x0b3e, 0x0b3e,
+0x0b40, 0x0b40,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b57, 0x0b57,
+0x0bbe, 0x0bbf,
+0x0bc1, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd7, 0x0bd7,
+0x0c01, 0x0c03,
+0x0c41, 0x0c44,
+0x0c82, 0x0c83,
+0x0cbe, 0x0cbe,
+0x0cc0, 0x0cc4,
+0x0cc7, 0x0cc8,
+0x0cca, 0x0ccb,
+0x0cd5, 0x0cd6,
+0x0d02, 0x0d03,
+0x0d3e, 0x0d40,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d57, 0x0d57,
+0x0d82, 0x0d83,
+0x0dcf, 0x0dd1,
+0x0dd8, 0x0ddf,
+0x0df2, 0x0df3,
+0x0f3e, 0x0f3f,
+0x0f7f, 0x0f7f,
+0x102b, 0x102c,
+0x1031, 0x1031,
+0x1038, 0x1038,
+0x103b, 0x103c,
+0x1056, 0x1057,
+0x1062, 0x1064,
+0x1067, 0x106d,
+0x1083, 0x1084,
+0x1087, 0x108c,
+0x108f, 0x108f,
+0x109a, 0x109c,
+0x17b6, 0x17b6,
+0x17be, 0x17c5,
+0x17c7, 0x17c8,
+0x1923, 0x1926,
+0x1929, 0x192b,
+0x1930, 0x1931,
+0x1933, 0x1938,
+0x1a19, 0x1a1a,
+0x1a55, 0x1a55,
+0x1a57, 0x1a57,
+0x1a61, 0x1a61,
+0x1a63, 0x1a64,
+0x1a6d, 0x1a72,
+0x1b04, 0x1b04,
+0x1b35, 0x1b35,
+0x1b3b, 0x1b3b,
+0x1b3d, 0x1b41,
+0x1b43, 0x1b44,
+0x1b82, 0x1b82,
+0x1ba1, 0x1ba1,
+0x1ba6, 0x1ba7,
+0x1baa, 0x1baa,
+0x1be7, 0x1be7,
+0x1bea, 0x1bec,
+0x1bee, 0x1bee,
+0x1bf2, 0x1bf3,
+0x1c24, 0x1c2b,
+0x1c34, 0x1c35,
+0x1ce1, 0x1ce1,
+0x1cf7, 0x1cf7,
+0x302e, 0x302f,
+0xa823, 0xa824,
+0xa827, 0xa827,
+0xa880, 0xa881,
+0xa8b4, 0xa8c3,
+0xa952, 0xa953,
+0xa983, 0xa983,
+0xa9b4, 0xa9b5,
+0xa9ba, 0xa9bb,
+0xa9be, 0xa9c0,
+0xaa2f, 0xaa30,
+0xaa33, 0xaa34,
+0xaa4d, 0xaa4d,
+0xaa7b, 0xaa7b,
+0xaa7d, 0xaa7d,
+0xaaeb, 0xaaeb,
+0xaaee, 0xaaef,
+0xaaf5, 0xaaf5,
+0xabe3, 0xabe4,
+0xabe6, 0xabe7,
+0xabe9, 0xabea,
+0xabec, 0xabec,
+0x11000, 0x11000,
+0x11002, 0x11002,
+0x11082, 0x11082,
+0x110b0, 0x110b2,
+0x110b7, 0x110b8,
+0x1112c, 0x1112c,
+0x11145, 0x11146,
+0x11182, 0x11182,
+0x111b3, 0x111b5,
+0x111bf, 0x111c0,
+0x1122c, 0x1122e,
+0x11232, 0x11233,
+0x11235, 0x11235,
+0x112e0, 0x112e2,
+0x11302, 0x11303,
+0x1133e, 0x1133f,
+0x11341, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11357, 0x11357,
+0x11362, 0x11363,
+0x11435, 0x11437,
+0x11440, 0x11441,
+0x11445, 0x11445,
+0x114b0, 0x114b2,
+0x114b9, 0x114b9,
+0x114bb, 0x114be,
+0x114c1, 0x114c1,
+0x115af, 0x115b1,
+0x115b8, 0x115bb,
+0x115be, 0x115be,
+0x11630, 0x11632,
+0x1163b, 0x1163c,
+0x1163e, 0x1163e,
+0x116ac, 0x116ac,
+0x116ae, 0x116af,
+0x116b6, 0x116b6,
+0x11720, 0x11721,
+0x11726, 0x11726,
+0x1182c, 0x1182e,
+0x11838, 0x11838,
+0x119d1, 0x119d3,
+0x119dc, 0x119df,
+0x119e4, 0x119e4,
+0x11a39, 0x11a39,
+0x11a57, 0x11a58,
+0x11a97, 0x11a97,
+0x11c2f, 0x11c2f,
+0x11c3e, 0x11c3e,
+0x11ca9, 0x11ca9,
+0x11cb1, 0x11cb1,
+0x11cb4, 0x11cb4,
+0x11d8a, 0x11d8e,
+0x11d93, 0x11d94,
+0x11d96, 0x11d96,
+0x11ef5, 0x11ef6,
+0x16f51, 0x16f87,
+0x1d165, 0x1d166,
+0x1d16d, 0x1d172,
+}; /* END of CR_Mc */
+
+/* PROPERTY: 'Me': General Category */
+static const OnigCodePoint
+CR_Me[] = { 5,
+0x0488, 0x0489,
+0x1abe, 0x1abe,
+0x20dd, 0x20e0,
+0x20e2, 0x20e4,
+0xa670, 0xa672,
+}; /* END of CR_Me */
+
+/* PROPERTY: 'Medefaidrin': Script */
+static const OnigCodePoint
+CR_Medefaidrin[] = { 1,
+0x16e40, 0x16e9a,
+}; /* END of CR_Medefaidrin */
+
+/* PROPERTY: 'Meetei_Mayek': Script */
+static const OnigCodePoint
+CR_Meetei_Mayek[] = { 3,
+0xaae0, 0xaaf6,
+0xabc0, 0xabed,
+0xabf0, 0xabf9,
+}; /* END of CR_Meetei_Mayek */
+
+/* PROPERTY: 'Mende_Kikakui': Script */
+static const OnigCodePoint
+CR_Mende_Kikakui[] = { 2,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+}; /* END of CR_Mende_Kikakui */
+
+/* PROPERTY: 'Meroitic_Cursive': Script */
+static const OnigCodePoint
+CR_Meroitic_Cursive[] = { 3,
+0x109a0, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x109ff,
+}; /* END of CR_Meroitic_Cursive */
+
+/* PROPERTY: 'Meroitic_Hieroglyphs': Script */
+static const OnigCodePoint
+CR_Meroitic_Hieroglyphs[] = { 1,
+0x10980, 0x1099f,
+}; /* END of CR_Meroitic_Hieroglyphs */
+
+/* PROPERTY: 'Miao': Script */
+static const OnigCodePoint
+CR_Miao[] = { 3,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+}; /* END of CR_Miao */
+
+/* PROPERTY: 'Mn': General Category */
+static const OnigCodePoint
+CR_Mn[] = { 318,
+0x0300, 0x036f,
+0x0483, 0x0487,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x0610, 0x061a,
+0x064b, 0x065f,
+0x0670, 0x0670,
+0x06d6, 0x06dc,
+0x06df, 0x06e4,
+0x06e7, 0x06e8,
+0x06ea, 0x06ed,
+0x0711, 0x0711,
+0x0730, 0x074a,
+0x07a6, 0x07b0,
+0x07eb, 0x07f3,
+0x07fd, 0x07fd,
+0x0816, 0x0819,
+0x081b, 0x0823,
+0x0825, 0x0827,
+0x0829, 0x082d,
+0x0859, 0x085b,
+0x08d3, 0x08e1,
+0x08e3, 0x0902,
+0x093a, 0x093a,
+0x093c, 0x093c,
+0x0941, 0x0948,
+0x094d, 0x094d,
+0x0951, 0x0957,
+0x0962, 0x0963,
+0x0981, 0x0981,
+0x09bc, 0x09bc,
+0x09c1, 0x09c4,
+0x09cd, 0x09cd,
+0x09e2, 0x09e3,
+0x09fe, 0x09fe,
+0x0a01, 0x0a02,
+0x0a3c, 0x0a3c,
+0x0a41, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a70, 0x0a71,
+0x0a75, 0x0a75,
+0x0a81, 0x0a82,
+0x0abc, 0x0abc,
+0x0ac1, 0x0ac5,
+0x0ac7, 0x0ac8,
+0x0acd, 0x0acd,
+0x0ae2, 0x0ae3,
+0x0afa, 0x0aff,
+0x0b01, 0x0b01,
+0x0b3c, 0x0b3c,
+0x0b3f, 0x0b3f,
+0x0b41, 0x0b44,
+0x0b4d, 0x0b4d,
+0x0b56, 0x0b56,
+0x0b62, 0x0b63,
+0x0b82, 0x0b82,
+0x0bc0, 0x0bc0,
+0x0bcd, 0x0bcd,
+0x0c00, 0x0c00,
+0x0c04, 0x0c04,
+0x0c3e, 0x0c40,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c62, 0x0c63,
+0x0c81, 0x0c81,
+0x0cbc, 0x0cbc,
+0x0cbf, 0x0cbf,
+0x0cc6, 0x0cc6,
+0x0ccc, 0x0ccd,
+0x0ce2, 0x0ce3,
+0x0d00, 0x0d01,
+0x0d3b, 0x0d3c,
+0x0d41, 0x0d44,
+0x0d4d, 0x0d4d,
+0x0d62, 0x0d63,
+0x0dca, 0x0dca,
+0x0dd2, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0e31, 0x0e31,
+0x0e34, 0x0e3a,
+0x0e47, 0x0e4e,
+0x0eb1, 0x0eb1,
+0x0eb4, 0x0ebc,
+0x0ec8, 0x0ecd,
+0x0f18, 0x0f19,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f71, 0x0f7e,
+0x0f80, 0x0f84,
+0x0f86, 0x0f87,
+0x0f8d, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x102d, 0x1030,
+0x1032, 0x1037,
+0x1039, 0x103a,
+0x103d, 0x103e,
+0x1058, 0x1059,
+0x105e, 0x1060,
+0x1071, 0x1074,
+0x1082, 0x1082,
+0x1085, 0x1086,
+0x108d, 0x108d,
+0x109d, 0x109d,
+0x135d, 0x135f,
+0x1712, 0x1714,
+0x1732, 0x1734,
+0x1752, 0x1753,
+0x1772, 0x1773,
+0x17b4, 0x17b5,
+0x17b7, 0x17bd,
+0x17c6, 0x17c6,
+0x17c9, 0x17d3,
+0x17dd, 0x17dd,
+0x180b, 0x180d,
+0x1885, 0x1886,
+0x18a9, 0x18a9,
+0x1920, 0x1922,
+0x1927, 0x1928,
+0x1932, 0x1932,
+0x1939, 0x193b,
+0x1a17, 0x1a18,
+0x1a1b, 0x1a1b,
+0x1a56, 0x1a56,
+0x1a58, 0x1a5e,
+0x1a60, 0x1a60,
+0x1a62, 0x1a62,
+0x1a65, 0x1a6c,
+0x1a73, 0x1a7c,
+0x1a7f, 0x1a7f,
+0x1ab0, 0x1abd,
+0x1b00, 0x1b03,
+0x1b34, 0x1b34,
+0x1b36, 0x1b3a,
+0x1b3c, 0x1b3c,
+0x1b42, 0x1b42,
+0x1b6b, 0x1b73,
+0x1b80, 0x1b81,
+0x1ba2, 0x1ba5,
+0x1ba8, 0x1ba9,
+0x1bab, 0x1bad,
+0x1be6, 0x1be6,
+0x1be8, 0x1be9,
+0x1bed, 0x1bed,
+0x1bef, 0x1bf1,
+0x1c2c, 0x1c33,
+0x1c36, 0x1c37,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1ce0,
+0x1ce2, 0x1ce8,
+0x1ced, 0x1ced,
+0x1cf4, 0x1cf4,
+0x1cf8, 0x1cf9,
+0x1dc0, 0x1df9,
+0x1dfb, 0x1dff,
+0x20d0, 0x20dc,
+0x20e1, 0x20e1,
+0x20e5, 0x20f0,
+0x2cef, 0x2cf1,
+0x2d7f, 0x2d7f,
+0x2de0, 0x2dff,
+0x302a, 0x302d,
+0x3099, 0x309a,
+0xa66f, 0xa66f,
+0xa674, 0xa67d,
+0xa69e, 0xa69f,
+0xa6f0, 0xa6f1,
+0xa802, 0xa802,
+0xa806, 0xa806,
+0xa80b, 0xa80b,
+0xa825, 0xa826,
+0xa8c4, 0xa8c5,
+0xa8e0, 0xa8f1,
+0xa8ff, 0xa8ff,
+0xa926, 0xa92d,
+0xa947, 0xa951,
+0xa980, 0xa982,
+0xa9b3, 0xa9b3,
+0xa9b6, 0xa9b9,
+0xa9bc, 0xa9bd,
+0xa9e5, 0xa9e5,
+0xaa29, 0xaa2e,
+0xaa31, 0xaa32,
+0xaa35, 0xaa36,
+0xaa43, 0xaa43,
+0xaa4c, 0xaa4c,
+0xaa7c, 0xaa7c,
+0xaab0, 0xaab0,
+0xaab2, 0xaab4,
+0xaab7, 0xaab8,
+0xaabe, 0xaabf,
+0xaac1, 0xaac1,
+0xaaec, 0xaaed,
+0xaaf6, 0xaaf6,
+0xabe5, 0xabe5,
+0xabe8, 0xabe8,
+0xabed, 0xabed,
+0xfb1e, 0xfb1e,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0x101fd, 0x101fd,
+0x102e0, 0x102e0,
+0x10376, 0x1037a,
+0x10a01, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a0f,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10ae5, 0x10ae6,
+0x10d24, 0x10d27,
+0x10f46, 0x10f50,
+0x11001, 0x11001,
+0x11038, 0x11046,
+0x1107f, 0x11081,
+0x110b3, 0x110b6,
+0x110b9, 0x110ba,
+0x11100, 0x11102,
+0x11127, 0x1112b,
+0x1112d, 0x11134,
+0x11173, 0x11173,
+0x11180, 0x11181,
+0x111b6, 0x111be,
+0x111c9, 0x111cc,
+0x1122f, 0x11231,
+0x11234, 0x11234,
+0x11236, 0x11237,
+0x1123e, 0x1123e,
+0x112df, 0x112df,
+0x112e3, 0x112ea,
+0x11300, 0x11301,
+0x1133b, 0x1133c,
+0x11340, 0x11340,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11438, 0x1143f,
+0x11442, 0x11444,
+0x11446, 0x11446,
+0x1145e, 0x1145e,
+0x114b3, 0x114b8,
+0x114ba, 0x114ba,
+0x114bf, 0x114c0,
+0x114c2, 0x114c3,
+0x115b2, 0x115b5,
+0x115bc, 0x115bd,
+0x115bf, 0x115c0,
+0x115dc, 0x115dd,
+0x11633, 0x1163a,
+0x1163d, 0x1163d,
+0x1163f, 0x11640,
+0x116ab, 0x116ab,
+0x116ad, 0x116ad,
+0x116b0, 0x116b5,
+0x116b7, 0x116b7,
+0x1171d, 0x1171f,
+0x11722, 0x11725,
+0x11727, 0x1172b,
+0x1182f, 0x11837,
+0x11839, 0x1183a,
+0x119d4, 0x119d7,
+0x119da, 0x119db,
+0x119e0, 0x119e0,
+0x11a01, 0x11a0a,
+0x11a33, 0x11a38,
+0x11a3b, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a51, 0x11a56,
+0x11a59, 0x11a5b,
+0x11a8a, 0x11a96,
+0x11a98, 0x11a99,
+0x11c30, 0x11c36,
+0x11c38, 0x11c3d,
+0x11c3f, 0x11c3f,
+0x11c92, 0x11ca7,
+0x11caa, 0x11cb0,
+0x11cb2, 0x11cb3,
+0x11cb5, 0x11cb6,
+0x11d31, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d45,
+0x11d47, 0x11d47,
+0x11d90, 0x11d91,
+0x11d95, 0x11d95,
+0x11d97, 0x11d97,
+0x11ef3, 0x11ef4,
+0x16af0, 0x16af4,
+0x16b30, 0x16b36,
+0x16f4f, 0x16f4f,
+0x16f8f, 0x16f92,
+0x1bc9d, 0x1bc9e,
+0x1d167, 0x1d169,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e130, 0x1e136,
+0x1e2ec, 0x1e2ef,
+0x1e8d0, 0x1e8d6,
+0x1e944, 0x1e94a,
+0xe0100, 0xe01ef,
+}; /* END of CR_Mn */
+
+/* PROPERTY: 'Modi': Script */
+static const OnigCodePoint
+CR_Modi[] = { 2,
+0x11600, 0x11644,
+0x11650, 0x11659,
+}; /* END of CR_Modi */
+
+/* PROPERTY: 'Mongolian': Script */
+static const OnigCodePoint
+CR_Mongolian[] = { 7,
+0x1800, 0x1801,
+0x1804, 0x1804,
+0x1806, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x11660, 0x1166c,
+}; /* END of CR_Mongolian */
+
+/* PROPERTY: 'Mro': Script */
+static const OnigCodePoint
+CR_Mro[] = { 3,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+}; /* END of CR_Mro */
+
+/* PROPERTY: 'Multani': Script */
+static const OnigCodePoint
+CR_Multani[] = { 5,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+}; /* END of CR_Multani */
+
+/* PROPERTY: 'Myanmar': Script */
+static const OnigCodePoint
+CR_Myanmar[] = { 3,
+0x1000, 0x109f,
+0xa9e0, 0xa9fe,
+0xaa60, 0xaa7f,
+}; /* END of CR_Myanmar */
+
+/* PROPERTY: 'N': Major Category */
+static const OnigCodePoint
+CR_N[] = { 130,
+0x0030, 0x0039,
+0x00b2, 0x00b3,
+0x00b9, 0x00b9,
+0x00bc, 0x00be,
+0x0660, 0x0669,
+0x06f0, 0x06f9,
+0x07c0, 0x07c9,
+0x0966, 0x096f,
+0x09e6, 0x09ef,
+0x09f4, 0x09f9,
+0x0a66, 0x0a6f,
+0x0ae6, 0x0aef,
+0x0b66, 0x0b6f,
+0x0b72, 0x0b77,
+0x0be6, 0x0bf2,
+0x0c66, 0x0c6f,
+0x0c78, 0x0c7e,
+0x0ce6, 0x0cef,
+0x0d58, 0x0d5e,
+0x0d66, 0x0d78,
+0x0de6, 0x0def,
+0x0e50, 0x0e59,
+0x0ed0, 0x0ed9,
+0x0f20, 0x0f33,
+0x1040, 0x1049,
+0x1090, 0x1099,
+0x1369, 0x137c,
+0x16ee, 0x16f0,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1810, 0x1819,
+0x1946, 0x194f,
+0x19d0, 0x19da,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1b50, 0x1b59,
+0x1bb0, 0x1bb9,
+0x1c40, 0x1c49,
+0x1c50, 0x1c59,
+0x2070, 0x2070,
+0x2074, 0x2079,
+0x2080, 0x2089,
+0x2150, 0x2182,
+0x2185, 0x2189,
+0x2460, 0x249b,
+0x24ea, 0x24ff,
+0x2776, 0x2793,
+0x2cfd, 0x2cfd,
+0x3007, 0x3007,
+0x3021, 0x3029,
+0x3038, 0x303a,
+0x3192, 0x3195,
+0x3220, 0x3229,
+0x3248, 0x324f,
+0x3251, 0x325f,
+0x3280, 0x3289,
+0x32b1, 0x32bf,
+0xa620, 0xa629,
+0xa6e6, 0xa6ef,
+0xa830, 0xa835,
+0xa8d0, 0xa8d9,
+0xa900, 0xa909,
+0xa9d0, 0xa9d9,
+0xa9f0, 0xa9f9,
+0xaa50, 0xaa59,
+0xabf0, 0xabf9,
+0xff10, 0xff19,
+0x10107, 0x10133,
+0x10140, 0x10178,
+0x1018a, 0x1018b,
+0x102e1, 0x102fb,
+0x10320, 0x10323,
+0x10341, 0x10341,
+0x1034a, 0x1034a,
+0x103d1, 0x103d5,
+0x104a0, 0x104a9,
+0x10858, 0x1085f,
+0x10879, 0x1087f,
+0x108a7, 0x108af,
+0x108fb, 0x108ff,
+0x10916, 0x1091b,
+0x109bc, 0x109bd,
+0x109c0, 0x109cf,
+0x109d2, 0x109ff,
+0x10a40, 0x10a48,
+0x10a7d, 0x10a7e,
+0x10a9d, 0x10a9f,
+0x10aeb, 0x10aef,
+0x10b58, 0x10b5f,
+0x10b78, 0x10b7f,
+0x10ba9, 0x10baf,
+0x10cfa, 0x10cff,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f1d, 0x10f26,
+0x10f51, 0x10f54,
+0x11052, 0x1106f,
+0x110f0, 0x110f9,
+0x11136, 0x1113f,
+0x111d0, 0x111d9,
+0x111e1, 0x111f4,
+0x112f0, 0x112f9,
+0x11450, 0x11459,
+0x114d0, 0x114d9,
+0x11650, 0x11659,
+0x116c0, 0x116c9,
+0x11730, 0x1173b,
+0x118e0, 0x118f2,
+0x11c50, 0x11c6c,
+0x11d50, 0x11d59,
+0x11da0, 0x11da9,
+0x11fc0, 0x11fd4,
+0x12400, 0x1246e,
+0x16a60, 0x16a69,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16e80, 0x16e96,
+0x1d2e0, 0x1d2f3,
+0x1d360, 0x1d378,
+0x1d7ce, 0x1d7ff,
+0x1e140, 0x1e149,
+0x1e2f0, 0x1e2f9,
+0x1e8c7, 0x1e8cf,
+0x1e950, 0x1e959,
+0x1ec71, 0x1ecab,
+0x1ecad, 0x1ecaf,
+0x1ecb1, 0x1ecb4,
+0x1ed01, 0x1ed2d,
+0x1ed2f, 0x1ed3d,
+0x1f100, 0x1f10c,
+}; /* END of CR_N */
+
+/* PROPERTY: 'Nabataean': Script */
+static const OnigCodePoint
+CR_Nabataean[] = { 2,
+0x10880, 0x1089e,
+0x108a7, 0x108af,
+}; /* END of CR_Nabataean */
+
+/* PROPERTY: 'Nandinagari': Script */
+static const OnigCodePoint
+CR_Nandinagari[] = { 3,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+}; /* END of CR_Nandinagari */
+
+/* PROPERTY: 'Nd': General Category */
+#define CR_Nd CR_Digit
+
+/* PROPERTY: 'New_Tai_Lue': Script */
+static const OnigCodePoint
+CR_New_Tai_Lue[] = { 4,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x19df,
+}; /* END of CR_New_Tai_Lue */
+
+/* PROPERTY: 'Newa': Script */
+static const OnigCodePoint
+CR_Newa[] = { 3,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+}; /* END of CR_Newa */
+
+/* PROPERTY: 'Nko': Script */
+static const OnigCodePoint
+CR_Nko[] = { 2,
+0x07c0, 0x07fa,
+0x07fd, 0x07ff,
+}; /* END of CR_Nko */
+
+/* PROPERTY: 'Nl': General Category */
+static const OnigCodePoint
+CR_Nl[] = { 12,
+0x16ee, 0x16f0,
+0x2160, 0x2182,
+0x2185, 0x2188,
+0x3007, 0x3007,
+0x3021, 0x3029,
+0x3038, 0x303a,
+0xa6e6, 0xa6ef,
+0x10140, 0x10174,
+0x10341, 0x10341,
+0x1034a, 0x1034a,
+0x103d1, 0x103d5,
+0x12400, 0x1246e,
+}; /* END of CR_Nl */
+
+/* PROPERTY: 'No': General Category */
+static const OnigCodePoint
+CR_No[] = { 70,
+0x00b2, 0x00b3,
+0x00b9, 0x00b9,
+0x00bc, 0x00be,
+0x09f4, 0x09f9,
+0x0b72, 0x0b77,
+0x0bf0, 0x0bf2,
+0x0c78, 0x0c7e,
+0x0d58, 0x0d5e,
+0x0d70, 0x0d78,
+0x0f2a, 0x0f33,
+0x1369, 0x137c,
+0x17f0, 0x17f9,
+0x19da, 0x19da,
+0x2070, 0x2070,
+0x2074, 0x2079,
+0x2080, 0x2089,
+0x2150, 0x215f,
+0x2189, 0x2189,
+0x2460, 0x249b,
+0x24ea, 0x24ff,
+0x2776, 0x2793,
+0x2cfd, 0x2cfd,
+0x3192, 0x3195,
+0x3220, 0x3229,
+0x3248, 0x324f,
+0x3251, 0x325f,
+0x3280, 0x3289,
+0x32b1, 0x32bf,
+0xa830, 0xa835,
+0x10107, 0x10133,
+0x10175, 0x10178,
+0x1018a, 0x1018b,
+0x102e1, 0x102fb,
+0x10320, 0x10323,
+0x10858, 0x1085f,
+0x10879, 0x1087f,
+0x108a7, 0x108af,
+0x108fb, 0x108ff,
+0x10916, 0x1091b,
+0x109bc, 0x109bd,
+0x109c0, 0x109cf,
+0x109d2, 0x109ff,
+0x10a40, 0x10a48,
+0x10a7d, 0x10a7e,
+0x10a9d, 0x10a9f,
+0x10aeb, 0x10aef,
+0x10b58, 0x10b5f,
+0x10b78, 0x10b7f,
+0x10ba9, 0x10baf,
+0x10cfa, 0x10cff,
+0x10e60, 0x10e7e,
+0x10f1d, 0x10f26,
+0x10f51, 0x10f54,
+0x11052, 0x11065,
+0x111e1, 0x111f4,
+0x1173a, 0x1173b,
+0x118ea, 0x118f2,
+0x11c5a, 0x11c6c,
+0x11fc0, 0x11fd4,
+0x16b5b, 0x16b61,
+0x16e80, 0x16e96,
+0x1d2e0, 0x1d2f3,
+0x1d360, 0x1d378,
+0x1e8c7, 0x1e8cf,
+0x1ec71, 0x1ecab,
+0x1ecad, 0x1ecaf,
+0x1ecb1, 0x1ecb4,
+0x1ed01, 0x1ed2d,
+0x1ed2f, 0x1ed3d,
+0x1f100, 0x1f10c,
+}; /* END of CR_No */
+
+/* PROPERTY: 'Noncharacter_Code_Point': Binary Property */
+static const OnigCodePoint
+CR_Noncharacter_Code_Point[] = { 18,
+0xfdd0, 0xfdef,
+0xfffe, 0xffff,
+0x1fffe, 0x1ffff,
+0x2fffe, 0x2ffff,
+0x3fffe, 0x3ffff,
+0x4fffe, 0x4ffff,
+0x5fffe, 0x5ffff,
+0x6fffe, 0x6ffff,
+0x7fffe, 0x7ffff,
+0x8fffe, 0x8ffff,
+0x9fffe, 0x9ffff,
+0xafffe, 0xaffff,
+0xbfffe, 0xbffff,
+0xcfffe, 0xcffff,
+0xdfffe, 0xdffff,
+0xefffe, 0xeffff,
+0xffffe, 0xfffff,
+0x10fffe, 0x10ffff,
+}; /* END of CR_Noncharacter_Code_Point */
+
+/* PROPERTY: 'Nushu': Script */
+static const OnigCodePoint
+CR_Nushu[] = { 2,
+0x16fe1, 0x16fe1,
+0x1b170, 0x1b2fb,
+}; /* END of CR_Nushu */
+
+/* PROPERTY: 'Nyiakeng_Puachue_Hmong': Script */
+static const OnigCodePoint
+CR_Nyiakeng_Puachue_Hmong[] = { 4,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+}; /* END of CR_Nyiakeng_Puachue_Hmong */
+
+/* PROPERTY: 'Ogham': Script */
+static const OnigCodePoint
+CR_Ogham[] = { 1,
+0x1680, 0x169c,
+}; /* END of CR_Ogham */
+
+/* PROPERTY: 'Ol_Chiki': Script */
+static const OnigCodePoint
+CR_Ol_Chiki[] = { 1,
+0x1c50, 0x1c7f,
+}; /* END of CR_Ol_Chiki */
+
+/* PROPERTY: 'Old_Hungarian': Script */
+static const OnigCodePoint
+CR_Old_Hungarian[] = { 3,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10cff,
+}; /* END of CR_Old_Hungarian */
+
+/* PROPERTY: 'Old_Italic': Script */
+static const OnigCodePoint
+CR_Old_Italic[] = { 2,
+0x10300, 0x10323,
+0x1032d, 0x1032f,
+}; /* END of CR_Old_Italic */
+
+/* PROPERTY: 'Old_North_Arabian': Script */
+static const OnigCodePoint
+CR_Old_North_Arabian[] = { 1,
+0x10a80, 0x10a9f,
+}; /* END of CR_Old_North_Arabian */
+
+/* PROPERTY: 'Old_Permic': Script */
+static const OnigCodePoint
+CR_Old_Permic[] = { 1,
+0x10350, 0x1037a,
+}; /* END of CR_Old_Permic */
+
+/* PROPERTY: 'Old_Persian': Script */
+static const OnigCodePoint
+CR_Old_Persian[] = { 2,
+0x103a0, 0x103c3,
+0x103c8, 0x103d5,
+}; /* END of CR_Old_Persian */
+
+/* PROPERTY: 'Old_Sogdian': Script */
+static const OnigCodePoint
+CR_Old_Sogdian[] = { 1,
+0x10f00, 0x10f27,
+}; /* END of CR_Old_Sogdian */
+
+/* PROPERTY: 'Old_South_Arabian': Script */
+static const OnigCodePoint
+CR_Old_South_Arabian[] = { 1,
+0x10a60, 0x10a7f,
+}; /* END of CR_Old_South_Arabian */
+
+/* PROPERTY: 'Old_Turkic': Script */
+static const OnigCodePoint
+CR_Old_Turkic[] = { 1,
+0x10c00, 0x10c48,
+}; /* END of CR_Old_Turkic */
+
+/* PROPERTY: 'Oriya': Script */
+static const OnigCodePoint
+CR_Oriya[] = { 14,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+}; /* END of CR_Oriya */
+
+/* PROPERTY: 'Osage': Script */
+static const OnigCodePoint
+CR_Osage[] = { 2,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+}; /* END of CR_Osage */
+
+/* PROPERTY: 'Osmanya': Script */
+static const OnigCodePoint
+CR_Osmanya[] = { 2,
+0x10480, 0x1049d,
+0x104a0, 0x104a9,
+}; /* END of CR_Osmanya */
+
+/* PROPERTY: 'Other_Alphabetic': Binary Property */
+static const OnigCodePoint
+CR_Other_Alphabetic[] = { 221,
+0x0345, 0x0345,
+0x05b0, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x0610, 0x061a,
+0x064b, 0x0657,
+0x0659, 0x065f,
+0x0670, 0x0670,
+0x06d6, 0x06dc,
+0x06e1, 0x06e4,
+0x06e7, 0x06e8,
+0x06ed, 0x06ed,
+0x0711, 0x0711,
+0x0730, 0x073f,
+0x07a6, 0x07b0,
+0x0816, 0x0817,
+0x081b, 0x0823,
+0x0825, 0x0827,
+0x0829, 0x082c,
+0x08d4, 0x08df,
+0x08e3, 0x08e9,
+0x08f0, 0x0903,
+0x093a, 0x093b,
+0x093e, 0x094c,
+0x094e, 0x094f,
+0x0955, 0x0957,
+0x0962, 0x0963,
+0x0981, 0x0983,
+0x09be, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09d7, 0x09d7,
+0x09e2, 0x09e3,
+0x0a01, 0x0a03,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4c,
+0x0a51, 0x0a51,
+0x0a70, 0x0a71,
+0x0a75, 0x0a75,
+0x0a81, 0x0a83,
+0x0abe, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ae2, 0x0ae3,
+0x0afa, 0x0afc,
+0x0b01, 0x0b03,
+0x0b3e, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b56, 0x0b57,
+0x0b62, 0x0b63,
+0x0b82, 0x0b82,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd7, 0x0bd7,
+0x0c00, 0x0c03,
+0x0c3e, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4c,
+0x0c55, 0x0c56,
+0x0c62, 0x0c63,
+0x0c81, 0x0c83,
+0x0cbe, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccc,
+0x0cd5, 0x0cd6,
+0x0ce2, 0x0ce3,
+0x0d00, 0x0d03,
+0x0d3e, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d57, 0x0d57,
+0x0d62, 0x0d63,
+0x0d82, 0x0d83,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0df2, 0x0df3,
+0x0e31, 0x0e31,
+0x0e34, 0x0e3a,
+0x0e4d, 0x0e4d,
+0x0eb1, 0x0eb1,
+0x0eb4, 0x0eb9,
+0x0ebb, 0x0ebc,
+0x0ecd, 0x0ecd,
+0x0f71, 0x0f81,
+0x0f8d, 0x0f97,
+0x0f99, 0x0fbc,
+0x102b, 0x1036,
+0x1038, 0x1038,
+0x103b, 0x103e,
+0x1056, 0x1059,
+0x105e, 0x1060,
+0x1062, 0x1064,
+0x1067, 0x106d,
+0x1071, 0x1074,
+0x1082, 0x108d,
+0x108f, 0x108f,
+0x109a, 0x109d,
+0x1712, 0x1713,
+0x1732, 0x1733,
+0x1752, 0x1753,
+0x1772, 0x1773,
+0x17b6, 0x17c8,
+0x1885, 0x1886,
+0x18a9, 0x18a9,
+0x1920, 0x192b,
+0x1930, 0x1938,
+0x1a17, 0x1a1b,
+0x1a55, 0x1a5e,
+0x1a61, 0x1a74,
+0x1b00, 0x1b04,
+0x1b35, 0x1b43,
+0x1b80, 0x1b82,
+0x1ba1, 0x1ba9,
+0x1bac, 0x1bad,
+0x1be7, 0x1bf1,
+0x1c24, 0x1c36,
+0x1de7, 0x1df4,
+0x24b6, 0x24e9,
+0x2de0, 0x2dff,
+0xa674, 0xa67b,
+0xa69e, 0xa69f,
+0xa802, 0xa802,
+0xa80b, 0xa80b,
+0xa823, 0xa827,
+0xa880, 0xa881,
+0xa8b4, 0xa8c3,
+0xa8c5, 0xa8c5,
+0xa8ff, 0xa8ff,
+0xa926, 0xa92a,
+0xa947, 0xa952,
+0xa980, 0xa983,
+0xa9b4, 0xa9bf,
+0xa9e5, 0xa9e5,
+0xaa29, 0xaa36,
+0xaa43, 0xaa43,
+0xaa4c, 0xaa4d,
+0xaa7b, 0xaa7d,
+0xaab0, 0xaab0,
+0xaab2, 0xaab4,
+0xaab7, 0xaab8,
+0xaabe, 0xaabe,
+0xaaeb, 0xaaef,
+0xaaf5, 0xaaf5,
+0xabe3, 0xabea,
+0xfb1e, 0xfb1e,
+0x10376, 0x1037a,
+0x10a01, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a0f,
+0x10d24, 0x10d27,
+0x11000, 0x11002,
+0x11038, 0x11045,
+0x11082, 0x11082,
+0x110b0, 0x110b8,
+0x11100, 0x11102,
+0x11127, 0x11132,
+0x11145, 0x11146,
+0x11180, 0x11182,
+0x111b3, 0x111bf,
+0x1122c, 0x11234,
+0x11237, 0x11237,
+0x1123e, 0x1123e,
+0x112df, 0x112e8,
+0x11300, 0x11303,
+0x1133e, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134c,
+0x11357, 0x11357,
+0x11362, 0x11363,
+0x11435, 0x11441,
+0x11443, 0x11445,
+0x114b0, 0x114c1,
+0x115af, 0x115b5,
+0x115b8, 0x115be,
+0x115dc, 0x115dd,
+0x11630, 0x1163e,
+0x11640, 0x11640,
+0x116ab, 0x116b5,
+0x1171d, 0x1172a,
+0x1182c, 0x11838,
+0x119d1, 0x119d7,
+0x119da, 0x119df,
+0x119e4, 0x119e4,
+0x11a01, 0x11a0a,
+0x11a35, 0x11a39,
+0x11a3b, 0x11a3e,
+0x11a51, 0x11a5b,
+0x11a8a, 0x11a97,
+0x11c2f, 0x11c36,
+0x11c38, 0x11c3e,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d31, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d41,
+0x11d43, 0x11d43,
+0x11d47, 0x11d47,
+0x11d8a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d96,
+0x11ef3, 0x11ef6,
+0x16f4f, 0x16f4f,
+0x16f51, 0x16f87,
+0x16f8f, 0x16f92,
+0x1bc9e, 0x1bc9e,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e947, 0x1e947,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+}; /* END of CR_Other_Alphabetic */
+
+/* PROPERTY: 'Other_Default_Ignorable_Code_Point': Binary Property */
+static const OnigCodePoint
+CR_Other_Default_Ignorable_Code_Point[] = { 11,
+0x034f, 0x034f,
+0x115f, 0x1160,
+0x17b4, 0x17b5,
+0x2065, 0x2065,
+0x3164, 0x3164,
+0xffa0, 0xffa0,
+0xfff0, 0xfff8,
+0xe0000, 0xe0000,
+0xe0002, 0xe001f,
+0xe0080, 0xe00ff,
+0xe01f0, 0xe0fff,
+}; /* END of CR_Other_Default_Ignorable_Code_Point */
+
+/* PROPERTY: 'Other_Grapheme_Extend': Binary Property */
+static const OnigCodePoint
+CR_Other_Grapheme_Extend[] = { 24,
+0x09be, 0x09be,
+0x09d7, 0x09d7,
+0x0b3e, 0x0b3e,
+0x0b57, 0x0b57,
+0x0bbe, 0x0bbe,
+0x0bd7, 0x0bd7,
+0x0cc2, 0x0cc2,
+0x0cd5, 0x0cd6,
+0x0d3e, 0x0d3e,
+0x0d57, 0x0d57,
+0x0dcf, 0x0dcf,
+0x0ddf, 0x0ddf,
+0x1b35, 0x1b35,
+0x200c, 0x200c,
+0x302e, 0x302f,
+0xff9e, 0xff9f,
+0x1133e, 0x1133e,
+0x11357, 0x11357,
+0x114b0, 0x114b0,
+0x114bd, 0x114bd,
+0x115af, 0x115af,
+0x1d165, 0x1d165,
+0x1d16e, 0x1d172,
+0xe0020, 0xe007f,
+}; /* END of CR_Other_Grapheme_Extend */
+
+/* PROPERTY: 'Other_ID_Continue': Binary Property */
+static const OnigCodePoint
+CR_Other_ID_Continue[] = { 4,
+0x00b7, 0x00b7,
+0x0387, 0x0387,
+0x1369, 0x1371,
+0x19da, 0x19da,
+}; /* END of CR_Other_ID_Continue */
+
+/* PROPERTY: 'Other_ID_Start': Binary Property */
+static const OnigCodePoint
+CR_Other_ID_Start[] = { 4,
+0x1885, 0x1886,
+0x2118, 0x2118,
+0x212e, 0x212e,
+0x309b, 0x309c,
+}; /* END of CR_Other_ID_Start */
+
+/* PROPERTY: 'Other_Lowercase': Binary Property */
+static const OnigCodePoint
+CR_Other_Lowercase[] = { 20,
+0x00aa, 0x00aa,
+0x00ba, 0x00ba,
+0x02b0, 0x02b8,
+0x02c0, 0x02c1,
+0x02e0, 0x02e4,
+0x0345, 0x0345,
+0x037a, 0x037a,
+0x1d2c, 0x1d6a,
+0x1d78, 0x1d78,
+0x1d9b, 0x1dbf,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2170, 0x217f,
+0x24d0, 0x24e9,
+0x2c7c, 0x2c7d,
+0xa69c, 0xa69d,
+0xa770, 0xa770,
+0xa7f8, 0xa7f9,
+0xab5c, 0xab5f,
+}; /* END of CR_Other_Lowercase */
+
+/* PROPERTY: 'Other_Math': Binary Property */
+static const OnigCodePoint
+CR_Other_Math[] = { 134,
+0x005e, 0x005e,
+0x03d0, 0x03d2,
+0x03d5, 0x03d5,
+0x03f0, 0x03f1,
+0x03f4, 0x03f5,
+0x2016, 0x2016,
+0x2032, 0x2034,
+0x2040, 0x2040,
+0x2061, 0x2064,
+0x207d, 0x207e,
+0x208d, 0x208e,
+0x20d0, 0x20dc,
+0x20e1, 0x20e1,
+0x20e5, 0x20e6,
+0x20eb, 0x20ef,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2128, 0x2129,
+0x212c, 0x212d,
+0x212f, 0x2131,
+0x2133, 0x2138,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x2195, 0x2199,
+0x219c, 0x219f,
+0x21a1, 0x21a2,
+0x21a4, 0x21a5,
+0x21a7, 0x21a7,
+0x21a9, 0x21ad,
+0x21b0, 0x21b1,
+0x21b6, 0x21b7,
+0x21bc, 0x21cd,
+0x21d0, 0x21d1,
+0x21d3, 0x21d3,
+0x21d5, 0x21db,
+0x21dd, 0x21dd,
+0x21e4, 0x21e5,
+0x2308, 0x230b,
+0x23b4, 0x23b5,
+0x23b7, 0x23b7,
+0x23d0, 0x23d0,
+0x23e2, 0x23e2,
+0x25a0, 0x25a1,
+0x25ae, 0x25b6,
+0x25bc, 0x25c0,
+0x25c6, 0x25c7,
+0x25ca, 0x25cb,
+0x25cf, 0x25d3,
+0x25e2, 0x25e2,
+0x25e4, 0x25e4,
+0x25e7, 0x25ec,
+0x2605, 0x2606,
+0x2640, 0x2640,
+0x2642, 0x2642,
+0x2660, 0x2663,
+0x266d, 0x266e,
+0x27c5, 0x27c6,
+0x27e6, 0x27ef,
+0x2983, 0x2998,
+0x29d8, 0x29db,
+0x29fc, 0x29fd,
+0xfe61, 0xfe61,
+0xfe63, 0xfe63,
+0xfe68, 0xfe68,
+0xff3c, 0xff3c,
+0xff3e, 0xff3e,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+}; /* END of CR_Other_Math */
+
+/* PROPERTY: 'Other_Uppercase': Binary Property */
+static const OnigCodePoint
+CR_Other_Uppercase[] = { 5,
+0x2160, 0x216f,
+0x24b6, 0x24cf,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+}; /* END of CR_Other_Uppercase */
+
+/* PROPERTY: 'P': Major Category */
+#define CR_P CR_Punct
+
+/* PROPERTY: 'Pahawh_Hmong': Script */
+static const OnigCodePoint
+CR_Pahawh_Hmong[] = { 5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+}; /* END of CR_Pahawh_Hmong */
+
+/* PROPERTY: 'Palmyrene': Script */
+static const OnigCodePoint
+CR_Palmyrene[] = { 1,
+0x10860, 0x1087f,
+}; /* END of CR_Palmyrene */
+
+/* PROPERTY: 'Pattern_Syntax': Binary Property */
+static const OnigCodePoint
+CR_Pattern_Syntax[] = { 28,
+0x0021, 0x002f,
+0x003a, 0x0040,
+0x005b, 0x005e,
+0x0060, 0x0060,
+0x007b, 0x007e,
+0x00a1, 0x00a7,
+0x00a9, 0x00a9,
+0x00ab, 0x00ac,
+0x00ae, 0x00ae,
+0x00b0, 0x00b1,
+0x00b6, 0x00b6,
+0x00bb, 0x00bb,
+0x00bf, 0x00bf,
+0x00d7, 0x00d7,
+0x00f7, 0x00f7,
+0x2010, 0x2027,
+0x2030, 0x203e,
+0x2041, 0x2053,
+0x2055, 0x205e,
+0x2190, 0x245f,
+0x2500, 0x2775,
+0x2794, 0x2bff,
+0x2e00, 0x2e7f,
+0x3001, 0x3003,
+0x3008, 0x3020,
+0x3030, 0x3030,
+0xfd3e, 0xfd3f,
+0xfe45, 0xfe46,
+}; /* END of CR_Pattern_Syntax */
+
+/* PROPERTY: 'Pattern_White_Space': Binary Property */
+static const OnigCodePoint
+CR_Pattern_White_Space[] = { 5,
+0x0009, 0x000d,
+0x0020, 0x0020,
+0x0085, 0x0085,
+0x200e, 0x200f,
+0x2028, 0x2029,
+}; /* END of CR_Pattern_White_Space */
+
+/* PROPERTY: 'Pau_Cin_Hau': Script */
+static const OnigCodePoint
+CR_Pau_Cin_Hau[] = { 1,
+0x11ac0, 0x11af8,
+}; /* END of CR_Pau_Cin_Hau */
+
+/* PROPERTY: 'Pc': General Category */
+static const OnigCodePoint
+CR_Pc[] = { 6,
+0x005f, 0x005f,
+0x203f, 0x2040,
+0x2054, 0x2054,
+0xfe33, 0xfe34,
+0xfe4d, 0xfe4f,
+0xff3f, 0xff3f,
+}; /* END of CR_Pc */
+
+/* PROPERTY: 'Pd': General Category */
+static const OnigCodePoint
+CR_Pd[] = { 17,
+0x002d, 0x002d,
+0x058a, 0x058a,
+0x05be, 0x05be,
+0x1400, 0x1400,
+0x1806, 0x1806,
+0x2010, 0x2015,
+0x2e17, 0x2e17,
+0x2e1a, 0x2e1a,
+0x2e3a, 0x2e3b,
+0x2e40, 0x2e40,
+0x301c, 0x301c,
+0x3030, 0x3030,
+0x30a0, 0x30a0,
+0xfe31, 0xfe32,
+0xfe58, 0xfe58,
+0xfe63, 0xfe63,
+0xff0d, 0xff0d,
+}; /* END of CR_Pd */
+
+/* PROPERTY: 'Pe': General Category */
+static const OnigCodePoint
+CR_Pe[] = { 72,
+0x0029, 0x0029,
+0x005d, 0x005d,
+0x007d, 0x007d,
+0x0f3b, 0x0f3b,
+0x0f3d, 0x0f3d,
+0x169c, 0x169c,
+0x2046, 0x2046,
+0x207e, 0x207e,
+0x208e, 0x208e,
+0x2309, 0x2309,
+0x230b, 0x230b,
+0x232a, 0x232a,
+0x2769, 0x2769,
+0x276b, 0x276b,
+0x276d, 0x276d,
+0x276f, 0x276f,
+0x2771, 0x2771,
+0x2773, 0x2773,
+0x2775, 0x2775,
+0x27c6, 0x27c6,
+0x27e7, 0x27e7,
+0x27e9, 0x27e9,
+0x27eb, 0x27eb,
+0x27ed, 0x27ed,
+0x27ef, 0x27ef,
+0x2984, 0x2984,
+0x2986, 0x2986,
+0x2988, 0x2988,
+0x298a, 0x298a,
+0x298c, 0x298c,
+0x298e, 0x298e,
+0x2990, 0x2990,
+0x2992, 0x2992,
+0x2994, 0x2994,
+0x2996, 0x2996,
+0x2998, 0x2998,
+0x29d9, 0x29d9,
+0x29db, 0x29db,
+0x29fd, 0x29fd,
+0x2e23, 0x2e23,
+0x2e25, 0x2e25,
+0x2e27, 0x2e27,
+0x2e29, 0x2e29,
+0x3009, 0x3009,
+0x300b, 0x300b,
+0x300d, 0x300d,
+0x300f, 0x300f,
+0x3011, 0x3011,
+0x3015, 0x3015,
+0x3017, 0x3017,
+0x3019, 0x3019,
+0x301b, 0x301b,
+0x301e, 0x301f,
+0xfd3e, 0xfd3e,
+0xfe18, 0xfe18,
+0xfe36, 0xfe36,
+0xfe38, 0xfe38,
+0xfe3a, 0xfe3a,
+0xfe3c, 0xfe3c,
+0xfe3e, 0xfe3e,
+0xfe40, 0xfe40,
+0xfe42, 0xfe42,
+0xfe44, 0xfe44,
+0xfe48, 0xfe48,
+0xfe5a, 0xfe5a,
+0xfe5c, 0xfe5c,
+0xfe5e, 0xfe5e,
+0xff09, 0xff09,
+0xff3d, 0xff3d,
+0xff5d, 0xff5d,
+0xff60, 0xff60,
+0xff63, 0xff63,
+}; /* END of CR_Pe */
+
+/* PROPERTY: 'Pf': General Category */
+static const OnigCodePoint
+CR_Pf[] = { 10,
+0x00bb, 0x00bb,
+0x2019, 0x2019,
+0x201d, 0x201d,
+0x203a, 0x203a,
+0x2e03, 0x2e03,
+0x2e05, 0x2e05,
+0x2e0a, 0x2e0a,
+0x2e0d, 0x2e0d,
+0x2e1d, 0x2e1d,
+0x2e21, 0x2e21,
+}; /* END of CR_Pf */
+
+/* PROPERTY: 'Phags_Pa': Script */
+static const OnigCodePoint
+CR_Phags_Pa[] = { 1,
+0xa840, 0xa877,
+}; /* END of CR_Phags_Pa */
+
+/* PROPERTY: 'Phoenician': Script */
+static const OnigCodePoint
+CR_Phoenician[] = { 2,
+0x10900, 0x1091b,
+0x1091f, 0x1091f,
+}; /* END of CR_Phoenician */
+
+/* PROPERTY: 'Pi': General Category */
+static const OnigCodePoint
+CR_Pi[] = { 11,
+0x00ab, 0x00ab,
+0x2018, 0x2018,
+0x201b, 0x201c,
+0x201f, 0x201f,
+0x2039, 0x2039,
+0x2e02, 0x2e02,
+0x2e04, 0x2e04,
+0x2e09, 0x2e09,
+0x2e0c, 0x2e0c,
+0x2e1c, 0x2e1c,
+0x2e20, 0x2e20,
+}; /* END of CR_Pi */
+
+/* PROPERTY: 'Po': General Category */
+static const OnigCodePoint
+CR_Po[] = { 179,
+0x0021, 0x0023,
+0x0025, 0x0027,
+0x002a, 0x002a,
+0x002c, 0x002c,
+0x002e, 0x002f,
+0x003a, 0x003b,
+0x003f, 0x0040,
+0x005c, 0x005c,
+0x00a1, 0x00a1,
+0x00a7, 0x00a7,
+0x00b6, 0x00b7,
+0x00bf, 0x00bf,
+0x037e, 0x037e,
+0x0387, 0x0387,
+0x055a, 0x055f,
+0x0589, 0x0589,
+0x05c0, 0x05c0,
+0x05c3, 0x05c3,
+0x05c6, 0x05c6,
+0x05f3, 0x05f4,
+0x0609, 0x060a,
+0x060c, 0x060d,
+0x061b, 0x061b,
+0x061e, 0x061f,
+0x066a, 0x066d,
+0x06d4, 0x06d4,
+0x0700, 0x070d,
+0x07f7, 0x07f9,
+0x0830, 0x083e,
+0x085e, 0x085e,
+0x0964, 0x0965,
+0x0970, 0x0970,
+0x09fd, 0x09fd,
+0x0a76, 0x0a76,
+0x0af0, 0x0af0,
+0x0c77, 0x0c77,
+0x0c84, 0x0c84,
+0x0df4, 0x0df4,
+0x0e4f, 0x0e4f,
+0x0e5a, 0x0e5b,
+0x0f04, 0x0f12,
+0x0f14, 0x0f14,
+0x0f85, 0x0f85,
+0x0fd0, 0x0fd4,
+0x0fd9, 0x0fda,
+0x104a, 0x104f,
+0x10fb, 0x10fb,
+0x1360, 0x1368,
+0x166e, 0x166e,
+0x16eb, 0x16ed,
+0x1735, 0x1736,
+0x17d4, 0x17d6,
+0x17d8, 0x17da,
+0x1800, 0x1805,
+0x1807, 0x180a,
+0x1944, 0x1945,
+0x1a1e, 0x1a1f,
+0x1aa0, 0x1aa6,
+0x1aa8, 0x1aad,
+0x1b5a, 0x1b60,
+0x1bfc, 0x1bff,
+0x1c3b, 0x1c3f,
+0x1c7e, 0x1c7f,
+0x1cc0, 0x1cc7,
+0x1cd3, 0x1cd3,
+0x2016, 0x2017,
+0x2020, 0x2027,
+0x2030, 0x2038,
+0x203b, 0x203e,
+0x2041, 0x2043,
+0x2047, 0x2051,
+0x2053, 0x2053,
+0x2055, 0x205e,
+0x2cf9, 0x2cfc,
+0x2cfe, 0x2cff,
+0x2d70, 0x2d70,
+0x2e00, 0x2e01,
+0x2e06, 0x2e08,
+0x2e0b, 0x2e0b,
+0x2e0e, 0x2e16,
+0x2e18, 0x2e19,
+0x2e1b, 0x2e1b,
+0x2e1e, 0x2e1f,
+0x2e2a, 0x2e2e,
+0x2e30, 0x2e39,
+0x2e3c, 0x2e3f,
+0x2e41, 0x2e41,
+0x2e43, 0x2e4f,
+0x3001, 0x3003,
+0x303d, 0x303d,
+0x30fb, 0x30fb,
+0xa4fe, 0xa4ff,
+0xa60d, 0xa60f,
+0xa673, 0xa673,
+0xa67e, 0xa67e,
+0xa6f2, 0xa6f7,
+0xa874, 0xa877,
+0xa8ce, 0xa8cf,
+0xa8f8, 0xa8fa,
+0xa8fc, 0xa8fc,
+0xa92e, 0xa92f,
+0xa95f, 0xa95f,
+0xa9c1, 0xa9cd,
+0xa9de, 0xa9df,
+0xaa5c, 0xaa5f,
+0xaade, 0xaadf,
+0xaaf0, 0xaaf1,
+0xabeb, 0xabeb,
+0xfe10, 0xfe16,
+0xfe19, 0xfe19,
+0xfe30, 0xfe30,
+0xfe45, 0xfe46,
+0xfe49, 0xfe4c,
+0xfe50, 0xfe52,
+0xfe54, 0xfe57,
+0xfe5f, 0xfe61,
+0xfe68, 0xfe68,
+0xfe6a, 0xfe6b,
+0xff01, 0xff03,
+0xff05, 0xff07,
+0xff0a, 0xff0a,
+0xff0c, 0xff0c,
+0xff0e, 0xff0f,
+0xff1a, 0xff1b,
+0xff1f, 0xff20,
+0xff3c, 0xff3c,
+0xff61, 0xff61,
+0xff64, 0xff65,
+0x10100, 0x10102,
+0x1039f, 0x1039f,
+0x103d0, 0x103d0,
+0x1056f, 0x1056f,
+0x10857, 0x10857,
+0x1091f, 0x1091f,
+0x1093f, 0x1093f,
+0x10a50, 0x10a58,
+0x10a7f, 0x10a7f,
+0x10af0, 0x10af6,
+0x10b39, 0x10b3f,
+0x10b99, 0x10b9c,
+0x10f55, 0x10f59,
+0x11047, 0x1104d,
+0x110bb, 0x110bc,
+0x110be, 0x110c1,
+0x11140, 0x11143,
+0x11174, 0x11175,
+0x111c5, 0x111c8,
+0x111cd, 0x111cd,
+0x111db, 0x111db,
+0x111dd, 0x111df,
+0x11238, 0x1123d,
+0x112a9, 0x112a9,
+0x1144b, 0x1144f,
+0x1145b, 0x1145b,
+0x1145d, 0x1145d,
+0x114c6, 0x114c6,
+0x115c1, 0x115d7,
+0x11641, 0x11643,
+0x11660, 0x1166c,
+0x1173c, 0x1173e,
+0x1183b, 0x1183b,
+0x119e2, 0x119e2,
+0x11a3f, 0x11a46,
+0x11a9a, 0x11a9c,
+0x11a9e, 0x11aa2,
+0x11c41, 0x11c45,
+0x11c70, 0x11c71,
+0x11ef7, 0x11ef8,
+0x11fff, 0x11fff,
+0x12470, 0x12474,
+0x16a6e, 0x16a6f,
+0x16af5, 0x16af5,
+0x16b37, 0x16b3b,
+0x16b44, 0x16b44,
+0x16e97, 0x16e9a,
+0x16fe2, 0x16fe2,
+0x1bc9f, 0x1bc9f,
+0x1da87, 0x1da8b,
+0x1e95e, 0x1e95f,
+}; /* END of CR_Po */
+
+/* PROPERTY: 'Prepended_Concatenation_Mark': Binary Property */
+static const OnigCodePoint
+CR_Prepended_Concatenation_Mark[] = { 6,
+0x0600, 0x0605,
+0x06dd, 0x06dd,
+0x070f, 0x070f,
+0x08e2, 0x08e2,
+0x110bd, 0x110bd,
+0x110cd, 0x110cd,
+}; /* END of CR_Prepended_Concatenation_Mark */
+
+/* PROPERTY: 'Ps': General Category */
+static const OnigCodePoint
+CR_Ps[] = { 75,
+0x0028, 0x0028,
+0x005b, 0x005b,
+0x007b, 0x007b,
+0x0f3a, 0x0f3a,
+0x0f3c, 0x0f3c,
+0x169b, 0x169b,
+0x201a, 0x201a,
+0x201e, 0x201e,
+0x2045, 0x2045,
+0x207d, 0x207d,
+0x208d, 0x208d,
+0x2308, 0x2308,
+0x230a, 0x230a,
+0x2329, 0x2329,
+0x2768, 0x2768,
+0x276a, 0x276a,
+0x276c, 0x276c,
+0x276e, 0x276e,
+0x2770, 0x2770,
+0x2772, 0x2772,
+0x2774, 0x2774,
+0x27c5, 0x27c5,
+0x27e6, 0x27e6,
+0x27e8, 0x27e8,
+0x27ea, 0x27ea,
+0x27ec, 0x27ec,
+0x27ee, 0x27ee,
+0x2983, 0x2983,
+0x2985, 0x2985,
+0x2987, 0x2987,
+0x2989, 0x2989,
+0x298b, 0x298b,
+0x298d, 0x298d,
+0x298f, 0x298f,
+0x2991, 0x2991,
+0x2993, 0x2993,
+0x2995, 0x2995,
+0x2997, 0x2997,
+0x29d8, 0x29d8,
+0x29da, 0x29da,
+0x29fc, 0x29fc,
+0x2e22, 0x2e22,
+0x2e24, 0x2e24,
+0x2e26, 0x2e26,
+0x2e28, 0x2e28,
+0x2e42, 0x2e42,
+0x3008, 0x3008,
+0x300a, 0x300a,
+0x300c, 0x300c,
+0x300e, 0x300e,
+0x3010, 0x3010,
+0x3014, 0x3014,
+0x3016, 0x3016,
+0x3018, 0x3018,
+0x301a, 0x301a,
+0x301d, 0x301d,
+0xfd3f, 0xfd3f,
+0xfe17, 0xfe17,
+0xfe35, 0xfe35,
+0xfe37, 0xfe37,
+0xfe39, 0xfe39,
+0xfe3b, 0xfe3b,
+0xfe3d, 0xfe3d,
+0xfe3f, 0xfe3f,
+0xfe41, 0xfe41,
+0xfe43, 0xfe43,
+0xfe47, 0xfe47,
+0xfe59, 0xfe59,
+0xfe5b, 0xfe5b,
+0xfe5d, 0xfe5d,
+0xff08, 0xff08,
+0xff3b, 0xff3b,
+0xff5b, 0xff5b,
+0xff5f, 0xff5f,
+0xff62, 0xff62,
+}; /* END of CR_Ps */
+
+/* PROPERTY: 'Psalter_Pahlavi': Script */
+static const OnigCodePoint
+CR_Psalter_Pahlavi[] = { 3,
+0x10b80, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+}; /* END of CR_Psalter_Pahlavi */
+
+/* PROPERTY: 'Quotation_Mark': Binary Property */
+static const OnigCodePoint
+CR_Quotation_Mark[] = { 13,
+0x0022, 0x0022,
+0x0027, 0x0027,
+0x00ab, 0x00ab,
+0x00bb, 0x00bb,
+0x2018, 0x201f,
+0x2039, 0x203a,
+0x2e42, 0x2e42,
+0x300c, 0x300f,
+0x301d, 0x301f,
+0xfe41, 0xfe44,
+0xff02, 0xff02,
+0xff07, 0xff07,
+0xff62, 0xff63,
+}; /* END of CR_Quotation_Mark */
+
+/* PROPERTY: 'Radical': Binary Property */
+static const OnigCodePoint
+CR_Radical[] = { 3,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+}; /* END of CR_Radical */
+
+/* PROPERTY: 'Regional_Indicator': Binary Property */
+static const OnigCodePoint
+CR_Regional_Indicator[] = { 1,
+0x1f1e6, 0x1f1ff,
+}; /* END of CR_Regional_Indicator */
+
+/* PROPERTY: 'Rejang': Script */
+static const OnigCodePoint
+CR_Rejang[] = { 2,
+0xa930, 0xa953,
+0xa95f, 0xa95f,
+}; /* END of CR_Rejang */
+
+/* PROPERTY: 'Runic': Script */
+static const OnigCodePoint
+CR_Runic[] = { 2,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+}; /* END of CR_Runic */
+
+/* PROPERTY: 'S': Major Category */
+static const OnigCodePoint
+CR_S[] = { 226,
+0x0024, 0x0024,
+0x002b, 0x002b,
+0x003c, 0x003e,
+0x005e, 0x005e,
+0x0060, 0x0060,
+0x007c, 0x007c,
+0x007e, 0x007e,
+0x00a2, 0x00a6,
+0x00a8, 0x00a9,
+0x00ac, 0x00ac,
+0x00ae, 0x00b1,
+0x00b4, 0x00b4,
+0x00b8, 0x00b8,
+0x00d7, 0x00d7,
+0x00f7, 0x00f7,
+0x02c2, 0x02c5,
+0x02d2, 0x02df,
+0x02e5, 0x02eb,
+0x02ed, 0x02ed,
+0x02ef, 0x02ff,
+0x0375, 0x0375,
+0x0384, 0x0385,
+0x03f6, 0x03f6,
+0x0482, 0x0482,
+0x058d, 0x058f,
+0x0606, 0x0608,
+0x060b, 0x060b,
+0x060e, 0x060f,
+0x06de, 0x06de,
+0x06e9, 0x06e9,
+0x06fd, 0x06fe,
+0x07f6, 0x07f6,
+0x07fe, 0x07ff,
+0x09f2, 0x09f3,
+0x09fa, 0x09fb,
+0x0af1, 0x0af1,
+0x0b70, 0x0b70,
+0x0bf3, 0x0bfa,
+0x0c7f, 0x0c7f,
+0x0d4f, 0x0d4f,
+0x0d79, 0x0d79,
+0x0e3f, 0x0e3f,
+0x0f01, 0x0f03,
+0x0f13, 0x0f13,
+0x0f15, 0x0f17,
+0x0f1a, 0x0f1f,
+0x0f34, 0x0f34,
+0x0f36, 0x0f36,
+0x0f38, 0x0f38,
+0x0fbe, 0x0fc5,
+0x0fc7, 0x0fcc,
+0x0fce, 0x0fcf,
+0x0fd5, 0x0fd8,
+0x109e, 0x109f,
+0x1390, 0x1399,
+0x166d, 0x166d,
+0x17db, 0x17db,
+0x1940, 0x1940,
+0x19de, 0x19ff,
+0x1b61, 0x1b6a,
+0x1b74, 0x1b7c,
+0x1fbd, 0x1fbd,
+0x1fbf, 0x1fc1,
+0x1fcd, 0x1fcf,
+0x1fdd, 0x1fdf,
+0x1fed, 0x1fef,
+0x1ffd, 0x1ffe,
+0x2044, 0x2044,
+0x2052, 0x2052,
+0x207a, 0x207c,
+0x208a, 0x208c,
+0x20a0, 0x20bf,
+0x2100, 0x2101,
+0x2103, 0x2106,
+0x2108, 0x2109,
+0x2114, 0x2114,
+0x2116, 0x2118,
+0x211e, 0x2123,
+0x2125, 0x2125,
+0x2127, 0x2127,
+0x2129, 0x2129,
+0x212e, 0x212e,
+0x213a, 0x213b,
+0x2140, 0x2144,
+0x214a, 0x214d,
+0x214f, 0x214f,
+0x218a, 0x218b,
+0x2190, 0x2307,
+0x230c, 0x2328,
+0x232b, 0x2426,
+0x2440, 0x244a,
+0x249c, 0x24e9,
+0x2500, 0x2767,
+0x2794, 0x27c4,
+0x27c7, 0x27e5,
+0x27f0, 0x2982,
+0x2999, 0x29d7,
+0x29dc, 0x29fb,
+0x29fe, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2bff,
+0x2ce5, 0x2cea,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3004, 0x3004,
+0x3012, 0x3013,
+0x3020, 0x3020,
+0x3036, 0x3037,
+0x303e, 0x303f,
+0x309b, 0x309c,
+0x3190, 0x3191,
+0x3196, 0x319f,
+0x31c0, 0x31e3,
+0x3200, 0x321e,
+0x322a, 0x3247,
+0x3250, 0x3250,
+0x3260, 0x327f,
+0x328a, 0x32b0,
+0x32c0, 0x33ff,
+0x4dc0, 0x4dff,
+0xa490, 0xa4c6,
+0xa700, 0xa716,
+0xa720, 0xa721,
+0xa789, 0xa78a,
+0xa828, 0xa82b,
+0xa836, 0xa839,
+0xaa77, 0xaa79,
+0xab5b, 0xab5b,
+0xfb29, 0xfb29,
+0xfbb2, 0xfbc1,
+0xfdfc, 0xfdfd,
+0xfe62, 0xfe62,
+0xfe64, 0xfe66,
+0xfe69, 0xfe69,
+0xff04, 0xff04,
+0xff0b, 0xff0b,
+0xff1c, 0xff1e,
+0xff3e, 0xff3e,
+0xff40, 0xff40,
+0xff5c, 0xff5c,
+0xff5e, 0xff5e,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfffc, 0xfffd,
+0x10137, 0x1013f,
+0x10179, 0x10189,
+0x1018c, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fc,
+0x10877, 0x10878,
+0x10ac8, 0x10ac8,
+0x1173f, 0x1173f,
+0x11fd5, 0x11ff1,
+0x16b3c, 0x16b3f,
+0x16b45, 0x16b45,
+0x1bc9c, 0x1bc9c,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d164,
+0x1d16a, 0x1d16c,
+0x1d183, 0x1d184,
+0x1d18c, 0x1d1a9,
+0x1d1ae, 0x1d1e8,
+0x1d200, 0x1d241,
+0x1d245, 0x1d245,
+0x1d300, 0x1d356,
+0x1d6c1, 0x1d6c1,
+0x1d6db, 0x1d6db,
+0x1d6fb, 0x1d6fb,
+0x1d715, 0x1d715,
+0x1d735, 0x1d735,
+0x1d74f, 0x1d74f,
+0x1d76f, 0x1d76f,
+0x1d789, 0x1d789,
+0x1d7a9, 0x1d7a9,
+0x1d7c3, 0x1d7c3,
+0x1d800, 0x1d9ff,
+0x1da37, 0x1da3a,
+0x1da6d, 0x1da74,
+0x1da76, 0x1da83,
+0x1da85, 0x1da86,
+0x1e14f, 0x1e14f,
+0x1e2ff, 0x1e2ff,
+0x1ecac, 0x1ecac,
+0x1ecb0, 0x1ecb0,
+0x1ed2e, 0x1ed2e,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+}; /* END of CR_S */
+
+/* PROPERTY: 'Samaritan': Script */
+static const OnigCodePoint
+CR_Samaritan[] = { 2,
+0x0800, 0x082d,
+0x0830, 0x083e,
+}; /* END of CR_Samaritan */
+
+/* PROPERTY: 'Saurashtra': Script */
+static const OnigCodePoint
+CR_Saurashtra[] = { 2,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+}; /* END of CR_Saurashtra */
+
+/* PROPERTY: 'Sc': General Category */
+static const OnigCodePoint
+CR_Sc[] = { 21,
+0x0024, 0x0024,
+0x00a2, 0x00a5,
+0x058f, 0x058f,
+0x060b, 0x060b,
+0x07fe, 0x07ff,
+0x09f2, 0x09f3,
+0x09fb, 0x09fb,
+0x0af1, 0x0af1,
+0x0bf9, 0x0bf9,
+0x0e3f, 0x0e3f,
+0x17db, 0x17db,
+0x20a0, 0x20bf,
+0xa838, 0xa838,
+0xfdfc, 0xfdfc,
+0xfe69, 0xfe69,
+0xff04, 0xff04,
+0xffe0, 0xffe1,
+0xffe5, 0xffe6,
+0x11fdd, 0x11fe0,
+0x1e2ff, 0x1e2ff,
+0x1ecb0, 0x1ecb0,
+}; /* END of CR_Sc */
+
+/* PROPERTY: 'Sentence_Terminal': Binary Property */
+static const OnigCodePoint
+CR_Sentence_Terminal[] = { 74,
+0x0021, 0x0021,
+0x002e, 0x002e,
+0x003f, 0x003f,
+0x0589, 0x0589,
+0x061e, 0x061f,
+0x06d4, 0x06d4,
+0x0700, 0x0702,
+0x07f9, 0x07f9,
+0x0837, 0x0837,
+0x0839, 0x0839,
+0x083d, 0x083e,
+0x0964, 0x0965,
+0x104a, 0x104b,
+0x1362, 0x1362,
+0x1367, 0x1368,
+0x166e, 0x166e,
+0x1735, 0x1736,
+0x1803, 0x1803,
+0x1809, 0x1809,
+0x1944, 0x1945,
+0x1aa8, 0x1aab,
+0x1b5a, 0x1b5b,
+0x1b5e, 0x1b5f,
+0x1c3b, 0x1c3c,
+0x1c7e, 0x1c7f,
+0x203c, 0x203d,
+0x2047, 0x2049,
+0x2e2e, 0x2e2e,
+0x2e3c, 0x2e3c,
+0x3002, 0x3002,
+0xa4ff, 0xa4ff,
+0xa60e, 0xa60f,
+0xa6f3, 0xa6f3,
+0xa6f7, 0xa6f7,
+0xa876, 0xa877,
+0xa8ce, 0xa8cf,
+0xa92f, 0xa92f,
+0xa9c8, 0xa9c9,
+0xaa5d, 0xaa5f,
+0xaaf0, 0xaaf1,
+0xabeb, 0xabeb,
+0xfe52, 0xfe52,
+0xfe56, 0xfe57,
+0xff01, 0xff01,
+0xff0e, 0xff0e,
+0xff1f, 0xff1f,
+0xff61, 0xff61,
+0x10a56, 0x10a57,
+0x10f55, 0x10f59,
+0x11047, 0x11048,
+0x110be, 0x110c1,
+0x11141, 0x11143,
+0x111c5, 0x111c6,
+0x111cd, 0x111cd,
+0x111de, 0x111df,
+0x11238, 0x11239,
+0x1123b, 0x1123c,
+0x112a9, 0x112a9,
+0x1144b, 0x1144c,
+0x115c2, 0x115c3,
+0x115c9, 0x115d7,
+0x11641, 0x11642,
+0x1173c, 0x1173e,
+0x11a42, 0x11a43,
+0x11a9b, 0x11a9c,
+0x11c41, 0x11c42,
+0x11ef7, 0x11ef8,
+0x16a6e, 0x16a6f,
+0x16af5, 0x16af5,
+0x16b37, 0x16b38,
+0x16b44, 0x16b44,
+0x16e98, 0x16e98,
+0x1bc9f, 0x1bc9f,
+0x1da88, 0x1da88,
+}; /* END of CR_Sentence_Terminal */
+
+/* PROPERTY: 'Sharada': Script */
+static const OnigCodePoint
+CR_Sharada[] = { 2,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+}; /* END of CR_Sharada */
+
+/* PROPERTY: 'Shavian': Script */
+static const OnigCodePoint
+CR_Shavian[] = { 1,
+0x10450, 0x1047f,
+}; /* END of CR_Shavian */
+
+/* PROPERTY: 'Siddham': Script */
+static const OnigCodePoint
+CR_Siddham[] = { 2,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+}; /* END of CR_Siddham */
+
+/* PROPERTY: 'SignWriting': Script */
+static const OnigCodePoint
+CR_SignWriting[] = { 3,
+0x1d800, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+}; /* END of CR_SignWriting */
+
+/* PROPERTY: 'Sinhala': Script */
+static const OnigCodePoint
+CR_Sinhala[] = { 13,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x111e1, 0x111f4,
+}; /* END of CR_Sinhala */
+
+/* PROPERTY: 'Sk': General Category */
+static const OnigCodePoint
+CR_Sk[] = { 29,
+0x005e, 0x005e,
+0x0060, 0x0060,
+0x00a8, 0x00a8,
+0x00af, 0x00af,
+0x00b4, 0x00b4,
+0x00b8, 0x00b8,
+0x02c2, 0x02c5,
+0x02d2, 0x02df,
+0x02e5, 0x02eb,
+0x02ed, 0x02ed,
+0x02ef, 0x02ff,
+0x0375, 0x0375,
+0x0384, 0x0385,
+0x1fbd, 0x1fbd,
+0x1fbf, 0x1fc1,
+0x1fcd, 0x1fcf,
+0x1fdd, 0x1fdf,
+0x1fed, 0x1fef,
+0x1ffd, 0x1ffe,
+0x309b, 0x309c,
+0xa700, 0xa716,
+0xa720, 0xa721,
+0xa789, 0xa78a,
+0xab5b, 0xab5b,
+0xfbb2, 0xfbc1,
+0xff3e, 0xff3e,
+0xff40, 0xff40,
+0xffe3, 0xffe3,
+0x1f3fb, 0x1f3ff,
+}; /* END of CR_Sk */
+
+/* PROPERTY: 'Sm': General Category */
+static const OnigCodePoint
+CR_Sm[] = { 64,
+0x002b, 0x002b,
+0x003c, 0x003e,
+0x007c, 0x007c,
+0x007e, 0x007e,
+0x00ac, 0x00ac,
+0x00b1, 0x00b1,
+0x00d7, 0x00d7,
+0x00f7, 0x00f7,
+0x03f6, 0x03f6,
+0x0606, 0x0608,
+0x2044, 0x2044,
+0x2052, 0x2052,
+0x207a, 0x207c,
+0x208a, 0x208c,
+0x2118, 0x2118,
+0x2140, 0x2144,
+0x214b, 0x214b,
+0x2190, 0x2194,
+0x219a, 0x219b,
+0x21a0, 0x21a0,
+0x21a3, 0x21a3,
+0x21a6, 0x21a6,
+0x21ae, 0x21ae,
+0x21ce, 0x21cf,
+0x21d2, 0x21d2,
+0x21d4, 0x21d4,
+0x21f4, 0x22ff,
+0x2320, 0x2321,
+0x237c, 0x237c,
+0x239b, 0x23b3,
+0x23dc, 0x23e1,
+0x25b7, 0x25b7,
+0x25c1, 0x25c1,
+0x25f8, 0x25ff,
+0x266f, 0x266f,
+0x27c0, 0x27c4,
+0x27c7, 0x27e5,
+0x27f0, 0x27ff,
+0x2900, 0x2982,
+0x2999, 0x29d7,
+0x29dc, 0x29fb,
+0x29fe, 0x2aff,
+0x2b30, 0x2b44,
+0x2b47, 0x2b4c,
+0xfb29, 0xfb29,
+0xfe62, 0xfe62,
+0xfe64, 0xfe66,
+0xff0b, 0xff0b,
+0xff1c, 0xff1e,
+0xff5c, 0xff5c,
+0xff5e, 0xff5e,
+0xffe2, 0xffe2,
+0xffe9, 0xffec,
+0x1d6c1, 0x1d6c1,
+0x1d6db, 0x1d6db,
+0x1d6fb, 0x1d6fb,
+0x1d715, 0x1d715,
+0x1d735, 0x1d735,
+0x1d74f, 0x1d74f,
+0x1d76f, 0x1d76f,
+0x1d789, 0x1d789,
+0x1d7a9, 0x1d7a9,
+0x1d7c3, 0x1d7c3,
+0x1eef0, 0x1eef1,
+}; /* END of CR_Sm */
+
+/* PROPERTY: 'So': General Category */
+static const OnigCodePoint
+CR_So[] = { 180,
+0x00a6, 0x00a6,
+0x00a9, 0x00a9,
+0x00ae, 0x00ae,
+0x00b0, 0x00b0,
+0x0482, 0x0482,
+0x058d, 0x058e,
+0x060e, 0x060f,
+0x06de, 0x06de,
+0x06e9, 0x06e9,
+0x06fd, 0x06fe,
+0x07f6, 0x07f6,
+0x09fa, 0x09fa,
+0x0b70, 0x0b70,
+0x0bf3, 0x0bf8,
+0x0bfa, 0x0bfa,
+0x0c7f, 0x0c7f,
+0x0d4f, 0x0d4f,
+0x0d79, 0x0d79,
+0x0f01, 0x0f03,
+0x0f13, 0x0f13,
+0x0f15, 0x0f17,
+0x0f1a, 0x0f1f,
+0x0f34, 0x0f34,
+0x0f36, 0x0f36,
+0x0f38, 0x0f38,
+0x0fbe, 0x0fc5,
+0x0fc7, 0x0fcc,
+0x0fce, 0x0fcf,
+0x0fd5, 0x0fd8,
+0x109e, 0x109f,
+0x1390, 0x1399,
+0x166d, 0x166d,
+0x1940, 0x1940,
+0x19de, 0x19ff,
+0x1b61, 0x1b6a,
+0x1b74, 0x1b7c,
+0x2100, 0x2101,
+0x2103, 0x2106,
+0x2108, 0x2109,
+0x2114, 0x2114,
+0x2116, 0x2117,
+0x211e, 0x2123,
+0x2125, 0x2125,
+0x2127, 0x2127,
+0x2129, 0x2129,
+0x212e, 0x212e,
+0x213a, 0x213b,
+0x214a, 0x214a,
+0x214c, 0x214d,
+0x214f, 0x214f,
+0x218a, 0x218b,
+0x2195, 0x2199,
+0x219c, 0x219f,
+0x21a1, 0x21a2,
+0x21a4, 0x21a5,
+0x21a7, 0x21ad,
+0x21af, 0x21cd,
+0x21d0, 0x21d1,
+0x21d3, 0x21d3,
+0x21d5, 0x21f3,
+0x2300, 0x2307,
+0x230c, 0x231f,
+0x2322, 0x2328,
+0x232b, 0x237b,
+0x237d, 0x239a,
+0x23b4, 0x23db,
+0x23e2, 0x2426,
+0x2440, 0x244a,
+0x249c, 0x24e9,
+0x2500, 0x25b6,
+0x25b8, 0x25c0,
+0x25c2, 0x25f7,
+0x2600, 0x266e,
+0x2670, 0x2767,
+0x2794, 0x27bf,
+0x2800, 0x28ff,
+0x2b00, 0x2b2f,
+0x2b45, 0x2b46,
+0x2b4d, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2bff,
+0x2ce5, 0x2cea,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3004, 0x3004,
+0x3012, 0x3013,
+0x3020, 0x3020,
+0x3036, 0x3037,
+0x303e, 0x303f,
+0x3190, 0x3191,
+0x3196, 0x319f,
+0x31c0, 0x31e3,
+0x3200, 0x321e,
+0x322a, 0x3247,
+0x3250, 0x3250,
+0x3260, 0x327f,
+0x328a, 0x32b0,
+0x32c0, 0x33ff,
+0x4dc0, 0x4dff,
+0xa490, 0xa4c6,
+0xa828, 0xa82b,
+0xa836, 0xa837,
+0xa839, 0xa839,
+0xaa77, 0xaa79,
+0xfdfd, 0xfdfd,
+0xffe4, 0xffe4,
+0xffe8, 0xffe8,
+0xffed, 0xffee,
+0xfffc, 0xfffd,
+0x10137, 0x1013f,
+0x10179, 0x10189,
+0x1018c, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fc,
+0x10877, 0x10878,
+0x10ac8, 0x10ac8,
+0x1173f, 0x1173f,
+0x11fd5, 0x11fdc,
+0x11fe1, 0x11ff1,
+0x16b3c, 0x16b3f,
+0x16b45, 0x16b45,
+0x1bc9c, 0x1bc9c,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d164,
+0x1d16a, 0x1d16c,
+0x1d183, 0x1d184,
+0x1d18c, 0x1d1a9,
+0x1d1ae, 0x1d1e8,
+0x1d200, 0x1d241,
+0x1d245, 0x1d245,
+0x1d300, 0x1d356,
+0x1d800, 0x1d9ff,
+0x1da37, 0x1da3a,
+0x1da6d, 0x1da74,
+0x1da76, 0x1da83,
+0x1da85, 0x1da86,
+0x1e14f, 0x1e14f,
+0x1ecac, 0x1ecac,
+0x1ed2e, 0x1ed2e,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f3fa,
+0x1f400, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+}; /* END of CR_So */
+
+/* PROPERTY: 'Soft_Dotted': Binary Property */
+static const OnigCodePoint
+CR_Soft_Dotted[] = { 31,
+0x0069, 0x006a,
+0x012f, 0x012f,
+0x0249, 0x0249,
+0x0268, 0x0268,
+0x029d, 0x029d,
+0x02b2, 0x02b2,
+0x03f3, 0x03f3,
+0x0456, 0x0456,
+0x0458, 0x0458,
+0x1d62, 0x1d62,
+0x1d96, 0x1d96,
+0x1da4, 0x1da4,
+0x1da8, 0x1da8,
+0x1e2d, 0x1e2d,
+0x1ecb, 0x1ecb,
+0x2071, 0x2071,
+0x2148, 0x2149,
+0x2c7c, 0x2c7c,
+0x1d422, 0x1d423,
+0x1d456, 0x1d457,
+0x1d48a, 0x1d48b,
+0x1d4be, 0x1d4bf,
+0x1d4f2, 0x1d4f3,
+0x1d526, 0x1d527,
+0x1d55a, 0x1d55b,
+0x1d58e, 0x1d58f,
+0x1d5c2, 0x1d5c3,
+0x1d5f6, 0x1d5f7,
+0x1d62a, 0x1d62b,
+0x1d65e, 0x1d65f,
+0x1d692, 0x1d693,
+}; /* END of CR_Soft_Dotted */
+
+/* PROPERTY: 'Sogdian': Script */
+static const OnigCodePoint
+CR_Sogdian[] = { 1,
+0x10f30, 0x10f59,
+}; /* END of CR_Sogdian */
+
+/* PROPERTY: 'Sora_Sompeng': Script */
+static const OnigCodePoint
+CR_Sora_Sompeng[] = { 2,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+}; /* END of CR_Sora_Sompeng */
+
+/* PROPERTY: 'Soyombo': Script */
+static const OnigCodePoint
+CR_Soyombo[] = { 1,
+0x11a50, 0x11aa2,
+}; /* END of CR_Soyombo */
+
+/* PROPERTY: 'Sundanese': Script */
+static const OnigCodePoint
+CR_Sundanese[] = { 2,
+0x1b80, 0x1bbf,
+0x1cc0, 0x1cc7,
+}; /* END of CR_Sundanese */
+
+/* PROPERTY: 'Syloti_Nagri': Script */
+static const OnigCodePoint
+CR_Syloti_Nagri[] = { 1,
+0xa800, 0xa82b,
+}; /* END of CR_Syloti_Nagri */
+
+/* PROPERTY: 'Syriac': Script */
+static const OnigCodePoint
+CR_Syriac[] = { 4,
+0x0700, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x074f,
+0x0860, 0x086a,
+}; /* END of CR_Syriac */
+
+/* PROPERTY: 'Tagalog': Script */
+static const OnigCodePoint
+CR_Tagalog[] = { 2,
+0x1700, 0x170c,
+0x170e, 0x1714,
+}; /* END of CR_Tagalog */
+
+/* PROPERTY: 'Tagbanwa': Script */
+static const OnigCodePoint
+CR_Tagbanwa[] = { 3,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+}; /* END of CR_Tagbanwa */
+
+/* PROPERTY: 'Tai_Le': Script */
+static const OnigCodePoint
+CR_Tai_Le[] = { 2,
+0x1950, 0x196d,
+0x1970, 0x1974,
+}; /* END of CR_Tai_Le */
+
+/* PROPERTY: 'Tai_Tham': Script */
+static const OnigCodePoint
+CR_Tai_Tham[] = { 5,
+0x1a20, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+}; /* END of CR_Tai_Tham */
+
+/* PROPERTY: 'Tai_Viet': Script */
+static const OnigCodePoint
+CR_Tai_Viet[] = { 2,
+0xaa80, 0xaac2,
+0xaadb, 0xaadf,
+}; /* END of CR_Tai_Viet */
+
+/* PROPERTY: 'Takri': Script */
+static const OnigCodePoint
+CR_Takri[] = { 2,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+}; /* END of CR_Takri */
+
+/* PROPERTY: 'Tamil': Script */
+static const OnigCodePoint
+CR_Tamil[] = { 18,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x11fc0, 0x11ff1,
+0x11fff, 0x11fff,
+}; /* END of CR_Tamil */
+
+/* PROPERTY: 'Tangut': Script */
+static const OnigCodePoint
+CR_Tangut[] = { 3,
+0x16fe0, 0x16fe0,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+}; /* END of CR_Tangut */
+
+/* PROPERTY: 'Telugu': Script */
+static const OnigCodePoint
+CR_Telugu[] = { 12,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c7f,
+}; /* END of CR_Telugu */
+
+/* PROPERTY: 'Terminal_Punctuation': Binary Property */
+static const OnigCodePoint
+CR_Terminal_Punctuation[] = { 102,
+0x0021, 0x0021,
+0x002c, 0x002c,
+0x002e, 0x002e,
+0x003a, 0x003b,
+0x003f, 0x003f,
+0x037e, 0x037e,
+0x0387, 0x0387,
+0x0589, 0x0589,
+0x05c3, 0x05c3,
+0x060c, 0x060c,
+0x061b, 0x061b,
+0x061e, 0x061f,
+0x06d4, 0x06d4,
+0x0700, 0x070a,
+0x070c, 0x070c,
+0x07f8, 0x07f9,
+0x0830, 0x083e,
+0x085e, 0x085e,
+0x0964, 0x0965,
+0x0e5a, 0x0e5b,
+0x0f08, 0x0f08,
+0x0f0d, 0x0f12,
+0x104a, 0x104b,
+0x1361, 0x1368,
+0x166e, 0x166e,
+0x16eb, 0x16ed,
+0x1735, 0x1736,
+0x17d4, 0x17d6,
+0x17da, 0x17da,
+0x1802, 0x1805,
+0x1808, 0x1809,
+0x1944, 0x1945,
+0x1aa8, 0x1aab,
+0x1b5a, 0x1b5b,
+0x1b5d, 0x1b5f,
+0x1c3b, 0x1c3f,
+0x1c7e, 0x1c7f,
+0x203c, 0x203d,
+0x2047, 0x2049,
+0x2e2e, 0x2e2e,
+0x2e3c, 0x2e3c,
+0x2e41, 0x2e41,
+0x2e4c, 0x2e4c,
+0x2e4e, 0x2e4f,
+0x3001, 0x3002,
+0xa4fe, 0xa4ff,
+0xa60d, 0xa60f,
+0xa6f3, 0xa6f7,
+0xa876, 0xa877,
+0xa8ce, 0xa8cf,
+0xa92f, 0xa92f,
+0xa9c7, 0xa9c9,
+0xaa5d, 0xaa5f,
+0xaadf, 0xaadf,
+0xaaf0, 0xaaf1,
+0xabeb, 0xabeb,
+0xfe50, 0xfe52,
+0xfe54, 0xfe57,
+0xff01, 0xff01,
+0xff0c, 0xff0c,
+0xff0e, 0xff0e,
+0xff1a, 0xff1b,
+0xff1f, 0xff1f,
+0xff61, 0xff61,
+0xff64, 0xff64,
+0x1039f, 0x1039f,
+0x103d0, 0x103d0,
+0x10857, 0x10857,
+0x1091f, 0x1091f,
+0x10a56, 0x10a57,
+0x10af0, 0x10af5,
+0x10b3a, 0x10b3f,
+0x10b99, 0x10b9c,
+0x10f55, 0x10f59,
+0x11047, 0x1104d,
+0x110be, 0x110c1,
+0x11141, 0x11143,
+0x111c5, 0x111c6,
+0x111cd, 0x111cd,
+0x111de, 0x111df,
+0x11238, 0x1123c,
+0x112a9, 0x112a9,
+0x1144b, 0x1144d,
+0x1145b, 0x1145b,
+0x115c2, 0x115c5,
+0x115c9, 0x115d7,
+0x11641, 0x11642,
+0x1173c, 0x1173e,
+0x11a42, 0x11a43,
+0x11a9b, 0x11a9c,
+0x11aa1, 0x11aa2,
+0x11c41, 0x11c43,
+0x11c71, 0x11c71,
+0x11ef7, 0x11ef8,
+0x12470, 0x12474,
+0x16a6e, 0x16a6f,
+0x16af5, 0x16af5,
+0x16b37, 0x16b39,
+0x16b44, 0x16b44,
+0x16e97, 0x16e98,
+0x1bc9f, 0x1bc9f,
+0x1da87, 0x1da8a,
+}; /* END of CR_Terminal_Punctuation */
+
+/* PROPERTY: 'Thaana': Script */
+static const OnigCodePoint
+CR_Thaana[] = { 1,
+0x0780, 0x07b1,
+}; /* END of CR_Thaana */
+
+/* PROPERTY: 'Thai': Script */
+static const OnigCodePoint
+CR_Thai[] = { 2,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e5b,
+}; /* END of CR_Thai */
+
+/* PROPERTY: 'Tibetan': Script */
+static const OnigCodePoint
+CR_Tibetan[] = { 7,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fd4,
+0x0fd9, 0x0fda,
+}; /* END of CR_Tibetan */
+
+/* PROPERTY: 'Tifinagh': Script */
+static const OnigCodePoint
+CR_Tifinagh[] = { 3,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d7f,
+}; /* END of CR_Tifinagh */
+
+/* PROPERTY: 'Tirhuta': Script */
+static const OnigCodePoint
+CR_Tirhuta[] = { 2,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+}; /* END of CR_Tirhuta */
+
+/* PROPERTY: 'Ugaritic': Script */
+static const OnigCodePoint
+CR_Ugaritic[] = { 2,
+0x10380, 0x1039d,
+0x1039f, 0x1039f,
+}; /* END of CR_Ugaritic */
+
+/* PROPERTY: 'Unified_Ideograph': Binary Property */
+static const OnigCodePoint
+CR_Unified_Ideograph[] = { 14,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xfa0e, 0xfa0f,
+0xfa11, 0xfa11,
+0xfa13, 0xfa14,
+0xfa1f, 0xfa1f,
+0xfa21, 0xfa21,
+0xfa23, 0xfa24,
+0xfa27, 0xfa29,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+}; /* END of CR_Unified_Ideograph */
+
+/* PROPERTY: 'Unknown': Script */
+static const OnigCodePoint
+CR_Unknown[] = { 664,
+0x0378, 0x0379,
+0x0380, 0x0383,
+0x038b, 0x038b,
+0x038d, 0x038d,
+0x03a2, 0x03a2,
+0x0530, 0x0530,
+0x0557, 0x0558,
+0x058b, 0x058c,
+0x0590, 0x0590,
+0x05c8, 0x05cf,
+0x05eb, 0x05ee,
+0x05f5, 0x05ff,
+0x061d, 0x061d,
+0x070e, 0x070e,
+0x074b, 0x074c,
+0x07b2, 0x07bf,
+0x07fb, 0x07fc,
+0x082e, 0x082f,
+0x083f, 0x083f,
+0x085c, 0x085d,
+0x085f, 0x085f,
+0x086b, 0x089f,
+0x08b5, 0x08b5,
+0x08be, 0x08d2,
+0x0984, 0x0984,
+0x098d, 0x098e,
+0x0991, 0x0992,
+0x09a9, 0x09a9,
+0x09b1, 0x09b1,
+0x09b3, 0x09b5,
+0x09ba, 0x09bb,
+0x09c5, 0x09c6,
+0x09c9, 0x09ca,
+0x09cf, 0x09d6,
+0x09d8, 0x09db,
+0x09de, 0x09de,
+0x09e4, 0x09e5,
+0x09ff, 0x0a00,
+0x0a04, 0x0a04,
+0x0a0b, 0x0a0e,
+0x0a11, 0x0a12,
+0x0a29, 0x0a29,
+0x0a31, 0x0a31,
+0x0a34, 0x0a34,
+0x0a37, 0x0a37,
+0x0a3a, 0x0a3b,
+0x0a3d, 0x0a3d,
+0x0a43, 0x0a46,
+0x0a49, 0x0a4a,
+0x0a4e, 0x0a50,
+0x0a52, 0x0a58,
+0x0a5d, 0x0a5d,
+0x0a5f, 0x0a65,
+0x0a77, 0x0a80,
+0x0a84, 0x0a84,
+0x0a8e, 0x0a8e,
+0x0a92, 0x0a92,
+0x0aa9, 0x0aa9,
+0x0ab1, 0x0ab1,
+0x0ab4, 0x0ab4,
+0x0aba, 0x0abb,
+0x0ac6, 0x0ac6,
+0x0aca, 0x0aca,
+0x0ace, 0x0acf,
+0x0ad1, 0x0adf,
+0x0ae4, 0x0ae5,
+0x0af2, 0x0af8,
+0x0b00, 0x0b00,
+0x0b04, 0x0b04,
+0x0b0d, 0x0b0e,
+0x0b11, 0x0b12,
+0x0b29, 0x0b29,
+0x0b31, 0x0b31,
+0x0b34, 0x0b34,
+0x0b3a, 0x0b3b,
+0x0b45, 0x0b46,
+0x0b49, 0x0b4a,
+0x0b4e, 0x0b55,
+0x0b58, 0x0b5b,
+0x0b5e, 0x0b5e,
+0x0b64, 0x0b65,
+0x0b78, 0x0b81,
+0x0b84, 0x0b84,
+0x0b8b, 0x0b8d,
+0x0b91, 0x0b91,
+0x0b96, 0x0b98,
+0x0b9b, 0x0b9b,
+0x0b9d, 0x0b9d,
+0x0ba0, 0x0ba2,
+0x0ba5, 0x0ba7,
+0x0bab, 0x0bad,
+0x0bba, 0x0bbd,
+0x0bc3, 0x0bc5,
+0x0bc9, 0x0bc9,
+0x0bce, 0x0bcf,
+0x0bd1, 0x0bd6,
+0x0bd8, 0x0be5,
+0x0bfb, 0x0bff,
+0x0c0d, 0x0c0d,
+0x0c11, 0x0c11,
+0x0c29, 0x0c29,
+0x0c3a, 0x0c3c,
+0x0c45, 0x0c45,
+0x0c49, 0x0c49,
+0x0c4e, 0x0c54,
+0x0c57, 0x0c57,
+0x0c5b, 0x0c5f,
+0x0c64, 0x0c65,
+0x0c70, 0x0c76,
+0x0c8d, 0x0c8d,
+0x0c91, 0x0c91,
+0x0ca9, 0x0ca9,
+0x0cb4, 0x0cb4,
+0x0cba, 0x0cbb,
+0x0cc5, 0x0cc5,
+0x0cc9, 0x0cc9,
+0x0cce, 0x0cd4,
+0x0cd7, 0x0cdd,
+0x0cdf, 0x0cdf,
+0x0ce4, 0x0ce5,
+0x0cf0, 0x0cf0,
+0x0cf3, 0x0cff,
+0x0d04, 0x0d04,
+0x0d0d, 0x0d0d,
+0x0d11, 0x0d11,
+0x0d45, 0x0d45,
+0x0d49, 0x0d49,
+0x0d50, 0x0d53,
+0x0d64, 0x0d65,
+0x0d80, 0x0d81,
+0x0d84, 0x0d84,
+0x0d97, 0x0d99,
+0x0db2, 0x0db2,
+0x0dbc, 0x0dbc,
+0x0dbe, 0x0dbf,
+0x0dc7, 0x0dc9,
+0x0dcb, 0x0dce,
+0x0dd5, 0x0dd5,
+0x0dd7, 0x0dd7,
+0x0de0, 0x0de5,
+0x0df0, 0x0df1,
+0x0df5, 0x0e00,
+0x0e3b, 0x0e3e,
+0x0e5c, 0x0e80,
+0x0e83, 0x0e83,
+0x0e85, 0x0e85,
+0x0e8b, 0x0e8b,
+0x0ea4, 0x0ea4,
+0x0ea6, 0x0ea6,
+0x0ebe, 0x0ebf,
+0x0ec5, 0x0ec5,
+0x0ec7, 0x0ec7,
+0x0ece, 0x0ecf,
+0x0eda, 0x0edb,
+0x0ee0, 0x0eff,
+0x0f48, 0x0f48,
+0x0f6d, 0x0f70,
+0x0f98, 0x0f98,
+0x0fbd, 0x0fbd,
+0x0fcd, 0x0fcd,
+0x0fdb, 0x0fff,
+0x10c6, 0x10c6,
+0x10c8, 0x10cc,
+0x10ce, 0x10cf,
+0x1249, 0x1249,
+0x124e, 0x124f,
+0x1257, 0x1257,
+0x1259, 0x1259,
+0x125e, 0x125f,
+0x1289, 0x1289,
+0x128e, 0x128f,
+0x12b1, 0x12b1,
+0x12b6, 0x12b7,
+0x12bf, 0x12bf,
+0x12c1, 0x12c1,
+0x12c6, 0x12c7,
+0x12d7, 0x12d7,
+0x1311, 0x1311,
+0x1316, 0x1317,
+0x135b, 0x135c,
+0x137d, 0x137f,
+0x139a, 0x139f,
+0x13f6, 0x13f7,
+0x13fe, 0x13ff,
+0x169d, 0x169f,
+0x16f9, 0x16ff,
+0x170d, 0x170d,
+0x1715, 0x171f,
+0x1737, 0x173f,
+0x1754, 0x175f,
+0x176d, 0x176d,
+0x1771, 0x1771,
+0x1774, 0x177f,
+0x17de, 0x17df,
+0x17ea, 0x17ef,
+0x17fa, 0x17ff,
+0x180f, 0x180f,
+0x181a, 0x181f,
+0x1879, 0x187f,
+0x18ab, 0x18af,
+0x18f6, 0x18ff,
+0x191f, 0x191f,
+0x192c, 0x192f,
+0x193c, 0x193f,
+0x1941, 0x1943,
+0x196e, 0x196f,
+0x1975, 0x197f,
+0x19ac, 0x19af,
+0x19ca, 0x19cf,
+0x19db, 0x19dd,
+0x1a1c, 0x1a1d,
+0x1a5f, 0x1a5f,
+0x1a7d, 0x1a7e,
+0x1a8a, 0x1a8f,
+0x1a9a, 0x1a9f,
+0x1aae, 0x1aaf,
+0x1abf, 0x1aff,
+0x1b4c, 0x1b4f,
+0x1b7d, 0x1b7f,
+0x1bf4, 0x1bfb,
+0x1c38, 0x1c3a,
+0x1c4a, 0x1c4c,
+0x1c89, 0x1c8f,
+0x1cbb, 0x1cbc,
+0x1cc8, 0x1ccf,
+0x1cfb, 0x1cff,
+0x1dfa, 0x1dfa,
+0x1f16, 0x1f17,
+0x1f1e, 0x1f1f,
+0x1f46, 0x1f47,
+0x1f4e, 0x1f4f,
+0x1f58, 0x1f58,
+0x1f5a, 0x1f5a,
+0x1f5c, 0x1f5c,
+0x1f5e, 0x1f5e,
+0x1f7e, 0x1f7f,
+0x1fb5, 0x1fb5,
+0x1fc5, 0x1fc5,
+0x1fd4, 0x1fd5,
+0x1fdc, 0x1fdc,
+0x1ff0, 0x1ff1,
+0x1ff5, 0x1ff5,
+0x1fff, 0x1fff,
+0x2065, 0x2065,
+0x2072, 0x2073,
+0x208f, 0x208f,
+0x209d, 0x209f,
+0x20c0, 0x20cf,
+0x20f1, 0x20ff,
+0x218c, 0x218f,
+0x2427, 0x243f,
+0x244b, 0x245f,
+0x2b74, 0x2b75,
+0x2b96, 0x2b97,
+0x2c2f, 0x2c2f,
+0x2c5f, 0x2c5f,
+0x2cf4, 0x2cf8,
+0x2d26, 0x2d26,
+0x2d28, 0x2d2c,
+0x2d2e, 0x2d2f,
+0x2d68, 0x2d6e,
+0x2d71, 0x2d7e,
+0x2d97, 0x2d9f,
+0x2da7, 0x2da7,
+0x2daf, 0x2daf,
+0x2db7, 0x2db7,
+0x2dbf, 0x2dbf,
+0x2dc7, 0x2dc7,
+0x2dcf, 0x2dcf,
+0x2dd7, 0x2dd7,
+0x2ddf, 0x2ddf,
+0x2e50, 0x2e7f,
+0x2e9a, 0x2e9a,
+0x2ef4, 0x2eff,
+0x2fd6, 0x2fef,
+0x2ffc, 0x2fff,
+0x3040, 0x3040,
+0x3097, 0x3098,
+0x3100, 0x3104,
+0x3130, 0x3130,
+0x318f, 0x318f,
+0x31bb, 0x31bf,
+0x31e4, 0x31ef,
+0x321f, 0x321f,
+0x4db6, 0x4dbf,
+0x9ff0, 0x9fff,
+0xa48d, 0xa48f,
+0xa4c7, 0xa4cf,
+0xa62c, 0xa63f,
+0xa6f8, 0xa6ff,
+0xa7c0, 0xa7c1,
+0xa7c7, 0xa7f6,
+0xa82c, 0xa82f,
+0xa83a, 0xa83f,
+0xa878, 0xa87f,
+0xa8c6, 0xa8cd,
+0xa8da, 0xa8df,
+0xa954, 0xa95e,
+0xa97d, 0xa97f,
+0xa9ce, 0xa9ce,
+0xa9da, 0xa9dd,
+0xa9ff, 0xa9ff,
+0xaa37, 0xaa3f,
+0xaa4e, 0xaa4f,
+0xaa5a, 0xaa5b,
+0xaac3, 0xaada,
+0xaaf7, 0xab00,
+0xab07, 0xab08,
+0xab0f, 0xab10,
+0xab17, 0xab1f,
+0xab27, 0xab27,
+0xab2f, 0xab2f,
+0xab68, 0xab6f,
+0xabee, 0xabef,
+0xabfa, 0xabff,
+0xd7a4, 0xd7af,
+0xd7c7, 0xd7ca,
+0xd7fc, 0xf8ff,
+0xfa6e, 0xfa6f,
+0xfada, 0xfaff,
+0xfb07, 0xfb12,
+0xfb18, 0xfb1c,
+0xfb37, 0xfb37,
+0xfb3d, 0xfb3d,
+0xfb3f, 0xfb3f,
+0xfb42, 0xfb42,
+0xfb45, 0xfb45,
+0xfbc2, 0xfbd2,
+0xfd40, 0xfd4f,
+0xfd90, 0xfd91,
+0xfdc8, 0xfdef,
+0xfdfe, 0xfdff,
+0xfe1a, 0xfe1f,
+0xfe53, 0xfe53,
+0xfe67, 0xfe67,
+0xfe6c, 0xfe6f,
+0xfe75, 0xfe75,
+0xfefd, 0xfefe,
+0xff00, 0xff00,
+0xffbf, 0xffc1,
+0xffc8, 0xffc9,
+0xffd0, 0xffd1,
+0xffd8, 0xffd9,
+0xffdd, 0xffdf,
+0xffe7, 0xffe7,
+0xffef, 0xfff8,
+0xfffe, 0xffff,
+0x1000c, 0x1000c,
+0x10027, 0x10027,
+0x1003b, 0x1003b,
+0x1003e, 0x1003e,
+0x1004e, 0x1004f,
+0x1005e, 0x1007f,
+0x100fb, 0x100ff,
+0x10103, 0x10106,
+0x10134, 0x10136,
+0x1018f, 0x1018f,
+0x1019c, 0x1019f,
+0x101a1, 0x101cf,
+0x101fe, 0x1027f,
+0x1029d, 0x1029f,
+0x102d1, 0x102df,
+0x102fc, 0x102ff,
+0x10324, 0x1032c,
+0x1034b, 0x1034f,
+0x1037b, 0x1037f,
+0x1039e, 0x1039e,
+0x103c4, 0x103c7,
+0x103d6, 0x103ff,
+0x1049e, 0x1049f,
+0x104aa, 0x104af,
+0x104d4, 0x104d7,
+0x104fc, 0x104ff,
+0x10528, 0x1052f,
+0x10564, 0x1056e,
+0x10570, 0x105ff,
+0x10737, 0x1073f,
+0x10756, 0x1075f,
+0x10768, 0x107ff,
+0x10806, 0x10807,
+0x10809, 0x10809,
+0x10836, 0x10836,
+0x10839, 0x1083b,
+0x1083d, 0x1083e,
+0x10856, 0x10856,
+0x1089f, 0x108a6,
+0x108b0, 0x108df,
+0x108f3, 0x108f3,
+0x108f6, 0x108fa,
+0x1091c, 0x1091e,
+0x1093a, 0x1093e,
+0x10940, 0x1097f,
+0x109b8, 0x109bb,
+0x109d0, 0x109d1,
+0x10a04, 0x10a04,
+0x10a07, 0x10a0b,
+0x10a14, 0x10a14,
+0x10a18, 0x10a18,
+0x10a36, 0x10a37,
+0x10a3b, 0x10a3e,
+0x10a49, 0x10a4f,
+0x10a59, 0x10a5f,
+0x10aa0, 0x10abf,
+0x10ae7, 0x10aea,
+0x10af7, 0x10aff,
+0x10b36, 0x10b38,
+0x10b56, 0x10b57,
+0x10b73, 0x10b77,
+0x10b92, 0x10b98,
+0x10b9d, 0x10ba8,
+0x10bb0, 0x10bff,
+0x10c49, 0x10c7f,
+0x10cb3, 0x10cbf,
+0x10cf3, 0x10cf9,
+0x10d28, 0x10d2f,
+0x10d3a, 0x10e5f,
+0x10e7f, 0x10eff,
+0x10f28, 0x10f2f,
+0x10f5a, 0x10fdf,
+0x10ff7, 0x10fff,
+0x1104e, 0x11051,
+0x11070, 0x1107e,
+0x110c2, 0x110cc,
+0x110ce, 0x110cf,
+0x110e9, 0x110ef,
+0x110fa, 0x110ff,
+0x11135, 0x11135,
+0x11147, 0x1114f,
+0x11177, 0x1117f,
+0x111ce, 0x111cf,
+0x111e0, 0x111e0,
+0x111f5, 0x111ff,
+0x11212, 0x11212,
+0x1123f, 0x1127f,
+0x11287, 0x11287,
+0x11289, 0x11289,
+0x1128e, 0x1128e,
+0x1129e, 0x1129e,
+0x112aa, 0x112af,
+0x112eb, 0x112ef,
+0x112fa, 0x112ff,
+0x11304, 0x11304,
+0x1130d, 0x1130e,
+0x11311, 0x11312,
+0x11329, 0x11329,
+0x11331, 0x11331,
+0x11334, 0x11334,
+0x1133a, 0x1133a,
+0x11345, 0x11346,
+0x11349, 0x1134a,
+0x1134e, 0x1134f,
+0x11351, 0x11356,
+0x11358, 0x1135c,
+0x11364, 0x11365,
+0x1136d, 0x1136f,
+0x11375, 0x113ff,
+0x1145a, 0x1145a,
+0x1145c, 0x1145c,
+0x11460, 0x1147f,
+0x114c8, 0x114cf,
+0x114da, 0x1157f,
+0x115b6, 0x115b7,
+0x115de, 0x115ff,
+0x11645, 0x1164f,
+0x1165a, 0x1165f,
+0x1166d, 0x1167f,
+0x116b9, 0x116bf,
+0x116ca, 0x116ff,
+0x1171b, 0x1171c,
+0x1172c, 0x1172f,
+0x11740, 0x117ff,
+0x1183c, 0x1189f,
+0x118f3, 0x118fe,
+0x11900, 0x1199f,
+0x119a8, 0x119a9,
+0x119d8, 0x119d9,
+0x119e5, 0x119ff,
+0x11a48, 0x11a4f,
+0x11aa3, 0x11abf,
+0x11af9, 0x11bff,
+0x11c09, 0x11c09,
+0x11c37, 0x11c37,
+0x11c46, 0x11c4f,
+0x11c6d, 0x11c6f,
+0x11c90, 0x11c91,
+0x11ca8, 0x11ca8,
+0x11cb7, 0x11cff,
+0x11d07, 0x11d07,
+0x11d0a, 0x11d0a,
+0x11d37, 0x11d39,
+0x11d3b, 0x11d3b,
+0x11d3e, 0x11d3e,
+0x11d48, 0x11d4f,
+0x11d5a, 0x11d5f,
+0x11d66, 0x11d66,
+0x11d69, 0x11d69,
+0x11d8f, 0x11d8f,
+0x11d92, 0x11d92,
+0x11d99, 0x11d9f,
+0x11daa, 0x11edf,
+0x11ef9, 0x11fbf,
+0x11ff2, 0x11ffe,
+0x1239a, 0x123ff,
+0x1246f, 0x1246f,
+0x12475, 0x1247f,
+0x12544, 0x12fff,
+0x1342f, 0x1342f,
+0x13439, 0x143ff,
+0x14647, 0x167ff,
+0x16a39, 0x16a3f,
+0x16a5f, 0x16a5f,
+0x16a6a, 0x16a6d,
+0x16a70, 0x16acf,
+0x16aee, 0x16aef,
+0x16af6, 0x16aff,
+0x16b46, 0x16b4f,
+0x16b5a, 0x16b5a,
+0x16b62, 0x16b62,
+0x16b78, 0x16b7c,
+0x16b90, 0x16e3f,
+0x16e9b, 0x16eff,
+0x16f4b, 0x16f4e,
+0x16f88, 0x16f8e,
+0x16fa0, 0x16fdf,
+0x16fe4, 0x16fff,
+0x187f8, 0x187ff,
+0x18af3, 0x1afff,
+0x1b11f, 0x1b14f,
+0x1b153, 0x1b163,
+0x1b168, 0x1b16f,
+0x1b2fc, 0x1bbff,
+0x1bc6b, 0x1bc6f,
+0x1bc7d, 0x1bc7f,
+0x1bc89, 0x1bc8f,
+0x1bc9a, 0x1bc9b,
+0x1bca4, 0x1cfff,
+0x1d0f6, 0x1d0ff,
+0x1d127, 0x1d128,
+0x1d1e9, 0x1d1ff,
+0x1d246, 0x1d2df,
+0x1d2f4, 0x1d2ff,
+0x1d357, 0x1d35f,
+0x1d379, 0x1d3ff,
+0x1d455, 0x1d455,
+0x1d49d, 0x1d49d,
+0x1d4a0, 0x1d4a1,
+0x1d4a3, 0x1d4a4,
+0x1d4a7, 0x1d4a8,
+0x1d4ad, 0x1d4ad,
+0x1d4ba, 0x1d4ba,
+0x1d4bc, 0x1d4bc,
+0x1d4c4, 0x1d4c4,
+0x1d506, 0x1d506,
+0x1d50b, 0x1d50c,
+0x1d515, 0x1d515,
+0x1d51d, 0x1d51d,
+0x1d53a, 0x1d53a,
+0x1d53f, 0x1d53f,
+0x1d545, 0x1d545,
+0x1d547, 0x1d549,
+0x1d551, 0x1d551,
+0x1d6a6, 0x1d6a7,
+0x1d7cc, 0x1d7cd,
+0x1da8c, 0x1da9a,
+0x1daa0, 0x1daa0,
+0x1dab0, 0x1dfff,
+0x1e007, 0x1e007,
+0x1e019, 0x1e01a,
+0x1e022, 0x1e022,
+0x1e025, 0x1e025,
+0x1e02b, 0x1e0ff,
+0x1e12d, 0x1e12f,
+0x1e13e, 0x1e13f,
+0x1e14a, 0x1e14d,
+0x1e150, 0x1e2bf,
+0x1e2fa, 0x1e2fe,
+0x1e300, 0x1e7ff,
+0x1e8c5, 0x1e8c6,
+0x1e8d7, 0x1e8ff,
+0x1e94c, 0x1e94f,
+0x1e95a, 0x1e95d,
+0x1e960, 0x1ec70,
+0x1ecb5, 0x1ed00,
+0x1ed3e, 0x1edff,
+0x1ee04, 0x1ee04,
+0x1ee20, 0x1ee20,
+0x1ee23, 0x1ee23,
+0x1ee25, 0x1ee26,
+0x1ee28, 0x1ee28,
+0x1ee33, 0x1ee33,
+0x1ee38, 0x1ee38,
+0x1ee3a, 0x1ee3a,
+0x1ee3c, 0x1ee41,
+0x1ee43, 0x1ee46,
+0x1ee48, 0x1ee48,
+0x1ee4a, 0x1ee4a,
+0x1ee4c, 0x1ee4c,
+0x1ee50, 0x1ee50,
+0x1ee53, 0x1ee53,
+0x1ee55, 0x1ee56,
+0x1ee58, 0x1ee58,
+0x1ee5a, 0x1ee5a,
+0x1ee5c, 0x1ee5c,
+0x1ee5e, 0x1ee5e,
+0x1ee60, 0x1ee60,
+0x1ee63, 0x1ee63,
+0x1ee65, 0x1ee66,
+0x1ee6b, 0x1ee6b,
+0x1ee73, 0x1ee73,
+0x1ee78, 0x1ee78,
+0x1ee7d, 0x1ee7d,
+0x1ee7f, 0x1ee7f,
+0x1ee8a, 0x1ee8a,
+0x1ee9c, 0x1eea0,
+0x1eea4, 0x1eea4,
+0x1eeaa, 0x1eeaa,
+0x1eebc, 0x1eeef,
+0x1eef2, 0x1efff,
+0x1f02c, 0x1f02f,
+0x1f094, 0x1f09f,
+0x1f0af, 0x1f0b0,
+0x1f0c0, 0x1f0c0,
+0x1f0d0, 0x1f0d0,
+0x1f0f6, 0x1f0ff,
+0x1f10d, 0x1f10f,
+0x1f16d, 0x1f16f,
+0x1f1ad, 0x1f1e5,
+0x1f203, 0x1f20f,
+0x1f23c, 0x1f23f,
+0x1f249, 0x1f24f,
+0x1f252, 0x1f25f,
+0x1f266, 0x1f2ff,
+0x1f6d6, 0x1f6df,
+0x1f6ed, 0x1f6ef,
+0x1f6fb, 0x1f6ff,
+0x1f774, 0x1f77f,
+0x1f7d9, 0x1f7df,
+0x1f7ec, 0x1f7ff,
+0x1f80c, 0x1f80f,
+0x1f848, 0x1f84f,
+0x1f85a, 0x1f85f,
+0x1f888, 0x1f88f,
+0x1f8ae, 0x1f8ff,
+0x1f90c, 0x1f90c,
+0x1f972, 0x1f972,
+0x1f977, 0x1f979,
+0x1f9a3, 0x1f9a4,
+0x1f9ab, 0x1f9ad,
+0x1f9cb, 0x1f9cc,
+0x1fa54, 0x1fa5f,
+0x1fa6e, 0x1fa6f,
+0x1fa74, 0x1fa77,
+0x1fa7b, 0x1fa7f,
+0x1fa83, 0x1fa8f,
+0x1fa96, 0x1ffff,
+0x2a6d7, 0x2a6ff,
+0x2b735, 0x2b73f,
+0x2b81e, 0x2b81f,
+0x2cea2, 0x2ceaf,
+0x2ebe1, 0x2f7ff,
+0x2fa1e, 0xe0000,
+0xe0002, 0xe001f,
+0xe0080, 0xe00ff,
+0xe01f0, 0x10ffff,
+}; /* END of CR_Unknown */
+
+/* PROPERTY: 'Uppercase': Derived Property */
+#define CR_Uppercase CR_Upper
+
+/* PROPERTY: 'Vai': Script */
+static const OnigCodePoint
+CR_Vai[] = { 1,
+0xa500, 0xa62b,
+}; /* END of CR_Vai */
+
+/* PROPERTY: 'Variation_Selector': Binary Property */
+static const OnigCodePoint
+CR_Variation_Selector[] = { 3,
+0x180b, 0x180d,
+0xfe00, 0xfe0f,
+0xe0100, 0xe01ef,
+}; /* END of CR_Variation_Selector */
+
+/* PROPERTY: 'Wancho': Script */
+static const OnigCodePoint
+CR_Wancho[] = { 2,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+}; /* END of CR_Wancho */
+
+/* PROPERTY: 'Warang_Citi': Script */
+static const OnigCodePoint
+CR_Warang_Citi[] = { 2,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+}; /* END of CR_Warang_Citi */
+
+/* PROPERTY: 'White_Space': Binary Property */
+#define CR_White_Space CR_Space
+
+/* PROPERTY: 'XID_Continue': Derived Property */
+static const OnigCodePoint
+CR_XID_Continue[] = { 720,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x005f, 0x005f,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00b7, 0x00b7,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0300, 0x0374,
+0x0376, 0x0377,
+0x037b, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x0483, 0x0487,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06df, 0x06e8,
+0x06ea, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07f5,
+0x07fa, 0x07fa,
+0x07fd, 0x07fd,
+0x0800, 0x082d,
+0x0840, 0x085b,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x08e1,
+0x08e3, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x09fe, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e4e,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f18, 0x0f19,
+0x0f20, 0x0f29,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f84,
+0x0f86, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x1000, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x135f,
+0x1369, 0x1371,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1734,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17d3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dd,
+0x17e0, 0x17e9,
+0x180b, 0x180d,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1ab0, 0x1abd,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b6b, 0x1b73,
+0x1b80, 0x1bf3,
+0x1c00, 0x1c37,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x203f, 0x2040,
+0x2054, 0x2054,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x20d0, 0x20dc,
+0x20e1, 0x20e1,
+0x20e5, 0x20f0,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2118, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x3005, 0x3007,
+0x3021, 0x302f,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x3099, 0x309a,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa66f,
+0xa674, 0xa67d,
+0xa67f, 0xa6f1,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8e0, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92d,
+0xa930, 0xa953,
+0xa960, 0xa97c,
+0xa980, 0xa9c0,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabec, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfc5d,
+0xfc64, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdf9,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0xfe33, 0xfe34,
+0xfe4d, 0xfe4f,
+0xfe71, 0xfe71,
+0xfe73, 0xfe73,
+0xfe77, 0xfe77,
+0xfe79, 0xfe79,
+0xfe7b, 0xfe7b,
+0xfe7d, 0xfe7d,
+0xfe7f, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff3f, 0xff3f,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x101fd, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102e0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae6,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f50,
+0x10fe0, 0x10ff6,
+0x11000, 0x11046,
+0x11066, 0x1106f,
+0x1107f, 0x110ba,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11173,
+0x11176, 0x11176,
+0x11180, 0x111c4,
+0x111c9, 0x111cc,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x1144a,
+0x11450, 0x11459,
+0x1145e, 0x1145f,
+0x11480, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115c0,
+0x115d8, 0x115dd,
+0x11600, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x11739,
+0x11800, 0x1183a,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a50, 0x11a99,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af4,
+0x16b00, 0x16b36,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e8d0, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0100, 0xe01ef,
+}; /* END of CR_XID_Continue */
+
+/* PROPERTY: 'XID_Start': Derived Property */
+static const OnigCodePoint
+CR_XID_Start[] = { 616,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037b, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0620, 0x064a,
+0x066e, 0x066f,
+0x0671, 0x06d3,
+0x06d5, 0x06d5,
+0x06e5, 0x06e6,
+0x06ee, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x0710,
+0x0712, 0x072f,
+0x074d, 0x07a5,
+0x07b1, 0x07b1,
+0x07ca, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0815,
+0x081a, 0x081a,
+0x0824, 0x0824,
+0x0828, 0x0828,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x0904, 0x0939,
+0x093d, 0x093d,
+0x0950, 0x0950,
+0x0958, 0x0961,
+0x0971, 0x0980,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09bd,
+0x09ce, 0x09ce,
+0x09dc, 0x09dd,
+0x09df, 0x09e1,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a72, 0x0a74,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0abd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae1,
+0x0af9, 0x0af9,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b3d,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b61,
+0x0b71, 0x0b71,
+0x0b83, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bd0, 0x0bd0,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c3d,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c61,
+0x0c80, 0x0c80,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cbd,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce1,
+0x0cf1, 0x0cf2,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d3d,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d56,
+0x0d5f, 0x0d61,
+0x0d7a, 0x0d7f,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0e01, 0x0e30,
+0x0e32, 0x0e32,
+0x0e40, 0x0e46,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb0,
+0x0eb2, 0x0eb2,
+0x0ebd, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f88, 0x0f8c,
+0x1000, 0x102a,
+0x103f, 0x103f,
+0x1050, 0x1055,
+0x105a, 0x105d,
+0x1061, 0x1061,
+0x1065, 0x1066,
+0x106e, 0x1070,
+0x1075, 0x1081,
+0x108e, 0x108e,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1711,
+0x1720, 0x1731,
+0x1740, 0x1751,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1780, 0x17b3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x1820, 0x1878,
+0x1880, 0x18a8,
+0x18aa, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a16,
+0x1a20, 0x1a54,
+0x1aa7, 0x1aa7,
+0x1b05, 0x1b33,
+0x1b45, 0x1b4b,
+0x1b83, 0x1ba0,
+0x1bae, 0x1baf,
+0x1bba, 0x1be5,
+0x1c00, 0x1c23,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2118, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa640, 0xa66e,
+0xa67f, 0xa69d,
+0xa6a0, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa801,
+0xa803, 0xa805,
+0xa807, 0xa80a,
+0xa80c, 0xa822,
+0xa840, 0xa873,
+0xa882, 0xa8b3,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8fe,
+0xa90a, 0xa925,
+0xa930, 0xa946,
+0xa960, 0xa97c,
+0xa984, 0xa9b2,
+0xa9cf, 0xa9cf,
+0xa9e0, 0xa9e4,
+0xa9e6, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa28,
+0xaa40, 0xaa42,
+0xaa44, 0xaa4b,
+0xaa60, 0xaa76,
+0xaa7a, 0xaa7a,
+0xaa7e, 0xaaaf,
+0xaab1, 0xaab1,
+0xaab5, 0xaab6,
+0xaab9, 0xaabd,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaea,
+0xaaf2, 0xaaf4,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabe2,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb1d,
+0xfb1f, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfc5d,
+0xfc64, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdf9,
+0xfe71, 0xfe71,
+0xfe73, 0xfe73,
+0xfe77, 0xfe77,
+0xfe79, 0xfe79,
+0xfe7b, 0xfe7b,
+0xfe7d, 0xfe7d,
+0xfe7f, 0xfefc,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xff9d,
+0xffa0, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x10375,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a00,
+0x10a10, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d23,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11003, 0x11037,
+0x11083, 0x110af,
+0x110d0, 0x110e8,
+0x11103, 0x11126,
+0x11144, 0x11144,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11183, 0x111b2,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x1122b,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112de,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x1133d,
+0x11350, 0x11350,
+0x1135d, 0x11361,
+0x11400, 0x11434,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114af,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115ae,
+0x115d8, 0x115db,
+0x11600, 0x1162f,
+0x11644, 0x11644,
+0x11680, 0x116aa,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x11800, 0x1182b,
+0x118a0, 0x118df,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d0,
+0x119e1, 0x119e1,
+0x119e3, 0x119e3,
+0x11a00, 0x11a00,
+0x11a0b, 0x11a32,
+0x11a3a, 0x11a3a,
+0x11a50, 0x11a50,
+0x11a5c, 0x11a89,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c2e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d30,
+0x11d46, 0x11d46,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d89,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef2,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f50, 0x16f50,
+0x16f93, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e94b, 0x1e94b,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_XID_Start */
+
+/* PROPERTY: 'Yi': Script */
+static const OnigCodePoint
+CR_Yi[] = { 2,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+}; /* END of CR_Yi */
+
+/* PROPERTY: 'Z': Major Category */
+static const OnigCodePoint
+CR_Z[] = { 8,
+0x0020, 0x0020,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x2028, 0x2029,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Z */
+
+/* PROPERTY: 'Zanabazar_Square': Script */
+static const OnigCodePoint
+CR_Zanabazar_Square[] = { 1,
+0x11a00, 0x11a47,
+}; /* END of CR_Zanabazar_Square */
+
+/* PROPERTY: 'Zl': General Category */
+static const OnigCodePoint
+CR_Zl[] = { 1,
+0x2028, 0x2028,
+}; /* END of CR_Zl */
+
+/* PROPERTY: 'Zp': General Category */
+static const OnigCodePoint
+CR_Zp[] = { 1,
+0x2029, 0x2029,
+}; /* END of CR_Zp */
+
+/* PROPERTY: 'Zs': General Category */
+static const OnigCodePoint
+CR_Zs[] = { 7,
+0x0020, 0x0020,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Zs */
+
+/* PROPERTY: 'In_Basic_Latin': Block */
+#define CR_In_Basic_Latin CR_ASCII
+
+/* PROPERTY: 'In_Latin_1_Supplement': Block */
+static const OnigCodePoint
+CR_In_Latin_1_Supplement[] = { 1,
+0x0080, 0x00ff,
+}; /* END of CR_In_Latin_1_Supplement */
+
+/* PROPERTY: 'In_Latin_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_A[] = { 1,
+0x0100, 0x017f,
+}; /* END of CR_In_Latin_Extended_A */
+
+/* PROPERTY: 'In_Latin_Extended_B': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_B[] = { 1,
+0x0180, 0x024f,
+}; /* END of CR_In_Latin_Extended_B */
+
+/* PROPERTY: 'In_IPA_Extensions': Block */
+static const OnigCodePoint
+CR_In_IPA_Extensions[] = { 1,
+0x0250, 0x02af,
+}; /* END of CR_In_IPA_Extensions */
+
+/* PROPERTY: 'In_Spacing_Modifier_Letters': Block */
+static const OnigCodePoint
+CR_In_Spacing_Modifier_Letters[] = { 1,
+0x02b0, 0x02ff,
+}; /* END of CR_In_Spacing_Modifier_Letters */
+
+/* PROPERTY: 'In_Combining_Diacritical_Marks': Block */
+static const OnigCodePoint
+CR_In_Combining_Diacritical_Marks[] = { 1,
+0x0300, 0x036f,
+}; /* END of CR_In_Combining_Diacritical_Marks */
+
+/* PROPERTY: 'In_Greek_and_Coptic': Block */
+static const OnigCodePoint
+CR_In_Greek_and_Coptic[] = { 1,
+0x0370, 0x03ff,
+}; /* END of CR_In_Greek_and_Coptic */
+
+/* PROPERTY: 'In_Cyrillic': Block */
+static const OnigCodePoint
+CR_In_Cyrillic[] = { 1,
+0x0400, 0x04ff,
+}; /* END of CR_In_Cyrillic */
+
+/* PROPERTY: 'In_Cyrillic_Supplement': Block */
+static const OnigCodePoint
+CR_In_Cyrillic_Supplement[] = { 1,
+0x0500, 0x052f,
+}; /* END of CR_In_Cyrillic_Supplement */
+
+/* PROPERTY: 'In_Armenian': Block */
+static const OnigCodePoint
+CR_In_Armenian[] = { 1,
+0x0530, 0x058f,
+}; /* END of CR_In_Armenian */
+
+/* PROPERTY: 'In_Hebrew': Block */
+static const OnigCodePoint
+CR_In_Hebrew[] = { 1,
+0x0590, 0x05ff,
+}; /* END of CR_In_Hebrew */
+
+/* PROPERTY: 'In_Arabic': Block */
+static const OnigCodePoint
+CR_In_Arabic[] = { 1,
+0x0600, 0x06ff,
+}; /* END of CR_In_Arabic */
+
+/* PROPERTY: 'In_Syriac': Block */
+static const OnigCodePoint
+CR_In_Syriac[] = { 1,
+0x0700, 0x074f,
+}; /* END of CR_In_Syriac */
+
+/* PROPERTY: 'In_Arabic_Supplement': Block */
+static const OnigCodePoint
+CR_In_Arabic_Supplement[] = { 1,
+0x0750, 0x077f,
+}; /* END of CR_In_Arabic_Supplement */
+
+/* PROPERTY: 'In_Thaana': Block */
+static const OnigCodePoint
+CR_In_Thaana[] = { 1,
+0x0780, 0x07bf,
+}; /* END of CR_In_Thaana */
+
+/* PROPERTY: 'In_NKo': Block */
+static const OnigCodePoint
+CR_In_NKo[] = { 1,
+0x07c0, 0x07ff,
+}; /* END of CR_In_NKo */
+
+/* PROPERTY: 'In_Samaritan': Block */
+static const OnigCodePoint
+CR_In_Samaritan[] = { 1,
+0x0800, 0x083f,
+}; /* END of CR_In_Samaritan */
+
+/* PROPERTY: 'In_Mandaic': Block */
+static const OnigCodePoint
+CR_In_Mandaic[] = { 1,
+0x0840, 0x085f,
+}; /* END of CR_In_Mandaic */
+
+/* PROPERTY: 'In_Syriac_Supplement': Block */
+static const OnigCodePoint
+CR_In_Syriac_Supplement[] = { 1,
+0x0860, 0x086f,
+}; /* END of CR_In_Syriac_Supplement */
+
+/* PROPERTY: 'In_Arabic_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Arabic_Extended_A[] = { 1,
+0x08a0, 0x08ff,
+}; /* END of CR_In_Arabic_Extended_A */
+
+/* PROPERTY: 'In_Devanagari': Block */
+static const OnigCodePoint
+CR_In_Devanagari[] = { 1,
+0x0900, 0x097f,
+}; /* END of CR_In_Devanagari */
+
+/* PROPERTY: 'In_Bengali': Block */
+static const OnigCodePoint
+CR_In_Bengali[] = { 1,
+0x0980, 0x09ff,
+}; /* END of CR_In_Bengali */
+
+/* PROPERTY: 'In_Gurmukhi': Block */
+static const OnigCodePoint
+CR_In_Gurmukhi[] = { 1,
+0x0a00, 0x0a7f,
+}; /* END of CR_In_Gurmukhi */
+
+/* PROPERTY: 'In_Gujarati': Block */
+static const OnigCodePoint
+CR_In_Gujarati[] = { 1,
+0x0a80, 0x0aff,
+}; /* END of CR_In_Gujarati */
+
+/* PROPERTY: 'In_Oriya': Block */
+static const OnigCodePoint
+CR_In_Oriya[] = { 1,
+0x0b00, 0x0b7f,
+}; /* END of CR_In_Oriya */
+
+/* PROPERTY: 'In_Tamil': Block */
+static const OnigCodePoint
+CR_In_Tamil[] = { 1,
+0x0b80, 0x0bff,
+}; /* END of CR_In_Tamil */
+
+/* PROPERTY: 'In_Telugu': Block */
+static const OnigCodePoint
+CR_In_Telugu[] = { 1,
+0x0c00, 0x0c7f,
+}; /* END of CR_In_Telugu */
+
+/* PROPERTY: 'In_Kannada': Block */
+static const OnigCodePoint
+CR_In_Kannada[] = { 1,
+0x0c80, 0x0cff,
+}; /* END of CR_In_Kannada */
+
+/* PROPERTY: 'In_Malayalam': Block */
+static const OnigCodePoint
+CR_In_Malayalam[] = { 1,
+0x0d00, 0x0d7f,
+}; /* END of CR_In_Malayalam */
+
+/* PROPERTY: 'In_Sinhala': Block */
+static const OnigCodePoint
+CR_In_Sinhala[] = { 1,
+0x0d80, 0x0dff,
+}; /* END of CR_In_Sinhala */
+
+/* PROPERTY: 'In_Thai': Block */
+static const OnigCodePoint
+CR_In_Thai[] = { 1,
+0x0e00, 0x0e7f,
+}; /* END of CR_In_Thai */
+
+/* PROPERTY: 'In_Lao': Block */
+static const OnigCodePoint
+CR_In_Lao[] = { 1,
+0x0e80, 0x0eff,
+}; /* END of CR_In_Lao */
+
+/* PROPERTY: 'In_Tibetan': Block */
+static const OnigCodePoint
+CR_In_Tibetan[] = { 1,
+0x0f00, 0x0fff,
+}; /* END of CR_In_Tibetan */
+
+/* PROPERTY: 'In_Myanmar': Block */
+static const OnigCodePoint
+CR_In_Myanmar[] = { 1,
+0x1000, 0x109f,
+}; /* END of CR_In_Myanmar */
+
+/* PROPERTY: 'In_Georgian': Block */
+static const OnigCodePoint
+CR_In_Georgian[] = { 1,
+0x10a0, 0x10ff,
+}; /* END of CR_In_Georgian */
+
+/* PROPERTY: 'In_Hangul_Jamo': Block */
+static const OnigCodePoint
+CR_In_Hangul_Jamo[] = { 1,
+0x1100, 0x11ff,
+}; /* END of CR_In_Hangul_Jamo */
+
+/* PROPERTY: 'In_Ethiopic': Block */
+static const OnigCodePoint
+CR_In_Ethiopic[] = { 1,
+0x1200, 0x137f,
+}; /* END of CR_In_Ethiopic */
+
+/* PROPERTY: 'In_Ethiopic_Supplement': Block */
+static const OnigCodePoint
+CR_In_Ethiopic_Supplement[] = { 1,
+0x1380, 0x139f,
+}; /* END of CR_In_Ethiopic_Supplement */
+
+/* PROPERTY: 'In_Cherokee': Block */
+static const OnigCodePoint
+CR_In_Cherokee[] = { 1,
+0x13a0, 0x13ff,
+}; /* END of CR_In_Cherokee */
+
+/* PROPERTY: 'In_Unified_Canadian_Aboriginal_Syllabics': Block */
+static const OnigCodePoint
+CR_In_Unified_Canadian_Aboriginal_Syllabics[] = { 1,
+0x1400, 0x167f,
+}; /* END of CR_In_Unified_Canadian_Aboriginal_Syllabics */
+
+/* PROPERTY: 'In_Ogham': Block */
+static const OnigCodePoint
+CR_In_Ogham[] = { 1,
+0x1680, 0x169f,
+}; /* END of CR_In_Ogham */
+
+/* PROPERTY: 'In_Runic': Block */
+static const OnigCodePoint
+CR_In_Runic[] = { 1,
+0x16a0, 0x16ff,
+}; /* END of CR_In_Runic */
+
+/* PROPERTY: 'In_Tagalog': Block */
+static const OnigCodePoint
+CR_In_Tagalog[] = { 1,
+0x1700, 0x171f,
+}; /* END of CR_In_Tagalog */
+
+/* PROPERTY: 'In_Hanunoo': Block */
+static const OnigCodePoint
+CR_In_Hanunoo[] = { 1,
+0x1720, 0x173f,
+}; /* END of CR_In_Hanunoo */
+
+/* PROPERTY: 'In_Buhid': Block */
+static const OnigCodePoint
+CR_In_Buhid[] = { 1,
+0x1740, 0x175f,
+}; /* END of CR_In_Buhid */
+
+/* PROPERTY: 'In_Tagbanwa': Block */
+static const OnigCodePoint
+CR_In_Tagbanwa[] = { 1,
+0x1760, 0x177f,
+}; /* END of CR_In_Tagbanwa */
+
+/* PROPERTY: 'In_Khmer': Block */
+static const OnigCodePoint
+CR_In_Khmer[] = { 1,
+0x1780, 0x17ff,
+}; /* END of CR_In_Khmer */
+
+/* PROPERTY: 'In_Mongolian': Block */
+static const OnigCodePoint
+CR_In_Mongolian[] = { 1,
+0x1800, 0x18af,
+}; /* END of CR_In_Mongolian */
+
+/* PROPERTY: 'In_Unified_Canadian_Aboriginal_Syllabics_Extended': Block */
+static const OnigCodePoint
+CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended[] = { 1,
+0x18b0, 0x18ff,
+}; /* END of CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended */
+
+/* PROPERTY: 'In_Limbu': Block */
+static const OnigCodePoint
+CR_In_Limbu[] = { 1,
+0x1900, 0x194f,
+}; /* END of CR_In_Limbu */
+
+/* PROPERTY: 'In_Tai_Le': Block */
+static const OnigCodePoint
+CR_In_Tai_Le[] = { 1,
+0x1950, 0x197f,
+}; /* END of CR_In_Tai_Le */
+
+/* PROPERTY: 'In_New_Tai_Lue': Block */
+static const OnigCodePoint
+CR_In_New_Tai_Lue[] = { 1,
+0x1980, 0x19df,
+}; /* END of CR_In_New_Tai_Lue */
+
+/* PROPERTY: 'In_Khmer_Symbols': Block */
+static const OnigCodePoint
+CR_In_Khmer_Symbols[] = { 1,
+0x19e0, 0x19ff,
+}; /* END of CR_In_Khmer_Symbols */
+
+/* PROPERTY: 'In_Buginese': Block */
+static const OnigCodePoint
+CR_In_Buginese[] = { 1,
+0x1a00, 0x1a1f,
+}; /* END of CR_In_Buginese */
+
+/* PROPERTY: 'In_Tai_Tham': Block */
+static const OnigCodePoint
+CR_In_Tai_Tham[] = { 1,
+0x1a20, 0x1aaf,
+}; /* END of CR_In_Tai_Tham */
+
+/* PROPERTY: 'In_Combining_Diacritical_Marks_Extended': Block */
+static const OnigCodePoint
+CR_In_Combining_Diacritical_Marks_Extended[] = { 1,
+0x1ab0, 0x1aff,
+}; /* END of CR_In_Combining_Diacritical_Marks_Extended */
+
+/* PROPERTY: 'In_Balinese': Block */
+static const OnigCodePoint
+CR_In_Balinese[] = { 1,
+0x1b00, 0x1b7f,
+}; /* END of CR_In_Balinese */
+
+/* PROPERTY: 'In_Sundanese': Block */
+static const OnigCodePoint
+CR_In_Sundanese[] = { 1,
+0x1b80, 0x1bbf,
+}; /* END of CR_In_Sundanese */
+
+/* PROPERTY: 'In_Batak': Block */
+static const OnigCodePoint
+CR_In_Batak[] = { 1,
+0x1bc0, 0x1bff,
+}; /* END of CR_In_Batak */
+
+/* PROPERTY: 'In_Lepcha': Block */
+static const OnigCodePoint
+CR_In_Lepcha[] = { 1,
+0x1c00, 0x1c4f,
+}; /* END of CR_In_Lepcha */
+
+/* PROPERTY: 'In_Ol_Chiki': Block */
+#define CR_In_Ol_Chiki CR_Ol_Chiki
+
+/* PROPERTY: 'In_Cyrillic_Extended_C': Block */
+static const OnigCodePoint
+CR_In_Cyrillic_Extended_C[] = { 1,
+0x1c80, 0x1c8f,
+}; /* END of CR_In_Cyrillic_Extended_C */
+
+/* PROPERTY: 'In_Georgian_Extended': Block */
+static const OnigCodePoint
+CR_In_Georgian_Extended[] = { 1,
+0x1c90, 0x1cbf,
+}; /* END of CR_In_Georgian_Extended */
+
+/* PROPERTY: 'In_Sundanese_Supplement': Block */
+static const OnigCodePoint
+CR_In_Sundanese_Supplement[] = { 1,
+0x1cc0, 0x1ccf,
+}; /* END of CR_In_Sundanese_Supplement */
+
+/* PROPERTY: 'In_Vedic_Extensions': Block */
+static const OnigCodePoint
+CR_In_Vedic_Extensions[] = { 1,
+0x1cd0, 0x1cff,
+}; /* END of CR_In_Vedic_Extensions */
+
+/* PROPERTY: 'In_Phonetic_Extensions': Block */
+static const OnigCodePoint
+CR_In_Phonetic_Extensions[] = { 1,
+0x1d00, 0x1d7f,
+}; /* END of CR_In_Phonetic_Extensions */
+
+/* PROPERTY: 'In_Phonetic_Extensions_Supplement': Block */
+static const OnigCodePoint
+CR_In_Phonetic_Extensions_Supplement[] = { 1,
+0x1d80, 0x1dbf,
+}; /* END of CR_In_Phonetic_Extensions_Supplement */
+
+/* PROPERTY: 'In_Combining_Diacritical_Marks_Supplement': Block */
+static const OnigCodePoint
+CR_In_Combining_Diacritical_Marks_Supplement[] = { 1,
+0x1dc0, 0x1dff,
+}; /* END of CR_In_Combining_Diacritical_Marks_Supplement */
+
+/* PROPERTY: 'In_Latin_Extended_Additional': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_Additional[] = { 1,
+0x1e00, 0x1eff,
+}; /* END of CR_In_Latin_Extended_Additional */
+
+/* PROPERTY: 'In_Greek_Extended': Block */
+static const OnigCodePoint
+CR_In_Greek_Extended[] = { 1,
+0x1f00, 0x1fff,
+}; /* END of CR_In_Greek_Extended */
+
+/* PROPERTY: 'In_General_Punctuation': Block */
+static const OnigCodePoint
+CR_In_General_Punctuation[] = { 1,
+0x2000, 0x206f,
+}; /* END of CR_In_General_Punctuation */
+
+/* PROPERTY: 'In_Superscripts_and_Subscripts': Block */
+static const OnigCodePoint
+CR_In_Superscripts_and_Subscripts[] = { 1,
+0x2070, 0x209f,
+}; /* END of CR_In_Superscripts_and_Subscripts */
+
+/* PROPERTY: 'In_Currency_Symbols': Block */
+static const OnigCodePoint
+CR_In_Currency_Symbols[] = { 1,
+0x20a0, 0x20cf,
+}; /* END of CR_In_Currency_Symbols */
+
+/* PROPERTY: 'In_Combining_Diacritical_Marks_for_Symbols': Block */
+static const OnigCodePoint
+CR_In_Combining_Diacritical_Marks_for_Symbols[] = { 1,
+0x20d0, 0x20ff,
+}; /* END of CR_In_Combining_Diacritical_Marks_for_Symbols */
+
+/* PROPERTY: 'In_Letterlike_Symbols': Block */
+static const OnigCodePoint
+CR_In_Letterlike_Symbols[] = { 1,
+0x2100, 0x214f,
+}; /* END of CR_In_Letterlike_Symbols */
+
+/* PROPERTY: 'In_Number_Forms': Block */
+static const OnigCodePoint
+CR_In_Number_Forms[] = { 1,
+0x2150, 0x218f,
+}; /* END of CR_In_Number_Forms */
+
+/* PROPERTY: 'In_Arrows': Block */
+static const OnigCodePoint
+CR_In_Arrows[] = { 1,
+0x2190, 0x21ff,
+}; /* END of CR_In_Arrows */
+
+/* PROPERTY: 'In_Mathematical_Operators': Block */
+static const OnigCodePoint
+CR_In_Mathematical_Operators[] = { 1,
+0x2200, 0x22ff,
+}; /* END of CR_In_Mathematical_Operators */
+
+/* PROPERTY: 'In_Miscellaneous_Technical': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Technical[] = { 1,
+0x2300, 0x23ff,
+}; /* END of CR_In_Miscellaneous_Technical */
+
+/* PROPERTY: 'In_Control_Pictures': Block */
+static const OnigCodePoint
+CR_In_Control_Pictures[] = { 1,
+0x2400, 0x243f,
+}; /* END of CR_In_Control_Pictures */
+
+/* PROPERTY: 'In_Optical_Character_Recognition': Block */
+static const OnigCodePoint
+CR_In_Optical_Character_Recognition[] = { 1,
+0x2440, 0x245f,
+}; /* END of CR_In_Optical_Character_Recognition */
+
+/* PROPERTY: 'In_Enclosed_Alphanumerics': Block */
+static const OnigCodePoint
+CR_In_Enclosed_Alphanumerics[] = { 1,
+0x2460, 0x24ff,
+}; /* END of CR_In_Enclosed_Alphanumerics */
+
+/* PROPERTY: 'In_Box_Drawing': Block */
+static const OnigCodePoint
+CR_In_Box_Drawing[] = { 1,
+0x2500, 0x257f,
+}; /* END of CR_In_Box_Drawing */
+
+/* PROPERTY: 'In_Block_Elements': Block */
+static const OnigCodePoint
+CR_In_Block_Elements[] = { 1,
+0x2580, 0x259f,
+}; /* END of CR_In_Block_Elements */
+
+/* PROPERTY: 'In_Geometric_Shapes': Block */
+static const OnigCodePoint
+CR_In_Geometric_Shapes[] = { 1,
+0x25a0, 0x25ff,
+}; /* END of CR_In_Geometric_Shapes */
+
+/* PROPERTY: 'In_Miscellaneous_Symbols': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Symbols[] = { 1,
+0x2600, 0x26ff,
+}; /* END of CR_In_Miscellaneous_Symbols */
+
+/* PROPERTY: 'In_Dingbats': Block */
+static const OnigCodePoint
+CR_In_Dingbats[] = { 1,
+0x2700, 0x27bf,
+}; /* END of CR_In_Dingbats */
+
+/* PROPERTY: 'In_Miscellaneous_Mathematical_Symbols_A': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Mathematical_Symbols_A[] = { 1,
+0x27c0, 0x27ef,
+}; /* END of CR_In_Miscellaneous_Mathematical_Symbols_A */
+
+/* PROPERTY: 'In_Supplemental_Arrows_A': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Arrows_A[] = { 1,
+0x27f0, 0x27ff,
+}; /* END of CR_In_Supplemental_Arrows_A */
+
+/* PROPERTY: 'In_Braille_Patterns': Block */
+#define CR_In_Braille_Patterns CR_Braille
+
+/* PROPERTY: 'In_Supplemental_Arrows_B': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Arrows_B[] = { 1,
+0x2900, 0x297f,
+}; /* END of CR_In_Supplemental_Arrows_B */
+
+/* PROPERTY: 'In_Miscellaneous_Mathematical_Symbols_B': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Mathematical_Symbols_B[] = { 1,
+0x2980, 0x29ff,
+}; /* END of CR_In_Miscellaneous_Mathematical_Symbols_B */
+
+/* PROPERTY: 'In_Supplemental_Mathematical_Operators': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Mathematical_Operators[] = { 1,
+0x2a00, 0x2aff,
+}; /* END of CR_In_Supplemental_Mathematical_Operators */
+
+/* PROPERTY: 'In_Miscellaneous_Symbols_and_Arrows': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Symbols_and_Arrows[] = { 1,
+0x2b00, 0x2bff,
+}; /* END of CR_In_Miscellaneous_Symbols_and_Arrows */
+
+/* PROPERTY: 'In_Glagolitic': Block */
+static const OnigCodePoint
+CR_In_Glagolitic[] = { 1,
+0x2c00, 0x2c5f,
+}; /* END of CR_In_Glagolitic */
+
+/* PROPERTY: 'In_Latin_Extended_C': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_C[] = { 1,
+0x2c60, 0x2c7f,
+}; /* END of CR_In_Latin_Extended_C */
+
+/* PROPERTY: 'In_Coptic': Block */
+static const OnigCodePoint
+CR_In_Coptic[] = { 1,
+0x2c80, 0x2cff,
+}; /* END of CR_In_Coptic */
+
+/* PROPERTY: 'In_Georgian_Supplement': Block */
+static const OnigCodePoint
+CR_In_Georgian_Supplement[] = { 1,
+0x2d00, 0x2d2f,
+}; /* END of CR_In_Georgian_Supplement */
+
+/* PROPERTY: 'In_Tifinagh': Block */
+static const OnigCodePoint
+CR_In_Tifinagh[] = { 1,
+0x2d30, 0x2d7f,
+}; /* END of CR_In_Tifinagh */
+
+/* PROPERTY: 'In_Ethiopic_Extended': Block */
+static const OnigCodePoint
+CR_In_Ethiopic_Extended[] = { 1,
+0x2d80, 0x2ddf,
+}; /* END of CR_In_Ethiopic_Extended */
+
+/* PROPERTY: 'In_Cyrillic_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Cyrillic_Extended_A[] = { 1,
+0x2de0, 0x2dff,
+}; /* END of CR_In_Cyrillic_Extended_A */
+
+/* PROPERTY: 'In_Supplemental_Punctuation': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Punctuation[] = { 1,
+0x2e00, 0x2e7f,
+}; /* END of CR_In_Supplemental_Punctuation */
+
+/* PROPERTY: 'In_CJK_Radicals_Supplement': Block */
+static const OnigCodePoint
+CR_In_CJK_Radicals_Supplement[] = { 1,
+0x2e80, 0x2eff,
+}; /* END of CR_In_CJK_Radicals_Supplement */
+
+/* PROPERTY: 'In_Kangxi_Radicals': Block */
+static const OnigCodePoint
+CR_In_Kangxi_Radicals[] = { 1,
+0x2f00, 0x2fdf,
+}; /* END of CR_In_Kangxi_Radicals */
+
+/* PROPERTY: 'In_Ideographic_Description_Characters': Block */
+static const OnigCodePoint
+CR_In_Ideographic_Description_Characters[] = { 1,
+0x2ff0, 0x2fff,
+}; /* END of CR_In_Ideographic_Description_Characters */
+
+/* PROPERTY: 'In_CJK_Symbols_and_Punctuation': Block */
+static const OnigCodePoint
+CR_In_CJK_Symbols_and_Punctuation[] = { 1,
+0x3000, 0x303f,
+}; /* END of CR_In_CJK_Symbols_and_Punctuation */
+
+/* PROPERTY: 'In_Hiragana': Block */
+static const OnigCodePoint
+CR_In_Hiragana[] = { 1,
+0x3040, 0x309f,
+}; /* END of CR_In_Hiragana */
+
+/* PROPERTY: 'In_Katakana': Block */
+static const OnigCodePoint
+CR_In_Katakana[] = { 1,
+0x30a0, 0x30ff,
+}; /* END of CR_In_Katakana */
+
+/* PROPERTY: 'In_Bopomofo': Block */
+static const OnigCodePoint
+CR_In_Bopomofo[] = { 1,
+0x3100, 0x312f,
+}; /* END of CR_In_Bopomofo */
+
+/* PROPERTY: 'In_Hangul_Compatibility_Jamo': Block */
+static const OnigCodePoint
+CR_In_Hangul_Compatibility_Jamo[] = { 1,
+0x3130, 0x318f,
+}; /* END of CR_In_Hangul_Compatibility_Jamo */
+
+/* PROPERTY: 'In_Kanbun': Block */
+static const OnigCodePoint
+CR_In_Kanbun[] = { 1,
+0x3190, 0x319f,
+}; /* END of CR_In_Kanbun */
+
+/* PROPERTY: 'In_Bopomofo_Extended': Block */
+static const OnigCodePoint
+CR_In_Bopomofo_Extended[] = { 1,
+0x31a0, 0x31bf,
+}; /* END of CR_In_Bopomofo_Extended */
+
+/* PROPERTY: 'In_CJK_Strokes': Block */
+static const OnigCodePoint
+CR_In_CJK_Strokes[] = { 1,
+0x31c0, 0x31ef,
+}; /* END of CR_In_CJK_Strokes */
+
+/* PROPERTY: 'In_Katakana_Phonetic_Extensions': Block */
+static const OnigCodePoint
+CR_In_Katakana_Phonetic_Extensions[] = { 1,
+0x31f0, 0x31ff,
+}; /* END of CR_In_Katakana_Phonetic_Extensions */
+
+/* PROPERTY: 'In_Enclosed_CJK_Letters_and_Months': Block */
+static const OnigCodePoint
+CR_In_Enclosed_CJK_Letters_and_Months[] = { 1,
+0x3200, 0x32ff,
+}; /* END of CR_In_Enclosed_CJK_Letters_and_Months */
+
+/* PROPERTY: 'In_CJK_Compatibility': Block */
+static const OnigCodePoint
+CR_In_CJK_Compatibility[] = { 1,
+0x3300, 0x33ff,
+}; /* END of CR_In_CJK_Compatibility */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_A': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_A[] = { 1,
+0x3400, 0x4dbf,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_A */
+
+/* PROPERTY: 'In_Yijing_Hexagram_Symbols': Block */
+static const OnigCodePoint
+CR_In_Yijing_Hexagram_Symbols[] = { 1,
+0x4dc0, 0x4dff,
+}; /* END of CR_In_Yijing_Hexagram_Symbols */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs[] = { 1,
+0x4e00, 0x9fff,
+}; /* END of CR_In_CJK_Unified_Ideographs */
+
+/* PROPERTY: 'In_Yi_Syllables': Block */
+static const OnigCodePoint
+CR_In_Yi_Syllables[] = { 1,
+0xa000, 0xa48f,
+}; /* END of CR_In_Yi_Syllables */
+
+/* PROPERTY: 'In_Yi_Radicals': Block */
+static const OnigCodePoint
+CR_In_Yi_Radicals[] = { 1,
+0xa490, 0xa4cf,
+}; /* END of CR_In_Yi_Radicals */
+
+/* PROPERTY: 'In_Lisu': Block */
+#define CR_In_Lisu CR_Lisu
+
+/* PROPERTY: 'In_Vai': Block */
+static const OnigCodePoint
+CR_In_Vai[] = { 1,
+0xa500, 0xa63f,
+}; /* END of CR_In_Vai */
+
+/* PROPERTY: 'In_Cyrillic_Extended_B': Block */
+static const OnigCodePoint
+CR_In_Cyrillic_Extended_B[] = { 1,
+0xa640, 0xa69f,
+}; /* END of CR_In_Cyrillic_Extended_B */
+
+/* PROPERTY: 'In_Bamum': Block */
+static const OnigCodePoint
+CR_In_Bamum[] = { 1,
+0xa6a0, 0xa6ff,
+}; /* END of CR_In_Bamum */
+
+/* PROPERTY: 'In_Modifier_Tone_Letters': Block */
+static const OnigCodePoint
+CR_In_Modifier_Tone_Letters[] = { 1,
+0xa700, 0xa71f,
+}; /* END of CR_In_Modifier_Tone_Letters */
+
+/* PROPERTY: 'In_Latin_Extended_D': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_D[] = { 1,
+0xa720, 0xa7ff,
+}; /* END of CR_In_Latin_Extended_D */
+
+/* PROPERTY: 'In_Syloti_Nagri': Block */
+static const OnigCodePoint
+CR_In_Syloti_Nagri[] = { 1,
+0xa800, 0xa82f,
+}; /* END of CR_In_Syloti_Nagri */
+
+/* PROPERTY: 'In_Common_Indic_Number_Forms': Block */
+static const OnigCodePoint
+CR_In_Common_Indic_Number_Forms[] = { 1,
+0xa830, 0xa83f,
+}; /* END of CR_In_Common_Indic_Number_Forms */
+
+/* PROPERTY: 'In_Phags_pa': Block */
+static const OnigCodePoint
+CR_In_Phags_pa[] = { 1,
+0xa840, 0xa87f,
+}; /* END of CR_In_Phags_pa */
+
+/* PROPERTY: 'In_Saurashtra': Block */
+static const OnigCodePoint
+CR_In_Saurashtra[] = { 1,
+0xa880, 0xa8df,
+}; /* END of CR_In_Saurashtra */
+
+/* PROPERTY: 'In_Devanagari_Extended': Block */
+static const OnigCodePoint
+CR_In_Devanagari_Extended[] = { 1,
+0xa8e0, 0xa8ff,
+}; /* END of CR_In_Devanagari_Extended */
+
+/* PROPERTY: 'In_Kayah_Li': Block */
+static const OnigCodePoint
+CR_In_Kayah_Li[] = { 1,
+0xa900, 0xa92f,
+}; /* END of CR_In_Kayah_Li */
+
+/* PROPERTY: 'In_Rejang': Block */
+static const OnigCodePoint
+CR_In_Rejang[] = { 1,
+0xa930, 0xa95f,
+}; /* END of CR_In_Rejang */
+
+/* PROPERTY: 'In_Hangul_Jamo_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Hangul_Jamo_Extended_A[] = { 1,
+0xa960, 0xa97f,
+}; /* END of CR_In_Hangul_Jamo_Extended_A */
+
+/* PROPERTY: 'In_Javanese': Block */
+static const OnigCodePoint
+CR_In_Javanese[] = { 1,
+0xa980, 0xa9df,
+}; /* END of CR_In_Javanese */
+
+/* PROPERTY: 'In_Myanmar_Extended_B': Block */
+static const OnigCodePoint
+CR_In_Myanmar_Extended_B[] = { 1,
+0xa9e0, 0xa9ff,
+}; /* END of CR_In_Myanmar_Extended_B */
+
+/* PROPERTY: 'In_Cham': Block */
+static const OnigCodePoint
+CR_In_Cham[] = { 1,
+0xaa00, 0xaa5f,
+}; /* END of CR_In_Cham */
+
+/* PROPERTY: 'In_Myanmar_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Myanmar_Extended_A[] = { 1,
+0xaa60, 0xaa7f,
+}; /* END of CR_In_Myanmar_Extended_A */
+
+/* PROPERTY: 'In_Tai_Viet': Block */
+static const OnigCodePoint
+CR_In_Tai_Viet[] = { 1,
+0xaa80, 0xaadf,
+}; /* END of CR_In_Tai_Viet */
+
+/* PROPERTY: 'In_Meetei_Mayek_Extensions': Block */
+static const OnigCodePoint
+CR_In_Meetei_Mayek_Extensions[] = { 1,
+0xaae0, 0xaaff,
+}; /* END of CR_In_Meetei_Mayek_Extensions */
+
+/* PROPERTY: 'In_Ethiopic_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Ethiopic_Extended_A[] = { 1,
+0xab00, 0xab2f,
+}; /* END of CR_In_Ethiopic_Extended_A */
+
+/* PROPERTY: 'In_Latin_Extended_E': Block */
+static const OnigCodePoint
+CR_In_Latin_Extended_E[] = { 1,
+0xab30, 0xab6f,
+}; /* END of CR_In_Latin_Extended_E */
+
+/* PROPERTY: 'In_Cherokee_Supplement': Block */
+static const OnigCodePoint
+CR_In_Cherokee_Supplement[] = { 1,
+0xab70, 0xabbf,
+}; /* END of CR_In_Cherokee_Supplement */
+
+/* PROPERTY: 'In_Meetei_Mayek': Block */
+static const OnigCodePoint
+CR_In_Meetei_Mayek[] = { 1,
+0xabc0, 0xabff,
+}; /* END of CR_In_Meetei_Mayek */
+
+/* PROPERTY: 'In_Hangul_Syllables': Block */
+static const OnigCodePoint
+CR_In_Hangul_Syllables[] = { 1,
+0xac00, 0xd7af,
+}; /* END of CR_In_Hangul_Syllables */
+
+/* PROPERTY: 'In_Hangul_Jamo_Extended_B': Block */
+static const OnigCodePoint
+CR_In_Hangul_Jamo_Extended_B[] = { 1,
+0xd7b0, 0xd7ff,
+}; /* END of CR_In_Hangul_Jamo_Extended_B */
+
+/* PROPERTY: 'In_High_Surrogates': Block */
+static const OnigCodePoint
+CR_In_High_Surrogates[] = { 1,
+0xd800, 0xdb7f,
+}; /* END of CR_In_High_Surrogates */
+
+/* PROPERTY: 'In_High_Private_Use_Surrogates': Block */
+static const OnigCodePoint
+CR_In_High_Private_Use_Surrogates[] = { 1,
+0xdb80, 0xdbff,
+}; /* END of CR_In_High_Private_Use_Surrogates */
+
+/* PROPERTY: 'In_Low_Surrogates': Block */
+static const OnigCodePoint
+CR_In_Low_Surrogates[] = { 1,
+0xdc00, 0xdfff,
+}; /* END of CR_In_Low_Surrogates */
+
+/* PROPERTY: 'In_Private_Use_Area': Block */
+static const OnigCodePoint
+CR_In_Private_Use_Area[] = { 1,
+0xe000, 0xf8ff,
+}; /* END of CR_In_Private_Use_Area */
+
+/* PROPERTY: 'In_CJK_Compatibility_Ideographs': Block */
+static const OnigCodePoint
+CR_In_CJK_Compatibility_Ideographs[] = { 1,
+0xf900, 0xfaff,
+}; /* END of CR_In_CJK_Compatibility_Ideographs */
+
+/* PROPERTY: 'In_Alphabetic_Presentation_Forms': Block */
+static const OnigCodePoint
+CR_In_Alphabetic_Presentation_Forms[] = { 1,
+0xfb00, 0xfb4f,
+}; /* END of CR_In_Alphabetic_Presentation_Forms */
+
+/* PROPERTY: 'In_Arabic_Presentation_Forms_A': Block */
+static const OnigCodePoint
+CR_In_Arabic_Presentation_Forms_A[] = { 1,
+0xfb50, 0xfdff,
+}; /* END of CR_In_Arabic_Presentation_Forms_A */
+
+/* PROPERTY: 'In_Variation_Selectors': Block */
+static const OnigCodePoint
+CR_In_Variation_Selectors[] = { 1,
+0xfe00, 0xfe0f,
+}; /* END of CR_In_Variation_Selectors */
+
+/* PROPERTY: 'In_Vertical_Forms': Block */
+static const OnigCodePoint
+CR_In_Vertical_Forms[] = { 1,
+0xfe10, 0xfe1f,
+}; /* END of CR_In_Vertical_Forms */
+
+/* PROPERTY: 'In_Combining_Half_Marks': Block */
+static const OnigCodePoint
+CR_In_Combining_Half_Marks[] = { 1,
+0xfe20, 0xfe2f,
+}; /* END of CR_In_Combining_Half_Marks */
+
+/* PROPERTY: 'In_CJK_Compatibility_Forms': Block */
+static const OnigCodePoint
+CR_In_CJK_Compatibility_Forms[] = { 1,
+0xfe30, 0xfe4f,
+}; /* END of CR_In_CJK_Compatibility_Forms */
+
+/* PROPERTY: 'In_Small_Form_Variants': Block */
+static const OnigCodePoint
+CR_In_Small_Form_Variants[] = { 1,
+0xfe50, 0xfe6f,
+}; /* END of CR_In_Small_Form_Variants */
+
+/* PROPERTY: 'In_Arabic_Presentation_Forms_B': Block */
+static const OnigCodePoint
+CR_In_Arabic_Presentation_Forms_B[] = { 1,
+0xfe70, 0xfeff,
+}; /* END of CR_In_Arabic_Presentation_Forms_B */
+
+/* PROPERTY: 'In_Halfwidth_and_Fullwidth_Forms': Block */
+static const OnigCodePoint
+CR_In_Halfwidth_and_Fullwidth_Forms[] = { 1,
+0xff00, 0xffef,
+}; /* END of CR_In_Halfwidth_and_Fullwidth_Forms */
+
+/* PROPERTY: 'In_Specials': Block */
+static const OnigCodePoint
+CR_In_Specials[] = { 1,
+0xfff0, 0xffff,
+}; /* END of CR_In_Specials */
+
+/* PROPERTY: 'In_Linear_B_Syllabary': Block */
+static const OnigCodePoint
+CR_In_Linear_B_Syllabary[] = { 1,
+0x10000, 0x1007f,
+}; /* END of CR_In_Linear_B_Syllabary */
+
+/* PROPERTY: 'In_Linear_B_Ideograms': Block */
+static const OnigCodePoint
+CR_In_Linear_B_Ideograms[] = { 1,
+0x10080, 0x100ff,
+}; /* END of CR_In_Linear_B_Ideograms */
+
+/* PROPERTY: 'In_Aegean_Numbers': Block */
+static const OnigCodePoint
+CR_In_Aegean_Numbers[] = { 1,
+0x10100, 0x1013f,
+}; /* END of CR_In_Aegean_Numbers */
+
+/* PROPERTY: 'In_Ancient_Greek_Numbers': Block */
+static const OnigCodePoint
+CR_In_Ancient_Greek_Numbers[] = { 1,
+0x10140, 0x1018f,
+}; /* END of CR_In_Ancient_Greek_Numbers */
+
+/* PROPERTY: 'In_Ancient_Symbols': Block */
+static const OnigCodePoint
+CR_In_Ancient_Symbols[] = { 1,
+0x10190, 0x101cf,
+}; /* END of CR_In_Ancient_Symbols */
+
+/* PROPERTY: 'In_Phaistos_Disc': Block */
+static const OnigCodePoint
+CR_In_Phaistos_Disc[] = { 1,
+0x101d0, 0x101ff,
+}; /* END of CR_In_Phaistos_Disc */
+
+/* PROPERTY: 'In_Lycian': Block */
+static const OnigCodePoint
+CR_In_Lycian[] = { 1,
+0x10280, 0x1029f,
+}; /* END of CR_In_Lycian */
+
+/* PROPERTY: 'In_Carian': Block */
+static const OnigCodePoint
+CR_In_Carian[] = { 1,
+0x102a0, 0x102df,
+}; /* END of CR_In_Carian */
+
+/* PROPERTY: 'In_Coptic_Epact_Numbers': Block */
+static const OnigCodePoint
+CR_In_Coptic_Epact_Numbers[] = { 1,
+0x102e0, 0x102ff,
+}; /* END of CR_In_Coptic_Epact_Numbers */
+
+/* PROPERTY: 'In_Old_Italic': Block */
+static const OnigCodePoint
+CR_In_Old_Italic[] = { 1,
+0x10300, 0x1032f,
+}; /* END of CR_In_Old_Italic */
+
+/* PROPERTY: 'In_Gothic': Block */
+static const OnigCodePoint
+CR_In_Gothic[] = { 1,
+0x10330, 0x1034f,
+}; /* END of CR_In_Gothic */
+
+/* PROPERTY: 'In_Old_Permic': Block */
+static const OnigCodePoint
+CR_In_Old_Permic[] = { 1,
+0x10350, 0x1037f,
+}; /* END of CR_In_Old_Permic */
+
+/* PROPERTY: 'In_Ugaritic': Block */
+static const OnigCodePoint
+CR_In_Ugaritic[] = { 1,
+0x10380, 0x1039f,
+}; /* END of CR_In_Ugaritic */
+
+/* PROPERTY: 'In_Old_Persian': Block */
+static const OnigCodePoint
+CR_In_Old_Persian[] = { 1,
+0x103a0, 0x103df,
+}; /* END of CR_In_Old_Persian */
+
+/* PROPERTY: 'In_Deseret': Block */
+#define CR_In_Deseret CR_Deseret
+
+/* PROPERTY: 'In_Shavian': Block */
+#define CR_In_Shavian CR_Shavian
+
+/* PROPERTY: 'In_Osmanya': Block */
+static const OnigCodePoint
+CR_In_Osmanya[] = { 1,
+0x10480, 0x104af,
+}; /* END of CR_In_Osmanya */
+
+/* PROPERTY: 'In_Osage': Block */
+static const OnigCodePoint
+CR_In_Osage[] = { 1,
+0x104b0, 0x104ff,
+}; /* END of CR_In_Osage */
+
+/* PROPERTY: 'In_Elbasan': Block */
+static const OnigCodePoint
+CR_In_Elbasan[] = { 1,
+0x10500, 0x1052f,
+}; /* END of CR_In_Elbasan */
+
+/* PROPERTY: 'In_Caucasian_Albanian': Block */
+static const OnigCodePoint
+CR_In_Caucasian_Albanian[] = { 1,
+0x10530, 0x1056f,
+}; /* END of CR_In_Caucasian_Albanian */
+
+/* PROPERTY: 'In_Linear_A': Block */
+static const OnigCodePoint
+CR_In_Linear_A[] = { 1,
+0x10600, 0x1077f,
+}; /* END of CR_In_Linear_A */
+
+/* PROPERTY: 'In_Cypriot_Syllabary': Block */
+static const OnigCodePoint
+CR_In_Cypriot_Syllabary[] = { 1,
+0x10800, 0x1083f,
+}; /* END of CR_In_Cypriot_Syllabary */
+
+/* PROPERTY: 'In_Imperial_Aramaic': Block */
+static const OnigCodePoint
+CR_In_Imperial_Aramaic[] = { 1,
+0x10840, 0x1085f,
+}; /* END of CR_In_Imperial_Aramaic */
+
+/* PROPERTY: 'In_Palmyrene': Block */
+#define CR_In_Palmyrene CR_Palmyrene
+
+/* PROPERTY: 'In_Nabataean': Block */
+static const OnigCodePoint
+CR_In_Nabataean[] = { 1,
+0x10880, 0x108af,
+}; /* END of CR_In_Nabataean */
+
+/* PROPERTY: 'In_Hatran': Block */
+static const OnigCodePoint
+CR_In_Hatran[] = { 1,
+0x108e0, 0x108ff,
+}; /* END of CR_In_Hatran */
+
+/* PROPERTY: 'In_Phoenician': Block */
+static const OnigCodePoint
+CR_In_Phoenician[] = { 1,
+0x10900, 0x1091f,
+}; /* END of CR_In_Phoenician */
+
+/* PROPERTY: 'In_Lydian': Block */
+static const OnigCodePoint
+CR_In_Lydian[] = { 1,
+0x10920, 0x1093f,
+}; /* END of CR_In_Lydian */
+
+/* PROPERTY: 'In_Meroitic_Hieroglyphs': Block */
+#define CR_In_Meroitic_Hieroglyphs CR_Meroitic_Hieroglyphs
+
+/* PROPERTY: 'In_Meroitic_Cursive': Block */
+static const OnigCodePoint
+CR_In_Meroitic_Cursive[] = { 1,
+0x109a0, 0x109ff,
+}; /* END of CR_In_Meroitic_Cursive */
+
+/* PROPERTY: 'In_Kharoshthi': Block */
+static const OnigCodePoint
+CR_In_Kharoshthi[] = { 1,
+0x10a00, 0x10a5f,
+}; /* END of CR_In_Kharoshthi */
+
+/* PROPERTY: 'In_Old_South_Arabian': Block */
+#define CR_In_Old_South_Arabian CR_Old_South_Arabian
+
+/* PROPERTY: 'In_Old_North_Arabian': Block */
+#define CR_In_Old_North_Arabian CR_Old_North_Arabian
+
+/* PROPERTY: 'In_Manichaean': Block */
+static const OnigCodePoint
+CR_In_Manichaean[] = { 1,
+0x10ac0, 0x10aff,
+}; /* END of CR_In_Manichaean */
+
+/* PROPERTY: 'In_Avestan': Block */
+static const OnigCodePoint
+CR_In_Avestan[] = { 1,
+0x10b00, 0x10b3f,
+}; /* END of CR_In_Avestan */
+
+/* PROPERTY: 'In_Inscriptional_Parthian': Block */
+static const OnigCodePoint
+CR_In_Inscriptional_Parthian[] = { 1,
+0x10b40, 0x10b5f,
+}; /* END of CR_In_Inscriptional_Parthian */
+
+/* PROPERTY: 'In_Inscriptional_Pahlavi': Block */
+static const OnigCodePoint
+CR_In_Inscriptional_Pahlavi[] = { 1,
+0x10b60, 0x10b7f,
+}; /* END of CR_In_Inscriptional_Pahlavi */
+
+/* PROPERTY: 'In_Psalter_Pahlavi': Block */
+static const OnigCodePoint
+CR_In_Psalter_Pahlavi[] = { 1,
+0x10b80, 0x10baf,
+}; /* END of CR_In_Psalter_Pahlavi */
+
+/* PROPERTY: 'In_Old_Turkic': Block */
+static const OnigCodePoint
+CR_In_Old_Turkic[] = { 1,
+0x10c00, 0x10c4f,
+}; /* END of CR_In_Old_Turkic */
+
+/* PROPERTY: 'In_Old_Hungarian': Block */
+static const OnigCodePoint
+CR_In_Old_Hungarian[] = { 1,
+0x10c80, 0x10cff,
+}; /* END of CR_In_Old_Hungarian */
+
+/* PROPERTY: 'In_Hanifi_Rohingya': Block */
+static const OnigCodePoint
+CR_In_Hanifi_Rohingya[] = { 1,
+0x10d00, 0x10d3f,
+}; /* END of CR_In_Hanifi_Rohingya */
+
+/* PROPERTY: 'In_Rumi_Numeral_Symbols': Block */
+static const OnigCodePoint
+CR_In_Rumi_Numeral_Symbols[] = { 1,
+0x10e60, 0x10e7f,
+}; /* END of CR_In_Rumi_Numeral_Symbols */
+
+/* PROPERTY: 'In_Old_Sogdian': Block */
+static const OnigCodePoint
+CR_In_Old_Sogdian[] = { 1,
+0x10f00, 0x10f2f,
+}; /* END of CR_In_Old_Sogdian */
+
+/* PROPERTY: 'In_Sogdian': Block */
+static const OnigCodePoint
+CR_In_Sogdian[] = { 1,
+0x10f30, 0x10f6f,
+}; /* END of CR_In_Sogdian */
+
+/* PROPERTY: 'In_Elymaic': Block */
+static const OnigCodePoint
+CR_In_Elymaic[] = { 1,
+0x10fe0, 0x10fff,
+}; /* END of CR_In_Elymaic */
+
+/* PROPERTY: 'In_Brahmi': Block */
+static const OnigCodePoint
+CR_In_Brahmi[] = { 1,
+0x11000, 0x1107f,
+}; /* END of CR_In_Brahmi */
+
+/* PROPERTY: 'In_Kaithi': Block */
+static const OnigCodePoint
+CR_In_Kaithi[] = { 1,
+0x11080, 0x110cf,
+}; /* END of CR_In_Kaithi */
+
+/* PROPERTY: 'In_Sora_Sompeng': Block */
+static const OnigCodePoint
+CR_In_Sora_Sompeng[] = { 1,
+0x110d0, 0x110ff,
+}; /* END of CR_In_Sora_Sompeng */
+
+/* PROPERTY: 'In_Chakma': Block */
+static const OnigCodePoint
+CR_In_Chakma[] = { 1,
+0x11100, 0x1114f,
+}; /* END of CR_In_Chakma */
+
+/* PROPERTY: 'In_Mahajani': Block */
+static const OnigCodePoint
+CR_In_Mahajani[] = { 1,
+0x11150, 0x1117f,
+}; /* END of CR_In_Mahajani */
+
+/* PROPERTY: 'In_Sharada': Block */
+static const OnigCodePoint
+CR_In_Sharada[] = { 1,
+0x11180, 0x111df,
+}; /* END of CR_In_Sharada */
+
+/* PROPERTY: 'In_Sinhala_Archaic_Numbers': Block */
+static const OnigCodePoint
+CR_In_Sinhala_Archaic_Numbers[] = { 1,
+0x111e0, 0x111ff,
+}; /* END of CR_In_Sinhala_Archaic_Numbers */
+
+/* PROPERTY: 'In_Khojki': Block */
+static const OnigCodePoint
+CR_In_Khojki[] = { 1,
+0x11200, 0x1124f,
+}; /* END of CR_In_Khojki */
+
+/* PROPERTY: 'In_Multani': Block */
+static const OnigCodePoint
+CR_In_Multani[] = { 1,
+0x11280, 0x112af,
+}; /* END of CR_In_Multani */
+
+/* PROPERTY: 'In_Khudawadi': Block */
+static const OnigCodePoint
+CR_In_Khudawadi[] = { 1,
+0x112b0, 0x112ff,
+}; /* END of CR_In_Khudawadi */
+
+/* PROPERTY: 'In_Grantha': Block */
+static const OnigCodePoint
+CR_In_Grantha[] = { 1,
+0x11300, 0x1137f,
+}; /* END of CR_In_Grantha */
+
+/* PROPERTY: 'In_Newa': Block */
+static const OnigCodePoint
+CR_In_Newa[] = { 1,
+0x11400, 0x1147f,
+}; /* END of CR_In_Newa */
+
+/* PROPERTY: 'In_Tirhuta': Block */
+static const OnigCodePoint
+CR_In_Tirhuta[] = { 1,
+0x11480, 0x114df,
+}; /* END of CR_In_Tirhuta */
+
+/* PROPERTY: 'In_Siddham': Block */
+static const OnigCodePoint
+CR_In_Siddham[] = { 1,
+0x11580, 0x115ff,
+}; /* END of CR_In_Siddham */
+
+/* PROPERTY: 'In_Modi': Block */
+static const OnigCodePoint
+CR_In_Modi[] = { 1,
+0x11600, 0x1165f,
+}; /* END of CR_In_Modi */
+
+/* PROPERTY: 'In_Mongolian_Supplement': Block */
+static const OnigCodePoint
+CR_In_Mongolian_Supplement[] = { 1,
+0x11660, 0x1167f,
+}; /* END of CR_In_Mongolian_Supplement */
+
+/* PROPERTY: 'In_Takri': Block */
+static const OnigCodePoint
+CR_In_Takri[] = { 1,
+0x11680, 0x116cf,
+}; /* END of CR_In_Takri */
+
+/* PROPERTY: 'In_Ahom': Block */
+static const OnigCodePoint
+CR_In_Ahom[] = { 1,
+0x11700, 0x1173f,
+}; /* END of CR_In_Ahom */
+
+/* PROPERTY: 'In_Dogra': Block */
+static const OnigCodePoint
+CR_In_Dogra[] = { 1,
+0x11800, 0x1184f,
+}; /* END of CR_In_Dogra */
+
+/* PROPERTY: 'In_Warang_Citi': Block */
+static const OnigCodePoint
+CR_In_Warang_Citi[] = { 1,
+0x118a0, 0x118ff,
+}; /* END of CR_In_Warang_Citi */
+
+/* PROPERTY: 'In_Nandinagari': Block */
+static const OnigCodePoint
+CR_In_Nandinagari[] = { 1,
+0x119a0, 0x119ff,
+}; /* END of CR_In_Nandinagari */
+
+/* PROPERTY: 'In_Zanabazar_Square': Block */
+static const OnigCodePoint
+CR_In_Zanabazar_Square[] = { 1,
+0x11a00, 0x11a4f,
+}; /* END of CR_In_Zanabazar_Square */
+
+/* PROPERTY: 'In_Soyombo': Block */
+static const OnigCodePoint
+CR_In_Soyombo[] = { 1,
+0x11a50, 0x11aaf,
+}; /* END of CR_In_Soyombo */
+
+/* PROPERTY: 'In_Pau_Cin_Hau': Block */
+static const OnigCodePoint
+CR_In_Pau_Cin_Hau[] = { 1,
+0x11ac0, 0x11aff,
+}; /* END of CR_In_Pau_Cin_Hau */
+
+/* PROPERTY: 'In_Bhaiksuki': Block */
+static const OnigCodePoint
+CR_In_Bhaiksuki[] = { 1,
+0x11c00, 0x11c6f,
+}; /* END of CR_In_Bhaiksuki */
+
+/* PROPERTY: 'In_Marchen': Block */
+static const OnigCodePoint
+CR_In_Marchen[] = { 1,
+0x11c70, 0x11cbf,
+}; /* END of CR_In_Marchen */
+
+/* PROPERTY: 'In_Masaram_Gondi': Block */
+static const OnigCodePoint
+CR_In_Masaram_Gondi[] = { 1,
+0x11d00, 0x11d5f,
+}; /* END of CR_In_Masaram_Gondi */
+
+/* PROPERTY: 'In_Gunjala_Gondi': Block */
+static const OnigCodePoint
+CR_In_Gunjala_Gondi[] = { 1,
+0x11d60, 0x11daf,
+}; /* END of CR_In_Gunjala_Gondi */
+
+/* PROPERTY: 'In_Makasar': Block */
+static const OnigCodePoint
+CR_In_Makasar[] = { 1,
+0x11ee0, 0x11eff,
+}; /* END of CR_In_Makasar */
+
+/* PROPERTY: 'In_Tamil_Supplement': Block */
+static const OnigCodePoint
+CR_In_Tamil_Supplement[] = { 1,
+0x11fc0, 0x11fff,
+}; /* END of CR_In_Tamil_Supplement */
+
+/* PROPERTY: 'In_Cuneiform': Block */
+static const OnigCodePoint
+CR_In_Cuneiform[] = { 1,
+0x12000, 0x123ff,
+}; /* END of CR_In_Cuneiform */
+
+/* PROPERTY: 'In_Cuneiform_Numbers_and_Punctuation': Block */
+static const OnigCodePoint
+CR_In_Cuneiform_Numbers_and_Punctuation[] = { 1,
+0x12400, 0x1247f,
+}; /* END of CR_In_Cuneiform_Numbers_and_Punctuation */
+
+/* PROPERTY: 'In_Early_Dynastic_Cuneiform': Block */
+static const OnigCodePoint
+CR_In_Early_Dynastic_Cuneiform[] = { 1,
+0x12480, 0x1254f,
+}; /* END of CR_In_Early_Dynastic_Cuneiform */
+
+/* PROPERTY: 'In_Egyptian_Hieroglyphs': Block */
+static const OnigCodePoint
+CR_In_Egyptian_Hieroglyphs[] = { 1,
+0x13000, 0x1342f,
+}; /* END of CR_In_Egyptian_Hieroglyphs */
+
+/* PROPERTY: 'In_Egyptian_Hieroglyph_Format_Controls': Block */
+static const OnigCodePoint
+CR_In_Egyptian_Hieroglyph_Format_Controls[] = { 1,
+0x13430, 0x1343f,
+}; /* END of CR_In_Egyptian_Hieroglyph_Format_Controls */
+
+/* PROPERTY: 'In_Anatolian_Hieroglyphs': Block */
+static const OnigCodePoint
+CR_In_Anatolian_Hieroglyphs[] = { 1,
+0x14400, 0x1467f,
+}; /* END of CR_In_Anatolian_Hieroglyphs */
+
+/* PROPERTY: 'In_Bamum_Supplement': Block */
+static const OnigCodePoint
+CR_In_Bamum_Supplement[] = { 1,
+0x16800, 0x16a3f,
+}; /* END of CR_In_Bamum_Supplement */
+
+/* PROPERTY: 'In_Mro': Block */
+static const OnigCodePoint
+CR_In_Mro[] = { 1,
+0x16a40, 0x16a6f,
+}; /* END of CR_In_Mro */
+
+/* PROPERTY: 'In_Bassa_Vah': Block */
+static const OnigCodePoint
+CR_In_Bassa_Vah[] = { 1,
+0x16ad0, 0x16aff,
+}; /* END of CR_In_Bassa_Vah */
+
+/* PROPERTY: 'In_Pahawh_Hmong': Block */
+static const OnigCodePoint
+CR_In_Pahawh_Hmong[] = { 1,
+0x16b00, 0x16b8f,
+}; /* END of CR_In_Pahawh_Hmong */
+
+/* PROPERTY: 'In_Medefaidrin': Block */
+static const OnigCodePoint
+CR_In_Medefaidrin[] = { 1,
+0x16e40, 0x16e9f,
+}; /* END of CR_In_Medefaidrin */
+
+/* PROPERTY: 'In_Miao': Block */
+static const OnigCodePoint
+CR_In_Miao[] = { 1,
+0x16f00, 0x16f9f,
+}; /* END of CR_In_Miao */
+
+/* PROPERTY: 'In_Ideographic_Symbols_and_Punctuation': Block */
+static const OnigCodePoint
+CR_In_Ideographic_Symbols_and_Punctuation[] = { 1,
+0x16fe0, 0x16fff,
+}; /* END of CR_In_Ideographic_Symbols_and_Punctuation */
+
+/* PROPERTY: 'In_Tangut': Block */
+static const OnigCodePoint
+CR_In_Tangut[] = { 1,
+0x17000, 0x187ff,
+}; /* END of CR_In_Tangut */
+
+/* PROPERTY: 'In_Tangut_Components': Block */
+static const OnigCodePoint
+CR_In_Tangut_Components[] = { 1,
+0x18800, 0x18aff,
+}; /* END of CR_In_Tangut_Components */
+
+/* PROPERTY: 'In_Kana_Supplement': Block */
+static const OnigCodePoint
+CR_In_Kana_Supplement[] = { 1,
+0x1b000, 0x1b0ff,
+}; /* END of CR_In_Kana_Supplement */
+
+/* PROPERTY: 'In_Kana_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Kana_Extended_A[] = { 1,
+0x1b100, 0x1b12f,
+}; /* END of CR_In_Kana_Extended_A */
+
+/* PROPERTY: 'In_Small_Kana_Extension': Block */
+static const OnigCodePoint
+CR_In_Small_Kana_Extension[] = { 1,
+0x1b130, 0x1b16f,
+}; /* END of CR_In_Small_Kana_Extension */
+
+/* PROPERTY: 'In_Nushu': Block */
+static const OnigCodePoint
+CR_In_Nushu[] = { 1,
+0x1b170, 0x1b2ff,
+}; /* END of CR_In_Nushu */
+
+/* PROPERTY: 'In_Duployan': Block */
+static const OnigCodePoint
+CR_In_Duployan[] = { 1,
+0x1bc00, 0x1bc9f,
+}; /* END of CR_In_Duployan */
+
+/* PROPERTY: 'In_Shorthand_Format_Controls': Block */
+static const OnigCodePoint
+CR_In_Shorthand_Format_Controls[] = { 1,
+0x1bca0, 0x1bcaf,
+}; /* END of CR_In_Shorthand_Format_Controls */
+
+/* PROPERTY: 'In_Byzantine_Musical_Symbols': Block */
+static const OnigCodePoint
+CR_In_Byzantine_Musical_Symbols[] = { 1,
+0x1d000, 0x1d0ff,
+}; /* END of CR_In_Byzantine_Musical_Symbols */
+
+/* PROPERTY: 'In_Musical_Symbols': Block */
+static const OnigCodePoint
+CR_In_Musical_Symbols[] = { 1,
+0x1d100, 0x1d1ff,
+}; /* END of CR_In_Musical_Symbols */
+
+/* PROPERTY: 'In_Ancient_Greek_Musical_Notation': Block */
+static const OnigCodePoint
+CR_In_Ancient_Greek_Musical_Notation[] = { 1,
+0x1d200, 0x1d24f,
+}; /* END of CR_In_Ancient_Greek_Musical_Notation */
+
+/* PROPERTY: 'In_Mayan_Numerals': Block */
+static const OnigCodePoint
+CR_In_Mayan_Numerals[] = { 1,
+0x1d2e0, 0x1d2ff,
+}; /* END of CR_In_Mayan_Numerals */
+
+/* PROPERTY: 'In_Tai_Xuan_Jing_Symbols': Block */
+static const OnigCodePoint
+CR_In_Tai_Xuan_Jing_Symbols[] = { 1,
+0x1d300, 0x1d35f,
+}; /* END of CR_In_Tai_Xuan_Jing_Symbols */
+
+/* PROPERTY: 'In_Counting_Rod_Numerals': Block */
+static const OnigCodePoint
+CR_In_Counting_Rod_Numerals[] = { 1,
+0x1d360, 0x1d37f,
+}; /* END of CR_In_Counting_Rod_Numerals */
+
+/* PROPERTY: 'In_Mathematical_Alphanumeric_Symbols': Block */
+static const OnigCodePoint
+CR_In_Mathematical_Alphanumeric_Symbols[] = { 1,
+0x1d400, 0x1d7ff,
+}; /* END of CR_In_Mathematical_Alphanumeric_Symbols */
+
+/* PROPERTY: 'In_Sutton_SignWriting': Block */
+static const OnigCodePoint
+CR_In_Sutton_SignWriting[] = { 1,
+0x1d800, 0x1daaf,
+}; /* END of CR_In_Sutton_SignWriting */
+
+/* PROPERTY: 'In_Glagolitic_Supplement': Block */
+static const OnigCodePoint
+CR_In_Glagolitic_Supplement[] = { 1,
+0x1e000, 0x1e02f,
+}; /* END of CR_In_Glagolitic_Supplement */
+
+/* PROPERTY: 'In_Nyiakeng_Puachue_Hmong': Block */
+static const OnigCodePoint
+CR_In_Nyiakeng_Puachue_Hmong[] = { 1,
+0x1e100, 0x1e14f,
+}; /* END of CR_In_Nyiakeng_Puachue_Hmong */
+
+/* PROPERTY: 'In_Wancho': Block */
+static const OnigCodePoint
+CR_In_Wancho[] = { 1,
+0x1e2c0, 0x1e2ff,
+}; /* END of CR_In_Wancho */
+
+/* PROPERTY: 'In_Mende_Kikakui': Block */
+static const OnigCodePoint
+CR_In_Mende_Kikakui[] = { 1,
+0x1e800, 0x1e8df,
+}; /* END of CR_In_Mende_Kikakui */
+
+/* PROPERTY: 'In_Adlam': Block */
+static const OnigCodePoint
+CR_In_Adlam[] = { 1,
+0x1e900, 0x1e95f,
+}; /* END of CR_In_Adlam */
+
+/* PROPERTY: 'In_Indic_Siyaq_Numbers': Block */
+static const OnigCodePoint
+CR_In_Indic_Siyaq_Numbers[] = { 1,
+0x1ec70, 0x1ecbf,
+}; /* END of CR_In_Indic_Siyaq_Numbers */
+
+/* PROPERTY: 'In_Ottoman_Siyaq_Numbers': Block */
+static const OnigCodePoint
+CR_In_Ottoman_Siyaq_Numbers[] = { 1,
+0x1ed00, 0x1ed4f,
+}; /* END of CR_In_Ottoman_Siyaq_Numbers */
+
+/* PROPERTY: 'In_Arabic_Mathematical_Alphabetic_Symbols': Block */
+static const OnigCodePoint
+CR_In_Arabic_Mathematical_Alphabetic_Symbols[] = { 1,
+0x1ee00, 0x1eeff,
+}; /* END of CR_In_Arabic_Mathematical_Alphabetic_Symbols */
+
+/* PROPERTY: 'In_Mahjong_Tiles': Block */
+static const OnigCodePoint
+CR_In_Mahjong_Tiles[] = { 1,
+0x1f000, 0x1f02f,
+}; /* END of CR_In_Mahjong_Tiles */
+
+/* PROPERTY: 'In_Domino_Tiles': Block */
+static const OnigCodePoint
+CR_In_Domino_Tiles[] = { 1,
+0x1f030, 0x1f09f,
+}; /* END of CR_In_Domino_Tiles */
+
+/* PROPERTY: 'In_Playing_Cards': Block */
+static const OnigCodePoint
+CR_In_Playing_Cards[] = { 1,
+0x1f0a0, 0x1f0ff,
+}; /* END of CR_In_Playing_Cards */
+
+/* PROPERTY: 'In_Enclosed_Alphanumeric_Supplement': Block */
+static const OnigCodePoint
+CR_In_Enclosed_Alphanumeric_Supplement[] = { 1,
+0x1f100, 0x1f1ff,
+}; /* END of CR_In_Enclosed_Alphanumeric_Supplement */
+
+/* PROPERTY: 'In_Enclosed_Ideographic_Supplement': Block */
+static const OnigCodePoint
+CR_In_Enclosed_Ideographic_Supplement[] = { 1,
+0x1f200, 0x1f2ff,
+}; /* END of CR_In_Enclosed_Ideographic_Supplement */
+
+/* PROPERTY: 'In_Miscellaneous_Symbols_and_Pictographs': Block */
+static const OnigCodePoint
+CR_In_Miscellaneous_Symbols_and_Pictographs[] = { 1,
+0x1f300, 0x1f5ff,
+}; /* END of CR_In_Miscellaneous_Symbols_and_Pictographs */
+
+/* PROPERTY: 'In_Emoticons': Block */
+static const OnigCodePoint
+CR_In_Emoticons[] = { 1,
+0x1f600, 0x1f64f,
+}; /* END of CR_In_Emoticons */
+
+/* PROPERTY: 'In_Ornamental_Dingbats': Block */
+static const OnigCodePoint
+CR_In_Ornamental_Dingbats[] = { 1,
+0x1f650, 0x1f67f,
+}; /* END of CR_In_Ornamental_Dingbats */
+
+/* PROPERTY: 'In_Transport_and_Map_Symbols': Block */
+static const OnigCodePoint
+CR_In_Transport_and_Map_Symbols[] = { 1,
+0x1f680, 0x1f6ff,
+}; /* END of CR_In_Transport_and_Map_Symbols */
+
+/* PROPERTY: 'In_Alchemical_Symbols': Block */
+static const OnigCodePoint
+CR_In_Alchemical_Symbols[] = { 1,
+0x1f700, 0x1f77f,
+}; /* END of CR_In_Alchemical_Symbols */
+
+/* PROPERTY: 'In_Geometric_Shapes_Extended': Block */
+static const OnigCodePoint
+CR_In_Geometric_Shapes_Extended[] = { 1,
+0x1f780, 0x1f7ff,
+}; /* END of CR_In_Geometric_Shapes_Extended */
+
+/* PROPERTY: 'In_Supplemental_Arrows_C': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Arrows_C[] = { 1,
+0x1f800, 0x1f8ff,
+}; /* END of CR_In_Supplemental_Arrows_C */
+
+/* PROPERTY: 'In_Supplemental_Symbols_and_Pictographs': Block */
+static const OnigCodePoint
+CR_In_Supplemental_Symbols_and_Pictographs[] = { 1,
+0x1f900, 0x1f9ff,
+}; /* END of CR_In_Supplemental_Symbols_and_Pictographs */
+
+/* PROPERTY: 'In_Chess_Symbols': Block */
+static const OnigCodePoint
+CR_In_Chess_Symbols[] = { 1,
+0x1fa00, 0x1fa6f,
+}; /* END of CR_In_Chess_Symbols */
+
+/* PROPERTY: 'In_Symbols_and_Pictographs_Extended_A': Block */
+static const OnigCodePoint
+CR_In_Symbols_and_Pictographs_Extended_A[] = { 1,
+0x1fa70, 0x1faff,
+}; /* END of CR_In_Symbols_and_Pictographs_Extended_A */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_B': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_B[] = { 1,
+0x20000, 0x2a6df,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_B */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_C': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_C[] = { 1,
+0x2a700, 0x2b73f,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_C */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_D': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_D[] = { 1,
+0x2b740, 0x2b81f,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_D */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_E': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_E[] = { 1,
+0x2b820, 0x2ceaf,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_E */
+
+/* PROPERTY: 'In_CJK_Unified_Ideographs_Extension_F': Block */
+static const OnigCodePoint
+CR_In_CJK_Unified_Ideographs_Extension_F[] = { 1,
+0x2ceb0, 0x2ebef,
+}; /* END of CR_In_CJK_Unified_Ideographs_Extension_F */
+
+/* PROPERTY: 'In_CJK_Compatibility_Ideographs_Supplement': Block */
+static const OnigCodePoint
+CR_In_CJK_Compatibility_Ideographs_Supplement[] = { 1,
+0x2f800, 0x2fa1f,
+}; /* END of CR_In_CJK_Compatibility_Ideographs_Supplement */
+
+/* PROPERTY: 'In_Tags': Block */
+static const OnigCodePoint
+CR_In_Tags[] = { 1,
+0xe0000, 0xe007f,
+}; /* END of CR_In_Tags */
+
+/* PROPERTY: 'In_Variation_Selectors_Supplement': Block */
+static const OnigCodePoint
+CR_In_Variation_Selectors_Supplement[] = { 1,
+0xe0100, 0xe01ef,
+}; /* END of CR_In_Variation_Selectors_Supplement */
+
+/* PROPERTY: 'In_Supplementary_Private_Use_Area_A': Block */
+static const OnigCodePoint
+CR_In_Supplementary_Private_Use_Area_A[] = { 1,
+0xf0000, 0xfffff,
+}; /* END of CR_In_Supplementary_Private_Use_Area_A */
+
+/* PROPERTY: 'In_Supplementary_Private_Use_Area_B': Block */
+static const OnigCodePoint
+CR_In_Supplementary_Private_Use_Area_B[] = { 1,
+0x100000, 0x10ffff,
+}; /* END of CR_In_Supplementary_Private_Use_Area_B */
+
+/* PROPERTY: 'In_No_Block': Block */
+static const OnigCodePoint
+CR_In_No_Block[] = { 53,
+0x0870, 0x089f,
+0x2fe0, 0x2fef,
+0x10200, 0x1027f,
+0x103e0, 0x103ff,
+0x10570, 0x105ff,
+0x10780, 0x107ff,
+0x108b0, 0x108df,
+0x10940, 0x1097f,
+0x10aa0, 0x10abf,
+0x10bb0, 0x10bff,
+0x10c50, 0x10c7f,
+0x10d40, 0x10e5f,
+0x10e80, 0x10eff,
+0x10f70, 0x10fdf,
+0x11250, 0x1127f,
+0x11380, 0x113ff,
+0x114e0, 0x1157f,
+0x116d0, 0x116ff,
+0x11740, 0x117ff,
+0x11850, 0x1189f,
+0x11900, 0x1199f,
+0x11ab0, 0x11abf,
+0x11b00, 0x11bff,
+0x11cc0, 0x11cff,
+0x11db0, 0x11edf,
+0x11f00, 0x11fbf,
+0x12550, 0x12fff,
+0x13440, 0x143ff,
+0x14680, 0x167ff,
+0x16a70, 0x16acf,
+0x16b90, 0x16e3f,
+0x16ea0, 0x16eff,
+0x16fa0, 0x16fdf,
+0x18b00, 0x1afff,
+0x1b300, 0x1bbff,
+0x1bcb0, 0x1cfff,
+0x1d250, 0x1d2df,
+0x1d380, 0x1d3ff,
+0x1dab0, 0x1dfff,
+0x1e030, 0x1e0ff,
+0x1e150, 0x1e2bf,
+0x1e300, 0x1e7ff,
+0x1e8e0, 0x1e8ff,
+0x1e960, 0x1ec6f,
+0x1ecc0, 0x1ecff,
+0x1ed50, 0x1edff,
+0x1ef00, 0x1efff,
+0x1fb00, 0x1ffff,
+0x2a6e0, 0x2a6ff,
+0x2ebf0, 0x2f7ff,
+0x2fa20, 0xdffff,
+0xe0080, 0xe00ff,
+0xe01f0, 0xeffff,
+}; /* END of CR_In_No_Block */
+
+static const OnigCodePoint*
+const CodeRanges[] = {
+ CR_NEWLINE,
+ CR_Alpha,
+ CR_Blank,
+ CR_Cntrl,
+ CR_Digit,
+ CR_Graph,
+ CR_Lower,
+ CR_Print,
+ CR_Punct,
+ CR_Space,
+ CR_Upper,
+ CR_XDigit,
+ CR_Word,
+ CR_Alnum,
+ CR_ASCII,
+ CR_ASCII_Hex_Digit,
+ CR_Adlam,
+ CR_Ahom,
+ CR_Alphabetic,
+ CR_Anatolian_Hieroglyphs,
+ CR_Any,
+ CR_Arabic,
+ CR_Armenian,
+ CR_Assigned,
+ CR_Avestan,
+ CR_Balinese,
+ CR_Bamum,
+ CR_Bassa_Vah,
+ CR_Batak,
+ CR_Bengali,
+ CR_Bhaiksuki,
+ CR_Bidi_Control,
+ CR_Bopomofo,
+ CR_Brahmi,
+ CR_Braille,
+ CR_Buginese,
+ CR_Buhid,
+ CR_C,
+ CR_Canadian_Aboriginal,
+ CR_Carian,
+ CR_Case_Ignorable,
+ CR_Cased,
+ CR_Caucasian_Albanian,
+ CR_Cc,
+ CR_Cf,
+ CR_Chakma,
+ CR_Cham,
+ CR_Changes_When_Casefolded,
+ CR_Changes_When_Casemapped,
+ CR_Changes_When_Lowercased,
+ CR_Changes_When_Titlecased,
+ CR_Changes_When_Uppercased,
+ CR_Cherokee,
+ CR_Cn,
+ CR_Co,
+ CR_Common,
+ CR_Coptic,
+ CR_Cs,
+ CR_Cuneiform,
+ CR_Cypriot,
+ CR_Cyrillic,
+ CR_Dash,
+ CR_Default_Ignorable_Code_Point,
+ CR_Deprecated,
+ CR_Deseret,
+ CR_Devanagari,
+ CR_Diacritic,
+ CR_Dogra,
+ CR_Duployan,
+ CR_Egyptian_Hieroglyphs,
+ CR_Elbasan,
+ CR_Elymaic,
+ CR_Emoji,
+ CR_Emoji_Component,
+ CR_Emoji_Modifier,
+ CR_Emoji_Modifier_Base,
+ CR_Emoji_Presentation,
+ CR_Ethiopic,
+ CR_Extended_Pictographic,
+ CR_Extender,
+ CR_Georgian,
+ CR_Glagolitic,
+ CR_Gothic,
+ CR_Grantha,
+ CR_Grapheme_Base,
+ CR_Grapheme_Extend,
+ CR_Grapheme_Link,
+ CR_Greek,
+ CR_Gujarati,
+ CR_Gunjala_Gondi,
+ CR_Gurmukhi,
+ CR_Han,
+ CR_Hangul,
+ CR_Hanifi_Rohingya,
+ CR_Hanunoo,
+ CR_Hatran,
+ CR_Hebrew,
+ CR_Hex_Digit,
+ CR_Hiragana,
+ CR_Hyphen,
+ CR_IDS_Binary_Operator,
+ CR_IDS_Trinary_Operator,
+ CR_ID_Continue,
+ CR_ID_Start,
+ CR_Ideographic,
+ CR_Imperial_Aramaic,
+ CR_Inherited,
+ CR_Inscriptional_Pahlavi,
+ CR_Inscriptional_Parthian,
+ CR_Javanese,
+ CR_Join_Control,
+ CR_Kaithi,
+ CR_Kannada,
+ CR_Katakana,
+ CR_Kayah_Li,
+ CR_Kharoshthi,
+ CR_Khmer,
+ CR_Khojki,
+ CR_Khudawadi,
+ CR_L,
+ CR_LC,
+ CR_Lao,
+ CR_Latin,
+ CR_Lepcha,
+ CR_Limbu,
+ CR_Linear_A,
+ CR_Linear_B,
+ CR_Lisu,
+ CR_Ll,
+ CR_Lm,
+ CR_Lo,
+ CR_Logical_Order_Exception,
+ CR_Lowercase,
+ CR_Lt,
+ CR_Lu,
+ CR_Lycian,
+ CR_Lydian,
+ CR_M,
+ CR_Mahajani,
+ CR_Makasar,
+ CR_Malayalam,
+ CR_Mandaic,
+ CR_Manichaean,
+ CR_Marchen,
+ CR_Masaram_Gondi,
+ CR_Math,
+ CR_Mc,
+ CR_Me,
+ CR_Medefaidrin,
+ CR_Meetei_Mayek,
+ CR_Mende_Kikakui,
+ CR_Meroitic_Cursive,
+ CR_Meroitic_Hieroglyphs,
+ CR_Miao,
+ CR_Mn,
+ CR_Modi,
+ CR_Mongolian,
+ CR_Mro,
+ CR_Multani,
+ CR_Myanmar,
+ CR_N,
+ CR_Nabataean,
+ CR_Nandinagari,
+ CR_Nd,
+ CR_New_Tai_Lue,
+ CR_Newa,
+ CR_Nko,
+ CR_Nl,
+ CR_No,
+ CR_Noncharacter_Code_Point,
+ CR_Nushu,
+ CR_Nyiakeng_Puachue_Hmong,
+ CR_Ogham,
+ CR_Ol_Chiki,
+ CR_Old_Hungarian,
+ CR_Old_Italic,
+ CR_Old_North_Arabian,
+ CR_Old_Permic,
+ CR_Old_Persian,
+ CR_Old_Sogdian,
+ CR_Old_South_Arabian,
+ CR_Old_Turkic,
+ CR_Oriya,
+ CR_Osage,
+ CR_Osmanya,
+ CR_Other_Alphabetic,
+ CR_Other_Default_Ignorable_Code_Point,
+ CR_Other_Grapheme_Extend,
+ CR_Other_ID_Continue,
+ CR_Other_ID_Start,
+ CR_Other_Lowercase,
+ CR_Other_Math,
+ CR_Other_Uppercase,
+ CR_P,
+ CR_Pahawh_Hmong,
+ CR_Palmyrene,
+ CR_Pattern_Syntax,
+ CR_Pattern_White_Space,
+ CR_Pau_Cin_Hau,
+ CR_Pc,
+ CR_Pd,
+ CR_Pe,
+ CR_Pf,
+ CR_Phags_Pa,
+ CR_Phoenician,
+ CR_Pi,
+ CR_Po,
+ CR_Prepended_Concatenation_Mark,
+ CR_Ps,
+ CR_Psalter_Pahlavi,
+ CR_Quotation_Mark,
+ CR_Radical,
+ CR_Regional_Indicator,
+ CR_Rejang,
+ CR_Runic,
+ CR_S,
+ CR_Samaritan,
+ CR_Saurashtra,
+ CR_Sc,
+ CR_Sentence_Terminal,
+ CR_Sharada,
+ CR_Shavian,
+ CR_Siddham,
+ CR_SignWriting,
+ CR_Sinhala,
+ CR_Sk,
+ CR_Sm,
+ CR_So,
+ CR_Soft_Dotted,
+ CR_Sogdian,
+ CR_Sora_Sompeng,
+ CR_Soyombo,
+ CR_Sundanese,
+ CR_Syloti_Nagri,
+ CR_Syriac,
+ CR_Tagalog,
+ CR_Tagbanwa,
+ CR_Tai_Le,
+ CR_Tai_Tham,
+ CR_Tai_Viet,
+ CR_Takri,
+ CR_Tamil,
+ CR_Tangut,
+ CR_Telugu,
+ CR_Terminal_Punctuation,
+ CR_Thaana,
+ CR_Thai,
+ CR_Tibetan,
+ CR_Tifinagh,
+ CR_Tirhuta,
+ CR_Ugaritic,
+ CR_Unified_Ideograph,
+ CR_Unknown,
+ CR_Uppercase,
+ CR_Vai,
+ CR_Variation_Selector,
+ CR_Wancho,
+ CR_Warang_Citi,
+ CR_White_Space,
+ CR_XID_Continue,
+ CR_XID_Start,
+ CR_Yi,
+ CR_Z,
+ CR_Zanabazar_Square,
+ CR_Zl,
+ CR_Zp,
+ CR_Zs,
+ CR_In_Basic_Latin,
+ CR_In_Latin_1_Supplement,
+ CR_In_Latin_Extended_A,
+ CR_In_Latin_Extended_B,
+ CR_In_IPA_Extensions,
+ CR_In_Spacing_Modifier_Letters,
+ CR_In_Combining_Diacritical_Marks,
+ CR_In_Greek_and_Coptic,
+ CR_In_Cyrillic,
+ CR_In_Cyrillic_Supplement,
+ CR_In_Armenian,
+ CR_In_Hebrew,
+ CR_In_Arabic,
+ CR_In_Syriac,
+ CR_In_Arabic_Supplement,
+ CR_In_Thaana,
+ CR_In_NKo,
+ CR_In_Samaritan,
+ CR_In_Mandaic,
+ CR_In_Syriac_Supplement,
+ CR_In_Arabic_Extended_A,
+ CR_In_Devanagari,
+ CR_In_Bengali,
+ CR_In_Gurmukhi,
+ CR_In_Gujarati,
+ CR_In_Oriya,
+ CR_In_Tamil,
+ CR_In_Telugu,
+ CR_In_Kannada,
+ CR_In_Malayalam,
+ CR_In_Sinhala,
+ CR_In_Thai,
+ CR_In_Lao,
+ CR_In_Tibetan,
+ CR_In_Myanmar,
+ CR_In_Georgian,
+ CR_In_Hangul_Jamo,
+ CR_In_Ethiopic,
+ CR_In_Ethiopic_Supplement,
+ CR_In_Cherokee,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics,
+ CR_In_Ogham,
+ CR_In_Runic,
+ CR_In_Tagalog,
+ CR_In_Hanunoo,
+ CR_In_Buhid,
+ CR_In_Tagbanwa,
+ CR_In_Khmer,
+ CR_In_Mongolian,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended,
+ CR_In_Limbu,
+ CR_In_Tai_Le,
+ CR_In_New_Tai_Lue,
+ CR_In_Khmer_Symbols,
+ CR_In_Buginese,
+ CR_In_Tai_Tham,
+ CR_In_Combining_Diacritical_Marks_Extended,
+ CR_In_Balinese,
+ CR_In_Sundanese,
+ CR_In_Batak,
+ CR_In_Lepcha,
+ CR_In_Ol_Chiki,
+ CR_In_Cyrillic_Extended_C,
+ CR_In_Georgian_Extended,
+ CR_In_Sundanese_Supplement,
+ CR_In_Vedic_Extensions,
+ CR_In_Phonetic_Extensions,
+ CR_In_Phonetic_Extensions_Supplement,
+ CR_In_Combining_Diacritical_Marks_Supplement,
+ CR_In_Latin_Extended_Additional,
+ CR_In_Greek_Extended,
+ CR_In_General_Punctuation,
+ CR_In_Superscripts_and_Subscripts,
+ CR_In_Currency_Symbols,
+ CR_In_Combining_Diacritical_Marks_for_Symbols,
+ CR_In_Letterlike_Symbols,
+ CR_In_Number_Forms,
+ CR_In_Arrows,
+ CR_In_Mathematical_Operators,
+ CR_In_Miscellaneous_Technical,
+ CR_In_Control_Pictures,
+ CR_In_Optical_Character_Recognition,
+ CR_In_Enclosed_Alphanumerics,
+ CR_In_Box_Drawing,
+ CR_In_Block_Elements,
+ CR_In_Geometric_Shapes,
+ CR_In_Miscellaneous_Symbols,
+ CR_In_Dingbats,
+ CR_In_Miscellaneous_Mathematical_Symbols_A,
+ CR_In_Supplemental_Arrows_A,
+ CR_In_Braille_Patterns,
+ CR_In_Supplemental_Arrows_B,
+ CR_In_Miscellaneous_Mathematical_Symbols_B,
+ CR_In_Supplemental_Mathematical_Operators,
+ CR_In_Miscellaneous_Symbols_and_Arrows,
+ CR_In_Glagolitic,
+ CR_In_Latin_Extended_C,
+ CR_In_Coptic,
+ CR_In_Georgian_Supplement,
+ CR_In_Tifinagh,
+ CR_In_Ethiopic_Extended,
+ CR_In_Cyrillic_Extended_A,
+ CR_In_Supplemental_Punctuation,
+ CR_In_CJK_Radicals_Supplement,
+ CR_In_Kangxi_Radicals,
+ CR_In_Ideographic_Description_Characters,
+ CR_In_CJK_Symbols_and_Punctuation,
+ CR_In_Hiragana,
+ CR_In_Katakana,
+ CR_In_Bopomofo,
+ CR_In_Hangul_Compatibility_Jamo,
+ CR_In_Kanbun,
+ CR_In_Bopomofo_Extended,
+ CR_In_CJK_Strokes,
+ CR_In_Katakana_Phonetic_Extensions,
+ CR_In_Enclosed_CJK_Letters_and_Months,
+ CR_In_CJK_Compatibility,
+ CR_In_CJK_Unified_Ideographs_Extension_A,
+ CR_In_Yijing_Hexagram_Symbols,
+ CR_In_CJK_Unified_Ideographs,
+ CR_In_Yi_Syllables,
+ CR_In_Yi_Radicals,
+ CR_In_Lisu,
+ CR_In_Vai,
+ CR_In_Cyrillic_Extended_B,
+ CR_In_Bamum,
+ CR_In_Modifier_Tone_Letters,
+ CR_In_Latin_Extended_D,
+ CR_In_Syloti_Nagri,
+ CR_In_Common_Indic_Number_Forms,
+ CR_In_Phags_pa,
+ CR_In_Saurashtra,
+ CR_In_Devanagari_Extended,
+ CR_In_Kayah_Li,
+ CR_In_Rejang,
+ CR_In_Hangul_Jamo_Extended_A,
+ CR_In_Javanese,
+ CR_In_Myanmar_Extended_B,
+ CR_In_Cham,
+ CR_In_Myanmar_Extended_A,
+ CR_In_Tai_Viet,
+ CR_In_Meetei_Mayek_Extensions,
+ CR_In_Ethiopic_Extended_A,
+ CR_In_Latin_Extended_E,
+ CR_In_Cherokee_Supplement,
+ CR_In_Meetei_Mayek,
+ CR_In_Hangul_Syllables,
+ CR_In_Hangul_Jamo_Extended_B,
+ CR_In_High_Surrogates,
+ CR_In_High_Private_Use_Surrogates,
+ CR_In_Low_Surrogates,
+ CR_In_Private_Use_Area,
+ CR_In_CJK_Compatibility_Ideographs,
+ CR_In_Alphabetic_Presentation_Forms,
+ CR_In_Arabic_Presentation_Forms_A,
+ CR_In_Variation_Selectors,
+ CR_In_Vertical_Forms,
+ CR_In_Combining_Half_Marks,
+ CR_In_CJK_Compatibility_Forms,
+ CR_In_Small_Form_Variants,
+ CR_In_Arabic_Presentation_Forms_B,
+ CR_In_Halfwidth_and_Fullwidth_Forms,
+ CR_In_Specials,
+ CR_In_Linear_B_Syllabary,
+ CR_In_Linear_B_Ideograms,
+ CR_In_Aegean_Numbers,
+ CR_In_Ancient_Greek_Numbers,
+ CR_In_Ancient_Symbols,
+ CR_In_Phaistos_Disc,
+ CR_In_Lycian,
+ CR_In_Carian,
+ CR_In_Coptic_Epact_Numbers,
+ CR_In_Old_Italic,
+ CR_In_Gothic,
+ CR_In_Old_Permic,
+ CR_In_Ugaritic,
+ CR_In_Old_Persian,
+ CR_In_Deseret,
+ CR_In_Shavian,
+ CR_In_Osmanya,
+ CR_In_Osage,
+ CR_In_Elbasan,
+ CR_In_Caucasian_Albanian,
+ CR_In_Linear_A,
+ CR_In_Cypriot_Syllabary,
+ CR_In_Imperial_Aramaic,
+ CR_In_Palmyrene,
+ CR_In_Nabataean,
+ CR_In_Hatran,
+ CR_In_Phoenician,
+ CR_In_Lydian,
+ CR_In_Meroitic_Hieroglyphs,
+ CR_In_Meroitic_Cursive,
+ CR_In_Kharoshthi,
+ CR_In_Old_South_Arabian,
+ CR_In_Old_North_Arabian,
+ CR_In_Manichaean,
+ CR_In_Avestan,
+ CR_In_Inscriptional_Parthian,
+ CR_In_Inscriptional_Pahlavi,
+ CR_In_Psalter_Pahlavi,
+ CR_In_Old_Turkic,
+ CR_In_Old_Hungarian,
+ CR_In_Hanifi_Rohingya,
+ CR_In_Rumi_Numeral_Symbols,
+ CR_In_Old_Sogdian,
+ CR_In_Sogdian,
+ CR_In_Elymaic,
+ CR_In_Brahmi,
+ CR_In_Kaithi,
+ CR_In_Sora_Sompeng,
+ CR_In_Chakma,
+ CR_In_Mahajani,
+ CR_In_Sharada,
+ CR_In_Sinhala_Archaic_Numbers,
+ CR_In_Khojki,
+ CR_In_Multani,
+ CR_In_Khudawadi,
+ CR_In_Grantha,
+ CR_In_Newa,
+ CR_In_Tirhuta,
+ CR_In_Siddham,
+ CR_In_Modi,
+ CR_In_Mongolian_Supplement,
+ CR_In_Takri,
+ CR_In_Ahom,
+ CR_In_Dogra,
+ CR_In_Warang_Citi,
+ CR_In_Nandinagari,
+ CR_In_Zanabazar_Square,
+ CR_In_Soyombo,
+ CR_In_Pau_Cin_Hau,
+ CR_In_Bhaiksuki,
+ CR_In_Marchen,
+ CR_In_Masaram_Gondi,
+ CR_In_Gunjala_Gondi,
+ CR_In_Makasar,
+ CR_In_Tamil_Supplement,
+ CR_In_Cuneiform,
+ CR_In_Cuneiform_Numbers_and_Punctuation,
+ CR_In_Early_Dynastic_Cuneiform,
+ CR_In_Egyptian_Hieroglyphs,
+ CR_In_Egyptian_Hieroglyph_Format_Controls,
+ CR_In_Anatolian_Hieroglyphs,
+ CR_In_Bamum_Supplement,
+ CR_In_Mro,
+ CR_In_Bassa_Vah,
+ CR_In_Pahawh_Hmong,
+ CR_In_Medefaidrin,
+ CR_In_Miao,
+ CR_In_Ideographic_Symbols_and_Punctuation,
+ CR_In_Tangut,
+ CR_In_Tangut_Components,
+ CR_In_Kana_Supplement,
+ CR_In_Kana_Extended_A,
+ CR_In_Small_Kana_Extension,
+ CR_In_Nushu,
+ CR_In_Duployan,
+ CR_In_Shorthand_Format_Controls,
+ CR_In_Byzantine_Musical_Symbols,
+ CR_In_Musical_Symbols,
+ CR_In_Ancient_Greek_Musical_Notation,
+ CR_In_Mayan_Numerals,
+ CR_In_Tai_Xuan_Jing_Symbols,
+ CR_In_Counting_Rod_Numerals,
+ CR_In_Mathematical_Alphanumeric_Symbols,
+ CR_In_Sutton_SignWriting,
+ CR_In_Glagolitic_Supplement,
+ CR_In_Nyiakeng_Puachue_Hmong,
+ CR_In_Wancho,
+ CR_In_Mende_Kikakui,
+ CR_In_Adlam,
+ CR_In_Indic_Siyaq_Numbers,
+ CR_In_Ottoman_Siyaq_Numbers,
+ CR_In_Arabic_Mathematical_Alphabetic_Symbols,
+ CR_In_Mahjong_Tiles,
+ CR_In_Domino_Tiles,
+ CR_In_Playing_Cards,
+ CR_In_Enclosed_Alphanumeric_Supplement,
+ CR_In_Enclosed_Ideographic_Supplement,
+ CR_In_Miscellaneous_Symbols_and_Pictographs,
+ CR_In_Emoticons,
+ CR_In_Ornamental_Dingbats,
+ CR_In_Transport_and_Map_Symbols,
+ CR_In_Alchemical_Symbols,
+ CR_In_Geometric_Shapes_Extended,
+ CR_In_Supplemental_Arrows_C,
+ CR_In_Supplemental_Symbols_and_Pictographs,
+ CR_In_Chess_Symbols,
+ CR_In_Symbols_and_Pictographs_Extended_A,
+ CR_In_CJK_Unified_Ideographs_Extension_B,
+ CR_In_CJK_Unified_Ideographs_Extension_C,
+ CR_In_CJK_Unified_Ideographs_Extension_D,
+ CR_In_CJK_Unified_Ideographs_Extension_E,
+ CR_In_CJK_Unified_Ideographs_Extension_F,
+ CR_In_CJK_Compatibility_Ideographs_Supplement,
+ CR_In_Tags,
+ CR_In_Variation_Selectors_Supplement,
+ CR_In_Supplementary_Private_Use_Area_A,
+ CR_In_Supplementary_Private_Use_Area_B,
+ CR_In_No_Block,
+};
+
+#define pool_offset(s) offsetof(struct unicode_prop_name_pool_t, unicode_prop_name_pool_str##s)
+
+
+#define TOTAL_KEYWORDS 801
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 44
+#define MIN_HASH_VALUE 10
+#define MAX_HASH_VALUE 5809
+/* maximum key range = 5800, duplicates = 0 */
+
+#ifndef GPERF_DOWNCASE
+#define GPERF_DOWNCASE 1
+static unsigned char gperf_downcase[256] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255
+ };
+#endif
+
+#ifndef GPERF_CASE_STRNCMP
+#define GPERF_CASE_STRNCMP 1
+static int
+gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
+{
+ for (; n > 0;)
+ {
+ unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
+ unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
+ if (c1 != 0 && c1 == c2)
+ {
+ n--;
+ continue;
+ }
+ return (int)c1 - (int)c2;
+ }
+ return 0;
+}
+#endif
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (register const char *str, register size_t len)
+{
+ static const unsigned short asso_values[] =
+ {
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 0, 1121, 136, 394, 19,
+ 417, 1048, 958, 7, 856, 8, 415, 103, 3, 16,
+ 1380, 1068, 56, 181, 326, 631, 1151, 930, 358, 1083,
+ 8, 0, 5, 5810, 5810, 5810, 5810, 0, 1121, 136,
+ 394, 19, 417, 1048, 958, 7, 856, 8, 415, 103,
+ 3, 16, 1380, 1068, 56, 181, 326, 631, 1151, 930,
+ 358, 1083, 8, 0, 5, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810,
+ 5810, 5810, 5810, 5810, 5810, 5810, 5810, 5810
+ };
+ register unsigned int hval = (unsigned int )len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[15]];
+ /*FALLTHROUGH*/
+ case 15:
+ case 14:
+ case 13:
+ case 12:
+ hval += asso_values[(unsigned char)str[11]];
+ /*FALLTHROUGH*/
+ case 11:
+ case 10:
+ case 9:
+ case 8:
+ case 7:
+ case 6:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]+2];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+struct unicode_prop_name_pool_t
+ {
+ char unicode_prop_name_pool_str10[sizeof("lana")];
+ char unicode_prop_name_pool_str14[sizeof("z")];
+ char unicode_prop_name_pool_str16[sizeof("yi")];
+ char unicode_prop_name_pool_str17[sizeof("lina")];
+ char unicode_prop_name_pool_str24[sizeof("mn")];
+ char unicode_prop_name_pool_str25[sizeof("yiii")];
+ char unicode_prop_name_pool_str27[sizeof("cn")];
+ char unicode_prop_name_pool_str28[sizeof("maka")];
+ char unicode_prop_name_pool_str30[sizeof("mani")];
+ char unicode_prop_name_pool_str33[sizeof("zzzz")];
+ char unicode_prop_name_pool_str34[sizeof("inkannada")];
+ char unicode_prop_name_pool_str35[sizeof("ci")];
+ char unicode_prop_name_pool_str37[sizeof("lo")];
+ char unicode_prop_name_pool_str38[sizeof("lao")];
+ char unicode_prop_name_pool_str39[sizeof("laoo")];
+ char unicode_prop_name_pool_str43[sizeof("miao")];
+ char unicode_prop_name_pool_str51[sizeof("innko")];
+ char unicode_prop_name_pool_str53[sizeof("co")];
+ char unicode_prop_name_pool_str56[sizeof("me")];
+ char unicode_prop_name_pool_str60[sizeof("loe")];
+ char unicode_prop_name_pool_str70[sizeof("gran")];
+ char unicode_prop_name_pool_str72[sizeof("pi")];
+ char unicode_prop_name_pool_str76[sizeof("lineara")];
+ char unicode_prop_name_pool_str84[sizeof("mark")];
+ char unicode_prop_name_pool_str86[sizeof("cari")];
+ char unicode_prop_name_pool_str87[sizeof("carian")];
+ char unicode_prop_name_pool_str90[sizeof("po")];
+ char unicode_prop_name_pool_str91[sizeof("mendekikakui")];
+ char unicode_prop_name_pool_str94[sizeof("grek")];
+ char unicode_prop_name_pool_str96[sizeof("pe")];
+ char unicode_prop_name_pool_str99[sizeof("meeteimayek")];
+ char unicode_prop_name_pool_str101[sizeof("inkharoshthi")];
+ char unicode_prop_name_pool_str102[sizeof("geor")];
+ char unicode_prop_name_pool_str103[sizeof("greek")];
+ char unicode_prop_name_pool_str107[sizeof("mro")];
+ char unicode_prop_name_pool_str108[sizeof("mroo")];
+ char unicode_prop_name_pool_str110[sizeof("kana")];
+ char unicode_prop_name_pool_str111[sizeof("mero")];
+ char unicode_prop_name_pool_str120[sizeof("m")];
+ char unicode_prop_name_pool_str133[sizeof("gonm")];
+ char unicode_prop_name_pool_str134[sizeof("cakm")];
+ char unicode_prop_name_pool_str139[sizeof("inosmanya")];
+ char unicode_prop_name_pool_str142[sizeof("inmanichaean")];
+ char unicode_prop_name_pool_str146[sizeof("inarmenian")];
+ char unicode_prop_name_pool_str151[sizeof("inmro")];
+ char unicode_prop_name_pool_str152[sizeof("inmiao")];
+ char unicode_prop_name_pool_str156[sizeof("c")];
+ char unicode_prop_name_pool_str163[sizeof("inchakma")];
+ char unicode_prop_name_pool_str166[sizeof("common")];
+ char unicode_prop_name_pool_str169[sizeof("mandaic")];
+ char unicode_prop_name_pool_str182[sizeof("inmyanmar")];
+ char unicode_prop_name_pool_str187[sizeof("inmakasar")];
+ char unicode_prop_name_pool_str192[sizeof("qaai")];
+ char unicode_prop_name_pool_str200[sizeof("inideographicsymbolsandpunctuation")];
+ char unicode_prop_name_pool_str204[sizeof("inkhmer")];
+ char unicode_prop_name_pool_str207[sizeof("cans")];
+ char unicode_prop_name_pool_str209[sizeof("prependedconcatenationmark")];
+ char unicode_prop_name_pool_str211[sizeof("lm")];
+ char unicode_prop_name_pool_str212[sizeof("marc")];
+ char unicode_prop_name_pool_str219[sizeof("connectorpunctuation")];
+ char unicode_prop_name_pool_str220[sizeof("inrunic")];
+ char unicode_prop_name_pool_str221[sizeof("incarian")];
+ char unicode_prop_name_pool_str223[sizeof("inavestan")];
+ char unicode_prop_name_pool_str225[sizeof("combiningmark")];
+ char unicode_prop_name_pool_str226[sizeof("incuneiformnumbersandpunctuation")];
+ char unicode_prop_name_pool_str231[sizeof("merc")];
+ char unicode_prop_name_pool_str238[sizeof("perm")];
+ char unicode_prop_name_pool_str239[sizeof("inahom")];
+ char unicode_prop_name_pool_str240[sizeof("inipaextensions")];
+ char unicode_prop_name_pool_str251[sizeof("incherokee")];
+ char unicode_prop_name_pool_str257[sizeof("insharada")];
+ char unicode_prop_name_pool_str268[sizeof("makasar")];
+ char unicode_prop_name_pool_str272[sizeof("inarrows")];
+ char unicode_prop_name_pool_str277[sizeof("lc")];
+ char unicode_prop_name_pool_str279[sizeof("masaramgondi")];
+ char unicode_prop_name_pool_str283[sizeof("incuneiform")];
+ char unicode_prop_name_pool_str290[sizeof("mc")];
+ char unicode_prop_name_pool_str293[sizeof("cc")];
+ char unicode_prop_name_pool_str295[sizeof("inzanabazarsquare")];
+ char unicode_prop_name_pool_str298[sizeof("lineseparator")];
+ char unicode_prop_name_pool_str302[sizeof("armn")];
+ char unicode_prop_name_pool_str305[sizeof("qmark")];
+ char unicode_prop_name_pool_str306[sizeof("armi")];
+ char unicode_prop_name_pool_str309[sizeof("insamaritan")];
+ char unicode_prop_name_pool_str316[sizeof("armenian")];
+ char unicode_prop_name_pool_str318[sizeof("inmarchen")];
+ char unicode_prop_name_pool_str319[sizeof("inmasaramgondi")];
+ char unicode_prop_name_pool_str321[sizeof("qaac")];
+ char unicode_prop_name_pool_str330[sizeof("pc")];
+ char unicode_prop_name_pool_str335[sizeof("inscriptionalparthian")];
+ char unicode_prop_name_pool_str336[sizeof("latn")];
+ char unicode_prop_name_pool_str340[sizeof("latin")];
+ char unicode_prop_name_pool_str342[sizeof("ri")];
+ char unicode_prop_name_pool_str345[sizeof("inthaana")];
+ char unicode_prop_name_pool_str352[sizeof("inkhmersymbols")];
+ char unicode_prop_name_pool_str355[sizeof("inkatakana")];
+ char unicode_prop_name_pool_str356[sizeof("incyrillic")];
+ char unicode_prop_name_pool_str357[sizeof("inthai")];
+ char unicode_prop_name_pool_str359[sizeof("incham")];
+ char unicode_prop_name_pool_str367[sizeof("inkaithi")];
+ char unicode_prop_name_pool_str369[sizeof("zs")];
+ char unicode_prop_name_pool_str372[sizeof("mtei")];
+ char unicode_prop_name_pool_str375[sizeof("vai")];
+ char unicode_prop_name_pool_str376[sizeof("vaii")];
+ char unicode_prop_name_pool_str379[sizeof("initialpunctuation")];
+ char unicode_prop_name_pool_str383[sizeof("cs")];
+ char unicode_prop_name_pool_str399[sizeof("insyriac")];
+ char unicode_prop_name_pool_str401[sizeof("pcm")];
+ char unicode_prop_name_pool_str415[sizeof("intakri")];
+ char unicode_prop_name_pool_str417[sizeof("mand")];
+ char unicode_prop_name_pool_str419[sizeof("l")];
+ char unicode_prop_name_pool_str420[sizeof("ps")];
+ char unicode_prop_name_pool_str427[sizeof("dia")];
+ char unicode_prop_name_pool_str431[sizeof("inkanaextendeda")];
+ char unicode_prop_name_pool_str433[sizeof("di")];
+ char unicode_prop_name_pool_str436[sizeof("mend")];
+ char unicode_prop_name_pool_str437[sizeof("modi")];
+ char unicode_prop_name_pool_str441[sizeof("ideo")];
+ char unicode_prop_name_pool_str445[sizeof("katakana")];
+ char unicode_prop_name_pool_str449[sizeof("prti")];
+ char unicode_prop_name_pool_str456[sizeof("inideographicdescriptioncharacters")];
+ char unicode_prop_name_pool_str457[sizeof("inlineara")];
+ char unicode_prop_name_pool_str458[sizeof("xidcontinue")];
+ char unicode_prop_name_pool_str461[sizeof("brai")];
+ char unicode_prop_name_pool_str463[sizeof("inlao")];
+ char unicode_prop_name_pool_str472[sizeof("ascii")];
+ char unicode_prop_name_pool_str474[sizeof("privateuse")];
+ char unicode_prop_name_pool_str477[sizeof("arabic")];
+ char unicode_prop_name_pool_str478[sizeof("mongolian")];
+ char unicode_prop_name_pool_str480[sizeof("inmyanmarextendeda")];
+ char unicode_prop_name_pool_str481[sizeof("inruminumeralsymbols")];
+ char unicode_prop_name_pool_str485[sizeof("letter")];
+ char unicode_prop_name_pool_str487[sizeof("innandinagari")];
+ char unicode_prop_name_pool_str499[sizeof("inmeeteimayek")];
+ char unicode_prop_name_pool_str500[sizeof("inoldnortharabian")];
+ char unicode_prop_name_pool_str503[sizeof("grlink")];
+ char unicode_prop_name_pool_str504[sizeof("knda")];
+ char unicode_prop_name_pool_str507[sizeof("kannada")];
+ char unicode_prop_name_pool_str509[sizeof("incjkcompatibilityforms")];
+ char unicode_prop_name_pool_str514[sizeof("incjkcompatibilityideographs")];
+ char unicode_prop_name_pool_str528[sizeof("inmodi")];
+ char unicode_prop_name_pool_str529[sizeof("kali")];
+ char unicode_prop_name_pool_str532[sizeof("control")];
+ char unicode_prop_name_pool_str536[sizeof("inadlam")];
+ char unicode_prop_name_pool_str538[sizeof("inspecials")];
+ char unicode_prop_name_pool_str540[sizeof("inmendekikakui")];
+ char unicode_prop_name_pool_str545[sizeof("intransportandmapsymbols")];
+ char unicode_prop_name_pool_str547[sizeof("letternumber")];
+ char unicode_prop_name_pool_str549[sizeof("xidc")];
+ char unicode_prop_name_pool_str550[sizeof("inmedefaidrin")];
+ char unicode_prop_name_pool_str558[sizeof("inchesssymbols")];
+ char unicode_prop_name_pool_str564[sizeof("inemoticons")];
+ char unicode_prop_name_pool_str573[sizeof("brahmi")];
+ char unicode_prop_name_pool_str575[sizeof("inolditalic")];
+ char unicode_prop_name_pool_str578[sizeof("palm")];
+ char unicode_prop_name_pool_str580[sizeof("inlycian")];
+ char unicode_prop_name_pool_str588[sizeof("inmiscellaneousmathematicalsymbolsa")];
+ char unicode_prop_name_pool_str594[sizeof("xids")];
+ char unicode_prop_name_pool_str603[sizeof("psalterpahlavi")];
+ char unicode_prop_name_pool_str619[sizeof("insundanese")];
+ char unicode_prop_name_pool_str620[sizeof("inoldsogdian")];
+ char unicode_prop_name_pool_str632[sizeof("diacritic")];
+ char unicode_prop_name_pool_str634[sizeof("gothic")];
+ char unicode_prop_name_pool_str635[sizeof("inancientsymbols")];
+ char unicode_prop_name_pool_str639[sizeof("meroiticcursive")];
+ char unicode_prop_name_pool_str643[sizeof("inmalayalam")];
+ char unicode_prop_name_pool_str648[sizeof("patternwhitespace")];
+ char unicode_prop_name_pool_str649[sizeof("sk")];
+ char unicode_prop_name_pool_str652[sizeof("insmallkanaextension")];
+ char unicode_prop_name_pool_str656[sizeof("inmandaic")];
+ char unicode_prop_name_pool_str657[sizeof("lt")];
+ char unicode_prop_name_pool_str665[sizeof("so")];
+ char unicode_prop_name_pool_str666[sizeof("inlinearbideograms")];
+ char unicode_prop_name_pool_str668[sizeof("incommonindicnumberforms")];
+ char unicode_prop_name_pool_str669[sizeof("incjkcompatibilityideographssupplement")];
+ char unicode_prop_name_pool_str677[sizeof("idc")];
+ char unicode_prop_name_pool_str678[sizeof("inoldsoutharabian")];
+ char unicode_prop_name_pool_str699[sizeof("insylotinagri")];
+ char unicode_prop_name_pool_str701[sizeof("idsbinaryoperator")];
+ char unicode_prop_name_pool_str707[sizeof("sora")];
+ char unicode_prop_name_pool_str708[sizeof("bamum")];
+ char unicode_prop_name_pool_str709[sizeof("inkanasupplement")];
+ char unicode_prop_name_pool_str710[sizeof("incjkstrokes")];
+ char unicode_prop_name_pool_str715[sizeof("joinc")];
+ char unicode_prop_name_pool_str718[sizeof("inopticalcharacterrecognition")];
+ char unicode_prop_name_pool_str722[sizeof("vs")];
+ char unicode_prop_name_pool_str728[sizeof("indominotiles")];
+ char unicode_prop_name_pool_str732[sizeof("batk")];
+ char unicode_prop_name_pool_str739[sizeof("grext")];
+ char unicode_prop_name_pool_str741[sizeof("batak")];
+ char unicode_prop_name_pool_str749[sizeof("patws")];
+ char unicode_prop_name_pool_str752[sizeof("inmodifiertoneletters")];
+ char unicode_prop_name_pool_str753[sizeof("ital")];
+ char unicode_prop_name_pool_str760[sizeof("bass")];
+ char unicode_prop_name_pool_str763[sizeof("decimalnumber")];
+ char unicode_prop_name_pool_str765[sizeof("alnum")];
+ char unicode_prop_name_pool_str767[sizeof("ids")];
+ char unicode_prop_name_pool_str776[sizeof("print")];
+ char unicode_prop_name_pool_str778[sizeof("inlatinextendeda")];
+ char unicode_prop_name_pool_str782[sizeof("intaitham")];
+ char unicode_prop_name_pool_str783[sizeof("inmusicalsymbols")];
+ char unicode_prop_name_pool_str785[sizeof("intaile")];
+ char unicode_prop_name_pool_str794[sizeof("samr")];
+ char unicode_prop_name_pool_str809[sizeof("samaritan")];
+ char unicode_prop_name_pool_str813[sizeof("s")];
+ char unicode_prop_name_pool_str816[sizeof("inlatinextendede")];
+ char unicode_prop_name_pool_str820[sizeof("bali")];
+ char unicode_prop_name_pool_str826[sizeof("lisu")];
+ char unicode_prop_name_pool_str827[sizeof("pauc")];
+ char unicode_prop_name_pool_str828[sizeof("patternsyntax")];
+ char unicode_prop_name_pool_str829[sizeof("incontrolpictures")];
+ char unicode_prop_name_pool_str830[sizeof("blank")];
+ char unicode_prop_name_pool_str834[sizeof("inmiscellaneoussymbols")];
+ char unicode_prop_name_pool_str835[sizeof("ll")];
+ char unicode_prop_name_pool_str836[sizeof("inancientgreekmusicalnotation")];
+ char unicode_prop_name_pool_str837[sizeof("zl")];
+ char unicode_prop_name_pool_str838[sizeof("inlydian")];
+ char unicode_prop_name_pool_str839[sizeof("sm")];
+ char unicode_prop_name_pool_str843[sizeof("inmiscellaneoussymbolsandarrows")];
+ char unicode_prop_name_pool_str844[sizeof("inugaritic")];
+ char unicode_prop_name_pool_str845[sizeof("bengali")];
+ char unicode_prop_name_pool_str846[sizeof("pd")];
+ char unicode_prop_name_pool_str848[sizeof("inmiscellaneoussymbolsandpictographs")];
+ char unicode_prop_name_pool_str850[sizeof("medf")];
+ char unicode_prop_name_pool_str855[sizeof("cf")];
+ char unicode_prop_name_pool_str858[sizeof("balinese")];
+ char unicode_prop_name_pool_str860[sizeof("medefaidrin")];
+ char unicode_prop_name_pool_str865[sizeof("han")];
+ char unicode_prop_name_pool_str869[sizeof("intamil")];
+ char unicode_prop_name_pool_str870[sizeof("hani")];
+ char unicode_prop_name_pool_str871[sizeof("inmultani")];
+ char unicode_prop_name_pool_str879[sizeof("hano")];
+ char unicode_prop_name_pool_str887[sizeof("inshorthandformatcontrols")];
+ char unicode_prop_name_pool_str891[sizeof("insaurashtra")];
+ char unicode_prop_name_pool_str892[sizeof("pf")];
+ char unicode_prop_name_pool_str894[sizeof("inoldturkic")];
+ char unicode_prop_name_pool_str896[sizeof("idcontinue")];
+ char unicode_prop_name_pool_str901[sizeof("hanunoo")];
+ char unicode_prop_name_pool_str905[sizeof("sc")];
+ char unicode_prop_name_pool_str906[sizeof("inkhojki")];
+ char unicode_prop_name_pool_str913[sizeof("idst")];
+ char unicode_prop_name_pool_str915[sizeof("canadianaboriginal")];
+ char unicode_prop_name_pool_str923[sizeof("hira")];
+ char unicode_prop_name_pool_str925[sizeof("plrd")];
+ char unicode_prop_name_pool_str939[sizeof("incaucasianalbanian")];
+ char unicode_prop_name_pool_str940[sizeof("indeseret")];
+ char unicode_prop_name_pool_str945[sizeof("inearlydynasticcuneiform")];
+ char unicode_prop_name_pool_str946[sizeof("inspacingmodifierletters")];
+ char unicode_prop_name_pool_str950[sizeof("innewa")];
+ char unicode_prop_name_pool_str972[sizeof("idstart")];
+ char unicode_prop_name_pool_str977[sizeof("zinh")];
+ char unicode_prop_name_pool_str981[sizeof("incyrillicextendeda")];
+ char unicode_prop_name_pool_str984[sizeof("dsrt")];
+ char unicode_prop_name_pool_str993[sizeof("cased")];
+ char unicode_prop_name_pool_str999[sizeof("glagolitic")];
+ char unicode_prop_name_pool_str1002[sizeof("inhanifirohingya")];
+ char unicode_prop_name_pool_str1006[sizeof("inancientgreeknumbers")];
+ char unicode_prop_name_pool_str1008[sizeof("inmeeteimayekextensions")];
+ char unicode_prop_name_pool_str1009[sizeof("intaixuanjingsymbols")];
+ char unicode_prop_name_pool_str1016[sizeof("joincontrol")];
+ char unicode_prop_name_pool_str1020[sizeof("runr")];
+ char unicode_prop_name_pool_str1023[sizeof("inwarangciti")];
+ char unicode_prop_name_pool_str1025[sizeof("deseret")];
+ char unicode_prop_name_pool_str1035[sizeof("inhiragana")];
+ char unicode_prop_name_pool_str1039[sizeof("sind")];
+ char unicode_prop_name_pool_str1047[sizeof("cherokee")];
+ char unicode_prop_name_pool_str1050[sizeof("inlatinextendedc")];
+ char unicode_prop_name_pool_str1052[sizeof("adlm")];
+ char unicode_prop_name_pool_str1053[sizeof("phoenician")];
+ char unicode_prop_name_pool_str1056[sizeof("cher")];
+ char unicode_prop_name_pool_str1059[sizeof("marchen")];
+ char unicode_prop_name_pool_str1062[sizeof("inkhudawadi")];
+ char unicode_prop_name_pool_str1063[sizeof("sinhala")];
+ char unicode_prop_name_pool_str1066[sizeof("lower")];
+ char unicode_prop_name_pool_str1068[sizeof("graphemelink")];
+ char unicode_prop_name_pool_str1069[sizeof("xidstart")];
+ char unicode_prop_name_pool_str1071[sizeof("ingrantha")];
+ char unicode_prop_name_pool_str1072[sizeof("bidic")];
+ char unicode_prop_name_pool_str1074[sizeof("xdigit")];
+ char unicode_prop_name_pool_str1076[sizeof("casedletter")];
+ char unicode_prop_name_pool_str1078[sizeof("gong")];
+ char unicode_prop_name_pool_str1079[sizeof("multani")];
+ char unicode_prop_name_pool_str1082[sizeof("gunjalagondi")];
+ char unicode_prop_name_pool_str1084[sizeof("cham")];
+ char unicode_prop_name_pool_str1086[sizeof("chakma")];
+ char unicode_prop_name_pool_str1087[sizeof("mong")];
+ char unicode_prop_name_pool_str1088[sizeof("kaithi")];
+ char unicode_prop_name_pool_str1089[sizeof("inmahajani")];
+ char unicode_prop_name_pool_str1090[sizeof("graphemebase")];
+ char unicode_prop_name_pool_str1092[sizeof("insiddham")];
+ char unicode_prop_name_pool_str1095[sizeof("inogham")];
+ char unicode_prop_name_pool_str1101[sizeof("inosage")];
+ char unicode_prop_name_pool_str1102[sizeof("incountingrodnumerals")];
+ char unicode_prop_name_pool_str1104[sizeof("inwancho")];
+ char unicode_prop_name_pool_str1105[sizeof("khojki")];
+ char unicode_prop_name_pool_str1107[sizeof("ingeneralpunctuation")];
+ char unicode_prop_name_pool_str1108[sizeof("georgian")];
+ char unicode_prop_name_pool_str1117[sizeof("incyrillicextendedc")];
+ char unicode_prop_name_pool_str1118[sizeof("inkayahli")];
+ char unicode_prop_name_pool_str1121[sizeof("khar")];
+ char unicode_prop_name_pool_str1124[sizeof("inoriya")];
+ char unicode_prop_name_pool_str1126[sizeof("manichaean")];
+ char unicode_prop_name_pool_str1132[sizeof("bamu")];
+ char unicode_prop_name_pool_str1133[sizeof("zanb")];
+ char unicode_prop_name_pool_str1136[sizeof("oriya")];
+ char unicode_prop_name_pool_str1137[sizeof("inolchiki")];
+ char unicode_prop_name_pool_str1138[sizeof("linb")];
+ char unicode_prop_name_pool_str1141[sizeof("inethiopic")];
+ char unicode_prop_name_pool_str1143[sizeof("wara")];
+ char unicode_prop_name_pool_str1144[sizeof("ingeorgian")];
+ char unicode_prop_name_pool_str1149[sizeof("innabataean")];
+ char unicode_prop_name_pool_str1154[sizeof("inkanbun")];
+ char unicode_prop_name_pool_str1156[sizeof("adlam")];
+ char unicode_prop_name_pool_str1157[sizeof("inbhaiksuki")];
+ char unicode_prop_name_pool_str1162[sizeof("insinhala")];
+ char unicode_prop_name_pool_str1163[sizeof("inelbasan")];
+ char unicode_prop_name_pool_str1169[sizeof("lowercase")];
+ char unicode_prop_name_pool_str1178[sizeof("takri")];
+ char unicode_prop_name_pool_str1179[sizeof("inmongolian")];
+ char unicode_prop_name_pool_str1181[sizeof("invai")];
+ char unicode_prop_name_pool_str1182[sizeof("xsux")];
+ char unicode_prop_name_pool_str1183[sizeof("cntrl")];
+ char unicode_prop_name_pool_str1186[sizeof("emoji")];
+ char unicode_prop_name_pool_str1187[sizeof("sterm")];
+ char unicode_prop_name_pool_str1189[sizeof("cuneiform")];
+ char unicode_prop_name_pool_str1192[sizeof("cwcm")];
+ char unicode_prop_name_pool_str1194[sizeof("hatran")];
+ char unicode_prop_name_pool_str1197[sizeof("linearb")];
+ char unicode_prop_name_pool_str1201[sizeof("taile")];
+ char unicode_prop_name_pool_str1202[sizeof("inlatinextendedadditional")];
+ char unicode_prop_name_pool_str1203[sizeof("inenclosedalphanumerics")];
+ char unicode_prop_name_pool_str1205[sizeof("anatolianhieroglyphs")];
+ char unicode_prop_name_pool_str1206[sizeof("incyrillicsupplement")];
+ char unicode_prop_name_pool_str1208[sizeof("intamilsupplement")];
+ char unicode_prop_name_pool_str1215[sizeof("inmiscellaneoustechnical")];
+ char unicode_prop_name_pool_str1217[sizeof("ahom")];
+ char unicode_prop_name_pool_str1218[sizeof("incherokeesupplement")];
+ char unicode_prop_name_pool_str1219[sizeof("takr")];
+ char unicode_prop_name_pool_str1224[sizeof("khmr")];
+ char unicode_prop_name_pool_str1228[sizeof("incjkunifiedideographsextensiona")];
+ char unicode_prop_name_pool_str1231[sizeof("quotationmark")];
+ char unicode_prop_name_pool_str1233[sizeof("lyci")];
+ char unicode_prop_name_pool_str1234[sizeof("lycian")];
+ char unicode_prop_name_pool_str1235[sizeof("ingurmukhi")];
+ char unicode_prop_name_pool_str1237[sizeof("runic")];
+ char unicode_prop_name_pool_str1238[sizeof("limb")];
+ char unicode_prop_name_pool_str1240[sizeof("inscriptionalpahlavi")];
+ char unicode_prop_name_pool_str1242[sizeof("hatr")];
+ char unicode_prop_name_pool_str1244[sizeof("variationselector")];
+ char unicode_prop_name_pool_str1246[sizeof("modifierletter")];
+ char unicode_prop_name_pool_str1247[sizeof("incjkunifiedideographsextensione")];
+ char unicode_prop_name_pool_str1262[sizeof("mymr")];
+ char unicode_prop_name_pool_str1265[sizeof("myanmar")];
+ char unicode_prop_name_pool_str1267[sizeof("lu")];
+ char unicode_prop_name_pool_str1275[sizeof("kharoshthi")];
+ char unicode_prop_name_pool_str1276[sizeof("inarabic")];
+ char unicode_prop_name_pool_str1278[sizeof("radical")];
+ char unicode_prop_name_pool_str1281[sizeof("khmer")];
+ char unicode_prop_name_pool_str1286[sizeof("inunifiedcanadianaboriginalsyllabics")];
+ char unicode_prop_name_pool_str1292[sizeof("osage")];
+ char unicode_prop_name_pool_str1296[sizeof("sundanese")];
+ char unicode_prop_name_pool_str1300[sizeof("innewtailue")];
+ char unicode_prop_name_pool_str1302[sizeof("logicalorderexception")];
+ char unicode_prop_name_pool_str1304[sizeof("math")];
+ char unicode_prop_name_pool_str1306[sizeof("braille")];
+ char unicode_prop_name_pool_str1311[sizeof("goth")];
+ char unicode_prop_name_pool_str1312[sizeof("insorasompeng")];
+ char unicode_prop_name_pool_str1316[sizeof("insoyombo")];
+ char unicode_prop_name_pool_str1317[sizeof("arab")];
+ char unicode_prop_name_pool_str1322[sizeof("saur")];
+ char unicode_prop_name_pool_str1329[sizeof("guru")];
+ char unicode_prop_name_pool_str1333[sizeof("term")];
+ char unicode_prop_name_pool_str1337[sizeof("paucinhau")];
+ char unicode_prop_name_pool_str1338[sizeof("inbasiclatin")];
+ char unicode_prop_name_pool_str1339[sizeof("inarabicpresentationformsa")];
+ char unicode_prop_name_pool_str1347[sizeof("punct")];
+ char unicode_prop_name_pool_str1348[sizeof("gurmukhi")];
+ char unicode_prop_name_pool_str1354[sizeof("grantha")];
+ char unicode_prop_name_pool_str1355[sizeof("inshavian")];
+ char unicode_prop_name_pool_str1356[sizeof("osma")];
+ char unicode_prop_name_pool_str1357[sizeof("inenclosedalphanumericsupplement")];
+ char unicode_prop_name_pool_str1360[sizeof("intirhuta")];
+ char unicode_prop_name_pool_str1361[sizeof("inelymaic")];
+ char unicode_prop_name_pool_str1362[sizeof("inhatran")];
+ char unicode_prop_name_pool_str1364[sizeof("incjkunifiedideographsextensionc")];
+ char unicode_prop_name_pool_str1365[sizeof("emojimodifier")];
+ char unicode_prop_name_pool_str1368[sizeof("uideo")];
+ char unicode_prop_name_pool_str1373[sizeof("bidicontrol")];
+ char unicode_prop_name_pool_str1379[sizeof("phnx")];
+ char unicode_prop_name_pool_str1380[sizeof("limbu")];
+ char unicode_prop_name_pool_str1384[sizeof("n")];
+ char unicode_prop_name_pool_str1388[sizeof("inenclosedideographicsupplement")];
+ char unicode_prop_name_pool_str1392[sizeof("mult")];
+ char unicode_prop_name_pool_str1398[sizeof("kthi")];
+ char unicode_prop_name_pool_str1399[sizeof("incjkunifiedideographs")];
+ char unicode_prop_name_pool_str1401[sizeof("ingreekandcoptic")];
+ char unicode_prop_name_pool_str1403[sizeof("inoldhungarian")];
+ char unicode_prop_name_pool_str1406[sizeof("incjkcompatibility")];
+ char unicode_prop_name_pool_str1409[sizeof("grbase")];
+ char unicode_prop_name_pool_str1411[sizeof("nandinagari")];
+ char unicode_prop_name_pool_str1412[sizeof("brah")];
+ char unicode_prop_name_pool_str1414[sizeof("no")];
+ char unicode_prop_name_pool_str1421[sizeof("sd")];
+ char unicode_prop_name_pool_str1423[sizeof("nko")];
+ char unicode_prop_name_pool_str1424[sizeof("nkoo")];
+ char unicode_prop_name_pool_str1427[sizeof("xpeo")];
+ char unicode_prop_name_pool_str1430[sizeof("sidd")];
+ char unicode_prop_name_pool_str1435[sizeof("inherited")];
+ char unicode_prop_name_pool_str1437[sizeof("p")];
+ char unicode_prop_name_pool_str1440[sizeof("phli")];
+ char unicode_prop_name_pool_str1443[sizeof("inmeroitichieroglyphs")];
+ char unicode_prop_name_pool_str1444[sizeof("inphoenician")];
+ char unicode_prop_name_pool_str1449[sizeof("inmayannumerals")];
+ char unicode_prop_name_pool_str1453[sizeof("saurashtra")];
+ char unicode_prop_name_pool_str1455[sizeof("inkangxiradicals")];
+ char unicode_prop_name_pool_str1461[sizeof("enclosingmark")];
+ char unicode_prop_name_pool_str1467[sizeof("graphemeextend")];
+ char unicode_prop_name_pool_str1468[sizeof("beng")];
+ char unicode_prop_name_pool_str1473[sizeof("inbatak")];
+ char unicode_prop_name_pool_str1474[sizeof("glag")];
+ char unicode_prop_name_pool_str1475[sizeof("ahex")];
+ char unicode_prop_name_pool_str1477[sizeof("patsyn")];
+ char unicode_prop_name_pool_str1479[sizeof("odi")];
+ char unicode_prop_name_pool_str1486[sizeof("dogra")];
+ char unicode_prop_name_pool_str1489[sizeof("intibetan")];
+ char unicode_prop_name_pool_str1491[sizeof("lydi")];
+ char unicode_prop_name_pool_str1492[sizeof("lydian")];
+ char unicode_prop_name_pool_str1499[sizeof("inblockelements")];
+ char unicode_prop_name_pool_str1506[sizeof("cwcf")];
+ char unicode_prop_name_pool_str1507[sizeof("inunifiedcanadianaboriginalsyllabicsextended")];
+ char unicode_prop_name_pool_str1508[sizeof("regionalindicator")];
+ char unicode_prop_name_pool_str1509[sizeof("ingreekextended")];
+ char unicode_prop_name_pool_str1513[sizeof("emojimodifierbase")];
+ char unicode_prop_name_pool_str1514[sizeof("inanatolianhieroglyphs")];
+ char unicode_prop_name_pool_str1516[sizeof("indogra")];
+ char unicode_prop_name_pool_str1517[sizeof("taiviet")];
+ char unicode_prop_name_pool_str1524[sizeof("inyiradicals")];
+ char unicode_prop_name_pool_str1525[sizeof("unassigned")];
+ char unicode_prop_name_pool_str1532[sizeof("insundanesesupplement")];
+ char unicode_prop_name_pool_str1535[sizeof("innumberforms")];
+ char unicode_prop_name_pool_str1538[sizeof("lowercaseletter")];
+ char unicode_prop_name_pool_str1541[sizeof("dogr")];
+ char unicode_prop_name_pool_str1542[sizeof("lepc")];
+ char unicode_prop_name_pool_str1545[sizeof("bhks")];
+ char unicode_prop_name_pool_str1553[sizeof("word")];
+ char unicode_prop_name_pool_str1554[sizeof("gujr")];
+ char unicode_prop_name_pool_str1555[sizeof("inphaistosdisc")];
+ char unicode_prop_name_pool_str1557[sizeof("bhaiksuki")];
+ char unicode_prop_name_pool_str1560[sizeof("dash")];
+ char unicode_prop_name_pool_str1562[sizeof("inarabicextendeda")];
+ char unicode_prop_name_pool_str1565[sizeof("gujarati")];
+ char unicode_prop_name_pool_str1566[sizeof("inlatinextendedd")];
+ char unicode_prop_name_pool_str1567[sizeof("innoblock")];
+ char unicode_prop_name_pool_str1570[sizeof("java")];
+ char unicode_prop_name_pool_str1576[sizeof("ingeometricshapes")];
+ char unicode_prop_name_pool_str1577[sizeof("cyrl")];
+ char unicode_prop_name_pool_str1582[sizeof("indevanagari")];
+ char unicode_prop_name_pool_str1583[sizeof("inbalinese")];
+ char unicode_prop_name_pool_str1585[sizeof("inbyzantinemusicalsymbols")];
+ char unicode_prop_name_pool_str1589[sizeof("tale")];
+ char unicode_prop_name_pool_str1591[sizeof("deva")];
+ char unicode_prop_name_pool_str1594[sizeof("hex")];
+ char unicode_prop_name_pool_str1601[sizeof("inmyanmarextendedb")];
+ char unicode_prop_name_pool_str1603[sizeof("sinh")];
+ char unicode_prop_name_pool_str1604[sizeof("cwt")];
+ char unicode_prop_name_pool_str1606[sizeof("shavian")];
+ char unicode_prop_name_pool_str1607[sizeof("devanagari")];
+ char unicode_prop_name_pool_str1609[sizeof("oidc")];
+ char unicode_prop_name_pool_str1615[sizeof("javanese")];
+ char unicode_prop_name_pool_str1621[sizeof("mlym")];
+ char unicode_prop_name_pool_str1622[sizeof("incjkunifiedideographsextensiond")];
+ char unicode_prop_name_pool_str1624[sizeof("sentenceterminal")];
+ char unicode_prop_name_pool_str1626[sizeof("malayalam")];
+ char unicode_prop_name_pool_str1628[sizeof("inhanunoo")];
+ char unicode_prop_name_pool_str1629[sizeof("insinhalaarchaicnumbers")];
+ char unicode_prop_name_pool_str1631[sizeof("olck")];
+ char unicode_prop_name_pool_str1633[sizeof("inimperialaramaic")];
+ char unicode_prop_name_pool_str1636[sizeof("olower")];
+ char unicode_prop_name_pool_str1638[sizeof("palmyrene")];
+ char unicode_prop_name_pool_str1642[sizeof("avestan")];
+ char unicode_prop_name_pool_str1645[sizeof("incjkunifiedideographsextensionf")];
+ char unicode_prop_name_pool_str1646[sizeof("insogdian")];
+ char unicode_prop_name_pool_str1647[sizeof("indingbats")];
+ char unicode_prop_name_pool_str1648[sizeof("olchiki")];
+ char unicode_prop_name_pool_str1654[sizeof("oids")];
+ char unicode_prop_name_pool_str1661[sizeof("punctuation")];
+ char unicode_prop_name_pool_str1663[sizeof("sund")];
+ char unicode_prop_name_pool_str1666[sizeof("inbraillepatterns")];
+ char unicode_prop_name_pool_str1669[sizeof("emojicomponent")];
+ char unicode_prop_name_pool_str1672[sizeof("ideographic")];
+ char unicode_prop_name_pool_str1673[sizeof("taml")];
+ char unicode_prop_name_pool_str1688[sizeof("format")];
+ char unicode_prop_name_pool_str1694[sizeof("inornamentaldingbats")];
+ char unicode_prop_name_pool_str1700[sizeof("coptic")];
+ char unicode_prop_name_pool_str1702[sizeof("caseignorable")];
+ char unicode_prop_name_pool_str1708[sizeof("idsb")];
+ char unicode_prop_name_pool_str1709[sizeof("inmiscellaneousmathematicalsymbolsb")];
+ char unicode_prop_name_pool_str1712[sizeof("sogdian")];
+ char unicode_prop_name_pool_str1715[sizeof("sogo")];
+ char unicode_prop_name_pool_str1720[sizeof("terminalpunctuation")];
+ char unicode_prop_name_pool_str1722[sizeof("intangut")];
+ char unicode_prop_name_pool_str1729[sizeof("intifinagh")];
+ char unicode_prop_name_pool_str1733[sizeof("inlowsurrogates")];
+ char unicode_prop_name_pool_str1743[sizeof("invariationselectors")];
+ char unicode_prop_name_pool_str1745[sizeof("copt")];
+ char unicode_prop_name_pool_str1750[sizeof("soyo")];
+ char unicode_prop_name_pool_str1753[sizeof("intags")];
+ char unicode_prop_name_pool_str1756[sizeof("inverticalforms")];
+ char unicode_prop_name_pool_str1757[sizeof("ininscriptionalparthian")];
+ char unicode_prop_name_pool_str1760[sizeof("ininscriptionalpahlavi")];
+ char unicode_prop_name_pool_str1763[sizeof("meroitichieroglyphs")];
+ char unicode_prop_name_pool_str1764[sizeof("asciihexdigit")];
+ char unicode_prop_name_pool_str1766[sizeof("inethiopicextendeda")];
+ char unicode_prop_name_pool_str1767[sizeof("invedicextensions")];
+ char unicode_prop_name_pool_str1781[sizeof("nand")];
+ char unicode_prop_name_pool_str1782[sizeof("cwl")];
+ char unicode_prop_name_pool_str1785[sizeof("cprt")];
+ char unicode_prop_name_pool_str1791[sizeof("innushu")];
+ char unicode_prop_name_pool_str1794[sizeof("zanabazarsquare")];
+ char unicode_prop_name_pool_str1797[sizeof("ingeometricshapesextended")];
+ char unicode_prop_name_pool_str1798[sizeof("avst")];
+ char unicode_prop_name_pool_str1808[sizeof("imperialaramaic")];
+ char unicode_prop_name_pool_str1810[sizeof("bopo")];
+ char unicode_prop_name_pool_str1812[sizeof("sarb")];
+ char unicode_prop_name_pool_str1819[sizeof("inoldpersian")];
+ char unicode_prop_name_pool_str1830[sizeof("intaiviet")];
+ char unicode_prop_name_pool_str1834[sizeof("mahj")];
+ char unicode_prop_name_pool_str1838[sizeof("inkatakanaphoneticextensions")];
+ char unicode_prop_name_pool_str1845[sizeof("mahajani")];
+ char unicode_prop_name_pool_str1871[sizeof("closepunctuation")];
+ char unicode_prop_name_pool_str1875[sizeof("inlisu")];
+ char unicode_prop_name_pool_str1878[sizeof("softdotted")];
+ char unicode_prop_name_pool_str1897[sizeof("unknown")];
+ char unicode_prop_name_pool_str1898[sizeof("invariationselectorssupplement")];
+ char unicode_prop_name_pool_str1910[sizeof("syrc")];
+ char unicode_prop_name_pool_str1911[sizeof("hang")];
+ char unicode_prop_name_pool_str1926[sizeof("incjksymbolsandpunctuation")];
+ char unicode_prop_name_pool_str1932[sizeof("ingujarati")];
+ char unicode_prop_name_pool_str1933[sizeof("bopomofo")];
+ char unicode_prop_name_pool_str1936[sizeof("alpha")];
+ char unicode_prop_name_pool_str1937[sizeof("khoj")];
+ char unicode_prop_name_pool_str1939[sizeof("inpalmyrene")];
+ char unicode_prop_name_pool_str1942[sizeof("ingunjalagondi")];
+ char unicode_prop_name_pool_str1948[sizeof("inoldpermic")];
+ char unicode_prop_name_pool_str1950[sizeof("inlepcha")];
+ char unicode_prop_name_pool_str1951[sizeof("assigned")];
+ char unicode_prop_name_pool_str1955[sizeof("incurrencysymbols")];
+ char unicode_prop_name_pool_str1958[sizeof("insmallformvariants")];
+ char unicode_prop_name_pool_str1959[sizeof("sorasompeng")];
+ char unicode_prop_name_pool_str1964[sizeof("inlinearbsyllabary")];
+ char unicode_prop_name_pool_str1965[sizeof("oldpersian")];
+ char unicode_prop_name_pool_str1972[sizeof("caucasianalbanian")];
+ char unicode_prop_name_pool_str1973[sizeof("inenclosedcjklettersandmonths")];
+ char unicode_prop_name_pool_str1975[sizeof("hiragana")];
+ char unicode_prop_name_pool_str1976[sizeof("inbamum")];
+ char unicode_prop_name_pool_str1979[sizeof("inrejang")];
+ char unicode_prop_name_pool_str1984[sizeof("graph")];
+ char unicode_prop_name_pool_str1990[sizeof("sharada")];
+ char unicode_prop_name_pool_str1991[sizeof("inethiopicsupplement")];
+ char unicode_prop_name_pool_str1996[sizeof("indevanagariextended")];
+ char unicode_prop_name_pool_str1997[sizeof("incoptic")];
+ char unicode_prop_name_pool_str1998[sizeof("insyriacsupplement")];
+ char unicode_prop_name_pool_str2004[sizeof("inmeroiticcursive")];
+ char unicode_prop_name_pool_str2014[sizeof("hmng")];
+ char unicode_prop_name_pool_str2022[sizeof("intelugu")];
+ char unicode_prop_name_pool_str2029[sizeof("incombiningdiacriticalmarks")];
+ char unicode_prop_name_pool_str2031[sizeof("mathsymbol")];
+ char unicode_prop_name_pool_str2036[sizeof("titlecaseletter")];
+ char unicode_prop_name_pool_str2038[sizeof("ugar")];
+ char unicode_prop_name_pool_str2039[sizeof("incombiningdiacriticalmarksforsymbols")];
+ char unicode_prop_name_pool_str2040[sizeof("spacingmark")];
+ char unicode_prop_name_pool_str2043[sizeof("shrd")];
+ char unicode_prop_name_pool_str2047[sizeof("injavanese")];
+ char unicode_prop_name_pool_str2048[sizeof("syriac")];
+ char unicode_prop_name_pool_str2054[sizeof("space")];
+ char unicode_prop_name_pool_str2056[sizeof("hebr")];
+ char unicode_prop_name_pool_str2061[sizeof("ext")];
+ char unicode_prop_name_pool_str2064[sizeof("inhanguljamo")];
+ char unicode_prop_name_pool_str2066[sizeof("phag")];
+ char unicode_prop_name_pool_str2076[sizeof("inhanguljamoextendeda")];
+ char unicode_prop_name_pool_str2082[sizeof("wancho")];
+ char unicode_prop_name_pool_str2084[sizeof("bugi")];
+ char unicode_prop_name_pool_str2089[sizeof("tamil")];
+ char unicode_prop_name_pool_str2093[sizeof("sogd")];
+ char unicode_prop_name_pool_str2094[sizeof("orkh")];
+ char unicode_prop_name_pool_str2097[sizeof("oldpermic")];
+ char unicode_prop_name_pool_str2100[sizeof("siddham")];
+ char unicode_prop_name_pool_str2102[sizeof("incyrillicextendedb")];
+ char unicode_prop_name_pool_str2105[sizeof("inbrahmi")];
+ char unicode_prop_name_pool_str2108[sizeof("inmongoliansupplement")];
+ char unicode_prop_name_pool_str2113[sizeof("thaa")];
+ char unicode_prop_name_pool_str2118[sizeof("thaana")];
+ char unicode_prop_name_pool_str2120[sizeof("thai")];
+ char unicode_prop_name_pool_str2122[sizeof("buginese")];
+ char unicode_prop_name_pool_str2127[sizeof("ingeorgiansupplement")];
+ char unicode_prop_name_pool_str2129[sizeof("digit")];
+ char unicode_prop_name_pool_str2132[sizeof("cyrillic")];
+ char unicode_prop_name_pool_str2149[sizeof("sylo")];
+ char unicode_prop_name_pool_str2150[sizeof("inphoneticextensions")];
+ char unicode_prop_name_pool_str2151[sizeof("separator")];
+ char unicode_prop_name_pool_str2159[sizeof("inethiopicextended")];
+ char unicode_prop_name_pool_str2163[sizeof("inmathematicalalphanumericsymbols")];
+ char unicode_prop_name_pool_str2168[sizeof("insymbolsandpictographsextendeda")];
+ char unicode_prop_name_pool_str2170[sizeof("nd")];
+ char unicode_prop_name_pool_str2176[sizeof("tirh")];
+ char unicode_prop_name_pool_str2178[sizeof("tirhuta")];
+ char unicode_prop_name_pool_str2184[sizeof("incombiningdiacriticalmarkssupplement")];
+ char unicode_prop_name_pool_str2193[sizeof("extender")];
+ char unicode_prop_name_pool_str2197[sizeof("wcho")];
+ char unicode_prop_name_pool_str2199[sizeof("inbengali")];
+ char unicode_prop_name_pool_str2201[sizeof("talu")];
+ char unicode_prop_name_pool_str2206[sizeof("tang")];
+ char unicode_prop_name_pool_str2207[sizeof("warangciti")];
+ char unicode_prop_name_pool_str2210[sizeof("tagbanwa")];
+ char unicode_prop_name_pool_str2211[sizeof("orya")];
+ char unicode_prop_name_pool_str2212[sizeof("nl")];
+ char unicode_prop_name_pool_str2213[sizeof("induployan")];
+ char unicode_prop_name_pool_str2214[sizeof("cwu")];
+ char unicode_prop_name_pool_str2216[sizeof("inbuginese")];
+ char unicode_prop_name_pool_str2220[sizeof("telu")];
+ char unicode_prop_name_pool_str2223[sizeof("ogam")];
+ char unicode_prop_name_pool_str2226[sizeof("taitham")];
+ char unicode_prop_name_pool_str2237[sizeof("rjng")];
+ char unicode_prop_name_pool_str2240[sizeof("insuttonsignwriting")];
+ char unicode_prop_name_pool_str2250[sizeof("incombiningdiacriticalmarksextended")];
+ char unicode_prop_name_pool_str2251[sizeof("number")];
+ char unicode_prop_name_pool_str2264[sizeof("inyijinghexagramsymbols")];
+ char unicode_prop_name_pool_str2277[sizeof("whitespace")];
+ char unicode_prop_name_pool_str2278[sizeof("currencysymbol")];
+ char unicode_prop_name_pool_str2285[sizeof("inottomansiyaqnumbers")];
+ char unicode_prop_name_pool_str2288[sizeof("inlimbu")];
+ char unicode_prop_name_pool_str2293[sizeof("incopticepactnumbers")];
+ char unicode_prop_name_pool_str2295[sizeof("ingeorgianextended")];
+ char unicode_prop_name_pool_str2305[sizeof("inphoneticextensionssupplement")];
+ char unicode_prop_name_pool_str2308[sizeof("any")];
+ char unicode_prop_name_pool_str2320[sizeof("osge")];
+ char unicode_prop_name_pool_str2325[sizeof("defaultignorablecodepoint")];
+ char unicode_prop_name_pool_str2326[sizeof("hangul")];
+ char unicode_prop_name_pool_str2333[sizeof("newa")];
+ char unicode_prop_name_pool_str2343[sizeof("ethi")];
+ char unicode_prop_name_pool_str2345[sizeof("hanifirohingya")];
+ char unicode_prop_name_pool_str2346[sizeof("hmnp")];
+ char unicode_prop_name_pool_str2348[sizeof("olditalic")];
+ char unicode_prop_name_pool_str2349[sizeof("incjkunifiedideographsextensionb")];
+ char unicode_prop_name_pool_str2352[sizeof("rohg")];
+ char unicode_prop_name_pool_str2353[sizeof("innyiakengpuachuehmong")];
+ char unicode_prop_name_pool_str2355[sizeof("incjkradicalssupplement")];
+ char unicode_prop_name_pool_str2364[sizeof("newtailue")];
+ char unicode_prop_name_pool_str2365[sizeof("newline")];
+ char unicode_prop_name_pool_str2366[sizeof("lepcha")];
+ char unicode_prop_name_pool_str2375[sizeof("deprecated")];
+ char unicode_prop_name_pool_str2381[sizeof("buhd")];
+ char unicode_prop_name_pool_str2391[sizeof("inglagolitic")];
+ char unicode_prop_name_pool_str2395[sizeof("inaegeannumbers")];
+ char unicode_prop_name_pool_str2400[sizeof("modifiersymbol")];
+ char unicode_prop_name_pool_str2410[sizeof("surrogate")];
+ char unicode_prop_name_pool_str2418[sizeof("inletterlikesymbols")];
+ char unicode_prop_name_pool_str2426[sizeof("idstrinaryoperator")];
+ char unicode_prop_name_pool_str2442[sizeof("intagalog")];
+ char unicode_prop_name_pool_str2443[sizeof("tangut")];
+ char unicode_prop_name_pool_str2445[sizeof("osmanya")];
+ char unicode_prop_name_pool_str2447[sizeof("oalpha")];
+ char unicode_prop_name_pool_str2448[sizeof("inphagspa")];
+ char unicode_prop_name_pool_str2455[sizeof("ugaritic")];
+ char unicode_prop_name_pool_str2456[sizeof("otheridcontinue")];
+ char unicode_prop_name_pool_str2460[sizeof("inarabicpresentationformsb")];
+ char unicode_prop_name_pool_str2462[sizeof("inbassavah")];
+ char unicode_prop_name_pool_str2469[sizeof("other")];
+ char unicode_prop_name_pool_str2478[sizeof("othernumber")];
+ char unicode_prop_name_pool_str2480[sizeof("sylotinagri")];
+ char unicode_prop_name_pool_str2487[sizeof("ingothic")];
+ char unicode_prop_name_pool_str2498[sizeof("inbuhid")];
+ char unicode_prop_name_pool_str2502[sizeof("inlatin1supplement")];
+ char unicode_prop_name_pool_str2516[sizeof("intagbanwa")];
+ char unicode_prop_name_pool_str2523[sizeof("shaw")];
+ char unicode_prop_name_pool_str2529[sizeof("oldhungarian")];
+ char unicode_prop_name_pool_str2538[sizeof("inmahjongtiles")];
+ char unicode_prop_name_pool_str2542[sizeof("hung")];
+ char unicode_prop_name_pool_str2544[sizeof("tifinagh")];
+ char unicode_prop_name_pool_str2554[sizeof("inbopomofo")];
+ char unicode_prop_name_pool_str2561[sizeof("narb")];
+ char unicode_prop_name_pool_str2571[sizeof("inyisyllables")];
+ char unicode_prop_name_pool_str2573[sizeof("kayahli")];
+ char unicode_prop_name_pool_str2578[sizeof("otheralphabetic")];
+ char unicode_prop_name_pool_str2582[sizeof("phagspa")];
+ char unicode_prop_name_pool_str2584[sizeof("inprivateusearea")];
+ char unicode_prop_name_pool_str2588[sizeof("elba")];
+ char unicode_prop_name_pool_str2591[sizeof("nchar")];
+ char unicode_prop_name_pool_str2607[sizeof("spaceseparator")];
+ char unicode_prop_name_pool_str2609[sizeof("tibt")];
+ char unicode_prop_name_pool_str2611[sizeof("extendedpictographic")];
+ char unicode_prop_name_pool_str2615[sizeof("tibetan")];
+ char unicode_prop_name_pool_str2616[sizeof("sgnw")];
+ char unicode_prop_name_pool_str2622[sizeof("hexdigit")];
+ char unicode_prop_name_pool_str2623[sizeof("tfng")];
+ char unicode_prop_name_pool_str2627[sizeof("inbamumsupplement")];
+ char unicode_prop_name_pool_str2632[sizeof("tavt")];
+ char unicode_prop_name_pool_str2633[sizeof("incombininghalfmarks")];
+ char unicode_prop_name_pool_str2634[sizeof("inarabicmathematicalalphabeticsymbols")];
+ char unicode_prop_name_pool_str2638[sizeof("khudawadi")];
+ char unicode_prop_name_pool_str2641[sizeof("inhalfwidthandfullwidthforms")];
+ char unicode_prop_name_pool_str2652[sizeof("inhangulsyllables")];
+ char unicode_prop_name_pool_str2653[sizeof("elym")];
+ char unicode_prop_name_pool_str2669[sizeof("symbol")];
+ char unicode_prop_name_pool_str2692[sizeof("bassavah")];
+ char unicode_prop_name_pool_str2696[sizeof("elymaic")];
+ char unicode_prop_name_pool_str2698[sizeof("changeswhencasemapped")];
+ char unicode_prop_name_pool_str2709[sizeof("oldturkic")];
+ char unicode_prop_name_pool_str2725[sizeof("inplayingcards")];
+ char unicode_prop_name_pool_str2767[sizeof("zp")];
+ char unicode_prop_name_pool_str2775[sizeof("elbasan")];
+ char unicode_prop_name_pool_str2776[sizeof("buhid")];
+ char unicode_prop_name_pool_str2779[sizeof("noncharactercodepoint")];
+ char unicode_prop_name_pool_str2785[sizeof("finalpunctuation")];
+ char unicode_prop_name_pool_str2794[sizeof("inpsalterpahlavi")];
+ char unicode_prop_name_pool_str2800[sizeof("inpaucinhau")];
+ char unicode_prop_name_pool_str2801[sizeof("nonspacingmark")];
+ char unicode_prop_name_pool_str2804[sizeof("changeswhentitlecased")];
+ char unicode_prop_name_pool_str2808[sizeof("inindicsiyaqnumbers")];
+ char unicode_prop_name_pool_str2813[sizeof("phlp")];
+ char unicode_prop_name_pool_str2824[sizeof("wspace")];
+ char unicode_prop_name_pool_str2831[sizeof("nbat")];
+ char unicode_prop_name_pool_str2836[sizeof("hluw")];
+ char unicode_prop_name_pool_str2838[sizeof("cypriot")];
+ char unicode_prop_name_pool_str2839[sizeof("nabataean")];
+ char unicode_prop_name_pool_str2841[sizeof("inalchemicalsymbols")];
+ char unicode_prop_name_pool_str2847[sizeof("dupl")];
+ char unicode_prop_name_pool_str2856[sizeof("otherlowercase")];
+ char unicode_prop_name_pool_str2875[sizeof("inarabicsupplement")];
+ char unicode_prop_name_pool_str2876[sizeof("inalphabeticpresentationforms")];
+ char unicode_prop_name_pool_str2890[sizeof("otherletter")];
+ char unicode_prop_name_pool_str2916[sizeof("emojipresentation")];
+ char unicode_prop_name_pool_str2930[sizeof("changeswhenlowercased")];
+ char unicode_prop_name_pool_str2953[sizeof("dashpunctuation")];
+ char unicode_prop_name_pool_str2954[sizeof("oldsogdian")];
+ char unicode_prop_name_pool_str2970[sizeof("intangutcomponents")];
+ char unicode_prop_name_pool_str2977[sizeof("soyombo")];
+ char unicode_prop_name_pool_str2996[sizeof("paragraphseparator")];
+ char unicode_prop_name_pool_str3012[sizeof("changeswhencasefolded")];
+ char unicode_prop_name_pool_str3015[sizeof("othersymbol")];
+ char unicode_prop_name_pool_str3020[sizeof("inlatinextendedb")];
+ char unicode_prop_name_pool_str3072[sizeof("otheruppercase")];
+ char unicode_prop_name_pool_str3079[sizeof("otheridstart")];
+ char unicode_prop_name_pool_str3084[sizeof("inhebrew")];
+ char unicode_prop_name_pool_str3088[sizeof("oldnortharabian")];
+ char unicode_prop_name_pool_str3092[sizeof("omath")];
+ char unicode_prop_name_pool_str3099[sizeof("incypriotsyllabary")];
+ char unicode_prop_name_pool_str3118[sizeof("inmathematicaloperators")];
+ char unicode_prop_name_pool_str3146[sizeof("changeswhenuppercased")];
+ char unicode_prop_name_pool_str3154[sizeof("nshu")];
+ char unicode_prop_name_pool_str3182[sizeof("insuperscriptsandsubscripts")];
+ char unicode_prop_name_pool_str3188[sizeof("ogrext")];
+ char unicode_prop_name_pool_str3197[sizeof("inhanguljamoextendedb")];
+ char unicode_prop_name_pool_str3198[sizeof("alphabetic")];
+ char unicode_prop_name_pool_str3199[sizeof("dep")];
+ char unicode_prop_name_pool_str3216[sizeof("oupper")];
+ char unicode_prop_name_pool_str3258[sizeof("zyyy")];
+ char unicode_prop_name_pool_str3267[sizeof("aghb")];
+ char unicode_prop_name_pool_str3285[sizeof("ogham")];
+ char unicode_prop_name_pool_str3306[sizeof("rejang")];
+ char unicode_prop_name_pool_str3324[sizeof("tagb")];
+ char unicode_prop_name_pool_str3350[sizeof("hyphen")];
+ char unicode_prop_name_pool_str3355[sizeof("insupplementalarrowsa")];
+ char unicode_prop_name_pool_str3413[sizeof("inpahawhhmong")];
+ char unicode_prop_name_pool_str3459[sizeof("nushu")];
+ char unicode_prop_name_pool_str3478[sizeof("othermath")];
+ char unicode_prop_name_pool_str3491[sizeof("insupplementalarrowsc")];
+ char unicode_prop_name_pool_str3494[sizeof("insupplementalmathematicaloperators")];
+ char unicode_prop_name_pool_str3500[sizeof("otherdefaultignorablecodepoint")];
+ char unicode_prop_name_pool_str3527[sizeof("inhighprivateusesurrogates")];
+ char unicode_prop_name_pool_str3538[sizeof("duployan")];
+ char unicode_prop_name_pool_str3663[sizeof("oldsoutharabian")];
+ char unicode_prop_name_pool_str3666[sizeof("tglg")];
+ char unicode_prop_name_pool_str3685[sizeof("tagalog")];
+ char unicode_prop_name_pool_str3692[sizeof("inbopomofoextended")];
+ char unicode_prop_name_pool_str3731[sizeof("signwriting")];
+ char unicode_prop_name_pool_str3750[sizeof("inegyptianhieroglyphs")];
+ char unicode_prop_name_pool_str3763[sizeof("inegyptianhieroglyphformatcontrols")];
+ char unicode_prop_name_pool_str3807[sizeof("upper")];
+ char unicode_prop_name_pool_str3810[sizeof("otherpunctuation")];
+ char unicode_prop_name_pool_str3872[sizeof("ethiopic")];
+ char unicode_prop_name_pool_str3881[sizeof("hebrew")];
+ char unicode_prop_name_pool_str3901[sizeof("telugu")];
+ char unicode_prop_name_pool_str3910[sizeof("uppercase")];
+ char unicode_prop_name_pool_str3937[sizeof("insupplementalpunctuation")];
+ char unicode_prop_name_pool_str3946[sizeof("unifiedideograph")];
+ char unicode_prop_name_pool_str3961[sizeof("pahawhhmong")];
+ char unicode_prop_name_pool_str3971[sizeof("inglagoliticsupplement")];
+ char unicode_prop_name_pool_str3992[sizeof("inboxdrawing")];
+ char unicode_prop_name_pool_str4279[sizeof("uppercaseletter")];
+ char unicode_prop_name_pool_str4298[sizeof("othergraphemeextend")];
+ char unicode_prop_name_pool_str4401[sizeof("inhighsurrogates")];
+ char unicode_prop_name_pool_str4476[sizeof("insupplementalarrowsb")];
+ char unicode_prop_name_pool_str4562[sizeof("inhangulcompatibilityjamo")];
+ char unicode_prop_name_pool_str4563[sizeof("egyp")];
+ char unicode_prop_name_pool_str4577[sizeof("insupplementalsymbolsandpictographs")];
+ char unicode_prop_name_pool_str4659[sizeof("nyiakengpuachuehmong")];
+ char unicode_prop_name_pool_str4688[sizeof("insupplementaryprivateuseareaa")];
+ char unicode_prop_name_pool_str4822[sizeof("openpunctuation")];
+ char unicode_prop_name_pool_str4851[sizeof("egyptianhieroglyphs")];
+ char unicode_prop_name_pool_str5809[sizeof("insupplementaryprivateuseareab")];
+ };
+static const struct unicode_prop_name_pool_t unicode_prop_name_pool_contents =
+ {
+ "lana",
+ "z",
+ "yi",
+ "lina",
+ "mn",
+ "yiii",
+ "cn",
+ "maka",
+ "mani",
+ "zzzz",
+ "inkannada",
+ "ci",
+ "lo",
+ "lao",
+ "laoo",
+ "miao",
+ "innko",
+ "co",
+ "me",
+ "loe",
+ "gran",
+ "pi",
+ "lineara",
+ "mark",
+ "cari",
+ "carian",
+ "po",
+ "mendekikakui",
+ "grek",
+ "pe",
+ "meeteimayek",
+ "inkharoshthi",
+ "geor",
+ "greek",
+ "mro",
+ "mroo",
+ "kana",
+ "mero",
+ "m",
+ "gonm",
+ "cakm",
+ "inosmanya",
+ "inmanichaean",
+ "inarmenian",
+ "inmro",
+ "inmiao",
+ "c",
+ "inchakma",
+ "common",
+ "mandaic",
+ "inmyanmar",
+ "inmakasar",
+ "qaai",
+ "inideographicsymbolsandpunctuation",
+ "inkhmer",
+ "cans",
+ "prependedconcatenationmark",
+ "lm",
+ "marc",
+ "connectorpunctuation",
+ "inrunic",
+ "incarian",
+ "inavestan",
+ "combiningmark",
+ "incuneiformnumbersandpunctuation",
+ "merc",
+ "perm",
+ "inahom",
+ "inipaextensions",
+ "incherokee",
+ "insharada",
+ "makasar",
+ "inarrows",
+ "lc",
+ "masaramgondi",
+ "incuneiform",
+ "mc",
+ "cc",
+ "inzanabazarsquare",
+ "lineseparator",
+ "armn",
+ "qmark",
+ "armi",
+ "insamaritan",
+ "armenian",
+ "inmarchen",
+ "inmasaramgondi",
+ "qaac",
+ "pc",
+ "inscriptionalparthian",
+ "latn",
+ "latin",
+ "ri",
+ "inthaana",
+ "inkhmersymbols",
+ "inkatakana",
+ "incyrillic",
+ "inthai",
+ "incham",
+ "inkaithi",
+ "zs",
+ "mtei",
+ "vai",
+ "vaii",
+ "initialpunctuation",
+ "cs",
+ "insyriac",
+ "pcm",
+ "intakri",
+ "mand",
+ "l",
+ "ps",
+ "dia",
+ "inkanaextendeda",
+ "di",
+ "mend",
+ "modi",
+ "ideo",
+ "katakana",
+ "prti",
+ "inideographicdescriptioncharacters",
+ "inlineara",
+ "xidcontinue",
+ "brai",
+ "inlao",
+ "ascii",
+ "privateuse",
+ "arabic",
+ "mongolian",
+ "inmyanmarextendeda",
+ "inruminumeralsymbols",
+ "letter",
+ "innandinagari",
+ "inmeeteimayek",
+ "inoldnortharabian",
+ "grlink",
+ "knda",
+ "kannada",
+ "incjkcompatibilityforms",
+ "incjkcompatibilityideographs",
+ "inmodi",
+ "kali",
+ "control",
+ "inadlam",
+ "inspecials",
+ "inmendekikakui",
+ "intransportandmapsymbols",
+ "letternumber",
+ "xidc",
+ "inmedefaidrin",
+ "inchesssymbols",
+ "inemoticons",
+ "brahmi",
+ "inolditalic",
+ "palm",
+ "inlycian",
+ "inmiscellaneousmathematicalsymbolsa",
+ "xids",
+ "psalterpahlavi",
+ "insundanese",
+ "inoldsogdian",
+ "diacritic",
+ "gothic",
+ "inancientsymbols",
+ "meroiticcursive",
+ "inmalayalam",
+ "patternwhitespace",
+ "sk",
+ "insmallkanaextension",
+ "inmandaic",
+ "lt",
+ "so",
+ "inlinearbideograms",
+ "incommonindicnumberforms",
+ "incjkcompatibilityideographssupplement",
+ "idc",
+ "inoldsoutharabian",
+ "insylotinagri",
+ "idsbinaryoperator",
+ "sora",
+ "bamum",
+ "inkanasupplement",
+ "incjkstrokes",
+ "joinc",
+ "inopticalcharacterrecognition",
+ "vs",
+ "indominotiles",
+ "batk",
+ "grext",
+ "batak",
+ "patws",
+ "inmodifiertoneletters",
+ "ital",
+ "bass",
+ "decimalnumber",
+ "alnum",
+ "ids",
+ "print",
+ "inlatinextendeda",
+ "intaitham",
+ "inmusicalsymbols",
+ "intaile",
+ "samr",
+ "samaritan",
+ "s",
+ "inlatinextendede",
+ "bali",
+ "lisu",
+ "pauc",
+ "patternsyntax",
+ "incontrolpictures",
+ "blank",
+ "inmiscellaneoussymbols",
+ "ll",
+ "inancientgreekmusicalnotation",
+ "zl",
+ "inlydian",
+ "sm",
+ "inmiscellaneoussymbolsandarrows",
+ "inugaritic",
+ "bengali",
+ "pd",
+ "inmiscellaneoussymbolsandpictographs",
+ "medf",
+ "cf",
+ "balinese",
+ "medefaidrin",
+ "han",
+ "intamil",
+ "hani",
+ "inmultani",
+ "hano",
+ "inshorthandformatcontrols",
+ "insaurashtra",
+ "pf",
+ "inoldturkic",
+ "idcontinue",
+ "hanunoo",
+ "sc",
+ "inkhojki",
+ "idst",
+ "canadianaboriginal",
+ "hira",
+ "plrd",
+ "incaucasianalbanian",
+ "indeseret",
+ "inearlydynasticcuneiform",
+ "inspacingmodifierletters",
+ "innewa",
+ "idstart",
+ "zinh",
+ "incyrillicextendeda",
+ "dsrt",
+ "cased",
+ "glagolitic",
+ "inhanifirohingya",
+ "inancientgreeknumbers",
+ "inmeeteimayekextensions",
+ "intaixuanjingsymbols",
+ "joincontrol",
+ "runr",
+ "inwarangciti",
+ "deseret",
+ "inhiragana",
+ "sind",
+ "cherokee",
+ "inlatinextendedc",
+ "adlm",
+ "phoenician",
+ "cher",
+ "marchen",
+ "inkhudawadi",
+ "sinhala",
+ "lower",
+ "graphemelink",
+ "xidstart",
+ "ingrantha",
+ "bidic",
+ "xdigit",
+ "casedletter",
+ "gong",
+ "multani",
+ "gunjalagondi",
+ "cham",
+ "chakma",
+ "mong",
+ "kaithi",
+ "inmahajani",
+ "graphemebase",
+ "insiddham",
+ "inogham",
+ "inosage",
+ "incountingrodnumerals",
+ "inwancho",
+ "khojki",
+ "ingeneralpunctuation",
+ "georgian",
+ "incyrillicextendedc",
+ "inkayahli",
+ "khar",
+ "inoriya",
+ "manichaean",
+ "bamu",
+ "zanb",
+ "oriya",
+ "inolchiki",
+ "linb",
+ "inethiopic",
+ "wara",
+ "ingeorgian",
+ "innabataean",
+ "inkanbun",
+ "adlam",
+ "inbhaiksuki",
+ "insinhala",
+ "inelbasan",
+ "lowercase",
+ "takri",
+ "inmongolian",
+ "invai",
+ "xsux",
+ "cntrl",
+ "emoji",
+ "sterm",
+ "cuneiform",
+ "cwcm",
+ "hatran",
+ "linearb",
+ "taile",
+ "inlatinextendedadditional",
+ "inenclosedalphanumerics",
+ "anatolianhieroglyphs",
+ "incyrillicsupplement",
+ "intamilsupplement",
+ "inmiscellaneoustechnical",
+ "ahom",
+ "incherokeesupplement",
+ "takr",
+ "khmr",
+ "incjkunifiedideographsextensiona",
+ "quotationmark",
+ "lyci",
+ "lycian",
+ "ingurmukhi",
+ "runic",
+ "limb",
+ "inscriptionalpahlavi",
+ "hatr",
+ "variationselector",
+ "modifierletter",
+ "incjkunifiedideographsextensione",
+ "mymr",
+ "myanmar",
+ "lu",
+ "kharoshthi",
+ "inarabic",
+ "radical",
+ "khmer",
+ "inunifiedcanadianaboriginalsyllabics",
+ "osage",
+ "sundanese",
+ "innewtailue",
+ "logicalorderexception",
+ "math",
+ "braille",
+ "goth",
+ "insorasompeng",
+ "insoyombo",
+ "arab",
+ "saur",
+ "guru",
+ "term",
+ "paucinhau",
+ "inbasiclatin",
+ "inarabicpresentationformsa",
+ "punct",
+ "gurmukhi",
+ "grantha",
+ "inshavian",
+ "osma",
+ "inenclosedalphanumericsupplement",
+ "intirhuta",
+ "inelymaic",
+ "inhatran",
+ "incjkunifiedideographsextensionc",
+ "emojimodifier",
+ "uideo",
+ "bidicontrol",
+ "phnx",
+ "limbu",
+ "n",
+ "inenclosedideographicsupplement",
+ "mult",
+ "kthi",
+ "incjkunifiedideographs",
+ "ingreekandcoptic",
+ "inoldhungarian",
+ "incjkcompatibility",
+ "grbase",
+ "nandinagari",
+ "brah",
+ "no",
+ "sd",
+ "nko",
+ "nkoo",
+ "xpeo",
+ "sidd",
+ "inherited",
+ "p",
+ "phli",
+ "inmeroitichieroglyphs",
+ "inphoenician",
+ "inmayannumerals",
+ "saurashtra",
+ "inkangxiradicals",
+ "enclosingmark",
+ "graphemeextend",
+ "beng",
+ "inbatak",
+ "glag",
+ "ahex",
+ "patsyn",
+ "odi",
+ "dogra",
+ "intibetan",
+ "lydi",
+ "lydian",
+ "inblockelements",
+ "cwcf",
+ "inunifiedcanadianaboriginalsyllabicsextended",
+ "regionalindicator",
+ "ingreekextended",
+ "emojimodifierbase",
+ "inanatolianhieroglyphs",
+ "indogra",
+ "taiviet",
+ "inyiradicals",
+ "unassigned",
+ "insundanesesupplement",
+ "innumberforms",
+ "lowercaseletter",
+ "dogr",
+ "lepc",
+ "bhks",
+ "word",
+ "gujr",
+ "inphaistosdisc",
+ "bhaiksuki",
+ "dash",
+ "inarabicextendeda",
+ "gujarati",
+ "inlatinextendedd",
+ "innoblock",
+ "java",
+ "ingeometricshapes",
+ "cyrl",
+ "indevanagari",
+ "inbalinese",
+ "inbyzantinemusicalsymbols",
+ "tale",
+ "deva",
+ "hex",
+ "inmyanmarextendedb",
+ "sinh",
+ "cwt",
+ "shavian",
+ "devanagari",
+ "oidc",
+ "javanese",
+ "mlym",
+ "incjkunifiedideographsextensiond",
+ "sentenceterminal",
+ "malayalam",
+ "inhanunoo",
+ "insinhalaarchaicnumbers",
+ "olck",
+ "inimperialaramaic",
+ "olower",
+ "palmyrene",
+ "avestan",
+ "incjkunifiedideographsextensionf",
+ "insogdian",
+ "indingbats",
+ "olchiki",
+ "oids",
+ "punctuation",
+ "sund",
+ "inbraillepatterns",
+ "emojicomponent",
+ "ideographic",
+ "taml",
+ "format",
+ "inornamentaldingbats",
+ "coptic",
+ "caseignorable",
+ "idsb",
+ "inmiscellaneousmathematicalsymbolsb",
+ "sogdian",
+ "sogo",
+ "terminalpunctuation",
+ "intangut",
+ "intifinagh",
+ "inlowsurrogates",
+ "invariationselectors",
+ "copt",
+ "soyo",
+ "intags",
+ "inverticalforms",
+ "ininscriptionalparthian",
+ "ininscriptionalpahlavi",
+ "meroitichieroglyphs",
+ "asciihexdigit",
+ "inethiopicextendeda",
+ "invedicextensions",
+ "nand",
+ "cwl",
+ "cprt",
+ "innushu",
+ "zanabazarsquare",
+ "ingeometricshapesextended",
+ "avst",
+ "imperialaramaic",
+ "bopo",
+ "sarb",
+ "inoldpersian",
+ "intaiviet",
+ "mahj",
+ "inkatakanaphoneticextensions",
+ "mahajani",
+ "closepunctuation",
+ "inlisu",
+ "softdotted",
+ "unknown",
+ "invariationselectorssupplement",
+ "syrc",
+ "hang",
+ "incjksymbolsandpunctuation",
+ "ingujarati",
+ "bopomofo",
+ "alpha",
+ "khoj",
+ "inpalmyrene",
+ "ingunjalagondi",
+ "inoldpermic",
+ "inlepcha",
+ "assigned",
+ "incurrencysymbols",
+ "insmallformvariants",
+ "sorasompeng",
+ "inlinearbsyllabary",
+ "oldpersian",
+ "caucasianalbanian",
+ "inenclosedcjklettersandmonths",
+ "hiragana",
+ "inbamum",
+ "inrejang",
+ "graph",
+ "sharada",
+ "inethiopicsupplement",
+ "indevanagariextended",
+ "incoptic",
+ "insyriacsupplement",
+ "inmeroiticcursive",
+ "hmng",
+ "intelugu",
+ "incombiningdiacriticalmarks",
+ "mathsymbol",
+ "titlecaseletter",
+ "ugar",
+ "incombiningdiacriticalmarksforsymbols",
+ "spacingmark",
+ "shrd",
+ "injavanese",
+ "syriac",
+ "space",
+ "hebr",
+ "ext",
+ "inhanguljamo",
+ "phag",
+ "inhanguljamoextendeda",
+ "wancho",
+ "bugi",
+ "tamil",
+ "sogd",
+ "orkh",
+ "oldpermic",
+ "siddham",
+ "incyrillicextendedb",
+ "inbrahmi",
+ "inmongoliansupplement",
+ "thaa",
+ "thaana",
+ "thai",
+ "buginese",
+ "ingeorgiansupplement",
+ "digit",
+ "cyrillic",
+ "sylo",
+ "inphoneticextensions",
+ "separator",
+ "inethiopicextended",
+ "inmathematicalalphanumericsymbols",
+ "insymbolsandpictographsextendeda",
+ "nd",
+ "tirh",
+ "tirhuta",
+ "incombiningdiacriticalmarkssupplement",
+ "extender",
+ "wcho",
+ "inbengali",
+ "talu",
+ "tang",
+ "warangciti",
+ "tagbanwa",
+ "orya",
+ "nl",
+ "induployan",
+ "cwu",
+ "inbuginese",
+ "telu",
+ "ogam",
+ "taitham",
+ "rjng",
+ "insuttonsignwriting",
+ "incombiningdiacriticalmarksextended",
+ "number",
+ "inyijinghexagramsymbols",
+ "whitespace",
+ "currencysymbol",
+ "inottomansiyaqnumbers",
+ "inlimbu",
+ "incopticepactnumbers",
+ "ingeorgianextended",
+ "inphoneticextensionssupplement",
+ "any",
+ "osge",
+ "defaultignorablecodepoint",
+ "hangul",
+ "newa",
+ "ethi",
+ "hanifirohingya",
+ "hmnp",
+ "olditalic",
+ "incjkunifiedideographsextensionb",
+ "rohg",
+ "innyiakengpuachuehmong",
+ "incjkradicalssupplement",
+ "newtailue",
+ "newline",
+ "lepcha",
+ "deprecated",
+ "buhd",
+ "inglagolitic",
+ "inaegeannumbers",
+ "modifiersymbol",
+ "surrogate",
+ "inletterlikesymbols",
+ "idstrinaryoperator",
+ "intagalog",
+ "tangut",
+ "osmanya",
+ "oalpha",
+ "inphagspa",
+ "ugaritic",
+ "otheridcontinue",
+ "inarabicpresentationformsb",
+ "inbassavah",
+ "other",
+ "othernumber",
+ "sylotinagri",
+ "ingothic",
+ "inbuhid",
+ "inlatin1supplement",
+ "intagbanwa",
+ "shaw",
+ "oldhungarian",
+ "inmahjongtiles",
+ "hung",
+ "tifinagh",
+ "inbopomofo",
+ "narb",
+ "inyisyllables",
+ "kayahli",
+ "otheralphabetic",
+ "phagspa",
+ "inprivateusearea",
+ "elba",
+ "nchar",
+ "spaceseparator",
+ "tibt",
+ "extendedpictographic",
+ "tibetan",
+ "sgnw",
+ "hexdigit",
+ "tfng",
+ "inbamumsupplement",
+ "tavt",
+ "incombininghalfmarks",
+ "inarabicmathematicalalphabeticsymbols",
+ "khudawadi",
+ "inhalfwidthandfullwidthforms",
+ "inhangulsyllables",
+ "elym",
+ "symbol",
+ "bassavah",
+ "elymaic",
+ "changeswhencasemapped",
+ "oldturkic",
+ "inplayingcards",
+ "zp",
+ "elbasan",
+ "buhid",
+ "noncharactercodepoint",
+ "finalpunctuation",
+ "inpsalterpahlavi",
+ "inpaucinhau",
+ "nonspacingmark",
+ "changeswhentitlecased",
+ "inindicsiyaqnumbers",
+ "phlp",
+ "wspace",
+ "nbat",
+ "hluw",
+ "cypriot",
+ "nabataean",
+ "inalchemicalsymbols",
+ "dupl",
+ "otherlowercase",
+ "inarabicsupplement",
+ "inalphabeticpresentationforms",
+ "otherletter",
+ "emojipresentation",
+ "changeswhenlowercased",
+ "dashpunctuation",
+ "oldsogdian",
+ "intangutcomponents",
+ "soyombo",
+ "paragraphseparator",
+ "changeswhencasefolded",
+ "othersymbol",
+ "inlatinextendedb",
+ "otheruppercase",
+ "otheridstart",
+ "inhebrew",
+ "oldnortharabian",
+ "omath",
+ "incypriotsyllabary",
+ "inmathematicaloperators",
+ "changeswhenuppercased",
+ "nshu",
+ "insuperscriptsandsubscripts",
+ "ogrext",
+ "inhanguljamoextendedb",
+ "alphabetic",
+ "dep",
+ "oupper",
+ "zyyy",
+ "aghb",
+ "ogham",
+ "rejang",
+ "tagb",
+ "hyphen",
+ "insupplementalarrowsa",
+ "inpahawhhmong",
+ "nushu",
+ "othermath",
+ "insupplementalarrowsc",
+ "insupplementalmathematicaloperators",
+ "otherdefaultignorablecodepoint",
+ "inhighprivateusesurrogates",
+ "duployan",
+ "oldsoutharabian",
+ "tglg",
+ "tagalog",
+ "inbopomofoextended",
+ "signwriting",
+ "inegyptianhieroglyphs",
+ "inegyptianhieroglyphformatcontrols",
+ "upper",
+ "otherpunctuation",
+ "ethiopic",
+ "hebrew",
+ "telugu",
+ "uppercase",
+ "insupplementalpunctuation",
+ "unifiedideograph",
+ "pahawhhmong",
+ "inglagoliticsupplement",
+ "inboxdrawing",
+ "uppercaseletter",
+ "othergraphemeextend",
+ "inhighsurrogates",
+ "insupplementalarrowsb",
+ "inhangulcompatibilityjamo",
+ "egyp",
+ "insupplementalsymbolsandpictographs",
+ "nyiakengpuachuehmong",
+ "insupplementaryprivateuseareaa",
+ "openpunctuation",
+ "egyptianhieroglyphs",
+ "insupplementaryprivateuseareab"
+ };
+#define unicode_prop_name_pool ((const char *) &unicode_prop_name_pool_contents)
+static const struct PoolPropertyNameCtype *
+unicode_lookup_property_name (register const char *str, register size_t len)
+{
+ static const struct PoolPropertyNameCtype wordlist[] =
+ {
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(10), 238},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(14), 262},
+ {-1},
+
+ {pool_offset(16), 261},
+
+ {pool_offset(17), 125},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(24), 154},
+
+ {pool_offset(25), 261},
+ {-1},
+
+ {pool_offset(27), 53},
+
+ {pool_offset(28), 139},
+ {-1},
+
+ {pool_offset(30), 142},
+ {-1}, {-1},
+
+ {pool_offset(33), 252},
+
+ {pool_offset(34), 295},
+
+ {pool_offset(35), 40},
+ {-1},
+
+ {pool_offset(37), 130},
+
+ {pool_offset(38), 121},
+
+ {pool_offset(39), 121},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(43), 153},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(51), 283},
+ {-1},
+
+ {pool_offset(53), 54},
+ {-1}, {-1},
+
+ {pool_offset(56), 147},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(60), 131},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(70), 83},
+ {-1},
+
+ {pool_offset(72), 205},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(76), 125},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(84), 137},
+ {-1},
+
+ {pool_offset(86), 39},
+
+ {pool_offset(87), 39},
+ {-1}, {-1},
+
+ {pool_offset(90), 206},
+
+ {pool_offset(91), 150},
+ {-1}, {-1},
+
+ {pool_offset(94), 87},
+ {-1},
+
+ {pool_offset(96), 201},
+ {-1}, {-1},
+
+ {pool_offset(99), 149},
+ {-1},
+
+ {pool_offset(101), 460},
+
+ {pool_offset(102), 80},
+
+ {pool_offset(103), 87},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(107), 157},
+
+ {pool_offset(108), 157},
+ {-1},
+
+ {pool_offset(110), 113},
+
+ {pool_offset(111), 152},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(120), 137},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(133), 144},
+
+ {pool_offset(134), 45},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(139), 446},
+ {-1}, {-1},
+
+ {pool_offset(142), 463},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(146), 277},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(151), 512},
+
+ {pool_offset(152), 516},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(156), 37},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(163), 478},
+ {-1}, {-1},
+
+ {pool_offset(166), 55},
+ {-1}, {-1},
+
+ {pool_offset(169), 141},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(182), 301},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(187), 503},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(192), 106},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(200), 517},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(204), 314},
+ {-1}, {-1},
+
+ {pool_offset(207), 38},
+ {-1},
+
+ {pool_offset(209), 207},
+ {-1},
+
+ {pool_offset(211), 129},
+
+ {pool_offset(212), 143},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(219), 199},
+
+ {pool_offset(220), 309},
+
+ {pool_offset(221), 437},
+ {-1},
+
+ {pool_offset(223), 464},
+ {-1},
+
+ {pool_offset(225), 137},
+
+ {pool_offset(226), 506},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(231), 151},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(238), 177},
+
+ {pool_offset(239), 492},
+
+ {pool_offset(240), 271},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(251), 306},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(257), 480},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(268), 139},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(272), 344},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(277), 120},
+ {-1},
+
+ {pool_offset(279), 144},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(283), 505},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(290), 146},
+ {-1}, {-1},
+
+ {pool_offset(293), 43},
+ {-1},
+
+ {pool_offset(295), 496},
+ {-1}, {-1},
+
+ {pool_offset(298), 264},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(302), 22},
+ {-1}, {-1},
+
+ {pool_offset(305), 210},
+
+ {pool_offset(306), 105},
+ {-1}, {-1},
+
+ {pool_offset(309), 284},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(316), 22},
+ {-1},
+
+ {pool_offset(318), 500},
+
+ {pool_offset(319), 501},
+ {-1},
+
+ {pool_offset(321), 56},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(330), 199},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(335), 108},
+
+ {pool_offset(336), 122},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(340), 122},
+ {-1},
+
+ {pool_offset(342), 212},
+ {-1}, {-1},
+
+ {pool_offset(345), 282},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(352), 320},
+ {-1}, {-1},
+
+ {pool_offset(355), 375},
+
+ {pool_offset(356), 275},
+
+ {pool_offset(357), 298},
+ {-1},
+
+ {pool_offset(359), 405},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(367), 476},
+ {-1},
+
+ {pool_offset(369), 266},
+ {-1}, {-1},
+
+ {pool_offset(372), 149},
+ {-1}, {-1},
+
+ {pool_offset(375), 254},
+
+ {pool_offset(376), 254},
+ {-1}, {-1},
+
+ {pool_offset(379), 205},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(383), 57},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(399), 280},
+ {-1},
+
+ {pool_offset(401), 207},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(415), 491},
+ {-1},
+
+ {pool_offset(417), 141},
+ {-1},
+
+ {pool_offset(419), 119},
+
+ {pool_offset(420), 208},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(427), 66},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(431), 521},
+ {-1},
+
+ {pool_offset(433), 62},
+ {-1}, {-1},
+
+ {pool_offset(436), 150},
+
+ {pool_offset(437), 155},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(441), 104},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(445), 113},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(449), 108},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(456), 372},
+
+ {pool_offset(457), 450},
+
+ {pool_offset(458), 259},
+ {-1}, {-1},
+
+ {pool_offset(461), 34},
+ {-1},
+
+ {pool_offset(463), 299},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(472), 14},
+ {-1},
+
+ {pool_offset(474), 54},
+ {-1}, {-1},
+
+ {pool_offset(477), 21},
+
+ {pool_offset(478), 156},
+ {-1},
+
+ {pool_offset(480), 406},
+
+ {pool_offset(481), 471},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(485), 119},
+ {-1},
+
+ {pool_offset(487), 495},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(499), 412},
+
+ {pool_offset(500), 462},
+ {-1}, {-1},
+
+ {pool_offset(503), 86},
+
+ {pool_offset(504), 112},
+ {-1}, {-1},
+
+ {pool_offset(507), 112},
+ {-1},
+
+ {pool_offset(509), 425},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(514), 419},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(528), 489},
+
+ {pool_offset(529), 114},
+ {-1}, {-1},
+
+ {pool_offset(532), 43},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(536), 538},
+ {-1},
+
+ {pool_offset(538), 429},
+ {-1},
+
+ {pool_offset(540), 537},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(545), 550},
+ {-1},
+
+ {pool_offset(547), 167},
+ {-1},
+
+ {pool_offset(549), 259},
+
+ {pool_offset(550), 515},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(558), 555},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(564), 548},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(573), 33},
+ {-1},
+
+ {pool_offset(575), 439},
+ {-1}, {-1},
+
+ {pool_offset(578), 195},
+ {-1},
+
+ {pool_offset(580), 436},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(588), 355},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(594), 260},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(603), 209},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(619), 325},
+
+ {pool_offset(620), 472},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(632), 66},
+ {-1},
+
+ {pool_offset(634), 82},
+
+ {pool_offset(635), 434},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(639), 151},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(643), 296},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(648), 197},
+
+ {pool_offset(649), 225},
+ {-1}, {-1},
+
+ {pool_offset(652), 522},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(656), 285},
+
+ {pool_offset(657), 133},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(665), 227},
+
+ {pool_offset(666), 431},
+ {-1},
+
+ {pool_offset(668), 396},
+
+ {pool_offset(669), 562},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(677), 102},
+
+ {pool_offset(678), 461},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(699), 395},
+ {-1},
+
+ {pool_offset(701), 100},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(707), 230},
+
+ {pool_offset(708), 26},
+
+ {pool_offset(709), 520},
+
+ {pool_offset(710), 380},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(715), 110},
+ {-1}, {-1},
+
+ {pool_offset(718), 348},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(722), 255},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(728), 543},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(732), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(739), 85},
+ {-1},
+
+ {pool_offset(741), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(749), 197},
+ {-1}, {-1},
+
+ {pool_offset(752), 393},
+
+ {pool_offset(753), 175},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(760), 27},
+ {-1}, {-1},
+
+ {pool_offset(763), 163},
+ {-1},
+
+ {pool_offset(765), 13},
+ {-1},
+
+ {pool_offset(767), 103},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(776), 7},
+ {-1},
+
+ {pool_offset(778), 269},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(782), 322},
+
+ {pool_offset(783), 527},
+ {-1},
+
+ {pool_offset(785), 318},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(794), 216},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(809), 216},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(813), 215},
+ {-1}, {-1},
+
+ {pool_offset(816), 410},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(820), 25},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(826), 127},
+
+ {pool_offset(827), 198},
+
+ {pool_offset(828), 196},
+
+ {pool_offset(829), 347},
+
+ {pool_offset(830), 2},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(834), 353},
+
+ {pool_offset(835), 128},
+
+ {pool_offset(836), 528},
+
+ {pool_offset(837), 264},
+
+ {pool_offset(838), 457},
+
+ {pool_offset(839), 226},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(843), 361},
+
+ {pool_offset(844), 442},
+
+ {pool_offset(845), 29},
+
+ {pool_offset(846), 200},
+ {-1},
+
+ {pool_offset(848), 547},
+ {-1},
+
+ {pool_offset(850), 148},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(855), 44},
+ {-1}, {-1},
+
+ {pool_offset(858), 25},
+ {-1},
+
+ {pool_offset(860), 148},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(865), 91},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(869), 293},
+
+ {pool_offset(870), 91},
+
+ {pool_offset(871), 483},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(879), 94},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(887), 525},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(891), 398},
+
+ {pool_offset(892), 202},
+ {-1},
+
+ {pool_offset(894), 468},
+ {-1},
+
+ {pool_offset(896), 102},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(901), 94},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(905), 218},
+
+ {pool_offset(906), 482},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(913), 101},
+ {-1},
+
+ {pool_offset(915), 38},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(923), 98},
+ {-1},
+
+ {pool_offset(925), 153},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(939), 449},
+
+ {pool_offset(940), 444},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(945), 507},
+
+ {pool_offset(946), 272},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(950), 486},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(972), 103},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(977), 106},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(981), 368},
+ {-1}, {-1},
+
+ {pool_offset(984), 64},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(993), 41},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(999), 81},
+ {-1}, {-1},
+
+ {pool_offset(1002), 470},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1006), 433},
+ {-1},
+
+ {pool_offset(1008), 408},
+
+ {pool_offset(1009), 530},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1016), 110},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1020), 214},
+ {-1}, {-1},
+
+ {pool_offset(1023), 494},
+ {-1},
+
+ {pool_offset(1025), 64},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1035), 374},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1039), 118},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1047), 52},
+ {-1}, {-1},
+
+ {pool_offset(1050), 363},
+ {-1},
+
+ {pool_offset(1052), 16},
+
+ {pool_offset(1053), 204},
+ {-1}, {-1},
+
+ {pool_offset(1056), 52},
+ {-1}, {-1},
+
+ {pool_offset(1059), 143},
+ {-1}, {-1},
+
+ {pool_offset(1062), 484},
+
+ {pool_offset(1063), 224},
+ {-1}, {-1},
+
+ {pool_offset(1066), 6},
+ {-1},
+
+ {pool_offset(1068), 86},
+
+ {pool_offset(1069), 260},
+ {-1},
+
+ {pool_offset(1071), 485},
+
+ {pool_offset(1072), 31},
+ {-1},
+
+ {pool_offset(1074), 11},
+ {-1},
+
+ {pool_offset(1076), 120},
+ {-1},
+
+ {pool_offset(1078), 89},
+
+ {pool_offset(1079), 158},
+ {-1}, {-1},
+
+ {pool_offset(1082), 89},
+ {-1},
+
+ {pool_offset(1084), 46},
+ {-1},
+
+ {pool_offset(1086), 45},
+
+ {pool_offset(1087), 156},
+
+ {pool_offset(1088), 111},
+
+ {pool_offset(1089), 479},
+
+ {pool_offset(1090), 84},
+ {-1},
+
+ {pool_offset(1092), 488},
+ {-1}, {-1},
+
+ {pool_offset(1095), 308},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1101), 447},
+
+ {pool_offset(1102), 531},
+ {-1},
+
+ {pool_offset(1104), 536},
+
+ {pool_offset(1105), 117},
+ {-1},
+
+ {pool_offset(1107), 338},
+
+ {pool_offset(1108), 80},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1117), 329},
+
+ {pool_offset(1118), 400},
+ {-1}, {-1},
+
+ {pool_offset(1121), 115},
+ {-1}, {-1},
+
+ {pool_offset(1124), 292},
+ {-1},
+
+ {pool_offset(1126), 142},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1132), 26},
+
+ {pool_offset(1133), 263},
+ {-1}, {-1},
+
+ {pool_offset(1136), 182},
+
+ {pool_offset(1137), 328},
+
+ {pool_offset(1138), 126},
+ {-1}, {-1},
+
+ {pool_offset(1141), 304},
+ {-1},
+
+ {pool_offset(1143), 257},
+
+ {pool_offset(1144), 302},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1149), 454},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1154), 378},
+ {-1},
+
+ {pool_offset(1156), 16},
+
+ {pool_offset(1157), 499},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1162), 297},
+
+ {pool_offset(1163), 448},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1169), 132},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1178), 240},
+
+ {pool_offset(1179), 315},
+ {-1},
+
+ {pool_offset(1181), 390},
+
+ {pool_offset(1182), 58},
+
+ {pool_offset(1183), 3},
+ {-1}, {-1},
+
+ {pool_offset(1186), 72},
+
+ {pool_offset(1187), 219},
+ {-1},
+
+ {pool_offset(1189), 58},
+ {-1}, {-1},
+
+ {pool_offset(1192), 48},
+ {-1},
+
+ {pool_offset(1194), 95},
+ {-1}, {-1},
+
+ {pool_offset(1197), 126},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1201), 237},
+
+ {pool_offset(1202), 336},
+
+ {pool_offset(1203), 349},
+ {-1},
+
+ {pool_offset(1205), 19},
+
+ {pool_offset(1206), 276},
+ {-1},
+
+ {pool_offset(1208), 504},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1215), 346},
+ {-1},
+
+ {pool_offset(1217), 17},
+
+ {pool_offset(1218), 411},
+
+ {pool_offset(1219), 240},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1224), 116},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1228), 384},
+ {-1}, {-1},
+
+ {pool_offset(1231), 210},
+ {-1},
+
+ {pool_offset(1233), 135},
+
+ {pool_offset(1234), 135},
+
+ {pool_offset(1235), 290},
+ {-1},
+
+ {pool_offset(1237), 214},
+
+ {pool_offset(1238), 124},
+ {-1},
+
+ {pool_offset(1240), 107},
+ {-1},
+
+ {pool_offset(1242), 95},
+ {-1},
+
+ {pool_offset(1244), 255},
+ {-1},
+
+ {pool_offset(1246), 129},
+
+ {pool_offset(1247), 560},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1262), 159},
+ {-1}, {-1},
+
+ {pool_offset(1265), 159},
+ {-1},
+
+ {pool_offset(1267), 134},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1275), 115},
+
+ {pool_offset(1276), 279},
+ {-1},
+
+ {pool_offset(1278), 211},
+ {-1}, {-1},
+
+ {pool_offset(1281), 116},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1286), 307},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1292), 183},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1296), 232},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1300), 319},
+ {-1},
+
+ {pool_offset(1302), 131},
+ {-1},
+
+ {pool_offset(1304), 145},
+ {-1},
+
+ {pool_offset(1306), 34},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1311), 82},
+
+ {pool_offset(1312), 477},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1316), 497},
+
+ {pool_offset(1317), 21},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1322), 217},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1329), 90},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1333), 244},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1337), 198},
+
+ {pool_offset(1338), 267},
+
+ {pool_offset(1339), 421},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1347), 8},
+
+ {pool_offset(1348), 90},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1354), 83},
+
+ {pool_offset(1355), 445},
+
+ {pool_offset(1356), 184},
+
+ {pool_offset(1357), 545},
+ {-1}, {-1},
+
+ {pool_offset(1360), 487},
+
+ {pool_offset(1361), 474},
+
+ {pool_offset(1362), 455},
+ {-1},
+
+ {pool_offset(1364), 558},
+
+ {pool_offset(1365), 74},
+ {-1}, {-1},
+
+ {pool_offset(1368), 251},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1373), 31},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1379), 204},
+
+ {pool_offset(1380), 124},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1384), 160},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1388), 546},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1392), 158},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1398), 111},
+
+ {pool_offset(1399), 386},
+ {-1},
+
+ {pool_offset(1401), 274},
+ {-1},
+
+ {pool_offset(1403), 469},
+ {-1}, {-1},
+
+ {pool_offset(1406), 383},
+ {-1}, {-1},
+
+ {pool_offset(1409), 84},
+ {-1},
+
+ {pool_offset(1411), 162},
+
+ {pool_offset(1412), 33},
+ {-1},
+
+ {pool_offset(1414), 168},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1421), 228},
+ {-1},
+
+ {pool_offset(1423), 166},
+
+ {pool_offset(1424), 166},
+ {-1}, {-1},
+
+ {pool_offset(1427), 178},
+ {-1}, {-1},
+
+ {pool_offset(1430), 222},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1435), 106},
+ {-1},
+
+ {pool_offset(1437), 193},
+ {-1}, {-1},
+
+ {pool_offset(1440), 107},
+ {-1}, {-1},
+
+ {pool_offset(1443), 458},
+
+ {pool_offset(1444), 456},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1449), 529},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1453), 217},
+ {-1},
+
+ {pool_offset(1455), 371},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1461), 147},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1467), 85},
+
+ {pool_offset(1468), 29},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1473), 326},
+
+ {pool_offset(1474), 81},
+
+ {pool_offset(1475), 15},
+ {-1},
+
+ {pool_offset(1477), 196},
+ {-1},
+
+ {pool_offset(1479), 186},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1486), 67},
+ {-1}, {-1},
+
+ {pool_offset(1489), 300},
+ {-1},
+
+ {pool_offset(1491), 136},
+
+ {pool_offset(1492), 136},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1499), 351},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1506), 47},
+
+ {pool_offset(1507), 316},
+
+ {pool_offset(1508), 212},
+
+ {pool_offset(1509), 337},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1513), 75},
+
+ {pool_offset(1514), 510},
+ {-1},
+
+ {pool_offset(1516), 493},
+
+ {pool_offset(1517), 239},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1524), 388},
+
+ {pool_offset(1525), 53},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1532), 331},
+ {-1}, {-1},
+
+ {pool_offset(1535), 343},
+ {-1}, {-1},
+
+ {pool_offset(1538), 128},
+ {-1}, {-1},
+
+ {pool_offset(1541), 67},
+
+ {pool_offset(1542), 123},
+ {-1}, {-1},
+
+ {pool_offset(1545), 30},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1553), 12},
+
+ {pool_offset(1554), 88},
+
+ {pool_offset(1555), 435},
+ {-1},
+
+ {pool_offset(1557), 30},
+ {-1}, {-1},
+
+ {pool_offset(1560), 61},
+ {-1},
+
+ {pool_offset(1562), 287},
+ {-1}, {-1},
+
+ {pool_offset(1565), 88},
+
+ {pool_offset(1566), 394},
+
+ {pool_offset(1567), 567},
+ {-1}, {-1},
+
+ {pool_offset(1570), 109},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1576), 352},
+
+ {pool_offset(1577), 60},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1582), 288},
+
+ {pool_offset(1583), 324},
+ {-1},
+
+ {pool_offset(1585), 526},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1589), 237},
+ {-1},
+
+ {pool_offset(1591), 65},
+ {-1}, {-1},
+
+ {pool_offset(1594), 97},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1601), 404},
+ {-1},
+
+ {pool_offset(1603), 224},
+
+ {pool_offset(1604), 50},
+ {-1},
+
+ {pool_offset(1606), 221},
+
+ {pool_offset(1607), 65},
+ {-1},
+
+ {pool_offset(1609), 188},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1615), 109},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1621), 140},
+
+ {pool_offset(1622), 559},
+ {-1},
+
+ {pool_offset(1624), 219},
+ {-1},
+
+ {pool_offset(1626), 140},
+ {-1},
+
+ {pool_offset(1628), 311},
+
+ {pool_offset(1629), 481},
+ {-1},
+
+ {pool_offset(1631), 173},
+ {-1},
+
+ {pool_offset(1633), 452},
+ {-1}, {-1},
+
+ {pool_offset(1636), 190},
+ {-1},
+
+ {pool_offset(1638), 195},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1642), 24},
+ {-1}, {-1},
+
+ {pool_offset(1645), 561},
+
+ {pool_offset(1646), 473},
+
+ {pool_offset(1647), 354},
+
+ {pool_offset(1648), 173},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1654), 189},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1661), 193},
+ {-1},
+
+ {pool_offset(1663), 232},
+ {-1}, {-1},
+
+ {pool_offset(1666), 357},
+ {-1}, {-1},
+
+ {pool_offset(1669), 73},
+ {-1}, {-1},
+
+ {pool_offset(1672), 104},
+
+ {pool_offset(1673), 241},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1688), 44},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1694), 549},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1700), 56},
+ {-1},
+
+ {pool_offset(1702), 40},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1708), 100},
+
+ {pool_offset(1709), 359},
+ {-1}, {-1},
+
+ {pool_offset(1712), 229},
+ {-1}, {-1},
+
+ {pool_offset(1715), 179},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1720), 244},
+ {-1},
+
+ {pool_offset(1722), 518},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1729), 366},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1733), 417},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1743), 422},
+ {-1},
+
+ {pool_offset(1745), 56},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1750), 231},
+ {-1}, {-1},
+
+ {pool_offset(1753), 563},
+ {-1}, {-1},
+
+ {pool_offset(1756), 423},
+
+ {pool_offset(1757), 465},
+ {-1}, {-1},
+
+ {pool_offset(1760), 466},
+ {-1}, {-1},
+
+ {pool_offset(1763), 152},
+
+ {pool_offset(1764), 15},
+ {-1},
+
+ {pool_offset(1766), 409},
+
+ {pool_offset(1767), 332},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1781), 162},
+
+ {pool_offset(1782), 49},
+ {-1}, {-1},
+
+ {pool_offset(1785), 59},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1791), 523},
+ {-1}, {-1},
+
+ {pool_offset(1794), 263},
+ {-1}, {-1},
+
+ {pool_offset(1797), 552},
+
+ {pool_offset(1798), 24},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1808), 105},
+ {-1},
+
+ {pool_offset(1810), 32},
+ {-1},
+
+ {pool_offset(1812), 180},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1819), 443},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(1830), 407},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1834), 138},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1838), 381},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1845), 138},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1871), 201},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1875), 389},
+ {-1}, {-1},
+
+ {pool_offset(1878), 228},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1897), 252},
+
+ {pool_offset(1898), 564},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(1910), 234},
+
+ {pool_offset(1911), 92},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1926), 373},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1932), 291},
+
+ {pool_offset(1933), 32},
+ {-1}, {-1},
+
+ {pool_offset(1936), 1},
+
+ {pool_offset(1937), 117},
+ {-1},
+
+ {pool_offset(1939), 453},
+ {-1}, {-1},
+
+ {pool_offset(1942), 502},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1948), 441},
+ {-1},
+
+ {pool_offset(1950), 327},
+
+ {pool_offset(1951), 23},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(1955), 340},
+ {-1}, {-1},
+
+ {pool_offset(1958), 426},
+
+ {pool_offset(1959), 230},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1964), 430},
+
+ {pool_offset(1965), 178},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1972), 42},
+
+ {pool_offset(1973), 382},
+ {-1},
+
+ {pool_offset(1975), 98},
+
+ {pool_offset(1976), 392},
+ {-1}, {-1},
+
+ {pool_offset(1979), 401},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1984), 5},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1990), 220},
+
+ {pool_offset(1991), 305},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(1996), 399},
+
+ {pool_offset(1997), 364},
+
+ {pool_offset(1998), 286},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2004), 459},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2014), 194},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2022), 294},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2029), 273},
+ {-1},
+
+ {pool_offset(2031), 226},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2036), 133},
+ {-1},
+
+ {pool_offset(2038), 250},
+
+ {pool_offset(2039), 341},
+
+ {pool_offset(2040), 146},
+ {-1}, {-1},
+
+ {pool_offset(2043), 220},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2047), 403},
+
+ {pool_offset(2048), 234},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2054), 9},
+ {-1},
+
+ {pool_offset(2056), 96},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2061), 79},
+ {-1}, {-1},
+
+ {pool_offset(2064), 303},
+ {-1},
+
+ {pool_offset(2066), 203},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2076), 402},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2082), 256},
+ {-1},
+
+ {pool_offset(2084), 35},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2089), 241},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2093), 229},
+
+ {pool_offset(2094), 181},
+ {-1}, {-1},
+
+ {pool_offset(2097), 177},
+ {-1}, {-1},
+
+ {pool_offset(2100), 222},
+ {-1},
+
+ {pool_offset(2102), 391},
+ {-1}, {-1},
+
+ {pool_offset(2105), 475},
+ {-1}, {-1},
+
+ {pool_offset(2108), 490},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2113), 245},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2118), 245},
+ {-1},
+
+ {pool_offset(2120), 246},
+ {-1},
+
+ {pool_offset(2122), 35},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2127), 365},
+ {-1},
+
+ {pool_offset(2129), 4},
+ {-1}, {-1},
+
+ {pool_offset(2132), 60},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2149), 233},
+
+ {pool_offset(2150), 333},
+
+ {pool_offset(2151), 262},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2159), 367},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2163), 532},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2168), 556},
+ {-1},
+
+ {pool_offset(2170), 163},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2176), 249},
+ {-1},
+
+ {pool_offset(2178), 249},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2184), 335},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2193), 79},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2197), 256},
+ {-1},
+
+ {pool_offset(2199), 289},
+ {-1},
+
+ {pool_offset(2201), 164},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2206), 242},
+
+ {pool_offset(2207), 257},
+ {-1}, {-1},
+
+ {pool_offset(2210), 236},
+
+ {pool_offset(2211), 182},
+
+ {pool_offset(2212), 167},
+
+ {pool_offset(2213), 524},
+
+ {pool_offset(2214), 51},
+ {-1},
+
+ {pool_offset(2216), 321},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2220), 243},
+ {-1}, {-1},
+
+ {pool_offset(2223), 172},
+ {-1}, {-1},
+
+ {pool_offset(2226), 238},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(2237), 213},
+ {-1}, {-1},
+
+ {pool_offset(2240), 533},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2250), 323},
+
+ {pool_offset(2251), 160},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2264), 385},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2277), 258},
+
+ {pool_offset(2278), 218},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2285), 540},
+ {-1}, {-1},
+
+ {pool_offset(2288), 317},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2293), 438},
+ {-1},
+
+ {pool_offset(2295), 330},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2305), 334},
+ {-1}, {-1},
+
+ {pool_offset(2308), 20},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(2320), 183},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2325), 62},
+
+ {pool_offset(2326), 92},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2333), 165},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2343), 77},
+ {-1},
+
+ {pool_offset(2345), 93},
+
+ {pool_offset(2346), 171},
+ {-1},
+
+ {pool_offset(2348), 175},
+
+ {pool_offset(2349), 557},
+ {-1}, {-1},
+
+ {pool_offset(2352), 93},
+
+ {pool_offset(2353), 535},
+ {-1},
+
+ {pool_offset(2355), 370},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2364), 164},
+
+ {pool_offset(2365), 0},
+
+ {pool_offset(2366), 123},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2375), 63},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2381), 36},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2391), 362},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2395), 432},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2400), 225},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2410), 57},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2418), 342},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2426), 101},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2442), 310},
+
+ {pool_offset(2443), 242},
+ {-1},
+
+ {pool_offset(2445), 184},
+ {-1},
+
+ {pool_offset(2447), 185},
+
+ {pool_offset(2448), 397},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2455), 250},
+
+ {pool_offset(2456), 188},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2460), 427},
+ {-1},
+
+ {pool_offset(2462), 513},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2469), 37},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2478), 168},
+ {-1},
+
+ {pool_offset(2480), 233},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2487), 440},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(2498), 312},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2502), 268},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2516), 313},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2523), 221},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2529), 174},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2538), 542},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2542), 174},
+ {-1},
+
+ {pool_offset(2544), 248},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2554), 376},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2561), 176},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2571), 387},
+ {-1},
+
+ {pool_offset(2573), 114},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2578), 185},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2582), 203},
+ {-1},
+
+ {pool_offset(2584), 418},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2588), 70},
+ {-1}, {-1},
+
+ {pool_offset(2591), 169},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2607), 266},
+ {-1},
+
+ {pool_offset(2609), 247},
+ {-1},
+
+ {pool_offset(2611), 78},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2615), 247},
+
+ {pool_offset(2616), 223},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2622), 97},
+
+ {pool_offset(2623), 248},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2627), 511},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2632), 239},
+
+ {pool_offset(2633), 424},
+
+ {pool_offset(2634), 541},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2638), 118},
+ {-1}, {-1},
+
+ {pool_offset(2641), 428},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(2652), 413},
+
+ {pool_offset(2653), 71},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2669), 215},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2692), 27},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2696), 71},
+ {-1},
+
+ {pool_offset(2698), 48},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(2709), 181},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2725), 544},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2767), 265},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2775), 70},
+
+ {pool_offset(2776), 36},
+ {-1}, {-1},
+
+ {pool_offset(2779), 169},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2785), 202},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2794), 467},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2800), 498},
+
+ {pool_offset(2801), 154},
+ {-1}, {-1},
+
+ {pool_offset(2804), 50},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(2808), 539},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2813), 209},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(2824), 258},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2831), 161},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2836), 19},
+ {-1},
+
+ {pool_offset(2838), 59},
+
+ {pool_offset(2839), 161},
+ {-1},
+
+ {pool_offset(2841), 551},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2847), 68},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2856), 190},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2875), 281},
+
+ {pool_offset(2876), 420},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2890), 130},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2916), 76},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2930), 49},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2953), 200},
+
+ {pool_offset(2954), 179},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2970), 519},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2977), 231},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(2996), 265},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3012), 47},
+ {-1}, {-1},
+
+ {pool_offset(3015), 227},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3020), 270},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3072), 192},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3079), 189},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3084), 278},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(3088), 176},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(3092), 191},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3099), 451},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3118), 345},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3146), 51},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3154), 170},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3182), 339},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3188), 187},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3197), 414},
+
+ {pool_offset(3198), 18},
+
+ {pool_offset(3199), 63},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3216), 192},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3258), 55},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3267), 42},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3285), 172},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(3306), 213},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3324), 236},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3350), 99},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3355), 356},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(3413), 514},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3459), 170},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3478), 191},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(3491), 553},
+ {-1}, {-1},
+
+ {pool_offset(3494), 360},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3500), 186},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3527), 416},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(3538), 68},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3663), 180},
+ {-1}, {-1},
+
+ {pool_offset(3666), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3685), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3692), 379},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(3731), 223},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3750), 508},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(3763), 509},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3807), 10},
+ {-1}, {-1},
+
+ {pool_offset(3810), 206},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3872), 77},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3881), 96},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(3901), 243},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3910), 253},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3937), 369},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3946), 251},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3961), 194},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(3971), 534},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(3992), 350},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4279), 134},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4298), 187},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(4401), 415},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+
+ {pool_offset(4476), 358},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4562), 377},
+
+ {pool_offset(4563), 69},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4577), 554},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4659), 171},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(4688), 565},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(4822), 208},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+
+ {pool_offset(4851), 69},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+
+ {pool_offset(5809), 566}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + unicode_prop_name_pool;
+
+ if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+#define UNICODE_PROPERTY_VERSION 120100
+#define UNICODE_EMOJI_VERSION 1201
+
+#define PROPERTY_NAME_MAX_SIZE 59
+#define CODE_RANGES_NUM 568
+
+#define PROP_INDEX_NEWLINE 0
+#define PROP_INDEX_ALPHA 1
+#define PROP_INDEX_BLANK 2
+#define PROP_INDEX_CNTRL 3
+#define PROP_INDEX_DIGIT 4
+#define PROP_INDEX_GRAPH 5
+#define PROP_INDEX_LOWER 6
+#define PROP_INDEX_PRINT 7
+#define PROP_INDEX_PUNCT 8
+#define PROP_INDEX_SPACE 9
+#define PROP_INDEX_UPPER 10
+#define PROP_INDEX_XDIGIT 11
+#define PROP_INDEX_WORD 12
+#define PROP_INDEX_ALNUM 13
+#define PROP_INDEX_ASCII 14
+#define PROP_INDEX_ASCIIHEXDIGIT 15
+#define PROP_INDEX_AHEX 15
+#define PROP_INDEX_ADLM 16
+#define PROP_INDEX_ADLAM 16
+#define PROP_INDEX_AHOM 17
+#define PROP_INDEX_ALPHABETIC 18
+#define PROP_INDEX_ANATOLIANHIEROGLYPHS 19
+#define PROP_INDEX_HLUW 19
+#define PROP_INDEX_ANY 20
+#define PROP_INDEX_ARABIC 21
+#define PROP_INDEX_ARAB 21
+#define PROP_INDEX_ARMN 22
+#define PROP_INDEX_ARMENIAN 22
+#define PROP_INDEX_ASSIGNED 23
+#define PROP_INDEX_AVST 24
+#define PROP_INDEX_AVESTAN 24
+#define PROP_INDEX_BALINESE 25
+#define PROP_INDEX_BALI 25
+#define PROP_INDEX_BAMUM 26
+#define PROP_INDEX_BAMU 26
+#define PROP_INDEX_BASSAVAH 27
+#define PROP_INDEX_BASS 27
+#define PROP_INDEX_BATAK 28
+#define PROP_INDEX_BATK 28
+#define PROP_INDEX_BENG 29
+#define PROP_INDEX_BENGALI 29
+#define PROP_INDEX_BHKS 30
+#define PROP_INDEX_BHAIKSUKI 30
+#define PROP_INDEX_BIDICONTROL 31
+#define PROP_INDEX_BIDIC 31
+#define PROP_INDEX_BOPO 32
+#define PROP_INDEX_BOPOMOFO 32
+#define PROP_INDEX_BRAHMI 33
+#define PROP_INDEX_BRAH 33
+#define PROP_INDEX_BRAI 34
+#define PROP_INDEX_BRAILLE 34
+#define PROP_INDEX_BUGI 35
+#define PROP_INDEX_BUGINESE 35
+#define PROP_INDEX_BUHD 36
+#define PROP_INDEX_BUHID 36
+#define PROP_INDEX_C 37
+#define PROP_INDEX_OTHER 37
+#define PROP_INDEX_CANS 38
+#define PROP_INDEX_CANADIANABORIGINAL 38
+#define PROP_INDEX_CARI 39
+#define PROP_INDEX_CARIAN 39
+#define PROP_INDEX_CI 40
+#define PROP_INDEX_CASEIGNORABLE 40
+#define PROP_INDEX_CASED 41
+#define PROP_INDEX_AGHB 42
+#define PROP_INDEX_CAUCASIANALBANIAN 42
+#define PROP_INDEX_CONTROL 43
+#define PROP_INDEX_CC 43
+#define PROP_INDEX_CF 44
+#define PROP_INDEX_FORMAT 44
+#define PROP_INDEX_CHAKMA 45
+#define PROP_INDEX_CAKM 45
+#define PROP_INDEX_CHAM 46
+#define PROP_INDEX_CWCF 47
+#define PROP_INDEX_CHANGESWHENCASEFOLDED 47
+#define PROP_INDEX_CWCM 48
+#define PROP_INDEX_CHANGESWHENCASEMAPPED 48
+#define PROP_INDEX_CWL 49
+#define PROP_INDEX_CHANGESWHENLOWERCASED 49
+#define PROP_INDEX_CWT 50
+#define PROP_INDEX_CHANGESWHENTITLECASED 50
+#define PROP_INDEX_CWU 51
+#define PROP_INDEX_CHANGESWHENUPPERCASED 51
+#define PROP_INDEX_CHER 52
+#define PROP_INDEX_CHEROKEE 52
+#define PROP_INDEX_CN 53
+#define PROP_INDEX_UNASSIGNED 53
+#define PROP_INDEX_PRIVATEUSE 54
+#define PROP_INDEX_CO 54
+#define PROP_INDEX_ZYYY 55
+#define PROP_INDEX_COMMON 55
+#define PROP_INDEX_COPT 56
+#define PROP_INDEX_COPTIC 56
+#define PROP_INDEX_QAAC 56
+#define PROP_INDEX_CS 57
+#define PROP_INDEX_SURROGATE 57
+#define PROP_INDEX_XSUX 58
+#define PROP_INDEX_CUNEIFORM 58
+#define PROP_INDEX_CPRT 59
+#define PROP_INDEX_CYPRIOT 59
+#define PROP_INDEX_CYRILLIC 60
+#define PROP_INDEX_CYRL 60
+#define PROP_INDEX_DASH 61
+#define PROP_INDEX_DEFAULTIGNORABLECODEPOINT 62
+#define PROP_INDEX_DI 62
+#define PROP_INDEX_DEP 63
+#define PROP_INDEX_DEPRECATED 63
+#define PROP_INDEX_DSRT 64
+#define PROP_INDEX_DESERET 64
+#define PROP_INDEX_DEVA 65
+#define PROP_INDEX_DEVANAGARI 65
+#define PROP_INDEX_DIACRITIC 66
+#define PROP_INDEX_DIA 66
+#define PROP_INDEX_DOGRA 67
+#define PROP_INDEX_DOGR 67
+#define PROP_INDEX_DUPL 68
+#define PROP_INDEX_DUPLOYAN 68
+#define PROP_INDEX_EGYPTIANHIEROGLYPHS 69
+#define PROP_INDEX_EGYP 69
+#define PROP_INDEX_ELBA 70
+#define PROP_INDEX_ELBASAN 70
+#define PROP_INDEX_ELYM 71
+#define PROP_INDEX_ELYMAIC 71
+#define PROP_INDEX_EMOJI 72
+#define PROP_INDEX_EMOJICOMPONENT 73
+#define PROP_INDEX_EMOJIMODIFIER 74
+#define PROP_INDEX_EMOJIMODIFIERBASE 75
+#define PROP_INDEX_EMOJIPRESENTATION 76
+#define PROP_INDEX_ETHIOPIC 77
+#define PROP_INDEX_ETHI 77
+#define PROP_INDEX_EXTENDEDPICTOGRAPHIC 78
+#define PROP_INDEX_EXT 79
+#define PROP_INDEX_EXTENDER 79
+#define PROP_INDEX_GEORGIAN 80
+#define PROP_INDEX_GEOR 80
+#define PROP_INDEX_GLAG 81
+#define PROP_INDEX_GLAGOLITIC 81
+#define PROP_INDEX_GOTH 82
+#define PROP_INDEX_GOTHIC 82
+#define PROP_INDEX_GRAN 83
+#define PROP_INDEX_GRANTHA 83
+#define PROP_INDEX_GRBASE 84
+#define PROP_INDEX_GRAPHEMEBASE 84
+#define PROP_INDEX_GREXT 85
+#define PROP_INDEX_GRAPHEMEEXTEND 85
+#define PROP_INDEX_GRAPHEMELINK 86
+#define PROP_INDEX_GRLINK 86
+#define PROP_INDEX_GREEK 87
+#define PROP_INDEX_GREK 87
+#define PROP_INDEX_GUJARATI 88
+#define PROP_INDEX_GUJR 88
+#define PROP_INDEX_GUNJALAGONDI 89
+#define PROP_INDEX_GONG 89
+#define PROP_INDEX_GURU 90
+#define PROP_INDEX_GURMUKHI 90
+#define PROP_INDEX_HANI 91
+#define PROP_INDEX_HAN 91
+#define PROP_INDEX_HANG 92
+#define PROP_INDEX_HANGUL 92
+#define PROP_INDEX_HANIFIROHINGYA 93
+#define PROP_INDEX_ROHG 93
+#define PROP_INDEX_HANUNOO 94
+#define PROP_INDEX_HANO 94
+#define PROP_INDEX_HATR 95
+#define PROP_INDEX_HATRAN 95
+#define PROP_INDEX_HEBREW 96
+#define PROP_INDEX_HEBR 96
+#define PROP_INDEX_HEXDIGIT 97
+#define PROP_INDEX_HEX 97
+#define PROP_INDEX_HIRAGANA 98
+#define PROP_INDEX_HIRA 98
+#define PROP_INDEX_HYPHEN 99
+#define PROP_INDEX_IDSB 100
+#define PROP_INDEX_IDSBINARYOPERATOR 100
+#define PROP_INDEX_IDST 101
+#define PROP_INDEX_IDSTRINARYOPERATOR 101
+#define PROP_INDEX_IDCONTINUE 102
+#define PROP_INDEX_IDC 102
+#define PROP_INDEX_IDS 103
+#define PROP_INDEX_IDSTART 103
+#define PROP_INDEX_IDEO 104
+#define PROP_INDEX_IDEOGRAPHIC 104
+#define PROP_INDEX_ARMI 105
+#define PROP_INDEX_IMPERIALARAMAIC 105
+#define PROP_INDEX_ZINH 106
+#define PROP_INDEX_INHERITED 106
+#define PROP_INDEX_QAAI 106
+#define PROP_INDEX_PHLI 107
+#define PROP_INDEX_INSCRIPTIONALPAHLAVI 107
+#define PROP_INDEX_INSCRIPTIONALPARTHIAN 108
+#define PROP_INDEX_PRTI 108
+#define PROP_INDEX_JAVANESE 109
+#define PROP_INDEX_JAVA 109
+#define PROP_INDEX_JOINC 110
+#define PROP_INDEX_JOINCONTROL 110
+#define PROP_INDEX_KAITHI 111
+#define PROP_INDEX_KTHI 111
+#define PROP_INDEX_KNDA 112
+#define PROP_INDEX_KANNADA 112
+#define PROP_INDEX_KATAKANA 113
+#define PROP_INDEX_KANA 113
+#define PROP_INDEX_KAYAHLI 114
+#define PROP_INDEX_KALI 114
+#define PROP_INDEX_KHAROSHTHI 115
+#define PROP_INDEX_KHAR 115
+#define PROP_INDEX_KHMR 116
+#define PROP_INDEX_KHMER 116
+#define PROP_INDEX_KHOJ 117
+#define PROP_INDEX_KHOJKI 117
+#define PROP_INDEX_KHUDAWADI 118
+#define PROP_INDEX_SIND 118
+#define PROP_INDEX_L 119
+#define PROP_INDEX_LETTER 119
+#define PROP_INDEX_LC 120
+#define PROP_INDEX_CASEDLETTER 120
+#define PROP_INDEX_LAO 121
+#define PROP_INDEX_LAOO 121
+#define PROP_INDEX_LATN 122
+#define PROP_INDEX_LATIN 122
+#define PROP_INDEX_LEPC 123
+#define PROP_INDEX_LEPCHA 123
+#define PROP_INDEX_LIMBU 124
+#define PROP_INDEX_LIMB 124
+#define PROP_INDEX_LINA 125
+#define PROP_INDEX_LINEARA 125
+#define PROP_INDEX_LINB 126
+#define PROP_INDEX_LINEARB 126
+#define PROP_INDEX_LISU 127
+#define PROP_INDEX_LOWERCASELETTER 128
+#define PROP_INDEX_LL 128
+#define PROP_INDEX_LM 129
+#define PROP_INDEX_MODIFIERLETTER 129
+#define PROP_INDEX_LO 130
+#define PROP_INDEX_OTHERLETTER 130
+#define PROP_INDEX_LOGICALORDEREXCEPTION 131
+#define PROP_INDEX_LOE 131
+#define PROP_INDEX_LOWERCASE 132
+#define PROP_INDEX_LT 133
+#define PROP_INDEX_TITLECASELETTER 133
+#define PROP_INDEX_UPPERCASELETTER 134
+#define PROP_INDEX_LU 134
+#define PROP_INDEX_LYCI 135
+#define PROP_INDEX_LYCIAN 135
+#define PROP_INDEX_LYDI 136
+#define PROP_INDEX_LYDIAN 136
+#define PROP_INDEX_M 137
+#define PROP_INDEX_COMBININGMARK 137
+#define PROP_INDEX_MARK 137
+#define PROP_INDEX_MAHJ 138
+#define PROP_INDEX_MAHAJANI 138
+#define PROP_INDEX_MAKASAR 139
+#define PROP_INDEX_MAKA 139
+#define PROP_INDEX_MALAYALAM 140
+#define PROP_INDEX_MLYM 140
+#define PROP_INDEX_MAND 141
+#define PROP_INDEX_MANDAIC 141
+#define PROP_INDEX_MANI 142
+#define PROP_INDEX_MANICHAEAN 142
+#define PROP_INDEX_MARC 143
+#define PROP_INDEX_MARCHEN 143
+#define PROP_INDEX_MASARAMGONDI 144
+#define PROP_INDEX_GONM 144
+#define PROP_INDEX_MATH 145
+#define PROP_INDEX_MC 146
+#define PROP_INDEX_SPACINGMARK 146
+#define PROP_INDEX_ENCLOSINGMARK 147
+#define PROP_INDEX_ME 147
+#define PROP_INDEX_MEDEFAIDRIN 148
+#define PROP_INDEX_MEDF 148
+#define PROP_INDEX_MEETEIMAYEK 149
+#define PROP_INDEX_MTEI 149
+#define PROP_INDEX_MENDEKIKAKUI 150
+#define PROP_INDEX_MEND 150
+#define PROP_INDEX_MEROITICCURSIVE 151
+#define PROP_INDEX_MERC 151
+#define PROP_INDEX_MEROITICHIEROGLYPHS 152
+#define PROP_INDEX_MERO 152
+#define PROP_INDEX_PLRD 153
+#define PROP_INDEX_MIAO 153
+#define PROP_INDEX_MN 154
+#define PROP_INDEX_NONSPACINGMARK 154
+#define PROP_INDEX_MODI 155
+#define PROP_INDEX_MONGOLIAN 156
+#define PROP_INDEX_MONG 156
+#define PROP_INDEX_MRO 157
+#define PROP_INDEX_MROO 157
+#define PROP_INDEX_MULT 158
+#define PROP_INDEX_MULTANI 158
+#define PROP_INDEX_MYANMAR 159
+#define PROP_INDEX_MYMR 159
+#define PROP_INDEX_NUMBER 160
+#define PROP_INDEX_N 160
+#define PROP_INDEX_NABATAEAN 161
+#define PROP_INDEX_NBAT 161
+#define PROP_INDEX_NAND 162
+#define PROP_INDEX_NANDINAGARI 162
+#define PROP_INDEX_DECIMALNUMBER 163
+#define PROP_INDEX_ND 163
+#define PROP_INDEX_TALU 164
+#define PROP_INDEX_NEWTAILUE 164
+#define PROP_INDEX_NEWA 165
+#define PROP_INDEX_NKO 166
+#define PROP_INDEX_NKOO 166
+#define PROP_INDEX_LETTERNUMBER 167
+#define PROP_INDEX_NL 167
+#define PROP_INDEX_OTHERNUMBER 168
+#define PROP_INDEX_NO 168
+#define PROP_INDEX_NONCHARACTERCODEPOINT 169
+#define PROP_INDEX_NCHAR 169
+#define PROP_INDEX_NSHU 170
+#define PROP_INDEX_NUSHU 170
+#define PROP_INDEX_HMNP 171
+#define PROP_INDEX_NYIAKENGPUACHUEHMONG 171
+#define PROP_INDEX_OGHAM 172
+#define PROP_INDEX_OGAM 172
+#define PROP_INDEX_OLCK 173
+#define PROP_INDEX_OLCHIKI 173
+#define PROP_INDEX_HUNG 174
+#define PROP_INDEX_OLDHUNGARIAN 174
+#define PROP_INDEX_ITAL 175
+#define PROP_INDEX_OLDITALIC 175
+#define PROP_INDEX_NARB 176
+#define PROP_INDEX_OLDNORTHARABIAN 176
+#define PROP_INDEX_OLDPERMIC 177
+#define PROP_INDEX_PERM 177
+#define PROP_INDEX_OLDPERSIAN 178
+#define PROP_INDEX_XPEO 178
+#define PROP_INDEX_SOGO 179
+#define PROP_INDEX_OLDSOGDIAN 179
+#define PROP_INDEX_SARB 180
+#define PROP_INDEX_OLDSOUTHARABIAN 180
+#define PROP_INDEX_OLDTURKIC 181
+#define PROP_INDEX_ORKH 181
+#define PROP_INDEX_ORYA 182
+#define PROP_INDEX_ORIYA 182
+#define PROP_INDEX_OSAGE 183
+#define PROP_INDEX_OSGE 183
+#define PROP_INDEX_OSMANYA 184
+#define PROP_INDEX_OSMA 184
+#define PROP_INDEX_OTHERALPHABETIC 185
+#define PROP_INDEX_OALPHA 185
+#define PROP_INDEX_ODI 186
+#define PROP_INDEX_OTHERDEFAULTIGNORABLECODEPOINT 186
+#define PROP_INDEX_OGREXT 187
+#define PROP_INDEX_OTHERGRAPHEMEEXTEND 187
+#define PROP_INDEX_OIDC 188
+#define PROP_INDEX_OTHERIDCONTINUE 188
+#define PROP_INDEX_OTHERIDSTART 189
+#define PROP_INDEX_OIDS 189
+#define PROP_INDEX_OTHERLOWERCASE 190
+#define PROP_INDEX_OLOWER 190
+#define PROP_INDEX_OTHERMATH 191
+#define PROP_INDEX_OMATH 191
+#define PROP_INDEX_OTHERUPPERCASE 192
+#define PROP_INDEX_OUPPER 192
+#define PROP_INDEX_P 193
+#define PROP_INDEX_PUNCTUATION 193
+#define PROP_INDEX_PAHAWHHMONG 194
+#define PROP_INDEX_HMNG 194
+#define PROP_INDEX_PALMYRENE 195
+#define PROP_INDEX_PALM 195
+#define PROP_INDEX_PATTERNSYNTAX 196
+#define PROP_INDEX_PATSYN 196
+#define PROP_INDEX_PATWS 197
+#define PROP_INDEX_PATTERNWHITESPACE 197
+#define PROP_INDEX_PAUCINHAU 198
+#define PROP_INDEX_PAUC 198
+#define PROP_INDEX_CONNECTORPUNCTUATION 199
+#define PROP_INDEX_PC 199
+#define PROP_INDEX_DASHPUNCTUATION 200
+#define PROP_INDEX_PD 200
+#define PROP_INDEX_PE 201
+#define PROP_INDEX_CLOSEPUNCTUATION 201
+#define PROP_INDEX_FINALPUNCTUATION 202
+#define PROP_INDEX_PF 202
+#define PROP_INDEX_PHAG 203
+#define PROP_INDEX_PHAGSPA 203
+#define PROP_INDEX_PHOENICIAN 204
+#define PROP_INDEX_PHNX 204
+#define PROP_INDEX_PI 205
+#define PROP_INDEX_INITIALPUNCTUATION 205
+#define PROP_INDEX_OTHERPUNCTUATION 206
+#define PROP_INDEX_PO 206
+#define PROP_INDEX_PREPENDEDCONCATENATIONMARK 207
+#define PROP_INDEX_PCM 207
+#define PROP_INDEX_PS 208
+#define PROP_INDEX_OPENPUNCTUATION 208
+#define PROP_INDEX_PHLP 209
+#define PROP_INDEX_PSALTERPAHLAVI 209
+#define PROP_INDEX_QUOTATIONMARK 210
+#define PROP_INDEX_QMARK 210
+#define PROP_INDEX_RADICAL 211
+#define PROP_INDEX_RI 212
+#define PROP_INDEX_REGIONALINDICATOR 212
+#define PROP_INDEX_REJANG 213
+#define PROP_INDEX_RJNG 213
+#define PROP_INDEX_RUNIC 214
+#define PROP_INDEX_RUNR 214
+#define PROP_INDEX_S 215
+#define PROP_INDEX_SYMBOL 215
+#define PROP_INDEX_SAMARITAN 216
+#define PROP_INDEX_SAMR 216
+#define PROP_INDEX_SAURASHTRA 217
+#define PROP_INDEX_SAUR 217
+#define PROP_INDEX_SC 218
+#define PROP_INDEX_CURRENCYSYMBOL 218
+#define PROP_INDEX_SENTENCETERMINAL 219
+#define PROP_INDEX_STERM 219
+#define PROP_INDEX_SHARADA 220
+#define PROP_INDEX_SHRD 220
+#define PROP_INDEX_SHAVIAN 221
+#define PROP_INDEX_SHAW 221
+#define PROP_INDEX_SIDDHAM 222
+#define PROP_INDEX_SIDD 222
+#define PROP_INDEX_SIGNWRITING 223
+#define PROP_INDEX_SGNW 223
+#define PROP_INDEX_SINH 224
+#define PROP_INDEX_SINHALA 224
+#define PROP_INDEX_SK 225
+#define PROP_INDEX_MODIFIERSYMBOL 225
+#define PROP_INDEX_MATHSYMBOL 226
+#define PROP_INDEX_SM 226
+#define PROP_INDEX_SO 227
+#define PROP_INDEX_OTHERSYMBOL 227
+#define PROP_INDEX_SD 228
+#define PROP_INDEX_SOFTDOTTED 228
+#define PROP_INDEX_SOGD 229
+#define PROP_INDEX_SOGDIAN 229
+#define PROP_INDEX_SORASOMPENG 230
+#define PROP_INDEX_SORA 230
+#define PROP_INDEX_SOYO 231
+#define PROP_INDEX_SOYOMBO 231
+#define PROP_INDEX_SUND 232
+#define PROP_INDEX_SUNDANESE 232
+#define PROP_INDEX_SYLO 233
+#define PROP_INDEX_SYLOTINAGRI 233
+#define PROP_INDEX_SYRC 234
+#define PROP_INDEX_SYRIAC 234
+#define PROP_INDEX_TGLG 235
+#define PROP_INDEX_TAGALOG 235
+#define PROP_INDEX_TAGBANWA 236
+#define PROP_INDEX_TAGB 236
+#define PROP_INDEX_TAILE 237
+#define PROP_INDEX_TALE 237
+#define PROP_INDEX_TAITHAM 238
+#define PROP_INDEX_LANA 238
+#define PROP_INDEX_TAIVIET 239
+#define PROP_INDEX_TAVT 239
+#define PROP_INDEX_TAKRI 240
+#define PROP_INDEX_TAKR 240
+#define PROP_INDEX_TAMIL 241
+#define PROP_INDEX_TAML 241
+#define PROP_INDEX_TANG 242
+#define PROP_INDEX_TANGUT 242
+#define PROP_INDEX_TELUGU 243
+#define PROP_INDEX_TELU 243
+#define PROP_INDEX_TERM 244
+#define PROP_INDEX_TERMINALPUNCTUATION 244
+#define PROP_INDEX_THAA 245
+#define PROP_INDEX_THAANA 245
+#define PROP_INDEX_THAI 246
+#define PROP_INDEX_TIBT 247
+#define PROP_INDEX_TIBETAN 247
+#define PROP_INDEX_TFNG 248
+#define PROP_INDEX_TIFINAGH 248
+#define PROP_INDEX_TIRHUTA 249
+#define PROP_INDEX_TIRH 249
+#define PROP_INDEX_UGAR 250
+#define PROP_INDEX_UGARITIC 250
+#define PROP_INDEX_UNIFIEDIDEOGRAPH 251
+#define PROP_INDEX_UIDEO 251
+#define PROP_INDEX_ZZZZ 252
+#define PROP_INDEX_UNKNOWN 252
+#define PROP_INDEX_UPPERCASE 253
+#define PROP_INDEX_VAII 254
+#define PROP_INDEX_VAI 254
+#define PROP_INDEX_VARIATIONSELECTOR 255
+#define PROP_INDEX_VS 255
+#define PROP_INDEX_WCHO 256
+#define PROP_INDEX_WANCHO 256
+#define PROP_INDEX_WARANGCITI 257
+#define PROP_INDEX_WARA 257
+#define PROP_INDEX_WHITESPACE 258
+#define PROP_INDEX_WSPACE 258
+#define PROP_INDEX_XIDC 259
+#define PROP_INDEX_XIDCONTINUE 259
+#define PROP_INDEX_XIDS 260
+#define PROP_INDEX_XIDSTART 260
+#define PROP_INDEX_YI 261
+#define PROP_INDEX_YIII 261
+#define PROP_INDEX_SEPARATOR 262
+#define PROP_INDEX_Z 262
+#define PROP_INDEX_ZANABAZARSQUARE 263
+#define PROP_INDEX_ZANB 263
+#define PROP_INDEX_ZL 264
+#define PROP_INDEX_LINESEPARATOR 264
+#define PROP_INDEX_ZP 265
+#define PROP_INDEX_PARAGRAPHSEPARATOR 265
+#define PROP_INDEX_ZS 266
+#define PROP_INDEX_SPACESEPARATOR 266
+#define PROP_INDEX_INBASICLATIN 267
+#define PROP_INDEX_INLATIN1SUPPLEMENT 268
+#define PROP_INDEX_INLATINEXTENDEDA 269
+#define PROP_INDEX_INLATINEXTENDEDB 270
+#define PROP_INDEX_INIPAEXTENSIONS 271
+#define PROP_INDEX_INSPACINGMODIFIERLETTERS 272
+#define PROP_INDEX_INCOMBININGDIACRITICALMARKS 273
+#define PROP_INDEX_INGREEKANDCOPTIC 274
+#define PROP_INDEX_INCYRILLIC 275
+#define PROP_INDEX_INCYRILLICSUPPLEMENT 276
+#define PROP_INDEX_INARMENIAN 277
+#define PROP_INDEX_INHEBREW 278
+#define PROP_INDEX_INARABIC 279
+#define PROP_INDEX_INSYRIAC 280
+#define PROP_INDEX_INARABICSUPPLEMENT 281
+#define PROP_INDEX_INTHAANA 282
+#define PROP_INDEX_INNKO 283
+#define PROP_INDEX_INSAMARITAN 284
+#define PROP_INDEX_INMANDAIC 285
+#define PROP_INDEX_INSYRIACSUPPLEMENT 286
+#define PROP_INDEX_INARABICEXTENDEDA 287
+#define PROP_INDEX_INDEVANAGARI 288
+#define PROP_INDEX_INBENGALI 289
+#define PROP_INDEX_INGURMUKHI 290
+#define PROP_INDEX_INGUJARATI 291
+#define PROP_INDEX_INORIYA 292
+#define PROP_INDEX_INTAMIL 293
+#define PROP_INDEX_INTELUGU 294
+#define PROP_INDEX_INKANNADA 295
+#define PROP_INDEX_INMALAYALAM 296
+#define PROP_INDEX_INSINHALA 297
+#define PROP_INDEX_INTHAI 298
+#define PROP_INDEX_INLAO 299
+#define PROP_INDEX_INTIBETAN 300
+#define PROP_INDEX_INMYANMAR 301
+#define PROP_INDEX_INGEORGIAN 302
+#define PROP_INDEX_INHANGULJAMO 303
+#define PROP_INDEX_INETHIOPIC 304
+#define PROP_INDEX_INETHIOPICSUPPLEMENT 305
+#define PROP_INDEX_INCHEROKEE 306
+#define PROP_INDEX_INUNIFIEDCANADIANABORIGINALSYLLABICS 307
+#define PROP_INDEX_INOGHAM 308
+#define PROP_INDEX_INRUNIC 309
+#define PROP_INDEX_INTAGALOG 310
+#define PROP_INDEX_INHANUNOO 311
+#define PROP_INDEX_INBUHID 312
+#define PROP_INDEX_INTAGBANWA 313
+#define PROP_INDEX_INKHMER 314
+#define PROP_INDEX_INMONGOLIAN 315
+#define PROP_INDEX_INUNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED 316
+#define PROP_INDEX_INLIMBU 317
+#define PROP_INDEX_INTAILE 318
+#define PROP_INDEX_INNEWTAILUE 319
+#define PROP_INDEX_INKHMERSYMBOLS 320
+#define PROP_INDEX_INBUGINESE 321
+#define PROP_INDEX_INTAITHAM 322
+#define PROP_INDEX_INCOMBININGDIACRITICALMARKSEXTENDED 323
+#define PROP_INDEX_INBALINESE 324
+#define PROP_INDEX_INSUNDANESE 325
+#define PROP_INDEX_INBATAK 326
+#define PROP_INDEX_INLEPCHA 327
+#define PROP_INDEX_INOLCHIKI 328
+#define PROP_INDEX_INCYRILLICEXTENDEDC 329
+#define PROP_INDEX_INGEORGIANEXTENDED 330
+#define PROP_INDEX_INSUNDANESESUPPLEMENT 331
+#define PROP_INDEX_INVEDICEXTENSIONS 332
+#define PROP_INDEX_INPHONETICEXTENSIONS 333
+#define PROP_INDEX_INPHONETICEXTENSIONSSUPPLEMENT 334
+#define PROP_INDEX_INCOMBININGDIACRITICALMARKSSUPPLEMENT 335
+#define PROP_INDEX_INLATINEXTENDEDADDITIONAL 336
+#define PROP_INDEX_INGREEKEXTENDED 337
+#define PROP_INDEX_INGENERALPUNCTUATION 338
+#define PROP_INDEX_INSUPERSCRIPTSANDSUBSCRIPTS 339
+#define PROP_INDEX_INCURRENCYSYMBOLS 340
+#define PROP_INDEX_INCOMBININGDIACRITICALMARKSFORSYMBOLS 341
+#define PROP_INDEX_INLETTERLIKESYMBOLS 342
+#define PROP_INDEX_INNUMBERFORMS 343
+#define PROP_INDEX_INARROWS 344
+#define PROP_INDEX_INMATHEMATICALOPERATORS 345
+#define PROP_INDEX_INMISCELLANEOUSTECHNICAL 346
+#define PROP_INDEX_INCONTROLPICTURES 347
+#define PROP_INDEX_INOPTICALCHARACTERRECOGNITION 348
+#define PROP_INDEX_INENCLOSEDALPHANUMERICS 349
+#define PROP_INDEX_INBOXDRAWING 350
+#define PROP_INDEX_INBLOCKELEMENTS 351
+#define PROP_INDEX_INGEOMETRICSHAPES 352
+#define PROP_INDEX_INMISCELLANEOUSSYMBOLS 353
+#define PROP_INDEX_INDINGBATS 354
+#define PROP_INDEX_INMISCELLANEOUSMATHEMATICALSYMBOLSA 355
+#define PROP_INDEX_INSUPPLEMENTALARROWSA 356
+#define PROP_INDEX_INBRAILLEPATTERNS 357
+#define PROP_INDEX_INSUPPLEMENTALARROWSB 358
+#define PROP_INDEX_INMISCELLANEOUSMATHEMATICALSYMBOLSB 359
+#define PROP_INDEX_INSUPPLEMENTALMATHEMATICALOPERATORS 360
+#define PROP_INDEX_INMISCELLANEOUSSYMBOLSANDARROWS 361
+#define PROP_INDEX_INGLAGOLITIC 362
+#define PROP_INDEX_INLATINEXTENDEDC 363
+#define PROP_INDEX_INCOPTIC 364
+#define PROP_INDEX_INGEORGIANSUPPLEMENT 365
+#define PROP_INDEX_INTIFINAGH 366
+#define PROP_INDEX_INETHIOPICEXTENDED 367
+#define PROP_INDEX_INCYRILLICEXTENDEDA 368
+#define PROP_INDEX_INSUPPLEMENTALPUNCTUATION 369
+#define PROP_INDEX_INCJKRADICALSSUPPLEMENT 370
+#define PROP_INDEX_INKANGXIRADICALS 371
+#define PROP_INDEX_INIDEOGRAPHICDESCRIPTIONCHARACTERS 372
+#define PROP_INDEX_INCJKSYMBOLSANDPUNCTUATION 373
+#define PROP_INDEX_INHIRAGANA 374
+#define PROP_INDEX_INKATAKANA 375
+#define PROP_INDEX_INBOPOMOFO 376
+#define PROP_INDEX_INHANGULCOMPATIBILITYJAMO 377
+#define PROP_INDEX_INKANBUN 378
+#define PROP_INDEX_INBOPOMOFOEXTENDED 379
+#define PROP_INDEX_INCJKSTROKES 380
+#define PROP_INDEX_INKATAKANAPHONETICEXTENSIONS 381
+#define PROP_INDEX_INENCLOSEDCJKLETTERSANDMONTHS 382
+#define PROP_INDEX_INCJKCOMPATIBILITY 383
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIONA 384
+#define PROP_INDEX_INYIJINGHEXAGRAMSYMBOLS 385
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHS 386
+#define PROP_INDEX_INYISYLLABLES 387
+#define PROP_INDEX_INYIRADICALS 388
+#define PROP_INDEX_INLISU 389
+#define PROP_INDEX_INVAI 390
+#define PROP_INDEX_INCYRILLICEXTENDEDB 391
+#define PROP_INDEX_INBAMUM 392
+#define PROP_INDEX_INMODIFIERTONELETTERS 393
+#define PROP_INDEX_INLATINEXTENDEDD 394
+#define PROP_INDEX_INSYLOTINAGRI 395
+#define PROP_INDEX_INCOMMONINDICNUMBERFORMS 396
+#define PROP_INDEX_INPHAGSPA 397
+#define PROP_INDEX_INSAURASHTRA 398
+#define PROP_INDEX_INDEVANAGARIEXTENDED 399
+#define PROP_INDEX_INKAYAHLI 400
+#define PROP_INDEX_INREJANG 401
+#define PROP_INDEX_INHANGULJAMOEXTENDEDA 402
+#define PROP_INDEX_INJAVANESE 403
+#define PROP_INDEX_INMYANMAREXTENDEDB 404
+#define PROP_INDEX_INCHAM 405
+#define PROP_INDEX_INMYANMAREXTENDEDA 406
+#define PROP_INDEX_INTAIVIET 407
+#define PROP_INDEX_INMEETEIMAYEKEXTENSIONS 408
+#define PROP_INDEX_INETHIOPICEXTENDEDA 409
+#define PROP_INDEX_INLATINEXTENDEDE 410
+#define PROP_INDEX_INCHEROKEESUPPLEMENT 411
+#define PROP_INDEX_INMEETEIMAYEK 412
+#define PROP_INDEX_INHANGULSYLLABLES 413
+#define PROP_INDEX_INHANGULJAMOEXTENDEDB 414
+#define PROP_INDEX_INHIGHSURROGATES 415
+#define PROP_INDEX_INHIGHPRIVATEUSESURROGATES 416
+#define PROP_INDEX_INLOWSURROGATES 417
+#define PROP_INDEX_INPRIVATEUSEAREA 418
+#define PROP_INDEX_INCJKCOMPATIBILITYIDEOGRAPHS 419
+#define PROP_INDEX_INALPHABETICPRESENTATIONFORMS 420
+#define PROP_INDEX_INARABICPRESENTATIONFORMSA 421
+#define PROP_INDEX_INVARIATIONSELECTORS 422
+#define PROP_INDEX_INVERTICALFORMS 423
+#define PROP_INDEX_INCOMBININGHALFMARKS 424
+#define PROP_INDEX_INCJKCOMPATIBILITYFORMS 425
+#define PROP_INDEX_INSMALLFORMVARIANTS 426
+#define PROP_INDEX_INARABICPRESENTATIONFORMSB 427
+#define PROP_INDEX_INHALFWIDTHANDFULLWIDTHFORMS 428
+#define PROP_INDEX_INSPECIALS 429
+#define PROP_INDEX_INLINEARBSYLLABARY 430
+#define PROP_INDEX_INLINEARBIDEOGRAMS 431
+#define PROP_INDEX_INAEGEANNUMBERS 432
+#define PROP_INDEX_INANCIENTGREEKNUMBERS 433
+#define PROP_INDEX_INANCIENTSYMBOLS 434
+#define PROP_INDEX_INPHAISTOSDISC 435
+#define PROP_INDEX_INLYCIAN 436
+#define PROP_INDEX_INCARIAN 437
+#define PROP_INDEX_INCOPTICEPACTNUMBERS 438
+#define PROP_INDEX_INOLDITALIC 439
+#define PROP_INDEX_INGOTHIC 440
+#define PROP_INDEX_INOLDPERMIC 441
+#define PROP_INDEX_INUGARITIC 442
+#define PROP_INDEX_INOLDPERSIAN 443
+#define PROP_INDEX_INDESERET 444
+#define PROP_INDEX_INSHAVIAN 445
+#define PROP_INDEX_INOSMANYA 446
+#define PROP_INDEX_INOSAGE 447
+#define PROP_INDEX_INELBASAN 448
+#define PROP_INDEX_INCAUCASIANALBANIAN 449
+#define PROP_INDEX_INLINEARA 450
+#define PROP_INDEX_INCYPRIOTSYLLABARY 451
+#define PROP_INDEX_INIMPERIALARAMAIC 452
+#define PROP_INDEX_INPALMYRENE 453
+#define PROP_INDEX_INNABATAEAN 454
+#define PROP_INDEX_INHATRAN 455
+#define PROP_INDEX_INPHOENICIAN 456
+#define PROP_INDEX_INLYDIAN 457
+#define PROP_INDEX_INMEROITICHIEROGLYPHS 458
+#define PROP_INDEX_INMEROITICCURSIVE 459
+#define PROP_INDEX_INKHAROSHTHI 460
+#define PROP_INDEX_INOLDSOUTHARABIAN 461
+#define PROP_INDEX_INOLDNORTHARABIAN 462
+#define PROP_INDEX_INMANICHAEAN 463
+#define PROP_INDEX_INAVESTAN 464
+#define PROP_INDEX_ININSCRIPTIONALPARTHIAN 465
+#define PROP_INDEX_ININSCRIPTIONALPAHLAVI 466
+#define PROP_INDEX_INPSALTERPAHLAVI 467
+#define PROP_INDEX_INOLDTURKIC 468
+#define PROP_INDEX_INOLDHUNGARIAN 469
+#define PROP_INDEX_INHANIFIROHINGYA 470
+#define PROP_INDEX_INRUMINUMERALSYMBOLS 471
+#define PROP_INDEX_INOLDSOGDIAN 472
+#define PROP_INDEX_INSOGDIAN 473
+#define PROP_INDEX_INELYMAIC 474
+#define PROP_INDEX_INBRAHMI 475
+#define PROP_INDEX_INKAITHI 476
+#define PROP_INDEX_INSORASOMPENG 477
+#define PROP_INDEX_INCHAKMA 478
+#define PROP_INDEX_INMAHAJANI 479
+#define PROP_INDEX_INSHARADA 480
+#define PROP_INDEX_INSINHALAARCHAICNUMBERS 481
+#define PROP_INDEX_INKHOJKI 482
+#define PROP_INDEX_INMULTANI 483
+#define PROP_INDEX_INKHUDAWADI 484
+#define PROP_INDEX_INGRANTHA 485
+#define PROP_INDEX_INNEWA 486
+#define PROP_INDEX_INTIRHUTA 487
+#define PROP_INDEX_INSIDDHAM 488
+#define PROP_INDEX_INMODI 489
+#define PROP_INDEX_INMONGOLIANSUPPLEMENT 490
+#define PROP_INDEX_INTAKRI 491
+#define PROP_INDEX_INAHOM 492
+#define PROP_INDEX_INDOGRA 493
+#define PROP_INDEX_INWARANGCITI 494
+#define PROP_INDEX_INNANDINAGARI 495
+#define PROP_INDEX_INZANABAZARSQUARE 496
+#define PROP_INDEX_INSOYOMBO 497
+#define PROP_INDEX_INPAUCINHAU 498
+#define PROP_INDEX_INBHAIKSUKI 499
+#define PROP_INDEX_INMARCHEN 500
+#define PROP_INDEX_INMASARAMGONDI 501
+#define PROP_INDEX_INGUNJALAGONDI 502
+#define PROP_INDEX_INMAKASAR 503
+#define PROP_INDEX_INTAMILSUPPLEMENT 504
+#define PROP_INDEX_INCUNEIFORM 505
+#define PROP_INDEX_INCUNEIFORMNUMBERSANDPUNCTUATION 506
+#define PROP_INDEX_INEARLYDYNASTICCUNEIFORM 507
+#define PROP_INDEX_INEGYPTIANHIEROGLYPHS 508
+#define PROP_INDEX_INEGYPTIANHIEROGLYPHFORMATCONTROLS 509
+#define PROP_INDEX_INANATOLIANHIEROGLYPHS 510
+#define PROP_INDEX_INBAMUMSUPPLEMENT 511
+#define PROP_INDEX_INMRO 512
+#define PROP_INDEX_INBASSAVAH 513
+#define PROP_INDEX_INPAHAWHHMONG 514
+#define PROP_INDEX_INMEDEFAIDRIN 515
+#define PROP_INDEX_INMIAO 516
+#define PROP_INDEX_INIDEOGRAPHICSYMBOLSANDPUNCTUATION 517
+#define PROP_INDEX_INTANGUT 518
+#define PROP_INDEX_INTANGUTCOMPONENTS 519
+#define PROP_INDEX_INKANASUPPLEMENT 520
+#define PROP_INDEX_INKANAEXTENDEDA 521
+#define PROP_INDEX_INSMALLKANAEXTENSION 522
+#define PROP_INDEX_INNUSHU 523
+#define PROP_INDEX_INDUPLOYAN 524
+#define PROP_INDEX_INSHORTHANDFORMATCONTROLS 525
+#define PROP_INDEX_INBYZANTINEMUSICALSYMBOLS 526
+#define PROP_INDEX_INMUSICALSYMBOLS 527
+#define PROP_INDEX_INANCIENTGREEKMUSICALNOTATION 528
+#define PROP_INDEX_INMAYANNUMERALS 529
+#define PROP_INDEX_INTAIXUANJINGSYMBOLS 530
+#define PROP_INDEX_INCOUNTINGRODNUMERALS 531
+#define PROP_INDEX_INMATHEMATICALALPHANUMERICSYMBOLS 532
+#define PROP_INDEX_INSUTTONSIGNWRITING 533
+#define PROP_INDEX_INGLAGOLITICSUPPLEMENT 534
+#define PROP_INDEX_INNYIAKENGPUACHUEHMONG 535
+#define PROP_INDEX_INWANCHO 536
+#define PROP_INDEX_INMENDEKIKAKUI 537
+#define PROP_INDEX_INADLAM 538
+#define PROP_INDEX_ININDICSIYAQNUMBERS 539
+#define PROP_INDEX_INOTTOMANSIYAQNUMBERS 540
+#define PROP_INDEX_INARABICMATHEMATICALALPHABETICSYMBOLS 541
+#define PROP_INDEX_INMAHJONGTILES 542
+#define PROP_INDEX_INDOMINOTILES 543
+#define PROP_INDEX_INPLAYINGCARDS 544
+#define PROP_INDEX_INENCLOSEDALPHANUMERICSUPPLEMENT 545
+#define PROP_INDEX_INENCLOSEDIDEOGRAPHICSUPPLEMENT 546
+#define PROP_INDEX_INMISCELLANEOUSSYMBOLSANDPICTOGRAPHS 547
+#define PROP_INDEX_INEMOTICONS 548
+#define PROP_INDEX_INORNAMENTALDINGBATS 549
+#define PROP_INDEX_INTRANSPORTANDMAPSYMBOLS 550
+#define PROP_INDEX_INALCHEMICALSYMBOLS 551
+#define PROP_INDEX_INGEOMETRICSHAPESEXTENDED 552
+#define PROP_INDEX_INSUPPLEMENTALARROWSC 553
+#define PROP_INDEX_INSUPPLEMENTALSYMBOLSANDPICTOGRAPHS 554
+#define PROP_INDEX_INCHESSSYMBOLS 555
+#define PROP_INDEX_INSYMBOLSANDPICTOGRAPHSEXTENDEDA 556
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIONB 557
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIONC 558
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIOND 559
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIONE 560
+#define PROP_INDEX_INCJKUNIFIEDIDEOGRAPHSEXTENSIONF 561
+#define PROP_INDEX_INCJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT 562
+#define PROP_INDEX_INTAGS 563
+#define PROP_INDEX_INVARIATIONSELECTORSSUPPLEMENT 564
+#define PROP_INDEX_INSUPPLEMENTARYPRIVATEUSEAREAA 565
+#define PROP_INDEX_INSUPPLEMENTARYPRIVATEUSEAREAB 566
+#define PROP_INDEX_INNOBLOCK 567
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data_posix.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data_posix.c
new file mode 100644
index 000000000..e299e85de
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_property_data_posix.c
@@ -0,0 +1,5347 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -T -C -c -t -j1 -L ANSI-C --ignore-case --pic -Q unicode_prop_name_pool -N unicode_lookup_property_name --output-file gperf2.tmp unicode_property_data_posix.gperf */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+
+
+/* Generated by make_unicode_property_data.py. */
+
+
+/* PROPERTY: 'NEWLINE': POSIX [[:NEWLINE:]] */
+static const OnigCodePoint
+CR_NEWLINE[] = { 1,
+0x000a, 0x000a,
+}; /* END of CR_NEWLINE */
+
+/* PROPERTY: 'Alpha': POSIX [[:Alpha:]] */
+static const OnigCodePoint
+CR_Alpha[] = { 679,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0345, 0x0345,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05b0, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0657,
+0x0659, 0x065f,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06e1, 0x06e8,
+0x06ed, 0x06ef,
+0x06fa, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x073f,
+0x074d, 0x07b1,
+0x07ca, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0817,
+0x081a, 0x082c,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d4, 0x08df,
+0x08e3, 0x08e9,
+0x08f0, 0x093b,
+0x093d, 0x094c,
+0x094e, 0x0950,
+0x0955, 0x0963,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09ce, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09f0, 0x09f1,
+0x09fc, 0x09fc,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4c,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a70, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0af9, 0x0afc,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0c00, 0x0c03,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4c,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccc,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e46,
+0x0e4d, 0x0e4d,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb9,
+0x0ebb, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ecd, 0x0ecd,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f81,
+0x0f88, 0x0f97,
+0x0f99, 0x0fbc,
+0x1000, 0x1036,
+0x1038, 0x1038,
+0x103b, 0x103f,
+0x1050, 0x108f,
+0x109a, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1713,
+0x1720, 0x1733,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17b3,
+0x17b6, 0x17c8,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x1938,
+0x1950, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a61, 0x1a74,
+0x1aa7, 0x1aa7,
+0x1b00, 0x1b33,
+0x1b35, 0x1b43,
+0x1b45, 0x1b4b,
+0x1b80, 0x1ba9,
+0x1bac, 0x1baf,
+0x1bba, 0x1be5,
+0x1be7, 0x1bf1,
+0x1c00, 0x1c36,
+0x1c4d, 0x1c4f,
+0x1c5a, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1de7, 0x1df4,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa61f,
+0xa62a, 0xa62b,
+0xa640, 0xa66e,
+0xa674, 0xa67b,
+0xa67f, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa805,
+0xa807, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c3,
+0xa8c5, 0xa8c5,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa8ff,
+0xa90a, 0xa92a,
+0xa930, 0xa952,
+0xa960, 0xa97c,
+0xa980, 0xa9b2,
+0xa9b4, 0xa9bf,
+0xa9cf, 0xa9cf,
+0xa9e0, 0xa9ef,
+0xa9fa, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa60, 0xaa76,
+0xaa7a, 0xaabe,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf5,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11000, 0x11045,
+0x11082, 0x110b8,
+0x110d0, 0x110e8,
+0x11100, 0x11132,
+0x11144, 0x11146,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11180, 0x111bf,
+0x111c1, 0x111c4,
+0x111da, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11234,
+0x11237, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112e8,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134c,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11400, 0x11441,
+0x11443, 0x11445,
+0x11447, 0x1144a,
+0x1145f, 0x1145f,
+0x11480, 0x114c1,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x11580, 0x115b5,
+0x115b8, 0x115be,
+0x115d8, 0x115dd,
+0x11600, 0x1163e,
+0x11640, 0x11640,
+0x11644, 0x11644,
+0x11680, 0x116b5,
+0x116b8, 0x116b8,
+0x11700, 0x1171a,
+0x1171d, 0x1172a,
+0x11800, 0x11838,
+0x118a0, 0x118df,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119df,
+0x119e1, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a32,
+0x11a35, 0x11a3e,
+0x11a50, 0x11a97,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c3e,
+0x11c40, 0x11c40,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d41,
+0x11d43, 0x11d43,
+0x11d46, 0x11d47,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d96,
+0x11d98, 0x11d98,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9e, 0x1bc9e,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e947, 0x1e947,
+0x1e94b, 0x1e94b,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Alpha */
+
+/* PROPERTY: 'Blank': POSIX [[:Blank:]] */
+static const OnigCodePoint
+CR_Blank[] = { 8,
+0x0009, 0x0009,
+0x0020, 0x0020,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Blank */
+
+/* PROPERTY: 'Cntrl': POSIX [[:Cntrl:]] */
+static const OnigCodePoint
+CR_Cntrl[] = { 2,
+0x0000, 0x001f,
+0x007f, 0x009f,
+}; /* END of CR_Cntrl */
+
+/* PROPERTY: 'Digit': POSIX [[:Digit:]] */
+static const OnigCodePoint
+CR_Digit[] = { 59,
+0x0030, 0x0039,
+0x0660, 0x0669,
+0x06f0, 0x06f9,
+0x07c0, 0x07c9,
+0x0966, 0x096f,
+0x09e6, 0x09ef,
+0x0a66, 0x0a6f,
+0x0ae6, 0x0aef,
+0x0b66, 0x0b6f,
+0x0be6, 0x0bef,
+0x0c66, 0x0c6f,
+0x0ce6, 0x0cef,
+0x0d66, 0x0d6f,
+0x0de6, 0x0def,
+0x0e50, 0x0e59,
+0x0ed0, 0x0ed9,
+0x0f20, 0x0f29,
+0x1040, 0x1049,
+0x1090, 0x1099,
+0x17e0, 0x17e9,
+0x1810, 0x1819,
+0x1946, 0x194f,
+0x19d0, 0x19d9,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1b50, 0x1b59,
+0x1bb0, 0x1bb9,
+0x1c40, 0x1c49,
+0x1c50, 0x1c59,
+0xa620, 0xa629,
+0xa8d0, 0xa8d9,
+0xa900, 0xa909,
+0xa9d0, 0xa9d9,
+0xa9f0, 0xa9f9,
+0xaa50, 0xaa59,
+0xabf0, 0xabf9,
+0xff10, 0xff19,
+0x104a0, 0x104a9,
+0x10d30, 0x10d39,
+0x11066, 0x1106f,
+0x110f0, 0x110f9,
+0x11136, 0x1113f,
+0x111d0, 0x111d9,
+0x112f0, 0x112f9,
+0x11450, 0x11459,
+0x114d0, 0x114d9,
+0x11650, 0x11659,
+0x116c0, 0x116c9,
+0x11730, 0x11739,
+0x118e0, 0x118e9,
+0x11c50, 0x11c59,
+0x11d50, 0x11d59,
+0x11da0, 0x11da9,
+0x16a60, 0x16a69,
+0x16b50, 0x16b59,
+0x1d7ce, 0x1d7ff,
+0x1e140, 0x1e149,
+0x1e2f0, 0x1e2f9,
+0x1e950, 0x1e959,
+}; /* END of CR_Digit */
+
+/* PROPERTY: 'Graph': POSIX [[:Graph:]] */
+static const OnigCodePoint
+CR_Graph[] = { 671,
+0x0021, 0x007e,
+0x00a1, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0600, 0x061c,
+0x061e, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07fa,
+0x07fd, 0x082d,
+0x0830, 0x083e,
+0x0840, 0x085b,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e3a,
+0x0e3f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x167f,
+0x1681, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1736,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a1b,
+0x1a1e, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+0x1b80, 0x1bf3,
+0x1bfc, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd0, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x200b, 0x2027,
+0x202a, 0x202e,
+0x2030, 0x205e,
+0x2060, 0x2064,
+0x2066, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x20d0, 0x20f0,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3001, 0x303f,
+0x3041, 0x3096,
+0x3099, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+0xa8e0, 0xa953,
+0xa95f, 0xa97c,
+0xa980, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaac2,
+0xaadb, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xe000, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe00, 0xfe19,
+0xfe20, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xfeff, 0xfeff,
+0xff01, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d27,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x110c1,
+0x110cd, 0x110cd,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x11146,
+0x11150, 0x11176,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+0x11600, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+0x11800, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+0x11a00, 0x11a47,
+0x11a50, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d1e8,
+0x1d200, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Graph */
+
+/* PROPERTY: 'Lower': POSIX [[:Lower:]] */
+static const OnigCodePoint
+CR_Lower[] = { 649,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00df, 0x00f6,
+0x00f8, 0x00ff,
+0x0101, 0x0101,
+0x0103, 0x0103,
+0x0105, 0x0105,
+0x0107, 0x0107,
+0x0109, 0x0109,
+0x010b, 0x010b,
+0x010d, 0x010d,
+0x010f, 0x010f,
+0x0111, 0x0111,
+0x0113, 0x0113,
+0x0115, 0x0115,
+0x0117, 0x0117,
+0x0119, 0x0119,
+0x011b, 0x011b,
+0x011d, 0x011d,
+0x011f, 0x011f,
+0x0121, 0x0121,
+0x0123, 0x0123,
+0x0125, 0x0125,
+0x0127, 0x0127,
+0x0129, 0x0129,
+0x012b, 0x012b,
+0x012d, 0x012d,
+0x012f, 0x012f,
+0x0131, 0x0131,
+0x0133, 0x0133,
+0x0135, 0x0135,
+0x0137, 0x0138,
+0x013a, 0x013a,
+0x013c, 0x013c,
+0x013e, 0x013e,
+0x0140, 0x0140,
+0x0142, 0x0142,
+0x0144, 0x0144,
+0x0146, 0x0146,
+0x0148, 0x0149,
+0x014b, 0x014b,
+0x014d, 0x014d,
+0x014f, 0x014f,
+0x0151, 0x0151,
+0x0153, 0x0153,
+0x0155, 0x0155,
+0x0157, 0x0157,
+0x0159, 0x0159,
+0x015b, 0x015b,
+0x015d, 0x015d,
+0x015f, 0x015f,
+0x0161, 0x0161,
+0x0163, 0x0163,
+0x0165, 0x0165,
+0x0167, 0x0167,
+0x0169, 0x0169,
+0x016b, 0x016b,
+0x016d, 0x016d,
+0x016f, 0x016f,
+0x0171, 0x0171,
+0x0173, 0x0173,
+0x0175, 0x0175,
+0x0177, 0x0177,
+0x017a, 0x017a,
+0x017c, 0x017c,
+0x017e, 0x0180,
+0x0183, 0x0183,
+0x0185, 0x0185,
+0x0188, 0x0188,
+0x018c, 0x018d,
+0x0192, 0x0192,
+0x0195, 0x0195,
+0x0199, 0x019b,
+0x019e, 0x019e,
+0x01a1, 0x01a1,
+0x01a3, 0x01a3,
+0x01a5, 0x01a5,
+0x01a8, 0x01a8,
+0x01aa, 0x01ab,
+0x01ad, 0x01ad,
+0x01b0, 0x01b0,
+0x01b4, 0x01b4,
+0x01b6, 0x01b6,
+0x01b9, 0x01ba,
+0x01bd, 0x01bf,
+0x01c6, 0x01c6,
+0x01c9, 0x01c9,
+0x01cc, 0x01cc,
+0x01ce, 0x01ce,
+0x01d0, 0x01d0,
+0x01d2, 0x01d2,
+0x01d4, 0x01d4,
+0x01d6, 0x01d6,
+0x01d8, 0x01d8,
+0x01da, 0x01da,
+0x01dc, 0x01dd,
+0x01df, 0x01df,
+0x01e1, 0x01e1,
+0x01e3, 0x01e3,
+0x01e5, 0x01e5,
+0x01e7, 0x01e7,
+0x01e9, 0x01e9,
+0x01eb, 0x01eb,
+0x01ed, 0x01ed,
+0x01ef, 0x01f0,
+0x01f3, 0x01f3,
+0x01f5, 0x01f5,
+0x01f9, 0x01f9,
+0x01fb, 0x01fb,
+0x01fd, 0x01fd,
+0x01ff, 0x01ff,
+0x0201, 0x0201,
+0x0203, 0x0203,
+0x0205, 0x0205,
+0x0207, 0x0207,
+0x0209, 0x0209,
+0x020b, 0x020b,
+0x020d, 0x020d,
+0x020f, 0x020f,
+0x0211, 0x0211,
+0x0213, 0x0213,
+0x0215, 0x0215,
+0x0217, 0x0217,
+0x0219, 0x0219,
+0x021b, 0x021b,
+0x021d, 0x021d,
+0x021f, 0x021f,
+0x0221, 0x0221,
+0x0223, 0x0223,
+0x0225, 0x0225,
+0x0227, 0x0227,
+0x0229, 0x0229,
+0x022b, 0x022b,
+0x022d, 0x022d,
+0x022f, 0x022f,
+0x0231, 0x0231,
+0x0233, 0x0239,
+0x023c, 0x023c,
+0x023f, 0x0240,
+0x0242, 0x0242,
+0x0247, 0x0247,
+0x0249, 0x0249,
+0x024b, 0x024b,
+0x024d, 0x024d,
+0x024f, 0x0293,
+0x0295, 0x02b8,
+0x02c0, 0x02c1,
+0x02e0, 0x02e4,
+0x0345, 0x0345,
+0x0371, 0x0371,
+0x0373, 0x0373,
+0x0377, 0x0377,
+0x037a, 0x037d,
+0x0390, 0x0390,
+0x03ac, 0x03ce,
+0x03d0, 0x03d1,
+0x03d5, 0x03d7,
+0x03d9, 0x03d9,
+0x03db, 0x03db,
+0x03dd, 0x03dd,
+0x03df, 0x03df,
+0x03e1, 0x03e1,
+0x03e3, 0x03e3,
+0x03e5, 0x03e5,
+0x03e7, 0x03e7,
+0x03e9, 0x03e9,
+0x03eb, 0x03eb,
+0x03ed, 0x03ed,
+0x03ef, 0x03f3,
+0x03f5, 0x03f5,
+0x03f8, 0x03f8,
+0x03fb, 0x03fc,
+0x0430, 0x045f,
+0x0461, 0x0461,
+0x0463, 0x0463,
+0x0465, 0x0465,
+0x0467, 0x0467,
+0x0469, 0x0469,
+0x046b, 0x046b,
+0x046d, 0x046d,
+0x046f, 0x046f,
+0x0471, 0x0471,
+0x0473, 0x0473,
+0x0475, 0x0475,
+0x0477, 0x0477,
+0x0479, 0x0479,
+0x047b, 0x047b,
+0x047d, 0x047d,
+0x047f, 0x047f,
+0x0481, 0x0481,
+0x048b, 0x048b,
+0x048d, 0x048d,
+0x048f, 0x048f,
+0x0491, 0x0491,
+0x0493, 0x0493,
+0x0495, 0x0495,
+0x0497, 0x0497,
+0x0499, 0x0499,
+0x049b, 0x049b,
+0x049d, 0x049d,
+0x049f, 0x049f,
+0x04a1, 0x04a1,
+0x04a3, 0x04a3,
+0x04a5, 0x04a5,
+0x04a7, 0x04a7,
+0x04a9, 0x04a9,
+0x04ab, 0x04ab,
+0x04ad, 0x04ad,
+0x04af, 0x04af,
+0x04b1, 0x04b1,
+0x04b3, 0x04b3,
+0x04b5, 0x04b5,
+0x04b7, 0x04b7,
+0x04b9, 0x04b9,
+0x04bb, 0x04bb,
+0x04bd, 0x04bd,
+0x04bf, 0x04bf,
+0x04c2, 0x04c2,
+0x04c4, 0x04c4,
+0x04c6, 0x04c6,
+0x04c8, 0x04c8,
+0x04ca, 0x04ca,
+0x04cc, 0x04cc,
+0x04ce, 0x04cf,
+0x04d1, 0x04d1,
+0x04d3, 0x04d3,
+0x04d5, 0x04d5,
+0x04d7, 0x04d7,
+0x04d9, 0x04d9,
+0x04db, 0x04db,
+0x04dd, 0x04dd,
+0x04df, 0x04df,
+0x04e1, 0x04e1,
+0x04e3, 0x04e3,
+0x04e5, 0x04e5,
+0x04e7, 0x04e7,
+0x04e9, 0x04e9,
+0x04eb, 0x04eb,
+0x04ed, 0x04ed,
+0x04ef, 0x04ef,
+0x04f1, 0x04f1,
+0x04f3, 0x04f3,
+0x04f5, 0x04f5,
+0x04f7, 0x04f7,
+0x04f9, 0x04f9,
+0x04fb, 0x04fb,
+0x04fd, 0x04fd,
+0x04ff, 0x04ff,
+0x0501, 0x0501,
+0x0503, 0x0503,
+0x0505, 0x0505,
+0x0507, 0x0507,
+0x0509, 0x0509,
+0x050b, 0x050b,
+0x050d, 0x050d,
+0x050f, 0x050f,
+0x0511, 0x0511,
+0x0513, 0x0513,
+0x0515, 0x0515,
+0x0517, 0x0517,
+0x0519, 0x0519,
+0x051b, 0x051b,
+0x051d, 0x051d,
+0x051f, 0x051f,
+0x0521, 0x0521,
+0x0523, 0x0523,
+0x0525, 0x0525,
+0x0527, 0x0527,
+0x0529, 0x0529,
+0x052b, 0x052b,
+0x052d, 0x052d,
+0x052f, 0x052f,
+0x0560, 0x0588,
+0x10d0, 0x10fa,
+0x10fd, 0x10ff,
+0x13f8, 0x13fd,
+0x1c80, 0x1c88,
+0x1d00, 0x1dbf,
+0x1e01, 0x1e01,
+0x1e03, 0x1e03,
+0x1e05, 0x1e05,
+0x1e07, 0x1e07,
+0x1e09, 0x1e09,
+0x1e0b, 0x1e0b,
+0x1e0d, 0x1e0d,
+0x1e0f, 0x1e0f,
+0x1e11, 0x1e11,
+0x1e13, 0x1e13,
+0x1e15, 0x1e15,
+0x1e17, 0x1e17,
+0x1e19, 0x1e19,
+0x1e1b, 0x1e1b,
+0x1e1d, 0x1e1d,
+0x1e1f, 0x1e1f,
+0x1e21, 0x1e21,
+0x1e23, 0x1e23,
+0x1e25, 0x1e25,
+0x1e27, 0x1e27,
+0x1e29, 0x1e29,
+0x1e2b, 0x1e2b,
+0x1e2d, 0x1e2d,
+0x1e2f, 0x1e2f,
+0x1e31, 0x1e31,
+0x1e33, 0x1e33,
+0x1e35, 0x1e35,
+0x1e37, 0x1e37,
+0x1e39, 0x1e39,
+0x1e3b, 0x1e3b,
+0x1e3d, 0x1e3d,
+0x1e3f, 0x1e3f,
+0x1e41, 0x1e41,
+0x1e43, 0x1e43,
+0x1e45, 0x1e45,
+0x1e47, 0x1e47,
+0x1e49, 0x1e49,
+0x1e4b, 0x1e4b,
+0x1e4d, 0x1e4d,
+0x1e4f, 0x1e4f,
+0x1e51, 0x1e51,
+0x1e53, 0x1e53,
+0x1e55, 0x1e55,
+0x1e57, 0x1e57,
+0x1e59, 0x1e59,
+0x1e5b, 0x1e5b,
+0x1e5d, 0x1e5d,
+0x1e5f, 0x1e5f,
+0x1e61, 0x1e61,
+0x1e63, 0x1e63,
+0x1e65, 0x1e65,
+0x1e67, 0x1e67,
+0x1e69, 0x1e69,
+0x1e6b, 0x1e6b,
+0x1e6d, 0x1e6d,
+0x1e6f, 0x1e6f,
+0x1e71, 0x1e71,
+0x1e73, 0x1e73,
+0x1e75, 0x1e75,
+0x1e77, 0x1e77,
+0x1e79, 0x1e79,
+0x1e7b, 0x1e7b,
+0x1e7d, 0x1e7d,
+0x1e7f, 0x1e7f,
+0x1e81, 0x1e81,
+0x1e83, 0x1e83,
+0x1e85, 0x1e85,
+0x1e87, 0x1e87,
+0x1e89, 0x1e89,
+0x1e8b, 0x1e8b,
+0x1e8d, 0x1e8d,
+0x1e8f, 0x1e8f,
+0x1e91, 0x1e91,
+0x1e93, 0x1e93,
+0x1e95, 0x1e9d,
+0x1e9f, 0x1e9f,
+0x1ea1, 0x1ea1,
+0x1ea3, 0x1ea3,
+0x1ea5, 0x1ea5,
+0x1ea7, 0x1ea7,
+0x1ea9, 0x1ea9,
+0x1eab, 0x1eab,
+0x1ead, 0x1ead,
+0x1eaf, 0x1eaf,
+0x1eb1, 0x1eb1,
+0x1eb3, 0x1eb3,
+0x1eb5, 0x1eb5,
+0x1eb7, 0x1eb7,
+0x1eb9, 0x1eb9,
+0x1ebb, 0x1ebb,
+0x1ebd, 0x1ebd,
+0x1ebf, 0x1ebf,
+0x1ec1, 0x1ec1,
+0x1ec3, 0x1ec3,
+0x1ec5, 0x1ec5,
+0x1ec7, 0x1ec7,
+0x1ec9, 0x1ec9,
+0x1ecb, 0x1ecb,
+0x1ecd, 0x1ecd,
+0x1ecf, 0x1ecf,
+0x1ed1, 0x1ed1,
+0x1ed3, 0x1ed3,
+0x1ed5, 0x1ed5,
+0x1ed7, 0x1ed7,
+0x1ed9, 0x1ed9,
+0x1edb, 0x1edb,
+0x1edd, 0x1edd,
+0x1edf, 0x1edf,
+0x1ee1, 0x1ee1,
+0x1ee3, 0x1ee3,
+0x1ee5, 0x1ee5,
+0x1ee7, 0x1ee7,
+0x1ee9, 0x1ee9,
+0x1eeb, 0x1eeb,
+0x1eed, 0x1eed,
+0x1eef, 0x1eef,
+0x1ef1, 0x1ef1,
+0x1ef3, 0x1ef3,
+0x1ef5, 0x1ef5,
+0x1ef7, 0x1ef7,
+0x1ef9, 0x1ef9,
+0x1efb, 0x1efb,
+0x1efd, 0x1efd,
+0x1eff, 0x1f07,
+0x1f10, 0x1f15,
+0x1f20, 0x1f27,
+0x1f30, 0x1f37,
+0x1f40, 0x1f45,
+0x1f50, 0x1f57,
+0x1f60, 0x1f67,
+0x1f70, 0x1f7d,
+0x1f80, 0x1f87,
+0x1f90, 0x1f97,
+0x1fa0, 0x1fa7,
+0x1fb0, 0x1fb4,
+0x1fb6, 0x1fb7,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fc7,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fd7,
+0x1fe0, 0x1fe7,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ff7,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x210a, 0x210a,
+0x210e, 0x210f,
+0x2113, 0x2113,
+0x212f, 0x212f,
+0x2134, 0x2134,
+0x2139, 0x2139,
+0x213c, 0x213d,
+0x2146, 0x2149,
+0x214e, 0x214e,
+0x2170, 0x217f,
+0x2184, 0x2184,
+0x24d0, 0x24e9,
+0x2c30, 0x2c5e,
+0x2c61, 0x2c61,
+0x2c65, 0x2c66,
+0x2c68, 0x2c68,
+0x2c6a, 0x2c6a,
+0x2c6c, 0x2c6c,
+0x2c71, 0x2c71,
+0x2c73, 0x2c74,
+0x2c76, 0x2c7d,
+0x2c81, 0x2c81,
+0x2c83, 0x2c83,
+0x2c85, 0x2c85,
+0x2c87, 0x2c87,
+0x2c89, 0x2c89,
+0x2c8b, 0x2c8b,
+0x2c8d, 0x2c8d,
+0x2c8f, 0x2c8f,
+0x2c91, 0x2c91,
+0x2c93, 0x2c93,
+0x2c95, 0x2c95,
+0x2c97, 0x2c97,
+0x2c99, 0x2c99,
+0x2c9b, 0x2c9b,
+0x2c9d, 0x2c9d,
+0x2c9f, 0x2c9f,
+0x2ca1, 0x2ca1,
+0x2ca3, 0x2ca3,
+0x2ca5, 0x2ca5,
+0x2ca7, 0x2ca7,
+0x2ca9, 0x2ca9,
+0x2cab, 0x2cab,
+0x2cad, 0x2cad,
+0x2caf, 0x2caf,
+0x2cb1, 0x2cb1,
+0x2cb3, 0x2cb3,
+0x2cb5, 0x2cb5,
+0x2cb7, 0x2cb7,
+0x2cb9, 0x2cb9,
+0x2cbb, 0x2cbb,
+0x2cbd, 0x2cbd,
+0x2cbf, 0x2cbf,
+0x2cc1, 0x2cc1,
+0x2cc3, 0x2cc3,
+0x2cc5, 0x2cc5,
+0x2cc7, 0x2cc7,
+0x2cc9, 0x2cc9,
+0x2ccb, 0x2ccb,
+0x2ccd, 0x2ccd,
+0x2ccf, 0x2ccf,
+0x2cd1, 0x2cd1,
+0x2cd3, 0x2cd3,
+0x2cd5, 0x2cd5,
+0x2cd7, 0x2cd7,
+0x2cd9, 0x2cd9,
+0x2cdb, 0x2cdb,
+0x2cdd, 0x2cdd,
+0x2cdf, 0x2cdf,
+0x2ce1, 0x2ce1,
+0x2ce3, 0x2ce4,
+0x2cec, 0x2cec,
+0x2cee, 0x2cee,
+0x2cf3, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0xa641, 0xa641,
+0xa643, 0xa643,
+0xa645, 0xa645,
+0xa647, 0xa647,
+0xa649, 0xa649,
+0xa64b, 0xa64b,
+0xa64d, 0xa64d,
+0xa64f, 0xa64f,
+0xa651, 0xa651,
+0xa653, 0xa653,
+0xa655, 0xa655,
+0xa657, 0xa657,
+0xa659, 0xa659,
+0xa65b, 0xa65b,
+0xa65d, 0xa65d,
+0xa65f, 0xa65f,
+0xa661, 0xa661,
+0xa663, 0xa663,
+0xa665, 0xa665,
+0xa667, 0xa667,
+0xa669, 0xa669,
+0xa66b, 0xa66b,
+0xa66d, 0xa66d,
+0xa681, 0xa681,
+0xa683, 0xa683,
+0xa685, 0xa685,
+0xa687, 0xa687,
+0xa689, 0xa689,
+0xa68b, 0xa68b,
+0xa68d, 0xa68d,
+0xa68f, 0xa68f,
+0xa691, 0xa691,
+0xa693, 0xa693,
+0xa695, 0xa695,
+0xa697, 0xa697,
+0xa699, 0xa699,
+0xa69b, 0xa69d,
+0xa723, 0xa723,
+0xa725, 0xa725,
+0xa727, 0xa727,
+0xa729, 0xa729,
+0xa72b, 0xa72b,
+0xa72d, 0xa72d,
+0xa72f, 0xa731,
+0xa733, 0xa733,
+0xa735, 0xa735,
+0xa737, 0xa737,
+0xa739, 0xa739,
+0xa73b, 0xa73b,
+0xa73d, 0xa73d,
+0xa73f, 0xa73f,
+0xa741, 0xa741,
+0xa743, 0xa743,
+0xa745, 0xa745,
+0xa747, 0xa747,
+0xa749, 0xa749,
+0xa74b, 0xa74b,
+0xa74d, 0xa74d,
+0xa74f, 0xa74f,
+0xa751, 0xa751,
+0xa753, 0xa753,
+0xa755, 0xa755,
+0xa757, 0xa757,
+0xa759, 0xa759,
+0xa75b, 0xa75b,
+0xa75d, 0xa75d,
+0xa75f, 0xa75f,
+0xa761, 0xa761,
+0xa763, 0xa763,
+0xa765, 0xa765,
+0xa767, 0xa767,
+0xa769, 0xa769,
+0xa76b, 0xa76b,
+0xa76d, 0xa76d,
+0xa76f, 0xa778,
+0xa77a, 0xa77a,
+0xa77c, 0xa77c,
+0xa77f, 0xa77f,
+0xa781, 0xa781,
+0xa783, 0xa783,
+0xa785, 0xa785,
+0xa787, 0xa787,
+0xa78c, 0xa78c,
+0xa78e, 0xa78e,
+0xa791, 0xa791,
+0xa793, 0xa795,
+0xa797, 0xa797,
+0xa799, 0xa799,
+0xa79b, 0xa79b,
+0xa79d, 0xa79d,
+0xa79f, 0xa79f,
+0xa7a1, 0xa7a1,
+0xa7a3, 0xa7a3,
+0xa7a5, 0xa7a5,
+0xa7a7, 0xa7a7,
+0xa7a9, 0xa7a9,
+0xa7af, 0xa7af,
+0xa7b5, 0xa7b5,
+0xa7b7, 0xa7b7,
+0xa7b9, 0xa7b9,
+0xa7bb, 0xa7bb,
+0xa7bd, 0xa7bd,
+0xa7bf, 0xa7bf,
+0xa7c3, 0xa7c3,
+0xa7f8, 0xa7fa,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabbf,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xff41, 0xff5a,
+0x10428, 0x1044f,
+0x104d8, 0x104fb,
+0x10cc0, 0x10cf2,
+0x118c0, 0x118df,
+0x16e60, 0x16e7f,
+0x1d41a, 0x1d433,
+0x1d44e, 0x1d454,
+0x1d456, 0x1d467,
+0x1d482, 0x1d49b,
+0x1d4b6, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d4cf,
+0x1d4ea, 0x1d503,
+0x1d51e, 0x1d537,
+0x1d552, 0x1d56b,
+0x1d586, 0x1d59f,
+0x1d5ba, 0x1d5d3,
+0x1d5ee, 0x1d607,
+0x1d622, 0x1d63b,
+0x1d656, 0x1d66f,
+0x1d68a, 0x1d6a5,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6e1,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d71b,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d755,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d78f,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7c9,
+0x1d7cb, 0x1d7cb,
+0x1e922, 0x1e943,
+}; /* END of CR_Lower */
+
+/* PROPERTY: 'Print': POSIX [[:Print:]] */
+static const OnigCodePoint
+CR_Print[] = { 668,
+0x0020, 0x007e,
+0x00a0, 0x0377,
+0x037a, 0x037f,
+0x0384, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x058a,
+0x058d, 0x058f,
+0x0591, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f4,
+0x0600, 0x061c,
+0x061e, 0x070d,
+0x070f, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07fa,
+0x07fd, 0x082d,
+0x0830, 0x083e,
+0x0840, 0x085b,
+0x085e, 0x085e,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a76,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0af1,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b77,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bfa,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c77, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4f,
+0x0d54, 0x0d63,
+0x0d66, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df4,
+0x0e01, 0x0e3a,
+0x0e3f, 0x0e5b,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fbe, 0x0fcc,
+0x0fce, 0x0fda,
+0x1000, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x137c,
+0x1380, 0x1399,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1400, 0x169c,
+0x16a0, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1736,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17dd,
+0x17e0, 0x17e9,
+0x17f0, 0x17f9,
+0x1800, 0x180e,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1940, 0x1940,
+0x1944, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19da,
+0x19de, 0x1a1b,
+0x1a1e, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa0, 0x1aad,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b7c,
+0x1b80, 0x1bf3,
+0x1bfc, 0x1c37,
+0x1c3b, 0x1c49,
+0x1c4d, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cc7,
+0x1cd0, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fc4,
+0x1fc6, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fdd, 0x1fef,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffe,
+0x2000, 0x2027,
+0x202a, 0x2064,
+0x2066, 0x2071,
+0x2074, 0x208e,
+0x2090, 0x209c,
+0x20a0, 0x20bf,
+0x20d0, 0x20f0,
+0x2100, 0x218b,
+0x2190, 0x2426,
+0x2440, 0x244a,
+0x2460, 0x2b73,
+0x2b76, 0x2b95,
+0x2b98, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2cf3,
+0x2cf9, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d70,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2e4f,
+0x2e80, 0x2e99,
+0x2e9b, 0x2ef3,
+0x2f00, 0x2fd5,
+0x2ff0, 0x2ffb,
+0x3000, 0x303f,
+0x3041, 0x3096,
+0x3099, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x3190, 0x31ba,
+0x31c0, 0x31e3,
+0x31f0, 0x321e,
+0x3220, 0x4db5,
+0x4dc0, 0x9fef,
+0xa000, 0xa48c,
+0xa490, 0xa4c6,
+0xa4d0, 0xa62b,
+0xa640, 0xa6f7,
+0xa700, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa82b,
+0xa830, 0xa839,
+0xa840, 0xa877,
+0xa880, 0xa8c5,
+0xa8ce, 0xa8d9,
+0xa8e0, 0xa953,
+0xa95f, 0xa97c,
+0xa980, 0xa9cd,
+0xa9cf, 0xa9d9,
+0xa9de, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa5c, 0xaac2,
+0xaadb, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab67,
+0xab70, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xe000, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbc1,
+0xfbd3, 0xfd3f,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfd,
+0xfe00, 0xfe19,
+0xfe20, 0xfe52,
+0xfe54, 0xfe66,
+0xfe68, 0xfe6b,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xfeff, 0xfeff,
+0xff01, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0xffe0, 0xffe6,
+0xffe8, 0xffee,
+0xfff9, 0xfffd,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10100, 0x10102,
+0x10107, 0x10133,
+0x10137, 0x1018e,
+0x10190, 0x1019b,
+0x101a0, 0x101a0,
+0x101d0, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102fb,
+0x10300, 0x10323,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x1039f, 0x103c3,
+0x103c8, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x1056f, 0x1056f,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10857, 0x1089e,
+0x108a7, 0x108af,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x108fb, 0x1091b,
+0x1091f, 0x10939,
+0x1093f, 0x1093f,
+0x10980, 0x109b7,
+0x109bc, 0x109cf,
+0x109d2, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a48,
+0x10a50, 0x10a58,
+0x10a60, 0x10a9f,
+0x10ac0, 0x10ae6,
+0x10aeb, 0x10af6,
+0x10b00, 0x10b35,
+0x10b39, 0x10b55,
+0x10b58, 0x10b72,
+0x10b78, 0x10b91,
+0x10b99, 0x10b9c,
+0x10ba9, 0x10baf,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10cfa, 0x10d27,
+0x10d30, 0x10d39,
+0x10e60, 0x10e7e,
+0x10f00, 0x10f27,
+0x10f30, 0x10f59,
+0x10fe0, 0x10ff6,
+0x11000, 0x1104d,
+0x11052, 0x1106f,
+0x1107f, 0x110c1,
+0x110cd, 0x110cd,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x11146,
+0x11150, 0x11176,
+0x11180, 0x111cd,
+0x111d0, 0x111df,
+0x111e1, 0x111f4,
+0x11200, 0x11211,
+0x11213, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a9,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x11459,
+0x1145b, 0x1145b,
+0x1145d, 0x1145f,
+0x11480, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115dd,
+0x11600, 0x11644,
+0x11650, 0x11659,
+0x11660, 0x1166c,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x1173f,
+0x11800, 0x1183b,
+0x118a0, 0x118f2,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e4,
+0x11a00, 0x11a47,
+0x11a50, 0x11aa2,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c45,
+0x11c50, 0x11c6c,
+0x11c70, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef8,
+0x11fc0, 0x11ff1,
+0x11fff, 0x12399,
+0x12400, 0x1246e,
+0x12470, 0x12474,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x13430, 0x13438,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16a6e, 0x16a6f,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af5,
+0x16b00, 0x16b45,
+0x16b50, 0x16b59,
+0x16b5b, 0x16b61,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e9a,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9c, 0x1bca3,
+0x1d000, 0x1d0f5,
+0x1d100, 0x1d126,
+0x1d129, 0x1d1e8,
+0x1d200, 0x1d245,
+0x1d2e0, 0x1d2f3,
+0x1d300, 0x1d356,
+0x1d360, 0x1d378,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d7cb,
+0x1d7ce, 0x1da8b,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14f,
+0x1e2c0, 0x1e2f9,
+0x1e2ff, 0x1e2ff,
+0x1e800, 0x1e8c4,
+0x1e8c7, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1e95e, 0x1e95f,
+0x1ec71, 0x1ecb4,
+0x1ed01, 0x1ed3d,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1eef0, 0x1eef1,
+0x1f000, 0x1f02b,
+0x1f030, 0x1f093,
+0x1f0a0, 0x1f0ae,
+0x1f0b1, 0x1f0bf,
+0x1f0c1, 0x1f0cf,
+0x1f0d1, 0x1f0f5,
+0x1f100, 0x1f10c,
+0x1f110, 0x1f16c,
+0x1f170, 0x1f1ac,
+0x1f1e6, 0x1f202,
+0x1f210, 0x1f23b,
+0x1f240, 0x1f248,
+0x1f250, 0x1f251,
+0x1f260, 0x1f265,
+0x1f300, 0x1f6d5,
+0x1f6e0, 0x1f6ec,
+0x1f6f0, 0x1f6fa,
+0x1f700, 0x1f773,
+0x1f780, 0x1f7d8,
+0x1f7e0, 0x1f7eb,
+0x1f800, 0x1f80b,
+0x1f810, 0x1f847,
+0x1f850, 0x1f859,
+0x1f860, 0x1f887,
+0x1f890, 0x1f8ad,
+0x1f900, 0x1f90b,
+0x1f90d, 0x1f971,
+0x1f973, 0x1f976,
+0x1f97a, 0x1f9a2,
+0x1f9a5, 0x1f9aa,
+0x1f9ae, 0x1f9ca,
+0x1f9cd, 0x1fa53,
+0x1fa60, 0x1fa6d,
+0x1fa70, 0x1fa73,
+0x1fa78, 0x1fa7a,
+0x1fa80, 0x1fa82,
+0x1fa90, 0x1fa95,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0001, 0xe0001,
+0xe0020, 0xe007f,
+0xe0100, 0xe01ef,
+0xf0000, 0xffffd,
+0x100000, 0x10fffd,
+}; /* END of CR_Print */
+
+/* PROPERTY: 'Punct': POSIX [[:Punct:]] */
+static const OnigCodePoint
+CR_Punct[] = { 182,
+0x0021, 0x0023,
+0x0025, 0x002a,
+0x002c, 0x002f,
+0x003a, 0x003b,
+0x003f, 0x0040,
+0x005b, 0x005d,
+0x005f, 0x005f,
+0x007b, 0x007b,
+0x007d, 0x007d,
+0x00a1, 0x00a1,
+0x00a7, 0x00a7,
+0x00ab, 0x00ab,
+0x00b6, 0x00b7,
+0x00bb, 0x00bb,
+0x00bf, 0x00bf,
+0x037e, 0x037e,
+0x0387, 0x0387,
+0x055a, 0x055f,
+0x0589, 0x058a,
+0x05be, 0x05be,
+0x05c0, 0x05c0,
+0x05c3, 0x05c3,
+0x05c6, 0x05c6,
+0x05f3, 0x05f4,
+0x0609, 0x060a,
+0x060c, 0x060d,
+0x061b, 0x061b,
+0x061e, 0x061f,
+0x066a, 0x066d,
+0x06d4, 0x06d4,
+0x0700, 0x070d,
+0x07f7, 0x07f9,
+0x0830, 0x083e,
+0x085e, 0x085e,
+0x0964, 0x0965,
+0x0970, 0x0970,
+0x09fd, 0x09fd,
+0x0a76, 0x0a76,
+0x0af0, 0x0af0,
+0x0c77, 0x0c77,
+0x0c84, 0x0c84,
+0x0df4, 0x0df4,
+0x0e4f, 0x0e4f,
+0x0e5a, 0x0e5b,
+0x0f04, 0x0f12,
+0x0f14, 0x0f14,
+0x0f3a, 0x0f3d,
+0x0f85, 0x0f85,
+0x0fd0, 0x0fd4,
+0x0fd9, 0x0fda,
+0x104a, 0x104f,
+0x10fb, 0x10fb,
+0x1360, 0x1368,
+0x1400, 0x1400,
+0x166e, 0x166e,
+0x169b, 0x169c,
+0x16eb, 0x16ed,
+0x1735, 0x1736,
+0x17d4, 0x17d6,
+0x17d8, 0x17da,
+0x1800, 0x180a,
+0x1944, 0x1945,
+0x1a1e, 0x1a1f,
+0x1aa0, 0x1aa6,
+0x1aa8, 0x1aad,
+0x1b5a, 0x1b60,
+0x1bfc, 0x1bff,
+0x1c3b, 0x1c3f,
+0x1c7e, 0x1c7f,
+0x1cc0, 0x1cc7,
+0x1cd3, 0x1cd3,
+0x2010, 0x2027,
+0x2030, 0x2043,
+0x2045, 0x2051,
+0x2053, 0x205e,
+0x207d, 0x207e,
+0x208d, 0x208e,
+0x2308, 0x230b,
+0x2329, 0x232a,
+0x2768, 0x2775,
+0x27c5, 0x27c6,
+0x27e6, 0x27ef,
+0x2983, 0x2998,
+0x29d8, 0x29db,
+0x29fc, 0x29fd,
+0x2cf9, 0x2cfc,
+0x2cfe, 0x2cff,
+0x2d70, 0x2d70,
+0x2e00, 0x2e2e,
+0x2e30, 0x2e4f,
+0x3001, 0x3003,
+0x3008, 0x3011,
+0x3014, 0x301f,
+0x3030, 0x3030,
+0x303d, 0x303d,
+0x30a0, 0x30a0,
+0x30fb, 0x30fb,
+0xa4fe, 0xa4ff,
+0xa60d, 0xa60f,
+0xa673, 0xa673,
+0xa67e, 0xa67e,
+0xa6f2, 0xa6f7,
+0xa874, 0xa877,
+0xa8ce, 0xa8cf,
+0xa8f8, 0xa8fa,
+0xa8fc, 0xa8fc,
+0xa92e, 0xa92f,
+0xa95f, 0xa95f,
+0xa9c1, 0xa9cd,
+0xa9de, 0xa9df,
+0xaa5c, 0xaa5f,
+0xaade, 0xaadf,
+0xaaf0, 0xaaf1,
+0xabeb, 0xabeb,
+0xfd3e, 0xfd3f,
+0xfe10, 0xfe19,
+0xfe30, 0xfe52,
+0xfe54, 0xfe61,
+0xfe63, 0xfe63,
+0xfe68, 0xfe68,
+0xfe6a, 0xfe6b,
+0xff01, 0xff03,
+0xff05, 0xff0a,
+0xff0c, 0xff0f,
+0xff1a, 0xff1b,
+0xff1f, 0xff20,
+0xff3b, 0xff3d,
+0xff3f, 0xff3f,
+0xff5b, 0xff5b,
+0xff5d, 0xff5d,
+0xff5f, 0xff65,
+0x10100, 0x10102,
+0x1039f, 0x1039f,
+0x103d0, 0x103d0,
+0x1056f, 0x1056f,
+0x10857, 0x10857,
+0x1091f, 0x1091f,
+0x1093f, 0x1093f,
+0x10a50, 0x10a58,
+0x10a7f, 0x10a7f,
+0x10af0, 0x10af6,
+0x10b39, 0x10b3f,
+0x10b99, 0x10b9c,
+0x10f55, 0x10f59,
+0x11047, 0x1104d,
+0x110bb, 0x110bc,
+0x110be, 0x110c1,
+0x11140, 0x11143,
+0x11174, 0x11175,
+0x111c5, 0x111c8,
+0x111cd, 0x111cd,
+0x111db, 0x111db,
+0x111dd, 0x111df,
+0x11238, 0x1123d,
+0x112a9, 0x112a9,
+0x1144b, 0x1144f,
+0x1145b, 0x1145b,
+0x1145d, 0x1145d,
+0x114c6, 0x114c6,
+0x115c1, 0x115d7,
+0x11641, 0x11643,
+0x11660, 0x1166c,
+0x1173c, 0x1173e,
+0x1183b, 0x1183b,
+0x119e2, 0x119e2,
+0x11a3f, 0x11a46,
+0x11a9a, 0x11a9c,
+0x11a9e, 0x11aa2,
+0x11c41, 0x11c45,
+0x11c70, 0x11c71,
+0x11ef7, 0x11ef8,
+0x11fff, 0x11fff,
+0x12470, 0x12474,
+0x16a6e, 0x16a6f,
+0x16af5, 0x16af5,
+0x16b37, 0x16b3b,
+0x16b44, 0x16b44,
+0x16e97, 0x16e9a,
+0x16fe2, 0x16fe2,
+0x1bc9f, 0x1bc9f,
+0x1da87, 0x1da8b,
+0x1e95e, 0x1e95f,
+}; /* END of CR_Punct */
+
+/* PROPERTY: 'Space': POSIX [[:Space:]] */
+static const OnigCodePoint
+CR_Space[] = { 10,
+0x0009, 0x000d,
+0x0020, 0x0020,
+0x0085, 0x0085,
+0x00a0, 0x00a0,
+0x1680, 0x1680,
+0x2000, 0x200a,
+0x2028, 0x2029,
+0x202f, 0x202f,
+0x205f, 0x205f,
+0x3000, 0x3000,
+}; /* END of CR_Space */
+
+/* PROPERTY: 'Upper': POSIX [[:Upper:]] */
+static const OnigCodePoint
+CR_Upper[] = { 641,
+0x0041, 0x005a,
+0x00c0, 0x00d6,
+0x00d8, 0x00de,
+0x0100, 0x0100,
+0x0102, 0x0102,
+0x0104, 0x0104,
+0x0106, 0x0106,
+0x0108, 0x0108,
+0x010a, 0x010a,
+0x010c, 0x010c,
+0x010e, 0x010e,
+0x0110, 0x0110,
+0x0112, 0x0112,
+0x0114, 0x0114,
+0x0116, 0x0116,
+0x0118, 0x0118,
+0x011a, 0x011a,
+0x011c, 0x011c,
+0x011e, 0x011e,
+0x0120, 0x0120,
+0x0122, 0x0122,
+0x0124, 0x0124,
+0x0126, 0x0126,
+0x0128, 0x0128,
+0x012a, 0x012a,
+0x012c, 0x012c,
+0x012e, 0x012e,
+0x0130, 0x0130,
+0x0132, 0x0132,
+0x0134, 0x0134,
+0x0136, 0x0136,
+0x0139, 0x0139,
+0x013b, 0x013b,
+0x013d, 0x013d,
+0x013f, 0x013f,
+0x0141, 0x0141,
+0x0143, 0x0143,
+0x0145, 0x0145,
+0x0147, 0x0147,
+0x014a, 0x014a,
+0x014c, 0x014c,
+0x014e, 0x014e,
+0x0150, 0x0150,
+0x0152, 0x0152,
+0x0154, 0x0154,
+0x0156, 0x0156,
+0x0158, 0x0158,
+0x015a, 0x015a,
+0x015c, 0x015c,
+0x015e, 0x015e,
+0x0160, 0x0160,
+0x0162, 0x0162,
+0x0164, 0x0164,
+0x0166, 0x0166,
+0x0168, 0x0168,
+0x016a, 0x016a,
+0x016c, 0x016c,
+0x016e, 0x016e,
+0x0170, 0x0170,
+0x0172, 0x0172,
+0x0174, 0x0174,
+0x0176, 0x0176,
+0x0178, 0x0179,
+0x017b, 0x017b,
+0x017d, 0x017d,
+0x0181, 0x0182,
+0x0184, 0x0184,
+0x0186, 0x0187,
+0x0189, 0x018b,
+0x018e, 0x0191,
+0x0193, 0x0194,
+0x0196, 0x0198,
+0x019c, 0x019d,
+0x019f, 0x01a0,
+0x01a2, 0x01a2,
+0x01a4, 0x01a4,
+0x01a6, 0x01a7,
+0x01a9, 0x01a9,
+0x01ac, 0x01ac,
+0x01ae, 0x01af,
+0x01b1, 0x01b3,
+0x01b5, 0x01b5,
+0x01b7, 0x01b8,
+0x01bc, 0x01bc,
+0x01c4, 0x01c4,
+0x01c7, 0x01c7,
+0x01ca, 0x01ca,
+0x01cd, 0x01cd,
+0x01cf, 0x01cf,
+0x01d1, 0x01d1,
+0x01d3, 0x01d3,
+0x01d5, 0x01d5,
+0x01d7, 0x01d7,
+0x01d9, 0x01d9,
+0x01db, 0x01db,
+0x01de, 0x01de,
+0x01e0, 0x01e0,
+0x01e2, 0x01e2,
+0x01e4, 0x01e4,
+0x01e6, 0x01e6,
+0x01e8, 0x01e8,
+0x01ea, 0x01ea,
+0x01ec, 0x01ec,
+0x01ee, 0x01ee,
+0x01f1, 0x01f1,
+0x01f4, 0x01f4,
+0x01f6, 0x01f8,
+0x01fa, 0x01fa,
+0x01fc, 0x01fc,
+0x01fe, 0x01fe,
+0x0200, 0x0200,
+0x0202, 0x0202,
+0x0204, 0x0204,
+0x0206, 0x0206,
+0x0208, 0x0208,
+0x020a, 0x020a,
+0x020c, 0x020c,
+0x020e, 0x020e,
+0x0210, 0x0210,
+0x0212, 0x0212,
+0x0214, 0x0214,
+0x0216, 0x0216,
+0x0218, 0x0218,
+0x021a, 0x021a,
+0x021c, 0x021c,
+0x021e, 0x021e,
+0x0220, 0x0220,
+0x0222, 0x0222,
+0x0224, 0x0224,
+0x0226, 0x0226,
+0x0228, 0x0228,
+0x022a, 0x022a,
+0x022c, 0x022c,
+0x022e, 0x022e,
+0x0230, 0x0230,
+0x0232, 0x0232,
+0x023a, 0x023b,
+0x023d, 0x023e,
+0x0241, 0x0241,
+0x0243, 0x0246,
+0x0248, 0x0248,
+0x024a, 0x024a,
+0x024c, 0x024c,
+0x024e, 0x024e,
+0x0370, 0x0370,
+0x0372, 0x0372,
+0x0376, 0x0376,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x038f,
+0x0391, 0x03a1,
+0x03a3, 0x03ab,
+0x03cf, 0x03cf,
+0x03d2, 0x03d4,
+0x03d8, 0x03d8,
+0x03da, 0x03da,
+0x03dc, 0x03dc,
+0x03de, 0x03de,
+0x03e0, 0x03e0,
+0x03e2, 0x03e2,
+0x03e4, 0x03e4,
+0x03e6, 0x03e6,
+0x03e8, 0x03e8,
+0x03ea, 0x03ea,
+0x03ec, 0x03ec,
+0x03ee, 0x03ee,
+0x03f4, 0x03f4,
+0x03f7, 0x03f7,
+0x03f9, 0x03fa,
+0x03fd, 0x042f,
+0x0460, 0x0460,
+0x0462, 0x0462,
+0x0464, 0x0464,
+0x0466, 0x0466,
+0x0468, 0x0468,
+0x046a, 0x046a,
+0x046c, 0x046c,
+0x046e, 0x046e,
+0x0470, 0x0470,
+0x0472, 0x0472,
+0x0474, 0x0474,
+0x0476, 0x0476,
+0x0478, 0x0478,
+0x047a, 0x047a,
+0x047c, 0x047c,
+0x047e, 0x047e,
+0x0480, 0x0480,
+0x048a, 0x048a,
+0x048c, 0x048c,
+0x048e, 0x048e,
+0x0490, 0x0490,
+0x0492, 0x0492,
+0x0494, 0x0494,
+0x0496, 0x0496,
+0x0498, 0x0498,
+0x049a, 0x049a,
+0x049c, 0x049c,
+0x049e, 0x049e,
+0x04a0, 0x04a0,
+0x04a2, 0x04a2,
+0x04a4, 0x04a4,
+0x04a6, 0x04a6,
+0x04a8, 0x04a8,
+0x04aa, 0x04aa,
+0x04ac, 0x04ac,
+0x04ae, 0x04ae,
+0x04b0, 0x04b0,
+0x04b2, 0x04b2,
+0x04b4, 0x04b4,
+0x04b6, 0x04b6,
+0x04b8, 0x04b8,
+0x04ba, 0x04ba,
+0x04bc, 0x04bc,
+0x04be, 0x04be,
+0x04c0, 0x04c1,
+0x04c3, 0x04c3,
+0x04c5, 0x04c5,
+0x04c7, 0x04c7,
+0x04c9, 0x04c9,
+0x04cb, 0x04cb,
+0x04cd, 0x04cd,
+0x04d0, 0x04d0,
+0x04d2, 0x04d2,
+0x04d4, 0x04d4,
+0x04d6, 0x04d6,
+0x04d8, 0x04d8,
+0x04da, 0x04da,
+0x04dc, 0x04dc,
+0x04de, 0x04de,
+0x04e0, 0x04e0,
+0x04e2, 0x04e2,
+0x04e4, 0x04e4,
+0x04e6, 0x04e6,
+0x04e8, 0x04e8,
+0x04ea, 0x04ea,
+0x04ec, 0x04ec,
+0x04ee, 0x04ee,
+0x04f0, 0x04f0,
+0x04f2, 0x04f2,
+0x04f4, 0x04f4,
+0x04f6, 0x04f6,
+0x04f8, 0x04f8,
+0x04fa, 0x04fa,
+0x04fc, 0x04fc,
+0x04fe, 0x04fe,
+0x0500, 0x0500,
+0x0502, 0x0502,
+0x0504, 0x0504,
+0x0506, 0x0506,
+0x0508, 0x0508,
+0x050a, 0x050a,
+0x050c, 0x050c,
+0x050e, 0x050e,
+0x0510, 0x0510,
+0x0512, 0x0512,
+0x0514, 0x0514,
+0x0516, 0x0516,
+0x0518, 0x0518,
+0x051a, 0x051a,
+0x051c, 0x051c,
+0x051e, 0x051e,
+0x0520, 0x0520,
+0x0522, 0x0522,
+0x0524, 0x0524,
+0x0526, 0x0526,
+0x0528, 0x0528,
+0x052a, 0x052a,
+0x052c, 0x052c,
+0x052e, 0x052e,
+0x0531, 0x0556,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x13a0, 0x13f5,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1e00, 0x1e00,
+0x1e02, 0x1e02,
+0x1e04, 0x1e04,
+0x1e06, 0x1e06,
+0x1e08, 0x1e08,
+0x1e0a, 0x1e0a,
+0x1e0c, 0x1e0c,
+0x1e0e, 0x1e0e,
+0x1e10, 0x1e10,
+0x1e12, 0x1e12,
+0x1e14, 0x1e14,
+0x1e16, 0x1e16,
+0x1e18, 0x1e18,
+0x1e1a, 0x1e1a,
+0x1e1c, 0x1e1c,
+0x1e1e, 0x1e1e,
+0x1e20, 0x1e20,
+0x1e22, 0x1e22,
+0x1e24, 0x1e24,
+0x1e26, 0x1e26,
+0x1e28, 0x1e28,
+0x1e2a, 0x1e2a,
+0x1e2c, 0x1e2c,
+0x1e2e, 0x1e2e,
+0x1e30, 0x1e30,
+0x1e32, 0x1e32,
+0x1e34, 0x1e34,
+0x1e36, 0x1e36,
+0x1e38, 0x1e38,
+0x1e3a, 0x1e3a,
+0x1e3c, 0x1e3c,
+0x1e3e, 0x1e3e,
+0x1e40, 0x1e40,
+0x1e42, 0x1e42,
+0x1e44, 0x1e44,
+0x1e46, 0x1e46,
+0x1e48, 0x1e48,
+0x1e4a, 0x1e4a,
+0x1e4c, 0x1e4c,
+0x1e4e, 0x1e4e,
+0x1e50, 0x1e50,
+0x1e52, 0x1e52,
+0x1e54, 0x1e54,
+0x1e56, 0x1e56,
+0x1e58, 0x1e58,
+0x1e5a, 0x1e5a,
+0x1e5c, 0x1e5c,
+0x1e5e, 0x1e5e,
+0x1e60, 0x1e60,
+0x1e62, 0x1e62,
+0x1e64, 0x1e64,
+0x1e66, 0x1e66,
+0x1e68, 0x1e68,
+0x1e6a, 0x1e6a,
+0x1e6c, 0x1e6c,
+0x1e6e, 0x1e6e,
+0x1e70, 0x1e70,
+0x1e72, 0x1e72,
+0x1e74, 0x1e74,
+0x1e76, 0x1e76,
+0x1e78, 0x1e78,
+0x1e7a, 0x1e7a,
+0x1e7c, 0x1e7c,
+0x1e7e, 0x1e7e,
+0x1e80, 0x1e80,
+0x1e82, 0x1e82,
+0x1e84, 0x1e84,
+0x1e86, 0x1e86,
+0x1e88, 0x1e88,
+0x1e8a, 0x1e8a,
+0x1e8c, 0x1e8c,
+0x1e8e, 0x1e8e,
+0x1e90, 0x1e90,
+0x1e92, 0x1e92,
+0x1e94, 0x1e94,
+0x1e9e, 0x1e9e,
+0x1ea0, 0x1ea0,
+0x1ea2, 0x1ea2,
+0x1ea4, 0x1ea4,
+0x1ea6, 0x1ea6,
+0x1ea8, 0x1ea8,
+0x1eaa, 0x1eaa,
+0x1eac, 0x1eac,
+0x1eae, 0x1eae,
+0x1eb0, 0x1eb0,
+0x1eb2, 0x1eb2,
+0x1eb4, 0x1eb4,
+0x1eb6, 0x1eb6,
+0x1eb8, 0x1eb8,
+0x1eba, 0x1eba,
+0x1ebc, 0x1ebc,
+0x1ebe, 0x1ebe,
+0x1ec0, 0x1ec0,
+0x1ec2, 0x1ec2,
+0x1ec4, 0x1ec4,
+0x1ec6, 0x1ec6,
+0x1ec8, 0x1ec8,
+0x1eca, 0x1eca,
+0x1ecc, 0x1ecc,
+0x1ece, 0x1ece,
+0x1ed0, 0x1ed0,
+0x1ed2, 0x1ed2,
+0x1ed4, 0x1ed4,
+0x1ed6, 0x1ed6,
+0x1ed8, 0x1ed8,
+0x1eda, 0x1eda,
+0x1edc, 0x1edc,
+0x1ede, 0x1ede,
+0x1ee0, 0x1ee0,
+0x1ee2, 0x1ee2,
+0x1ee4, 0x1ee4,
+0x1ee6, 0x1ee6,
+0x1ee8, 0x1ee8,
+0x1eea, 0x1eea,
+0x1eec, 0x1eec,
+0x1eee, 0x1eee,
+0x1ef0, 0x1ef0,
+0x1ef2, 0x1ef2,
+0x1ef4, 0x1ef4,
+0x1ef6, 0x1ef6,
+0x1ef8, 0x1ef8,
+0x1efa, 0x1efa,
+0x1efc, 0x1efc,
+0x1efe, 0x1efe,
+0x1f08, 0x1f0f,
+0x1f18, 0x1f1d,
+0x1f28, 0x1f2f,
+0x1f38, 0x1f3f,
+0x1f48, 0x1f4d,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f5f,
+0x1f68, 0x1f6f,
+0x1fb8, 0x1fbb,
+0x1fc8, 0x1fcb,
+0x1fd8, 0x1fdb,
+0x1fe8, 0x1fec,
+0x1ff8, 0x1ffb,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210b, 0x210d,
+0x2110, 0x2112,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x2130, 0x2133,
+0x213e, 0x213f,
+0x2145, 0x2145,
+0x2160, 0x216f,
+0x2183, 0x2183,
+0x24b6, 0x24cf,
+0x2c00, 0x2c2e,
+0x2c60, 0x2c60,
+0x2c62, 0x2c64,
+0x2c67, 0x2c67,
+0x2c69, 0x2c69,
+0x2c6b, 0x2c6b,
+0x2c6d, 0x2c70,
+0x2c72, 0x2c72,
+0x2c75, 0x2c75,
+0x2c7e, 0x2c80,
+0x2c82, 0x2c82,
+0x2c84, 0x2c84,
+0x2c86, 0x2c86,
+0x2c88, 0x2c88,
+0x2c8a, 0x2c8a,
+0x2c8c, 0x2c8c,
+0x2c8e, 0x2c8e,
+0x2c90, 0x2c90,
+0x2c92, 0x2c92,
+0x2c94, 0x2c94,
+0x2c96, 0x2c96,
+0x2c98, 0x2c98,
+0x2c9a, 0x2c9a,
+0x2c9c, 0x2c9c,
+0x2c9e, 0x2c9e,
+0x2ca0, 0x2ca0,
+0x2ca2, 0x2ca2,
+0x2ca4, 0x2ca4,
+0x2ca6, 0x2ca6,
+0x2ca8, 0x2ca8,
+0x2caa, 0x2caa,
+0x2cac, 0x2cac,
+0x2cae, 0x2cae,
+0x2cb0, 0x2cb0,
+0x2cb2, 0x2cb2,
+0x2cb4, 0x2cb4,
+0x2cb6, 0x2cb6,
+0x2cb8, 0x2cb8,
+0x2cba, 0x2cba,
+0x2cbc, 0x2cbc,
+0x2cbe, 0x2cbe,
+0x2cc0, 0x2cc0,
+0x2cc2, 0x2cc2,
+0x2cc4, 0x2cc4,
+0x2cc6, 0x2cc6,
+0x2cc8, 0x2cc8,
+0x2cca, 0x2cca,
+0x2ccc, 0x2ccc,
+0x2cce, 0x2cce,
+0x2cd0, 0x2cd0,
+0x2cd2, 0x2cd2,
+0x2cd4, 0x2cd4,
+0x2cd6, 0x2cd6,
+0x2cd8, 0x2cd8,
+0x2cda, 0x2cda,
+0x2cdc, 0x2cdc,
+0x2cde, 0x2cde,
+0x2ce0, 0x2ce0,
+0x2ce2, 0x2ce2,
+0x2ceb, 0x2ceb,
+0x2ced, 0x2ced,
+0x2cf2, 0x2cf2,
+0xa640, 0xa640,
+0xa642, 0xa642,
+0xa644, 0xa644,
+0xa646, 0xa646,
+0xa648, 0xa648,
+0xa64a, 0xa64a,
+0xa64c, 0xa64c,
+0xa64e, 0xa64e,
+0xa650, 0xa650,
+0xa652, 0xa652,
+0xa654, 0xa654,
+0xa656, 0xa656,
+0xa658, 0xa658,
+0xa65a, 0xa65a,
+0xa65c, 0xa65c,
+0xa65e, 0xa65e,
+0xa660, 0xa660,
+0xa662, 0xa662,
+0xa664, 0xa664,
+0xa666, 0xa666,
+0xa668, 0xa668,
+0xa66a, 0xa66a,
+0xa66c, 0xa66c,
+0xa680, 0xa680,
+0xa682, 0xa682,
+0xa684, 0xa684,
+0xa686, 0xa686,
+0xa688, 0xa688,
+0xa68a, 0xa68a,
+0xa68c, 0xa68c,
+0xa68e, 0xa68e,
+0xa690, 0xa690,
+0xa692, 0xa692,
+0xa694, 0xa694,
+0xa696, 0xa696,
+0xa698, 0xa698,
+0xa69a, 0xa69a,
+0xa722, 0xa722,
+0xa724, 0xa724,
+0xa726, 0xa726,
+0xa728, 0xa728,
+0xa72a, 0xa72a,
+0xa72c, 0xa72c,
+0xa72e, 0xa72e,
+0xa732, 0xa732,
+0xa734, 0xa734,
+0xa736, 0xa736,
+0xa738, 0xa738,
+0xa73a, 0xa73a,
+0xa73c, 0xa73c,
+0xa73e, 0xa73e,
+0xa740, 0xa740,
+0xa742, 0xa742,
+0xa744, 0xa744,
+0xa746, 0xa746,
+0xa748, 0xa748,
+0xa74a, 0xa74a,
+0xa74c, 0xa74c,
+0xa74e, 0xa74e,
+0xa750, 0xa750,
+0xa752, 0xa752,
+0xa754, 0xa754,
+0xa756, 0xa756,
+0xa758, 0xa758,
+0xa75a, 0xa75a,
+0xa75c, 0xa75c,
+0xa75e, 0xa75e,
+0xa760, 0xa760,
+0xa762, 0xa762,
+0xa764, 0xa764,
+0xa766, 0xa766,
+0xa768, 0xa768,
+0xa76a, 0xa76a,
+0xa76c, 0xa76c,
+0xa76e, 0xa76e,
+0xa779, 0xa779,
+0xa77b, 0xa77b,
+0xa77d, 0xa77e,
+0xa780, 0xa780,
+0xa782, 0xa782,
+0xa784, 0xa784,
+0xa786, 0xa786,
+0xa78b, 0xa78b,
+0xa78d, 0xa78d,
+0xa790, 0xa790,
+0xa792, 0xa792,
+0xa796, 0xa796,
+0xa798, 0xa798,
+0xa79a, 0xa79a,
+0xa79c, 0xa79c,
+0xa79e, 0xa79e,
+0xa7a0, 0xa7a0,
+0xa7a2, 0xa7a2,
+0xa7a4, 0xa7a4,
+0xa7a6, 0xa7a6,
+0xa7a8, 0xa7a8,
+0xa7aa, 0xa7ae,
+0xa7b0, 0xa7b4,
+0xa7b6, 0xa7b6,
+0xa7b8, 0xa7b8,
+0xa7ba, 0xa7ba,
+0xa7bc, 0xa7bc,
+0xa7be, 0xa7be,
+0xa7c2, 0xa7c2,
+0xa7c4, 0xa7c6,
+0xff21, 0xff3a,
+0x10400, 0x10427,
+0x104b0, 0x104d3,
+0x10c80, 0x10cb2,
+0x118a0, 0x118bf,
+0x16e40, 0x16e5f,
+0x1d400, 0x1d419,
+0x1d434, 0x1d44d,
+0x1d468, 0x1d481,
+0x1d49c, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b5,
+0x1d4d0, 0x1d4e9,
+0x1d504, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d538, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d56c, 0x1d585,
+0x1d5a0, 0x1d5b9,
+0x1d5d4, 0x1d5ed,
+0x1d608, 0x1d621,
+0x1d63c, 0x1d655,
+0x1d670, 0x1d689,
+0x1d6a8, 0x1d6c0,
+0x1d6e2, 0x1d6fa,
+0x1d71c, 0x1d734,
+0x1d756, 0x1d76e,
+0x1d790, 0x1d7a8,
+0x1d7ca, 0x1d7ca,
+0x1e900, 0x1e921,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+}; /* END of CR_Upper */
+
+/* PROPERTY: 'XDigit': POSIX [[:XDigit:]] */
+static const OnigCodePoint
+CR_XDigit[] = { 3,
+0x0030, 0x0039,
+0x0041, 0x0046,
+0x0061, 0x0066,
+}; /* END of CR_XDigit */
+
+/* PROPERTY: 'Word': POSIX [[:Word:]] */
+static const OnigCodePoint
+CR_Word[] = { 716,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x005f, 0x005f,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0300, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x0483, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x0591, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06df, 0x06e8,
+0x06ea, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x074a,
+0x074d, 0x07b1,
+0x07c0, 0x07f5,
+0x07fa, 0x07fa,
+0x07fd, 0x07fd,
+0x0800, 0x082d,
+0x0840, 0x085b,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d3, 0x08e1,
+0x08e3, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bc, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x09fe, 0x09fe,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3c, 0x0a3c,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4d,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abc, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acd,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0aff,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3c, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4d,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcd,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4d,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbc, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccd,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dca, 0x0dca,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e4e,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ec8, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f18, 0x0f19,
+0x0f20, 0x0f29,
+0x0f35, 0x0f35,
+0x0f37, 0x0f37,
+0x0f39, 0x0f39,
+0x0f3e, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f84,
+0x0f86, 0x0f97,
+0x0f99, 0x0fbc,
+0x0fc6, 0x0fc6,
+0x1000, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x135d, 0x135f,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1714,
+0x1720, 0x1734,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17d3,
+0x17d7, 0x17d7,
+0x17dc, 0x17dd,
+0x17e0, 0x17e9,
+0x180b, 0x180d,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x193b,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19d9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a60, 0x1a7c,
+0x1a7f, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1ab0, 0x1abe,
+0x1b00, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b6b, 0x1b73,
+0x1b80, 0x1bf3,
+0x1c00, 0x1c37,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1cd0, 0x1cd2,
+0x1cd4, 0x1cfa,
+0x1d00, 0x1df9,
+0x1dfb, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x203f, 0x2040,
+0x2054, 0x2054,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x20d0, 0x20f0,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d7f, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x302f,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x3099, 0x309a,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa672,
+0xa674, 0xa67d,
+0xa67f, 0xa6f1,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8e0, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92d,
+0xa930, 0xa953,
+0xa960, 0xa97c,
+0xa980, 0xa9c0,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf6,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabec, 0xabed,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe00, 0xfe0f,
+0xfe20, 0xfe2f,
+0xfe33, 0xfe34,
+0xfe4d, 0xfe4f,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff3f, 0xff3f,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x101fd, 0x101fd,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x102e0, 0x102e0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a38, 0x10a3a,
+0x10a3f, 0x10a3f,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae6,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f50,
+0x10fe0, 0x10ff6,
+0x11000, 0x11046,
+0x11066, 0x1106f,
+0x1107f, 0x110ba,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11134,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11173,
+0x11176, 0x11176,
+0x11180, 0x111c4,
+0x111c9, 0x111cc,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112ea,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133b, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134d,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11366, 0x1136c,
+0x11370, 0x11374,
+0x11400, 0x1144a,
+0x11450, 0x11459,
+0x1145e, 0x1145f,
+0x11480, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115c0,
+0x115d8, 0x115dd,
+0x11600, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172b,
+0x11730, 0x11739,
+0x11800, 0x1183a,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a3e,
+0x11a47, 0x11a47,
+0x11a50, 0x11a99,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16af0, 0x16af4,
+0x16b00, 0x16b36,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9d, 0x1bc9e,
+0x1d165, 0x1d169,
+0x1d16d, 0x1d172,
+0x1d17b, 0x1d182,
+0x1d185, 0x1d18b,
+0x1d1aa, 0x1d1ad,
+0x1d242, 0x1d244,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1da00, 0x1da36,
+0x1da3b, 0x1da6c,
+0x1da75, 0x1da75,
+0x1da84, 0x1da84,
+0x1da9b, 0x1da9f,
+0x1daa1, 0x1daaf,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e130, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e8d0, 0x1e8d6,
+0x1e900, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+0xe0100, 0xe01ef,
+}; /* END of CR_Word */
+
+/* PROPERTY: 'Alnum': POSIX [[:Alnum:]] */
+static const OnigCodePoint
+CR_Alnum[] = { 715,
+0x0030, 0x0039,
+0x0041, 0x005a,
+0x0061, 0x007a,
+0x00aa, 0x00aa,
+0x00b5, 0x00b5,
+0x00ba, 0x00ba,
+0x00c0, 0x00d6,
+0x00d8, 0x00f6,
+0x00f8, 0x02c1,
+0x02c6, 0x02d1,
+0x02e0, 0x02e4,
+0x02ec, 0x02ec,
+0x02ee, 0x02ee,
+0x0345, 0x0345,
+0x0370, 0x0374,
+0x0376, 0x0377,
+0x037a, 0x037d,
+0x037f, 0x037f,
+0x0386, 0x0386,
+0x0388, 0x038a,
+0x038c, 0x038c,
+0x038e, 0x03a1,
+0x03a3, 0x03f5,
+0x03f7, 0x0481,
+0x048a, 0x052f,
+0x0531, 0x0556,
+0x0559, 0x0559,
+0x0560, 0x0588,
+0x05b0, 0x05bd,
+0x05bf, 0x05bf,
+0x05c1, 0x05c2,
+0x05c4, 0x05c5,
+0x05c7, 0x05c7,
+0x05d0, 0x05ea,
+0x05ef, 0x05f2,
+0x0610, 0x061a,
+0x0620, 0x0657,
+0x0659, 0x0669,
+0x066e, 0x06d3,
+0x06d5, 0x06dc,
+0x06e1, 0x06e8,
+0x06ed, 0x06fc,
+0x06ff, 0x06ff,
+0x0710, 0x073f,
+0x074d, 0x07b1,
+0x07c0, 0x07ea,
+0x07f4, 0x07f5,
+0x07fa, 0x07fa,
+0x0800, 0x0817,
+0x081a, 0x082c,
+0x0840, 0x0858,
+0x0860, 0x086a,
+0x08a0, 0x08b4,
+0x08b6, 0x08bd,
+0x08d4, 0x08df,
+0x08e3, 0x08e9,
+0x08f0, 0x093b,
+0x093d, 0x094c,
+0x094e, 0x0950,
+0x0955, 0x0963,
+0x0966, 0x096f,
+0x0971, 0x0983,
+0x0985, 0x098c,
+0x098f, 0x0990,
+0x0993, 0x09a8,
+0x09aa, 0x09b0,
+0x09b2, 0x09b2,
+0x09b6, 0x09b9,
+0x09bd, 0x09c4,
+0x09c7, 0x09c8,
+0x09cb, 0x09cc,
+0x09ce, 0x09ce,
+0x09d7, 0x09d7,
+0x09dc, 0x09dd,
+0x09df, 0x09e3,
+0x09e6, 0x09f1,
+0x09fc, 0x09fc,
+0x0a01, 0x0a03,
+0x0a05, 0x0a0a,
+0x0a0f, 0x0a10,
+0x0a13, 0x0a28,
+0x0a2a, 0x0a30,
+0x0a32, 0x0a33,
+0x0a35, 0x0a36,
+0x0a38, 0x0a39,
+0x0a3e, 0x0a42,
+0x0a47, 0x0a48,
+0x0a4b, 0x0a4c,
+0x0a51, 0x0a51,
+0x0a59, 0x0a5c,
+0x0a5e, 0x0a5e,
+0x0a66, 0x0a75,
+0x0a81, 0x0a83,
+0x0a85, 0x0a8d,
+0x0a8f, 0x0a91,
+0x0a93, 0x0aa8,
+0x0aaa, 0x0ab0,
+0x0ab2, 0x0ab3,
+0x0ab5, 0x0ab9,
+0x0abd, 0x0ac5,
+0x0ac7, 0x0ac9,
+0x0acb, 0x0acc,
+0x0ad0, 0x0ad0,
+0x0ae0, 0x0ae3,
+0x0ae6, 0x0aef,
+0x0af9, 0x0afc,
+0x0b01, 0x0b03,
+0x0b05, 0x0b0c,
+0x0b0f, 0x0b10,
+0x0b13, 0x0b28,
+0x0b2a, 0x0b30,
+0x0b32, 0x0b33,
+0x0b35, 0x0b39,
+0x0b3d, 0x0b44,
+0x0b47, 0x0b48,
+0x0b4b, 0x0b4c,
+0x0b56, 0x0b57,
+0x0b5c, 0x0b5d,
+0x0b5f, 0x0b63,
+0x0b66, 0x0b6f,
+0x0b71, 0x0b71,
+0x0b82, 0x0b83,
+0x0b85, 0x0b8a,
+0x0b8e, 0x0b90,
+0x0b92, 0x0b95,
+0x0b99, 0x0b9a,
+0x0b9c, 0x0b9c,
+0x0b9e, 0x0b9f,
+0x0ba3, 0x0ba4,
+0x0ba8, 0x0baa,
+0x0bae, 0x0bb9,
+0x0bbe, 0x0bc2,
+0x0bc6, 0x0bc8,
+0x0bca, 0x0bcc,
+0x0bd0, 0x0bd0,
+0x0bd7, 0x0bd7,
+0x0be6, 0x0bef,
+0x0c00, 0x0c03,
+0x0c05, 0x0c0c,
+0x0c0e, 0x0c10,
+0x0c12, 0x0c28,
+0x0c2a, 0x0c39,
+0x0c3d, 0x0c44,
+0x0c46, 0x0c48,
+0x0c4a, 0x0c4c,
+0x0c55, 0x0c56,
+0x0c58, 0x0c5a,
+0x0c60, 0x0c63,
+0x0c66, 0x0c6f,
+0x0c80, 0x0c83,
+0x0c85, 0x0c8c,
+0x0c8e, 0x0c90,
+0x0c92, 0x0ca8,
+0x0caa, 0x0cb3,
+0x0cb5, 0x0cb9,
+0x0cbd, 0x0cc4,
+0x0cc6, 0x0cc8,
+0x0cca, 0x0ccc,
+0x0cd5, 0x0cd6,
+0x0cde, 0x0cde,
+0x0ce0, 0x0ce3,
+0x0ce6, 0x0cef,
+0x0cf1, 0x0cf2,
+0x0d00, 0x0d03,
+0x0d05, 0x0d0c,
+0x0d0e, 0x0d10,
+0x0d12, 0x0d3a,
+0x0d3d, 0x0d44,
+0x0d46, 0x0d48,
+0x0d4a, 0x0d4c,
+0x0d4e, 0x0d4e,
+0x0d54, 0x0d57,
+0x0d5f, 0x0d63,
+0x0d66, 0x0d6f,
+0x0d7a, 0x0d7f,
+0x0d82, 0x0d83,
+0x0d85, 0x0d96,
+0x0d9a, 0x0db1,
+0x0db3, 0x0dbb,
+0x0dbd, 0x0dbd,
+0x0dc0, 0x0dc6,
+0x0dcf, 0x0dd4,
+0x0dd6, 0x0dd6,
+0x0dd8, 0x0ddf,
+0x0de6, 0x0def,
+0x0df2, 0x0df3,
+0x0e01, 0x0e3a,
+0x0e40, 0x0e46,
+0x0e4d, 0x0e4d,
+0x0e50, 0x0e59,
+0x0e81, 0x0e82,
+0x0e84, 0x0e84,
+0x0e86, 0x0e8a,
+0x0e8c, 0x0ea3,
+0x0ea5, 0x0ea5,
+0x0ea7, 0x0eb9,
+0x0ebb, 0x0ebd,
+0x0ec0, 0x0ec4,
+0x0ec6, 0x0ec6,
+0x0ecd, 0x0ecd,
+0x0ed0, 0x0ed9,
+0x0edc, 0x0edf,
+0x0f00, 0x0f00,
+0x0f20, 0x0f29,
+0x0f40, 0x0f47,
+0x0f49, 0x0f6c,
+0x0f71, 0x0f81,
+0x0f88, 0x0f97,
+0x0f99, 0x0fbc,
+0x1000, 0x1036,
+0x1038, 0x1038,
+0x103b, 0x1049,
+0x1050, 0x109d,
+0x10a0, 0x10c5,
+0x10c7, 0x10c7,
+0x10cd, 0x10cd,
+0x10d0, 0x10fa,
+0x10fc, 0x1248,
+0x124a, 0x124d,
+0x1250, 0x1256,
+0x1258, 0x1258,
+0x125a, 0x125d,
+0x1260, 0x1288,
+0x128a, 0x128d,
+0x1290, 0x12b0,
+0x12b2, 0x12b5,
+0x12b8, 0x12be,
+0x12c0, 0x12c0,
+0x12c2, 0x12c5,
+0x12c8, 0x12d6,
+0x12d8, 0x1310,
+0x1312, 0x1315,
+0x1318, 0x135a,
+0x1380, 0x138f,
+0x13a0, 0x13f5,
+0x13f8, 0x13fd,
+0x1401, 0x166c,
+0x166f, 0x167f,
+0x1681, 0x169a,
+0x16a0, 0x16ea,
+0x16ee, 0x16f8,
+0x1700, 0x170c,
+0x170e, 0x1713,
+0x1720, 0x1733,
+0x1740, 0x1753,
+0x1760, 0x176c,
+0x176e, 0x1770,
+0x1772, 0x1773,
+0x1780, 0x17b3,
+0x17b6, 0x17c8,
+0x17d7, 0x17d7,
+0x17dc, 0x17dc,
+0x17e0, 0x17e9,
+0x1810, 0x1819,
+0x1820, 0x1878,
+0x1880, 0x18aa,
+0x18b0, 0x18f5,
+0x1900, 0x191e,
+0x1920, 0x192b,
+0x1930, 0x1938,
+0x1946, 0x196d,
+0x1970, 0x1974,
+0x1980, 0x19ab,
+0x19b0, 0x19c9,
+0x19d0, 0x19d9,
+0x1a00, 0x1a1b,
+0x1a20, 0x1a5e,
+0x1a61, 0x1a74,
+0x1a80, 0x1a89,
+0x1a90, 0x1a99,
+0x1aa7, 0x1aa7,
+0x1b00, 0x1b33,
+0x1b35, 0x1b43,
+0x1b45, 0x1b4b,
+0x1b50, 0x1b59,
+0x1b80, 0x1ba9,
+0x1bac, 0x1be5,
+0x1be7, 0x1bf1,
+0x1c00, 0x1c36,
+0x1c40, 0x1c49,
+0x1c4d, 0x1c7d,
+0x1c80, 0x1c88,
+0x1c90, 0x1cba,
+0x1cbd, 0x1cbf,
+0x1ce9, 0x1cec,
+0x1cee, 0x1cf3,
+0x1cf5, 0x1cf6,
+0x1cfa, 0x1cfa,
+0x1d00, 0x1dbf,
+0x1de7, 0x1df4,
+0x1e00, 0x1f15,
+0x1f18, 0x1f1d,
+0x1f20, 0x1f45,
+0x1f48, 0x1f4d,
+0x1f50, 0x1f57,
+0x1f59, 0x1f59,
+0x1f5b, 0x1f5b,
+0x1f5d, 0x1f5d,
+0x1f5f, 0x1f7d,
+0x1f80, 0x1fb4,
+0x1fb6, 0x1fbc,
+0x1fbe, 0x1fbe,
+0x1fc2, 0x1fc4,
+0x1fc6, 0x1fcc,
+0x1fd0, 0x1fd3,
+0x1fd6, 0x1fdb,
+0x1fe0, 0x1fec,
+0x1ff2, 0x1ff4,
+0x1ff6, 0x1ffc,
+0x2071, 0x2071,
+0x207f, 0x207f,
+0x2090, 0x209c,
+0x2102, 0x2102,
+0x2107, 0x2107,
+0x210a, 0x2113,
+0x2115, 0x2115,
+0x2119, 0x211d,
+0x2124, 0x2124,
+0x2126, 0x2126,
+0x2128, 0x2128,
+0x212a, 0x212d,
+0x212f, 0x2139,
+0x213c, 0x213f,
+0x2145, 0x2149,
+0x214e, 0x214e,
+0x2160, 0x2188,
+0x24b6, 0x24e9,
+0x2c00, 0x2c2e,
+0x2c30, 0x2c5e,
+0x2c60, 0x2ce4,
+0x2ceb, 0x2cee,
+0x2cf2, 0x2cf3,
+0x2d00, 0x2d25,
+0x2d27, 0x2d27,
+0x2d2d, 0x2d2d,
+0x2d30, 0x2d67,
+0x2d6f, 0x2d6f,
+0x2d80, 0x2d96,
+0x2da0, 0x2da6,
+0x2da8, 0x2dae,
+0x2db0, 0x2db6,
+0x2db8, 0x2dbe,
+0x2dc0, 0x2dc6,
+0x2dc8, 0x2dce,
+0x2dd0, 0x2dd6,
+0x2dd8, 0x2dde,
+0x2de0, 0x2dff,
+0x2e2f, 0x2e2f,
+0x3005, 0x3007,
+0x3021, 0x3029,
+0x3031, 0x3035,
+0x3038, 0x303c,
+0x3041, 0x3096,
+0x309d, 0x309f,
+0x30a1, 0x30fa,
+0x30fc, 0x30ff,
+0x3105, 0x312f,
+0x3131, 0x318e,
+0x31a0, 0x31ba,
+0x31f0, 0x31ff,
+0x3400, 0x4db5,
+0x4e00, 0x9fef,
+0xa000, 0xa48c,
+0xa4d0, 0xa4fd,
+0xa500, 0xa60c,
+0xa610, 0xa62b,
+0xa640, 0xa66e,
+0xa674, 0xa67b,
+0xa67f, 0xa6ef,
+0xa717, 0xa71f,
+0xa722, 0xa788,
+0xa78b, 0xa7bf,
+0xa7c2, 0xa7c6,
+0xa7f7, 0xa805,
+0xa807, 0xa827,
+0xa840, 0xa873,
+0xa880, 0xa8c3,
+0xa8c5, 0xa8c5,
+0xa8d0, 0xa8d9,
+0xa8f2, 0xa8f7,
+0xa8fb, 0xa8fb,
+0xa8fd, 0xa92a,
+0xa930, 0xa952,
+0xa960, 0xa97c,
+0xa980, 0xa9b2,
+0xa9b4, 0xa9bf,
+0xa9cf, 0xa9d9,
+0xa9e0, 0xa9fe,
+0xaa00, 0xaa36,
+0xaa40, 0xaa4d,
+0xaa50, 0xaa59,
+0xaa60, 0xaa76,
+0xaa7a, 0xaabe,
+0xaac0, 0xaac0,
+0xaac2, 0xaac2,
+0xaadb, 0xaadd,
+0xaae0, 0xaaef,
+0xaaf2, 0xaaf5,
+0xab01, 0xab06,
+0xab09, 0xab0e,
+0xab11, 0xab16,
+0xab20, 0xab26,
+0xab28, 0xab2e,
+0xab30, 0xab5a,
+0xab5c, 0xab67,
+0xab70, 0xabea,
+0xabf0, 0xabf9,
+0xac00, 0xd7a3,
+0xd7b0, 0xd7c6,
+0xd7cb, 0xd7fb,
+0xf900, 0xfa6d,
+0xfa70, 0xfad9,
+0xfb00, 0xfb06,
+0xfb13, 0xfb17,
+0xfb1d, 0xfb28,
+0xfb2a, 0xfb36,
+0xfb38, 0xfb3c,
+0xfb3e, 0xfb3e,
+0xfb40, 0xfb41,
+0xfb43, 0xfb44,
+0xfb46, 0xfbb1,
+0xfbd3, 0xfd3d,
+0xfd50, 0xfd8f,
+0xfd92, 0xfdc7,
+0xfdf0, 0xfdfb,
+0xfe70, 0xfe74,
+0xfe76, 0xfefc,
+0xff10, 0xff19,
+0xff21, 0xff3a,
+0xff41, 0xff5a,
+0xff66, 0xffbe,
+0xffc2, 0xffc7,
+0xffca, 0xffcf,
+0xffd2, 0xffd7,
+0xffda, 0xffdc,
+0x10000, 0x1000b,
+0x1000d, 0x10026,
+0x10028, 0x1003a,
+0x1003c, 0x1003d,
+0x1003f, 0x1004d,
+0x10050, 0x1005d,
+0x10080, 0x100fa,
+0x10140, 0x10174,
+0x10280, 0x1029c,
+0x102a0, 0x102d0,
+0x10300, 0x1031f,
+0x1032d, 0x1034a,
+0x10350, 0x1037a,
+0x10380, 0x1039d,
+0x103a0, 0x103c3,
+0x103c8, 0x103cf,
+0x103d1, 0x103d5,
+0x10400, 0x1049d,
+0x104a0, 0x104a9,
+0x104b0, 0x104d3,
+0x104d8, 0x104fb,
+0x10500, 0x10527,
+0x10530, 0x10563,
+0x10600, 0x10736,
+0x10740, 0x10755,
+0x10760, 0x10767,
+0x10800, 0x10805,
+0x10808, 0x10808,
+0x1080a, 0x10835,
+0x10837, 0x10838,
+0x1083c, 0x1083c,
+0x1083f, 0x10855,
+0x10860, 0x10876,
+0x10880, 0x1089e,
+0x108e0, 0x108f2,
+0x108f4, 0x108f5,
+0x10900, 0x10915,
+0x10920, 0x10939,
+0x10980, 0x109b7,
+0x109be, 0x109bf,
+0x10a00, 0x10a03,
+0x10a05, 0x10a06,
+0x10a0c, 0x10a13,
+0x10a15, 0x10a17,
+0x10a19, 0x10a35,
+0x10a60, 0x10a7c,
+0x10a80, 0x10a9c,
+0x10ac0, 0x10ac7,
+0x10ac9, 0x10ae4,
+0x10b00, 0x10b35,
+0x10b40, 0x10b55,
+0x10b60, 0x10b72,
+0x10b80, 0x10b91,
+0x10c00, 0x10c48,
+0x10c80, 0x10cb2,
+0x10cc0, 0x10cf2,
+0x10d00, 0x10d27,
+0x10d30, 0x10d39,
+0x10f00, 0x10f1c,
+0x10f27, 0x10f27,
+0x10f30, 0x10f45,
+0x10fe0, 0x10ff6,
+0x11000, 0x11045,
+0x11066, 0x1106f,
+0x11082, 0x110b8,
+0x110d0, 0x110e8,
+0x110f0, 0x110f9,
+0x11100, 0x11132,
+0x11136, 0x1113f,
+0x11144, 0x11146,
+0x11150, 0x11172,
+0x11176, 0x11176,
+0x11180, 0x111bf,
+0x111c1, 0x111c4,
+0x111d0, 0x111da,
+0x111dc, 0x111dc,
+0x11200, 0x11211,
+0x11213, 0x11234,
+0x11237, 0x11237,
+0x1123e, 0x1123e,
+0x11280, 0x11286,
+0x11288, 0x11288,
+0x1128a, 0x1128d,
+0x1128f, 0x1129d,
+0x1129f, 0x112a8,
+0x112b0, 0x112e8,
+0x112f0, 0x112f9,
+0x11300, 0x11303,
+0x11305, 0x1130c,
+0x1130f, 0x11310,
+0x11313, 0x11328,
+0x1132a, 0x11330,
+0x11332, 0x11333,
+0x11335, 0x11339,
+0x1133d, 0x11344,
+0x11347, 0x11348,
+0x1134b, 0x1134c,
+0x11350, 0x11350,
+0x11357, 0x11357,
+0x1135d, 0x11363,
+0x11400, 0x11441,
+0x11443, 0x11445,
+0x11447, 0x1144a,
+0x11450, 0x11459,
+0x1145f, 0x1145f,
+0x11480, 0x114c1,
+0x114c4, 0x114c5,
+0x114c7, 0x114c7,
+0x114d0, 0x114d9,
+0x11580, 0x115b5,
+0x115b8, 0x115be,
+0x115d8, 0x115dd,
+0x11600, 0x1163e,
+0x11640, 0x11640,
+0x11644, 0x11644,
+0x11650, 0x11659,
+0x11680, 0x116b5,
+0x116b8, 0x116b8,
+0x116c0, 0x116c9,
+0x11700, 0x1171a,
+0x1171d, 0x1172a,
+0x11730, 0x11739,
+0x11800, 0x11838,
+0x118a0, 0x118e9,
+0x118ff, 0x118ff,
+0x119a0, 0x119a7,
+0x119aa, 0x119d7,
+0x119da, 0x119df,
+0x119e1, 0x119e1,
+0x119e3, 0x119e4,
+0x11a00, 0x11a32,
+0x11a35, 0x11a3e,
+0x11a50, 0x11a97,
+0x11a9d, 0x11a9d,
+0x11ac0, 0x11af8,
+0x11c00, 0x11c08,
+0x11c0a, 0x11c36,
+0x11c38, 0x11c3e,
+0x11c40, 0x11c40,
+0x11c50, 0x11c59,
+0x11c72, 0x11c8f,
+0x11c92, 0x11ca7,
+0x11ca9, 0x11cb6,
+0x11d00, 0x11d06,
+0x11d08, 0x11d09,
+0x11d0b, 0x11d36,
+0x11d3a, 0x11d3a,
+0x11d3c, 0x11d3d,
+0x11d3f, 0x11d41,
+0x11d43, 0x11d43,
+0x11d46, 0x11d47,
+0x11d50, 0x11d59,
+0x11d60, 0x11d65,
+0x11d67, 0x11d68,
+0x11d6a, 0x11d8e,
+0x11d90, 0x11d91,
+0x11d93, 0x11d96,
+0x11d98, 0x11d98,
+0x11da0, 0x11da9,
+0x11ee0, 0x11ef6,
+0x12000, 0x12399,
+0x12400, 0x1246e,
+0x12480, 0x12543,
+0x13000, 0x1342e,
+0x14400, 0x14646,
+0x16800, 0x16a38,
+0x16a40, 0x16a5e,
+0x16a60, 0x16a69,
+0x16ad0, 0x16aed,
+0x16b00, 0x16b2f,
+0x16b40, 0x16b43,
+0x16b50, 0x16b59,
+0x16b63, 0x16b77,
+0x16b7d, 0x16b8f,
+0x16e40, 0x16e7f,
+0x16f00, 0x16f4a,
+0x16f4f, 0x16f87,
+0x16f8f, 0x16f9f,
+0x16fe0, 0x16fe1,
+0x16fe3, 0x16fe3,
+0x17000, 0x187f7,
+0x18800, 0x18af2,
+0x1b000, 0x1b11e,
+0x1b150, 0x1b152,
+0x1b164, 0x1b167,
+0x1b170, 0x1b2fb,
+0x1bc00, 0x1bc6a,
+0x1bc70, 0x1bc7c,
+0x1bc80, 0x1bc88,
+0x1bc90, 0x1bc99,
+0x1bc9e, 0x1bc9e,
+0x1d400, 0x1d454,
+0x1d456, 0x1d49c,
+0x1d49e, 0x1d49f,
+0x1d4a2, 0x1d4a2,
+0x1d4a5, 0x1d4a6,
+0x1d4a9, 0x1d4ac,
+0x1d4ae, 0x1d4b9,
+0x1d4bb, 0x1d4bb,
+0x1d4bd, 0x1d4c3,
+0x1d4c5, 0x1d505,
+0x1d507, 0x1d50a,
+0x1d50d, 0x1d514,
+0x1d516, 0x1d51c,
+0x1d51e, 0x1d539,
+0x1d53b, 0x1d53e,
+0x1d540, 0x1d544,
+0x1d546, 0x1d546,
+0x1d54a, 0x1d550,
+0x1d552, 0x1d6a5,
+0x1d6a8, 0x1d6c0,
+0x1d6c2, 0x1d6da,
+0x1d6dc, 0x1d6fa,
+0x1d6fc, 0x1d714,
+0x1d716, 0x1d734,
+0x1d736, 0x1d74e,
+0x1d750, 0x1d76e,
+0x1d770, 0x1d788,
+0x1d78a, 0x1d7a8,
+0x1d7aa, 0x1d7c2,
+0x1d7c4, 0x1d7cb,
+0x1d7ce, 0x1d7ff,
+0x1e000, 0x1e006,
+0x1e008, 0x1e018,
+0x1e01b, 0x1e021,
+0x1e023, 0x1e024,
+0x1e026, 0x1e02a,
+0x1e100, 0x1e12c,
+0x1e137, 0x1e13d,
+0x1e140, 0x1e149,
+0x1e14e, 0x1e14e,
+0x1e2c0, 0x1e2eb,
+0x1e2f0, 0x1e2f9,
+0x1e800, 0x1e8c4,
+0x1e900, 0x1e943,
+0x1e947, 0x1e947,
+0x1e94b, 0x1e94b,
+0x1e950, 0x1e959,
+0x1ee00, 0x1ee03,
+0x1ee05, 0x1ee1f,
+0x1ee21, 0x1ee22,
+0x1ee24, 0x1ee24,
+0x1ee27, 0x1ee27,
+0x1ee29, 0x1ee32,
+0x1ee34, 0x1ee37,
+0x1ee39, 0x1ee39,
+0x1ee3b, 0x1ee3b,
+0x1ee42, 0x1ee42,
+0x1ee47, 0x1ee47,
+0x1ee49, 0x1ee49,
+0x1ee4b, 0x1ee4b,
+0x1ee4d, 0x1ee4f,
+0x1ee51, 0x1ee52,
+0x1ee54, 0x1ee54,
+0x1ee57, 0x1ee57,
+0x1ee59, 0x1ee59,
+0x1ee5b, 0x1ee5b,
+0x1ee5d, 0x1ee5d,
+0x1ee5f, 0x1ee5f,
+0x1ee61, 0x1ee62,
+0x1ee64, 0x1ee64,
+0x1ee67, 0x1ee6a,
+0x1ee6c, 0x1ee72,
+0x1ee74, 0x1ee77,
+0x1ee79, 0x1ee7c,
+0x1ee7e, 0x1ee7e,
+0x1ee80, 0x1ee89,
+0x1ee8b, 0x1ee9b,
+0x1eea1, 0x1eea3,
+0x1eea5, 0x1eea9,
+0x1eeab, 0x1eebb,
+0x1f130, 0x1f149,
+0x1f150, 0x1f169,
+0x1f170, 0x1f189,
+0x20000, 0x2a6d6,
+0x2a700, 0x2b734,
+0x2b740, 0x2b81d,
+0x2b820, 0x2cea1,
+0x2ceb0, 0x2ebe0,
+0x2f800, 0x2fa1d,
+}; /* END of CR_Alnum */
+
+/* PROPERTY: 'ASCII': POSIX [[:ASCII:]] */
+static const OnigCodePoint
+CR_ASCII[] = { 1,
+0x0000, 0x007f,
+}; /* END of CR_ASCII */
+
+
+static const OnigCodePoint*
+const CodeRanges[] = {
+ CR_NEWLINE,
+ CR_Alpha,
+ CR_Blank,
+ CR_Cntrl,
+ CR_Digit,
+ CR_Graph,
+ CR_Lower,
+ CR_Print,
+ CR_Punct,
+ CR_Space,
+ CR_Upper,
+ CR_XDigit,
+ CR_Word,
+ CR_Alnum,
+ CR_ASCII,
+};
+
+#define pool_offset(s) offsetof(struct unicode_prop_name_pool_t, unicode_prop_name_pool_str##s)
+
+
+#define TOTAL_KEYWORDS 15
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 7
+#define MIN_HASH_VALUE 5
+#define MAX_HASH_VALUE 19
+/* maximum key range = 15, duplicates = 0 */
+
+#ifndef GPERF_DOWNCASE
+#define GPERF_DOWNCASE 1
+static unsigned char gperf_downcase[256] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255
+ };
+#endif
+
+#ifndef GPERF_CASE_STRNCMP
+#define GPERF_CASE_STRNCMP 1
+static int
+gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
+{
+ for (; n > 0;)
+ {
+ unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
+ unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
+ if (c1 != 0 && c1 == c2)
+ {
+ n--;
+ continue;
+ }
+ return (int)c1 - (int)c2;
+ }
+ return 0;
+}
+#endif
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (register const char *str, register size_t len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 2, 12, 5, 3, 20,
+ 20, 10, 20, 0, 20, 20, 9, 20, 1, 20,
+ 0, 20, 9, 7, 3, 6, 20, 2, 3, 20,
+ 20, 20, 20, 20, 20, 20, 20, 2, 12, 5,
+ 3, 20, 20, 10, 20, 0, 20, 20, 9, 20,
+ 1, 20, 0, 20, 9, 7, 3, 6, 20, 2,
+ 3, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20
+ };
+ return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
+}
+
+struct unicode_prop_name_pool_t
+ {
+ char unicode_prop_name_pool_str5[sizeof("print")];
+ char unicode_prop_name_pool_str6[sizeof("punct")];
+ char unicode_prop_name_pool_str7[sizeof("alpha")];
+ char unicode_prop_name_pool_str8[sizeof("alnum")];
+ char unicode_prop_name_pool_str9[sizeof("xdigit")];
+ char unicode_prop_name_pool_str10[sizeof("newline")];
+ char unicode_prop_name_pool_str11[sizeof("upper")];
+ char unicode_prop_name_pool_str12[sizeof("ascii")];
+ char unicode_prop_name_pool_str13[sizeof("cntrl")];
+ char unicode_prop_name_pool_str14[sizeof("space")];
+ char unicode_prop_name_pool_str15[sizeof("word")];
+ char unicode_prop_name_pool_str16[sizeof("lower")];
+ char unicode_prop_name_pool_str17[sizeof("graph")];
+ char unicode_prop_name_pool_str18[sizeof("digit")];
+ char unicode_prop_name_pool_str19[sizeof("blank")];
+ };
+static const struct unicode_prop_name_pool_t unicode_prop_name_pool_contents =
+ {
+ "print",
+ "punct",
+ "alpha",
+ "alnum",
+ "xdigit",
+ "newline",
+ "upper",
+ "ascii",
+ "cntrl",
+ "space",
+ "word",
+ "lower",
+ "graph",
+ "digit",
+ "blank"
+ };
+#define unicode_prop_name_pool ((const char *) &unicode_prop_name_pool_contents)
+static const struct PoolPropertyNameCtype *
+unicode_lookup_property_name (register const char *str, register size_t len)
+{
+ static const struct PoolPropertyNameCtype wordlist[] =
+ {
+ {-1}, {-1}, {-1}, {-1}, {-1},
+
+ {pool_offset(5), 7},
+
+ {pool_offset(6), 8},
+
+ {pool_offset(7), 1},
+
+ {pool_offset(8), 13},
+
+ {pool_offset(9), 11},
+
+ {pool_offset(10), 0},
+
+ {pool_offset(11), 10},
+
+ {pool_offset(12), 14},
+
+ {pool_offset(13), 3},
+
+ {pool_offset(14), 9},
+
+ {pool_offset(15), 12},
+
+ {pool_offset(16), 6},
+
+ {pool_offset(17), 5},
+
+ {pool_offset(18), 4},
+
+ {pool_offset(19), 2}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + unicode_prop_name_pool;
+
+ if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+#define PROPERTY_NAME_MAX_SIZE 17
+#define CODE_RANGES_NUM 15
+
+#define PROP_INDEX_NEWLINE 0
+#define PROP_INDEX_ALPHA 1
+#define PROP_INDEX_BLANK 2
+#define PROP_INDEX_CNTRL 3
+#define PROP_INDEX_DIGIT 4
+#define PROP_INDEX_GRAPH 5
+#define PROP_INDEX_LOWER 6
+#define PROP_INDEX_PRINT 7
+#define PROP_INDEX_PUNCT 8
+#define PROP_INDEX_SPACE 9
+#define PROP_INDEX_UPPER 10
+#define PROP_INDEX_XDIGIT 11
+#define PROP_INDEX_WORD 12
+#define PROP_INDEX_ALNUM 13
+#define PROP_INDEX_ASCII 14
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_unfold_key.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_unfold_key.c
new file mode 100644
index 000000000..65bfa2603
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_unfold_key.c
@@ -0,0 +1,3303 @@
+/* This file was converted by gperf_unfold_key_conv.py
+ from gperf output file. */
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -n -C -T -c -t -j1 -L ANSI-C -F,-1,0 -N onigenc_unicode_unfold_key unicode_unfold_key.gperf */
+/* Computed positions: -k'1-3' */
+
+
+
+/* This gperf source file was generated by make_unicode_fold_data.py */
+
+/*-
+ * Copyright (c) 2017-2020 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#include "regint.h"
+
+#define TOTAL_KEYWORDS 1487
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 3
+#define MIN_HASH_VALUE 10
+#define MAX_HASH_VALUE 1958
+/* maximum key range = 1949, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+hash(OnigCodePoint codes[])
+{
+ static const unsigned short asso_values[] =
+ {
+ 9, 5, 2, 111, 176, 1, 110, 1959, 1959, 1959,
+ 1959, 1959, 1959, 13, 1959, 1959, 1959, 77, 1959, 1959,
+ 63, 1959, 1959, 1959, 1959, 86, 1959, 1959, 1959, 7,
+ 1959, 0, 3, 1959, 191, 624, 1536, 132, 1519, 613,
+ 1513, 607, 1602, 586, 1505, 4, 1497, 570, 1492, 554,
+ 1482, 907, 1601, 898, 1469, 595, 1468, 405, 1463, 546,
+ 1458, 538, 1453, 474, 1444, 890, 1596, 877, 1419, 725,
+ 1590, 698, 1588, 635, 1160, 682, 1021, 338, 1122, 671,
+ 812, 559, 819, 1580, 756, 1082, 744, 1438, 637, 1428,
+ 266, 1429, 1502, 1285, 1440, 1578, 467, 1419, 873, 490,
+ 1380, 779, 731, 1057, 1261, 1034, 1567, 762, 1389, 495,
+ 1510, 156, 648, 805, 1537, 862, 1523, 853, 1469, 845,
+ 1252, 796, 342, 1297, 801, 1287, 542, 1408, 477, 1400,
+ 237, 1109, 20, 1099, 548, 1067, 1, 1280, 326, 1043,
+ 767, 1030, 756, 938, 598, 254, 26, 1275, 165, 1270,
+ 149, 1575, 15, 1368, 133, 1202, 625, 403, 408, 373,
+ 296, 1397, 283, 519, 1381, 503, 1372, 18, 6, 415,
+ 1253, 769, 8, 484, 1358, 658, 1565, 464, 427, 244,
+ 1241, 360, 1233, 390, 1350, 219, 377, 206, 1223, 328,
+ 1211, 145, 1198, 454, 135, 73, 1020, 103, 1012, 63,
+ 995, 53, 748, 196, 573, 116, 684, 93, 983, 83,
+ 1004, 182, 735, 31, 713, 319, 977, 306, 706, 44,
+ 836, 293, 1187, 280, 1135, 268, 671, 976, 1350, 447,
+ 1182, 437, 964, 946, 351, 932, 1349, 923, 1090, 1194,
+ 1175, 827, 1299, 1165, 1410, 1155, 1522, 1557, 313, 1146,
+ 424, 1136, 233, 1130, 161, 1316, 93, 167, 134, 618,
+ 1959, 1118, 128, 1342, 1959, 1335, 124, 1331, 75, 1327,
+ 191, 1308, 45, 1545, 1959, 1534, 1, 230, 9, 643,
+ 5, 1564, 40, 1553, 65, 531, 55, 993, 25, 1476,
+ 2
+ };
+ return asso_values[(unsigned char)onig_codes_byte_at(codes, 2)+35] + asso_values[(unsigned char)onig_codes_byte_at(codes, 1)+1] + asso_values[(unsigned char)onig_codes_byte_at(codes, 0)];
+}
+
+const struct ByUnfoldKey *
+onigenc_unicode_unfold_key(OnigCodePoint code)
+{
+ static const struct ByUnfoldKey wordlist[] =
+ {
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1040a, 3441, 1},
+ {0xffffffff, -1, 0},
+
+ {0x01f1, 483, 1},
+
+ {0x1e0a, 1882, 1},
+
+ {0x040a, 1029, 1},
+
+ {0x010a, 186, 1},
+
+ {0x1f0a, 2243, 1},
+
+ {0x2c0a, 2606, 1},
+
+ {0x1f85, 154, 2},
+
+ {0x0189, 619, 1},
+
+ {0x1f89, 134, 2},
+
+ {0x1ff3, 96, 2},
+
+ {0x1c85, 954, 1},
+
+ {0xab85, 1663, 1},
+
+ {0x10c85, 3654, 1},
+
+ {0xab89, 1675, 1},
+
+ {0x10c89, 3666, 1},
+
+ {0x1e84, 2066, 1},
+
+ {0x2c75, 2738, 1},
+
+ {0x0184, 360, 1},
+
+ {0x1f84, 149, 2},
+
+ {0x2c84, 2747, 1},
+
+ {0xab75, 1615, 1},
+
+ {0xa784, 3261, 1},
+
+ {0x1c84, 954, 1},
+
+ {0xab84, 1660, 1},
+
+ {0x10c84, 3651, 1},
+
+ {0x104b2, 3537, 1},
+
+ {0x1f6f, 2378, 1},
+
+ {0x2c6f, 604, 1},
+
+ {0x1eb2, 2120, 1},
+
+ {0x04b2, 1159, 1},
+
+ {0x01b2, 700, 1},
+
+ {0x1fb2, 249, 2},
+
+ {0x2cb2, 2816, 1},
+
+ {0xa684, 3096, 1},
+
+ {0xa7b2, 709, 1},
+
+ {0x1cb2, 1564, 1},
+
+ {0xabb2, 1798, 1},
+
+ {0x10cb2, 3789, 1},
+
+ {0x104b8, 3555, 1},
+
+ {0x01f7, 414, 1},
+
+ {0x1ff7, 67, 3},
+
+ {0x1eb8, 2129, 1},
+
+ {0x04b8, 1168, 1},
+
+ {0x01b8, 408, 1},
+
+ {0x1fb8, 2423, 1},
+
+ {0x2cb8, 2825, 1},
+
+ {0x2ced, 2894, 1},
+
+ {0xa7b8, 3315, 1},
+
+ {0x1cb8, 1582, 1},
+
+ {0xabb8, 1816, 1},
+
+ {0x1ea6, 2102, 1},
+
+ {0x04a6, 1141, 1},
+
+ {0x01a6, 679, 1},
+
+ {0x1fa6, 239, 2},
+
+ {0x2ca6, 2798, 1},
+
+ {0x1ffb, 2420, 1},
+
+ {0xa7a6, 3303, 1},
+
+ {0x1ca6, 1528, 1},
+
+ {0xaba6, 1762, 1},
+
+ {0x10ca6, 3753, 1},
+
+ {0x1ea4, 2099, 1},
+
+ {0x04a4, 1138, 1},
+
+ {0x01a4, 390, 1},
+
+ {0x1fa4, 229, 2},
+
+ {0x2ca4, 2795, 1},
+
+ {0x1ff9, 2408, 1},
+
+ {0xa7a4, 3300, 1},
+
+ {0x1ca4, 1522, 1},
+
+ {0xaba4, 1756, 1},
+
+ {0x10ca4, 3747, 1},
+
+ {0x1ea0, 2093, 1},
+
+ {0x04a0, 1132, 1},
+
+ {0x01a0, 384, 1},
+
+ {0x1fa0, 209, 2},
+
+ {0x2ca0, 2789, 1},
+
+ {0x1fe9, 2438, 1},
+
+ {0xa7a0, 3294, 1},
+
+ {0x1ca0, 1510, 1},
+
+ {0xaba0, 1744, 1},
+
+ {0x10ca0, 3735, 1},
+
+ {0x1eae, 2114, 1},
+
+ {0x04ae, 1153, 1},
+
+ {0x01ae, 691, 1},
+
+ {0x1fae, 239, 2},
+
+ {0x2cae, 2810, 1},
+
+ {0x13fd, 1855, 1},
+
+ {0xa7ae, 655, 1},
+
+ {0x1cae, 1552, 1},
+
+ {0xabae, 1786, 1},
+
+ {0x10cae, 3777, 1},
+
+ {0x1eac, 2111, 1},
+
+ {0x04ac, 1150, 1},
+
+ {0x01ac, 396, 1},
+
+ {0x1fac, 229, 2},
+
+ {0x2cac, 2807, 1},
+
+ {0x00dd, 162, 1},
+
+ {0xa7ac, 637, 1},
+
+ {0x1cac, 1546, 1},
+
+ {0xabac, 1780, 1},
+
+ {0x10cac, 3771, 1},
+
+ {0x1ea2, 2096, 1},
+
+ {0x04a2, 1135, 1},
+
+ {0x01a2, 387, 1},
+
+ {0x1fa2, 219, 2},
+
+ {0x2ca2, 2792, 1},
+
+ {0x10b2, 2954, 1},
+
+ {0xa7a2, 3297, 1},
+
+ {0x1ca2, 1516, 1},
+
+ {0xaba2, 1750, 1},
+
+ {0x10ca2, 3741, 1},
+
+ {0x118b2, 3846, 1},
+
+ {0x050a, 1291, 1},
+
+ {0x020a, 517, 1},
+
+ {0x1eaa, 2108, 1},
+
+ {0x04aa, 1147, 1},
+
+ {0x13fb, 1849, 1},
+
+ {0x1faa, 219, 2},
+
+ {0x2caa, 2804, 1},
+
+ {0x10b8, 2972, 1},
+
+ {0xa7aa, 646, 1},
+
+ {0x1caa, 1540, 1},
+
+ {0xabaa, 1774, 1},
+
+ {0x10caa, 3765, 1},
+
+ {0x118b8, 3864, 1},
+
+ {0x1fe7, 47, 3},
+
+ {0x13f9, 1843, 1},
+
+ {0x10402, 3417, 1},
+
+ {0x10a6, 2918, 1},
+
+ {0x1fe3, 41, 3},
+
+ {0x1e02, 1870, 1},
+
+ {0x0402, 1005, 1},
+
+ {0x0102, 174, 1},
+
+ {0x118a6, 3810, 1},
+
+ {0x2c02, 2582, 1},
+
+ {0x019f, 673, 1},
+
+ {0x1f9f, 204, 2},
+
+ {0x00df, 24, 2},
+
+ {0x10a4, 2912, 1},
+
+ {0xab77, 1621, 1},
+
+ {0x1c9f, 1507, 1},
+
+ {0xab9f, 1741, 1},
+
+ {0x10c9f, 3732, 1},
+
+ {0x118a4, 3804, 1},
+
+ {0x049c, 1126, 1},
+
+ {0x019c, 664, 1},
+
+ {0x1f9c, 189, 2},
+
+ {0x2c9c, 2783, 1},
+
+ {0x10a0, 2900, 1},
+
+ {0xa79c, 3288, 1},
+
+ {0x1c9c, 1498, 1},
+
+ {0xab9c, 1732, 1},
+
+ {0x10c9c, 3723, 1},
+
+ {0x118a0, 3792, 1},
+
+ {0x1e4c, 1981, 1},
+
+ {0xab73, 1609, 1},
+
+ {0x014c, 279, 1},
+
+ {0x1f4c, 2339, 1},
+
+ {0x10ae, 2942, 1},
+
+ {0x004c, 31, 1},
+
+ {0xa74c, 3192, 1},
+
+ {0x01db, 450, 1},
+
+ {0x1fdb, 2402, 1},
+
+ {0x118ae, 3834, 1},
+
+ {0x00db, 156, 1},
+
+ {0x1ede, 2186, 1},
+
+ {0x04de, 1225, 1},
+
+ {0x01de, 456, 1},
+
+ {0x10ac, 2936, 1},
+
+ {0x2cde, 2882, 1},
+
+ {0x00de, 165, 1},
+
+ {0xab71, 1603, 1},
+
+ {0xa64c, 3039, 1},
+
+ {0x118ac, 3828, 1},
+
+ {0x24b8, 2504, 1},
+
+ {0x03f1, 802, 1},
+
+ {0x03ff, 730, 1},
+
+ {0x104b0, 3531, 1},
+
+ {0x10a2, 2906, 1},
+
+ {0x03f5, 758, 1},
+
+ {0x1eb0, 2117, 1},
+
+ {0x04b0, 1156, 1},
+
+ {0x0389, 739, 1},
+
+ {0x118a2, 3798, 1},
+
+ {0x2cb0, 2813, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa7b0, 712, 1},
+
+ {0x1cb0, 1558, 1},
+
+ {0xabb0, 1792, 1},
+
+ {0x10cb0, 3783, 1},
+
+ {0x2165, 2462, 1},
+
+ {0x10aa, 2930, 1},
+
+ {0x1feb, 2414, 1},
+
+ {0x2ceb, 2891, 1},
+
+ {0x1ea8, 2105, 1},
+
+ {0x04a8, 1144, 1},
+
+ {0x118aa, 3822, 1},
+
+ {0x1fa8, 209, 2},
+
+ {0x2ca8, 2801, 1},
+
+ {0x03fd, 724, 1},
+
+ {0xa7a8, 3306, 1},
+
+ {0x1ca8, 1534, 1},
+
+ {0xaba8, 1768, 1},
+
+ {0x10ca8, 3759, 1},
+
+ {0x1e98, 38, 2},
+
+ {0x0498, 1120, 1},
+
+ {0x0198, 375, 1},
+
+ {0x1f98, 169, 2},
+
+ {0x2c98, 2777, 1},
+
+ {0x2161, 2450, 1},
+
+ {0xa798, 3282, 1},
+
+ {0x1c98, 1486, 1},
+
+ {0xab98, 1720, 1},
+
+ {0x10c98, 3711, 1},
+
+ {0x03f7, 890, 1},
+
+ {0x216f, 2492, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e96, 16, 2},
+
+ {0x0496, 1117, 1},
+
+ {0x0196, 652, 1},
+
+ {0x1f96, 199, 2},
+
+ {0x2c96, 2774, 1},
+
+ {0xa698, 3126, 1},
+
+ {0xa796, 3279, 1},
+
+ {0x1c96, 1480, 1},
+
+ {0xab96, 1714, 1},
+
+ {0x10c96, 3705, 1},
+
+ {0x03a6, 816, 1},
+
+ {0x1ef2, 2216, 1},
+
+ {0x04f2, 1255, 1},
+
+ {0x01f2, 483, 1},
+
+ {0x1ff2, 257, 2},
+
+ {0x2cf2, 2897, 1},
+
+ {0x01d9, 447, 1},
+
+ {0x1fd9, 2432, 1},
+
+ {0xa696, 3123, 1},
+
+ {0x00d9, 150, 1},
+
+ {0x03a4, 810, 1},
+
+ {0x1f5f, 2354, 1},
+
+ {0x03f9, 884, 1},
+
+ {0x0502, 1279, 1},
+
+ {0x0202, 505, 1},
+
+ {0x1e90, 2084, 1},
+
+ {0x0490, 1108, 1},
+
+ {0x0190, 628, 1},
+
+ {0x1f90, 169, 2},
+
+ {0x2c90, 2765, 1},
+
+ {0x03a0, 798, 1},
+
+ {0xa790, 3270, 1},
+
+ {0x1c90, 1462, 1},
+
+ {0xab90, 1696, 1},
+
+ {0x10c90, 3687, 1},
+
+ {0x1e6e, 2033, 1},
+
+ {0x046e, 1069, 1},
+
+ {0x016e, 330, 1},
+
+ {0x1f6e, 2375, 1},
+
+ {0x2c6e, 667, 1},
+
+ {0x10b0, 2948, 1},
+
+ {0xa76e, 3243, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa690, 3114, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118b0, 3840, 1},
+
+ {0x104be, 3573, 1},
+
+ {0x054c, 1429, 1},
+
+ {0x024c, 598, 1},
+
+ {0x1ebe, 2138, 1},
+
+ {0x04be, 1177, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1fbe, 773, 1},
+
+ {0x2cbe, 2834, 1},
+
+ {0x10a8, 2924, 1},
+
+ {0xa7be, 3324, 1},
+
+ {0x1cbe, 1594, 1},
+
+ {0xabbe, 1834, 1},
+
+ {0x104bc, 3567, 1},
+
+ {0x118a8, 3816, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1ebc, 2135, 1},
+
+ {0x04bc, 1174, 1},
+
+ {0x01bc, 411, 1},
+
+ {0x1fbc, 62, 2},
+
+ {0x2cbc, 2831, 1},
+
+ {0x017f, 52, 1},
+
+ {0xa7bc, 3321, 1},
+
+ {0x2c7f, 583, 1},
+
+ {0xabbc, 1828, 1},
+ {0xffffffff, -1, 0},
+
+ {0x104ba, 3561, 1},
+
+ {0xab7f, 1645, 1},
+
+ {0x03aa, 830, 1},
+
+ {0x1eba, 2132, 1},
+
+ {0x04ba, 1171, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1fba, 2381, 1},
+
+ {0x2cba, 2828, 1},
+
+ {0x017d, 351, 1},
+
+ {0xa7ba, 3318, 1},
+
+ {0x1cba, 1588, 1},
+
+ {0xabba, 1822, 1},
+
+ {0xa77d, 1858, 1},
+
+ {0x104b6, 3549, 1},
+
+ {0xab7d, 1639, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1eb6, 2126, 1},
+
+ {0x04b6, 1165, 1},
+
+ {0x16e4c, 3924, 1},
+
+ {0x1fb6, 58, 2},
+
+ {0x2cb6, 2822, 1},
+
+ {0x039f, 795, 1},
+
+ {0xa7b6, 3312, 1},
+
+ {0x1cb6, 1576, 1},
+
+ {0xabb6, 1810, 1},
+
+ {0x01d5, 441, 1},
+
+ {0x104b4, 3543, 1},
+ {0xffffffff, -1, 0},
+
+ {0x00d5, 141, 1},
+
+ {0x1eb4, 2123, 1},
+
+ {0x04b4, 1162, 1},
+
+ {0x039c, 785, 1},
+
+ {0x1fb4, 50, 2},
+
+ {0x2cb4, 2819, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa7b4, 3309, 1},
+
+ {0x1cb4, 1570, 1},
+
+ {0xabb4, 1804, 1},
+
+ {0x1e9a, 0, 2},
+
+ {0x049a, 1123, 1},
+
+ {0x2c67, 2726, 1},
+
+ {0x1f9a, 179, 2},
+
+ {0x2c9a, 2780, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa79a, 3285, 1},
+
+ {0x1c9a, 1492, 1},
+
+ {0xab9a, 1726, 1},
+
+ {0x10c9a, 3717, 1},
+
+ {0x1e2a, 1930, 1},
+
+ {0x042a, 980, 1},
+
+ {0x012a, 234, 1},
+
+ {0x1f2a, 2285, 1},
+
+ {0x2c2a, 2702, 1},
+
+ {0x03de, 857, 1},
+
+ {0xa72a, 3144, 1},
+
+ {0x10be, 2990, 1},
+
+ {0xa69a, 3129, 1},
+
+ {0x0057, 65, 1},
+
+ {0x104c7, 3600, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118be, 3882, 1},
+
+ {0x1e90a, 4014, 1},
+
+ {0x04c7, 1189, 1},
+
+ {0x01c7, 421, 1},
+
+ {0x1fc7, 15, 3},
+ {0xffffffff, -1, 0},
+
+ {0x00c7, 99, 1},
+
+ {0x10bc, 2984, 1},
+
+ {0x03b0, 41, 3},
+
+ {0xff37, 3399, 1},
+
+ {0x1e92, 2087, 1},
+
+ {0x0492, 1111, 1},
+
+ {0x118bc, 3876, 1},
+
+ {0x1f92, 179, 2},
+
+ {0x2c92, 2768, 1},
+
+ {0xfb02, 12, 2},
+
+ {0xa792, 3273, 1},
+
+ {0x1c92, 1468, 1},
+
+ {0xab92, 1702, 1},
+
+ {0x10c92, 3693, 1},
+
+ {0x10ba, 2978, 1},
+ {0xffffffff, -1, 0},
+
+ {0x03a8, 823, 1},
+
+ {0x1e7c, 2054, 1},
+
+ {0x047c, 1090, 1},
+
+ {0x118ba, 3870, 1},
+
+ {0x0537, 1366, 1},
+
+ {0x1e97, 34, 2},
+
+ {0xa692, 3117, 1},
+
+ {0x0197, 649, 1},
+
+ {0x1f97, 204, 2},
+
+ {0xab7c, 1636, 1},
+
+ {0x0398, 768, 1},
+
+ {0x10b6, 2966, 1},
+
+ {0x1c97, 1483, 1},
+
+ {0xab97, 1717, 1},
+
+ {0x10c97, 3708, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118b6, 3858, 1},
+
+ {0x16e5f, 3981, 1},
+
+ {0x1e94, 2090, 1},
+
+ {0x0494, 1114, 1},
+
+ {0x0194, 640, 1},
+
+ {0x1f94, 189, 2},
+
+ {0x2c94, 2771, 1},
+
+ {0x0396, 762, 1},
+
+ {0x10b4, 2960, 1},
+
+ {0x1c94, 1474, 1},
+
+ {0xab94, 1708, 1},
+
+ {0x10c94, 3699, 1},
+
+ {0x24be, 2522, 1},
+
+ {0x118b4, 3852, 1},
+
+ {0x10416, 3477, 1},
+
+ {0x1e7a, 2051, 1},
+
+ {0x047a, 1087, 1},
+
+ {0x1e16, 1900, 1},
+
+ {0x0416, 916, 1},
+
+ {0x0116, 204, 1},
+
+ {0xa694, 3120, 1},
+
+ {0x2c16, 2642, 1},
+
+ {0x017b, 348, 1},
+
+ {0xab7a, 1630, 1},
+
+ {0x24bc, 2516, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa77b, 3249, 1},
+
+ {0x1e86, 2069, 1},
+
+ {0xab7b, 1633, 1},
+
+ {0x0186, 616, 1},
+
+ {0x1f86, 159, 2},
+
+ {0x2c86, 2750, 1},
+
+ {0x0390, 25, 3},
+
+ {0xa786, 3264, 1},
+
+ {0x1c86, 980, 1},
+
+ {0xab86, 1666, 1},
+
+ {0x10c86, 3657, 1},
+
+ {0x24ba, 2510, 1},
+
+ {0x01d7, 444, 1},
+
+ {0x1fd7, 31, 3},
+
+ {0x10c7, 3014, 1},
+
+ {0x018f, 625, 1},
+
+ {0x1f8f, 164, 2},
+
+ {0xff2a, 3360, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa686, 3099, 1},
+
+ {0x104c4, 3591, 1},
+
+ {0xab8f, 1693, 1},
+
+ {0x10c8f, 3684, 1},
+
+ {0x1ec4, 2147, 1},
+
+ {0x24b6, 2498, 1},
+
+ {0x01c4, 417, 1},
+
+ {0x1fc4, 54, 2},
+
+ {0x2cc4, 2843, 1},
+
+ {0x00c4, 89, 1},
+
+ {0xa7c4, 3276, 1},
+
+ {0x104c2, 3585, 1},
+
+ {0x216e, 2489, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1ec2, 2144, 1},
+
+ {0x052a, 1339, 1},
+
+ {0x022a, 562, 1},
+
+ {0x1fc2, 253, 2},
+
+ {0x2cc2, 2840, 1},
+
+ {0x00c2, 83, 1},
+
+ {0xa7c2, 3327, 1},
+
+ {0x1e9e, 24, 2},
+
+ {0x049e, 1129, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f9e, 199, 2},
+
+ {0x2c9e, 2786, 1},
+
+ {0x037f, 887, 1},
+
+ {0xa79e, 3291, 1},
+
+ {0x1c9e, 1504, 1},
+
+ {0xab9e, 1738, 1},
+
+ {0x10c9e, 3729, 1},
+
+ {0x1e8e, 2081, 1},
+
+ {0x048e, 1105, 1},
+
+ {0x018e, 453, 1},
+
+ {0x1f8e, 159, 2},
+
+ {0x2c8e, 2762, 1},
+
+ {0x013d, 258, 1},
+
+ {0x1f3d, 2318, 1},
+
+ {0x1041c, 3495, 1},
+
+ {0xab8e, 1690, 1},
+
+ {0x10c8e, 3681, 1},
+
+ {0x1e1c, 1909, 1},
+
+ {0x041c, 934, 1},
+
+ {0x011c, 213, 1},
+
+ {0x1f1c, 2273, 1},
+
+ {0x2c1c, 2660, 1},
+
+ {0x1e902, 3990, 1},
+
+ {0x1f5d, 2351, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa68e, 3111, 1},
+
+ {0x24c7, 2549, 1},
+
+ {0x1e8a, 2075, 1},
+
+ {0x048a, 1099, 1},
+
+ {0x018a, 622, 1},
+
+ {0x1f8a, 139, 2},
+
+ {0x2c8a, 2756, 1},
+
+ {0x03d5, 816, 1},
+
+ {0x1e40, 1963, 1},
+ {0xffffffff, -1, 0},
+
+ {0xab8a, 1678, 1},
+
+ {0x10c8a, 3669, 1},
+
+ {0x16e57, 3957, 1},
+
+ {0x1e4a, 1978, 1},
+
+ {0xa740, 3174, 1},
+
+ {0x014a, 276, 1},
+
+ {0x1f4a, 2333, 1},
+ {0xffffffff, -1, 0},
+
+ {0x004a, 24, 1},
+
+ {0xa74a, 3189, 1},
+
+ {0xa68a, 3105, 1},
+
+ {0x1e82, 2063, 1},
+
+ {0x039a, 778, 1},
+
+ {0x0182, 357, 1},
+
+ {0x1f82, 139, 2},
+
+ {0x2c82, 2744, 1},
+
+ {0xa640, 3020, 1},
+
+ {0xa782, 3258, 1},
+
+ {0x1c82, 940, 1},
+
+ {0xab82, 1654, 1},
+
+ {0x10c82, 3645, 1},
+
+ {0xa64a, 3035, 1},
+
+ {0x10c4, 3008, 1},
+
+ {0x0516, 1309, 1},
+
+ {0x0216, 535, 1},
+
+ {0x2167, 2468, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e80, 2060, 1},
+
+ {0x0480, 1096, 1},
+
+ {0xa682, 3093, 1},
+
+ {0x1f80, 129, 2},
+
+ {0x2c80, 2741, 1},
+
+ {0x10c2, 3002, 1},
+
+ {0xa780, 3255, 1},
+
+ {0x1c80, 902, 1},
+
+ {0xab80, 1648, 1},
+
+ {0x10c80, 3639, 1},
+
+ {0x212a, 27, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1efa, 2228, 1},
+
+ {0x04fa, 1267, 1},
+
+ {0x01fa, 493, 1},
+
+ {0x1ffa, 2417, 1},
+
+ {0x1041a, 3489, 1},
+
+ {0x0392, 748, 1},
+
+ {0xa680, 3090, 1},
+
+ {0x1e1a, 1906, 1},
+
+ {0x041a, 928, 1},
+
+ {0x011a, 210, 1},
+
+ {0x1f1a, 2267, 1},
+
+ {0x2c1a, 2654, 1},
+
+ {0x10418, 3483, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f5b, 2348, 1},
+
+ {0x1e18, 1903, 1},
+
+ {0x0418, 922, 1},
+
+ {0x0118, 207, 1},
+
+ {0x1f18, 2261, 1},
+
+ {0x2c18, 2648, 1},
+
+ {0x1040e, 3453, 1},
+
+ {0x2c63, 1861, 1},
+
+ {0x0397, 765, 1},
+
+ {0x1e0e, 1888, 1},
+
+ {0x040e, 1041, 1},
+
+ {0x010e, 192, 1},
+
+ {0x1f0e, 2255, 1},
+
+ {0x2c0e, 2618, 1},
+
+ {0x1e2e, 1936, 1},
+
+ {0x042e, 993, 1},
+
+ {0x012e, 240, 1},
+
+ {0x1f2e, 2297, 1},
+
+ {0x2c2e, 2714, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa72e, 3150, 1},
+
+ {0x0394, 755, 1},
+
+ {0x1040c, 3447, 1},
+ {0xffffffff, -1, 0},
+
+ {0x24c4, 2540, 1},
+
+ {0x1e0c, 1885, 1},
+
+ {0x040c, 1035, 1},
+
+ {0x010c, 189, 1},
+
+ {0x1f0c, 2249, 1},
+
+ {0x2c0c, 2612, 1},
+
+ {0x01a9, 685, 1},
+
+ {0x1fa9, 214, 2},
+
+ {0x053d, 1384, 1},
+
+ {0x023d, 378, 1},
+
+ {0x24c2, 2534, 1},
+
+ {0x1ca9, 1537, 1},
+
+ {0xaba9, 1771, 1},
+
+ {0x10ca9, 3762, 1},
+
+ {0x10408, 3435, 1},
+
+ {0x051c, 1318, 1},
+
+ {0x021c, 544, 1},
+
+ {0x1e08, 1879, 1},
+
+ {0x0408, 1023, 1},
+
+ {0x0108, 183, 1},
+
+ {0x1f08, 2237, 1},
+
+ {0x2c08, 2600, 1},
+
+ {0x0386, 733, 1},
+
+ {0x10414, 3471, 1},
+ {0xffffffff, -1, 0},
+
+ {0x13fa, 1846, 1},
+
+ {0x1e14, 1897, 1},
+
+ {0x0414, 909, 1},
+
+ {0x0114, 201, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c14, 2636, 1},
+
+ {0x0540, 1393, 1},
+
+ {0x1f6d, 2372, 1},
+
+ {0x2c6d, 607, 1},
+
+ {0x038f, 842, 1},
+
+ {0x10406, 3429, 1},
+
+ {0x054a, 1423, 1},
+
+ {0x024a, 595, 1},
+
+ {0x1e06, 1876, 1},
+
+ {0x0406, 1017, 1},
+
+ {0x0106, 180, 1},
+
+ {0x10404, 3423, 1},
+
+ {0x2c06, 2594, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e04, 1873, 1},
+
+ {0x0404, 1011, 1},
+
+ {0x0104, 177, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c04, 2588, 1},
+
+ {0x1ee0, 2189, 1},
+
+ {0x04e0, 1228, 1},
+
+ {0x01e0, 459, 1},
+
+ {0x10400, 3411, 1},
+
+ {0x2ce0, 2885, 1},
+
+ {0x03c2, 806, 1},
+
+ {0x1e00, 1867, 1},
+
+ {0x0400, 999, 1},
+
+ {0x0100, 171, 1},
+
+ {0x0179, 345, 1},
+
+ {0x2c00, 2576, 1},
+
+ {0x16e5d, 3975, 1},
+
+ {0x039e, 792, 1},
+
+ {0xa779, 3246, 1},
+
+ {0x10426, 3525, 1},
+
+ {0xab79, 1627, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e26, 1924, 1},
+
+ {0x0426, 968, 1},
+
+ {0x0126, 228, 1},
+
+ {0xfb16, 125, 2},
+
+ {0x2c26, 2690, 1},
+
+ {0x038e, 839, 1},
+
+ {0xa726, 3138, 1},
+
+ {0x16e40, 3888, 1},
+
+ {0x1ef4, 2219, 1},
+
+ {0x04f4, 1258, 1},
+
+ {0x01f4, 487, 1},
+
+ {0x1ff4, 101, 2},
+
+ {0x16e4a, 3918, 1},
+
+ {0x051a, 1315, 1},
+
+ {0x021a, 541, 1},
+
+ {0x10a9, 2927, 1},
+
+ {0x1f4d, 2342, 1},
+
+ {0xff2e, 3372, 1},
+
+ {0x004d, 34, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118a9, 3819, 1},
+
+ {0x0518, 1312, 1},
+
+ {0x0218, 538, 1},
+
+ {0x1e8c, 2078, 1},
+
+ {0x048c, 1102, 1},
+
+ {0x038a, 742, 1},
+
+ {0x1f8c, 149, 2},
+
+ {0x2c8c, 2759, 1},
+ {0xffffffff, -1, 0},
+
+ {0x050e, 1297, 1},
+
+ {0x020e, 523, 1},
+
+ {0xab8c, 1684, 1},
+
+ {0x10c8c, 3675, 1},
+
+ {0x104bf, 3576, 1},
+
+ {0x052e, 1345, 1},
+
+ {0x022e, 568, 1},
+
+ {0x1e2c, 1933, 1},
+
+ {0x042c, 987, 1},
+
+ {0x012c, 237, 1},
+
+ {0x1f2c, 2291, 1},
+
+ {0x2c2c, 2708, 1},
+
+ {0xa68c, 3108, 1},
+
+ {0xa72c, 3147, 1},
+
+ {0x1cbf, 1597, 1},
+
+ {0xabbf, 1837, 1},
+
+ {0x050c, 1294, 1},
+
+ {0x020c, 520, 1},
+
+ {0x1e28, 1927, 1},
+
+ {0x0428, 974, 1},
+
+ {0x0128, 231, 1},
+
+ {0x1f28, 2279, 1},
+
+ {0x2c28, 2696, 1},
+
+ {0x1fab, 224, 2},
+
+ {0xa728, 3141, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa7ab, 631, 1},
+
+ {0x1cab, 1543, 1},
+
+ {0xabab, 1777, 1},
+
+ {0x10cab, 3768, 1},
+
+ {0x16e5b, 3969, 1},
+
+ {0x10424, 3519, 1},
+
+ {0x0508, 1288, 1},
+
+ {0x0208, 514, 1},
+
+ {0x1e24, 1921, 1},
+
+ {0x0424, 962, 1},
+
+ {0x0124, 225, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c24, 2684, 1},
+
+ {0x104b7, 3552, 1},
+
+ {0xa724, 3135, 1},
+
+ {0x0514, 1306, 1},
+
+ {0x0214, 532, 1},
+
+ {0x03fa, 893, 1},
+
+ {0x01b7, 706, 1},
+
+ {0x1fb7, 10, 3},
+
+ {0x104b3, 3540, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1cb7, 1579, 1},
+
+ {0xabb7, 1813, 1},
+
+ {0x01b3, 402, 1},
+
+ {0x1fb3, 62, 2},
+
+ {0x0506, 1285, 1},
+
+ {0x0206, 511, 1},
+
+ {0xa7b3, 3330, 1},
+
+ {0x1cb3, 1567, 1},
+
+ {0xabb3, 1801, 1},
+
+ {0x10422, 3513, 1},
+
+ {0x0504, 1282, 1},
+
+ {0x0204, 508, 1},
+
+ {0x1e22, 1918, 1},
+
+ {0x0422, 954, 1},
+
+ {0x0122, 222, 1},
+
+ {0xff26, 3348, 1},
+
+ {0x2c22, 2678, 1},
+
+ {0xff35, 3393, 1},
+
+ {0xa722, 3132, 1},
+
+ {0x104b1, 3534, 1},
+
+ {0x0143, 267, 1},
+
+ {0x0500, 1276, 1},
+
+ {0x0200, 502, 1},
+
+ {0x0043, 6, 1},
+
+ {0x01b1, 697, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2163, 2456, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa7b1, 688, 1},
+
+ {0x1cb1, 1561, 1},
+
+ {0xabb1, 1795, 1},
+
+ {0x10cb1, 3786, 1},
+
+ {0x0526, 1333, 1},
+
+ {0x0226, 556, 1},
+
+ {0x0535, 1360, 1},
+
+ {0x10bf, 2993, 1},
+
+ {0x03a9, 826, 1},
+
+ {0x01a7, 393, 1},
+
+ {0x1fa7, 244, 2},
+
+ {0x1e916, 4050, 1},
+
+ {0x118bf, 3885, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1ca7, 1531, 1},
+
+ {0xaba7, 1765, 1},
+
+ {0x10ca7, 3756, 1},
+
+ {0x054d, 1432, 1},
+
+ {0x1f6b, 2366, 1},
+
+ {0x2c6b, 2732, 1},
+
+ {0x10ab, 2933, 1},
+
+ {0x1e48, 1975, 1},
+ {0xffffffff, -1, 0},
+
+ {0xff2c, 3366, 1},
+
+ {0x1f48, 2327, 1},
+
+ {0x118ab, 3825, 1},
+
+ {0x0048, 21, 1},
+
+ {0xa748, 3186, 1},
+
+ {0x1e88, 2072, 1},
+
+ {0x1f69, 2360, 1},
+
+ {0x2c69, 2729, 1},
+
+ {0x1f88, 129, 2},
+
+ {0x2c88, 2753, 1},
+ {0xffffffff, -1, 0},
+
+ {0xff28, 3354, 1},
+
+ {0x1c88, 3035, 1},
+
+ {0xab88, 1672, 1},
+
+ {0x10c88, 3663, 1},
+
+ {0x1e42, 1966, 1},
+
+ {0xa648, 3032, 1},
+
+ {0x052c, 1342, 1},
+
+ {0x022c, 565, 1},
+
+ {0x10b7, 2969, 1},
+
+ {0x0042, 3, 1},
+
+ {0xa742, 3177, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa688, 3102, 1},
+
+ {0x118b7, 3861, 1},
+
+ {0x216d, 2486, 1},
+
+ {0x10b3, 2957, 1},
+
+ {0xff24, 3342, 1},
+
+ {0x0528, 1336, 1},
+
+ {0x0228, 559, 1},
+
+ {0x03e0, 860, 1},
+
+ {0x118b3, 3849, 1},
+
+ {0x1e56, 1996, 1},
+
+ {0xa642, 3023, 1},
+
+ {0x0156, 294, 1},
+
+ {0x1f56, 62, 3},
+
+ {0x16e4d, 3927, 1},
+
+ {0x0056, 62, 1},
+
+ {0xa756, 3207, 1},
+
+ {0x24bf, 2525, 1},
+
+ {0x1f59, 2345, 1},
+
+ {0x1e4e, 1984, 1},
+
+ {0x0059, 71, 1},
+
+ {0x014e, 282, 1},
+
+ {0x0524, 1330, 1},
+
+ {0x0224, 553, 1},
+
+ {0x004e, 37, 1},
+
+ {0xa74e, 3195, 1},
+
+ {0x10b1, 2951, 1},
+
+ {0x042d, 990, 1},
+
+ {0xa656, 3054, 1},
+
+ {0x1f2d, 2294, 1},
+
+ {0x2c2d, 2711, 1},
+
+ {0x118b1, 3843, 1},
+
+ {0xff22, 3336, 1},
+
+ {0x03f4, 768, 1},
+
+ {0x042f, 996, 1},
+
+ {0x1e91c, 4068, 1},
+
+ {0x1f2f, 2300, 1},
+
+ {0xa64e, 3042, 1},
+
+ {0x104ce, 3621, 1},
+
+ {0x10a7, 2921, 1},
+
+ {0x2126, 826, 1},
+
+ {0x1ece, 2162, 1},
+
+ {0xfb14, 109, 2},
+ {0xffffffff, -1, 0},
+
+ {0x118a7, 3813, 1},
+
+ {0x2cce, 2858, 1},
+
+ {0x00ce, 120, 1},
+
+ {0x104b9, 3558, 1},
+
+ {0x038c, 836, 1},
+
+ {0x0522, 1327, 1},
+
+ {0x0222, 550, 1},
+
+ {0xff33, 3387, 1},
+
+ {0x24b7, 2501, 1},
+
+ {0x1fb9, 2426, 1},
+
+ {0xfb06, 29, 2},
+
+ {0x0543, 1402, 1},
+
+ {0x0243, 354, 1},
+
+ {0x1cb9, 1585, 1},
+
+ {0xabb9, 1819, 1},
+
+ {0x1e54, 1993, 1},
+
+ {0xfb04, 5, 3},
+
+ {0x0154, 291, 1},
+
+ {0x1f54, 57, 3},
+
+ {0xff31, 3381, 1},
+
+ {0x0054, 56, 1},
+
+ {0xa754, 3204, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e52, 1990, 1},
+
+ {0x0533, 1354, 1},
+
+ {0x0152, 288, 1},
+
+ {0x1f52, 52, 3},
+
+ {0xfb00, 4, 2},
+
+ {0x0052, 49, 1},
+
+ {0xa752, 3201, 1},
+
+ {0x03ab, 833, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e50, 1987, 1},
+
+ {0xa654, 3051, 1},
+
+ {0x0150, 285, 1},
+
+ {0x1f50, 84, 2},
+
+ {0x0531, 1348, 1},
+
+ {0x0050, 43, 1},
+
+ {0xa750, 3198, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xa652, 3048, 1},
+
+ {0x0548, 1417, 1},
+
+ {0x0248, 592, 1},
+
+ {0x10420, 3507, 1},
+
+ {0x013f, 261, 1},
+
+ {0x1f3f, 2324, 1},
+
+ {0x1e20, 1915, 1},
+
+ {0x0420, 947, 1},
+
+ {0x0120, 219, 1},
+
+ {0xa650, 3045, 1},
+
+ {0x2c20, 2672, 1},
+ {0xffffffff, -1, 0},
+
+ {0x16e43, 3897, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e91a, 4062, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1041e, 3501, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0542, 1399, 1},
+
+ {0x1e1e, 1912, 1},
+
+ {0x041e, 940, 1},
+
+ {0x011e, 216, 1},
+
+ {0x1e918, 4056, 1},
+
+ {0x2c1e, 2666, 1},
+
+ {0x10412, 3465, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e12, 1894, 1},
+
+ {0x0412, 902, 1},
+
+ {0x0112, 198, 1},
+
+ {0x1e90e, 4026, 1},
+
+ {0x2c12, 2630, 1},
+ {0xffffffff, -1, 0},
+
+ {0x10410, 3459, 1},
+
+ {0xff2d, 3369, 1},
+
+ {0x0556, 1459, 1},
+
+ {0x1e10, 1891, 1},
+
+ {0x0410, 896, 1},
+
+ {0x0110, 195, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c10, 2624, 1},
+
+ {0xff2f, 3375, 1},
+
+ {0x10b9, 2975, 1},
+
+ {0x16e48, 3912, 1},
+
+ {0x054e, 1435, 1},
+
+ {0x024e, 601, 1},
+
+ {0x1e90c, 4020, 1},
+
+ {0x118b9, 3867, 1},
+ {0xffffffff, -1, 0},
+
+ {0x104ca, 3609, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1eca, 2156, 1},
+
+ {0x03a7, 820, 1},
+
+ {0x01ca, 425, 1},
+
+ {0x1fca, 2393, 1},
+
+ {0x2cca, 2852, 1},
+
+ {0x00ca, 108, 1},
+
+ {0x104c8, 3603, 1},
+ {0xffffffff, -1, 0},
+
+ {0x16e42, 3894, 1},
+
+ {0x1ec8, 2153, 1},
+
+ {0x1e908, 4008, 1},
+
+ {0x01c8, 421, 1},
+
+ {0x1fc8, 2387, 1},
+
+ {0x2cc8, 2849, 1},
+
+ {0x00c8, 102, 1},
+
+ {0x1e6c, 2030, 1},
+
+ {0x046c, 1066, 1},
+
+ {0x016c, 327, 1},
+
+ {0x1f6c, 2369, 1},
+
+ {0x1e914, 4044, 1},
+
+ {0x104c6, 3597, 1},
+
+ {0xa76c, 3240, 1},
+
+ {0x0388, 736, 1},
+
+ {0x1ec6, 2150, 1},
+
+ {0x216b, 2480, 1},
+
+ {0x16e56, 3954, 1},
+
+ {0x1fc6, 67, 2},
+
+ {0x2cc6, 2846, 1},
+
+ {0x00c6, 96, 1},
+
+ {0xa7c6, 1864, 1},
+
+ {0x16e59, 3963, 1},
+
+ {0x1e906, 4002, 1},
+
+ {0x0554, 1453, 1},
+
+ {0xa66c, 3087, 1},
+
+ {0x16e4e, 3930, 1},
+
+ {0x2169, 2474, 1},
+
+ {0x24ce, 2570, 1},
+
+ {0x1e904, 3996, 1},
+
+ {0x104c5, 3594, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0552, 1447, 1},
+ {0xffffffff, -1, 0},
+
+ {0x04c5, 1186, 1},
+
+ {0x01c5, 417, 1},
+ {0xffffffff, -1, 0},
+
+ {0x24b9, 2507, 1},
+
+ {0x00c5, 92, 1},
+
+ {0xa7c5, 682, 1},
+
+ {0x1e900, 3984, 1},
+
+ {0x0550, 1441, 1},
+
+ {0x104c0, 3579, 1},
+
+ {0x104b5, 3546, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1ec0, 2141, 1},
+
+ {0x04c0, 1201, 1},
+ {0xffffffff, -1, 0},
+
+ {0x01b5, 405, 1},
+
+ {0x2cc0, 2837, 1},
+
+ {0x00c0, 77, 1},
+
+ {0x00b5, 785, 1},
+
+ {0x053f, 1390, 1},
+
+ {0x1cb5, 1573, 1},
+
+ {0xabb5, 1807, 1},
+
+ {0x1fad, 234, 2},
+
+ {0x0520, 1324, 1},
+
+ {0x0220, 381, 1},
+
+ {0xa7ad, 661, 1},
+
+ {0x1cad, 1549, 1},
+
+ {0xabad, 1783, 1},
+
+ {0x10cad, 3774, 1},
+
+ {0x1efc, 2231, 1},
+
+ {0x04fc, 1270, 1},
+
+ {0x01fc, 496, 1},
+
+ {0x1ffc, 96, 2},
+
+ {0x16e54, 3948, 1},
+
+ {0x1fa5, 234, 2},
+ {0xffffffff, -1, 0},
+
+ {0x051e, 1321, 1},
+
+ {0x021e, 547, 1},
+
+ {0x1ca5, 1525, 1},
+
+ {0xaba5, 1759, 1},
+
+ {0x10ca5, 3750, 1},
+
+ {0x16e52, 3942, 1},
+
+ {0x01af, 399, 1},
+
+ {0x1faf, 244, 2},
+
+ {0x0512, 1303, 1},
+
+ {0x0212, 529, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1caf, 1555, 1},
+
+ {0xabaf, 1789, 1},
+
+ {0x10caf, 3780, 1},
+
+ {0x16e50, 3936, 1},
+
+ {0x1fa3, 224, 2},
+ {0xffffffff, -1, 0},
+
+ {0x0510, 1300, 1},
+
+ {0x0210, 526, 1},
+
+ {0x1ca3, 1519, 1},
+
+ {0xaba3, 1753, 1},
+
+ {0x10ca3, 3744, 1},
+
+ {0x0429, 977, 1},
+
+ {0x1fa1, 214, 2},
+
+ {0x1f29, 2282, 1},
+
+ {0x2c29, 2699, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1ca1, 1513, 1},
+
+ {0xaba1, 1747, 1},
+
+ {0x10ca1, 3738, 1},
+
+ {0x1e6a, 2027, 1},
+
+ {0x046a, 1063, 1},
+
+ {0x016a, 324, 1},
+
+ {0x1f6a, 2363, 1},
+
+ {0x1e46, 1972, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa76a, 3237, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x0046, 15, 1},
+
+ {0xa746, 3183, 1},
+
+ {0x10c5, 3011, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e68, 2024, 1},
+
+ {0x0468, 1060, 1},
+
+ {0x0168, 321, 1},
+
+ {0x1f68, 2357, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa66a, 3084, 1},
+
+ {0xa768, 3234, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xa646, 3029, 1},
+
+ {0x10c0, 2996, 1},
+
+ {0x10b5, 2963, 1},
+
+ {0x24ca, 2558, 1},
+
+ {0x13fc, 1852, 1},
+
+ {0x1e44, 1969, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118b5, 3855, 1},
+
+ {0x10ad, 2939, 1},
+
+ {0xa668, 3081, 1},
+
+ {0x0044, 9, 1},
+
+ {0xa744, 3180, 1},
+
+ {0x24c8, 2552, 1},
+
+ {0x118ad, 3831, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e64, 2018, 1},
+
+ {0x0464, 1054, 1},
+
+ {0x0164, 315, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c64, 676, 1},
+
+ {0x10a5, 2915, 1},
+
+ {0xa764, 3228, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa644, 3026, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118a5, 3807, 1},
+
+ {0x24c6, 2546, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x10af, 2945, 1},
+
+ {0x1e32, 1942, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0132, 243, 1},
+
+ {0xa664, 3075, 1},
+
+ {0x118af, 3837, 1},
+
+ {0x104cb, 3612, 1},
+
+ {0xa732, 3153, 1},
+
+ {0x10a3, 2909, 1},
+ {0xffffffff, -1, 0},
+
+ {0x04cb, 1195, 1},
+
+ {0x01cb, 425, 1},
+
+ {0x1fcb, 2396, 1},
+
+ {0x118a3, 3801, 1},
+
+ {0x00cb, 111, 1},
+
+ {0x24c5, 2543, 1},
+
+ {0x10a1, 2903, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e62, 2015, 1},
+
+ {0x0462, 1050, 1},
+
+ {0x0162, 312, 1},
+
+ {0x118a1, 3795, 1},
+
+ {0x2c62, 658, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa762, 3225, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x24c0, 2528, 1},
+
+ {0x1e60, 2011, 1},
+
+ {0x0460, 1047, 1},
+
+ {0x0160, 309, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c60, 2717, 1},
+
+ {0xff29, 3357, 1},
+
+ {0xa760, 3222, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa662, 3072, 1},
+
+ {0x1ee2, 2192, 1},
+
+ {0x04e2, 1231, 1},
+
+ {0x01e2, 462, 1},
+
+ {0x1fe2, 36, 3},
+
+ {0x2ce2, 2888, 1},
+
+ {0x042b, 984, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f2b, 2288, 1},
+
+ {0x2c2b, 2705, 1},
+
+ {0xa660, 3069, 1},
+ {0xffffffff, -1, 0},
+
+ {0x216c, 2483, 1},
+
+ {0x1eda, 2180, 1},
+
+ {0x04da, 1219, 1},
+
+ {0x104bd, 3570, 1},
+
+ {0x1fda, 2399, 1},
+
+ {0x2cda, 2876, 1},
+
+ {0x00da, 153, 1},
+
+ {0x1ed8, 2177, 1},
+
+ {0x04d8, 1216, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1fd8, 2429, 1},
+
+ {0x2cd8, 2873, 1},
+
+ {0x00d8, 147, 1},
+
+ {0x1cbd, 1591, 1},
+
+ {0xabbd, 1831, 1},
+
+ {0x0546, 1411, 1},
+
+ {0x0246, 589, 1},
+
+ {0x1ed6, 2174, 1},
+
+ {0x04d6, 1213, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1fd6, 76, 2},
+
+ {0x2cd6, 2870, 1},
+
+ {0x00d6, 144, 1},
+
+ {0x104d2, 3633, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1ed2, 2168, 1},
+
+ {0x04d2, 1207, 1},
+
+ {0x10427, 3528, 1},
+
+ {0x1fd2, 20, 3},
+
+ {0x2cd2, 2864, 1},
+
+ {0x00d2, 132, 1},
+
+ {0x0427, 971, 1},
+
+ {0x104d0, 3627, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c27, 2693, 1},
+
+ {0x1ed0, 2165, 1},
+
+ {0x04d0, 1204, 1},
+
+ {0x0544, 1405, 1},
+
+ {0x0244, 694, 1},
+
+ {0x2cd0, 2861, 1},
+
+ {0x00d0, 126, 1},
+
+ {0x03a5, 813, 1},
+
+ {0x104cd, 3618, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xff32, 3384, 1},
+
+ {0x04cd, 1198, 1},
+
+ {0x01cd, 429, 1},
+ {0xffffffff, -1, 0},
+
+ {0x104c3, 3588, 1},
+
+ {0x00cd, 117, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x04c3, 1183, 1},
+
+ {0x104bb, 3564, 1},
+
+ {0x1fc3, 71, 2},
+
+ {0x16e46, 3906, 1},
+
+ {0x00c3, 86, 1},
+
+ {0x03a3, 806, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1fbb, 2384, 1},
+
+ {0x104cc, 3615, 1},
+
+ {0x0532, 1351, 1},
+
+ {0x0232, 574, 1},
+
+ {0x1ecc, 2159, 1},
+
+ {0xabbb, 1825, 1},
+
+ {0x03a1, 802, 1},
+
+ {0x1fcc, 71, 2},
+
+ {0x2ccc, 2855, 1},
+
+ {0x00cc, 114, 1},
+
+ {0x019d, 670, 1},
+
+ {0x1f9d, 194, 2},
+
+ {0x1e78, 2048, 1},
+
+ {0x0478, 1084, 1},
+
+ {0x0178, 168, 1},
+
+ {0x1c9d, 1501, 1},
+
+ {0xab9d, 1735, 1},
+
+ {0x10c9d, 3726, 1},
+ {0xffffffff, -1, 0},
+
+ {0x16e44, 3900, 1},
+
+ {0xab78, 1624, 1},
+
+ {0x1e9b, 2011, 1},
+
+ {0x10bd, 2987, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f9b, 184, 2},
+
+ {0xff2b, 3363, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118bd, 3879, 1},
+
+ {0x1c9b, 1495, 1},
+
+ {0xab9b, 1729, 1},
+
+ {0x10c9b, 3720, 1},
+
+ {0x216a, 2477, 1},
+
+ {0x24cb, 2561, 1},
+
+ {0x1e99, 42, 2},
+
+ {0x1e920, 4080, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f99, 174, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1c99, 1489, 1},
+
+ {0xab99, 1723, 1},
+
+ {0x10c99, 3714, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2168, 2471, 1},
+
+ {0x0193, 634, 1},
+
+ {0x1f93, 184, 2},
+
+ {0x1e91e, 4074, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1c93, 1471, 1},
+
+ {0xab93, 1705, 1},
+
+ {0x10c93, 3696, 1},
+
+ {0x0191, 369, 1},
+
+ {0x1f91, 174, 2},
+
+ {0x1e912, 4038, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1c91, 1465, 1},
+
+ {0xab91, 1699, 1},
+
+ {0x10c91, 3690, 1},
+ {0xffffffff, -1, 0},
+
+ {0x10cd, 3017, 1},
+
+ {0xff27, 3351, 1},
+
+ {0x1e910, 4032, 1},
+
+ {0x0187, 363, 1},
+
+ {0x1f87, 164, 2},
+
+ {0x0055, 59, 1},
+
+ {0x2164, 2459, 1},
+
+ {0x10c3, 3005, 1},
+
+ {0x1c87, 1050, 1},
+
+ {0xab87, 1669, 1},
+
+ {0x10c87, 3660, 1},
+
+ {0x0145, 270, 1},
+
+ {0x10bb, 2981, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0045, 12, 1},
+
+ {0x24bd, 2519, 1},
+ {0xffffffff, -1, 0},
+
+ {0x118bb, 3873, 1},
+
+ {0x1e72, 2039, 1},
+
+ {0x0472, 1075, 1},
+
+ {0x0172, 336, 1},
+
+ {0x2132, 2444, 1},
+
+ {0x2c72, 2735, 1},
+
+ {0x1e70, 2036, 1},
+
+ {0x0470, 1072, 1},
+
+ {0x0170, 333, 1},
+
+ {0xab72, 1606, 1},
+
+ {0x2c70, 610, 1},
+
+ {0x1e66, 2021, 1},
+
+ {0x0466, 1057, 1},
+
+ {0x0166, 318, 1},
+
+ {0xab70, 1600, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1e3a, 1954, 1},
+
+ {0xa766, 3231, 1},
+
+ {0x1e5a, 2002, 1},
+
+ {0x1f3a, 2309, 1},
+
+ {0x015a, 300, 1},
+
+ {0x2162, 2453, 1},
+
+ {0xa73a, 3165, 1},
+
+ {0x005a, 74, 1},
+
+ {0xa75a, 3213, 1},
+
+ {0x03e2, 863, 1},
+ {0xffffffff, -1, 0},
+
+ {0x104cf, 3624, 1},
+
+ {0x1e58, 1999, 1},
+
+ {0xa666, 3078, 1},
+
+ {0x0158, 297, 1},
+
+ {0x2160, 2447, 1},
+
+ {0x01cf, 432, 1},
+
+ {0x0058, 68, 1},
+
+ {0xa758, 3210, 1},
+
+ {0x00cf, 123, 1},
+
+ {0xa65a, 3060, 1},
+
+ {0x03da, 851, 1},
+
+ {0x24cd, 2567, 1},
+
+ {0x1eec, 2207, 1},
+
+ {0x04ec, 1246, 1},
+
+ {0x01ec, 477, 1},
+
+ {0x1fec, 2441, 1},
+
+ {0x03d8, 848, 1},
+
+ {0x212b, 92, 1},
+
+ {0x24c3, 2537, 1},
+
+ {0xa658, 3057, 1},
+
+ {0x1edc, 2183, 1},
+
+ {0x04dc, 1222, 1},
+ {0xffffffff, -1, 0},
+
+ {0x24bb, 2513, 1},
+
+ {0x2cdc, 2879, 1},
+
+ {0x00dc, 159, 1},
+
+ {0x03d6, 798, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x24cc, 2564, 1},
+
+ {0x1eea, 2204, 1},
+
+ {0x04ea, 1243, 1},
+
+ {0x01ea, 474, 1},
+
+ {0x1fea, 2411, 1},
+
+ {0x1ee8, 2201, 1},
+
+ {0x04e8, 1240, 1},
+
+ {0x01e8, 471, 1},
+
+ {0x1fe8, 2435, 1},
+
+ {0x1ee6, 2198, 1},
+
+ {0x04e6, 1237, 1},
+
+ {0x01e6, 468, 1},
+
+ {0x1fe6, 88, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x03d0, 748, 1},
+
+ {0x1ee4, 2195, 1},
+
+ {0x04e4, 1234, 1},
+
+ {0x01e4, 465, 1},
+
+ {0x1fe4, 80, 2},
+
+ {0x104c9, 3606, 1},
+
+ {0x104c1, 3582, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x04c9, 1192, 1},
+
+ {0x04c1, 1180, 1},
+
+ {0x1fc9, 2390, 1},
+
+ {0x1f95, 194, 2},
+
+ {0x00c9, 105, 1},
+
+ {0x00c1, 80, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1c95, 1477, 1},
+
+ {0xab95, 1711, 1},
+
+ {0x10c95, 3702, 1},
+
+ {0x018b, 366, 1},
+
+ {0x1f8b, 144, 2},
+
+ {0x0555, 1456, 1},
+
+ {0x0587, 105, 2},
+
+ {0xa78b, 3267, 1},
+ {0xffffffff, -1, 0},
+
+ {0xab8b, 1681, 1},
+
+ {0x10c8b, 3672, 1},
+
+ {0x1e76, 2045, 1},
+
+ {0x0476, 1081, 1},
+
+ {0x0176, 342, 1},
+
+ {0x0545, 1408, 1},
+
+ {0x0245, 703, 1},
+ {0xffffffff, -1, 0},
+
+ {0x039d, 789, 1},
+
+ {0x1f83, 144, 2},
+
+ {0xab76, 1618, 1},
+ {0xffffffff, -1, 0},
+
+ {0xff3a, 3408, 1},
+
+ {0x1c83, 950, 1},
+
+ {0xab83, 1657, 1},
+
+ {0x10c83, 3648, 1},
+
+ {0x0141, 264, 1},
+
+ {0x0181, 613, 1},
+
+ {0x1f81, 134, 2},
+
+ {0x0041, 0, 1},
+ {0xffffffff, -1, 0},
+
+ {0x039b, 782, 1},
+
+ {0x1c81, 909, 1},
+
+ {0xab81, 1651, 1},
+
+ {0x10c81, 3642, 1},
+
+ {0x0149, 46, 2},
+
+ {0x1f49, 2330, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0049, 4086, 1},
+
+ {0x053a, 1375, 1},
+
+ {0x023a, 2720, 1},
+
+ {0x1e7e, 2057, 1},
+
+ {0x047e, 1093, 1},
+
+ {0x0399, 773, 1},
+
+ {0x1e5e, 2008, 1},
+
+ {0x2c7e, 580, 1},
+
+ {0x015e, 306, 1},
+
+ {0xa77e, 3252, 1},
+
+ {0x16e55, 3951, 1},
+
+ {0xab7e, 1642, 1},
+
+ {0xa75e, 3219, 1},
+
+ {0x104d1, 3630, 1},
+
+ {0x1e5c, 2005, 1},
+
+ {0x0393, 752, 1},
+
+ {0x015c, 303, 1},
+ {0xffffffff, -1, 0},
+
+ {0x01d1, 435, 1},
+
+ {0x16e45, 3903, 1},
+
+ {0xa75c, 3216, 1},
+
+ {0x00d1, 129, 1},
+
+ {0x10421, 3510, 1},
+
+ {0x0391, 745, 1},
+
+ {0xa65e, 3066, 1},
+
+ {0x1e3e, 1960, 1},
+
+ {0x0421, 950, 1},
+ {0xffffffff, -1, 0},
+
+ {0x1f3e, 2321, 1},
+
+ {0x2c21, 2675, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa73e, 3171, 1},
+
+ {0xa65c, 3063, 1},
+
+ {0x10c1, 2999, 1},
+
+ {0x1e36, 1948, 1},
+
+ {0x1e38, 1951, 1},
+
+ {0x0136, 249, 1},
+
+ {0x24cf, 2573, 1},
+
+ {0x1f38, 2303, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa736, 3159, 1},
+
+ {0xa738, 3162, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0345, 773, 1},
+
+ {0x1e34, 1945, 1},
+
+ {0x16e5a, 3966, 1},
+
+ {0x0134, 246, 1},
+
+ {0x1041d, 3498, 1},
+
+ {0x013b, 255, 1},
+
+ {0x1f3b, 2312, 1},
+
+ {0xa734, 3156, 1},
+
+ {0x041d, 937, 1},
+
+ {0x0372, 718, 1},
+
+ {0x1f1d, 2276, 1},
+
+ {0x2c1d, 2663, 1},
+
+ {0x16e58, 3960, 1},
+
+ {0x1041b, 3492, 1},
+
+ {0x0370, 715, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x041b, 931, 1},
+
+ {0x10419, 3486, 1},
+
+ {0x1f1b, 2270, 1},
+
+ {0x2c1b, 2657, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0419, 925, 1},
+
+ {0x10417, 3480, 1},
+
+ {0x1f19, 2264, 1},
+
+ {0x2c19, 2651, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0417, 919, 1},
+
+ {0x10415, 3474, 1},
+
+ {0x10413, 3468, 1},
+
+ {0x2c17, 2645, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0415, 913, 1},
+
+ {0x0413, 906, 1},
+
+ {0x2166, 2465, 1},
+
+ {0x2c15, 2639, 1},
+
+ {0x2c13, 2633, 1},
+
+ {0x0053, 52, 1},
+
+ {0x03cf, 845, 1},
+
+ {0x1efe, 2234, 1},
+
+ {0x04fe, 1273, 1},
+
+ {0x01fe, 499, 1},
+
+ {0x1040f, 3456, 1},
+ {0xffffffff, -1, 0},
+
+ {0x24c9, 2555, 1},
+
+ {0x24c1, 2531, 1},
+
+ {0x040f, 1044, 1},
+
+ {0x03ec, 878, 1},
+
+ {0x1f0f, 2258, 1},
+
+ {0x2c0f, 2621, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1040d, 3450, 1},
+
+ {0x0541, 1396, 1},
+
+ {0x0241, 586, 1},
+
+ {0x03dc, 854, 1},
+
+ {0x040d, 1038, 1},
+
+ {0x1040b, 3444, 1},
+
+ {0x1f0d, 2252, 1},
+
+ {0x2c0d, 2615, 1},
+ {0xffffffff, -1, 0},
+
+ {0x040b, 1032, 1},
+
+ {0x0549, 1420, 1},
+
+ {0x1f0b, 2246, 1},
+
+ {0x2c0b, 2609, 1},
+
+ {0x10409, 3438, 1},
+
+ {0x03ea, 875, 1},
+
+ {0x0139, 252, 1},
+
+ {0x1f39, 2306, 1},
+
+ {0x0409, 1026, 1},
+
+ {0x03e8, 872, 1},
+
+ {0x1f09, 2240, 1},
+
+ {0x2c09, 2603, 1},
+
+ {0x10405, 3426, 1},
+
+ {0x03e6, 869, 1},
+
+ {0xff21, 3333, 1},
+
+ {0x1f4b, 2336, 1},
+
+ {0x0405, 1014, 1},
+
+ {0x004b, 27, 1},
+
+ {0x10403, 3420, 1},
+
+ {0x2c05, 2591, 1},
+
+ {0x03e4, 866, 1},
+
+ {0x104d3, 3636, 1},
+
+ {0x0403, 1008, 1},
+
+ {0xff36, 3396, 1},
+
+ {0xff38, 3402, 1},
+
+ {0x2c03, 2585, 1},
+
+ {0x01d3, 438, 1},
+
+ {0x1fd3, 25, 3},
+
+ {0x0395, 758, 1},
+
+ {0x00d3, 135, 1},
+
+ {0x0051, 46, 1},
+
+ {0x053e, 1387, 1},
+
+ {0x023e, 2723, 1},
+
+ {0xff34, 3390, 1},
+
+ {0x16e41, 3891, 1},
+
+ {0x10401, 3414, 1},
+
+ {0x1ef0, 2213, 1},
+
+ {0x04f0, 1252, 1},
+
+ {0x01f0, 20, 2},
+
+ {0x0401, 1002, 1},
+
+ {0x0536, 1363, 1},
+
+ {0x0538, 1369, 1},
+
+ {0x2c01, 2579, 1},
+
+ {0x16e49, 3915, 1},
+
+ {0x004f, 40, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0376, 721, 1},
+
+ {0x1eee, 2210, 1},
+
+ {0x04ee, 1249, 1},
+
+ {0x01ee, 480, 1},
+
+ {0x0534, 1357, 1},
+ {0xffffffff, -1, 0},
+
+ {0x053b, 1378, 1},
+
+ {0x023b, 577, 1},
+
+ {0x16e5e, 3978, 1},
+
+ {0x1ef8, 2225, 1},
+
+ {0x04f8, 1264, 1},
+
+ {0x01f8, 490, 1},
+
+ {0x1ff8, 2405, 1},
+
+ {0x1ed4, 2171, 1},
+
+ {0x04d4, 1210, 1},
+ {0xffffffff, -1, 0},
+
+ {0x16e5c, 3972, 1},
+
+ {0x2cd4, 2867, 1},
+
+ {0x00d4, 138, 1},
+
+ {0x2183, 2495, 1},
+
+ {0x1ef6, 2222, 1},
+
+ {0x04f6, 1261, 1},
+
+ {0x01f6, 372, 1},
+
+ {0x1ff6, 92, 2},
+
+ {0x1f8d, 154, 2},
+
+ {0x0147, 273, 1},
+ {0xffffffff, -1, 0},
+
+ {0xa78d, 643, 1},
+
+ {0x0047, 18, 1},
+
+ {0xab8d, 1687, 1},
+
+ {0x10c8d, 3678, 1},
+
+ {0x1e74, 2042, 1},
+
+ {0x0474, 1078, 1},
+
+ {0x0174, 339, 1},
+
+ {0x1e3c, 1957, 1},
+
+ {0x0553, 1450, 1},
+
+ {0x1e30, 1939, 1},
+
+ {0x1f3c, 2315, 1},
+
+ {0x0130, 261, 2},
+
+ {0xab74, 1612, 1},
+
+ {0xa73c, 3168, 1},
+
+ {0x10425, 3522, 1},
+
+ {0x03d1, 768, 1},
+
+ {0x10423, 3516, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0425, 965, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0423, 959, 1},
+
+ {0x2c25, 2687, 1},
+
+ {0x1041f, 3504, 1},
+
+ {0x2c23, 2681, 1},
+
+ {0xff39, 3405, 1},
+ {0xffffffff, -1, 0},
+
+ {0x041f, 944, 1},
+
+ {0x10411, 3462, 1},
+
+ {0x10407, 3432, 1},
+
+ {0x2c1f, 2669, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0411, 899, 1},
+
+ {0x0407, 1020, 1},
+ {0xffffffff, -1, 0},
+
+ {0x2c11, 2627, 1},
+
+ {0x2c07, 2597, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x0539, 1372, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x13f8, 1840, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x054b, 1426, 1},
+
+ {0x16e53, 3945, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0},
+
+ {0x0551, 1444, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x054f, 1438, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x03fe, 727, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x16e4b, 3921, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xff30, 3378, 1},
+ {0xffffffff, -1, 0},
+
+ {0x16e51, 3939, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0547, 1414, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xff25, 3345, 1},
+ {0xffffffff, -1, 0},
+
+ {0xff23, 3339, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x053c, 1381, 1},
+
+ {0x16e4f, 3933, 1},
+ {0xffffffff, -1, 0},
+
+ {0x0230, 571, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xfb17, 117, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xfb15, 113, 2},
+
+ {0xfb13, 121, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x03f0, 778, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x16e47, 3909, 1},
+ {0xffffffff, -1, 0},
+
+ {0x03ee, 881, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xfb05, 29, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xfb03, 0, 3},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e921, 4083, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0xfb01, 8, 2},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0},
+
+ {0x1e91d, 4071, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e91b, 4065, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e919, 4059, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e917, 4053, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e915, 4047, 1},
+
+ {0x1e913, 4041, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e90f, 4029, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e90d, 4023, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e90b, 4017, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e909, 4011, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e905, 3999, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e903, 3993, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0},
+
+ {0x1e901, 3987, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e91f, 4077, 1},
+ {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0}, {0xffffffff, -1, 0},
+
+ {0x1e911, 4035, 1},
+
+ {0x1e907, 4005, 1}
+ };
+
+
+ {
+ int key = hash(&code);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ OnigCodePoint gcode = wordlist[key].code;
+
+ if (code == gcode && wordlist[key].index >= 0)
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_wb_data.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_wb_data.c
new file mode 100644
index 000000000..8e1a26707
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/unicode_wb_data.c
@@ -0,0 +1,1023 @@
+/* unicode_wb_data.c: Generated by make_unicode_wb_data.py. */
+/*-
+ * Copyright (c) 2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#define WORD_BREAK_PROPERTY_VERSION 120100
+
+/*
+ALetter
+CR
+Double_Quote
+Extend
+ExtendNumLet
+Format
+Hebrew_Letter
+Katakana
+LF
+MidLetter
+MidNum
+MidNumLet
+Newline
+Numeric
+Regional_Indicator
+Single_Quote
+WSegSpace
+ZWJ
+*/
+
+static int WB_RANGE_NUM = 970;
+static WB_RANGE_TYPE WB_RANGES[] = {
+ {0x00000a, 0x00000a, WB_LF },
+ {0x00000b, 0x00000c, WB_Newline },
+ {0x00000d, 0x00000d, WB_CR },
+ {0x000020, 0x000020, WB_WSegSpace },
+ {0x000022, 0x000022, WB_Double_Quote },
+ {0x000027, 0x000027, WB_Single_Quote },
+ {0x00002c, 0x00002c, WB_MidNum },
+ {0x00002e, 0x00002e, WB_MidNumLet },
+ {0x000030, 0x000039, WB_Numeric },
+ {0x00003a, 0x00003a, WB_MidLetter },
+ {0x00003b, 0x00003b, WB_MidNum },
+ {0x000041, 0x00005a, WB_ALetter },
+ {0x00005f, 0x00005f, WB_ExtendNumLet },
+ {0x000061, 0x00007a, WB_ALetter },
+ {0x000085, 0x000085, WB_Newline },
+ {0x0000aa, 0x0000aa, WB_ALetter },
+ {0x0000ad, 0x0000ad, WB_Format },
+ {0x0000b5, 0x0000b5, WB_ALetter },
+ {0x0000b7, 0x0000b7, WB_MidLetter },
+ {0x0000ba, 0x0000ba, WB_ALetter },
+ {0x0000c0, 0x0000d6, WB_ALetter },
+ {0x0000d8, 0x0000f6, WB_ALetter },
+ {0x0000f8, 0x0002d7, WB_ALetter },
+ {0x0002de, 0x0002e4, WB_ALetter },
+ {0x0002ec, 0x0002ff, WB_ALetter },
+ {0x000300, 0x00036f, WB_Extend },
+ {0x000370, 0x000374, WB_ALetter },
+ {0x000376, 0x000377, WB_ALetter },
+ {0x00037a, 0x00037d, WB_ALetter },
+ {0x00037e, 0x00037e, WB_MidNum },
+ {0x00037f, 0x00037f, WB_ALetter },
+ {0x000386, 0x000386, WB_ALetter },
+ {0x000387, 0x000387, WB_MidLetter },
+ {0x000388, 0x00038a, WB_ALetter },
+ {0x00038c, 0x00038c, WB_ALetter },
+ {0x00038e, 0x0003a1, WB_ALetter },
+ {0x0003a3, 0x0003f5, WB_ALetter },
+ {0x0003f7, 0x000481, WB_ALetter },
+ {0x000483, 0x000489, WB_Extend },
+ {0x00048a, 0x00052f, WB_ALetter },
+ {0x000531, 0x000556, WB_ALetter },
+ {0x000559, 0x000559, WB_ALetter },
+ {0x00055b, 0x00055c, WB_ALetter },
+ {0x00055e, 0x00055e, WB_ALetter },
+ {0x000560, 0x000588, WB_ALetter },
+ {0x000589, 0x000589, WB_MidNum },
+ {0x000591, 0x0005bd, WB_Extend },
+ {0x0005bf, 0x0005bf, WB_Extend },
+ {0x0005c1, 0x0005c2, WB_Extend },
+ {0x0005c4, 0x0005c5, WB_Extend },
+ {0x0005c7, 0x0005c7, WB_Extend },
+ {0x0005d0, 0x0005ea, WB_Hebrew_Letter },
+ {0x0005ef, 0x0005f2, WB_Hebrew_Letter },
+ {0x0005f3, 0x0005f3, WB_ALetter },
+ {0x0005f4, 0x0005f4, WB_MidLetter },
+ {0x000600, 0x000605, WB_Format },
+ {0x00060c, 0x00060d, WB_MidNum },
+ {0x000610, 0x00061a, WB_Extend },
+ {0x00061c, 0x00061c, WB_Format },
+ {0x000620, 0x00064a, WB_ALetter },
+ {0x00064b, 0x00065f, WB_Extend },
+ {0x000660, 0x000669, WB_Numeric },
+ {0x00066b, 0x00066b, WB_Numeric },
+ {0x00066c, 0x00066c, WB_MidNum },
+ {0x00066e, 0x00066f, WB_ALetter },
+ {0x000670, 0x000670, WB_Extend },
+ {0x000671, 0x0006d3, WB_ALetter },
+ {0x0006d5, 0x0006d5, WB_ALetter },
+ {0x0006d6, 0x0006dc, WB_Extend },
+ {0x0006dd, 0x0006dd, WB_Format },
+ {0x0006df, 0x0006e4, WB_Extend },
+ {0x0006e5, 0x0006e6, WB_ALetter },
+ {0x0006e7, 0x0006e8, WB_Extend },
+ {0x0006ea, 0x0006ed, WB_Extend },
+ {0x0006ee, 0x0006ef, WB_ALetter },
+ {0x0006f0, 0x0006f9, WB_Numeric },
+ {0x0006fa, 0x0006fc, WB_ALetter },
+ {0x0006ff, 0x0006ff, WB_ALetter },
+ {0x00070f, 0x00070f, WB_Format },
+ {0x000710, 0x000710, WB_ALetter },
+ {0x000711, 0x000711, WB_Extend },
+ {0x000712, 0x00072f, WB_ALetter },
+ {0x000730, 0x00074a, WB_Extend },
+ {0x00074d, 0x0007a5, WB_ALetter },
+ {0x0007a6, 0x0007b0, WB_Extend },
+ {0x0007b1, 0x0007b1, WB_ALetter },
+ {0x0007c0, 0x0007c9, WB_Numeric },
+ {0x0007ca, 0x0007ea, WB_ALetter },
+ {0x0007eb, 0x0007f3, WB_Extend },
+ {0x0007f4, 0x0007f5, WB_ALetter },
+ {0x0007f8, 0x0007f8, WB_MidNum },
+ {0x0007fa, 0x0007fa, WB_ALetter },
+ {0x0007fd, 0x0007fd, WB_Extend },
+ {0x000800, 0x000815, WB_ALetter },
+ {0x000816, 0x000819, WB_Extend },
+ {0x00081a, 0x00081a, WB_ALetter },
+ {0x00081b, 0x000823, WB_Extend },
+ {0x000824, 0x000824, WB_ALetter },
+ {0x000825, 0x000827, WB_Extend },
+ {0x000828, 0x000828, WB_ALetter },
+ {0x000829, 0x00082d, WB_Extend },
+ {0x000840, 0x000858, WB_ALetter },
+ {0x000859, 0x00085b, WB_Extend },
+ {0x000860, 0x00086a, WB_ALetter },
+ {0x0008a0, 0x0008b4, WB_ALetter },
+ {0x0008b6, 0x0008bd, WB_ALetter },
+ {0x0008d3, 0x0008e1, WB_Extend },
+ {0x0008e2, 0x0008e2, WB_Format },
+ {0x0008e3, 0x000903, WB_Extend },
+ {0x000904, 0x000939, WB_ALetter },
+ {0x00093a, 0x00093c, WB_Extend },
+ {0x00093d, 0x00093d, WB_ALetter },
+ {0x00093e, 0x00094f, WB_Extend },
+ {0x000950, 0x000950, WB_ALetter },
+ {0x000951, 0x000957, WB_Extend },
+ {0x000958, 0x000961, WB_ALetter },
+ {0x000962, 0x000963, WB_Extend },
+ {0x000966, 0x00096f, WB_Numeric },
+ {0x000971, 0x000980, WB_ALetter },
+ {0x000981, 0x000983, WB_Extend },
+ {0x000985, 0x00098c, WB_ALetter },
+ {0x00098f, 0x000990, WB_ALetter },
+ {0x000993, 0x0009a8, WB_ALetter },
+ {0x0009aa, 0x0009b0, WB_ALetter },
+ {0x0009b2, 0x0009b2, WB_ALetter },
+ {0x0009b6, 0x0009b9, WB_ALetter },
+ {0x0009bc, 0x0009bc, WB_Extend },
+ {0x0009bd, 0x0009bd, WB_ALetter },
+ {0x0009be, 0x0009c4, WB_Extend },
+ {0x0009c7, 0x0009c8, WB_Extend },
+ {0x0009cb, 0x0009cd, WB_Extend },
+ {0x0009ce, 0x0009ce, WB_ALetter },
+ {0x0009d7, 0x0009d7, WB_Extend },
+ {0x0009dc, 0x0009dd, WB_ALetter },
+ {0x0009df, 0x0009e1, WB_ALetter },
+ {0x0009e2, 0x0009e3, WB_Extend },
+ {0x0009e6, 0x0009ef, WB_Numeric },
+ {0x0009f0, 0x0009f1, WB_ALetter },
+ {0x0009fc, 0x0009fc, WB_ALetter },
+ {0x0009fe, 0x0009fe, WB_Extend },
+ {0x000a01, 0x000a03, WB_Extend },
+ {0x000a05, 0x000a0a, WB_ALetter },
+ {0x000a0f, 0x000a10, WB_ALetter },
+ {0x000a13, 0x000a28, WB_ALetter },
+ {0x000a2a, 0x000a30, WB_ALetter },
+ {0x000a32, 0x000a33, WB_ALetter },
+ {0x000a35, 0x000a36, WB_ALetter },
+ {0x000a38, 0x000a39, WB_ALetter },
+ {0x000a3c, 0x000a3c, WB_Extend },
+ {0x000a3e, 0x000a42, WB_Extend },
+ {0x000a47, 0x000a48, WB_Extend },
+ {0x000a4b, 0x000a4d, WB_Extend },
+ {0x000a51, 0x000a51, WB_Extend },
+ {0x000a59, 0x000a5c, WB_ALetter },
+ {0x000a5e, 0x000a5e, WB_ALetter },
+ {0x000a66, 0x000a6f, WB_Numeric },
+ {0x000a70, 0x000a71, WB_Extend },
+ {0x000a72, 0x000a74, WB_ALetter },
+ {0x000a75, 0x000a75, WB_Extend },
+ {0x000a81, 0x000a83, WB_Extend },
+ {0x000a85, 0x000a8d, WB_ALetter },
+ {0x000a8f, 0x000a91, WB_ALetter },
+ {0x000a93, 0x000aa8, WB_ALetter },
+ {0x000aaa, 0x000ab0, WB_ALetter },
+ {0x000ab2, 0x000ab3, WB_ALetter },
+ {0x000ab5, 0x000ab9, WB_ALetter },
+ {0x000abc, 0x000abc, WB_Extend },
+ {0x000abd, 0x000abd, WB_ALetter },
+ {0x000abe, 0x000ac5, WB_Extend },
+ {0x000ac7, 0x000ac9, WB_Extend },
+ {0x000acb, 0x000acd, WB_Extend },
+ {0x000ad0, 0x000ad0, WB_ALetter },
+ {0x000ae0, 0x000ae1, WB_ALetter },
+ {0x000ae2, 0x000ae3, WB_Extend },
+ {0x000ae6, 0x000aef, WB_Numeric },
+ {0x000af9, 0x000af9, WB_ALetter },
+ {0x000afa, 0x000aff, WB_Extend },
+ {0x000b01, 0x000b03, WB_Extend },
+ {0x000b05, 0x000b0c, WB_ALetter },
+ {0x000b0f, 0x000b10, WB_ALetter },
+ {0x000b13, 0x000b28, WB_ALetter },
+ {0x000b2a, 0x000b30, WB_ALetter },
+ {0x000b32, 0x000b33, WB_ALetter },
+ {0x000b35, 0x000b39, WB_ALetter },
+ {0x000b3c, 0x000b3c, WB_Extend },
+ {0x000b3d, 0x000b3d, WB_ALetter },
+ {0x000b3e, 0x000b44, WB_Extend },
+ {0x000b47, 0x000b48, WB_Extend },
+ {0x000b4b, 0x000b4d, WB_Extend },
+ {0x000b56, 0x000b57, WB_Extend },
+ {0x000b5c, 0x000b5d, WB_ALetter },
+ {0x000b5f, 0x000b61, WB_ALetter },
+ {0x000b62, 0x000b63, WB_Extend },
+ {0x000b66, 0x000b6f, WB_Numeric },
+ {0x000b71, 0x000b71, WB_ALetter },
+ {0x000b82, 0x000b82, WB_Extend },
+ {0x000b83, 0x000b83, WB_ALetter },
+ {0x000b85, 0x000b8a, WB_ALetter },
+ {0x000b8e, 0x000b90, WB_ALetter },
+ {0x000b92, 0x000b95, WB_ALetter },
+ {0x000b99, 0x000b9a, WB_ALetter },
+ {0x000b9c, 0x000b9c, WB_ALetter },
+ {0x000b9e, 0x000b9f, WB_ALetter },
+ {0x000ba3, 0x000ba4, WB_ALetter },
+ {0x000ba8, 0x000baa, WB_ALetter },
+ {0x000bae, 0x000bb9, WB_ALetter },
+ {0x000bbe, 0x000bc2, WB_Extend },
+ {0x000bc6, 0x000bc8, WB_Extend },
+ {0x000bca, 0x000bcd, WB_Extend },
+ {0x000bd0, 0x000bd0, WB_ALetter },
+ {0x000bd7, 0x000bd7, WB_Extend },
+ {0x000be6, 0x000bef, WB_Numeric },
+ {0x000c00, 0x000c04, WB_Extend },
+ {0x000c05, 0x000c0c, WB_ALetter },
+ {0x000c0e, 0x000c10, WB_ALetter },
+ {0x000c12, 0x000c28, WB_ALetter },
+ {0x000c2a, 0x000c39, WB_ALetter },
+ {0x000c3d, 0x000c3d, WB_ALetter },
+ {0x000c3e, 0x000c44, WB_Extend },
+ {0x000c46, 0x000c48, WB_Extend },
+ {0x000c4a, 0x000c4d, WB_Extend },
+ {0x000c55, 0x000c56, WB_Extend },
+ {0x000c58, 0x000c5a, WB_ALetter },
+ {0x000c60, 0x000c61, WB_ALetter },
+ {0x000c62, 0x000c63, WB_Extend },
+ {0x000c66, 0x000c6f, WB_Numeric },
+ {0x000c80, 0x000c80, WB_ALetter },
+ {0x000c81, 0x000c83, WB_Extend },
+ {0x000c85, 0x000c8c, WB_ALetter },
+ {0x000c8e, 0x000c90, WB_ALetter },
+ {0x000c92, 0x000ca8, WB_ALetter },
+ {0x000caa, 0x000cb3, WB_ALetter },
+ {0x000cb5, 0x000cb9, WB_ALetter },
+ {0x000cbc, 0x000cbc, WB_Extend },
+ {0x000cbd, 0x000cbd, WB_ALetter },
+ {0x000cbe, 0x000cc4, WB_Extend },
+ {0x000cc6, 0x000cc8, WB_Extend },
+ {0x000cca, 0x000ccd, WB_Extend },
+ {0x000cd5, 0x000cd6, WB_Extend },
+ {0x000cde, 0x000cde, WB_ALetter },
+ {0x000ce0, 0x000ce1, WB_ALetter },
+ {0x000ce2, 0x000ce3, WB_Extend },
+ {0x000ce6, 0x000cef, WB_Numeric },
+ {0x000cf1, 0x000cf2, WB_ALetter },
+ {0x000d00, 0x000d03, WB_Extend },
+ {0x000d05, 0x000d0c, WB_ALetter },
+ {0x000d0e, 0x000d10, WB_ALetter },
+ {0x000d12, 0x000d3a, WB_ALetter },
+ {0x000d3b, 0x000d3c, WB_Extend },
+ {0x000d3d, 0x000d3d, WB_ALetter },
+ {0x000d3e, 0x000d44, WB_Extend },
+ {0x000d46, 0x000d48, WB_Extend },
+ {0x000d4a, 0x000d4d, WB_Extend },
+ {0x000d4e, 0x000d4e, WB_ALetter },
+ {0x000d54, 0x000d56, WB_ALetter },
+ {0x000d57, 0x000d57, WB_Extend },
+ {0x000d5f, 0x000d61, WB_ALetter },
+ {0x000d62, 0x000d63, WB_Extend },
+ {0x000d66, 0x000d6f, WB_Numeric },
+ {0x000d7a, 0x000d7f, WB_ALetter },
+ {0x000d82, 0x000d83, WB_Extend },
+ {0x000d85, 0x000d96, WB_ALetter },
+ {0x000d9a, 0x000db1, WB_ALetter },
+ {0x000db3, 0x000dbb, WB_ALetter },
+ {0x000dbd, 0x000dbd, WB_ALetter },
+ {0x000dc0, 0x000dc6, WB_ALetter },
+ {0x000dca, 0x000dca, WB_Extend },
+ {0x000dcf, 0x000dd4, WB_Extend },
+ {0x000dd6, 0x000dd6, WB_Extend },
+ {0x000dd8, 0x000ddf, WB_Extend },
+ {0x000de6, 0x000def, WB_Numeric },
+ {0x000df2, 0x000df3, WB_Extend },
+ {0x000e31, 0x000e31, WB_Extend },
+ {0x000e34, 0x000e3a, WB_Extend },
+ {0x000e47, 0x000e4e, WB_Extend },
+ {0x000e50, 0x000e59, WB_Numeric },
+ {0x000eb1, 0x000eb1, WB_Extend },
+ {0x000eb4, 0x000ebc, WB_Extend },
+ {0x000ec8, 0x000ecd, WB_Extend },
+ {0x000ed0, 0x000ed9, WB_Numeric },
+ {0x000f00, 0x000f00, WB_ALetter },
+ {0x000f18, 0x000f19, WB_Extend },
+ {0x000f20, 0x000f29, WB_Numeric },
+ {0x000f35, 0x000f35, WB_Extend },
+ {0x000f37, 0x000f37, WB_Extend },
+ {0x000f39, 0x000f39, WB_Extend },
+ {0x000f3e, 0x000f3f, WB_Extend },
+ {0x000f40, 0x000f47, WB_ALetter },
+ {0x000f49, 0x000f6c, WB_ALetter },
+ {0x000f71, 0x000f84, WB_Extend },
+ {0x000f86, 0x000f87, WB_Extend },
+ {0x000f88, 0x000f8c, WB_ALetter },
+ {0x000f8d, 0x000f97, WB_Extend },
+ {0x000f99, 0x000fbc, WB_Extend },
+ {0x000fc6, 0x000fc6, WB_Extend },
+ {0x00102b, 0x00103e, WB_Extend },
+ {0x001040, 0x001049, WB_Numeric },
+ {0x001056, 0x001059, WB_Extend },
+ {0x00105e, 0x001060, WB_Extend },
+ {0x001062, 0x001064, WB_Extend },
+ {0x001067, 0x00106d, WB_Extend },
+ {0x001071, 0x001074, WB_Extend },
+ {0x001082, 0x00108d, WB_Extend },
+ {0x00108f, 0x00108f, WB_Extend },
+ {0x001090, 0x001099, WB_Numeric },
+ {0x00109a, 0x00109d, WB_Extend },
+ {0x0010a0, 0x0010c5, WB_ALetter },
+ {0x0010c7, 0x0010c7, WB_ALetter },
+ {0x0010cd, 0x0010cd, WB_ALetter },
+ {0x0010d0, 0x0010fa, WB_ALetter },
+ {0x0010fc, 0x001248, WB_ALetter },
+ {0x00124a, 0x00124d, WB_ALetter },
+ {0x001250, 0x001256, WB_ALetter },
+ {0x001258, 0x001258, WB_ALetter },
+ {0x00125a, 0x00125d, WB_ALetter },
+ {0x001260, 0x001288, WB_ALetter },
+ {0x00128a, 0x00128d, WB_ALetter },
+ {0x001290, 0x0012b0, WB_ALetter },
+ {0x0012b2, 0x0012b5, WB_ALetter },
+ {0x0012b8, 0x0012be, WB_ALetter },
+ {0x0012c0, 0x0012c0, WB_ALetter },
+ {0x0012c2, 0x0012c5, WB_ALetter },
+ {0x0012c8, 0x0012d6, WB_ALetter },
+ {0x0012d8, 0x001310, WB_ALetter },
+ {0x001312, 0x001315, WB_ALetter },
+ {0x001318, 0x00135a, WB_ALetter },
+ {0x00135d, 0x00135f, WB_Extend },
+ {0x001380, 0x00138f, WB_ALetter },
+ {0x0013a0, 0x0013f5, WB_ALetter },
+ {0x0013f8, 0x0013fd, WB_ALetter },
+ {0x001401, 0x00166c, WB_ALetter },
+ {0x00166f, 0x00167f, WB_ALetter },
+ {0x001680, 0x001680, WB_WSegSpace },
+ {0x001681, 0x00169a, WB_ALetter },
+ {0x0016a0, 0x0016ea, WB_ALetter },
+ {0x0016ee, 0x0016f8, WB_ALetter },
+ {0x001700, 0x00170c, WB_ALetter },
+ {0x00170e, 0x001711, WB_ALetter },
+ {0x001712, 0x001714, WB_Extend },
+ {0x001720, 0x001731, WB_ALetter },
+ {0x001732, 0x001734, WB_Extend },
+ {0x001740, 0x001751, WB_ALetter },
+ {0x001752, 0x001753, WB_Extend },
+ {0x001760, 0x00176c, WB_ALetter },
+ {0x00176e, 0x001770, WB_ALetter },
+ {0x001772, 0x001773, WB_Extend },
+ {0x0017b4, 0x0017d3, WB_Extend },
+ {0x0017dd, 0x0017dd, WB_Extend },
+ {0x0017e0, 0x0017e9, WB_Numeric },
+ {0x00180b, 0x00180d, WB_Extend },
+ {0x00180e, 0x00180e, WB_Format },
+ {0x001810, 0x001819, WB_Numeric },
+ {0x001820, 0x001878, WB_ALetter },
+ {0x001880, 0x001884, WB_ALetter },
+ {0x001885, 0x001886, WB_Extend },
+ {0x001887, 0x0018a8, WB_ALetter },
+ {0x0018a9, 0x0018a9, WB_Extend },
+ {0x0018aa, 0x0018aa, WB_ALetter },
+ {0x0018b0, 0x0018f5, WB_ALetter },
+ {0x001900, 0x00191e, WB_ALetter },
+ {0x001920, 0x00192b, WB_Extend },
+ {0x001930, 0x00193b, WB_Extend },
+ {0x001946, 0x00194f, WB_Numeric },
+ {0x0019d0, 0x0019d9, WB_Numeric },
+ {0x001a00, 0x001a16, WB_ALetter },
+ {0x001a17, 0x001a1b, WB_Extend },
+ {0x001a55, 0x001a5e, WB_Extend },
+ {0x001a60, 0x001a7c, WB_Extend },
+ {0x001a7f, 0x001a7f, WB_Extend },
+ {0x001a80, 0x001a89, WB_Numeric },
+ {0x001a90, 0x001a99, WB_Numeric },
+ {0x001ab0, 0x001abe, WB_Extend },
+ {0x001b00, 0x001b04, WB_Extend },
+ {0x001b05, 0x001b33, WB_ALetter },
+ {0x001b34, 0x001b44, WB_Extend },
+ {0x001b45, 0x001b4b, WB_ALetter },
+ {0x001b50, 0x001b59, WB_Numeric },
+ {0x001b6b, 0x001b73, WB_Extend },
+ {0x001b80, 0x001b82, WB_Extend },
+ {0x001b83, 0x001ba0, WB_ALetter },
+ {0x001ba1, 0x001bad, WB_Extend },
+ {0x001bae, 0x001baf, WB_ALetter },
+ {0x001bb0, 0x001bb9, WB_Numeric },
+ {0x001bba, 0x001be5, WB_ALetter },
+ {0x001be6, 0x001bf3, WB_Extend },
+ {0x001c00, 0x001c23, WB_ALetter },
+ {0x001c24, 0x001c37, WB_Extend },
+ {0x001c40, 0x001c49, WB_Numeric },
+ {0x001c4d, 0x001c4f, WB_ALetter },
+ {0x001c50, 0x001c59, WB_Numeric },
+ {0x001c5a, 0x001c7d, WB_ALetter },
+ {0x001c80, 0x001c88, WB_ALetter },
+ {0x001c90, 0x001cba, WB_ALetter },
+ {0x001cbd, 0x001cbf, WB_ALetter },
+ {0x001cd0, 0x001cd2, WB_Extend },
+ {0x001cd4, 0x001ce8, WB_Extend },
+ {0x001ce9, 0x001cec, WB_ALetter },
+ {0x001ced, 0x001ced, WB_Extend },
+ {0x001cee, 0x001cf3, WB_ALetter },
+ {0x001cf4, 0x001cf4, WB_Extend },
+ {0x001cf5, 0x001cf6, WB_ALetter },
+ {0x001cf7, 0x001cf9, WB_Extend },
+ {0x001cfa, 0x001cfa, WB_ALetter },
+ {0x001d00, 0x001dbf, WB_ALetter },
+ {0x001dc0, 0x001df9, WB_Extend },
+ {0x001dfb, 0x001dff, WB_Extend },
+ {0x001e00, 0x001f15, WB_ALetter },
+ {0x001f18, 0x001f1d, WB_ALetter },
+ {0x001f20, 0x001f45, WB_ALetter },
+ {0x001f48, 0x001f4d, WB_ALetter },
+ {0x001f50, 0x001f57, WB_ALetter },
+ {0x001f59, 0x001f59, WB_ALetter },
+ {0x001f5b, 0x001f5b, WB_ALetter },
+ {0x001f5d, 0x001f5d, WB_ALetter },
+ {0x001f5f, 0x001f7d, WB_ALetter },
+ {0x001f80, 0x001fb4, WB_ALetter },
+ {0x001fb6, 0x001fbc, WB_ALetter },
+ {0x001fbe, 0x001fbe, WB_ALetter },
+ {0x001fc2, 0x001fc4, WB_ALetter },
+ {0x001fc6, 0x001fcc, WB_ALetter },
+ {0x001fd0, 0x001fd3, WB_ALetter },
+ {0x001fd6, 0x001fdb, WB_ALetter },
+ {0x001fe0, 0x001fec, WB_ALetter },
+ {0x001ff2, 0x001ff4, WB_ALetter },
+ {0x001ff6, 0x001ffc, WB_ALetter },
+ {0x002000, 0x002006, WB_WSegSpace },
+ {0x002008, 0x00200a, WB_WSegSpace },
+ {0x00200c, 0x00200c, WB_Extend },
+ {0x00200d, 0x00200d, WB_ZWJ },
+ {0x00200e, 0x00200f, WB_Format },
+ {0x002018, 0x002019, WB_MidNumLet },
+ {0x002024, 0x002024, WB_MidNumLet },
+ {0x002027, 0x002027, WB_MidLetter },
+ {0x002028, 0x002029, WB_Newline },
+ {0x00202a, 0x00202e, WB_Format },
+ {0x00202f, 0x00202f, WB_ExtendNumLet },
+ {0x00203f, 0x002040, WB_ExtendNumLet },
+ {0x002044, 0x002044, WB_MidNum },
+ {0x002054, 0x002054, WB_ExtendNumLet },
+ {0x00205f, 0x00205f, WB_WSegSpace },
+ {0x002060, 0x002064, WB_Format },
+ {0x002066, 0x00206f, WB_Format },
+ {0x002071, 0x002071, WB_ALetter },
+ {0x00207f, 0x00207f, WB_ALetter },
+ {0x002090, 0x00209c, WB_ALetter },
+ {0x0020d0, 0x0020f0, WB_Extend },
+ {0x002102, 0x002102, WB_ALetter },
+ {0x002107, 0x002107, WB_ALetter },
+ {0x00210a, 0x002113, WB_ALetter },
+ {0x002115, 0x002115, WB_ALetter },
+ {0x002119, 0x00211d, WB_ALetter },
+ {0x002124, 0x002124, WB_ALetter },
+ {0x002126, 0x002126, WB_ALetter },
+ {0x002128, 0x002128, WB_ALetter },
+ {0x00212a, 0x00212d, WB_ALetter },
+ {0x00212f, 0x002139, WB_ALetter },
+ {0x00213c, 0x00213f, WB_ALetter },
+ {0x002145, 0x002149, WB_ALetter },
+ {0x00214e, 0x00214e, WB_ALetter },
+ {0x002160, 0x002188, WB_ALetter },
+ {0x0024b6, 0x0024e9, WB_ALetter },
+ {0x002c00, 0x002c2e, WB_ALetter },
+ {0x002c30, 0x002c5e, WB_ALetter },
+ {0x002c60, 0x002ce4, WB_ALetter },
+ {0x002ceb, 0x002cee, WB_ALetter },
+ {0x002cef, 0x002cf1, WB_Extend },
+ {0x002cf2, 0x002cf3, WB_ALetter },
+ {0x002d00, 0x002d25, WB_ALetter },
+ {0x002d27, 0x002d27, WB_ALetter },
+ {0x002d2d, 0x002d2d, WB_ALetter },
+ {0x002d30, 0x002d67, WB_ALetter },
+ {0x002d6f, 0x002d6f, WB_ALetter },
+ {0x002d7f, 0x002d7f, WB_Extend },
+ {0x002d80, 0x002d96, WB_ALetter },
+ {0x002da0, 0x002da6, WB_ALetter },
+ {0x002da8, 0x002dae, WB_ALetter },
+ {0x002db0, 0x002db6, WB_ALetter },
+ {0x002db8, 0x002dbe, WB_ALetter },
+ {0x002dc0, 0x002dc6, WB_ALetter },
+ {0x002dc8, 0x002dce, WB_ALetter },
+ {0x002dd0, 0x002dd6, WB_ALetter },
+ {0x002dd8, 0x002dde, WB_ALetter },
+ {0x002de0, 0x002dff, WB_Extend },
+ {0x002e2f, 0x002e2f, WB_ALetter },
+ {0x003000, 0x003000, WB_WSegSpace },
+ {0x003005, 0x003005, WB_ALetter },
+ {0x00302a, 0x00302f, WB_Extend },
+ {0x003031, 0x003035, WB_Katakana },
+ {0x00303b, 0x00303c, WB_ALetter },
+ {0x003099, 0x00309a, WB_Extend },
+ {0x00309b, 0x00309c, WB_Katakana },
+ {0x0030a0, 0x0030fa, WB_Katakana },
+ {0x0030fc, 0x0030ff, WB_Katakana },
+ {0x003105, 0x00312f, WB_ALetter },
+ {0x003131, 0x00318e, WB_ALetter },
+ {0x0031a0, 0x0031ba, WB_ALetter },
+ {0x0031f0, 0x0031ff, WB_Katakana },
+ {0x0032d0, 0x0032fe, WB_Katakana },
+ {0x003300, 0x003357, WB_Katakana },
+ {0x00a000, 0x00a48c, WB_ALetter },
+ {0x00a4d0, 0x00a4fd, WB_ALetter },
+ {0x00a500, 0x00a60c, WB_ALetter },
+ {0x00a610, 0x00a61f, WB_ALetter },
+ {0x00a620, 0x00a629, WB_Numeric },
+ {0x00a62a, 0x00a62b, WB_ALetter },
+ {0x00a640, 0x00a66e, WB_ALetter },
+ {0x00a66f, 0x00a672, WB_Extend },
+ {0x00a674, 0x00a67d, WB_Extend },
+ {0x00a67f, 0x00a69d, WB_ALetter },
+ {0x00a69e, 0x00a69f, WB_Extend },
+ {0x00a6a0, 0x00a6ef, WB_ALetter },
+ {0x00a6f0, 0x00a6f1, WB_Extend },
+ {0x00a717, 0x00a7bf, WB_ALetter },
+ {0x00a7c2, 0x00a7c6, WB_ALetter },
+ {0x00a7f7, 0x00a801, WB_ALetter },
+ {0x00a802, 0x00a802, WB_Extend },
+ {0x00a803, 0x00a805, WB_ALetter },
+ {0x00a806, 0x00a806, WB_Extend },
+ {0x00a807, 0x00a80a, WB_ALetter },
+ {0x00a80b, 0x00a80b, WB_Extend },
+ {0x00a80c, 0x00a822, WB_ALetter },
+ {0x00a823, 0x00a827, WB_Extend },
+ {0x00a840, 0x00a873, WB_ALetter },
+ {0x00a880, 0x00a881, WB_Extend },
+ {0x00a882, 0x00a8b3, WB_ALetter },
+ {0x00a8b4, 0x00a8c5, WB_Extend },
+ {0x00a8d0, 0x00a8d9, WB_Numeric },
+ {0x00a8e0, 0x00a8f1, WB_Extend },
+ {0x00a8f2, 0x00a8f7, WB_ALetter },
+ {0x00a8fb, 0x00a8fb, WB_ALetter },
+ {0x00a8fd, 0x00a8fe, WB_ALetter },
+ {0x00a8ff, 0x00a8ff, WB_Extend },
+ {0x00a900, 0x00a909, WB_Numeric },
+ {0x00a90a, 0x00a925, WB_ALetter },
+ {0x00a926, 0x00a92d, WB_Extend },
+ {0x00a930, 0x00a946, WB_ALetter },
+ {0x00a947, 0x00a953, WB_Extend },
+ {0x00a960, 0x00a97c, WB_ALetter },
+ {0x00a980, 0x00a983, WB_Extend },
+ {0x00a984, 0x00a9b2, WB_ALetter },
+ {0x00a9b3, 0x00a9c0, WB_Extend },
+ {0x00a9cf, 0x00a9cf, WB_ALetter },
+ {0x00a9d0, 0x00a9d9, WB_Numeric },
+ {0x00a9e5, 0x00a9e5, WB_Extend },
+ {0x00a9f0, 0x00a9f9, WB_Numeric },
+ {0x00aa00, 0x00aa28, WB_ALetter },
+ {0x00aa29, 0x00aa36, WB_Extend },
+ {0x00aa40, 0x00aa42, WB_ALetter },
+ {0x00aa43, 0x00aa43, WB_Extend },
+ {0x00aa44, 0x00aa4b, WB_ALetter },
+ {0x00aa4c, 0x00aa4d, WB_Extend },
+ {0x00aa50, 0x00aa59, WB_Numeric },
+ {0x00aa7b, 0x00aa7d, WB_Extend },
+ {0x00aab0, 0x00aab0, WB_Extend },
+ {0x00aab2, 0x00aab4, WB_Extend },
+ {0x00aab7, 0x00aab8, WB_Extend },
+ {0x00aabe, 0x00aabf, WB_Extend },
+ {0x00aac1, 0x00aac1, WB_Extend },
+ {0x00aae0, 0x00aaea, WB_ALetter },
+ {0x00aaeb, 0x00aaef, WB_Extend },
+ {0x00aaf2, 0x00aaf4, WB_ALetter },
+ {0x00aaf5, 0x00aaf6, WB_Extend },
+ {0x00ab01, 0x00ab06, WB_ALetter },
+ {0x00ab09, 0x00ab0e, WB_ALetter },
+ {0x00ab11, 0x00ab16, WB_ALetter },
+ {0x00ab20, 0x00ab26, WB_ALetter },
+ {0x00ab28, 0x00ab2e, WB_ALetter },
+ {0x00ab30, 0x00ab67, WB_ALetter },
+ {0x00ab70, 0x00abe2, WB_ALetter },
+ {0x00abe3, 0x00abea, WB_Extend },
+ {0x00abec, 0x00abed, WB_Extend },
+ {0x00abf0, 0x00abf9, WB_Numeric },
+ {0x00ac00, 0x00d7a3, WB_ALetter },
+ {0x00d7b0, 0x00d7c6, WB_ALetter },
+ {0x00d7cb, 0x00d7fb, WB_ALetter },
+ {0x00fb00, 0x00fb06, WB_ALetter },
+ {0x00fb13, 0x00fb17, WB_ALetter },
+ {0x00fb1d, 0x00fb1d, WB_Hebrew_Letter },
+ {0x00fb1e, 0x00fb1e, WB_Extend },
+ {0x00fb1f, 0x00fb28, WB_Hebrew_Letter },
+ {0x00fb2a, 0x00fb36, WB_Hebrew_Letter },
+ {0x00fb38, 0x00fb3c, WB_Hebrew_Letter },
+ {0x00fb3e, 0x00fb3e, WB_Hebrew_Letter },
+ {0x00fb40, 0x00fb41, WB_Hebrew_Letter },
+ {0x00fb43, 0x00fb44, WB_Hebrew_Letter },
+ {0x00fb46, 0x00fb4f, WB_Hebrew_Letter },
+ {0x00fb50, 0x00fbb1, WB_ALetter },
+ {0x00fbd3, 0x00fd3d, WB_ALetter },
+ {0x00fd50, 0x00fd8f, WB_ALetter },
+ {0x00fd92, 0x00fdc7, WB_ALetter },
+ {0x00fdf0, 0x00fdfb, WB_ALetter },
+ {0x00fe00, 0x00fe0f, WB_Extend },
+ {0x00fe10, 0x00fe10, WB_MidNum },
+ {0x00fe13, 0x00fe13, WB_MidLetter },
+ {0x00fe14, 0x00fe14, WB_MidNum },
+ {0x00fe20, 0x00fe2f, WB_Extend },
+ {0x00fe33, 0x00fe34, WB_ExtendNumLet },
+ {0x00fe4d, 0x00fe4f, WB_ExtendNumLet },
+ {0x00fe50, 0x00fe50, WB_MidNum },
+ {0x00fe52, 0x00fe52, WB_MidNumLet },
+ {0x00fe54, 0x00fe54, WB_MidNum },
+ {0x00fe55, 0x00fe55, WB_MidLetter },
+ {0x00fe70, 0x00fe74, WB_ALetter },
+ {0x00fe76, 0x00fefc, WB_ALetter },
+ {0x00feff, 0x00feff, WB_Format },
+ {0x00ff07, 0x00ff07, WB_MidNumLet },
+ {0x00ff0c, 0x00ff0c, WB_MidNum },
+ {0x00ff0e, 0x00ff0e, WB_MidNumLet },
+ {0x00ff10, 0x00ff19, WB_Numeric },
+ {0x00ff1a, 0x00ff1a, WB_MidLetter },
+ {0x00ff1b, 0x00ff1b, WB_MidNum },
+ {0x00ff21, 0x00ff3a, WB_ALetter },
+ {0x00ff3f, 0x00ff3f, WB_ExtendNumLet },
+ {0x00ff41, 0x00ff5a, WB_ALetter },
+ {0x00ff66, 0x00ff9d, WB_Katakana },
+ {0x00ff9e, 0x00ff9f, WB_Extend },
+ {0x00ffa0, 0x00ffbe, WB_ALetter },
+ {0x00ffc2, 0x00ffc7, WB_ALetter },
+ {0x00ffca, 0x00ffcf, WB_ALetter },
+ {0x00ffd2, 0x00ffd7, WB_ALetter },
+ {0x00ffda, 0x00ffdc, WB_ALetter },
+ {0x00fff9, 0x00fffb, WB_Format },
+ {0x010000, 0x01000b, WB_ALetter },
+ {0x01000d, 0x010026, WB_ALetter },
+ {0x010028, 0x01003a, WB_ALetter },
+ {0x01003c, 0x01003d, WB_ALetter },
+ {0x01003f, 0x01004d, WB_ALetter },
+ {0x010050, 0x01005d, WB_ALetter },
+ {0x010080, 0x0100fa, WB_ALetter },
+ {0x010140, 0x010174, WB_ALetter },
+ {0x0101fd, 0x0101fd, WB_Extend },
+ {0x010280, 0x01029c, WB_ALetter },
+ {0x0102a0, 0x0102d0, WB_ALetter },
+ {0x0102e0, 0x0102e0, WB_Extend },
+ {0x010300, 0x01031f, WB_ALetter },
+ {0x01032d, 0x01034a, WB_ALetter },
+ {0x010350, 0x010375, WB_ALetter },
+ {0x010376, 0x01037a, WB_Extend },
+ {0x010380, 0x01039d, WB_ALetter },
+ {0x0103a0, 0x0103c3, WB_ALetter },
+ {0x0103c8, 0x0103cf, WB_ALetter },
+ {0x0103d1, 0x0103d5, WB_ALetter },
+ {0x010400, 0x01049d, WB_ALetter },
+ {0x0104a0, 0x0104a9, WB_Numeric },
+ {0x0104b0, 0x0104d3, WB_ALetter },
+ {0x0104d8, 0x0104fb, WB_ALetter },
+ {0x010500, 0x010527, WB_ALetter },
+ {0x010530, 0x010563, WB_ALetter },
+ {0x010600, 0x010736, WB_ALetter },
+ {0x010740, 0x010755, WB_ALetter },
+ {0x010760, 0x010767, WB_ALetter },
+ {0x010800, 0x010805, WB_ALetter },
+ {0x010808, 0x010808, WB_ALetter },
+ {0x01080a, 0x010835, WB_ALetter },
+ {0x010837, 0x010838, WB_ALetter },
+ {0x01083c, 0x01083c, WB_ALetter },
+ {0x01083f, 0x010855, WB_ALetter },
+ {0x010860, 0x010876, WB_ALetter },
+ {0x010880, 0x01089e, WB_ALetter },
+ {0x0108e0, 0x0108f2, WB_ALetter },
+ {0x0108f4, 0x0108f5, WB_ALetter },
+ {0x010900, 0x010915, WB_ALetter },
+ {0x010920, 0x010939, WB_ALetter },
+ {0x010980, 0x0109b7, WB_ALetter },
+ {0x0109be, 0x0109bf, WB_ALetter },
+ {0x010a00, 0x010a00, WB_ALetter },
+ {0x010a01, 0x010a03, WB_Extend },
+ {0x010a05, 0x010a06, WB_Extend },
+ {0x010a0c, 0x010a0f, WB_Extend },
+ {0x010a10, 0x010a13, WB_ALetter },
+ {0x010a15, 0x010a17, WB_ALetter },
+ {0x010a19, 0x010a35, WB_ALetter },
+ {0x010a38, 0x010a3a, WB_Extend },
+ {0x010a3f, 0x010a3f, WB_Extend },
+ {0x010a60, 0x010a7c, WB_ALetter },
+ {0x010a80, 0x010a9c, WB_ALetter },
+ {0x010ac0, 0x010ac7, WB_ALetter },
+ {0x010ac9, 0x010ae4, WB_ALetter },
+ {0x010ae5, 0x010ae6, WB_Extend },
+ {0x010b00, 0x010b35, WB_ALetter },
+ {0x010b40, 0x010b55, WB_ALetter },
+ {0x010b60, 0x010b72, WB_ALetter },
+ {0x010b80, 0x010b91, WB_ALetter },
+ {0x010c00, 0x010c48, WB_ALetter },
+ {0x010c80, 0x010cb2, WB_ALetter },
+ {0x010cc0, 0x010cf2, WB_ALetter },
+ {0x010d00, 0x010d23, WB_ALetter },
+ {0x010d24, 0x010d27, WB_Extend },
+ {0x010d30, 0x010d39, WB_Numeric },
+ {0x010f00, 0x010f1c, WB_ALetter },
+ {0x010f27, 0x010f27, WB_ALetter },
+ {0x010f30, 0x010f45, WB_ALetter },
+ {0x010f46, 0x010f50, WB_Extend },
+ {0x010fe0, 0x010ff6, WB_ALetter },
+ {0x011000, 0x011002, WB_Extend },
+ {0x011003, 0x011037, WB_ALetter },
+ {0x011038, 0x011046, WB_Extend },
+ {0x011066, 0x01106f, WB_Numeric },
+ {0x01107f, 0x011082, WB_Extend },
+ {0x011083, 0x0110af, WB_ALetter },
+ {0x0110b0, 0x0110ba, WB_Extend },
+ {0x0110bd, 0x0110bd, WB_Format },
+ {0x0110cd, 0x0110cd, WB_Format },
+ {0x0110d0, 0x0110e8, WB_ALetter },
+ {0x0110f0, 0x0110f9, WB_Numeric },
+ {0x011100, 0x011102, WB_Extend },
+ {0x011103, 0x011126, WB_ALetter },
+ {0x011127, 0x011134, WB_Extend },
+ {0x011136, 0x01113f, WB_Numeric },
+ {0x011144, 0x011144, WB_ALetter },
+ {0x011145, 0x011146, WB_Extend },
+ {0x011150, 0x011172, WB_ALetter },
+ {0x011173, 0x011173, WB_Extend },
+ {0x011176, 0x011176, WB_ALetter },
+ {0x011180, 0x011182, WB_Extend },
+ {0x011183, 0x0111b2, WB_ALetter },
+ {0x0111b3, 0x0111c0, WB_Extend },
+ {0x0111c1, 0x0111c4, WB_ALetter },
+ {0x0111c9, 0x0111cc, WB_Extend },
+ {0x0111d0, 0x0111d9, WB_Numeric },
+ {0x0111da, 0x0111da, WB_ALetter },
+ {0x0111dc, 0x0111dc, WB_ALetter },
+ {0x011200, 0x011211, WB_ALetter },
+ {0x011213, 0x01122b, WB_ALetter },
+ {0x01122c, 0x011237, WB_Extend },
+ {0x01123e, 0x01123e, WB_Extend },
+ {0x011280, 0x011286, WB_ALetter },
+ {0x011288, 0x011288, WB_ALetter },
+ {0x01128a, 0x01128d, WB_ALetter },
+ {0x01128f, 0x01129d, WB_ALetter },
+ {0x01129f, 0x0112a8, WB_ALetter },
+ {0x0112b0, 0x0112de, WB_ALetter },
+ {0x0112df, 0x0112ea, WB_Extend },
+ {0x0112f0, 0x0112f9, WB_Numeric },
+ {0x011300, 0x011303, WB_Extend },
+ {0x011305, 0x01130c, WB_ALetter },
+ {0x01130f, 0x011310, WB_ALetter },
+ {0x011313, 0x011328, WB_ALetter },
+ {0x01132a, 0x011330, WB_ALetter },
+ {0x011332, 0x011333, WB_ALetter },
+ {0x011335, 0x011339, WB_ALetter },
+ {0x01133b, 0x01133c, WB_Extend },
+ {0x01133d, 0x01133d, WB_ALetter },
+ {0x01133e, 0x011344, WB_Extend },
+ {0x011347, 0x011348, WB_Extend },
+ {0x01134b, 0x01134d, WB_Extend },
+ {0x011350, 0x011350, WB_ALetter },
+ {0x011357, 0x011357, WB_Extend },
+ {0x01135d, 0x011361, WB_ALetter },
+ {0x011362, 0x011363, WB_Extend },
+ {0x011366, 0x01136c, WB_Extend },
+ {0x011370, 0x011374, WB_Extend },
+ {0x011400, 0x011434, WB_ALetter },
+ {0x011435, 0x011446, WB_Extend },
+ {0x011447, 0x01144a, WB_ALetter },
+ {0x011450, 0x011459, WB_Numeric },
+ {0x01145e, 0x01145e, WB_Extend },
+ {0x01145f, 0x01145f, WB_ALetter },
+ {0x011480, 0x0114af, WB_ALetter },
+ {0x0114b0, 0x0114c3, WB_Extend },
+ {0x0114c4, 0x0114c5, WB_ALetter },
+ {0x0114c7, 0x0114c7, WB_ALetter },
+ {0x0114d0, 0x0114d9, WB_Numeric },
+ {0x011580, 0x0115ae, WB_ALetter },
+ {0x0115af, 0x0115b5, WB_Extend },
+ {0x0115b8, 0x0115c0, WB_Extend },
+ {0x0115d8, 0x0115db, WB_ALetter },
+ {0x0115dc, 0x0115dd, WB_Extend },
+ {0x011600, 0x01162f, WB_ALetter },
+ {0x011630, 0x011640, WB_Extend },
+ {0x011644, 0x011644, WB_ALetter },
+ {0x011650, 0x011659, WB_Numeric },
+ {0x011680, 0x0116aa, WB_ALetter },
+ {0x0116ab, 0x0116b7, WB_Extend },
+ {0x0116b8, 0x0116b8, WB_ALetter },
+ {0x0116c0, 0x0116c9, WB_Numeric },
+ {0x01171d, 0x01172b, WB_Extend },
+ {0x011730, 0x011739, WB_Numeric },
+ {0x011800, 0x01182b, WB_ALetter },
+ {0x01182c, 0x01183a, WB_Extend },
+ {0x0118a0, 0x0118df, WB_ALetter },
+ {0x0118e0, 0x0118e9, WB_Numeric },
+ {0x0118ff, 0x0118ff, WB_ALetter },
+ {0x0119a0, 0x0119a7, WB_ALetter },
+ {0x0119aa, 0x0119d0, WB_ALetter },
+ {0x0119d1, 0x0119d7, WB_Extend },
+ {0x0119da, 0x0119e0, WB_Extend },
+ {0x0119e1, 0x0119e1, WB_ALetter },
+ {0x0119e3, 0x0119e3, WB_ALetter },
+ {0x0119e4, 0x0119e4, WB_Extend },
+ {0x011a00, 0x011a00, WB_ALetter },
+ {0x011a01, 0x011a0a, WB_Extend },
+ {0x011a0b, 0x011a32, WB_ALetter },
+ {0x011a33, 0x011a39, WB_Extend },
+ {0x011a3a, 0x011a3a, WB_ALetter },
+ {0x011a3b, 0x011a3e, WB_Extend },
+ {0x011a47, 0x011a47, WB_Extend },
+ {0x011a50, 0x011a50, WB_ALetter },
+ {0x011a51, 0x011a5b, WB_Extend },
+ {0x011a5c, 0x011a89, WB_ALetter },
+ {0x011a8a, 0x011a99, WB_Extend },
+ {0x011a9d, 0x011a9d, WB_ALetter },
+ {0x011ac0, 0x011af8, WB_ALetter },
+ {0x011c00, 0x011c08, WB_ALetter },
+ {0x011c0a, 0x011c2e, WB_ALetter },
+ {0x011c2f, 0x011c36, WB_Extend },
+ {0x011c38, 0x011c3f, WB_Extend },
+ {0x011c40, 0x011c40, WB_ALetter },
+ {0x011c50, 0x011c59, WB_Numeric },
+ {0x011c72, 0x011c8f, WB_ALetter },
+ {0x011c92, 0x011ca7, WB_Extend },
+ {0x011ca9, 0x011cb6, WB_Extend },
+ {0x011d00, 0x011d06, WB_ALetter },
+ {0x011d08, 0x011d09, WB_ALetter },
+ {0x011d0b, 0x011d30, WB_ALetter },
+ {0x011d31, 0x011d36, WB_Extend },
+ {0x011d3a, 0x011d3a, WB_Extend },
+ {0x011d3c, 0x011d3d, WB_Extend },
+ {0x011d3f, 0x011d45, WB_Extend },
+ {0x011d46, 0x011d46, WB_ALetter },
+ {0x011d47, 0x011d47, WB_Extend },
+ {0x011d50, 0x011d59, WB_Numeric },
+ {0x011d60, 0x011d65, WB_ALetter },
+ {0x011d67, 0x011d68, WB_ALetter },
+ {0x011d6a, 0x011d89, WB_ALetter },
+ {0x011d8a, 0x011d8e, WB_Extend },
+ {0x011d90, 0x011d91, WB_Extend },
+ {0x011d93, 0x011d97, WB_Extend },
+ {0x011d98, 0x011d98, WB_ALetter },
+ {0x011da0, 0x011da9, WB_Numeric },
+ {0x011ee0, 0x011ef2, WB_ALetter },
+ {0x011ef3, 0x011ef6, WB_Extend },
+ {0x012000, 0x012399, WB_ALetter },
+ {0x012400, 0x01246e, WB_ALetter },
+ {0x012480, 0x012543, WB_ALetter },
+ {0x013000, 0x01342e, WB_ALetter },
+ {0x013430, 0x013438, WB_Format },
+ {0x014400, 0x014646, WB_ALetter },
+ {0x016800, 0x016a38, WB_ALetter },
+ {0x016a40, 0x016a5e, WB_ALetter },
+ {0x016a60, 0x016a69, WB_Numeric },
+ {0x016ad0, 0x016aed, WB_ALetter },
+ {0x016af0, 0x016af4, WB_Extend },
+ {0x016b00, 0x016b2f, WB_ALetter },
+ {0x016b30, 0x016b36, WB_Extend },
+ {0x016b40, 0x016b43, WB_ALetter },
+ {0x016b50, 0x016b59, WB_Numeric },
+ {0x016b63, 0x016b77, WB_ALetter },
+ {0x016b7d, 0x016b8f, WB_ALetter },
+ {0x016e40, 0x016e7f, WB_ALetter },
+ {0x016f00, 0x016f4a, WB_ALetter },
+ {0x016f4f, 0x016f4f, WB_Extend },
+ {0x016f50, 0x016f50, WB_ALetter },
+ {0x016f51, 0x016f87, WB_Extend },
+ {0x016f8f, 0x016f92, WB_Extend },
+ {0x016f93, 0x016f9f, WB_ALetter },
+ {0x016fe0, 0x016fe1, WB_ALetter },
+ {0x016fe3, 0x016fe3, WB_ALetter },
+ {0x01b000, 0x01b000, WB_Katakana },
+ {0x01b164, 0x01b167, WB_Katakana },
+ {0x01bc00, 0x01bc6a, WB_ALetter },
+ {0x01bc70, 0x01bc7c, WB_ALetter },
+ {0x01bc80, 0x01bc88, WB_ALetter },
+ {0x01bc90, 0x01bc99, WB_ALetter },
+ {0x01bc9d, 0x01bc9e, WB_Extend },
+ {0x01bca0, 0x01bca3, WB_Format },
+ {0x01d165, 0x01d169, WB_Extend },
+ {0x01d16d, 0x01d172, WB_Extend },
+ {0x01d173, 0x01d17a, WB_Format },
+ {0x01d17b, 0x01d182, WB_Extend },
+ {0x01d185, 0x01d18b, WB_Extend },
+ {0x01d1aa, 0x01d1ad, WB_Extend },
+ {0x01d242, 0x01d244, WB_Extend },
+ {0x01d400, 0x01d454, WB_ALetter },
+ {0x01d456, 0x01d49c, WB_ALetter },
+ {0x01d49e, 0x01d49f, WB_ALetter },
+ {0x01d4a2, 0x01d4a2, WB_ALetter },
+ {0x01d4a5, 0x01d4a6, WB_ALetter },
+ {0x01d4a9, 0x01d4ac, WB_ALetter },
+ {0x01d4ae, 0x01d4b9, WB_ALetter },
+ {0x01d4bb, 0x01d4bb, WB_ALetter },
+ {0x01d4bd, 0x01d4c3, WB_ALetter },
+ {0x01d4c5, 0x01d505, WB_ALetter },
+ {0x01d507, 0x01d50a, WB_ALetter },
+ {0x01d50d, 0x01d514, WB_ALetter },
+ {0x01d516, 0x01d51c, WB_ALetter },
+ {0x01d51e, 0x01d539, WB_ALetter },
+ {0x01d53b, 0x01d53e, WB_ALetter },
+ {0x01d540, 0x01d544, WB_ALetter },
+ {0x01d546, 0x01d546, WB_ALetter },
+ {0x01d54a, 0x01d550, WB_ALetter },
+ {0x01d552, 0x01d6a5, WB_ALetter },
+ {0x01d6a8, 0x01d6c0, WB_ALetter },
+ {0x01d6c2, 0x01d6da, WB_ALetter },
+ {0x01d6dc, 0x01d6fa, WB_ALetter },
+ {0x01d6fc, 0x01d714, WB_ALetter },
+ {0x01d716, 0x01d734, WB_ALetter },
+ {0x01d736, 0x01d74e, WB_ALetter },
+ {0x01d750, 0x01d76e, WB_ALetter },
+ {0x01d770, 0x01d788, WB_ALetter },
+ {0x01d78a, 0x01d7a8, WB_ALetter },
+ {0x01d7aa, 0x01d7c2, WB_ALetter },
+ {0x01d7c4, 0x01d7cb, WB_ALetter },
+ {0x01d7ce, 0x01d7ff, WB_Numeric },
+ {0x01da00, 0x01da36, WB_Extend },
+ {0x01da3b, 0x01da6c, WB_Extend },
+ {0x01da75, 0x01da75, WB_Extend },
+ {0x01da84, 0x01da84, WB_Extend },
+ {0x01da9b, 0x01da9f, WB_Extend },
+ {0x01daa1, 0x01daaf, WB_Extend },
+ {0x01e000, 0x01e006, WB_Extend },
+ {0x01e008, 0x01e018, WB_Extend },
+ {0x01e01b, 0x01e021, WB_Extend },
+ {0x01e023, 0x01e024, WB_Extend },
+ {0x01e026, 0x01e02a, WB_Extend },
+ {0x01e100, 0x01e12c, WB_ALetter },
+ {0x01e130, 0x01e136, WB_Extend },
+ {0x01e137, 0x01e13d, WB_ALetter },
+ {0x01e140, 0x01e149, WB_Numeric },
+ {0x01e14e, 0x01e14e, WB_ALetter },
+ {0x01e2c0, 0x01e2eb, WB_ALetter },
+ {0x01e2ec, 0x01e2ef, WB_Extend },
+ {0x01e2f0, 0x01e2f9, WB_Numeric },
+ {0x01e800, 0x01e8c4, WB_ALetter },
+ {0x01e8d0, 0x01e8d6, WB_Extend },
+ {0x01e900, 0x01e943, WB_ALetter },
+ {0x01e944, 0x01e94a, WB_Extend },
+ {0x01e94b, 0x01e94b, WB_ALetter },
+ {0x01e950, 0x01e959, WB_Numeric },
+ {0x01ee00, 0x01ee03, WB_ALetter },
+ {0x01ee05, 0x01ee1f, WB_ALetter },
+ {0x01ee21, 0x01ee22, WB_ALetter },
+ {0x01ee24, 0x01ee24, WB_ALetter },
+ {0x01ee27, 0x01ee27, WB_ALetter },
+ {0x01ee29, 0x01ee32, WB_ALetter },
+ {0x01ee34, 0x01ee37, WB_ALetter },
+ {0x01ee39, 0x01ee39, WB_ALetter },
+ {0x01ee3b, 0x01ee3b, WB_ALetter },
+ {0x01ee42, 0x01ee42, WB_ALetter },
+ {0x01ee47, 0x01ee47, WB_ALetter },
+ {0x01ee49, 0x01ee49, WB_ALetter },
+ {0x01ee4b, 0x01ee4b, WB_ALetter },
+ {0x01ee4d, 0x01ee4f, WB_ALetter },
+ {0x01ee51, 0x01ee52, WB_ALetter },
+ {0x01ee54, 0x01ee54, WB_ALetter },
+ {0x01ee57, 0x01ee57, WB_ALetter },
+ {0x01ee59, 0x01ee59, WB_ALetter },
+ {0x01ee5b, 0x01ee5b, WB_ALetter },
+ {0x01ee5d, 0x01ee5d, WB_ALetter },
+ {0x01ee5f, 0x01ee5f, WB_ALetter },
+ {0x01ee61, 0x01ee62, WB_ALetter },
+ {0x01ee64, 0x01ee64, WB_ALetter },
+ {0x01ee67, 0x01ee6a, WB_ALetter },
+ {0x01ee6c, 0x01ee72, WB_ALetter },
+ {0x01ee74, 0x01ee77, WB_ALetter },
+ {0x01ee79, 0x01ee7c, WB_ALetter },
+ {0x01ee7e, 0x01ee7e, WB_ALetter },
+ {0x01ee80, 0x01ee89, WB_ALetter },
+ {0x01ee8b, 0x01ee9b, WB_ALetter },
+ {0x01eea1, 0x01eea3, WB_ALetter },
+ {0x01eea5, 0x01eea9, WB_ALetter },
+ {0x01eeab, 0x01eebb, WB_ALetter },
+ {0x01f130, 0x01f149, WB_ALetter },
+ {0x01f150, 0x01f169, WB_ALetter },
+ {0x01f170, 0x01f189, WB_ALetter },
+ {0x01f1e6, 0x01f1ff, WB_Regional_Indicator },
+ {0x01f3fb, 0x01f3ff, WB_Extend },
+ {0x0e0001, 0x0e0001, WB_Format },
+ {0x0e0020, 0x0e007f, WB_Extend },
+ {0x0e0100, 0x0e01ef, WB_Extend }
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_be.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_be.c
new file mode 100644
index 000000000..3f25d7a15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_be.c
@@ -0,0 +1,276 @@
+/**********************************************************************
+ utf16_be.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regint.h" /* for USE_CALLOUT */
+
+
+static int
+init(void)
+{
+#ifdef USE_CALLOUT
+
+ int id;
+ OnigEncoding enc;
+ char* name;
+ unsigned int args[4];
+ OnigValue opts[4];
+
+ enc = ONIG_ENCODING_UTF16_BE;
+
+ name = "\000F\000A\000I\000L\000\000"; BC0_P(name, fail);
+ name = "\000M\000I\000S\000M\000A\000T\000C\000H\000\000"; BC0_P(name, mismatch);
+
+ name = "\000M\000A\000X\000\000";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_CHAR;
+ opts[0].c = 'X';
+ BC_B_O(name, max, 2, args, 1, opts);
+
+ name = "\000E\000R\000R\000O\000R\000\000";
+ args[0] = ONIG_TYPE_LONG; opts[0].l = ONIG_ABORT;
+ BC_P_O(name, error, 1, args, 1, opts);
+
+ name = "\000C\000O\000U\000N\000T\000\000";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, count, 1, args, 1, opts);
+
+ name = "\000T\000O\000T\000A\000L\000_\000C\000O\000U\000N\000T\000\000";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, total_count, 1, args, 1, opts);
+
+ name = "\000C\000M\000P\000\000";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_STRING;
+ args[2] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ BC_P(name, cmp, 3, args);
+
+#endif /* USE_CALLOUT */
+
+ return ONIG_NORMAL;
+}
+
+static const int EncLen_UTF16[] = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static int
+utf16be_mbc_enc_len(const UChar* p)
+{
+ return EncLen_UTF16[*p];
+}
+
+static int
+is_valid_mbc_string(const UChar* s, const UChar* end)
+{
+ while (s < end) {
+ int len = utf16be_mbc_enc_len(s);
+ if (len == 4) {
+ if (s + 2 >= end)
+ return FALSE;
+ if (! UTF16_IS_SURROGATE_SECOND(*(s+2)))
+ return FALSE;
+ }
+ else
+ if (UTF16_IS_SURROGATE_SECOND(*s))
+ return FALSE;
+
+ s += len;
+ }
+
+ if (s != end)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static int
+utf16be_is_mbc_newline(const UChar* p, const UChar* end)
+{
+ if (p + 1 < end) {
+ if (*(p+1) == NEWLINE_CODE && *p == 0x00)
+ return 1;
+#ifdef USE_UNICODE_ALL_LINE_TERMINATORS
+ if ((
+#ifndef USE_CRNL_AS_LINE_TERMINATOR
+ *(p+1) == 0x0d ||
+#endif
+ *(p+1) == 0x85) && *p == 0x00)
+ return 1;
+
+ if (*p == 0x20 && (*(p+1) == 0x29 || *(p+1) == 0x28))
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+static OnigCodePoint
+utf16be_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
+{
+ OnigCodePoint code;
+
+ if (UTF16_IS_SURROGATE_FIRST(*p)) {
+ code = ((((p[0] - 0xd8) << 2) + ((p[1] & 0xc0) >> 6) + 1) << 16)
+ + ((((p[1] & 0x3f) << 2) + (p[2] - 0xdc)) << 8)
+ + p[3];
+ }
+ else {
+ code = p[0] * 256 + p[1];
+ }
+ return code;
+}
+
+static int
+utf16be_code_to_mbclen(OnigCodePoint code)
+{
+ if (code > 0xffff) {
+ if (code > 0x10ffff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+ else
+ return 4;
+ }
+ else {
+ return 2;
+ }
+}
+
+static int
+utf16be_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar* p = buf;
+
+ if (code > 0xffff) {
+ unsigned int plane, high;
+
+ plane = (code >> 16) - 1;
+ *p++ = (plane >> 2) + 0xd8;
+ high = (code & 0xff00) >> 8;
+ *p++ = ((plane & 0x03) << 6) + (high >> 2);
+ *p++ = (high & 0x03) + 0xdc;
+ *p = (UChar )(code & 0xff);
+ return 4;
+ }
+ else {
+ *p++ = (UChar )((code & 0xff00) >> 8);
+ *p++ = (UChar )(code & 0xff);
+ return 2;
+ }
+}
+
+static int
+utf16be_mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end, UChar* fold)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_ASCII_CODE(*(p+1)) && *p == 0) {
+ p++;
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (*p == 0x49) {
+ *fold++ = 0x01;
+ *fold = 0x31;
+ (*pp) += 2;
+ return 2;
+ }
+ }
+#endif
+
+ *fold++ = 0;
+ *fold = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ *pp += 2;
+ return 2;
+ }
+ else
+ return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF16_BE, flag,
+ pp, end, fold);
+}
+
+static UChar*
+utf16be_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ if (s <= start) return (UChar* )s;
+
+ if ((s - start) % 2 == 1) {
+ s--;
+ }
+
+ if (UTF16_IS_SURROGATE_SECOND(*s) && s > start + 1 &&
+ UTF16_IS_SURROGATE_FIRST(*(s-2)))
+ s -= 2;
+
+ return (UChar* )s;
+}
+
+static int
+utf16be_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_unicode_get_case_fold_codes_by_str(ONIG_ENCODING_UTF16_BE,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingUTF16_BE = {
+ utf16be_mbc_enc_len,
+ "UTF-16BE", /* name */
+ 4, /* max enc length */
+ 2, /* min enc length */
+ utf16be_is_mbc_newline,
+ utf16be_mbc_to_code,
+ utf16be_code_to_mbclen,
+ utf16be_code_to_mbc,
+ utf16be_mbc_case_fold,
+ onigenc_unicode_apply_all_case_fold,
+ utf16be_get_case_fold_codes_by_str,
+ onigenc_unicode_property_name_to_ctype,
+ onigenc_unicode_is_code_ctype,
+ onigenc_utf16_32_get_ctype_code_range,
+ utf16be_left_adjust_char_head,
+ onigenc_always_false_is_allowed_reverse_match,
+ init,
+ 0, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_UNICODE|ENC_FLAG_SKIP_OFFSET_2,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_le.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_le.c
new file mode 100644
index 000000000..2470ca01b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf16_le.c
@@ -0,0 +1,276 @@
+/**********************************************************************
+ utf16_le.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+#include "regint.h" /* for USE_CALLOUT */
+
+static int
+init(void)
+{
+#ifdef USE_CALLOUT
+
+ int id;
+ OnigEncoding enc;
+ char* name;
+ unsigned int args[4];
+ OnigValue opts[4];
+
+ enc = ONIG_ENCODING_UTF16_LE;
+
+ name = "F\000A\000I\000L\000\000\000"; BC0_P(name, fail);
+ name = "M\000I\000S\000M\000A\000T\000C\000H\000\000\000"; BC0_P(name, mismatch);
+
+ name = "M\000A\000X\000\000\000";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_CHAR;
+ opts[0].c = 'X';
+ BC_B_O(name, max, 2, args, 1, opts);
+
+ name = "E\000R\000R\000O\000R\000\000\000";
+ args[0] = ONIG_TYPE_LONG; opts[0].l = ONIG_ABORT;
+ BC_P_O(name, error, 1, args, 1, opts);
+
+ name = "C\000O\000U\000N\000T\000\000\000";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, count, 1, args, 1, opts);
+
+ name = "T\000O\000T\000A\000L\000_\000C\000O\000U\000N\000T\000\000\000";
+ args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
+ BC_B_O(name, total_count, 1, args, 1, opts);
+
+ name = "C\000M\000P\000\000\000";
+ args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ args[1] = ONIG_TYPE_STRING;
+ args[2] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
+ BC_P(name, cmp, 3, args);
+
+#endif /* USE_CALLOUT */
+
+ return ONIG_NORMAL;
+}
+
+static const int EncLen_UTF16[] = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static int
+utf16le_code_to_mbclen(OnigCodePoint code)
+{
+ if (code > 0xffff) {
+ if (code > 0x10ffff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+ else
+ return 4;
+ }
+ else {
+ return 2;
+ }
+}
+
+static int
+utf16le_mbc_enc_len(const UChar* p)
+{
+ return EncLen_UTF16[*(p+1)];
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ const UChar* end1 = end - 1;
+
+ while (p < end1) {
+ int len = utf16le_mbc_enc_len(p);
+ if (len == 4) {
+ if (p + 3 < end && ! UTF16_IS_SURROGATE_SECOND(*(p + 3)))
+ return FALSE;
+ }
+ else
+ if (UTF16_IS_SURROGATE_SECOND(*(p + 1)))
+ return FALSE;
+
+ p += len;
+ }
+
+ if (p != end)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static int
+utf16le_is_mbc_newline(const UChar* p, const UChar* end)
+{
+ if (p + 1 < end) {
+ if (*p == NEWLINE_CODE && *(p+1) == 0x00)
+ return 1;
+#ifdef USE_UNICODE_ALL_LINE_TERMINATORS
+ if ((
+#ifndef USE_CRNL_AS_LINE_TERMINATOR
+ *p == 0x0d ||
+#endif
+ *p == 0x85) && *(p+1) == 0x00)
+ return 1;
+
+ if (*(p+1) == 0x20 && (*p == 0x29 || *p == 0x28))
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+static OnigCodePoint
+utf16le_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
+{
+ OnigCodePoint code;
+ UChar c0 = *p;
+ UChar c1 = *(p+1);
+
+ if (UTF16_IS_SURROGATE_FIRST(c1)) {
+ code = ((((c1 - 0xd8) << 2) + ((c0 & 0xc0) >> 6) + 1) << 16)
+ + ((((c0 & 0x3f) << 2) + (p[3] - 0xdc)) << 8)
+ + p[2];
+ }
+ else {
+ code = c1 * 256 + p[0];
+ }
+ return code;
+}
+
+static int
+utf16le_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar* p = buf;
+
+ if (code > 0xffff) {
+ unsigned int plane, high;
+
+ plane = (code >> 16) - 1;
+ high = (code & 0xff00) >> 8;
+
+ *p++ = ((plane & 0x03) << 6) + (high >> 2);
+ *p++ = (plane >> 2) + 0xd8;
+ *p++ = (UChar )(code & 0xff);
+ *p = (high & 0x03) + 0xdc;
+ return 4;
+ }
+ else {
+ *p++ = (UChar )(code & 0xff);
+ *p++ = (UChar )((code & 0xff00) >> 8);
+ return 2;
+ }
+}
+
+static int
+utf16le_mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end, UChar* fold)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_ASCII_CODE(*p) && *(p+1) == 0) {
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (*p == 0x49) {
+ *fold++ = 0x31;
+ *fold = 0x01;
+ (*pp) += 2;
+ return 2;
+ }
+ }
+#endif
+
+ *fold++ = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ *fold = 0;
+ *pp += 2;
+ return 2;
+ }
+ else
+ return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF16_LE, flag, pp, end,
+ fold);
+}
+
+static UChar*
+utf16le_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ if (s <= start) return (UChar* )s;
+
+ if ((s - start) % 2 == 1) {
+ s--;
+ }
+
+ if (UTF16_IS_SURROGATE_SECOND(*(s+1)) && s > start + 1 &&
+ UTF16_IS_SURROGATE_FIRST(*(s-1)))
+ s -= 2;
+
+ return (UChar* )s;
+}
+
+static int
+utf16le_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_unicode_get_case_fold_codes_by_str(ONIG_ENCODING_UTF16_LE,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingUTF16_LE = {
+ utf16le_mbc_enc_len,
+ "UTF-16LE", /* name */
+ 4, /* max enc length */
+ 2, /* min enc length */
+ utf16le_is_mbc_newline,
+ utf16le_mbc_to_code,
+ utf16le_code_to_mbclen,
+ utf16le_code_to_mbc,
+ utf16le_mbc_case_fold,
+ onigenc_unicode_apply_all_case_fold,
+ utf16le_get_case_fold_codes_by_str,
+ onigenc_unicode_property_name_to_ctype,
+ onigenc_unicode_is_code_ctype,
+ onigenc_utf16_32_get_ctype_code_range,
+ utf16le_left_adjust_char_head,
+ onigenc_always_false_is_allowed_reverse_match,
+ init,
+ 0, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_UNICODE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_be.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_be.c
new file mode 100644
index 000000000..bdd3db767
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_be.c
@@ -0,0 +1,163 @@
+/**********************************************************************
+ utf32_be.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+static int
+utf32be_mbc_enc_len(const UChar* p ARG_UNUSED)
+{
+ return 4;
+}
+
+static int
+is_valid_mbc_string(const UChar* s, const UChar* end)
+{
+ return onigenc_length_check_is_valid_mbc_string(ONIG_ENCODING_UTF32_BE, s, end);
+}
+
+static int
+utf32be_is_mbc_newline(const UChar* p, const UChar* end)
+{
+ if (p + 3 < end) {
+ if (*(p+3) == NEWLINE_CODE && *(p+2) == 0 && *(p+1) == 0 && *p == 0)
+ return 1;
+#ifdef USE_UNICODE_ALL_LINE_TERMINATORS
+ if ((
+#ifndef USE_CRNL_AS_LINE_TERMINATOR
+ *(p+3) == 0x0d ||
+#endif
+ *(p+3) == 0x85)
+ && *(p+2) == 0 && *(p+1) == 0 && *p == 0x00)
+ return 1;
+
+ if (*(p+2) == 0x20 && (*(p+3) == 0x29 || *(p+3) == 0x28)
+ && *(p+1) == 0 && *p == 0)
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+static OnigCodePoint
+utf32be_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
+{
+ return (OnigCodePoint )(((p[0] * 256 + p[1]) * 256 + p[2]) * 256 + p[3]);
+}
+
+static int
+utf32be_code_to_mbclen(OnigCodePoint code ARG_UNUSED)
+{
+ return 4;
+}
+
+static int
+utf32be_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar* p = buf;
+
+ *p++ = (UChar )((code & 0xff000000) >>24);
+ *p++ = (UChar )((code & 0xff0000) >>16);
+ *p++ = (UChar )((code & 0xff00) >> 8);
+ *p++ = (UChar ) (code & 0xff);
+ return 4;
+}
+
+static int
+utf32be_mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end, UChar* fold)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_ASCII_CODE(*(p+3)) && *(p+2) == 0 && *(p+1) == 0 && *p == 0) {
+ *fold++ = 0;
+ *fold++ = 0;
+
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (*(p+3) == 0x49) {
+ *fold++ = 0x01;
+ *fold = 0x31;
+ (*pp) += 4;
+ return 4;
+ }
+ }
+#endif
+
+ *fold++ = 0;
+ *fold = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*(p+3));
+ *pp += 4;
+ return 4;
+ }
+ else
+ return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF32_BE, flag, pp, end,
+ fold);
+}
+
+static UChar*
+utf32be_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ int rem;
+
+ if (s <= start) return (UChar* )s;
+
+ rem = (s - start) % 4;
+ return (UChar* )(s - rem);
+}
+
+static int
+utf32be_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_unicode_get_case_fold_codes_by_str(ONIG_ENCODING_UTF32_BE,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingUTF32_BE = {
+ utf32be_mbc_enc_len,
+ "UTF-32BE", /* name */
+ 4, /* max enc length */
+ 4, /* min enc length */
+ utf32be_is_mbc_newline,
+ utf32be_mbc_to_code,
+ utf32be_code_to_mbclen,
+ utf32be_code_to_mbc,
+ utf32be_mbc_case_fold,
+ onigenc_unicode_apply_all_case_fold,
+ utf32be_get_case_fold_codes_by_str,
+ onigenc_unicode_property_name_to_ctype,
+ onigenc_unicode_is_code_ctype,
+ onigenc_utf16_32_get_ctype_code_range,
+ utf32be_left_adjust_char_head,
+ onigenc_always_false_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_UNICODE|ENC_FLAG_SKIP_OFFSET_4,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_le.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_le.c
new file mode 100644
index 000000000..473ab744d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf32_le.c
@@ -0,0 +1,164 @@
+/**********************************************************************
+ utf32_le.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+static int
+utf32le_mbc_enc_len(const UChar* p ARG_UNUSED)
+{
+ return 4;
+}
+
+static int
+is_valid_mbc_string(const UChar* s, const UChar* end)
+{
+ return onigenc_length_check_is_valid_mbc_string(ONIG_ENCODING_UTF32_LE, s, end);
+}
+
+static int
+utf32le_is_mbc_newline(const UChar* p, const UChar* end)
+{
+ if (p + 3 < end) {
+ if (*p == NEWLINE_CODE && *(p+1) == 0 && *(p+2) == 0 && *(p+3) == 0)
+ return 1;
+#ifdef USE_UNICODE_ALL_LINE_TERMINATORS
+ if ((
+#ifndef USE_CRNL_AS_LINE_TERMINATOR
+ *p == 0x0d ||
+#endif
+ *p == 0x85)
+ && *(p+1) == 0x00 && (p+2) == 0x00 && *(p+3) == 0x00)
+ return 1;
+
+ if (*(p+1) == 0x20 && (*p == 0x29 || *p == 0x28)
+ && *(p+2) == 0x00 && *(p+3) == 0x00)
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+static OnigCodePoint
+utf32le_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
+{
+ return (OnigCodePoint )(((p[3] * 256 + p[2]) * 256 + p[1]) * 256 + p[0]);
+}
+
+static int
+utf32le_code_to_mbclen(OnigCodePoint code ARG_UNUSED)
+{
+ return 4;
+}
+
+static int
+utf32le_code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+ UChar* p = buf;
+
+ *p++ = (UChar ) (code & 0xff);
+ *p++ = (UChar )((code & 0xff00) >> 8);
+ *p++ = (UChar )((code & 0xff0000) >>16);
+ *p++ = (UChar )((code & 0xff000000) >>24);
+ return 4;
+}
+
+static int
+utf32le_mbc_case_fold(OnigCaseFoldType flag,
+ const UChar** pp, const UChar* end, UChar* fold)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_ASCII_CODE(*p) && *(p+1) == 0 && *(p+2) == 0 && *(p+3) == 0) {
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (*p == 0x49) {
+ *fold++ = 0x31;
+ *fold++ = 0x01;
+ }
+ }
+ else {
+#endif
+ *fold++ = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ *fold++ = 0;
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ }
+#endif
+
+ *fold++ = 0;
+ *fold = 0;
+ *pp += 4;
+ return 4;
+ }
+ else
+ return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF32_LE, flag, pp, end,
+ fold);
+}
+
+static UChar*
+utf32le_left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ int rem;
+
+ if (s <= start) return (UChar* )s;
+
+ rem = (s - start) % 4;
+ return (UChar* )(s - rem);
+}
+
+static int
+utf32le_get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_unicode_get_case_fold_codes_by_str(ONIG_ENCODING_UTF32_LE,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingUTF32_LE = {
+ utf32le_mbc_enc_len,
+ "UTF-32LE", /* name */
+ 4, /* max enc length */
+ 4, /* min enc length */
+ utf32le_is_mbc_newline,
+ utf32le_mbc_to_code,
+ utf32le_code_to_mbclen,
+ utf32le_code_to_mbc,
+ utf32le_mbc_case_fold,
+ onigenc_unicode_apply_all_case_fold,
+ utf32le_get_case_fold_codes_by_str,
+ onigenc_unicode_property_name_to_ctype,
+ onigenc_unicode_is_code_ctype,
+ onigenc_utf16_32_get_ctype_code_range,
+ utf32le_left_adjust_char_head,
+ onigenc_always_false_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_UNICODE|ENC_FLAG_SKIP_OFFSET_1,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf8.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf8.c
new file mode 100644
index 000000000..1178d09a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/src/utf8.c
@@ -0,0 +1,290 @@
+/**********************************************************************
+ utf8.c - Oniguruma (regular expression library)
+**********************************************************************/
+/*-
+ * Copyright (c) 2002-2019 K.Kosako
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include "regenc.h"
+
+/* U+0000 - U+10FFFF */
+#define USE_RFC3629_RANGE
+
+/* #define USE_INVALID_CODE_SCHEME */
+
+#ifdef USE_INVALID_CODE_SCHEME
+/* virtual codepoint values for invalid encoding byte 0xfe and 0xff */
+#define INVALID_CODE_FE 0xfffffffe
+#define INVALID_CODE_FF 0xffffffff
+#define VALID_CODE_LIMIT 0x7fffffff
+#endif
+
+#define utf8_islead(c) ((UChar )((c) & 0xc0) != 0x80)
+#define utf8_istail(c) ((UChar )((c) & 0xc0) == 0x80)
+
+static const int EncLen_UTF8[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+#ifdef USE_RFC3629_RANGE
+ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+#else
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
+#endif
+};
+
+static int
+mbc_enc_len(const UChar* p)
+{
+ return EncLen_UTF8[*p];
+}
+
+static int
+is_valid_mbc_string(const UChar* p, const UChar* end)
+{
+ int i, len;
+
+ while (p < end) {
+ if (! utf8_islead(*p))
+ return FALSE;
+
+ len = mbc_enc_len(p++);
+ if (len > 1) {
+ for (i = 1; i < len; i++) {
+ if (p == end)
+ return FALSE;
+
+ if (! utf8_istail(*p++))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static OnigCodePoint
+mbc_to_code(const UChar* p, const UChar* end)
+{
+ int c, len;
+ OnigCodePoint n;
+
+ len = mbc_enc_len(p);
+ if (len > (int )(end - p)) len = (int )(end - p);
+
+ c = *p++;
+ if (len > 1) {
+ len--;
+ n = c & ((1 << (6 - len)) - 1);
+ while (len--) {
+ c = *p++;
+ n = (n << 6) | (c & ((1 << 6) - 1));
+ }
+ return n;
+ }
+ else {
+#ifdef USE_INVALID_CODE_SCHEME
+ if (c > 0xfd) {
+ return ((c == 0xfe) ? INVALID_CODE_FE : INVALID_CODE_FF);
+ }
+#endif
+ return (OnigCodePoint )c;
+ }
+}
+
+static int
+code_to_mbclen(OnigCodePoint code)
+{
+ if ((code & 0xffffff80) == 0) return 1;
+ else if ((code & 0xfffff800) == 0) return 2;
+ else if ((code & 0xffff0000) == 0) return 3;
+ else if ((code & 0xffe00000) == 0) return 4;
+#ifndef USE_RFC3629_RANGE
+ else if ((code & 0xfc000000) == 0) return 5;
+ else if ((code & 0x80000000) == 0) return 6;
+#endif
+#ifdef USE_INVALID_CODE_SCHEME
+ else if (code == INVALID_CODE_FE) return 1;
+ else if (code == INVALID_CODE_FF) return 1;
+#endif
+ else
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+}
+
+static int
+code_to_mbc(OnigCodePoint code, UChar *buf)
+{
+#define UTF8_TRAILS(code, shift) (UChar )((((code) >> (shift)) & 0x3f) | 0x80)
+#define UTF8_TRAIL0(code) (UChar )(((code) & 0x3f) | 0x80)
+
+ if ((code & 0xffffff80) == 0) {
+ *buf = (UChar )code;
+ return 1;
+ }
+ else {
+ UChar *p = buf;
+
+ if ((code & 0xfffff800) == 0) {
+ *p++ = (UChar )(((code>>6)& 0x1f) | 0xc0);
+ }
+ else if ((code & 0xffff0000) == 0) {
+ *p++ = (UChar )(((code>>12) & 0x0f) | 0xe0);
+ *p++ = UTF8_TRAILS(code, 6);
+ }
+ else if ((code & 0xffe00000) == 0) {
+ *p++ = (UChar )(((code>>18) & 0x07) | 0xf0);
+ *p++ = UTF8_TRAILS(code, 12);
+ *p++ = UTF8_TRAILS(code, 6);
+ }
+#ifndef USE_RFC3629_RANGE
+ else if ((code & 0xfc000000) == 0) {
+ *p++ = (UChar )(((code>>24) & 0x03) | 0xf8);
+ *p++ = UTF8_TRAILS(code, 18);
+ *p++ = UTF8_TRAILS(code, 12);
+ *p++ = UTF8_TRAILS(code, 6);
+ }
+ else if ((code & 0x80000000) == 0) {
+ *p++ = (UChar )(((code>>30) & 0x01) | 0xfc);
+ *p++ = UTF8_TRAILS(code, 24);
+ *p++ = UTF8_TRAILS(code, 18);
+ *p++ = UTF8_TRAILS(code, 12);
+ *p++ = UTF8_TRAILS(code, 6);
+ }
+#endif
+#ifdef USE_INVALID_CODE_SCHEME
+ else if (code == INVALID_CODE_FE) {
+ *p = 0xfe;
+ return 1;
+ }
+ else if (code == INVALID_CODE_FF) {
+ *p = 0xff;
+ return 1;
+ }
+#endif
+ else {
+ return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
+ }
+
+ *p++ = UTF8_TRAIL0(code);
+ return (int )(p - buf);
+ }
+}
+
+static int
+mbc_case_fold(OnigCaseFoldType flag, const UChar** pp,
+ const UChar* end, UChar* fold)
+{
+ const UChar* p = *pp;
+
+ if (ONIGENC_IS_MBC_ASCII(p)) {
+#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
+ if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
+ if (*p == 0x49) {
+ *fold++ = 0xc4;
+ *fold = 0xb1;
+ (*pp)++;
+ return 2;
+ }
+ }
+#endif
+
+ *fold = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
+ (*pp)++;
+ return 1; /* return byte length of converted char to lower */
+ }
+ else {
+ return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF8, flag,
+ pp, end, fold);
+ }
+}
+
+static int
+get_ctype_code_range(OnigCtype ctype, OnigCodePoint *sb_out,
+ const OnigCodePoint* ranges[])
+{
+ *sb_out = 0x80;
+ return onigenc_unicode_ctype_code_range(ctype, ranges);
+}
+
+
+static UChar*
+left_adjust_char_head(const UChar* start, const UChar* s)
+{
+ const UChar *p;
+
+ if (s <= start) return (UChar* )s;
+ p = s;
+
+ while (!utf8_islead(*p) && p > start) p--;
+ return (UChar* )p;
+}
+
+static int
+get_case_fold_codes_by_str(OnigCaseFoldType flag,
+ const OnigUChar* p, const OnigUChar* end, OnigCaseFoldCodeItem items[])
+{
+ return onigenc_unicode_get_case_fold_codes_by_str(ONIG_ENCODING_UTF8,
+ flag, p, end, items);
+}
+
+OnigEncodingType OnigEncodingUTF8 = {
+ mbc_enc_len,
+ "UTF-8", /* name */
+#ifdef USE_RFC3629_RANGE
+ 4, /* max enc length */
+#else
+ 6,
+#endif
+ 1, /* min enc length */
+ onigenc_is_mbc_newline_0x0a,
+ mbc_to_code,
+ code_to_mbclen,
+ code_to_mbc,
+ mbc_case_fold,
+ onigenc_unicode_apply_all_case_fold,
+ get_case_fold_codes_by_str,
+ onigenc_unicode_property_name_to_ctype,
+ onigenc_unicode_is_code_ctype,
+ get_ctype_code_range,
+ left_adjust_char_head,
+ onigenc_always_true_is_allowed_reverse_match,
+ NULL, /* init */
+ NULL, /* is_initialized */
+ is_valid_mbc_string,
+ ENC_FLAG_ASCII_COMPATIBLE|ENC_FLAG_UNICODE|ENC_FLAG_SKIP_OFFSET_1_OR_0,
+ 0, 0
+};
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test-driver b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test-driver
new file mode 100755
index 000000000..b8521a482
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test-driver
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 2011-2018 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error. This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+ echo "$0: $*" >&2
+ print_usage >&2
+ exit 2
+}
+
+print_usage ()
+{
+ cat <<END
+Usage:
+ test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+ [--expect-failure={yes|no}] [--color-tests={yes|no}]
+ [--enable-hard-errors={yes|no}] [--]
+ TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file= # Where to save the output of the test script.
+trs_file= # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+ case $1 in
+ --help) print_usage; exit $?;;
+ --version) echo "test-driver $scriptversion"; exit $?;;
+ --test-name) test_name=$2; shift;;
+ --log-file) log_file=$2; shift;;
+ --trs-file) trs_file=$2; shift;;
+ --color-tests) color_tests=$2; shift;;
+ --expect-failure) expect_failure=$2; shift;;
+ --enable-hard-errors) enable_hard_errors=$2; shift;;
+ --) shift; break;;
+ -*) usage_error "invalid option: '$1'";;
+ *) break;;
+ esac
+ shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file" = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+ usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+ usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+ # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+ red='' # Red.
+ grn='' # Green.
+ lgn='' # Light green.
+ blu='' # Blue.
+ mgn='' # Magenta.
+ std='' # No color.
+else
+ red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+ tweaked_estatus=1
+else
+ tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+ 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+ 0:*) col=$grn res=PASS recheck=no gcopy=no;;
+ 77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
+ 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
+ *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
+ *:*) col=$red res=FAIL recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/Makefile.am b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/Makefile.am
new file mode 100644
index 000000000..ada0afbcd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/Makefile.am
@@ -0,0 +1,65 @@
+## Makefile.am for Oniguruma
+lib_onig = ../src/libonig.la
+
+AM_LDFLAGS = -L$(prefix)/lib
+AM_CFLAGS = -Wall -Wno-invalid-source-encoding
+AM_CPPFLAGS = -I$(top_srcdir)/src
+
+if ENABLE_POSIX_API
+TESTS = test_utf8 test_syntax testc testp testcu test_regset
+else
+TESTS = test_utf8 test_syntax testc testcu test_regset
+endif
+
+check_PROGRAMS = $(TESTS)
+
+test: test_uchar $(TESTS)
+ @echo "[Oniguruma API, UTF-8 check]"
+ @./test_utf8 | grep RESULT
+ @echo "[Oniguruma API, SYNTAX check]"
+ @./test_syntax | grep RESULT
+ @echo "[Oniguruma API, ASCII/EUC-JP check]"
+ @./testc | grep RESULT
+if ENABLE_POSIX_API
+ @echo "[POSIX API, ASCII/EUC-JP check]"
+ @./testp | grep RESULT
+endif
+ @echo "[Oniguruma API, UTF-16 check]"
+ @./testcu | grep RESULT
+ @echo ""
+ @echo "[Oniguruma API, regset check]"
+ @./test_regset
+
+test_uchar:
+ @echo "[UChar in oniguruma.h check]"
+ @grep "\(^\|[^g]\)UChar" $(top_srcdir)/src/oniguruma.h
+ @echo ""
+
+test_utf8_SOURCES = test_utf8.c
+test_utf8_LDADD = $(lib_onig)
+
+test_syntax_SOURCES = test_syntax.c
+test_syntax_LDADD = $(lib_onig)
+
+testc_SOURCES = testc.c
+testc_LDADD = $(lib_onig)
+
+testp_SOURCES = testc.c
+testp_LDADD = $(lib_onig)
+testp_CFLAGS = -DPOSIX_TEST -Wall -Wno-invalid-source-encoding
+
+
+testcu_SOURCES = testu.c
+testcu_LDADD = $(lib_onig)
+
+test_regset_SOURCES = test_regset.c
+test_regset_LDADD = $(lib_onig)
+
+
+gcov:
+ make CFLAGS="--coverage" test_utf8
+ make CFLAGS="--coverage" test_syntax
+ make CFLAGS="--coverage" testc
+ make CFLAGS="--coverage" testp
+ make CFLAGS="--coverage" testcu
+ make CFLAGS="--coverage" test_regset
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_regset.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_regset.c
new file mode 100644
index 000000000..9a93a427e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_regset.c
@@ -0,0 +1,456 @@
+/*
+ * test_regset.c --- test for regset API
+ * Copyright (c) 2019 K.Kosako
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "oniguruma.h"
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+
+static int
+make_regset(int line_no, int n, char* pat[], OnigRegSet** rset, int error_no)
+{
+ int r;
+ int i;
+ OnigRegSet* set;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ *rset = NULL;
+ r = onig_regset_new(&set, 0, NULL);
+ if (r != 0) return r;
+
+ for (i = 0; i < n; i++) {
+ r = onig_new(&reg, (UChar* )pat[i], (UChar* )(pat[i] + strlen(pat[i])),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT,
+ &einfo);
+ if (r != 0) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ if (error_no == 0) {
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(stderr, "ERROR: %d: %s /%s/\n", line_no, s, pat[i]);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): %d: /%s/ %d\n", line_no, pat[i], r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL(ERROR): %d: /%s/ %d, %d\n",
+ line_no, pat[i], error_no, r);
+ nfail++;
+ }
+ }
+ return r;
+ }
+
+ r = onig_regset_add(set, reg);
+ if (r != 0) {
+ onig_regset_free(set);
+ fprintf(stderr, "ERROR: %d: onig_regset_add(): /%s/\n", line_no, pat[i]);
+ nerror++;
+ return r;
+ }
+ }
+
+ *rset = set;
+ return 0;
+}
+
+static double
+get_sec(clock_t start, clock_t end)
+{
+ double t;
+
+ t = (double )(end - start) / CLOCKS_PER_SEC;
+ return t;
+}
+
+/* use clock(), because clock_gettime() doesn't exist in Windows and old Unix. */
+
+static int
+time_test(int repeat, int n, char* ps[], char* s, char* end, double* rt_set, double* rt_reg)
+{
+ int r;
+ int i;
+ int match_pos;
+ OnigRegSet* set;
+ clock_t ts1, ts2;
+ double t_set, t_reg;
+
+ r = make_regset(0, n, ps, &set, 0);
+ if (r != 0) return r;
+
+ ts1 = clock();
+ for (i = 0; i < repeat; i++) {
+ r = onig_regset_search(set, (UChar* )s, (UChar* )end, (UChar* )s, (UChar* )end,
+ ONIG_REGSET_POSITION_LEAD, ONIG_OPTION_NONE, &match_pos);
+ if (r < 0) {
+ fprintf(stderr, "FAIL onig_regset_search(POSITION_LEAD): %d\n", r);
+ return r;
+ }
+ }
+
+ ts2 = clock();
+ t_set = get_sec(ts1, ts2);
+
+ ts1 = clock();
+ for (i = 0; i < repeat; i++) {
+ r = onig_regset_search(set, (UChar* )s, (UChar* )end, (UChar* )s, (UChar* )end,
+ ONIG_REGSET_REGEX_LEAD, ONIG_OPTION_NONE, &match_pos);
+ if (r < 0) {
+ fprintf(stderr, "FAIL onig_regset_search(REGEX_LEAD): %d\n", r);
+ return r;
+ }
+ }
+
+ ts2 = clock();
+ t_reg = get_sec(ts1, ts2);
+
+ onig_regset_free(set);
+
+ *rt_set = t_set;
+ *rt_reg = t_reg;
+ return 0;
+}
+
+static void
+fisher_yates_shuffle(int n, char* ps[], char* cps[])
+{
+#define GET_RAND(n) (rand()%(n+1))
+#define SWAP(a,b) { char* tmp = a; a = b; b = tmp; }
+
+ int i;
+
+ for (i = 0; i < n; i++)
+ cps[i] = ps[i];
+
+ for (i = n - 1; i > 0; i--) {
+ int x = GET_RAND(i);
+ SWAP(cps[i], cps[x]);
+ }
+}
+
+static void
+time_compare(int n, char* ps[], char* s, char* end)
+{
+ int r;
+ int i;
+ int repeat;
+ double t_set, t_reg;
+ double total_set, total_reg;
+ char** cps;
+
+ cps = (char** )malloc(sizeof(char*) * n);
+ if (cps == 0) return ;
+
+ repeat = 100 / n;
+ total_set = total_reg = 0.0;
+ for (i = 0; i < n; i++) {
+ fisher_yates_shuffle(n, ps, cps);
+ r = time_test(repeat, n, cps, s, end, &t_set, &t_reg);
+ if (r != 0) return ;
+ total_set += t_set;
+ total_reg += t_reg;
+ }
+
+ free(cps);
+
+ fprintf(stdout, "POS lead: %6.2lfmsec. REG lead: %6.2lfmsec.\n",
+ total_set * 1000.0, total_reg * 1000.0);
+}
+
+
+static OnigRegSetLead XX_LEAD = ONIG_REGSET_POSITION_LEAD;
+
+static void
+xx(int line_no, int n, char* ps[], char* s, int from, int to, int mem, int not, int error_no)
+{
+ int r;
+ int match_pos;
+ int match_index;
+ OnigRegSet* set;
+ char *end;
+
+ r = make_regset(line_no, n, ps, &set, error_no);
+ if (r != 0) return ;
+
+ end = s + strlen(s);
+
+ r = onig_regset_search(set, (UChar* )s, (UChar* )end, (UChar* )s, (UChar* )end,
+ XX_LEAD, ONIG_OPTION_NONE, &match_pos);
+ if (r < 0) {
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): %d\n", line_no);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: %d\n", line_no);
+ nfail++;
+ }
+ }
+ else {
+ if (error_no == 0) {
+ char buf[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )buf, r);
+ fprintf(stderr, "ERROR: %d: %s\n", line_no, buf);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): %d: %d\n", line_no, r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL ERROR NO: %d: %d, %d\n", line_no, error_no, r);
+ nfail++;
+ }
+ }
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): %d\n", line_no);
+ nfail++;
+ }
+ else {
+ OnigRegion* region;
+
+ match_index = r;
+ region = onig_regset_get_region(set, match_index);
+ if (region == 0) {
+ fprintf(stderr, "ERROR: %d: can't get region.\n", line_no);
+ nerror++;
+ return ;
+ }
+
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: %d\n", line_no);
+ nsucc++;
+ }
+ else {
+ char buf[1000];
+ int len;
+ len = region->end[mem] - region->beg[mem];
+ strncpy(buf, s + region->beg[mem], len);
+ buf[len] = '\0';
+ fprintf(stdout, "FAIL: %d: %d-%d : %d-%d (%s)\n", line_no,
+ from, to, region->beg[mem], region->end[mem], buf);
+ nfail++;
+ }
+ }
+ }
+
+ onig_regset_free(set);
+}
+
+static void
+x2(int line_no, int n, char* ps[], char* s, int from, int to)
+{
+ xx(line_no, n, ps, s, from, to, 0, 0, 0);
+}
+
+static void
+x3(int line_no, int n, char* ps[], char* s, int from, int to, int mem)
+{
+ xx(line_no, n, ps, s, from, to, mem, 0, 0);
+}
+
+static void
+n(int line_no, int n, char* ps[], char* s)
+{
+ xx(line_no, n, ps, s, 0, 0, 0, 1, 0);
+}
+
+#define ASIZE(a) sizeof(a)/sizeof(a[0])
+#define X2(ps,s,from,to) x2(__LINE__,ASIZE(ps),ps,s,from,to)
+#define X3(ps,s,from,to,mem) x3(__LINE__,ASIZE(ps),ps,s,from,to,mem)
+#define N(ps,s) n(__LINE__,ASIZE(ps),ps,s)
+#define NZERO(s) n(__LINE__,0,(char** )0,s)
+
+#ifndef _WIN32
+
+/* getdelim() doesn't exist in Windows */
+
+static int
+get_all_content_of_file(char* path, char** rs, char** rend)
+{
+ size_t len;
+ size_t n;
+ char* line;
+ FILE* fp;
+
+ fp = fopen(path, "r");
+ if (fp == 0) return -1;
+
+ n = 0;
+ line = NULL;
+ len = getdelim(&line, &n, EOF, fp);
+ fclose(fp);
+ if (len < 0) return -2;
+
+ *rs = line;
+ *rend = line + len;
+ return 0;
+}
+#endif
+
+
+#define TEXT_PATH "kofu-utf8.txt"
+
+/* --- To get kofu.txt ---
+ $ wget https://www.aozora.gr.jp/cards/000148/files/774_ruby_1640.zip
+ $ unzip 774_ruby_1640.zip
+ $ nkf -Lu -w8 kofu.txt > kofu-utf8.txt
+ (convert encoding to utf-8 with BOM and line terminator to be Unix-form)
+*/
+
+static char* p1[] = {
+ "abc",
+ "(bca)",
+ "(cab)"
+};
+
+static char* p2[] = {
+ "å°èª¬",
+ "9",
+ "å¤ç›®æ¼±çŸ³",
+};
+
+static char* p3[] = {
+ "^ã„る。",
+ "^æ ¡æ­£",
+ "^底本",
+ "^ 翌日",
+};
+
+static char* p4[] = {
+ "《[^》]{5}》",
+ "《[^》]{6}》",
+ "《[^》]{7}》",
+ "《[^》]{8}》",
+ "《[^》]{9}》",
+ "《[^》]{10}》",
+ "《[^》]{11}》",
+ "《[^》]{12}》",
+ "《[^》]{13}》",
+ "《[^》]{14}》",
+ "《[^》]{15}》",
+ "《[^》]{16}》",
+ "《[^》]{17}》",
+ "《[^》]{18}》",
+ "《[^》]{19}》",
+ "《[^》]{20}》",
+};
+
+static char* p5[] = {
+ "å°å®¤åœ­",
+ "bbbbbb",
+ "ドナルド・トランプ",
+ "筑摩書房",
+ "æ¾åŽŸ",
+ "aaaaaaaaa",
+ "bbbbbbbbb",
+ "ccccc",
+ "ddddddddddd",
+ "eee",
+ "ffffffffffff",
+ "gggggggggg",
+ "hhhhhhhhhhhhhh",
+ "iiiiiii",
+};
+
+static char* p6[] = {
+ "^.{1000,}",
+ "æ¾åŽŸ",
+ "å°å®¤åœ­",
+ "ドナルド・トランプ",
+ "筑摩書房",
+};
+
+static char* p7[] = {
+ "0+", "1+", "2+", "3+", "4+", "5+", "6+", "7+", "8+", "9+",
+};
+
+extern int
+main(int argc, char* argv[])
+{
+#ifndef _WIN32
+ int file_exist;
+#endif
+ int r;
+ char *s, *end;
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ srand(12345);
+
+ XX_LEAD = ONIG_REGSET_POSITION_LEAD;
+
+ NZERO(" abab bccab ca");
+ X2(p1, " abab bccab ca", 8, 11);
+ X3(p1, " abab bccab ca", 8, 11, 1);
+ N(p2, " XXXX AAA 1223 012345678bbb");
+ X2(p2, "0123456789", 9, 10);
+ X2(p7, "abcde 555 qwert", 6, 9);
+
+ XX_LEAD = ONIG_REGSET_REGEX_LEAD;
+
+ NZERO(" abab bccab ca");
+ X2(p1, " abab bccab ca", 8, 11);
+ X3(p1, " abab bccab ca", 8, 11, 1);
+ N(p2, " XXXX AAA 1223 012345678bbb");
+ X2(p2, "0123456789", 9, 10);
+ X2(p7, "abcde 555 qwert", 6, 9);
+
+#ifndef _WIN32
+ r = get_all_content_of_file(TEXT_PATH, &s, &end);
+ if (r == 0) {
+ fprintf(stdout, "FILE: %s, size: %d\n", TEXT_PATH, (int )(end - s));
+ file_exist = 1;
+ }
+ else {
+ fprintf(stdout, "Ignore %s\n", TEXT_PATH);
+ file_exist = 0;
+ }
+
+ if (file_exist != 0) {
+ X2(p2, s, 10, 22);
+ X2(p3, s, 496079, 496088);
+ X2(p4, s, 1294, 1315);
+ }
+#endif
+
+ fprintf(stdout,
+ "\nRESULT SUCC: %4d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+#ifndef _WIN32
+ if (file_exist != 0) {
+ fprintf(stdout, "\n");
+ time_compare(ASIZE(p2), p2, s, end);
+ time_compare(ASIZE(p3), p3, s, end);
+ time_compare(ASIZE(p4), p4, s, end);
+ time_compare(ASIZE(p5), p5, s, end);
+ time_compare(ASIZE(p6), p6, s, end);
+ fprintf(stdout, "\n");
+ free(s);
+ }
+#endif
+
+ onig_end();
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_syntax.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_syntax.c
new file mode 100644
index 000000000..df80e5901
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_syntax.c
@@ -0,0 +1,246 @@
+/*
+ * test_syntax.c
+ * Copyright (c) 2019-2020 K.Kosako
+ */
+#include "config.h"
+#ifdef ONIG_ESCAPE_UCHAR_COLLISION
+#undef ONIG_ESCAPE_UCHAR_COLLISION
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "oniguruma.h"
+
+#define SLEN(s) strlen(s)
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+static FILE* err_file;
+
+static OnigRegion* region;
+
+static OnigSyntaxType* Syntax;
+
+static void xx(char* pattern, char* str, int from, int to, int mem, int not,
+ int error_no)
+{
+ int r;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ r = onig_new(&reg, (UChar* )pattern, (UChar* )(pattern + SLEN(pattern)),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, Syntax, &einfo);
+ if (r) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ if (error_no == 0) {
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(err_file, "ERROR: %s /%s/\n", s, pattern);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): /%s/ %d\n", pattern, r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL(ERROR): /%s/ '%s', %d, %d\n", pattern, str,
+ error_no, r);
+ nfail++;
+ }
+ }
+
+ return ;
+ }
+
+ r = onig_search(reg, (UChar* )str, (UChar* )(str + SLEN(str)),
+ (UChar* )str, (UChar* )(str + SLEN(str)),
+ region, ONIG_OPTION_NONE);
+ if (r < ONIG_MISMATCH) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ if (error_no == 0) {
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(err_file, "ERROR: %s /%s/\n", s, pattern);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): /%s/ '%s', %d\n", pattern, str, r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL ERROR NO: /%s/ '%s', %d, %d\n", pattern, str,
+ error_no, r);
+ nfail++;
+ }
+ }
+
+ return ;
+ }
+
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, region->beg[mem], region->end[mem]);
+ nfail++;
+ }
+ }
+ }
+ onig_free(reg);
+}
+
+static void x2(char* pattern, char* str, int from, int to)
+{
+ xx(pattern, str, from, to, 0, 0, 0);
+}
+
+static void x3(char* pattern, char* str, int from, int to, int mem)
+{
+ xx(pattern, str, from, to, mem, 0, 0);
+}
+
+static void n(char* pattern, char* str)
+{
+ xx(pattern, str, 0, 0, 0, 1, 0);
+}
+
+static void e(char* pattern, char* str, int error_no)
+{
+ xx(pattern, str, 0, 0, 0, 0, error_no);
+}
+
+static int test_fixed_interval()
+{
+ x2("a{1,3}?", "aaa", 0, 1);
+ x2("a{3}", "aaa", 0, 3);
+ x2("a{3}?", "aaa", 0, 3);
+ n("a{3}?", "aa");
+ x2("a{3,3}?", "aaa", 0, 3);
+ n("a{3,3}?", "aa");
+
+ x2("a{1,3}+", "aaaaaa", 0, 3);
+ x2("a{3}+", "aaaaaa", 0, 3);
+ x2("a{3,3}+", "aaaaaa", 0, 3);
+
+ return 0;
+}
+
+static int test_isolated_option()
+{
+ x2("", "", 0, 0);
+ x2("^", "", 0, 0);
+ n("^a", "\na");
+ n(".", "\n");
+ x2("(?s:.)", "\n", 0, 1);
+ x2("(?s).", "\n", 0, 1);
+ x2("(?s)a|.", "\n", 0, 1);
+ n("(?s:a)|.", "\n");
+ x2("b(?s)a|.", "\n", 0, 1);
+ n("((?s)a)|.", "\n");
+ n("b(?:(?s)a)|z|.", "\n");
+ n(".|b(?s)a", "\n");
+ n(".(?s)", "\n");
+ n("(?s)(?-s)a|.", "\n");
+ x2("(?s)a|.(?-s)", "\n", 0, 1);
+ x2("(?s)a|((?-s)).", "\n", 0, 1);
+ x2("(?s)a|(?:(?-s)).", "\n", 0, 1); // !!! Perl 5.26.1 returns empty match
+ x2("(?s)a|(?:).", "\n", 0, 1); // !!! Perl 5.26.1 returns empty match
+ x2("(?s)a|(?:.)", "\n", 0, 1);
+ x2("(?s)a|(?:a*).", "\n", 0, 1);
+ n("a|(?:).", "\n"); // !!! Perl 5.26.1 returns empty match
+ n("a|(?:)(.)", "\n");
+ x2("(?s)a|(?:)(.)", "\n", 0, 1);
+ x2("b(?s)a|(?:)(.)", "\n", 0, 1);
+ n("b((?s)a)|(?:)(.)", "\n");
+
+ return 0;
+}
+
+static int test_prec_read()
+{
+ x2("(?=a).b", "ab", 0, 2);
+ x2("(?=ab|(.))\\1", "ab", 1, 2); // doesn't backtrack if success once in prec-read
+ n("(?!(.)z)a\\1", "aa"); // ! Perl 5.26.1 match with "aa"
+
+ return 0;
+}
+
+static int test_look_behind()
+{
+ x2("(?<=a)b", "ab", 1, 2);
+ x2("(?<=a|b)c", "abc", 2, 3);
+ x2("(?<=a|(.))\\1", "abcc", 3, 4);
+
+ // following is not match in Perl and Java
+ //x2("(?<=a|(.))\\1", "aa", 1, 2);
+
+ n("(?<!c|c)a", "ca");
+
+ return 0;
+}
+
+extern int main(int argc, char* argv[])
+{
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ err_file = stdout;
+
+ region = onig_region_new();
+
+ Syntax = ONIG_SYNTAX_PERL;
+
+ test_fixed_interval();
+ test_isolated_option();
+ test_prec_read();
+ test_look_behind();
+ e("(?<=ab|(.))\\1", "abb", ONIGERR_INVALID_LOOK_BEHIND_PATTERN); // Variable length lookbehind not implemented in Perl 5.26.1
+
+ x3("()", "abc", 0, 0, 1);
+ e("(", "", ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS);
+ // different spec.
+ // e("\\x{7fffffff}", "", ONIGERR_TOO_BIG_WIDE_CHAR_VALUE);
+
+ Syntax = ONIG_SYNTAX_JAVA;
+
+ test_fixed_interval();
+ test_isolated_option();
+ test_prec_read();
+ test_look_behind();
+ x2("(?<=ab|(.))\\1", "abb", 2, 3);
+ n("(?<!ab|b)c", "bbc");
+ n("(?<!b|ab)c", "bbc");
+
+ fprintf(stdout,
+ "\nRESULT SUCC: %4d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+ onig_region_free(region, 1);
+ onig_end();
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_utf8.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_utf8.c
new file mode 100644
index 000000000..6e08723f8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/test_utf8.c
@@ -0,0 +1,1438 @@
+/*
+ * test_utf8.c
+ * Copyright (c) 2019-2020 K.Kosako
+ */
+#include "config.h"
+#ifdef ONIG_ESCAPE_UCHAR_COLLISION
+#undef ONIG_ESCAPE_UCHAR_COLLISION
+#endif
+#include <stdio.h>
+
+#include "oniguruma.h"
+
+#include <string.h>
+
+#define SLEN(s) strlen(s)
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+static FILE* err_file;
+
+static OnigRegion* region;
+
+static void xx(char* pattern, char* str, int from, int to, int mem, int not,
+ int error_no)
+{
+ int r;
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ r = onig_new(&reg, (UChar* )pattern, (UChar* )(pattern + SLEN(pattern)),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ if (error_no == 0) {
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(err_file, "ERROR: %s /%s/\n", s, pattern);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): /%s/ %d\n", pattern, r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL(ERROR): /%s/ '%s', %d, %d\n", pattern, str,
+ error_no, r);
+ nfail++;
+ }
+ }
+
+ return ;
+ }
+
+ r = onig_search(reg, (UChar* )str, (UChar* )(str + SLEN(str)),
+ (UChar* )str, (UChar* )(str + SLEN(str)),
+ region, ONIG_OPTION_NONE);
+ if (r < ONIG_MISMATCH) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+
+ if (error_no == 0) {
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(err_file, "ERROR: %s /%s/\n", s, pattern);
+ nerror++;
+ }
+ else {
+ if (r == error_no) {
+ fprintf(stdout, "OK(ERROR): /%s/ '%s', %d\n", pattern, str, r);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL ERROR NO: /%s/ '%s', %d, %d\n", pattern, str,
+ error_no, r);
+ nfail++;
+ }
+ }
+
+ return ;
+ }
+
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, region->beg[mem], region->end[mem]);
+ nfail++;
+ }
+ }
+ }
+ onig_free(reg);
+}
+
+static void x2(char* pattern, char* str, int from, int to)
+{
+ xx(pattern, str, from, to, 0, 0, 0);
+}
+
+static void x3(char* pattern, char* str, int from, int to, int mem)
+{
+ xx(pattern, str, from, to, mem, 0, 0);
+}
+
+static void n(char* pattern, char* str)
+{
+ xx(pattern, str, 0, 0, 0, 1, 0);
+}
+
+static void e(char* pattern, char* str, int error_no)
+{
+ xx(pattern, str, 0, 0, 0, 0, error_no);
+}
+
+extern int main(int argc, char* argv[])
+{
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_UTF8;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ err_file = stdout;
+
+ region = onig_region_new();
+
+ x2("", "", 0, 0);
+ x2("^", "", 0, 0);
+ x2("^a", "\na", 1, 2);
+ x2("$", "", 0, 0);
+ x2("$\\O", "bb\n", 2, 3);
+ x2("\\G", "", 0, 0);
+ x2("\\A", "", 0, 0);
+ x2("\\Z", "", 0, 0);
+ x2("\\z", "", 0, 0);
+ x2("^$", "", 0, 0);
+ x2("\\ca", "\001", 0, 1);
+ x2("\\C-b", "\002", 0, 1);
+ x2("\\c\\\\", "\034", 0, 1);
+ x2("q[\\c\\\\]", "q\034", 0, 2);
+ x2("", "a", 0, 0);
+ x2("a", "a", 0, 1);
+ x2("\\x61", "a", 0, 1);
+ x2("aa", "aa", 0, 2);
+ x2("aaa", "aaa", 0, 3);
+ x2("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 35);
+ x2("ab", "ab", 0, 2);
+ x2("b", "ab", 1, 2);
+ x2("bc", "abc", 1, 3);
+ x2("(?i:#RET#)", "#INS##RET#", 5, 10);
+ x2("\\17", "\017", 0, 1);
+ x2("\\x1f", "\x1f", 0, 1);
+ x2("a(?#....\\\\JJJJ)b", "ab", 0, 2);
+ x2("(?x) G (o O(?-x)oO) g L", "GoOoOgLe", 0, 7);
+ x2(".", "a", 0, 1);
+ n(".", "");
+ x2("..", "ab", 0, 2);
+ x2("\\w", "e", 0, 1);
+ n("\\W", "e");
+ x2("\\s", " ", 0, 1);
+ x2("\\S", "b", 0, 1);
+ x2("\\d", "4", 0, 1);
+ n("\\D", "4");
+ x2("\\b", "z ", 0, 0);
+ x2("\\b", " z", 1, 1);
+ x2("\\b", " z ", 2, 2);
+ x2("\\B", "zz ", 1, 1);
+ x2("\\B", "z ", 2, 2);
+ x2("\\B", " z", 0, 0);
+ x2("[ab]", "b", 0, 1);
+ n("[ab]", "c");
+ x2("[a-z]", "t", 0, 1);
+ n("[^a]", "a");
+ x2("[^a]", "\n", 0, 1);
+ x2("[]]", "]", 0, 1);
+ n("[^]]", "]");
+ x2("[\\^]+", "0^^1", 1, 3);
+ x2("[b-]", "b", 0, 1);
+ x2("[b-]", "-", 0, 1);
+ x2("[\\w]", "z", 0, 1);
+ n("[\\w]", " ");
+ x2("[\\W]", "b$", 1, 2);
+ x2("[\\d]", "5", 0, 1);
+ n("[\\d]", "e");
+ x2("[\\D]", "t", 0, 1);
+ n("[\\D]", "3");
+ x2("[\\s]", " ", 0, 1);
+ n("[\\s]", "a");
+ x2("[\\S]", "b", 0, 1);
+ n("[\\S]", " ");
+ x2("[\\w\\d]", "2", 0, 1);
+ n("[\\w\\d]", " ");
+ x2("[[:upper:]]", "B", 0, 1);
+ x2("[*[:xdigit:]+]", "+", 0, 1);
+ x2("[*[:xdigit:]+]", "GHIKK-9+*", 6, 7);
+ x2("[*[:xdigit:]+]", "-@^+", 3, 4);
+ n("[[:upper]]", "A");
+ x2("[[:upper]]", ":", 0, 1);
+ x2("[\\044-\\047]", "\046", 0, 1);
+ x2("[\\x5a-\\x5c]", "\x5b", 0, 1);
+ x2("[\\x6A-\\x6D]", "\x6c", 0, 1);
+ n("[\\x6A-\\x6D]", "\x6E");
+ n("^[0-9A-F]+ 0+ UNDEF ", "75F 00000000 SECT14A notype () External | _rb_apply");
+ x2("[\\[]", "[", 0, 1);
+ x2("[\\]]", "]", 0, 1);
+ x2("[&]", "&", 0, 1);
+ x2("[[ab]]", "b", 0, 1);
+ x2("[[ab]c]", "c", 0, 1);
+ n("[[^a]]", "a");
+ n("[^[a]]", "a");
+ x2("[[ab]&&bc]", "b", 0, 1);
+ n("[[ab]&&bc]", "a");
+ n("[[ab]&&bc]", "c");
+ x2("[a-z&&b-y&&c-x]", "w", 0, 1);
+ n("[^a-z&&b-y&&c-x]", "w");
+ x2("[[^a&&a]&&a-z]", "b", 0, 1);
+ n("[[^a&&a]&&a-z]", "a");
+ x2("[[^a-z&&bcdef]&&[^c-g]]", "h", 0, 1);
+ n("[[^a-z&&bcdef]&&[^c-g]]", "c");
+ x2("[^[^abc]&&[^cde]]", "c", 0, 1);
+ x2("[^[^abc]&&[^cde]]", "e", 0, 1);
+ n("[^[^abc]&&[^cde]]", "f");
+ x2("[a-&&-a]", "-", 0, 1);
+ n("[a\\-&&\\-a]", "&");
+ n("\\wabc", " abc");
+ x2("a\\Wbc", "a bc", 0, 4);
+ x2("a.b.c", "aabbc", 0, 5);
+ x2(".\\wb\\W..c", "abb bcc", 0, 7);
+ x2("\\s\\wzzz", " zzzz", 0, 5);
+ x2("aa.b", "aabb", 0, 4);
+ n(".a", "ab");
+ x2(".a", "aa", 0, 2);
+ x2("^a", "a", 0, 1);
+ x2("^a$", "a", 0, 1);
+ x2("^\\w$", "a", 0, 1);
+ n("^\\w$", " ");
+ x2("^\\wab$", "zab", 0, 3);
+ x2("^\\wabcdef$", "zabcdef", 0, 7);
+ x2("^\\w...def$", "zabcdef", 0, 7);
+ x2("\\w\\w\\s\\Waaa\\d", "aa aaa4", 0, 8);
+ x2("\\A\\Z", "", 0, 0);
+ x2("\\Axyz", "xyz", 0, 3);
+ x2("xyz\\Z", "xyz", 0, 3);
+ x2("xyz\\z", "xyz", 0, 3);
+ x2("a\\Z", "a", 0, 1);
+ x2("\\Gaz", "az", 0, 2);
+ n("\\Gz", "bza");
+ n("az\\G", "az");
+ n("az\\A", "az");
+ n("a\\Az", "az");
+ x2("\\^\\$", "^$", 0, 2);
+ x2("^x?y", "xy", 0, 2);
+ x2("^(x?y)", "xy", 0, 2);
+ x2("\\w", "_", 0, 1);
+ n("\\W", "_");
+ x2("(?=z)z", "z", 0, 1);
+ n("(?=z).", "a");
+ x2("(?!z)a", "a", 0, 1);
+ n("(?!z)a", "z");
+ x2("(?i:a)", "a", 0, 1);
+ x2("(?i:a)", "A", 0, 1);
+ x2("(?i:A)", "a", 0, 1);
+ x2("(?i:i)", "I", 0, 1);
+ x2("(?i:I)", "i", 0, 1);
+ x2("(?i:[A-Z])", "i", 0, 1);
+ x2("(?i:[a-z])", "I", 0, 1);
+ n("(?i:A)", "b");
+ x2("(?i:ss)", "ss", 0, 2);
+ x2("(?i:ss)", "Ss", 0, 2);
+ x2("(?i:ss)", "SS", 0, 2);
+ /* 0xc5,0xbf == 017F: # LATIN SMALL LETTER LONG S */
+ x2("(?i:ss)", "\xc5\xbfS", 0, 3);
+ x2("(?i:ss)", "s\xc5\xbf", 0, 3);
+ /* 0xc3,0x9f == 00DF: # LATIN SMALL LETTER SHARP S */
+ x2("(?i:ss)", "\xc3\x9f", 0, 2);
+ /* 0xe1,0xba,0x9e == 1E9E # LATIN CAPITAL LETTER SHARP S */
+ x2("(?i:ss)", "\xe1\xba\x9e", 0, 3);
+ x2("(?i:xssy)", "xssy", 0, 4);
+ x2("(?i:xssy)", "xSsy", 0, 4);
+ x2("(?i:xssy)", "xSSy", 0, 4);
+ x2("(?i:xssy)", "x\xc5\xbfSy", 0, 5);
+ x2("(?i:xssy)", "xs\xc5\xbfy", 0, 5);
+ x2("(?i:xssy)", "x\xc3\x9fy", 0, 4);
+ x2("(?i:xssy)", "x\xe1\xba\x9ey", 0, 5);
+ x2("(?i:x\xc3\x9fy)", "xssy", 0, 4);
+ x2("(?i:x\xc3\x9fy)", "xSSy", 0, 4);
+ x2("(?i:\xc3\x9f)", "ss", 0, 2);
+ x2("(?i:\xc3\x9f)", "SS", 0, 2);
+ x2("(?i:[\xc3\x9f])", "ss", 0, 2);
+ x2("(?i:[\xc3\x9f])", "SS", 0, 2);
+ x2("(?i)(?<!ss)z", "qqz", 2, 3);
+ x2("(?i:[A-Z])", "a", 0, 1);
+ x2("(?i:[f-m])", "H", 0, 1);
+ x2("(?i:[f-m])", "h", 0, 1);
+ n("(?i:[f-m])", "e");
+ x2("(?i:[A-c])", "D", 0, 1);
+ n("(?i:[^a-z])", "A");
+ n("(?i:[^a-z])", "a");
+ x2("(?i:[!-k])", "Z", 0, 1);
+ x2("(?i:[!-k])", "7", 0, 1);
+ x2("(?i:[T-}])", "b", 0, 1);
+ x2("(?i:[T-}])", "{", 0, 1);
+ x2("(?i:\\?a)", "?A", 0, 2);
+ x2("(?i:\\*A)", "*a", 0, 2);
+ n(".", "\n");
+ x2("(?m:.)", "\n", 0, 1);
+ x2("(?m:a.)", "a\n", 0, 2);
+ x2("(?m:.b)", "a\nb", 1, 3);
+ x2(".*abc", "dddabdd\nddabc", 8, 13);
+ x2(".+abc", "dddabdd\nddabcaa\naaaabc", 8, 13);
+ x2("(?m:.*abc)", "dddabddabc", 0, 10);
+ n("(?i)(?-i)a", "A");
+ n("(?i)(?-i:a)", "A");
+ x2("a?", "", 0, 0);
+ x2("a?", "b", 0, 0);
+ x2("a?", "a", 0, 1);
+ x2("a*", "", 0, 0);
+ x2("a*", "a", 0, 1);
+ x2("a*", "aaa", 0, 3);
+ x2("a*", "baaaa", 0, 0);
+ n("a+", "");
+ x2("a+", "a", 0, 1);
+ x2("a+", "aaaa", 0, 4);
+ x2("a+", "aabbb", 0, 2);
+ x2("a+", "baaaa", 1, 5);
+ x2(".?", "", 0, 0);
+ x2(".?", "f", 0, 1);
+ x2(".?", "\n", 0, 0);
+ x2(".*", "", 0, 0);
+ x2(".*", "abcde", 0, 5);
+ x2(".+", "z", 0, 1);
+ x2(".+", "zdswer\n", 0, 6);
+ x2("(.*)a\\1f", "babfbac", 0, 4);
+ x2("(.*)a\\1f", "bacbabf", 3, 7);
+ x2("((.*)a\\2f)", "bacbabf", 3, 7);
+ x2("(.*)a\\1f", "baczzzzzz\nbazz\nzzzzbabf", 19, 23);
+ x2("a|b", "a", 0, 1);
+ x2("a|b", "b", 0, 1);
+ x2("|a", "a", 0, 0);
+ x2("(|a)", "a", 0, 0);
+ x2("ab|bc", "ab", 0, 2);
+ x2("ab|bc", "bc", 0, 2);
+ x2("z(?:ab|bc)", "zbc", 0, 3);
+ x2("a(?:ab|bc)c", "aabc", 0, 4);
+ x2("ab|(?:ac|az)", "az", 0, 2);
+ x2("a|b|c", "dc", 1, 2);
+ x2("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "pqr", 0, 2);
+ n("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "mn");
+ x2("a|^z", "ba", 1, 2);
+ x2("a|^z", "za", 0, 1);
+ x2("a|\\Gz", "bza", 2, 3);
+ x2("a|\\Gz", "za", 0, 1);
+ x2("a|\\Az", "bza", 2, 3);
+ x2("a|\\Az", "za", 0, 1);
+ x2("a|b\\Z", "ba", 1, 2);
+ x2("a|b\\Z", "b", 0, 1);
+ x2("a|b\\z", "ba", 1, 2);
+ x2("a|b\\z", "b", 0, 1);
+ x2("\\w|\\s", " ", 0, 1);
+ n("\\w|\\w", " ");
+ x2("\\w|%", "%", 0, 1);
+ x2("\\w|[&$]", "&", 0, 1);
+ x2("[b-d]|[^e-z]", "a", 0, 1);
+ x2("(?:a|[c-f])|bz", "dz", 0, 1);
+ x2("(?:a|[c-f])|bz", "bz", 0, 2);
+ x2("abc|(?=zz)..f", "zzf", 0, 3);
+ x2("abc|(?!zz)..f", "abf", 0, 3);
+ x2("(?=za)..a|(?=zz)..a", "zza", 0, 3);
+ n("(?>a|abd)c", "abdc");
+ x2("(?>abd|a)c", "abdc", 0, 4);
+ x2("a?|b", "a", 0, 1);
+ x2("a?|b", "b", 0, 0);
+ x2("a?|b", "", 0, 0);
+ x2("a*|b", "aa", 0, 2);
+ x2("a*|b*", "ba", 0, 0);
+ x2("a*|b*", "ab", 0, 1);
+ x2("a+|b*", "", 0, 0);
+ x2("a+|b*", "bbb", 0, 3);
+ x2("a+|b*", "abbb", 0, 1);
+ n("a+|b+", "");
+ x2("(a|b)?", "b", 0, 1);
+ x2("(a|b)*", "ba", 0, 2);
+ x2("(a|b)+", "bab", 0, 3);
+ x2("(ab|ca)+", "caabbc", 0, 4);
+ x2("(ab|ca)+", "aabca", 1, 5);
+ x2("(ab|ca)+", "abzca", 0, 2);
+ x2("(a|bab)+", "ababa", 0, 5);
+ x2("(a|bab)+", "ba", 1, 2);
+ x2("(a|bab)+", "baaaba", 1, 4);
+ x2("(?:a|b)(?:a|b)", "ab", 0, 2);
+ x2("(?:a*|b*)(?:a*|b*)", "aaabbb", 0, 3);
+ x2("(?:a*|b*)(?:a+|b+)", "aaabbb", 0, 6);
+ x2("(?:a+|b+){2}", "aaabbb", 0, 6);
+ x2("h{0,}", "hhhh", 0, 4);
+ x2("(?:a+|b+){1,2}", "aaabbb", 0, 6);
+ n("ax{2}*a", "0axxxa1");
+ n("a.{0,2}a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXXa0");
+ x2("^a{2,}?a$", "aaa", 0, 3);
+ x2("^[a-z]{2,}?$", "aaa", 0, 3);
+ x2("(?:a+|\\Ab*)cc", "cc", 0, 2);
+ n("(?:a+|\\Ab*)cc", "abcc");
+ x2("(?:^a+|b+)*c", "aabbbabc", 6, 8);
+ x2("(?:^a+|b+)*c", "aabbbbc", 0, 7);
+ x2("a|(?i)c", "C", 0, 1);
+ x2("(?i)c|a", "C", 0, 1);
+ x2("(?i)c|a", "A", 0, 1);
+ x2("a(?i)b|c", "aB", 0, 2);
+ x2("a(?i)b|c", "aC", 0, 2);
+ n("a(?i)b|c", "AC");
+ n("a(?:(?i)b)|c", "aC");
+ x2("(?i:c)|a", "C", 0, 1);
+ n("(?i:c)|a", "A");
+ x2("[abc]?", "abc", 0, 1);
+ x2("[abc]*", "abc", 0, 3);
+ x2("[^abc]*", "abc", 0, 0);
+ n("[^abc]+", "abc");
+ x2("a?\?", "aaa", 0, 0);
+ x2("ba?\?b", "bab", 0, 3);
+ x2("a*?", "aaa", 0, 0);
+ x2("ba*?", "baa", 0, 1);
+ x2("ba*?b", "baab", 0, 4);
+ x2("a+?", "aaa", 0, 1);
+ x2("ba+?", "baa", 0, 2);
+ x2("ba+?b", "baab", 0, 4);
+ x2("(?:a?)?\?", "a", 0, 0);
+ x2("(?:a?\?)?", "a", 0, 0);
+ x2("(?:a?)+?", "aaa", 0, 1);
+ x2("(?:a+)?\?", "aaa", 0, 0);
+ x2("(?:a+)?\?b", "aaab", 0, 4);
+ x2("(?:ab)?{2}", "", 0, 0);
+ x2("(?:ab)?{2}", "ababa", 0, 4);
+ x2("(?:ab)*{0}", "ababa", 0, 0);
+ x2("(?:ab){3,}", "abababab", 0, 8);
+ n("(?:ab){3,}", "abab");
+ x2("(?:ab){2,4}", "ababab", 0, 6);
+ x2("(?:ab){2,4}", "ababababab", 0, 8);
+ x2("(?:ab){2,4}?", "ababababab", 0, 4);
+ x2("(?:ab){,}", "ab{,}", 0, 5);
+ x2("(?:abc)+?{2}", "abcabcabc", 0, 6);
+ x2("(?:X*)(?i:xa)", "XXXa", 0, 4);
+ x2("(d+)([^abc]z)", "dddz", 0, 4);
+ x2("([^abc]*)([^abc]z)", "dddz", 0, 4);
+ x2("(\\w+)(\\wz)", "dddz", 0, 4);
+ x3("(a)", "a", 0, 1, 1);
+ x3("(ab)", "ab", 0, 2, 1);
+ x2("((ab))", "ab", 0, 2);
+ x3("((ab))", "ab", 0, 2, 1);
+ x3("((ab))", "ab", 0, 2, 2);
+ x3("((((((((((((((((((((ab))))))))))))))))))))", "ab", 0, 2, 20);
+ x3("(ab)(cd)", "abcd", 0, 2, 1);
+ x3("(ab)(cd)", "abcd", 2, 4, 2);
+ x3("()(a)bc(def)ghijk", "abcdefghijk", 3, 6, 3);
+ x3("(()(a)bc(def)ghijk)", "abcdefghijk", 3, 6, 4);
+ x2("(^a)", "a", 0, 1);
+ x3("(a)|(a)", "ba", 1, 2, 1);
+ x3("(^a)|(a)", "ba", 1, 2, 2);
+ x3("(a?)", "aaa", 0, 1, 1);
+ x3("(a*)", "aaa", 0, 3, 1);
+ x3("(a*)", "", 0, 0, 1);
+ x3("(a+)", "aaaaaaa", 0, 7, 1);
+ x3("(a+|b*)", "bbbaa", 0, 3, 1);
+ x3("(a+|b?)", "bbbaa", 0, 1, 1);
+ x3("(abc)?", "abc", 0, 3, 1);
+ x3("(abc)*", "abc", 0, 3, 1);
+ x3("(abc)+", "abc", 0, 3, 1);
+ x3("(xyz|abc)+", "abc", 0, 3, 1);
+ x3("([xyz][abc]|abc)+", "abc", 0, 3, 1);
+ x3("((?i:abc))", "AbC", 0, 3, 1);
+ x2("(abc)(?i:\\1)", "abcABC", 0, 6);
+ x3("((?m:a.c))", "a\nc", 0, 3, 1);
+ x3("((?=az)a)", "azb", 0, 1, 1);
+ x3("abc|(.abd)", "zabd", 0, 4, 1);
+ x2("(?:abc)|(ABC)", "abc", 0, 3);
+ x3("(?i:(abc))|(zzz)", "ABC", 0, 3, 1);
+ x3("a*(.)", "aaaaz", 4, 5, 1);
+ x3("a*?(.)", "aaaaz", 0, 1, 1);
+ x3("a*?(c)", "aaaac", 4, 5, 1);
+ x3("[bcd]a*(.)", "caaaaz", 5, 6, 1);
+ x3("(\\Abb)cc", "bbcc", 0, 2, 1);
+ n("(\\Abb)cc", "zbbcc");
+ x3("(^bb)cc", "bbcc", 0, 2, 1);
+ n("(^bb)cc", "zbbcc");
+ x3("cc(bb$)", "ccbb", 2, 4, 1);
+ n("cc(bb$)", "ccbbb");
+ n("(\\1)", "");
+ n("\\1(a)", "aa");
+ n("(a(b)\\1)\\2+", "ababb");
+ n("(?:(?:\\1|z)(a))+$", "zaa");
+ x2("(?:(?:\\1|z)(a))+$", "zaaa", 0, 4);
+ x2("(a)(?=\\1)", "aa", 0, 1);
+ n("(a)$|\\1", "az");
+ x2("(a)\\1", "aa", 0, 2);
+ n("(a)\\1", "ab");
+ x2("(a?)\\1", "aa", 0, 2);
+ x2("(a?\?)\\1", "aa", 0, 0);
+ x2("(a*)\\1", "aaaaa", 0, 4);
+ x3("(a*)\\1", "aaaaa", 0, 2, 1);
+ x2("a(b*)\\1", "abbbb", 0, 5);
+ x2("a(b*)\\1", "ab", 0, 1);
+ x2("(a*)(b*)\\1\\2", "aaabbaaabb", 0, 10);
+ x2("(a*)(b*)\\2", "aaabbbb", 0, 7);
+ x2("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 8);
+ x3("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 3, 7);
+ x2("(a)(b)(c)\\2\\1\\3", "abcbac", 0, 6);
+ x2("([a-d])\\1", "cc", 0, 2);
+ x2("(\\w\\d\\s)\\1", "f5 f5 ", 0, 6);
+ n("(\\w\\d\\s)\\1", "f5 f5");
+ x2("(who|[a-c]{3})\\1", "whowho", 0, 6);
+ x2("...(who|[a-c]{3})\\1", "abcwhowho", 0, 9);
+ x2("(who|[a-c]{3})\\1", "cbccbc", 0, 6);
+ x2("(^a)\\1", "aa", 0, 2);
+ n("(^a)\\1", "baa");
+ n("(a$)\\1", "aa");
+ n("(ab\\Z)\\1", "ab");
+ x2("(a*\\Z)\\1", "a", 1, 1);
+ x2(".(a*\\Z)\\1", "ba", 1, 2);
+ x3("(.(abc)\\2)", "zabcabc", 0, 7, 1);
+ x3("(.(..\\d.)\\2)", "z12341234", 0, 9, 1);
+ x2("((?i:az))\\1", "AzAz", 0, 4);
+ n("((?i:az))\\1", "Azaz");
+ x2("(?<=a)b", "ab", 1, 2);
+ n("(?<=a)b", "bb");
+ x2("(?<=a|b)b", "bb", 1, 2);
+ x2("(?<=a|bc)b", "bcb", 2, 3);
+ x2("(?<=a|bc)b", "ab", 1, 2);
+ x2("(?<=a|bc||defghij|klmnopq|r)z", "rz", 1, 2);
+ x3("(?<=(abc))d", "abcd", 0, 3, 1);
+ x2("(?<=(?i:abc))d", "ABCd", 3, 4);
+ x2("(a)\\g<1>", "aa", 0, 2);
+ x2("(?<!a)b", "cb", 1, 2);
+ n("(?<!a)b", "ab");
+ x2("(?<!a|bc)b", "bbb", 0, 1);
+ n("(?<!a|bc)z", "bcz");
+ x2("(?<name1>a)", "a", 0, 1);
+ x2("(?<name_2>ab)\\g<name_2>", "abab", 0, 4);
+ x2("(?<name_3>.zv.)\\k<name_3>", "azvbazvb", 0, 8);
+ x2("(?<=\\g<ab>)|-\\zEND (?<ab>XyZ)", "XyZ", 3, 3);
+ x2("(?<n>|a\\g<n>)+", "", 0, 0);
+ x2("(?<n>|\\(\\g<n>\\))+$", "()(())", 0, 6);
+ x3("\\g<n>(?<n>.){0}", "X", 0, 1, 1);
+ x2("\\g<n>(abc|df(?<n>.YZ){2,8}){0}", "XYZ", 0, 3);
+ x2("\\A(?<n>(a\\g<n>)|)\\z", "aaaa", 0, 4);
+ x2("(?<n>|\\g<m>\\g<n>)\\z|\\zEND (?<m>a|(b)\\g<m>)", "bbbbabba", 0, 8);
+ x2("(?<name1240>\\w+\\sx)a+\\k<name1240>", " fg xaaaaaaaafg x", 2, 18);
+ x3("(z)()()(?<_9>a)\\g<_9>", "zaa", 2, 3, 1);
+ x2("(.)(((?<_>a)))\\k<_>", "zaa", 0, 3);
+ x2("((?<name1>\\d)|(?<name2>\\w))(\\k<name1>|\\k<name2>)", "ff", 0, 2);
+ x2("(?:(?<x>)|(?<x>efg))\\k<x>", "", 0, 0);
+ x2("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefgefg", 3, 9);
+ n("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefg");
+ x2("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "a-pyumpyum", 2, 10);
+ x3("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "xxxxabcdefghijklmnabcdefghijklmn", 4, 18, 14);
+ x3("(?<name1>)(?<name2>)(?<name3>)(?<name4>)(?<name5>)(?<name6>)(?<name7>)(?<name8>)(?<name9>)(?<name10>)(?<name11>)(?<name12>)(?<name13>)(?<name14>)(?<name15>)(?<name16>aaa)(?<name17>)$", "aaa", 0, 3, 16);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "a", 0, 1);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "((((((a))))))", 0, 13);
+ x3("(?<foo>a|\\(\\g<foo>\\))", "((((((((a))))))))", 0, 17, 1);
+ x2("\\g<bar>|\\zEND(?<bar>.*abc$)", "abcxxxabc", 0, 9);
+ x2("\\g<1>|\\zEND(.a.)", "bac", 0, 3);
+ x3("\\g<_A>\\g<_A>|\\zEND(.a.)(?<_A>.b.)", "xbxyby", 3, 6, 1);
+ x2("\\A(?:\\g<pon>|\\g<pan>|\\zEND (?<pan>a|c\\g<pon>c)(?<pon>b|d\\g<pan>d))$", "cdcbcdc", 0, 7);
+ x2("\\A(?<n>|a\\g<m>)\\z|\\zEND (?<m>\\g<n>)", "aaaa", 0, 4);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaaca", 1, 5);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaacaaaaa", 0, 10);
+ x2("(?<pare>\\(([^\\(\\)]++|\\g<pare>)*+\\))", "((a))", 0, 5);
+ x2("()*\\1", "", 0, 0);
+ x2("(?:()|())*\\1\\2", "", 0, 0);
+ x2("(?:a*|b*)*c", "abadc", 4, 5);
+ x3("(?:\\1a|())*", "a", 0, 0, 1);
+ x2("x((.)*)*x", "0x1x2x3", 1, 6);
+ x2("x((.)*)*x(?i:\\1)\\Z", "0x1x2x1X2", 1, 9);
+ x2("(?:()|()|()|()|()|())*\\2\\5", "", 0, 0);
+ x2("(?:()|()|()|(x)|()|())*\\2b\\5", "b", 0, 1);
+ x2("[0-9-a]", "-", 0, 1); // PR#44
+ n("[0-9-a]", ":"); // PR#44
+ x3("(\\(((?:[^(]|\\g<1>)*)\\))", "(abc)(abc)", 1, 4, 2); // PR#43
+ x2("\\o{101}", "A", 0, 1);
+ x2("\\A(a|b\\g<1>c)\\k<1+3>\\z", "bbacca", 0, 6);
+ n("\\A(a|b\\g<1>c)\\k<1+3>\\z", "bbaccb");
+ x2("(?i)\\A(a|b\\g<1>c)\\k<1+2>\\z", "bBACcbac", 0, 8);
+ x2("(?i)(?<X>aa)|(?<X>bb)\\k<X>", "BBbb", 0, 4);
+ x2("(?:\\k'+1'B|(A)C)*", "ACAB", 0, 4); // relative backref by postitive number
+ x2("\\g<+2>(abc)(ABC){0}", "ABCabc", 0, 6); // relative call by positive number
+ x2("A\\g'0'|B()", "AAAAB", 0, 5);
+ x3("(A\\g'0')|B", "AAAAB", 0, 5, 1);
+ x2("(a*)(?(1))aa", "aaaaa", 0, 5);
+ x2("(a*)(?(-1))aa", "aaaaa", 0, 5);
+ x2("(?<name>aaa)(?('name'))aa", "aaaaa", 0, 5);
+ x2("(a)(?(1)aa|bb)a", "aaaaa", 0, 4);
+ x2("(?:aa|())(?(<1>)aa|bb)a", "aabba", 0, 5);
+ x2("(?:aa|())(?('1')aa|bb|cc)a", "aacca", 0, 5);
+ x3("(a*)(?(1)aa|a)b", "aaab", 0, 1, 1);
+ n("(a)(?(1)a|b)c", "abc");
+ x2("(a)(?(1)|)c", "ac", 0, 2);
+ n("(?()aaa|bbb)", "bbb");
+ x2("(a)(?(1+0)b|c)d", "abd", 0, 3);
+ x2("(?:(?'name'a)|(?'name'b))(?('name')c|d)e", "ace", 0, 3);
+ x2("(?:(?'name'a)|(?'name'b))(?('name')c|d)e", "bce", 0, 3);
+ x2("\\R", "\r\n", 0, 2);
+ x2("\\R", "\r", 0, 1);
+ x2("\\R", "\n", 0, 1);
+ x2("\\R", "\x0b", 0, 1);
+ n("\\R\\n", "\r\n");
+ x2("\\R", "\xc2\x85", 0, 2);
+ x2("\\N", "a", 0, 1);
+ n("\\N", "\n");
+ n("(?m:\\N)", "\n");
+ n("(?-m:\\N)", "\n");
+ x2("\\O", "a", 0, 1);
+ x2("\\O", "\n", 0, 1);
+ x2("(?m:\\O)", "\n", 0, 1);
+ x2("(?-m:\\O)", "\n", 0, 1);
+ x2("\\K", "a", 0, 0);
+ x2("a\\K", "a", 1, 1);
+ x2("a\\Kb", "ab", 1, 2);
+ x2("(a\\Kb|ac\\Kd)", "acd", 2, 3);
+ x2("(a\\Kb|\\Kac\\K)*", "acababacab", 9, 10);
+ x2("(?:()|())*\\1", "abc", 0, 0);
+ x2("(?:()|())*\\2", "abc", 0, 0);
+ x2("(?:()|()|())*\\3\\1", "abc", 0, 0);
+ x2("(|(?:a(?:\\g'1')*))b|", "abc", 0, 2);
+ x2("^(\"|)(.*)\\1$", "XX", 0, 2);
+ x2("(abc|def|ghi|jkl|mno|pqr|stu){0,10}?\\z", "admno", 2, 5);
+ x2("(abc|(def|ghi|jkl|mno|pqr){0,7}?){5}\\z", "adpqrpqrpqr", 2, 11); // cover OP_REPEAT_INC_NG_SG
+ x2("(?!abc).*\\z", "abcde", 1, 5); // cover OP_PREC_READ_NOT_END
+ x2("(.{2,})?", "abcde", 0, 5); // up coverage
+ x2("((a|b|c|d|e|f|g|h|i|j|k|l|m|n)+)?", "abcde", 0, 5); // up coverage
+ x2("((a|b|c|d|e|f|g|h|i|j|k|l|m|n){3,})?", "abcde", 0, 5); // up coverage
+ x2("((?:a(?:b|c|d|e|f|g|h|i|j|k|l|m|n))+)?", "abacadae", 0, 8); // up coverage
+ x2("((?:a(?:b|c|d|e|f|g|h|i|j|k|l|m|n))+?)?z", "abacadaez", 0, 9); // up coverage
+ x2("\\A((a|b)\?\?)?z", "bz", 0, 2); // up coverage
+ x2("((?<x>abc){0}a\\g<x>d)+", "aabcd", 0, 5); // up coverage
+ x2("((?(abc)true|false))+", "false", 0, 5); // up coverage
+ x2("((?i:abc)d)+", "abcdABCd", 0, 8); // up coverage
+ x2("((?<!abc)def)+", "bcdef", 2, 5); // up coverage
+ x2("(\\ba)+", "aaa", 0, 1); // up coverage
+ x2("()(?<x>ab)(?(<x>)a|b)", "aba", 0, 3); // up coverage
+ x2("(?<=a.b)c", "azbc", 3, 4); // up coverage
+ n("(?<=(?:abcde){30})z", "abc"); // up coverage
+ x2("(?<=(?(a)a|bb))z", "aaz", 2, 3); // up coverage
+ x2("[a]*\\W", "aa@", 0, 3); // up coverage
+ x2("[a]*[b]", "aab", 0, 3); // up coverage
+ n("a*\\W", "aaa"); // up coverage
+ n("(?W)a*\\W", "aaa"); // up coverage
+ x2("(?<=ab(?<=ab))", "ab", 2, 2); // up coverage
+ x2("(?<x>a)(?<x>b)(\\k<x>)+", "abbaab", 0, 6); // up coverage
+ x2("()(\\1)(\\2)", "abc", 0, 0); // up coverage
+ x2("((?(a)b|c))(\\1)", "abab", 0, 4); // up coverage
+ x2("(?<x>$|b\\g<x>)", "bbb", 0, 3); // up coverage
+ x2("(?<x>(?(a)a|b)|c\\g<x>)", "cccb", 0, 4); // up coverage
+ x2("(a)(?(1)a*|b*)+", "aaaa", 0, 4); // up coverage
+ x2("[[^abc]&&cde]*", "de", 0, 2); // up coverage
+ n("(a){10}{10}", "aa"); // up coverage
+ x2("(?:a?)+", "aa", 0, 2); // up coverage
+ x2("(?:a?)*?", "a", 0, 0); // up coverage
+ x2("(?:a*)*?", "a", 0, 0); // up coverage
+ x2("(?:a+?)*", "a", 0, 1); // up coverage
+ x2("\\h", "5", 0, 1); // up coverage
+ x2("\\H", "z", 0, 1); // up coverage
+ x2("[\\h]", "5", 0, 1); // up coverage
+ x2("[\\H]", "z", 0, 1); // up coverage
+ x2("[\\o{101}]", "A", 0, 1); // up coverage
+ x2("[\\u0041]", "A", 0, 1); // up coverage
+
+ x2("(?~)", "", 0, 0);
+ x2("(?~)", "A", 0, 0);
+ x2("aaaaa(?~)", "aaaaaaaaaa", 0, 5);
+ x2("(?~(?:|aaa))", "aaa", 0, 0);
+ x2("(?~aaa|)", "aaa", 0, 0);
+ x2("a(?~(?~)).", "abcdefghijklmnopqrstuvwxyz", 0, 26); // !!!
+ x2("/\\*(?~\\*/)\\*/", "/* */ */", 0, 5);
+ x2("(?~\\w+)zzzzz", "zzzzz", 0, 5);
+ x2("(?~\\w*)zzzzz", "zzzzz", 0, 5);
+ x2("(?~A.C|B)", "ABC", 0, 0);
+ x2("(?~XYZ|ABC)a", "ABCa", 1, 4);
+ x2("(?~XYZ|ABC)a", "aABCa", 0, 1);
+ x2("<[^>]*>(?~[<>])</[^>]*>", "<a>vvv</a> <b> </b>", 0, 10);
+ x2("(?~ab)", "ccc\ndab", 0, 5);
+ x2("(?m:(?~ab))", "ccc\ndab", 0, 5);
+ x2("(?-m:(?~ab))", "ccc\ndab", 0, 5);
+ x2("(?~abc)xyz", "xyz012345678901234567890123456789abc", 0, 3);
+
+ // absent with expr
+ x2("(?~|78|\\d*)", "123456789", 0, 6);
+ x2("(?~|def|(?:abc|de|f){0,100})", "abcdedeabcfdefabc", 0, 11);
+ x2("(?~|ab|.*)", "ccc\nddd", 0, 3);
+ x2("(?~|ab|\\O*)", "ccc\ndab", 0, 5);
+ x2("(?~|ab|\\O{2,10})", "ccc\ndab", 0, 5);
+ x2("(?~|ab|\\O{1,10})", "ab", 1, 2);
+ n("(?~|ab|\\O{2,10})", "ab");
+ x2("(?~|abc|\\O{1,10})", "abc", 1, 3);
+ x2("(?~|ab|\\O{5,10})|abc", "abc", 0, 3);
+ x2("(?~|ab|\\O{1,10})", "cccccccccccab", 0, 10);
+ x2("(?~|aaa|)", "aaa", 0, 0);
+ x2("(?~||a*)", "aaaaaa", 0, 0);
+ x2("(?~||a*?)", "aaaaaa", 0, 0);
+ x2("(a)(?~|b|\\1)", "aaaaaa", 0, 2);
+ x2("(a)(?~|bb|(?:a\\1)*)", "aaaaaa", 0, 5);
+ x2("(b|c)(?~|abac|(?:a\\1)*)", "abababacabab", 1, 4);
+ n("(?~|c|a*+)a", "aaaaa");
+ x2("(?~|aaaaa|a*+)", "aaaaa", 0, 0);
+ x2("(?~|aaaaaa|a*+)b", "aaaaaab", 1, 7);
+ x2("(?~|abcd|(?>))", "zzzabcd", 0, 0);
+ x2("(?~|abc|a*?)", "aaaabc", 0, 0);
+
+ // absent range cutter
+ x2("(?~|abc)a*", "aaaaaabc", 0, 5);
+ x2("(?~|abc)a*z|aaaaaabc", "aaaaaabc", 0, 8);
+ x2("(?~|aaaaaa)a*", "aaaaaa", 0, 0);
+ x2("(?~|abc)aaaa|aaaabc", "aaaabc", 0, 6);
+ x2("(?>(?~|abc))aaaa|aaaabc", "aaaabc", 0, 6);
+ x2("(?~|)a", "a", 0, 1);
+ n("(?~|a)a", "a");
+ x2("(?~|a)(?~|)a", "a", 0, 1);
+ x2("(?~|a).*(?~|)a", "bbbbbbbbbbbbbbbbbbbba", 0, 21);
+ x2("(?~|abc).*(xyz|pqr)(?~|)abc", "aaaaxyzaaapqrabc", 0, 16);
+ x2("(?~|abc).*(xyz|pqr)(?~|)abc", "aaaaxyzaaaabcpqrabc", 11, 19);
+ n("\\A(?~|abc).*(xyz|pqrabc)(?~|)abc", "aaaaxyzaaaabcpqrabcabc");
+
+ x2("", "ã‚", 0, 0);
+ x2("ã‚", "ã‚", 0, 3);
+ n("ã„", "ã‚");
+ x2("ã†ã†", "ã†ã†", 0, 6);
+ x2("ã‚ã„ã†", "ã‚ã„ã†", 0, 9);
+ x2("ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“", "ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“ã“", 0, 105);
+ x2("ã‚", "ã„ã‚", 3, 6);
+ x2("ã„ã†", "ã‚ã„ã†", 3, 9);
+ x2("\\xca\\xb8", "\xca\xb8", 0, 2);
+ x2(".", "ã‚", 0, 3);
+ x2("..", "ã‹ã", 0, 6);
+ x2("\\w", "ãŠ", 0, 3);
+ n("\\W", "ã‚");
+ x2("[\\W]", "ã†$", 3, 4);
+ x2("\\S", "ã", 0, 3);
+ x2("\\S", "æ¼¢", 0, 3);
+ x2("\\b", "æ°— ", 0, 0);
+ x2("\\b", " ã»", 1, 1);
+ x2("\\B", "ã›ã ", 3, 3);
+ x2("\\B", "ㆠ", 4, 4);
+ x2("\\B", " ã„", 0, 0);
+ x2("[ãŸã¡]", "ã¡", 0, 3);
+ n("[ãªã«]", "ã¬");
+ x2("[ã†-ãŠ]", "ãˆ", 0, 3);
+ n("[^ã‘]", "ã‘");
+ x2("[\\w]", "ã­", 0, 3);
+ n("[\\d]", "ãµ");
+ x2("[\\D]", "ã¯", 0, 3);
+ n("[\\s]", "ã");
+ x2("[\\S]", "ã¸", 0, 3);
+ x2("[\\w\\d]", "よ", 0, 3);
+ x2("[\\w\\d]", " よ", 3, 6);
+ n("\\w鬼車", " 鬼車");
+ x2("鬼\\W車", "鬼 車", 0, 7);
+ x2("ã‚.ã„.ã†", "ã‚ã‚ã„ã„ã†", 0, 15);
+ x2(".\\wã†\\W..ãž", "ãˆã†ã† ã†ãžãž", 0, 19);
+ x2("\\s\\wã“ã“ã“", " ã“ã“ã“ã“", 0, 13);
+ x2("ã‚ã‚.ã‘", "ã‚ã‚ã‘ã‘", 0, 12);
+ n(".ã„", "ã„ãˆ");
+ x2(".ãŠ", "ãŠãŠ", 0, 6);
+ x2("^ã‚", "ã‚", 0, 3);
+ x2("^ã‚€$", "ã‚€", 0, 3);
+ x2("^\\w$", "ã«", 0, 3);
+ x2("^\\wã‹ããã‘ã“$", "zã‹ããã‘ã“", 0, 16);
+ x2("^\\w...ã†ãˆãŠ$", "zã‚ã„ã†ã†ãˆãŠ", 0, 19);
+ x2("\\w\\w\\s\\WãŠãŠãŠ\\d", "a㊠ãŠãŠãŠ4", 0, 16);
+ x2("\\AãŸã¡ã¤", "ãŸã¡ã¤", 0, 9);
+ x2("ã‚€ã‚ã‚‚\\Z", "ã‚€ã‚ã‚‚", 0, 9);
+ x2("ã‹ãã\\z", "ã‹ãã", 0, 9);
+ x2("ã‹ãã\\Z", "ã‹ãã\n", 0, 9);
+ x2("\\Gã½ã´", "ã½ã´", 0, 6);
+ n("\\Gãˆ", "ã†ãˆãŠ");
+ n("ã¨ã¦\\G", "ã¨ã¦");
+ n("ã¾ã¿\\A", "ã¾ã¿");
+ n("ã¾\\Aã¿", "ã¾ã¿");
+ x2("(?=ã›)ã›", "ã›", 0, 3);
+ n("(?=ã†).", "ã„");
+ x2("(?!ã†)ã‹", "ã‹", 0, 3);
+ n("(?!ã¨)ã‚", "ã¨");
+ x2("(?i:ã‚)", "ã‚", 0, 3);
+ x2("(?i:ã¶ã¹)", "ã¶ã¹", 0, 6);
+ n("(?i:ã„)", "ã†");
+ x2("(?m:よ.)", "よ\n", 0, 4);
+ x2("(?m:.ã‚)", "ã¾\nã‚", 3, 7);
+ x2("ã‚?", "", 0, 0);
+ x2("変?", "化", 0, 0);
+ x2("変?", "変", 0, 3);
+ x2("é‡*", "", 0, 0);
+ x2("é‡*", "é‡", 0, 3);
+ x2("å­*", "å­å­å­", 0, 9);
+ x2("馬*", "鹿馬馬馬馬", 0, 0);
+ n("å±±+", "");
+ x2("æ²³+", "æ²³", 0, 3);
+ x2("時+", "時時時時", 0, 12);
+ x2("ãˆ+", "ãˆãˆã†ã†ã†", 0, 6);
+ x2("ã†+", "ãŠã†ã†ã†ã†", 3, 15);
+ x2(".?", "ãŸ", 0, 3);
+ x2(".*", "ã±ã´ã·ãº", 0, 12);
+ x2(".+", "ã‚", 0, 3);
+ x2(".+", "ã„ã†ãˆã‹\n", 0, 12);
+ x2("ã‚|ã„", "ã‚", 0, 3);
+ x2("ã‚|ã„", "ã„", 0, 3);
+ x2("ã‚ã„|ã„ã†", "ã‚ã„", 0, 6);
+ x2("ã‚ã„|ã„ã†", "ã„ã†", 0, 6);
+ x2("ã‚’(?:ã‹ã|ãã)", "ã‚’ã‹ã", 0, 9);
+ x2("ã‚’(?:ã‹ã|ãã)ã‘", "ã‚’ããã‘", 0, 12);
+ x2("ã‚ã„|(?:ã‚ã†|ã‚ã‚’)", "ã‚ã‚’", 0, 6);
+ x2("ã‚|ã„|ã†", "ãˆã†", 3, 6);
+ x2("ã‚|ã„|ã†ãˆ|ãŠã‹ã|ã|ã‘ã“ã•|ã—ã™ã›|ã|ãŸã¡|ã¤ã¦ã¨ãªã«|ã¬ã­", "ã—ã™ã›", 0, 9);
+ n("ã‚|ã„|ã†ãˆ|ãŠã‹ã|ã|ã‘ã“ã•|ã—ã™ã›|ã|ãŸã¡|ã¤ã¦ã¨ãªã«|ã¬ã­", "ã™ã›");
+ x2("ã‚|^ã‚", "ã¶ã‚", 3, 6);
+ x2("ã‚|^ã‚’", "ã‚’ã‚", 0, 3);
+ x2("鬼|\\G車", "ã‘車鬼", 6, 9);
+ x2("鬼|\\G車", "車鬼", 0, 3);
+ x2("鬼|\\A車", "b車鬼", 4, 7);
+ x2("鬼|\\A車", "車", 0, 3);
+ x2("鬼|車\\Z", "車鬼", 3, 6);
+ x2("鬼|車\\Z", "車", 0, 3);
+ x2("鬼|車\\Z", "車\n", 0, 3);
+ x2("鬼|車\\z", "車鬼", 3, 6);
+ x2("鬼|車\\z", "車", 0, 3);
+ x2("\\w|\\s", "ãŠ", 0, 3);
+ x2("\\w|%", "%ãŠ", 0, 1);
+ x2("\\w|[&$]", "ã†&", 0, 3);
+ x2("[ã„-ã‘]", "ã†", 0, 3);
+ x2("[ã„-ã‘]|[^ã‹-ã“]", "ã‚", 0, 3);
+ x2("[ã„-ã‘]|[^ã‹-ã“]", "ã‹", 0, 3);
+ x2("[^ã‚]", "\n", 0, 1);
+ x2("(?:ã‚|[ã†-ã])|ã„ã‚’", "ã†ã‚’", 0, 3);
+ x2("(?:ã‚|[ã†-ã])|ã„ã‚’", "ã„ã‚’", 0, 6);
+ x2("ã‚ã„ã†|(?=ã‘ã‘)..ã»", "ã‘ã‘ã»", 0, 9);
+ x2("ã‚ã„ã†|(?!ã‘ã‘)..ã»", "ã‚ã„ã»", 0, 9);
+ x2("(?=ã‚’ã‚)..ã‚|(?=ã‚’ã‚’)..ã‚", "ã‚’ã‚’ã‚", 0, 9);
+ x2("(?<=ã‚|ã„ã†)ã„", "ã„ã†ã„", 6, 9);
+ n("(?>ã‚|ã‚ã„ãˆ)ã†", "ã‚ã„ãˆã†");
+ x2("(?>ã‚ã„ãˆ|ã‚)ã†", "ã‚ã„ãˆã†", 0, 12);
+ x2("ã‚?|ã„", "ã‚", 0, 3);
+ x2("ã‚?|ã„", "ã„", 0, 0);
+ x2("ã‚?|ã„", "", 0, 0);
+ x2("ã‚*|ã„", "ã‚ã‚", 0, 6);
+ x2("ã‚*|ã„*", "ã„ã‚", 0, 0);
+ x2("ã‚*|ã„*", "ã‚ã„", 0, 3);
+ x2("[aã‚]*|ã„*", "aã‚ã„ã„ã„", 0, 4);
+ x2("ã‚+|ã„*", "", 0, 0);
+ x2("ã‚+|ã„*", "ã„ã„ã„", 0, 9);
+ x2("ã‚+|ã„*", "ã‚ã„ã„ã„", 0, 3);
+ x2("ã‚+|ã„*", "aã‚ã„ã„ã„", 0, 0);
+ n("ã‚+|ã„+", "");
+ x2("(ã‚|ã„)?", "ã„", 0, 3);
+ x2("(ã‚|ã„)*", "ã„ã‚", 0, 6);
+ x2("(ã‚|ã„)+", "ã„ã‚ã„", 0, 9);
+ x2("(ã‚ã„|ã†ã‚)+", "ã†ã‚ã‚ã„ã†ãˆ", 0, 12);
+ x2("(ã‚ã„|ã†ãˆ)+", "ã†ã‚ã‚ã„ã†ãˆ", 6, 18);
+ x2("(ã‚ã„|ã†ã‚)+", "ã‚ã‚ã„ã†ã‚", 3, 15);
+ x2("(ã‚ã„|ã†ã‚)+", "ã‚ã„ã‚’ã†ã‚", 0, 6);
+ x2("(ã‚ã„|ã†ã‚)+", "$$zzzzã‚ã„ã‚’ã†ã‚", 6, 12);
+ x2("(ã‚|ã„ã‚ã„)+", "ã‚ã„ã‚ã„ã‚", 0, 15);
+ x2("(ã‚|ã„ã‚ã„)+", "ã„ã‚", 3, 6);
+ x2("(ã‚|ã„ã‚ã„)+", "ã„ã‚ã‚ã‚ã„ã‚", 3, 12);
+ x2("(?:ã‚|ã„)(?:ã‚|ã„)", "ã‚ã„", 0, 6);
+ x2("(?:ã‚*|ã„*)(?:ã‚*|ã„*)", "ã‚ã‚ã‚ã„ã„ã„", 0, 9);
+ x2("(?:ã‚*|ã„*)(?:ã‚+|ã„+)", "ã‚ã‚ã‚ã„ã„ã„", 0, 18);
+ x2("(?:ã‚+|ã„+){2}", "ã‚ã‚ã‚ã„ã„ã„", 0, 18);
+ x2("(?:ã‚+|ã„+){1,2}", "ã‚ã‚ã‚ã„ã„ã„", 0, 18);
+ x2("(?:ã‚+|\\Aã„*)ã†ã†", "ã†ã†", 0, 6);
+ n("(?:ã‚+|\\Aã„*)ã†ã†", "ã‚ã„ã†ã†");
+ x2("(?:^ã‚+|ã„+)*ã†", "ã‚ã‚ã„ã„ã„ã‚ã„ã†", 18, 24);
+ x2("(?:^ã‚+|ã„+)*ã†", "ã‚ã‚ã„ã„ã„ã„ã†", 0, 21);
+ x2("ã†{0,}", "ã†ã†ã†ã†", 0, 12);
+ x2("ã‚|(?i)c", "C", 0, 1);
+ x2("(?i)c|ã‚", "C", 0, 1);
+ x2("(?i:ã‚)|a", "a", 0, 1);
+ n("(?i:ã‚)|a", "A");
+ x2("[ã‚ã„ã†]?", "ã‚ã„ã†", 0, 3);
+ x2("[ã‚ã„ã†]*", "ã‚ã„ã†", 0, 9);
+ x2("[^ã‚ã„ã†]*", "ã‚ã„ã†", 0, 0);
+ n("[^ã‚ã„ã†]+", "ã‚ã„ã†");
+ x2("ã‚?\?", "ã‚ã‚ã‚", 0, 0);
+ x2("ã„ã‚?\?ã„", "ã„ã‚ã„", 0, 9);
+ x2("ã‚*?", "ã‚ã‚ã‚", 0, 0);
+ x2("ã„ã‚*?", "ã„ã‚ã‚", 0, 3);
+ x2("ã„ã‚*?ã„", "ã„ã‚ã‚ã„", 0, 12);
+ x2("ã‚+?", "ã‚ã‚ã‚", 0, 3);
+ x2("ã„ã‚+?", "ã„ã‚ã‚", 0, 6);
+ x2("ã„ã‚+?ã„", "ã„ã‚ã‚ã„", 0, 12);
+ x2("(?:天?)?\?", "天", 0, 0);
+ x2("(?:天?\?)?", "天", 0, 0);
+ x2("(?:夢?)+?", "夢夢夢", 0, 3);
+ x2("(?:風+)?\?", "風風風", 0, 0);
+ x2("(?:雪+)?\?霜", "雪雪雪霜", 0, 12);
+ x2("(?:ã‚ã„)?{2}", "", 0, 0);
+ x2("(?:鬼車)?{2}", "鬼車鬼車鬼", 0, 12);
+ x2("(?:鬼車)*{0}", "鬼車鬼車鬼", 0, 0);
+ x2("(?:鬼車){3,}", "鬼車鬼車鬼車鬼車", 0, 24);
+ n("(?:鬼車){3,}", "鬼車鬼車");
+ x2("(?:鬼車){2,4}", "鬼車鬼車鬼車", 0, 18);
+ x2("(?:鬼車){2,4}", "鬼車鬼車鬼車鬼車鬼車", 0, 24);
+ x2("(?:鬼車){2,4}?", "鬼車鬼車鬼車鬼車鬼車", 0, 12);
+ x2("(?:鬼車){,}", "鬼車{,}", 0, 9);
+ x2("(?:ã‹ãã)+?{2}", "ã‹ããã‹ããã‹ãã", 0, 18);
+ x3("(ç«)", "ç«", 0, 3, 1);
+ x3("(ç«æ°´)", "ç«æ°´", 0, 6, 1);
+ x2("((時間))", "時間", 0, 6);
+ x3("((風水))", "風水", 0, 6, 1);
+ x3("((昨日))", "昨日", 0, 6, 2);
+ x3("((((((((((((((((((((é‡å­))))))))))))))))))))", "é‡å­", 0, 6, 20);
+ x3("(ã‚ã„)(ã†ãˆ)", "ã‚ã„ã†ãˆ", 0, 6, 1);
+ x3("(ã‚ã„)(ã†ãˆ)", "ã‚ã„ã†ãˆ", 6, 12, 2);
+ x3("()(ã‚)ã„ã†(ãˆãŠã‹)ããã‘ã“", "ã‚ã„ã†ãˆãŠã‹ããã‘ã“", 9, 18, 3);
+ x3("(()(ã‚)ã„ã†(ãˆãŠã‹)ããã‘ã“)", "ã‚ã„ã†ãˆãŠã‹ããã‘ã“", 9, 18, 4);
+ x3(".*(フォ)ン・マ(ン()シュタ)イン", "フォン・マンシュタイン", 15, 27, 2);
+ x2("(^ã‚)", "ã‚", 0, 3);
+ x3("(ã‚)|(ã‚)", "ã„ã‚", 3, 6, 1);
+ x3("(^ã‚)|(ã‚)", "ã„ã‚", 3, 6, 2);
+ x3("(ã‚?)", "ã‚ã‚ã‚", 0, 3, 1);
+ x3("(ã¾*)", "ã¾ã¾ã¾", 0, 9, 1);
+ x3("(ã¨*)", "", 0, 0, 1);
+ x3("(ã‚‹+)", "ã‚‹ã‚‹ã‚‹ã‚‹ã‚‹ã‚‹ã‚‹", 0, 21, 1);
+ x3("(ãµ+|ã¸*)", "ãµãµãµã¸ã¸", 0, 9, 1);
+ x3("(ã‚+|ã„?)", "ã„ã„ã„ã‚ã‚", 0, 3, 1);
+ x3("(ã‚ã„ã†)?", "ã‚ã„ã†", 0, 9, 1);
+ x3("(ã‚ã„ã†)*", "ã‚ã„ã†", 0, 9, 1);
+ x3("(ã‚ã„ã†)+", "ã‚ã„ã†", 0, 9, 1);
+ x3("(ã•ã—ã™|ã‚ã„ã†)+", "ã‚ã„ã†", 0, 9, 1);
+ x3("([ãªã«ã¬][ã‹ãã]|ã‹ãã)+", "ã‹ãã", 0, 9, 1);
+ x3("((?i:ã‚ã„ã†))", "ã‚ã„ã†", 0, 9, 1);
+ x3("((?m:ã‚.ã†))", "ã‚\nã†", 0, 7, 1);
+ x3("((?=ã‚ã‚“)ã‚)", "ã‚ã‚“ã„", 0, 3, 1);
+ x3("ã‚ã„ã†|(.ã‚ã„ãˆ)", "ã‚“ã‚ã„ãˆ", 0, 12, 1);
+ x3("ã‚*(.)", "ã‚ã‚ã‚ã‚ã‚“", 12, 15, 1);
+ x3("ã‚*?(.)", "ã‚ã‚ã‚ã‚ã‚“", 0, 3, 1);
+ x3("ã‚*?(ã‚“)", "ã‚ã‚ã‚ã‚ã‚“", 12, 15, 1);
+ x3("[ã„ã†ãˆ]ã‚*(.)", "ãˆã‚ã‚ã‚ã‚ã‚“", 15, 18, 1);
+ x3("(\\Aã„ã„)ã†ã†", "ã„ã„ã†ã†", 0, 6, 1);
+ n("(\\Aã„ã„)ã†ã†", "ã‚“ã„ã„ã†ã†");
+ x3("(^ã„ã„)ã†ã†", "ã„ã„ã†ã†", 0, 6, 1);
+ n("(^ã„ã„)ã†ã†", "ã‚“ã„ã„ã†ã†");
+ x3("ã‚ã‚(ã‚‹ã‚‹$)", "ã‚ã‚ã‚‹ã‚‹", 6, 12, 1);
+ n("ã‚ã‚(ã‚‹ã‚‹$)", "ã‚ã‚ã‚‹ã‚‹ã‚‹");
+ x2("(ç„¡)\\1", "ç„¡ç„¡", 0, 6);
+ n("(ç„¡)\\1", "ç„¡æ­¦");
+ x2("(空?)\\1", "空空", 0, 6);
+ x2("(空?\?)\\1", "空空", 0, 0);
+ x2("(空*)\\1", "空空空空空", 0, 12);
+ x3("(空*)\\1", "空空空空空", 0, 6, 1);
+ x2("ã‚(ã„*)\\1", "ã‚ã„ã„ã„ã„", 0, 15);
+ x2("ã‚(ã„*)\\1", "ã‚ã„", 0, 3);
+ x2("(ã‚*)(ã„*)\\1\\2", "ã‚ã‚ã‚ã„ã„ã‚ã‚ã‚ã„ã„", 0, 30);
+ x2("(ã‚*)(ã„*)\\2", "ã‚ã‚ã‚ã„ã„ã„ã„", 0, 21);
+ x3("(ã‚*)(ã„*)\\2", "ã‚ã‚ã‚ã„ã„ã„ã„", 9, 15, 2);
+ x2("(((((((ã½*)ãº))))))ã´\\7", "ã½ã½ã½ãºã´ã½ã½ã½", 0, 24);
+ x3("(((((((ã½*)ãº))))))ã´\\7", "ã½ã½ã½ãºã´ã½ã½ã½", 0, 9, 7);
+ x2("(ã¯)(ã²)(ãµ)\\2\\1\\3", "ã¯ã²ãµã²ã¯ãµ", 0, 18);
+ x2("([ã-ã‘])\\1", "ãã", 0, 6);
+ x2("(\\w\\d\\s)\\1", "ã‚5 ã‚5 ", 0, 10);
+ n("(\\w\\d\\s)\\1", "ã‚5 ã‚5");
+ x2("(誰?|[ã‚-ã†]{3})\\1", "誰?誰?", 0, 12);
+ x2("...(誰?|[ã‚-ã†]{3})\\1", "ã‚aã‚誰?誰?", 0, 19);
+ x2("(誰?|[ã‚-ã†]{3})\\1", "ã†ã„ã†ã†ã„ã†", 0, 18);
+ x2("(^ã“)\\1", "ã“ã“", 0, 6);
+ n("(^ã‚€)\\1", "ã‚むむ");
+ n("(ã‚$)\\1", "ã‚ã‚");
+ n("(ã‚ã„\\Z)\\1", "ã‚ã„");
+ x2("(ã‚*\\Z)\\1", "ã‚", 3, 3);
+ x2(".(ã‚*\\Z)\\1", "ã„ã‚", 3, 6);
+ x3("(.(ã‚„ã„ゆ)\\2)", "zã‚„ã„ゆやã„ゆ", 0, 19, 1);
+ x3("(.(..\\d.)\\2)", "ã‚12341234", 0, 11, 1);
+ x2("((?i:ã‚vãš))\\1", "ã‚vãšã‚vãš", 0, 14);
+ x2("(?<æ„šã‹>変|\\(\\g<æ„šã‹>\\))", "((((((変))))))", 0, 15);
+ x2("\\A(?:\\g<阿_1>|\\g<云_2>|\\z終了 (?<阿_1>観|自\\g<云_2>自)(?<云_2>在|è©è–©\\g<阿_1>è©è–©))$", "è©è–©è‡ªè©è–©è‡ªåœ¨è‡ªè©è–©è‡ªè©è–©", 0, 39);
+ x2("[[ã²ãµ]]", "ãµ", 0, 3);
+ x2("[[ã„ãŠã†]ã‹]", "ã‹", 0, 3);
+ n("[[^ã‚]]", "ã‚");
+ n("[^[ã‚]]", "ã‚");
+ x2("[^[^ã‚]]", "ã‚", 0, 3);
+ x2("[[ã‹ãã]&&ãã]", "ã", 0, 3);
+ n("[[ã‹ãã]&&ãã]", "ã‹");
+ n("[[ã‹ãã]&&ãã]", "ã‘");
+ x2("[ã‚-ã‚“&&ã„-ã‚’&&ã†-ã‚‘]", "ã‚‘", 0, 3);
+ n("[^ã‚-ã‚“&&ã„-ã‚’&&ã†-ã‚‘]", "ã‚‘");
+ x2("[[^ã‚&&ã‚]&&ã‚-ã‚“]", "ã„", 0, 3);
+ n("[[^ã‚&&ã‚]&&ã‚-ã‚“]", "ã‚");
+ x2("[[^ã‚-ã‚“&&ã„ã†ãˆãŠ]&&[^ã†-ã‹]]", "ã", 0, 3);
+ n("[[^ã‚-ã‚“&&ã„ã†ãˆãŠ]&&[^ã†-ã‹]]", "ã„");
+ x2("[^[^ã‚ã„ã†]&&[^ã†ãˆãŠ]]", "ã†", 0, 3);
+ x2("[^[^ã‚ã„ã†]&&[^ã†ãˆãŠ]]", "ãˆ", 0, 3);
+ n("[^[^ã‚ã„ã†]&&[^ã†ãˆãŠ]]", "ã‹");
+ x2("[ã‚-&&-ã‚]", "-", 0, 1);
+ x2("[^[^a-zã‚ã„ã†]&&[^bcdefgã†ãˆãŠ]q-w]", "ãˆ", 0, 3);
+ x2("[^[^a-zã‚ã„ã†]&&[^bcdefgã†ãˆãŠ]g-w]", "f", 0, 1);
+ x2("[^[^a-zã‚ã„ã†]&&[^bcdefgã†ãˆãŠ]g-w]", "g", 0, 1);
+ n("[^[^a-zã‚ã„ã†]&&[^bcdefgã†ãˆãŠ]g-w]", "2");
+ x2("a<b>ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰<\\/b>", "a<b>ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰</b>", 0, 44);
+ x2(".<b>ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰<\\/b>", "a<b>ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰</b>", 0, 44);
+ x2("\\n?\\z", "ã“ã‚“ã«ã¡ã¯", 15, 15);
+ x2("(?m).*", "é’赤黄", 0, 9);
+ x2("(?m).*a", "é’赤黄a", 0, 10);
+
+ x2("\\p{Hiragana}", "ã´", 0, 3);
+ n("\\P{Hiragana}", "ã´");
+ x2("\\p{Emoji}", "\xE2\xAD\x90", 0, 3);
+ x2("\\p{^Emoji}", "\xEF\xBC\x93", 0, 3);
+ x2("\\p{Extended_Pictographic}", "\xE2\x9A\xA1", 0, 3);
+ n("\\p{Extended_Pictographic}", "\xE3\x81\x82");
+
+ x2("\\p{Word}", "ã“", 0, 3);
+ n("\\p{^Word}", "ã“");
+ x2("[\\p{Word}]", "ã“", 0, 3);
+ n("[\\p{^Word}]", "ã“");
+ n("[^\\p{Word}]", "ã“");
+ x2("[^\\p{^Word}]", "ã“", 0, 3);
+ x2("[^\\p{^Word}&&\\p{ASCII}]", "ã“", 0, 3);
+ x2("[^\\p{^Word}&&\\p{ASCII}]", "a", 0, 1);
+ n("[^\\p{^Word}&&\\p{ASCII}]", "#");
+ x2("[^[\\p{^Word}]&&[\\p{ASCII}]]", "ã“", 0, 3);
+ x2("[^[\\p{ASCII}]&&[^\\p{Word}]]", "ã“", 0, 3);
+ n("[[\\p{ASCII}]&&[^\\p{Word}]]", "ã“");
+ x2("[^[\\p{^Word}]&&[^\\p{ASCII}]]", "ã“", 0, 3);
+ x2("[^\\x{104a}]", "ã“", 0, 3);
+ x2("[^\\p{^Word}&&[^\\x{104a}]]", "ã“", 0, 3);
+ x2("[^[\\p{^Word}]&&[^\\x{104a}]]", "ã“", 0, 3);
+ n("[^\\p{Word}||[^\\x{104a}]]", "ã“");
+
+ x2("\\p{^Cntrl}", "ã“", 0, 3);
+ n("\\p{Cntrl}", "ã“");
+ x2("[\\p{^Cntrl}]", "ã“", 0, 3);
+ n("[\\p{Cntrl}]", "ã“");
+ n("[^\\p{^Cntrl}]", "ã“");
+ x2("[^\\p{Cntrl}]", "ã“", 0, 3);
+ x2("[^\\p{Cntrl}&&\\p{ASCII}]", "ã“", 0, 3);
+ x2("[^\\p{Cntrl}&&\\p{ASCII}]", "a", 0, 1);
+ n("[^\\p{^Cntrl}&&\\p{ASCII}]", "#");
+ x2("[^[\\p{^Cntrl}]&&[\\p{ASCII}]]", "ã“", 0, 3);
+ x2("[^[\\p{ASCII}]&&[^\\p{Cntrl}]]", "ã“", 0, 3);
+ n("[[\\p{ASCII}]&&[^\\p{Cntrl}]]", "ã“");
+ n("[^[\\p{^Cntrl}]&&[^\\p{ASCII}]]", "ã“");
+ n("[^\\p{^Cntrl}&&[^\\x{104a}]]", "ã“");
+ n("[^[\\p{^Cntrl}]&&[^\\x{104a}]]", "ã“");
+ n("[^\\p{Cntrl}||[^\\x{104a}]]", "ã“");
+
+ x2("(?-W:\\p{Word})", "ã“", 0, 3);
+ n("(?W:\\p{Word})", "ã“");
+ x2("(?W:\\p{Word})", "k", 0, 1);
+ x2("(?-W:[[:word:]])", "ã“", 0, 3);
+ n("(?W:[[:word:]])", "ã“");
+ x2("(?-D:\\p{Digit})", "3", 0, 3);
+ n("(?D:\\p{Digit})", "3");
+ x2("(?-S:\\p{Space})", "\xc2\x85", 0, 2);
+ n("(?S:\\p{Space})", "\xc2\x85");
+ x2("(?-P:\\p{Word})", "ã“", 0, 3);
+ n("(?P:\\p{Word})", "ã“");
+ x2("(?-W:\\w)", "ã“", 0, 3);
+ n("(?W:\\w)", "ã“");
+ x2("(?-W:\\w)", "k", 0, 1);
+ x2("(?W:\\w)", "k", 0, 1);
+ n("(?-W:\\W)", "ã“");
+ x2("(?W:\\W)", "ã“", 0, 3);
+ n("(?-W:\\W)", "k");
+ n("(?W:\\W)", "k");
+
+ x2("(?-W:\\b)", "ã“", 0, 0);
+ n("(?W:\\b)", "ã“");
+ x2("(?-W:\\b)", "h", 0, 0);
+ x2("(?W:\\b)", "h", 0, 0);
+ n("(?-W:\\B)", "ã“");
+ x2("(?W:\\B)", "ã“", 0, 0);
+ n("(?-W:\\B)", "h");
+ n("(?W:\\B)", "h");
+ x2("(?-P:\\b)", "ã“", 0, 0);
+ n("(?P:\\b)", "ã“");
+ x2("(?-P:\\b)", "h", 0, 0);
+ x2("(?P:\\b)", "h", 0, 0);
+ n("(?-P:\\B)", "ã“");
+ x2("(?P:\\B)", "ã“", 0, 0);
+ n("(?-P:\\B)", "h");
+ n("(?P:\\B)", "h");
+
+ x2("\\p{InBasicLatin}", "\x41", 0, 1);
+ //x2("\\p{Grapheme_Cluster_Break_Regional_Indicator}", "\xF0\x9F\x87\xA9", 0, 4);
+ //n("\\p{Grapheme_Cluster_Break_Regional_Indicator}", "\xF0\x9F\x87\xA5");
+
+ // extended grapheme cluster
+
+ // CR + LF
+ n(".\\y\\O", "\x0d\x0a");
+ x2(".\\Y\\O", "\x0d\x0a", 0, 2);
+
+ // LATIN SMALL LETTER G, COMBINING DIAERESIS
+ n("^.\\y.$", "\x67\xCC\x88");
+ x2(".\\Y.", "\x67\xCC\x88", 0, 3);
+ x2("\\y.\\Y.\\y", "\x67\xCC\x88", 0, 3);
+ // HANGUL SYLLABLE GAG
+ x2("\\y.\\y", "\xEA\xB0\x81", 0, 3);
+ // HANGUL CHOSEONG KIYEOK, HANGUL JUNGSEONG A, HANGUL JONGSEONG KIYEOK
+ x2("^.\\Y.\\Y.$", "\xE1\x84\x80\xE1\x85\xA1\xE1\x86\xA8", 0, 9);
+ n("^.\\y.\\Y.$", "\xE1\x84\x80\xE1\x85\xA1\xE1\x86\xA8");
+ // TAMIL LETTER NA, TAMIL VOWEL SIGN I,
+ x2(".\\Y.", "\xE0\xAE\xA8\xE0\xAE\xBF", 0, 6);
+ n(".\\y.", "\xE0\xAE\xA8\xE0\xAE\xBF");
+ // THAI CHARACTER KO KAI, THAI CHARACTER SARA AM
+ x2(".\\Y.", "\xE0\xB8\x81\xE0\xB8\xB3", 0, 6);
+ n(".\\y.", "\xE0\xB8\x81\xE0\xB8\xB3");
+ // DEVANAGARI LETTER SSA, DEVANAGARI VOWEL SIGN I
+ x2(".\\Y.", "\xE0\xA4\xB7\xE0\xA4\xBF", 0, 6);
+ n(".\\y.", "\xE0\xA4\xB7\xE0\xA4\xBF");
+
+ // {Extended_Pictographic} Extend* ZWJ x {Extended_Pictographic}
+ x2("..\\Y.", "\xE3\x80\xB0\xE2\x80\x8D\xE2\xAD\x95", 0, 9);
+ x2("...\\Y.", "\xE3\x80\xB0\xCC\x82\xE2\x80\x8D\xE2\xAD\x95", 0, 11);
+ n("...\\Y.", "\xE3\x80\xB0\xCD\xB0\xE2\x80\x8D\xE2\xAD\x95");
+
+ // CR + LF
+ n("^\\X\\X$", "\x0d\x0a");
+ x2("^\\X$", "\x0d\x0a", 0, 2);
+ // LATIN SMALL LETTER G, COMBINING DIAERESIS
+ n("^\\X\\X.$", "\x67\xCC\x88");
+ x2("^\\X$", "\x67\xCC\x88", 0, 3);
+ // HANGUL CHOSEONG KIYEOK, HANGUL JUNGSEONG A, HANGUL JONGSEONG KIYEOK
+ x2("^\\X$", "\xE1\x84\x80\xE1\x85\xA1\xE1\x86\xA8", 0, 9);
+ n("^\\X\\X\\X$", "\xE1\x84\x80\xE1\x85\xA1\xE1\x86\xA8");
+ // TAMIL LETTER NA, TAMIL VOWEL SIGN I,
+ x2("^\\X$", "\xE0\xAE\xA8\xE0\xAE\xBF", 0, 6);
+ n("\\X\\X", "\xE0\xAE\xA8\xE0\xAE\xBF");
+ // THAI CHARACTER KO KAI, THAI CHARACTER SARA AM
+ x2("^\\X$", "\xE0\xB8\x81\xE0\xB8\xB3", 0, 6);
+ n("\\X\\X", "\xE0\xB8\x81\xE0\xB8\xB3");
+ // DEVANAGARI LETTER SSA, DEVANAGARI VOWEL SIGN I
+ x2("^\\X$", "\xE0\xA4\xB7\xE0\xA4\xBF", 0, 6);
+ n("\\X\\X", "\xE0\xA4\xB7\xE0\xA4\xBF");
+
+ n("^\\X.$", "\xE0\xAE\xA8\xE0\xAE\xBF");
+
+ // a + COMBINING GRAVE ACCENT (U+0300)
+ x2("h\\Xllo", "ha\xCC\x80llo", 0, 7);
+
+ // Text Segment: Extended Grapheme Cluster <-> Word Boundary
+ x2("(?y{g})\\yabc\\y", "abc", 0, 3);
+ x2("(?y{g})\\y\\X\\y", "abc", 0, 1);
+ x2("(?y{w})\\yabc\\y", "abc", 0, 3); // WB1, WB2
+ x2("(?y{w})\\X", "\r\n", 0, 2); // WB3
+ x2("(?y{w})\\X", "\x0cz", 0, 1); // WB3a
+ x2("(?y{w})\\X", "q\x0c", 0, 1); // WB3b
+ x2("(?y{w})\\X", "\xE2\x80\x8D\xE2\x9D\x87", 0, 6); // WB3c
+ x2("(?y{w})\\X", "\x20\x20", 0, 2); // WB3d
+ x2("(?y{w})\\X", "a\xE2\x80\x8D", 0, 4); // WB4
+ x2("(?y{w})\\y\\X\\y", "abc", 0, 3); // WB5
+ x2("(?y{w})\\y\\X\\y", "v\xCE\x87w", 0, 4); // WB6, WB7
+ x2("(?y{w})\\y\\X\\y", "\xD7\x93\x27", 0, 3); // WB7a
+ x2("(?y{w})\\y\\X\\y", "\xD7\x93\x22\xD7\x93", 0, 5); // WB7b, WB7c
+ x2("(?y{w})\\X", "14 45", 0, 2); // WB8
+ x2("(?y{w})\\X", "a14", 0, 3); // WB9
+ x2("(?y{w})\\X", "832e", 0, 4); // WB10
+ x2("(?y{w})\\X", "8\xEF\xBC\x8C\xDB\xB0", 0, 6); // WB11, WB12
+ x2("(?y{w})\\y\\X\\y", "ケン", 0, 6); // WB13
+ x2("(?y{w})\\y\\X\\y", "ケン\xE2\x80\xAFタ", 0, 12); // WB13a, WB13b
+ x2("(?y{w})\\y\\X\\y", "\x21\x23", 0, 1); // WB999
+ x2("(?y{w})\\y\\X\\y", "山ア", 0, 3);
+ x2("(?y{w})\\X", "3.14", 0, 4);
+ x2("(?y{w})\\X", "3 14", 0, 1);
+
+ x2("\\x40", "@", 0, 1);
+ x2("\\x1", "\x01", 0, 1);
+ x2("\\x{1}", "\x01", 0, 1);
+ x2("\\x{4E38}", "\xE4\xB8\xB8", 0, 3);
+ x2("\\u4E38", "\xE4\xB8\xB8", 0, 3);
+ x2("\\u0040", "@", 0, 1);
+
+ x2("c.*\\b", "abc", 2, 3);
+ x2("\\b.*abc.*\\b", "abc", 0, 3);
+ x2("((?()0+)+++(((0\\g<0>)0)|())++++((?(1)(0\\g<0>))++++++0*())++++((?(1)(0\\g<1>)+)++++++++++*())++++((?(1)((0)\\g<0>)+)++())+0++*+++(((0\\g<0>))*())++++((?(1)(0\\g<0>)+)++++++++++*|)++++*+++((?(1)((0)\\g<0>)+)+++++++++())++*|)++++((?()0))|", "abcde", 0, 0); // #139
+
+ n("(*FAIL)", "abcdefg");
+ n("abcd(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)(*FAIL)", "abcdefg");
+ x2("(?:[ab]|(*MAX{2}).)*", "abcbaaccaaa", 0, 7);
+ x2("(?:(*COUNT[AB]{X})[ab]|(*COUNT[CD]{X})[cd])*(*CMP{AB,<,CD})",
+ "abababcdab", 5, 8);
+ x2("(?(?{....})123|456)", "123", 0, 3);
+ x2("(?(*FAIL)123|456)", "456", 0, 3);
+
+ x2("\\g'0'++{,0}", "abcdefgh", 0, 0);
+ x2("\\g'0'++{,0}?", "abcdefgh", 0, 0);
+ x2("\\g'0'++{,0}b", "abcdefgh", 1, 2);
+ x2("\\g'0'++{,0}?def", "abcdefgh", 3, 6);
+ x2("a{1,3}?", "aaa", 0, 1);
+ x2("a{3}", "aaa", 0, 3);
+ x2("a{3}?", "aaa", 0, 3);
+ x2("a{3}?", "aa", 0, 0);
+ x2("a{3,3}?", "aaa", 0, 3);
+ n("a{3,3}?", "aa");
+ x2("a{1,3}+", "aaaaaa", 0, 6);
+ x2("a{3}+", "aaaaaa", 0, 6);
+ x2("a{3,3}+", "aaaaaa", 0, 6);
+ n("a{2,3}?", "a");
+ n("a{3,2}a", "aaa");
+ x2("a{3,2}b", "aaab", 0, 4);
+ x2("a{3,2}b", "aaaab", 1, 5);
+ x2("a{3,2}b", "aab", 0, 3);
+ x2("a{3,2}?", "", 0, 0); /* == (?:a{3,2})?*/
+ x2("a{2,3}+a", "aaa", 0, 3); /* == (?:a{2,3})+*/
+ x2("[\\x{0}-\\x{7fffffff}]", "a", 0, 1);
+ x2("[\\x{7f}-\\x{7fffffff}]", "\xe5\xae\xb6", 0, 3);
+ x2("[a[cdef]]", "a", 0, 1);
+ n("[a[xyz]-c]", "b");
+ x2("[a[xyz]-c]", "a", 0, 1);
+ x2("[a[xyz]-c]", "-", 0, 1);
+ x2("[a[xyz]-c]", "c", 0, 1);
+ x2("(a.c|def)(.{4})(?<=\\1)", "abcdabc", 0, 7);
+ x2("(a.c|de)(.{4})(?<=\\1)", "abcdabc", 0, 7);
+ x2("(a.c|def)(.{5})(?<=d\\1e)", "abcdabce", 0, 8);
+ x2("(a.c|.)d(?<=\\k<1>d)", "zzzzzabcdabc", 5, 9);
+ x2("(?<=az*)abc", "azzzzzzzzzzabcdabcabc", 11, 14);
+ x2("(?<=ab|abc|abcd)ef", "abcdef", 4, 6);
+ x2("(?<=ta+|tb+|tc+|td+)zz", "tcccccccccczz", 11, 13);
+ x2("(?<=t.{7}|t.{5}|t.{2}|t.)zz", "tczz", 2, 4);
+ x2("(?<=t.{7}|t.{5}|t.{2})zz", "tczzzz", 3, 5);
+ x2("(?<=t.{7}|t.{5}|t.{3})zz", "tczzazzbzz", 8, 10);
+ n("(?<=t.{7}|t.{5}|t.{3})zz", "tczzazzbczz");
+ x2("(?<=(ab|abc|abcd))ef", "abcdef", 4, 6);
+ x2("(?<=(ta+|tb+|tc+|td+))zz", "tcccccccccczz", 11, 13);
+ x2("(?<=(t.{7}|t.{5}|t.{2}|t.))zz", "tczz", 2, 4);
+ x2("(?<=(t.{7}|t.{5}|t.{2}))zz", "tczzzz", 3, 5);
+ x2("(?<=(t.{7}|t.{5}|t.{3}))zz", "tczzazzbzz", 8, 10);
+ n("(?<=(t.{7}|t.{5}|t.{3}))zz", "tczzazzbczz");
+ x2("(.{1,4})(.{1,4})(?<=\\2\\1)", "abaaba", 0, 6);
+ x2("(.{1,4})(.{1,4})(?<=\\2\\1)", "ababab", 0, 6);
+ n("(.{1,4})(.{1,4})(?<=\\2\\1)", "abcdabce");
+ x2("(.{1,4})(.{1,4})(?<=\\2\\1)", "abcdabceabce", 4, 12);
+ x2("(?<=a)", "a", 1, 1);
+ x2("(?<=a.*\\w)z", "abbbz", 4, 5);
+ n("(?<=a.*\\w)z", "abb z");
+ x2("(?<=a.*\\W)z", "abb z", 4, 5);
+ x2("(?<=a.*\\b)z", "abb z", 4, 5);
+ x2("(?<=(?>abc))", "abc", 3, 3);
+ x2("(?<=a\\Xz)", "abz", 3, 3);
+ n("(?<=^a*)bc", "zabc");
+ n("(?<=a*\\b)b", "abc");
+ x2("(?<=a+.*[efg])z", "abcdfz", 5, 6);
+ x2("(?<=a+.*[efg])z", "abcdfgz", 6, 7);
+ n("(?<=a+.*[efg])z", "bcdfz");
+ x2("(?<=a*.*[efg])z", "bcdfz", 4, 5);
+ n("(?<=a+.*[efg])z", "abcdz");
+ x2("(?<=v|t|a+.*[efg])z", "abcdfz", 5, 6);
+ x2("(?<=v|t|^a+.*[efg])z", "abcdfz", 5, 6);
+ x2("(?<=^(?:v|t|a+.*[efg]))z", "abcdfz", 5, 6);
+ x2("(?<=v|^t|a+.*[efg])z", "uabcdfz", 6, 7);
+ n("^..(?<=(a{,2}))\\1z", "aaaaz"); // !!! look-behind is shortest priority
+ x2("^..(?<=(a{,2}))\\1z", "aaz", 0, 3); // shortest priority
+ e("(?<=(?~|zoo)a.*z)", "abcdefz", ONIGERR_INVALID_LOOK_BEHIND_PATTERN);
+ e("(?<=(?~|)a.*z)", "abcdefz", ONIGERR_INVALID_LOOK_BEHIND_PATTERN);
+ e("(a(?~|boo)z){0}(?<=\\g<1>)", "abcdefz", ONIGERR_INVALID_LOOK_BEHIND_PATTERN);
+ x2("(?<=(?<= )| )", "abcde fg", 6, 6); // #173
+ x2("(?<=D|)(?<=@!nnnnnnnnnIIIIn;{1}D?()|<x@x*xxxD|)(?<=@xxx|xxxxx\\g<1>;{1}x)", "(?<=D|)(?<=@!nnnnnnnnnIIIIn;{1}D?()|<x@x*xxxD|)(?<=@xxx|xxxxx\\g<1>;{1}x)", 55, 55); // #173
+ x2("(?<=;()|)\\g<1>", "", 0, 0); // reduced #173
+ x2("(?<=;()|)\\k<1>", ";", 1, 1);
+ x2("(())\\g<3>{0}(?<=|())", "abc", 0, 0); // #175
+ x2("(?<=()|)\\1{0}", "abc", 0, 0);
+ e("(?<!xxxxxxxxxxxxxxxxxxxxxxx{32774}{65521}xxxxxxxx{65521}xxxxxxxxxxxxxx{32774}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)", "", ONIGERR_INVALID_LOOK_BEHIND_PATTERN); // #177
+ x2("(?<=(?<=abc))def", "abcdef", 3, 6);
+ x2("(?<=ab(?<=.+b)c)def", "abcdef", 3, 6);
+ n("(?<=ab(?<=a+)c)def", "abcdef");
+ n("(?<=abc)(?<!abc)def", "abcdef");
+ n("(?<!ab.)(?<=.bc)def", "abcdef");
+ x2("(?<!ab.)(?<=.bc)def", "abcdefcbcdef", 9, 12);
+ n("(?<!abc)def", "abcdef");
+ n("(?<!xxx|abc)def", "abcdef");
+ n("(?<!xxxxx|abc)def", "abcdef");
+ n("(?<!xxxxx|abc)def", "xxxxxxdef");
+ n("(?<!x+|abc)def", "abcdef");
+ n("(?<!x+|abc)def", "xxxxxxxxxdef");
+ x2("(?<!x+|abc)def", "xxxxxxxxzdef", 9, 12);
+ n("(?<!a.*z|a)def", "axxxxxxxzdef");
+ n("(?<!a.*z|a)def", "bxxxxxxxadef");
+ x2("(?<!a.*z|a)def", "axxxxxxxzdefxxdef", 14, 17);
+ x2("(?<!a.*z|a)def", "bxxxxxxxadefxxdef", 14, 17);
+ x2("(?<!a.*z|a)def", "bxxxxxxxzdef", 9, 12);
+ x2("(?<!x+|y+)\\d+", "xxx572", 4, 6);
+ x2("(?<!3+|4+)\\d+", "33334444", 0, 8);
+ n(".(?<!3+|4+)\\d+", "33334444");
+ n("(.{,3})..(?<!\\1)", "aaaaa");
+ x2("(.{,3})..(?<!\\1)", "abcde", 0, 5);
+ x2("(.{,3})...(?<!\\1)", "abcde", 0, 5);
+ x2("(a.c)(.{3,}?)(?<!\\1)", "abcabcd", 0, 7);
+ x2("(a*)(.{3,}?)(?<!\\1)", "abcabcd", 0, 5);
+ x2("(?:(a.*b)|c.*d)(?<!(?(1))azzzb)", "azzzzb", 0, 6);
+ n("(?:(a.*b)|c.*d)(?<!(?(1))azzzb)", "azzzb");
+ x2("<(?<!NT{+}abcd)", "<(?<!NT{+}abcd)", 0, 1);
+ x2("(?<!a.*c)def", "abbbbdef", 5, 8);
+ n("(?<!a.*c)def", "abbbcdef");
+ x2("(?<!a.*X\\b)def", "abbbbbXdef", 7, 10);
+ n("(?<!a.*X\\B)def", "abbbbbXdef");
+ x2("(?<!a.*[uvw])def", "abbbbbXdef", 7, 10);
+ n("(?<!a.*[uvw])def", "abbbbbwdef");
+ x2("(?<!ab*\\S+)def", "abbbbb def", 9, 12);
+ x2("(?<!a.*\\S)def", "abbbbb def", 7, 10);
+ n("(?<!ab*\\s+)def", "abbbbb def");
+ x2("(?<!ab*\\s+\\B)def", "abbbbb def", 9, 12);
+ n("(?<!v|t|a+.*[efg])z", "abcdfz");
+ x2("(?<!v|t|a+.*[efg])z", "abcdfzavzuz", 10, 11);
+ n("(?<!v|t|^a+.*[efg])z", "abcdfz");
+ n("(?<!^(?:v|t|a+.*[efg]))z", "abcdfz");
+ x2("(?<!v|^t|^a+.*[efg])z", "uabcdfz", 6, 7);
+
+ x2("((?(a)\\g<1>|b))", "aab", 0, 3);
+ x2("((?(a)\\g<1>))", "aab", 0, 2);
+ x2("(b(?(a)|\\g<1>))", "bba", 0, 3);
+ e("(()(?(2)\\g<1>))", "", ONIGERR_NEVER_ENDING_RECURSION);
+ x2("(?(a)(?:b|c))", "ac", 0, 2);
+ n("^(?(a)b|c)", "ac");
+ x2("(?i)a|b", "B", 0, 1);
+ n("((?i)a|b.)|c", "C");
+ n("c(?i)a.|b.", "Caz");
+ x2("c(?i)a|b", "cB", 0, 2); /* == c(?i:a|b) */
+ x2("c(?i)a.|b.", "cBb", 0, 3);
+
+ x2("(?i)st", "st", 0, 2);
+ x2("(?i)st", "St", 0, 2);
+ x2("(?i)st", "sT", 0, 2);
+ x2("(?i)st", "\xC5\xBFt", 0, 3); // U+017F
+ x2("(?i)st", "\xEF\xAC\x85", 0, 3); // U+FB05
+ x2("(?i)st", "\xEF\xAC\x86", 0, 3); // U+FB06
+ x2("(?i)ast", "Ast", 0, 3);
+ x2("(?i)ast", "ASt", 0, 3);
+ x2("(?i)ast", "AsT", 0, 3);
+ x2("(?i)ast", "A\xC5\xBFt", 0, 4); // U+017F
+ x2("(?i)ast", "A\xEF\xAC\x85", 0, 4); // U+FB05
+ x2("(?i)ast", "A\xEF\xAC\x86", 0, 4); // U+FB06
+ x2("(?i)stZ", "stz", 0, 3);
+ x2("(?i)stZ", "Stz", 0, 3);
+ x2("(?i)stZ", "sTz", 0, 3);
+ x2("(?i)stZ", "\xC5\xBFtz", 0, 4); // U+017F
+ x2("(?i)stZ", "\xEF\xAC\x85z", 0, 4); // U+FB05
+ x2("(?i)stZ", "\xEF\xAC\x86z", 0, 4); // U+FB06
+ x2("(?i)BstZ", "bstz", 0, 4);
+ x2("(?i)BstZ", "bStz", 0, 4);
+ x2("(?i)BstZ", "bsTz", 0, 4);
+ x2("(?i)BstZ", "b\xC5\xBFtz", 0, 5); // U+017F
+ x2("(?i)BstZ", "b\xEF\xAC\x85z", 0, 5); // U+FB05
+ x2("(?i)BstZ", "b\xEF\xAC\x86z", 0, 5); // U+FB06
+ x2("(?i).*st\\z", "tttssss\xC5\xBFt", 0, 10); // U+017F
+ x2("(?i).*st\\z", "tttssss\xEF\xAC\x85", 0, 10); // U+FB05
+ x2("(?i).*st\\z", "tttssss\xEF\xAC\x86", 0, 10); // U+FB06
+ x2("(?i).*ã‚stã„\\z", "tttssssã‚\xC5\xBFtã„", 0, 16); // U+017F
+ x2("(?i).*ã‚stã„\\z", "tttssssã‚\xEF\xAC\x85ã„", 0, 16); // U+FB05
+ x2("(?i).*ã‚stã„\\z", "tttssssã‚\xEF\xAC\x86ã„", 0, 16); // U+FB06
+ x2("(?i).*\xC5\xBFt\\z", "tttssssst", 0, 9); // U+017F
+ x2("(?i).*\xEF\xAC\x85\\z", "tttssssã‚st", 0, 12); // U+FB05
+ x2("(?i).*\xEF\xAC\x86ã„\\z", "tttssssstã„", 0, 12); // U+FB06
+ x2("(?i).*\xEF\xAC\x85\\z", "tttssssã‚\xEF\xAC\x85", 0, 13);
+
+ x2("(?i).*ss", "abcdefghijklmnopqrstuvwxyz\xc3\x9f", 0, 28); // U+00DF
+ x2("(?i).*ss.*", "abcdefghijklmnopqrstuvwxyz\xc3\x9fxyz", 0, 31); // U+00DF
+ x2("(?i).*\xc3\x9f", "abcdefghijklmnopqrstuvwxyzss", 0, 28); // U+00DF
+ x2("(?i).*ss.*", "abcdefghijklmnopqrstuvwxyzSSxyz", 0, 31);
+
+ x2("(?i)ssv", "\xc3\x9fv", 0, 3); // U+00DF
+ x2("(?i)(?<=ss)v", "SSv", 2, 3);
+ x2("(?i)(?<=\xc3\x9f)v", "\xc3\x9fv", 2, 3);
+ //x2("(?i)(?<=\xc3\x9f)v", "ssv", 2, 3);
+ //x2("(?i)(?<=ss)v", "\xc3\x9fv", 2, 3);
+
+ /* #156 U+01F0 (UTF-8: C7 B0) */
+ x2("(?i).+IsssÇ°", ".+IsssÇ°", 0, 8);
+ x2(".+IsssÇ°", ".+IsssÇ°", 0, 8);
+ x2("(?i)Ç°", "Ç°", 0, 2);
+ x2("(?i)Ç°", "j\xcc\x8c", 0, 3);
+ x2("(?i)j\xcc\x8c", "Ç°", 0, 2);
+ x2("(?i)5Ç°", "5Ç°", 0, 3);
+ x2("(?i)5Ç°", "5j\xcc\x8c", 0, 4);
+ x2("(?i)5j\xcc\x8c", "5Ç°", 0, 3);
+ x2("(?i)Ç°v", "Ç°V", 0, 3);
+ x2("(?i)Ç°v", "j\xcc\x8cV", 0, 4);
+ x2("(?i)j\xcc\x8cv", "Ç°V", 0, 3);
+ x2("(?i)[Ç°]", "Ç°", 0, 2);
+ x2("(?i)[Ç°]", "j\xcc\x8c", 0, 3);
+ //x2("(?i)[j]\xcc\x8c", "Ç°", 0, 2);
+ x2("(?i)\ufb00a", "ffa", 0, 3);
+ x2("(?i)ffz", "\xef\xac\x80z", 0, 4);
+ x2("(?i)\u2126", "\xcf\x89", 0, 2);
+ x2("a(?i)\u2126", "a\xcf\x89", 0, 3);
+ x2("(?i)A\u2126", "a\xcf\x89", 0, 3);
+ x2("(?i)A\u2126=", "a\xcf\x89=", 0, 4);
+ x2("(?i:ss)=1234567890", "\xc5\xbf\xc5\xbf=1234567890", 0, 15);
+
+ n("a(b|)+d", "abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcd"); /* https://www.haijin-boys.com/discussions/5079 */
+ n(" \xfd", ""); /* https://bugs.php.net/bug.php?id=77370 */
+ /* can't use \xfc00.. because compiler error: hex escape sequence out of range */
+ n("()0\\xfc00000\\xfc00000\\xfc00000\xfc", ""); /* https://bugs.php.net/bug.php?id=77371 */
+ x2("000||0\xfa", "0", 0, 0); /* https://bugs.php.net/bug.php?id=77381 */
+ e("(?i)000000000000000000000\xf0", "", ONIGERR_INVALID_CODE_POINT_VALUE); /* https://bugs.php.net/bug.php?id=77382 */
+ n("0000\\\xf5", "0"); /* https://bugs.php.net/bug.php?id=77385 */
+ n("(?i)FFF00000000000000000\xfd", ""); /* https://bugs.php.net/bug.php?id=77394 */
+ e("x{55380}{77590}", "", ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE);
+ e("(xyz){40000}{99999}(?<name>vv)", "", ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE);
+ e("f{90000,90000}{80000,80000}", "", ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE);
+ n("f{90000,90000}{80000,80001}", "");
+
+ x2("\\p{Common}", "\xe3\x8b\xbf", 0, 3); /* U+32FF */
+ x2("\\p{In_Enclosed_CJK_Letters_and_Months}", "\xe3\x8b\xbf", 0, 3); /* U+32FF */
+
+ e("\\x{7fffffff}", "", ONIGERR_TOO_BIG_WIDE_CHAR_VALUE);
+ e("[\\x{7fffffff}]", "", ONIGERR_INVALID_CODE_POINT_VALUE);
+ e("\\u040", "@", ONIGERR_INVALID_CODE_POINT_VALUE);
+ e("(?<abc>\\g<abc>)", "zzzz", ONIGERR_NEVER_ENDING_RECURSION);
+ e("(*FOO)", "abcdefg", ONIGERR_UNDEFINED_CALLOUT_NAME);
+ e("*", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("|*", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("(?i)*", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("(?:*)", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("(?m:*)", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("(?:)*", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED);
+ e("^*", "abc", ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID);
+
+ fprintf(stdout,
+ "\nRESULT SUCC: %4d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+ onig_region_free(region, 1);
+ onig_end();
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testc.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testc.c
new file mode 100644
index 000000000..5c60764b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testc.c
@@ -0,0 +1,979 @@
+/*
+ * testc.c
+ * Copyright (c) 2019 K.Kosako
+ */
+#include "config.h"
+#include <stdio.h>
+
+#ifdef POSIX_TEST
+#include "onigposix.h"
+#else
+#include "oniguruma.h"
+#endif
+
+#include <string.h>
+
+#define SLEN(s) strlen(s)
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+static FILE* err_file;
+
+#ifndef POSIX_TEST
+static OnigRegion* region;
+#endif
+
+static void xx(char* pattern, char* str, int from, int to, int mem, int not)
+{
+ int r;
+
+#ifdef POSIX_TEST
+ regex_t reg;
+ char buf[200];
+ regmatch_t pmatch[25];
+
+ r = regcomp(&reg, pattern, REG_EXTENDED | REG_NEWLINE);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ r = regexec(&reg, str, reg.re_nsub + 1, pmatch, 0);
+ if (r != 0 && r != REG_NOMATCH) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ if (r == REG_NOMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (pmatch[mem].rm_so == from && pmatch[mem].rm_eo == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, pmatch[mem].rm_so, pmatch[mem].rm_eo);
+ nfail++;
+ }
+ }
+ }
+ regfree(&reg);
+
+#else
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ r = onig_new(&reg, (UChar* )pattern, (UChar* )(pattern + SLEN(pattern)),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_EUC_JP, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ r = onig_search(reg, (UChar* )str, (UChar* )(str + SLEN(str)),
+ (UChar* )str, (UChar* )(str + SLEN(str)),
+ region, ONIG_OPTION_NONE);
+ if (r < ONIG_MISMATCH) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, region->beg[mem], region->end[mem]);
+ nfail++;
+ }
+ }
+ }
+ onig_free(reg);
+#endif
+}
+
+static void x2(char* pattern, char* str, int from, int to)
+{
+ xx(pattern, str, from, to, 0, 0);
+}
+
+static void x3(char* pattern, char* str, int from, int to, int mem)
+{
+ xx(pattern, str, from, to, mem, 0);
+}
+
+static void n(char* pattern, char* str)
+{
+ xx(pattern, str, 0, 0, 0, 1);
+}
+
+extern int main(int argc, char* argv[])
+{
+#ifndef POSIX_TEST
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_EUC_JP;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+#endif
+
+ err_file = stdout;
+
+#ifdef POSIX_TEST
+ reg_set_encoding(REG_POSIX_ENCODING_EUC_JP);
+#else
+ region = onig_region_new();
+#endif
+
+ x2("", "", 0, 0);
+ x2("^", "", 0, 0);
+ x2("$", "", 0, 0);
+ x2("\\G", "", 0, 0);
+ x2("\\A", "", 0, 0);
+ x2("\\Z", "", 0, 0);
+ x2("\\z", "", 0, 0);
+ x2("^$", "", 0, 0);
+ x2("\\ca", "\001", 0, 1);
+ x2("\\C-b", "\002", 0, 1);
+ x2("\\c\\\\", "\034", 0, 1);
+ x2("q[\\c\\\\]", "q\034", 0, 2);
+ x2("", "a", 0, 0);
+ x2("a", "a", 0, 1);
+ x2("\\x61", "a", 0, 1);
+ x2("aa", "aa", 0, 2);
+ x2("aaa", "aaa", 0, 3);
+ x2("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 35);
+ x2("ab", "ab", 0, 2);
+ x2("b", "ab", 1, 2);
+ x2("bc", "abc", 1, 3);
+ x2("(?i:#RET#)", "#INS##RET#", 5, 10);
+ x2("\\17", "\017", 0, 1);
+ x2("\\x1f", "\x1f", 0, 1);
+ x2("a(?#....\\\\JJJJ)b", "ab", 0, 2);
+ x2("(?x) G (o O(?-x)oO) g L", "GoOoOgLe", 0, 7);
+ x2(".", "a", 0, 1);
+ n(".", "");
+ x2("..", "ab", 0, 2);
+ x2("\\w", "e", 0, 1);
+ n("\\W", "e");
+ x2("\\s", " ", 0, 1);
+ x2("\\S", "b", 0, 1);
+ x2("\\d", "4", 0, 1);
+ n("\\D", "4");
+ x2("\\b", "z ", 0, 0);
+ x2("\\b", " z", 1, 1);
+ x2("\\B", "zz ", 1, 1);
+ x2("\\B", "z ", 2, 2);
+ x2("\\B", " z", 0, 0);
+ x2("[ab]", "b", 0, 1);
+ n("[ab]", "c");
+ x2("[a-z]", "t", 0, 1);
+ n("[^a]", "a");
+ x2("[^a]", "\n", 0, 1);
+ x2("[]]", "]", 0, 1);
+ n("[^]]", "]");
+ x2("[\\^]+", "0^^1", 1, 3);
+ x2("[b-]", "b", 0, 1);
+ x2("[b-]", "-", 0, 1);
+ x2("[\\w]", "z", 0, 1);
+ n("[\\w]", " ");
+ x2("[\\W]", "b$", 1, 2);
+ x2("[\\d]", "5", 0, 1);
+ n("[\\d]", "e");
+ x2("[\\D]", "t", 0, 1);
+ n("[\\D]", "3");
+ x2("[\\s]", " ", 0, 1);
+ n("[\\s]", "a");
+ x2("[\\S]", "b", 0, 1);
+ n("[\\S]", " ");
+ x2("[\\w\\d]", "2", 0, 1);
+ n("[\\w\\d]", " ");
+ x2("[[:upper:]]", "B", 0, 1);
+ x2("[*[:xdigit:]+]", "+", 0, 1);
+ x2("[*[:xdigit:]+]", "GHIKK-9+*", 6, 7);
+ x2("[*[:xdigit:]+]", "-@^+", 3, 4);
+ n("[[:upper]]", "A");
+ x2("[[:upper]]", ":", 0, 1);
+ x2("[\\044-\\047]", "\046", 0, 1);
+ x2("[\\x5a-\\x5c]", "\x5b", 0, 1);
+ x2("[\\x6A-\\x6D]", "\x6c", 0, 1);
+ n("[\\x6A-\\x6D]", "\x6E");
+ n("^[0-9A-F]+ 0+ UNDEF ", "75F 00000000 SECT14A notype () External | _rb_apply");
+ x2("[\\[]", "[", 0, 1);
+ x2("[\\]]", "]", 0, 1);
+ x2("[&]", "&", 0, 1);
+ x2("[[ab]]", "b", 0, 1);
+ x2("[[ab]c]", "c", 0, 1);
+ n("[[^a]]", "a");
+ n("[^[a]]", "a");
+ x2("[[ab]&&bc]", "b", 0, 1);
+ n("[[ab]&&bc]", "a");
+ n("[[ab]&&bc]", "c");
+ x2("[a-z&&b-y&&c-x]", "w", 0, 1);
+ n("[^a-z&&b-y&&c-x]", "w");
+ x2("[[^a&&a]&&a-z]", "b", 0, 1);
+ n("[[^a&&a]&&a-z]", "a");
+ x2("[[^a-z&&bcdef]&&[^c-g]]", "h", 0, 1);
+ n("[[^a-z&&bcdef]&&[^c-g]]", "c");
+ x2("[^[^abc]&&[^cde]]", "c", 0, 1);
+ x2("[^[^abc]&&[^cde]]", "e", 0, 1);
+ n("[^[^abc]&&[^cde]]", "f");
+ x2("[a-&&-a]", "-", 0, 1);
+ n("[a\\-&&\\-a]", "&");
+ n("\\wabc", " abc");
+ x2("a\\Wbc", "a bc", 0, 4);
+ x2("a.b.c", "aabbc", 0, 5);
+ x2(".\\wb\\W..c", "abb bcc", 0, 7);
+ x2("\\s\\wzzz", " zzzz", 0, 5);
+ x2("aa.b", "aabb", 0, 4);
+ n(".a", "ab");
+ x2(".a", "aa", 0, 2);
+ x2("^a", "a", 0, 1);
+ x2("^a$", "a", 0, 1);
+ x2("^\\w$", "a", 0, 1);
+ n("^\\w$", " ");
+ x2("^\\wab$", "zab", 0, 3);
+ x2("^\\wabcdef$", "zabcdef", 0, 7);
+ x2("^\\w...def$", "zabcdef", 0, 7);
+ x2("\\w\\w\\s\\Waaa\\d", "aa aaa4", 0, 8);
+ x2("\\A\\Z", "", 0, 0);
+ x2("\\Axyz", "xyz", 0, 3);
+ x2("xyz\\Z", "xyz", 0, 3);
+ x2("xyz\\z", "xyz", 0, 3);
+ x2("a\\Z", "a", 0, 1);
+ x2("\\Gaz", "az", 0, 2);
+ n("\\Gz", "bza");
+ n("az\\G", "az");
+ n("az\\A", "az");
+ n("a\\Az", "az");
+ x2("\\^\\$", "^$", 0, 2);
+ x2("^x?y", "xy", 0, 2);
+ x2("^(x?y)", "xy", 0, 2);
+ x2("\\w", "_", 0, 1);
+ n("\\W", "_");
+ x2("(?=z)z", "z", 0, 1);
+ n("(?=z).", "a");
+ x2("(?!z)a", "a", 0, 1);
+ n("(?!z)a", "z");
+ x2("(?i:a)", "a", 0, 1);
+ x2("(?i:a)", "A", 0, 1);
+ x2("(?i:A)", "a", 0, 1);
+ n("(?i:A)", "b");
+ x2("(?i:[A-Z])", "a", 0, 1);
+ x2("(?i:[f-m])", "H", 0, 1);
+ x2("(?i:[f-m])", "h", 0, 1);
+ n("(?i:[f-m])", "e");
+ x2("(?i:[A-c])", "D", 0, 1);
+ n("(?i:[^a-z])", "A");
+ n("(?i:[^a-z])", "a");
+ x2("(?i:[!-k])", "Z", 0, 1);
+ x2("(?i:[!-k])", "7", 0, 1);
+ x2("(?i:[T-}])", "b", 0, 1);
+ x2("(?i:[T-}])", "{", 0, 1);
+ x2("(?i:\\?a)", "?A", 0, 2);
+ x2("(?i:\\*A)", "*a", 0, 2);
+ n(".", "\n");
+ x2("(?m:.)", "\n", 0, 1);
+ x2("(?m:a.)", "a\n", 0, 2);
+ x2("(?m:.b)", "a\nb", 1, 3);
+ x2(".*abc", "dddabdd\nddabc", 8, 13);
+ x2("(?m:.*abc)", "dddabddabc", 0, 10);
+ n("(?i)(?-i)a", "A");
+ n("(?i)(?-i:a)", "A");
+ x2("a?", "", 0, 0);
+ x2("a?", "b", 0, 0);
+ x2("a?", "a", 0, 1);
+ x2("a*", "", 0, 0);
+ x2("a*", "a", 0, 1);
+ x2("a*", "aaa", 0, 3);
+ x2("a*", "baaaa", 0, 0);
+ n("a+", "");
+ x2("a+", "a", 0, 1);
+ x2("a+", "aaaa", 0, 4);
+ x2("a+", "aabbb", 0, 2);
+ x2("a+", "baaaa", 1, 5);
+ x2(".?", "", 0, 0);
+ x2(".?", "f", 0, 1);
+ x2(".?", "\n", 0, 0);
+ x2(".*", "", 0, 0);
+ x2(".*", "abcde", 0, 5);
+ x2(".+", "z", 0, 1);
+ x2(".+", "zdswer\n", 0, 6);
+ x2("(.*)a\\1f", "babfbac", 0, 4);
+ x2("(.*)a\\1f", "bacbabf", 3, 7);
+ x2("((.*)a\\2f)", "bacbabf", 3, 7);
+ x2("(.*)a\\1f", "baczzzzzz\nbazz\nzzzzbabf", 19, 23);
+ x2("a|b", "a", 0, 1);
+ x2("a|b", "b", 0, 1);
+ x2("|a", "a", 0, 0);
+ x2("(|a)", "a", 0, 0);
+ x2("ab|bc", "ab", 0, 2);
+ x2("ab|bc", "bc", 0, 2);
+ x2("z(?:ab|bc)", "zbc", 0, 3);
+ x2("a(?:ab|bc)c", "aabc", 0, 4);
+ x2("ab|(?:ac|az)", "az", 0, 2);
+ x2("a|b|c", "dc", 1, 2);
+ x2("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "pqr", 0, 2);
+ n("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "mn");
+ x2("a|^z", "ba", 1, 2);
+ x2("a|^z", "za", 0, 1);
+ x2("a|\\Gz", "bza", 2, 3);
+ x2("a|\\Gz", "za", 0, 1);
+ x2("a|\\Az", "bza", 2, 3);
+ x2("a|\\Az", "za", 0, 1);
+ x2("a|b\\Z", "ba", 1, 2);
+ x2("a|b\\Z", "b", 0, 1);
+ x2("a|b\\z", "ba", 1, 2);
+ x2("a|b\\z", "b", 0, 1);
+ x2("\\w|\\s", " ", 0, 1);
+ n("\\w|\\w", " ");
+ x2("\\w|%", "%", 0, 1);
+ x2("\\w|[&$]", "&", 0, 1);
+ x2("[b-d]|[^e-z]", "a", 0, 1);
+ x2("(?:a|[c-f])|bz", "dz", 0, 1);
+ x2("(?:a|[c-f])|bz", "bz", 0, 2);
+ x2("abc|(?=zz)..f", "zzf", 0, 3);
+ x2("abc|(?!zz)..f", "abf", 0, 3);
+ x2("(?=za)..a|(?=zz)..a", "zza", 0, 3);
+ n("(?>a|abd)c", "abdc");
+ x2("(?>abd|a)c", "abdc", 0, 4);
+ x2("a?|b", "a", 0, 1);
+ x2("a?|b", "b", 0, 0);
+ x2("a?|b", "", 0, 0);
+ x2("a*|b", "aa", 0, 2);
+ x2("a*|b*", "ba", 0, 0);
+ x2("a*|b*", "ab", 0, 1);
+ x2("a+|b*", "", 0, 0);
+ x2("a+|b*", "bbb", 0, 3);
+ x2("a+|b*", "abbb", 0, 1);
+ n("a+|b+", "");
+ x2("(a|b)?", "b", 0, 1);
+ x2("(a|b)*", "ba", 0, 2);
+ x2("(a|b)+", "bab", 0, 3);
+ x2("(ab|ca)+", "caabbc", 0, 4);
+ x2("(ab|ca)+", "aabca", 1, 5);
+ x2("(ab|ca)+", "abzca", 0, 2);
+ x2("(a|bab)+", "ababa", 0, 5);
+ x2("(a|bab)+", "ba", 1, 2);
+ x2("(a|bab)+", "baaaba", 1, 4);
+ x2("(?:a|b)(?:a|b)", "ab", 0, 2);
+ x2("(?:a*|b*)(?:a*|b*)", "aaabbb", 0, 3);
+ x2("(?:a*|b*)(?:a+|b+)", "aaabbb", 0, 6);
+ x2("(?:a+|b+){2}", "aaabbb", 0, 6);
+ x2("h{0,}", "hhhh", 0, 4);
+ x2("(?:a+|b+){1,2}", "aaabbb", 0, 6);
+ n("ax{2}*a", "0axxxa1");
+ n("a.{0,2}a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXXa0");
+ x2("^a{2,}?a$", "aaa", 0, 3);
+ x2("^[a-z]{2,}?$", "aaa", 0, 3);
+ x2("(?:a+|\\Ab*)cc", "cc", 0, 2);
+ n("(?:a+|\\Ab*)cc", "abcc");
+ x2("(?:^a+|b+)*c", "aabbbabc", 6, 8);
+ x2("(?:^a+|b+)*c", "aabbbbc", 0, 7);
+ x2("a|(?i)c", "C", 0, 1);
+ x2("(?i)c|a", "C", 0, 1);
+ x2("(?i)c|a", "A", 0, 1);
+ x2("(?i:c)|a", "C", 0, 1);
+ n("(?i:c)|a", "A");
+ x2("[abc]?", "abc", 0, 1);
+ x2("[abc]*", "abc", 0, 3);
+ x2("[^abc]*", "abc", 0, 0);
+ n("[^abc]+", "abc");
+ x2("a?\?", "aaa", 0, 0);
+ x2("ba?\?b", "bab", 0, 3);
+ x2("a*?", "aaa", 0, 0);
+ x2("ba*?", "baa", 0, 1);
+ x2("ba*?b", "baab", 0, 4);
+ x2("a+?", "aaa", 0, 1);
+ x2("ba+?", "baa", 0, 2);
+ x2("ba+?b", "baab", 0, 4);
+ x2("(?:a?)?\?", "a", 0, 0);
+ x2("(?:a?\?)?", "a", 0, 0);
+ x2("(?:a?)+?", "aaa", 0, 1);
+ x2("(?:a+)?\?", "aaa", 0, 0);
+ x2("(?:a+)?\?b", "aaab", 0, 4);
+ x2("(?:ab)?{2}", "", 0, 0);
+ x2("(?:ab)?{2}", "ababa", 0, 4);
+ x2("(?:ab)*{0}", "ababa", 0, 0);
+ x2("(?:ab){3,}", "abababab", 0, 8);
+ n("(?:ab){3,}", "abab");
+ x2("(?:ab){2,4}", "ababab", 0, 6);
+ x2("(?:ab){2,4}", "ababababab", 0, 8);
+ x2("(?:ab){2,4}?", "ababababab", 0, 4);
+ x2("(?:ab){,}", "ab{,}", 0, 5);
+ x2("(?:abc)+?{2}", "abcabcabc", 0, 6);
+ x2("(?:X*)(?i:xa)", "XXXa", 0, 4);
+ x2("(d+)([^abc]z)", "dddz", 0, 4);
+ x2("([^abc]*)([^abc]z)", "dddz", 0, 4);
+ x2("(\\w+)(\\wz)", "dddz", 0, 4);
+ x3("(a)", "a", 0, 1, 1);
+ x3("(ab)", "ab", 0, 2, 1);
+ x2("((ab))", "ab", 0, 2);
+ x3("((ab))", "ab", 0, 2, 1);
+ x3("((ab))", "ab", 0, 2, 2);
+ x3("((((((((((((((((((((ab))))))))))))))))))))", "ab", 0, 2, 20);
+ x3("(ab)(cd)", "abcd", 0, 2, 1);
+ x3("(ab)(cd)", "abcd", 2, 4, 2);
+ x3("()(a)bc(def)ghijk", "abcdefghijk", 3, 6, 3);
+ x3("(()(a)bc(def)ghijk)", "abcdefghijk", 3, 6, 4);
+ x2("(^a)", "a", 0, 1);
+ x3("(a)|(a)", "ba", 1, 2, 1);
+ x3("(^a)|(a)", "ba", 1, 2, 2);
+ x3("(a?)", "aaa", 0, 1, 1);
+ x3("(a*)", "aaa", 0, 3, 1);
+ x3("(a*)", "", 0, 0, 1);
+ x3("(a+)", "aaaaaaa", 0, 7, 1);
+ x3("(a+|b*)", "bbbaa", 0, 3, 1);
+ x3("(a+|b?)", "bbbaa", 0, 1, 1);
+ x3("(abc)?", "abc", 0, 3, 1);
+ x3("(abc)*", "abc", 0, 3, 1);
+ x3("(abc)+", "abc", 0, 3, 1);
+ x3("(xyz|abc)+", "abc", 0, 3, 1);
+ x3("([xyz][abc]|abc)+", "abc", 0, 3, 1);
+ x3("((?i:abc))", "AbC", 0, 3, 1);
+ x2("(abc)(?i:\\1)", "abcABC", 0, 6);
+ x3("((?m:a.c))", "a\nc", 0, 3, 1);
+ x3("((?=az)a)", "azb", 0, 1, 1);
+ x3("abc|(.abd)", "zabd", 0, 4, 1);
+ x2("(?:abc)|(ABC)", "abc", 0, 3);
+ x3("(?i:(abc))|(zzz)", "ABC", 0, 3, 1);
+ x3("a*(.)", "aaaaz", 4, 5, 1);
+ x3("a*?(.)", "aaaaz", 0, 1, 1);
+ x3("a*?(c)", "aaaac", 4, 5, 1);
+ x3("[bcd]a*(.)", "caaaaz", 5, 6, 1);
+ x3("(\\Abb)cc", "bbcc", 0, 2, 1);
+ n("(\\Abb)cc", "zbbcc");
+ x3("(^bb)cc", "bbcc", 0, 2, 1);
+ n("(^bb)cc", "zbbcc");
+ x3("cc(bb$)", "ccbb", 2, 4, 1);
+ n("cc(bb$)", "ccbbb");
+ n("(\\1)", "");
+ n("\\1(a)", "aa");
+ n("(a(b)\\1)\\2+", "ababb");
+ n("(?:(?:\\1|z)(a))+$", "zaa");
+ x2("(?:(?:\\1|z)(a))+$", "zaaa", 0, 4);
+ x2("(a)(?=\\1)", "aa", 0, 1);
+ n("(a)$|\\1", "az");
+ x2("(a)\\1", "aa", 0, 2);
+ n("(a)\\1", "ab");
+ x2("(a?)\\1", "aa", 0, 2);
+ x2("(a?\?)\\1", "aa", 0, 0);
+ x2("(a*)\\1", "aaaaa", 0, 4);
+ x3("(a*)\\1", "aaaaa", 0, 2, 1);
+ x2("a(b*)\\1", "abbbb", 0, 5);
+ x2("a(b*)\\1", "ab", 0, 1);
+ x2("(a*)(b*)\\1\\2", "aaabbaaabb", 0, 10);
+ x2("(a*)(b*)\\2", "aaabbbb", 0, 7);
+ x2("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 8);
+ x3("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 3, 7);
+ x2("(a)(b)(c)\\2\\1\\3", "abcbac", 0, 6);
+ x2("([a-d])\\1", "cc", 0, 2);
+ x2("(\\w\\d\\s)\\1", "f5 f5 ", 0, 6);
+ n("(\\w\\d\\s)\\1", "f5 f5");
+ x2("(who|[a-c]{3})\\1", "whowho", 0, 6);
+ x2("...(who|[a-c]{3})\\1", "abcwhowho", 0, 9);
+ x2("(who|[a-c]{3})\\1", "cbccbc", 0, 6);
+ x2("(^a)\\1", "aa", 0, 2);
+ n("(^a)\\1", "baa");
+ n("(a$)\\1", "aa");
+ n("(ab\\Z)\\1", "ab");
+ x2("(a*\\Z)\\1", "a", 1, 1);
+ x2(".(a*\\Z)\\1", "ba", 1, 2);
+ x3("(.(abc)\\2)", "zabcabc", 0, 7, 1);
+ x3("(.(..\\d.)\\2)", "z12341234", 0, 9, 1);
+ x2("((?i:az))\\1", "AzAz", 0, 4);
+ n("((?i:az))\\1", "Azaz");
+ x2("(?<=a)b", "ab", 1, 2);
+ n("(?<=a)b", "bb");
+ x2("(?<=a|b)b", "bb", 1, 2);
+ x2("(?<=a|bc)b", "bcb", 2, 3);
+ x2("(?<=a|bc)b", "ab", 1, 2);
+ x2("(?<=a|bc||defghij|klmnopq|r)z", "rz", 1, 2);
+ x2("(a)\\g<1>", "aa", 0, 2);
+ x2("(?<!a)b", "cb", 1, 2);
+ n("(?<!a)b", "ab");
+ x2("(?<!a|bc)b", "bbb", 0, 1);
+ n("(?<!a|bc)z", "bcz");
+ x2("(?<name1>a)", "a", 0, 1);
+ x2("(?<name_2>ab)\\g<name_2>", "abab", 0, 4);
+ x2("(?<name_3>.zv.)\\k<name_3>", "azvbazvb", 0, 8);
+ x2("(?<=\\g<ab>)|-\\zEND (?<ab>XyZ)", "XyZ", 3, 3);
+ x2("(?<n>|a\\g<n>)+", "", 0, 0);
+ x2("(?<n>|\\(\\g<n>\\))+$", "()(())", 0, 6);
+ x3("\\g<n>(?<n>.){0}", "X", 0, 1, 1);
+ x2("\\g<n>(abc|df(?<n>.YZ){2,8}){0}", "XYZ", 0, 3);
+ x2("\\A(?<n>(a\\g<n>)|)\\z", "aaaa", 0, 4);
+ x2("(?<n>|\\g<m>\\g<n>)\\z|\\zEND (?<m>a|(b)\\g<m>)", "bbbbabba", 0, 8);
+ x2("(?<name1240>\\w+\\sx)a+\\k<name1240>", " fg xaaaaaaaafg x", 2, 18);
+ x3("(z)()()(?<_9>a)\\g<_9>", "zaa", 2, 3, 1);
+ x2("(.)(((?<_>a)))\\k<_>", "zaa", 0, 3);
+ x2("((?<name1>\\d)|(?<name2>\\w))(\\k<name1>|\\k<name2>)", "ff", 0, 2);
+ x2("(?:(?<x>)|(?<x>efg))\\k<x>", "", 0, 0);
+ x2("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefgefg", 3, 9);
+ n("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefg");
+ x2("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "a-pyumpyum", 2, 10);
+ x3("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "xxxxabcdefghijklmnabcdefghijklmn", 4, 18, 14);
+ x3("(?<name1>)(?<name2>)(?<name3>)(?<name4>)(?<name5>)(?<name6>)(?<name7>)(?<name8>)(?<name9>)(?<name10>)(?<name11>)(?<name12>)(?<name13>)(?<name14>)(?<name15>)(?<name16>aaa)(?<name17>)$", "aaa", 0, 3, 16);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "a", 0, 1);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "((((((a))))))", 0, 13);
+ x3("(?<foo>a|\\(\\g<foo>\\))", "((((((((a))))))))", 0, 17, 1);
+ x2("\\g<bar>|\\zEND(?<bar>.*abc$)", "abcxxxabc", 0, 9);
+ x2("\\g<1>|\\zEND(.a.)", "bac", 0, 3);
+ x3("\\g<_A>\\g<_A>|\\zEND(.a.)(?<_A>.b.)", "xbxyby", 3, 6, 1);
+ x2("\\A(?:\\g<pon>|\\g<pan>|\\zEND (?<pan>a|c\\g<pon>c)(?<pon>b|d\\g<pan>d))$", "cdcbcdc", 0, 7);
+ x2("\\A(?<n>|a\\g<m>)\\z|\\zEND (?<m>\\g<n>)", "aaaa", 0, 4);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaaca", 1, 5);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaacaaaaa", 0, 10);
+ x2("(?<pare>\\(([^\\(\\)]++|\\g<pare>)*+\\))", "((a))", 0, 5);
+ x2("()*\\1", "", 0, 0);
+ x2("(?:()|())*\\1\\2", "", 0, 0);
+ x3("(?:\\1a|())*", "a", 0, 0, 1);
+ x2("x((.)*)*x", "0x1x2x3", 1, 6);
+ x2("x((.)*)*x(?i:\\1)\\Z", "0x1x2x1X2", 1, 9);
+ x2("(?:()|()|()|()|()|())*\\2\\5", "", 0, 0);
+ x2("(?:()|()|()|(x)|()|())*\\2b\\5", "b", 0, 1);
+ x2("\\xED\\xF2", "\xed\xf2", 0, 2);
+ x2("[0-9-a]", "-", 0, 1); // PR#44
+ n("[0-9-a]", ":"); // PR#44
+ x3("(\\(((?:[^(]|\\g<1>)*)\\))", "(abc)(abc)", 1, 4, 2); // PR#43
+ x2("\\o{101}", "A", 0, 1);
+ x2("(?:\\k'+1'B|(A)C)*", "ACAB", 0, 4); // relative backref by postitive number
+ x2("\\g<+2>(abc)(ABC){0}", "ABCabc", 0, 6); // relative call by positive number
+ x2("A\\g'0'|B()", "AAAAB", 0, 5);
+ x3("(A\\g'0')|B", "AAAAB", 0, 5, 1);
+ x2("(a*)(?(1))aa", "aaaaa", 0, 5);
+ x2("(a*)(?(-1))aa", "aaaaa", 0, 5);
+ x2("(?<name>aaa)(?('name'))aa", "aaaaa", 0, 5);
+ x2("(a)(?(1)aa|bb)a", "aaaaa", 0, 4);
+ x2("(?:aa|())(?(<1>)aa|bb)a", "aabba", 0, 5);
+ x2("(?:aa|())(?('1')aa|bb|cc)a", "aacca", 0, 5);
+ x3("(a*)(?(1)aa|a)b", "aaab", 0, 1, 1);
+ n("(a)(?(1)a|b)c", "abc");
+ x2("(a)(?(1)|)c", "ac", 0, 2);
+ n("(?()aaa|bbb)", "bbb");
+ x2("(a)(?(1+0)b|c)d", "abd", 0, 3);
+ x2("(?:(?'name'a)|(?'name'b))(?('name')c|d)e", "ace", 0, 3);
+ x2("(?:(?'name'a)|(?'name'b))(?('name')c|d)e", "bce", 0, 3);
+ x2("\\R", "\r\n", 0, 2);
+ x2("\\R", "\r", 0, 1);
+ x2("\\R", "\n", 0, 1);
+ x2("\\R", "\x0b", 0, 1);
+ n("\\R\\n", "\r\n");
+ n("\\R", "\xc2\x85"); // because euc-jp is not Unicode
+ x2("\\N", "a", 0, 1);
+ n("\\N", "\n");
+ n("(?m:\\N)", "\n");
+ n("(?-m:\\N)", "\n");
+ x2("\\O", "a", 0, 1);
+ x2("\\O", "\n", 0, 1);
+ x2("(?m:\\O)", "\n", 0, 1);
+ x2("(?-m:\\O)", "\n", 0, 1);
+ x2("\\K", "a", 0, 0);
+ x2("a\\K", "a", 1, 1);
+ x2("a\\Kb", "ab", 1, 2);
+ x2("(a\\Kb|ac\\Kd)", "acd", 2, 3);
+ x2("(a\\Kb|\\Kac\\K)*", "acababacab", 9, 10);
+
+ x2("(?~)", "", 0, 0);
+ x2("(?~)", "A", 0, 0);
+ x2("aaaaa(?~)", "aaaaaaaaaa", 0, 5);
+ x2("(?~(?:|aaa))", "aaa", 0, 0);
+ x2("(?~aaa|)", "aaa", 0, 0);
+ x2("a(?~(?~)).", "abcdefghijklmnopqrstuvwxyz", 0, 26); // !!!
+ x2("/\\*(?~\\*/)\\*/", "/* */ */", 0, 5);
+ x2("(?~\\w+)zzzzz", "zzzzz", 0, 5);
+ x2("(?~\\w*)zzzzz", "zzzzz", 0, 5);
+ x2("(?~A.C|B)", "ABC", 0, 0);
+ x2("(?~XYZ|ABC)a", "ABCa", 1, 4);
+ x2("(?~XYZ|ABC)a", "aABCa", 0, 1);
+ x2("<[^>]*>(?~[<>])</[^>]*>", "<a>vvv</a> <b> </b>", 0, 10);
+ x2("(?~ab)", "ccc\ndab", 0, 5);
+ x2("(?m:(?~ab))", "ccc\ndab", 0, 5);
+ x2("(?-m:(?~ab))", "ccc\ndab", 0, 5);
+ x2("(?~abc)xyz", "xyz012345678901234567890123456789abc", 0, 3);
+
+ // absent with expr
+ x2("(?~|78|\\d*)", "123456789", 0, 6);
+ x2("(?~|def|(?:abc|de|f){0,100})", "abcdedeabcfdefabc", 0, 11);
+ x2("(?~|ab|.*)", "ccc\nddd", 0, 3);
+ x2("(?~|ab|\\O*)", "ccc\ndab", 0, 5);
+ x2("(?~|ab|\\O{2,10})", "ccc\ndab", 0, 5);
+ x2("(?~|ab|\\O{1,10})", "ab", 1, 2);
+ n("(?~|ab|\\O{2,10})", "ab");
+ x2("(?~|abc|\\O{1,10})", "abc", 1, 3);
+ x2("(?~|ab|\\O{5,10})|abc", "abc", 0, 3);
+ x2("(?~|ab|\\O{1,10})", "cccccccccccab", 0, 10);
+ x2("(?~|aaa|)", "aaa", 0, 0);
+ x2("(?~||a*)", "aaaaaa", 0, 0);
+ x2("(?~||a*?)", "aaaaaa", 0, 0);
+ x2("(a)(?~|b|\\1)", "aaaaaa", 0, 2);
+ x2("(a)(?~|bb|(?:a\\1)*)", "aaaaaa", 0, 5);
+ x2("(b|c)(?~|abac|(?:a\\1)*)", "abababacabab", 1, 4);
+ n("(?~|c|a*+)a", "aaaaa");
+ x2("(?~|aaaaa|a*+)", "aaaaa", 0, 0);
+ x2("(?~|aaaaaa|a*+)b", "aaaaaab", 1, 7);
+ x2("(?~|abcd|(?>))", "zzzabcd", 0, 0);
+ x2("(?~|abc|a*?)", "aaaabc", 0, 0);
+
+ // absent stopper
+ x2("(?~|abc)a*", "aaaaaabc", 0, 5);
+ x2("(?~|abc)a*z|aaaaaabc", "aaaaaabc", 0, 8);
+ x2("(?~|aaaaaa)a*", "aaaaaa", 0, 0);
+ x2("(?~|abc)aaaa|aaaabc", "aaaabc", 0, 6);
+ x2("(?>(?~|abc))aaaa|aaaabc", "aaaabc", 0, 6);
+ x2("(?~|)a", "a", 0, 1);
+ n("(?~|a)a", "a");
+ x2("(?~|a)(?~|)a", "a", 0, 1);
+ x2("(?~|a).*(?~|)a", "bbbbbbbbbbbbbbbbbbbba", 0, 21);
+ x2("(?~|abc).*(xyz|pqr)(?~|)abc", "aaaaxyzaaapqrabc", 0, 16);
+ x2("(?~|abc).*(xyz|pqr)(?~|)abc", "aaaaxyzaaaabcpqrabc", 11, 19);
+ n("\\A(?~|abc).*(xyz|pqrabc)(?~|)abc", "aaaaxyzaaaabcpqrabcabc");
+ x2("(?~|a)(?~|)c|ab|a|", "ab", 0, 2);
+ x2("(?~|a)((?~|)c|ab|a|)", "ab", 0, 0);
+ x2("(?~|a)((?>(?~|))c|ab|a|)", "ab", 0, 0);
+
+ // extended grapheme cluster
+
+ // CR + LF
+ n(".\\y\\O", "\x0d\x0a");
+ x2(".\\Y\\O", "\x0d\x0a", 0, 2);
+ n("\\X\\X", "\x0d\x0a");
+ x2("^\\X$", "\x0d\x0a", 0, 2);
+ x2("^\\X\\X\\X$", "ab\x0d\x0a", 0, 4);
+
+ x2("", "¤¢", 0, 0);
+ x2("¤¢", "¤¢", 0, 2);
+ n("¤¤", "¤¢");
+ x2("¤¦¤¦", "¤¦¤¦", 0, 4);
+ x2("¤¢¤¤¤¦", "¤¢¤¤¤¦", 0, 6);
+ x2("¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³", "¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³¤³", 0, 70);
+ x2("¤¢", "¤¤¤¢", 2, 4);
+ x2("¤¤¤¦", "¤¢¤¤¤¦", 2, 6);
+ x2("\\xca\\xb8", "\xca\xb8", 0, 2);
+ x2(".", "¤¢", 0, 2);
+ x2("..", "¤«¤­", 0, 4);
+ x2("\\w", "¤ª", 0, 2);
+ n("\\W", "¤¢");
+ x2("[\\W]", "¤¦$", 2, 3);
+ x2("\\S", "¤½", 0, 2);
+ x2("\\S", "´Á", 0, 2);
+ x2("\\b", "µ¤ ", 0, 0);
+ x2("\\b", " ¤Û", 1, 1);
+ x2("\\B", "¤»¤½ ", 2, 2);
+ x2("\\B", "¤¦ ", 3, 3);
+ x2("\\B", " ¤¤", 0, 0);
+ x2("[¤¿¤Á]", "¤Á", 0, 2);
+ n("[¤Ê¤Ë]", "¤Ì");
+ x2("[¤¦-¤ª]", "¤¨", 0, 2);
+ n("[^¤±]", "¤±");
+ x2("[\\w]", "¤Í", 0, 2);
+ n("[\\d]", "¤Õ");
+ x2("[\\D]", "¤Ï", 0, 2);
+ n("[\\s]", "¤¯");
+ x2("[\\S]", "¤Ø", 0, 2);
+ x2("[\\w\\d]", "¤è", 0, 2);
+ x2("[\\w\\d]", " ¤è", 3, 5);
+ n("\\wµ´¼Ö", " µ´¼Ö");
+ x2("µ´\\W¼Ö", "µ´ ¼Ö", 0, 5);
+ x2("¤¢.¤¤.¤¦", "¤¢¤¢¤¤¤¤¤¦", 0, 10);
+ x2(".\\w¤¦\\W..¤¾", "¤¨¤¦¤¦ ¤¦¤¾¤¾", 0, 13);
+ x2("\\s\\w¤³¤³¤³", " ¤³¤³¤³¤³", 0, 9);
+ x2("¤¢¤¢.¤±", "¤¢¤¢¤±¤±", 0, 8);
+ n(".¤¤", "¤¤¤¨");
+ x2(".¤ª", "¤ª¤ª", 0, 4);
+ x2("^¤¢", "¤¢", 0, 2);
+ x2("^¤à$", "¤à", 0, 2);
+ x2("^\\w$", "¤Ë", 0, 2);
+ x2("^\\w¤«¤­¤¯¤±¤³$", "z¤«¤­¤¯¤±¤³", 0, 11);
+ x2("^\\w...¤¦¤¨¤ª$", "z¤¢¤¤¤¦¤¦¤¨¤ª", 0, 13);
+ x2("\\w\\w\\s\\W¤ª¤ª¤ª\\d", "a¤ª ¤ª¤ª¤ª4", 0, 12);
+ x2("\\A¤¿¤Á¤Ä", "¤¿¤Á¤Ä", 0, 6);
+ x2("¤à¤á¤â\\Z", "¤à¤á¤â", 0, 6);
+ x2("¤«¤­¤¯\\z", "¤«¤­¤¯", 0, 6);
+ x2("¤«¤­¤¯\\Z", "¤«¤­¤¯\n", 0, 6);
+ x2("\\G¤Ý¤Ô", "¤Ý¤Ô", 0, 4);
+ n("\\G¤¨", "¤¦¤¨¤ª");
+ n("¤È¤Æ\\G", "¤È¤Æ");
+ n("¤Þ¤ß\\A", "¤Þ¤ß");
+ n("¤Þ\\A¤ß", "¤Þ¤ß");
+ x2("(?=¤»)¤»", "¤»", 0, 2);
+ n("(?=¤¦).", "¤¤");
+ x2("(?!¤¦)¤«", "¤«", 0, 2);
+ n("(?!¤È)¤¢", "¤È");
+ x2("(?i:¤¢)", "¤¢", 0, 2);
+ x2("(?i:¤Ö¤Ù)", "¤Ö¤Ù", 0, 4);
+ n("(?i:¤¤)", "¤¦");
+ x2("(?m:¤è.)", "¤è\n", 0, 3);
+ x2("(?m:.¤á)", "¤Þ\n¤á", 2, 5);
+ x2("¤¢?", "", 0, 0);
+ x2("ÊÑ?", "²½", 0, 0);
+ x2("ÊÑ?", "ÊÑ", 0, 2);
+ x2("ÎÌ*", "", 0, 0);
+ x2("ÎÌ*", "ÎÌ", 0, 2);
+ x2("»Ò*", "»Ò»Ò»Ò", 0, 6);
+ x2("ÇÏ*", "¼¯ÇÏÇÏÇÏÇÏ", 0, 0);
+ n("»³+", "");
+ x2("²Ï+", "²Ï", 0, 2);
+ x2("»þ+", "»þ»þ»þ»þ", 0, 8);
+ x2("¤¨+", "¤¨¤¨¤¦¤¦¤¦", 0, 4);
+ x2("¤¦+", "¤ª¤¦¤¦¤¦¤¦", 2, 10);
+ x2(".?", "¤¿", 0, 2);
+ x2(".*", "¤Ñ¤Ô¤×¤Ú", 0, 8);
+ x2(".+", "¤í", 0, 2);
+ x2(".+", "¤¤¤¦¤¨¤«\n", 0, 8);
+ x2("¤¢|¤¤", "¤¢", 0, 2);
+ x2("¤¢|¤¤", "¤¤", 0, 2);
+ x2("¤¢¤¤|¤¤¤¦", "¤¢¤¤", 0, 4);
+ x2("¤¢¤¤|¤¤¤¦", "¤¤¤¦", 0, 4);
+ x2("¤ò(?:¤«¤­|¤­¤¯)", "¤ò¤«¤­", 0, 6);
+ x2("¤ò(?:¤«¤­|¤­¤¯)¤±", "¤ò¤­¤¯¤±", 0, 8);
+ x2("¤¢¤¤|(?:¤¢¤¦|¤¢¤ò)", "¤¢¤ò", 0, 4);
+ x2("¤¢|¤¤|¤¦", "¤¨¤¦", 2, 4);
+ x2("¤¢|¤¤|¤¦¤¨|¤ª¤«¤­|¤¯|¤±¤³¤µ|¤·¤¹¤»|¤½|¤¿¤Á|¤Ä¤Æ¤È¤Ê¤Ë|¤Ì¤Í", "¤·¤¹¤»", 0, 6);
+ n("¤¢|¤¤|¤¦¤¨|¤ª¤«¤­|¤¯|¤±¤³¤µ|¤·¤¹¤»|¤½|¤¿¤Á|¤Ä¤Æ¤È¤Ê¤Ë|¤Ì¤Í", "¤¹¤»");
+ x2("¤¢|^¤ï", "¤Ö¤¢", 2, 4);
+ x2("¤¢|^¤ò", "¤ò¤¢", 0, 2);
+ x2("µ´|\\G¼Ö", "¤±¼Öµ´", 4, 6);
+ x2("µ´|\\G¼Ö", "¼Öµ´", 0, 2);
+ x2("µ´|\\A¼Ö", "b¼Öµ´", 3, 5);
+ x2("µ´|\\A¼Ö", "¼Ö", 0, 2);
+ x2("µ´|¼Ö\\Z", "¼Öµ´", 2, 4);
+ x2("µ´|¼Ö\\Z", "¼Ö", 0, 2);
+ x2("µ´|¼Ö\\Z", "¼Ö\n", 0, 2);
+ x2("µ´|¼Ö\\z", "¼Öµ´", 2, 4);
+ x2("µ´|¼Ö\\z", "¼Ö", 0, 2);
+ x2("\\w|\\s", "¤ª", 0, 2);
+ x2("\\w|%", "%¤ª", 0, 1);
+ x2("\\w|[&$]", "¤¦&", 0, 2);
+ x2("[¤¤-¤±]", "¤¦", 0, 2);
+ x2("[¤¤-¤±]|[^¤«-¤³]", "¤¢", 0, 2);
+ x2("[¤¤-¤±]|[^¤«-¤³]", "¤«", 0, 2);
+ x2("[^¤¢]", "\n", 0, 1);
+ x2("(?:¤¢|[¤¦-¤­])|¤¤¤ò", "¤¦¤ò", 0, 2);
+ x2("(?:¤¢|[¤¦-¤­])|¤¤¤ò", "¤¤¤ò", 0, 4);
+ x2("¤¢¤¤¤¦|(?=¤±¤±)..¤Û", "¤±¤±¤Û", 0, 6);
+ x2("¤¢¤¤¤¦|(?!¤±¤±)..¤Û", "¤¢¤¤¤Û", 0, 6);
+ x2("(?=¤ò¤¢)..¤¢|(?=¤ò¤ò)..¤¢", "¤ò¤ò¤¢", 0, 6);
+ x2("(?<=¤¢|¤¤¤¦)¤¤", "¤¤¤¦¤¤", 4, 6);
+ n("(?>¤¢|¤¢¤¤¤¨)¤¦", "¤¢¤¤¤¨¤¦");
+ x2("(?>¤¢¤¤¤¨|¤¢)¤¦", "¤¢¤¤¤¨¤¦", 0, 8);
+ x2("¤¢?|¤¤", "¤¢", 0, 2);
+ x2("¤¢?|¤¤", "¤¤", 0, 0);
+ x2("¤¢?|¤¤", "", 0, 0);
+ x2("¤¢*|¤¤", "¤¢¤¢", 0, 4);
+ x2("¤¢*|¤¤*", "¤¤¤¢", 0, 0);
+ x2("¤¢*|¤¤*", "¤¢¤¤", 0, 2);
+ x2("[a¤¢]*|¤¤*", "a¤¢¤¤¤¤¤¤", 0, 3);
+ x2("¤¢+|¤¤*", "", 0, 0);
+ x2("¤¢+|¤¤*", "¤¤¤¤¤¤", 0, 6);
+ x2("¤¢+|¤¤*", "¤¢¤¤¤¤¤¤", 0, 2);
+ x2("¤¢+|¤¤*", "a¤¢¤¤¤¤¤¤", 0, 0);
+ n("¤¢+|¤¤+", "");
+ x2("(¤¢|¤¤)?", "¤¤", 0, 2);
+ x2("(¤¢|¤¤)*", "¤¤¤¢", 0, 4);
+ x2("(¤¢|¤¤)+", "¤¤¤¢¤¤", 0, 6);
+ x2("(¤¢¤¤|¤¦¤¢)+", "¤¦¤¢¤¢¤¤¤¦¤¨", 0, 8);
+ x2("(¤¢¤¤|¤¦¤¨)+", "¤¦¤¢¤¢¤¤¤¦¤¨", 4, 12);
+ x2("(¤¢¤¤|¤¦¤¢)+", "¤¢¤¢¤¤¤¦¤¢", 2, 10);
+ x2("(¤¢¤¤|¤¦¤¢)+", "¤¢¤¤¤ò¤¦¤¢", 0, 4);
+ x2("(¤¢¤¤|¤¦¤¢)+", "$$zzzz¤¢¤¤¤ò¤¦¤¢", 6, 10);
+ x2("(¤¢|¤¤¤¢¤¤)+", "¤¢¤¤¤¢¤¤¤¢", 0, 10);
+ x2("(¤¢|¤¤¤¢¤¤)+", "¤¤¤¢", 2, 4);
+ x2("(¤¢|¤¤¤¢¤¤)+", "¤¤¤¢¤¢¤¢¤¤¤¢", 2, 8);
+ x2("(?:¤¢|¤¤)(?:¤¢|¤¤)", "¤¢¤¤", 0, 4);
+ x2("(?:¤¢*|¤¤*)(?:¤¢*|¤¤*)", "¤¢¤¢¤¢¤¤¤¤¤¤", 0, 6);
+ x2("(?:¤¢*|¤¤*)(?:¤¢+|¤¤+)", "¤¢¤¢¤¢¤¤¤¤¤¤", 0, 12);
+ x2("(?:¤¢+|¤¤+){2}", "¤¢¤¢¤¢¤¤¤¤¤¤", 0, 12);
+ x2("(?:¤¢+|¤¤+){1,2}", "¤¢¤¢¤¢¤¤¤¤¤¤", 0, 12);
+ x2("(?:¤¢+|\\A¤¤*)¤¦¤¦", "¤¦¤¦", 0, 4);
+ n("(?:¤¢+|\\A¤¤*)¤¦¤¦", "¤¢¤¤¤¦¤¦");
+ x2("(?:^¤¢+|¤¤+)*¤¦", "¤¢¤¢¤¤¤¤¤¤¤¢¤¤¤¦", 12, 16);
+ x2("(?:^¤¢+|¤¤+)*¤¦", "¤¢¤¢¤¤¤¤¤¤¤¤¤¦", 0, 14);
+ x2("¤¦{0,}", "¤¦¤¦¤¦¤¦", 0, 8);
+ x2("¤¢|(?i)c", "C", 0, 1);
+ x2("(?i)c|¤¢", "C", 0, 1);
+ x2("(?i:¤¢)|a", "a", 0, 1);
+ n("(?i:¤¢)|a", "A");
+ x2("[¤¢¤¤¤¦]?", "¤¢¤¤¤¦", 0, 2);
+ x2("[¤¢¤¤¤¦]*", "¤¢¤¤¤¦", 0, 6);
+ x2("[^¤¢¤¤¤¦]*", "¤¢¤¤¤¦", 0, 0);
+ n("[^¤¢¤¤¤¦]+", "¤¢¤¤¤¦");
+ x2("¤¢?\?", "¤¢¤¢¤¢", 0, 0);
+ x2("¤¤¤¢?\?¤¤", "¤¤¤¢¤¤", 0, 6);
+ x2("¤¢*?", "¤¢¤¢¤¢", 0, 0);
+ x2("¤¤¤¢*?", "¤¤¤¢¤¢", 0, 2);
+ x2("¤¤¤¢*?¤¤", "¤¤¤¢¤¢¤¤", 0, 8);
+ x2("¤¢+?", "¤¢¤¢¤¢", 0, 2);
+ x2("¤¤¤¢+?", "¤¤¤¢¤¢", 0, 4);
+ x2("¤¤¤¢+?¤¤", "¤¤¤¢¤¢¤¤", 0, 8);
+ x2("(?:Å·?)?\?", "Å·", 0, 0);
+ x2("(?:Å·?\?)?", "Å·", 0, 0);
+ x2("(?:Ì´?)+?", "Ì´Ì´Ì´", 0, 2);
+ x2("(?:É÷+)?\?", "É÷É÷É÷", 0, 0);
+ x2("(?:Àã+)?\?Áú", "ÀãÀãÀãÁú", 0, 8);
+ x2("(?:¤¢¤¤)?{2}", "", 0, 0);
+ x2("(?:µ´¼Ö)?{2}", "µ´¼Öµ´¼Öµ´", 0, 8);
+ x2("(?:µ´¼Ö)*{0}", "µ´¼Öµ´¼Öµ´", 0, 0);
+ x2("(?:µ´¼Ö){3,}", "µ´¼Öµ´¼Öµ´¼Öµ´¼Ö", 0, 16);
+ n("(?:µ´¼Ö){3,}", "µ´¼Öµ´¼Ö");
+ x2("(?:µ´¼Ö){2,4}", "µ´¼Öµ´¼Öµ´¼Ö", 0, 12);
+ x2("(?:µ´¼Ö){2,4}", "µ´¼Öµ´¼Öµ´¼Öµ´¼Öµ´¼Ö", 0, 16);
+ x2("(?:µ´¼Ö){2,4}?", "µ´¼Öµ´¼Öµ´¼Öµ´¼Öµ´¼Ö", 0, 8);
+ x2("(?:µ´¼Ö){,}", "µ´¼Ö{,}", 0, 7);
+ x2("(?:¤«¤­¤¯)+?{2}", "¤«¤­¤¯¤«¤­¤¯¤«¤­¤¯", 0, 12);
+ x3("(²Ð)", "²Ð", 0, 2, 1);
+ x3("(²Ð¿å)", "²Ð¿å", 0, 4, 1);
+ x2("((»þ´Ö))", "»þ´Ö", 0, 4);
+ x3("((É÷¿å))", "É÷¿å", 0, 4, 1);
+ x3("((ºòÆü))", "ºòÆü", 0, 4, 2);
+ x3("((((((((((((((((((((ÎÌ»Ò))))))))))))))))))))", "ÎÌ»Ò", 0, 4, 20);
+ x3("(¤¢¤¤)(¤¦¤¨)", "¤¢¤¤¤¦¤¨", 0, 4, 1);
+ x3("(¤¢¤¤)(¤¦¤¨)", "¤¢¤¤¤¦¤¨", 4, 8, 2);
+ x3("()(¤¢)¤¤¤¦(¤¨¤ª¤«)¤­¤¯¤±¤³", "¤¢¤¤¤¦¤¨¤ª¤«¤­¤¯¤±¤³", 6, 12, 3);
+ x3("(()(¤¢)¤¤¤¦(¤¨¤ª¤«)¤­¤¯¤±¤³)", "¤¢¤¤¤¦¤¨¤ª¤«¤­¤¯¤±¤³", 6, 12, 4);
+ x3(".*(¥Õ¥©)¥ó¡¦¥Þ(¥ó()¥·¥å¥¿)¥¤¥ó", "¥Õ¥©¥ó¡¦¥Þ¥ó¥·¥å¥¿¥¤¥ó", 10, 18, 2);
+ x2("(^¤¢)", "¤¢", 0, 2);
+ x3("(¤¢)|(¤¢)", "¤¤¤¢", 2, 4, 1);
+ x3("(^¤¢)|(¤¢)", "¤¤¤¢", 2, 4, 2);
+ x3("(¤¢?)", "¤¢¤¢¤¢", 0, 2, 1);
+ x3("(¤Þ*)", "¤Þ¤Þ¤Þ", 0, 6, 1);
+ x3("(¤È*)", "", 0, 0, 1);
+ x3("(¤ë+)", "¤ë¤ë¤ë¤ë¤ë¤ë¤ë", 0, 14, 1);
+ x3("(¤Õ+|¤Ø*)", "¤Õ¤Õ¤Õ¤Ø¤Ø", 0, 6, 1);
+ x3("(¤¢+|¤¤?)", "¤¤¤¤¤¤¤¢¤¢", 0, 2, 1);
+ x3("(¤¢¤¤¤¦)?", "¤¢¤¤¤¦", 0, 6, 1);
+ x3("(¤¢¤¤¤¦)*", "¤¢¤¤¤¦", 0, 6, 1);
+ x3("(¤¢¤¤¤¦)+", "¤¢¤¤¤¦", 0, 6, 1);
+ x3("(¤µ¤·¤¹|¤¢¤¤¤¦)+", "¤¢¤¤¤¦", 0, 6, 1);
+ x3("([¤Ê¤Ë¤Ì][¤«¤­¤¯]|¤«¤­¤¯)+", "¤«¤­¤¯", 0, 6, 1);
+ x3("((?i:¤¢¤¤¤¦))", "¤¢¤¤¤¦", 0, 6, 1);
+ x3("((?m:¤¢.¤¦))", "¤¢\n¤¦", 0, 5, 1);
+ x3("((?=¤¢¤ó)¤¢)", "¤¢¤ó¤¤", 0, 2, 1);
+ x3("¤¢¤¤¤¦|(.¤¢¤¤¤¨)", "¤ó¤¢¤¤¤¨", 0, 8, 1);
+ x3("¤¢*(.)", "¤¢¤¢¤¢¤¢¤ó", 8, 10, 1);
+ x3("¤¢*?(.)", "¤¢¤¢¤¢¤¢¤ó", 0, 2, 1);
+ x3("¤¢*?(¤ó)", "¤¢¤¢¤¢¤¢¤ó", 8, 10, 1);
+ x3("[¤¤¤¦¤¨]¤¢*(.)", "¤¨¤¢¤¢¤¢¤¢¤ó", 10, 12, 1);
+ x3("(\\A¤¤¤¤)¤¦¤¦", "¤¤¤¤¤¦¤¦", 0, 4, 1);
+ n("(\\A¤¤¤¤)¤¦¤¦", "¤ó¤¤¤¤¤¦¤¦");
+ x3("(^¤¤¤¤)¤¦¤¦", "¤¤¤¤¤¦¤¦", 0, 4, 1);
+ n("(^¤¤¤¤)¤¦¤¦", "¤ó¤¤¤¤¤¦¤¦");
+ x3("¤í¤í(¤ë¤ë$)", "¤í¤í¤ë¤ë", 4, 8, 1);
+ n("¤í¤í(¤ë¤ë$)", "¤í¤í¤ë¤ë¤ë");
+ x2("(̵)\\1", "̵̵", 0, 4);
+ n("(̵)\\1", "̵Éð");
+ x2("(¶õ?)\\1", "¶õ¶õ", 0, 4);
+ x2("(¶õ?\?)\\1", "¶õ¶õ", 0, 0);
+ x2("(¶õ*)\\1", "¶õ¶õ¶õ¶õ¶õ", 0, 8);
+ x3("(¶õ*)\\1", "¶õ¶õ¶õ¶õ¶õ", 0, 4, 1);
+ x2("¤¢(¤¤*)\\1", "¤¢¤¤¤¤¤¤¤¤", 0, 10);
+ x2("¤¢(¤¤*)\\1", "¤¢¤¤", 0, 2);
+ x2("(¤¢*)(¤¤*)\\1\\2", "¤¢¤¢¤¢¤¤¤¤¤¢¤¢¤¢¤¤¤¤", 0, 20);
+ x2("(¤¢*)(¤¤*)\\2", "¤¢¤¢¤¢¤¤¤¤¤¤¤¤", 0, 14);
+ x3("(¤¢*)(¤¤*)\\2", "¤¢¤¢¤¢¤¤¤¤¤¤¤¤", 6, 10, 2);
+ x2("(((((((¤Ý*)¤Ú))))))¤Ô\\7", "¤Ý¤Ý¤Ý¤Ú¤Ô¤Ý¤Ý¤Ý", 0, 16);
+ x3("(((((((¤Ý*)¤Ú))))))¤Ô\\7", "¤Ý¤Ý¤Ý¤Ú¤Ô¤Ý¤Ý¤Ý", 0, 6, 7);
+ x2("(¤Ï)(¤Ò)(¤Õ)\\2\\1\\3", "¤Ï¤Ò¤Õ¤Ò¤Ï¤Õ", 0, 12);
+ x2("([¤­-¤±])\\1", "¤¯¤¯", 0, 4);
+ x2("(\\w\\d\\s)\\1", "¤¢5 ¤¢5 ", 0, 8);
+ n("(\\w\\d\\s)\\1", "¤¢5 ¤¢5");
+ x2("(ï¡©|[¤¢-¤¦]{3})\\1", "ï¡©", 0, 8);
+ x2("...(ï¡©|[¤¢-¤¦]{3})\\1", "¤¢a¤¢Ã¯¡©Ã¯¡©", 0, 13);
+ x2("(ï¡©|[¤¢-¤¦]{3})\\1", "¤¦¤¤¤¦¤¦¤¤¤¦", 0, 12);
+ x2("(^¤³)\\1", "¤³¤³", 0, 4);
+ n("(^¤à)\\1", "¤á¤à¤à");
+ n("(¤¢$)\\1", "¤¢¤¢");
+ n("(¤¢¤¤\\Z)\\1", "¤¢¤¤");
+ x2("(¤¢*\\Z)\\1", "¤¢", 2, 2);
+ x2(".(¤¢*\\Z)\\1", "¤¤¤¢", 2, 4);
+ x3("(.(¤ä¤¤¤æ)\\2)", "z¤ä¤¤¤æ¤ä¤¤¤æ", 0, 13, 1);
+ x3("(.(..\\d.)\\2)", "¤¢12341234", 0, 10, 1);
+ x2("((?i:¤¢v¤º))\\1", "¤¢v¤º¤¢v¤º", 0, 10);
+ x2("(?<¶ò¤«>ÊÑ|\\(\\g<¶ò¤«>\\))", "((((((ÊÑ))))))", 0, 14);
+ x2("\\A(?:\\g<°¤_1>|\\g<±¾_2>|\\z½ªÎ» (?<°¤_1>´Ñ|¼«\\g<±¾_2>¼«)(?<±¾_2>ºß|Ê\\g<°¤_1>Ê))$", "Ê¼«Ê¼«ºß¼«Ê¼«Ê", 0, 26);
+ x2("[[¤Ò¤Õ]]", "¤Õ", 0, 2);
+ x2("[[¤¤¤ª¤¦]¤«]", "¤«", 0, 2);
+ n("[[^¤¢]]", "¤¢");
+ n("[^[¤¢]]", "¤¢");
+ x2("[^[^¤¢]]", "¤¢", 0, 2);
+ x2("[[¤«¤­¤¯]&&¤­¤¯]", "¤¯", 0, 2);
+ n("[[¤«¤­¤¯]&&¤­¤¯]", "¤«");
+ n("[[¤«¤­¤¯]&&¤­¤¯]", "¤±");
+ x2("[¤¢-¤ó&&¤¤-¤ò&&¤¦-¤ñ]", "¤ñ", 0, 2);
+ n("[^¤¢-¤ó&&¤¤-¤ò&&¤¦-¤ñ]", "¤ñ");
+ x2("[[^¤¢&&¤¢]&&¤¢-¤ó]", "¤¤", 0, 2);
+ n("[[^¤¢&&¤¢]&&¤¢-¤ó]", "¤¢");
+ x2("[[^¤¢-¤ó&&¤¤¤¦¤¨¤ª]&&[^¤¦-¤«]]", "¤­", 0, 2);
+ n("[[^¤¢-¤ó&&¤¤¤¦¤¨¤ª]&&[^¤¦-¤«]]", "¤¤");
+ x2("[^[^¤¢¤¤¤¦]&&[^¤¦¤¨¤ª]]", "¤¦", 0, 2);
+ x2("[^[^¤¢¤¤¤¦]&&[^¤¦¤¨¤ª]]", "¤¨", 0, 2);
+ n("[^[^¤¢¤¤¤¦]&&[^¤¦¤¨¤ª]]", "¤«");
+ x2("[¤¢-&&-¤¢]", "-", 0, 1);
+ x2("[^[^a-z¤¢¤¤¤¦]&&[^bcdefg¤¦¤¨¤ª]q-w]", "¤¨", 0, 2);
+ x2("[^[^a-z¤¢¤¤¤¦]&&[^bcdefg¤¦¤¨¤ª]g-w]", "f", 0, 1);
+ x2("[^[^a-z¤¢¤¤¤¦]&&[^bcdefg¤¦¤¨¤ª]g-w]", "g", 0, 1);
+ n("[^[^a-z¤¢¤¤¤¦]&&[^bcdefg¤¦¤¨¤ª]g-w]", "2");
+ x2("a<b>¥Ð¡¼¥¸¥ç¥ó¤Î¥À¥¦¥ó¥í¡¼¥É<\\/b>", "a<b>¥Ð¡¼¥¸¥ç¥ó¤Î¥À¥¦¥ó¥í¡¼¥É</b>", 0, 32);
+ x2(".<b>¥Ð¡¼¥¸¥ç¥ó¤Î¥À¥¦¥ó¥í¡¼¥É<\\/b>", "a<b>¥Ð¡¼¥¸¥ç¥ó¤Î¥À¥¦¥ó¥í¡¼¥É</b>", 0, 32);
+ x2("\\n?\\z", "¤³¤ó¤Ë¤Á¤Ï", 10, 10);
+
+#ifndef POSIX_TEST
+ x2("\\p{Hiragana}", "¤Ô", 0, 2);
+ n("\\P{Hiragana}", "¤Ô");
+#endif
+
+ fprintf(stdout,
+ "\nRESULT SUCC: %4d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+#ifndef POSIX_TEST
+ onig_region_free(region, 1);
+ onig_end();
+#endif
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testu.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testu.c
new file mode 100644
index 000000000..24397ab58
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/test/testu.c
@@ -0,0 +1,955 @@
+/*
+ * testu.c
+ * Copyright (c) 2019 K.Kosako
+ */
+#include<stdio.h>
+
+#ifdef POSIX_TEST
+#include "onigposix.h"
+#else
+#include "oniguruma.h"
+#endif
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+static FILE* err_file;
+
+#ifndef POSIX_TEST
+static OnigRegion* region;
+static OnigEncoding ENC;
+#endif
+
+#define ulen(p) onigenc_str_bytelen_null(ENC, (UChar* )p)
+
+static void uconv(char* from, char* to, int len)
+{
+ int i;
+ unsigned char c;
+ char *q;
+
+ q = to;
+
+ for (i = 0; i < len; i += 2) {
+ c = (unsigned char )from[i];
+ if (c == 0) {
+ c = (unsigned char )from[i+1];
+ if (c < 0x20 || c >= 0x7f || c == 0x5c || c == 0x22) {
+ sprintf(q, "\\%03o", c);
+ q += 4;
+ }
+ else {
+ sprintf(q, "%c", c);
+ q++;
+ }
+ }
+ else {
+ sprintf(q, "\\%03o", c);
+ q += 4;
+ c = (unsigned char )from[i+1];
+ sprintf(q, "\\%03o", c);
+ q += 4;
+ }
+ }
+
+ *q = 0;
+}
+
+static void xx(char* pattern, char* str, int from, int to, int mem, int not)
+{
+ int r;
+ char cpat[4000], cstr[4000];
+
+#ifdef POSIX_TEST
+ regex_t reg;
+ char buf[200];
+ regmatch_t pmatch[20];
+
+ uconv(pattern, cpat, ulen(pattern));
+ uconv(str, cstr, ulen(str));
+
+ r = regcomp(&reg, pattern, REG_EXTENDED | REG_NEWLINE);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ r = regexec(&reg, str, reg.re_nsub + 1, pmatch, 0);
+ if (r != 0 && r != REG_NOMATCH) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ if (r == REG_NOMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", cpat, cstr);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", cpat, cstr);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", cpat, cstr);
+ nfail++;
+ }
+ else {
+ if (pmatch[mem].rm_so == from && pmatch[mem].rm_eo == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", cpat, cstr);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", cpat, cstr,
+ from, to, pmatch[mem].rm_so, pmatch[mem].rm_eo);
+ nfail++;
+ }
+ }
+ }
+ regfree(&reg);
+
+#else
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ uconv(pattern, cpat, ulen(pattern));
+ uconv(str, cstr, ulen(str));
+
+ r = onig_new(&reg, (UChar* )pattern, (UChar* )(pattern + ulen(pattern)),
+ ONIG_OPTION_DEFAULT, ENC, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ r = onig_search(reg, (UChar* )str, (UChar* )(str + ulen(str)),
+ (UChar* )str, (UChar* )(str + ulen(str)),
+ region, ONIG_OPTION_NONE);
+ if (r < ONIG_MISMATCH) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", cpat, cstr);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", cpat, cstr);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", cpat, cstr);
+ nfail++;
+ }
+ else {
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", cpat, cstr);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", cpat, cstr,
+ from, to, region->beg[mem], region->end[mem]);
+ nfail++;
+ }
+ }
+ }
+ onig_free(reg);
+#endif
+}
+
+static void x2(char* pattern, char* str, int from, int to)
+{
+ xx(pattern, str, from, to, 0, 0);
+}
+
+static void x3(char* pattern, char* str, int from, int to, int mem)
+{
+ xx(pattern, str, from, to, mem, 0);
+}
+
+static void n(char* pattern, char* str)
+{
+ xx(pattern, str, 0, 0, 0, 1);
+}
+
+extern int main(int argc, char* argv[])
+{
+ OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_UTF16_BE;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+
+ err_file = stdout;
+
+#ifndef POSIX_TEST
+ region = onig_region_new();
+#endif
+#ifdef POSIX_TEST
+ reg_set_encoding(REG_POSIX_ENCODING_UTF16_BE);
+#else
+ ENC = ONIG_ENCODING_UTF16_BE;
+#endif
+ x2("\000\000", "\000\000", 0, 0);
+ x2("\000^\000\000", "\000\000", 0, 0);
+ x2("\000$\000\000", "\000\000", 0, 0);
+ x2("\000\134\000G\000\000", "\000\000", 0, 0);
+ x2("\000\134\000A\000\000", "\000\000", 0, 0);
+ x2("\000\134\000Z\000\000", "\000\000", 0, 0);
+ x2("\000\134\000z\000\000", "\000\000", 0, 0);
+ x2("\000^\000$\000\000", "\000\000", 0, 0);
+ x2("\000\134\000c\000a\000\000", "\000\001\000\000", 0, 2);
+ x2("\000\134\000C\000-\000b\000\000", "\000\002\000\000", 0, 2);
+ x2("\000\134\000c\000\134\000\134\000\000", "\000\034\000\000", 0, 2);
+ x2("\000q\000[\000\134\000c\000\134\000\134\000]\000\000", "\000q\000\034\000\000", 0, 4);
+ x2("\000\000", "\000a\000\000", 0, 0);
+ x2("\000a\000\000", "\000a\000\000", 0, 2);
+ x2("\000\134\000x\0000\0000\000\134\000x\0006\0001\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000a\000\000", "\000a\000a\000\000", 0, 4);
+ x2("\000a\000a\000a\000\000", "\000a\000a\000a\000\000", 0, 6);
+ x2("\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000\000", "\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000a\000\000", 0, 70);
+ x2("\000a\000b\000\000", "\000a\000b\000\000", 0, 4);
+ x2("\000b\000\000", "\000a\000b\000\000", 2, 4);
+ x2("\000b\000c\000\000", "\000a\000b\000c\000\000", 2, 6);
+ x2("\000(\000?\000i\000:\000#\000R\000E\000T\000#\000)\000\000", "\000#\000I\000N\000S\000#\000#\000R\000E\000T\000#\000\000", 10, 20);
+ x2("\000\134\0000\0000\0000\000\134\0001\0007\000\000", "\000\017\000\000", 0, 2);
+ x2("\000\134\000x\0000\0000\000\134\000x\0001\000f\000\000", "\000\037\000\000", 0, 2);
+ x2("\000a\000(\000?\000#\000.\000.\000.\000.\000\134\000\134\000J\000J\000J\000J\000)\000b\000\000", "\000a\000b\000\000", 0, 4);
+ x2("\000(\000?\000x\000)\000 \000 \000G\000 \000(\000o\000 \000O\000(\000?\000-\000x\000)\000o\000O\000)\000 \000g\000 \000L\000\000", "\000G\000o\000O\000o\000O\000g\000L\000e\000\000", 0, 14);
+ x2("\000.\000\000", "\000a\000\000", 0, 2);
+ n("\000.\000\000", "\000\000");
+ x2("\000.\000.\000\000", "\000a\000b\000\000", 0, 4);
+ x2("\000\134\000w\000\000", "\000e\000\000", 0, 2);
+ n("\000\134\000W\000\000", "\000e\000\000");
+ x2("\000\134\000s\000\000", "\000 \000\000", 0, 2);
+ x2("\000\134\000S\000\000", "\000b\000\000", 0, 2);
+ x2("\000\134\000d\000\000", "\0004\000\000", 0, 2);
+ n("\000\134\000D\000\000", "\0004\000\000");
+ x2("\000\134\000b\000\000", "\000z\000 \000\000", 0, 0);
+ x2("\000\134\000b\000\000", "\000 \000z\000\000", 2, 2);
+ x2("\000\134\000B\000\000", "\000z\000z\000 \000\000", 2, 2);
+ x2("\000\134\000B\000\000", "\000z\000 \000\000", 4, 4);
+ x2("\000\134\000B\000\000", "\000 \000z\000\000", 0, 0);
+ x2("\000[\000a\000b\000]\000\000", "\000b\000\000", 0, 2);
+ n("\000[\000a\000b\000]\000\000", "\000c\000\000");
+ x2("\000[\000a\000-\000z\000]\000\000", "\000t\000\000", 0, 2);
+ n("\000[\000^\000a\000]\000\000", "\000a\000\000");
+ x2("\000[\000^\000a\000]\000\000", "\000\012\000\000", 0, 2);
+ x2("\000[\000]\000]\000\000", "\000]\000\000", 0, 2);
+ n("\000[\000^\000]\000]\000\000", "\000]\000\000");
+ x2("\000[\000\134\000^\000]\000+\000\000", "\0000\000^\000^\0001\000\000", 2, 6);
+ x2("\000[\000b\000-\000]\000\000", "\000b\000\000", 0, 2);
+ x2("\000[\000b\000-\000]\000\000", "\000-\000\000", 0, 2);
+ x2("\000[\000\134\000w\000]\000\000", "\000z\000\000", 0, 2);
+ n("\000[\000\134\000w\000]\000\000", "\000 \000\000");
+ x2("\000[\000\134\000W\000]\000\000", "\000b\000$\000\000", 2, 4);
+ x2("\000[\000\134\000d\000]\000\000", "\0005\000\000", 0, 2);
+ n("\000[\000\134\000d\000]\000\000", "\000e\000\000");
+ x2("\000[\000\134\000D\000]\000\000", "\000t\000\000", 0, 2);
+ n("\000[\000\134\000D\000]\000\000", "\0003\000\000");
+ x2("\000[\000\134\000s\000]\000\000", "\000 \000\000", 0, 2);
+ n("\000[\000\134\000s\000]\000\000", "\000a\000\000");
+ x2("\000[\000\134\000S\000]\000\000", "\000b\000\000", 0, 2);
+ n("\000[\000\134\000S\000]\000\000", "\000 \000\000");
+ x2("\000[\000\134\000w\000\134\000d\000]\000\000", "\0002\000\000", 0, 2);
+ n("\000[\000\134\000w\000\134\000d\000]\000\000", "\000 \000\000");
+ x2("\000[\000[\000:\000u\000p\000p\000e\000r\000:\000]\000]\000\000", "\000B\000\000", 0, 2);
+ x2("\000[\000*\000[\000:\000x\000d\000i\000g\000i\000t\000:\000]\000+\000]\000\000", "\000+\000\000", 0, 2);
+ x2("\000[\000*\000[\000:\000x\000d\000i\000g\000i\000t\000:\000]\000+\000]\000\000", "\000G\000H\000I\000K\000K\000-\0009\000+\000*\000\000", 12, 14);
+ x2("\000[\000*\000[\000:\000x\000d\000i\000g\000i\000t\000:\000]\000+\000]\000\000", "\000-\000@\000^\000+\000\000", 6, 8);
+ n("\000[\000[\000:\000u\000p\000p\000e\000r\000]\000]\000\000", "\000A\000\000");
+ x2("\000[\000[\000:\000u\000p\000p\000e\000r\000]\000]\000\000", "\000:\000\000", 0, 2);
+ x2("\000[\000\134\0000\0000\0000\000\134\0000\0004\0004\000-\000\134\0000\0000\0000\000\134\0000\0004\0007\000]\000\000", "\000&\000\000", 0, 2);
+ x2("\000[\000\134\000x\0000\0000\000\134\000x\0005\000a\000-\000\134\000x\0000\0000\000\134\000x\0005\000c\000]\000\000", "\000[\000\000", 0, 2);
+ x2("\000[\000\134\000x\0000\0000\000\134\000x\0006\000A\000-\000\134\000x\0000\0000\000\134\000x\0006\000D\000]\000\000", "\000l\000\000", 0, 2);
+ n("\000[\000\134\000x\0000\0000\000\134\000x\0006\000A\000-\000\134\000x\0000\0000\000\134\000x\0006\000D\000]\000\000", "\000n\000\000");
+ n("\000^\000[\0000\000-\0009\000A\000-\000F\000]\000+\000 \0000\000+\000 \000U\000N\000D\000E\000F\000 \000\000", "\0007\0005\000F\000 \0000\0000\0000\0000\0000\0000\0000\0000\000 \000S\000E\000C\000T\0001\0004\000A\000 \000n\000o\000t\000y\000p\000e\000 \000(\000)\000 \000 \000 \000 \000E\000x\000t\000e\000r\000n\000a\000l\000 \000 \000 \000 \000|\000 \000_\000r\000b\000_\000a\000p\000p\000l\000y\000\000");
+ x2("\000[\000\134\000[\000]\000\000", "\000[\000\000", 0, 2);
+ x2("\000[\000\134\000]\000]\000\000", "\000]\000\000", 0, 2);
+ x2("\000[\000&\000]\000\000", "\000&\000\000", 0, 2);
+ x2("\000[\000[\000a\000b\000]\000]\000\000", "\000b\000\000", 0, 2);
+ x2("\000[\000[\000a\000b\000]\000c\000]\000\000", "\000c\000\000", 0, 2);
+ n("\000[\000[\000^\000a\000]\000]\000\000", "\000a\000\000");
+ n("\000[\000^\000[\000a\000]\000]\000\000", "\000a\000\000");
+ x2("\000[\000[\000a\000b\000]\000&\000&\000b\000c\000]\000\000", "\000b\000\000", 0, 2);
+ n("\000[\000[\000a\000b\000]\000&\000&\000b\000c\000]\000\000", "\000a\000\000");
+ n("\000[\000[\000a\000b\000]\000&\000&\000b\000c\000]\000\000", "\000c\000\000");
+ x2("\000[\000a\000-\000z\000&\000&\000b\000-\000y\000&\000&\000c\000-\000x\000]\000\000", "\000w\000\000", 0, 2);
+ n("\000[\000^\000a\000-\000z\000&\000&\000b\000-\000y\000&\000&\000c\000-\000x\000]\000\000", "\000w\000\000");
+ x2("\000[\000[\000^\000a\000&\000&\000a\000]\000&\000&\000a\000-\000z\000]\000\000", "\000b\000\000", 0, 2);
+ n("\000[\000[\000^\000a\000&\000&\000a\000]\000&\000&\000a\000-\000z\000]\000\000", "\000a\000\000");
+ x2("\000[\000[\000^\000a\000-\000z\000&\000&\000b\000c\000d\000e\000f\000]\000&\000&\000[\000^\000c\000-\000g\000]\000]\000\000", "\000h\000\000", 0, 2);
+ n("\000[\000[\000^\000a\000-\000z\000&\000&\000b\000c\000d\000e\000f\000]\000&\000&\000[\000^\000c\000-\000g\000]\000]\000\000", "\000c\000\000");
+ x2("\000[\000^\000[\000^\000a\000b\000c\000]\000&\000&\000[\000^\000c\000d\000e\000]\000]\000\000", "\000c\000\000", 0, 2);
+ x2("\000[\000^\000[\000^\000a\000b\000c\000]\000&\000&\000[\000^\000c\000d\000e\000]\000]\000\000", "\000e\000\000", 0, 2);
+ n("\000[\000^\000[\000^\000a\000b\000c\000]\000&\000&\000[\000^\000c\000d\000e\000]\000]\000\000", "\000f\000\000");
+ x2("\000[\000a\000-\000&\000&\000-\000a\000]\000\000", "\000-\000\000", 0, 2);
+ n("\000[\000a\000\134\000-\000&\000&\000\134\000-\000a\000]\000\000", "\000&\000\000");
+ n("\000\134\000w\000a\000b\000c\000\000", "\000 \000a\000b\000c\000\000");
+ x2("\000a\000\134\000W\000b\000c\000\000", "\000a\000 \000b\000c\000\000", 0, 8);
+ x2("\000a\000.\000b\000.\000c\000\000", "\000a\000a\000b\000b\000c\000\000", 0, 10);
+ x2("\000.\000\134\000w\000b\000\134\000W\000.\000.\000c\000\000", "\000a\000b\000b\000 \000b\000c\000c\000\000", 0, 14);
+ x2("\000\134\000s\000\134\000w\000z\000z\000z\000\000", "\000 \000z\000z\000z\000z\000\000", 0, 10);
+ x2("\000a\000a\000.\000b\000\000", "\000a\000a\000b\000b\000\000", 0, 8);
+ n("\000.\000a\000\000", "\000a\000b\000\000");
+ x2("\000.\000a\000\000", "\000a\000a\000\000", 0, 4);
+ x2("\000^\000a\000\000", "\000a\000\000", 0, 2);
+ x2("\000^\000a\000$\000\000", "\000a\000\000", 0, 2);
+ x2("\000^\000\134\000w\000$\000\000", "\000a\000\000", 0, 2);
+ n("\000^\000\134\000w\000$\000\000", "\000 \000\000");
+ x2("\000^\000\134\000w\000a\000b\000$\000\000", "\000z\000a\000b\000\000", 0, 6);
+ x2("\000^\000\134\000w\000a\000b\000c\000d\000e\000f\000$\000\000", "\000z\000a\000b\000c\000d\000e\000f\000\000", 0, 14);
+ x2("\000^\000\134\000w\000.\000.\000.\000d\000e\000f\000$\000\000", "\000z\000a\000b\000c\000d\000e\000f\000\000", 0, 14);
+ x2("\000\134\000w\000\134\000w\000\134\000s\000\134\000W\000a\000a\000a\000\134\000d\000\000", "\000a\000a\000 \000 \000a\000a\000a\0004\000\000", 0, 16);
+ x2("\000\134\000A\000\134\000Z\000\000", "\000\000", 0, 0);
+ x2("\000\134\000A\000x\000y\000z\000\000", "\000x\000y\000z\000\000", 0, 6);
+ x2("\000x\000y\000z\000\134\000Z\000\000", "\000x\000y\000z\000\000", 0, 6);
+ x2("\000x\000y\000z\000\134\000z\000\000", "\000x\000y\000z\000\000", 0, 6);
+ x2("\000a\000\134\000Z\000\000", "\000a\000\000", 0, 2);
+ x2("\000\134\000G\000a\000z\000\000", "\000a\000z\000\000", 0, 4);
+ n("\000\134\000G\000z\000\000", "\000b\000z\000a\000\000");
+ n("\000a\000z\000\134\000G\000\000", "\000a\000z\000\000");
+ n("\000a\000z\000\134\000A\000\000", "\000a\000z\000\000");
+ n("\000a\000\134\000A\000z\000\000", "\000a\000z\000\000");
+ x2("\000\134\000^\000\134\000$\000\000", "\000^\000$\000\000", 0, 4);
+ x2("\000^\000x\000?\000y\000\000", "\000x\000y\000\000", 0, 4);
+ x2("\000^\000(\000x\000?\000y\000)\000\000", "\000x\000y\000\000", 0, 4);
+ x2("\000\134\000w\000\000", "\000_\000\000", 0, 2);
+ n("\000\134\000W\000\000", "\000_\000\000");
+ x2("\000(\000?\000=\000z\000)\000z\000\000", "\000z\000\000", 0, 2);
+ n("\000(\000?\000=\000z\000)\000.\000\000", "\000a\000\000");
+ x2("\000(\000?\000!\000z\000)\000a\000\000", "\000a\000\000", 0, 2);
+ n("\000(\000?\000!\000z\000)\000a\000\000", "\000z\000\000");
+ x2("\000(\000?\000i\000:\000a\000)\000\000", "\000a\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000a\000)\000\000", "\000A\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000A\000)\000\000", "\000a\000\000", 0, 2);
+ n("\000(\000?\000i\000:\000A\000)\000\000", "\000b\000\000");
+ x2("\000(\000?\000i\000:\000[\000A\000-\000Z\000]\000)\000\000", "\000a\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000[\000f\000-\000m\000]\000)\000\000", "\000H\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000[\000f\000-\000m\000]\000)\000\000", "\000h\000\000", 0, 2);
+ n("\000(\000?\000i\000:\000[\000f\000-\000m\000]\000)\000\000", "\000e\000\000");
+ x2("\000(\000?\000i\000:\000[\000A\000-\000c\000]\000)\000\000", "\000D\000\000", 0, 2);
+ n("\000(\000?\000i\000:\000[\000^\000a\000-\000z\000]\000)\000\000", "\000A\000\000");
+ n("\000(\000?\000i\000:\000[\000^\000a\000-\000z\000]\000)\000\000", "\000a\000\000");
+ x2("\000(\000?\000i\000:\000[\000!\000-\000k\000]\000)\000\000", "\000Z\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000[\000!\000-\000k\000]\000)\000\000", "\0007\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000[\000T\000-\000}\000]\000)\000\000", "\000b\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000[\000T\000-\000}\000]\000)\000\000", "\000{\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000\134\000?\000a\000)\000\000", "\000?\000A\000\000", 0, 4);
+ x2("\000(\000?\000i\000:\000\134\000*\000A\000)\000\000", "\000*\000a\000\000", 0, 4);
+ n("\000.\000\000", "\000\012\000\000");
+ x2("\000(\000?\000m\000:\000.\000)\000\000", "\000\012\000\000", 0, 2);
+ x2("\000(\000?\000m\000:\000a\000.\000)\000\000", "\000a\000\012\000\000", 0, 4);
+ x2("\000(\000?\000m\000:\000.\000b\000)\000\000", "\000a\000\012\000b\000\000", 2, 6);
+ x2("\000.\000*\000a\000b\000c\000\000", "\000d\000d\000d\000a\000b\000d\000d\000\012\000d\000d\000a\000b\000c\000\000", 16, 26);
+ x2("\000(\000?\000m\000:\000.\000*\000a\000b\000c\000)\000\000", "\000d\000d\000d\000a\000b\000d\000d\000a\000b\000c\000\000", 0, 20);
+ n("\000(\000?\000i\000)\000(\000?\000-\000i\000)\000a\000\000", "\000A\000\000");
+ n("\000(\000?\000i\000)\000(\000?\000-\000i\000:\000a\000)\000\000", "\000A\000\000");
+ x2("\000a\000?\000\000", "\000\000", 0, 0);
+ x2("\000a\000?\000\000", "\000b\000\000", 0, 0);
+ x2("\000a\000?\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000*\000\000", "\000\000", 0, 0);
+ x2("\000a\000*\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000*\000\000", "\000a\000a\000a\000\000", 0, 6);
+ x2("\000a\000*\000\000", "\000b\000a\000a\000a\000a\000\000", 0, 0);
+ n("\000a\000+\000\000", "\000\000");
+ x2("\000a\000+\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000+\000\000", "\000a\000a\000a\000a\000\000", 0, 8);
+ x2("\000a\000+\000\000", "\000a\000a\000b\000b\000b\000\000", 0, 4);
+ x2("\000a\000+\000\000", "\000b\000a\000a\000a\000a\000\000", 2, 10);
+ x2("\000.\000?\000\000", "\000\000", 0, 0);
+ x2("\000.\000?\000\000", "\000f\000\000", 0, 2);
+ x2("\000.\000?\000\000", "\000\012\000\000", 0, 0);
+ x2("\000.\000*\000\000", "\000\000", 0, 0);
+ x2("\000.\000*\000\000", "\000a\000b\000c\000d\000e\000\000", 0, 10);
+ x2("\000.\000+\000\000", "\000z\000\000", 0, 2);
+ x2("\000.\000+\000\000", "\000z\000d\000s\000w\000e\000r\000\012\000\000", 0, 12);
+ x2("\000(\000.\000*\000)\000a\000\134\0001\000f\000\000", "\000b\000a\000b\000f\000b\000a\000c\000\000", 0, 8);
+ x2("\000(\000.\000*\000)\000a\000\134\0001\000f\000\000", "\000b\000a\000c\000b\000a\000b\000f\000\000", 6, 14);
+ x2("\000(\000(\000.\000*\000)\000a\000\134\0002\000f\000)\000\000", "\000b\000a\000c\000b\000a\000b\000f\000\000", 6, 14);
+ x2("\000(\000.\000*\000)\000a\000\134\0001\000f\000\000", "\000b\000a\000c\000z\000z\000z\000z\000z\000z\000\012\000b\000a\000z\000z\000\012\000z\000z\000z\000z\000b\000a\000b\000f\000\000", 38, 46);
+ x2("\000a\000|\000b\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000|\000b\000\000", "\000b\000\000", 0, 2);
+ x2("\000|\000a\000\000", "\000a\000\000", 0, 0);
+ x2("\000(\000|\000a\000)\000\000", "\000a\000\000", 0, 0);
+ x2("\000a\000b\000|\000b\000c\000\000", "\000a\000b\000\000", 0, 4);
+ x2("\000a\000b\000|\000b\000c\000\000", "\000b\000c\000\000", 0, 4);
+ x2("\000z\000(\000?\000:\000a\000b\000|\000b\000c\000)\000\000", "\000z\000b\000c\000\000", 0, 6);
+ x2("\000a\000(\000?\000:\000a\000b\000|\000b\000c\000)\000c\000\000", "\000a\000a\000b\000c\000\000", 0, 8);
+ x2("\000a\000b\000|\000(\000?\000:\000a\000c\000|\000a\000z\000)\000\000", "\000a\000z\000\000", 0, 4);
+ x2("\000a\000|\000b\000|\000c\000\000", "\000d\000c\000\000", 2, 4);
+ x2("\000a\000|\000b\000|\000c\000d\000|\000e\000f\000g\000|\000h\000|\000i\000j\000k\000|\000l\000m\000n\000|\000o\000|\000p\000q\000|\000r\000s\000t\000u\000v\000w\000x\000|\000y\000z\000\000", "\000p\000q\000r\000\000", 0, 4);
+ n("\000a\000|\000b\000|\000c\000d\000|\000e\000f\000g\000|\000h\000|\000i\000j\000k\000|\000l\000m\000n\000|\000o\000|\000p\000q\000|\000r\000s\000t\000u\000v\000w\000x\000|\000y\000z\000\000", "\000m\000n\000\000");
+ x2("\000a\000|\000^\000z\000\000", "\000b\000a\000\000", 2, 4);
+ x2("\000a\000|\000^\000z\000\000", "\000z\000a\000\000", 0, 2);
+ x2("\000a\000|\000\134\000G\000z\000\000", "\000b\000z\000a\000\000", 4, 6);
+ x2("\000a\000|\000\134\000G\000z\000\000", "\000z\000a\000\000", 0, 2);
+ x2("\000a\000|\000\134\000A\000z\000\000", "\000b\000z\000a\000\000", 4, 6);
+ x2("\000a\000|\000\134\000A\000z\000\000", "\000z\000a\000\000", 0, 2);
+ x2("\000a\000|\000b\000\134\000Z\000\000", "\000b\000a\000\000", 2, 4);
+ x2("\000a\000|\000b\000\134\000Z\000\000", "\000b\000\000", 0, 2);
+ x2("\000a\000|\000b\000\134\000z\000\000", "\000b\000a\000\000", 2, 4);
+ x2("\000a\000|\000b\000\134\000z\000\000", "\000b\000\000", 0, 2);
+ x2("\000\134\000w\000|\000\134\000s\000\000", "\000 \000\000", 0, 2);
+ n("\000\134\000w\000|\000\134\000w\000\000", "\000 \000\000");
+ x2("\000\134\000w\000|\000%\000\000", "\000%\000\000", 0, 2);
+ x2("\000\134\000w\000|\000[\000&\000$\000]\000\000", "\000&\000\000", 0, 2);
+ x2("\000[\000b\000-\000d\000]\000|\000[\000^\000e\000-\000z\000]\000\000", "\000a\000\000", 0, 2);
+ x2("\000(\000?\000:\000a\000|\000[\000c\000-\000f\000]\000)\000|\000b\000z\000\000", "\000d\000z\000\000", 0, 2);
+ x2("\000(\000?\000:\000a\000|\000[\000c\000-\000f\000]\000)\000|\000b\000z\000\000", "\000b\000z\000\000", 0, 4);
+ x2("\000a\000b\000c\000|\000(\000?\000=\000z\000z\000)\000.\000.\000f\000\000", "\000z\000z\000f\000\000", 0, 6);
+ x2("\000a\000b\000c\000|\000(\000?\000!\000z\000z\000)\000.\000.\000f\000\000", "\000a\000b\000f\000\000", 0, 6);
+ x2("\000(\000?\000=\000z\000a\000)\000.\000.\000a\000|\000(\000?\000=\000z\000z\000)\000.\000.\000a\000\000", "\000z\000z\000a\000\000", 0, 6);
+ n("\000(\000?\000>\000a\000|\000a\000b\000d\000)\000c\000\000", "\000a\000b\000d\000c\000\000");
+ x2("\000(\000?\000>\000a\000b\000d\000|\000a\000)\000c\000\000", "\000a\000b\000d\000c\000\000", 0, 8);
+ x2("\000a\000?\000|\000b\000\000", "\000a\000\000", 0, 2);
+ x2("\000a\000?\000|\000b\000\000", "\000b\000\000", 0, 0);
+ x2("\000a\000?\000|\000b\000\000", "\000\000", 0, 0);
+ x2("\000a\000*\000|\000b\000\000", "\000a\000a\000\000", 0, 4);
+ x2("\000a\000*\000|\000b\000*\000\000", "\000b\000a\000\000", 0, 0);
+ x2("\000a\000*\000|\000b\000*\000\000", "\000a\000b\000\000", 0, 2);
+ x2("\000a\000+\000|\000b\000*\000\000", "\000\000", 0, 0);
+ x2("\000a\000+\000|\000b\000*\000\000", "\000b\000b\000b\000\000", 0, 6);
+ x2("\000a\000+\000|\000b\000*\000\000", "\000a\000b\000b\000b\000\000", 0, 2);
+ n("\000a\000+\000|\000b\000+\000\000", "\000\000");
+ x2("\000(\000a\000|\000b\000)\000?\000\000", "\000b\000\000", 0, 2);
+ x2("\000(\000a\000|\000b\000)\000*\000\000", "\000b\000a\000\000", 0, 4);
+ x2("\000(\000a\000|\000b\000)\000+\000\000", "\000b\000a\000b\000\000", 0, 6);
+ x2("\000(\000a\000b\000|\000c\000a\000)\000+\000\000", "\000c\000a\000a\000b\000b\000c\000\000", 0, 8);
+ x2("\000(\000a\000b\000|\000c\000a\000)\000+\000\000", "\000a\000a\000b\000c\000a\000\000", 2, 10);
+ x2("\000(\000a\000b\000|\000c\000a\000)\000+\000\000", "\000a\000b\000z\000c\000a\000\000", 0, 4);
+ x2("\000(\000a\000|\000b\000a\000b\000)\000+\000\000", "\000a\000b\000a\000b\000a\000\000", 0, 10);
+ x2("\000(\000a\000|\000b\000a\000b\000)\000+\000\000", "\000b\000a\000\000", 2, 4);
+ x2("\000(\000a\000|\000b\000a\000b\000)\000+\000\000", "\000b\000a\000a\000a\000b\000a\000\000", 2, 8);
+ x2("\000(\000?\000:\000a\000|\000b\000)\000(\000?\000:\000a\000|\000b\000)\000\000", "\000a\000b\000\000", 0, 4);
+ x2("\000(\000?\000:\000a\000*\000|\000b\000*\000)\000(\000?\000:\000a\000*\000|\000b\000*\000)\000\000", "\000a\000a\000a\000b\000b\000b\000\000", 0, 6);
+ x2("\000(\000?\000:\000a\000*\000|\000b\000*\000)\000(\000?\000:\000a\000+\000|\000b\000+\000)\000\000", "\000a\000a\000a\000b\000b\000b\000\000", 0, 12);
+ x2("\000(\000?\000:\000a\000+\000|\000b\000+\000)\000{\0002\000}\000\000", "\000a\000a\000a\000b\000b\000b\000\000", 0, 12);
+ x2("\000h\000{\0000\000,\000}\000\000", "\000h\000h\000h\000h\000\000", 0, 8);
+ x2("\000(\000?\000:\000a\000+\000|\000b\000+\000)\000{\0001\000,\0002\000}\000\000", "\000a\000a\000a\000b\000b\000b\000\000", 0, 12);
+ n("\000a\000x\000{\0002\000}\000*\000a\000\000", "\0000\000a\000x\000x\000x\000a\0001\000\000");
+ n("\000a\000.\000{\0000\000,\0002\000}\000a\000\000", "\0000\000a\000X\000X\000X\000a\0000\000\000");
+ n("\000a\000.\000{\0000\000,\0002\000}\000?\000a\000\000", "\0000\000a\000X\000X\000X\000a\0000\000\000");
+ n("\000a\000.\000{\0000\000,\0002\000}\000?\000a\000\000", "\0000\000a\000X\000X\000X\000X\000a\0000\000\000");
+ x2("\000^\000a\000{\0002\000,\000}\000?\000a\000$\000\000", "\000a\000a\000a\000\000", 0, 6);
+ x2("\000^\000[\000a\000-\000z\000]\000{\0002\000,\000}\000?\000$\000\000", "\000a\000a\000a\000\000", 0, 6);
+ x2("\000(\000?\000:\000a\000+\000|\000\134\000A\000b\000*\000)\000c\000c\000\000", "\000c\000c\000\000", 0, 4);
+ n("\000(\000?\000:\000a\000+\000|\000\134\000A\000b\000*\000)\000c\000c\000\000", "\000a\000b\000c\000c\000\000");
+ x2("\000(\000?\000:\000^\000a\000+\000|\000b\000+\000)\000*\000c\000\000", "\000a\000a\000b\000b\000b\000a\000b\000c\000\000", 12, 16);
+ x2("\000(\000?\000:\000^\000a\000+\000|\000b\000+\000)\000*\000c\000\000", "\000a\000a\000b\000b\000b\000b\000c\000\000", 0, 14);
+ x2("\000a\000|\000(\000?\000i\000)\000c\000\000", "\000C\000\000", 0, 2);
+ x2("\000(\000?\000i\000)\000c\000|\000a\000\000", "\000C\000\000", 0, 2);
+ x2("\000(\000?\000i\000)\000c\000|\000a\000\000", "\000A\000\000", 0, 2);
+ x2("\000(\000?\000i\000:\000c\000)\000|\000a\000\000", "\000C\000\000", 0, 2);
+ n("\000(\000?\000i\000:\000c\000)\000|\000a\000\000", "\000A\000\000");
+ x2("\000[\000a\000b\000c\000]\000?\000\000", "\000a\000b\000c\000\000", 0, 2);
+ x2("\000[\000a\000b\000c\000]\000*\000\000", "\000a\000b\000c\000\000", 0, 6);
+ x2("\000[\000^\000a\000b\000c\000]\000*\000\000", "\000a\000b\000c\000\000", 0, 0);
+ n("\000[\000^\000a\000b\000c\000]\000+\000\000", "\000a\000b\000c\000\000");
+ x2("\000a\000?\000?\000\000", "\000a\000a\000a\000\000", 0, 0);
+ x2("\000b\000a\000?\000?\000b\000\000", "\000b\000a\000b\000\000", 0, 6);
+ x2("\000a\000*\000?\000\000", "\000a\000a\000a\000\000", 0, 0);
+ x2("\000b\000a\000*\000?\000\000", "\000b\000a\000a\000\000", 0, 2);
+ x2("\000b\000a\000*\000?\000b\000\000", "\000b\000a\000a\000b\000\000", 0, 8);
+ x2("\000a\000+\000?\000\000", "\000a\000a\000a\000\000", 0, 2);
+ x2("\000b\000a\000+\000?\000\000", "\000b\000a\000a\000\000", 0, 4);
+ x2("\000b\000a\000+\000?\000b\000\000", "\000b\000a\000a\000b\000\000", 0, 8);
+ x2("\000(\000?\000:\000a\000?\000)\000?\000?\000\000", "\000a\000\000", 0, 0);
+ x2("\000(\000?\000:\000a\000?\000?\000)\000?\000\000", "\000a\000\000", 0, 0);
+ x2("\000(\000?\000:\000a\000?\000)\000+\000?\000\000", "\000a\000a\000a\000\000", 0, 2);
+ x2("\000(\000?\000:\000a\000+\000)\000?\000?\000\000", "\000a\000a\000a\000\000", 0, 0);
+ x2("\000(\000?\000:\000a\000+\000)\000?\000?\000b\000\000", "\000a\000a\000a\000b\000\000", 0, 8);
+ x2("\000(\000?\000:\000a\000b\000)\000?\000{\0002\000}\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000:\000a\000b\000)\000?\000{\0002\000}\000\000", "\000a\000b\000a\000b\000a\000\000", 0, 8);
+ x2("\000(\000?\000:\000a\000b\000)\000*\000{\0000\000}\000\000", "\000a\000b\000a\000b\000a\000\000", 0, 0);
+ x2("\000(\000?\000:\000a\000b\000)\000{\0003\000,\000}\000\000", "\000a\000b\000a\000b\000a\000b\000a\000b\000\000", 0, 16);
+ n("\000(\000?\000:\000a\000b\000)\000{\0003\000,\000}\000\000", "\000a\000b\000a\000b\000\000");
+ x2("\000(\000?\000:\000a\000b\000)\000{\0002\000,\0004\000}\000\000", "\000a\000b\000a\000b\000a\000b\000\000", 0, 12);
+ x2("\000(\000?\000:\000a\000b\000)\000{\0002\000,\0004\000}\000\000", "\000a\000b\000a\000b\000a\000b\000a\000b\000a\000b\000\000", 0, 16);
+ x2("\000(\000?\000:\000a\000b\000)\000{\0002\000,\0004\000}\000?\000\000", "\000a\000b\000a\000b\000a\000b\000a\000b\000a\000b\000\000", 0, 8);
+ x2("\000(\000?\000:\000a\000b\000)\000{\000,\000}\000\000", "\000a\000b\000{\000,\000}\000\000", 0, 10);
+ x2("\000(\000?\000:\000a\000b\000c\000)\000+\000?\000{\0002\000}\000\000", "\000a\000b\000c\000a\000b\000c\000a\000b\000c\000\000", 0, 12);
+ x2("\000(\000?\000:\000X\000*\000)\000(\000?\000i\000:\000x\000a\000)\000\000", "\000X\000X\000X\000a\000\000", 0, 8);
+ x2("\000(\000d\000+\000)\000(\000[\000^\000a\000b\000c\000]\000z\000)\000\000", "\000d\000d\000d\000z\000\000", 0, 8);
+ x2("\000(\000[\000^\000a\000b\000c\000]\000*\000)\000(\000[\000^\000a\000b\000c\000]\000z\000)\000\000", "\000d\000d\000d\000z\000\000", 0, 8);
+ x2("\000(\000\134\000w\000+\000)\000(\000\134\000w\000z\000)\000\000", "\000d\000d\000d\000z\000\000", 0, 8);
+ x3("\000(\000a\000)\000\000", "\000a\000\000", 0, 2, 1);
+ x3("\000(\000a\000b\000)\000\000", "\000a\000b\000\000", 0, 4, 1);
+ x2("\000(\000(\000a\000b\000)\000)\000\000", "\000a\000b\000\000", 0, 4);
+ x3("\000(\000(\000a\000b\000)\000)\000\000", "\000a\000b\000\000", 0, 4, 1);
+ x3("\000(\000(\000a\000b\000)\000)\000\000", "\000a\000b\000\000", 0, 4, 2);
+ x3("\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000a\000b\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000\000", "\000a\000b\000\000", 0, 4, 20);
+ x3("\000(\000a\000b\000)\000(\000c\000d\000)\000\000", "\000a\000b\000c\000d\000\000", 0, 4, 1);
+ x3("\000(\000a\000b\000)\000(\000c\000d\000)\000\000", "\000a\000b\000c\000d\000\000", 4, 8, 2);
+ x3("\000(\000)\000(\000a\000)\000b\000c\000(\000d\000e\000f\000)\000g\000h\000i\000j\000k\000\000", "\000a\000b\000c\000d\000e\000f\000g\000h\000i\000j\000k\000\000", 6, 12, 3);
+ x3("\000(\000(\000)\000(\000a\000)\000b\000c\000(\000d\000e\000f\000)\000g\000h\000i\000j\000k\000)\000\000", "\000a\000b\000c\000d\000e\000f\000g\000h\000i\000j\000k\000\000", 6, 12, 4);
+ x2("\000(\000^\000a\000)\000\000", "\000a\000\000", 0, 2);
+ x3("\000(\000a\000)\000|\000(\000a\000)\000\000", "\000b\000a\000\000", 2, 4, 1);
+ x3("\000(\000^\000a\000)\000|\000(\000a\000)\000\000", "\000b\000a\000\000", 2, 4, 2);
+ x3("\000(\000a\000?\000)\000\000", "\000a\000a\000a\000\000", 0, 2, 1);
+ x3("\000(\000a\000*\000)\000\000", "\000a\000a\000a\000\000", 0, 6, 1);
+ x3("\000(\000a\000*\000)\000\000", "\000\000", 0, 0, 1);
+ x3("\000(\000a\000+\000)\000\000", "\000a\000a\000a\000a\000a\000a\000a\000\000", 0, 14, 1);
+ x3("\000(\000a\000+\000|\000b\000*\000)\000\000", "\000b\000b\000b\000a\000a\000\000", 0, 6, 1);
+ x3("\000(\000a\000+\000|\000b\000?\000)\000\000", "\000b\000b\000b\000a\000a\000\000", 0, 2, 1);
+ x3("\000(\000a\000b\000c\000)\000?\000\000", "\000a\000b\000c\000\000", 0, 6, 1);
+ x3("\000(\000a\000b\000c\000)\000*\000\000", "\000a\000b\000c\000\000", 0, 6, 1);
+ x3("\000(\000a\000b\000c\000)\000+\000\000", "\000a\000b\000c\000\000", 0, 6, 1);
+ x3("\000(\000x\000y\000z\000|\000a\000b\000c\000)\000+\000\000", "\000a\000b\000c\000\000", 0, 6, 1);
+ x3("\000(\000[\000x\000y\000z\000]\000[\000a\000b\000c\000]\000|\000a\000b\000c\000)\000+\000\000", "\000a\000b\000c\000\000", 0, 6, 1);
+ x3("\000(\000(\000?\000i\000:\000a\000b\000c\000)\000)\000\000", "\000A\000b\000C\000\000", 0, 6, 1);
+ x2("\000(\000a\000b\000c\000)\000(\000?\000i\000:\000\134\0001\000)\000\000", "\000a\000b\000c\000A\000B\000C\000\000", 0, 12);
+ x3("\000(\000(\000?\000m\000:\000a\000.\000c\000)\000)\000\000", "\000a\000\012\000c\000\000", 0, 6, 1);
+ x3("\000(\000(\000?\000=\000a\000z\000)\000a\000)\000\000", "\000a\000z\000b\000\000", 0, 2, 1);
+ x3("\000a\000b\000c\000|\000(\000.\000a\000b\000d\000)\000\000", "\000z\000a\000b\000d\000\000", 0, 8, 1);
+ x2("\000(\000?\000:\000a\000b\000c\000)\000|\000(\000A\000B\000C\000)\000\000", "\000a\000b\000c\000\000", 0, 6);
+ x3("\000(\000?\000i\000:\000(\000a\000b\000c\000)\000)\000|\000(\000z\000z\000z\000)\000\000", "\000A\000B\000C\000\000", 0, 6, 1);
+ x3("\000a\000*\000(\000.\000)\000\000", "\000a\000a\000a\000a\000z\000\000", 8, 10, 1);
+ x3("\000a\000*\000?\000(\000.\000)\000\000", "\000a\000a\000a\000a\000z\000\000", 0, 2, 1);
+ x3("\000a\000*\000?\000(\000c\000)\000\000", "\000a\000a\000a\000a\000c\000\000", 8, 10, 1);
+ x3("\000[\000b\000c\000d\000]\000a\000*\000(\000.\000)\000\000", "\000c\000a\000a\000a\000a\000z\000\000", 10, 12, 1);
+ x3("\000(\000\134\000A\000b\000b\000)\000c\000c\000\000", "\000b\000b\000c\000c\000\000", 0, 4, 1);
+ n("\000(\000\134\000A\000b\000b\000)\000c\000c\000\000", "\000z\000b\000b\000c\000c\000\000");
+ x3("\000(\000^\000b\000b\000)\000c\000c\000\000", "\000b\000b\000c\000c\000\000", 0, 4, 1);
+ n("\000(\000^\000b\000b\000)\000c\000c\000\000", "\000z\000b\000b\000c\000c\000\000");
+ x3("\000c\000c\000(\000b\000b\000$\000)\000\000", "\000c\000c\000b\000b\000\000", 4, 8, 1);
+ n("\000c\000c\000(\000b\000b\000$\000)\000\000", "\000c\000c\000b\000b\000b\000\000");
+ n("\000(\000\134\0001\000)\000\000", "\000\000");
+ n("\000\134\0001\000(\000a\000)\000\000", "\000a\000a\000\000");
+ n("\000(\000a\000(\000b\000)\000\134\0001\000)\000\134\0002\000+\000\000", "\000a\000b\000a\000b\000b\000\000");
+ n("\000(\000?\000:\000(\000?\000:\000\134\0001\000|\000z\000)\000(\000a\000)\000)\000+\000$\000\000", "\000z\000a\000a\000\000");
+ x2("\000(\000?\000:\000(\000?\000:\000\134\0001\000|\000z\000)\000(\000a\000)\000)\000+\000$\000\000", "\000z\000a\000a\000a\000\000", 0, 8);
+ x2("\000(\000a\000)\000(\000?\000=\000\134\0001\000)\000\000", "\000a\000a\000\000", 0, 2);
+ n("\000(\000a\000)\000$\000|\000\134\0001\000\000", "\000a\000z\000\000");
+ x2("\000(\000a\000)\000\134\0001\000\000", "\000a\000a\000\000", 0, 4);
+ n("\000(\000a\000)\000\134\0001\000\000", "\000a\000b\000\000");
+ x2("\000(\000a\000?\000)\000\134\0001\000\000", "\000a\000a\000\000", 0, 4);
+ x2("\000(\000a\000?\000?\000)\000\134\0001\000\000", "\000a\000a\000\000", 0, 0);
+ x2("\000(\000a\000*\000)\000\134\0001\000\000", "\000a\000a\000a\000a\000a\000\000", 0, 8);
+ x3("\000(\000a\000*\000)\000\134\0001\000\000", "\000a\000a\000a\000a\000a\000\000", 0, 4, 1);
+ x2("\000a\000(\000b\000*\000)\000\134\0001\000\000", "\000a\000b\000b\000b\000b\000\000", 0, 10);
+ x2("\000a\000(\000b\000*\000)\000\134\0001\000\000", "\000a\000b\000\000", 0, 2);
+ x2("\000(\000a\000*\000)\000(\000b\000*\000)\000\134\0001\000\134\0002\000\000", "\000a\000a\000a\000b\000b\000a\000a\000a\000b\000b\000\000", 0, 20);
+ x2("\000(\000a\000*\000)\000(\000b\000*\000)\000\134\0002\000\000", "\000a\000a\000a\000b\000b\000b\000b\000\000", 0, 14);
+ x2("\000(\000(\000(\000(\000(\000(\000(\000a\000*\000)\000b\000)\000)\000)\000)\000)\000)\000c\000\134\0007\000\000", "\000a\000a\000a\000b\000c\000a\000a\000a\000\000", 0, 16);
+ x3("\000(\000(\000(\000(\000(\000(\000(\000a\000*\000)\000b\000)\000)\000)\000)\000)\000)\000c\000\134\0007\000\000", "\000a\000a\000a\000b\000c\000a\000a\000a\000\000", 0, 6, 7);
+ x2("\000(\000a\000)\000(\000b\000)\000(\000c\000)\000\134\0002\000\134\0001\000\134\0003\000\000", "\000a\000b\000c\000b\000a\000c\000\000", 0, 12);
+ x2("\000(\000[\000a\000-\000d\000]\000)\000\134\0001\000\000", "\000c\000c\000\000", 0, 4);
+ x2("\000(\000\134\000w\000\134\000d\000\134\000s\000)\000\134\0001\000\000", "\000f\0005\000 \000f\0005\000 \000\000", 0, 12);
+ n("\000(\000\134\000w\000\134\000d\000\134\000s\000)\000\134\0001\000\000", "\000f\0005\000 \000f\0005\000\000");
+ x2("\000(\000w\000h\000o\000|\000[\000a\000-\000c\000]\000{\0003\000}\000)\000\134\0001\000\000", "\000w\000h\000o\000w\000h\000o\000\000", 0, 12);
+ x2("\000.\000.\000.\000(\000w\000h\000o\000|\000[\000a\000-\000c\000]\000{\0003\000}\000)\000\134\0001\000\000", "\000a\000b\000c\000w\000h\000o\000w\000h\000o\000\000", 0, 18);
+ x2("\000(\000w\000h\000o\000|\000[\000a\000-\000c\000]\000{\0003\000}\000)\000\134\0001\000\000", "\000c\000b\000c\000c\000b\000c\000\000", 0, 12);
+ x2("\000(\000^\000a\000)\000\134\0001\000\000", "\000a\000a\000\000", 0, 4);
+ n("\000(\000^\000a\000)\000\134\0001\000\000", "\000b\000a\000a\000\000");
+ n("\000(\000a\000$\000)\000\134\0001\000\000", "\000a\000a\000\000");
+ n("\000(\000a\000b\000\134\000Z\000)\000\134\0001\000\000", "\000a\000b\000\000");
+ x2("\000(\000a\000*\000\134\000Z\000)\000\134\0001\000\000", "\000a\000\000", 2, 2);
+ x2("\000.\000(\000a\000*\000\134\000Z\000)\000\134\0001\000\000", "\000b\000a\000\000", 2, 4);
+ x3("\000(\000.\000(\000a\000b\000c\000)\000\134\0002\000)\000\000", "\000z\000a\000b\000c\000a\000b\000c\000\000", 0, 14, 1);
+ x3("\000(\000.\000(\000.\000.\000\134\000d\000.\000)\000\134\0002\000)\000\000", "\000z\0001\0002\0003\0004\0001\0002\0003\0004\000\000", 0, 18, 1);
+ x2("\000(\000(\000?\000i\000:\000a\000z\000)\000)\000\134\0001\000\000", "\000A\000z\000A\000z\000\000", 0, 8);
+ n("\000(\000(\000?\000i\000:\000a\000z\000)\000)\000\134\0001\000\000", "\000A\000z\000a\000z\000\000");
+ x2("\000(\000?\000<\000=\000a\000)\000b\000\000", "\000a\000b\000\000", 2, 4);
+ n("\000(\000?\000<\000=\000a\000)\000b\000\000", "\000b\000b\000\000");
+ x2("\000(\000?\000<\000=\000a\000|\000b\000)\000b\000\000", "\000b\000b\000\000", 2, 4);
+ x2("\000(\000?\000<\000=\000a\000|\000b\000c\000)\000b\000\000", "\000b\000c\000b\000\000", 4, 6);
+ x2("\000(\000?\000<\000=\000a\000|\000b\000c\000)\000b\000\000", "\000a\000b\000\000", 2, 4);
+ x2("\000(\000?\000<\000=\000a\000|\000b\000c\000|\000|\000d\000e\000f\000g\000h\000i\000j\000|\000k\000l\000m\000n\000o\000p\000q\000|\000r\000)\000z\000\000", "\000r\000z\000\000", 2, 4);
+ x2("\000(\000a\000)\000\134\000g\000<\0001\000>\000\000", "\000a\000a\000\000", 0, 4);
+ x2("\000(\000?\000<\000!\000a\000)\000b\000\000", "\000c\000b\000\000", 2, 4);
+ n("\000(\000?\000<\000!\000a\000)\000b\000\000", "\000a\000b\000\000");
+ x2("\000(\000?\000<\000!\000a\000|\000b\000c\000)\000b\000\000", "\000b\000b\000b\000\000", 0, 2);
+ n("\000(\000?\000<\000!\000a\000|\000b\000c\000)\000z\000\000", "\000b\000c\000z\000\000");
+ x2("\000(\000?\000<\000n\000a\000m\000e\0001\000>\000a\000)\000\000", "\000a\000\000", 0, 2);
+ x2("\000(\000?\000<\000n\000a\000m\000e\000_\0002\000>\000a\000b\000)\000\134\000g\000<\000n\000a\000m\000e\000_\0002\000>\000\000", "\000a\000b\000a\000b\000\000", 0, 8);
+ x2("\000(\000?\000<\000n\000a\000m\000e\000_\0003\000>\000.\000z\000v\000.\000)\000\134\000k\000<\000n\000a\000m\000e\000_\0003\000>\000\000", "\000a\000z\000v\000b\000a\000z\000v\000b\000\000", 0, 16);
+ x2("\000(\000?\000<\000=\000\134\000g\000<\000a\000b\000>\000)\000|\000-\000\134\000z\000E\000N\000D\000 \000(\000?\000<\000a\000b\000>\000X\000y\000Z\000)\000\000", "\000X\000y\000Z\000\000", 6, 6);
+ x2("\000(\000?\000<\000n\000>\000|\000a\000\134\000g\000<\000n\000>\000)\000+\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000<\000n\000>\000|\000\134\000(\000\134\000g\000<\000n\000>\000\134\000)\000)\000+\000$\000\000", "\000(\000)\000(\000(\000)\000)\000\000", 0, 12);
+ x3("\000\134\000g\000<\000n\000>\000(\000?\000<\000n\000>\000.\000)\000{\0000\000}\000\000", "\000X\000\000", 0, 2, 1);
+ x2("\000\134\000g\000<\000n\000>\000(\000a\000b\000c\000|\000d\000f\000(\000?\000<\000n\000>\000.\000Y\000Z\000)\000{\0002\000,\0008\000}\000)\000{\0000\000}\000\000", "\000X\000Y\000Z\000\000", 0, 6);
+ x2("\000\134\000A\000(\000?\000<\000n\000>\000(\000a\000\134\000g\000<\000n\000>\000)\000|\000)\000\134\000z\000\000", "\000a\000a\000a\000a\000\000", 0, 8);
+ x2("\000(\000?\000<\000n\000>\000|\000\134\000g\000<\000m\000>\000\134\000g\000<\000n\000>\000)\000\134\000z\000|\000\134\000z\000E\000N\000D\000 \000(\000?\000<\000m\000>\000a\000|\000(\000b\000)\000\134\000g\000<\000m\000>\000)\000\000", "\000b\000b\000b\000b\000a\000b\000b\000a\000\000", 0, 16);
+ x2("\000(\000?\000<\000n\000a\000m\000e\0001\0002\0004\0000\000>\000\134\000w\000+\000\134\000s\000x\000)\000a\000+\000\134\000k\000<\000n\000a\000m\000e\0001\0002\0004\0000\000>\000\000", "\000 \000 \000f\000g\000 \000x\000a\000a\000a\000a\000a\000a\000a\000a\000f\000g\000 \000x\000\000", 4, 36);
+ x3("\000(\000z\000)\000(\000)\000(\000)\000(\000?\000<\000_\0009\000>\000a\000)\000\134\000g\000<\000_\0009\000>\000\000", "\000z\000a\000a\000\000", 4, 6, 1);
+ x2("\000(\000.\000)\000(\000(\000(\000?\000<\000_\000>\000a\000)\000)\000)\000\134\000k\000<\000_\000>\000\000", "\000z\000a\000a\000\000", 0, 6);
+ x2("\000(\000(\000?\000<\000n\000a\000m\000e\0001\000>\000\134\000d\000)\000|\000(\000?\000<\000n\000a\000m\000e\0002\000>\000\134\000w\000)\000)\000(\000\134\000k\000<\000n\000a\000m\000e\0001\000>\000|\000\134\000k\000<\000n\000a\000m\000e\0002\000>\000)\000\000", "\000f\000f\000\000", 0, 4);
+ x2("\000(\000?\000:\000(\000?\000<\000x\000>\000)\000|\000(\000?\000<\000x\000>\000e\000f\000g\000)\000)\000\134\000k\000<\000x\000>\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000:\000(\000?\000<\000x\000>\000a\000b\000c\000)\000|\000(\000?\000<\000x\000>\000e\000f\000g\000)\000)\000\134\000k\000<\000x\000>\000\000", "\000a\000b\000c\000e\000f\000g\000e\000f\000g\000\000", 6, 18);
+ n("\000(\000?\000:\000(\000?\000<\000x\000>\000a\000b\000c\000)\000|\000(\000?\000<\000x\000>\000e\000f\000g\000)\000)\000\134\000k\000<\000x\000>\000\000", "\000a\000b\000c\000e\000f\000g\000\000");
+ x2("\000(\000?\000:\000(\000?\000<\000n\0001\000>\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000)\000\134\000k\000<\000n\0001\000>\000$\000\000", "\000a\000-\000p\000y\000u\000m\000p\000y\000u\000m\000\000", 4, 20);
+ x3("\000(\000?\000:\000(\000?\000<\000n\0001\000>\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000|\000(\000?\000<\000n\0001\000>\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000.\000)\000)\000\134\000k\000<\000n\0001\000>\000$\000\000", "\000x\000x\000x\000x\000a\000b\000c\000d\000e\000f\000g\000h\000i\000j\000k\000l\000m\000n\000a\000b\000c\000d\000e\000f\000g\000h\000i\000j\000k\000l\000m\000n\000\000", 8, 36, 14);
+ x3("\000(\000?\000<\000n\000a\000m\000e\0001\000>\000)\000(\000?\000<\000n\000a\000m\000e\0002\000>\000)\000(\000?\000<\000n\000a\000m\000e\0003\000>\000)\000(\000?\000<\000n\000a\000m\000e\0004\000>\000)\000(\000?\000<\000n\000a\000m\000e\0005\000>\000)\000(\000?\000<\000n\000a\000m\000e\0006\000>\000)\000(\000?\000<\000n\000a\000m\000e\0007\000>\000)\000(\000?\000<\000n\000a\000m\000e\0008\000>\000)\000(\000?\000<\000n\000a\000m\000e\0009\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0000\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0001\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0002\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0003\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0004\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0005\000>\000)\000(\000?\000<\000n\000a\000m\000e\0001\0006\000>\000a\000a\000a\000)\000(\000?\000<\000n\000a\000m\000e\0001\0007\000>\000)\000$\000\000", "\000a\000a\000a\000\000", 0, 6, 16);
+ x2("\000(\000?\000<\000f\000o\000o\000>\000a\000|\000\134\000(\000\134\000g\000<\000f\000o\000o\000>\000\134\000)\000)\000\000", "\000a\000\000", 0, 2);
+ x2("\000(\000?\000<\000f\000o\000o\000>\000a\000|\000\134\000(\000\134\000g\000<\000f\000o\000o\000>\000\134\000)\000)\000\000", "\000(\000(\000(\000(\000(\000(\000a\000)\000)\000)\000)\000)\000)\000\000", 0, 26);
+ x3("\000(\000?\000<\000f\000o\000o\000>\000a\000|\000\134\000(\000\134\000g\000<\000f\000o\000o\000>\000\134\000)\000)\000\000", "\000(\000(\000(\000(\000(\000(\000(\000(\000a\000)\000)\000)\000)\000)\000)\000)\000)\000\000", 0, 34, 1);
+ x2("\000\134\000g\000<\000b\000a\000r\000>\000|\000\134\000z\000E\000N\000D\000(\000?\000<\000b\000a\000r\000>\000.\000*\000a\000b\000c\000$\000)\000\000", "\000a\000b\000c\000x\000x\000x\000a\000b\000c\000\000", 0, 18);
+ x2("\000\134\000g\000<\0001\000>\000|\000\134\000z\000E\000N\000D\000(\000.\000a\000.\000)\000\000", "\000b\000a\000c\000\000", 0, 6);
+ x3("\000\134\000g\000<\000_\000A\000>\000\134\000g\000<\000_\000A\000>\000|\000\134\000z\000E\000N\000D\000(\000.\000a\000.\000)\000(\000?\000<\000_\000A\000>\000.\000b\000.\000)\000\000", "\000x\000b\000x\000y\000b\000y\000\000", 6, 12, 1);
+ x2("\000\134\000A\000(\000?\000:\000\134\000g\000<\000p\000o\000n\000>\000|\000\134\000g\000<\000p\000a\000n\000>\000|\000\134\000z\000E\000N\000D\000 \000 \000(\000?\000<\000p\000a\000n\000>\000a\000|\000c\000\134\000g\000<\000p\000o\000n\000>\000c\000)\000(\000?\000<\000p\000o\000n\000>\000b\000|\000d\000\134\000g\000<\000p\000a\000n\000>\000d\000)\000)\000$\000\000", "\000c\000d\000c\000b\000c\000d\000c\000\000", 0, 14);
+ x2("\000\134\000A\000(\000?\000<\000n\000>\000|\000a\000\134\000g\000<\000m\000>\000)\000\134\000z\000|\000\134\000z\000E\000N\000D\000 \000(\000?\000<\000m\000>\000\134\000g\000<\000n\000>\000)\000\000", "\000a\000a\000a\000a\000\000", 0, 8);
+ x2("\000(\000?\000<\000n\000>\000(\000a\000|\000b\000\134\000g\000<\000n\000>\000c\000)\000{\0003\000,\0005\000}\000)\000\000", "\000b\000a\000a\000a\000a\000c\000a\000\000", 2, 10);
+ x2("\000(\000?\000<\000n\000>\000(\000a\000|\000b\000\134\000g\000<\000n\000>\000c\000)\000{\0003\000,\0005\000}\000)\000\000", "\000b\000a\000a\000a\000a\000c\000a\000a\000a\000a\000a\000\000", 0, 20);
+ x2("\000(\000?\000<\000p\000a\000r\000e\000>\000\134\000(\000(\000[\000^\000\134\000(\000\134\000)\000]\000+\000+\000|\000\134\000g\000<\000p\000a\000r\000e\000>\000)\000*\000+\000\134\000)\000)\000\000", "\000(\000(\000a\000)\000)\000\000", 0, 10);
+ x2("\000(\000)\000*\000\134\0001\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000:\000(\000)\000|\000(\000)\000)\000*\000\134\0001\000\134\0002\000\000", "\000\000", 0, 0);
+ x3("\000(\000?\000:\000\134\0001\000a\000|\000(\000)\000)\000*\000\000", "\000a\000\000", 0, 0, 1);
+ x2("\000x\000(\000(\000.\000)\000*\000)\000*\000x\000\000", "\0000\000x\0001\000x\0002\000x\0003\000\000", 2, 12);
+ x2("\000x\000(\000(\000.\000)\000*\000)\000*\000x\000(\000?\000i\000:\000\134\0001\000)\000\134\000Z\000\000", "\0000\000x\0001\000x\0002\000x\0001\000X\0002\000\000", 2, 18);
+ x2("\000(\000?\000:\000(\000)\000|\000(\000)\000|\000(\000)\000|\000(\000)\000|\000(\000)\000|\000(\000)\000)\000*\000\134\0002\000\134\0005\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000:\000(\000)\000|\000(\000)\000|\000(\000)\000|\000(\000x\000)\000|\000(\000)\000|\000(\000)\000)\000*\000\134\0002\000b\000\134\0005\000\000", "\000b\000\000", 0, 2);
+ x2("\217\372\000\000", "\217\372\000\000", 0, 2);
+ x2("\000\000", "0B\000\000", 0, 0);
+ x2("0B\000\000", "0B\000\000", 0, 2);
+ n("0D\000\000", "0B\000\000");
+ x2("0F0F\000\000", "0F0F\000\000", 0, 4);
+ x2("0B0D0F\000\000", "0B0D0F\000\000", 0, 6);
+ x2("0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S\000\000", "0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S0S\000\000", 0, 70);
+ x2("0B\000\000", "0D0B\000\000", 2, 4);
+ x2("0D0F\000\000", "0B0D0F\000\000", 2, 6);
+ x2("e\207\000\000", "e\207\000\000", 0, 2);
+ x2("\000.\000\000", "0B\000\000", 0, 2);
+ x2("\000.\000.\000\000", "0K0M\000\000", 0, 4);
+ x2("\000\134\000w\000\000", "0J\000\000", 0, 2);
+ n("\000\134\000W\000\000", "0B\000\000");
+ x2("\000[\000\134\000W\000]\000\000", "0F\000$\000\000", 2, 4);
+ x2("\000\134\000S\000\000", "0]\000\000", 0, 2);
+ x2("\000\134\000S\000\000", "o\042\000\000", 0, 2);
+ x2("\000\134\000b\000\000", "l\027\000 \000\000", 0, 0);
+ x2("\000\134\000b\000\000", "\000 0{\000\000", 2, 2);
+ x2("\000\134\000B\000\000", "0[0]\000 \000\000", 2, 2);
+ x2("\000\134\000B\000\000", "0F\000 \000\000", 4, 4);
+ x2("\000\134\000B\000\000", "\000 0D\000\000", 0, 0);
+ x2("\000[0_0a\000]\000\000", "0a\000\000", 0, 2);
+ n("\000[0j0k\000]\000\000", "0l\000\000");
+ x2("\000[0F\000-0J\000]\000\000", "0H\000\000", 0, 2);
+ n("\000[\000^0Q\000]\000\000", "0Q\000\000");
+ x2("\000[\000\134\000w\000]\000\000", "0m\000\000", 0, 2);
+ n("\000[\000\134\000d\000]\000\000", "0u\000\000");
+ x2("\000[\000\134\000D\000]\000\000", "0o\000\000", 0, 2);
+ n("\000[\000\134\000s\000]\000\000", "0O\000\000");
+ x2("\000[\000\134\000S\000]\000\000", "0x\000\000", 0, 2);
+ x2("\000[\000\134\000w\000\134\000d\000]\000\000", "0\210\000\000", 0, 2);
+ x2("\000[\000\134\000w\000\134\000d\000]\000\000", "\000 \000 \000 0\210\000\000", 6, 8);
+ n("\000\134\000w\233<\216\312\000\000", "\000 \233<\216\312\000\000");
+ x2("\233<\000\134\000W\216\312\000\000", "\233<\000 \216\312\000\000", 0, 6);
+ x2("0B\000.0D\000.0F\000\000", "0B0B0D0D0F\000\000", 0, 10);
+ x2("\000.\000\134\000w0F\000\134\000W\000.\000.0^\000\000", "0H0F0F\000 0F0^0^\000\000", 0, 14);
+ x2("\000\134\000s\000\134\000w0S0S0S\000\000", "\000 0S0S0S0S\000\000", 0, 10);
+ x2("0B0B\000.0Q\000\000", "0B0B0Q0Q\000\000", 0, 8);
+ n("\000.0D\000\000", "0D0H\000\000");
+ x2("\000.0J\000\000", "0J0J\000\000", 0, 4);
+ x2("\000^0B\000\000", "0B\000\000", 0, 2);
+ x2("\000^0\200\000$\000\000", "0\200\000\000", 0, 2);
+ x2("\000^\000\134\000w\000$\000\000", "0k\000\000", 0, 2);
+ x2("\000^\000\134\000w0K0M0O0Q0S\000$\000\000", "\000z0K0M0O0Q0S\000\000", 0, 12);
+ x2("\000^\000\134\000w\000.\000.\000.0F0H0J\000$\000\000", "\000z0B0D0F0F0H0J\000\000", 0, 14);
+ x2("\000\134\000w\000\134\000w\000\134\000s\000\134\000W0J0J0J\000\134\000d\000\000", "\000a0J\000 \000 0J0J0J\0004\000\000", 0, 16);
+ x2("\000\134\000A0_0a0d\000\000", "0_0a0d\000\000", 0, 6);
+ x2("0\2000\2010\202\000\134\000Z\000\000", "0\2000\2010\202\000\000", 0, 6);
+ x2("0K0M0O\000\134\000z\000\000", "0K0M0O\000\000", 0, 6);
+ x2("0K0M0O\000\134\000Z\000\000", "0K0M0O\000\012\000\000", 0, 6);
+ x2("\000\134\000G0}0t\000\000", "0}0t\000\000", 0, 4);
+ n("\000\134\000G0H\000\000", "0F0H0J\000\000");
+ n("0h0f\000\134\000G\000\000", "0h0f\000\000");
+ n("0~0\177\000\134\000A\000\000", "0~0\177\000\000");
+ n("0~\000\134\000A0\177\000\000", "0~0\177\000\000");
+ x2("\000(\000?\000=0[\000)0[\000\000", "0[\000\000", 0, 2);
+ n("\000(\000?\000=0F\000)\000.\000\000", "0D\000\000");
+ x2("\000(\000?\000!0F\000)0K\000\000", "0K\000\000", 0, 2);
+ n("\000(\000?\000!0h\000)0B\000\000", "0h\000\000");
+ x2("\000(\000?\000i\000:0B\000)\000\000", "0B\000\000", 0, 2);
+ x2("\000(\000?\000i\000:0v0y\000)\000\000", "0v0y\000\000", 0, 4);
+ n("\000(\000?\000i\000:0D\000)\000\000", "0F\000\000");
+ x2("\000(\000?\000m\000:0\210\000.\000)\000\000", "0\210\000\012\000\000", 0, 4);
+ x2("\000(\000?\000m\000:\000.0\201\000)\000\000", "0~\000\0120\201\000\000", 2, 6);
+ x2("0B\000?\000\000", "\000\000", 0, 0);
+ x2("Y\011\000?\000\000", "S\026\000\000", 0, 0);
+ x2("Y\011\000?\000\000", "Y\011\000\000", 0, 2);
+ x2("\221\317\000*\000\000", "\000\000", 0, 0);
+ x2("\221\317\000*\000\000", "\221\317\000\000", 0, 2);
+ x2("[P\000*\000\000", "[P[P[P\000\000", 0, 6);
+ x2("\231\254\000*\000\000", "\236\177\231\254\231\254\231\254\231\254\000\000", 0, 0);
+ n("\134q\000+\000\000", "\000\000");
+ x2("l\263\000+\000\000", "l\263\000\000", 0, 2);
+ x2("fB\000+\000\000", "fBfBfBfB\000\000", 0, 8);
+ x2("0H\000+\000\000", "0H0H0F0F0F\000\000", 0, 4);
+ x2("0F\000+\000\000", "0J0F0F0F0F\000\000", 2, 10);
+ x2("\000.\000?\000\000", "0_\000\000", 0, 2);
+ x2("\000.\000*\000\000", "0q0t0w0z\000\000", 0, 8);
+ x2("\000.\000+\000\000", "0\215\000\000", 0, 2);
+ x2("\000.\000+\000\000", "0D0F0H0K\000\012\000\000", 0, 8);
+ x2("0B\000|0D\000\000", "0B\000\000", 0, 2);
+ x2("0B\000|0D\000\000", "0D\000\000", 0, 2);
+ x2("0B0D\000|0D0F\000\000", "0B0D\000\000", 0, 4);
+ x2("0B0D\000|0D0F\000\000", "0D0F\000\000", 0, 4);
+ x2("0\222\000(\000?\000:0K0M\000|0M0O\000)\000\000", "0\2220K0M\000\000", 0, 6);
+ x2("0\222\000(\000?\000:0K0M\000|0M0O\000)0Q\000\000", "0\2220M0O0Q\000\000", 0, 8);
+ x2("0B0D\000|\000(\000?\000:0B0F\000|0B0\222\000)\000\000", "0B0\222\000\000", 0, 4);
+ x2("0B\000|0D\000|0F\000\000", "0H0F\000\000", 2, 4);
+ x2("0B\000|0D\000|0F0H\000|0J0K0M\000|0O\000|0Q0S0U\000|0W0Y0[\000|0]\000|0_0a\000|0d0f0h0j0k\000|0l0m\000\000", "0W0Y0[\000\000", 0, 6);
+ n("0B\000|0D\000|0F0H\000|0J0K0M\000|0O\000|0Q0S0U\000|0W0Y0[\000|0]\000|0_0a\000|0d0f0h0j0k\000|0l0m\000\000", "0Y0[\000\000");
+ x2("0B\000|\000^0\217\000\000", "0v0B\000\000", 2, 4);
+ x2("0B\000|\000^0\222\000\000", "0\2220B\000\000", 0, 2);
+ x2("\233<\000|\000\134\000G\216\312\000\000", "0Q\216\312\233<\000\000", 4, 6);
+ x2("\233<\000|\000\134\000G\216\312\000\000", "\216\312\233<\000\000", 0, 2);
+ x2("\233<\000|\000\134\000A\216\312\000\000", "\000b\216\312\233<\000\000", 4, 6);
+ x2("\233<\000|\000\134\000A\216\312\000\000", "\216\312\000\000", 0, 2);
+ x2("\233<\000|\216\312\000\134\000Z\000\000", "\216\312\233<\000\000", 2, 4);
+ x2("\233<\000|\216\312\000\134\000Z\000\000", "\216\312\000\000", 0, 2);
+ x2("\233<\000|\216\312\000\134\000Z\000\000", "\216\312\000\012\000\000", 0, 2);
+ x2("\233<\000|\216\312\000\134\000z\000\000", "\216\312\233<\000\000", 2, 4);
+ x2("\233<\000|\216\312\000\134\000z\000\000", "\216\312\000\000", 0, 2);
+ x2("\000\134\000w\000|\000\134\000s\000\000", "0J\000\000", 0, 2);
+ x2("\000\134\000w\000|\000%\000\000", "\000%0J\000\000", 0, 2);
+ x2("\000\134\000w\000|\000[\000&\000$\000]\000\000", "0F\000&\000\000", 0, 2);
+ x2("\000[0D\000-0Q\000]\000\000", "0F\000\000", 0, 2);
+ x2("\000[0D\000-0Q\000]\000|\000[\000^0K\000-0S\000]\000\000", "0B\000\000", 0, 2);
+ x2("\000[0D\000-0Q\000]\000|\000[\000^0K\000-0S\000]\000\000", "0K\000\000", 0, 2);
+ x2("\000[\000^0B\000]\000\000", "\000\012\000\000", 0, 2);
+ x2("\000(\000?\000:0B\000|\000[0F\000-0M\000]\000)\000|0D0\222\000\000", "0F0\222\000\000", 0, 2);
+ x2("\000(\000?\000:0B\000|\000[0F\000-0M\000]\000)\000|0D0\222\000\000", "0D0\222\000\000", 0, 4);
+ x2("0B0D0F\000|\000(\000?\000=0Q0Q\000)\000.\000.0{\000\000", "0Q0Q0{\000\000", 0, 6);
+ x2("0B0D0F\000|\000(\000?\000!0Q0Q\000)\000.\000.0{\000\000", "0B0D0{\000\000", 0, 6);
+ x2("\000(\000?\000=0\2220B\000)\000.\000.0B\000|\000(\000?\000=0\2220\222\000)\000.\000.0B\000\000", "0\2220\2220B\000\000", 0, 6);
+ x2("\000(\000?\000<\000=0B\000|0D0F\000)0D\000\000", "0D0F0D\000\000", 4, 6);
+ n("\000(\000?\000>0B\000|0B0D0H\000)0F\000\000", "0B0D0H0F\000\000");
+ x2("\000(\000?\000>0B0D0H\000|0B\000)0F\000\000", "0B0D0H0F\000\000", 0, 8);
+ x2("0B\000?\000|0D\000\000", "0B\000\000", 0, 2);
+ x2("0B\000?\000|0D\000\000", "0D\000\000", 0, 0);
+ x2("0B\000?\000|0D\000\000", "\000\000", 0, 0);
+ x2("0B\000*\000|0D\000\000", "0B0B\000\000", 0, 4);
+ x2("0B\000*\000|0D\000*\000\000", "0D0B\000\000", 0, 0);
+ x2("0B\000*\000|0D\000*\000\000", "0B0D\000\000", 0, 2);
+ x2("\000[\000a0B\000]\000*\000|0D\000*\000\000", "\000a0B0D0D0D\000\000", 0, 4);
+ x2("0B\000+\000|0D\000*\000\000", "\000\000", 0, 0);
+ x2("0B\000+\000|0D\000*\000\000", "0D0D0D\000\000", 0, 6);
+ x2("0B\000+\000|0D\000*\000\000", "0B0D0D0D\000\000", 0, 2);
+ x2("0B\000+\000|0D\000*\000\000", "\000a0B0D0D0D\000\000", 0, 0);
+ n("0B\000+\000|0D\000+\000\000", "\000\000");
+ x2("\000(0B\000|0D\000)\000?\000\000", "0D\000\000", 0, 2);
+ x2("\000(0B\000|0D\000)\000*\000\000", "0D0B\000\000", 0, 4);
+ x2("\000(0B\000|0D\000)\000+\000\000", "0D0B0D\000\000", 0, 6);
+ x2("\000(0B0D\000|0F0B\000)\000+\000\000", "0F0B0B0D0F0H\000\000", 0, 8);
+ x2("\000(0B0D\000|0F0H\000)\000+\000\000", "0F0B0B0D0F0H\000\000", 4, 12);
+ x2("\000(0B0D\000|0F0B\000)\000+\000\000", "0B0B0D0F0B\000\000", 2, 10);
+ x2("\000(0B0D\000|0F0B\000)\000+\000\000", "0B0D0\2220F0B\000\000", 0, 4);
+ x2("\000(0B0D\000|0F0B\000)\000+\000\000", "\000$\000$\000z\000z\000z\000z0B0D0\2220F0B\000\000", 12, 16);
+ x2("\000(0B\000|0D0B0D\000)\000+\000\000", "0B0D0B0D0B\000\000", 0, 10);
+ x2("\000(0B\000|0D0B0D\000)\000+\000\000", "0D0B\000\000", 2, 4);
+ x2("\000(0B\000|0D0B0D\000)\000+\000\000", "0D0B0B0B0D0B\000\000", 2, 8);
+ x2("\000(\000?\000:0B\000|0D\000)\000(\000?\000:0B\000|0D\000)\000\000", "0B0D\000\000", 0, 4);
+ x2("\000(\000?\000:0B\000*\000|0D\000*\000)\000(\000?\000:0B\000*\000|0D\000*\000)\000\000", "0B0B0B0D0D0D\000\000", 0, 6);
+ x2("\000(\000?\000:0B\000*\000|0D\000*\000)\000(\000?\000:0B\000+\000|0D\000+\000)\000\000", "0B0B0B0D0D0D\000\000", 0, 12);
+ x2("\000(\000?\000:0B\000+\000|0D\000+\000)\000{\0002\000}\000\000", "0B0B0B0D0D0D\000\000", 0, 12);
+ x2("\000(\000?\000:0B\000+\000|0D\000+\000)\000{\0001\000,\0002\000}\000\000", "0B0B0B0D0D0D\000\000", 0, 12);
+ x2("\000(\000?\000:0B\000+\000|\000\134\000A0D\000*\000)0F0F\000\000", "0F0F\000\000", 0, 4);
+ n("\000(\000?\000:0B\000+\000|\000\134\000A0D\000*\000)0F0F\000\000", "0B0D0F0F\000\000");
+ x2("\000(\000?\000:\000^0B\000+\000|0D\000+\000)\000*0F\000\000", "0B0B0D0D0D0B0D0F\000\000", 12, 16);
+ x2("\000(\000?\000:\000^0B\000+\000|0D\000+\000)\000*0F\000\000", "0B0B0D0D0D0D0F\000\000", 0, 14);
+ x2("0F\000{\0000\000,\000}\000\000", "0F0F0F0F\000\000", 0, 8);
+ x2("0B\000|\000(\000?\000i\000)\000c\000\000", "\000C\000\000", 0, 2);
+ x2("\000(\000?\000i\000)\000c\000|0B\000\000", "\000C\000\000", 0, 2);
+ x2("\000(\000?\000i\000:0B\000)\000|\000a\000\000", "\000a\000\000", 0, 2);
+ n("\000(\000?\000i\000:0B\000)\000|\000a\000\000", "\000A\000\000");
+ x2("\000[0B0D0F\000]\000?\000\000", "0B0D0F\000\000", 0, 2);
+ x2("\000[0B0D0F\000]\000*\000\000", "0B0D0F\000\000", 0, 6);
+ x2("\000[\000^0B0D0F\000]\000*\000\000", "0B0D0F\000\000", 0, 0);
+ n("\000[\000^0B0D0F\000]\000+\000\000", "0B0D0F\000\000");
+ x2("0B\000?\000?\000\000", "0B0B0B\000\000", 0, 0);
+ x2("0D0B\000?\000?0D\000\000", "0D0B0D\000\000", 0, 6);
+ x2("0B\000*\000?\000\000", "0B0B0B\000\000", 0, 0);
+ x2("0D0B\000*\000?\000\000", "0D0B0B\000\000", 0, 2);
+ x2("0D0B\000*\000?0D\000\000", "0D0B0B0D\000\000", 0, 8);
+ x2("0B\000+\000?\000\000", "0B0B0B\000\000", 0, 2);
+ x2("0D0B\000+\000?\000\000", "0D0B0B\000\000", 0, 4);
+ x2("0D0B\000+\000?0D\000\000", "0D0B0B0D\000\000", 0, 8);
+ x2("\000(\000?\000:Y)\000?\000)\000?\000?\000\000", "Y)\000\000", 0, 0);
+ x2("\000(\000?\000:Y)\000?\000?\000)\000?\000\000", "Y)\000\000", 0, 0);
+ x2("\000(\000?\000:Y\042\000?\000)\000+\000?\000\000", "Y\042Y\042Y\042\000\000", 0, 2);
+ x2("\000(\000?\000:\230\250\000+\000)\000?\000?\000\000", "\230\250\230\250\230\250\000\000", 0, 0);
+ x2("\000(\000?\000:\226\352\000+\000)\000?\000?\227\034\000\000", "\226\352\226\352\226\352\227\034\000\000", 0, 8);
+ x2("\000(\000?\000:0B0D\000)\000?\000{\0002\000}\000\000", "\000\000", 0, 0);
+ x2("\000(\000?\000:\233<\216\312\000)\000?\000{\0002\000}\000\000", "\233<\216\312\233<\216\312\233<\000\000", 0, 8);
+ x2("\000(\000?\000:\233<\216\312\000)\000*\000{\0000\000}\000\000", "\233<\216\312\233<\216\312\233<\000\000", 0, 0);
+ x2("\000(\000?\000:\233<\216\312\000)\000{\0003\000,\000}\000\000", "\233<\216\312\233<\216\312\233<\216\312\233<\216\312\000\000", 0, 16);
+ n("\000(\000?\000:\233<\216\312\000)\000{\0003\000,\000}\000\000", "\233<\216\312\233<\216\312\000\000");
+ x2("\000(\000?\000:\233<\216\312\000)\000{\0002\000,\0004\000}\000\000", "\233<\216\312\233<\216\312\233<\216\312\000\000", 0, 12);
+ x2("\000(\000?\000:\233<\216\312\000)\000{\0002\000,\0004\000}\000\000", "\233<\216\312\233<\216\312\233<\216\312\233<\216\312\233<\216\312\000\000", 0, 16);
+ x2("\000(\000?\000:\233<\216\312\000)\000{\0002\000,\0004\000}\000?\000\000", "\233<\216\312\233<\216\312\233<\216\312\233<\216\312\233<\216\312\000\000", 0, 8);
+ x2("\000(\000?\000:\233<\216\312\000)\000{\000,\000}\000\000", "\233<\216\312\000{\000,\000}\000\000", 0, 10);
+ x2("\000(\000?\000:0K0M0O\000)\000+\000?\000{\0002\000}\000\000", "0K0M0O0K0M0O0K0M0O\000\000", 0, 12);
+ x3("\000(pk\000)\000\000", "pk\000\000", 0, 2, 1);
+ x3("\000(pkl4\000)\000\000", "pkl4\000\000", 0, 4, 1);
+ x2("\000(\000(fB\225\223\000)\000)\000\000", "fB\225\223\000\000", 0, 4);
+ x3("\000(\000(\230\250l4\000)\000)\000\000", "\230\250l4\000\000", 0, 4, 1);
+ x3("\000(\000(f(e\345\000)\000)\000\000", "f(e\345\000\000", 0, 4, 2);
+ x3("\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\000(\221\317[P\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000)\000\000", "\221\317[P\000\000", 0, 4, 20);
+ x3("\000(0B0D\000)\000(0F0H\000)\000\000", "0B0D0F0H\000\000", 0, 4, 1);
+ x3("\000(0B0D\000)\000(0F0H\000)\000\000", "0B0D0F0H\000\000", 4, 8, 2);
+ x3("\000(\000)\000(0B\000)0D0F\000(0H0J0K\000)0M0O0Q0S\000\000", "0B0D0F0H0J0K0M0O0Q0S\000\000", 6, 12, 3);
+ x3("\000(\000(\000)\000(0B\000)0D0F\000(0H0J0K\000)0M0O0Q0S\000)\000\000", "0B0D0F0H0J0K0M0O0Q0S\000\000", 6, 12, 4);
+ x3("\000.\000*\000(0\3250\251\000)0\3630\3730\336\000(0\363\000(\000)0\2670\3450\277\000)0\2440\363\000\000", "0\3250\2510\3630\3730\3360\3630\2670\3450\2770\2440\363\000\000", 10, 18, 2);
+ x2("\000(\000^0B\000)\000\000", "0B\000\000", 0, 2);
+ x3("\000(0B\000)\000|\000(0B\000)\000\000", "0D0B\000\000", 2, 4, 1);
+ x3("\000(\000^0B\000)\000|\000(0B\000)\000\000", "0D0B\000\000", 2, 4, 2);
+ x3("\000(0B\000?\000)\000\000", "0B0B0B\000\000", 0, 2, 1);
+ x3("\000(0~\000*\000)\000\000", "0~0~0~\000\000", 0, 6, 1);
+ x3("\000(0h\000*\000)\000\000", "\000\000", 0, 0, 1);
+ x3("\000(0\213\000+\000)\000\000", "0\2130\2130\2130\2130\2130\2130\213\000\000", 0, 14, 1);
+ x3("\000(0u\000+\000|0x\000*\000)\000\000", "0u0u0u0x0x\000\000", 0, 6, 1);
+ x3("\000(0B\000+\000|0D\000?\000)\000\000", "0D0D0D0B0B\000\000", 0, 2, 1);
+ x3("\000(0B0D0F\000)\000?\000\000", "0B0D0F\000\000", 0, 6, 1);
+ x3("\000(0B0D0F\000)\000*\000\000", "0B0D0F\000\000", 0, 6, 1);
+ x3("\000(0B0D0F\000)\000+\000\000", "0B0D0F\000\000", 0, 6, 1);
+ x3("\000(0U0W0Y\000|0B0D0F\000)\000+\000\000", "0B0D0F\000\000", 0, 6, 1);
+ x3("\000(\000[0j0k0l\000]\000[0K0M0O\000]\000|0K0M0O\000)\000+\000\000", "0K0M0O\000\000", 0, 6, 1);
+ x3("\000(\000(\000?\000i\000:0B0D0F\000)\000)\000\000", "0B0D0F\000\000", 0, 6, 1);
+ x3("\000(\000(\000?\000m\000:0B\000.0F\000)\000)\000\000", "0B\000\0120F\000\000", 0, 6, 1);
+ x3("\000(\000(\000?\000=0B0\223\000)0B\000)\000\000", "0B0\2230D\000\000", 0, 2, 1);
+ x3("0B0D0F\000|\000(\000.0B0D0H\000)\000\000", "0\2230B0D0H\000\000", 0, 8, 1);
+ x3("0B\000*\000(\000.\000)\000\000", "0B0B0B0B0\223\000\000", 8, 10, 1);
+ x3("0B\000*\000?\000(\000.\000)\000\000", "0B0B0B0B0\223\000\000", 0, 2, 1);
+ x3("0B\000*\000?\000(0\223\000)\000\000", "0B0B0B0B0\223\000\000", 8, 10, 1);
+ x3("\000[0D0F0H\000]0B\000*\000(\000.\000)\000\000", "0H0B0B0B0B0\223\000\000", 10, 12, 1);
+ x3("\000(\000\134\000A0D0D\000)0F0F\000\000", "0D0D0F0F\000\000", 0, 4, 1);
+ n("\000(\000\134\000A0D0D\000)0F0F\000\000", "0\2230D0D0F0F\000\000");
+ x3("\000(\000^0D0D\000)0F0F\000\000", "0D0D0F0F\000\000", 0, 4, 1);
+ n("\000(\000^0D0D\000)0F0F\000\000", "0\2230D0D0F0F\000\000");
+ x3("0\2150\215\000(0\2130\213\000$\000)\000\000", "0\2150\2150\2130\213\000\000", 4, 8, 1);
+ n("0\2150\215\000(0\2130\213\000$\000)\000\000", "0\2150\2150\2130\2130\213\000\000");
+ x2("\000(q!\000)\000\134\0001\000\000", "q!q!\000\000", 0, 4);
+ n("\000(q!\000)\000\134\0001\000\000", "q!kf\000\000");
+ x2("\000(zz\000?\000)\000\134\0001\000\000", "zzzz\000\000", 0, 4);
+ x2("\000(zz\000?\000?\000)\000\134\0001\000\000", "zzzz\000\000", 0, 0);
+ x2("\000(zz\000*\000)\000\134\0001\000\000", "zzzzzzzzzz\000\000", 0, 8);
+ x3("\000(zz\000*\000)\000\134\0001\000\000", "zzzzzzzzzz\000\000", 0, 4, 1);
+ x2("0B\000(0D\000*\000)\000\134\0001\000\000", "0B0D0D0D0D\000\000", 0, 10);
+ x2("0B\000(0D\000*\000)\000\134\0001\000\000", "0B0D\000\000", 0, 2);
+ x2("\000(0B\000*\000)\000(0D\000*\000)\000\134\0001\000\134\0002\000\000", "0B0B0B0D0D0B0B0B0D0D\000\000", 0, 20);
+ x2("\000(0B\000*\000)\000(0D\000*\000)\000\134\0002\000\000", "0B0B0B0D0D0D0D\000\000", 0, 14);
+ x3("\000(0B\000*\000)\000(0D\000*\000)\000\134\0002\000\000", "0B0B0B0D0D0D0D\000\000", 6, 10, 2);
+ x2("\000(\000(\000(\000(\000(\000(\000(0}\000*\000)0z\000)\000)\000)\000)\000)\000)0t\000\134\0007\000\000", "0}0}0}0z0t0}0}0}\000\000", 0, 16);
+ x3("\000(\000(\000(\000(\000(\000(\000(0}\000*\000)0z\000)\000)\000)\000)\000)\000)0t\000\134\0007\000\000", "0}0}0}0z0t0}0}0}\000\000", 0, 6, 7);
+ x2("\000(0o\000)\000(0r\000)\000(0u\000)\000\134\0002\000\134\0001\000\134\0003\000\000", "0o0r0u0r0o0u\000\000", 0, 12);
+ x2("\000(\000[0M\000-0Q\000]\000)\000\134\0001\000\000", "0O0O\000\000", 0, 4);
+ x2("\000(\000\134\000w\000\134\000d\000\134\000s\000)\000\134\0001\000\000", "0B\0005\000 0B\0005\000 \000\000", 0, 12);
+ n("\000(\000\134\000w\000\134\000d\000\134\000s\000)\000\134\0001\000\000", "0B\0005\000 0B\0005\000\000");
+ x2("\000(\212\260\377\037\000|\000[0B\000-0F\000]\000{\0003\000}\000)\000\134\0001\000\000", "\212\260\377\037\212\260\377\037\000\000", 0, 8);
+ x2("\000.\000.\000.\000(\212\260\377\037\000|\000[0B\000-0F\000]\000{\0003\000}\000)\000\134\0001\000\000", "0B\000a0B\212\260\377\037\212\260\377\037\000\000", 0, 14);
+ x2("\000(\212\260\377\037\000|\000[0B\000-0F\000]\000{\0003\000}\000)\000\134\0001\000\000", "0F0D0F0F0D0F\000\000", 0, 12);
+ x2("\000(\000^0S\000)\000\134\0001\000\000", "0S0S\000\000", 0, 4);
+ n("\000(\000^0\200\000)\000\134\0001\000\000", "0\2010\2000\200\000\000");
+ n("\000(0B\000$\000)\000\134\0001\000\000", "0B0B\000\000");
+ n("\000(0B0D\000\134\000Z\000)\000\134\0001\000\000", "0B0D\000\000");
+ x2("\000(0B\000*\000\134\000Z\000)\000\134\0001\000\000", "0B\000\000", 2, 2);
+ x2("\000.\000(0B\000*\000\134\000Z\000)\000\134\0001\000\000", "0D0B\000\000", 2, 4);
+ x3("\000(\000.\000(0\2040D0\206\000)\000\134\0002\000)\000\000", "\000z0\2040D0\2060\2040D0\206\000\000", 0, 14, 1);
+ x3("\000(\000.\000(\000.\000.\000\134\000d\000.\000)\000\134\0002\000)\000\000", "0B\0001\0002\0003\0004\0001\0002\0003\0004\000\000", 0, 18, 1);
+ x2("\000(\000(\000?\000i\000:0B\000v0Z\000)\000)\000\134\0001\000\000", "0B\000v0Z0B\000v0Z\000\000", 0, 12);
+ x2("\000(\000?\000<a\0320K\000>Y\011\000|\000\134\000(\000\134\000g\000<a\0320K\000>\000\134\000)\000)\000\000", "\000(\000(\000(\000(\000(\000(Y\011\000)\000)\000)\000)\000)\000)\000\000", 0, 26);
+ x2("\000\134\000A\000(\000?\000:\000\134\000g\000<\226?\000_\0001\000>\000|\000\134\000g\000<N\221\000_\0002\000>\000|\000\134\000z}BN\206\000 \000 \000(\000?\000<\226?\000_\0001\000>\211\263\000|\201\352\000\134\000g\000<N\221\000_\0002\000>\201\352\000)\000(\000?\000<N\221\000_\0002\000>W(\000|\203\351\205\251\000\134\000g\000<\226?\000_\0001\000>\203\351\205\251\000)\000)\000$\000\000", "\203\351\205\251\201\352\203\351\205\251\201\352W(\201\352\203\351\205\251\201\352\203\351\205\251\000\000", 0, 26);
+ x2("\000[\000[0r0u\000]\000]\000\000", "0u\000\000", 0, 2);
+ x2("\000[\000[0D0J0F\000]0K\000]\000\000", "0K\000\000", 0, 2);
+ n("\000[\000[\000^0B\000]\000]\000\000", "0B\000\000");
+ n("\000[\000^\000[0B\000]\000]\000\000", "0B\000\000");
+ x2("\000[\000^\000[\000^0B\000]\000]\000\000", "0B\000\000", 0, 2);
+ x2("\000[\000[0K0M0O\000]\000&\000&0M0O\000]\000\000", "0O\000\000", 0, 2);
+ n("\000[\000[0K0M0O\000]\000&\000&0M0O\000]\000\000", "0K\000\000");
+ n("\000[\000[0K0M0O\000]\000&\000&0M0O\000]\000\000", "0Q\000\000");
+ x2("\000[0B\000-0\223\000&\000&0D\000-0\222\000&\000&0F\000-0\221\000]\000\000", "0\221\000\000", 0, 2);
+ n("\000[\000^0B\000-0\223\000&\000&0D\000-0\222\000&\000&0F\000-0\221\000]\000\000", "0\221\000\000");
+ x2("\000[\000[\000^0B\000&\000&0B\000]\000&\000&0B\000-0\223\000]\000\000", "0D\000\000", 0, 2);
+ n("\000[\000[\000^0B\000&\000&0B\000]\000&\000&0B\000-0\223\000]\000\000", "0B\000\000");
+ x2("\000[\000[\000^0B\000-0\223\000&\000&0D0F0H0J\000]\000&\000&\000[\000^0F\000-0K\000]\000]\000\000", "0M\000\000", 0, 2);
+ n("\000[\000[\000^0B\000-0\223\000&\000&0D0F0H0J\000]\000&\000&\000[\000^0F\000-0K\000]\000]\000\000", "0D\000\000");
+ x2("\000[\000^\000[\000^0B0D0F\000]\000&\000&\000[\000^0F0H0J\000]\000]\000\000", "0F\000\000", 0, 2);
+ x2("\000[\000^\000[\000^0B0D0F\000]\000&\000&\000[\000^0F0H0J\000]\000]\000\000", "0H\000\000", 0, 2);
+ n("\000[\000^\000[\000^0B0D0F\000]\000&\000&\000[\000^0F0H0J\000]\000]\000\000", "0K\000\000");
+ x2("\000[0B\000-\000&\000&\000-0B\000]\000\000", "\000-\000\000", 0, 2);
+ x2("\000[\000^\000[\000^\000a\000-\000z0B0D0F\000]\000&\000&\000[\000^\000b\000c\000d\000e\000f\000g0F0H0J\000]\000q\000-\000w\000]\000\000", "0H\000\000", 0, 2);
+ x2("\000[\000^\000[\000^\000a\000-\000z0B0D0F\000]\000&\000&\000[\000^\000b\000c\000d\000e\000f\000g0F0H0J\000]\000g\000-\000w\000]\000\000", "\000f\000\000", 0, 2);
+ x2("\000[\000^\000[\000^\000a\000-\000z0B0D0F\000]\000&\000&\000[\000^\000b\000c\000d\000e\000f\000g0F0H0J\000]\000g\000-\000w\000]\000\000", "\000g\000\000", 0, 2);
+ n("\000[\000^\000[\000^\000a\000-\000z0B0D0F\000]\000&\000&\000[\000^\000b\000c\000d\000e\000f\000g0F0H0J\000]\000g\000-\000w\000]\000\000", "\0002\000\000");
+ x2("\000a\000<\000b\000>0\3200\3740\2700\3470\3630n0\3000\2460\3630\3550\3740\311\000<\000\134\000/\000b\000>\000\000", "\000a\000<\000b\000>0\3200\3740\2700\3470\3630n0\3000\2460\3630\3550\3740\311\000<\000/\000b\000>\000\000", 0, 40);
+ x2("\000.\000<\000b\000>0\3200\3740\2700\3470\3630n0\3000\2460\3630\3550\3740\311\000<\000\134\000/\000b\000>\000\000", "\000a\000<\000b\000>0\3200\3740\2700\3470\3630n0\3000\2460\3630\3550\3740\311\000<\000/\000b\000>\000\000", 0, 40);
+ x2("\000^\000\\\000p\000{\000K\000a\000t\000a\000k\000a\000n\000a\000}\000$\000\000", "\060\277\000\000", 0, 2);
+ x2("\000\\\000o\000{\0001\0000\0001\000}\000\000", "\000A\000\000", 0, 2);
+ x2("\000\\\000o\000{\0001\0001\0000\0007\0002\0001\000}\000\000", "\221\321\000\000", 0, 2);
+ x2("\000\\\000R\000\000", "\000\015\000\012\000\000", 0, 4); // \R: general newline
+ x2("\000\\\000R\000\000", "\000\012\000\000", 0, 2);
+ x2("\000\\\000R\000\000", "\000\015\000\000", 0, 2);
+ x2("\000\\\000R\000\000", "\000\013\000\000", 0, 2);
+ n("\000\\\000R\000\012\000\000", "\000\015\000\012\000\000");
+ x2("\000\\\000R\000\000", "\x00\x85\000\000", 0, 2);
+ x2("\000\\\000R\000\000", "\x20\x28\000\000", 0, 2);
+ x2("\000\\\000R\000\000", "\x20\x29\000\000", 0, 2);
+ n("\000\\\000R\000\000", "\x20\x2a\000\000");
+
+ x2("\000\\\000w\000\000", "\x01\x00\000\000", 0, 2);
+ n("\000\\\000W\000\000", "\x01\x00\000\000");
+ x2("\000\\\000d\000\000", "\x0b\x66\000\000", 0, 2);
+ n("\000\\\000D\000\000", "\x0b\x66\000\000");
+ x2("\000\\\000s\000\000", "\x20\x01\000\000", 0, 2);
+ n("\000\\\000S\000\000", "\x20\x01\000\000");
+ x2("\000\\\000b\000\000", "\x00\x20\x01\x00\000\000", 2, 2);
+ n("\000\\\000B\000\000", "\x01\x00\000\000");
+ x2("\000\\\000B\000\000", "\x00\x20\000\000", 0, 0);
+ x2("\000[\000[\000:\000g\000r\000a\000p\000h\000:\000]\000]\000\000",
+ "\x0d\x30\000\000", 0, 2);
+ n("\000[\000[\000:\000g\000r\000a\000p\000h\000:\000]\000]\000\000",
+ "\x0a\x00\000\000");
+
+ // extended grapheme cluster
+
+ // CR + LF
+ n("\000.\000\\\000y\000\\\000O\000\000", "\x00\x0d\x00\x0a\000\000");
+ x2("\000.\000\\\000Y\000\\\000O\000\000", "\x00\x0d\x00\x0a\000\000", 0, 4);
+
+ // LATIN SMALL LETTER G, COMBINING DIAERESIS
+ n("\000^\000.\000\\\000y\000.\000$\000\000", "\x00\x67\x03\x08\000\000");
+ x2("\000.\000\\\000Y\000.\000\000", "\x00\x67\x03\x08\000\000", 0, 4);
+ x2("\000\\\000y\000.\000\\\000Y\000.\000\\\000y\000\000",
+ "\x00\x67\x03\x08\000\000", 0, 4);
+ // TAMIL LETTER NA, TAMIL VOWEL SIGN I,
+ x2("\000.\000\\\000Y\000.\000\000", "\x0B\xA8\x0B\xBF\000\000", 0, 4);
+ n("\000.\000\\\000y\000.\000\000", "\x0B\xA8\x0B\xBF\000\000");
+
+ // CR + LF
+ n("\000\\\000X\000\\\000X\000\000", "\x00\x0d\x00\x0a\000\000");
+ x2("\000^\000\\\000X\000$\000\000", "\x00\x0d\x00\x0a\000\000", 0, 4);
+ // LATIN SMALL LETTER G, COMBINING DIAERESIS
+ n("\000\\\000X\000\\\000X\000\000", "\x00\x67\x03\x08\000\000");
+ x2("\000^\000\\\000X\000$\000\000", "\x00\x67\x03\x08\000\000", 0, 4);
+ // TAMIL LETTER NA, TAMIL VOWEL SIGN I,
+ x2("\000^\000\\\000X\000$\000\000", "\x0B\xA8\x0B\xBF\000\000", 0, 4);
+ n("\000\\\000X\000\\\000X\000\000", "\x0B\xA8\x0B\xBF\000\000");
+
+
+ fprintf(stdout,
+ "\nRESULT SUCC: %4d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+#ifndef POSIX_TEST
+ onig_region_free(region, 1);
+ onig_end();
+#endif
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/windows/testc.c b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/windows/testc.c
new file mode 100644
index 000000000..b657682a6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/oniguruma/windows/testc.c
@@ -0,0 +1,865 @@
+/*
+ * This program was generated by testconv.rb.
+ */
+#ifdef ONIG_ESCAPE_UCHAR_COLLISION
+#undef ONIG_ESCAPE_UCHAR_COLLISION
+#endif
+#include <stdio.h>
+
+#ifdef POSIX_TEST
+#include "onigposix.h"
+#else
+#include "oniguruma.h"
+#endif
+
+#include <string.h>
+
+#define SLEN(s) strlen(s)
+
+static int nsucc = 0;
+static int nfail = 0;
+static int nerror = 0;
+
+static FILE* err_file;
+
+#ifndef POSIX_TEST
+static OnigRegion* region;
+#endif
+
+static void xx(char* pattern, char* str, int from, int to, int mem, int not)
+{
+ int r;
+
+#ifdef POSIX_TEST
+ regex_t reg;
+ char buf[200];
+ regmatch_t pmatch[25];
+
+ r = regcomp(&reg, pattern, REG_EXTENDED | REG_NEWLINE);
+ if (r) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ r = regexec(&reg, str, reg.re_nsub + 1, pmatch, 0);
+ if (r != 0 && r != REG_NOMATCH) {
+ regerror(r, &reg, buf, sizeof(buf));
+ fprintf(err_file, "ERROR: %s\n", buf);
+ nerror++;
+ return ;
+ }
+
+ if (r == REG_NOMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (pmatch[mem].rm_so == from && pmatch[mem].rm_eo == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, pmatch[mem].rm_so, pmatch[mem].rm_eo);
+ nfail++;
+ }
+ }
+ }
+ regfree(&reg);
+
+#else
+ regex_t* reg;
+ OnigErrorInfo einfo;
+
+ r = onig_new(&reg, (UChar* )pattern, (UChar* )(pattern + SLEN(pattern)),
+ ONIG_OPTION_DEFAULT, ONIG_ENCODING_SJIS, ONIG_SYNTAX_DEFAULT, &einfo);
+ if (r) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r, &einfo);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ r = onig_search(reg, (UChar* )str, (UChar* )(str + SLEN(str)),
+ (UChar* )str, (UChar* )(str + SLEN(str)),
+ region, ONIG_OPTION_NONE);
+ if (r < ONIG_MISMATCH) {
+ char s[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str((UChar* )s, r);
+ fprintf(err_file, "ERROR: %s\n", s);
+ nerror++;
+ return ;
+ }
+
+ if (r == ONIG_MISMATCH) {
+ if (not) {
+ fprintf(stdout, "OK(N): /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ }
+ else {
+ if (not) {
+ fprintf(stdout, "FAIL(N): /%s/ '%s'\n", pattern, str);
+ nfail++;
+ }
+ else {
+ if (region->beg[mem] == from && region->end[mem] == to) {
+ fprintf(stdout, "OK: /%s/ '%s'\n", pattern, str);
+ nsucc++;
+ }
+ else {
+ fprintf(stdout, "FAIL: /%s/ '%s' %d-%d : %d-%d\n", pattern, str,
+ from, to, region->beg[mem], region->end[mem]);
+ nfail++;
+ }
+ }
+ }
+ onig_free(reg);
+#endif
+}
+
+static void x2(char* pattern, char* str, int from, int to)
+{
+ xx(pattern, str, from, to, 0, 0);
+}
+
+static void x3(char* pattern, char* str, int from, int to, int mem)
+{
+ xx(pattern, str, from, to, mem, 0);
+}
+
+static void n(char* pattern, char* str)
+{
+ xx(pattern, str, 0, 0, 0, 1);
+}
+
+extern int main(int argc, char* argv[])
+{
+#ifndef POSIX_TEST
+ static OnigEncoding use_encs[1];
+
+ use_encs[0] = ONIG_ENCODING_SJIS;
+ onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
+#endif
+
+ err_file = stdout;
+
+#ifdef POSIX_TEST
+ reg_set_encoding(REG_POSIX_ENCODING_SJIS);
+#else
+ region = onig_region_new();
+#endif
+
+ x2("", "", 0, 0);
+ x2("^", "", 0, 0);
+ x2("$", "", 0, 0);
+ x2("\\G", "", 0, 0);
+ x2("\\A", "", 0, 0);
+ x2("\\Z", "", 0, 0);
+ x2("\\z", "", 0, 0);
+ x2("^$", "", 0, 0);
+ x2("\\ca", "\001", 0, 1);
+ x2("\\C-b", "\002", 0, 1);
+ x2("\\c\\\\", "\034", 0, 1);
+ x2("q[\\c\\\\]", "q\034", 0, 2);
+ x2("", "a", 0, 0);
+ x2("a", "a", 0, 1);
+ x2("\\x61", "a", 0, 1);
+ x2("aa", "aa", 0, 2);
+ x2("aaa", "aaa", 0, 3);
+ x2("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 35);
+ x2("ab", "ab", 0, 2);
+ x2("b", "ab", 1, 2);
+ x2("bc", "abc", 1, 3);
+ x2("(?i:#RET#)", "#INS##RET#", 5, 10);
+ x2("\\17", "\017", 0, 1);
+ x2("\\x1f", "\x1f", 0, 1);
+ x2("a(?#....\\\\JJJJ)b", "ab", 0, 2);
+ x2("(?x) G (o O(?-x)oO) g L", "GoOoOgLe", 0, 7);
+ x2(".", "a", 0, 1);
+ n(".", "");
+ x2("..", "ab", 0, 2);
+ x2("\\w", "e", 0, 1);
+ n("\\W", "e");
+ x2("\\s", " ", 0, 1);
+ x2("\\S", "b", 0, 1);
+ x2("\\d", "4", 0, 1);
+ n("\\D", "4");
+ x2("\\b", "z ", 0, 0);
+ x2("\\b", " z", 1, 1);
+ x2("\\B", "zz ", 1, 1);
+ x2("\\B", "z ", 2, 2);
+ x2("\\B", " z", 0, 0);
+ x2("[ab]", "b", 0, 1);
+ n("[ab]", "c");
+ x2("[a-z]", "t", 0, 1);
+ n("[^a]", "a");
+ x2("[^a]", "\n", 0, 1);
+ x2("[]]", "]", 0, 1);
+ n("[^]]", "]");
+ x2("[\\^]+", "0^^1", 1, 3);
+ x2("[b-]", "b", 0, 1);
+ x2("[b-]", "-", 0, 1);
+ x2("[\\w]", "z", 0, 1);
+ n("[\\w]", " ");
+ x2("[\\W]", "b$", 1, 2);
+ x2("[\\d]", "5", 0, 1);
+ n("[\\d]", "e");
+ x2("[\\D]", "t", 0, 1);
+ n("[\\D]", "3");
+ x2("[\\s]", " ", 0, 1);
+ n("[\\s]", "a");
+ x2("[\\S]", "b", 0, 1);
+ n("[\\S]", " ");
+ x2("[\\w\\d]", "2", 0, 1);
+ n("[\\w\\d]", " ");
+ x2("[[:upper:]]", "B", 0, 1);
+ x2("[*[:xdigit:]+]", "+", 0, 1);
+ x2("[*[:xdigit:]+]", "GHIKK-9+*", 6, 7);
+ x2("[*[:xdigit:]+]", "-@^+", 3, 4);
+ n("[[:upper]]", "A");
+ x2("[[:upper]]", ":", 0, 1);
+ x2("[\\044-\\047]", "\046", 0, 1);
+ x2("[\\x5a-\\x5c]", "\x5b", 0, 1);
+ x2("[\\x6A-\\x6D]", "\x6c", 0, 1);
+ n("[\\x6A-\\x6D]", "\x6E");
+ n("^[0-9A-F]+ 0+ UNDEF ", "75F 00000000 SECT14A notype () External | _rb_apply");
+ x2("[\\[]", "[", 0, 1);
+ x2("[\\]]", "]", 0, 1);
+ x2("[&]", "&", 0, 1);
+ x2("[[ab]]", "b", 0, 1);
+ x2("[[ab]c]", "c", 0, 1);
+ n("[[^a]]", "a");
+ n("[^[a]]", "a");
+ x2("[[ab]&&bc]", "b", 0, 1);
+ n("[[ab]&&bc]", "a");
+ n("[[ab]&&bc]", "c");
+ x2("[a-z&&b-y&&c-x]", "w", 0, 1);
+ n("[^a-z&&b-y&&c-x]", "w");
+ x2("[[^a&&a]&&a-z]", "b", 0, 1);
+ n("[[^a&&a]&&a-z]", "a");
+ x2("[[^a-z&&bcdef]&&[^c-g]]", "h", 0, 1);
+ n("[[^a-z&&bcdef]&&[^c-g]]", "c");
+ x2("[^[^abc]&&[^cde]]", "c", 0, 1);
+ x2("[^[^abc]&&[^cde]]", "e", 0, 1);
+ n("[^[^abc]&&[^cde]]", "f");
+ x2("[a-&&-a]", "-", 0, 1);
+ n("[a\\-&&\\-a]", "&");
+ n("\\wabc", " abc");
+ x2("a\\Wbc", "a bc", 0, 4);
+ x2("a.b.c", "aabbc", 0, 5);
+ x2(".\\wb\\W..c", "abb bcc", 0, 7);
+ x2("\\s\\wzzz", " zzzz", 0, 5);
+ x2("aa.b", "aabb", 0, 4);
+ n(".a", "ab");
+ x2(".a", "aa", 0, 2);
+ x2("^a", "a", 0, 1);
+ x2("^a$", "a", 0, 1);
+ x2("^\\w$", "a", 0, 1);
+ n("^\\w$", " ");
+ x2("^\\wab$", "zab", 0, 3);
+ x2("^\\wabcdef$", "zabcdef", 0, 7);
+ x2("^\\w...def$", "zabcdef", 0, 7);
+ x2("\\w\\w\\s\\Waaa\\d", "aa aaa4", 0, 8);
+ x2("\\A\\Z", "", 0, 0);
+ x2("\\Axyz", "xyz", 0, 3);
+ x2("xyz\\Z", "xyz", 0, 3);
+ x2("xyz\\z", "xyz", 0, 3);
+ x2("a\\Z", "a", 0, 1);
+ x2("\\Gaz", "az", 0, 2);
+ n("\\Gz", "bza");
+ n("az\\G", "az");
+ n("az\\A", "az");
+ n("a\\Az", "az");
+ x2("\\^\\$", "^$", 0, 2);
+ x2("^x?y", "xy", 0, 2);
+ x2("^(x?y)", "xy", 0, 2);
+ x2("\\w", "_", 0, 1);
+ n("\\W", "_");
+ x2("(?=z)z", "z", 0, 1);
+ n("(?=z).", "a");
+ x2("(?!z)a", "a", 0, 1);
+ n("(?!z)a", "z");
+ x2("(?i:a)", "a", 0, 1);
+ x2("(?i:a)", "A", 0, 1);
+ x2("(?i:A)", "a", 0, 1);
+ n("(?i:A)", "b");
+ x2("(?i:[A-Z])", "a", 0, 1);
+ x2("(?i:[f-m])", "H", 0, 1);
+ x2("(?i:[f-m])", "h", 0, 1);
+ n("(?i:[f-m])", "e");
+ x2("(?i:[A-c])", "D", 0, 1);
+ n("(?i:[^a-z])", "A");
+ n("(?i:[^a-z])", "a");
+ x2("(?i:[!-k])", "Z", 0, 1);
+ x2("(?i:[!-k])", "7", 0, 1);
+ x2("(?i:[T-}])", "b", 0, 1);
+ x2("(?i:[T-}])", "{", 0, 1);
+ x2("(?i:\\?a)", "?A", 0, 2);
+ x2("(?i:\\*A)", "*a", 0, 2);
+ n(".", "\n");
+ x2("(?m:.)", "\n", 0, 1);
+ x2("(?m:a.)", "a\n", 0, 2);
+ x2("(?m:.b)", "a\nb", 1, 3);
+ x2(".*abc", "dddabdd\nddabc", 8, 13);
+ x2("(?m:.*abc)", "dddabddabc", 0, 10);
+ n("(?i)(?-i)a", "A");
+ n("(?i)(?-i:a)", "A");
+ x2("a?", "", 0, 0);
+ x2("a?", "b", 0, 0);
+ x2("a?", "a", 0, 1);
+ x2("a*", "", 0, 0);
+ x2("a*", "a", 0, 1);
+ x2("a*", "aaa", 0, 3);
+ x2("a*", "baaaa", 0, 0);
+ n("a+", "");
+ x2("a+", "a", 0, 1);
+ x2("a+", "aaaa", 0, 4);
+ x2("a+", "aabbb", 0, 2);
+ x2("a+", "baaaa", 1, 5);
+ x2(".?", "", 0, 0);
+ x2(".?", "f", 0, 1);
+ x2(".?", "\n", 0, 0);
+ x2(".*", "", 0, 0);
+ x2(".*", "abcde", 0, 5);
+ x2(".+", "z", 0, 1);
+ x2(".+", "zdswer\n", 0, 6);
+ x2("(.*)a\\1f", "babfbac", 0, 4);
+ x2("(.*)a\\1f", "bacbabf", 3, 7);
+ x2("((.*)a\\2f)", "bacbabf", 3, 7);
+ x2("(.*)a\\1f", "baczzzzzz\nbazz\nzzzzbabf", 19, 23);
+ x2("a|b", "a", 0, 1);
+ x2("a|b", "b", 0, 1);
+ x2("|a", "a", 0, 0);
+ x2("(|a)", "a", 0, 0);
+ x2("ab|bc", "ab", 0, 2);
+ x2("ab|bc", "bc", 0, 2);
+ x2("z(?:ab|bc)", "zbc", 0, 3);
+ x2("a(?:ab|bc)c", "aabc", 0, 4);
+ x2("ab|(?:ac|az)", "az", 0, 2);
+ x2("a|b|c", "dc", 1, 2);
+ x2("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "pqr", 0, 2);
+ n("a|b|cd|efg|h|ijk|lmn|o|pq|rstuvwx|yz", "mn");
+ x2("a|^z", "ba", 1, 2);
+ x2("a|^z", "za", 0, 1);
+ x2("a|\\Gz", "bza", 2, 3);
+ x2("a|\\Gz", "za", 0, 1);
+ x2("a|\\Az", "bza", 2, 3);
+ x2("a|\\Az", "za", 0, 1);
+ x2("a|b\\Z", "ba", 1, 2);
+ x2("a|b\\Z", "b", 0, 1);
+ x2("a|b\\z", "ba", 1, 2);
+ x2("a|b\\z", "b", 0, 1);
+ x2("\\w|\\s", " ", 0, 1);
+ n("\\w|\\w", " ");
+ x2("\\w|%", "%", 0, 1);
+ x2("\\w|[&$]", "&", 0, 1);
+ x2("[b-d]|[^e-z]", "a", 0, 1);
+ x2("(?:a|[c-f])|bz", "dz", 0, 1);
+ x2("(?:a|[c-f])|bz", "bz", 0, 2);
+ x2("abc|(?=zz)..f", "zzf", 0, 3);
+ x2("abc|(?!zz)..f", "abf", 0, 3);
+ x2("(?=za)..a|(?=zz)..a", "zza", 0, 3);
+ n("(?>a|abd)c", "abdc");
+ x2("(?>abd|a)c", "abdc", 0, 4);
+ x2("a?|b", "a", 0, 1);
+ x2("a?|b", "b", 0, 0);
+ x2("a?|b", "", 0, 0);
+ x2("a*|b", "aa", 0, 2);
+ x2("a*|b*", "ba", 0, 0);
+ x2("a*|b*", "ab", 0, 1);
+ x2("a+|b*", "", 0, 0);
+ x2("a+|b*", "bbb", 0, 3);
+ x2("a+|b*", "abbb", 0, 1);
+ n("a+|b+", "");
+ x2("(a|b)?", "b", 0, 1);
+ x2("(a|b)*", "ba", 0, 2);
+ x2("(a|b)+", "bab", 0, 3);
+ x2("(ab|ca)+", "caabbc", 0, 4);
+ x2("(ab|ca)+", "aabca", 1, 5);
+ x2("(ab|ca)+", "abzca", 0, 2);
+ x2("(a|bab)+", "ababa", 0, 5);
+ x2("(a|bab)+", "ba", 1, 2);
+ x2("(a|bab)+", "baaaba", 1, 4);
+ x2("(?:a|b)(?:a|b)", "ab", 0, 2);
+ x2("(?:a*|b*)(?:a*|b*)", "aaabbb", 0, 3);
+ x2("(?:a*|b*)(?:a+|b+)", "aaabbb", 0, 6);
+ x2("(?:a+|b+){2}", "aaabbb", 0, 6);
+ x2("h{0,}", "hhhh", 0, 4);
+ x2("(?:a+|b+){1,2}", "aaabbb", 0, 6);
+ n("ax{2}*a", "0axxxa1");
+ n("a.{0,2}a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXa0");
+ n("a.{0,2}?a", "0aXXXXa0");
+ x2("^a{2,}?a$", "aaa", 0, 3);
+ x2("^[a-z]{2,}?$", "aaa", 0, 3);
+ x2("(?:a+|\\Ab*)cc", "cc", 0, 2);
+ n("(?:a+|\\Ab*)cc", "abcc");
+ x2("(?:^a+|b+)*c", "aabbbabc", 6, 8);
+ x2("(?:^a+|b+)*c", "aabbbbc", 0, 7);
+ x2("a|(?i)c", "C", 0, 1);
+ x2("(?i)c|a", "C", 0, 1);
+ x2("(?i)c|a", "A", 0, 1);
+ x2("(?i:c)|a", "C", 0, 1);
+ n("(?i:c)|a", "A");
+ x2("[abc]?", "abc", 0, 1);
+ x2("[abc]*", "abc", 0, 3);
+ x2("[^abc]*", "abc", 0, 0);
+ n("[^abc]+", "abc");
+ x2("a?\?", "aaa", 0, 0);
+ x2("ba?\?b", "bab", 0, 3);
+ x2("a*?", "aaa", 0, 0);
+ x2("ba*?", "baa", 0, 1);
+ x2("ba*?b", "baab", 0, 4);
+ x2("a+?", "aaa", 0, 1);
+ x2("ba+?", "baa", 0, 2);
+ x2("ba+?b", "baab", 0, 4);
+ x2("(?:a?)?\?", "a", 0, 0);
+ x2("(?:a?\?)?", "a", 0, 0);
+ x2("(?:a?)+?", "aaa", 0, 1);
+ x2("(?:a+)?\?", "aaa", 0, 0);
+ x2("(?:a+)?\?b", "aaab", 0, 4);
+ x2("(?:ab)?{2}", "", 0, 0);
+ x2("(?:ab)?{2}", "ababa", 0, 4);
+ x2("(?:ab)*{0}", "ababa", 0, 0);
+ x2("(?:ab){3,}", "abababab", 0, 8);
+ n("(?:ab){3,}", "abab");
+ x2("(?:ab){2,4}", "ababab", 0, 6);
+ x2("(?:ab){2,4}", "ababababab", 0, 8);
+ x2("(?:ab){2,4}?", "ababababab", 0, 4);
+ x2("(?:ab){,}", "ab{,}", 0, 5);
+ x2("(?:abc)+?{2}", "abcabcabc", 0, 6);
+ x2("(?:X*)(?i:xa)", "XXXa", 0, 4);
+ x2("(d+)([^abc]z)", "dddz", 0, 4);
+ x2("([^abc]*)([^abc]z)", "dddz", 0, 4);
+ x2("(\\w+)(\\wz)", "dddz", 0, 4);
+ x3("(a)", "a", 0, 1, 1);
+ x3("(ab)", "ab", 0, 2, 1);
+ x2("((ab))", "ab", 0, 2);
+ x3("((ab))", "ab", 0, 2, 1);
+ x3("((ab))", "ab", 0, 2, 2);
+ x3("((((((((((((((((((((ab))))))))))))))))))))", "ab", 0, 2, 20);
+ x3("(ab)(cd)", "abcd", 0, 2, 1);
+ x3("(ab)(cd)", "abcd", 2, 4, 2);
+ x3("()(a)bc(def)ghijk", "abcdefghijk", 3, 6, 3);
+ x3("(()(a)bc(def)ghijk)", "abcdefghijk", 3, 6, 4);
+ x2("(^a)", "a", 0, 1);
+ x3("(a)|(a)", "ba", 1, 2, 1);
+ x3("(^a)|(a)", "ba", 1, 2, 2);
+ x3("(a?)", "aaa", 0, 1, 1);
+ x3("(a*)", "aaa", 0, 3, 1);
+ x3("(a*)", "", 0, 0, 1);
+ x3("(a+)", "aaaaaaa", 0, 7, 1);
+ x3("(a+|b*)", "bbbaa", 0, 3, 1);
+ x3("(a+|b?)", "bbbaa", 0, 1, 1);
+ x3("(abc)?", "abc", 0, 3, 1);
+ x3("(abc)*", "abc", 0, 3, 1);
+ x3("(abc)+", "abc", 0, 3, 1);
+ x3("(xyz|abc)+", "abc", 0, 3, 1);
+ x3("([xyz][abc]|abc)+", "abc", 0, 3, 1);
+ x3("((?i:abc))", "AbC", 0, 3, 1);
+ x2("(abc)(?i:\\1)", "abcABC", 0, 6);
+ x3("((?m:a.c))", "a\nc", 0, 3, 1);
+ x3("((?=az)a)", "azb", 0, 1, 1);
+ x3("abc|(.abd)", "zabd", 0, 4, 1);
+ x2("(?:abc)|(ABC)", "abc", 0, 3);
+ x3("(?i:(abc))|(zzz)", "ABC", 0, 3, 1);
+ x3("a*(.)", "aaaaz", 4, 5, 1);
+ x3("a*?(.)", "aaaaz", 0, 1, 1);
+ x3("a*?(c)", "aaaac", 4, 5, 1);
+ x3("[bcd]a*(.)", "caaaaz", 5, 6, 1);
+ x3("(\\Abb)cc", "bbcc", 0, 2, 1);
+ n("(\\Abb)cc", "zbbcc");
+ x3("(^bb)cc", "bbcc", 0, 2, 1);
+ n("(^bb)cc", "zbbcc");
+ x3("cc(bb$)", "ccbb", 2, 4, 1);
+ n("cc(bb$)", "ccbbb");
+ n("(\\1)", "");
+ n("\\1(a)", "aa");
+ n("(a(b)\\1)\\2+", "ababb");
+ n("(?:(?:\\1|z)(a))+$", "zaa");
+ x2("(?:(?:\\1|z)(a))+$", "zaaa", 0, 4);
+ x2("(a)(?=\\1)", "aa", 0, 1);
+ n("(a)$|\\1", "az");
+ x2("(a)\\1", "aa", 0, 2);
+ n("(a)\\1", "ab");
+ x2("(a?)\\1", "aa", 0, 2);
+ x2("(a?\?)\\1", "aa", 0, 0);
+ x2("(a*)\\1", "aaaaa", 0, 4);
+ x3("(a*)\\1", "aaaaa", 0, 2, 1);
+ x2("a(b*)\\1", "abbbb", 0, 5);
+ x2("a(b*)\\1", "ab", 0, 1);
+ x2("(a*)(b*)\\1\\2", "aaabbaaabb", 0, 10);
+ x2("(a*)(b*)\\2", "aaabbbb", 0, 7);
+ x2("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 8);
+ x3("(((((((a*)b))))))c\\7", "aaabcaaa", 0, 3, 7);
+ x2("(a)(b)(c)\\2\\1\\3", "abcbac", 0, 6);
+ x2("([a-d])\\1", "cc", 0, 2);
+ x2("(\\w\\d\\s)\\1", "f5 f5 ", 0, 6);
+ n("(\\w\\d\\s)\\1", "f5 f5");
+ x2("(who|[a-c]{3})\\1", "whowho", 0, 6);
+ x2("...(who|[a-c]{3})\\1", "abcwhowho", 0, 9);
+ x2("(who|[a-c]{3})\\1", "cbccbc", 0, 6);
+ x2("(^a)\\1", "aa", 0, 2);
+ n("(^a)\\1", "baa");
+ n("(a$)\\1", "aa");
+ n("(ab\\Z)\\1", "ab");
+ x2("(a*\\Z)\\1", "a", 1, 1);
+ x2(".(a*\\Z)\\1", "ba", 1, 2);
+ x3("(.(abc)\\2)", "zabcabc", 0, 7, 1);
+ x3("(.(..\\d.)\\2)", "z12341234", 0, 9, 1);
+ x2("((?i:az))\\1", "AzAz", 0, 4);
+ n("((?i:az))\\1", "Azaz");
+ x2("(?<=a)b", "ab", 1, 2);
+ n("(?<=a)b", "bb");
+ x2("(?<=a|b)b", "bb", 1, 2);
+ x2("(?<=a|bc)b", "bcb", 2, 3);
+ x2("(?<=a|bc)b", "ab", 1, 2);
+ x2("(?<=a|bc||defghij|klmnopq|r)z", "rz", 1, 2);
+ x2("(a)\\g<1>", "aa", 0, 2);
+ x2("(?<!a)b", "cb", 1, 2);
+ n("(?<!a)b", "ab");
+ x2("(?<!a|bc)b", "bbb", 0, 1);
+ n("(?<!a|bc)z", "bcz");
+ x2("(?<name1>a)", "a", 0, 1);
+ x2("(?<name_2>ab)\\g<name_2>", "abab", 0, 4);
+ x2("(?<name_3>.zv.)\\k<name_3>", "azvbazvb", 0, 8);
+ x2("(?<=\\g<ab>)|-\\zEND (?<ab>XyZ)", "XyZ", 3, 3);
+ x2("(?<n>|a\\g<n>)+", "", 0, 0);
+ x2("(?<n>|\\(\\g<n>\\))+$", "()(())", 0, 6);
+ x3("\\g<n>(?<n>.){0}", "X", 0, 1, 1);
+ x2("\\g<n>(abc|df(?<n>.YZ){2,8}){0}", "XYZ", 0, 3);
+ x2("\\A(?<n>(a\\g<n>)|)\\z", "aaaa", 0, 4);
+ x2("(?<n>|\\g<m>\\g<n>)\\z|\\zEND (?<m>a|(b)\\g<m>)", "bbbbabba", 0, 8);
+ x2("(?<name1240>\\w+\\sx)a+\\k<name1240>", " fg xaaaaaaaafg x", 2, 18);
+ x3("(z)()()(?<_9>a)\\g<_9>", "zaa", 2, 3, 1);
+ x2("(.)(((?<_>a)))\\k<_>", "zaa", 0, 3);
+ x2("((?<name1>\\d)|(?<name2>\\w))(\\k<name1>|\\k<name2>)", "ff", 0, 2);
+ x2("(?:(?<x>)|(?<x>efg))\\k<x>", "", 0, 0);
+ x2("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefgefg", 3, 9);
+ n("(?:(?<x>abc)|(?<x>efg))\\k<x>", "abcefg");
+ x2("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "a-pyumpyum", 2, 10);
+ x3("(?:(?<n1>.)|(?<n1>..)|(?<n1>...)|(?<n1>....)|(?<n1>.....)|(?<n1>......)|(?<n1>.......)|(?<n1>........)|(?<n1>.........)|(?<n1>..........)|(?<n1>...........)|(?<n1>............)|(?<n1>.............)|(?<n1>..............))\\k<n1>$", "xxxxabcdefghijklmnabcdefghijklmn", 4, 18, 14);
+ x3("(?<name1>)(?<name2>)(?<name3>)(?<name4>)(?<name5>)(?<name6>)(?<name7>)(?<name8>)(?<name9>)(?<name10>)(?<name11>)(?<name12>)(?<name13>)(?<name14>)(?<name15>)(?<name16>aaa)(?<name17>)$", "aaa", 0, 3, 16);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "a", 0, 1);
+ x2("(?<foo>a|\\(\\g<foo>\\))", "((((((a))))))", 0, 13);
+ x3("(?<foo>a|\\(\\g<foo>\\))", "((((((((a))))))))", 0, 17, 1);
+ x2("\\g<bar>|\\zEND(?<bar>.*abc$)", "abcxxxabc", 0, 9);
+ x2("\\g<1>|\\zEND(.a.)", "bac", 0, 3);
+ x3("\\g<_A>\\g<_A>|\\zEND(.a.)(?<_A>.b.)", "xbxyby", 3, 6, 1);
+ x2("\\A(?:\\g<pon>|\\g<pan>|\\zEND (?<pan>a|c\\g<pon>c)(?<pon>b|d\\g<pan>d))$", "cdcbcdc", 0, 7);
+ x2("\\A(?<n>|a\\g<m>)\\z|\\zEND (?<m>\\g<n>)", "aaaa", 0, 4);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaaca", 1, 5);
+ x2("(?<n>(a|b\\g<n>c){3,5})", "baaaacaaaaa", 0, 10);
+ x2("(?<pare>\\(([^\\(\\)]++|\\g<pare>)*+\\))", "((a))", 0, 5);
+ x2("()*\\1", "", 0, 0);
+ x2("(?:()|())*\\1\\2", "", 0, 0);
+ x3("(?:\\1a|())*", "a", 0, 0, 1);
+ x2("x((.)*)*x", "0x1x2x3", 1, 6);
+ x2("x((.)*)*x(?i:\\1)\\Z", "0x1x2x1X2", 1, 9);
+ x2("(?:()|()|()|()|()|())*\\2\\5", "", 0, 0);
+ x2("(?:()|()|()|(x)|()|())*\\2b\\5", "b", 0, 1);
+ x2("\\xED\\xF2", "\xed\xf2", 0, 2);
+ x2("", "‚ ", 0, 0);
+ x2("‚ ", "‚ ", 0, 2);
+ n("‚¢", "‚ ");
+ x2("‚¤‚¤", "‚¤‚¤", 0, 4);
+ x2("‚ ‚¢‚¤", "‚ ‚¢‚¤", 0, 6);
+ x2("‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±", "‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±‚±", 0, 70);
+ x2("‚ ", "‚¢‚ ", 2, 4);
+ x2("‚¢‚¤", "‚ ‚¢‚¤", 2, 6);
+ x2("\\xca\\xb8", "\xca\xb8", 0, 2);
+ x2(".", "‚ ", 0, 2);
+ x2("..", "‚©‚«", 0, 4);
+ x2("\\w", "‚¨", 0, 2);
+ n("\\W", "‚ ");
+ x2("[\\W]", "‚¤$", 2, 3);
+ x2("\\S", "‚»", 0, 2);
+ x2("\\S", "Š¿", 0, 2);
+ x2("\\b", "‹C ", 0, 0);
+ x2("\\b", " ‚Ù", 1, 1);
+ x2("\\B", "‚¹‚» ", 2, 2);
+ x2("\\B", "‚¤ ", 3, 3);
+ x2("\\B", " ‚¢", 0, 0);
+ x2("[‚½‚¿]", "‚¿", 0, 2);
+ n("[‚È‚É]", "‚Ê");
+ x2("[‚¤-‚¨]", "‚¦", 0, 2);
+ n("[^‚¯]", "‚¯");
+ x2("[\\w]", "‚Ë", 0, 2);
+ n("[\\d]", "‚Ó");
+ x2("[\\D]", "‚Í", 0, 2);
+ n("[\\s]", "‚­");
+ x2("[\\S]", "‚Ö", 0, 2);
+ x2("[\\w\\d]", "‚æ", 0, 2);
+ x2("[\\w\\d]", " ‚æ", 3, 5);
+ n("\\w‹SŽÔ", " ‹SŽÔ");
+ x2("‹S\\WŽÔ", "‹S ŽÔ", 0, 5);
+ x2("‚ .‚¢.‚¤", "‚ ‚ ‚¢‚¢‚¤", 0, 10);
+ x2(".\\w‚¤\\W..‚¼", "‚¦‚¤‚¤ ‚¤‚¼‚¼", 0, 13);
+ x2("\\s\\w‚±‚±‚±", " ‚±‚±‚±‚±", 0, 9);
+ x2("‚ ‚ .‚¯", "‚ ‚ ‚¯‚¯", 0, 8);
+ n(".‚¢", "‚¢‚¦");
+ x2(".‚¨", "‚¨‚¨", 0, 4);
+ x2("^‚ ", "‚ ", 0, 2);
+ x2("^‚Þ$", "‚Þ", 0, 2);
+ x2("^\\w$", "‚É", 0, 2);
+ x2("^\\w‚©‚«‚­‚¯‚±$", "z‚©‚«‚­‚¯‚±", 0, 11);
+ x2("^\\w...‚¤‚¦‚¨$", "z‚ ‚¢‚¤‚¤‚¦‚¨", 0, 13);
+ x2("\\w\\w\\s\\W‚¨‚¨‚¨\\d", "a‚¨ ‚¨‚¨‚¨4", 0, 12);
+ x2("\\A‚½‚¿‚Â", "‚½‚¿‚Â", 0, 6);
+ x2("‚Þ‚ß‚à\\Z", "‚Þ‚ß‚à", 0, 6);
+ x2("‚©‚«‚­\\z", "‚©‚«‚­", 0, 6);
+ x2("‚©‚«‚­\\Z", "‚©‚«‚­\n", 0, 6);
+ x2("\\G‚Û‚Ò", "‚Û‚Ò", 0, 4);
+ n("\\G‚¦", "‚¤‚¦‚¨");
+ n("‚Æ‚Ä\\G", "‚Æ‚Ä");
+ n("‚Ü‚Ý\\A", "‚Ü‚Ý");
+ n("‚Ü\\A‚Ý", "‚Ü‚Ý");
+ x2("(?=‚¹)‚¹", "‚¹", 0, 2);
+ n("(?=‚¤).", "‚¢");
+ x2("(?!‚¤)‚©", "‚©", 0, 2);
+ n("(?!‚Æ)‚ ", "‚Æ");
+ x2("(?i:‚ )", "‚ ", 0, 2);
+ x2("(?i:‚Ô‚×)", "‚Ô‚×", 0, 4);
+ n("(?i:‚¢)", "‚¤");
+ x2("(?m:‚æ.)", "‚æ\n", 0, 3);
+ x2("(?m:.‚ß)", "‚Ü\n‚ß", 2, 5);
+ x2("‚ ?", "", 0, 0);
+ x2("•Ï?", "‰»", 0, 0);
+ x2("•Ï?", "•Ï", 0, 2);
+ x2("—Ê*", "", 0, 0);
+ x2("—Ê*", "—Ê", 0, 2);
+ x2("Žq*", "ŽqŽqŽq", 0, 6);
+ x2("”n*", "Ž­”n”n”n”n", 0, 0);
+ n("ŽR+", "");
+ x2("‰Í+", "‰Í", 0, 2);
+ x2("Žž+", "ŽžŽžŽžŽž", 0, 8);
+ x2("‚¦+", "‚¦‚¦‚¤‚¤‚¤", 0, 4);
+ x2("‚¤+", "‚¨‚¤‚¤‚¤‚¤", 2, 10);
+ x2(".?", "‚½", 0, 2);
+ x2(".*", "‚Ï‚Ò‚Õ‚Ø", 0, 8);
+ x2(".+", "‚ë", 0, 2);
+ x2(".+", "‚¢‚¤‚¦‚©\n", 0, 8);
+ x2("‚ |‚¢", "‚ ", 0, 2);
+ x2("‚ |‚¢", "‚¢", 0, 2);
+ x2("‚ ‚¢|‚¢‚¤", "‚ ‚¢", 0, 4);
+ x2("‚ ‚¢|‚¢‚¤", "‚¢‚¤", 0, 4);
+ x2("‚ð(?:‚©‚«|‚«‚­)", "‚ð‚©‚«", 0, 6);
+ x2("‚ð(?:‚©‚«|‚«‚­)‚¯", "‚ð‚«‚­‚¯", 0, 8);
+ x2("‚ ‚¢|(?:‚ ‚¤|‚ ‚ð)", "‚ ‚ð", 0, 4);
+ x2("‚ |‚¢|‚¤", "‚¦‚¤", 2, 4);
+ x2("‚ |‚¢|‚¤‚¦|‚¨‚©‚«|‚­|‚¯‚±‚³|‚µ‚·‚¹|‚»|‚½‚¿|‚‚ĂƂȂÉ|‚Ê‚Ë", "‚µ‚·‚¹", 0, 6);
+ n("‚ |‚¢|‚¤‚¦|‚¨‚©‚«|‚­|‚¯‚±‚³|‚µ‚·‚¹|‚»|‚½‚¿|‚‚ĂƂȂÉ|‚Ê‚Ë", "‚·‚¹");
+ x2("‚ |^‚í", "‚Ô‚ ", 2, 4);
+ x2("‚ |^‚ð", "‚ð‚ ", 0, 2);
+ x2("‹S|\\GŽÔ", "‚¯ŽÔ‹S", 4, 6);
+ x2("‹S|\\GŽÔ", "ŽÔ‹S", 0, 2);
+ x2("‹S|\\AŽÔ", "bŽÔ‹S", 3, 5);
+ x2("‹S|\\AŽÔ", "ŽÔ", 0, 2);
+ x2("‹S|ŽÔ\\Z", "ŽÔ‹S", 2, 4);
+ x2("‹S|ŽÔ\\Z", "ŽÔ", 0, 2);
+ x2("‹S|ŽÔ\\Z", "ŽÔ\n", 0, 2);
+ x2("‹S|ŽÔ\\z", "ŽÔ‹S", 2, 4);
+ x2("‹S|ŽÔ\\z", "ŽÔ", 0, 2);
+ x2("\\w|\\s", "‚¨", 0, 2);
+ x2("\\w|%", "%‚¨", 0, 1);
+ x2("\\w|[&$]", "‚¤&", 0, 2);
+ x2("[‚¢-‚¯]", "‚¤", 0, 2);
+ x2("[‚¢-‚¯]|[^‚©-‚±]", "‚ ", 0, 2);
+ x2("[‚¢-‚¯]|[^‚©-‚±]", "‚©", 0, 2);
+ x2("[^‚ ]", "\n", 0, 1);
+ x2("(?:‚ |[‚¤-‚«])|‚¢‚ð", "‚¤‚ð", 0, 2);
+ x2("(?:‚ |[‚¤-‚«])|‚¢‚ð", "‚¢‚ð", 0, 4);
+ x2("‚ ‚¢‚¤|(?=‚¯‚¯)..‚Ù", "‚¯‚¯‚Ù", 0, 6);
+ x2("‚ ‚¢‚¤|(?!‚¯‚¯)..‚Ù", "‚ ‚¢‚Ù", 0, 6);
+ x2("(?=‚ð‚ )..‚ |(?=‚ð‚ð)..‚ ", "‚ð‚ð‚ ", 0, 6);
+ x2("(?<=‚ |‚¢‚¤)‚¢", "‚¢‚¤‚¢", 4, 6);
+ n("(?>‚ |‚ ‚¢‚¦)‚¤", "‚ ‚¢‚¦‚¤");
+ x2("(?>‚ ‚¢‚¦|‚ )‚¤", "‚ ‚¢‚¦‚¤", 0, 8);
+ x2("‚ ?|‚¢", "‚ ", 0, 2);
+ x2("‚ ?|‚¢", "‚¢", 0, 0);
+ x2("‚ ?|‚¢", "", 0, 0);
+ x2("‚ *|‚¢", "‚ ‚ ", 0, 4);
+ x2("‚ *|‚¢*", "‚¢‚ ", 0, 0);
+ x2("‚ *|‚¢*", "‚ ‚¢", 0, 2);
+ x2("[a‚ ]*|‚¢*", "a‚ ‚¢‚¢‚¢", 0, 3);
+ x2("‚ +|‚¢*", "", 0, 0);
+ x2("‚ +|‚¢*", "‚¢‚¢‚¢", 0, 6);
+ x2("‚ +|‚¢*", "‚ ‚¢‚¢‚¢", 0, 2);
+ x2("‚ +|‚¢*", "a‚ ‚¢‚¢‚¢", 0, 0);
+ n("‚ +|‚¢+", "");
+ x2("(‚ |‚¢)?", "‚¢", 0, 2);
+ x2("(‚ |‚¢)*", "‚¢‚ ", 0, 4);
+ x2("(‚ |‚¢)+", "‚¢‚ ‚¢", 0, 6);
+ x2("(‚ ‚¢|‚¤‚ )+", "‚¤‚ ‚ ‚¢‚¤‚¦", 0, 8);
+ x2("(‚ ‚¢|‚¤‚¦)+", "‚¤‚ ‚ ‚¢‚¤‚¦", 4, 12);
+ x2("(‚ ‚¢|‚¤‚ )+", "‚ ‚ ‚¢‚¤‚ ", 2, 10);
+ x2("(‚ ‚¢|‚¤‚ )+", "‚ ‚¢‚ð‚¤‚ ", 0, 4);
+ x2("(‚ ‚¢|‚¤‚ )+", "$$zzzz‚ ‚¢‚ð‚¤‚ ", 6, 10);
+ x2("(‚ |‚¢‚ ‚¢)+", "‚ ‚¢‚ ‚¢‚ ", 0, 10);
+ x2("(‚ |‚¢‚ ‚¢)+", "‚¢‚ ", 2, 4);
+ x2("(‚ |‚¢‚ ‚¢)+", "‚¢‚ ‚ ‚ ‚¢‚ ", 2, 8);
+ x2("(?:‚ |‚¢)(?:‚ |‚¢)", "‚ ‚¢", 0, 4);
+ x2("(?:‚ *|‚¢*)(?:‚ *|‚¢*)", "‚ ‚ ‚ ‚¢‚¢‚¢", 0, 6);
+ x2("(?:‚ *|‚¢*)(?:‚ +|‚¢+)", "‚ ‚ ‚ ‚¢‚¢‚¢", 0, 12);
+ x2("(?:‚ +|‚¢+){2}", "‚ ‚ ‚ ‚¢‚¢‚¢", 0, 12);
+ x2("(?:‚ +|‚¢+){1,2}", "‚ ‚ ‚ ‚¢‚¢‚¢", 0, 12);
+ x2("(?:‚ +|\\A‚¢*)‚¤‚¤", "‚¤‚¤", 0, 4);
+ n("(?:‚ +|\\A‚¢*)‚¤‚¤", "‚ ‚¢‚¤‚¤");
+ x2("(?:^‚ +|‚¢+)*‚¤", "‚ ‚ ‚¢‚¢‚¢‚ ‚¢‚¤", 12, 16);
+ x2("(?:^‚ +|‚¢+)*‚¤", "‚ ‚ ‚¢‚¢‚¢‚¢‚¤", 0, 14);
+ x2("‚¤{0,}", "‚¤‚¤‚¤‚¤", 0, 8);
+ x2("‚ |(?i)c", "C", 0, 1);
+ x2("(?i)c|‚ ", "C", 0, 1);
+ x2("(?i:‚ )|a", "a", 0, 1);
+ n("(?i:‚ )|a", "A");
+ x2("[‚ ‚¢‚¤]?", "‚ ‚¢‚¤", 0, 2);
+ x2("[‚ ‚¢‚¤]*", "‚ ‚¢‚¤", 0, 6);
+ x2("[^‚ ‚¢‚¤]*", "‚ ‚¢‚¤", 0, 0);
+ n("[^‚ ‚¢‚¤]+", "‚ ‚¢‚¤");
+ x2("‚ ?\?", "‚ ‚ ‚ ", 0, 0);
+ x2("‚¢‚ ?\?‚¢", "‚¢‚ ‚¢", 0, 6);
+ x2("‚ *?", "‚ ‚ ‚ ", 0, 0);
+ x2("‚¢‚ *?", "‚¢‚ ‚ ", 0, 2);
+ x2("‚¢‚ *?‚¢", "‚¢‚ ‚ ‚¢", 0, 8);
+ x2("‚ +?", "‚ ‚ ‚ ", 0, 2);
+ x2("‚¢‚ +?", "‚¢‚ ‚ ", 0, 4);
+ x2("‚¢‚ +?‚¢", "‚¢‚ ‚ ‚¢", 0, 8);
+ x2("(?:“V?)?\?", "“V", 0, 0);
+ x2("(?:“V?\?)?", "“V", 0, 0);
+ x2("(?:–²?)+?", "–²–²–²", 0, 2);
+ x2("(?:•—+)?\?", "•—•—•—", 0, 0);
+ x2("(?:á+)?\?‘š", "ááá‘š", 0, 8);
+ x2("(?:‚ ‚¢)?{2}", "", 0, 0);
+ x2("(?:‹SŽÔ)?{2}", "‹SŽÔ‹SŽÔ‹S", 0, 8);
+ x2("(?:‹SŽÔ)*{0}", "‹SŽÔ‹SŽÔ‹S", 0, 0);
+ x2("(?:‹SŽÔ){3,}", "‹SŽÔ‹SŽÔ‹SŽÔ‹SŽÔ", 0, 16);
+ n("(?:‹SŽÔ){3,}", "‹SŽÔ‹SŽÔ");
+ x2("(?:‹SŽÔ){2,4}", "‹SŽÔ‹SŽÔ‹SŽÔ", 0, 12);
+ x2("(?:‹SŽÔ){2,4}", "‹SŽÔ‹SŽÔ‹SŽÔ‹SŽÔ‹SŽÔ", 0, 16);
+ x2("(?:‹SŽÔ){2,4}?", "‹SŽÔ‹SŽÔ‹SŽÔ‹SŽÔ‹SŽÔ", 0, 8);
+ x2("(?:‹SŽÔ){,}", "‹SŽÔ{,}", 0, 7);
+ x2("(?:‚©‚«‚­)+?{2}", "‚©‚«‚­‚©‚«‚­‚©‚«‚­", 0, 12);
+ x3("(‰Î)", "‰Î", 0, 2, 1);
+ x3("(‰Î…)", "‰Î…", 0, 4, 1);
+ x2("((ŽžŠÔ))", "ŽžŠÔ", 0, 4);
+ x3("((•—…))", "•—…", 0, 4, 1);
+ x3("((ð“ú))", "ð“ú", 0, 4, 2);
+ x3("((((((((((((((((((((—ÊŽq))))))))))))))))))))", "—ÊŽq", 0, 4, 20);
+ x3("(‚ ‚¢)(‚¤‚¦)", "‚ ‚¢‚¤‚¦", 0, 4, 1);
+ x3("(‚ ‚¢)(‚¤‚¦)", "‚ ‚¢‚¤‚¦", 4, 8, 2);
+ x3("()(‚ )‚¢‚¤(‚¦‚¨‚©)‚«‚­‚¯‚±", "‚ ‚¢‚¤‚¦‚¨‚©‚«‚­‚¯‚±", 6, 12, 3);
+ x3("(()(‚ )‚¢‚¤(‚¦‚¨‚©)‚«‚­‚¯‚±)", "‚ ‚¢‚¤‚¦‚¨‚©‚«‚­‚¯‚±", 6, 12, 4);
+ x3(".*(ƒtƒH)ƒ“Eƒ}(ƒ“()ƒVƒ…ƒ^)ƒCƒ“", "ƒtƒHƒ“Eƒ}ƒ“ƒVƒ…ƒ^ƒCƒ“", 10, 18, 2);
+ x2("(^‚ )", "‚ ", 0, 2);
+ x3("(‚ )|(‚ )", "‚¢‚ ", 2, 4, 1);
+ x3("(^‚ )|(‚ )", "‚¢‚ ", 2, 4, 2);
+ x3("(‚ ?)", "‚ ‚ ‚ ", 0, 2, 1);
+ x3("(‚Ü*)", "‚Ü‚Ü‚Ü", 0, 6, 1);
+ x3("(‚Æ*)", "", 0, 0, 1);
+ x3("(‚é+)", "‚é‚é‚é‚é‚é‚é‚é", 0, 14, 1);
+ x3("(‚Ó+|‚Ö*)", "‚Ó‚Ó‚Ó‚Ö‚Ö", 0, 6, 1);
+ x3("(‚ +|‚¢?)", "‚¢‚¢‚¢‚ ‚ ", 0, 2, 1);
+ x3("(‚ ‚¢‚¤)?", "‚ ‚¢‚¤", 0, 6, 1);
+ x3("(‚ ‚¢‚¤)*", "‚ ‚¢‚¤", 0, 6, 1);
+ x3("(‚ ‚¢‚¤)+", "‚ ‚¢‚¤", 0, 6, 1);
+ x3("(‚³‚µ‚·|‚ ‚¢‚¤)+", "‚ ‚¢‚¤", 0, 6, 1);
+ x3("([‚È‚É‚Ê][‚©‚«‚­]|‚©‚«‚­)+", "‚©‚«‚­", 0, 6, 1);
+ x3("((?i:‚ ‚¢‚¤))", "‚ ‚¢‚¤", 0, 6, 1);
+ x3("((?m:‚ .‚¤))", "‚ \n‚¤", 0, 5, 1);
+ x3("((?=‚ ‚ñ)‚ )", "‚ ‚ñ‚¢", 0, 2, 1);
+ x3("‚ ‚¢‚¤|(.‚ ‚¢‚¦)", "‚ñ‚ ‚¢‚¦", 0, 8, 1);
+ x3("‚ *(.)", "‚ ‚ ‚ ‚ ‚ñ", 8, 10, 1);
+ x3("‚ *?(.)", "‚ ‚ ‚ ‚ ‚ñ", 0, 2, 1);
+ x3("‚ *?(‚ñ)", "‚ ‚ ‚ ‚ ‚ñ", 8, 10, 1);
+ x3("[‚¢‚¤‚¦]‚ *(.)", "‚¦‚ ‚ ‚ ‚ ‚ñ", 10, 12, 1);
+ x3("(\\A‚¢‚¢)‚¤‚¤", "‚¢‚¢‚¤‚¤", 0, 4, 1);
+ n("(\\A‚¢‚¢)‚¤‚¤", "‚ñ‚¢‚¢‚¤‚¤");
+ x3("(^‚¢‚¢)‚¤‚¤", "‚¢‚¢‚¤‚¤", 0, 4, 1);
+ n("(^‚¢‚¢)‚¤‚¤", "‚ñ‚¢‚¢‚¤‚¤");
+ x3("‚ë‚ë(‚é‚é$)", "‚ë‚ë‚é‚é", 4, 8, 1);
+ n("‚ë‚ë(‚é‚é$)", "‚ë‚ë‚é‚é‚é");
+ x2("(–³)\\1", "–³–³", 0, 4);
+ n("(–³)\\1", "–³•");
+ x2("(‹ó?)\\1", "‹ó‹ó", 0, 4);
+ x2("(‹ó?\?)\\1", "‹ó‹ó", 0, 0);
+ x2("(‹ó*)\\1", "‹ó‹ó‹ó‹ó‹ó", 0, 8);
+ x3("(‹ó*)\\1", "‹ó‹ó‹ó‹ó‹ó", 0, 4, 1);
+ x2("‚ (‚¢*)\\1", "‚ ‚¢‚¢‚¢‚¢", 0, 10);
+ x2("‚ (‚¢*)\\1", "‚ ‚¢", 0, 2);
+ x2("(‚ *)(‚¢*)\\1\\2", "‚ ‚ ‚ ‚¢‚¢‚ ‚ ‚ ‚¢‚¢", 0, 20);
+ x2("(‚ *)(‚¢*)\\2", "‚ ‚ ‚ ‚¢‚¢‚¢‚¢", 0, 14);
+ x3("(‚ *)(‚¢*)\\2", "‚ ‚ ‚ ‚¢‚¢‚¢‚¢", 6, 10, 2);
+ x2("(((((((‚Û*)‚Ø))))))‚Ò\\7", "‚Û‚Û‚Û‚Ø‚Ò‚Û‚Û‚Û", 0, 16);
+ x3("(((((((‚Û*)‚Ø))))))‚Ò\\7", "‚Û‚Û‚Û‚Ø‚Ò‚Û‚Û‚Û", 0, 6, 7);
+ x2("(‚Í)(‚Ð)(‚Ó)\\2\\1\\3", "‚͂ЂӂЂ͂Ó", 0, 12);
+ x2("([‚«-‚¯])\\1", "‚­‚­", 0, 4);
+ x2("(\\w\\d\\s)\\1", "‚ 5 ‚ 5 ", 0, 8);
+ n("(\\w\\d\\s)\\1", "‚ 5 ‚ 5");
+ x2("(’NH|[‚ -‚¤]{3})\\1", "’NH’NH", 0, 8);
+ x2("...(’NH|[‚ -‚¤]{3})\\1", "‚ a‚ ’NH’NH", 0, 13);
+ x2("(’NH|[‚ -‚¤]{3})\\1", "‚¤‚¢‚¤‚¤‚¢‚¤", 0, 12);
+ x2("(^‚±)\\1", "‚±‚±", 0, 4);
+ n("(^‚Þ)\\1", "‚ß‚Þ‚Þ");
+ n("(‚ $)\\1", "‚ ‚ ");
+ n("(‚ ‚¢\\Z)\\1", "‚ ‚¢");
+ x2("(‚ *\\Z)\\1", "‚ ", 2, 2);
+ x2(".(‚ *\\Z)\\1", "‚¢‚ ", 2, 4);
+ x3("(.(‚â‚¢‚ä)\\2)", "z‚â‚¢‚ä‚â‚¢‚ä", 0, 13, 1);
+ x3("(.(..\\d.)\\2)", "‚ 12341234", 0, 10, 1);
+ x2("((?i:‚ v‚¸))\\1", "‚ v‚¸‚ v‚¸", 0, 10);
+ x2("(?<‹ð‚©>•Ï|\\(\\g<‹ð‚©>\\))", "((((((•Ï))))))", 0, 14);
+ x2("\\A(?:\\g<ˆ¢_1>|\\g<‰]_2>|\\zI—¹ (?<ˆ¢_1>ŠÏ|Ž©\\g<‰]_2>Ž©)(?<‰]_2>Ý|•ìŽF\\g<ˆ¢_1>•ìŽF))$", "•ìŽFŽ©•ìŽFŽ©ÝŽ©•ìŽFŽ©•ìŽF", 0, 26);
+ x2("[[‚ЂÓ]]", "‚Ó", 0, 2);
+ x2("[[‚¢‚¨‚¤]‚©]", "‚©", 0, 2);
+ n("[[^‚ ]]", "‚ ");
+ n("[^[‚ ]]", "‚ ");
+ x2("[^[^‚ ]]", "‚ ", 0, 2);
+ x2("[[‚©‚«‚­]&&‚«‚­]", "‚­", 0, 2);
+ n("[[‚©‚«‚­]&&‚«‚­]", "‚©");
+ n("[[‚©‚«‚­]&&‚«‚­]", "‚¯");
+ x2("[‚ -‚ñ&&‚¢-‚ð&&‚¤-‚ï]", "‚ï", 0, 2);
+ n("[^‚ -‚ñ&&‚¢-‚ð&&‚¤-‚ï]", "‚ï");
+ x2("[[^‚ &&‚ ]&&‚ -‚ñ]", "‚¢", 0, 2);
+ n("[[^‚ &&‚ ]&&‚ -‚ñ]", "‚ ");
+ x2("[[^‚ -‚ñ&&‚¢‚¤‚¦‚¨]&&[^‚¤-‚©]]", "‚«", 0, 2);
+ n("[[^‚ -‚ñ&&‚¢‚¤‚¦‚¨]&&[^‚¤-‚©]]", "‚¢");
+ x2("[^[^‚ ‚¢‚¤]&&[^‚¤‚¦‚¨]]", "‚¤", 0, 2);
+ x2("[^[^‚ ‚¢‚¤]&&[^‚¤‚¦‚¨]]", "‚¦", 0, 2);
+ n("[^[^‚ ‚¢‚¤]&&[^‚¤‚¦‚¨]]", "‚©");
+ x2("[‚ -&&-‚ ]", "-", 0, 1);
+ x2("[^[^a-z‚ ‚¢‚¤]&&[^bcdefg‚¤‚¦‚¨]q-w]", "‚¦", 0, 2);
+ x2("[^[^a-z‚ ‚¢‚¤]&&[^bcdefg‚¤‚¦‚¨]g-w]", "f", 0, 1);
+ x2("[^[^a-z‚ ‚¢‚¤]&&[^bcdefg‚¤‚¦‚¨]g-w]", "g", 0, 1);
+ n("[^[^a-z‚ ‚¢‚¤]&&[^bcdefg‚¤‚¦‚¨]g-w]", "2");
+ x2("a<b>ƒo[ƒWƒ‡ƒ“‚̃_ƒEƒ“ƒ[ƒh<\\/b>", "a<b>ƒo[ƒWƒ‡ƒ“‚̃_ƒEƒ“ƒ[ƒh</b>", 0, 32);
+ x2(".<b>ƒo[ƒWƒ‡ƒ“‚̃_ƒEƒ“ƒ[ƒh<\\/b>", "a<b>ƒo[ƒWƒ‡ƒ“‚̃_ƒEƒ“ƒ[ƒh</b>", 0, 32);
+ fprintf(stdout,
+ "\nRESULT SUCC: %d, FAIL: %d, ERROR: %d (by Oniguruma %s)\n",
+ nsucc, nfail, nerror, onig_version());
+
+#ifndef POSIX_TEST
+ onig_region_free(region, 1);
+ onig_end();
+#endif
+
+ return ((nfail == 0 && nerror == 0) ? 0 : -1);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdarg.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdarg.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdarg.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stddef.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stddef.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stddef.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdio.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdio.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdio.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdlib.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdlib.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/stdlib.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/string.h b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/string.h
new file mode 100644
index 000000000..820040066
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/RegularExpressionDxe/string.h
@@ -0,0 +1,9 @@
+/** @file
+ Include file to support building the third-party oniguruma.
+
+Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <OnigurumaUefiPort.h>
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.c b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.c
new file mode 100644
index 000000000..cb3eab1b4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.c
@@ -0,0 +1,315 @@
+/** @file
+ Report Status Code Router PEIM which produces Report Stataus Code Handler PPI and Status Code PPI.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ReportStatusCodeRouterPei.h"
+
+EFI_PEI_RSC_HANDLER_PPI mRscHandlerPpi = {
+ Register,
+ Unregister
+ };
+
+EFI_PEI_PROGRESS_CODE_PPI mStatusCodePpi = {
+ ReportDispatcher
+ };
+
+EFI_PEI_PPI_DESCRIPTOR mRscHandlerPpiList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiRscHandlerPpiGuid,
+ &mRscHandlerPpi
+ }
+};
+
+EFI_PEI_PPI_DESCRIPTOR mStatusCodePpiList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiStatusCodePpiGuid,
+ &mStatusCodePpi
+ }
+};
+
+/**
+ Worker function to create one memory status code GUID'ed HOB,
+ using PacketIndex to identify the packet.
+
+ @param PacketIndex Index of records packet.
+
+ @return Pointer to the memory status code packet.
+
+**/
+UINTN *
+CreateRscHandlerCallbackPacket (
+ VOID
+ )
+{
+ UINTN *NumberOfEntries;
+
+ //
+ // Build GUID'ed HOB with PCD defined size.
+ //
+ NumberOfEntries = BuildGuidHob (
+ &gStatusCodeCallbackGuid,
+ sizeof (EFI_PEI_RSC_HANDLER_CALLBACK) * 64 + sizeof (UINTN)
+ );
+ ASSERT (NumberOfEntries != NULL);
+
+ *NumberOfEntries = 0;
+
+ return NumberOfEntries;
+}
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called
+ when a call to ReportStatusCode() occurs.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_PEI_RSC_HANDLER_CALLBACK Callback
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_RSC_HANDLER_CALLBACK *CallbackEntry;
+ UINTN *NumberOfEntries;
+ UINTN Index;
+ UINTN FreeEntryIndex;
+ UINTN *FreePacket;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
+ FreePacket = NULL;
+ FreeEntryIndex = 0;
+ while (Hob.Raw != NULL) {
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);
+ CallbackEntry = (EFI_PEI_RSC_HANDLER_CALLBACK *) (NumberOfEntries + 1);
+ if (FreePacket == NULL && *NumberOfEntries < 64) {
+ //
+ // If current total number of handlers does not exceed 64, put new handler
+ // at the last of packet
+ //
+ FreePacket = NumberOfEntries;
+ FreeEntryIndex = *NumberOfEntries;
+ }
+ for (Index = 0; Index < *NumberOfEntries; Index++) {
+ if (CallbackEntry[Index] == Callback) {
+ //
+ // If the function was already registered. It can't be registered again.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ if (FreePacket == NULL && CallbackEntry[Index] == NULL) {
+ //
+ // If the total number of handlers in current packet is max value 64,
+ // search an entry with NULL pointer and fill new handler into this entry.
+ //
+ FreePacket = NumberOfEntries;
+ FreeEntryIndex = Index;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
+ }
+
+ if (FreePacket == NULL) {
+ FreePacket = CreateRscHandlerCallbackPacket();
+ }
+
+ CallbackEntry = (EFI_PEI_RSC_HANDLER_CALLBACK *) (FreePacket + 1);
+ CallbackEntry[FreeEntryIndex] = Callback;
+
+ if (*FreePacket == FreeEntryIndex) {
+ //
+ // If new registered callback is added as a new entry in the packet,
+ // increase the total number of handlers in the packet.
+ //
+ *FreePacket += 1;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ ReportStatusCode() messages will no longer be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_PEI_RSC_HANDLER_CALLBACK Callback
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_RSC_HANDLER_CALLBACK *CallbackEntry;
+ UINTN *NumberOfEntries;
+ UINTN Index;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
+ while (Hob.Raw != NULL) {
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);
+ CallbackEntry = (EFI_PEI_RSC_HANDLER_CALLBACK *) (NumberOfEntries + 1);
+ for (Index = 0; Index < *NumberOfEntries; Index++) {
+ if (CallbackEntry[Index] == Callback) {
+ //
+ // Set removed entry as NULL.
+ //
+ CallbackEntry[Index] = NULL;
+ return EFI_SUCCESS;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ 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
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PEI_RSC_HANDLER_CALLBACK *CallbackEntry;
+ UINTN *NumberOfEntries;
+ UINTN Index;
+
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
+ while (Hob.Raw != NULL) {
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);
+ CallbackEntry = (EFI_PEI_RSC_HANDLER_CALLBACK *) (NumberOfEntries + 1);
+ for (Index = 0; Index < *NumberOfEntries; Index++) {
+ if (CallbackEntry[Index] != NULL) {
+ CallbackEntry[Index](
+ PeiServices,
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of Status Code PEIM.
+
+ This function is the entry point of this Status Code Router PEIM.
+ It produces Report Stataus Code Handler PPI and 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
+GenericStatusCodePeiEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
+ EFI_PEI_PROGRESS_CODE_PPI *OldStatusCodePpi;
+
+ CreateRscHandlerCallbackPacket ();
+
+ //
+ // Install Report Status Code Handler PPI
+ //
+ Status = PeiServicesInstallPpi (mRscHandlerPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Status Code PPI. PI spec specifies that there can be only one instance
+ // of this PPI in system. So first check if other instance already exists.
+ // If no other instance exists, then just install the PPI.
+ // If other instance already exists, then reinstall it.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiStatusCodePpiGuid,
+ 0,
+ &OldDescriptor,
+ (VOID **) &OldStatusCodePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesReInstallPpi (OldDescriptor, mStatusCodePpiList);
+ } else {
+ Status = PeiServicesInstallPpi (mStatusCodePpiList);
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.h b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.h
new file mode 100644
index 000000000..b06fa5da9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.h
@@ -0,0 +1,103 @@
+/** @file
+ Internal include file for Report Status Code Router PEIM.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PEI_REPORT_STATUS_CODE_ROUTER_H__
+#define __PEI_REPORT_STATUS_CODE_ROUTER_H__
+
+
+#include <Ppi/ReportStatusCodeHandler.h>
+#include <Ppi/StatusCode.h>
+
+#include <Guid/StatusCodeCallbackGuid.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called
+ when a call to ReportStatusCode() occurs.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_PEI_RSC_HANDLER_CALLBACK Callback
+ );
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ ReportStatusCode() messages will no longer be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_PEI_RSC_HANDLER_CALLBACK Callback
+ );
+
+/**
+ 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/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
new file mode 100644
index 000000000..a53d0587e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
@@ -0,0 +1,55 @@
+## @file
+# Report Status Code Router PEIM which produces Report Stataus Code Handler PPI and Status Code PPI.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ReportStatusCodeRouterPei
+ MODULE_UNI_FILE = ReportStatusCodeRouterPei.uni
+ FILE_GUID = A3610442-E69F-4DF3-82CA-2360C4031A23
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GenericStatusCodePeiEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is only for build)
+#
+
+[Sources]
+ ReportStatusCodeRouterPei.c
+ ReportStatusCodeRouterPei.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ DebugLib
+ HobLib
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## CONSUMES ## HOB
+ gStatusCodeCallbackGuid
+
+[Ppis]
+ gEfiPeiRscHandlerPpiGuid ## PRODUCES
+ gEfiPeiStatusCodePpiGuid ## PRODUCES
+
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ReportStatusCodeRouterPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.uni
new file mode 100644
index 000000000..8f391d2a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Report Status Code Router PEIM which produces Report Stataus Code Handler PPI and Status Code PPI.
+//
+// Report Status Code Router is a PEIM that produces Report Status Code Handler PPI and Status Code PPI.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PEIM that produces Report Status Code Handler PPI and Status Code PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Report Status Code Router is a PEIM that produces Report Status Code Handler PPI and Status Code PPI."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPeiExtra.uni
new file mode 100644
index 000000000..6e962e324
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ReportStatusCodeRouterPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Routing PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.c b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.c
new file mode 100644
index 000000000..0464d0777
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.c
@@ -0,0 +1,409 @@
+/** @file
+ Report Status Code Router Driver which produces Report Stataus Code Handler Protocol
+ and Status Code Runtime Protocol.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ReportStatusCodeRouterRuntimeDxe.h"
+
+EFI_HANDLE mHandle = NULL;
+LIST_ENTRY mCallbackListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackListHead);
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+
+//
+// Report operation nest status.
+// If it is set, then the report operation has nested.
+//
+UINT32 mStatusCodeNestStatus = 0;
+
+EFI_STATUS_CODE_PROTOCOL mStatusCodeProtocol = {
+ ReportDispatcher
+};
+
+EFI_RSC_HANDLER_PROTOCOL mRscHandlerProtocol = {
+ Register,
+ Unregister
+ };
+
+/**
+ Event callback function to invoke status code handler in list.
+
+ @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
+RscHandlerNotification (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+ EFI_PHYSICAL_ADDRESS Address;
+ RSC_DATA_ENTRY *RscData;
+
+ CallbackEntry = (RSC_HANDLER_CALLBACK_ENTRY *) Context;
+
+ //
+ // Traverse the status code data buffer to parse all
+ // data to report.
+ //
+ Address = CallbackEntry->StatusCodeDataBuffer;
+ while (Address < CallbackEntry->EndPointer) {
+ RscData = (RSC_DATA_ENTRY *) (UINTN) Address;
+ CallbackEntry->RscHandlerCallback (
+ RscData->Type,
+ RscData->Value,
+ RscData->Instance,
+ &RscData->CallerId,
+ &RscData->Data
+ );
+
+ Address += (OFFSET_OF (RSC_DATA_ENTRY, Data) + RscData->Data.HeaderSize + RscData->Data.Size);
+ Address = ALIGN_VARIABLE (Address);
+ }
+
+ CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
+}
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function. During the bootservices,
+ this is the callback for which this service can be invoked. The report status code router
+ will create an event such that the callback function is only invoked at the TPL for which it was
+ registered. The entity that registers for the callback should also register for an event upon
+ generation of exit boot services and invoke the unregister service.
+ If the handler does not have a TPL dependency, it should register for a callback at TPL high. The
+ router infrastructure will support making callbacks at runtime, but the caller for runtime invocation
+ must meet the following criteria:
+ 1. must be a runtime driver type so that its memory is not reclaimed
+ 2. not unregister at exit boot services so that the router will still have its callback address
+ 3. the caller must be self-contained (eg. Not call out into any boot-service interfaces) and be
+ runtime safe, in general.
+
+ @param[in] Callback A pointer to a function of type EFI_RSC_HANDLER_CALLBACK that is called when
+ a call to ReportStatusCode() occurs.
+ @param[in] Tpl TPL at which callback can be safely invoked.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_RSC_HANDLER_CALLBACK Callback,
+ IN EFI_TPL Tpl
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
+ CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ if (CallbackEntry->RscHandlerCallback == Callback) {
+ //
+ // If the function was already registered. It can't be registered again.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ CallbackEntry = AllocateRuntimeZeroPool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));
+ ASSERT (CallbackEntry != NULL);
+
+ CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
+ CallbackEntry->RscHandlerCallback = Callback;
+ CallbackEntry->Tpl = Tpl;
+
+ //
+ // If TPL of registered callback funtion is not TPL_HIGH_LEVEL, then event should be created
+ // for it, and related buffer for status code data should be prepared.
+ // Here the data buffer must be prepared in advance, because Report Status Code Protocol might
+ // be invoked under TPL_HIGH_LEVEL and no memory allocation is allowed then.
+ // If TPL is TPL_HIGH_LEVEL, then all status code will be reported immediately, without data
+ // buffer and event trigger.
+ //
+ if (Tpl != TPL_HIGH_LEVEL) {
+ CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocatePool (EFI_PAGE_SIZE);
+ CallbackEntry->BufferSize = EFI_PAGE_SIZE;
+ CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ Tpl,
+ RscHandlerNotification,
+ CallbackEntry,
+ &CallbackEntry->Event
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ A callback function must be unregistered before it is deallocated. It is important that any registered
+ callbacks that are not runtime complaint be unregistered when ExitBootServices() is called.
+
+ @param[in] Callback A pointer to a function of type EFI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_RSC_HANDLER_CALLBACK Callback
+ )
+{
+ LIST_ENTRY *Link;
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
+ CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ if (CallbackEntry->RscHandlerCallback == Callback) {
+ //
+ // If the function is found in list, delete it and return.
+ //
+ if (CallbackEntry->Tpl != TPL_HIGH_LEVEL) {
+ FreePool ((VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer);
+ gBS->CloseEvent (CallbackEntry->Event);
+ }
+ RemoveEntryList (&CallbackEntry->Node);
+ FreePool (CallbackEntry);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides an interface that a software module can call to report a status code.
+
+ @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.
+ @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 Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+ RSC_DATA_ENTRY *RscData;
+ EFI_STATUS Status;
+ VOID *NewBuffer;
+ EFI_PHYSICAL_ADDRESS FailSafeEndPointer;
+
+ //
+ // 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;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link);) {
+ CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ //
+ // The handler may remove itself, so get the next handler in advance.
+ //
+ Link = GetNextNode (&mCallbackListHead, Link);
+ if ((CallbackEntry->Tpl == TPL_HIGH_LEVEL) || EfiAtRuntime ()) {
+ CallbackEntry->RscHandlerCallback (
+ Type,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ continue;
+ }
+
+ //
+ // If callback is registered with TPL lower than TPL_HIGH_LEVEL, event must be signaled at boot time to possibly wait for
+ // allowed TPL to report status code. Related data should also be stored in data buffer.
+ //
+ FailSafeEndPointer = CallbackEntry->EndPointer;
+ CallbackEntry->EndPointer = ALIGN_VARIABLE (CallbackEntry->EndPointer);
+ RscData = (RSC_DATA_ENTRY *) (UINTN) CallbackEntry->EndPointer;
+ CallbackEntry->EndPointer += sizeof (RSC_DATA_ENTRY);
+ if (Data != NULL) {
+ CallbackEntry->EndPointer += (Data->Size + Data->HeaderSize - sizeof (EFI_STATUS_CODE_DATA));
+ }
+
+ //
+ // If data buffer is about to be used up (7/8 here), try to reallocate a buffer with double size, if not at TPL_HIGH_LEVEL.
+ //
+ if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + (CallbackEntry->BufferSize / 8) * 7)) {
+ if (EfiGetCurrentTpl () < TPL_HIGH_LEVEL) {
+ NewBuffer = ReallocatePool (
+ CallbackEntry->BufferSize,
+ CallbackEntry->BufferSize * 2,
+ (VOID *) (UINTN) CallbackEntry->StatusCodeDataBuffer
+ );
+ if (NewBuffer != NULL) {
+ FailSafeEndPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NewBuffer + (FailSafeEndPointer - CallbackEntry->StatusCodeDataBuffer);
+ CallbackEntry->EndPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) NewBuffer + (CallbackEntry->EndPointer - CallbackEntry->StatusCodeDataBuffer);
+ RscData = (RSC_DATA_ENTRY *) (UINTN) ((UINTN) NewBuffer + ((UINTN) RscData - CallbackEntry->StatusCodeDataBuffer));
+ CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS) (UINTN) NewBuffer;
+ CallbackEntry->BufferSize *= 2;
+ }
+ }
+ }
+
+ //
+ // If data buffer is used up, do not report for this time.
+ //
+ if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + CallbackEntry->BufferSize)) {
+ CallbackEntry->EndPointer = FailSafeEndPointer;
+ continue;
+ }
+
+ RscData->Type = Type;
+ RscData->Value = Value;
+ RscData->Instance = Instance;
+ if (CallerId != NULL) {
+ CopyGuid (&RscData->CallerId, CallerId);
+ }
+ if (Data != NULL) {
+ CopyMem (&RscData->Data, Data, Data->HeaderSize + Data->Size);
+ } else {
+ ZeroMem (&RscData->Data, sizeof (RscData->Data));
+ RscData->Data.HeaderSize = sizeof (RscData->Data);
+ }
+
+ Status = gBS->SignalEvent (CallbackEntry->Event);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // 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
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
+ CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ Status = EfiConvertFunctionPointer (0, (VOID **) &CallbackEntry->RscHandlerCallback);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = EfiConvertList (
+ 0,
+ &mCallbackListHead
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Entry point of Generic Status Code Driver.
+
+ This function is the entry point of this Generic Status Code Driver.
+ It installs eport Stataus Code Handler Protocol and 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
+GenericStatusCodeRuntimeDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiRscHandlerProtocolGuid,
+ &mRscHandlerProtocol,
+ &gEfiStatusCodeRuntimeProtocolGuid,
+ &mStatusCodeProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualAddressChangeCallBack,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.h b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.h
new file mode 100644
index 000000000..d975920d5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.h
@@ -0,0 +1,136 @@
+/** @file
+ Internal include file for Report Status Code Router Driver.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __REPORT_STATUS_CODE_ROUTER_RUNTIME_DXE_H__
+#define __REPORT_STATUS_CODE_ROUTER_RUNTIME_DXE_H__
+
+
+#include <Protocol/ReportStatusCodeHandler.h>
+#include <Protocol/StatusCode.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include "Library/UefiLib.h"
+
+#define RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE SIGNATURE_32 ('r', 'h', 'c', 'e')
+
+typedef struct {
+ UINTN Signature;
+ EFI_RSC_HANDLER_CALLBACK RscHandlerCallback;
+ EFI_TPL Tpl;
+ EFI_EVENT Event;
+ EFI_PHYSICAL_ADDRESS StatusCodeDataBuffer;
+ UINTN BufferSize;
+ EFI_PHYSICAL_ADDRESS EndPointer;
+ LIST_ENTRY Node;
+} RSC_HANDLER_CALLBACK_ENTRY;
+
+typedef struct {
+ EFI_STATUS_CODE_TYPE Type;
+ EFI_STATUS_CODE_VALUE Value;
+ UINT32 Instance;
+ UINT32 Reserved;
+ EFI_GUID CallerId;
+ EFI_STATUS_CODE_DATA Data;
+} RSC_DATA_ENTRY;
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function. During the bootservices,
+ this is the callback for which this service can be invoked. The report status code router
+ will create an event such that the callback function is only invoked at the TPL for which it was
+ registered. The entity that registers for the callback should also register for an event upon
+ generation of exit boot services and invoke the unregister service.
+ If the handler does not have a TPL dependency, it should register for a callback at TPL high. The
+ router infrastructure will support making callbacks at runtime, but the caller for runtime invocation
+ must meet the following criteria:
+ 1. must be a runtime driver type so that its memory is not reclaimed
+ 2. not unregister at exit boot services so that the router will still have its callback address
+ 3. the caller must be self-contained (eg. Not call out into any boot-service interfaces) and be
+ runtime safe, in general.
+
+ @param[in] Callback A pointer to a function of type EFI_RSC_HANDLER_CALLBACK that is called when
+ a call to ReportStatusCode() occurs.
+ @param[in] Tpl TPL at which callback can be safely invoked.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_RSC_HANDLER_CALLBACK Callback,
+ IN EFI_TPL Tpl
+ );
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ A callback function must be unregistered before it is deallocated. It is important that any registered
+ callbacks that are not runtime complaint be unregistered when ExitBootServices() is called.
+
+ @param[in] Callback A pointer to a function of type EFI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_RSC_HANDLER_CALLBACK Callback
+ );
+
+/**
+ Provides an interface that a software module can call to report a status code.
+
+ @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.
+ @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 Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+#endif
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
new file mode 100644
index 000000000..4b53f79e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
@@ -0,0 +1,58 @@
+## @file
+# Report Status Code Router Driver which produces Report Stataus Code Handler Protocol and Status Code Runtime Protocol.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ReportStatusCodeRouterRuntimeDxe
+ MODULE_UNI_FILE = ReportStatusCodeRouterRuntimeDxe.uni
+ FILE_GUID = D93CE3D8-A7EB-4730-8C8E-CC466A9ECC3C
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GenericStatusCodeRuntimeDxeEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ ReportStatusCodeRouterRuntimeDxe.c
+ ReportStatusCodeRouterRuntimeDxe.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiRuntimeLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ HobLib
+ DebugLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiRscHandlerProtocolGuid ## PRODUCES
+ gEfiStatusCodeRuntimeProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ReportStatusCodeRouterRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.uni
new file mode 100644
index 000000000..480cd5167
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Report Status Code Router Driver which produces Report Stataus Code Handler Protocol and Status Code Runtime Protocol.
+//
+// Report Status Code Router Driver that produces Report Status Code Handler Protocol and Status Code Runtime Protocol.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces Report Status Code Handler Protocol and Status Code Runtime Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Report Status Code Router Driver that produces Report Status Code Handler Protocol and Status Code Runtime Protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxeExtra.uni
new file mode 100644
index 000000000..1085a4921
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ReportStatusCodeRouterRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Routing DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c
new file mode 100644
index 000000000..c3ab5cd05
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c
@@ -0,0 +1,233 @@
+/** @file
+ Report Status Code Router Driver which produces SMM Report Stataus Code Handler Protocol
+ and SMM Status Code Protocol.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ReportStatusCodeRouterSmm.h"
+
+LIST_ENTRY mCallbackListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackListHead);
+
+//
+// Report operation nest status.
+// If it is set, then the report operation has nested.
+//
+UINT32 mStatusCodeNestStatus = 0;
+
+EFI_SMM_STATUS_CODE_PROTOCOL mSmmStatusCodeProtocol = {
+ ReportDispatcher
+};
+
+EFI_SMM_RSC_HANDLER_PROTOCOL mSmmRscHandlerProtocol = {
+ Register,
+ Unregister
+ };
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called
+ when a call to ReportStatusCode() occurs.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_SMM_RSC_HANDLER_CALLBACK Callback
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
+ CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ if (CallbackEntry->RscHandlerCallback == Callback) {
+ //
+ // If the function was already registered. It can't be registered again.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ CallbackEntry = (SMM_RSC_HANDLER_CALLBACK_ENTRY *)AllocatePool (sizeof (SMM_RSC_HANDLER_CALLBACK_ENTRY));
+ ASSERT (CallbackEntry != NULL);
+
+ CallbackEntry->Signature = SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
+ CallbackEntry->RscHandlerCallback = Callback;
+
+ InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ ReportStatusCode() messages will no longer be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_SMM_RSC_HANDLER_CALLBACK Callback
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
+ CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ if (CallbackEntry->RscHandlerCallback == Callback) {
+ //
+ // If the function is found in list, delete it and return.
+ //
+ RemoveEntryList (&CallbackEntry->Node);
+ FreePool (CallbackEntry);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Provides an interface that a software module can call to report a status code.
+
+ @param This EFI_SMM_STATUS_CODE_PROTOCOL instance.
+ @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.
+ @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 CONST EFI_SMM_STATUS_CODE_PROTOCOL *This,
+ 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
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
+
+ //
+ // 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;
+ }
+
+ for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link);) {
+ CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
+ //
+ // The handler may remove itself, so get the next handler in advance.
+ //
+ Link = GetNextNode (&mCallbackListHead, Link);
+ CallbackEntry->RscHandlerCallback (
+ Type,
+ Value,
+ Instance,
+ (EFI_GUID*)CallerId,
+ Data
+ );
+
+ }
+
+ //
+ // Restore the nest status of report
+ //
+ InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of Generic Status Code Driver.
+
+ This function is the entry point of SMM Status Code Router .
+ It produces SMM Report Stataus Code Handler and Status Code protocol.
+
+ @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
+GenericStatusCodeSmmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+
+ //
+ // Install SmmRscHandler Protocol
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEfiSmmRscHandlerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install SmmStatusCode Protocol
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEfiSmmStatusCodeProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmStatusCodeProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.h b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.h
new file mode 100644
index 000000000..f8c48c62e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.h
@@ -0,0 +1,103 @@
+/** @file
+ Internal include file for Report Status Code Router Driver.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __REPORT_STATUS_CODE_ROUTER_SMM_H__
+#define __REPORT_STATUS_CODE_ROUTER_SMM_H__
+
+
+#include <Protocol/SmmReportStatusCodeHandler.h>
+#include <Protocol/SmmStatusCode.h>
+
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE SIGNATURE_32 ('s', 'h', 'c', 'e')
+
+typedef struct {
+ UINTN Signature;
+ EFI_SMM_RSC_HANDLER_CALLBACK RscHandlerCallback;
+ LIST_ENTRY Node;
+} SMM_RSC_HANDLER_CALLBACK_ENTRY;
+
+/**
+ Register the callback function for ReportStatusCode() notification.
+
+ When this function is called the function pointer is added to an internal list and any future calls to
+ ReportStatusCode() will be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called
+ when a call to ReportStatusCode() occurs.
+
+ @retval EFI_SUCCESS Function was successfully registered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_OUT_OF_RESOURCES The internal buffer ran out of space. No more functions can be
+ registered.
+ @retval EFI_ALREADY_STARTED The function was already registered. It can't be registered again.
+
+**/
+EFI_STATUS
+EFIAPI
+Register (
+ IN EFI_SMM_RSC_HANDLER_CALLBACK Callback
+ );
+
+/**
+ Remove a previously registered callback function from the notification list.
+
+ ReportStatusCode() messages will no longer be forwarded to the Callback function.
+
+ @param[in] Callback A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be
+ unregistered.
+
+ @retval EFI_SUCCESS The function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER The callback function was NULL.
+ @retval EFI_NOT_FOUND The callback function was not found to be unregistered.
+
+**/
+EFI_STATUS
+EFIAPI
+Unregister (
+ IN EFI_SMM_RSC_HANDLER_CALLBACK Callback
+ );
+
+/**
+ Provides an interface that a software module can call to report a status code.
+
+ @param This EFI_SMM_STATUS_CODE_PROTOCOL instance.
+ @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.
+ @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 CONST EFI_SMM_STATUS_CODE_PROTOCOL *This,
+ 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/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf
new file mode 100644
index 000000000..46fdcb7bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf
@@ -0,0 +1,51 @@
+## @file
+# Report Status Code Router Driver which produces SMM Report Stataus Code Handler Protocol and SMM Status Code Protocol.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ReportStatusCodeRouterSmm
+ MODULE_UNI_FILE = ReportStatusCodeRouterSmm.uni
+ FILE_GUID = A6885402-D022-4b0e-A509-4711B90F2A39
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GenericStatusCodeSmmEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ReportStatusCodeRouterSmm.c
+ ReportStatusCodeRouterSmm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseLib
+ SynchronizationLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiSmmRscHandlerProtocolGuid ## PRODUCES
+ gEfiSmmStatusCodeProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ReportStatusCodeRouterSmmExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.uni
new file mode 100644
index 000000000..b65f8b6d2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Report Status Code Router Driver which produces SMM Report Stataus Code Handler Protocol and SMM Status Code Protocol.
+//
+// Report Status Code Router Driver that produces SMM Report Status Code Handler Protocol and SMM Status Code Protocol.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces SMM Report Status Code Handler Protocol and SMM Status Code Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Report Status Code Router Driver that produces SMM Report Status Code Handler Protocol and SMM Status Code Protocol."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmmExtra.uni b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmmExtra.uni
new file mode 100644
index 000000000..771c47a38
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmmExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ReportStatusCodeRouterSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Routing SMM Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c
new file mode 100644
index 000000000..ce90c8625
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.c
@@ -0,0 +1,362 @@
+/** @file
+ Implementation of Reset2, ResetFilter and ResetHandler PPIs.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ResetSystem.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mResetTypeStr[] = {
+ L"Cold", L"Warm", L"Shutdown", L"PlatformSpecific"
+};
+
+EFI_PEI_RESET2_PPI mPpiReset2 = {
+ ResetSystem2
+};
+
+EFI_GUID *mProcessingOrder[] = {
+ &gEdkiiPlatformSpecificResetFilterPpiGuid,
+ &gEdkiiPlatformSpecificResetNotificationPpiGuid,
+ &gEdkiiPlatformSpecificResetHandlerPpiGuid
+};
+
+RESET_FILTER_INSTANCE mResetFilter = {
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ &gEdkiiPlatformSpecificResetFilterPpiGuid
+};
+
+RESET_FILTER_INSTANCE mResetNotification = {
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ &gEdkiiPlatformSpecificResetNotificationPpiGuid
+};
+
+RESET_FILTER_INSTANCE mResetHandler = {
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ &gEdkiiPlatformSpecificResetHandlerPpiGuid
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListReset[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiReset2PpiGuid,
+ &mPpiReset2
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEdkiiPlatformSpecificResetFilterPpiGuid,
+ &mResetFilter.ResetFilter
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEdkiiPlatformSpecificResetNotificationPpiGuid,
+ &mResetNotification.ResetFilter
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEdkiiPlatformSpecificResetHandlerPpiGuid,
+ &mResetHandler.ResetFilter
+ }
+};
+
+/**
+ Register a notification function to be called when ResetSystem() is called.
+
+ The RegisterResetNotify() function registers a notification function that is called when
+ ResetSystem() is called and prior to completing the reset of the platform.
+ The registered functions must not perform a platform reset themselves. These
+ notifications are intended only for the notification of components which may need some
+ special-purpose maintenance prior to the platform resetting.
+ The list of registered reset notification functions are processed if ResetSystem()is called
+ before ExitBootServices(). The list of registered reset notification functions is ignored if
+ ResetSystem() is called after ExitBootServices().
+
+ @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
+ @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
+
+ @retval EFI_SUCCESS The reset notification function was successfully registered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
+ @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterResetNotify (
+ IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ )
+{
+ RESET_FILTER_INSTANCE *ResetFilter;
+ RESET_FILTER_LIST *List;
+ VOID *Hob;
+ UINTN Index;
+
+ if (ResetFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ResetFilter = (RESET_FILTER_INSTANCE *) This;
+ ASSERT (CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
+ CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
+ CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
+ );
+
+ Hob = GetFirstGuidHob (ResetFilter->Guid);
+ if (Hob == NULL) {
+ //
+ // When the GUIDed HOB doesn't exist, create it.
+ //
+ List = (RESET_FILTER_LIST *)BuildGuidHob (
+ ResetFilter->Guid,
+ sizeof (RESET_FILTER_LIST) + sizeof (EFI_RESET_SYSTEM) * PcdGet32 (PcdMaximumPeiResetNotifies)
+ );
+ if (List == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ List->Signature = RESET_FILTER_LIST_SIGNATURE;
+ List->Count = PcdGet32 (PcdMaximumPeiResetNotifies);
+ ZeroMem (List->ResetFilters, sizeof (EFI_RESET_SYSTEM) * List->Count);
+ List->ResetFilters[0] = ResetFunction;
+ return EFI_SUCCESS;
+ } else {
+ List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
+ ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
+ //
+ // Firstly check whether the ResetFunction is already registerred.
+ //
+ for (Index = 0; Index < List->Count; Index++) {
+ if (List->ResetFilters[Index] == ResetFunction) {
+ break;
+ }
+ }
+ if (Index != List->Count) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Secondly find the first free slot.
+ //
+ for (Index = 0; Index < List->Count; Index++) {
+ if (List->ResetFilters[Index] == NULL) {
+ break;
+ }
+ }
+
+ if (Index == List->Count) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ List->ResetFilters[Index] = ResetFunction;
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Unregister a notification function.
+
+ The UnregisterResetNotify() function removes the previously registered
+ notification using RegisterResetNotify().
+
+ @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
+ @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
+
+ @retval EFI_SUCCESS The reset notification function was unregistered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
+ registered using RegisterResetNotify().
+
+**/
+EFI_STATUS
+EFIAPI
+UnregisterResetNotify (
+ IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ )
+{
+
+ RESET_FILTER_INSTANCE *ResetFilter;
+ RESET_FILTER_LIST *List;
+ VOID *Hob;
+ UINTN Index;
+
+ if (ResetFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ResetFilter = (RESET_FILTER_INSTANCE *)This;
+ ASSERT (CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
+ CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
+ CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
+ );
+
+ Hob = GetFirstGuidHob (ResetFilter->Guid);
+ if (Hob == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
+ ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
+ for (Index = 0; Index < List->Count; Index++) {
+ if (List->ResetFilters[Index] == ResetFunction) {
+ break;
+ }
+ }
+
+ if (Index == List->Count) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ List->ResetFilters[Index] = NULL;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The PEIM's entry point.
+
+ It initializes the Reset2, ResetFilter and ResetHandler PPIs.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval EFI_ALREADY_STARTED The Reset2 PPI was already installed.
+ @retval others Status code returned from PeiServicesInstallPpi().
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeResetSystem (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ VOID *Ppi;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReset2PpiGuid, 0, NULL, (VOID **)&Ppi);
+ if (Status != EFI_NOT_FOUND) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ PeiServicesInstallPpi (mPpiListReset);
+
+ return Status;
+}
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+**/
+VOID
+EFIAPI
+ResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ VOID *Hob;
+ UINTN Index;
+ RESET_FILTER_LIST *List;
+ UINTN OrderIndex;
+ UINT8 RecursionDepth;
+ UINT8 *RecursionDepthPointer;
+
+ //
+ // The recursion depth is stored in GUIDed HOB using gEfiCallerIdGuid.
+ //
+ Hob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (Hob == NULL) {
+ RecursionDepth = 0;
+ RecursionDepthPointer = BuildGuidDataHob (&gEfiCallerIdGuid, &RecursionDepth, sizeof (RecursionDepth));
+ } else {
+ RecursionDepthPointer = (UINT8 *)GET_GUID_HOB_DATA (Hob);
+ }
+ //
+ // Only do REPORT_STATUS_CODE() on first call to ResetSystem()
+ //
+ if (*RecursionDepthPointer == 0) {
+ //
+ // Indicate reset system PEI service is called.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_SERVICE | EFI_SW_PS_PC_RESET_SYSTEM));
+ }
+
+ //
+ // Increase the call depth
+ //
+ (*RecursionDepthPointer)++;
+ DEBUG ((DEBUG_INFO, "PEI ResetSystem2: Reset call depth = %d.\n", *RecursionDepthPointer));
+
+ if (*RecursionDepthPointer <= MAX_RESET_NOTIFY_DEPTH) {
+ //
+ // Iteratively call Reset Filters and Reset Handlers.
+ //
+ for (OrderIndex = 0; OrderIndex < ARRAY_SIZE (mProcessingOrder); OrderIndex++) {
+ Hob = GetFirstGuidHob (mProcessingOrder[OrderIndex]);
+ if (Hob != NULL) {
+ List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
+ ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
+
+ for (Index = 0; Index < List->Count; Index++) {
+ if (List->ResetFilters[Index] != NULL) {
+ List->ResetFilters[Index] (ResetType, ResetStatus, DataSize, ResetData);
+ }
+ }
+ }
+ }
+ } else {
+ ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));
+ DEBUG ((DEBUG_ERROR, "PEI ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));
+ }
+
+ switch (ResetType) {
+ case EfiResetWarm:
+ ResetWarm ();
+ break;
+
+ case EfiResetCold:
+ ResetCold ();
+ break;
+
+ case EfiResetShutdown:
+ ResetShutdown ();
+ return ;
+
+ case EfiResetPlatformSpecific:
+ ResetPlatformSpecific (DataSize, ResetData);
+ return;
+
+ default:
+ return ;
+ }
+
+ //
+ // Given we should have reset getting here would be bad
+ //
+ ASSERT (FALSE);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.h b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.h
new file mode 100644
index 000000000..4d49a308a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystem.h
@@ -0,0 +1,121 @@
+/** @file
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RESET_SYSTEM2_H_
+#define _RESET_SYSTEM2_H_
+
+
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Ppi/Reset2.h>
+#include <Ppi/PlatformSpecificResetFilter.h>
+#include <Ppi/PlatformSpecificResetNotification.h>
+#include <Ppi/PlatformSpecificResetHandler.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+
+//
+// The maximum recursion depth to ResetSystem() by reset notification handlers
+//
+#define MAX_RESET_NOTIFY_DEPTH 10
+
+//
+// Data to put in GUIDed HOB
+//
+typedef struct {
+ UINT32 Signature;
+ UINT32 Count;
+ EFI_RESET_SYSTEM ResetFilters[0]; // ResetFilters[PcdGet32 (PcdMaximumResetNotifies)]
+} RESET_FILTER_LIST;
+#define RESET_FILTER_LIST_SIGNATURE SIGNATURE_32('r', 's', 't', 'l')
+
+
+typedef struct {
+ EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI ResetFilter;
+ EFI_GUID *Guid;
+} RESET_FILTER_INSTANCE;
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+
+**/
+VOID
+EFIAPI
+ResetSystem2 (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ );
+/**
+ Register a notification function to be called when ResetSystem() is called.
+
+ The RegisterResetNotify() function registers a notification function that is called when
+ ResetSystem()is called and prior to completing the reset of the platform.
+ The registered functions must not perform a platform reset themselves. These
+ notifications are intended only for the notification of components which may need some
+ special-purpose maintenance prior to the platform resetting.
+
+ @param[in] This A pointer to the EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI instance.
+ @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
+
+ @retval EFI_SUCCESS The reset notification function was successfully registered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
+ @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterResetNotify (
+ IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ );
+
+/**
+ Unregister a notification function.
+
+ The UnregisterResetNotify() function removes the previously registered
+ notification using RegisterResetNotify().
+
+ @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
+ @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
+
+ @retval EFI_SUCCESS The reset notification function was unregistered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
+ registered using RegisterResetNotify().
+
+**/
+EFI_STATUS
+EFIAPI
+UnregisterResetNotify (
+ IN EFI_RESET_NOTIFICATION_PROTOCOL *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ );
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf
new file mode 100644
index 000000000..89f48bc49
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf
@@ -0,0 +1,57 @@
+## @file
+# This driver implements Reset2, ResetFilter and ResetHandler PPIs.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ResetSystemPei
+ MODULE_UNI_FILE = ResetSystemPei.uni
+ FILE_GUID = 6141E486-7543-4F1A-A579-FF532ED78E75
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeResetSystem
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ResetSystem.h
+ ResetSystem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ PeiServicesLib
+ HobLib
+ PeimEntryPoint
+ ResetSystemLib
+ ReportStatusCodeLib
+
+[Ppis]
+ gEfiPeiReset2PpiGuid ## PRODUCES
+ gEdkiiPlatformSpecificResetFilterPpiGuid ## PRODUCES
+ gEdkiiPlatformSpecificResetHandlerPpiGuid ## PRODUCES
+ gEdkiiPlatformSpecificResetNotificationPpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaximumPeiResetNotifies
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ResetSystemPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.uni b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.uni
new file mode 100644
index 000000000..7f67a71be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// This driver implements Reset2, ResetFilter and ResetHandler PPIs.
+//
+// Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements Reset2, ResetFilter and ResetHandler PPIs"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver implements Reset2, ResetFilter and ResetHandler PPIs."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPeiExtra.uni
new file mode 100644
index 000000000..7891bd050
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemPei/ResetSystemPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ResetSystemPei Localized Strings and Content
+//
+// Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Reset System PEIM"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c
new file mode 100644
index 000000000..77aedcba6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.c
@@ -0,0 +1,313 @@
+/** @file
+ Reset Architectural and Reset Notification protocols implementation.
+
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "ResetSystem.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mResetTypeStr[] = {
+ L"Cold", L"Warm", L"Shutdown", L"PlatformSpecific"
+};
+
+//
+// The current ResetSystem() notification recursion depth
+//
+UINTN mResetNotifyDepth = 0;
+
+/**
+ Register a notification function to be called when ResetSystem() is called.
+
+ The RegisterResetNotify() function registers a notification function that is called when
+ ResetSystem()is called and prior to completing the reset of the platform.
+ The registered functions must not perform a platform reset themselves. These
+ notifications are intended only for the notification of components which may need some
+ special-purpose maintenance prior to the platform resetting.
+ The list of registered reset notification functions are processed if ResetSystem()is called
+ before ExitBootServices(). The list of registered reset notification functions is ignored if
+ ResetSystem()is called after ExitBootServices().
+
+ @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
+ @param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
+
+ @retval EFI_SUCCESS The reset notification function was successfully registered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
+ @retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterResetNotify (
+ IN EFI_RESET_NOTIFICATION_PROTOCOL *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ )
+{
+ RESET_NOTIFICATION_INSTANCE *Instance;
+ LIST_ENTRY *Link;
+ RESET_NOTIFY_ENTRY *Entry;
+
+ if (ResetFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);
+
+ for ( Link = GetFirstNode (&Instance->ResetNotifies)
+ ; !IsNull (&Instance->ResetNotifies, Link)
+ ; Link = GetNextNode (&Instance->ResetNotifies, Link)
+ ) {
+ Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);
+ if (Entry->ResetNotify == ResetFunction) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ ASSERT (IsNull (&Instance->ResetNotifies, Link));
+ Entry = AllocatePool (sizeof (*Entry));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Entry->Signature = RESET_NOTIFY_ENTRY_SIGNATURE;
+ Entry->ResetNotify = ResetFunction;
+ InsertTailList (&Instance->ResetNotifies, &Entry->Link);
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister a notification function.
+
+ The UnregisterResetNotify() function removes the previously registered
+ notification using RegisterResetNotify().
+
+ @param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
+ @param[in] ResetFunction The pointer to the ResetFunction being unregistered.
+
+ @retval EFI_SUCCESS The reset notification function was unregistered.
+ @retval EFI_INVALID_PARAMETER ResetFunction is NULL.
+ @retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
+ registered using RegisterResetNotify().
+
+**/
+EFI_STATUS
+EFIAPI
+UnregisterResetNotify (
+ IN EFI_RESET_NOTIFICATION_PROTOCOL *This,
+ IN EFI_RESET_SYSTEM ResetFunction
+ )
+{
+ RESET_NOTIFICATION_INSTANCE *Instance;
+ LIST_ENTRY *Link;
+ RESET_NOTIFY_ENTRY *Entry;
+
+ if (ResetFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = RESET_NOTIFICATION_INSTANCE_FROM_THIS (This);
+
+ for ( Link = GetFirstNode (&Instance->ResetNotifies)
+ ; !IsNull (&Instance->ResetNotifies, Link)
+ ; Link = GetNextNode (&Instance->ResetNotifies, Link)
+ ) {
+ Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);
+ if (Entry->ResetNotify == ResetFunction) {
+ RemoveEntryList (&Entry->Link);
+ FreePool (Entry);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+RESET_NOTIFICATION_INSTANCE mResetNotification = {
+ RESET_NOTIFICATION_INSTANCE_SIGNATURE,
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ INITIALIZE_LIST_HEAD_VARIABLE (mResetNotification.ResetNotifies)
+};
+
+RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetFilter = {
+ RESET_NOTIFICATION_INSTANCE_SIGNATURE,
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetFilter.ResetNotifies)
+};
+
+RESET_NOTIFICATION_INSTANCE mPlatformSpecificResetHandler = {
+ RESET_NOTIFICATION_INSTANCE_SIGNATURE,
+ {
+ RegisterResetNotify,
+ UnregisterResetNotify
+ },
+ INITIALIZE_LIST_HEAD_VARIABLE (mPlatformSpecificResetHandler.ResetNotifies)
+};
+
+/**
+ The driver's entry point.
+
+ It initializes the Reset Architectural Protocol.
+
+ @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 Cannot install ResetArch protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeResetSystem (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Make sure the Reset Architectural Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid);
+
+ //
+ // Hook the runtime service table
+ //
+ gRT->ResetSystem = RuntimeServiceResetSystem;
+
+ //
+ // Now install the Reset RT AP on a new handle
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiResetArchProtocolGuid, NULL,
+ &gEfiResetNotificationProtocolGuid, &mResetNotification.ResetNotification,
+ &gEdkiiPlatformSpecificResetFilterProtocolGuid, &mPlatformSpecificResetFilter.ResetNotification,
+ &gEdkiiPlatformSpecificResetHandlerProtocolGuid, &mPlatformSpecificResetHandler.ResetNotification,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+**/
+VOID
+EFIAPI
+RuntimeServiceResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ RESET_NOTIFY_ENTRY *Entry;
+
+ //
+ // Only do REPORT_STATUS_CODE() on first call to RuntimeServiceResetSystem()
+ //
+ if (mResetNotifyDepth == 0) {
+ //
+ // Indicate reset system runtime service is called.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_RESET_SYSTEM));
+ }
+
+ mResetNotifyDepth++;
+ DEBUG ((
+ DEBUG_INFO, "DXE ResetSystem2: ResetType %s, Call Depth = %d.\n",
+ mResetTypeStr[ResetType], mResetNotifyDepth
+ ));
+
+ if (mResetNotifyDepth <= MAX_RESET_NOTIFY_DEPTH) {
+ if (!EfiAtRuntime ()) {
+ //
+ // Call reset notification functions registered through the
+ // EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PROTOCOL.
+ //
+ for ( Link = GetFirstNode (&mPlatformSpecificResetFilter.ResetNotifies)
+ ; !IsNull (&mPlatformSpecificResetFilter.ResetNotifies, Link)
+ ; Link = GetNextNode (&mPlatformSpecificResetFilter.ResetNotifies, Link)
+ ) {
+ Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);
+ Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);
+ }
+ //
+ // Call reset notification functions registered through the
+ // EFI_RESET_NOTIFICATION_PROTOCOL.
+ //
+ for ( Link = GetFirstNode (&mResetNotification.ResetNotifies)
+ ; !IsNull (&mResetNotification.ResetNotifies, Link)
+ ; Link = GetNextNode (&mResetNotification.ResetNotifies, Link)
+ ) {
+ Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);
+ Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);
+ }
+ //
+ // call reset notification functions registered through the
+ // EDKII_PLATFORM_SPECIFIC_RESET_HANDLER_PROTOCOL.
+ //
+ for ( Link = GetFirstNode (&mPlatformSpecificResetHandler.ResetNotifies)
+ ; !IsNull (&mPlatformSpecificResetHandler.ResetNotifies, Link)
+ ; Link = GetNextNode (&mPlatformSpecificResetHandler.ResetNotifies, Link)
+ ) {
+ Entry = RESET_NOTIFY_ENTRY_FROM_LINK (Link);
+ Entry->ResetNotify (ResetType, ResetStatus, DataSize, ResetData);
+ }
+ }
+ } else {
+ ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));
+ DEBUG ((DEBUG_ERROR, "DXE ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));
+ }
+
+ switch (ResetType) {
+ case EfiResetWarm:
+
+ ResetWarm ();
+ break;
+
+ case EfiResetCold:
+ ResetCold ();
+ break;
+
+ case EfiResetShutdown:
+ ResetShutdown ();
+ return ;
+
+ case EfiResetPlatformSpecific:
+ ResetPlatformSpecific (DataSize, ResetData);
+ return;
+
+ default:
+ return ;
+ }
+
+ //
+ // Given we should have reset getting here would be bad
+ //
+ ASSERT (FALSE);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.h b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.h
new file mode 100644
index 000000000..87d9c572a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystem.h
@@ -0,0 +1,98 @@
+/** @file
+
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RESET_SYSTEM_H_
+#define _RESET_SYSTEM_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/Reset.h>
+#include <Protocol/ResetNotification.h>
+#include <Protocol/PlatformSpecificResetFilter.h>
+#include <Protocol/PlatformSpecificResetHandler.h>
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// The maximum recurstion depth to ResetSystem() by reset notification handlers
+//
+#define MAX_RESET_NOTIFY_DEPTH 10
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_RESET_SYSTEM ResetNotify;
+} RESET_NOTIFY_ENTRY;
+#define RESET_NOTIFY_ENTRY_SIGNATURE SIGNATURE_32('r', 's', 't', 'n')
+#define RESET_NOTIFY_ENTRY_FROM_LINK(a) CR (a, RESET_NOTIFY_ENTRY, Link, RESET_NOTIFY_ENTRY_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ EFI_RESET_NOTIFICATION_PROTOCOL ResetNotification;
+ LIST_ENTRY ResetNotifies;
+} RESET_NOTIFICATION_INSTANCE;
+#define RESET_NOTIFICATION_INSTANCE_SIGNATURE SIGNATURE_32('r', 's', 't', 'i')
+#define RESET_NOTIFICATION_INSTANCE_FROM_THIS(a) \
+ CR (a, RESET_NOTIFICATION_INSTANCE, ResetNotification, RESET_NOTIFICATION_INSTANCE_SIGNATURE)
+
+/**
+ The driver's entry point.
+
+ It initializes the Reset Architectural Protocol.
+
+ @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 Cannot install ResetArch protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeResetSystem (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Resets the entire platform.
+
+ @param[in] ResetType The type of reset to perform.
+ @param[in] ResetStatus The status code for the reset.
+ @param[in] DataSize The size, in bytes, of ResetData.
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ string, optionally followed by additional binary data.
+ The string is a description that the caller may use to further
+ indicate the reason for the system reset.
+ For a ResetType of EfiResetPlatformSpecific the data buffer
+ also starts with a Null-terminated string that is followed
+ by an EFI_GUID that describes the specific type of reset to perform.
+
+**/
+VOID
+EFIAPI
+RuntimeServiceResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN VOID *ResetData OPTIONAL
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
new file mode 100644
index 000000000..a11e38b5b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# This driver implements Reset Architectural and Reset Notification protocols.
+#
+# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ResetSystemRuntimeDxe
+ MODULE_UNI_FILE = ResetSystemRuntimeDxe.uni
+ FILE_GUID = 4B28E4C7-FF36-4e10-93CF-A82159E777C5
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeResetSystem
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ ResetSystem.h
+ ResetSystem.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ResetSystemLib
+ UefiRuntimeServicesTableLib
+ UefiRuntimeLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ DebugLib
+ BaseLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+
+
+[Protocols]
+ gEfiResetArchProtocolGuid ## PRODUCES
+ gEfiResetNotificationProtocolGuid ## PRODUCES
+ gEdkiiPlatformSpecificResetFilterProtocolGuid ## PRODUCES
+ gEdkiiPlatformSpecificResetHandlerProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ ResetSystemRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.uni
new file mode 100644
index 000000000..504029da6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// This driver implements Reset Architectural and Reset Notification protocols.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements Reset Architectural and Reset Notification protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver implements Reset Architectural and Reset Notification protocols."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxeExtra.uni
new file mode 100644
index 000000000..f799dad2b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// ResetSystemRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Reset System DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.c b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.c
new file mode 100644
index 000000000..8cf464155
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.c
@@ -0,0 +1,354 @@
+/** @file
+ Section Extraction DXE Driver
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/GuidedSectionExtraction.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+//
+// Module global for the Section Extraction Protocol handle
+//
+EFI_HANDLE mSectionExtractionHandle = NULL;
+
+//
+// Module global for the Section Extraction Protocol instance
+//
+EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
+ CustomGuidedSectionExtract
+};
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ VOID *ScratchBuffer;
+ VOID *AllocatedOutputBuffer;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+ AllocatedOutputBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize > 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePool (ScratchBufferSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
+ if (AllocatedOutputBuffer == NULL) {
+ FreePool (ScratchBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Call decode function to extract raw data from the guided section.
+ //
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ if (AllocatedOutputBuffer != NULL) {
+ FreePool (AllocatedOutputBuffer);
+ }
+ if (ScratchBuffer != NULL) {
+ FreePool (ScratchBuffer);
+ }
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (*OutputBuffer != AllocatedOutputBuffer) {
+ //
+ // OutputBuffer was returned as a different value,
+ // so copy section contents to the allocated memory buffer.
+ //
+ CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Set real size of output buffer.
+ //
+ *OutputSize = (UINTN) OutputBufferSize;
+
+ //
+ // Free unused scratch buffer.
+ //
+ if (ScratchBuffer != NULL) {
+ FreePool (ScratchBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry for the Section Extraction DXE module.
+
+ This routine registers the Section Extraction Protocols that have been registered
+ with the Section Extraction Library.
+
+ @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
+SectionExtractionDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ //
+ // Install custom guided extraction protocol
+ //
+ while (ExtractHandlerNumber-- > 0) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSectionExtractionHandle,
+ &ExtractHandlerGuidTable [ExtractHandlerNumber], &mCustomGuidedSectionExtractionProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
new file mode 100644
index 000000000..aa3f56e3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
@@ -0,0 +1,43 @@
+## @file
+# Section Extraction DXE Driver
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SectionExtractionDxe
+ FILE_GUID = A0E8E04C-9B5A-43be-8B7D-C98760492B68
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SectionExtractionDxeEntry
+ MODULE_UNI_FILE = SectionExtractionDxe.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SectionExtractionDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ ExtractGuidedSectionLib
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SectionExtractionDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni
new file mode 100644
index 000000000..4e4548191
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Section Extraction DXE Driver
+//
+// Produces the Section Extraction Protocol required to load modules from firmware volumes that may use compression, signing, or encryption.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Section Extraction DXE Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Produces the Section Extraction Protocol required to load modules from firmware volumes that may use compression, signing, or encryption."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni
new file mode 100644
index 000000000..7e745893a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// Section Extraction DXE Module Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Section Extraction DXE"
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.c b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.c
new file mode 100644
index 000000000..8b0c3fdcc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.c
@@ -0,0 +1,263 @@
+/** @file
+ Section Extraction PEIM
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/GuidedSectionExtraction.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+ The ExtractSection() function processes the input section and
+ returns a pointer to the section contents. If the section being
+ extracted does not require processing (if the section
+ GuidedSectionHeader.Attributes has the
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
+ OutputBuffer is just updated to point to the start of the
+ section's contents. Otherwise, *Buffer must be allocated
+ from PEI permanent memory.
+
+ @param This Indicates the
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
+ Buffer containing the input GUIDed section to be
+ processed. OutputBuffer OutputBuffer is
+ allocated from PEI permanent memory and contains
+ the new section stream.
+ @param InputSection A pointer to the input buffer, which contains
+ the input section to be processed.
+ @param OutputBuffer A pointer to a caller-allocated buffer, whose
+ size is specified by the contents of OutputSize.
+ @param OutputSize A pointer to a caller-allocated
+ UINTN in which the size of *OutputBuffer
+ allocation is stored. If the function
+ returns anything other than EFI_SUCCESS,
+ the value of OutputSize is undefined.
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's GuidedSectionHeader.
+ Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear,
+ AuthenticationStatus must return
+ zero. These bits reflect the
+ status of the extraction
+ operation. If the function
+ returns anything other than
+ EFI_SUCCESS, the value of
+ AuthenticationStatus is
+ undefined.
+
+ @retval EFI_SUCCESS The InputSection was
+ successfully processed and the
+ section contents were returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+//
+// Module global for the Section Extraction PPI instance
+//
+CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
+ CustomGuidedSectionExtract
+};
+
+/**
+ The ExtractSection() function processes the input section and
+ returns a pointer to the section contents. If the section being
+ extracted does not require processing (if the section
+ GuidedSectionHeader.Attributes has the
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
+ OutputBuffer is just updated to point to the start of the
+ section's contents. Otherwise, *Buffer must be allocated
+ from PEI permanent memory.
+
+ @param This Indicates the
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
+ Buffer containing the input GUIDed section to be
+ processed. OutputBuffer OutputBuffer is
+ allocated from PEI permanent memory and contains
+ the new section stream.
+ @param InputSection A pointer to the input buffer, which contains
+ the input section to be processed.
+ @param OutputBuffer A pointer to a caller-allocated buffer, whose
+ size is specified by the contents of OutputSize.
+ @param OutputSize A pointer to a caller-allocated
+ UINTN in which the size of *OutputBuffer
+ allocation is stored. If the function
+ returns anything other than EFI_SUCCESS,
+ the value of OutputSize is undefined.
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's GuidedSectionHeader.
+ Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear,
+ AuthenticationStatus must return
+ zero. These bits reflect the
+ status of the extraction
+ operation. If the function
+ returns anything other than
+ EFI_SUCCESS, the value of
+ AuthenticationStatus is
+ undefined.
+
+ @retval EFI_SUCCESS The InputSection was
+ successfully processed and the
+ section contents were returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *ScratchBuffer;
+ UINT32 ScratchBufferSize;
+ UINT32 OutputBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize != 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize));
+ if (*OutputBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
+ }
+
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ *OutputSize = (UINTN) OutputBufferSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry for Section Extraction PEIM driver.
+
+ This routine registers the Section Extraction PPIs that have been registered
+ with the Section Extraction Library.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+SectionExtractionPeiEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+ EFI_PEI_PPI_DESCRIPTOR *GuidPpi;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ //
+ // Install custom extraction guid PPI
+ //
+ if (ExtractHandlerNumber > 0) {
+ GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
+ ASSERT (GuidPpi != NULL);
+ while (ExtractHandlerNumber-- > 0) {
+ GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+ GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi;
+ GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber];
+ Status = PeiServicesInstallPpi (GuidPpi++);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.inf b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.inf
new file mode 100644
index 000000000..b3874359a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.inf
@@ -0,0 +1,44 @@
+## @file
+# Section Extraction PEI Module
+#
+# Produce one or more Section Extraction PPIs.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SectionExtractionPei
+ FILE_GUID = EED5EA31-38E2-463d-B623-2C57702B8A1C
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SectionExtractionPeiEntry
+ MODULE_UNI_FILE = SectionExtractionPei.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ SectionExtractionPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ ExtractGuidedSectionLib
+ DebugLib
+ MemoryAllocationLib
+ PeiServicesLib
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SectionExtractionPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.uni b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.uni
new file mode 100644
index 000000000..85ff6f44a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Section Extraction PEI Module
+//
+// Produce one or more Section Extraction PPIs.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Section Extraction PEI Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Produces the Section Extraction PPI required to load modules from firmware volumes that may use compression, signing, or encryption."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPeiExtra.uni
new file mode 100644
index 000000000..374bbab8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SectionExtractionPei/SectionExtractionPeiExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// Section Extraction PEIM Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Section Extraction PEI"
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
new file mode 100644
index 000000000..6a5f4a3b9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.c
@@ -0,0 +1,408 @@
+/** @file
+ Implement defer image load services for user identification in UEFI2.2.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Defer3rdPartyImageLoad.h"
+
+//
+// The structure to save the deferred 3rd party image information.
+//
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ BOOLEAN BootOption;
+ BOOLEAN Loaded;
+} DEFERRED_3RD_PARTY_IMAGE_INFO;
+
+//
+// The table to save the deferred 3rd party image item.
+//
+typedef struct {
+ UINTN Count; ///< deferred 3rd party image count
+ DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo; ///< deferred 3rd party image item
+} DEFERRED_3RD_PARTY_IMAGE_TABLE;
+
+BOOLEAN mImageLoadedAfterEndOfDxe = FALSE;
+BOOLEAN mEndOfDxe = FALSE;
+DEFERRED_3RD_PARTY_IMAGE_TABLE mDeferred3rdPartyImage = {
+ 0, // Deferred image count
+ NULL // The deferred image info
+};
+
+EFI_DEFERRED_IMAGE_LOAD_PROTOCOL mDeferredImageLoad = {
+ GetDefferedImageInfo
+};
+
+/**
+ Return whether the file comes from FV.
+
+ @param[in] File This is a pointer to the device path of the file
+ that is being dispatched.
+
+ @retval TRUE File comes from FV.
+ @retval FALSE File doesn't come from FV.
+**/
+BOOLEAN
+FileFromFv (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Find the deferred image which matches the device path.
+
+ @param[in] ImageDevicePath A pointer to the device path of a image.
+ @param[in] BootOption Whether the image is a boot option.
+
+ @return Pointer to the found deferred image or NULL if not found.
+**/
+DEFERRED_3RD_PARTY_IMAGE_INFO *
+LookupImage (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,
+ IN BOOLEAN BootOption
+ )
+{
+ UINTN Index;
+ UINTN DevicePathSize;
+
+ DevicePathSize = GetDevicePathSize (ImageDevicePath);
+
+ for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {
+ if (CompareMem (ImageDevicePath, mDeferred3rdPartyImage.ImageInfo[Index].ImageDevicePath, DevicePathSize) == 0) {
+ ASSERT (mDeferred3rdPartyImage.ImageInfo[Index].BootOption == BootOption);
+ return &mDeferred3rdPartyImage.ImageInfo[Index];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Add the image info to a deferred image list.
+
+ @param[in] ImageDevicePath A pointer to the device path of a image.
+ @param[in] BootOption Whether the image is a boot option.
+
+**/
+VOID
+QueueImage (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,
+ IN BOOLEAN BootOption
+ )
+{
+ DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo;
+
+ //
+ // Expand memory for the new deferred image.
+ //
+ ImageInfo = ReallocatePool (
+ mDeferred3rdPartyImage.Count * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),
+ (mDeferred3rdPartyImage.Count + 1) * sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO),
+ mDeferred3rdPartyImage.ImageInfo
+ );
+ if (ImageInfo == NULL) {
+ return;
+ }
+ mDeferred3rdPartyImage.ImageInfo = ImageInfo;
+
+ //
+ // Save the deferred image information.
+ //
+ ImageInfo = &mDeferred3rdPartyImage.ImageInfo[mDeferred3rdPartyImage.Count];
+ ImageInfo->ImageDevicePath = DuplicateDevicePath (ImageDevicePath);
+ if (ImageInfo->ImageDevicePath == NULL) {
+ return;
+ }
+ ImageInfo->BootOption = BootOption;
+ ImageInfo->Loaded = FALSE;
+ mDeferred3rdPartyImage.Count++;
+}
+
+
+/**
+ Returns information about a deferred image.
+
+ This function returns information about a single deferred image. The deferred images are
+ numbered consecutively, starting with 0. If there is no image which corresponds to
+ ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by
+ iteratively calling this function until EFI_NOT_FOUND is returned.
+ Image may be NULL and ImageSize set to 0 if the decision to defer execution was made
+ because of the location of the executable image, rather than its actual contents.
+
+ @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+ @param[in] ImageIndex Zero-based index of the deferred index.
+ @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.
+ The device path should not be freed by the caller.
+ @param[out] Image On return, points to the first byte of the image or NULL if the
+ image is not available. The image should not be freed by the caller
+ unless LoadImage() has been successfully called.
+ @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.
+ @param[out] BootOption On return, points to TRUE if the image was intended as a boot option
+ or FALSE if it was not intended as a boot option.
+
+ @retval EFI_SUCCESS Image information returned successfully.
+ @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.
+ @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or
+ BootOption is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDefferedImageInfo (
+ IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,
+ IN UINTN ImageIndex,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize,
+ OUT BOOLEAN *BootOption
+ )
+{
+ UINTN Index;
+ UINTN NewCount;
+
+ if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ImageDevicePath == NULL) || (BootOption == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Remove the loaded images from the defer list in the first call.
+ //
+ if (ImageIndex == 0) {
+ NewCount = 0;
+ for (Index = 0; Index < mDeferred3rdPartyImage.Count; Index++) {
+ if (!mDeferred3rdPartyImage.ImageInfo[Index].Loaded) {
+ CopyMem (
+ &mDeferred3rdPartyImage.ImageInfo[NewCount],
+ &mDeferred3rdPartyImage.ImageInfo[Index],
+ sizeof (DEFERRED_3RD_PARTY_IMAGE_INFO)
+ );
+ NewCount++;
+ }
+ }
+
+ mDeferred3rdPartyImage.Count = NewCount;
+ }
+
+ if (ImageIndex >= mDeferred3rdPartyImage.Count) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the request deferred image.
+ //
+ *ImageDevicePath = mDeferred3rdPartyImage.ImageInfo[ImageIndex].ImageDevicePath;
+ *BootOption = mDeferred3rdPartyImage.ImageInfo[ImageIndex].BootOption;
+ *Image = NULL;
+ *ImageSize = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+EndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
+
+/**
+ Event notification for gEfiDxeSmmReadyToLockProtocolGuid event.
+
+ This function reports failure if any deferred image is loaded before
+ this callback.
+ Platform should publish ReadyToLock protocol immediately after signaling
+ of the End of DXE Event.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+DxeSmmReadyToLock (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ gBS->CloseEvent (Event);
+
+ if (mImageLoadedAfterEndOfDxe) {
+ //
+ // Platform should not dispatch the 3rd party images after signaling EndOfDxe event
+ // but before publishing DxeSmmReadyToLock protocol.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "[Security] 3rd party images must be dispatched after DxeSmmReadyToLock Protocol installation!\n"
+ ));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)
+ );
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
+}
+
+/**
+ Defer the 3rd party image load and installs Deferred Image Load Protocol.
+
+ @param[in] File This is a pointer to the device path of the file that
+ is being dispatched. This will optionally be used for
+ logging.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file is not 3rd party image and can be loaded immediately.
+ @retval EFI_ACCESS_DENIED The file is 3rd party image and needs deferred.
+**/
+EFI_STATUS
+Defer3rdPartyImageLoad (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN BOOLEAN BootPolicy
+ )
+{
+ DEFERRED_3RD_PARTY_IMAGE_INFO *ImageInfo;
+
+ //
+ // Ignore if File is NULL.
+ //
+ if (File == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (FileFromFv (File)) {
+ return EFI_SUCCESS;
+ }
+
+ ImageInfo = LookupImage (File, BootPolicy);
+
+ DEBUG_CODE (
+ CHAR16 *DevicePathStr;
+ DevicePathStr = ConvertDevicePathToText (File, FALSE, FALSE);
+ DEBUG ((
+ DEBUG_INFO,
+ "[Security] 3rd party image[%p] %s EndOfDxe: %s.\n", ImageInfo,
+ mEndOfDxe ? L"can be loaded after": L"is deferred to load before",
+ DevicePathStr
+ ));
+ if (DevicePathStr != NULL) {
+ FreePool (DevicePathStr);
+ }
+ );
+
+ if (mEndOfDxe) {
+ mImageLoadedAfterEndOfDxe = TRUE;
+ //
+ // The image might be first time loaded after EndOfDxe,
+ // So ImageInfo can be NULL.
+ //
+ if (ImageInfo != NULL) {
+ ImageInfo->Loaded = TRUE;
+ }
+ return EFI_SUCCESS;
+ } else {
+ //
+ // The image might be second time loaded before EndOfDxe,
+ // So ImageInfo can be non-NULL.
+ //
+ if (ImageInfo == NULL) {
+ QueueImage (File, BootPolicy);
+ }
+ return EFI_ACCESS_DENIED;
+ }
+}
+
+/**
+ Installs DeferredImageLoad Protocol and listens EndOfDxe event.
+**/
+VOID
+Defer3rdPartyImageLoadInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_EVENT Event;
+ VOID *Registration;
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiDeferredImageLoadProtocolGuid,
+ &mDeferredImageLoad,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_CALLBACK,
+ DxeSmmReadyToLock,
+ NULL,
+ &Registration
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.h b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.h
new file mode 100644
index 000000000..8986b3d8d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/Defer3rdPartyImageLoad.h
@@ -0,0 +1,89 @@
+/** @file
+ Implement defer image load services for user identification in UEFI2.2.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEFER_3RD_PARTY_IMAGE_LOAD_H_
+#define _DEFER_3RD_PARTY_IMAGE_LOAD_H_
+
+#include <PiDxe.h>
+#include <Guid/EventGroup.h>
+#include <Protocol/DeferredImageLoad.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+/**
+ Returns information about a deferred image.
+
+ This function returns information about a single deferred image. The deferred images are
+ numbered consecutively, starting with 0. If there is no image which corresponds to
+ ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by
+ iteratively calling this function until EFI_NOT_FOUND is returned.
+ Image may be NULL and ImageSize set to 0 if the decision to defer execution was made
+ because of the location of the executable image, rather than its actual contents.
+
+ @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+ @param[in] ImageIndex Zero-based index of the deferred index.
+ @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.
+ The device path should not be freed by the caller.
+ @param[out] Image On return, points to the first byte of the image or NULL if the
+ image is not available. The image should not be freed by the caller
+ unless LoadImage() has been successfully called.
+ @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.
+ @param[out] BootOption On return, points to TRUE if the image was intended as a boot option
+ or FALSE if it was not intended as a boot option.
+
+ @retval EFI_SUCCESS Image information returned successfully.
+ @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.
+ @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or
+ BootOption is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDefferedImageInfo (
+ IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,
+ IN UINTN ImageIndex,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize,
+ OUT BOOLEAN *BootOption
+ );
+
+/**
+ Defer the 3rd party image load and installs Deferred Image Load Protocol.
+
+ @param[in] File This is a pointer to the device path of the file that
+ is being dispatched. This will optionally be used for
+ logging.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file is not 3rd party image and can be loaded immediately.
+ @retval EFI_ACCESS_DENIED The file is 3rd party image and needs deferred.
+**/
+EFI_STATUS
+Defer3rdPartyImageLoad (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN BOOLEAN BootPolicy
+ );
+
+/**
+ Installs DeferredImageLoad Protocol and listens EndOfDxe event.
+**/
+VOID
+Defer3rdPartyImageLoadInitialize (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStub.c b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStub.c
new file mode 100644
index 000000000..79f98b28e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStub.c
@@ -0,0 +1,210 @@
+/** @file
+ This driver produces Security2 and Security architectural protocol based on SecurityManagementLib.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Uefi.h>
+#include <Protocol/Security.h>
+#include <Protocol/Security2.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/SecurityManagementLib.h>
+#include "Defer3rdPartyImageLoad.h"
+
+//
+// Handle for the Security Architectural Protocol instance produced by this driver
+//
+EFI_HANDLE mSecurityArchProtocolHandle = NULL;
+
+/**
+ The EFI_SECURITY_ARCH_PROTOCOL (SAP) is used to abstract platform-specific
+ policy from the DXE core response to an attempt to use a file that returns a
+ given status for the authentication check from the section extraction protocol.
+
+ The possible responses in a given SAP implementation may include locking
+ flash upon failure to authenticate, attestation logging for all signed drivers,
+ and other exception operations. The File parameter allows for possible logging
+ within the SAP of the driver.
+
+ If File is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
+ then EFI_ACCESS_DENIED is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use right now, but it
+ might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
+ returned.
+
+ @param This The EFI_SECURITY_ARCH_PROTOCOL instance.
+ @param AuthenticationStatus
+ This is the authentication type returned from the Section
+ Extraction protocol. See the Section Extraction Protocol
+ Specification for details on this type.
+ @param File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+
+ @retval EFI_SUCCESS Do nothing and return success.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+**/
+EFI_STATUS
+EFIAPI
+SecurityStubAuthenticateState (
+ IN CONST EFI_SECURITY_ARCH_PROTOCOL *This,
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ExecuteSecurity2Handlers (EFI_AUTH_OPERATION_AUTHENTICATION_STATE,
+ AuthenticationStatus,
+ File,
+ NULL,
+ 0,
+ FALSE
+ );
+ if (Status == EFI_SUCCESS) {
+ Status = ExecuteSecurityHandlers (AuthenticationStatus, File);
+ }
+
+ return Status;
+}
+
+/**
+ The DXE Foundation uses this service to measure and/or verify a UEFI image.
+
+ This service abstracts the invocation of Trusted Computing Group (TCG) measured boot, UEFI
+ Secure boot, and UEFI User Identity infrastructure. For the former two, the DXE Foundation
+ invokes the FileAuthentication() with a DevicePath and corresponding image in
+ FileBuffer memory. The TCG measurement code will record the FileBuffer contents into the
+ appropriate PCR. The image verification logic will confirm the integrity and provenance of the
+ image in FileBuffer of length FileSize . The origin of the image will be DevicePath in
+ these cases.
+ If the FileBuffer is NULL, the interface will determine if the DevicePath can be connected
+ in order to support the User Identification policy.
+
+ @param This The EFI_SECURITY2_ARCH_PROTOCOL instance.
+ @param File A pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param FileBuffer A pointer to the buffer with the UEFI file image.
+ @param FileSize The size of the file.
+ @param BootPolicy A boot policy that was used to call LoadImage() UEFI service. If
+ FileAuthentication() is invoked not from the LoadImage(),
+ BootPolicy must be set to FALSE.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SECURITY_VIOLATION The file specified by DevicePath and FileBuffer did not
+ authenticate, and the platform policy dictates that the file should be
+ placed in the untrusted state. The image has been added to the file
+ execution table.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation many not use File.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+**/
+EFI_STATUS
+EFIAPI
+Security2StubAuthenticate (
+ IN CONST EFI_SECURITY2_ARCH_PROTOCOL *This,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ EFI_STATUS Status;
+
+ if (FileBuffer != NULL) {
+ Status = Defer3rdPartyImageLoad (File, BootPolicy);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return ExecuteSecurity2Handlers (EFI_AUTH_OPERATION_VERIFY_IMAGE |
+ EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD |
+ EFI_AUTH_OPERATION_MEASURE_IMAGE |
+ EFI_AUTH_OPERATION_CONNECT_POLICY,
+ 0,
+ File,
+ FileBuffer,
+ FileSize,
+ BootPolicy
+ );
+}
+
+//
+// Security2 and Security Architectural Protocol instance produced by this driver
+//
+EFI_SECURITY_ARCH_PROTOCOL mSecurityStub = {
+ SecurityStubAuthenticateState
+};
+
+EFI_SECURITY2_ARCH_PROTOCOL mSecurity2Stub = {
+ Security2StubAuthenticate
+};
+
+/**
+ Installs Security2 and Security Architectural Protocol.
+
+ @param ImageHandle The image handle of this driver.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Install the sample Security Architectural Protocol successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityStubInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure the Security Architectural Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiSecurity2ArchProtocolGuid);
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiSecurityArchProtocolGuid);
+
+ //
+ // Install the Security Architectural Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSecurityArchProtocolHandle,
+ &gEfiSecurity2ArchProtocolGuid,
+ &mSecurity2Stub,
+ &gEfiSecurityArchProtocolGuid,
+ &mSecurityStub,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Defer3rdPartyImageLoadInitialize ();
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
new file mode 100644
index 000000000..32c6b13e9
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# This driver produces security2 and security architectural protocol based on SecurityManagementLib.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecurityStubDxe
+ MODULE_UNI_FILE = SecurityStubDxe.uni
+ FILE_GUID = F80697E9-7FD6-4665-8646-88E33EF71DFC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SecurityStubInitialize
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ SecurityStub.c
+ Defer3rdPartyImageLoad.c
+ Defer3rdPartyImageLoad.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ SecurityManagementLib
+ ReportStatusCodeLib
+ UefiLib
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiSecurityArchProtocolGuid ## PRODUCES
+ gEfiSecurity2ArchProtocolGuid ## PRODUCES
+ gEfiDeferredImageLoadProtocolGuid ## PRODUCES
+ gEfiDxeSmmReadyToLockProtocolGuid ## NOTIFY
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SecurityStubDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.uni b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.uni
new file mode 100644
index 000000000..7727eb599
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver produces security2 and security architectural protocol based on SecurityManagementLib.
+//
+// This driver produces security2 and security architectural protocol based on SecurityManagementLib.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces security2 and security architectural protocol based on SecurityManagementLib"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces security2 and security architectural protocol based on SecurityManagementLib."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxeExtra.uni
new file mode 100644
index 000000000..270b5bf3a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SecurityStubDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Security Stub DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
new file mode 100644
index 000000000..9337440c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
@@ -0,0 +1,49 @@
+## @file
+# Serial driver that layers on top of a Serial Port Library instance.
+#
+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SerialDxe
+ MODULE_UNI_FILE = SerialDxe.uni
+ FILE_GUID = 9A5163E7-5C29-453F-825C-837A46A81E15
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = SerialDxeInitialize
+
+[Sources.common]
+ SerialIo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ PcdLib
+ SerialPortLib
+
+[Protocols]
+ gEfiSerialIoProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultReceiveFifoDepth ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SerialDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni
new file mode 100644
index 000000000..fc7d30af0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Serial driver that layers on top of a Serial Port Library instance.
+//
+// Serial driver that layers on top of a Serial Port Library instance.
+//
+// Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Serial driver that layers on top of a Serial Port Library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Serial driver that layers on top of a Serial Port Library instance."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni
new file mode 100644
index 000000000..579adf6ab
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SerialDxe Localized Strings and Content
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SerialDxe Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialIo.c b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialIo.c
new file mode 100644
index 000000000..fb816a161
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SerialDxe/SerialIo.c
@@ -0,0 +1,562 @@
+/** @file
+ Serial driver that layers on top of a Serial Port Library instance.
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Guid/SerialPortLibVendor.h>
+
+typedef struct {
+ VENDOR_DEVICE_PATH Guid;
+ UART_DEVICE_PATH Uart;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} SERIAL_DEVICE_PATH;
+
+/**
+ Reset the serial device.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ );
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
+ data bits, and stop bits on a serial device.
+
+ @param This Protocol instance pointer.
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
+ device's default interface speed.
+ @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
+ serial interface. A ReceiveFifoDepth value of 0 will use
+ the device's default FIFO depth.
+ @param Timeout The requested time out for a single character in microseconds.
+ This timeout applies to both the transmit and receive side of the
+ interface. A Timeout value of 0 will use the device's default time
+ out value.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ value of 0 will use the device's default data bit setting.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ 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 the control bits on a serial device
+
+ @param This Protocol instance pointer.
+ @param Control Set the bits of Control that are settable.
+
+ @retval EFI_SUCCESS The new control bits were set on the serial device.
+ @retval EFI_UNSUPPORTED The serial device does not support this operation.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ );
+
+/**
+ Retrieves the status of the control bits on a serial device
+
+ @param This Protocol instance pointer.
+ @param Control A pointer to return the current Control signals from the serial device.
+
+ @retval EFI_SUCCESS The control bits were read from the serial device.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ );
+
+/**
+ Writes data to a serial device.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of
+ data actually written.
+ @param Buffer The buffer of data to write
+
+ @retval EFI_SUCCESS The data was written.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The data write was stopped due to a timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads data from a serial device.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of
+ data returned in Buffer.
+ @param Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data was read.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The data write was stopped due to a timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_HANDLE mSerialHandle = NULL;
+
+SERIAL_DEVICE_PATH mSerialDevicePath = {
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },
+ EDKII_SERIAL_PORT_LIB_VENDOR_GUID
+ },
+ {
+ { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },
+ 0, // Reserved
+ 0, // BaudRate
+ 0, // DataBits
+ 0, // Parity
+ 0 // StopBits
+ },
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
+};
+
+//
+// Template used to initialize the Serial IO protocols.
+//
+EFI_SERIAL_IO_MODE mSerialIoMode = {
+ //
+ // value field set in SerialDxeInitialize()?
+ //--------- ------------------- -----------------------------
+ 0, // ControlMask
+ 1000 * 1000, // Timeout
+ 0, // BaudRate yes
+ 1, // ReceiveFifoDepth
+ 0, // DataBits yes
+ 0, // Parity yes
+ 0 // StopBits yes
+};
+
+EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {
+ SERIAL_IO_INTERFACE_REVISION,
+ SerialReset,
+ SerialSetAttributes,
+ SerialSetControl,
+ SerialGetControl,
+ SerialWrite,
+ SerialRead,
+ &mSerialIoMode
+};
+
+/**
+ Reset the serial device.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The serial device could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SerialPortInitialize ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 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
+ );
+
+ //
+ // The serial device may not support some of the attributes. To prevent
+ // later failure, always return EFI_SUCCESS when SetAttributes is returning
+ // EFI_INVALID_PARAMETER.
+ //
+ if (Status == EFI_INVALID_PARAMETER) {
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
+ data bits, and stop bits on a serial device.
+
+ @param This Protocol instance pointer.
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
+ device's default interface speed.
+ @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
+ serial interface. A ReceiveFifoDepth value of 0 will use
+ the device's default FIFO depth.
+ @param Timeout The requested time out for a single character in microseconds.
+ This timeout applies to both the transmit and receive side of the
+ interface. A Timeout value of 0 will use the device's default time
+ out value.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ value of 0 will use the device's default data bit setting.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ 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;
+ EFI_TPL Tpl;
+ UINT64 OriginalBaudRate;
+ UINT32 OriginalReceiveFifoDepth;
+ UINT32 OriginalTimeout;
+ EFI_PARITY_TYPE OriginalParity;
+ UINT8 OriginalDataBits;
+ EFI_STOP_BITS_TYPE OriginalStopBits;
+
+ //
+ // Preserve the original input values in case
+ // SerialPortSetAttributes() updates the input/output
+ // parameters even on error.
+ //
+ OriginalBaudRate = BaudRate;
+ OriginalReceiveFifoDepth = ReceiveFifoDepth;
+ OriginalTimeout = Timeout;
+ OriginalParity = Parity;
+ OriginalDataBits = DataBits;
+ OriginalStopBits = StopBits;
+ Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);
+ if (EFI_ERROR (Status)) {
+ //
+ // If it is just to set Timeout value and unsupported is returned,
+ // do not return error.
+ //
+ if ((Status == EFI_UNSUPPORTED) &&
+ (This->Mode->Timeout != OriginalTimeout) &&
+ (This->Mode->ReceiveFifoDepth == OriginalReceiveFifoDepth) &&
+ (This->Mode->BaudRate == OriginalBaudRate) &&
+ (This->Mode->DataBits == (UINT32) OriginalDataBits) &&
+ (This->Mode->Parity == (UINT32) OriginalParity) &&
+ (This->Mode->StopBits == (UINT32) OriginalStopBits)) {
+ //
+ // Restore to the original input values.
+ //
+ BaudRate = OriginalBaudRate;
+ ReceiveFifoDepth = OriginalReceiveFifoDepth;
+ Timeout = OriginalTimeout;
+ Parity = OriginalParity;
+ DataBits = OriginalDataBits;
+ StopBits = OriginalStopBits;
+ Status = EFI_SUCCESS;
+ } else if (Status == EFI_INVALID_PARAMETER || Status == EFI_UNSUPPORTED) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Set the Serial I/O mode and update the device path
+ //
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Set the Serial I/O mode
+ //
+ This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
+ This->Mode->Timeout = Timeout;
+ This->Mode->BaudRate = BaudRate;
+ This->Mode->DataBits = (UINT32) DataBits;
+ This->Mode->Parity = (UINT32) Parity;
+ This->Mode->StopBits = (UINT32) StopBits;
+
+ //
+ // Check if the device path has actually changed
+ //
+ if (mSerialDevicePath.Uart.BaudRate == BaudRate &&
+ mSerialDevicePath.Uart.DataBits == DataBits &&
+ mSerialDevicePath.Uart.Parity == (UINT8) Parity &&
+ mSerialDevicePath.Uart.StopBits == (UINT8) StopBits
+ ) {
+ gBS->RestoreTPL (Tpl);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Update the device path
+ //
+ mSerialDevicePath.Uart.BaudRate = BaudRate;
+ mSerialDevicePath.Uart.DataBits = DataBits;
+ mSerialDevicePath.Uart.Parity = (UINT8) Parity;
+ mSerialDevicePath.Uart.StopBits = (UINT8) StopBits;
+
+ Status = gBS->ReinstallProtocolInterface (
+ mSerialHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mSerialDevicePath,
+ &mSerialDevicePath
+ );
+
+ gBS->RestoreTPL (Tpl);
+
+ return Status;
+}
+
+/**
+ Set the control bits on a serial device
+
+ @param This Protocol instance pointer.
+ @param Control Set the bits of Control that are settable.
+
+ @retval EFI_SUCCESS The new control bits were set on the serial device.
+ @retval EFI_UNSUPPORTED The serial device does not support this operation.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ )
+{
+ return SerialPortSetControl (Control);
+}
+
+/**
+ Retrieves the status of the control bits on a serial device
+
+ @param This Protocol instance pointer.
+ @param Control A pointer to return the current Control signals from the serial device.
+
+ @retval EFI_SUCCESS The control bits were read from the serial device.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ )
+{
+ return SerialPortGetControl (Control);
+}
+
+/**
+ Writes data to a serial device.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of
+ data actually written.
+ @param Buffer The buffer of data to write
+
+ @retval EFI_SUCCESS The data was written.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The data write was stopped due to a timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ UINTN Count;
+
+ Count = SerialPortWrite (Buffer, *BufferSize);
+
+ if (Count != *BufferSize) {
+ *BufferSize = Count;
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads data from a serial device.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input, the size of the Buffer. On output, the amount of
+ data returned in Buffer.
+ @param Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data was read.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The data write was stopped due to a timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN Count;
+ UINTN TimeOut;
+
+ Count = 0;
+
+ while (Count < *BufferSize) {
+ TimeOut = 0;
+ while (TimeOut < mSerialIoMode.Timeout) {
+ if (SerialPortPoll ()) {
+ break;
+ }
+ gBS->Stall (10);
+ TimeOut += 10;
+ }
+ if (TimeOut >= mSerialIoMode.Timeout) {
+ break;
+ }
+ SerialPortRead (Buffer, 1);
+ Count++;
+ Buffer = (VOID *) ((UINT8 *) Buffer + 1);
+ }
+
+ if (Count != *BufferSize) {
+ *BufferSize = Count;
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for the Serial Io Protocol.
+
+ @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
+SerialDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);
+ mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);
+ mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);
+ mSerialIoMode.ReceiveFifoDepth = PcdGet16 (PcdUartDefaultReceiveFifoDepth);
+ mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);
+ mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);
+
+ //
+ // Issue a reset to initialize the Serial Port
+ //
+ Status = mSerialIoTemplate.Reset (&mSerialIoTemplate);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Make a new handle with Serial IO protocol and its device path on it.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSerialHandle,
+ &gEfiSerialIoProtocolGuid, &mSerialIoTemplate,
+ &gEfiDevicePathProtocolGuid, &mSerialDevicePath,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
new file mode 100644
index 000000000..d273d2aac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
@@ -0,0 +1,3734 @@
+/** @file
+Utility functions for expression evaluation.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Setup.h"
+
+//
+// Global stack used to evaluate boolean expresions
+//
+EFI_HII_VALUE *mOpCodeScopeStack = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
+
+EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
+UINTN mExpressionEvaluationStackOffset = 0;
+
+EFI_HII_VALUE *mCurrentExpressionStack = NULL;
+EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
+EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
+
+EFI_HII_VALUE *mMapExpressionListStack = NULL;
+EFI_HII_VALUE *mMapExpressionListEnd = NULL;
+EFI_HII_VALUE *mMapExpressionListPointer = NULL;
+
+FORM_EXPRESSION **mFormExpressionStack = NULL;
+FORM_EXPRESSION **mFormExpressionEnd = NULL;
+FORM_EXPRESSION **mFormExpressionPointer = NULL;
+
+FORM_EXPRESSION **mStatementExpressionStack = NULL;
+FORM_EXPRESSION **mStatementExpressionEnd = NULL;
+FORM_EXPRESSION **mStatementExpressionPointer = NULL;
+
+FORM_EXPRESSION **mOptionExpressionStack = NULL;
+FORM_EXPRESSION **mOptionExpressionEnd = NULL;
+FORM_EXPRESSION **mOptionExpressionPointer = NULL;
+
+
+//
+// Unicode collation protocol interface
+//
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;
+
+/**
+ Grow size of the stack.
+
+ This is an internal function.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+
+ @retval EFI_SUCCESS Grow stack success.
+ @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
+
+**/
+EFI_STATUS
+GrowStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd
+ )
+{
+ UINTN Size;
+ EFI_HII_VALUE *NewStack;
+
+ Size = EXPRESSION_STACK_SIZE_INCREMENT;
+ if (*StackPtr != NULL) {
+ Size = Size + (*StackEnd - *Stack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*StackPtr != NULL) {
+ //
+ // Copy from Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ *Stack,
+ (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (*Stack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ *StackPtr = NewStack + (*StackPtr - *Stack);
+ *Stack = NewStack;
+ *StackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+ @param Data Data to push.
+
+ @retval EFI_SUCCESS Push stack success.
+
+**/
+EFI_STATUS
+PushStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd,
+ IN EFI_HII_VALUE *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (*StackPtr >= *StackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowStack (Stack, StackPtr, StackEnd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
+ if (Data->Type == EFI_IFR_TYPE_BUFFER) {
+ (*StackPtr)->Buffer = AllocateCopyPool(Data->BufferLen, Data->Buffer);
+ ASSERT ((*StackPtr)->Buffer != NULL);
+ }
+
+ *StackPtr = *StackPtr + 1;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop an element from the stack.
+
+ @param Stack On input: old stack
+ @param StackPtr On input: old stack pointer; On output: new stack pointer
+ @param Data Data to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopStack (
+ IN EFI_HII_VALUE *Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ OUT EFI_HII_VALUE *Data
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (*StackPtr == Stack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ *StackPtr = *StackPtr - 1;
+ CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ )
+{
+ mCurrentExpressionPointer = mCurrentExpressionStack;
+ mFormExpressionPointer = mFormExpressionStack;
+ mStatementExpressionPointer = mStatementExpressionStack;
+ mOptionExpressionPointer = mOptionExpressionStack;
+}
+
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &mCurrentExpressionEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ )
+{
+ mMapExpressionListPointer = mMapExpressionListStack;
+}
+
+
+/**
+ Grow size of the stack.
+
+ This is an internal function.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+ @param MemberSize The stack member size.
+
+ @retval EFI_SUCCESS Grow stack success.
+ @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
+
+**/
+EFI_STATUS
+GrowConditionalStack (
+ IN OUT FORM_EXPRESSION ***Stack,
+ IN OUT FORM_EXPRESSION ***StackPtr,
+ IN OUT FORM_EXPRESSION ***StackEnd,
+ IN UINTN MemberSize
+ )
+{
+ UINTN Size;
+ FORM_EXPRESSION **NewStack;
+
+ Size = EXPRESSION_STACK_SIZE_INCREMENT;
+ if (*StackPtr != NULL) {
+ Size = Size + (*StackEnd - *Stack);
+ }
+
+ NewStack = AllocatePool (Size * MemberSize);
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*StackPtr != NULL) {
+ //
+ // Copy from Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ *Stack,
+ (*StackEnd - *Stack) * MemberSize
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (*Stack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ *StackPtr = NewStack + (*StackPtr - *Stack);
+ *Stack = NewStack;
+ *StackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Push an element onto the Stack.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+ @param Data Data to push.
+
+ @retval EFI_SUCCESS Push stack success.
+
+**/
+EFI_STATUS
+PushConditionalStack (
+ IN OUT FORM_EXPRESSION ***Stack,
+ IN OUT FORM_EXPRESSION ***StackPtr,
+ IN OUT FORM_EXPRESSION ***StackEnd,
+ IN FORM_EXPRESSION **Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (*StackPtr >= *StackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ CopyMem (*StackPtr, Data, sizeof (FORM_EXPRESSION *));
+ *StackPtr = *StackPtr + 1;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Pop an element from the stack.
+
+ @param Stack On input: old stack
+ @param StackPtr On input: old stack pointer; On output: new stack pointer
+ @param Data Data to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopConditionalStack (
+ IN FORM_EXPRESSION **Stack,
+ IN OUT FORM_EXPRESSION ***StackPtr,
+ OUT FORM_EXPRESSION **Data
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (*StackPtr == Stack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ *StackPtr = *StackPtr - 1;
+ CopyMem (Data, *StackPtr, sizeof (FORM_EXPRESSION *));
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Get the expression list count.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval >=0 The expression count
+ @retval -1 Input parameter error.
+
+**/
+INTN
+GetConditionalExpressionCount (
+ IN EXPRESS_LEVEL Level
+ )
+{
+ switch (Level) {
+ case ExpressForm:
+ return mFormExpressionPointer - mFormExpressionStack;
+ case ExpressStatement:
+ return mStatementExpressionPointer - mStatementExpressionStack;
+ case ExpressOption:
+ return mOptionExpressionPointer - mOptionExpressionStack;
+ default:
+ ASSERT (FALSE);
+ return -1;
+ }
+}
+
+/**
+ Get the expression Buffer pointer.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval The start pointer of the expression buffer or NULL.
+
+**/
+FORM_EXPRESSION **
+GetConditionalExpressionList (
+ IN EXPRESS_LEVEL Level
+ )
+{
+ switch (Level) {
+ case ExpressForm:
+ return mFormExpressionStack;
+ case ExpressStatement:
+ return mStatementExpressionStack;
+ case ExpressOption:
+ return mOptionExpressionStack;
+ default:
+ ASSERT (FALSE);
+ return NULL;
+ }
+}
+
+
+/**
+ Push the expression options onto the Stack.
+
+ @param Pointer Pointer to the current expression.
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushConditionalExpression (
+ IN FORM_EXPRESSION *Pointer,
+ IN EXPRESS_LEVEL Level
+ )
+{
+ switch (Level) {
+ case ExpressForm:
+ return PushConditionalStack (
+ &mFormExpressionStack,
+ &mFormExpressionPointer,
+ &mFormExpressionEnd,
+ &Pointer
+ );
+ case ExpressStatement:
+ return PushConditionalStack (
+ &mStatementExpressionStack,
+ &mStatementExpressionPointer,
+ &mStatementExpressionEnd,
+ &Pointer
+ );
+ case ExpressOption:
+ return PushConditionalStack (
+ &mOptionExpressionStack,
+ &mOptionExpressionPointer,
+ &mOptionExpressionEnd,
+ &Pointer
+ );
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Pop the expression options from the Stack
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopConditionalExpression (
+ IN EXPRESS_LEVEL Level
+ )
+{
+ FORM_EXPRESSION *Pointer;
+
+ switch (Level) {
+ case ExpressForm:
+ return PopConditionalStack (
+ mFormExpressionStack,
+ &mFormExpressionPointer,
+ &Pointer
+ );
+
+ case ExpressStatement:
+ return PopConditionalStack (
+ mStatementExpressionStack,
+ &mStatementExpressionPointer,
+ &Pointer
+ );
+
+ case ExpressOption:
+ return PopConditionalStack (
+ mOptionExpressionStack,
+ &mOptionExpressionPointer,
+ &Pointer
+ );
+
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &mMapExpressionListEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ )
+{
+ mOpCodeScopeStackPointer = mOpCodeScopeStack;
+}
+
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Data.Value.u8 = Operand;
+
+ return PushStack (
+ &mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &mOpCodeScopeStackEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &Data
+ );
+
+ *Operand = Data.Value.u8;
+
+ return Status;
+}
+
+
+/**
+ Push an Expression value onto the Stack
+
+ @param Value Expression value to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushExpression (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ return PushStack (
+ &mExpressionEvaluationStack,
+ &mExpressionEvaluationStackPointer,
+ &mExpressionEvaluationStackEnd,
+ Value
+ );
+}
+
+
+/**
+ Pop an Expression value from the stack.
+
+ @param Value Expression value to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopExpression (
+ OUT EFI_HII_VALUE *Value
+ )
+{
+ return PopStack (
+ mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
+ &mExpressionEvaluationStackPointer,
+ Value
+ );
+}
+
+/**
+ Get current stack offset from stack start.
+
+ @return Stack offset to stack start.
+**/
+UINTN
+SaveExpressionEvaluationStackOffset (
+ VOID
+ )
+{
+ UINTN TempStackOffset;
+ TempStackOffset = mExpressionEvaluationStackOffset;
+ mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
+ return TempStackOffset;
+}
+
+/**
+ Restore stack offset based on input stack offset
+
+ @param StackOffset Offset to stack start.
+
+**/
+VOID
+RestoreExpressionEvaluationStackOffset (
+ UINTN StackOffset
+ )
+{
+ mExpressionEvaluationStackOffset = StackOffset;
+}
+
+/**
+ Get Form given its FormId.
+
+ @param FormSet The formset which contains this form.
+ @param FormId Id of this form.
+
+ @retval Pointer The form.
+ @retval NULL Specified Form is not found in the formset.
+
+**/
+FORM_BROWSER_FORM *
+IdToForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT16 FormId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ if (Form->FormId == FormId) {
+ return Form;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Search a Question in Form scope using its QuestionId.
+
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion2 (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ if (QuestionId == 0 || Form == NULL) {
+ //
+ // The value of zero is reserved
+ //
+ return NULL;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Question->QuestionId == QuestionId) {
+ return Question;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Search a Question in Formset scope using its QuestionId.
+
+ @param FormSet The formset which contains this form.
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ //
+ // Search in the form scope first
+ //
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ return Question;
+ }
+
+ //
+ // Search in the formset scope
+ //
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ //
+ // EFI variable storage may be updated by Callback() asynchronous,
+ // to keep synchronous, always reload the Question Value.
+ //
+ if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
+ }
+
+ return Question;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get Expression given its RuleId.
+
+ @param Form The form which contains this Expression.
+ @param RuleId Id of this Expression.
+
+ @retval Pointer The Expression.
+ @retval NULL Specified Expression not found in the form.
+
+**/
+FORM_EXPRESSION *
+RuleIdToExpression (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT8 RuleId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ while (!IsNull (&Form->ExpressionListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+
+ if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {
+ return Expression;
+ }
+
+ Link = GetNextNode (&Form->ExpressionListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Locate the Unicode Collation Protocol interface for later use.
+
+ @retval EFI_SUCCESS Protocol interface initialize success.
+ @retval Other Protocol interface initialize failed.
+
+**/
+EFI_STATUS
+InitializeUnicodeCollationProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mUnicodeCollation != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
+ // instances first and then select one which support English language.
+ // Current implementation just pick the first instance.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID **) &mUnicodeCollation
+ );
+ return Status;
+}
+
+/**
+ Convert the input Unicode character to upper.
+
+ @param String Th Unicode character to be converted.
+
+**/
+VOID
+IfrStrToUpper (
+ IN CHAR16 *String
+ )
+{
+ while (*String != 0) {
+ if ((*String >= 'a') && (*String <= 'z')) {
+ *String = (UINT16) ((*String) & ((UINT16) ~0x20));
+ }
+ String++;
+ }
+}
+
+/**
+ Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
+
+ EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
+ EFI_IFR_TYPE_BUFFER when do the value compare.
+
+ @param Value Expression value to compare on.
+
+ @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
+ @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
+
+**/
+BOOLEAN
+IsTypeInBuffer (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_BUFFER:
+ case EFI_IFR_TYPE_DATE:
+ case EFI_IFR_TYPE_TIME:
+ case EFI_IFR_TYPE_REF:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
+
+ @param Value Expression value to compare on.
+
+ @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
+ @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
+
+**/
+BOOLEAN
+IsTypeInUINT64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ case EFI_IFR_TYPE_BOOLEAN:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Return the buffer length for this value.
+
+ EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
+ EFI_IFR_TYPE_BUFFER when do the value compare.
+
+ @param Value Expression value to compare on.
+
+ @retval BufLen Return the buffer length.
+
+**/
+UINT16
+GetLengthForValue (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_BUFFER:
+ return Value->BufferLen;
+
+ case EFI_IFR_TYPE_DATE:
+ return (UINT16) sizeof (EFI_HII_DATE);
+
+ case EFI_IFR_TYPE_TIME:
+ return (UINT16) sizeof (EFI_HII_TIME);
+
+ case EFI_IFR_TYPE_REF:
+ return (UINT16) sizeof (EFI_HII_REF);
+
+ default:
+ return 0;
+ }
+}
+
+/**
+ Return the buffer pointer for this value.
+
+ EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
+ EFI_IFR_TYPE_BUFFER when do the value compare.
+
+ @param Value Expression value to compare on.
+
+ @retval Buf Return the buffer pointer.
+
+**/
+UINT8 *
+GetBufferForValue (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_BUFFER:
+ return Value->Buffer;
+
+ case EFI_IFR_TYPE_DATE:
+ return (UINT8 *) (&Value->Value.date);
+
+ case EFI_IFR_TYPE_TIME:
+ return (UINT8 *) (&Value->Value.time);
+
+ case EFI_IFR_TYPE_REF:
+ return (UINT8 *) (&Value->Value.ref);
+
+ default:
+ return NULL;
+ }
+}
+
+/**
+ Evaluate opcode EFI_IFR_TO_STRING.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format String format in EFI_IFR_TO_STRING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToString (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ CHAR16 *PrintFormat;
+ CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
+ UINT8 *TmpBuf;
+ UINT8 *SrcBuf;
+ UINTN SrcLen;
+ UINTN BufferSize;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
+ switch (Format) {
+ case EFI_IFR_STRING_UNSIGNED_DEC:
+ case EFI_IFR_STRING_SIGNED_DEC:
+ PrintFormat = L"%ld";
+ break;
+
+ case EFI_IFR_STRING_LOWERCASE_HEX:
+ PrintFormat = L"%lx";
+ break;
+
+ case EFI_IFR_STRING_UPPERCASE_HEX:
+ PrintFormat = L"%lX";
+ break;
+
+ default:
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
+ String = Buffer;
+ break;
+
+ case EFI_IFR_TYPE_STRING:
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ String = (Value.Value.b) ? L"True" : L"False";
+ break;
+
+ case EFI_IFR_TYPE_BUFFER:
+ case EFI_IFR_TYPE_DATE:
+ case EFI_IFR_TYPE_TIME:
+ case EFI_IFR_TYPE_REF:
+ //
+ // + 3 is base on the unicode format, the length may be odd number,
+ // so need 1 byte to align, also need 2 bytes for L'\0'.
+ //
+ if (Value.Type == EFI_IFR_TYPE_BUFFER) {
+ SrcLen = Value.BufferLen;
+ SrcBuf = Value.Buffer;
+ } else {
+ SrcBuf = GetBufferForValue(&Value);
+ SrcLen = GetLengthForValue(&Value);
+ }
+
+ TmpBuf = AllocateZeroPool (SrcLen + 3);
+ ASSERT (TmpBuf != NULL);
+ if (Format == EFI_IFR_STRING_ASCII) {
+ CopyMem (TmpBuf, SrcBuf, SrcLen);
+ PrintFormat = L"%a";
+ } else {
+ // Format == EFI_IFR_STRING_UNICODE
+ CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16));
+ PrintFormat = L"%s";
+ }
+ UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf);
+ String = Buffer;
+ FreePool (TmpBuf);
+ if (Value.Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Value.Buffer);
+ }
+ break;
+
+ default:
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ Result->Value.string = NewString (String, FormSet->HiiHandle);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_TO_UINT.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToUint (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ CHAR16 *StringPtr;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value.Type >= EFI_IFR_TYPE_OTHER && !IsTypeInBuffer(&Value)) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ if (Value.Type == EFI_IFR_TYPE_STRING) {
+ String = GetToken (Value.Value.string, FormSet->HiiHandle);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ IfrStrToUpper (String);
+ StringPtr = StrStr (String, L"0X");
+ if (StringPtr != NULL) {
+ //
+ // Hex string
+ //
+ Result->Value.u64 = StrHexToUint64 (String);
+ } else {
+ //
+ // decimal string
+ //
+ Result->Value.u64 = StrDecimalToUint64 (String);
+ }
+ FreePool (String);
+ } else if (IsTypeInBuffer(&Value)) {
+ if (GetLengthForValue (&Value) > 8) {
+ if (Value.Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Value.Buffer);
+ }
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (GetBufferForValue (&Value) != NULL);
+ Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value);
+
+ if (Value.Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Value.Buffer);
+ }
+ } else {
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_CATENATE.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrCatenate (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[2];
+ CHAR16 *String[2];
+ UINTN Index;
+ CHAR16 *StringPtr;
+ UINTN Size;
+ UINT16 Length0;
+ UINT16 Length1;
+ UINT8 *TmpBuf;
+ UINTN MaxLen;
+
+ //
+ // String[0] - The second string
+ // String[1] - The first string
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ StringPtr = NULL;
+ Status = EFI_SUCCESS;
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
+ String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+ }
+
+ if (Value[0].Type == EFI_IFR_TYPE_STRING) {
+ Size = StrSize (String[0]);
+ MaxLen = (StrSize (String[1]) + Size) / sizeof (CHAR16);
+ StringPtr= AllocatePool (MaxLen * sizeof (CHAR16));
+ ASSERT (StringPtr != NULL);
+ StrCpyS (StringPtr, MaxLen, String[1]);
+ StrCatS (StringPtr, MaxLen, String[0]);
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
+ } else {
+ Result->Type = EFI_IFR_TYPE_BUFFER;
+ Length0 = GetLengthForValue(&Value[0]);
+ Length1 = GetLengthForValue(&Value[1]);
+ Result->BufferLen = (UINT16) (Length0 + Length1);
+
+ Result->Buffer = AllocateZeroPool (Result->BufferLen);
+ ASSERT (Result->Buffer != NULL);
+
+ TmpBuf = GetBufferForValue(&Value[0]);
+ ASSERT (TmpBuf != NULL);
+ CopyMem (Result->Buffer, TmpBuf, Length0);
+ TmpBuf = GetBufferForValue(&Value[1]);
+ ASSERT (TmpBuf != NULL);
+ CopyMem (&Result->Buffer[Length0], TmpBuf, Length1);
+ }
+Done:
+ if (Value[0].Buffer != NULL) {
+ FreePool (Value[0].Buffer);
+ }
+ if (Value[1].Buffer != NULL) {
+ FreePool (Value[1].Buffer);
+ }
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+ if (StringPtr != NULL) {
+ FreePool (StringPtr);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_MATCH.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMatch (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[2];
+ CHAR16 *String[2];
+ UINTN Index;
+
+ //
+ // String[0] - The string to search
+ // String[1] - pattern
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ Status = EFI_SUCCESS;
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_BOOLEAN;
+ Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_MATCH2.
+
+ @param FormSet Formset which contains this opcode.
+ @param SyntaxType Syntax type for match2.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMatch2 (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN EFI_GUID *SyntaxType,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[2];
+ CHAR16 *String[2];
+ UINTN Index;
+ UINTN GuidIndex;
+ EFI_HANDLE *HandleBuffer;
+ UINTN BufferSize;
+ EFI_REGULAR_EXPRESSION_PROTOCOL *RegularExpressionProtocol;
+ UINTN RegExSyntaxTypeListSize;
+ EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList;
+ UINTN CapturesCount;
+
+ //
+ // String[0] - The string to search
+ // String[1] - pattern
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ HandleBuffer = NULL;
+ RegExSyntaxTypeList = NULL;
+ Status = EFI_SUCCESS;
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ BufferSize = 0;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandle(
+ ByProtocol,
+ &gEfiRegularExpressionProtocolGuid,
+ NULL,
+ &BufferSize,
+ HandleBuffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HandleBuffer = AllocateZeroPool(BufferSize);
+ if (HandleBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ Status = gBS->LocateHandle(
+ ByProtocol,
+ &gEfiRegularExpressionProtocolGuid,
+ NULL,
+ &BufferSize,
+ HandleBuffer);
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ ASSERT (HandleBuffer != NULL);
+ for ( Index = 0; Index < BufferSize / sizeof(EFI_HANDLE); Index ++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiRegularExpressionProtocolGuid,
+ (VOID**)&RegularExpressionProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ RegExSyntaxTypeListSize = 0;
+ RegExSyntaxTypeList = NULL;
+
+ Status = RegularExpressionProtocol->GetInfo (
+ RegularExpressionProtocol,
+ &RegExSyntaxTypeListSize,
+ RegExSyntaxTypeList
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ RegExSyntaxTypeList = AllocateZeroPool(RegExSyntaxTypeListSize);
+ if (RegExSyntaxTypeList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ Status = RegularExpressionProtocol->GetInfo (
+ RegularExpressionProtocol,
+ &RegExSyntaxTypeListSize,
+ RegExSyntaxTypeList
+ );
+ } else if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ for (GuidIndex = 0; GuidIndex < RegExSyntaxTypeListSize / sizeof(EFI_GUID); GuidIndex++) {
+ if (CompareGuid (&RegExSyntaxTypeList[GuidIndex], SyntaxType)) {
+ //
+ // Find the match type, return the value.
+ //
+ Result->Type = EFI_IFR_TYPE_BOOLEAN;
+ Status = RegularExpressionProtocol->MatchString (
+ RegularExpressionProtocol,
+ String[0],
+ String[1],
+ SyntaxType,
+ &Result->Value.b,
+ NULL,
+ &CapturesCount
+ );
+ goto Done;
+ }
+ }
+
+ if (RegExSyntaxTypeList != NULL) {
+ FreePool (RegExSyntaxTypeList);
+ }
+ }
+
+ //
+ // Type specified by SyntaxType is not supported
+ // in any of the EFI_REGULAR_EXPRESSION_PROTOCOL instances.
+ //
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+ if (RegExSyntaxTypeList != NULL) {
+ FreePool (RegExSyntaxTypeList);
+ }
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_FIND.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format Case sensitive or insensitive.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrFind (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[3];
+ CHAR16 *String[2];
+ UINTN Base;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ ZeroMem (Value, sizeof (Value));
+
+ if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[2]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ Base = (UINTN) Value[0].Value.u64;
+
+ //
+ // String[0] - sub-string
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
+ //
+ // Case insensitive, convert both string to upper case
+ //
+ IfrStrToUpper (String[Index]);
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ if (Base >= StrLen (String[1])) {
+ Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
+ } else {
+ StringPtr = StrStr (String[1] + Base, String[0]);
+ Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
+ }
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_MID.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMid (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[3];
+ CHAR16 *String;
+ UINTN Base;
+ UINTN Length;
+ CHAR16 *SubString;
+ UINT16 BufferLen;
+ UINT8 *Buffer;
+
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[2]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ Length = (UINTN) Value[0].Value.u64;
+
+ if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ Base = (UINTN) Value[1].Value.u64;
+
+ if (Value[2].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[2])) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ if (Value[2].Type == EFI_IFR_TYPE_STRING) {
+ String = GetToken (Value[2].Value.string, FormSet->HiiHandle);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Length == 0 || Base >= StrLen (String)) {
+ SubString = gEmptyString;
+ } else {
+ SubString = String + Base;
+ if ((Base + Length) < StrLen (String)) {
+ SubString[Length] = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+ FreePool (String);
+ } else {
+ BufferLen = GetLengthForValue (&Value[2]);
+ Buffer = GetBufferForValue (&Value[2]);
+
+ Result->Type = EFI_IFR_TYPE_BUFFER;
+ if (Length == 0 || Base >= BufferLen) {
+ Result->BufferLen = 0;
+ Result->Buffer = NULL;
+ } else {
+ Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
+ Result->Buffer = AllocateZeroPool (Result->BufferLen);
+ ASSERT (Result->Buffer != NULL);
+ CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen);
+ }
+
+ if (Value[2].Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Value[2].Buffer);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_TOKEN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToken (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[3];
+ CHAR16 *String[2];
+ UINTN Count;
+ CHAR16 *Delimiter;
+ CHAR16 *SubString;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[2]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ Count = (UINTN) Value[0].Value.u64;
+
+ //
+ // String[0] - Delimiter
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Delimiter = String[0];
+ SubString = String[1];
+ while (Count > 0) {
+ SubString = StrStr (SubString, Delimiter);
+ if (SubString != NULL) {
+ //
+ // Skip over the delimiter
+ //
+ SubString = SubString + StrLen (Delimiter);
+ } else {
+ break;
+ }
+ Count--;
+ }
+
+ if (SubString == NULL) {
+ //
+ // nth delimited sub-string not found, push an empty string
+ //
+ SubString = gEmptyString;
+ } else {
+ //
+ // Put a NULL terminator for nth delimited sub-string
+ //
+ StringPtr = StrStr (SubString, Delimiter);
+ if (StringPtr != NULL) {
+ *StringPtr = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_SPAN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrSpan (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Flags,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value[3];
+ CHAR16 *String[2];
+ CHAR16 *Charset;
+ UINTN Base;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ BOOLEAN Found;
+
+ ZeroMem (Value, sizeof (Value));
+
+ Status = PopExpression (&Value[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PopExpression (&Value[2]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ return EFI_SUCCESS;
+ }
+ Base = (UINTN) Value[0].Value.u64;
+
+ //
+ // String[0] - Charset
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ if (Base >= StrLen (String[1])) {
+ Result->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ Found = FALSE;
+ StringPtr = String[1] + Base;
+ Charset = String[0];
+ while (*StringPtr != 0 && !Found) {
+ Index = 0;
+ while (Charset[Index] != 0) {
+ if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
+ if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ } else {
+ if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ }
+ //
+ // Skip characters pair representing low-end of a range and high-end of a range
+ //
+ Index += 2;
+ }
+
+ if (!Found) {
+ StringPtr++;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Result->Value.u64 = StringPtr - String[1];
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ UINT64 Temp;
+
+ Temp = 0;
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Temp = Value->Value.u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Temp = Value->Value.u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Temp = Value->Value.u32;
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ Temp = Value->Value.b;
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ Temp = Value->Value.u32 & 0xffffff;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ Temp = Value->Value.u32;
+ break;
+
+ default:
+ return;
+ }
+
+ Value->Value.u64 = Temp;
+}
+
+/**
+ Get UINT64 type value.
+
+ @param Value Input Hii value.
+
+ @retval UINT64 Return the UINT64 type value.
+
+**/
+UINT64
+HiiValueToUINT64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ UINT64 RetVal;
+
+ RetVal = 0;
+
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ RetVal = Value->Value.u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ RetVal = Value->Value.u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ RetVal = Value->Value.u32;
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ RetVal = Value->Value.b;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ RetVal = *(UINT64*) &Value->Value.date;
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
+ break;
+
+ default:
+ RetVal = Value->Value.u64;
+ break;
+ }
+
+ return RetVal;
+}
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param Result Return value after compare.
+ retval 0 Two operators equal.
+ return Positive value if Value1 is greater than Value2.
+ retval Negative value if Value1 is less than Value2.
+ @param HiiHandle Only required for string compare.
+
+ @retval other Could not perform compare on two values.
+ @retval EFI_SUCCESS Compare the value success.
+
+**/
+EFI_STATUS
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ OUT INTN *Result,
+ IN EFI_HII_HANDLE HiiHandle OPTIONAL
+ )
+{
+ INT64 Temp64;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+ UINTN Len;
+ UINT8 *Buf1;
+ UINT16 Buf1Len;
+ UINT8 *Buf2;
+ UINT16 Buf2Len;
+
+ if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
+ if (Value1->Value.string == 0 || Value2->Value.string == 0) {
+ //
+ // StringId 0 is reserved
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Value1->Value.string == Value2->Value.string) {
+ *Result = 0;
+ return EFI_SUCCESS;
+ }
+
+ Str1 = GetToken (Value1->Value.string, HiiHandle);
+ if (Str1 == NULL) {
+ //
+ // String not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ Str2 = GetToken (Value2->Value.string, HiiHandle);
+ if (Str2 == NULL) {
+ FreePool (Str1);
+ return EFI_NOT_FOUND;
+ }
+
+ *Result = StrCmp (Str1, Str2);
+
+ FreePool (Str1);
+ FreePool (Str2);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Take types(date, time, ref, buffer) as buffer
+ //
+ if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
+ Buf1 = GetBufferForValue(Value1);
+ Buf1Len = GetLengthForValue(Value1);
+ Buf2 = GetBufferForValue(Value2);
+ Buf2Len = GetLengthForValue(Value2);
+
+ Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
+ *Result = CompareMem (Buf1, Buf2, Len);
+ if ((*Result == 0) && (Buf1Len != Buf2Len)) {
+ //
+ // In this case, means base on samll number buffer, the data is same
+ // So which value has more data, which value is bigger.
+ //
+ *Result = Buf1Len > Buf2Len ? 1 : -1;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Take types(integer, boolean) as integer
+ //
+ if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
+ Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
+ if (Temp64 > 0) {
+ *Result = 1;
+ } else if (Temp64 < 0) {
+ *Result = -1;
+ } else {
+ *Result = 0;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Check if current user has the privilege specified by the permissions GUID.
+
+ @param[in] Guid A GUID specifying setup access permissions.
+
+ @retval TRUE Current user has the privilege.
+ @retval FALSE Current user does not have the privilege.
+**/
+BOOLEAN
+CheckUserPrivilege (
+ IN EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE UserProfileHandle;
+ EFI_USER_INFO_HANDLE UserInfoHandle;
+ EFI_USER_INFO *UserInfo;
+ EFI_GUID *UserPermissionsGuid;
+ UINTN UserInfoSize;
+ UINTN AccessControlDataSize;
+ EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
+ UINTN RemainSize;
+
+ if (mUserManager == NULL) {
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &mUserManager
+ );
+ if (EFI_ERROR (Status)) {
+ ///
+ /// If the system does not support user management, then it is assumed that
+ /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
+ /// op-code is always TRUE.
+ ///
+ return TRUE;
+ }
+ }
+
+ Status = mUserManager->Current (mUserManager, &UserProfileHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Enumerate all user information of the current user profile
+ /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
+ ///
+
+ for (UserInfoHandle = NULL;;) {
+ Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ UserInfoSize = 0;
+ Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ continue;
+ }
+
+ UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);
+ if (UserInfo == NULL) {
+ break;
+ }
+
+ Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
+ if (EFI_ERROR (Status) ||
+ UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||
+ UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {
+ FreePool (UserInfo);
+ continue;
+ }
+
+ RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
+ AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
+ while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
+ if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
+ break;
+ }
+ if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
+ ///
+ /// Check if current user has the privilege specified by the permissions GUID.
+ ///
+
+ UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
+ AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
+ while (AccessControlDataSize >= sizeof (EFI_GUID)) {
+ if (CompareGuid (Guid, UserPermissionsGuid)) {
+ FreePool (UserInfo);
+ return TRUE;
+ }
+ UserPermissionsGuid++;
+ AccessControlDataSize -= sizeof (EFI_GUID);
+ }
+ }
+ RemainSize -= AccessControl->Size;
+ AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
+ }
+
+ FreePool (UserInfo);
+ }
+ return FALSE;
+}
+
+/**
+ Get question value from the predefined formset.
+
+ @param DevicePath The driver's device path which produece the formset data.
+ @param InputHiiHandle The hii handle associate with the formset data.
+ @param FormSetGuid The formset guid which include the question.
+ @param QuestionId The question id which need to get value from.
+ @param Value The return data about question's value.
+
+ @retval TRUE Get the question value success.
+ @retval FALSE Get the question value failed.
+**/
+BOOLEAN
+GetQuestionValueFromForm (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_HII_HANDLE InputHiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN EFI_QUESTION_ID QuestionId,
+ OUT EFI_HII_VALUE *Value
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_FORMSET *FormSet;
+ FORM_BROWSER_FORM *Form;
+ BOOLEAN GetTheVal;
+ LIST_ENTRY *Link;
+
+ //
+ // The input parameter DevicePath or InputHiiHandle must have one valid input.
+ //
+ ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) ||
+ (DevicePath == NULL && InputHiiHandle != NULL) );
+
+ GetTheVal = TRUE;
+ HiiHandle = NULL;
+ Question = NULL;
+ Form = NULL;
+
+ //
+ // Get HiiHandle.
+ //
+ if (DevicePath != NULL) {
+ HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid);
+ if (HiiHandle == NULL) {
+ return FALSE;
+ }
+ } else {
+ HiiHandle = InputHiiHandle;
+ }
+ ASSERT (HiiHandle != NULL);
+
+ //
+ // Get the formset data include this question.
+ //
+ FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
+ ASSERT (FormSet != NULL);
+ Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);
+ if (EFI_ERROR (Status)) {
+ GetTheVal = FALSE;
+ goto Done;
+ }
+
+ //
+ // Base on the Question Id to get the question info.
+ //
+ Question = IdToQuestion(FormSet, NULL, QuestionId);
+ if (Question == NULL) {
+ GetTheVal = FALSE;
+ goto Done;
+ }
+
+ //
+ // Search form in the formset scope
+ //
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ break;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ Form = NULL;
+ }
+ ASSERT (Form != NULL);
+
+ //
+ // Get the question value.
+ //
+ Status = GetQuestionValue(FormSet, Form, Question, GetSetValueWithEditBuffer);
+ if (EFI_ERROR (Status)) {
+ GetTheVal = FALSE;
+ goto Done;
+ }
+
+ CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
+
+Done:
+ //
+ // Clean the formset structure and restore the global parameter.
+ //
+ if (FormSet != NULL) {
+ DestroyFormSet (FormSet);
+ }
+
+ return GetTheVal;
+}
+
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_STATEMENT *Question2;
+ UINT16 Index;
+ EFI_HII_VALUE Data1;
+ EFI_HII_VALUE Data2;
+ EFI_HII_VALUE Data3;
+ FORM_EXPRESSION *RuleExpression;
+ EFI_HII_VALUE *Value;
+ INTN Result;
+ CHAR16 *StrPtr;
+ CHAR16 *NameValue;
+ UINT32 TempValue;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+ UINTN StackOffset;
+ UINTN TempLength;
+ CHAR16 TempStr[5];
+ UINT8 DigitUint8;
+ UINT8 *TempBuffer;
+ EFI_TIME EfiTime;
+ EFI_HII_VALUE QuestionVal;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ StrPtr = NULL;
+
+ //
+ // Save current stack offset.
+ //
+ StackOffset = SaveExpressionEvaluationStackOffset ();
+
+ ASSERT (Expression != NULL);
+ Expression->Result.Type = EFI_IFR_TYPE_OTHER;
+
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ while (!IsNull (&Expression->OpCodeListHead, Link)) {
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+
+ Link = GetNextNode (&Expression->OpCodeListHead, Link);
+
+ ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
+
+ Value = &Data3;
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Status = EFI_SUCCESS;
+
+ switch (OpCode->Operand) {
+ //
+ // Built-in functions
+ //
+ case EFI_IFR_EQ_ID_VAL_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL);
+ if (Status == EFI_UNSUPPORTED) {
+ Status = EFI_SUCCESS;
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
+ if (Question2 == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle);
+ if (Status == EFI_UNSUPPORTED) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value->Value.b = FALSE;
+ for (Index =0; Index < OpCode->ListLength; Index++) {
+ if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
+ Value->Value.b = TRUE;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_DUP_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ case EFI_IFR_THIS_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
+ break;
+
+ case EFI_IFR_GET_OP:
+ //
+ // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
+ //
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ //
+ // Get value from Edit Buffer
+ //
+ Value->Type = OpCode->ValueType;
+ CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
+ //
+ // Get value from string except for STRING value.
+ //
+ Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (StrPtr != NULL);
+ TempLength = StrLen (StrPtr);
+ if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
+ Value->Type = OpCode->ValueType;
+ TempBuffer = (UINT8 *) &Value->Value;
+ ZeroMem (TempStr, sizeof (TempStr));
+ for (Index = 0; Index < TempLength; Index ++) {
+ TempStr[0] = StrPtr[TempLength - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TempStr);
+ if ((Index & 1) == 0) {
+ TempBuffer [Index/2] = DigitUint8;
+ } else {
+ TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ //
+ // Get value from variable.
+ //
+ TempLength = OpCode->ValueWidth;
+ Value->Type = OpCode->ValueType;
+ Status = gRT->GetVariable (
+ OpCode->ValueName,
+ &OpCode->VarStorage->Guid,
+ NULL,
+ &TempLength,
+ &Value->Value
+ );
+ if (EFI_ERROR (Status)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ }
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ } else {
+ //
+ // For Time/Date Data
+ //
+ if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
+ //
+ // Only support Data/Time data when storage doesn't exist.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ Status = gRT->GetTime (&EfiTime, NULL);
+ if (!EFI_ERROR (Status)) {
+ if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
+ switch (OpCode->VarStoreInfo.VarOffset) {
+ case 0x00:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ Value->Value.u16 = EfiTime.Year;
+ break;
+ case 0x02:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = EfiTime.Month;
+ break;
+ case 0x03:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = EfiTime.Day;
+ break;
+ default:
+ //
+ // Invalid Date field.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ } else {
+ switch (OpCode->VarStoreInfo.VarOffset) {
+ case 0x00:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = EfiTime.Hour;
+ break;
+ case 0x01:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = EfiTime.Minute;
+ break;
+ case 0x02:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = EfiTime.Second;
+ break;
+ default:
+ //
+ // Invalid Time field.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ //
+ // EFI_IFR_QUESTION_REF3
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (OpCode->DevicePath != 0) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+
+ StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
+ if (StrPtr != NULL && mPathFromText != NULL) {
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StrPtr);
+ if (DevicePath != NULL && GetQuestionValueFromForm(DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
+ Value = &QuestionVal;
+ }
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+ }
+
+ if (StrPtr != NULL) {
+ FreePool (StrPtr);
+ }
+ } else if (IsZeroGuid (&OpCode->Guid)) {
+ if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+ Value = &QuestionVal;
+ } else {
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ //
+ // push the questions' value on to the expression stack
+ //
+ Value = &Question->HiiValue;
+ }
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ //
+ // Find expression for this rule
+ //
+ RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
+ if (RuleExpression == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ //
+ // Evaluate this rule expression
+ //
+ Status = EvaluateExpression (FormSet, Form, RuleExpression);
+ if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value = &RuleExpression->Result;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ Value->Value.string = OpCode->Value.Value.string;
+ break;
+
+ //
+ // Constant
+ //
+ case EFI_IFR_TRUE_OP:
+ case EFI_IFR_FALSE_OP:
+ case EFI_IFR_ONE_OP:
+ case EFI_IFR_ONES_OP:
+ case EFI_IFR_UINT8_OP:
+ case EFI_IFR_UINT16_OP:
+ case EFI_IFR_UINT32_OP:
+ case EFI_IFR_UINT64_OP:
+ case EFI_IFR_UNDEFINED_OP:
+ case EFI_IFR_VERSION_OP:
+ case EFI_IFR_ZERO_OP:
+ Value = &OpCode->Value;
+ break;
+
+ //
+ // unary-op
+ //
+ case EFI_IFR_LENGTH_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer (Value)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (Value->Type == EFI_IFR_TYPE_STRING) {
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = StrLen (StrPtr);
+ FreePool (StrPtr);
+ } else {
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = GetLengthForValue(Value);
+ FreePool (Value->Buffer);
+ }
+ break;
+
+ case EFI_IFR_NOT_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+ Value->Value.b = (BOOLEAN) (!Value->Value.b);
+ break;
+
+ case EFI_IFR_QUESTION_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_STRING_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value->Type = EFI_IFR_TYPE_STRING;
+ StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
+ if (StrPtr == NULL) {
+ //
+ // If String not exit, push an empty string
+ //
+ Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
+ } else {
+ Index = (UINT16) Value->Value.u64;
+ Value->Value.string = Index;
+ FreePool (StrPtr);
+ }
+ break;
+
+ case EFI_IFR_TO_BOOLEAN_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Convert an expression to a Boolean
+ //
+ if (Value->Type <= EFI_IFR_TYPE_DATE) {
+ //
+ // When converting from an unsigned integer, zero will be converted to
+ // FALSE and any other value will be converted to TRUE.
+ //
+ Value->Value.b = (BOOLEAN) (HiiValueToUINT64(Value) != 0);
+
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ } else if (Value->Type == EFI_IFR_TYPE_STRING) {
+ //
+ // When converting from a string, if case-insensitive compare
+ // with "true" is True, then push True. If a case-insensitive compare
+ // with "false" is True, then push False. Otherwise, push Undefined.
+ //
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ IfrStrToUpper (StrPtr);
+ if (StrCmp (StrPtr, L"TRUE") == 0){
+ Value->Value.b = TRUE;
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ } else if (StrCmp (StrPtr, L"FALSE") == 0) {
+ Value->Value.b = FALSE;
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ } else {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ }
+ FreePool (StrPtr);
+ } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
+ //
+ // When converting from a buffer, if the buffer is all zeroes,
+ // then push False. Otherwise push True.
+ //
+ for (Index =0; Index < Value->BufferLen; Index ++) {
+ if (Value->Buffer[Index] != 0) {
+ break;
+ }
+ }
+
+ if (Index >= Value->BufferLen) {
+ Value->Value.b = FALSE;
+ } else {
+ Value->Value.b = TRUE;
+ }
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ FreePool (Value->Buffer);
+ }
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ Status = IfrToString (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_TO_UINT_OP:
+ Status = IfrToUint (FormSet, Value);
+ break;
+
+ case EFI_IFR_TO_LOWER_OP:
+ case EFI_IFR_TO_UPPER_OP:
+ Status = InitializeUnicodeCollationProtocol ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value->Type != EFI_IFR_TYPE_STRING) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
+ if (StrPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
+ mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
+ } else {
+ mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
+ }
+ Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
+ FreePool (StrPtr);
+ break;
+
+ case EFI_IFR_BITWISE_NOT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type > EFI_IFR_TYPE_DATE) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = ~ HiiValueToUINT64(Value);
+ break;
+
+ case EFI_IFR_SET_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Data1.Type = EFI_IFR_TYPE_BOOLEAN;
+ Data1.Value.b = FALSE;
+ //
+ // Set value to var storage buffer
+ //
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
+ NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
+ ASSERT (NameValue != NULL);
+ //
+ // Convert Buffer to Hex String
+ //
+ TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;
+ StrPtr = NameValue;
+ for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
+ UnicodeValueToStringS (
+ StrPtr,
+ (OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16) - ((UINTN)StrPtr - (UINTN)NameValue),
+ PREFIX_ZERO | RADIX_HEX,
+ *TempBuffer,
+ 2
+ );
+ StrPtr += StrnLenS (StrPtr, OpCode->ValueWidth * 2 + 1 - ((UINTN)StrPtr - (UINTN)NameValue) / sizeof (CHAR16));
+ }
+ Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
+ FreePool (NameValue);
+ if (!EFI_ERROR (Status)) {
+ Data1.Value.b = TRUE;
+ }
+ }
+ break;
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ Status = gRT->SetVariable (
+ OpCode->ValueName,
+ &OpCode->VarStorage->Guid,
+ OpCode->VarStorage->Attributes,
+ OpCode->ValueWidth,
+ &Value->Value
+ );
+ if (!EFI_ERROR (Status)) {
+ Data1.Value.b = TRUE;
+ }
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ } else {
+ //
+ // For Time/Date Data
+ //
+ if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
+ //
+ // Only support Data/Time data when storage doesn't exist.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ Status = gRT->GetTime (&EfiTime, NULL);
+ if (!EFI_ERROR (Status)) {
+ if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
+ switch (OpCode->VarStoreInfo.VarOffset) {
+ case 0x00:
+ EfiTime.Year = Value->Value.u16;
+ break;
+ case 0x02:
+ EfiTime.Month = Value->Value.u8;
+ break;
+ case 0x03:
+ EfiTime.Day = Value->Value.u8;
+ break;
+ default:
+ //
+ // Invalid Date field.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ } else {
+ switch (OpCode->VarStoreInfo.VarOffset) {
+ case 0x00:
+ EfiTime.Hour = Value->Value.u8;
+ break;
+ case 0x01:
+ EfiTime.Minute = Value->Value.u8;
+ break;
+ case 0x02:
+ EfiTime.Second = Value->Value.u8;
+ break;
+ default:
+ //
+ // Invalid Time field.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ Status = gRT->SetTime (&EfiTime);
+ if (!EFI_ERROR (Status)) {
+ Data1.Value.b = TRUE;
+ }
+ }
+ }
+ Value = &Data1;
+ break;
+
+ //
+ // binary-op
+ //
+ case EFI_IFR_ADD_OP:
+ case EFI_IFR_SUBTRACT_OP:
+ case EFI_IFR_MULTIPLY_OP:
+ case EFI_IFR_DIVIDE_OP:
+ case EFI_IFR_MODULO_OP:
+ case EFI_IFR_BITWISE_AND_OP:
+ case EFI_IFR_BITWISE_OR_OP:
+ case EFI_IFR_SHIFT_LEFT_OP:
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Data2.Type > EFI_IFR_TYPE_DATE) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+
+ if (Data1.Type > EFI_IFR_TYPE_DATE) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_ADD_OP:
+ Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2);
+ break;
+
+ case EFI_IFR_SUBTRACT_OP:
+ Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2);
+ break;
+
+ case EFI_IFR_MULTIPLY_OP:
+ Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
+ break;
+
+ case EFI_IFR_DIVIDE_OP:
+ Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
+ break;
+
+ case EFI_IFR_MODULO_OP:
+ DivU64x32Remainder (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue);
+ Value->Value.u64 = TempValue;
+ break;
+
+ case EFI_IFR_BITWISE_AND_OP:
+ Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2);
+ break;
+
+ case EFI_IFR_BITWISE_OR_OP:
+ Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2);
+ break;
+
+ case EFI_IFR_SHIFT_LEFT_OP:
+ Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
+ break;
+
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_AND_OP:
+ case EFI_IFR_OR_OP:
+ //
+ // Two Boolean operator
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (OpCode->Operand == EFI_IFR_AND_OP) {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
+ } else {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
+ }
+ break;
+
+ case EFI_IFR_EQUAL_OP:
+ case EFI_IFR_NOT_EQUAL_OP:
+ case EFI_IFR_GREATER_EQUAL_OP:
+ case EFI_IFR_GREATER_THAN_OP:
+ case EFI_IFR_LESS_EQUAL_OP:
+ case EFI_IFR_LESS_THAN_OP:
+ //
+ // Compare two integer, string, boolean or date/time
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Data2.Type > EFI_IFR_TYPE_BOOLEAN &&
+ Data2.Type != EFI_IFR_TYPE_STRING &&
+ !IsTypeInBuffer(&Data2)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (Data1.Type > EFI_IFR_TYPE_BOOLEAN &&
+ Data1.Type != EFI_IFR_TYPE_STRING &&
+ !IsTypeInBuffer(&Data1)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle);
+ if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Data1.Buffer);
+ }
+ if (Data2.Type == EFI_IFR_TYPE_BUFFER) {
+ FreePool (Data2.Buffer);
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_NOT_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_MATCH_OP:
+ Status = InitializeUnicodeCollationProtocol ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = IfrMatch (FormSet, Value);
+ break;
+
+ case EFI_IFR_MATCH2_OP:
+ Status = IfrMatch2 (FormSet, &OpCode->Guid, Value);
+ break;
+
+ case EFI_IFR_CATENATE_OP:
+ Status = IfrCatenate (FormSet, Value);
+ break;
+
+ //
+ // ternary-op
+ //
+ case EFI_IFR_CONDITIONAL_OP:
+ //
+ // Pop third expression from the expression stack
+ //
+ Status = PopExpression (&Data3);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop second expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop first expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+ }
+
+ if (Data1.Value.b) {
+ Value = &Data3;
+ } else {
+ Value = &Data2;
+ }
+ break;
+
+ case EFI_IFR_FIND_OP:
+ Status = IfrFind (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_MID_OP:
+ Status = IfrMid (FormSet, Value);
+ break;
+
+ case EFI_IFR_TOKEN_OP:
+ Status = IfrToken (FormSet, Value);
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ Status = IfrSpan (FormSet, OpCode->Flags, Value);
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Pop the check value
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check MapExpression list is valid.
+ //
+ if (OpCode->MapExpressionList.ForwardLink == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Go through map expression list.
+ //
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ //
+ // Evaluate the first expression in this pair.
+ //
+ Status = EvaluateExpression (FormSet, Form, SubExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Compare the expression value with current value
+ //
+ if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+ //
+ // Try get the map value.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ Status = EvaluateExpression (FormSet, Form, SubExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Value = &SubExpression->Result;
+ break;
+ }
+ //
+ // Skip the second expression on this pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Goto the first expression on next pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ }
+
+ //
+ // No map value is found.
+ //
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (EFI_ERROR (Status) || Value->Type == EFI_IFR_TYPE_UNDEFINED) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Pop the final result from expression stack
+ //
+ Value = &Data1;
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // After evaluating an expression, there should be only one value left on the expression stack
+ //
+ if (PopExpression (Value) != EFI_ACCESS_DENIED) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ RestoreExpressionEvaluationStackOffset (StackOffset);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the result is TRUE or FALSE.
+
+ For the EFI_HII_VALUE value type is numeric, return TRUE if the
+ value is not 0.
+
+ @param Result Input the result data.
+
+ @retval TRUE The result is TRUE.
+ @retval FALSE The result is FALSE.
+
+**/
+BOOLEAN
+IsTrue (
+ IN EFI_HII_VALUE *Result
+ )
+{
+ switch (Result->Type) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ return Result->Value.b;
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ return (BOOLEAN)(Result->Value.u8 != 0);
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ return (BOOLEAN)(Result->Value.u16 != 0);
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ return (BOOLEAN)(Result->Value.u32 != 0);
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ return (BOOLEAN)(Result->Value.u64 != 0);
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Return the result of the expression list. Check the expression list and
+ return the highest priority express result.
+ Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
+
+ @param ExpList The input expression list.
+ @param Evaluate Whether need to evaluate the expression first.
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+
+ @retval EXPRESS_RESULT Return the higher priority express result.
+ DisableIf > SuppressIf > GrayOutIf > FALSE
+
+**/
+EXPRESS_RESULT
+EvaluateExpressionList (
+ IN FORM_EXPRESSION_LIST *ExpList,
+ IN BOOLEAN Evaluate,
+ IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
+ IN FORM_BROWSER_FORM *Form OPTIONAL
+ )
+{
+ UINTN Index;
+ EXPRESS_RESULT ReturnVal;
+ EXPRESS_RESULT CompareOne;
+ EFI_STATUS Status;
+
+ if (ExpList == NULL) {
+ return ExpressFalse;
+ }
+
+ ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
+ Index = 0;
+
+ //
+ // Check whether need to evaluate the expression first.
+ //
+ if (Evaluate) {
+ while (ExpList->Count > Index) {
+ Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]);
+ if (EFI_ERROR (Status)) {
+ return ExpressFalse;
+ }
+ }
+ }
+
+ //
+ // Run the list of expressions.
+ //
+ ReturnVal = ExpressFalse;
+ for (Index = 0; Index < ExpList->Count; Index++) {
+ if (IsTrue (&ExpList->Expression[Index]->Result)) {
+ switch (ExpList->Expression[Index]->Type) {
+ case EFI_HII_EXPRESSION_SUPPRESS_IF:
+ CompareOne = ExpressSuppress;
+ break;
+
+ case EFI_HII_EXPRESSION_GRAY_OUT_IF:
+ CompareOne = ExpressGrayOut;
+ break;
+
+ case EFI_HII_EXPRESSION_DISABLE_IF:
+ CompareOne = ExpressDisable;
+ break;
+
+ default:
+ return ExpressFalse;
+ }
+
+ ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
+ }
+ }
+
+ return ReturnVal;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h
new file mode 100644
index 000000000..51d0abf84
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h
@@ -0,0 +1,259 @@
+/** @file
+Private structure, MACRO and function definitions for User Interface related functionalities.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EXPRESSION_H_
+#define _EXPRESSION_H_
+
+/**
+ Get the expression list count.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval >=0 The expression count
+ @retval -1 Input parameter error.
+
+**/
+INTN
+GetConditionalExpressionCount (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ );
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ );
+
+/**
+ Get the expression Buffer pointer.
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval The start pointer of the expression buffer or NULL.
+
+**/
+FORM_EXPRESSION **
+GetConditionalExpressionList (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ );
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ );
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ );
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ );
+
+/**
+ Push the expression options onto the Stack.
+
+ @param Pointer Pointer to the current expression.
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushConditionalExpression (
+ IN FORM_EXPRESSION *Pointer,
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop the expression options from the Stack
+
+ @param Level Which type this expression belong to. Form,
+ statement or option?
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopConditionalExpression (
+ IN EXPRESS_LEVEL Level
+ );
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ );
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ );
+
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression
+ );
+/**
+ Return the result of the expression list. Check the expression list and
+ return the highest priority express result.
+ Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
+
+ @param ExpList The input expression list.
+ @param Evaluate Whether need to evaluate the expression first.
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+
+ @retval EXPRESS_RESULT Return the higher priority express result.
+ DisableIf > SuppressIf > GrayOutIf > FALSE
+
+**/
+EXPRESS_RESULT
+EvaluateExpressionList (
+ IN FORM_EXPRESSION_LIST *ExpList,
+ IN BOOLEAN Evaluate,
+ IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
+ IN FORM_BROWSER_FORM *Form OPTIONAL
+ );
+
+/**
+ Get Form given its FormId.
+
+ @param FormSet The formset which contains this form.
+ @param FormId Id of this form.
+
+ @retval Pointer The form.
+ @retval NULL Specified Form is not found in the formset.
+
+**/
+FORM_BROWSER_FORM *
+IdToForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT16 FormId
+ );
+
+#endif // _EXPRESSION_H
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
new file mode 100644
index 000000000..edb6a0fc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
@@ -0,0 +1,2694 @@
+/** @file
+Parser for IFR binary encoding.
+
+Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Setup.h"
+
+UINTN mStatementIndex;
+UINTN mExpressionOpCodeIndex;
+EFI_QUESTION_ID mUsedQuestionId;
+extern LIST_ENTRY gBrowserStorageList;
+/**
+ Initialize Statement header members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSet.
+ @param Form Pointer of the current Form.
+
+ @return The Statement.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateStatement (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_STATEMENT_HEADER *StatementHdr;
+ INTN ConditionalExprCount;
+
+ if (Form == NULL) {
+ //
+ // Only guid op may out side the form level.
+ //
+ ASSERT (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP);
+ }
+
+ Statement = &FormSet->StatementBuffer[mStatementIndex];
+ mStatementIndex++;
+
+ InitializeListHead (&Statement->DefaultListHead);
+ InitializeListHead (&Statement->OptionListHead);
+ InitializeListHead (&Statement->InconsistentListHead);
+ InitializeListHead (&Statement->NoSubmitListHead);
+ InitializeListHead (&Statement->WarningListHead);
+
+ Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;
+
+ Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Statement->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData;
+ Statement->QuestionReferToBitField = FALSE;
+
+ StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
+ CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID));
+
+ ConditionalExprCount = GetConditionalExpressionCount(ExpressStatement);
+ if (ConditionalExprCount > 0) {
+ //
+ // Form is inside of suppressif
+ //
+
+ Statement->Expression = (FORM_EXPRESSION_LIST *) AllocatePool(
+ (UINTN) (sizeof(FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof(FORM_EXPRESSION *))));
+ ASSERT (Statement->Expression != NULL);
+ Statement->Expression->Count = (UINTN) ConditionalExprCount;
+ Statement->Expression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
+ CopyMem (Statement->Expression->Expression, GetConditionalExpressionList(ExpressStatement), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
+ }
+
+ //
+ // Insert this Statement into current Form
+ //
+ if (Form == NULL) {
+ InsertTailList (&FormSet->StatementListOSF, &Statement->Link);
+ } else {
+ InsertTailList (&Form->StatementListHead, &Statement->Link);
+ }
+ return Statement;
+}
+
+/**
+ Initialize Question's members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSet.
+ @param Form Pointer of the current Form.
+
+ @return The Question.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateQuestion (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_QUESTION_HEADER *QuestionHdr;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ NAME_VALUE_NODE *NameValueNode;
+ BOOLEAN Find;
+
+ Statement = CreateStatement (OpCodeData, FormSet, Form);
+ if (Statement == NULL) {
+ return NULL;
+ }
+
+ QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16));
+
+ Statement->QuestionFlags = QuestionHdr->Flags;
+
+ if (Statement->VarStoreId == 0) {
+ //
+ // VarStoreId of zero indicates no variable storage
+ //
+ return Statement;
+ }
+
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if (Storage->VarStoreId == Statement->VarStoreId) {
+ Statement->Storage = Storage->BrowserStorage;
+ break;
+ }
+
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+ }
+ ASSERT (Statement->Storage != NULL);
+
+ //
+ // Initialilze varname for Name/Value or EFI Variable
+ //
+ if ((Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) ||
+ (Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
+ Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->HiiHandle);
+ ASSERT (Statement->VariableName != NULL);
+
+ if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Check whether old string node already exist.
+ //
+ Find = FALSE;
+ if (!IsListEmpty(&Statement->Storage->NameValueListHead)) {
+ Link = GetFirstNode (&Statement->Storage->NameValueListHead);
+ while (!IsNull (&Statement->Storage->NameValueListHead, Link)) {
+ NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (StrCmp (Statement->VariableName, NameValueNode->Name) == 0) {
+ Find = TRUE;
+ break;
+ }
+
+ Link = GetNextNode (&Statement->Storage->NameValueListHead, Link);
+ }
+ }
+
+ if (!Find) {
+ //
+ // Insert to Name/Value varstore list
+ //
+ NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE));
+ ASSERT (NameValueNode != NULL);
+ NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE;
+ NameValueNode->Name = AllocateCopyPool (StrSize (Statement->VariableName), Statement->VariableName);
+ ASSERT (NameValueNode->Name != NULL);
+ NameValueNode->Value = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->Value != NULL);
+ NameValueNode->EditValue = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->EditValue != NULL);
+
+ InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link);
+ }
+ }
+ }
+
+ return Statement;
+}
+
+
+/**
+ Allocate a FORM_EXPRESSION node.
+
+ @param Form The Form associated with this Expression
+ @param OpCode The binary opcode data.
+
+ @return Pointer to a FORM_EXPRESSION data structure.
+
+**/
+FORM_EXPRESSION *
+CreateExpression (
+ IN OUT FORM_BROWSER_FORM *Form,
+ IN UINT8 *OpCode
+ )
+{
+ FORM_EXPRESSION *Expression;
+
+ Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (Expression != NULL);
+ Expression->Signature = FORM_EXPRESSION_SIGNATURE;
+ InitializeListHead (&Expression->OpCodeListHead);
+ Expression->OpCode = (EFI_IFR_OP_HEADER *) OpCode;
+
+ return Expression;
+}
+
+/**
+ Create ConfigHdr string for a storage.
+
+ @param FormSet Pointer of the current FormSet
+ @param Storage Pointer of the storage
+
+ @retval EFI_SUCCESS Initialize ConfigHdr success
+
+**/
+EFI_STATUS
+InitializeConfigHdr (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORMSET_STORAGE *Storage
+ )
+{
+ CHAR16 *Name;
+
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ Name = Storage->BrowserStorage->Name;
+ } else {
+ Name = NULL;
+ }
+
+ Storage->ConfigHdr = HiiConstructConfigHdr (
+ &Storage->BrowserStorage->Guid,
+ Name,
+ FormSet->DriverHandle
+ );
+
+ if (Storage->ConfigHdr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the global storage link base on the input storate type, name and guid.
+
+ For EFI_HII_VARSTORE_EFI_VARIABLE and EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER,
+ same guid + name = same storage
+
+ For EFI_HII_VARSTORE_NAME_VALUE:
+ same guid + HiiHandle = same storage
+
+ For EFI_HII_VARSTORE_BUFFER:
+ same guid + name + HiiHandle = same storage
+
+ @param StorageType Storage type.
+ @param StorageGuid Storage guid.
+ @param StorageName Storage Name.
+ @param HiiHandle HiiHandle for this varstore.
+
+ @return Pointer to a GLOBAL_STORAGE data structure.
+
+**/
+BROWSER_STORAGE *
+FindStorageInList (
+ IN UINT8 StorageType,
+ IN EFI_GUID *StorageGuid,
+ IN CHAR16 *StorageName,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_STORAGE *BrowserStorage;
+
+ Link = GetFirstNode (&gBrowserStorageList);
+ while (!IsNull (&gBrowserStorageList, Link)) {
+ BrowserStorage = BROWSER_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserStorageList, Link);
+
+ if ((BrowserStorage->Type == StorageType) && CompareGuid (&BrowserStorage->Guid, StorageGuid)) {
+ if (StorageType == EFI_HII_VARSTORE_NAME_VALUE) {
+ if (BrowserStorage->HiiHandle == HiiHandle) {
+ return BrowserStorage;
+ }
+
+ continue;
+ }
+
+ ASSERT (StorageName != NULL);
+ if (StrCmp (BrowserStorage->Name, StorageName) == 0) {
+ if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE || StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ return BrowserStorage;
+ } else if (StorageType == EFI_HII_VARSTORE_BUFFER && BrowserStorage->HiiHandle == HiiHandle) {
+ return BrowserStorage;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Intialize the Global Storage.
+
+ @param BrowserStorage Pointer to the global storage.
+ @param StorageType Storage type.
+ @param OpCodeData Binary data for this opcode.
+
+**/
+VOID
+IntializeBrowserStorage (
+ IN BROWSER_STORAGE *BrowserStorage,
+ IN UINT8 StorageType,
+ IN UINT8 *OpCodeData
+ )
+{
+ switch (StorageType) {
+ case EFI_HII_VARSTORE_BUFFER:
+ CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&BrowserStorage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
+
+ BrowserStorage->Buffer = AllocateZeroPool (BrowserStorage->Size);
+ BrowserStorage->EditBuffer = AllocateZeroPool (BrowserStorage->Size);
+ break;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&BrowserStorage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32));
+ CopyMem (&BrowserStorage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16));
+
+ if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ BrowserStorage->Buffer = AllocateZeroPool (BrowserStorage->Size);
+ BrowserStorage->EditBuffer = AllocateZeroPool (BrowserStorage->Size);
+ }
+ break;
+
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ CopyMem (&BrowserStorage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+
+ InitializeListHead (&BrowserStorage->NameValueListHead);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List.
+
+ @param FormSet Pointer of the current FormSet
+ @param StorageType Storage type.
+ @param OpCodeData Binary data for this opcode.
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+CreateStorage (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 StorageType,
+ IN UINT8 *OpCodeData
+ )
+{
+ FORMSET_STORAGE *Storage;
+ CHAR16 *UnicodeString;
+ UINT16 Index;
+ BROWSER_STORAGE *BrowserStorage;
+ EFI_GUID *StorageGuid;
+ CHAR8 *StorageName;
+
+ UnicodeString = NULL;
+ StorageName = NULL;
+ switch (StorageType) {
+ case EFI_HII_VARSTORE_BUFFER:
+ StorageGuid = (EFI_GUID *) (CHAR8*) &((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
+ StorageName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ break;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ StorageGuid = (EFI_GUID *) (CHAR8*) &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
+ StorageName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
+ break;
+
+ default:
+ ASSERT (StorageType == EFI_HII_VARSTORE_NAME_VALUE);
+ StorageGuid = &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
+ break;
+ }
+
+ if (StorageType != EFI_HII_VARSTORE_NAME_VALUE) {
+ ASSERT (StorageName != NULL);
+
+ UnicodeString = AllocateZeroPool (AsciiStrSize (StorageName) * 2);
+ ASSERT (UnicodeString != NULL);
+ for (Index = 0; StorageName[Index] != 0; Index++) {
+ UnicodeString[Index] = (CHAR16) StorageName[Index];
+ }
+ }
+
+ Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE));
+ ASSERT (Storage != NULL);
+ Storage->Signature = FORMSET_STORAGE_SIGNATURE;
+ InsertTailList (&FormSet->StorageListHead, &Storage->Link);
+
+ BrowserStorage = FindStorageInList(StorageType, StorageGuid, UnicodeString, FormSet->HiiHandle);
+ if (BrowserStorage == NULL) {
+ BrowserStorage = AllocateZeroPool (sizeof (BROWSER_STORAGE));
+ ASSERT (BrowserStorage != NULL);
+
+ BrowserStorage->Signature = BROWSER_STORAGE_SIGNATURE;
+ InsertTailList (&gBrowserStorageList, &BrowserStorage->Link);
+
+ IntializeBrowserStorage (BrowserStorage, StorageType, OpCodeData);
+ BrowserStorage->Type = StorageType;
+ if (StorageType != EFI_HII_VARSTORE_NAME_VALUE) {
+ BrowserStorage->Name = UnicodeString;
+ }
+
+ BrowserStorage->HiiHandle = FormSet->HiiHandle;
+
+ BrowserStorage->Initialized = FALSE;
+ }
+
+ Storage->BrowserStorage = BrowserStorage;
+ InitializeConfigHdr (FormSet, Storage);
+ Storage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigHdr), Storage->ConfigHdr);
+ Storage->SpareStrLen = 0;
+
+ return Storage;
+}
+
+/**
+ Get Formset_storage base on the input varstoreid info.
+
+ @param FormSet Pointer of the current FormSet.
+ @param VarStoreId Varstore ID info.
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+GetFstStgFromVarId (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN EFI_VARSTORE_ID VarStoreId
+ )
+{
+ FORMSET_STORAGE *FormsetStorage;
+ LIST_ENTRY *Link;
+ BOOLEAN Found;
+
+ Found = FALSE;
+ FormsetStorage = NULL;
+ //
+ // Find Formset Storage for this Question
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if (FormsetStorage->VarStoreId == VarStoreId) {
+ Found = TRUE;
+ break;
+ }
+
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+ }
+
+ return Found ? FormsetStorage : NULL;
+}
+
+/**
+ Get Formset_storage base on the input browser storage.
+
+ More than one formsets may share the same browser storage,
+ this function just get the first formset storage which
+ share the browser storage.
+
+ @param Storage browser storage info.
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+
+**/
+FORMSET_STORAGE *
+GetFstStgFromBrsStg (
+ IN BROWSER_STORAGE *Storage
+ )
+{
+ FORMSET_STORAGE *FormsetStorage;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *FormsetLink;
+ FORM_BROWSER_FORMSET *FormSet;
+ BOOLEAN Found;
+
+ Found = FALSE;
+ FormsetStorage = NULL;
+
+ FormsetLink = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, FormsetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormsetLink);
+ FormsetLink = GetNextNode (&gBrowserFormSetList, FormsetLink);
+
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (FormsetStorage->BrowserStorage == Storage) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ break;
+ }
+ }
+
+ return Found ? FormsetStorage : NULL;
+}
+
+/**
+ Initialize Request Element of a Question. <RequestElement> ::= '&'<BlockName> | '&'<Label>
+
+ @param FormSet Pointer of the current FormSet.
+ @param Question The Question to be initialized.
+ @param Form Pointer of the current form.
+
+ @retval EFI_SUCCESS Function success.
+ @retval EFI_INVALID_PARAMETER No storage associated with the Question.
+
+**/
+EFI_STATUS
+InitializeRequestElement (
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormsetStorage;
+ UINTN StrLen;
+ UINTN StringSize;
+ CHAR16 *NewStr;
+ CHAR16 RequestElement[30];
+ LIST_ENTRY *Link;
+ BOOLEAN Find;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+ UINTN MaxLen;
+
+ Storage = Question->Storage;
+ if (Storage == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ //
+ // <ConfigRequest> is unnecessary for EFI variable storage,
+ // GetVariable()/SetVariable() will be used to retrieve/save values
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Prepare <RequestElement>
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ StrLen = UnicodeSPrint (
+ RequestElement,
+ 30 * sizeof (CHAR16),
+ L"&OFFSET=%04x&WIDTH=%04x",
+ Question->VarStoreInfo.VarOffset,
+ Question->StorageWidth
+ );
+ HiiToLower(RequestElement);
+ Question->BlockName = AllocateCopyPool ((StrLen + 1) * sizeof (CHAR16), RequestElement);
+ } else {
+ StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName);
+ }
+
+ if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
+ //
+ // Password with CALLBACK flag is stored in encoded format,
+ // so don't need to append it to <ConfigRequest>
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find Formset Storage for this Question
+ //
+ FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
+ ASSERT (FormsetStorage != NULL);
+ StringSize = (FormsetStorage->ConfigRequest != NULL) ? StrSize (FormsetStorage->ConfigRequest) : sizeof (CHAR16);
+ MaxLen = StringSize / sizeof (CHAR16) + FormsetStorage->SpareStrLen;
+
+ //
+ // Append <RequestElement> to <ConfigRequest>
+ //
+ if (StrLen > FormsetStorage->SpareStrLen) {
+ //
+ // Old String buffer is not sufficient for RequestElement, allocate a new one
+ //
+ MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
+ NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (NewStr != NULL);
+ if (FormsetStorage->ConfigRequest != NULL) {
+ CopyMem (NewStr, FormsetStorage->ConfigRequest, StringSize);
+ FreePool (FormsetStorage->ConfigRequest);
+ }
+ FormsetStorage->ConfigRequest = NewStr;
+ FormsetStorage->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
+ }
+
+ StrCatS (FormsetStorage->ConfigRequest, MaxLen, RequestElement);
+ FormsetStorage->ElementCount++;
+ FormsetStorage->SpareStrLen -= StrLen;
+
+ //
+ // Update the Config Request info saved in the form.
+ //
+ ConfigInfo = NULL;
+ Find = FALSE;
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+
+ if (ConfigInfo != NULL && ConfigInfo->Storage == FormsetStorage->BrowserStorage) {
+ Find = TRUE;
+ break;
+ }
+
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+ }
+
+ if (!Find) {
+ ConfigInfo = AllocateZeroPool(sizeof (FORM_BROWSER_CONFIG_REQUEST));
+ ASSERT (ConfigInfo != NULL);
+ ConfigInfo->Signature = FORM_BROWSER_CONFIG_REQUEST_SIGNATURE;
+ ConfigInfo->ConfigRequest = AllocateCopyPool (StrSize (FormsetStorage->ConfigHdr), FormsetStorage->ConfigHdr);
+ ASSERT (ConfigInfo->ConfigRequest != NULL);
+ ConfigInfo->SpareStrLen = 0;
+ ConfigInfo->Storage = FormsetStorage->BrowserStorage;
+ InsertTailList(&Form->ConfigRequestHead, &ConfigInfo->Link);
+ }
+ StringSize = (ConfigInfo->ConfigRequest != NULL) ? StrSize (ConfigInfo->ConfigRequest) : sizeof (CHAR16);
+ MaxLen = StringSize / sizeof (CHAR16) + ConfigInfo->SpareStrLen;
+
+ //
+ // Append <RequestElement> to <ConfigRequest>
+ //
+ if (StrLen > ConfigInfo->SpareStrLen) {
+ //
+ // Old String buffer is not sufficient for RequestElement, allocate a new one
+ //
+ MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
+ NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (NewStr != NULL);
+ if (ConfigInfo->ConfigRequest != NULL) {
+ CopyMem (NewStr, ConfigInfo->ConfigRequest, StringSize);
+ FreePool (ConfigInfo->ConfigRequest);
+ }
+ ConfigInfo->ConfigRequest = NewStr;
+ ConfigInfo->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
+ }
+
+ StrCatS (ConfigInfo->ConfigRequest, MaxLen, RequestElement);
+ ConfigInfo->ElementCount++;
+ ConfigInfo->SpareStrLen -= StrLen;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Free resources of a Expression.
+
+ @param FormSet Pointer of the Expression
+
+**/
+VOID
+DestroyExpression (
+ IN FORM_EXPRESSION *Expression
+ )
+{
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+
+ while (!IsListEmpty (&Expression->OpCodeListHead)) {
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+ RemoveEntryList (&OpCode->Link);
+
+ if (OpCode->ValueList != NULL) {
+ FreePool (OpCode->ValueList);
+ }
+
+ if (OpCode->ValueName != NULL) {
+ FreePool (OpCode->ValueName);
+ }
+
+ if (OpCode->MapExpressionList.ForwardLink != NULL) {
+ while (!IsListEmpty (&OpCode->MapExpressionList)) {
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ RemoveEntryList(&SubExpression->Link);
+ DestroyExpression (SubExpression);
+ }
+ }
+ }
+
+ //
+ // Free this Expression
+ //
+ FreePool (Expression);
+}
+
+/**
+ Free resources of a storage.
+
+ @param Storage Pointer of the storage
+
+**/
+VOID
+DestroyStorage (
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ if (Storage == NULL) {
+ return;
+ }
+
+ if (Storage->ConfigRequest != NULL) {
+ FreePool (Storage->ConfigRequest);
+ }
+
+ FreePool (Storage);
+}
+
+
+/**
+ Free resources of a Statement.
+
+ @param FormSet Pointer of the FormSet
+ @param Statement Pointer of the Statement
+
+**/
+VOID
+DestroyStatement (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ FORM_EXPRESSION *Expression;
+
+ //
+ // Free Default value List
+ //
+ while (!IsListEmpty (&Statement->DefaultListHead)) {
+ Link = GetFirstNode (&Statement->DefaultListHead);
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+ RemoveEntryList (&Default->Link);
+
+ if (Default->Value.Buffer != NULL) {
+ FreePool (Default->Value.Buffer);
+ }
+ FreePool (Default);
+ }
+
+ //
+ // Free Options List
+ //
+ while (!IsListEmpty (&Statement->OptionListHead)) {
+ Link = GetFirstNode (&Statement->OptionListHead);
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ if (Option->SuppressExpression != NULL) {
+ FreePool (Option->SuppressExpression);
+ }
+ RemoveEntryList (&Option->Link);
+
+ FreePool (Option);
+ }
+
+ //
+ // Free Inconsistent List
+ //
+ while (!IsListEmpty (&Statement->InconsistentListHead)) {
+ Link = GetFirstNode (&Statement->InconsistentListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free NoSubmit List
+ //
+ while (!IsListEmpty (&Statement->NoSubmitListHead)) {
+ Link = GetFirstNode (&Statement->NoSubmitListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free WarningIf List
+ //
+ while (!IsListEmpty (&Statement->WarningListHead)) {
+ Link = GetFirstNode (&Statement->WarningListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ if (Statement->Expression != NULL) {
+ FreePool (Statement->Expression);
+ }
+
+ if (Statement->VariableName != NULL) {
+ FreePool (Statement->VariableName);
+ }
+ if (Statement->BlockName != NULL) {
+ FreePool (Statement->BlockName);
+ }
+ if (Statement->BufferValue != NULL) {
+ FreePool (Statement->BufferValue);
+ }
+ if (Statement->Operand == EFI_IFR_STRING_OP || Statement->Operand == EFI_IFR_PASSWORD_OP) {
+ DeleteString(Statement->HiiValue.Value.string, FormSet->HiiHandle);
+ }
+}
+
+
+/**
+ Free resources of a Form.
+
+ @param FormSet Pointer of the FormSet
+ @param Form Pointer of the Form.
+
+**/
+VOID
+DestroyForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_STATEMENT *Statement;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+
+ //
+ // Free Form Expressions
+ //
+ while (!IsListEmpty (&Form->ExpressionListHead)) {
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Statements/Questions
+ //
+ while (!IsListEmpty (&Form->StatementListHead)) {
+ Link = GetFirstNode (&Form->StatementListHead);
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ RemoveEntryList (&Statement->Link);
+
+ DestroyStatement (FormSet, Statement);
+ }
+
+ //
+ // Free ConfigRequest string.
+ //
+ while (!IsListEmpty (&Form->ConfigRequestHead)) {
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ RemoveEntryList (&ConfigInfo->Link);
+
+ FreePool (ConfigInfo->ConfigRequest);
+ FreePool (ConfigInfo);
+ }
+
+ if (Form->SuppressExpression != NULL) {
+ FreePool (Form->SuppressExpression);
+ }
+
+ UiFreeMenuList (&Form->FormViewListHead);
+
+ //
+ // Free this Form
+ //
+ FreePool (Form);
+}
+
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_FORM *Form;
+
+ if (FormSet->IfrBinaryData == NULL) {
+ //
+ // Uninitialized FormSet
+ //
+ FreePool (FormSet);
+ return;
+ }
+
+ //
+ // Free IFR binary buffer
+ //
+ FreePool (FormSet->IfrBinaryData);
+
+ //
+ // Free FormSet Storage
+ //
+ if (FormSet->StorageListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->StorageListHead)) {
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ RemoveEntryList (&Storage->Link);
+
+ DestroyStorage (Storage);
+ }
+ }
+
+ //
+ // Free FormSet Default Store
+ //
+ if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ Link = GetFirstNode (&FormSet->DefaultStoreListHead);
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
+ RemoveEntryList (&DefaultStore->Link);
+
+ FreePool (DefaultStore);
+ }
+ }
+
+ //
+ // Free Formset Expressions
+ //
+ while (!IsListEmpty (&FormSet->ExpressionListHead)) {
+ Link = GetFirstNode (&FormSet->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Forms
+ //
+ if (FormSet->FormListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->FormListHead)) {
+ Link = GetFirstNode (&FormSet->FormListHead);
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ RemoveEntryList (&Form->Link);
+
+ DestroyForm (FormSet, Form);
+ }
+ }
+
+ if (FormSet->StatementBuffer != NULL) {
+ FreePool (FormSet->StatementBuffer);
+ }
+ if (FormSet->ExpressionBuffer != NULL) {
+ FreePool (FormSet->ExpressionBuffer);
+ }
+
+ FreePool (FormSet);
+}
+
+
+/**
+ Tell whether this Operand is an Expression OpCode or not
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Expression OpCode.
+ @retval FALSE Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsExpressionOpCode (
+ IN UINT8 Operand
+ )
+{
+ if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
+ ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP)) ||
+ ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
+ (Operand == EFI_IFR_CATENATE_OP) ||
+ (Operand == EFI_IFR_TO_LOWER_OP) ||
+ (Operand == EFI_IFR_TO_UPPER_OP) ||
+ (Operand == EFI_IFR_MAP_OP) ||
+ (Operand == EFI_IFR_VERSION_OP) ||
+ (Operand == EFI_IFR_SECURITY_OP) ||
+ (Operand == EFI_IFR_MATCH2_OP)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Tell whether this Operand is an Statement OpCode.
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Statement OpCode.
+ @retval FALSE Not an Statement OpCode.
+
+**/
+BOOLEAN
+IsStatementOpCode (
+ IN UINT8 Operand
+ )
+{
+ if ((Operand == EFI_IFR_SUBTITLE_OP) ||
+ (Operand == EFI_IFR_TEXT_OP) ||
+ (Operand == EFI_IFR_RESET_BUTTON_OP) ||
+ (Operand == EFI_IFR_REF_OP) ||
+ (Operand == EFI_IFR_ACTION_OP) ||
+ (Operand == EFI_IFR_NUMERIC_OP) ||
+ (Operand == EFI_IFR_ORDERED_LIST_OP) ||
+ (Operand == EFI_IFR_CHECKBOX_OP) ||
+ (Operand == EFI_IFR_STRING_OP) ||
+ (Operand == EFI_IFR_PASSWORD_OP) ||
+ (Operand == EFI_IFR_DATE_OP) ||
+ (Operand == EFI_IFR_TIME_OP) ||
+ (Operand == EFI_IFR_GUID_OP) ||
+ (Operand == EFI_IFR_ONE_OF_OP)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Tell whether this Operand is an known OpCode.
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Statement OpCode.
+ @retval FALSE Not an Statement OpCode.
+
+**/
+BOOLEAN
+IsUnKnownOpCode (
+ IN UINT8 Operand
+ )
+{
+ return Operand > EFI_IFR_MATCH2_OP ? TRUE : FALSE;
+}
+
+/**
+ Calculate number of Statemens(Questions) and Expression OpCodes.
+
+ @param FormSet The FormSet to be counted.
+ @param NumberOfStatement Number of Statemens(Questions)
+ @param NumberOfExpression Number of Expression OpCodes
+
+**/
+VOID
+CountOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT UINTN *NumberOfStatement,
+ OUT UINTN *NumberOfExpression
+ )
+{
+ UINTN StatementCount;
+ UINTN ExpressionCount;
+ UINT8 *OpCodeData;
+ UINTN Offset;
+ UINTN OpCodeLen;
+
+ Offset = 0;
+ StatementCount = 0;
+ ExpressionCount = 0;
+
+ while (Offset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + Offset;
+ OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ Offset += OpCodeLen;
+
+ if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) {
+ ExpressionCount++;
+ } else {
+ StatementCount++;
+ }
+ }
+
+ *NumberOfStatement = StatementCount;
+ *NumberOfExpression = ExpressionCount;
+}
+
+
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORM *CurrentForm;
+ FORM_BROWSER_STATEMENT *CurrentStatement;
+ FORM_BROWSER_STATEMENT *ParentStatement;
+ EXPRESSION_OPCODE *ExpressionOpCode;
+ FORM_EXPRESSION *CurrentExpression;
+ UINT8 Operand;
+ UINT8 Scope;
+ UINTN OpCodeOffset;
+ UINTN OpCodeLength;
+ UINT8 *OpCodeData;
+ UINT8 ScopeOpCode;
+ FORMSET_STORAGE *Storage;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ QUESTION_DEFAULT *CurrentDefault;
+ QUESTION_OPTION *CurrentOption;
+ UINT8 Width;
+ UINTN NumberOfStatement;
+ UINTN NumberOfExpression;
+ EFI_IMAGE_ID *ImageId;
+ BOOLEAN SuppressForQuestion;
+ BOOLEAN SuppressForOption;
+ UINT16 DepthOfDisable;
+ BOOLEAN OpCodeDisabled;
+ BOOLEAN SingleOpCodeExpression;
+ BOOLEAN InScopeDefault;
+ EFI_HII_VALUE *Value;
+ EFI_IFR_FORM_MAP_METHOD *MapMethod;
+ UINT8 MapScopeDepth;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *VarStorage;
+ LIST_ENTRY *MapExpressionList;
+ EFI_VARSTORE_ID TempVarstoreId;
+ BOOLEAN InScopeDisable;
+ INTN ConditionalExprCount;
+ BOOLEAN InUnknownScope;
+ UINT8 UnknownDepth;
+ FORMSET_DEFAULTSTORE *PreDefaultStore;
+ LIST_ENTRY *DefaultLink;
+ BOOLEAN HaveInserted;
+ UINT16 TotalBits;
+ BOOLEAN QuestionReferBitField;
+
+ SuppressForQuestion = FALSE;
+ SuppressForOption = FALSE;
+ InScopeDisable = FALSE;
+ DepthOfDisable = 0;
+ OpCodeDisabled = FALSE;
+ SingleOpCodeExpression = FALSE;
+ InScopeDefault = FALSE;
+ CurrentExpression = NULL;
+ CurrentDefault = NULL;
+ CurrentOption = NULL;
+ ImageId = NULL;
+ MapMethod = NULL;
+ MapScopeDepth = 0;
+ Link = NULL;
+ VarStorage = NULL;
+ MapExpressionList = NULL;
+ TempVarstoreId = 0;
+ ConditionalExprCount = 0;
+ InUnknownScope = FALSE;
+ UnknownDepth = 0;
+ QuestionReferBitField = FALSE;
+
+ //
+ // Get the number of Statements and Expressions
+ //
+ CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
+
+ mStatementIndex = 0;
+ mUsedQuestionId = 1;
+ FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
+ if (FormSet->StatementBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mExpressionOpCodeIndex = 0;
+ FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
+ if (FormSet->ExpressionBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&FormSet->StatementListOSF);
+ InitializeListHead (&FormSet->StorageListHead);
+ InitializeListHead (&FormSet->SaveFailStorageListHead);
+ InitializeListHead (&FormSet->DefaultStoreListHead);
+ InitializeListHead (&FormSet->FormListHead);
+ InitializeListHead (&FormSet->ExpressionListHead);
+ ResetCurrentExpressionStack ();
+ ResetMapExpressionListStack ();
+
+ CurrentForm = NULL;
+ CurrentStatement = NULL;
+ ParentStatement = NULL;
+
+ ResetScopeStack ();
+
+ OpCodeOffset = 0;
+ while (OpCodeOffset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;
+
+ OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ OpCodeOffset += OpCodeLength;
+ Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope;
+
+ if (InUnknownScope) {
+ if (Operand == EFI_IFR_END_OP) {
+ UnknownDepth --;
+
+ if (UnknownDepth == 0) {
+ InUnknownScope = FALSE;
+ }
+ } else {
+ if (Scope != 0) {
+ UnknownDepth ++;
+ }
+ }
+
+ continue;
+ }
+
+ if (IsUnKnownOpCode(Operand)) {
+ if (Scope != 0) {
+ InUnknownScope = TRUE;
+ UnknownDepth ++;
+ }
+
+ continue;
+ }
+
+ //
+ // If scope bit set, push onto scope stack
+ //
+ if (Scope != 0) {
+ PushScope (Operand);
+ }
+
+ if (OpCodeDisabled) {
+ //
+ // DisableIf Expression is evaluated to be TRUE, try to find its end.
+ // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
+ //
+ if (Operand == EFI_IFR_DISABLE_IF_OP) {
+ DepthOfDisable++;
+ } else if (Operand == EFI_IFR_END_OP) {
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
+ if (DepthOfDisable == 0) {
+ InScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ } else {
+ DepthOfDisable--;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (IsExpressionOpCode (Operand)) {
+ ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
+ mExpressionOpCodeIndex++;
+
+ ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
+ ExpressionOpCode->Operand = Operand;
+ Value = &ExpressionOpCode->Value;
+
+ switch (Operand) {
+ case EFI_IFR_EQ_ID_VAL_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ListLength, sizeof (UINT16));
+ ExpressionOpCode->ValueList = AllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ValueList);
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ case EFI_IFR_FIND_OP:
+ ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId;
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags;
+ break;
+
+ case EFI_IFR_THIS_OP:
+ ASSERT (ParentStatement != NULL);
+ ExpressionOpCode->QuestionId = ParentStatement->QuestionId;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *) OpCodeData)->Permissions, sizeof (EFI_GUID));
+ break;
+
+ case EFI_IFR_MATCH2_OP:
+ CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_MATCH2 *) OpCodeData)->SyntaxType, sizeof (EFI_GUID));
+ break;
+
+ case EFI_IFR_GET_OP:
+ case EFI_IFR_SET_OP:
+ CopyMem (&TempVarstoreId, &((EFI_IFR_GET *) OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
+ if (TempVarstoreId != 0) {
+ if (FormSet->StorageListHead.ForwardLink != NULL) {
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ if (VarStorage->VarStoreId == ((EFI_IFR_GET *) OpCodeData)->VarStoreId) {
+ ExpressionOpCode->VarStorage = VarStorage->BrowserStorage;
+ break;
+ }
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+ }
+ }
+ if (ExpressionOpCode->VarStorage == NULL) {
+ //
+ // VarStorage is not found.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ ExpressionOpCode->ValueType = ((EFI_IFR_GET *) OpCodeData)->VarStoreType;
+ switch (ExpressionOpCode->ValueType) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ ExpressionOpCode->ValueWidth = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_STRING:
+ ExpressionOpCode->ValueWidth = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ ExpressionOpCode->ValueWidth = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ ExpressionOpCode->ValueWidth = 8;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_DATE);
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_TIME);
+ break;
+
+ case EFI_IFR_TYPE_REF:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_REF);
+ break;
+
+ case EFI_IFR_TYPE_OTHER:
+ case EFI_IFR_TYPE_UNDEFINED:
+ case EFI_IFR_TYPE_ACTION:
+ case EFI_IFR_TYPE_BUFFER:
+ default:
+ //
+ // Invalid value type for Get/Set opcode.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarName, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarName, sizeof (EFI_STRING_ID));
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
+ if ((ExpressionOpCode->VarStorage != NULL) &&
+ (ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE ||
+ ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
+ ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->HiiHandle);
+ if (ExpressionOpCode->ValueName == NULL) {
+ //
+ // String ID is invalid.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
+ CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
+ CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+ }
+ break;
+
+ //
+ // constant
+ //
+ case EFI_IFR_TRUE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = TRUE;
+ break;
+
+ case EFI_IFR_FALSE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 1;
+ break;
+
+ case EFI_IFR_ZERO_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 0;
+ break;
+
+ case EFI_IFR_ONES_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = 0xffffffffffffffffULL;
+ break;
+
+ case EFI_IFR_UINT8_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value;
+ break;
+
+ case EFI_IFR_UINT16_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_UINT32_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32));
+ break;
+
+ case EFI_IFR_UINT64_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64));
+ break;
+
+ case EFI_IFR_UNDEFINED_OP:
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+
+ case EFI_IFR_VERSION_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ Value->Value.u16 = EFI_IFR_SPECIFICATION_VERSION;
+ break;
+
+ default:
+ break;
+ }
+ //
+ // Create sub expression nested in MAP opcode
+ //
+ if (CurrentExpression == NULL && MapScopeDepth > 0) {
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ ASSERT (MapExpressionList != NULL);
+ InsertTailList (MapExpressionList, &CurrentExpression->Link);
+ if (Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ }
+ ASSERT (CurrentExpression != NULL);
+ InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
+ if (Operand == EFI_IFR_MAP_OP) {
+ //
+ // Store current Map Expression List.
+ //
+ if (MapExpressionList != NULL) {
+ PushMapExpressionList (MapExpressionList);
+ }
+ //
+ // Initialize new Map Expression List.
+ //
+ MapExpressionList = &ExpressionOpCode->MapExpressionList;
+ InitializeListHead (MapExpressionList);
+ //
+ // Store current expression.
+ //
+ PushCurrentExpression (CurrentExpression);
+ CurrentExpression = NULL;
+ MapScopeDepth ++;
+ } else if (SingleOpCodeExpression) {
+ //
+ // There are two cases to indicate the end of an Expression:
+ // for single OpCode expression: one Expression OpCode
+ // for expression consists of more than one OpCode: EFI_IFR_END
+ //
+ SingleOpCodeExpression = FALSE;
+
+ if (InScopeDisable && CurrentForm == NULL) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OpCodeDisabled = IsTrue(&CurrentExpression->Result);
+ }
+
+ CurrentExpression = NULL;
+ }
+
+ continue;
+ }
+
+ //
+ // Parse the Opcode
+ //
+ switch (Operand) {
+
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // Check the formset GUID
+ //
+ if (CompareMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+ CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
+ FormSet->OpCode = (EFI_IFR_OP_HEADER *) OpCodeData;//save the opcode address of formset
+
+ if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+ //
+ // The formset OpCode contains ClassGuid
+ //
+ FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
+ }
+ break;
+
+ case EFI_IFR_FORM_OP:
+ //
+ // Create a new Form for this FormSet
+ //
+ CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
+ InitializeListHead (&CurrentForm->ExpressionListHead);
+ InitializeListHead (&CurrentForm->StatementListHead);
+ InitializeListHead (&CurrentForm->ConfigRequestHead);
+ InitializeListHead (&CurrentForm->FormViewListHead);
+
+ CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
+ CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16));
+ CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
+
+ ConditionalExprCount = GetConditionalExpressionCount(ExpressForm);
+ if ( ConditionalExprCount > 0) {
+ //
+ // Form is inside of suppressif
+ //
+ CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *) AllocatePool(
+ (UINTN) (sizeof(FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof(FORM_EXPRESSION *))));
+ ASSERT (CurrentForm->SuppressExpression != NULL);
+ CurrentForm->SuppressExpression->Count = (UINTN) ConditionalExprCount;
+ CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
+ CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList(ExpressForm), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
+ }
+
+ if (Scope != 0) {
+ //
+ // Enter scope of a Form, suppressif will be used for Question or Option
+ //
+ SuppressForQuestion = TRUE;
+ }
+
+ //
+ // Insert into Form list of this FormSet
+ //
+ InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
+ break;
+
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // Create a new Form for this FormSet
+ //
+ CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
+ InitializeListHead (&CurrentForm->ExpressionListHead);
+ InitializeListHead (&CurrentForm->StatementListHead);
+ InitializeListHead (&CurrentForm->ConfigRequestHead);
+ InitializeListHead (&CurrentForm->FormViewListHead);
+
+ CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16));
+
+ MapMethod = (EFI_IFR_FORM_MAP_METHOD *) (OpCodeData + sizeof (EFI_IFR_FORM_MAP));
+ //
+ // FormMap Form must contain at least one Map Method.
+ //
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length < ((UINTN) (UINT8 *) (MapMethod + 1) - (UINTN) OpCodeData)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Try to find the standard form map method.
+ //
+ while (((UINTN) (UINT8 *) MapMethod - (UINTN) OpCodeData) < ((EFI_IFR_OP_HEADER *) OpCodeData)->Length) {
+ if (CompareGuid ((EFI_GUID *) (VOID *) &MapMethod->MethodIdentifier, &gEfiHiiStandardFormGuid)) {
+ CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID));
+ CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
+ break;
+ }
+ MapMethod ++;
+ }
+ //
+ // If the standard form map method is not found, the first map method title will be used.
+ //
+ if (CurrentForm->FormTitle == 0) {
+ MapMethod = (EFI_IFR_FORM_MAP_METHOD *) (OpCodeData + sizeof (EFI_IFR_FORM_MAP));
+ CopyMem (&CurrentForm->FormTitle, &MapMethod->MethodTitle, sizeof (EFI_STRING_ID));
+ }
+
+ ConditionalExprCount = GetConditionalExpressionCount(ExpressForm);
+ if ( ConditionalExprCount > 0) {
+ //
+ // Form is inside of suppressif
+ //
+ CurrentForm->SuppressExpression = (FORM_EXPRESSION_LIST *) AllocatePool(
+ (UINTN) (sizeof(FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof(FORM_EXPRESSION *))));
+ ASSERT (CurrentForm->SuppressExpression != NULL);
+ CurrentForm->SuppressExpression->Count = (UINTN) ConditionalExprCount;
+ CurrentForm->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
+ CopyMem (CurrentForm->SuppressExpression->Expression, GetConditionalExpressionList(ExpressForm), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
+ }
+
+ if (Scope != 0) {
+ //
+ // Enter scope of a Form, suppressif will be used for Question or Option
+ //
+ SuppressForQuestion = TRUE;
+ }
+
+ //
+ // Insert into Form list of this FormSet
+ //
+ InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
+ break;
+
+ //
+ // Storage
+ //
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // Create a buffer Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_BUFFER, OpCodeData);
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // Create a name/value Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_NAME_VALUE, OpCodeData);
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Create a EFI variable Storage for this FormSet
+ //
+ if (OpCodeLength < sizeof (EFI_IFR_VARSTORE_EFI)) {
+ //
+ // Create efi varstore with format follow UEFI spec before 2.3.1.
+ //
+ Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE, OpCodeData);
+ } else {
+ //
+ // Create efi varstore with format follow UEFI spec 2.3.1 and later.
+ //
+ Storage = CreateStorage (FormSet, EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER, OpCodeData);
+ }
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ break;
+
+ //
+ // DefaultStore
+ //
+ case EFI_IFR_DEFAULTSTORE_OP:
+ HaveInserted = FALSE;
+ DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
+ ASSERT (DefaultStore != NULL);
+ DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;
+
+ CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId, sizeof (UINT16));
+ CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));
+ //
+ // Insert it to the DefaultStore list of this Formset with ascending order.
+ //
+ if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+ while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
+ PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
+ if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
+ InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
+ HaveInserted = TRUE;
+ break;
+ }
+ }
+ }
+ if (!HaveInserted) {
+ InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
+ }
+ break;
+
+ //
+ // Statements
+ //
+ case EFI_IFR_SUBTITLE_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
+ break;
+
+ case EFI_IFR_TEXT_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
+ CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RESET_BUTTON_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->FakeQuestionId = mUsedQuestionId++;
+ CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
+ break;
+
+ //
+ // Questions
+ //
+ case EFI_IFR_ACTION_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
+
+ if (OpCodeLength == sizeof (EFI_IFR_ACTION_1)) {
+ //
+ // No QuestionConfig present, so no configuration string will be processed
+ //
+ CurrentStatement->QuestionConfig = 0;
+ } else {
+ CopyMem (&CurrentStatement->QuestionConfig, &((EFI_IFR_ACTION *) OpCodeData)->QuestionConfig, sizeof (EFI_STRING_ID));
+ }
+ break;
+
+ case EFI_IFR_REF_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ Value = &CurrentStatement->HiiValue;
+ Value->Type = EFI_IFR_TYPE_REF;
+ if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
+ CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
+ CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
+ CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
+ CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+ }
+ }
+ }
+ }
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_REF);
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags;
+ Value = &CurrentStatement->HiiValue;
+
+ if (QuestionReferBitField) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte offset)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+
+ //
+ // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step;
+
+ //
+ // Update the Flag and type of Minimum/Maximum/Step according to the actual width of bit field,
+ // in order to make Browser handle these question with bit varstore correctly.
+ //
+ ((EFI_IFR_NUMERIC *) OpCodeData)->Flags &= EDKII_IFR_DISPLAY_BIT;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->Flags >>= 2;
+ switch (CurrentStatement->StorageWidth) {
+ case 1:
+ ((EFI_IFR_NUMERIC *) OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_8;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue = (UINT8)CurrentStatement->Minimum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue = (UINT8)CurrentStatement->Maximum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step = (UINT8)CurrentStatement->Step;
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+ case 2:
+ ((EFI_IFR_NUMERIC *) OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_16;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue = (UINT16)CurrentStatement->Minimum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue = (UINT16)CurrentStatement->Maximum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step = (UINT16)CurrentStatement->Step;
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+ case 3:
+ case 4:
+ ((EFI_IFR_NUMERIC *) OpCodeData)->Flags |= EFI_IFR_TYPE_NUM_SIZE_32;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue = (UINT32)CurrentStatement->Minimum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue = (UINT32)CurrentStatement->Maximum;
+ ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step = (UINT32)CurrentStatement->Step;
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT8);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT16);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step, sizeof (UINT32));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT32);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step, sizeof (UINT64));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT64);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ break;
+
+ default:
+ break;
+ }
+ }
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+
+ if ((Operand == EFI_IFR_ONE_OF_OP) && Scope != 0) {
+ SuppressForOption = TRUE;
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags;
+ CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
+ CurrentStatement->BufferValue = NULL;
+
+ if (Scope != 0) {
+ SuppressForOption = TRUE;
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (BOOLEAN);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;
+
+ if (QuestionReferBitField) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte offset)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = 1;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+ }
+
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+
+ break;
+
+ case EFI_IFR_STRING_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize;
+ CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize;
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+ CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
+ CurrentStatement->HiiValue.Value.string = NewString ((CHAR16*) CurrentStatement->BufferValue, FormSet->HiiHandle);
+
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
+ CurrentStatement->HiiValue.Value.string = NewString ((CHAR16*) CurrentStatement->BufferValue, FormSet->HiiHandle);
+
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+ break;
+
+ case EFI_IFR_DATE_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;
+
+ if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_DATE);
+
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ case EFI_IFR_TIME_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;
+
+ if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_TIME);
+
+ InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ //
+ // Default
+ //
+ case EFI_IFR_DEFAULT_OP:
+ //
+ // EFI_IFR_DEFAULT appear in scope of a Question,
+ // It creates a default value for the current question.
+ // A Question may have more than one Default value which have different default types.
+ //
+ CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
+ ASSERT (CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type;
+ CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16));
+ if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CurrentDefault->Value.BufferLen = (UINT16) (OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value));
+ CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *) OpCodeData)->Value);
+ ASSERT (CurrentDefault->Value.Buffer != NULL);
+ } else {
+ CopyMem (&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_DEFAULT, Value));
+ ExtendValueToU64 (&CurrentDefault->Value);
+ }
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link);
+
+ if (Scope != 0) {
+ InScopeDefault = TRUE;
+ }
+ break;
+
+ //
+ // Option
+ //
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ ASSERT (ParentStatement != NULL);
+ if (ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP && ((((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
+ //
+ // It's keep the default value for ordered list opcode.
+ //
+ CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
+ ASSERT (CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
+ if ((((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ } else {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ }
+
+ CurrentDefault->Value.BufferLen = (UINT16) (OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ CurrentDefault->Value.Buffer = AllocateCopyPool (CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value);
+ ASSERT (CurrentDefault->Value.Buffer != NULL);
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link);
+ break;
+ }
+
+ //
+ // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
+ // It create a selection for use in current Question.
+ //
+ CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
+ ASSERT (CurrentOption != NULL);
+ CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
+ CurrentOption->OpCode = (EFI_IFR_ONE_OF_OPTION *) OpCodeData;
+
+ CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
+ CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
+ CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID));
+ CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ ExtendValueToU64 (&CurrentOption->Value);
+
+ ConditionalExprCount = GetConditionalExpressionCount(ExpressOption);
+ if ( ConditionalExprCount > 0) {
+ //
+ // Form is inside of suppressif
+ //
+ CurrentOption->SuppressExpression = (FORM_EXPRESSION_LIST *) AllocatePool(
+ (UINTN) (sizeof(FORM_EXPRESSION_LIST) + ((ConditionalExprCount -1) * sizeof(FORM_EXPRESSION *))));
+ ASSERT (CurrentOption->SuppressExpression != NULL);
+ CurrentOption->SuppressExpression->Count = (UINTN) ConditionalExprCount;
+ CurrentOption->SuppressExpression->Signature = FORM_EXPRESSION_LIST_SIGNATURE;
+ CopyMem (CurrentOption->SuppressExpression->Expression, GetConditionalExpressionList(ExpressOption), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));
+ }
+
+ //
+ // Insert to Option list of current Question
+ //
+ InsertTailList (&ParentStatement->OptionListHead, &CurrentOption->Link);
+ //
+ // Now we know the Storage width of nested Ordered List
+ //
+ if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (ParentStatement->BufferValue == NULL)) {
+ Width = 1;
+ switch (CurrentOption->Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Width = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Width = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Width = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Width = 8;
+ break;
+
+ default:
+ //
+ // Invalid type for Ordered List
+ //
+ break;
+ }
+
+ ParentStatement->StorageWidth = (UINT16) (ParentStatement->MaxContainers * Width);
+ ParentStatement->BufferValue = AllocateZeroPool (ParentStatement->StorageWidth);
+ ParentStatement->ValueType = CurrentOption->Value.Type;
+ if (ParentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+ ParentStatement->HiiValue.Buffer = ParentStatement->BufferValue;
+ ParentStatement->HiiValue.BufferLen = ParentStatement->StorageWidth;
+ }
+
+ InitializeRequestElement (FormSet, ParentStatement, CurrentForm);
+ }
+ break;
+
+ //
+ // Conditional
+ //
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));
+
+ if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
+ InsertTailList (&ParentStatement->NoSubmitListHead, &CurrentExpression->Link);
+ } else {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
+ InsertTailList (&ParentStatement->InconsistentListHead, &CurrentExpression->Link);
+ }
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));
+ CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WARNING_IF;
+ InsertTailList (&ParentStatement->WarningListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ //
+ // Question and Option will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;
+
+ if (CurrentForm == NULL) {
+ InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
+ } else {
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ }
+
+ if (SuppressForOption) {
+ PushConditionalExpression(CurrentExpression, ExpressOption);
+ } else if (SuppressForQuestion) {
+ PushConditionalExpression(CurrentExpression, ExpressStatement);
+ } else {
+ PushConditionalExpression(CurrentExpression, ExpressForm);
+ }
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ //
+ // Questions will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ PushConditionalExpression(CurrentExpression, ExpressStatement);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ //
+ // The DisableIf expression should only rely on constant, so it could be
+ // evaluated at initialization and it will not be queued
+ //
+ CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (CurrentExpression != NULL);
+ CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
+ InitializeListHead (&CurrentExpression->OpCodeListHead);
+
+ if (CurrentForm != NULL) {
+ //
+ // This is DisableIf for Question, enqueue it to Form expression list
+ //
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ PushConditionalExpression(CurrentExpression, ExpressStatement);
+ }
+
+ OpCodeDisabled = FALSE;
+ InScopeDisable = TRUE;
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Expression
+ //
+ case EFI_IFR_VALUE_OP:
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ if (InScopeDefault) {
+ //
+ // Used for default (EFI_IFR_DEFAULT)
+ //
+ CurrentDefault->ValueExpression = CurrentExpression;
+ } else {
+ //
+ // If used for a question, then the question will be read-only
+ //
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (ParentStatement != NULL);
+ ParentStatement->ValueExpression = CurrentExpression;
+ }
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_RULE_OP:
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;
+
+ CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_READ_OP:
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (ParentStatement != NULL);
+ ParentStatement->ReadExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WRITE_OP:
+ CurrentExpression = CreateExpression (CurrentForm, OpCodeData);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (ParentStatement != NULL);
+ ParentStatement->WriteExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Image
+ //
+ case EFI_IFR_IMAGE_OP:
+ //
+ // Get ScopeOpcode from top of stack
+ //
+ PopScope (&ScopeOpCode);
+ PushScope (ScopeOpCode);
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ ImageId = &FormSet->ImageId;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ ASSERT (CurrentForm != NULL);
+ ImageId = &CurrentForm->ImageId;
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ ASSERT (CurrentOption != NULL);
+ ImageId = &CurrentOption->ImageId;
+ break;
+
+ default:
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler.
+ //
+ ASSERT (ParentStatement != NULL);
+ ImageId = &ParentStatement->ImageId;
+ break;
+ }
+
+ ASSERT (ImageId != NULL);
+ CopyMem (ImageId, &((EFI_IFR_IMAGE *) OpCodeData)->Id, sizeof (EFI_IMAGE_ID));
+ break;
+
+ //
+ // Refresh
+ //
+ case EFI_IFR_REFRESH_OP:
+ ASSERT (ParentStatement != NULL);
+ ParentStatement->RefreshInterval = ((EFI_IFR_REFRESH *) OpCodeData)->RefreshInterval;
+ break;
+
+ //
+ // Refresh guid.
+ //
+ case EFI_IFR_REFRESH_ID_OP:
+ //
+ // Get ScopeOpcode from top of stack
+ //
+ PopScope (&ScopeOpCode);
+ PushScope (ScopeOpCode);
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ ASSERT (CurrentForm != NULL);
+ CopyMem (&CurrentForm->RefreshGuid, &((EFI_IFR_REFRESH_ID *) OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));
+ break;
+
+ default:
+ ASSERT (ParentStatement != NULL);
+ CopyMem (&ParentStatement->RefreshGuid, &((EFI_IFR_REFRESH_ID *) OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));
+ break;
+ }
+ break;
+
+ //
+ // Modal tag
+ //
+ case EFI_IFR_MODAL_TAG_OP:
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->ModalForm = TRUE;
+ break;
+
+ //
+ // Lock tag, used by form and statement.
+ //
+ case EFI_IFR_LOCKED_OP:
+ //
+ // Get ScopeOpcode from top of stack
+ //
+ PopScope (&ScopeOpCode);
+ PushScope (ScopeOpCode);
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->Locked = TRUE;
+ break;
+
+ default:
+ ASSERT (ParentStatement != NULL);
+ ParentStatement->Locked = TRUE;
+ }
+ break;
+
+ //
+ // Vendor specific
+ //
+ case EFI_IFR_GUID_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
+ Scope = 0;
+ QuestionReferBitField = TRUE;
+ }
+ break;
+
+ //
+ // Scope End
+ //
+ case EFI_IFR_END_OP:
+ QuestionReferBitField = FALSE;
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ ResetScopeStack ();
+ return Status;
+ }
+
+ //
+ // Parent statement end tag found, update ParentStatement info.
+ //
+ if (IsStatementOpCode(ScopeOpCode) && (ParentStatement != NULL) && (ParentStatement->Operand == ScopeOpCode)) {
+ ParentStatement = ParentStatement->ParentStatement;
+ }
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // End of FormSet, update FormSet IFR binary length
+ // to stop parsing substantial OpCodes
+ //
+ FormSet->IfrBinaryLength = OpCodeOffset;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // End of Form
+ //
+ CurrentForm = NULL;
+ SuppressForQuestion = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // End of Option
+ //
+ CurrentOption = NULL;
+ break;
+
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
+ //
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ if (SuppressForOption) {
+ PopConditionalExpression(ExpressOption);
+ } else if (SuppressForQuestion) {
+ PopConditionalExpression(ExpressStatement);
+ } else {
+ PopConditionalExpression(ExpressForm);
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ PopConditionalExpression(ExpressStatement);
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ if (CurrentForm != NULL) {
+ PopConditionalExpression(ExpressStatement);
+ }
+ InScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ SuppressForOption = FALSE;
+ break;
+
+ case EFI_IFR_DEFAULT_OP:
+ InScopeDefault = FALSE;
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Get current Map Expression List.
+ //
+ Status = PopMapExpressionList ((VOID **) &MapExpressionList);
+ if (Status == EFI_ACCESS_DENIED) {
+ MapExpressionList = NULL;
+ }
+ //
+ // Get current expression.
+ //
+ Status = PopCurrentExpression ((VOID **) &CurrentExpression);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapScopeDepth > 0);
+ MapScopeDepth --;
+ break;
+
+ default:
+ if (IsExpressionOpCode (ScopeOpCode)) {
+ if (InScopeDisable && CurrentForm == NULL) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ ASSERT (CurrentExpression != NULL);
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OpCodeDisabled = IsTrue (&CurrentExpression->Result);
+
+ //
+ // DisableIf Expression is only used once and not queued, free it
+ //
+ DestroyExpression (CurrentExpression);
+ }
+
+ //
+ // End of current Expression
+ //
+ CurrentExpression = NULL;
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (IsStatementOpCode(Operand)) {
+ CurrentStatement->ParentStatement = ParentStatement;
+ if (Scope != 0) {
+ //
+ // Scope != 0, other statements or options may nest in this statement.
+ // Update the ParentStatement info.
+ //
+ ParentStatement = CurrentStatement;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
new file mode 100644
index 000000000..7f8587373
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
@@ -0,0 +1,2645 @@
+/** @file
+Utility functions for UI presentation.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Setup.h"
+
+BOOLEAN mHiiPackageListUpdated;
+UI_MENU_SELECTION *gCurrentSelection;
+EFI_HII_HANDLE mCurrentHiiHandle = NULL;
+EFI_GUID mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
+UINT16 mCurrentFormId = 0;
+EFI_EVENT mValueChangedEvent = NULL;
+LIST_ENTRY mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
+UINT16 mCurFakeQestId;
+FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
+BOOLEAN mFinishRetrieveCall = FALSE;
+BOOLEAN mDynamicFormUpdated = FALSE;
+
+/**
+ Check whether the ConfigAccess protocol is available.
+
+ @param FormSet FormSet of which the ConfigAcces protocol need to be checked.
+
+ @retval EFI_SUCCESS The function executed successfully.
+
+**/
+EFI_STATUS
+CheckConfigAccess(
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->HandleProtocol (
+ FormSet->DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &FormSet->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Configuration Driver don't attach ConfigAccess protocol to its HII package
+ // list, then there will be no configuration action required.
+ // Or the ConfigAccess protocol has been uninstalled.
+ //
+ FormSet->ConfigAccess = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Evaluate all expressions in a Form.
+
+ @param FormSet FormSet this Form belongs to.
+ @param Form The Form.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+
+**/
+EFI_STATUS
+EvaluateFormExpressions (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ while (!IsNull (&Form->ExpressionListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ExpressionListHead, Link);
+
+ if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||
+ Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||
+ Expression->Type == EFI_HII_EXPRESSION_WARNING_IF ||
+ Expression->Type == EFI_HII_EXPRESSION_WRITE ||
+ (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {
+ //
+ // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
+ //
+ continue;
+ }
+
+ Status = EvaluateExpression (FormSet, Form, Expression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Base on the opcode buffer info to get the display statement.
+
+ @param OpCode The input opcode buffer for this statement.
+
+ @retval Statement The statement use this opcode buffer.
+
+**/
+FORM_DISPLAY_ENGINE_STATEMENT *
+GetDisplayStatement (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gDisplayFormData.StatementListHead);
+ while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {
+ DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+
+ if (DisplayStatement->OpCode == OpCode) {
+ return DisplayStatement;
+ }
+ Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Free the refresh event list.
+
+**/
+VOID
+FreeRefreshEvent (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+
+ while (!IsListEmpty (&mRefreshEventList)) {
+ Link = GetFirstNode (&mRefreshEventList);
+ EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);
+ RemoveEntryList (&EventNode->Link);
+
+ gBS->CloseEvent (EventNode->RefreshEvent);
+
+ FreePool (EventNode);
+ }
+}
+
+/**
+ Check whether this statement value is changed. If yes, update the statement value and return TRUE;
+ else return FALSE.
+
+ @param Statement The statement need to check.
+
+**/
+VOID
+UpdateStatement (
+ IN OUT FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
+
+ //
+ // Reset FormPackage update flag
+ //
+ mHiiPackageListUpdated = FALSE;
+
+ //
+ // Question value may be changed, need invoke its Callback()
+ //
+ ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
+
+ if (mHiiPackageListUpdated) {
+ //
+ // Package list is updated, force to reparse IFR binary of target Formset
+ //
+ mHiiPackageListUpdated = FALSE;
+ gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
+ }
+}
+
+/**
+ Refresh the question which has refresh guid event attribute.
+
+ @param Event The event which has this function related.
+ @param Context The input context info related to this event or the status code return to the caller.
+**/
+VOID
+EFIAPI
+RefreshEventNotifyForStatement(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+
+ Statement = (FORM_BROWSER_STATEMENT *)Context;
+ UpdateStatement(Statement);
+ gBS->SignalEvent (mValueChangedEvent);
+}
+
+/**
+ Refresh the questions within this form.
+
+ @param Event The event which has this function related.
+ @param Context The input context info related to this event or the status code return to the caller.
+**/
+VOID
+EFIAPI
+RefreshEventNotifyForForm(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
+
+ gBS->SignalEvent (mValueChangedEvent);
+}
+
+/**
+ Create refresh hook event for statement which has refresh event or interval.
+
+ @param Statement The statement need to check.
+
+**/
+VOID
+CreateRefreshEventForStatement (
+ IN FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT RefreshEvent;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+
+ //
+ // If question has refresh guid, create the notify function.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ RefreshEventNotifyForStatement,
+ Statement,
+ &Statement->RefreshGuid,
+ &RefreshEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
+ ASSERT (EventNode != NULL);
+ EventNode->RefreshEvent = RefreshEvent;
+ InsertTailList(&mRefreshEventList, &EventNode->Link);
+}
+
+/**
+ Create refresh hook event for form which has refresh event or interval.
+
+ @param Form The form need to check.
+
+**/
+VOID
+CreateRefreshEventForForm (
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT RefreshEvent;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+
+ //
+ // If question has refresh guid, create the notify function.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ RefreshEventNotifyForForm,
+ Form,
+ &Form->RefreshGuid,
+ &RefreshEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
+ ASSERT (EventNode != NULL);
+ EventNode->RefreshEvent = RefreshEvent;
+ InsertTailList(&mRefreshEventList, &EventNode->Link);
+}
+
+/**
+
+ Initialize the Display statement structure data.
+
+ @param DisplayStatement Pointer to the display Statement data strucure.
+ @param Statement The statement need to check.
+**/
+VOID
+InitializeDisplayStatement (
+ IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
+ IN FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ DISPLAY_QUESTION_OPTION *DisplayOption;
+ FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement;
+
+ DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
+ DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
+ DisplayStatement->OpCode = Statement->OpCode;
+ InitializeListHead (&DisplayStatement->NestStatementList);
+ InitializeListHead (&DisplayStatement->OptionListHead);
+
+ if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {
+ DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;
+ }
+ if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {
+ DisplayStatement->Attribute |= HII_DISPLAY_READONLY;
+ }
+
+ //
+ // Initilize the option list in statement.
+ //
+ Link = GetFirstNode (&Statement->OptionListHead);
+ while (!IsNull (&Statement->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Statement->OptionListHead, Link);
+ if ((Option->SuppressExpression != NULL) &&
+ ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
+ continue;
+ }
+
+ DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));
+ ASSERT (DisplayOption != NULL);
+
+ DisplayOption->ImageId = Option->ImageId;
+ DisplayOption->Signature = DISPLAY_QUESTION_OPTION_SIGNATURE;
+ DisplayOption->OptionOpCode = Option->OpCode;
+ InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);
+ }
+
+ CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));
+
+ //
+ // Some special op code need an extra buffer to save the data.
+ // Such as string, password, orderedlist...
+ //
+ if (Statement->BufferValue != NULL) {
+ //
+ // Ordered list opcode may not initilized, get default value here.
+ //
+ if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {
+ GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);
+ }
+
+ DisplayStatement->CurrentValue.Buffer = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);
+ DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;
+ }
+
+ DisplayStatement->SettingChangedFlag = Statement->ValueChanged;
+
+ //
+ // Get the highlight statement for current form.
+ //
+ if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||
+ ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {
+ gDisplayFormData.HighLightedStatement = DisplayStatement;
+ }
+
+ //
+ // Create the refresh event process function.
+ //
+ if (!IsZeroGuid (&Statement->RefreshGuid)) {
+ CreateRefreshEventForStatement (Statement);
+ }
+
+ //
+ // For RTC type of date/time, set default refresh interval to be 1 second.
+ //
+ if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {
+ Statement->RefreshInterval = 1;
+ }
+
+ //
+ // Create the refresh guid hook event.
+ // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
+ //
+ if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) {
+ gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
+ }
+
+ //
+ // Save the password check function for later use.
+ //
+ if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
+ DisplayStatement->PasswordCheck = PasswordCheck;
+ }
+
+ //
+ // If this statement is nest in the subtitle, insert to the host statement.
+ // else insert to the form it belongs to.
+ //
+ if (Statement->ParentStatement != NULL) {
+ ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode);
+ ASSERT (ParentStatement != NULL);
+ InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);
+ } else {
+ InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
+ }
+}
+
+/**
+ Process for the refresh interval statement.
+
+ @param Event The Event need to be process
+ @param Context The context of the event.
+
+**/
+VOID
+EFIAPI
+RefreshIntervalProcess (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+
+ if (Statement->RefreshInterval == 0) {
+ continue;
+ }
+
+ UpdateStatement(Statement);
+ }
+
+ gBS->SignalEvent (mValueChangedEvent);
+}
+
+/**
+
+ Make a copy of the global hotkey info.
+
+**/
+VOID
+UpdateHotkeyList (
+ VOID
+ )
+{
+ BROWSER_HOT_KEY *HotKey;
+ BROWSER_HOT_KEY *CopyKey;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gBrowserHotKeyList);
+ while (!IsNull (&gBrowserHotKeyList, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+
+ CopyKey = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);
+ ASSERT (CopyKey != NULL);
+ CopyKey->KeyData = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);
+ ASSERT (CopyKey->KeyData != NULL);
+ CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);
+ ASSERT (CopyKey->HelpString != NULL);
+
+ InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
+
+ Link = GetNextNode (&gBrowserHotKeyList, Link);
+ }
+}
+
+/**
+
+ Get the extra question attribute from override question list.
+
+ @param QuestionId The question id for this request question.
+
+ @retval The attribute for this question or NULL if not found this
+ question in the list.
+
+**/
+UINT32
+ProcessQuestionExtraAttr (
+ IN EFI_QUESTION_ID QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_ATTRIBUTE_OVERRIDE *QuestionDesc;
+
+ //
+ // Return HII_DISPLAY_NONE if input a invalid question id.
+ //
+ if (QuestionId == 0) {
+ return HII_DISPLAY_NONE;
+ }
+
+ Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
+ while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) {
+ QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link);
+ Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link);
+
+ if ((QuestionDesc->QuestionId == QuestionId) &&
+ (QuestionDesc->FormId == gCurrentSelection->FormId) &&
+ (QuestionDesc->HiiHandle == gCurrentSelection->Handle) &&
+ CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) {
+ return QuestionDesc->Attribute;
+ }
+ }
+
+ return HII_DISPLAY_NONE;
+}
+
+/**
+
+ Enum all statement in current form, find all the statement can be display and
+ add to the display form.
+
+**/
+VOID
+AddStatementToDisplayForm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
+ UINT8 MinRefreshInterval;
+ EFI_EVENT RefreshIntervalEvent;
+ FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
+ BOOLEAN FormEditable;
+ UINT32 ExtraAttribute;
+
+ MinRefreshInterval = 0;
+ FormEditable = FALSE;
+
+ //
+ // Process the statement outside the form, these statements are not recognized
+ // by browser core.
+ //
+ Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
+ while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
+
+ DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (DisplayStatement != NULL);
+ DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
+ DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
+ DisplayStatement->OpCode = Statement->OpCode;
+
+ InitializeListHead (&DisplayStatement->NestStatementList);
+ InitializeListHead (&DisplayStatement->OptionListHead);
+
+ InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
+ }
+
+ //
+ // treat formset as statement outside the form,get its opcode.
+ //
+ DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (DisplayStatement != NULL);
+
+ DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
+ DisplayStatement->Version = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
+ DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode;
+
+ InitializeListHead (&DisplayStatement->NestStatementList);
+ InitializeListHead (&DisplayStatement->OptionListHead);
+
+ InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
+
+ //
+ // Process the statement in this form.
+ //
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+
+ //
+ // This statement can't be show, skip it.
+ //
+ if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
+ continue;
+ }
+
+ //
+ // Check the extra attribute.
+ //
+ ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId);
+ if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) {
+ continue;
+ }
+
+ DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (DisplayStatement != NULL);
+
+ //
+ // Initialize this statement and add it to the display form.
+ //
+ InitializeDisplayStatement(DisplayStatement, Statement);
+
+ //
+ // Set the extra attribute.
+ //
+ DisplayStatement->Attribute |= ExtraAttribute;
+
+ if (Statement->Storage != NULL) {
+ FormEditable = TRUE;
+ }
+
+ //
+ // Get the minimal refresh interval value for later use.
+ //
+ if ((Statement->RefreshInterval != 0) &&
+ (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {
+ MinRefreshInterval = Statement->RefreshInterval;
+ }
+ }
+
+ //
+ // Create the periodic timer for refresh interval statement.
+ //
+ if (MinRefreshInterval != 0) {
+ Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
+ ASSERT_EFI_ERROR (Status);
+
+ EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
+ ASSERT (EventNode != NULL);
+ EventNode->RefreshEvent = RefreshIntervalEvent;
+ InsertTailList(&mRefreshEventList, &EventNode->Link);
+ }
+
+ //
+ // Create the refresh event process function for Form.
+ //
+ if (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) {
+ CreateRefreshEventForForm (gCurrentSelection->Form);
+ if (gDisplayFormData.FormRefreshEvent == NULL) {
+ gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
+ }
+ }
+
+ //
+ // Update hotkey list field.
+ //
+ if (gBrowserSettingScope == SystemLevel || FormEditable) {
+ UpdateHotkeyList();
+ }
+}
+
+/**
+
+ Initialize the SettingChangedFlag variable in the display form.
+
+**/
+VOID
+UpdateDataChangedFlag (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *LocalFormSet;
+
+ gDisplayFormData.SettingChangedFlag = FALSE;
+
+ if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
+ }
+
+ //
+ // Base on the system level to check whether need to show the NV flag.
+ //
+ switch (gBrowserSettingScope) {
+ case SystemLevel:
+ //
+ // Check the maintain list to see whether there is any change.
+ //
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
+ }
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ }
+ break;
+
+ case FormSetLevel:
+ if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {
+ gDisplayFormData.SettingChangedFlag = TRUE;
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+
+ Initialize the Display form structure data.
+
+**/
+VOID
+InitializeDisplayFormData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ gDisplayFormData.Signature = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
+ gDisplayFormData.Version = FORM_DISPLAY_ENGINE_VERSION_1;
+ gDisplayFormData.ImageId = 0;
+ gDisplayFormData.AnimationId = 0;
+
+ InitializeListHead (&gDisplayFormData.StatementListHead);
+ InitializeListHead (&gDisplayFormData.StatementListOSF);
+ InitializeListHead (&gDisplayFormData.HotKeyListHead);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_CALLBACK,
+ EfiEventEmptyFunction,
+ NULL,
+ &mValueChangedEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+
+ Free the kotkey info saved in form data.
+
+**/
+VOID
+FreeHotkeyList (
+ VOID
+ )
+{
+ BROWSER_HOT_KEY *HotKey;
+ LIST_ENTRY *Link;
+
+ while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
+ Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+
+ RemoveEntryList (&HotKey->Link);
+
+ FreePool (HotKey->KeyData);
+ FreePool (HotKey->HelpString);
+ FreePool (HotKey);
+ }
+}
+
+/**
+
+ Update the Display form structure data.
+
+**/
+VOID
+UpdateDisplayFormData (
+ VOID
+ )
+{
+ gDisplayFormData.FormTitle = gCurrentSelection->Form->FormTitle;
+ gDisplayFormData.FormId = gCurrentSelection->FormId;
+ gDisplayFormData.HiiHandle = gCurrentSelection->Handle;
+ CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
+
+ gDisplayFormData.Attribute = 0;
+ gDisplayFormData.Attribute |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
+ gDisplayFormData.Attribute |= gCurrentSelection->Form->Locked ? HII_DISPLAY_LOCK : 0;
+
+ gDisplayFormData.FormRefreshEvent = NULL;
+ gDisplayFormData.HighLightedStatement = NULL;
+
+ UpdateDataChangedFlag ();
+
+ AddStatementToDisplayForm ();
+}
+
+/**
+
+ Free the Display Statement structure data.
+
+ @param StatementList Point to the statement list which need to be free.
+
+**/
+VOID
+FreeStatementData (
+ LIST_ENTRY *StatementList
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *OptionLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ DISPLAY_QUESTION_OPTION *Option;
+
+ //
+ // Free Statements/Questions
+ //
+ while (!IsListEmpty (StatementList)) {
+ Link = GetFirstNode (StatementList);
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+
+ //
+ // Free Options List
+ //
+ while (!IsListEmpty (&Statement->OptionListHead)) {
+ OptionLink = GetFirstNode (&Statement->OptionListHead);
+ Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
+ RemoveEntryList (&Option->Link);
+ FreePool (Option);
+ }
+
+ //
+ // Free nest statement List
+ //
+ if (!IsListEmpty (&Statement->NestStatementList)) {
+ FreeStatementData(&Statement->NestStatementList);
+ }
+
+ RemoveEntryList (&Statement->DisplayLink);
+ FreePool (Statement);
+ }
+}
+
+/**
+
+ Free the Display form structure data.
+
+**/
+VOID
+FreeDisplayFormData (
+ VOID
+ )
+{
+ FreeStatementData (&gDisplayFormData.StatementListHead);
+ FreeStatementData (&gDisplayFormData.StatementListOSF);
+
+ FreeRefreshEvent();
+
+ FreeHotkeyList();
+}
+
+/**
+
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ LIST_ENTRY *Link;
+
+ Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
+ while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Statement->OpCode == DisplayStatement->OpCode) {
+ return Statement;
+ }
+
+ Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Update the ValueChanged status for questions in this form.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+UpdateStatementStatusForForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ //
+ // For password opcode, not set the the value changed flag.
+ //
+ if (Question->Operand == EFI_IFR_PASSWORD_OP) {
+ continue;
+ }
+
+ IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);
+ }
+}
+
+/**
+ Update the ValueChanged status for questions in this formset.
+
+ @param FormSet FormSet data structure.
+
+**/
+VOID
+UpdateStatementStatusForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ UpdateStatementStatusForForm (FormSet, Form);
+ }
+}
+
+/**
+ Update the ValueChanged status for questions.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Default action.
+
+**/
+VOID
+UpdateStatementStatus (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *LocalFormSet;
+
+ switch (SettingScope) {
+ case SystemLevel:
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(LocalFormSet)) {
+ continue;
+ }
+
+ UpdateStatementStatusForFormSet (LocalFormSet);
+ }
+ break;
+
+ case FormSetLevel:
+ UpdateStatementStatusForFormSet (FormSet);
+ break;
+
+ case FormLevel:
+ UpdateStatementStatusForForm (FormSet, Form);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+
+ Process the action request in user input.
+
+ @param Action The user input action request info.
+ @param DefaultId The user input default Id info.
+
+ @retval EFI_SUCESSS This function always return successfully for now.
+
+**/
+EFI_STATUS
+ProcessAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ )
+{
+ //
+ // This is caused by use press ESC, and it should not combine with other action type.
+ //
+ if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
+ FindNextMenu (gCurrentSelection, FormLevel);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Below is normal hotkey trigged action, these action maybe combine with each other.
+ //
+ if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ }
+
+ if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
+ ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
+ UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ }
+
+ if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
+ SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ }
+
+ if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
+ gResetRequiredFormLevel = TRUE;
+ gResetRequiredSystemLevel = TRUE;
+ }
+
+ if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
+ //
+ // Form Exit without saving, Similar to ESC Key.
+ // FormSet Exit without saving, Exit SendForm.
+ // System Exit without saving, CallExitHandler and Exit SendForm.
+ //
+ DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
+ if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
+ FindNextMenu (gCurrentSelection, gBrowserSettingScope);
+ } else if (gBrowserSettingScope == SystemLevel) {
+ if (ExitHandlerFunction != NULL) {
+ ExitHandlerFunction ();
+ }
+ gCurrentSelection->Action = UI_ACTION_EXIT;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the formset guid is in this Hii package list.
+
+ @param HiiHandle The HiiHandle for this HII package list.
+ @param FormSetGuid The formset guid for the request formset.
+
+ @retval TRUE Find the formset guid.
+ @retval FALSE Not found the formset guid.
+
+**/
+BOOLEAN
+GetFormsetGuidFromHiiHandle (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid
+ )
+{
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN BufferSize;
+ UINT32 Offset;
+ UINT32 Offset2;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ EFI_STATUS Status;
+ BOOLEAN FindGuid;
+
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ FindGuid = FALSE;
+
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status) || HiiPackageList == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ Offset2 = 0;
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
+
+ while (Offset < PackageListLength) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset += PackageHeader.Length;
+
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Search FormSet in this Form Package
+ //
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset2 < PackageHeader.Length) {
+ OpCodeData = Package + Offset2;
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
+ if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){
+ FindGuid = TRUE;
+ break;
+ }
+ }
+
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ }
+ }
+ if (FindGuid) {
+ break;
+ }
+ }
+
+ FreePool (HiiPackageList);
+
+ return FindGuid;
+}
+
+/**
+ Find HII Handle in the HII database associated with given Device Path.
+
+ If DevicePath is NULL, then ASSERT.
+
+ @param DevicePath Device Path associated with the HII package list
+ handle.
+ @param FormsetGuid The formset guid for this formset.
+
+ @retval Handle HII package list Handle associated with the Device
+ Path.
+ @retval NULL Hii Package list handle is not found.
+
+**/
+EFI_HII_HANDLE
+DevicePathToHiiHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_GUID *FormsetGuid
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ UINTN Index;
+ EFI_HANDLE Handle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+
+ ASSERT (DevicePath != NULL);
+
+ TmpDevicePath = DevicePath;
+ //
+ // Locate Device Path Protocol handle buffer
+ //
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TmpDevicePath,
+ &DriverHandle
+ );
+ if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
+ return NULL;
+ }
+
+ //
+ // Retrieve all HII Handles from HII database
+ //
+ HiiHandles = HiiGetHiiHandles (NULL);
+ if (HiiHandles == NULL) {
+ return NULL;
+ }
+
+ //
+ // Search Hii Handle by Driver Handle
+ //
+ HiiHandle = NULL;
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ Status = mHiiDatabase->GetPackageListHandle (
+ mHiiDatabase,
+ HiiHandles[Index],
+ &Handle
+ );
+ if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
+ if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {
+ HiiHandle = HiiHandles[Index];
+ break;
+ }
+
+ if (HiiHandle != NULL) {
+ break;
+ }
+ }
+ }
+
+ FreePool (HiiHandles);
+ return HiiHandle;
+}
+
+/**
+ Find HII Handle in the HII database associated with given form set guid.
+
+ If FormSetGuid is NULL, then ASSERT.
+
+ @param ComparingGuid FormSet Guid associated with the HII package list
+ handle.
+
+ @retval Handle HII package list Handle associated with the Device
+ Path.
+ @retval NULL Hii Package list handle is not found.
+
+**/
+EFI_HII_HANDLE
+FormSetGuidToHiiHandle (
+ EFI_GUID *ComparingGuid
+ )
+{
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+ UINTN Index;
+
+ ASSERT (ComparingGuid != NULL);
+
+ HiiHandle = NULL;
+ //
+ // Get all the Hii handles
+ //
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ //
+ // Search for formset of each class type
+ //
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {
+ HiiHandle = HiiHandles[Index];
+ break;
+ }
+
+ if (HiiHandle != NULL) {
+ break;
+ }
+ }
+
+ FreePool (HiiHandles);
+
+ return HiiHandle;
+}
+
+/**
+ check how to process the changed data in current form or form set.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+
+ @param Scope Data save or discard scope, form or formset.
+
+ @retval TRUE Success process the changed data, will return to the parent form.
+ @retval FALSE Reject to process the changed data, will stay at current form.
+**/
+BOOLEAN
+ProcessChangedData (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE Scope
+ )
+{
+ BOOLEAN RetValue;
+ EFI_STATUS Status;
+
+ RetValue = TRUE;
+ switch (mFormDisplay->ConfirmDataChange()) {
+ case BROWSER_ACTION_DISCARD:
+ DiscardForm (Selection->FormSet, Selection->Form, Scope);
+ break;
+
+ case BROWSER_ACTION_SUBMIT:
+ Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);
+ if (EFI_ERROR (Status)) {
+ RetValue = FALSE;
+ }
+ break;
+
+ case BROWSER_ACTION_NONE:
+ RetValue = FALSE;
+ break;
+
+ default:
+ //
+ // if Invalid value return, process same as BROWSER_ACTION_NONE.
+ //
+ RetValue = FALSE;
+ break;
+ }
+
+ return RetValue;
+}
+
+/**
+ Find parent formset menu(the first menu which has different formset) for current menu.
+ If not find, just return to the first menu.
+
+ @param Selection The selection info.
+
+**/
+VOID
+FindParentFormSet (
+ IN OUT UI_MENU_SELECTION *Selection
+ )
+{
+ FORM_ENTRY_INFO *CurrentMenu;
+ FORM_ENTRY_INFO *ParentMenu;
+
+ CurrentMenu = Selection->CurrentMenu;
+ ParentMenu = UiFindParentMenu(CurrentMenu, FormSetLevel);
+
+ if (ParentMenu != NULL) {
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
+ Selection->Handle = ParentMenu->HiiHandle;
+ Selection->FormId = ParentMenu->FormId;
+ Selection->QuestionId = ParentMenu->QuestionId;
+ } else {
+ Selection->FormId = CurrentMenu->FormId;
+ Selection->QuestionId = CurrentMenu->QuestionId;
+ }
+
+ Selection->Statement = NULL;
+}
+
+/**
+ Process the goto op code, update the info in the selection structure.
+
+ @param Statement The statement belong to goto op code.
+ @param Selection The selection info.
+
+ @retval EFI_SUCCESS The menu process successfully.
+ @return Other value if the process failed.
+**/
+EFI_STATUS
+ProcessGotoOpCode (
+ IN OUT FORM_BROWSER_STATEMENT *Statement,
+ IN OUT UI_MENU_SELECTION *Selection
+ )
+{
+ CHAR16 *StringPtr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ FORM_BROWSER_FORM *RefForm;
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+
+ Status = EFI_SUCCESS;
+ StringPtr = NULL;
+ HiiHandle = NULL;
+
+ //
+ // Prepare the device path check, get the device path info first.
+ //
+ if (Statement->HiiValue.Value.ref.DevicePath != 0) {
+ StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
+ }
+
+ //
+ // Check whether the device path string is a valid string.
+ //
+ if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {
+ if (Selection->Form->ModalForm) {
+ return Status;
+ }
+
+ //
+ // Goto another Hii Package list
+ //
+ if (mPathFromText != NULL) {
+ DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
+ if (DevicePath != NULL) {
+ HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
+ FreePool (DevicePath);
+ }
+ FreePool (StringPtr);
+ } else {
+ //
+ // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
+ //
+ PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);
+ FreePool (StringPtr);
+ return Status;
+ }
+
+ if (HiiHandle != Selection->Handle) {
+ //
+ // Goto another Formset, check for uncommitted data
+ //
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
+ if (!ProcessChangedData(Selection, FormSetLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ Selection->Handle = HiiHandle;
+ if (Selection->Handle == NULL) {
+ //
+ // If target Hii Handle not found, exit current formset.
+ //
+ FindParentFormSet(Selection);
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {
+ if (Selection->Form->ModalForm) {
+ return Status;
+ }
+ if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
+ //
+ // Goto another Formset, check for uncommitted data
+ //
+ if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
+ IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
+ if (!ProcessChangedData(Selection, FormSetLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
+ if (Selection->Handle == NULL) {
+ //
+ // If target Hii Handle not found, exit current formset.
+ //
+ FindParentFormSet(Selection);
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (Statement->HiiValue.Value.ref.FormId != 0) {
+ //
+ // Goto another Form, check for uncommitted data
+ //
+ if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
+ if (!ProcessChangedData (Selection, FormLevel)) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
+ if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
+ if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
+ //
+ // Form is suppressed.
+ //
+ PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
+ return EFI_SUCCESS;
+ }
+ }
+
+ Selection->FormId = Statement->HiiValue.Value.ref.FormId;
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
+ Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
+ }
+
+ return Status;
+}
+
+
+/**
+ Process Question Config.
+
+ @param Selection The UI menu selection.
+ @param Question The Question to be peocessed.
+
+ @retval EFI_SUCCESS Question Config process success.
+ @retval Other Question Config process fail.
+
+**/
+EFI_STATUS
+ProcessQuestionConfig (
+ IN UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ConfigResp;
+ CHAR16 *Progress;
+
+ if (Question->QuestionConfig == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get <ConfigResp>
+ //
+ ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
+ if (ConfigResp == NULL) {
+ return EFI_NOT_FOUND;
+ } else if (ConfigResp[0] == L'\0') {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Send config to Configuration Driver
+ //
+ Status = mHiiConfigRouting->RouteConfig (
+ mHiiConfigRouting,
+ ConfigResp,
+ &Progress
+ );
+
+ return Status;
+}
+
+/**
+
+ Process the user input data.
+
+ @param UserInput The user input data.
+
+ @retval EFI_SUCESSS This function always return successfully for now.
+
+**/
+EFI_STATUS
+ProcessUserInput (
+ IN USER_INPUT *UserInput
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ Status = EFI_SUCCESS;
+ Statement = NULL;
+
+ //
+ // When Exit from FormDisplay function, one of the below two cases must be true.
+ //
+ ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
+
+ //
+ // Remove the last highligh question id, this id will update when show next form.
+ //
+ gCurrentSelection->QuestionId = 0;
+ if (UserInput->SelectedStatement != NULL){
+ Statement = GetBrowserStatement(UserInput->SelectedStatement);
+ ASSERT (Statement != NULL);
+
+ //
+ // This question is the current user select one,record it and later
+ // show it as the highlight question.
+ //
+ gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
+ //
+ // For statement like text, actio, it not has question id.
+ // So use FakeQuestionId to save the question.
+ //
+ if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
+ mCurFakeQestId = Statement->FakeQuestionId;
+ } else {
+ mCurFakeQestId = 0;
+ }
+ }
+
+ //
+ // First process the Action field in USER_INPUT.
+ //
+ if (UserInput->Action != 0) {
+ Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
+ gCurrentSelection->Statement = NULL;
+ } else {
+ ASSERT (Statement != NULL);
+ gCurrentSelection->Statement = Statement;
+ switch (Statement->Operand) {
+ case EFI_IFR_REF_OP:
+ Status = ProcessGotoOpCode(Statement, gCurrentSelection);
+ break;
+
+ case EFI_IFR_ACTION_OP:
+ //
+ // Process the Config string <ConfigResp>
+ //
+ Status = ProcessQuestionConfig (gCurrentSelection, Statement);
+ break;
+
+ case EFI_IFR_RESET_BUTTON_OP:
+ //
+ // Reset Question to default value specified by DefaultId
+ //
+ Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);
+ UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);
+ break;
+
+ default:
+ switch (Statement->Operand) {
+ case EFI_IFR_STRING_OP:
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
+ FreePool (UserInput->InputValue.Buffer);
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ if (UserInput->InputValue.Buffer == NULL) {
+ //
+ // User not input new password, just return.
+ //
+ break;
+ }
+
+ DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
+ Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
+ ZeroMem (UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
+ FreePool (UserInput->InputValue.Buffer);
+ //
+ // Two password match, send it to Configuration Driver
+ //
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
+ PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
+ //
+ // Clean the value after saved it.
+ //
+ ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
+ HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
+ } else {
+ SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
+ break;
+
+ default:
+ CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
+ break;
+ }
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+
+ Display form and wait for user to select one menu option, then return it.
+
+ @retval EFI_SUCESSS This function always return successfully for now.
+
+**/
+EFI_STATUS
+DisplayForm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ USER_INPUT UserInput;
+ FORM_ENTRY_INFO *CurrentMenu;
+
+ ZeroMem (&UserInput, sizeof (USER_INPUT));
+
+ //
+ // Update the menu history data.
+ //
+ CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
+ if (CurrentMenu == NULL) {
+ //
+ // Current menu not found, add it to the menu tree
+ //
+ CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
+ gCurrentSelection->FormId, gCurrentSelection->QuestionId);
+ ASSERT (CurrentMenu != NULL);
+ }
+
+ //
+ // Back up the form view history data for this form.
+ //
+ UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
+
+ gCurrentSelection->CurrentMenu = CurrentMenu;
+
+ if (gCurrentSelection->QuestionId == 0) {
+ //
+ // Highlight not specified, fetch it from cached menu
+ //
+ gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
+ }
+
+ Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UpdateDisplayFormData ();
+
+ ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
+ Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
+ if (EFI_ERROR (Status)) {
+ FreeDisplayFormData();
+ return Status;
+ }
+
+ CheckConfigAccess(gCurrentSelection->FormSet);
+
+ Status = ProcessUserInput (&UserInput);
+ FreeDisplayFormData();
+ return Status;
+}
+
+/**
+ Functions which are registered to receive notification of
+ database events have this prototype. The actual event is encoded
+ in NotifyType. The following table describes how PackageType,
+ PackageGuid, Handle, and Package are used for each of the
+ notification types.
+
+ @param PackageType Package type of the notification.
+
+ @param PackageGuid If PackageType is
+ EFI_HII_PACKAGE_TYPE_GUID, then this is
+ the pointer to the GUID from the Guid
+ field of EFI_HII_PACKAGE_GUID_HEADER.
+ Otherwise, it must be NULL.
+
+ @param Package Points to the package referred to by the
+ notification Handle The handle of the package
+ list which contains the specified package.
+
+ @param Handle The HII handle.
+
+ @param NotifyType The type of change concerning the
+ database. See
+ EFI_HII_DATABASE_NOTIFY_TYPE.
+
+**/
+EFI_STATUS
+EFIAPI
+FormUpdateNotify (
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN CONST EFI_HII_PACKAGE_HEADER *Package,
+ IN EFI_HII_HANDLE Handle,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
+ )
+{
+ mHiiPackageListUpdated = TRUE;
+ mDynamicFormUpdated = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the NV flag info for this form set.
+
+ @param FormSet FormSet data structure.
+
+**/
+BOOLEAN
+IsNvUpdateRequiredForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+ BOOLEAN RetVal;
+
+ //
+ // Not finished question initialization, return FALSE.
+ //
+ if (!FormSet->QuestionInited) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ RetVal = IsNvUpdateRequiredForForm(Form);
+ if (RetVal) {
+ break;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ return RetVal;
+}
+
+/**
+ Update the NvUpdateRequired flag for a form.
+
+ @param Form Form data structure.
+
+**/
+BOOLEAN
+IsNvUpdateRequiredForForm (
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Statement->ValueChanged) {
+ return TRUE;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find menu which will show next time.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+ @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
+ else, we need to exit current formset.
+
+ @retval TRUE Exit current form.
+ @retval FALSE User press ESC and keep in current form.
+**/
+BOOLEAN
+FindNextMenu (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE SettingLevel
+ )
+{
+ FORM_ENTRY_INFO *CurrentMenu;
+ FORM_ENTRY_INFO *ParentMenu;
+ BROWSER_SETTING_SCOPE Scope;
+
+ CurrentMenu = Selection->CurrentMenu;
+ Scope = FormSetLevel;
+
+ ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);
+ while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {
+ ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);
+ }
+
+ if (ParentMenu != NULL) {
+ if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
+ Scope = FormLevel;
+ } else {
+ Scope = FormSetLevel;
+ }
+ }
+
+ //
+ // Form Level Check whether the data is changed.
+ //
+ if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
+ (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
+ if (!ProcessChangedData(Selection, gBrowserSettingScope)) {
+ return FALSE;
+ }
+ }
+
+ if (ParentMenu != NULL) {
+ //
+ // ParentMenu is found. Then, go to it.
+ //
+ if (Scope == FormLevel) {
+ Selection->Action = UI_ACTION_REFRESH_FORM;
+ } else {
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
+ Selection->Handle = ParentMenu->HiiHandle;
+ }
+
+ Selection->Statement = NULL;
+
+ Selection->FormId = ParentMenu->FormId;
+ Selection->QuestionId = ParentMenu->QuestionId;
+
+ //
+ // Clear highlight record for this menu
+ //
+ CurrentMenu->QuestionId = 0;
+ return FALSE;
+ }
+
+ //
+ // Current in root page, exit the SendForm
+ //
+ Selection->Action = UI_ACTION_EXIT;
+
+ return TRUE;
+}
+
+/**
+ Reconnect the controller.
+
+ @param DriverHandle The controller handle which need to be reconnect.
+
+ @retval TRUE do the reconnect behavior success.
+ @retval FALSE do the reconnect behavior failed.
+
+**/
+BOOLEAN
+ReconnectController (
+ IN EFI_HANDLE DriverHandle
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->DisconnectController(DriverHandle, NULL, NULL);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);
+ }
+
+ return Status == EFI_SUCCESS;
+}
+
+/**
+ Call the call back function for the question and process the return action.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+ @param FormSet The formset this question belong to.
+ @param Form The form this question belong to.
+ @param Question The Question which need to call.
+ @param Action The action request.
+ @param SkipSaveOrDiscard Whether skip save or discard action.
+
+ @retval EFI_SUCCESS The call back function executes successfully.
+ @return Other value if the call back function failed to execute.
+**/
+EFI_STATUS
+ProcessCallBackFunction (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_BROWSER_ACTION Action,
+ IN BOOLEAN SkipSaveOrDiscard
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS InternalStatus;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_HII_VALUE *HiiValue;
+ EFI_IFR_TYPE_VALUE *TypeValue;
+ FORM_BROWSER_STATEMENT *Statement;
+ BOOLEAN SubmitFormIsRequired;
+ BOOLEAN DiscardFormIsRequired;
+ BOOLEAN NeedExit;
+ LIST_ENTRY *Link;
+ BROWSER_SETTING_SCOPE SettingLevel;
+ EFI_IFR_TYPE_VALUE BackUpValue;
+ UINT8 *BackUpBuffer;
+ CHAR16 *NewString;
+
+ ConfigAccess = FormSet->ConfigAccess;
+ SubmitFormIsRequired = FALSE;
+ SettingLevel = FormSetLevel;
+ DiscardFormIsRequired = FALSE;
+ NeedExit = FALSE;
+ Status = EFI_SUCCESS;
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ BackUpBuffer = NULL;
+
+ if (ConfigAccess == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ //
+ // if Question != NULL, only process the question. Else, process all question in this form.
+ //
+ if ((Question != NULL) && (Statement != Question)) {
+ continue;
+ }
+
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
+ continue;
+ }
+
+ //
+ // Check whether Statement is disabled.
+ //
+ if (Statement->Expression != NULL) {
+ if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
+ continue;
+ }
+ }
+
+ HiiValue = &Statement->HiiValue;
+ TypeValue = &HiiValue->Value;
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+ //
+ // For OrderedList, passing in the value buffer to Callback()
+ //
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
+ }
+
+ //
+ // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
+ //
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+ BackUpBuffer = AllocateCopyPool(Statement->StorageWidth, Statement->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ } else {
+ CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
+ }
+ }
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = ConfigAccess->Callback (
+ ConfigAccess,
+ Action,
+ Statement->QuestionId,
+ HiiValue->Type,
+ TypeValue,
+ &ActionRequest
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
+ //
+ if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
+ NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
+ ASSERT (NewString != NULL);
+
+ ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
+ if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
+ ZeroMem (Statement->BufferValue, Statement->StorageWidth);
+ CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
+ } else {
+ CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
+ }
+ FreePool (NewString);
+ }
+
+ //
+ // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
+ //
+ switch (Action) {
+ case EFI_BROWSER_ACTION_CHANGED:
+ switch (ActionRequest) {
+ case EFI_BROWSER_ACTION_REQUEST_RESET:
+ DiscardFormIsRequired = TRUE;
+ gResetRequiredFormLevel = TRUE;
+ gResetRequiredSystemLevel = TRUE;
+ NeedExit = TRUE;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
+ SubmitFormIsRequired = TRUE;
+ NeedExit = TRUE;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_EXIT:
+ DiscardFormIsRequired = TRUE;
+ NeedExit = TRUE;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
+ SubmitFormIsRequired = TRUE;
+ SettingLevel = FormLevel;
+ NeedExit = TRUE;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
+ DiscardFormIsRequired = TRUE;
+ SettingLevel = FormLevel;
+ NeedExit = TRUE;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
+ SubmitFormIsRequired = TRUE;
+ SettingLevel = FormLevel;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
+ DiscardFormIsRequired = TRUE;
+ SettingLevel = FormLevel;
+ break;
+
+ case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
+ gCallbackReconnect = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_CHANGING:
+ //
+ // Do the question validation.
+ //
+ Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
+ if (!EFI_ERROR (Status)) {
+ //
+ //check whether the question value changed compared with edit buffer before updating edit buffer
+ // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
+ //
+ IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
+ //
+ // According the spec, return value from call back of "changing" and
+ // "retrieve" should update to the question's temp buffer.
+ //
+ SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_RETRIEVE:
+ //
+ // According the spec, return value from call back of "changing" and
+ // "retrieve" should update to the question's temp buffer.
+ //
+ SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ //
+ // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
+ // then the browser will use the value passed to Callback() and ignore the
+ // value returned by Callback().
+ //
+ if (Action == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+ CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth);
+ } else {
+ CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
+ }
+
+ //
+ // Do the question validation.
+ //
+ InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
+ if (!EFI_ERROR (InternalStatus)) {
+ //
+ //check whether the question value changed compared with edit buffer before updating edit buffer
+ // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
+ //
+ IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
+ SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
+ }
+ }
+
+ //
+ // According the spec, return fail from call back of "changing" and
+ // "retrieve", should restore the question's value.
+ //
+ if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {
+ if (Statement->Storage != NULL) {
+ GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
+ } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
+ ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
+ }
+ }
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
+ }
+
+ if (Status == EFI_UNSUPPORTED) {
+ //
+ // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
+ //
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ if (BackUpBuffer != NULL) {
+ FreePool (BackUpBuffer);
+ }
+
+ //
+ // If Question != NULL, means just process one question
+ // and if code reach here means this question has finished
+ // processing, so just break.
+ //
+ if (Question != NULL) {
+ break;
+ }
+ }
+
+ if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
+ //
+ // Confirm changes with user first.
+ //
+ if (IsNvUpdateRequiredForFormSet(FormSet)) {
+ if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
+ gCallbackReconnect = FALSE;
+ DiscardFormIsRequired = TRUE;
+ } else {
+ SubmitFormIsRequired = TRUE;
+ }
+ } else {
+ PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
+ }
+
+ //
+ // Exit current formset before do the reconnect.
+ //
+ NeedExit = TRUE;
+ SettingLevel = FormSetLevel;
+ }
+
+ if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
+ SubmitForm (FormSet, Form, SettingLevel);
+ }
+
+ if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
+ DiscardForm (FormSet, Form, SettingLevel);
+ }
+
+ if (NeedExit) {
+ FindNextMenu (Selection, SettingLevel);
+ }
+
+ return Status;
+}
+
+/**
+ Call the retrieve type call back function for one question to get the initialize data.
+
+ This function only used when in the initialize stage, because in this stage, the
+ Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
+
+ @param ConfigAccess The config access protocol produced by the hii driver.
+ @param Statement The Question which need to call.
+ @param FormSet The formset this question belong to.
+
+ @retval EFI_SUCCESS The call back function executes successfully.
+ @return Other value if the call back function failed to execute.
+**/
+EFI_STATUS
+ProcessRetrieveForQuestion (
+ IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
+ IN FORM_BROWSER_STATEMENT *Statement,
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_HII_VALUE *HiiValue;
+ EFI_IFR_TYPE_VALUE *TypeValue;
+ CHAR16 *NewString;
+
+ Status = EFI_SUCCESS;
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+
+ if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HiiValue = &Statement->HiiValue;
+ TypeValue = &HiiValue->Value;
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+ //
+ // For OrderedList, passing in the value buffer to Callback()
+ //
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
+ }
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = ConfigAccess->Callback (
+ ConfigAccess,
+ EFI_BROWSER_ACTION_RETRIEVE,
+ Statement->QuestionId,
+ HiiValue->Type,
+ TypeValue,
+ &ActionRequest
+ );
+ if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
+ NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
+ ASSERT (NewString != NULL);
+
+ ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
+ if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
+ ZeroMem (Statement->BufferValue, Statement->StorageWidth);
+ CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
+ } else {
+ CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
+ }
+ FreePool (NewString);
+ }
+
+ return Status;
+}
+
+/**
+ The worker function that send the displays to the screen. On output,
+ the selection made by user is returned.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+
+ @retval EFI_SUCCESS The page is displayed successfully.
+ @return Other value if the page failed to be diplayed.
+
+**/
+EFI_STATUS
+SetupBrowser (
+ IN OUT UI_MENU_SELECTION *Selection
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_HANDLE NotifyHandle;
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ ConfigAccess = Selection->FormSet->ConfigAccess;
+
+ //
+ // Register notify for Form package update
+ //
+ Status = mHiiDatabase->RegisterPackageNotify (
+ mHiiDatabase,
+ EFI_HII_PACKAGE_FORMS,
+ NULL,
+ FormUpdateNotify,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ &NotifyHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize current settings of Questions in this FormSet
+ //
+ InitializeCurrentSetting (Selection->FormSet);
+
+ //
+ // Initilize Action field.
+ //
+ Selection->Action = UI_ACTION_REFRESH_FORM;
+
+ //
+ // Clean the mCurFakeQestId value is formset refreshed.
+ //
+ mCurFakeQestId = 0;
+
+ do {
+
+ //
+ // Reset Status to prevent the next break from returning incorrect error status.
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // IFR is updated, force to reparse the IFR binary
+ // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
+ // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
+ //
+ if (mHiiPackageListUpdated) {
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ mHiiPackageListUpdated = FALSE;
+ break;
+ }
+
+ //
+ // Initialize Selection->Form
+ //
+ if (Selection->FormId == 0) {
+ //
+ // Zero FormId indicates display the first Form in a FormSet
+ //
+ Link = GetFirstNode (&Selection->FormSet->FormListHead);
+
+ Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Selection->FormId = Selection->Form->FormId;
+ } else {
+ Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
+ }
+
+ if (Selection->Form == NULL) {
+ //
+ // No Form to display
+ //
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Check Form is suppressed.
+ //
+ if (Selection->Form->SuppressExpression != NULL) {
+ if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
+ //
+ // Form is suppressed.
+ //
+ PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ //
+ // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
+ // for each question with callback flag.
+ // New form may be the first form, or the different form after another form close.
+ //
+ if (((Selection->Handle != mCurrentHiiHandle) ||
+ (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
+ (Selection->FormId != mCurrentFormId))) {
+ //
+ // Update Retrieve flag.
+ //
+ mFinishRetrieveCall = FALSE;
+
+ //
+ // Keep current form information
+ //
+ mCurrentHiiHandle = Selection->Handle;
+ CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
+ mCurrentFormId = Selection->FormId;
+
+ if (ConfigAccess != NULL) {
+ Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
+ //
+ if (mHiiPackageListUpdated) {
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ mHiiPackageListUpdated = FALSE;
+ break;
+ }
+ }
+ }
+
+ //
+ // Load Questions' Value for display
+ //
+ Status = LoadFormSetConfig (Selection, Selection->FormSet);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (!mFinishRetrieveCall) {
+ //
+ // Finish call RETRIEVE callback for this form.
+ //
+ mFinishRetrieveCall = TRUE;
+
+ if (ConfigAccess != NULL) {
+ Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // IFR is updated during callback of open form, force to reparse the IFR binary
+ //
+ if (mHiiPackageListUpdated) {
+ Selection->Action = UI_ACTION_REFRESH_FORMSET;
+ mHiiPackageListUpdated = FALSE;
+ break;
+ }
+ }
+ }
+
+ //
+ // Display form
+ //
+ Status = DisplayForm ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
+ //
+ Statement = Selection->Statement;
+ if (Statement != NULL) {
+ if ((ConfigAccess != NULL) &&
+ ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
+ (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
+ Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
+ if (Statement->Operand == EFI_IFR_REF_OP) {
+ //
+ // Process dynamic update ref opcode.
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = ProcessGotoOpCode(Statement, Selection);
+ }
+
+ //
+ // Callback return error status or status return from process goto opcode.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Cross reference will not be taken, restore all essential field
+ //
+ Selection->Handle = mCurrentHiiHandle;
+ CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = mCurrentFormId;
+ Selection->QuestionId = 0;
+ Selection->Action = UI_ACTION_REFRESH_FORM;
+ }
+ }
+
+
+ if (!EFI_ERROR (Status) &&
+ (Statement->Operand != EFI_IFR_REF_OP) &&
+ ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {
+ //
+ // Only question value has been changed, browser will trig CHANGED callback.
+ //
+ ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
+ //
+ //check whether the question value changed compared with buffer value
+ //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
+ //
+ IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
+ }
+ } else {
+ //
+ // Do the question validation.
+ //
+ Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
+ if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
+ SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
+ //
+ // Verify whether question value has checked, update the ValueChanged flag in Question.
+ //
+ IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
+ }
+ }
+
+ //
+ // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
+ // and process question success till here, trig the gResetFlag/gFlagReconnect.
+ //
+ if ((Status == EFI_SUCCESS) &&
+ (Statement->Storage == NULL)) {
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
+ gResetRequiredFormLevel = TRUE;
+ gResetRequiredSystemLevel = TRUE;
+ }
+
+ if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
+ gFlagReconnect = TRUE;
+ }
+ }
+ }
+
+ //
+ // Check whether Exit flag is TRUE.
+ //
+ if (gExitRequired) {
+ switch (gBrowserSettingScope) {
+ case SystemLevel:
+ Selection->Action = UI_ACTION_EXIT;
+ break;
+
+ case FormSetLevel:
+ case FormLevel:
+ FindNextMenu (Selection, gBrowserSettingScope);
+ break;
+
+ default:
+ break;
+ }
+
+ gExitRequired = FALSE;
+ }
+
+ //
+ // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
+ // for each question with callback flag.
+ //
+ if ((ConfigAccess != NULL) &&
+ ((Selection->Action == UI_ACTION_EXIT) ||
+ (Selection->Handle != mCurrentHiiHandle) ||
+ (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
+ (Selection->FormId != mCurrentFormId))) {
+
+ Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ } while (Selection->Action == UI_ACTION_REFRESH_FORM);
+
+Done:
+ //
+ // Reset current form information to the initial setting when error happens or form exit.
+ //
+ if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
+ mCurrentHiiHandle = NULL;
+ CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
+ mCurrentFormId = 0;
+ }
+
+ //
+ // Unregister notify for Form package update
+ //
+ mHiiDatabase->UnregisterPackageNotify (
+ mHiiDatabase,
+ NotifyHandle
+ );
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
new file mode 100644
index 000000000..f936a4b8e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
@@ -0,0 +1,6675 @@
+/** @file
+Entry and initialization module for the browser.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Setup.h"
+
+SETUP_DRIVER_PRIVATE_DATA mPrivateData = {
+ SETUP_DRIVER_SIGNATURE,
+ NULL,
+ {
+ SendForm,
+ BrowserCallback
+ },
+ {
+ SetScope,
+ RegisterHotKey,
+ RegiserExitHandler,
+ SaveReminder
+ },
+ {
+ BROWSER_EXTENSION2_VERSION_1_1,
+ SetScope,
+ RegisterHotKey,
+ RegiserExitHandler,
+ IsBrowserDataModified,
+ ExecuteAction,
+ {NULL,NULL},
+ {NULL,NULL},
+ IsResetRequired
+ }
+};
+
+EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
+EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
+EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
+EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
+
+UINTN gBrowserContextCount = 0;
+LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
+LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
+LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
+LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
+LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);
+
+BOOLEAN mSystemSubmit = FALSE;
+BOOLEAN gResetRequiredFormLevel;
+BOOLEAN gResetRequiredSystemLevel = FALSE;
+BOOLEAN gExitRequired;
+BOOLEAN gFlagReconnect;
+BOOLEAN gCallbackReconnect;
+BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
+BOOLEAN mBrowserScopeFirstSet = TRUE;
+EXIT_HANDLER ExitHandlerFunction = NULL;
+FORM_BROWSER_FORMSET *mSystemLevelFormSet;
+
+//
+// Browser Global Strings
+//
+CHAR16 *gEmptyString;
+CHAR16 *mUnknownString = L"!";
+
+extern EFI_GUID mCurrentFormSetGuid;
+extern EFI_HII_HANDLE mCurrentHiiHandle;
+extern UINT16 mCurrentFormId;
+extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
+extern BOOLEAN mDynamicFormUpdated;
+
+/**
+ Create a menu with specified formset GUID and form ID, and add it as a child
+ of the given parent menu.
+
+ @param HiiHandle Hii handle related to this formset.
+ @param FormSetGuid The Formset Guid of menu to be added.
+ @param FormId The Form ID of menu to be added.
+ @param QuestionId The question id of this menu to be added.
+
+ @return A pointer to the newly added menu or NULL if memory is insufficient.
+
+**/
+FORM_ENTRY_INFO *
+UiAddMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId,
+ IN UINT16 QuestionId
+ )
+{
+ FORM_ENTRY_INFO *MenuList;
+
+ MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
+ if (MenuList == NULL) {
+ return NULL;
+ }
+
+ MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;
+
+ MenuList->HiiHandle = HiiHandle;
+ CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
+ MenuList->FormId = FormId;
+ MenuList->QuestionId = QuestionId;
+
+ //
+ // If parent is not specified, it is the root Form of a Formset
+ //
+ InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
+
+ return MenuList;
+}
+
+/**
+ Return the form id for the input hiihandle and formset.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+
+ @return First form's id for this form set.
+
+**/
+EFI_FORM_ID
+GetFirstFormId (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+
+ Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ return Form->FormId;
+}
+
+/**
+ Search Menu with given FormSetGuid and FormId in all cached menu list.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+ @param FormId The Form ID of menu to search.
+
+ @return A pointer to menu found or NULL if not found.
+
+**/
+FORM_ENTRY_INFO *
+UiFindMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_ENTRY_INFO *MenuList;
+ FORM_ENTRY_INFO *RetMenu;
+ EFI_FORM_ID FirstFormId;
+
+ RetMenu = NULL;
+
+ Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
+ while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
+ Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);
+
+ //
+ // If already find the menu, free the menus behind it.
+ //
+ if (RetMenu != NULL) {
+ RemoveEntryList (&MenuList->Link);
+ FreePool (MenuList);
+ continue;
+ }
+
+ //
+ // Find the same FromSet.
+ //
+ if (MenuList->HiiHandle == HiiHandle) {
+ if (IsZeroGuid (&MenuList->FormSetGuid)) {
+ //
+ // FormSetGuid is not specified.
+ //
+ RetMenu = MenuList;
+ } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {
+ if (MenuList->FormId == FormId) {
+ RetMenu = MenuList;
+ } else if (FormId == 0 || MenuList->FormId == 0 ) {
+ FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);
+ if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {
+ RetMenu = MenuList;
+ }
+ }
+ }
+ }
+ }
+
+ return RetMenu;
+}
+
+/**
+ Find parent menu for current menu.
+
+ @param CurrentMenu Current Menu
+ @param SettingLevel Whether find parent menu in Form Level or Formset level.
+ In form level, just find the parent menu;
+ In formset level, find the parent menu which has different
+ formset guid value.
+
+ @retval The parent menu for current menu.
+**/
+FORM_ENTRY_INFO *
+UiFindParentMenu (
+ IN FORM_ENTRY_INFO *CurrentMenu,
+ IN BROWSER_SETTING_SCOPE SettingLevel
+ )
+{
+ FORM_ENTRY_INFO *ParentMenu;
+ LIST_ENTRY *Link;
+
+ ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel);
+
+ if (CurrentMenu == NULL) {
+ return NULL;
+ }
+
+ ParentMenu = NULL;
+ Link = &CurrentMenu->Link;
+
+ while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
+ ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink);
+
+ if (SettingLevel == FormLevel) {
+ //
+ // For FormLevel, just find the parent menu, return.
+ //
+ break;
+ }
+
+ if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
+ //
+ // For SystemLevel, must find the menu which has different formset.
+ //
+ break;
+ }
+
+ Link = Link->BackLink;
+ }
+
+ //
+ // Not find the parent menu, just return NULL.
+ //
+ if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
+ return NULL;
+ }
+
+ return ParentMenu;
+}
+
+/**
+ Free Menu list linked list.
+
+ @param MenuListHead One Menu list point in the menu list.
+
+**/
+VOID
+UiFreeMenuList (
+ LIST_ENTRY *MenuListHead
+ )
+{
+ FORM_ENTRY_INFO *MenuList;
+
+ while (!IsListEmpty (MenuListHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ FreePool (MenuList);
+ }
+}
+
+/**
+ Copy current Menu list to the new menu list.
+
+ @param NewMenuListHead New create Menu list.
+ @param CurrentMenuListHead Current Menu list.
+
+**/
+VOID
+UiCopyMenuList (
+ OUT LIST_ENTRY *NewMenuListHead,
+ IN LIST_ENTRY *CurrentMenuListHead
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_ENTRY_INFO *MenuList;
+ FORM_ENTRY_INFO *NewMenuEntry;
+
+ //
+ // If new menu list not empty, free it first.
+ //
+ UiFreeMenuList (NewMenuListHead);
+
+ Link = GetFirstNode (CurrentMenuListHead);
+ while (!IsNull (CurrentMenuListHead, Link)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
+ Link = GetNextNode (CurrentMenuListHead, Link);
+
+ NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
+ ASSERT (NewMenuEntry != NULL);
+ NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE;
+ NewMenuEntry->HiiHandle = MenuList->HiiHandle;
+ CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID));
+ NewMenuEntry->FormId = MenuList->FormId;
+ NewMenuEntry->QuestionId = MenuList->QuestionId;
+
+ InsertTailList (NewMenuListHead, &NewMenuEntry->Link);
+ }
+}
+
+/**
+ Load all hii formset to the browser.
+
+**/
+VOID
+LoadAllHiiFormset (
+ VOID
+ )
+{
+ FORM_BROWSER_FORMSET *LocalFormSet;
+ EFI_HII_HANDLE *HiiHandles;
+ UINTN Index;
+ EFI_GUID ZeroGuid;
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *OldFormset;
+
+ OldFormset = mSystemLevelFormSet;
+
+ //
+ // Get all the Hii handles
+ //
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ //
+ // Search for formset of each class type
+ //
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ //
+ // Check HiiHandles[Index] does exist in global maintain list.
+ //
+ if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
+ continue;
+ }
+
+ //
+ // Initilize FormSet Setting
+ //
+ LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
+ ASSERT (LocalFormSet != NULL);
+ mSystemLevelFormSet = LocalFormSet;
+
+ ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
+ Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
+ if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
+ DestroyFormSet (LocalFormSet);
+ continue;
+ }
+ InitializeCurrentSetting (LocalFormSet);
+
+ //
+ // Initilize Questions' Value
+ //
+ Status = LoadFormSetConfig (NULL, LocalFormSet);
+ if (EFI_ERROR (Status)) {
+ DestroyFormSet (LocalFormSet);
+ continue;
+ }
+ }
+
+ //
+ // Free resources, and restore gOldFormSet and gClassOfVfr
+ //
+ FreePool (HiiHandles);
+
+ mSystemLevelFormSet = OldFormset;
+}
+
+/**
+ Pop up the error info.
+
+ @param BrowserStatus The input browser status.
+ @param HiiHandle The Hiihandle for this opcode.
+ @param OpCode The opcode use to get the erro info and timeout value.
+ @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF.
+
+**/
+UINT32
+PopupErrorMessage (
+ IN UINT32 BrowserStatus,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL
+ IN CHAR16 *ErrorString
+ )
+{
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ USER_INPUT UserInputData;
+
+ Statement = NULL;
+
+ if (OpCode != NULL) {
+ Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT));
+ ASSERT (Statement != NULL);
+ Statement->OpCode = OpCode;
+ gDisplayFormData.HighLightedStatement = Statement;
+ }
+
+ //
+ // Used to compatible with old display engine.
+ // New display engine not use this field.
+ //
+ gDisplayFormData.ErrorString = ErrorString;
+ gDisplayFormData.BrowserStatus = BrowserStatus;
+
+ if (HiiHandle != NULL) {
+ gDisplayFormData.HiiHandle = HiiHandle;
+ }
+
+ mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData);
+
+ gDisplayFormData.BrowserStatus = BROWSER_SUCCESS;
+ gDisplayFormData.ErrorString = NULL;
+
+ if (OpCode != NULL) {
+ FreePool (Statement);
+ }
+
+ return UserInputData.Action;
+}
+
+/**
+ This is the routine which an external caller uses to direct the browser
+ where to obtain it's information.
+
+
+ @param This The Form Browser protocol instanse.
+ @param Handles A pointer to an array of Handles. If HandleCount > 1 we
+ display a list of the formsets for the handles specified.
+ @param HandleCount The number of Handles specified in Handle.
+ @param FormSetGuid This field points to the EFI_GUID which must match the Guid
+ field in the EFI_IFR_FORM_SET op-code for the specified
+ forms-based package. If FormSetGuid is NULL, then this
+ function will display the first found forms package.
+ @param FormId This field specifies which EFI_IFR_FORM to render as the first
+ displayable page. If this field has a value of 0x0000, then
+ the forms browser will render the specified forms in their encoded order.
+ @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
+ characters.
+ @param ActionRequest Points to the action recommended by the form.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_NOT_FOUND No valid forms could be found to display.
+
+**/
+EFI_STATUS
+EFIAPI
+SendForm (
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
+ IN EFI_HII_HANDLE *Handles,
+ IN UINTN HandleCount,
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN UINT16 FormId, OPTIONAL
+ IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UI_MENU_SELECTION *Selection;
+ UINTN Index;
+ FORM_BROWSER_FORMSET *FormSet;
+ FORM_ENTRY_INFO *MenuList;
+ BOOLEAN RetVal;
+
+ //
+ // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.
+ //
+ if (mFormDisplay == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Save globals used by SendForm()
+ //
+ SaveBrowserContext ();
+
+ gFlagReconnect = FALSE;
+ gResetRequiredFormLevel = FALSE;
+ gExitRequired = FALSE;
+ gCallbackReconnect = FALSE;
+ Status = EFI_SUCCESS;
+ gEmptyString = L"";
+ gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
+ ASSERT (Selection != NULL);
+
+ Selection->Handle = Handles[Index];
+ if (FormSetGuid != NULL) {
+ CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
+ Selection->FormId = FormId;
+ } else {
+ CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
+ }
+
+ do {
+ FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
+ ASSERT (FormSet != NULL);
+
+ //
+ // Validate the HiiHandle
+ // if validate failed, find the first validate parent HiiHandle.
+ //
+ if (!ValidateHiiHandle(Selection->Handle)) {
+ FindNextMenu (Selection, FormSetLevel);
+ }
+
+ //
+ // Initialize internal data structures of FormSet
+ //
+ Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
+ if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
+ DestroyFormSet (FormSet);
+ break;
+ }
+ Selection->FormSet = FormSet;
+ mSystemLevelFormSet = FormSet;
+ mDynamicFormUpdated = FALSE;
+
+ //
+ // Display this formset
+ //
+ gCurrentSelection = Selection;
+
+ Status = SetupBrowser (Selection);
+
+ gCurrentSelection = NULL;
+ mSystemLevelFormSet = NULL;
+
+ //
+ // If callback update form dynamically, it's not exiting of the formset for user so system do not reconnect driver hanlde
+ // this time.
+ //
+ if (!mDynamicFormUpdated && (gFlagReconnect || gCallbackReconnect)) {
+ RetVal = ReconnectController (FormSet->DriverHandle);
+ if (!RetVal) {
+ PopupErrorMessage(BROWSER_RECONNECT_FAIL, NULL, NULL, NULL);
+ }
+ gFlagReconnect = FALSE;
+ gCallbackReconnect = FALSE;
+ }
+
+ //
+ // If no data is changed, don't need to save current FormSet into the maintain list.
+ //
+ if (!IsNvUpdateRequiredForFormSet (FormSet)) {
+ CleanBrowserStorage(FormSet);
+ RemoveEntryList (&FormSet->Link);
+ DestroyFormSet (FormSet);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
+
+ FreePool (Selection);
+ }
+
+ if (ActionRequest != NULL) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ if (gResetRequiredFormLevel) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
+ }
+ }
+
+ mFormDisplay->ExitDisplay();
+
+ //
+ // Clear the menu history data.
+ //
+ while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+ FreePool (MenuList);
+ }
+
+ //
+ // Restore globals used by SendForm()
+ //
+ RestoreBrowserContext ();
+
+ return Status;
+}
+
+/**
+ Get or set data to the storage.
+
+ @param ResultsDataSize The size of the buffer associatedwith ResultsData.
+ @param ResultsData A string returned from an IFR browser or
+ equivalent. The results string will have no
+ routing information in them.
+ @param RetrieveData A BOOLEAN field which allows an agent to retrieve
+ (if RetrieveData = TRUE) data from the uncommitted
+ browser state information or set (if RetrieveData
+ = FALSE) data in the uncommitted browser state
+ information.
+ @param Storage The pointer to the storage.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+
+**/
+EFI_STATUS
+ProcessStorage (
+ IN OUT UINTN *ResultsDataSize,
+ IN OUT EFI_STRING *ResultsData,
+ IN BOOLEAN RetrieveData,
+ IN BROWSER_STORAGE *Storage
+ )
+{
+ CHAR16 *ConfigResp;
+ EFI_STATUS Status;
+ CHAR16 *StrPtr;
+ UINTN BufferSize;
+ UINTN TmpSize;
+ UINTN MaxLen;
+ FORMSET_STORAGE *BrowserStorage;
+
+ if (RetrieveData) {
+ //
+ // Generate <ConfigResp>
+ //
+ Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.
+ // Also need to consider add "\0" at first time.
+ //
+ StrPtr = StrStr (ConfigResp, L"PATH");
+ ASSERT (StrPtr != NULL);
+ StrPtr = StrStr (StrPtr, L"&");
+ StrPtr += 1;
+ BufferSize = StrSize (StrPtr);
+
+ //
+ // Copy the data if the input buffer is bigger enough.
+ //
+ if (*ResultsDataSize >= BufferSize) {
+ StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr);
+ }
+
+ *ResultsDataSize = BufferSize;
+ FreePool (ConfigResp);
+ } else {
+ //
+ // Prepare <ConfigResp>
+ //
+ BrowserStorage = GetFstStgFromBrsStg (Storage);
+ ASSERT (BrowserStorage != NULL);
+ TmpSize = StrLen (*ResultsData);
+ BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
+ MaxLen = BufferSize / sizeof (CHAR16);
+ ConfigResp = AllocateZeroPool (BufferSize);
+ ASSERT (ConfigResp != NULL);
+
+ StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr);
+ StrCatS (ConfigResp, MaxLen, L"&");
+ StrCatS (ConfigResp, MaxLen, *ResultsData);
+
+ //
+ // Update Browser uncommited data
+ //
+ Status = ConfigRespToStorage (Storage, ConfigResp);
+ FreePool (ConfigResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine called this service in the browser to retrieve or set certain uncommitted
+ state information that resides in the open formsets.
+
+ @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
+ instance.
+ @param ResultsDataSize A pointer to the size of the buffer associated
+ with ResultsData.
+ @param ResultsData A string returned from an IFR browser or
+ equivalent. The results string will have no
+ routing information in them.
+ @param RetrieveData A BOOLEAN field which allows an agent to retrieve
+ (if RetrieveData = TRUE) data from the uncommitted
+ browser state information or set (if RetrieveData
+ = FALSE) data in the uncommitted browser state
+ information.
+ @param VariableGuid An optional field to indicate the target variable
+ GUID name to use.
+ @param VariableName An optional field to indicate the target
+ human-readable variable name.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+ @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
+ contain the results data.
+
+**/
+EFI_STATUS
+EFIAPI
+BrowserCallback (
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
+ IN OUT UINTN *ResultsDataSize,
+ IN OUT EFI_STRING ResultsData,
+ IN BOOLEAN RetrieveData,
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormsetStorage;
+ UINTN TotalSize;
+ BOOLEAN Found;
+
+ if (ResultsDataSize == NULL || ResultsData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TotalSize = *ResultsDataSize;
+ Storage = NULL;
+ Found = FALSE;
+ Status = EFI_SUCCESS;
+
+ if (VariableGuid != NULL) {
+ //
+ // Try to find target storage in the current formset.
+ //
+ Link = GetFirstNode (&gBrowserStorageList);
+ while (!IsNull (&gBrowserStorageList, Link)) {
+ Storage = BROWSER_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserStorageList, Link);
+ //
+ // Check the current storage.
+ //
+ if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
+ continue;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ //
+ // Buffer storage require both GUID and Name
+ //
+ if (VariableName == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
+ continue;
+ }
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||
+ Storage->Type == EFI_HII_VARSTORE_BUFFER) {
+ if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {
+ continue;
+ }
+ }
+
+ Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ ConfigRequestAdjust (Storage, ResultsData, TRUE);
+ }
+
+ //
+ // Different formsets may have same varstore, so here just set the flag
+ // not exit the circle.
+ //
+ Found = TRUE;
+ break;
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ //
+ // GUID/Name is not specified, take the first storage in FormSet
+ //
+ if (mSystemLevelFormSet == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Generate <ConfigResp>
+ //
+ Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);
+ if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (RetrieveData) {
+ Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+ *ResultsDataSize = TotalSize;
+ }
+
+ return Status;
+
+}
+
+
+/**
+ Callback function for SimpleTextInEx protocol install events
+
+ @param Event the event that is signaled.
+ @param Context not used here.
+
+**/
+VOID
+EFIAPI
+FormDisplayCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mFormDisplay != NULL) {
+ return;
+ }
+
+ gBS->LocateProtocol (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ NULL,
+ (VOID **) &mFormDisplay
+ );
+}
+
+/**
+ Initialize Setup Browser driver.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
+ @return Other value if failed to initialize the Setup Browser module.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSetup (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ //
+ // Locate required Hii relative protocols
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &mHiiDatabase
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **) &mHiiConfigRouting
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathFromTextProtocolGuid,
+ NULL,
+ (VOID **) &mPathFromText
+ );
+
+ //
+ // Install FormBrowser2 protocol
+ //
+ mPrivateData.Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEfiFormBrowser2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FormBrowser2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install FormBrowserEx2 protocol
+ //
+ InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
+ InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
+ mPrivateData.Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEdkiiFormBrowserEx2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FormBrowserEx2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEdkiiFormBrowserExProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.FormBrowserEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeDisplayFormData ();
+
+ Status = gBS->LocateProtocol (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ NULL,
+ (VOID **) &mFormDisplay
+ );
+
+ if (EFI_ERROR (Status)) {
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ TPL_CALLBACK,
+ FormDisplayCallback,
+ NULL,
+ &Registration
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Create a new string in HII Package List.
+
+ @param String The String to be added
+ @param HiiHandle The package list in the HII database to insert the
+ specified string.
+
+ @return The output string.
+
+**/
+EFI_STRING_ID
+NewString (
+ IN CHAR16 *String,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING_ID StringId;
+
+ StringId = HiiSetString (HiiHandle, 0, String, NULL);
+ ASSERT (StringId != 0);
+
+ return StringId;
+}
+
+
+/**
+ Delete a string from HII Package List.
+
+ @param StringId Id of the string in HII database.
+ @param HiiHandle The HII package list handle.
+
+ @retval EFI_SUCCESS The string was deleted successfully.
+
+**/
+EFI_STATUS
+DeleteString (
+ IN EFI_STRING_ID StringId,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ CHAR16 NullChar;
+
+ NullChar = CHAR_NULL;
+ HiiSetString (HiiHandle, StringId, &NullChar, NULL);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING String;
+
+ if (HiiHandle == NULL) {
+ return NULL;
+ }
+
+ String = HiiGetString (HiiHandle, Token, NULL);
+ if (String == NULL) {
+ String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
+ ASSERT (String != NULL);
+ }
+ return (CHAR16 *) String;
+}
+
+
+/**
+ Allocate new memory and then copy the Unicode string Source to Destination.
+
+ @param Dest Location to copy string
+ @param Src String to copy
+
+**/
+VOID
+NewStringCpy (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ )
+{
+ if (*Dest != NULL) {
+ FreePool (*Dest);
+ }
+ *Dest = AllocateCopyPool (StrSize (Src), Src);
+ ASSERT (*Dest != NULL);
+}
+
+
+/**
+ Allocate new memory and concatinate Source on the end of Destination.
+
+ @param Dest String to added to the end of.
+ @param Src String to concatinate.
+
+**/
+VOID
+NewStringCat (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *NewString;
+ UINTN MaxLen;
+
+ if (*Dest == NULL) {
+ NewStringCpy (Dest, Src);
+ return;
+ }
+
+ MaxLen = ( StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16);
+ NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (NewString != NULL);
+
+ StrCpyS (NewString, MaxLen, *Dest);
+ StrCatS (NewString, MaxLen, Src);
+
+ FreePool (*Dest);
+ *Dest = NewString;
+}
+
+/**
+ Get Value for given Name from a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The retured Value.
+ @param GetValueFrom Where to get source value, from EditValue or Value.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+GetValueByName (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN OUT CHAR16 **Value,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+
+ if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Value = NULL;
+
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (StrCmp (Name, Node->Name) == 0) {
+ if (GetValueFrom == GetSetValueWithEditBuffer) {
+ NewStringCpy (Value, Node->EditValue);
+ } else {
+ NewStringCpy (Value, Node->Value);
+ }
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Set Value of given Name in a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The Value to set.
+ @param SetValueTo Whether update editValue or Value.
+ @param ReturnNode The node use the input name.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+SetValueByName (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN CHAR16 *Value,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
+ OUT NAME_VALUE_NODE **ReturnNode
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+ CHAR16 *Buffer;
+
+ if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (StrCmp (Name, Node->Name) == 0) {
+ if (SetValueTo == GetSetValueWithEditBuffer) {
+ Buffer = Node->EditValue;
+ } else {
+ Buffer = Node->Value;
+ }
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+ Buffer = AllocateCopyPool (StrSize (Value), Value);
+ ASSERT (Buffer != NULL);
+ if (SetValueTo == GetSetValueWithEditBuffer) {
+ Node->EditValue = Buffer;
+ } else {
+ Node->Value = Buffer;
+ }
+
+ if (ReturnNode != NULL) {
+ *ReturnNode = Node;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
+
+ @param Storage The Storage to be conveted.
+ @param ConfigResp The returned <ConfigResp>.
+ @param ConfigRequest The ConfigRequest string.
+ @param GetEditBuf Get the data from editbuffer or buffer.
+
+ @retval EFI_SUCCESS Convert success.
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.
+
+**/
+EFI_STATUS
+StorageToConfigResp (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 **ConfigResp,
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN GetEditBuf
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Progress;
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+ UINT8 *SourceBuf;
+ FORMSET_STORAGE *FormsetStorage;
+
+ Status = EFI_SUCCESS;
+
+ switch (Storage->Type) {
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
+ Status = mHiiConfigRouting->BlockToConfig (
+ mHiiConfigRouting,
+ ConfigRequest,
+ SourceBuf,
+ Storage->Size,
+ ConfigResp,
+ &Progress
+ );
+ break;
+
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ *ConfigResp = NULL;
+ FormsetStorage = GetFstStgFromBrsStg(Storage);
+ ASSERT (FormsetStorage != NULL);
+ NewStringCat (ConfigResp, FormsetStorage->ConfigHdr);
+
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (StrStr (ConfigRequest, Node->Name) != NULL) {
+ NewStringCat (ConfigResp, L"&");
+ NewStringCat (ConfigResp, Node->Name);
+ NewStringCat (ConfigResp, L"=");
+ if (GetEditBuf) {
+ NewStringCat (ConfigResp, Node->EditValue);
+ } else {
+ NewStringCat (ConfigResp, Node->Value);
+ }
+ }
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+ break;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
+
+ @param Storage The Storage to receive the settings.
+ @param ConfigResp The <ConfigResp> to be converted.
+
+ @retval EFI_SUCCESS Convert success.
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.
+
+**/
+EFI_STATUS
+ConfigRespToStorage (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *ConfigResp
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Progress;
+ UINTN BufferSize;
+ CHAR16 *StrPtr;
+ CHAR16 *Name;
+ CHAR16 *Value;
+
+ Status = EFI_SUCCESS;
+
+ switch (Storage->Type) {
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ BufferSize = Storage->Size;
+ Status = mHiiConfigRouting->ConfigToBlock (
+ mHiiConfigRouting,
+ ConfigResp,
+ Storage->EditBuffer,
+ &BufferSize,
+ &Progress
+ );
+ break;
+
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ StrPtr = StrStr (ConfigResp, L"PATH");
+ if (StrPtr == NULL) {
+ break;
+ }
+ StrPtr = StrStr (ConfigResp, L"&");
+ while (StrPtr != NULL) {
+ //
+ // Skip '&'
+ //
+ StrPtr = StrPtr + 1;
+ Name = StrPtr;
+ StrPtr = StrStr (StrPtr, L"=");
+ if (StrPtr == NULL) {
+ break;
+ }
+ *StrPtr = 0;
+
+ //
+ // Skip '='
+ //
+ StrPtr = StrPtr + 1;
+ Value = StrPtr;
+ StrPtr = StrStr (StrPtr, L"&");
+ if (StrPtr != NULL) {
+ *StrPtr = 0;
+ }
+ SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
+ }
+ break;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Get bit field value from the buffer and then set the value for the question.
+ Note: Data type UINT32 can cover all the bit field value.
+
+ @param Question The question refer to bit field.
+ @param Buffer Point to the buffer which the question value get from.
+
+**/
+VOID
+GetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer
+ )
+{
+ UINTN StartBit;
+ UINTN EndBit;
+ UINT32 RetVal;
+ UINT32 BufferValue;
+
+ StartBit = Question->BitVarOffset % 8;
+ EndBit = StartBit + Question->BitStorageWidth - 1;
+
+ CopyMem ((UINT8 *) &BufferValue, Buffer, Question->StorageWidth);
+
+ RetVal = BitFieldRead32 (BufferValue, StartBit, EndBit);
+
+ //
+ // Set question value.
+ // Note: Since Question with BufferValue (orderedlist, password, string)are not supported to refer bit field.
+ // Only oneof/checkbox/oneof can support bit field.So we can copy the value to the Hiivalue of Question directly.
+ //
+ CopyMem ((UINT8 *) &Question->HiiValue.Value, (UINT8 *) &RetVal, Question->StorageWidth);
+}
+
+/**
+ Set bit field value to the buffer.
+ Note: Data type UINT32 can cover all the bit field value.
+
+ @param Question The question refer to bit field.
+ @param Buffer Point to the buffer which the question value set to.
+ @param Value The bit field value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN OUT UINT8 *Buffer,
+ IN UINT32 Value
+ )
+{
+ UINT32 Operand;
+ UINTN StartBit;
+ UINTN EndBit;
+ UINT32 RetVal;
+
+ StartBit = Question->BitVarOffset % 8;
+ EndBit = StartBit + Question->BitStorageWidth - 1;
+
+ CopyMem ((UINT8*) &Operand, Buffer, Question->StorageWidth);
+
+ RetVal = BitFieldWrite32 (Operand, StartBit, EndBit, Value);
+
+ CopyMem (Buffer, (UINT8*) &RetVal, Question->StorageWidth);
+}
+
+/**
+ Convert the buffer value to HiiValue.
+
+ @param Question The question.
+ @param Value Unicode buffer save the question value.
+
+ @retval Status whether convert the value success.
+
+**/
+EFI_STATUS
+BufferToValue (
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16 *Value
+ )
+{
+ CHAR16 *StringPtr;
+ BOOLEAN IsBufferStorage;
+ CHAR16 *DstBuf;
+ CHAR16 TempChar;
+ UINTN LengthStr;
+ UINT8 *Dst;
+ CHAR16 TemStr[5];
+ UINTN Index;
+ UINT8 DigitUint8;
+ BOOLEAN IsString;
+ UINTN Length;
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+
+ Buffer = NULL;
+
+ IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
+ if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ IsBufferStorage = TRUE;
+ } else {
+ IsBufferStorage = FALSE;
+ }
+
+ //
+ // Question Value is provided by Buffer Storage or NameValue Storage
+ //
+ if (Question->BufferValue != NULL) {
+ //
+ // This Question is password or orderedlist
+ //
+ Dst = Question->BufferValue;
+ } else {
+ //
+ // Other type of Questions
+ //
+ if (Question->QuestionReferToBitField) {
+ Buffer = (UINT8 *)AllocateZeroPool (Question->StorageWidth);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Dst = Buffer;
+ } else {
+ Dst = (UINT8 *) &Question->HiiValue.Value;
+ }
+ }
+
+ //
+ // Temp cut at the end of this section, end with '\0' or '&'.
+ //
+ StringPtr = Value;
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ TempChar = *StringPtr;
+ *StringPtr = L'\0';
+
+ LengthStr = StrLen (Value);
+
+ //
+ // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type.
+ // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters).
+ // So the maximum value string length of a question is : Question->StorageWidth * 2.
+ // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert.
+ //
+ if (LengthStr > (UINTN) Question->StorageWidth * 2) {
+ Length = (UINTN) Question->StorageWidth * 2;
+ } else {
+ Length = LengthStr;
+ }
+
+ Status = EFI_SUCCESS;
+ if (!IsBufferStorage && IsString) {
+ //
+ // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
+ // Add string tail char L'\0' into Length
+ //
+ DstBuf = (CHAR16 *) Dst;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index += 4) {
+ StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4);
+ DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
+ }
+ //
+ // Add tailing L'\0' character
+ //
+ DstBuf[Index/4] = L'\0';
+ } else {
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = Value[LengthStr - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ Dst [Index/2] = DigitUint8;
+ } else {
+ Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
+ }
+ }
+ }
+
+ *StringPtr = TempChar;
+
+ if (Buffer != NULL && Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, Buffer);
+ FreePool (Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Get Question's current Value.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+GetQuestionValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Enabled;
+ BOOLEAN Pending;
+ UINT8 *Dst;
+ UINTN StorageWidth;
+ EFI_TIME EfiTime;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormsetStorage;
+ EFI_IFR_TYPE_VALUE *QuestionValue;
+ CHAR16 *ConfigRequest;
+ CHAR16 *Progress;
+ CHAR16 *Result;
+ CHAR16 *Value;
+ UINTN Length;
+ BOOLEAN IsBufferStorage;
+ UINTN MaxLen;
+
+ Status = EFI_SUCCESS;
+ Value = NULL;
+ Result = NULL;
+
+ if (GetValueFrom >= GetSetValueWithMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Question value is provided by an Expression, evaluate it
+ //
+ if (Question->ValueExpression != NULL) {
+ Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
+ if (!EFI_ERROR (Status)) {
+ if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+ ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
+ if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
+ CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
+ Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
+ } else {
+ CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
+ Question->HiiValue.BufferLen = Question->StorageWidth;
+ }
+ FreePool (Question->ValueExpression->Result.Buffer);
+ }
+ Question->HiiValue.Type = Question->ValueExpression->Result.Type;
+ CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+ }
+ return Status;
+ }
+
+ //
+ // Get question value by read expression.
+ //
+ if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
+ Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
+ if (!EFI_ERROR (Status) &&
+ ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
+ //
+ // Only update question value to the valid result.
+ //
+ if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+ ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
+ if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
+ CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
+ Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
+ } else {
+ CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
+ Question->HiiValue.BufferLen = Question->StorageWidth;
+ }
+ FreePool (Question->ReadExpression->Result.Buffer);
+ }
+ Question->HiiValue.Type = Question->ReadExpression->Result.Type;
+ CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Question value is provided by RTC
+ //
+ Storage = Question->Storage;
+ QuestionValue = &Question->HiiValue.Value;
+ if (Storage == NULL) {
+ //
+ // It's a Question without storage, or RTC date/time
+ //
+ if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
+ //
+ // Date and time define the same Flags bit
+ //
+ switch (Question->Flags & EFI_QF_DATE_STORAGE) {
+ case QF_DATE_STORAGE_TIME:
+ Status = gRT->GetTime (&EfiTime, NULL);
+ break;
+
+ case QF_DATE_STORAGE_WAKEUP:
+ Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
+ break;
+
+ case QF_DATE_STORAGE_NORMAL:
+ default:
+ //
+ // For date/time without storage
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (Question->Operand == EFI_IFR_DATE_OP){
+ QuestionValue->date.Year = 0xff;
+ QuestionValue->date.Month = 0xff;
+ QuestionValue->date.Day = 0xff;
+ } else {
+ QuestionValue->time.Hour = 0xff;
+ QuestionValue->time.Minute = 0xff;
+ QuestionValue->time.Second = 0xff;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (Question->Operand == EFI_IFR_DATE_OP) {
+ QuestionValue->date.Year = EfiTime.Year;
+ QuestionValue->date.Month = EfiTime.Month;
+ QuestionValue->date.Day = EfiTime.Day;
+ } else {
+ QuestionValue->time.Hour = EfiTime.Hour;
+ QuestionValue->time.Minute = EfiTime.Minute;
+ QuestionValue->time.Second = EfiTime.Second;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Question value is provided by EFI variable
+ //
+ StorageWidth = Question->StorageWidth;
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ if (Question->BufferValue != NULL) {
+ Dst = Question->BufferValue;
+ } else {
+ Dst = (UINT8 *) QuestionValue;
+ }
+
+ Status = gRT->GetVariable (
+ Question->VariableName,
+ &Storage->Guid,
+ NULL,
+ &StorageWidth,
+ Dst
+ );
+ //
+ // Always return success, even this EFI variable doesn't exist
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Question Value is provided by Buffer Storage or NameValue Storage
+ //
+ if (Question->BufferValue != NULL) {
+ //
+ // This Question is password or orderedlist
+ //
+ Dst = Question->BufferValue;
+ } else {
+ //
+ // Other type of Questions
+ //
+ Dst = (UINT8 *) &Question->HiiValue.Value;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ IsBufferStorage = TRUE;
+ } else {
+ IsBufferStorage = FALSE;
+ }
+ if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
+ if (IsBufferStorage) {
+ if (GetValueFrom == GetSetValueWithEditBuffer) {
+ //
+ // Copy from storage Edit buffer
+ // If the Question refer to bit filed, get the value in the related bit filed.
+ //
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset);
+ } else {
+ CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
+ }
+ } else {
+ //
+ // Copy from storage Edit buffer
+ // If the Question refer to bit filed, get the value in the related bit filed.
+ //
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset);
+ } else {
+ CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
+ }
+ }
+ } else {
+ Value = NULL;
+ Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (Value != NULL);
+ Status = BufferToValue (Question, Value);
+ FreePool (Value);
+ }
+ } else {
+ FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
+ ASSERT (FormsetStorage != NULL);
+ //
+ // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
+ // <ConfigHdr> + "&" + <VariableName>
+ //
+ if (IsBufferStorage) {
+ Length = StrLen (FormsetStorage->ConfigHdr);
+ Length += StrLen (Question->BlockName);
+ } else {
+ Length = StrLen (FormsetStorage->ConfigHdr);
+ Length += StrLen (Question->VariableName) + 1;
+ }
+ // Allocate buffer include '\0'
+ MaxLen = Length + 1;
+ ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (ConfigRequest != NULL);
+
+ StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr);
+ if (IsBufferStorage) {
+ StrCatS (ConfigRequest, MaxLen, Question->BlockName);
+ } else {
+ StrCatS (ConfigRequest, MaxLen, L"&");
+ StrCatS (ConfigRequest, MaxLen, Question->VariableName);
+ }
+
+ //
+ // Request current settings from Configuration Driver
+ //
+ Status = mHiiConfigRouting->ExtractConfig (
+ mHiiConfigRouting,
+ ConfigRequest,
+ &Progress,
+ &Result
+ );
+ FreePool (ConfigRequest);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Skip <ConfigRequest>
+ //
+ if (IsBufferStorage) {
+ Value = StrStr (Result, L"&VALUE");
+ if (Value == NULL) {
+ FreePool (Result);
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Skip "&VALUE"
+ //
+ Value = Value + 6;
+ } else {
+ Value = Result + Length;
+ }
+ if (*Value != '=') {
+ FreePool (Result);
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Skip '=', point to value
+ //
+ Value = Value + 1;
+
+ Status = BufferToValue (Question, Value);
+ if (EFI_ERROR (Status)) {
+ FreePool (Result);
+ return Status;
+ }
+
+ //
+ // Synchronize Edit Buffer
+ //
+ if (IsBufferStorage) {
+ CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
+ } else {
+ SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
+ }
+
+ if (Result != NULL) {
+ FreePool (Result);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Save Question Value to edit copy(cached) or Storage(uncached).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Pointer to the Question.
+ @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+SetQuestionValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Enabled;
+ BOOLEAN Pending;
+ UINT8 *Src;
+ EFI_TIME EfiTime;
+ UINTN BufferLen;
+ UINTN StorageWidth;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormsetStorage;
+ EFI_IFR_TYPE_VALUE *QuestionValue;
+ CHAR16 *ConfigResp;
+ CHAR16 *Progress;
+ CHAR16 *Value;
+ UINTN Length;
+ BOOLEAN IsBufferStorage;
+ BOOLEAN IsString;
+ UINT8 *TemBuffer;
+ CHAR16 *TemName;
+ CHAR16 *TemString;
+ UINTN Index;
+ NAME_VALUE_NODE *Node;
+ UINTN MaxLen;
+
+ Status = EFI_SUCCESS;
+ Node = NULL;
+
+ if (SetValueTo >= GetSetValueWithMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Question value is provided by an Expression, then it is read only
+ //
+ if (Question->ValueExpression != NULL) {
+ return Status;
+ }
+
+ //
+ // Before set question value, evaluate its write expression.
+ //
+ if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
+ Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Question value is provided by RTC
+ //
+ Storage = Question->Storage;
+ QuestionValue = &Question->HiiValue.Value;
+ if (Storage == NULL) {
+ //
+ // It's a Question without storage, or RTC date/time
+ //
+ if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
+ //
+ // Date and time define the same Flags bit
+ //
+ switch (Question->Flags & EFI_QF_DATE_STORAGE) {
+ case QF_DATE_STORAGE_TIME:
+ Status = gRT->GetTime (&EfiTime, NULL);
+ break;
+
+ case QF_DATE_STORAGE_WAKEUP:
+ Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
+ break;
+
+ case QF_DATE_STORAGE_NORMAL:
+ default:
+ //
+ // For date/time without storage
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Question->Operand == EFI_IFR_DATE_OP) {
+ EfiTime.Year = QuestionValue->date.Year;
+ EfiTime.Month = QuestionValue->date.Month;
+ EfiTime.Day = QuestionValue->date.Day;
+ } else {
+ EfiTime.Hour = QuestionValue->time.Hour;
+ EfiTime.Minute = QuestionValue->time.Minute;
+ EfiTime.Second = QuestionValue->time.Second;
+ }
+
+ if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
+ Status = gRT->SetTime (&EfiTime);
+ } else {
+ Status = gRT->SetWakeupTime (TRUE, &EfiTime);
+ }
+ }
+
+ return Status;
+ }
+
+ //
+ // Question value is provided by EFI variable
+ //
+ StorageWidth = Question->StorageWidth;
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ if (Question->BufferValue != NULL) {
+ Src = Question->BufferValue;
+ } else {
+ Src = (UINT8 *) QuestionValue;
+ }
+
+ Status = gRT->SetVariable (
+ Question->VariableName,
+ &Storage->Guid,
+ Storage->Attributes,
+ StorageWidth,
+ Src
+ );
+ return Status;
+ }
+
+ //
+ // Question Value is provided by Buffer Storage or NameValue Storage
+ //
+ if (Question->BufferValue != NULL) {
+ Src = Question->BufferValue;
+ } else {
+ Src = (UINT8 *) &Question->HiiValue.Value;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ IsBufferStorage = TRUE;
+ } else {
+ IsBufferStorage = FALSE;
+ }
+ IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
+
+ if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
+ if (IsBufferStorage) {
+ if (SetValueTo == GetSetValueWithEditBuffer) {
+ //
+ // Copy to storage edit buffer
+ // If the Question refer to bit filed, copy the value in related bit filed to storage edit buffer.
+ //
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue (Question, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src));
+ } else {
+ CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
+ }
+ } else if (SetValueTo == GetSetValueWithBuffer) {
+ //
+ // Copy to storage buffer
+ // If the Question refer to bit filed, copy the value in related bit filed to storage buffer.
+ //
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src));
+ } else {
+ CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
+ }
+ }
+ } else {
+ if (IsString) {
+ //
+ // Allocate enough string buffer.
+ //
+ Value = NULL;
+ BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
+ Value = AllocateZeroPool (BufferLen);
+ ASSERT (Value != NULL);
+ //
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
+ //
+ TemName = (CHAR16 *) Src;
+ TemString = Value;
+ for (; *TemName != L'\0'; TemName++) {
+ UnicodeValueToStringS (
+ TemString,
+ BufferLen - ((UINTN)TemString - (UINTN)Value),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemName,
+ 4
+ );
+ TemString += StrnLenS (TemString, (BufferLen - ((UINTN)TemString - (UINTN)Value)) / sizeof (CHAR16));
+ }
+ } else {
+ BufferLen = StorageWidth * 2 + 1;
+ Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
+ ASSERT (Value != NULL);
+ //
+ // Convert Buffer to Hex String
+ //
+ TemBuffer = Src + StorageWidth - 1;
+ TemString = Value;
+ for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
+ UnicodeValueToStringS (
+ TemString,
+ BufferLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)Value),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemBuffer,
+ 2
+ );
+ TemString += StrnLenS (TemString, BufferLen - ((UINTN)TemString - (UINTN)Value) / sizeof (CHAR16));
+ }
+ }
+
+ Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
+ FreePool (Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ } else if (SetValueTo == GetSetValueWithHiiDriver) {
+ //
+ // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
+ // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
+ //
+ if (IsBufferStorage) {
+ Length = StrLen (Question->BlockName) + 7;
+ } else {
+ Length = StrLen (Question->VariableName) + 2;
+ }
+ if (!IsBufferStorage && IsString) {
+ Length += (StrLen ((CHAR16 *) Src) * 4);
+ } else {
+ Length += (StorageWidth * 2);
+ }
+ FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
+ ASSERT (FormsetStorage != NULL);
+ MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1;
+ ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (ConfigResp != NULL);
+
+ StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr);
+ if (IsBufferStorage) {
+ StrCatS (ConfigResp, MaxLen, Question->BlockName);
+ StrCatS (ConfigResp, MaxLen, L"&VALUE=");
+ } else {
+ StrCatS (ConfigResp, MaxLen, L"&");
+ StrCatS (ConfigResp, MaxLen, Question->VariableName);
+ StrCatS (ConfigResp, MaxLen, L"=");
+ }
+
+ Value = ConfigResp + StrLen (ConfigResp);
+
+ if (!IsBufferStorage && IsString) {
+ //
+ // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
+ //
+ TemName = (CHAR16 *) Src;
+ TemString = Value;
+ for (; *TemName != L'\0'; TemName++) {
+ UnicodeValueToStringS (
+ TemString,
+ MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemName,
+ 4
+ );
+ TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
+ }
+ } else {
+ //
+ // Convert Buffer to Hex String
+ //
+ TemBuffer = Src + StorageWidth - 1;
+ TemString = Value;
+ for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
+ UnicodeValueToStringS (
+ TemString,
+ MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
+ PREFIX_ZERO | RADIX_HEX,
+ *TemBuffer,
+ 2
+ );
+ TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
+ }
+ }
+
+ //
+ // Convert to lower char.
+ //
+ for (TemString = Value; *Value != L'\0'; Value++) {
+ if (*Value >= L'A' && *Value <= L'Z') {
+ *Value = (CHAR16) (*Value - L'A' + L'a');
+ }
+ }
+
+ //
+ // Submit Question Value to Configuration Driver
+ //
+ Status = mHiiConfigRouting->RouteConfig (
+ mHiiConfigRouting,
+ ConfigResp,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (ConfigResp);
+ return Status;
+ }
+ FreePool (ConfigResp);
+
+ //
+ // Sync storage, from editbuffer to buffer.
+ //
+ CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
+ }
+
+ return Status;
+}
+
+
+/**
+ Perform nosubmitif check for a Form.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question The Question to be validated.
+ @param Type Validation type: NoSubmit
+
+ @retval EFI_SUCCESS Form validation pass.
+ @retval other Form validation failed.
+
+**/
+EFI_STATUS
+ValidateQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINTN Type
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ListHead;
+ FORM_EXPRESSION *Expression;
+ UINT32 BrowserStatus;
+ CHAR16 *ErrorStr;
+
+ BrowserStatus = BROWSER_SUCCESS;
+ ErrorStr = NULL;
+
+ switch (Type) {
+ case EFI_HII_EXPRESSION_INCONSISTENT_IF:
+ ListHead = &Question->InconsistentListHead;
+ break;
+
+ case EFI_HII_EXPRESSION_WARNING_IF:
+ ListHead = &Question->WarningListHead;
+ break;
+
+ case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
+ ListHead = &Question->NoSubmitListHead;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ Link = GetFirstNode (ListHead);
+ while (!IsNull (ListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+
+ //
+ // Evaluate the expression
+ //
+ Status = EvaluateExpression (FormSet, Form, Expression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsTrue (&Expression->Result)) {
+ switch (Type) {
+ case EFI_HII_EXPRESSION_INCONSISTENT_IF:
+ BrowserStatus = BROWSER_INCONSISTENT_IF;
+ break;
+
+ case EFI_HII_EXPRESSION_WARNING_IF:
+ BrowserStatus = BROWSER_WARNING_IF;
+ break;
+
+ case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
+ BrowserStatus = BROWSER_NO_SUBMIT_IF;
+ //
+ // This code only used to compatible with old display engine,
+ // New display engine will not use this field.
+ //
+ if (Expression->Error != 0) {
+ ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
+ //
+ // If in system submit process and for no_submit_if check, not popup this error message.
+ // Will process this fail again later in not system submit process.
+ //
+ PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
+ }
+
+ if (ErrorStr != NULL) {
+ FreePool (ErrorStr);
+ }
+
+ if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+ }
+
+ Link = GetNextNode (ListHead, Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform question check.
+
+ If one question has more than one check, process form high priority to low.
+ Only one error info will be popup.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question The Question to be validated.
+
+ @retval EFI_SUCCESS Form validation pass.
+ @retval other Form validation failed.
+
+**/
+EFI_STATUS
+ValueChangedValidation (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Do the inconsistentif check.
+ //
+ if (!IsListEmpty (&Question->InconsistentListHead)) {
+ Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Do the warningif check.
+ //
+ if (!IsListEmpty (&Question->WarningListHead)) {
+ Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
+ }
+
+ return Status;
+}
+
+/**
+ Perform NoSubmit check for each Form in FormSet.
+
+ @param FormSet FormSet data structure.
+ @param CurrentForm Current input form data structure.
+ @param Statement The statement for this check.
+
+ @retval EFI_SUCCESS Form validation pass.
+ @retval other Form validation failed.
+
+**/
+EFI_STATUS
+NoSubmitCheck (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM **CurrentForm,
+ OUT FORM_BROWSER_STATEMENT **Statement
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *LinkForm;
+
+ LinkForm = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, LinkForm)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
+ LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
+
+ if (*CurrentForm != NULL && *CurrentForm != Form) {
+ continue;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
+ if (EFI_ERROR (Status)) {
+ if (*CurrentForm == NULL) {
+ *CurrentForm = Form;
+ }
+ if (Statement != NULL) {
+ *Statement = Question;
+ }
+ return Status;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill storage's edit copy with settings requested from Configuration Driver.
+
+ @param Storage The storage which need to sync.
+ @param ConfigRequest The config request string which used to sync storage.
+ @param SyncOrRestore Sync the buffer to editbuffer or Restore the
+ editbuffer to buffer
+ if TRUE, copy the editbuffer to the buffer.
+ if FALSE, copy the buffer to the editbuffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+SynchronizeStorage (
+ OUT BROWSER_STORAGE *Storage,
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN SyncOrRestore
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Progress;
+ EFI_STRING Result;
+ UINTN BufferSize;
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+ UINT8 *Src;
+ UINT8 *Dst;
+
+ Status = EFI_SUCCESS;
+ Result = NULL;
+
+ if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
+ (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ BufferSize = Storage->Size;
+
+ if (SyncOrRestore) {
+ Src = Storage->EditBuffer;
+ Dst = Storage->Buffer;
+ } else {
+ Src = Storage->Buffer;
+ Dst = Storage->EditBuffer;
+ }
+
+ if (ConfigRequest != NULL) {
+ Status = mHiiConfigRouting->BlockToConfig(
+ mHiiConfigRouting,
+ ConfigRequest,
+ Src,
+ BufferSize,
+ &Result,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = mHiiConfigRouting->ConfigToBlock (
+ mHiiConfigRouting,
+ Result,
+ Dst,
+ &BufferSize,
+ &Progress
+ );
+ if (Result != NULL) {
+ FreePool (Result);
+ }
+ } else {
+ CopyMem (Dst, Src, BufferSize);
+ }
+ } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
+ (ConfigRequest == NULL)) {
+ if (SyncOrRestore) {
+ NewStringCpy (&Node->Value, Node->EditValue);
+ } else {
+ NewStringCpy (&Node->EditValue, Node->Value);
+ }
+ }
+
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ When discard the question value, call the callback function with Changed type
+ to inform the hii driver.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+SendDiscardInfoToDriver (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ EFI_IFR_TYPE_VALUE *TypeValue;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ if (FormSet->ConfigAccess == NULL) {
+ return;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
+ continue;
+ }
+
+ if (Question->Operand == EFI_IFR_PASSWORD_OP) {
+ continue;
+ }
+
+ if (!Question->ValueChanged) {
+ continue;
+ }
+
+ //
+ // Restore the question value before call the CHANGED callback type.
+ //
+ GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+
+ if (Question->Operand == EFI_IFR_STRING_OP){
+ HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
+ }
+
+ if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
+ } else {
+ TypeValue = &Question->HiiValue.Value;
+ }
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ FormSet->ConfigAccess->Callback (
+ FormSet->ConfigAccess,
+ EFI_BROWSER_ACTION_CHANGED,
+ Question->QuestionId,
+ Question->HiiValue.Type,
+ TypeValue,
+ &ActionRequest
+ );
+ }
+}
+
+/**
+ When submit the question value, call the callback function with Submitted type
+ to inform the hii driver.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+SubmitCallbackForForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ EFI_IFR_TYPE_VALUE *TypeValue;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ if (FormSet->ConfigAccess == NULL) {
+ return;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
+ continue;
+ }
+
+ if (Question->Operand == EFI_IFR_PASSWORD_OP) {
+ continue;
+ }
+
+ if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
+ } else {
+ TypeValue = &Question->HiiValue.Value;
+ }
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ FormSet->ConfigAccess->Callback (
+ FormSet->ConfigAccess,
+ EFI_BROWSER_ACTION_SUBMITTED,
+ Question->QuestionId,
+ Question->HiiValue.Type,
+ TypeValue,
+ &ActionRequest
+ );
+ }
+}
+
+/**
+ When value set Success, call the submit callback function.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+SubmitCallback (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_FORM *CurrentForm;
+ LIST_ENTRY *Link;
+
+ if (Form != NULL) {
+ SubmitCallbackForForm(FormSet, Form);
+ return;
+ }
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ SubmitCallbackForForm(FormSet, CurrentForm);
+ }
+}
+
+/**
+ Validate the HiiHandle.
+
+ @param HiiHandle The input HiiHandle which need to validate.
+
+ @retval TRUE The handle is validate.
+ @retval FALSE The handle is invalidate.
+
+**/
+BOOLEAN
+ValidateHiiHandle (
+ EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_HII_HANDLE *HiiHandles;
+ UINTN Index;
+ BOOLEAN Find;
+
+ if (HiiHandle == NULL) {
+ return FALSE;
+ }
+
+ Find = FALSE;
+
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ if (HiiHandles[Index] == HiiHandle) {
+ Find = TRUE;
+ break;
+ }
+ }
+
+ FreePool (HiiHandles);
+
+ return Find;
+}
+
+/**
+ Validate the FormSet. If the formset is not validate, remove it from the list.
+
+ @param FormSet The input FormSet which need to validate.
+
+ @retval TRUE The handle is validate.
+ @retval FALSE The handle is invalidate.
+
+**/
+BOOLEAN
+ValidateFormSet (
+ FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ BOOLEAN Find;
+
+ ASSERT (FormSet != NULL);
+
+ Find = ValidateHiiHandle(FormSet->HiiHandle);
+ //
+ // Should not remove the formset which is being used.
+ //
+ if (!Find && (FormSet != gCurrentSelection->FormSet)) {
+ CleanBrowserStorage(FormSet);
+ RemoveEntryList (&FormSet->Link);
+ DestroyFormSet (FormSet);
+ }
+
+ return Find;
+}
+/**
+ Check whether need to enable the reset flag in form level.
+ Also clean all ValueChanged flag in question.
+
+ @param SetFlag Whether need to set the Reset Flag.
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+UpdateFlagForForm (
+ IN BOOLEAN SetFlag,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ BOOLEAN OldValue;
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ if (!Question->ValueChanged) {
+ continue;
+ }
+
+ OldValue = Question->ValueChanged;
+
+ //
+ // Compare the buffer and editbuffer data to see whether the data has been saved.
+ //
+ Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
+
+ //
+ // Only the changed data has been saved, then need to set the reset flag.
+ //
+ if (SetFlag && OldValue && !Question->ValueChanged) {
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
+ gResetRequiredFormLevel = TRUE;
+ gResetRequiredSystemLevel = TRUE;
+ }
+
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
+ gFlagReconnect = TRUE;
+ }
+ }
+ }
+}
+
+/**
+ Check whether need to enable the reset flag.
+ Also clean ValueChanged flag for all statements.
+
+ Form level or formset level, only one.
+
+ @param SetFlag Whether need to set the Reset Flag.
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+**/
+VOID
+ValueChangeResetFlagUpdate (
+ IN BOOLEAN SetFlag,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_FORM *CurrentForm;
+ LIST_ENTRY *Link;
+
+ if (Form != NULL) {
+ UpdateFlagForForm(SetFlag, FormSet, Form);
+ return;
+ }
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
+ }
+}
+
+/**
+ Base on the return Progress string to find the form.
+
+ Base on the first return Offset/Width (Name) string to find the form
+ which keep this string.
+
+ @param FormSet FormSet data structure.
+ @param Storage Storage which has this Progress string.
+ @param Progress The Progress string which has the first fail string.
+ @param RetForm The return form for this progress string.
+ @param RetQuestion The return question for the error progress string.
+
+ @retval TRUE Find the error form and statement for this error progress string.
+ @retval FALSE Not find the error form.
+
+**/
+BOOLEAN
+FindQuestionFromProgress (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN BROWSER_STORAGE *Storage,
+ IN EFI_STRING Progress,
+ OUT FORM_BROWSER_FORM **RetForm,
+ OUT FORM_BROWSER_STATEMENT **RetQuestion
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *LinkStorage;
+ LIST_ENTRY *LinkStatement;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+ FORM_BROWSER_FORM *Form;
+ EFI_STRING EndStr;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ ASSERT ((*Progress == '&') || (*Progress == 'G'));
+
+ ConfigInfo = NULL;
+ *RetForm = NULL;
+ *RetQuestion = NULL;
+
+ //
+ // Skip the first "&" or the ConfigHdr part.
+ //
+ if (*Progress == '&') {
+ Progress++;
+ } else {
+ //
+ // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // For Name/Value type, Skip the ConfigHdr part.
+ //
+ EndStr = StrStr (Progress, L"PATH=");
+ ASSERT (EndStr != NULL);
+ while (*EndStr != '&') {
+ EndStr++;
+ }
+
+ *EndStr = '\0';
+ } else {
+ //
+ // For Buffer type, Skip the ConfigHdr part.
+ //
+ EndStr = StrStr (Progress, L"&OFFSET=");
+ ASSERT (EndStr != NULL);
+ *EndStr = '\0';
+ }
+
+ Progress = EndStr + 1;
+ }
+
+ //
+ // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
+ // here, just keep the "Fred" string.
+ //
+ EndStr = StrStr (Progress, L"=");
+ ASSERT (EndStr != NULL);
+ *EndStr = '\0';
+ } else {
+ //
+ // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
+ // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
+ //
+ EndStr = StrStr (Progress, L"&VALUE=");
+ ASSERT (EndStr != NULL);
+ *EndStr = '\0';
+ }
+
+ //
+ // Search in the form list.
+ //
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ //
+ // Search in the ConfigReqeust list in this form.
+ //
+ LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
+ LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
+
+ if (Storage != ConfigInfo->Storage) {
+ continue;
+ }
+
+ if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
+ //
+ // Find the OffsetWidth string in this form.
+ //
+ *RetForm = Form;
+ break;
+ }
+ }
+
+ if (*RetForm != NULL) {
+ LinkStatement = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, LinkStatement)) {
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
+ LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
+
+ if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
+ *RetQuestion = Statement;
+ break;
+ }
+
+ if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {
+ *RetQuestion = Statement;
+ break;
+ }
+ }
+ }
+
+ if (*RetForm != NULL) {
+ break;
+ }
+ }
+
+ //
+ // restore the OffsetWidth string to the original format.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ *EndStr = '=';
+ } else {
+ *EndStr = '&';
+ }
+
+ return (BOOLEAN) (*RetForm != NULL);
+}
+
+/**
+ Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest
+ for form and formset.
+
+ @param Storage Storage which has this Progress string.
+ @param ConfigRequest The ConfigRequest string.
+ @param Progress The Progress string which has the first fail string.
+ @param RestoreConfigRequest Return the RestoreConfigRequest string.
+ @param SyncConfigRequest Return the SyncConfigRequest string.
+
+**/
+VOID
+GetSyncRestoreConfigRequest(
+ IN BROWSER_STORAGE *Storage,
+ IN EFI_STRING ConfigRequest,
+ IN EFI_STRING Progress,
+ OUT EFI_STRING *RestoreConfigRequest,
+ OUT EFI_STRING *SyncConfigRequest
+ )
+{
+ EFI_STRING EndStr;
+ EFI_STRING ConfigHdrEndStr;
+ EFI_STRING ElementStr;
+ UINTN TotalSize;
+ UINTN RestoreEleSize;
+ UINTN SyncSize;
+
+ ASSERT ((*Progress == L'&') || (*Progress == L'G'));
+ //
+ // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair.
+ // Need to restore all the fields in the ConfigRequest.
+ //
+ if (*Progress == L'G') {
+ *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
+ ASSERT (*RestoreConfigRequest != NULL);
+ return;
+ }
+
+ //
+ // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
+ // here, just keep the "Fred" string.
+ //
+ EndStr = StrStr (Progress, L"=");
+ ASSERT (EndStr != NULL);
+ *EndStr = L'\0';
+ //
+ // Find the ConfigHdr in ConfigRequest.
+ //
+ ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH=");
+ ASSERT (ConfigHdrEndStr != NULL);
+ while (*ConfigHdrEndStr != L'&') {
+ ConfigHdrEndStr++;
+ }
+ } else {
+ //
+ // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
+ // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
+ //
+ EndStr = StrStr (Progress, L"&VALUE=");
+ ASSERT (EndStr != NULL);
+ *EndStr = L'\0';
+ //
+ // Find the ConfigHdr in ConfigRequest.
+ //
+ ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET=");
+ }
+ //
+ // Find the first fail pair in the ConfigRequest.
+ //
+ ElementStr = StrStr (ConfigRequest, Progress);
+ ASSERT (ElementStr != NULL);
+ //
+ // To get the RestoreConfigRequest.
+ //
+ RestoreEleSize = StrSize (ElementStr);
+ TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16);
+ *RestoreConfigRequest = AllocateZeroPool (TotalSize);
+ ASSERT (*RestoreConfigRequest != NULL);
+ StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest);
+ StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr);
+ //
+ // To get the SyncConfigRequest.
+ //
+ SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16);
+ *SyncConfigRequest = AllocateZeroPool (SyncSize);
+ ASSERT (*SyncConfigRequest != NULL);
+ StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1);
+
+ //
+ // restore the Progress string to the original format.
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ *EndStr = L'=';
+ } else {
+ *EndStr = L'&';
+ }
+}
+
+/**
+ Popup an save error info and get user input.
+
+ @param TitleId The form title id.
+ @param HiiHandle The hii handle for this package.
+
+ @retval UINT32 The user select option for the save fail.
+ BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
+**/
+UINT32
+ConfirmSaveFail (
+ IN EFI_STRING_ID TitleId,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ CHAR16 *FormTitle;
+ CHAR16 *StringBuffer;
+ UINT32 RetVal;
+
+ FormTitle = GetToken (TitleId, HiiHandle);
+
+ StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
+ ASSERT (StringBuffer != NULL);
+
+ UnicodeSPrint (
+ StringBuffer,
+ 24 * sizeof (CHAR16) + StrSize (FormTitle),
+ L"Submit Fail For Form: %s.",
+ FormTitle
+ );
+
+ RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
+
+ FreePool (StringBuffer);
+ FreePool (FormTitle);
+
+ return RetVal;
+}
+
+/**
+ Popup an NO_SUBMIT_IF error info and get user input.
+
+ @param TitleId The form title id.
+ @param HiiHandle The hii handle for this package.
+
+ @retval UINT32 The user select option for the save fail.
+ BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
+**/
+UINT32
+ConfirmNoSubmitFail (
+ IN EFI_STRING_ID TitleId,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ CHAR16 *FormTitle;
+ CHAR16 *StringBuffer;
+ UINT32 RetVal;
+
+ FormTitle = GetToken (TitleId, HiiHandle);
+
+ StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
+ ASSERT (StringBuffer != NULL);
+
+ UnicodeSPrint (
+ StringBuffer,
+ 24 * sizeof (CHAR16) + StrSize (FormTitle),
+ L"NO_SUBMIT_IF error For Form: %s.",
+ FormTitle
+ );
+
+ RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
+
+ FreePool (StringBuffer);
+ FreePool (FormTitle);
+
+ return RetVal;
+}
+
+/**
+ Discard data based on the input setting scope (Form, FormSet or System).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Discard action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+DiscardForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+ FORM_BROWSER_FORMSET *LocalFormSet;
+ FORM_BROWSER_FORMSET *OldFormSet;
+
+ //
+ // Check the supported setting level.
+ //
+ if (SettingScope >= MaxLevel) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
+ ConfigInfo = NULL;
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+
+ if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // Skip if there is no RequestElement
+ //
+ if (ConfigInfo->ElementCount == 0) {
+ continue;
+ }
+
+ //
+ // Prepare <ConfigResp>
+ //
+ SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
+
+ //
+ // Call callback with Changed type to inform the driver.
+ //
+ SendDiscardInfoToDriver (FormSet, Form);
+ }
+
+ ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
+ } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
+
+ //
+ // Discard Buffer storage or Name/Value storage
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // Skip if there is no RequestElement
+ //
+ if (Storage->ElementCount == 0) {
+ continue;
+ }
+
+ SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
+ }
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+
+ //
+ // Call callback with Changed type to inform the driver.
+ //
+ SendDiscardInfoToDriver (FormSet, Form);
+ }
+
+ ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
+ } else if (SettingScope == SystemLevel) {
+ //
+ // System Level Discard.
+ //
+ OldFormSet = mSystemLevelFormSet;
+
+ //
+ // Discard changed value for each FormSet in the maintain list.
+ //
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(LocalFormSet)) {
+ continue;
+ }
+
+ mSystemLevelFormSet = LocalFormSet;
+
+ DiscardForm (LocalFormSet, NULL, FormSetLevel);
+ if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
+ //
+ // Remove maintain backup list after discard except for the current using FormSet.
+ //
+ CleanBrowserStorage(LocalFormSet);
+ RemoveEntryList (&LocalFormSet->Link);
+ DestroyFormSet (LocalFormSet);
+ }
+ }
+
+ mSystemLevelFormSet = OldFormSet;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submit data for a form.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+SubmitForForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_STRING ConfigResp;
+ EFI_STRING Progress;
+ BROWSER_STORAGE *Storage;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+ BOOLEAN SubmitFormFail;
+
+ SubmitFormFail = FALSE;
+
+ if (!IsNvUpdateRequiredForForm (Form)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = NoSubmitCheck (FormSet, &Form, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+
+ Storage = ConfigInfo->Storage;
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // Skip if there is no RequestElement
+ //
+ if (ConfigInfo->ElementCount == 0) {
+ continue;
+ }
+
+ //
+ // 1. Prepare <ConfigResp>
+ //
+ Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 2. Set value to hii config routine protocol.
+ //
+ Status = mHiiConfigRouting->RouteConfig (
+ mHiiConfigRouting,
+ ConfigResp,
+ &Progress
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
+ //
+ SubmitFormFail = TRUE;
+ GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest);
+ InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
+ FreePool (ConfigResp);
+ continue;
+ }
+
+ FreePool (ConfigResp);
+ //
+ // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
+ //
+ SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
+ }
+
+ //
+ // 4. Process the save failed storage.
+ //
+ if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
+ if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
+ Link = GetFirstNode (&gBrowserSaveFailFormSetList);
+ while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
+ Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
+ //
+ // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
+ // base on the SyncConfigRequest to Sync the buffer.
+ //
+ SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE);
+ FreePool (ConfigInfo->RestoreConfigRequest);
+ ConfigInfo->RestoreConfigRequest = NULL;
+ if (ConfigInfo->SyncConfigRequest != NULL) {
+ SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE);
+ FreePool (ConfigInfo->SyncConfigRequest);
+ ConfigInfo->SyncConfigRequest = NULL;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+ SendDiscardInfoToDriver (FormSet,Form);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ //
+ // Free Form save fail list.
+ //
+ while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
+ Link = GetFirstNode (&gBrowserSaveFailFormSetList);
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
+ RemoveEntryList (&ConfigInfo->SaveFailLink);
+ }
+ }
+
+ //
+ // 5. Update the NV flag.
+ //
+ ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
+
+ //
+ // 6 Call callback with Submitted type to inform the driver.
+ //
+ if (!SubmitFormFail) {
+ SubmitCallback (FormSet, Form);
+ }
+
+ return Status;
+}
+
+/**
+ Submit data for a formset.
+
+ @param FormSet FormSet data structure.
+ @param SkipProcessFail Whether skip to process the save failed storage.
+ If submit formset is called when do system level save,
+ set this value to true and process the failed formset
+ together.
+ if submit formset is called when do formset level save,
+ set the value to false and process the failed storage
+ right after process all storages for this formset.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+SubmitForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN BOOLEAN SkipProcessFail
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_STRING ConfigResp;
+ EFI_STRING Progress;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormSetStorage;
+ FORM_BROWSER_FORM *Form;
+ BOOLEAN HasInserted;
+ FORM_BROWSER_STATEMENT *Question;
+ BOOLEAN SubmitFormSetFail;
+ BOOLEAN DiscardChange;
+
+ HasInserted = FALSE;
+ SubmitFormSetFail = FALSE;
+ DiscardChange = FALSE;
+
+ if (!IsNvUpdateRequiredForFormSet (FormSet)) {
+ return EFI_SUCCESS;
+ }
+
+ Form = NULL;
+ Status = NoSubmitCheck (FormSet, &Form, &Question);
+ if (EFI_ERROR (Status)) {
+ if (SkipProcessFail) {
+ //
+ // Process NO_SUBMIT check first, so insert it at head.
+ //
+ FormSet->SaveFailForm = Form;
+ FormSet->SaveFailStatement = Question;
+ InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
+ }
+
+ return Status;
+ }
+
+ Form = NULL;
+ Question = NULL;
+ //
+ // Submit Buffer storage or Name/Value storage
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Storage = FormSetStorage->BrowserStorage;
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // Skip if there is no RequestElement
+ //
+ if (FormSetStorage->ElementCount == 0) {
+ continue;
+ }
+
+ //
+ // 1. Prepare <ConfigResp>
+ //
+ Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 2. Send <ConfigResp> to Routine config Protocol.
+ //
+ Status = mHiiConfigRouting->RouteConfig (
+ mHiiConfigRouting,
+ ConfigResp,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
+ //
+ SubmitFormSetFail = TRUE;
+ GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest);
+ InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
+ if (!HasInserted) {
+ //
+ // Call submit formset for system level, save the formset info
+ // and process later.
+ //
+ FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
+ ASSERT (Form != NULL && Question != NULL);
+ FormSet->SaveFailForm = Form;
+ FormSet->SaveFailStatement = Question;
+ if (SkipProcessFail) {
+ InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
+ }
+ HasInserted = TRUE;
+ }
+
+ FreePool (ConfigResp);
+ continue;
+ }
+
+ FreePool (ConfigResp);
+ //
+ // 3. Config success, update storage shadow Buffer
+ //
+ SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
+ }
+
+ //
+ // 4. Has save fail storage need to handle.
+ //
+ if (Form != NULL) {
+ if (!SkipProcessFail) {
+ //
+ // If not in system level, just handl the save failed storage here.
+ //
+ if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
+ DiscardChange = TRUE;
+ Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
+ while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
+ Storage = FormSetStorage->BrowserStorage;
+ Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
+ //
+ // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
+ // base on the SyncConfigRequest to Sync the buffer.
+ //
+ SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
+ FreePool (FormSetStorage->RestoreConfigRequest);
+ FormSetStorage->RestoreConfigRequest = NULL;
+ if (FormSetStorage->SyncConfigRequest != NULL) {
+ SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
+ FreePool (FormSetStorage->SyncConfigRequest);
+ FormSetStorage->SyncConfigRequest = NULL;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+ } else {
+ UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
+
+ gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
+ gCurrentSelection->Handle = FormSet->HiiHandle;
+ CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
+ gCurrentSelection->FormId = Form->FormId;
+ gCurrentSelection->QuestionId = Question->QuestionId;
+
+ Status = EFI_UNSUPPORTED;
+ }
+
+ //
+ // Free FormSet save fail list.
+ //
+ while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
+ Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
+ FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
+ RemoveEntryList (&FormSetStorage->SaveFailLink);
+ }
+ } else {
+ //
+ // If in system level, just return error and handle the failed formset later.
+ //
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // If user discard the change, send the discard info to driver.
+ //
+ if (DiscardChange) {
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ //
+ // Call callback with Changed type to inform the driver.
+ //
+ SendDiscardInfoToDriver (FormSet, Form);
+ }
+ }
+
+ //
+ // 5. Update the NV flag.
+ //
+ ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
+
+ //
+ // 6. Call callback with Submitted type to inform the driver.
+ //
+ if (!SubmitFormSetFail) {
+ SubmitCallback (FormSet, NULL);
+ }
+
+ return Status;
+}
+
+/**
+ Submit data for all formsets.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+SubmitForSystem (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *FormLink;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *FormSetStorage;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_FORMSET *LocalFormSet;
+ UINT32 UserSelection;
+ FORM_BROWSER_STATEMENT *Question;
+
+ mSystemSubmit = TRUE;
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(LocalFormSet)) {
+ continue;
+ }
+
+ Status = SubmitForFormSet (LocalFormSet, TRUE);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Remove maintain backup list after save except for the current using FormSet.
+ //
+ if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
+ CleanBrowserStorage(LocalFormSet);
+ RemoveEntryList (&LocalFormSet->Link);
+ DestroyFormSet (LocalFormSet);
+ }
+ }
+ mSystemSubmit = FALSE;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Process the save failed formsets.
+ //
+ Link = GetFirstNode (&gBrowserSaveFailFormSetList);
+ while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
+ Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
+
+ if (!ValidateFormSet(LocalFormSet)) {
+ continue;
+ }
+
+ Form = LocalFormSet->SaveFailForm;
+ Question= LocalFormSet->SaveFailStatement;
+
+ //
+ // Confirm with user, get user input.
+ //
+ if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
+ //
+ // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
+ //
+ UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
+ } else {
+ UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
+ }
+
+ if (UserSelection == BROWSER_ACTION_DISCARD) {
+ if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
+ StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
+ while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
+
+ SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
+ }
+ } else {
+ StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
+ while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
+ StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
+ //
+ // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
+ // base on the SyncConfigRequest to Sync the buffer.
+ //
+ SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
+ FreePool (FormSetStorage->RestoreConfigRequest);
+ FormSetStorage->RestoreConfigRequest = NULL;
+ if ( FormSetStorage->SyncConfigRequest != NULL) {
+ SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
+ FreePool (FormSetStorage->SyncConfigRequest);
+ FormSetStorage->SyncConfigRequest = NULL;
+ }
+ }
+ }
+
+ FormLink = GetFirstNode (&LocalFormSet->FormListHead);
+ while (!IsNull (&LocalFormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink);
+ //
+ // Call callback with Changed type to inform the driver.
+ //
+ SendDiscardInfoToDriver (LocalFormSet, Form);
+ }
+
+ if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
+ CleanBrowserStorage(LocalFormSet);
+ RemoveEntryList (&LocalFormSet->Link);
+ RemoveEntryList (&LocalFormSet->SaveFailLink);
+ DestroyFormSet (LocalFormSet);
+ } else {
+ ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
+ }
+ } else {
+ if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
+ NoSubmitCheck (LocalFormSet, &Form, &Question);
+ }
+
+ UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
+
+ gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
+ gCurrentSelection->Handle = LocalFormSet->HiiHandle;
+ CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
+ gCurrentSelection->FormId = Form->FormId;
+ gCurrentSelection->QuestionId = Question->QuestionId;
+
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ }
+
+ //
+ // Clean the list which will not process.
+ //
+ while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
+ Link = GetFirstNode (&gBrowserSaveFailFormSetList);
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
+ RemoveEntryList (&LocalFormSet->SaveFailLink);
+
+ while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
+ StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
+ FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
+ RemoveEntryList (&FormSetStorage->SaveFailLink);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Submit data based on the input Setting level (Form, FormSet or System).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Submit action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+SubmitForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ )
+{
+ EFI_STATUS Status;
+
+ switch (SettingScope) {
+ case FormLevel:
+ Status = SubmitForForm(FormSet, Form);
+ break;
+
+ case FormSetLevel:
+ Status = SubmitForFormSet (FormSet, FALSE);
+ break;
+
+ case SystemLevel:
+ Status = SubmitForSystem ();
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Converts the unicode character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+EFIAPI
+HiiToLower (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+}
+
+/**
+ Find the point in the ConfigResp string for this question.
+
+ @param Question The question.
+ @param ConfigResp Get ConfigResp string.
+
+ @retval point to the offset where is for this question.
+
+**/
+CHAR16 *
+GetOffsetFromConfigResp (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16 *ConfigResp
+ )
+{
+ CHAR16 *RequestElement;
+ CHAR16 *BlockData;
+
+ //
+ // Type is EFI_HII_VARSTORE_NAME_VALUE.
+ //
+ if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ RequestElement = StrStr (ConfigResp, Question->VariableName);
+ if (RequestElement != NULL) {
+ //
+ // Skip the "VariableName=" field.
+ //
+ RequestElement += StrLen (Question->VariableName) + 1;
+ }
+
+ return RequestElement;
+ }
+
+ //
+ // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
+ //
+
+ //
+ // Convert all hex digits in ConfigResp to lower case before searching.
+ //
+ HiiToLower (ConfigResp);
+
+ //
+ // 1. Directly use Question->BlockName to find.
+ //
+ RequestElement = StrStr (ConfigResp, Question->BlockName);
+ if (RequestElement != NULL) {
+ //
+ // Skip the "Question->BlockName&VALUE=" field.
+ //
+ RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
+ return RequestElement;
+ }
+
+ //
+ // 2. Change all hex digits in Question->BlockName to lower and compare again.
+ //
+ BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);
+ ASSERT (BlockData != NULL);
+ HiiToLower (BlockData);
+ RequestElement = StrStr (ConfigResp, BlockData);
+ FreePool (BlockData);
+
+ if (RequestElement != NULL) {
+ //
+ // Skip the "Question->BlockName&VALUE=" field.
+ //
+ RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
+ }
+
+ return RequestElement;
+}
+
+/**
+ Get Question default value from AltCfg string.
+
+ @param FormSet The form set.
+ @param Form The form
+ @param Question The question.
+
+ @retval EFI_SUCCESS Question is reset to default value.
+
+**/
+EFI_STATUS
+GetDefaultValueFromAltCfg (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question
+ )
+{
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormSetStorage;
+ CHAR16 *ConfigResp;
+ CHAR16 *Value;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+
+ Storage = Question->Storage;
+ if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try to get AltCfg string from form. If not found it, then
+ // try to get it from formset.
+ //
+ ConfigResp = NULL;
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+
+ if (Storage == ConfigInfo->Storage) {
+ ConfigResp = ConfigInfo->ConfigAltResp;
+ break;
+ }
+ }
+
+ if (ConfigResp == NULL) {
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (Storage == FormSetStorage->BrowserStorage) {
+ ConfigResp = FormSetStorage->ConfigAltResp;
+ break;
+ }
+ }
+ }
+
+ if (ConfigResp == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Value = GetOffsetFromConfigResp (Question, ConfigResp);
+ if (Value == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return BufferToValue (Question, Value);
+}
+
+/**
+ Get default Id value used for browser.
+
+ @param DefaultId The default id value used by hii.
+
+ @retval Browser used default value.
+
+**/
+INTN
+GetDefaultIdForCallBack (
+ UINTN DefaultId
+ )
+{
+ if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
+ return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
+ } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
+ } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
+ return EFI_BROWSER_ACTION_DEFAULT_SAFE;
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
+ return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
+ return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
+ } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
+ return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
+ } else {
+ return -1;
+ }
+}
+
+
+
+/**
+ Return data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+
+ @retval Value The data to be returned
+
+**/
+UINT64
+GetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index
+ )
+{
+ UINT64 Data;
+
+ ASSERT (Array != NULL);
+
+ Data = 0;
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Data = (UINT64) *(((UINT8 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Data = (UINT64) *(((UINT16 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Data = (UINT64) *(((UINT32 *) Array) + Index);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Data = (UINT64) *(((UINT64 *) Array) + Index);
+ break;
+
+ default:
+ break;
+ }
+
+ return Data;
+}
+
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+
+ ASSERT (Array != NULL);
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *(((UINT8 *) Array) + Index) = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *(((UINT16 *) Array) + Index) = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *(((UINT32 *) Array) + Index) = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *(((UINT64 *) Array) + Index) = (UINT64) Value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ INTN Result;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+ //
+ // Check the suppressif condition, only a valid option can be return.
+ //
+ if ((Option->SuppressExpression == NULL) ||
+ ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
+ return Option;
+ }
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Reset Question to its default value.
+
+ @param FormSet The form set.
+ @param Form The form.
+ @param Question The question.
+ @param DefaultId The Class of the default.
+
+ @retval EFI_SUCCESS Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT16 DefaultId
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ EFI_HII_VALUE *HiiValue;
+ UINT8 Index;
+ EFI_STRING StrValue;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ INTN Action;
+ CHAR16 *NewString;
+ EFI_IFR_TYPE_VALUE *TypeValue;
+ UINT16 OriginalDefaultId;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ LIST_ENTRY *DefaultLink;
+
+ Status = EFI_NOT_FOUND;
+ StrValue = NULL;
+ OriginalDefaultId = DefaultId;
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+ //
+ // Statement don't have storage, skip them
+ //
+ if (Question->QuestionId == 0) {
+ return Status;
+ }
+
+ //
+ // There are Five ways to specify default value for a Question:
+ // 1, use call back function (highest priority)
+ // 2, use ExtractConfig function
+ // 3, use nested EFI_IFR_DEFAULT
+ // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
+ // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
+ //
+ReGetDefault:
+ HiiValue = &Question->HiiValue;
+ TypeValue = &HiiValue->Value;
+ if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+ //
+ // For orderedlist, need to pass the BufferValue to Callback function.
+ //
+ TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
+ }
+
+ //
+ // Get Question defaut value from call back function.
+ //
+ ConfigAccess = FormSet->ConfigAccess;
+ Action = GetDefaultIdForCallBack (DefaultId);
+ if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = ConfigAccess->Callback (
+ ConfigAccess,
+ Action,
+ Question->QuestionId,
+ HiiValue->Type,
+ TypeValue,
+ &ActionRequest
+ );
+ if (!EFI_ERROR (Status)) {
+ if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
+ NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
+ ASSERT (NewString != NULL);
+
+ ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
+ if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
+ ZeroMem (Question->BufferValue, Question->StorageWidth);
+ CopyMem (Question->BufferValue, NewString, StrSize (NewString));
+ } else {
+ CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
+ }
+
+ FreePool (NewString);
+ }
+ return Status;
+ }
+ }
+
+ //
+ // Get default value from altcfg string.
+ //
+ if (ConfigAccess != NULL) {
+ Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // EFI_IFR_DEFAULT has highest priority
+ //
+ if (!IsListEmpty (&Question->DefaultListHead)) {
+ Link = GetFirstNode (&Question->DefaultListHead);
+ while (!IsNull (&Question->DefaultListHead, Link)) {
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+
+ if (Default->DefaultId == DefaultId) {
+ if (Default->ValueExpression != NULL) {
+ //
+ // Default is provided by an Expression, evaluate it
+ //
+ Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+ ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
+ if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
+ CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
+ Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
+ } else {
+ CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
+ Question->HiiValue.BufferLen = Question->StorageWidth;
+ }
+ FreePool (Default->ValueExpression->Result.Buffer);
+ }
+ HiiValue->Type = Default->ValueExpression->Result.Type;
+ CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+ } else {
+ //
+ // Default value is embedded in EFI_IFR_DEFAULT
+ //
+ if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ ASSERT (HiiValue->Buffer != NULL);
+ CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
+ } else {
+ CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
+ }
+ }
+
+ if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
+ StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
+ if (StrValue == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ if (Question->StorageWidth > StrSize (StrValue)) {
+ ZeroMem (Question->BufferValue, Question->StorageWidth);
+ CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
+ } else {
+ CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Question->DefaultListHead, Link);
+ }
+ }
+
+ //
+ // EFI_ONE_OF_OPTION
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // OneOfOption could only provide Standard and Manufacturing default
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ if ((Option->SuppressExpression != NULL) &&
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
+ continue;
+ }
+
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
+ ) {
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ //
+ // EFI_IFR_CHECKBOX - lowest priority
+ //
+ if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // Checkbox could only provide Standard and Manufacturing default
+ //
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
+ ) {
+ HiiValue->Value.b = TRUE;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
+ // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
+ // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
+ //
+ while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
+ DefaultId = DefaultStore->DefaultId;
+ if (DefaultId == OriginalDefaultId) {
+ continue;
+ }
+ goto ReGetDefault;
+ }
+
+ //
+ // For Questions without default value for all the default id in the DefaultStoreList.
+ //
+ Status = EFI_NOT_FOUND;
+ switch (Question->Operand) {
+ case EFI_IFR_CHECKBOX_OP:
+ HiiValue->Value.b = FALSE;
+ Status = EFI_SUCCESS;
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Take minimum value as numeric default value
+ //
+ if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
+ //
+ // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
+ //
+ switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) {
+ HiiValue->Value.u8 = (UINT8) Question->Minimum;
+ Status = EFI_SUCCESS;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) {
+ HiiValue->Value.u16 = (UINT16) Question->Minimum;
+ Status = EFI_SUCCESS;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) {
+ HiiValue->Value.u32 = (UINT32) Question->Minimum;
+ Status = EFI_SUCCESS;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) {
+ HiiValue->Value.u64 = Question->Minimum;
+ Status = EFI_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
+ HiiValue->Value.u64 = Question->Minimum;
+ Status = EFI_SUCCESS;
+ }
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Take first oneof option as oneof's default value
+ //
+ if (ValueToOption (Question, HiiValue) == NULL) {
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ if ((Option->SuppressExpression != NULL) &&
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
+ continue;
+ }
+
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ //
+ // Take option sequence in IFR as ordered list's default value
+ //
+ Index = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Status = EFI_SUCCESS;
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Link = GetNextNode (&Question->OptionListHead, Link);
+
+ if ((Option->SuppressExpression != NULL) &&
+ EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
+ continue;
+ }
+
+ SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
+
+ Index++;
+ if (Index >= Question->MaxContainers) {
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Get AltCfg string for current form.
+
+ @param FormSet Form data structure.
+ @param Form Form data structure.
+ @param DefaultId The Class of the default.
+ @param BrowserStorage The input request storage for the questions.
+
+**/
+VOID
+ExtractAltCfgForForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN BROWSER_STORAGE *BrowserStorage
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ CHAR16 *ConfigResp;
+ CHAR16 *Progress;
+ CHAR16 *Result;
+ BROWSER_STORAGE *Storage;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+ FORMSET_STORAGE *FormSetStorage;
+
+ //
+ // Check whether has get AltCfg string for this formset.
+ // If yes, no need to get AltCfg for form.
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Storage = FormSetStorage->BrowserStorage;
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+ if (BrowserStorage != NULL && BrowserStorage != Storage) {
+ continue;
+ }
+
+ if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&
+ FormSetStorage->ElementCount != 0 &&
+ FormSetStorage->HasCallAltCfg) {
+ return;
+ }
+ }
+
+ //
+ // Get AltCfg string for each form.
+ //
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+
+ Storage = ConfigInfo->Storage;
+ if (BrowserStorage != NULL && BrowserStorage != Storage) {
+ continue;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // 1. Skip if there is no RequestElement
+ //
+ if (ConfigInfo->ElementCount == 0) {
+ continue;
+ }
+
+ //
+ // 2. Get value through hii config routine protocol.
+ //
+ Status = mHiiConfigRouting->ExtractConfig (
+ mHiiConfigRouting,
+ ConfigInfo->ConfigRequest,
+ &Progress,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
+ // Get the default configuration string according to the default ID.
+ //
+ Status = mHiiConfigRouting->GetAltConfig (
+ mHiiConfigRouting,
+ Result,
+ &Storage->Guid,
+ Storage->Name,
+ NULL,
+ &DefaultId, // it can be NULL to get the current setting.
+ &ConfigResp
+ );
+ FreePool (Result);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ConfigInfo->ConfigAltResp = ConfigResp;
+ }
+}
+
+/**
+ Clean AltCfg string for current form.
+
+ @param Form Form data structure.
+
+**/
+VOID
+CleanAltCfgForForm (
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
+
+ Link = GetFirstNode (&Form->ConfigRequestHead);
+ while (!IsNull (&Form->ConfigRequestHead, Link)) {
+ ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
+ Link = GetNextNode (&Form->ConfigRequestHead, Link);
+
+ if (ConfigInfo->ConfigAltResp != NULL) {
+ FreePool (ConfigInfo->ConfigAltResp);
+ ConfigInfo->ConfigAltResp = NULL;
+ }
+ }
+}
+
+/**
+ Get AltCfg string for current formset.
+
+ @param FormSet Form data structure.
+ @param DefaultId The Class of the default.
+ @param BrowserStorage The input request storage for the questions.
+
+**/
+VOID
+ExtractAltCfgForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT16 DefaultId,
+ IN BROWSER_STORAGE *BrowserStorage
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ CHAR16 *ConfigResp;
+ CHAR16 *Progress;
+ CHAR16 *Result;
+ BROWSER_STORAGE *Storage;
+ FORMSET_STORAGE *FormSetStorage;
+
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Storage = FormSetStorage->BrowserStorage;
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (BrowserStorage != NULL && BrowserStorage != Storage) {
+ continue;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
+ continue;
+ }
+
+ //
+ // 1. Skip if there is no RequestElement
+ //
+ if (FormSetStorage->ElementCount == 0) {
+ continue;
+ }
+
+ FormSetStorage->HasCallAltCfg = TRUE;
+
+ //
+ // 2. Get value through hii config routine protocol.
+ //
+ Status = mHiiConfigRouting->ExtractConfig (
+ mHiiConfigRouting,
+ FormSetStorage->ConfigRequest,
+ &Progress,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
+ // Get the default configuration string according to the default ID.
+ //
+ Status = mHiiConfigRouting->GetAltConfig (
+ mHiiConfigRouting,
+ Result,
+ &Storage->Guid,
+ Storage->Name,
+ NULL,
+ &DefaultId, // it can be NULL to get the current setting.
+ &ConfigResp
+ );
+
+ FreePool (Result);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ FormSetStorage->ConfigAltResp = ConfigResp;
+ }
+
+}
+
+/**
+ Clean AltCfg string for current formset.
+
+ @param FormSet Form data structure.
+
+**/
+VOID
+CleanAltCfgForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *FormSetStorage;
+
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (FormSetStorage->ConfigAltResp != NULL) {
+ FreePool (FormSetStorage->ConfigAltResp);
+ FormSetStorage->ConfigAltResp = NULL;
+ }
+
+ FormSetStorage->HasCallAltCfg = FALSE;
+ }
+}
+
+/**
+ Reset Questions to their initial value or default value in a Form, Formset or System.
+
+ GetDefaultValueScope parameter decides which questions will reset
+ to its default value.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The Class of the default.
+ @param SettingScope Setting Scope for Default action.
+ @param GetDefaultValueScope Get default value scope.
+ @param Storage Get default value only for this storage.
+ @param RetrieveValueFirst Whether call the retrieve call back to
+ get the initial value before get default
+ value.
+ @param SkipGetAltCfg Whether skip the get altcfg string process.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN BROWSER_SETTING_SCOPE SettingScope,
+ IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
+ IN BROWSER_STORAGE *Storage OPTIONAL,
+ IN BOOLEAN RetrieveValueFirst,
+ IN BOOLEAN SkipGetAltCfg
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *FormLink;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_FORMSET *LocalFormSet;
+ FORM_BROWSER_FORMSET *OldFormSet;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Check the supported setting level.
+ //
+ if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (SettingScope == FormLevel) {
+ //
+ // Prepare the AltCfg String for form.
+ //
+ if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
+ ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
+ }
+
+ //
+ // Extract Form default
+ //
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+
+ //
+ // If get default value only for this storage, check the storage first.
+ //
+ if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
+ continue;
+ }
+
+ //
+ // If get default value only for no storage question, just skip the question which has storage.
+ //
+ if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
+ continue;
+ }
+
+ //
+ // If Question is disabled, don't reset it to default
+ //
+ if (Question->Expression != NULL) {
+ if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
+ continue;
+ }
+ }
+
+ if (RetrieveValueFirst) {
+ //
+ // Call the Retrieve call back to get the initial question value.
+ //
+ Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
+ }
+
+ //
+ // If not request to get the initial value or get initial value fail, then get default value.
+ //
+ if (!RetrieveValueFirst || EFI_ERROR (Status)) {
+ Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+
+ //
+ // Synchronize Buffer storage's Edit buffer
+ //
+ if ((Question->Storage != NULL) &&
+ (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
+ SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+ }
+ }
+
+ //
+ // Clean the AltCfg String.
+ //
+ if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
+ CleanAltCfgForForm(Form);
+ }
+ } else if (SettingScope == FormSetLevel) {
+ //
+ // Prepare the AltCfg String for formset.
+ //
+ if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
+ ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
+ }
+
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+
+ //
+ // Clean the AltCfg String.
+ //
+ if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
+ CleanAltCfgForFormSet (FormSet);
+ }
+ } else if (SettingScope == SystemLevel) {
+ //
+ // Preload all Hii formset.
+ //
+ LoadAllHiiFormset();
+
+ OldFormSet = mSystemLevelFormSet;
+
+ //
+ // Set Default Value for each FormSet in the maintain list.
+ //
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(LocalFormSet)) {
+ continue;
+ }
+
+ mSystemLevelFormSet = LocalFormSet;
+
+ ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
+ }
+
+ mSystemLevelFormSet = OldFormSet;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Validate whether this question's value has changed.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval TRUE Question's value has changed.
+ @retval FALSE Question's value has not changed
+
+**/
+BOOLEAN
+IsQuestionValueChanged (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ )
+{
+ EFI_HII_VALUE BackUpValue;
+ CHAR8 *BackUpBuffer;
+ EFI_HII_VALUE BackUpValue2;
+ CHAR8 *BackUpBuffer2;
+ EFI_STATUS Status;
+ BOOLEAN ValueChanged;
+ UINTN BufferWidth;
+
+ //
+ // For quetion without storage, always mark it as data not changed.
+ //
+ if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
+ return FALSE;
+ }
+
+ BackUpBuffer = NULL;
+ BackUpBuffer2 = NULL;
+ ValueChanged = FALSE;
+
+ switch (Question->Operand) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ BufferWidth = Question->StorageWidth;
+ BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ break;
+
+ case EFI_IFR_STRING_OP:
+ case EFI_IFR_PASSWORD_OP:
+ BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
+ BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer != NULL);
+ break;
+
+ default:
+ BufferWidth = 0;
+ break;
+ }
+ CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
+
+ if (GetValueFrom == GetSetValueWithBothBuffer) {
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+ ASSERT_EFI_ERROR(Status);
+
+ switch (Question->Operand) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ BufferWidth = Question->StorageWidth;
+ BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer2 != NULL);
+ break;
+
+ case EFI_IFR_STRING_OP:
+ case EFI_IFR_PASSWORD_OP:
+ BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
+ BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
+ ASSERT (BackUpBuffer2 != NULL);
+ break;
+
+ default:
+ BufferWidth = 0;
+ break;
+ }
+ CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
+
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
+ ASSERT_EFI_ERROR(Status);
+
+ if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
+ CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
+ ValueChanged = TRUE;
+ }
+ } else {
+ Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
+ ASSERT_EFI_ERROR(Status);
+
+ if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
+ CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
+ ValueChanged = TRUE;
+ }
+ }
+
+ CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
+ if (BackUpBuffer != NULL) {
+ CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
+ FreePool (BackUpBuffer);
+ }
+
+ if (BackUpBuffer2 != NULL) {
+ FreePool (BackUpBuffer2);
+ }
+
+ Question->ValueChanged = ValueChanged;
+
+ return ValueChanged;
+}
+
+/**
+ Initialize Question's Edit copy from Storage.
+
+ @param Selection Selection contains the information about
+ the Selection, form and formset to be displayed.
+ Selection action may be updated in retrieve callback.
+ If Selection is NULL, only initialize Question value.
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+LoadFormConfig (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ //
+ // Initialize local copy of Value for each Question
+ //
+ if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
+ } else {
+ Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
+ HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize Question's Edit copy from Storage for the whole Formset.
+
+ @param Selection Selection contains the information about
+ the Selection, form and formset to be displayed.
+ Selection action may be updated in retrieve callback.
+ If Selection is NULL, only initialize Question value.
+ @param FormSet FormSet data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+LoadFormSetConfig (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORM *Form;
+
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ //
+ // Initialize local copy of Value for each Form
+ //
+ Status = LoadFormConfig (Selection, FormSet, Form);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ //
+ // Finished question initialization.
+ //
+ FormSet->QuestionInited = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove the Request element from the Config Request.
+
+ @param Storage Pointer to the browser storage.
+ @param RequestElement The pointer to the Request element.
+
+**/
+VOID
+RemoveElement (
+ IN OUT BROWSER_STORAGE *Storage,
+ IN CHAR16 *RequestElement
+ )
+{
+ CHAR16 *NewStr;
+ CHAR16 *DestStr;
+
+ ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
+
+ NewStr = StrStr (Storage->ConfigRequest, RequestElement);
+
+ if (NewStr == NULL) {
+ return;
+ }
+
+ //
+ // Remove this element from this ConfigRequest.
+ //
+ DestStr = NewStr;
+ NewStr += StrLen (RequestElement);
+ CopyMem (DestStr, NewStr, StrSize (NewStr));
+
+ Storage->SpareStrLen += StrLen (RequestElement);
+}
+
+/**
+ Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
+
+ @param Storage Pointer to the formset storage.
+ @param ConfigRequest The pointer to the Request element.
+
+**/
+VOID
+RemoveConfigRequest (
+ FORMSET_STORAGE *Storage,
+ CHAR16 *ConfigRequest
+ )
+{
+ CHAR16 *RequestElement;
+ CHAR16 *NextRequestElement;
+ CHAR16 *SearchKey;
+
+ //
+ // No request element in it, just return.
+ //
+ if (ConfigRequest == NULL) {
+ return;
+ }
+
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
+ //
+ SearchKey = L"&";
+ } else {
+ //
+ // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
+ //
+ SearchKey = L"&OFFSET";
+ }
+
+ //
+ // Find SearchKey storage
+ //
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ RequestElement = StrStr (ConfigRequest, L"PATH");
+ ASSERT (RequestElement != NULL);
+ RequestElement = StrStr (RequestElement, SearchKey);
+ } else {
+ RequestElement = StrStr (ConfigRequest, SearchKey);
+ }
+
+ while (RequestElement != NULL) {
+ //
+ // +1 to avoid find header itself.
+ //
+ NextRequestElement = StrStr (RequestElement + 1, SearchKey);
+
+ //
+ // The last Request element in configRequest string.
+ //
+ if (NextRequestElement != NULL) {
+ //
+ // Replace "&" with '\0'.
+ //
+ *NextRequestElement = L'\0';
+ }
+
+ RemoveElement (Storage->BrowserStorage, RequestElement);
+
+ if (NextRequestElement != NULL) {
+ //
+ // Restore '&' with '\0' for later used.
+ //
+ *NextRequestElement = L'&';
+ }
+
+ RequestElement = NextRequestElement;
+ }
+
+ //
+ // If no request element remain, just remove the ConfigRequest string.
+ //
+ if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
+ FreePool (Storage->BrowserStorage->ConfigRequest);
+ Storage->BrowserStorage->ConfigRequest = NULL;
+ Storage->BrowserStorage->SpareStrLen = 0;
+ }
+}
+
+/**
+ Base on the current formset info, clean the ConfigRequest string in browser storage.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+CleanBrowserStorage (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+
+ if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
+ if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
+ continue;
+ }
+
+ RemoveConfigRequest (Storage, Storage->ConfigRequest);
+ } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
+ Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ if (Storage->BrowserStorage->ConfigRequest != NULL) {
+ FreePool (Storage->BrowserStorage->ConfigRequest);
+ Storage->BrowserStorage->ConfigRequest = NULL;
+ }
+ Storage->BrowserStorage->Initialized = FALSE;
+ }
+ }
+}
+
+/**
+ Check whether current element in the ConfigReqeust string.
+
+ @param BrowserStorage Storage which includes ConfigReqeust.
+ @param RequestElement New element need to check.
+
+ @retval TRUE The Element is in the ConfigReqeust string.
+ @retval FALSE The Element not in the configReqeust String.
+
+**/
+BOOLEAN
+ElementValidation (
+ BROWSER_STORAGE *BrowserStorage,
+ CHAR16 *RequestElement
+ )
+{
+ return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
+}
+
+/**
+ Append the Request element to the Config Request.
+
+ @param ConfigRequest Current ConfigRequest info.
+ @param SpareStrLen Current remain free buffer for config reqeust.
+ @param RequestElement New Request element.
+
+**/
+VOID
+AppendConfigRequest (
+ IN OUT CHAR16 **ConfigRequest,
+ IN OUT UINTN *SpareStrLen,
+ IN CHAR16 *RequestElement
+ )
+{
+ CHAR16 *NewStr;
+ UINTN StringSize;
+ UINTN StrLength;
+ UINTN MaxLen;
+
+ StrLength = StrLen (RequestElement);
+ StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
+ MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen;
+
+ //
+ // Append <RequestElement> to <ConfigRequest>
+ //
+ if (StrLength > *SpareStrLen) {
+ //
+ // Old String buffer is not sufficient for RequestElement, allocate a new one
+ //
+ MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
+ NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (NewStr != NULL);
+
+ if (*ConfigRequest != NULL) {
+ CopyMem (NewStr, *ConfigRequest, StringSize);
+ FreePool (*ConfigRequest);
+ }
+ *ConfigRequest = NewStr;
+ *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
+ }
+
+ StrCatS (*ConfigRequest, MaxLen, RequestElement);
+ *SpareStrLen -= StrLength;
+}
+
+/**
+ Adjust the config request info, remove the request elements which already in AllConfigRequest string.
+
+ @param Storage Form set Storage.
+ @param Request The input request string.
+ @param RespString Whether the input is ConfigRequest or ConfigResp format.
+
+ @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
+ @retval FALSE All elements covered by current used elements.
+
+**/
+BOOLEAN
+ConfigRequestAdjust (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Request,
+ IN BOOLEAN RespString
+ )
+{
+ CHAR16 *RequestElement;
+ CHAR16 *NextRequestElement;
+ CHAR16 *NextElementBakup;
+ CHAR16 *SearchKey;
+ CHAR16 *ValueKey;
+ BOOLEAN RetVal;
+ CHAR16 *ConfigRequest;
+
+ RetVal = FALSE;
+ NextElementBakup = NULL;
+ ValueKey = NULL;
+
+ if (Request != NULL) {
+ ConfigRequest = Request;
+ } else {
+ ConfigRequest = Storage->ConfigRequest;
+ }
+
+ if (Storage->ConfigRequest == NULL) {
+ Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
+ return TRUE;
+ }
+
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
+ //
+ SearchKey = L"&";
+ } else {
+ //
+ // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
+ //
+ SearchKey = L"&OFFSET";
+ ValueKey = L"&VALUE";
+ }
+
+ //
+ // Find SearchKey storage
+ //
+ if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ RequestElement = StrStr (ConfigRequest, L"PATH");
+ ASSERT (RequestElement != NULL);
+ RequestElement = StrStr (RequestElement, SearchKey);
+ } else {
+ RequestElement = StrStr (ConfigRequest, SearchKey);
+ }
+
+ while (RequestElement != NULL) {
+
+ //
+ // +1 to avoid find header itself.
+ //
+ NextRequestElement = StrStr (RequestElement + 1, SearchKey);
+
+ //
+ // The last Request element in configRequest string.
+ //
+ if (NextRequestElement != NULL) {
+ if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ NextElementBakup = NextRequestElement;
+ NextRequestElement = StrStr (RequestElement, ValueKey);
+ ASSERT (NextRequestElement != NULL);
+ }
+ //
+ // Replace "&" with '\0'.
+ //
+ *NextRequestElement = L'\0';
+ } else {
+ if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ NextElementBakup = NextRequestElement;
+ NextRequestElement = StrStr (RequestElement, ValueKey);
+ ASSERT (NextRequestElement != NULL);
+ //
+ // Replace "&" with '\0'.
+ //
+ *NextRequestElement = L'\0';
+ }
+ }
+
+ if (!ElementValidation (Storage, RequestElement)) {
+ //
+ // Add this element to the Storage->BrowserStorage->AllRequestElement.
+ //
+ AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
+ RetVal = TRUE;
+ }
+
+ if (NextRequestElement != NULL) {
+ //
+ // Restore '&' with '\0' for later used.
+ //
+ *NextRequestElement = L'&';
+ }
+
+ if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
+ RequestElement = NextElementBakup;
+ } else {
+ RequestElement = NextRequestElement;
+ }
+ }
+
+ return RetVal;
+}
+
+/**
+ Fill storage's edit copy with settings requested from Configuration Driver.
+
+ @param FormSet FormSet data structure.
+ @param Storage Buffer Storage.
+
+**/
+VOID
+LoadStorage (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING Progress;
+ EFI_STRING Result;
+ CHAR16 *StrPtr;
+ EFI_STRING ConfigRequest;
+ UINTN StrLen;
+
+ ConfigRequest = NULL;
+
+ switch (Storage->BrowserStorage->Type) {
+ case EFI_HII_VARSTORE_EFI_VARIABLE:
+ return;
+
+ case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
+ if (Storage->BrowserStorage->ConfigRequest != NULL) {
+ ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
+ return;
+ }
+ break;
+
+ case EFI_HII_VARSTORE_BUFFER:
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ //
+ // Skip if there is no RequestElement.
+ //
+ if (Storage->ElementCount == 0) {
+ return;
+ }
+
+ //
+ // Just update the ConfigRequest, if storage already initialized.
+ //
+ if (Storage->BrowserStorage->Initialized) {
+ ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
+ return;
+ }
+
+ Storage->BrowserStorage->Initialized = TRUE;
+ break;
+
+ default:
+ return;
+ }
+
+ if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
+ //
+ // Create the config request string to get all fields for this storage.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
+ //
+ StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (StrLen);
+ ASSERT (ConfigRequest != NULL);
+ UnicodeSPrint (
+ ConfigRequest,
+ StrLen,
+ L"%s&OFFSET=0&WIDTH=%04x",
+ Storage->ConfigHdr,
+ Storage->BrowserStorage->Size);
+ } else {
+ ConfigRequest = Storage->ConfigRequest;
+ }
+
+ //
+ // Request current settings from Configuration Driver
+ //
+ Status = mHiiConfigRouting->ExtractConfig (
+ mHiiConfigRouting,
+ ConfigRequest,
+ &Progress,
+ &Result
+ );
+
+ //
+ // If get value fail, extract default from IFR binary
+ //
+ if (EFI_ERROR (Status)) {
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
+ } else {
+ //
+ // Convert Result from <ConfigAltResp> to <ConfigResp>
+ //
+ StrPtr = StrStr (Result, L"&GUID=");
+ if (StrPtr != NULL) {
+ *StrPtr = L'\0';
+ }
+
+ Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
+ FreePool (Result);
+ }
+
+ Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
+
+ //
+ // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
+ //
+ SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
+
+ if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
+ if (ConfigRequest != NULL) {
+ FreePool (ConfigRequest);
+ }
+ }
+}
+
+/**
+ Get Value changed status from old question.
+
+ @param NewFormSet FormSet data structure.
+ @param OldQuestion Old question which has value changed.
+
+**/
+VOID
+SyncStatusForQuestion (
+ IN OUT FORM_BROWSER_FORMSET *NewFormSet,
+ IN FORM_BROWSER_STATEMENT *OldQuestion
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *QuestionLink;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Question;
+
+ //
+ // For each form in one formset.
+ //
+ Link = GetFirstNode (&NewFormSet->FormListHead);
+ while (!IsNull (&NewFormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&NewFormSet->FormListHead, Link);
+
+ //
+ // for each question in one form.
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+
+ if (Question->QuestionId == OldQuestion->QuestionId) {
+ Question->ValueChanged = TRUE;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ Get Value changed status from old formset.
+
+ @param NewFormSet FormSet data structure.
+ @param OldFormSet FormSet data structure.
+
+**/
+VOID
+SyncStatusForFormSet (
+ IN OUT FORM_BROWSER_FORMSET *NewFormSet,
+ IN FORM_BROWSER_FORMSET *OldFormSet
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *QuestionLink;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Question;
+
+ //
+ // For each form in one formset.
+ //
+ Link = GetFirstNode (&OldFormSet->FormListHead);
+ while (!IsNull (&OldFormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ Link = GetNextNode (&OldFormSet->FormListHead, Link);
+
+ //
+ // for each question in one form.
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+
+ if (!Question->ValueChanged) {
+ continue;
+ }
+
+ //
+ // Find the same question in new formset and update the value changed flag.
+ //
+ SyncStatusForQuestion (NewFormSet, Question);
+ }
+ }
+}
+
+/**
+ Get current setting of Questions.
+
+ @param FormSet FormSet data structure.
+
+**/
+VOID
+InitializeCurrentSetting (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ FORM_BROWSER_FORMSET *OldFormSet;
+
+ //
+ // Try to find pre FormSet in the maintain backup list.
+ // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
+ //
+ OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
+ if (OldFormSet != NULL) {
+ SyncStatusForFormSet (FormSet, OldFormSet);
+ RemoveEntryList (&OldFormSet->Link);
+ DestroyFormSet (OldFormSet);
+ }
+ InsertTailList (&gBrowserFormSetList, &FormSet->Link);
+
+ //
+ // Extract default from IFR binary for no storage questions.
+ //
+ ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
+
+ //
+ // Request current settings from Configuration Driver
+ //
+ Link = GetFirstNode (&FormSet->StorageListHead);
+ while (!IsNull (&FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ LoadStorage (FormSet, Storage);
+
+ Link = GetNextNode (&FormSet->StorageListHead, Link);
+ }
+}
+
+
+/**
+ Fetch the Ifr binary data of a FormSet.
+
+ @param Handle PackageList Handle
+ @param FormSetGuid On input, GUID or class GUID of a formset. If not
+ specified (NULL or zero GUID), take the first
+ FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
+ found in package list.
+ On output, GUID of the formset found(if not NULL).
+ @param BinaryLength The length of the FormSet IFR binary.
+ @param BinaryData The buffer designed to receive the FormSet.
+
+ @retval EFI_SUCCESS Buffer filled with the requested FormSet.
+ BufferLength was updated.
+ @retval EFI_INVALID_PARAMETER The handle is unknown.
+ @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
+ be found with the requested FormId.
+
+**/
+EFI_STATUS
+GetIfrBinaryData (
+ IN EFI_HII_HANDLE Handle,
+ IN OUT EFI_GUID *FormSetGuid,
+ OUT UINTN *BinaryLength,
+ OUT UINT8 **BinaryData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN BufferSize;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ UINT32 Offset;
+ UINT32 Offset2;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT8 Index;
+ UINT8 NumberOfClassGuid;
+ BOOLEAN ClassGuidMatch;
+ EFI_GUID *ClassGuid;
+ EFI_GUID *ComparingGuid;
+
+ OpCodeData = NULL;
+ Package = NULL;
+ ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
+ //
+ if (FormSetGuid == NULL) {
+ ComparingGuid = &gZeroGuid;
+ } else {
+ ComparingGuid = FormSetGuid;
+ }
+
+ //
+ // Get HII PackageList
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (HiiPackageList != NULL);
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ Offset2 = 0;
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
+
+ ClassGuidMatch = FALSE;
+ while (Offset < PackageListLength) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Search FormSet in this Form Package
+ //
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset2 < PackageHeader.Length) {
+ OpCodeData = Package + Offset2;
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
+ //
+ // Try to compare against formset GUID
+ //
+ if (IsZeroGuid (ComparingGuid) ||
+ CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
+ break;
+ }
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+ //
+ // Try to compare against formset class GUID
+ //
+ NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
+ for (Index = 0; Index < NumberOfClassGuid; Index++) {
+ if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
+ ClassGuidMatch = TRUE;
+ break;
+ }
+ }
+ if (ClassGuidMatch) {
+ break;
+ }
+ } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
+ ClassGuidMatch = TRUE;
+ break;
+ }
+ }
+
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ }
+
+ if (Offset2 < PackageHeader.Length) {
+ //
+ // Target formset found
+ //
+ break;
+ }
+ }
+
+ Offset += PackageHeader.Length;
+ }
+
+ if (Offset >= PackageListLength) {
+ //
+ // Form package not found in this Package List
+ //
+ FreePool (HiiPackageList);
+ return EFI_NOT_FOUND;
+ }
+
+ if (FormSetGuid != NULL) {
+ //
+ // Return the FormSet GUID
+ //
+ CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+
+ //
+ // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
+ // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
+ // of the Form Package.
+ //
+ *BinaryLength = PackageHeader.Length - Offset2;
+ *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
+
+ FreePool (HiiPackageList);
+
+ if (*BinaryData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize the internal data structure of a FormSet.
+
+ @param Handle PackageList Handle
+ @param FormSetGuid On input, GUID or class GUID of a formset. If not
+ specified (NULL or zero GUID), take the first
+ FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
+ found in package list.
+ On output, GUID of the formset found(if not NULL).
+ @param FormSet FormSet data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The specified FormSet could not be found.
+
+**/
+EFI_STATUS
+InitializeFormSet (
+ IN EFI_HII_HANDLE Handle,
+ IN OUT EFI_GUID *FormSetGuid,
+ OUT FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
+ FormSet->HiiHandle = Handle;
+ CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
+ FormSet->QuestionInited = FALSE;
+
+ //
+ // Retrieve ConfigAccess Protocol associated with this HiiPackageList
+ //
+ Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ FormSet->DriverHandle = DriverHandle;
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &FormSet->ConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Configuration Driver don't attach ConfigAccess protocol to its HII package
+ // list, then there will be no configuration action required
+ //
+ FormSet->ConfigAccess = NULL;
+ }
+
+ //
+ // Parse the IFR binary OpCodes
+ //
+ Status = ParseOpCodes (FormSet);
+
+ return Status;
+}
+
+
+/**
+ Save globals used by previous call to SendForm(). SendForm() may be called from
+ HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
+ So, save globals of previous call to SendForm() and restore them upon exit.
+
+**/
+VOID
+SaveBrowserContext (
+ VOID
+ )
+{
+ BROWSER_CONTEXT *Context;
+ FORM_ENTRY_INFO *MenuList;
+ FORM_BROWSER_FORMSET *FormSet;
+
+ gBrowserContextCount++;
+ if (gBrowserContextCount == 1) {
+ //
+ // This is not reentry of SendForm(), no context to save
+ //
+ return;
+ }
+
+ Context = AllocatePool (sizeof (BROWSER_CONTEXT));
+ ASSERT (Context != NULL);
+
+ Context->Signature = BROWSER_CONTEXT_SIGNATURE;
+
+ //
+ // Save FormBrowser context
+ //
+ Context->Selection = gCurrentSelection;
+ Context->ResetRequired = gResetRequiredFormLevel;
+ Context->FlagReconnect = gFlagReconnect;
+ Context->CallbackReconnect = gCallbackReconnect;
+ Context->ExitRequired = gExitRequired;
+ Context->HiiHandle = mCurrentHiiHandle;
+ Context->FormId = mCurrentFormId;
+ CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
+ Context->SystemLevelFormSet = mSystemLevelFormSet;
+ Context->CurFakeQestId = mCurFakeQestId;
+ Context->HiiPackageListUpdated = mHiiPackageListUpdated;
+ Context->FinishRetrieveCall = mFinishRetrieveCall;
+
+ //
+ // Save the menu history data.
+ //
+ InitializeListHead(&Context->FormHistoryList);
+ while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ InsertTailList(&Context->FormHistoryList, &MenuList->Link);
+ }
+
+ //
+ // Save formset list.
+ //
+ InitializeListHead(&Context->FormSetList);
+ while (!IsListEmpty (&gBrowserFormSetList)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
+ RemoveEntryList (&FormSet->Link);
+
+ InsertTailList(&Context->FormSetList, &FormSet->Link);
+ }
+
+ //
+ // Insert to FormBrowser context list
+ //
+ InsertHeadList (&gBrowserContextList, &Context->Link);
+}
+
+
+/**
+ Restore globals used by previous call to SendForm().
+
+**/
+VOID
+RestoreBrowserContext (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_CONTEXT *Context;
+ FORM_ENTRY_INFO *MenuList;
+ FORM_BROWSER_FORMSET *FormSet;
+
+ ASSERT (gBrowserContextCount != 0);
+ gBrowserContextCount--;
+ if (gBrowserContextCount == 0) {
+ //
+ // This is not reentry of SendForm(), no context to restore
+ //
+ return;
+ }
+
+ ASSERT (!IsListEmpty (&gBrowserContextList));
+
+ Link = GetFirstNode (&gBrowserContextList);
+ Context = BROWSER_CONTEXT_FROM_LINK (Link);
+
+ //
+ // Restore FormBrowser context
+ //
+ gCurrentSelection = Context->Selection;
+ gResetRequiredFormLevel = Context->ResetRequired;
+ gFlagReconnect = Context->FlagReconnect;
+ gCallbackReconnect = Context->CallbackReconnect;
+ gExitRequired = Context->ExitRequired;
+ mCurrentHiiHandle = Context->HiiHandle;
+ mCurrentFormId = Context->FormId;
+ CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
+ mSystemLevelFormSet = Context->SystemLevelFormSet;
+ mCurFakeQestId = Context->CurFakeQestId;
+ mHiiPackageListUpdated = Context->HiiPackageListUpdated;
+ mFinishRetrieveCall = Context->FinishRetrieveCall;
+
+ //
+ // Restore the menu history data.
+ //
+ while (!IsListEmpty (&Context->FormHistoryList)) {
+ MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
+ RemoveEntryList (&MenuList->Link);
+
+ InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
+ }
+
+ //
+ // Restore the Formset data.
+ //
+ while (!IsListEmpty (&Context->FormSetList)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
+ RemoveEntryList (&FormSet->Link);
+
+ InsertTailList(&gBrowserFormSetList, &FormSet->Link);
+ }
+
+ //
+ // Remove from FormBrowser context list
+ //
+ RemoveEntryList (&Context->Link);
+ gBS->FreePool (Context);
+}
+
+/**
+ Find the matched FormSet context in the backup maintain list based on HiiHandle.
+
+ @param Handle The Hii Handle.
+
+ @return the found FormSet context. If no found, NULL will return.
+
+**/
+FORM_BROWSER_FORMSET *
+GetFormSetFromHiiHandle (
+ EFI_HII_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(FormSet)) {
+ continue;
+ }
+ if (FormSet->HiiHandle == Handle) {
+ return FormSet;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Check whether the input HII handle is the FormSet that is being used.
+
+ @param Handle The Hii Handle.
+
+ @retval TRUE HII handle is being used.
+ @retval FALSE HII handle is not being used.
+
+**/
+BOOLEAN
+IsHiiHandleInBrowserContext (
+ EFI_HII_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_CONTEXT *Context;
+
+ //
+ // HiiHandle is Current FormSet.
+ //
+ if (mCurrentHiiHandle == Handle) {
+ return TRUE;
+ }
+
+ //
+ // Check whether HiiHandle is in BrowserContext.
+ //
+ Link = GetFirstNode (&gBrowserContextList);
+ while (!IsNull (&gBrowserContextList, Link)) {
+ Context = BROWSER_CONTEXT_FROM_LINK (Link);
+ if (Context->HiiHandle == Handle) {
+ //
+ // HiiHandle is in BrowserContext
+ //
+ return TRUE;
+ }
+ Link = GetNextNode (&gBrowserContextList, Link);
+ }
+
+ return FALSE;
+}
+
+/**
+ Perform Password check.
+ Passwork may be encrypted by driver that requires the specific check.
+
+ @param Form Form where Password Statement is in.
+ @param Statement Password statement
+ @param PasswordString Password string to be checked. It may be NULL.
+ NULL means to restore password.
+ "" string can be used to checked whether old password does exist.
+
+ @return Status Status of Password check.
+**/
+EFI_STATUS
+EFIAPI
+PasswordCheck (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_STRING PasswordString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_IFR_TYPE_VALUE IfrTypeValue;
+ FORM_BROWSER_STATEMENT *Question;
+
+ ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
+ Question = GetBrowserStatement(Statement);
+ ASSERT (Question != NULL);
+
+ if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
+ if (ConfigAccess == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // If a password doesn't have the CALLBACK flag, browser will not handle it.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Prepare password string in HII database
+ //
+ if (PasswordString != NULL) {
+ IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
+ } else {
+ IfrTypeValue.string = 0;
+ }
+
+ //
+ // Send password to Configuration Driver for validation
+ //
+ Status = ConfigAccess->Callback (
+ ConfigAccess,
+ EFI_BROWSER_ACTION_CHANGING,
+ Question->QuestionId,
+ Question->HiiValue.Type,
+ &IfrTypeValue,
+ &ActionRequest
+ );
+
+ //
+ // Remove password string from HII database
+ //
+ if (PasswordString != NULL) {
+ DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
+ }
+
+ return Status;
+}
+
+/**
+ Find the registered HotKey based on KeyData.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key.
+
+ @return The registered HotKey context. If no found, NULL will return.
+**/
+BROWSER_HOT_KEY *
+GetHotKeyFromRegisterList (
+ IN EFI_INPUT_KEY *KeyData
+ )
+{
+ LIST_ENTRY *Link;
+ BROWSER_HOT_KEY *HotKey;
+
+ Link = GetFirstNode (&gBrowserHotKeyList);
+ while (!IsNull (&gBrowserHotKeyList, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+ if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
+ return HotKey;
+ }
+ Link = GetNextNode (&gBrowserHotKeyList, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Configure what scope the hot key will impact.
+ All hot keys have the same scope. The mixed hot keys with the different level are not supported.
+ If no scope is set, the default scope will be FormSet level.
+ After all registered hot keys are removed, previous Scope can reset to another level.
+
+ @param[in] Scope Scope level to be set.
+
+ @retval EFI_SUCCESS Scope is set correctly.
+ @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
+ @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
+
+**/
+EFI_STATUS
+EFIAPI
+SetScope (
+ IN BROWSER_SETTING_SCOPE Scope
+ )
+{
+ if (Scope >= MaxLevel) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // When no hot key registered in system or on the first setting,
+ // Scope can be set.
+ //
+ if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
+ gBrowserSettingScope = Scope;
+ mBrowserScopeFirstSet = FALSE;
+ } else if (Scope != gBrowserSettingScope) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register the hot key with its browser action, or unregistered the hot key.
+ Only support hot key that is not printable character (control key, function key, etc.).
+ If the action value is zero, the hot key will be unregistered if it has been registered.
+ If the same hot key has been registered, the new action and help string will override the previous ones.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key. Its type is EFI_INPUT_KEY to
+ be supported by all ConsoleIn devices.
+ @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
+ @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
+ @param[in] HelpString Help string that describes the hot key information.
+ Its value may be NULL for the unregistered hot key.
+
+ @retval EFI_SUCCESS Hot key is registered or unregistered.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
+ @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
+ @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
+ @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHotKey (
+ IN EFI_INPUT_KEY *KeyData,
+ IN UINT32 Action,
+ IN UINT16 DefaultId,
+ IN EFI_STRING HelpString OPTIONAL
+ )
+{
+ BROWSER_HOT_KEY *HotKey;
+
+ //
+ // Check input parameters.
+ //
+ if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
+ (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the input KeyData is in BrowserHotKeyList.
+ //
+ HotKey = GetHotKeyFromRegisterList (KeyData);
+
+ //
+ // Unregister HotKey
+ //
+ if (Action == BROWSER_ACTION_UNREGISTER) {
+ if (HotKey != NULL) {
+ //
+ // The registered HotKey is found.
+ // Remove it from List, and free its resource.
+ //
+ RemoveEntryList (&HotKey->Link);
+ FreePool (HotKey->KeyData);
+ FreePool (HotKey->HelpString);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // The registered HotKey is not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (HotKey != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create new Key, and add it into List.
+ //
+ HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
+ ASSERT (HotKey != NULL);
+ HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
+ HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
+ InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
+
+ //
+ // Fill HotKey information.
+ //
+ HotKey->Action = Action;
+ HotKey->DefaultId = DefaultId;
+ if (HotKey->HelpString != NULL) {
+ FreePool (HotKey->HelpString);
+ }
+ HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register Exit handler function.
+ When more than one handler function is registered, the latter one will override the previous one.
+ When NULL handler is specified, the previous Exit handler will be unregistered.
+
+ @param[in] Handler Pointer to handler function.
+
+**/
+VOID
+EFIAPI
+RegiserExitHandler (
+ IN EXIT_HANDLER Handler
+ )
+{
+ ExitHandlerFunction = Handler;
+ return;
+}
+
+/**
+ Check whether the browser data has been modified.
+
+ @retval TRUE Browser data is modified.
+ @retval FALSE No browser data is modified.
+
+**/
+BOOLEAN
+EFIAPI
+IsBrowserDataModified (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+
+ switch (gBrowserSettingScope) {
+ case FormLevel:
+ if (gCurrentSelection == NULL) {
+ return FALSE;
+ }
+ return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
+
+ case FormSetLevel:
+ if (gCurrentSelection == NULL) {
+ return FALSE;
+ }
+ return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
+
+ case SystemLevel:
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ if (!ValidateFormSet(FormSet)) {
+ continue;
+ }
+
+ if (IsNvUpdateRequiredForFormSet (FormSet)) {
+ return TRUE;
+ }
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ }
+ return FALSE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Execute the action requested by the Action parameter.
+
+ @param[in] Action Execute the request action.
+ @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
+
+ @retval EFI_SUCCESS Execute the request action succss.
+ @retval EFI_INVALID_PARAMETER The input action value is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+ExecuteAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ FORM_BROWSER_FORM *Form;
+
+ if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ Form = NULL;
+ if (gBrowserSettingScope < SystemLevel) {
+ FormSet = gCurrentSelection->FormSet;
+ Form = gCurrentSelection->Form;
+ }
+
+ //
+ // Executet the discard action.
+ //
+ if ((Action & BROWSER_ACTION_DISCARD) != 0) {
+ Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Executet the difault action.
+ //
+ if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
+ Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
+ }
+
+ //
+ // Executet the submit action.
+ //
+ if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
+ Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Executet the reset action.
+ //
+ if ((Action & BROWSER_ACTION_RESET) != 0) {
+ gResetRequiredFormLevel = TRUE;
+ gResetRequiredSystemLevel = TRUE;
+ }
+
+ //
+ // Executet the exit action.
+ //
+ if ((Action & BROWSER_ACTION_EXIT) != 0) {
+ DiscardForm (FormSet, Form, gBrowserSettingScope);
+ if (gBrowserSettingScope == SystemLevel) {
+ if (ExitHandlerFunction != NULL) {
+ ExitHandlerFunction ();
+ }
+ }
+
+ gExitRequired = TRUE;
+ }
+
+ return Status;
+}
+
+/**
+ Create reminder to let user to choose save or discard the changed browser data.
+ Caller can use it to actively check the changed browser data.
+
+ @retval BROWSER_NO_CHANGES No browser data is changed.
+ @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
+ @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
+ @retval BROWSER_KEEP_CURRENT Browser keep current changes.
+
+**/
+UINT32
+EFIAPI
+SaveReminder (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+ BOOLEAN IsDataChanged;
+ UINT32 DataSavedAction;
+ UINT32 ConfirmRet;
+
+ DataSavedAction = BROWSER_NO_CHANGES;
+ IsDataChanged = FALSE;
+ Link = GetFirstNode (&gBrowserFormSetList);
+ while (!IsNull (&gBrowserFormSetList, Link)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ Link = GetNextNode (&gBrowserFormSetList, Link);
+ if (!ValidateFormSet(FormSet)) {
+ continue;
+ }
+ if (IsNvUpdateRequiredForFormSet (FormSet)) {
+ IsDataChanged = TRUE;
+ break;
+ }
+ }
+
+ //
+ // No data is changed. No save is required.
+ //
+ if (!IsDataChanged) {
+ return DataSavedAction;
+ }
+
+ //
+ // If data is changed, prompt user to save or discard it.
+ //
+ do {
+ ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
+
+ if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
+ SubmitForm (NULL, NULL, SystemLevel);
+ DataSavedAction = BROWSER_SAVE_CHANGES;
+ break;
+ } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
+ DiscardForm (NULL, NULL, SystemLevel);
+ DataSavedAction = BROWSER_DISCARD_CHANGES;
+ break;
+ } else if (ConfirmRet == BROWSER_ACTION_NONE) {
+ DataSavedAction = BROWSER_KEEP_CURRENT;
+ break;
+ }
+ } while (1);
+
+ return DataSavedAction;
+}
+
+/**
+ Check whether the Reset Required for the browser
+
+ @retval TRUE Browser required to reset after exit.
+ @retval FALSE Browser not need to reset after exit.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+ VOID
+ )
+{
+ return gResetRequiredSystemLevel;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h
new file mode 100644
index 000000000..5d46fa42e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h
@@ -0,0 +1,1875 @@
+/** @file
+Private MACRO, structure and function definitions for Setup Browser module.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _SETUP_H_
+#define _SETUP_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/FormBrowserEx2.h>
+#include <Protocol/DisplayProtocol.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/UserManager.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/RegularExpressionProtocol.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/HiiFormMapMethodGuid.h>
+#include <Guid/ZeroGuid.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+
+
+//
+// This is the generated header file which includes whatever needs to be exported (strings + IFR)
+//
+
+#define UI_ACTION_NONE 0
+#define UI_ACTION_REFRESH_FORM 1
+#define UI_ACTION_REFRESH_FORMSET 2
+#define UI_ACTION_EXIT 3
+
+//
+//
+// Time definitions
+//
+#define ONE_SECOND 10000000
+
+// Incremental string lenght of ConfigRequest
+//
+#define CONFIG_REQUEST_STRING_INCREMENTAL 1024
+
+//
+// Incremental size of stack for expression
+//
+#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
+
+#define EFI_IFR_SPECIFICATION_VERSION (UINT16) (((EFI_SYSTEM_TABLE_REVISION >> 16) << 8) | (((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) / 10) << 4) | ((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) % 10))
+
+
+#define SETUP_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'B', 'D', 'V')
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ //
+ // Produced protocol
+ //
+ EFI_FORM_BROWSER2_PROTOCOL FormBrowser2;
+ EDKII_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx;
+
+ EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2;
+
+} SETUP_DRIVER_PRIVATE_DATA;
+
+//
+// IFR relative definition
+//
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
+#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
+#define EFI_HII_EXPRESSION_DISABLE_IF 4
+#define EFI_HII_EXPRESSION_VALUE 5
+#define EFI_HII_EXPRESSION_RULE 6
+#define EFI_HII_EXPRESSION_READ 7
+#define EFI_HII_EXPRESSION_WRITE 8
+#define EFI_HII_EXPRESSION_WARNING_IF 9
+
+#define EFI_HII_VARSTORE_BUFFER 0
+#define EFI_HII_VARSTORE_NAME_VALUE 1
+#define EFI_HII_VARSTORE_EFI_VARIABLE 2 // EFI Varstore type follow UEFI spec before 2.3.1.
+#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3 // EFI varstore type follow UEFI spec 2.3.1 and later.
+
+#define FORM_INCONSISTENT_VALIDATION 0
+#define FORM_NO_SUBMIT_VALIDATION 1
+
+#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ CHAR16 *Value;
+ CHAR16 *EditValue;
+} NAME_VALUE_NODE;
+
+#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE)
+
+#define BROWSER_STORAGE_SIGNATURE SIGNATURE_32 ('B', 'S', 'T', 'G')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Type; // Storage type
+
+ BOOLEAN Initialized; // Whether this varstore is initialized, efi varstore not used.
+
+ EFI_HII_HANDLE HiiHandle; // HiiHandle for this varstore, efi varstore not used.
+ EFI_GUID Guid;
+
+ CHAR16 *Name; // For EFI_IFR_VARSTORE
+ UINT16 Size;
+ UINT8 *Buffer;
+ UINT8 *EditBuffer; // Edit copy for Buffer Storage
+
+ LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE
+
+ UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+
+ CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
+ // <RequestElement> includes all fields which is used by current form sets.
+ UINTN SpareStrLen; // Spare length of ConfigRequest string buffer
+} BROWSER_STORAGE;
+
+#define BROWSER_STORAGE_FROM_LINK(a) CR (a, BROWSER_STORAGE, Link, BROWSER_STORAGE_SIGNATURE)
+
+#define FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'G')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ LIST_ENTRY SaveFailLink;
+
+ UINT16 VarStoreId;
+
+ BROWSER_STORAGE *BrowserStorage;
+
+ CHAR16 *ConfigHdr; // <ConfigHdr>
+
+ CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
+ CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest.
+ BOOLEAN HasCallAltCfg; // Flag to show whether browser has call ExtractConfig to get Altcfg string.
+ UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest>
+ UINTN SpareStrLen; // Spare length of ConfigRequest string buffer
+ CHAR16 *RestoreConfigRequest; // When submit formset fail, the element need to be restored
+ CHAR16 *SyncConfigRequest; // When submit formset fail, the element need to be synced
+} FORMSET_STORAGE;
+
+#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE)
+#define FORMSET_STORAGE_FROM_SAVE_FAIL_LINK(a) CR (a, FORMSET_STORAGE, SaveFailLink, FORMSET_STORAGE_SIGNATURE)
+
+typedef union {
+ EFI_STRING_ID VarName;
+ UINT16 VarOffset;
+} VAR_STORE_INFO;
+
+#define EXPRESSION_OPCODE_SIGNATURE SIGNATURE_32 ('E', 'X', 'O', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Operand;
+
+ UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND
+ UINT8 Flags; // For EFI_IFR_SPAN
+ UINT8 RuleId; // For EFI_IFR_RULE_REF
+
+ EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1
+
+ EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1
+ EFI_QUESTION_ID QuestionId2;
+
+ UINT16 ListLength; // For EFI_IFR_EQ_ID_VAL_LIST
+ UINT16 *ValueList;
+
+ EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3
+ EFI_GUID Guid;
+
+ BROWSER_STORAGE *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET
+ VAR_STORE_INFO VarStoreInfo;// For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueType; // For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueWidth; // For EFI_IFR_SET, EFI_IFR_GET
+ CHAR16 *ValueName; // For EFI_IFR_SET, EFI_IFR_GET
+ LIST_ENTRY MapExpressionList; // nested expressions inside of Map opcode.
+} EXPRESSION_OPCODE;
+
+#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE)
+
+#define FORM_EXPRESSION_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Type; // Type for this expression
+
+ UINT8 RuleId; // For EFI_IFR_RULE only
+ EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only
+
+ EFI_HII_VALUE Result; // Expression evaluation result
+
+ UINT8 TimeOut; // For EFI_IFR_WARNING_IF
+ EFI_IFR_OP_HEADER *OpCode; // Save the opcode buffer.
+
+ LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE)
+} FORM_EXPRESSION;
+
+#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE)
+
+#define FORM_EXPRESSION_LIST_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'R')
+
+typedef struct {
+ UINTN Signature;
+ UINTN Count;
+ FORM_EXPRESSION *Expression[1]; // Array[Count] of expressions
+} FORM_EXPRESSION_LIST;
+
+#define QUESTION_DEFAULT_SIGNATURE SIGNATURE_32 ('Q', 'D', 'F', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_HII_VALUE Value; // Default value
+
+ FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE
+} QUESTION_DEFAULT;
+
+#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE)
+
+#define QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_IFR_ONE_OF_OPTION *OpCode; // OneOfOption Data
+
+ EFI_STRING_ID Text;
+ UINT8 Flags;
+ EFI_HII_VALUE Value;
+ EFI_IMAGE_ID ImageId;
+
+ FORM_EXPRESSION_LIST *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf
+} QUESTION_OPTION;
+
+#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE)
+
+typedef enum {
+ ExpressFalse = 0,
+ ExpressGrayOut,
+ ExpressSuppress,
+ ExpressDisable
+} EXPRESS_RESULT;
+
+typedef enum {
+ ExpressNone = 0,
+ ExpressForm,
+ ExpressStatement,
+ ExpressOption
+} EXPRESS_LEVEL;
+
+typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT;
+
+#define FORM_BROWSER_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A')
+
+struct _FORM_BROWSER_STATEMENT{
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Operand; // The operand (first byte) of this Statement or Question
+ EFI_IFR_OP_HEADER *OpCode;
+
+ //
+ // Statement Header
+ //
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+ EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT
+
+ //
+ // Fake Question Id, used for statement not has true QuestionId.
+ //
+ EFI_QUESTION_ID FakeQuestionId;
+
+ //
+ // Question Header
+ //
+ EFI_QUESTION_ID QuestionId; // The value of zero is reserved
+ EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage
+ BROWSER_STORAGE *Storage;
+ VAR_STORE_INFO VarStoreInfo;
+ UINT16 StorageWidth;
+ UINT16 BitStorageWidth;
+ UINT16 BitVarOffset;
+ UINT8 QuestionFlags;
+ BOOLEAN QuestionReferToBitField;// Whether the question is stored in a bit field.
+ CHAR16 *VariableName; // Name/Value or EFI Variable name
+ CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..."
+
+ EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof
+ UINT8 *BufferValue; // Edit copy for string, password, orderedlist
+ UINT8 ValueType; // Data type for orderedlist value array
+
+ //
+ // OpCode specific members
+ //
+ UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF,
+ // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER
+ UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST
+
+ UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number
+ EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed
+
+ UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value
+ UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length
+ UINT64 Step;
+
+ EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON
+ EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID
+ BOOLEAN Locked; // Whether this statement is locked.
+ BOOLEAN ValueChanged; // Whether this statement's value is changed.
+ //
+ // Get from IFR parsing
+ //
+ FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly
+ LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values
+ LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
+
+ EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE
+ UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh
+
+ FORM_BROWSER_STATEMENT *ParentStatement;
+
+ LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION)
+ LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION)
+ LIST_ENTRY WarningListHead; // nested warning expression list (FORM_EXPRESSION)
+ FORM_EXPRESSION_LIST *Expression; // nesting inside of GrayOutIf/DisableIf/SuppressIf
+
+ FORM_EXPRESSION *ReadExpression; // nested EFI_IFR_READ, provide this question value by read expression.
+ FORM_EXPRESSION *WriteExpression; // nested EFI_IFR_WRITE, evaluate write expression after this question value is set.
+};
+
+#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE)
+
+#define FORM_BROWSER_CONFIG_REQUEST_SIGNATURE SIGNATURE_32 ('F', 'C', 'R', 'S')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ LIST_ENTRY SaveFailLink;
+
+ CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>
+ CHAR16 *ConfigAltResp; // Alt config response string for this ConfigRequest.
+ UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest>
+ UINTN SpareStrLen;
+ CHAR16 *RestoreConfigRequest; // When submit form fail, the element need to be restored
+ CHAR16 *SyncConfigRequest; // When submit form fail, the element need to be synced
+
+ BROWSER_STORAGE *Storage;
+} FORM_BROWSER_CONFIG_REQUEST;
+#define FORM_BROWSER_CONFIG_REQUEST_FROM_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, Link, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE)
+#define FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_CONFIG_REQUEST, SaveFailLink, FORM_BROWSER_CONFIG_REQUEST_SIGNATURE)
+
+#define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M')
+#define STANDARD_MAP_FORM_TYPE 0x01
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 FormId; // FormId of normal form or formmap form.
+ EFI_STRING_ID FormTitle; // FormTile of normal form, or FormMapMethod title of formmap form.
+ UINT16 FormType; // Specific form type for the different form.
+
+ EFI_IMAGE_ID ImageId;
+
+ BOOLEAN ModalForm; // Whether this is a modal form.
+ BOOLEAN Locked; // Whether this form is locked.
+ EFI_GUID RefreshGuid; // Form refresh event guid.
+
+ LIST_ENTRY FormViewListHead; // List of type FORMID_INFO is Browser View Form History List.
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+ LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT)
+ LIST_ENTRY ConfigRequestHead; // List of configreques for all storage.
+ FORM_EXPRESSION_LIST *SuppressExpression; // nesting inside of SuppressIf
+} FORM_BROWSER_FORM;
+
+#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE)
+
+#define FORMSET_DEFAULTSTORE_SIGNATURE SIGNATURE_32 ('F', 'D', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_STRING_ID DefaultName;
+} FORMSET_DEFAULTSTORE;
+
+#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE)
+
+#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ LIST_ENTRY SaveFailLink;
+
+ EFI_HII_HANDLE HiiHandle; // unique id for formset.
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ UINTN IfrBinaryLength;
+ UINT8 *IfrBinaryData;
+
+ BOOLEAN QuestionInited; // Have finished question initilization?
+ EFI_GUID Guid;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID Help;
+ UINT8 NumberOfClassGuid;
+ EFI_GUID ClassGuid[3]; // Up to three ClassGuid
+ UINT16 Class; // Tiano extended Class code
+ UINT16 SubClass; // Tiano extended Subclass code
+ EFI_IMAGE_ID ImageId;
+ EFI_IFR_OP_HEADER *OpCode; //mainly for formset op to get ClassGuid
+
+ FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions
+ EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode
+ FORM_BROWSER_FORM *SaveFailForm; // The form which failed to save.
+ FORM_BROWSER_STATEMENT *SaveFailStatement; // The Statement which failed to save.
+
+ LIST_ENTRY StatementListOSF; // Statement list out side of the form.
+ LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE)
+ LIST_ENTRY SaveFailStorageListHead; // Storage list for the save fail storage.
+ LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
+ LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM)
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+} FORM_BROWSER_FORMSET;
+#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
+
+#define FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK(a) CR (a, FORM_BROWSER_FORMSET, SaveFailLink, FORM_BROWSER_FORMSET_SIGNATURE)
+
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_EVENT RefreshEvent;
+} FORM_BROWSER_REFRESH_EVENT_NODE;
+
+#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link)
+
+
+typedef struct {
+ EFI_HII_HANDLE Handle;
+
+ //
+ // Target formset/form/Question information
+ //
+ EFI_GUID FormSetGuid;
+ UINT16 FormId;
+ UINT16 QuestionId;
+ UINTN Sequence; // used for time/date only.
+
+ UINTN TopRow;
+ UINTN BottomRow;
+ UINTN PromptCol;
+ UINTN OptionCol;
+ UINTN CurrentRow;
+
+ //
+ // Ation for Browser to taken:
+ // UI_ACTION_NONE - navigation inside a form
+ // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form
+ // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary
+ //
+ UINTN Action;
+
+ //
+ // Current selected fomset/form/Question
+ //
+ FORM_BROWSER_FORMSET *FormSet;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ //
+ // Whether the Form is editable
+ //
+ BOOLEAN FormEditable;
+
+ FORM_ENTRY_INFO *CurrentMenu;
+} UI_MENU_SELECTION;
+
+#define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ //
+ // Globals defined in Setup.c
+ //
+ BOOLEAN FlagReconnect;
+ BOOLEAN CallbackReconnect;
+ BOOLEAN ResetRequired;
+ BOOLEAN ExitRequired;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_GUID FormSetGuid;
+ EFI_FORM_ID FormId;
+ UI_MENU_SELECTION *Selection;
+ FORM_BROWSER_FORMSET *SystemLevelFormSet;
+ EFI_QUESTION_ID CurFakeQestId;
+ BOOLEAN HiiPackageListUpdated;
+ BOOLEAN FinishRetrieveCall;
+ LIST_ENTRY FormHistoryList;
+ LIST_ENTRY FormSetList;
+} BROWSER_CONTEXT;
+
+#define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE)
+
+//
+// Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll.
+//
+typedef enum {
+ GetDefaultForNoStorage, // Get default value for question which not has storage.
+ GetDefaultForStorage, // Get default value for question which has storage.
+ GetDefaultForAll, // Get default value for all questions.
+ GetDefaultForMax // Invalid value.
+} BROWSER_GET_DEFAULT_VALUE;
+
+//
+// Get/set question value from/to.
+//
+typedef enum {
+ GetSetValueWithEditBuffer = 0, // Get/Set question value from/to editbuffer in the storage.
+ GetSetValueWithBuffer, // Get/Set question value from/to buffer in the storage.
+ GetSetValueWithHiiDriver, // Get/Set question value from/to hii driver.
+ GetSetValueWithBothBuffer, // Compare the editbuffer with buffer for this question, not use the question value.
+ GetSetValueWithMax // Invalid value.
+} GET_SET_QUESTION_VALUE_WITH;
+
+extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
+extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
+extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
+extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
+
+extern BOOLEAN gCallbackReconnect;
+extern BOOLEAN gFlagReconnect;
+extern BOOLEAN gResetRequiredFormLevel;
+extern BOOLEAN gResetRequiredSystemLevel;
+extern BOOLEAN gExitRequired;
+extern LIST_ENTRY gBrowserFormSetList;
+extern LIST_ENTRY gBrowserHotKeyList;
+extern BROWSER_SETTING_SCOPE gBrowserSettingScope;
+extern EXIT_HANDLER ExitHandlerFunction;
+extern EFI_HII_HANDLE mCurrentHiiHandle;
+extern SETUP_DRIVER_PRIVATE_DATA mPrivateData;
+//
+// Browser Global Strings
+//
+extern CHAR16 *gEmptyString;
+
+extern UI_MENU_SELECTION *gCurrentSelection;
+extern BOOLEAN mHiiPackageListUpdated;
+extern UINT16 mCurFakeQestId;
+extern BOOLEAN mFinishRetrieveCall;
+
+//
+// Global Procedure Defines
+//
+#include "Expression.h"
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeBrowserStrings (
+ VOID
+ );
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ );
+
+
+/**
+ Create a new string in HII Package List.
+
+ @param String The String to be added
+ @param HiiHandle The package list in the HII database to insert the
+ specified string.
+
+ @return The output string.
+
+**/
+EFI_STRING_ID
+NewString (
+ IN CHAR16 *String,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Delete a string from HII Package List.
+
+ @param StringId Id of the string in HII database.
+ @param HiiHandle The HII package list handle.
+
+ @retval EFI_SUCCESS The string was deleted successfully.
+
+**/
+EFI_STATUS
+DeleteString (
+ IN EFI_STRING_ID StringId,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Get Value for given Name from a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The retured Value.
+ @param GetValueFrom Where to get source value, from EditValue or Value.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+GetValueByName (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN OUT CHAR16 **Value,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ );
+
+/**
+ Set Value of given Name in a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The Value to set.
+ @param SetValueTo Whether update editValue or Value.
+ @param ReturnNode The node use the input name.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+SetValueByName (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN CHAR16 *Value,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
+ OUT NAME_VALUE_NODE **ReturnNode
+ );
+
+/**
+ Validate whether this question's value has changed.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval TRUE Question's value has changed.
+ @retval FALSE Question's value has not changed
+
+**/
+BOOLEAN
+IsQuestionValueChanged (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ );
+
+/**
+ Validate the FormSet. If the formset is not validate, remove it from the list.
+
+ @param FormSet The input FormSet which need to validate.
+
+ @retval TRUE The handle is validate.
+ @retval FALSE The handle is invalidate.
+
+**/
+BOOLEAN
+ValidateFormSet (
+ FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Update the ValueChanged status for questions.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Default action.
+
+**/
+VOID
+UpdateStatementStatus (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ );
+
+/**
+ Get Question's current Value.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Question to be initialized.
+ @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+GetQuestionValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
+ );
+
+/**
+ Save Question Value to edit copy(cached) or Storage(uncached).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question Pointer to the Question.
+ @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+SetQuestionValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN GET_SET_QUESTION_VALUE_WITH SetValueTo
+ );
+
+/**
+ Perform inconsistent check for a Form.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question The Question to be validated.
+ @param Type Validation type: InConsistent or NoSubmit
+
+ @retval EFI_SUCCESS Form validation pass.
+ @retval other Form validation failed.
+
+**/
+EFI_STATUS
+ValidateQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINTN Type
+ );
+
+
+/**
+ Discard data based on the input setting scope (Form, FormSet or System).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Discard action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+DiscardForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ );
+
+/**
+ Submit data based on the input Setting level (Form, FormSet or System).
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param SettingScope Setting Scope for Submit action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+SubmitForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ );
+
+/**
+ Reset Question to its default value.
+
+ @param FormSet The form set.
+ @param Form The form.
+ @param Question The question.
+ @param DefaultId The Class of the default.
+
+ @retval EFI_SUCCESS Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT16 DefaultId
+ );
+
+/**
+ Get current setting of Questions.
+
+ @param FormSet FormSet data structure.
+
+**/
+VOID
+InitializeCurrentSetting (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Initialize the internal data structure of a FormSet.
+
+ @param Handle PackageList Handle
+ @param FormSetGuid GUID of a formset. If not specified (NULL or zero
+ GUID), take the first FormSet found in package
+ list.
+ @param FormSet FormSet data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The specified FormSet could not be found.
+
+**/
+EFI_STATUS
+InitializeFormSet (
+ IN EFI_HII_HANDLE Handle,
+ IN OUT EFI_GUID *FormSetGuid,
+ OUT FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Reset Questions to their initial value or default value in a Form, Formset or System.
+
+ GetDefaultValueScope parameter decides which questions will reset
+ to its default value.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The Class of the default.
+ @param SettingScope Setting Scope for Default action.
+ @param GetDefaultValueScope Get default value scope.
+ @param Storage Get default value only for this storage.
+ @param RetrieveValueFirst Whether call the retrieve call back to
+ get the initial value before get default
+ value.
+ @param SkipGetAltCfg Whether skip the get altcfg string process.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN BROWSER_SETTING_SCOPE SettingScope,
+ IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
+ IN BROWSER_STORAGE *Storage,
+ IN BOOLEAN RetrieveValueFirst,
+ IN BOOLEAN SkipGetAltCfg
+ );
+
+/**
+ Initialize Question's Edit copy from Storage.
+
+ @param Selection Selection contains the information about
+ the Selection, form and formset to be displayed.
+ Selection action may be updated in retrieve callback.
+ If Selection is NULL, only initialize Question value.
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+LoadFormConfig (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ );
+
+/**
+ Initialize Question's Edit copy from Storage for the whole Formset.
+
+ @param Selection Selection contains the information about
+ the Selection, form and formset to be displayed.
+ Selection action may be updated in retrieve callback.
+ If Selection is NULL, only initialize Question value.
+ @param FormSet FormSet data structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+LoadFormSetConfig (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
+
+ @param Storage The Storage to be conveted.
+ @param ConfigResp The returned <ConfigResp>.
+ @param ConfigRequest The ConfigRequest string.
+ @param GetEditBuf Get the data from editbuffer or buffer.
+
+ @retval EFI_SUCCESS Convert success.
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.
+
+**/
+EFI_STATUS
+StorageToConfigResp (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 **ConfigResp,
+ IN CHAR16 *ConfigRequest,
+ IN BOOLEAN GetEditBuf
+ );
+
+/**
+ Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
+
+ @param Storage The Storage to receive the settings.
+ @param ConfigResp The <ConfigResp> to be converted.
+
+ @retval EFI_SUCCESS Convert success.
+ @retval EFI_INVALID_PARAMETER Incorrect storage type.
+
+**/
+EFI_STATUS
+ConfigRespToStorage (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *ConfigResp
+ );
+
+/**
+ Fill storage's edit copy with settings requested from Configuration Driver.
+
+ @param FormSet FormSet data structure.
+ @param Storage Buffer Storage.
+
+**/
+VOID
+LoadStorage (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORMSET_STORAGE *Storage
+ );
+
+/**
+ Fetch the Ifr binary data of a FormSet.
+
+ @param Handle PackageList Handle
+ @param FormSetGuid GUID of a formset. If not specified (NULL or zero
+ GUID), take the first FormSet found in package
+ list.
+ @param BinaryLength The length of the FormSet IFR binary.
+ @param BinaryData The buffer designed to receive the FormSet.
+
+ @retval EFI_SUCCESS Buffer filled with the requested FormSet.
+ BufferLength was updated.
+ @retval EFI_INVALID_PARAMETER The handle is unknown.
+ @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
+ be found with the requested FormId.
+
+**/
+EFI_STATUS
+GetIfrBinaryData (
+ IN EFI_HII_HANDLE Handle,
+ IN OUT EFI_GUID *FormSetGuid,
+ OUT UINTN *BinaryLength,
+ OUT UINT8 **BinaryData
+ );
+
+/**
+ Save globals used by previous call to SendForm(). SendForm() may be called from
+ HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
+ So, save globals of previous call to SendForm() and restore them upon exit.
+
+**/
+VOID
+SaveBrowserContext (
+ VOID
+ );
+
+/**
+ Restore globals used by previous call to SendForm().
+
+**/
+VOID
+RestoreBrowserContext (
+ VOID
+ );
+
+/**
+ This is the routine which an external caller uses to direct the browser
+ where to obtain it's information.
+
+
+ @param This The Form Browser protocol instanse.
+ @param Handles A pointer to an array of Handles. If HandleCount > 1 we
+ display a list of the formsets for the handles specified.
+ @param HandleCount The number of Handles specified in Handle.
+ @param FormSetGuid This field points to the EFI_GUID which must match the Guid
+ field in the EFI_IFR_FORM_SET op-code for the specified
+ forms-based package. If FormSetGuid is NULL, then this
+ function will display the first found forms package.
+ @param FormId This field specifies which EFI_IFR_FORM to render as the first
+ displayable page. If this field has a value of 0x0000, then
+ the forms browser will render the specified forms in their encoded order.
+ ScreenDimenions - This allows the browser to be called so that it occupies a
+ portion of the physical screen instead of dynamically determining the screen dimensions.
+ ActionRequest - Points to the action recommended by the form.
+ @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
+ characters.
+ @param ActionRequest Points to the action recommended by the form.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_NOT_FOUND No valid forms could be found to display.
+
+**/
+EFI_STATUS
+EFIAPI
+SendForm (
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
+ IN EFI_HII_HANDLE *Handles,
+ IN UINTN HandleCount,
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN UINT16 FormId, OPTIONAL
+ IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
+ );
+
+/**
+ This function is called by a callback handler to retrieve uncommitted state
+ data from the browser.
+
+ @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
+ instance.
+ @param ResultsDataSize A pointer to the size of the buffer associated
+ with ResultsData.
+ @param ResultsData A string returned from an IFR browser or
+ equivalent. The results string will have no
+ routing information in them.
+ @param RetrieveData A BOOLEAN field which allows an agent to retrieve
+ (if RetrieveData = TRUE) data from the uncommitted
+ browser state information or set (if RetrieveData
+ = FALSE) data in the uncommitted browser state
+ information.
+ @param VariableGuid An optional field to indicate the target variable
+ GUID name to use.
+ @param VariableName An optional field to indicate the target
+ human-readable variable name.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+ @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
+ contain the results data.
+
+**/
+EFI_STATUS
+EFIAPI
+BrowserCallback (
+ IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
+ IN OUT UINTN *ResultsDataSize,
+ IN OUT EFI_STRING ResultsData,
+ IN BOOLEAN RetrieveData,
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName OPTIONAL
+ );
+
+/**
+ Find menu which will show next time.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+ @param SettingLevel Input Settting level, if it is FormLevel, just exit current form.
+ else, we need to exit current formset.
+
+ @retval TRUE Exit current form.
+ @retval FALSE User press ESC and keep in current form.
+**/
+BOOLEAN
+FindNextMenu (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN BROWSER_SETTING_SCOPE SettingLevel
+ );
+
+/**
+ check whether the form need to update the NV.
+
+ @param Form Form data structure.
+
+ @retval TRUE Need to update the NV.
+ @retval FALSE No need to update the NV.
+**/
+BOOLEAN
+IsNvUpdateRequiredForForm (
+ IN FORM_BROWSER_FORM *Form
+ );
+
+/**
+ check whether the formset need to update the NV.
+
+ @param FormSet FormSet data structure.
+
+ @retval TRUE Need to update the NV.
+ @retval FALSE No need to update the NV.
+**/
+BOOLEAN
+IsNvUpdateRequiredForFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Call the call back function for the question and process the return action.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+ @param FormSet The formset this question belong to.
+ @param Form The form this question belong to.
+ @param Question The Question which need to call.
+ @param Action The action request.
+ @param SkipSaveOrDiscard Whether skip save or discard action.
+
+ @retval EFI_SUCCESS The call back function executes successfully.
+ @return Other value if the call back function failed to execute.
+**/
+EFI_STATUS
+ProcessCallBackFunction (
+ IN OUT UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_BROWSER_ACTION Action,
+ IN BOOLEAN SkipSaveOrDiscard
+ );
+
+/**
+ Call the retrieve type call back function for one question to get the initialize data.
+
+ This function only used when in the initialize stage, because in this stage, the
+ Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
+
+ @param ConfigAccess The config access protocol produced by the hii driver.
+ @param Statement The Question which need to call.
+ @param FormSet The formset this question belong to.
+
+ @retval EFI_SUCCESS The call back function executes successfully.
+ @return Other value if the call back function failed to execute.
+**/
+EFI_STATUS
+ProcessRetrieveForQuestion (
+ IN EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess,
+ IN FORM_BROWSER_STATEMENT *Statement,
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Find the matched FormSet context in the backup maintain list based on HiiHandle.
+
+ @param Handle The Hii Handle.
+
+ @return the found FormSet context. If no found, NULL will return.
+
+**/
+FORM_BROWSER_FORMSET *
+GetFormSetFromHiiHandle (
+ EFI_HII_HANDLE Handle
+ );
+
+/**
+ Check whether the input HII handle is the FormSet that is being used.
+
+ @param Handle The Hii Handle.
+
+ @retval TRUE HII handle is being used.
+ @retval FALSE HII handle is not being used.
+
+**/
+BOOLEAN
+IsHiiHandleInBrowserContext (
+ EFI_HII_HANDLE Handle
+ );
+
+/**
+ Configure what scope the hot key will impact.
+ All hot keys have the same scope. The mixed hot keys with the different level are not supported.
+ If no scope is set, the default scope will be FormSet level.
+ After all registered hot keys are removed, previous Scope can reset to another level.
+
+ @param[in] Scope Scope level to be set.
+
+ @retval EFI_SUCCESS Scope is set correctly.
+ @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
+ @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
+
+**/
+EFI_STATUS
+EFIAPI
+SetScope (
+ IN BROWSER_SETTING_SCOPE Scope
+ );
+
+/**
+ Register the hot key with its browser action, or unregistered the hot key.
+ Only support hot key that is not printable character (control key, function key, etc.).
+ If the action value is zero, the hot key will be unregistered if it has been registered.
+ If the same hot key has been registered, the new action and help string will override the previous ones.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key. Its type is EFI_INPUT_KEY to
+ be supported by all ConsoleIn devices.
+ @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
+ @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
+ @param[in] HelpString Help string that describes the hot key information.
+ Its value may be NULL for the unregistered hot key.
+
+ @retval EFI_SUCCESS Hot key is registered or unregistered.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+ @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
+ @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
+ @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHotKey (
+ IN EFI_INPUT_KEY *KeyData,
+ IN UINT32 Action,
+ IN UINT16 DefaultId,
+ IN EFI_STRING HelpString OPTIONAL
+ );
+
+/**
+ Register Exit handler function.
+ When more than one handler function is registered, the latter one will override the previous one.
+ When NULL handler is specified, the previous Exit handler will be unregistered.
+
+ @param[in] Handler Pointer to handler function.
+
+**/
+VOID
+EFIAPI
+RegiserExitHandler (
+ IN EXIT_HANDLER Handler
+ );
+
+/**
+
+ Check whether the browser data has been modified.
+
+ @retval TRUE Browser data is changed.
+ @retval FALSE No browser data is changed.
+
+**/
+BOOLEAN
+EFIAPI
+IsBrowserDataModified (
+ VOID
+ );
+
+/**
+
+ Execute the action requested by the Action parameter.
+
+ @param[in] Action Execute the request action.
+ @param[in] DefaultId The default Id info when need to load default value.
+
+ @retval EFI_SUCCESS Execute the request action succss.
+ @retval EFI_INVALID_PARAMETER The input action value is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+ExecuteAction (
+ IN UINT32 Action,
+ IN UINT16 DefaultId
+ );
+
+/**
+ Create reminder to let user to choose save or discard the changed browser data.
+ Caller can use it to actively check the changed browser data.
+
+ @retval BROWSER_NO_CHANGES No browser data is changed.
+ @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
+ @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
+ @retval BROWSER_KEEP_CURRENT Browser keep current changes.
+
+**/
+UINT32
+EFIAPI
+SaveReminder (
+ VOID
+ );
+
+/**
+ Check whether the Reset Required for the browser
+
+ @retval TRUE Browser required to reset after exit.
+ @retval FALSE Browser not need to reset after exit.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+ VOID
+ );
+
+/**
+ Find the registered HotKey based on KeyData.
+
+ @param[in] KeyData A pointer to a buffer that describes the keystroke
+ information for the hot key.
+
+ @return The registered HotKey context. If no found, NULL will return.
+**/
+BROWSER_HOT_KEY *
+GetHotKeyFromRegisterList (
+ IN EFI_INPUT_KEY *KeyData
+ );
+
+/**
+
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ );
+
+/**
+ Password may be stored as encrypted by Configuration Driver. When change a
+ password, user will be challenged with old password. To validate user input old
+ password, we will send the clear text to Configuration Driver via Callback().
+ Configuration driver is responsible to check the passed in password and return
+ the validation result. If validation pass, state machine in password Callback()
+ will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
+ After user type in new password twice, Callback() will be invoked to send the
+ new password to Configuration Driver.
+
+ @param Selection Pointer to UI_MENU_SELECTION.
+ @param MenuOption The MenuOption for this password Question.
+ @param String The clear text of password.
+
+ @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
+ @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
+ @retval EFI_SUCCESS Password correct, Browser will prompt for new
+ password.
+ @retval EFI_NOT_READY Password incorrect, Browser will show error
+ message.
+ @retval Other Browser will do nothing.
+ @return In state of BROWSER_STATE_SET_PASSWORD:
+ @retval EFI_SUCCESS Set password success.
+ @retval Other Set password failed.
+
+**/
+EFI_STATUS
+PasswordCallback (
+ IN UI_MENU_SELECTION *Selection,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16 *String
+ );
+
+/**
+ Display error message for invalid password.
+
+**/
+VOID
+PasswordInvalid (
+ VOID
+ );
+
+/**
+ The worker function that send the displays to the screen. On output,
+ the selection made by user is returned.
+
+ @param Selection On input, Selection tell setup browser the information
+ about the Selection, form and formset to be displayed.
+ On output, Selection return the screen item that is selected
+ by user.
+
+ @retval EFI_SUCCESS The page is displayed successfully.
+ @return Other value if the page failed to be diplayed.
+
+**/
+EFI_STATUS
+SetupBrowser (
+ IN OUT UI_MENU_SELECTION *Selection
+ );
+
+/**
+ Free up the resource allocated for all strings required
+ by Setup Browser.
+
+**/
+VOID
+FreeBrowserStrings (
+ VOID
+ );
+
+/**
+ Create a menu with specified formset GUID and form ID, and add it as a child
+ of the given parent menu.
+
+ @param HiiHandle Hii handle related to this formset.
+ @param FormSetGuid The Formset Guid of menu to be added.
+ @param FormId The Form ID of menu to be added.
+ @param QuestionId The question id of this menu to be added.
+
+ @return A pointer to the newly added menu or NULL if memory is insufficient.
+
+**/
+FORM_ENTRY_INFO *
+UiAddMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId,
+ IN UINT16 QuestionId
+ );
+
+/**
+ Search Menu with given FormSetGuid and FormId in all cached menu list.
+
+ @param HiiHandle HiiHandle for FormSet.
+ @param FormSetGuid The Formset GUID of the menu to search.
+ @param FormId The Form ID of menu to search.
+
+ @return A pointer to menu found or NULL if not found.
+
+**/
+FORM_ENTRY_INFO *
+UiFindMenuList (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid,
+ IN UINT16 FormId
+ );
+
+/**
+ Free Menu list linked list.
+
+ @param MenuListHead One Menu list point in the menu list.
+
+**/
+VOID
+UiFreeMenuList (
+ LIST_ENTRY *MenuListHead
+ );
+
+/**
+ Find parent menu for current menu.
+
+ @param CurrentMenu Current Menu
+ @param SettingLevel Whether find parent menu in Form Level or Formset level.
+ In form level, just find the parent menu;
+ In formset level, find the parent menu which has different
+ formset guid value.
+
+ @retval The parent menu for current menu.
+**/
+FORM_ENTRY_INFO *
+UiFindParentMenu (
+ IN FORM_ENTRY_INFO *CurrentMenu,
+ IN BROWSER_SETTING_SCOPE SettingLevel
+ );
+
+/**
+ Validate the HiiHandle.
+
+ @param HiiHandle The input HiiHandle which need to validate.
+
+ @retval TRUE The handle is validate.
+ @retval FALSE The handle is invalidate.
+
+**/
+BOOLEAN
+ValidateHiiHandle (
+ EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Copy current Menu list to the new menu list.
+
+ @param NewMenuListHead New create Menu list.
+ @param CurrentMenuListHead Current Menu list.
+
+**/
+VOID
+UiCopyMenuList (
+ OUT LIST_ENTRY *NewMenuListHead,
+ IN LIST_ENTRY *CurrentMenuListHead
+ );
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ );
+/**
+ Return data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+
+ @retval Value The data to be returned
+
+**/
+UINT64
+GetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index
+ );
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ );
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param Result Return value after compare.
+ retval 0 Two operators equal.
+ return Positive value if Value1 is greater than Value2.
+ retval Negative value if Value1 is less than Value2.
+ @param HiiHandle Only required for string compare.
+
+ @retval other Could not perform compare on two values.
+ @retval EFI_SUCCESS Compare the value success.
+
+**/
+EFI_STATUS
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ OUT INTN *Result,
+ IN EFI_HII_HANDLE HiiHandle OPTIONAL
+ );
+
+/**
+ Perform Password check.
+ Passwork may be encrypted by driver that requires the specific check.
+
+ @param Form Form where Password Statement is in.
+ @param Statement Password statement
+ @param PasswordString Password string to be checked. It may be NULL.
+ NULL means to restore password.
+ "" string can be used to checked whether old password does exist.
+
+ @return Status Status of Password check.
+**/
+EFI_STATUS
+EFIAPI
+PasswordCheck (
+ IN FORM_DISPLAY_ENGINE_FORM *Form,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN EFI_STRING PasswordString OPTIONAL
+ );
+
+/**
+
+ Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
+
+ @param DisplayStatement The input FORM_DISPLAY_ENGINE_STATEMENT.
+
+ @retval FORM_BROWSER_STATEMENT The return FORM_BROWSER_STATEMENT info.
+
+**/
+FORM_BROWSER_STATEMENT *
+GetBrowserStatement (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
+ );
+
+/**
+
+ Initialize the Display form structure data.
+
+**/
+VOID
+InitializeDisplayFormData (
+ VOID
+ );
+
+
+/**
+ Base on the current formset info, clean the ConfigRequest string in browser storage.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+CleanBrowserStorage (
+ IN OUT FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Find HII Handle in the HII database associated with given Device Path.
+
+ If DevicePath is NULL, then ASSERT.
+
+ @param DevicePath Device Path associated with the HII package list
+ handle.
+ @param FormsetGuid The formset guid for this formset.
+
+ @retval Handle HII package list Handle associated with the Device
+ Path.
+ @retval NULL Hii Package list handle is not found.
+
+**/
+EFI_HII_HANDLE
+DevicePathToHiiHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_GUID *FormsetGuid
+ );
+
+/**
+ Adjust the config request info, remove the request elements which already in AllConfigRequest string.
+
+ @param Storage Form set Storage.
+ @param Request The input request string.
+ @param RespString Whether the input is ConfigRequest or ConfigResp format.
+
+ @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
+ @retval FALSE All elements covered by current used elements.
+
+**/
+BOOLEAN
+ConfigRequestAdjust (
+ IN BROWSER_STORAGE *Storage,
+ IN CHAR16 *Request,
+ IN BOOLEAN RespString
+ );
+
+/**
+ Perform question check.
+
+ If one question has more than one check, process form high priority to low.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param Question The Question to be validated.
+
+ @retval EFI_SUCCESS Form validation pass.
+ @retval other Form validation failed.
+
+**/
+EFI_STATUS
+ValueChangedValidation (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question
+ );
+
+/**
+ Pop up the error info.
+
+ @param BrowserStatus The input browser status.
+ @param HiiHandle The HiiHandle for this error opcode.
+ @param OpCode The opcode use to get the erro info and timeout value.
+ @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF.
+
+**/
+UINT32
+PopupErrorMessage (
+ IN UINT32 BrowserStatus,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL
+ IN CHAR16 *ErrorString
+ );
+
+/**
+ Check whether the result is TRUE or FALSE.
+
+ For the EFI_HII_VALUE value type is numeric, return TRUE if the
+ value is not 0.
+
+ @param Result Input the result data.
+
+ @retval TRUE The result is TRUE.
+ @retval FALSE The result is FALSE.
+
+**/
+BOOLEAN
+IsTrue (
+ IN EFI_HII_VALUE *Result
+ );
+
+/**
+ Get Formset_storage base on the input varstoreid info.
+
+ @param FormSet Pointer of the current FormSet.
+ @param VarStoreId Varstore ID info.
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+GetFstStgFromVarId (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN EFI_VARSTORE_ID VarStoreId
+ );
+
+/**
+ Get Formset_storage base on the input browser storage.
+
+ More than one formsets may share the same browser storage,
+ this function just get the first formset storage which
+ share the browser storage.
+
+ @param Storage browser storage info.
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+
+**/
+FORMSET_STORAGE *
+GetFstStgFromBrsStg (
+ IN BROWSER_STORAGE *Storage
+ );
+
+/**
+ Reconnect the controller.
+
+ @param DriverHandle The controller handle which need to be reconnect.
+
+ @retval TRUE do the reconnect behavior success.
+ @retval FALSE do the reconnect behavior failed.
+
+**/
+BOOLEAN
+ReconnectController (
+ IN EFI_HANDLE DriverHandle
+ );
+
+/**
+ Converts the unicode character of the string from uppercase to lowercase.
+ This is a internal function.
+
+ @param ConfigString String to be converted
+
+**/
+VOID
+EFIAPI
+HiiToLower (
+ IN EFI_STRING ConfigString
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni
new file mode 100644
index 000000000..49b21252e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification.
+//
+// It also produces FormBrowserEx(2) protocol to let user register the different Hot key service.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the FORM BROWSER2 protocol defined in the UEFI Specification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver produces text display service. It can show HII Form package and interact with user. It also produces FormBrowserEx protocol to let user register the different Hot key service."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
new file mode 100644
index 000000000..82db7c1ef
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
@@ -0,0 +1,79 @@
+## @file
+# The DXE driver produces FORM BROWSER2 protocol defined in UEFI specification.
+#
+# It also produces FormBrowserEx(2) protocol to let user register the different Hot key service.
+#
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SetupBrowser
+ MODULE_UNI_FILE = SetupBrowser.uni
+ FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 2.0
+ ENTRY_POINT = InitializeSetup
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Setup.c
+ Setup.h
+ IfrParse.c
+ Expression.c
+ Presentation.c
+ Expression.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ DevicePathLib
+ PcdLib
+ UefiLib
+
+[Guids]
+ gEfiHiiPlatformSetupFormsetGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiHiiStandardFormGuid ## SOMETIMES_CONSUMES ## GUID
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+ gEdkiiIfrBitVarstoreGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFormBrowser2ProtocolGuid ## PRODUCES
+ gEdkiiFormBrowserEx2ProtocolGuid ## PRODUCES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiUnicodeCollation2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathFromTextProtocolGuid ## SOMETIMES_CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEdkiiFormDisplayEngineProtocolGuid
+ gEdkiiFormBrowserExProtocolGuid ## PRODUCES
+ gEfiRegularExpressionProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SetupBrowserExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni
new file mode 100644
index 000000000..33d9b8e46
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SetupBrowser Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Setup Browser DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
new file mode 100644
index 000000000..3cdb0b1ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
@@ -0,0 +1,1455 @@
+/** @file
+ This code produces the Smbios protocol. It also responsible for constructing
+ SMBIOS table into system table.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmbiosDxe.h"
+
+//
+// Module Global:
+// Since this driver will only ever produce one instance of the
+// protocol you are not required to dynamically allocate the PrivateData.
+//
+SMBIOS_INSTANCE mPrivateData;
+
+UINTN mPreAllocatedPages = 0;
+UINTN mPre64BitAllocatedPages = 0;
+
+//
+// Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.
+//
+SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;
+SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {
+ //
+ // AnchorString
+ //
+ {
+ 0x5f,
+ 0x53,
+ 0x4d,
+ 0x5f
+ },
+ //
+ // EntryPointStructureChecksum,TO BE FILLED
+ //
+ 0,
+ //
+ // EntryPointStructure Length
+ //
+ 0x1f,
+ //
+ // MajorVersion
+ //
+ 0,
+ //
+ // MinorVersion
+ //
+ 0,
+ //
+ // MaxStructureSize, TO BE FILLED
+ //
+ 0,
+ //
+ // EntryPointRevision
+ //
+ 0,
+ //
+ // FormattedArea
+ //
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ //
+ // IntermediateAnchorString
+ //
+ {
+ 0x5f,
+ 0x44,
+ 0x4d,
+ 0x49,
+ 0x5f
+ },
+ //
+ // IntermediateChecksum, TO BE FILLED
+ //
+ 0,
+ //
+ // TableLength, TO BE FILLED
+ //
+ 0,
+ //
+ // TableAddress, TO BE FILLED
+ //
+ 0,
+ //
+ // NumberOfSmbiosStructures, TO BE FILLED
+ //
+ 0,
+ //
+ // SmbiosBcdRevision
+ //
+ 0
+};
+
+SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30EntryPointStructure = NULL;
+SMBIOS_TABLE_3_0_ENTRY_POINT Smbios30EntryPointStructureData = {
+ //
+ // AnchorString _SM3_
+ //
+ {
+ 0x5f,
+ 0x53,
+ 0x4d,
+ 0x33,
+ 0x5f,
+ },
+ //
+ // EntryPointStructureChecksum,TO BE FILLED
+ //
+ 0,
+ //
+ // EntryPointLength
+ //
+ 0x18,
+ //
+ // MajorVersion
+ //
+ 0,
+ //
+ // MinorVersion
+ //
+ 0,
+ //
+ // DocRev
+ //
+ 0,
+ //
+ // EntryPointRevision
+ //
+ 0x01,
+ //
+ // Reserved
+ //
+ 0,
+ //
+ // TableMaximumSize,TO BE FILLED
+ //
+ 0,
+ //
+ // TableAddress,TO BE FILLED
+ //
+ 0
+};
+/**
+
+ Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param Head Pointer to the beginning of SMBIOS structure.
+ @param Size The returned size.
+ @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
+
+ @retval EFI_SUCCESS Size retured in Size.
+ @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSmbiosStructureSize (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN EFI_SMBIOS_TABLE_HEADER *Head,
+ OUT UINTN *Size,
+ OUT UINTN *NumberOfStrings
+ )
+{
+ UINTN FullSize;
+ UINTN StrLen;
+ UINTN MaxLen;
+ INT8* CharInStr;
+
+ if (Size == NULL || NumberOfStrings == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FullSize = Head->Length;
+ CharInStr = (INT8*)Head + Head->Length;
+ *Size = FullSize;
+ *NumberOfStrings = 0;
+ StrLen = 0;
+ //
+ // look for the two consecutive zeros, check the string limit by the way.
+ //
+ while (*CharInStr != 0 || *(CharInStr+1) != 0) {
+ if (*CharInStr == 0) {
+ *Size += 1;
+ CharInStr++;
+ }
+
+ if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)){
+ MaxLen = SMBIOS_STRING_MAX_LENGTH;
+ } else if (This->MajorVersion < 3) {
+ //
+ // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
+ // However, the length of the entire structure table (including all strings) must be reported
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
+ // which is a WORD field limited to 65,535 bytes.
+ //
+ MaxLen = SMBIOS_TABLE_MAX_LENGTH;
+ } else {
+ //
+ // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.
+ // Locate the end of string as long as possible.
+ //
+ MaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;
+ }
+
+ for (StrLen = 0 ; StrLen < MaxLen; StrLen++) {
+ if (*(CharInStr+StrLen) == 0) {
+ break;
+ }
+ }
+
+ if (StrLen == MaxLen) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // forward the pointer
+ //
+ CharInStr += StrLen;
+ *Size += StrLen;
+ *NumberOfStrings += 1;
+ }
+
+ //
+ // count ending two zeros.
+ //
+ *Size += 2;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Determin whether an SmbiosHandle has already in use.
+
+ @param Head Pointer to the beginning of SMBIOS structure.
+ @param Handle A unique handle will be assigned to the SMBIOS record.
+
+ @retval TRUE Smbios handle already in use.
+ @retval FALSE Smbios handle is NOT used.
+
+**/
+BOOLEAN
+EFIAPI
+CheckSmbiosHandleExistance (
+ IN LIST_ENTRY *Head,
+ IN EFI_SMBIOS_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ SMBIOS_HANDLE_ENTRY *HandleEntry;
+
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
+ if (HandleEntry->SmbiosHandle == Handle) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+
+ Get the max SmbiosHandle that could be use.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param MaxHandle The max handle that could be assigned to the SMBIOS record.
+
+**/
+VOID
+EFIAPI
+GetMaxSmbiosHandle (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN OUT EFI_SMBIOS_HANDLE *MaxHandle
+ )
+{
+ if (This->MajorVersion == 2 && This->MinorVersion == 0) {
+ *MaxHandle = 0xFFFE;
+ } else {
+ *MaxHandle = 0xFEFF;
+ }
+}
+
+/**
+
+ Get an SmbiosHandle that could use.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
+
+ @retval EFI_SUCCESS Smbios handle got.
+ @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
+
+**/
+EFI_STATUS
+EFIAPI
+GetAvailableSmbiosHandle (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN OUT EFI_SMBIOS_HANDLE *Handle
+ )
+{
+ LIST_ENTRY *Head;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;
+ EFI_SMBIOS_HANDLE AvailableHandle;
+
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
+
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ Head = &Private->AllocatedHandleListHead;
+ for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {
+ if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {
+ *Handle = AvailableHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+
+/**
+ Add an SMBIOS record.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
+ means no handle.
+ @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle
+ will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,
+ EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
+ @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
+ determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
+ by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
+ a set of null terminated strings and a null.
+
+ @retval EFI_SUCCESS Record was added.
+ @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
+ @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosAdd (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN EFI_HANDLE ProducerHandle, OPTIONAL
+ IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
+ IN EFI_SMBIOS_TABLE_HEADER *Record
+ )
+{
+ VOID *Raw;
+ UINTN TotalSize;
+ UINTN RecordSize;
+ UINTN StructureSize;
+ UINTN NumberOfStrings;
+ EFI_STATUS Status;
+ LIST_ENTRY *Head;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_ENTRY *SmbiosEntry;
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;
+ SMBIOS_HANDLE_ENTRY *HandleEntry;
+ EFI_SMBIOS_RECORD_HEADER *InternalRecord;
+ BOOLEAN Smbios32BitTable;
+ BOOLEAN Smbios64BitTable;
+
+ if (SmbiosHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ //
+ // Check whether SmbiosHandle is already in use
+ //
+ Head = &Private->AllocatedHandleListHead;
+ if (*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // when SmbiosHandle is 0xFFFE, an available handle will be assigned
+ //
+ if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {
+ Status = GetAvailableSmbiosHandle(This, SmbiosHandle);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Check this handle validity
+ //
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
+ if (*SmbiosHandle > MaxSmbiosHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Calculate record size and string number
+ //
+ Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Smbios32BitTable = FALSE;
+ Smbios64BitTable = FALSE;
+ if ((This->MajorVersion < 0x3) ||
+ ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
+ //
+ // For SMBIOS 32-bit table, the length of the entire structure table (including all strings) must be reported
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
+ // which is a WORD field limited to 65,535 bytes. So the max size of 32-bit table should not exceed 65,535 bytes.
+ //
+ if ((EntryPointStructure != NULL) &&
+ (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH)) {
+ DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));
+ } else {
+ Smbios32BitTable = TRUE;
+ DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 32-bit table\n", Record->Type, StructureSize));
+ }
+ }
+
+ //
+ // For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes.
+ //
+ if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
+ //
+ // For SMBIOS 64-bit table, Structure table maximum size in SMBIOS 3.0 (64-bit) Entry Point
+ // is a DWORD field limited to 0xFFFFFFFF bytes. So the max size of 64-bit table should not exceed 0xFFFFFFFF bytes.
+ //
+ if ((Smbios30EntryPointStructure != NULL) &&
+ (Smbios30EntryPointStructure->TableMaximumSize + StructureSize > SMBIOS_3_0_TABLE_MAX_LENGTH)) {
+ DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));
+ } else {
+ DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 64-bit table\n", Record->Type, StructureSize));
+ Smbios64BitTable = TRUE;
+ }
+ }
+
+ if ((!Smbios32BitTable) && (!Smbios64BitTable)) {
+ //
+ // If both 32-bit and 64-bit table are not updated, quit
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enter into critical section
+ //
+ Status = EfiAcquireLockOrFail (&Private->DataLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;
+ TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;
+
+ //
+ // Allocate internal buffer
+ //
+ SmbiosEntry = AllocateZeroPool (TotalSize);
+ if (SmbiosEntry == NULL) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY));
+ if (HandleEntry == NULL) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Build Handle Entry and insert into linked list
+ //
+ HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;
+ HandleEntry->SmbiosHandle = *SmbiosHandle;
+ InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);
+
+ InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);
+ Raw = (VOID *) (InternalRecord + 1);
+
+ //
+ // Build internal record Header
+ //
+ InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
+ InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);
+ InternalRecord->RecordSize = RecordSize;
+ InternalRecord->ProducerHandle = ProducerHandle;
+ InternalRecord->NumberOfStrings = NumberOfStrings;
+ //
+ // Insert record into the internal linked list
+ //
+ SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
+ SmbiosEntry->RecordHeader = InternalRecord;
+ SmbiosEntry->RecordSize = TotalSize;
+ SmbiosEntry->Smbios32BitTable = Smbios32BitTable;
+ SmbiosEntry->Smbios64BitTable = Smbios64BitTable;
+ InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);
+
+ CopyMem (Raw, Record, StructureSize);
+ ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;
+
+ //
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.
+ // Here we create SMBIOS table and publish it in
+ // configuration table, so other UEFI drivers can get SMBIOS table from
+ // configuration table without depending on PI SMBIOS protocol.
+ //
+ SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable);
+
+ //
+ // Leave critical section
+ //
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the string associated with an existing SMBIOS record.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
+ @param StringNumber The non-zero string number of the string to update
+ @param String Update the StringNumber string with String.
+
+ @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
+ @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
+ @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.
+ @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosUpdateString (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN EFI_SMBIOS_HANDLE *SmbiosHandle,
+ IN UINTN *StringNumber,
+ IN CHAR8 *String
+ )
+{
+ UINTN InputStrLen;
+ UINTN TargetStrLen;
+ UINTN StrIndex;
+ UINTN TargetStrOffset;
+ UINTN NewEntrySize;
+ CHAR8 *StrStart;
+ VOID *Raw;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ EFI_STATUS Status;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_ENTRY *SmbiosEntry;
+ EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;
+ EFI_SMBIOS_TABLE_HEADER *Record;
+ EFI_SMBIOS_RECORD_HEADER *InternalRecord;
+
+ //
+ // Check args validity
+ //
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
+
+ if (*SmbiosHandle > MaxSmbiosHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (String == NULL) {
+ return EFI_ABORTED;
+ }
+
+ if (*StringNumber == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ InputStrLen = AsciiStrLen(String);
+
+ if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)) {
+ if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {
+ return EFI_UNSUPPORTED;
+ }
+ } else if (This->MajorVersion < 3) {
+ //
+ // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
+ // However, the length of the entire structure table (including all strings) must be reported
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
+ // which is a WORD field limited to 65,535 bytes.
+ //
+ if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if (InputStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH) {
+ //
+ // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.
+ // The input string length should not exceed 0xFFFFFFFF bytes.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ //
+ // Enter into critical section
+ //
+ Status = EfiAcquireLockOrFail (&Private->DataLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Head = &Private->DataListHead;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
+ Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
+
+ if (Record->Handle == *SmbiosHandle) {
+ //
+ // Find out the specified SMBIOS record
+ //
+ if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Point to unformed string section
+ //
+ StrStart = (CHAR8 *) Record + Record->Length;
+
+ for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {
+ //
+ // A string ends in 00h
+ //
+ if (*StrStart == 0) {
+ StrIndex++;
+ }
+
+ //
+ // String section ends in double-null (0000h)
+ //
+ if (*StrStart == 0 && *(StrStart + 1) == 0) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (*StrStart == 0) {
+ StrStart++;
+ TargetStrOffset++;
+ }
+
+ //
+ // Now we get the string target
+ //
+ TargetStrLen = AsciiStrLen(StrStart);
+ if (InputStrLen == TargetStrLen) {
+ AsciiStrCpyS(StrStart, TargetStrLen + 1, String);
+ //
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.
+ // Here we create SMBIOS table and publish it in
+ // configuration table, so other UEFI drivers can get SMBIOS table from
+ // configuration table without depending on PI SMBIOS protocol.
+ //
+ SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_SUCCESS;
+ }
+
+ SmbiosEntry->Smbios32BitTable = FALSE;
+ SmbiosEntry->Smbios64BitTable = FALSE;
+ if ((This->MajorVersion < 0x3) ||
+ ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {
+ //
+ // 32-bit table is produced, check the valid length.
+ //
+ if ((EntryPointStructure != NULL) &&
+ (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH)) {
+ //
+ // The length of the entire structure table (including all strings) must be reported
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
+ // which is a WORD field limited to 65,535 bytes.
+ //
+ DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 32-bit table\n"));
+ SmbiosEntry->Smbios32BitTable = TRUE;
+ }
+ }
+
+ if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {
+ //
+ // 64-bit table is produced, check the valid length.
+ //
+ if ((Smbios30EntryPointStructure != NULL) &&
+ (Smbios30EntryPointStructure->TableMaximumSize + InputStrLen - TargetStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH)) {
+ DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 64-bit table\n"));
+ SmbiosEntry->Smbios64BitTable = TRUE;
+ }
+ }
+
+ if ((!SmbiosEntry->Smbios32BitTable) && (!SmbiosEntry->Smbios64BitTable)) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Original string buffer size is not exactly match input string length.
+ // Re-allocate buffer is needed.
+ //
+ NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;
+ ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);
+
+ if (ResizedSmbiosEntry == NULL) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);
+ Raw = (VOID *) (InternalRecord + 1);
+
+ //
+ // Build internal record Header
+ //
+ InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
+ InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);
+ InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;
+ InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
+ InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;
+
+ //
+ // Copy SMBIOS structure and optional strings.
+ //
+ CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset);
+ CopyMem ((VOID*)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1);
+ CopyMem ((CHAR8*)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1),
+ (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1,
+ SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1);
+
+ //
+ // Insert new record
+ //
+ ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
+ ResizedSmbiosEntry->RecordHeader = InternalRecord;
+ ResizedSmbiosEntry->RecordSize = NewEntrySize;
+ ResizedSmbiosEntry->Smbios32BitTable = SmbiosEntry->Smbios32BitTable;
+ ResizedSmbiosEntry->Smbios64BitTable = SmbiosEntry->Smbios64BitTable;
+ InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);
+
+ //
+ // Remove old record
+ //
+ RemoveEntryList(Link);
+ FreePool(SmbiosEntry);
+ //
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.
+ // Here we create SMBIOS table and publish it in
+ // configuration table, so other UEFI drivers can get SMBIOS table from
+ // configuration table without depending on PI SMBIOS protocol.
+ //
+ SmbiosTableConstruction (ResizedSmbiosEntry->Smbios32BitTable, ResizedSmbiosEntry->Smbios64BitTable);
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_SUCCESS;
+ }
+ }
+
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Remove an SMBIOS record.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param SmbiosHandle The handle of the SMBIOS record to remove.
+
+ @retval EFI_SUCCESS SMBIOS record was removed.
+ @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosRemove (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN EFI_SMBIOS_HANDLE SmbiosHandle
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ EFI_STATUS Status;
+ EFI_SMBIOS_HANDLE MaxSmbiosHandle;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_ENTRY *SmbiosEntry;
+ SMBIOS_HANDLE_ENTRY *HandleEntry;
+ EFI_SMBIOS_TABLE_HEADER *Record;
+
+ //
+ // Check args validity
+ //
+ GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
+
+ if (SmbiosHandle > MaxSmbiosHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ //
+ // Enter into critical section
+ //
+ Status = EfiAcquireLockOrFail (&Private->DataLock);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Head = &Private->DataListHead;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
+ Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
+ if (Record->Handle == SmbiosHandle) {
+ //
+ // Remove specified smobios record from DataList
+ //
+ RemoveEntryList(Link);
+ //
+ // Remove this handle from AllocatedHandleList
+ //
+ Head = &Private->AllocatedHandleListHead;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
+ if (HandleEntry->SmbiosHandle == SmbiosHandle) {
+ RemoveEntryList(Link);
+ FreePool(HandleEntry);
+ break;
+ }
+ }
+ //
+ // Some UEFI drivers (such as network) need some information in SMBIOS table.
+ // Here we create SMBIOS table and publish it in
+ // configuration table, so other UEFI drivers can get SMBIOS table from
+ // configuration table without depending on PI SMBIOS protocol.
+ //
+ if (SmbiosEntry->Smbios32BitTable) {
+ DEBUG ((EFI_D_INFO, "SmbiosRemove: remove from 32-bit table\n"));
+ }
+ if (SmbiosEntry->Smbios64BitTable) {
+ DEBUG ((EFI_D_INFO, "SmbiosRemove: remove from 64-bit table\n"));
+ }
+ //
+ // Update the whole SMBIOS table again based on which table the removed SMBIOS record is in.
+ //
+ SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);
+ FreePool(SmbiosEntry);
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Leave critical section
+ //
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_INVALID_PARAMETER;
+
+}
+
+/**
+ Allow the caller to discover all or some of the SMBIOS records.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
+ next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
+ handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.
+ @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
+ this functionally it ignored. Type is not modified by the GetNext() function.
+ @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
+ the unformatted area. The unformatted area optionally contains text strings.
+ @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
+ If a NULL pointer is passed in no data will be returned
+
+ @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
+ @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosGetNext (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
+ IN EFI_SMBIOS_TYPE *Type, OPTIONAL
+ OUT EFI_SMBIOS_TABLE_HEADER **Record,
+ OUT EFI_HANDLE *ProducerHandle OPTIONAL
+ )
+{
+ BOOLEAN StartPointFound;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_ENTRY *SmbiosEntry;
+ EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
+
+ if (SmbiosHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StartPointFound = FALSE;
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ Head = &Private->DataListHead;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
+ SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
+
+ //
+ // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned
+ //
+ if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {
+ if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
+ continue;
+ }
+
+ *SmbiosHandle = SmbiosTableHeader->Handle;
+ *Record =SmbiosTableHeader;
+ if (ProducerHandle != NULL) {
+ *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Start this round search from the next SMBIOS handle
+ //
+ if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {
+ StartPointFound = TRUE;
+ continue;
+ }
+
+ if (StartPointFound) {
+ if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
+ continue;
+ }
+
+ *SmbiosHandle = SmbiosTableHeader->Handle;
+ *Record = SmbiosTableHeader;
+ if (ProducerHandle != NULL) {
+ *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Allow the caller to discover all of the SMBIOS records.
+
+ @param This The EFI_SMBIOS_PROTOCOL instance.
+ @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
+ If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
+ @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
+ the unformatted area. The unformatted area optionally contains text strings.
+
+ @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
+ *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
+ @retval EFI_NOT_FOUND There is no more SMBIOS entry.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextSmbiosRecord (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,
+ OUT EFI_SMBIOS_TABLE_HEADER **Record
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ SMBIOS_INSTANCE *Private;
+ EFI_SMBIOS_ENTRY *SmbiosEntry;
+ EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
+
+ Private = SMBIOS_INSTANCE_FROM_THIS (This);
+ if (*CurrentSmbiosEntry == NULL) {
+ //
+ // Get the beginning of SMBIOS entry.
+ //
+ Head = &Private->DataListHead;
+ } else {
+ //
+ // Get previous SMBIOS entry and make it as start point.
+ //
+ Head = &(*CurrentSmbiosEntry)->Link;
+ }
+
+ Link = Head->ForwardLink;
+
+ if (Link == &Private->DataListHead) {
+ //
+ // If no more SMBIOS entry in the list, return not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
+ SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
+ *Record = SmbiosTableHeader;
+ *CurrentSmbiosEntry = SmbiosEntry;
+ return EFI_SUCCESS;
+}
+
+/**
+ Assembles SMBIOS table from the SMBIOS protocol. Produce Table
+ Entry Point and return the pointer to it.
+
+ @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
+
+ @retval EFI_SUCCESS Structure created sucessfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosCreateTable (
+ OUT VOID **TableEntryPointStructure
+ )
+{
+ UINT8 *BufferPointer;
+ UINTN RecordSize;
+ UINTN NumOfStr;
+ EFI_STATUS Status;
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+ EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
+ EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
+ EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;
+
+ Status = EFI_SUCCESS;
+ BufferPointer = NULL;
+
+ if (EntryPointStructure == NULL) {
+ //
+ // Initialize the EntryPointStructure with initial values.
+ // It should be done only once.
+ // Allocate memory (below 4GB).
+ //
+ DEBUG ((EFI_D_INFO, "SmbiosCreateTable: Initialize 32-bit entry point structure\n"));
+ EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
+ EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
+ EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);
+ PhysicalAddress = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmbiosCreateTable () could not allocate EntryPointStructure < 4GB\n"));
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;
+
+ CopyMem (
+ EntryPointStructure,
+ &EntryPointStructureData,
+ sizeof (SMBIOS_TABLE_ENTRY_POINT)
+ );
+ }
+
+ //
+ // Get Smbios protocol to traverse SMBIOS records.
+ //
+ SmbiosProtocol = &mPrivateData.Smbios;
+
+ //
+ // Make some statistics about all the structures
+ //
+ EntryPointStructure->NumberOfSmbiosStructures = 0;
+ EntryPointStructure->TableLength = 0;
+ EntryPointStructure->MaxStructureSize = 0;
+
+ //
+ // Calculate EPS Table Length
+ //
+ CurrentSmbiosEntry = NULL;
+ do {
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
+
+ if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
+ //
+ // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
+ //
+ EntryPointStructure->NumberOfSmbiosStructures++;
+ EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);
+ if (RecordSize > EntryPointStructure->MaxStructureSize) {
+ EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;
+ }
+ }
+ } while (!EFI_ERROR(Status));
+
+ //
+ // Create End-Of-Table structure
+ //
+ GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);
+ EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;
+ EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);
+ EndStructure.Header.Handle = SmbiosHandle;
+ EndStructure.Tailing[0] = 0;
+ EndStructure.Tailing[1] = 0;
+ EntryPointStructure->NumberOfSmbiosStructures++;
+ EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));
+ if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {
+ EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);
+ }
+
+ if (EFI_SIZE_TO_PAGES ((UINT32) EntryPointStructure->TableLength) > mPreAllocatedPages) {
+ //
+ // If new SMBIOS table size exceeds the previous allocated page,
+ // it is time to re-allocate memory (below 4GB).
+ //
+ DEBUG ((EFI_D_INFO, "%a() re-allocate SMBIOS 32-bit table\n",
+ __FUNCTION__));
+ if (EntryPointStructure->TableAddress != 0) {
+ //
+ // Free the previous allocated page
+ //
+ FreePages (
+ (VOID*)(UINTN)EntryPointStructure->TableAddress,
+ mPreAllocatedPages
+ );
+ EntryPointStructure->TableAddress = 0;
+ mPreAllocatedPages = 0;
+ }
+
+ PhysicalAddress = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
+ EntryPointStructure->TableAddress = 0;
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;
+ mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
+ }
+ }
+
+ //
+ // Assemble the tables
+ //
+ ASSERT (EntryPointStructure->TableAddress != 0);
+ BufferPointer = (UINT8 *) (UINTN) EntryPointStructure->TableAddress;
+ CurrentSmbiosEntry = NULL;
+ do {
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
+
+ if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
+ CopyMem (BufferPointer, SmbiosRecord, RecordSize);
+ BufferPointer = BufferPointer + RecordSize;
+ }
+ } while (!EFI_ERROR(Status));
+
+ //
+ // Assemble End-Of-Table structure
+ //
+ CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
+
+ //
+ // Fixup checksums in the Entry Point Structure
+ //
+ EntryPointStructure->IntermediateChecksum = 0;
+ EntryPointStructure->EntryPointStructureChecksum = 0;
+
+ EntryPointStructure->IntermediateChecksum =
+ CalculateCheckSum8 ((UINT8 *) EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);
+ EntryPointStructure->EntryPointStructureChecksum =
+ CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);
+
+ //
+ // Returns the pointer
+ //
+ *TableEntryPointStructure = EntryPointStructure;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Assembles SMBIOS 64-bit table from the SMBIOS protocol. Produce Table
+ Entry Point and return the pointer to it.
+
+ @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
+
+ @retval EFI_SUCCESS Structure created sucessfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosCreate64BitTable (
+ OUT VOID **TableEntryPointStructure
+ )
+{
+ UINT8 *BufferPointer;
+ UINTN RecordSize;
+ UINTN NumOfStr;
+ EFI_STATUS Status;
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+ EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
+ EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
+ EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;
+
+ Status = EFI_SUCCESS;
+ BufferPointer = NULL;
+
+ if (Smbios30EntryPointStructure == NULL) {
+ //
+ // Initialize the Smbios30EntryPointStructure with initial values.
+ // It should be done only once.
+ // Allocate memory at any address.
+ //
+ DEBUG ((EFI_D_INFO, "SmbiosCreateTable: Initialize 64-bit entry point structure\n"));
+ Smbios30EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
+ Smbios30EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
+ Smbios30EntryPointStructureData.DocRev = PcdGet8 (PcdSmbiosDocRev);
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmbiosCreate64BitTable() could not allocate Smbios30EntryPointStructure\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Smbios30EntryPointStructure = (SMBIOS_TABLE_3_0_ENTRY_POINT *) (UINTN) PhysicalAddress;
+
+ CopyMem (
+ Smbios30EntryPointStructure,
+ &Smbios30EntryPointStructureData,
+ sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)
+ );
+ }
+
+ //
+ // Get Smbios protocol to traverse SMBIOS records.
+ //
+ SmbiosProtocol = &mPrivateData.Smbios;
+ Smbios30EntryPointStructure->TableMaximumSize = 0;
+
+ //
+ // Calculate EPS Table Length
+ //
+ CurrentSmbiosEntry = NULL;
+ do {
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
+
+ if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
+ //
+ // Record TableMaximumSize
+ //
+ Smbios30EntryPointStructure->TableMaximumSize = (UINT32) (Smbios30EntryPointStructure->TableMaximumSize + RecordSize);
+ }
+ } while (!EFI_ERROR(Status));
+
+ //
+ // Create End-Of-Table structure
+ //
+ GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);
+ EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;
+ EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);
+ EndStructure.Header.Handle = SmbiosHandle;
+ EndStructure.Tailing[0] = 0;
+ EndStructure.Tailing[1] = 0;
+ Smbios30EntryPointStructure->TableMaximumSize = (UINT32) (Smbios30EntryPointStructure->TableMaximumSize + sizeof (EndStructure));
+
+ if (EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize) > mPre64BitAllocatedPages) {
+ //
+ // If new SMBIOS table size exceeds the previous allocated page,
+ // it is time to re-allocate memory at anywhere.
+ //
+ DEBUG ((EFI_D_INFO, "%a() re-allocate SMBIOS 64-bit table\n",
+ __FUNCTION__));
+ if (Smbios30EntryPointStructure->TableAddress != 0) {
+ //
+ // Free the previous allocated page
+ //
+ FreePages (
+ (VOID*)(UINTN)Smbios30EntryPointStructure->TableAddress,
+ mPre64BitAllocatedPages
+ );
+ Smbios30EntryPointStructure->TableAddress = 0;
+ mPre64BitAllocatedPages = 0;
+ }
+
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS 64-bit table\n"));
+ Smbios30EntryPointStructure->TableAddress = 0;
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ Smbios30EntryPointStructure->TableAddress = PhysicalAddress;
+ mPre64BitAllocatedPages = EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize);
+ }
+ }
+
+ //
+ // Assemble the tables
+ //
+ ASSERT (Smbios30EntryPointStructure->TableAddress != 0);
+ BufferPointer = (UINT8 *) (UINTN) Smbios30EntryPointStructure->TableAddress;
+ CurrentSmbiosEntry = NULL;
+ do {
+ Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
+
+ if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {
+ //
+ // This record can be added to 64-bit table
+ //
+ GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
+ CopyMem (BufferPointer, SmbiosRecord, RecordSize);
+ BufferPointer = BufferPointer + RecordSize;
+ }
+ } while (!EFI_ERROR(Status));
+
+ //
+ // Assemble End-Of-Table structure
+ //
+ CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
+
+ //
+ // Fixup checksums in the Entry Point Structure
+ //
+ Smbios30EntryPointStructure->EntryPointStructureChecksum = 0;
+ Smbios30EntryPointStructure->EntryPointStructureChecksum =
+ CalculateCheckSum8 ((UINT8 *) Smbios30EntryPointStructure, Smbios30EntryPointStructure->EntryPointLength);
+
+ //
+ // Returns the pointer
+ //
+ *TableEntryPointStructure = Smbios30EntryPointStructure;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create Smbios Table and installs the Smbios Table to the System Table.
+
+ @param Smbios32BitTable The flag to update 32-bit table.
+ @param Smbios64BitTable The flag to update 64-bit table.
+
+**/
+VOID
+EFIAPI
+SmbiosTableConstruction (
+ BOOLEAN Smbios32BitTable,
+ BOOLEAN Smbios64BitTable
+ )
+{
+ UINT8 *Eps;
+ UINT8 *Eps64Bit;
+ EFI_STATUS Status;
+
+ if (Smbios32BitTable) {
+ Status = SmbiosCreateTable ((VOID **) &Eps);
+ if (!EFI_ERROR (Status)) {
+ gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);
+ }
+ }
+
+ if (Smbios64BitTable) {
+ Status = SmbiosCreate64BitTable ((VOID **) &Eps64Bit);
+ if (!EFI_ERROR (Status)) {
+ gBS->InstallConfigurationTable (&gEfiSmbios3TableGuid, Eps64Bit);
+ }
+ }
+}
+
+/**
+
+ Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
+
+ @param ImageHandle Module's image handle
+ @param SystemTable Pointer of EFI_SYSTEM_TABLE
+
+ @retval EFI_SUCCESS Smbios protocol installed
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
+ mPrivateData.Smbios.Add = SmbiosAdd;
+ mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
+ mPrivateData.Smbios.Remove = SmbiosRemove;
+ mPrivateData.Smbios.GetNext = SmbiosGetNext;
+ mPrivateData.Smbios.MajorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);
+ mPrivateData.Smbios.MinorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);
+
+ InitializeListHead (&mPrivateData.DataListHead);
+ InitializeListHead (&mPrivateData.AllocatedHandleListHead);
+ EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
+
+ //
+ // Make a new handle and install the protocol
+ //
+ mPrivateData.Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEfiSmbiosProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.Smbios
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h
new file mode 100644
index 000000000..f97c85ae4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.h
@@ -0,0 +1,124 @@
+/** @file
+ This code supports the implementation of the Smbios protocol
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMBIOS_DXE_H_
+#define _SMBIOS_DXE_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/SmBios.h>
+#include <Guid/EventGroup.h>
+#include <Guid/SmBios.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/PcdLib.h>
+
+#define SMBIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('S', 'B', 'i', 's')
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ //
+ // Produced protocol
+ //
+ EFI_SMBIOS_PROTOCOL Smbios;
+ //
+ // Updates to record list must be locked.
+ //
+ EFI_LOCK DataLock;
+ //
+ // List of EFI_SMBIOS_ENTRY structures.
+ //
+ LIST_ENTRY DataListHead;
+ //
+ // List of allocated SMBIOS handle.
+ //
+ LIST_ENTRY AllocatedHandleListHead;
+} SMBIOS_INSTANCE;
+
+#define SMBIOS_INSTANCE_FROM_THIS(this) CR (this, SMBIOS_INSTANCE, Smbios, SMBIOS_INSTANCE_SIGNATURE)
+
+//
+// SMBIOS record Header
+//
+// An SMBIOS internal Record is an EFI_SMBIOS_RECORD_HEADER followed by (RecordSize - HeaderSize) bytes of
+// data. The format of the data is defined by the SMBIOS spec.
+//
+//
+#define EFI_SMBIOS_RECORD_HEADER_VERSION 0x0100
+typedef struct {
+ UINT16 Version;
+ UINT16 HeaderSize;
+ UINTN RecordSize;
+ EFI_HANDLE ProducerHandle;
+ UINTN NumberOfStrings;
+} EFI_SMBIOS_RECORD_HEADER;
+
+
+//
+// Private data structure to contain the SMBIOS record. One record per
+// structure. SmbiosRecord is a copy of the data passed in and follows RecordHeader .
+//
+#define EFI_SMBIOS_ENTRY_SIGNATURE SIGNATURE_32 ('S', 'r', 'e', 'c')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_SMBIOS_RECORD_HEADER *RecordHeader;
+ UINTN RecordSize;
+ //
+ // Indicate which table this record is added to.
+ //
+ BOOLEAN Smbios32BitTable;
+ BOOLEAN Smbios64BitTable;
+} EFI_SMBIOS_ENTRY;
+
+#define SMBIOS_ENTRY_FROM_LINK(link) CR (link, EFI_SMBIOS_ENTRY, Link, EFI_SMBIOS_ENTRY_SIGNATURE)
+
+//
+// Private data to contain the Smbios handle that already allocated.
+//
+#define SMBIOS_HANDLE_ENTRY_SIGNATURE SIGNATURE_32 ('S', 'h', 'r', 'd')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ //
+ // Filter driver will register what record guid filter should be used.
+ //
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+
+} SMBIOS_HANDLE_ENTRY;
+
+#define SMBIOS_HANDLE_ENTRY_FROM_LINK(link) CR (link, SMBIOS_HANDLE_ENTRY, Link, SMBIOS_HANDLE_ENTRY_SIGNATURE)
+
+typedef struct {
+ EFI_SMBIOS_TABLE_HEADER Header;
+ UINT8 Tailing[2];
+} EFI_SMBIOS_TABLE_END_STRUCTURE;
+
+/**
+ Create Smbios Table and installs the Smbios Table to the System Table.
+
+ @param Smbios32BitTable The flag to update 32-bit table.
+ @param Smbios64BitTable The flag to update 64-bit table.
+
+**/
+VOID
+EFIAPI
+SmbiosTableConstruction (
+ BOOLEAN Smbios32BitTable,
+ BOOLEAN Smbios64BitTable
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
new file mode 100644
index 000000000..f6c036e1d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
@@ -0,0 +1,61 @@
+## @file
+# This driver initializes and installs the SMBIOS protocol, constructs SMBIOS table into system configuration table.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmbiosDxe
+ MODULE_UNI_FILE = SmbiosDxe.uni
+ FILE_GUID = F9D88642-0737-49bc-81B5-6889CD57D9EA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = SmbiosDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+
+[Sources]
+ SmbiosDxe.h
+ SmbiosDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiSmbiosProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiSmbiosTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiSmbios3TableGuid ## SOMETIMES_PRODUCES ## SystemTable
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosEntryPointProvideMethod ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmbiosDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.uni b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.uni
new file mode 100644
index 000000000..b35cb37dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver initializes and installs the SMBIOS protocol, constructs SMBIOS table into system configuration table.
+//
+// This driver initializes and installs the SMBIOS protocol, and constructs SMBIOS table into the system configuration table.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes and installs the SMBIOS protocol, and constructs SMBIOS table into the system configuration table"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver initializes and installs the SMBIOS protocol, and constructs SMBIOS table into the system configuration table."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxeExtra.uni
new file mode 100644
index 000000000..67586c564
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmbiosDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMBIOS DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c
new file mode 100644
index 000000000..1050c9b17
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.c
@@ -0,0 +1,671 @@
+/** @file
+ This driver measures SMBIOS table to TPM.
+
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/SmBios.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Guid/EventGroup.h>
+#include <Guid/SmBios.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/PcdLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+#define FIELD_SIZE_OF(TYPE, Field) ((UINTN)sizeof(((TYPE *)0)->Field))
+
+typedef struct {
+ UINT8 Type;
+ UINTN Offset;
+ UINTN Size;
+ UINT32 Flags;
+} SMBIOS_FILTER_TABLE;
+#define SMBIOS_FILTER_TABLE_FLAG_IS_STRING BIT0
+
+typedef struct {
+ UINT8 Type;
+ SMBIOS_FILTER_TABLE *Filter; // NULL means all fields
+ UINTN FilterCount;
+} SMBIOS_FILTER_STRUCT;
+
+//
+// Platform Specific Policy
+//
+SMBIOS_FILTER_TABLE mSmbiosFilterType1BlackList[] = {
+ {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, Uuid), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, Uuid), 0},
+ {0x01, OFFSET_OF(SMBIOS_TABLE_TYPE1, WakeUpType), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE1, WakeUpType), 0},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType2BlackList[] = {
+ {0x02, OFFSET_OF(SMBIOS_TABLE_TYPE2, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE2, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x02, OFFSET_OF(SMBIOS_TABLE_TYPE2, LocationInChassis), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE2, LocationInChassis), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType3BlackList[] = {
+ {0x03, OFFSET_OF(SMBIOS_TABLE_TYPE3, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE3, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x03, OFFSET_OF(SMBIOS_TABLE_TYPE3, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE3, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType4BlackList[] = {
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, PartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, PartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, CoreCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, CoreCount), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, ThreadCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, ThreadCount), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, CoreCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, CoreCount2), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, EnabledCoreCount2), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, ThreadCount2), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, ThreadCount2), 0},
+ {0x04, OFFSET_OF(SMBIOS_TABLE_TYPE4, Voltage), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE4, Voltage), 0},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType17BlackList[] = {
+ {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, AssetTag), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, AssetTag), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x11, OFFSET_OF(SMBIOS_TABLE_TYPE17, PartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE17, PartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType22BlackList[] = {
+ {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SBDSSerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SBDSSerialNumber), 0},
+ {0x16, OFFSET_OF(SMBIOS_TABLE_TYPE22, SBDSManufactureDate), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE22, SBDSManufactureDate), 0},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType23BlackList[] = {
+ {0x17, OFFSET_OF(SMBIOS_TABLE_TYPE23, ResetCount), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE23, ResetCount), 0},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType27BlackList[] = {
+ {0x1B, OFFSET_OF(SMBIOS_TABLE_TYPE27, NominalSpeed), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE27, NominalSpeed), 0},
+};
+SMBIOS_FILTER_TABLE mSmbiosFilterType39BlackList[] = {
+ {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, SerialNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, SerialNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, AssetTagNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, AssetTagNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+ {0x27, OFFSET_OF(SMBIOS_TABLE_TYPE39, ModelPartNumber), FIELD_SIZE_OF(SMBIOS_TABLE_TYPE39, ModelPartNumber), SMBIOS_FILTER_TABLE_FLAG_IS_STRING},
+};
+
+SMBIOS_FILTER_STRUCT mSmbiosFilterStandardTableBlackList[] = {
+ {0x01, mSmbiosFilterType1BlackList, sizeof(mSmbiosFilterType1BlackList)/sizeof(mSmbiosFilterType1BlackList[0])},
+ {0x02, mSmbiosFilterType2BlackList, sizeof(mSmbiosFilterType2BlackList)/sizeof(mSmbiosFilterType2BlackList[0])},
+ {0x03, mSmbiosFilterType3BlackList, sizeof(mSmbiosFilterType3BlackList)/sizeof(mSmbiosFilterType3BlackList[0])},
+ {0x04, mSmbiosFilterType4BlackList, sizeof(mSmbiosFilterType4BlackList)/sizeof(mSmbiosFilterType4BlackList[0])},
+ {0x0B, NULL, 0},
+ {0x0F, NULL, 0},
+ {0x11, mSmbiosFilterType17BlackList, sizeof(mSmbiosFilterType17BlackList)/sizeof(mSmbiosFilterType17BlackList[0])},
+ {0x12, NULL, 0},
+ {0x16, mSmbiosFilterType22BlackList, sizeof(mSmbiosFilterType22BlackList)/sizeof(mSmbiosFilterType22BlackList[0])},
+ {0x17, mSmbiosFilterType23BlackList, sizeof(mSmbiosFilterType23BlackList)/sizeof(mSmbiosFilterType23BlackList[0])},
+ {0x1B, mSmbiosFilterType27BlackList, sizeof(mSmbiosFilterType27BlackList)/sizeof(mSmbiosFilterType27BlackList[0])},
+ {0x1F, NULL, 0},
+ {0x21, NULL, 0},
+ {0x27, mSmbiosFilterType39BlackList, sizeof(mSmbiosFilterType39BlackList)/sizeof(mSmbiosFilterType39BlackList[0])},
+};
+
+EFI_SMBIOS_PROTOCOL *mSmbios;
+UINTN mMaxLen;
+
+#pragma pack (1)
+
+#define SMBIOS_HANDOFF_TABLE_DESC "SmbiosTable"
+typedef struct {
+ UINT8 TableDescriptionSize;
+ UINT8 TableDescription[sizeof(SMBIOS_HANDOFF_TABLE_DESC)];
+ UINT64 NumberOfTables;
+ EFI_CONFIGURATION_TABLE TableEntry[1];
+} SMBIOS_HANDOFF_TABLE_POINTERS2;
+
+#pragma pack ()
+
+/**
+
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x", (UINTN)Data[Index]));
+ }
+}
+
+/**
+
+ This function dump raw data with colume format.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpHex (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN Left;
+
+#define COLUME_SIZE (16 * 2)
+
+ Count = Size / COLUME_SIZE;
+ Left = Size % COLUME_SIZE;
+ for (Index = 0; Index < Count; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ }
+
+ if (Left != 0) {
+ DEBUG ((EFI_D_VERBOSE, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, Left);
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ }
+}
+
+
+/**
+
+ This function get filter structure by SMBIOS type.
+
+ @param Type SMBIOS type
+
+**/
+SMBIOS_FILTER_STRUCT *
+GetFilterStructByType (
+ IN UINT8 Type
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof(mSmbiosFilterStandardTableBlackList)/sizeof(mSmbiosFilterStandardTableBlackList[0]); Index++) {
+ if (mSmbiosFilterStandardTableBlackList[Index].Type == Type) {
+ return &mSmbiosFilterStandardTableBlackList[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+
+ This function get SMBIOS string in SMBIOS table.
+
+ @param Head SMBIOS table head
+ @param StringId SMBIOS string ID
+ @param StringLen length of SMBIOS string
+
+ @return SMBIOS string data
+**/
+CHAR8 *
+GetSmbiosStringById (
+ IN EFI_SMBIOS_TABLE_HEADER *Head,
+ IN SMBIOS_TABLE_STRING StringId,
+ OUT UINTN *StringLen
+ )
+{
+ UINTN Size;
+ UINTN StrLen;
+ CHAR8 *CharInStr;
+ UINTN StringsNumber;
+ CHAR8 *String;
+
+ CharInStr = (CHAR8 *)Head + Head->Length;
+ Size = Head->Length;
+ StringsNumber = 0;
+ StrLen = 0;
+ //
+ // look for the two consecutive zeros, check the string limit by the way.
+ //
+ String = NULL;
+ while (*CharInStr != 0 || *(CharInStr+1) != 0) {
+ if (*CharInStr == 0) {
+ Size += 1;
+ CharInStr++;
+ }
+ String = CharInStr;
+
+ for (StrLen = 0 ; StrLen < mMaxLen; StrLen++) {
+ if (*(CharInStr+StrLen) == 0) {
+ break;
+ }
+ }
+ *StringLen = StrLen;
+
+ if (StrLen == mMaxLen) {
+ return NULL;
+ }
+
+ //
+ // forward the pointer
+ //
+ CharInStr += StrLen;
+ Size += StrLen;
+ StringsNumber += 1;
+ if (StringsNumber == StringId) {
+ break;
+ }
+ }
+
+ return String;
+}
+
+/**
+
+ This function update SMBIOS table based on policy.
+
+ @param TableEntry SMBIOS table
+ @param TableEntrySize SMBIOS table size
+
+**/
+VOID
+FilterSmbiosEntry (
+ IN OUT VOID *TableEntry,
+ IN UINTN TableEntrySize
+ )
+{
+ SMBIOS_FILTER_STRUCT *FilterStruct;
+ SMBIOS_FILTER_TABLE *Filter;
+ UINTN Index;
+ SMBIOS_TABLE_STRING StringId;
+ CHAR8 *String;
+ UINTN StringLen;
+
+ DEBUG ((EFI_D_INFO, "Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type));
+ DEBUG_CODE (InternalDumpHex (TableEntry, TableEntrySize););
+
+ //
+ // Skip measurement for OEM types.
+ //
+ if (((SMBIOS_STRUCTURE *)TableEntry)->Type >= SMBIOS_OEM_BEGIN) {
+ // zero all table fields, except header
+ ZeroMem ((UINT8 *)TableEntry + sizeof(SMBIOS_STRUCTURE), TableEntrySize - sizeof(SMBIOS_STRUCTURE));
+ } else {
+ FilterStruct = GetFilterStructByType (((SMBIOS_STRUCTURE *)TableEntry)->Type);
+ if (FilterStruct != NULL) {
+ if (FilterStruct->Filter == NULL || FilterStruct->FilterCount == 0) {
+ // zero all table fields, except header
+ ZeroMem ((UINT8 *)TableEntry + sizeof(SMBIOS_STRUCTURE), TableEntrySize - sizeof(SMBIOS_STRUCTURE));
+ } else {
+ Filter = FilterStruct->Filter;
+ for (Index = 0; Index < FilterStruct->FilterCount; Index++) {
+ if (((SMBIOS_STRUCTURE *) TableEntry)->Length >= (Filter[Index].Offset + Filter[Index].Size)) {
+ //
+ // The field is present in the SMBIOS entry.
+ //
+ if ((Filter[Index].Flags & SMBIOS_FILTER_TABLE_FLAG_IS_STRING) != 0) {
+ CopyMem (&StringId, (UINT8 *)TableEntry + Filter[Index].Offset, sizeof(StringId));
+ if (StringId != 0) {
+ // set ' ' for string field
+ String = GetSmbiosStringById (TableEntry, StringId, &StringLen);
+ ASSERT (String != NULL);
+ //DEBUG ((EFI_D_INFO,"StrId(0x%x)-%a(%d)\n", StringId, String, StringLen));
+ SetMem (String, StringLen, ' ');
+ }
+ }
+ // zero non-string field
+ ZeroMem ((UINT8 *)TableEntry + Filter[Index].Offset, Filter[Index].Size);
+ }
+ }
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Filter Smbios Table (Type - %d):\n", ((SMBIOS_STRUCTURE *)TableEntry)->Type));
+ DEBUG_CODE (InternalDumpHex (TableEntry, TableEntrySize););
+}
+
+/**
+
+ Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
+
+ @param Head Pointer to the beginning of SMBIOS structure.
+ @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
+
+ @return Size The returned size.
+**/
+UINTN
+GetSmbiosStructureSize (
+ IN EFI_SMBIOS_TABLE_HEADER *Head,
+ OUT UINTN *NumberOfStrings
+ )
+{
+ UINTN Size;
+ UINTN StrLen;
+ CHAR8 *CharInStr;
+ UINTN StringsNumber;
+
+ CharInStr = (CHAR8 *)Head + Head->Length;
+ Size = Head->Length;
+ StringsNumber = 0;
+ StrLen = 0;
+ //
+ // look for the two consecutive zeros, check the string limit by the way.
+ //
+ while (*CharInStr != 0 || *(CharInStr+1) != 0) {
+ if (*CharInStr == 0) {
+ Size += 1;
+ CharInStr++;
+ }
+
+ for (StrLen = 0 ; StrLen < mMaxLen; StrLen++) {
+ if (*(CharInStr+StrLen) == 0) {
+ break;
+ }
+ }
+
+ if (StrLen == mMaxLen) {
+ return 0;
+ }
+
+ //
+ // forward the pointer
+ //
+ CharInStr += StrLen;
+ Size += StrLen;
+ StringsNumber += 1;
+ }
+
+ //
+ // count ending two zeros.
+ //
+ Size += 2;
+
+ if (NumberOfStrings != NULL) {
+ *NumberOfStrings = StringsNumber;
+ }
+ return Size;
+}
+
+/**
+
+ This function returns full SMBIOS table length.
+
+ @param TableAddress SMBIOS table based address
+ @param TableMaximumSize Maximum size of SMBIOS table
+
+ @return SMBIOS table length
+
+**/
+UINTN
+GetSmbiosTableLength (
+ IN VOID *TableAddress,
+ IN UINTN TableMaximumSize
+ )
+{
+ VOID *TableEntry;
+ VOID *TableAddressEnd;
+ UINTN TableEntryLength;
+
+ TableAddressEnd = (VOID *)((UINTN)TableAddress + TableMaximumSize);
+ TableEntry = TableAddress;
+ while (TableEntry < TableAddressEnd) {
+ TableEntryLength = GetSmbiosStructureSize (TableEntry, NULL);
+ if (TableEntryLength == 0) {
+ break;
+ }
+ if (((SMBIOS_STRUCTURE *)TableEntry)->Type == 127) {
+ TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength);
+ break;
+ }
+ TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength);
+ }
+
+ return ((UINTN)TableEntry - (UINTN)TableAddress);
+}
+
+/**
+
+ This function updatess full SMBIOS table length.
+
+ @param TableAddress SMBIOS table based address
+ @param TableLength SMBIOS table length
+
+**/
+VOID
+FilterSmbiosTable (
+ IN OUT VOID *TableAddress,
+ IN UINTN TableLength
+ )
+{
+ VOID *TableAddressEnd;
+ VOID *TableEntry;
+ UINTN TableEntryLength;
+
+ TableEntry = TableAddress;
+ TableAddressEnd = (VOID *)((UINTN)TableAddress + TableLength);
+ while ((UINTN)TableEntry < (UINTN)TableAddressEnd) {
+ TableEntryLength = GetSmbiosStructureSize (TableEntry, NULL);
+ if (TableEntryLength == 0) {
+ break;
+ }
+
+ FilterSmbiosEntry (TableEntry, TableEntryLength);
+
+ TableEntry = (VOID *)((UINTN)TableEntry + TableEntryLength);
+ }
+}
+
+/**
+ Measure SMBIOS with EV_EFI_HANDOFF_TABLES to PCR[1].
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+MeasureSmbiosTable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDOFF_TABLE_POINTERS HandoffTables;
+ SMBIOS_HANDOFF_TABLE_POINTERS2 SmbiosHandoffTables2;
+ UINT32 EventType;
+ VOID *EventLog;
+ UINT32 EventLogSize;
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
+ SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios3Table;
+ VOID *SmbiosTableAddress;
+ VOID *TableAddress;
+ UINTN TableLength;
+
+ SmbiosTable = NULL;
+ Smbios3Table = NULL;
+ SmbiosTableAddress = NULL;
+ TableLength = 0;
+
+ if (mSmbios->MajorVersion >= 3) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiSmbios3TableGuid,
+ (VOID **) &Smbios3Table
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Smbios3Table:\n"));
+ DEBUG ((EFI_D_INFO, " AnchorString - '%c%c%c%c%c'\n",
+ Smbios3Table->AnchorString[0],
+ Smbios3Table->AnchorString[1],
+ Smbios3Table->AnchorString[2],
+ Smbios3Table->AnchorString[3],
+ Smbios3Table->AnchorString[4]
+ ));
+ DEBUG ((EFI_D_INFO, " EntryPointStructureChecksum - 0x%02x\n", Smbios3Table->EntryPointStructureChecksum));
+ DEBUG ((EFI_D_INFO, " EntryPointLength - 0x%02x\n", Smbios3Table->EntryPointLength));
+ DEBUG ((EFI_D_INFO, " MajorVersion - 0x%02x\n", Smbios3Table->MajorVersion));
+ DEBUG ((EFI_D_INFO, " MinorVersion - 0x%02x\n", Smbios3Table->MinorVersion));
+ DEBUG ((EFI_D_INFO, " DocRev - 0x%02x\n", Smbios3Table->DocRev));
+ DEBUG ((EFI_D_INFO, " EntryPointRevision - 0x%02x\n", Smbios3Table->EntryPointRevision));
+ DEBUG ((EFI_D_INFO, " TableMaximumSize - 0x%08x\n", Smbios3Table->TableMaximumSize));
+ DEBUG ((EFI_D_INFO, " TableAddress - 0x%016lx\n", Smbios3Table->TableAddress));
+ }
+ }
+
+ if (Smbios3Table == NULL) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiSmbiosTableGuid,
+ (VOID **) &SmbiosTable
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "SmbiosTable:\n"));
+ DEBUG ((EFI_D_INFO, " AnchorString - '%c%c%c%c'\n",
+ SmbiosTable->AnchorString[0],
+ SmbiosTable->AnchorString[1],
+ SmbiosTable->AnchorString[2],
+ SmbiosTable->AnchorString[3]
+ ));
+ DEBUG ((EFI_D_INFO, " EntryPointStructureChecksum - 0x%02x\n", SmbiosTable->EntryPointStructureChecksum));
+ DEBUG ((EFI_D_INFO, " EntryPointLength - 0x%02x\n", SmbiosTable->EntryPointLength));
+ DEBUG ((EFI_D_INFO, " MajorVersion - 0x%02x\n", SmbiosTable->MajorVersion));
+ DEBUG ((EFI_D_INFO, " MinorVersion - 0x%02x\n", SmbiosTable->MinorVersion));
+ DEBUG ((EFI_D_INFO, " MaxStructureSize - 0x%08x\n", SmbiosTable->MaxStructureSize));
+ DEBUG ((EFI_D_INFO, " EntryPointRevision - 0x%02x\n", SmbiosTable->EntryPointRevision));
+ DEBUG ((EFI_D_INFO, " FormattedArea - '%c%c%c%c%c'\n",
+ SmbiosTable->FormattedArea[0],
+ SmbiosTable->FormattedArea[1],
+ SmbiosTable->FormattedArea[2],
+ SmbiosTable->FormattedArea[3],
+ SmbiosTable->FormattedArea[4]
+ ));
+ DEBUG ((EFI_D_INFO, " IntermediateAnchorString - '%c%c%c%c%c'\n",
+ SmbiosTable->IntermediateAnchorString[0],
+ SmbiosTable->IntermediateAnchorString[1],
+ SmbiosTable->IntermediateAnchorString[2],
+ SmbiosTable->IntermediateAnchorString[3],
+ SmbiosTable->IntermediateAnchorString[4]
+ ));
+ DEBUG ((EFI_D_INFO, " IntermediateChecksum - 0x%02x\n", SmbiosTable->IntermediateChecksum));
+ DEBUG ((EFI_D_INFO, " TableLength - 0x%04x\n", SmbiosTable->TableLength));
+ DEBUG ((EFI_D_INFO, " TableAddress - 0x%08x\n", SmbiosTable->TableAddress));
+ DEBUG ((EFI_D_INFO, " NumberOfSmbiosStructures - 0x%04x\n", SmbiosTable->NumberOfSmbiosStructures));
+ DEBUG ((EFI_D_INFO, " SmbiosBcdRevision - 0x%02x\n", SmbiosTable->SmbiosBcdRevision));
+ }
+ }
+
+ if (Smbios3Table != NULL) {
+ SmbiosTableAddress = (VOID *)(UINTN)Smbios3Table->TableAddress;
+ TableLength = GetSmbiosTableLength (SmbiosTableAddress, Smbios3Table->TableMaximumSize);
+ } else if (SmbiosTable != NULL) {
+ SmbiosTableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress;
+ TableLength = SmbiosTable->TableLength;
+ }
+
+ if (SmbiosTableAddress != NULL) {
+ DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTableAddress));
+ DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", TableLength));
+ DEBUG_CODE (InternalDumpHex ((UINT8 *)(UINTN)SmbiosTableAddress, TableLength););
+
+ TableAddress = AllocateCopyPool ((UINTN)TableLength, (VOID *)(UINTN)SmbiosTableAddress);
+ if (TableAddress == NULL) {
+ return ;
+ }
+
+ FilterSmbiosTable (TableAddress, TableLength);
+
+ DEBUG ((DEBUG_INFO, "The final Smbios Table starts at: 0x%x\n", TableAddress));
+ DEBUG ((DEBUG_INFO, "The final Smbios Table size: 0x%x\n", TableLength));
+ DEBUG_CODE (InternalDumpHex (TableAddress, TableLength););
+
+ HandoffTables.NumberOfTables = 1;
+ if (Smbios3Table != NULL) {
+ CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gEfiSmbios3TableGuid);
+ HandoffTables.TableEntry[0].VendorTable = Smbios3Table;
+ } else {
+ CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gEfiSmbiosTableGuid);
+ HandoffTables.TableEntry[0].VendorTable = SmbiosTable;
+ }
+ EventType = EV_EFI_HANDOFF_TABLES;
+ EventLog = &HandoffTables;
+ EventLogSize = sizeof (HandoffTables);
+
+ if (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105) {
+ SmbiosHandoffTables2.TableDescriptionSize = sizeof(SmbiosHandoffTables2.TableDescription);
+ CopyMem (SmbiosHandoffTables2.TableDescription, SMBIOS_HANDOFF_TABLE_DESC, sizeof(SmbiosHandoffTables2.TableDescription));
+ SmbiosHandoffTables2.NumberOfTables = HandoffTables.NumberOfTables;
+ CopyMem (&(SmbiosHandoffTables2.TableEntry[0]), &(HandoffTables.TableEntry[0]), sizeof(SmbiosHandoffTables2.TableEntry[0]));
+ EventType = EV_EFI_HANDOFF_TABLES2;
+ EventLog = &SmbiosHandoffTables2;
+ EventLogSize = sizeof (SmbiosHandoffTables2);
+ }
+ Status = TpmMeasureAndLogData (
+ 1, // PCRIndex
+ EventType, // EventType
+ EventLog, // EventLog
+ EventLogSize, // LogLen
+ TableAddress, // HashData
+ TableLength // HashDataLen
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseEvent (Event) ;
+ }
+ }
+
+ return ;
+}
+
+/**
+
+ Driver to produce Smbios measurement.
+
+ @param ImageHandle Module's image handle
+ @param SystemTable Pointer of EFI_SYSTEM_TABLE
+
+ @return Status returned from EfiCreateEventReadyToBootEx().
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosMeasurementDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "The Smbios Table Version: %x.%x\n", mSmbios->MajorVersion, mSmbios->MinorVersion));
+
+ if (mSmbios->MajorVersion < 2 || (mSmbios->MajorVersion == 2 && mSmbios->MinorVersion < 7)){
+ mMaxLen = SMBIOS_STRING_MAX_LENGTH;
+ } else if (mSmbios->MajorVersion < 3) {
+ //
+ // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
+ // However, the length of the entire structure table (including all strings) must be reported
+ // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
+ // which is a WORD field limited to 65,535 bytes.
+ //
+ mMaxLen = SMBIOS_TABLE_MAX_LENGTH;
+ } else {
+ //
+ // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.
+ // Locate the end of string as long as possible.
+ //
+ mMaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;
+ }
+
+ //
+ // Measure Smbios tables
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ MeasureSmbiosTable,
+ NULL,
+ &Event
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf
new file mode 100644
index 000000000..7537bfb51
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.inf
@@ -0,0 +1,68 @@
+## @file
+# This driver measures SMBIOS table to TPM.
+#
+# This driver is a sample driver to follow TCG platform specification to
+# filter some fields in SMBIOS table.
+# - Platform configuration information that is automatically updated,
+# such as clock registers, and system unique information, such as
+# asset numbers or serial numbers, MUST NOT be measured into PCR [1],
+# or any other PCR.
+# The OEM types are skipped and platform code can measure them by self if required.
+#
+# A platform may use its own policy to filter some fields in SMBIOS table.
+#
+# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmbiosMeasurementDxe
+ MODULE_UNI_FILE = SmbiosMeasurementDxe.uni
+ FILE_GUID = D27FED59-ABB4-4FED-BEAD-2A878C7E4A7E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmbiosMeasurementDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+
+[Sources]
+ SmbiosMeasurementDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ TpmMeasurementLib
+
+[Protocols]
+ gEfiSmbiosProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES
+
+[Depex]
+ gEfiSmbiosProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmbiosMeasurementDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni
new file mode 100644
index 000000000..cb4cbd36f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This driver measures SMBIOS table to TPM.
+//
+// This driver calculates SMBIOS table based on default policy and calls TPM interface to measure the updated SMBIOS table.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "This driver measures SMBIOS table to TPM."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver calculates SMBIOS table based on default policy and calls TPM interface to measure the updated SMBIOS table."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni
new file mode 100644
index 000000000..3709aaae7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmbiosMeasurementDxe/SmbiosMeasurementDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// SmbiosMeasurementDxe Localized Strings and Content
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMBIOS Measurement DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c
new file mode 100644
index 000000000..9a5dbb272
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c
@@ -0,0 +1,92 @@
+/** @file
+A driver allocates common SMM communication buffer in EfiReservedMemoryType.
+
+This driver allocates common SMM communication buffer in EfiReservedMemoryType,
+then it publishes the information to EFI configuration table with
+gEdkiiPiSmmCommunicationRegionTableGuid.
+Any other driver or application can get the table and know the common
+communication buffer.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#define DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES 4
+
+/**
+ Entry Point for SMM communication buffer driver.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+SmmCommunicationBufferEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DescriptorSize;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+
+ DescriptorSize = sizeof(EFI_MEMORY_DESCRIPTOR);
+ //
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ DescriptorSize += sizeof(UINT64) - (DescriptorSize % sizeof (UINT64));
+
+ //
+ // Allocate and fill PiSmmCommunicationRegionTable
+ //
+ PiSmmCommunicationRegionTable = AllocateReservedPool (sizeof(EDKII_PI_SMM_COMMUNICATION_REGION_TABLE) + DescriptorSize);
+ ASSERT(PiSmmCommunicationRegionTable != NULL);
+ ZeroMem (PiSmmCommunicationRegionTable, sizeof(EDKII_PI_SMM_COMMUNICATION_REGION_TABLE) + DescriptorSize);
+
+ PiSmmCommunicationRegionTable->Version = EDKII_PI_SMM_COMMUNICATION_REGION_TABLE_VERSION;
+ PiSmmCommunicationRegionTable->NumberOfEntries = 1;
+ PiSmmCommunicationRegionTable->DescriptorSize = DescriptorSize;
+ Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1);
+ Entry->Type = EfiConventionalMemory;
+ Entry->PhysicalStart = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES);
+ ASSERT(Entry->PhysicalStart != 0);
+ Entry->VirtualStart = 0;
+ Entry->NumberOfPages = DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES;
+ Entry->Attribute = 0;
+
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationRegionTable:(0x%x)\n", PiSmmCommunicationRegionTable));
+ DEBUG ((EFI_D_INFO, " Version - 0x%x\n", PiSmmCommunicationRegionTable->Version));
+ DEBUG ((EFI_D_INFO, " NumberOfEntries - 0x%x\n", PiSmmCommunicationRegionTable->NumberOfEntries));
+ DEBUG ((EFI_D_INFO, " DescriptorSize - 0x%x\n", PiSmmCommunicationRegionTable->DescriptorSize));
+ DEBUG ((EFI_D_INFO, "Entry:(0x%x)\n", Entry));
+ DEBUG ((EFI_D_INFO, " Type - 0x%x\n", Entry->Type));
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%lx\n", Entry->PhysicalStart));
+ DEBUG ((EFI_D_INFO, " VirtualStart - 0x%lx\n", Entry->VirtualStart));
+ DEBUG ((EFI_D_INFO, " NumberOfPages - 0x%lx\n", Entry->NumberOfPages));
+ DEBUG ((EFI_D_INFO, " Attribute - 0x%lx\n", Entry->Attribute));
+
+ //
+ // Publish this table, so that other driver can use the buffer.
+ //
+ Status = gBS->InstallConfigurationTable (&gEdkiiPiSmmCommunicationRegionTableGuid, PiSmmCommunicationRegionTable);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
new file mode 100644
index 000000000..5c867ba1d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# A driver allocates common SMM communication buffer in EfiReservedMemoryType.
+#
+# This driver allocates common SMM communication buffer in EfiReservedMemoryType,
+# then it publishes the information to EFI configuration table with
+# gEdkiiPiSmmCommunicationRegionTableGuid.
+# Any other driver or application can get the table and know the common
+# communication buffer.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCommunicationBufferDxe
+ MODULE_UNI_FILE = SmmCommunicationBufferDxe.uni
+ FILE_GUID = 8FAAD0A7-02B4-432F-8F5C-B880965D8B41
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmCommunicationBufferEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCommunicationBufferDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ HobLib
+ DebugLib
+
+[Guids]
+ gEdkiiPiSmmCommunicationRegionTableGuid ## PRODUCES ## SystemTable
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmmCommunicationBufferExtraDxe.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.uni b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.uni
new file mode 100644
index 000000000..de047d406
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// A driver allocates common SMM communication buffer in EfiReservedMemoryType.
+//
+// This driver allocates common SMM communication buffer in EfiReservedMemoryType,
+// then it publishes the information to EFI configuration table with
+// gEdkiiPiSmmCommunicationRegionTableGuid.
+// Any other driver or application can get the table and know the common
+// communication buffer.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "A driver allocates common SMM communication buffer in EfiReservedMemoryType."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver allocates common SMM communication buffer in EfiReservedMemoryType, then it publishes the information to EFI configuration table with gEdkiiPiSmmCommunicationRegionTableGuid. Any other driver or application can get the table and know the common communication buffer."
diff --git a/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferExtraDxe.uni b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferExtraDxe.uni
new file mode 100644
index 000000000..3e96020f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferExtraDxe.uni
@@ -0,0 +1,12 @@
+// /** @file
+// SmmCommunicationBuffer Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM Communication Buffer DXE Driver"
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/MemoryStausCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/MemoryStausCodeWorker.c
new file mode 100644
index 000000000..6c116707f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/MemoryStausCodeWorker.c
@@ -0,0 +1,121 @@
+/** @file
+ PEI memory status code worker.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerPei.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 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 always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryStatusCodeReportWorker (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+
+ 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/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
new file mode 100644
index 000000000..3aa5642b6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
@@ -0,0 +1,161 @@
+/** @file
+ Serial I/O status code reporting worker.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "StatusCodeHandlerPei.h"
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @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 Status code reported to serial I/O successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialStatusCodeReportWorker (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ CHAR8 *Filename;
+ CHAR8 *Description;
+ CHAR8 *Format;
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+ 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
+ );
+
+ ASSERT(CharCount > 0);
+
+ 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",
+ ((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/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
new file mode 100644
index 000000000..9b2ea4ee8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
@@ -0,0 +1,63 @@
+/** @file
+ Report Status Code Handler PEIM which produces general handlers and hook them
+ onto the PEI status code router.
+
+ Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerPei.h"
+
+/**
+ 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
+StatusCodeHandlerPeiEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RSC_HANDLER_PPI *RscHandlerPpi;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiRscHandlerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &RscHandlerPpi
+ );
+ ASSERT_EFI_ERROR (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 (PcdGetBool (PcdStatusCodeUseSerial)) {
+ Status = SerialPortInitialize();
+ ASSERT_EFI_ERROR (Status);
+ Status = RscHandlerPpi->Register (SerialStatusCodeReportWorker);
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ Status = MemoryStatusCodeInitializeWorker ();
+ ASSERT_EFI_ERROR (Status);
+ Status = RscHandlerPpi->Register (MemoryStatusCodeReportWorker);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.h b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.h
new file mode 100644
index 000000000..34901f29e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.h
@@ -0,0 +1,119 @@
+/** @file
+ Internal include file for Status Code Handler PEIM.
+
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __STATUS_CODE_HANDLER_PEI_H__
+#define __STATUS_CODE_HANDLER_PEI_H__
+
+
+#include <Ppi/ReportStatusCodeHandler.h>
+
+#include <Guid/MemoryStatusCodeRecord.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.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/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+
+//
+// Define the maximum message length
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @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 Status code reported to serial I/O successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialStatusCodeReportWorker (
+ 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,
+ 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 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 always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryStatusCodeReportWorker (
+ 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,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+#endif
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
new file mode 100644
index 000000000..64380ddfa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
@@ -0,0 +1,65 @@
+## @file
+# Report Status Code Handler PEIM which produces general handlers and hook them onto the PEI status code router.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StatusCodeHandlerPei
+ MODULE_UNI_FILE = StatusCodeHandlerPei.uni
+ FILE_GUID = 9D225237-FA01-464C-A949-BAABC02D31D0
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = StatusCodeHandlerPeiEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is only for build)
+#
+
+[Sources]
+ StatusCodeHandlerPei.c
+ StatusCodeHandlerPei.h
+ SerialStatusCodeWorker.c
+ MemoryStausCodeWorker.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ PcdLib
+ HobLib
+ SerialPortLib
+ ReportStatusCodeLib
+ PrintLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gMemoryStatusCodeRecordGuid
+ gEfiStatusCodeDataTypeStringGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Ppis]
+ gEfiPeiRscHandlerPpiGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiRscHandlerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ StatusCodeHandlerPeiExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.uni
new file mode 100644
index 000000000..6464cb9fe
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Report Status Code Handler PEIM which produces general handlers and hook them onto the PEI status code router.
+//
+// This is the Report Status Code Handler PEIM that produces general handlers and hooks them onto the PEI status code router.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PEIM that produces general handlers and hooks them onto the PEI status code router"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is the Report Status Code Handler PEIM that produces general handlers and hooks them onto the PEI status code router."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPeiExtra.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPeiExtra.uni
new file mode 100644
index 000000000..6ee6903ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// StatusCodeHandlerPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Handler PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/MemoryStatusCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/MemoryStatusCodeWorker.c
new file mode 100644
index 000000000..9a3431b26
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/MemoryStatusCodeWorker.c
@@ -0,0 +1,110 @@
+/** @file
+ Runtime memory status code worker.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerRuntimeDxe.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.
+ @retval others Errors from gBS->InstallConfigurationTable().
+
+**/
+EFI_STATUS
+RtMemoryStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // 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);
+ Status = gBS->InstallConfigurationTable (&gMemoryStatusCodeRecordGuid, mRtMemoryStatusCodeTable);
+
+ return Status;
+}
+
+
+/**
+ 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.
+ @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 successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+EFIAPI
+RtMemoryStatusCodeReportWorker (
+ 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
+ )
+{
+ 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/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCodeWorker.c
new file mode 100644
index 000000000..0b98e7ec6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCodeWorker.c
@@ -0,0 +1,156 @@
+/** @file
+ Serial I/O status code reporting worker.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerRuntimeDxe.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
+EFIAPI
+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[MAX_DEBUG_MESSAGE_LENGTH];
+ 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
+ );
+ ASSERT (CharCount > 0);
+
+ 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",
+ ((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/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.c
new file mode 100644
index 000000000..a8c0fe5b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.c
@@ -0,0 +1,201 @@
+/** @file
+ Status Code Handler Driver which produces general handlers and hook them
+ onto the DXE status code router.
+
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerRuntimeDxe.h"
+
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+static 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
+ )
+{
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
+ mRscHandlerProtocol->Unregister (SerialStatusCodeReportWorker);
+ }
+}
+
+/**
+ 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 (PcdGetBool (PcdStatusCodeUseSerial)) {
+ //
+ // Call Serial Port Lib API to initialize serial port.
+ //
+ Status = SerialPortInitialize ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ Status = RtMemoryStatusCodeInitializeWorker ();
+ 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 (PcdGetBool (PcdStatusCodeUseSerial)) {
+ SerialStatusCodeReportWorker (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance,
+ NULL,
+ NULL
+ );
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ RtMemoryStatusCodeReportWorker (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance,
+ NULL,
+ NULL
+ );
+ }
+ }
+ }
+ }
+}
+
+/**
+ 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
+StatusCodeHandlerRuntimeDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gEfiRscHandlerProtocolGuid,
+ NULL,
+ (VOID **) &mRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch initialization request to supported devices
+ //
+ InitializationDispatcherWorker ();
+
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
+ mRscHandlerProtocol->Register (SerialStatusCodeReportWorker, TPL_HIGH_LEVEL);
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ mRscHandlerProtocol->Register (RtMemoryStatusCodeReportWorker, TPL_HIGH_LEVEL);
+ }
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UnregisterBootTimeHandlers,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServicesEvent
+ );
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualAddressChangeCallBack,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.h b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.h
new file mode 100644
index 000000000..fd4689c2d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.h
@@ -0,0 +1,121 @@
+/** @file
+ Internal include file for Status Code Handler Driver.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __STATUS_CODE_HANDLER_RUNTIME_DXE_H__
+#define __STATUS_CODE_HANDLER_RUNTIME_DXE_H__
+
+#include <Protocol/ReportStatusCodeHandler.h>
+
+#include <Guid/MemoryStatusCodeRecord.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/EventGroup.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/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/SerialPortLib.h>
+
+//
+// Define the maximum message length
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+extern RUNTIME_MEMORY_STATUSCODE_HEADER *mRtMemoryStatusCodeTable;
+
+/**
+ 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
+EFIAPI
+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.
+ @retval others Errors from gBS->InstallConfigurationTable().
+
+**/
+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.
+ @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 successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+EFIAPI
+RtMemoryStatusCodeReportWorker (
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
new file mode 100644
index 000000000..faadfd957
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# Status Code Handler Driver which produces general handlers and hook them onto the DXE status code router.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StatusCodeHandlerRuntimeDxe
+ MODULE_UNI_FILE = StatusCodeHandlerRuntimeDxe.uni
+ FILE_GUID = 6C2004EF-4E0E-4BE4-B14C-340EB4AA5891
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = StatusCodeHandlerRuntimeDxeEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ StatusCodeHandlerRuntimeDxe.c
+ StatusCodeHandlerRuntimeDxe.h
+ SerialStatusCodeWorker.c
+ MemoryStatusCodeWorker.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SerialPortLib
+ UefiRuntimeLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ HobLib
+ PcdLib
+ PrintLib
+ ReportStatusCodeLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gMemoryStatusCodeRecordGuid
+ gEfiStatusCodeDataTypeStringGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiRscHandlerProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeReplayIn ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize |128| gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ StatusCodeHandlerRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.uni
new file mode 100644
index 000000000..a886049e8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Status Code Handler Driver which produces general handlers and hook them onto the DXE status code router.
+//
+// The Status Code Handler Driver that produces general handlers and hooks them onto the DXE status code router.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces general handlers and hooks them onto the DXE status code router"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The Status Code Handler Driver that produces general handlers and hooks them onto the DXE status code router."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxeExtra.uni
new file mode 100644
index 000000000..c5ed8a260
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// StatusCodeHandlerRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Handler DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/MemoryStatusCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/MemoryStatusCodeWorker.c
new file mode 100644
index 000000000..c9b43fd24
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/MemoryStatusCodeWorker.c
@@ -0,0 +1,107 @@
+/** @file
+ Runtime memory status code worker.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerSmm.h"
+
+RUNTIME_MEMORY_STATUSCODE_HEADER *mSmmMemoryStatusCodeTable;
+
+/**
+ Initialize SMM memory status code table as initialization for memory status code worker
+
+ @retval EFI_SUCCESS SMM memory status code table successfully initialized.
+ @retval others Errors from gSmst->SmmInstallConfigurationTable().
+**/
+EFI_STATUS
+MemoryStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Allocate SMM memory status code pool.
+ //
+ mSmmMemoryStatusCodeTable = (RUNTIME_MEMORY_STATUSCODE_HEADER *)AllocateZeroPool (sizeof (RUNTIME_MEMORY_STATUSCODE_HEADER) + PcdGet16 (PcdStatusCodeMemorySize) * 1024);
+ ASSERT (mSmmMemoryStatusCodeTable != NULL);
+
+ mSmmMemoryStatusCodeTable->MaxRecordsNumber = (PcdGet16 (PcdStatusCodeMemorySize) * 1024) / sizeof (MEMORY_STATUSCODE_RECORD);
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gMemoryStatusCodeRecordGuid,
+ &mSmmMemoryStatusCodeTable,
+ sizeof (mSmmMemoryStatusCodeTable)
+ );
+ return Status;
+}
+
+
+/**
+ 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.
+ @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 successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryStatusCodeReportWorker (
+ 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
+ )
+{
+ MEMORY_STATUSCODE_RECORD *Record;
+
+ //
+ // Locate current record buffer.
+ //
+ Record = (MEMORY_STATUSCODE_RECORD *) (mSmmMemoryStatusCodeTable + 1);
+ Record = &Record[mSmmMemoryStatusCodeTable->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.
+ //
+ mSmmMemoryStatusCodeTable->NumberOfRecords++;
+ if (mSmmMemoryStatusCodeTable->RecordIndex == mSmmMemoryStatusCodeTable->MaxRecordsNumber) {
+ //
+ // Wrap around record index.
+ //
+ mSmmMemoryStatusCodeTable->RecordIndex = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.c
new file mode 100644
index 000000000..3df0a6712
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.c
@@ -0,0 +1,156 @@
+/** @file
+ Serial I/O status code reporting worker.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerSmm.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
+EFIAPI
+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[MAX_DEBUG_MESSAGE_LENGTH];
+ 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
+ );
+ ASSERT (CharCount > 0);
+
+ 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",
+ ((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/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.c b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.c
new file mode 100644
index 000000000..20271571d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.c
@@ -0,0 +1,84 @@
+/** @file
+ Status Code Handler Driver which produces general handlers and hook them
+ onto the SMM status code router.
+
+ Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StatusCodeHandlerSmm.h"
+
+EFI_SMM_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+
+
+/**
+ Dispatch initialization request to sub status code devices based on
+ customized feature flags.
+
+**/
+VOID
+InitializationDispatcherWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If enable UseSerial, then initialize serial port.
+ // if enable UseRuntimeMemory, then initialize runtime memory status code worker.
+ //
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
+ //
+ // Call Serial Port Lib API to initialize serial port.
+ //
+ Status = SerialPortInitialize ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ Status = MemoryStatusCodeInitializeWorker ();
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Entry point of SMM Status Code Driver.
+
+ This function is the entry point of SMM Status Code Driver.
+
+ @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
+StatusCodeHandlerSmmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmRscHandlerProtocolGuid,
+ NULL,
+ (VOID **) &mRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch initialization request to supported devices
+ //
+ InitializationDispatcherWorker ();
+
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
+ mRscHandlerProtocol->Register (SerialStatusCodeReportWorker);
+ }
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
+ mRscHandlerProtocol->Register (MemoryStatusCodeReportWorker);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.h b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.h
new file mode 100644
index 000000000..6b5d53a4f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.h
@@ -0,0 +1,117 @@
+/** @file
+ Internal include file for Status Code Handler Driver.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __STATUS_CODE_HANDLER_SMM_H__
+#define __STATUS_CODE_HANDLER_SMM_H__
+
+#include <Protocol/SmmReportStatusCodeHandler.h>
+
+#include <Guid/MemoryStatusCodeRecord.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+#include <Library/SynchronizationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+//
+// Define the maximum message length
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+extern RUNTIME_MEMORY_STATUSCODE_HEADER *mSmmMemoryStatusCodeTable;
+
+/**
+ 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
+EFIAPI
+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
+MemoryStatusCodeInitializeWorker (
+ 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.
+ @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 successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryStatusCodeReportWorker (
+ 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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
new file mode 100644
index 000000000..4e24d87e5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
@@ -0,0 +1,65 @@
+## @file
+# Status Code Handler Driver which produces general handlers and hook them onto the SMM status code router.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StatusCodeHandlerSmm
+ MODULE_UNI_FILE = StatusCodeHandlerSmm.uni
+ FILE_GUID = 79CD78D8-6EDC-4978-BD02-3299C387AB17
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ VERSION_STRING = 1.0
+ ENTRY_POINT = StatusCodeHandlerSmmEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ StatusCodeHandlerSmm.c
+ StatusCodeHandlerSmm.h
+ SerialStatusCodeWorker.c
+ MemoryStatusCodeWorker.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SerialPortLib
+ SmmServicesTableLib
+ UefiDriverEntryPoint
+ PcdLib
+ PrintLib
+ ReportStatusCodeLib
+ DebugLib
+ MemoryAllocationLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiStatusCodeDataTypeStringGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gMemoryStatusCodeRecordGuid ## SOMETIMES_PRODUCES ## UNDEFINED # SmmSystemTable
+
+[Protocols]
+ gEfiSmmRscHandlerProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize |128| gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiSmmRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ StatusCodeHandlerSmmExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.uni
new file mode 100644
index 000000000..fa568441b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Status Code Handler Driver which produces general handlers and hook them onto the SMM status code router.
+//
+// This is the Status Code Handler Driver that produces general handlers and hooks them onto the SMM status code router.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces general handlers and hooks them onto the SMM status code router"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is the Status Code Handler Driver that produces general handlers and hooks them onto the SMM status code router."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmmExtra.uni b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmmExtra.uni
new file mode 100644
index 000000000..d861e36e2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmmExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// StatusCodeHandlerSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Status Code Handler SMM Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.c b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.c
new file mode 100644
index 000000000..2ca4ae5cd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.c
@@ -0,0 +1,160 @@
+/** @file
+ Implementation of Timestamp Protocol using UEFI APIs.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/Timestamp.h>
+
+//
+// The StartValue in TimerLib
+//
+UINT64 mTimerLibStartValue = 0;
+
+//
+// The EndValue in TimerLib
+//
+UINT64 mTimerLibEndValue = 0;
+
+//
+// The properties of timestamp
+//
+EFI_TIMESTAMP_PROPERTIES mTimestampProperties = {
+ 0,
+ 0
+};
+
+/**
+ Retrieves the current value of a 64-bit free running timestamp counter.
+
+ The counter shall count up in proportion to the amount of time that has passed. The counter value
+ will always roll over to zero. The properties of the counter can be retrieved from GetProperties().
+ The caller should be prepared for the function to return the same value twice across successive calls.
+ The counter value will not go backwards other than when wrapping, as defined by EndValue in GetProperties().
+ The frequency of the returned timestamp counter value must remain constant. Power management operations that
+ affect clocking must not change the returned counter frequency. The quantization of counter value updates may
+ vary as long as the value reflecting time passed remains consistent.
+
+ @retval The current value of the free running timestamp counter.
+
+**/
+UINT64
+EFIAPI
+TimestampDriverGetTimestamp (
+ VOID
+ )
+{
+ //
+ // The timestamp of Timestamp Protocol
+ //
+ UINT64 TimestampValue;
+ TimestampValue = 0;
+
+ //
+ // Get the timestamp
+ //
+ if (mTimerLibStartValue > mTimerLibEndValue) {
+ TimestampValue = mTimerLibStartValue - GetPerformanceCounter();
+ } else {
+ TimestampValue = GetPerformanceCounter() - mTimerLibStartValue;
+ }
+
+ return TimestampValue;
+}
+
+/**
+ Obtains timestamp counter properties including frequency and value limits.
+
+ @param[out] Properties The properties of the timestamp counter.
+
+ @retval EFI_SUCCESS The properties were successfully retrieved.
+ @retval EFI_DEVICE_ERROR An error occurred trying to retrieve the properties of the timestamp
+ counter subsystem. Properties is not pedated.
+ @retval EFI_INVALID_PARAMETER Properties is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TimestampDriverGetProperties(
+ OUT EFI_TIMESTAMP_PROPERTIES *Properties
+ )
+{
+ if (Properties == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get timestamp properties
+ //
+ CopyMem((VOID *) Properties, (VOID *) &mTimestampProperties, sizeof (mTimestampProperties));
+
+ return EFI_SUCCESS;
+}
+
+//
+// The Timestamp Protocol instance produced by this driver
+//
+EFI_TIMESTAMP_PROTOCOL mTimestamp = {
+ TimestampDriverGetTimestamp,
+ TimestampDriverGetProperties
+};
+
+/**
+ Entry point of the Timestamp Protocol driver.
+
+ @param ImageHandle The image handle of this driver.
+ @param SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Watchdog Timer Architectural Protocol successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+TimestampDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ EFI_HANDLE TimestampHandle;
+ TimestampHandle = NULL;
+
+ //
+ // Get the start value, end value and frequency in Timerlib
+ //
+ mTimestampProperties.Frequency = GetPerformanceCounterProperties(&mTimerLibStartValue, &mTimerLibEndValue);
+
+ //
+ // Set the EndValue
+ //
+ if (mTimerLibEndValue > mTimerLibStartValue) {
+ mTimestampProperties.EndValue = mTimerLibEndValue - mTimerLibStartValue;
+ } else {
+ mTimestampProperties.EndValue = mTimerLibStartValue - mTimerLibEndValue;
+ }
+
+ DEBUG ((EFI_D_INFO, "TimerFrequency:0x%lx, TimerLibStartTime:0x%lx, TimerLibEndtime:0x%lx\n", mTimestampProperties.Frequency, mTimerLibStartValue, mTimerLibEndValue));
+
+ //
+ // Install the Timestamp Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &TimestampHandle,
+ &gEfiTimestampProtocolGuid,
+ &mTimestamp,
+ NULL
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf
new file mode 100644
index 000000000..13825bcae
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf
@@ -0,0 +1,46 @@
+## @file
+# Generic Timestamp driver producing Timestamp Protocol using UEFI APIs.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TimestampDxe
+ MODULE_UNI_FILE = TimestampDxe.uni
+ FILE_GUID = C10194E7-DEB2-4AF4-9EEE-BFFDE4D7D4C7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TimestampDriverInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Sources]
+ TimestampDxe.c
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ BaseMemoryLib
+ DebugLib
+
+[Protocols]
+ gEfiTimestampProtocolGuid ## PRODUCES
+
+[depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TimestampDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.uni b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.uni
new file mode 100644
index 000000000..1ae482aca
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Generic Timestamp driver producing Timestamp Protocol using UEFI APIs.
+//
+// A generic Timestamp driver producing Timestamp Protocol using UEFI APIs.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
+
+#string STR_MODULE_DESCRIPTION #language en-US "A generic Timestamp driver producing Timestamp Protocol using UEFI APIs."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxeExtra.uni
new file mode 100644
index 000000000..619cadf33
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/TimestampDxe/TimestampDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// TimestampDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Timestamp DXE Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni
new file mode 100644
index 000000000..106c1dfdc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni
new file mode 100644
index 000000000..22dd992be
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PeiVariable Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Variable Access PEI Module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.c b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.c
new file mode 100644
index 000000000..f420b5816
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -0,0 +1,1231 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Variable.h"
+
+//
+// Module globals
+//
+EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
+ PeiGetVariable,
+ PeiGetNextVariableName
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ &mVariablePpi
+};
+
+
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return PeiServicesInstallPpi (&mPpiListVariable);
+}
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The start of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This code gets the size of variable header.
+
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ if (AuthFlag) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+/**
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->NameSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+ }
+}
+
+
+/**
+ This code gets the size of data of variable.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->DataSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+ }
+}
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param Variable Pointer to the Variable Header.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable, AuthFlag);
+ Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+ return (UINT8 *) Value;
+}
+
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN Value;
+
+ Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+ Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = HEADER_ALIGN (Value);
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) {
+ //
+ // Next variable is in spare block.
+ //
+ Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress);
+ }
+ }
+
+ return (VARIABLE_HEADER *) Value;
+}
+
+/**
+ Get variable store status.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ }
+
+ if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Name1 Pointer to one variable name.
+ @param Name2 Pointer to another variable name.
+ @param NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialNameSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name1 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name2 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the variable in our database
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param VariableName Name of the variable to compare to 'Variable'
+ @param VendorGuid GUID of the variable to compare to 'Variable'
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VOID *Point;
+ EFI_GUID *TempVendorGuid;
+
+ TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+ if (VariableName[0] == 0) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID a UINT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *) VendorGuid)[0] == ((INT32 *) TempVendorGuid)[0]) &&
+ (((INT32 *) VendorGuid)[1] == ((INT32 *) TempVendorGuid)[1]) &&
+ (((INT32 *) VendorGuid)[2] == ((INT32 *) TempVendorGuid)[2]) &&
+ (((INT32 *) VendorGuid)[3] == ((INT32 *) TempVendorGuid)[3])
+ ) {
+ ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+ Point = (VOID *) GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get HOB variable store.
+
+ @param[out] StoreInfo Return the store info.
+ @param[out] VariableStoreHeader Return variable store header.
+
+**/
+VOID
+GetHobVariableStore (
+ OUT VARIABLE_STORE_INFO *StoreInfo,
+ OUT VARIABLE_STORE_HEADER **VariableStoreHeader
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Make sure there is no more than one Variable HOB.
+ //
+ DEBUG_CODE (
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+ ASSERT (FALSE);
+ } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ }
+ }
+ );
+
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ *VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = TRUE;
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ *VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ StoreInfo->AuthFlag = FALSE;
+ }
+ }
+}
+
+/**
+ Return the variable store header and the store info based on the Index.
+
+ @param Type The type of the variable store.
+ @param StoreInfo Return the store info.
+
+ @return Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+ IN VARIABLE_STORE_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->FtwLastWriteData = NULL;
+ StoreInfo->AuthFlag = FALSE;
+ VariableStoreHeader = NULL;
+ switch (Type) {
+ case VariableStoreTypeHob:
+ GetHobVariableStore (StoreInfo, &VariableStoreHeader);
+
+ break;
+
+ case VariableStoreTypeNv:
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ //
+ // Emulated non-volatile variable mode is not enabled.
+ //
+
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
+ PcdGet64 (PcdFlashNvStorageVariableBase64) :
+ PcdGet32 (PcdFlashNvStorageVariableBase)
+ );
+ ASSERT (NvStorageBase != 0);
+
+ //
+ // First let FvHeader point to NV storage base.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;
+
+ //
+ // Check the FTW last write data hob.
+ //
+ BackUpOffset = 0;
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ //
+ // Let FvHeader point to spare block.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;
+ DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ StoreInfo->FtwLastWriteData = FtwLastWriteData;
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
+ //
+ }
+ }
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ break;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);
+
+ StoreInfo->AuthFlag = (BOOLEAN) (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));
+
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // If it's the first time to access variable region in flash, create a guid hob to record
+ // VAR_ADDED type variable info.
+ // Note that as the resource of PEI phase is limited, only store the limited number of
+ // VAR_ADDED type variables to reduce access time.
+ //
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+ StoreInfo->IndexTable->Length = 0;
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->GoneThrough = 0;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ StoreInfo->VariableStoreHeader = VariableStoreHeader;
+ return VariableStoreHeader;
+}
+
+/**
+ Get variable header that has consecutive content.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PartialHeaderSize;
+
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable > (UINTN) SpareAddress) &&
+ (((UINTN) Variable - (UINTN) SpareAddress + (UINTN) TargetAddress) >= (UINTN) GetEndPointer (StoreInfo->VariableStoreHeader))) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN) TargetAddress)) {
+ //
+ // Variable header pointed by Variable is inconsecutive,
+ // create a guid hob to combine the two partial variable header content together.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+ PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+ }
+ }
+ } else {
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+ Get variable name or data to output buffer.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param Size Variable name/data size.
+ @param Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {
+ //
+ // Variable name/data is inconsecutive.
+ //
+ PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem (Buffer, NameOrData, PartialSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);
+ return;
+ }
+ }
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+ Find the variable in the specified variable store.
+
+ @param StoreInfo Pointer to the store info structure.
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableEx (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *LastVariable;
+ VARIABLE_HEADER *MaxIndex;
+ UINTN Index;
+ UINTN Offset;
+ BOOLEAN StopRecord;
+ VARIABLE_HEADER *InDeletedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ VARIABLE_HEADER *VariableHeader;
+
+ VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+ if (VariableStoreHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (~VariableStoreHeader->Size == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ IndexTable = StoreInfo->IndexTable;
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
+
+ InDeletedVariable = NULL;
+
+ //
+ // No Variable Address equals zero, so 0 as initial value is safe.
+ //
+ MaxIndex = NULL;
+ VariableHeader = NULL;
+
+ if (IndexTable != NULL) {
+ //
+ // traverse the variable index table to look for varible.
+ // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
+ //
+ for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
+ ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
+ Offset += IndexTable->Index[Index];
+ MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset);
+ GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+ if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (IndexTable->GoneThrough != 0) {
+ //
+ // If the table has all the existing variables indexed, return.
+ //
+ PtrTrack->CurrPtr = InDeletedVariable;
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+ }
+ }
+
+ if (MaxIndex != NULL) {
+ //
+ // HOB exists but the variable cannot be found in HOB
+ // If not found in HOB, then let's start from the MaxIndex we've found.
+ //
+ Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
+ LastVariable = MaxIndex;
+ } else {
+ //
+ // Start Pointers for the variable.
+ // Actual Data Pointer where data can be written.
+ //
+ Variable = PtrTrack->StartPtr;
+ LastVariable = PtrTrack->StartPtr;
+ }
+
+ //
+ // Find the variable by walk through variable store
+ //
+ StopRecord = FALSE;
+ while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // Record Variable in VariableIndex HOB
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ Offset = (UINTN) Variable - (UINTN) LastVariable;
+ if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
+ //
+ // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
+ // or the record buffer is full.
+ //
+ StopRecord = TRUE;
+ } else {
+ IndexTable->Index[IndexTable->Length++] = (UINT16) Offset;
+ LastVariable = Variable;
+ }
+ }
+
+ if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+ }
+ //
+ // If gone through the VariableStore, that means we never find in Firmware any more.
+ //
+ if ((IndexTable != NULL) && !StopRecord) {
+ IndexTable->GoneThrough = 1;
+ }
+
+ PtrTrack->CurrPtr = InDeletedVariable;
+
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+ Find the variable in HOB and Non-Volatile variable storages.
+
+ @param VariableName Name of the variable to be found
+ @param VendorGuid Vendor GUID to be found.
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param StoreInfo Return the store info.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+**/
+EFI_STATUS
+FindVariable (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_TYPE Type;
+
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ GetVariableStore (Type, StoreInfo);
+ Status = FindVariableEx (
+ StoreInfo,
+ VariableName,
+ VendorGuid,
+ PtrTrack
+ );
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_HEADER *VariableHeader;
+
+ if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableName[0] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ VariableHeader = NULL;
+
+ //
+ // Find existing variable
+ //
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
+ //
+ // Get data size
+ //
+ VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Attributes != NULL) {
+ *Attributes = VariableHeader->Attributes;
+ }
+ *DataSize = VarDataSize;
+
+ return Status;
+}
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_STORE_TYPE Type;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariableInHob;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ UINTN VarNameSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_INFO StoreInfoForNv;
+ VARIABLE_STORE_INFO StoreInfoForHob;
+
+ if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableHeader = NULL;
+
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable
+ //
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+
+ VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+ VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
+
+ while (TRUE) {
+ //
+ // Switch from HOB to Non-Volatile.
+ //
+ while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+ //
+ // Find current storage index
+ //
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+ break;
+ }
+ }
+ ASSERT (Type < VariableStoreTypeMax);
+ //
+ // Switch to next storage
+ //
+ for (Type++; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] != NULL) {
+ break;
+ }
+ }
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (Type == VariableStoreTypeMax) {
+ return EFI_NOT_FOUND;
+ }
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.CurrPtr = Variable.StartPtr;
+ GetVariableStore (Type, &StoreInfo);
+ }
+
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ Status = FindVariableEx (
+ &StoreInfo,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ //
+ // Don't return NV variable when HOB overrides it
+ //
+ if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
+ (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
+ ) {
+ Status = FindVariableEx (
+ &StoreInfoForHob,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariableInHob
+ );
+ if (!EFI_ERROR (Status)) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ ASSERT (VarNameSize != 0);
+
+ if (VarNameSize <= *VariableNameSize) {
+ GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *) VariableName);
+
+ CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ //
+ // Variable is found
+ //
+ return Status;
+ } else {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.h b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.h
new file mode 100644
index 000000000..5f660b339
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -0,0 +1,144 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_VARIABLE_H_
+#define _PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VariableIndexTable.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+
+typedef enum {
+ VariableStoreTypeHob,
+ VariableStoreTypeNv,
+ VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ //
+ // If it is not NULL, it means there may be an inconsecutive variable whose
+ // partial content is still in NV storage, but another partial content is backed up
+ // in spare block.
+ //
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ BOOLEAN AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+/**
+ Provide the functionality of the variable services.
+
+ @param FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param VariableName A pointer to a null-terminated string that is the variable's name.
+ @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param Attributes If non-NULL, on return, points to the variable's attributes.
+ @param DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param Data Points to the buffer which will hold the returned variable value.
+ May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
new file mode 100644
index 000000000..7cbdd2385
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -0,0 +1,74 @@
+## @file
+# Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiVariable
+ MODULE_UNI_FILE = PeiVariable.uni
+ FILE_GUID = 34C8C28F-B61C-45a2-8F2E-89E46BECC63B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimInitializeVariableServices
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Variable.c
+ Variable.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ HobLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+
+[Guids]
+ ## CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiAuthenticatedVariableGuid
+ ## SOMETIMES_CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableGuid
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableIndexTableGuid
+ gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## HOB
+ ## CONSUMES ## GUID # Dependence
+ gEdkiiFaultTolerantWriteGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEdkiiFaultTolerantWriteGuid
+
+# [BootMode]
+# RECOVERY_FULL ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiVariableExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
new file mode 100644
index 000000000..75350ca2e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
@@ -0,0 +1,339 @@
+/** @file
+ Measure TCG required variable.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/ImageAuthentication.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+#include "PrivilegePolymorphic.h"
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mVariableType[] = {
+ {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid},
+ {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
+ {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
+ {EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid},
+};
+
+//
+// "SecureBoot" may update following PK Del/Add
+// Cache its value to detect value update
+//
+UINT8 *mSecureBootVarData = NULL;
+UINTN mSecureBootVarDataSize = 0;
+
+/**
+ This function will return if this variable is SecureBootPolicy Variable.
+
+ @param[in] VariableName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+
+ @retval TRUE This is SecureBootPolicy Variable
+ @retval FALSE This is not SecureBootPolicy Variable
+**/
+BOOLEAN
+IsSecureBootPolicyVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Measure and log an EFI variable, and extend the measurement result into a specific PCR.
+
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] VarData The content of the variable data.
+ @param[in] VarSize The size of the variable data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *VarData,
+ IN UINTN VarSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarNameLength;
+ UEFI_VARIABLE_DATA *VarLog;
+ UINT32 VarLogSize;
+
+ ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
+
+ VarNameLength = StrLen (VarName);
+ VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+ VarLog = (UEFI_VARIABLE_DATA *) AllocateZeroPool (VarLogSize);
+ if (VarLog == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
+ VarLog->UnicodeNameLength = VarNameLength;
+ VarLog->VariableDataLength = VarSize;
+ CopyMem (
+ VarLog->UnicodeName,
+ VarName,
+ VarNameLength * sizeof (*VarName)
+ );
+ if (VarSize != 0) {
+ CopyMem (
+ (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "VariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_DRIVER_CONFIG));
+ DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+ Status = TpmMeasureAndLogData (
+ 7,
+ EV_EFI_VARIABLE_DRIVER_CONFIG,
+ VarLog,
+ VarLogSize,
+ VarLog,
+ VarLogSize
+ );
+ FreePool (VarLog);
+ return Status;
+}
+
+/**
+ Returns the status whether get the variable success. The function retrieves
+ variable through the UEFI Runtime Service GetVariable(). The
+ returned buffer is allocated using AllocatePool(). The caller is responsible
+ for freeing this buffer with FreePool().
+
+ This API is only invoked in boot time. It may NOT be invoked at runtime.
+
+ @param[in] Name The pointer to a Null-terminated Unicode string.
+ @param[in] Guid The pointer to an EFI_GUID structure
+ @param[out] Value The buffer point saved the variable info.
+ @param[out] Size The buffer size of the variable.
+
+ @return EFI_OUT_OF_RESOURCES Allocate buffer failed.
+ @return EFI_SUCCESS Find the specified variable.
+ @return Others Errors Return errors from call to gRT->GetVariable.
+
+**/
+EFI_STATUS
+InternalGetVariable (
+ IN CONST CHAR16 *Name,
+ IN CONST EFI_GUID *Guid,
+ OUT VOID **Value,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ //
+ // Try to get the variable size.
+ //
+ BufferSize = 0;
+ *Value = NULL;
+ if (Size != NULL) {
+ *Size = 0;
+ }
+
+ Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer to get the variable.
+ //
+ *Value = AllocatePool (BufferSize);
+ ASSERT (*Value != NULL);
+ if (*Value == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get the variable data.
+ //
+ Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
+ if (EFI_ERROR (Status)) {
+ FreePool(*Value);
+ *Value = NULL;
+ }
+
+ if (Size != NULL) {
+ *Size = BufferSize;
+ }
+
+ return Status;
+}
+
+/**
+ SecureBoot Hook for SetVariable.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableDataSize;
+ VOID *VariableData;
+
+ if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
+ return ;
+ }
+
+ //
+ // We should NOT use Data and DataSize here,because it may include signature,
+ // or is just partial with append attributes, or is deleted.
+ // We should GetVariable again, to get full variable content.
+ //
+ Status = InternalGetVariable (
+ VariableName,
+ VendorGuid,
+ &VariableData,
+ &VariableDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Measure DBT only if present and not empty
+ //
+ if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0 &&
+ CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) {
+ DEBUG((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));
+ return;
+ } else {
+ VariableData = NULL;
+ VariableDataSize = 0;
+ }
+ }
+
+ Status = MeasureVariable (
+ VariableName,
+ VendorGuid,
+ VariableData,
+ VariableDataSize
+ );
+ DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+
+ if (VariableData != NULL) {
+ FreePool (VariableData);
+ }
+
+ //
+ // "SecureBoot" is 8bit & read-only. It can only be changed according to PK update
+ //
+ if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0) &&
+ CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
+ Status = InternalGetVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &VariableData,
+ &VariableDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // If PK update is successful. "SecureBoot" shall always exist ever since variable write service is ready
+ //
+ ASSERT(mSecureBootVarData != NULL);
+
+ if (CompareMem(mSecureBootVarData, VariableData, VariableDataSize) != 0) {
+ FreePool(mSecureBootVarData);
+ mSecureBootVarData = VariableData;
+ mSecureBootVarDataSize = VariableDataSize;
+
+ DEBUG((DEBUG_INFO, "%s variable updated according to PK change. Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME));
+ Status = MeasureVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ mSecureBootVarData,
+ mSecureBootVarDataSize
+ );
+ DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+ } else {
+ //
+ // "SecureBoot" variable is not changed
+ //
+ FreePool(VariableData);
+ }
+ }
+
+ return ;
+}
+
+/**
+ Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+ Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Record initial "SecureBoot" variable value.
+ // It is used to detect SecureBoot variable change in SecureBootHook.
+ //
+ Status = InternalGetVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ (VOID **)&mSecureBootVarData,
+ &mSecureBootVarDataSize
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // Read could fail when Auth Variable solution is not supported
+ //
+ DEBUG((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status));
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h
new file mode 100644
index 000000000..2f5695f0e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h
@@ -0,0 +1,157 @@
+/** @file
+ Polymorphic functions that are called from both the privileged driver (i.e.,
+ the DXE_SMM variable module) and the non-privileged drivers (i.e., one or
+ both of the DXE_RUNTIME variable modules).
+
+ Each of these functions has two implementations, appropriate for privileged
+ vs. non-privileged driver code.
+
+ Copyright (c) 2017, Red Hat, Inc.<BR>
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _PRIVILEGE_POLYMORPHIC_H_
+#define _PRIVILEGE_POLYMORPHIC_H_
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+ SecureBoot Hook for auth variable update.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Initialization for MOR Control Lock.
+
+ @retval EFI_SUCCESS MorLock initialization success.
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ );
+
+/**
+ Delayed initialization for MOR Control Lock at EndOfDxe.
+
+ This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+ VOID
+ );
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable
+ driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or
+ attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this
+ function. Variable driver can just return
+ EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ This service is consumed by the variable modules to place a barrier to stop
+ speculative execution.
+
+ Ensures that no later instruction will execute speculatively, until all prior
+ instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+ VOID
+ );
+
+/**
+ Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+ VOID
+ );
+
+/**
+ Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+ VOID
+ );
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+MmVariableServiceInitialize (
+ VOID
+ );
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ );
+
+/**
+ Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+ This information is used by the MorLock code to infer whether an existing
+ MOR variable is legitimate or not.
+
+ @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
+ protocol database
+ @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+ protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
new file mode 100644
index 000000000..1def8e249
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
@@ -0,0 +1,155 @@
+/** @file
+ Handles non-volatile variable store garbage collection, using FTW
+ (Fault Tolerant Write) protocol.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+ Gets LBA of block and offset by given address.
+
+ This function gets the Logical Block Address (LBA) of a firmware
+ volume block containing the given address, and the offset of the
+ address on the block.
+
+ @param Address Address which should be contained
+ by returned FVB handle.
+ @param Lba Pointer to LBA for output.
+ @param Offset Pointer to offset for output.
+
+ @retval EFI_SUCCESS LBA and offset successfully returned.
+ @retval EFI_NOT_FOUND Fail to find FVB handle by address.
+ @retval EFI_ABORTED Fail to find valid LBA and offset.
+
+**/
+EFI_STATUS
+GetLbaAndOffsetByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
+ UINT32 LbaIndex;
+
+ Fvb = NULL;
+ *Lba = (EFI_LBA) (-1);
+ *Offset = 0;
+
+ //
+ // Get the proper FVB protocol.
+ //
+ Status = GetFvbInfoByAddress (Address, NULL, &Fvb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the Base Address of FV.
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
+
+ //
+ // Get the (LBA, Offset) of Address.
+ //
+ if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
+ //
+ // BUGBUG: Assume one FV has one type of BlockLength.
+ //
+ FvbMapEntry = &FwVolHeader->BlockMap[0];
+ for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
+ if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
+ //
+ // Found the (Lba, Offset).
+ //
+ *Lba = LbaIndex - 1;
+ *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ Writes a buffer to variable storage space, in the working block.
+
+ This function writes a buffer to variable storage space into a firmware
+ volume block device. The destination is specified by parameter
+ VariableBase. Fault Tolerant Write protocol is used for writing.
+
+ @param VariableBase Base address of variable to write
+ @param VariableBuffer Point to the variable data buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ IN VARIABLE_STORE_HEADER *VariableBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FvbHandle;
+ EFI_LBA VarLba;
+ UINTN VarOffset;
+ UINTN FtwBufferSize;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+
+ //
+ // Locate fault tolerant write protocol.
+ //
+ Status = GetFtwProtocol((VOID **) &FtwProtocol);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Locate Fvb handle by address.
+ //
+ Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get LBA and Offset by address.
+ //
+ Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
+ ASSERT (FtwBufferSize == VariableBuffer->Size);
+
+ //
+ // FTW write record.
+ //
+ Status = FtwProtocol->Write (
+ FtwProtocol,
+ VarLba, // LBA
+ VarOffset, // Offset
+ FtwBufferSize, // NumBytes
+ NULL, // PrivateData NULL
+ FvbHandle, // Fvb Handle
+ (VOID *) VariableBuffer // write buffer
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierDxe.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierDxe.c
new file mode 100644
index 000000000..b219ea9ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierDxe.c
@@ -0,0 +1,27 @@
+/** @file
+ Barrier to stop speculative execution (DXE version).
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+ This service is consumed by the variable modules to place a barrier to stop
+ speculative execution.
+
+ Ensures that no later instruction will execute speculatively, until all prior
+ instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+ VOID
+ )
+{
+ //
+ // Do nothing.
+ //
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierSmm.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierSmm.c
new file mode 100644
index 000000000..7107c0429
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/SpeculationBarrierSmm.c
@@ -0,0 +1,26 @@
+/** @file
+ Barrier to stop speculative execution (SMM version).
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include "Variable.h"
+
+/**
+ This service is consumed by the variable modules to place a barrier to stop
+ speculative execution.
+
+ Ensures that no later instruction will execute speculatively, until all prior
+ instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+ VOID
+ )
+{
+ SpeculationBarrier ();
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c
new file mode 100644
index 000000000..e7accf4ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c
@@ -0,0 +1,124 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control support (DXE version).
+
+ This module clears MemoryOverwriteRequestControlLock variable to indicate
+ MOR lock control unsupported.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+extern EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable
+ driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or
+ attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this
+ function. Variable driver can just return
+ EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ //
+ // Just let it pass. No need provide protection for DXE version.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for MOR Control Lock.
+
+ @retval EFI_SUCCESS MorLock initialization success.
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ )
+{
+ //
+ // Always clear variable to report unsupported to OS.
+ // The reason is that the DXE version is not proper to provide *protection*.
+ // BIOS should use SMM version variable driver to provide such capability.
+ //
+ VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ 0, // Attributes
+ 0, // DataSize
+ NULL // Data
+ );
+
+ //
+ // Need set this variable to be read-only to prevent other module set it.
+ //
+ VariableLockRequestToLock (&mVariableLock, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid);
+
+ //
+ // The MOR variable can effectively improve platform security only when the
+ // MorLock variable protects the MOR variable. In turn MorLock cannot be made
+ // secure without SMM support in the platform firmware (see above).
+ //
+ // Thus, delete the MOR variable, should it exist for any reason (some OSes
+ // are known to create MOR unintentionally, in an attempt to set it), then
+ // also lock the MOR variable, in order to prevent other modules from
+ // creating it.
+ //
+ VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ 0, // Attributes
+ 0, // DataSize
+ NULL // Data
+ );
+ VariableLockRequestToLock (
+ &mVariableLock,
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delayed initialization for MOR Control Lock at EndOfDxe.
+
+ This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+ VOID
+ )
+{
+ //
+ // Do nothing.
+ //
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
new file mode 100644
index 000000000..6d80eb643
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
@@ -0,0 +1,512 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).
+
+ This module initilizes MemoryOverwriteRequestControlLock variable.
+ This module adds Variable Hook and check MemoryOverwriteRequestControlLock.
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mMorVariableType[] = {
+ {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid},
+ {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid},
+};
+
+BOOLEAN mMorPassThru = FALSE;
+
+#define MOR_LOCK_DATA_UNLOCKED 0x0
+#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1
+#define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2
+
+#define MOR_LOCK_V1_SIZE 1
+#define MOR_LOCK_V2_KEY_SIZE 8
+
+typedef enum {
+ MorLockStateUnlocked = 0,
+ MorLockStateLocked = 1,
+} MOR_LOCK_STATE;
+
+BOOLEAN mMorLockInitializationRequired = FALSE;
+UINT8 mMorLockKey[MOR_LOCK_V2_KEY_SIZE];
+BOOLEAN mMorLockKeyEmpty = TRUE;
+BOOLEAN mMorLockPassThru = FALSE;
+MOR_LOCK_STATE mMorLockState = MorLockStateUnlocked;
+
+/**
+ Returns if this is MOR related variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR related.
+ @retval FALSE The variable is NOT MOR related.
+**/
+BOOLEAN
+IsAnyMorVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mMorVariableType)/sizeof(mMorVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Returns if this is MOR lock variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR lock variable.
+ @retval FALSE The variable is NOT MOR lock variable.
+**/
+BOOLEAN
+IsMorLockVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
+ (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Set MOR lock variable.
+
+ @param Data MOR Lock variable data.
+
+ @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 was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode 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 saved due to a hardware failure.
+ @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_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ 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
+SetMorLockVariable (
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+
+ mMorLockPassThru = TRUE;
+ Status = VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(Data),
+ &Data
+ );
+ mMorLockPassThru = FALSE;
+ return Status;
+}
+
+/**
+ This service is an MorLock checker handler for the SetVariable().
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MorLock check pass, and Variable driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MorLock data or data size or attributes is not allowed.
+ @retval EFI_ACCESS_DENIED The MorLock is locked.
+ @retval EFI_WRITE_PROTECTED The MorLock deletion is not allowed.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
+ Variable driver can just return EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMorLock (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Basic Check
+ //
+ if (Attributes == 0 || DataSize == 0 || Data == NULL) {
+ //
+ // Permit deletion for passthru request, deny it otherwise.
+ //
+ return mMorLockPassThru ? EFI_SUCCESS : EFI_WRITE_PROTECTED;
+ }
+
+ if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+ ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Do not check if the request is passthru.
+ //
+ if (mMorLockPassThru) {
+ return EFI_SUCCESS;
+ }
+
+ if (mMorLockState == MorLockStateUnlocked) {
+ //
+ // In Unlocked State
+ //
+ if (DataSize == MOR_LOCK_V1_SIZE) {
+ //
+ // V1 - lock permanently
+ //
+ if (*(UINT8 *)Data == MOR_LOCK_DATA_UNLOCKED) {
+ //
+ // Unlock
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+ if (!EFI_ERROR (Status)) {
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ } else {
+ //
+ // SetVar fail
+ //
+ return Status;
+ }
+ } else if (*(UINT8 *)Data == MOR_LOCK_DATA_LOCKED_WITHOUT_KEY) {
+ //
+ // Lock without key
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Lock success
+ //
+ mMorLockState = MorLockStateLocked;
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ } else {
+ //
+ // SetVar fail
+ //
+ return Status;
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (DataSize == MOR_LOCK_V2_KEY_SIZE) {
+ //
+ // V2 lock and provision the key
+ //
+
+ //
+ // Need set here because the data value on flash is different
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY);
+ if (EFI_ERROR(Status)) {
+ //
+ // SetVar fail, do not provision the key
+ //
+ return Status;
+ } else {
+ //
+ // Lock success, provision the key
+ //
+ mMorLockKeyEmpty = FALSE;
+ CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE);
+ mMorLockState = MorLockStateLocked;
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // In Locked State
+ //
+ if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {
+ return EFI_ACCESS_DENIED;
+ }
+ if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {
+ //
+ // Key match - unlock
+ //
+
+ //
+ // Need set here because the data value on flash is different
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+ if (EFI_ERROR (Status)) {
+ //
+ // SetVar fail
+ //
+ return Status;
+ } else {
+ //
+ // Unlock Success
+ //
+ mMorLockState = MorLockStateUnlocked;
+ mMorLockKeyEmpty = TRUE;
+ ZeroMem (mMorLockKey, sizeof(mMorLockKey));
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ //
+ // Key mismatch - Prevent Dictionary Attack
+ //
+ mMorLockState = MorLockStateLocked;
+ mMorLockKeyEmpty = TRUE;
+ ZeroMem (mMorLockKey, sizeof(mMorLockKey));
+ return EFI_ACCESS_DENIED;
+ }
+ }
+}
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable
+ driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or
+ attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this
+ function. Variable driver can just return
+ EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ //
+ // do not handle non-MOR variable
+ //
+ if (!IsAnyMorVariable (VariableName, VendorGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // MorLock variable
+ //
+ if (IsMorLockVariable (VariableName, VendorGuid)) {
+ return SetVariableCheckHandlerMorLock (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ }
+
+ //
+ // Mor Variable
+ //
+
+ //
+ // Permit deletion for passthru request.
+ //
+ if (((Attributes == 0) || (DataSize == 0)) && mMorPassThru) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Basic Check
+ //
+ if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+ (DataSize != sizeof(UINT8)) ||
+ (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mMorLockState == MorLockStateLocked) {
+ //
+ // If lock, deny access
+ //
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // grant access
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for MOR Control Lock.
+
+ @retval EFI_SUCCESS MorLock initialization success.
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ )
+{
+ mMorLockInitializationRequired = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Delayed initialization for MOR Control Lock at EndOfDxe.
+
+ This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+ VOID
+ )
+{
+ UINTN MorSize;
+ EFI_STATUS MorStatus;
+
+ if (!mMorLockInitializationRequired) {
+ //
+ // The EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL has never been installed, thus
+ // the variable write service is unavailable. This should never happen.
+ //
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Check if the MOR variable exists.
+ //
+ MorSize = 0;
+ MorStatus = VariableServiceGetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL, // Attributes
+ &MorSize,
+ NULL // Data
+ );
+ //
+ // We provided a zero-sized buffer, so the above call can never succeed.
+ //
+ ASSERT (EFI_ERROR (MorStatus));
+
+ if (MorStatus == EFI_BUFFER_TOO_SMALL) {
+ //
+ // The MOR variable exists.
+ //
+ // Some OSes don't follow the TCG's Platform Reset Attack Mitigation spec
+ // in that the OS should never create the MOR variable, only read and write
+ // it -- these OSes (unintentionally) create MOR if the platform firmware
+ // does not produce it. Whether this is the case (from the last OS boot)
+ // can be deduced from the absence of the TCG / TCG2 protocols, as edk2's
+ // MOR implementation depends on (one of) those protocols.
+ //
+ if (VariableHaveTcgProtocols ()) {
+ //
+ // The MOR variable originates from the platform firmware; set the MOR
+ // Control Lock variable to report the locking capability to the OS.
+ //
+ SetMorLockVariable (0);
+ return;
+ }
+
+ //
+ // The MOR variable's origin is inexplicable; delete it.
+ //
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: deleting unexpected / unsupported variable %g:%s\n",
+ __FUNCTION__,
+ &gEfiMemoryOverwriteControlDataGuid,
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
+ ));
+
+ mMorPassThru = TRUE;
+ VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ 0, // Attributes
+ 0, // DataSize
+ NULL // Data
+ );
+ mMorPassThru = FALSE;
+ }
+
+ //
+ // The MOR variable is absent; the platform firmware does not support it.
+ // Lock the variable so that no other module may create it.
+ //
+ VariableLockRequestToLock (
+ NULL, // This
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid
+ );
+
+ //
+ // Delete the MOR Control Lock variable too (should it exists for some
+ // reason) and prevent other modules from creating it.
+ //
+ mMorLockPassThru = TRUE;
+ VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ 0, // Attributes
+ 0, // DataSize
+ NULL // Data
+ );
+ mMorLockPassThru = FALSE;
+
+ VariableLockRequestToLock (
+ NULL, // This
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c
new file mode 100644
index 000000000..f15219df5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c
@@ -0,0 +1,149 @@
+/** @file
+ Implementation functions and structures for var check protocol
+ and variable lock protocol based on VarCheckLib.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+ Write request coming from SMM environment through EFI_SMM_VARIABLE_PROTOCOL is allowed.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = VarCheckLibVariablePropertyGet (VariableName, VendorGuid, &Property);
+ if (!EFI_ERROR (Status)) {
+ Property.Property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ } else {
+ Property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ Property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ Property.Attributes = 0;
+ Property.MinSize = 1;
+ Property.MaxSize = MAX_UINTN;
+ }
+ Status = VarCheckLibVariablePropertySet (VariableName, VendorGuid, &Property);
+
+ DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s %r\n", VendorGuid, VariableName, Status));
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibRegisterSetVariableCheckHandler (Handler);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibVariablePropertySet (Name, Guid, VariableProperty);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibVariablePropertyGet (Name, Guid, VariableProperty);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
new file mode 100644
index 000000000..41f8ff4ce
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -0,0 +1,3753 @@
+/** @file
+ The common variable operation routines shared by DXE_RUNTIME variable
+ module and DXE_SMM variable module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. They may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
+ They need check input parameter.
+
+ VariableServiceGetVariable() and VariableServiceSetVariable() are external API
+ to receive datasize and data buffer. The size should be checked carefully.
+
+ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
+ integer overflow. It should also check attribute to avoid authentication bypass.
+
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
+Copyright (c) Microsoft Corporation.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+
+///
+/// Define a memory cache that improves the search performance for a variable.
+/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
+///
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+
+///
+/// Memory cache of Fv Header.
+///
+EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = NULL;
+
+///
+/// The memory entry used for variable statistics data.
+///
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+///
+/// It indicates the var check request source.
+/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
+///
+VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;
+
+//
+// It will record the current boot error flag before EndOfDxe.
+//
+VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
+
+VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
+ {
+ &gEdkiiVarErrorFlagGuid,
+ VAR_ERROR_FLAG_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (VAR_ERROR_FLAG),
+ sizeof (VAR_ERROR_FLAG)
+ }
+ },
+};
+
+AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
+ AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
+ //
+ // StructSize, TO BE FILLED
+ //
+ 0,
+ //
+ // MaxAuthVariableSize, TO BE FILLED
+ //
+ 0,
+ VariableExLibFindVariable,
+ VariableExLibFindNextVariable,
+ VariableExLibUpdateVariable,
+ VariableExLibGetScratchBuffer,
+ VariableExLibCheckRemainingSpaceForConsistency,
+ VariableExLibAtRuntime,
+};
+
+AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
+
+/**
+
+ This function writes data to the FWH at the correct LBA even if the LBAs
+ are fragmented.
+
+ @param Global Pointer to VARAIBLE_GLOBAL structure.
+ @param Volatile Point out the Variable is Volatile or Non-Volatile.
+ @param SetByIndex TRUE if target pointer is given as index.
+ FALSE if target pointer is absolute.
+ @param Fvb Pointer to the writable FVB protocol.
+ @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
+ structure.
+ @param DataSize Size of data to be written.
+ @param Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Parameters not valid.
+ @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
+ @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN SetByIndex,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN UINTN DataPtrIndex,
+ IN UINT32 DataSize,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ UINTN BlockIndex2;
+ UINTN LinearOffset;
+ UINTN CurrWriteSize;
+ UINTN CurrWritePtr;
+ UINT8 *CurrBuffer;
+ EFI_LBA LbaNumber;
+ UINTN Size;
+ VARIABLE_STORE_HEADER *VolatileBase;
+ EFI_PHYSICAL_ADDRESS FvVolHdr;
+ EFI_PHYSICAL_ADDRESS DataPtr;
+ EFI_STATUS Status;
+
+ FvVolHdr = 0;
+ DataPtr = DataPtrIndex;
+
+ //
+ // Check if the Data is Volatile.
+ //
+ if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ if (Fvb == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Data Pointer should point to the actual Address where data is to be
+ // written.
+ //
+ if (SetByIndex) {
+ DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ }
+
+ if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // Data Pointer should point to the actual Address where data is to be
+ // written.
+ //
+ if (Volatile) {
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ if (SetByIndex) {
+ DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ }
+
+ if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ if (SetByIndex) {
+ DataPtr += (UINTN) mNvVariableCache;
+ }
+
+ if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
+ //
+ CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If we are here we are dealing with Non-Volatile Variables.
+ //
+ LinearOffset = (UINTN) FvVolHdr;
+ CurrWritePtr = (UINTN) DataPtr;
+ CurrWriteSize = DataSize;
+ CurrBuffer = Buffer;
+ LbaNumber = 0;
+
+ if (CurrWritePtr < LinearOffset) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+ for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+ //
+ // Check to see if the Variable Writes are spanning through multiple
+ // blocks.
+ //
+ if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
+ if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
+ Status = Fvb->Write (
+ Fvb,
+ LbaNumber,
+ (UINTN) (CurrWritePtr - LinearOffset),
+ &CurrWriteSize,
+ CurrBuffer
+ );
+ return Status;
+ } else {
+ Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
+ Status = Fvb->Write (
+ Fvb,
+ LbaNumber,
+ (UINTN) (CurrWritePtr - LinearOffset),
+ &Size,
+ CurrBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
+ CurrBuffer = CurrBuffer + Size;
+ CurrWriteSize = CurrWriteSize - Size;
+ }
+ }
+
+ LinearOffset += PtrBlockMapEntry->Length;
+ LbaNumber++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Record variable error flag.
+
+ @param[in] Flag Variable error flag to record.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] VariableSize Size of the variable.
+
+**/
+VOID
+RecordVarErrorFlag (
+ IN VAR_ERROR_FLAG Flag,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN VariableSize
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ VAR_ERROR_FLAG *VarErrFlag;
+ VAR_ERROR_FLAG TempFlag;
+
+ DEBUG_CODE (
+ DEBUG ((EFI_D_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
+ if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
+ if (AtRuntime ()) {
+ DEBUG ((EFI_D_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+ } else {
+ DEBUG ((EFI_D_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
+ }
+ );
+
+ if (!mEndOfDxe) {
+ //
+ // Before EndOfDxe, just record the current boot variable error flag to local variable,
+ // and leave the variable error flag in NV flash as the last boot variable error flag.
+ // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
+ // will be initialized to this local current boot variable error flag.
+ //
+ mCurrentBootVarErrFlag &= Flag;
+ return;
+ }
+
+ //
+ // Record error flag (it should have be initialized).
+ //
+ Status = FindVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ TempFlag = *VarErrFlag;
+ TempFlag &= Flag;
+ if (TempFlag == *VarErrFlag) {
+ return;
+ }
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ sizeof (TempFlag),
+ &TempFlag
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update the data in NV cache.
+ //
+ *VarErrFlag = TempFlag;
+ Status = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+ 0,
+ mNvVariableCache->Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+ Initialize variable error flag.
+
+ Before EndOfDxe, the variable indicates the last boot variable error flag,
+ then it means the last boot variable error flag must be got before EndOfDxe.
+ After EndOfDxe, the variable indicates the current boot variable error flag,
+ then it means the current boot variable error flag must be got after EndOfDxe.
+
+**/
+VOID
+InitializeVarErrorFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ VAR_ERROR_FLAG Flag;
+ VAR_ERROR_FLAG VarErrFlag;
+
+ if (!mEndOfDxe) {
+ return;
+ }
+
+ Flag = mCurrentBootVarErrFlag;
+ DEBUG ((EFI_D_INFO, "Initialize variable error flag (%02x)\n", Flag));
+
+ Status = FindVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat));
+ if (VarErrFlag == Flag) {
+ return;
+ }
+ }
+
+ UpdateVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Flag,
+ sizeof (Flag),
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+}
+
+/**
+ Is user variable?
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ //
+ // Only after End Of Dxe, the variables belong to system variable are fixed.
+ // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+ // then no need to check if the variable is user variable or not specially.
+ //
+ if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+ if (VarCheckLibVariablePropertyGet (
+ GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ &Property
+ ) == EFI_NOT_FOUND) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Calculate common user variable total size.
+
+**/
+VOID
+CalculateCommonUserVariableTotalSize (
+ VOID
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *NextVariable;
+ UINTN VariableSize;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ //
+ // Only after End Of Dxe, the variables belong to system variable are fixed.
+ // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+ // then no need to calculate the common user variable total size specially.
+ //
+ if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+ Variable = GetStartPointer (mNvVariableCache);
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (VarCheckLibVariablePropertyGet (
+ GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ &Property
+ ) == EFI_NOT_FOUND) {
+ //
+ // No property, it is user variable.
+ //
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+ }
+}
+
+/**
+ Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+ VOID
+ )
+{
+ if (!mEndOfDxe) {
+ return;
+ }
+
+ InitializeVarErrorFlag ();
+ CalculateCommonUserVariableTotalSize ();
+}
+
+/**
+
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *AddedVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *NextAddedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ VOID *Point0;
+ VOID *Point1;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ EFI_STATUS DoneStatus;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_HEADER *UpdatingVariable;
+ VARIABLE_HEADER *UpdatingInDeletedTransition;
+ BOOLEAN AuthFormat;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+ UpdatingVariable = NULL;
+ UpdatingInDeletedTransition = NULL;
+ if (UpdatingPtrTrack != NULL) {
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
+
+ CommonVariableTotalSize = 0;
+ CommonUserVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // Start Pointers for the variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+ Variable != UpdatingVariable &&
+ Variable != UpdatingInDeletedTransition
+ ) {
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ if (NewVariable != NULL) {
+ //
+ // Add the new variable size.
+ //
+ MaximumBufferSize += NewVariableSize;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
+ // as the buffer to reduce SMRAM consumption for SMM variable driver.
+ //
+ MaximumBufferSize = mNvVariableCache->Size;
+ ValidBuffer = (UINT8 *) mNvVariableCache;
+ }
+
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header.
+ //
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ Variable = NextVariable;
+ }
+
+ //
+ // Reinstall all in delete transition variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+
+ //
+ // Buffer has cached all ADDED variable.
+ // Per IN_DELETED variable, we have to guarantee that
+ // no ADDED one in previous buffer.
+ //
+
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
+ NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
+ if (CompareGuid (
+ GetVendorGuidPtr (AddedVariable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat)
+ ) && NameSize == NameSizeOfVariable (Variable, AuthFormat)) {
+ Point0 = (VOID *) GetVariableNamePtr (AddedVariable, AuthFormat);
+ Point1 = (VOID *) GetVariableNamePtr (Variable, AuthFormat);
+ if (CompareMem (Point0, Point1, NameSize) == 0) {
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+ AddedVariable = NextAddedVariable;
+ }
+ if (!FoundAdded) {
+ //
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+ //
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Install the new variable if it is not NULL.
+ //
+ if (NewVariable != NULL) {
+ if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
+ //
+ // No enough space to store the new variable.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ if (!IsVolatile) {
+ if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += NewVariableSize;
+ } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize += NewVariableSize;
+ if (IsUserVariable (NewVariable)) {
+ CommonUserVariableTotalSize += NewVariableSize;
+ }
+ }
+ if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ //
+ // No enough space to store the new variable by NV or NV+HR attribute.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
+ if (UpdatingVariable != NULL) {
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+ }
+ CurrPtr += NewVariableSize;
+ }
+
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.
+ //
+ SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
+ CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);
+ *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
+ if (!IsVolatile) {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, perform FTW here.
+ //
+ Status = FtwVariableSpace (
+ VariableBase,
+ (VARIABLE_STORE_HEADER *) ValidBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ } else {
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
+ Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
+ while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
+ NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+ *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;
+ }
+ }
+
+Done:
+ DoneStatus = EFI_SUCCESS;
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ FreePool (ValidBuffer);
+ } else {
+ //
+ // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
+ //
+ CopyMem (mNvVariableCache, (UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size);
+ DoneStatus = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+ 0,
+ VariableStoreHeader->Size
+ );
+ ASSERT_EFI_ERROR (DoneStatus);
+ }
+
+ if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
+ Status = DoneStatus;
+ }
+
+ return Status;
+}
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+ at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+ Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN IgnoreRtCheck
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ VARIABLE_STORE_TYPE Type;
+
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
+ // make use of this mapping to implement search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;
+ VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;
+ VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
+
+ //
+ // Find the variable by walk through HOB, volatile and non-volatile variable store.
+ //
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] == NULL) {
+ continue;
+ }
+
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (
+ VariableName,
+ VendorGuid,
+ IgnoreRtCheck,
+ PtrTrack,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get index from supported language codes according to language string.
+
+ This code is used to get corresponding index 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 and calculate the index.
+ In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Lang = "eng"
+ Iso639Language = TRUE
+ The return value is "0".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Lang = "fr-FR"
+ Iso639Language = FALSE
+ The return value is "3".
+
+ @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 The index of language in the language codes.
+
+**/
+UINTN
+GetIndexFromSupportedLangCodes(
+ 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 index of Lang string in SupportedLang string.
+ //
+ Index = Index / CompareLength;
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ } else {
+ //
+ // Compare RFC4646 language code
+ //
+ Index = 0;
+ for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
+
+ for (Index = 0; *SupportedLang != '\0'; Index++, 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 index of Lang string in SupportedLang string.
+ //
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ }
+}
+
+/**
+ Get language string from supported language codes according to index.
+
+ This code is used to get corresponding language strings in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
+ In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Index = "1"
+ Iso639Language = TRUE
+ The return value is "fra".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Index = "1"
+ Iso639Language = FALSE
+ The return value is "fr".
+
+ @param SupportedLang Platform supported language codes.
+ @param Index The index in supported language codes.
+ @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+ @retval The language string in the language codes.
+
+**/
+CHAR8 *
+GetLangFromSupportedLangCodes (
+ IN CHAR8 *SupportedLang,
+ IN UINTN Index,
+ IN BOOLEAN Iso639Language
+)
+{
+ UINTN SubIndex;
+ UINTN CompareLength;
+ CHAR8 *Supported;
+
+ SubIndex = 0;
+ Supported = SupportedLang;
+ if (Iso639Language) {
+ //
+ // According to the index of Lang string in SupportedLang string to get the language.
+ // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ mVariableModuleGlobal->Lang[CompareLength] = '\0';
+ return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
+
+ } else {
+ while (TRUE) {
+ //
+ // Take semicolon as delimitation, sequentially traverse supported language codes.
+ //
+ for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
+ Supported++;
+ }
+ if ((*Supported == '\0') && (SubIndex != Index)) {
+ //
+ // Have completed the traverse, but not find corrsponding string.
+ // This case is not allowed to happen.
+ //
+ ASSERT(FALSE);
+ return NULL;
+ }
+ if (SubIndex == Index) {
+ //
+ // According to the index of Lang string in SupportedLang string to get the language.
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
+ return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
+ }
+ SubIndex++;
+
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ }
+ }
+}
+
+/**
+ Returns a pointer to an allocated buffer that contains the best matching language
+ from a set of supported languages.
+
+ 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. This function
+ supports a variable argument list that allows the caller to pass in a prioritized
+ list of language codes to test against all the language codes in SupportedLanguages.
+
+ If SupportedLanguages is NULL, then ASSERT().
+
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
+ contains a set of language codes in the format
+ specified by Iso639Language.
+ @param[in] Iso639Language If not zero, then all language codes are assumed to be
+ in ISO 639-2 format. If zero, then all language
+ codes are assumed to be in RFC 4646 language format
+ @param[in] ... A variable argument list that contains pointers to
+ Null-terminated ASCII strings that contain one or more
+ language codes in the format specified by Iso639Language.
+ The first language code from each of these language
+ code lists is used to determine if it is an exact or
+ close match to any of the language codes in
+ SupportedLanguages. Close matches only apply to RFC 4646
+ language codes, and the matching algorithm from RFC 4647
+ is used to determine if a close match is present. If
+ an exact or close match is found, then the matching
+ language code from SupportedLanguages is returned. If
+ no matches are found, then the next variable argument
+ parameter is evaluated. The variable argument list
+ is terminated by a NULL.
+
+ @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 *
+EFIAPI
+VariableGetBestLanguage (
+ IN CONST CHAR8 *SupportedLanguages,
+ IN UINTN Iso639Language,
+ ...
+ )
+{
+ VA_LIST Args;
+ CHAR8 *Language;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+ CONST CHAR8 *Supported;
+ CHAR8 *Buffer;
+
+ if (SupportedLanguages == NULL) {
+ return NULL;
+ }
+
+ VA_START (Args, Iso639Language);
+ while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
+ //
+ // Default to ISO 639-2 mode
+ //
+ CompareLength = 3;
+ LanguageLength = MIN (3, AsciiStrLen (Language));
+
+ //
+ // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
+ //
+ if (Iso639Language == 0) {
+ for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
+ }
+
+ //
+ // Trim back the length of Language used until it is empty
+ //
+ while (LanguageLength > 0) {
+ //
+ // Loop through all language codes in SupportedLanguages
+ //
+ for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
+ //
+ // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
+ //
+ if (Iso639Language == 0) {
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ //
+ // Determine the length of the next language code in Supported
+ //
+ for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
+ //
+ // If Language is longer than the Supported, then skip to the next language
+ //
+ if (LanguageLength > CompareLength) {
+ continue;
+ }
+ }
+ //
+ // See if the first LanguageLength characters in Supported match Language
+ //
+ if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
+ VA_END (Args);
+
+ Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
+ Buffer[CompareLength] = '\0';
+ return CopyMem (Buffer, Supported, CompareLength);
+ }
+ }
+
+ if (Iso639Language != 0) {
+ //
+ // If ISO 639 mode, then each language can only be tested once
+ //
+ LanguageLength = 0;
+ } else {
+ //
+ // If RFC 4646 mode, then trim Language from the right to the next '-' character
+ //
+ for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
+ }
+ }
+ }
+ VA_END (Args);
+
+ //
+ // No matches were found
+ //
+ return NULL;
+}
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param[in] Marker VA_LIST style variable argument list.
+ The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+ IN UINT32 Attributes,
+ IN VA_LIST Marker
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ VARIABLE_ENTRY_CONSISTENCY *VariableEntry;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINTN TotalNeededSize;
+ UINTN OriginalVarSize;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ VARIABLE_HEADER *NextVariable;
+ UINTN VarNameSize;
+ UINTN VarDataSize;
+
+ //
+ // Non-Volatile related.
+ //
+ VariableStoreHeader = mNvVariableCache;
+
+ Status = VariableServiceQueryVariableInfoInternal (
+ Attributes,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ TotalNeededSize = 0;
+ VA_COPY (Args, Marker);
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ while (VariableEntry != NULL) {
+ //
+ // Calculate variable total size.
+ //
+ VarNameSize = StrSize (VariableEntry->Name);
+ VarNameSize += GET_PAD_SIZE (VarNameSize);
+ VarDataSize = VariableEntry->VariableSize;
+ VarDataSize += GET_PAD_SIZE (VarDataSize);
+ VariableEntry->VariableSize = HEADER_ALIGN (
+ GetVariableHeaderSize (
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ ) + VarNameSize + VarDataSize
+ );
+
+ TotalNeededSize += VariableEntry->VariableSize;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ }
+ VA_END (Args);
+
+ if (RemainingVariableStorageSize >= TotalNeededSize) {
+ //
+ // Already have enough space.
+ //
+ return TRUE;
+ } else if (AtRuntime ()) {
+ //
+ // At runtime, no reclaim.
+ // The original variable space of Variables can't be reused.
+ //
+ return FALSE;
+ }
+
+ VA_COPY (Args, Marker);
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ while (VariableEntry != NULL) {
+ //
+ // Check if Variable[Index] has been present and get its size.
+ //
+ OriginalVarSize = 0;
+ VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+ VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
+ Status = FindVariableEx (
+ VariableEntry->Name,
+ VariableEntry->Guid,
+ FALSE,
+ &VariablePtrTrack,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get size of Variable[Index].
+ //
+ NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;
+ //
+ // Add the original size of Variable[Index] to remaining variable storage size.
+ //
+ RemainingVariableStorageSize += OriginalVarSize;
+ }
+ if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
+ //
+ // No enough space for Variable[Index].
+ //
+ VA_END (Args);
+ return FALSE;
+ }
+ //
+ // Sub the (new) size of Variable[Index] from remaining variable storage size.
+ //
+ RemainingVariableStorageSize -= VariableEntry->VariableSize;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ }
+ VA_END (Args);
+
+ return TRUE;
+}
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ )
+{
+ VA_LIST Marker;
+ BOOLEAN Return;
+
+ VA_START (Marker, Attributes);
+
+ Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+ VA_END (Marker);
+
+ return Return;
+}
+
+/**
+ Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
+
+ When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
+
+ According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
+ and are read-only. Therefore, in variable driver, only store the original value for other use.
+
+ @param[in] VariableName Name of variable.
+
+ @param[in] Data Variable data.
+
+ @param[in] DataSize Size of data. 0 means delete.
+
+ @retval EFI_SUCCESS The update operation is successful or ignored.
+ @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
+ @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
+ @retval Others Other errors happened during the update operation.
+
+**/
+EFI_STATUS
+AutoUpdateLangVariable (
+ IN CHAR16 *VariableName,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BestPlatformLang;
+ CHAR8 *BestLang;
+ UINTN Index;
+ UINT32 Attributes;
+ VARIABLE_POINTER_TRACK Variable;
+ BOOLEAN SetLanguageCodes;
+ VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
+
+ //
+ // Don't do updates for delete operation
+ //
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ SetLanguageCodes = FALSE;
+
+ if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
+ //
+ // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (AtRuntime ()) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
+ FreePool (mVariableModuleGlobal->PlatformLangCodes);
+ }
+ mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
+
+ //
+ // PlatformLang holds a single language from PlatformLangCodes,
+ // so the size of PlatformLangCodes is enough for the PlatformLang.
+ //
+ if (mVariableModuleGlobal->PlatformLang != NULL) {
+ FreePool (mVariableModuleGlobal->PlatformLang);
+ }
+ mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
+ ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
+
+ } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
+ //
+ // LangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (AtRuntime ()) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (mVariableModuleGlobal->LangCodes != NULL) {
+ FreePool (mVariableModuleGlobal->LangCodes);
+ }
+ mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (mVariableModuleGlobal->LangCodes != NULL);
+ }
+
+ if (SetLanguageCodes
+ && (mVariableModuleGlobal->PlatformLangCodes != NULL)
+ && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // Update Lang if PlatformLang is already set
+ // Update PlatformLang if Lang is already set
+ //
+ Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Lang
+ //
+ VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
+ Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ } else {
+ Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update PlatformLang
+ //
+ VariableName = EFI_LANG_VARIABLE_NAME;
+ Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ } else {
+ //
+ // Neither PlatformLang nor Lang is set, directly return
+ //
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
+ //
+ Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
+ //
+ // Update Lang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // When setting PlatformLang, firstly get most matched language string from supported language codes.
+ //
+ BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
+ if (BestPlatformLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
+
+ //
+ // Get the corresponding ISO639 language tag according to RFC4646 language tag.
+ //
+ BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
+
+ //
+ // Check the variable space for both Lang and PlatformLang variable.
+ //
+ VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+ VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;
+
+ VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
+ VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
+ if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+ //
+ // No enough variable space to set both Lang and PlatformLang successfully.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
+ //
+ FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+ Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,
+ ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);
+ }
+
+ DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
+ }
+ }
+
+ } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
+ //
+ // Update PlatformLang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // When setting Lang, firstly get most matched language string from supported language codes.
+ //
+ BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
+ if (BestLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
+
+ //
+ // Get the corresponding RFC4646 language tag according to ISO639 language tag.
+ //
+ BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
+
+ //
+ // Check the variable space for both PlatformLang and Lang variable.
+ //
+ VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
+ VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
+
+ VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+ VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;
+ if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+ //
+ // No enough variable space to set both PlatformLang and Lang successfully.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
+ //
+ FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+ Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,
+ AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);
+ }
+
+ DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
+ }
+ }
+ }
+
+ if (SetLanguageCodes) {
+ //
+ // Continue to set PlatformLangCodes or LangCodes.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN EFI_TIME *TimeStamp OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_HEADER *NextVariable;
+ UINTN ScratchSize;
+ UINTN MaxDataSize;
+ UINTN VarNameOffset;
+ UINTN VarDataOffset;
+ UINTN VarNameSize;
+ UINTN VarSize;
+ BOOLEAN Volatile;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ UINT8 State;
+ VARIABLE_POINTER_TRACK *Variable;
+ VARIABLE_POINTER_TRACK NvVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
+ UINT8 *BufferForMerge;
+ UINTN MergedBufSize;
+ BOOLEAN DataReady;
+ UINTN DataOffset;
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ BOOLEAN AuthFormat;
+
+ if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
+ //
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ //
+ DEBUG ((EFI_D_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
+ return EFI_NOT_AVAILABLE_YET;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ //
+ // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ // The authenticated variable perhaps is not initialized, just return here.
+ //
+ DEBUG ((EFI_D_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ }
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // Check if CacheVariable points to the variable in variable HOB.
+ // If yes, let CacheVariable points to the variable in NV variable cache.
+ //
+ if ((CacheVariable->CurrPtr != NULL) &&
+ (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
+ (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))
+ ) {
+ CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
+ CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
+ CacheVariable->Volatile = FALSE;
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat);
+ if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {
+ //
+ // There is no matched variable in NV variable cache.
+ //
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // It is to delete variable,
+ // go to delete this variable in variable HOB and
+ // try to flush other variables from HOB to flash.
+ //
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
+ Variable = CacheVariable;
+ } else {
+ //
+ // Update/Delete existing NV variable.
+ // CacheVariable points to the variable in the memory copy of Flash area
+ // Now let Variable points to the same variable in Flash area.
+ //
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
+ Variable = &NvVariable;
+ Variable->StartPtr = GetStartPointer (VariableStoreHeader);
+ Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
+
+ Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
+ if (CacheVariable->InDeletedTransitionPtr != NULL) {
+ Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
+ } else {
+ Variable->InDeletedTransitionPtr = NULL;
+ }
+ Variable->Volatile = FALSE;
+ }
+
+ Fvb = mVariableModuleGlobal->FvbInstance;
+
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
+ ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
+ SetMem (NextVariable, ScratchSize, 0xff);
+ DataReady = FALSE;
+
+ if (Variable->CurrPtr != NULL) {
+ //
+ // Update/Delete existing variable.
+ //
+ if (AtRuntime ()) {
+ //
+ // If AtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ //
+ // Only variable that have NV attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Only variable that have RT attributes can be updated/deleted in Runtime.
+ //
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Setting a data variable with no access, or zero DataSize attributes
+ // causes it to be deleted.
+ // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
+ // not delete the variable.
+ //
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ //
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+ State = CacheVariable->InDeletedTransitionPtr->State;
+ State &= VAR_DELETED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ Fvb,
+ (UINTN) &Variable->InDeletedTransitionPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!Variable->Volatile) {
+ CacheVariable->InDeletedTransitionPtr->State = State;
+ }
+ } else {
+ goto Done;
+ }
+ }
+
+ State = CacheVariable->CurrPtr->State;
+ State &= VAR_DELETED;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ Fvb,
+ (UINTN) &Variable->CurrPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
+ if (!Variable->Volatile) {
+ CacheVariable->CurrPtr->State = State;
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+ goto Done;
+ }
+ //
+ // If the variable is marked valid, and the same data has been passed in,
+ // then return to the caller immediately.
+ //
+ if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize &&
+ (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) &&
+ ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
+ (TimeStamp == NULL)) {
+ //
+ // Variable content unchanged and no need to update timestamp, just return.
+ //
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
+ (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
+
+ //
+ // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
+ //
+ if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
+ //
+ // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
+ // From DataOffset of NextVariable is to save the existing variable data.
+ //
+ DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat);
+ BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);
+ CopyMem (
+ BufferForMerge,
+ (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset),
+ DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
+ );
+
+ //
+ // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
+ } else {
+ MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
+ }
+
+ //
+ // Append the new data to the end of existing data.
+ // Max Harware error record variable data size is different from common/auth variable.
+ //
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
+ }
+
+ if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) {
+ //
+ // Existing data size + new data size exceed maximum variable size limitation.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ CopyMem (
+ (UINT8*) (
+ (UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
+ ),
+ Data,
+ DataSize
+ );
+ MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) +
+ DataSize;
+
+ //
+ // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
+ //
+ Data = BufferForMerge;
+ DataSize = MergedBufSize;
+ DataReady = TRUE;
+ }
+
+ //
+ // Mark the old variable as in delete transition.
+ //
+ State = CacheVariable->CurrPtr->State;
+ State &= VAR_IN_DELETED_TRANSITION;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ Fvb,
+ (UINTN) &Variable->CurrPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (!Variable->Volatile) {
+ CacheVariable->CurrPtr->State = State;
+ }
+ }
+ } else {
+ //
+ // Not found existing variable. Create a new variable.
+ //
+
+ if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Make sure we are trying to create a new variable.
+ // Setting a data variable with zero DataSize or no access attributes means to delete it.
+ //
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime.
+ //
+ if (AtRuntime () &&
+ (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Function part - create a new variable and copy the data.
+ // Both update a variable and create a variable will come here.
+ //
+ NextVariable->StartId = VARIABLE_DATA;
+ //
+ // NextVariable->State = VAR_ADDED;
+ //
+ NextVariable->Reserved = 0;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) NextVariable;
+ AuthVariable->PubKeyIndex = KeyIndex;
+ AuthVariable->MonotonicCount = MonotonicCount;
+ ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
+
+ if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ (TimeStamp != NULL)) {
+ if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
+ CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ //
+ // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+ // when the new TimeStamp value is later than the current timestamp associated
+ // with the variable, we need associate the new timestamp with the updated value.
+ //
+ if (Variable->CurrPtr != NULL) {
+ if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
+ CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
+ // Attributes bitmask parameter of a GetVariable() call.
+ //
+ NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+ VarNameOffset = GetVariableHeaderSize (AuthFormat);
+ VarNameSize = StrSize (VariableName);
+ CopyMem (
+ (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
+ VariableName,
+ VarNameSize
+ );
+ VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
+
+ //
+ // If DataReady is TRUE, it means the variable data has been saved into
+ // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
+ //
+ if (!DataReady) {
+ CopyMem (
+ (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
+ Data,
+ DataSize
+ );
+ }
+
+ CopyMem (
+ GetVendorGuidPtr (NextVariable, AuthFormat),
+ VendorGuid,
+ sizeof (EFI_GUID)
+ );
+ //
+ // There will be pad bytes after Data, the NextVariable->NameSize and
+ // NextVariable->DataSize should not include pad size so that variable
+ // service can get actual size in GetVariable.
+ //
+ SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
+ SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
+
+ //
+ // The actual size of the variable that stores in storage should
+ // include pad size.
+ //
+ VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Create a nonvolatile variable.
+ //
+ Volatile = FALSE;
+
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+ IsCommonVariable = TRUE;
+ IsCommonUserVariable = IsUserVariable (NextVariable);
+ }
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
+ && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
+ || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
+ || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))) {
+ if (AtRuntime ()) {
+ if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ Variable,
+ NextVariable,
+ HEADER_ALIGN (VarSize)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The new variable has been integrated successfully during reclaiming.
+ //
+ if (Variable->CurrPtr != NULL) {
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
+ CacheVariable->InDeletedTransitionPtr = NULL;
+ }
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ } else {
+ if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ }
+ goto Done;
+ }
+
+ if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+ //
+ // Four steps
+ // 1. Write variable header
+ // 2. Set variable state to header valid
+ // 3. Write variable data
+ // 4. Set variable state to valid
+ //
+ //
+ // Step 1:
+ //
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ (UINT32) GetVariableHeaderSize (AuthFormat),
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Step 2:
+ //
+ NextVariable->State = VAR_HEADER_VALID_ONLY;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
+ sizeof (UINT8),
+ &NextVariable->State
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Step 3:
+ //
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (AuthFormat),
+ (UINT32) (VarSize - GetVariableHeaderSize (AuthFormat)),
+ (UINT8 *) NextVariable + GetVariableHeaderSize (AuthFormat)
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Step 4:
+ //
+ NextVariable->State = VAR_ADDED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
+ sizeof (UINT8),
+ &NextVariable->State
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Update the memory copy of Flash region.
+ //
+ CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
+ } else {
+ //
+ // Emulated non-volatile variable mode.
+ //
+ NextVariable->State = VAR_ADDED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ (UINT32) VarSize,
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
+ if (IsCommonUserVariable) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
+ }
+ }
+ } else {
+ //
+ // Create a volatile variable.
+ //
+ Volatile = TRUE;
+
+ if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
+ //
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
+ &mVariableModuleGlobal->VolatileLastVariableOffset,
+ TRUE,
+ Variable,
+ NextVariable,
+ HEADER_ALIGN (VarSize)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The new variable has been integrated successfully during reclaiming.
+ //
+ if (Variable->CurrPtr != NULL) {
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
+ CacheVariable->InDeletedTransitionPtr = NULL;
+ }
+ UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
+ }
+ goto Done;
+ }
+
+ NextVariable->State = VAR_ADDED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ TRUE,
+ TRUE,
+ Fvb,
+ mVariableModuleGlobal->VolatileLastVariableOffset,
+ (UINT32) VarSize,
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
+ }
+
+ //
+ // Mark the old variable as deleted.
+ //
+ if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ //
+ // Both ADDED and IN_DELETED_TRANSITION old variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+ State = CacheVariable->InDeletedTransitionPtr->State;
+ State &= VAR_DELETED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ Fvb,
+ (UINTN) &Variable->InDeletedTransitionPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (!EFI_ERROR (Status)) {
+ if (!Variable->Volatile) {
+ CacheVariable->InDeletedTransitionPtr->State = State;
+ }
+ } else {
+ goto Done;
+ }
+ }
+
+ State = CacheVariable->CurrPtr->State;
+ State &= VAR_DELETED;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ Fvb,
+ (UINTN) &Variable->CurrPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (!EFI_ERROR (Status) && !Variable->Volatile) {
+ CacheVariable->CurrPtr->State = State;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
+ if (!Volatile) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+
+Done:
+ if (!EFI_ERROR (Status)) {
+ if ((Variable->CurrPtr != NULL && !Variable->Volatile) || (Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);
+ } else {
+ VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
+ }
+
+ if (VolatileCacheInstance->Store != NULL) {
+ Status = SynchronizeRuntimeVariableCache (
+ VolatileCacheInstance,
+ 0,
+ VolatileCacheInstance->Store->Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return Status;
+}
+
+/**
+
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize is external input.
+ This function will do basic validation, before parse the data.
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found.
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data The buffer to return the contents of the variable. May be NULL
+ with a zero DataSize in order to determine the size buffer needed.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableName[0] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data size
+ //
+ VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ ASSERT (VarDataSize != 0);
+
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);
+
+ *DataSize = VarDataSize;
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ *DataSize = VarDataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+Done:
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ if (Attributes != NULL && Variable.CurrPtr != NULL) {
+ *Attributes = Variable.CurrPtr->Attributes;
+ }
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+}
+
+/**
+
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param VariableNameSize The size of the VariableName buffer. The size must be large
+ enough to fit input string supplied in VariableName buffer.
+ @param VariableName Pointer to variable name.
+ @param VendorGuid Variable Vendor Guid.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
+ VariableNameSize has been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+ GUID of an existing variable.
+ @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
+ the input VariableName buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxLen;
+ UINTN VarNameSize;
+ BOOLEAN AuthFormat;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // Calculate the possible maximum length of name string, including the Null terminator.
+ //
+ MaxLen = *VariableNameSize / sizeof (CHAR16);
+ if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
+ //
+ // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
+ // follow spec to return EFI_INVALID_PARAMETER.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as FindVariable
+ // makes use of this mapping to implement search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
+
+ Status = VariableServiceGetNextVariableInternal (
+ VariableName,
+ VendorGuid,
+ VariableStoreHeader,
+ &VariablePtr,
+ AuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ VarNameSize = NameSizeOfVariable (VariablePtr, AuthFormat);
+ ASSERT (VarNameSize != 0);
+ if (VarNameSize <= *VariableNameSize) {
+ CopyMem (
+ VariableName,
+ GetVariableNamePtr (VariablePtr, AuthFormat),
+ VarNameSize
+ );
+ CopyMem (
+ VendorGuid,
+ GetVendorGuidPtr (VariablePtr, AuthFormat),
+ sizeof (EFI_GUID)
+ );
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ }
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+}
+
+/**
+
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ EFI_STATUS Status;
+ VARIABLE_HEADER *NextVariable;
+ EFI_PHYSICAL_ADDRESS Point;
+ UINTN PayloadSize;
+ BOOLEAN AuthFormat;
+
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // Check input parameters.
+ //
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for reserverd bit in variable attribute.
+ // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
+ // the delete operation of common authenticated variable at user physical presence.
+ // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
+ //
+ if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure if runtime bit is set, boot service bit is set also.
+ //
+ if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ return EFI_UNSUPPORTED;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ //
+ // Not support authenticated variable write.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+ //
+ // Not support harware error record variable variable.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
+ // cannot be set both.
+ //
+ if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+ && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
+ //
+ // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
+ // Maybe it's the delete operation of common authenticated variable at user physical presence.
+ //
+ if (DataSize != AUTHINFO_SIZE) {
+ return EFI_UNSUPPORTED;
+ }
+ PayloadSize = DataSize - AUTHINFO_SIZE;
+ } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ //
+ // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
+ //
+ if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||
+ ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||
+ ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ //
+ // The VariableSpeculationBarrier() call here is to ensure the above sanity
+ // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
+ // before the execution of subsequent codes.
+ //
+ VariableSpeculationBarrier ();
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+ } else {
+ PayloadSize = DataSize;
+ }
+
+ if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){
+ //
+ // Prevent whole variable size overflow
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The size of the VariableName, including the Unicode Null in bytes plus
+ // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
+ // bytes for HwErrRec#### variable.
+ //
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (StrSize (VariableName) + PayloadSize >
+ PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // The size of the VariableName, including the Unicode Null in bytes plus
+ // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (StrSize (VariableName) + PayloadSize >
+ mVariableModuleGlobal->MaxAuthVariableSize -
+ GetVariableHeaderSize (AuthFormat)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Failed to set variable '%s' with Guid %g\n",
+ __FUNCTION__, VariableName, VendorGuid));
+ DEBUG ((DEBUG_ERROR,
+ "NameSize(0x%x) + PayloadSize(0x%x) > "
+ "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
+ StrSize (VariableName), PayloadSize,
+ mVariableModuleGlobal->MaxAuthVariableSize,
+ GetVariableHeaderSize (AuthFormat)
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ if (StrSize (VariableName) + PayloadSize >
+ mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (AuthFormat)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Failed to set variable '%s' with Guid %g\n",
+ __FUNCTION__, VariableName, VendorGuid));
+ DEBUG ((DEBUG_ERROR,
+ "NameSize(0x%x) + PayloadSize(0x%x) > "
+ "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
+ StrSize (VariableName), PayloadSize,
+ mVariableModuleGlobal->MaxVariableSize,
+ GetVariableHeaderSize (AuthFormat)
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (StrSize (VariableName) + PayloadSize >
+ mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (AuthFormat)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Failed to set variable '%s' with Guid %g\n",
+ __FUNCTION__, VariableName, VendorGuid));
+ DEBUG ((DEBUG_ERROR,
+ "NameSize(0x%x) + PayloadSize(0x%x) > "
+ "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
+ StrSize (VariableName), PayloadSize,
+ mVariableModuleGlobal->MaxVolatileVariableSize,
+ GetVariableHeaderSize (AuthFormat)
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ //
+ // Special Handling for MOR Lock variable.
+ //
+ Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));
+ if (Status == EFI_ALREADY_STARTED) {
+ //
+ // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
+ // Variable driver can just return SUCCESS.
+ //
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ //
+ // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
+ //
+ if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
+ Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ //
+ // Parse non-volatile variable data and get last variable offset.
+ //
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
+ while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) {
+ NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
+ }
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
+ }
+
+ //
+ // Check whether the input variable is already existed.
+ //
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
+ if (!EFI_ERROR (Status)) {
+ if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {
+ //
+ // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
+ // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
+ // 1. No access attributes specified
+ // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
+ //
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
+ goto Done;
+ }
+ }
+
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+ //
+ // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
+ //
+ Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
+ //
+ goto Done;
+ }
+ }
+
+ if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
+ } else {
+ Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
+ }
+
+Done:
+ InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ if (!AtRuntime ()) {
+ if (!EFI_ERROR (Status)) {
+ SecureBootHook (
+ VariableName,
+ VendorGuid
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_SUCCESS Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *NextVariable;
+ UINT64 VariableSize;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT64 CommonVariableTotalSize;
+ UINT64 HwErrVariableTotalSize;
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+
+ CommonVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ //
+ // Query is Volatile related.
+ //
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ } else {
+ //
+ // Query is Non-Volatile related.
+ //
+ VariableStoreHeader = mNvVariableCache;
+ }
+
+ //
+ // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
+ // with the storage size (excluding the storage header size).
+ //
+ *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
+
+ //
+ // Harware error record variable needs larger size.
+ //
+ if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
+ *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ } else {
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ if (AtRuntime ()) {
+ *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
+ } else {
+ *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
+ }
+ }
+
+ //
+ // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ } else {
+ *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }
+ }
+
+ //
+ // Point to the starting address of the variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+
+ //
+ // Now walk through the related variable store.
+ //
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
+
+ if (AtRuntime ()) {
+ //
+ // We don't take the state of the variables in mind
+ // when calculating RemainingVariableStorageSize,
+ // since the space occupied by variables not marked with
+ // VAR_ADDED is not allowed to be reclaimed in Runtime.
+ //
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ } else {
+ //
+ // Only care about Variables with State VAR_ADDED, because
+ // the space not marked as VAR_ADDED is reclaimable now.
+ //
+ if (Variable->State == VAR_ADDED) {
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is not also a same ADDED one at the same time,
+ // this IN_DELETED_TRANSITION variable is valid.
+ //
+ VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+ VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
+ Status = FindVariableEx (
+ GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ FALSE,
+ &VariablePtrTrack,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ }
+
+ //
+ // Go to the next one.
+ //
+ Variable = NextVariable;
+ }
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
+ } else {
+ if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
+ *RemainingVariableStorageSize = 0;
+ } else {
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
+ }
+ }
+
+ if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
+ *MaximumVariableSize = 0;
+ } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) <
+ *MaximumVariableSize
+ ) {
+ *MaximumVariableSize = *RemainingVariableStorageSize -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @return EFI_SUCCESS Query successfully.
+ @return EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ EFI_STATUS Status;
+
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ //
+ // Deprecated attribute, make this check as highest priority.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
+ //
+ // Make sure the Attributes combination is supported by the platform.
+ //
+ return EFI_UNSUPPORTED;
+ } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ //
+ // Make sure if runtime bit is set, boot service bit is set also.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
+ //
+ // Make sure RT Attribute is set if we are in Runtime phase.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ //
+ // Make sure Hw Attribute is set with NV.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ //
+ // Not support authenticated variable write.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+ //
+ // Not support harware error record variable variable.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = VariableServiceQueryVariableInfoInternal (
+ Attributes,
+ MaximumVariableStorageSize,
+ RemainingVariableStorageSize,
+ MaximumVariableSize
+ );
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+}
+
+/**
+ This function reclaims variable storage if free size is below the threshold.
+
+ Caution: This function may be invoked at SMM mode.
+ Care must be taken to make sure not security issue.
+
+**/
+VOID
+ReclaimForOS(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN RemainingCommonRuntimeVariableSpace;
+ UINTN RemainingHwErrVariableSpace;
+ STATIC BOOLEAN Reclaimed;
+
+ //
+ // This function will be called only once at EndOfDxe or ReadyToBoot event.
+ //
+ if (Reclaimed) {
+ return;
+ }
+ Reclaimed = TRUE;
+
+ Status = EFI_SUCCESS;
+
+ if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
+ RemainingCommonRuntimeVariableSpace = 0;
+ } else {
+ RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
+ }
+
+ RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
+
+ //
+ // Check if the free area is below a threshold.
+ //
+ if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
+ (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
+ ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
+ (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ NULL,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Get maximum variable size, covering both non-volatile and volatile variables.
+
+ @return Maximum variable size.
+
+**/
+UINTN
+GetMaxVariableSize (
+ VOID
+ )
+{
+ UINTN MaxVariableSize;
+
+ MaxVariableSize = GetNonVolatileMaxVariableSize();
+ //
+ // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
+ // the default zero value.
+ //
+ if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
+ MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
+ }
+ return MaxVariableSize;
+}
+
+/**
+ Flush the HOB variable to flash.
+
+ @param[in] VariableName Name of variable has been updated or deleted.
+ @param[in] VendorGuid Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_HEADER *Variable;
+ VOID *VariableData;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ BOOLEAN ErrorFlag;
+ BOOLEAN AuthFormat;
+
+ ErrorFlag = FALSE;
+ AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ //
+ // Flush the HOB variable to flash.
+ //
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ //
+ // Set HobVariableBase to 0, it can avoid SetVariable to call back.
+ //
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ for ( Variable = GetStartPointer (VariableStoreHeader)
+ ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
+ ; Variable = GetNextVariablePtr (Variable, AuthFormat)
+ ) {
+ if (Variable->State != VAR_ADDED) {
+ //
+ // The HOB variable has been set to DELETED state in local.
+ //
+ continue;
+ }
+ ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
+ if (VendorGuid == NULL || VariableName == NULL ||
+ !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) ||
+ StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0) {
+ VariableData = GetVariableDataPtr (Variable, AuthFormat);
+ FindVariable (
+ GetVariableNamePtr (Variable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat),
+ &VariablePtrTrack,
+ &mVariableModuleGlobal->VariableGlobal, FALSE
+ );
+ Status = UpdateVariable (
+ GetVariableNamePtr (Variable, AuthFormat),
+ GetVendorGuidPtr (Variable, AuthFormat),
+ VariableData,
+ DataSizeOfVariable (Variable, AuthFormat),
+ Variable->Attributes,
+ 0,
+ 0,
+ &VariablePtrTrack,
+ NULL
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ "Variable driver flush the HOB variable to flash: %g %s %r\n",
+ GetVendorGuidPtr (Variable, AuthFormat),
+ GetVariableNamePtr (Variable, AuthFormat),
+ Status
+ ));
+ } else {
+ //
+ // The updated or deleted variable is matched with this HOB variable.
+ // Don't break here because we will try to set other HOB variables
+ // since this variable could be set successfully.
+ //
+ Status = EFI_SUCCESS;
+ }
+ if (!EFI_ERROR (Status)) {
+ //
+ // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
+ // set the HOB variable to DELETED state in local.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "Variable driver set the HOB variable to DELETED state in local: %g %s\n",
+ GetVendorGuidPtr (Variable, AuthFormat),
+ GetVariableNamePtr (Variable, AuthFormat)
+ ));
+ Variable->State &= VAR_DELETED;
+ } else {
+ ErrorFlag = TRUE;
+ }
+ }
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) {
+ Status = SynchronizeRuntimeVariableCache (
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
+ 0,
+ mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (ErrorFlag) {
+ //
+ // We still have HOB variable(s) not flushed in flash.
+ //
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
+ } else {
+ //
+ // All HOB variables have been flushed in flash.
+ //
+ DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) {
+ *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE;
+ }
+ if (!AtRuntime ()) {
+ FreePool ((VOID *) VariableStoreHeader);
+ }
+ }
+ }
+
+}
+
+/**
+ Initializes variable write service.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Others Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT8 Data;
+ VARIABLE_ENTRY_PROPERTY *VariableEntry;
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ //
+ // Check if the free area is really free.
+ //
+ for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
+ Data = ((UINT8 *) mNvVariableCache)[Index];
+ if (Data != 0xff) {
+ //
+ // There must be something wrong in variable store, do reclaim operation.
+ //
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ NULL,
+ NULL,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+ }
+ break;
+ }
+ }
+
+ FlushHobVariableToFlash (NULL, NULL);
+
+ Status = EFI_SUCCESS;
+ ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ //
+ // Authenticated variable initialize.
+ //
+ mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
+ mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
+ if (mAuthContextOut.AuthVarEntry != NULL) {
+ for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
+ VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
+ Status = VarCheckLibVariablePropertySet (
+ VariableEntry->Name,
+ VariableEntry->Guid,
+ &VariableEntry->VariableProperty
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ } else if (Status == EFI_UNSUPPORTED) {
+ DEBUG ((EFI_D_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
+ DEBUG ((EFI_D_INFO, "Variable driver will continue to work without auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
+ VariableEntry = &mVariableEntryProperty[Index];
+ Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ //
+ // Initialize MOR Lock variable.
+ //
+ MorLockInit ();
+
+ return Status;
+}
+
+/**
+ Convert normal variable storage to the allocated auth variable storage.
+
+ @param[in] NormalVarStorage Pointer to the normal variable storage header
+
+ @retval the allocated auth variable storage
+**/
+VOID *
+ConvertNormalVarStorageToAuthVarStorage (
+ VARIABLE_STORE_HEADER *NormalVarStorage
+ )
+{
+ VARIABLE_HEADER *StartPtr;
+ UINT8 *NextPtr;
+ VARIABLE_HEADER *EndPtr;
+ UINTN AuthVarStroageSize;
+ AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
+ VARIABLE_STORE_HEADER *AuthVarStorage;
+
+ AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
+ //
+ // Set AuthFormat as FALSE for normal variable storage
+ //
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
+
+ //
+ // Calculate Auth Variable Storage Size
+ //
+ StartPtr = GetStartPointer (NormalVarStorage);
+ EndPtr = GetEndPointer (NormalVarStorage);
+ while (StartPtr < EndPtr) {
+ if (StartPtr->State == VAR_ADDED) {
+ AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
+ AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
+ AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
+ }
+ StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }
+
+ //
+ // Allocate Runtime memory for Auth Variable Storage
+ //
+ AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
+ ASSERT (AuthVarStorage != NULL);
+ if (AuthVarStorage == NULL) {
+ return NULL;
+ }
+
+ //
+ // Copy Variable from Normal storage to Auth storage
+ //
+ StartPtr = GetStartPointer (NormalVarStorage);
+ EndPtr = GetEndPointer (NormalVarStorage);
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage);
+ while (StartPtr < EndPtr) {
+ if (StartPtr->State == VAR_ADDED) {
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr);
+ //
+ // Copy Variable Header
+ //
+ AuthStartPtr->StartId = StartPtr->StartId;
+ AuthStartPtr->State = StartPtr->State;
+ AuthStartPtr->Attributes = StartPtr->Attributes;
+ AuthStartPtr->NameSize = StartPtr->NameSize;
+ AuthStartPtr->DataSize = StartPtr->DataSize;
+ CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
+ //
+ // Copy Variable Name
+ //
+ NextPtr = (UINT8 *) (AuthStartPtr + 1);
+ CopyMem (
+ NextPtr,
+ GetVariableNamePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+ AuthStartPtr->NameSize
+ );
+ //
+ // Copy Variable Data
+ //
+ NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
+ CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize);
+ //
+ // Go to next variable
+ //
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
+ }
+ StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ }
+ //
+ // Update Auth Storage Header
+ //
+ AuthVarStorage->Format = NormalVarStorage->Format;
+ AuthVarStorage->State = NormalVarStorage->State;
+ AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
+ CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
+ ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
+
+ //
+ // Restore AuthFormat
+ //
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
+ return AuthVarStorage;
+}
+
+/**
+ Get HOB variable store.
+
+ @param[in] VariableGuid NV variable store signature.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+GetHobVariableStore (
+ IN EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT64 VariableStoreLength;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ BOOLEAN NeedConvertNormalToAuth;
+
+ //
+ // Make sure there is no more than one Variable HOB.
+ //
+ DEBUG_CODE (
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+ ASSERT (FALSE);
+ } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+ ASSERT (FALSE);
+ }
+ }
+ }
+ );
+
+ //
+ // Combinations supported:
+ // 1. Normal NV variable store +
+ // Normal HOB variable store
+ // 2. Auth NV variable store +
+ // Auth HOB variable store
+ // 3. Auth NV variable store +
+ // Normal HOB variable store (code will convert it to Auth Format)
+ //
+ NeedConvertNormalToAuth = FALSE;
+ GuidHob = GetFirstGuidHob (VariableGuid);
+ if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) {
+ //
+ // Try getting it from normal variable HOB
+ //
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ NeedConvertNormalToAuth = TRUE;
+ }
+ if (GuidHob != NULL) {
+ VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
+ VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
+ if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
+ if (!NeedConvertNormalToAuth) {
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
+ } else {
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader);
+ }
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VolatileVariableStore;
+ UINTN ScratchSize;
+ EFI_GUID *VariableGuid;
+
+ //
+ // Allocate runtime memory for variable driver global structure.
+ //
+ mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
+ if (mVariableModuleGlobal == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
+
+ //
+ // Init non-volatile variable store.
+ //
+ Status = InitNonVolatileVariableStore ();
+ if (EFI_ERROR (Status)) {
+ FreePool (mVariableModuleGlobal);
+ return Status;
+ }
+
+ //
+ // mVariableModuleGlobal->VariableGlobal.AuthFormat
+ // has been initialized in InitNonVolatileVariableStore().
+ //
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable format!\n"));
+ //
+ // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
+ //
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ VariableGuid = &gEfiAuthenticatedVariableGuid;
+ } else {
+ DEBUG ((EFI_D_INFO, "Variable driver will work without auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ VariableGuid = &gEfiVariableGuid;
+ }
+
+ //
+ // Get HOB variable store.
+ //
+ Status = GetHobVariableStore (VariableGuid);
+ if (EFI_ERROR (Status)) {
+ if (mNvFvHeaderCache != NULL) {
+ FreePool (mNvFvHeaderCache);
+ }
+ FreePool (mVariableModuleGlobal);
+ return Status;
+ }
+
+ mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
+ PcdGet32 (PcdMaxVolatileVariableSize) :
+ mVariableModuleGlobal->MaxVariableSize
+ );
+ //
+ // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
+ //
+ ScratchSize = GetMaxVariableSize ();
+ mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
+ VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
+ if (VolatileVariableStore == NULL) {
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ }
+ if (mNvFvHeaderCache != NULL) {
+ FreePool (mNvFvHeaderCache);
+ }
+ FreePool (mVariableModuleGlobal);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
+
+ //
+ // Initialize Variable Specific Data.
+ //
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
+ mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
+
+ CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
+ VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
+ VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
+ VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
+ VolatileVariableStore->Reserved = 0;
+ VolatileVariableStore->Reserved1 = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the proper fvb handle and/or fvb protocol by the given Flash address.
+
+ @param[in] Address The Flash address.
+ @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
+ @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
+
+**/
+EFI_STATUS
+GetFvbInfoByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_HANDLE *FvbHandle OPTIONAL,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ HandleBuffer = NULL;
+ //
+ // Get all FVB handles.
+ //
+ Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the FVB to access variable store.
+ //
+ Fvb = NULL;
+ for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
+ Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Ensure this FVB protocol supported Write operation.
+ //
+ Status = Fvb->GetAttributes (Fvb, &Attributes);
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
+ continue;
+ }
+
+ //
+ // Compare the address and select the right one.
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Assume one FVB has one type of BlockSize.
+ //
+ Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
+ if (FvbHandle != NULL) {
+ *FvbHandle = HandleBuffer[Index];
+ }
+ if (FvbProtocol != NULL) {
+ *FvbProtocol = Fvb;
+ }
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ FreePool (HandleBuffer);
+
+ if (Fvb == NULL) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
new file mode 100644
index 000000000..0b2bb6ae6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -0,0 +1,829 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by Variable modules.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_H_
+#define _VARIABLE_H_
+
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Variable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/AuthVariableLib.h>
+#include <Library/VarCheckLib.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+#include <Guid/VariableFormat.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+#include <Guid/VarErrorFlag.h>
+
+#include "PrivilegePolymorphic.h"
+
+#define NV_STORAGE_VARIABLE_BASE (EFI_PHYSICAL_ADDRESS) \
+ (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? \
+ PcdGet64 (PcdFlashNvStorageVariableBase64) : \
+ PcdGet32 (PcdFlashNvStorageVariableBase))
+
+#define EFI_VARIABLE_ATTRIBUTES_MASK (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS | \
+ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+ EFI_VARIABLE_APPEND_WRITE)
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE 3
+
+typedef enum {
+ VariableStoreTypeVolatile,
+ VariableStoreTypeHob,
+ VariableStoreTypeNv,
+ VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+ UINT32 PendingUpdateOffset;
+ UINT32 PendingUpdateLength;
+ VARIABLE_STORE_HEADER *Store;
+} VARIABLE_RUNTIME_CACHE;
+
+typedef struct {
+ BOOLEAN *ReadLock;
+ BOOLEAN *PendingUpdate;
+ BOOLEAN *HobFlushComplete;
+ VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache;
+ VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache;
+ VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache;
+} VARIABLE_RUNTIME_CACHE_CONTEXT;
+
+typedef struct {
+ VARIABLE_HEADER *CurrPtr;
+ //
+ // If both ADDED and IN_DELETED_TRANSITION variable are present,
+ // InDeletedTransitionPtr will point to the IN_DELETED_TRANSITION one.
+ // Otherwise, CurrPtr will point to the ADDED or IN_DELETED_TRANSITION one,
+ // and InDeletedTransitionPtr will be NULL at the same time.
+ //
+ VARIABLE_HEADER *InDeletedTransitionPtr;
+ VARIABLE_HEADER *EndPtr;
+ VARIABLE_HEADER *StartPtr;
+ BOOLEAN Volatile;
+} VARIABLE_POINTER_TRACK;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS HobVariableBase;
+ EFI_PHYSICAL_ADDRESS VolatileVariableBase;
+ EFI_PHYSICAL_ADDRESS NonVolatileVariableBase;
+ VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext;
+ EFI_LOCK VariableServicesLock;
+ UINT32 ReentrantState;
+ BOOLEAN AuthFormat;
+ BOOLEAN AuthSupport;
+ BOOLEAN EmuNvMode;
+} VARIABLE_GLOBAL;
+
+typedef struct {
+ VARIABLE_GLOBAL VariableGlobal;
+ UINTN VolatileLastVariableOffset;
+ UINTN NonVolatileLastVariableOffset;
+ UINTN CommonVariableSpace;
+ UINTN CommonMaxUserVariableSpace;
+ UINTN CommonRuntimeVariableSpace;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ UINTN MaxVariableSize;
+ UINTN MaxAuthVariableSize;
+ UINTN MaxVolatileVariableSize;
+ UINTN ScratchBufferSize;
+ CHAR8 *PlatformLangCodes;
+ CHAR8 *LangCodes;
+ CHAR8 *PlatformLang;
+ CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1];
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance;
+} VARIABLE_MODULE_GLOBAL;
+
+/**
+ Flush the HOB variable to flash.
+
+ @param[in] VariableName Name of variable has been updated or deleted.
+ @param[in] VendorGuid Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Writes a buffer to variable storage space, in the working block.
+
+ This function writes a buffer to variable storage space into a firmware
+ volume block device. The destination is specified by the parameter
+ VariableBase. Fault Tolerant Write protocol is used for writing.
+
+ @param VariableBase Base address of the variable to write.
+ @param VariableBuffer Point to the variable data buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ IN VARIABLE_STORE_HEADER *VariableBuffer
+ );
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+ at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+ Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN IgnoreRtCheck
+ );
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param[in] Marker VA_LIST style variable argument list.
+ The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+ IN UINT32 Attributes,
+ IN VA_LIST Marker
+ );
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in, out] Variable The variable information that is used to keep track of variable usage.
+
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN OUT VARIABLE_POINTER_TRACK *Variable,
+ IN EFI_TIME *TimeStamp OPTIONAL
+ );
+
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ );
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param Lock A pointer to the lock data structure to initialize.
+ @param Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ );
+
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ );
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Retrieve the FVB protocol interface by HANDLE.
+
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param[out] FvBlock The interface of FVB protocol
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the FVB protocol.
+ @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ );
+
+/**
+ Function returns an array of handles that support the FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ VOID
+ );
+
+/**
+ This function reclaims variable storage if free size is below the threshold.
+
+**/
+VOID
+ReclaimForOS(
+ VOID
+ );
+
+/**
+ Get maximum variable size, covering both non-volatile and volatile variables.
+
+ @return Maximum variable size.
+
+**/
+UINTN
+GetMaxVariableSize (
+ VOID
+ );
+
+/**
+ Initializes variable write service.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Others Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+ VOID
+ );
+
+/**
+ Retrieve the SMM Fault Tolerent Write protocol interface.
+
+ @param[out] FtwProtocol The interface of SMM Ftw protocol
+
+ @retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol.
+ @retval EFI_NOT_FOUND The SMM SAR protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+ OUT VOID **FtwProtocol
+ );
+
+/**
+ Get the proper fvb handle and/or fvb protocol by the given Flash address.
+
+ @param[in] Address The Flash address.
+ @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
+ @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
+
+**/
+EFI_STATUS
+GetFvbInfoByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_HANDLE *FvbHandle OPTIONAL,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
+ );
+
+/**
+
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found.
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data The buffer to return the contents of the variable. May be NULL
+ with a zero DataSize in order to determine the size buffer needed.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+/**
+
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param VariableNameSize The size of the VariableName buffer. The size must be large
+ enough to fit input string supplied in VariableName buffer.
+ @param VariableName Pointer to variable name.
+ @param VendorGuid Variable Vendor Guid.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
+ VariableNameSize has been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+ GUID of an existing variable.
+ @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
+ the input VariableName buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ );
+
+/**
+
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_SUCCESS Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+/**
+
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @return EFI_SUCCESS Query successfully.
+ @return EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ );
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+ VOID
+ );
+
+extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+extern EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache;
+extern VARIABLE_STORE_HEADER *mNvVariableCache;
+extern VARIABLE_INFO_ENTRY *gVariableInfo;
+extern BOOLEAN mEndOfDxe;
+extern VAR_CHECK_REQUEST_SOURCE mRequestSource;
+
+extern AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the variable found.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the next variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Get scratch buffer.
+
+ @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+ the maximum supported buffer size, this value contains
+ the maximum supported buffer size as output.
+ @param[out] ScratchBuffer Pointer to scratch buffer address.
+
+ @retval EFI_SUCCESS Get scratch buffer successfully.
+ @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+ IN OUT UINTN *ScratchBufferSize,
+ OUT VOID **ScratchBuffer
+ );
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ );
+
+/**
+ Return TRUE if at OS runtime.
+
+ @retval TRUE If at OS runtime.
+ @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
new file mode 100644
index 000000000..7d2b6c8e1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -0,0 +1,581 @@
+/** @file
+ Implement all four UEFI Runtime Variable services for the nonvolatile
+ and volatile storage space and install variable architecture protocol.
+
+Copyright (C) 2013, Red Hat, Inc.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+EFI_HANDLE mHandle = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+VOID *mFtwRegistration = NULL;
+VOID ***mVarCheckAddressPointer = NULL;
+UINTN mVarCheckAddressPointerCount = 0;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock = { VariableLockRequestToLock };
+EDKII_VAR_CHECK_PROTOCOL mVarCheck = { VarCheckRegisterSetVariableCheckHandler,
+ VarCheckVariablePropertySet,
+ VarCheckVariablePropertyGet };
+
+/**
+ Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+ Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData(
+ VOID
+ );
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return EfiAtRuntime ();
+}
+
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param Lock A pointer to the lock data structure to initialize.
+ @param Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ )
+{
+ return EfiInitializeLock (Lock, Priority);
+}
+
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!AtRuntime ()) {
+ EfiAcquireLock (Lock);
+ }
+}
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!AtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+/**
+ Retrieve the Fault Tolerent Write protocol interface.
+
+ @param[out] FtwProtocol The interface of Ftw protocol
+
+ @retval EFI_SUCCESS The FTW protocol instance was found and returned in FtwProtocol.
+ @retval EFI_NOT_FOUND The FTW protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+ OUT VOID **FtwProtocol
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Fault Tolerent Write protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ NULL,
+ FtwProtocol
+ );
+ return Status;
+}
+
+/**
+ Retrieve the FVB protocol interface by HANDLE.
+
+ @param[in] FvBlockHandle The handle of FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param[out] FvBlock The interface of FVB protocol
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the FVB protocol.
+ @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ )
+{
+ //
+ // To get the FVB protocol interface on the handle
+ //
+ return gBS->HandleProtocol (
+ FvBlockHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) FvBlock
+ );
+}
+
+
+/**
+ Function returns an array of handles that support the FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate all handles of Fvb protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ NumberHandles,
+ Buffer
+ );
+ return Status;
+}
+
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableClassAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+
+ if (mVariableModuleGlobal->FvbInstance != NULL) {
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
+ }
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
+ EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
+ EfiConvertPointer (0x0, (VOID **) &mNvFvHeaderCache);
+
+ if (mAuthContextOut.AddressPointer != NULL) {
+ for (Index = 0; Index < mAuthContextOut.AddressPointerCount; Index++) {
+ EfiConvertPointer (0x0, (VOID **) mAuthContextOut.AddressPointer[Index]);
+ }
+ }
+
+ if (mVarCheckAddressPointer != NULL) {
+ for (Index = 0; Index < mVarCheckAddressPointerCount; Index++) {
+ EfiConvertPointer (0x0, (VOID **) mVarCheckAddressPointer[Index]);
+ }
+ }
+}
+
+
+/**
+ Notification function of EVT_GROUP_READY_TO_BOOT event group.
+
+ This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
+ When the Boot Manager is about to load and execute a boot option, it reclaims variable
+ storage if free size is below the threshold.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ if (!mEndOfDxe) {
+ MorLockInitAtEndOfDxe ();
+ //
+ // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
+ //
+ mEndOfDxe = TRUE;
+ mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ }
+ ReclaimForOS ();
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
+ } else {
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
+ }
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));
+ MorLockInitAtEndOfDxe ();
+ mEndOfDxe = TRUE;
+ mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+ ReclaimForOS ();
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Initializes variable write service for DXE.
+
+**/
+VOID
+VariableWriteServiceInitializeDxe (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = VariableWriteServiceInitialize ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
+ }
+
+ //
+ // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
+ // Secure Boot Policy Variable change. Record their initial value.
+ //
+ RecordSecureBootPolicyVarData();
+
+ //
+ // Install the Variable Write Architectural protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableWriteArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Fault Tolerant Write protocol notification event handler.
+
+ Non-Volatile variable write may needs FTW protocol to reclaim when
+ writting variable.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+FtwNotificationEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ UINT64 VariableStoreLength;
+ UINTN FtwMaxBlockSize;
+
+ //
+ // Ensure FTW protocol is installed.
+ //
+ Status = GetFtwProtocol ((VOID**) &FtwProtocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
+ NvStorageVariableBase = NV_STORAGE_VARIABLE_BASE;
+ VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;
+
+ //
+ // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+ //
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+
+ //
+ // Find the proper FVB protocol for variable.
+ //
+ Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ mVariableModuleGlobal->FvbInstance = FvbProtocol;
+
+ //
+ // Mark the variable storage region of the FLASH as RUNTIME.
+ //
+ VariableStoreLength = mNvVariableCache->Size;
+ BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
+ Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
+ Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
+
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Variable driver failed to get flash memory attribute.\n"));
+ } else {
+ if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == 0) {
+ Status = gDS->SetMemorySpaceAttributes (
+ BaseAddress,
+ Length,
+ GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));
+ }
+ }
+ }
+
+ //
+ // Initializes variable write service after FTW was ready.
+ //
+ VariableWriteServiceInitializeDxe ();
+
+ //
+ // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.
+ //
+ gBS->CloseEvent (Event);
+
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
+
+ Status = VariableCommonInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVarCheckProtocolGuid,
+ &mVarCheck,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
+ SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
+ SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
+ SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo;
+
+ //
+ // Now install the Variable Runtime Architectural protocol on a new handle.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ //
+ // Register FtwNotificationEvent () notify function.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ TPL_CALLBACK,
+ FtwNotificationEvent,
+ (VOID *)SystemTable,
+ &mFtwRegistration
+ );
+ } else {
+ //
+ // Emulated non-volatile variable mode does not depend on FVB and FTW.
+ //
+ VariableWriteServiceInitializeDxe ();
+ }
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableClassAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to reclaim variable for OS usage.
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_NOTIFY,
+ OnReadyToBoot,
+ NULL,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to set the End Of DXE flag.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ OnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
new file mode 100644
index 000000000..e865a089d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
@@ -0,0 +1,258 @@
+/** @file
+ Provides variable driver extended services.
+
+Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableParsing.h"
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the variable found.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ Status = FindVariable (
+ VariableName,
+ VendorGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ AuthVariableInfo->Data = NULL;
+ AuthVariableInfo->DataSize = 0;
+ AuthVariableInfo->Attributes = 0;
+ AuthVariableInfo->PubKeyIndex = 0;
+ AuthVariableInfo->MonotonicCount = 0;
+ AuthVariableInfo->TimeStamp = NULL;
+ return Status;
+ }
+
+ AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable.CurrPtr;
+ AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
+ AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariable->MonotonicCount));
+ AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the next variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_HEADER *VariablePtr;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+
+ VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
+
+ Status = VariableServiceGetNextVariableInternal (
+ VariableName,
+ VendorGuid,
+ VariableStoreHeader,
+ &VariablePtr,
+ mVariableModuleGlobal->VariableGlobal.AuthFormat
+ );
+ if (EFI_ERROR (Status)) {
+ AuthVariableInfo->VariableName = NULL;
+ AuthVariableInfo->VendorGuid = NULL;
+ AuthVariableInfo->Data = NULL;
+ AuthVariableInfo->DataSize = 0;
+ AuthVariableInfo->Attributes = 0;
+ AuthVariableInfo->PubKeyIndex = 0;
+ AuthVariableInfo->MonotonicCount = 0;
+ AuthVariableInfo->TimeStamp = NULL;
+ return Status;
+ }
+
+ AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Data = GetVariableDataPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ AuthVariableInfo->Attributes = VariablePtr->Attributes;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *) VariablePtr;
+ AuthVariableInfo->PubKeyIndex = AuthVariablePtr->PubKeyIndex;
+ AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariablePtr->MonotonicCount));
+ AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+
+ FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ return UpdateVariable (
+ AuthVariableInfo->VariableName,
+ AuthVariableInfo->VendorGuid,
+ AuthVariableInfo->Data,
+ AuthVariableInfo->DataSize,
+ AuthVariableInfo->Attributes,
+ AuthVariableInfo->PubKeyIndex,
+ AuthVariableInfo->MonotonicCount,
+ &Variable,
+ AuthVariableInfo->TimeStamp
+ );
+}
+
+/**
+ Get scratch buffer.
+
+ @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+ the maximum supported buffer size, this value contains
+ the maximum supported buffer size as output.
+ @param[out] ScratchBuffer Pointer to scratch buffer address.
+
+ @retval EFI_SUCCESS Get scratch buffer successfully.
+ @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+ IN OUT UINTN *ScratchBufferSize,
+ OUT VOID **ScratchBuffer
+ )
+{
+ UINTN MaxBufferSize;
+
+ MaxBufferSize = mVariableModuleGlobal->ScratchBufferSize;
+ if (*ScratchBufferSize > MaxBufferSize) {
+ *ScratchBufferSize = MaxBufferSize;
+ return EFI_UNSUPPORTED;
+ }
+
+ *ScratchBuffer = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ )
+{
+ VA_LIST Marker;
+ BOOLEAN Return;
+
+ VA_START (Marker, Attributes);
+
+ Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+ VA_END (Marker);
+
+ return Return;
+}
+
+/**
+ Return TRUE if at OS runtime.
+
+ @retval TRUE If at OS runtime.
+ @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+ VOID
+ )
+{
+ return AtRuntime ();
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
new file mode 100644
index 000000000..0637a828b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
@@ -0,0 +1,334 @@
+/** @file
+ Common variable non-volatile store routines.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+
+extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+
+/**
+ Get non-volatile maximum variable size.
+
+ @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+ VOID
+ )
+{
+ if (PcdGet32 (PcdHwErrStorageSize) != 0) {
+ return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
+ PcdGet32 (PcdMaxHardwareErrorVariableSize));
+ } else {
+ return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
+ }
+}
+
+/**
+ Init emulated non-volatile variable store.
+
+ @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+InitEmuNonVolatileVariableStore (
+ OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStore;
+ UINT32 VariableStoreLength;
+ BOOLEAN FullyInitializeStore;
+ UINT32 HwErrStorageSize;
+
+ FullyInitializeStore = TRUE;
+
+ VariableStoreLength = PcdGet32 (PcdVariableStoreSize);
+ ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
+
+ //
+ // Allocate memory for variable store.
+ //
+ if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {
+ VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);
+ if (VariableStore == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // A memory location has been reserved for the NV variable store. Certain
+ // platforms may be able to preserve a memory range across system resets,
+ // thereby providing better NV variable emulation.
+ //
+ VariableStore =
+ (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)
+ PcdGet64 (PcdEmuVariableNvStoreReserved);
+ if ((VariableStore->Size == VariableStoreLength) &&
+ (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&
+ (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
+ (VariableStore->State == VARIABLE_STORE_HEALTHY)) {
+ DEBUG((
+ DEBUG_INFO,
+ "Variable Store reserved at %p appears to be valid\n",
+ VariableStore
+ ));
+ FullyInitializeStore = FALSE;
+ }
+ }
+
+ if (FullyInitializeStore) {
+ SetMem (VariableStore, VariableStoreLength, 0xff);
+ //
+ // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
+ //
+ CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);
+ VariableStore->Size = VariableStoreLength;
+ VariableStore->Format = VARIABLE_STORE_FORMATTED;
+ VariableStore->State = VARIABLE_STORE_HEALTHY;
+ VariableStore->Reserved = 0;
+ VariableStore->Reserved1 = 0;
+ }
+
+ *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
+
+ HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
+
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than the value of
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+ //
+ ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+
+ mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
+ mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
+ mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Init real non-volatile variable store.
+
+ @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitRealNonVolatileVariableStore (
+ OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *VariableStore;
+ UINT32 VariableStoreLength;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT8 *NvStorageData;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+ UINT32 BackUpSize;
+ UINT32 HwErrStorageSize;
+ UINT32 MaxUserNvVariableSpaceSize;
+ UINT32 BoottimeReservedNvVariableSpaceSize;
+ EFI_STATUS Status;
+ VOID *FtwProtocol;
+
+ mVariableModuleGlobal->FvbInstance = NULL;
+
+ //
+ // Allocate runtime memory used for a memory copy of the FLASH region.
+ // Keep the memory and the FLASH in sync as updates occur.
+ //
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
+ if (NvStorageData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NvStorageBase = NV_STORAGE_VARIABLE_BASE;
+ ASSERT (NvStorageBase != 0);
+
+ //
+ // Copy NV storage data to the memory buffer.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);
+
+ Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+ //
+ // If FTW protocol has been installed, no need to check FTW last write data hob.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Check the FTW last write data hob.
+ //
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // Copy the backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
+ (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ //
+ // Flash NV storage from the Offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ BackUpSize = NvStorageSize - BackUpOffset;
+ DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // Copy the partial backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);
+ }
+ }
+ }
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+ FreePool (NvStorageData);
+ DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);
+ VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;
+ ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
+ ASSERT (VariableStore->Size == VariableStoreLength);
+
+ //
+ // Check if the Variable Store header is not corrupted
+ //
+ if (GetVariableStoreStatus (VariableStore) != EfiValid) {
+ FreePool (NvStorageData);
+ DEBUG((DEBUG_ERROR, "Variable Store header is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ mNvFvHeaderCache = FvHeader;
+
+ *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
+
+ HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
+ MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
+ BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
+
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than the value of
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+ //
+ ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+ //
+ // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+ //
+ ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+ //
+ // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+ //
+ ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+
+ mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
+ mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
+ mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Variable driver common space: 0x%x 0x%x 0x%x\n",
+ mVariableModuleGlobal->CommonVariableSpace,
+ mVariableModuleGlobal->CommonMaxUserVariableSpace,
+ mVariableModuleGlobal->CommonRuntimeVariableSpace
+ ));
+
+ //
+ // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+ //
+ ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Init non-volatile variable store.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+ VOID
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *NextVariable;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ UINTN VariableSize;
+ EFI_STATUS Status;
+
+ if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;
+ DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));
+ } else {
+ Status = InitRealNonVolatileVariableStore (&VariableStoreBase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;
+ }
+
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));
+
+ mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);
+ mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
+
+ //
+ // Parse non-volatile variable data and get last variable offset.
+ //
+ Variable = GetStartPointer (mNvVariableCache);
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h
new file mode 100644
index 000000000..43653f27e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.h
@@ -0,0 +1,67 @@
+/** @file
+ Common variable non-volatile store routines.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_NON_VOLATILE_H_
+#define _VARIABLE_NON_VOLATILE_H_
+
+#include "Variable.h"
+
+/**
+ Get non-volatile maximum variable size.
+
+ @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+ VOID
+ );
+
+/**
+ Init emulated non-volatile variable store.
+
+ @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+InitEmuNonVolatileVariableStore (
+ EFI_PHYSICAL_ADDRESS *VariableStoreBase
+ );
+
+/**
+ Init real non-volatile variable store.
+
+ @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitRealNonVolatileVariableStore (
+ OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase
+ );
+
+/**
+ Init non-volatile variable store.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
new file mode 100644
index 000000000..f6d187543
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.c
@@ -0,0 +1,788 @@
+/** @file
+ Functions in this module are associated with variable parsing operations and
+ are intended to be usable across variable driver source files.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableStoreEnd Pointer to the Variable Store End.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableStoreEnd
+ )
+{
+ if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
+ //
+ // Variable is NULL or has reached the end of variable store,
+ // or the StartId is not correct.
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the current status of Variable Store.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store status is raw.
+ @retval EfiValid Variable store status is valid.
+ @retval EfiInvalid Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFormat
+ )
+{
+ UINTN Value;
+
+ if (AuthFormat) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the variable header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFormat) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->NameSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+ }
+}
+
+/**
+ This code sets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] NameSize Name size to set.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetNameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN NameSize,
+ IN BOOLEAN AuthFormat
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFormat) {
+ AuthVariable->NameSize = (UINT32) NameSize;
+ } else {
+ Variable->NameSize = (UINT32) NameSize;
+ }
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFormat) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->DataSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+ }
+}
+
+/**
+ This code sets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] DataSize Data size to set.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetDataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN DataSize,
+ IN BOOLEAN AuthFormat
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFormat) {
+ AuthVariable->DataSize = (UINT32) DataSize;
+ } else {
+ Variable->DataSize = (UINT32) DataSize;
+ }
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFormat));
+}
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFormat) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable, AuthFormat);
+ Value += NameSizeOfVariable (Variable, AuthFormat);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat));
+
+ return (UINT8 *) Value;
+}
+
+/**
+ This code gets the variable data offset related to variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Variable Data offset.
+
+**/
+UINTN
+GetVariableDataOffset (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = GetVariableHeaderSize (AuthFormat);
+ Value += NameSizeOfVariable (Variable, AuthFormat);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat));
+
+ return Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ )
+{
+ UINTN Value;
+
+ Value = (UINTN) GetVariableDataPtr (Variable, AuthFormat);
+ Value += DataSizeOfVariable (Variable, AuthFormat);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable, AuthFormat));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The start of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+/**
+ Compare two EFI_TIME data.
+
+
+ @param[in] FirstTime A pointer to the first EFI_TIME data.
+ @param[in] SecondTime A pointer to the second EFI_TIME data.
+
+ @retval TRUE The FirstTime is not later than the SecondTime.
+ @retval FALSE The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+VariableCompareTimeStampInternal (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ )
+{
+ if (FirstTime->Year != SecondTime->Year) {
+ return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
+ } else if (FirstTime->Month != SecondTime->Month) {
+ return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
+ } else if (FirstTime->Day != SecondTime->Day) {
+ return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
+ } else if (FirstTime->Hour != SecondTime->Hour) {
+ return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
+ } else if (FirstTime->Minute != SecondTime->Minute) {
+ return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
+ }
+
+ return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
+}
+
+/**
+ Find the variable in the specified variable store.
+
+ @param[in] VariableName Name of the variable to be found
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+ @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+**/
+EFI_STATUS
+FindVariableEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN IgnoreRtCheck,
+ IN OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN BOOLEAN AuthFormat
+ )
+{
+ VARIABLE_HEADER *InDeletedVariable;
+ VOID *Point;
+
+ PtrTrack->InDeletedTransitionPtr = NULL;
+
+ //
+ // Find the variable by walk through HOB, volatile and non-volatile variable store.
+ //
+ InDeletedVariable = NULL;
+
+ for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
+ ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
+ ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
+ ) {
+ if (PtrTrack->CurrPtr->State == VAR_ADDED ||
+ PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
+ ) {
+ if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+ if (VariableName[0] == 0) {
+ if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+ return EFI_SUCCESS;
+ }
+ } else {
+ if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr, AuthFormat))) {
+ Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr, AuthFormat);
+
+ ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat) != 0);
+ if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat)) == 0) {
+ if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ PtrTrack->CurrPtr = InDeletedVariable;
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+ This code finds the next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+ @param[in] VariableStoreList A list of variable stores that should be used to get the next variable.
+ The maximum number of entries is the max value of VARIABLE_STORE_TYPE.
+ @param[out] VariablePtr Pointer to variable header address.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+ GUID of an existing variable.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VARIABLE_STORE_HEADER **VariableStoreList,
+ OUT VARIABLE_HEADER **VariablePtr,
+ IN BOOLEAN AuthFormat
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_TYPE StoreType;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariableInHob;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+
+ Status = EFI_NOT_FOUND;
+
+ if (VariableStoreList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Variable, sizeof (Variable));
+
+ // Check if the variable exists in the given variable store list
+ for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
+ if (VariableStoreList[StoreType] == NULL) {
+ continue;
+ }
+
+ Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+ Variable.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
+ Variable.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, &Variable, AuthFormat);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
+ //
+ // For VariableName is an empty string, FindVariableEx() will try to find and return
+ // the first qualified variable, and if FindVariableEx() returns error (EFI_NOT_FOUND)
+ // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
+ //
+ if (VariableName[0] != 0) {
+ //
+ // For VariableName is not an empty string, and FindVariableEx() returns error as
+ // VariableName and VendorGuid are not a name and GUID of an existing variable,
+ // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ }
+ goto Done;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not empty, get next variable.
+ //
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+ }
+
+ while (TRUE) {
+ //
+ // Switch to the next variable store if needed
+ //
+ while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
+ //
+ // Find current storage index
+ //
+ for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
+ if ((VariableStoreList[StoreType] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreList[StoreType]))) {
+ break;
+ }
+ }
+ ASSERT (StoreType < VariableStoreTypeMax);
+ //
+ // Switch to next storage
+ //
+ for (StoreType++; StoreType < VariableStoreTypeMax; StoreType++) {
+ if (VariableStoreList[StoreType] != NULL) {
+ break;
+ }
+ }
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (StoreType == VariableStoreTypeMax) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+ Variable.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
+ Variable.CurrPtr = Variable.StartPtr;
+ }
+
+ //
+ // Variable is found
+ //
+ if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+ if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ VariablePtrTrack.StartPtr = Variable.StartPtr;
+ VariablePtrTrack.EndPtr = Variable.EndPtr;
+ Status = FindVariableEx (
+ GetVariableNamePtr (Variable.CurrPtr, AuthFormat),
+ GetVendorGuidPtr (Variable.CurrPtr, AuthFormat),
+ FALSE,
+ &VariablePtrTrack,
+ AuthFormat
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+ continue;
+ }
+ }
+
+ //
+ // Don't return NV variable when HOB overrides it
+ //
+ if ((VariableStoreList[VariableStoreTypeHob] != NULL) && (VariableStoreList[VariableStoreTypeNv] != NULL) &&
+ (Variable.StartPtr == GetStartPointer (VariableStoreList[VariableStoreTypeNv]))
+ ) {
+ VariableInHob.StartPtr = GetStartPointer (VariableStoreList[VariableStoreTypeHob]);
+ VariableInHob.EndPtr = GetEndPointer (VariableStoreList[VariableStoreTypeHob]);
+ Status = FindVariableEx (
+ GetVariableNamePtr (Variable.CurrPtr, AuthFormat),
+ GetVendorGuidPtr (Variable.CurrPtr, AuthFormat),
+ FALSE,
+ &VariableInHob,
+ AuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+ continue;
+ }
+ }
+
+ *VariablePtr = Variable.CurrPtr;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ Routine used to track statistical information about variable usage.
+ The data is stored in the EFI system table so it can be accessed later.
+ VariableInfo.efi can dump out the table. Only Boot Services variable
+ accesses are tracked by this code. The PcdVariableCollectStatistics
+ build flag controls if this feature is enabled.
+
+ A read that hits in the cache will have Read and Cache true for
+ the transaction. Data is allocated by this routine, but never
+ freed.
+
+ @param[in] VariableName Name of the Variable to track.
+ @param[in] VendorGuid Guid of the Variable to track.
+ @param[in] Volatile TRUE if volatile FALSE if non-volatile.
+ @param[in] Read TRUE if GetVariable() was called.
+ @param[in] Write TRUE if SetVariable() was called.
+ @param[in] Delete TRUE if deleted via SetVariable().
+ @param[in] Cache TRUE for a cache hit.
+ @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_ENTRY structures.
+
+**/
+VOID
+UpdateVariableInfo (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN Read,
+ IN BOOLEAN Write,
+ IN BOOLEAN Delete,
+ IN BOOLEAN Cache,
+ IN OUT VARIABLE_INFO_ENTRY **VariableInfo
+ )
+{
+ VARIABLE_INFO_ENTRY *Entry;
+
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+ if (VariableName == NULL || VendorGuid == NULL || VariableInfo == NULL) {
+ return;
+ }
+ if (AtRuntime ()) {
+ // Don't collect statistics at runtime.
+ return;
+ }
+
+ if (*VariableInfo == NULL) {
+ //
+ // On the first call allocate a entry and place a pointer to it in
+ // the EFI System Table.
+ //
+ *VariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+ ASSERT (*VariableInfo != NULL);
+
+ CopyGuid (&(*VariableInfo)->VendorGuid, VendorGuid);
+ (*VariableInfo)->Name = AllocateZeroPool (StrSize (VariableName));
+ ASSERT ((*VariableInfo)->Name != NULL);
+ StrCpyS ((*VariableInfo)->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
+ (*VariableInfo)->Volatile = Volatile;
+ }
+
+
+ for (Entry = (*VariableInfo); Entry != NULL; Entry = Entry->Next) {
+ if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
+ if (StrCmp (VariableName, Entry->Name) == 0) {
+ if (Read) {
+ Entry->ReadCount++;
+ }
+ if (Write) {
+ Entry->WriteCount++;
+ }
+ if (Delete) {
+ Entry->DeleteCount++;
+ }
+ if (Cache) {
+ Entry->CacheCount++;
+ }
+
+ return;
+ }
+ }
+
+ if (Entry->Next == NULL) {
+ //
+ // If the entry is not in the table add it.
+ // Next iteration of the loop will fill in the data.
+ //
+ Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+ ASSERT (Entry->Next != NULL);
+
+ CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
+ Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));
+ ASSERT (Entry->Next->Name != NULL);
+ StrCpyS (Entry->Next->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
+ Entry->Next->Volatile = Volatile;
+ }
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
new file mode 100644
index 000000000..92a729d14
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableParsing.h
@@ -0,0 +1,347 @@
+/** @file
+ Functions in this module are associated with variable parsing operations and
+ are intended to be usable across variable driver source files.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_PARSING_H_
+#define _VARIABLE_PARSING_H_
+
+#include <Guid/ImageAuthentication.h>
+#include "Variable.h"
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableStoreEnd Pointer to the Variable Store End.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableStoreEnd
+ );
+
+/**
+
+ This code gets the current status of Variable Store.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store status is raw.
+ @retval EfiValid Variable store status is valid.
+ @retval EfiInvalid Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the variable header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ This code sets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] NameSize Name size to set.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetNameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN NameSize,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ This code gets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ This code sets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] DataSize Data size to set.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetDataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN DataSize,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ This code gets the variable data offset related to variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Variable Data offset.
+
+**/
+UINTN
+GetVariableDataOffset (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @return Pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ Compare two EFI_TIME data.
+
+
+ @param[in] FirstTime A pointer to the first EFI_TIME data.
+ @param[in] SecondTime A pointer to the second EFI_TIME data.
+
+ @retval TRUE The FirstTime is not later than the SecondTime.
+ @retval FALSE The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+VariableCompareTimeStampInternal (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ );
+
+/**
+ Find the variable in the specified variable store.
+
+ @param[in] VariableName Name of the variable to be found
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+ @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+**/
+EFI_STATUS
+FindVariableEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN IgnoreRtCheck,
+ IN OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ This code finds the next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+ @param[in] VariableStoreList A list of variable stores that should be used to get the next variable.
+ The maximum number of entries is the max value of VARIABLE_STORE_TYPE.
+ @param[out] VariablePtr Pointer to variable header address.
+ @param[in] AuthFormat TRUE indicates authenticated variables are used.
+ FALSE indicates authenticated variables are not used.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+ GUID of an existing variable.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VARIABLE_STORE_HEADER **VariableStoreList,
+ OUT VARIABLE_HEADER **VariablePtr,
+ IN BOOLEAN AuthFormat
+ );
+
+/**
+ Routine used to track statistical information about variable usage.
+ The data is stored in the EFI system table so it can be accessed later.
+ VariableInfo.efi can dump out the table. Only Boot Services variable
+ accesses are tracked by this code. The PcdVariableCollectStatistics
+ build flag controls if this feature is enabled.
+
+ A read that hits in the cache will have Read and Cache true for
+ the transaction. Data is allocated by this routine, but never
+ freed.
+
+ @param[in] VariableName Name of the Variable to track.
+ @param[in] VendorGuid Guid of the Variable to track.
+ @param[in] Volatile TRUE if volatile FALSE if non-volatile.
+ @param[in] Read TRUE if GetVariable() was called.
+ @param[in] Write TRUE if SetVariable() was called.
+ @param[in] Delete TRUE if deleted via SetVariable().
+ @param[in] Cache TRUE for a cache hit.
+ @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_ENTRY structures.
+
+**/
+VOID
+UpdateVariableInfo (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN Read,
+ IN BOOLEAN Write,
+ IN BOOLEAN Delete,
+ IN BOOLEAN Cache,
+ IN OUT VARIABLE_INFO_ENTRY **VariableInfo
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
new file mode 100644
index 000000000..bc93cc07d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
@@ -0,0 +1,153 @@
+/** @file
+ Functions related to managing the UEFI variable runtime cache. This file should only include functions
+ used by the SMM UEFI variable driver.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. They may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+extern VARIABLE_STORE_HEADER *mNvVariableCache;
+
+/**
+ Copies any pending updates to runtime variable caches.
+
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.
+ @retval EFI_SUCCESS The volatile store was updated successfully.
+
+**/
+EFI_STATUS
+FlushPendingRuntimeVariableCacheUpdates (
+ VOID
+ )
+{
+ VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext;
+
+ VariableRuntimeCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;
+
+ if (VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == NULL ||
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == NULL ||
+ VariableRuntimeCacheContext->PendingUpdate == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*(VariableRuntimeCacheContext->PendingUpdate)) {
+ if (VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != NULL &&
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {
+ CopyMem (
+ (VOID *) (
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeHobCache.Store) +
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset
+ ),
+ (VOID *) (
+ ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase) +
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset
+ ),
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength
+ );
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;
+ }
+
+ CopyMem (
+ (VOID *) (
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeNvCache.Store) +
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset
+ ),
+ (VOID *) (
+ ((UINT8 *) (UINTN) mNvVariableCache) +
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset
+ ),
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength
+ );
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength = 0;
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;
+
+ CopyMem (
+ (VOID *) (
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store) +
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset
+ ),
+ (VOID *) (
+ ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase) +
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset
+ ),
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength
+ );
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = 0;
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;
+ *(VariableRuntimeCacheContext->PendingUpdate) = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronizes the runtime variable caches with all pending updates outside runtime.
+
+ Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt
+ to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the
+ update is added as a pending update for the given variable store and it will be flushed to the runtime cache
+ at the next opportunity the ReadLock is available.
+
+ @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.
+ @param[in] Offset Offset in bytes to apply the update.
+ @param[in] Length Length of data in bytes of the update.
+
+ @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime
+ cache ReadLock was available, the runtime cache was updated successfully.
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.
+
+**/
+EFI_STATUS
+SynchronizeRuntimeVariableCache (
+ IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache,
+ IN UINTN Offset,
+ IN UINTN Length
+ )
+{
+ if (VariableRuntimeCache == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else if (VariableRuntimeCache->Store == NULL) {
+ // The runtime cache may not be active or allocated yet.
+ // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET.
+ return EFI_SUCCESS;
+ }
+
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL ||
+ mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) &&
+ VariableRuntimeCache->PendingUpdateLength > 0) {
+ VariableRuntimeCache->PendingUpdateLength =
+ (UINT32) (
+ MAX (
+ (UINTN) (VariableRuntimeCache->PendingUpdateOffset + VariableRuntimeCache->PendingUpdateLength),
+ Offset + Length
+ ) - MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset)
+ );
+ VariableRuntimeCache->PendingUpdateOffset =
+ (UINT32) MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset);
+ } else {
+ VariableRuntimeCache->PendingUpdateLength = (UINT32) Length;
+ VariableRuntimeCache->PendingUpdateOffset = (UINT32) Offset;
+ }
+ *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE;
+
+ if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock) == FALSE) {
+ return FlushPendingRuntimeVariableCacheUpdates ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h
new file mode 100644
index 000000000..f9804a1d6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.h
@@ -0,0 +1,51 @@
+/** @file
+ The common variable volatile store routines shared by the DXE_RUNTIME variable
+ module and the DXE_SMM variable module.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VARIABLE_RUNTIME_CACHE_H_
+#define _VARIABLE_RUNTIME_CACHE_H_
+
+#include "Variable.h"
+
+/**
+ Copies any pending updates to runtime variable caches.
+
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.
+ @retval EFI_SUCCESS The volatile store was updated successfully.
+
+**/
+EFI_STATUS
+FlushPendingRuntimeVariableCacheUpdates (
+ VOID
+ );
+
+/**
+ Synchronizes the runtime variable caches with all pending updates outside runtime.
+
+ Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt
+ to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the
+ update is added as a pending update for the given variable store and it will be flushed to the runtime cache
+ at the next opportunity the ReadLock is available.
+
+ @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.
+ @param[in] Offset Offset in bytes to apply the update.
+ @param[in] Length Length of data in bytes of the update.
+
+ @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime
+ cache ReadLock was available, the runtime cache was updated successfully.
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.
+
+**/
+EFI_STATUS
+SynchronizeRuntimeVariableCache (
+ IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache,
+ IN UINTN Offset,
+ IN UINTN Length
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
new file mode 100644
index 000000000..ceea5d1ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -0,0 +1,146 @@
+## @file
+# Provides variable service.
+#
+# This module installs variable arch protocol and variable write arch protocol to provide
+# variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableRuntimeDxe
+ MODULE_UNI_FILE = VariableRuntimeDxe.uni
+ FILE_GUID = CBD2E4D5-7068-4FF5-B462-9822B4AD8D60
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableClassAddressChangeEvent
+#
+
+[Sources]
+ Reclaim.c
+ Variable.c
+ VariableDxe.c
+ Variable.h
+ VariableNonVolatile.c
+ VariableNonVolatile.h
+ VariableParsing.c
+ VariableParsing.h
+ VariableRuntimeCache.c
+ VariableRuntimeCache.h
+ PrivilegePolymorphic.h
+ Measurement.c
+ TcgMorLockDxe.c
+ VarCheck.c
+ VariableExLib.c
+ SpeculationBarrierDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ PcdLib
+ HobLib
+ TpmMeasurementLib
+ AuthVariableLib
+ VarCheckLib
+
+[Protocols]
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFaultTolerantWriteProtocolGuid
+ gEfiVariableWriteArchProtocolGuid ## PRODUCES
+ gEfiVariableArchProtocolGuid ## PRODUCES
+ gEdkiiVariableLockProtocolGuid ## PRODUCES
+ gEdkiiVarCheckProtocolGuid ## PRODUCES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang"
+ ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang"
+ ## SOMETIMES_CONSUMES ## Variable:L"Lang"
+ ## SOMETIMES_PRODUCES ## Variable:L"Lang"
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ gEfiGlobalVariableGuid
+
+ gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiSystemNvDataFvGuid ## CONSUMES ## GUID
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB
+
+ ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag"
+ ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag"
+ gEdkiiVarErrorFlagGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"db"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbx"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbt"
+ gEfiImageSecurityDatabaseGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable.
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni
new file mode 100644
index 000000000..227b8c6fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides variable service.
+//
+// This module installs variable arch protocol and variable write arch protocol to provide
+// variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides variable service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs variable arch protocol and variable write arch protocol to provide variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo. Caution: This module requires additional review when modified. This driver will have external input - variable data. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni
new file mode 100644
index 000000000..f0976418f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableRuntimeDxe module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
new file mode 100644
index 000000000..caca5c324
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -0,0 +1,1188 @@
+/** @file
+ The sample implementation for SMM variable protocol. And this driver
+ implements an SMI handler to communicate with the DXE runtime driver
+ to provide variable services.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data and communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmVariableHandler() will receive untrusted input and do basic validation.
+
+ Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+ VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+ SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/SmmVariable.h>
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Protocol/SmmFaultTolerantWrite.h>
+#include <Protocol/MmEndOfDxe.h>
+#include <Protocol/SmmVarCheck.h>
+
+#include <Library/MmServicesTableLib.h>
+
+#include <Guid/SmmVariableCommon.h>
+#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+extern VARIABLE_STORE_HEADER *mNvVariableCache;
+
+BOOLEAN mAtRuntime = FALSE;
+UINT8 *mVariableBufferPayload = NULL;
+UINTN mVariableBufferPayloadSize;
+
+/**
+ SecureBoot Hook for SetVariable.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ return ;
+}
+
+/**
+
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ @param VariableName Name of Variable to be found.
+ @param VendorGuid Variable vendor GUID.
+ @param Attributes Attribute value of the variable found
+ @param DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
+ //
+ mRequestSource = VarCheckFromTrusted;
+ Status = VariableServiceSetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ mRequestSource = VarCheckFromUntrusted;
+ return Status;
+}
+
+EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
+ VariableServiceGetVariable,
+ VariableServiceGetNextVariableName,
+ SmmVariableSetVariable,
+ VariableServiceQueryVariableInfo
+};
+
+EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHandler,
+ VarCheckVariablePropertySet,
+ VarCheckVariablePropertyGet };
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return mAtRuntime;
+}
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param Lock A pointer to the lock data structure to initialize.
+ @param Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ )
+{
+ return Lock;
+}
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+
+}
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+
+}
+
+/**
+ Retrieve the SMM Fault Tolerent Write protocol interface.
+
+ @param[out] FtwProtocol The interface of SMM Ftw protocol
+
+ @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
+ @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
+ @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+ OUT VOID **FtwProtocol
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Smm Fault Tolerent Write protocol
+ //
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ NULL,
+ FtwProtocol
+ );
+ return Status;
+}
+
+
+/**
+ Retrieve the SMM FVB protocol interface by HANDLE.
+
+ @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
+ reading, writing, and erasing the target block.
+ @param[out] FvBlock The interface of SMM FVB protocol
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
+ @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+ IN EFI_HANDLE FvBlockHandle,
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
+ )
+{
+ //
+ // To get the SMM FVB protocol interface on the handle
+ //
+ return gMmst->MmHandleProtocol (
+ FvBlockHandle,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ (VOID **) FvBlock
+ );
+}
+
+
+/**
+ Function returns an array of handles that support the SMM FVB protocol
+ in a buffer allocated from pool.
+
+ @param[out] NumberHandles The number of handles returned in Buffer.
+ @param[out] Buffer A pointer to the buffer to return the requested
+ array of handles that support SMM FVB protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NumberHandles.
+ @retval EFI_NOT_FOUND No SMM FVB handle was found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+ OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if ((NumberHandles == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = gMmst->MmLocateHandle (
+ ByProtocol,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &BufferSize,
+ *Buffer
+ );
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gMmst->MmLocateHandle (
+ ByProtocol,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR(Status)) {
+ *NumberHandles = 0;
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the variable statistics information from the information buffer pointed by gVariableInfo.
+
+ Caution: This function may be invoked at SMM runtime.
+ InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
+
+ @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
+ On input, point to the variable information returned last time. if
+ InfoEntry->VendorGuid is zero, return the first information.
+ On output, point to the next variable information.
+ @param[in, out] InfoSize On input, the size of the variable information buffer.
+ On output, the returned variable information size.
+
+ @retval EFI_SUCCESS The variable information is found and returned successfully.
+ @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
+ PcdVariableCollectStatistics should be set TRUE to support it.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid.
+
+**/
+EFI_STATUS
+SmmVariableGetStatistics (
+ IN OUT VARIABLE_INFO_ENTRY *InfoEntry,
+ IN OUT UINTN *InfoSize
+ )
+{
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ UINTN NameSize;
+ UINTN StatisticsInfoSize;
+ CHAR16 *InfoName;
+ UINTN InfoNameMaxSize;
+ EFI_GUID VendorGuid;
+
+ if (InfoEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableInfo = gVariableInfo;
+ if (VariableInfo == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY);
+ if (*InfoSize < StatisticsInfoSize) {
+ *InfoSize = StatisticsInfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ InfoName = (CHAR16 *)(InfoEntry + 1);
+ InfoNameMaxSize = (*InfoSize - sizeof (VARIABLE_INFO_ENTRY));
+
+ CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
+
+ if (IsZeroGuid (&VendorGuid)) {
+ //
+ // Return the first variable info
+ //
+ NameSize = StrSize (VariableInfo->Name);
+ StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
+ if (*InfoSize < StatisticsInfoSize) {
+ *InfoSize = StatisticsInfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+ CopyMem (InfoName, VariableInfo->Name, NameSize);
+ *InfoSize = StatisticsInfoSize;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the next variable info
+ //
+ while (VariableInfo != NULL) {
+ if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
+ NameSize = StrSize (VariableInfo->Name);
+ if (NameSize <= InfoNameMaxSize) {
+ if (CompareMem (VariableInfo->Name, InfoName, NameSize) == 0) {
+ //
+ // Find the match one
+ //
+ VariableInfo = VariableInfo->Next;
+ break;
+ }
+ }
+ }
+ VariableInfo = VariableInfo->Next;
+ };
+
+ if (VariableInfo == NULL) {
+ *InfoSize = 0;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Output the new variable info
+ //
+ NameSize = StrSize (VariableInfo->Name);
+ StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
+ if (*InfoSize < StatisticsInfoSize) {
+ *InfoSize = StatisticsInfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+ CopyMem (InfoName, VariableInfo->Name, NameSize);
+ *InfoSize = StatisticsInfoSize;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the variable wrapper driver.
+
+ Caution: This function may receive untrusted input.
+ This variable data and communicate buffer are external input, so this function will do basic validation.
+ Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+ VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+ SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;
+ SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *RuntimeVariableCacheContext;
+ SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *GetRuntimeCacheInfo;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCacheContext;
+ VARIABLE_STORE_HEADER *VariableCache;
+ UINTN InfoSize;
+ UINTN NameBufferSize;
+ UINTN CommBufferPayloadSize;
+ UINTN TempCommBufferSize;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ CommBufferPayloadSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
+ switch (SmmVariableFunctionHeader->Function) {
+ case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
+ if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ DEBUG ((EFI_D_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
+ if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+ + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // The VariableSpeculationBarrier() call here is to ensure the previous
+ // range/content checks for the CommBuffer have been completed before the
+ // subsequent consumption of the CommBuffer content.
+ //
+ VariableSpeculationBarrier ();
+ if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceGetVariable (
+ SmmVariableHeader->Name,
+ &SmmVariableHeader->Guid,
+ &SmmVariableHeader->Attributes,
+ &SmmVariableHeader->DataSize,
+ (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
+ if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;
+ if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+ if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure input VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceGetNextVariableName (
+ &GetNextVariableName->NameSize,
+ GetNextVariableName->Name,
+ &GetNextVariableName->Guid
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
+ if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
+ if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+ + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ // Data buffer should not contain SMM range
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // The VariableSpeculationBarrier() call here is to ensure the previous
+ // range/content checks for the CommBuffer have been completed before the
+ // subsequent consumption of the CommBuffer content.
+ //
+ VariableSpeculationBarrier ();
+ if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceSetVariable (
+ SmmVariableHeader->Name,
+ &SmmVariableHeader->Guid,
+ SmmVariableHeader->Attributes,
+ SmmVariableHeader->DataSize,
+ (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
+ );
+ break;
+
+ case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
+ DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
+
+ Status = VariableServiceQueryVariableInfo (
+ QueryVariableInfo->Attributes,
+ &QueryVariableInfo->MaximumVariableStorageSize,
+ &QueryVariableInfo->RemainingVariableStorageSize,
+ &QueryVariableInfo->MaximumVariableSize
+ );
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
+ DEBUG ((EFI_D_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ GetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
+ GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+ if (AtRuntime()) {
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (!mEndOfDxe) {
+ MorLockInitAtEndOfDxe ();
+ mEndOfDxe = TRUE;
+ VarCheckLibInitializeAtEndOfDxe (NULL);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ }
+ ReclaimForOS ();
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
+ mAtRuntime = TRUE;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_STATISTICS:
+ VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;
+ InfoSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+ //
+ // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
+ // It is covered by previous CommBuffer check
+ //
+
+ //
+ // Do not need to check CommBufferSize buffer as it should point to SMRAM
+ // that was used by SMM core to cache CommSize from SmmCommunication protocol.
+ //
+
+ Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);
+ *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;
+ Status = VariableLockRequestToLock (
+ NULL,
+ VariableToLock->Name,
+ &VariableToLock->Guid
+ );
+ }
+ break;
+ case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) SmmVariableFunctionHeader->Data;
+ Status = VarCheckVariablePropertySet (
+ CommVariableProperty->Name,
+ &CommVariableProperty->Guid,
+ &CommVariableProperty->VariableProperty
+ );
+ }
+ break;
+ case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) mVariableBufferPayload;
+ if ((UINTN) (~0) - CommVariableProperty->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + CommVariableProperty->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // The VariableSpeculationBarrier() call here is to ensure the previous
+ // range/content checks for the CommBuffer have been completed before the
+ // subsequent consumption of the CommBuffer content.
+ //
+ VariableSpeculationBarrier ();
+ if (CommVariableProperty->NameSize < sizeof (CHAR16) || CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VarCheckVariablePropertyGet (
+ CommVariableProperty->Name,
+ &CommVariableProperty->Guid,
+ &CommVariableProperty->VariableProperty
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+ case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (mEndOfDxe) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) mVariableBufferPayload;
+
+ //
+ // Verify required runtime cache buffers are provided.
+ //
+ if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL ||
+ RuntimeVariableCacheContext->RuntimeNvCache == NULL ||
+ RuntimeVariableCacheContext->PendingUpdate == NULL ||
+ RuntimeVariableCacheContext->ReadLock == NULL ||
+ RuntimeVariableCacheContext->HobFlushComplete == NULL) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // Verify minimum size requirements for the runtime variable store buffers.
+ //
+ if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
+ RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER)) ||
+ RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER) ||
+ RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ //
+ // Verify runtime buffers do not overlap with SMRAM ranges.
+ //
+ if (RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
+ !VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->RuntimeHobCache,
+ (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (!VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache,
+ (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (!VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->RuntimeNvCache,
+ (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (!VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->PendingUpdate,
+ sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (!VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->ReadLock,
+ sizeof (*(RuntimeVariableCacheContext->ReadLock)))) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ if (!VariableSmmIsBufferOutsideSmmValid (
+ (UINTN) RuntimeVariableCacheContext->HobFlushComplete,
+ sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) {
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ VariableCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;
+ VariableCacheContext->VariableRuntimeHobCache.Store = RuntimeVariableCacheContext->RuntimeHobCache;
+ VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache;
+ VariableCacheContext->VariableRuntimeNvCache.Store = RuntimeVariableCacheContext->RuntimeNvCache;
+ VariableCacheContext->PendingUpdate = RuntimeVariableCacheContext->PendingUpdate;
+ VariableCacheContext->ReadLock = RuntimeVariableCacheContext->ReadLock;
+ VariableCacheContext->HobFlushComplete = RuntimeVariableCacheContext->HobFlushComplete;
+
+ // Set up the intial pending request since the RT cache needs to be in sync with SMM cache
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 &&
+ VariableCacheContext->VariableRuntimeHobCache.Store != NULL) {
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
+ CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature));
+ }
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;
+ VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
+ CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature));
+
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;
+ VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;
+ VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
+ CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature));
+
+ *(VariableCacheContext->PendingUpdate) = TRUE;
+ *(VariableCacheContext->ReadLock) = FALSE;
+ *(VariableCacheContext->HobFlushComplete) = FALSE;
+
+ Status = EFI_SUCCESS;
+ break;
+ case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE:
+ Status = FlushPendingRuntimeVariableCacheUpdates ();
+ break;
+ case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) {
+ DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
+
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size;
+ } else {
+ GetRuntimeCacheInfo->TotalHobStorageSize = 0;
+ }
+
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size;
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;
+ GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache->Size;
+ GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+ Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+EXIT:
+
+ SmmVariableFunctionHeader->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SMM END_OF_DXE protocol notification event handler.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));
+ MorLockInitAtEndOfDxe ();
+ mEndOfDxe = TRUE;
+ VarCheckLibInitializeAtEndOfDxe (NULL);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+ ReclaimForOS ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes variable write service for SMM.
+
+**/
+VOID
+VariableWriteServiceInitializeSmm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = VariableWriteServiceInitialize ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
+ }
+
+ //
+ // Notify the variable wrapper driver the variable write service is ready
+ //
+ VariableNotifySmmWriteReady ();
+}
+
+/**
+ SMM Fault Tolerant Write protocol notification event handler.
+
+ Non-Volatile variable write may needs FTW protocol to reclaim when
+ writting variable.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEventCallback runs successfully
+ @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
+
+ **/
+EFI_STATUS
+EFIAPI
+SmmFtwNotificationEvent (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
+ UINTN FtwMaxBlockSize;
+
+ if (mVariableModuleGlobal->FvbInstance != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Ensure SMM FTW protocol is installed.
+ //
+ Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
+ }
+
+ NvStorageVariableBase = NV_STORAGE_VARIABLE_BASE;
+ VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;
+
+ //
+ // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+ //
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+
+ //
+ // Find the proper FVB protocol for variable.
+ //
+ Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ mVariableModuleGlobal->FvbInstance = FvbProtocol;
+
+ //
+ // Initializes variable write service after FTW was ready.
+ //
+ VariableWriteServiceInitializeSmm ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MmVariableServiceInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE VariableHandle;
+ VOID *SmmFtwRegistration;
+ VOID *SmmEndOfDxeRegistration;
+
+ //
+ // Variable initialize.
+ //
+ Status = VariableCommonInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the Smm Variable Protocol on a new handle.
+ //
+ VariableHandle = NULL;
+ Status = gMmst->MmInstallProtocolInterface (
+ &VariableHandle,
+ &gEfiSmmVariableProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gSmmVariable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gMmst->MmInstallProtocolInterface (
+ &VariableHandle,
+ &gEdkiiSmmVarCheckProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmVarCheck
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVariableBufferPayloadSize = GetMaxVariableSize () +
+ OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) -
+ GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+
+ Status = gMmst->MmAllocatePool (
+ EfiRuntimeServicesData,
+ mVariableBufferPayloadSize,
+ (VOID **)&mVariableBufferPayload
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Register SMM variable SMI handler
+ ///
+ VariableHandle = NULL;
+ Status = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Notify the variable wrapper driver the variable service is ready
+ //
+ VariableNotifySmmReady ();
+
+ //
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gMmst->MmRegisterProtocolNotify (
+ &gEfiMmEndOfDxeProtocolGuid,
+ SmmEndOfDxeCallback,
+ &SmmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+ //
+ // Register FtwNotificationEvent () notify function.
+ //
+ Status = gMmst->MmRegisterProtocolNotify (
+ &gEfiSmmFaultTolerantWriteProtocolGuid,
+ SmmFtwNotificationEvent,
+ &SmmFtwRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SmmFtwNotificationEvent (NULL, NULL, NULL);
+ } else {
+ //
+ // Emulated non-volatile variable mode does not depend on FVB and FTW.
+ //
+ VariableWriteServiceInitializeSmm ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
new file mode 100644
index 000000000..bc3033588
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -0,0 +1,149 @@
+## @file
+# Provides SMM variable service.
+#
+# This module installs SMM variable protocol into SMM protocol database,
+# which can be used by SMM driver, and installs SMM variable protocol
+# into BS protocol database, which can be used to notify the SMM Runtime
+# Dxe driver that the SMM variable service is ready.
+# This module should be used with SMM Runtime DXE module together. The
+# SMM Runtime DXE module would install variable arch protocol and variable
+# write arch protocol based on SMM variable module.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data and communicate buffer in SMM mode.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+# The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+# may not be modified without authorization. If platform fails to protect these resources,
+# the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableSmm
+ MODULE_UNI_FILE = VariableSmm.uni
+ FILE_GUID = 23A089B3-EED5-4ac5-B2AB-43E3298C2343
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+
+[Sources]
+ Reclaim.c
+ Variable.c
+ VariableTraditionalMm.c
+ VariableSmm.c
+ VariableNonVolatile.c
+ VariableNonVolatile.h
+ VariableParsing.c
+ VariableParsing.h
+ VariableRuntimeCache.c
+ VariableRuntimeCache.h
+ VarCheck.c
+ Variable.h
+ PrivilegePolymorphic.h
+ VariableExLib.c
+ TcgMorLockSmm.c
+ SpeculationBarrierSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+ MmServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ PcdLib
+ SmmMemLib
+ AuthVariableLib
+ VarCheckLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiSmmFaultTolerantWriteProtocolGuid
+ ## PRODUCES
+ ## UNDEFINED # SmiHandlerRegister
+ gEfiSmmVariableProtocolGuid
+ gEfiMmEndOfDxeProtocolGuid ## NOTIFY
+ gEdkiiSmmVarCheckProtocolGuid ## PRODUCES
+ gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang"
+ ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang"
+ ## SOMETIMES_CONSUMES ## Variable:L"Lang"
+ ## SOMETIMES_PRODUCES ## Variable:L"Lang"
+ gEfiGlobalVariableGuid
+
+ gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+
+ gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol
+ gEfiSystemNvDataFvGuid ## CONSUMES ## GUID
+ gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB
+
+ ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag"
+ ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag"
+ gEdkiiVarErrorFlagGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable.
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableSmmExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni
new file mode 100644
index 000000000..414c7cdc7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Provides SMM variable service.
+//
+// This module installs SMM variable protocol into SMM protocol database,
+// which can be used by SMM driver, and installs SMM variable protocol
+// into BS protocol database, which can be used to notify the SMM Runtime
+// Dxe driver that the SMM variable service is ready.
+// This module should be used with SMM Runtime DXE module together. The
+// SMM Runtime DXE module would install variable arch protocol and variable
+// write arch protocol based on SMM variable module.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data and communicate buffer in SMM mode.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides SMM variable service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs SMM variable protocol into SMM protocol database, which can be used by SMM driver, and installs SMM variable protocol into BS protocol database, which can be used to notify the SMM Runtime DXE driver that the SMM variable service is ready. This module should be used with SMM Runtime DXE module together. The SMM Runtime DXE module would install variable arch protocol and variable write arch protocol based on SMM variable module. Caution: This module requires additional review when modified. This driver will have external input - variable data and communicate buffer in SMM mode. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni
new file mode 100644
index 000000000..f724209f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableSmm module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
new file mode 100644
index 000000000..663a1aaa1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -0,0 +1,1801 @@
+/** @file
+ Implement all four UEFI Runtime Variable services for the nonvolatile
+ and volatile storage space and install variable architecture protocol
+ based on SMM variable module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
+ to receive data buffer. The size should be checked carefully.
+
+ InitCommunicateBuffer() is really function to check the variable data size.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Variable.h>
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/SmmVariableCommon.h>
+
+#include "PrivilegePolymorphic.h"
+#include "VariableParsing.h"
+
+EFI_HANDLE mHandle = NULL;
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 = NULL;
+UINT8 *mVariableBuffer = NULL;
+UINT8 *mVariableBufferPhysical = NULL;
+VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
+UINTN mVariableBufferSize;
+UINTN mVariableRuntimeHobCacheBufferSize;
+UINTN mVariableRuntimeNvCacheBufferSize;
+UINTN mVariableRuntimeVolatileCacheBufferSize;
+UINTN mVariableBufferPayloadSize;
+BOOLEAN mVariableRuntimeCachePendingUpdate;
+BOOLEAN mVariableRuntimeCacheReadLock;
+BOOLEAN mVariableAuthFormat;
+BOOLEAN mHobFlushComplete;
+EFI_LOCK mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
+EDKII_VAR_CHECK_PROTOCOL mVarCheck;
+
+/**
+ Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+ Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData(
+ VOID
+ );
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (Lock);
+ }
+}
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return EfiAtRuntime ();
+}
+
+/**
+ Initialize the variable cache buffer as an empty variable store.
+
+ @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
+ @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
+ buffer that is allocated. On output, the actual size of the buffer allocated.
+ If TotalVariableCacheSize is zero, a buffer will not be allocated and the
+ function will return with EFI_SUCCESS.
+
+ @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
+ @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
+
+**/
+EFI_STATUS
+InitVariableCache (
+ OUT VARIABLE_STORE_HEADER **VariableCacheBuffer,
+ IN OUT UINTN *TotalVariableCacheSize
+ )
+{
+ VARIABLE_STORE_HEADER *VariableCacheStorePtr;
+
+ if (TotalVariableCacheSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*TotalVariableCacheSize == 0) {
+ return EFI_SUCCESS;
+ }
+ if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));
+
+ //
+ // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
+ //
+ *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages (
+ EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
+ );
+ if (*VariableCacheBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ VariableCacheStorePtr = *VariableCacheBuffer;
+ SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);
+
+ ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));
+ VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize;
+ VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;
+ VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the communicate buffer using DataSize and Function.
+
+ The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
+ DataSize.
+
+ Caution: This function may receive untrusted input.
+ The data size external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[out] DataPtr Points to the data in the communicate buffer.
+ @param[in] DataSize The data size to send to SMM.
+ @param[in] Function The function number to initialize the communicate header.
+
+ @retval EFI_INVALID_PARAMETER The data size is too big.
+ @retval EFI_SUCCESS Find the specified variable.
+
+**/
+EFI_STATUS
+InitCommunicateBuffer (
+ OUT VOID **DataPtr OPTIONAL,
+ IN UINTN DataSize,
+ IN UINTN Function
+ )
+{
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+
+ if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *) mVariableBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = Function;
+ if (DataPtr != NULL) {
+ *DataPtr = SmmVariableFunctionHeader->Data;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send the data in communicate buffer to SMM.
+
+ @param[in] DataSize This size of the function header and the data.
+
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.
+ @retval Others Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+ CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ Status = mMmCommunication2->Communicate (mMmCommunication2,
+ mVariableBufferPhysical,
+ mVariableBuffer,
+ &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *) mVariableBuffer;
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+ return SmmVariableFunctionHeader->ReturnStatus;
+}
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
+
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
+ as pending to be read-only.
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+ Or VariableName is an empty string.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+ VariableToLock = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (VariableToLock != NULL);
+
+ CopyGuid (&VariableToLock->Guid, VendorGuid);
+ VariableToLock->NameSize = VariableNameSize;
+ CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (Name);
+ CommVariableProperty = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (CommVariableProperty != NULL);
+
+ CopyGuid (&CommVariableProperty->Guid, Guid);
+ CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
+ CommVariableProperty->NameSize = VariableNameSize;
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (Name);
+ CommVariableProperty = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (CommVariableProperty != NULL);
+
+ CopyGuid (&CommVariableProperty->Guid, Guid);
+ CommVariableProperty->NameSize = VariableNameSize;
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (Status == EFI_SUCCESS) {
+ CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ Signals SMM to synchronize any pending variable updates with the runtime cache(s).
+
+**/
+VOID
+SyncRuntimeCache (
+ VOID
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+}
+
+/**
+ Check whether a SMI must be triggered to retrieve pending cache updates.
+
+ If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
+ will prevent the HOB cache from being used for future runtime cache hits.
+
+**/
+VOID
+CheckForRuntimeCacheSync (
+ VOID
+ )
+{
+ if (mVariableRuntimeCachePendingUpdate) {
+ SyncRuntimeCache ();
+ }
+ ASSERT (!mVariableRuntimeCachePendingUpdate);
+
+ //
+ // The HOB variable data may have finished being flushed in the runtime cache sync update
+ //
+ if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {
+ if (!EfiAtRuntime ()) {
+ FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));
+ }
+ mVariableRuntimeHobCacheBuffer = NULL;
+ }
+}
+
+/**
+ Finds the given variable in a runtime cache variable store.
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInRuntimeCache (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN TempDataSize;
+ VARIABLE_POINTER_TRACK RtPtrTrack;
+ VARIABLE_STORE_TYPE StoreType;
+ VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
+
+ Status = EFI_NOT_FOUND;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));
+
+ //
+ // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+ // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+ // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+ // cache read lock should always be free when entering this function.
+ //
+ ASSERT (!mVariableRuntimeCacheReadLock);
+
+ mVariableRuntimeCacheReadLock = TRUE;
+ CheckForRuntimeCacheSync ();
+
+ if (!mVariableRuntimeCachePendingUpdate) {
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as FindVariable
+ // makes use of this mapping to implement search algorithm.
+ //
+ VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+ VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
+ VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
+
+ for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
+ if (VariableStoreList[StoreType] == NULL) {
+ continue;
+ }
+
+ RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+ RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
+ RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get data size
+ //
+ TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
+ ASSERT (TempDataSize != 0);
+
+ if (*DataSize >= TempDataSize) {
+ if (Data == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
+ *DataSize = TempDataSize;
+
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ *DataSize = TempDataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ }
+ }
+
+Done:
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ if (Attributes != NULL && RtPtrTrack.CurrPtr != NULL) {
+ *Attributes = RtPtrTrack.CurrPtr->Attributes;
+ }
+ }
+ mVariableRuntimeCacheReadLock = FALSE;
+
+ return Status;
+}
+
+/**
+ Finds the given variable in a variable store in SMM.
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInSmm (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ UINTN TempDataSize;
+ UINTN VariableNameSize;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempDataSize = *DataSize;
+ VariableNameSize = StrSize (VariableName);
+ SmmVariableHeader = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
+ //
+ // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+ //
+ TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
+ }
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmVariableHeader != NULL);
+
+ CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
+ SmmVariableHeader->DataSize = TempDataSize;
+ SmmVariableHeader->NameSize = VariableNameSize;
+ if (Attributes == NULL) {
+ SmmVariableHeader->Attributes = 0;
+ } else {
+ SmmVariableHeader->Attributes = *Attributes;
+ }
+ CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+ //
+ // Get data from SMM.
+ //
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // SMM CommBuffer DataSize can be a trimed value
+ // Only update DataSize when needed
+ //
+ *DataSize = SmmVariableHeader->DataSize;
+ }
+ if (Attributes != NULL) {
+ *Attributes = SmmVariableHeader->Attributes;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Data != NULL) {
+ CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (VariableName[0] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+ } else {
+ Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ return Status;
+}
+
+/**
+ Finds the next available variable in a runtime cache variable store.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+GetNextVariableNameInRuntimeCache (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarNameSize;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+ // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+ // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+ // cache read lock should always be free when entering this function.
+ //
+ ASSERT (!mVariableRuntimeCacheReadLock);
+
+ CheckForRuntimeCacheSync ();
+
+ mVariableRuntimeCacheReadLock = TRUE;
+ if (!mVariableRuntimeCachePendingUpdate) {
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as FindVariable
+ // makes use of this mapping to implement search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+ VariableStoreHeader[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
+ VariableStoreHeader[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
+
+ Status = VariableServiceGetNextVariableInternal (
+ VariableName,
+ VendorGuid,
+ VariableStoreHeader,
+ &VariablePtr,
+ mVariableAuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);
+ ASSERT (VarNameSize != 0);
+ if (VarNameSize <= *VariableNameSize) {
+ CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);
+ CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ }
+ }
+ mVariableRuntimeCacheReadLock = FALSE;
+
+ return Status;
+}
+
+/**
+ Finds the next available variable in a SMM variable store.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+GetNextVariableNameInSmm (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
+ UINTN OutVariableNameSize;
+ UINTN InVariableNameSize;
+
+ OutVariableNameSize = *VariableNameSize;
+ InVariableNameSize = StrSize (VariableName);
+ SmmGetNextVariableName = NULL;
+
+ //
+ // If input string exceeds SMM payload limit. Return failure
+ //
+ if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ //
+ // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+ //
+ OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+ }
+ //
+ // Payload should be Guid + NameSize + MAX of Input & Output buffer
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
+
+ Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmGetNextVariableName != NULL);
+
+ //
+ // SMM comm buffer->NameSize is buffer size for return string
+ //
+ SmmGetNextVariableName->NameSize = OutVariableNameSize;
+
+ CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
+ //
+ // Copy whole string
+ //
+ CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
+ if (OutVariableNameSize > InVariableNameSize) {
+ ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
+ }
+
+ //
+ // Send data to SMM
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+ //
+ // Get data from SMM.
+ //
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // SMM CommBuffer NameSize can be a trimed value
+ // Only update VariableNameSize when needed
+ //
+ *VariableNameSize = SmmGetNextVariableName->NameSize;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
+ CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
+
+Done:
+ return Status;
+}
+
+/**
+ This code Finds the Next available variable.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxLen;
+
+ Status = EFI_NOT_FOUND;
+
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Calculate the possible maximum length of name string, including the Null terminator.
+ //
+ MaxLen = *VariableNameSize / sizeof (CHAR16);
+ if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
+ //
+ // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
+ // follow spec to return EFI_INVALID_PARAMETER.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);
+ } else {
+ Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ return Status;
+}
+
+/**
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable found
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Set successfully.
+ @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ UINTN VariableNameSize;
+
+ //
+ // Check input parameters.
+ //
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+ SmmVariableHeader = NULL;
+
+ //
+ // If VariableName or DataSize exceeds SMM payload limit. Return failure
+ //
+ if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
+ Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmVariableHeader != NULL);
+
+ CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
+ SmmVariableHeader->DataSize = DataSize;
+ SmmVariableHeader->NameSize = VariableNameSize;
+ SmmVariableHeader->Attributes = Attributes;
+ CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+ CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ if (!EfiAtRuntime ()) {
+ if (!EFI_ERROR (Status)) {
+ SecureBootHook (
+ VariableName,
+ VendorGuid
+ );
+ }
+ }
+ return Status;
+}
+
+
+/**
+ This code returns information about the EFI variables.
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @retval EFI_SUCCESS Query successfully.
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
+
+ SmmQueryVariableInfo = NULL;
+
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
+ //
+ PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+ Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (SmmQueryVariableInfo != NULL);
+
+ SmmQueryVariableInfo->Attributes = Attributes;
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
+ *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
+ *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ Exit Boot Services Event notification handler.
+
+ Notify SMM variable driver about the event.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+}
+
+
+/**
+ On Ready To Boot Services Event notification handler.
+
+ Notify SMM variable driver about the event.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+
+ //
+ // Install the system configuration table for variable info data captured
+ //
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {
+ if (mVariableAuthFormat) {
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);
+ } else {
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);
+ }
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
+ EfiConvertPointer (0x0, (VOID **) &mMmCommunication2);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);
+}
+
+/**
+ This code gets variable payload size.
+
+ @param[out] VariablePayloadSize Output pointer to variable payload size.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval Others Get unsuccessfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariablePayloadSize (
+ OUT UINTN *VariablePayloadSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmGetPayloadSize = NULL;
+ CommBuffer = NULL;
+
+ if(VariablePayloadSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ //
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ CommBuffer = AllocateZeroPool (CommSize);
+ if (CommBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
+ SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
+
+Done:
+ if (CommBuffer != NULL) {
+ FreePool (CommBuffer);
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ This code gets information needed from SMM for runtime cache initialization.
+
+ @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
+ @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
+ @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
+ @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
+
+ @retval EFI_SUCCESS Retrieved the size successfully.
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
+ @retval Others Could not retrieve the size successfully.
+
+**/
+EFI_STATUS
+GetRuntimeCacheInfo (
+ OUT UINTN *TotalHobStorageSize,
+ OUT UINTN *TotalNvStorageSize,
+ OUT UINTN *TotalVolatileStorageSize,
+ OUT BOOLEAN *AuthenticatedVariableUsage
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmGetRuntimeCacheInfo = NULL;
+ CommBuffer = mVariableBuffer;
+
+ if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CommBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+ ZeroMem (CommBuffer, CommSize);
+
+ SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;
+ SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;
+ *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;
+ *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;
+ *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ Sends the runtime variable cache context information to SMM.
+
+ @retval EFI_SUCCESS Retrieved the size successfully.
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
+ @retval Others Could not retrieve the size successfully.;
+
+**/
+EFI_STATUS
+SendRuntimeVariableCacheContextToSmm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;
+ EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmRuntimeVarCacheContext = NULL;
+ CommBuffer = mVariableBuffer;
+
+ if (CommBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+ //
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+ ZeroMem (CommBuffer, CommSize);
+
+ SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;
+ SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;
+
+ SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;
+ SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;
+ SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;
+ SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;
+ SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;
+ SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+/**
+ Initialize variable service and install Variable Architectural protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **) &mMmCommunication2);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate memory for variable communicate buffer.
+ //
+ Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
+ ASSERT_EFI_ERROR (Status);
+ mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
+ mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
+ ASSERT (mVariableBuffer != NULL);
+
+ //
+ // Save the buffer physical address used for SMM conmunication.
+ //
+ mVariableBufferPhysical = mVariableBuffer;
+
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));
+ //
+ // Allocate runtime variable cache memory buffers.
+ //
+ Status = GetRuntimeCacheInfo (
+ &mVariableRuntimeHobCacheBufferSize,
+ &mVariableRuntimeNvCacheBufferSize,
+ &mVariableRuntimeVolatileCacheBufferSize,
+ &mVariableAuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = SendRuntimeVariableCacheContextToSmm ();
+ if (!EFI_ERROR (Status)) {
+ SyncRuntimeCache ();
+ }
+ }
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ mVariableRuntimeHobCacheBuffer = NULL;
+ mVariableRuntimeNvCacheBuffer = NULL;
+ mVariableRuntimeVolatileCacheBuffer = NULL;
+ }
+ }
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));
+ }
+
+ gRT->GetVariable = RuntimeServiceGetVariable;
+ gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
+ gRT->SetVariable = RuntimeServiceSetVariable;
+ gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
+
+ //
+ // Install the Variable Architectural Protocol on a new handle.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVariableLock.RequestToLock = VariableLockRequestToLock;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
+ mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
+ mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVarCheckProtocolGuid,
+ &mVarCheck,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ SMM Non-Volatile variable write service is ready notify event handler.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableWriteReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *ProtocolOps;
+
+ //
+ // Check whether the protocol is installed or not.
+ //
+ Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
+ // Secure Boot Policy Variable change. Record their initial value.
+ //
+ RecordSecureBootPolicyVarData();
+
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableWriteArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableSmmRuntimeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *SmmVariableRegistration;
+ VOID *SmmVariableWriteRegistration;
+ EFI_EVENT OnReadyToBootEvent;
+ EFI_EVENT ExitBootServiceEvent;
+ EFI_EVENT LegacyBootEvent;
+
+ EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
+
+ //
+ // Smm variable service is ready
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiSmmVariableProtocolGuid,
+ TPL_CALLBACK,
+ SmmVariableReady,
+ NULL,
+ &SmmVariableRegistration
+ );
+
+ //
+ // Smm Non-Volatile variable write service is ready
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gSmmVariableWriteGuid,
+ TPL_CALLBACK,
+ SmmVariableWriteReady,
+ NULL,
+ &SmmVariableWriteRegistration
+ );
+
+ //
+ // Register the event to reclaim variable for OS usage.
+ //
+ EfiCreateEventReadyToBootEx (
+ TPL_NOTIFY,
+ OnReadyToBoot,
+ NULL,
+ &OnReadyToBootEvent
+ );
+
+ //
+ // Register the event to inform SMM variable that it is at runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &ExitBootServiceEvent
+ );
+
+ //
+ // Register the event to inform SMM variable that it is at runtime for legacy boot.
+ // Reuse OnExitBootServices() here.
+ //
+ EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ OnExitBootServices,
+ NULL,
+ &LegacyBootEvent
+ );
+
+ //
+ // Register the event to convert the pointer for runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
new file mode 100644
index 000000000..01564e4c5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -0,0 +1,106 @@
+## @file
+# Runtime DXE part corresponding to SMM authenticated variable module.
+#
+# This module installs variable arch protocol and variable write arch protocol to provide
+# variable service. This module need work together with SMM authenticated variable module.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+# The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+# may not be modified without authorization. If platform fails to protect these resources,
+# the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableSmmRuntimeDxe
+ MODULE_UNI_FILE = VariableSmmRuntimeDxe.uni
+ FILE_GUID = 9F7DCADE-11EA-448a-A46F-76E003657DD1
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VariableSmmRuntimeInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableAddressChangeEvent
+#
+
+[Sources]
+ VariableSmmRuntimeDxe.c
+ PrivilegePolymorphic.h
+ Measurement.c
+ VariableParsing.c
+ VariableParsing.h
+ Variable.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ DebugLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ TpmMeasurementLib
+
+[Protocols]
+ gEfiVariableWriteArchProtocolGuid ## PRODUCES
+ gEfiVariableArchProtocolGuid ## PRODUCES
+ gEfiMmCommunication2ProtocolGuid ## CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ ## UNDEFINED # Used to do smm communication
+ gEfiSmmVariableProtocolGuid
+ gEdkiiVariableLockProtocolGuid ## PRODUCES
+ gEdkiiVarCheckProtocolGuid ## PRODUCES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES
+
+[Guids]
+ ## PRODUCES ## GUID # Signature of Variable store header
+ ## CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ ## PRODUCES ## GUID # Signature of Variable store header
+ ## CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVariableGuid
+
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ ## CONSUMES ## GUID # Locate protocol
+ ## CONSUMES ## GUID # Protocol notify
+ gSmmVariableWriteGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ gEfiGlobalVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"db"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbx"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbt"
+ gEfiImageSecurityDatabaseGuid
+
+[Depex]
+ gEfiMmCommunication2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableSmmRuntimeDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni
new file mode 100644
index 000000000..9639f0007
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// This module is the Runtime DXE part correspond to SMM variable module.
+//
+// It installs variable arch protocol and variable write arch protocol to provide
+// four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo
+// and works with SMM variable module together.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The Runtime DXE part corresponding to the SMM variable module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It installs variable arch protocol and variable write arch protocol to provide four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo and works with SMM variable module together."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
new file mode 100644
index 000000000..bbabdf827
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableSmmRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableSmmRuntimeDxe module"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c
new file mode 100644
index 000000000..0d774f366
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c
@@ -0,0 +1,89 @@
+/** @file
+
+ Parts of the SMM/MM implementation that are specific to standalone MM
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return TRUE;
+}
+
+/**
+ Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+ VOID
+ )
+{
+}
+
+/**
+ Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+ VOID
+ )
+{
+}
+
+/**
+ Variable service MM driver entry point.
+
+ @param[in] ImageHandle A handle for the image that is initializing this
+ driver
+ @param[in] MmSystemTable A pointer to the MM system table
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ return MmVariableServiceInitialize ();
+}
+
+/**
+ Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+ This information is used by the MorLock code to infer whether an existing
+ MOR variable is legitimate or not.
+
+ @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
+ protocol database
+ @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+ protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+ VOID
+ )
+{
+ return FALSE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
new file mode 100644
index 000000000..6e17f6cdf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -0,0 +1,139 @@
+## @file
+# Provides SMM variable service.
+#
+# This module installs SMM variable protocol into SMM protocol database,
+# which can be used by SMM driver, and installs SMM variable protocol
+# into BS protocol database, which can be used to notify the SMM Runtime
+# Dxe driver that the SMM variable service is ready.
+# This module should be used with SMM Runtime DXE module together. The
+# SMM Runtime DXE module would install variable arch protocol and variable
+# write arch protocol based on SMM variable module.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data and communicate buffer in SMM mode.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+# The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+# may not be modified without authorization. If platform fails to protect these resources,
+# the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = VariableStandaloneMm
+ FILE_GUID = 7ee2c0c1-c21a-4113-a53a-66824a95696f
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+
+[Sources]
+ Reclaim.c
+ Variable.c
+ VariableSmm.c
+ VariableStandaloneMm.c
+ VariableNonVolatile.c
+ VariableNonVolatile.h
+ VariableParsing.c
+ VariableParsing.h
+ VariableRuntimeCache.c
+ VariableRuntimeCache.h
+ VarCheck.c
+ Variable.h
+ PrivilegePolymorphic.h
+ VariableExLib.c
+ TcgMorLockSmm.c
+ SpeculationBarrierSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ AuthVariableLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ StandaloneMmDriverEntryPoint
+ SynchronizationLib
+ VarCheckLib
+
+[Protocols]
+ gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiSmmFaultTolerantWriteProtocolGuid
+ ## PRODUCES
+ ## UNDEFINED # SmiHandlerRegister
+ gEfiSmmVariableProtocolGuid
+ gEfiMmEndOfDxeProtocolGuid ## NOTIFY
+ gEdkiiSmmVarCheckProtocolGuid ## PRODUCES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang"
+ ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang"
+ ## SOMETIMES_CONSUMES ## Variable:L"Lang"
+ ## SOMETIMES_PRODUCES ## Variable:L"Lang"
+ gEfiGlobalVariableGuid
+
+ gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+
+ gEfiSystemNvDataFvGuid ## CONSUMES ## GUID
+ gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB
+
+ ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag"
+ ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag"
+ gEdkiiVarErrorFlagGuid
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable.
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+ TRUE
diff --git a/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c
new file mode 100644
index 000000000..ac43d297f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c
@@ -0,0 +1,130 @@
+/** @file
+
+ Parts of the SMM/MM implementation that are specific to traditional MM
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmMemLib.h>
+#include "Variable.h"
+
+/**
+ This function checks if the buffer is valid per processor architecture and
+ does not overlap with SMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and does not
+ overlap with SMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlaps
+ with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return SmmIsBufferOutsideSmmValid (Buffer, Length);
+}
+
+/**
+ Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiSmmVariableProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gSmmVariableWriteGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Variable service MM driver entry point
+
+ @param[in] ImageHandle A handle for the image that is initializing this
+ driver
+ @param[in] SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmVariableServiceInitialize ();
+}
+
+/**
+ Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+ This information is used by the MorLock code to infer whether an existing
+ MOR variable is legitimate or not.
+
+ @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
+ protocol database
+ @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+ protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ Status = gBS->LocateProtocol (
+ &gEfiTcg2ProtocolGuid,
+ NULL, // Registration
+ &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiTcgProtocolGuid,
+ NULL, // Registration
+ &Interface
+ );
+ return !EFI_ERROR (Status);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.c b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.c
new file mode 100644
index 000000000..f72b4df80
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.c
@@ -0,0 +1,245 @@
+/** @file
+ Implementation of Watchdog Timer Architectural Protocol using UEFI APIs.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "WatchdogTimer.h"
+
+//
+// Handle for the Watchdog Timer Architectural Protocol instance produced by this driver
+//
+EFI_HANDLE mWatchdogTimerHandle = NULL;
+
+//
+// The Watchdog Timer Architectural Protocol instance produced by this driver
+//
+EFI_WATCHDOG_TIMER_ARCH_PROTOCOL mWatchdogTimer = {
+ WatchdogTimerDriverRegisterHandler,
+ WatchdogTimerDriverSetTimerPeriod,
+ WatchdogTimerDriverGetTimerPeriod
+};
+
+//
+// The watchdog timer period in 100 ns units
+//
+UINT64 mWatchdogTimerPeriod = 0;
+
+//
+// The notification function to call if the watchdig timer fires
+//
+EFI_WATCHDOG_TIMER_NOTIFY mWatchdogTimerNotifyFunction = NULL;
+
+//
+// The one-shot timer event that is armed when the watchdog timer is enabled
+//
+EFI_EVENT mWatchdogTimerEvent;
+
+
+/**
+ Notification function that is called if the watchdog timer is fired.
+
+ Notification function for the one-shot timer event that was signaled
+ when the watchdog timer expired. If a handler has been registered with
+ the Watchdog Timer Architectural Protocol, then that handler is called
+ passing in the time period that has passed that cause the watchdog timer
+ to fire. Then, a call to the Runtime Service ResetSystem() is made to
+ reset the platform.
+
+ @param Timer The one-shot timer event that was signaled when the
+ watchdog timer expired.
+ @param Context The context that was registered when the event Timer was created.
+
+**/
+VOID
+EFIAPI
+WatchdogTimerDriverExpires (
+ IN EFI_EVENT Timer,
+ IN VOID *Context
+ )
+{
+ REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_MINOR, (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_TIMER_EXPIRED));
+
+ //
+ // If a notification function has been registered, then call it
+ //
+ if (mWatchdogTimerNotifyFunction != NULL) {
+ mWatchdogTimerNotifyFunction (mWatchdogTimerPeriod);
+ }
+
+ DEBUG ((EFI_D_ERROR, "Watchdog Timer resetting system\n"));
+
+ //
+ // Reset the platform
+ //
+ gRT->ResetSystem (EfiResetCold, EFI_TIMEOUT, 0, NULL);
+}
+
+
+/**
+ Registers a handler that is to be invoked when the watchdog timer fires.
+
+ This function registers a handler that is to be invoked when the watchdog
+ timer fires. By default, the EFI_WATCHDOG_TIMER protocol will call the
+ Runtime Service ResetSystem() when the watchdog timer fires. If a
+ NotifyFunction is registered, then the NotifyFunction will be called before
+ the Runtime Service ResetSystem() is called. If NotifyFunction is NULL, then
+ the watchdog handler is unregistered. If a watchdog handler is registered,
+ then EFI_SUCCESS is returned. If an attempt is made to register a handler
+ when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+ If an attempt is made to uninstall a handler when a handler is not installed,
+ then return EFI_INVALID_PARAMETER.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param NotifyFunction The function to call when the watchdog timer fires. If this
+ is NULL, then the handler will be unregistered.
+
+ @retval EFI_SUCCESS The watchdog timer handler was registered or unregistered.
+ @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already registered.
+ @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverRegisterHandler (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction
+ )
+{
+ //
+ // If NotifyFunction is NULL, and a handler was not previously registered,
+ // return EFI_INVALID_PARAMETER.
+ //
+ if (NotifyFunction == NULL && mWatchdogTimerNotifyFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If NotifyFunction is not NULL, and a handler is already registered,
+ // return EFI_ALREADY_STARTED.
+ //
+ if (NotifyFunction != NULL && mWatchdogTimerNotifyFunction != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mWatchdogTimerNotifyFunction = NotifyFunction;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the amount of time in the future to fire the watchdog timer.
+
+ This function sets the amount of time to wait before firing the watchdog
+ timer to TimerPeriod 100 ns units. If TimerPeriod is 0, then the watchdog
+ timer is disabled.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod The amount of time in 100 ns units to wait before the watchdog
+ timer is fired. If TimerPeriod is zero, then the watchdog
+ timer is disabled.
+
+ @retval EFI_SUCCESS The watchdog timer has been programmed to fire in Time
+ 100 ns units.
+ @retval EFI_DEVICE_ERROR A watchdog timer could not be programmed due to a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverSetTimerPeriod (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 TimerPeriod
+ )
+{
+ mWatchdogTimerPeriod = TimerPeriod;
+
+ return gBS->SetTimer (
+ mWatchdogTimerEvent,
+ (mWatchdogTimerPeriod == 0) ? TimerCancel : TimerRelative,
+ mWatchdogTimerPeriod
+ );
+}
+
+/**
+ Retrieves the amount of time in 100 ns units that the system will wait before firing the watchdog timer.
+
+ This function retrieves the amount of time the system will wait before firing
+ the watchdog timer. This period is returned in TimerPeriod, and EFI_SUCCESS
+ is returned. If TimerPeriod is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod A pointer to the amount of time in 100 ns units that the system
+ will wait before the watchdog timer is fired. If TimerPeriod of
+ zero is returned, then the watchdog timer is disabled.
+
+ @retval EFI_SUCCESS The amount of time that the system will wait before
+ firing the watchdog timer was returned in TimerPeriod.
+ @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverGetTimerPeriod (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 *TimerPeriod
+ )
+{
+ if (TimerPeriod == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TimerPeriod = mWatchdogTimerPeriod;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of the Watchdog Timer Architectural Protocol driver.
+
+ @param ImageHandle The image handle of this driver.
+ @param SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Watchdog Timer Architectural Protocol successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure the Watchdog Timer Architectural Protocol has not been installed in the system yet.
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtocolGuid);
+
+ //
+ // Create the timer event to implement a simple watchdog timer
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ WatchdogTimerDriverExpires,
+ NULL,
+ &mWatchdogTimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the Watchdog Timer Arch Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mWatchdogTimerHandle,
+ &gEfiWatchdogTimerArchProtocolGuid,
+ &mWatchdogTimer,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.h b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.h
new file mode 100644
index 000000000..58396255b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.h
@@ -0,0 +1,102 @@
+/** @file
+ The internal include file for WatchDogTimer module.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _WATCHDOG_TIMER_H_
+#define _WATCHDOG_TIMER_H_
+
+
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/WatchdogTimer.h>
+
+
+/**
+ Registers a handler that is to be invoked when the watchdog timer fires.
+
+ This function registers a handler that is to be invoked when the watchdog
+ timer fires. By default, the EFI_WATCHDOG_TIMER protocol will call the
+ Runtime Service ResetSystem() when the watchdog timer fires. If a
+ NotifyFunction is registered, then the NotifyFunction will be called before
+ the Runtime Service ResetSystem() is called. If NotifyFunction is NULL, then
+ the watchdog handler is unregistered. If a watchdog handler is registered,
+ then EFI_SUCCESS is returned. If an attempt is made to register a handler
+ when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+ If an attempt is made to uninstall a handler when a handler is not installed,
+ then return EFI_INVALID_PARAMETER.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param NotifyFunction The function to call when the watchdog timer fires. If this
+ is NULL, then the handler will be unregistered.
+
+ @retval EFI_SUCCESS The watchdog timer handler was registered or unregistered.
+ @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already registered.
+ @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverRegisterHandler (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction
+ );
+
+/**
+ Sets the amount of time in the future to fire the watchdog timer.
+
+ This function sets the amount of time to wait before firing the watchdog
+ timer to TimerPeriod 100 ns units. If TimerPeriod is 0, then the watchdog
+ timer is disabled.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod The amount of time in 100 ns units to wait before the watchdog
+ timer is fired. If TimerPeriod is zero, then the watchdog
+ timer is disabled.
+
+ @retval EFI_SUCCESS The watchdog timer has been programmed to fire in Time
+ 100 ns units.
+ @retval EFI_DEVICE_ERROR A watchdog timer could not be programmed due to a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverSetTimerPeriod (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 TimerPeriod
+ );
+
+/**
+ Retrieves the amount of time in 100 ns units that the system will wait before firing the watchdog timer.
+
+ This function retrieves the amount of time the system will wait before firing
+ the watchdog timer. This period is returned in TimerPeriod, and EFI_SUCCESS
+ is returned. If TimerPeriod is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod A pointer to the amount of time in 100 ns units that the system
+ will wait before the watchdog timer is fired. If TimerPeriod of
+ zero is returned, then the watchdog timer is disabled.
+
+ @retval EFI_SUCCESS The amount of time that the system will wait before
+ firing the watchdog timer was returned in TimerPeriod.
+ @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WatchdogTimerDriverGetTimerPeriod (
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 *TimerPeriod
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
new file mode 100644
index 000000000..e6dc67caa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
@@ -0,0 +1,51 @@
+## @file
+# Generic watchdog timer driver producing Watchdog Timer Architectural Protocol using UEFI APIs.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = WatchdogTimer
+ MODULE_UNI_FILE = WatchdogTimer.uni
+ FILE_GUID = F099D67F-71AE-4c36-B2A3-DCEB0EB2B7D8
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = WatchdogTimerDriverInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Sources]
+ WatchdogTimer.h
+ WatchdogTimer.c
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ ReportStatusCodeLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiWatchdogTimerArchProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiTimerArchProtocolGuid
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ WatchdogTimerExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.uni b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.uni
new file mode 100644
index 000000000..f169840a4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Generic watchdog timer driver producing Watchdog Timer Architectural Protocol using UEFI APIs.
+//
+// A generic watchdog timer driver producing Watchdog Timer Architectural Protocol using UEFI APIs.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Generic watchdog timer driver producing Watchdog Timer Architectural Protocol using UEFI APIs"
+
+#string STR_MODULE_DESCRIPTION #language en-US "A generic watchdog timer driver producing Watchdog Timer Architectural Protocol using UEFI APIs."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimerExtra.uni b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimerExtra.uni
new file mode 100644
index 000000000..0c4347917
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimerExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// WatchdogTimer Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Watchdog Timer DXE Driver"
+
+